v4.19.13 snapshot.
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
new file mode 100644
index 0000000..3c3ef42
--- /dev/null
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -0,0 +1,1425 @@
+/*
+ * 88pm860x-codec.c -- 88PM860x ALSA SoC Audio Driver
+ *
+ * Copyright 2010 Marvell International Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/88pm860x.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/jack.h>
+#include <trace/events/asoc.h>
+
+#include "88pm860x-codec.h"
+
+#define MAX_NAME_LEN		20
+#define REG_CACHE_SIZE		0x40
+#define REG_CACHE_BASE		0xb0
+
+/* Status Register 1 (0x01) */
+#define REG_STATUS_1		0x01
+#define MIC_STATUS		(1 << 7)
+#define HOOK_STATUS		(1 << 6)
+#define HEADSET_STATUS		(1 << 5)
+
+/* Mic Detection Register (0x37) */
+#define REG_MIC_DET		0x37
+#define CONTINUOUS_POLLING	(3 << 1)
+#define EN_MIC_DET		(1 << 0)
+#define MICDET_MASK		0x07
+
+/* Headset Detection Register (0x38) */
+#define REG_HS_DET		0x38
+#define EN_HS_DET		(1 << 0)
+
+/* Misc2 Register (0x42) */
+#define REG_MISC2		0x42
+#define AUDIO_PLL		(1 << 5)
+#define AUDIO_SECTION_RESET	(1 << 4)
+#define AUDIO_SECTION_ON	(1 << 3)
+
+/* PCM Interface Register 2 (0xb1) */
+#define PCM_INF2_BCLK		(1 << 6)	/* Bit clock polarity */
+#define PCM_INF2_FS		(1 << 5)	/* Frame Sync polarity */
+#define PCM_INF2_MASTER		(1 << 4)	/* Master / Slave */
+#define PCM_INF2_18WL		(1 << 3)	/* 18 / 16 bits */
+#define PCM_GENERAL_I2S		0
+#define PCM_EXACT_I2S		1
+#define PCM_LEFT_I2S		2
+#define PCM_RIGHT_I2S		3
+#define PCM_SHORT_FS		4
+#define PCM_LONG_FS		5
+#define PCM_MODE_MASK		7
+
+/* I2S Interface Register 4 (0xbe) */
+#define I2S_EQU_BYP		(1 << 6)
+
+/* DAC Offset Register (0xcb) */
+#define DAC_MUTE		(1 << 7)
+#define MUTE_LEFT		(1 << 6)
+#define MUTE_RIGHT		(1 << 2)
+
+/* ADC Analog Register 1 (0xd0) */
+#define REG_ADC_ANA_1		0xd0
+#define MIC1BIAS_MASK		0x60
+
+/* Earpiece/Speaker Control Register 2 (0xda) */
+#define REG_EAR2		0xda
+#define RSYNC_CHANGE		(1 << 2)
+
+/* Audio Supplies Register 2 (0xdc) */
+#define REG_SUPPLIES2		0xdc
+#define LDO15_READY		(1 << 4)
+#define LDO15_EN		(1 << 3)
+#define CPUMP_READY		(1 << 2)
+#define CPUMP_EN		(1 << 1)
+#define AUDIO_EN		(1 << 0)
+#define SUPPLY_MASK		(LDO15_EN | CPUMP_EN | AUDIO_EN)
+
+/* Audio Enable Register 1 (0xdd) */
+#define ADC_MOD_RIGHT		(1 << 1)
+#define ADC_MOD_LEFT		(1 << 0)
+
+/* Audio Enable Register 2 (0xde) */
+#define ADC_LEFT		(1 << 5)
+#define ADC_RIGHT		(1 << 4)
+
+/* DAC Enable Register 2 (0xe1) */
+#define DAC_LEFT		(1 << 5)
+#define DAC_RIGHT		(1 << 4)
+#define MODULATOR		(1 << 3)
+
+/* Shorts Register (0xeb) */
+#define REG_SHORTS		0xeb
+#define CLR_SHORT_LO2		(1 << 7)
+#define SHORT_LO2		(1 << 6)
+#define CLR_SHORT_LO1		(1 << 5)
+#define SHORT_LO1		(1 << 4)
+#define CLR_SHORT_HS2		(1 << 3)
+#define SHORT_HS2		(1 << 2)
+#define CLR_SHORT_HS1		(1 << 1)
+#define SHORT_HS1		(1 << 0)
+
+/*
+ * This widget should be just after DAC & PGA in DAPM power-on sequence and
+ * before DAC & PGA in DAPM power-off sequence.
+ */
+#define PM860X_DAPM_OUTPUT(wname, wevent)	\
+	SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, 0, 0, NULL, 0, wevent, \
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD)
+
+struct pm860x_det {
+	struct snd_soc_jack	*hp_jack;
+	struct snd_soc_jack	*mic_jack;
+	int			hp_det;
+	int			mic_det;
+	int			hook_det;
+	int			hs_shrt;
+	int			lo_shrt;
+};
+
+struct pm860x_priv {
+	unsigned int		sysclk;
+	unsigned int		pcmclk;
+	unsigned int		dir;
+	unsigned int		filter;
+	struct snd_soc_component *component;
+	struct i2c_client	*i2c;
+	struct regmap		*regmap;
+	struct pm860x_chip	*chip;
+	struct pm860x_det	det;
+
+	int			irq[4];
+	unsigned char		name[4][MAX_NAME_LEN+1];
+};
+
+/* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
+static const DECLARE_TLV_DB_SCALE(dpga_tlv, -9450, 150, 1);
+
+/* -9dB to 0db in 3dB steps */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -900, 300, 0);
+
+/* {-23, -17, -13.5, -11, -9, -6, -3, 0}dB */
+static const DECLARE_TLV_DB_RANGE(mic_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(-2300, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(-1700, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(-1350, 0, 0),
+	3, 3, TLV_DB_SCALE_ITEM(-1100, 0, 0),
+	4, 7, TLV_DB_SCALE_ITEM(-900, 300, 0)
+);
+
+/* {0, 0, 0, -6, 0, 6, 12, 18}dB */
+static const DECLARE_TLV_DB_RANGE(aux_tlv,
+	0, 2, TLV_DB_SCALE_ITEM(0, 0, 0),
+	3, 7, TLV_DB_SCALE_ITEM(-600, 600, 0)
+);
+
+/* {-16, -13, -10, -7, -5.2, -3,3, -2.2, 0}dB, mute instead of -16dB */
+static const DECLARE_TLV_DB_RANGE(out_tlv,
+	0, 3, TLV_DB_SCALE_ITEM(-1600, 300, 1),
+	4, 4, TLV_DB_SCALE_ITEM(-520, 0, 0),
+	5, 5, TLV_DB_SCALE_ITEM(-330, 0, 0),
+	6, 7, TLV_DB_SCALE_ITEM(-220, 220, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(st_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(-12041, 602, 0),
+	2, 3, TLV_DB_SCALE_ITEM(-11087, 250, 0),
+	4, 5, TLV_DB_SCALE_ITEM(-10643, 158, 0),
+	6, 7, TLV_DB_SCALE_ITEM(-10351, 116, 0),
+	8, 9, TLV_DB_SCALE_ITEM(-10133, 92, 0),
+	10, 13, TLV_DB_SCALE_ITEM(-9958, 70, 0),
+	14, 17, TLV_DB_SCALE_ITEM(-9689, 53, 0),
+	18, 271, TLV_DB_SCALE_ITEM(-9484, 37, 0)
+);
+
+/* Sidetone Gain = M * 2^(-5-N) */
+struct st_gain {
+	unsigned int	db;
+	unsigned int	m;
+	unsigned int	n;
+};
+
+static struct st_gain st_table[] = {
+	{-12041,  1, 15}, {-11439,  1, 14}, {-11087,  3, 15}, {-10837,  1, 13},
+	{-10643,  5, 15}, {-10485,  3, 14}, {-10351,  7, 15}, {-10235,  1, 12},
+	{-10133,  9, 15}, {-10041,  5, 14}, { -9958, 11, 15}, { -9883,  3, 13},
+	{ -9813, 13, 15}, { -9749,  7, 14}, { -9689, 15, 15}, { -9633,  1, 11},
+	{ -9580, 17, 15}, { -9531,  9, 14}, { -9484, 19, 15}, { -9439,  5, 13},
+	{ -9397, 21, 15}, { -9356, 11, 14}, { -9318, 23, 15}, { -9281,  3, 12},
+	{ -9245, 25, 15}, { -9211, 13, 14}, { -9178, 27, 15}, { -9147,  7, 13},
+	{ -9116, 29, 15}, { -9087, 15, 14}, { -9058, 31, 15}, { -9031,  1, 10},
+	{ -8978, 17, 14}, { -8929,  9, 13}, { -8882, 19, 14}, { -8837,  5, 12},
+	{ -8795, 21, 14}, { -8754, 11, 13}, { -8716, 23, 14}, { -8679,  3, 11},
+	{ -8643, 25, 14}, { -8609, 13, 13}, { -8576, 27, 14}, { -8545,  7, 12},
+	{ -8514, 29, 14}, { -8485, 15, 13}, { -8456, 31, 14}, { -8429,  1,  9},
+	{ -8376, 17, 13}, { -8327,  9, 12}, { -8280, 19, 13}, { -8235,  5, 11},
+	{ -8193, 21, 13}, { -8152, 11, 12}, { -8114, 23, 13}, { -8077,  3, 10},
+	{ -8041, 25, 13}, { -8007, 13, 12}, { -7974, 27, 13}, { -7943,  7, 11},
+	{ -7912, 29, 13}, { -7883, 15, 12}, { -7854, 31, 13}, { -7827,  1,  8},
+	{ -7774, 17, 12}, { -7724,  9, 11}, { -7678, 19, 12}, { -7633,  5, 10},
+	{ -7591, 21, 12}, { -7550, 11, 11}, { -7512, 23, 12}, { -7475,  3,  9},
+	{ -7439, 25, 12}, { -7405, 13, 11}, { -7372, 27, 12}, { -7341,  7, 10},
+	{ -7310, 29, 12}, { -7281, 15, 11}, { -7252, 31, 12}, { -7225,  1,  7},
+	{ -7172, 17, 11}, { -7122,  9, 10}, { -7075, 19, 11}, { -7031,  5,  9},
+	{ -6989, 21, 11}, { -6948, 11, 10}, { -6910, 23, 11}, { -6873,  3,  8},
+	{ -6837, 25, 11}, { -6803, 13, 10}, { -6770, 27, 11}, { -6739,  7,  9},
+	{ -6708, 29, 11}, { -6679, 15, 10}, { -6650, 31, 11}, { -6623,  1,  6},
+	{ -6570, 17, 10}, { -6520,  9,  9}, { -6473, 19, 10}, { -6429,  5,  8},
+	{ -6386, 21, 10}, { -6346, 11,  9}, { -6307, 23, 10}, { -6270,  3,  7},
+	{ -6235, 25, 10}, { -6201, 13,  9}, { -6168, 27, 10}, { -6137,  7,  8},
+	{ -6106, 29, 10}, { -6077, 15,  9}, { -6048, 31, 10}, { -6021,  1,  5},
+	{ -5968, 17,  9}, { -5918,  9,  8}, { -5871, 19,  9}, { -5827,  5,  7},
+	{ -5784, 21,  9}, { -5744, 11,  8}, { -5705, 23,  9}, { -5668,  3,  6},
+	{ -5633, 25,  9}, { -5599, 13,  8}, { -5566, 27,  9}, { -5535,  7,  7},
+	{ -5504, 29,  9}, { -5475, 15,  8}, { -5446, 31,  9}, { -5419,  1,  4},
+	{ -5366, 17,  8}, { -5316,  9,  7}, { -5269, 19,  8}, { -5225,  5,  6},
+	{ -5182, 21,  8}, { -5142, 11,  7}, { -5103, 23,  8}, { -5066,  3,  5},
+	{ -5031, 25,  8}, { -4997, 13,  7}, { -4964, 27,  8}, { -4932,  7,  6},
+	{ -4902, 29,  8}, { -4873, 15,  7}, { -4844, 31,  8}, { -4816,  1,  3},
+	{ -4764, 17,  7}, { -4714,  9,  6}, { -4667, 19,  7}, { -4623,  5,  5},
+	{ -4580, 21,  7}, { -4540, 11,  6}, { -4501, 23,  7}, { -4464,  3,  4},
+	{ -4429, 25,  7}, { -4395, 13,  6}, { -4362, 27,  7}, { -4330,  7,  5},
+	{ -4300, 29,  7}, { -4270, 15,  6}, { -4242, 31,  7}, { -4214,  1,  2},
+	{ -4162, 17,  6}, { -4112,  9,  5}, { -4065, 19,  6}, { -4021,  5,  4},
+	{ -3978, 21,  6}, { -3938, 11,  5}, { -3899, 23,  6}, { -3862,  3,  3},
+	{ -3827, 25,  6}, { -3793, 13,  5}, { -3760, 27,  6}, { -3728,  7,  4},
+	{ -3698, 29,  6}, { -3668, 15,  5}, { -3640, 31,  6}, { -3612,  1,  1},
+	{ -3560, 17,  5}, { -3510,  9,  4}, { -3463, 19,  5}, { -3419,  5,  3},
+	{ -3376, 21,  5}, { -3336, 11,  4}, { -3297, 23,  5}, { -3260,  3,  2},
+	{ -3225, 25,  5}, { -3191, 13,  4}, { -3158, 27,  5}, { -3126,  7,  3},
+	{ -3096, 29,  5}, { -3066, 15,  4}, { -3038, 31,  5}, { -3010,  1,  0},
+	{ -2958, 17,  4}, { -2908,  9,  3}, { -2861, 19,  4}, { -2816,  5,  2},
+	{ -2774, 21,  4}, { -2734, 11,  3}, { -2695, 23,  4}, { -2658,  3,  1},
+	{ -2623, 25,  4}, { -2589, 13,  3}, { -2556, 27,  4}, { -2524,  7,  2},
+	{ -2494, 29,  4}, { -2464, 15,  3}, { -2436, 31,  4}, { -2408,  2,  0},
+	{ -2356, 17,  3}, { -2306,  9,  2}, { -2259, 19,  3}, { -2214,  5,  1},
+	{ -2172, 21,  3}, { -2132, 11,  2}, { -2093, 23,  3}, { -2056,  3,  0},
+	{ -2021, 25,  3}, { -1987, 13,  2}, { -1954, 27,  3}, { -1922,  7,  1},
+	{ -1892, 29,  3}, { -1862, 15,  2}, { -1834, 31,  3}, { -1806,  4,  0},
+	{ -1754, 17,  2}, { -1704,  9,  1}, { -1657, 19,  2}, { -1612,  5,  0},
+	{ -1570, 21,  2}, { -1530, 11,  1}, { -1491, 23,  2}, { -1454,  6,  0},
+	{ -1419, 25,  2}, { -1384, 13,  1}, { -1352, 27,  2}, { -1320,  7,  0},
+	{ -1290, 29,  2}, { -1260, 15,  1}, { -1232, 31,  2}, { -1204,  8,  0},
+	{ -1151, 17,  1}, { -1102,  9,  0}, { -1055, 19,  1}, { -1010, 10,  0},
+	{  -968, 21,  1}, {  -928, 11,  0}, {  -889, 23,  1}, {  -852, 12,  0},
+	{  -816, 25,  1}, {  -782, 13,  0}, {  -750, 27,  1}, {  -718, 14,  0},
+	{  -688, 29,  1}, {  -658, 15,  0}, {  -630, 31,  1}, {  -602, 16,  0},
+	{  -549, 17,  0}, {  -500, 18,  0}, {  -453, 19,  0}, {  -408, 20,  0},
+	{  -366, 21,  0}, {  -325, 22,  0}, {  -287, 23,  0}, {  -250, 24,  0},
+	{  -214, 25,  0}, {  -180, 26,  0}, {  -148, 27,  0}, {  -116, 28,  0},
+	{   -86, 29,  0}, {   -56, 30,  0}, {   -28, 31,  0}, {     0,  0,  0},
+};
+
+static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	int val[2], val2[2], i;
+
+	val[0] = snd_soc_component_read32(component, reg) & 0x3f;
+	val[1] = (snd_soc_component_read32(component, PM860X_SIDETONE_SHIFT) >> 4) & 0xf;
+	val2[0] = snd_soc_component_read32(component, reg2) & 0x3f;
+	val2[1] = (snd_soc_component_read32(component, PM860X_SIDETONE_SHIFT)) & 0xf;
+
+	for (i = 0; i < ARRAY_SIZE(st_table); i++) {
+		if ((st_table[i].m == val[0]) && (st_table[i].n == val[1]))
+			ucontrol->value.integer.value[0] = i;
+		if ((st_table[i].m == val2[0]) && (st_table[i].n == val2[1]))
+			ucontrol->value.integer.value[1] = i;
+	}
+	return 0;
+}
+
+static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	int err;
+	unsigned int val, val2;
+
+	val = ucontrol->value.integer.value[0];
+	val2 = ucontrol->value.integer.value[1];
+
+	if (val >= ARRAY_SIZE(st_table) || val2 >= ARRAY_SIZE(st_table))
+		return -EINVAL;
+
+	err = snd_soc_component_update_bits(component, reg, 0x3f, st_table[val].m);
+	if (err < 0)
+		return err;
+	err = snd_soc_component_update_bits(component, PM860X_SIDETONE_SHIFT, 0xf0,
+				  st_table[val].n << 4);
+	if (err < 0)
+		return err;
+
+	err = snd_soc_component_update_bits(component, reg2, 0x3f, st_table[val2].m);
+	if (err < 0)
+		return err;
+	err = snd_soc_component_update_bits(component, PM860X_SIDETONE_SHIFT, 0x0f,
+				  st_table[val2].n);
+	return err;
+}
+
+static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	unsigned int shift = mc->shift;
+	int max = mc->max, val, val2;
+	unsigned int mask = (1 << fls(max)) - 1;
+
+	val = snd_soc_component_read32(component, reg) >> shift;
+	val2 = snd_soc_component_read32(component, reg2) >> shift;
+	ucontrol->value.integer.value[0] = (max - val) & mask;
+	ucontrol->value.integer.value[1] = (max - val2) & mask;
+
+	return 0;
+}
+
+static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	unsigned int shift = mc->shift;
+	int max = mc->max;
+	unsigned int mask = (1 << fls(max)) - 1;
+	int err;
+	unsigned int val, val2, val_mask;
+
+	val_mask = mask << shift;
+	val = ((max - ucontrol->value.integer.value[0]) & mask);
+	val2 = ((max - ucontrol->value.integer.value[1]) & mask);
+
+	val = val << shift;
+	val2 = val2 << shift;
+
+	err = snd_soc_component_update_bits(component, reg, val_mask, val);
+	if (err < 0)
+		return err;
+
+	err = snd_soc_component_update_bits(component, reg2, val_mask, val2);
+	return err;
+}
+
+/* DAPM Widget Events */
+/*
+ * A lot registers are belong to RSYNC domain. It requires enabling RSYNC bit
+ * after updating these registers. Otherwise, these updated registers won't
+ * be effective.
+ */
+static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	/*
+	 * In order to avoid current on the load, mute power-on and power-off
+	 * should be transients.
+	 * Unmute by DAC_MUTE. It should be unmuted when DAPM sequence is
+	 * finished.
+	 */
+	snd_soc_component_update_bits(component, PM860X_DAC_OFFSET, DAC_MUTE, 0);
+	snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
+			    RSYNC_CHANGE, RSYNC_CHANGE);
+	return 0;
+}
+
+static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	unsigned int dac = 0;
+	int data;
+
+	if (!strcmp(w->name, "Left DAC"))
+		dac = DAC_LEFT;
+	if (!strcmp(w->name, "Right DAC"))
+		dac = DAC_RIGHT;
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (dac) {
+			/* Auto mute in power-on sequence. */
+			dac |= MODULATOR;
+			snd_soc_component_update_bits(component, PM860X_DAC_OFFSET,
+					    DAC_MUTE, DAC_MUTE);
+			snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
+					    RSYNC_CHANGE, RSYNC_CHANGE);
+			/* update dac */
+			snd_soc_component_update_bits(component, PM860X_DAC_EN_2,
+					    dac, dac);
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		if (dac) {
+			/* Auto mute in power-off sequence. */
+			snd_soc_component_update_bits(component, PM860X_DAC_OFFSET,
+					    DAC_MUTE, DAC_MUTE);
+			snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
+					    RSYNC_CHANGE, RSYNC_CHANGE);
+			/* update dac */
+			data = snd_soc_component_read32(component, PM860X_DAC_EN_2);
+			data &= ~dac;
+			if (!(data & (DAC_LEFT | DAC_RIGHT)))
+				data &= ~MODULATOR;
+			snd_soc_component_write(component, PM860X_DAC_EN_2, data);
+		}
+		break;
+	}
+	return 0;
+}
+
+static const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"};
+
+static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"};
+
+static SOC_ENUM_SINGLE_DECL(pm860x_hs1_opamp_enum,
+			    PM860X_HS1_CTRL, 5, pm860x_opamp_texts);
+
+static SOC_ENUM_SINGLE_DECL(pm860x_hs2_opamp_enum,
+			    PM860X_HS2_CTRL, 5, pm860x_opamp_texts);
+
+static SOC_ENUM_SINGLE_DECL(pm860x_hs1_pa_enum,
+			    PM860X_HS1_CTRL, 3, pm860x_pa_texts);
+
+static SOC_ENUM_SINGLE_DECL(pm860x_hs2_pa_enum,
+			    PM860X_HS2_CTRL, 3, pm860x_pa_texts);
+
+static SOC_ENUM_SINGLE_DECL(pm860x_lo1_opamp_enum,
+			    PM860X_LO1_CTRL, 5, pm860x_opamp_texts);
+
+static SOC_ENUM_SINGLE_DECL(pm860x_lo2_opamp_enum,
+			    PM860X_LO2_CTRL, 5, pm860x_opamp_texts);
+
+static SOC_ENUM_SINGLE_DECL(pm860x_lo1_pa_enum,
+			    PM860X_LO1_CTRL, 3, pm860x_pa_texts);
+
+static SOC_ENUM_SINGLE_DECL(pm860x_lo2_pa_enum,
+			    PM860X_LO2_CTRL, 3, pm860x_pa_texts);
+
+static SOC_ENUM_SINGLE_DECL(pm860x_spk_pa_enum,
+			    PM860X_EAR_CTRL_1, 5, pm860x_pa_texts);
+
+static SOC_ENUM_SINGLE_DECL(pm860x_ear_pa_enum,
+			    PM860X_EAR_CTRL_2, 0, pm860x_pa_texts);
+
+static SOC_ENUM_SINGLE_DECL(pm860x_spk_ear_opamp_enum,
+			    PM860X_EAR_CTRL_1, 3, pm860x_opamp_texts);
+
+static const struct snd_kcontrol_new pm860x_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2,
+			PM860X_ADC_ANA_3, 6, 3, 0, adc_tlv),
+	SOC_DOUBLE_TLV("AUX Capture Volume", PM860X_ADC_ANA_3, 0, 3, 7, 0,
+			aux_tlv),
+	SOC_SINGLE_TLV("MIC1 Capture Volume", PM860X_ADC_ANA_2, 0, 7, 0,
+			mic_tlv),
+	SOC_SINGLE_TLV("MIC3 Capture Volume", PM860X_ADC_ANA_2, 3, 7, 0,
+			mic_tlv),
+	SOC_DOUBLE_R_EXT_TLV("Sidetone Volume", PM860X_SIDETONE_L_GAIN,
+			     PM860X_SIDETONE_R_GAIN, 0, ARRAY_SIZE(st_table)-1,
+			     0, snd_soc_get_volsw_2r_st,
+			     snd_soc_put_volsw_2r_st, st_tlv),
+	SOC_SINGLE_TLV("Speaker Playback Volume", PM860X_EAR_CTRL_1,
+			0, 7, 0, out_tlv),
+	SOC_DOUBLE_R_TLV("Line Playback Volume", PM860X_LO1_CTRL,
+			 PM860X_LO2_CTRL, 0, 7, 0, out_tlv),
+	SOC_DOUBLE_R_TLV("Headset Playback Volume", PM860X_HS1_CTRL,
+			 PM860X_HS2_CTRL, 0, 7, 0, out_tlv),
+	SOC_DOUBLE_R_EXT_TLV("Hifi Left Playback Volume",
+			     PM860X_HIFIL_GAIN_LEFT,
+			     PM860X_HIFIL_GAIN_RIGHT, 0, 63, 0,
+			     snd_soc_get_volsw_2r_out,
+			     snd_soc_put_volsw_2r_out, dpga_tlv),
+	SOC_DOUBLE_R_EXT_TLV("Hifi Right Playback Volume",
+			     PM860X_HIFIR_GAIN_LEFT,
+			     PM860X_HIFIR_GAIN_RIGHT, 0, 63, 0,
+			     snd_soc_get_volsw_2r_out,
+			     snd_soc_put_volsw_2r_out, dpga_tlv),
+	SOC_DOUBLE_R_EXT_TLV("Lofi Playback Volume", PM860X_LOFI_GAIN_LEFT,
+			     PM860X_LOFI_GAIN_RIGHT, 0, 63, 0,
+			     snd_soc_get_volsw_2r_out,
+			     snd_soc_put_volsw_2r_out, dpga_tlv),
+	SOC_ENUM("Headset1 Operational Amplifier Current",
+		 pm860x_hs1_opamp_enum),
+	SOC_ENUM("Headset2 Operational Amplifier Current",
+		 pm860x_hs2_opamp_enum),
+	SOC_ENUM("Headset1 Amplifier Current", pm860x_hs1_pa_enum),
+	SOC_ENUM("Headset2 Amplifier Current", pm860x_hs2_pa_enum),
+	SOC_ENUM("Lineout1 Operational Amplifier Current",
+		 pm860x_lo1_opamp_enum),
+	SOC_ENUM("Lineout2 Operational Amplifier Current",
+		 pm860x_lo2_opamp_enum),
+	SOC_ENUM("Lineout1 Amplifier Current", pm860x_lo1_pa_enum),
+	SOC_ENUM("Lineout2 Amplifier Current", pm860x_lo2_pa_enum),
+	SOC_ENUM("Speaker Operational Amplifier Current",
+		 pm860x_spk_ear_opamp_enum),
+	SOC_ENUM("Speaker Amplifier Current", pm860x_spk_pa_enum),
+	SOC_ENUM("Earpiece Amplifier Current", pm860x_ear_pa_enum),
+};
+
+/*
+ * DAPM Controls
+ */
+
+/* PCM Switch / PCM Interface */
+static const struct snd_kcontrol_new pcm_switch_controls =
+	SOC_DAPM_SINGLE("Switch", PM860X_ADC_EN_2, 0, 1, 0);
+
+/* AUX1 Switch */
+static const struct snd_kcontrol_new aux1_switch_controls =
+	SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 4, 1, 0);
+
+/* AUX2 Switch */
+static const struct snd_kcontrol_new aux2_switch_controls =
+	SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 5, 1, 0);
+
+/* Left Ex. PA Switch */
+static const struct snd_kcontrol_new lepa_switch_controls =
+	SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 2, 1, 0);
+
+/* Right Ex. PA Switch */
+static const struct snd_kcontrol_new repa_switch_controls =
+	SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 1, 1, 0);
+
+/* PCM Mux / Mux7 */
+static const char *aif1_text[] = {
+	"PCM L", "PCM R",
+};
+
+static SOC_ENUM_SINGLE_DECL(aif1_enum,
+			    PM860X_PCM_IFACE_3, 6, aif1_text);
+
+static const struct snd_kcontrol_new aif1_mux =
+	SOC_DAPM_ENUM("PCM Mux", aif1_enum);
+
+/* I2S Mux / Mux9 */
+static const char *i2s_din_text[] = {
+	"DIN", "DIN1",
+};
+
+static SOC_ENUM_SINGLE_DECL(i2s_din_enum,
+			    PM860X_I2S_IFACE_3, 1, i2s_din_text);
+
+static const struct snd_kcontrol_new i2s_din_mux =
+	SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum);
+
+/* I2S Mic Mux / Mux8 */
+static const char *i2s_mic_text[] = {
+	"Ex PA", "ADC",
+};
+
+static SOC_ENUM_SINGLE_DECL(i2s_mic_enum,
+			    PM860X_I2S_IFACE_3, 4, i2s_mic_text);
+
+static const struct snd_kcontrol_new i2s_mic_mux =
+	SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum);
+
+/* ADCL Mux / Mux2 */
+static const char *adcl_text[] = {
+	"ADCR", "ADCL",
+};
+
+static SOC_ENUM_SINGLE_DECL(adcl_enum,
+			    PM860X_PCM_IFACE_3, 4, adcl_text);
+
+static const struct snd_kcontrol_new adcl_mux =
+	SOC_DAPM_ENUM("ADC Left Mux", adcl_enum);
+
+/* ADCR Mux / Mux3 */
+static const char *adcr_text[] = {
+	"ADCL", "ADCR",
+};
+
+static SOC_ENUM_SINGLE_DECL(adcr_enum,
+			    PM860X_PCM_IFACE_3, 2, adcr_text);
+
+static const struct snd_kcontrol_new adcr_mux =
+	SOC_DAPM_ENUM("ADC Right Mux", adcr_enum);
+
+/* ADCR EC Mux / Mux6 */
+static const char *adcr_ec_text[] = {
+	"ADCR", "EC",
+};
+
+static SOC_ENUM_SINGLE_DECL(adcr_ec_enum,
+			    PM860X_ADC_EN_2, 3, adcr_ec_text);
+
+static const struct snd_kcontrol_new adcr_ec_mux =
+	SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum);
+
+/* EC Mux / Mux4 */
+static const char *ec_text[] = {
+	"Left", "Right", "Left + Right",
+};
+
+static SOC_ENUM_SINGLE_DECL(ec_enum,
+			    PM860X_EC_PATH, 1, ec_text);
+
+static const struct snd_kcontrol_new ec_mux =
+	SOC_DAPM_ENUM("EC Mux", ec_enum);
+
+static const char *dac_text[] = {
+	"No input", "Right", "Left", "No input",
+};
+
+/* DAC Headset 1 Mux / Mux10 */
+static SOC_ENUM_SINGLE_DECL(dac_hs1_enum,
+			    PM860X_ANA_INPUT_SEL_1, 0, dac_text);
+
+static const struct snd_kcontrol_new dac_hs1_mux =
+	SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum);
+
+/* DAC Headset 2 Mux / Mux11 */
+static SOC_ENUM_SINGLE_DECL(dac_hs2_enum,
+			    PM860X_ANA_INPUT_SEL_1, 2, dac_text);
+
+static const struct snd_kcontrol_new dac_hs2_mux =
+	SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum);
+
+/* DAC Lineout 1 Mux / Mux12 */
+static SOC_ENUM_SINGLE_DECL(dac_lo1_enum,
+			    PM860X_ANA_INPUT_SEL_1, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_lo1_mux =
+	SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum);
+
+/* DAC Lineout 2 Mux / Mux13 */
+static SOC_ENUM_SINGLE_DECL(dac_lo2_enum,
+			    PM860X_ANA_INPUT_SEL_1, 6, dac_text);
+
+static const struct snd_kcontrol_new dac_lo2_mux =
+	SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum);
+
+/* DAC Spearker Earphone Mux / Mux14 */
+static SOC_ENUM_SINGLE_DECL(dac_spk_ear_enum,
+			    PM860X_ANA_INPUT_SEL_2, 0, dac_text);
+
+static const struct snd_kcontrol_new dac_spk_ear_mux =
+	SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum);
+
+/* Headset 1 Mux / Mux15 */
+static const char *in_text[] = {
+	"Digital", "Analog",
+};
+
+static SOC_ENUM_SINGLE_DECL(hs1_enum,
+			    PM860X_ANA_TO_ANA, 0, in_text);
+
+static const struct snd_kcontrol_new hs1_mux =
+	SOC_DAPM_ENUM("Headset1 Mux", hs1_enum);
+
+/* Headset 2 Mux / Mux16 */
+static SOC_ENUM_SINGLE_DECL(hs2_enum,
+			    PM860X_ANA_TO_ANA, 1, in_text);
+
+static const struct snd_kcontrol_new hs2_mux =
+	SOC_DAPM_ENUM("Headset2 Mux", hs2_enum);
+
+/* Lineout 1 Mux / Mux17 */
+static SOC_ENUM_SINGLE_DECL(lo1_enum,
+			    PM860X_ANA_TO_ANA, 2, in_text);
+
+static const struct snd_kcontrol_new lo1_mux =
+	SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum);
+
+/* Lineout 2 Mux / Mux18 */
+static SOC_ENUM_SINGLE_DECL(lo2_enum,
+			    PM860X_ANA_TO_ANA, 3, in_text);
+
+static const struct snd_kcontrol_new lo2_mux =
+	SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum);
+
+/* Speaker Earpiece Demux */
+static const char *spk_text[] = {
+	"Earpiece", "Speaker",
+};
+
+static SOC_ENUM_SINGLE_DECL(spk_enum,
+			    PM860X_ANA_TO_ANA, 6, spk_text);
+
+static const struct snd_kcontrol_new spk_demux =
+	SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum);
+
+/* MIC Mux / Mux1 */
+static const char *mic_text[] = {
+	"Mic 1", "Mic 2",
+};
+
+static SOC_ENUM_SINGLE_DECL(mic_enum,
+			    PM860X_ADC_ANA_4, 4, mic_text);
+
+static const struct snd_kcontrol_new mic_mux =
+	SOC_DAPM_ENUM("MIC Mux", mic_enum);
+
+static const struct snd_soc_dapm_widget pm860x_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("PCM SDI", "PCM Playback", 0,
+			    PM860X_ADC_EN_2, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("PCM SDO", "PCM Capture", 0,
+			     PM860X_PCM_IFACE_3, 1, 1),
+
+
+	SND_SOC_DAPM_AIF_IN("I2S DIN", "I2S Playback", 0,
+			    SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("I2S DIN1", "I2S Playback", 0,
+			    SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S DOUT", "I2S Capture", 0,
+			     PM860X_I2S_IFACE_3, 5, 1),
+	SND_SOC_DAPM_SUPPLY("I2S CLK", PM860X_DAC_EN_2, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("I2S Mic Mux", SND_SOC_NOPM, 0, 0, &i2s_mic_mux),
+	SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adcl_mux),
+	SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcr_mux),
+	SND_SOC_DAPM_MUX("EC Mux", SND_SOC_NOPM, 0, 0, &ec_mux),
+	SND_SOC_DAPM_MUX("ADCR EC Mux", SND_SOC_NOPM, 0, 0, &adcr_ec_mux),
+	SND_SOC_DAPM_SWITCH("Left EPA", SND_SOC_NOPM, 0, 0,
+			    &lepa_switch_controls),
+	SND_SOC_DAPM_SWITCH("Right EPA", SND_SOC_NOPM, 0, 0,
+			    &repa_switch_controls),
+
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Left ADC MOD", PM860X_ADC_EN_1,
+			 0, 1, 1, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Right ADC MOD", PM860X_ADC_EN_1,
+			 1, 1, 1, 0),
+	SND_SOC_DAPM_ADC("Left ADC", NULL, PM860X_ADC_EN_2, 5, 0),
+	SND_SOC_DAPM_ADC("Right ADC", NULL, PM860X_ADC_EN_2, 4, 0),
+
+	SND_SOC_DAPM_SWITCH("AUX1 Switch", SND_SOC_NOPM, 0, 0,
+			    &aux1_switch_controls),
+	SND_SOC_DAPM_SWITCH("AUX2 Switch", SND_SOC_NOPM, 0, 0,
+			    &aux2_switch_controls),
+
+	SND_SOC_DAPM_MUX("MIC Mux", SND_SOC_NOPM, 0, 0, &mic_mux),
+	SND_SOC_DAPM_MICBIAS("Mic1 Bias", PM860X_ADC_ANA_1, 2, 0),
+	SND_SOC_DAPM_MICBIAS("Mic3 Bias", PM860X_ADC_ANA_1, 7, 0),
+	SND_SOC_DAPM_PGA("MIC1 Volume", PM860X_ADC_EN_1, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MIC3 Volume", PM860X_ADC_EN_1, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUX1 Volume", PM860X_ADC_EN_1, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUX2 Volume", PM860X_ADC_EN_1, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Sidetone PGA", PM860X_ADC_EN_2, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Lofi PGA", PM860X_ADC_EN_2, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_INPUT("AUX1"),
+	SND_SOC_DAPM_INPUT("AUX2"),
+	SND_SOC_DAPM_INPUT("MIC1P"),
+	SND_SOC_DAPM_INPUT("MIC1N"),
+	SND_SOC_DAPM_INPUT("MIC2P"),
+	SND_SOC_DAPM_INPUT("MIC2N"),
+	SND_SOC_DAPM_INPUT("MIC3P"),
+	SND_SOC_DAPM_INPUT("MIC3N"),
+
+	SND_SOC_DAPM_DAC_E("Left DAC", NULL, SND_SOC_NOPM, 0, 0,
+			   pm860x_dac_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_DAC_E("Right DAC", NULL, SND_SOC_NOPM, 0, 0,
+			   pm860x_dac_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_MUX("I2S DIN Mux", SND_SOC_NOPM, 0, 0, &i2s_din_mux),
+	SND_SOC_DAPM_MUX("DAC HS1 Mux", SND_SOC_NOPM, 0, 0, &dac_hs1_mux),
+	SND_SOC_DAPM_MUX("DAC HS2 Mux", SND_SOC_NOPM, 0, 0, &dac_hs2_mux),
+	SND_SOC_DAPM_MUX("DAC LO1 Mux", SND_SOC_NOPM, 0, 0, &dac_lo1_mux),
+	SND_SOC_DAPM_MUX("DAC LO2 Mux", SND_SOC_NOPM, 0, 0, &dac_lo2_mux),
+	SND_SOC_DAPM_MUX("DAC SP Mux", SND_SOC_NOPM, 0, 0, &dac_spk_ear_mux),
+	SND_SOC_DAPM_MUX("Headset1 Mux", SND_SOC_NOPM, 0, 0, &hs1_mux),
+	SND_SOC_DAPM_MUX("Headset2 Mux", SND_SOC_NOPM, 0, 0, &hs2_mux),
+	SND_SOC_DAPM_MUX("Lineout1 Mux", SND_SOC_NOPM, 0, 0, &lo1_mux),
+	SND_SOC_DAPM_MUX("Lineout2 Mux", SND_SOC_NOPM, 0, 0, &lo2_mux),
+	SND_SOC_DAPM_MUX("Speaker Earpiece Demux", SND_SOC_NOPM, 0, 0,
+			 &spk_demux),
+
+
+	SND_SOC_DAPM_PGA("Headset1 PGA", PM860X_DAC_EN_1, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Headset2 PGA", PM860X_DAC_EN_1, 1, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("HS1"),
+	SND_SOC_DAPM_OUTPUT("HS2"),
+	SND_SOC_DAPM_PGA("Lineout1 PGA", PM860X_DAC_EN_1, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Lineout2 PGA", PM860X_DAC_EN_1, 3, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+	SND_SOC_DAPM_PGA("Earpiece PGA", PM860X_DAC_EN_1, 4, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("EARP"),
+	SND_SOC_DAPM_OUTPUT("EARN"),
+	SND_SOC_DAPM_PGA("Speaker PGA", PM860X_DAC_EN_1, 5, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("LSP"),
+	SND_SOC_DAPM_OUTPUT("LSN"),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "VCODEC", PM860X_AUDIO_SUPPLIES_2,
+			 0, SUPPLY_MASK, SUPPLY_MASK, 0),
+
+	PM860X_DAPM_OUTPUT("RSYNC", pm860x_rsync_event),
+};
+
+static const struct snd_soc_dapm_route pm860x_dapm_routes[] = {
+	/* supply */
+	{"Left DAC", NULL, "VCODEC"},
+	{"Right DAC", NULL, "VCODEC"},
+	{"Left ADC", NULL, "VCODEC"},
+	{"Right ADC", NULL, "VCODEC"},
+	{"Left ADC", NULL, "Left ADC MOD"},
+	{"Right ADC", NULL, "Right ADC MOD"},
+
+	/* I2S Clock */
+	{"I2S DIN", NULL, "I2S CLK"},
+	{"I2S DIN1", NULL, "I2S CLK"},
+	{"I2S DOUT", NULL, "I2S CLK"},
+
+	/* PCM/AIF1 Inputs */
+	{"PCM SDO", NULL, "ADC Left Mux"},
+	{"PCM SDO", NULL, "ADCR EC Mux"},
+
+	/* PCM/AFI2 Outputs */
+	{"Lofi PGA", NULL, "PCM SDI"},
+	{"Lofi PGA", NULL, "Sidetone PGA"},
+	{"Left DAC", NULL, "Lofi PGA"},
+	{"Right DAC", NULL, "Lofi PGA"},
+
+	/* I2S/AIF2 Inputs */
+	{"MIC Mux", "Mic 1", "MIC1P"},
+	{"MIC Mux", "Mic 1", "MIC1N"},
+	{"MIC Mux", "Mic 2", "MIC2P"},
+	{"MIC Mux", "Mic 2", "MIC2N"},
+	{"MIC1 Volume", NULL, "MIC Mux"},
+	{"MIC3 Volume", NULL, "MIC3P"},
+	{"MIC3 Volume", NULL, "MIC3N"},
+	{"Left ADC", NULL, "MIC1 Volume"},
+	{"Right ADC", NULL, "MIC3 Volume"},
+	{"ADC Left Mux", "ADCR", "Right ADC"},
+	{"ADC Left Mux", "ADCL", "Left ADC"},
+	{"ADC Right Mux", "ADCL", "Left ADC"},
+	{"ADC Right Mux", "ADCR", "Right ADC"},
+	{"Left EPA", "Switch", "Left DAC"},
+	{"Right EPA", "Switch", "Right DAC"},
+	{"EC Mux", "Left", "Left DAC"},
+	{"EC Mux", "Right", "Right DAC"},
+	{"EC Mux", "Left + Right", "Left DAC"},
+	{"EC Mux", "Left + Right", "Right DAC"},
+	{"ADCR EC Mux", "ADCR", "ADC Right Mux"},
+	{"ADCR EC Mux", "EC", "EC Mux"},
+	{"I2S Mic Mux", "Ex PA", "Left EPA"},
+	{"I2S Mic Mux", "Ex PA", "Right EPA"},
+	{"I2S Mic Mux", "ADC", "ADC Left Mux"},
+	{"I2S Mic Mux", "ADC", "ADCR EC Mux"},
+	{"I2S DOUT", NULL, "I2S Mic Mux"},
+
+	/* I2S/AIF2 Outputs */
+	{"I2S DIN Mux", "DIN", "I2S DIN"},
+	{"I2S DIN Mux", "DIN1", "I2S DIN1"},
+	{"Left DAC", NULL, "I2S DIN Mux"},
+	{"Right DAC", NULL, "I2S DIN Mux"},
+	{"DAC HS1 Mux", "Left", "Left DAC"},
+	{"DAC HS1 Mux", "Right", "Right DAC"},
+	{"DAC HS2 Mux", "Left", "Left DAC"},
+	{"DAC HS2 Mux", "Right", "Right DAC"},
+	{"DAC LO1 Mux", "Left", "Left DAC"},
+	{"DAC LO1 Mux", "Right", "Right DAC"},
+	{"DAC LO2 Mux", "Left", "Left DAC"},
+	{"DAC LO2 Mux", "Right", "Right DAC"},
+	{"Headset1 Mux", "Digital", "DAC HS1 Mux"},
+	{"Headset2 Mux", "Digital", "DAC HS2 Mux"},
+	{"Lineout1 Mux", "Digital", "DAC LO1 Mux"},
+	{"Lineout2 Mux", "Digital", "DAC LO2 Mux"},
+	{"Headset1 PGA", NULL, "Headset1 Mux"},
+	{"Headset2 PGA", NULL, "Headset2 Mux"},
+	{"Lineout1 PGA", NULL, "Lineout1 Mux"},
+	{"Lineout2 PGA", NULL, "Lineout2 Mux"},
+	{"DAC SP Mux", "Left", "Left DAC"},
+	{"DAC SP Mux", "Right", "Right DAC"},
+	{"Speaker Earpiece Demux", "Speaker", "DAC SP Mux"},
+	{"Speaker PGA", NULL, "Speaker Earpiece Demux"},
+	{"Earpiece PGA", NULL, "Speaker Earpiece Demux"},
+
+	{"RSYNC", NULL, "Headset1 PGA"},
+	{"RSYNC", NULL, "Headset2 PGA"},
+	{"RSYNC", NULL, "Lineout1 PGA"},
+	{"RSYNC", NULL, "Lineout2 PGA"},
+	{"RSYNC", NULL, "Speaker PGA"},
+	{"RSYNC", NULL, "Speaker PGA"},
+	{"RSYNC", NULL, "Earpiece PGA"},
+	{"RSYNC", NULL, "Earpiece PGA"},
+
+	{"HS1", NULL, "RSYNC"},
+	{"HS2", NULL, "RSYNC"},
+	{"LINEOUT1", NULL, "RSYNC"},
+	{"LINEOUT2", NULL, "RSYNC"},
+	{"LSP", NULL, "RSYNC"},
+	{"LSN", NULL, "RSYNC"},
+	{"EARP", NULL, "RSYNC"},
+	{"EARN", NULL, "RSYNC"},
+};
+
+/*
+ * Use MUTE_LEFT & MUTE_RIGHT to implement digital mute.
+ * These bits can also be used to mute.
+ */
+static int pm860x_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	int data = 0, mask = MUTE_LEFT | MUTE_RIGHT;
+
+	if (mute)
+		data = mask;
+	snd_soc_component_update_bits(component, PM860X_DAC_OFFSET, mask, data);
+	snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
+			    RSYNC_CHANGE, RSYNC_CHANGE);
+	return 0;
+}
+
+static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned char inf = 0, mask = 0;
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		inf &= ~PCM_INF2_18WL;
+		break;
+	case 18:
+		inf |= PCM_INF2_18WL;
+		break;
+	default:
+		return -EINVAL;
+	}
+	mask |= PCM_INF2_18WL;
+	snd_soc_component_update_bits(component, PM860X_PCM_IFACE_2, mask, inf);
+
+	/* sample rate */
+	switch (params_rate(params)) {
+	case 8000:
+		inf = 0;
+		break;
+	case 16000:
+		inf = 3;
+		break;
+	case 32000:
+		inf = 6;
+		break;
+	case 48000:
+		inf = 8;
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, PM860X_PCM_RATE, 0x0f, inf);
+
+	return 0;
+}
+
+static int pm860x_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				  unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
+	unsigned char inf = 0, mask = 0;
+	int ret = -EINVAL;
+
+	mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+	case SND_SOC_DAIFMT_CBM_CFS:
+		if (pm860x->dir == PM860X_CLK_DIR_OUT) {
+			inf |= PCM_INF2_MASTER;
+			ret = 0;
+		}
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		if (pm860x->dir == PM860X_CLK_DIR_IN) {
+			inf &= ~PCM_INF2_MASTER;
+			ret = 0;
+		}
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		inf |= PCM_EXACT_I2S;
+		ret = 0;
+		break;
+	}
+	mask |= PCM_MODE_MASK;
+	if (ret)
+		return ret;
+	snd_soc_component_update_bits(component, PM860X_PCM_IFACE_2, mask, inf);
+	return 0;
+}
+
+static int pm860x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
+
+	if (dir == PM860X_CLK_DIR_OUT)
+		pm860x->dir = PM860X_CLK_DIR_OUT;
+	else	/* Slave mode is not supported */
+		return -EINVAL;
+
+	return 0;
+}
+
+static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned char inf;
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		inf = 0;
+		break;
+	case 18:
+		inf = PCM_INF2_18WL;
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, PM860X_I2S_IFACE_2, PCM_INF2_18WL, inf);
+
+	/* sample rate */
+	switch (params_rate(params)) {
+	case 8000:
+		inf = 0;
+		break;
+	case 11025:
+		inf = 1;
+		break;
+	case 16000:
+		inf = 3;
+		break;
+	case 22050:
+		inf = 4;
+		break;
+	case 32000:
+		inf = 6;
+		break;
+	case 44100:
+		inf = 7;
+		break;
+	case 48000:
+		inf = 8;
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, PM860X_I2S_IFACE_4, 0xf, inf);
+
+	return 0;
+}
+
+static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				  unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
+	unsigned char inf = 0, mask = 0;
+
+	mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		if (pm860x->dir == PM860X_CLK_DIR_OUT)
+			inf |= PCM_INF2_MASTER;
+		else
+			return -EINVAL;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		if (pm860x->dir == PM860X_CLK_DIR_IN)
+			inf &= ~PCM_INF2_MASTER;
+		else
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		inf |= PCM_EXACT_I2S;
+		break;
+	default:
+		return -EINVAL;
+	}
+	mask |= PCM_MODE_MASK;
+	snd_soc_component_update_bits(component, PM860X_I2S_IFACE_2, mask, inf);
+	return 0;
+}
+
+static int pm860x_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
+	int data;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/* Enable Audio PLL & Audio section */
+			data = AUDIO_PLL | AUDIO_SECTION_ON;
+			pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
+			udelay(300);
+			data = AUDIO_PLL | AUDIO_SECTION_RESET
+				| AUDIO_SECTION_ON;
+			pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON;
+		pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops pm860x_pcm_dai_ops = {
+	.digital_mute	= pm860x_digital_mute,
+	.hw_params	= pm860x_pcm_hw_params,
+	.set_fmt	= pm860x_pcm_set_dai_fmt,
+	.set_sysclk	= pm860x_set_dai_sysclk,
+};
+
+static const struct snd_soc_dai_ops pm860x_i2s_dai_ops = {
+	.digital_mute	= pm860x_digital_mute,
+	.hw_params	= pm860x_i2s_hw_params,
+	.set_fmt	= pm860x_i2s_set_dai_fmt,
+	.set_sysclk	= pm860x_set_dai_sysclk,
+};
+
+#define PM860X_RATES	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |	\
+			 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+
+static struct snd_soc_dai_driver pm860x_dai[] = {
+	{
+		/* DAI PCM */
+		.name	= "88pm860x-pcm",
+		.id	= 1,
+		.playback = {
+			.stream_name	= "PCM Playback",
+			.channels_min	= 2,
+			.channels_max	= 2,
+			.rates		= PM860X_RATES,
+			.formats	= SNDRV_PCM_FMTBIT_S16_LE | \
+					  SNDRV_PCM_FMTBIT_S18_3LE,
+		},
+		.capture = {
+			.stream_name	= "PCM Capture",
+			.channels_min	= 2,
+			.channels_max	= 2,
+			.rates		= PM860X_RATES,
+			.formats	= SNDRV_PCM_FMTBIT_S16_LE | \
+					  SNDRV_PCM_FMTBIT_S18_3LE,
+		},
+		.ops	= &pm860x_pcm_dai_ops,
+	}, {
+		/* DAI I2S */
+		.name	= "88pm860x-i2s",
+		.id	= 2,
+		.playback = {
+			.stream_name	= "I2S Playback",
+			.channels_min	= 2,
+			.channels_max	= 2,
+			.rates		= SNDRV_PCM_RATE_8000_48000,
+			.formats	= SNDRV_PCM_FMTBIT_S16_LE | \
+					  SNDRV_PCM_FMTBIT_S18_3LE,
+		},
+		.capture = {
+			.stream_name	= "I2S Capture",
+			.channels_min	= 2,
+			.channels_max	= 2,
+			.rates		= SNDRV_PCM_RATE_8000_48000,
+			.formats	= SNDRV_PCM_FMTBIT_S16_LE | \
+					  SNDRV_PCM_FMTBIT_S18_3LE,
+		},
+		.ops	= &pm860x_i2s_dai_ops,
+	},
+};
+
+static irqreturn_t pm860x_component_handler(int irq, void *data)
+{
+	struct pm860x_priv *pm860x = data;
+	int status, shrt, report = 0, mic_report = 0;
+	int mask;
+
+	status = pm860x_reg_read(pm860x->i2c, REG_STATUS_1);
+	shrt = pm860x_reg_read(pm860x->i2c, REG_SHORTS);
+	mask = pm860x->det.hs_shrt | pm860x->det.hook_det | pm860x->det.lo_shrt
+		| pm860x->det.hp_det;
+
+#ifndef CONFIG_SND_SOC_88PM860X_MODULE
+	if (status & (HEADSET_STATUS | MIC_STATUS | SHORT_HS1 | SHORT_HS2 |
+		      SHORT_LO1 | SHORT_LO2))
+		trace_snd_soc_jack_irq(dev_name(pm860x->component->dev));
+#endif
+
+	if ((pm860x->det.hp_det & SND_JACK_HEADPHONE)
+		&& (status & HEADSET_STATUS))
+		report |= SND_JACK_HEADPHONE;
+
+	if ((pm860x->det.mic_det & SND_JACK_MICROPHONE)
+		&& (status & MIC_STATUS))
+		mic_report |= SND_JACK_MICROPHONE;
+
+	if (pm860x->det.hs_shrt && (shrt & (SHORT_HS1 | SHORT_HS2)))
+		report |= pm860x->det.hs_shrt;
+
+	if (pm860x->det.hook_det && (status & HOOK_STATUS))
+		report |= pm860x->det.hook_det;
+
+	if (pm860x->det.lo_shrt && (shrt & (SHORT_LO1 | SHORT_LO2)))
+		report |= pm860x->det.lo_shrt;
+
+	if (report)
+		snd_soc_jack_report(pm860x->det.hp_jack, report, mask);
+	if (mic_report)
+		snd_soc_jack_report(pm860x->det.mic_jack, SND_JACK_MICROPHONE,
+				    SND_JACK_MICROPHONE);
+
+	dev_dbg(pm860x->component->dev, "headphone report:0x%x, mask:%x\n",
+		report, mask);
+	dev_dbg(pm860x->component->dev, "microphone report:0x%x\n", mic_report);
+	return IRQ_HANDLED;
+}
+
+int pm860x_hs_jack_detect(struct snd_soc_component *component,
+			  struct snd_soc_jack *jack,
+			  int det, int hook, int hs_shrt, int lo_shrt)
+{
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
+	int data;
+
+	pm860x->det.hp_jack = jack;
+	pm860x->det.hp_det = det;
+	pm860x->det.hook_det = hook;
+	pm860x->det.hs_shrt = hs_shrt;
+	pm860x->det.lo_shrt = lo_shrt;
+
+	if (det & SND_JACK_HEADPHONE)
+		pm860x_set_bits(pm860x->i2c, REG_HS_DET,
+				EN_HS_DET, EN_HS_DET);
+	/* headset short detect */
+	if (hs_shrt) {
+		data = CLR_SHORT_HS2 | CLR_SHORT_HS1;
+		pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data);
+	}
+	/* Lineout short detect */
+	if (lo_shrt) {
+		data = CLR_SHORT_LO2 | CLR_SHORT_LO1;
+		pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data);
+	}
+
+	/* sync status */
+	pm860x_component_handler(0, pm860x);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pm860x_hs_jack_detect);
+
+int pm860x_mic_jack_detect(struct snd_soc_component *component,
+			   struct snd_soc_jack *jack, int det)
+{
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
+
+	pm860x->det.mic_jack = jack;
+	pm860x->det.mic_det = det;
+
+	if (det & SND_JACK_MICROPHONE)
+		pm860x_set_bits(pm860x->i2c, REG_MIC_DET,
+				MICDET_MASK, MICDET_MASK);
+
+	/* sync status */
+	pm860x_component_handler(0, pm860x);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pm860x_mic_jack_detect);
+
+static int pm860x_probe(struct snd_soc_component *component)
+{
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
+	int i, ret;
+
+	pm860x->component = component;
+	snd_soc_component_init_regmap(component,  pm860x->regmap);
+
+	for (i = 0; i < 4; i++) {
+		ret = request_threaded_irq(pm860x->irq[i], NULL,
+					   pm860x_component_handler, IRQF_ONESHOT,
+					   pm860x->name[i], pm860x);
+		if (ret < 0) {
+			dev_err(component->dev, "Failed to request IRQ!\n");
+			goto out;
+		}
+	}
+
+	return 0;
+
+out:
+	while (--i >= 0)
+		free_irq(pm860x->irq[i], pm860x);
+	return ret;
+}
+
+static void pm860x_remove(struct snd_soc_component *component)
+{
+	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
+	int i;
+
+	for (i = 3; i >= 0; i--)
+		free_irq(pm860x->irq[i], pm860x);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_pm860x = {
+	.probe			= pm860x_probe,
+	.remove			= pm860x_remove,
+	.set_bias_level		= pm860x_set_bias_level,
+	.controls		= pm860x_snd_controls,
+	.num_controls		= ARRAY_SIZE(pm860x_snd_controls),
+	.dapm_widgets		= pm860x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pm860x_dapm_widgets),
+	.dapm_routes		= pm860x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pm860x_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int pm860x_codec_probe(struct platform_device *pdev)
+{
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+	struct pm860x_priv *pm860x;
+	struct resource *res;
+	int i, ret;
+
+	pm860x = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_priv),
+			      GFP_KERNEL);
+	if (pm860x == NULL)
+		return -ENOMEM;
+
+	pm860x->chip = chip;
+	pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client
+			: chip->companion;
+	pm860x->regmap = (chip->id == CHIP_PM8607) ? chip->regmap
+			: chip->regmap_companion;
+	platform_set_drvdata(pdev, pm860x);
+
+	for (i = 0; i < 4; i++) {
+		res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+		if (!res) {
+			dev_err(&pdev->dev, "Failed to get IRQ resources\n");
+			return -EINVAL;
+		}
+		pm860x->irq[i] = res->start + chip->irq_base;
+		strncpy(pm860x->name[i], res->name, MAX_NAME_LEN);
+	}
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+				     &soc_component_dev_pm860x,
+				     pm860x_dai, ARRAY_SIZE(pm860x_dai));
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register component\n");
+		return -EINVAL;
+	}
+	return ret;
+}
+
+static int pm860x_codec_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver pm860x_codec_driver = {
+	.driver	= {
+		.name	= "88pm860x-codec",
+	},
+	.probe	= pm860x_codec_probe,
+	.remove	= pm860x_codec_remove,
+};
+
+module_platform_driver(pm860x_codec_driver);
+
+MODULE_DESCRIPTION("ASoC 88PM860x driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:88pm860x-codec");
+
diff --git a/sound/soc/codecs/88pm860x-codec.h b/sound/soc/codecs/88pm860x-codec.h
new file mode 100644
index 0000000..33aa9ff
--- /dev/null
+++ b/sound/soc/codecs/88pm860x-codec.h
@@ -0,0 +1,96 @@
+/*
+ * 88pm860x-codec.h -- 88PM860x ALSA SoC Audio Driver
+ *
+ * Copyright 2010 Marvell International Ltd.
+ *	Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __88PM860X_H
+#define __88PM860X_H
+
+#define PM860X_PCM_IFACE_1		0xb0
+#define PM860X_PCM_IFACE_2		0xb1
+#define PM860X_PCM_IFACE_3		0xb2
+#define PM860X_PCM_RATE			0xb3
+#define PM860X_EC_PATH			0xb4
+#define PM860X_SIDETONE_L_GAIN		0xb5
+#define PM860X_SIDETONE_R_GAIN		0xb6
+#define PM860X_SIDETONE_SHIFT		0xb7
+#define PM860X_ADC_OFFSET_1		0xb8
+#define PM860X_ADC_OFFSET_2		0xb9
+#define PM860X_DMIC_DELAY		0xba
+
+#define PM860X_I2S_IFACE_1		0xbb
+#define PM860X_I2S_IFACE_2		0xbc
+#define PM860X_I2S_IFACE_3		0xbd
+#define PM860X_I2S_IFACE_4		0xbe
+#define PM860X_EQUALIZER_N0_1		0xbf
+#define PM860X_EQUALIZER_N0_2		0xc0
+#define PM860X_EQUALIZER_N1_1		0xc1
+#define PM860X_EQUALIZER_N1_2		0xc2
+#define PM860X_EQUALIZER_D1_1		0xc3
+#define PM860X_EQUALIZER_D1_2		0xc4
+#define PM860X_LOFI_GAIN_LEFT		0xc5
+#define PM860X_LOFI_GAIN_RIGHT		0xc6
+#define PM860X_HIFIL_GAIN_LEFT		0xc7
+#define PM860X_HIFIL_GAIN_RIGHT		0xc8
+#define PM860X_HIFIR_GAIN_LEFT		0xc9
+#define PM860X_HIFIR_GAIN_RIGHT		0xca
+#define PM860X_DAC_OFFSET		0xcb
+#define PM860X_OFFSET_LEFT_1		0xcc
+#define PM860X_OFFSET_LEFT_2		0xcd
+#define PM860X_OFFSET_RIGHT_1		0xce
+#define PM860X_OFFSET_RIGHT_2		0xcf
+#define PM860X_ADC_ANA_1		0xd0
+#define PM860X_ADC_ANA_2		0xd1
+#define PM860X_ADC_ANA_3		0xd2
+#define PM860X_ADC_ANA_4		0xd3
+#define PM860X_ANA_TO_ANA		0xd4
+#define PM860X_HS1_CTRL			0xd5
+#define PM860X_HS2_CTRL			0xd6
+#define PM860X_LO1_CTRL			0xd7
+#define PM860X_LO2_CTRL			0xd8
+#define PM860X_EAR_CTRL_1		0xd9
+#define PM860X_EAR_CTRL_2		0xda
+#define PM860X_AUDIO_SUPPLIES_1		0xdb
+#define PM860X_AUDIO_SUPPLIES_2		0xdc
+#define PM860X_ADC_EN_1			0xdd
+#define PM860X_ADC_EN_2			0xde
+#define PM860X_DAC_EN_1			0xdf
+#define PM860X_DAC_EN_2			0xe1
+#define PM860X_AUDIO_CAL_1		0xe2
+#define PM860X_AUDIO_CAL_2		0xe3
+#define PM860X_AUDIO_CAL_3		0xe4
+#define PM860X_AUDIO_CAL_4		0xe5
+#define PM860X_AUDIO_CAL_5		0xe6
+#define PM860X_ANA_INPUT_SEL_1		0xe7
+#define PM860X_ANA_INPUT_SEL_2		0xe8
+
+#define PM860X_PCM_IFACE_4		0xe9
+#define PM860X_I2S_IFACE_5		0xea
+
+#define PM860X_SHORTS			0x3b
+#define PM860X_PLL_ADJ_1		0x3c
+#define PM860X_PLL_ADJ_2		0x3d
+
+/* bits definition */
+#define PM860X_CLK_DIR_IN		0
+#define PM860X_CLK_DIR_OUT		1
+
+#define PM860X_DET_HEADSET		(1 << 0)
+#define PM860X_DET_MIC			(1 << 1)
+#define PM860X_DET_HOOK			(1 << 2)
+#define PM860X_SHORT_HEADSET		(1 << 3)
+#define PM860X_SHORT_LINEOUT		(1 << 4)
+#define PM860X_DET_MASK			0x1F
+
+extern int pm860x_hs_jack_detect(struct snd_soc_component *, struct snd_soc_jack *,
+				 int, int, int, int);
+extern int pm860x_mic_jack_detect(struct snd_soc_component *, struct snd_soc_jack *,
+				  int);
+
+#endif	/* __88PM860X_H */
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
new file mode 100644
index 0000000..efb095d
--- /dev/null
+++ b/sound/soc/codecs/Kconfig
@@ -0,0 +1,1313 @@
+# Helper to resolve issues with configs that have SPI enabled but I2C
+# modular, meaning we can't build the codec driver in with I2C support.
+# We use an ordered list of conditional defaults to pick the appropriate
+# setting - SPI can't be modular so that case doesn't need to be covered.
+config SND_SOC_I2C_AND_SPI
+	tristate
+	default m if I2C=m
+	default y if I2C=y
+	default y if SPI_MASTER=y
+
+menu "CODEC drivers"
+
+config SND_SOC_ALL_CODECS
+	tristate "Build all ASoC CODEC drivers"
+	depends on COMPILE_TEST
+	select SND_SOC_88PM860X if MFD_88PM860X
+	select SND_SOC_L3
+	select SND_SOC_AB8500_CODEC if ABX500_CORE
+	select SND_SOC_AC97_CODEC
+	select SND_SOC_AD1836 if SPI_MASTER
+	select SND_SOC_AD193X_SPI if SPI_MASTER
+	select SND_SOC_AD193X_I2C if I2C
+	select SND_SOC_AD1980 if SND_SOC_AC97_BUS
+	select SND_SOC_AD73311
+	select SND_SOC_ADAU1373 if I2C
+	select SND_SOC_ADAU1761_I2C if I2C
+	select SND_SOC_ADAU1761_SPI if SPI
+	select SND_SOC_ADAU1781_I2C if I2C
+	select SND_SOC_ADAU1781_SPI if SPI
+	select SND_SOC_ADAV801 if SPI_MASTER
+	select SND_SOC_ADAV803 if I2C
+	select SND_SOC_ADAU1977_SPI if SPI_MASTER
+	select SND_SOC_ADAU1977_I2C if I2C
+	select SND_SOC_ADAU1701 if I2C
+	select SND_SOC_ADAU7002
+	select SND_SOC_ADS117X
+	select SND_SOC_AK4104 if SPI_MASTER
+	select SND_SOC_AK4458 if I2C
+	select SND_SOC_AK4535 if I2C
+	select SND_SOC_AK4554
+	select SND_SOC_AK4613 if I2C
+	select SND_SOC_AK4641 if I2C
+	select SND_SOC_AK4642 if I2C
+	select SND_SOC_AK4671 if I2C
+	select SND_SOC_AK5386
+	select SND_SOC_AK5558 if I2C
+	select SND_SOC_ALC5623 if I2C
+	select SND_SOC_ALC5632 if I2C
+	select SND_SOC_BT_SCO
+	select SND_SOC_BD28623
+	select SND_SOC_CQ0093VC
+	select SND_SOC_CS35L32 if I2C
+	select SND_SOC_CS35L33 if I2C
+	select SND_SOC_CS35L34 if I2C
+	select SND_SOC_CS35L35 if I2C
+	select SND_SOC_CS42L42 if I2C
+	select SND_SOC_CS42L51_I2C if I2C
+	select SND_SOC_CS42L52 if I2C && INPUT
+	select SND_SOC_CS42L56 if I2C && INPUT
+	select SND_SOC_CS42L73 if I2C
+	select SND_SOC_CS4265 if I2C
+	select SND_SOC_CS4270 if I2C
+	select SND_SOC_CS4271_I2C if I2C
+	select SND_SOC_CS4271_SPI if SPI_MASTER
+	select SND_SOC_CS42XX8_I2C if I2C
+	select SND_SOC_CS43130 if I2C
+	select SND_SOC_CS4349 if I2C
+	select SND_SOC_CS47L24 if MFD_CS47L24
+	select SND_SOC_CS53L30 if I2C
+	select SND_SOC_CX20442 if TTY
+	select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_DA7213 if I2C
+	select SND_SOC_DA7218 if I2C
+	select SND_SOC_DA7219 if I2C
+	select SND_SOC_DA732X if I2C
+	select SND_SOC_DA9055 if I2C
+	select SND_SOC_DMIC if GPIOLIB
+	select SND_SOC_ES8316 if I2C
+	select SND_SOC_ES8328_SPI if SPI_MASTER
+	select SND_SOC_ES8328_I2C if I2C
+	select SND_SOC_ES7134
+	select SND_SOC_ES7241
+	select SND_SOC_GTM601
+	select SND_SOC_HDAC_HDMI
+	select SND_SOC_ICS43432
+	select SND_SOC_INNO_RK3036
+	select SND_SOC_ISABELLE if I2C
+	select SND_SOC_JZ4740_CODEC
+	select SND_SOC_LM4857 if I2C
+	select SND_SOC_LM49453 if I2C
+	select SND_SOC_MAX98088 if I2C
+	select SND_SOC_MAX98090 if I2C
+	select SND_SOC_MAX98095 if I2C
+	select SND_SOC_MAX98357A if GPIOLIB
+	select SND_SOC_MAX98371 if I2C
+	select SND_SOC_MAX98504 if I2C
+	select SND_SOC_MAX9867 if I2C
+	select SND_SOC_MAX98925 if I2C
+	select SND_SOC_MAX98926 if I2C
+	select SND_SOC_MAX98927 if I2C
+	select SND_SOC_MAX98373 if I2C
+	select SND_SOC_MAX9850 if I2C
+	select SND_SOC_MAX9860 if I2C
+	select SND_SOC_MAX9759
+	select SND_SOC_MAX9768 if I2C
+	select SND_SOC_MAX9877 if I2C
+	select SND_SOC_MC13783 if MFD_MC13XXX
+	select SND_SOC_ML26124 if I2C
+	select SND_SOC_MT6351 if MTK_PMIC_WRAP
+	select SND_SOC_NAU8540 if I2C
+	select SND_SOC_NAU8810 if I2C
+	select SND_SOC_NAU8824 if I2C
+	select SND_SOC_NAU8825 if I2C
+	select SND_SOC_HDMI_CODEC
+	select SND_SOC_PCM1681 if I2C
+	select SND_SOC_PCM1789_I2C if I2C
+	select SND_SOC_PCM179X_I2C if I2C
+	select SND_SOC_PCM179X_SPI if SPI_MASTER
+	select SND_SOC_PCM186X_I2C if I2C
+	select SND_SOC_PCM186X_SPI if SPI_MASTER
+	select SND_SOC_PCM3008
+	select SND_SOC_PCM3168A_I2C if I2C
+	select SND_SOC_PCM3168A_SPI if SPI_MASTER
+	select SND_SOC_PCM5102A
+	select SND_SOC_PCM512x_I2C if I2C
+	select SND_SOC_PCM512x_SPI if SPI_MASTER
+	select SND_SOC_RT274 if I2C
+	select SND_SOC_RT286 if I2C
+	select SND_SOC_RT298 if I2C
+	select SND_SOC_RT1305 if I2C
+	select SND_SOC_RT5514 if I2C
+	select SND_SOC_RT5616 if I2C
+	select SND_SOC_RT5631 if I2C
+	select SND_SOC_RT5640 if I2C
+	select SND_SOC_RT5645 if I2C
+	select SND_SOC_RT5651 if I2C
+	select SND_SOC_RT5659 if I2C
+	select SND_SOC_RT5660 if I2C
+	select SND_SOC_RT5663 if I2C
+	select SND_SOC_RT5665 if I2C
+	select SND_SOC_RT5668 if I2C
+	select SND_SOC_RT5670 if I2C
+	select SND_SOC_RT5677 if I2C && SPI_MASTER
+	select SND_SOC_RT5682 if I2C
+	select SND_SOC_SGTL5000 if I2C
+	select SND_SOC_SI476X if MFD_SI476X_CORE
+	select SND_SOC_SIMPLE_AMPLIFIER
+	select SND_SOC_SIRF_AUDIO_CODEC
+	select SND_SOC_SPDIF
+	select SND_SOC_SSM2305
+	select SND_SOC_SSM2518 if I2C
+	select SND_SOC_SSM2602_SPI if SPI_MASTER
+	select SND_SOC_SSM2602_I2C if I2C
+	select SND_SOC_SSM4567 if I2C
+	select SND_SOC_STA32X if I2C
+	select SND_SOC_STA350 if I2C
+	select SND_SOC_STA529 if I2C
+	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
+	select SND_SOC_STI_SAS
+	select SND_SOC_TAS2552 if I2C
+	select SND_SOC_TAS5086 if I2C
+	select SND_SOC_TAS571X if I2C
+	select SND_SOC_TAS5720 if I2C
+	select SND_SOC_TAS6424 if I2C
+	select SND_SOC_TDA7419 if I2C
+	select SND_SOC_TFA9879 if I2C
+	select SND_SOC_TLV320AIC23_I2C if I2C
+	select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
+	select SND_SOC_TLV320AIC26 if SPI_MASTER
+	select SND_SOC_TLV320AIC31XX if I2C
+	select SND_SOC_TLV320AIC32X4_I2C if I2C
+	select SND_SOC_TLV320AIC32X4_SPI if SPI_MASTER
+	select SND_SOC_TLV320AIC3X if I2C
+	select SND_SOC_TPA6130A2 if I2C
+	select SND_SOC_TLV320DAC33 if I2C
+	select SND_SOC_TSCS42XX if I2C
+	select SND_SOC_TSCS454 if I2C
+	select SND_SOC_TS3A227E if I2C
+	select SND_SOC_TWL4030 if TWL4030_CORE
+	select SND_SOC_TWL6040 if TWL6040_CORE
+	select SND_SOC_UDA134X
+	select SND_SOC_UDA1380 if I2C
+	select SND_SOC_WL1273 if MFD_WL1273_CORE
+	select SND_SOC_WM0010 if SPI_MASTER
+	select SND_SOC_WM1250_EV1 if I2C
+	select SND_SOC_WM2000 if I2C
+	select SND_SOC_WM2200 if I2C
+	select SND_SOC_WM5100 if I2C
+	select SND_SOC_WM5102 if MFD_WM5102
+	select SND_SOC_WM5110 if MFD_WM5110
+	select SND_SOC_WM8350 if MFD_WM8350
+	select SND_SOC_WM8400 if MFD_WM8400
+	select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8523 if I2C
+	select SND_SOC_WM8524 if GPIOLIB
+	select SND_SOC_WM8580 if I2C
+	select SND_SOC_WM8711 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8727
+	select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8737 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8741 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8770 if SPI_MASTER
+	select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8782
+	select SND_SOC_WM8804_I2C if I2C
+	select SND_SOC_WM8804_SPI if SPI_MASTER
+	select SND_SOC_WM8900 if I2C
+	select SND_SOC_WM8903 if I2C
+	select SND_SOC_WM8904 if I2C
+	select SND_SOC_WM8940 if I2C
+	select SND_SOC_WM8955 if I2C
+	select SND_SOC_WM8960 if I2C
+	select SND_SOC_WM8961 if I2C
+	select SND_SOC_WM8962 if I2C && INPUT
+	select SND_SOC_WM8971 if I2C
+	select SND_SOC_WM8974 if I2C
+	select SND_SOC_WM8978 if I2C
+	select SND_SOC_WM8983 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8990 if I2C
+	select SND_SOC_WM8991 if I2C
+	select SND_SOC_WM8993 if I2C
+	select SND_SOC_WM8994 if MFD_WM8994
+	select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8996 if I2C
+	select SND_SOC_WM8997 if MFD_WM8997
+	select SND_SOC_WM8998 if MFD_WM8998
+	select SND_SOC_WM9081 if I2C
+	select SND_SOC_WM9090 if I2C
+	select SND_SOC_WM9705 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW)
+	select SND_SOC_WM9712 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW)
+	select SND_SOC_WM9713 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW)
+        help
+          Normally ASoC codec drivers are only built if a machine driver which
+          uses them is also built since they are only usable with a machine
+          driver.  Selecting this option will allow these drivers to be built
+          without an explicit machine driver for test and development purposes.
+
+	  Support for the bus types used to access the codecs to be built must
+	  be selected separately.
+
+          If unsure select "N".
+
+config SND_SOC_88PM860X
+	tristate
+
+config SND_SOC_ARIZONA
+	tristate
+	default y if SND_SOC_CS47L24=y
+	default y if SND_SOC_WM5102=y
+	default y if SND_SOC_WM5110=y
+	default y if SND_SOC_WM8997=y
+	default y if SND_SOC_WM8998=y
+	default m if SND_SOC_CS47L24=m
+	default m if SND_SOC_WM5102=m
+	default m if SND_SOC_WM5110=m
+	default m if SND_SOC_WM8997=m
+	default m if SND_SOC_WM8998=m
+
+config SND_SOC_WM_HUBS
+	tristate
+	default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
+	default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m
+
+config SND_SOC_WM_ADSP
+	tristate
+	select SND_SOC_COMPRESS
+	default y if SND_SOC_CS47L24=y
+	default y if SND_SOC_WM5102=y
+	default y if SND_SOC_WM5110=y
+	default y if SND_SOC_WM2200=y
+	default m if SND_SOC_CS47L24=m
+	default m if SND_SOC_WM5102=m
+	default m if SND_SOC_WM5110=m
+	default m if SND_SOC_WM2200=m
+
+config SND_SOC_AB8500_CODEC
+	tristate
+
+config SND_SOC_AC97_CODEC
+	tristate "Build generic ASoC AC97 CODEC driver"
+	select SND_AC97_CODEC
+	select SND_SOC_AC97_BUS
+
+config SND_SOC_AD1836
+	tristate
+
+config SND_SOC_AD193X
+	tristate
+
+config SND_SOC_AD193X_SPI
+	tristate
+	select SND_SOC_AD193X
+
+config SND_SOC_AD193X_I2C
+	tristate
+	select SND_SOC_AD193X
+
+config SND_SOC_AD1980
+	select REGMAP_AC97
+	tristate
+
+config SND_SOC_AD73311
+	tristate
+
+config SND_SOC_ADAU_UTILS
+	tristate
+
+config SND_SOC_ADAU1373
+	tristate
+	select SND_SOC_ADAU_UTILS
+
+config SND_SOC_ADAU1701
+	tristate "Analog Devices ADAU1701 CODEC"
+	depends on I2C
+	select SND_SOC_SIGMADSP_I2C
+
+config SND_SOC_ADAU17X1
+	tristate
+	select SND_SOC_SIGMADSP_REGMAP
+	select SND_SOC_ADAU_UTILS
+
+config SND_SOC_ADAU1761
+	tristate
+	select SND_SOC_ADAU17X1
+
+config SND_SOC_ADAU1761_I2C
+	tristate "Analog Devices AU1761 CODEC - I2C"
+	depends on I2C
+	select SND_SOC_ADAU1761
+	select REGMAP_I2C
+
+config SND_SOC_ADAU1761_SPI
+	tristate "Analog Devices AU1761 CODEC - SPI"
+	depends on SPI
+	select SND_SOC_ADAU1761
+	select REGMAP_SPI
+
+config SND_SOC_ADAU1781
+	select SND_SOC_ADAU17X1
+	tristate
+
+config SND_SOC_ADAU1781_I2C
+	tristate
+	select SND_SOC_ADAU1781
+	select REGMAP_I2C
+
+config SND_SOC_ADAU1781_SPI
+	tristate
+	select SND_SOC_ADAU1781
+	select REGMAP_SPI
+
+config SND_SOC_ADAU1977
+	tristate
+
+config SND_SOC_ADAU1977_SPI
+	tristate
+	select SND_SOC_ADAU1977
+	select REGMAP_SPI
+
+config SND_SOC_ADAU1977_I2C
+	tristate
+	select SND_SOC_ADAU1977
+	select REGMAP_I2C
+
+config SND_SOC_ADAU7002
+	tristate "Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter"
+
+config SND_SOC_ADAV80X
+	tristate
+
+config SND_SOC_ADAV801
+	tristate
+	select SND_SOC_ADAV80X
+
+config SND_SOC_ADAV803
+	tristate
+	select SND_SOC_ADAV80X
+
+config SND_SOC_ADS117X
+	tristate
+
+config SND_SOC_AK4104
+	tristate "AKM AK4104 CODEC"
+	depends on SPI_MASTER
+
+config SND_SOC_AK4458
+	tristate "AKM AK4458 CODEC"
+	depends on I2C
+	select REGMAP_I2C
+
+config SND_SOC_AK4535
+	tristate
+
+config SND_SOC_AK4554
+	tristate "AKM AK4554 CODEC"
+
+config SND_SOC_AK4613
+	tristate "AKM AK4613 CODEC"
+	depends on I2C
+
+config SND_SOC_AK4641
+	tristate
+
+config SND_SOC_AK4642
+	tristate "AKM AK4642 CODEC"
+	depends on I2C
+
+config SND_SOC_AK4671
+	tristate
+
+config SND_SOC_AK5386
+	tristate "AKM AK5638 CODEC"
+
+config SND_SOC_AK5558
+	tristate "AKM AK5558 CODEC"
+	depends on I2C
+	select REGMAP_I2C
+
+config SND_SOC_ALC5623
+       tristate "Realtek ALC5623 CODEC"
+	depends on I2C
+
+config SND_SOC_ALC5632
+	tristate
+
+config SND_SOC_BD28623
+	tristate "ROHM BD28623 CODEC"
+	help
+	  Enable support for ROHM BD28623MUV Class D speaker amplifier.
+	  This codec does not have any control buses such as I2C, it
+	  detect format of I2S automatically.
+
+config SND_SOC_BT_SCO
+	tristate "Dummy BT SCO codec driver"
+
+config SND_SOC_CPCAP
+	tristate "Motorola CPCAP codec"
+	depends on MFD_CPCAP
+
+config SND_SOC_CQ0093VC
+	tristate
+
+config SND_SOC_CS35L32
+	tristate "Cirrus Logic CS35L32 CODEC"
+	depends on I2C
+
+config SND_SOC_CS35L33
+	tristate "Cirrus Logic CS35L33 CODEC"
+	depends on I2C
+
+config SND_SOC_CS35L34
+	tristate "Cirrus Logic CS35L34 CODEC"
+	depends on I2C
+
+config SND_SOC_CS35L35
+	tristate "Cirrus Logic CS35L35 CODEC"
+	depends on I2C
+
+config SND_SOC_CS42L42
+	tristate "Cirrus Logic CS42L42 CODEC"
+	depends on I2C
+
+config SND_SOC_CS42L51
+	tristate
+
+config SND_SOC_CS42L51_I2C
+	tristate "Cirrus Logic CS42L51 CODEC (I2C)"
+	depends on I2C
+	select SND_SOC_CS42L51
+
+config SND_SOC_CS42L52
+	tristate "Cirrus Logic CS42L52 CODEC"
+	depends on I2C && INPUT
+
+config SND_SOC_CS42L56
+	tristate "Cirrus Logic CS42L56 CODEC"
+	depends on I2C && INPUT
+
+config SND_SOC_CS42L73
+	tristate "Cirrus Logic CS42L73 CODEC"
+	depends on I2C
+
+config SND_SOC_CS4265
+	tristate "Cirrus Logic CS4265 CODEC"
+	depends on I2C
+	select REGMAP_I2C
+
+# Cirrus Logic CS4270 Codec
+config SND_SOC_CS4270
+	tristate "Cirrus Logic CS4270 CODEC"
+	depends on I2C
+
+# Cirrus Logic CS4270 Codec VD = 3.3V Errata
+# Select if you are affected by the errata where the part will not function
+# if MCLK divide-by-1.5 is selected and VD is set to 3.3V.  The driver will
+# not select any sample rates that require MCLK to be divided by 1.5.
+config SND_SOC_CS4270_VD33_ERRATA
+	bool
+	depends on SND_SOC_CS4270
+
+config SND_SOC_CS4271
+	tristate
+
+config SND_SOC_CS4271_I2C
+	tristate "Cirrus Logic CS4271 CODEC (I2C)"
+	depends on I2C
+	select SND_SOC_CS4271
+	select REGMAP_I2C
+
+config SND_SOC_CS4271_SPI
+	tristate "Cirrus Logic CS4271 CODEC (SPI)"
+	depends on SPI_MASTER
+	select SND_SOC_CS4271
+	select REGMAP_SPI
+
+config SND_SOC_CS42XX8
+	tristate
+
+config SND_SOC_CS42XX8_I2C
+	tristate "Cirrus Logic CS42448/CS42888 CODEC (I2C)"
+	depends on I2C
+	select SND_SOC_CS42XX8
+	select REGMAP_I2C
+
+# Cirrus Logic CS43130 HiFi DAC
+config SND_SOC_CS43130
+        tristate "Cirrus Logic CS43130 CODEC"
+        depends on I2C
+
+# Cirrus Logic CS4349 HiFi DAC
+config SND_SOC_CS4349
+	tristate "Cirrus Logic CS4349 CODEC"
+	depends on I2C
+
+config SND_SOC_CS47L24
+	tristate
+
+# Cirrus Logic Quad-Channel ADC
+config SND_SOC_CS53L30
+	tristate "Cirrus Logic CS53L30 CODEC"
+	depends on I2C
+
+config SND_SOC_CX20442
+	tristate
+	depends on TTY
+
+config SND_SOC_JZ4740_CODEC
+	select REGMAP_MMIO
+	tristate
+
+config SND_SOC_L3
+       tristate
+
+config SND_SOC_DA7210
+        tristate
+
+config SND_SOC_DA7213
+        tristate
+
+config SND_SOC_DA7218
+	tristate
+
+config SND_SOC_DA7219
+        tristate
+
+config SND_SOC_DA732X
+        tristate
+
+config SND_SOC_DA9055
+	tristate
+
+config SND_SOC_DMIC
+	tristate
+
+config SND_SOC_HDMI_CODEC
+	tristate
+	select SND_PCM_ELD
+	select SND_PCM_IEC958
+	select HDMI
+
+config SND_SOC_ES7134
+       tristate "Everest Semi ES7134 CODEC"
+
+config SND_SOC_ES7241
+       tristate "Everest Semi ES7241 CODEC"
+
+config SND_SOC_ES8316
+	tristate "Everest Semi ES8316 CODEC"
+	depends on I2C
+
+config SND_SOC_ES8328
+	tristate
+
+config SND_SOC_ES8328_I2C
+	tristate "Everest Semi ES8328 CODEC (I2C)"
+	depends on I2C
+	select SND_SOC_ES8328
+
+config SND_SOC_ES8328_SPI
+	tristate "Everest Semi ES8328 CODEC (SPI)"
+	depends on SPI_MASTER
+	select SND_SOC_ES8328
+
+config SND_SOC_GTM601
+	tristate 'GTM601 UMTS modem audio codec'
+
+config SND_SOC_HDAC_HDMI
+	tristate
+	select SND_HDA_EXT_CORE
+	select SND_PCM_ELD
+	select HDMI
+
+config SND_SOC_ICS43432
+	tristate
+
+config SND_SOC_INNO_RK3036
+	tristate "Inno codec driver for RK3036 SoC"
+	select REGMAP_MMIO
+
+config SND_SOC_ISABELLE
+        tristate
+
+config SND_SOC_LM49453
+	tristate
+
+config SND_SOC_MAX98088
+       tristate
+
+config SND_SOC_MAX98090
+       tristate
+
+config SND_SOC_MAX98095
+       tristate
+
+config SND_SOC_MAX98357A
+       tristate
+
+config SND_SOC_MAX98371
+       tristate
+
+config SND_SOC_MAX98504
+	tristate "Maxim MAX98504 speaker amplifier"
+	depends on I2C
+
+config SND_SOC_MAX9867
+	tristate "Maxim MAX9867 CODEC"
+	depends on I2C
+
+config SND_SOC_MAX98925
+       tristate
+
+config SND_SOC_MAX98926
+	tristate
+
+config SND_SOC_MAX98927
+	tristate "Maxim Integrated MAX98927 Speaker Amplifier"
+	depends on I2C
+
+config SND_SOC_MAX98373
+	tristate "Maxim Integrated MAX98373 Speaker Amplifier"
+	depends on I2C
+
+config SND_SOC_MAX9850
+	tristate
+
+config SND_SOC_MAX9860
+	tristate "Maxim MAX9860 Mono Audio Voice Codec"
+	depends on I2C
+	select REGMAP_I2C
+
+config SND_SOC_MSM8916_WCD_ANALOG
+	tristate "Qualcomm MSM8916 WCD Analog Codec"
+	depends on SPMI || COMPILE_TEST
+
+config SND_SOC_MSM8916_WCD_DIGITAL
+	tristate "Qualcomm MSM8916 WCD DIGITAL Codec"
+
+config SND_SOC_PCM1681
+	tristate "Texas Instruments PCM1681 CODEC"
+	depends on I2C
+
+config SND_SOC_PCM1789
+	tristate
+
+config SND_SOC_PCM1789_I2C
+	tristate "Texas Instruments PCM1789 CODEC (I2C)"
+	depends on I2C
+	select SND_SOC_PCM1789
+	help
+	  Enable support for Texas Instruments PCM1789 CODEC.
+	  Select this if your PCM1789 is connected via an I2C bus.
+
+config SND_SOC_PCM179X
+	tristate
+
+config SND_SOC_PCM179X_I2C
+	tristate "Texas Instruments PCM179X CODEC (I2C)"
+	depends on I2C
+	select SND_SOC_PCM179X
+	help
+	  Enable support for Texas Instruments PCM179x CODEC.
+	  Select this if your PCM179x is connected via an I2C bus.
+
+config SND_SOC_PCM179X_SPI
+	tristate "Texas Instruments PCM179X CODEC (SPI)"
+	depends on SPI_MASTER
+	select SND_SOC_PCM179X
+	help
+	  Enable support for Texas Instruments PCM179x CODEC.
+	  Select this if your PCM179x is connected via an SPI bus.
+
+config SND_SOC_PCM186X
+	tristate
+
+config SND_SOC_PCM186X_I2C
+	tristate "Texas Instruments PCM186x CODECs - I2C"
+	depends on I2C
+	select SND_SOC_PCM186X
+	select REGMAP_I2C
+
+config SND_SOC_PCM186X_SPI
+	tristate "Texas Instruments PCM186x CODECs - SPI"
+	depends on SPI_MASTER
+	select SND_SOC_PCM186X
+	select REGMAP_SPI
+
+config SND_SOC_PCM3008
+       tristate
+
+config SND_SOC_PCM3168A
+	tristate
+
+config SND_SOC_PCM3168A_I2C
+	tristate "Texas Instruments PCM3168A CODEC - I2C"
+	depends on I2C
+	select SND_SOC_PCM3168A
+	select REGMAP_I2C
+
+config SND_SOC_PCM3168A_SPI
+	tristate "Texas Instruments PCM3168A CODEC - SPI"
+	depends on SPI_MASTER
+	select SND_SOC_PCM3168A
+	select REGMAP_SPI
+
+config SND_SOC_PCM5102A
+	tristate
+
+config SND_SOC_PCM512x
+	tristate
+
+config SND_SOC_PCM512x_I2C
+	tristate "Texas Instruments PCM512x CODECs - I2C"
+	depends on I2C
+	select SND_SOC_PCM512x
+	select REGMAP_I2C
+
+config SND_SOC_PCM512x_SPI
+	tristate "Texas Instruments PCM512x CODECs - SPI"
+	depends on SPI_MASTER
+	select SND_SOC_PCM512x
+	select REGMAP_SPI
+
+config SND_SOC_RL6231
+	tristate
+	default y if SND_SOC_RT5514=y
+	default y if SND_SOC_RT5616=y
+	default y if SND_SOC_RT5640=y
+	default y if SND_SOC_RT5645=y
+	default y if SND_SOC_RT5651=y
+	default y if SND_SOC_RT5659=y
+	default y if SND_SOC_RT5660=y
+	default y if SND_SOC_RT5663=y
+	default y if SND_SOC_RT5665=y
+	default y if SND_SOC_RT5668=y
+	default y if SND_SOC_RT5670=y
+	default y if SND_SOC_RT5677=y
+	default y if SND_SOC_RT5682=y
+	default y if SND_SOC_RT1305=y
+	default m if SND_SOC_RT5514=m
+	default m if SND_SOC_RT5616=m
+	default m if SND_SOC_RT5640=m
+	default m if SND_SOC_RT5645=m
+	default m if SND_SOC_RT5651=m
+	default m if SND_SOC_RT5659=m
+	default m if SND_SOC_RT5660=m
+	default m if SND_SOC_RT5663=m
+	default m if SND_SOC_RT5665=m
+	default m if SND_SOC_RT5668=m
+	default m if SND_SOC_RT5670=m
+	default m if SND_SOC_RT5677=m
+	default m if SND_SOC_RT5682=m
+	default m if SND_SOC_RT1305=m
+
+config SND_SOC_RL6347A
+	tristate
+	default y if SND_SOC_RT274=y
+	default y if SND_SOC_RT286=y
+	default y if SND_SOC_RT298=y
+	default m if SND_SOC_RT274=m
+	default m if SND_SOC_RT286=m
+	default m if SND_SOC_RT298=m
+
+config SND_SOC_RT274
+	tristate
+	depends on I2C
+
+config SND_SOC_RT286
+	tristate
+	depends on I2C
+
+config SND_SOC_RT298
+	tristate
+	depends on I2C
+
+config SND_SOC_RT1305
+	tristate
+
+config SND_SOC_RT5514
+	tristate
+
+config SND_SOC_RT5514_SPI
+	tristate
+
+config SND_SOC_RT5514_SPI_BUILTIN
+	bool # force RT5514_SPI to be built-in to avoid link errors
+	default SND_SOC_RT5514=y && SND_SOC_RT5514_SPI=m
+
+config SND_SOC_RT5616
+	tristate "Realtek RT5616 CODEC"
+	depends on I2C
+
+config SND_SOC_RT5631
+	tristate "Realtek ALC5631/RT5631 CODEC"
+	depends on I2C
+
+config SND_SOC_RT5640
+	tristate
+
+config SND_SOC_RT5645
+        tristate
+
+config SND_SOC_RT5651
+	tristate
+
+config SND_SOC_RT5659
+	tristate
+
+config SND_SOC_RT5660
+	tristate
+
+config SND_SOC_RT5663
+	tristate
+
+config SND_SOC_RT5665
+	tristate
+
+config SND_SOC_RT5668
+	tristate
+
+config SND_SOC_RT5670
+	tristate
+
+config SND_SOC_RT5677
+	tristate
+	select REGMAP_I2C
+	select REGMAP_IRQ
+
+config SND_SOC_RT5677_SPI
+	tristate
+	default SND_SOC_RT5677 && SPI
+
+config SND_SOC_RT5682
+	tristate
+
+#Freescale sgtl5000 codec
+config SND_SOC_SGTL5000
+	tristate "Freescale SGTL5000 CODEC"
+	depends on I2C
+
+config SND_SOC_SI476X
+	tristate
+
+config SND_SOC_SIGMADSP
+	tristate
+	select CRC32
+
+config SND_SOC_SIGMADSP_I2C
+	tristate
+	select SND_SOC_SIGMADSP
+
+config SND_SOC_SIGMADSP_REGMAP
+	tristate
+	select SND_SOC_SIGMADSP
+
+config SND_SOC_SIMPLE_AMPLIFIER
+	tristate "Simple Audio Amplifier"
+	select GPIOLIB
+
+config SND_SOC_SIRF_AUDIO_CODEC
+	tristate "SiRF SoC internal audio codec"
+	select REGMAP_MMIO
+
+config SND_SOC_SPDIF
+	tristate "S/PDIF CODEC"
+
+config SND_SOC_SSM2305
+	tristate "Analog Devices SSM2305 Class-D Amplifier"
+	help
+	  Enable support for Analog Devices SSM2305 filterless
+	  high-efficiency mono Class-D audio power amplifiers.
+
+config SND_SOC_SSM2518
+	tristate
+
+config SND_SOC_SSM2602
+	tristate
+
+config SND_SOC_SSM2602_SPI
+	tristate "Analog Devices SSM2602 CODEC - SPI"
+	depends on SPI_MASTER
+	select SND_SOC_SSM2602
+	select REGMAP_SPI
+
+config SND_SOC_SSM2602_I2C
+	tristate "Analog Devices SSM2602 CODEC - I2C"
+	depends on I2C
+	select SND_SOC_SSM2602
+	select REGMAP_I2C
+
+config SND_SOC_SSM4567
+	tristate "Analog Devices ssm4567 amplifier driver support"
+	depends on I2C
+
+config SND_SOC_STA32X
+	tristate "STA326, STA328 and STA329 speaker amplifier"
+	depends on I2C
+	select REGMAP_I2C
+
+config SND_SOC_STA350
+	tristate "STA350 speaker amplifier"
+	depends on I2C
+
+config SND_SOC_STA529
+	tristate
+
+config SND_SOC_STAC9766
+	tristate
+
+config SND_SOC_STI_SAS
+	tristate "codec Audio support for STI SAS codec"
+
+config SND_SOC_TAS2552
+	tristate "Texas Instruments TAS2552 Mono Audio amplifier"
+	depends on I2C
+
+config SND_SOC_TAS5086
+	tristate "Texas Instruments TAS5086 speaker amplifier"
+	depends on I2C
+
+config SND_SOC_TAS571X
+	tristate "Texas Instruments TAS571x power amplifiers"
+	depends on I2C
+	help
+	  Enable support for Texas Instruments TAS5707, TAS5711, TAS5717,
+	  TAS5719 and TAS5721 power amplifiers
+
+config SND_SOC_TAS5720
+	tristate "Texas Instruments TAS5720 Mono Audio amplifier"
+	depends on I2C
+	help
+	  Enable support for Texas Instruments TAS5720L/M high-efficiency mono
+	  Class-D audio power amplifiers.
+
+config SND_SOC_TAS6424
+	tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier"
+	depends on I2C
+	help
+	  Enable support for Texas Instruments TAS6424 high-efficiency
+	  digital input quad-channel Class-D audio power amplifiers.
+
+config SND_SOC_TDA7419
+	tristate "ST TDA7419 audio processor"
+	depends on I2C
+	select REGMAP_I2C
+
+config SND_SOC_TFA9879
+	tristate "NXP Semiconductors TFA9879 amplifier"
+	depends on I2C
+
+config SND_SOC_TLV320AIC23
+	tristate
+
+config SND_SOC_TLV320AIC23_I2C
+	tristate "Texas Instruments TLV320AIC23 audio CODEC - I2C"
+	depends on I2C
+	select SND_SOC_TLV320AIC23
+
+config SND_SOC_TLV320AIC23_SPI
+	tristate "Texas Instruments TLV320AIC23 audio CODEC - SPI"
+	depends on SPI_MASTER
+	select SND_SOC_TLV320AIC23
+
+config SND_SOC_TLV320AIC26
+	tristate
+	depends on SPI
+
+config SND_SOC_TLV320AIC31XX
+	tristate "Texas Instruments TLV320AIC31xx CODECs"
+	depends on I2C
+	select REGMAP_I2C
+
+config SND_SOC_TLV320AIC32X4
+	tristate
+
+config SND_SOC_TLV320AIC32X4_I2C
+	tristate "Texas Instruments TLV320AIC32x4 audio CODECs - I2C"
+	depends on I2C
+	select SND_SOC_TLV320AIC32X4
+
+config SND_SOC_TLV320AIC32X4_SPI
+	tristate "Texas Instruments TLV320AIC32x4 audio CODECs - SPI"
+	depends on SPI_MASTER
+	select SND_SOC_TLV320AIC32X4
+
+config SND_SOC_TLV320AIC3X
+	tristate "Texas Instruments TLV320AIC3x CODECs"
+	depends on I2C
+
+config SND_SOC_TLV320DAC33
+	tristate
+
+config SND_SOC_TS3A227E
+	tristate "TI Headset/Mic detect and keypress chip"
+	depends on I2C
+
+config SND_SOC_TSCS42XX
+	tristate "Tempo Semiconductor TSCS42xx CODEC"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  Add support for Tempo Semiconductor's TSCS42xx audio CODEC.
+
+config SND_SOC_TSCS454
+	tristate "Tempo Semiconductor TSCS454 CODEC"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  Add support for Tempo Semiconductor's TSCS454 audio CODEC.
+
+config SND_SOC_TWL4030
+	select MFD_TWL4030_AUDIO
+	tristate
+
+config SND_SOC_TWL6040
+	tristate
+
+config SND_SOC_UDA134X
+       tristate
+
+config SND_SOC_UDA1380
+        tristate
+	depends on I2C
+
+config SND_SOC_WL1273
+	tristate
+
+config SND_SOC_WM0010
+	tristate
+
+config SND_SOC_WM1250_EV1
+	tristate
+
+config SND_SOC_WM2000
+	tristate
+
+config SND_SOC_WM2200
+	tristate
+
+config SND_SOC_WM5100
+	tristate
+
+config SND_SOC_WM5102
+	tristate
+
+config SND_SOC_WM5110
+	tristate
+
+config SND_SOC_WM8350
+	tristate
+
+config SND_SOC_WM8400
+	tristate
+
+config SND_SOC_WM8510
+	tristate "Wolfson Microelectronics WM8510 CODEC"
+	depends on SND_SOC_I2C_AND_SPI
+
+config SND_SOC_WM8523
+	tristate "Wolfson Microelectronics WM8523 DAC"
+	depends on I2C
+
+config SND_SOC_WM8524
+	tristate "Wolfson Microelectronics WM8524 DAC"
+	depends on GPIOLIB
+
+config SND_SOC_WM8580
+	tristate "Wolfson Microelectronics WM8580 and WM8581 CODECs"
+	depends on I2C
+
+config SND_SOC_WM8711
+	tristate "Wolfson Microelectronics WM8711 CODEC"
+	depends on SND_SOC_I2C_AND_SPI
+
+config SND_SOC_WM8727
+	tristate
+
+config SND_SOC_WM8728
+	tristate "Wolfson Microelectronics WM8728 DAC"
+	depends on SND_SOC_I2C_AND_SPI
+
+config SND_SOC_WM8731
+	tristate "Wolfson Microelectronics WM8731 CODEC"
+	depends on SND_SOC_I2C_AND_SPI
+
+config SND_SOC_WM8737
+	tristate "Wolfson Microelectronics WM8737 ADC"
+	depends on SND_SOC_I2C_AND_SPI
+
+config SND_SOC_WM8741
+	tristate "Wolfson Microelectronics WM8737 DAC"
+	depends on SND_SOC_I2C_AND_SPI
+
+config SND_SOC_WM8750
+	tristate "Wolfson Microelectronics WM8750 CODEC"
+	depends on SND_SOC_I2C_AND_SPI
+
+config SND_SOC_WM8753
+	tristate "Wolfson Microelectronics WM8753 CODEC"
+	depends on SND_SOC_I2C_AND_SPI
+
+config SND_SOC_WM8770
+	tristate "Wolfson Microelectronics WM8770 CODEC"
+	depends on SPI_MASTER
+
+config SND_SOC_WM8776
+	tristate "Wolfson Microelectronics WM8776 CODEC"
+	depends on SND_SOC_I2C_AND_SPI
+
+config SND_SOC_WM8782
+	tristate "Wolfson Microelectronics WM8782 ADC"
+
+config SND_SOC_WM8804
+	tristate
+
+config SND_SOC_WM8804_I2C
+	tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver I2C"
+	depends on I2C
+	select SND_SOC_WM8804
+	select REGMAP_I2C
+
+config SND_SOC_WM8804_SPI
+	tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver SPI"
+	depends on SPI_MASTER
+	select SND_SOC_WM8804
+	select REGMAP_SPI
+
+config SND_SOC_WM8900
+	tristate
+
+config SND_SOC_WM8903
+	tristate "Wolfson Microelectronics WM8903 CODEC"
+	depends on I2C
+
+config SND_SOC_WM8904
+	tristate
+
+config SND_SOC_WM8940
+        tristate
+
+config SND_SOC_WM8955
+	tristate
+
+config SND_SOC_WM8960
+	tristate "Wolfson Microelectronics WM8960 CODEC"
+	depends on I2C
+
+config SND_SOC_WM8961
+	tristate
+
+config SND_SOC_WM8962
+	tristate "Wolfson Microelectronics WM8962 CODEC"
+	depends on I2C && INPUT
+
+config SND_SOC_WM8971
+	tristate
+
+config SND_SOC_WM8974
+	tristate "Wolfson Microelectronics WM8974 codec"
+	depends on I2C
+
+config SND_SOC_WM8978
+	tristate "Wolfson Microelectronics WM8978 codec"
+	depends on I2C
+
+config SND_SOC_WM8983
+	tristate
+
+config SND_SOC_WM8985
+	tristate "Wolfson Microelectronics WM8985 and WM8758 codec driver"
+	depends on SND_SOC_I2C_AND_SPI
+
+config SND_SOC_WM8988
+	tristate
+
+config SND_SOC_WM8990
+	tristate
+
+config SND_SOC_WM8991
+	tristate
+
+config SND_SOC_WM8993
+	tristate
+
+config SND_SOC_WM8994
+	tristate
+
+config SND_SOC_WM8995
+	tristate
+
+config SND_SOC_WM8996
+	tristate
+
+config SND_SOC_WM8997
+	tristate
+
+config SND_SOC_WM8998
+	tristate
+
+config SND_SOC_WM9081
+	tristate
+	depends on I2C
+
+config SND_SOC_WM9090
+	tristate
+
+config SND_SOC_WM9705
+	tristate
+	select REGMAP_AC97
+	select AC97_BUS_COMPAT if AC97_BUS_NEW
+
+config SND_SOC_WM9712
+	tristate
+	select REGMAP_AC97
+	select AC97_BUS_COMPAT if AC97_BUS_NEW
+
+config SND_SOC_WM9713
+	tristate
+	select REGMAP_AC97
+	select AC97_BUS_COMPAT if AC97_BUS_NEW
+
+config SND_SOC_ZX_AUD96P22
+	tristate "ZTE ZX AUD96P22 CODEC"
+	depends on I2C
+	select REGMAP_I2C
+
+# Amp
+config SND_SOC_LM4857
+	tristate
+
+config SND_SOC_MAX9759
+	tristate "Maxim MAX9759 speaker Amplifier"
+	select GPIOLIB
+
+config SND_SOC_MAX9768
+	tristate
+
+config SND_SOC_MAX9877
+	tristate
+
+config SND_SOC_MC13783
+	tristate
+
+config SND_SOC_ML26124
+	tristate
+
+config SND_SOC_MT6351
+	tristate "MediaTek MT6351 Codec"
+
+config SND_SOC_NAU8540
+       tristate "Nuvoton Technology Corporation NAU85L40 CODEC"
+       depends on I2C
+
+config SND_SOC_NAU8810
+	tristate "Nuvoton Technology Corporation NAU88C10 CODEC"
+	depends on I2C
+
+config SND_SOC_NAU8824
+	tristate "Nuvoton Technology Corporation NAU88L24 CODEC"
+	depends on I2C
+
+config SND_SOC_NAU8825
+	tristate
+
+config SND_SOC_TPA6130A2
+	tristate "Texas Instruments TPA6130A2 headphone amplifier"
+	depends on I2C
+
+endmenu
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
new file mode 100644
index 0000000..7ae7c85
--- /dev/null
+++ b/sound/soc/codecs/Makefile
@@ -0,0 +1,517 @@
+# SPDX-License-Identifier: GPL-2.0
+snd-soc-88pm860x-objs := 88pm860x-codec.o
+snd-soc-ab8500-codec-objs := ab8500-codec.o
+snd-soc-ac97-objs := ac97.o
+snd-soc-ad1836-objs := ad1836.o
+snd-soc-ad193x-objs := ad193x.o
+snd-soc-ad193x-spi-objs := ad193x-spi.o
+snd-soc-ad193x-i2c-objs := ad193x-i2c.o
+snd-soc-ad1980-objs := ad1980.o
+snd-soc-ad73311-objs := ad73311.o
+snd-soc-adau-utils-objs := adau-utils.o
+snd-soc-adau1373-objs := adau1373.o
+snd-soc-adau1701-objs := adau1701.o
+snd-soc-adau17x1-objs := adau17x1.o
+snd-soc-adau1761-objs := adau1761.o
+snd-soc-adau1761-i2c-objs := adau1761-i2c.o
+snd-soc-adau1761-spi-objs := adau1761-spi.o
+snd-soc-adau1781-objs := adau1781.o
+snd-soc-adau1781-i2c-objs := adau1781-i2c.o
+snd-soc-adau1781-spi-objs := adau1781-spi.o
+snd-soc-adau1977-objs := adau1977.o
+snd-soc-adau1977-spi-objs := adau1977-spi.o
+snd-soc-adau1977-i2c-objs := adau1977-i2c.o
+snd-soc-adau7002-objs := adau7002.o
+snd-soc-adav80x-objs := adav80x.o
+snd-soc-adav801-objs := adav801.o
+snd-soc-adav803-objs := adav803.o
+snd-soc-ads117x-objs := ads117x.o
+snd-soc-ak4104-objs := ak4104.o
+snd-soc-ak4458-objs := ak4458.o
+snd-soc-ak4535-objs := ak4535.o
+snd-soc-ak4554-objs := ak4554.o
+snd-soc-ak4613-objs := ak4613.o
+snd-soc-ak4641-objs := ak4641.o
+snd-soc-ak4642-objs := ak4642.o
+snd-soc-ak4671-objs := ak4671.o
+snd-soc-ak5386-objs := ak5386.o
+snd-soc-ak5558-objs := ak5558.o
+snd-soc-arizona-objs := arizona.o
+snd-soc-bd28623-objs := bd28623.o
+snd-soc-bt-sco-objs := bt-sco.o
+snd-soc-cpcap-objs := cpcap.o
+snd-soc-cq93vc-objs := cq93vc.o
+snd-soc-cs35l32-objs := cs35l32.o
+snd-soc-cs35l33-objs := cs35l33.o
+snd-soc-cs35l34-objs := cs35l34.o
+snd-soc-cs35l35-objs := cs35l35.o
+snd-soc-cs42l42-objs := cs42l42.o
+snd-soc-cs42l51-objs := cs42l51.o
+snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
+snd-soc-cs42l52-objs := cs42l52.o
+snd-soc-cs42l56-objs := cs42l56.o
+snd-soc-cs42l73-objs := cs42l73.o
+snd-soc-cs4265-objs := cs4265.o
+snd-soc-cs4270-objs := cs4270.o
+snd-soc-cs4271-objs := cs4271.o
+snd-soc-cs4271-i2c-objs := cs4271-i2c.o
+snd-soc-cs4271-spi-objs := cs4271-spi.o
+snd-soc-cs42xx8-objs := cs42xx8.o
+snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
+snd-soc-cs43130-objs := cs43130.o
+snd-soc-cs4349-objs := cs4349.o
+snd-soc-cs47l24-objs := cs47l24.o
+snd-soc-cs53l30-objs := cs53l30.o
+snd-soc-cx20442-objs := cx20442.o
+snd-soc-da7210-objs := da7210.o
+snd-soc-da7213-objs := da7213.o
+snd-soc-da7218-objs := da7218.o
+snd-soc-da7219-objs := da7219.o da7219-aad.o
+snd-soc-da732x-objs := da732x.o
+snd-soc-da9055-objs := da9055.o
+snd-soc-dmic-objs := dmic.o
+snd-soc-es7134-objs := es7134.o
+snd-soc-es7241-objs := es7241.o
+snd-soc-es8316-objs := es8316.o
+snd-soc-es8328-objs := es8328.o
+snd-soc-es8328-i2c-objs := es8328-i2c.o
+snd-soc-es8328-spi-objs := es8328-spi.o
+snd-soc-gtm601-objs := gtm601.o
+snd-soc-hdac-hdmi-objs := hdac_hdmi.o
+snd-soc-ics43432-objs := ics43432.o
+snd-soc-inno-rk3036-objs := inno_rk3036.o
+snd-soc-isabelle-objs := isabelle.o
+snd-soc-jz4740-codec-objs := jz4740.o
+snd-soc-l3-objs := l3.o
+snd-soc-lm4857-objs := lm4857.o
+snd-soc-lm49453-objs := lm49453.o
+snd-soc-max9759-objs := max9759.o
+snd-soc-max9768-objs := max9768.o
+snd-soc-max98088-objs := max98088.o
+snd-soc-max98090-objs := max98090.o
+snd-soc-max98095-objs := max98095.o
+snd-soc-max98357a-objs := max98357a.o
+snd-soc-max98371-objs := max98371.o
+snd-soc-max9867-objs := max9867.o
+snd-soc-max98925-objs := max98925.o
+snd-soc-max98926-objs := max98926.o
+snd-soc-max98927-objs := max98927.o
+snd-soc-max98373-objs := max98373.o
+snd-soc-max9850-objs := max9850.o
+snd-soc-max9860-objs := max9860.o
+snd-soc-mc13783-objs := mc13783.o
+snd-soc-ml26124-objs := ml26124.o
+snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
+snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
+snd-soc-mt6351-objs := mt6351.o
+snd-soc-nau8540-objs := nau8540.o
+snd-soc-nau8810-objs := nau8810.o
+snd-soc-nau8824-objs := nau8824.o
+snd-soc-nau8825-objs := nau8825.o
+snd-soc-hdmi-codec-objs := hdmi-codec.o
+snd-soc-pcm1681-objs := pcm1681.o
+snd-soc-pcm1789-codec-objs := pcm1789.o
+snd-soc-pcm1789-i2c-objs := pcm1789-i2c.o
+snd-soc-pcm179x-codec-objs := pcm179x.o
+snd-soc-pcm179x-i2c-objs := pcm179x-i2c.o
+snd-soc-pcm179x-spi-objs := pcm179x-spi.o
+snd-soc-pcm186x-objs := pcm186x.o
+snd-soc-pcm186x-i2c-objs := pcm186x-i2c.o
+snd-soc-pcm186x-spi-objs := pcm186x-spi.o
+snd-soc-pcm3008-objs := pcm3008.o
+snd-soc-pcm3168a-objs := pcm3168a.o
+snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o
+snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o
+snd-soc-pcm5102a-objs := pcm5102a.o
+snd-soc-pcm512x-objs := pcm512x.o
+snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
+snd-soc-pcm512x-spi-objs := pcm512x-spi.o
+snd-soc-rl6231-objs := rl6231.o
+snd-soc-rl6347a-objs := rl6347a.o
+snd-soc-rt1305-objs := rt1305.o
+snd-soc-rt274-objs := rt274.o
+snd-soc-rt286-objs := rt286.o
+snd-soc-rt298-objs := rt298.o
+snd-soc-rt5514-objs := rt5514.o
+snd-soc-rt5514-spi-objs := rt5514-spi.o
+snd-soc-rt5616-objs := rt5616.o
+snd-soc-rt5631-objs := rt5631.o
+snd-soc-rt5640-objs := rt5640.o
+snd-soc-rt5645-objs := rt5645.o
+snd-soc-rt5651-objs := rt5651.o
+snd-soc-rt5659-objs := rt5659.o
+snd-soc-rt5660-objs := rt5660.o
+snd-soc-rt5663-objs := rt5663.o
+snd-soc-rt5665-objs := rt5665.o
+snd-soc-rt5668-objs := rt5668.o
+snd-soc-rt5670-objs := rt5670.o
+snd-soc-rt5677-objs := rt5677.o
+snd-soc-rt5677-spi-objs := rt5677-spi.o
+snd-soc-rt5682-objs := rt5682.o
+snd-soc-sgtl5000-objs := sgtl5000.o
+snd-soc-alc5623-objs := alc5623.o
+snd-soc-alc5632-objs := alc5632.o
+snd-soc-sigmadsp-objs := sigmadsp.o
+snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o
+snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o
+snd-soc-si476x-objs := si476x.o
+snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
+snd-soc-spdif-tx-objs := spdif_transmitter.o
+snd-soc-spdif-rx-objs := spdif_receiver.o
+snd-soc-ssm2305-objs := ssm2305.o
+snd-soc-ssm2518-objs := ssm2518.o
+snd-soc-ssm2602-objs := ssm2602.o
+snd-soc-ssm2602-spi-objs := ssm2602-spi.o
+snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o
+snd-soc-ssm4567-objs := ssm4567.o
+snd-soc-sta32x-objs := sta32x.o
+snd-soc-sta350-objs := sta350.o
+snd-soc-sta529-objs := sta529.o
+snd-soc-stac9766-objs := stac9766.o
+snd-soc-sti-sas-objs := sti-sas.o
+snd-soc-tas5086-objs := tas5086.o
+snd-soc-tas571x-objs := tas571x.o
+snd-soc-tas5720-objs := tas5720.o
+snd-soc-tas6424-objs := tas6424.o
+snd-soc-tda7419-objs := tda7419.o
+snd-soc-tfa9879-objs := tfa9879.o
+snd-soc-tlv320aic23-objs := tlv320aic23.o
+snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
+snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
+snd-soc-tlv320aic26-objs := tlv320aic26.o
+snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
+snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
+snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o
+snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
+snd-soc-tlv320aic3x-objs := tlv320aic3x.o
+snd-soc-tlv320dac33-objs := tlv320dac33.o
+snd-soc-tscs42xx-objs := tscs42xx.o
+snd-soc-tscs454-objs := tscs454.o
+snd-soc-ts3a227e-objs := ts3a227e.o
+snd-soc-twl4030-objs := twl4030.o
+snd-soc-twl6040-objs := twl6040.o
+snd-soc-uda134x-objs := uda134x.o
+snd-soc-uda1380-objs := uda1380.o
+snd-soc-wl1273-objs := wl1273.o
+snd-soc-wm-adsp-objs := wm_adsp.o
+snd-soc-wm0010-objs := wm0010.o
+snd-soc-wm1250-ev1-objs := wm1250-ev1.o
+snd-soc-wm2000-objs := wm2000.o
+snd-soc-wm2200-objs := wm2200.o
+snd-soc-wm5100-objs := wm5100.o wm5100-tables.o
+snd-soc-wm5102-objs := wm5102.o
+snd-soc-wm5110-objs := wm5110.o
+snd-soc-wm8350-objs := wm8350.o
+snd-soc-wm8400-objs := wm8400.o
+snd-soc-wm8510-objs := wm8510.o
+snd-soc-wm8523-objs := wm8523.o
+snd-soc-wm8524-objs := wm8524.o
+snd-soc-wm8580-objs := wm8580.o
+snd-soc-wm8711-objs := wm8711.o
+snd-soc-wm8727-objs := wm8727.o
+snd-soc-wm8728-objs := wm8728.o
+snd-soc-wm8731-objs := wm8731.o
+snd-soc-wm8737-objs := wm8737.o
+snd-soc-wm8741-objs := wm8741.o
+snd-soc-wm8750-objs := wm8750.o
+snd-soc-wm8753-objs := wm8753.o
+snd-soc-wm8770-objs := wm8770.o
+snd-soc-wm8776-objs := wm8776.o
+snd-soc-wm8782-objs := wm8782.o
+snd-soc-wm8804-objs := wm8804.o
+snd-soc-wm8804-i2c-objs := wm8804-i2c.o
+snd-soc-wm8804-spi-objs := wm8804-spi.o
+snd-soc-wm8900-objs := wm8900.o
+snd-soc-wm8903-objs := wm8903.o
+snd-soc-wm8904-objs := wm8904.o
+snd-soc-wm8996-objs := wm8996.o
+snd-soc-wm8940-objs := wm8940.o
+snd-soc-wm8955-objs := wm8955.o
+snd-soc-wm8960-objs := wm8960.o
+snd-soc-wm8961-objs := wm8961.o
+snd-soc-wm8962-objs := wm8962.o
+snd-soc-wm8971-objs := wm8971.o
+snd-soc-wm8974-objs := wm8974.o
+snd-soc-wm8978-objs := wm8978.o
+snd-soc-wm8983-objs := wm8983.o
+snd-soc-wm8985-objs := wm8985.o
+snd-soc-wm8988-objs := wm8988.o
+snd-soc-wm8990-objs := wm8990.o
+snd-soc-wm8991-objs := wm8991.o
+snd-soc-wm8993-objs := wm8993.o
+snd-soc-wm8994-objs := wm8994.o wm8958-dsp2.o
+snd-soc-wm8995-objs := wm8995.o
+snd-soc-wm8997-objs := wm8997.o
+snd-soc-wm8998-objs := wm8998.o
+snd-soc-wm9081-objs := wm9081.o
+snd-soc-wm9090-objs := wm9090.o
+snd-soc-wm9705-objs := wm9705.o
+snd-soc-wm9712-objs := wm9712.o
+snd-soc-wm9713-objs := wm9713.o
+snd-soc-wm-hubs-objs := wm_hubs.o
+snd-soc-zx-aud96p22-objs := zx_aud96p22.o
+# Amp
+snd-soc-max9877-objs := max9877.o
+snd-soc-max98504-objs := max98504.o
+snd-soc-simple-amplifier-objs := simple-amplifier.o
+snd-soc-tpa6130a2-objs := tpa6130a2.o
+snd-soc-tas2552-objs := tas2552.o
+
+obj-$(CONFIG_SND_SOC_88PM860X)	+= snd-soc-88pm860x.o
+obj-$(CONFIG_SND_SOC_AB8500_CODEC)	+= snd-soc-ab8500-codec.o
+obj-$(CONFIG_SND_SOC_AC97_CODEC)	+= snd-soc-ac97.o
+obj-$(CONFIG_SND_SOC_AD1836)	+= snd-soc-ad1836.o
+obj-$(CONFIG_SND_SOC_AD193X)	+= snd-soc-ad193x.o
+obj-$(CONFIG_SND_SOC_AD193X_SPI)	+= snd-soc-ad193x-spi.o
+obj-$(CONFIG_SND_SOC_AD193X_I2C)	+= snd-soc-ad193x-i2c.o
+obj-$(CONFIG_SND_SOC_AD1980)	+= snd-soc-ad1980.o
+obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
+obj-$(CONFIG_SND_SOC_ADAU_UTILS)	+= snd-soc-adau-utils.o
+obj-$(CONFIG_SND_SOC_ADAU1373)	+= snd-soc-adau1373.o
+obj-$(CONFIG_SND_SOC_ADAU1701)		+= snd-soc-adau1701.o
+obj-$(CONFIG_SND_SOC_ADAU17X1)		+= snd-soc-adau17x1.o
+obj-$(CONFIG_SND_SOC_ADAU1761)		+= snd-soc-adau1761.o
+obj-$(CONFIG_SND_SOC_ADAU1761_I2C)	+= snd-soc-adau1761-i2c.o
+obj-$(CONFIG_SND_SOC_ADAU1761_SPI)	+= snd-soc-adau1761-spi.o
+obj-$(CONFIG_SND_SOC_ADAU1781)		+= snd-soc-adau1781.o
+obj-$(CONFIG_SND_SOC_ADAU1781_I2C)	+= snd-soc-adau1781-i2c.o
+obj-$(CONFIG_SND_SOC_ADAU1781_SPI)	+= snd-soc-adau1781-spi.o
+obj-$(CONFIG_SND_SOC_ADAU1977)		+= snd-soc-adau1977.o
+obj-$(CONFIG_SND_SOC_ADAU1977_SPI)	+= snd-soc-adau1977-spi.o
+obj-$(CONFIG_SND_SOC_ADAU1977_I2C)	+= snd-soc-adau1977-i2c.o
+obj-$(CONFIG_SND_SOC_ADAU7002)	+= snd-soc-adau7002.o
+obj-$(CONFIG_SND_SOC_ADAV80X)  += snd-soc-adav80x.o
+obj-$(CONFIG_SND_SOC_ADAV801)  += snd-soc-adav801.o
+obj-$(CONFIG_SND_SOC_ADAV803)  += snd-soc-adav803.o
+obj-$(CONFIG_SND_SOC_ADS117X)	+= snd-soc-ads117x.o
+obj-$(CONFIG_SND_SOC_AK4104)	+= snd-soc-ak4104.o
+obj-$(CONFIG_SND_SOC_AK4458)	+= snd-soc-ak4458.o
+obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
+obj-$(CONFIG_SND_SOC_AK4554)	+= snd-soc-ak4554.o
+obj-$(CONFIG_SND_SOC_AK4613)	+= snd-soc-ak4613.o
+obj-$(CONFIG_SND_SOC_AK4641)	+= snd-soc-ak4641.o
+obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
+obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
+obj-$(CONFIG_SND_SOC_AK5386)	+= snd-soc-ak5386.o
+obj-$(CONFIG_SND_SOC_AK5558)	+= snd-soc-ak5558.o
+obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
+obj-$(CONFIG_SND_SOC_ALC5632)	+= snd-soc-alc5632.o
+obj-$(CONFIG_SND_SOC_ARIZONA)	+= snd-soc-arizona.o
+obj-$(CONFIG_SND_SOC_BD28623)	+= snd-soc-bd28623.o
+obj-$(CONFIG_SND_SOC_BT_SCO)	+= snd-soc-bt-sco.o
+obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
+obj-$(CONFIG_SND_SOC_CPCAP)	+= snd-soc-cpcap.o
+obj-$(CONFIG_SND_SOC_CS35L32)	+= snd-soc-cs35l32.o
+obj-$(CONFIG_SND_SOC_CS35L33)	+= snd-soc-cs35l33.o
+obj-$(CONFIG_SND_SOC_CS35L34)	+= snd-soc-cs35l34.o
+obj-$(CONFIG_SND_SOC_CS35L35)	+= snd-soc-cs35l35.o
+obj-$(CONFIG_SND_SOC_CS42L42)	+= snd-soc-cs42l42.o
+obj-$(CONFIG_SND_SOC_CS42L51)	+= snd-soc-cs42l51.o
+obj-$(CONFIG_SND_SOC_CS42L51_I2C)	+= snd-soc-cs42l51-i2c.o
+obj-$(CONFIG_SND_SOC_CS42L52)	+= snd-soc-cs42l52.o
+obj-$(CONFIG_SND_SOC_CS42L56)	+= snd-soc-cs42l56.o
+obj-$(CONFIG_SND_SOC_CS42L73)	+= snd-soc-cs42l73.o
+obj-$(CONFIG_SND_SOC_CS4265)	+= snd-soc-cs4265.o
+obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
+obj-$(CONFIG_SND_SOC_CS4271)	+= snd-soc-cs4271.o
+obj-$(CONFIG_SND_SOC_CS4271_I2C)	+= snd-soc-cs4271-i2c.o
+obj-$(CONFIG_SND_SOC_CS4271_SPI)	+= snd-soc-cs4271-spi.o
+obj-$(CONFIG_SND_SOC_CS42XX8)	+= snd-soc-cs42xx8.o
+obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
+obj-$(CONFIG_SND_SOC_CS43130)   += snd-soc-cs43130.o
+obj-$(CONFIG_SND_SOC_CS4349)	+= snd-soc-cs4349.o
+obj-$(CONFIG_SND_SOC_CS47L24)	+= snd-soc-cs47l24.o
+obj-$(CONFIG_SND_SOC_CS53L30)	+= snd-soc-cs53l30.o
+obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o
+obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o
+obj-$(CONFIG_SND_SOC_DA7213)	+= snd-soc-da7213.o
+obj-$(CONFIG_SND_SOC_DA7218)	+= snd-soc-da7218.o
+obj-$(CONFIG_SND_SOC_DA7219)	+= snd-soc-da7219.o
+obj-$(CONFIG_SND_SOC_DA732X)	+= snd-soc-da732x.o
+obj-$(CONFIG_SND_SOC_DA9055)	+= snd-soc-da9055.o
+obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
+obj-$(CONFIG_SND_SOC_ES7134)	+= snd-soc-es7134.o
+obj-$(CONFIG_SND_SOC_ES7241)	+= snd-soc-es7241.o
+obj-$(CONFIG_SND_SOC_ES8316)    += snd-soc-es8316.o
+obj-$(CONFIG_SND_SOC_ES8328)	+= snd-soc-es8328.o
+obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
+obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
+obj-$(CONFIG_SND_SOC_GTM601)    += snd-soc-gtm601.o
+obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o
+obj-$(CONFIG_SND_SOC_ICS43432)	+= snd-soc-ics43432.o
+obj-$(CONFIG_SND_SOC_INNO_RK3036)	+= snd-soc-inno-rk3036.o
+obj-$(CONFIG_SND_SOC_ISABELLE)	+= snd-soc-isabelle.o
+obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
+obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
+obj-$(CONFIG_SND_SOC_LM4857)	+= snd-soc-lm4857.o
+obj-$(CONFIG_SND_SOC_LM49453)   += snd-soc-lm49453.o
+obj-$(CONFIG_SND_SOC_MAX9759)	+= snd-soc-max9759.o
+obj-$(CONFIG_SND_SOC_MAX9768)	+= snd-soc-max9768.o
+obj-$(CONFIG_SND_SOC_MAX98088)	+= snd-soc-max98088.o
+obj-$(CONFIG_SND_SOC_MAX98090)	+= snd-soc-max98090.o
+obj-$(CONFIG_SND_SOC_MAX98095)	+= snd-soc-max98095.o
+obj-$(CONFIG_SND_SOC_MAX98357A)	+= snd-soc-max98357a.o
+obj-$(CONFIG_SND_SOC_MAX98371)	+= snd-soc-max98371.o
+obj-$(CONFIG_SND_SOC_MAX9867)	+= snd-soc-max9867.o
+obj-$(CONFIG_SND_SOC_MAX98925)	+= snd-soc-max98925.o
+obj-$(CONFIG_SND_SOC_MAX98926)	+= snd-soc-max98926.o
+obj-$(CONFIG_SND_SOC_MAX98927)	+= snd-soc-max98927.o
+obj-$(CONFIG_SND_SOC_MAX98373)	+= snd-soc-max98373.o
+obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
+obj-$(CONFIG_SND_SOC_MAX9860)	+= snd-soc-max9860.o
+obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o
+obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
+obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o
+obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
+obj-$(CONFIG_SND_SOC_MT6351)	+= snd-soc-mt6351.o
+obj-$(CONFIG_SND_SOC_NAU8540)   += snd-soc-nau8540.o
+obj-$(CONFIG_SND_SOC_NAU8810)   += snd-soc-nau8810.o
+obj-$(CONFIG_SND_SOC_NAU8824)   += snd-soc-nau8824.o
+obj-$(CONFIG_SND_SOC_NAU8825)   += snd-soc-nau8825.o
+obj-$(CONFIG_SND_SOC_HDMI_CODEC)	+= snd-soc-hdmi-codec.o
+obj-$(CONFIG_SND_SOC_PCM1681)	+= snd-soc-pcm1681.o
+obj-$(CONFIG_SND_SOC_PCM179X)	+= snd-soc-pcm179x-codec.o
+obj-$(CONFIG_SND_SOC_PCM1789_I2C)	+= snd-soc-pcm1789-i2c.o
+obj-$(CONFIG_SND_SOC_PCM1789)	+= snd-soc-pcm1789-codec.o
+obj-$(CONFIG_SND_SOC_PCM179X_I2C)	+= snd-soc-pcm179x-i2c.o
+obj-$(CONFIG_SND_SOC_PCM179X_SPI)	+= snd-soc-pcm179x-spi.o
+obj-$(CONFIG_SND_SOC_PCM186X)	+= snd-soc-pcm186x.o
+obj-$(CONFIG_SND_SOC_PCM186X_I2C)	+= snd-soc-pcm186x-i2c.o
+obj-$(CONFIG_SND_SOC_PCM186X_SPI)	+= snd-soc-pcm186x-spi.o
+obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
+obj-$(CONFIG_SND_SOC_PCM3168A)	+= snd-soc-pcm3168a.o
+obj-$(CONFIG_SND_SOC_PCM3168A_I2C)	+= snd-soc-pcm3168a-i2c.o
+obj-$(CONFIG_SND_SOC_PCM3168A_SPI)	+= snd-soc-pcm3168a-spi.o
+obj-$(CONFIG_SND_SOC_PCM5102A)	+= snd-soc-pcm5102a.o
+obj-$(CONFIG_SND_SOC_PCM512x)	+= snd-soc-pcm512x.o
+obj-$(CONFIG_SND_SOC_PCM512x_I2C)	+= snd-soc-pcm512x-i2c.o
+obj-$(CONFIG_SND_SOC_PCM512x_SPI)	+= snd-soc-pcm512x-spi.o
+obj-$(CONFIG_SND_SOC_RL6231)	+= snd-soc-rl6231.o
+obj-$(CONFIG_SND_SOC_RL6347A)	+= snd-soc-rl6347a.o
+obj-$(CONFIG_SND_SOC_RT1305)	+= snd-soc-rt1305.o
+obj-$(CONFIG_SND_SOC_RT274)	+= snd-soc-rt274.o
+obj-$(CONFIG_SND_SOC_RT286)	+= snd-soc-rt286.o
+obj-$(CONFIG_SND_SOC_RT298)	+= snd-soc-rt298.o
+obj-$(CONFIG_SND_SOC_RT5514)	+= snd-soc-rt5514.o
+obj-$(CONFIG_SND_SOC_RT5514_SPI)	+= snd-soc-rt5514-spi.o
+obj-$(CONFIG_SND_SOC_RT5514_SPI_BUILTIN)	+= snd-soc-rt5514-spi.o
+obj-$(CONFIG_SND_SOC_RT5616)	+= snd-soc-rt5616.o
+obj-$(CONFIG_SND_SOC_RT5631)	+= snd-soc-rt5631.o
+obj-$(CONFIG_SND_SOC_RT5640)	+= snd-soc-rt5640.o
+obj-$(CONFIG_SND_SOC_RT5645)	+= snd-soc-rt5645.o
+obj-$(CONFIG_SND_SOC_RT5651)	+= snd-soc-rt5651.o
+obj-$(CONFIG_SND_SOC_RT5659)	+= snd-soc-rt5659.o
+obj-$(CONFIG_SND_SOC_RT5660)	+= snd-soc-rt5660.o
+obj-$(CONFIG_SND_SOC_RT5663)	+= snd-soc-rt5663.o
+obj-$(CONFIG_SND_SOC_RT5665)	+= snd-soc-rt5665.o
+obj-$(CONFIG_SND_SOC_RT5668)	+= snd-soc-rt5668.o
+obj-$(CONFIG_SND_SOC_RT5670)	+= snd-soc-rt5670.o
+obj-$(CONFIG_SND_SOC_RT5677)	+= snd-soc-rt5677.o
+obj-$(CONFIG_SND_SOC_RT5677_SPI)	+= snd-soc-rt5677-spi.o
+obj-$(CONFIG_SND_SOC_RT5682)	+= snd-soc-rt5682.o
+obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
+obj-$(CONFIG_SND_SOC_SIGMADSP)	+= snd-soc-sigmadsp.o
+obj-$(CONFIG_SND_SOC_SIGMADSP_I2C)	+= snd-soc-sigmadsp-i2c.o
+obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP)	+= snd-soc-sigmadsp-regmap.o
+obj-$(CONFIG_SND_SOC_SI476X)	+= snd-soc-si476x.o
+obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif-rx.o snd-soc-spdif-tx.o
+obj-$(CONFIG_SND_SOC_SIRF_AUDIO_CODEC) += sirf-audio-codec.o
+obj-$(CONFIG_SND_SOC_SSM2305)	+= snd-soc-ssm2305.o
+obj-$(CONFIG_SND_SOC_SSM2518)	+= snd-soc-ssm2518.o
+obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
+obj-$(CONFIG_SND_SOC_SSM2602_SPI)	+= snd-soc-ssm2602-spi.o
+obj-$(CONFIG_SND_SOC_SSM2602_I2C)	+= snd-soc-ssm2602-i2c.o
+obj-$(CONFIG_SND_SOC_SSM4567)	+= snd-soc-ssm4567.o
+obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o
+obj-$(CONFIG_SND_SOC_STA350)   += snd-soc-sta350.o
+obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
+obj-$(CONFIG_SND_SOC_STAC9766)	+= snd-soc-stac9766.o
+obj-$(CONFIG_SND_SOC_STI_SAS)	+= snd-soc-sti-sas.o
+obj-$(CONFIG_SND_SOC_TAS2552)	+= snd-soc-tas2552.o
+obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
+obj-$(CONFIG_SND_SOC_TAS571X)	+= snd-soc-tas571x.o
+obj-$(CONFIG_SND_SOC_TAS5720)	+= snd-soc-tas5720.o
+obj-$(CONFIG_SND_SOC_TAS6424)	+= snd-soc-tas6424.o
+obj-$(CONFIG_SND_SOC_TDA7419)	+= snd-soc-tda7419.o
+obj-$(CONFIG_SND_SOC_TFA9879)	+= snd-soc-tfa9879.o
+obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
+obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)	+= snd-soc-tlv320aic23-i2c.o
+obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI)	+= snd-soc-tlv320aic23-spi.o
+obj-$(CONFIG_SND_SOC_TLV320AIC26)	+= snd-soc-tlv320aic26.o
+obj-$(CONFIG_SND_SOC_TLV320AIC31XX)     += snd-soc-tlv320aic31xx.o
+obj-$(CONFIG_SND_SOC_TLV320AIC32X4)     += snd-soc-tlv320aic32x4.o
+obj-$(CONFIG_SND_SOC_TLV320AIC32X4_I2C)	+= snd-soc-tlv320aic32x4-i2c.o
+obj-$(CONFIG_SND_SOC_TLV320AIC32X4_SPI)	+= snd-soc-tlv320aic32x4-spi.o
+obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
+obj-$(CONFIG_SND_SOC_TLV320DAC33)	+= snd-soc-tlv320dac33.o
+obj-$(CONFIG_SND_SOC_TSCS42XX)	+= snd-soc-tscs42xx.o
+obj-$(CONFIG_SND_SOC_TSCS454)	+= snd-soc-tscs454.o
+obj-$(CONFIG_SND_SOC_TS3A227E)	+= snd-soc-ts3a227e.o
+obj-$(CONFIG_SND_SOC_TWL4030)	+= snd-soc-twl4030.o
+obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o
+obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
+obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
+obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
+obj-$(CONFIG_SND_SOC_WM0010)	+= snd-soc-wm0010.o
+obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
+obj-$(CONFIG_SND_SOC_WM2000)	+= snd-soc-wm2000.o
+obj-$(CONFIG_SND_SOC_WM2200)	+= snd-soc-wm2200.o
+obj-$(CONFIG_SND_SOC_WM5100)	+= snd-soc-wm5100.o
+obj-$(CONFIG_SND_SOC_WM5102)	+= snd-soc-wm5102.o
+obj-$(CONFIG_SND_SOC_WM5110)	+= snd-soc-wm5110.o
+obj-$(CONFIG_SND_SOC_WM8350)	+= snd-soc-wm8350.o
+obj-$(CONFIG_SND_SOC_WM8400)	+= snd-soc-wm8400.o
+obj-$(CONFIG_SND_SOC_WM8510)	+= snd-soc-wm8510.o
+obj-$(CONFIG_SND_SOC_WM8523)	+= snd-soc-wm8523.o
+obj-$(CONFIG_SND_SOC_WM8524)	+= snd-soc-wm8524.o
+obj-$(CONFIG_SND_SOC_WM8580)	+= snd-soc-wm8580.o
+obj-$(CONFIG_SND_SOC_WM8711)	+= snd-soc-wm8711.o
+obj-$(CONFIG_SND_SOC_WM8727)	+= snd-soc-wm8727.o
+obj-$(CONFIG_SND_SOC_WM8728)	+= snd-soc-wm8728.o
+obj-$(CONFIG_SND_SOC_WM8731)	+= snd-soc-wm8731.o
+obj-$(CONFIG_SND_SOC_WM8737)	+= snd-soc-wm8737.o
+obj-$(CONFIG_SND_SOC_WM8741)	+= snd-soc-wm8741.o
+obj-$(CONFIG_SND_SOC_WM8750)	+= snd-soc-wm8750.o
+obj-$(CONFIG_SND_SOC_WM8753)	+= snd-soc-wm8753.o
+obj-$(CONFIG_SND_SOC_WM8770)	+= snd-soc-wm8770.o
+obj-$(CONFIG_SND_SOC_WM8776)	+= snd-soc-wm8776.o
+obj-$(CONFIG_SND_SOC_WM8782)	+= snd-soc-wm8782.o
+obj-$(CONFIG_SND_SOC_WM8804)	+= snd-soc-wm8804.o
+obj-$(CONFIG_SND_SOC_WM8804_I2C) += snd-soc-wm8804-i2c.o
+obj-$(CONFIG_SND_SOC_WM8804_SPI) += snd-soc-wm8804-spi.o
+obj-$(CONFIG_SND_SOC_WM8900)	+= snd-soc-wm8900.o
+obj-$(CONFIG_SND_SOC_WM8903)	+= snd-soc-wm8903.o
+obj-$(CONFIG_SND_SOC_WM8904)	+= snd-soc-wm8904.o
+obj-$(CONFIG_SND_SOC_WM8996)	+= snd-soc-wm8996.o
+obj-$(CONFIG_SND_SOC_WM8940)	+= snd-soc-wm8940.o
+obj-$(CONFIG_SND_SOC_WM8955)	+= snd-soc-wm8955.o
+obj-$(CONFIG_SND_SOC_WM8960)	+= snd-soc-wm8960.o
+obj-$(CONFIG_SND_SOC_WM8961)	+= snd-soc-wm8961.o
+obj-$(CONFIG_SND_SOC_WM8962)	+= snd-soc-wm8962.o
+obj-$(CONFIG_SND_SOC_WM8971)	+= snd-soc-wm8971.o
+obj-$(CONFIG_SND_SOC_WM8974)	+= snd-soc-wm8974.o
+obj-$(CONFIG_SND_SOC_WM8978)	+= snd-soc-wm8978.o
+obj-$(CONFIG_SND_SOC_WM8983)	+= snd-soc-wm8983.o
+obj-$(CONFIG_SND_SOC_WM8985)	+= snd-soc-wm8985.o
+obj-$(CONFIG_SND_SOC_WM8988)	+= snd-soc-wm8988.o
+obj-$(CONFIG_SND_SOC_WM8990)	+= snd-soc-wm8990.o
+obj-$(CONFIG_SND_SOC_WM8991)	+= snd-soc-wm8991.o
+obj-$(CONFIG_SND_SOC_WM8993)	+= snd-soc-wm8993.o
+obj-$(CONFIG_SND_SOC_WM8994)	+= snd-soc-wm8994.o
+obj-$(CONFIG_SND_SOC_WM8995)	+= snd-soc-wm8995.o
+obj-$(CONFIG_SND_SOC_WM8997)	+= snd-soc-wm8997.o
+obj-$(CONFIG_SND_SOC_WM8998)	+= snd-soc-wm8998.o
+obj-$(CONFIG_SND_SOC_WM9081)	+= snd-soc-wm9081.o
+obj-$(CONFIG_SND_SOC_WM9090)	+= snd-soc-wm9090.o
+obj-$(CONFIG_SND_SOC_WM9705)	+= snd-soc-wm9705.o
+obj-$(CONFIG_SND_SOC_WM9712)	+= snd-soc-wm9712.o
+obj-$(CONFIG_SND_SOC_WM9713)	+= snd-soc-wm9713.o
+obj-$(CONFIG_SND_SOC_WM_ADSP)	+= snd-soc-wm-adsp.o
+obj-$(CONFIG_SND_SOC_WM_HUBS)	+= snd-soc-wm-hubs.o
+obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o
+
+# Amp
+obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
+obj-$(CONFIG_SND_SOC_MAX98504)	+= snd-soc-max98504.o
+obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER)	+= snd-soc-simple-amplifier.o
+obj-$(CONFIG_SND_SOC_TPA6130A2)	+= snd-soc-tpa6130a2.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
new file mode 100644
index 0000000..03bbbcd
--- /dev/null
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -0,0 +1,2586 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>,
+ *         for ST-Ericsson.
+ *
+ *         Based on the early work done by:
+ *         Mikko J. Lehto <mikko.lehto@symbio.com>,
+ *         Mikko Sarmanne <mikko.sarmanne@symbio.com>,
+ *         Jarmo K. Kuronen <jarmo.kuronen@symbio.com>,
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500-sysctrl.h>
+#include <linux/mfd/abx500/ab8500-codec.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "ab8500-codec.h"
+
+/* Macrocell value definitions */
+#define CLK_32K_OUT2_DISABLE			0x01
+#define INACTIVE_RESET_AUDIO			0x02
+#define ENABLE_AUDIO_CLK_TO_AUDIO_BLK		0x10
+#define ENABLE_VINTCORE12_SUPPLY		0x04
+#define GPIO27_DIR_OUTPUT			0x04
+#define GPIO29_DIR_OUTPUT			0x10
+#define GPIO31_DIR_OUTPUT			0x40
+
+/* Macrocell register definitions */
+#define AB8500_GPIO_DIR4_REG			0x13 /* Bank AB8500_MISC */
+
+/* Nr of FIR/IIR-coeff banks in ANC-block */
+#define AB8500_NR_OF_ANC_COEFF_BANKS		2
+
+/* Minimum duration to keep ANC IIR Init bit high or
+low before proceeding with the configuration sequence */
+#define AB8500_ANC_SM_DELAY			2000
+
+#define AB8500_FILTER_CONTROL(xname, xcount, xmin, xmax) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.info = filter_control_info, \
+	.get = filter_control_get, .put = filter_control_put, \
+	.private_value = (unsigned long)&(struct filter_control) \
+		{.count = xcount, .min = xmin, .max = xmax} }
+
+struct filter_control {
+	long min, max;
+	unsigned int count;
+	long value[128];
+};
+
+/* Sidetone states */
+static const char * const enum_sid_state[] = {
+	"Unconfigured",
+	"Apply FIR",
+	"FIR is configured",
+};
+enum sid_state {
+	SID_UNCONFIGURED = 0,
+	SID_APPLY_FIR = 1,
+	SID_FIR_CONFIGURED = 2,
+};
+
+static const char * const enum_anc_state[] = {
+	"Unconfigured",
+	"Apply FIR and IIR",
+	"FIR and IIR are configured",
+	"Apply FIR",
+	"FIR is configured",
+	"Apply IIR",
+	"IIR is configured"
+};
+enum anc_state {
+	ANC_UNCONFIGURED = 0,
+	ANC_APPLY_FIR_IIR = 1,
+	ANC_FIR_IIR_CONFIGURED = 2,
+	ANC_APPLY_FIR = 3,
+	ANC_FIR_CONFIGURED = 4,
+	ANC_APPLY_IIR = 5,
+	ANC_IIR_CONFIGURED = 6
+};
+
+/* Analog microphones */
+enum amic_idx {
+	AMIC_IDX_1A,
+	AMIC_IDX_1B,
+	AMIC_IDX_2
+};
+
+struct ab8500_codec_drvdata_dbg {
+	struct regulator *vaud;
+	struct regulator *vamic1;
+	struct regulator *vamic2;
+	struct regulator *vdmic;
+};
+
+/* Private data for AB8500 device-driver */
+struct ab8500_codec_drvdata {
+	struct regmap *regmap;
+	struct mutex ctrl_lock;
+
+	/* Sidetone */
+	long *sid_fir_values;
+	enum sid_state sid_status;
+
+	/* ANC */
+	long *anc_fir_values;
+	long *anc_iir_values;
+	enum anc_state anc_status;
+};
+
+static inline const char *amic_micbias_str(enum amic_micbias micbias)
+{
+	switch (micbias) {
+	case AMIC_MICBIAS_VAMIC1:
+		return "VAMIC1";
+	case AMIC_MICBIAS_VAMIC2:
+		return "VAMIC2";
+	default:
+		return "Unknown";
+	}
+}
+
+static inline const char *amic_type_str(enum amic_type type)
+{
+	switch (type) {
+	case AMIC_TYPE_DIFFERENTIAL:
+		return "DIFFERENTIAL";
+	case AMIC_TYPE_SINGLE_ENDED:
+		return "SINGLE ENDED";
+	default:
+		return "Unknown";
+	}
+}
+
+/*
+ * Read'n'write functions
+ */
+
+/* Read a register from the audio-bank of AB8500 */
+static int ab8500_codec_read_reg(void *context, unsigned int reg,
+				 unsigned int *value)
+{
+	struct device *dev = context;
+	int status;
+
+	u8 value8;
+	status = abx500_get_register_interruptible(dev, AB8500_AUDIO,
+						   reg, &value8);
+	*value = (unsigned int)value8;
+
+	return status;
+}
+
+/* Write to a register in the audio-bank of AB8500 */
+static int ab8500_codec_write_reg(void *context, unsigned int reg,
+				  unsigned int value)
+{
+	struct device *dev = context;
+
+	return abx500_set_register_interruptible(dev, AB8500_AUDIO,
+						 reg, value);
+}
+
+static const struct regmap_config ab8500_codec_regmap = {
+	.reg_read = ab8500_codec_read_reg,
+	.reg_write = ab8500_codec_write_reg,
+};
+
+/*
+ * Controls - DAPM
+ */
+
+/* Earpiece */
+
+/* Earpiece source selector */
+static const char * const enum_ear_lineout_source[] = {"Headset Left",
+						"Speaker Left"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ear_lineout_source, AB8500_DMICFILTCONF,
+			AB8500_DMICFILTCONF_DA3TOEAR, enum_ear_lineout_source);
+static const struct snd_kcontrol_new dapm_ear_lineout_source =
+	SOC_DAPM_ENUM("Earpiece or LineOut Mono Source",
+		dapm_enum_ear_lineout_source);
+
+/* LineOut */
+
+/* LineOut source selector */
+static const char * const enum_lineout_source[] = {"Mono Path", "Stereo Path"};
+static SOC_ENUM_DOUBLE_DECL(dapm_enum_lineout_source, AB8500_ANACONF5,
+			AB8500_ANACONF5_HSLDACTOLOL,
+			AB8500_ANACONF5_HSRDACTOLOR, enum_lineout_source);
+static const struct snd_kcontrol_new dapm_lineout_source[] = {
+	SOC_DAPM_ENUM("LineOut Source", dapm_enum_lineout_source),
+};
+
+/* Handsfree */
+
+/* Speaker Left - ANC selector */
+static const char * const enum_HFx_sel[] = {"Audio Path", "ANC"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_HFl_sel, AB8500_DIGMULTCONF2,
+			AB8500_DIGMULTCONF2_HFLSEL, enum_HFx_sel);
+static const struct snd_kcontrol_new dapm_HFl_select[] = {
+	SOC_DAPM_ENUM("Speaker Left Source", dapm_enum_HFl_sel),
+};
+
+/* Speaker Right - ANC selector */
+static SOC_ENUM_SINGLE_DECL(dapm_enum_HFr_sel, AB8500_DIGMULTCONF2,
+			AB8500_DIGMULTCONF2_HFRSEL, enum_HFx_sel);
+static const struct snd_kcontrol_new dapm_HFr_select[] = {
+	SOC_DAPM_ENUM("Speaker Right Source", dapm_enum_HFr_sel),
+};
+
+/* Mic 1 */
+
+/* Mic 1 - Mic 1a or 1b selector */
+static const char * const enum_mic1ab_sel[] = {"Mic 1b", "Mic 1a"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_mic1ab_sel, AB8500_ANACONF3,
+			AB8500_ANACONF3_MIC1SEL, enum_mic1ab_sel);
+static const struct snd_kcontrol_new dapm_mic1ab_mux[] = {
+	SOC_DAPM_ENUM("Mic 1a or 1b Select", dapm_enum_mic1ab_sel),
+};
+
+/* Mic 1 - AD3 - Mic 1 or DMic 3 selector */
+static const char * const enum_ad3_sel[] = {"Mic 1", "DMic 3"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad3_sel, AB8500_DIGMULTCONF1,
+			AB8500_DIGMULTCONF1_AD3SEL, enum_ad3_sel);
+static const struct snd_kcontrol_new dapm_ad3_select[] = {
+	SOC_DAPM_ENUM("AD3 Source Select", dapm_enum_ad3_sel),
+};
+
+/* Mic 1 - AD6 - Mic 1 or DMic 6 selector */
+static const char * const enum_ad6_sel[] = {"Mic 1", "DMic 6"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad6_sel, AB8500_DIGMULTCONF1,
+			AB8500_DIGMULTCONF1_AD6SEL, enum_ad6_sel);
+static const struct snd_kcontrol_new dapm_ad6_select[] = {
+	SOC_DAPM_ENUM("AD6 Source Select", dapm_enum_ad6_sel),
+};
+
+/* Mic 2 */
+
+/* Mic 2 - AD5 - Mic 2 or DMic 5 selector */
+static const char * const enum_ad5_sel[] = {"Mic 2", "DMic 5"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad5_sel, AB8500_DIGMULTCONF1,
+			AB8500_DIGMULTCONF1_AD5SEL, enum_ad5_sel);
+static const struct snd_kcontrol_new dapm_ad5_select[] = {
+	SOC_DAPM_ENUM("AD5 Source Select", dapm_enum_ad5_sel),
+};
+
+/* LineIn */
+
+/* LineIn left - AD1 - LineIn Left or DMic 1 selector */
+static const char * const enum_ad1_sel[] = {"LineIn Left", "DMic 1"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad1_sel, AB8500_DIGMULTCONF1,
+			AB8500_DIGMULTCONF1_AD1SEL, enum_ad1_sel);
+static const struct snd_kcontrol_new dapm_ad1_select[] = {
+	SOC_DAPM_ENUM("AD1 Source Select", dapm_enum_ad1_sel),
+};
+
+/* LineIn right - Mic 2 or LineIn Right selector */
+static const char * const enum_mic2lr_sel[] = {"Mic 2", "LineIn Right"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_mic2lr_sel, AB8500_ANACONF3,
+			AB8500_ANACONF3_LINRSEL, enum_mic2lr_sel);
+static const struct snd_kcontrol_new dapm_mic2lr_select[] = {
+	SOC_DAPM_ENUM("Mic 2 or LINR Select", dapm_enum_mic2lr_sel),
+};
+
+/* LineIn right - AD2 - LineIn Right or DMic2 selector */
+static const char * const enum_ad2_sel[] = {"LineIn Right", "DMic 2"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_ad2_sel, AB8500_DIGMULTCONF1,
+			AB8500_DIGMULTCONF1_AD2SEL, enum_ad2_sel);
+static const struct snd_kcontrol_new dapm_ad2_select[] = {
+	SOC_DAPM_ENUM("AD2 Source Select", dapm_enum_ad2_sel),
+};
+
+
+/* ANC */
+
+static const char * const enum_anc_in_sel[] = {"Mic 1 / DMic 6",
+					"Mic 2 / DMic 5"};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_anc_in_sel, AB8500_DMICFILTCONF,
+			AB8500_DMICFILTCONF_ANCINSEL, enum_anc_in_sel);
+static const struct snd_kcontrol_new dapm_anc_in_select[] = {
+	SOC_DAPM_ENUM("ANC Source", dapm_enum_anc_in_sel),
+};
+
+/* ANC - Enable/Disable */
+static const struct snd_kcontrol_new dapm_anc_enable[] = {
+	SOC_DAPM_SINGLE("Switch", AB8500_ANCCONF1,
+			AB8500_ANCCONF1_ENANC, 0, 0),
+};
+
+/* ANC to Earpiece - Mute */
+static const struct snd_kcontrol_new dapm_anc_ear_mute[] = {
+	SOC_DAPM_SINGLE("Switch", AB8500_DIGMULTCONF1,
+			AB8500_DIGMULTCONF1_ANCSEL, 1, 0),
+};
+
+
+
+/* Sidetone left */
+
+/* Sidetone left - Input selector */
+static const char * const enum_stfir1_in_sel[] = {
+	"LineIn Left", "LineIn Right", "Mic 1", "Headset Left"
+};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_stfir1_in_sel, AB8500_DIGMULTCONF2,
+			AB8500_DIGMULTCONF2_FIRSID1SEL, enum_stfir1_in_sel);
+static const struct snd_kcontrol_new dapm_stfir1_in_select[] = {
+	SOC_DAPM_ENUM("Sidetone Left Source", dapm_enum_stfir1_in_sel),
+};
+
+/* Sidetone right path */
+
+/* Sidetone right - Input selector */
+static const char * const enum_stfir2_in_sel[] = {
+	"LineIn Right", "Mic 1", "DMic 4", "Headset Right"
+};
+static SOC_ENUM_SINGLE_DECL(dapm_enum_stfir2_in_sel, AB8500_DIGMULTCONF2,
+			AB8500_DIGMULTCONF2_FIRSID2SEL, enum_stfir2_in_sel);
+static const struct snd_kcontrol_new dapm_stfir2_in_select[] = {
+	SOC_DAPM_ENUM("Sidetone Right Source", dapm_enum_stfir2_in_sel),
+};
+
+/* Vibra */
+
+static const char * const enum_pwm2vibx[] = {"Audio Path", "PWM Generator"};
+
+static SOC_ENUM_SINGLE_DECL(dapm_enum_pwm2vib1, AB8500_PWMGENCONF1,
+			AB8500_PWMGENCONF1_PWMTOVIB1, enum_pwm2vibx);
+
+static const struct snd_kcontrol_new dapm_pwm2vib1[] = {
+	SOC_DAPM_ENUM("Vibra 1 Controller", dapm_enum_pwm2vib1),
+};
+
+static SOC_ENUM_SINGLE_DECL(dapm_enum_pwm2vib2, AB8500_PWMGENCONF1,
+			AB8500_PWMGENCONF1_PWMTOVIB2, enum_pwm2vibx);
+
+static const struct snd_kcontrol_new dapm_pwm2vib2[] = {
+	SOC_DAPM_ENUM("Vibra 2 Controller", dapm_enum_pwm2vib2),
+};
+
+/*
+ * DAPM-widgets
+ */
+
+static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = {
+
+	/* Clocks */
+	SND_SOC_DAPM_CLOCK_SUPPLY("audioclk"),
+
+	/* Regulators */
+	SND_SOC_DAPM_REGULATOR_SUPPLY("V-AUD", 0, 0),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC1", 0, 0),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC2", 0, 0),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("V-DMIC", 0, 0),
+
+	/* Power */
+	SND_SOC_DAPM_SUPPLY("Audio Power",
+			AB8500_POWERUP, AB8500_POWERUP_POWERUP, 0,
+			NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("Audio Analog Power",
+			AB8500_POWERUP, AB8500_POWERUP_ENANA, 0,
+			NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* Main supply node */
+	SND_SOC_DAPM_SUPPLY("Main Supply", SND_SOC_NOPM, 0, 0,
+			NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* DA/AD */
+
+	SND_SOC_DAPM_INPUT("ADC Input"),
+	SND_SOC_DAPM_ADC("ADC", "ab8500_0c", SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_OUTPUT("DAC Output"),
+
+	SND_SOC_DAPM_AIF_IN("DA_IN1", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DA_IN2", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DA_IN3", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DA_IN4", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DA_IN5", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DA_IN6", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AD_OUT1", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AD_OUT2", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AD_OUT3", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AD_OUT4", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AD_OUT57", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AD_OUT68", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+	/* Headset path */
+
+	SND_SOC_DAPM_SUPPLY("Charge Pump", AB8500_ANACONF5,
+			AB8500_ANACONF5_ENCPHS, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("DA1 Enable", "ab8500_0p",
+			AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA1, 0),
+	SND_SOC_DAPM_DAC("DA2 Enable", "ab8500_0p",
+			AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA2, 0),
+
+	SND_SOC_DAPM_PGA("HSL Digital Volume", SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_PGA("HSR Digital Volume", SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_DAC("HSL DAC", "ab8500_0p",
+			AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHSL, 0),
+	SND_SOC_DAPM_DAC("HSR DAC", "ab8500_0p",
+			AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHSR, 0),
+	SND_SOC_DAPM_MIXER("HSL DAC Mute", AB8500_MUTECONF,
+			AB8500_MUTECONF_MUTDACHSL, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("HSR DAC Mute", AB8500_MUTECONF,
+			AB8500_MUTECONF_MUTDACHSR, 1,
+			NULL, 0),
+	SND_SOC_DAPM_DAC("HSL DAC Driver", "ab8500_0p",
+			AB8500_ANACONF3, AB8500_ANACONF3_ENDRVHSL, 0),
+	SND_SOC_DAPM_DAC("HSR DAC Driver", "ab8500_0p",
+			AB8500_ANACONF3, AB8500_ANACONF3_ENDRVHSR, 0),
+
+	SND_SOC_DAPM_MIXER("HSL Mute",
+			AB8500_MUTECONF, AB8500_MUTECONF_MUTHSL, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("HSR Mute",
+			AB8500_MUTECONF, AB8500_MUTECONF_MUTHSR, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("HSL Enable",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENHSL, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("HSR Enable",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENHSR, 0,
+			NULL, 0),
+	SND_SOC_DAPM_PGA("HSL Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_PGA("HSR Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("Headset Left"),
+	SND_SOC_DAPM_OUTPUT("Headset Right"),
+
+	/* LineOut path */
+
+	SND_SOC_DAPM_MUX("LineOut Source",
+			SND_SOC_NOPM, 0, 0, dapm_lineout_source),
+
+	SND_SOC_DAPM_MIXER("LOL Disable HFL",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENHFL, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("LOR Disable HFR",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENHFR, 1,
+			NULL, 0),
+
+	SND_SOC_DAPM_MIXER("LOL Enable",
+			AB8500_ANACONF5, AB8500_ANACONF5_ENLOL, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("LOR Enable",
+			AB8500_ANACONF5, AB8500_ANACONF5_ENLOR, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("LineOut Left"),
+	SND_SOC_DAPM_OUTPUT("LineOut Right"),
+
+	/* Earpiece path */
+
+	SND_SOC_DAPM_MUX("Earpiece or LineOut Mono Source",
+			SND_SOC_NOPM, 0, 0, &dapm_ear_lineout_source),
+	SND_SOC_DAPM_MIXER("EAR DAC",
+			AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACEAR, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("EAR Mute",
+			AB8500_MUTECONF, AB8500_MUTECONF_MUTEAR, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("EAR Enable",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENEAR, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("Earpiece"),
+
+	/* Handsfree path */
+
+	SND_SOC_DAPM_MIXER("DA3 Channel Volume",
+			AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA3, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DA4 Channel Volume",
+			AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA4, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MUX("Speaker Left Source",
+			SND_SOC_NOPM, 0, 0, dapm_HFl_select),
+	SND_SOC_DAPM_MUX("Speaker Right Source",
+			SND_SOC_NOPM, 0, 0, dapm_HFr_select),
+	SND_SOC_DAPM_MIXER("HFL DAC", AB8500_DAPATHCONF,
+			AB8500_DAPATHCONF_ENDACHFL, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("HFR DAC",
+			AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHFR, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DA4 or ANC path to HfR",
+			AB8500_DIGMULTCONF2, AB8500_DIGMULTCONF2_DATOHFREN, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DA3 or ANC path to HfL",
+			AB8500_DIGMULTCONF2, AB8500_DIGMULTCONF2_DATOHFLEN, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("HFL Enable",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENHFL, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("HFR Enable",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENHFR, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("Speaker Left"),
+	SND_SOC_DAPM_OUTPUT("Speaker Right"),
+
+	/* Vibrator path */
+
+	SND_SOC_DAPM_INPUT("PWMGEN1"),
+	SND_SOC_DAPM_INPUT("PWMGEN2"),
+
+	SND_SOC_DAPM_MIXER("DA5 Channel Volume",
+			AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA5, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DA6 Channel Volume",
+			AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA6, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("VIB1 DAC",
+			AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACVIB1, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("VIB2 DAC",
+			AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACVIB2, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MUX("Vibra 1 Controller",
+			SND_SOC_NOPM, 0, 0, dapm_pwm2vib1),
+	SND_SOC_DAPM_MUX("Vibra 2 Controller",
+			SND_SOC_NOPM, 0, 0, dapm_pwm2vib2),
+	SND_SOC_DAPM_MIXER("VIB1 Enable",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENVIB1, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("VIB2 Enable",
+			AB8500_ANACONF4, AB8500_ANACONF4_ENVIB2, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("Vibra 1"),
+	SND_SOC_DAPM_OUTPUT("Vibra 2"),
+
+	/* Mic 1 */
+
+	SND_SOC_DAPM_INPUT("Mic 1"),
+
+	SND_SOC_DAPM_MUX("Mic 1a or 1b Select",
+			SND_SOC_NOPM, 0, 0, dapm_mic1ab_mux),
+	SND_SOC_DAPM_MIXER("MIC1 Mute",
+			AB8500_ANACONF2, AB8500_ANACONF2_MUTMIC1, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("MIC1A V-AMICx Enable",
+			AB8500_ANACONF2, AB8500_ANACONF2_ENMIC1, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("MIC1B V-AMICx Enable",
+			AB8500_ANACONF2, AB8500_ANACONF2_ENMIC1, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("MIC1 ADC",
+			AB8500_ANACONF3, AB8500_ANACONF3_ENADCMIC, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MUX("AD3 Source Select",
+			SND_SOC_NOPM, 0, 0, dapm_ad3_select),
+	SND_SOC_DAPM_MIXER("AD3 Channel Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("AD3 Enable",
+			AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD34, 0,
+			NULL, 0),
+
+	/* Mic 2 */
+
+	SND_SOC_DAPM_INPUT("Mic 2"),
+
+	SND_SOC_DAPM_MIXER("MIC2 Mute",
+			AB8500_ANACONF2, AB8500_ANACONF2_MUTMIC2, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("MIC2 V-AMICx Enable", AB8500_ANACONF2,
+			AB8500_ANACONF2_ENMIC2, 0,
+			NULL, 0),
+
+	/* LineIn */
+
+	SND_SOC_DAPM_INPUT("LineIn Left"),
+	SND_SOC_DAPM_INPUT("LineIn Right"),
+
+	SND_SOC_DAPM_MIXER("LINL Mute",
+			AB8500_ANACONF2, AB8500_ANACONF2_MUTLINL, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("LINR Mute",
+			AB8500_ANACONF2, AB8500_ANACONF2_MUTLINR, 1,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("LINL Enable", AB8500_ANACONF2,
+			AB8500_ANACONF2_ENLINL, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("LINR Enable", AB8500_ANACONF2,
+			AB8500_ANACONF2_ENLINR, 0,
+			NULL, 0),
+
+	/* LineIn Bypass path */
+	SND_SOC_DAPM_MIXER("LINL to HSL Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("LINR to HSR Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+
+	/* LineIn, Mic 2 */
+	SND_SOC_DAPM_MUX("Mic 2 or LINR Select",
+			SND_SOC_NOPM, 0, 0, dapm_mic2lr_select),
+	SND_SOC_DAPM_MIXER("LINL ADC", AB8500_ANACONF3,
+			AB8500_ANACONF3_ENADCLINL, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("LINR ADC", AB8500_ANACONF3,
+			AB8500_ANACONF3_ENADCLINR, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MUX("AD1 Source Select",
+			SND_SOC_NOPM, 0, 0, dapm_ad1_select),
+	SND_SOC_DAPM_MUX("AD2 Source Select",
+			SND_SOC_NOPM, 0, 0, dapm_ad2_select),
+	SND_SOC_DAPM_MIXER("AD1 Channel Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("AD2 Channel Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_MIXER("AD12 Enable",
+			AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD12, 0,
+			NULL, 0),
+
+	/* HD Capture path */
+
+	SND_SOC_DAPM_MUX("AD5 Source Select",
+			SND_SOC_NOPM, 0, 0, dapm_ad5_select),
+	SND_SOC_DAPM_MUX("AD6 Source Select",
+			SND_SOC_NOPM, 0, 0, dapm_ad6_select),
+	SND_SOC_DAPM_MIXER("AD5 Channel Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("AD6 Channel Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("AD57 Enable",
+			AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD5768, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("AD68 Enable",
+			AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD5768, 0,
+			NULL, 0),
+
+	/* Digital Microphone path */
+
+	SND_SOC_DAPM_INPUT("DMic 1"),
+	SND_SOC_DAPM_INPUT("DMic 2"),
+	SND_SOC_DAPM_INPUT("DMic 3"),
+	SND_SOC_DAPM_INPUT("DMic 4"),
+	SND_SOC_DAPM_INPUT("DMic 5"),
+	SND_SOC_DAPM_INPUT("DMic 6"),
+
+	SND_SOC_DAPM_MIXER("DMIC1",
+			AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC1, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DMIC2",
+			AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC2, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DMIC3",
+			AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC3, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DMIC4",
+			AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC4, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DMIC5",
+			AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC5, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("DMIC6",
+			AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC6, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("AD4 Channel Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("AD4 Enable",
+			AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD34,
+			0, NULL, 0),
+
+	/* Acoustical Noise Cancellation path */
+
+	SND_SOC_DAPM_INPUT("ANC Configure Input"),
+	SND_SOC_DAPM_OUTPUT("ANC Configure Output"),
+
+	SND_SOC_DAPM_MUX("ANC Source",
+			SND_SOC_NOPM, 0, 0,
+			dapm_anc_in_select),
+	SND_SOC_DAPM_SWITCH("ANC",
+			SND_SOC_NOPM, 0, 0,
+			dapm_anc_enable),
+	SND_SOC_DAPM_SWITCH("ANC to Earpiece",
+			SND_SOC_NOPM, 0, 0,
+			dapm_anc_ear_mute),
+
+	/* Sidetone Filter path */
+
+	SND_SOC_DAPM_MUX("Sidetone Left Source",
+			SND_SOC_NOPM, 0, 0,
+			dapm_stfir1_in_select),
+	SND_SOC_DAPM_MUX("Sidetone Right Source",
+			SND_SOC_NOPM, 0, 0,
+			dapm_stfir2_in_select),
+	SND_SOC_DAPM_MIXER("STFIR1 Control",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("STFIR2 Control",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("STFIR1 Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_MIXER("STFIR2 Volume",
+			SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+};
+
+/*
+ * DAPM-routes
+ */
+static const struct snd_soc_dapm_route ab8500_dapm_routes[] = {
+	/* Power AB8500 audio-block when AD/DA is active */
+	{"Main Supply", NULL, "V-AUD"},
+	{"Main Supply", NULL, "audioclk"},
+	{"Main Supply", NULL, "Audio Power"},
+	{"Main Supply", NULL, "Audio Analog Power"},
+
+	{"DAC", NULL, "ab8500_0p"},
+	{"DAC", NULL, "Main Supply"},
+	{"ADC", NULL, "ab8500_0c"},
+	{"ADC", NULL, "Main Supply"},
+
+	/* ANC Configure */
+	{"ANC Configure Input", NULL, "Main Supply"},
+	{"ANC Configure Output", NULL, "ANC Configure Input"},
+
+	/* AD/DA */
+	{"ADC", NULL, "ADC Input"},
+	{"DAC Output", NULL, "DAC"},
+
+	/* Powerup charge pump if DA1/2 is in use */
+
+	{"DA_IN1", NULL, "ab8500_0p"},
+	{"DA_IN1", NULL, "Charge Pump"},
+	{"DA_IN2", NULL, "ab8500_0p"},
+	{"DA_IN2", NULL, "Charge Pump"},
+
+	/* Headset path */
+
+	{"DA1 Enable", NULL, "DA_IN1"},
+	{"DA2 Enable", NULL, "DA_IN2"},
+
+	{"HSL Digital Volume", NULL, "DA1 Enable"},
+	{"HSR Digital Volume", NULL, "DA2 Enable"},
+
+	{"HSL DAC", NULL, "HSL Digital Volume"},
+	{"HSR DAC", NULL, "HSR Digital Volume"},
+
+	{"HSL DAC Mute", NULL, "HSL DAC"},
+	{"HSR DAC Mute", NULL, "HSR DAC"},
+
+	{"HSL DAC Driver", NULL, "HSL DAC Mute"},
+	{"HSR DAC Driver", NULL, "HSR DAC Mute"},
+
+	{"HSL Mute", NULL, "HSL DAC Driver"},
+	{"HSR Mute", NULL, "HSR DAC Driver"},
+
+	{"HSL Enable", NULL, "HSL Mute"},
+	{"HSR Enable", NULL, "HSR Mute"},
+
+	{"HSL Volume", NULL, "HSL Enable"},
+	{"HSR Volume", NULL, "HSR Enable"},
+
+	{"Headset Left", NULL, "HSL Volume"},
+	{"Headset Right", NULL, "HSR Volume"},
+
+	/* HF or LineOut path */
+
+	{"DA_IN3", NULL, "ab8500_0p"},
+	{"DA3 Channel Volume", NULL, "DA_IN3"},
+	{"DA_IN4", NULL, "ab8500_0p"},
+	{"DA4 Channel Volume", NULL, "DA_IN4"},
+
+	{"Speaker Left Source", "Audio Path", "DA3 Channel Volume"},
+	{"Speaker Right Source", "Audio Path", "DA4 Channel Volume"},
+
+	{"DA3 or ANC path to HfL", NULL, "Speaker Left Source"},
+	{"DA4 or ANC path to HfR", NULL, "Speaker Right Source"},
+
+	/* HF path */
+
+	{"HFL DAC", NULL, "DA3 or ANC path to HfL"},
+	{"HFR DAC", NULL, "DA4 or ANC path to HfR"},
+
+	{"HFL Enable", NULL, "HFL DAC"},
+	{"HFR Enable", NULL, "HFR DAC"},
+
+	{"Speaker Left", NULL, "HFL Enable"},
+	{"Speaker Right", NULL, "HFR Enable"},
+
+	/* Earpiece path */
+
+	{"Earpiece or LineOut Mono Source", "Headset Left",
+		"HSL Digital Volume"},
+	{"Earpiece or LineOut Mono Source", "Speaker Left",
+		"DA3 or ANC path to HfL"},
+
+	{"EAR DAC", NULL, "Earpiece or LineOut Mono Source"},
+
+	{"EAR Mute", NULL, "EAR DAC"},
+
+	{"EAR Enable", NULL, "EAR Mute"},
+
+	{"Earpiece", NULL, "EAR Enable"},
+
+	/* LineOut path stereo */
+
+	{"LineOut Source", "Stereo Path", "HSL DAC Driver"},
+	{"LineOut Source", "Stereo Path", "HSR DAC Driver"},
+
+	/* LineOut path mono */
+
+	{"LineOut Source", "Mono Path", "EAR DAC"},
+
+	/* LineOut path */
+
+	{"LOL Disable HFL", NULL, "LineOut Source"},
+	{"LOR Disable HFR", NULL, "LineOut Source"},
+
+	{"LOL Enable", NULL, "LOL Disable HFL"},
+	{"LOR Enable", NULL, "LOR Disable HFR"},
+
+	{"LineOut Left", NULL, "LOL Enable"},
+	{"LineOut Right", NULL, "LOR Enable"},
+
+	/* Vibrator path */
+
+	{"DA_IN5", NULL, "ab8500_0p"},
+	{"DA5 Channel Volume", NULL, "DA_IN5"},
+	{"DA_IN6", NULL, "ab8500_0p"},
+	{"DA6 Channel Volume", NULL, "DA_IN6"},
+
+	{"VIB1 DAC", NULL, "DA5 Channel Volume"},
+	{"VIB2 DAC", NULL, "DA6 Channel Volume"},
+
+	{"Vibra 1 Controller", "Audio Path", "VIB1 DAC"},
+	{"Vibra 2 Controller", "Audio Path", "VIB2 DAC"},
+	{"Vibra 1 Controller", "PWM Generator", "PWMGEN1"},
+	{"Vibra 2 Controller", "PWM Generator", "PWMGEN2"},
+
+	{"VIB1 Enable", NULL, "Vibra 1 Controller"},
+	{"VIB2 Enable", NULL, "Vibra 2 Controller"},
+
+	{"Vibra 1", NULL, "VIB1 Enable"},
+	{"Vibra 2", NULL, "VIB2 Enable"},
+
+
+	/* Mic 2 */
+
+	{"MIC2 V-AMICx Enable", NULL, "Mic 2"},
+
+	/* LineIn */
+	{"LINL Mute", NULL, "LineIn Left"},
+	{"LINR Mute", NULL, "LineIn Right"},
+
+	{"LINL Enable", NULL, "LINL Mute"},
+	{"LINR Enable", NULL, "LINR Mute"},
+
+	/* LineIn, Mic 2 */
+	{"Mic 2 or LINR Select", "LineIn Right", "LINR Enable"},
+	{"Mic 2 or LINR Select", "Mic 2", "MIC2 V-AMICx Enable"},
+
+	{"LINL ADC", NULL, "LINL Enable"},
+	{"LINR ADC", NULL, "Mic 2 or LINR Select"},
+
+	{"AD1 Source Select", "LineIn Left", "LINL ADC"},
+	{"AD2 Source Select", "LineIn Right", "LINR ADC"},
+
+	{"AD1 Channel Volume", NULL, "AD1 Source Select"},
+	{"AD2 Channel Volume", NULL, "AD2 Source Select"},
+
+	{"AD12 Enable", NULL, "AD1 Channel Volume"},
+	{"AD12 Enable", NULL, "AD2 Channel Volume"},
+
+	{"AD_OUT1", NULL, "ab8500_0c"},
+	{"AD_OUT1", NULL, "AD12 Enable"},
+	{"AD_OUT2", NULL, "ab8500_0c"},
+	{"AD_OUT2", NULL, "AD12 Enable"},
+
+	/* Mic 1 */
+
+	{"MIC1 Mute", NULL, "Mic 1"},
+
+	{"MIC1A V-AMICx Enable", NULL, "MIC1 Mute"},
+	{"MIC1B V-AMICx Enable", NULL, "MIC1 Mute"},
+
+	{"Mic 1a or 1b Select", "Mic 1a", "MIC1A V-AMICx Enable"},
+	{"Mic 1a or 1b Select", "Mic 1b", "MIC1B V-AMICx Enable"},
+
+	{"MIC1 ADC", NULL, "Mic 1a or 1b Select"},
+
+	{"AD3 Source Select", "Mic 1", "MIC1 ADC"},
+
+	{"AD3 Channel Volume", NULL, "AD3 Source Select"},
+
+	{"AD3 Enable", NULL, "AD3 Channel Volume"},
+
+	{"AD_OUT3", NULL, "ab8500_0c"},
+	{"AD_OUT3", NULL, "AD3 Enable"},
+
+	/* HD Capture path */
+
+	{"AD5 Source Select", "Mic 2", "LINR ADC"},
+	{"AD6 Source Select", "Mic 1", "MIC1 ADC"},
+
+	{"AD5 Channel Volume", NULL, "AD5 Source Select"},
+	{"AD6 Channel Volume", NULL, "AD6 Source Select"},
+
+	{"AD57 Enable", NULL, "AD5 Channel Volume"},
+	{"AD68 Enable", NULL, "AD6 Channel Volume"},
+
+	{"AD_OUT57", NULL, "ab8500_0c"},
+	{"AD_OUT57", NULL, "AD57 Enable"},
+	{"AD_OUT68", NULL, "ab8500_0c"},
+	{"AD_OUT68", NULL, "AD68 Enable"},
+
+	/* Digital Microphone path */
+
+	{"DMic 1", NULL, "V-DMIC"},
+	{"DMic 2", NULL, "V-DMIC"},
+	{"DMic 3", NULL, "V-DMIC"},
+	{"DMic 4", NULL, "V-DMIC"},
+	{"DMic 5", NULL, "V-DMIC"},
+	{"DMic 6", NULL, "V-DMIC"},
+
+	{"AD1 Source Select", NULL, "DMic 1"},
+	{"AD2 Source Select", NULL, "DMic 2"},
+	{"AD3 Source Select", NULL, "DMic 3"},
+	{"AD5 Source Select", NULL, "DMic 5"},
+	{"AD6 Source Select", NULL, "DMic 6"},
+
+	{"AD4 Channel Volume", NULL, "DMic 4"},
+	{"AD4 Enable", NULL, "AD4 Channel Volume"},
+
+	{"AD_OUT4", NULL, "ab8500_0c"},
+	{"AD_OUT4", NULL, "AD4 Enable"},
+
+	/* LineIn Bypass path */
+
+	{"LINL to HSL Volume", NULL, "LINL Enable"},
+	{"LINR to HSR Volume", NULL, "LINR Enable"},
+
+	{"HSL DAC Driver", NULL, "LINL to HSL Volume"},
+	{"HSR DAC Driver", NULL, "LINR to HSR Volume"},
+
+	/* ANC path (Acoustic Noise Cancellation) */
+
+	{"ANC Source", "Mic 2 / DMic 5", "AD5 Channel Volume"},
+	{"ANC Source", "Mic 1 / DMic 6", "AD6 Channel Volume"},
+
+	{"ANC", "Switch", "ANC Source"},
+
+	{"Speaker Left Source", "ANC", "ANC"},
+	{"Speaker Right Source", "ANC", "ANC"},
+	{"ANC to Earpiece", "Switch", "ANC"},
+
+	{"HSL Digital Volume", NULL, "ANC to Earpiece"},
+
+	/* Sidetone Filter path */
+
+	{"Sidetone Left Source", "LineIn Left", "AD12 Enable"},
+	{"Sidetone Left Source", "LineIn Right", "AD12 Enable"},
+	{"Sidetone Left Source", "Mic 1", "AD3 Enable"},
+	{"Sidetone Left Source", "Headset Left", "DA_IN1"},
+	{"Sidetone Right Source", "LineIn Right", "AD12 Enable"},
+	{"Sidetone Right Source", "Mic 1", "AD3 Enable"},
+	{"Sidetone Right Source", "DMic 4", "AD4 Enable"},
+	{"Sidetone Right Source", "Headset Right", "DA_IN2"},
+
+	{"STFIR1 Control", NULL, "Sidetone Left Source"},
+	{"STFIR2 Control", NULL, "Sidetone Right Source"},
+
+	{"STFIR1 Volume", NULL, "STFIR1 Control"},
+	{"STFIR2 Volume", NULL, "STFIR2 Control"},
+
+	{"DA1 Enable", NULL, "STFIR1 Volume"},
+	{"DA2 Enable", NULL, "STFIR2 Volume"},
+};
+
+static const struct snd_soc_dapm_route ab8500_dapm_routes_mic1a_vamicx[] = {
+	{"MIC1A V-AMICx Enable", NULL, "V-AMIC1"},
+	{"MIC1A V-AMICx Enable", NULL, "V-AMIC2"},
+};
+
+static const struct snd_soc_dapm_route ab8500_dapm_routes_mic1b_vamicx[] = {
+	{"MIC1B V-AMICx Enable", NULL, "V-AMIC1"},
+	{"MIC1B V-AMICx Enable", NULL, "V-AMIC2"},
+};
+
+static const struct snd_soc_dapm_route ab8500_dapm_routes_mic2_vamicx[] = {
+	{"MIC2 V-AMICx Enable", NULL, "V-AMIC1"},
+	{"MIC2 V-AMICx Enable", NULL, "V-AMIC2"},
+};
+
+/* ANC FIR-coefficients configuration sequence */
+static void anc_fir(struct snd_soc_component *component,
+		unsigned int bnk, unsigned int par, unsigned int val)
+{
+	if (par == 0 && bnk == 0)
+		snd_soc_component_update_bits(component, AB8500_ANCCONF1,
+			BIT(AB8500_ANCCONF1_ANCFIRUPDATE),
+			BIT(AB8500_ANCCONF1_ANCFIRUPDATE));
+
+	snd_soc_component_write(component, AB8500_ANCCONF5, val >> 8 & 0xff);
+	snd_soc_component_write(component, AB8500_ANCCONF6, val &  0xff);
+
+	if (par == AB8500_ANC_FIR_COEFFS - 1 && bnk == 1)
+		snd_soc_component_update_bits(component, AB8500_ANCCONF1,
+			BIT(AB8500_ANCCONF1_ANCFIRUPDATE), 0);
+}
+
+/* ANC IIR-coefficients configuration sequence */
+static void anc_iir(struct snd_soc_component *component, unsigned int bnk,
+		unsigned int par, unsigned int val)
+{
+	if (par == 0) {
+		if (bnk == 0) {
+			snd_soc_component_update_bits(component, AB8500_ANCCONF1,
+					BIT(AB8500_ANCCONF1_ANCIIRINIT),
+					BIT(AB8500_ANCCONF1_ANCIIRINIT));
+			usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY);
+			snd_soc_component_update_bits(component, AB8500_ANCCONF1,
+					BIT(AB8500_ANCCONF1_ANCIIRINIT), 0);
+			usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY);
+		} else {
+			snd_soc_component_update_bits(component, AB8500_ANCCONF1,
+					BIT(AB8500_ANCCONF1_ANCIIRUPDATE),
+					BIT(AB8500_ANCCONF1_ANCIIRUPDATE));
+		}
+	} else if (par > 3) {
+		snd_soc_component_write(component, AB8500_ANCCONF7, 0);
+		snd_soc_component_write(component, AB8500_ANCCONF8, val >> 16 & 0xff);
+	}
+
+	snd_soc_component_write(component, AB8500_ANCCONF7, val >> 8 & 0xff);
+	snd_soc_component_write(component, AB8500_ANCCONF8, val & 0xff);
+
+	if (par == AB8500_ANC_IIR_COEFFS - 1 && bnk == 1)
+		snd_soc_component_update_bits(component, AB8500_ANCCONF1,
+			BIT(AB8500_ANCCONF1_ANCIIRUPDATE), 0);
+}
+
+/* ANC IIR-/FIR-coefficients configuration sequence */
+static void anc_configure(struct snd_soc_component *component,
+			bool apply_fir, bool apply_iir)
+{
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
+	unsigned int bnk, par, val;
+
+	dev_dbg(component->dev, "%s: Enter.\n", __func__);
+
+	if (apply_fir)
+		snd_soc_component_update_bits(component, AB8500_ANCCONF1,
+			BIT(AB8500_ANCCONF1_ENANC), 0);
+
+	snd_soc_component_update_bits(component, AB8500_ANCCONF1,
+		BIT(AB8500_ANCCONF1_ENANC), BIT(AB8500_ANCCONF1_ENANC));
+
+	if (apply_fir)
+		for (bnk = 0; bnk < AB8500_NR_OF_ANC_COEFF_BANKS; bnk++)
+			for (par = 0; par < AB8500_ANC_FIR_COEFFS; par++) {
+				val = snd_soc_component_read32(component,
+						drvdata->anc_fir_values[par]);
+				anc_fir(component, bnk, par, val);
+			}
+
+	if (apply_iir)
+		for (bnk = 0; bnk < AB8500_NR_OF_ANC_COEFF_BANKS; bnk++)
+			for (par = 0; par < AB8500_ANC_IIR_COEFFS; par++) {
+				val = snd_soc_component_read32(component,
+						drvdata->anc_iir_values[par]);
+				anc_iir(component, bnk, par, val);
+			}
+
+	dev_dbg(component->dev, "%s: Exit.\n", __func__);
+}
+
+/*
+ * Control-events
+ */
+
+static int sid_status_control_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
+
+	mutex_lock(&drvdata->ctrl_lock);
+	ucontrol->value.enumerated.item[0] = drvdata->sid_status;
+	mutex_unlock(&drvdata->ctrl_lock);
+
+	return 0;
+}
+
+/* Write sidetone FIR-coefficients configuration sequence */
+static int sid_status_control_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
+	unsigned int param, sidconf, val;
+	int status = 1;
+
+	dev_dbg(component->dev, "%s: Enter\n", __func__);
+
+	if (ucontrol->value.enumerated.item[0] != SID_APPLY_FIR) {
+		dev_err(component->dev,
+			"%s: ERROR: This control supports '%s' only!\n",
+			__func__, enum_sid_state[SID_APPLY_FIR]);
+		return -EIO;
+	}
+
+	mutex_lock(&drvdata->ctrl_lock);
+
+	sidconf = snd_soc_component_read32(component, AB8500_SIDFIRCONF);
+	if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) {
+		if ((sidconf & BIT(AB8500_SIDFIRCONF_ENFIRSIDS)) == 0) {
+			dev_err(component->dev, "%s: Sidetone busy while off!\n",
+				__func__);
+			status = -EPERM;
+		} else {
+			status = -EBUSY;
+		}
+		goto out;
+	}
+
+	snd_soc_component_write(component, AB8500_SIDFIRADR, 0);
+
+	for (param = 0; param < AB8500_SID_FIR_COEFFS; param++) {
+		val = snd_soc_component_read32(component, drvdata->sid_fir_values[param]);
+		snd_soc_component_write(component, AB8500_SIDFIRCOEF1, val >> 8 & 0xff);
+		snd_soc_component_write(component, AB8500_SIDFIRCOEF2, val & 0xff);
+	}
+
+	snd_soc_component_update_bits(component, AB8500_SIDFIRADR,
+		BIT(AB8500_SIDFIRADR_FIRSIDSET),
+		BIT(AB8500_SIDFIRADR_FIRSIDSET));
+	snd_soc_component_update_bits(component, AB8500_SIDFIRADR,
+		BIT(AB8500_SIDFIRADR_FIRSIDSET), 0);
+
+	drvdata->sid_status = SID_FIR_CONFIGURED;
+
+out:
+	mutex_unlock(&drvdata->ctrl_lock);
+
+	dev_dbg(component->dev, "%s: Exit\n", __func__);
+
+	return status;
+}
+
+static int anc_status_control_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
+
+	mutex_lock(&drvdata->ctrl_lock);
+	ucontrol->value.enumerated.item[0] = drvdata->anc_status;
+	mutex_unlock(&drvdata->ctrl_lock);
+
+	return 0;
+}
+
+static int anc_status_control_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
+	struct device *dev = component->dev;
+	bool apply_fir, apply_iir;
+	unsigned int req;
+	int status;
+
+	dev_dbg(dev, "%s: Enter.\n", __func__);
+
+	mutex_lock(&drvdata->ctrl_lock);
+
+	req = ucontrol->value.enumerated.item[0];
+	if (req >= ARRAY_SIZE(enum_anc_state)) {
+		status = -EINVAL;
+		goto cleanup;
+	}
+	if (req != ANC_APPLY_FIR_IIR && req != ANC_APPLY_FIR &&
+		req != ANC_APPLY_IIR) {
+		dev_err(dev, "%s: ERROR: Unsupported status to set '%s'!\n",
+			__func__, enum_anc_state[req]);
+		status = -EINVAL;
+		goto cleanup;
+	}
+	apply_fir = req == ANC_APPLY_FIR || req == ANC_APPLY_FIR_IIR;
+	apply_iir = req == ANC_APPLY_IIR || req == ANC_APPLY_FIR_IIR;
+
+	status = snd_soc_dapm_force_enable_pin(dapm, "ANC Configure Input");
+	if (status < 0) {
+		dev_err(dev,
+			"%s: ERROR: Failed to enable power (status = %d)!\n",
+			__func__, status);
+		goto cleanup;
+	}
+	snd_soc_dapm_sync(dapm);
+
+	anc_configure(component, apply_fir, apply_iir);
+
+	if (apply_fir) {
+		if (drvdata->anc_status == ANC_IIR_CONFIGURED)
+			drvdata->anc_status = ANC_FIR_IIR_CONFIGURED;
+		else if (drvdata->anc_status != ANC_FIR_IIR_CONFIGURED)
+			drvdata->anc_status =  ANC_FIR_CONFIGURED;
+	}
+	if (apply_iir) {
+		if (drvdata->anc_status == ANC_FIR_CONFIGURED)
+			drvdata->anc_status = ANC_FIR_IIR_CONFIGURED;
+		else if (drvdata->anc_status != ANC_FIR_IIR_CONFIGURED)
+			drvdata->anc_status =  ANC_IIR_CONFIGURED;
+	}
+
+	status = snd_soc_dapm_disable_pin(dapm, "ANC Configure Input");
+	snd_soc_dapm_sync(dapm);
+
+cleanup:
+	mutex_unlock(&drvdata->ctrl_lock);
+
+	if (status < 0)
+		dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n",
+			__func__, status);
+
+	dev_dbg(dev, "%s: Exit.\n", __func__);
+
+	return (status < 0) ? status : 1;
+}
+
+static int filter_control_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	struct filter_control *fc =
+			(struct filter_control *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = fc->count;
+	uinfo->value.integer.min = fc->min;
+	uinfo->value.integer.max = fc->max;
+
+	return 0;
+}
+
+static int filter_control_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = snd_soc_component_get_drvdata(component);
+	struct filter_control *fc =
+			(struct filter_control *)kcontrol->private_value;
+	unsigned int i;
+
+	mutex_lock(&drvdata->ctrl_lock);
+	for (i = 0; i < fc->count; i++)
+		ucontrol->value.integer.value[i] = fc->value[i];
+	mutex_unlock(&drvdata->ctrl_lock);
+
+	return 0;
+}
+
+static int filter_control_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ab8500_codec_drvdata *drvdata = snd_soc_component_get_drvdata(component);
+	struct filter_control *fc =
+			(struct filter_control *)kcontrol->private_value;
+	unsigned int i;
+
+	mutex_lock(&drvdata->ctrl_lock);
+	for (i = 0; i < fc->count; i++)
+		fc->value[i] = ucontrol->value.integer.value[i];
+	mutex_unlock(&drvdata->ctrl_lock);
+
+	return 0;
+}
+
+/*
+ * Controls - Non-DAPM ASoC
+ */
+
+static DECLARE_TLV_DB_SCALE(adx_dig_gain_tlv, -3200, 100, 1);
+/* -32dB = Mute */
+
+static DECLARE_TLV_DB_SCALE(dax_dig_gain_tlv, -6300, 100, 1);
+/* -63dB = Mute */
+
+static DECLARE_TLV_DB_SCALE(hs_ear_dig_gain_tlv, -100, 100, 1);
+/* -1dB = Mute */
+
+static const DECLARE_TLV_DB_RANGE(hs_gain_tlv,
+	0, 3, TLV_DB_SCALE_ITEM(-3200, 400, 0),
+	4, 15, TLV_DB_SCALE_ITEM(-1800, 200, 0)
+);
+
+static DECLARE_TLV_DB_SCALE(mic_gain_tlv, 0, 100, 0);
+
+static DECLARE_TLV_DB_SCALE(lin_gain_tlv, -1000, 200, 0);
+
+static DECLARE_TLV_DB_SCALE(lin2hs_gain_tlv, -3800, 200, 1);
+/* -38dB = Mute */
+
+static const char * const enum_hsfadspeed[] = {"2ms", "0.5ms", "10.6ms",
+					"5ms"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_hsfadspeed,
+	AB8500_DIGMICCONF, AB8500_DIGMICCONF_HSFADSPEED, enum_hsfadspeed);
+
+static const char * const enum_envdetthre[] = {
+	"250mV", "300mV", "350mV", "400mV",
+	"450mV", "500mV", "550mV", "600mV",
+	"650mV", "700mV", "750mV", "800mV",
+	"850mV", "900mV", "950mV", "1.00V" };
+static SOC_ENUM_SINGLE_DECL(soc_enum_envdeththre,
+	AB8500_ENVCPCONF, AB8500_ENVCPCONF_ENVDETHTHRE, enum_envdetthre);
+static SOC_ENUM_SINGLE_DECL(soc_enum_envdetlthre,
+	AB8500_ENVCPCONF, AB8500_ENVCPCONF_ENVDETLTHRE, enum_envdetthre);
+static const char * const enum_envdettime[] = {
+	"26.6us", "53.2us", "106us",  "213us",
+	"426us",  "851us",  "1.70ms", "3.40ms",
+	"6.81ms", "13.6ms", "27.2ms", "54.5ms",
+	"109ms",  "218ms",  "436ms",  "872ms" };
+static SOC_ENUM_SINGLE_DECL(soc_enum_envdettime,
+	AB8500_SIGENVCONF, AB8500_SIGENVCONF_ENVDETTIME, enum_envdettime);
+
+static const char * const enum_sinc31[] = {"Sinc 3", "Sinc 1"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_hsesinc, AB8500_HSLEARDIGGAIN,
+			AB8500_HSLEARDIGGAIN_HSSINC1, enum_sinc31);
+
+static const char * const enum_fadespeed[] = {"1ms", "4ms", "8ms", "16ms"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_fadespeed, AB8500_HSRDIGGAIN,
+			AB8500_HSRDIGGAIN_FADESPEED, enum_fadespeed);
+
+/* Earpiece */
+
+static const char * const enum_lowpow[] = {"Normal", "Low Power"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_eardaclowpow, AB8500_ANACONF1,
+			AB8500_ANACONF1_EARDACLOWPOW, enum_lowpow);
+static SOC_ENUM_SINGLE_DECL(soc_enum_eardrvlowpow, AB8500_ANACONF1,
+			AB8500_ANACONF1_EARDRVLOWPOW, enum_lowpow);
+
+static const char * const enum_av_mode[] = {"Audio", "Voice"};
+static SOC_ENUM_DOUBLE_DECL(soc_enum_ad12voice, AB8500_ADFILTCONF,
+	AB8500_ADFILTCONF_AD1VOICE, AB8500_ADFILTCONF_AD2VOICE, enum_av_mode);
+static SOC_ENUM_DOUBLE_DECL(soc_enum_ad34voice, AB8500_ADFILTCONF,
+	AB8500_ADFILTCONF_AD3VOICE, AB8500_ADFILTCONF_AD4VOICE, enum_av_mode);
+
+/* DA */
+
+static SOC_ENUM_SINGLE_DECL(soc_enum_da12voice,
+			AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_DA12VOICE,
+			enum_av_mode);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da34voice,
+			AB8500_DASLOTCONF3, AB8500_DASLOTCONF3_DA34VOICE,
+			enum_av_mode);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da56voice,
+			AB8500_DASLOTCONF5, AB8500_DASLOTCONF5_DA56VOICE,
+			enum_av_mode);
+
+static const char * const enum_da2hslr[] = {"Sidetone", "Audio Path"};
+static SOC_ENUM_DOUBLE_DECL(soc_enum_da2hslr, AB8500_DIGMULTCONF1,
+			AB8500_DIGMULTCONF1_DATOHSLEN,
+			AB8500_DIGMULTCONF1_DATOHSREN, enum_da2hslr);
+
+static const char * const enum_sinc53[] = {"Sinc 5", "Sinc 3"};
+static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic12sinc, AB8500_DMICFILTCONF,
+			AB8500_DMICFILTCONF_DMIC1SINC3,
+			AB8500_DMICFILTCONF_DMIC2SINC3, enum_sinc53);
+static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic34sinc, AB8500_DMICFILTCONF,
+			AB8500_DMICFILTCONF_DMIC3SINC3,
+			AB8500_DMICFILTCONF_DMIC4SINC3, enum_sinc53);
+static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic56sinc, AB8500_DMICFILTCONF,
+			AB8500_DMICFILTCONF_DMIC5SINC3,
+			AB8500_DMICFILTCONF_DMIC6SINC3, enum_sinc53);
+
+/* Digital interface - DA from slot mapping */
+static const char * const enum_da_from_slot_map[] = {"SLOT0",
+					"SLOT1",
+					"SLOT2",
+					"SLOT3",
+					"SLOT4",
+					"SLOT5",
+					"SLOT6",
+					"SLOT7",
+					"SLOT8",
+					"SLOT9",
+					"SLOT10",
+					"SLOT11",
+					"SLOT12",
+					"SLOT13",
+					"SLOT14",
+					"SLOT15",
+					"SLOT16",
+					"SLOT17",
+					"SLOT18",
+					"SLOT19",
+					"SLOT20",
+					"SLOT21",
+					"SLOT22",
+					"SLOT23",
+					"SLOT24",
+					"SLOT25",
+					"SLOT26",
+					"SLOT27",
+					"SLOT28",
+					"SLOT29",
+					"SLOT30",
+					"SLOT31"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_da1slotmap,
+			AB8500_DASLOTCONF1, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da2slotmap,
+			AB8500_DASLOTCONF2, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da3slotmap,
+			AB8500_DASLOTCONF3, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da4slotmap,
+			AB8500_DASLOTCONF4, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da5slotmap,
+			AB8500_DASLOTCONF5, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da6slotmap,
+			AB8500_DASLOTCONF6, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da7slotmap,
+			AB8500_DASLOTCONF7, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_da8slotmap,
+			AB8500_DASLOTCONF8, AB8500_DASLOTCONFX_SLTODAX_SHIFT,
+			enum_da_from_slot_map);
+
+/* Digital interface - AD to slot mapping */
+static const char * const enum_ad_to_slot_map[] = {"AD_OUT1",
+					"AD_OUT2",
+					"AD_OUT3",
+					"AD_OUT4",
+					"AD_OUT5",
+					"AD_OUT6",
+					"AD_OUT7",
+					"AD_OUT8",
+					"zeroes",
+					"zeroes",
+					"zeroes",
+					"zeroes",
+					"tristate",
+					"tristate",
+					"tristate",
+					"tristate"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot0map,
+			AB8500_ADSLOTSEL1, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot1map,
+			AB8500_ADSLOTSEL1, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot2map,
+			AB8500_ADSLOTSEL2, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot3map,
+			AB8500_ADSLOTSEL2, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot4map,
+			AB8500_ADSLOTSEL3, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot5map,
+			AB8500_ADSLOTSEL3, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot6map,
+			AB8500_ADSLOTSEL4, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot7map,
+			AB8500_ADSLOTSEL4, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot8map,
+			AB8500_ADSLOTSEL5, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot9map,
+			AB8500_ADSLOTSEL5, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot10map,
+			AB8500_ADSLOTSEL6, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot11map,
+			AB8500_ADSLOTSEL6, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot12map,
+			AB8500_ADSLOTSEL7, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot13map,
+			AB8500_ADSLOTSEL7, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot14map,
+			AB8500_ADSLOTSEL8, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot15map,
+			AB8500_ADSLOTSEL8, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot16map,
+			AB8500_ADSLOTSEL9, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot17map,
+			AB8500_ADSLOTSEL9, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot18map,
+			AB8500_ADSLOTSEL10, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot19map,
+			AB8500_ADSLOTSEL10, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot20map,
+			AB8500_ADSLOTSEL11, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot21map,
+			AB8500_ADSLOTSEL11, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot22map,
+			AB8500_ADSLOTSEL12, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot23map,
+			AB8500_ADSLOTSEL12, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot24map,
+			AB8500_ADSLOTSEL13, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot25map,
+			AB8500_ADSLOTSEL13, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot26map,
+			AB8500_ADSLOTSEL14, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot27map,
+			AB8500_ADSLOTSEL14, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot28map,
+			AB8500_ADSLOTSEL15, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot29map,
+			AB8500_ADSLOTSEL15, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot30map,
+			AB8500_ADSLOTSEL16, AB8500_ADSLOTSELX_EVEN_SHIFT,
+			enum_ad_to_slot_map);
+static SOC_ENUM_SINGLE_DECL(soc_enum_adslot31map,
+			AB8500_ADSLOTSEL16, AB8500_ADSLOTSELX_ODD_SHIFT,
+			enum_ad_to_slot_map);
+
+/* Digital interface - Burst mode */
+static const char * const enum_mask[] = {"Unmasked", "Masked"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomask,
+			AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFOMASK,
+			enum_mask);
+static const char * const enum_bitclk0[] = {"19_2_MHz", "38_4_MHz"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_bfifo19m2,
+			AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFO19M2,
+			enum_bitclk0);
+static const char * const enum_slavemaster[] = {"Slave", "Master"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomast,
+			AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFOMAST_SHIFT,
+			enum_slavemaster);
+
+/* Sidetone */
+static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_sidstate, enum_sid_state);
+
+/* ANC */
+static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_ancstate, enum_anc_state);
+
+static struct snd_kcontrol_new ab8500_ctrls[] = {
+	/* Charge pump */
+	SOC_ENUM("Charge Pump High Threshold For Low Voltage",
+		soc_enum_envdeththre),
+	SOC_ENUM("Charge Pump Low Threshold For Low Voltage",
+		soc_enum_envdetlthre),
+	SOC_SINGLE("Charge Pump Envelope Detection Switch",
+		AB8500_SIGENVCONF, AB8500_SIGENVCONF_ENVDETCPEN,
+		1, 0),
+	SOC_ENUM("Charge Pump Envelope Detection Decay Time",
+		soc_enum_envdettime),
+
+	/* Headset */
+	SOC_ENUM("Headset Mode", soc_enum_da12voice),
+	SOC_SINGLE("Headset High Pass Switch",
+		AB8500_ANACONF1, AB8500_ANACONF1_HSHPEN,
+		1, 0),
+	SOC_SINGLE("Headset Low Power Switch",
+		AB8500_ANACONF1, AB8500_ANACONF1_HSLOWPOW,
+		1, 0),
+	SOC_SINGLE("Headset DAC Low Power Switch",
+		AB8500_ANACONF1, AB8500_ANACONF1_DACLOWPOW1,
+		1, 0),
+	SOC_SINGLE("Headset DAC Drv Low Power Switch",
+		AB8500_ANACONF1, AB8500_ANACONF1_DACLOWPOW0,
+		1, 0),
+	SOC_ENUM("Headset Fade Speed", soc_enum_hsfadspeed),
+	SOC_ENUM("Headset Source", soc_enum_da2hslr),
+	SOC_ENUM("Headset Filter", soc_enum_hsesinc),
+	SOC_DOUBLE_R_TLV("Headset Master Volume",
+		AB8500_DADIGGAIN1, AB8500_DADIGGAIN2,
+		0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv),
+	SOC_DOUBLE_R_TLV("Headset Digital Volume",
+		AB8500_HSLEARDIGGAIN, AB8500_HSRDIGGAIN,
+		0, AB8500_HSLEARDIGGAIN_HSLDGAIN_MAX, 1, hs_ear_dig_gain_tlv),
+	SOC_DOUBLE_TLV("Headset Volume",
+		AB8500_ANAGAIN3,
+		AB8500_ANAGAIN3_HSLGAIN, AB8500_ANAGAIN3_HSRGAIN,
+		AB8500_ANAGAIN3_HSXGAIN_MAX, 1, hs_gain_tlv),
+
+	/* Earpiece */
+	SOC_ENUM("Earpiece DAC Mode",
+		soc_enum_eardaclowpow),
+	SOC_ENUM("Earpiece DAC Drv Mode",
+		soc_enum_eardrvlowpow),
+
+	/* HandsFree */
+	SOC_ENUM("HF Mode", soc_enum_da34voice),
+	SOC_SINGLE("HF and Headset Swap Switch",
+		AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_SWAPDA12_34,
+		1, 0),
+	SOC_DOUBLE("HF Low EMI Mode Switch",
+		AB8500_CLASSDCONF1,
+		AB8500_CLASSDCONF1_HFLSWAPEN, AB8500_CLASSDCONF1_HFRSWAPEN,
+		1, 0),
+	SOC_DOUBLE("HF FIR Bypass Switch",
+		AB8500_CLASSDCONF2,
+		AB8500_CLASSDCONF2_FIRBYP0, AB8500_CLASSDCONF2_FIRBYP1,
+		1, 0),
+	SOC_DOUBLE("HF High Volume Switch",
+		AB8500_CLASSDCONF2,
+		AB8500_CLASSDCONF2_HIGHVOLEN0, AB8500_CLASSDCONF2_HIGHVOLEN1,
+		1, 0),
+	SOC_SINGLE("HF L and R Bridge Switch",
+		AB8500_CLASSDCONF1, AB8500_CLASSDCONF1_PARLHF,
+		1, 0),
+	SOC_DOUBLE_R_TLV("HF Master Volume",
+		AB8500_DADIGGAIN3, AB8500_DADIGGAIN4,
+		0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv),
+
+	/* Vibra */
+	SOC_DOUBLE("Vibra High Volume Switch",
+		AB8500_CLASSDCONF2,
+		AB8500_CLASSDCONF2_HIGHVOLEN2, AB8500_CLASSDCONF2_HIGHVOLEN3,
+		1, 0),
+	SOC_DOUBLE("Vibra Low EMI Mode Switch",
+		AB8500_CLASSDCONF1,
+		AB8500_CLASSDCONF1_VIB1SWAPEN, AB8500_CLASSDCONF1_VIB2SWAPEN,
+		1, 0),
+	SOC_DOUBLE("Vibra FIR Bypass Switch",
+		AB8500_CLASSDCONF2,
+		AB8500_CLASSDCONF2_FIRBYP2, AB8500_CLASSDCONF2_FIRBYP3,
+		1, 0),
+	SOC_ENUM("Vibra Mode", soc_enum_da56voice),
+	SOC_DOUBLE_R("Vibra PWM Duty Cycle N",
+		AB8500_PWMGENCONF3, AB8500_PWMGENCONF5,
+		AB8500_PWMGENCONFX_PWMVIBXDUTCYC,
+		AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX, 0),
+	SOC_DOUBLE_R("Vibra PWM Duty Cycle P",
+		AB8500_PWMGENCONF2, AB8500_PWMGENCONF4,
+		AB8500_PWMGENCONFX_PWMVIBXDUTCYC,
+		AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX, 0),
+	SOC_SINGLE("Vibra 1 and 2 Bridge Switch",
+		AB8500_CLASSDCONF1, AB8500_CLASSDCONF1_PARLVIB,
+		1, 0),
+	SOC_DOUBLE_R_TLV("Vibra Master Volume",
+		AB8500_DADIGGAIN5, AB8500_DADIGGAIN6,
+		0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv),
+
+	/* HandsFree, Vibra */
+	SOC_SINGLE("ClassD High Pass Volume",
+		AB8500_CLASSDCONF3, AB8500_CLASSDCONF3_DITHHPGAIN,
+		AB8500_CLASSDCONF3_DITHHPGAIN_MAX, 0),
+	SOC_SINGLE("ClassD White Volume",
+		AB8500_CLASSDCONF3, AB8500_CLASSDCONF3_DITHWGAIN,
+		AB8500_CLASSDCONF3_DITHWGAIN_MAX, 0),
+
+	/* Mic 1, Mic 2, LineIn */
+	SOC_DOUBLE_R_TLV("Mic Master Volume",
+		AB8500_ADDIGGAIN3, AB8500_ADDIGGAIN4,
+		0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv),
+
+	/* Mic 1 */
+	SOC_SINGLE_TLV("Mic 1",
+		AB8500_ANAGAIN1,
+		AB8500_ANAGAINX_MICXGAIN,
+		AB8500_ANAGAINX_MICXGAIN_MAX, 0, mic_gain_tlv),
+	SOC_SINGLE("Mic 1 Low Power Switch",
+		AB8500_ANAGAIN1, AB8500_ANAGAINX_LOWPOWMICX,
+		1, 0),
+
+	/* Mic 2 */
+	SOC_DOUBLE("Mic High Pass Switch",
+		AB8500_ADFILTCONF,
+		AB8500_ADFILTCONF_AD3NH, AB8500_ADFILTCONF_AD4NH,
+		1, 1),
+	SOC_ENUM("Mic Mode", soc_enum_ad34voice),
+	SOC_ENUM("Mic Filter", soc_enum_dmic34sinc),
+	SOC_SINGLE_TLV("Mic 2",
+		AB8500_ANAGAIN2,
+		AB8500_ANAGAINX_MICXGAIN,
+		AB8500_ANAGAINX_MICXGAIN_MAX, 0, mic_gain_tlv),
+	SOC_SINGLE("Mic 2 Low Power Switch",
+		AB8500_ANAGAIN2, AB8500_ANAGAINX_LOWPOWMICX,
+		1, 0),
+
+	/* LineIn */
+	SOC_DOUBLE("LineIn High Pass Switch",
+		AB8500_ADFILTCONF,
+		AB8500_ADFILTCONF_AD1NH, AB8500_ADFILTCONF_AD2NH,
+		1, 1),
+	SOC_ENUM("LineIn Filter", soc_enum_dmic12sinc),
+	SOC_ENUM("LineIn Mode", soc_enum_ad12voice),
+	SOC_DOUBLE_R_TLV("LineIn Master Volume",
+		AB8500_ADDIGGAIN1, AB8500_ADDIGGAIN2,
+		0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv),
+	SOC_DOUBLE_TLV("LineIn",
+		AB8500_ANAGAIN4,
+		AB8500_ANAGAIN4_LINLGAIN, AB8500_ANAGAIN4_LINRGAIN,
+		AB8500_ANAGAIN4_LINXGAIN_MAX, 0, lin_gain_tlv),
+	SOC_DOUBLE_R_TLV("LineIn to Headset Volume",
+		AB8500_DIGLINHSLGAIN, AB8500_DIGLINHSRGAIN,
+		AB8500_DIGLINHSXGAIN_LINTOHSXGAIN,
+		AB8500_DIGLINHSXGAIN_LINTOHSXGAIN_MAX,
+		1, lin2hs_gain_tlv),
+
+	/* DMic */
+	SOC_ENUM("DMic Filter", soc_enum_dmic56sinc),
+	SOC_DOUBLE_R_TLV("DMic Master Volume",
+		AB8500_ADDIGGAIN5, AB8500_ADDIGGAIN6,
+		0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv),
+
+	/* Digital gains */
+	SOC_ENUM("Digital Gain Fade Speed", soc_enum_fadespeed),
+
+	/* Analog loopback */
+	SOC_DOUBLE_R_TLV("Analog Loopback Volume",
+		AB8500_ADDIGLOOPGAIN1, AB8500_ADDIGLOOPGAIN2,
+		0, AB8500_ADDIGLOOPGAINX_ADXLBGAIN_MAX, 1, dax_dig_gain_tlv),
+
+	/* Digital interface - DA from slot mapping */
+	SOC_ENUM("Digital Interface DA 1 From Slot Map", soc_enum_da1slotmap),
+	SOC_ENUM("Digital Interface DA 2 From Slot Map", soc_enum_da2slotmap),
+	SOC_ENUM("Digital Interface DA 3 From Slot Map", soc_enum_da3slotmap),
+	SOC_ENUM("Digital Interface DA 4 From Slot Map", soc_enum_da4slotmap),
+	SOC_ENUM("Digital Interface DA 5 From Slot Map", soc_enum_da5slotmap),
+	SOC_ENUM("Digital Interface DA 6 From Slot Map", soc_enum_da6slotmap),
+	SOC_ENUM("Digital Interface DA 7 From Slot Map", soc_enum_da7slotmap),
+	SOC_ENUM("Digital Interface DA 8 From Slot Map", soc_enum_da8slotmap),
+
+	/* Digital interface - AD to slot mapping */
+	SOC_ENUM("Digital Interface AD To Slot 0 Map", soc_enum_adslot0map),
+	SOC_ENUM("Digital Interface AD To Slot 1 Map", soc_enum_adslot1map),
+	SOC_ENUM("Digital Interface AD To Slot 2 Map", soc_enum_adslot2map),
+	SOC_ENUM("Digital Interface AD To Slot 3 Map", soc_enum_adslot3map),
+	SOC_ENUM("Digital Interface AD To Slot 4 Map", soc_enum_adslot4map),
+	SOC_ENUM("Digital Interface AD To Slot 5 Map", soc_enum_adslot5map),
+	SOC_ENUM("Digital Interface AD To Slot 6 Map", soc_enum_adslot6map),
+	SOC_ENUM("Digital Interface AD To Slot 7 Map", soc_enum_adslot7map),
+	SOC_ENUM("Digital Interface AD To Slot 8 Map", soc_enum_adslot8map),
+	SOC_ENUM("Digital Interface AD To Slot 9 Map", soc_enum_adslot9map),
+	SOC_ENUM("Digital Interface AD To Slot 10 Map", soc_enum_adslot10map),
+	SOC_ENUM("Digital Interface AD To Slot 11 Map", soc_enum_adslot11map),
+	SOC_ENUM("Digital Interface AD To Slot 12 Map", soc_enum_adslot12map),
+	SOC_ENUM("Digital Interface AD To Slot 13 Map", soc_enum_adslot13map),
+	SOC_ENUM("Digital Interface AD To Slot 14 Map", soc_enum_adslot14map),
+	SOC_ENUM("Digital Interface AD To Slot 15 Map", soc_enum_adslot15map),
+	SOC_ENUM("Digital Interface AD To Slot 16 Map", soc_enum_adslot16map),
+	SOC_ENUM("Digital Interface AD To Slot 17 Map", soc_enum_adslot17map),
+	SOC_ENUM("Digital Interface AD To Slot 18 Map", soc_enum_adslot18map),
+	SOC_ENUM("Digital Interface AD To Slot 19 Map", soc_enum_adslot19map),
+	SOC_ENUM("Digital Interface AD To Slot 20 Map", soc_enum_adslot20map),
+	SOC_ENUM("Digital Interface AD To Slot 21 Map", soc_enum_adslot21map),
+	SOC_ENUM("Digital Interface AD To Slot 22 Map", soc_enum_adslot22map),
+	SOC_ENUM("Digital Interface AD To Slot 23 Map", soc_enum_adslot23map),
+	SOC_ENUM("Digital Interface AD To Slot 24 Map", soc_enum_adslot24map),
+	SOC_ENUM("Digital Interface AD To Slot 25 Map", soc_enum_adslot25map),
+	SOC_ENUM("Digital Interface AD To Slot 26 Map", soc_enum_adslot26map),
+	SOC_ENUM("Digital Interface AD To Slot 27 Map", soc_enum_adslot27map),
+	SOC_ENUM("Digital Interface AD To Slot 28 Map", soc_enum_adslot28map),
+	SOC_ENUM("Digital Interface AD To Slot 29 Map", soc_enum_adslot29map),
+	SOC_ENUM("Digital Interface AD To Slot 30 Map", soc_enum_adslot30map),
+	SOC_ENUM("Digital Interface AD To Slot 31 Map", soc_enum_adslot31map),
+
+	/* Digital interface - Loopback */
+	SOC_SINGLE("Digital Interface AD 1 Loopback Switch",
+		AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_DAI7TOADO1,
+		1, 0),
+	SOC_SINGLE("Digital Interface AD 2 Loopback Switch",
+		AB8500_DASLOTCONF2, AB8500_DASLOTCONF2_DAI8TOADO2,
+		1, 0),
+	SOC_SINGLE("Digital Interface AD 3 Loopback Switch",
+		AB8500_DASLOTCONF3, AB8500_DASLOTCONF3_DAI7TOADO3,
+		1, 0),
+	SOC_SINGLE("Digital Interface AD 4 Loopback Switch",
+		AB8500_DASLOTCONF4, AB8500_DASLOTCONF4_DAI8TOADO4,
+		1, 0),
+	SOC_SINGLE("Digital Interface AD 5 Loopback Switch",
+		AB8500_DASLOTCONF5, AB8500_DASLOTCONF5_DAI7TOADO5,
+		1, 0),
+	SOC_SINGLE("Digital Interface AD 6 Loopback Switch",
+		AB8500_DASLOTCONF6, AB8500_DASLOTCONF6_DAI8TOADO6,
+		1, 0),
+	SOC_SINGLE("Digital Interface AD 7 Loopback Switch",
+		AB8500_DASLOTCONF7, AB8500_DASLOTCONF7_DAI8TOADO7,
+		1, 0),
+	SOC_SINGLE("Digital Interface AD 8 Loopback Switch",
+		AB8500_DASLOTCONF8, AB8500_DASLOTCONF8_DAI7TOADO8,
+		1, 0),
+
+	/* Digital interface - Burst FIFO */
+	SOC_SINGLE("Digital Interface 0 FIFO Enable Switch",
+		AB8500_DIGIFCONF3, AB8500_DIGIFCONF3_IF0BFIFOEN,
+		1, 0),
+	SOC_ENUM("Burst FIFO Mask", soc_enum_bfifomask),
+	SOC_ENUM("Burst FIFO Bit-clock Frequency", soc_enum_bfifo19m2),
+	SOC_SINGLE("Burst FIFO Threshold",
+		AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFOINT_SHIFT,
+		AB8500_FIFOCONF1_BFIFOINT_MAX, 0),
+	SOC_SINGLE("Burst FIFO Length",
+		AB8500_FIFOCONF2, AB8500_FIFOCONF2_BFIFOTX_SHIFT,
+		AB8500_FIFOCONF2_BFIFOTX_MAX, 0),
+	SOC_SINGLE("Burst FIFO EOS Extra Slots",
+		AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFOEXSL_SHIFT,
+		AB8500_FIFOCONF3_BFIFOEXSL_MAX, 0),
+	SOC_SINGLE("Burst FIFO FS Extra Bit-clocks",
+		AB8500_FIFOCONF3, AB8500_FIFOCONF3_PREBITCLK0_SHIFT,
+		AB8500_FIFOCONF3_PREBITCLK0_MAX, 0),
+	SOC_ENUM("Burst FIFO Interface Mode", soc_enum_bfifomast),
+
+	SOC_SINGLE("Burst FIFO Interface Switch",
+		AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFORUN_SHIFT,
+		1, 0),
+	SOC_SINGLE("Burst FIFO Switch Frame Number",
+		AB8500_FIFOCONF4, AB8500_FIFOCONF4_BFIFOFRAMSW_SHIFT,
+		AB8500_FIFOCONF4_BFIFOFRAMSW_MAX, 0),
+	SOC_SINGLE("Burst FIFO Wake Up Delay",
+		AB8500_FIFOCONF5, AB8500_FIFOCONF5_BFIFOWAKEUP_SHIFT,
+		AB8500_FIFOCONF5_BFIFOWAKEUP_MAX, 0),
+	SOC_SINGLE("Burst FIFO Samples In FIFO",
+		AB8500_FIFOCONF6, AB8500_FIFOCONF6_BFIFOSAMPLE_SHIFT,
+		AB8500_FIFOCONF6_BFIFOSAMPLE_MAX, 0),
+
+	/* ANC */
+	SOC_ENUM_EXT("ANC Status", soc_enum_ancstate,
+		anc_status_control_get, anc_status_control_put),
+	SOC_SINGLE_XR_SX("ANC Warp Delay Shift",
+		AB8500_ANCCONF2, 1, AB8500_ANCCONF2_SHIFT,
+		AB8500_ANCCONF2_MIN, AB8500_ANCCONF2_MAX, 0),
+	SOC_SINGLE_XR_SX("ANC FIR Output Shift",
+		AB8500_ANCCONF3, 1, AB8500_ANCCONF3_SHIFT,
+		AB8500_ANCCONF3_MIN, AB8500_ANCCONF3_MAX, 0),
+	SOC_SINGLE_XR_SX("ANC IIR Output Shift",
+		AB8500_ANCCONF4, 1, AB8500_ANCCONF4_SHIFT,
+		AB8500_ANCCONF4_MIN, AB8500_ANCCONF4_MAX, 0),
+	SOC_SINGLE_XR_SX("ANC Warp Delay",
+		AB8500_ANCCONF9, 2, AB8500_ANC_WARP_DELAY_SHIFT,
+		AB8500_ANC_WARP_DELAY_MIN, AB8500_ANC_WARP_DELAY_MAX, 0),
+
+	/* Sidetone */
+	SOC_ENUM_EXT("Sidetone Status", soc_enum_sidstate,
+		sid_status_control_get, sid_status_control_put),
+	SOC_SINGLE_STROBE("Sidetone Reset",
+		AB8500_SIDFIRADR, AB8500_SIDFIRADR_FIRSIDSET, 0),
+};
+
+static struct snd_kcontrol_new ab8500_filter_controls[] = {
+	AB8500_FILTER_CONTROL("ANC FIR Coefficients", AB8500_ANC_FIR_COEFFS,
+		AB8500_ANC_FIR_COEFF_MIN, AB8500_ANC_FIR_COEFF_MAX),
+	AB8500_FILTER_CONTROL("ANC IIR Coefficients", AB8500_ANC_IIR_COEFFS,
+		AB8500_ANC_IIR_COEFF_MIN, AB8500_ANC_IIR_COEFF_MAX),
+	AB8500_FILTER_CONTROL("Sidetone FIR Coefficients",
+			AB8500_SID_FIR_COEFFS, AB8500_SID_FIR_COEFF_MIN,
+			AB8500_SID_FIR_COEFF_MAX)
+};
+enum ab8500_filter {
+	AB8500_FILTER_ANC_FIR = 0,
+	AB8500_FILTER_ANC_IIR = 1,
+	AB8500_FILTER_SID_FIR = 2,
+};
+
+/*
+ * Extended interface for codec-driver
+ */
+
+static int ab8500_audio_init_audioblock(struct snd_soc_component *component)
+{
+	int status;
+
+	dev_dbg(component->dev, "%s: Enter.\n", __func__);
+
+	/* Reset audio-registers and disable 32kHz-clock output 2 */
+	status = ab8500_sysctrl_write(AB8500_STW4500CTRL3,
+				AB8500_STW4500CTRL3_CLK32KOUT2DIS |
+					AB8500_STW4500CTRL3_RESETAUDN,
+				AB8500_STW4500CTRL3_RESETAUDN);
+	if (status < 0)
+		return status;
+
+	return 0;
+}
+
+static int ab8500_audio_setup_mics(struct snd_soc_component *component,
+			struct amic_settings *amics)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	u8 value8;
+	unsigned int value;
+	int status;
+	const struct snd_soc_dapm_route *route;
+
+	dev_dbg(component->dev, "%s: Enter.\n", __func__);
+
+	/* Set DMic-clocks to outputs */
+	status = abx500_get_register_interruptible(component->dev, AB8500_MISC,
+						AB8500_GPIO_DIR4_REG,
+						&value8);
+	if (status < 0)
+		return status;
+	value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT |
+		GPIO31_DIR_OUTPUT;
+	status = abx500_set_register_interruptible(component->dev,
+						AB8500_MISC,
+						AB8500_GPIO_DIR4_REG,
+						value);
+	if (status < 0)
+		return status;
+
+	/* Attach regulators to AMic DAPM-paths */
+	dev_dbg(component->dev, "%s: Mic 1a regulator: %s\n", __func__,
+		amic_micbias_str(amics->mic1a_micbias));
+	route = &ab8500_dapm_routes_mic1a_vamicx[amics->mic1a_micbias];
+	status = snd_soc_dapm_add_routes(dapm, route, 1);
+	dev_dbg(component->dev, "%s: Mic 1b regulator: %s\n", __func__,
+		amic_micbias_str(amics->mic1b_micbias));
+	route = &ab8500_dapm_routes_mic1b_vamicx[amics->mic1b_micbias];
+	status |= snd_soc_dapm_add_routes(dapm, route, 1);
+	dev_dbg(component->dev, "%s: Mic 2 regulator: %s\n", __func__,
+		amic_micbias_str(amics->mic2_micbias));
+	route = &ab8500_dapm_routes_mic2_vamicx[amics->mic2_micbias];
+	status |= snd_soc_dapm_add_routes(dapm, route, 1);
+	if (status < 0) {
+		dev_err(component->dev,
+			"%s: Failed to add AMic-regulator DAPM-routes (%d).\n",
+			__func__, status);
+		return status;
+	}
+
+	/* Set AMic-configuration */
+	dev_dbg(component->dev, "%s: Mic 1 mic-type: %s\n", __func__,
+		amic_type_str(amics->mic1_type));
+	snd_soc_component_update_bits(component, AB8500_ANAGAIN1, AB8500_ANAGAINX_ENSEMICX,
+			amics->mic1_type == AMIC_TYPE_DIFFERENTIAL ?
+				0 : AB8500_ANAGAINX_ENSEMICX);
+	dev_dbg(component->dev, "%s: Mic 2 mic-type: %s\n", __func__,
+		amic_type_str(amics->mic2_type));
+	snd_soc_component_update_bits(component, AB8500_ANAGAIN2, AB8500_ANAGAINX_ENSEMICX,
+			amics->mic2_type == AMIC_TYPE_DIFFERENTIAL ?
+				0 : AB8500_ANAGAINX_ENSEMICX);
+
+	return 0;
+}
+
+static int ab8500_audio_set_ear_cmv(struct snd_soc_component *component,
+				enum ear_cm_voltage ear_cmv)
+{
+	char *cmv_str;
+
+	switch (ear_cmv) {
+	case EAR_CMV_0_95V:
+		cmv_str = "0.95V";
+		break;
+	case EAR_CMV_1_10V:
+		cmv_str = "1.10V";
+		break;
+	case EAR_CMV_1_27V:
+		cmv_str = "1.27V";
+		break;
+	case EAR_CMV_1_58V:
+		cmv_str = "1.58V";
+		break;
+	default:
+		dev_err(component->dev,
+			"%s: Unknown earpiece CM-voltage (%d)!\n",
+			__func__, (int)ear_cmv);
+		return -EINVAL;
+	}
+	dev_dbg(component->dev, "%s: Earpiece CM-voltage: %s\n", __func__,
+		cmv_str);
+	snd_soc_component_update_bits(component, AB8500_ANACONF1, AB8500_ANACONF1_EARSELCM,
+			ear_cmv);
+
+	return 0;
+}
+
+static int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai,
+				unsigned int delay)
+{
+	unsigned int mask, val;
+	struct snd_soc_component *component = dai->component;
+
+	mask = BIT(AB8500_DIGIFCONF2_IF0DEL);
+	val = 0;
+
+	switch (delay) {
+	case 0:
+		break;
+	case 1:
+		val |= BIT(AB8500_DIGIFCONF2_IF0DEL);
+		break;
+	default:
+		dev_err(dai->component->dev,
+			"%s: ERROR: Unsupported bit-delay (0x%x)!\n",
+			__func__, delay);
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->component->dev, "%s: IF0 Bit-delay: %d bits.\n",
+		__func__, delay);
+	snd_soc_component_update_bits(component, AB8500_DIGIFCONF2, mask, val);
+
+	return 0;
+}
+
+/* Gates clocking according format mask */
+static int ab8500_codec_set_dai_clock_gate(struct snd_soc_component *component,
+					unsigned int fmt)
+{
+	unsigned int mask;
+	unsigned int val;
+
+	mask = BIT(AB8500_DIGIFCONF1_ENMASTGEN) |
+			BIT(AB8500_DIGIFCONF1_ENFSBITCLK0);
+
+	val = BIT(AB8500_DIGIFCONF1_ENMASTGEN);
+
+	switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+	case SND_SOC_DAIFMT_CONT: /* continuous clock */
+		dev_dbg(component->dev, "%s: IF0 Clock is continuous.\n",
+			__func__);
+		val |= BIT(AB8500_DIGIFCONF1_ENFSBITCLK0);
+		break;
+	case SND_SOC_DAIFMT_GATED: /* clock is gated */
+		dev_dbg(component->dev, "%s: IF0 Clock is gated.\n",
+			__func__);
+		break;
+	default:
+		dev_err(component->dev,
+			"%s: ERROR: Unsupported clock mask (0x%x)!\n",
+			__func__, fmt & SND_SOC_DAIFMT_CLOCK_MASK);
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, AB8500_DIGIFCONF1, mask, val);
+
+	return 0;
+}
+
+static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	unsigned int mask;
+	unsigned int val;
+	struct snd_soc_component *component = dai->component;
+	int status;
+
+	dev_dbg(component->dev, "%s: Enter (fmt = 0x%x)\n", __func__, fmt);
+
+	mask = BIT(AB8500_DIGIFCONF3_IF1DATOIF0AD) |
+			BIT(AB8500_DIGIFCONF3_IF1CLKTOIF0CLK) |
+			BIT(AB8500_DIGIFCONF3_IF0BFIFOEN) |
+			BIT(AB8500_DIGIFCONF3_IF0MASTER);
+	val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & FRM master */
+		dev_dbg(dai->component->dev,
+			"%s: IF0 Master-mode: AB8500 master.\n", __func__);
+		val |= BIT(AB8500_DIGIFCONF3_IF0MASTER);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & FRM slave */
+		dev_dbg(dai->component->dev,
+			"%s: IF0 Master-mode: AB8500 slave.\n", __func__);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & FRM master */
+	case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
+		dev_err(dai->component->dev,
+			"%s: ERROR: The device is either a master or a slave.\n",
+			__func__);
+	default:
+		dev_err(dai->component->dev,
+			"%s: ERROR: Unsupporter master mask 0x%x\n",
+			__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, AB8500_DIGIFCONF3, mask, val);
+
+	/* Set clock gating */
+	status = ab8500_codec_set_dai_clock_gate(component, fmt);
+	if (status) {
+		dev_err(dai->component->dev,
+			"%s: ERROR: Failed to set clock gate (%d).\n",
+			__func__, status);
+		return status;
+	}
+
+	/* Setting data transfer format */
+
+	mask = BIT(AB8500_DIGIFCONF2_IF0FORMAT0) |
+		BIT(AB8500_DIGIFCONF2_IF0FORMAT1) |
+		BIT(AB8500_DIGIFCONF2_FSYNC0P) |
+		BIT(AB8500_DIGIFCONF2_BITCLK0P);
+	val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S: /* I2S mode */
+		dev_dbg(dai->component->dev, "%s: IF0 Protocol: I2S\n", __func__);
+		val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT1);
+		ab8500_audio_set_bit_delay(dai, 0);
+		break;
+
+	case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */
+		dev_dbg(dai->component->dev,
+			"%s: IF0 Protocol: DSP A (TDM)\n", __func__);
+		val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0);
+		ab8500_audio_set_bit_delay(dai, 1);
+		break;
+
+	case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */
+		dev_dbg(dai->component->dev,
+			"%s: IF0 Protocol: DSP B (TDM)\n", __func__);
+		val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0);
+		ab8500_audio_set_bit_delay(dai, 0);
+		break;
+
+	default:
+		dev_err(dai->component->dev,
+			"%s: ERROR: Unsupported format (0x%x)!\n",
+			__func__, fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
+		dev_dbg(dai->component->dev,
+			"%s: IF0: Normal bit clock, normal frame\n",
+			__func__);
+		break;
+	case SND_SOC_DAIFMT_NB_IF: /* normal BCLK + inv FRM */
+		dev_dbg(dai->component->dev,
+			"%s: IF0: Normal bit clock, inverted frame\n",
+			__func__);
+		val |= BIT(AB8500_DIGIFCONF2_FSYNC0P);
+		break;
+	case SND_SOC_DAIFMT_IB_NF: /* invert BCLK + nor FRM */
+		dev_dbg(dai->component->dev,
+			"%s: IF0: Inverted bit clock, normal frame\n",
+			__func__);
+		val |= BIT(AB8500_DIGIFCONF2_BITCLK0P);
+		break;
+	case SND_SOC_DAIFMT_IB_IF: /* invert BCLK + FRM */
+		dev_dbg(dai->component->dev,
+			"%s: IF0: Inverted bit clock, inverted frame\n",
+			__func__);
+		val |= BIT(AB8500_DIGIFCONF2_FSYNC0P);
+		val |= BIT(AB8500_DIGIFCONF2_BITCLK0P);
+		break;
+	default:
+		dev_err(dai->component->dev,
+			"%s: ERROR: Unsupported INV mask 0x%x\n",
+			__func__, fmt & SND_SOC_DAIFMT_INV_MASK);
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, AB8500_DIGIFCONF2, mask, val);
+
+	return 0;
+}
+
+static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
+		unsigned int tx_mask, unsigned int rx_mask,
+		int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int val, mask, slot, slots_active;
+
+	mask = BIT(AB8500_DIGIFCONF2_IF0WL0) |
+		BIT(AB8500_DIGIFCONF2_IF0WL1);
+	val = 0;
+
+	switch (slot_width) {
+	case 16:
+		break;
+	case 20:
+		val |= BIT(AB8500_DIGIFCONF2_IF0WL0);
+		break;
+	case 24:
+		val |= BIT(AB8500_DIGIFCONF2_IF0WL1);
+		break;
+	case 32:
+		val |= BIT(AB8500_DIGIFCONF2_IF0WL1) |
+			BIT(AB8500_DIGIFCONF2_IF0WL0);
+		break;
+	default:
+		dev_err(dai->component->dev, "%s: Unsupported slot-width 0x%x\n",
+			__func__, slot_width);
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->component->dev, "%s: IF0 slot-width: %d bits.\n",
+		__func__, slot_width);
+	snd_soc_component_update_bits(component, AB8500_DIGIFCONF2, mask, val);
+
+	/* Setup TDM clocking according to slot count */
+	dev_dbg(dai->component->dev, "%s: Slots, total: %d\n", __func__, slots);
+	mask = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) |
+			BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
+	switch (slots) {
+	case 2:
+		val = AB8500_MASK_NONE;
+		break;
+	case 4:
+		val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0);
+		break;
+	case 8:
+		val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
+		break;
+	case 16:
+		val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) |
+			BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
+		break;
+	default:
+		dev_err(dai->component->dev,
+			"%s: ERROR: Unsupported number of slots (%d)!\n",
+			__func__, slots);
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, AB8500_DIGIFCONF1, mask, val);
+
+	/* Setup TDM DA according to active tx slots */
+
+	if (tx_mask & ~0xff)
+		return -EINVAL;
+
+	mask = AB8500_DASLOTCONFX_SLTODAX_MASK;
+	tx_mask = tx_mask << AB8500_DA_DATA0_OFFSET;
+	slots_active = hweight32(tx_mask);
+
+	dev_dbg(dai->component->dev, "%s: Slots, active, TX: %d\n", __func__,
+		slots_active);
+
+	switch (slots_active) {
+	case 0:
+		break;
+	case 1:
+		slot = ffs(tx_mask);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF1, mask, slot);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF3, mask, slot);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF2, mask, slot);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF4, mask, slot);
+		break;
+	case 2:
+		slot = ffs(tx_mask);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF1, mask, slot);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF3, mask, slot);
+		slot = fls(tx_mask);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF2, mask, slot);
+		snd_soc_component_update_bits(component, AB8500_DASLOTCONF4, mask, slot);
+		break;
+	case 8:
+		dev_dbg(dai->component->dev,
+			"%s: In 8-channel mode DA-from-slot mapping is set manually.",
+			__func__);
+		break;
+	default:
+		dev_err(dai->component->dev,
+			"%s: Unsupported number of active TX-slots (%d)!\n",
+			__func__, slots_active);
+		return -EINVAL;
+	}
+
+	/* Setup TDM AD according to active RX-slots */
+
+	if (rx_mask & ~0xff)
+		return -EINVAL;
+
+	rx_mask = rx_mask << AB8500_AD_DATA0_OFFSET;
+	slots_active = hweight32(rx_mask);
+
+	dev_dbg(dai->component->dev, "%s: Slots, active, RX: %d\n", __func__,
+		slots_active);
+
+	switch (slots_active) {
+	case 0:
+		break;
+	case 1:
+		slot = ffs(rx_mask);
+		snd_soc_component_update_bits(component, AB8500_ADSLOTSEL(slot),
+				AB8500_MASK_SLOT(slot),
+				AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));
+		break;
+	case 2:
+		slot = ffs(rx_mask);
+		snd_soc_component_update_bits(component,
+				AB8500_ADSLOTSEL(slot),
+				AB8500_MASK_SLOT(slot),
+				AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));
+		slot = fls(rx_mask);
+		snd_soc_component_update_bits(component,
+				AB8500_ADSLOTSEL(slot),
+				AB8500_MASK_SLOT(slot),
+				AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT2, slot));
+		break;
+	case 8:
+		dev_dbg(dai->component->dev,
+			"%s: In 8-channel mode AD-to-slot mapping is set manually.",
+			__func__);
+		break;
+	default:
+		dev_err(dai->component->dev,
+			"%s: Unsupported number of active RX-slots (%d)!\n",
+			__func__, slots_active);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops ab8500_codec_ops = {
+	.set_fmt = ab8500_codec_set_dai_fmt,
+	.set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
+};
+
+static struct snd_soc_dai_driver ab8500_codec_dai[] = {
+	{
+		.name = "ab8500-codec-dai.0",
+		.id = 0,
+		.playback = {
+			.stream_name = "ab8500_0p",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = AB8500_SUPPORTED_RATE,
+			.formats = AB8500_SUPPORTED_FMT,
+		},
+		.ops = &ab8500_codec_ops,
+		.symmetric_rates = 1
+	},
+	{
+		.name = "ab8500-codec-dai.1",
+		.id = 1,
+		.capture = {
+			.stream_name = "ab8500_0c",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = AB8500_SUPPORTED_RATE,
+			.formats = AB8500_SUPPORTED_FMT,
+		},
+		.ops = &ab8500_codec_ops,
+		.symmetric_rates = 1
+	}
+};
+
+static void ab8500_codec_of_probe(struct device *dev, struct device_node *np,
+				struct ab8500_codec_platform_data *codec)
+{
+	u32 value;
+
+	if (of_property_read_bool(np, "stericsson,amic1-type-single-ended"))
+		codec->amics.mic1_type = AMIC_TYPE_SINGLE_ENDED;
+	else
+		codec->amics.mic1_type = AMIC_TYPE_DIFFERENTIAL;
+
+	if (of_property_read_bool(np, "stericsson,amic2-type-single-ended"))
+		codec->amics.mic2_type = AMIC_TYPE_SINGLE_ENDED;
+	else
+		codec->amics.mic2_type = AMIC_TYPE_DIFFERENTIAL;
+
+	/* Has a non-standard Vamic been requested? */
+	if (of_property_read_bool(np, "stericsson,amic1a-bias-vamic2"))
+		codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC2;
+	else
+		codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC1;
+
+	if (of_property_read_bool(np, "stericsson,amic1b-bias-vamic2"))
+		codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC2;
+	else
+		codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC1;
+
+	if (of_property_read_bool(np, "stericsson,amic2-bias-vamic1"))
+		codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC1;
+	else
+		codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC2;
+
+	if (!of_property_read_u32(np, "stericsson,earpeice-cmv", &value)) {
+		switch (value) {
+		case 950 :
+			codec->ear_cmv = EAR_CMV_0_95V;
+			break;
+		case 1100 :
+			codec->ear_cmv = EAR_CMV_1_10V;
+			break;
+		case 1270 :
+			codec->ear_cmv = EAR_CMV_1_27V;
+			break;
+		case 1580 :
+			codec->ear_cmv = EAR_CMV_1_58V;
+			break;
+		default :
+			codec->ear_cmv = EAR_CMV_UNKNOWN;
+			dev_err(dev, "Unsuitable earpiece voltage found in DT\n");
+		}
+	} else {
+		dev_warn(dev, "No earpiece voltage found in DT - using default\n");
+		codec->ear_cmv = EAR_CMV_0_95V;
+	}
+}
+
+static int ab8500_codec_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct device *dev = component->dev;
+	struct device_node *np = dev->of_node;
+	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
+	struct ab8500_codec_platform_data codec_pdata;
+	struct filter_control *fc;
+	int status;
+
+	dev_dbg(dev, "%s: Enter.\n", __func__);
+
+	ab8500_codec_of_probe(dev, np, &codec_pdata);
+
+	status = ab8500_audio_setup_mics(component, &codec_pdata.amics);
+	if (status < 0) {
+		pr_err("%s: Failed to setup mics (%d)!\n", __func__, status);
+		return status;
+	}
+	status = ab8500_audio_set_ear_cmv(component, codec_pdata.ear_cmv);
+	if (status < 0) {
+		pr_err("%s: Failed to set earpiece CM-voltage (%d)!\n",
+			__func__, status);
+		return status;
+	}
+
+	status = ab8500_audio_init_audioblock(component);
+	if (status < 0) {
+		dev_err(dev, "%s: failed to init audio-block (%d)!\n",
+			__func__, status);
+		return status;
+	}
+
+	/* Override HW-defaults */
+	snd_soc_component_write(component, AB8500_ANACONF5,
+		      BIT(AB8500_ANACONF5_HSAUTOEN));
+	snd_soc_component_write(component, AB8500_SHORTCIRCONF,
+		      BIT(AB8500_SHORTCIRCONF_HSZCDDIS));
+
+	/* Add filter controls */
+	status = snd_soc_add_component_controls(component, ab8500_filter_controls,
+				ARRAY_SIZE(ab8500_filter_controls));
+	if (status < 0) {
+		dev_err(dev,
+			"%s: failed to add ab8500 filter controls (%d).\n",
+			__func__, status);
+		return status;
+	}
+	fc = (struct filter_control *)
+		&ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value;
+	drvdata->anc_fir_values = (long *)fc->value;
+	fc = (struct filter_control *)
+		&ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value;
+	drvdata->anc_iir_values = (long *)fc->value;
+	fc = (struct filter_control *)
+		&ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value;
+	drvdata->sid_fir_values = (long *)fc->value;
+
+	snd_soc_dapm_disable_pin(dapm, "ANC Configure Input");
+
+	mutex_init(&drvdata->ctrl_lock);
+
+	return status;
+}
+
+static const struct snd_soc_component_driver ab8500_component_driver = {
+	.probe			= ab8500_codec_probe,
+	.controls		= ab8500_ctrls,
+	.num_controls		= ARRAY_SIZE(ab8500_ctrls),
+	.dapm_widgets		= ab8500_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ab8500_dapm_widgets),
+	.dapm_routes		= ab8500_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ab8500_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int ab8500_codec_driver_probe(struct platform_device *pdev)
+{
+	int status;
+	struct ab8500_codec_drvdata *drvdata;
+
+	dev_dbg(&pdev->dev, "%s: Enter.\n", __func__);
+
+	/* Create driver private-data struct */
+	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_codec_drvdata),
+			GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->sid_status = SID_UNCONFIGURED;
+	drvdata->anc_status = ANC_UNCONFIGURED;
+	dev_set_drvdata(&pdev->dev, drvdata);
+
+	drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev,
+					   &ab8500_codec_regmap);
+	if (IS_ERR(drvdata->regmap)) {
+		status = PTR_ERR(drvdata->regmap);
+		dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n",
+			__func__, status);
+		return status;
+	}
+
+	dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__);
+	status = devm_snd_soc_register_component(&pdev->dev,
+				&ab8500_component_driver,
+				ab8500_codec_dai,
+				ARRAY_SIZE(ab8500_codec_dai));
+	if (status < 0)
+		dev_err(&pdev->dev,
+			"%s: Error: Failed to register codec (%d).\n",
+			__func__, status);
+
+	return status;
+}
+
+static struct platform_driver ab8500_codec_platform_driver = {
+	.driver	= {
+		.name	= "ab8500-codec",
+	},
+	.probe		= ab8500_codec_driver_probe,
+};
+module_platform_driver(ab8500_codec_platform_driver);
+
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ab8500-codec.h b/sound/soc/codecs/ab8500-codec.h
new file mode 100644
index 0000000..e2e5442
--- /dev/null
+++ b/sound/soc/codecs/ab8500-codec.h
@@ -0,0 +1,592 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ *         Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>,
+ *         Roger Nilsson <roger.xr.nilsson@stericsson.com>,
+ *         for ST-Ericsson.
+ *
+ *         Based on the early work done by:
+ *         Mikko J. Lehto <mikko.lehto@symbio.com>,
+ *         Mikko Sarmanne <mikko.sarmanne@symbio.com>,
+ *         for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef AB8500_CODEC_REGISTERS_H
+#define AB8500_CODEC_REGISTERS_H
+
+#define AB8500_SUPPORTED_RATE			(SNDRV_PCM_RATE_48000)
+#define AB8500_SUPPORTED_FMT			(SNDRV_PCM_FMTBIT_S16_LE)
+
+/* AB8500 interface slot offset definitions */
+
+#define AB8500_AD_DATA0_OFFSET	0
+#define AB8500_DA_DATA0_OFFSET	8
+#define AB8500_AD_DATA1_OFFSET	16
+#define AB8500_DA_DATA1_OFFSET	24
+
+/* AB8500 audio bank (0x0d) register definitions */
+
+#define AB8500_POWERUP				0x00
+#define AB8500_AUDSWRESET			0x01
+#define AB8500_ADPATHENA			0x02
+#define AB8500_DAPATHENA			0x03
+#define AB8500_ANACONF1				0x04
+#define AB8500_ANACONF2				0x05
+#define AB8500_DIGMICCONF			0x06
+#define AB8500_ANACONF3				0x07
+#define AB8500_ANACONF4				0x08
+#define AB8500_DAPATHCONF			0x09
+#define AB8500_MUTECONF				0x0A
+#define AB8500_SHORTCIRCONF			0x0B
+#define AB8500_ANACONF5				0x0C
+#define AB8500_ENVCPCONF			0x0D
+#define AB8500_SIGENVCONF			0x0E
+#define AB8500_PWMGENCONF1			0x0F
+#define AB8500_PWMGENCONF2			0x10
+#define AB8500_PWMGENCONF3			0x11
+#define AB8500_PWMGENCONF4			0x12
+#define AB8500_PWMGENCONF5			0x13
+#define AB8500_ANAGAIN1				0x14
+#define AB8500_ANAGAIN2				0x15
+#define AB8500_ANAGAIN3				0x16
+#define AB8500_ANAGAIN4				0x17
+#define AB8500_DIGLINHSLGAIN			0x18
+#define AB8500_DIGLINHSRGAIN			0x19
+#define AB8500_ADFILTCONF			0x1A
+#define AB8500_DIGIFCONF1			0x1B
+#define AB8500_DIGIFCONF2			0x1C
+#define AB8500_DIGIFCONF3			0x1D
+#define AB8500_DIGIFCONF4			0x1E
+#define AB8500_ADSLOTSEL1			0x1F
+#define AB8500_ADSLOTSEL2			0x20
+#define AB8500_ADSLOTSEL3			0x21
+#define AB8500_ADSLOTSEL4			0x22
+#define AB8500_ADSLOTSEL5			0x23
+#define AB8500_ADSLOTSEL6			0x24
+#define AB8500_ADSLOTSEL7			0x25
+#define AB8500_ADSLOTSEL8			0x26
+#define AB8500_ADSLOTSEL9			0x27
+#define AB8500_ADSLOTSEL10			0x28
+#define AB8500_ADSLOTSEL11			0x29
+#define AB8500_ADSLOTSEL12			0x2A
+#define AB8500_ADSLOTSEL13			0x2B
+#define AB8500_ADSLOTSEL14			0x2C
+#define AB8500_ADSLOTSEL15			0x2D
+#define AB8500_ADSLOTSEL16			0x2E
+#define AB8500_ADSLOTSEL(slot)			(AB8500_ADSLOTSEL1 + (slot >> 1))
+#define AB8500_ADSLOTHIZCTRL1			0x2F
+#define AB8500_ADSLOTHIZCTRL2			0x30
+#define AB8500_ADSLOTHIZCTRL3			0x31
+#define AB8500_ADSLOTHIZCTRL4			0x32
+#define AB8500_DASLOTCONF1			0x33
+#define AB8500_DASLOTCONF2			0x34
+#define AB8500_DASLOTCONF3			0x35
+#define AB8500_DASLOTCONF4			0x36
+#define AB8500_DASLOTCONF5			0x37
+#define AB8500_DASLOTCONF6			0x38
+#define AB8500_DASLOTCONF7			0x39
+#define AB8500_DASLOTCONF8			0x3A
+#define AB8500_CLASSDCONF1			0x3B
+#define AB8500_CLASSDCONF2			0x3C
+#define AB8500_CLASSDCONF3			0x3D
+#define AB8500_DMICFILTCONF			0x3E
+#define AB8500_DIGMULTCONF1			0x3F
+#define AB8500_DIGMULTCONF2			0x40
+#define AB8500_ADDIGGAIN1			0x41
+#define AB8500_ADDIGGAIN2			0x42
+#define AB8500_ADDIGGAIN3			0x43
+#define AB8500_ADDIGGAIN4			0x44
+#define AB8500_ADDIGGAIN5			0x45
+#define AB8500_ADDIGGAIN6			0x46
+#define AB8500_DADIGGAIN1			0x47
+#define AB8500_DADIGGAIN2			0x48
+#define AB8500_DADIGGAIN3			0x49
+#define AB8500_DADIGGAIN4			0x4A
+#define AB8500_DADIGGAIN5			0x4B
+#define AB8500_DADIGGAIN6			0x4C
+#define AB8500_ADDIGLOOPGAIN1			0x4D
+#define AB8500_ADDIGLOOPGAIN2			0x4E
+#define AB8500_HSLEARDIGGAIN			0x4F
+#define AB8500_HSRDIGGAIN			0x50
+#define AB8500_SIDFIRGAIN1			0x51
+#define AB8500_SIDFIRGAIN2			0x52
+#define AB8500_ANCCONF1				0x53
+#define AB8500_ANCCONF2				0x54
+#define AB8500_ANCCONF3				0x55
+#define AB8500_ANCCONF4				0x56
+#define AB8500_ANCCONF5				0x57
+#define AB8500_ANCCONF6				0x58
+#define AB8500_ANCCONF7				0x59
+#define AB8500_ANCCONF8				0x5A
+#define AB8500_ANCCONF9				0x5B
+#define AB8500_ANCCONF10			0x5C
+#define AB8500_ANCCONF11			0x5D
+#define AB8500_ANCCONF12			0x5E
+#define AB8500_ANCCONF13			0x5F
+#define AB8500_ANCCONF14			0x60
+#define AB8500_SIDFIRADR			0x61
+#define AB8500_SIDFIRCOEF1			0x62
+#define AB8500_SIDFIRCOEF2			0x63
+#define AB8500_SIDFIRCONF			0x64
+#define AB8500_AUDINTMASK1			0x65
+#define AB8500_AUDINTSOURCE1			0x66
+#define AB8500_AUDINTMASK2			0x67
+#define AB8500_AUDINTSOURCE2			0x68
+#define AB8500_FIFOCONF1			0x69
+#define AB8500_FIFOCONF2			0x6A
+#define AB8500_FIFOCONF3			0x6B
+#define AB8500_FIFOCONF4			0x6C
+#define AB8500_FIFOCONF5			0x6D
+#define AB8500_FIFOCONF6			0x6E
+#define AB8500_AUDREV				0x6F
+
+#define AB8500_FIRST_REG			AB8500_POWERUP
+#define AB8500_LAST_REG				AB8500_AUDREV
+#define AB8500_CACHEREGNUM			(AB8500_LAST_REG + 1)
+
+#define AB8500_MASK_ALL				0xFF
+#define AB8500_MASK_SLOT(slot)			((slot & 1) ? 0xF0 : 0x0F)
+#define AB8500_MASK_NONE			0x00
+
+/* AB8500_POWERUP */
+#define AB8500_POWERUP_POWERUP			7
+#define AB8500_POWERUP_ENANA			3
+
+/* AB8500_AUDSWRESET */
+#define AB8500_AUDSWRESET_SWRESET		7
+
+/* AB8500_ADPATHENA */
+#define AB8500_ADPATHENA_ENAD12			7
+#define AB8500_ADPATHENA_ENAD34			5
+#define AB8500_ADPATHENA_ENAD5768		3
+
+/* AB8500_DAPATHENA */
+#define AB8500_DAPATHENA_ENDA1			7
+#define AB8500_DAPATHENA_ENDA2			6
+#define AB8500_DAPATHENA_ENDA3			5
+#define AB8500_DAPATHENA_ENDA4			4
+#define AB8500_DAPATHENA_ENDA5			3
+#define AB8500_DAPATHENA_ENDA6			2
+
+/* AB8500_ANACONF1 */
+#define AB8500_ANACONF1_HSLOWPOW		7
+#define AB8500_ANACONF1_DACLOWPOW1		6
+#define AB8500_ANACONF1_DACLOWPOW0		5
+#define AB8500_ANACONF1_EARDACLOWPOW		4
+#define AB8500_ANACONF1_EARSELCM		2
+#define AB8500_ANACONF1_HSHPEN			1
+#define AB8500_ANACONF1_EARDRVLOWPOW		0
+
+/* AB8500_ANACONF2 */
+#define AB8500_ANACONF2_ENMIC1			7
+#define AB8500_ANACONF2_ENMIC2			6
+#define AB8500_ANACONF2_ENLINL			5
+#define AB8500_ANACONF2_ENLINR			4
+#define AB8500_ANACONF2_MUTMIC1			3
+#define AB8500_ANACONF2_MUTMIC2			2
+#define AB8500_ANACONF2_MUTLINL			1
+#define AB8500_ANACONF2_MUTLINR			0
+
+/* AB8500_DIGMICCONF */
+#define AB8500_DIGMICCONF_ENDMIC1		7
+#define AB8500_DIGMICCONF_ENDMIC2		6
+#define AB8500_DIGMICCONF_ENDMIC3		5
+#define AB8500_DIGMICCONF_ENDMIC4		4
+#define AB8500_DIGMICCONF_ENDMIC5		3
+#define AB8500_DIGMICCONF_ENDMIC6		2
+#define AB8500_DIGMICCONF_HSFADSPEED		0
+
+/* AB8500_ANACONF3 */
+#define AB8500_ANACONF3_MIC1SEL			7
+#define AB8500_ANACONF3_LINRSEL			6
+#define AB8500_ANACONF3_ENDRVHSL		5
+#define AB8500_ANACONF3_ENDRVHSR		4
+#define AB8500_ANACONF3_ENADCMIC		2
+#define AB8500_ANACONF3_ENADCLINL		1
+#define AB8500_ANACONF3_ENADCLINR		0
+
+/* AB8500_ANACONF4 */
+#define AB8500_ANACONF4_DISPDVSS		7
+#define AB8500_ANACONF4_ENEAR			6
+#define AB8500_ANACONF4_ENHSL			5
+#define AB8500_ANACONF4_ENHSR			4
+#define AB8500_ANACONF4_ENHFL			3
+#define AB8500_ANACONF4_ENHFR			2
+#define AB8500_ANACONF4_ENVIB1			1
+#define AB8500_ANACONF4_ENVIB2			0
+
+/* AB8500_DAPATHCONF */
+#define AB8500_DAPATHCONF_ENDACEAR		6
+#define AB8500_DAPATHCONF_ENDACHSL		5
+#define AB8500_DAPATHCONF_ENDACHSR		4
+#define AB8500_DAPATHCONF_ENDACHFL		3
+#define AB8500_DAPATHCONF_ENDACHFR		2
+#define AB8500_DAPATHCONF_ENDACVIB1		1
+#define AB8500_DAPATHCONF_ENDACVIB2		0
+
+/* AB8500_MUTECONF */
+#define AB8500_MUTECONF_MUTEAR			6
+#define AB8500_MUTECONF_MUTHSL			5
+#define AB8500_MUTECONF_MUTHSR			4
+#define AB8500_MUTECONF_MUTDACEAR		2
+#define AB8500_MUTECONF_MUTDACHSL		1
+#define AB8500_MUTECONF_MUTDACHSR		0
+
+/* AB8500_SHORTCIRCONF */
+#define AB8500_SHORTCIRCONF_ENSHORTPWD		7
+#define AB8500_SHORTCIRCONF_EARSHORTDIS		6
+#define AB8500_SHORTCIRCONF_HSSHORTDIS		5
+#define AB8500_SHORTCIRCONF_HSPULLDEN		4
+#define AB8500_SHORTCIRCONF_HSOSCEN		2
+#define AB8500_SHORTCIRCONF_HSFADDIS		1
+#define AB8500_SHORTCIRCONF_HSZCDDIS		0
+/* Zero cross should be disabled */
+
+/* AB8500_ANACONF5 */
+#define AB8500_ANACONF5_ENCPHS			7
+#define AB8500_ANACONF5_HSLDACTOLOL		5
+#define AB8500_ANACONF5_HSRDACTOLOR		4
+#define AB8500_ANACONF5_ENLOL			3
+#define AB8500_ANACONF5_ENLOR			2
+#define AB8500_ANACONF5_HSAUTOEN		0
+
+/* AB8500_ENVCPCONF */
+#define AB8500_ENVCPCONF_ENVDETHTHRE		4
+#define AB8500_ENVCPCONF_ENVDETLTHRE		0
+#define AB8500_ENVCPCONF_ENVDETHTHRE_MAX	0x0F
+#define AB8500_ENVCPCONF_ENVDETLTHRE_MAX	0x0F
+
+/* AB8500_SIGENVCONF */
+#define AB8500_SIGENVCONF_CPLVEN		5
+#define AB8500_SIGENVCONF_ENVDETCPEN		4
+#define AB8500_SIGENVCONF_ENVDETTIME		0
+#define AB8500_SIGENVCONF_ENVDETTIME_MAX	0x0F
+
+/* AB8500_PWMGENCONF1 */
+#define AB8500_PWMGENCONF1_PWMTOVIB1		7
+#define AB8500_PWMGENCONF1_PWMTOVIB2		6
+#define AB8500_PWMGENCONF1_PWM1CTRL		5
+#define AB8500_PWMGENCONF1_PWM2CTRL		4
+#define AB8500_PWMGENCONF1_PWM1NCTRL		3
+#define AB8500_PWMGENCONF1_PWM1PCTRL		2
+#define AB8500_PWMGENCONF1_PWM2NCTRL		1
+#define AB8500_PWMGENCONF1_PWM2PCTRL		0
+
+/* AB8500_PWMGENCONF2 */
+/* AB8500_PWMGENCONF3 */
+/* AB8500_PWMGENCONF4 */
+/* AB8500_PWMGENCONF5 */
+#define AB8500_PWMGENCONFX_PWMVIBXPOL		7
+#define AB8500_PWMGENCONFX_PWMVIBXDUTCYC	0
+#define AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX	0x64
+
+/* AB8500_ANAGAIN1 */
+/* AB8500_ANAGAIN2 */
+#define AB8500_ANAGAINX_ENSEMICX		7
+#define AB8500_ANAGAINX_LOWPOWMICX		6
+#define AB8500_ANAGAINX_MICXGAIN		0
+#define AB8500_ANAGAINX_MICXGAIN_MAX		0x1F
+
+/* AB8500_ANAGAIN3 */
+#define AB8500_ANAGAIN3_HSLGAIN			4
+#define AB8500_ANAGAIN3_HSRGAIN			0
+#define AB8500_ANAGAIN3_HSXGAIN_MAX		0x0F
+
+/* AB8500_ANAGAIN4 */
+#define AB8500_ANAGAIN4_LINLGAIN		4
+#define AB8500_ANAGAIN4_LINRGAIN		0
+#define AB8500_ANAGAIN4_LINXGAIN_MAX		0x0F
+
+/* AB8500_DIGLINHSLGAIN */
+/* AB8500_DIGLINHSRGAIN */
+#define AB8500_DIGLINHSXGAIN_LINTOHSXGAIN	0
+#define AB8500_DIGLINHSXGAIN_LINTOHSXGAIN_MAX	0x13
+
+/* AB8500_ADFILTCONF */
+#define AB8500_ADFILTCONF_AD1NH			7
+#define AB8500_ADFILTCONF_AD2NH			6
+#define AB8500_ADFILTCONF_AD3NH			5
+#define AB8500_ADFILTCONF_AD4NH			4
+#define AB8500_ADFILTCONF_AD1VOICE		3
+#define AB8500_ADFILTCONF_AD2VOICE		2
+#define AB8500_ADFILTCONF_AD3VOICE		1
+#define AB8500_ADFILTCONF_AD4VOICE		0
+
+/* AB8500_DIGIFCONF1 */
+#define AB8500_DIGIFCONF1_ENMASTGEN		7
+#define AB8500_DIGIFCONF1_IF1BITCLKOS1		6
+#define AB8500_DIGIFCONF1_IF1BITCLKOS0		5
+#define AB8500_DIGIFCONF1_ENFSBITCLK1		4
+#define AB8500_DIGIFCONF1_IF0BITCLKOS1		2
+#define AB8500_DIGIFCONF1_IF0BITCLKOS0		1
+#define AB8500_DIGIFCONF1_ENFSBITCLK0		0
+
+/* AB8500_DIGIFCONF2 */
+#define AB8500_DIGIFCONF2_FSYNC0P		6
+#define AB8500_DIGIFCONF2_BITCLK0P		5
+#define AB8500_DIGIFCONF2_IF0DEL		4
+#define AB8500_DIGIFCONF2_IF0FORMAT1		3
+#define AB8500_DIGIFCONF2_IF0FORMAT0		2
+#define AB8500_DIGIFCONF2_IF0WL1		1
+#define AB8500_DIGIFCONF2_IF0WL0		0
+
+/* AB8500_DIGIFCONF3 */
+#define AB8500_DIGIFCONF3_IF0DATOIF1AD		7
+#define AB8500_DIGIFCONF3_IF0CLKTOIF1CLK	6
+#define AB8500_DIGIFCONF3_IF1MASTER		5
+#define AB8500_DIGIFCONF3_IF1DATOIF0AD		3
+#define AB8500_DIGIFCONF3_IF1CLKTOIF0CLK	2
+#define AB8500_DIGIFCONF3_IF0MASTER		1
+#define AB8500_DIGIFCONF3_IF0BFIFOEN		0
+
+/* AB8500_DIGIFCONF4 */
+#define AB8500_DIGIFCONF4_FSYNC1P		6
+#define AB8500_DIGIFCONF4_BITCLK1P		5
+#define AB8500_DIGIFCONF4_IF1DEL		4
+#define AB8500_DIGIFCONF4_IF1FORMAT1		3
+#define AB8500_DIGIFCONF4_IF1FORMAT0		2
+#define AB8500_DIGIFCONF4_IF1WL1		1
+#define AB8500_DIGIFCONF4_IF1WL0		0
+
+/* AB8500_ADSLOTSELX */
+#define AB8500_AD_OUT1	0x0
+#define AB8500_AD_OUT2	0x1
+#define AB8500_AD_OUT3	0x2
+#define AB8500_AD_OUT4	0x3
+#define AB8500_AD_OUT5	0x4
+#define AB8500_AD_OUT6	0x5
+#define AB8500_AD_OUT7	0x6
+#define AB8500_AD_OUT8	0x7
+#define AB8500_ZEROES	0x8
+#define AB8500_TRISTATE	0xF
+#define AB8500_ADSLOTSELX_EVEN_SHIFT		0
+#define AB8500_ADSLOTSELX_ODD_SHIFT		4
+#define AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(out, slot)	\
+	((out) << (((slot) & 1) ? \
+	 AB8500_ADSLOTSELX_ODD_SHIFT : AB8500_ADSLOTSELX_EVEN_SHIFT))
+
+/* AB8500_ADSLOTHIZCTRL1 */
+/* AB8500_ADSLOTHIZCTRL2 */
+/* AB8500_ADSLOTHIZCTRL3 */
+/* AB8500_ADSLOTHIZCTRL4 */
+/* AB8500_DASLOTCONF1 */
+#define AB8500_DASLOTCONF1_DA12VOICE		7
+#define AB8500_DASLOTCONF1_SWAPDA12_34		6
+#define AB8500_DASLOTCONF1_DAI7TOADO1		5
+
+/* AB8500_DASLOTCONF2 */
+#define AB8500_DASLOTCONF2_DAI8TOADO2		5
+
+/* AB8500_DASLOTCONF3 */
+#define AB8500_DASLOTCONF3_DA34VOICE		7
+#define AB8500_DASLOTCONF3_DAI7TOADO3		5
+
+/* AB8500_DASLOTCONF4 */
+#define AB8500_DASLOTCONF4_DAI8TOADO4		5
+
+/* AB8500_DASLOTCONF5 */
+#define AB8500_DASLOTCONF5_DA56VOICE		7
+#define AB8500_DASLOTCONF5_DAI7TOADO5		5
+
+/* AB8500_DASLOTCONF6 */
+#define AB8500_DASLOTCONF6_DAI8TOADO6		5
+
+/* AB8500_DASLOTCONF7 */
+#define AB8500_DASLOTCONF7_DAI8TOADO7		5
+
+/* AB8500_DASLOTCONF8 */
+#define AB8500_DASLOTCONF8_DAI7TOADO8		5
+
+#define AB8500_DASLOTCONFX_SLTODAX_SHIFT	0
+#define AB8500_DASLOTCONFX_SLTODAX_MASK		0x1F
+
+/* AB8500_CLASSDCONF1 */
+#define AB8500_CLASSDCONF1_PARLHF		7
+#define AB8500_CLASSDCONF1_PARLVIB		6
+#define AB8500_CLASSDCONF1_VIB1SWAPEN		3
+#define AB8500_CLASSDCONF1_VIB2SWAPEN		2
+#define AB8500_CLASSDCONF1_HFLSWAPEN		1
+#define AB8500_CLASSDCONF1_HFRSWAPEN		0
+
+/* AB8500_CLASSDCONF2 */
+#define AB8500_CLASSDCONF2_FIRBYP3		7
+#define AB8500_CLASSDCONF2_FIRBYP2		6
+#define AB8500_CLASSDCONF2_FIRBYP1		5
+#define AB8500_CLASSDCONF2_FIRBYP0		4
+#define AB8500_CLASSDCONF2_HIGHVOLEN3		3
+#define AB8500_CLASSDCONF2_HIGHVOLEN2		2
+#define AB8500_CLASSDCONF2_HIGHVOLEN1		1
+#define AB8500_CLASSDCONF2_HIGHVOLEN0		0
+
+/* AB8500_CLASSDCONF3 */
+#define AB8500_CLASSDCONF3_DITHHPGAIN		4
+#define AB8500_CLASSDCONF3_DITHHPGAIN_MAX	0x0A
+#define AB8500_CLASSDCONF3_DITHWGAIN		0
+#define AB8500_CLASSDCONF3_DITHWGAIN_MAX	0x0A
+
+/* AB8500_DMICFILTCONF */
+#define AB8500_DMICFILTCONF_ANCINSEL		7
+#define AB8500_DMICFILTCONF_DA3TOEAR		6
+#define AB8500_DMICFILTCONF_DMIC1SINC3		5
+#define AB8500_DMICFILTCONF_DMIC2SINC3		4
+#define AB8500_DMICFILTCONF_DMIC3SINC3		3
+#define AB8500_DMICFILTCONF_DMIC4SINC3		2
+#define AB8500_DMICFILTCONF_DMIC5SINC3		1
+#define AB8500_DMICFILTCONF_DMIC6SINC3		0
+
+/* AB8500_DIGMULTCONF1 */
+#define AB8500_DIGMULTCONF1_DATOHSLEN		7
+#define AB8500_DIGMULTCONF1_DATOHSREN		6
+#define AB8500_DIGMULTCONF1_AD1SEL		5
+#define AB8500_DIGMULTCONF1_AD2SEL		4
+#define AB8500_DIGMULTCONF1_AD3SEL		3
+#define AB8500_DIGMULTCONF1_AD5SEL		2
+#define AB8500_DIGMULTCONF1_AD6SEL		1
+#define AB8500_DIGMULTCONF1_ANCSEL		0
+
+/* AB8500_DIGMULTCONF2 */
+#define AB8500_DIGMULTCONF2_DATOHFREN		7
+#define AB8500_DIGMULTCONF2_DATOHFLEN		6
+#define AB8500_DIGMULTCONF2_HFRSEL		5
+#define AB8500_DIGMULTCONF2_HFLSEL		4
+#define AB8500_DIGMULTCONF2_FIRSID1SEL		2
+#define AB8500_DIGMULTCONF2_FIRSID2SEL		0
+
+/* AB8500_ADDIGGAIN1 */
+/* AB8500_ADDIGGAIN2 */
+/* AB8500_ADDIGGAIN3 */
+/* AB8500_ADDIGGAIN4 */
+/* AB8500_ADDIGGAIN5 */
+/* AB8500_ADDIGGAIN6 */
+#define AB8500_ADDIGGAINX_FADEDISADX		6
+#define AB8500_ADDIGGAINX_ADXGAIN_MAX		0x3F
+
+/* AB8500_DADIGGAIN1 */
+/* AB8500_DADIGGAIN2 */
+/* AB8500_DADIGGAIN3 */
+/* AB8500_DADIGGAIN4 */
+/* AB8500_DADIGGAIN5 */
+/* AB8500_DADIGGAIN6 */
+#define AB8500_DADIGGAINX_FADEDISDAX		6
+#define AB8500_DADIGGAINX_DAXGAIN_MAX		0x3F
+
+/* AB8500_ADDIGLOOPGAIN1 */
+/* AB8500_ADDIGLOOPGAIN2 */
+#define AB8500_ADDIGLOOPGAINX_FADEDISADXL	6
+#define AB8500_ADDIGLOOPGAINX_ADXLBGAIN_MAX	0x3F
+
+/* AB8500_HSLEARDIGGAIN */
+#define AB8500_HSLEARDIGGAIN_HSSINC1		7
+#define AB8500_HSLEARDIGGAIN_FADEDISHSL		4
+#define AB8500_HSLEARDIGGAIN_HSLDGAIN_MAX	0x09
+
+/* AB8500_HSRDIGGAIN */
+#define AB8500_HSRDIGGAIN_FADESPEED		6
+#define AB8500_HSRDIGGAIN_FADEDISHSR		4
+#define AB8500_HSRDIGGAIN_HSRDGAIN_MAX		0x09
+
+/* AB8500_SIDFIRGAIN1 */
+/* AB8500_SIDFIRGAIN2 */
+#define AB8500_SIDFIRGAINX_FIRSIDXGAIN_MAX	0x1F
+
+/* AB8500_ANCCONF1 */
+#define AB8500_ANCCONF1_ANCIIRUPDATE		3
+#define AB8500_ANCCONF1_ENANC			2
+#define AB8500_ANCCONF1_ANCIIRINIT		1
+#define AB8500_ANCCONF1_ANCFIRUPDATE		0
+
+/* AB8500_ANCCONF2 */
+#define AB8500_ANCCONF2_SHIFT			5
+#define AB8500_ANCCONF2_MIN			-0x10
+#define AB8500_ANCCONF2_MAX			0xF
+
+/* AB8500_ANCCONF3 */
+#define AB8500_ANCCONF3_SHIFT			5
+#define AB8500_ANCCONF3_MIN			-0x10
+#define AB8500_ANCCONF3_MAX			0xF
+
+/* AB8500_ANCCONF4 */
+#define AB8500_ANCCONF4_SHIFT			5
+#define AB8500_ANCCONF4_MIN			-0x10
+#define AB8500_ANCCONF4_MAX			0xF
+
+/* AB8500_ANC_FIR_COEFFS */
+#define AB8500_ANC_FIR_COEFF_MIN		-0x8000
+#define AB8500_ANC_FIR_COEFF_MAX		0x7FFF
+#define AB8500_ANC_FIR_COEFFS			15
+
+/* AB8500_ANC_IIR_COEFFS */
+#define AB8500_ANC_IIR_COEFF_MIN		-0x800000
+#define AB8500_ANC_IIR_COEFF_MAX		0x7FFFFF
+#define AB8500_ANC_IIR_COEFFS			24
+/* AB8500_ANC_WARP_DELAY */
+#define AB8500_ANC_WARP_DELAY_SHIFT		16
+#define AB8500_ANC_WARP_DELAY_MIN		0x0000
+#define AB8500_ANC_WARP_DELAY_MAX		0xFFFF
+
+/* AB8500_ANCCONF11 */
+/* AB8500_ANCCONF12 */
+/* AB8500_ANCCONF13 */
+/* AB8500_ANCCONF14 */
+
+/* AB8500_SIDFIRADR */
+#define AB8500_SIDFIRADR_FIRSIDSET		7
+#define AB8500_SIDFIRADR_ADDRESS_SHIFT		0
+#define AB8500_SIDFIRADR_ADDRESS_MAX		0x7F
+
+/* AB8500_SIDFIRCOEF1 */
+/* AB8500_SIDFIRCOEF2 */
+#define AB8500_SID_FIR_COEFF_MIN		0
+#define AB8500_SID_FIR_COEFF_MAX		0xFFFF
+#define AB8500_SID_FIR_COEFFS			128
+
+/* AB8500_SIDFIRCONF */
+#define AB8500_SIDFIRCONF_ENFIRSIDS		2
+#define AB8500_SIDFIRCONF_FIRSIDSTOIF1		1
+#define AB8500_SIDFIRCONF_FIRSIDBUSY		0
+
+/* AB8500_AUDINTMASK1 */
+/* AB8500_AUDINTSOURCE1 */
+/* AB8500_AUDINTMASK2 */
+/* AB8500_AUDINTSOURCE2 */
+
+/* AB8500_FIFOCONF1 */
+#define AB8500_FIFOCONF1_BFIFOMASK		0x80
+#define AB8500_FIFOCONF1_BFIFO19M2		0x40
+#define AB8500_FIFOCONF1_BFIFOINT_SHIFT		0
+#define AB8500_FIFOCONF1_BFIFOINT_MAX		0x3F
+
+/* AB8500_FIFOCONF2 */
+#define AB8500_FIFOCONF2_BFIFOTX_SHIFT		0
+#define AB8500_FIFOCONF2_BFIFOTX_MAX		0xFF
+
+/* AB8500_FIFOCONF3 */
+#define AB8500_FIFOCONF3_BFIFOEXSL_SHIFT	5
+#define AB8500_FIFOCONF3_BFIFOEXSL_MAX		0x5
+#define AB8500_FIFOCONF3_PREBITCLK0_SHIFT	2
+#define AB8500_FIFOCONF3_PREBITCLK0_MAX		0x7
+#define AB8500_FIFOCONF3_BFIFOMAST_SHIFT	1
+#define AB8500_FIFOCONF3_BFIFORUN_SHIFT		0
+
+/* AB8500_FIFOCONF4 */
+#define AB8500_FIFOCONF4_BFIFOFRAMSW_SHIFT	0
+#define AB8500_FIFOCONF4_BFIFOFRAMSW_MAX	0xFF
+
+/* AB8500_FIFOCONF5 */
+#define AB8500_FIFOCONF5_BFIFOWAKEUP_SHIFT	0
+#define AB8500_FIFOCONF5_BFIFOWAKEUP_MAX	0xFF
+
+/* AB8500_FIFOCONF6 */
+#define AB8500_FIFOCONF6_BFIFOSAMPLE_SHIFT	0
+#define AB8500_FIFOCONF6_BFIFOSAMPLE_MAX	0xFF
+
+/* AB8500_AUDREV */
+
+#endif
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
new file mode 100644
index 0000000..02b4d01
--- /dev/null
+++ b/sound/soc/codecs/ac97.c
@@ -0,0 +1,154 @@
+/*
+ * ac97.c  --  ALSA Soc AC97 codec support
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ *  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.
+ *
+ * Generic AC97 support.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+static const struct snd_soc_dapm_widget ac97_widgets[] = {
+	SND_SOC_DAPM_INPUT("RX"),
+	SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route ac97_routes[] = {
+	{ "AC97 Capture", NULL, "RX" },
+	{ "TX", NULL, "AC97 Playback" },
+};
+
+static int ac97_prepare(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
+
+	int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+		  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
+	return snd_ac97_set_rate(ac97, reg, substream->runtime->rate);
+}
+
+static const struct snd_soc_dai_ops ac97_dai_ops = {
+	.prepare	= ac97_prepare,
+};
+
+static struct snd_soc_dai_driver ac97_dai = {
+	.name = "ac97-hifi",
+	.playback = {
+		.stream_name = "AC97 Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = SND_SOC_STD_AC97_FMTS,},
+	.capture = {
+		.stream_name = "AC97 Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = SND_SOC_STD_AC97_FMTS,},
+	.ops = &ac97_dai_ops,
+};
+
+static int ac97_soc_probe(struct snd_soc_component *component)
+{
+	struct snd_ac97 *ac97;
+	struct snd_ac97_bus *ac97_bus;
+	struct snd_ac97_template ac97_template;
+	int ret;
+
+	/* add codec as bus device for standard ac97 */
+	ret = snd_ac97_bus(component->card->snd_card, 0, soc_ac97_ops,
+			   NULL, &ac97_bus);
+	if (ret < 0)
+		return ret;
+
+	memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
+	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97);
+	if (ret < 0)
+		return ret;
+
+	snd_soc_component_set_drvdata(component, ac97);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int ac97_soc_suspend(struct snd_soc_component *component)
+{
+	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
+
+	snd_ac97_suspend(ac97);
+
+	return 0;
+}
+
+static int ac97_soc_resume(struct snd_soc_component *component)
+{
+
+	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
+
+	snd_ac97_resume(ac97);
+
+	return 0;
+}
+#else
+#define ac97_soc_suspend NULL
+#define ac97_soc_resume NULL
+#endif
+
+static const struct snd_soc_component_driver soc_component_dev_ac97 = {
+	.probe			= ac97_soc_probe,
+	.suspend		= ac97_soc_suspend,
+	.resume			= ac97_soc_resume,
+	.dapm_widgets		= ac97_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ac97_widgets),
+	.dapm_routes		= ac97_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ac97_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int ac97_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_ac97, &ac97_dai, 1);
+}
+
+static int ac97_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver ac97_codec_driver = {
+	.driver = {
+		.name = "ac97-codec",
+	},
+
+	.probe = ac97_probe,
+	.remove = ac97_remove,
+};
+
+module_platform_driver(ac97_codec_driver);
+
+MODULE_DESCRIPTION("Soc Generic AC97 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ac97-codec");
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
new file mode 100644
index 0000000..ada663b
--- /dev/null
+++ b/sound/soc/codecs/ad1836.c
@@ -0,0 +1,413 @@
+ /*
+ * Audio Codec driver supporting:
+ *  AD1835A, AD1836, AD1837A, AD1838A, AD1839A
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include "ad1836.h"
+
+enum ad1836_type {
+	AD1835,
+	AD1836,
+	AD1838,
+};
+
+/* codec private data */
+struct ad1836_priv {
+	enum ad1836_type type;
+	struct regmap *regmap;
+};
+
+/*
+ * AD1836 volume/mute/de-emphasis etc. controls
+ */
+static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"};
+
+static SOC_ENUM_SINGLE_DECL(ad1836_deemp_enum,
+			    AD1836_DAC_CTRL1, 8, ad1836_deemp);
+
+#define AD1836_DAC_VOLUME(x) \
+	SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \
+			AD1836_DAC_R_VOL(x), 0, 0x3FF, 0)
+
+#define AD1836_DAC_SWITCH(x) \
+	SOC_DOUBLE("DAC" #x " Playback Switch", AD1836_DAC_CTRL2, \
+			AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1)
+
+#define AD1836_ADC_SWITCH(x) \
+	SOC_DOUBLE("ADC" #x " Capture Switch", AD1836_ADC_CTRL2, \
+		AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1)
+
+static const struct snd_kcontrol_new ad183x_dac_controls[] = {
+	AD1836_DAC_VOLUME(1),
+	AD1836_DAC_SWITCH(1),
+	AD1836_DAC_VOLUME(2),
+	AD1836_DAC_SWITCH(2),
+	AD1836_DAC_VOLUME(3),
+	AD1836_DAC_SWITCH(3),
+	AD1836_DAC_VOLUME(4),
+	AD1836_DAC_SWITCH(4),
+};
+
+static const struct snd_soc_dapm_widget ad183x_dac_dapm_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("DAC1OUT"),
+	SND_SOC_DAPM_OUTPUT("DAC2OUT"),
+	SND_SOC_DAPM_OUTPUT("DAC3OUT"),
+	SND_SOC_DAPM_OUTPUT("DAC4OUT"),
+};
+
+static const struct snd_soc_dapm_route ad183x_dac_routes[] = {
+	{ "DAC1OUT", NULL, "DAC" },
+	{ "DAC2OUT", NULL, "DAC" },
+	{ "DAC3OUT", NULL, "DAC" },
+	{ "DAC4OUT", NULL, "DAC" },
+};
+
+static const struct snd_kcontrol_new ad183x_adc_controls[] = {
+	AD1836_ADC_SWITCH(1),
+	AD1836_ADC_SWITCH(2),
+	AD1836_ADC_SWITCH(3),
+};
+
+static const struct snd_soc_dapm_widget ad183x_adc_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("ADC1IN"),
+	SND_SOC_DAPM_INPUT("ADC2IN"),
+};
+
+static const struct snd_soc_dapm_route ad183x_adc_routes[] = {
+	{ "ADC", NULL, "ADC1IN" },
+	{ "ADC", NULL, "ADC2IN" },
+};
+
+static const struct snd_kcontrol_new ad183x_controls[] = {
+	/* ADC high-pass filter */
+	SOC_SINGLE("ADC High Pass Filter Switch", AD1836_ADC_CTRL1,
+			AD1836_ADC_HIGHPASS_FILTER, 1, 0),
+
+	/* DAC de-emphasis */
+	SOC_ENUM("Playback Deemphasis", ad1836_deemp_enum),
+};
+
+static const struct snd_soc_dapm_widget ad183x_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", "Playback", AD1836_DAC_CTRL1,
+				AD1836_DAC_POWERDOWN, 1),
+	SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1836_ADC_CTRL1,
+				AD1836_ADC_POWERDOWN, 1, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route ad183x_dapm_routes[] = {
+	{ "DAC", NULL, "ADC_PWR" },
+	{ "ADC", NULL, "ADC_PWR" },
+};
+
+static const DECLARE_TLV_DB_SCALE(ad1836_in_tlv, 0, 300, 0);
+
+static const struct snd_kcontrol_new ad1836_controls[] = {
+	SOC_DOUBLE_TLV("ADC2 Capture Volume", AD1836_ADC_CTRL1, 3, 0, 4, 0,
+	    ad1836_in_tlv),
+};
+
+/*
+ * DAI ops entries
+ */
+
+static int ad1836_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	/* at present, we support adc aux mode to interface with
+	 * blackfin sport tdm mode
+	 */
+	case SND_SOC_DAIFMT_DSP_A:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_IF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	/* ALCLK,ABCLK are both output, AD1836 can only be master */
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ad1836_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct ad1836_priv *ad1836 = snd_soc_component_get_drvdata(dai->component);
+	int word_len = 0;
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		word_len = AD1836_WORD_LEN_16;
+		break;
+	case 20:
+		word_len = AD1836_WORD_LEN_20;
+		break;
+	case 24:
+	case 32:
+		word_len = AD1836_WORD_LEN_24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(ad1836->regmap, AD1836_DAC_CTRL1,
+		AD1836_DAC_WORD_LEN_MASK,
+		word_len << AD1836_DAC_WORD_LEN_OFFSET);
+
+	regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
+		AD1836_ADC_WORD_LEN_MASK,
+		word_len << AD1836_ADC_WORD_OFFSET);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops ad1836_dai_ops = {
+	.hw_params = ad1836_hw_params,
+	.set_fmt = ad1836_set_dai_fmt,
+};
+
+#define AD183X_DAI(_name, num_dacs, num_adcs) \
+{ \
+	.name = _name "-hifi", \
+	.playback = { \
+		.stream_name = "Playback", \
+		.channels_min = 2, \
+		.channels_max = (num_dacs) * 2, \
+		.rates = SNDRV_PCM_RATE_48000,  \
+		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \
+	}, \
+	.capture = { \
+		.stream_name = "Capture", \
+		.channels_min = 2, \
+		.channels_max = (num_adcs) * 2, \
+		.rates = SNDRV_PCM_RATE_48000, \
+		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \
+	}, \
+	.ops = &ad1836_dai_ops, \
+}
+
+static struct snd_soc_dai_driver ad183x_dais[] = {
+	[AD1835] = AD183X_DAI("ad1835", 4, 1),
+	[AD1836] = AD183X_DAI("ad1836", 3, 2),
+	[AD1838] = AD183X_DAI("ad1838", 3, 1),
+};
+
+#ifdef CONFIG_PM
+static int ad1836_suspend(struct snd_soc_component *component)
+{
+	struct ad1836_priv *ad1836 = snd_soc_component_get_drvdata(component);
+	/* reset clock control mode */
+	return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
+		AD1836_ADC_SERFMT_MASK, 0);
+}
+
+static int ad1836_resume(struct snd_soc_component *component)
+{
+	struct ad1836_priv *ad1836 = snd_soc_component_get_drvdata(component);
+	/* restore clock control mode */
+	return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
+		AD1836_ADC_SERFMT_MASK, AD1836_ADC_AUX);
+}
+#else
+#define ad1836_suspend NULL
+#define ad1836_resume  NULL
+#endif
+
+static int ad1836_probe(struct snd_soc_component *component)
+{
+	struct ad1836_priv *ad1836 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int num_dacs, num_adcs;
+	int ret = 0;
+	int i;
+
+	num_dacs = ad183x_dais[ad1836->type].playback.channels_max / 2;
+	num_adcs = ad183x_dais[ad1836->type].capture.channels_max / 2;
+
+	/* default setting for ad1836 */
+	/* de-emphasis: 48kHz, power-on dac */
+	regmap_write(ad1836->regmap, AD1836_DAC_CTRL1, 0x300);
+	/* unmute dac channels */
+	regmap_write(ad1836->regmap, AD1836_DAC_CTRL2, 0x0);
+	/* high-pass filter enable, power-on adc */
+	regmap_write(ad1836->regmap, AD1836_ADC_CTRL1, 0x100);
+	/* unmute adc channles, adc aux mode */
+	regmap_write(ad1836->regmap, AD1836_ADC_CTRL2, 0x180);
+	/* volume */
+	for (i = 1; i <= num_dacs; ++i) {
+		regmap_write(ad1836->regmap, AD1836_DAC_L_VOL(i), 0x3FF);
+		regmap_write(ad1836->regmap, AD1836_DAC_R_VOL(i), 0x3FF);
+	}
+
+	if (ad1836->type == AD1836) {
+		/* left/right diff:PGA/MUX */
+		regmap_write(ad1836->regmap, AD1836_ADC_CTRL3, 0x3A);
+		ret = snd_soc_add_component_controls(component, ad1836_controls,
+				ARRAY_SIZE(ad1836_controls));
+		if (ret)
+			return ret;
+	} else {
+		regmap_write(ad1836->regmap, AD1836_ADC_CTRL3, 0x00);
+	}
+
+	ret = snd_soc_add_component_controls(component, ad183x_dac_controls, num_dacs * 2);
+	if (ret)
+		return ret;
+
+	ret = snd_soc_add_component_controls(component, ad183x_adc_controls, num_adcs);
+	if (ret)
+		return ret;
+
+	ret = snd_soc_dapm_new_controls(dapm, ad183x_dac_dapm_widgets, num_dacs);
+	if (ret)
+		return ret;
+
+	ret = snd_soc_dapm_new_controls(dapm, ad183x_adc_dapm_widgets, num_adcs);
+	if (ret)
+		return ret;
+
+	ret = snd_soc_dapm_add_routes(dapm, ad183x_dac_routes, num_dacs);
+	if (ret)
+		return ret;
+
+	ret = snd_soc_dapm_add_routes(dapm, ad183x_adc_routes, num_adcs);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+/* power down chip */
+static void ad1836_remove(struct snd_soc_component *component)
+{
+	struct ad1836_priv *ad1836 = snd_soc_component_get_drvdata(component);
+	/* reset clock control mode */
+	regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
+		AD1836_ADC_SERFMT_MASK, 0);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_ad1836 = {
+	.probe			= ad1836_probe,
+	.remove			= ad1836_remove,
+	.suspend		= ad1836_suspend,
+	.resume			= ad1836_resume,
+	.controls		= ad183x_controls,
+	.num_controls		= ARRAY_SIZE(ad183x_controls),
+	.dapm_widgets		= ad183x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ad183x_dapm_widgets),
+	.dapm_routes		= ad183x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ad183x_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct reg_default ad1836_reg_defaults[] = {
+	{ AD1836_DAC_CTRL1, 0x0000 },
+	{ AD1836_DAC_CTRL2, 0x0000 },
+	{ AD1836_DAC_L_VOL(0), 0x0000 },
+	{ AD1836_DAC_R_VOL(0), 0x0000 },
+	{ AD1836_DAC_L_VOL(1), 0x0000 },
+	{ AD1836_DAC_R_VOL(1), 0x0000 },
+	{ AD1836_DAC_L_VOL(2), 0x0000 },
+	{ AD1836_DAC_R_VOL(2), 0x0000 },
+	{ AD1836_DAC_L_VOL(3), 0x0000 },
+	{ AD1836_DAC_R_VOL(3), 0x0000 },
+	{ AD1836_ADC_CTRL1, 0x0000 },
+	{ AD1836_ADC_CTRL2, 0x0000 },
+	{ AD1836_ADC_CTRL3, 0x0000 },
+};
+
+static const struct regmap_config ad1836_regmap_config = {
+	.val_bits = 12,
+	.reg_bits = 4,
+	.read_flag_mask = 0x08,
+
+	.max_register = AD1836_ADC_CTRL3,
+	.reg_defaults = ad1836_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ad1836_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int ad1836_spi_probe(struct spi_device *spi)
+{
+	struct ad1836_priv *ad1836;
+	int ret;
+
+	ad1836 = devm_kzalloc(&spi->dev, sizeof(struct ad1836_priv),
+			      GFP_KERNEL);
+	if (ad1836 == NULL)
+		return -ENOMEM;
+
+	ad1836->regmap = devm_regmap_init_spi(spi, &ad1836_regmap_config);
+	if (IS_ERR(ad1836->regmap))
+		return PTR_ERR(ad1836->regmap);
+
+	ad1836->type = spi_get_device_id(spi)->driver_data;
+
+	spi_set_drvdata(spi, ad1836);
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_ad1836, &ad183x_dais[ad1836->type], 1);
+	return ret;
+}
+
+static const struct spi_device_id ad1836_ids[] = {
+	{ "ad1835", AD1835 },
+	{ "ad1836", AD1836 },
+	{ "ad1837", AD1835 },
+	{ "ad1838", AD1838 },
+	{ "ad1839", AD1838 },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, ad1836_ids);
+
+static struct spi_driver ad1836_spi_driver = {
+	.driver = {
+		.name	= "ad1836",
+	},
+	.probe		= ad1836_spi_probe,
+	.id_table	= ad1836_ids,
+};
+
+module_spi_driver(ad1836_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ad1836 driver");
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad1836.h b/sound/soc/codecs/ad1836.h
new file mode 100644
index 0000000..dd7be0d
--- /dev/null
+++ b/sound/soc/codecs/ad1836.h
@@ -0,0 +1,51 @@
+/*
+ * Audio Codec driver supporting:
+ *  AD1835A, AD1836, AD1837A, AD1838A, AD1839A
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __AD1836_H__
+#define __AD1836_H__
+
+#define AD1836_DAC_CTRL1               0
+#define AD1836_DAC_POWERDOWN           2
+#define AD1836_DAC_SERFMT_MASK         0xE0
+#define AD1836_DAC_SERFMT_PCK256       (0x4 << 5)
+#define AD1836_DAC_SERFMT_PCK128       (0x5 << 5)
+#define AD1836_DAC_WORD_LEN_MASK       0x18
+#define AD1836_DAC_WORD_LEN_OFFSET     3
+
+#define AD1836_DAC_CTRL2               1
+
+/* These macros are one-based. So AD183X_MUTE_LEFT(1) will return the mute bit
+ * for the first ADC/DAC */
+#define AD1836_MUTE_LEFT(x) (((x) * 2) - 2)
+#define AD1836_MUTE_RIGHT(x) (((x) * 2) - 1)
+
+#define AD1836_DAC_L_VOL(x) ((x) * 2)
+#define AD1836_DAC_R_VOL(x) (1 + ((x) * 2))
+
+#define AD1836_ADC_CTRL1               12
+#define AD1836_ADC_POWERDOWN           7
+#define AD1836_ADC_HIGHPASS_FILTER     8
+
+#define AD1836_ADC_CTRL2               13
+#define AD1836_ADC_WORD_LEN_MASK       0x30
+#define AD1836_ADC_WORD_OFFSET         4
+#define AD1836_ADC_SERFMT_MASK         (7 << 6)
+#define AD1836_ADC_SERFMT_PCK256       (0x4 << 6)
+#define AD1836_ADC_SERFMT_PCK128       (0x5 << 6)
+#define AD1836_ADC_AUX                 (0x6 << 6)
+
+#define AD1836_ADC_CTRL3               14
+
+#define AD1836_NUM_REGS                16
+
+#define AD1836_WORD_LEN_24 0x0
+#define AD1836_WORD_LEN_20 0x1
+#define AD1836_WORD_LEN_16 0x2
+
+#endif
diff --git a/sound/soc/codecs/ad193x-i2c.c b/sound/soc/codecs/ad193x-i2c.c
new file mode 100644
index 0000000..b955133
--- /dev/null
+++ b/sound/soc/codecs/ad193x-i2c.c
@@ -0,0 +1,49 @@
+/*
+ * AD1936/AD1937 audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "ad193x.h"
+
+static const struct i2c_device_id ad193x_id[] = {
+	{ "ad1936", AD193X },
+	{ "ad1937", AD193X },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ad193x_id);
+
+static int ad193x_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct regmap_config config;
+
+	config = ad193x_regmap_config;
+	config.val_bits = 8;
+	config.reg_bits = 8;
+
+	return ad193x_probe(&client->dev,
+			    devm_regmap_init_i2c(client, &config),
+			    (enum ad193x_type)id->driver_data);
+}
+
+static struct i2c_driver ad193x_i2c_driver = {
+	.driver = {
+		.name = "ad193x",
+	},
+	.probe    = ad193x_i2c_probe,
+	.id_table = ad193x_id,
+};
+module_i2c_driver(ad193x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC AD1936/AD1937 audio CODEC driver");
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad193x-spi.c b/sound/soc/codecs/ad193x-spi.c
new file mode 100644
index 0000000..3c1394a
--- /dev/null
+++ b/sound/soc/codecs/ad193x-spi.c
@@ -0,0 +1,54 @@
+/*
+ * AD1938/AD1939 audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "ad193x.h"
+
+static int ad193x_spi_probe(struct spi_device *spi)
+{
+	const struct spi_device_id *id = spi_get_device_id(spi);
+	struct regmap_config config;
+
+	config = ad193x_regmap_config;
+	config.val_bits = 8;
+	config.reg_bits = 16;
+	config.read_flag_mask = 0x09;
+	config.write_flag_mask = 0x08;
+
+	return ad193x_probe(&spi->dev, devm_regmap_init_spi(spi, &config),
+			    (enum ad193x_type)id->driver_data);
+}
+
+static const struct spi_device_id ad193x_spi_id[] = {
+	{ "ad193x", AD193X },
+	{ "ad1933", AD1933 },
+	{ "ad1934", AD1934 },
+	{ "ad1938", AD193X },
+	{ "ad1939", AD193X },
+	{ "adau1328", AD193X },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, ad193x_spi_id);
+
+static struct spi_driver ad193x_spi_driver = {
+	.driver = {
+		.name	= "ad193x",
+	},
+	.probe		= ad193x_spi_probe,
+	.id_table	= ad193x_spi_id,
+};
+module_spi_driver(ad193x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC AD1938/AD1939 audio CODEC driver");
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
new file mode 100644
index 0000000..4b60ebe
--- /dev/null
+++ b/sound/soc/codecs/ad193x.c
@@ -0,0 +1,454 @@
+/*
+ * AD193X Audio Codec driver supporting AD1936/7/8/9
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "ad193x.h"
+
+/* codec private data */
+struct ad193x_priv {
+	struct regmap *regmap;
+	enum ad193x_type type;
+	int sysclk;
+};
+
+/*
+ * AD193X volume/mute/de-emphasis etc. controls
+ */
+static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"};
+
+static SOC_ENUM_SINGLE_DECL(ad193x_deemp_enum, AD193X_DAC_CTRL2, 1,
+			    ad193x_deemp);
+
+static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0);
+
+static const struct snd_kcontrol_new ad193x_snd_controls[] = {
+	/* DAC volume control */
+	SOC_DOUBLE_R_TLV("DAC1 Volume", AD193X_DAC_L1_VOL,
+			AD193X_DAC_R1_VOL, 0, 0xFF, 1, adau193x_tlv),
+	SOC_DOUBLE_R_TLV("DAC2 Volume", AD193X_DAC_L2_VOL,
+			AD193X_DAC_R2_VOL, 0, 0xFF, 1, adau193x_tlv),
+	SOC_DOUBLE_R_TLV("DAC3 Volume", AD193X_DAC_L3_VOL,
+			AD193X_DAC_R3_VOL, 0, 0xFF, 1, adau193x_tlv),
+	SOC_DOUBLE_R_TLV("DAC4 Volume", AD193X_DAC_L4_VOL,
+			AD193X_DAC_R4_VOL, 0, 0xFF, 1, adau193x_tlv),
+
+	/* DAC switch control */
+	SOC_DOUBLE("DAC1 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL1_MUTE,
+		AD193X_DACR1_MUTE, 1, 1),
+	SOC_DOUBLE("DAC2 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL2_MUTE,
+		AD193X_DACR2_MUTE, 1, 1),
+	SOC_DOUBLE("DAC3 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL3_MUTE,
+		AD193X_DACR3_MUTE, 1, 1),
+	SOC_DOUBLE("DAC4 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL4_MUTE,
+		AD193X_DACR4_MUTE, 1, 1),
+
+	/* DAC de-emphasis */
+	SOC_ENUM("Playback Deemphasis", ad193x_deemp_enum),
+};
+
+static const struct snd_kcontrol_new ad193x_adc_snd_controls[] = {
+	/* ADC switch control */
+	SOC_DOUBLE("ADC1 Switch", AD193X_ADC_CTRL0, AD193X_ADCL1_MUTE,
+		AD193X_ADCR1_MUTE, 1, 1),
+	SOC_DOUBLE("ADC2 Switch", AD193X_ADC_CTRL0, AD193X_ADCL2_MUTE,
+		AD193X_ADCR2_MUTE, 1, 1),
+
+	/* ADC high-pass filter */
+	SOC_SINGLE("ADC High Pass Filter Switch", AD193X_ADC_CTRL0,
+			AD193X_ADC_HIGHPASS_FILTER, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_PGA("DAC Output", AD193X_DAC_CTRL0, 0, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0),
+	SND_SOC_DAPM_VMID("VMID"),
+	SND_SOC_DAPM_OUTPUT("DAC1OUT"),
+	SND_SOC_DAPM_OUTPUT("DAC2OUT"),
+	SND_SOC_DAPM_OUTPUT("DAC3OUT"),
+	SND_SOC_DAPM_OUTPUT("DAC4OUT"),
+};
+
+static const struct snd_soc_dapm_widget ad193x_adc_widgets[] = {
+	SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0),
+	SND_SOC_DAPM_INPUT("ADC1IN"),
+	SND_SOC_DAPM_INPUT("ADC2IN"),
+};
+
+static const struct snd_soc_dapm_route audio_paths[] = {
+	{ "DAC", NULL, "SYSCLK" },
+	{ "DAC Output", NULL, "DAC" },
+	{ "DAC Output", NULL, "VMID" },
+	{ "DAC1OUT", NULL, "DAC Output" },
+	{ "DAC2OUT", NULL, "DAC Output" },
+	{ "DAC3OUT", NULL, "DAC Output" },
+	{ "DAC4OUT", NULL, "DAC Output" },
+	{ "SYSCLK", NULL, "PLL_PWR" },
+};
+
+static const struct snd_soc_dapm_route ad193x_adc_audio_paths[] = {
+	{ "ADC", NULL, "SYSCLK" },
+	{ "ADC", NULL, "ADC_PWR" },
+	{ "ADC", NULL, "ADC1IN" },
+	{ "ADC", NULL, "ADC2IN" },
+};
+
+static inline bool ad193x_has_adc(const struct ad193x_priv *ad193x)
+{
+	switch (ad193x->type) {
+	case AD1933:
+	case AD1934:
+		return false;
+	default:
+		break;
+	}
+
+	return true;
+}
+
+/*
+ * DAI ops entries
+ */
+
+static int ad193x_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(dai->component);
+
+	if (mute)
+		regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,
+				    AD193X_DAC_MASTER_MUTE,
+				    AD193X_DAC_MASTER_MUTE);
+	else
+		regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,
+				    AD193X_DAC_MASTER_MUTE, 0);
+
+	return 0;
+}
+
+static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			       unsigned int rx_mask, int slots, int width)
+{
+	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(dai->component);
+	unsigned int channels;
+
+	switch (slots) {
+	case 2:
+		channels = AD193X_2_CHANNELS;
+		break;
+	case 4:
+		channels = AD193X_4_CHANNELS;
+		break;
+	case 8:
+		channels = AD193X_8_CHANNELS;
+		break;
+	case 16:
+		channels = AD193X_16_CHANNELS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1,
+		AD193X_DAC_CHAN_MASK, channels << AD193X_DAC_CHAN_SHFT);
+	if (ad193x_has_adc(ad193x))
+		regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2,
+				   AD193X_ADC_CHAN_MASK,
+				   channels << AD193X_ADC_CHAN_SHFT);
+
+	return 0;
+}
+
+static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(codec_dai->component);
+	unsigned int adc_serfmt = 0;
+	unsigned int adc_fmt = 0;
+	unsigned int dac_fmt = 0;
+
+	/* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S
+	 * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A)
+	 */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		adc_serfmt |= AD193X_ADC_SERFMT_TDM;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		adc_serfmt |= AD193X_ADC_SERFMT_AUX;
+		break;
+	default:
+		if (ad193x_has_adc(ad193x))
+			return -EINVAL;
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
+		break;
+	case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */
+		adc_fmt |= AD193X_ADC_LEFT_HIGH;
+		dac_fmt |= AD193X_DAC_LEFT_HIGH;
+		break;
+	case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */
+		adc_fmt |= AD193X_ADC_BCLK_INV;
+		dac_fmt |= AD193X_DAC_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */
+		adc_fmt |= AD193X_ADC_LEFT_HIGH;
+		adc_fmt |= AD193X_ADC_BCLK_INV;
+		dac_fmt |= AD193X_DAC_LEFT_HIGH;
+		dac_fmt |= AD193X_DAC_BCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */
+		adc_fmt |= AD193X_ADC_LCR_MASTER;
+		adc_fmt |= AD193X_ADC_BCLK_MASTER;
+		dac_fmt |= AD193X_DAC_LCR_MASTER;
+		dac_fmt |= AD193X_DAC_BCLK_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */
+		adc_fmt |= AD193X_ADC_LCR_MASTER;
+		dac_fmt |= AD193X_DAC_LCR_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
+		adc_fmt |= AD193X_ADC_BCLK_MASTER;
+		dac_fmt |= AD193X_DAC_BCLK_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (ad193x_has_adc(ad193x)) {
+		regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1,
+				   AD193X_ADC_SERFMT_MASK, adc_serfmt);
+		regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2,
+				   AD193X_ADC_FMT_MASK, adc_fmt);
+	}
+	regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1,
+		AD193X_DAC_FMT_MASK, dac_fmt);
+
+	return 0;
+}
+
+static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
+	switch (freq) {
+	case 12288000:
+	case 18432000:
+	case 24576000:
+	case 36864000:
+		ad193x->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int ad193x_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	int word_len = 0, master_rate = 0;
+	struct snd_soc_component *component = dai->component;
+	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		word_len = 3;
+		break;
+	case 20:
+		word_len = 1;
+		break;
+	case 24:
+	case 32:
+		word_len = 0;
+		break;
+	}
+
+	switch (ad193x->sysclk) {
+	case 12288000:
+		master_rate = AD193X_PLL_INPUT_256;
+		break;
+	case 18432000:
+		master_rate = AD193X_PLL_INPUT_384;
+		break;
+	case 24576000:
+		master_rate = AD193X_PLL_INPUT_512;
+		break;
+	case 36864000:
+		master_rate = AD193X_PLL_INPUT_768;
+		break;
+	}
+
+	regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL0,
+			    AD193X_PLL_INPUT_MASK, master_rate);
+
+	regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,
+			    AD193X_DAC_WORD_LEN_MASK,
+			    word_len << AD193X_DAC_WORD_LEN_SHFT);
+
+	if (ad193x_has_adc(ad193x))
+		regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1,
+				   AD193X_ADC_WORD_LEN_MASK, word_len);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops ad193x_dai_ops = {
+	.hw_params = ad193x_hw_params,
+	.digital_mute = ad193x_mute,
+	.set_tdm_slot = ad193x_set_tdm_slot,
+	.set_sysclk	= ad193x_set_dai_sysclk,
+	.set_fmt = ad193x_set_dai_fmt,
+};
+
+/* codec DAI instance */
+static struct snd_soc_dai_driver ad193x_dai = {
+	.name = "ad193x-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 4,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+	.ops = &ad193x_dai_ops,
+};
+
+static int ad193x_component_probe(struct snd_soc_component *component)
+{
+	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int num, ret;
+
+	/* default setting for ad193x */
+
+	/* unmute dac channels */
+	regmap_write(ad193x->regmap, AD193X_DAC_CHNL_MUTE, 0x0);
+	/* de-emphasis: 48kHz, powedown dac */
+	regmap_write(ad193x->regmap, AD193X_DAC_CTRL2, 0x1A);
+	/* dac in tdm mode */
+	regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x40);
+
+	/* adc only */
+	if (ad193x_has_adc(ad193x)) {
+		/* high-pass filter enable */
+		regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3);
+		/* sata delay=1, adc aux mode */
+		regmap_write(ad193x->regmap, AD193X_ADC_CTRL1, 0x43);
+	}
+
+	/* pll input: mclki/xi */
+	regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
+	regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL1, 0x04);
+
+	/* adc only */
+	if (ad193x_has_adc(ad193x)) {
+		/* add adc controls */
+		num = ARRAY_SIZE(ad193x_adc_snd_controls);
+		ret = snd_soc_add_component_controls(component,
+						 ad193x_adc_snd_controls,
+						 num);
+		if (ret)
+			return ret;
+
+		/* add adc widgets */
+		num = ARRAY_SIZE(ad193x_adc_widgets);
+		ret = snd_soc_dapm_new_controls(dapm,
+						ad193x_adc_widgets,
+						num);
+		if (ret)
+			return ret;
+
+		/* add adc routes */
+		num = ARRAY_SIZE(ad193x_adc_audio_paths);
+		ret = snd_soc_dapm_add_routes(dapm,
+					      ad193x_adc_audio_paths,
+					      num);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_ad193x = {
+	.probe			= ad193x_component_probe,
+	.controls		= ad193x_snd_controls,
+	.num_controls		= ARRAY_SIZE(ad193x_snd_controls),
+	.dapm_widgets		= ad193x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ad193x_dapm_widgets),
+	.dapm_routes		= audio_paths,
+	.num_dapm_routes	= ARRAY_SIZE(audio_paths),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+const struct regmap_config ad193x_regmap_config = {
+	.max_register = AD193X_NUM_REGS - 1,
+};
+EXPORT_SYMBOL_GPL(ad193x_regmap_config);
+
+int ad193x_probe(struct device *dev, struct regmap *regmap,
+		 enum ad193x_type type)
+{
+	struct ad193x_priv *ad193x;
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	ad193x = devm_kzalloc(dev, sizeof(*ad193x), GFP_KERNEL);
+	if (ad193x == NULL)
+		return -ENOMEM;
+
+	ad193x->regmap = regmap;
+	ad193x->type = type;
+
+	dev_set_drvdata(dev, ad193x);
+
+	return devm_snd_soc_register_component(dev, &soc_component_dev_ad193x,
+		&ad193x_dai, 1);
+}
+EXPORT_SYMBOL_GPL(ad193x_probe);
+
+MODULE_DESCRIPTION("ASoC ad193x driver");
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h
new file mode 100644
index 0000000..8b1e65f
--- /dev/null
+++ b/sound/soc/codecs/ad193x.h
@@ -0,0 +1,99 @@
+/*
+ * AD193X Audio Codec driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __AD193X_H__
+#define __AD193X_H__
+
+#include <linux/regmap.h>
+
+struct device;
+
+enum ad193x_type {
+	AD193X,
+	AD1933,
+	AD1934,
+};
+
+extern const struct regmap_config ad193x_regmap_config;
+int ad193x_probe(struct device *dev, struct regmap *regmap,
+		 enum ad193x_type type);
+
+#define AD193X_PLL_CLK_CTRL0    0x00
+#define AD193X_PLL_POWERDOWN           0x01
+#define AD193X_PLL_INPUT_MASK   0x6
+#define AD193X_PLL_INPUT_256    (0 << 1)
+#define AD193X_PLL_INPUT_384    (1 << 1)
+#define AD193X_PLL_INPUT_512    (2 << 1)
+#define AD193X_PLL_INPUT_768    (3 << 1)
+#define AD193X_PLL_CLK_CTRL1    0x01
+#define AD193X_DAC_CTRL0        0x02
+#define AD193X_DAC_POWERDOWN           0x01
+#define AD193X_DAC_SERFMT_MASK		0xC0
+#define AD193X_DAC_SERFMT_STEREO	(0 << 6)
+#define AD193X_DAC_SERFMT_TDM		(1 << 6)
+#define AD193X_DAC_CTRL1        0x03
+#define AD193X_DAC_CHAN_SHFT    1
+#define AD193X_DAC_CHAN_MASK    (3 << AD193X_DAC_CHAN_SHFT)
+#define AD193X_DAC_LCR_MASTER   (1 << 4)
+#define AD193X_DAC_BCLK_MASTER  (1 << 5)
+#define AD193X_DAC_LEFT_HIGH    (1 << 3)
+#define AD193X_DAC_BCLK_INV     (1 << 7)
+#define AD193X_DAC_FMT_MASK	(AD193X_DAC_LCR_MASTER | \
+	AD193X_DAC_BCLK_MASTER | AD193X_DAC_LEFT_HIGH | AD193X_DAC_BCLK_INV)
+#define AD193X_DAC_CTRL2        0x04
+#define AD193X_DAC_WORD_LEN_SHFT        3
+#define AD193X_DAC_WORD_LEN_MASK        0x18
+#define AD193X_DAC_MASTER_MUTE  1
+#define AD193X_DAC_CHNL_MUTE    0x05
+#define AD193X_DACL1_MUTE       0
+#define AD193X_DACR1_MUTE       1
+#define AD193X_DACL2_MUTE       2
+#define AD193X_DACR2_MUTE       3
+#define AD193X_DACL3_MUTE       4
+#define AD193X_DACR3_MUTE       5
+#define AD193X_DACL4_MUTE       6
+#define AD193X_DACR4_MUTE       7
+#define AD193X_DAC_L1_VOL       0x06
+#define AD193X_DAC_R1_VOL       0x07
+#define AD193X_DAC_L2_VOL       0x08
+#define AD193X_DAC_R2_VOL       0x09
+#define AD193X_DAC_L3_VOL       0x0a
+#define AD193X_DAC_R3_VOL       0x0b
+#define AD193X_DAC_L4_VOL       0x0c
+#define AD193X_DAC_R4_VOL       0x0d
+#define AD193X_ADC_CTRL0        0x0e
+#define AD193X_ADC_POWERDOWN           0x01
+#define AD193X_ADC_HIGHPASS_FILTER	1
+#define AD193X_ADCL1_MUTE 		2
+#define AD193X_ADCR1_MUTE 		3
+#define AD193X_ADCL2_MUTE 		4
+#define AD193X_ADCR2_MUTE 		5
+#define AD193X_ADC_CTRL1        0x0f
+#define AD193X_ADC_SERFMT_MASK		0x60
+#define AD193X_ADC_SERFMT_STEREO	(0 << 5)
+#define AD193X_ADC_SERFMT_TDM		(1 << 5)
+#define AD193X_ADC_SERFMT_AUX		(2 << 5)
+#define AD193X_ADC_WORD_LEN_MASK	0x3
+#define AD193X_ADC_CTRL2        0x10
+#define AD193X_ADC_CHAN_SHFT    4
+#define AD193X_ADC_CHAN_MASK    (3 << AD193X_ADC_CHAN_SHFT)
+#define AD193X_ADC_LCR_MASTER   (1 << 3)
+#define AD193X_ADC_BCLK_MASTER  (1 << 6)
+#define AD193X_ADC_LEFT_HIGH    (1 << 2)
+#define AD193X_ADC_BCLK_INV     (1 << 1)
+#define AD193X_ADC_FMT_MASK	(AD193X_ADC_LCR_MASTER | \
+	AD193X_ADC_BCLK_MASTER | AD193X_ADC_LEFT_HIGH | AD193X_ADC_BCLK_INV)
+
+#define AD193X_2_CHANNELS   0
+#define AD193X_4_CHANNELS   1
+#define AD193X_8_CHANNELS   2
+#define AD193X_16_CHANNELS  3
+
+#define AD193X_NUM_REGS          17
+
+#endif
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
new file mode 100644
index 0000000..16dab3f
--- /dev/null
+++ b/sound/soc/codecs/ad1980.c
@@ -0,0 +1,330 @@
+/*
+ * ad1980.c  --  ALSA Soc AD1980 codec support
+ *
+ * Copyright:	Analog Device Inc.
+ * Author:	Roy Huang <roy.huang@analog.com>
+ * 		Cliff Cai <cliff.cai@analog.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+/*
+ * WARNING:
+ *
+ * Because Analog Devices Inc. discontinued the ad1980 sound chip since
+ * Sep. 2009, this ad1980 driver is not maintained, tested and supported
+ * by ADI now.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+static const struct reg_default ad1980_reg_defaults[] = {
+	{ 0x02, 0x8000 },
+	{ 0x04, 0x8000 },
+	{ 0x06, 0x8000 },
+	{ 0x0c, 0x8008 },
+	{ 0x0e, 0x8008 },
+	{ 0x10, 0x8808 },
+	{ 0x12, 0x8808 },
+	{ 0x16, 0x8808 },
+	{ 0x18, 0x8808 },
+	{ 0x1a, 0x0000 },
+	{ 0x1c, 0x8000 },
+	{ 0x20, 0x0000 },
+	{ 0x28, 0x03c7 },
+	{ 0x2c, 0xbb80 },
+	{ 0x2e, 0xbb80 },
+	{ 0x30, 0xbb80 },
+	{ 0x32, 0xbb80 },
+	{ 0x36, 0x8080 },
+	{ 0x38, 0x8080 },
+	{ 0x3a, 0x2000 },
+	{ 0x60, 0x0000 },
+	{ 0x62, 0x0000 },
+	{ 0x72, 0x0000 },
+	{ 0x74, 0x1001 },
+	{ 0x76, 0x0000 },
+};
+
+static bool ad1980_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AC97_RESET ... AC97_MASTER_MONO:
+	case AC97_PHONE ... AC97_CD:
+	case AC97_AUX ... AC97_GENERAL_PURPOSE:
+	case AC97_POWERDOWN ... AC97_PCM_LR_ADC_RATE:
+	case AC97_SPDIF:
+	case AC97_CODEC_CLASS_REV:
+	case AC97_PCI_SVID:
+	case AC97_AD_CODEC_CFG:
+	case AC97_AD_JACK_SPDIF:
+	case AC97_AD_SERIAL_CFG:
+	case AC97_VENDOR_ID1:
+	case AC97_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool ad1980_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AC97_VENDOR_ID1:
+	case AC97_VENDOR_ID2:
+		return false;
+	default:
+		return ad1980_readable_reg(dev, reg);
+	}
+}
+
+static const struct regmap_config ad1980_regmap_config = {
+	.reg_bits = 16,
+	.reg_stride = 2,
+	.val_bits = 16,
+	.max_register = 0x7e,
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = regmap_ac97_default_volatile,
+	.readable_reg = ad1980_readable_reg,
+	.writeable_reg = ad1980_writeable_reg,
+
+	.reg_defaults = ad1980_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ad1980_reg_defaults),
+};
+
+static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line",
+		"Stereo Mix", "Mono Mix", "Phone"};
+
+static SOC_ENUM_DOUBLE_DECL(ad1980_cap_src,
+			    AC97_REC_SEL, 8, 0, ad1980_rec_sel);
+
+static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = {
+SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1),
+SOC_SINGLE("Master Playback Switch", AC97_MASTER, 15, 1, 1),
+
+SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
+SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1),
+
+SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1),
+SOC_SINGLE("PCM Playback Switch", AC97_PCM, 15, 1, 1),
+
+SOC_DOUBLE("PCM Capture Volume", AC97_REC_GAIN, 8, 0, 31, 0),
+SOC_SINGLE("PCM Capture Switch", AC97_REC_GAIN, 15, 1, 1),
+
+SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1),
+SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
+
+SOC_SINGLE("Phone Capture Volume", AC97_PHONE, 0, 31, 1),
+SOC_SINGLE("Phone Capture Switch", AC97_PHONE, 15, 1, 1),
+
+SOC_SINGLE("Mic Volume", AC97_MIC, 0, 31, 1),
+SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1),
+
+SOC_SINGLE("Stereo Mic Switch", AC97_AD_MISC, 6, 1, 0),
+SOC_DOUBLE("Line HP Swap Switch", AC97_AD_MISC, 10, 5, 1, 0),
+
+SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1),
+SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1),
+
+SOC_DOUBLE("Center/LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 0, 31, 1),
+SOC_DOUBLE("Center/LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 7, 1, 1),
+
+SOC_ENUM("Capture Source", ad1980_cap_src),
+
+SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget ad1980_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2"),
+SND_SOC_DAPM_INPUT("CD_L"),
+SND_SOC_DAPM_INPUT("CD_R"),
+SND_SOC_DAPM_INPUT("AUX_L"),
+SND_SOC_DAPM_INPUT("AUX_R"),
+SND_SOC_DAPM_INPUT("LINE_IN_L"),
+SND_SOC_DAPM_INPUT("LINE_IN_R"),
+
+SND_SOC_DAPM_OUTPUT("LFE_OUT"),
+SND_SOC_DAPM_OUTPUT("CENTER_OUT"),
+SND_SOC_DAPM_OUTPUT("LINE_OUT_L"),
+SND_SOC_DAPM_OUTPUT("LINE_OUT_R"),
+SND_SOC_DAPM_OUTPUT("MONO_OUT"),
+SND_SOC_DAPM_OUTPUT("HP_OUT_L"),
+SND_SOC_DAPM_OUTPUT("HP_OUT_R"),
+};
+
+static const struct snd_soc_dapm_route ad1980_dapm_routes[] = {
+	{ "Capture", NULL, "MIC1" },
+	{ "Capture", NULL, "MIC2" },
+	{ "Capture", NULL, "CD_L" },
+	{ "Capture", NULL, "CD_R" },
+	{ "Capture", NULL, "AUX_L" },
+	{ "Capture", NULL, "AUX_R" },
+	{ "Capture", NULL, "LINE_IN_L" },
+	{ "Capture", NULL, "LINE_IN_R" },
+
+	{ "LFE_OUT", NULL, "Playback" },
+	{ "CENTER_OUT", NULL, "Playback" },
+	{ "LINE_OUT_L", NULL, "Playback" },
+	{ "LINE_OUT_R", NULL, "Playback" },
+	{ "MONO_OUT", NULL, "Playback" },
+	{ "HP_OUT_L", NULL, "Playback" },
+	{ "HP_OUT_R", NULL, "Playback" },
+};
+
+static struct snd_soc_dai_driver ad1980_dai = {
+	.name = "ad1980-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 6,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SND_SOC_STD_AC97_FMTS, },
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SND_SOC_STD_AC97_FMTS, },
+};
+
+#define AD1980_VENDOR_ID 0x41445300
+#define AD1980_VENDOR_MASK 0xffffff00
+
+static int ad1980_reset(struct snd_soc_component *component, int try_warm)
+{
+	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
+	unsigned int retry_cnt = 0;
+	int ret;
+
+	do {
+		ret = snd_ac97_reset(ac97, true, AD1980_VENDOR_ID,
+			AD1980_VENDOR_MASK);
+		if (ret >= 0)
+			return 0;
+
+		/*
+		 * Set bit 16slot in register 74h, then every slot will has only
+		 * 16 bits. This command is sent out in 20bit mode, in which
+		 * case the first nibble of data is eaten by the addr. (Tag is
+		 * always 16 bit)
+		 */
+		snd_soc_component_write(component, AC97_AD_SERIAL_CFG, 0x9900);
+
+	} while (retry_cnt++ < 10);
+
+	dev_err(component->dev, "Failed to reset: AC97 link error\n");
+
+	return -EIO;
+}
+
+static int ad1980_soc_probe(struct snd_soc_component *component)
+{
+	struct snd_ac97 *ac97;
+	struct regmap *regmap;
+	int ret;
+	u16 vendor_id2;
+	u16 ext_status;
+
+	ac97 = snd_soc_new_ac97_component(component, 0, 0);
+	if (IS_ERR(ac97)) {
+		ret = PTR_ERR(ac97);
+		dev_err(component->dev, "Failed to register AC97 component: %d\n", ret);
+		return ret;
+	}
+
+	regmap = regmap_init_ac97(ac97, &ad1980_regmap_config);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		goto err_free_ac97;
+	}
+
+	snd_soc_component_init_regmap(component, regmap);
+	snd_soc_component_set_drvdata(component, ac97);
+
+	ret = ad1980_reset(component, 0);
+	if (ret < 0)
+		goto reset_err;
+
+	vendor_id2 = snd_soc_component_read32(component, AC97_VENDOR_ID2);
+	if (vendor_id2 == 0x5374) {
+		dev_warn(component->dev,
+			"Found AD1981 - only 2/2 IN/OUT Channels supported\n");
+	}
+
+	/* unmute captures and playbacks volume */
+	snd_soc_component_write(component, AC97_MASTER, 0x0000);
+	snd_soc_component_write(component, AC97_PCM, 0x0000);
+	snd_soc_component_write(component, AC97_REC_GAIN, 0x0000);
+	snd_soc_component_write(component, AC97_CENTER_LFE_MASTER, 0x0000);
+	snd_soc_component_write(component, AC97_SURROUND_MASTER, 0x0000);
+
+	/*power on LFE/CENTER/Surround DACs*/
+	ext_status = snd_soc_component_read32(component, AC97_EXTENDED_STATUS);
+	snd_soc_component_write(component, AC97_EXTENDED_STATUS, ext_status&~0x3800);
+
+	return 0;
+
+reset_err:
+	snd_soc_component_exit_regmap(component);
+err_free_ac97:
+	snd_soc_free_ac97_component(ac97);
+	return ret;
+}
+
+static void ad1980_soc_remove(struct snd_soc_component *component)
+{
+	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_exit_regmap(component);
+	snd_soc_free_ac97_component(ac97);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_ad1980 = {
+	.probe			= ad1980_soc_probe,
+	.remove			= ad1980_soc_remove,
+	.controls		= ad1980_snd_ac97_controls,
+	.num_controls		= ARRAY_SIZE(ad1980_snd_ac97_controls),
+	.dapm_widgets		= ad1980_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ad1980_dapm_widgets),
+	.dapm_routes		= ad1980_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ad1980_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int ad1980_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_ad1980, &ad1980_dai, 1);
+}
+
+static struct platform_driver ad1980_codec_driver = {
+	.driver = {
+			.name = "ad1980",
+	},
+
+	.probe = ad1980_probe,
+};
+
+module_platform_driver(ad1980_codec_driver);
+
+MODULE_DESCRIPTION("ASoC ad1980 driver (Obsolete)");
+MODULE_AUTHOR("Roy Huang, Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
new file mode 100644
index 0000000..03ee571
--- /dev/null
+++ b/sound/soc/codecs/ad73311.c
@@ -0,0 +1,86 @@
+/*
+ * ad73311.c  --  ALSA Soc AD73311 codec support
+ *
+ * Copyright:	Analog Device Inc.
+ * Author:	Cliff Cai <cliff.cai@analog.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "ad73311.h"
+
+static const struct snd_soc_dapm_widget ad73311_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("VINP"),
+SND_SOC_DAPM_INPUT("VINN"),
+SND_SOC_DAPM_OUTPUT("VOUTN"),
+SND_SOC_DAPM_OUTPUT("VOUTP"),
+};
+
+static const struct snd_soc_dapm_route ad73311_dapm_routes[] = {
+	{ "Capture", NULL, "VINP" },
+	{ "Capture", NULL, "VINN" },
+
+	{ "VOUTN", NULL, "Playback" },
+	{ "VOUTP", NULL, "Playback" },
+};
+
+static struct snd_soc_dai_driver ad73311_dai = {
+	.name = "ad73311-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+
+static const struct snd_soc_component_driver soc_component_dev_ad73311 = {
+	.dapm_widgets		= ad73311_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ad73311_dapm_widgets),
+	.dapm_routes		= ad73311_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ad73311_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int ad73311_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_ad73311, &ad73311_dai, 1);
+}
+
+static struct platform_driver ad73311_codec_driver = {
+	.driver = {
+			.name = "ad73311",
+	},
+
+	.probe = ad73311_probe,
+};
+
+module_platform_driver(ad73311_codec_driver);
+
+MODULE_DESCRIPTION("ASoC ad73311 driver");
+MODULE_AUTHOR("Cliff Cai ");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad73311.h b/sound/soc/codecs/ad73311.h
new file mode 100644
index 0000000..4b353ee
--- /dev/null
+++ b/sound/soc/codecs/ad73311.h
@@ -0,0 +1,88 @@
+/*
+ * File:         sound/soc/codec/ad73311.h
+ * Based on:
+ * Author:       Cliff Cai <cliff.cai@analog.com>
+ *
+ * Created:      Thur Sep 25, 2008
+ * Description:  definitions for AD73311 registers
+ *
+ *
+ * Modified:
+ *               Copyright 2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __AD73311_H__
+#define __AD73311_H__
+
+#define AD_CONTROL	0x8000
+#define AD_DATA		0x0000
+#define AD_READ		0x4000
+#define AD_WRITE	0x0000
+
+/* Control register A */
+#define CTRL_REG_A	(0 << 8)
+
+#define REGA_MODE_PRO	0x00
+#define REGA_MODE_DATA	0x01
+#define REGA_MODE_MIXED	0x03
+#define REGA_DLB		0x04
+#define REGA_SLB		0x08
+#define REGA_DEVC(x)		((x & 0x7) << 4)
+#define REGA_RESET		0x80
+
+/* Control register B */
+#define CTRL_REG_B	(1 << 8)
+
+#define REGB_DIRATE(x)	(x & 0x3)
+#define REGB_SCDIV(x)	((x & 0x3) << 2)
+#define REGB_MCDIV(x)	((x & 0x7) << 4)
+#define REGB_CEE		(1 << 7)
+
+/* Control register C */
+#define CTRL_REG_C	(2 << 8)
+
+#define REGC_PUDEV		(1 << 0)
+#define REGC_PUADC		(1 << 3)
+#define REGC_PUDAC		(1 << 4)
+#define REGC_PUREF		(1 << 5)
+#define REGC_REFUSE		(1 << 6)
+
+/* Control register D */
+#define CTRL_REG_D	(3 << 8)
+
+#define REGD_IGS(x)		(x & 0x7)
+#define REGD_RMOD		(1 << 3)
+#define REGD_OGS(x)		((x & 0x7) << 4)
+#define REGD_MUTE		(1 << 7)
+
+/* Control register E */
+#define CTRL_REG_E	(4 << 8)
+
+#define REGE_DA(x)		(x & 0x1f)
+#define REGE_IBYP		(1 << 5)
+
+/* Control register F */
+#define CTRL_REG_F	(5 << 8)
+
+#define REGF_SEEN		(1 << 5)
+#define REGF_INV		(1 << 6)
+#define REGF_ALB		(1 << 7)
+
+#endif
diff --git a/sound/soc/codecs/adau-utils.c b/sound/soc/codecs/adau-utils.c
new file mode 100644
index 0000000..19d6a6f
--- /dev/null
+++ b/sound/soc/codecs/adau-utils.c
@@ -0,0 +1,61 @@
+/*
+ * Shared helper functions for devices from the ADAU family
+ *
+ * Copyright 2011-2016 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/gcd.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "adau-utils.h"
+
+int adau_calc_pll_cfg(unsigned int freq_in, unsigned int freq_out,
+	uint8_t regs[5])
+{
+	unsigned int r, n, m, i, j;
+	unsigned int div;
+
+	if (!freq_out) {
+		r = 0;
+		n = 0;
+		m = 0;
+		div = 0;
+	} else {
+		if (freq_out % freq_in != 0) {
+			div = DIV_ROUND_UP(freq_in, 13500000);
+			freq_in /= div;
+			r = freq_out / freq_in;
+			i = freq_out % freq_in;
+			j = gcd(i, freq_in);
+			n = i / j;
+			m = freq_in / j;
+			div--;
+		} else {
+			r = freq_out / freq_in;
+			n = 0;
+			m = 0;
+			div = 0;
+		}
+		if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2)
+			return -EINVAL;
+	}
+
+	regs[0] = m >> 8;
+	regs[1] = m & 0xff;
+	regs[2] = n >> 8;
+	regs[3] = n & 0xff;
+	regs[4] = (r << 3) | (div << 1);
+	if (m != 0)
+		regs[4] |= 1; /* Fractional mode */
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(adau_calc_pll_cfg);
+
+MODULE_DESCRIPTION("ASoC ADAU audio CODECs shared helper functions");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/adau-utils.h b/sound/soc/codecs/adau-utils.h
new file mode 100644
index 0000000..bf5947b
--- /dev/null
+++ b/sound/soc/codecs/adau-utils.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef SOUND_SOC_CODECS_ADAU_PLL_H
+#define SOUND_SOC_CODECS_ADAU_PLL_H
+
+int adau_calc_pll_cfg(unsigned int freq_in, unsigned int freq_out,
+	uint8_t regs[5]);
+
+#endif
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
new file mode 100644
index 0000000..f22ff9f
--- /dev/null
+++ b/sound/soc/codecs/adau1373.c
@@ -0,0 +1,1520 @@
+/*
+ * Analog Devices ADAU1373 Audio Codec drive
+ *
+ * Copyright 2011 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/gcd.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/adau1373.h>
+
+#include "adau1373.h"
+#include "adau-utils.h"
+
+struct adau1373_dai {
+	unsigned int clk_src;
+	unsigned int sysclk;
+	bool enable_src;
+	bool master;
+};
+
+struct adau1373 {
+	struct regmap *regmap;
+	struct adau1373_dai dais[3];
+};
+
+#define ADAU1373_INPUT_MODE	0x00
+#define ADAU1373_AINL_CTRL(x)	(0x01 + (x) * 2)
+#define ADAU1373_AINR_CTRL(x)	(0x02 + (x) * 2)
+#define ADAU1373_LLINE_OUT(x)	(0x9 + (x) * 2)
+#define ADAU1373_RLINE_OUT(x)	(0xa + (x) * 2)
+#define ADAU1373_LSPK_OUT	0x0d
+#define ADAU1373_RSPK_OUT	0x0e
+#define ADAU1373_LHP_OUT	0x0f
+#define ADAU1373_RHP_OUT	0x10
+#define ADAU1373_ADC_GAIN	0x11
+#define ADAU1373_LADC_MIXER	0x12
+#define ADAU1373_RADC_MIXER	0x13
+#define ADAU1373_LLINE1_MIX	0x14
+#define ADAU1373_RLINE1_MIX	0x15
+#define ADAU1373_LLINE2_MIX	0x16
+#define ADAU1373_RLINE2_MIX	0x17
+#define ADAU1373_LSPK_MIX	0x18
+#define ADAU1373_RSPK_MIX	0x19
+#define ADAU1373_LHP_MIX	0x1a
+#define ADAU1373_RHP_MIX	0x1b
+#define ADAU1373_EP_MIX		0x1c
+#define ADAU1373_HP_CTRL	0x1d
+#define ADAU1373_HP_CTRL2	0x1e
+#define ADAU1373_LS_CTRL	0x1f
+#define ADAU1373_EP_CTRL	0x21
+#define ADAU1373_MICBIAS_CTRL1	0x22
+#define ADAU1373_MICBIAS_CTRL2	0x23
+#define ADAU1373_OUTPUT_CTRL	0x24
+#define ADAU1373_PWDN_CTRL1	0x25
+#define ADAU1373_PWDN_CTRL2	0x26
+#define ADAU1373_PWDN_CTRL3	0x27
+#define ADAU1373_DPLL_CTRL(x)	(0x28 + (x) * 7)
+#define ADAU1373_PLL_CTRL1(x)	(0x29 + (x) * 7)
+#define ADAU1373_PLL_CTRL2(x)	(0x2a + (x) * 7)
+#define ADAU1373_PLL_CTRL3(x)	(0x2b + (x) * 7)
+#define ADAU1373_PLL_CTRL4(x)	(0x2c + (x) * 7)
+#define ADAU1373_PLL_CTRL5(x)	(0x2d + (x) * 7)
+#define ADAU1373_PLL_CTRL6(x)	(0x2e + (x) * 7)
+#define ADAU1373_HEADDECT	0x36
+#define ADAU1373_ADC_DAC_STATUS	0x37
+#define ADAU1373_ADC_CTRL	0x3c
+#define ADAU1373_DAI(x)		(0x44 + (x))
+#define ADAU1373_CLK_SRC_DIV(x)	(0x40 + (x) * 2)
+#define ADAU1373_BCLKDIV(x)	(0x47 + (x))
+#define ADAU1373_SRC_RATIOA(x)	(0x4a + (x) * 2)
+#define ADAU1373_SRC_RATIOB(x)	(0x4b + (x) * 2)
+#define ADAU1373_DEEMP_CTRL	0x50
+#define ADAU1373_SRC_DAI_CTRL(x) (0x51 + (x))
+#define ADAU1373_DIN_MIX_CTRL(x) (0x56 + (x))
+#define ADAU1373_DOUT_MIX_CTRL(x) (0x5b + (x))
+#define ADAU1373_DAI_PBL_VOL(x)	(0x62 + (x) * 2)
+#define ADAU1373_DAI_PBR_VOL(x)	(0x63 + (x) * 2)
+#define ADAU1373_DAI_RECL_VOL(x) (0x68 + (x) * 2)
+#define ADAU1373_DAI_RECR_VOL(x) (0x69 + (x) * 2)
+#define ADAU1373_DAC1_PBL_VOL	0x6e
+#define ADAU1373_DAC1_PBR_VOL	0x6f
+#define ADAU1373_DAC2_PBL_VOL	0x70
+#define ADAU1373_DAC2_PBR_VOL	0x71
+#define ADAU1373_ADC_RECL_VOL	0x72
+#define ADAU1373_ADC_RECR_VOL	0x73
+#define ADAU1373_DMIC_RECL_VOL	0x74
+#define ADAU1373_DMIC_RECR_VOL	0x75
+#define ADAU1373_VOL_GAIN1	0x76
+#define ADAU1373_VOL_GAIN2	0x77
+#define ADAU1373_VOL_GAIN3	0x78
+#define ADAU1373_HPF_CTRL	0x7d
+#define ADAU1373_BASS1		0x7e
+#define ADAU1373_BASS2		0x7f
+#define ADAU1373_DRC(x)		(0x80 + (x) * 0x10)
+#define ADAU1373_3D_CTRL1	0xc0
+#define ADAU1373_3D_CTRL2	0xc1
+#define ADAU1373_FDSP_SEL1	0xdc
+#define ADAU1373_FDSP_SEL2	0xdd
+#define ADAU1373_FDSP_SEL3	0xde
+#define ADAU1373_FDSP_SEL4	0xdf
+#define ADAU1373_DIGMICCTRL	0xe2
+#define ADAU1373_DIGEN		0xeb
+#define ADAU1373_SOFT_RESET	0xff
+
+
+#define ADAU1373_PLL_CTRL6_DPLL_BYPASS	BIT(1)
+#define ADAU1373_PLL_CTRL6_PLL_EN	BIT(0)
+
+#define ADAU1373_DAI_INVERT_BCLK	BIT(7)
+#define ADAU1373_DAI_MASTER		BIT(6)
+#define ADAU1373_DAI_INVERT_LRCLK	BIT(4)
+#define ADAU1373_DAI_WLEN_16		0x0
+#define ADAU1373_DAI_WLEN_20		0x4
+#define ADAU1373_DAI_WLEN_24		0x8
+#define ADAU1373_DAI_WLEN_32		0xc
+#define ADAU1373_DAI_WLEN_MASK		0xc
+#define ADAU1373_DAI_FORMAT_RIGHT_J	0x0
+#define ADAU1373_DAI_FORMAT_LEFT_J	0x1
+#define ADAU1373_DAI_FORMAT_I2S		0x2
+#define ADAU1373_DAI_FORMAT_DSP		0x3
+
+#define ADAU1373_BCLKDIV_SOURCE		BIT(5)
+#define ADAU1373_BCLKDIV_SR_MASK	(0x07 << 2)
+#define ADAU1373_BCLKDIV_BCLK_MASK	0x03
+#define ADAU1373_BCLKDIV_32		0x03
+#define ADAU1373_BCLKDIV_64		0x02
+#define ADAU1373_BCLKDIV_128		0x01
+#define ADAU1373_BCLKDIV_256		0x00
+
+#define ADAU1373_ADC_CTRL_PEAK_DETECT	BIT(0)
+#define ADAU1373_ADC_CTRL_RESET		BIT(1)
+#define ADAU1373_ADC_CTRL_RESET_FORCE	BIT(2)
+
+#define ADAU1373_OUTPUT_CTRL_LDIFF	BIT(3)
+#define ADAU1373_OUTPUT_CTRL_LNFBEN	BIT(2)
+
+#define ADAU1373_PWDN_CTRL3_PWR_EN BIT(0)
+
+#define ADAU1373_EP_CTRL_MICBIAS1_OFFSET 4
+#define ADAU1373_EP_CTRL_MICBIAS2_OFFSET 2
+
+static const struct reg_default adau1373_reg_defaults[] = {
+	{ ADAU1373_INPUT_MODE,		0x00 },
+	{ ADAU1373_AINL_CTRL(0),	0x00 },
+	{ ADAU1373_AINR_CTRL(0),	0x00 },
+	{ ADAU1373_AINL_CTRL(1),	0x00 },
+	{ ADAU1373_AINR_CTRL(1),	0x00 },
+	{ ADAU1373_AINL_CTRL(2),	0x00 },
+	{ ADAU1373_AINR_CTRL(2),	0x00 },
+	{ ADAU1373_AINL_CTRL(3),	0x00 },
+	{ ADAU1373_AINR_CTRL(3),	0x00 },
+	{ ADAU1373_LLINE_OUT(0),	0x00 },
+	{ ADAU1373_RLINE_OUT(0),	0x00 },
+	{ ADAU1373_LLINE_OUT(1),	0x00 },
+	{ ADAU1373_RLINE_OUT(1),	0x00 },
+	{ ADAU1373_LSPK_OUT,		0x00 },
+	{ ADAU1373_RSPK_OUT,		0x00 },
+	{ ADAU1373_LHP_OUT,		0x00 },
+	{ ADAU1373_RHP_OUT,		0x00 },
+	{ ADAU1373_ADC_GAIN,		0x00 },
+	{ ADAU1373_LADC_MIXER,		0x00 },
+	{ ADAU1373_RADC_MIXER,		0x00 },
+	{ ADAU1373_LLINE1_MIX,		0x00 },
+	{ ADAU1373_RLINE1_MIX,		0x00 },
+	{ ADAU1373_LLINE2_MIX,		0x00 },
+	{ ADAU1373_RLINE2_MIX,		0x00 },
+	{ ADAU1373_LSPK_MIX,		0x00 },
+	{ ADAU1373_RSPK_MIX,		0x00 },
+	{ ADAU1373_LHP_MIX,		0x00 },
+	{ ADAU1373_RHP_MIX,		0x00 },
+	{ ADAU1373_EP_MIX,		0x00 },
+	{ ADAU1373_HP_CTRL,		0x00 },
+	{ ADAU1373_HP_CTRL2,		0x00 },
+	{ ADAU1373_LS_CTRL,		0x00 },
+	{ ADAU1373_EP_CTRL,		0x00 },
+	{ ADAU1373_MICBIAS_CTRL1,	0x00 },
+	{ ADAU1373_MICBIAS_CTRL2,	0x00 },
+	{ ADAU1373_OUTPUT_CTRL,		0x00 },
+	{ ADAU1373_PWDN_CTRL1,		0x00 },
+	{ ADAU1373_PWDN_CTRL2,		0x00 },
+	{ ADAU1373_PWDN_CTRL3,		0x00 },
+	{ ADAU1373_DPLL_CTRL(0),	0x00 },
+	{ ADAU1373_PLL_CTRL1(0),	0x00 },
+	{ ADAU1373_PLL_CTRL2(0),	0x00 },
+	{ ADAU1373_PLL_CTRL3(0),	0x00 },
+	{ ADAU1373_PLL_CTRL4(0),	0x00 },
+	{ ADAU1373_PLL_CTRL5(0),	0x00 },
+	{ ADAU1373_PLL_CTRL6(0),	0x02 },
+	{ ADAU1373_DPLL_CTRL(1),	0x00 },
+	{ ADAU1373_PLL_CTRL1(1),	0x00 },
+	{ ADAU1373_PLL_CTRL2(1),	0x00 },
+	{ ADAU1373_PLL_CTRL3(1),	0x00 },
+	{ ADAU1373_PLL_CTRL4(1),	0x00 },
+	{ ADAU1373_PLL_CTRL5(1),	0x00 },
+	{ ADAU1373_PLL_CTRL6(1),	0x02 },
+	{ ADAU1373_HEADDECT,		0x00 },
+	{ ADAU1373_ADC_CTRL,		0x00 },
+	{ ADAU1373_CLK_SRC_DIV(0),	0x00 },
+	{ ADAU1373_CLK_SRC_DIV(1),	0x00 },
+	{ ADAU1373_DAI(0),		0x0a },
+	{ ADAU1373_DAI(1),		0x0a },
+	{ ADAU1373_DAI(2),		0x0a },
+	{ ADAU1373_BCLKDIV(0),		0x00 },
+	{ ADAU1373_BCLKDIV(1),		0x00 },
+	{ ADAU1373_BCLKDIV(2),		0x00 },
+	{ ADAU1373_SRC_RATIOA(0),	0x00 },
+	{ ADAU1373_SRC_RATIOB(0),	0x00 },
+	{ ADAU1373_SRC_RATIOA(1),	0x00 },
+	{ ADAU1373_SRC_RATIOB(1),	0x00 },
+	{ ADAU1373_SRC_RATIOA(2),	0x00 },
+	{ ADAU1373_SRC_RATIOB(2),	0x00 },
+	{ ADAU1373_DEEMP_CTRL,		0x00 },
+	{ ADAU1373_SRC_DAI_CTRL(0),	0x08 },
+	{ ADAU1373_SRC_DAI_CTRL(1),	0x08 },
+	{ ADAU1373_SRC_DAI_CTRL(2),	0x08 },
+	{ ADAU1373_DIN_MIX_CTRL(0),	0x00 },
+	{ ADAU1373_DIN_MIX_CTRL(1),	0x00 },
+	{ ADAU1373_DIN_MIX_CTRL(2),	0x00 },
+	{ ADAU1373_DIN_MIX_CTRL(3),	0x00 },
+	{ ADAU1373_DIN_MIX_CTRL(4),	0x00 },
+	{ ADAU1373_DOUT_MIX_CTRL(0),	0x00 },
+	{ ADAU1373_DOUT_MIX_CTRL(1),	0x00 },
+	{ ADAU1373_DOUT_MIX_CTRL(2),	0x00 },
+	{ ADAU1373_DOUT_MIX_CTRL(3),	0x00 },
+	{ ADAU1373_DOUT_MIX_CTRL(4),	0x00 },
+	{ ADAU1373_DAI_PBL_VOL(0),	0x00 },
+	{ ADAU1373_DAI_PBR_VOL(0),	0x00 },
+	{ ADAU1373_DAI_PBL_VOL(1),	0x00 },
+	{ ADAU1373_DAI_PBR_VOL(1),	0x00 },
+	{ ADAU1373_DAI_PBL_VOL(2),	0x00 },
+	{ ADAU1373_DAI_PBR_VOL(2),	0x00 },
+	{ ADAU1373_DAI_RECL_VOL(0),	0x00 },
+	{ ADAU1373_DAI_RECR_VOL(0),	0x00 },
+	{ ADAU1373_DAI_RECL_VOL(1),	0x00 },
+	{ ADAU1373_DAI_RECR_VOL(1),	0x00 },
+	{ ADAU1373_DAI_RECL_VOL(2),	0x00 },
+	{ ADAU1373_DAI_RECR_VOL(2),	0x00 },
+	{ ADAU1373_DAC1_PBL_VOL,	0x00 },
+	{ ADAU1373_DAC1_PBR_VOL,	0x00 },
+	{ ADAU1373_DAC2_PBL_VOL,	0x00 },
+	{ ADAU1373_DAC2_PBR_VOL,	0x00 },
+	{ ADAU1373_ADC_RECL_VOL,	0x00 },
+	{ ADAU1373_ADC_RECR_VOL,	0x00 },
+	{ ADAU1373_DMIC_RECL_VOL,	0x00 },
+	{ ADAU1373_DMIC_RECR_VOL,	0x00 },
+	{ ADAU1373_VOL_GAIN1,		0x00 },
+	{ ADAU1373_VOL_GAIN2,		0x00 },
+	{ ADAU1373_VOL_GAIN3,		0x00 },
+	{ ADAU1373_HPF_CTRL,		0x00 },
+	{ ADAU1373_BASS1,		0x00 },
+	{ ADAU1373_BASS2,		0x00 },
+	{ ADAU1373_DRC(0) + 0x0,	0x78 },
+	{ ADAU1373_DRC(0) + 0x1,	0x18 },
+	{ ADAU1373_DRC(0) + 0x2,	0x00 },
+	{ ADAU1373_DRC(0) + 0x3,	0x00 },
+	{ ADAU1373_DRC(0) + 0x4,	0x00 },
+	{ ADAU1373_DRC(0) + 0x5,	0xc0 },
+	{ ADAU1373_DRC(0) + 0x6,	0x00 },
+	{ ADAU1373_DRC(0) + 0x7,	0x00 },
+	{ ADAU1373_DRC(0) + 0x8,	0x00 },
+	{ ADAU1373_DRC(0) + 0x9,	0xc0 },
+	{ ADAU1373_DRC(0) + 0xa,	0x88 },
+	{ ADAU1373_DRC(0) + 0xb,	0x7a },
+	{ ADAU1373_DRC(0) + 0xc,	0xdf },
+	{ ADAU1373_DRC(0) + 0xd,	0x20 },
+	{ ADAU1373_DRC(0) + 0xe,	0x00 },
+	{ ADAU1373_DRC(0) + 0xf,	0x00 },
+	{ ADAU1373_DRC(1) + 0x0,	0x78 },
+	{ ADAU1373_DRC(1) + 0x1,	0x18 },
+	{ ADAU1373_DRC(1) + 0x2,	0x00 },
+	{ ADAU1373_DRC(1) + 0x3,	0x00 },
+	{ ADAU1373_DRC(1) + 0x4,	0x00 },
+	{ ADAU1373_DRC(1) + 0x5,	0xc0 },
+	{ ADAU1373_DRC(1) + 0x6,	0x00 },
+	{ ADAU1373_DRC(1) + 0x7,	0x00 },
+	{ ADAU1373_DRC(1) + 0x8,	0x00 },
+	{ ADAU1373_DRC(1) + 0x9,	0xc0 },
+	{ ADAU1373_DRC(1) + 0xa,	0x88 },
+	{ ADAU1373_DRC(1) + 0xb,	0x7a },
+	{ ADAU1373_DRC(1) + 0xc,	0xdf },
+	{ ADAU1373_DRC(1) + 0xd,	0x20 },
+	{ ADAU1373_DRC(1) + 0xe,	0x00 },
+	{ ADAU1373_DRC(1) + 0xf,	0x00 },
+	{ ADAU1373_DRC(2) + 0x0,	0x78 },
+	{ ADAU1373_DRC(2) + 0x1,	0x18 },
+	{ ADAU1373_DRC(2) + 0x2,	0x00 },
+	{ ADAU1373_DRC(2) + 0x3,	0x00 },
+	{ ADAU1373_DRC(2) + 0x4,	0x00 },
+	{ ADAU1373_DRC(2) + 0x5,	0xc0 },
+	{ ADAU1373_DRC(2) + 0x6,	0x00 },
+	{ ADAU1373_DRC(2) + 0x7,	0x00 },
+	{ ADAU1373_DRC(2) + 0x8,	0x00 },
+	{ ADAU1373_DRC(2) + 0x9,	0xc0 },
+	{ ADAU1373_DRC(2) + 0xa,	0x88 },
+	{ ADAU1373_DRC(2) + 0xb,	0x7a },
+	{ ADAU1373_DRC(2) + 0xc,	0xdf },
+	{ ADAU1373_DRC(2) + 0xd,	0x20 },
+	{ ADAU1373_DRC(2) + 0xe,	0x00 },
+	{ ADAU1373_DRC(2) + 0xf,	0x00 },
+	{ ADAU1373_3D_CTRL1,		0x00 },
+	{ ADAU1373_3D_CTRL2,		0x00 },
+	{ ADAU1373_FDSP_SEL1,		0x00 },
+	{ ADAU1373_FDSP_SEL2,		0x00 },
+	{ ADAU1373_FDSP_SEL2,		0x00 },
+	{ ADAU1373_FDSP_SEL4,		0x00 },
+	{ ADAU1373_DIGMICCTRL,		0x00 },
+	{ ADAU1373_DIGEN,		0x00 },
+};
+
+static const DECLARE_TLV_DB_RANGE(adau1373_out_tlv,
+	0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1),
+	8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0),
+	16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0),
+	24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0)
+);
+
+static const DECLARE_TLV_DB_MINMAX(adau1373_digital_tlv, -9563, 0);
+static const DECLARE_TLV_DB_SCALE(adau1373_in_pga_tlv, -1300, 100, 1);
+static const DECLARE_TLV_DB_SCALE(adau1373_ep_tlv, -600, 600, 1);
+
+static const DECLARE_TLV_DB_SCALE(adau1373_input_boost_tlv, 0, 2000, 0);
+static const DECLARE_TLV_DB_SCALE(adau1373_gain_boost_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(adau1373_speaker_boost_tlv, 1200, 600, 0);
+
+static const char *adau1373_fdsp_sel_text[] = {
+	"None",
+	"Channel 1",
+	"Channel 2",
+	"Channel 3",
+	"Channel 4",
+	"Channel 5",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1373_drc1_channel_enum,
+	ADAU1373_FDSP_SEL1, 4, adau1373_fdsp_sel_text);
+static SOC_ENUM_SINGLE_DECL(adau1373_drc2_channel_enum,
+	ADAU1373_FDSP_SEL1, 0, adau1373_fdsp_sel_text);
+static SOC_ENUM_SINGLE_DECL(adau1373_drc3_channel_enum,
+	ADAU1373_FDSP_SEL2, 0, adau1373_fdsp_sel_text);
+static SOC_ENUM_SINGLE_DECL(adau1373_hpf_channel_enum,
+	ADAU1373_FDSP_SEL3, 0, adau1373_fdsp_sel_text);
+static SOC_ENUM_SINGLE_DECL(adau1373_bass_channel_enum,
+	ADAU1373_FDSP_SEL4, 4, adau1373_fdsp_sel_text);
+
+static const char *adau1373_hpf_cutoff_text[] = {
+	"3.7Hz", "50Hz", "100Hz", "150Hz", "200Hz", "250Hz", "300Hz", "350Hz",
+	"400Hz", "450Hz", "500Hz", "550Hz", "600Hz", "650Hz", "700Hz", "750Hz",
+	"800Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1373_hpf_cutoff_enum,
+	ADAU1373_HPF_CTRL, 3, adau1373_hpf_cutoff_text);
+
+static const char *adau1373_bass_lpf_cutoff_text[] = {
+	"801Hz", "1001Hz",
+};
+
+static const char *adau1373_bass_clip_level_text[] = {
+	"0.125", "0.250", "0.370", "0.500", "0.625", "0.750", "0.875",
+};
+
+static const unsigned int adau1373_bass_clip_level_values[] = {
+	1, 2, 3, 4, 5, 6, 7,
+};
+
+static const char *adau1373_bass_hpf_cutoff_text[] = {
+	"158Hz", "232Hz", "347Hz", "520Hz",
+};
+
+static const DECLARE_TLV_DB_RANGE(adau1373_bass_tlv,
+	0, 2, TLV_DB_SCALE_ITEM(-600, 600, 1),
+	3, 4, TLV_DB_SCALE_ITEM(950, 250, 0),
+	5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0)
+);
+
+static SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum,
+	ADAU1373_BASS1, 5, adau1373_bass_lpf_cutoff_text);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1373_bass_clip_level_enum,
+	ADAU1373_BASS1, 2, 7, adau1373_bass_clip_level_text,
+	adau1373_bass_clip_level_values);
+
+static SOC_ENUM_SINGLE_DECL(adau1373_bass_hpf_cutoff_enum,
+	ADAU1373_BASS1, 0, adau1373_bass_hpf_cutoff_text);
+
+static const char *adau1373_3d_level_text[] = {
+	"0%", "6.67%", "13.33%", "20%", "26.67%", "33.33%",
+	"40%", "46.67%", "53.33%", "60%", "66.67%", "73.33%",
+	"80%", "86.67", "99.33%", "100%"
+};
+
+static const char *adau1373_3d_cutoff_text[] = {
+	"No 3D", "0.03125 fs", "0.04583 fs", "0.075 fs", "0.11458 fs",
+	"0.16875 fs", "0.27083 fs"
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum,
+	ADAU1373_3D_CTRL1, 4, adau1373_3d_level_text);
+static SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum,
+	ADAU1373_3D_CTRL1, 0, adau1373_3d_cutoff_text);
+
+static const DECLARE_TLV_DB_RANGE(adau1373_3d_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 7, TLV_DB_LINEAR_ITEM(-1800, -120)
+);
+
+static const char *adau1373_lr_mux_text[] = {
+	"Mute",
+	"Right Channel (L+R)",
+	"Left Channel (L+R)",
+	"Stereo",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1373_lineout1_lr_mux_enum,
+	ADAU1373_OUTPUT_CTRL, 4, adau1373_lr_mux_text);
+static SOC_ENUM_SINGLE_DECL(adau1373_lineout2_lr_mux_enum,
+	ADAU1373_OUTPUT_CTRL, 6, adau1373_lr_mux_text);
+static SOC_ENUM_SINGLE_DECL(adau1373_speaker_lr_mux_enum,
+	ADAU1373_LS_CTRL, 4, adau1373_lr_mux_text);
+
+static const struct snd_kcontrol_new adau1373_controls[] = {
+	SOC_DOUBLE_R_TLV("AIF1 Capture Volume", ADAU1373_DAI_RECL_VOL(0),
+		ADAU1373_DAI_RECR_VOL(0), 0, 0xff, 1, adau1373_digital_tlv),
+	SOC_DOUBLE_R_TLV("AIF2 Capture Volume", ADAU1373_DAI_RECL_VOL(1),
+		ADAU1373_DAI_RECR_VOL(1), 0, 0xff, 1, adau1373_digital_tlv),
+	SOC_DOUBLE_R_TLV("AIF3 Capture Volume", ADAU1373_DAI_RECL_VOL(2),
+		ADAU1373_DAI_RECR_VOL(2), 0, 0xff, 1, adau1373_digital_tlv),
+
+	SOC_DOUBLE_R_TLV("ADC Capture Volume", ADAU1373_ADC_RECL_VOL,
+		ADAU1373_ADC_RECR_VOL, 0, 0xff, 1, adau1373_digital_tlv),
+	SOC_DOUBLE_R_TLV("DMIC Capture Volume", ADAU1373_DMIC_RECL_VOL,
+		ADAU1373_DMIC_RECR_VOL, 0, 0xff, 1, adau1373_digital_tlv),
+
+	SOC_DOUBLE_R_TLV("AIF1 Playback Volume", ADAU1373_DAI_PBL_VOL(0),
+		ADAU1373_DAI_PBR_VOL(0), 0, 0xff, 1, adau1373_digital_tlv),
+	SOC_DOUBLE_R_TLV("AIF2 Playback Volume", ADAU1373_DAI_PBL_VOL(1),
+		ADAU1373_DAI_PBR_VOL(1), 0, 0xff, 1, adau1373_digital_tlv),
+	SOC_DOUBLE_R_TLV("AIF3 Playback Volume", ADAU1373_DAI_PBL_VOL(2),
+		ADAU1373_DAI_PBR_VOL(2), 0, 0xff, 1, adau1373_digital_tlv),
+
+	SOC_DOUBLE_R_TLV("DAC1 Playback Volume", ADAU1373_DAC1_PBL_VOL,
+		ADAU1373_DAC1_PBR_VOL, 0, 0xff, 1, adau1373_digital_tlv),
+	SOC_DOUBLE_R_TLV("DAC2 Playback Volume", ADAU1373_DAC2_PBL_VOL,
+		ADAU1373_DAC2_PBR_VOL, 0, 0xff, 1, adau1373_digital_tlv),
+
+	SOC_DOUBLE_R_TLV("Lineout1 Playback Volume", ADAU1373_LLINE_OUT(0),
+		ADAU1373_RLINE_OUT(0), 0, 0x1f, 0, adau1373_out_tlv),
+	SOC_DOUBLE_R_TLV("Speaker Playback Volume", ADAU1373_LSPK_OUT,
+		ADAU1373_RSPK_OUT, 0, 0x1f, 0, adau1373_out_tlv),
+	SOC_DOUBLE_R_TLV("Headphone Playback Volume", ADAU1373_LHP_OUT,
+		ADAU1373_RHP_OUT, 0, 0x1f, 0, adau1373_out_tlv),
+
+	SOC_DOUBLE_R_TLV("Input 1 Capture Volume", ADAU1373_AINL_CTRL(0),
+		ADAU1373_AINR_CTRL(0), 0, 0x1f, 0, adau1373_in_pga_tlv),
+	SOC_DOUBLE_R_TLV("Input 2 Capture Volume", ADAU1373_AINL_CTRL(1),
+		ADAU1373_AINR_CTRL(1), 0, 0x1f, 0, adau1373_in_pga_tlv),
+	SOC_DOUBLE_R_TLV("Input 3 Capture Volume", ADAU1373_AINL_CTRL(2),
+		ADAU1373_AINR_CTRL(2), 0, 0x1f, 0, adau1373_in_pga_tlv),
+	SOC_DOUBLE_R_TLV("Input 4 Capture Volume", ADAU1373_AINL_CTRL(3),
+		ADAU1373_AINR_CTRL(3), 0, 0x1f, 0, adau1373_in_pga_tlv),
+
+	SOC_SINGLE_TLV("Earpiece Playback Volume", ADAU1373_EP_CTRL, 0, 3, 0,
+		adau1373_ep_tlv),
+
+	SOC_DOUBLE_TLV("AIF3 Boost Playback Volume", ADAU1373_VOL_GAIN1, 4, 5,
+		1, 0, adau1373_gain_boost_tlv),
+	SOC_DOUBLE_TLV("AIF2 Boost Playback Volume", ADAU1373_VOL_GAIN1, 2, 3,
+		1, 0, adau1373_gain_boost_tlv),
+	SOC_DOUBLE_TLV("AIF1 Boost Playback Volume", ADAU1373_VOL_GAIN1, 0, 1,
+		1, 0, adau1373_gain_boost_tlv),
+	SOC_DOUBLE_TLV("AIF3 Boost Capture Volume", ADAU1373_VOL_GAIN2, 4, 5,
+		1, 0, adau1373_gain_boost_tlv),
+	SOC_DOUBLE_TLV("AIF2 Boost Capture Volume", ADAU1373_VOL_GAIN2, 2, 3,
+		1, 0, adau1373_gain_boost_tlv),
+	SOC_DOUBLE_TLV("AIF1 Boost Capture Volume", ADAU1373_VOL_GAIN2, 0, 1,
+		1, 0, adau1373_gain_boost_tlv),
+	SOC_DOUBLE_TLV("DMIC Boost Capture Volume", ADAU1373_VOL_GAIN3, 6, 7,
+		1, 0, adau1373_gain_boost_tlv),
+	SOC_DOUBLE_TLV("ADC Boost Capture Volume", ADAU1373_VOL_GAIN3, 4, 5,
+		1, 0, adau1373_gain_boost_tlv),
+	SOC_DOUBLE_TLV("DAC2 Boost Playback Volume", ADAU1373_VOL_GAIN3, 2, 3,
+		1, 0, adau1373_gain_boost_tlv),
+	SOC_DOUBLE_TLV("DAC1 Boost Playback Volume", ADAU1373_VOL_GAIN3, 0, 1,
+		1, 0, adau1373_gain_boost_tlv),
+
+	SOC_DOUBLE_TLV("Input 1 Boost Capture Volume", ADAU1373_ADC_GAIN, 0, 4,
+		1, 0, adau1373_input_boost_tlv),
+	SOC_DOUBLE_TLV("Input 2 Boost Capture Volume", ADAU1373_ADC_GAIN, 1, 5,
+		1, 0, adau1373_input_boost_tlv),
+	SOC_DOUBLE_TLV("Input 3 Boost Capture Volume", ADAU1373_ADC_GAIN, 2, 6,
+		1, 0, adau1373_input_boost_tlv),
+	SOC_DOUBLE_TLV("Input 4 Boost Capture Volume", ADAU1373_ADC_GAIN, 3, 7,
+		1, 0, adau1373_input_boost_tlv),
+
+	SOC_DOUBLE_TLV("Speaker Boost Playback Volume", ADAU1373_LS_CTRL, 2, 3,
+		1, 0, adau1373_speaker_boost_tlv),
+
+	SOC_ENUM("Lineout1 LR Mux", adau1373_lineout1_lr_mux_enum),
+	SOC_ENUM("Speaker LR Mux", adau1373_speaker_lr_mux_enum),
+
+	SOC_ENUM("HPF Cutoff", adau1373_hpf_cutoff_enum),
+	SOC_DOUBLE("HPF Switch", ADAU1373_HPF_CTRL, 1, 0, 1, 0),
+	SOC_ENUM("HPF Channel", adau1373_hpf_channel_enum),
+
+	SOC_ENUM("Bass HPF Cutoff", adau1373_bass_hpf_cutoff_enum),
+	SOC_ENUM("Bass Clip Level Threshold", adau1373_bass_clip_level_enum),
+	SOC_ENUM("Bass LPF Cutoff", adau1373_bass_lpf_cutoff_enum),
+	SOC_DOUBLE("Bass Playback Switch", ADAU1373_BASS2, 0, 1, 1, 0),
+	SOC_SINGLE_TLV("Bass Playback Volume", ADAU1373_BASS2, 2, 7, 0,
+	    adau1373_bass_tlv),
+	SOC_ENUM("Bass Channel", adau1373_bass_channel_enum),
+
+	SOC_ENUM("3D Freq", adau1373_3d_cutoff_enum),
+	SOC_ENUM("3D Level", adau1373_3d_level_enum),
+	SOC_SINGLE("3D Playback Switch", ADAU1373_3D_CTRL2, 0, 1, 0),
+	SOC_SINGLE_TLV("3D Playback Volume", ADAU1373_3D_CTRL2, 2, 7, 0,
+		adau1373_3d_tlv),
+	SOC_ENUM("3D Channel", adau1373_bass_channel_enum),
+
+	SOC_SINGLE("Zero Cross Switch", ADAU1373_PWDN_CTRL3, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new adau1373_lineout2_controls[] = {
+	SOC_DOUBLE_R_TLV("Lineout2 Playback Volume", ADAU1373_LLINE_OUT(1),
+		ADAU1373_RLINE_OUT(1), 0, 0x1f, 0, adau1373_out_tlv),
+	SOC_ENUM("Lineout2 LR Mux", adau1373_lineout2_lr_mux_enum),
+};
+
+static const struct snd_kcontrol_new adau1373_drc_controls[] = {
+	SOC_ENUM("DRC1 Channel", adau1373_drc1_channel_enum),
+	SOC_ENUM("DRC2 Channel", adau1373_drc2_channel_enum),
+	SOC_ENUM("DRC3 Channel", adau1373_drc3_channel_enum),
+};
+
+static int adau1373_pll_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
+	unsigned int pll_id = w->name[3] - '1';
+	unsigned int val;
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		val = ADAU1373_PLL_CTRL6_PLL_EN;
+	else
+		val = 0;
+
+	regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id),
+		ADAU1373_PLL_CTRL6_PLL_EN, val);
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		mdelay(5);
+
+	return 0;
+}
+
+static const char *adau1373_decimator_text[] = {
+	"ADC",
+	"DMIC1",
+};
+
+static SOC_ENUM_SINGLE_VIRT_DECL(adau1373_decimator_enum,
+	adau1373_decimator_text);
+
+static const struct snd_kcontrol_new adau1373_decimator_mux =
+	SOC_DAPM_ENUM("Decimator Mux", adau1373_decimator_enum);
+
+static const struct snd_kcontrol_new adau1373_left_adc_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC1 Switch", ADAU1373_LADC_MIXER, 4, 1, 0),
+	SOC_DAPM_SINGLE("Input 4 Switch", ADAU1373_LADC_MIXER, 3, 1, 0),
+	SOC_DAPM_SINGLE("Input 3 Switch", ADAU1373_LADC_MIXER, 2, 1, 0),
+	SOC_DAPM_SINGLE("Input 2 Switch", ADAU1373_LADC_MIXER, 1, 1, 0),
+	SOC_DAPM_SINGLE("Input 1 Switch", ADAU1373_LADC_MIXER, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new adau1373_right_adc_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC1 Switch", ADAU1373_RADC_MIXER, 4, 1, 0),
+	SOC_DAPM_SINGLE("Input 4 Switch", ADAU1373_RADC_MIXER, 3, 1, 0),
+	SOC_DAPM_SINGLE("Input 3 Switch", ADAU1373_RADC_MIXER, 2, 1, 0),
+	SOC_DAPM_SINGLE("Input 2 Switch", ADAU1373_RADC_MIXER, 1, 1, 0),
+	SOC_DAPM_SINGLE("Input 1 Switch", ADAU1373_RADC_MIXER, 0, 1, 0),
+};
+
+#define DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(_name, _reg) \
+const struct snd_kcontrol_new _name[] = { \
+	SOC_DAPM_SINGLE("Left DAC2 Switch", _reg, 7, 1, 0), \
+	SOC_DAPM_SINGLE("Right DAC2 Switch", _reg, 6, 1, 0), \
+	SOC_DAPM_SINGLE("Left DAC1 Switch", _reg, 5, 1, 0), \
+	SOC_DAPM_SINGLE("Right DAC1 Switch", _reg, 4, 1, 0), \
+	SOC_DAPM_SINGLE("Input 4 Bypass Switch", _reg, 3, 1, 0), \
+	SOC_DAPM_SINGLE("Input 3 Bypass Switch", _reg, 2, 1, 0), \
+	SOC_DAPM_SINGLE("Input 2 Bypass Switch", _reg, 1, 1, 0), \
+	SOC_DAPM_SINGLE("Input 1 Bypass Switch", _reg, 0, 1, 0), \
+}
+
+static DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(adau1373_left_line1_mixer_controls,
+	ADAU1373_LLINE1_MIX);
+static DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(adau1373_right_line1_mixer_controls,
+	ADAU1373_RLINE1_MIX);
+static DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(adau1373_left_line2_mixer_controls,
+	ADAU1373_LLINE2_MIX);
+static DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(adau1373_right_line2_mixer_controls,
+	ADAU1373_RLINE2_MIX);
+static DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(adau1373_left_spk_mixer_controls,
+	ADAU1373_LSPK_MIX);
+static DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(adau1373_right_spk_mixer_controls,
+	ADAU1373_RSPK_MIX);
+static DECLARE_ADAU1373_OUTPUT_MIXER_CTRLS(adau1373_ep_mixer_controls,
+	ADAU1373_EP_MIX);
+
+static const struct snd_kcontrol_new adau1373_left_hp_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", ADAU1373_LHP_MIX, 5, 1, 0),
+	SOC_DAPM_SINGLE("Left DAC2 Switch", ADAU1373_LHP_MIX, 4, 1, 0),
+	SOC_DAPM_SINGLE("Input 4 Bypass Switch", ADAU1373_LHP_MIX, 3, 1, 0),
+	SOC_DAPM_SINGLE("Input 3 Bypass Switch", ADAU1373_LHP_MIX, 2, 1, 0),
+	SOC_DAPM_SINGLE("Input 2 Bypass Switch", ADAU1373_LHP_MIX, 1, 1, 0),
+	SOC_DAPM_SINGLE("Input 1 Bypass Switch", ADAU1373_LHP_MIX, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new adau1373_right_hp_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Right DAC1 Switch", ADAU1373_RHP_MIX, 5, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC2 Switch", ADAU1373_RHP_MIX, 4, 1, 0),
+	SOC_DAPM_SINGLE("Input 4 Bypass Switch", ADAU1373_RHP_MIX, 3, 1, 0),
+	SOC_DAPM_SINGLE("Input 3 Bypass Switch", ADAU1373_RHP_MIX, 2, 1, 0),
+	SOC_DAPM_SINGLE("Input 2 Bypass Switch", ADAU1373_RHP_MIX, 1, 1, 0),
+	SOC_DAPM_SINGLE("Input 1 Bypass Switch", ADAU1373_RHP_MIX, 0, 1, 0),
+};
+
+#define DECLARE_ADAU1373_DSP_CHANNEL_MIXER_CTRLS(_name, _reg) \
+const struct snd_kcontrol_new _name[] = { \
+	SOC_DAPM_SINGLE("DMIC2 Swapped Switch", _reg, 6, 1, 0), \
+	SOC_DAPM_SINGLE("DMIC2 Switch", _reg, 5, 1, 0), \
+	SOC_DAPM_SINGLE("ADC/DMIC1 Swapped Switch", _reg, 4, 1, 0), \
+	SOC_DAPM_SINGLE("ADC/DMIC1 Switch", _reg, 3, 1, 0), \
+	SOC_DAPM_SINGLE("AIF3 Switch", _reg, 2, 1, 0), \
+	SOC_DAPM_SINGLE("AIF2 Switch", _reg, 1, 1, 0), \
+	SOC_DAPM_SINGLE("AIF1 Switch", _reg, 0, 1, 0), \
+}
+
+static DECLARE_ADAU1373_DSP_CHANNEL_MIXER_CTRLS(adau1373_dsp_channel1_mixer_controls,
+	ADAU1373_DIN_MIX_CTRL(0));
+static DECLARE_ADAU1373_DSP_CHANNEL_MIXER_CTRLS(adau1373_dsp_channel2_mixer_controls,
+	ADAU1373_DIN_MIX_CTRL(1));
+static DECLARE_ADAU1373_DSP_CHANNEL_MIXER_CTRLS(adau1373_dsp_channel3_mixer_controls,
+	ADAU1373_DIN_MIX_CTRL(2));
+static DECLARE_ADAU1373_DSP_CHANNEL_MIXER_CTRLS(adau1373_dsp_channel4_mixer_controls,
+	ADAU1373_DIN_MIX_CTRL(3));
+static DECLARE_ADAU1373_DSP_CHANNEL_MIXER_CTRLS(adau1373_dsp_channel5_mixer_controls,
+	ADAU1373_DIN_MIX_CTRL(4));
+
+#define DECLARE_ADAU1373_DSP_OUTPUT_MIXER_CTRLS(_name, _reg) \
+const struct snd_kcontrol_new _name[] = { \
+	SOC_DAPM_SINGLE("DSP Channel5 Switch", _reg, 4, 1, 0), \
+	SOC_DAPM_SINGLE("DSP Channel4 Switch", _reg, 3, 1, 0), \
+	SOC_DAPM_SINGLE("DSP Channel3 Switch", _reg, 2, 1, 0), \
+	SOC_DAPM_SINGLE("DSP Channel2 Switch", _reg, 1, 1, 0), \
+	SOC_DAPM_SINGLE("DSP Channel1 Switch", _reg, 0, 1, 0), \
+}
+
+static DECLARE_ADAU1373_DSP_OUTPUT_MIXER_CTRLS(adau1373_aif1_mixer_controls,
+	ADAU1373_DOUT_MIX_CTRL(0));
+static DECLARE_ADAU1373_DSP_OUTPUT_MIXER_CTRLS(adau1373_aif2_mixer_controls,
+	ADAU1373_DOUT_MIX_CTRL(1));
+static DECLARE_ADAU1373_DSP_OUTPUT_MIXER_CTRLS(adau1373_aif3_mixer_controls,
+	ADAU1373_DOUT_MIX_CTRL(2));
+static DECLARE_ADAU1373_DSP_OUTPUT_MIXER_CTRLS(adau1373_dac1_mixer_controls,
+	ADAU1373_DOUT_MIX_CTRL(3));
+static DECLARE_ADAU1373_DSP_OUTPUT_MIXER_CTRLS(adau1373_dac2_mixer_controls,
+	ADAU1373_DOUT_MIX_CTRL(4));
+
+static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = {
+	/* Datasheet claims Left ADC is bit 6 and Right ADC is bit 7, but that
+	 * doesn't seem to be the case. */
+	SND_SOC_DAPM_ADC("Left ADC", NULL, ADAU1373_PWDN_CTRL1, 7, 0),
+	SND_SOC_DAPM_ADC("Right ADC", NULL, ADAU1373_PWDN_CTRL1, 6, 0),
+
+	SND_SOC_DAPM_ADC("DMIC1", NULL, ADAU1373_DIGMICCTRL, 0, 0),
+	SND_SOC_DAPM_ADC("DMIC2", NULL, ADAU1373_DIGMICCTRL, 2, 0),
+
+	SND_SOC_DAPM_MUX("Decimator Mux", SND_SOC_NOPM, 0, 0,
+		&adau1373_decimator_mux),
+
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", ADAU1373_PWDN_CTRL1, 5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", ADAU1373_PWDN_CTRL1, 4, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("IN4PGA", ADAU1373_PWDN_CTRL1, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IN3PGA", ADAU1373_PWDN_CTRL1, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IN2PGA", ADAU1373_PWDN_CTRL1, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IN1PGA", ADAU1373_PWDN_CTRL1, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("Left DAC2", NULL, ADAU1373_PWDN_CTRL2, 7, 0),
+	SND_SOC_DAPM_DAC("Right DAC2", NULL, ADAU1373_PWDN_CTRL2, 6, 0),
+	SND_SOC_DAPM_DAC("Left DAC1", NULL, ADAU1373_PWDN_CTRL2, 5, 0),
+	SND_SOC_DAPM_DAC("Right DAC1", NULL, ADAU1373_PWDN_CTRL2, 4, 0),
+
+	SOC_MIXER_ARRAY("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+		adau1373_left_adc_mixer_controls),
+	SOC_MIXER_ARRAY("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+		adau1373_right_adc_mixer_controls),
+
+	SOC_MIXER_ARRAY("Left Lineout2 Mixer", ADAU1373_PWDN_CTRL2, 3, 0,
+		adau1373_left_line2_mixer_controls),
+	SOC_MIXER_ARRAY("Right Lineout2 Mixer", ADAU1373_PWDN_CTRL2, 2, 0,
+		adau1373_right_line2_mixer_controls),
+	SOC_MIXER_ARRAY("Left Lineout1 Mixer", ADAU1373_PWDN_CTRL2, 1, 0,
+		adau1373_left_line1_mixer_controls),
+	SOC_MIXER_ARRAY("Right Lineout1 Mixer", ADAU1373_PWDN_CTRL2, 0, 0,
+		adau1373_right_line1_mixer_controls),
+
+	SOC_MIXER_ARRAY("Earpiece Mixer", ADAU1373_PWDN_CTRL3, 4, 0,
+		adau1373_ep_mixer_controls),
+	SOC_MIXER_ARRAY("Left Speaker Mixer", ADAU1373_PWDN_CTRL3, 3, 0,
+		adau1373_left_spk_mixer_controls),
+	SOC_MIXER_ARRAY("Right Speaker Mixer", ADAU1373_PWDN_CTRL3, 2, 0,
+		adau1373_right_spk_mixer_controls),
+	SOC_MIXER_ARRAY("Left Headphone Mixer", SND_SOC_NOPM, 0, 0,
+		adau1373_left_hp_mixer_controls),
+	SOC_MIXER_ARRAY("Right Headphone Mixer", SND_SOC_NOPM, 0, 0,
+		adau1373_right_hp_mixer_controls),
+	SND_SOC_DAPM_SUPPLY("Headphone Enable", ADAU1373_PWDN_CTRL3, 1, 0,
+		NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("AIF1 CLK", ADAU1373_SRC_DAI_CTRL(0), 0, 0,
+	    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AIF2 CLK", ADAU1373_SRC_DAI_CTRL(1), 0, 0,
+	    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AIF3 CLK", ADAU1373_SRC_DAI_CTRL(2), 0, 0,
+	    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AIF1 IN SRC", ADAU1373_SRC_DAI_CTRL(0), 2, 0,
+	    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AIF1 OUT SRC", ADAU1373_SRC_DAI_CTRL(0), 1, 0,
+	    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AIF2 IN SRC", ADAU1373_SRC_DAI_CTRL(1), 2, 0,
+	    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AIF2 OUT SRC", ADAU1373_SRC_DAI_CTRL(1), 1, 0,
+	    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AIF3 IN SRC", ADAU1373_SRC_DAI_CTRL(2), 2, 0,
+	    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AIF3 OUT SRC", ADAU1373_SRC_DAI_CTRL(2), 1, 0,
+	    NULL, 0),
+
+	SND_SOC_DAPM_AIF_IN("AIF1 IN", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1 OUT", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2 IN", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2 OUT", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF3 IN", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF3 OUT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	SOC_MIXER_ARRAY("DSP Channel1 Mixer", SND_SOC_NOPM, 0, 0,
+		adau1373_dsp_channel1_mixer_controls),
+	SOC_MIXER_ARRAY("DSP Channel2 Mixer", SND_SOC_NOPM, 0, 0,
+		adau1373_dsp_channel2_mixer_controls),
+	SOC_MIXER_ARRAY("DSP Channel3 Mixer", SND_SOC_NOPM, 0, 0,
+		adau1373_dsp_channel3_mixer_controls),
+	SOC_MIXER_ARRAY("DSP Channel4 Mixer", SND_SOC_NOPM, 0, 0,
+		adau1373_dsp_channel4_mixer_controls),
+	SOC_MIXER_ARRAY("DSP Channel5 Mixer", SND_SOC_NOPM, 0, 0,
+		adau1373_dsp_channel5_mixer_controls),
+
+	SOC_MIXER_ARRAY("AIF1 Mixer", SND_SOC_NOPM, 0, 0,
+		adau1373_aif1_mixer_controls),
+	SOC_MIXER_ARRAY("AIF2 Mixer", SND_SOC_NOPM, 0, 0,
+		adau1373_aif2_mixer_controls),
+	SOC_MIXER_ARRAY("AIF3 Mixer", SND_SOC_NOPM, 0, 0,
+		adau1373_aif3_mixer_controls),
+	SOC_MIXER_ARRAY("DAC1 Mixer", SND_SOC_NOPM, 0, 0,
+		adau1373_dac1_mixer_controls),
+	SOC_MIXER_ARRAY("DAC2 Mixer", SND_SOC_NOPM, 0, 0,
+		adau1373_dac2_mixer_controls),
+
+	SND_SOC_DAPM_SUPPLY("DSP", ADAU1373_DIGEN, 4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Recording Engine B", ADAU1373_DIGEN, 3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Recording Engine A", ADAU1373_DIGEN, 2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Playback Engine B", ADAU1373_DIGEN, 1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Playback Engine A", ADAU1373_DIGEN, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("PLL1", SND_SOC_NOPM, 0, 0, adau1373_pll_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("PLL2", SND_SOC_NOPM, 0, 0, adau1373_pll_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("SYSCLK1", ADAU1373_CLK_SRC_DIV(0), 7, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("SYSCLK2", ADAU1373_CLK_SRC_DIV(1), 7, 0, NULL, 0),
+
+	SND_SOC_DAPM_INPUT("AIN1L"),
+	SND_SOC_DAPM_INPUT("AIN1R"),
+	SND_SOC_DAPM_INPUT("AIN2L"),
+	SND_SOC_DAPM_INPUT("AIN2R"),
+	SND_SOC_DAPM_INPUT("AIN3L"),
+	SND_SOC_DAPM_INPUT("AIN3R"),
+	SND_SOC_DAPM_INPUT("AIN4L"),
+	SND_SOC_DAPM_INPUT("AIN4R"),
+
+	SND_SOC_DAPM_INPUT("DMIC1DAT"),
+	SND_SOC_DAPM_INPUT("DMIC2DAT"),
+
+	SND_SOC_DAPM_OUTPUT("LOUT1L"),
+	SND_SOC_DAPM_OUTPUT("LOUT1R"),
+	SND_SOC_DAPM_OUTPUT("LOUT2L"),
+	SND_SOC_DAPM_OUTPUT("LOUT2R"),
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("SPKL"),
+	SND_SOC_DAPM_OUTPUT("SPKR"),
+	SND_SOC_DAPM_OUTPUT("EP"),
+};
+
+static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source,
+	struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
+	unsigned int dai;
+	const char *clk;
+
+	dai = sink->name[3] - '1';
+
+	if (!adau1373->dais[dai].master)
+		return 0;
+
+	if (adau1373->dais[dai].clk_src == ADAU1373_CLK_SRC_PLL1)
+		clk = "SYSCLK1";
+	else
+		clk = "SYSCLK2";
+
+	return strcmp(source->name, clk) == 0;
+}
+
+static int adau1373_check_src(struct snd_soc_dapm_widget *source,
+	struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
+	unsigned int dai;
+
+	dai = sink->name[3] - '1';
+
+	return adau1373->dais[dai].enable_src;
+}
+
+#define DSP_CHANNEL_MIXER_ROUTES(_sink) \
+	{ _sink, "DMIC2 Swapped Switch", "DMIC2" }, \
+	{ _sink, "DMIC2 Switch", "DMIC2" }, \
+	{ _sink, "ADC/DMIC1 Swapped Switch", "Decimator Mux" }, \
+	{ _sink, "ADC/DMIC1 Switch", "Decimator Mux" }, \
+	{ _sink, "AIF1 Switch", "AIF1 IN" }, \
+	{ _sink, "AIF2 Switch", "AIF2 IN" }, \
+	{ _sink, "AIF3 Switch", "AIF3 IN" }
+
+#define DSP_OUTPUT_MIXER_ROUTES(_sink) \
+	{ _sink, "DSP Channel1 Switch", "DSP Channel1 Mixer" }, \
+	{ _sink, "DSP Channel2 Switch", "DSP Channel2 Mixer" }, \
+	{ _sink, "DSP Channel3 Switch", "DSP Channel3 Mixer" }, \
+	{ _sink, "DSP Channel4 Switch", "DSP Channel4 Mixer" }, \
+	{ _sink, "DSP Channel5 Switch", "DSP Channel5 Mixer" }
+
+#define LEFT_OUTPUT_MIXER_ROUTES(_sink) \
+	{ _sink, "Right DAC2 Switch", "Right DAC2" }, \
+	{ _sink, "Left DAC2 Switch", "Left DAC2" }, \
+	{ _sink, "Right DAC1 Switch", "Right DAC1" }, \
+	{ _sink, "Left DAC1 Switch", "Left DAC1" }, \
+	{ _sink, "Input 1 Bypass Switch", "IN1PGA" }, \
+	{ _sink, "Input 2 Bypass Switch", "IN2PGA" }, \
+	{ _sink, "Input 3 Bypass Switch", "IN3PGA" }, \
+	{ _sink, "Input 4 Bypass Switch", "IN4PGA" }
+
+#define RIGHT_OUTPUT_MIXER_ROUTES(_sink) \
+	{ _sink, "Right DAC2 Switch", "Right DAC2" }, \
+	{ _sink, "Left DAC2 Switch", "Left DAC2" }, \
+	{ _sink, "Right DAC1 Switch", "Right DAC1" }, \
+	{ _sink, "Left DAC1 Switch", "Left DAC1" }, \
+	{ _sink, "Input 1 Bypass Switch", "IN1PGA" }, \
+	{ _sink, "Input 2 Bypass Switch", "IN2PGA" }, \
+	{ _sink, "Input 3 Bypass Switch", "IN3PGA" }, \
+	{ _sink, "Input 4 Bypass Switch", "IN4PGA" }
+
+static const struct snd_soc_dapm_route adau1373_dapm_routes[] = {
+	{ "Left ADC Mixer", "DAC1 Switch", "Left DAC1" },
+	{ "Left ADC Mixer", "Input 1 Switch", "IN1PGA" },
+	{ "Left ADC Mixer", "Input 2 Switch", "IN2PGA" },
+	{ "Left ADC Mixer", "Input 3 Switch", "IN3PGA" },
+	{ "Left ADC Mixer", "Input 4 Switch", "IN4PGA" },
+
+	{ "Right ADC Mixer", "DAC1 Switch", "Right DAC1" },
+	{ "Right ADC Mixer", "Input 1 Switch", "IN1PGA" },
+	{ "Right ADC Mixer", "Input 2 Switch", "IN2PGA" },
+	{ "Right ADC Mixer", "Input 3 Switch", "IN3PGA" },
+	{ "Right ADC Mixer", "Input 4 Switch", "IN4PGA" },
+
+	{ "Left ADC", NULL, "Left ADC Mixer" },
+	{ "Right ADC", NULL, "Right ADC Mixer" },
+
+	{ "Decimator Mux", "ADC", "Left ADC" },
+	{ "Decimator Mux", "ADC", "Right ADC" },
+	{ "Decimator Mux", "DMIC1", "DMIC1" },
+
+	DSP_CHANNEL_MIXER_ROUTES("DSP Channel1 Mixer"),
+	DSP_CHANNEL_MIXER_ROUTES("DSP Channel2 Mixer"),
+	DSP_CHANNEL_MIXER_ROUTES("DSP Channel3 Mixer"),
+	DSP_CHANNEL_MIXER_ROUTES("DSP Channel4 Mixer"),
+	DSP_CHANNEL_MIXER_ROUTES("DSP Channel5 Mixer"),
+
+	DSP_OUTPUT_MIXER_ROUTES("AIF1 Mixer"),
+	DSP_OUTPUT_MIXER_ROUTES("AIF2 Mixer"),
+	DSP_OUTPUT_MIXER_ROUTES("AIF3 Mixer"),
+	DSP_OUTPUT_MIXER_ROUTES("DAC1 Mixer"),
+	DSP_OUTPUT_MIXER_ROUTES("DAC2 Mixer"),
+
+	{ "AIF1 OUT", NULL, "AIF1 Mixer" },
+	{ "AIF2 OUT", NULL, "AIF2 Mixer" },
+	{ "AIF3 OUT", NULL, "AIF3 Mixer" },
+	{ "Left DAC1", NULL, "DAC1 Mixer" },
+	{ "Right DAC1", NULL, "DAC1 Mixer" },
+	{ "Left DAC2", NULL, "DAC2 Mixer" },
+	{ "Right DAC2", NULL, "DAC2 Mixer" },
+
+	LEFT_OUTPUT_MIXER_ROUTES("Left Lineout1 Mixer"),
+	RIGHT_OUTPUT_MIXER_ROUTES("Right Lineout1 Mixer"),
+	LEFT_OUTPUT_MIXER_ROUTES("Left Lineout2 Mixer"),
+	RIGHT_OUTPUT_MIXER_ROUTES("Right Lineout2 Mixer"),
+	LEFT_OUTPUT_MIXER_ROUTES("Left Speaker Mixer"),
+	RIGHT_OUTPUT_MIXER_ROUTES("Right Speaker Mixer"),
+
+	{ "Left Headphone Mixer", "Left DAC2 Switch", "Left DAC2" },
+	{ "Left Headphone Mixer", "Left DAC1 Switch", "Left DAC1" },
+	{ "Left Headphone Mixer", "Input 1 Bypass Switch", "IN1PGA" },
+	{ "Left Headphone Mixer", "Input 2 Bypass Switch", "IN2PGA" },
+	{ "Left Headphone Mixer", "Input 3 Bypass Switch", "IN3PGA" },
+	{ "Left Headphone Mixer", "Input 4 Bypass Switch", "IN4PGA" },
+	{ "Right Headphone Mixer", "Right DAC2 Switch", "Right DAC2" },
+	{ "Right Headphone Mixer", "Right DAC1 Switch", "Right DAC1" },
+	{ "Right Headphone Mixer", "Input 1 Bypass Switch", "IN1PGA" },
+	{ "Right Headphone Mixer", "Input 2 Bypass Switch", "IN2PGA" },
+	{ "Right Headphone Mixer", "Input 3 Bypass Switch", "IN3PGA" },
+	{ "Right Headphone Mixer", "Input 4 Bypass Switch", "IN4PGA" },
+
+	{ "Left Headphone Mixer", NULL, "Headphone Enable" },
+	{ "Right Headphone Mixer", NULL, "Headphone Enable" },
+
+	{ "Earpiece Mixer", "Right DAC2 Switch", "Right DAC2" },
+	{ "Earpiece Mixer", "Left DAC2 Switch", "Left DAC2" },
+	{ "Earpiece Mixer", "Right DAC1 Switch", "Right DAC1" },
+	{ "Earpiece Mixer", "Left DAC1 Switch", "Left DAC1" },
+	{ "Earpiece Mixer", "Input 1 Bypass Switch", "IN1PGA" },
+	{ "Earpiece Mixer", "Input 2 Bypass Switch", "IN2PGA" },
+	{ "Earpiece Mixer", "Input 3 Bypass Switch", "IN3PGA" },
+	{ "Earpiece Mixer", "Input 4 Bypass Switch", "IN4PGA" },
+
+	{ "LOUT1L", NULL, "Left Lineout1 Mixer" },
+	{ "LOUT1R", NULL, "Right Lineout1 Mixer" },
+	{ "LOUT2L", NULL, "Left Lineout2 Mixer" },
+	{ "LOUT2R", NULL, "Right Lineout2 Mixer" },
+	{ "SPKL", NULL, "Left Speaker Mixer" },
+	{ "SPKR", NULL, "Right Speaker Mixer" },
+	{ "HPL", NULL, "Left Headphone Mixer" },
+	{ "HPR", NULL, "Right Headphone Mixer" },
+	{ "EP", NULL, "Earpiece Mixer" },
+
+	{ "IN1PGA", NULL, "AIN1L" },
+	{ "IN2PGA", NULL, "AIN2L" },
+	{ "IN3PGA", NULL, "AIN3L" },
+	{ "IN4PGA", NULL, "AIN4L" },
+	{ "IN1PGA", NULL, "AIN1R" },
+	{ "IN2PGA", NULL, "AIN2R" },
+	{ "IN3PGA", NULL, "AIN3R" },
+	{ "IN4PGA", NULL, "AIN4R" },
+
+	{ "SYSCLK1", NULL, "PLL1" },
+	{ "SYSCLK2", NULL, "PLL2" },
+
+	{ "Left DAC1", NULL, "SYSCLK1" },
+	{ "Right DAC1", NULL, "SYSCLK1" },
+	{ "Left DAC2", NULL, "SYSCLK1" },
+	{ "Right DAC2", NULL, "SYSCLK1" },
+	{ "Left ADC", NULL, "SYSCLK1" },
+	{ "Right ADC", NULL, "SYSCLK1" },
+
+	{ "DSP", NULL, "SYSCLK1" },
+
+	{ "AIF1 Mixer", NULL, "DSP" },
+	{ "AIF2 Mixer", NULL, "DSP" },
+	{ "AIF3 Mixer", NULL, "DSP" },
+	{ "DAC1 Mixer", NULL, "DSP" },
+	{ "DAC2 Mixer", NULL, "DSP" },
+	{ "DAC1 Mixer", NULL, "Playback Engine A" },
+	{ "DAC2 Mixer", NULL, "Playback Engine B" },
+	{ "Left ADC Mixer", NULL, "Recording Engine A" },
+	{ "Right ADC Mixer", NULL, "Recording Engine A" },
+
+	{ "AIF1 CLK", NULL, "SYSCLK1", adau1373_check_aif_clk },
+	{ "AIF2 CLK", NULL, "SYSCLK1", adau1373_check_aif_clk },
+	{ "AIF3 CLK", NULL, "SYSCLK1", adau1373_check_aif_clk },
+	{ "AIF1 CLK", NULL, "SYSCLK2", adau1373_check_aif_clk },
+	{ "AIF2 CLK", NULL, "SYSCLK2", adau1373_check_aif_clk },
+	{ "AIF3 CLK", NULL, "SYSCLK2", adau1373_check_aif_clk },
+
+	{ "AIF1 IN", NULL, "AIF1 CLK" },
+	{ "AIF1 OUT", NULL, "AIF1 CLK" },
+	{ "AIF2 IN", NULL, "AIF2 CLK" },
+	{ "AIF2 OUT", NULL, "AIF2 CLK" },
+	{ "AIF3 IN", NULL, "AIF3 CLK" },
+	{ "AIF3 OUT", NULL, "AIF3 CLK" },
+	{ "AIF1 IN", NULL, "AIF1 IN SRC", adau1373_check_src },
+	{ "AIF1 OUT", NULL, "AIF1 OUT SRC", adau1373_check_src },
+	{ "AIF2 IN", NULL, "AIF2 IN SRC", adau1373_check_src },
+	{ "AIF2 OUT", NULL, "AIF2 OUT SRC", adau1373_check_src },
+	{ "AIF3 IN", NULL, "AIF3 IN SRC", adau1373_check_src },
+	{ "AIF3 OUT", NULL, "AIF3 OUT SRC", adau1373_check_src },
+
+	{ "DMIC1", NULL, "DMIC1DAT" },
+	{ "DMIC1", NULL, "SYSCLK1" },
+	{ "DMIC1", NULL, "Recording Engine A" },
+	{ "DMIC2", NULL, "DMIC2DAT" },
+	{ "DMIC2", NULL, "SYSCLK1" },
+	{ "DMIC2", NULL, "Recording Engine B" },
+};
+
+static int adau1373_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
+	struct adau1373_dai *adau1373_dai = &adau1373->dais[dai->id];
+	unsigned int div;
+	unsigned int freq;
+	unsigned int ctrl;
+
+	freq = adau1373_dai->sysclk;
+
+	if (freq % params_rate(params) != 0)
+		return -EINVAL;
+
+	switch (freq / params_rate(params)) {
+	case 1024: /* sysclk / 256 */
+		div = 0;
+		break;
+	case 1536: /* 2/3 sysclk / 256 */
+		div = 1;
+		break;
+	case 2048: /* 1/2 sysclk / 256 */
+		div = 2;
+		break;
+	case 3072: /* 1/3 sysclk / 256 */
+		div = 3;
+		break;
+	case 4096: /* 1/4 sysclk / 256 */
+		div = 4;
+		break;
+	case 6144: /* 1/6 sysclk / 256 */
+		div = 5;
+		break;
+	case 5632: /* 2/11 sysclk / 256 */
+		div = 6;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	adau1373_dai->enable_src = (div != 0);
+
+	regmap_update_bits(adau1373->regmap, ADAU1373_BCLKDIV(dai->id),
+		ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK,
+		(div << 2) | ADAU1373_BCLKDIV_64);
+
+	switch (params_width(params)) {
+	case 16:
+		ctrl = ADAU1373_DAI_WLEN_16;
+		break;
+	case 20:
+		ctrl = ADAU1373_DAI_WLEN_20;
+		break;
+	case 24:
+		ctrl = ADAU1373_DAI_WLEN_24;
+		break;
+	case 32:
+		ctrl = ADAU1373_DAI_WLEN_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(adau1373->regmap, ADAU1373_DAI(dai->id),
+			ADAU1373_DAI_WLEN_MASK, ctrl);
+}
+
+static int adau1373_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
+	struct adau1373_dai *adau1373_dai = &adau1373->dais[dai->id];
+	unsigned int ctrl;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		ctrl = ADAU1373_DAI_MASTER;
+		adau1373_dai->master = true;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		ctrl = 0;
+		adau1373_dai->master = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		ctrl |= ADAU1373_DAI_FORMAT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ctrl |= ADAU1373_DAI_FORMAT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		ctrl |= ADAU1373_DAI_FORMAT_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		ctrl |= ADAU1373_DAI_FORMAT_DSP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		ctrl |= ADAU1373_DAI_INVERT_BCLK;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		ctrl |= ADAU1373_DAI_INVERT_LRCLK;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		ctrl |= ADAU1373_DAI_INVERT_LRCLK | ADAU1373_DAI_INVERT_BCLK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(adau1373->regmap, ADAU1373_DAI(dai->id),
+		~ADAU1373_DAI_WLEN_MASK, ctrl);
+
+	return 0;
+}
+
+static int adau1373_set_dai_sysclk(struct snd_soc_dai *dai,
+	int clk_id, unsigned int freq, int dir)
+{
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(dai->component);
+	struct adau1373_dai *adau1373_dai = &adau1373->dais[dai->id];
+
+	switch (clk_id) {
+	case ADAU1373_CLK_SRC_PLL1:
+	case ADAU1373_CLK_SRC_PLL2:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	adau1373_dai->sysclk = freq;
+	adau1373_dai->clk_src = clk_id;
+
+	regmap_update_bits(adau1373->regmap, ADAU1373_BCLKDIV(dai->id),
+		ADAU1373_BCLKDIV_SOURCE, clk_id << 5);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops adau1373_dai_ops = {
+	.hw_params	= adau1373_hw_params,
+	.set_sysclk	= adau1373_set_dai_sysclk,
+	.set_fmt	= adau1373_set_dai_fmt,
+};
+
+#define ADAU1373_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver adau1373_dai_driver[] = {
+	{
+		.id = 0,
+		.name = "adau1373-aif1",
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = ADAU1373_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = ADAU1373_FORMATS,
+		},
+		.ops = &adau1373_dai_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.id = 1,
+		.name = "adau1373-aif2",
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = ADAU1373_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = ADAU1373_FORMATS,
+		},
+		.ops = &adau1373_dai_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.id = 2,
+		.name = "adau1373-aif3",
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = ADAU1373_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF3 Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = ADAU1373_FORMATS,
+		},
+		.ops = &adau1373_dai_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static int adau1373_set_pll(struct snd_soc_component *component, int pll_id,
+	int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
+	unsigned int dpll_div = 0;
+	uint8_t pll_regs[5];
+	int ret;
+
+	switch (pll_id) {
+	case ADAU1373_PLL1:
+	case ADAU1373_PLL2:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (source) {
+	case ADAU1373_PLL_SRC_BCLK1:
+	case ADAU1373_PLL_SRC_BCLK2:
+	case ADAU1373_PLL_SRC_BCLK3:
+	case ADAU1373_PLL_SRC_LRCLK1:
+	case ADAU1373_PLL_SRC_LRCLK2:
+	case ADAU1373_PLL_SRC_LRCLK3:
+	case ADAU1373_PLL_SRC_MCLK1:
+	case ADAU1373_PLL_SRC_MCLK2:
+	case ADAU1373_PLL_SRC_GPIO1:
+	case ADAU1373_PLL_SRC_GPIO2:
+	case ADAU1373_PLL_SRC_GPIO3:
+	case ADAU1373_PLL_SRC_GPIO4:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (freq_in < 7813 || freq_in > 27000000)
+		return -EINVAL;
+
+	if (freq_out < 45158000 || freq_out > 49152000)
+		return -EINVAL;
+
+	/* APLL input needs to be >= 8Mhz, so in case freq_in is less we use the
+	 * DPLL to get it there. DPLL_out = (DPLL_in / div) * 1024 */
+	while (freq_in < 8000000) {
+		freq_in *= 2;
+		dpll_div++;
+	}
+
+	ret = adau_calc_pll_cfg(freq_in, freq_out, pll_regs);
+	if (ret)
+		return -EINVAL;
+
+	if (dpll_div) {
+		dpll_div = 11 - dpll_div;
+		regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id),
+			ADAU1373_PLL_CTRL6_DPLL_BYPASS, 0);
+	} else {
+		regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id),
+			ADAU1373_PLL_CTRL6_DPLL_BYPASS,
+			ADAU1373_PLL_CTRL6_DPLL_BYPASS);
+	}
+
+	regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id),
+		(source << 4) | dpll_div);
+	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), pll_regs[0]);
+	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), pll_regs[1]);
+	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), pll_regs[2]);
+	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), pll_regs[3]);
+	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id), pll_regs[4]);
+
+	/* Set sysclk to pll_rate / 4 */
+	regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09);
+
+	return 0;
+}
+
+static void adau1373_load_drc_settings(struct adau1373 *adau1373,
+	unsigned int nr, uint8_t *drc)
+{
+	unsigned int i;
+
+	for (i = 0; i < ADAU1373_DRC_SIZE; ++i)
+		regmap_write(adau1373->regmap, ADAU1373_DRC(nr) + i, drc[i]);
+}
+
+static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias)
+{
+	switch (micbias) {
+	case ADAU1373_MICBIAS_2_9V:
+	case ADAU1373_MICBIAS_2_2V:
+	case ADAU1373_MICBIAS_2_6V:
+	case ADAU1373_MICBIAS_1_8V:
+		return true;
+	default:
+		break;
+	}
+	return false;
+}
+
+static int adau1373_probe(struct snd_soc_component *component)
+{
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
+	struct adau1373_platform_data *pdata = component->dev->platform_data;
+	bool lineout_differential = false;
+	unsigned int val;
+	int i;
+
+	if (pdata) {
+		if (pdata->num_drc > ARRAY_SIZE(pdata->drc_setting))
+			return -EINVAL;
+
+		if (!adau1373_valid_micbias(pdata->micbias1) ||
+			!adau1373_valid_micbias(pdata->micbias2))
+			return -EINVAL;
+
+		for (i = 0; i < pdata->num_drc; ++i) {
+			adau1373_load_drc_settings(adau1373, i,
+				pdata->drc_setting[i]);
+		}
+
+		snd_soc_add_component_controls(component, adau1373_drc_controls,
+			pdata->num_drc);
+
+		val = 0;
+		for (i = 0; i < 4; ++i) {
+			if (pdata->input_differential[i])
+				val |= BIT(i);
+		}
+		regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val);
+
+		val = 0;
+		if (pdata->lineout_differential)
+			val |= ADAU1373_OUTPUT_CTRL_LDIFF;
+		if (pdata->lineout_ground_sense)
+			val |= ADAU1373_OUTPUT_CTRL_LNFBEN;
+		regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val);
+
+		lineout_differential = pdata->lineout_differential;
+
+		regmap_write(adau1373->regmap, ADAU1373_EP_CTRL,
+			(pdata->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) |
+			(pdata->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET));
+	}
+
+	if (!lineout_differential) {
+		snd_soc_add_component_controls(component, adau1373_lineout2_controls,
+			ARRAY_SIZE(adau1373_lineout2_controls));
+	}
+
+	regmap_write(adau1373->regmap, ADAU1373_ADC_CTRL,
+	    ADAU1373_ADC_CTRL_RESET_FORCE | ADAU1373_ADC_CTRL_PEAK_DETECT);
+
+	return 0;
+}
+
+static int adau1373_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		regmap_update_bits(adau1373->regmap, ADAU1373_PWDN_CTRL3,
+			ADAU1373_PWDN_CTRL3_PWR_EN, ADAU1373_PWDN_CTRL3_PWR_EN);
+		break;
+	case SND_SOC_BIAS_OFF:
+		regmap_update_bits(adau1373->regmap, ADAU1373_PWDN_CTRL3,
+			ADAU1373_PWDN_CTRL3_PWR_EN, 0);
+		break;
+	}
+	return 0;
+}
+
+static int adau1373_resume(struct snd_soc_component *component)
+{
+	struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component);
+
+	regcache_sync(adau1373->regmap);
+
+	return 0;
+}
+
+static bool adau1373_register_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case ADAU1373_SOFT_RESET:
+	case ADAU1373_ADC_DAC_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config adau1373_regmap_config = {
+	.val_bits = 8,
+	.reg_bits = 8,
+
+	.volatile_reg = adau1373_register_volatile,
+	.max_register = ADAU1373_SOFT_RESET,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = adau1373_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(adau1373_reg_defaults),
+};
+
+static const struct snd_soc_component_driver adau1373_component_driver = {
+	.probe			= adau1373_probe,
+	.resume			= adau1373_resume,
+	.set_bias_level		= adau1373_set_bias_level,
+	.set_pll		= adau1373_set_pll,
+	.controls		= adau1373_controls,
+	.num_controls		= ARRAY_SIZE(adau1373_controls),
+	.dapm_widgets		= adau1373_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(adau1373_dapm_widgets),
+	.dapm_routes		= adau1373_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(adau1373_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int adau1373_i2c_probe(struct i2c_client *client,
+			      const struct i2c_device_id *id)
+{
+	struct adau1373 *adau1373;
+	int ret;
+
+	adau1373 = devm_kzalloc(&client->dev, sizeof(*adau1373), GFP_KERNEL);
+	if (!adau1373)
+		return -ENOMEM;
+
+	adau1373->regmap = devm_regmap_init_i2c(client,
+		&adau1373_regmap_config);
+	if (IS_ERR(adau1373->regmap))
+		return PTR_ERR(adau1373->regmap);
+
+	regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00);
+
+	dev_set_drvdata(&client->dev, adau1373);
+
+	ret = devm_snd_soc_register_component(&client->dev,
+			&adau1373_component_driver,
+			adau1373_dai_driver, ARRAY_SIZE(adau1373_dai_driver));
+	return ret;
+}
+
+static const struct i2c_device_id adau1373_i2c_id[] = {
+	{ "adau1373", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adau1373_i2c_id);
+
+static struct i2c_driver adau1373_i2c_driver = {
+	.driver = {
+		.name = "adau1373",
+	},
+	.probe = adau1373_i2c_probe,
+	.id_table = adau1373_i2c_id,
+};
+
+module_i2c_driver(adau1373_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1373 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1373.h b/sound/soc/codecs/adau1373.h
new file mode 100644
index 0000000..56320d5
--- /dev/null
+++ b/sound/soc/codecs/adau1373.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ADAU1373_H__
+#define __ADAU1373_H__
+
+enum adau1373_pll_src {
+	ADAU1373_PLL_SRC_MCLK1 = 0,
+	ADAU1373_PLL_SRC_BCLK1 = 1,
+	ADAU1373_PLL_SRC_BCLK2 = 2,
+	ADAU1373_PLL_SRC_BCLK3 = 3,
+	ADAU1373_PLL_SRC_LRCLK1 = 4,
+	ADAU1373_PLL_SRC_LRCLK2 = 5,
+	ADAU1373_PLL_SRC_LRCLK3 = 6,
+	ADAU1373_PLL_SRC_GPIO1 = 7,
+	ADAU1373_PLL_SRC_GPIO2 = 8,
+	ADAU1373_PLL_SRC_GPIO3 = 9,
+	ADAU1373_PLL_SRC_GPIO4 = 10,
+	ADAU1373_PLL_SRC_MCLK2 = 11,
+};
+
+enum adau1373_pll {
+	ADAU1373_PLL1 = 0,
+	ADAU1373_PLL2 = 1,
+};
+
+enum adau1373_clk_src {
+	ADAU1373_CLK_SRC_PLL1 = 0,
+	ADAU1373_CLK_SRC_PLL2 = 1,
+};
+
+#endif
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
new file mode 100644
index 0000000..b5a6174
--- /dev/null
+++ b/sound/soc/codecs/adau1701.c
@@ -0,0 +1,922 @@
+/*
+ * Driver for ADAU1701 SigmaDSP processor
+ *
+ * Copyright 2011 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *	based on an inital version by Cliff Cai <cliff.cai@analog.com>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/unaligned.h>
+
+#include "sigmadsp.h"
+#include "adau1701.h"
+
+#define ADAU1701_SAFELOAD_DATA(i) (0x0810 + (i))
+#define ADAU1701_SAFELOAD_ADDR(i) (0x0815 + (i))
+
+#define ADAU1701_DSPCTRL	0x081c
+#define ADAU1701_SEROCTL	0x081e
+#define ADAU1701_SERICTL	0x081f
+
+#define ADAU1701_AUXNPOW	0x0822
+#define ADAU1701_PINCONF_0	0x0820
+#define ADAU1701_PINCONF_1	0x0821
+#define ADAU1701_AUXNPOW	0x0822
+
+#define ADAU1701_OSCIPOW	0x0826
+#define ADAU1701_DACSET		0x0827
+
+#define ADAU1701_MAX_REGISTER	0x0828
+
+#define ADAU1701_DSPCTRL_CR		(1 << 2)
+#define ADAU1701_DSPCTRL_DAM		(1 << 3)
+#define ADAU1701_DSPCTRL_ADM		(1 << 4)
+#define ADAU1701_DSPCTRL_IST		(1 << 5)
+#define ADAU1701_DSPCTRL_SR_48		0x00
+#define ADAU1701_DSPCTRL_SR_96		0x01
+#define ADAU1701_DSPCTRL_SR_192		0x02
+#define ADAU1701_DSPCTRL_SR_MASK	0x03
+
+#define ADAU1701_SEROCTL_INV_LRCLK	0x2000
+#define ADAU1701_SEROCTL_INV_BCLK	0x1000
+#define ADAU1701_SEROCTL_MASTER		0x0800
+
+#define ADAU1701_SEROCTL_OBF16		0x0000
+#define ADAU1701_SEROCTL_OBF8		0x0200
+#define ADAU1701_SEROCTL_OBF4		0x0400
+#define ADAU1701_SEROCTL_OBF2		0x0600
+#define ADAU1701_SEROCTL_OBF_MASK	0x0600
+
+#define ADAU1701_SEROCTL_OLF1024	0x0000
+#define ADAU1701_SEROCTL_OLF512		0x0080
+#define ADAU1701_SEROCTL_OLF256		0x0100
+#define ADAU1701_SEROCTL_OLF_MASK	0x0180
+
+#define ADAU1701_SEROCTL_MSB_DEALY1	0x0000
+#define ADAU1701_SEROCTL_MSB_DEALY0	0x0004
+#define ADAU1701_SEROCTL_MSB_DEALY8	0x0008
+#define ADAU1701_SEROCTL_MSB_DEALY12	0x000c
+#define ADAU1701_SEROCTL_MSB_DEALY16	0x0010
+#define ADAU1701_SEROCTL_MSB_DEALY_MASK	0x001c
+
+#define ADAU1701_SEROCTL_WORD_LEN_24	0x0000
+#define ADAU1701_SEROCTL_WORD_LEN_20	0x0001
+#define ADAU1701_SEROCTL_WORD_LEN_16	0x0002
+#define ADAU1701_SEROCTL_WORD_LEN_MASK	0x0003
+
+#define ADAU1701_AUXNPOW_VBPD		0x40
+#define ADAU1701_AUXNPOW_VRPD		0x20
+
+#define ADAU1701_SERICTL_I2S		0
+#define ADAU1701_SERICTL_LEFTJ		1
+#define ADAU1701_SERICTL_TDM		2
+#define ADAU1701_SERICTL_RIGHTJ_24	3
+#define ADAU1701_SERICTL_RIGHTJ_20	4
+#define ADAU1701_SERICTL_RIGHTJ_18	5
+#define ADAU1701_SERICTL_RIGHTJ_16	6
+#define ADAU1701_SERICTL_MODE_MASK	7
+#define ADAU1701_SERICTL_INV_BCLK	BIT(3)
+#define ADAU1701_SERICTL_INV_LRCLK	BIT(4)
+
+#define ADAU1701_OSCIPOW_OPD		0x04
+#define ADAU1701_DACSET_DACINIT		1
+
+#define ADAU1707_CLKDIV_UNSET		(-1U)
+
+#define ADAU1701_FIRMWARE "adau1701.bin"
+
+static const char * const supply_names[] = {
+	"dvdd", "avdd"
+};
+
+struct adau1701 {
+	int gpio_nreset;
+	int gpio_pll_mode[2];
+	unsigned int dai_fmt;
+	unsigned int pll_clkdiv;
+	unsigned int sysclk;
+	struct regmap *regmap;
+	struct i2c_client *client;
+	u8 pin_config[12];
+
+	struct sigmadsp *sigmadsp;
+	struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+};
+
+static const struct snd_kcontrol_new adau1701_controls[] = {
+	SOC_SINGLE("Master Capture Switch", ADAU1701_DSPCTRL, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget adau1701_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC0", "Playback", ADAU1701_AUXNPOW, 3, 1),
+	SND_SOC_DAPM_DAC("DAC1", "Playback", ADAU1701_AUXNPOW, 2, 1),
+	SND_SOC_DAPM_DAC("DAC2", "Playback", ADAU1701_AUXNPOW, 1, 1),
+	SND_SOC_DAPM_DAC("DAC3", "Playback", ADAU1701_AUXNPOW, 0, 1),
+	SND_SOC_DAPM_ADC("ADC", "Capture", ADAU1701_AUXNPOW, 7, 1),
+
+	SND_SOC_DAPM_OUTPUT("OUT0"),
+	SND_SOC_DAPM_OUTPUT("OUT1"),
+	SND_SOC_DAPM_OUTPUT("OUT2"),
+	SND_SOC_DAPM_OUTPUT("OUT3"),
+	SND_SOC_DAPM_INPUT("IN0"),
+	SND_SOC_DAPM_INPUT("IN1"),
+};
+
+static const struct snd_soc_dapm_route adau1701_dapm_routes[] = {
+	{ "OUT0", NULL, "DAC0" },
+	{ "OUT1", NULL, "DAC1" },
+	{ "OUT2", NULL, "DAC2" },
+	{ "OUT3", NULL, "DAC3" },
+
+	{ "ADC", NULL, "IN0" },
+	{ "ADC", NULL, "IN1" },
+};
+
+static unsigned int adau1701_register_size(struct device *dev,
+		unsigned int reg)
+{
+	switch (reg) {
+	case ADAU1701_PINCONF_0:
+	case ADAU1701_PINCONF_1:
+		return 3;
+	case ADAU1701_DSPCTRL:
+	case ADAU1701_SEROCTL:
+	case ADAU1701_AUXNPOW:
+	case ADAU1701_OSCIPOW:
+	case ADAU1701_DACSET:
+		return 2;
+	case ADAU1701_SERICTL:
+		return 1;
+	}
+
+	dev_err(dev, "Unsupported register address: %d\n", reg);
+	return 0;
+}
+
+static bool adau1701_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case ADAU1701_DACSET:
+	case ADAU1701_DSPCTRL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int adau1701_reg_write(void *context, unsigned int reg,
+			      unsigned int value)
+{
+	struct i2c_client *client = context;
+	unsigned int i;
+	unsigned int size;
+	uint8_t buf[5];
+	int ret;
+
+	size = adau1701_register_size(&client->dev, reg);
+	if (size == 0)
+		return -EINVAL;
+
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xff;
+
+	for (i = size + 1; i >= 2; --i) {
+		buf[i] = value;
+		value >>= 8;
+	}
+
+	ret = i2c_master_send(client, buf, size + 2);
+	if (ret == size + 2)
+		return 0;
+	else if (ret < 0)
+		return ret;
+	else
+		return -EIO;
+}
+
+static int adau1701_reg_read(void *context, unsigned int reg,
+			     unsigned int *value)
+{
+	int ret;
+	unsigned int i;
+	unsigned int size;
+	uint8_t send_buf[2], recv_buf[3];
+	struct i2c_client *client = context;
+	struct i2c_msg msgs[2];
+
+	size = adau1701_register_size(&client->dev, reg);
+	if (size == 0)
+		return -EINVAL;
+
+	send_buf[0] = reg >> 8;
+	send_buf[1] = reg & 0xff;
+
+	msgs[0].addr = client->addr;
+	msgs[0].len = sizeof(send_buf);
+	msgs[0].buf = send_buf;
+	msgs[0].flags = 0;
+
+	msgs[1].addr = client->addr;
+	msgs[1].len = size;
+	msgs[1].buf = recv_buf;
+	msgs[1].flags = I2C_M_RD;
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0)
+		return ret;
+	else if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	*value = 0;
+
+	for (i = 0; i < size; i++) {
+		*value <<= 8;
+		*value |= recv_buf[i];
+	}
+
+	return 0;
+}
+
+static int adau1701_safeload(struct sigmadsp *sigmadsp, unsigned int addr,
+	const uint8_t bytes[], size_t len)
+{
+	struct i2c_client *client = to_i2c_client(sigmadsp->dev);
+	struct adau1701 *adau1701 = i2c_get_clientdata(client);
+	unsigned int val;
+	unsigned int i;
+	uint8_t buf[10];
+	int ret;
+
+	ret = regmap_read(adau1701->regmap, ADAU1701_DSPCTRL, &val);
+	if (ret)
+		return ret;
+
+	if (val & ADAU1701_DSPCTRL_IST)
+		msleep(50);
+
+	for (i = 0; i < len / 4; i++) {
+		put_unaligned_le16(ADAU1701_SAFELOAD_DATA(i), buf);
+		buf[2] = 0x00;
+		memcpy(buf + 3, bytes + i * 4, 4);
+		ret = i2c_master_send(client, buf, 7);
+		if (ret < 0)
+			return ret;
+		else if (ret != 7)
+			return -EIO;
+
+		put_unaligned_le16(ADAU1701_SAFELOAD_ADDR(i), buf);
+		put_unaligned_le16(addr + i, buf + 2);
+		ret = i2c_master_send(client, buf, 4);
+		if (ret < 0)
+			return ret;
+		else if (ret != 4)
+			return -EIO;
+	}
+
+	return regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL,
+		ADAU1701_DSPCTRL_IST, ADAU1701_DSPCTRL_IST);
+}
+
+static const struct sigmadsp_ops adau1701_sigmadsp_ops = {
+	.safeload = adau1701_safeload,
+};
+
+static int adau1701_reset(struct snd_soc_component *component, unsigned int clkdiv,
+	unsigned int rate)
+{
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	sigmadsp_reset(adau1701->sigmadsp);
+
+	if (clkdiv != ADAU1707_CLKDIV_UNSET &&
+	    gpio_is_valid(adau1701->gpio_pll_mode[0]) &&
+	    gpio_is_valid(adau1701->gpio_pll_mode[1])) {
+		switch (clkdiv) {
+		case 64:
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0);
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0);
+			break;
+		case 256:
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0);
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1);
+			break;
+		case 384:
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1);
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0);
+			break;
+		case 0:	/* fallback */
+		case 512:
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1);
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1);
+			break;
+		}
+	}
+
+	adau1701->pll_clkdiv = clkdiv;
+
+	if (gpio_is_valid(adau1701->gpio_nreset)) {
+		gpio_set_value_cansleep(adau1701->gpio_nreset, 0);
+		/* minimum reset time is 20ns */
+		udelay(1);
+		gpio_set_value_cansleep(adau1701->gpio_nreset, 1);
+		/* power-up time may be as long as 85ms */
+		mdelay(85);
+	}
+
+	/*
+	 * Postpone the firmware download to a point in time when we
+	 * know the correct PLL setup
+	 */
+	if (clkdiv != ADAU1707_CLKDIV_UNSET) {
+		ret = sigmadsp_setup(adau1701->sigmadsp, rate);
+		if (ret) {
+			dev_warn(component->dev, "Failed to load firmware\n");
+			return ret;
+		}
+	}
+
+	regmap_write(adau1701->regmap, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT);
+	regmap_write(adau1701->regmap, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
+
+	regcache_mark_dirty(adau1701->regmap);
+	regcache_sync(adau1701->regmap);
+
+	return 0;
+}
+
+static int adau1701_set_capture_pcm_format(struct snd_soc_component *component,
+					   struct snd_pcm_hw_params *params)
+{
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
+	unsigned int mask = ADAU1701_SEROCTL_WORD_LEN_MASK;
+	unsigned int val;
+
+	switch (params_width(params)) {
+	case 16:
+		val = ADAU1701_SEROCTL_WORD_LEN_16;
+		break;
+	case 20:
+		val = ADAU1701_SEROCTL_WORD_LEN_20;
+		break;
+	case 24:
+		val = ADAU1701_SEROCTL_WORD_LEN_24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (adau1701->dai_fmt == SND_SOC_DAIFMT_RIGHT_J) {
+		switch (params_width(params)) {
+		case 16:
+			val |= ADAU1701_SEROCTL_MSB_DEALY16;
+			break;
+		case 20:
+			val |= ADAU1701_SEROCTL_MSB_DEALY12;
+			break;
+		case 24:
+			val |= ADAU1701_SEROCTL_MSB_DEALY8;
+			break;
+		}
+		mask |= ADAU1701_SEROCTL_MSB_DEALY_MASK;
+	}
+
+	regmap_update_bits(adau1701->regmap, ADAU1701_SEROCTL, mask, val);
+
+	return 0;
+}
+
+static int adau1701_set_playback_pcm_format(struct snd_soc_component *component,
+					    struct snd_pcm_hw_params *params)
+{
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	if (adau1701->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
+		return 0;
+
+	switch (params_width(params)) {
+	case 16:
+		val = ADAU1701_SERICTL_RIGHTJ_16;
+		break;
+	case 20:
+		val = ADAU1701_SERICTL_RIGHTJ_20;
+		break;
+	case 24:
+		val = ADAU1701_SERICTL_RIGHTJ_24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(adau1701->regmap, ADAU1701_SERICTL,
+		ADAU1701_SERICTL_MODE_MASK, val);
+
+	return 0;
+}
+
+static int adau1701_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
+	unsigned int clkdiv = adau1701->sysclk / params_rate(params);
+	unsigned int val;
+	int ret;
+
+	/*
+	 * If the mclk/lrclk ratio changes, the chip needs updated PLL
+	 * mode GPIO settings, and a full reset cycle, including a new
+	 * firmware upload.
+	 */
+	if (clkdiv != adau1701->pll_clkdiv) {
+		ret = adau1701_reset(component, clkdiv, params_rate(params));
+		if (ret < 0)
+			return ret;
+	}
+
+	switch (params_rate(params)) {
+	case 192000:
+		val = ADAU1701_DSPCTRL_SR_192;
+		break;
+	case 96000:
+		val = ADAU1701_DSPCTRL_SR_96;
+		break;
+	case 48000:
+		val = ADAU1701_DSPCTRL_SR_48;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL,
+		ADAU1701_DSPCTRL_SR_MASK, val);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return adau1701_set_playback_pcm_format(component, params);
+	else
+		return adau1701_set_capture_pcm_format(component, params);
+}
+
+static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
+	unsigned int serictl = 0x00, seroctl = 0x00;
+	bool invert_lrclk;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* master, 64-bits per sample, 1 frame per sample */
+		seroctl |= ADAU1701_SEROCTL_MASTER | ADAU1701_SEROCTL_OBF16
+				| ADAU1701_SEROCTL_OLF1024;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		invert_lrclk = false;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		invert_lrclk = true;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		invert_lrclk = false;
+		serictl |= ADAU1701_SERICTL_INV_BCLK;
+		seroctl |= ADAU1701_SEROCTL_INV_BCLK;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		invert_lrclk = true;
+		serictl |= ADAU1701_SERICTL_INV_BCLK;
+		seroctl |= ADAU1701_SEROCTL_INV_BCLK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		serictl |= ADAU1701_SERICTL_LEFTJ;
+		seroctl |= ADAU1701_SEROCTL_MSB_DEALY0;
+		invert_lrclk = !invert_lrclk;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		serictl |= ADAU1701_SERICTL_RIGHTJ_24;
+		seroctl |= ADAU1701_SEROCTL_MSB_DEALY8;
+		invert_lrclk = !invert_lrclk;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (invert_lrclk) {
+		seroctl |= ADAU1701_SEROCTL_INV_LRCLK;
+		serictl |= ADAU1701_SERICTL_INV_LRCLK;
+	}
+
+	adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+	regmap_write(adau1701->regmap, ADAU1701_SERICTL, serictl);
+	regmap_update_bits(adau1701->regmap, ADAU1701_SEROCTL,
+		~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl);
+
+	return 0;
+}
+
+static int adau1701_set_bias_level(struct snd_soc_component *component,
+		enum snd_soc_bias_level level)
+{
+	unsigned int mask = ADAU1701_AUXNPOW_VBPD | ADAU1701_AUXNPOW_VRPD;
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* Enable VREF and VREF buffer */
+		regmap_update_bits(adau1701->regmap,
+				   ADAU1701_AUXNPOW, mask, 0x00);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* Disable VREF and VREF buffer */
+		regmap_update_bits(adau1701->regmap,
+				   ADAU1701_AUXNPOW, mask, mask);
+		break;
+	}
+
+	return 0;
+}
+
+static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int mask = ADAU1701_DSPCTRL_DAM;
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	if (mute)
+		val = 0;
+	else
+		val = mask;
+
+	regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL, mask, val);
+
+	return 0;
+}
+
+static int adau1701_set_sysclk(struct snd_soc_component *component, int clk_id,
+	int source, unsigned int freq, int dir)
+{
+	unsigned int val;
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case ADAU1701_CLK_SRC_OSC:
+		val = 0x0;
+		break;
+	case ADAU1701_CLK_SRC_MCLK:
+		val = ADAU1701_OSCIPOW_OPD;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(adau1701->regmap, ADAU1701_OSCIPOW,
+			   ADAU1701_OSCIPOW_OPD, val);
+	adau1701->sysclk = freq;
+
+	return 0;
+}
+
+static int adau1701_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(dai->component);
+
+	return sigmadsp_restrict_params(adau1701->sigmadsp, substream);
+}
+
+#define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
+	SNDRV_PCM_RATE_192000)
+
+#define ADAU1701_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops adau1701_dai_ops = {
+	.set_fmt	= adau1701_set_dai_fmt,
+	.hw_params	= adau1701_hw_params,
+	.digital_mute	= adau1701_digital_mute,
+	.startup	= adau1701_startup,
+};
+
+static struct snd_soc_dai_driver adau1701_dai = {
+	.name = "adau1701",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = ADAU1701_RATES,
+		.formats = ADAU1701_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = ADAU1701_RATES,
+		.formats = ADAU1701_FORMATS,
+	},
+	.ops = &adau1701_dai_ops,
+	.symmetric_rates = 1,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id adau1701_dt_ids[] = {
+	{ .compatible = "adi,adau1701", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adau1701_dt_ids);
+#endif
+
+static int adau1701_probe(struct snd_soc_component *component)
+{
+	int i, ret;
+	unsigned int val;
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
+
+	ret = sigmadsp_attach(adau1701->sigmadsp, component);
+	if (ret)
+		return ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
+				    adau1701->supplies);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to enable regulators: %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * Let the pll_clkdiv variable default to something that won't happen
+	 * at runtime. That way, we can postpone the firmware download from
+	 * adau1701_reset() to a point in time when we know the correct PLL
+	 * mode parameters.
+	 */
+	adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET;
+
+	/* initalize with pre-configured pll mode settings */
+	ret = adau1701_reset(component, adau1701->pll_clkdiv, 0);
+	if (ret < 0)
+		goto exit_regulators_disable;
+
+	/* set up pin config */
+	val = 0;
+	for (i = 0; i < 6; i++)
+		val |= adau1701->pin_config[i] << (i * 4);
+
+	regmap_write(adau1701->regmap, ADAU1701_PINCONF_0, val);
+
+	val = 0;
+	for (i = 0; i < 6; i++)
+		val |= adau1701->pin_config[i + 6] << (i * 4);
+
+	regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val);
+
+	return 0;
+
+exit_regulators_disable:
+
+	regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
+	return ret;
+}
+
+static void adau1701_remove(struct snd_soc_component *component)
+{
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
+
+	if (gpio_is_valid(adau1701->gpio_nreset))
+		gpio_set_value_cansleep(adau1701->gpio_nreset, 0);
+
+	regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
+}
+
+#ifdef CONFIG_PM
+static int adau1701_suspend(struct snd_soc_component *component)
+{
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
+
+	regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies),
+			       adau1701->supplies);
+
+	return 0;
+}
+
+static int adau1701_resume(struct snd_soc_component *component)
+{
+	struct adau1701 *adau1701 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+        ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
+				    adau1701->supplies);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to enable regulators: %d\n", ret);
+		return ret;
+	}
+
+	return adau1701_reset(component, adau1701->pll_clkdiv, 0);
+}
+#else
+#define adau1701_resume 	NULL
+#define adau1701_suspend 	NULL
+#endif /* CONFIG_PM */
+
+static const struct snd_soc_component_driver adau1701_component_drv = {
+	.probe			= adau1701_probe,
+	.remove			= adau1701_remove,
+	.resume			= adau1701_resume,
+	.suspend		= adau1701_suspend,
+	.set_bias_level		= adau1701_set_bias_level,
+	.controls		= adau1701_controls,
+	.num_controls		= ARRAY_SIZE(adau1701_controls),
+	.dapm_widgets		= adau1701_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(adau1701_dapm_widgets),
+	.dapm_routes		= adau1701_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(adau1701_dapm_routes),
+	.set_sysclk		= adau1701_set_sysclk,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config adau1701_regmap = {
+	.reg_bits		= 16,
+	.val_bits		= 32,
+	.max_register		= ADAU1701_MAX_REGISTER,
+	.cache_type		= REGCACHE_RBTREE,
+	.volatile_reg		= adau1701_volatile_reg,
+	.reg_write		= adau1701_reg_write,
+	.reg_read		= adau1701_reg_read,
+};
+
+static int adau1701_i2c_probe(struct i2c_client *client,
+			      const struct i2c_device_id *id)
+{
+	struct adau1701 *adau1701;
+	struct device *dev = &client->dev;
+	int gpio_nreset = -EINVAL;
+	int gpio_pll_mode[2] = { -EINVAL, -EINVAL };
+	int ret, i;
+
+	adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL);
+	if (!adau1701)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+		adau1701->supplies[i].supply = supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(adau1701->supplies),
+			adau1701->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to get regulators: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
+			adau1701->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable regulators: %d\n", ret);
+		return ret;
+	}
+
+	adau1701->client = client;
+	adau1701->regmap = devm_regmap_init(dev, NULL, client,
+					    &adau1701_regmap);
+	if (IS_ERR(adau1701->regmap)) {
+		ret = PTR_ERR(adau1701->regmap);
+		goto exit_regulators_disable;
+	}
+
+
+	if (dev->of_node) {
+		gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0);
+		if (gpio_nreset < 0 && gpio_nreset != -ENOENT) {
+			ret = gpio_nreset;
+			goto exit_regulators_disable;
+		}
+
+		gpio_pll_mode[0] = of_get_named_gpio(dev->of_node,
+						   "adi,pll-mode-gpios", 0);
+		if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) {
+			ret = gpio_pll_mode[0];
+			goto exit_regulators_disable;
+		}
+
+		gpio_pll_mode[1] = of_get_named_gpio(dev->of_node,
+						   "adi,pll-mode-gpios", 1);
+		if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) {
+			ret = gpio_pll_mode[1];
+			goto exit_regulators_disable;
+		}
+
+		of_property_read_u32(dev->of_node, "adi,pll-clkdiv",
+				     &adau1701->pll_clkdiv);
+
+		of_property_read_u8_array(dev->of_node, "adi,pin-config",
+					  adau1701->pin_config,
+					  ARRAY_SIZE(adau1701->pin_config));
+	}
+
+	if (gpio_is_valid(gpio_nreset)) {
+		ret = devm_gpio_request_one(dev, gpio_nreset, GPIOF_OUT_INIT_LOW,
+					    "ADAU1701 Reset");
+		if (ret < 0)
+			goto exit_regulators_disable;
+	}
+
+	if (gpio_is_valid(gpio_pll_mode[0]) &&
+	    gpio_is_valid(gpio_pll_mode[1])) {
+		ret = devm_gpio_request_one(dev, gpio_pll_mode[0],
+					    GPIOF_OUT_INIT_LOW,
+					    "ADAU1701 PLL mode 0");
+		if (ret < 0)
+			goto exit_regulators_disable;
+
+		ret = devm_gpio_request_one(dev, gpio_pll_mode[1],
+					    GPIOF_OUT_INIT_LOW,
+					    "ADAU1701 PLL mode 1");
+		if (ret < 0)
+			goto exit_regulators_disable;
+	}
+
+	adau1701->gpio_nreset = gpio_nreset;
+	adau1701->gpio_pll_mode[0] = gpio_pll_mode[0];
+	adau1701->gpio_pll_mode[1] = gpio_pll_mode[1];
+
+	i2c_set_clientdata(client, adau1701);
+
+	adau1701->sigmadsp = devm_sigmadsp_init_i2c(client,
+		&adau1701_sigmadsp_ops, ADAU1701_FIRMWARE);
+	if (IS_ERR(adau1701->sigmadsp)) {
+		ret = PTR_ERR(adau1701->sigmadsp);
+		goto exit_regulators_disable;
+	}
+
+	ret = devm_snd_soc_register_component(&client->dev,
+			&adau1701_component_drv,
+			&adau1701_dai, 1);
+
+exit_regulators_disable:
+
+	regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
+	return ret;
+}
+
+static const struct i2c_device_id adau1701_i2c_id[] = {
+	{ "adau1401", 0 },
+	{ "adau1401a", 0 },
+	{ "adau1701", 0 },
+	{ "adau1702", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id);
+
+static struct i2c_driver adau1701_i2c_driver = {
+	.driver = {
+		.name	= "adau1701",
+		.of_match_table	= of_match_ptr(adau1701_dt_ids),
+	},
+	.probe		= adau1701_i2c_probe,
+	.id_table	= adau1701_i2c_id,
+};
+
+module_i2c_driver(adau1701_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1701 SigmaDSP driver");
+MODULE_AUTHOR("Cliff Cai <cliff.cai@analog.com>");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1701.h b/sound/soc/codecs/adau1701.h
new file mode 100644
index 0000000..8d0949a
--- /dev/null
+++ b/sound/soc/codecs/adau1701.h
@@ -0,0 +1,17 @@
+/*
+ * header file for ADAU1701 SigmaDSP processor
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ADAU1701_H
+#define _ADAU1701_H
+
+enum adau1701_clk_src {
+	ADAU1701_CLK_SRC_OSC,
+	ADAU1701_CLK_SRC_MCLK,
+};
+
+#endif
diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c
new file mode 100644
index 0000000..9e7f257
--- /dev/null
+++ b/sound/soc/codecs/adau1761-i2c.c
@@ -0,0 +1,71 @@
+/*
+ * Driver for ADAU1361/ADAU1461/ADAU1761/ADAU1961 codec
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "adau1761.h"
+
+static int adau1761_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct regmap_config config;
+
+	config = adau1761_regmap_config;
+	config.val_bits = 8;
+	config.reg_bits = 16;
+
+	return adau1761_probe(&client->dev,
+		devm_regmap_init_i2c(client, &config),
+		id->driver_data, NULL);
+}
+
+static int adau1761_i2c_remove(struct i2c_client *client)
+{
+	adau17x1_remove(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id adau1761_i2c_ids[] = {
+	{ "adau1361", ADAU1361 },
+	{ "adau1461", ADAU1761 },
+	{ "adau1761", ADAU1761 },
+	{ "adau1961", ADAU1361 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adau1761_i2c_ids);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id adau1761_i2c_dt_ids[] = {
+	{ .compatible = "adi,adau1361", },
+	{ .compatible = "adi,adau1461", },
+	{ .compatible = "adi,adau1761", },
+	{ .compatible = "adi,adau1961", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, adau1761_i2c_dt_ids);
+#endif
+
+static struct i2c_driver adau1761_i2c_driver = {
+	.driver = {
+		.name = "adau1761",
+		.of_match_table = of_match_ptr(adau1761_i2c_dt_ids),
+	},
+	.probe = adau1761_i2c_probe,
+	.remove = adau1761_i2c_remove,
+	.id_table = adau1761_i2c_ids,
+};
+module_i2c_driver(adau1761_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC I2C driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1761-spi.c b/sound/soc/codecs/adau1761-spi.c
new file mode 100644
index 0000000..a0b214b
--- /dev/null
+++ b/sound/soc/codecs/adau1761-spi.c
@@ -0,0 +1,88 @@
+/*
+ * Driver for ADAU1361/ADAU1461/ADAU1761/ADAU1961 codec
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include "adau1761.h"
+
+static void adau1761_spi_switch_mode(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+
+	/*
+	 * To get the device into SPI mode CLATCH has to be pulled low three
+	 * times.  Do this by issuing three dummy reads.
+	 */
+	spi_w8r8(spi, 0x00);
+	spi_w8r8(spi, 0x00);
+	spi_w8r8(spi, 0x00);
+}
+
+static int adau1761_spi_probe(struct spi_device *spi)
+{
+	const struct spi_device_id *id = spi_get_device_id(spi);
+	struct regmap_config config;
+
+	if (!id)
+		return -EINVAL;
+
+	config = adau1761_regmap_config;
+	config.val_bits = 8;
+	config.reg_bits = 24;
+	config.read_flag_mask = 0x1;
+
+	return adau1761_probe(&spi->dev,
+		devm_regmap_init_spi(spi, &config),
+		id->driver_data, adau1761_spi_switch_mode);
+}
+
+static int adau1761_spi_remove(struct spi_device *spi)
+{
+	adau17x1_remove(&spi->dev);
+	return 0;
+}
+
+static const struct spi_device_id adau1761_spi_id[] = {
+	{ "adau1361", ADAU1361 },
+	{ "adau1461", ADAU1761 },
+	{ "adau1761", ADAU1761 },
+	{ "adau1961", ADAU1361 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, adau1761_spi_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id adau1761_spi_dt_ids[] = {
+	{ .compatible = "adi,adau1361", },
+	{ .compatible = "adi,adau1461", },
+	{ .compatible = "adi,adau1761", },
+	{ .compatible = "adi,adau1961", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, adau1761_spi_dt_ids);
+#endif
+
+static struct spi_driver adau1761_spi_driver = {
+	.driver = {
+		.name = "adau1761",
+		.of_match_table = of_match_ptr(adau1761_spi_dt_ids),
+	},
+	.probe = adau1761_spi_probe,
+	.remove = adau1761_spi_remove,
+	.id_table = adau1761_spi_id,
+};
+module_spi_driver(adau1761_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC SPI driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c
new file mode 100644
index 0000000..be136e9
--- /dev/null
+++ b/sound/soc/codecs/adau1761.c
@@ -0,0 +1,817 @@
+/*
+ * Driver for ADAU1361/ADAU1461/ADAU1761/ADAU1961 codec
+ *
+ * Copyright 2011-2013 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/platform_data/adau17x1.h>
+
+#include "adau17x1.h"
+#include "adau1761.h"
+
+#define ADAU1761_DIGMIC_JACKDETECT	0x4008
+#define ADAU1761_REC_MIXER_LEFT0	0x400a
+#define ADAU1761_REC_MIXER_LEFT1	0x400b
+#define ADAU1761_REC_MIXER_RIGHT0	0x400c
+#define ADAU1761_REC_MIXER_RIGHT1	0x400d
+#define ADAU1761_LEFT_DIFF_INPUT_VOL	0x400e
+#define ADAU1761_RIGHT_DIFF_INPUT_VOL	0x400f
+#define ADAU1761_PLAY_LR_MIXER_LEFT	0x4020
+#define ADAU1761_PLAY_MIXER_LEFT0	0x401c
+#define ADAU1761_PLAY_MIXER_LEFT1	0x401d
+#define ADAU1761_PLAY_MIXER_RIGHT0	0x401e
+#define ADAU1761_PLAY_MIXER_RIGHT1	0x401f
+#define ADAU1761_PLAY_LR_MIXER_RIGHT	0x4021
+#define ADAU1761_PLAY_MIXER_MONO	0x4022
+#define ADAU1761_PLAY_HP_LEFT_VOL	0x4023
+#define ADAU1761_PLAY_HP_RIGHT_VOL	0x4024
+#define ADAU1761_PLAY_LINE_LEFT_VOL	0x4025
+#define ADAU1761_PLAY_LINE_RIGHT_VOL	0x4026
+#define ADAU1761_PLAY_MONO_OUTPUT_VOL	0x4027
+#define ADAU1761_POP_CLICK_SUPPRESS	0x4028
+#define ADAU1761_JACK_DETECT_PIN	0x4031
+#define ADAU1761_DEJITTER		0x4036
+#define ADAU1761_CLK_ENABLE0		0x40f9
+#define ADAU1761_CLK_ENABLE1		0x40fa
+
+#define ADAU1761_DIGMIC_JACKDETECT_ACTIVE_LOW	BIT(0)
+#define ADAU1761_DIGMIC_JACKDETECT_DIGMIC	BIT(5)
+
+#define ADAU1761_DIFF_INPUT_VOL_LDEN		BIT(0)
+
+#define ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP	BIT(0)
+#define ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE	BIT(1)
+
+#define ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP	BIT(0)
+
+#define ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP	BIT(0)
+
+#define ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP	BIT(0)
+
+
+#define ADAU1761_FIRMWARE "adau1761.bin"
+
+static const struct reg_default adau1761_reg_defaults[] = {
+	{ ADAU1761_DEJITTER,			0x03 },
+	{ ADAU1761_DIGMIC_JACKDETECT,		0x00 },
+	{ ADAU1761_REC_MIXER_LEFT0,		0x00 },
+	{ ADAU1761_REC_MIXER_LEFT1,		0x00 },
+	{ ADAU1761_REC_MIXER_RIGHT0,		0x00 },
+	{ ADAU1761_REC_MIXER_RIGHT1,		0x00 },
+	{ ADAU1761_LEFT_DIFF_INPUT_VOL,		0x00 },
+	{ ADAU1761_RIGHT_DIFF_INPUT_VOL,	0x00 },
+	{ ADAU1761_PLAY_LR_MIXER_LEFT,		0x00 },
+	{ ADAU1761_PLAY_MIXER_LEFT0,		0x00 },
+	{ ADAU1761_PLAY_MIXER_LEFT1,		0x00 },
+	{ ADAU1761_PLAY_MIXER_RIGHT0,		0x00 },
+	{ ADAU1761_PLAY_MIXER_RIGHT1,		0x00 },
+	{ ADAU1761_PLAY_LR_MIXER_RIGHT,		0x00 },
+	{ ADAU1761_PLAY_MIXER_MONO,		0x00 },
+	{ ADAU1761_PLAY_HP_LEFT_VOL,		0x00 },
+	{ ADAU1761_PLAY_HP_RIGHT_VOL,		0x00 },
+	{ ADAU1761_PLAY_LINE_LEFT_VOL,		0x00 },
+	{ ADAU1761_PLAY_LINE_RIGHT_VOL,		0x00 },
+	{ ADAU1761_PLAY_MONO_OUTPUT_VOL,	0x00 },
+	{ ADAU1761_POP_CLICK_SUPPRESS,		0x00 },
+	{ ADAU1761_JACK_DETECT_PIN,		0x00 },
+	{ ADAU1761_CLK_ENABLE0,			0x00 },
+	{ ADAU1761_CLK_ENABLE1,			0x00 },
+	{ ADAU17X1_CLOCK_CONTROL,		0x00 },
+	{ ADAU17X1_PLL_CONTROL,			0x00 },
+	{ ADAU17X1_REC_POWER_MGMT,		0x00 },
+	{ ADAU17X1_MICBIAS,			0x00 },
+	{ ADAU17X1_SERIAL_PORT0,		0x00 },
+	{ ADAU17X1_SERIAL_PORT1,		0x00 },
+	{ ADAU17X1_CONVERTER0,			0x00 },
+	{ ADAU17X1_CONVERTER1,			0x00 },
+	{ ADAU17X1_LEFT_INPUT_DIGITAL_VOL,	0x00 },
+	{ ADAU17X1_RIGHT_INPUT_DIGITAL_VOL,	0x00 },
+	{ ADAU17X1_ADC_CONTROL,			0x00 },
+	{ ADAU17X1_PLAY_POWER_MGMT,		0x00 },
+	{ ADAU17X1_DAC_CONTROL0,		0x00 },
+	{ ADAU17X1_DAC_CONTROL1,		0x00 },
+	{ ADAU17X1_DAC_CONTROL2,		0x00 },
+	{ ADAU17X1_SERIAL_PORT_PAD,		0xaa },
+	{ ADAU17X1_CONTROL_PORT_PAD0,		0xaa },
+	{ ADAU17X1_CONTROL_PORT_PAD1,		0x00 },
+	{ ADAU17X1_DSP_SAMPLING_RATE,		0x01 },
+	{ ADAU17X1_SERIAL_INPUT_ROUTE,		0x00 },
+	{ ADAU17X1_SERIAL_OUTPUT_ROUTE,		0x00 },
+	{ ADAU17X1_DSP_ENABLE,			0x00 },
+	{ ADAU17X1_DSP_RUN,			0x00 },
+	{ ADAU17X1_SERIAL_SAMPLING_RATE,	0x00 },
+};
+
+static const DECLARE_TLV_DB_SCALE(adau1761_sing_in_tlv, -1500, 300, 1);
+static const DECLARE_TLV_DB_SCALE(adau1761_diff_in_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adau1761_out_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(adau1761_sidetone_tlv, -1800, 300, 1);
+static const DECLARE_TLV_DB_SCALE(adau1761_boost_tlv, -600, 600, 1);
+static const DECLARE_TLV_DB_SCALE(adau1761_pga_boost_tlv, -2000, 2000, 1);
+
+static const unsigned int adau1761_bias_select_values[] = {
+	0, 2, 3,
+};
+
+static const char * const adau1761_bias_select_text[] = {
+	"Normal operation", "Enhanced performance", "Power saving",
+};
+
+static const char * const adau1761_bias_select_extreme_text[] = {
+	"Normal operation", "Extreme power saving", "Enhanced performance",
+	"Power saving",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1761_adc_bias_enum,
+		ADAU17X1_REC_POWER_MGMT, 3, adau1761_bias_select_extreme_text);
+static SOC_ENUM_SINGLE_DECL(adau1761_hp_bias_enum,
+		ADAU17X1_PLAY_POWER_MGMT, 6, adau1761_bias_select_extreme_text);
+static SOC_ENUM_SINGLE_DECL(adau1761_dac_bias_enum,
+		ADAU17X1_PLAY_POWER_MGMT, 4, adau1761_bias_select_extreme_text);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_playback_bias_enum,
+		ADAU17X1_PLAY_POWER_MGMT, 2, 0x3, adau1761_bias_select_text,
+		adau1761_bias_select_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_capture_bias_enum,
+		ADAU17X1_REC_POWER_MGMT, 1, 0x3, adau1761_bias_select_text,
+		adau1761_bias_select_values);
+
+static const struct snd_kcontrol_new adau1761_jack_detect_controls[] = {
+	SOC_SINGLE("Speaker Auto-mute Switch", ADAU1761_DIGMIC_JACKDETECT,
+		4, 1, 0),
+};
+
+static const struct snd_kcontrol_new adau1761_differential_mode_controls[] = {
+	SOC_DOUBLE_R_TLV("Capture Volume", ADAU1761_LEFT_DIFF_INPUT_VOL,
+		ADAU1761_RIGHT_DIFF_INPUT_VOL, 2, 0x3f, 0,
+		adau1761_diff_in_tlv),
+	SOC_DOUBLE_R("Capture Switch", ADAU1761_LEFT_DIFF_INPUT_VOL,
+		ADAU1761_RIGHT_DIFF_INPUT_VOL, 1, 1, 0),
+
+	SOC_DOUBLE_R_TLV("PGA Boost Capture Volume", ADAU1761_REC_MIXER_LEFT1,
+		ADAU1761_REC_MIXER_RIGHT1, 3, 2, 0, adau1761_pga_boost_tlv),
+};
+
+static const struct snd_kcontrol_new adau1761_single_mode_controls[] = {
+	SOC_SINGLE_TLV("Input 1 Capture Volume", ADAU1761_REC_MIXER_LEFT0,
+		4, 7, 0, adau1761_sing_in_tlv),
+	SOC_SINGLE_TLV("Input 2 Capture Volume", ADAU1761_REC_MIXER_LEFT0,
+		1, 7, 0, adau1761_sing_in_tlv),
+	SOC_SINGLE_TLV("Input 3 Capture Volume", ADAU1761_REC_MIXER_RIGHT0,
+		4, 7, 0, adau1761_sing_in_tlv),
+	SOC_SINGLE_TLV("Input 4 Capture Volume", ADAU1761_REC_MIXER_RIGHT0,
+		1, 7, 0, adau1761_sing_in_tlv),
+};
+
+static const struct snd_kcontrol_new adau1761_controls[] = {
+	SOC_DOUBLE_R_TLV("Aux Capture Volume", ADAU1761_REC_MIXER_LEFT1,
+		ADAU1761_REC_MIXER_RIGHT1, 0, 7, 0, adau1761_sing_in_tlv),
+
+	SOC_DOUBLE_R_TLV("Headphone Playback Volume", ADAU1761_PLAY_HP_LEFT_VOL,
+		ADAU1761_PLAY_HP_RIGHT_VOL, 2, 0x3f, 0, adau1761_out_tlv),
+	SOC_DOUBLE_R("Headphone Playback Switch", ADAU1761_PLAY_HP_LEFT_VOL,
+		ADAU1761_PLAY_HP_RIGHT_VOL, 1, 1, 0),
+	SOC_DOUBLE_R_TLV("Lineout Playback Volume", ADAU1761_PLAY_LINE_LEFT_VOL,
+		ADAU1761_PLAY_LINE_RIGHT_VOL, 2, 0x3f, 0, adau1761_out_tlv),
+	SOC_DOUBLE_R("Lineout Playback Switch", ADAU1761_PLAY_LINE_LEFT_VOL,
+		ADAU1761_PLAY_LINE_RIGHT_VOL, 1, 1, 0),
+
+	SOC_ENUM("ADC Bias", adau1761_adc_bias_enum),
+	SOC_ENUM("DAC Bias", adau1761_dac_bias_enum),
+	SOC_ENUM("Capture Bias", adau1761_capture_bias_enum),
+	SOC_ENUM("Playback Bias", adau1761_playback_bias_enum),
+	SOC_ENUM("Headphone Bias", adau1761_hp_bias_enum),
+};
+
+static const struct snd_kcontrol_new adau1761_mono_controls[] = {
+	SOC_SINGLE_TLV("Mono Playback Volume", ADAU1761_PLAY_MONO_OUTPUT_VOL,
+		2, 0x3f, 0, adau1761_out_tlv),
+	SOC_SINGLE("Mono Playback Switch", ADAU1761_PLAY_MONO_OUTPUT_VOL,
+		1, 1, 0),
+};
+
+static const struct snd_kcontrol_new adau1761_left_mixer_controls[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Left DAC Switch",
+		ADAU1761_PLAY_MIXER_LEFT0, 5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("Right DAC Switch",
+		ADAU1761_PLAY_MIXER_LEFT0, 6, 1, 0),
+	SOC_DAPM_SINGLE_TLV("Aux Bypass Volume",
+		ADAU1761_PLAY_MIXER_LEFT0, 1, 8, 0, adau1761_sidetone_tlv),
+	SOC_DAPM_SINGLE_TLV("Right Bypass Volume",
+		ADAU1761_PLAY_MIXER_LEFT1, 4, 8, 0, adau1761_sidetone_tlv),
+	SOC_DAPM_SINGLE_TLV("Left Bypass Volume",
+		ADAU1761_PLAY_MIXER_LEFT1, 0, 8, 0, adau1761_sidetone_tlv),
+};
+
+static const struct snd_kcontrol_new adau1761_right_mixer_controls[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Left DAC Switch",
+		ADAU1761_PLAY_MIXER_RIGHT0, 5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("Right DAC Switch",
+		ADAU1761_PLAY_MIXER_RIGHT0, 6, 1, 0),
+	SOC_DAPM_SINGLE_TLV("Aux Bypass Volume",
+		ADAU1761_PLAY_MIXER_RIGHT0, 1, 8, 0, adau1761_sidetone_tlv),
+	SOC_DAPM_SINGLE_TLV("Right Bypass Volume",
+		ADAU1761_PLAY_MIXER_RIGHT1, 4, 8, 0, adau1761_sidetone_tlv),
+	SOC_DAPM_SINGLE_TLV("Left Bypass Volume",
+		ADAU1761_PLAY_MIXER_RIGHT1, 0, 8, 0, adau1761_sidetone_tlv),
+};
+
+static const struct snd_kcontrol_new adau1761_left_lr_mixer_controls[] = {
+	SOC_DAPM_SINGLE_TLV("Left Volume",
+		ADAU1761_PLAY_LR_MIXER_LEFT, 1, 2, 0, adau1761_boost_tlv),
+	SOC_DAPM_SINGLE_TLV("Right Volume",
+		ADAU1761_PLAY_LR_MIXER_LEFT, 3, 2, 0, adau1761_boost_tlv),
+};
+
+static const struct snd_kcontrol_new adau1761_right_lr_mixer_controls[] = {
+	SOC_DAPM_SINGLE_TLV("Left Volume",
+		ADAU1761_PLAY_LR_MIXER_RIGHT, 1, 2, 0, adau1761_boost_tlv),
+	SOC_DAPM_SINGLE_TLV("Right Volume",
+		ADAU1761_PLAY_LR_MIXER_RIGHT, 3, 2, 0, adau1761_boost_tlv),
+};
+
+static const char * const adau1761_input_mux_text[] = {
+	"ADC", "DMIC",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1761_input_mux_enum,
+	ADAU17X1_ADC_CONTROL, 2, adau1761_input_mux_text);
+
+static const struct snd_kcontrol_new adau1761_input_mux_control =
+	SOC_DAPM_ENUM("Input Select", adau1761_input_mux_enum);
+
+static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+
+	/* After any power changes have been made the dejitter circuit
+	 * has to be reinitialized. */
+	regmap_write(adau->regmap, ADAU1761_DEJITTER, 0);
+	if (!adau->master)
+		regmap_write(adau->regmap, ADAU1761_DEJITTER, 3);
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget adau1x61_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Left Input Mixer", ADAU1761_REC_MIXER_LEFT0, 0, 0,
+		NULL, 0),
+	SND_SOC_DAPM_MIXER("Right Input Mixer", ADAU1761_REC_MIXER_RIGHT0, 0, 0,
+		NULL, 0),
+
+	SOC_MIXER_ARRAY("Left Playback Mixer", ADAU1761_PLAY_MIXER_LEFT0,
+		0, 0, adau1761_left_mixer_controls),
+	SOC_MIXER_ARRAY("Right Playback Mixer", ADAU1761_PLAY_MIXER_RIGHT0,
+		0, 0, adau1761_right_mixer_controls),
+	SOC_MIXER_ARRAY("Left LR Playback Mixer", ADAU1761_PLAY_LR_MIXER_LEFT,
+		0, 0, adau1761_left_lr_mixer_controls),
+	SOC_MIXER_ARRAY("Right LR Playback Mixer", ADAU1761_PLAY_LR_MIXER_RIGHT,
+		0, 0, adau1761_right_lr_mixer_controls),
+
+	SND_SOC_DAPM_SUPPLY("Headphone", ADAU1761_PLAY_HP_LEFT_VOL,
+		0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("SYSCLK", 2, SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_POST("Dejitter fixup", adau1761_dejitter_fixup),
+
+	SND_SOC_DAPM_INPUT("LAUX"),
+	SND_SOC_DAPM_INPUT("RAUX"),
+	SND_SOC_DAPM_INPUT("LINP"),
+	SND_SOC_DAPM_INPUT("LINN"),
+	SND_SOC_DAPM_INPUT("RINP"),
+	SND_SOC_DAPM_INPUT("RINN"),
+
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+	SND_SOC_DAPM_OUTPUT("ROUT"),
+	SND_SOC_DAPM_OUTPUT("LHP"),
+	SND_SOC_DAPM_OUTPUT("RHP"),
+};
+
+static const struct snd_soc_dapm_widget adau1761_mono_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Mono Playback Mixer", ADAU1761_PLAY_MIXER_MONO,
+		0, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("MONOOUT"),
+};
+
+static const struct snd_soc_dapm_widget adau1761_capless_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY_S("Headphone VGND", 1, ADAU1761_PLAY_MIXER_MONO,
+		0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route adau1x61_dapm_routes[] = {
+	{ "Left Input Mixer", NULL, "LINP" },
+	{ "Left Input Mixer", NULL, "LINN" },
+	{ "Left Input Mixer", NULL, "LAUX" },
+
+	{ "Right Input Mixer", NULL, "RINP" },
+	{ "Right Input Mixer", NULL, "RINN" },
+	{ "Right Input Mixer", NULL, "RAUX" },
+
+	{ "Left Playback Mixer", NULL, "Left Playback Enable"},
+	{ "Right Playback Mixer", NULL, "Right Playback Enable"},
+	{ "Left LR Playback Mixer", NULL, "Left Playback Enable"},
+	{ "Right LR Playback Mixer", NULL, "Right Playback Enable"},
+
+	{ "Left Playback Mixer", "Left DAC Switch", "Left DAC" },
+	{ "Left Playback Mixer", "Right DAC Switch", "Right DAC" },
+
+	{ "Right Playback Mixer", "Left DAC Switch", "Left DAC" },
+	{ "Right Playback Mixer", "Right DAC Switch", "Right DAC" },
+
+	{ "Left LR Playback Mixer", "Left Volume", "Left Playback Mixer" },
+	{ "Left LR Playback Mixer", "Right Volume", "Right Playback Mixer" },
+
+	{ "Right LR Playback Mixer", "Left Volume", "Left Playback Mixer" },
+	{ "Right LR Playback Mixer", "Right Volume", "Right Playback Mixer" },
+
+	{ "LHP", NULL, "Left Playback Mixer" },
+	{ "RHP", NULL, "Right Playback Mixer" },
+
+	{ "LHP", NULL, "Headphone" },
+	{ "RHP", NULL, "Headphone" },
+
+	{ "LOUT", NULL, "Left LR Playback Mixer" },
+	{ "ROUT", NULL, "Right LR Playback Mixer" },
+
+	{ "Left Playback Mixer", "Aux Bypass Volume", "LAUX" },
+	{ "Left Playback Mixer", "Left Bypass Volume", "Left Input Mixer" },
+	{ "Left Playback Mixer", "Right Bypass Volume", "Right Input Mixer" },
+	{ "Right Playback Mixer", "Aux Bypass Volume", "RAUX" },
+	{ "Right Playback Mixer", "Left Bypass Volume", "Left Input Mixer" },
+	{ "Right Playback Mixer", "Right Bypass Volume", "Right Input Mixer" },
+};
+
+static const struct snd_soc_dapm_route adau1761_mono_dapm_routes[] = {
+	{ "Mono Playback Mixer", NULL, "Left Playback Mixer" },
+	{ "Mono Playback Mixer", NULL, "Right Playback Mixer" },
+
+	{ "MONOOUT", NULL, "Mono Playback Mixer" },
+};
+
+static const struct snd_soc_dapm_route adau1761_capless_dapm_routes[] = {
+	{ "Headphone", NULL, "Headphone VGND" },
+};
+
+static const struct snd_soc_dapm_widget adau1761_dmic_widgets[] = {
+	SND_SOC_DAPM_MUX("Left Decimator Mux", SND_SOC_NOPM, 0, 0,
+		&adau1761_input_mux_control),
+	SND_SOC_DAPM_MUX("Right Decimator Mux", SND_SOC_NOPM, 0, 0,
+		&adau1761_input_mux_control),
+
+	SND_SOC_DAPM_INPUT("DMIC"),
+};
+
+static const struct snd_soc_dapm_route adau1761_dmic_routes[] = {
+	{ "Left Decimator Mux", "ADC", "Left Input Mixer" },
+	{ "Left Decimator Mux", "DMIC", "DMIC" },
+	{ "Right Decimator Mux", "ADC", "Right Input Mixer" },
+	{ "Right Decimator Mux", "DMIC", "DMIC" },
+
+	{ "Left Decimator", NULL, "Left Decimator Mux" },
+	{ "Right Decimator", NULL, "Right Decimator Mux" },
+};
+
+static const struct snd_soc_dapm_route adau1761_no_dmic_routes[] = {
+	{ "Left Decimator", NULL, "Left Input Mixer" },
+	{ "Right Decimator", NULL, "Right Input Mixer" },
+};
+
+static const struct snd_soc_dapm_widget adau1761_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("Serial Port Clock", ADAU1761_CLK_ENABLE0,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Serial Input Routing Clock", ADAU1761_CLK_ENABLE0,
+		1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Serial Output Routing Clock", ADAU1761_CLK_ENABLE0,
+		3, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Decimator Resync Clock", ADAU1761_CLK_ENABLE0,
+		4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Interpolator Resync Clock", ADAU1761_CLK_ENABLE0,
+		2, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Slew Clock", ADAU1761_CLK_ENABLE0, 6, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ALC Clock", ADAU1761_CLK_ENABLE0, 5, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("Digital Clock 0", 1, ADAU1761_CLK_ENABLE1,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("Digital Clock 1", 1, ADAU1761_CLK_ENABLE1,
+		1, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route adau1761_dapm_routes[] = {
+	{ "Left Decimator", NULL, "Digital Clock 0", },
+	{ "Right Decimator", NULL, "Digital Clock 0", },
+	{ "Left DAC", NULL, "Digital Clock 0", },
+	{ "Right DAC", NULL, "Digital Clock 0", },
+
+	{ "AIFCLK", NULL, "Digital Clock 1" },
+
+	{ "Playback", NULL, "Serial Port Clock" },
+	{ "Capture", NULL, "Serial Port Clock" },
+	{ "Playback", NULL, "Serial Input Routing Clock" },
+	{ "Capture", NULL, "Serial Output Routing Clock" },
+
+	{ "Left Decimator", NULL, "Decimator Resync Clock" },
+	{ "Right Decimator", NULL, "Decimator Resync Clock" },
+	{ "Left DAC", NULL, "Interpolator Resync Clock" },
+	{ "Right DAC", NULL, "Interpolator Resync Clock" },
+
+	{ "DSP", NULL, "Digital Clock 0" },
+
+	{ "Slew Clock", NULL, "Digital Clock 0" },
+	{ "Right Playback Mixer", NULL, "Slew Clock" },
+	{ "Left Playback Mixer", NULL, "Slew Clock" },
+
+	{ "Left Input Mixer", NULL, "ALC Clock" },
+	{ "Right Input Mixer", NULL, "ALC Clock" },
+
+	{ "Digital Clock 0", NULL, "SYSCLK" },
+	{ "Digital Clock 1", NULL, "SYSCLK" },
+};
+
+static int adau1761_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		regcache_cache_only(adau->regmap, false);
+		regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
+			ADAU17X1_CLOCK_CONTROL_SYSCLK_EN,
+			ADAU17X1_CLOCK_CONTROL_SYSCLK_EN);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			regcache_sync(adau->regmap);
+		break;
+	case SND_SOC_BIAS_OFF:
+		regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
+			ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, 0);
+		regcache_cache_only(adau->regmap, true);
+		break;
+
+	}
+	return 0;
+}
+
+static enum adau1761_output_mode adau1761_get_lineout_mode(
+	struct snd_soc_component *component)
+{
+	struct adau1761_platform_data *pdata = component->dev->platform_data;
+
+	if (pdata)
+		return pdata->lineout_mode;
+
+	return ADAU1761_OUTPUT_MODE_LINE;
+}
+
+static int adau1761_setup_digmic_jackdetect(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau1761_platform_data *pdata = component->dev->platform_data;
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+	enum adau1761_digmic_jackdet_pin_mode mode;
+	unsigned int val = 0;
+	int ret;
+
+	if (pdata)
+		mode = pdata->digmic_jackdetect_pin_mode;
+	else
+		mode = ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE;
+
+	switch (mode) {
+	case ADAU1761_DIGMIC_JACKDET_PIN_MODE_JACKDETECT:
+		switch (pdata->jackdetect_debounce_time) {
+		case ADAU1761_JACKDETECT_DEBOUNCE_5MS:
+		case ADAU1761_JACKDETECT_DEBOUNCE_10MS:
+		case ADAU1761_JACKDETECT_DEBOUNCE_20MS:
+		case ADAU1761_JACKDETECT_DEBOUNCE_40MS:
+			val |= pdata->jackdetect_debounce_time << 6;
+			break;
+		default:
+			return -EINVAL;
+		}
+		if (pdata->jackdetect_active_low)
+			val |= ADAU1761_DIGMIC_JACKDETECT_ACTIVE_LOW;
+
+		ret = snd_soc_add_component_controls(component,
+			adau1761_jack_detect_controls,
+			ARRAY_SIZE(adau1761_jack_detect_controls));
+		if (ret)
+			return ret;
+	case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */
+		ret = snd_soc_dapm_add_routes(dapm, adau1761_no_dmic_routes,
+			ARRAY_SIZE(adau1761_no_dmic_routes));
+		if (ret)
+			return ret;
+		break;
+	case ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC:
+		ret = snd_soc_dapm_new_controls(dapm, adau1761_dmic_widgets,
+			ARRAY_SIZE(adau1761_dmic_widgets));
+		if (ret)
+			return ret;
+
+		ret = snd_soc_dapm_add_routes(dapm, adau1761_dmic_routes,
+			ARRAY_SIZE(adau1761_dmic_routes));
+		if (ret)
+			return ret;
+
+		val |= ADAU1761_DIGMIC_JACKDETECT_DIGMIC;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_write(adau->regmap, ADAU1761_DIGMIC_JACKDETECT, val);
+
+	return 0;
+}
+
+static int adau1761_setup_headphone_mode(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+	struct adau1761_platform_data *pdata = component->dev->platform_data;
+	enum adau1761_output_mode mode;
+	int ret;
+
+	if (pdata)
+		mode = pdata->headphone_mode;
+	else
+		mode = ADAU1761_OUTPUT_MODE_HEADPHONE;
+
+	switch (mode) {
+	case ADAU1761_OUTPUT_MODE_LINE:
+		break;
+	case ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS:
+		regmap_update_bits(adau->regmap, ADAU1761_PLAY_MONO_OUTPUT_VOL,
+			ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP |
+			ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE,
+			ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP |
+			ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE);
+		/* fallthrough */
+	case ADAU1761_OUTPUT_MODE_HEADPHONE:
+		regmap_update_bits(adau->regmap, ADAU1761_PLAY_HP_RIGHT_VOL,
+			ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP,
+			ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode == ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS) {
+		ret = snd_soc_dapm_new_controls(dapm,
+			adau1761_capless_dapm_widgets,
+			ARRAY_SIZE(adau1761_capless_dapm_widgets));
+		if (ret)
+			return ret;
+		ret = snd_soc_dapm_add_routes(dapm,
+			adau1761_capless_dapm_routes,
+			ARRAY_SIZE(adau1761_capless_dapm_routes));
+	} else {
+		ret = snd_soc_add_component_controls(component, adau1761_mono_controls,
+			ARRAY_SIZE(adau1761_mono_controls));
+		if (ret)
+			return ret;
+		ret = snd_soc_dapm_new_controls(dapm,
+			adau1761_mono_dapm_widgets,
+			ARRAY_SIZE(adau1761_mono_dapm_widgets));
+		if (ret)
+			return ret;
+		ret = snd_soc_dapm_add_routes(dapm,
+			adau1761_mono_dapm_routes,
+			ARRAY_SIZE(adau1761_mono_dapm_routes));
+	}
+
+	return ret;
+}
+
+static bool adau1761_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case ADAU1761_DIGMIC_JACKDETECT:
+	case ADAU1761_REC_MIXER_LEFT0:
+	case ADAU1761_REC_MIXER_LEFT1:
+	case ADAU1761_REC_MIXER_RIGHT0:
+	case ADAU1761_REC_MIXER_RIGHT1:
+	case ADAU1761_LEFT_DIFF_INPUT_VOL:
+	case ADAU1761_RIGHT_DIFF_INPUT_VOL:
+	case ADAU1761_PLAY_LR_MIXER_LEFT:
+	case ADAU1761_PLAY_MIXER_LEFT0:
+	case ADAU1761_PLAY_MIXER_LEFT1:
+	case ADAU1761_PLAY_MIXER_RIGHT0:
+	case ADAU1761_PLAY_MIXER_RIGHT1:
+	case ADAU1761_PLAY_LR_MIXER_RIGHT:
+	case ADAU1761_PLAY_MIXER_MONO:
+	case ADAU1761_PLAY_HP_LEFT_VOL:
+	case ADAU1761_PLAY_HP_RIGHT_VOL:
+	case ADAU1761_PLAY_LINE_LEFT_VOL:
+	case ADAU1761_PLAY_LINE_RIGHT_VOL:
+	case ADAU1761_PLAY_MONO_OUTPUT_VOL:
+	case ADAU1761_POP_CLICK_SUPPRESS:
+	case ADAU1761_JACK_DETECT_PIN:
+	case ADAU1761_DEJITTER:
+	case ADAU1761_CLK_ENABLE0:
+	case ADAU1761_CLK_ENABLE1:
+		return true;
+	default:
+		break;
+	}
+
+	return adau17x1_readable_register(dev, reg);
+}
+
+static int adau1761_component_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau1761_platform_data *pdata = component->dev->platform_data;
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = adau17x1_add_widgets(component);
+	if (ret < 0)
+		return ret;
+
+	if (pdata && pdata->input_differential) {
+		regmap_update_bits(adau->regmap, ADAU1761_LEFT_DIFF_INPUT_VOL,
+			ADAU1761_DIFF_INPUT_VOL_LDEN,
+			ADAU1761_DIFF_INPUT_VOL_LDEN);
+		regmap_update_bits(adau->regmap, ADAU1761_RIGHT_DIFF_INPUT_VOL,
+			ADAU1761_DIFF_INPUT_VOL_LDEN,
+			ADAU1761_DIFF_INPUT_VOL_LDEN);
+		ret = snd_soc_add_component_controls(component,
+			adau1761_differential_mode_controls,
+			ARRAY_SIZE(adau1761_differential_mode_controls));
+		if (ret)
+			return ret;
+	} else {
+		ret = snd_soc_add_component_controls(component,
+			adau1761_single_mode_controls,
+			ARRAY_SIZE(adau1761_single_mode_controls));
+		if (ret)
+			return ret;
+	}
+
+	switch (adau1761_get_lineout_mode(component)) {
+	case ADAU1761_OUTPUT_MODE_LINE:
+		break;
+	case ADAU1761_OUTPUT_MODE_HEADPHONE:
+		regmap_update_bits(adau->regmap, ADAU1761_PLAY_LINE_LEFT_VOL,
+			ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP,
+			ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP);
+		regmap_update_bits(adau->regmap, ADAU1761_PLAY_LINE_RIGHT_VOL,
+			ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP,
+			ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = adau1761_setup_headphone_mode(component);
+	if (ret)
+		return ret;
+
+	ret = adau1761_setup_digmic_jackdetect(component);
+	if (ret)
+		return ret;
+
+	if (adau->type == ADAU1761) {
+		ret = snd_soc_dapm_new_controls(dapm, adau1761_dapm_widgets,
+			ARRAY_SIZE(adau1761_dapm_widgets));
+		if (ret)
+			return ret;
+
+		ret = snd_soc_dapm_add_routes(dapm, adau1761_dapm_routes,
+			ARRAY_SIZE(adau1761_dapm_routes));
+		if (ret)
+			return ret;
+	}
+
+	ret = adau17x1_add_routes(component);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver adau1761_component_driver = {
+	.probe			= adau1761_component_probe,
+	.resume			= adau17x1_resume,
+	.set_bias_level		= adau1761_set_bias_level,
+	.controls		= adau1761_controls,
+	.num_controls		= ARRAY_SIZE(adau1761_controls),
+	.dapm_widgets		= adau1x61_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(adau1x61_dapm_widgets),
+	.dapm_routes		= adau1x61_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(adau1x61_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+#define ADAU1761_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+	SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver adau1361_dai_driver = {
+	.name = "adau-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 4,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = ADAU1761_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 4,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = ADAU1761_FORMATS,
+	},
+	.ops = &adau17x1_dai_ops,
+};
+
+static struct snd_soc_dai_driver adau1761_dai_driver = {
+	.name = "adau-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = ADAU1761_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = ADAU1761_FORMATS,
+	},
+	.ops = &adau17x1_dai_ops,
+};
+
+int adau1761_probe(struct device *dev, struct regmap *regmap,
+	enum adau17x1_type type, void (*switch_mode)(struct device *dev))
+{
+	struct snd_soc_dai_driver *dai_drv;
+	const char *firmware_name;
+	int ret;
+
+	if (type == ADAU1361) {
+		dai_drv = &adau1361_dai_driver;
+		firmware_name = NULL;
+	} else {
+		dai_drv = &adau1761_dai_driver;
+		firmware_name = ADAU1761_FIRMWARE;
+	}
+
+	ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name);
+	if (ret)
+		return ret;
+
+	/* Enable cache only mode as we could miss writes before bias level
+	 * reaches standby and the core clock is enabled */
+	regcache_cache_only(regmap, true);
+
+	return devm_snd_soc_register_component(dev, &adau1761_component_driver,
+					       dai_drv, 1);
+}
+EXPORT_SYMBOL_GPL(adau1761_probe);
+
+const struct regmap_config adau1761_regmap_config = {
+	.val_bits = 8,
+	.reg_bits = 16,
+	.max_register = 0x40fa,
+	.reg_defaults = adau1761_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults),
+	.readable_reg = adau1761_readable_register,
+	.volatile_reg = adau17x1_volatile_register,
+	.precious_reg = adau17x1_precious_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(adau1761_regmap_config);
+
+MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1761.h b/sound/soc/codecs/adau1761.h
new file mode 100644
index 0000000..a9e0d28
--- /dev/null
+++ b/sound/soc/codecs/adau1761.h
@@ -0,0 +1,23 @@
+/*
+ * ADAU1361/ADAU1461/ADAU1761/ADAU1961 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __SOUND_SOC_CODECS_ADAU1761_H__
+#define __SOUND_SOC_CODECS_ADAU1761_H__
+
+#include <linux/regmap.h>
+#include "adau17x1.h"
+
+struct device;
+
+int adau1761_probe(struct device *dev, struct regmap *regmap,
+	enum adau17x1_type type, void (*switch_mode)(struct device *dev));
+
+extern const struct regmap_config adau1761_regmap_config;
+
+#endif
diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c
new file mode 100644
index 0000000..7b9d180
--- /dev/null
+++ b/sound/soc/codecs/adau1781-i2c.c
@@ -0,0 +1,67 @@
+/*
+ * Driver for ADAU1381/ADAU1781 CODEC
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "adau1781.h"
+
+static int adau1781_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct regmap_config config;
+
+	config = adau1781_regmap_config;
+	config.val_bits = 8;
+	config.reg_bits = 16;
+
+	return adau1781_probe(&client->dev,
+		devm_regmap_init_i2c(client, &config),
+		id->driver_data, NULL);
+}
+
+static int adau1781_i2c_remove(struct i2c_client *client)
+{
+	adau17x1_remove(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id adau1781_i2c_ids[] = {
+	{ "adau1381", ADAU1381 },
+	{ "adau1781", ADAU1781 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adau1781_i2c_ids);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id adau1781_i2c_dt_ids[] = {
+	{ .compatible = "adi,adau1381", },
+	{ .compatible = "adi,adau1781", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, adau1781_i2c_dt_ids);
+#endif
+
+static struct i2c_driver adau1781_i2c_driver = {
+	.driver = {
+		.name = "adau1781",
+		.of_match_table = of_match_ptr(adau1781_i2c_dt_ids),
+	},
+	.probe = adau1781_i2c_probe,
+	.remove = adau1781_i2c_remove,
+	.id_table = adau1781_i2c_ids,
+};
+module_i2c_driver(adau1781_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 CODEC I2C driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1781-spi.c b/sound/soc/codecs/adau1781-spi.c
new file mode 100644
index 0000000..9b23354
--- /dev/null
+++ b/sound/soc/codecs/adau1781-spi.c
@@ -0,0 +1,84 @@
+/*
+ * Driver for ADAU1381/ADAU1781 CODEC
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include "adau1781.h"
+
+static void adau1781_spi_switch_mode(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+
+	/*
+	 * To get the device into SPI mode CLATCH has to be pulled low three
+	 * times.  Do this by issuing three dummy reads.
+	 */
+	spi_w8r8(spi, 0x00);
+	spi_w8r8(spi, 0x00);
+	spi_w8r8(spi, 0x00);
+}
+
+static int adau1781_spi_probe(struct spi_device *spi)
+{
+	const struct spi_device_id *id = spi_get_device_id(spi);
+	struct regmap_config config;
+
+	if (!id)
+		return -EINVAL;
+
+	config = adau1781_regmap_config;
+	config.val_bits = 8;
+	config.reg_bits = 24;
+	config.read_flag_mask = 0x1;
+
+	return adau1781_probe(&spi->dev,
+		devm_regmap_init_spi(spi, &config),
+		id->driver_data, adau1781_spi_switch_mode);
+}
+
+static int adau1781_spi_remove(struct spi_device *spi)
+{
+	adau17x1_remove(&spi->dev);
+	return 0;
+}
+
+static const struct spi_device_id adau1781_spi_id[] = {
+	{ "adau1381", ADAU1381 },
+	{ "adau1781", ADAU1781 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, adau1781_spi_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id adau1781_spi_dt_ids[] = {
+	{ .compatible = "adi,adau1381", },
+	{ .compatible = "adi,adau1781", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, adau1781_spi_dt_ids);
+#endif
+
+static struct spi_driver adau1781_spi_driver = {
+	.driver = {
+		.name = "adau1781",
+		.of_match_table = of_match_ptr(adau1781_spi_dt_ids),
+	},
+	.probe = adau1781_spi_probe,
+	.remove = adau1781_spi_remove,
+	.id_table = adau1781_spi_id,
+};
+module_spi_driver(adau1781_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 CODEC SPI driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c
new file mode 100644
index 0000000..6a66557
--- /dev/null
+++ b/sound/soc/codecs/adau1781.c
@@ -0,0 +1,509 @@
+/*
+ * Driver for ADAU1381/ADAU1781 codec
+ *
+ * Copyright 2011-2013 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/platform_data/adau17x1.h>
+
+#include "adau17x1.h"
+#include "adau1781.h"
+
+#define ADAU1781_DMIC_BEEP_CTRL		0x4008
+#define ADAU1781_LEFT_PGA		0x400e
+#define ADAU1781_RIGHT_PGA		0x400f
+#define ADAU1781_LEFT_PLAYBACK_MIXER	0x401c
+#define ADAU1781_RIGHT_PLAYBACK_MIXER	0x401e
+#define ADAU1781_MONO_PLAYBACK_MIXER	0x401f
+#define ADAU1781_LEFT_LINEOUT		0x4025
+#define ADAU1781_RIGHT_LINEOUT		0x4026
+#define ADAU1781_SPEAKER		0x4027
+#define ADAU1781_BEEP_ZC		0x4028
+#define ADAU1781_DEJITTER		0x4032
+#define ADAU1781_DIG_PWDN0		0x4080
+#define ADAU1781_DIG_PWDN1		0x4081
+
+#define ADAU1781_INPUT_DIFFERNTIAL BIT(3)
+
+#define ADAU1381_FIRMWARE "adau1381.bin"
+#define ADAU1781_FIRMWARE "adau1781.bin"
+
+static const struct reg_default adau1781_reg_defaults[] = {
+	{ ADAU1781_DMIC_BEEP_CTRL,		0x00 },
+	{ ADAU1781_LEFT_PGA,			0xc7 },
+	{ ADAU1781_RIGHT_PGA,			0xc7 },
+	{ ADAU1781_LEFT_PLAYBACK_MIXER,		0x00 },
+	{ ADAU1781_RIGHT_PLAYBACK_MIXER,	0x00 },
+	{ ADAU1781_MONO_PLAYBACK_MIXER,		0x00 },
+	{ ADAU1781_LEFT_LINEOUT,		0x00 },
+	{ ADAU1781_RIGHT_LINEOUT,		0x00 },
+	{ ADAU1781_SPEAKER,			0x00 },
+	{ ADAU1781_BEEP_ZC,			0x19 },
+	{ ADAU1781_DEJITTER,			0x60 },
+	{ ADAU1781_DIG_PWDN1,			0x0c },
+	{ ADAU1781_DIG_PWDN1,			0x00 },
+	{ ADAU17X1_CLOCK_CONTROL,		0x00 },
+	{ ADAU17X1_PLL_CONTROL,			0x00 },
+	{ ADAU17X1_REC_POWER_MGMT,		0x00 },
+	{ ADAU17X1_MICBIAS,			0x04 },
+	{ ADAU17X1_SERIAL_PORT0,		0x00 },
+	{ ADAU17X1_SERIAL_PORT1,		0x00 },
+	{ ADAU17X1_CONVERTER0,			0x00 },
+	{ ADAU17X1_CONVERTER1,			0x00 },
+	{ ADAU17X1_LEFT_INPUT_DIGITAL_VOL,	0x00 },
+	{ ADAU17X1_RIGHT_INPUT_DIGITAL_VOL,	0x00 },
+	{ ADAU17X1_ADC_CONTROL,			0x00 },
+	{ ADAU17X1_PLAY_POWER_MGMT,		0x00 },
+	{ ADAU17X1_DAC_CONTROL0,		0x00 },
+	{ ADAU17X1_DAC_CONTROL1,		0x00 },
+	{ ADAU17X1_DAC_CONTROL2,		0x00 },
+	{ ADAU17X1_SERIAL_PORT_PAD,		0x00 },
+	{ ADAU17X1_CONTROL_PORT_PAD0,		0x00 },
+	{ ADAU17X1_CONTROL_PORT_PAD1,		0x00 },
+	{ ADAU17X1_DSP_SAMPLING_RATE,		0x01 },
+	{ ADAU17X1_SERIAL_INPUT_ROUTE,		0x00 },
+	{ ADAU17X1_SERIAL_OUTPUT_ROUTE,		0x00 },
+	{ ADAU17X1_DSP_ENABLE,			0x00 },
+	{ ADAU17X1_DSP_RUN,			0x00 },
+	{ ADAU17X1_SERIAL_SAMPLING_RATE,	0x00 },
+};
+
+static const DECLARE_TLV_DB_SCALE(adau1781_speaker_tlv, 0, 200, 0);
+
+static const DECLARE_TLV_DB_RANGE(adau1781_pga_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
+	2, 3, TLV_DB_SCALE_ITEM(1000, 400, 0),
+	4, 4, TLV_DB_SCALE_ITEM(1700, 0, 0),
+	5, 7, TLV_DB_SCALE_ITEM(2000, 600, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(adau1781_beep_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
+	2, 3, TLV_DB_SCALE_ITEM(1000, 400, 0),
+	4, 4, TLV_DB_SCALE_ITEM(-2300, 0, 0),
+	5, 7, TLV_DB_SCALE_ITEM(2000, 600, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(adau1781_sidetone_tlv, -1800, 300, 1);
+
+static const char * const adau1781_speaker_bias_select_text[] = {
+	"Normal operation", "Power saving", "Enhanced performance",
+};
+
+static const char * const adau1781_bias_select_text[] = {
+	"Normal operation", "Extreme power saving", "Power saving",
+	"Enhanced performance",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau1781_adc_bias_enum,
+		ADAU17X1_REC_POWER_MGMT, 3, adau1781_bias_select_text);
+static SOC_ENUM_SINGLE_DECL(adau1781_speaker_bias_enum,
+		ADAU17X1_PLAY_POWER_MGMT, 6, adau1781_speaker_bias_select_text);
+static SOC_ENUM_SINGLE_DECL(adau1781_dac_bias_enum,
+		ADAU17X1_PLAY_POWER_MGMT, 4, adau1781_bias_select_text);
+static SOC_ENUM_SINGLE_DECL(adau1781_playback_bias_enum,
+		ADAU17X1_PLAY_POWER_MGMT, 2, adau1781_bias_select_text);
+static SOC_ENUM_SINGLE_DECL(adau1781_capture_bias_enum,
+		ADAU17X1_REC_POWER_MGMT, 1, adau1781_bias_select_text);
+
+static const struct snd_kcontrol_new adau1781_controls[] = {
+	SOC_SINGLE_TLV("Beep Capture Volume", ADAU1781_DMIC_BEEP_CTRL, 0, 7, 0,
+		adau1781_beep_tlv),
+	SOC_DOUBLE_R_TLV("PGA Capture Volume", ADAU1781_LEFT_PGA,
+		ADAU1781_RIGHT_PGA, 5, 7, 0, adau1781_pga_tlv),
+	SOC_DOUBLE_R("PGA Capture Switch", ADAU1781_LEFT_PGA,
+		ADAU1781_RIGHT_PGA, 1, 1, 0),
+
+	SOC_DOUBLE_R("Lineout Playback Switch", ADAU1781_LEFT_LINEOUT,
+		ADAU1781_RIGHT_LINEOUT, 1, 1, 0),
+	SOC_SINGLE("Beep ZC Switch", ADAU1781_BEEP_ZC, 0, 1, 0),
+
+	SOC_SINGLE("Mono Playback Switch", ADAU1781_MONO_PLAYBACK_MIXER,
+		0, 1, 0),
+	SOC_SINGLE_TLV("Mono Playback Volume", ADAU1781_SPEAKER, 6, 3, 0,
+		adau1781_speaker_tlv),
+
+	SOC_ENUM("ADC Bias", adau1781_adc_bias_enum),
+	SOC_ENUM("DAC Bias", adau1781_dac_bias_enum),
+	SOC_ENUM("Capture Bias", adau1781_capture_bias_enum),
+	SOC_ENUM("Playback Bias", adau1781_playback_bias_enum),
+	SOC_ENUM("Speaker Bias", adau1781_speaker_bias_enum),
+};
+
+static const struct snd_kcontrol_new adau1781_beep_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Beep Capture Switch", ADAU1781_DMIC_BEEP_CTRL,
+		3, 1, 0),
+};
+
+static const struct snd_kcontrol_new adau1781_left_mixer_controls[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+		ADAU1781_LEFT_PLAYBACK_MIXER, 5, 1, 0),
+	SOC_DAPM_SINGLE_TLV("Beep Playback Volume",
+		ADAU1781_LEFT_PLAYBACK_MIXER, 1, 8, 0, adau1781_sidetone_tlv),
+};
+
+static const struct snd_kcontrol_new adau1781_right_mixer_controls[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch",
+		ADAU1781_RIGHT_PLAYBACK_MIXER, 6, 1, 0),
+	SOC_DAPM_SINGLE_TLV("Beep Playback Volume",
+		ADAU1781_LEFT_PLAYBACK_MIXER, 1, 8, 0, adau1781_sidetone_tlv),
+};
+
+static const struct snd_kcontrol_new adau1781_mono_mixer_controls[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Left Switch",
+		ADAU1781_MONO_PLAYBACK_MIXER, 7, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("Right Switch",
+		 ADAU1781_MONO_PLAYBACK_MIXER, 6, 1, 0),
+	SOC_DAPM_SINGLE_TLV("Beep Playback Volume",
+		ADAU1781_MONO_PLAYBACK_MIXER, 2, 8, 0, adau1781_sidetone_tlv),
+};
+
+static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+
+	/* After any power changes have been made the dejitter circuit
+	 * has to be reinitialized. */
+	regmap_write(adau->regmap, ADAU1781_DEJITTER, 0);
+	if (!adau->master)
+		regmap_write(adau->regmap, ADAU1781_DEJITTER, 5);
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget adau1781_dapm_widgets[] = {
+	SND_SOC_DAPM_PGA("Left PGA", ADAU1781_LEFT_PGA, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right PGA", ADAU1781_RIGHT_PGA, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUT_DRV("Speaker", ADAU1781_SPEAKER, 0, 0, NULL, 0),
+
+	SOC_MIXER_NAMED_CTL_ARRAY("Beep Mixer", ADAU17X1_MICBIAS, 4, 0,
+		adau1781_beep_mixer_controls),
+
+	SOC_MIXER_ARRAY("Left Lineout Mixer", SND_SOC_NOPM, 0, 0,
+		adau1781_left_mixer_controls),
+	SOC_MIXER_ARRAY("Right Lineout Mixer", SND_SOC_NOPM, 0, 0,
+		adau1781_right_mixer_controls),
+	SOC_MIXER_ARRAY("Mono Mixer", SND_SOC_NOPM, 0, 0,
+		adau1781_mono_mixer_controls),
+
+	SND_SOC_DAPM_SUPPLY("Serial Input Routing", ADAU1781_DIG_PWDN0,
+		2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Serial Output Routing", ADAU1781_DIG_PWDN0,
+		3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Clock Domain Transfer", ADAU1781_DIG_PWDN0,
+		5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Serial Ports", ADAU1781_DIG_PWDN0, 4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Engine", ADAU1781_DIG_PWDN0, 7, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Engine", ADAU1781_DIG_PWDN1, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Digital Mic", ADAU1781_DIG_PWDN1, 1, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Sound Engine", ADAU1781_DIG_PWDN0, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, ADAU1781_DIG_PWDN0, 1, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Zero Crossing Detector", ADAU1781_DIG_PWDN1, 2, 0,
+		NULL, 0),
+
+	SND_SOC_DAPM_POST("Dejitter fixup", adau1781_dejitter_fixup),
+
+	SND_SOC_DAPM_INPUT("BEEP"),
+
+	SND_SOC_DAPM_OUTPUT("AOUTL"),
+	SND_SOC_DAPM_OUTPUT("AOUTR"),
+	SND_SOC_DAPM_OUTPUT("SP"),
+	SND_SOC_DAPM_INPUT("LMIC"),
+	SND_SOC_DAPM_INPUT("RMIC"),
+};
+
+static const struct snd_soc_dapm_route adau1781_dapm_routes[] = {
+	{ "Left Lineout Mixer", NULL, "Left Playback Enable" },
+	{ "Right Lineout Mixer", NULL, "Right Playback Enable" },
+
+	{ "Left Lineout Mixer", "Beep Playback Volume", "Beep Mixer" },
+	{ "Left Lineout Mixer", "Switch", "Left DAC" },
+
+	{ "Right Lineout Mixer", "Beep Playback Volume", "Beep Mixer" },
+	{ "Right Lineout Mixer", "Switch", "Right DAC" },
+
+	{ "Mono Mixer", "Beep Playback Volume", "Beep Mixer" },
+	{ "Mono Mixer", "Right Switch", "Right DAC" },
+	{ "Mono Mixer", "Left Switch", "Left DAC" },
+	{ "Speaker", NULL, "Mono Mixer" },
+
+	{ "Mono Mixer", NULL, "SYSCLK" },
+	{ "Left Lineout Mixer", NULL, "SYSCLK" },
+	{ "Left Lineout Mixer", NULL, "SYSCLK" },
+
+	{ "Beep Mixer", "Beep Capture Switch", "BEEP" },
+	{ "Beep Mixer", NULL, "Zero Crossing Detector" },
+
+	{ "Left DAC", NULL, "DAC Engine" },
+	{ "Right DAC", NULL, "DAC Engine" },
+
+	{ "Sound Engine", NULL, "SYSCLK" },
+	{ "DSP", NULL, "Sound Engine" },
+
+	{ "Left Decimator", NULL, "ADC Engine" },
+	{ "Right Decimator", NULL, "ADC Engine" },
+
+	{ "AIFCLK", NULL, "SYSCLK" },
+
+	{ "Playback", NULL, "Serial Input Routing" },
+	{ "Playback", NULL, "Serial Ports" },
+	{ "Playback", NULL, "Clock Domain Transfer" },
+	{ "Capture", NULL, "Serial Output Routing" },
+	{ "Capture", NULL, "Serial Ports" },
+	{ "Capture", NULL, "Clock Domain Transfer" },
+
+	{ "AOUTL", NULL, "Left Lineout Mixer" },
+	{ "AOUTR", NULL, "Right Lineout Mixer" },
+	{ "SP", NULL, "Speaker" },
+};
+
+static const struct snd_soc_dapm_route adau1781_adc_dapm_routes[] = {
+	{ "Left PGA", NULL, "LMIC" },
+	{ "Right PGA", NULL, "RMIC" },
+
+	{ "Left Decimator", NULL, "Left PGA" },
+	{ "Right Decimator", NULL, "Right PGA" },
+};
+
+static const char * const adau1781_dmic_select_text[] = {
+	"DMIC1", "DMIC2",
+};
+
+static SOC_ENUM_SINGLE_VIRT_DECL(adau1781_dmic_select_enum,
+	adau1781_dmic_select_text);
+
+static const struct snd_kcontrol_new adau1781_dmic_mux =
+	SOC_DAPM_ENUM("DMIC Select", adau1781_dmic_select_enum);
+
+static const struct snd_soc_dapm_widget adau1781_dmic_dapm_widgets[] = {
+	SND_SOC_DAPM_MUX("DMIC Select", SND_SOC_NOPM, 0, 0, &adau1781_dmic_mux),
+
+	SND_SOC_DAPM_ADC("DMIC1", NULL, ADAU1781_DMIC_BEEP_CTRL, 4, 0),
+	SND_SOC_DAPM_ADC("DMIC2", NULL, ADAU1781_DMIC_BEEP_CTRL, 5, 0),
+};
+
+static const struct snd_soc_dapm_route adau1781_dmic_dapm_routes[] = {
+	{ "DMIC1", NULL, "LMIC" },
+	{ "DMIC2", NULL, "RMIC" },
+
+	{ "DMIC1", NULL, "Digital Mic" },
+	{ "DMIC2", NULL, "Digital Mic" },
+
+	{ "DMIC Select", "DMIC1", "DMIC1" },
+	{ "DMIC Select", "DMIC2", "DMIC2" },
+
+	{ "Left Decimator", NULL, "DMIC Select" },
+	{ "Right Decimator", NULL, "DMIC Select" },
+};
+
+static int adau1781_set_bias_level(struct snd_soc_component *component,
+		enum snd_soc_bias_level level)
+{
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
+			ADAU17X1_CLOCK_CONTROL_SYSCLK_EN,
+			ADAU17X1_CLOCK_CONTROL_SYSCLK_EN);
+
+		/* Precharge */
+		regmap_update_bits(adau->regmap, ADAU1781_DIG_PWDN1, 0x8, 0x8);
+		break;
+	case SND_SOC_BIAS_OFF:
+		regmap_update_bits(adau->regmap, ADAU1781_DIG_PWDN1, 0xc, 0x0);
+		regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
+			ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static bool adau1781_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case ADAU1781_DMIC_BEEP_CTRL:
+	case ADAU1781_LEFT_PGA:
+	case ADAU1781_RIGHT_PGA:
+	case ADAU1781_LEFT_PLAYBACK_MIXER:
+	case ADAU1781_RIGHT_PLAYBACK_MIXER:
+	case ADAU1781_MONO_PLAYBACK_MIXER:
+	case ADAU1781_LEFT_LINEOUT:
+	case ADAU1781_RIGHT_LINEOUT:
+	case ADAU1781_SPEAKER:
+	case ADAU1781_BEEP_ZC:
+	case ADAU1781_DEJITTER:
+	case ADAU1781_DIG_PWDN0:
+	case ADAU1781_DIG_PWDN1:
+		return true;
+	default:
+		break;
+	}
+
+	return adau17x1_readable_register(dev, reg);
+}
+
+static int adau1781_set_input_mode(struct adau *adau, unsigned int reg,
+	bool differential)
+{
+	unsigned int val;
+
+	if (differential)
+		val = ADAU1781_INPUT_DIFFERNTIAL;
+	else
+		val = 0;
+
+	return regmap_update_bits(adau->regmap, reg,
+		ADAU1781_INPUT_DIFFERNTIAL, val);
+}
+
+static int adau1781_component_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau1781_platform_data *pdata = dev_get_platdata(component->dev);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = adau17x1_add_widgets(component);
+	if (ret)
+		return ret;
+
+	if (pdata) {
+		ret = adau1781_set_input_mode(adau, ADAU1781_LEFT_PGA,
+			pdata->left_input_differential);
+		if (ret)
+			return ret;
+		ret = adau1781_set_input_mode(adau, ADAU1781_RIGHT_PGA,
+			pdata->right_input_differential);
+		if (ret)
+			return ret;
+	}
+
+	if (pdata && pdata->use_dmic) {
+		ret = snd_soc_dapm_new_controls(dapm,
+			adau1781_dmic_dapm_widgets,
+			ARRAY_SIZE(adau1781_dmic_dapm_widgets));
+		if (ret)
+			return ret;
+		ret = snd_soc_dapm_add_routes(dapm, adau1781_dmic_dapm_routes,
+			ARRAY_SIZE(adau1781_dmic_dapm_routes));
+		if (ret)
+			return ret;
+	} else {
+		ret = snd_soc_dapm_add_routes(dapm, adau1781_adc_dapm_routes,
+			ARRAY_SIZE(adau1781_adc_dapm_routes));
+		if (ret)
+			return ret;
+	}
+
+	ret = adau17x1_add_routes(component);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver adau1781_component_driver = {
+	.probe			= adau1781_component_probe,
+	.resume			= adau17x1_resume,
+	.set_bias_level		= adau1781_set_bias_level,
+	.controls		= adau1781_controls,
+	.num_controls		= ARRAY_SIZE(adau1781_controls),
+	.dapm_widgets		= adau1781_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(adau1781_dapm_widgets),
+	.dapm_routes		= adau1781_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(adau1781_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+#define ADAU1781_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+	SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver adau1781_dai_driver = {
+	.name = "adau-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = ADAU1781_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = ADAU1781_FORMATS,
+	},
+	.ops = &adau17x1_dai_ops,
+};
+
+const struct regmap_config adau1781_regmap_config = {
+	.val_bits		= 8,
+	.reg_bits		= 16,
+	.max_register		= 0x40f8,
+	.reg_defaults		= adau1781_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(adau1781_reg_defaults),
+	.readable_reg		= adau1781_readable_register,
+	.volatile_reg		= adau17x1_volatile_register,
+	.precious_reg		= adau17x1_precious_register,
+	.cache_type		= REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(adau1781_regmap_config);
+
+int adau1781_probe(struct device *dev, struct regmap *regmap,
+	enum adau17x1_type type, void (*switch_mode)(struct device *dev))
+{
+	const char *firmware_name;
+	int ret;
+
+	switch (type) {
+	case ADAU1381:
+		firmware_name = ADAU1381_FIRMWARE;
+		break;
+	case ADAU1781:
+		firmware_name = ADAU1781_FIRMWARE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_component(dev, &adau1781_component_driver,
+		&adau1781_dai_driver, 1);
+}
+EXPORT_SYMBOL_GPL(adau1781_probe);
+
+MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1781.h b/sound/soc/codecs/adau1781.h
new file mode 100644
index 0000000..2b96e0a
--- /dev/null
+++ b/sound/soc/codecs/adau1781.h
@@ -0,0 +1,23 @@
+/*
+ * ADAU1381/ADAU1781 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __SOUND_SOC_CODECS_ADAU1781_H__
+#define __SOUND_SOC_CODECS_ADAU1781_H__
+
+#include <linux/regmap.h>
+#include "adau17x1.h"
+
+struct device;
+
+int adau1781_probe(struct device *dev, struct regmap *regmap,
+	enum adau17x1_type type, void (*switch_mode)(struct device *dev));
+
+extern const struct regmap_config adau1781_regmap_config;
+
+#endif
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
new file mode 100644
index 0000000..57169b8
--- /dev/null
+++ b/sound/soc/codecs/adau17x1.c
@@ -0,0 +1,1032 @@
+/*
+ * Common code for ADAU1X61 and ADAU1X81 codecs
+ *
+ * Copyright 2011-2014 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/gcd.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include "sigmadsp.h"
+#include "adau17x1.h"
+#include "adau-utils.h"
+
+static const char * const adau17x1_capture_mixer_boost_text[] = {
+	"Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau17x1_capture_boost_enum,
+	ADAU17X1_REC_POWER_MGMT, 5, adau17x1_capture_mixer_boost_text);
+
+static const char * const adau17x1_mic_bias_mode_text[] = {
+	"Normal operation", "High performance",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau17x1_mic_bias_mode_enum,
+	ADAU17X1_MICBIAS, 3, adau17x1_mic_bias_mode_text);
+
+static const DECLARE_TLV_DB_MINMAX(adau17x1_digital_tlv, -9563, 0);
+
+static const struct snd_kcontrol_new adau17x1_controls[] = {
+	SOC_DOUBLE_R_TLV("Digital Capture Volume",
+		ADAU17X1_LEFT_INPUT_DIGITAL_VOL,
+		ADAU17X1_RIGHT_INPUT_DIGITAL_VOL,
+		0, 0xff, 1, adau17x1_digital_tlv),
+	SOC_DOUBLE_R_TLV("Digital Playback Volume", ADAU17X1_DAC_CONTROL1,
+		ADAU17X1_DAC_CONTROL2, 0, 0xff, 1, adau17x1_digital_tlv),
+
+	SOC_SINGLE("ADC High Pass Filter Switch", ADAU17X1_ADC_CONTROL,
+		5, 1, 0),
+	SOC_SINGLE("Playback De-emphasis Switch", ADAU17X1_DAC_CONTROL0,
+		2, 1, 0),
+
+	SOC_ENUM("Capture Boost", adau17x1_capture_boost_enum),
+
+	SOC_ENUM("Mic Bias Mode", adau17x1_mic_bias_mode_enum),
+};
+
+static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		adau->pll_regs[5] = 1;
+	} else {
+		adau->pll_regs[5] = 0;
+		/* Bypass the PLL when disabled, otherwise registers will become
+		 * inaccessible. */
+		regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
+			ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL, 0);
+	}
+
+	/* The PLL register is 6 bytes long and can only be written at once. */
+	regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
+			adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		mdelay(5);
+		regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
+			ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL,
+			ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL);
+	}
+
+	return 0;
+}
+
+static int adau17x1_adc_fixup(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+
+	/*
+	 * If we are capturing, toggle the ADOSR bit in Converter Control 0 to
+	 * avoid losing SNR (workaround from ADI). This must be done after
+	 * the ADC(s) have been enabled. According to the data sheet, it is
+	 * normally illegal to set this bit when the sampling rate is 96 kHz,
+	 * but according to ADI it is acceptable for this workaround.
+	 */
+	regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0,
+		ADAU17X1_CONVERTER0_ADOSR, ADAU17X1_CONVERTER0_ADOSR);
+	regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0,
+		ADAU17X1_CONVERTER0_ADOSR, 0);
+
+	return 0;
+}
+
+static const char * const adau17x1_mono_stereo_text[] = {
+	"Stereo",
+	"Mono Left Channel (L+R)",
+	"Mono Right Channel (L+R)",
+	"Mono (L+R)",
+};
+
+static SOC_ENUM_SINGLE_DECL(adau17x1_dac_mode_enum,
+	ADAU17X1_DAC_CONTROL0, 6, adau17x1_mono_stereo_text);
+
+static const struct snd_kcontrol_new adau17x1_dac_mode_mux =
+	SOC_DAPM_ENUM("DAC Mono-Stereo-Mode", adau17x1_dac_mode_enum);
+
+static const struct snd_soc_dapm_widget adau17x1_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY_S("PLL", 3, SND_SOC_NOPM, 0, 0, adau17x1_pll_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY("AIFCLK", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU17X1_MICBIAS, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Left Playback Enable", ADAU17X1_PLAY_POWER_MGMT,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Right Playback Enable", ADAU17X1_PLAY_POWER_MGMT,
+		1, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("Left DAC Mode Mux", SND_SOC_NOPM, 0, 0,
+		&adau17x1_dac_mode_mux),
+	SND_SOC_DAPM_MUX("Right DAC Mode Mux", SND_SOC_NOPM, 0, 0,
+		&adau17x1_dac_mode_mux),
+
+	SND_SOC_DAPM_ADC_E("Left Decimator", NULL, ADAU17X1_ADC_CONTROL, 0, 0,
+			   adau17x1_adc_fixup, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_ADC("Right Decimator", NULL, ADAU17X1_ADC_CONTROL, 1, 0),
+	SND_SOC_DAPM_DAC("Left DAC", NULL, ADAU17X1_DAC_CONTROL0, 0, 0),
+	SND_SOC_DAPM_DAC("Right DAC", NULL, ADAU17X1_DAC_CONTROL0, 1, 0),
+};
+
+static const struct snd_soc_dapm_route adau17x1_dapm_routes[] = {
+	{ "Left Decimator", NULL, "SYSCLK" },
+	{ "Right Decimator", NULL, "SYSCLK" },
+	{ "Left DAC", NULL, "SYSCLK" },
+	{ "Right DAC", NULL, "SYSCLK" },
+	{ "Capture", NULL, "SYSCLK" },
+	{ "Playback", NULL, "SYSCLK" },
+
+	{ "Left DAC", NULL, "Left DAC Mode Mux" },
+	{ "Right DAC", NULL, "Right DAC Mode Mux" },
+
+	{ "Capture", NULL, "AIFCLK" },
+	{ "Playback", NULL, "AIFCLK" },
+};
+
+static const struct snd_soc_dapm_route adau17x1_dapm_pll_route = {
+	"SYSCLK", NULL, "PLL",
+};
+
+/*
+ * The MUX register for the Capture and Playback MUXs selects either DSP as
+ * source/destination or one of the TDM slots. The TDM slot is selected via
+ * snd_soc_dai_set_tdm_slot(), so we only expose whether to go to the DSP or
+ * directly to the DAI interface with this control.
+ */
+static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	struct snd_soc_dapm_update update = {};
+	unsigned int stream = e->shift_l;
+	unsigned int val, change;
+	int reg;
+
+	if (ucontrol->value.enumerated.item[0] >= e->items)
+		return -EINVAL;
+
+	switch (ucontrol->value.enumerated.item[0]) {
+	case 0:
+		val = 0;
+		adau->dsp_bypass[stream] = false;
+		break;
+	default:
+		val = (adau->tdm_slot[stream] * 2) + 1;
+		adau->dsp_bypass[stream] = true;
+		break;
+	}
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		reg = ADAU17X1_SERIAL_INPUT_ROUTE;
+	else
+		reg = ADAU17X1_SERIAL_OUTPUT_ROUTE;
+
+	change = snd_soc_component_test_bits(component, reg, 0xff, val);
+	if (change) {
+		update.kcontrol = kcontrol;
+		update.mask = 0xff;
+		update.reg = reg;
+		update.val = val;
+
+		snd_soc_dapm_mux_update_power(dapm, kcontrol,
+				ucontrol->value.enumerated.item[0], e, &update);
+	}
+
+	return change;
+}
+
+static int adau17x1_dsp_mux_enum_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int stream = e->shift_l;
+	unsigned int reg, val;
+	int ret;
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		reg = ADAU17X1_SERIAL_INPUT_ROUTE;
+	else
+		reg = ADAU17X1_SERIAL_OUTPUT_ROUTE;
+
+	ret = regmap_read(adau->regmap, reg, &val);
+	if (ret)
+		return ret;
+
+	if (val != 0)
+		val = 1;
+	ucontrol->value.enumerated.item[0] = val;
+
+	return 0;
+}
+
+#define DECLARE_ADAU17X1_DSP_MUX_CTRL(_name, _label, _stream, _text) \
+	const struct snd_kcontrol_new _name = \
+		SOC_DAPM_ENUM_EXT(_label, (const struct soc_enum)\
+			SOC_ENUM_SINGLE(SND_SOC_NOPM, _stream, \
+				ARRAY_SIZE(_text), _text), \
+			adau17x1_dsp_mux_enum_get, adau17x1_dsp_mux_enum_put)
+
+static const char * const adau17x1_dac_mux_text[] = {
+	"DSP",
+	"AIFIN",
+};
+
+static const char * const adau17x1_capture_mux_text[] = {
+	"DSP",
+	"Decimator",
+};
+
+static DECLARE_ADAU17X1_DSP_MUX_CTRL(adau17x1_dac_mux, "DAC Playback Mux",
+	SNDRV_PCM_STREAM_PLAYBACK, adau17x1_dac_mux_text);
+
+static DECLARE_ADAU17X1_DSP_MUX_CTRL(adau17x1_capture_mux, "Capture Mux",
+	SNDRV_PCM_STREAM_CAPTURE, adau17x1_capture_mux_text);
+
+static const struct snd_soc_dapm_widget adau17x1_dsp_dapm_widgets[] = {
+	SND_SOC_DAPM_PGA("DSP", ADAU17X1_DSP_RUN, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SIGGEN("DSP Siggen"),
+
+	SND_SOC_DAPM_MUX("DAC Playback Mux", SND_SOC_NOPM, 0, 0,
+		&adau17x1_dac_mux),
+	SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0,
+		&adau17x1_capture_mux),
+};
+
+static const struct snd_soc_dapm_route adau17x1_dsp_dapm_routes[] = {
+	{ "DAC Playback Mux", "DSP", "DSP" },
+	{ "DAC Playback Mux", "AIFIN", "Playback" },
+
+	{ "Left DAC Mode Mux", "Stereo", "DAC Playback Mux" },
+	{ "Left DAC Mode Mux", "Mono (L+R)", "DAC Playback Mux" },
+	{ "Left DAC Mode Mux", "Mono Left Channel (L+R)", "DAC Playback Mux" },
+	{ "Right DAC Mode Mux", "Stereo", "DAC Playback Mux" },
+	{ "Right DAC Mode Mux", "Mono (L+R)", "DAC Playback Mux" },
+	{ "Right DAC Mode Mux", "Mono Right Channel (L+R)", "DAC Playback Mux" },
+
+	{ "Capture Mux", "DSP", "DSP" },
+	{ "Capture Mux", "Decimator", "Left Decimator" },
+	{ "Capture Mux", "Decimator", "Right Decimator" },
+
+	{ "Capture", NULL, "Capture Mux" },
+
+	{ "DSP", NULL, "DSP Siggen" },
+
+	{ "DSP", NULL, "Left Decimator" },
+	{ "DSP", NULL, "Right Decimator" },
+	{ "DSP", NULL, "Playback" },
+};
+
+static const struct snd_soc_dapm_route adau17x1_no_dsp_dapm_routes[] = {
+	{ "Left DAC Mode Mux", "Stereo", "Playback" },
+	{ "Left DAC Mode Mux", "Mono (L+R)", "Playback" },
+	{ "Left DAC Mode Mux", "Mono Left Channel (L+R)", "Playback" },
+	{ "Right DAC Mode Mux", "Stereo", "Playback" },
+	{ "Right DAC Mode Mux", "Mono (L+R)", "Playback" },
+	{ "Right DAC Mode Mux", "Mono Right Channel (L+R)", "Playback" },
+	{ "Capture", NULL, "Left Decimator" },
+	{ "Capture", NULL, "Right Decimator" },
+};
+
+bool adau17x1_has_dsp(struct adau *adau)
+{
+	switch (adau->type) {
+	case ADAU1761:
+	case ADAU1381:
+	case ADAU1781:
+		return true;
+	default:
+		return false;
+	}
+}
+EXPORT_SYMBOL_GPL(adau17x1_has_dsp);
+
+static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
+	int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = dai->component;
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	if (freq_in < 8000000 || freq_in > 27000000)
+		return -EINVAL;
+
+	ret = adau_calc_pll_cfg(freq_in, freq_out, adau->pll_regs);
+	if (ret < 0)
+		return ret;
+
+	/* The PLL register is 6 bytes long and can only be written at once. */
+	ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
+			adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
+	if (ret)
+		return ret;
+
+	adau->pll_freq = freq_out;
+
+	return 0;
+}
+
+static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(dai->component);
+	struct adau *adau = snd_soc_component_get_drvdata(dai->component);
+	bool is_pll;
+	bool was_pll;
+
+	switch (clk_id) {
+	case ADAU17X1_CLK_SRC_MCLK:
+		is_pll = false;
+		break;
+	case ADAU17X1_CLK_SRC_PLL_AUTO:
+		if (!adau->mclk)
+			return -EINVAL;
+		/* Fall-through */
+	case ADAU17X1_CLK_SRC_PLL:
+		is_pll = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (adau->clk_src) {
+	case ADAU17X1_CLK_SRC_MCLK:
+		was_pll = false;
+		break;
+	case ADAU17X1_CLK_SRC_PLL:
+	case ADAU17X1_CLK_SRC_PLL_AUTO:
+		was_pll = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	adau->sysclk = freq;
+
+	if (is_pll != was_pll) {
+		if (is_pll) {
+			snd_soc_dapm_add_routes(dapm,
+				&adau17x1_dapm_pll_route, 1);
+		} else {
+			snd_soc_dapm_del_routes(dapm,
+				&adau17x1_dapm_pll_route, 1);
+		}
+	}
+
+	adau->clk_src = clk_id;
+
+	return 0;
+}
+
+static int adau17x1_auto_pll(struct snd_soc_dai *dai,
+	struct snd_pcm_hw_params *params)
+{
+	struct adau *adau = snd_soc_dai_get_drvdata(dai);
+	unsigned int pll_rate;
+
+	switch (params_rate(params)) {
+	case 48000:
+	case 8000:
+	case 12000:
+	case 16000:
+	case 24000:
+	case 32000:
+	case 96000:
+		pll_rate = 48000 * 1024;
+		break;
+	case 44100:
+	case 7350:
+	case 11025:
+	case 14700:
+	case 22050:
+	case 29400:
+	case 88200:
+		pll_rate = 44100 * 1024;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return adau17x1_set_dai_pll(dai, ADAU17X1_PLL, ADAU17X1_PLL_SRC_MCLK,
+		clk_get_rate(adau->mclk), pll_rate);
+}
+
+static int adau17x1_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+	unsigned int val, div, dsp_div;
+	unsigned int freq;
+	int ret;
+
+	switch (adau->clk_src) {
+	case ADAU17X1_CLK_SRC_PLL_AUTO:
+		ret = adau17x1_auto_pll(dai, params);
+		if (ret)
+			return ret;
+		/* Fall-through */
+	case ADAU17X1_CLK_SRC_PLL:
+		freq = adau->pll_freq;
+		break;
+	default:
+		freq = adau->sysclk;
+		break;
+	}
+
+	if (freq % params_rate(params) != 0)
+		return -EINVAL;
+
+	switch (freq / params_rate(params)) {
+	case 1024: /* fs */
+		div = 0;
+		dsp_div = 1;
+		break;
+	case 6144: /* fs / 6 */
+		div = 1;
+		dsp_div = 6;
+		break;
+	case 4096: /* fs / 4 */
+		div = 2;
+		dsp_div = 5;
+		break;
+	case 3072: /* fs / 3 */
+		div = 3;
+		dsp_div = 4;
+		break;
+	case 2048: /* fs / 2 */
+		div = 4;
+		dsp_div = 3;
+		break;
+	case 1536: /* fs / 1.5 */
+		div = 5;
+		dsp_div = 2;
+		break;
+	case 512: /* fs / 0.5 */
+		div = 6;
+		dsp_div = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0,
+		ADAU17X1_CONVERTER0_CONVSR_MASK, div);
+	if (adau17x1_has_dsp(adau)) {
+		regmap_write(adau->regmap, ADAU17X1_SERIAL_SAMPLING_RATE, div);
+		regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div);
+	}
+
+	if (adau->sigmadsp) {
+		ret = adau17x1_setup_firmware(component, params_rate(params));
+		if (ret < 0)
+			return ret;
+	}
+
+	if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
+		return 0;
+
+	switch (params_width(params)) {
+	case 16:
+		val = ADAU17X1_SERIAL_PORT1_DELAY16;
+		break;
+	case 24:
+		val = ADAU17X1_SERIAL_PORT1_DELAY8;
+		break;
+	case 32:
+		val = ADAU17X1_SERIAL_PORT1_DELAY0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1,
+			ADAU17X1_SERIAL_PORT1_DELAY_MASK, val);
+}
+
+static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai,
+		unsigned int fmt)
+{
+	struct adau *adau = snd_soc_component_get_drvdata(dai->component);
+	unsigned int ctrl0, ctrl1;
+	int lrclk_pol;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		ctrl0 = ADAU17X1_SERIAL_PORT0_MASTER;
+		adau->master = true;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		ctrl0 = 0;
+		adau->master = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		lrclk_pol = 0;
+		ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY1;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
+		lrclk_pol = 1;
+		ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY0;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		lrclk_pol = 1;
+		ctrl0 |= ADAU17X1_SERIAL_PORT0_PULSE_MODE;
+		ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY1;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		lrclk_pol = 1;
+		ctrl0 |= ADAU17X1_SERIAL_PORT0_PULSE_MODE;
+		ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		ctrl0 |= ADAU17X1_SERIAL_PORT0_BCLK_POL;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		lrclk_pol = !lrclk_pol;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		ctrl0 |= ADAU17X1_SERIAL_PORT0_BCLK_POL;
+		lrclk_pol = !lrclk_pol;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (lrclk_pol)
+		ctrl0 |= ADAU17X1_SERIAL_PORT0_LRCLK_POL;
+
+	regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT0, ctrl0);
+	regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT1, ctrl1);
+
+	adau->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+	return 0;
+}
+
+static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai,
+	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+	struct adau *adau = snd_soc_component_get_drvdata(dai->component);
+	unsigned int ser_ctrl0, ser_ctrl1;
+	unsigned int conv_ctrl0, conv_ctrl1;
+
+	/* I2S mode */
+	if (slots == 0) {
+		slots = 2;
+		rx_mask = 3;
+		tx_mask = 3;
+		slot_width = 32;
+	}
+
+	switch (slots) {
+	case 2:
+		ser_ctrl0 = ADAU17X1_SERIAL_PORT0_STEREO;
+		break;
+	case 4:
+		ser_ctrl0 = ADAU17X1_SERIAL_PORT0_TDM4;
+		break;
+	case 8:
+		if (adau->type == ADAU1361)
+			return -EINVAL;
+
+		ser_ctrl0 = ADAU17X1_SERIAL_PORT0_TDM8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (slot_width * slots) {
+	case 32:
+		if (adau->type == ADAU1761)
+			return -EINVAL;
+
+		ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK32;
+		break;
+	case 64:
+		ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK64;
+		break;
+	case 48:
+		ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK48;
+		break;
+	case 128:
+		ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK128;
+		break;
+	case 256:
+		if (adau->type == ADAU1361)
+			return -EINVAL;
+
+		ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK256;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (rx_mask) {
+	case 0x03:
+		conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(1);
+		adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 0;
+		break;
+	case 0x0c:
+		conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(2);
+		adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 1;
+		break;
+	case 0x30:
+		conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(3);
+		adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 2;
+		break;
+	case 0xc0:
+		conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(4);
+		adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (tx_mask) {
+	case 0x03:
+		conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(1);
+		adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 0;
+		break;
+	case 0x0c:
+		conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(2);
+		adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 1;
+		break;
+	case 0x30:
+		conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(3);
+		adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 2;
+		break;
+	case 0xc0:
+		conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(4);
+		adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0,
+		ADAU17X1_CONVERTER0_DAC_PAIR_MASK, conv_ctrl0);
+	regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER1,
+		ADAU17X1_CONVERTER1_ADC_PAIR_MASK, conv_ctrl1);
+	regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT0,
+		ADAU17X1_SERIAL_PORT0_TDM_MASK, ser_ctrl0);
+	regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1,
+		ADAU17X1_SERIAL_PORT1_BCLK_MASK, ser_ctrl1);
+
+	if (!adau17x1_has_dsp(adau))
+		return 0;
+
+	if (adau->dsp_bypass[SNDRV_PCM_STREAM_PLAYBACK]) {
+		regmap_write(adau->regmap, ADAU17X1_SERIAL_INPUT_ROUTE,
+			(adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] * 2) + 1);
+	}
+
+	if (adau->dsp_bypass[SNDRV_PCM_STREAM_CAPTURE]) {
+		regmap_write(adau->regmap, ADAU17X1_SERIAL_OUTPUT_ROUTE,
+			(adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] * 2) + 1);
+	}
+
+	return 0;
+}
+
+static int adau17x1_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct adau *adau = snd_soc_component_get_drvdata(dai->component);
+
+	if (adau->sigmadsp)
+		return sigmadsp_restrict_params(adau->sigmadsp, substream);
+
+	return 0;
+}
+
+const struct snd_soc_dai_ops adau17x1_dai_ops = {
+	.hw_params	= adau17x1_hw_params,
+	.set_sysclk	= adau17x1_set_dai_sysclk,
+	.set_fmt	= adau17x1_set_dai_fmt,
+	.set_pll	= adau17x1_set_dai_pll,
+	.set_tdm_slot	= adau17x1_set_dai_tdm_slot,
+	.startup	= adau17x1_startup,
+};
+EXPORT_SYMBOL_GPL(adau17x1_dai_ops);
+
+int adau17x1_set_micbias_voltage(struct snd_soc_component *component,
+	enum adau17x1_micbias_voltage micbias)
+{
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+
+	switch (micbias) {
+	case ADAU17X1_MICBIAS_0_90_AVDD:
+	case ADAU17X1_MICBIAS_0_65_AVDD:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_write(adau->regmap, ADAU17X1_MICBIAS, micbias << 2);
+}
+EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage);
+
+bool adau17x1_precious_register(struct device *dev, unsigned int reg)
+{
+	/* SigmaDSP parameter memory */
+	if (reg < 0x400)
+		return true;
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(adau17x1_precious_register);
+
+bool adau17x1_readable_register(struct device *dev, unsigned int reg)
+{
+	/* SigmaDSP parameter memory */
+	if (reg < 0x400)
+		return true;
+
+	switch (reg) {
+	case ADAU17X1_CLOCK_CONTROL:
+	case ADAU17X1_PLL_CONTROL:
+	case ADAU17X1_REC_POWER_MGMT:
+	case ADAU17X1_MICBIAS:
+	case ADAU17X1_SERIAL_PORT0:
+	case ADAU17X1_SERIAL_PORT1:
+	case ADAU17X1_CONVERTER0:
+	case ADAU17X1_CONVERTER1:
+	case ADAU17X1_LEFT_INPUT_DIGITAL_VOL:
+	case ADAU17X1_RIGHT_INPUT_DIGITAL_VOL:
+	case ADAU17X1_ADC_CONTROL:
+	case ADAU17X1_PLAY_POWER_MGMT:
+	case ADAU17X1_DAC_CONTROL0:
+	case ADAU17X1_DAC_CONTROL1:
+	case ADAU17X1_DAC_CONTROL2:
+	case ADAU17X1_SERIAL_PORT_PAD:
+	case ADAU17X1_CONTROL_PORT_PAD0:
+	case ADAU17X1_CONTROL_PORT_PAD1:
+	case ADAU17X1_DSP_SAMPLING_RATE:
+	case ADAU17X1_SERIAL_INPUT_ROUTE:
+	case ADAU17X1_SERIAL_OUTPUT_ROUTE:
+	case ADAU17X1_DSP_ENABLE:
+	case ADAU17X1_DSP_RUN:
+	case ADAU17X1_SERIAL_SAMPLING_RATE:
+		return true;
+	default:
+		break;
+	}
+	return false;
+}
+EXPORT_SYMBOL_GPL(adau17x1_readable_register);
+
+bool adau17x1_volatile_register(struct device *dev, unsigned int reg)
+{
+	/* SigmaDSP parameter and program memory */
+	if (reg < 0x4000)
+		return true;
+
+	switch (reg) {
+	/* The PLL register is 6 bytes long */
+	case ADAU17X1_PLL_CONTROL:
+	case ADAU17X1_PLL_CONTROL + 1:
+	case ADAU17X1_PLL_CONTROL + 2:
+	case ADAU17X1_PLL_CONTROL + 3:
+	case ADAU17X1_PLL_CONTROL + 4:
+	case ADAU17X1_PLL_CONTROL + 5:
+		return true;
+	default:
+		break;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(adau17x1_volatile_register);
+
+int adau17x1_setup_firmware(struct snd_soc_component *component,
+	unsigned int rate)
+{
+	int ret;
+	int dspsr, dsp_run;
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	/* Check if sample rate is the same as before. If it is there is no
+	 * point in performing the below steps as the call to
+	 * sigmadsp_setup(...) will return directly when it finds the sample
+	 * rate to be the same as before. By checking this we can prevent an
+	 * audiable popping noise which occours when toggling DSP_RUN.
+	 */
+	if (adau->sigmadsp->current_samplerate == rate)
+		return 0;
+
+	snd_soc_dapm_mutex_lock(dapm);
+
+	ret = regmap_read(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, &dspsr);
+	if (ret)
+		goto err;
+
+	ret = regmap_read(adau->regmap, ADAU17X1_DSP_RUN, &dsp_run);
+	if (ret)
+		goto err;
+
+	regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1);
+	regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf);
+	regmap_write(adau->regmap, ADAU17X1_DSP_RUN, 0);
+
+	ret = sigmadsp_setup(adau->sigmadsp, rate);
+	if (ret) {
+		regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0);
+		goto err;
+	}
+	regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dspsr);
+	regmap_write(adau->regmap, ADAU17X1_DSP_RUN, dsp_run);
+
+err:
+	snd_soc_dapm_mutex_unlock(dapm);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(adau17x1_setup_firmware);
+
+int adau17x1_add_widgets(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = snd_soc_add_component_controls(component, adau17x1_controls,
+		ARRAY_SIZE(adau17x1_controls));
+	if (ret)
+		return ret;
+	ret = snd_soc_dapm_new_controls(dapm, adau17x1_dapm_widgets,
+		ARRAY_SIZE(adau17x1_dapm_widgets));
+	if (ret)
+		return ret;
+
+	if (adau17x1_has_dsp(adau)) {
+		ret = snd_soc_dapm_new_controls(dapm, adau17x1_dsp_dapm_widgets,
+			ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
+		if (ret)
+			return ret;
+
+		if (!adau->sigmadsp)
+			return 0;
+
+		ret = sigmadsp_attach(adau->sigmadsp, component);
+		if (ret) {
+			dev_err(component->dev, "Failed to attach firmware: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
+
+int adau17x1_add_routes(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = snd_soc_dapm_add_routes(dapm, adau17x1_dapm_routes,
+		ARRAY_SIZE(adau17x1_dapm_routes));
+	if (ret)
+		return ret;
+
+	if (adau17x1_has_dsp(adau)) {
+		ret = snd_soc_dapm_add_routes(dapm, adau17x1_dsp_dapm_routes,
+			ARRAY_SIZE(adau17x1_dsp_dapm_routes));
+	} else {
+		ret = snd_soc_dapm_add_routes(dapm, adau17x1_no_dsp_dapm_routes,
+			ARRAY_SIZE(adau17x1_no_dsp_dapm_routes));
+	}
+
+	if (adau->clk_src != ADAU17X1_CLK_SRC_MCLK)
+		snd_soc_dapm_add_routes(dapm, &adau17x1_dapm_pll_route, 1);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(adau17x1_add_routes);
+
+int adau17x1_resume(struct snd_soc_component *component)
+{
+	struct adau *adau = snd_soc_component_get_drvdata(component);
+
+	if (adau->switch_mode)
+		adau->switch_mode(component->dev);
+
+	regcache_sync(adau->regmap);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(adau17x1_resume);
+
+int adau17x1_probe(struct device *dev, struct regmap *regmap,
+	enum adau17x1_type type, void (*switch_mode)(struct device *dev),
+	const char *firmware_name)
+{
+	struct adau *adau;
+	int ret;
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	adau = devm_kzalloc(dev, sizeof(*adau), GFP_KERNEL);
+	if (!adau)
+		return -ENOMEM;
+
+	adau->mclk = devm_clk_get(dev, "mclk");
+	if (IS_ERR(adau->mclk)) {
+		if (PTR_ERR(adau->mclk) != -ENOENT)
+			return PTR_ERR(adau->mclk);
+		/* Clock is optional (for the driver) */
+		adau->mclk = NULL;
+	} else if (adau->mclk) {
+		adau->clk_src = ADAU17X1_CLK_SRC_PLL_AUTO;
+
+		/*
+		 * Any valid PLL output rate will work at this point, use one
+		 * that is likely to be chosen later as well. The register will
+		 * be written when the PLL is powered up for the first time.
+		 */
+		ret = adau_calc_pll_cfg(clk_get_rate(adau->mclk), 48000 * 1024,
+				adau->pll_regs);
+		if (ret < 0)
+			return ret;
+
+		ret = clk_prepare_enable(adau->mclk);
+		if (ret)
+			return ret;
+	}
+
+	adau->regmap = regmap;
+	adau->switch_mode = switch_mode;
+	adau->type = type;
+
+	dev_set_drvdata(dev, adau);
+
+	if (firmware_name) {
+		adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL,
+			firmware_name);
+		if (IS_ERR(adau->sigmadsp)) {
+			dev_warn(dev, "Could not find firmware file: %ld\n",
+				PTR_ERR(adau->sigmadsp));
+			adau->sigmadsp = NULL;
+		}
+	}
+
+	if (switch_mode)
+		switch_mode(dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(adau17x1_probe);
+
+void adau17x1_remove(struct device *dev)
+{
+	struct adau *adau = dev_get_drvdata(dev);
+
+	if (adau->mclk)
+		clk_disable_unprepare(adau->mclk);
+}
+EXPORT_SYMBOL_GPL(adau17x1_remove);
+
+MODULE_DESCRIPTION("ASoC ADAU1X61/ADAU1X81 common code");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h
new file mode 100644
index 0000000..e6fe87b
--- /dev/null
+++ b/sound/soc/codecs/adau17x1.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ADAU17X1_H__
+#define __ADAU17X1_H__
+
+#include <linux/regmap.h>
+#include <linux/platform_data/adau17x1.h>
+
+#include "sigmadsp.h"
+
+enum adau17x1_type {
+	ADAU1361,
+	ADAU1761,
+	ADAU1381,
+	ADAU1781,
+};
+
+enum adau17x1_pll {
+	ADAU17X1_PLL,
+};
+
+enum adau17x1_pll_src {
+	ADAU17X1_PLL_SRC_MCLK,
+};
+
+enum adau17x1_clk_src {
+	/* Automatically configure PLL based on the sample rate */
+	ADAU17X1_CLK_SRC_PLL_AUTO,
+	ADAU17X1_CLK_SRC_MCLK,
+	ADAU17X1_CLK_SRC_PLL,
+};
+
+struct clk;
+
+struct adau {
+	unsigned int sysclk;
+	unsigned int pll_freq;
+	struct clk *mclk;
+
+	enum adau17x1_clk_src clk_src;
+	enum adau17x1_type type;
+	void (*switch_mode)(struct device *dev);
+
+	unsigned int dai_fmt;
+
+	uint8_t pll_regs[6];
+
+	bool master;
+
+	unsigned int tdm_slot[2];
+	bool dsp_bypass[2];
+
+	struct regmap *regmap;
+	struct sigmadsp *sigmadsp;
+};
+
+int adau17x1_add_widgets(struct snd_soc_component *component);
+int adau17x1_add_routes(struct snd_soc_component *component);
+int adau17x1_probe(struct device *dev, struct regmap *regmap,
+	enum adau17x1_type type, void (*switch_mode)(struct device *dev),
+	const char *firmware_name);
+void adau17x1_remove(struct device *dev);
+int adau17x1_set_micbias_voltage(struct snd_soc_component *component,
+	enum adau17x1_micbias_voltage micbias);
+bool adau17x1_readable_register(struct device *dev, unsigned int reg);
+bool adau17x1_volatile_register(struct device *dev, unsigned int reg);
+bool adau17x1_precious_register(struct device *dev, unsigned int reg);
+int adau17x1_resume(struct snd_soc_component *component);
+
+extern const struct snd_soc_dai_ops adau17x1_dai_ops;
+
+int adau17x1_setup_firmware(struct snd_soc_component *component,
+	unsigned int rate);
+bool adau17x1_has_dsp(struct adau *adau);
+
+#define ADAU17X1_CLOCK_CONTROL			0x4000
+#define ADAU17X1_PLL_CONTROL			0x4002
+#define ADAU17X1_REC_POWER_MGMT			0x4009
+#define ADAU17X1_MICBIAS			0x4010
+#define ADAU17X1_SERIAL_PORT0			0x4015
+#define ADAU17X1_SERIAL_PORT1			0x4016
+#define ADAU17X1_CONVERTER0			0x4017
+#define ADAU17X1_CONVERTER1			0x4018
+#define ADAU17X1_LEFT_INPUT_DIGITAL_VOL		0x401a
+#define ADAU17X1_RIGHT_INPUT_DIGITAL_VOL	0x401b
+#define ADAU17X1_ADC_CONTROL			0x4019
+#define ADAU17X1_PLAY_POWER_MGMT		0x4029
+#define ADAU17X1_DAC_CONTROL0			0x402a
+#define ADAU17X1_DAC_CONTROL1			0x402b
+#define ADAU17X1_DAC_CONTROL2			0x402c
+#define ADAU17X1_SERIAL_PORT_PAD		0x402d
+#define ADAU17X1_CONTROL_PORT_PAD0		0x402f
+#define ADAU17X1_CONTROL_PORT_PAD1		0x4030
+#define ADAU17X1_DSP_SAMPLING_RATE		0x40eb
+#define ADAU17X1_SERIAL_INPUT_ROUTE		0x40f2
+#define ADAU17X1_SERIAL_OUTPUT_ROUTE		0x40f3
+#define ADAU17X1_DSP_ENABLE			0x40f5
+#define ADAU17X1_DSP_RUN			0x40f6
+#define ADAU17X1_SERIAL_SAMPLING_RATE		0x40f8
+
+#define ADAU17X1_SERIAL_PORT0_BCLK_POL		BIT(4)
+#define ADAU17X1_SERIAL_PORT0_LRCLK_POL		BIT(3)
+#define ADAU17X1_SERIAL_PORT0_MASTER		BIT(0)
+
+#define ADAU17X1_SERIAL_PORT1_DELAY1		0x00
+#define ADAU17X1_SERIAL_PORT1_DELAY0		0x01
+#define ADAU17X1_SERIAL_PORT1_DELAY8		0x02
+#define ADAU17X1_SERIAL_PORT1_DELAY16		0x03
+#define ADAU17X1_SERIAL_PORT1_DELAY_MASK	0x03
+
+#define ADAU17X1_CLOCK_CONTROL_INFREQ_MASK	0x6
+#define ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL	BIT(3)
+#define ADAU17X1_CLOCK_CONTROL_SYSCLK_EN	BIT(0)
+
+#define ADAU17X1_SERIAL_PORT1_BCLK64		(0x0 << 5)
+#define ADAU17X1_SERIAL_PORT1_BCLK32		(0x1 << 5)
+#define ADAU17X1_SERIAL_PORT1_BCLK48		(0x2 << 5)
+#define ADAU17X1_SERIAL_PORT1_BCLK128		(0x3 << 5)
+#define ADAU17X1_SERIAL_PORT1_BCLK256		(0x4 << 5)
+#define ADAU17X1_SERIAL_PORT1_BCLK_MASK		(0x7 << 5)
+
+#define ADAU17X1_SERIAL_PORT0_STEREO		(0x0 << 1)
+#define ADAU17X1_SERIAL_PORT0_TDM4		(0x1 << 1)
+#define ADAU17X1_SERIAL_PORT0_TDM8		(0x2 << 1)
+#define ADAU17X1_SERIAL_PORT0_TDM_MASK		(0x3 << 1)
+#define ADAU17X1_SERIAL_PORT0_PULSE_MODE	BIT(5)
+
+#define ADAU17X1_CONVERTER0_DAC_PAIR(x)		(((x) - 1) << 5)
+#define ADAU17X1_CONVERTER0_DAC_PAIR_MASK	(0x3 << 5)
+#define ADAU17X1_CONVERTER1_ADC_PAIR(x)		((x) - 1)
+#define ADAU17X1_CONVERTER1_ADC_PAIR_MASK	0x3
+
+#define ADAU17X1_CONVERTER0_CONVSR_MASK		0x7
+
+#define ADAU17X1_CONVERTER0_ADOSR		BIT(3)
+
+
+#endif
diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c
new file mode 100644
index 0000000..e7fe1ee
--- /dev/null
+++ b/sound/soc/codecs/adau1977-i2c.c
@@ -0,0 +1,51 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "adau1977.h"
+
+static int adau1977_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct regmap_config config;
+
+	config = adau1977_regmap_config;
+	config.val_bits = 8;
+	config.reg_bits = 8;
+
+	return adau1977_probe(&client->dev,
+		devm_regmap_init_i2c(client, &config),
+		id->driver_data, NULL);
+}
+
+static const struct i2c_device_id adau1977_i2c_ids[] = {
+	{ "adau1977", ADAU1977 },
+	{ "adau1978", ADAU1978 },
+	{ "adau1979", ADAU1978 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids);
+
+static struct i2c_driver adau1977_i2c_driver = {
+	.driver = {
+		.name = "adau1977",
+	},
+	.probe = adau1977_i2c_probe,
+	.id_table = adau1977_i2c_ids,
+};
+module_i2c_driver(adau1977_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1977-spi.c b/sound/soc/codecs/adau1977-spi.c
new file mode 100644
index 0000000..84ffbde
--- /dev/null
+++ b/sound/soc/codecs/adau1977-spi.c
@@ -0,0 +1,68 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include "adau1977.h"
+
+static void adau1977_spi_switch_mode(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+
+	/*
+	 * To get the device into SPI mode CLATCH has to be pulled low three
+	 * times.  Do this by issuing three dummy reads.
+	 */
+	spi_w8r8(spi, 0x00);
+	spi_w8r8(spi, 0x00);
+	spi_w8r8(spi, 0x00);
+}
+
+static int adau1977_spi_probe(struct spi_device *spi)
+{
+	const struct spi_device_id *id = spi_get_device_id(spi);
+	struct regmap_config config;
+
+	if (!id)
+		return -EINVAL;
+
+	config = adau1977_regmap_config;
+	config.val_bits = 8;
+	config.reg_bits = 16;
+	config.read_flag_mask = 0x1;
+
+	return adau1977_probe(&spi->dev,
+		devm_regmap_init_spi(spi, &config),
+		id->driver_data, adau1977_spi_switch_mode);
+}
+
+static const struct spi_device_id adau1977_spi_ids[] = {
+	{ "adau1977", ADAU1977 },
+	{ "adau1978", ADAU1978 },
+	{ "adau1979", ADAU1978 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, adau1977_spi_ids);
+
+static struct spi_driver adau1977_spi_driver = {
+	.driver = {
+		.name = "adau1977",
+	},
+	.probe = adau1977_spi_probe,
+	.id_table = adau1977_spi_ids,
+};
+module_spi_driver(adau1977_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
new file mode 100644
index 0000000..116af6a
--- /dev/null
+++ b/sound/soc/codecs/adau1977.c
@@ -0,0 +1,1006 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_data/adau1977.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "adau1977.h"
+
+#define ADAU1977_REG_POWER		0x00
+#define ADAU1977_REG_PLL		0x01
+#define ADAU1977_REG_BOOST		0x02
+#define ADAU1977_REG_MICBIAS		0x03
+#define ADAU1977_REG_BLOCK_POWER_SAI	0x04
+#define ADAU1977_REG_SAI_CTRL0		0x05
+#define ADAU1977_REG_SAI_CTRL1		0x06
+#define ADAU1977_REG_CMAP12		0x07
+#define ADAU1977_REG_CMAP34		0x08
+#define ADAU1977_REG_SAI_OVERTEMP	0x09
+#define ADAU1977_REG_POST_ADC_GAIN(x)	(0x0a + (x))
+#define ADAU1977_REG_MISC_CONTROL	0x0e
+#define ADAU1977_REG_DIAG_CONTROL	0x10
+#define ADAU1977_REG_STATUS(x)		(0x11 + (x))
+#define ADAU1977_REG_DIAG_IRQ1		0x15
+#define ADAU1977_REG_DIAG_IRQ2		0x16
+#define ADAU1977_REG_ADJUST1		0x17
+#define ADAU1977_REG_ADJUST2		0x18
+#define ADAU1977_REG_ADC_CLIP		0x19
+#define ADAU1977_REG_DC_HPF_CAL		0x1a
+
+#define ADAU1977_POWER_RESET			BIT(7)
+#define ADAU1977_POWER_PWUP			BIT(0)
+
+#define ADAU1977_PLL_CLK_S			BIT(4)
+#define ADAU1977_PLL_MCS_MASK			0x7
+
+#define ADAU1977_MICBIAS_MB_VOLTS_MASK		0xf0
+#define ADAU1977_MICBIAS_MB_VOLTS_OFFSET	4
+
+#define ADAU1977_BLOCK_POWER_SAI_LR_POL		BIT(7)
+#define ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE	BIT(6)
+#define ADAU1977_BLOCK_POWER_SAI_LDO_EN		BIT(5)
+
+#define ADAU1977_SAI_CTRL0_FMT_MASK		(0x3 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_I2S		(0x0 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_LJ		(0x1 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_RJ_24BIT		(0x2 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_RJ_16BIT		(0x3 << 6)
+
+#define ADAU1977_SAI_CTRL0_SAI_MASK		(0x7 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_I2S		(0x0 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_2		(0x1 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_4		(0x2 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_8		(0x3 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_16		(0x4 << 3)
+
+#define ADAU1977_SAI_CTRL0_FS_MASK		(0x7)
+#define ADAU1977_SAI_CTRL0_FS_8000_12000	(0x0)
+#define ADAU1977_SAI_CTRL0_FS_16000_24000	(0x1)
+#define ADAU1977_SAI_CTRL0_FS_32000_48000	(0x2)
+#define ADAU1977_SAI_CTRL0_FS_64000_96000	(0x3)
+#define ADAU1977_SAI_CTRL0_FS_128000_192000	(0x4)
+
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK	(0x3 << 5)
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_32	(0x0 << 5)
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_24	(0x1 << 5)
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_16	(0x2 << 5)
+#define ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK	(0x1 << 4)
+#define ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT	(0x1 << 4)
+#define ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT	(0x0 << 4)
+#define ADAU1977_SAI_CTRL1_LRCLK_PULSE		BIT(3)
+#define ADAU1977_SAI_CTRL1_MSB			BIT(2)
+#define ADAU1977_SAI_CTRL1_BCLKRATE_16		(0x1 << 1)
+#define ADAU1977_SAI_CTRL1_BCLKRATE_32		(0x0 << 1)
+#define ADAU1977_SAI_CTRL1_BCLKRATE_MASK	(0x1 << 1)
+#define ADAU1977_SAI_CTRL1_MASTER		BIT(0)
+
+#define ADAU1977_SAI_OVERTEMP_DRV_C(x)		BIT(4 + (x))
+#define ADAU1977_SAI_OVERTEMP_DRV_HIZ		BIT(3)
+
+#define ADAU1977_MISC_CONTROL_SUM_MODE_MASK	(0x3 << 6)
+#define ADAU1977_MISC_CONTROL_SUM_MODE_1CH	(0x2 << 6)
+#define ADAU1977_MISC_CONTROL_SUM_MODE_2CH	(0x1 << 6)
+#define ADAU1977_MISC_CONTROL_SUM_MODE_4CH	(0x0 << 6)
+#define ADAU1977_MISC_CONTROL_MMUTE		BIT(4)
+#define ADAU1977_MISC_CONTROL_DC_CAL		BIT(0)
+
+#define ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET	4
+#define ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET	0
+
+struct adau1977 {
+	struct regmap *regmap;
+	bool right_j;
+	unsigned int sysclk;
+	enum adau1977_sysclk_src sysclk_src;
+	struct gpio_desc *reset_gpio;
+	enum adau1977_type type;
+
+	struct regulator *avdd_reg;
+	struct regulator *dvdd_reg;
+
+	struct snd_pcm_hw_constraint_list constraints;
+
+	struct device *dev;
+	void (*switch_mode)(struct device *dev);
+
+	unsigned int max_master_fs;
+	unsigned int slot_width;
+	bool enabled;
+	bool master;
+};
+
+static const struct reg_default adau1977_reg_defaults[] = {
+	{ 0x00, 0x00 },
+	{ 0x01, 0x41 },
+	{ 0x02, 0x4a },
+	{ 0x03, 0x7d },
+	{ 0x04, 0x3d },
+	{ 0x05, 0x02 },
+	{ 0x06, 0x00 },
+	{ 0x07, 0x10 },
+	{ 0x08, 0x32 },
+	{ 0x09, 0xf0 },
+	{ 0x0a, 0xa0 },
+	{ 0x0b, 0xa0 },
+	{ 0x0c, 0xa0 },
+	{ 0x0d, 0xa0 },
+	{ 0x0e, 0x02 },
+	{ 0x10, 0x0f },
+	{ 0x15, 0x20 },
+	{ 0x16, 0x00 },
+	{ 0x17, 0x00 },
+	{ 0x18, 0x00 },
+	{ 0x1a, 0x00 },
+};
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(adau1977_adc_gain, -3562, 6000);
+
+static const struct snd_soc_dapm_widget adau1977_micbias_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU1977_REG_MICBIAS,
+		3, 0, NULL, 0)
+};
+
+static const struct snd_soc_dapm_widget adau1977_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("Vref", ADAU1977_REG_BLOCK_POWER_SAI,
+		4, 0, NULL, 0),
+
+	SND_SOC_DAPM_ADC("ADC1", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 0, 0),
+	SND_SOC_DAPM_ADC("ADC2", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 1, 0),
+	SND_SOC_DAPM_ADC("ADC3", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 2, 0),
+	SND_SOC_DAPM_ADC("ADC4", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 3, 0),
+
+	SND_SOC_DAPM_INPUT("AIN1"),
+	SND_SOC_DAPM_INPUT("AIN2"),
+	SND_SOC_DAPM_INPUT("AIN3"),
+	SND_SOC_DAPM_INPUT("AIN4"),
+
+	SND_SOC_DAPM_OUTPUT("VREF"),
+};
+
+static const struct snd_soc_dapm_route adau1977_dapm_routes[] = {
+	{ "ADC1", NULL, "AIN1" },
+	{ "ADC2", NULL, "AIN2" },
+	{ "ADC3", NULL, "AIN3" },
+	{ "ADC4", NULL, "AIN4" },
+
+	{ "ADC1", NULL, "Vref" },
+	{ "ADC2", NULL, "Vref" },
+	{ "ADC3", NULL, "Vref" },
+	{ "ADC4", NULL, "Vref" },
+
+	{ "VREF", NULL, "Vref" },
+};
+
+#define ADAU1977_VOLUME(x) \
+	SOC_SINGLE_TLV("ADC" #x " Capture Volume", \
+		ADAU1977_REG_POST_ADC_GAIN((x) - 1), \
+		0, 255, 1, adau1977_adc_gain)
+
+#define ADAU1977_HPF_SWITCH(x) \
+	SOC_SINGLE("ADC" #x " Highpass-Filter Capture Switch", \
+		ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0)
+
+#define ADAU1977_DC_SUB_SWITCH(x) \
+	SOC_SINGLE("ADC" #x " DC Subtraction Capture Switch", \
+		ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0)
+
+static const struct snd_kcontrol_new adau1977_snd_controls[] = {
+	ADAU1977_VOLUME(1),
+	ADAU1977_VOLUME(2),
+	ADAU1977_VOLUME(3),
+	ADAU1977_VOLUME(4),
+
+	ADAU1977_HPF_SWITCH(1),
+	ADAU1977_HPF_SWITCH(2),
+	ADAU1977_HPF_SWITCH(3),
+	ADAU1977_HPF_SWITCH(4),
+
+	ADAU1977_DC_SUB_SWITCH(1),
+	ADAU1977_DC_SUB_SWITCH(2),
+	ADAU1977_DC_SUB_SWITCH(3),
+	ADAU1977_DC_SUB_SWITCH(4),
+};
+
+static int adau1977_reset(struct adau1977 *adau1977)
+{
+	int ret;
+
+	/*
+	 * The reset bit is obviously volatile, but we need to be able to cache
+	 * the other bits in the register, so we can't just mark the whole
+	 * register as volatile. Since this is the only place where we'll ever
+	 * touch the reset bit just bypass the cache for this operation.
+	 */
+	regcache_cache_bypass(adau1977->regmap, true);
+	ret = regmap_write(adau1977->regmap, ADAU1977_REG_POWER,
+			ADAU1977_POWER_RESET);
+	regcache_cache_bypass(adau1977->regmap, false);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+/*
+ * Returns the appropriate setting for ths FS field in the CTRL0 register
+ * depending on the rate.
+ */
+static int adau1977_lookup_fs(unsigned int rate)
+{
+	if (rate >= 8000 && rate <= 12000)
+		return ADAU1977_SAI_CTRL0_FS_8000_12000;
+	else if (rate >= 16000 && rate <= 24000)
+		return ADAU1977_SAI_CTRL0_FS_16000_24000;
+	else if (rate >= 32000 && rate <= 48000)
+		return ADAU1977_SAI_CTRL0_FS_32000_48000;
+	else if (rate >= 64000 && rate <= 96000)
+		return ADAU1977_SAI_CTRL0_FS_64000_96000;
+	else if (rate >= 128000 && rate <= 192000)
+		return ADAU1977_SAI_CTRL0_FS_128000_192000;
+	else
+		return -EINVAL;
+}
+
+static int adau1977_lookup_mcs(struct adau1977 *adau1977, unsigned int rate,
+	unsigned int fs)
+{
+	unsigned int mcs;
+
+	/*
+	 * rate = sysclk / (512 * mcs_lut[mcs]) * 2**fs
+	 * => mcs_lut[mcs] = sysclk / (512 * rate) * 2**fs
+	 * => mcs_lut[mcs] = sysclk / ((512 / 2**fs) * rate)
+	 */
+
+	rate *= 512 >> fs;
+
+	if (adau1977->sysclk % rate != 0)
+		return -EINVAL;
+
+	mcs = adau1977->sysclk / rate;
+
+	/* The factors configured by MCS are 1, 2, 3, 4, 6 */
+	if (mcs < 1 || mcs > 6 || mcs == 5)
+		return -EINVAL;
+
+	mcs = mcs - 1;
+	if (mcs == 5)
+		mcs = 4;
+
+	return mcs;
+}
+
+static int adau1977_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
+	unsigned int rate = params_rate(params);
+	unsigned int slot_width;
+	unsigned int ctrl0, ctrl0_mask;
+	unsigned int ctrl1;
+	int mcs, fs;
+	int ret;
+
+	fs = adau1977_lookup_fs(rate);
+	if (fs < 0)
+		return fs;
+
+	if (adau1977->sysclk_src == ADAU1977_SYSCLK_SRC_MCLK) {
+		mcs = adau1977_lookup_mcs(adau1977, rate, fs);
+		if (mcs < 0)
+			return mcs;
+	} else {
+		mcs = 0;
+	}
+
+	ctrl0_mask = ADAU1977_SAI_CTRL0_FS_MASK;
+	ctrl0 = fs;
+
+	if (adau1977->right_j) {
+		switch (params_width(params)) {
+		case 16:
+			ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_16BIT;
+			break;
+		case 24:
+			ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT;
+			break;
+		default:
+			return -EINVAL;
+		}
+		ctrl0_mask |= ADAU1977_SAI_CTRL0_FMT_MASK;
+	}
+
+	if (adau1977->master) {
+		switch (params_width(params)) {
+		case 16:
+			ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT;
+			slot_width = 16;
+			break;
+		case 24:
+		case 32:
+			ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT;
+			slot_width = 32;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		/* In TDM mode there is a fixed slot width */
+		if (adau1977->slot_width)
+			slot_width = adau1977->slot_width;
+
+		if (slot_width == 16)
+			ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_16;
+		else
+			ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_32;
+
+		ret = regmap_update_bits(adau1977->regmap,
+			ADAU1977_REG_SAI_CTRL1,
+			ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK |
+			ADAU1977_SAI_CTRL1_BCLKRATE_MASK,
+			ctrl1);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
+				ctrl0_mask, ctrl0);
+	if (ret < 0)
+		return ret;
+
+	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL,
+				ADAU1977_PLL_MCS_MASK, mcs);
+}
+
+static int adau1977_power_disable(struct adau1977 *adau1977)
+{
+	int ret = 0;
+
+	if (!adau1977->enabled)
+		return 0;
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER,
+		ADAU1977_POWER_PWUP, 0);
+	if (ret)
+		return ret;
+
+	regcache_mark_dirty(adau1977->regmap);
+
+	gpiod_set_value_cansleep(adau1977->reset_gpio, 0);
+
+	regcache_cache_only(adau1977->regmap, true);
+
+	regulator_disable(adau1977->avdd_reg);
+	if (adau1977->dvdd_reg)
+		regulator_disable(adau1977->dvdd_reg);
+
+	adau1977->enabled = false;
+
+	return 0;
+}
+
+static int adau1977_power_enable(struct adau1977 *adau1977)
+{
+	unsigned int val;
+	int ret = 0;
+
+	if (adau1977->enabled)
+		return 0;
+
+	ret = regulator_enable(adau1977->avdd_reg);
+	if (ret)
+		return ret;
+
+	if (adau1977->dvdd_reg) {
+		ret = regulator_enable(adau1977->dvdd_reg);
+		if (ret)
+			goto err_disable_avdd;
+	}
+
+	gpiod_set_value_cansleep(adau1977->reset_gpio, 1);
+
+	regcache_cache_only(adau1977->regmap, false);
+
+	if (adau1977->switch_mode)
+		adau1977->switch_mode(adau1977->dev);
+
+	ret = adau1977_reset(adau1977);
+	if (ret)
+		goto err_disable_dvdd;
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER,
+		ADAU1977_POWER_PWUP, ADAU1977_POWER_PWUP);
+	if (ret)
+		goto err_disable_dvdd;
+
+	ret = regcache_sync(adau1977->regmap);
+	if (ret)
+		goto err_disable_dvdd;
+
+	/*
+	 * The PLL register is not affected by the software reset. It is
+	 * possible that the value of the register was changed to the
+	 * default value while we were in cache only mode. In this case
+	 * regcache_sync will skip over it and we have to manually sync
+	 * it.
+	 */
+	ret = regmap_read(adau1977->regmap, ADAU1977_REG_PLL, &val);
+	if (ret)
+		goto err_disable_dvdd;
+
+	if (val == 0x41) {
+		regcache_cache_bypass(adau1977->regmap, true);
+		ret = regmap_write(adau1977->regmap, ADAU1977_REG_PLL,
+			0x41);
+		if (ret)
+			goto err_disable_dvdd;
+		regcache_cache_bypass(adau1977->regmap, false);
+	}
+
+	adau1977->enabled = true;
+
+	return ret;
+
+err_disable_dvdd:
+	if (adau1977->dvdd_reg)
+		regulator_disable(adau1977->dvdd_reg);
+err_disable_avdd:
+		regulator_disable(adau1977->avdd_reg);
+	return ret;
+}
+
+static int adau1977_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			ret = adau1977_power_enable(adau1977);
+		break;
+	case SND_SOC_BIAS_OFF:
+		ret = adau1977_power_disable(adau1977);
+		break;
+	}
+
+	return ret;
+}
+
+static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+	unsigned int rx_mask, int slots, int width)
+{
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
+	unsigned int ctrl0, ctrl1, drv;
+	unsigned int slot[4];
+	unsigned int i;
+	int ret;
+
+	if (slots == 0) {
+		/* 0 = No fixed slot width */
+		adau1977->slot_width = 0;
+		adau1977->max_master_fs = 192000;
+		return regmap_update_bits(adau1977->regmap,
+			ADAU1977_REG_SAI_CTRL0, ADAU1977_SAI_CTRL0_SAI_MASK,
+			ADAU1977_SAI_CTRL0_SAI_I2S);
+	}
+
+	if (rx_mask == 0 || tx_mask != 0)
+		return -EINVAL;
+
+	drv = 0;
+	for (i = 0; i < 4; i++) {
+		slot[i] = __ffs(rx_mask);
+		drv |= ADAU1977_SAI_OVERTEMP_DRV_C(i);
+		rx_mask &= ~(1 << slot[i]);
+		if (slot[i] >= slots)
+			return -EINVAL;
+		if (rx_mask == 0)
+			break;
+	}
+
+	if (rx_mask != 0)
+		return -EINVAL;
+
+	switch (width) {
+	case 16:
+		ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_16;
+		break;
+	case 24:
+		/* We can only generate 16 bit or 32 bit wide slots */
+		if (adau1977->master)
+			return -EINVAL;
+		ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_24;
+		break;
+	case 32:
+		ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (slots) {
+	case 2:
+		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_2;
+		break;
+	case 4:
+		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_4;
+		break;
+	case 8:
+		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_8;
+		break;
+	case 16:
+		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_16;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP,
+		ADAU1977_SAI_OVERTEMP_DRV_C(0) |
+		ADAU1977_SAI_OVERTEMP_DRV_C(1) |
+		ADAU1977_SAI_OVERTEMP_DRV_C(2) |
+		ADAU1977_SAI_OVERTEMP_DRV_C(3), drv);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP12,
+		(slot[1] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) |
+		(slot[0] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET));
+	if (ret)
+		return ret;
+
+	ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP34,
+		(slot[3] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) |
+		(slot[2] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET));
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
+		ADAU1977_SAI_CTRL0_SAI_MASK, ctrl0);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1,
+		ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK, ctrl1);
+	if (ret)
+		return ret;
+
+	adau1977->slot_width = width;
+
+	/* In master mode the maximum bitclock is 24.576 MHz */
+	adau1977->max_master_fs = min(192000, 24576000 / width / slots);
+
+	return 0;
+}
+
+static int adau1977_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
+	unsigned int val;
+
+	if (mute)
+		val = ADAU1977_MISC_CONTROL_MMUTE;
+	else
+		val = 0;
+
+	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MISC_CONTROL,
+			ADAU1977_MISC_CONTROL_MMUTE, val);
+}
+
+static int adau1977_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
+	unsigned int ctrl0 = 0, ctrl1 = 0, block_power = 0;
+	bool invert_lrclk;
+	int ret;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		adau1977->master = false;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		ctrl1 |= ADAU1977_SAI_CTRL1_MASTER;
+		adau1977->master = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		invert_lrclk = false;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE;
+		invert_lrclk = false;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		invert_lrclk = true;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE;
+		invert_lrclk = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	adau1977->right_j = false;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ;
+		invert_lrclk = !invert_lrclk;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT;
+		adau1977->right_j = true;
+		invert_lrclk = !invert_lrclk;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE;
+		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S;
+		invert_lrclk = false;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE;
+		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ;
+		invert_lrclk = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (invert_lrclk)
+		block_power |= ADAU1977_BLOCK_POWER_SAI_LR_POL;
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI,
+		ADAU1977_BLOCK_POWER_SAI_LR_POL |
+		ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE, block_power);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
+		ADAU1977_SAI_CTRL0_FMT_MASK,
+		ctrl0);
+	if (ret)
+		return ret;
+
+	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1,
+		ADAU1977_SAI_CTRL1_MASTER | ADAU1977_SAI_CTRL1_LRCLK_PULSE,
+		ctrl1);
+}
+
+static int adau1977_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
+	u64 formats = 0;
+
+	if (adau1977->slot_width == 16)
+		formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE;
+	else if (adau1977->right_j || adau1977->slot_width == 24)
+		formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE;
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+		SNDRV_PCM_HW_PARAM_RATE, &adau1977->constraints);
+
+	if (adau1977->master)
+		snd_pcm_hw_constraint_minmax(substream->runtime,
+			SNDRV_PCM_HW_PARAM_RATE, 8000, adau1977->max_master_fs);
+
+	if (formats != 0)
+		snd_pcm_hw_constraint_mask64(substream->runtime,
+			SNDRV_PCM_HW_PARAM_FORMAT, formats);
+
+	return 0;
+}
+
+static int adau1977_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
+	unsigned int val;
+
+	if (tristate)
+		val = ADAU1977_SAI_OVERTEMP_DRV_HIZ;
+	else
+		val = 0;
+
+	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP,
+		ADAU1977_SAI_OVERTEMP_DRV_HIZ, val);
+}
+
+static const struct snd_soc_dai_ops adau1977_dai_ops = {
+	.startup	= adau1977_startup,
+	.hw_params	= adau1977_hw_params,
+	.mute_stream	= adau1977_mute,
+	.set_fmt	= adau1977_set_dai_fmt,
+	.set_tdm_slot	= adau1977_set_tdm_slot,
+	.set_tristate	= adau1977_set_tristate,
+};
+
+static struct snd_soc_dai_driver adau1977_dai = {
+	.name = "adau1977-hifi",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 4,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+		    SNDRV_PCM_FMTBIT_S32_LE,
+		.sig_bits = 24,
+	},
+	.ops = &adau1977_dai_ops,
+};
+
+static const unsigned int adau1977_rates[] = {
+	8000, 16000, 32000, 64000, 128000,
+	11025, 22050, 44100, 88200, 172400,
+	12000, 24000, 48000, 96000, 192000,
+};
+
+#define ADAU1977_RATE_CONSTRAINT_MASK_32000 0x001f
+#define ADAU1977_RATE_CONSTRAINT_MASK_44100 0x03e0
+#define ADAU1977_RATE_CONSTRAINT_MASK_48000 0x7c00
+/* All rates >= 32000 */
+#define ADAU1977_RATE_CONSTRAINT_MASK_LRCLK 0x739c
+
+static bool adau1977_check_sysclk(unsigned int mclk, unsigned int base_freq)
+{
+	unsigned int mcs;
+
+	if (mclk % (base_freq * 128) != 0)
+		return false;
+
+	mcs = mclk / (128 * base_freq);
+	if (mcs < 1 || mcs > 6 || mcs == 5)
+		return false;
+
+	return true;
+}
+
+static int adau1977_set_sysclk(struct snd_soc_component *component,
+	int clk_id, int source, unsigned int freq, int dir)
+{
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
+	unsigned int mask = 0;
+	unsigned int clk_src;
+	unsigned int ret;
+
+	if (dir != SND_SOC_CLOCK_IN)
+		return -EINVAL;
+
+	if (clk_id != ADAU1977_SYSCLK)
+		return -EINVAL;
+
+	switch (source) {
+	case ADAU1977_SYSCLK_SRC_MCLK:
+		clk_src = 0;
+		break;
+	case ADAU1977_SYSCLK_SRC_LRCLK:
+		clk_src = ADAU1977_PLL_CLK_S;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (freq != 0 && source == ADAU1977_SYSCLK_SRC_MCLK) {
+		if (freq < 4000000 || freq > 36864000)
+			return -EINVAL;
+
+		if (adau1977_check_sysclk(freq, 32000))
+			mask |= ADAU1977_RATE_CONSTRAINT_MASK_32000;
+		if (adau1977_check_sysclk(freq, 44100))
+			mask |= ADAU1977_RATE_CONSTRAINT_MASK_44100;
+		if (adau1977_check_sysclk(freq, 48000))
+			mask |= ADAU1977_RATE_CONSTRAINT_MASK_48000;
+
+		if (mask == 0)
+			return -EINVAL;
+	} else if (source == ADAU1977_SYSCLK_SRC_LRCLK) {
+		mask = ADAU1977_RATE_CONSTRAINT_MASK_LRCLK;
+	}
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL,
+		ADAU1977_PLL_CLK_S, clk_src);
+	if (ret)
+		return ret;
+
+	adau1977->constraints.mask = mask;
+	adau1977->sysclk_src = source;
+	adau1977->sysclk = freq;
+
+	return 0;
+}
+
+static int adau1977_component_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (adau1977->type) {
+	case ADAU1977:
+		ret = snd_soc_dapm_new_controls(dapm,
+			adau1977_micbias_dapm_widgets,
+			ARRAY_SIZE(adau1977_micbias_dapm_widgets));
+		if (ret < 0)
+			return ret;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver adau1977_component_driver = {
+	.probe			= adau1977_component_probe,
+	.set_bias_level		= adau1977_set_bias_level,
+	.set_sysclk		= adau1977_set_sysclk,
+	.controls		= adau1977_snd_controls,
+	.num_controls		= ARRAY_SIZE(adau1977_snd_controls),
+	.dapm_widgets		= adau1977_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(adau1977_dapm_widgets),
+	.dapm_routes		= adau1977_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(adau1977_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int adau1977_setup_micbias(struct adau1977 *adau1977)
+{
+	struct adau1977_platform_data *pdata = adau1977->dev->platform_data;
+	unsigned int micbias;
+
+	if (pdata) {
+		micbias = pdata->micbias;
+		if (micbias > ADAU1977_MICBIAS_9V0)
+			return -EINVAL;
+
+	} else {
+		micbias = ADAU1977_MICBIAS_8V5;
+	}
+
+	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MICBIAS,
+		ADAU1977_MICBIAS_MB_VOLTS_MASK,
+		micbias << ADAU1977_MICBIAS_MB_VOLTS_OFFSET);
+}
+
+int adau1977_probe(struct device *dev, struct regmap *regmap,
+	enum adau1977_type type, void (*switch_mode)(struct device *dev))
+{
+	unsigned int power_off_mask;
+	struct adau1977 *adau1977;
+	int ret;
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	adau1977 = devm_kzalloc(dev, sizeof(*adau1977), GFP_KERNEL);
+	if (adau1977 == NULL)
+		return -ENOMEM;
+
+	adau1977->dev = dev;
+	adau1977->type = type;
+	adau1977->regmap = regmap;
+	adau1977->switch_mode = switch_mode;
+	adau1977->max_master_fs = 192000;
+
+	adau1977->constraints.list = adau1977_rates;
+	adau1977->constraints.count = ARRAY_SIZE(adau1977_rates);
+
+	adau1977->avdd_reg = devm_regulator_get(dev, "AVDD");
+	if (IS_ERR(adau1977->avdd_reg))
+		return PTR_ERR(adau1977->avdd_reg);
+
+	adau1977->dvdd_reg = devm_regulator_get_optional(dev, "DVDD");
+	if (IS_ERR(adau1977->dvdd_reg)) {
+		if (PTR_ERR(adau1977->dvdd_reg) != -ENODEV)
+			return PTR_ERR(adau1977->dvdd_reg);
+		adau1977->dvdd_reg = NULL;
+	}
+
+	adau1977->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						       GPIOD_OUT_LOW);
+	if (IS_ERR(adau1977->reset_gpio))
+		return PTR_ERR(adau1977->reset_gpio);
+
+	dev_set_drvdata(dev, adau1977);
+
+	if (adau1977->reset_gpio)
+		ndelay(100);
+
+	ret = adau1977_power_enable(adau1977);
+	if (ret)
+		return ret;
+
+	if (type == ADAU1977) {
+		ret = adau1977_setup_micbias(adau1977);
+		if (ret)
+			goto err_poweroff;
+	}
+
+	if (adau1977->dvdd_reg)
+		power_off_mask = ~0;
+	else
+		power_off_mask = (unsigned int)~ADAU1977_BLOCK_POWER_SAI_LDO_EN;
+
+	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI,
+				power_off_mask, 0x00);
+	if (ret)
+		goto err_poweroff;
+
+	ret = adau1977_power_disable(adau1977);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_component(dev, &adau1977_component_driver,
+			&adau1977_dai, 1);
+
+err_poweroff:
+	adau1977_power_disable(adau1977);
+	return ret;
+
+}
+EXPORT_SYMBOL_GPL(adau1977_probe);
+
+static bool adau1977_register_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case ADAU1977_REG_STATUS(0):
+	case ADAU1977_REG_STATUS(1):
+	case ADAU1977_REG_STATUS(2):
+	case ADAU1977_REG_STATUS(3):
+	case ADAU1977_REG_ADC_CLIP:
+		return true;
+	}
+
+	return false;
+}
+
+const struct regmap_config adau1977_regmap_config = {
+	.max_register = ADAU1977_REG_DC_HPF_CAL,
+	.volatile_reg = adau1977_register_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = adau1977_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(adau1977_reg_defaults),
+};
+EXPORT_SYMBOL_GPL(adau1977_regmap_config);
+
+MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1977.h b/sound/soc/codecs/adau1977.h
new file mode 100644
index 0000000..95e7143
--- /dev/null
+++ b/sound/soc/codecs/adau1977.h
@@ -0,0 +1,37 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __SOUND_SOC_CODECS_ADAU1977_H__
+#define __SOUND_SOC_CODECS_ADAU1977_H__
+
+#include <linux/regmap.h>
+
+struct device;
+
+enum adau1977_type {
+	ADAU1977,
+	ADAU1978,
+	ADAU1979,
+};
+
+int adau1977_probe(struct device *dev, struct regmap *regmap,
+	enum adau1977_type type, void (*switch_mode)(struct device *dev));
+
+extern const struct regmap_config adau1977_regmap_config;
+
+enum adau1977_clk_id {
+	ADAU1977_SYSCLK,
+};
+
+enum adau1977_sysclk_src {
+	ADAU1977_SYSCLK_SRC_MCLK,
+	ADAU1977_SYSCLK_SRC_LRCLK,
+};
+
+#endif
diff --git a/sound/soc/codecs/adau7002.c b/sound/soc/codecs/adau7002.c
new file mode 100644
index 0000000..fdff868
--- /dev/null
+++ b/sound/soc/codecs/adau7002.c
@@ -0,0 +1,94 @@
+/*
+ * ADAU7002 Stereo PDM-to-I2S/TDM converter driver
+ *
+ * Copyright 2014-2016 Analog Devices
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/acpi.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <sound/soc.h>
+
+static const struct snd_soc_dapm_widget adau7002_widgets[] = {
+	SND_SOC_DAPM_INPUT("PDM_DAT"),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("IOVDD", 0, 0),
+};
+
+static const struct snd_soc_dapm_route adau7002_routes[] = {
+	{ "Capture", NULL, "PDM_DAT" },
+	{ "Capture", NULL, "IOVDD" },
+};
+
+static struct snd_soc_dai_driver adau7002_dai = {
+	.name = "adau7002-hifi",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |
+			SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE,
+		.sig_bits = 20,
+	},
+};
+
+static const struct snd_soc_component_driver adau7002_component_driver = {
+	.dapm_widgets		= adau7002_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(adau7002_widgets),
+	.dapm_routes		= adau7002_routes,
+	.num_dapm_routes	= ARRAY_SIZE(adau7002_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int adau7002_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&adau7002_component_driver,
+			&adau7002_dai, 1);
+}
+
+static int adau7002_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id adau7002_dt_ids[] = {
+	{ .compatible = "adi,adau7002", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adau7002_dt_ids);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id adau7002_acpi_match[] = {
+	{ "ADAU7002", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, adau7002_acpi_match);
+#endif
+
+static struct platform_driver adau7002_driver = {
+	.driver = {
+		.name = "adau7002",
+		.of_match_table	= of_match_ptr(adau7002_dt_ids),
+		.acpi_match_table = ACPI_PTR(adau7002_acpi_match),
+	},
+	.probe = adau7002_probe,
+	.remove = adau7002_remove,
+};
+module_platform_driver(adau7002_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ADAU7002 Stereo PDM-to-I2S/TDM Converter driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/adav801.c b/sound/soc/codecs/adav801.c
new file mode 100644
index 0000000..d82f79d
--- /dev/null
+++ b/sound/soc/codecs/adav801.c
@@ -0,0 +1,45 @@
+/*
+ * ADAV801 audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "adav80x.h"
+
+static const struct spi_device_id adav80x_spi_id[] = {
+	{ "adav801", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, adav80x_spi_id);
+
+static int adav80x_spi_probe(struct spi_device *spi)
+{
+	struct regmap_config config;
+
+	config = adav80x_regmap_config;
+	config.read_flag_mask = 0x01;
+
+	return adav80x_bus_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
+}
+
+static struct spi_driver adav80x_spi_driver = {
+	.driver = {
+		.name	= "adav801",
+	},
+	.probe		= adav80x_spi_probe,
+	.id_table	= adav80x_spi_id,
+};
+module_spi_driver(adav80x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ADAV801 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_AUTHOR("Yi Li <yi.li@analog.com>>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c
new file mode 100644
index 0000000..deb14bc
--- /dev/null
+++ b/sound/soc/codecs/adav803.c
@@ -0,0 +1,42 @@
+/*
+ * ADAV803 audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "adav80x.h"
+
+static const struct i2c_device_id adav803_id[] = {
+	{ "adav803", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adav803_id);
+
+static int adav803_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	return adav80x_bus_probe(&client->dev,
+		devm_regmap_init_i2c(client, &adav80x_regmap_config));
+}
+
+static struct i2c_driver adav803_driver = {
+	.driver = {
+		.name = "adav803",
+	},
+	.probe = adav803_probe,
+	.id_table = adav803_id,
+};
+module_i2c_driver(adav803_driver);
+
+MODULE_DESCRIPTION("ASoC ADAV803 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_AUTHOR("Yi Li <yi.li@analog.com>>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
new file mode 100644
index 0000000..8b9ca7e
--- /dev/null
+++ b/sound/soc/codecs/adav80x.c
@@ -0,0 +1,883 @@
+/*
+ * ADAV80X Audio Codec driver supporting ADAV801, ADAV803
+ *
+ * Copyright 2011 Analog Devices Inc.
+ * Author: Yi Li <yi.li@analog.com>
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "adav80x.h"
+
+#define ADAV80X_PLAYBACK_CTRL	0x04
+#define ADAV80X_AUX_IN_CTRL	0x05
+#define ADAV80X_REC_CTRL	0x06
+#define ADAV80X_AUX_OUT_CTRL	0x07
+#define ADAV80X_DPATH_CTRL1	0x62
+#define ADAV80X_DPATH_CTRL2	0x63
+#define ADAV80X_DAC_CTRL1	0x64
+#define ADAV80X_DAC_CTRL2	0x65
+#define ADAV80X_DAC_CTRL3	0x66
+#define ADAV80X_DAC_L_VOL	0x68
+#define ADAV80X_DAC_R_VOL	0x69
+#define ADAV80X_PGA_L_VOL	0x6c
+#define ADAV80X_PGA_R_VOL	0x6d
+#define ADAV80X_ADC_CTRL1	0x6e
+#define ADAV80X_ADC_CTRL2	0x6f
+#define ADAV80X_ADC_L_VOL	0x70
+#define ADAV80X_ADC_R_VOL	0x71
+#define ADAV80X_PLL_CTRL1	0x74
+#define ADAV80X_PLL_CTRL2	0x75
+#define ADAV80X_ICLK_CTRL1	0x76
+#define ADAV80X_ICLK_CTRL2	0x77
+#define ADAV80X_PLL_CLK_SRC	0x78
+#define ADAV80X_PLL_OUTE	0x7a
+
+#define ADAV80X_PLL_CLK_SRC_PLL_XIN(pll)	0x00
+#define ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll)	(0x40 << (pll))
+#define ADAV80X_PLL_CLK_SRC_PLL_MASK(pll)	(0x40 << (pll))
+
+#define ADAV80X_ICLK_CTRL1_DAC_SRC(src)		((src) << 5)
+#define ADAV80X_ICLK_CTRL1_ADC_SRC(src)		((src) << 2)
+#define ADAV80X_ICLK_CTRL1_ICLK2_SRC(src)	(src)
+#define ADAV80X_ICLK_CTRL2_ICLK1_SRC(src)	((src) << 3)
+
+#define ADAV80X_PLL_CTRL1_PLLDIV		0x10
+#define ADAV80X_PLL_CTRL1_PLLPD(pll)		(0x04 << (pll))
+#define ADAV80X_PLL_CTRL1_XTLPD			0x02
+
+#define ADAV80X_PLL_CTRL2_FIELD(pll, x)		((x) << ((pll) * 4))
+
+#define ADAV80X_PLL_CTRL2_FS_48(pll)	ADAV80X_PLL_CTRL2_FIELD((pll), 0x00)
+#define ADAV80X_PLL_CTRL2_FS_32(pll)	ADAV80X_PLL_CTRL2_FIELD((pll), 0x08)
+#define ADAV80X_PLL_CTRL2_FS_44(pll)	ADAV80X_PLL_CTRL2_FIELD((pll), 0x0c)
+
+#define ADAV80X_PLL_CTRL2_SEL(pll)	ADAV80X_PLL_CTRL2_FIELD((pll), 0x02)
+#define ADAV80X_PLL_CTRL2_DOUB(pll)	ADAV80X_PLL_CTRL2_FIELD((pll), 0x01)
+#define ADAV80X_PLL_CTRL2_PLL_MASK(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x0f)
+
+#define ADAV80X_ADC_CTRL1_MODULATOR_MASK	0x80
+#define ADAV80X_ADC_CTRL1_MODULATOR_128FS	0x00
+#define ADAV80X_ADC_CTRL1_MODULATOR_64FS	0x80
+
+#define ADAV80X_DAC_CTRL1_PD			0x80
+
+#define ADAV80X_DAC_CTRL2_DIV1			0x00
+#define ADAV80X_DAC_CTRL2_DIV1_5		0x10
+#define ADAV80X_DAC_CTRL2_DIV2			0x20
+#define ADAV80X_DAC_CTRL2_DIV3			0x30
+#define ADAV80X_DAC_CTRL2_DIV_MASK		0x30
+
+#define ADAV80X_DAC_CTRL2_INTERPOL_256FS	0x00
+#define ADAV80X_DAC_CTRL2_INTERPOL_128FS	0x40
+#define ADAV80X_DAC_CTRL2_INTERPOL_64FS		0x80
+#define ADAV80X_DAC_CTRL2_INTERPOL_MASK		0xc0
+
+#define ADAV80X_DAC_CTRL2_DEEMPH_NONE		0x00
+#define ADAV80X_DAC_CTRL2_DEEMPH_44		0x01
+#define ADAV80X_DAC_CTRL2_DEEMPH_32		0x02
+#define ADAV80X_DAC_CTRL2_DEEMPH_48		0x03
+#define ADAV80X_DAC_CTRL2_DEEMPH_MASK		0x01
+
+#define ADAV80X_CAPTURE_MODE_MASTER		0x20
+#define ADAV80X_CAPTURE_WORD_LEN24		0x00
+#define ADAV80X_CAPTURE_WORD_LEN20		0x04
+#define ADAV80X_CAPTRUE_WORD_LEN18		0x08
+#define ADAV80X_CAPTURE_WORD_LEN16		0x0c
+#define ADAV80X_CAPTURE_WORD_LEN_MASK		0x0c
+
+#define ADAV80X_CAPTURE_MODE_LEFT_J		0x00
+#define ADAV80X_CAPTURE_MODE_I2S		0x01
+#define ADAV80X_CAPTURE_MODE_RIGHT_J		0x03
+#define ADAV80X_CAPTURE_MODE_MASK		0x03
+
+#define ADAV80X_PLAYBACK_MODE_MASTER		0x10
+#define ADAV80X_PLAYBACK_MODE_LEFT_J		0x00
+#define ADAV80X_PLAYBACK_MODE_I2S		0x01
+#define ADAV80X_PLAYBACK_MODE_RIGHT_J_24	0x04
+#define ADAV80X_PLAYBACK_MODE_RIGHT_J_20	0x05
+#define ADAV80X_PLAYBACK_MODE_RIGHT_J_18	0x06
+#define ADAV80X_PLAYBACK_MODE_RIGHT_J_16	0x07
+#define ADAV80X_PLAYBACK_MODE_MASK		0x07
+
+#define ADAV80X_PLL_OUTE_SYSCLKPD(x)		BIT(2 - (x))
+
+static const struct reg_default adav80x_reg_defaults[] = {
+	{ ADAV80X_PLAYBACK_CTRL,	0x01 },
+	{ ADAV80X_AUX_IN_CTRL,		0x01 },
+	{ ADAV80X_REC_CTRL,		0x02 },
+	{ ADAV80X_AUX_OUT_CTRL,		0x01 },
+	{ ADAV80X_DPATH_CTRL1,		0xc0 },
+	{ ADAV80X_DPATH_CTRL2,		0x11 },
+	{ ADAV80X_DAC_CTRL1,		0x00 },
+	{ ADAV80X_DAC_CTRL2,		0x00 },
+	{ ADAV80X_DAC_CTRL3,		0x00 },
+	{ ADAV80X_DAC_L_VOL,		0xff },
+	{ ADAV80X_DAC_R_VOL,		0xff },
+	{ ADAV80X_PGA_L_VOL,		0x00 },
+	{ ADAV80X_PGA_R_VOL,		0x00 },
+	{ ADAV80X_ADC_CTRL1,		0x00 },
+	{ ADAV80X_ADC_CTRL2,		0x00 },
+	{ ADAV80X_ADC_L_VOL,		0xff },
+	{ ADAV80X_ADC_R_VOL,		0xff },
+	{ ADAV80X_PLL_CTRL1,		0x00 },
+	{ ADAV80X_PLL_CTRL2,		0x00 },
+	{ ADAV80X_ICLK_CTRL1,		0x00 },
+	{ ADAV80X_ICLK_CTRL2,		0x00 },
+	{ ADAV80X_PLL_CLK_SRC,		0x00 },
+	{ ADAV80X_PLL_OUTE,		0x00 },
+};
+
+struct adav80x {
+	struct regmap *regmap;
+
+	enum adav80x_clk_src clk_src;
+	unsigned int sysclk;
+	enum adav80x_pll_src pll_src;
+
+	unsigned int dai_fmt[2];
+	unsigned int rate;
+	bool deemph;
+	bool sysclk_pd[3];
+};
+
+static const char *adav80x_mux_text[] = {
+	"ADC",
+	"Playback",
+	"Aux Playback",
+};
+
+static const unsigned int adav80x_mux_values[] = {
+	0, 2, 3,
+};
+
+#define ADAV80X_MUX_ENUM_DECL(name, reg, shift) \
+	SOC_VALUE_ENUM_DOUBLE_DECL(name, reg, shift, 7, \
+		ARRAY_SIZE(adav80x_mux_text), adav80x_mux_text, \
+		adav80x_mux_values)
+
+static ADAV80X_MUX_ENUM_DECL(adav80x_aux_capture_enum, ADAV80X_DPATH_CTRL1, 0);
+static ADAV80X_MUX_ENUM_DECL(adav80x_capture_enum, ADAV80X_DPATH_CTRL1, 3);
+static ADAV80X_MUX_ENUM_DECL(adav80x_dac_enum, ADAV80X_DPATH_CTRL2, 3);
+
+static const struct snd_kcontrol_new adav80x_aux_capture_mux_ctrl =
+	SOC_DAPM_ENUM("Route", adav80x_aux_capture_enum);
+static const struct snd_kcontrol_new adav80x_capture_mux_ctrl =
+	SOC_DAPM_ENUM("Route", adav80x_capture_enum);
+static const struct snd_kcontrol_new adav80x_dac_mux_ctrl =
+	SOC_DAPM_ENUM("Route", adav80x_dac_enum);
+
+#define ADAV80X_MUX(name, ctrl) \
+	SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+
+static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", NULL, ADAV80X_DAC_CTRL1, 7, 1),
+	SND_SOC_DAPM_ADC("ADC", NULL, ADAV80X_ADC_CTRL1, 5, 1),
+
+	SND_SOC_DAPM_PGA("Right PGA", ADAV80X_ADC_CTRL1, 0, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Left PGA", ADAV80X_ADC_CTRL1, 1, 1, NULL, 0),
+
+	SND_SOC_DAPM_AIF_OUT("AIFOUT", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIFIN", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_OUT("AIFAUXOUT", "Aux Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIFAUXIN", "Aux Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	ADAV80X_MUX("Aux Capture Select", &adav80x_aux_capture_mux_ctrl),
+	ADAV80X_MUX("Capture Select", &adav80x_capture_mux_ctrl),
+	ADAV80X_MUX("DAC Select", &adav80x_dac_mux_ctrl),
+
+	SND_SOC_DAPM_INPUT("VINR"),
+	SND_SOC_DAPM_INPUT("VINL"),
+	SND_SOC_DAPM_OUTPUT("VOUTR"),
+	SND_SOC_DAPM_OUTPUT("VOUTL"),
+
+	SND_SOC_DAPM_SUPPLY("SYSCLK", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL1", ADAV80X_PLL_CTRL1, 2, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL2", ADAV80X_PLL_CTRL1, 3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("OSC", ADAV80X_PLL_CTRL1, 1, 1, NULL, 0),
+};
+
+static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+	const char *clk;
+
+	switch (adav80x->clk_src) {
+	case ADAV80X_CLK_PLL1:
+		clk = "PLL1";
+		break;
+	case ADAV80X_CLK_PLL2:
+		clk = "PLL2";
+		break;
+	case ADAV80X_CLK_XTAL:
+		clk = "OSC";
+		break;
+	default:
+		return 0;
+	}
+
+	return strcmp(source->name, clk) == 0;
+}
+
+static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+
+	return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL;
+}
+
+
+static const struct snd_soc_dapm_route adav80x_dapm_routes[] = {
+	{ "DAC Select", "ADC", "ADC" },
+	{ "DAC Select", "Playback", "AIFIN" },
+	{ "DAC Select", "Aux Playback", "AIFAUXIN" },
+	{ "DAC", NULL,  "DAC Select" },
+
+	{ "Capture Select", "ADC", "ADC" },
+	{ "Capture Select", "Playback", "AIFIN" },
+	{ "Capture Select", "Aux Playback", "AIFAUXIN" },
+	{ "AIFOUT", NULL,  "Capture Select" },
+
+	{ "Aux Capture Select", "ADC", "ADC" },
+	{ "Aux Capture Select", "Playback", "AIFIN" },
+	{ "Aux Capture Select", "Aux Playback", "AIFAUXIN" },
+	{ "AIFAUXOUT", NULL,  "Aux Capture Select" },
+
+	{ "VOUTR",  NULL, "DAC" },
+	{ "VOUTL",  NULL, "DAC" },
+
+	{ "Left PGA", NULL, "VINL" },
+	{ "Right PGA", NULL, "VINR" },
+	{ "ADC", NULL, "Left PGA" },
+	{ "ADC", NULL, "Right PGA" },
+
+	{ "SYSCLK", NULL, "PLL1", adav80x_dapm_sysclk_check },
+	{ "SYSCLK", NULL, "PLL2", adav80x_dapm_sysclk_check },
+	{ "SYSCLK", NULL, "OSC", adav80x_dapm_sysclk_check },
+	{ "PLL1", NULL, "OSC", adav80x_dapm_pll_check },
+	{ "PLL2", NULL, "OSC", adav80x_dapm_pll_check },
+
+	{ "ADC", NULL, "SYSCLK" },
+	{ "DAC", NULL, "SYSCLK" },
+	{ "AIFOUT", NULL, "SYSCLK" },
+	{ "AIFAUXOUT", NULL, "SYSCLK" },
+	{ "AIFIN", NULL, "SYSCLK" },
+	{ "AIFAUXIN", NULL, "SYSCLK" },
+};
+
+static int adav80x_set_deemph(struct snd_soc_component *component)
+{
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	if (adav80x->deemph) {
+		switch (adav80x->rate) {
+		case 32000:
+			val = ADAV80X_DAC_CTRL2_DEEMPH_32;
+			break;
+		case 44100:
+			val = ADAV80X_DAC_CTRL2_DEEMPH_44;
+			break;
+		case 48000:
+		case 64000:
+		case 88200:
+		case 96000:
+			val = ADAV80X_DAC_CTRL2_DEEMPH_48;
+			break;
+		default:
+			val = ADAV80X_DAC_CTRL2_DEEMPH_NONE;
+			break;
+		}
+	} else {
+		val = ADAV80X_DAC_CTRL2_DEEMPH_NONE;
+	}
+
+	return regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2,
+		ADAV80X_DAC_CTRL2_DEEMPH_MASK, val);
+}
+
+static int adav80x_put_deemph(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+	unsigned int deemph = ucontrol->value.integer.value[0];
+
+	if (deemph > 1)
+		return -EINVAL;
+
+	adav80x->deemph = deemph;
+
+	return adav80x_set_deemph(component);
+}
+
+static int adav80x_get_deemph(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = adav80x->deemph;
+	return 0;
+};
+
+static const DECLARE_TLV_DB_SCALE(adav80x_inpga_tlv, 0, 50, 0);
+static const DECLARE_TLV_DB_MINMAX(adav80x_digital_tlv, -9563, 0);
+
+static const struct snd_kcontrol_new adav80x_controls[] = {
+	SOC_DOUBLE_R_TLV("Master Playback Volume", ADAV80X_DAC_L_VOL,
+		ADAV80X_DAC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv),
+	SOC_DOUBLE_R_TLV("Master Capture Volume", ADAV80X_ADC_L_VOL,
+			ADAV80X_ADC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv),
+
+	SOC_DOUBLE_R_TLV("PGA Capture Volume", ADAV80X_PGA_L_VOL,
+			ADAV80X_PGA_R_VOL, 0, 0x30, 0, adav80x_inpga_tlv),
+
+	SOC_DOUBLE("Master Playback Switch", ADAV80X_DAC_CTRL1, 0, 1, 1, 0),
+	SOC_DOUBLE("Master Capture Switch", ADAV80X_ADC_CTRL1, 2, 3, 1, 1),
+
+	SOC_SINGLE("ADC High Pass Filter Switch", ADAV80X_ADC_CTRL1, 6, 1, 0),
+
+	SOC_SINGLE_BOOL_EXT("Playback De-emphasis Switch", 0,
+			adav80x_get_deemph, adav80x_put_deemph),
+};
+
+static unsigned int adav80x_port_ctrl_regs[2][2] = {
+	{ ADAV80X_REC_CTRL, ADAV80X_PLAYBACK_CTRL, },
+	{ ADAV80X_AUX_OUT_CTRL, ADAV80X_AUX_IN_CTRL },
+};
+
+static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+	unsigned int capture = 0x00;
+	unsigned int playback = 0x00;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		capture |= ADAV80X_CAPTURE_MODE_MASTER;
+		playback |= ADAV80X_PLAYBACK_MODE_MASTER;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		capture |= ADAV80X_CAPTURE_MODE_I2S;
+		playback |= ADAV80X_PLAYBACK_MODE_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		capture |= ADAV80X_CAPTURE_MODE_LEFT_J;
+		playback |= ADAV80X_PLAYBACK_MODE_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		capture |= ADAV80X_CAPTURE_MODE_RIGHT_J;
+		playback |= ADAV80X_PLAYBACK_MODE_RIGHT_J_24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0],
+		ADAV80X_CAPTURE_MODE_MASK | ADAV80X_CAPTURE_MODE_MASTER,
+		capture);
+	regmap_write(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1],
+		playback);
+
+	adav80x->dai_fmt[dai->id] = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+	return 0;
+}
+
+static int adav80x_set_adc_clock(struct snd_soc_component *component,
+		unsigned int sample_rate)
+{
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	if (sample_rate <= 48000)
+		val = ADAV80X_ADC_CTRL1_MODULATOR_128FS;
+	else
+		val = ADAV80X_ADC_CTRL1_MODULATOR_64FS;
+
+	regmap_update_bits(adav80x->regmap, ADAV80X_ADC_CTRL1,
+		ADAV80X_ADC_CTRL1_MODULATOR_MASK, val);
+
+	return 0;
+}
+
+static int adav80x_set_dac_clock(struct snd_soc_component *component,
+		unsigned int sample_rate)
+{
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	if (sample_rate <= 48000)
+		val = ADAV80X_DAC_CTRL2_DIV1 | ADAV80X_DAC_CTRL2_INTERPOL_256FS;
+	else
+		val = ADAV80X_DAC_CTRL2_DIV2 | ADAV80X_DAC_CTRL2_INTERPOL_128FS;
+
+	regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2,
+		ADAV80X_DAC_CTRL2_DIV_MASK | ADAV80X_DAC_CTRL2_INTERPOL_MASK,
+		val);
+
+	return 0;
+}
+
+static int adav80x_set_capture_pcm_format(struct snd_soc_component *component,
+		struct snd_soc_dai *dai, struct snd_pcm_hw_params *params)
+{
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	switch (params_width(params)) {
+	case 16:
+		val = ADAV80X_CAPTURE_WORD_LEN16;
+		break;
+	case 18:
+		val = ADAV80X_CAPTRUE_WORD_LEN18;
+		break;
+	case 20:
+		val = ADAV80X_CAPTURE_WORD_LEN20;
+		break;
+	case 24:
+		val = ADAV80X_CAPTURE_WORD_LEN24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0],
+		ADAV80X_CAPTURE_WORD_LEN_MASK, val);
+
+	return 0;
+}
+
+static int adav80x_set_playback_pcm_format(struct snd_soc_component *component,
+		struct snd_soc_dai *dai, struct snd_pcm_hw_params *params)
+{
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	if (adav80x->dai_fmt[dai->id] != SND_SOC_DAIFMT_RIGHT_J)
+		return 0;
+
+	switch (params_width(params)) {
+	case 16:
+		val = ADAV80X_PLAYBACK_MODE_RIGHT_J_16;
+		break;
+	case 18:
+		val = ADAV80X_PLAYBACK_MODE_RIGHT_J_18;
+		break;
+	case 20:
+		val = ADAV80X_PLAYBACK_MODE_RIGHT_J_20;
+		break;
+	case 24:
+		val = ADAV80X_PLAYBACK_MODE_RIGHT_J_24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1],
+		ADAV80X_PLAYBACK_MODE_MASK, val);
+
+	return 0;
+}
+
+static int adav80x_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+	unsigned int rate = params_rate(params);
+
+	if (rate * 256 != adav80x->sysclk)
+		return -EINVAL;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		adav80x_set_playback_pcm_format(component, dai, params);
+		adav80x_set_dac_clock(component, rate);
+	} else {
+		adav80x_set_capture_pcm_format(component, dai, params);
+		adav80x_set_adc_clock(component, rate);
+	}
+	adav80x->rate = rate;
+	adav80x_set_deemph(component);
+
+	return 0;
+}
+
+static int adav80x_set_sysclk(struct snd_soc_component *component,
+			      int clk_id, int source,
+			      unsigned int freq, int dir)
+{
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	if (dir == SND_SOC_CLOCK_IN) {
+		switch (clk_id) {
+		case ADAV80X_CLK_XIN:
+		case ADAV80X_CLK_XTAL:
+		case ADAV80X_CLK_MCLKI:
+		case ADAV80X_CLK_PLL1:
+		case ADAV80X_CLK_PLL2:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		adav80x->sysclk = freq;
+
+		if (adav80x->clk_src != clk_id) {
+			unsigned int iclk_ctrl1, iclk_ctrl2;
+
+			adav80x->clk_src = clk_id;
+			if (clk_id == ADAV80X_CLK_XTAL)
+				clk_id = ADAV80X_CLK_XIN;
+
+			iclk_ctrl1 = ADAV80X_ICLK_CTRL1_DAC_SRC(clk_id) |
+					ADAV80X_ICLK_CTRL1_ADC_SRC(clk_id) |
+					ADAV80X_ICLK_CTRL1_ICLK2_SRC(clk_id);
+			iclk_ctrl2 = ADAV80X_ICLK_CTRL2_ICLK1_SRC(clk_id);
+
+			regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL1,
+				iclk_ctrl1);
+			regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2,
+				iclk_ctrl2);
+
+			snd_soc_dapm_sync(dapm);
+		}
+	} else {
+		unsigned int mask;
+
+		switch (clk_id) {
+		case ADAV80X_CLK_SYSCLK1:
+		case ADAV80X_CLK_SYSCLK2:
+		case ADAV80X_CLK_SYSCLK3:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		clk_id -= ADAV80X_CLK_SYSCLK1;
+		mask = ADAV80X_PLL_OUTE_SYSCLKPD(clk_id);
+
+		if (freq == 0) {
+			regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE,
+				mask, mask);
+			adav80x->sysclk_pd[clk_id] = true;
+		} else {
+			regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE,
+				mask, 0);
+			adav80x->sysclk_pd[clk_id] = false;
+		}
+
+		snd_soc_dapm_mutex_lock(dapm);
+
+		if (adav80x->sysclk_pd[0])
+			snd_soc_dapm_disable_pin_unlocked(dapm, "PLL1");
+		else
+			snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL1");
+
+		if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2])
+			snd_soc_dapm_disable_pin_unlocked(dapm, "PLL2");
+		else
+			snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL2");
+
+		snd_soc_dapm_sync_unlocked(dapm);
+
+		snd_soc_dapm_mutex_unlock(dapm);
+	}
+
+	return 0;
+}
+
+static int adav80x_set_pll(struct snd_soc_component *component, int pll_id,
+		int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+	unsigned int pll_ctrl1 = 0;
+	unsigned int pll_ctrl2 = 0;
+	unsigned int pll_src;
+
+	switch (source) {
+	case ADAV80X_PLL_SRC_XTAL:
+	case ADAV80X_PLL_SRC_XIN:
+	case ADAV80X_PLL_SRC_MCLKI:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (!freq_out)
+		return 0;
+
+	switch (freq_in) {
+	case 27000000:
+		break;
+	case 54000000:
+		if (source == ADAV80X_PLL_SRC_XIN) {
+			pll_ctrl1 |= ADAV80X_PLL_CTRL1_PLLDIV;
+			break;
+		}
+		/* fall through */
+	default:
+		return -EINVAL;
+	}
+
+	if (freq_out > 12288000) {
+		pll_ctrl2 |= ADAV80X_PLL_CTRL2_DOUB(pll_id);
+		freq_out /= 2;
+	}
+
+	/* freq_out = sample_rate * 256 */
+	switch (freq_out) {
+	case 8192000:
+		pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_32(pll_id);
+		break;
+	case 11289600:
+		pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_44(pll_id);
+		break;
+	case 12288000:
+		pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_48(pll_id);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL1,
+			ADAV80X_PLL_CTRL1_PLLDIV, pll_ctrl1);
+	regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL2,
+			ADAV80X_PLL_CTRL2_PLL_MASK(pll_id), pll_ctrl2);
+
+	if (source != adav80x->pll_src) {
+		if (source == ADAV80X_PLL_SRC_MCLKI)
+			pll_src = ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll_id);
+		else
+			pll_src = ADAV80X_PLL_CLK_SRC_PLL_XIN(pll_id);
+
+		regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CLK_SRC,
+				ADAV80X_PLL_CLK_SRC_PLL_MASK(pll_id), pll_src);
+
+		adav80x->pll_src = source;
+
+		snd_soc_dapm_sync(dapm);
+	}
+
+	return 0;
+}
+
+static int adav80x_set_bias_level(struct snd_soc_component *component,
+		enum snd_soc_bias_level level)
+{
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+	unsigned int mask = ADAV80X_DAC_CTRL1_PD;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask,
+			0x00);
+		break;
+	case SND_SOC_BIAS_OFF:
+		regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask,
+			mask);
+		break;
+	}
+
+	return 0;
+}
+
+/* Enforce the same sample rate on all audio interfaces */
+static int adav80x_dai_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+
+	if (!snd_soc_component_is_active(component) || !adav80x->rate)
+		return 0;
+
+	return snd_pcm_hw_constraint_single(substream->runtime,
+			SNDRV_PCM_HW_PARAM_RATE, adav80x->rate);
+}
+
+static void adav80x_dai_shutdown(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+
+	if (!snd_soc_component_is_active(component))
+		adav80x->rate = 0;
+}
+
+static const struct snd_soc_dai_ops adav80x_dai_ops = {
+	.set_fmt = adav80x_set_dai_fmt,
+	.hw_params = adav80x_hw_params,
+	.startup = adav80x_dai_startup,
+	.shutdown = adav80x_dai_shutdown,
+};
+
+#define ADAV80X_PLAYBACK_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | \
+	SNDRV_PCM_RATE_96000)
+
+#define ADAV80X_CAPTURE_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+
+#define ADAV80X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
+	SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver adav80x_dais[] = {
+	{
+		.name = "adav80x-hifi",
+		.id = 0,
+		.playback = {
+			.stream_name = "HiFi Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = ADAV80X_PLAYBACK_RATES,
+			.formats = ADAV80X_FORMATS,
+	},
+		.capture = {
+			.stream_name = "HiFi Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = ADAV80X_CAPTURE_RATES,
+			.formats = ADAV80X_FORMATS,
+		},
+		.ops = &adav80x_dai_ops,
+	},
+	{
+		.name = "adav80x-aux",
+		.id = 1,
+		.playback = {
+			.stream_name = "Aux Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = ADAV80X_PLAYBACK_RATES,
+			.formats = ADAV80X_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Aux Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = ADAV80X_CAPTURE_RATES,
+			.formats = ADAV80X_FORMATS,
+		},
+		.ops = &adav80x_dai_ops,
+	},
+};
+
+static int adav80x_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+
+	/* Force PLLs on for SYSCLK output */
+	snd_soc_dapm_force_enable_pin(dapm, "PLL1");
+	snd_soc_dapm_force_enable_pin(dapm, "PLL2");
+
+	/* Power down S/PDIF receiver, since it is currently not supported */
+	regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20);
+	/* Disable DAC zero flag */
+	regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6);
+
+	return 0;
+}
+
+static int adav80x_resume(struct snd_soc_component *component)
+{
+	struct adav80x *adav80x = snd_soc_component_get_drvdata(component);
+
+	regcache_sync(adav80x->regmap);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver adav80x_component_driver = {
+	.probe			= adav80x_probe,
+	.resume			= adav80x_resume,
+	.set_bias_level		= adav80x_set_bias_level,
+	.set_pll		= adav80x_set_pll,
+	.set_sysclk		= adav80x_set_sysclk,
+	.controls		= adav80x_controls,
+	.num_controls		= ARRAY_SIZE(adav80x_controls),
+	.dapm_widgets		= adav80x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(adav80x_dapm_widgets),
+	.dapm_routes		= adav80x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(adav80x_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+int adav80x_bus_probe(struct device *dev, struct regmap *regmap)
+{
+	struct adav80x *adav80x;
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	adav80x = devm_kzalloc(dev, sizeof(*adav80x), GFP_KERNEL);
+	if (!adav80x)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, adav80x);
+	adav80x->regmap = regmap;
+
+	return devm_snd_soc_register_component(dev, &adav80x_component_driver,
+		adav80x_dais, ARRAY_SIZE(adav80x_dais));
+}
+EXPORT_SYMBOL_GPL(adav80x_bus_probe);
+
+const struct regmap_config adav80x_regmap_config = {
+	.val_bits = 8,
+	.pad_bits = 1,
+	.reg_bits = 7,
+
+	.max_register = ADAV80X_PLL_OUTE,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = adav80x_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults),
+};
+EXPORT_SYMBOL_GPL(adav80x_regmap_config);
+
+MODULE_DESCRIPTION("ASoC ADAV80x driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_AUTHOR("Yi Li <yi.li@analog.com>>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adav80x.h b/sound/soc/codecs/adav80x.h
new file mode 100644
index 0000000..8a1d7c0
--- /dev/null
+++ b/sound/soc/codecs/adav80x.h
@@ -0,0 +1,42 @@
+/*
+ * header file for ADAV80X parts
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ADAV80X_H
+#define _ADAV80X_H
+
+#include <linux/regmap.h>
+
+struct device;
+
+extern const struct regmap_config adav80x_regmap_config;
+int adav80x_bus_probe(struct device *dev, struct regmap *regmap);
+
+enum adav80x_pll_src {
+	ADAV80X_PLL_SRC_XIN,
+	ADAV80X_PLL_SRC_XTAL,
+	ADAV80X_PLL_SRC_MCLKI,
+};
+
+enum adav80x_pll {
+	ADAV80X_PLL1 = 0,
+	ADAV80X_PLL2 = 1,
+};
+
+enum adav80x_clk_src {
+	ADAV80X_CLK_XIN = 0,
+	ADAV80X_CLK_MCLKI = 1,
+	ADAV80X_CLK_PLL1 = 2,
+	ADAV80X_CLK_PLL2 = 3,
+	ADAV80X_CLK_XTAL = 6,
+
+	ADAV80X_CLK_SYSCLK1 = 6,
+	ADAV80X_CLK_SYSCLK2 = 7,
+	ADAV80X_CLK_SYSCLK3 = 8,
+};
+
+#endif
diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c
new file mode 100644
index 0000000..bcd45ff
--- /dev/null
+++ b/sound/soc/codecs/ads117x.c
@@ -0,0 +1,100 @@
+/*
+ * ads117x.c  --  Driver for ads1174/8 ADC chips
+ *
+ * Copyright 2009 ShotSpotter Inc.
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <linux/of.h>
+
+#define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
+#define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+static const struct snd_soc_dapm_widget ads117x_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("Input1"),
+SND_SOC_DAPM_INPUT("Input2"),
+SND_SOC_DAPM_INPUT("Input3"),
+SND_SOC_DAPM_INPUT("Input4"),
+SND_SOC_DAPM_INPUT("Input5"),
+SND_SOC_DAPM_INPUT("Input6"),
+SND_SOC_DAPM_INPUT("Input7"),
+SND_SOC_DAPM_INPUT("Input8"),
+};
+
+static const struct snd_soc_dapm_route ads117x_dapm_routes[] = {
+	{ "Capture", NULL, "Input1" },
+	{ "Capture", NULL, "Input2" },
+	{ "Capture", NULL, "Input3" },
+	{ "Capture", NULL, "Input4" },
+	{ "Capture", NULL, "Input5" },
+	{ "Capture", NULL, "Input6" },
+	{ "Capture", NULL, "Input7" },
+	{ "Capture", NULL, "Input8" },
+};
+
+static struct snd_soc_dai_driver ads117x_dai = {
+/* ADC */
+	.name = "ads117x-hifi",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 32,
+		.rates = ADS117X_RATES,
+		.formats = ADS117X_FORMATS,},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_ads117x = {
+	.dapm_widgets		= ads117x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ads117x_dapm_widgets),
+	.dapm_routes		= ads117x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ads117x_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int ads117x_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_ads117x, &ads117x_dai, 1);
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id ads117x_dt_ids[] = {
+	{ .compatible = "ti,ads1174" },
+	{ .compatible = "ti,ads1178" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ads117x_dt_ids);
+#endif
+
+static struct platform_driver ads117x_codec_driver = {
+	.driver = {
+			.name = "ads117x-codec",
+			.of_match_table = of_match_ptr(ads117x_dt_ids),
+	},
+
+	.probe = ads117x_probe,
+};
+
+module_platform_driver(ads117x_codec_driver);
+
+MODULE_DESCRIPTION("ASoC ads117x driver");
+MODULE_AUTHOR("Graeme Gregory");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
new file mode 100644
index 0000000..32bc545
--- /dev/null
+++ b/sound/soc/codecs/ak4104.c
@@ -0,0 +1,356 @@
+/*
+ * AK4104 ALSA SoC (ASoC) driver
+ *
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+/* AK4104 registers addresses */
+#define AK4104_REG_CONTROL1		0x00
+#define AK4104_REG_RESERVED		0x01
+#define AK4104_REG_CONTROL2		0x02
+#define AK4104_REG_TX			0x03
+#define AK4104_REG_CHN_STATUS(x)	((x) + 0x04)
+#define AK4104_NUM_REGS			10
+
+#define AK4104_REG_MASK			0x1f
+#define AK4104_READ			0xc0
+#define AK4104_WRITE			0xe0
+#define AK4104_RESERVED_VAL		0x5b
+
+/* Bit masks for AK4104 registers */
+#define AK4104_CONTROL1_RSTN		(1 << 0)
+#define AK4104_CONTROL1_PW		(1 << 1)
+#define AK4104_CONTROL1_DIF0		(1 << 2)
+#define AK4104_CONTROL1_DIF1		(1 << 3)
+
+#define AK4104_CONTROL2_SEL0		(1 << 0)
+#define AK4104_CONTROL2_SEL1		(1 << 1)
+#define AK4104_CONTROL2_MODE		(1 << 2)
+
+#define AK4104_TX_TXE			(1 << 0)
+#define AK4104_TX_V			(1 << 1)
+
+struct ak4104_private {
+	struct regmap *regmap;
+	struct regulator *regulator;
+};
+
+static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = {
+SND_SOC_DAPM_PGA("TXE", AK4104_REG_TX, AK4104_TX_TXE, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route ak4104_dapm_routes[] = {
+	{ "TXE", NULL, "Playback" },
+	{ "TX", NULL, "TXE" },
+};
+
+static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int format)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
+	int val = 0;
+	int ret;
+
+	/* set DAI format */
+	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val |= AK4104_CONTROL1_DIF0;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		val |= AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1;
+		break;
+	default:
+		dev_err(component->dev, "invalid dai format\n");
+		return -EINVAL;
+	}
+
+	/* This device can only be slave */
+	if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+		return -EINVAL;
+
+	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
+				 AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1,
+				 val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int ak4104_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
+	int ret, val = 0;
+
+	/* set the IEC958 bits: consumer mode, no copyright bit */
+	val |= IEC958_AES0_CON_NOT_COPYRIGHT;
+	regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(0), val);
+
+	val = 0;
+
+	switch (params_rate(params)) {
+	case 22050:
+		val |= IEC958_AES3_CON_FS_22050;
+		break;
+	case 24000:
+		val |= IEC958_AES3_CON_FS_24000;
+		break;
+	case 32000:
+		val |= IEC958_AES3_CON_FS_32000;
+		break;
+	case 44100:
+		val |= IEC958_AES3_CON_FS_44100;
+		break;
+	case 48000:
+		val |= IEC958_AES3_CON_FS_48000;
+		break;
+	case 88200:
+		val |= IEC958_AES3_CON_FS_88200;
+		break;
+	case 96000:
+		val |= IEC958_AES3_CON_FS_96000;
+		break;
+	case 176400:
+		val |= IEC958_AES3_CON_FS_176400;
+		break;
+	case 192000:
+		val |= IEC958_AES3_CON_FS_192000;
+		break;
+	default:
+		dev_err(component->dev, "unsupported sampling rate\n");
+		return -EINVAL;
+	}
+
+	ret = regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(3), val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops ak4101_dai_ops = {
+	.hw_params = ak4104_hw_params,
+	.set_fmt = ak4104_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver ak4104_dai = {
+	.name = "ak4104-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+			 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+			 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+			 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE  |
+			   SNDRV_PCM_FMTBIT_S24_3LE |
+			   SNDRV_PCM_FMTBIT_S24_LE
+	},
+	.ops = &ak4101_dai_ops,
+};
+
+static int ak4104_probe(struct snd_soc_component *component)
+{
+	struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = regulator_enable(ak4104->regulator);
+	if (ret < 0) {
+		dev_err(component->dev, "Unable to enable regulator: %d\n", ret);
+		return ret;
+	}
+
+	/* set power-up and non-reset bits */
+	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
+				 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
+				 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
+	if (ret < 0)
+		goto exit_disable_regulator;
+
+	/* enable transmitter */
+	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
+				 AK4104_TX_TXE, AK4104_TX_TXE);
+	if (ret < 0)
+		goto exit_disable_regulator;
+
+	return 0;
+
+exit_disable_regulator:
+	regulator_disable(ak4104->regulator);
+	return ret;
+}
+
+static void ak4104_remove(struct snd_soc_component *component)
+{
+	struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
+
+	regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
+			   AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
+	regulator_disable(ak4104->regulator);
+}
+
+#ifdef CONFIG_PM
+static int ak4104_soc_suspend(struct snd_soc_component *component)
+{
+	struct ak4104_private *priv = snd_soc_component_get_drvdata(component);
+
+	regulator_disable(priv->regulator);
+
+	return 0;
+}
+
+static int ak4104_soc_resume(struct snd_soc_component *component)
+{
+	struct ak4104_private *priv = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = regulator_enable(priv->regulator);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+#else
+#define ak4104_soc_suspend	NULL
+#define ak4104_soc_resume	NULL
+#endif /* CONFIG_PM */
+
+static const struct snd_soc_component_driver soc_component_device_ak4104 = {
+	.probe			= ak4104_probe,
+	.remove			= ak4104_remove,
+	.suspend		= ak4104_soc_suspend,
+	.resume			= ak4104_soc_resume,
+	.dapm_widgets		= ak4104_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4104_dapm_widgets),
+	.dapm_routes		= ak4104_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ak4104_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config ak4104_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = AK4104_NUM_REGS - 1,
+	.read_flag_mask = AK4104_READ,
+	.write_flag_mask = AK4104_WRITE,
+
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int ak4104_spi_probe(struct spi_device *spi)
+{
+	struct device_node *np = spi->dev.of_node;
+	struct ak4104_private *ak4104;
+	unsigned int val;
+	int ret;
+
+	spi->bits_per_word = 8;
+	spi->mode = SPI_MODE_0;
+	ret = spi_setup(spi);
+	if (ret < 0)
+		return ret;
+
+	ak4104 = devm_kzalloc(&spi->dev, sizeof(struct ak4104_private),
+			      GFP_KERNEL);
+	if (ak4104 == NULL)
+		return -ENOMEM;
+
+	ak4104->regulator = devm_regulator_get(&spi->dev, "vdd");
+	if (IS_ERR(ak4104->regulator)) {
+		ret = PTR_ERR(ak4104->regulator);
+		dev_err(&spi->dev, "Unable to get Vdd regulator: %d\n", ret);
+		return ret;
+	}
+
+	ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap);
+	if (IS_ERR(ak4104->regmap)) {
+		ret = PTR_ERR(ak4104->regmap);
+		return ret;
+	}
+
+	if (np) {
+		enum of_gpio_flags flags;
+		int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
+
+		if (gpio_is_valid(gpio)) {
+			ret = devm_gpio_request_one(&spi->dev, gpio,
+				     flags & OF_GPIO_ACTIVE_LOW ?
+					GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
+				     "ak4104 reset");
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	/* read the 'reserved' register - according to the datasheet, it
+	 * should contain 0x5b. Not a good way to verify the presence of
+	 * the device, but there is no hardware ID register. */
+	ret = regmap_read(ak4104->regmap, AK4104_REG_RESERVED, &val);
+	if (ret != 0)
+		return ret;
+	if (val != AK4104_RESERVED_VAL)
+		return -ENODEV;
+
+	spi_set_drvdata(spi, ak4104);
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_device_ak4104, &ak4104_dai, 1);
+	return ret;
+}
+
+static const struct of_device_id ak4104_of_match[] = {
+	{ .compatible = "asahi-kasei,ak4104", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ak4104_of_match);
+
+static const struct spi_device_id ak4104_id_table[] = {
+	{ "ak4104", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, ak4104_id_table);
+
+static struct spi_driver ak4104_spi_driver = {
+	.driver  = {
+		.name   = "ak4104",
+		.of_match_table = ak4104_of_match,
+	},
+	.id_table = ak4104_id_table,
+	.probe  = ak4104_spi_probe,
+};
+
+module_spi_driver(ak4104_spi_driver);
+
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_DESCRIPTION("Asahi Kasei AK4104 ALSA SoC driver");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
new file mode 100644
index 0000000..299ada4
--- /dev/null
+++ b/sound/soc/codecs/ak4458.c
@@ -0,0 +1,657 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Audio driver for AK4458 DAC
+//
+// Copyright (C) 2016 Asahi Kasei Microdevices Corporation
+// Copyright 2018 NXP
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "ak4458.h"
+
+/* AK4458 Codec Private Data */
+struct ak4458_priv {
+	struct device *dev;
+	struct regmap *regmap;
+	struct gpio_desc *reset_gpiod;
+	struct gpio_desc *mute_gpiod;
+	int digfil;	/* SSLOW, SD, SLOW bits */
+	int fs;		/* sampling rate */
+	int fmt;
+	int slots;
+	int slot_width;
+};
+
+static const struct reg_default ak4458_reg_defaults[] = {
+	{ 0x00, 0x0C },	/*	0x00	AK4458_00_CONTROL1	*/
+	{ 0x01, 0x22 },	/*	0x01	AK4458_01_CONTROL2	*/
+	{ 0x02, 0x00 },	/*	0x02	AK4458_02_CONTROL3	*/
+	{ 0x03, 0xFF },	/*	0x03	AK4458_03_LCHATT	*/
+	{ 0x04, 0xFF },	/*	0x04	AK4458_04_RCHATT	*/
+	{ 0x05, 0x00 },	/*	0x05	AK4458_05_CONTROL4	*/
+	{ 0x06, 0x00 },	/*	0x06	AK4458_06_DSD1		*/
+	{ 0x07, 0x03 },	/*	0x07	AK4458_07_CONTROL5	*/
+	{ 0x08, 0x00 },	/*	0x08	AK4458_08_SOUND_CONTROL	*/
+	{ 0x09, 0x00 },	/*	0x09	AK4458_09_DSD2		*/
+	{ 0x0A, 0x0D },	/*	0x0A	AK4458_0A_CONTROL6	*/
+	{ 0x0B, 0x0C },	/*	0x0B	AK4458_0B_CONTROL7	*/
+	{ 0x0C, 0x00 },	/*	0x0C	AK4458_0C_CONTROL8	*/
+	{ 0x0D, 0x00 },	/*	0x0D	AK4458_0D_CONTROL9	*/
+	{ 0x0E, 0x50 },	/*	0x0E	AK4458_0E_CONTROL10	*/
+	{ 0x0F, 0xFF },	/*	0x0F	AK4458_0F_L2CHATT	*/
+	{ 0x10, 0xFF },	/*	0x10	AK4458_10_R2CHATT	*/
+	{ 0x11, 0xFF },	/*	0x11	AK4458_11_L3CHATT	*/
+	{ 0x12, 0xFF },	/*	0x12	AK4458_12_R3CHATT	*/
+	{ 0x13, 0xFF },	/*	0x13	AK4458_13_L4CHATT	*/
+	{ 0x14, 0xFF },	/*	0x14	AK4458_14_R4CHATT	*/
+};
+
+/*
+ * Volume control:
+ * from -127 to 0 dB in 0.5 dB steps (mute instead of -127.5 dB)
+ */
+static DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+
+/*
+ * DEM1 bit DEM0 bit Mode
+ * 0 0 44.1kHz
+ * 0 1 OFF (default)
+ * 1 0 48kHz
+ * 1 1 32kHz
+ */
+static const char * const ak4458_dem_select_texts[] = {
+	"44.1kHz", "OFF", "48kHz", "32kHz"
+};
+
+/*
+ * SSLOW, SD, SLOW bits Digital Filter Setting
+ * 0, 0, 0 : Sharp Roll-Off Filter
+ * 0, 0, 1 : Slow Roll-Off Filter
+ * 0, 1, 0 : Short delay Sharp Roll-Off Filter
+ * 0, 1, 1 : Short delay Slow Roll-Off Filter
+ * 1, *, * : Super Slow Roll-Off Filter
+ */
+static const char * const ak4458_digfil_select_texts[] = {
+	"Sharp Roll-Off Filter",
+	"Slow Roll-Off Filter",
+	"Short delay Sharp Roll-Off Filter",
+	"Short delay Slow Roll-Off Filter",
+	"Super Slow Roll-Off Filter"
+};
+
+/*
+ * DZFB: Inverting Enable of DZF
+ * 0: DZF goes H at Zero Detection
+ * 1: DZF goes L at Zero Detection
+ */
+static const char * const ak4458_dzfb_select_texts[] = {"H", "L"};
+
+/*
+ * SC1-0 bits: Sound Mode Setting
+ * 0 0 : Sound Mode 0
+ * 0 1 : Sound Mode 1
+ * 1 0 : Sound Mode 2
+ * 1 1 : Reserved
+ */
+static const char * const ak4458_sc_select_texts[] = {
+	"Sound Mode 0", "Sound Mode 1", "Sound Mode 2"
+};
+
+/* FIR2-0 bits: FIR Filter Mode Setting */
+static const char * const ak4458_fir_select_texts[] = {
+	"Mode 0", "Mode 1", "Mode 2", "Mode 3",
+	"Mode 4", "Mode 5", "Mode 6", "Mode 7",
+};
+
+/* ATS1-0 bits Attenuation Speed */
+static const char * const ak4458_ats_select_texts[] = {
+	"4080/fs", "2040/fs", "510/fs", "255/fs",
+};
+
+/* DIF2 bit Audio Interface Format Setting(BICK fs) */
+static const char * const ak4458_dif_select_texts[] = {"32fs,48fs", "64fs",};
+
+static const struct soc_enum ak4458_dac1_dem_enum =
+	SOC_ENUM_SINGLE(AK4458_01_CONTROL2, 1,
+			ARRAY_SIZE(ak4458_dem_select_texts),
+			ak4458_dem_select_texts);
+static const struct soc_enum ak4458_dac2_dem_enum =
+	SOC_ENUM_SINGLE(AK4458_0A_CONTROL6, 0,
+			ARRAY_SIZE(ak4458_dem_select_texts),
+			ak4458_dem_select_texts);
+static const struct soc_enum ak4458_dac3_dem_enum =
+	SOC_ENUM_SINGLE(AK4458_0E_CONTROL10, 4,
+			ARRAY_SIZE(ak4458_dem_select_texts),
+			ak4458_dem_select_texts);
+static const struct soc_enum ak4458_dac4_dem_enum =
+	SOC_ENUM_SINGLE(AK4458_0E_CONTROL10, 6,
+			ARRAY_SIZE(ak4458_dem_select_texts),
+			ak4458_dem_select_texts);
+static const struct soc_enum ak4458_digfil_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak4458_digfil_select_texts),
+			    ak4458_digfil_select_texts);
+static const struct soc_enum ak4458_dzfb_enum =
+	SOC_ENUM_SINGLE(AK4458_02_CONTROL3, 2,
+			ARRAY_SIZE(ak4458_dzfb_select_texts),
+			ak4458_dzfb_select_texts);
+static const struct soc_enum ak4458_sm_enum =
+	SOC_ENUM_SINGLE(AK4458_08_SOUND_CONTROL, 0,
+			ARRAY_SIZE(ak4458_sc_select_texts),
+			ak4458_sc_select_texts);
+static const struct soc_enum ak4458_fir_enum =
+	SOC_ENUM_SINGLE(AK4458_0C_CONTROL8, 0,
+			ARRAY_SIZE(ak4458_fir_select_texts),
+			ak4458_fir_select_texts);
+static const struct soc_enum ak4458_ats_enum =
+	SOC_ENUM_SINGLE(AK4458_0B_CONTROL7, 6,
+			ARRAY_SIZE(ak4458_ats_select_texts),
+			ak4458_ats_select_texts);
+static const struct soc_enum ak4458_dif_enum =
+	SOC_ENUM_SINGLE(AK4458_00_CONTROL1, 3,
+			ARRAY_SIZE(ak4458_dif_select_texts),
+			ak4458_dif_select_texts);
+
+static int get_digfil(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.enumerated.item[0] = ak4458->digfil;
+
+	return 0;
+}
+
+static int set_digfil(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+	int num;
+
+	num = ucontrol->value.enumerated.item[0];
+	if (num > 4)
+		return -EINVAL;
+
+	ak4458->digfil = num;
+
+	/* write SD bit */
+	snd_soc_component_update_bits(component, AK4458_01_CONTROL2,
+			    AK4458_SD_MASK,
+			    ((ak4458->digfil & 0x02) << 4));
+
+	/* write SLOW bit */
+	snd_soc_component_update_bits(component, AK4458_02_CONTROL3,
+			    AK4458_SLOW_MASK,
+			    (ak4458->digfil & 0x01));
+
+	/* write SSLOW bit */
+	snd_soc_component_update_bits(component, AK4458_05_CONTROL4,
+			    AK4458_SSLOW_MASK,
+			    ((ak4458->digfil & 0x04) >> 2));
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new ak4458_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("DAC1 Playback Volume", AK4458_03_LCHATT,
+			 AK4458_04_RCHATT, 0, 0xFF, 0, dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC2 Playback Volume", AK4458_0F_L2CHATT,
+			 AK4458_10_R2CHATT, 0, 0xFF, 0, dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC3 Playback Volume", AK4458_11_L3CHATT,
+			 AK4458_12_R3CHATT, 0, 0xFF, 0, dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC4 Playback Volume", AK4458_13_L4CHATT,
+			 AK4458_14_R4CHATT, 0, 0xFF, 0, dac_tlv),
+	SOC_ENUM("AK4458 De-emphasis Response DAC1", ak4458_dac1_dem_enum),
+	SOC_ENUM("AK4458 De-emphasis Response DAC2", ak4458_dac2_dem_enum),
+	SOC_ENUM("AK4458 De-emphasis Response DAC3", ak4458_dac3_dem_enum),
+	SOC_ENUM("AK4458 De-emphasis Response DAC4", ak4458_dac4_dem_enum),
+	SOC_ENUM_EXT("AK4458 Digital Filter Setting", ak4458_digfil_enum,
+		     get_digfil, set_digfil),
+	SOC_ENUM("AK4458 Inverting Enable of DZFB", ak4458_dzfb_enum),
+	SOC_ENUM("AK4458 Sound Mode", ak4458_sm_enum),
+	SOC_ENUM("AK4458 FIR Filter Mode Setting", ak4458_fir_enum),
+	SOC_ENUM("AK4458 Attenuation transition Time Setting",
+		 ak4458_ats_enum),
+	SOC_ENUM("AK4458 BICK fs Setting", ak4458_dif_enum),
+};
+
+/* ak4458 dapm widgets */
+static const struct snd_soc_dapm_widget ak4458_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("AK4458 DAC1", NULL, AK4458_0A_CONTROL6, 2, 0),/*pw*/
+	SND_SOC_DAPM_AIF_IN("AK4458 SDTI", "Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_OUTPUT("AK4458 AOUTA"),
+
+	SND_SOC_DAPM_DAC("AK4458 DAC2", NULL, AK4458_0A_CONTROL6, 3, 0),/*pw*/
+	SND_SOC_DAPM_OUTPUT("AK4458 AOUTB"),
+
+	SND_SOC_DAPM_DAC("AK4458 DAC3", NULL, AK4458_0B_CONTROL7, 2, 0),/*pw*/
+	SND_SOC_DAPM_OUTPUT("AK4458 AOUTC"),
+
+	SND_SOC_DAPM_DAC("AK4458 DAC4", NULL, AK4458_0B_CONTROL7, 3, 0),/*pw*/
+	SND_SOC_DAPM_OUTPUT("AK4458 AOUTD"),
+};
+
+static const struct snd_soc_dapm_route ak4458_intercon[] = {
+	{"AK4458 DAC1",		NULL,	"AK4458 SDTI"},
+	{"AK4458 AOUTA",	NULL,	"AK4458 DAC1"},
+
+	{"AK4458 DAC2",		NULL,	"AK4458 SDTI"},
+	{"AK4458 AOUTB",	NULL,	"AK4458 DAC2"},
+
+	{"AK4458 DAC3",		NULL,	"AK4458 SDTI"},
+	{"AK4458 AOUTC",	NULL,	"AK4458 DAC3"},
+
+	{"AK4458 DAC4",		NULL,	"AK4458 SDTI"},
+	{"AK4458 AOUTD",	NULL,	"AK4458 DAC4"},
+};
+
+static int ak4458_rstn_control(struct snd_soc_component *component, int bit)
+{
+	int ret;
+
+	if (bit)
+		ret = snd_soc_component_update_bits(component,
+					  AK4458_00_CONTROL1,
+					  AK4458_RSTN_MASK,
+					  0x1);
+	else
+		ret = snd_soc_component_update_bits(component,
+					  AK4458_00_CONTROL1,
+					  AK4458_RSTN_MASK,
+					  0x0);
+	return ret;
+}
+
+static int ak4458_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+	int pcm_width = max(params_physical_width(params), ak4458->slot_width);
+	int nfs1;
+	u8 format;
+
+	nfs1 = params_rate(params);
+	ak4458->fs = nfs1;
+
+	/* Master Clock Frequency Auto Setting Mode Enable */
+	snd_soc_component_update_bits(component, AK4458_00_CONTROL1, 0x80, 0x80);
+
+	switch (pcm_width) {
+	case 16:
+		if (ak4458->fmt == SND_SOC_DAIFMT_I2S)
+			format = AK4458_DIF_24BIT_I2S;
+		else
+			format = AK4458_DIF_16BIT_LSB;
+		break;
+	case 32:
+		switch (ak4458->fmt) {
+		case SND_SOC_DAIFMT_I2S:
+			format = AK4458_DIF_32BIT_I2S;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			format = AK4458_DIF_32BIT_MSB;
+			break;
+		case SND_SOC_DAIFMT_RIGHT_J:
+			format = AK4458_DIF_32BIT_LSB;
+			break;
+		case SND_SOC_DAIFMT_DSP_B:
+			format = AK4458_DIF_32BIT_MSB;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, AK4458_00_CONTROL1,
+			    AK4458_DIF_MASK, format);
+
+	ak4458_rstn_control(component, 0);
+	ak4458_rstn_control(component, 1);
+
+	return 0;
+}
+
+static int ak4458_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS: /* Slave Mode */
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM: /* Master Mode is not supported */
+	case SND_SOC_DAIFMT_CBS_CFM:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	default:
+		dev_err(component->dev, "Master mode unsupported\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_DSP_B:
+		ak4458->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+		break;
+	default:
+		dev_err(component->dev, "Audio format 0x%02X unsupported\n",
+			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+		return -EINVAL;
+	}
+
+	ak4458_rstn_control(component, 0);
+	ak4458_rstn_control(component, 1);
+
+	return 0;
+}
+
+static const int att_speed[] = { 4080, 2040, 510, 255 };
+
+static int ak4458_set_dai_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+	int nfs, ndt, ret, reg;
+	int ats;
+
+	nfs = ak4458->fs;
+
+	reg = snd_soc_component_read32(component, AK4458_0B_CONTROL7);
+	ats = (reg & AK4458_ATS_MASK) >> AK4458_ATS_SHIFT;
+
+	ndt = att_speed[ats] / (nfs / 1000);
+
+	if (mute) {
+		ret = snd_soc_component_update_bits(component, AK4458_01_CONTROL2,  0x01, 1);
+		mdelay(ndt);
+		if (ak4458->mute_gpiod)
+			gpiod_set_value_cansleep(ak4458->mute_gpiod, 1);
+	} else {
+		if (ak4458->mute_gpiod)
+			gpiod_set_value_cansleep(ak4458->mute_gpiod, 0);
+		ret = snd_soc_component_update_bits(component, AK4458_01_CONTROL2, 0x01, 0);
+		mdelay(ndt);
+	}
+
+	return 0;
+}
+
+static int ak4458_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			       unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+	int mode;
+
+	ak4458->slots = slots;
+	ak4458->slot_width = slot_width;
+
+	switch (slots * slot_width) {
+	case 128:
+		mode = AK4458_MODE_TDM128;
+		break;
+	case 256:
+		mode = AK4458_MODE_TDM256;
+		break;
+	case 512:
+		mode = AK4458_MODE_TDM512;
+		break;
+	default:
+		mode = AK4458_MODE_NORMAL;
+		break;
+	}
+
+	snd_soc_component_update_bits(component, AK4458_0A_CONTROL6,
+			    AK4458_MODE_MASK,
+			    mode);
+
+	return 0;
+}
+
+#define AK4458_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE |\
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+static const unsigned int ak4458_rates[] = {
+	8000, 11025,  16000, 22050,
+	32000, 44100, 48000, 88200,
+	96000, 176400, 192000, 352800,
+	384000, 705600, 768000, 1411200,
+	2822400,
+};
+
+static const struct snd_pcm_hw_constraint_list ak4458_rate_constraints = {
+	.count = ARRAY_SIZE(ak4458_rates),
+	.list = ak4458_rates,
+};
+
+static int ak4458_startup(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	int ret;
+
+	ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
+					 SNDRV_PCM_HW_PARAM_RATE,
+					 &ak4458_rate_constraints);
+
+	return ret;
+}
+
+static struct snd_soc_dai_ops ak4458_dai_ops = {
+	.startup        = ak4458_startup,
+	.hw_params	= ak4458_hw_params,
+	.set_fmt	= ak4458_set_dai_fmt,
+	.digital_mute	= ak4458_set_dai_mute,
+	.set_tdm_slot	= ak4458_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver ak4458_dai = {
+	.name = "ak4458-aif",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = AK4458_FORMATS,
+	},
+	.ops = &ak4458_dai_ops,
+};
+
+static void ak4458_power_off(struct ak4458_priv *ak4458)
+{
+	if (ak4458->reset_gpiod) {
+		gpiod_set_value_cansleep(ak4458->reset_gpiod, 0);
+		usleep_range(1000, 2000);
+	}
+}
+
+static void ak4458_power_on(struct ak4458_priv *ak4458)
+{
+	if (ak4458->reset_gpiod) {
+		gpiod_set_value_cansleep(ak4458->reset_gpiod, 1);
+		usleep_range(1000, 2000);
+	}
+}
+
+static void ak4458_init(struct snd_soc_component *component)
+{
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+
+	/* External Mute ON */
+	if (ak4458->mute_gpiod)
+		gpiod_set_value_cansleep(ak4458->mute_gpiod, 1);
+
+	ak4458_power_on(ak4458);
+
+	snd_soc_component_update_bits(component, AK4458_00_CONTROL1,
+			    0x80, 0x80);   /* ACKS bit = 1; 10000000 */
+
+	ak4458_rstn_control(component, 1);
+}
+
+static int ak4458_probe(struct snd_soc_component *component)
+{
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+
+	ak4458_init(component);
+
+	ak4458->fs = 48000;
+
+	return 0;
+}
+
+static void ak4458_remove(struct snd_soc_component *component)
+{
+	struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
+
+	ak4458_power_off(ak4458);
+}
+
+#ifdef CONFIG_PM
+static int __maybe_unused ak4458_runtime_suspend(struct device *dev)
+{
+	struct ak4458_priv *ak4458 = dev_get_drvdata(dev);
+
+	regcache_cache_only(ak4458->regmap, true);
+
+	ak4458_power_off(ak4458);
+
+	if (ak4458->mute_gpiod)
+		gpiod_set_value_cansleep(ak4458->mute_gpiod, 0);
+
+	return 0;
+}
+
+static int __maybe_unused ak4458_runtime_resume(struct device *dev)
+{
+	struct ak4458_priv *ak4458 = dev_get_drvdata(dev);
+
+	if (ak4458->mute_gpiod)
+		gpiod_set_value_cansleep(ak4458->mute_gpiod, 1);
+
+	ak4458_power_off(ak4458);
+	ak4458_power_on(ak4458);
+
+	regcache_cache_only(ak4458->regmap, false);
+	regcache_mark_dirty(ak4458->regmap);
+
+	return regcache_sync(ak4458->regmap);
+}
+#endif /* CONFIG_PM */
+
+static const struct snd_soc_component_driver soc_codec_dev_ak4458 = {
+	.probe			= ak4458_probe,
+	.remove			= ak4458_remove,
+	.controls		= ak4458_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4458_snd_controls),
+	.dapm_widgets		= ak4458_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4458_dapm_widgets),
+	.dapm_routes		= ak4458_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(ak4458_intercon),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config ak4458_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = AK4458_14_R4CHATT,
+	.reg_defaults = ak4458_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ak4458_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const struct dev_pm_ops ak4458_pm = {
+	SET_RUNTIME_PM_OPS(ak4458_runtime_suspend, ak4458_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static int ak4458_i2c_probe(struct i2c_client *i2c)
+{
+	struct ak4458_priv *ak4458;
+	int ret;
+
+	ak4458 = devm_kzalloc(&i2c->dev, sizeof(*ak4458), GFP_KERNEL);
+	if (!ak4458)
+		return -ENOMEM;
+
+	ak4458->regmap = devm_regmap_init_i2c(i2c, &ak4458_regmap);
+	if (IS_ERR(ak4458->regmap))
+		return PTR_ERR(ak4458->regmap);
+
+	i2c_set_clientdata(i2c, ak4458);
+	ak4458->dev = &i2c->dev;
+
+	ak4458->reset_gpiod = devm_gpiod_get_optional(ak4458->dev, "reset",
+						      GPIOD_OUT_LOW);
+	if (IS_ERR(ak4458->reset_gpiod))
+		return PTR_ERR(ak4458->reset_gpiod);
+
+	ak4458->mute_gpiod = devm_gpiod_get_optional(ak4458->dev, "mute",
+						     GPIOD_OUT_LOW);
+	if (IS_ERR(ak4458->mute_gpiod))
+		return PTR_ERR(ak4458->mute_gpiod);
+
+	ret = devm_snd_soc_register_component(ak4458->dev, &soc_codec_dev_ak4458,
+				     &ak4458_dai, 1);
+	if (ret < 0) {
+		dev_err(ak4458->dev, "Failed to register CODEC: %d\n", ret);
+		return ret;
+	}
+
+	pm_runtime_enable(&i2c->dev);
+
+	return 0;
+}
+
+static int ak4458_i2c_remove(struct i2c_client *i2c)
+{
+	pm_runtime_disable(&i2c->dev);
+
+	return 0;
+}
+
+static const struct of_device_id ak4458_of_match[] = {
+	{ .compatible = "asahi-kasei,ak4458", },
+	{ },
+};
+
+static struct i2c_driver ak4458_i2c_driver = {
+	.driver = {
+		.name = "ak4458",
+		.pm = &ak4458_pm,
+		.of_match_table = ak4458_of_match,
+		},
+	.probe_new = ak4458_i2c_probe,
+	.remove = ak4458_i2c_remove,
+};
+
+module_i2c_driver(ak4458_i2c_driver);
+
+MODULE_AUTHOR("Junichi Wakasugi <wakasugi.jb@om.asahi-kasei.co.jp>");
+MODULE_AUTHOR("Mihai Serban <mihai.serban@nxp.com>");
+MODULE_DESCRIPTION("ASoC AK4458 DAC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ak4458.h b/sound/soc/codecs/ak4458.h
new file mode 100644
index 0000000..f906215
--- /dev/null
+++ b/sound/soc/codecs/ak4458.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Audio driver for AK4458
+ *
+ * Copyright (C) 2016 Asahi Kasei Microdevices Corporation
+ * Copyright 2018 NXP
+ */
+
+#ifndef _AK4458_H
+#define _AK4458_H
+
+#include <linux/regmap.h>
+
+/* Settings */
+
+#define AK4458_00_CONTROL1			0x00
+#define AK4458_01_CONTROL2			0x01
+#define AK4458_02_CONTROL3			0x02
+#define AK4458_03_LCHATT			0x03
+#define AK4458_04_RCHATT			0x04
+#define AK4458_05_CONTROL4			0x05
+#define AK4458_06_DSD1				0x06
+#define AK4458_07_CONTROL5			0x07
+#define AK4458_08_SOUND_CONTROL			0x08
+#define AK4458_09_DSD2				0x09
+#define AK4458_0A_CONTROL6			0x0A
+#define AK4458_0B_CONTROL7			0x0B
+#define AK4458_0C_CONTROL8			0x0C
+#define AK4458_0D_CONTROL9			0x0D
+#define AK4458_0E_CONTROL10			0x0E
+#define AK4458_0F_L2CHATT			0x0F
+#define AK4458_10_R2CHATT			0x10
+#define AK4458_11_L3CHATT			0x11
+#define AK4458_12_R3CHATT			0x12
+#define AK4458_13_L4CHATT			0x13
+#define AK4458_14_R4CHATT			0x14
+
+/* Bitfield Definitions */
+
+/* AK4458_00_CONTROL1 (0x00) Fields
+ * Addr Register Name  D7     D6    D5    D4    D3    D2    D1    D0
+ * 00H  Control 1      ACKS   0     0     0     DIF2  DIF1  DIF0  RSTN
+ */
+
+/* Digital Filter (SD, SLOW, SSLOW) */
+#define AK4458_SD_MASK		GENMASK(5, 5)
+#define AK4458_SLOW_MASK	GENMASK(0, 0)
+#define AK4458_SSLOW_MASK	GENMASK(0, 0)
+
+/* DIF2	1 0
+ *  x	1 0 MSB justified  Figure 3 (default)
+ *  x	1 1 I2S Compliment  Figure 4
+ */
+#define AK4458_DIF_SHIFT	1
+#define AK4458_DIF_MASK		GENMASK(3, 1)
+
+#define AK4458_DIF_16BIT_LSB	(0 << 1)
+#define AK4458_DIF_24BIT_I2S	(3 << 1)
+#define AK4458_DIF_32BIT_LSB	(5 << 1)
+#define AK4458_DIF_32BIT_MSB	(6 << 1)
+#define AK4458_DIF_32BIT_I2S	(7 << 1)
+
+/* AK4458_00_CONTROL1 (0x00) D0 bit */
+#define AK4458_RSTN_MASK	GENMASK(0, 0)
+#define AK4458_RSTN		(0x1 << 0)
+
+/* AK4458_0A_CONTROL6 Mode bits */
+#define AK4458_MODE_SHIFT	6
+#define AK4458_MODE_MASK	GENMASK(7, 6)
+#define AK4458_MODE_NORMAL	(0 << AK4458_MODE_SHIFT)
+#define AK4458_MODE_TDM128	(1 << AK4458_MODE_SHIFT)
+#define AK4458_MODE_TDM256	(2 << AK4458_MODE_SHIFT)
+#define AK4458_MODE_TDM512	(3 << AK4458_MODE_SHIFT)
+
+/* DAC Digital attenuator transition time setting
+ * Table 19
+ * Mode	ATS1	ATS2	ATT speed
+ * 0	0	0	4080/fs
+ * 1	0	1	2040/fs
+ * 2	1	0	510/fs
+ * 3	1	1	255/fs
+ * */
+#define AK4458_ATS_SHIFT	6
+#define AK4458_ATS_MASK		GENMASK(7, 6)
+
+#endif /* _AK4458_H */
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
new file mode 100644
index 0000000..31f6099
--- /dev/null
+++ b/sound/soc/codecs/ak4535.c
@@ -0,0 +1,453 @@
+/*
+ * ak4535.c  --  AK4535 ALSA Soc Audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on wm8753.c by Liam Girdwood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include "ak4535.h"
+
+/* codec private data */
+struct ak4535_priv {
+	struct regmap *regmap;
+	unsigned int sysclk;
+};
+
+/*
+ * ak4535 register cache
+ */
+static const struct reg_default ak4535_reg_defaults[] = {
+	{ 0, 0x00 },
+	{ 1, 0x80 },
+	{ 2, 0x00 },
+	{ 3, 0x03 },
+	{ 4, 0x02 },
+	{ 5, 0x00 },
+	{ 6, 0x11 },
+	{ 7, 0x01 },
+	{ 8, 0x00 },
+	{ 9, 0x40 },
+	{ 10, 0x36 },
+	{ 11, 0x10 },
+	{ 12, 0x00 },
+	{ 13, 0x00 },
+	{ 14, 0x57 },
+};
+
+static bool ak4535_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AK4535_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"};
+static const char *ak4535_mono_out[] = {"(L + R)/2", "Hi-Z"};
+static const char *ak4535_hp_out[] = {"Stereo", "Mono"};
+static const char *ak4535_deemp[] = {"44.1kHz", "Off", "48kHz", "32kHz"};
+static const char *ak4535_mic_select[] = {"Internal", "External"};
+
+static const struct soc_enum ak4535_enum[] = {
+	SOC_ENUM_SINGLE(AK4535_SIG1, 7, 2, ak4535_mono_gain),
+	SOC_ENUM_SINGLE(AK4535_SIG1, 6, 2, ak4535_mono_out),
+	SOC_ENUM_SINGLE(AK4535_MODE2, 2, 2, ak4535_hp_out),
+	SOC_ENUM_SINGLE(AK4535_DAC, 0, 4, ak4535_deemp),
+	SOC_ENUM_SINGLE(AK4535_MIC, 1, 2, ak4535_mic_select),
+};
+
+static const struct snd_kcontrol_new ak4535_snd_controls[] = {
+	SOC_SINGLE("ALC2 Switch", AK4535_SIG1, 1, 1, 0),
+	SOC_ENUM("Mono 1 Output", ak4535_enum[1]),
+	SOC_ENUM("Mono 1 Gain", ak4535_enum[0]),
+	SOC_ENUM("Headphone Output", ak4535_enum[2]),
+	SOC_ENUM("Playback Deemphasis", ak4535_enum[3]),
+	SOC_SINGLE("Bass Volume", AK4535_DAC, 2, 3, 0),
+	SOC_SINGLE("Mic Boost (+20dB) Switch", AK4535_MIC, 0, 1, 0),
+	SOC_ENUM("Mic Select", ak4535_enum[4]),
+	SOC_SINGLE("ALC Operation Time", AK4535_TIMER, 0, 3, 0),
+	SOC_SINGLE("ALC Recovery Time", AK4535_TIMER, 2, 3, 0),
+	SOC_SINGLE("ALC ZC Time", AK4535_TIMER, 4, 3, 0),
+	SOC_SINGLE("ALC 1 Switch", AK4535_ALC1, 5, 1, 0),
+	SOC_SINGLE("ALC 2 Switch", AK4535_ALC1, 6, 1, 0),
+	SOC_SINGLE("ALC Volume", AK4535_ALC2, 0, 127, 0),
+	SOC_SINGLE("Capture Volume", AK4535_PGA, 0, 127, 0),
+	SOC_SINGLE("Left Playback Volume", AK4535_LATT, 0, 127, 1),
+	SOC_SINGLE("Right Playback Volume", AK4535_RATT, 0, 127, 1),
+	SOC_SINGLE("AUX Bypass Volume", AK4535_VOL, 0, 15, 0),
+	SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0),
+};
+
+/* Mono 1 Mixer */
+static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0),
+	SOC_DAPM_SINGLE("Mono Playback Switch", AK4535_SIG1, 5, 1, 0),
+};
+
+/* Stereo Mixer */
+static const struct snd_kcontrol_new ak4535_stereo_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG2, 4, 1, 0),
+	SOC_DAPM_SINGLE("Playback Switch", AK4535_SIG2, 7, 1, 0),
+	SOC_DAPM_SINGLE("Aux Bypass Switch", AK4535_SIG2, 5, 1, 0),
+};
+
+/* Input Mixer */
+static const struct snd_kcontrol_new ak4535_input_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Mic Capture Switch", AK4535_MIC, 2, 1, 0),
+	SOC_DAPM_SINGLE("Aux Capture Switch", AK4535_MIC, 5, 1, 0),
+};
+
+/* Input mux */
+static const struct snd_kcontrol_new ak4535_input_mux_control =
+	SOC_DAPM_ENUM("Input Select", ak4535_enum[4]);
+
+/* HP L switch */
+static const struct snd_kcontrol_new ak4535_hpl_control =
+	SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 1, 1, 1);
+
+/* HP R switch */
+static const struct snd_kcontrol_new ak4535_hpr_control =
+	SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 0, 1, 1);
+
+/* mono 2 switch */
+static const struct snd_kcontrol_new ak4535_mono2_control =
+	SOC_DAPM_SINGLE("Switch", AK4535_SIG1, 0, 1, 0);
+
+/* Line out switch */
+static const struct snd_kcontrol_new ak4535_line_control =
+	SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 6, 1, 0);
+
+/* ak4535 dapm widgets */
+static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0,
+		&ak4535_stereo_mixer_controls[0],
+		ARRAY_SIZE(ak4535_stereo_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0,
+		&ak4535_mono1_mixer_controls[0],
+		ARRAY_SIZE(ak4535_mono1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0,
+		&ak4535_input_mixer_controls[0],
+		ARRAY_SIZE(ak4535_input_mixer_controls)),
+	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+		&ak4535_input_mux_control),
+	SND_SOC_DAPM_DAC("DAC", "Playback", AK4535_PM2, 0, 0),
+	SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0,
+		&ak4535_mono2_control),
+	/* speaker powersave bit */
+	SND_SOC_DAPM_PGA("Speaker Enable", AK4535_MODE2, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0,
+		&ak4535_line_control),
+	SND_SOC_DAPM_SWITCH("Left HP Enable", SND_SOC_NOPM, 0, 0,
+		&ak4535_hpl_control),
+	SND_SOC_DAPM_SWITCH("Right HP Enable", SND_SOC_NOPM, 0, 0,
+		&ak4535_hpr_control),
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("ROUT"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("SPP"),
+	SND_SOC_DAPM_OUTPUT("SPN"),
+	SND_SOC_DAPM_OUTPUT("MOUT1"),
+	SND_SOC_DAPM_OUTPUT("MOUT2"),
+	SND_SOC_DAPM_OUTPUT("MICOUT"),
+	SND_SOC_DAPM_ADC("ADC", "Capture", AK4535_PM1, 0, 0),
+	SND_SOC_DAPM_PGA("Spk Amp", AK4535_PM2, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HP R Amp", AK4535_PM2, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HP L Amp", AK4535_PM2, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mic", AK4535_PM1, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Line Out", AK4535_PM1, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono Out", AK4535_PM1, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUX In", AK4535_PM1, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4535_MIC, 3, 0),
+	SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4535_MIC, 4, 0),
+	SND_SOC_DAPM_INPUT("MICIN"),
+	SND_SOC_DAPM_INPUT("MICEXT"),
+	SND_SOC_DAPM_INPUT("AUX"),
+	SND_SOC_DAPM_INPUT("MIN"),
+	SND_SOC_DAPM_INPUT("AIN"),
+};
+
+static const struct snd_soc_dapm_route ak4535_audio_map[] = {
+	/*stereo mixer */
+	{"Stereo Mixer", "Playback Switch", "DAC"},
+	{"Stereo Mixer", "Mic Sidetone Switch", "Mic"},
+	{"Stereo Mixer", "Aux Bypass Switch", "AUX In"},
+
+	/* mono1 mixer */
+	{"Mono1 Mixer", "Mic Sidetone Switch", "Mic"},
+	{"Mono1 Mixer", "Mono Playback Switch", "DAC"},
+
+	/* Mic */
+	{"Mic", NULL, "AIN"},
+	{"Input Mux", "Internal", "Mic Int Bias"},
+	{"Input Mux", "External", "Mic Ext Bias"},
+	{"Mic Int Bias", NULL, "MICIN"},
+	{"Mic Ext Bias", NULL, "MICEXT"},
+	{"MICOUT", NULL, "Input Mux"},
+
+	/* line out */
+	{"LOUT", NULL, "Line Out Enable"},
+	{"ROUT", NULL, "Line Out Enable"},
+	{"Line Out Enable", "Switch", "Line Out"},
+	{"Line Out", NULL, "Stereo Mixer"},
+
+	/* mono1 out */
+	{"MOUT1", NULL, "Mono Out"},
+	{"Mono Out", NULL, "Mono1 Mixer"},
+
+	/* left HP */
+	{"HPL", NULL, "Left HP Enable"},
+	{"Left HP Enable", "Switch", "HP L Amp"},
+	{"HP L Amp", NULL, "Stereo Mixer"},
+
+	/* right HP */
+	{"HPR", NULL, "Right HP Enable"},
+	{"Right HP Enable", "Switch", "HP R Amp"},
+	{"HP R Amp", NULL, "Stereo Mixer"},
+
+	/* speaker */
+	{"SPP", NULL, "Speaker Enable"},
+	{"SPN", NULL, "Speaker Enable"},
+	{"Speaker Enable", "Switch", "Spk Amp"},
+	{"Spk Amp", NULL, "MIN"},
+
+	/* mono 2 */
+	{"MOUT2", NULL, "Mono 2 Enable"},
+	{"Mono 2 Enable", "Switch", "Stereo Mixer"},
+
+	/* Aux In */
+	{"Aux In", NULL, "AUX"},
+
+	/* ADC */
+	{"ADC", NULL, "Input Mixer"},
+	{"Input Mixer", "Mic Capture Switch", "Mic"},
+	{"Input Mixer", "Aux Capture Switch", "Aux In"},
+};
+
+static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+	int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct ak4535_priv *ak4535 = snd_soc_component_get_drvdata(component);
+
+	ak4535->sysclk = freq;
+	return 0;
+}
+
+static int ak4535_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4535_priv *ak4535 = snd_soc_component_get_drvdata(component);
+	u8 mode2 = snd_soc_component_read32(component, AK4535_MODE2) & ~(0x3 << 5);
+	int rate = params_rate(params), fs = 256;
+
+	if (rate)
+		fs = ak4535->sysclk / rate;
+
+	/* set fs */
+	switch (fs) {
+	case 1024:
+		mode2 |= (0x2 << 5);
+		break;
+	case 512:
+		mode2 |= (0x1 << 5);
+		break;
+	case 256:
+		break;
+	}
+
+	/* set rate */
+	snd_soc_component_write(component, AK4535_MODE2, mode2);
+	return 0;
+}
+
+static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u8 mode1 = 0;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		mode1 = 0x0002;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		mode1 = 0x0001;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* use 32 fs for BCLK to save power */
+	mode1 |= 0x4;
+
+	snd_soc_component_write(component, AK4535_MODE1, mode1);
+	return 0;
+}
+
+static int ak4535_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, AK4535_DAC);
+	if (!mute)
+		snd_soc_component_write(component, AK4535_DAC, mute_reg & ~0x20);
+	else
+		snd_soc_component_write(component, AK4535_DAC, mute_reg | 0x20);
+	return 0;
+}
+
+static int ak4535_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_component_update_bits(component, AK4535_DAC, 0x20, 0);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		snd_soc_component_update_bits(component, AK4535_DAC, 0x20, 0x20);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_component_update_bits(component, AK4535_PM1, 0x80, 0x80);
+		snd_soc_component_update_bits(component, AK4535_PM2, 0x80, 0);
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, AK4535_PM1, 0x80, 0);
+		break;
+	}
+	return 0;
+}
+
+#define AK4535_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+static const struct snd_soc_dai_ops ak4535_dai_ops = {
+	.hw_params	= ak4535_hw_params,
+	.set_fmt	= ak4535_set_dai_fmt,
+	.digital_mute	= ak4535_mute,
+	.set_sysclk	= ak4535_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver ak4535_dai = {
+	.name = "ak4535-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = AK4535_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = AK4535_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = &ak4535_dai_ops,
+};
+
+static int ak4535_resume(struct snd_soc_component *component)
+{
+	snd_soc_component_cache_sync(component);
+	return 0;
+}
+
+static const struct regmap_config ak4535_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = AK4535_STATUS,
+	.volatile_reg = ak4535_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = ak4535_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ak4535_reg_defaults),
+};
+
+static const struct snd_soc_component_driver soc_component_dev_ak4535 = {
+	.resume			= ak4535_resume,
+	.set_bias_level		= ak4535_set_bias_level,
+	.controls		= ak4535_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4535_snd_controls),
+	.dapm_widgets		= ak4535_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4535_dapm_widgets),
+	.dapm_routes		= ak4535_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(ak4535_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int ak4535_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct ak4535_priv *ak4535;
+	int ret;
+
+	ak4535 = devm_kzalloc(&i2c->dev, sizeof(struct ak4535_priv),
+			      GFP_KERNEL);
+	if (ak4535 == NULL)
+		return -ENOMEM;
+
+	ak4535->regmap = devm_regmap_init_i2c(i2c, &ak4535_regmap);
+	if (IS_ERR(ak4535->regmap)) {
+		ret = PTR_ERR(ak4535->regmap);
+		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, ak4535);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_ak4535, &ak4535_dai, 1);
+
+	return ret;
+}
+
+static const struct i2c_device_id ak4535_i2c_id[] = {
+	{ "ak4535", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id);
+
+static struct i2c_driver ak4535_i2c_driver = {
+	.driver = {
+		.name = "ak4535",
+	},
+	.probe =    ak4535_i2c_probe,
+	.id_table = ak4535_i2c_id,
+};
+
+module_i2c_driver(ak4535_i2c_driver);
+
+MODULE_DESCRIPTION("Soc AK4535 driver");
+MODULE_AUTHOR("Richard Purdie");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h
new file mode 100644
index 0000000..402de1d
--- /dev/null
+++ b/sound/soc/codecs/ak4535.h
@@ -0,0 +1,37 @@
+/*
+ * ak4535.h  --  AK4535 Soc Audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on wm8753.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _AK4535_H
+#define _AK4535_H
+
+/* AK4535 register space */
+
+#define AK4535_PM1		0x0
+#define AK4535_PM2		0x1
+#define AK4535_SIG1		0x2
+#define AK4535_SIG2		0x3
+#define AK4535_MODE1		0x4
+#define AK4535_MODE2		0x5
+#define AK4535_DAC		0x6
+#define AK4535_MIC		0x7
+#define AK4535_TIMER		0x8
+#define AK4535_ALC1		0x9
+#define AK4535_ALC2		0xa
+#define AK4535_PGA		0xb
+#define AK4535_LATT		0xc
+#define AK4535_RATT		0xd
+#define AK4535_VOL		0xe
+#define AK4535_STATUS		0xf
+
+#endif
diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c
new file mode 100644
index 0000000..2fa83a1
--- /dev/null
+++ b/sound/soc/codecs/ak4554.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+// ak4554.c
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+/*
+ * ak4554 is very simple DA/AD converter which has no setting register.
+ *
+ * CAUTION
+ *
+ * ak4554 playback format is SND_SOC_DAIFMT_RIGHT_J,
+ * and,   capture  format is SND_SOC_DAIFMT_LEFT_J
+ * on same bit clock, LR clock.
+ * But, this driver doesn't have snd_soc_dai_ops :: set_fmt
+ *
+ * CPU/Codec DAI image
+ *
+ * CPU-DAI1 (plaback only fmt = RIGHT_J) --+-- ak4554
+ *					   |
+ * CPU-DAI2 (capture only fmt = LEFT_J) ---+
+ */
+
+static const struct snd_soc_dapm_widget ak4554_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AINL"),
+SND_SOC_DAPM_INPUT("AINR"),
+
+SND_SOC_DAPM_OUTPUT("AOUTL"),
+SND_SOC_DAPM_OUTPUT("AOUTR"),
+};
+
+static const struct snd_soc_dapm_route ak4554_dapm_routes[] = {
+	{ "Capture", NULL, "AINL" },
+	{ "Capture", NULL, "AINR" },
+
+	{ "AOUTL", NULL, "Playback" },
+	{ "AOUTR", NULL, "Playback" },
+};
+
+static struct snd_soc_dai_driver ak4554_dai = {
+	.name = "ak4554-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.symmetric_rates = 1,
+};
+
+static const struct snd_soc_component_driver soc_component_dev_ak4554 = {
+	.dapm_widgets		= ak4554_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4554_dapm_widgets),
+	.dapm_routes		= ak4554_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ak4554_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int ak4554_soc_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_ak4554,
+				      &ak4554_dai, 1);
+}
+
+static const struct of_device_id ak4554_of_match[] = {
+	{ .compatible = "asahi-kasei,ak4554" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ak4554_of_match);
+
+static struct platform_driver ak4554_driver = {
+	.driver = {
+		.name = "ak4554-adc-dac",
+		.of_match_table = ak4554_of_match,
+	},
+	.probe	= ak4554_soc_probe,
+};
+module_platform_driver(ak4554_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SoC AK4554 driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
new file mode 100644
index 0000000..c1181a2
--- /dev/null
+++ b/sound/soc/codecs/ak4613.c
@@ -0,0 +1,700 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// ak4613.c  --  Asahi Kasei ALSA Soc Audio driver
+//
+// Copyright (C) 2015 Renesas Electronics Corporation
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// Based on ak4642.c by Kuninori Morimoto
+// Based on wm8731.c by Richard Purdie
+// Based on ak4535.c by Richard Purdie
+// Based on wm8753.c by Liam Girdwood
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#define PW_MGMT1	0x00 /* Power Management 1 */
+#define PW_MGMT2	0x01 /* Power Management 2 */
+#define PW_MGMT3	0x02 /* Power Management 3 */
+#define CTRL1		0x03 /* Control 1 */
+#define CTRL2		0x04 /* Control 2 */
+#define DEMP1		0x05 /* De-emphasis1 */
+#define DEMP2		0x06 /* De-emphasis2 */
+#define OFD		0x07 /* Overflow Detect */
+#define ZRD		0x08 /* Zero Detect */
+#define ICTRL		0x09 /* Input Control */
+#define OCTRL		0x0a /* Output Control */
+#define LOUT1		0x0b /* LOUT1 Volume Control */
+#define ROUT1		0x0c /* ROUT1 Volume Control */
+#define LOUT2		0x0d /* LOUT2 Volume Control */
+#define ROUT2		0x0e /* ROUT2 Volume Control */
+#define LOUT3		0x0f /* LOUT3 Volume Control */
+#define ROUT3		0x10 /* ROUT3 Volume Control */
+#define LOUT4		0x11 /* LOUT4 Volume Control */
+#define ROUT4		0x12 /* ROUT4 Volume Control */
+#define LOUT5		0x13 /* LOUT5 Volume Control */
+#define ROUT5		0x14 /* ROUT5 Volume Control */
+#define LOUT6		0x15 /* LOUT6 Volume Control */
+#define ROUT6		0x16 /* ROUT6 Volume Control */
+
+/* PW_MGMT1 */
+#define RSTN		BIT(0)
+#define PMDAC		BIT(1)
+#define PMADC		BIT(2)
+#define PMVR		BIT(3)
+
+/* PW_MGMT2 */
+#define PMAD_ALL	0x7
+
+/* PW_MGMT3 */
+#define PMDA_ALL	0x3f
+
+/* CTRL1 */
+#define DIF0		BIT(3)
+#define DIF1		BIT(4)
+#define DIF2		BIT(5)
+#define TDM0		BIT(6)
+#define TDM1		BIT(7)
+#define NO_FMT		(0xff)
+#define FMT_MASK	(0xf8)
+
+/* CTRL2 */
+#define DFS_MASK		(3 << 2)
+#define DFS_NORMAL_SPEED	(0 << 2)
+#define DFS_DOUBLE_SPEED	(1 << 2)
+#define DFS_QUAD_SPEED		(2 << 2)
+
+/* ICTRL */
+#define ICTRL_MASK	(0x3)
+
+/* OCTRL */
+#define OCTRL_MASK	(0x3F)
+
+struct ak4613_formats {
+	unsigned int width;
+	unsigned int fmt;
+};
+
+struct ak4613_interface {
+	struct ak4613_formats capture;
+	struct ak4613_formats playback;
+};
+
+struct ak4613_priv {
+	struct mutex lock;
+	const struct ak4613_interface *iface;
+	struct snd_pcm_hw_constraint_list constraint;
+	struct work_struct dummy_write_work;
+	struct snd_soc_component *component;
+	unsigned int rate;
+	unsigned int sysclk;
+
+	unsigned int fmt;
+	u8 oc;
+	u8 ic;
+	int cnt;
+};
+
+/*
+ * Playback Volume
+ *
+ * max : 0x00 : 0 dB
+ *       ( 0.5 dB step )
+ * min : 0xFE : -127.0 dB
+ * mute: 0xFF
+ */
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12750, 50, 1);
+
+static const struct snd_kcontrol_new ak4613_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("Digital Playback Volume1", LOUT1, ROUT1,
+			 0, 0xFF, 1, out_tlv),
+	SOC_DOUBLE_R_TLV("Digital Playback Volume2", LOUT2, ROUT2,
+			 0, 0xFF, 1, out_tlv),
+	SOC_DOUBLE_R_TLV("Digital Playback Volume3", LOUT3, ROUT3,
+			 0, 0xFF, 1, out_tlv),
+	SOC_DOUBLE_R_TLV("Digital Playback Volume4", LOUT4, ROUT4,
+			 0, 0xFF, 1, out_tlv),
+	SOC_DOUBLE_R_TLV("Digital Playback Volume5", LOUT5, ROUT5,
+			 0, 0xFF, 1, out_tlv),
+	SOC_DOUBLE_R_TLV("Digital Playback Volume6", LOUT6, ROUT6,
+			 0, 0xFF, 1, out_tlv),
+};
+
+static const struct reg_default ak4613_reg[] = {
+	{ 0x0,  0x0f }, { 0x1,  0x07 }, { 0x2,  0x3f }, { 0x3,  0x20 },
+	{ 0x4,  0x20 }, { 0x5,  0x55 }, { 0x6,  0x05 }, { 0x7,  0x07 },
+	{ 0x8,  0x0f }, { 0x9,  0x07 }, { 0xa,  0x3f }, { 0xb,  0x00 },
+	{ 0xc,  0x00 }, { 0xd,  0x00 }, { 0xe,  0x00 }, { 0xf,  0x00 },
+	{ 0x10, 0x00 }, { 0x11, 0x00 }, { 0x12, 0x00 }, { 0x13, 0x00 },
+	{ 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 },
+};
+
+#define AUDIO_IFACE_TO_VAL(fmts) ((fmts - ak4613_iface) << 3)
+#define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt }
+static const struct ak4613_interface ak4613_iface[] = {
+	/* capture */				/* playback */
+	/* [0] - [2] are not supported */
+	[3] = {	AUDIO_IFACE(24, LEFT_J),	AUDIO_IFACE(24, LEFT_J) },
+	[4] = {	AUDIO_IFACE(24, I2S),		AUDIO_IFACE(24, I2S) },
+};
+
+static const struct regmap_config ak4613_regmap_cfg = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= 0x16,
+	.reg_defaults		= ak4613_reg,
+	.num_reg_defaults	= ARRAY_SIZE(ak4613_reg),
+	.cache_type		= REGCACHE_RBTREE,
+};
+
+static const struct of_device_id ak4613_of_match[] = {
+	{ .compatible = "asahi-kasei,ak4613",	.data = &ak4613_regmap_cfg },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ak4613_of_match);
+
+static const struct i2c_device_id ak4613_i2c_id[] = {
+	{ "ak4613", (kernel_ulong_t)&ak4613_regmap_cfg },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ak4613_i2c_id);
+
+static const struct snd_soc_dapm_widget ak4613_dapm_widgets[] = {
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("LOUT1"),
+	SND_SOC_DAPM_OUTPUT("LOUT2"),
+	SND_SOC_DAPM_OUTPUT("LOUT3"),
+	SND_SOC_DAPM_OUTPUT("LOUT4"),
+	SND_SOC_DAPM_OUTPUT("LOUT5"),
+	SND_SOC_DAPM_OUTPUT("LOUT6"),
+
+	SND_SOC_DAPM_OUTPUT("ROUT1"),
+	SND_SOC_DAPM_OUTPUT("ROUT2"),
+	SND_SOC_DAPM_OUTPUT("ROUT3"),
+	SND_SOC_DAPM_OUTPUT("ROUT4"),
+	SND_SOC_DAPM_OUTPUT("ROUT5"),
+	SND_SOC_DAPM_OUTPUT("ROUT6"),
+
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("LIN1"),
+	SND_SOC_DAPM_INPUT("LIN2"),
+
+	SND_SOC_DAPM_INPUT("RIN1"),
+	SND_SOC_DAPM_INPUT("RIN2"),
+
+	/* DAC */
+	SND_SOC_DAPM_DAC("DAC1", NULL, PW_MGMT3, 0, 0),
+	SND_SOC_DAPM_DAC("DAC2", NULL, PW_MGMT3, 1, 0),
+	SND_SOC_DAPM_DAC("DAC3", NULL, PW_MGMT3, 2, 0),
+	SND_SOC_DAPM_DAC("DAC4", NULL, PW_MGMT3, 3, 0),
+	SND_SOC_DAPM_DAC("DAC5", NULL, PW_MGMT3, 4, 0),
+	SND_SOC_DAPM_DAC("DAC6", NULL, PW_MGMT3, 5, 0),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC("ADC1", NULL, PW_MGMT2, 0, 0),
+	SND_SOC_DAPM_ADC("ADC2", NULL, PW_MGMT2, 1, 0),
+};
+
+static const struct snd_soc_dapm_route ak4613_intercon[] = {
+	{"LOUT1", NULL, "DAC1"},
+	{"LOUT2", NULL, "DAC2"},
+	{"LOUT3", NULL, "DAC3"},
+	{"LOUT4", NULL, "DAC4"},
+	{"LOUT5", NULL, "DAC5"},
+	{"LOUT6", NULL, "DAC6"},
+
+	{"ROUT1", NULL, "DAC1"},
+	{"ROUT2", NULL, "DAC2"},
+	{"ROUT3", NULL, "DAC3"},
+	{"ROUT4", NULL, "DAC4"},
+	{"ROUT5", NULL, "DAC5"},
+	{"ROUT6", NULL, "DAC6"},
+
+	{"DAC1", NULL, "Playback"},
+	{"DAC2", NULL, "Playback"},
+	{"DAC3", NULL, "Playback"},
+	{"DAC4", NULL, "Playback"},
+	{"DAC5", NULL, "Playback"},
+	{"DAC6", NULL, "Playback"},
+
+	{"Capture", NULL, "ADC1"},
+	{"Capture", NULL, "ADC2"},
+
+	{"ADC1", NULL, "LIN1"},
+	{"ADC2", NULL, "LIN2"},
+
+	{"ADC1", NULL, "RIN1"},
+	{"ADC2", NULL, "RIN2"},
+};
+
+static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
+	struct device *dev = component->dev;
+
+	mutex_lock(&priv->lock);
+	priv->cnt--;
+	if (priv->cnt < 0) {
+		dev_err(dev, "unexpected counter error\n");
+		priv->cnt = 0;
+	}
+	if (!priv->cnt)
+		priv->iface = NULL;
+	mutex_unlock(&priv->lock);
+}
+
+static void ak4613_hw_constraints(struct ak4613_priv *priv,
+				  struct snd_pcm_runtime *runtime)
+{
+	static const unsigned int ak4613_rates[] = {
+		 32000,
+		 44100,
+		 48000,
+		 64000,
+		 88200,
+		 96000,
+		176400,
+		192000,
+	};
+	struct snd_pcm_hw_constraint_list *constraint = &priv->constraint;
+	unsigned int fs;
+	int i;
+
+	constraint->list	= ak4613_rates;
+	constraint->mask	= 0;
+	constraint->count	= 0;
+
+	/*
+	 * Slave Mode
+	 *	Normal: [32kHz, 48kHz] : 256fs,384fs or 512fs
+	 *	Double: [64kHz, 96kHz] : 256fs
+	 *	Quad  : [128kHz,192kHz]: 128fs
+	 *
+	 * Master mode
+	 *	Normal: [32kHz, 48kHz] : 256fs or 512fs
+	 *	Double: [64kHz, 96kHz] : 256fs
+	 *	Quad  : [128kHz,192kHz]: 128fs
+	*/
+	for (i = 0; i < ARRAY_SIZE(ak4613_rates); i++) {
+		/* minimum fs on each range */
+		fs = (ak4613_rates[i] <= 96000) ? 256 : 128;
+
+		if (priv->sysclk >= ak4613_rates[i] * fs)
+			constraint->count = i + 1;
+	}
+
+	snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE, constraint);
+}
+
+static int ak4613_dai_startup(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
+
+	priv->cnt++;
+
+	ak4613_hw_constraints(priv, substream->runtime);
+
+	return 0;
+}
+
+static int ak4613_dai_set_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
+
+	priv->sysclk = freq;
+
+	return 0;
+}
+
+static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
+
+	fmt &= SND_SOC_DAIFMT_FORMAT_MASK;
+
+	switch (fmt) {
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_I2S:
+		priv->fmt = fmt;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static bool ak4613_dai_fmt_matching(const struct ak4613_interface *iface,
+				    int is_play,
+				    unsigned int fmt, unsigned int width)
+{
+	const struct ak4613_formats *fmts;
+
+	fmts = (is_play) ? &iface->playback : &iface->capture;
+
+	if (fmts->fmt != fmt)
+		return false;
+
+	if (fmts->width != width)
+		return false;
+
+	return true;
+}
+
+static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
+	const struct ak4613_interface *iface;
+	struct device *dev = component->dev;
+	unsigned int width = params_width(params);
+	unsigned int fmt = priv->fmt;
+	unsigned int rate;
+	int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	int i, ret;
+	u8 fmt_ctrl, ctrl2;
+
+	rate = params_rate(params);
+	switch (rate) {
+	case 32000:
+	case 44100:
+	case 48000:
+		ctrl2 = DFS_NORMAL_SPEED;
+		break;
+	case 64000:
+	case 88200:
+	case 96000:
+		ctrl2 = DFS_DOUBLE_SPEED;
+		break;
+	case 176400:
+	case 192000:
+		ctrl2 = DFS_QUAD_SPEED;
+		break;
+	default:
+		return -EINVAL;
+	}
+	priv->rate = rate;
+
+	/*
+	 * FIXME
+	 *
+	 * It doesn't support TDM at this point
+	 */
+	fmt_ctrl = NO_FMT;
+	ret = -EINVAL;
+	iface = NULL;
+
+	mutex_lock(&priv->lock);
+	if (priv->iface) {
+		if (ak4613_dai_fmt_matching(priv->iface, is_play, fmt, width))
+			iface = priv->iface;
+	} else {
+		for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) {
+			if (!ak4613_dai_fmt_matching(ak4613_iface + i,
+						     is_play,
+						     fmt, width))
+				continue;
+			iface = ak4613_iface + i;
+			break;
+		}
+	}
+
+	if ((priv->iface == NULL) ||
+	    (priv->iface == iface)) {
+		priv->iface = iface;
+		ret = 0;
+	}
+	mutex_unlock(&priv->lock);
+
+	if (ret < 0)
+		goto hw_params_end;
+
+	fmt_ctrl = AUDIO_IFACE_TO_VAL(iface);
+
+	snd_soc_component_update_bits(component, CTRL1, FMT_MASK, fmt_ctrl);
+	snd_soc_component_update_bits(component, CTRL2, DFS_MASK, ctrl2);
+
+	snd_soc_component_update_bits(component, ICTRL, ICTRL_MASK, priv->ic);
+	snd_soc_component_update_bits(component, OCTRL, OCTRL_MASK, priv->oc);
+
+hw_params_end:
+	if (ret < 0)
+		dev_warn(dev, "unsupported data width/format combination\n");
+
+	return ret;
+}
+
+static int ak4613_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	u8 mgmt1 = 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		mgmt1 |= RSTN;
+		/* fall through */
+	case SND_SOC_BIAS_PREPARE:
+		mgmt1 |= PMADC | PMDAC;
+		/* fall through */
+	case SND_SOC_BIAS_STANDBY:
+		mgmt1 |= PMVR;
+		/* fall through */
+	case SND_SOC_BIAS_OFF:
+	default:
+		break;
+	}
+
+	snd_soc_component_write(component, PW_MGMT1, mgmt1);
+
+	return 0;
+}
+
+static void ak4613_dummy_write(struct work_struct *work)
+{
+	struct ak4613_priv *priv = container_of(work,
+						struct ak4613_priv,
+						dummy_write_work);
+	struct snd_soc_component *component = priv->component;
+	unsigned int mgmt1;
+	unsigned int mgmt3;
+
+	/*
+	 * PW_MGMT1 / PW_MGMT3 needs dummy write at least after 5 LR clocks
+	 *
+	 * Note
+	 *
+	 * To avoid extra delay, we want to avoid preemption here,
+	 * but we can't. Because it uses I2C access which is using IRQ
+	 * and sleep. Thus, delay might be more than 5 LR clocks
+	 * see also
+	 *	ak4613_dai_trigger()
+	 */
+	udelay(5000000 / priv->rate);
+
+	snd_soc_component_read(component, PW_MGMT1, &mgmt1);
+	snd_soc_component_read(component, PW_MGMT3, &mgmt3);
+
+	snd_soc_component_write(component, PW_MGMT1, mgmt1);
+	snd_soc_component_write(component, PW_MGMT3, mgmt3);
+}
+
+static int ak4613_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
+
+	/*
+	 * FIXME
+	 *
+	 * PW_MGMT1 / PW_MGMT3 needs dummy write at least after 5 LR clocks
+	 * from Power Down Release. Otherwise, Playback volume will be 0dB.
+	 * To avoid complex multiple delay/dummy_write method from
+	 * ak4613_set_bias_level() / SND_SOC_DAPM_DAC_E("DACx", ...),
+	 * call it once here.
+	 *
+	 * But, unfortunately, we can't "write" here because here is atomic
+	 * context (It uses I2C access for writing).
+	 * Thus, use schedule_work() to switching to normal context
+	 * immediately.
+	 *
+	 * Note
+	 *
+	 * Calling ak4613_dummy_write() function might be delayed.
+	 * In such case, ak4613 volume might be temporarily 0dB when
+	 * beggining of playback.
+	 * see also
+	 *	ak4613_dummy_write()
+	 */
+
+	if ((cmd != SNDRV_PCM_TRIGGER_START) &&
+	    (cmd != SNDRV_PCM_TRIGGER_RESUME))
+		return 0;
+
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+		return  0;
+
+	priv->component = component;
+	schedule_work(&priv->dummy_write_work);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops ak4613_dai_ops = {
+	.startup	= ak4613_dai_startup,
+	.shutdown	= ak4613_dai_shutdown,
+	.set_sysclk	= ak4613_dai_set_sysclk,
+	.set_fmt	= ak4613_dai_set_fmt,
+	.trigger	= ak4613_dai_trigger,
+	.hw_params	= ak4613_dai_hw_params,
+};
+
+#define AK4613_PCM_RATE		(SNDRV_PCM_RATE_32000  |\
+				 SNDRV_PCM_RATE_44100  |\
+				 SNDRV_PCM_RATE_48000  |\
+				 SNDRV_PCM_RATE_64000  |\
+				 SNDRV_PCM_RATE_88200  |\
+				 SNDRV_PCM_RATE_96000  |\
+				 SNDRV_PCM_RATE_176400 |\
+				 SNDRV_PCM_RATE_192000)
+#define AK4613_PCM_FMTBIT	(SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver ak4613_dai = {
+	.name = "ak4613-hifi",
+	.playback = {
+		.stream_name	= "Playback",
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= AK4613_PCM_RATE,
+		.formats	= AK4613_PCM_FMTBIT,
+	},
+	.capture = {
+		.stream_name	= "Capture",
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= AK4613_PCM_RATE,
+		.formats	= AK4613_PCM_FMTBIT,
+	},
+	.ops = &ak4613_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int ak4613_suspend(struct snd_soc_component *component)
+{
+	struct regmap *regmap = dev_get_regmap(component->dev, NULL);
+
+	regcache_cache_only(regmap, true);
+	regcache_mark_dirty(regmap);
+	return 0;
+}
+
+static int ak4613_resume(struct snd_soc_component *component)
+{
+	struct regmap *regmap = dev_get_regmap(component->dev, NULL);
+
+	regcache_cache_only(regmap, false);
+	return regcache_sync(regmap);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_ak4613 = {
+	.suspend		= ak4613_suspend,
+	.resume			= ak4613_resume,
+	.set_bias_level		= ak4613_set_bias_level,
+	.controls		= ak4613_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4613_snd_controls),
+	.dapm_widgets		= ak4613_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4613_dapm_widgets),
+	.dapm_routes		= ak4613_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(ak4613_intercon),
+	.idle_bias_on		= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static void ak4613_parse_of(struct ak4613_priv *priv,
+			    struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	char prop[32];
+	int i;
+
+	/* Input 1 - 2 */
+	for (i = 0; i < 2; i++) {
+		snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1);
+		if (!of_get_property(np, prop, NULL))
+			priv->ic |= 1 << i;
+	}
+
+	/* Output 1 - 6 */
+	for (i = 0; i < 6; i++) {
+		snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1);
+		if (!of_get_property(np, prop, NULL))
+			priv->oc |= 1 << i;
+	}
+}
+
+static int ak4613_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct device *dev = &i2c->dev;
+	struct device_node *np = dev->of_node;
+	const struct regmap_config *regmap_cfg;
+	struct regmap *regmap;
+	struct ak4613_priv *priv;
+
+	regmap_cfg = NULL;
+	if (np) {
+		const struct of_device_id *of_id;
+
+		of_id = of_match_device(ak4613_of_match, dev);
+		if (of_id)
+			regmap_cfg = of_id->data;
+	} else {
+		regmap_cfg = (const struct regmap_config *)id->driver_data;
+	}
+
+	if (!regmap_cfg)
+		return -EINVAL;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	ak4613_parse_of(priv, dev);
+
+	priv->iface		= NULL;
+	priv->cnt		= 0;
+	priv->sysclk		= 0;
+	INIT_WORK(&priv->dummy_write_work, ak4613_dummy_write);
+
+	mutex_init(&priv->lock);
+
+	i2c_set_clientdata(i2c, priv);
+
+	regmap = devm_regmap_init_i2c(i2c, regmap_cfg);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return devm_snd_soc_register_component(dev, &soc_component_dev_ak4613,
+				      &ak4613_dai, 1);
+}
+
+static int ak4613_i2c_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static struct i2c_driver ak4613_i2c_driver = {
+	.driver = {
+		.name = "ak4613-codec",
+		.of_match_table = ak4613_of_match,
+	},
+	.probe		= ak4613_i2c_probe,
+	.remove		= ak4613_i2c_remove,
+	.id_table	= ak4613_i2c_id,
+};
+
+module_i2c_driver(ak4613_i2c_driver);
+
+MODULE_DESCRIPTION("Soc AK4613 driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
new file mode 100644
index 0000000..05869be
--- /dev/null
+++ b/sound/soc/codecs/ak4641.c
@@ -0,0 +1,645 @@
+/*
+ * ak4641.c  --  AK4641 ALSA Soc Audio driver
+ *
+ * Copyright (C) 2008 Harald Welte <laforge@gnufiish.org>
+ * Copyright (C) 2011 Dmitry Artamonow <mad_soft@inbox.ru>
+ *
+ * Based on ak4535.c by Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/ak4641.h>
+
+/* AK4641 register space */
+#define AK4641_PM1		0x00
+#define AK4641_PM2		0x01
+#define AK4641_SIG1		0x02
+#define AK4641_SIG2		0x03
+#define AK4641_MODE1		0x04
+#define AK4641_MODE2		0x05
+#define AK4641_DAC		0x06
+#define AK4641_MIC		0x07
+#define AK4641_TIMER		0x08
+#define AK4641_ALC1		0x09
+#define AK4641_ALC2		0x0a
+#define AK4641_PGA		0x0b
+#define AK4641_LATT		0x0c
+#define AK4641_RATT		0x0d
+#define AK4641_VOL		0x0e
+#define AK4641_STATUS		0x0f
+#define AK4641_EQLO		0x10
+#define AK4641_EQMID		0x11
+#define AK4641_EQHI		0x12
+#define AK4641_BTIF		0x13
+
+/* codec private data */
+struct ak4641_priv {
+	struct regmap *regmap;
+	unsigned int sysclk;
+	int deemph;
+	int playback_fs;
+};
+
+/*
+ * ak4641 register cache
+ */
+static const struct reg_default ak4641_reg_defaults[] = {
+	{  0, 0x00 }, {  1, 0x80 }, {  2, 0x00 }, {  3, 0x80 },
+	{  4, 0x02 }, {  5, 0x00 }, {  6, 0x11 }, {  7, 0x05 },
+	{  8, 0x00 }, {  9, 0x00 }, { 10, 0x36 }, { 11, 0x10 },
+	{ 12, 0x00 }, { 13, 0x00 }, { 14, 0x57 }, { 15, 0x00 },
+	{ 16, 0x88 }, { 17, 0x88 }, { 18, 0x08 }, { 19, 0x08 }
+};
+
+static const int deemph_settings[] = {44100, 0, 48000, 32000};
+
+static int ak4641_set_deemph(struct snd_soc_component *component)
+{
+	struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
+	int i, best = 0;
+
+	for (i = 0 ; i < ARRAY_SIZE(deemph_settings); i++) {
+		/* if deemphasis is on, select the nearest available rate */
+		if (ak4641->deemph && deemph_settings[i] != 0 &&
+		    abs(deemph_settings[i] - ak4641->playback_fs) <
+		    abs(deemph_settings[best] - ak4641->playback_fs))
+			best = i;
+
+		if (!ak4641->deemph && deemph_settings[i] == 0)
+			best = i;
+	}
+
+	dev_dbg(component->dev, "Set deemphasis %d\n", best);
+
+	return snd_soc_component_update_bits(component, AK4641_DAC, 0x3, best);
+}
+
+static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
+	int deemph = ucontrol->value.integer.value[0];
+
+	if (deemph > 1)
+		return -EINVAL;
+
+	ak4641->deemph = deemph;
+
+	return ak4641_set_deemph(component);
+}
+
+static int ak4641_get_deemph(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = ak4641->deemph;
+	return 0;
+};
+
+static const char *ak4641_mono_out[] = {"(L + R)/2", "Hi-Z"};
+static const char *ak4641_hp_out[] = {"Stereo", "Mono"};
+static const char *ak4641_mic_select[] = {"Internal", "External"};
+static const char *ak4641_mic_or_dac[] = {"Microphone", "Voice DAC"};
+
+
+static const DECLARE_TLV_DB_SCALE(mono_gain_tlv, -1700, 2300, 0);
+static const DECLARE_TLV_DB_SCALE(mic_boost_tlv, 0, 2000, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(master_tlv, -12750, 50, 0);
+static const DECLARE_TLV_DB_SCALE(mic_stereo_sidetone_tlv, -2700, 300, 0);
+static const DECLARE_TLV_DB_SCALE(mic_mono_sidetone_tlv, -400, 400, 0);
+static const DECLARE_TLV_DB_SCALE(capture_tlv, -800, 50, 0);
+static const DECLARE_TLV_DB_SCALE(alc_tlv, -800, 50, 0);
+static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0);
+
+
+static SOC_ENUM_SINGLE_DECL(ak4641_mono_out_enum,
+			    AK4641_SIG1, 6, ak4641_mono_out);
+static SOC_ENUM_SINGLE_DECL(ak4641_hp_out_enum,
+			    AK4641_MODE2, 2, ak4641_hp_out);
+static SOC_ENUM_SINGLE_DECL(ak4641_mic_select_enum,
+			    AK4641_MIC, 1, ak4641_mic_select);
+static SOC_ENUM_SINGLE_DECL(ak4641_mic_or_dac_enum,
+			    AK4641_BTIF, 4, ak4641_mic_or_dac);
+
+static const struct snd_kcontrol_new ak4641_snd_controls[] = {
+	SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum),
+	SOC_SINGLE_TLV("Mono 1 Gain Volume", AK4641_SIG1, 7, 1, 1,
+							mono_gain_tlv),
+	SOC_ENUM("Headphone Output", ak4641_hp_out_enum),
+	SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
+					ak4641_get_deemph, ak4641_put_deemph),
+
+	SOC_SINGLE_TLV("Mic Boost Volume", AK4641_MIC, 0, 1, 0, mic_boost_tlv),
+
+	SOC_SINGLE("ALC Operation Time", AK4641_TIMER, 0, 3, 0),
+	SOC_SINGLE("ALC Recovery Time", AK4641_TIMER, 2, 3, 0),
+	SOC_SINGLE("ALC ZC Time", AK4641_TIMER, 4, 3, 0),
+
+	SOC_SINGLE("ALC 1 Switch", AK4641_ALC1, 5, 1, 0),
+
+	SOC_SINGLE_TLV("ALC Volume", AK4641_ALC2, 0, 71, 0, alc_tlv),
+	SOC_SINGLE("Left Out Enable Switch", AK4641_SIG2, 1, 1, 0),
+	SOC_SINGLE("Right Out Enable Switch", AK4641_SIG2, 0, 1, 0),
+
+	SOC_SINGLE_TLV("Capture Volume", AK4641_PGA, 0, 71, 0, capture_tlv),
+
+	SOC_DOUBLE_R_TLV("Master Playback Volume", AK4641_LATT,
+				AK4641_RATT, 0, 255, 1, master_tlv),
+
+	SOC_SINGLE_TLV("AUX In Volume", AK4641_VOL, 0, 15, 0, aux_in_tlv),
+
+	SOC_SINGLE("Equalizer Switch", AK4641_DAC, 2, 1, 0),
+	SOC_SINGLE_TLV("EQ1 100 Hz Volume", AK4641_EQLO, 0, 15, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ2 250 Hz Volume", AK4641_EQLO, 4, 15, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ3 1 kHz Volume", AK4641_EQMID, 0, 15, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ4 3.5 kHz Volume", AK4641_EQMID, 4, 15, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ5 10 kHz Volume", AK4641_EQHI, 0, 15, 1, eq_tlv),
+};
+
+/* Mono 1 Mixer */
+static const struct snd_kcontrol_new ak4641_mono1_mixer_controls[] = {
+	SOC_DAPM_SINGLE_TLV("Mic Mono Sidetone Volume", AK4641_VOL, 7, 1, 0,
+						mic_mono_sidetone_tlv),
+	SOC_DAPM_SINGLE("Mic Mono Sidetone Switch", AK4641_SIG1, 4, 1, 0),
+	SOC_DAPM_SINGLE("Mono Playback Switch", AK4641_SIG1, 5, 1, 0),
+};
+
+/* Stereo Mixer */
+static const struct snd_kcontrol_new ak4641_stereo_mixer_controls[] = {
+	SOC_DAPM_SINGLE_TLV("Mic Sidetone Volume", AK4641_VOL, 4, 7, 0,
+						mic_stereo_sidetone_tlv),
+	SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4641_SIG2, 4, 1, 0),
+	SOC_DAPM_SINGLE("Playback Switch", AK4641_SIG2, 7, 1, 0),
+	SOC_DAPM_SINGLE("Aux Bypass Switch", AK4641_SIG2, 5, 1, 0),
+};
+
+/* Input Mixer */
+static const struct snd_kcontrol_new ak4641_input_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Mic Capture Switch", AK4641_MIC, 2, 1, 0),
+	SOC_DAPM_SINGLE("Aux Capture Switch", AK4641_MIC, 5, 1, 0),
+};
+
+/* Mic mux */
+static const struct snd_kcontrol_new ak4641_mic_mux_control =
+	SOC_DAPM_ENUM("Mic Select", ak4641_mic_select_enum);
+
+/* Input mux */
+static const struct snd_kcontrol_new ak4641_input_mux_control =
+	SOC_DAPM_ENUM("Input Select", ak4641_mic_or_dac_enum);
+
+/* mono 2 switch */
+static const struct snd_kcontrol_new ak4641_mono2_control =
+	SOC_DAPM_SINGLE("Switch", AK4641_SIG1, 0, 1, 0);
+
+/* ak4641 dapm widgets */
+static const struct snd_soc_dapm_widget ak4641_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0,
+		&ak4641_stereo_mixer_controls[0],
+		ARRAY_SIZE(ak4641_stereo_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0,
+		&ak4641_mono1_mixer_controls[0],
+		ARRAY_SIZE(ak4641_mono1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0,
+		&ak4641_input_mixer_controls[0],
+		ARRAY_SIZE(ak4641_input_mixer_controls)),
+	SND_SOC_DAPM_MUX("Mic Mux", SND_SOC_NOPM, 0, 0,
+		&ak4641_mic_mux_control),
+	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+		&ak4641_input_mux_control),
+	SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0,
+		&ak4641_mono2_control),
+
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+	SND_SOC_DAPM_OUTPUT("ROUT"),
+	SND_SOC_DAPM_OUTPUT("MOUT1"),
+	SND_SOC_DAPM_OUTPUT("MOUT2"),
+	SND_SOC_DAPM_OUTPUT("MICOUT"),
+
+	SND_SOC_DAPM_ADC("ADC", "HiFi Capture", AK4641_PM1, 0, 0),
+	SND_SOC_DAPM_PGA("Mic", AK4641_PM1, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUX In", AK4641_PM1, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono Out", AK4641_PM1, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Line Out", AK4641_PM1, 4, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("DAC", "HiFi Playback", AK4641_PM2, 0, 0),
+	SND_SOC_DAPM_PGA("Mono Out 2", AK4641_PM2, 3, 0, NULL, 0),
+
+	SND_SOC_DAPM_ADC("Voice ADC", "Voice Capture", AK4641_BTIF, 0, 0),
+	SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AK4641_BTIF, 1, 0),
+
+	SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4641_MIC, 3, 0),
+	SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4641_MIC, 4, 0),
+
+	SND_SOC_DAPM_INPUT("MICIN"),
+	SND_SOC_DAPM_INPUT("MICEXT"),
+	SND_SOC_DAPM_INPUT("AUX"),
+	SND_SOC_DAPM_INPUT("AIN"),
+};
+
+static const struct snd_soc_dapm_route ak4641_audio_map[] = {
+	/* Stereo Mixer */
+	{"Stereo Mixer", "Playback Switch", "DAC"},
+	{"Stereo Mixer", "Mic Sidetone Switch", "Input Mux"},
+	{"Stereo Mixer", "Aux Bypass Switch", "AUX In"},
+
+	/* Mono 1 Mixer */
+	{"Mono1 Mixer", "Mic Mono Sidetone Switch", "Input Mux"},
+	{"Mono1 Mixer", "Mono Playback Switch", "DAC"},
+
+	/* Mic */
+	{"Mic", NULL, "AIN"},
+	{"Mic Mux", "Internal", "Mic Int Bias"},
+	{"Mic Mux", "External", "Mic Ext Bias"},
+	{"Mic Int Bias", NULL, "MICIN"},
+	{"Mic Ext Bias", NULL, "MICEXT"},
+	{"MICOUT", NULL, "Mic Mux"},
+
+	/* Input Mux */
+	{"Input Mux", "Microphone", "Mic"},
+	{"Input Mux", "Voice DAC", "Voice DAC"},
+
+	/* Line Out */
+	{"LOUT", NULL, "Line Out"},
+	{"ROUT", NULL, "Line Out"},
+	{"Line Out", NULL, "Stereo Mixer"},
+
+	/* Mono 1 Out */
+	{"MOUT1", NULL, "Mono Out"},
+	{"Mono Out", NULL, "Mono1 Mixer"},
+
+	/* Mono 2 Out */
+	{"MOUT2", NULL, "Mono 2 Enable"},
+	{"Mono 2 Enable", "Switch", "Mono Out 2"},
+	{"Mono Out 2", NULL, "Stereo Mixer"},
+
+	{"Voice ADC", NULL, "Mono 2 Enable"},
+
+	/* Aux In */
+	{"AUX In", NULL, "AUX"},
+
+	/* ADC */
+	{"ADC", NULL, "Input Mixer"},
+	{"Input Mixer", "Mic Capture Switch", "Mic"},
+	{"Input Mixer", "Aux Capture Switch", "AUX In"},
+};
+
+static int ak4641_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+	int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
+
+	ak4641->sysclk = freq;
+	return 0;
+}
+
+static int ak4641_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
+	int rate = params_rate(params), fs = 256;
+	u8 mode2;
+
+	if (rate)
+		fs = ak4641->sysclk / rate;
+	else
+		return -EINVAL;
+
+	/* set fs */
+	switch (fs) {
+	case 1024:
+		mode2 = (0x2 << 5);
+		break;
+	case 512:
+		mode2 = (0x1 << 5);
+		break;
+	case 256:
+		mode2 = (0x0 << 5);
+		break;
+	default:
+		dev_err(component->dev, "Error: unsupported fs=%d\n", fs);
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, AK4641_MODE2, (0x3 << 5), mode2);
+
+	/* Update de-emphasis filter for the new rate */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ak4641->playback_fs = rate;
+		ak4641_set_deemph(component);
+	}
+
+	return 0;
+}
+
+static int ak4641_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				  unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u8 btif;
+	int ret;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		btif = (0x3 << 5);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		btif = (0x2 << 5);
+		break;
+	case SND_SOC_DAIFMT_DSP_A:	/* MSB after FRM */
+		btif = (0x0 << 5);
+		break;
+	case SND_SOC_DAIFMT_DSP_B:	/* MSB during FRM */
+		btif = (0x1 << 5);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = snd_soc_component_update_bits(component, AK4641_BTIF, (0x3 << 5), btif);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int ak4641_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u8 mode1 = 0;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		mode1 = 0x02;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		mode1 = 0x01;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_soc_component_write(component, AK4641_MODE1, mode1);
+}
+
+static int ak4641_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+
+	return snd_soc_component_update_bits(component, AK4641_DAC, 0x20, mute ? 0x20 : 0);
+}
+
+static int ak4641_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	struct ak4641_priv *ak4641 = snd_soc_component_get_drvdata(component);
+	struct ak4641_platform_data *pdata = component->dev->platform_data;
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* unmute */
+		snd_soc_component_update_bits(component, AK4641_DAC, 0x20, 0);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* mute */
+		snd_soc_component_update_bits(component, AK4641_DAC, 0x20, 0x20);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			if (pdata && gpio_is_valid(pdata->gpio_power))
+				gpio_set_value(pdata->gpio_power, 1);
+			mdelay(1);
+			if (pdata && gpio_is_valid(pdata->gpio_npdn))
+				gpio_set_value(pdata->gpio_npdn, 1);
+			mdelay(1);
+
+			ret = regcache_sync(ak4641->regmap);
+			if (ret) {
+				dev_err(component->dev,
+					"Failed to sync cache: %d\n", ret);
+				return ret;
+			}
+		}
+		snd_soc_component_update_bits(component, AK4641_PM1, 0x80, 0x80);
+		snd_soc_component_update_bits(component, AK4641_PM2, 0x80, 0);
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, AK4641_PM1, 0x80, 0);
+		if (pdata && gpio_is_valid(pdata->gpio_npdn))
+			gpio_set_value(pdata->gpio_npdn, 0);
+		if (pdata && gpio_is_valid(pdata->gpio_power))
+			gpio_set_value(pdata->gpio_power, 0);
+		regcache_mark_dirty(ak4641->regmap);
+		break;
+	}
+	return 0;
+}
+
+#define AK4641_RATES	(SNDRV_PCM_RATE_8000_48000)
+#define AK4641_RATES_BT (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+			 SNDRV_PCM_RATE_16000)
+#define AK4641_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE)
+
+static const struct snd_soc_dai_ops ak4641_i2s_dai_ops = {
+	.hw_params    = ak4641_i2s_hw_params,
+	.set_fmt      = ak4641_i2s_set_dai_fmt,
+	.digital_mute = ak4641_mute,
+	.set_sysclk   = ak4641_set_dai_sysclk,
+};
+
+static const struct snd_soc_dai_ops ak4641_pcm_dai_ops = {
+	.hw_params    = NULL, /* rates are controlled by BT chip */
+	.set_fmt      = ak4641_pcm_set_dai_fmt,
+	.digital_mute = ak4641_mute,
+	.set_sysclk   = ak4641_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver ak4641_dai[] = {
+{
+	.name = "ak4641-hifi",
+	.id = 1,
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = AK4641_RATES,
+		.formats = AK4641_FORMATS,
+	},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = AK4641_RATES,
+		.formats = AK4641_FORMATS,
+	},
+	.ops = &ak4641_i2s_dai_ops,
+	.symmetric_rates = 1,
+},
+{
+	.name = "ak4641-voice",
+	.id = 1,
+	.playback = {
+		.stream_name = "Voice Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = AK4641_RATES_BT,
+		.formats = AK4641_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Voice Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = AK4641_RATES_BT,
+		.formats = AK4641_FORMATS,
+	},
+	.ops = &ak4641_pcm_dai_ops,
+	.symmetric_rates = 1,
+},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_ak4641 = {
+	.controls		= ak4641_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4641_snd_controls),
+	.dapm_widgets		= ak4641_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4641_dapm_widgets),
+	.dapm_routes		= ak4641_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(ak4641_audio_map),
+	.set_bias_level		= ak4641_set_bias_level,
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config ak4641_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = AK4641_BTIF,
+	.reg_defaults = ak4641_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ak4641_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int ak4641_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct ak4641_platform_data *pdata = i2c->dev.platform_data;
+	struct ak4641_priv *ak4641;
+	int ret;
+
+	ak4641 = devm_kzalloc(&i2c->dev, sizeof(struct ak4641_priv),
+			      GFP_KERNEL);
+	if (!ak4641)
+		return -ENOMEM;
+
+	ak4641->regmap = devm_regmap_init_i2c(i2c, &ak4641_regmap);
+	if (IS_ERR(ak4641->regmap))
+		return PTR_ERR(ak4641->regmap);
+
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power)) {
+			ret = gpio_request_one(pdata->gpio_power,
+					GPIOF_OUT_INIT_LOW, "ak4641 power");
+			if (ret)
+				goto err_out;
+		}
+		if (gpio_is_valid(pdata->gpio_npdn)) {
+			ret = gpio_request_one(pdata->gpio_npdn,
+					GPIOF_OUT_INIT_LOW, "ak4641 npdn");
+			if (ret)
+				goto err_gpio;
+
+			udelay(1); /* > 150 ns */
+			gpio_set_value(pdata->gpio_npdn, 1);
+		}
+	}
+
+	i2c_set_clientdata(i2c, ak4641);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				&soc_component_dev_ak4641,
+				ak4641_dai, ARRAY_SIZE(ak4641_dai));
+	if (ret != 0)
+		goto err_gpio2;
+
+	return 0;
+
+err_gpio2:
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power))
+			gpio_set_value(pdata->gpio_power, 0);
+		if (gpio_is_valid(pdata->gpio_npdn))
+			gpio_free(pdata->gpio_npdn);
+	}
+err_gpio:
+	if (pdata && gpio_is_valid(pdata->gpio_power))
+		gpio_free(pdata->gpio_power);
+err_out:
+	return ret;
+}
+
+static int ak4641_i2c_remove(struct i2c_client *i2c)
+{
+	struct ak4641_platform_data *pdata = i2c->dev.platform_data;
+
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power)) {
+			gpio_set_value(pdata->gpio_power, 0);
+			gpio_free(pdata->gpio_power);
+		}
+		if (gpio_is_valid(pdata->gpio_npdn))
+			gpio_free(pdata->gpio_npdn);
+	}
+
+	return 0;
+}
+
+static const struct i2c_device_id ak4641_i2c_id[] = {
+	{ "ak4641", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ak4641_i2c_id);
+
+static struct i2c_driver ak4641_i2c_driver = {
+	.driver = {
+		.name = "ak4641",
+	},
+	.probe =    ak4641_i2c_probe,
+	.remove =   ak4641_i2c_remove,
+	.id_table = ak4641_i2c_id,
+};
+
+module_i2c_driver(ak4641_i2c_driver);
+
+MODULE_DESCRIPTION("SoC AK4641 driver");
+MODULE_AUTHOR("Harald Welte <laforge@gnufiish.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
new file mode 100644
index 0000000..3532370
--- /dev/null
+++ b/sound/soc/codecs/ak4642.c
@@ -0,0 +1,708 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// ak4642.c  --  AK4642/AK4643 ALSA Soc Audio driver
+//
+// Copyright (C) 2009 Renesas Solutions Corp.
+// Kuninori Morimoto <morimoto.kuninori@renesas.com>
+//
+// Based on wm8731.c by Richard Purdie
+// Based on ak4535.c by Richard Purdie
+// Based on wm8753.c by Liam Girdwood
+
+/* ** CAUTION **
+ *
+ * This is very simple driver.
+ * It can use headphone output / stereo input only
+ *
+ * AK4642 is tested.
+ * AK4643 is tested.
+ * AK4648 is tested.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#define PW_MGMT1	0x00
+#define PW_MGMT2	0x01
+#define SG_SL1		0x02
+#define SG_SL2		0x03
+#define MD_CTL1		0x04
+#define MD_CTL2		0x05
+#define TIMER		0x06
+#define ALC_CTL1	0x07
+#define ALC_CTL2	0x08
+#define L_IVC		0x09
+#define L_DVC		0x0a
+#define ALC_CTL3	0x0b
+#define R_IVC		0x0c
+#define R_DVC		0x0d
+#define MD_CTL3		0x0e
+#define MD_CTL4		0x0f
+#define PW_MGMT3	0x10
+#define DF_S		0x11
+#define FIL3_0		0x12
+#define FIL3_1		0x13
+#define FIL3_2		0x14
+#define FIL3_3		0x15
+#define EQ_0		0x16
+#define EQ_1		0x17
+#define EQ_2		0x18
+#define EQ_3		0x19
+#define EQ_4		0x1a
+#define EQ_5		0x1b
+#define FIL1_0		0x1c
+#define FIL1_1		0x1d
+#define FIL1_2		0x1e
+#define FIL1_3		0x1f	/* The maximum valid register for ak4642 */
+#define PW_MGMT4	0x20
+#define MD_CTL5		0x21
+#define LO_MS		0x22
+#define HP_MS		0x23
+#define SPK_MS		0x24	/* The maximum valid register for ak4643 */
+#define EQ_FBEQAB	0x25
+#define EQ_FBEQCD	0x26
+#define EQ_FBEQE	0x27	/* The maximum valid register for ak4648 */
+
+/* PW_MGMT1*/
+#define PMVCM		(1 << 6) /* VCOM Power Management */
+#define PMMIN		(1 << 5) /* MIN Input Power Management */
+#define PMDAC		(1 << 2) /* DAC Power Management */
+#define PMADL		(1 << 0) /* MIC Amp Lch and ADC Lch Power Management */
+
+/* PW_MGMT2 */
+#define HPMTN		(1 << 6)
+#define PMHPL		(1 << 5)
+#define PMHPR		(1 << 4)
+#define MS		(1 << 3) /* master/slave select */
+#define MCKO		(1 << 1)
+#define PMPLL		(1 << 0)
+
+#define PMHP_MASK	(PMHPL | PMHPR)
+#define PMHP		PMHP_MASK
+
+/* PW_MGMT3 */
+#define PMADR		(1 << 0) /* MIC L / ADC R Power Management */
+
+/* SG_SL1 */
+#define MINS		(1 << 6) /* Switch from MIN to Speaker */
+#define DACL		(1 << 4) /* Switch from DAC to Stereo or Receiver */
+#define PMMP		(1 << 2) /* MPWR pin Power Management */
+#define MGAIN0		(1 << 0) /* MIC amp gain*/
+
+/* SG_SL2 */
+#define LOPS		(1 << 6) /* Stero Line-out Power Save Mode */
+
+/* TIMER */
+#define ZTM(param)	((param & 0x3) << 4) /* ALC Zero Crossing TimeOut */
+#define WTM(param)	(((param & 0x4) << 4) | ((param & 0x3) << 2))
+
+/* ALC_CTL1 */
+#define ALC		(1 << 5) /* ALC Enable */
+#define LMTH0		(1 << 0) /* ALC Limiter / Recovery Level */
+
+/* MD_CTL1 */
+#define PLL3		(1 << 7)
+#define PLL2		(1 << 6)
+#define PLL1		(1 << 5)
+#define PLL0		(1 << 4)
+#define PLL_MASK	(PLL3 | PLL2 | PLL1 | PLL0)
+
+#define BCKO_MASK	(1 << 3)
+#define BCKO_64		BCKO_MASK
+
+#define DIF_MASK	(3 << 0)
+#define DSP		(0 << 0)
+#define RIGHT_J		(1 << 0)
+#define LEFT_J		(2 << 0)
+#define I2S		(3 << 0)
+
+/* MD_CTL2 */
+#define FSs(val)	(((val & 0x7) << 0) | ((val & 0x8) << 2))
+#define PSs(val)	((val & 0x3) << 6)
+
+/* MD_CTL3 */
+#define BST1		(1 << 3)
+
+/* MD_CTL4 */
+#define DACH		(1 << 0)
+
+struct ak4642_drvdata {
+	const struct regmap_config *regmap_config;
+	int extended_frequencies;
+};
+
+struct ak4642_priv {
+	const struct ak4642_drvdata *drvdata;
+	struct clk *mcko;
+};
+
+/*
+ * Playback Volume (table 39)
+ *
+ * max : 0x00 : +12.0 dB
+ *       ( 0.5 dB step )
+ * min : 0xFE : -115.0 dB
+ * mute: 0xFF
+ */
+static const DECLARE_TLV_DB_SCALE(out_tlv, -11550, 50, 1);
+
+static const struct snd_kcontrol_new ak4642_snd_controls[] = {
+
+	SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC,
+			 0, 0xFF, 1, out_tlv),
+	SOC_SINGLE("ALC Capture Switch", ALC_CTL1, 5, 1, 0),
+	SOC_SINGLE("ALC Capture ZC Switch", ALC_CTL1, 4, 1, 1),
+};
+
+static const struct snd_kcontrol_new ak4642_headphone_control =
+	SOC_DAPM_SINGLE("Switch", PW_MGMT2, 6, 1, 0);
+
+static const struct snd_kcontrol_new ak4642_lout_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DACL", SG_SL1, 4, 1, 0),
+};
+
+/* event handlers */
+static int ak4642_lout_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMD:
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Power save mode ON */
+		snd_soc_component_update_bits(component, SG_SL2, LOPS, LOPS);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+	case SND_SOC_DAPM_POST_PMD:
+		/* Power save mode OFF */
+		msleep(300);
+		snd_soc_component_update_bits(component, SG_SL2, LOPS, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = {
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("HPOUTL"),
+	SND_SOC_DAPM_OUTPUT("HPOUTR"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT"),
+
+	SND_SOC_DAPM_PGA("HPL Out", PW_MGMT2, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HPR Out", PW_MGMT2, 4, 0, NULL, 0),
+	SND_SOC_DAPM_SWITCH("Headphone Enable", SND_SOC_NOPM, 0, 0,
+			    &ak4642_headphone_control),
+
+	SND_SOC_DAPM_PGA("DACH", MD_CTL4, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER_E("LINEOUT Mixer", PW_MGMT1, 3, 0,
+			   &ak4642_lout_mixer_controls[0],
+			   ARRAY_SIZE(ak4642_lout_mixer_controls),
+			   ak4642_lout_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	/* DAC */
+	SND_SOC_DAPM_DAC("DAC", NULL, PW_MGMT1, 2, 0),
+};
+
+static const struct snd_soc_dapm_route ak4642_intercon[] = {
+
+	/* Outputs */
+	{"HPOUTL", NULL, "HPL Out"},
+	{"HPOUTR", NULL, "HPR Out"},
+	{"LINEOUT", NULL, "LINEOUT Mixer"},
+
+	{"HPL Out", NULL, "Headphone Enable"},
+	{"HPR Out", NULL, "Headphone Enable"},
+
+	{"Headphone Enable", "Switch", "DACH"},
+
+	{"DACH", NULL, "DAC"},
+
+	{"LINEOUT Mixer", "DACL", "DAC"},
+
+	{ "DAC", NULL, "Playback" },
+};
+
+/*
+ * ak4642 register cache
+ */
+static const struct reg_default ak4643_reg[] = {
+	{  0, 0x00 }, {  1, 0x00 }, {  2, 0x01 }, {  3, 0x00 },
+	{  4, 0x02 }, {  5, 0x00 }, {  6, 0x00 }, {  7, 0x00 },
+	{  8, 0xe1 }, {  9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 },
+	{ 12, 0xe1 }, { 13, 0x18 }, { 14, 0x11 }, { 15, 0x08 },
+	{ 16, 0x00 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x00 },
+	{ 20, 0x00 }, { 21, 0x00 }, { 22, 0x00 }, { 23, 0x00 },
+	{ 24, 0x00 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0x00 },
+	{ 28, 0x00 }, { 29, 0x00 }, { 30, 0x00 }, { 31, 0x00 },
+	{ 32, 0x00 }, { 33, 0x00 }, { 34, 0x00 }, { 35, 0x00 },
+	{ 36, 0x00 },
+};
+
+/* The default settings for 0x0 ~ 0x1f registers are the same for ak4642
+   and ak4643. So we reuse the ak4643 reg_default for ak4642.
+   The valid registers for ak4642 are 0x0 ~ 0x1f which is a subset of ak4643,
+   so define NUM_AK4642_REG_DEFAULTS for ak4642.
+*/
+#define ak4642_reg ak4643_reg
+#define NUM_AK4642_REG_DEFAULTS	(FIL1_3 + 1)
+
+static const struct reg_default ak4648_reg[] = {
+	{  0, 0x00 }, {  1, 0x00 }, {  2, 0x01 }, {  3, 0x00 },
+	{  4, 0x02 }, {  5, 0x00 }, {  6, 0x00 }, {  7, 0x00 },
+	{  8, 0xe1 }, {  9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 },
+	{ 12, 0xe1 }, { 13, 0x18 }, { 14, 0x11 }, { 15, 0xb8 },
+	{ 16, 0x00 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x00 },
+	{ 20, 0x00 }, { 21, 0x00 }, { 22, 0x00 }, { 23, 0x00 },
+	{ 24, 0x00 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0x00 },
+	{ 28, 0x00 }, { 29, 0x00 }, { 30, 0x00 }, { 31, 0x00 },
+	{ 32, 0x00 }, { 33, 0x00 }, { 34, 0x00 }, { 35, 0x00 },
+	{ 36, 0x00 }, { 37, 0x88 }, { 38, 0x88 }, { 39, 0x08 },
+};
+
+static int ak4642_dai_startup(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	struct snd_soc_component *component = dai->component;
+
+	if (is_play) {
+		/*
+		 * start headphone output
+		 *
+		 * PLL, Master Mode
+		 * Audio I/F Format :MSB justified (ADC & DAC)
+		 * Bass Boost Level : Middle
+		 *
+		 * This operation came from example code of
+		 * "ASAHI KASEI AK4642" (japanese) manual p97.
+		 */
+		snd_soc_component_write(component, L_IVC, 0x91); /* volume */
+		snd_soc_component_write(component, R_IVC, 0x91); /* volume */
+	} else {
+		/*
+		 * start stereo input
+		 *
+		 * PLL Master Mode
+		 * Audio I/F Format:MSB justified (ADC & DAC)
+		 * Pre MIC AMP:+20dB
+		 * MIC Power On
+		 * ALC setting:Refer to Table 35
+		 * ALC bit=“1”
+		 *
+		 * This operation came from example code of
+		 * "ASAHI KASEI AK4642" (japanese) manual p94.
+		 */
+		snd_soc_component_update_bits(component, SG_SL1, PMMP | MGAIN0, PMMP | MGAIN0);
+		snd_soc_component_write(component, TIMER, ZTM(0x3) | WTM(0x3));
+		snd_soc_component_write(component, ALC_CTL1, ALC | LMTH0);
+		snd_soc_component_update_bits(component, PW_MGMT1, PMADL, PMADL);
+		snd_soc_component_update_bits(component, PW_MGMT3, PMADR, PMADR);
+	}
+
+	return 0;
+}
+
+static void ak4642_dai_shutdown(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	struct snd_soc_component *component = dai->component;
+
+	if (is_play) {
+	} else {
+		/* stop stereo input */
+		snd_soc_component_update_bits(component, PW_MGMT1, PMADL, 0);
+		snd_soc_component_update_bits(component, PW_MGMT3, PMADR, 0);
+		snd_soc_component_update_bits(component, ALC_CTL1, ALC, 0);
+	}
+}
+
+static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai,
+	int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct ak4642_priv *priv = snd_soc_component_get_drvdata(component);
+	u8 pll;
+	int extended_freq = 0;
+
+	switch (freq) {
+	case 11289600:
+		pll = PLL2;
+		break;
+	case 12288000:
+		pll = PLL2 | PLL0;
+		break;
+	case 12000000:
+		pll = PLL2 | PLL1;
+		break;
+	case 24000000:
+		pll = PLL2 | PLL1 | PLL0;
+		break;
+	case 13500000:
+		pll = PLL3 | PLL2;
+		break;
+	case 27000000:
+		pll = PLL3 | PLL2 | PLL0;
+		break;
+	case 19200000:
+		pll = PLL3;
+		extended_freq = 1;
+		break;
+	case 13000000:
+		pll = PLL3 | PLL2 | PLL1;
+		extended_freq = 1;
+		break;
+	case 26000000:
+		pll = PLL3 | PLL2 | PLL1 | PLL0;
+		extended_freq = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (extended_freq && !priv->drvdata->extended_frequencies)
+		return -EINVAL;
+
+	snd_soc_component_update_bits(component, MD_CTL1, PLL_MASK, pll);
+
+	return 0;
+}
+
+static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 data;
+	u8 bcko;
+
+	data = MCKO | PMPLL; /* use MCKO */
+	bcko = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		data |= MS;
+		bcko = BCKO_64;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, PW_MGMT2, MS | MCKO | PMPLL, data);
+	snd_soc_component_update_bits(component, MD_CTL1, BCKO_MASK, bcko);
+
+	/* format type */
+	data = 0;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_LEFT_J:
+		data = LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		data = I2S;
+		break;
+	/* FIXME
+	 * Please add RIGHT_J / DSP support here
+	 */
+	default:
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, MD_CTL1, DIF_MASK, data);
+
+	return 0;
+}
+
+static int ak4642_set_mcko(struct snd_soc_component *component,
+			   u32 frequency)
+{
+	static const u32 fs_list[] = {
+		[0] = 8000,
+		[1] = 12000,
+		[2] = 16000,
+		[3] = 24000,
+		[4] = 7350,
+		[5] = 11025,
+		[6] = 14700,
+		[7] = 22050,
+		[10] = 32000,
+		[11] = 48000,
+		[14] = 29400,
+		[15] = 44100,
+	};
+	static const u32 ps_list[] = {
+		[0] = 256,
+		[1] = 128,
+		[2] = 64,
+		[3] = 32
+	};
+	int ps, fs;
+
+	for (ps = 0; ps < ARRAY_SIZE(ps_list); ps++) {
+		for (fs = 0; fs < ARRAY_SIZE(fs_list); fs++) {
+			if (frequency == ps_list[ps] * fs_list[fs]) {
+				snd_soc_component_write(component, MD_CTL2,
+					      PSs(ps) | FSs(fs));
+				return 0;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int ak4642_dai_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak4642_priv *priv = snd_soc_component_get_drvdata(component);
+	u32 rate = clk_get_rate(priv->mcko);
+
+	if (!rate)
+		rate = params_rate(params) * 256;
+
+	return ak4642_set_mcko(component, rate);
+}
+
+static int ak4642_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_write(component, PW_MGMT1, 0x00);
+		break;
+	default:
+		snd_soc_component_update_bits(component, PW_MGMT1, PMVCM, PMVCM);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops ak4642_dai_ops = {
+	.startup	= ak4642_dai_startup,
+	.shutdown	= ak4642_dai_shutdown,
+	.set_sysclk	= ak4642_dai_set_sysclk,
+	.set_fmt	= ak4642_dai_set_fmt,
+	.hw_params	= ak4642_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver ak4642_dai = {
+	.name = "ak4642-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE },
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE },
+	.ops = &ak4642_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int ak4642_suspend(struct snd_soc_component *component)
+{
+	struct regmap *regmap = dev_get_regmap(component->dev, NULL);
+
+	regcache_cache_only(regmap, true);
+	regcache_mark_dirty(regmap);
+	return 0;
+}
+
+static int ak4642_resume(struct snd_soc_component *component)
+{
+	struct regmap *regmap = dev_get_regmap(component->dev, NULL);
+
+	regcache_cache_only(regmap, false);
+	regcache_sync(regmap);
+	return 0;
+}
+static int ak4642_probe(struct snd_soc_component *component)
+{
+	struct ak4642_priv *priv = snd_soc_component_get_drvdata(component);
+
+	if (priv->mcko)
+		ak4642_set_mcko(component, clk_get_rate(priv->mcko));
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_ak4642 = {
+	.probe			= ak4642_probe,
+	.suspend		= ak4642_suspend,
+	.resume			= ak4642_resume,
+	.set_bias_level		= ak4642_set_bias_level,
+	.controls		= ak4642_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4642_snd_controls),
+	.dapm_widgets		= ak4642_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4642_dapm_widgets),
+	.dapm_routes		= ak4642_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(ak4642_intercon),
+	.idle_bias_on		= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config ak4642_regmap = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= FIL1_3,
+	.reg_defaults		= ak4642_reg,
+	.num_reg_defaults	= NUM_AK4642_REG_DEFAULTS,
+	.cache_type		= REGCACHE_RBTREE,
+};
+
+static const struct regmap_config ak4643_regmap = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= SPK_MS,
+	.reg_defaults		= ak4643_reg,
+	.num_reg_defaults	= ARRAY_SIZE(ak4643_reg),
+	.cache_type		= REGCACHE_RBTREE,
+};
+
+static const struct regmap_config ak4648_regmap = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= EQ_FBEQE,
+	.reg_defaults		= ak4648_reg,
+	.num_reg_defaults	= ARRAY_SIZE(ak4648_reg),
+	.cache_type		= REGCACHE_RBTREE,
+};
+
+static const struct ak4642_drvdata ak4642_drvdata = {
+	.regmap_config = &ak4642_regmap,
+};
+
+static const struct ak4642_drvdata ak4643_drvdata = {
+	.regmap_config = &ak4643_regmap,
+};
+
+static const struct ak4642_drvdata ak4648_drvdata = {
+	.regmap_config = &ak4648_regmap,
+	.extended_frequencies = 1,
+};
+
+#ifdef CONFIG_COMMON_CLK
+static struct clk *ak4642_of_parse_mcko(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct clk *clk;
+	const char *clk_name = np->name;
+	const char *parent_clk_name = NULL;
+	u32 rate;
+
+	if (of_property_read_u32(np, "clock-frequency", &rate))
+		return NULL;
+
+	if (of_property_read_bool(np, "clocks"))
+		parent_clk_name = of_clk_get_parent_name(np, 0);
+
+	of_property_read_string(np, "clock-output-names", &clk_name);
+
+	clk = clk_register_fixed_rate(dev, clk_name, parent_clk_name, 0, rate);
+	if (!IS_ERR(clk))
+		of_clk_add_provider(np, of_clk_src_simple_get, clk);
+
+	return clk;
+}
+#else
+#define ak4642_of_parse_mcko(d) 0
+#endif
+
+static const struct of_device_id ak4642_of_match[];
+static int ak4642_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct device *dev = &i2c->dev;
+	struct device_node *np = dev->of_node;
+	const struct ak4642_drvdata *drvdata = NULL;
+	struct regmap *regmap;
+	struct ak4642_priv *priv;
+	struct clk *mcko = NULL;
+
+	if (np) {
+		const struct of_device_id *of_id;
+
+		mcko = ak4642_of_parse_mcko(dev);
+		if (IS_ERR(mcko))
+			mcko = NULL;
+
+		of_id = of_match_device(ak4642_of_match, dev);
+		if (of_id)
+			drvdata = of_id->data;
+	} else {
+		drvdata = (const struct ak4642_drvdata *)id->driver_data;
+	}
+
+	if (!drvdata) {
+		dev_err(dev, "Unknown device type\n");
+		return -EINVAL;
+	}
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->drvdata = drvdata;
+	priv->mcko = mcko;
+
+	i2c_set_clientdata(i2c, priv);
+
+	regmap = devm_regmap_init_i2c(i2c, drvdata->regmap_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return devm_snd_soc_register_component(dev,
+				&soc_component_dev_ak4642, &ak4642_dai, 1);
+}
+
+static const struct of_device_id ak4642_of_match[] = {
+	{ .compatible = "asahi-kasei,ak4642",	.data = &ak4642_drvdata},
+	{ .compatible = "asahi-kasei,ak4643",	.data = &ak4643_drvdata},
+	{ .compatible = "asahi-kasei,ak4648",	.data = &ak4648_drvdata},
+	{},
+};
+MODULE_DEVICE_TABLE(of, ak4642_of_match);
+
+static const struct i2c_device_id ak4642_i2c_id[] = {
+	{ "ak4642", (kernel_ulong_t)&ak4642_drvdata },
+	{ "ak4643", (kernel_ulong_t)&ak4643_drvdata },
+	{ "ak4648", (kernel_ulong_t)&ak4648_drvdata },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
+
+static struct i2c_driver ak4642_i2c_driver = {
+	.driver = {
+		.name = "ak4642-codec",
+		.of_match_table = ak4642_of_match,
+	},
+	.probe		= ak4642_i2c_probe,
+	.id_table	= ak4642_i2c_id,
+};
+
+module_i2c_driver(ak4642_i2c_driver);
+
+MODULE_DESCRIPTION("Soc AK4642 driver");
+MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
new file mode 100644
index 0000000..7133fd6
--- /dev/null
+++ b/sound/soc/codecs/ak4671.c
@@ -0,0 +1,673 @@
+/*
+ * ak4671.c  --  audio driver for AK4671
+ *
+ * Copyright (C) 2009 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "ak4671.h"
+
+
+/* ak4671 register cache & default register settings */
+static const struct reg_default ak4671_reg_defaults[] = {
+	{ 0x00, 0x00 },	/* AK4671_AD_DA_POWER_MANAGEMENT	(0x00)	*/
+	{ 0x01, 0xf6 },	/* AK4671_PLL_MODE_SELECT0		(0x01)	*/
+	{ 0x02, 0x00 },	/* AK4671_PLL_MODE_SELECT1		(0x02)	*/
+	{ 0x03, 0x02 },	/* AK4671_FORMAT_SELECT			(0x03)	*/
+	{ 0x04, 0x00 },	/* AK4671_MIC_SIGNAL_SELECT		(0x04)	*/
+	{ 0x05, 0x55 },	/* AK4671_MIC_AMP_GAIN			(0x05)	*/
+	{ 0x06, 0x00 },	/* AK4671_MIXING_POWER_MANAGEMENT0	(0x06)	*/
+	{ 0x07, 0x00 },	/* AK4671_MIXING_POWER_MANAGEMENT1	(0x07)	*/
+	{ 0x08, 0xb5 },	/* AK4671_OUTPUT_VOLUME_CONTROL		(0x08)	*/
+	{ 0x09, 0x00 },	/* AK4671_LOUT1_SIGNAL_SELECT		(0x09)	*/
+	{ 0x0a, 0x00 },	/* AK4671_ROUT1_SIGNAL_SELECT		(0x0a)	*/
+	{ 0x0b, 0x00 },	/* AK4671_LOUT2_SIGNAL_SELECT		(0x0b)	*/
+	{ 0x0c, 0x00 },	/* AK4671_ROUT2_SIGNAL_SELECT		(0x0c)	*/
+	{ 0x0d, 0x00 },	/* AK4671_LOUT3_SIGNAL_SELECT		(0x0d)	*/
+	{ 0x0e, 0x00 },	/* AK4671_ROUT3_SIGNAL_SELECT		(0x0e)	*/
+	{ 0x0f, 0x00 },	/* AK4671_LOUT1_POWER_MANAGERMENT	(0x0f)	*/
+	{ 0x10, 0x00 },	/* AK4671_LOUT2_POWER_MANAGERMENT	(0x10)	*/
+	{ 0x11, 0x80 },	/* AK4671_LOUT3_POWER_MANAGERMENT	(0x11)	*/
+	{ 0x12, 0x91 },	/* AK4671_LCH_INPUT_VOLUME_CONTROL	(0x12)	*/
+	{ 0x13, 0x91 },	/* AK4671_RCH_INPUT_VOLUME_CONTROL	(0x13)	*/
+	{ 0x14, 0xe1 },	/* AK4671_ALC_REFERENCE_SELECT		(0x14)	*/
+	{ 0x15, 0x00 },	/* AK4671_DIGITAL_MIXING_CONTROL	(0x15)	*/
+	{ 0x16, 0x00 },	/* AK4671_ALC_TIMER_SELECT		(0x16)	*/
+	{ 0x17, 0x00 },	/* AK4671_ALC_MODE_CONTROL		(0x17)	*/
+	{ 0x18, 0x02 },	/* AK4671_MODE_CONTROL1			(0x18)	*/
+	{ 0x19, 0x01 },	/* AK4671_MODE_CONTROL2			(0x19)	*/
+	{ 0x1a, 0x18 },	/* AK4671_LCH_OUTPUT_VOLUME_CONTROL	(0x1a)	*/
+	{ 0x1b, 0x18 },	/* AK4671_RCH_OUTPUT_VOLUME_CONTROL	(0x1b)	*/
+	{ 0x1c, 0x00 },	/* AK4671_SIDETONE_A_CONTROL		(0x1c)	*/
+	{ 0x1d, 0x02 },	/* AK4671_DIGITAL_FILTER_SELECT		(0x1d)	*/
+	{ 0x1e, 0x00 },	/* AK4671_FIL3_COEFFICIENT0		(0x1e)	*/
+	{ 0x1f, 0x00 },	/* AK4671_FIL3_COEFFICIENT1		(0x1f)	*/
+	{ 0x20, 0x00 },	/* AK4671_FIL3_COEFFICIENT2		(0x20)	*/
+	{ 0x21, 0x00 },	/* AK4671_FIL3_COEFFICIENT3		(0x21)	*/
+	{ 0x22, 0x00 },	/* AK4671_EQ_COEFFICIENT0		(0x22)	*/
+	{ 0x23, 0x00 },	/* AK4671_EQ_COEFFICIENT1		(0x23)	*/
+	{ 0x24, 0x00 },	/* AK4671_EQ_COEFFICIENT2		(0x24)	*/
+	{ 0x25, 0x00 },	/* AK4671_EQ_COEFFICIENT3		(0x25)	*/
+	{ 0x26, 0x00 },	/* AK4671_EQ_COEFFICIENT4		(0x26)	*/
+	{ 0x27, 0x00 },	/* AK4671_EQ_COEFFICIENT5		(0x27)	*/
+	{ 0x28, 0xa9 },	/* AK4671_FIL1_COEFFICIENT0		(0x28)	*/
+	{ 0x29, 0x1f },	/* AK4671_FIL1_COEFFICIENT1		(0x29)	*/
+	{ 0x2a, 0xad },	/* AK4671_FIL1_COEFFICIENT2		(0x2a)	*/
+	{ 0x2b, 0x20 },	/* AK4671_FIL1_COEFFICIENT3		(0x2b)	*/
+	{ 0x2c, 0x00 },	/* AK4671_FIL2_COEFFICIENT0		(0x2c)	*/
+	{ 0x2d, 0x00 },	/* AK4671_FIL2_COEFFICIENT1		(0x2d)	*/
+	{ 0x2e, 0x00 },	/* AK4671_FIL2_COEFFICIENT2		(0x2e)	*/
+	{ 0x2f, 0x00 },	/* AK4671_FIL2_COEFFICIENT3		(0x2f)	*/
+	{ 0x30, 0x00 },	/* AK4671_DIGITAL_FILTER_SELECT2	(0x30)	*/
+
+	{ 0x32, 0x00 },	/* AK4671_E1_COEFFICIENT0		(0x32)	*/
+	{ 0x33, 0x00 },	/* AK4671_E1_COEFFICIENT1		(0x33)	*/
+	{ 0x34, 0x00 },	/* AK4671_E1_COEFFICIENT2		(0x34)	*/
+	{ 0x35, 0x00 },	/* AK4671_E1_COEFFICIENT3		(0x35)	*/
+	{ 0x36, 0x00 },	/* AK4671_E1_COEFFICIENT4		(0x36)	*/
+	{ 0x37, 0x00 },	/* AK4671_E1_COEFFICIENT5		(0x37)	*/
+	{ 0x38, 0x00 },	/* AK4671_E2_COEFFICIENT0		(0x38)	*/
+	{ 0x39, 0x00 },	/* AK4671_E2_COEFFICIENT1		(0x39)	*/
+	{ 0x3a, 0x00 },	/* AK4671_E2_COEFFICIENT2		(0x3a)	*/
+	{ 0x3b, 0x00 },	/* AK4671_E2_COEFFICIENT3		(0x3b)	*/
+	{ 0x3c, 0x00 },	/* AK4671_E2_COEFFICIENT4		(0x3c)	*/
+	{ 0x3d, 0x00 },	/* AK4671_E2_COEFFICIENT5		(0x3d)	*/
+	{ 0x3e, 0x00 },	/* AK4671_E3_COEFFICIENT0		(0x3e)	*/
+	{ 0x3f, 0x00 },	/* AK4671_E3_COEFFICIENT1		(0x3f)	*/
+	{ 0x40, 0x00 },	/* AK4671_E3_COEFFICIENT2		(0x40)	*/
+	{ 0x41, 0x00 },	/* AK4671_E3_COEFFICIENT3		(0x41)	*/
+	{ 0x42, 0x00 },	/* AK4671_E3_COEFFICIENT4		(0x42)	*/
+	{ 0x43, 0x00 },	/* AK4671_E3_COEFFICIENT5		(0x43)	*/
+	{ 0x44, 0x00 },	/* AK4671_E4_COEFFICIENT0		(0x44)	*/
+	{ 0x45, 0x00 },	/* AK4671_E4_COEFFICIENT1		(0x45)	*/
+	{ 0x46, 0x00 },	/* AK4671_E4_COEFFICIENT2		(0x46)	*/
+	{ 0x47, 0x00 },	/* AK4671_E4_COEFFICIENT3		(0x47)	*/
+	{ 0x48, 0x00 },	/* AK4671_E4_COEFFICIENT4		(0x48)	*/
+	{ 0x49, 0x00 },	/* AK4671_E4_COEFFICIENT5		(0x49)	*/
+	{ 0x4a, 0x00 },	/* AK4671_E5_COEFFICIENT0		(0x4a)	*/
+	{ 0x4b, 0x00 },	/* AK4671_E5_COEFFICIENT1		(0x4b)	*/
+	{ 0x4c, 0x00 },	/* AK4671_E5_COEFFICIENT2		(0x4c)	*/
+	{ 0x4d, 0x00 },	/* AK4671_E5_COEFFICIENT3		(0x4d)	*/
+	{ 0x4e, 0x00 },	/* AK4671_E5_COEFFICIENT4		(0x4e)	*/
+	{ 0x4f, 0x00 },	/* AK4671_E5_COEFFICIENT5		(0x4f)	*/
+	{ 0x50, 0x88 },	/* AK4671_EQ_CONTROL_250HZ_100HZ	(0x50)	*/
+	{ 0x51, 0x88 },	/* AK4671_EQ_CONTROL_3500HZ_1KHZ	(0x51)	*/
+	{ 0x52, 0x08 },	/* AK4671_EQ_CONTRO_10KHZ		(0x52)	*/
+	{ 0x53, 0x00 },	/* AK4671_PCM_IF_CONTROL0		(0x53)	*/
+	{ 0x54, 0x00 },	/* AK4671_PCM_IF_CONTROL1		(0x54)	*/
+	{ 0x55, 0x00 },	/* AK4671_PCM_IF_CONTROL2		(0x55)	*/
+	{ 0x56, 0x18 },	/* AK4671_DIGITAL_VOLUME_B_CONTROL	(0x56)	*/
+	{ 0x57, 0x18 },	/* AK4671_DIGITAL_VOLUME_C_CONTROL	(0x57)	*/
+	{ 0x58, 0x00 },	/* AK4671_SIDETONE_VOLUME_CONTROL	(0x58)	*/
+	{ 0x59, 0x00 },	/* AK4671_DIGITAL_MIXING_CONTROL2	(0x59)	*/
+	{ 0x5a, 0x00 },	/* AK4671_SAR_ADC_CONTROL		(0x5a)	*/
+};
+
+/*
+ * LOUT1/ROUT1 output volume control:
+ * from -24 to 6 dB in 6 dB steps (mute instead of -30 dB)
+ */
+static DECLARE_TLV_DB_SCALE(out1_tlv, -3000, 600, 1);
+
+/*
+ * LOUT2/ROUT2 output volume control:
+ * from -33 to 6 dB in 3 dB steps (mute instead of -33 dB)
+ */
+static DECLARE_TLV_DB_SCALE(out2_tlv, -3300, 300, 1);
+
+/*
+ * LOUT3/ROUT3 output volume control:
+ * from -6 to 3 dB in 3 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(out3_tlv, -600, 300, 0);
+
+/*
+ * Mic amp gain control:
+ * from -15 to 30 dB in 3 dB steps
+ * REVISIT: The actual min value(0x01) is -12 dB and the reg value 0x00 is not
+ * available
+ */
+static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -1500, 300, 0);
+
+static const struct snd_kcontrol_new ak4671_snd_controls[] = {
+	/* Common playback gain controls */
+	SOC_SINGLE_TLV("Line Output1 Playback Volume",
+			AK4671_OUTPUT_VOLUME_CONTROL, 0, 0x6, 0, out1_tlv),
+	SOC_SINGLE_TLV("Headphone Output2 Playback Volume",
+			AK4671_OUTPUT_VOLUME_CONTROL, 4, 0xd, 0, out2_tlv),
+	SOC_SINGLE_TLV("Line Output3 Playback Volume",
+			AK4671_LOUT3_POWER_MANAGERMENT, 6, 0x3, 0, out3_tlv),
+
+	/* Common capture gain controls */
+	SOC_DOUBLE_TLV("Mic Amp Capture Volume",
+			AK4671_MIC_AMP_GAIN, 0, 4, 0xf, 0, mic_amp_tlv),
+};
+
+/* event handlers */
+static int ak4671_out2_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, AK4671_LOUT2_POWER_MANAGERMENT,
+				    AK4671_MUTEN, AK4671_MUTEN);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, AK4671_LOUT2_POWER_MANAGERMENT,
+				    AK4671_MUTEN, 0);
+		break;
+	}
+
+	return 0;
+}
+
+/* Output Mixers */
+static const struct snd_kcontrol_new ak4671_lout1_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DACL", AK4671_LOUT1_SIGNAL_SELECT, 0, 1, 0),
+	SOC_DAPM_SINGLE("LINL1", AK4671_LOUT1_SIGNAL_SELECT, 1, 1, 0),
+	SOC_DAPM_SINGLE("LINL2", AK4671_LOUT1_SIGNAL_SELECT, 2, 1, 0),
+	SOC_DAPM_SINGLE("LINL3", AK4671_LOUT1_SIGNAL_SELECT, 3, 1, 0),
+	SOC_DAPM_SINGLE("LINL4", AK4671_LOUT1_SIGNAL_SELECT, 4, 1, 0),
+	SOC_DAPM_SINGLE("LOOPL", AK4671_LOUT1_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_rout1_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DACR", AK4671_ROUT1_SIGNAL_SELECT, 0, 1, 0),
+	SOC_DAPM_SINGLE("RINR1", AK4671_ROUT1_SIGNAL_SELECT, 1, 1, 0),
+	SOC_DAPM_SINGLE("RINR2", AK4671_ROUT1_SIGNAL_SELECT, 2, 1, 0),
+	SOC_DAPM_SINGLE("RINR3", AK4671_ROUT1_SIGNAL_SELECT, 3, 1, 0),
+	SOC_DAPM_SINGLE("RINR4", AK4671_ROUT1_SIGNAL_SELECT, 4, 1, 0),
+	SOC_DAPM_SINGLE("LOOPR", AK4671_ROUT1_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_lout2_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DACHL", AK4671_LOUT2_SIGNAL_SELECT, 0, 1, 0),
+	SOC_DAPM_SINGLE("LINH1", AK4671_LOUT2_SIGNAL_SELECT, 1, 1, 0),
+	SOC_DAPM_SINGLE("LINH2", AK4671_LOUT2_SIGNAL_SELECT, 2, 1, 0),
+	SOC_DAPM_SINGLE("LINH3", AK4671_LOUT2_SIGNAL_SELECT, 3, 1, 0),
+	SOC_DAPM_SINGLE("LINH4", AK4671_LOUT2_SIGNAL_SELECT, 4, 1, 0),
+	SOC_DAPM_SINGLE("LOOPHL", AK4671_LOUT2_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_rout2_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DACHR", AK4671_ROUT2_SIGNAL_SELECT, 0, 1, 0),
+	SOC_DAPM_SINGLE("RINH1", AK4671_ROUT2_SIGNAL_SELECT, 1, 1, 0),
+	SOC_DAPM_SINGLE("RINH2", AK4671_ROUT2_SIGNAL_SELECT, 2, 1, 0),
+	SOC_DAPM_SINGLE("RINH3", AK4671_ROUT2_SIGNAL_SELECT, 3, 1, 0),
+	SOC_DAPM_SINGLE("RINH4", AK4671_ROUT2_SIGNAL_SELECT, 4, 1, 0),
+	SOC_DAPM_SINGLE("LOOPHR", AK4671_ROUT2_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_lout3_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DACSL", AK4671_LOUT3_SIGNAL_SELECT, 0, 1, 0),
+	SOC_DAPM_SINGLE("LINS1", AK4671_LOUT3_SIGNAL_SELECT, 1, 1, 0),
+	SOC_DAPM_SINGLE("LINS2", AK4671_LOUT3_SIGNAL_SELECT, 2, 1, 0),
+	SOC_DAPM_SINGLE("LINS3", AK4671_LOUT3_SIGNAL_SELECT, 3, 1, 0),
+	SOC_DAPM_SINGLE("LINS4", AK4671_LOUT3_SIGNAL_SELECT, 4, 1, 0),
+	SOC_DAPM_SINGLE("LOOPSL", AK4671_LOUT3_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DACSR", AK4671_ROUT3_SIGNAL_SELECT, 0, 1, 0),
+	SOC_DAPM_SINGLE("RINS1", AK4671_ROUT3_SIGNAL_SELECT, 1, 1, 0),
+	SOC_DAPM_SINGLE("RINS2", AK4671_ROUT3_SIGNAL_SELECT, 2, 1, 0),
+	SOC_DAPM_SINGLE("RINS3", AK4671_ROUT3_SIGNAL_SELECT, 3, 1, 0),
+	SOC_DAPM_SINGLE("RINS4", AK4671_ROUT3_SIGNAL_SELECT, 4, 1, 0),
+	SOC_DAPM_SINGLE("LOOPSR", AK4671_ROUT3_SIGNAL_SELECT, 5, 1, 0),
+};
+
+/* Input MUXs */
+static const char *ak4671_lin_mux_texts[] =
+		{"LIN1", "LIN2", "LIN3", "LIN4"};
+static SOC_ENUM_SINGLE_DECL(ak4671_lin_mux_enum,
+			    AK4671_MIC_SIGNAL_SELECT, 0,
+			    ak4671_lin_mux_texts);
+static const struct snd_kcontrol_new ak4671_lin_mux_control =
+	SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum);
+
+static const char *ak4671_rin_mux_texts[] =
+		{"RIN1", "RIN2", "RIN3", "RIN4"};
+static SOC_ENUM_SINGLE_DECL(ak4671_rin_mux_enum,
+			    AK4671_MIC_SIGNAL_SELECT, 2,
+			    ak4671_rin_mux_texts);
+static const struct snd_kcontrol_new ak4671_rin_mux_control =
+	SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum);
+
+static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = {
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("LIN1"),
+	SND_SOC_DAPM_INPUT("RIN1"),
+	SND_SOC_DAPM_INPUT("LIN2"),
+	SND_SOC_DAPM_INPUT("RIN2"),
+	SND_SOC_DAPM_INPUT("LIN3"),
+	SND_SOC_DAPM_INPUT("RIN3"),
+	SND_SOC_DAPM_INPUT("LIN4"),
+	SND_SOC_DAPM_INPUT("RIN4"),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("LOUT1"),
+	SND_SOC_DAPM_OUTPUT("ROUT1"),
+	SND_SOC_DAPM_OUTPUT("LOUT2"),
+	SND_SOC_DAPM_OUTPUT("ROUT2"),
+	SND_SOC_DAPM_OUTPUT("LOUT3"),
+	SND_SOC_DAPM_OUTPUT("ROUT3"),
+
+	/* DAC */
+	SND_SOC_DAPM_DAC("DAC Left", "Left HiFi Playback",
+			AK4671_AD_DA_POWER_MANAGEMENT, 6, 0),
+	SND_SOC_DAPM_DAC("DAC Right", "Right HiFi Playback",
+			AK4671_AD_DA_POWER_MANAGEMENT, 7, 0),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC("ADC Left", "Left HiFi Capture",
+			AK4671_AD_DA_POWER_MANAGEMENT, 4, 0),
+	SND_SOC_DAPM_ADC("ADC Right", "Right HiFi Capture",
+			AK4671_AD_DA_POWER_MANAGEMENT, 5, 0),
+
+	/* PGA */
+	SND_SOC_DAPM_PGA("LOUT2 Mix Amp",
+			AK4671_LOUT2_POWER_MANAGERMENT, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("ROUT2 Mix Amp",
+			AK4671_LOUT2_POWER_MANAGERMENT, 6, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("LIN1 Mixing Circuit",
+			AK4671_MIXING_POWER_MANAGEMENT1, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("RIN1 Mixing Circuit",
+			AK4671_MIXING_POWER_MANAGEMENT1, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("LIN2 Mixing Circuit",
+			AK4671_MIXING_POWER_MANAGEMENT1, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("RIN2 Mixing Circuit",
+			AK4671_MIXING_POWER_MANAGEMENT1, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("LIN3 Mixing Circuit",
+			AK4671_MIXING_POWER_MANAGEMENT1, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("RIN3 Mixing Circuit",
+			AK4671_MIXING_POWER_MANAGEMENT1, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("LIN4 Mixing Circuit",
+			AK4671_MIXING_POWER_MANAGEMENT1, 6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("RIN4 Mixing Circuit",
+			AK4671_MIXING_POWER_MANAGEMENT1, 7, 0, NULL, 0),
+
+	/* Output Mixers */
+	SND_SOC_DAPM_MIXER("LOUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 0, 0,
+			&ak4671_lout1_mixer_controls[0],
+			ARRAY_SIZE(ak4671_lout1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("ROUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 1, 0,
+			&ak4671_rout1_mixer_controls[0],
+			ARRAY_SIZE(ak4671_rout1_mixer_controls)),
+	SND_SOC_DAPM_MIXER_E("LOUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT,
+			0, 0, &ak4671_lout2_mixer_controls[0],
+			ARRAY_SIZE(ak4671_lout2_mixer_controls),
+			ak4671_out2_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MIXER_E("ROUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT,
+			1, 0, &ak4671_rout2_mixer_controls[0],
+			ARRAY_SIZE(ak4671_rout2_mixer_controls),
+			ak4671_out2_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MIXER("LOUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 0, 0,
+			&ak4671_lout3_mixer_controls[0],
+			ARRAY_SIZE(ak4671_lout3_mixer_controls)),
+	SND_SOC_DAPM_MIXER("ROUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 1, 0,
+			&ak4671_rout3_mixer_controls[0],
+			ARRAY_SIZE(ak4671_rout3_mixer_controls)),
+
+	/* Input MUXs */
+	SND_SOC_DAPM_MUX("LIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 2, 0,
+			&ak4671_lin_mux_control),
+	SND_SOC_DAPM_MUX("RIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 3, 0,
+			&ak4671_rin_mux_control),
+
+	/* Mic Power */
+	SND_SOC_DAPM_MICBIAS("Mic Bias", AK4671_AD_DA_POWER_MANAGEMENT, 1, 0),
+
+	/* Supply */
+	SND_SOC_DAPM_SUPPLY("PMPLL", AK4671_PLL_MODE_SELECT1, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route ak4671_intercon[] = {
+	{"DAC Left", NULL, "PMPLL"},
+	{"DAC Right", NULL, "PMPLL"},
+	{"ADC Left", NULL, "PMPLL"},
+	{"ADC Right", NULL, "PMPLL"},
+
+	/* Outputs */
+	{"LOUT1", NULL, "LOUT1 Mixer"},
+	{"ROUT1", NULL, "ROUT1 Mixer"},
+	{"LOUT2", NULL, "LOUT2 Mix Amp"},
+	{"ROUT2", NULL, "ROUT2 Mix Amp"},
+	{"LOUT3", NULL, "LOUT3 Mixer"},
+	{"ROUT3", NULL, "ROUT3 Mixer"},
+
+	{"LOUT1 Mixer", "DACL", "DAC Left"},
+	{"ROUT1 Mixer", "DACR", "DAC Right"},
+	{"LOUT2 Mixer", "DACHL", "DAC Left"},
+	{"ROUT2 Mixer", "DACHR", "DAC Right"},
+	{"LOUT2 Mix Amp", NULL, "LOUT2 Mixer"},
+	{"ROUT2 Mix Amp", NULL, "ROUT2 Mixer"},
+	{"LOUT3 Mixer", "DACSL", "DAC Left"},
+	{"ROUT3 Mixer", "DACSR", "DAC Right"},
+
+	/* Inputs */
+	{"LIN MUX", "LIN1", "LIN1"},
+	{"LIN MUX", "LIN2", "LIN2"},
+	{"LIN MUX", "LIN3", "LIN3"},
+	{"LIN MUX", "LIN4", "LIN4"},
+
+	{"RIN MUX", "RIN1", "RIN1"},
+	{"RIN MUX", "RIN2", "RIN2"},
+	{"RIN MUX", "RIN3", "RIN3"},
+	{"RIN MUX", "RIN4", "RIN4"},
+
+	{"LIN1", NULL, "Mic Bias"},
+	{"RIN1", NULL, "Mic Bias"},
+	{"LIN2", NULL, "Mic Bias"},
+	{"RIN2", NULL, "Mic Bias"},
+
+	{"ADC Left", NULL, "LIN MUX"},
+	{"ADC Right", NULL, "RIN MUX"},
+
+	/* Analog Loops */
+	{"LIN1 Mixing Circuit", NULL, "LIN1"},
+	{"RIN1 Mixing Circuit", NULL, "RIN1"},
+	{"LIN2 Mixing Circuit", NULL, "LIN2"},
+	{"RIN2 Mixing Circuit", NULL, "RIN2"},
+	{"LIN3 Mixing Circuit", NULL, "LIN3"},
+	{"RIN3 Mixing Circuit", NULL, "RIN3"},
+	{"LIN4 Mixing Circuit", NULL, "LIN4"},
+	{"RIN4 Mixing Circuit", NULL, "RIN4"},
+
+	{"LOUT1 Mixer", "LINL1", "LIN1 Mixing Circuit"},
+	{"ROUT1 Mixer", "RINR1", "RIN1 Mixing Circuit"},
+	{"LOUT2 Mixer", "LINH1", "LIN1 Mixing Circuit"},
+	{"ROUT2 Mixer", "RINH1", "RIN1 Mixing Circuit"},
+	{"LOUT3 Mixer", "LINS1", "LIN1 Mixing Circuit"},
+	{"ROUT3 Mixer", "RINS1", "RIN1 Mixing Circuit"},
+
+	{"LOUT1 Mixer", "LINL2", "LIN2 Mixing Circuit"},
+	{"ROUT1 Mixer", "RINR2", "RIN2 Mixing Circuit"},
+	{"LOUT2 Mixer", "LINH2", "LIN2 Mixing Circuit"},
+	{"ROUT2 Mixer", "RINH2", "RIN2 Mixing Circuit"},
+	{"LOUT3 Mixer", "LINS2", "LIN2 Mixing Circuit"},
+	{"ROUT3 Mixer", "RINS2", "RIN2 Mixing Circuit"},
+
+	{"LOUT1 Mixer", "LINL3", "LIN3 Mixing Circuit"},
+	{"ROUT1 Mixer", "RINR3", "RIN3 Mixing Circuit"},
+	{"LOUT2 Mixer", "LINH3", "LIN3 Mixing Circuit"},
+	{"ROUT2 Mixer", "RINH3", "RIN3 Mixing Circuit"},
+	{"LOUT3 Mixer", "LINS3", "LIN3 Mixing Circuit"},
+	{"ROUT3 Mixer", "RINS3", "RIN3 Mixing Circuit"},
+
+	{"LOUT1 Mixer", "LINL4", "LIN4 Mixing Circuit"},
+	{"ROUT1 Mixer", "RINR4", "RIN4 Mixing Circuit"},
+	{"LOUT2 Mixer", "LINH4", "LIN4 Mixing Circuit"},
+	{"ROUT2 Mixer", "RINH4", "RIN4 Mixing Circuit"},
+	{"LOUT3 Mixer", "LINS4", "LIN4 Mixing Circuit"},
+	{"ROUT3 Mixer", "RINS4", "RIN4 Mixing Circuit"},
+};
+
+static int ak4671_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 fs;
+
+	fs = snd_soc_component_read32(component, AK4671_PLL_MODE_SELECT0);
+	fs &= ~AK4671_FS;
+
+	switch (params_rate(params)) {
+	case 8000:
+		fs |= AK4671_FS_8KHZ;
+		break;
+	case 12000:
+		fs |= AK4671_FS_12KHZ;
+		break;
+	case 16000:
+		fs |= AK4671_FS_16KHZ;
+		break;
+	case 24000:
+		fs |= AK4671_FS_24KHZ;
+		break;
+	case 11025:
+		fs |= AK4671_FS_11_025KHZ;
+		break;
+	case 22050:
+		fs |= AK4671_FS_22_05KHZ;
+		break;
+	case 32000:
+		fs |= AK4671_FS_32KHZ;
+		break;
+	case 44100:
+		fs |= AK4671_FS_44_1KHZ;
+		break;
+	case 48000:
+		fs |= AK4671_FS_48KHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, AK4671_PLL_MODE_SELECT0, fs);
+
+	return 0;
+}
+
+static int ak4671_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+		unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 pll;
+
+	pll = snd_soc_component_read32(component, AK4671_PLL_MODE_SELECT0);
+	pll &= ~AK4671_PLL;
+
+	switch (freq) {
+	case 11289600:
+		pll |= AK4671_PLL_11_2896MHZ;
+		break;
+	case 12000000:
+		pll |= AK4671_PLL_12MHZ;
+		break;
+	case 12288000:
+		pll |= AK4671_PLL_12_288MHZ;
+		break;
+	case 13000000:
+		pll |= AK4671_PLL_13MHZ;
+		break;
+	case 13500000:
+		pll |= AK4671_PLL_13_5MHZ;
+		break;
+	case 19200000:
+		pll |= AK4671_PLL_19_2MHZ;
+		break;
+	case 24000000:
+		pll |= AK4671_PLL_24MHZ;
+		break;
+	case 26000000:
+		pll |= AK4671_PLL_26MHZ;
+		break;
+	case 27000000:
+		pll |= AK4671_PLL_27MHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, AK4671_PLL_MODE_SELECT0, pll);
+
+	return 0;
+}
+
+static int ak4671_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 mode;
+	u8 format;
+
+	/* set master/slave audio interface */
+	mode = snd_soc_component_read32(component, AK4671_PLL_MODE_SELECT1);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		mode |= AK4671_M_S;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		mode &= ~(AK4671_M_S);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	format = snd_soc_component_read32(component, AK4671_FORMAT_SELECT);
+	format &= ~AK4671_DIF;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		format |= AK4671_DIF_I2S_MODE;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		format |= AK4671_DIF_MSB_MODE;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		format |= AK4671_DIF_DSP_MODE;
+		format |= AK4671_BCKP;
+		format |= AK4671_MSBS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set mode and format */
+	snd_soc_component_write(component, AK4671_PLL_MODE_SELECT1, mode);
+	snd_soc_component_write(component, AK4671_FORMAT_SELECT, format);
+
+	return 0;
+}
+
+static int ak4671_set_bias_level(struct snd_soc_component *component,
+		enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_component_update_bits(component, AK4671_AD_DA_POWER_MANAGEMENT,
+				    AK4671_PMVCM, AK4671_PMVCM);
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_write(component, AK4671_AD_DA_POWER_MANAGEMENT, 0x00);
+		break;
+	}
+	return 0;
+}
+
+#define AK4671_RATES		(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+				SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+				SNDRV_PCM_RATE_48000)
+
+#define AK4671_FORMATS		SNDRV_PCM_FMTBIT_S16_LE
+
+static const struct snd_soc_dai_ops ak4671_dai_ops = {
+	.hw_params	= ak4671_hw_params,
+	.set_sysclk	= ak4671_set_dai_sysclk,
+	.set_fmt	= ak4671_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver ak4671_dai = {
+	.name = "ak4671-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = AK4671_RATES,
+		.formats = AK4671_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = AK4671_RATES,
+		.formats = AK4671_FORMATS,},
+	.ops = &ak4671_dai_ops,
+};
+
+static const struct snd_soc_component_driver soc_component_dev_ak4671 = {
+	.set_bias_level		= ak4671_set_bias_level,
+	.controls		= ak4671_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4671_snd_controls),
+	.dapm_widgets		= ak4671_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4671_dapm_widgets),
+	.dapm_routes		= ak4671_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(ak4671_intercon),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config ak4671_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = AK4671_SAR_ADC_CONTROL,
+	.reg_defaults = ak4671_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ak4671_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int ak4671_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	int ret;
+
+	regmap = devm_regmap_init_i2c(client, &ak4671_regmap);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		dev_err(&client->dev, "Failed to create regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&client->dev,
+			&soc_component_dev_ak4671, &ak4671_dai, 1);
+	return ret;
+}
+
+static const struct i2c_device_id ak4671_i2c_id[] = {
+	{ "ak4671", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id);
+
+static struct i2c_driver ak4671_i2c_driver = {
+	.driver = {
+		.name = "ak4671-codec",
+	},
+	.probe = ak4671_i2c_probe,
+	.id_table = ak4671_i2c_id,
+};
+
+module_i2c_driver(ak4671_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC AK4671 codec driver");
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h
new file mode 100644
index 0000000..394a34d
--- /dev/null
+++ b/sound/soc/codecs/ak4671.h
@@ -0,0 +1,151 @@
+/*
+ * ak4671.h  --  audio driver for AK4671
+ *
+ * Copyright (C) 2009 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef _AK4671_H
+#define _AK4671_H
+
+#define AK4671_AD_DA_POWER_MANAGEMENT		0x00
+#define AK4671_PLL_MODE_SELECT0			0x01
+#define AK4671_PLL_MODE_SELECT1			0x02
+#define AK4671_FORMAT_SELECT			0x03
+#define AK4671_MIC_SIGNAL_SELECT		0x04
+#define AK4671_MIC_AMP_GAIN			0x05
+#define AK4671_MIXING_POWER_MANAGEMENT0		0x06
+#define AK4671_MIXING_POWER_MANAGEMENT1		0x07
+#define AK4671_OUTPUT_VOLUME_CONTROL		0x08
+#define AK4671_LOUT1_SIGNAL_SELECT		0x09
+#define AK4671_ROUT1_SIGNAL_SELECT		0x0a
+#define AK4671_LOUT2_SIGNAL_SELECT		0x0b
+#define AK4671_ROUT2_SIGNAL_SELECT		0x0c
+#define AK4671_LOUT3_SIGNAL_SELECT		0x0d
+#define AK4671_ROUT3_SIGNAL_SELECT		0x0e
+#define AK4671_LOUT1_POWER_MANAGERMENT		0x0f
+#define AK4671_LOUT2_POWER_MANAGERMENT		0x10
+#define AK4671_LOUT3_POWER_MANAGERMENT		0x11
+#define AK4671_LCH_INPUT_VOLUME_CONTROL		0x12
+#define AK4671_RCH_INPUT_VOLUME_CONTROL		0x13
+#define AK4671_ALC_REFERENCE_SELECT		0x14
+#define AK4671_DIGITAL_MIXING_CONTROL		0x15
+#define AK4671_ALC_TIMER_SELECT			0x16
+#define AK4671_ALC_MODE_CONTROL			0x17
+#define AK4671_MODE_CONTROL1			0x18
+#define AK4671_MODE_CONTROL2			0x19
+#define AK4671_LCH_OUTPUT_VOLUME_CONTROL	0x1a
+#define AK4671_RCH_OUTPUT_VOLUME_CONTROL	0x1b
+#define AK4671_SIDETONE_A_CONTROL		0x1c
+#define AK4671_DIGITAL_FILTER_SELECT		0x1d
+#define AK4671_FIL3_COEFFICIENT0		0x1e
+#define AK4671_FIL3_COEFFICIENT1		0x1f
+#define AK4671_FIL3_COEFFICIENT2		0x20
+#define AK4671_FIL3_COEFFICIENT3		0x21
+#define AK4671_EQ_COEFFICIENT0			0x22
+#define AK4671_EQ_COEFFICIENT1			0x23
+#define AK4671_EQ_COEFFICIENT2			0x24
+#define AK4671_EQ_COEFFICIENT3			0x25
+#define AK4671_EQ_COEFFICIENT4			0x26
+#define AK4671_EQ_COEFFICIENT5			0x27
+#define AK4671_FIL1_COEFFICIENT0		0x28
+#define AK4671_FIL1_COEFFICIENT1		0x29
+#define AK4671_FIL1_COEFFICIENT2		0x2a
+#define AK4671_FIL1_COEFFICIENT3		0x2b
+#define AK4671_FIL2_COEFFICIENT0		0x2c
+#define AK4671_FIL2_COEFFICIENT1		0x2d
+#define AK4671_FIL2_COEFFICIENT2		0x2e
+#define AK4671_FIL2_COEFFICIENT3		0x2f
+#define AK4671_DIGITAL_FILTER_SELECT2		0x30
+#define AK4671_E1_COEFFICIENT0			0x32
+#define AK4671_E1_COEFFICIENT1			0x33
+#define AK4671_E1_COEFFICIENT2			0x34
+#define AK4671_E1_COEFFICIENT3			0x35
+#define AK4671_E1_COEFFICIENT4			0x36
+#define AK4671_E1_COEFFICIENT5			0x37
+#define AK4671_E2_COEFFICIENT0			0x38
+#define AK4671_E2_COEFFICIENT1			0x39
+#define AK4671_E2_COEFFICIENT2			0x3a
+#define AK4671_E2_COEFFICIENT3			0x3b
+#define AK4671_E2_COEFFICIENT4			0x3c
+#define AK4671_E2_COEFFICIENT5			0x3d
+#define AK4671_E3_COEFFICIENT0			0x3e
+#define AK4671_E3_COEFFICIENT1			0x3f
+#define AK4671_E3_COEFFICIENT2			0x40
+#define AK4671_E3_COEFFICIENT3			0x41
+#define AK4671_E3_COEFFICIENT4			0x42
+#define AK4671_E3_COEFFICIENT5			0x43
+#define AK4671_E4_COEFFICIENT0			0x44
+#define AK4671_E4_COEFFICIENT1			0x45
+#define AK4671_E4_COEFFICIENT2			0x46
+#define AK4671_E4_COEFFICIENT3			0x47
+#define AK4671_E4_COEFFICIENT4			0x48
+#define AK4671_E4_COEFFICIENT5			0x49
+#define AK4671_E5_COEFFICIENT0			0x4a
+#define AK4671_E5_COEFFICIENT1			0x4b
+#define AK4671_E5_COEFFICIENT2			0x4c
+#define AK4671_E5_COEFFICIENT3			0x4d
+#define AK4671_E5_COEFFICIENT4			0x4e
+#define AK4671_E5_COEFFICIENT5			0x4f
+#define AK4671_EQ_CONTROL_250HZ_100HZ		0x50
+#define AK4671_EQ_CONTROL_3500HZ_1KHZ		0x51
+#define AK4671_EQ_CONTRO_10KHZ			0x52
+#define AK4671_PCM_IF_CONTROL0			0x53
+#define AK4671_PCM_IF_CONTROL1			0x54
+#define AK4671_PCM_IF_CONTROL2			0x55
+#define AK4671_DIGITAL_VOLUME_B_CONTROL		0x56
+#define AK4671_DIGITAL_VOLUME_C_CONTROL		0x57
+#define AK4671_SIDETONE_VOLUME_CONTROL		0x58
+#define AK4671_DIGITAL_MIXING_CONTROL2		0x59
+#define AK4671_SAR_ADC_CONTROL			0x5a
+
+/* Bitfield Definitions */
+
+/* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */
+#define AK4671_PMVCM				0x01
+
+/* AK4671_PLL_MODE_SELECT0 (0x01) Fields */
+#define AK4671_PLL				0x0f
+#define AK4671_PLL_11_2896MHZ			(4 << 0)
+#define AK4671_PLL_12_288MHZ			(5 << 0)
+#define AK4671_PLL_12MHZ			(6 << 0)
+#define AK4671_PLL_24MHZ			(7 << 0)
+#define AK4671_PLL_19_2MHZ			(8 << 0)
+#define AK4671_PLL_13_5MHZ			(12 << 0)
+#define AK4671_PLL_27MHZ			(13 << 0)
+#define AK4671_PLL_13MHZ			(14 << 0)
+#define AK4671_PLL_26MHZ			(15 << 0)
+#define AK4671_FS				0xf0
+#define AK4671_FS_8KHZ				(0 << 4)
+#define AK4671_FS_12KHZ				(1 << 4)
+#define AK4671_FS_16KHZ				(2 << 4)
+#define AK4671_FS_24KHZ				(3 << 4)
+#define AK4671_FS_11_025KHZ			(5 << 4)
+#define AK4671_FS_22_05KHZ			(7 << 4)
+#define AK4671_FS_32KHZ				(10 << 4)
+#define AK4671_FS_48KHZ				(11 << 4)
+#define AK4671_FS_44_1KHZ			(15 << 4)
+
+/* AK4671_PLL_MODE_SELECT1 (0x02) Fields */
+#define AK4671_PMPLL				0x01
+#define AK4671_M_S				0x02
+
+/* AK4671_FORMAT_SELECT (0x03) Fields */
+#define AK4671_DIF				0x03
+#define AK4671_DIF_DSP_MODE			(0 << 0)
+#define AK4671_DIF_MSB_MODE			(2 << 0)
+#define AK4671_DIF_I2S_MODE			(3 << 0)
+#define AK4671_BCKP				0x04
+#define AK4671_MSBS				0x08
+#define AK4671_SDOD				0x10
+
+/* AK4671_LOUT2_POWER_MANAGEMENT (0x10) Fields */
+#define AK4671_MUTEN				0x04
+
+#endif
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c
new file mode 100644
index 0000000..d212960
--- /dev/null
+++ b/sound/soc/codecs/ak5386.c
@@ -0,0 +1,212 @@
+/*
+ * ALSA SoC driver for
+ *    Asahi Kasei AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC
+ *
+ * (c) 2013 Daniel Mack <zonque@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+
+static const char * const supply_names[] = {
+	"va", "vd"
+};
+
+struct ak5386_priv {
+	int reset_gpio;
+	struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+};
+
+static const struct snd_soc_dapm_widget ak5386_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AINL"),
+SND_SOC_DAPM_INPUT("AINR"),
+};
+
+static const struct snd_soc_dapm_route ak5386_dapm_routes[] = {
+	{ "Capture", NULL, "AINL" },
+	{ "Capture", NULL, "AINR" },
+};
+
+static int ak5386_soc_probe(struct snd_soc_component *component)
+{
+	struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
+	return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
+}
+
+static void ak5386_soc_remove(struct snd_soc_component *component)
+{
+	struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
+	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
+}
+
+#ifdef CONFIG_PM
+static int ak5386_soc_suspend(struct snd_soc_component *component)
+{
+	struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
+	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
+	return 0;
+}
+
+static int ak5386_soc_resume(struct snd_soc_component *component)
+{
+	struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
+	return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
+}
+#else
+#define ak5386_soc_suspend	NULL
+#define ak5386_soc_resume	NULL
+#endif /* CONFIG_PM */
+
+static const struct snd_soc_component_driver soc_component_ak5386 = {
+	.probe			= ak5386_soc_probe,
+	.remove			= ak5386_soc_remove,
+	.suspend		= ak5386_soc_suspend,
+	.resume			= ak5386_soc_resume,
+	.dapm_widgets		= ak5386_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak5386_dapm_widgets),
+	.dapm_routes		= ak5386_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ak5386_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int format)
+{
+	struct snd_soc_component *component = codec_dai->component;
+
+	format &= SND_SOC_DAIFMT_FORMAT_MASK;
+	if (format != SND_SOC_DAIFMT_LEFT_J &&
+	    format != SND_SOC_DAIFMT_I2S) {
+		dev_err(component->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ak5386_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
+
+	/*
+	 * From the datasheet:
+	 *
+	 * All external clocks (MCLK, SCLK and LRCK) must be present unless
+	 * PDN pin = “L”. If these clocks are not provided, the AK5386 may
+	 * draw excess current due to its use of internal dynamically
+	 * refreshed logic. If the external clocks are not present, place
+	 * the AK5386 in power-down mode (PDN pin = “L”).
+	 */
+
+	if (gpio_is_valid(priv->reset_gpio))
+		gpio_set_value(priv->reset_gpio, 1);
+
+	return 0;
+}
+
+static int ak5386_hw_free(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
+
+	if (gpio_is_valid(priv->reset_gpio))
+		gpio_set_value(priv->reset_gpio, 0);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops ak5386_dai_ops = {
+	.set_fmt	= ak5386_set_dai_fmt,
+	.hw_params	= ak5386_hw_params,
+	.hw_free	= ak5386_hw_free,
+};
+
+static struct snd_soc_dai_driver ak5386_dai = {
+	.name		= "ak5386-hifi",
+	.capture	= {
+		.stream_name	= "Capture",
+		.channels_min	= 1,
+		.channels_max	= 2,
+		.rates		= SNDRV_PCM_RATE_8000_192000,
+		.formats	= SNDRV_PCM_FMTBIT_S8     |
+				  SNDRV_PCM_FMTBIT_S16_LE |
+				  SNDRV_PCM_FMTBIT_S24_LE |
+				  SNDRV_PCM_FMTBIT_S24_3LE,
+	},
+	.ops	= &ak5386_dai_ops,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id ak5386_dt_ids[] = {
+	{ .compatible = "asahi-kasei,ak5386", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ak5386_dt_ids);
+#endif
+
+static int ak5386_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ak5386_priv *priv;
+	int ret, i;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->reset_gpio = -EINVAL;
+	dev_set_drvdata(dev, priv);
+
+	for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+		priv->supplies[i].supply = supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
+				      priv->supplies);
+	if (ret < 0)
+		return ret;
+
+	if (of_match_device(of_match_ptr(ak5386_dt_ids), dev))
+		priv->reset_gpio = of_get_named_gpio(dev->of_node,
+						      "reset-gpio", 0);
+
+	if (gpio_is_valid(priv->reset_gpio))
+		if (devm_gpio_request_one(dev, priv->reset_gpio,
+					  GPIOF_OUT_INIT_LOW,
+					  "AK5386 Reset"))
+			priv->reset_gpio = -EINVAL;
+
+	return devm_snd_soc_register_component(dev, &soc_component_ak5386,
+				      &ak5386_dai, 1);
+}
+
+static struct platform_driver ak5386_driver = {
+	.probe		= ak5386_probe,
+	.driver		= {
+		.name	= "ak5386",
+		.of_match_table = of_match_ptr(ak5386_dt_ids),
+	},
+};
+
+module_platform_driver(ak5386_driver);
+
+MODULE_DESCRIPTION("ASoC driver for AK5386 ADC");
+MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c
new file mode 100644
index 0000000..448bb90
--- /dev/null
+++ b/sound/soc/codecs/ak5558.c
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Audio driver for AK5558 ADC
+//
+// Copyright (C) 2015 Asahi Kasei Microdevices Corporation
+// Copyright 2018 NXP
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "ak5558.h"
+
+/* AK5558 Codec Private Data */
+struct ak5558_priv {
+	struct snd_soc_component component;
+	struct regmap *regmap;
+	struct i2c_client *i2c;
+	struct gpio_desc *reset_gpiod; /* Reset & Power down GPIO */
+	int slots;
+	int slot_width;
+};
+
+/* ak5558 register cache & default register settings */
+static const struct reg_default ak5558_reg[] = {
+	{ 0x0, 0xFF },	/*	0x00	AK5558_00_POWER_MANAGEMENT1	*/
+	{ 0x1, 0x01 },	/*	0x01	AK5558_01_POWER_MANAGEMENT2	*/
+	{ 0x2, 0x01 },	/*	0x02	AK5558_02_CONTROL1		*/
+	{ 0x3, 0x00 },	/*	0x03	AK5558_03_CONTROL2		*/
+	{ 0x4, 0x00 },	/*	0x04	AK5558_04_CONTROL3		*/
+	{ 0x5, 0x00 }	/*	0x05	AK5558_05_DSD			*/
+};
+
+static const char * const mono_texts[] = {
+	"8 Slot", "2 Slot", "4 Slot", "1 Slot",
+};
+
+static const struct soc_enum ak5558_mono_enum[] = {
+	SOC_ENUM_SINGLE(AK5558_01_POWER_MANAGEMENT2, 1,
+			ARRAY_SIZE(mono_texts), mono_texts),
+};
+
+static const char * const digfil_texts[] = {
+	"Sharp Roll-Off", "Show Roll-Off",
+	"Short Delay Sharp Roll-Off", "Short Delay Show Roll-Off",
+};
+
+static const struct soc_enum ak5558_adcset_enum[] = {
+	SOC_ENUM_SINGLE(AK5558_04_CONTROL3, 0,
+			ARRAY_SIZE(digfil_texts), digfil_texts),
+};
+
+static const struct snd_kcontrol_new ak5558_snd_controls[] = {
+	SOC_ENUM("AK5558 Monaural Mode", ak5558_mono_enum[0]),
+	SOC_ENUM("AK5558 Digital Filter", ak5558_adcset_enum[0]),
+};
+
+static const struct snd_soc_dapm_widget ak5558_dapm_widgets[] = {
+	/* Analog Input */
+	SND_SOC_DAPM_INPUT("AIN1"),
+	SND_SOC_DAPM_INPUT("AIN2"),
+	SND_SOC_DAPM_INPUT("AIN3"),
+	SND_SOC_DAPM_INPUT("AIN4"),
+	SND_SOC_DAPM_INPUT("AIN5"),
+	SND_SOC_DAPM_INPUT("AIN6"),
+	SND_SOC_DAPM_INPUT("AIN7"),
+	SND_SOC_DAPM_INPUT("AIN8"),
+
+	SND_SOC_DAPM_ADC("ADC Ch1", NULL, AK5558_00_POWER_MANAGEMENT1, 0, 0),
+	SND_SOC_DAPM_ADC("ADC Ch2", NULL, AK5558_00_POWER_MANAGEMENT1, 1, 0),
+	SND_SOC_DAPM_ADC("ADC Ch3", NULL, AK5558_00_POWER_MANAGEMENT1, 2, 0),
+	SND_SOC_DAPM_ADC("ADC Ch4", NULL, AK5558_00_POWER_MANAGEMENT1, 3, 0),
+	SND_SOC_DAPM_ADC("ADC Ch5", NULL, AK5558_00_POWER_MANAGEMENT1, 4, 0),
+	SND_SOC_DAPM_ADC("ADC Ch6", NULL, AK5558_00_POWER_MANAGEMENT1, 5, 0),
+	SND_SOC_DAPM_ADC("ADC Ch7", NULL, AK5558_00_POWER_MANAGEMENT1, 6, 0),
+	SND_SOC_DAPM_ADC("ADC Ch8", NULL, AK5558_00_POWER_MANAGEMENT1, 7, 0),
+
+	SND_SOC_DAPM_AIF_OUT("SDTO", "Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route ak5558_intercon[] = {
+	{"ADC Ch1", NULL, "AIN1"},
+	{"SDTO", NULL, "ADC Ch1"},
+
+	{"ADC Ch2", NULL, "AIN2"},
+	{"SDTO", NULL, "ADC Ch2"},
+
+	{"ADC Ch3", NULL, "AIN3"},
+	{"SDTO", NULL, "ADC Ch3"},
+
+	{"ADC Ch4", NULL, "AIN4"},
+	{"SDTO", NULL, "ADC Ch4"},
+
+	{"ADC Ch5", NULL, "AIN5"},
+	{"SDTO", NULL, "ADC Ch5"},
+
+	{"ADC Ch6", NULL, "AIN6"},
+	{"SDTO", NULL, "ADC Ch6"},
+
+	{"ADC Ch7", NULL, "AIN7"},
+	{"SDTO", NULL, "ADC Ch7"},
+
+	{"ADC Ch8", NULL, "AIN8"},
+	{"SDTO", NULL, "ADC Ch8"},
+};
+
+static int ak5558_set_mcki(struct snd_soc_component *component)
+{
+	return snd_soc_component_update_bits(component, AK5558_02_CONTROL1, AK5558_CKS,
+				   AK5558_CKS_AUTO);
+}
+
+static int ak5558_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component);
+	u8 bits;
+	int pcm_width = max(params_physical_width(params), ak5558->slot_width);
+
+	/* set master/slave audio interface */
+	bits = snd_soc_component_read32(component, AK5558_02_CONTROL1);
+	bits &= ~AK5558_BITS;
+
+	switch (pcm_width) {
+	case 16:
+		bits |= AK5558_DIF_24BIT_MODE;
+		break;
+	case 32:
+		bits |= AK5558_DIF_32BIT_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, AK5558_02_CONTROL1, AK5558_BITS, bits);
+
+	return 0;
+}
+
+static int ak5558_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 format;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	default:
+		dev_err(dai->dev, "Clock mode unsupported");
+		return -EINVAL;
+	}
+
+	/* set master/slave audio interface */
+	format = snd_soc_component_read32(component, AK5558_02_CONTROL1);
+	format &= ~AK5558_DIF;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		format |= AK5558_DIF_I2S_MODE;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		format |= AK5558_DIF_MSB_MODE;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		format |= AK5558_DIF_MSB_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, AK5558_02_CONTROL1, AK5558_DIF, format);
+
+	return 0;
+}
+
+static int ak5558_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			       unsigned int rx_mask, int slots,
+			       int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component);
+	int tdm_mode;
+
+	ak5558->slots = slots;
+	ak5558->slot_width = slot_width;
+
+	switch (slots * slot_width) {
+	case 128:
+		tdm_mode = AK5558_MODE_TDM128;
+		break;
+	case 256:
+		tdm_mode = AK5558_MODE_TDM256;
+		break;
+	case 512:
+		tdm_mode = AK5558_MODE_TDM512;
+		break;
+	default:
+		tdm_mode = AK5558_MODE_NORMAL;
+		break;
+	}
+
+	snd_soc_component_update_bits(component, AK5558_03_CONTROL2, AK5558_MODE_BITS,
+			    tdm_mode);
+	return 0;
+}
+
+#define AK5558_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE |\
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+static const unsigned int ak5558_rates[] = {
+	8000, 11025,  16000, 22050,
+	32000, 44100, 48000, 88200,
+	96000, 176400, 192000, 352800,
+	384000, 705600, 768000, 1411200,
+	2822400,
+};
+
+static const struct snd_pcm_hw_constraint_list ak5558_rate_constraints = {
+	.count = ARRAY_SIZE(ak5558_rates),
+	.list = ak5558_rates,
+};
+
+static int ak5558_startup(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE,
+					  &ak5558_rate_constraints);
+}
+
+static struct snd_soc_dai_ops ak5558_dai_ops = {
+	.startup        = ak5558_startup,
+	.hw_params	= ak5558_hw_params,
+
+	.set_fmt	= ak5558_set_dai_fmt,
+	.set_tdm_slot   = ak5558_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver ak5558_dai = {
+	.name = "ak5558-aif",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = AK5558_FORMATS,
+	},
+	.ops = &ak5558_dai_ops,
+};
+
+static void ak5558_power_off(struct ak5558_priv *ak5558)
+{
+	if (!ak5558->reset_gpiod)
+		return;
+
+	gpiod_set_value_cansleep(ak5558->reset_gpiod, 0);
+	usleep_range(1000, 2000);
+}
+
+static void ak5558_power_on(struct ak5558_priv *ak5558)
+{
+	if (!ak5558->reset_gpiod)
+		return;
+
+	gpiod_set_value_cansleep(ak5558->reset_gpiod, 1);
+	usleep_range(1000, 2000);
+}
+
+static int ak5558_probe(struct snd_soc_component *component)
+{
+	struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component);
+
+	ak5558_power_on(ak5558);
+	return ak5558_set_mcki(component);
+}
+
+static void ak5558_remove(struct snd_soc_component *component)
+{
+	struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component);
+
+	ak5558_power_off(ak5558);
+}
+
+static int __maybe_unused ak5558_runtime_suspend(struct device *dev)
+{
+	struct ak5558_priv *ak5558 = dev_get_drvdata(dev);
+
+	regcache_cache_only(ak5558->regmap, true);
+	ak5558_power_off(ak5558);
+
+	return 0;
+}
+
+static int __maybe_unused ak5558_runtime_resume(struct device *dev)
+{
+	struct ak5558_priv *ak5558 = dev_get_drvdata(dev);
+
+	ak5558_power_off(ak5558);
+	ak5558_power_on(ak5558);
+
+	regcache_cache_only(ak5558->regmap, false);
+	regcache_mark_dirty(ak5558->regmap);
+
+	return regcache_sync(ak5558->regmap);
+}
+
+static const struct dev_pm_ops ak5558_pm = {
+	SET_RUNTIME_PM_OPS(ak5558_runtime_suspend, ak5558_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static const struct snd_soc_component_driver soc_codec_dev_ak5558 = {
+	.probe			= ak5558_probe,
+	.remove			= ak5558_remove,
+	.controls		= ak5558_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak5558_snd_controls),
+	.dapm_widgets		= ak5558_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak5558_dapm_widgets),
+	.dapm_routes		= ak5558_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(ak5558_intercon),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config ak5558_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = AK5558_05_DSD,
+	.reg_defaults = ak5558_reg,
+	.num_reg_defaults = ARRAY_SIZE(ak5558_reg),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int ak5558_i2c_probe(struct i2c_client *i2c)
+{
+	struct ak5558_priv *ak5558;
+	int ret = 0;
+
+	ak5558 = devm_kzalloc(&i2c->dev, sizeof(*ak5558), GFP_KERNEL);
+	if (!ak5558)
+		return -ENOMEM;
+
+	ak5558->regmap = devm_regmap_init_i2c(i2c, &ak5558_regmap);
+	if (IS_ERR(ak5558->regmap))
+		return PTR_ERR(ak5558->regmap);
+
+	i2c_set_clientdata(i2c, ak5558);
+	ak5558->i2c = i2c;
+
+	ak5558->reset_gpiod = devm_gpiod_get_optional(&i2c->dev, "reset",
+						      GPIOD_OUT_LOW);
+	if (IS_ERR(ak5558->reset_gpiod))
+		return PTR_ERR(ak5558->reset_gpiod);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_codec_dev_ak5558,
+				     &ak5558_dai, 1);
+	if (ret)
+		return ret;
+
+	pm_runtime_enable(&i2c->dev);
+
+	return 0;
+}
+
+static int ak5558_i2c_remove(struct i2c_client *i2c)
+{
+	pm_runtime_disable(&i2c->dev);
+
+	return 0;
+}
+
+static const struct of_device_id ak5558_i2c_dt_ids[] = {
+	{ .compatible = "asahi-kasei,ak5558"},
+	{ }
+};
+
+static struct i2c_driver ak5558_i2c_driver = {
+	.driver = {
+		.name = "ak5558",
+		.of_match_table = of_match_ptr(ak5558_i2c_dt_ids),
+		.pm = &ak5558_pm,
+	},
+	.probe_new = ak5558_i2c_probe,
+	.remove = ak5558_i2c_remove,
+};
+
+module_i2c_driver(ak5558_i2c_driver);
+
+MODULE_AUTHOR("Junichi Wakasugi <wakasugi.jb@om.asahi-kasei.co.jp>");
+MODULE_AUTHOR("Mihai Serban <mihai.serban@nxp.com>");
+MODULE_DESCRIPTION("ASoC AK5558 ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ak5558.h b/sound/soc/codecs/ak5558.h
new file mode 100644
index 0000000..6105908
--- /dev/null
+++ b/sound/soc/codecs/ak5558.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Audio driver header for AK5558
+ *
+ * Copyright (C) 2016 Asahi Kasei Microdevices Corporation
+ * Copyright 2018 NXP
+ */
+
+#ifndef _AK5558_H
+#define _AK5558_H
+
+#define AK5558_00_POWER_MANAGEMENT1    0x00
+#define AK5558_01_POWER_MANAGEMENT2    0x01
+#define AK5558_02_CONTROL1             0x02
+#define AK5558_03_CONTROL2             0x03
+#define AK5558_04_CONTROL3             0x04
+#define AK5558_05_DSD                  0x05
+
+/* AK5558_02_CONTROL1 fields */
+#define AK5558_DIF			GENMASK(1, 1)
+#define AK5558_DIF_MSB_MODE		(0 << 1)
+#define AK5558_DIF_I2S_MODE		(1 << 1)
+
+#define AK5558_BITS			GENMASK(2, 2)
+#define AK5558_DIF_24BIT_MODE		(0 << 2)
+#define AK5558_DIF_32BIT_MODE		(1 << 2)
+
+#define AK5558_CKS			GENMASK(6, 3)
+#define AK5558_CKS_128FS_192KHZ		(0 << 3)
+#define AK5558_CKS_192FS_192KHZ		(1 << 3)
+#define AK5558_CKS_256FS_48KHZ		(2 << 3)
+#define AK5558_CKS_256FS_96KHZ		(3 << 3)
+#define AK5558_CKS_384FS_96KHZ		(4 << 3)
+#define AK5558_CKS_384FS_48KHZ		(5 << 3)
+#define AK5558_CKS_512FS_48KHZ		(6 << 3)
+#define AK5558_CKS_768FS_48KHZ		(7 << 3)
+#define AK5558_CKS_64FS_384KHZ		(8 << 3)
+#define AK5558_CKS_32FS_768KHZ		(9 << 3)
+#define AK5558_CKS_96FS_384KHZ		(10 << 3)
+#define AK5558_CKS_48FS_768KHZ		(11 << 3)
+#define AK5558_CKS_64FS_768KHZ		(12 << 3)
+#define AK5558_CKS_1024FS_16KHZ		(13 << 3)
+#define AK5558_CKS_AUTO			(15 << 3)
+
+/* AK5558_03_CONTROL2 fields */
+#define AK5558_MODE_BITS	GENMASK(6, 5)
+#define AK5558_MODE_NORMAL	(0 << 5)
+#define AK5558_MODE_TDM128	(1 << 5)
+#define AK5558_MODE_TDM256	(2 << 5)
+#define AK5558_MODE_TDM512	(3 << 5)
+
+#endif
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
new file mode 100644
index 0000000..981a329
--- /dev/null
+++ b/sound/soc/codecs/alc5623.c
@@ -0,0 +1,1095 @@
+/*
+ * alc5623.c  --  alc562[123] ALSA Soc Audio driver
+ *
+ * Copyright 2008 Realtek Microelectronics
+ * Author: flove <flove@realtek.com> Ethan <eku@marvell.com>
+ *
+ * Copyright 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ *
+ * Based on WM8753.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/alc5623.h>
+
+#include "alc5623.h"
+
+static int caps_charge = 2000;
+module_param(caps_charge, int, 0);
+MODULE_PARM_DESC(caps_charge, "ALC5623 cap charge time (msecs)");
+
+/* codec private data */
+struct alc5623_priv {
+	struct regmap *regmap;
+	u8 id;
+	unsigned int sysclk;
+	unsigned int add_ctrl;
+	unsigned int jack_det_ctrl;
+};
+
+static inline int alc5623_reset(struct snd_soc_component *component)
+{
+	return snd_soc_component_write(component, ALC5623_RESET, 0);
+}
+
+static int amp_mixer_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	/* to power-on/off class-d amp generators/speaker */
+	/* need to write to 'index-46h' register :        */
+	/* so write index num (here 0x46) to reg 0x6a     */
+	/* and then 0xffff/0 to reg 0x6c                  */
+	snd_soc_component_write(component, ALC5623_HID_CTRL_INDEX, 0x46);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_write(component, ALC5623_HID_CTRL_DATA, 0xFFFF);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_write(component, ALC5623_HID_CTRL_DATA, 0);
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * ALC5623 Controls
+ */
+
+static const DECLARE_TLV_DB_SCALE(vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(hp_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -1650, 150, 0);
+static const DECLARE_TLV_DB_RANGE(boost_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0)
+);
+static const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new alc5621_vol_snd_controls[] = {
+	SOC_DOUBLE_TLV("Speaker Playback Volume",
+			ALC5623_SPK_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+	SOC_DOUBLE("Speaker Playback Switch",
+			ALC5623_SPK_OUT_VOL, 15, 7, 1, 1),
+	SOC_DOUBLE_TLV("Headphone Playback Volume",
+			ALC5623_HP_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+	SOC_DOUBLE("Headphone Playback Switch",
+			ALC5623_HP_OUT_VOL, 15, 7, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5622_vol_snd_controls[] = {
+	SOC_DOUBLE_TLV("Speaker Playback Volume",
+			ALC5623_SPK_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+	SOC_DOUBLE("Speaker Playback Switch",
+			ALC5623_SPK_OUT_VOL, 15, 7, 1, 1),
+	SOC_DOUBLE_TLV("Line Playback Volume",
+			ALC5623_HP_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+	SOC_DOUBLE("Line Playback Switch",
+			ALC5623_HP_OUT_VOL, 15, 7, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5623_vol_snd_controls[] = {
+	SOC_DOUBLE_TLV("Line Playback Volume",
+			ALC5623_SPK_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+	SOC_DOUBLE("Line Playback Switch",
+			ALC5623_SPK_OUT_VOL, 15, 7, 1, 1),
+	SOC_DOUBLE_TLV("Headphone Playback Volume",
+			ALC5623_HP_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+	SOC_DOUBLE("Headphone Playback Switch",
+			ALC5623_HP_OUT_VOL, 15, 7, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5623_snd_controls[] = {
+	SOC_DOUBLE_TLV("Auxout Playback Volume",
+			ALC5623_MONO_AUX_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+	SOC_DOUBLE("Auxout Playback Switch",
+			ALC5623_MONO_AUX_OUT_VOL, 15, 7, 1, 1),
+	SOC_DOUBLE_TLV("PCM Playback Volume",
+			ALC5623_STEREO_DAC_VOL, 8, 0, 31, 1, vol_tlv),
+	SOC_DOUBLE_TLV("AuxI Capture Volume",
+			ALC5623_AUXIN_VOL, 8, 0, 31, 1, vol_tlv),
+	SOC_DOUBLE_TLV("LineIn Capture Volume",
+			ALC5623_LINE_IN_VOL, 8, 0, 31, 1, vol_tlv),
+	SOC_SINGLE_TLV("Mic1 Capture Volume",
+			ALC5623_MIC_VOL, 8, 31, 1, vol_tlv),
+	SOC_SINGLE_TLV("Mic2 Capture Volume",
+			ALC5623_MIC_VOL, 0, 31, 1, vol_tlv),
+	SOC_DOUBLE_TLV("Rec Capture Volume",
+			ALC5623_ADC_REC_GAIN, 7, 0, 31, 0, adc_rec_tlv),
+	SOC_SINGLE_TLV("Mic 1 Boost Volume",
+			ALC5623_MIC_CTRL, 10, 2, 0, boost_tlv),
+	SOC_SINGLE_TLV("Mic 2 Boost Volume",
+			ALC5623_MIC_CTRL, 8, 2, 0, boost_tlv),
+	SOC_SINGLE_TLV("Digital Boost Volume",
+			ALC5623_ADD_CTRL_REG, 4, 3, 0, dig_tlv),
+};
+
+/*
+ * DAPM Controls
+ */
+static const struct snd_kcontrol_new alc5623_hp_mixer_controls[] = {
+SOC_DAPM_SINGLE("LI2HP Playback Switch", ALC5623_LINE_IN_VOL, 15, 1, 1),
+SOC_DAPM_SINGLE("AUXI2HP Playback Switch", ALC5623_AUXIN_VOL, 15, 1, 1),
+SOC_DAPM_SINGLE("MIC12HP Playback Switch", ALC5623_MIC_ROUTING_CTRL, 15, 1, 1),
+SOC_DAPM_SINGLE("MIC22HP Playback Switch", ALC5623_MIC_ROUTING_CTRL, 7, 1, 1),
+SOC_DAPM_SINGLE("DAC2HP Playback Switch", ALC5623_STEREO_DAC_VOL, 15, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5623_hpl_mixer_controls[] = {
+SOC_DAPM_SINGLE("ADC2HP_L Playback Switch", ALC5623_ADC_REC_GAIN, 15, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5623_hpr_mixer_controls[] = {
+SOC_DAPM_SINGLE("ADC2HP_R Playback Switch", ALC5623_ADC_REC_GAIN, 14, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5623_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("ADC2MONO_L Playback Switch", ALC5623_ADC_REC_GAIN, 13, 1, 1),
+SOC_DAPM_SINGLE("ADC2MONO_R Playback Switch", ALC5623_ADC_REC_GAIN, 12, 1, 1),
+SOC_DAPM_SINGLE("LI2MONO Playback Switch", ALC5623_LINE_IN_VOL, 13, 1, 1),
+SOC_DAPM_SINGLE("AUXI2MONO Playback Switch", ALC5623_AUXIN_VOL, 13, 1, 1),
+SOC_DAPM_SINGLE("MIC12MONO Playback Switch", ALC5623_MIC_ROUTING_CTRL, 13, 1, 1),
+SOC_DAPM_SINGLE("MIC22MONO Playback Switch", ALC5623_MIC_ROUTING_CTRL, 5, 1, 1),
+SOC_DAPM_SINGLE("DAC2MONO Playback Switch", ALC5623_STEREO_DAC_VOL, 13, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5623_speaker_mixer_controls[] = {
+SOC_DAPM_SINGLE("LI2SPK Playback Switch", ALC5623_LINE_IN_VOL, 14, 1, 1),
+SOC_DAPM_SINGLE("AUXI2SPK Playback Switch", ALC5623_AUXIN_VOL, 14, 1, 1),
+SOC_DAPM_SINGLE("MIC12SPK Playback Switch", ALC5623_MIC_ROUTING_CTRL, 14, 1, 1),
+SOC_DAPM_SINGLE("MIC22SPK Playback Switch", ALC5623_MIC_ROUTING_CTRL, 6, 1, 1),
+SOC_DAPM_SINGLE("DAC2SPK Playback Switch", ALC5623_STEREO_DAC_VOL, 14, 1, 1),
+};
+
+/* Left Record Mixer */
+static const struct snd_kcontrol_new alc5623_captureL_mixer_controls[] = {
+SOC_DAPM_SINGLE("Mic1 Capture Switch", ALC5623_ADC_REC_MIXER, 14, 1, 1),
+SOC_DAPM_SINGLE("Mic2 Capture Switch", ALC5623_ADC_REC_MIXER, 13, 1, 1),
+SOC_DAPM_SINGLE("LineInL Capture Switch", ALC5623_ADC_REC_MIXER, 12, 1, 1),
+SOC_DAPM_SINGLE("Left AuxI Capture Switch", ALC5623_ADC_REC_MIXER, 11, 1, 1),
+SOC_DAPM_SINGLE("HPMixerL Capture Switch", ALC5623_ADC_REC_MIXER, 10, 1, 1),
+SOC_DAPM_SINGLE("SPKMixer Capture Switch", ALC5623_ADC_REC_MIXER, 9, 1, 1),
+SOC_DAPM_SINGLE("MonoMixer Capture Switch", ALC5623_ADC_REC_MIXER, 8, 1, 1),
+};
+
+/* Right Record Mixer */
+static const struct snd_kcontrol_new alc5623_captureR_mixer_controls[] = {
+SOC_DAPM_SINGLE("Mic1 Capture Switch", ALC5623_ADC_REC_MIXER, 6, 1, 1),
+SOC_DAPM_SINGLE("Mic2 Capture Switch", ALC5623_ADC_REC_MIXER, 5, 1, 1),
+SOC_DAPM_SINGLE("LineInR Capture Switch", ALC5623_ADC_REC_MIXER, 4, 1, 1),
+SOC_DAPM_SINGLE("Right AuxI Capture Switch", ALC5623_ADC_REC_MIXER, 3, 1, 1),
+SOC_DAPM_SINGLE("HPMixerR Capture Switch", ALC5623_ADC_REC_MIXER, 2, 1, 1),
+SOC_DAPM_SINGLE("SPKMixer Capture Switch", ALC5623_ADC_REC_MIXER, 1, 1, 1),
+SOC_DAPM_SINGLE("MonoMixer Capture Switch", ALC5623_ADC_REC_MIXER, 0, 1, 1),
+};
+
+static const char *alc5623_spk_n_sour_sel[] = {
+		"RN/-R", "RP/+R", "LN/-R", "Vmid" };
+static const char *alc5623_hpl_out_input_sel[] = {
+		"Vmid", "HP Left Mix"};
+static const char *alc5623_hpr_out_input_sel[] = {
+		"Vmid", "HP Right Mix"};
+static const char *alc5623_spkout_input_sel[] = {
+		"Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"};
+static const char *alc5623_aux_out_input_sel[] = {
+		"Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"};
+
+/* auxout output mux */
+static SOC_ENUM_SINGLE_DECL(alc5623_aux_out_input_enum,
+			    ALC5623_OUTPUT_MIXER_CTRL, 6,
+			    alc5623_aux_out_input_sel);
+static const struct snd_kcontrol_new alc5623_auxout_mux_controls =
+SOC_DAPM_ENUM("Route", alc5623_aux_out_input_enum);
+
+/* speaker output mux */
+static SOC_ENUM_SINGLE_DECL(alc5623_spkout_input_enum,
+			    ALC5623_OUTPUT_MIXER_CTRL, 10,
+			    alc5623_spkout_input_sel);
+static const struct snd_kcontrol_new alc5623_spkout_mux_controls =
+SOC_DAPM_ENUM("Route", alc5623_spkout_input_enum);
+
+/* headphone left output mux */
+static SOC_ENUM_SINGLE_DECL(alc5623_hpl_out_input_enum,
+			    ALC5623_OUTPUT_MIXER_CTRL, 9,
+			    alc5623_hpl_out_input_sel);
+static const struct snd_kcontrol_new alc5623_hpl_out_mux_controls =
+SOC_DAPM_ENUM("Route", alc5623_hpl_out_input_enum);
+
+/* headphone right output mux */
+static SOC_ENUM_SINGLE_DECL(alc5623_hpr_out_input_enum,
+			    ALC5623_OUTPUT_MIXER_CTRL, 8,
+			    alc5623_hpr_out_input_sel);
+static const struct snd_kcontrol_new alc5623_hpr_out_mux_controls =
+SOC_DAPM_ENUM("Route", alc5623_hpr_out_input_enum);
+
+/* speaker output N select */
+static SOC_ENUM_SINGLE_DECL(alc5623_spk_n_sour_enum,
+			    ALC5623_OUTPUT_MIXER_CTRL, 14,
+			    alc5623_spk_n_sour_sel);
+static const struct snd_kcontrol_new alc5623_spkoutn_mux_controls =
+SOC_DAPM_ENUM("Route", alc5623_spk_n_sour_enum);
+
+static const struct snd_soc_dapm_widget alc5623_dapm_widgets[] = {
+/* Muxes */
+SND_SOC_DAPM_MUX("AuxOut Mux", SND_SOC_NOPM, 0, 0,
+	&alc5623_auxout_mux_controls),
+SND_SOC_DAPM_MUX("SpeakerOut Mux", SND_SOC_NOPM, 0, 0,
+	&alc5623_spkout_mux_controls),
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0,
+	&alc5623_hpl_out_mux_controls),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0,
+	&alc5623_hpr_out_mux_controls),
+SND_SOC_DAPM_MUX("SpeakerOut N Mux", SND_SOC_NOPM, 0, 0,
+	&alc5623_spkoutn_mux_controls),
+
+/* output mixers */
+SND_SOC_DAPM_MIXER("HP Mix", SND_SOC_NOPM, 0, 0,
+	&alc5623_hp_mixer_controls[0],
+	ARRAY_SIZE(alc5623_hp_mixer_controls)),
+SND_SOC_DAPM_MIXER("HPR Mix", ALC5623_PWR_MANAG_ADD2, 4, 0,
+	&alc5623_hpr_mixer_controls[0],
+	ARRAY_SIZE(alc5623_hpr_mixer_controls)),
+SND_SOC_DAPM_MIXER("HPL Mix", ALC5623_PWR_MANAG_ADD2, 5, 0,
+	&alc5623_hpl_mixer_controls[0],
+	ARRAY_SIZE(alc5623_hpl_mixer_controls)),
+SND_SOC_DAPM_MIXER("HPOut Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Mono Mix", ALC5623_PWR_MANAG_ADD2, 2, 0,
+	&alc5623_mono_mixer_controls[0],
+	ARRAY_SIZE(alc5623_mono_mixer_controls)),
+SND_SOC_DAPM_MIXER("Speaker Mix", ALC5623_PWR_MANAG_ADD2, 3, 0,
+	&alc5623_speaker_mixer_controls[0],
+	ARRAY_SIZE(alc5623_speaker_mixer_controls)),
+
+/* input mixers */
+SND_SOC_DAPM_MIXER("Left Capture Mix", ALC5623_PWR_MANAG_ADD2, 1, 0,
+	&alc5623_captureL_mixer_controls[0],
+	ARRAY_SIZE(alc5623_captureL_mixer_controls)),
+SND_SOC_DAPM_MIXER("Right Capture Mix", ALC5623_PWR_MANAG_ADD2, 0, 0,
+	&alc5623_captureR_mixer_controls[0],
+	ARRAY_SIZE(alc5623_captureR_mixer_controls)),
+
+SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback",
+	ALC5623_PWR_MANAG_ADD2, 9, 0),
+SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback",
+	ALC5623_PWR_MANAG_ADD2, 8, 0),
+SND_SOC_DAPM_MIXER("I2S Mix", ALC5623_PWR_MANAG_ADD1, 15, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("AuxI Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Line Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture",
+	ALC5623_PWR_MANAG_ADD2, 7, 0),
+SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture",
+	ALC5623_PWR_MANAG_ADD2, 6, 0),
+SND_SOC_DAPM_PGA("Left Headphone", ALC5623_PWR_MANAG_ADD3, 10, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Headphone", ALC5623_PWR_MANAG_ADD3, 9, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SpeakerOut", ALC5623_PWR_MANAG_ADD3, 12, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Left AuxOut", ALC5623_PWR_MANAG_ADD3, 14, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right AuxOut", ALC5623_PWR_MANAG_ADD3, 13, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Left LineIn", ALC5623_PWR_MANAG_ADD3, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right LineIn", ALC5623_PWR_MANAG_ADD3, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Left AuxI", ALC5623_PWR_MANAG_ADD3, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right AuxI", ALC5623_PWR_MANAG_ADD3, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC1 PGA", ALC5623_PWR_MANAG_ADD3, 3, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC2 PGA", ALC5623_PWR_MANAG_ADD3, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC1 Pre Amp", ALC5623_PWR_MANAG_ADD3, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC2 Pre Amp", ALC5623_PWR_MANAG_ADD3, 0, 0, NULL, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias1", ALC5623_PWR_MANAG_ADD1, 11, 0),
+
+SND_SOC_DAPM_OUTPUT("AUXOUTL"),
+SND_SOC_DAPM_OUTPUT("AUXOUTR"),
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("HPR"),
+SND_SOC_DAPM_OUTPUT("SPKOUT"),
+SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+SND_SOC_DAPM_INPUT("LINEINL"),
+SND_SOC_DAPM_INPUT("LINEINR"),
+SND_SOC_DAPM_INPUT("AUXINL"),
+SND_SOC_DAPM_INPUT("AUXINR"),
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2"),
+SND_SOC_DAPM_VMID("Vmid"),
+};
+
+static const char *alc5623_amp_names[] = {"AB Amp", "D Amp"};
+static SOC_ENUM_SINGLE_DECL(alc5623_amp_enum,
+			    ALC5623_OUTPUT_MIXER_CTRL, 13,
+			    alc5623_amp_names);
+static const struct snd_kcontrol_new alc5623_amp_mux_controls =
+	SOC_DAPM_ENUM("Route", alc5623_amp_enum);
+
+static const struct snd_soc_dapm_widget alc5623_dapm_amp_widgets[] = {
+SND_SOC_DAPM_PGA_E("D Amp", ALC5623_PWR_MANAG_ADD2, 14, 0, NULL, 0,
+	amp_mixer_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_PGA("AB Amp", ALC5623_PWR_MANAG_ADD2, 15, 0, NULL, 0),
+SND_SOC_DAPM_MUX("AB-D Amp Mux", SND_SOC_NOPM, 0, 0,
+	&alc5623_amp_mux_controls),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	/* virtual mixer - mixes left & right channels */
+	{"I2S Mix", NULL,				"Left DAC"},
+	{"I2S Mix", NULL,				"Right DAC"},
+	{"Line Mix", NULL,				"Right LineIn"},
+	{"Line Mix", NULL,				"Left LineIn"},
+	{"AuxI Mix", NULL,				"Left AuxI"},
+	{"AuxI Mix", NULL,				"Right AuxI"},
+	{"AUXOUTL", NULL,				"Left AuxOut"},
+	{"AUXOUTR", NULL,				"Right AuxOut"},
+
+	/* HP mixer */
+	{"HPL Mix", "ADC2HP_L Playback Switch",		"Left Capture Mix"},
+	{"HPL Mix", NULL,				"HP Mix"},
+	{"HPR Mix", "ADC2HP_R Playback Switch",		"Right Capture Mix"},
+	{"HPR Mix", NULL,				"HP Mix"},
+	{"HP Mix", "LI2HP Playback Switch",		"Line Mix"},
+	{"HP Mix", "AUXI2HP Playback Switch",		"AuxI Mix"},
+	{"HP Mix", "MIC12HP Playback Switch",		"MIC1 PGA"},
+	{"HP Mix", "MIC22HP Playback Switch",		"MIC2 PGA"},
+	{"HP Mix", "DAC2HP Playback Switch",		"I2S Mix"},
+
+	/* speaker mixer */
+	{"Speaker Mix", "LI2SPK Playback Switch",	"Line Mix"},
+	{"Speaker Mix", "AUXI2SPK Playback Switch",	"AuxI Mix"},
+	{"Speaker Mix", "MIC12SPK Playback Switch",	"MIC1 PGA"},
+	{"Speaker Mix", "MIC22SPK Playback Switch",	"MIC2 PGA"},
+	{"Speaker Mix", "DAC2SPK Playback Switch",	"I2S Mix"},
+
+	/* mono mixer */
+	{"Mono Mix", "ADC2MONO_L Playback Switch",	"Left Capture Mix"},
+	{"Mono Mix", "ADC2MONO_R Playback Switch",	"Right Capture Mix"},
+	{"Mono Mix", "LI2MONO Playback Switch",		"Line Mix"},
+	{"Mono Mix", "AUXI2MONO Playback Switch",	"AuxI Mix"},
+	{"Mono Mix", "MIC12MONO Playback Switch",	"MIC1 PGA"},
+	{"Mono Mix", "MIC22MONO Playback Switch",	"MIC2 PGA"},
+	{"Mono Mix", "DAC2MONO Playback Switch",	"I2S Mix"},
+
+	/* Left record mixer */
+	{"Left Capture Mix", "LineInL Capture Switch",	"LINEINL"},
+	{"Left Capture Mix", "Left AuxI Capture Switch", "AUXINL"},
+	{"Left Capture Mix", "Mic1 Capture Switch",	"MIC1 Pre Amp"},
+	{"Left Capture Mix", "Mic2 Capture Switch",	"MIC2 Pre Amp"},
+	{"Left Capture Mix", "HPMixerL Capture Switch", "HPL Mix"},
+	{"Left Capture Mix", "SPKMixer Capture Switch", "Speaker Mix"},
+	{"Left Capture Mix", "MonoMixer Capture Switch", "Mono Mix"},
+
+	/*Right record mixer */
+	{"Right Capture Mix", "LineInR Capture Switch",	"LINEINR"},
+	{"Right Capture Mix", "Right AuxI Capture Switch",	"AUXINR"},
+	{"Right Capture Mix", "Mic1 Capture Switch",	"MIC1 Pre Amp"},
+	{"Right Capture Mix", "Mic2 Capture Switch",	"MIC2 Pre Amp"},
+	{"Right Capture Mix", "HPMixerR Capture Switch", "HPR Mix"},
+	{"Right Capture Mix", "SPKMixer Capture Switch", "Speaker Mix"},
+	{"Right Capture Mix", "MonoMixer Capture Switch", "Mono Mix"},
+
+	/* headphone left mux */
+	{"Left Headphone Mux", "HP Left Mix",		"HPL Mix"},
+	{"Left Headphone Mux", "Vmid",			"Vmid"},
+
+	/* headphone right mux */
+	{"Right Headphone Mux", "HP Right Mix",		"HPR Mix"},
+	{"Right Headphone Mux", "Vmid",			"Vmid"},
+
+	/* speaker out mux */
+	{"SpeakerOut Mux", "Vmid",			"Vmid"},
+	{"SpeakerOut Mux", "HPOut Mix",			"HPOut Mix"},
+	{"SpeakerOut Mux", "Speaker Mix",		"Speaker Mix"},
+	{"SpeakerOut Mux", "Mono Mix",			"Mono Mix"},
+
+	/* Mono/Aux Out mux */
+	{"AuxOut Mux", "Vmid",				"Vmid"},
+	{"AuxOut Mux", "HPOut Mix",			"HPOut Mix"},
+	{"AuxOut Mux", "Speaker Mix",			"Speaker Mix"},
+	{"AuxOut Mux", "Mono Mix",			"Mono Mix"},
+
+	/* output pga */
+	{"HPL", NULL,					"Left Headphone"},
+	{"Left Headphone", NULL,			"Left Headphone Mux"},
+	{"HPR", NULL,					"Right Headphone"},
+	{"Right Headphone", NULL,			"Right Headphone Mux"},
+	{"Left AuxOut", NULL,				"AuxOut Mux"},
+	{"Right AuxOut", NULL,				"AuxOut Mux"},
+
+	/* input pga */
+	{"Left LineIn", NULL,				"LINEINL"},
+	{"Right LineIn", NULL,				"LINEINR"},
+	{"Left AuxI", NULL,				"AUXINL"},
+	{"Right AuxI", NULL,				"AUXINR"},
+	{"MIC1 Pre Amp", NULL,				"MIC1"},
+	{"MIC2 Pre Amp", NULL,				"MIC2"},
+	{"MIC1 PGA", NULL,				"MIC1 Pre Amp"},
+	{"MIC2 PGA", NULL,				"MIC2 Pre Amp"},
+
+	/* left ADC */
+	{"Left ADC", NULL,				"Left Capture Mix"},
+
+	/* right ADC */
+	{"Right ADC", NULL,				"Right Capture Mix"},
+
+	{"SpeakerOut N Mux", "RN/-R",			"SpeakerOut"},
+	{"SpeakerOut N Mux", "RP/+R",			"SpeakerOut"},
+	{"SpeakerOut N Mux", "LN/-R",			"SpeakerOut"},
+	{"SpeakerOut N Mux", "Vmid",			"Vmid"},
+
+	{"SPKOUT", NULL,				"SpeakerOut"},
+	{"SPKOUTN", NULL,				"SpeakerOut N Mux"},
+};
+
+static const struct snd_soc_dapm_route intercon_spk[] = {
+	{"SpeakerOut", NULL,				"SpeakerOut Mux"},
+};
+
+static const struct snd_soc_dapm_route intercon_amp_spk[] = {
+	{"AB Amp", NULL,				"SpeakerOut Mux"},
+	{"D Amp", NULL,					"SpeakerOut Mux"},
+	{"AB-D Amp Mux", "AB Amp",			"AB Amp"},
+	{"AB-D Amp Mux", "D Amp",			"D Amp"},
+	{"SpeakerOut", NULL,				"AB-D Amp Mux"},
+};
+
+/* PLL divisors */
+struct _pll_div {
+	u32 pll_in;
+	u32 pll_out;
+	u16 regvalue;
+};
+
+/* Note : pll code from original alc5623 driver. Not sure of how good it is */
+/* useful only for master mode */
+static const struct _pll_div codec_master_pll_div[] = {
+
+	{  2048000,  8192000,	0x0ea0},
+	{  3686400,  8192000,	0x4e27},
+	{ 12000000,  8192000,	0x456b},
+	{ 13000000,  8192000,	0x495f},
+	{ 13100000,  8192000,	0x0320},
+	{  2048000,  11289600,	0xf637},
+	{  3686400,  11289600,	0x2f22},
+	{ 12000000,  11289600,	0x3e2f},
+	{ 13000000,  11289600,	0x4d5b},
+	{ 13100000,  11289600,	0x363b},
+	{  2048000,  16384000,	0x1ea0},
+	{  3686400,  16384000,	0x9e27},
+	{ 12000000,  16384000,	0x452b},
+	{ 13000000,  16384000,	0x542f},
+	{ 13100000,  16384000,	0x03a0},
+	{  2048000,  16934400,	0xe625},
+	{  3686400,  16934400,	0x9126},
+	{ 12000000,  16934400,	0x4d2c},
+	{ 13000000,  16934400,	0x742f},
+	{ 13100000,  16934400,	0x3c27},
+	{  2048000,  22579200,	0x2aa0},
+	{  3686400,  22579200,	0x2f20},
+	{ 12000000,  22579200,	0x7e2f},
+	{ 13000000,  22579200,	0x742f},
+	{ 13100000,  22579200,	0x3c27},
+	{  2048000,  24576000,	0x2ea0},
+	{  3686400,  24576000,	0xee27},
+	{ 12000000,  24576000,	0x2915},
+	{ 13000000,  24576000,	0x772e},
+	{ 13100000,  24576000,	0x0d20},
+};
+
+static const struct _pll_div codec_slave_pll_div[] = {
+
+	{  1024000,  16384000,  0x3ea0},
+	{  1411200,  22579200,	0x3ea0},
+	{  1536000,  24576000,	0x3ea0},
+	{  2048000,  16384000,  0x1ea0},
+	{  2822400,  22579200,	0x1ea0},
+	{  3072000,  24576000,	0x1ea0},
+
+};
+
+static int alc5623_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+		int source, unsigned int freq_in, unsigned int freq_out)
+{
+	int i;
+	struct snd_soc_component *component = codec_dai->component;
+	int gbl_clk = 0, pll_div = 0;
+	u16 reg;
+
+	if (pll_id < ALC5623_PLL_FR_MCLK || pll_id > ALC5623_PLL_FR_BCK)
+		return -ENODEV;
+
+	/* Disable PLL power */
+	snd_soc_component_update_bits(component, ALC5623_PWR_MANAG_ADD2,
+				ALC5623_PWR_ADD2_PLL,
+				0);
+
+	/* pll is not used in slave mode */
+	reg = snd_soc_component_read32(component, ALC5623_DAI_CONTROL);
+	if (reg & ALC5623_DAI_SDP_SLAVE_MODE)
+		return 0;
+
+	if (!freq_in || !freq_out)
+		return 0;
+
+	switch (pll_id) {
+	case ALC5623_PLL_FR_MCLK:
+		for (i = 0; i < ARRAY_SIZE(codec_master_pll_div); i++) {
+			if (codec_master_pll_div[i].pll_in == freq_in
+			   && codec_master_pll_div[i].pll_out == freq_out) {
+				/* PLL source from MCLK */
+				pll_div  = codec_master_pll_div[i].regvalue;
+				break;
+			}
+		}
+		break;
+	case ALC5623_PLL_FR_BCK:
+		for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i++) {
+			if (codec_slave_pll_div[i].pll_in == freq_in
+			   && codec_slave_pll_div[i].pll_out == freq_out) {
+				/* PLL source from Bitclk */
+				gbl_clk = ALC5623_GBL_CLK_PLL_SOUR_SEL_BITCLK;
+				pll_div = codec_slave_pll_div[i].regvalue;
+				break;
+			}
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (!pll_div)
+		return -EINVAL;
+
+	snd_soc_component_write(component, ALC5623_GLOBAL_CLK_CTRL_REG, gbl_clk);
+	snd_soc_component_write(component, ALC5623_PLL_CTRL, pll_div);
+	snd_soc_component_update_bits(component, ALC5623_PWR_MANAG_ADD2,
+				ALC5623_PWR_ADD2_PLL,
+				ALC5623_PWR_ADD2_PLL);
+	gbl_clk |= ALC5623_GBL_CLK_SYS_SOUR_SEL_PLL;
+	snd_soc_component_write(component, ALC5623_GLOBAL_CLK_CTRL_REG, gbl_clk);
+
+	return 0;
+}
+
+struct _coeff_div {
+	u16 fs;
+	u16 regvalue;
+};
+
+/* codec hifi mclk (after PLL) clock divider coefficients */
+/* values inspired from column BCLK=32Fs of Appendix A table */
+static const struct _coeff_div coeff_div[] = {
+	{256*8, 0x3a69},
+	{384*8, 0x3c6b},
+	{256*4, 0x2a69},
+	{384*4, 0x2c6b},
+	{256*2, 0x1a69},
+	{384*2, 0x1c6b},
+	{256*1, 0x0a69},
+	{384*1, 0x0c6b},
+};
+
+static int get_coeff(struct snd_soc_component *component, int rate)
+{
+	struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].fs * rate == alc5623->sysclk)
+			return i;
+	}
+	return -EINVAL;
+}
+
+/*
+ * Clock after PLL and dividers
+ */
+static int alc5623_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
+
+	switch (freq) {
+	case  8192000:
+	case 11289600:
+	case 12288000:
+	case 16384000:
+	case 16934400:
+	case 18432000:
+	case 22579200:
+	case 24576000:
+		alc5623->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int alc5623_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface = ALC5623_DAI_SDP_MASTER_MODE;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		iface = ALC5623_DAI_SDP_SLAVE_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= ALC5623_DAI_I2S_DF_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		iface |= ALC5623_DAI_I2S_DF_RIGHT;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= ALC5623_DAI_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= ALC5623_DAI_I2S_DF_PCM;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= ALC5623_DAI_I2S_DF_PCM | ALC5623_DAI_I2S_PCM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= ALC5623_DAI_MAIN_I2S_BCLK_POL_CTRL;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= ALC5623_DAI_MAIN_I2S_BCLK_POL_CTRL;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_soc_component_write(component, ALC5623_DAI_CONTROL, iface);
+}
+
+static int alc5623_pcm_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
+	int coeff, rate;
+	u16 iface;
+
+	iface = snd_soc_component_read32(component, ALC5623_DAI_CONTROL);
+	iface &= ~ALC5623_DAI_I2S_DL_MASK;
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		iface |= ALC5623_DAI_I2S_DL_16;
+		break;
+	case 20:
+		iface |= ALC5623_DAI_I2S_DL_20;
+		break;
+	case 24:
+		iface |= ALC5623_DAI_I2S_DL_24;
+		break;
+	case 32:
+		iface |= ALC5623_DAI_I2S_DL_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface & srate */
+	snd_soc_component_write(component, ALC5623_DAI_CONTROL, iface);
+	rate = params_rate(params);
+	coeff = get_coeff(component, rate);
+	if (coeff < 0)
+		return -EINVAL;
+
+	coeff = coeff_div[coeff].regvalue;
+	dev_dbg(component->dev, "%s: sysclk=%d,rate=%d,coeff=0x%04x\n",
+		__func__, alc5623->sysclk, rate, coeff);
+	snd_soc_component_write(component, ALC5623_STEREO_AD_DA_CLK_CTRL, coeff);
+
+	return 0;
+}
+
+static int alc5623_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 hp_mute = ALC5623_MISC_M_DAC_L_INPUT | ALC5623_MISC_M_DAC_R_INPUT;
+	u16 mute_reg = snd_soc_component_read32(component, ALC5623_MISC_CTRL) & ~hp_mute;
+
+	if (mute)
+		mute_reg |= hp_mute;
+
+	return snd_soc_component_write(component, ALC5623_MISC_CTRL, mute_reg);
+}
+
+#define ALC5623_ADD2_POWER_EN (ALC5623_PWR_ADD2_VREF \
+	| ALC5623_PWR_ADD2_DAC_REF_CIR)
+
+#define ALC5623_ADD3_POWER_EN (ALC5623_PWR_ADD3_MAIN_BIAS \
+	| ALC5623_PWR_ADD3_MIC1_BOOST_AD)
+
+#define ALC5623_ADD1_POWER_EN \
+	(ALC5623_PWR_ADD1_SHORT_CURR_DET_EN | ALC5623_PWR_ADD1_SOFTGEN_EN \
+	| ALC5623_PWR_ADD1_DEPOP_BUF_HP | ALC5623_PWR_ADD1_HP_OUT_AMP \
+	| ALC5623_PWR_ADD1_HP_OUT_ENH_AMP)
+
+#define ALC5623_ADD1_POWER_EN_5622 \
+	(ALC5623_PWR_ADD1_SHORT_CURR_DET_EN \
+	| ALC5623_PWR_ADD1_HP_OUT_AMP)
+
+static void enable_power_depop(struct snd_soc_component *component)
+{
+	struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_update_bits(component, ALC5623_PWR_MANAG_ADD1,
+				ALC5623_PWR_ADD1_SOFTGEN_EN,
+				ALC5623_PWR_ADD1_SOFTGEN_EN);
+
+	snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD3, ALC5623_ADD3_POWER_EN);
+
+	snd_soc_component_update_bits(component, ALC5623_MISC_CTRL,
+				ALC5623_MISC_HP_DEPOP_MODE2_EN,
+				ALC5623_MISC_HP_DEPOP_MODE2_EN);
+
+	msleep(500);
+
+	snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD2, ALC5623_ADD2_POWER_EN);
+
+	/* avoid writing '1' into 5622 reserved bits */
+	if (alc5623->id == 0x22)
+		snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD1,
+			ALC5623_ADD1_POWER_EN_5622);
+	else
+		snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD1,
+			ALC5623_ADD1_POWER_EN);
+
+	/* disable HP Depop2 */
+	snd_soc_component_update_bits(component, ALC5623_MISC_CTRL,
+				ALC5623_MISC_HP_DEPOP_MODE2_EN,
+				0);
+
+}
+
+static int alc5623_set_bias_level(struct snd_soc_component *component,
+				      enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		enable_power_depop(component);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* everything off except vref/vmid, */
+		snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD2,
+				ALC5623_PWR_ADD2_VREF);
+		snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD3,
+				ALC5623_PWR_ADD3_MAIN_BIAS);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* everything off, dac mute, inactive */
+		snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD2, 0);
+		snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD3, 0);
+		snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD1, 0);
+		break;
+	}
+	return 0;
+}
+
+#define ALC5623_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE \
+			| SNDRV_PCM_FMTBIT_S24_LE \
+			| SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops alc5623_dai_ops = {
+		.hw_params = alc5623_pcm_hw_params,
+		.digital_mute = alc5623_mute,
+		.set_fmt = alc5623_set_dai_fmt,
+		.set_sysclk = alc5623_set_dai_sysclk,
+		.set_pll = alc5623_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver alc5623_dai = {
+	.name = "alc5623-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =	8000,
+		.rate_max =	48000,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = ALC5623_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =	8000,
+		.rate_max =	48000,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = ALC5623_FORMATS,},
+
+	.ops = &alc5623_dai_ops,
+};
+
+static int alc5623_suspend(struct snd_soc_component *component)
+{
+	struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(alc5623->regmap, true);
+
+	return 0;
+}
+
+static int alc5623_resume(struct snd_soc_component *component)
+{
+	struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	/* Sync reg_cache with the hardware */
+	regcache_cache_only(alc5623->regmap, false);
+	ret = regcache_sync(alc5623->regmap);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to sync register cache: %d\n",
+			ret);
+		regcache_cache_only(alc5623->regmap, true);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int alc5623_probe(struct snd_soc_component *component)
+{
+	struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	alc5623_reset(component);
+
+	if (alc5623->add_ctrl) {
+		snd_soc_component_write(component, ALC5623_ADD_CTRL_REG,
+				alc5623->add_ctrl);
+	}
+
+	if (alc5623->jack_det_ctrl) {
+		snd_soc_component_write(component, ALC5623_JACK_DET_CTRL,
+				alc5623->jack_det_ctrl);
+	}
+
+	switch (alc5623->id) {
+	case 0x21:
+		snd_soc_add_component_controls(component, alc5621_vol_snd_controls,
+			ARRAY_SIZE(alc5621_vol_snd_controls));
+		break;
+	case 0x22:
+		snd_soc_add_component_controls(component, alc5622_vol_snd_controls,
+			ARRAY_SIZE(alc5622_vol_snd_controls));
+		break;
+	case 0x23:
+		snd_soc_add_component_controls(component, alc5623_vol_snd_controls,
+			ARRAY_SIZE(alc5623_vol_snd_controls));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_add_component_controls(component, alc5623_snd_controls,
+			ARRAY_SIZE(alc5623_snd_controls));
+
+	snd_soc_dapm_new_controls(dapm, alc5623_dapm_widgets,
+					ARRAY_SIZE(alc5623_dapm_widgets));
+
+	/* set up audio path interconnects */
+	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
+
+	switch (alc5623->id) {
+	case 0x21:
+	case 0x22:
+		snd_soc_dapm_new_controls(dapm, alc5623_dapm_amp_widgets,
+					ARRAY_SIZE(alc5623_dapm_amp_widgets));
+		snd_soc_dapm_add_routes(dapm, intercon_amp_spk,
+					ARRAY_SIZE(intercon_amp_spk));
+		break;
+	case 0x23:
+		snd_soc_dapm_add_routes(dapm, intercon_spk,
+					ARRAY_SIZE(intercon_spk));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_device_alc5623 = {
+	.probe			= alc5623_probe,
+	.suspend		= alc5623_suspend,
+	.resume			= alc5623_resume,
+	.set_bias_level		= alc5623_set_bias_level,
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config alc5623_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.reg_stride = 2,
+
+	.max_register = ALC5623_VENDOR_ID2,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+/*
+ * ALC5623 2 wire address is determined by A1 pin
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+static int alc5623_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct alc5623_platform_data *pdata;
+	struct alc5623_priv *alc5623;
+	struct device_node *np;
+	unsigned int vid1, vid2;
+	int ret;
+	u32 val32;
+
+	alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv),
+			       GFP_KERNEL);
+	if (alc5623 == NULL)
+		return -ENOMEM;
+
+	alc5623->regmap = devm_regmap_init_i2c(client, &alc5623_regmap);
+	if (IS_ERR(alc5623->regmap)) {
+		ret = PTR_ERR(alc5623->regmap);
+		dev_err(&client->dev, "Failed to initialise I/O: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID1, &vid1);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to read vendor ID1: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID2, &vid2);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to read vendor ID2: %d\n", ret);
+		return ret;
+	}
+	vid2 >>= 8;
+
+	if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) {
+		dev_err(&client->dev, "unknown or wrong codec\n");
+		dev_err(&client->dev, "Expected %x:%lx, got %x:%x\n",
+				0x10ec, id->driver_data,
+				vid1, vid2);
+		return -ENODEV;
+	}
+
+	dev_dbg(&client->dev, "Found codec id : alc56%02x\n", vid2);
+
+	pdata = client->dev.platform_data;
+	if (pdata) {
+		alc5623->add_ctrl = pdata->add_ctrl;
+		alc5623->jack_det_ctrl = pdata->jack_det_ctrl;
+	} else {
+		if (client->dev.of_node) {
+			np = client->dev.of_node;
+			ret = of_property_read_u32(np, "add-ctrl", &val32);
+			if (!ret)
+				alc5623->add_ctrl = val32;
+			ret = of_property_read_u32(np, "jack-det-ctrl", &val32);
+			if (!ret)
+				alc5623->jack_det_ctrl = val32;
+		}
+	}
+
+	alc5623->id = vid2;
+	switch (alc5623->id) {
+	case 0x21:
+		alc5623_dai.name = "alc5621-hifi";
+		break;
+	case 0x22:
+		alc5623_dai.name = "alc5622-hifi";
+		break;
+	case 0x23:
+		alc5623_dai.name = "alc5623-hifi";
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	i2c_set_clientdata(client, alc5623);
+
+	ret =  devm_snd_soc_register_component(&client->dev,
+		&soc_component_device_alc5623, &alc5623_dai, 1);
+	if (ret != 0)
+		dev_err(&client->dev, "Failed to register codec: %d\n", ret);
+
+	return ret;
+}
+
+static const struct i2c_device_id alc5623_i2c_table[] = {
+	{"alc5621", 0x21},
+	{"alc5622", 0x22},
+	{"alc5623", 0x23},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, alc5623_i2c_table);
+
+static const struct of_device_id alc5623_of_match[] = {
+	{ .compatible = "realtek,alc5623", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, alc5623_of_match);
+
+/*  i2c codec control layer */
+static struct i2c_driver alc5623_i2c_driver = {
+	.driver = {
+		.name = "alc562x-codec",
+		.of_match_table = of_match_ptr(alc5623_of_match),
+	},
+	.probe = alc5623_i2c_probe,
+	.id_table = alc5623_i2c_table,
+};
+
+module_i2c_driver(alc5623_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC alc5621/2/3 driver");
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/alc5623.h b/sound/soc/codecs/alc5623.h
new file mode 100644
index 0000000..f3d6826
--- /dev/null
+++ b/sound/soc/codecs/alc5623.h
@@ -0,0 +1,161 @@
+/*
+ * alc5623.h  --  alc562[123] ALSA Soc Audio driver
+ *
+ * Copyright 2008 Realtek Microelectronics
+ * Copyright 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * Author: flove <flove@realtek.com>
+ * Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _ALC5623_H
+#define _ALC5623_H
+
+#define ALC5623_RESET				0x00
+/*				5621 5622 5623  */
+/* speaker output vol		   2    2       */
+/* line output vol                      4    2  */
+/* HP output vol		   4    0    4  */
+#define ALC5623_SPK_OUT_VOL			0x02
+#define ALC5623_HP_OUT_VOL			0x04
+#define ALC5623_MONO_AUX_OUT_VOL		0x06
+#define ALC5623_AUXIN_VOL			0x08
+#define ALC5623_LINE_IN_VOL			0x0A
+#define ALC5623_STEREO_DAC_VOL			0x0C
+#define ALC5623_MIC_VOL				0x0E
+#define ALC5623_MIC_ROUTING_CTRL		0x10
+#define ALC5623_ADC_REC_GAIN			0x12
+#define ALC5623_ADC_REC_MIXER			0x14
+#define ALC5623_SOFT_VOL_CTRL_TIME		0x16
+/* ALC5623_OUTPUT_MIXER_CTRL :			*/
+/* same remark as for reg 2 line vs speaker	*/
+#define ALC5623_OUTPUT_MIXER_CTRL		0x1C
+#define ALC5623_MIC_CTRL			0x22
+
+#define	ALC5623_DAI_CONTROL			0x34
+#define ALC5623_DAI_SDP_MASTER_MODE		(0 << 15)
+#define ALC5623_DAI_SDP_SLAVE_MODE		(1 << 15)
+#define ALC5623_DAI_I2S_PCM_MODE		(1 << 14)
+#define ALC5623_DAI_MAIN_I2S_BCLK_POL_CTRL	(1 <<  7)
+#define ALC5623_DAI_ADC_DATA_L_R_SWAP		(1 <<  5)
+#define ALC5623_DAI_DAC_DATA_L_R_SWAP		(1 <<  4)
+#define ALC5623_DAI_I2S_DL_MASK			(3 <<  2)
+#define ALC5623_DAI_I2S_DL_32			(3 <<  2)
+#define	ALC5623_DAI_I2S_DL_24			(2 <<  2)
+#define ALC5623_DAI_I2S_DL_20			(1 <<  2)
+#define ALC5623_DAI_I2S_DL_16			(0 <<  2)
+#define ALC5623_DAI_I2S_DF_PCM			(3 <<  0)
+#define	ALC5623_DAI_I2S_DF_LEFT			(2 <<  0)
+#define ALC5623_DAI_I2S_DF_RIGHT		(1 <<  0)
+#define ALC5623_DAI_I2S_DF_I2S			(0 <<  0)
+
+#define ALC5623_STEREO_AD_DA_CLK_CTRL		0x36
+#define	ALC5623_COMPANDING_CTRL			0x38
+
+#define	ALC5623_PWR_MANAG_ADD1			0x3A
+#define ALC5623_PWR_ADD1_MAIN_I2S_EN		(1 << 15)
+#define ALC5623_PWR_ADD1_ZC_DET_PD_EN		(1 << 14)
+#define ALC5623_PWR_ADD1_MIC1_BIAS_EN		(1 << 11)
+#define ALC5623_PWR_ADD1_SHORT_CURR_DET_EN	(1 << 10)
+#define ALC5623_PWR_ADD1_SOFTGEN_EN		(1 <<  8) /* rsvd on 5622 */
+#define	ALC5623_PWR_ADD1_DEPOP_BUF_HP		(1 <<  6) /* rsvd on 5622 */
+#define	ALC5623_PWR_ADD1_HP_OUT_AMP		(1 <<  5)
+#define	ALC5623_PWR_ADD1_HP_OUT_ENH_AMP		(1 <<  4) /* rsvd on 5622 */
+#define ALC5623_PWR_ADD1_DEPOP_BUF_AUX		(1 <<  2)
+#define ALC5623_PWR_ADD1_AUX_OUT_AMP		(1 <<  1)
+#define ALC5623_PWR_ADD1_AUX_OUT_ENH_AMP	(1 <<  0) /* rsvd on 5622 */
+
+#define ALC5623_PWR_MANAG_ADD2			0x3C
+#define ALC5623_PWR_ADD2_LINEOUT		(1 << 15) /* rt5623 */
+#define ALC5623_PWR_ADD2_CLASS_AB		(1 << 15) /* rt5621 */
+#define ALC5623_PWR_ADD2_CLASS_D		(1 << 14) /* rt5621 */
+#define ALC5623_PWR_ADD2_VREF			(1 << 13)
+#define ALC5623_PWR_ADD2_PLL			(1 << 12)
+#define ALC5623_PWR_ADD2_DAC_REF_CIR		(1 << 10)
+#define ALC5623_PWR_ADD2_L_DAC_CLK		(1 <<  9)
+#define ALC5623_PWR_ADD2_R_DAC_CLK		(1 <<  8)
+#define ALC5623_PWR_ADD2_L_ADC_CLK_GAIN		(1 <<  7)
+#define ALC5623_PWR_ADD2_R_ADC_CLK_GAIN		(1 <<  6)
+#define ALC5623_PWR_ADD2_L_HP_MIXER		(1 <<  5)
+#define ALC5623_PWR_ADD2_R_HP_MIXER		(1 <<  4)
+#define ALC5623_PWR_ADD2_SPK_MIXER		(1 <<  3)
+#define ALC5623_PWR_ADD2_MONO_MIXER		(1 <<  2)
+#define ALC5623_PWR_ADD2_L_ADC_REC_MIXER	(1 <<  1)
+#define ALC5623_PWR_ADD2_R_ADC_REC_MIXER	(1 <<  0)
+
+#define ALC5623_PWR_MANAG_ADD3			0x3E
+#define ALC5623_PWR_ADD3_MAIN_BIAS		(1 << 15)
+#define ALC5623_PWR_ADD3_AUXOUT_L_VOL_AMP	(1 << 14)
+#define ALC5623_PWR_ADD3_AUXOUT_R_VOL_AMP	(1 << 13)
+#define ALC5623_PWR_ADD3_SPK_OUT		(1 << 12)
+#define ALC5623_PWR_ADD3_HP_L_OUT_VOL		(1 << 10)
+#define ALC5623_PWR_ADD3_HP_R_OUT_VOL		(1 <<  9)
+#define ALC5623_PWR_ADD3_LINEIN_L_VOL		(1 <<  7)
+#define ALC5623_PWR_ADD3_LINEIN_R_VOL		(1 <<  6)
+#define ALC5623_PWR_ADD3_AUXIN_L_VOL		(1 <<  5)
+#define ALC5623_PWR_ADD3_AUXIN_R_VOL		(1 <<  4)
+#define ALC5623_PWR_ADD3_MIC1_FUN_CTRL		(1 <<  3)
+#define ALC5623_PWR_ADD3_MIC2_FUN_CTRL		(1 <<  2)
+#define ALC5623_PWR_ADD3_MIC1_BOOST_AD		(1 <<  1)
+#define ALC5623_PWR_ADD3_MIC2_BOOST_AD		(1 <<  0)
+
+#define ALC5623_ADD_CTRL_REG			0x40
+
+#define	ALC5623_GLOBAL_CLK_CTRL_REG		0x42
+#define ALC5623_GBL_CLK_SYS_SOUR_SEL_PLL	(1 << 15)
+#define ALC5623_GBL_CLK_SYS_SOUR_SEL_MCLK	(0 << 15)
+#define ALC5623_GBL_CLK_PLL_SOUR_SEL_BITCLK	(1 << 14)
+#define ALC5623_GBL_CLK_PLL_SOUR_SEL_MCLK	(0 << 14)
+#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV8	(3 <<  1)
+#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV4	(2 <<  1)
+#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV2	(1 <<  1)
+#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV1	(0 <<  1)
+#define ALC5623_GBL_CLK_PLL_PRE_DIV2		(1 <<  0)
+#define ALC5623_GBL_CLK_PLL_PRE_DIV1		(0 <<  0)
+
+#define ALC5623_PLL_CTRL			0x44
+#define ALC5623_PLL_CTRL_N_VAL(n)		(((n)&0xff) << 8)
+#define ALC5623_PLL_CTRL_K_VAL(k)		(((k)&0x7)  << 4)
+#define ALC5623_PLL_CTRL_M_VAL(m)		((m)&0xf)
+
+#define ALC5623_GPIO_OUTPUT_PIN_CTRL		0x4A
+#define ALC5623_GPIO_PIN_CONFIG			0x4C
+#define ALC5623_GPIO_PIN_POLARITY		0x4E
+#define ALC5623_GPIO_PIN_STICKY			0x50
+#define ALC5623_GPIO_PIN_WAKEUP			0x52
+#define ALC5623_GPIO_PIN_STATUS			0x54
+#define ALC5623_GPIO_PIN_SHARING		0x56
+#define	ALC5623_OVER_CURR_STATUS		0x58
+#define ALC5623_JACK_DET_CTRL			0x5A
+
+#define ALC5623_MISC_CTRL			0x5E
+#define ALC5623_MISC_DISABLE_FAST_VREG		(1 << 15)
+#define ALC5623_MISC_SPK_CLASS_AB_OC_PD		(1 << 13) /* 5621 */
+#define ALC5623_MISC_SPK_CLASS_AB_OC_DET	(1 << 12) /* 5621 */
+#define ALC5623_MISC_HP_DEPOP_MODE3_EN		(1 << 10)
+#define ALC5623_MISC_HP_DEPOP_MODE2_EN		(1 <<  9)
+#define ALC5623_MISC_HP_DEPOP_MODE1_EN		(1 <<  8)
+#define ALC5623_MISC_AUXOUT_DEPOP_MODE3_EN	(1 <<  6)
+#define ALC5623_MISC_AUXOUT_DEPOP_MODE2_EN	(1 <<  5)
+#define ALC5623_MISC_AUXOUT_DEPOP_MODE1_EN	(1 <<  4)
+#define ALC5623_MISC_M_DAC_L_INPUT		(1 <<  3)
+#define ALC5623_MISC_M_DAC_R_INPUT		(1 <<  2)
+#define ALC5623_MISC_IRQOUT_INV_CTRL		(1 <<  0)
+
+#define	ALC5623_PSEDUEO_SPATIAL_CTRL		0x60
+#define ALC5623_EQ_CTRL				0x62
+#define ALC5623_EQ_MODE_ENABLE			0x66
+#define ALC5623_AVC_CTRL			0x68
+#define ALC5623_HID_CTRL_INDEX			0x6A
+#define ALC5623_HID_CTRL_DATA			0x6C
+#define ALC5623_VENDOR_ID1			0x7C
+#define ALC5623_VENDOR_ID2			0x7E
+
+#define ALC5623_PLL_FR_MCLK			0
+#define ALC5623_PLL_FR_BCK			1
+#endif
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
new file mode 100644
index 0000000..08034a6
--- /dev/null
+++ b/sound/soc/codecs/alc5632.c
@@ -0,0 +1,1192 @@
+/*
+* alc5632.c  --  ALC5632 ALSA SoC Audio Codec
+*
+* Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+*
+* Authors:  Leon Romanovsky <leon@leon.nu>
+*           Andrey Danin <danindrey@mail.ru>
+*           Ilya Petrov <ilya.muromec@gmail.com>
+*           Marc Dietrich <marvin24@gmx.de>
+*
+* Based on alc5623.c by Arnaud Patard
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include "alc5632.h"
+
+/*
+ * ALC5632 register cache
+ */
+static const struct reg_default alc5632_reg_defaults[] = {
+	{   2, 0x8080 },	/* R2   - Speaker Output Volume */
+	{   4, 0x8080 },	/* R4   - Headphone Output Volume */
+	{   6, 0x8080 },	/* R6   - AUXOUT Volume */
+	{   8, 0xC800 },	/* R8   - Phone Input */
+	{  10, 0xE808 },	/* R10  - LINE_IN Volume */
+	{  12, 0x1010 },	/* R12  - STEREO DAC Input Volume */
+	{  14, 0x0808 },	/* R14  - MIC Input Volume */
+	{  16, 0xEE0F },	/* R16  - Stereo DAC and MIC Routing Control */
+	{  18, 0xCBCB },	/* R18  - ADC Record Gain */
+	{  20, 0x7F7F },	/* R20  - ADC Record Mixer Control */
+	{  24, 0xE010 },	/* R24  - Voice DAC Volume */
+	{  28, 0x8008 },	/* R28  - Output Mixer Control */
+	{  34, 0x0000 },	/* R34  - Microphone Control */
+	{  36, 0x00C0 },    /* R36  - Codec Digital MIC/Digital Boost
+						   Control */
+	{  46, 0x0000 },	/* R46  - Stereo DAC/Voice DAC/Stereo ADC
+						   Function Select */
+	{  52, 0x8000 },	/* R52  - Main Serial Data Port Control
+						   (Stereo I2S) */
+	{  54, 0x0000 },	/* R54  - Extend Serial Data Port Control
+						   (VoDAC_I2S/PCM) */
+	{  58, 0x0000 },	/* R58  - Power Management Addition 1 */
+	{  60, 0x0000 },	/* R60  - Power Management Addition 2 */
+	{  62, 0x8000 },	/* R62  - Power Management Addition 3 */
+	{  64, 0x0C0A },	/* R64  - General Purpose Control Register 1 */
+	{  66, 0x0000 },	/* R66  - General Purpose Control Register 2 */
+	{  68, 0x0000 },	/* R68  - PLL1 Control */
+	{  70, 0x0000 },	/* R70  - PLL2 Control */
+	{  76, 0xBE3E },	/* R76  - GPIO Pin Configuration */
+	{  78, 0xBE3E },	/* R78  - GPIO Pin Polarity */
+	{  80, 0x0000 },	/* R80  - GPIO Pin Sticky */
+	{  82, 0x0000 },	/* R82  - GPIO Pin Wake Up */
+	{  86, 0x0000 },	/* R86  - Pin Sharing */
+	{  90, 0x0009 },	/* R90  - Soft Volume Control Setting */
+	{  92, 0x0000 },	/* R92  - GPIO_Output Pin Control */
+	{  94, 0x3000 },	/* R94  - MISC Control */
+	{  96, 0x3075 },	/* R96  - Stereo DAC Clock Control_1 */
+	{  98, 0x1010 },	/* R98  - Stereo DAC Clock Control_2 */
+	{ 100, 0x3110 },	/* R100 - VoDAC_PCM Clock Control_1 */
+	{ 104, 0x0553 },	/* R104 - Pseudo Stereo and Spatial Effect
+						   Block Control */
+	{ 106, 0x0000 },	/* R106 - Private Register Address */
+};
+
+/* codec private data */
+struct alc5632_priv {
+	struct regmap *regmap;
+	u8 id;
+	unsigned int sysclk;
+};
+
+static bool alc5632_volatile_register(struct device *dev,
+							unsigned int reg)
+{
+	switch (reg) {
+	case ALC5632_RESET:
+	case ALC5632_PWR_DOWN_CTRL_STATUS:
+	case ALC5632_GPIO_PIN_STATUS:
+	case ALC5632_OVER_CURR_STATUS:
+	case ALC5632_HID_CTRL_DATA:
+	case ALC5632_EQ_CTRL:
+	case ALC5632_VENDOR_ID1:
+	case ALC5632_VENDOR_ID2:
+		return true;
+
+	default:
+		break;
+	}
+
+	return false;
+}
+
+static inline int alc5632_reset(struct regmap *map)
+{
+	return regmap_write(map, ALC5632_RESET, 0x59B4);
+}
+
+static int amp_mixer_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	/* to power-on/off class-d amp generators/speaker */
+	/* need to write to 'index-46h' register :        */
+	/* so write index num (here 0x46) to reg 0x6a     */
+	/* and then 0xffff/0 to reg 0x6c                  */
+	snd_soc_component_write(component, ALC5632_HID_CTRL_INDEX, 0x46);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_write(component, ALC5632_HID_CTRL_DATA, 0xFFFF);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_write(component, ALC5632_HID_CTRL_DATA, 0);
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * ALC5632 Controls
+ */
+
+/* -34.5db min scale, 1.5db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(vol_tlv, -3450, 150, 0);
+/* -46.5db min scale, 1.5db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(hp_tlv, -4650, 150, 0);
+/* -16.5db min scale, 1.5db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -1650, 150, 0);
+static const DECLARE_TLV_DB_RANGE(boost_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+	1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0)
+);
+/* 0db min scale, 6 db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0);
+/* 0db min scalem 0.75db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(vdac_tlv, -3525, 75, 0);
+
+static const struct snd_kcontrol_new alc5632_vol_snd_controls[] = {
+	/* left starts at bit 8, right at bit 0 */
+	/* 31 steps (5 bit), -46.5db scale */
+	SOC_DOUBLE_TLV("Speaker Playback Volume",
+			ALC5632_SPK_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+	/* bit 15 mutes left, bit 7 right */
+	SOC_DOUBLE("Speaker Playback Switch",
+			ALC5632_SPK_OUT_VOL, 15, 7, 1, 1),
+	SOC_DOUBLE_TLV("Headphone Playback Volume",
+			ALC5632_HP_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+	SOC_DOUBLE("Headphone Playback Switch",
+			ALC5632_HP_OUT_VOL, 15, 7, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5632_snd_controls[] = {
+	SOC_DOUBLE_TLV("Auxout Playback Volume",
+			ALC5632_AUX_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+	SOC_DOUBLE("Auxout Playback Switch",
+			ALC5632_AUX_OUT_VOL, 15, 7, 1, 1),
+	SOC_SINGLE_TLV("Voice DAC Playback Volume",
+			ALC5632_VOICE_DAC_VOL, 0, 63, 0, vdac_tlv),
+	SOC_SINGLE("Voice DAC Playback Switch",
+			ALC5632_VOICE_DAC_VOL, 12, 1, 1),
+	SOC_SINGLE_TLV("Phone Playback Volume",
+			ALC5632_PHONE_IN_VOL, 8, 31, 1, vol_tlv),
+	SOC_DOUBLE_TLV("LineIn Playback Volume",
+			ALC5632_LINE_IN_VOL, 8, 0, 31, 1, vol_tlv),
+	SOC_DOUBLE_TLV("Master Playback Volume",
+			ALC5632_STEREO_DAC_IN_VOL, 8, 0, 63, 1, vdac_tlv),
+	SOC_DOUBLE("Master Playback Switch",
+			ALC5632_STEREO_DAC_IN_VOL, 15, 7, 1, 1),
+	SOC_SINGLE_TLV("Mic1 Playback Volume",
+			ALC5632_MIC_VOL, 8, 31, 1, vol_tlv),
+	SOC_SINGLE_TLV("Mic2 Playback Volume",
+			ALC5632_MIC_VOL, 0, 31, 1, vol_tlv),
+	SOC_DOUBLE_TLV("Rec Capture Volume",
+			ALC5632_ADC_REC_GAIN, 8, 0, 31, 0, adc_rec_tlv),
+	SOC_SINGLE_TLV("Mic 1 Boost Volume",
+			ALC5632_MIC_CTRL, 10, 3, 0, boost_tlv),
+	SOC_SINGLE_TLV("Mic 2 Boost Volume",
+			ALC5632_MIC_CTRL, 8, 3, 0, boost_tlv),
+	SOC_SINGLE_TLV("DMIC Boost Capture Volume",
+			ALC5632_DIGI_BOOST_CTRL, 0, 7, 0, dig_tlv),
+	SOC_SINGLE("DMIC En Capture Switch",
+			ALC5632_DIGI_BOOST_CTRL, 15, 1, 0),
+	SOC_SINGLE("DMIC PreFilter Capture Switch",
+			ALC5632_DIGI_BOOST_CTRL, 12, 1, 0),
+};
+
+/*
+ * DAPM Controls
+ */
+static const struct snd_kcontrol_new alc5632_hp_mixer_controls[] = {
+SOC_DAPM_SINGLE("LI2HP Playback Switch", ALC5632_LINE_IN_VOL, 15, 1, 1),
+SOC_DAPM_SINGLE("PHONE2HP Playback Switch", ALC5632_PHONE_IN_VOL, 15, 1, 1),
+SOC_DAPM_SINGLE("MIC12HP Playback Switch", ALC5632_MIC_ROUTING_CTRL, 15, 1, 1),
+SOC_DAPM_SINGLE("MIC22HP Playback Switch", ALC5632_MIC_ROUTING_CTRL, 11, 1, 1),
+SOC_DAPM_SINGLE("VOICE2HP Playback Switch", ALC5632_VOICE_DAC_VOL, 15, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5632_hpl_mixer_controls[] = {
+SOC_DAPM_SINGLE("ADC2HP_L Playback Switch", ALC5632_ADC_REC_GAIN, 15, 1, 1),
+SOC_DAPM_SINGLE("DACL2HP Playback Switch", ALC5632_MIC_ROUTING_CTRL, 3, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5632_hpr_mixer_controls[] = {
+SOC_DAPM_SINGLE("ADC2HP_R Playback Switch", ALC5632_ADC_REC_GAIN, 7, 1, 1),
+SOC_DAPM_SINGLE("DACR2HP Playback Switch", ALC5632_MIC_ROUTING_CTRL, 2, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5632_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("ADC2MONO_L Playback Switch", ALC5632_ADC_REC_GAIN, 14, 1, 1),
+SOC_DAPM_SINGLE("ADC2MONO_R Playback Switch", ALC5632_ADC_REC_GAIN, 6, 1, 1),
+SOC_DAPM_SINGLE("LI2MONO Playback Switch", ALC5632_LINE_IN_VOL, 13, 1, 1),
+SOC_DAPM_SINGLE("MIC12MONO Playback Switch",
+					ALC5632_MIC_ROUTING_CTRL, 13, 1, 1),
+SOC_DAPM_SINGLE("MIC22MONO Playback Switch",
+					ALC5632_MIC_ROUTING_CTRL, 9, 1, 1),
+SOC_DAPM_SINGLE("DAC2MONO Playback Switch", ALC5632_MIC_ROUTING_CTRL, 0, 1, 1),
+SOC_DAPM_SINGLE("VOICE2MONO Playback Switch", ALC5632_VOICE_DAC_VOL, 13, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5632_speaker_mixer_controls[] = {
+SOC_DAPM_SINGLE("LI2SPK Playback Switch", ALC5632_LINE_IN_VOL, 14, 1, 1),
+SOC_DAPM_SINGLE("PHONE2SPK Playback Switch", ALC5632_PHONE_IN_VOL, 14, 1, 1),
+SOC_DAPM_SINGLE("MIC12SPK Playback Switch",
+					ALC5632_MIC_ROUTING_CTRL, 14, 1, 1),
+SOC_DAPM_SINGLE("MIC22SPK Playback Switch",
+					ALC5632_MIC_ROUTING_CTRL, 10, 1, 1),
+SOC_DAPM_SINGLE("DAC2SPK Playback Switch", ALC5632_MIC_ROUTING_CTRL, 1, 1, 1),
+SOC_DAPM_SINGLE("VOICE2SPK Playback Switch", ALC5632_VOICE_DAC_VOL, 14, 1, 1),
+};
+
+/* Left Record Mixer */
+static const struct snd_kcontrol_new alc5632_captureL_mixer_controls[] = {
+SOC_DAPM_SINGLE("MIC12REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 14, 1, 1),
+SOC_DAPM_SINGLE("MIC22REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 13, 1, 1),
+SOC_DAPM_SINGLE("LIL2REC Capture Switch", ALC5632_ADC_REC_MIXER, 12, 1, 1),
+SOC_DAPM_SINGLE("PH2REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 11, 1, 1),
+SOC_DAPM_SINGLE("HPL2REC Capture Switch", ALC5632_ADC_REC_MIXER, 10, 1, 1),
+SOC_DAPM_SINGLE("SPK2REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 9, 1, 1),
+SOC_DAPM_SINGLE("MONO2REC_L Capture Switch", ALC5632_ADC_REC_MIXER, 8, 1, 1),
+};
+
+/* Right Record Mixer */
+static const struct snd_kcontrol_new alc5632_captureR_mixer_controls[] = {
+SOC_DAPM_SINGLE("MIC12REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 6, 1, 1),
+SOC_DAPM_SINGLE("MIC22REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 5, 1, 1),
+SOC_DAPM_SINGLE("LIR2REC Capture Switch", ALC5632_ADC_REC_MIXER, 4, 1, 1),
+SOC_DAPM_SINGLE("PH2REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 3, 1, 1),
+SOC_DAPM_SINGLE("HPR2REC Capture Switch", ALC5632_ADC_REC_MIXER, 2, 1, 1),
+SOC_DAPM_SINGLE("SPK2REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 1, 1, 1),
+SOC_DAPM_SINGLE("MONO2REC_R Capture Switch", ALC5632_ADC_REC_MIXER, 0, 1, 1),
+};
+
+/* Dmic Mixer */
+static const struct snd_kcontrol_new alc5632_dmicl_mixer_controls[] = {
+SOC_DAPM_SINGLE("DMICL2ADC Capture Switch", ALC5632_DIGI_BOOST_CTRL, 7, 1, 1),
+};
+static const struct snd_kcontrol_new alc5632_dmicr_mixer_controls[] = {
+SOC_DAPM_SINGLE("DMICR2ADC Capture Switch", ALC5632_DIGI_BOOST_CTRL, 6, 1, 1),
+};
+
+static const char * const alc5632_spk_n_sour_sel[] = {
+		"RN/-R", "RP/+R", "LN/-R", "Mute"};
+static const char * const alc5632_hpl_out_input_sel[] = {
+		"Vmid", "HP Left Mix"};
+static const char * const alc5632_hpr_out_input_sel[] = {
+		"Vmid", "HP Right Mix"};
+static const char * const alc5632_spkout_input_sel[] = {
+		"Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"};
+static const char * const alc5632_aux_out_input_sel[] = {
+		"Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"};
+static const char * const alc5632_adcr_func_sel[] = {
+		"Stereo ADC", "Voice ADC"};
+static const char * const alc5632_i2s_out_sel[] = {
+		"ADC LR", "Voice Stereo Digital"};
+
+/* auxout output mux */
+static SOC_ENUM_SINGLE_DECL(alc5632_aux_out_input_enum,
+			    ALC5632_OUTPUT_MIXER_CTRL, 6,
+			    alc5632_aux_out_input_sel);
+static const struct snd_kcontrol_new alc5632_auxout_mux_controls =
+SOC_DAPM_ENUM("AuxOut Mux", alc5632_aux_out_input_enum);
+
+/* speaker output mux */
+static SOC_ENUM_SINGLE_DECL(alc5632_spkout_input_enum,
+			    ALC5632_OUTPUT_MIXER_CTRL, 10,
+			    alc5632_spkout_input_sel);
+static const struct snd_kcontrol_new alc5632_spkout_mux_controls =
+SOC_DAPM_ENUM("SpeakerOut Mux", alc5632_spkout_input_enum);
+
+/* headphone left output mux */
+static SOC_ENUM_SINGLE_DECL(alc5632_hpl_out_input_enum,
+			    ALC5632_OUTPUT_MIXER_CTRL, 9,
+			    alc5632_hpl_out_input_sel);
+static const struct snd_kcontrol_new alc5632_hpl_out_mux_controls =
+SOC_DAPM_ENUM("Left Headphone Mux", alc5632_hpl_out_input_enum);
+
+/* headphone right output mux */
+static SOC_ENUM_SINGLE_DECL(alc5632_hpr_out_input_enum,
+			    ALC5632_OUTPUT_MIXER_CTRL, 8,
+			    alc5632_hpr_out_input_sel);
+static const struct snd_kcontrol_new alc5632_hpr_out_mux_controls =
+SOC_DAPM_ENUM("Right Headphone Mux", alc5632_hpr_out_input_enum);
+
+/* speaker output N select */
+static SOC_ENUM_SINGLE_DECL(alc5632_spk_n_sour_enum,
+			    ALC5632_OUTPUT_MIXER_CTRL, 14,
+			    alc5632_spk_n_sour_sel);
+static const struct snd_kcontrol_new alc5632_spkoutn_mux_controls =
+SOC_DAPM_ENUM("SpeakerOut N Mux", alc5632_spk_n_sour_enum);
+
+/* speaker amplifier */
+static const char *alc5632_amp_names[] = {"AB Amp", "D Amp"};
+static SOC_ENUM_SINGLE_DECL(alc5632_amp_enum,
+			    ALC5632_OUTPUT_MIXER_CTRL, 13,
+			    alc5632_amp_names);
+static const struct snd_kcontrol_new alc5632_amp_mux_controls =
+	SOC_DAPM_ENUM("AB-D Amp Mux", alc5632_amp_enum);
+
+/* ADC output select */
+static SOC_ENUM_SINGLE_DECL(alc5632_adcr_func_enum,
+			    ALC5632_DAC_FUNC_SELECT, 5,
+			    alc5632_adcr_func_sel);
+static const struct snd_kcontrol_new alc5632_adcr_func_controls =
+	SOC_DAPM_ENUM("ADCR Mux", alc5632_adcr_func_enum);
+
+/* I2S out select */
+static SOC_ENUM_SINGLE_DECL(alc5632_i2s_out_enum,
+			    ALC5632_I2S_OUT_CTL, 5,
+			    alc5632_i2s_out_sel);
+static const struct snd_kcontrol_new alc5632_i2s_out_controls =
+	SOC_DAPM_ENUM("I2SOut Mux", alc5632_i2s_out_enum);
+
+static const struct snd_soc_dapm_widget alc5632_dapm_widgets[] = {
+/* Muxes */
+SND_SOC_DAPM_MUX("AuxOut Mux", SND_SOC_NOPM, 0, 0,
+	&alc5632_auxout_mux_controls),
+SND_SOC_DAPM_MUX("SpeakerOut Mux", SND_SOC_NOPM, 0, 0,
+	&alc5632_spkout_mux_controls),
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0,
+	&alc5632_hpl_out_mux_controls),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0,
+	&alc5632_hpr_out_mux_controls),
+SND_SOC_DAPM_MUX("SpeakerOut N Mux", SND_SOC_NOPM, 0, 0,
+	&alc5632_spkoutn_mux_controls),
+SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0,
+	&alc5632_adcr_func_controls),
+SND_SOC_DAPM_MUX("I2SOut Mux", ALC5632_PWR_MANAG_ADD1, 11, 0,
+	&alc5632_i2s_out_controls),
+
+/* output mixers */
+SND_SOC_DAPM_MIXER("HP Mix", SND_SOC_NOPM, 0, 0,
+	&alc5632_hp_mixer_controls[0],
+	ARRAY_SIZE(alc5632_hp_mixer_controls)),
+SND_SOC_DAPM_MIXER("HPR Mix", ALC5632_PWR_MANAG_ADD2, 4, 0,
+	&alc5632_hpr_mixer_controls[0],
+	ARRAY_SIZE(alc5632_hpr_mixer_controls)),
+SND_SOC_DAPM_MIXER("HPL Mix", ALC5632_PWR_MANAG_ADD2, 5, 0,
+	&alc5632_hpl_mixer_controls[0],
+	ARRAY_SIZE(alc5632_hpl_mixer_controls)),
+SND_SOC_DAPM_MIXER("HPOut Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Mono Mix", ALC5632_PWR_MANAG_ADD2, 2, 0,
+	&alc5632_mono_mixer_controls[0],
+	ARRAY_SIZE(alc5632_mono_mixer_controls)),
+SND_SOC_DAPM_MIXER("Speaker Mix", ALC5632_PWR_MANAG_ADD2, 3, 0,
+	&alc5632_speaker_mixer_controls[0],
+	ARRAY_SIZE(alc5632_speaker_mixer_controls)),
+SND_SOC_DAPM_MIXER("DMICL Mix", SND_SOC_NOPM, 0, 0,
+	&alc5632_dmicl_mixer_controls[0],
+	ARRAY_SIZE(alc5632_dmicl_mixer_controls)),
+SND_SOC_DAPM_MIXER("DMICR Mix", SND_SOC_NOPM, 0, 0,
+	&alc5632_dmicr_mixer_controls[0],
+	ARRAY_SIZE(alc5632_dmicr_mixer_controls)),
+
+/* input mixers */
+SND_SOC_DAPM_MIXER("Left Capture Mix", ALC5632_PWR_MANAG_ADD2, 1, 0,
+	&alc5632_captureL_mixer_controls[0],
+	ARRAY_SIZE(alc5632_captureL_mixer_controls)),
+SND_SOC_DAPM_MIXER("Right Capture Mix", ALC5632_PWR_MANAG_ADD2, 0, 0,
+	&alc5632_captureR_mixer_controls[0],
+	ARRAY_SIZE(alc5632_captureR_mixer_controls)),
+
+SND_SOC_DAPM_AIF_IN("AIFRXL", "Left HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIFRXR", "Right HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIFTXL", "Left HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIFTXR", "Right HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("VAIFRX", "Voice Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("VAIFTX", "Voice Capture", 0, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_DAC("Voice DAC", NULL, ALC5632_PWR_MANAG_ADD2, 10, 0),
+SND_SOC_DAPM_DAC("Left DAC", NULL, ALC5632_PWR_MANAG_ADD2, 9, 0),
+SND_SOC_DAPM_DAC("Right DAC", NULL, ALC5632_PWR_MANAG_ADD2, 8, 0),
+SND_SOC_DAPM_ADC("Left ADC", NULL, ALC5632_PWR_MANAG_ADD2, 7, 0),
+SND_SOC_DAPM_ADC("Right ADC", NULL, ALC5632_PWR_MANAG_ADD2, 6, 0),
+
+SND_SOC_DAPM_MIXER("DAC Left Channel", ALC5632_PWR_MANAG_ADD1, 15, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("DAC Right Channel",
+	ALC5632_PWR_MANAG_ADD1, 14, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("I2S Mix", ALC5632_PWR_MANAG_ADD1, 11, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Phone Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Line Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Voice Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("ADCLR", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Left Headphone", ALC5632_PWR_MANAG_ADD3, 11, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Headphone", ALC5632_PWR_MANAG_ADD3, 10, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Left Speaker", ALC5632_PWR_MANAG_ADD3, 13, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Speaker", ALC5632_PWR_MANAG_ADD3, 12, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Aux Out", ALC5632_PWR_MANAG_ADD3, 14, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Left LineIn", ALC5632_PWR_MANAG_ADD3, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right LineIn", ALC5632_PWR_MANAG_ADD3, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Phone", ALC5632_PWR_MANAG_ADD3, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Phone ADMix", ALC5632_PWR_MANAG_ADD3, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC1 PGA", ALC5632_PWR_MANAG_ADD3, 3, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC2 PGA", ALC5632_PWR_MANAG_ADD3, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC1 Pre Amp", ALC5632_PWR_MANAG_ADD3, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC2 Pre Amp", ALC5632_PWR_MANAG_ADD3, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS1", ALC5632_PWR_MANAG_ADD1, 3, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", ALC5632_PWR_MANAG_ADD1, 2, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_E("D Amp", ALC5632_PWR_MANAG_ADD2, 14, 0, NULL, 0,
+	amp_mixer_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_PGA("AB Amp", ALC5632_PWR_MANAG_ADD2, 15, 0, NULL, 0),
+SND_SOC_DAPM_MUX("AB-D Amp Mux", ALC5632_PWR_MANAG_ADD1, 10, 0,
+	&alc5632_amp_mux_controls),
+
+SND_SOC_DAPM_OUTPUT("AUXOUT"),
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("HPR"),
+SND_SOC_DAPM_OUTPUT("SPKOUT"),
+SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+
+SND_SOC_DAPM_INPUT("LINEINL"),
+SND_SOC_DAPM_INPUT("LINEINR"),
+SND_SOC_DAPM_INPUT("PHONEP"),
+SND_SOC_DAPM_INPUT("PHONEN"),
+SND_SOC_DAPM_INPUT("DMICDAT"),
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2"),
+SND_SOC_DAPM_VMID("Vmid"),
+};
+
+
+static const struct snd_soc_dapm_route alc5632_dapm_routes[] = {
+	/* Playback streams */
+	{"Left DAC", NULL, "AIFRXL"},
+	{"Right DAC", NULL, "AIFRXR"},
+
+	/* virtual mixer - mixes left & right channels */
+	{"I2S Mix",	NULL,	"Left DAC"},
+	{"I2S Mix",	NULL,	"Right DAC"},
+	{"Line Mix",	NULL,	"Right LineIn"},
+	{"Line Mix",	NULL,	"Left LineIn"},
+	{"Phone Mix",	NULL,	"Phone"},
+	{"Phone Mix",	NULL,	"Phone ADMix"},
+	{"AUXOUT",		NULL,	"Aux Out"},
+
+	/* DAC */
+	{"DAC Right Channel",	NULL,	"I2S Mix"},
+	{"DAC Left Channel",	NULL,   "I2S Mix"},
+
+	/* HP mixer */
+	{"HPL Mix",	"ADC2HP_L Playback Switch",	"Left Capture Mix"},
+	{"HPL Mix", NULL,					"HP Mix"},
+	{"HPR Mix", "ADC2HP_R Playback Switch",	"Right Capture Mix"},
+	{"HPR Mix", NULL,					"HP Mix"},
+	{"HP Mix",	"LI2HP Playback Switch",	"Line Mix"},
+	{"HP Mix",	"PHONE2HP Playback Switch",	"Phone Mix"},
+	{"HP Mix",	"MIC12HP Playback Switch",	"MIC1 PGA"},
+	{"HP Mix",	"MIC22HP Playback Switch",	"MIC2 PGA"},
+	{"HP Mix", "VOICE2HP Playback Switch",	"Voice Mix"},
+	{"HPR Mix", "DACR2HP Playback Switch",	"DAC Right Channel"},
+	{"HPL Mix", "DACL2HP Playback Switch",	"DAC Left Channel"},
+	{"HPOut Mix", NULL, "HP Mix"},
+	{"HPOut Mix", NULL, "HPR Mix"},
+	{"HPOut Mix", NULL, "HPL Mix"},
+
+	/* speaker mixer */
+	{"Speaker Mix", "LI2SPK Playback Switch",	"Line Mix"},
+	{"Speaker Mix", "PHONE2SPK Playback Switch", "Phone Mix"},
+	{"Speaker Mix", "MIC12SPK Playback Switch",	"MIC1 PGA"},
+	{"Speaker Mix", "MIC22SPK Playback Switch",	"MIC2 PGA"},
+	{"Speaker Mix", "DAC2SPK Playback Switch",	"DAC Left Channel"},
+	{"Speaker Mix", "VOICE2SPK Playback Switch",	"Voice Mix"},
+
+	/* mono mixer */
+	{"Mono Mix", "ADC2MONO_L Playback Switch",	"Left Capture Mix"},
+	{"Mono Mix", "ADC2MONO_R Playback Switch",	"Right Capture Mix"},
+	{"Mono Mix", "LI2MONO Playback Switch",		"Line Mix"},
+	{"Mono Mix", "MIC12MONO Playback Switch",	"MIC1 PGA"},
+	{"Mono Mix", "MIC22MONO Playback Switch",	"MIC2 PGA"},
+	{"Mono Mix", "DAC2MONO Playback Switch",	"DAC Left Channel"},
+	{"Mono Mix", "VOICE2MONO Playback Switch",	"Voice Mix"},
+
+	/* Left record mixer */
+	{"Left Capture Mix", "LIL2REC Capture Switch", "LINEINL"},
+	{"Left Capture Mix", "PH2REC_L Capture Switch", "PHONEN"},
+	{"Left Capture Mix", "MIC12REC_L Capture Switch", "MIC1 Pre Amp"},
+	{"Left Capture Mix", "MIC22REC_L Capture Switch", "MIC2 Pre Amp"},
+	{"Left Capture Mix", "HPL2REC Capture Switch", "HPL Mix"},
+	{"Left Capture Mix", "SPK2REC_L Capture Switch", "Speaker Mix"},
+	{"Left Capture Mix", "MONO2REC_L Capture Switch", "Mono Mix"},
+
+	/*Right record mixer */
+	{"Right Capture Mix", "LIR2REC Capture Switch", "LINEINR"},
+	{"Right Capture Mix", "PH2REC_R Capture Switch", "PHONEP"},
+	{"Right Capture Mix", "MIC12REC_R Capture Switch", "MIC1 Pre Amp"},
+	{"Right Capture Mix", "MIC22REC_R Capture Switch", "MIC2 Pre Amp"},
+	{"Right Capture Mix", "HPR2REC Capture Switch", "HPR Mix"},
+	{"Right Capture Mix", "SPK2REC_R Capture Switch", "Speaker Mix"},
+	{"Right Capture Mix", "MONO2REC_R Capture Switch", "Mono Mix"},
+
+	/* headphone left mux */
+	{"Left Headphone Mux", "HP Left Mix",		"HPL Mix"},
+	{"Left Headphone Mux", "Vmid",			"Vmid"},
+
+	/* headphone right mux */
+	{"Right Headphone Mux", "HP Right Mix",		"HPR Mix"},
+	{"Right Headphone Mux", "Vmid",			"Vmid"},
+
+	/* speaker out mux */
+	{"SpeakerOut Mux", "Vmid",			"Vmid"},
+	{"SpeakerOut Mux", "HPOut Mix",			"HPOut Mix"},
+	{"SpeakerOut Mux", "Speaker Mix",		"Speaker Mix"},
+	{"SpeakerOut Mux", "Mono Mix",			"Mono Mix"},
+
+	/* Mono/Aux Out mux */
+	{"AuxOut Mux", "Vmid",				"Vmid"},
+	{"AuxOut Mux", "HPOut Mix",			"HPOut Mix"},
+	{"AuxOut Mux", "Speaker Mix",			"Speaker Mix"},
+	{"AuxOut Mux", "Mono Mix",			"Mono Mix"},
+
+	/* output pga */
+	{"HPL", NULL,					"Left Headphone"},
+	{"Left Headphone", NULL,			"Left Headphone Mux"},
+	{"HPR", NULL,					"Right Headphone"},
+	{"Right Headphone", NULL,			"Right Headphone Mux"},
+	{"Aux Out", NULL,				"AuxOut Mux"},
+
+	/* input pga */
+	{"Left LineIn", NULL,				"LINEINL"},
+	{"Right LineIn", NULL,				"LINEINR"},
+	{"Phone", NULL,				"PHONEP"},
+	{"MIC1 Pre Amp", NULL,				"MIC1"},
+	{"MIC2 Pre Amp", NULL,				"MIC2"},
+	{"MIC1 PGA", NULL,				"MIC1 Pre Amp"},
+	{"MIC2 PGA", NULL,				"MIC2 Pre Amp"},
+
+	/* left ADC */
+	{"Left ADC", NULL,				"Left Capture Mix"},
+	{"DMICL Mix", "DMICL2ADC Capture Switch", "DMICDAT"},
+	{"Left ADC", NULL,				"DMICL Mix"},
+	{"ADCLR", NULL,					"Left ADC"},
+
+	/* right ADC */
+	{"Right ADC", NULL, "Right Capture Mix"},
+	{"DMICR Mix", "DMICR2ADC Capture Switch", "DMICDAT"},
+	{"Right ADC", NULL, "DMICR Mix"},
+	{"ADCR Mux", "Stereo ADC", "Right ADC"},
+	{"ADCR Mux", "Voice ADC", "Right ADC"},
+	{"ADCLR", NULL, "ADCR Mux"},
+	{"VAIFTX", NULL, "ADCR Mux"},
+
+	/* Digital I2S out */
+	{"I2SOut Mux", "ADC LR", "ADCLR"},
+	{"I2SOut Mux", "Voice Stereo Digital", "VAIFRX"},
+	{"AIFTXL", NULL, "I2SOut Mux"},
+	{"AIFTXR", NULL, "I2SOut Mux"},
+
+	/* Voice Mix */
+	{"Voice DAC", NULL, "VAIFRX"},
+	{"Voice Mix", NULL, "Voice DAC"},
+
+	/* Speaker Output */
+	{"SpeakerOut N Mux", "RN/-R",			"Left Speaker"},
+	{"SpeakerOut N Mux", "RP/+R",			"Left Speaker"},
+	{"SpeakerOut N Mux", "LN/-R",			"Left Speaker"},
+	{"SpeakerOut N Mux", "Mute",			"Vmid"},
+
+	{"SpeakerOut N Mux", "RN/-R",			"Right Speaker"},
+	{"SpeakerOut N Mux", "RP/+R",			"Right Speaker"},
+	{"SpeakerOut N Mux", "LN/-R",			"Right Speaker"},
+	{"SpeakerOut N Mux", "Mute",			"Vmid"},
+
+	{"AB Amp", NULL,				"SpeakerOut Mux"},
+	{"D Amp", NULL,					"SpeakerOut Mux"},
+	{"AB-D Amp Mux", "AB Amp",			"AB Amp"},
+	{"AB-D Amp Mux", "D Amp",			"D Amp"},
+	{"Left Speaker", NULL,				"AB-D Amp Mux"},
+	{"Right Speaker", NULL,				"AB-D Amp Mux"},
+
+	{"SPKOUT", NULL,				"Left Speaker"},
+	{"SPKOUT", NULL,				"Right Speaker"},
+
+	{"SPKOUTN", NULL,				"SpeakerOut N Mux"},
+
+};
+
+/* PLL divisors */
+struct _pll_div {
+	u32 pll_in;
+	u32 pll_out;
+	u16 regvalue;
+};
+
+/* Note : pll code from original alc5632 driver. Not sure of how good it is */
+/* useful only for master mode */
+static const struct _pll_div codec_master_pll_div[] = {
+
+	{  2048000,  8192000,	0x0ea0},
+	{  3686400,  8192000,	0x4e27},
+	{ 12000000,  8192000,	0x456b},
+	{ 13000000,  8192000,	0x495f},
+	{ 13100000,  8192000,	0x0320},
+	{  2048000,  11289600,	0xf637},
+	{  3686400,  11289600,	0x2f22},
+	{ 12000000,  11289600,	0x3e2f},
+	{ 13000000,  11289600,	0x4d5b},
+	{ 13100000,  11289600,	0x363b},
+	{  2048000,  16384000,	0x1ea0},
+	{  3686400,  16384000,	0x9e27},
+	{ 12000000,  16384000,	0x452b},
+	{ 13000000,  16384000,	0x542f},
+	{ 13100000,  16384000,	0x03a0},
+	{  2048000,  16934400,	0xe625},
+	{  3686400,  16934400,	0x9126},
+	{ 12000000,  16934400,	0x4d2c},
+	{ 13000000,  16934400,	0x742f},
+	{ 13100000,  16934400,	0x3c27},
+	{  2048000,  22579200,	0x2aa0},
+	{  3686400,  22579200,	0x2f20},
+	{ 12000000,  22579200,	0x7e2f},
+	{ 13000000,  22579200,	0x742f},
+	{ 13100000,  22579200,	0x3c27},
+	{  2048000,  24576000,	0x2ea0},
+	{  3686400,  24576000,	0xee27},
+	{ 12000000,  24576000,	0x2915},
+	{ 13000000,  24576000,	0x772e},
+	{ 13100000,  24576000,	0x0d20},
+};
+
+/* FOUT = MCLK*(N+2)/((M+2)*(K+2))
+   N: bit 15:8 (div 2 .. div 257)
+   K: bit  6:4 typical 2
+   M: bit  3:0 (div 2 .. div 17)
+
+   same as for 5623 - thanks!
+*/
+
+static const struct _pll_div codec_slave_pll_div[] = {
+
+	{  1024000,  16384000,  0x3ea0},
+	{  1411200,  22579200,	0x3ea0},
+	{  1536000,  24576000,	0x3ea0},
+	{  2048000,  16384000,  0x1ea0},
+	{  2822400,  22579200,	0x1ea0},
+	{  3072000,  24576000,	0x1ea0},
+
+};
+
+static int alc5632_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+		int source, unsigned int freq_in, unsigned int freq_out)
+{
+	int i;
+	struct snd_soc_component *component = codec_dai->component;
+	int gbl_clk = 0, pll_div = 0;
+	u16 reg;
+
+	if (pll_id < ALC5632_PLL_FR_MCLK || pll_id > ALC5632_PLL_FR_VBCLK)
+		return -EINVAL;
+
+	/* Disable PLL power */
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD2,
+				ALC5632_PWR_ADD2_PLL1,
+				0);
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD2,
+				ALC5632_PWR_ADD2_PLL2,
+				0);
+
+	/* pll is not used in slave mode */
+	reg = snd_soc_component_read32(component, ALC5632_DAI_CONTROL);
+	if (reg & ALC5632_DAI_SDP_SLAVE_MODE)
+		return 0;
+
+	if (!freq_in || !freq_out)
+		return 0;
+
+	switch (pll_id) {
+	case ALC5632_PLL_FR_MCLK:
+		for (i = 0; i < ARRAY_SIZE(codec_master_pll_div); i++) {
+			if (codec_master_pll_div[i].pll_in == freq_in
+			   && codec_master_pll_div[i].pll_out == freq_out) {
+				/* PLL source from MCLK */
+				pll_div  = codec_master_pll_div[i].regvalue;
+				break;
+			}
+		}
+		break;
+	case ALC5632_PLL_FR_BCLK:
+		for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i++) {
+			if (codec_slave_pll_div[i].pll_in == freq_in
+			   && codec_slave_pll_div[i].pll_out == freq_out) {
+				/* PLL source from Bitclk */
+				gbl_clk = ALC5632_PLL_FR_BCLK;
+				pll_div = codec_slave_pll_div[i].regvalue;
+				break;
+			}
+		}
+		break;
+	case ALC5632_PLL_FR_VBCLK:
+		for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i++) {
+			if (codec_slave_pll_div[i].pll_in == freq_in
+			   && codec_slave_pll_div[i].pll_out == freq_out) {
+				/* PLL source from voice clock */
+				gbl_clk = ALC5632_PLL_FR_VBCLK;
+				pll_div = codec_slave_pll_div[i].regvalue;
+				break;
+			}
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (!pll_div)
+		return -EINVAL;
+
+	/* choose MCLK/BCLK/VBCLK */
+	snd_soc_component_write(component, ALC5632_GPCR2, gbl_clk);
+	/* choose PLL1 clock rate */
+	snd_soc_component_write(component, ALC5632_PLL1_CTRL, pll_div);
+	/* enable PLL1 */
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD2,
+				ALC5632_PWR_ADD2_PLL1,
+				ALC5632_PWR_ADD2_PLL1);
+	/* enable PLL2 */
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD2,
+				ALC5632_PWR_ADD2_PLL2,
+				ALC5632_PWR_ADD2_PLL2);
+	/* use PLL1 as main SYSCLK */
+	snd_soc_component_update_bits(component, ALC5632_GPCR1,
+			ALC5632_GPCR1_CLK_SYS_SRC_SEL_PLL1,
+			ALC5632_GPCR1_CLK_SYS_SRC_SEL_PLL1);
+
+	return 0;
+}
+
+struct _coeff_div {
+	u16 fs;
+	u16 regvalue;
+};
+
+/* codec hifi mclk (after PLL) clock divider coefficients */
+/* values inspired from column BCLK=32Fs of Appendix A table */
+static const struct _coeff_div coeff_div[] = {
+	{512*1, 0x3075},
+};
+
+static int get_coeff(struct snd_soc_component *component, int rate)
+{
+	struct alc5632_priv *alc5632 = snd_soc_component_get_drvdata(component);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].fs * rate == alc5632->sysclk)
+			return i;
+	}
+	return -EINVAL;
+}
+
+/*
+ * Clock after PLL and dividers
+ */
+static int alc5632_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct alc5632_priv *alc5632 = snd_soc_component_get_drvdata(component);
+
+	switch (freq) {
+	case  4096000:
+	case  8192000:
+	case 11289600:
+	case 12288000:
+	case 16384000:
+	case 16934400:
+	case 18432000:
+	case 22579200:
+	case 24576000:
+		alc5632->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int alc5632_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface = ALC5632_DAI_SDP_MASTER_MODE;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		iface = ALC5632_DAI_SDP_SLAVE_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= ALC5632_DAI_I2S_DF_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= ALC5632_DAI_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= ALC5632_DAI_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= ALC5632_DAI_I2S_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= ALC5632_DAI_MAIN_I2S_BCLK_POL_CTRL;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= ALC5632_DAI_MAIN_I2S_BCLK_POL_CTRL;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_soc_component_write(component, ALC5632_DAI_CONTROL, iface);
+}
+
+static int alc5632_pcm_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	int coeff, rate;
+	u16 iface;
+
+	iface = snd_soc_component_read32(component, ALC5632_DAI_CONTROL);
+	iface &= ~ALC5632_DAI_I2S_DL_MASK;
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		iface |= ALC5632_DAI_I2S_DL_16;
+		break;
+	case 20:
+		iface |= ALC5632_DAI_I2S_DL_20;
+		break;
+	case 24:
+		iface |= ALC5632_DAI_I2S_DL_24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface & srate */
+	snd_soc_component_write(component, ALC5632_DAI_CONTROL, iface);
+	rate = params_rate(params);
+	coeff = get_coeff(component, rate);
+	if (coeff < 0)
+		return -EINVAL;
+
+	coeff = coeff_div[coeff].regvalue;
+	snd_soc_component_write(component, ALC5632_DAC_CLK_CTRL1, coeff);
+
+	return 0;
+}
+
+static int alc5632_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 hp_mute = ALC5632_MISC_HP_DEPOP_MUTE_L
+						|ALC5632_MISC_HP_DEPOP_MUTE_R;
+	u16 mute_reg = snd_soc_component_read32(component, ALC5632_MISC_CTRL) & ~hp_mute;
+
+	if (mute)
+		mute_reg |= hp_mute;
+
+	return snd_soc_component_write(component, ALC5632_MISC_CTRL, mute_reg);
+}
+
+#define ALC5632_ADD2_POWER_EN (ALC5632_PWR_ADD2_VREF)
+
+#define ALC5632_ADD3_POWER_EN (ALC5632_PWR_ADD3_MIC1_BOOST_AD)
+
+#define ALC5632_ADD1_POWER_EN \
+		(ALC5632_PWR_ADD1_DAC_REF \
+		| ALC5632_PWR_ADD1_SOFTGEN_EN \
+		| ALC5632_PWR_ADD1_HP_OUT_AMP \
+		| ALC5632_PWR_ADD1_HP_OUT_ENH_AMP \
+		| ALC5632_PWR_ADD1_MAIN_BIAS)
+
+static void enable_power_depop(struct snd_soc_component *component)
+{
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD1,
+				ALC5632_PWR_ADD1_SOFTGEN_EN,
+				ALC5632_PWR_ADD1_SOFTGEN_EN);
+
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD3,
+				ALC5632_ADD3_POWER_EN,
+				ALC5632_ADD3_POWER_EN);
+
+	snd_soc_component_update_bits(component, ALC5632_MISC_CTRL,
+				ALC5632_MISC_HP_DEPOP_MODE2_EN,
+				ALC5632_MISC_HP_DEPOP_MODE2_EN);
+
+	/* "normal" mode: 0 @ 26 */
+	/* set all PR0-7 mixers to 0 */
+	snd_soc_component_update_bits(component, ALC5632_PWR_DOWN_CTRL_STATUS,
+				ALC5632_PWR_DOWN_CTRL_STATUS_MASK,
+				0);
+
+	msleep(500);
+
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD2,
+				ALC5632_ADD2_POWER_EN,
+				ALC5632_ADD2_POWER_EN);
+
+	snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD1,
+				ALC5632_ADD1_POWER_EN,
+				ALC5632_ADD1_POWER_EN);
+
+	/* disable HP Depop2 */
+	snd_soc_component_update_bits(component, ALC5632_MISC_CTRL,
+				ALC5632_MISC_HP_DEPOP_MODE2_EN,
+				0);
+
+}
+
+static int alc5632_set_bias_level(struct snd_soc_component *component,
+				      enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		enable_power_depop(component);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* everything off except vref/vmid, */
+		snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD1,
+				ALC5632_PWR_MANAG_ADD1_MASK,
+				ALC5632_PWR_ADD1_MAIN_BIAS);
+		snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD2,
+				ALC5632_PWR_MANAG_ADD2_MASK,
+				ALC5632_PWR_ADD2_VREF);
+		/* "normal" mode: 0 @ 26 */
+		snd_soc_component_update_bits(component, ALC5632_PWR_DOWN_CTRL_STATUS,
+				ALC5632_PWR_DOWN_CTRL_STATUS_MASK,
+				0xffff ^ (ALC5632_PWR_VREF_PR3
+				| ALC5632_PWR_VREF_PR2));
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* everything off, dac mute, inactive */
+		snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD2,
+				ALC5632_PWR_MANAG_ADD2_MASK, 0);
+		snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD3,
+				ALC5632_PWR_MANAG_ADD3_MASK, 0);
+		snd_soc_component_update_bits(component, ALC5632_PWR_MANAG_ADD1,
+				ALC5632_PWR_MANAG_ADD1_MASK, 0);
+		break;
+	}
+	return 0;
+}
+
+#define ALC5632_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE \
+			| SNDRV_PCM_FMTBIT_S24_LE \
+			| SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops alc5632_dai_ops = {
+		.hw_params = alc5632_pcm_hw_params,
+		.digital_mute = alc5632_mute,
+		.set_fmt = alc5632_set_dai_fmt,
+		.set_sysclk = alc5632_set_dai_sysclk,
+		.set_pll = alc5632_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver alc5632_dai = {
+	.name = "alc5632-hifi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =	8000,
+		.rate_max =	48000,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = ALC5632_FORMATS,},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =	8000,
+		.rate_max =	48000,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = ALC5632_FORMATS,},
+
+	.ops = &alc5632_dai_ops,
+	.symmetric_rates = 1,
+};
+
+#ifdef CONFIG_PM
+static int alc5632_resume(struct snd_soc_component *component)
+{
+	struct alc5632_priv *alc5632 = snd_soc_component_get_drvdata(component);
+
+	regcache_sync(alc5632->regmap);
+
+	return 0;
+}
+#else
+#define	alc5632_resume	NULL
+#endif
+
+static int alc5632_probe(struct snd_soc_component *component)
+{
+	struct alc5632_priv *alc5632 = snd_soc_component_get_drvdata(component);
+
+	switch (alc5632->id) {
+	case 0x5c:
+		snd_soc_add_component_controls(component, alc5632_vol_snd_controls,
+			ARRAY_SIZE(alc5632_vol_snd_controls));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_device_alc5632 = {
+	.probe			= alc5632_probe,
+	.resume			= alc5632_resume,
+	.set_bias_level		= alc5632_set_bias_level,
+	.controls		= alc5632_snd_controls,
+	.num_controls		= ARRAY_SIZE(alc5632_snd_controls),
+	.dapm_widgets		= alc5632_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(alc5632_dapm_widgets),
+	.dapm_routes		= alc5632_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(alc5632_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config alc5632_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = ALC5632_MAX_REGISTER,
+	.reg_defaults = alc5632_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(alc5632_reg_defaults),
+	.volatile_reg = alc5632_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+/*
+ * alc5632 2 wire address is determined by A1 pin
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+static int alc5632_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct alc5632_priv *alc5632;
+	int ret, ret1, ret2;
+	unsigned int vid1, vid2;
+
+	alc5632 = devm_kzalloc(&client->dev,
+			 sizeof(struct alc5632_priv), GFP_KERNEL);
+	if (alc5632 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, alc5632);
+
+	alc5632->regmap = devm_regmap_init_i2c(client, &alc5632_regmap);
+	if (IS_ERR(alc5632->regmap)) {
+		ret = PTR_ERR(alc5632->regmap);
+		dev_err(&client->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	ret1 = regmap_read(alc5632->regmap, ALC5632_VENDOR_ID1, &vid1);
+	ret2 = regmap_read(alc5632->regmap, ALC5632_VENDOR_ID2, &vid2);
+	if (ret1 != 0 || ret2 != 0) {
+		dev_err(&client->dev,
+		"Failed to read chip ID: ret1=%d, ret2=%d\n", ret1, ret2);
+		return -EIO;
+	}
+
+	vid2 >>= 8;
+
+	if ((vid1 != 0x10EC) || (vid2 != id->driver_data)) {
+		dev_err(&client->dev,
+		"Device is not a ALC5632: VID1=0x%x, VID2=0x%x\n", vid1, vid2);
+		return -EINVAL;
+	}
+
+	ret = alc5632_reset(alc5632->regmap);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	alc5632->id = vid2;
+	switch (alc5632->id) {
+	case 0x5c:
+		alc5632_dai.name = "alc5632-hifi";
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = devm_snd_soc_register_component(&client->dev,
+		&soc_component_device_alc5632, &alc5632_dai, 1);
+
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to register component: %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static const struct i2c_device_id alc5632_i2c_table[] = {
+	{"alc5632", 0x5c},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, alc5632_i2c_table);
+
+static const struct of_device_id alc5632_of_match[] = {
+	{ .compatible = "realtek,alc5632", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, alc5632_of_match);
+
+/* i2c codec control layer */
+static struct i2c_driver alc5632_i2c_driver = {
+	.driver = {
+		.name = "alc5632",
+		.of_match_table = of_match_ptr(alc5632_of_match),
+	},
+	.probe = alc5632_i2c_probe,
+	.id_table = alc5632_i2c_table,
+};
+
+module_i2c_driver(alc5632_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ALC5632 driver");
+MODULE_AUTHOR("Leon Romanovsky <leon@leon.nu>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/alc5632.h b/sound/soc/codecs/alc5632.h
new file mode 100644
index 0000000..1b5bda5
--- /dev/null
+++ b/sound/soc/codecs/alc5632.h
@@ -0,0 +1,252 @@
+/*
+* alc5632.h  --  ALC5632 ALSA SoC Audio Codec
+*
+* Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+*
+* Authors:  Leon Romanovsky <leon@leon.nu>
+*           Andrey Danin <danindrey@mail.ru>
+*           Ilya Petrov <ilya.muromec@gmail.com>
+*           Marc Dietrich <marvin24@gmx.de>
+*
+* Based on alc5623.h by Arnaud Patard
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*/
+
+#ifndef _ALC5632_H
+#define _ALC5632_H
+
+#define ALC5632_RESET				0x00
+/* speaker output vol		   2    2           */
+/* line output vol                      4    2      */
+/* HP output vol		   4    0    4      */
+#define ALC5632_SPK_OUT_VOL			0x02 /* spe out vol */
+#define ALC5632_SPK_OUT_VOL_STEP		1.5
+#define ALC5632_HP_OUT_VOL			0x04 /* hp out vol */
+#define ALC5632_AUX_OUT_VOL			0x06 /* aux out vol */
+#define ALC5632_PHONE_IN_VOL			0x08 /* phone in vol */
+#define ALC5632_LINE_IN_VOL			0x0A /* line in vol */
+#define ALC5632_STEREO_DAC_IN_VOL		0x0C /* stereo dac in vol */
+#define ALC5632_MIC_VOL				0x0E /* mic in vol */
+/* stero dac/mic routing */
+#define ALC5632_MIC_ROUTING_CTRL		0x10
+#define ALC5632_MIC_ROUTE_MONOMIX		(1 << 0)
+#define ALC5632_MIC_ROUTE_SPK			(1 << 1)
+#define ALC5632_MIC_ROUTE_HP			(1 << 2)
+
+#define ALC5632_ADC_REC_GAIN			0x12 /* rec gain */
+#define ALC5632_ADC_REC_GAIN_RANGE		0x1F1F
+#define ALC5632_ADC_REC_GAIN_BASE		(-16.5)
+#define ALC5632_ADC_REC_GAIN_STEP		1.5
+
+#define ALC5632_ADC_REC_MIXER			0x14 /* mixer control */
+#define ALC5632_ADC_REC_MIC1			(1 << 6)
+#define ALC5632_ADC_REC_MIC2			(1 << 5)
+#define ALC5632_ADC_REC_LINE_IN			(1 << 4)
+#define ALC5632_ADC_REC_AUX			(1 << 3)
+#define ALC5632_ADC_REC_HP			(1 << 2)
+#define ALC5632_ADC_REC_SPK			(1 << 1)
+#define ALC5632_ADC_REC_MONOMIX			(1 << 0)
+
+#define ALC5632_VOICE_DAC_VOL			0x18 /* voice dac vol */
+#define ALC5632_I2S_OUT_CTL				0x1A /* undocumented reg. found in path scheme */
+/* ALC5632_OUTPUT_MIXER_CTRL :			*/
+/* same remark as for reg 2 line vs speaker	*/
+#define ALC5632_OUTPUT_MIXER_CTRL		0x1C /* out mix ctrl */
+#define ALC5632_OUTPUT_MIXER_RP			(1 << 14)
+#define ALC5632_OUTPUT_MIXER_WEEK		(1 << 12)
+#define ALC5632_OUTPUT_MIXER_HP			(1 << 10)
+#define ALC5632_OUTPUT_MIXER_AUX_SPK		(2 <<  6)
+#define ALC5632_OUTPUT_MIXER_AUX_HP_LR          (1 << 6)
+#define ALC5632_OUTPUT_MIXER_HP_R               (1 << 8)
+#define ALC5632_OUTPUT_MIXER_HP_L               (1 << 9)
+
+#define ALC5632_MIC_CTRL			0x22 /* mic phone ctrl */
+#define ALC5632_MIC_BOOST_BYPASS		0
+#define ALC5632_MIC_BOOST_20DB			1
+#define ALC5632_MIC_BOOST_30DB			2
+#define ALC5632_MIC_BOOST_40DB			3
+
+#define ALC5632_DIGI_BOOST_CTRL			0x24 /* digi mic / bost ctl */
+#define ALC5632_MIC_BOOST_RANGE			7
+#define ALC5632_MIC_BOOST_STEP			6
+#define ALC5632_PWR_DOWN_CTRL_STATUS		0x26
+#define ALC5632_PWR_DOWN_CTRL_STATUS_MASK	0xEF00
+#define ALC5632_PWR_VREF_PR3			(1 << 11)
+#define ALC5632_PWR_VREF_PR2			(1 << 10)
+#define ALC5632_PWR_VREF_STATUS			(1 << 3)
+#define ALC5632_PWR_AMIX_STATUS			(1 << 2)
+#define ALC5632_PWR_DAC_STATUS			(1 << 1)
+#define ALC5632_PWR_ADC_STATUS			(1 << 0)
+/* stereo/voice DAC / stereo adc func ctrl */
+#define ALC5632_DAC_FUNC_SELECT			0x2E
+
+/* Main serial data port ctrl (i2s) */
+#define ALC5632_DAI_CONTROL			0x34
+
+#define ALC5632_DAI_SDP_MASTER_MODE		(0 << 15)
+#define ALC5632_DAI_SDP_SLAVE_MODE		(1 << 15)
+#define ALC5632_DAI_SADLRCK_MODE		(1 << 14)
+/* 0:voice, 1:main */
+#define ALC5632_DAI_MAIN_I2S_SYSCLK_SEL		(1 <<  8)
+#define ALC5632_DAI_MAIN_I2S_BCLK_POL_CTRL	(1 <<  7)
+/* 0:normal, 1:invert */
+#define ALC5632_DAI_MAIN_I2S_LRCK_INV		(1 <<  6)
+#define ALC5632_DAI_I2S_DL_MASK			(3 <<  2)
+#define ALC5632_DAI_I2S_DL_8			(3 <<  2)
+#define	ALC5632_DAI_I2S_DL_24			(2 <<  2)
+#define	ALC5632_DAI_I2S_DL_20			(1 <<  2)
+#define ALC5632_DAI_I2S_DL_16			(0 <<  2)
+#define ALC5632_DAI_I2S_DF_MASK			(3 <<  0)
+#define ALC5632_DAI_I2S_DF_PCM_B		(3 <<  0)
+#define	ALC5632_DAI_I2S_DF_PCM_A		(2 <<  0)
+#define ALC5632_DAI_I2S_DF_LEFT			(1 <<  0)
+#define ALC5632_DAI_I2S_DF_I2S			(0 <<  0)
+/* extend serial data port control (VoDAC_i2c/pcm) */
+#define ALC5632_DAI_CONTROL2			0x36
+/* 0:gpio func, 1:voice pcm */
+#define ALC5632_DAI_VOICE_PCM_ENABLE		(1 << 15)
+/* 0:master, 1:slave */
+#define ALC5632_DAI_VOICE_MODE_SEL		(1 << 14)
+/* 0:disable, 1:enable */
+#define ALC5632_DAI_HPF_CLK_CTRL		(1 << 13)
+/* 0:main, 1:voice */
+#define ALC5632_DAI_VOICE_I2S_SYSCLK_SEL	(1 <<  8)
+/* 0:normal, 1:invert */
+#define ALC5632_DAI_VOICE_VBCLK_SYSCLK_SEL	(1 <<  7)
+/* 0:normal, 1:invert */
+#define ALC5632_DAI_VOICE_I2S_LR_INV		(1 <<  6)
+#define ALC5632_DAI_VOICE_DL_MASK		(3 <<  2)
+#define ALC5632_DAI_VOICE_DL_16			(0 <<  2)
+#define ALC5632_DAI_VOICE_DL_20			(1 <<  2)
+#define ALC5632_DAI_VOICE_DL_24			(2 <<  2)
+#define ALC5632_DAI_VOICE_DL_8			(3 <<  2)
+#define ALC5632_DAI_VOICE_DF_MASK		(3 <<  0)
+#define ALC5632_DAI_VOICE_DF_I2S		(0 <<  0)
+#define ALC5632_DAI_VOICE_DF_LEFT		(1 <<  0)
+#define ALC5632_DAI_VOICE_DF_PCM_A		(2 <<  0)
+#define ALC5632_DAI_VOICE_DF_PCM_B		(3 <<  0)
+
+#define	ALC5632_PWR_MANAG_ADD1			0x3A
+#define	ALC5632_PWR_MANAG_ADD1_MASK		0xEFFF
+#define ALC5632_PWR_ADD1_DAC_L_EN		(1 << 15)
+#define ALC5632_PWR_ADD1_DAC_R_EN		(1 << 14)
+#define ALC5632_PWR_ADD1_ZERO_CROSS		(1 << 13)
+#define ALC5632_PWR_ADD1_MAIN_I2S_EN		(1 << 11)
+#define ALC5632_PWR_ADD1_SPK_AMP_EN		(1 << 10)
+#define ALC5632_PWR_ADD1_HP_OUT_AMP		(1 <<  9)
+#define ALC5632_PWR_ADD1_HP_OUT_ENH_AMP		(1 <<  8)
+#define ALC5632_PWR_ADD1_VOICE_DAC_MIX		(1 <<  7)
+#define	ALC5632_PWR_ADD1_SOFTGEN_EN		(1 <<  6)
+#define	ALC5632_PWR_ADD1_MIC1_SHORT_CURR	(1 <<  5)
+#define	ALC5632_PWR_ADD1_MIC2_SHORT_CURR	(1 <<  4)
+#define	ALC5632_PWR_ADD1_MIC1_EN		(1 <<  3)
+#define	ALC5632_PWR_ADD1_MIC2_EN		(1 <<  2)
+#define ALC5632_PWR_ADD1_MAIN_BIAS		(1 <<  1)
+#define ALC5632_PWR_ADD1_DAC_REF		(1 <<  0)
+
+#define ALC5632_PWR_MANAG_ADD2			0x3C
+#define ALC5632_PWR_MANAG_ADD2_MASK		0x7FFF
+#define ALC5632_PWR_ADD2_PLL1			(1 << 15)
+#define ALC5632_PWR_ADD2_PLL2			(1 << 14)
+#define ALC5632_PWR_ADD2_VREF			(1 << 13)
+#define ALC5632_PWR_ADD2_OVT_DET		(1 << 12)
+#define ALC5632_PWR_ADD2_VOICE_DAC		(1 << 10)
+#define ALC5632_PWR_ADD2_L_DAC_CLK		(1 <<  9)
+#define ALC5632_PWR_ADD2_R_DAC_CLK		(1 <<  8)
+#define ALC5632_PWR_ADD2_L_ADC_CLK_GAIN		(1 <<  7)
+#define ALC5632_PWR_ADD2_R_ADC_CLK_GAIN		(1 <<  6)
+#define ALC5632_PWR_ADD2_L_HP_MIXER		(1 <<  5)
+#define ALC5632_PWR_ADD2_R_HP_MIXER		(1 <<  4)
+#define ALC5632_PWR_ADD2_SPK_MIXER		(1 <<  3)
+#define ALC5632_PWR_ADD2_MONO_MIXER		(1 <<  2)
+#define ALC5632_PWR_ADD2_L_ADC_REC_MIXER	(1 <<  1)
+#define ALC5632_PWR_ADD2_R_ADC_REC_MIXER	(1 <<  0)
+
+#define ALC5632_PWR_MANAG_ADD3			0x3E
+#define ALC5632_PWR_MANAG_ADD3_MASK		0x7CFF
+#define ALC5632_PWR_ADD3_AUXOUT_VOL		(1 << 14)
+#define ALC5632_PWR_ADD3_SPK_L_OUT		(1 << 13)
+#define ALC5632_PWR_ADD3_SPK_R_OUT		(1 << 12)
+#define ALC5632_PWR_ADD3_HP_L_OUT_VOL		(1 << 11)
+#define ALC5632_PWR_ADD3_HP_R_OUT_VOL		(1 << 10)
+#define ALC5632_PWR_ADD3_LINEIN_L_VOL		(1 <<  7)
+#define ALC5632_PWR_ADD3_LINEIN_R_VOL		(1 <<  6)
+#define ALC5632_PWR_ADD3_AUXIN_VOL		(1 <<  5)
+#define ALC5632_PWR_ADD3_AUXIN_MIX		(1 <<  4)
+#define ALC5632_PWR_ADD3_MIC1_VOL		(1 <<  3)
+#define ALC5632_PWR_ADD3_MIC2_VOL		(1 <<  2)
+#define ALC5632_PWR_ADD3_MIC1_BOOST_AD		(1 <<  1)
+#define ALC5632_PWR_ADD3_MIC2_BOOST_AD		(1 <<  0)
+
+#define ALC5632_GPCR1				0x40
+#define ALC5632_GPCR1_CLK_SYS_SRC_SEL_PLL1	(1 << 15)
+#define ALC5632_GPCR1_CLK_SYS_SRC_SEL_MCLK	(0 << 15)
+#define ALC5632_GPCR1_DAC_HI_FLT_EN		(1 << 10)
+#define ALC5632_GPCR1_SPK_AMP_CTRL		(7 <<  1)
+#define ALC5632_GPCR1_VDD_100			(5 <<  1)
+#define ALC5632_GPCR1_VDD_125			(4 <<  1)
+#define ALC5632_GPCR1_VDD_150			(3 <<  1)
+#define ALC5632_GPCR1_VDD_175			(2 <<  1)
+#define ALC5632_GPCR1_VDD_200			(1 <<  1)
+#define ALC5632_GPCR1_VDD_225			(0 <<  1)
+
+#define	ALC5632_GPCR2				0x42
+#define ALC5632_GPCR2_PLL1_SOUR_SEL		(3 << 12)
+#define ALC5632_PLL_FR_MCLK			(0 << 12)
+#define ALC5632_PLL_FR_BCLK			(2 << 12)
+#define ALC5632_PLL_FR_VBCLK			(3 << 12)
+#define ALC5632_GPCR2_CLK_PLL_PRE_DIV1		(0 <<  0)
+
+#define ALC5632_PLL1_CTRL			0x44
+#define ALC5632_PLL1_CTRL_N_VAL(n)		(((n) & 0x0f) << 8)
+#define ALC5632_PLL1_M_BYPASS			(1 <<  7)
+#define ALC5632_PLL1_CTRL_K_VAL(k)		(((k) & 0x07) << 4)
+#define ALC5632_PLL1_CTRL_M_VAL(m)		(((m) & 0x0f) << 0)
+
+#define ALC5632_PLL2_CTRL			0x46
+#define ALC5632_PLL2_EN				(1 << 15)
+#define ALC5632_PLL2_RATIO			(0 << 15)
+
+#define ALC5632_GPIO_PIN_CONFIG			0x4C
+#define ALC5632_GPIO_PIN_POLARITY		0x4E
+#define ALC5632_GPIO_PIN_STICKY			0x50
+#define ALC5632_GPIO_PIN_WAKEUP			0x52
+#define ALC5632_GPIO_PIN_STATUS			0x54
+#define ALC5632_GPIO_PIN_SHARING		0x56
+#define	ALC5632_OVER_CURR_STATUS		0x58
+#define ALC5632_SOFTVOL_CTRL			0x5A
+#define ALC5632_GPIO_OUPUT_PIN_CTRL		0x5C
+
+#define ALC5632_MISC_CTRL			0x5E
+#define ALC5632_MISC_DISABLE_FAST_VREG		(1 << 15)
+#define ALC5632_MISC_AVC_TRGT_SEL		(3 << 12)
+#define ALC5632_MISC_AVC_TRGT_RIGHT		(1 << 12)
+#define ALC5632_MISC_AVC_TRGT_LEFT		(2 << 12)
+#define ALC5632_MISC_AVC_TRGT_BOTH		(3 << 12)
+#define ALC5632_MISC_HP_DEPOP_MODE1_EN		(1 <<  9)
+#define ALC5632_MISC_HP_DEPOP_MODE2_EN		(1 <<  8)
+#define ALC5632_MISC_HP_DEPOP_MUTE_L		(1 <<  7)
+#define ALC5632_MISC_HP_DEPOP_MUTE_R		(1 <<  6)
+#define ALC5632_MISC_HP_DEPOP_MUTE		(1 <<  5)
+#define ALC5632_MISC_GPIO_WAKEUP_CTRL		(1 <<  1)
+#define ALC5632_MISC_IRQOUT_INV_CTRL		(1 <<  0)
+
+#define ALC5632_DAC_CLK_CTRL1			0x60
+#define ALC5632_DAC_CLK_CTRL2			0x62
+#define ALC5632_DAC_CLK_CTRL2_DIV1_2		(1 << 0)
+#define ALC5632_VOICE_DAC_PCM_CLK_CTRL1		0x64
+#define ALC5632_PSEUDO_SPATIAL_CTRL		0x68
+#define ALC5632_HID_CTRL_INDEX			0x6A
+#define ALC5632_HID_CTRL_DATA			0x6C
+#define ALC5632_EQ_CTRL				0x6E
+
+/* undocumented */
+#define ALC5632_VENDOR_ID1			0x7C
+#define ALC5632_VENDOR_ID2			0x7E
+
+#define ALC5632_MAX_REGISTER        0x7E
+
+#endif
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
new file mode 100644
index 0000000..5727ea0
--- /dev/null
+++ b/sound/soc/codecs/arizona.c
@@ -0,0 +1,2863 @@
+/*
+ * arizona.c - Wolfson Arizona class device shared support
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/gcd.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+
+#define ARIZONA_AIF_BCLK_CTRL                   0x00
+#define ARIZONA_AIF_TX_PIN_CTRL                 0x01
+#define ARIZONA_AIF_RX_PIN_CTRL                 0x02
+#define ARIZONA_AIF_RATE_CTRL                   0x03
+#define ARIZONA_AIF_FORMAT                      0x04
+#define ARIZONA_AIF_TX_BCLK_RATE                0x05
+#define ARIZONA_AIF_RX_BCLK_RATE                0x06
+#define ARIZONA_AIF_FRAME_CTRL_1                0x07
+#define ARIZONA_AIF_FRAME_CTRL_2                0x08
+#define ARIZONA_AIF_FRAME_CTRL_3                0x09
+#define ARIZONA_AIF_FRAME_CTRL_4                0x0A
+#define ARIZONA_AIF_FRAME_CTRL_5                0x0B
+#define ARIZONA_AIF_FRAME_CTRL_6                0x0C
+#define ARIZONA_AIF_FRAME_CTRL_7                0x0D
+#define ARIZONA_AIF_FRAME_CTRL_8                0x0E
+#define ARIZONA_AIF_FRAME_CTRL_9                0x0F
+#define ARIZONA_AIF_FRAME_CTRL_10               0x10
+#define ARIZONA_AIF_FRAME_CTRL_11               0x11
+#define ARIZONA_AIF_FRAME_CTRL_12               0x12
+#define ARIZONA_AIF_FRAME_CTRL_13               0x13
+#define ARIZONA_AIF_FRAME_CTRL_14               0x14
+#define ARIZONA_AIF_FRAME_CTRL_15               0x15
+#define ARIZONA_AIF_FRAME_CTRL_16               0x16
+#define ARIZONA_AIF_FRAME_CTRL_17               0x17
+#define ARIZONA_AIF_FRAME_CTRL_18               0x18
+#define ARIZONA_AIF_TX_ENABLES                  0x19
+#define ARIZONA_AIF_RX_ENABLES                  0x1A
+#define ARIZONA_AIF_FORCE_WRITE                 0x1B
+
+#define ARIZONA_FLL_VCO_CORNER 141900000
+#define ARIZONA_FLL_MAX_FREF   13500000
+#define ARIZONA_FLL_MIN_FVCO   90000000
+#define ARIZONA_FLL_MAX_FRATIO 16
+#define ARIZONA_FLL_MAX_REFDIV 8
+#define ARIZONA_FLL_MIN_OUTDIV 2
+#define ARIZONA_FLL_MAX_OUTDIV 7
+
+#define ARIZONA_FMT_DSP_MODE_A          0
+#define ARIZONA_FMT_DSP_MODE_B          1
+#define ARIZONA_FMT_I2S_MODE            2
+#define ARIZONA_FMT_LEFT_JUSTIFIED_MODE 3
+
+#define arizona_fll_err(_fll, fmt, ...) \
+	dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
+#define arizona_fll_warn(_fll, fmt, ...) \
+	dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
+#define arizona_fll_dbg(_fll, fmt, ...) \
+	dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
+
+#define arizona_aif_err(_dai, fmt, ...) \
+	dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
+#define arizona_aif_warn(_dai, fmt, ...) \
+	dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
+#define arizona_aif_dbg(_dai, fmt, ...) \
+	dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
+
+static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol,
+			  int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+	int val;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		val = snd_soc_component_read32(component,
+					       ARIZONA_INTERRUPT_RAW_STATUS_3);
+		if (val & ARIZONA_SPK_OVERHEAT_STS) {
+			dev_crit(arizona->dev,
+				 "Speaker not enabled due to temperature\n");
+			return -EBUSY;
+		}
+
+		regmap_update_bits_async(arizona->regmap,
+					 ARIZONA_OUTPUT_ENABLES_1,
+					 1 << w->shift, 1 << w->shift);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_update_bits_async(arizona->regmap,
+					 ARIZONA_OUTPUT_ENABLES_1,
+					 1 << w->shift, 0);
+		break;
+	default:
+		break;
+	}
+
+	return arizona_out_ev(w, kcontrol, event);
+}
+
+static irqreturn_t arizona_thermal_warn(int irq, void *data)
+{
+	struct arizona *arizona = data;
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
+			  &val);
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to read thermal status: %d\n",
+			ret);
+	} else if (val & ARIZONA_SPK_OVERHEAT_WARN_STS) {
+		dev_crit(arizona->dev, "Thermal warning\n");
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
+{
+	struct arizona *arizona = data;
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
+			  &val);
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to read thermal status: %d\n",
+			ret);
+	} else if (val & ARIZONA_SPK_OVERHEAT_STS) {
+		dev_crit(arizona->dev, "Thermal shutdown\n");
+		ret = regmap_update_bits(arizona->regmap,
+					 ARIZONA_OUTPUT_ENABLES_1,
+					 ARIZONA_OUT4L_ENA |
+					 ARIZONA_OUT4R_ENA, 0);
+		if (ret != 0)
+			dev_crit(arizona->dev,
+				 "Failed to disable speaker outputs: %d\n",
+				 ret);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static const struct snd_soc_dapm_widget arizona_spkl =
+	SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
+			   ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD);
+
+static const struct snd_soc_dapm_widget arizona_spkr =
+	SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
+			   ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD);
+
+int arizona_init_spk(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+	int ret;
+
+	ret = snd_soc_dapm_new_controls(dapm, &arizona_spkl, 1);
+	if (ret != 0)
+		return ret;
+
+	switch (arizona->type) {
+	case WM8997:
+	case CS47L24:
+	case WM1831:
+		break;
+	default:
+		ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1);
+		if (ret != 0)
+			return ret;
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_spk);
+
+int arizona_init_spk_irqs(struct arizona *arizona)
+{
+	int ret;
+
+	ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,
+				  "Thermal warning", arizona_thermal_warn,
+				  arizona);
+	if (ret != 0)
+		dev_err(arizona->dev,
+			"Failed to get thermal warning IRQ: %d\n",
+			ret);
+
+	ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT,
+				  "Thermal shutdown", arizona_thermal_shutdown,
+				  arizona);
+	if (ret != 0)
+		dev_err(arizona->dev,
+			"Failed to get thermal shutdown IRQ: %d\n",
+			ret);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_spk_irqs);
+
+int arizona_free_spk_irqs(struct arizona *arizona)
+{
+	arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, arizona);
+	arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT, arizona);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_free_spk_irqs);
+
+static const struct snd_soc_dapm_route arizona_mono_routes[] = {
+	{ "OUT1R", NULL, "OUT1L" },
+	{ "OUT2R", NULL, "OUT2L" },
+	{ "OUT3R", NULL, "OUT3L" },
+	{ "OUT4R", NULL, "OUT4L" },
+	{ "OUT5R", NULL, "OUT5L" },
+	{ "OUT6R", NULL, "OUT6L" },
+};
+
+int arizona_init_mono(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+	int i;
+
+	for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
+		if (arizona->pdata.out_mono[i])
+			snd_soc_dapm_add_routes(dapm,
+						&arizona_mono_routes[i], 1);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_mono);
+
+int arizona_init_gpio(struct snd_soc_component *component)
+{
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+	int i;
+
+	switch (arizona->type) {
+	case WM5110:
+	case WM8280:
+		snd_soc_component_disable_pin(component,
+					      "DRC2 Signal Activity");
+		break;
+	default:
+		break;
+	}
+
+	snd_soc_component_disable_pin(component, "DRC1 Signal Activity");
+
+	for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
+		switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
+		case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
+			snd_soc_component_enable_pin(component,
+						     "DRC1 Signal Activity");
+			break;
+		case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
+			snd_soc_component_enable_pin(component,
+						     "DRC2 Signal Activity");
+			break;
+		default:
+			break;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_gpio);
+
+int arizona_init_common(struct arizona *arizona)
+{
+	struct arizona_pdata *pdata = &arizona->pdata;
+	unsigned int val, mask;
+	int i;
+
+	BLOCKING_INIT_NOTIFIER_HEAD(&arizona->notifier);
+
+	for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
+		/* Default is 0 so noop with defaults */
+		if (pdata->out_mono[i])
+			val = ARIZONA_OUT1_MONO;
+		else
+			val = 0;
+
+		regmap_update_bits(arizona->regmap,
+				   ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8),
+				   ARIZONA_OUT1_MONO, val);
+	}
+
+	for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) {
+		if (pdata->spk_mute[i])
+			regmap_update_bits(arizona->regmap,
+					   ARIZONA_PDM_SPK1_CTRL_1 + (i * 2),
+					   ARIZONA_SPK1_MUTE_ENDIAN_MASK |
+					   ARIZONA_SPK1_MUTE_SEQ1_MASK,
+					   pdata->spk_mute[i]);
+
+		if (pdata->spk_fmt[i])
+			regmap_update_bits(arizona->regmap,
+					   ARIZONA_PDM_SPK1_CTRL_2 + (i * 2),
+					   ARIZONA_SPK1_FMT_MASK,
+					   pdata->spk_fmt[i]);
+	}
+
+	for (i = 0; i < ARIZONA_MAX_INPUT; i++) {
+		/* Default for both is 0 so noop with defaults */
+		val = pdata->dmic_ref[i] << ARIZONA_IN1_DMIC_SUP_SHIFT;
+		if (pdata->inmode[i] & ARIZONA_INMODE_DMIC)
+			val |= 1 << ARIZONA_IN1_MODE_SHIFT;
+
+		switch (arizona->type) {
+		case WM8998:
+		case WM1814:
+			regmap_update_bits(arizona->regmap,
+				ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 8),
+				ARIZONA_IN1L_SRC_SE_MASK,
+				(pdata->inmode[i] & ARIZONA_INMODE_SE)
+					<< ARIZONA_IN1L_SRC_SE_SHIFT);
+
+			regmap_update_bits(arizona->regmap,
+				ARIZONA_ADC_DIGITAL_VOLUME_1R + (i * 8),
+				ARIZONA_IN1R_SRC_SE_MASK,
+				(pdata->inmode[i] & ARIZONA_INMODE_SE)
+					<< ARIZONA_IN1R_SRC_SE_SHIFT);
+
+			mask = ARIZONA_IN1_DMIC_SUP_MASK |
+			       ARIZONA_IN1_MODE_MASK;
+			break;
+		default:
+			if (pdata->inmode[i] & ARIZONA_INMODE_SE)
+				val |= 1 << ARIZONA_IN1_SINGLE_ENDED_SHIFT;
+
+			mask = ARIZONA_IN1_DMIC_SUP_MASK |
+			       ARIZONA_IN1_MODE_MASK |
+			       ARIZONA_IN1_SINGLE_ENDED_MASK;
+			break;
+		}
+
+		regmap_update_bits(arizona->regmap,
+				   ARIZONA_IN1L_CONTROL + (i * 8),
+				   mask, val);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_common);
+
+int arizona_init_vol_limit(struct arizona *arizona)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(arizona->pdata.out_vol_limit); ++i) {
+		if (arizona->pdata.out_vol_limit[i])
+			regmap_update_bits(arizona->regmap,
+					   ARIZONA_DAC_VOLUME_LIMIT_1L + i * 4,
+					   ARIZONA_OUT1L_VOL_LIM_MASK,
+					   arizona->pdata.out_vol_limit[i]);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_vol_limit);
+
+const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
+	"None",
+	"Tone Generator 1",
+	"Tone Generator 2",
+	"Haptics",
+	"AEC",
+	"AEC2",
+	"Mic Mute Mixer",
+	"Noise Generator",
+	"IN1L",
+	"IN1R",
+	"IN2L",
+	"IN2R",
+	"IN3L",
+	"IN3R",
+	"IN4L",
+	"IN4R",
+	"AIF1RX1",
+	"AIF1RX2",
+	"AIF1RX3",
+	"AIF1RX4",
+	"AIF1RX5",
+	"AIF1RX6",
+	"AIF1RX7",
+	"AIF1RX8",
+	"AIF2RX1",
+	"AIF2RX2",
+	"AIF2RX3",
+	"AIF2RX4",
+	"AIF2RX5",
+	"AIF2RX6",
+	"AIF3RX1",
+	"AIF3RX2",
+	"SLIMRX1",
+	"SLIMRX2",
+	"SLIMRX3",
+	"SLIMRX4",
+	"SLIMRX5",
+	"SLIMRX6",
+	"SLIMRX7",
+	"SLIMRX8",
+	"EQ1",
+	"EQ2",
+	"EQ3",
+	"EQ4",
+	"DRC1L",
+	"DRC1R",
+	"DRC2L",
+	"DRC2R",
+	"LHPF1",
+	"LHPF2",
+	"LHPF3",
+	"LHPF4",
+	"DSP1.1",
+	"DSP1.2",
+	"DSP1.3",
+	"DSP1.4",
+	"DSP1.5",
+	"DSP1.6",
+	"DSP2.1",
+	"DSP2.2",
+	"DSP2.3",
+	"DSP2.4",
+	"DSP2.5",
+	"DSP2.6",
+	"DSP3.1",
+	"DSP3.2",
+	"DSP3.3",
+	"DSP3.4",
+	"DSP3.5",
+	"DSP3.6",
+	"DSP4.1",
+	"DSP4.2",
+	"DSP4.3",
+	"DSP4.4",
+	"DSP4.5",
+	"DSP4.6",
+	"ASRC1L",
+	"ASRC1R",
+	"ASRC2L",
+	"ASRC2R",
+	"ISRC1INT1",
+	"ISRC1INT2",
+	"ISRC1INT3",
+	"ISRC1INT4",
+	"ISRC1DEC1",
+	"ISRC1DEC2",
+	"ISRC1DEC3",
+	"ISRC1DEC4",
+	"ISRC2INT1",
+	"ISRC2INT2",
+	"ISRC2INT3",
+	"ISRC2INT4",
+	"ISRC2DEC1",
+	"ISRC2DEC2",
+	"ISRC2DEC3",
+	"ISRC2DEC4",
+	"ISRC3INT1",
+	"ISRC3INT2",
+	"ISRC3INT3",
+	"ISRC3INT4",
+	"ISRC3DEC1",
+	"ISRC3DEC2",
+	"ISRC3DEC3",
+	"ISRC3DEC4",
+};
+EXPORT_SYMBOL_GPL(arizona_mixer_texts);
+
+unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
+	0x00,  /* None */
+	0x04,  /* Tone */
+	0x05,
+	0x06,  /* Haptics */
+	0x08,  /* AEC */
+	0x09,  /* AEC2 */
+	0x0c,  /* Noise mixer */
+	0x0d,  /* Comfort noise */
+	0x10,  /* IN1L */
+	0x11,
+	0x12,
+	0x13,
+	0x14,
+	0x15,
+	0x16,
+	0x17,
+	0x20,  /* AIF1RX1 */
+	0x21,
+	0x22,
+	0x23,
+	0x24,
+	0x25,
+	0x26,
+	0x27,
+	0x28,  /* AIF2RX1 */
+	0x29,
+	0x2a,
+	0x2b,
+	0x2c,
+	0x2d,
+	0x30,  /* AIF3RX1 */
+	0x31,
+	0x38,  /* SLIMRX1 */
+	0x39,
+	0x3a,
+	0x3b,
+	0x3c,
+	0x3d,
+	0x3e,
+	0x3f,
+	0x50,  /* EQ1 */
+	0x51,
+	0x52,
+	0x53,
+	0x58,  /* DRC1L */
+	0x59,
+	0x5a,
+	0x5b,
+	0x60,  /* LHPF1 */
+	0x61,
+	0x62,
+	0x63,
+	0x68,  /* DSP1.1 */
+	0x69,
+	0x6a,
+	0x6b,
+	0x6c,
+	0x6d,
+	0x70,  /* DSP2.1 */
+	0x71,
+	0x72,
+	0x73,
+	0x74,
+	0x75,
+	0x78,  /* DSP3.1 */
+	0x79,
+	0x7a,
+	0x7b,
+	0x7c,
+	0x7d,
+	0x80,  /* DSP4.1 */
+	0x81,
+	0x82,
+	0x83,
+	0x84,
+	0x85,
+	0x90,  /* ASRC1L */
+	0x91,
+	0x92,
+	0x93,
+	0xa0,  /* ISRC1INT1 */
+	0xa1,
+	0xa2,
+	0xa3,
+	0xa4,  /* ISRC1DEC1 */
+	0xa5,
+	0xa6,
+	0xa7,
+	0xa8,  /* ISRC2DEC1 */
+	0xa9,
+	0xaa,
+	0xab,
+	0xac,  /* ISRC2INT1 */
+	0xad,
+	0xae,
+	0xaf,
+	0xb0,  /* ISRC3DEC1 */
+	0xb1,
+	0xb2,
+	0xb3,
+	0xb4,  /* ISRC3INT1 */
+	0xb5,
+	0xb6,
+	0xb7,
+};
+EXPORT_SYMBOL_GPL(arizona_mixer_values);
+
+const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
+EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
+
+const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
+	"12kHz", "24kHz", "48kHz", "96kHz", "192kHz",
+	"11.025kHz", "22.05kHz", "44.1kHz", "88.2kHz", "176.4kHz",
+	"4kHz", "8kHz", "16kHz", "32kHz",
+};
+EXPORT_SYMBOL_GPL(arizona_sample_rate_text);
+
+const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
+	0x01, 0x02, 0x03, 0x04, 0x05, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+	0x10, 0x11, 0x12, 0x13,
+};
+EXPORT_SYMBOL_GPL(arizona_sample_rate_val);
+
+const char *arizona_sample_rate_val_to_name(unsigned int rate_val)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(arizona_sample_rate_val); ++i) {
+		if (arizona_sample_rate_val[i] == rate_val)
+			return arizona_sample_rate_text[i];
+	}
+
+	return "Illegal";
+}
+EXPORT_SYMBOL_GPL(arizona_sample_rate_val_to_name);
+
+const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
+	"SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
+};
+EXPORT_SYMBOL_GPL(arizona_rate_text);
+
+const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
+	0, 1, 2, 8,
+};
+EXPORT_SYMBOL_GPL(arizona_rate_val);
+
+const struct soc_enum arizona_isrc_fsh[] = {
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
+			      ARIZONA_ISRC1_FSH_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
+			      ARIZONA_ISRC2_FSH_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
+			      ARIZONA_ISRC3_FSH_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+};
+EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
+
+const struct soc_enum arizona_isrc_fsl[] = {
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
+			      ARIZONA_ISRC1_FSL_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
+			      ARIZONA_ISRC2_FSL_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
+			      ARIZONA_ISRC3_FSL_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+};
+EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
+
+const struct soc_enum arizona_asrc_rate1 =
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
+			      ARIZONA_ASRC_RATE1_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE - 1,
+			      arizona_rate_text, arizona_rate_val);
+EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
+
+static const char * const arizona_vol_ramp_text[] = {
+	"0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
+	"15ms/6dB", "30ms/6dB",
+};
+
+SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
+		     ARIZONA_INPUT_VOLUME_RAMP,
+		     ARIZONA_IN_VD_RAMP_SHIFT,
+		     arizona_vol_ramp_text);
+EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
+
+SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
+		     ARIZONA_INPUT_VOLUME_RAMP,
+		     ARIZONA_IN_VI_RAMP_SHIFT,
+		     arizona_vol_ramp_text);
+EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
+
+SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
+		     ARIZONA_OUTPUT_VOLUME_RAMP,
+		     ARIZONA_OUT_VD_RAMP_SHIFT,
+		     arizona_vol_ramp_text);
+EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
+
+SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
+		     ARIZONA_OUTPUT_VOLUME_RAMP,
+		     ARIZONA_OUT_VI_RAMP_SHIFT,
+		     arizona_vol_ramp_text);
+EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
+
+static const char * const arizona_lhpf_mode_text[] = {
+	"Low-pass", "High-pass"
+};
+
+SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
+		     ARIZONA_HPLPF1_1,
+		     ARIZONA_LHPF1_MODE_SHIFT,
+		     arizona_lhpf_mode_text);
+EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
+
+SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
+		     ARIZONA_HPLPF2_1,
+		     ARIZONA_LHPF2_MODE_SHIFT,
+		     arizona_lhpf_mode_text);
+EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
+
+SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
+		     ARIZONA_HPLPF3_1,
+		     ARIZONA_LHPF3_MODE_SHIFT,
+		     arizona_lhpf_mode_text);
+EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
+
+SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
+		     ARIZONA_HPLPF4_1,
+		     ARIZONA_LHPF4_MODE_SHIFT,
+		     arizona_lhpf_mode_text);
+EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
+
+static const char * const arizona_ng_hold_text[] = {
+	"30ms", "120ms", "250ms", "500ms",
+};
+
+SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
+		     ARIZONA_NOISE_GATE_CONTROL,
+		     ARIZONA_NGATE_HOLD_SHIFT,
+		     arizona_ng_hold_text);
+EXPORT_SYMBOL_GPL(arizona_ng_hold);
+
+static const char * const arizona_in_hpf_cut_text[] = {
+	"2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
+};
+
+SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
+		     ARIZONA_HPF_CONTROL,
+		     ARIZONA_IN_HPF_CUT_SHIFT,
+		     arizona_in_hpf_cut_text);
+EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
+
+static const char * const arizona_in_dmic_osr_text[] = {
+	"1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
+};
+
+const struct soc_enum arizona_in_dmic_osr[] = {
+	SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
+			ARRAY_SIZE(arizona_in_dmic_osr_text),
+			arizona_in_dmic_osr_text),
+	SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
+			ARRAY_SIZE(arizona_in_dmic_osr_text),
+			arizona_in_dmic_osr_text),
+	SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
+			ARRAY_SIZE(arizona_in_dmic_osr_text),
+			arizona_in_dmic_osr_text),
+	SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
+			ARRAY_SIZE(arizona_in_dmic_osr_text),
+			arizona_in_dmic_osr_text),
+};
+EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
+
+static const char * const arizona_anc_input_src_text[] = {
+	"None", "IN1", "IN2", "IN3", "IN4",
+};
+
+static const char * const arizona_anc_channel_src_text[] = {
+	"None", "Left", "Right", "Combine",
+};
+
+const struct soc_enum arizona_anc_input_src[] = {
+	SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
+			ARIZONA_IN_RXANCL_SEL_SHIFT,
+			ARRAY_SIZE(arizona_anc_input_src_text),
+			arizona_anc_input_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL,
+			ARIZONA_FCL_MIC_MODE_SEL_SHIFT,
+			ARRAY_SIZE(arizona_anc_channel_src_text),
+			arizona_anc_channel_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
+			ARIZONA_IN_RXANCR_SEL_SHIFT,
+			ARRAY_SIZE(arizona_anc_input_src_text),
+			arizona_anc_input_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL,
+			ARIZONA_FCR_MIC_MODE_SEL_SHIFT,
+			ARRAY_SIZE(arizona_anc_channel_src_text),
+			arizona_anc_channel_src_text),
+};
+EXPORT_SYMBOL_GPL(arizona_anc_input_src);
+
+static const char * const arizona_anc_ng_texts[] = {
+	"None",
+	"Internal",
+	"External",
+};
+
+SOC_ENUM_SINGLE_DECL(arizona_anc_ng_enum, SND_SOC_NOPM, 0,
+		     arizona_anc_ng_texts);
+EXPORT_SYMBOL_GPL(arizona_anc_ng_enum);
+
+static const char * const arizona_output_anc_src_text[] = {
+	"None", "RXANCL", "RXANCR",
+};
+
+const struct soc_enum arizona_output_anc_src[] = {
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
+			ARIZONA_OUT1L_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1R,
+			ARIZONA_OUT1R_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
+			ARIZONA_OUT2L_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2R,
+			ARIZONA_OUT2R_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
+			ARIZONA_OUT3L_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_DAC_VOLUME_LIMIT_3R,
+			ARIZONA_OUT3R_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4L,
+			ARIZONA_OUT4L_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4R,
+			ARIZONA_OUT4R_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5L,
+			ARIZONA_OUT5L_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5R,
+			ARIZONA_OUT5R_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6L,
+			ARIZONA_OUT6L_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6R,
+			ARIZONA_OUT6R_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+};
+EXPORT_SYMBOL_GPL(arizona_output_anc_src);
+
+const struct snd_kcontrol_new arizona_voice_trigger_switch[] = {
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 1, 1, 0),
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 2, 1, 0),
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 3, 1, 0),
+};
+EXPORT_SYMBOL_GPL(arizona_voice_trigger_switch);
+
+static void arizona_in_set_vu(struct snd_soc_component *component, int ena)
+{
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+	int i;
+
+	if (ena)
+		val = ARIZONA_IN_VU;
+	else
+		val = 0;
+
+	for (i = 0; i < priv->num_inputs; i++)
+		snd_soc_component_update_bits(component,
+				    ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
+				    ARIZONA_IN_VU, val);
+}
+
+bool arizona_input_analog(struct snd_soc_component *component, int shift)
+{
+	unsigned int reg = ARIZONA_IN1L_CONTROL + ((shift / 2) * 8);
+	unsigned int val = snd_soc_component_read32(component, reg);
+
+	return !(val & ARIZONA_IN1_MODE_MASK);
+}
+EXPORT_SYMBOL_GPL(arizona_input_analog);
+
+int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+		  int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	unsigned int reg;
+
+	if (w->shift % 2)
+		reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
+	else
+		reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		priv->in_pending++;
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, reg,
+					      ARIZONA_IN1L_MUTE, 0);
+
+		/* If this is the last input pending then allow VU */
+		priv->in_pending--;
+		if (priv->in_pending == 0) {
+			msleep(1);
+			arizona_in_set_vu(component, 1);
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, reg,
+				    ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
+				    ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Disable volume updates if no inputs are enabled */
+		reg = snd_soc_component_read32(component, ARIZONA_INPUT_ENABLES);
+		if (reg == 0)
+			arizona_in_set_vu(component, 0);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_in_ev);
+
+int arizona_out_ev(struct snd_soc_dapm_widget *w,
+		   struct snd_kcontrol *kcontrol,
+		   int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		switch (w->shift) {
+		case ARIZONA_OUT1L_ENA_SHIFT:
+		case ARIZONA_OUT1R_ENA_SHIFT:
+		case ARIZONA_OUT2L_ENA_SHIFT:
+		case ARIZONA_OUT2R_ENA_SHIFT:
+		case ARIZONA_OUT3L_ENA_SHIFT:
+		case ARIZONA_OUT3R_ENA_SHIFT:
+			priv->out_up_pending++;
+			priv->out_up_delay += 17;
+			break;
+		case ARIZONA_OUT4L_ENA_SHIFT:
+		case ARIZONA_OUT4R_ENA_SHIFT:
+			priv->out_up_pending++;
+			switch (arizona->type) {
+			case WM5102:
+			case WM8997:
+				break;
+			default:
+				priv->out_up_delay += 10;
+				break;
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		switch (w->shift) {
+		case ARIZONA_OUT1L_ENA_SHIFT:
+		case ARIZONA_OUT1R_ENA_SHIFT:
+		case ARIZONA_OUT2L_ENA_SHIFT:
+		case ARIZONA_OUT2R_ENA_SHIFT:
+		case ARIZONA_OUT3L_ENA_SHIFT:
+		case ARIZONA_OUT3R_ENA_SHIFT:
+		case ARIZONA_OUT4L_ENA_SHIFT:
+		case ARIZONA_OUT4R_ENA_SHIFT:
+			priv->out_up_pending--;
+			if (!priv->out_up_pending && priv->out_up_delay) {
+				dev_dbg(component->dev, "Power up delay: %d\n",
+					priv->out_up_delay);
+				msleep(priv->out_up_delay);
+				priv->out_up_delay = 0;
+			}
+			break;
+
+		default:
+			break;
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		switch (w->shift) {
+		case ARIZONA_OUT1L_ENA_SHIFT:
+		case ARIZONA_OUT1R_ENA_SHIFT:
+		case ARIZONA_OUT2L_ENA_SHIFT:
+		case ARIZONA_OUT2R_ENA_SHIFT:
+		case ARIZONA_OUT3L_ENA_SHIFT:
+		case ARIZONA_OUT3R_ENA_SHIFT:
+			priv->out_down_pending++;
+			priv->out_down_delay++;
+			break;
+		case ARIZONA_OUT4L_ENA_SHIFT:
+		case ARIZONA_OUT4R_ENA_SHIFT:
+			priv->out_down_pending++;
+			switch (arizona->type) {
+			case WM5102:
+			case WM8997:
+				break;
+			case WM8998:
+			case WM1814:
+				priv->out_down_delay += 5;
+				break;
+			default:
+				priv->out_down_delay++;
+				break;
+			}
+		default:
+			break;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		switch (w->shift) {
+		case ARIZONA_OUT1L_ENA_SHIFT:
+		case ARIZONA_OUT1R_ENA_SHIFT:
+		case ARIZONA_OUT2L_ENA_SHIFT:
+		case ARIZONA_OUT2R_ENA_SHIFT:
+		case ARIZONA_OUT3L_ENA_SHIFT:
+		case ARIZONA_OUT3R_ENA_SHIFT:
+		case ARIZONA_OUT4L_ENA_SHIFT:
+		case ARIZONA_OUT4R_ENA_SHIFT:
+			priv->out_down_pending--;
+			if (!priv->out_down_pending && priv->out_down_delay) {
+				dev_dbg(component->dev, "Power down delay: %d\n",
+					priv->out_down_delay);
+				msleep(priv->out_down_delay);
+				priv->out_down_delay = 0;
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_out_ev);
+
+int arizona_hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+		  int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+	unsigned int mask = 1 << w->shift;
+	unsigned int val;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		val = mask;
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		val = 0;
+		break;
+	case SND_SOC_DAPM_PRE_PMU:
+	case SND_SOC_DAPM_POST_PMD:
+		return arizona_out_ev(w, kcontrol, event);
+	default:
+		return -EINVAL;
+	}
+
+	/* Store the desired state for the HP outputs */
+	priv->arizona->hp_ena &= ~mask;
+	priv->arizona->hp_ena |= val;
+
+	/* Force off if HPDET clamp is active */
+	if (priv->arizona->hpdet_clamp)
+		val = 0;
+
+	regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
+				 mask, val);
+
+	return arizona_out_ev(w, kcontrol, event);
+}
+EXPORT_SYMBOL_GPL(arizona_hp_ev);
+
+static int arizona_dvfs_enable(struct snd_soc_component *component)
+{
+	const struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+	int ret;
+
+	ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
+	if (ret) {
+		dev_err(component->dev, "Failed to boost DCVDD: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_update_bits(arizona->regmap,
+				 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
+				 ARIZONA_SUBSYS_MAX_FREQ,
+				 ARIZONA_SUBSYS_MAX_FREQ);
+	if (ret) {
+		dev_err(component->dev, "Failed to enable subsys max: %d\n", ret);
+		regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int arizona_dvfs_disable(struct snd_soc_component *component)
+{
+	const struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+	int ret;
+
+	ret = regmap_update_bits(arizona->regmap,
+				 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
+				 ARIZONA_SUBSYS_MAX_FREQ, 0);
+	if (ret) {
+		dev_err(component->dev, "Failed to disable subsys max: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
+	if (ret) {
+		dev_err(component->dev, "Failed to unboost DCVDD: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int arizona_dvfs_up(struct snd_soc_component *component, unsigned int flags)
+{
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	mutex_lock(&priv->dvfs_lock);
+
+	if (!priv->dvfs_cached && !priv->dvfs_reqs) {
+		ret = arizona_dvfs_enable(component);
+		if (ret)
+			goto err;
+	}
+
+	priv->dvfs_reqs |= flags;
+err:
+	mutex_unlock(&priv->dvfs_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_dvfs_up);
+
+int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags)
+{
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	unsigned int old_reqs;
+	int ret = 0;
+
+	mutex_lock(&priv->dvfs_lock);
+
+	old_reqs = priv->dvfs_reqs;
+	priv->dvfs_reqs &= ~flags;
+
+	if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
+		ret = arizona_dvfs_disable(component);
+
+	mutex_unlock(&priv->dvfs_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_dvfs_down);
+
+int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	mutex_lock(&priv->dvfs_lock);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (priv->dvfs_reqs)
+			ret = arizona_dvfs_enable(component);
+
+		priv->dvfs_cached = false;
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* We must ensure DVFS is disabled before the codec goes into
+		 * suspend so that we are never in an illegal state of DVFS
+		 * enabled without enough DCVDD
+		 */
+		priv->dvfs_cached = true;
+
+		if (priv->dvfs_reqs)
+			ret = arizona_dvfs_disable(component);
+		break;
+	default:
+		break;
+	}
+
+	mutex_unlock(&priv->dvfs_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
+
+void arizona_init_dvfs(struct arizona_priv *priv)
+{
+	mutex_init(&priv->dvfs_lock);
+}
+EXPORT_SYMBOL_GPL(arizona_init_dvfs);
+
+int arizona_anc_ev(struct snd_soc_dapm_widget *w,
+		   struct snd_kcontrol *kcontrol,
+		   int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	unsigned int val;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		val = 1 << w->shift;
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		val = 1 << (w->shift + 1);
+		break;
+	default:
+		return 0;
+	}
+
+	snd_soc_component_write(component, ARIZONA_CLOCK_CONTROL, val);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_anc_ev);
+
+static unsigned int arizona_opclk_ref_48k_rates[] = {
+	6144000,
+	12288000,
+	24576000,
+	49152000,
+};
+
+static unsigned int arizona_opclk_ref_44k1_rates[] = {
+	5644800,
+	11289600,
+	22579200,
+	45158400,
+};
+
+static int arizona_set_opclk(struct snd_soc_component *component,
+			     unsigned int clk, unsigned int freq)
+{
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	unsigned int reg;
+	unsigned int *rates;
+	int ref, div, refclk;
+
+	switch (clk) {
+	case ARIZONA_CLK_OPCLK:
+		reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
+		refclk = priv->sysclk;
+		break;
+	case ARIZONA_CLK_ASYNC_OPCLK:
+		reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
+		refclk = priv->asyncclk;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (refclk % 8000)
+		rates = arizona_opclk_ref_44k1_rates;
+	else
+		rates = arizona_opclk_ref_48k_rates;
+
+	for (ref = 0; ref < ARRAY_SIZE(arizona_opclk_ref_48k_rates) &&
+	     rates[ref] <= refclk; ref++) {
+		div = 1;
+		while (rates[ref] / div >= freq && div < 32) {
+			if (rates[ref] / div == freq) {
+				dev_dbg(component->dev, "Configured %dHz OPCLK\n",
+					freq);
+				snd_soc_component_update_bits(component, reg,
+						    ARIZONA_OPCLK_DIV_MASK |
+						    ARIZONA_OPCLK_SEL_MASK,
+						    (div <<
+						     ARIZONA_OPCLK_DIV_SHIFT) |
+						    ref);
+				return 0;
+			}
+			div++;
+		}
+	}
+
+	dev_err(component->dev, "Unable to generate %dHz OPCLK\n", freq);
+	return -EINVAL;
+}
+
+int arizona_clk_ev(struct snd_soc_dapm_widget *w,
+		   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+	unsigned int val;
+	int clk_idx;
+	int ret;
+
+	ret = regmap_read(arizona->regmap, w->reg, &val);
+	if (ret) {
+		dev_err(component->dev, "Failed to check clock source: %d\n", ret);
+		return ret;
+	}
+
+	val = (val & ARIZONA_SYSCLK_SRC_MASK) >> ARIZONA_SYSCLK_SRC_SHIFT;
+
+	switch (val) {
+	case ARIZONA_CLK_SRC_MCLK1:
+		clk_idx = ARIZONA_MCLK1;
+		break;
+	case ARIZONA_CLK_SRC_MCLK2:
+		clk_idx = ARIZONA_MCLK2;
+		break;
+	default:
+		return 0;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		return clk_prepare_enable(arizona->mclk[clk_idx]);
+	case SND_SOC_DAPM_POST_PMD:
+		clk_disable_unprepare(arizona->mclk[clk_idx]);
+		return 0;
+	default:
+		return 0;
+	}
+}
+EXPORT_SYMBOL_GPL(arizona_clk_ev);
+
+int arizona_set_sysclk(struct snd_soc_component *component, int clk_id,
+		       int source, unsigned int freq, int dir)
+{
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+	char *name;
+	unsigned int reg;
+	unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
+	unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
+	int *clk;
+
+	switch (clk_id) {
+	case ARIZONA_CLK_SYSCLK:
+		name = "SYSCLK";
+		reg = ARIZONA_SYSTEM_CLOCK_1;
+		clk = &priv->sysclk;
+		mask |= ARIZONA_SYSCLK_FRAC;
+		break;
+	case ARIZONA_CLK_ASYNCCLK:
+		name = "ASYNCCLK";
+		reg = ARIZONA_ASYNC_CLOCK_1;
+		clk = &priv->asyncclk;
+		break;
+	case ARIZONA_CLK_OPCLK:
+	case ARIZONA_CLK_ASYNC_OPCLK:
+		return arizona_set_opclk(component, clk_id, freq);
+	default:
+		return -EINVAL;
+	}
+
+	switch (freq) {
+	case  5644800:
+	case  6144000:
+		break;
+	case 11289600:
+	case 12288000:
+		val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
+		break;
+	case 22579200:
+	case 24576000:
+		val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
+		break;
+	case 45158400:
+	case 49152000:
+		val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
+		break;
+	case 67737600:
+	case 73728000:
+		val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
+		break;
+	case 90316800:
+	case 98304000:
+		val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
+		break;
+	case 135475200:
+	case 147456000:
+		val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
+		break;
+	case 0:
+		dev_dbg(arizona->dev, "%s cleared\n", name);
+		*clk = freq;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	*clk = freq;
+
+	if (freq % 6144000)
+		val |= ARIZONA_SYSCLK_FRAC;
+
+	dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
+
+	return regmap_update_bits(arizona->regmap, reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(arizona_set_sysclk);
+
+static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+	int lrclk, bclk, mode, base;
+
+	base = dai->driver->base;
+
+	lrclk = 0;
+	bclk = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		mode = ARIZONA_FMT_DSP_MODE_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
+				!= SND_SOC_DAIFMT_CBM_CFM) {
+			arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
+			return -EINVAL;
+		}
+		mode = ARIZONA_FMT_DSP_MODE_B;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		mode = ARIZONA_FMT_I2S_MODE;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
+				!= SND_SOC_DAIFMT_CBM_CFM) {
+			arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
+			return -EINVAL;
+		}
+		mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
+		break;
+	default:
+		arizona_aif_err(dai, "Unsupported DAI format %d\n",
+				fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		bclk |= ARIZONA_AIF1_BCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		bclk |= ARIZONA_AIF1_BCLK_MSTR;
+		lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
+		break;
+	default:
+		arizona_aif_err(dai, "Unsupported master mode %d\n",
+				fmt & SND_SOC_DAIFMT_MASTER_MASK);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		bclk |= ARIZONA_AIF1_BCLK_INV;
+		lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		bclk |= ARIZONA_AIF1_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
+				 ARIZONA_AIF1_BCLK_INV |
+				 ARIZONA_AIF1_BCLK_MSTR,
+				 bclk);
+	regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
+				 ARIZONA_AIF1TX_LRCLK_INV |
+				 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
+	regmap_update_bits_async(arizona->regmap,
+				 base + ARIZONA_AIF_RX_PIN_CTRL,
+				 ARIZONA_AIF1RX_LRCLK_INV |
+				 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
+	regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
+			   ARIZONA_AIF1_FMT_MASK, mode);
+
+	return 0;
+}
+
+static const int arizona_48k_bclk_rates[] = {
+	-1,
+	48000,
+	64000,
+	96000,
+	128000,
+	192000,
+	256000,
+	384000,
+	512000,
+	768000,
+	1024000,
+	1536000,
+	2048000,
+	3072000,
+	4096000,
+	6144000,
+	8192000,
+	12288000,
+	24576000,
+};
+
+static const int arizona_44k1_bclk_rates[] = {
+	-1,
+	44100,
+	58800,
+	88200,
+	117600,
+	177640,
+	235200,
+	352800,
+	470400,
+	705600,
+	940800,
+	1411200,
+	1881600,
+	2822400,
+	3763200,
+	5644800,
+	7526400,
+	11289600,
+	22579200,
+};
+
+static const unsigned int arizona_sr_vals[] = {
+	0,
+	12000,
+	24000,
+	48000,
+	96000,
+	192000,
+	384000,
+	768000,
+	0,
+	11025,
+	22050,
+	44100,
+	88200,
+	176400,
+	352800,
+	705600,
+	4000,
+	8000,
+	16000,
+	32000,
+	64000,
+	128000,
+	256000,
+	512000,
+};
+
+#define ARIZONA_48K_RATE_MASK	0x0F003E
+#define ARIZONA_44K1_RATE_MASK	0x003E00
+#define ARIZONA_RATE_MASK	(ARIZONA_48K_RATE_MASK | ARIZONA_44K1_RATE_MASK)
+
+static const struct snd_pcm_hw_constraint_list arizona_constraint = {
+	.count	= ARRAY_SIZE(arizona_sr_vals),
+	.list	= arizona_sr_vals,
+};
+
+static int arizona_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
+	unsigned int base_rate;
+
+	if (!substream->runtime)
+		return 0;
+
+	switch (dai_priv->clk) {
+	case ARIZONA_CLK_SYSCLK:
+		base_rate = priv->sysclk;
+		break;
+	case ARIZONA_CLK_ASYNCCLK:
+		base_rate = priv->asyncclk;
+		break;
+	default:
+		return 0;
+	}
+
+	if (base_rate == 0)
+		dai_priv->constraint.mask = ARIZONA_RATE_MASK;
+	else if (base_rate % 8000)
+		dai_priv->constraint.mask = ARIZONA_44K1_RATE_MASK;
+	else
+		dai_priv->constraint.mask = ARIZONA_48K_RATE_MASK;
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE,
+					  &dai_priv->constraint);
+}
+
+static void arizona_wm5102_set_dac_comp(struct snd_soc_component *component,
+					unsigned int rate)
+{
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+	struct reg_sequence dac_comp[] = {
+		{ 0x80, 0x3 },
+		{ ARIZONA_DAC_COMP_1, 0 },
+		{ ARIZONA_DAC_COMP_2, 0 },
+		{ 0x80, 0x0 },
+	};
+
+	mutex_lock(&arizona->dac_comp_lock);
+
+	dac_comp[1].def = arizona->dac_comp_coeff;
+	if (rate >= 176400)
+		dac_comp[2].def = arizona->dac_comp_enabled;
+
+	mutex_unlock(&arizona->dac_comp_lock);
+
+	regmap_multi_reg_write(arizona->regmap,
+			       dac_comp,
+			       ARRAY_SIZE(dac_comp));
+}
+
+static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
+	int base = dai->driver->base;
+	int i, sr_val, ret;
+
+	/*
+	 * We will need to be more flexible than this in future,
+	 * currently we use a single sample rate for SYSCLK.
+	 */
+	for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
+		if (arizona_sr_vals[i] == params_rate(params))
+			break;
+	if (i == ARRAY_SIZE(arizona_sr_vals)) {
+		arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
+				params_rate(params));
+		return -EINVAL;
+	}
+	sr_val = i;
+
+	switch (priv->arizona->type) {
+	case WM5102:
+	case WM8997:
+		if (arizona_sr_vals[sr_val] >= 88200)
+			ret = arizona_dvfs_up(component, ARIZONA_DVFS_SR1_RQ);
+		else
+			ret = arizona_dvfs_down(component, ARIZONA_DVFS_SR1_RQ);
+
+		if (ret) {
+			arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
+			return ret;
+		}
+		break;
+	default:
+		break;
+	}
+
+	switch (dai_priv->clk) {
+	case ARIZONA_CLK_SYSCLK:
+		switch (priv->arizona->type) {
+		case WM5102:
+			arizona_wm5102_set_dac_comp(component,
+						    params_rate(params));
+			break;
+		default:
+			break;
+		}
+
+		snd_soc_component_update_bits(component, ARIZONA_SAMPLE_RATE_1,
+					      ARIZONA_SAMPLE_RATE_1_MASK,
+					      sr_val);
+		if (base)
+			snd_soc_component_update_bits(component,
+					base + ARIZONA_AIF_RATE_CTRL,
+					ARIZONA_AIF1_RATE_MASK, 0);
+		break;
+	case ARIZONA_CLK_ASYNCCLK:
+		snd_soc_component_update_bits(component,
+					      ARIZONA_ASYNC_SAMPLE_RATE_1,
+					      ARIZONA_ASYNC_SAMPLE_RATE_1_MASK,
+					      sr_val);
+		if (base)
+			snd_soc_component_update_bits(component,
+					base + ARIZONA_AIF_RATE_CTRL,
+					ARIZONA_AIF1_RATE_MASK,
+					8 << ARIZONA_AIF1_RATE_SHIFT);
+		break;
+	default:
+		arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static bool arizona_aif_cfg_changed(struct snd_soc_component *component,
+				    int base, int bclk, int lrclk, int frame)
+{
+	int val;
+
+	val = snd_soc_component_read32(component, base + ARIZONA_AIF_BCLK_CTRL);
+	if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
+		return true;
+
+	val = snd_soc_component_read32(component, base + ARIZONA_AIF_TX_BCLK_RATE);
+	if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
+		return true;
+
+	val = snd_soc_component_read32(component, base + ARIZONA_AIF_FRAME_CTRL_1);
+	if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
+			     ARIZONA_AIF1TX_SLOT_LEN_MASK)))
+		return true;
+
+	return false;
+}
+
+static int arizona_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+	int base = dai->driver->base;
+	const int *rates;
+	int i, ret, val;
+	int channels = params_channels(params);
+	int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
+	int tdm_width = arizona->tdm_width[dai->id - 1];
+	int tdm_slots = arizona->tdm_slots[dai->id - 1];
+	int bclk, lrclk, wl, frame, bclk_target;
+	bool reconfig;
+	unsigned int aif_tx_state, aif_rx_state;
+
+	if (params_rate(params) % 4000)
+		rates = &arizona_44k1_bclk_rates[0];
+	else
+		rates = &arizona_48k_bclk_rates[0];
+
+	wl = params_width(params);
+
+	if (tdm_slots) {
+		arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
+				tdm_slots, tdm_width);
+		bclk_target = tdm_slots * tdm_width * params_rate(params);
+		channels = tdm_slots;
+	} else {
+		bclk_target = snd_soc_params_to_bclk(params);
+		tdm_width = wl;
+	}
+
+	if (chan_limit && chan_limit < channels) {
+		arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
+		bclk_target /= channels;
+		bclk_target *= chan_limit;
+	}
+
+	/* Force multiple of 2 channels for I2S mode */
+	val = snd_soc_component_read32(component, base + ARIZONA_AIF_FORMAT);
+	val &= ARIZONA_AIF1_FMT_MASK;
+	if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
+		arizona_aif_dbg(dai, "Forcing stereo mode\n");
+		bclk_target /= channels;
+		bclk_target *= channels + 1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
+		if (rates[i] >= bclk_target &&
+		    rates[i] % params_rate(params) == 0) {
+			bclk = i;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
+		arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
+				params_rate(params));
+		return -EINVAL;
+	}
+
+	lrclk = rates[bclk] / params_rate(params);
+
+	arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
+			rates[bclk], rates[bclk] / lrclk);
+
+	frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
+
+	reconfig = arizona_aif_cfg_changed(component, base, bclk, lrclk, frame);
+
+	if (reconfig) {
+		/* Save AIF TX/RX state */
+		aif_tx_state = snd_soc_component_read32(component,
+					    base + ARIZONA_AIF_TX_ENABLES);
+		aif_rx_state = snd_soc_component_read32(component,
+					    base + ARIZONA_AIF_RX_ENABLES);
+		/* Disable AIF TX/RX before reconfiguring it */
+		regmap_update_bits_async(arizona->regmap,
+					 base + ARIZONA_AIF_TX_ENABLES,
+					 0xff, 0x0);
+		regmap_update_bits(arizona->regmap,
+				   base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
+	}
+
+	ret = arizona_hw_params_rate(substream, params, dai);
+	if (ret != 0)
+		goto restore_aif;
+
+	if (reconfig) {
+		regmap_update_bits_async(arizona->regmap,
+					 base + ARIZONA_AIF_BCLK_CTRL,
+					 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
+		regmap_update_bits_async(arizona->regmap,
+					 base + ARIZONA_AIF_TX_BCLK_RATE,
+					 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
+		regmap_update_bits_async(arizona->regmap,
+					 base + ARIZONA_AIF_RX_BCLK_RATE,
+					 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
+		regmap_update_bits_async(arizona->regmap,
+					 base + ARIZONA_AIF_FRAME_CTRL_1,
+					 ARIZONA_AIF1TX_WL_MASK |
+					 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
+		regmap_update_bits(arizona->regmap,
+				   base + ARIZONA_AIF_FRAME_CTRL_2,
+				   ARIZONA_AIF1RX_WL_MASK |
+				   ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
+	}
+
+restore_aif:
+	if (reconfig) {
+		/* Restore AIF TX/RX state */
+		regmap_update_bits_async(arizona->regmap,
+					 base + ARIZONA_AIF_TX_ENABLES,
+					 0xff, aif_tx_state);
+		regmap_update_bits(arizona->regmap,
+				   base + ARIZONA_AIF_RX_ENABLES,
+				   0xff, aif_rx_state);
+	}
+	return ret;
+}
+
+static const char *arizona_dai_clk_str(int clk_id)
+{
+	switch (clk_id) {
+	case ARIZONA_CLK_SYSCLK:
+		return "SYSCLK";
+	case ARIZONA_CLK_ASYNCCLK:
+		return "ASYNCCLK";
+	default:
+		return "Unknown clock";
+	}
+}
+
+static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
+	struct snd_soc_dapm_route routes[2];
+
+	switch (clk_id) {
+	case ARIZONA_CLK_SYSCLK:
+	case ARIZONA_CLK_ASYNCCLK:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (clk_id == dai_priv->clk)
+		return 0;
+
+	if (dai->active) {
+		dev_err(component->dev, "Can't change clock on active DAI %d\n",
+			dai->id);
+		return -EBUSY;
+	}
+
+	dev_dbg(component->dev, "Setting AIF%d to %s\n", dai->id + 1,
+		arizona_dai_clk_str(clk_id));
+
+	memset(&routes, 0, sizeof(routes));
+	routes[0].sink = dai->driver->capture.stream_name;
+	routes[1].sink = dai->driver->playback.stream_name;
+
+	routes[0].source = arizona_dai_clk_str(dai_priv->clk);
+	routes[1].source = arizona_dai_clk_str(dai_priv->clk);
+	snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
+
+	routes[0].source = arizona_dai_clk_str(clk_id);
+	routes[1].source = arizona_dai_clk_str(clk_id);
+	snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
+
+	dai_priv->clk = clk_id;
+
+	return snd_soc_dapm_sync(dapm);
+}
+
+static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+	struct snd_soc_component *component = dai->component;
+	int base = dai->driver->base;
+	unsigned int reg;
+
+	if (tristate)
+		reg = ARIZONA_AIF1_TRI;
+	else
+		reg = 0;
+
+	return snd_soc_component_update_bits(component,
+					     base + ARIZONA_AIF_RATE_CTRL,
+					     ARIZONA_AIF1_TRI, reg);
+}
+
+static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
+					 unsigned int base,
+					 int channels, unsigned int mask)
+{
+	struct snd_soc_component *component = dai->component;
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+	int slot, i;
+
+	for (i = 0; i < channels; ++i) {
+		slot = ffs(mask) - 1;
+		if (slot < 0)
+			return;
+
+		regmap_write(arizona->regmap, base + i, slot);
+
+		mask &= ~(1 << slot);
+	}
+
+	if (mask)
+		arizona_aif_warn(dai, "Too many channels in TDM mask\n");
+}
+
+static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+				unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+	int base = dai->driver->base;
+	int rx_max_chan = dai->driver->playback.channels_max;
+	int tx_max_chan = dai->driver->capture.channels_max;
+
+	/* Only support TDM for the physical AIFs */
+	if (dai->id > ARIZONA_MAX_AIF)
+		return -ENOTSUPP;
+
+	if (slots == 0) {
+		tx_mask = (1 << tx_max_chan) - 1;
+		rx_mask = (1 << rx_max_chan) - 1;
+	}
+
+	arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
+				     tx_max_chan, tx_mask);
+	arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
+				     rx_max_chan, rx_mask);
+
+	arizona->tdm_width[dai->id - 1] = slot_width;
+	arizona->tdm_slots[dai->id - 1] = slots;
+
+	return 0;
+}
+
+const struct snd_soc_dai_ops arizona_dai_ops = {
+	.startup = arizona_startup,
+	.set_fmt = arizona_set_fmt,
+	.set_tdm_slot = arizona_set_tdm_slot,
+	.hw_params = arizona_hw_params,
+	.set_sysclk = arizona_dai_set_sysclk,
+	.set_tristate = arizona_set_tristate,
+};
+EXPORT_SYMBOL_GPL(arizona_dai_ops);
+
+const struct snd_soc_dai_ops arizona_simple_dai_ops = {
+	.startup = arizona_startup,
+	.hw_params = arizona_hw_params_rate,
+	.set_sysclk = arizona_dai_set_sysclk,
+};
+EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
+
+int arizona_init_dai(struct arizona_priv *priv, int id)
+{
+	struct arizona_dai_priv *dai_priv = &priv->dai[id];
+
+	dai_priv->clk = ARIZONA_CLK_SYSCLK;
+	dai_priv->constraint = arizona_constraint;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_dai);
+
+static struct {
+	unsigned int min;
+	unsigned int max;
+	u16 fratio;
+	int ratio;
+} fll_fratios[] = {
+	{       0,    64000, 4, 16 },
+	{   64000,   128000, 3,  8 },
+	{  128000,   256000, 2,  4 },
+	{  256000,  1000000, 1,  2 },
+	{ 1000000, 13500000, 0,  1 },
+};
+
+static const unsigned int pseudo_fref_max[ARIZONA_FLL_MAX_FRATIO] = {
+	13500000,
+	 6144000,
+	 6144000,
+	 3072000,
+	 3072000,
+	 2822400,
+	 2822400,
+	 1536000,
+	 1536000,
+	 1536000,
+	 1536000,
+	 1536000,
+	 1536000,
+	 1536000,
+	 1536000,
+	  768000,
+};
+
+static struct {
+	unsigned int min;
+	unsigned int max;
+	u16 gain;
+} fll_gains[] = {
+	{       0,   256000, 0 },
+	{  256000,  1000000, 2 },
+	{ 1000000, 13500000, 4 },
+};
+
+struct arizona_fll_cfg {
+	int n;
+	unsigned int theta;
+	unsigned int lambda;
+	int refdiv;
+	int outdiv;
+	int fratio;
+	int gain;
+};
+
+static int arizona_validate_fll(struct arizona_fll *fll,
+				unsigned int Fref,
+				unsigned int Fout)
+{
+	unsigned int Fvco_min;
+
+	if (fll->fout && Fout != fll->fout) {
+		arizona_fll_err(fll,
+				"Can't change output on active FLL\n");
+		return -EINVAL;
+	}
+
+	if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
+		arizona_fll_err(fll,
+				"Can't scale %dMHz in to <=13.5MHz\n",
+				Fref);
+		return -EINVAL;
+	}
+
+	Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
+	if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
+		arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
+				Fout);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int arizona_find_fratio(unsigned int Fref, int *fratio)
+{
+	int i;
+
+	/* Find an appropriate FLL_FRATIO */
+	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+			if (fratio)
+				*fratio = fll_fratios[i].fratio;
+			return fll_fratios[i].ratio;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int arizona_calc_fratio(struct arizona_fll *fll,
+			       struct arizona_fll_cfg *cfg,
+			       unsigned int target,
+			       unsigned int Fref, bool sync)
+{
+	int init_ratio, ratio;
+	int refdiv, div;
+
+	/* Fref must be <=13.5MHz, find initial refdiv */
+	div = 1;
+	cfg->refdiv = 0;
+	while (Fref > ARIZONA_FLL_MAX_FREF) {
+		div *= 2;
+		Fref /= 2;
+		cfg->refdiv++;
+
+		if (div > ARIZONA_FLL_MAX_REFDIV)
+			return -EINVAL;
+	}
+
+	/* Find an appropriate FLL_FRATIO */
+	init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
+	if (init_ratio < 0) {
+		arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
+				Fref);
+		return init_ratio;
+	}
+
+	switch (fll->arizona->type) {
+	case WM5102:
+	case WM8997:
+		return init_ratio;
+	case WM5110:
+	case WM8280:
+		if (fll->arizona->rev < 3 || sync)
+			return init_ratio;
+		break;
+	default:
+		if (sync)
+			return init_ratio;
+		break;
+	}
+
+	cfg->fratio = init_ratio - 1;
+
+	/* Adjust FRATIO/refdiv to avoid integer mode if possible */
+	refdiv = cfg->refdiv;
+
+	arizona_fll_dbg(fll, "pseudo: initial ratio=%u fref=%u refdiv=%u\n",
+			init_ratio, Fref, refdiv);
+
+	while (div <= ARIZONA_FLL_MAX_REFDIV) {
+		/* start from init_ratio because this may already give a
+		 * fractional N.K
+		 */
+		for (ratio = init_ratio; ratio > 0; ratio--) {
+			if (target % (ratio * Fref)) {
+				cfg->refdiv = refdiv;
+				cfg->fratio = ratio - 1;
+				arizona_fll_dbg(fll,
+					"pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
+					Fref, refdiv, div, ratio);
+				return ratio;
+			}
+		}
+
+		for (ratio = init_ratio + 1; ratio <= ARIZONA_FLL_MAX_FRATIO;
+		     ratio++) {
+			if ((ARIZONA_FLL_VCO_CORNER / 2) /
+			    (fll->vco_mult * ratio) < Fref) {
+				arizona_fll_dbg(fll, "pseudo: hit VCO corner\n");
+				break;
+			}
+
+			if (Fref > pseudo_fref_max[ratio - 1]) {
+				arizona_fll_dbg(fll,
+					"pseudo: exceeded max fref(%u) for ratio=%u\n",
+					pseudo_fref_max[ratio - 1],
+					ratio);
+				break;
+			}
+
+			if (target % (ratio * Fref)) {
+				cfg->refdiv = refdiv;
+				cfg->fratio = ratio - 1;
+				arizona_fll_dbg(fll,
+					"pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
+					Fref, refdiv, div, ratio);
+				return ratio;
+			}
+		}
+
+		div *= 2;
+		Fref /= 2;
+		refdiv++;
+		init_ratio = arizona_find_fratio(Fref, NULL);
+		arizona_fll_dbg(fll,
+				"pseudo: change fref=%u refdiv=%d(%d) ratio=%u\n",
+				Fref, refdiv, div, init_ratio);
+	}
+
+	arizona_fll_warn(fll, "Falling back to integer mode operation\n");
+	return cfg->fratio + 1;
+}
+
+static int arizona_calc_fll(struct arizona_fll *fll,
+			    struct arizona_fll_cfg *cfg,
+			    unsigned int Fref, bool sync)
+{
+	unsigned int target, div, gcd_fll;
+	int i, ratio;
+
+	arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
+
+	/* Fvco should be over the targt; don't check the upper bound */
+	div = ARIZONA_FLL_MIN_OUTDIV;
+	while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
+		div++;
+		if (div > ARIZONA_FLL_MAX_OUTDIV)
+			return -EINVAL;
+	}
+	target = fll->fout * div / fll->vco_mult;
+	cfg->outdiv = div;
+
+	arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
+
+	/* Find an appropriate FLL_FRATIO and refdiv */
+	ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
+	if (ratio < 0)
+		return ratio;
+
+	/* Apply the division for our remaining calculations */
+	Fref = Fref / (1 << cfg->refdiv);
+
+	cfg->n = target / (ratio * Fref);
+
+	if (target % (ratio * Fref)) {
+		gcd_fll = gcd(target, ratio * Fref);
+		arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
+
+		cfg->theta = (target - (cfg->n * ratio * Fref))
+			/ gcd_fll;
+		cfg->lambda = (ratio * Fref) / gcd_fll;
+	} else {
+		cfg->theta = 0;
+		cfg->lambda = 0;
+	}
+
+	/* Round down to 16bit range with cost of accuracy lost.
+	 * Denominator must be bigger than numerator so we only
+	 * take care of it.
+	 */
+	while (cfg->lambda >= (1 << 16)) {
+		cfg->theta >>= 1;
+		cfg->lambda >>= 1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
+		if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
+			cfg->gain = fll_gains[i].gain;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(fll_gains)) {
+		arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
+				Fref);
+		return -EINVAL;
+	}
+
+	arizona_fll_dbg(fll, "N=%d THETA=%d LAMBDA=%d\n",
+			cfg->n, cfg->theta, cfg->lambda);
+	arizona_fll_dbg(fll, "FRATIO=0x%x(%d) OUTDIV=%d REFCLK_DIV=0x%x(%d)\n",
+			cfg->fratio, ratio, cfg->outdiv,
+			cfg->refdiv, 1 << cfg->refdiv);
+	arizona_fll_dbg(fll, "GAIN=0x%x(%d)\n", cfg->gain, 1 << cfg->gain);
+
+	return 0;
+}
+
+static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
+			      struct arizona_fll_cfg *cfg, int source,
+			      bool sync)
+{
+	regmap_update_bits_async(arizona->regmap, base + 3,
+				 ARIZONA_FLL1_THETA_MASK, cfg->theta);
+	regmap_update_bits_async(arizona->regmap, base + 4,
+				 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
+	regmap_update_bits_async(arizona->regmap, base + 5,
+				 ARIZONA_FLL1_FRATIO_MASK,
+				 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
+	regmap_update_bits_async(arizona->regmap, base + 6,
+				 ARIZONA_FLL1_CLK_REF_DIV_MASK |
+				 ARIZONA_FLL1_CLK_REF_SRC_MASK,
+				 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
+				 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
+
+	if (sync) {
+		regmap_update_bits(arizona->regmap, base + 0x7,
+				   ARIZONA_FLL1_GAIN_MASK,
+				   cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+	} else {
+		regmap_update_bits(arizona->regmap, base + 0x5,
+				   ARIZONA_FLL1_OUTDIV_MASK,
+				   cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+		regmap_update_bits(arizona->regmap, base + 0x9,
+				   ARIZONA_FLL1_GAIN_MASK,
+				   cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+	}
+
+	regmap_update_bits_async(arizona->regmap, base + 2,
+				 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
+				 ARIZONA_FLL1_CTRL_UPD | cfg->n);
+}
+
+static int arizona_is_enabled_fll(struct arizona_fll *fll, int base)
+{
+	struct arizona *arizona = fll->arizona;
+	unsigned int reg;
+	int ret;
+
+	ret = regmap_read(arizona->regmap, base + 1, &reg);
+	if (ret != 0) {
+		arizona_fll_err(fll, "Failed to read current state: %d\n",
+				ret);
+		return ret;
+	}
+
+	return reg & ARIZONA_FLL1_ENA;
+}
+
+static int arizona_set_fll_clks(struct arizona_fll *fll, int base, bool ena)
+{
+	struct arizona *arizona = fll->arizona;
+	unsigned int val;
+	struct clk *clk;
+	int ret;
+
+	ret = regmap_read(arizona->regmap, base + 6, &val);
+	if (ret != 0) {
+		arizona_fll_err(fll, "Failed to read current source: %d\n",
+				ret);
+		return ret;
+	}
+
+	val &= ARIZONA_FLL1_CLK_REF_SRC_MASK;
+	val >>= ARIZONA_FLL1_CLK_REF_SRC_SHIFT;
+
+	switch (val) {
+	case ARIZONA_FLL_SRC_MCLK1:
+		clk = arizona->mclk[ARIZONA_MCLK1];
+		break;
+	case ARIZONA_FLL_SRC_MCLK2:
+		clk = arizona->mclk[ARIZONA_MCLK2];
+		break;
+	default:
+		return 0;
+	}
+
+	if (ena) {
+		return clk_prepare_enable(clk);
+	} else {
+		clk_disable_unprepare(clk);
+		return 0;
+	}
+}
+
+static int arizona_enable_fll(struct arizona_fll *fll)
+{
+	struct arizona *arizona = fll->arizona;
+	bool use_sync = false;
+	int already_enabled = arizona_is_enabled_fll(fll, fll->base);
+	int sync_enabled = arizona_is_enabled_fll(fll, fll->base + 0x10);
+	struct arizona_fll_cfg cfg;
+	int i;
+	unsigned int val;
+
+	if (already_enabled < 0)
+		return already_enabled;
+	if (sync_enabled < 0)
+		return sync_enabled;
+
+	if (already_enabled) {
+		/* Facilitate smooth refclk across the transition */
+		regmap_update_bits(fll->arizona->regmap, fll->base + 1,
+				   ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
+		udelay(32);
+		regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
+					 ARIZONA_FLL1_GAIN_MASK, 0);
+
+		if (arizona_is_enabled_fll(fll, fll->base + 0x10) > 0)
+			arizona_set_fll_clks(fll, fll->base + 0x10, false);
+		arizona_set_fll_clks(fll, fll->base, false);
+	}
+
+	/*
+	 * If we have both REFCLK and SYNCCLK then enable both,
+	 * otherwise apply the SYNCCLK settings to REFCLK.
+	 */
+	if (fll->ref_src >= 0 && fll->ref_freq &&
+	    fll->ref_src != fll->sync_src) {
+		arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
+
+		/* Ref path hardcodes lambda to 65536 when sync is on */
+		if (fll->sync_src >= 0 && cfg.lambda)
+			cfg.theta = (cfg.theta * (1 << 16)) / cfg.lambda;
+
+		arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
+				  false);
+		if (fll->sync_src >= 0) {
+			arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
+
+			arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
+					  fll->sync_src, true);
+			use_sync = true;
+		}
+	} else if (fll->sync_src >= 0) {
+		arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
+
+		arizona_apply_fll(arizona, fll->base, &cfg,
+				  fll->sync_src, false);
+
+		regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
+					 ARIZONA_FLL1_SYNC_ENA, 0);
+	} else {
+		arizona_fll_err(fll, "No clocks provided\n");
+		return -EINVAL;
+	}
+
+	if (already_enabled && !!sync_enabled != use_sync)
+		arizona_fll_warn(fll, "Synchroniser changed on active FLL\n");
+
+	/*
+	 * Increase the bandwidth if we're not using a low frequency
+	 * sync source.
+	 */
+	if (use_sync && fll->sync_freq > 100000)
+		regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
+					 ARIZONA_FLL1_SYNC_BW, 0);
+	else
+		regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
+					 ARIZONA_FLL1_SYNC_BW,
+					 ARIZONA_FLL1_SYNC_BW);
+
+	if (!already_enabled)
+		pm_runtime_get_sync(arizona->dev);
+
+	if (use_sync) {
+		arizona_set_fll_clks(fll, fll->base + 0x10, true);
+		regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
+					 ARIZONA_FLL1_SYNC_ENA,
+					 ARIZONA_FLL1_SYNC_ENA);
+	}
+	arizona_set_fll_clks(fll, fll->base, true);
+	regmap_update_bits_async(arizona->regmap, fll->base + 1,
+				 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
+
+	if (already_enabled)
+		regmap_update_bits_async(arizona->regmap, fll->base + 1,
+					 ARIZONA_FLL1_FREERUN, 0);
+
+	arizona_fll_dbg(fll, "Waiting for FLL lock...\n");
+	val = 0;
+	for (i = 0; i < 15; i++) {
+		if (i < 5)
+			usleep_range(200, 400);
+		else
+			msleep(20);
+
+		regmap_read(arizona->regmap,
+			    ARIZONA_INTERRUPT_RAW_STATUS_5,
+			    &val);
+		if (val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1)))
+			break;
+	}
+	if (i == 15)
+		arizona_fll_warn(fll, "Timed out waiting for lock\n");
+	else
+		arizona_fll_dbg(fll, "FLL locked (%d polls)\n", i);
+
+	return 0;
+}
+
+static void arizona_disable_fll(struct arizona_fll *fll)
+{
+	struct arizona *arizona = fll->arizona;
+	bool ref_change, sync_change;
+
+	regmap_update_bits_async(arizona->regmap, fll->base + 1,
+				 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
+	regmap_update_bits_check(arizona->regmap, fll->base + 1,
+				 ARIZONA_FLL1_ENA, 0, &ref_change);
+	regmap_update_bits_check(arizona->regmap, fll->base + 0x11,
+				 ARIZONA_FLL1_SYNC_ENA, 0, &sync_change);
+	regmap_update_bits_async(arizona->regmap, fll->base + 1,
+				 ARIZONA_FLL1_FREERUN, 0);
+
+	if (sync_change)
+		arizona_set_fll_clks(fll, fll->base + 0x10, false);
+
+	if (ref_change) {
+		arizona_set_fll_clks(fll, fll->base, false);
+		pm_runtime_put_autosuspend(arizona->dev);
+	}
+}
+
+int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
+			   unsigned int Fref, unsigned int Fout)
+{
+	int ret = 0;
+
+	if (fll->ref_src == source && fll->ref_freq == Fref)
+		return 0;
+
+	if (fll->fout && Fref > 0) {
+		ret = arizona_validate_fll(fll, Fref, fll->fout);
+		if (ret != 0)
+			return ret;
+	}
+
+	fll->ref_src = source;
+	fll->ref_freq = Fref;
+
+	if (fll->fout && Fref > 0)
+		ret = arizona_enable_fll(fll);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
+
+int arizona_set_fll(struct arizona_fll *fll, int source,
+		    unsigned int Fref, unsigned int Fout)
+{
+	int ret = 0;
+
+	if (fll->sync_src == source &&
+	    fll->sync_freq == Fref && fll->fout == Fout)
+		return 0;
+
+	if (Fout) {
+		if (fll->ref_src >= 0) {
+			ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
+			if (ret != 0)
+				return ret;
+		}
+
+		ret = arizona_validate_fll(fll, Fref, Fout);
+		if (ret != 0)
+			return ret;
+	}
+
+	fll->sync_src = source;
+	fll->sync_freq = Fref;
+	fll->fout = Fout;
+
+	if (Fout)
+		ret = arizona_enable_fll(fll);
+	else
+		arizona_disable_fll(fll);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_set_fll);
+
+int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
+		     int ok_irq, struct arizona_fll *fll)
+{
+	unsigned int val;
+
+	fll->id = id;
+	fll->base = base;
+	fll->arizona = arizona;
+	fll->sync_src = ARIZONA_FLL_SRC_NONE;
+
+	/* Configure default refclk to 32kHz if we have one */
+	regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
+	switch (val & ARIZONA_CLK_32K_SRC_MASK) {
+	case ARIZONA_CLK_SRC_MCLK1:
+	case ARIZONA_CLK_SRC_MCLK2:
+		fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
+		break;
+	default:
+		fll->ref_src = ARIZONA_FLL_SRC_NONE;
+	}
+	fll->ref_freq = 32768;
+
+	snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
+	snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
+		 "FLL%d clock OK", id);
+
+	regmap_update_bits(arizona->regmap, fll->base + 1,
+			   ARIZONA_FLL1_FREERUN, 0);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_fll);
+
+/**
+ * arizona_set_output_mode - Set the mode of the specified output
+ *
+ * @component: Device to configure
+ * @output: Output number
+ * @diff: True to set the output to differential mode
+ *
+ * Some systems use external analogue switches to connect more
+ * analogue devices to the CODEC than are supported by the device.  In
+ * some systems this requires changing the switched output from single
+ * ended to differential mode dynamically at runtime, an operation
+ * supported using this function.
+ *
+ * Most systems have a single static configuration and should use
+ * platform data instead.
+ */
+int arizona_set_output_mode(struct snd_soc_component *component, int output,
+			    bool diff)
+{
+	unsigned int reg, val;
+
+	if (output < 1 || output > 6)
+		return -EINVAL;
+
+	reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
+
+	if (diff)
+		val = ARIZONA_OUT1_MONO;
+	else
+		val = 0;
+
+	return snd_soc_component_update_bits(component, reg,
+					     ARIZONA_OUT1_MONO, val);
+}
+EXPORT_SYMBOL_GPL(arizona_set_output_mode);
+
+static const struct soc_enum arizona_adsp2_rate_enum[] = {
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
+			      ARIZONA_DSP1_RATE_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
+			      ARIZONA_DSP1_RATE_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
+			      ARIZONA_DSP1_RATE_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP4_CONTROL_1,
+			      ARIZONA_DSP1_RATE_SHIFT, 0xf,
+			      ARIZONA_RATE_ENUM_SIZE,
+			      arizona_rate_text, arizona_rate_val),
+};
+
+const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = {
+	SOC_ENUM("DSP1 Rate", arizona_adsp2_rate_enum[0]),
+	SOC_ENUM("DSP2 Rate", arizona_adsp2_rate_enum[1]),
+	SOC_ENUM("DSP3 Rate", arizona_adsp2_rate_enum[2]),
+	SOC_ENUM("DSP4 Rate", arizona_adsp2_rate_enum[3]),
+};
+EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls);
+
+static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
+{
+	s16 a = be16_to_cpu(_a);
+	s16 b = be16_to_cpu(_b);
+
+	if (!mode) {
+		return abs(a) >= 4096;
+	} else {
+		if (abs(b) >= 4096)
+			return true;
+
+		return (abs((a << 16) / (4096 - b)) >= 4096 << 4);
+	}
+}
+
+int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+	struct soc_bytes *params = (void *)kcontrol->private_value;
+	unsigned int val;
+	__be16 *data;
+	int len;
+	int ret;
+
+	len = params->num_regs * regmap_get_val_bytes(arizona->regmap);
+
+	data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
+	if (!data)
+		return -ENOMEM;
+
+	data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE);
+
+	if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) ||
+	    arizona_eq_filter_unstable(true, data[4], data[5]) ||
+	    arizona_eq_filter_unstable(true, data[8], data[9]) ||
+	    arizona_eq_filter_unstable(true, data[12], data[13]) ||
+	    arizona_eq_filter_unstable(false, data[16], data[17])) {
+		dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = regmap_read(arizona->regmap, params->base, &val);
+	if (ret != 0)
+		goto out;
+
+	val &= ~ARIZONA_EQ1_B1_MODE;
+	data[0] |= cpu_to_be16(val);
+
+	ret = regmap_raw_write(arizona->regmap, params->base, data, len);
+
+out:
+	kfree(data);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_eq_coeff_put);
+
+int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+	__be16 *data = (__be16 *)ucontrol->value.bytes.data;
+	s16 val = be16_to_cpu(*data);
+
+	if (abs(val) >= 4096) {
+		dev_err(arizona->dev, "Rejecting unstable LHPF coefficients\n");
+		return -EINVAL;
+	}
+
+	return snd_soc_bytes_put(kcontrol, ucontrol);
+}
+EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
+
+int arizona_of_get_audio_pdata(struct arizona *arizona)
+{
+	struct arizona_pdata *pdata = &arizona->pdata;
+	struct device_node *np = arizona->dev->of_node;
+	struct property *prop;
+	const __be32 *cur;
+	u32 val;
+	u32 pdm_val[ARIZONA_MAX_PDM_SPK];
+	int ret;
+	int count = 0;
+
+	count = 0;
+	of_property_for_each_u32(np, "wlf,inmode", prop, cur, val) {
+		if (count == ARRAY_SIZE(pdata->inmode))
+			break;
+
+		pdata->inmode[count] = val;
+		count++;
+	}
+
+	count = 0;
+	of_property_for_each_u32(np, "wlf,dmic-ref", prop, cur, val) {
+		if (count == ARRAY_SIZE(pdata->dmic_ref))
+			break;
+
+		pdata->dmic_ref[count] = val;
+		count++;
+	}
+
+	count = 0;
+	of_property_for_each_u32(np, "wlf,out-mono", prop, cur, val) {
+		if (count == ARRAY_SIZE(pdata->out_mono))
+			break;
+
+		pdata->out_mono[count] = !!val;
+		count++;
+	}
+
+	count = 0;
+	of_property_for_each_u32(np, "wlf,max-channels-clocked", prop, cur, val) {
+		if (count == ARRAY_SIZE(pdata->max_channels_clocked))
+			break;
+
+		pdata->max_channels_clocked[count] = val;
+		count++;
+	}
+
+	count = 0;
+	of_property_for_each_u32(np, "wlf,out-volume-limit", prop, cur, val) {
+		if (count == ARRAY_SIZE(pdata->out_vol_limit))
+			break;
+
+		pdata->out_vol_limit[count] = val;
+		count++;
+	}
+
+	ret = of_property_read_u32_array(np, "wlf,spk-fmt",
+					 pdm_val, ARRAY_SIZE(pdm_val));
+
+	if (ret >= 0)
+		for (count = 0; count < ARRAY_SIZE(pdata->spk_fmt); ++count)
+			pdata->spk_fmt[count] = pdm_val[count];
+
+	ret = of_property_read_u32_array(np, "wlf,spk-mute",
+					 pdm_val, ARRAY_SIZE(pdm_val));
+
+	if (ret >= 0)
+		for (count = 0; count < ARRAY_SIZE(pdata->spk_mute); ++count)
+			pdata->spk_mute[count] = pdm_val[count];
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_of_get_audio_pdata);
+
+MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
new file mode 100644
index 0000000..e3ccee5
--- /dev/null
+++ b/sound/soc/codecs/arizona.h
@@ -0,0 +1,357 @@
+/*
+ * arizona.h - Wolfson Arizona class device shared support
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ASOC_ARIZONA_H
+#define _ASOC_ARIZONA_H
+
+#include <linux/completion.h>
+#include <linux/notifier.h>
+#include <linux/mfd/arizona/core.h>
+
+#include <sound/soc.h>
+
+#include "wm_adsp.h"
+
+#define ARIZONA_CLK_SYSCLK         1
+#define ARIZONA_CLK_ASYNCCLK       2
+#define ARIZONA_CLK_OPCLK          3
+#define ARIZONA_CLK_ASYNC_OPCLK    4
+
+#define ARIZONA_CLK_SRC_MCLK1    0x0
+#define ARIZONA_CLK_SRC_MCLK2    0x1
+#define ARIZONA_CLK_SRC_FLL1     0x4
+#define ARIZONA_CLK_SRC_FLL2     0x5
+#define ARIZONA_CLK_SRC_AIF1BCLK 0x8
+#define ARIZONA_CLK_SRC_AIF2BCLK 0x9
+#define ARIZONA_CLK_SRC_AIF3BCLK 0xa
+
+#define ARIZONA_FLL_SRC_NONE      -1
+#define ARIZONA_FLL_SRC_MCLK1      0
+#define ARIZONA_FLL_SRC_MCLK2      1
+#define ARIZONA_FLL_SRC_SLIMCLK    3
+#define ARIZONA_FLL_SRC_FLL1       4
+#define ARIZONA_FLL_SRC_FLL2       5
+#define ARIZONA_FLL_SRC_AIF1BCLK   8
+#define ARIZONA_FLL_SRC_AIF2BCLK   9
+#define ARIZONA_FLL_SRC_AIF3BCLK  10
+#define ARIZONA_FLL_SRC_AIF1LRCLK 12
+#define ARIZONA_FLL_SRC_AIF2LRCLK 13
+#define ARIZONA_FLL_SRC_AIF3LRCLK 14
+
+#define ARIZONA_MIXER_VOL_MASK             0x00FE
+#define ARIZONA_MIXER_VOL_SHIFT                 1
+#define ARIZONA_MIXER_VOL_WIDTH                 7
+
+#define ARIZONA_CLK_6MHZ   0
+#define ARIZONA_CLK_12MHZ  1
+#define ARIZONA_CLK_24MHZ  2
+#define ARIZONA_CLK_49MHZ  3
+#define ARIZONA_CLK_73MHZ  4
+#define ARIZONA_CLK_98MHZ  5
+#define ARIZONA_CLK_147MHZ 6
+
+#define ARIZONA_MAX_DAI  10
+#define ARIZONA_MAX_ADSP 4
+
+#define ARIZONA_DVFS_SR1_RQ	0x001
+#define ARIZONA_DVFS_ADSP1_RQ	0x100
+
+/* Notifier events */
+#define ARIZONA_NOTIFY_VOICE_TRIGGER   0x1
+
+struct wm_adsp;
+
+struct arizona_dai_priv {
+	int clk;
+
+	struct snd_pcm_hw_constraint_list constraint;
+};
+
+struct arizona_priv {
+	struct wm_adsp adsp[ARIZONA_MAX_ADSP];
+	struct arizona *arizona;
+	int sysclk;
+	int asyncclk;
+	struct arizona_dai_priv dai[ARIZONA_MAX_DAI];
+
+	int num_inputs;
+	unsigned int in_pending;
+
+	unsigned int out_up_pending;
+	unsigned int out_up_delay;
+	unsigned int out_down_pending;
+	unsigned int out_down_delay;
+
+	unsigned int dvfs_reqs;
+	struct mutex dvfs_lock;
+	bool dvfs_cached;
+};
+
+struct arizona_voice_trigger_info {
+	int core;
+};
+
+#define ARIZONA_NUM_MIXER_INPUTS 104
+
+extern const unsigned int arizona_mixer_tlv[];
+extern const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
+extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
+
+#define ARIZONA_GAINMUX_CONTROLS(name, base) \
+	SOC_SINGLE_RANGE_TLV(name " Input Volume", base + 1,		\
+			     ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,	\
+			     arizona_mixer_tlv)
+
+#define ARIZONA_MIXER_CONTROLS(name, base) \
+	SOC_SINGLE_RANGE_TLV(name " Input 1 Volume", base + 1,		\
+			     ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,	\
+			     arizona_mixer_tlv),			\
+	SOC_SINGLE_RANGE_TLV(name " Input 2 Volume", base + 3,		\
+			     ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,	\
+			     arizona_mixer_tlv),			\
+	SOC_SINGLE_RANGE_TLV(name " Input 3 Volume", base + 5,		\
+			     ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,	\
+			     arizona_mixer_tlv),			\
+	SOC_SINGLE_RANGE_TLV(name " Input 4 Volume", base + 7,		\
+			     ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0,	\
+			     arizona_mixer_tlv)
+
+#define ARIZONA_MUX_ENUM_DECL(name, reg) \
+	SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL( \
+		name, reg, 0, 0xff, arizona_mixer_texts, arizona_mixer_values)
+
+#define ARIZONA_MUX_CTL_DECL(name) \
+	const struct snd_kcontrol_new name##_mux =	\
+		SOC_DAPM_ENUM("Route", name##_enum)
+
+#define ARIZONA_MUX_ENUMS(name, base_reg) \
+	static ARIZONA_MUX_ENUM_DECL(name##_enum, base_reg);      \
+	static ARIZONA_MUX_CTL_DECL(name)
+
+#define ARIZONA_MIXER_ENUMS(name, base_reg) \
+	ARIZONA_MUX_ENUMS(name##_in1, base_reg);     \
+	ARIZONA_MUX_ENUMS(name##_in2, base_reg + 2); \
+	ARIZONA_MUX_ENUMS(name##_in3, base_reg + 4); \
+	ARIZONA_MUX_ENUMS(name##_in4, base_reg + 6)
+
+#define ARIZONA_DSP_AUX_ENUMS(name, base_reg) \
+	ARIZONA_MUX_ENUMS(name##_aux1, base_reg);	\
+	ARIZONA_MUX_ENUMS(name##_aux2, base_reg + 8);	\
+	ARIZONA_MUX_ENUMS(name##_aux3, base_reg + 16);	\
+	ARIZONA_MUX_ENUMS(name##_aux4, base_reg + 24);	\
+	ARIZONA_MUX_ENUMS(name##_aux5, base_reg + 32);	\
+	ARIZONA_MUX_ENUMS(name##_aux6, base_reg + 40)
+
+#define ARIZONA_MUX(name, ctrl) \
+	SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+
+#define ARIZONA_MUX_WIDGETS(name, name_str) \
+	ARIZONA_MUX(name_str " Input", &name##_mux)
+
+#define ARIZONA_MIXER_WIDGETS(name, name_str)	\
+	ARIZONA_MUX(name_str " Input 1", &name##_in1_mux), \
+	ARIZONA_MUX(name_str " Input 2", &name##_in2_mux), \
+	ARIZONA_MUX(name_str " Input 3", &name##_in3_mux), \
+	ARIZONA_MUX(name_str " Input 4", &name##_in4_mux), \
+	SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
+
+#define ARIZONA_DSP_WIDGETS(name, name_str) \
+	ARIZONA_MIXER_WIDGETS(name##L, name_str "L"), \
+	ARIZONA_MIXER_WIDGETS(name##R, name_str "R"), \
+	ARIZONA_MUX(name_str " Aux 1", &name##_aux1_mux), \
+	ARIZONA_MUX(name_str " Aux 2", &name##_aux2_mux), \
+	ARIZONA_MUX(name_str " Aux 3", &name##_aux3_mux), \
+	ARIZONA_MUX(name_str " Aux 4", &name##_aux4_mux), \
+	ARIZONA_MUX(name_str " Aux 5", &name##_aux5_mux), \
+	ARIZONA_MUX(name_str " Aux 6", &name##_aux6_mux)
+
+#define ARIZONA_MUX_ROUTES(widget, name) \
+	{ widget, NULL, name " Input" }, \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Input")
+
+#define ARIZONA_MIXER_ROUTES(widget, name) \
+	{ widget, NULL, name " Mixer" },         \
+	{ name " Mixer", NULL, name " Input 1" }, \
+	{ name " Mixer", NULL, name " Input 2" }, \
+	{ name " Mixer", NULL, name " Input 3" }, \
+	{ name " Mixer", NULL, name " Input 4" }, \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Input 1"), \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Input 2"), \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Input 3"), \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Input 4")
+
+#define ARIZONA_DSP_ROUTES(name) \
+	{ name, NULL, name " Preloader"}, \
+	{ name " Preloader", NULL, "SYSCLK" }, \
+	{ name " Preload", NULL, name " Preloader"}, \
+	{ name, NULL, name " Aux 1" }, \
+	{ name, NULL, name " Aux 2" }, \
+	{ name, NULL, name " Aux 3" }, \
+	{ name, NULL, name " Aux 4" }, \
+	{ name, NULL, name " Aux 5" }, \
+	{ name, NULL, name " Aux 6" }, \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 1"), \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 2"), \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 3"), \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 4"), \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 5"), \
+	ARIZONA_MIXER_INPUT_ROUTES(name " Aux 6"), \
+	ARIZONA_MIXER_ROUTES(name, name "L"), \
+	ARIZONA_MIXER_ROUTES(name, name "R")
+
+#define ARIZONA_EQ_CONTROL(xname, xbase)                      \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,   \
+	.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
+	.put = arizona_eq_coeff_put, .private_value =         \
+	((unsigned long)&(struct soc_bytes) { .base = xbase,  \
+	 .num_regs = 20, .mask = ~ARIZONA_EQ1_B1_MODE }) }
+
+#define ARIZONA_LHPF_CONTROL(xname, xbase)                    \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,   \
+	.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
+	.put = arizona_lhpf_coeff_put, .private_value =       \
+	((unsigned long)&(struct soc_bytes) { .base = xbase,  \
+	 .num_regs = 1 }) }
+
+#define ARIZONA_RATE_ENUM_SIZE 4
+#define ARIZONA_SAMPLE_RATE_ENUM_SIZE 14
+
+extern const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
+extern const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
+extern const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE];
+extern const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE];
+
+extern const struct soc_enum arizona_isrc_fsl[];
+extern const struct soc_enum arizona_isrc_fsh[];
+extern const struct soc_enum arizona_asrc_rate1;
+
+extern const struct soc_enum arizona_in_vi_ramp;
+extern const struct soc_enum arizona_in_vd_ramp;
+
+extern const struct soc_enum arizona_out_vi_ramp;
+extern const struct soc_enum arizona_out_vd_ramp;
+
+extern const struct soc_enum arizona_lhpf1_mode;
+extern const struct soc_enum arizona_lhpf2_mode;
+extern const struct soc_enum arizona_lhpf3_mode;
+extern const struct soc_enum arizona_lhpf4_mode;
+
+extern const struct soc_enum arizona_ng_hold;
+extern const struct soc_enum arizona_in_hpf_cut_enum;
+extern const struct soc_enum arizona_in_dmic_osr[];
+
+extern const struct snd_kcontrol_new arizona_adsp2_rate_controls[];
+
+extern const struct soc_enum arizona_anc_input_src[];
+extern const struct soc_enum arizona_anc_ng_enum;
+extern const struct soc_enum arizona_output_anc_src[];
+
+extern const struct snd_kcontrol_new arizona_voice_trigger_switch[];
+
+int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+		  int event);
+int arizona_out_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+		   int event);
+int arizona_hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+		  int event);
+int arizona_anc_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+		   int event);
+
+int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_value *ucontrol);
+int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol);
+
+int arizona_clk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+		   int event);
+int arizona_set_sysclk(struct snd_soc_component *component, int clk_id, int source,
+		       unsigned int freq, int dir);
+
+extern const struct snd_soc_dai_ops arizona_dai_ops;
+extern const struct snd_soc_dai_ops arizona_simple_dai_ops;
+
+#define ARIZONA_FLL_NAME_LEN 20
+
+struct arizona_fll {
+	struct arizona *arizona;
+	int id;
+	unsigned int base;
+	unsigned int vco_mult;
+
+	unsigned int fout;
+	int sync_src;
+	unsigned int sync_freq;
+	int ref_src;
+	unsigned int ref_freq;
+
+	char lock_name[ARIZONA_FLL_NAME_LEN];
+	char clock_ok_name[ARIZONA_FLL_NAME_LEN];
+};
+
+int arizona_dvfs_up(struct snd_soc_component *component, unsigned int flags);
+int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags);
+int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event);
+void arizona_init_dvfs(struct arizona_priv *priv);
+
+int arizona_init_fll(struct arizona *arizona, int id, int base,
+		     int lock_irq, int ok_irq, struct arizona_fll *fll);
+int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
+			   unsigned int Fref, unsigned int Fout);
+int arizona_set_fll(struct arizona_fll *fll, int source,
+		    unsigned int Fref, unsigned int Fout);
+
+int arizona_init_spk(struct snd_soc_component *component);
+int arizona_init_gpio(struct snd_soc_component *component);
+int arizona_init_mono(struct snd_soc_component *component);
+
+int arizona_init_common(struct arizona *arizona);
+int arizona_init_vol_limit(struct arizona *arizona);
+
+int arizona_init_spk_irqs(struct arizona *arizona);
+int arizona_free_spk_irqs(struct arizona *arizona);
+
+int arizona_init_dai(struct arizona_priv *priv, int dai);
+
+int arizona_set_output_mode(struct snd_soc_component *component, int output,
+			    bool diff);
+
+bool arizona_input_analog(struct snd_soc_component *component, int shift);
+
+const char *arizona_sample_rate_val_to_name(unsigned int rate_val);
+
+static inline int arizona_register_notifier(struct snd_soc_component *component,
+					    struct notifier_block *nb,
+					    int (*notify)
+					    (struct notifier_block *nb,
+					    unsigned long action, void *data))
+{
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+
+	nb->notifier_call = notify;
+
+	return blocking_notifier_chain_register(&arizona->notifier, nb);
+}
+
+static inline int arizona_unregister_notifier(struct snd_soc_component *component,
+					      struct notifier_block *nb)
+{
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+
+	return blocking_notifier_chain_unregister(&arizona->notifier, nb);
+}
+
+int arizona_of_get_audio_pdata(struct arizona *arizona);
+
+#endif
diff --git a/sound/soc/codecs/bd28623.c b/sound/soc/codecs/bd28623.c
new file mode 100644
index 0000000..31904ef
--- /dev/null
+++ b/sound/soc/codecs/bd28623.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// ROHM BD28623MUV class D speaker amplifier codec driver.
+//
+// Copyright (c) 2018 Socionext Inc.
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#define BD28623_NUM_SUPPLIES    3
+
+static const char *const bd28623_supply_names[BD28623_NUM_SUPPLIES] = {
+	"VCCA",
+	"VCCP1",
+	"VCCP2",
+};
+
+struct bd28623_priv {
+	struct device *dev;
+	struct regulator_bulk_data supplies[BD28623_NUM_SUPPLIES];
+	struct gpio_desc *reset_gpio;
+	struct gpio_desc *mute_gpio;
+
+	int switch_spk;
+};
+
+static const struct snd_soc_dapm_widget bd28623_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_OUTPUT("OUT1P"),
+	SND_SOC_DAPM_OUTPUT("OUT1N"),
+	SND_SOC_DAPM_OUTPUT("OUT2P"),
+	SND_SOC_DAPM_OUTPUT("OUT2N"),
+};
+
+static const struct snd_soc_dapm_route bd28623_routes[] = {
+	{ "OUT1P", NULL, "DAC" },
+	{ "OUT1N", NULL, "DAC" },
+	{ "OUT2P", NULL, "DAC" },
+	{ "OUT2N", NULL, "DAC" },
+};
+
+static int bd28623_power_on(struct bd28623_priv *bd)
+{
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(bd->supplies), bd->supplies);
+	if (ret) {
+		dev_err(bd->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	gpiod_set_value_cansleep(bd->reset_gpio, 0);
+	usleep_range(300000, 400000);
+
+	return 0;
+}
+
+static void bd28623_power_off(struct bd28623_priv *bd)
+{
+	gpiod_set_value_cansleep(bd->reset_gpio, 1);
+
+	regulator_bulk_disable(ARRAY_SIZE(bd->supplies), bd->supplies);
+}
+
+static int bd28623_get_switch_spk(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = bd->switch_spk;
+
+	return 0;
+}
+
+static int bd28623_set_switch_spk(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
+
+	if (bd->switch_spk == ucontrol->value.integer.value[0])
+		return 0;
+
+	bd->switch_spk = ucontrol->value.integer.value[0];
+
+	gpiod_set_value_cansleep(bd->mute_gpio, bd->switch_spk ? 0 : 1);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new bd28623_controls[] = {
+	SOC_SINGLE_BOOL_EXT("Speaker Switch", 0,
+			    bd28623_get_switch_spk, bd28623_set_switch_spk),
+};
+
+static int bd28623_codec_probe(struct snd_soc_component *component)
+{
+	struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	bd->switch_spk = 1;
+
+	ret = bd28623_power_on(bd);
+	if (ret)
+		return ret;
+
+	gpiod_set_value_cansleep(bd->mute_gpio, bd->switch_spk ? 0 : 1);
+
+	return 0;
+}
+
+static void bd28623_codec_remove(struct snd_soc_component *component)
+{
+	struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
+
+	bd28623_power_off(bd);
+}
+
+static int bd28623_codec_suspend(struct snd_soc_component *component)
+{
+	struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
+
+	bd28623_power_off(bd);
+
+	return 0;
+}
+
+static int bd28623_codec_resume(struct snd_soc_component *component)
+{
+	struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = bd28623_power_on(bd);
+	if (ret)
+		return ret;
+
+	gpiod_set_value_cansleep(bd->mute_gpio, bd->switch_spk ? 0 : 1);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_codec_bd = {
+	.probe			= bd28623_codec_probe,
+	.remove			= bd28623_codec_remove,
+	.suspend		= bd28623_codec_suspend,
+	.resume			= bd28623_codec_resume,
+	.dapm_widgets		= bd28623_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(bd28623_widgets),
+	.dapm_routes		= bd28623_routes,
+	.num_dapm_routes	= ARRAY_SIZE(bd28623_routes),
+	.controls		= bd28623_controls,
+	.num_controls		= ARRAY_SIZE(bd28623_controls),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static struct snd_soc_dai_driver soc_dai_bd = {
+	.name     = "bd28623-speaker",
+	.playback = {
+		.stream_name  = "Playback",
+		.formats      = SNDRV_PCM_FMTBIT_S32_LE |
+				SNDRV_PCM_FMTBIT_S24_LE |
+				SNDRV_PCM_FMTBIT_S16_LE,
+		.rates        = SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_44100 |
+				SNDRV_PCM_RATE_32000,
+		.channels_min = 2,
+		.channels_max = 2,
+	},
+};
+
+static int bd28623_probe(struct platform_device *pdev)
+{
+	struct bd28623_priv *bd;
+	struct device *dev = &pdev->dev;
+	int i, ret;
+
+	bd = devm_kzalloc(&pdev->dev, sizeof(struct bd28623_priv), GFP_KERNEL);
+	if (!bd)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(bd->supplies); i++)
+		bd->supplies[i].supply = bd28623_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(bd->supplies),
+				      bd->supplies);
+	if (ret) {
+		dev_err(dev, "Failed to get supplies: %d\n", ret);
+		return ret;
+	}
+
+	bd->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						 GPIOD_OUT_HIGH);
+	if (IS_ERR(bd->reset_gpio)) {
+		dev_err(dev, "Failed to request reset_gpio: %ld\n",
+			PTR_ERR(bd->reset_gpio));
+		return PTR_ERR(bd->reset_gpio);
+	}
+
+	bd->mute_gpio = devm_gpiod_get_optional(dev, "mute",
+						GPIOD_OUT_HIGH);
+	if (IS_ERR(bd->mute_gpio)) {
+		dev_err(dev, "Failed to request mute_gpio: %ld\n",
+			PTR_ERR(bd->mute_gpio));
+		return PTR_ERR(bd->mute_gpio);
+	}
+
+	platform_set_drvdata(pdev, bd);
+	bd->dev = dev;
+
+	return devm_snd_soc_register_component(dev, &soc_codec_bd,
+					       &soc_dai_bd, 1);
+}
+
+static const struct of_device_id bd28623_of_match[] = {
+	{ .compatible = "rohm,bd28623", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, bd28623_of_match);
+
+static struct platform_driver bd28623_codec_driver = {
+	.driver = {
+		.name = "bd28623",
+		.of_match_table = of_match_ptr(bd28623_of_match),
+	},
+	.probe  = bd28623_probe,
+};
+module_platform_driver(bd28623_codec_driver);
+
+MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
+MODULE_DESCRIPTION("ROHM BD28623 speaker amplifier driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c
new file mode 100644
index 0000000..8422042
--- /dev/null
+++ b/sound/soc/codecs/bt-sco.c
@@ -0,0 +1,122 @@
+/*
+ * Driver for generic Bluetooth SCO link
+ * Copyright 2011 Lars-Peter Clausen <lars@metafoo.de>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/soc.h>
+
+static const struct snd_soc_dapm_widget bt_sco_widgets[] = {
+	SND_SOC_DAPM_INPUT("RX"),
+	SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route bt_sco_routes[] = {
+	{ "Capture", NULL, "RX" },
+	{ "TX", NULL, "Playback" },
+};
+
+static struct snd_soc_dai_driver bt_sco_dai[] = {
+	{
+		.name = "bt-sco-pcm",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.capture = {
+			 .stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+	},
+	{
+		.name = "bt-sco-pcm-wb",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.capture = {
+			 .stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+	}
+};
+
+static const struct snd_soc_component_driver soc_component_dev_bt_sco = {
+	.dapm_widgets		= bt_sco_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(bt_sco_widgets),
+	.dapm_routes		= bt_sco_routes,
+	.num_dapm_routes	= ARRAY_SIZE(bt_sco_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int bt_sco_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_bt_sco,
+				      bt_sco_dai, ARRAY_SIZE(bt_sco_dai));
+}
+
+static int bt_sco_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct platform_device_id bt_sco_driver_ids[] = {
+	{
+		.name		= "dfbmcs320",
+	},
+	{
+		.name		= "bt-sco",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id bt_sco_codec_of_match[] = {
+	{ .compatible = "delta,dfbmcs320", },
+	{ .compatible = "linux,bt-sco", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, bt_sco_codec_of_match);
+#endif
+
+static struct platform_driver bt_sco_driver = {
+	.driver = {
+		.name = "bt-sco",
+		.of_match_table = of_match_ptr(bt_sco_codec_of_match),
+	},
+	.probe = bt_sco_probe,
+	.remove = bt_sco_remove,
+	.id_table = bt_sco_driver_ids,
+};
+
+module_platform_driver(bt_sco_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ASoC generic bluetooth sco link driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
new file mode 100644
index 0000000..d7f05b3
--- /dev/null
+++ b/sound/soc/codecs/cpcap.c
@@ -0,0 +1,1562 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ALSA SoC CPCAP codec driver
+ *
+ * Copyright (C) 2017 - 2018 Sebastian Reichel <sre@kernel.org>
+ *
+ * Very loosely based on original driver from Motorola:
+ * Copyright (C) 2007 - 2009 Motorola, Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/motorola-cpcap.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+/* Register 513 CPCAP_REG_CC     --- CODEC */
+#define CPCAP_BIT_CDC_CLK2                15
+#define CPCAP_BIT_CDC_CLK1                14
+#define CPCAP_BIT_CDC_CLK0                13
+#define CPCAP_BIT_CDC_SR3                 12
+#define CPCAP_BIT_CDC_SR2                 11
+#define CPCAP_BIT_CDC_SR1                 10
+#define CPCAP_BIT_CDC_SR0                 9
+#define CPCAP_BIT_CDC_CLOCK_TREE_RESET    8
+#define CPCAP_BIT_MIC2_CDC_EN             7
+#define CPCAP_BIT_CDC_EN_RX               6
+#define CPCAP_BIT_DF_RESET                5
+#define CPCAP_BIT_MIC1_CDC_EN             4
+#define CPCAP_BIT_AUDOHPF_1		  3
+#define CPCAP_BIT_AUDOHPF_0		  2
+#define CPCAP_BIT_AUDIHPF_1		  1
+#define CPCAP_BIT_AUDIHPF_0		  0
+
+/* Register 514 CPCAP_REG_CDI    --- CODEC Digital Audio Interface */
+#define CPCAP_BIT_CDC_PLL_SEL             15
+#define CPCAP_BIT_CLK_IN_SEL              13
+#define CPCAP_BIT_DIG_AUD_IN              12
+#define CPCAP_BIT_CDC_CLK_EN              11
+#define CPCAP_BIT_CDC_DIG_AUD_FS1         10
+#define CPCAP_BIT_CDC_DIG_AUD_FS0         9
+#define CPCAP_BIT_MIC2_TIMESLOT2          8
+#define CPCAP_BIT_MIC2_TIMESLOT1          7
+#define CPCAP_BIT_MIC2_TIMESLOT0          6
+#define CPCAP_BIT_MIC1_RX_TIMESLOT2       5
+#define CPCAP_BIT_MIC1_RX_TIMESLOT1       4
+#define CPCAP_BIT_MIC1_RX_TIMESLOT0       3
+#define CPCAP_BIT_FS_INV                  2
+#define CPCAP_BIT_CLK_INV                 1
+#define CPCAP_BIT_SMB_CDC                 0
+
+/* Register 515 CPCAP_REG_SDAC   --- Stereo DAC */
+#define CPCAP_BIT_FSYNC_CLK_IN_COMMON     11
+#define CPCAP_BIT_SLAVE_PLL_CLK_INPUT     10
+#define CPCAP_BIT_ST_CLOCK_TREE_RESET     9
+#define CPCAP_BIT_DF_RESET_ST_DAC         8
+#define CPCAP_BIT_ST_SR3                  7
+#define CPCAP_BIT_ST_SR2                  6
+#define CPCAP_BIT_ST_SR1                  5
+#define CPCAP_BIT_ST_SR0                  4
+#define CPCAP_BIT_ST_DAC_CLK2             3
+#define CPCAP_BIT_ST_DAC_CLK1             2
+#define CPCAP_BIT_ST_DAC_CLK0             1
+#define CPCAP_BIT_ST_DAC_EN               0
+
+/* Register 516 CPCAP_REG_SDACDI --- Stereo DAC Digital Audio Interface */
+#define CPCAP_BIT_ST_L_TIMESLOT2          13
+#define CPCAP_BIT_ST_L_TIMESLOT1          12
+#define CPCAP_BIT_ST_L_TIMESLOT0          11
+#define CPCAP_BIT_ST_R_TIMESLOT2          10
+#define CPCAP_BIT_ST_R_TIMESLOT1          9
+#define CPCAP_BIT_ST_R_TIMESLOT0          8
+#define CPCAP_BIT_ST_DAC_CLK_IN_SEL       7
+#define CPCAP_BIT_ST_FS_INV               6
+#define CPCAP_BIT_ST_CLK_INV              5
+#define CPCAP_BIT_ST_DIG_AUD_FS1          4
+#define CPCAP_BIT_ST_DIG_AUD_FS0          3
+#define CPCAP_BIT_DIG_AUD_IN_ST_DAC       2
+#define CPCAP_BIT_ST_CLK_EN               1
+#define CPCAP_BIT_SMB_ST_DAC              0
+
+/* Register 517 CPCAP_REG_TXI    --- TX Interface */
+#define CPCAP_BIT_PTT_TH		15
+#define CPCAP_BIT_PTT_CMP_EN		14
+#define CPCAP_BIT_HS_ID_TX		13
+#define CPCAP_BIT_MB_ON2		12
+#define CPCAP_BIT_MB_ON1L		11
+#define CPCAP_BIT_MB_ON1R		10
+#define CPCAP_BIT_RX_L_ENCODE		9
+#define CPCAP_BIT_RX_R_ENCODE		8
+#define CPCAP_BIT_MIC2_MUX		7
+#define CPCAP_BIT_MIC2_PGA_EN		6
+#define CPCAP_BIT_CDET_DIS		5
+#define CPCAP_BIT_EMU_MIC_MUX		4
+#define CPCAP_BIT_HS_MIC_MUX		3
+#define CPCAP_BIT_MIC1_MUX		2
+#define CPCAP_BIT_MIC1_PGA_EN		1
+#define CPCAP_BIT_DLM			0
+
+/* Register 518 CPCAP_REG_TXMP   --- Mic Gain */
+#define CPCAP_BIT_MB_BIAS_R1              11
+#define CPCAP_BIT_MB_BIAS_R0              10
+#define CPCAP_BIT_MIC2_GAIN_4             9
+#define CPCAP_BIT_MIC2_GAIN_3             8
+#define CPCAP_BIT_MIC2_GAIN_2             7
+#define CPCAP_BIT_MIC2_GAIN_1             6
+#define CPCAP_BIT_MIC2_GAIN_0             5
+#define CPCAP_BIT_MIC1_GAIN_4             4
+#define CPCAP_BIT_MIC1_GAIN_3             3
+#define CPCAP_BIT_MIC1_GAIN_2             2
+#define CPCAP_BIT_MIC1_GAIN_1             1
+#define CPCAP_BIT_MIC1_GAIN_0             0
+
+/* Register 519 CPCAP_REG_RXOA   --- RX Output Amplifier */
+#define CPCAP_BIT_UNUSED_519_15		15
+#define CPCAP_BIT_UNUSED_519_14		14
+#define CPCAP_BIT_UNUSED_519_13		13
+#define CPCAP_BIT_STDAC_LOW_PWR_DISABLE	12
+#define CPCAP_BIT_HS_LOW_PWR		11
+#define CPCAP_BIT_HS_ID_RX		10
+#define CPCAP_BIT_ST_HS_CP_EN		9
+#define CPCAP_BIT_EMU_SPKR_R_EN		8
+#define CPCAP_BIT_EMU_SPKR_L_EN		7
+#define CPCAP_BIT_HS_L_EN		6
+#define CPCAP_BIT_HS_R_EN		5
+#define CPCAP_BIT_A4_LINEOUT_L_EN	4
+#define CPCAP_BIT_A4_LINEOUT_R_EN	3
+#define CPCAP_BIT_A2_LDSP_L_EN		2
+#define CPCAP_BIT_A2_LDSP_R_EN		1
+#define CPCAP_BIT_A1_EAR_EN		0
+
+/* Register 520 CPCAP_REG_RXVC   --- RX Volume Control */
+#define CPCAP_BIT_VOL_EXT3                15
+#define CPCAP_BIT_VOL_EXT2                14
+#define CPCAP_BIT_VOL_EXT1                13
+#define CPCAP_BIT_VOL_EXT0                12
+#define CPCAP_BIT_VOL_DAC3                11
+#define CPCAP_BIT_VOL_DAC2                10
+#define CPCAP_BIT_VOL_DAC1                9
+#define CPCAP_BIT_VOL_DAC0                8
+#define CPCAP_BIT_VOL_DAC_LSB_1dB1        7
+#define CPCAP_BIT_VOL_DAC_LSB_1dB0        6
+#define CPCAP_BIT_VOL_CDC3                5
+#define CPCAP_BIT_VOL_CDC2                4
+#define CPCAP_BIT_VOL_CDC1                3
+#define CPCAP_BIT_VOL_CDC0                2
+#define CPCAP_BIT_VOL_CDC_LSB_1dB1        1
+#define CPCAP_BIT_VOL_CDC_LSB_1dB0        0
+
+/* Register 521 CPCAP_REG_RXCOA  --- Codec to Output Amp Switches */
+#define CPCAP_BIT_PGA_CDC_EN              10
+#define CPCAP_BIT_CDC_SW                  9
+#define CPCAP_BIT_PGA_OUTR_USBDP_CDC_SW   8
+#define CPCAP_BIT_PGA_OUTL_USBDN_CDC_SW   7
+#define CPCAP_BIT_ALEFT_HS_CDC_SW         6
+#define CPCAP_BIT_ARIGHT_HS_CDC_SW        5
+#define CPCAP_BIT_A4_LINEOUT_L_CDC_SW     4
+#define CPCAP_BIT_A4_LINEOUT_R_CDC_SW     3
+#define CPCAP_BIT_A2_LDSP_L_CDC_SW        2
+#define CPCAP_BIT_A2_LDSP_R_CDC_SW        1
+#define CPCAP_BIT_A1_EAR_CDC_SW           0
+
+/* Register 522 CPCAP_REG_RXSDOA --- RX Stereo DAC to Output Amp Switches */
+#define CPCAP_BIT_PGA_DAC_EN              12
+#define CPCAP_BIT_ST_DAC_SW               11
+#define CPCAP_BIT_MONO_DAC1               10
+#define CPCAP_BIT_MONO_DAC0               9
+#define CPCAP_BIT_PGA_OUTR_USBDP_DAC_SW   8
+#define CPCAP_BIT_PGA_OUTL_USBDN_DAC_SW   7
+#define CPCAP_BIT_ALEFT_HS_DAC_SW         6
+#define CPCAP_BIT_ARIGHT_HS_DAC_SW        5
+#define CPCAP_BIT_A4_LINEOUT_L_DAC_SW     4
+#define CPCAP_BIT_A4_LINEOUT_R_DAC_SW     3
+#define CPCAP_BIT_A2_LDSP_L_DAC_SW        2
+#define CPCAP_BIT_A2_LDSP_R_DAC_SW        1
+#define CPCAP_BIT_A1_EAR_DAC_SW           0
+
+/* Register 523 CPCAP_REG_RXEPOA --- RX External PGA to Output Amp Switches */
+#define CPCAP_BIT_PGA_EXT_L_EN            14
+#define CPCAP_BIT_PGA_EXT_R_EN            13
+#define CPCAP_BIT_PGA_IN_L_SW             12
+#define CPCAP_BIT_PGA_IN_R_SW             11
+#define CPCAP_BIT_MONO_EXT1               10
+#define CPCAP_BIT_MONO_EXT0               9
+#define CPCAP_BIT_PGA_OUTR_USBDP_EXT_SW   8
+#define CPCAP_BIT_PGA_OUTL_USBDN_EXT_SW   7
+#define CPCAP_BIT_ALEFT_HS_EXT_SW         6
+#define CPCAP_BIT_ARIGHT_HS_EXT_SW        5
+#define CPCAP_BIT_A4_LINEOUT_L_EXT_SW     4
+#define CPCAP_BIT_A4_LINEOUT_R_EXT_SW     3
+#define CPCAP_BIT_A2_LDSP_L_EXT_SW        2
+#define CPCAP_BIT_A2_LDSP_R_EXT_SW        1
+#define CPCAP_BIT_A1_EAR_EXT_SW           0
+
+/* Register 525 CPCAP_REG_A2LA --- SPK Amplifier and Clock Config for Headset */
+#define CPCAP_BIT_NCP_CLK_SYNC            7
+#define CPCAP_BIT_A2_CLK_SYNC             6
+#define CPCAP_BIT_A2_FREE_RUN             5
+#define CPCAP_BIT_A2_CLK2                 4
+#define CPCAP_BIT_A2_CLK1                 3
+#define CPCAP_BIT_A2_CLK0                 2
+#define CPCAP_BIT_A2_CLK_IN               1
+#define CPCAP_BIT_A2_CONFIG               0
+
+#define SLEEP_ACTIVATE_POWER 2
+#define CLOCK_TREE_RESET_TIME 1
+
+/* constants for ST delay workaround */
+#define STM_STDAC_ACTIVATE_RAMP_TIME   1
+#define STM_STDAC_EN_TEST_PRE          0x090C
+#define STM_STDAC_EN_TEST_POST         0x0000
+#define STM_STDAC_EN_ST_TEST1_PRE      0x2400
+#define STM_STDAC_EN_ST_TEST1_POST     0x0400
+
+struct cpcap_reg_info {
+	u16 reg;
+	u16 mask;
+	u16 val;
+};
+
+static const struct cpcap_reg_info cpcap_default_regs[] = {
+	{ CPCAP_REG_CC, 0xFFFF, 0x0000 },
+	{ CPCAP_REG_CC, 0xFFFF, 0x0000 },
+	{ CPCAP_REG_CDI, 0xBFFF, 0x0000 },
+	{ CPCAP_REG_SDAC, 0x0FFF, 0x0000 },
+	{ CPCAP_REG_SDACDI, 0x3FFF, 0x0000 },
+	{ CPCAP_REG_TXI, 0x0FDF, 0x0000 },
+	{ CPCAP_REG_TXMP, 0x0FFF, 0x0400 },
+	{ CPCAP_REG_RXOA, 0x01FF, 0x0000 },
+	{ CPCAP_REG_RXVC, 0xFF3C, 0x0000 },
+	{ CPCAP_REG_RXCOA, 0x07FF, 0x0000 },
+	{ CPCAP_REG_RXSDOA, 0x1FFF, 0x0000 },
+	{ CPCAP_REG_RXEPOA, 0x7FFF, 0x0000 },
+	{ CPCAP_REG_A2LA, BIT(CPCAP_BIT_A2_FREE_RUN),
+	  BIT(CPCAP_BIT_A2_FREE_RUN) },
+};
+
+enum cpcap_dai {
+	CPCAP_DAI_HIFI,
+	CPCAP_DAI_VOICE,
+};
+
+struct cpcap_audio {
+	struct snd_soc_component *component;
+	struct regmap *regmap;
+
+	u16 vendor;
+
+	int codec_clk_id;
+	int codec_freq;
+	int codec_format;
+};
+
+static int cpcap_st_workaround(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	int err = 0;
+
+	/* Only CPCAP from ST requires workaround */
+	if (cpcap->vendor != CPCAP_VENDOR_ST)
+		return 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		err = regmap_write(cpcap->regmap, CPCAP_REG_TEST,
+				   STM_STDAC_EN_TEST_PRE);
+		if (err)
+			return err;
+		err = regmap_write(cpcap->regmap, CPCAP_REG_ST_TEST1,
+				   STM_STDAC_EN_ST_TEST1_PRE);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		msleep(STM_STDAC_ACTIVATE_RAMP_TIME);
+
+		err = regmap_write(cpcap->regmap, CPCAP_REG_ST_TEST1,
+				   STM_STDAC_EN_ST_TEST1_POST);
+		if (err)
+			return err;
+		err = regmap_write(cpcap->regmap, CPCAP_REG_TEST,
+				   STM_STDAC_EN_TEST_POST);
+		break;
+	default:
+		break;
+	}
+
+	return err;
+}
+
+/* Capture Gain Control: 0dB to 31dB in 1dB steps */
+static const DECLARE_TLV_DB_SCALE(mic_gain_tlv, 0, 100, 0);
+
+/* Playback Gain Control: -33dB to 12dB in 3dB steps */
+static const DECLARE_TLV_DB_SCALE(vol_tlv, -3300, 300, 0);
+
+static const struct snd_kcontrol_new cpcap_snd_controls[] = {
+	/* Playback Gain */
+	SOC_SINGLE_TLV("HiFi Playback Volume",
+		CPCAP_REG_RXVC, CPCAP_BIT_VOL_DAC0, 0xF, 0, vol_tlv),
+	SOC_SINGLE_TLV("Voice Playback Volume",
+		CPCAP_REG_RXVC, CPCAP_BIT_VOL_CDC0, 0xF, 0, vol_tlv),
+	SOC_SINGLE_TLV("Ext Playback Volume",
+		CPCAP_REG_RXVC, CPCAP_BIT_VOL_EXT0, 0xF, 0, vol_tlv),
+
+	/* Capture Gain */
+	SOC_SINGLE_TLV("Mic1 Capture Volume",
+		CPCAP_REG_TXMP, CPCAP_BIT_MIC1_GAIN_0, 0x1F, 0, mic_gain_tlv),
+	SOC_SINGLE_TLV("Mic2 Capture Volume",
+		CPCAP_REG_TXMP, CPCAP_BIT_MIC2_GAIN_0, 0x1F, 0, mic_gain_tlv),
+
+	/* Phase Invert */
+	SOC_SINGLE("Hifi Left Phase Invert Switch",
+		CPCAP_REG_RXSDOA, CPCAP_BIT_MONO_DAC0, 1, 0),
+	SOC_SINGLE("Ext Left Phase Invert Switch",
+		CPCAP_REG_RXEPOA, CPCAP_BIT_MONO_EXT0, 1, 0),
+};
+
+static const char * const cpcap_out_mux_texts[] = {
+	"Off", "Voice", "HiFi", "Ext"
+};
+
+static const char * const cpcap_in_right_mux_texts[] = {
+	"Off", "Mic 1", "Headset Mic", "EMU Mic", "Ext Right"
+};
+
+static const char * const cpcap_in_left_mux_texts[] = {
+	"Off", "Mic 2", "Ext Left"
+};
+
+/*
+ * input muxes use unusual register layout, so that we need to use custom
+ * getter/setter methods
+ */
+static SOC_ENUM_SINGLE_EXT_DECL(cpcap_input_left_mux_enum,
+				cpcap_in_left_mux_texts);
+static SOC_ENUM_SINGLE_EXT_DECL(cpcap_input_right_mux_enum,
+				cpcap_in_right_mux_texts);
+
+/*
+ * mux uses same bit in CPCAP_REG_RXCOA, CPCAP_REG_RXSDOA & CPCAP_REG_RXEPOA;
+ * even though the register layout makes it look like a mixer, this is a mux.
+ * Enabling multiple inputs will result in no audio being forwarded.
+ */
+static SOC_ENUM_SINGLE_DECL(cpcap_earpiece_mux_enum, 0, 0, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_spkr_r_mux_enum, 0, 1, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_spkr_l_mux_enum, 0, 2, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_line_r_mux_enum, 0, 3, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_line_l_mux_enum, 0, 4, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_hs_r_mux_enum, 0, 5, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_hs_l_mux_enum, 0, 6, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_emu_l_mux_enum, 0, 7, cpcap_out_mux_texts);
+static SOC_ENUM_SINGLE_DECL(cpcap_emu_r_mux_enum, 0, 8, cpcap_out_mux_texts);
+
+static int cpcap_output_mux_get_enum(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int shift = e->shift_l;
+	int reg_voice, reg_hifi, reg_ext, status;
+	int err;
+
+	err = regmap_read(cpcap->regmap, CPCAP_REG_RXCOA, &reg_voice);
+	if (err)
+		return err;
+	err = regmap_read(cpcap->regmap, CPCAP_REG_RXSDOA, &reg_hifi);
+	if (err)
+		return err;
+	err = regmap_read(cpcap->regmap, CPCAP_REG_RXEPOA, &reg_ext);
+	if (err)
+		return err;
+
+	reg_voice = (reg_voice >> shift) & 1;
+	reg_hifi = (reg_hifi >> shift) & 1;
+	reg_ext = (reg_ext >> shift) & 1;
+	status = reg_ext << 2 | reg_hifi << 1 | reg_voice;
+
+	switch (status) {
+	case 0x04:
+		ucontrol->value.enumerated.item[0] = 3;
+		break;
+	case 0x02:
+		ucontrol->value.enumerated.item[0] = 2;
+		break;
+	case 0x01:
+		ucontrol->value.enumerated.item[0] = 1;
+		break;
+	default:
+		ucontrol->value.enumerated.item[0] = 0;
+		break;
+	}
+
+	return 0;
+}
+
+static int cpcap_output_mux_put_enum(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm =
+		snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int muxval = ucontrol->value.enumerated.item[0];
+	unsigned int mask = BIT(e->shift_l);
+	u16 reg_voice = 0x00, reg_hifi = 0x00, reg_ext = 0x00;
+	int err;
+
+	switch (muxval) {
+	case 1:
+		reg_voice = mask;
+		break;
+	case 2:
+		reg_hifi = mask;
+		break;
+	case 3:
+		reg_ext = mask;
+		break;
+	default:
+		break;
+	}
+
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA,
+				 mask, reg_voice);
+	if (err)
+		return err;
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXSDOA,
+				 mask, reg_hifi);
+	if (err)
+		return err;
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXEPOA,
+				 mask, reg_ext);
+	if (err)
+		return err;
+
+	snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL);
+
+	return 0;
+}
+
+static int cpcap_input_right_mux_get_enum(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	int regval, mask;
+	int err;
+
+	err = regmap_read(cpcap->regmap, CPCAP_REG_TXI, &regval);
+	if (err)
+		return err;
+
+	mask = 0;
+	mask |= BIT(CPCAP_BIT_MIC1_MUX);
+	mask |= BIT(CPCAP_BIT_HS_MIC_MUX);
+	mask |= BIT(CPCAP_BIT_EMU_MIC_MUX);
+	mask |= BIT(CPCAP_BIT_RX_R_ENCODE);
+
+	switch (regval & mask) {
+	case BIT(CPCAP_BIT_RX_R_ENCODE):
+		ucontrol->value.enumerated.item[0] = 4;
+		break;
+	case BIT(CPCAP_BIT_EMU_MIC_MUX):
+		ucontrol->value.enumerated.item[0] = 3;
+		break;
+	case BIT(CPCAP_BIT_HS_MIC_MUX):
+		ucontrol->value.enumerated.item[0] = 2;
+		break;
+	case BIT(CPCAP_BIT_MIC1_MUX):
+		ucontrol->value.enumerated.item[0] = 1;
+		break;
+	default:
+		ucontrol->value.enumerated.item[0] = 0;
+		break;
+	}
+
+	return 0;
+}
+
+static int cpcap_input_right_mux_put_enum(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm =
+		snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int muxval = ucontrol->value.enumerated.item[0];
+	int regval = 0, mask;
+	int err;
+
+	mask = 0;
+	mask |= BIT(CPCAP_BIT_MIC1_MUX);
+	mask |= BIT(CPCAP_BIT_HS_MIC_MUX);
+	mask |= BIT(CPCAP_BIT_EMU_MIC_MUX);
+	mask |= BIT(CPCAP_BIT_RX_R_ENCODE);
+
+	switch (muxval) {
+	case 1:
+		regval = BIT(CPCAP_BIT_MIC1_MUX);
+		break;
+	case 2:
+		regval = BIT(CPCAP_BIT_HS_MIC_MUX);
+		break;
+	case 3:
+		regval = BIT(CPCAP_BIT_EMU_MIC_MUX);
+		break;
+	case 4:
+		regval = BIT(CPCAP_BIT_RX_R_ENCODE);
+		break;
+	default:
+		break;
+	}
+
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
+				 mask, regval);
+	if (err)
+		return err;
+
+	snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL);
+
+	return 0;
+}
+
+static int cpcap_input_left_mux_get_enum(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	int regval, mask;
+	int err;
+
+	err = regmap_read(cpcap->regmap, CPCAP_REG_TXI, &regval);
+	if (err)
+		return err;
+
+	mask = 0;
+	mask |= BIT(CPCAP_BIT_MIC2_MUX);
+	mask |= BIT(CPCAP_BIT_RX_L_ENCODE);
+
+	switch (regval & mask) {
+	case BIT(CPCAP_BIT_RX_L_ENCODE):
+		ucontrol->value.enumerated.item[0] = 2;
+		break;
+	case BIT(CPCAP_BIT_MIC2_MUX):
+		ucontrol->value.enumerated.item[0] = 1;
+		break;
+	default:
+		ucontrol->value.enumerated.item[0] = 0;
+		break;
+	}
+
+	return 0;
+}
+
+static int cpcap_input_left_mux_put_enum(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm =
+		snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int muxval = ucontrol->value.enumerated.item[0];
+	int regval = 0, mask;
+	int err;
+
+	mask = 0;
+	mask |= BIT(CPCAP_BIT_MIC2_MUX);
+	mask |= BIT(CPCAP_BIT_RX_L_ENCODE);
+
+	switch (muxval) {
+	case 1:
+		regval = BIT(CPCAP_BIT_MIC2_MUX);
+		break;
+	case 2:
+		regval = BIT(CPCAP_BIT_RX_L_ENCODE);
+		break;
+	default:
+		break;
+	}
+
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
+				 mask, regval);
+	if (err)
+		return err;
+
+	snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new cpcap_input_left_mux =
+	SOC_DAPM_ENUM_EXT("Input Left", cpcap_input_left_mux_enum,
+			  cpcap_input_left_mux_get_enum,
+			  cpcap_input_left_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_input_right_mux =
+	SOC_DAPM_ENUM_EXT("Input Right", cpcap_input_right_mux_enum,
+			  cpcap_input_right_mux_get_enum,
+			  cpcap_input_right_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_emu_left_mux =
+	SOC_DAPM_ENUM_EXT("EMU Left", cpcap_emu_l_mux_enum,
+			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_emu_right_mux =
+	SOC_DAPM_ENUM_EXT("EMU Right", cpcap_emu_r_mux_enum,
+			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_hs_left_mux =
+	SOC_DAPM_ENUM_EXT("Headset Left", cpcap_hs_l_mux_enum,
+			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_hs_right_mux =
+	SOC_DAPM_ENUM_EXT("Headset Right", cpcap_hs_r_mux_enum,
+			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_line_left_mux =
+	SOC_DAPM_ENUM_EXT("Line Left", cpcap_line_l_mux_enum,
+			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_line_right_mux =
+	SOC_DAPM_ENUM_EXT("Line Right", cpcap_line_r_mux_enum,
+			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_speaker_left_mux =
+	SOC_DAPM_ENUM_EXT("Speaker Left", cpcap_spkr_l_mux_enum,
+			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_speaker_right_mux =
+	SOC_DAPM_ENUM_EXT("Speaker Right", cpcap_spkr_r_mux_enum,
+			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+static const struct snd_kcontrol_new cpcap_earpiece_mux =
+	SOC_DAPM_ENUM_EXT("Earpiece", cpcap_earpiece_mux_enum,
+			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
+
+static const struct snd_kcontrol_new cpcap_hifi_mono_mixer_controls[] = {
+	SOC_DAPM_SINGLE("HiFi Mono Playback Switch",
+		CPCAP_REG_RXSDOA, CPCAP_BIT_MONO_DAC1, 1, 0),
+};
+static const struct snd_kcontrol_new cpcap_ext_mono_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Ext Mono Playback Switch",
+		CPCAP_REG_RXEPOA, CPCAP_BIT_MONO_EXT0, 1, 0),
+};
+
+static const struct snd_kcontrol_new cpcap_extr_mute_control =
+	SOC_DAPM_SINGLE("Switch",
+		CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_IN_R_SW, 1, 0);
+static const struct snd_kcontrol_new cpcap_extl_mute_control =
+	SOC_DAPM_SINGLE("Switch",
+		CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_IN_L_SW, 1, 0);
+
+static const struct snd_kcontrol_new cpcap_voice_loopback =
+	SOC_DAPM_SINGLE("Switch",
+		CPCAP_REG_TXI, CPCAP_BIT_DLM, 1, 0);
+
+static const struct snd_soc_dapm_widget cpcap_dapm_widgets[] = {
+	/* DAIs */
+	SND_SOC_DAPM_AIF_IN("HiFi RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("Voice RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("Voice TX", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+	/* Power Supply */
+	SND_SOC_DAPM_REGULATOR_SUPPLY("VAUDIO", SLEEP_ACTIVATE_POWER, 0),
+
+	/* Highpass Filters */
+	SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Highpass Filter RX",
+		CPCAP_REG_CC, CPCAP_BIT_AUDIHPF_0, 0x3, 0x3, 0x0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Highpass Filter TX",
+		CPCAP_REG_CC, CPCAP_BIT_AUDOHPF_0, 0x3, 0x3, 0x0),
+
+	/* Clocks */
+	SND_SOC_DAPM_SUPPLY("HiFi DAI Clock",
+		CPCAP_REG_SDACDI, CPCAP_BIT_ST_CLK_EN, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Voice DAI Clock",
+		CPCAP_REG_CDI, CPCAP_BIT_CDC_CLK_EN, 0, NULL, 0),
+
+	/* Microphone Bias */
+	SND_SOC_DAPM_SUPPLY("MIC1R Bias",
+		CPCAP_REG_TXI, CPCAP_BIT_MB_ON1R, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MIC1L Bias",
+		CPCAP_REG_TXI, CPCAP_BIT_MB_ON1L, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MIC2 Bias",
+		CPCAP_REG_TXI, CPCAP_BIT_MB_ON2, 0, NULL, 0),
+
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("MICR"),
+	SND_SOC_DAPM_INPUT("HSMIC"),
+	SND_SOC_DAPM_INPUT("EMUMIC"),
+	SND_SOC_DAPM_INPUT("MICL"),
+	SND_SOC_DAPM_INPUT("EXTR"),
+	SND_SOC_DAPM_INPUT("EXTL"),
+
+	/* Capture Route */
+	SND_SOC_DAPM_MUX("Right Capture Route",
+		SND_SOC_NOPM, 0, 0, &cpcap_input_right_mux),
+	SND_SOC_DAPM_MUX("Left Capture Route",
+		SND_SOC_NOPM, 0, 0, &cpcap_input_left_mux),
+
+	/* Capture PGAs */
+	SND_SOC_DAPM_PGA("Microphone 1 PGA",
+		CPCAP_REG_TXI, CPCAP_BIT_MIC1_PGA_EN, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Microphone 2 PGA",
+		CPCAP_REG_TXI, CPCAP_BIT_MIC2_PGA_EN, 0, NULL, 0),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC("ADC Right", NULL,
+		CPCAP_REG_CC, CPCAP_BIT_MIC1_CDC_EN, 0),
+	SND_SOC_DAPM_ADC("ADC Left", NULL,
+		CPCAP_REG_CC, CPCAP_BIT_MIC2_CDC_EN, 0),
+
+	/* DAC */
+	SND_SOC_DAPM_DAC_E("DAC HiFi", NULL,
+		CPCAP_REG_SDAC, CPCAP_BIT_ST_DAC_EN, 0,
+		cpcap_st_workaround,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_DAC_E("DAC Voice", NULL,
+		CPCAP_REG_CC, CPCAP_BIT_CDC_EN_RX, 0,
+		cpcap_st_workaround,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+	/* Playback PGA */
+	SND_SOC_DAPM_PGA("HiFi PGA",
+		CPCAP_REG_RXSDOA, CPCAP_BIT_PGA_DAC_EN, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Voice PGA",
+		CPCAP_REG_RXCOA, CPCAP_BIT_PGA_CDC_EN, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_E("Ext Right PGA",
+		CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_EXT_R_EN, 0,
+		NULL, 0,
+		cpcap_st_workaround,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_E("Ext Left PGA",
+		CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_EXT_L_EN, 0,
+		NULL, 0,
+		cpcap_st_workaround,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+	/* Playback Switch */
+	SND_SOC_DAPM_SWITCH("Ext Right Enable", SND_SOC_NOPM, 0, 0,
+		&cpcap_extr_mute_control),
+	SND_SOC_DAPM_SWITCH("Ext Left Enable", SND_SOC_NOPM, 0, 0,
+		&cpcap_extl_mute_control),
+
+	/* Loopback Switch */
+	SND_SOC_DAPM_SWITCH("Voice Loopback", SND_SOC_NOPM, 0, 0,
+		&cpcap_voice_loopback),
+
+	/* Mono Mixer */
+	SOC_MIXER_ARRAY("HiFi Mono Left Mixer", SND_SOC_NOPM, 0, 0,
+		cpcap_hifi_mono_mixer_controls),
+	SOC_MIXER_ARRAY("HiFi Mono Right Mixer", SND_SOC_NOPM, 0, 0,
+		cpcap_hifi_mono_mixer_controls),
+	SOC_MIXER_ARRAY("Ext Mono Left Mixer", SND_SOC_NOPM, 0, 0,
+		cpcap_ext_mono_mixer_controls),
+	SOC_MIXER_ARRAY("Ext Mono Right Mixer", SND_SOC_NOPM, 0, 0,
+		cpcap_ext_mono_mixer_controls),
+
+	/* Output Routes */
+	SND_SOC_DAPM_MUX("Earpiece Playback Route", SND_SOC_NOPM, 0, 0,
+		&cpcap_earpiece_mux),
+	SND_SOC_DAPM_MUX("Speaker Right Playback Route", SND_SOC_NOPM, 0, 0,
+		&cpcap_speaker_right_mux),
+	SND_SOC_DAPM_MUX("Speaker Left Playback Route", SND_SOC_NOPM, 0, 0,
+		&cpcap_speaker_left_mux),
+	SND_SOC_DAPM_MUX("Lineout Right Playback Route", SND_SOC_NOPM, 0, 0,
+		&cpcap_line_right_mux),
+	SND_SOC_DAPM_MUX("Lineout Left Playback Route", SND_SOC_NOPM, 0, 0,
+		&cpcap_line_left_mux),
+	SND_SOC_DAPM_MUX("Headset Right Playback Route", SND_SOC_NOPM, 0, 0,
+		&cpcap_hs_right_mux),
+	SND_SOC_DAPM_MUX("Headset Left Playback Route", SND_SOC_NOPM, 0, 0,
+		&cpcap_hs_left_mux),
+	SND_SOC_DAPM_MUX("EMU Right Playback Route", SND_SOC_NOPM, 0, 0,
+		&cpcap_emu_right_mux),
+	SND_SOC_DAPM_MUX("EMU Left Playback Route", SND_SOC_NOPM, 0, 0,
+		&cpcap_emu_left_mux),
+
+	/* Output Amplifier */
+	SND_SOC_DAPM_PGA("Earpiece PGA",
+		CPCAP_REG_RXOA, CPCAP_BIT_A1_EAR_EN, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Speaker Right PGA",
+		CPCAP_REG_RXOA, CPCAP_BIT_A2_LDSP_R_EN, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Speaker Left PGA",
+		CPCAP_REG_RXOA, CPCAP_BIT_A2_LDSP_L_EN, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Lineout Right PGA",
+		CPCAP_REG_RXOA, CPCAP_BIT_A4_LINEOUT_R_EN, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Lineout Left PGA",
+		CPCAP_REG_RXOA, CPCAP_BIT_A4_LINEOUT_L_EN, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Headset Right PGA",
+		CPCAP_REG_RXOA, CPCAP_BIT_HS_R_EN, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Headset Left PGA",
+		CPCAP_REG_RXOA, CPCAP_BIT_HS_L_EN, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("EMU Right PGA",
+		CPCAP_REG_RXOA, CPCAP_BIT_EMU_SPKR_R_EN, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("EMU Left PGA",
+		CPCAP_REG_RXOA, CPCAP_BIT_EMU_SPKR_L_EN, 0, NULL, 0),
+
+	/* Headet Charge Pump */
+	SND_SOC_DAPM_SUPPLY("Headset Charge Pump",
+		CPCAP_REG_RXOA, CPCAP_BIT_ST_HS_CP_EN, 0, NULL, 0),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("EP"),
+	SND_SOC_DAPM_OUTPUT("SPKR"),
+	SND_SOC_DAPM_OUTPUT("SPKL"),
+	SND_SOC_DAPM_OUTPUT("LINER"),
+	SND_SOC_DAPM_OUTPUT("LINEL"),
+	SND_SOC_DAPM_OUTPUT("HSR"),
+	SND_SOC_DAPM_OUTPUT("HSL"),
+	SND_SOC_DAPM_OUTPUT("EMUR"),
+	SND_SOC_DAPM_OUTPUT("EMUL"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	/* Power Supply */
+	{"HiFi PGA", NULL, "VAUDIO"},
+	{"Voice PGA", NULL, "VAUDIO"},
+	{"Ext Right PGA", NULL, "VAUDIO"},
+	{"Ext Left PGA", NULL, "VAUDIO"},
+	{"Microphone 1 PGA", NULL, "VAUDIO"},
+	{"Microphone 2 PGA", NULL, "VAUDIO"},
+
+	/* Stream -> AIF */
+	{"HiFi RX", NULL, "HiFi Playback"},
+	{"Voice RX", NULL, "Voice Playback"},
+	{"Voice Capture", NULL, "Voice TX"},
+
+	/* AIF clocks */
+	{"HiFi RX", NULL, "HiFi DAI Clock"},
+	{"Voice RX", NULL, "Voice DAI Clock"},
+	{"Voice TX", NULL, "Voice DAI Clock"},
+
+	/* Digital Loopback */
+	{"Voice Loopback", "Switch", "Voice TX"},
+	{"Voice RX", NULL, "Voice Loopback"},
+
+	/* Highpass Filters */
+	{"Highpass Filter RX", NULL, "Voice RX"},
+	{"Voice TX", NULL, "Highpass Filter TX"},
+
+	/* AIF -> DAC mapping */
+	{"DAC HiFi", NULL, "HiFi RX"},
+	{"DAC Voice", NULL, "Highpass Filter RX"},
+
+	/* DAC -> PGA */
+	{"HiFi PGA", NULL, "DAC HiFi"},
+	{"Voice PGA", NULL, "DAC Voice"},
+
+	/* Ext Input -> PGA */
+	{"Ext Right PGA", NULL, "EXTR"},
+	{"Ext Left PGA", NULL, "EXTL"},
+
+	/* Ext PGA -> Ext Playback Switch */
+	{"Ext Right Enable", "Switch", "Ext Right PGA"},
+	{"Ext Left Enable", "Switch", "Ext Left PGA"},
+
+	/* HiFi PGA -> Mono Mixer */
+	{"HiFi Mono Left Mixer", NULL, "HiFi PGA"},
+	{"HiFi Mono Left Mixer", "HiFi Mono Playback Switch", "HiFi PGA"},
+	{"HiFi Mono Right Mixer", NULL, "HiFi PGA"},
+	{"HiFi Mono Right Mixer", "HiFi Mono Playback Switch", "HiFi PGA"},
+
+	/* Ext Playback Switch -> Ext Mono Mixer */
+	{"Ext Mono Right Mixer", NULL, "Ext Right Enable"},
+	{"Ext Mono Right Mixer", "Ext Mono Playback Switch", "Ext Left Enable"},
+	{"Ext Mono Left Mixer", NULL, "Ext Left Enable"},
+	{"Ext Mono Left Mixer", "Ext Mono Playback Switch", "Ext Right Enable"},
+
+	/* HiFi Mono Mixer -> Output Route */
+	{"Earpiece Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+	{"Speaker Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+	{"Speaker Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
+	{"Lineout Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+	{"Lineout Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
+	{"Headset Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+	{"Headset Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
+	{"EMU Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
+	{"EMU Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
+
+	/* Voice PGA -> Output Route */
+	{"Earpiece Playback Route", "Voice", "Voice PGA"},
+	{"Speaker Right Playback Route", "Voice", "Voice PGA"},
+	{"Speaker Left Playback Route", "Voice", "Voice PGA"},
+	{"Lineout Right Playback Route", "Voice", "Voice PGA"},
+	{"Lineout Left Playback Route", "Voice", "Voice PGA"},
+	{"Headset Right Playback Route", "Voice", "Voice PGA"},
+	{"Headset Left Playback Route", "Voice", "Voice PGA"},
+	{"EMU Right Playback Route", "Voice", "Voice PGA"},
+	{"EMU Left Playback Route", "Voice", "Voice PGA"},
+
+	/* Ext Mono Mixer -> Output Route */
+	{"Earpiece Playback Route", "Ext", "Ext Mono Right Mixer"},
+	{"Speaker Right Playback Route", "Ext", "Ext Mono Right Mixer"},
+	{"Speaker Left Playback Route", "Ext", "Ext Mono Left Mixer"},
+	{"Lineout Right Playback Route", "Ext", "Ext Mono Right Mixer"},
+	{"Lineout Left Playback Route", "Ext", "Ext Mono Left Mixer"},
+	{"Headset Right Playback Route", "Ext", "Ext Mono Right Mixer"},
+	{"Headset Left Playback Route", "Ext", "Ext Mono Left Mixer"},
+	{"EMU Right Playback Route", "Ext", "Ext Mono Right Mixer"},
+	{"EMU Left Playback Route", "Ext", "Ext Mono Left Mixer"},
+
+	/* Output Route -> Output Amplifier */
+	{"Earpiece PGA", NULL, "Earpiece Playback Route"},
+	{"Speaker Right PGA", NULL, "Speaker Right Playback Route"},
+	{"Speaker Left PGA", NULL, "Speaker Left Playback Route"},
+	{"Lineout Right PGA", NULL, "Lineout Right Playback Route"},
+	{"Lineout Left PGA", NULL, "Lineout Left Playback Route"},
+	{"Headset Right PGA", NULL, "Headset Right Playback Route"},
+	{"Headset Left PGA", NULL, "Headset Left Playback Route"},
+	{"EMU Right PGA", NULL, "EMU Right Playback Route"},
+	{"EMU Left PGA", NULL, "EMU Left Playback Route"},
+
+	/* Output Amplifier -> Output */
+	{"EP", NULL, "Earpiece PGA"},
+	{"SPKR", NULL, "Speaker Right PGA"},
+	{"SPKL", NULL, "Speaker Left PGA"},
+	{"LINER", NULL, "Lineout Right PGA"},
+	{"LINEL", NULL, "Lineout Left PGA"},
+	{"HSR", NULL, "Headset Right PGA"},
+	{"HSL", NULL, "Headset Left PGA"},
+	{"EMUR", NULL, "EMU Right PGA"},
+	{"EMUL", NULL, "EMU Left PGA"},
+
+	/* Headset Charge Pump -> Headset */
+	{"HSR", NULL, "Headset Charge Pump"},
+	{"HSL", NULL, "Headset Charge Pump"},
+
+	/* Mic -> Mic Route */
+	{"Right Capture Route", "Mic 1", "MICR"},
+	{"Right Capture Route", "Headset Mic", "HSMIC"},
+	{"Right Capture Route", "EMU Mic", "EMUMIC"},
+	{"Right Capture Route", "Ext Right", "EXTR"},
+	{"Left Capture Route", "Mic 2", "MICL"},
+	{"Left Capture Route", "Ext Left", "EXTL"},
+
+	/* Input Route -> Microphone PGA */
+	{"Microphone 1 PGA", NULL, "Right Capture Route"},
+	{"Microphone 2 PGA", NULL, "Left Capture Route"},
+
+	/* Microphone PGA -> ADC */
+	{"ADC Right", NULL, "Microphone 1 PGA"},
+	{"ADC Left", NULL, "Microphone 2 PGA"},
+
+	/* ADC -> Stream */
+	{"Highpass Filter TX", NULL, "ADC Right"},
+	{"Highpass Filter TX", NULL, "ADC Left"},
+
+	/* Mic Bias */
+	{"MICL", NULL, "MIC1L Bias"},
+	{"MICR", NULL, "MIC1R Bias"},
+};
+
+static int cpcap_set_sysclk(struct cpcap_audio *cpcap, enum cpcap_dai dai,
+			    int clk_id, int freq)
+{
+	u16 clkfreqreg, clkfreqshift;
+	u16 clkfreqmask, clkfreqval;
+	u16 clkidreg, clkidshift;
+	u16 mask, val;
+	int err;
+
+	switch (dai) {
+	case CPCAP_DAI_HIFI:
+		clkfreqreg = CPCAP_REG_SDAC;
+		clkfreqshift = CPCAP_BIT_ST_DAC_CLK0;
+		clkidreg = CPCAP_REG_SDACDI;
+		clkidshift = CPCAP_BIT_ST_DAC_CLK_IN_SEL;
+		break;
+	case CPCAP_DAI_VOICE:
+		clkfreqreg = CPCAP_REG_CC;
+		clkfreqshift = CPCAP_BIT_CDC_CLK0;
+		clkidreg = CPCAP_REG_CDI;
+		clkidshift = CPCAP_BIT_CLK_IN_SEL;
+		break;
+	default:
+		dev_err(cpcap->component->dev, "invalid DAI: %d", dai);
+		return -EINVAL;
+	}
+
+	/* setup clk id */
+	if (clk_id < 0 || clk_id > 1) {
+		dev_err(cpcap->component->dev, "invalid clk id %d", clk_id);
+		return -EINVAL;
+	}
+	err = regmap_update_bits(cpcap->regmap, clkidreg, BIT(clkidshift),
+				 clk_id ? BIT(clkidshift) : 0);
+	if (err)
+		return err;
+
+	/* enable PLL for Voice DAI */
+	if (dai == CPCAP_DAI_VOICE) {
+		mask = BIT(CPCAP_BIT_CDC_PLL_SEL);
+		val = BIT(CPCAP_BIT_CDC_PLL_SEL);
+		err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
+					 mask, val);
+		if (err)
+			return err;
+	}
+
+	/* setup frequency */
+	clkfreqmask = 0x7 << clkfreqshift;
+	switch (freq) {
+	case 15360000:
+		clkfreqval = 0x01 << clkfreqshift;
+		break;
+	case 16800000:
+		clkfreqval = 0x02 << clkfreqshift;
+		break;
+	case 19200000:
+		clkfreqval = 0x03 << clkfreqshift;
+		break;
+	case 26000000:
+		clkfreqval = 0x04 << clkfreqshift;
+		break;
+	case 33600000:
+		clkfreqval = 0x05 << clkfreqshift;
+		break;
+	case 38400000:
+		clkfreqval = 0x06 << clkfreqshift;
+		break;
+	default:
+		dev_err(cpcap->component->dev, "unsupported freq %u", freq);
+		return -EINVAL;
+	}
+
+	err = regmap_update_bits(cpcap->regmap, clkfreqreg,
+				 clkfreqmask, clkfreqval);
+	if (err)
+		return err;
+
+	if (dai == CPCAP_DAI_VOICE) {
+		cpcap->codec_clk_id = clk_id;
+		cpcap->codec_freq = freq;
+	}
+
+	return 0;
+}
+
+static int cpcap_set_samprate(struct cpcap_audio *cpcap, enum cpcap_dai dai,
+			      int samplerate)
+{
+	struct snd_soc_component *component = cpcap->component;
+	u16 sampreg, sampmask, sampshift, sampval, sampreset;
+	int err, sampreadval;
+
+	switch (dai) {
+	case CPCAP_DAI_HIFI:
+		sampreg = CPCAP_REG_SDAC;
+		sampshift = CPCAP_BIT_ST_SR0;
+		sampreset = BIT(CPCAP_BIT_DF_RESET_ST_DAC) |
+			    BIT(CPCAP_BIT_ST_CLOCK_TREE_RESET);
+		break;
+	case CPCAP_DAI_VOICE:
+		sampreg = CPCAP_REG_CC;
+		sampshift = CPCAP_BIT_CDC_SR0;
+		sampreset = BIT(CPCAP_BIT_DF_RESET) |
+			    BIT(CPCAP_BIT_CDC_CLOCK_TREE_RESET);
+		break;
+	default:
+		dev_err(component->dev, "invalid DAI: %d", dai);
+		return -EINVAL;
+	}
+
+	sampmask = 0xF << sampshift | sampreset;
+	switch (samplerate) {
+	case 48000:
+		sampval = 0x8 << sampshift;
+		break;
+	case 44100:
+		sampval = 0x7 << sampshift;
+		break;
+	case 32000:
+		sampval = 0x6 << sampshift;
+		break;
+	case 24000:
+		sampval = 0x5 << sampshift;
+		break;
+	case 22050:
+		sampval = 0x4 << sampshift;
+		break;
+	case 16000:
+		sampval = 0x3 << sampshift;
+		break;
+	case 12000:
+		sampval = 0x2 << sampshift;
+		break;
+	case 11025:
+		sampval = 0x1 << sampshift;
+		break;
+	case 8000:
+		sampval = 0x0 << sampshift;
+		break;
+	default:
+		dev_err(component->dev, "unsupported samplerate %d", samplerate);
+		return -EINVAL;
+	}
+	err = regmap_update_bits(cpcap->regmap, sampreg,
+				 sampmask, sampval | sampreset);
+	if (err)
+		return err;
+
+	/* Wait for clock tree reset to complete */
+	mdelay(CLOCK_TREE_RESET_TIME);
+
+	err = regmap_read(cpcap->regmap, sampreg, &sampreadval);
+	if (err)
+		return err;
+
+	if (sampreadval & sampreset) {
+		dev_err(component->dev, "reset self-clear failed: %04x",
+			sampreadval);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int cpcap_hifi_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	int rate = params_rate(params);
+
+	dev_dbg(component->dev, "HiFi setup HW params: rate=%d", rate);
+	return cpcap_set_samprate(cpcap, CPCAP_DAI_HIFI, rate);
+}
+
+static int cpcap_hifi_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
+				     unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	struct device *dev = component->dev;
+
+	dev_dbg(dev, "HiFi setup sysclk: clk_id=%u, freq=%u", clk_id, freq);
+	return cpcap_set_sysclk(cpcap, CPCAP_DAI_HIFI, clk_id, freq);
+}
+
+static int cpcap_hifi_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				  unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	struct device *dev = component->dev;
+	static const u16 reg = CPCAP_REG_SDACDI;
+	static const u16 mask =
+		BIT(CPCAP_BIT_SMB_ST_DAC) |
+		BIT(CPCAP_BIT_ST_CLK_INV) |
+		BIT(CPCAP_BIT_ST_FS_INV) |
+		BIT(CPCAP_BIT_ST_DIG_AUD_FS0) |
+		BIT(CPCAP_BIT_ST_DIG_AUD_FS1) |
+		BIT(CPCAP_BIT_ST_L_TIMESLOT0) |
+		BIT(CPCAP_BIT_ST_L_TIMESLOT1) |
+		BIT(CPCAP_BIT_ST_L_TIMESLOT2) |
+		BIT(CPCAP_BIT_ST_R_TIMESLOT0) |
+		BIT(CPCAP_BIT_ST_R_TIMESLOT1) |
+		BIT(CPCAP_BIT_ST_R_TIMESLOT2);
+	u16 val = 0x0000;
+
+	dev_dbg(dev, "HiFi setup dai format (%08x)", fmt);
+
+	/*
+	 * "HiFi Playback" should always be configured as
+	 * SND_SOC_DAIFMT_CBM_CFM - codec clk & frm master
+	 * SND_SOC_DAIFMT_I2S - I2S mode
+	 */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		val &= ~BIT(CPCAP_BIT_SMB_ST_DAC);
+		break;
+	default:
+		dev_err(dev, "HiFi dai fmt failed: CPCAP should be master");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_IF:
+		val |= BIT(CPCAP_BIT_ST_FS_INV);
+		val |= BIT(CPCAP_BIT_ST_CLK_INV);
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		val &= ~BIT(CPCAP_BIT_ST_FS_INV);
+		val |= BIT(CPCAP_BIT_ST_CLK_INV);
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		val |= BIT(CPCAP_BIT_ST_FS_INV);
+		val &= ~BIT(CPCAP_BIT_ST_CLK_INV);
+		break;
+	case SND_SOC_DAIFMT_NB_NF:
+		val &= ~BIT(CPCAP_BIT_ST_FS_INV);
+		val &= ~BIT(CPCAP_BIT_ST_CLK_INV);
+		break;
+	default:
+		dev_err(dev, "HiFi dai fmt failed: unsupported clock invert mode");
+		return -EINVAL;
+	}
+
+	if (val & BIT(CPCAP_BIT_ST_CLK_INV))
+		val &= ~BIT(CPCAP_BIT_ST_CLK_INV);
+	else
+		val |= BIT(CPCAP_BIT_ST_CLK_INV);
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS0);
+		val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS1);
+		break;
+	default:
+		/* 01 - 4 slots network mode */
+		val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS0);
+		val &= ~BIT(CPCAP_BIT_ST_DIG_AUD_FS1);
+		/* L on slot 1 */
+		val |= BIT(CPCAP_BIT_ST_L_TIMESLOT0);
+		break;
+	}
+
+	dev_dbg(dev, "HiFi dai format: val=%04x", val);
+	return regmap_update_bits(cpcap->regmap, reg, mask, val);
+}
+
+static int cpcap_hifi_set_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	static const u16 reg = CPCAP_REG_RXSDOA;
+	static const u16 mask = BIT(CPCAP_BIT_ST_DAC_SW);
+	u16 val;
+
+	if (mute)
+		val = 0;
+	else
+		val = BIT(CPCAP_BIT_ST_DAC_SW);
+
+	dev_dbg(component->dev, "HiFi mute: %d", mute);
+	return regmap_update_bits(cpcap->regmap, reg, mask, val);
+}
+
+static const struct snd_soc_dai_ops cpcap_dai_hifi_ops = {
+	.hw_params	= cpcap_hifi_hw_params,
+	.set_sysclk	= cpcap_hifi_set_dai_sysclk,
+	.set_fmt	= cpcap_hifi_set_dai_fmt,
+	.digital_mute	= cpcap_hifi_set_mute,
+};
+
+static int cpcap_voice_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct device *dev = component->dev;
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	static const u16 reg_cdi = CPCAP_REG_CDI;
+	int rate = params_rate(params);
+	int channels = params_channels(params);
+	int direction = substream->stream;
+	u16 val, mask;
+	int err;
+
+	dev_dbg(dev, "Voice setup HW params: rate=%d, direction=%d, chan=%d",
+		rate, direction, channels);
+
+	err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, rate);
+	if (err)
+		return err;
+
+	if (direction == SNDRV_PCM_STREAM_CAPTURE) {
+		mask = 0x0000;
+		mask |= CPCAP_BIT_MIC1_RX_TIMESLOT0;
+		mask |= CPCAP_BIT_MIC1_RX_TIMESLOT1;
+		mask |= CPCAP_BIT_MIC1_RX_TIMESLOT2;
+		mask |= CPCAP_BIT_MIC2_TIMESLOT0;
+		mask |= CPCAP_BIT_MIC2_TIMESLOT1;
+		mask |= CPCAP_BIT_MIC2_TIMESLOT2;
+		val = 0x0000;
+		if (channels >= 2)
+			val = BIT(CPCAP_BIT_MIC1_RX_TIMESLOT0);
+		err = regmap_update_bits(cpcap->regmap, reg_cdi, mask, val);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int cpcap_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
+				      unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "Voice setup sysclk: clk_id=%u, freq=%u",
+		clk_id, freq);
+	return cpcap_set_sysclk(cpcap, CPCAP_DAI_VOICE, clk_id, freq);
+}
+
+static int cpcap_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				   unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	static const u16 mask = BIT(CPCAP_BIT_SMB_CDC) |
+				BIT(CPCAP_BIT_CLK_INV) |
+				BIT(CPCAP_BIT_FS_INV) |
+				BIT(CPCAP_BIT_CDC_DIG_AUD_FS0) |
+				BIT(CPCAP_BIT_CDC_DIG_AUD_FS1);
+	u16 val = 0x0000;
+	int err;
+
+	dev_dbg(component->dev, "Voice setup dai format (%08x)", fmt);
+
+	/*
+	 * "Voice Playback" and "Voice Capture" should always be
+	 * configured as SND_SOC_DAIFMT_CBM_CFM - codec clk & frm
+	 * master
+	 */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		val &= ~BIT(CPCAP_BIT_SMB_CDC);
+		break;
+	default:
+		dev_err(component->dev, "Voice dai fmt failed: CPCAP should be the master");
+		val &= ~BIT(CPCAP_BIT_SMB_CDC);
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_IF:
+		val |= BIT(CPCAP_BIT_CLK_INV);
+		val |= BIT(CPCAP_BIT_FS_INV);
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		val |= BIT(CPCAP_BIT_CLK_INV);
+		val &= ~BIT(CPCAP_BIT_FS_INV);
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		val &= ~BIT(CPCAP_BIT_CLK_INV);
+		val |= BIT(CPCAP_BIT_FS_INV);
+		break;
+	case SND_SOC_DAIFMT_NB_NF:
+		val &= ~BIT(CPCAP_BIT_CLK_INV);
+		val &= ~BIT(CPCAP_BIT_FS_INV);
+		break;
+	default:
+		dev_err(component->dev, "Voice dai fmt failed: unsupported clock invert mode");
+		break;
+	}
+
+	if (val & BIT(CPCAP_BIT_CLK_INV))
+		val &= ~BIT(CPCAP_BIT_CLK_INV);
+	else
+		val |= BIT(CPCAP_BIT_CLK_INV);
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		/* 11 - true I2S mode */
+		val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS0);
+		val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS1);
+		break;
+	default:
+		/* 4 timeslots network mode */
+		val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS0);
+		val &= ~BIT(CPCAP_BIT_CDC_DIG_AUD_FS1);
+		break;
+	}
+
+	dev_dbg(component->dev, "Voice dai format: val=%04x", val);
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, mask, val);
+	if (err)
+		return err;
+
+	cpcap->codec_format = val;
+	return 0;
+}
+
+static int cpcap_voice_set_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	static const u16 reg = CPCAP_REG_RXCOA;
+	static const u16 mask = BIT(CPCAP_BIT_CDC_SW);
+	u16 val;
+
+	if (mute)
+		val = 0;
+	else
+		val = BIT(CPCAP_BIT_CDC_SW);
+
+	dev_dbg(component->dev, "Voice mute: %d", mute);
+	return regmap_update_bits(cpcap->regmap, reg, mask, val);
+};
+
+static const struct snd_soc_dai_ops cpcap_dai_voice_ops = {
+	.hw_params	= cpcap_voice_hw_params,
+	.set_sysclk	= cpcap_voice_set_dai_sysclk,
+	.set_fmt	= cpcap_voice_set_dai_fmt,
+	.digital_mute	= cpcap_voice_set_mute,
+};
+
+static struct snd_soc_dai_driver cpcap_dai[] = {
+{
+	.id = 0,
+	.name = "cpcap-hifi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE,
+	},
+	.ops = &cpcap_dai_hifi_ops,
+},
+{
+	.id = 1,
+	.name = "cpcap-voice",
+	.playback = {
+		.stream_name = "Voice Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "Voice Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &cpcap_dai_voice_ops,
+},
+};
+
+static int cpcap_dai_mux(struct cpcap_audio *cpcap, bool swap_dai_configuration)
+{
+	u16 hifi_val, voice_val;
+	u16 hifi_mask = BIT(CPCAP_BIT_DIG_AUD_IN_ST_DAC);
+	u16 voice_mask = BIT(CPCAP_BIT_DIG_AUD_IN);
+	int err;
+
+
+
+	if (!swap_dai_configuration) {
+		/* Codec on DAI0, HiFi on DAI1 */
+		voice_val = 0;
+		hifi_val = hifi_mask;
+	} else {
+		/* Codec on DAI1, HiFi on DAI0 */
+		voice_val = voice_mask;
+		hifi_val = 0;
+	}
+
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
+				 voice_mask, voice_val);
+	if (err)
+		return err;
+
+	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_SDACDI,
+				 hifi_mask, hifi_val);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int cpcap_audio_reset(struct snd_soc_component *component,
+			     bool swap_dai_configuration)
+{
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+	int i, err = 0;
+
+	dev_dbg(component->dev, "init audio codec");
+
+	for (i = 0; i < ARRAY_SIZE(cpcap_default_regs); i++) {
+		err = regmap_update_bits(cpcap->regmap,
+					 cpcap_default_regs[i].reg,
+					 cpcap_default_regs[i].mask,
+					 cpcap_default_regs[i].val);
+		if (err)
+			return err;
+	}
+
+	/* setup default settings */
+	err = cpcap_dai_mux(cpcap, swap_dai_configuration);
+	if (err)
+		return err;
+
+	err = cpcap_set_sysclk(cpcap, CPCAP_DAI_HIFI, 0, 26000000);
+	if (err)
+		return err;
+	err = cpcap_set_sysclk(cpcap, CPCAP_DAI_VOICE, 0, 26000000);
+	if (err)
+		return err;
+
+	err = cpcap_set_samprate(cpcap, CPCAP_DAI_HIFI, 48000);
+	if (err)
+		return err;
+
+	err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, 48000);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int cpcap_soc_probe(struct snd_soc_component *component)
+{
+	struct cpcap_audio *cpcap;
+	int err;
+
+	cpcap = devm_kzalloc(component->dev, sizeof(*cpcap), GFP_KERNEL);
+	if (!cpcap)
+		return -ENOMEM;
+	snd_soc_component_set_drvdata(component, cpcap);
+	cpcap->component = component;
+
+	cpcap->regmap = dev_get_regmap(component->dev->parent, NULL);
+	if (!cpcap->regmap)
+		return -ENODEV;
+	snd_soc_component_init_regmap(component, cpcap->regmap);
+
+	err = cpcap_get_vendor(component->dev, cpcap->regmap, &cpcap->vendor);
+	if (err)
+		return err;
+
+	return cpcap_audio_reset(component, false);
+}
+
+static struct snd_soc_component_driver soc_codec_dev_cpcap = {
+	.probe			= cpcap_soc_probe,
+	.controls		= cpcap_snd_controls,
+	.num_controls		= ARRAY_SIZE(cpcap_snd_controls),
+	.dapm_widgets		= cpcap_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cpcap_dapm_widgets),
+	.dapm_routes		= intercon,
+	.num_dapm_routes	= ARRAY_SIZE(intercon),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int cpcap_codec_probe(struct platform_device *pdev)
+{
+	struct device_node *codec_node =
+		of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec");
+
+	pdev->dev.of_node = codec_node;
+
+	return devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_cpcap,
+				      cpcap_dai, ARRAY_SIZE(cpcap_dai));
+}
+
+static struct platform_driver cpcap_codec_driver = {
+	.probe		= cpcap_codec_probe,
+	.driver		= {
+		.name	= "cpcap-codec",
+	},
+};
+module_platform_driver(cpcap_codec_driver);
+
+MODULE_ALIAS("platform:cpcap-codec");
+MODULE_DESCRIPTION("ASoC CPCAP codec driver");
+MODULE_AUTHOR("Sebastian Reichel");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
new file mode 100644
index 0000000..3301861d
--- /dev/null
+++ b/sound/soc/codecs/cq93vc.c
@@ -0,0 +1,168 @@
+/*
+ * ALSA SoC CQ0093 Voice Codec Driver for DaVinci platforms
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc
+ *
+ * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/mfd/davinci_voicecodec.h>
+#include <linux/spi/spi.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+static const struct snd_kcontrol_new cq93vc_snd_controls[] = {
+	SOC_SINGLE("PGA Capture Volume", DAVINCI_VC_REG05, 0, 0x03, 0),
+	SOC_SINGLE("Mono DAC Playback Volume", DAVINCI_VC_REG09, 0, 0x3f, 0),
+};
+
+static int cq93vc_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 reg;
+
+	if (mute)
+		reg = DAVINCI_VC_REG09_MUTE;
+	else
+		reg = 0;
+
+	snd_soc_component_update_bits(component, DAVINCI_VC_REG09, DAVINCI_VC_REG09_MUTE,
+			    reg);
+
+	return 0;
+}
+
+static int cq93vc_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	switch (freq) {
+	case 22579200:
+	case 27000000:
+	case 33868800:
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int cq93vc_set_bias_level(struct snd_soc_component *component,
+				enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_component_write(component, DAVINCI_VC_REG12,
+			     DAVINCI_VC_REG12_POWER_ALL_ON);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_component_write(component, DAVINCI_VC_REG12,
+			     DAVINCI_VC_REG12_POWER_ALL_OFF);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* force all power off */
+		snd_soc_component_write(component, DAVINCI_VC_REG12,
+			     DAVINCI_VC_REG12_POWER_ALL_OFF);
+		break;
+	}
+
+	return 0;
+}
+
+#define CQ93VC_RATES	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
+#define CQ93VC_FORMATS	(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
+
+static const struct snd_soc_dai_ops cq93vc_dai_ops = {
+	.digital_mute	= cq93vc_mute,
+	.set_sysclk	= cq93vc_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver cq93vc_dai = {
+	.name = "cq93vc-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = CQ93VC_RATES,
+		.formats = CQ93VC_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = CQ93VC_RATES,
+		.formats = CQ93VC_FORMATS,},
+	.ops = &cq93vc_dai_ops,
+};
+
+static int cq93vc_probe(struct snd_soc_component *component)
+{
+	struct davinci_vc *davinci_vc = component->dev->platform_data;
+
+	snd_soc_component_init_regmap(component, davinci_vc->regmap);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_cq93vc = {
+	.set_bias_level		= cq93vc_set_bias_level,
+	.probe			= cq93vc_probe,
+	.controls		= cq93vc_snd_controls,
+	.num_controls		= ARRAY_SIZE(cq93vc_snd_controls),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int cq93vc_platform_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_cq93vc, &cq93vc_dai, 1);
+}
+
+static int cq93vc_platform_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver cq93vc_codec_driver = {
+	.driver = {
+			.name = "cq93vc-codec",
+	},
+
+	.probe = cq93vc_platform_probe,
+	.remove = cq93vc_platform_remove,
+};
+
+module_platform_driver(cq93vc_codec_driver);
+
+MODULE_DESCRIPTION("Texas Instruments DaVinci ASoC CQ0093 Voice Codec Driver");
+MODULE_AUTHOR("Miguel Aguilar");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
new file mode 100644
index 0000000..4297058
--- /dev/null
+++ b/sound/soc/codecs/cs35l32.c
@@ -0,0 +1,586 @@
+/*
+ * cs35l32.c -- CS35L32 ALSA SoC audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <dt-bindings/sound/cs35l32.h>
+
+#include "cs35l32.h"
+
+#define CS35L32_NUM_SUPPLIES 2
+static const char *const cs35l32_supply_names[CS35L32_NUM_SUPPLIES] = {
+	"VA",
+	"VP",
+};
+
+struct  cs35l32_private {
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct regulator_bulk_data supplies[CS35L32_NUM_SUPPLIES];
+	struct cs35l32_platform_data pdata;
+	struct gpio_desc *reset_gpio;
+};
+
+static const struct reg_default cs35l32_reg_defaults[] = {
+
+	{ 0x06, 0x04 }, /* Power Ctl 1 */
+	{ 0x07, 0xE8 }, /* Power Ctl 2 */
+	{ 0x08, 0x40 }, /* Clock Ctl */
+	{ 0x09, 0x20 }, /* Low Battery Threshold */
+	{ 0x0A, 0x00 }, /* Voltage Monitor [RO] */
+	{ 0x0B, 0x40 }, /* Conv Peak Curr Protection CTL */
+	{ 0x0C, 0x07 }, /* IMON Scaling */
+	{ 0x0D, 0x03 }, /* Audio/LED Pwr Manager */
+	{ 0x0F, 0x20 }, /* Serial Port Control */
+	{ 0x10, 0x14 }, /* Class D Amp CTL */
+	{ 0x11, 0x00 }, /* Protection Release CTL */
+	{ 0x12, 0xFF }, /* Interrupt Mask 1 */
+	{ 0x13, 0xFF }, /* Interrupt Mask 2 */
+	{ 0x14, 0xFF }, /* Interrupt Mask 3 */
+	{ 0x19, 0x00 }, /* LED Flash Mode Current */
+	{ 0x1A, 0x00 }, /* LED Movie Mode Current */
+	{ 0x1B, 0x20 }, /* LED Flash Timer */
+	{ 0x1C, 0x00 }, /* LED Flash Inhibit Current */
+};
+
+static bool cs35l32_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS35L32_DEVID_AB ... CS35L32_AUDIO_LED_MNGR:
+	case CS35L32_ADSP_CTL ... CS35L32_FLASH_INHIBIT:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs35l32_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS35L32_DEVID_AB ... CS35L32_REV_ID:
+	case CS35L32_INT_STATUS_1 ... CS35L32_LED_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs35l32_precious_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS35L32_INT_STATUS_1 ... CS35L32_LED_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static DECLARE_TLV_DB_SCALE(classd_ctl_tlv, 900, 300, 0);
+
+static const struct snd_kcontrol_new imon_ctl =
+	SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 6, 1, 1);
+
+static const struct snd_kcontrol_new vmon_ctl =
+	SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 7, 1, 1);
+
+static const struct snd_kcontrol_new vpmon_ctl =
+	SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 5, 1, 1);
+
+static const struct snd_kcontrol_new cs35l32_snd_controls[] = {
+	SOC_SINGLE_TLV("Speaker Volume", CS35L32_CLASSD_CTL,
+		       3, 0x04, 1, classd_ctl_tlv),
+	SOC_SINGLE("Zero Cross Switch", CS35L32_CLASSD_CTL, 2, 1, 0),
+	SOC_SINGLE("Gain Manager Switch", CS35L32_AUDIO_LED_MNGR, 3, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget cs35l32_dapm_widgets[] = {
+
+	SND_SOC_DAPM_SUPPLY("BOOST", CS35L32_PWRCTL1, 2, 1, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Speaker", CS35L32_PWRCTL1, 7, 1, NULL, 0),
+
+	SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L32_PWRCTL2, 3, 1),
+
+	SND_SOC_DAPM_INPUT("VP"),
+	SND_SOC_DAPM_INPUT("ISENSE"),
+	SND_SOC_DAPM_INPUT("VSENSE"),
+
+	SND_SOC_DAPM_SWITCH("VMON ADC", CS35L32_PWRCTL2, 7, 1, &vmon_ctl),
+	SND_SOC_DAPM_SWITCH("IMON ADC", CS35L32_PWRCTL2, 6, 1, &imon_ctl),
+	SND_SOC_DAPM_SWITCH("VPMON ADC", CS35L32_PWRCTL2, 5, 1, &vpmon_ctl),
+};
+
+static const struct snd_soc_dapm_route cs35l32_audio_map[] = {
+
+	{"Speaker", NULL, "BOOST"},
+
+	{"VMON ADC", NULL, "VSENSE"},
+	{"IMON ADC", NULL, "ISENSE"},
+	{"VPMON ADC", NULL, "VP"},
+
+	{"SDOUT", "Switch", "VMON ADC"},
+	{"SDOUT",  "Switch", "IMON ADC"},
+	{"SDOUT", "Switch", "VPMON ADC"},
+
+	{"Capture", NULL, "SDOUT"},
+};
+
+static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		snd_soc_component_update_bits(component, CS35L32_ADSP_CTL,
+				    CS35L32_ADSP_MASTER_MASK,
+				CS35L32_ADSP_MASTER_MASK);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		snd_soc_component_update_bits(component, CS35L32_ADSP_CTL,
+				    CS35L32_ADSP_MASTER_MASK, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cs35l32_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+	struct snd_soc_component *component = dai->component;
+
+	return snd_soc_component_update_bits(component, CS35L32_PWRCTL2,
+					CS35L32_SDOUT_3ST, tristate << 3);
+}
+
+static const struct snd_soc_dai_ops cs35l32_ops = {
+	.set_fmt = cs35l32_set_dai_fmt,
+	.set_tristate = cs35l32_set_tristate,
+};
+
+static struct snd_soc_dai_driver cs35l32_dai[] = {
+	{
+		.name = "cs35l32-monitor",
+		.id = 0,
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = CS35L32_RATES,
+			.formats = CS35L32_FORMATS,
+		},
+		.ops = &cs35l32_ops,
+		.symmetric_rates = 1,
+	}
+};
+
+static int cs35l32_component_set_sysclk(struct snd_soc_component *component,
+			      int clk_id, int source, unsigned int freq, int dir)
+{
+	unsigned int val;
+
+	switch (freq) {
+	case 6000000:
+		val = CS35L32_MCLK_RATIO;
+		break;
+	case 12000000:
+		val = CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO;
+		break;
+	case 6144000:
+		val = 0;
+		break;
+	case 12288000:
+		val = CS35L32_MCLK_DIV2_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_soc_component_update_bits(component, CS35L32_CLK_CTL,
+			CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_cs35l32 = {
+	.set_sysclk		= cs35l32_component_set_sysclk,
+	.controls		= cs35l32_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs35l32_snd_controls),
+	.dapm_widgets		= cs35l32_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs35l32_dapm_widgets),
+	.dapm_routes		= cs35l32_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs35l32_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+/* Current and threshold powerup sequence Pg37 in datasheet */
+static const struct reg_sequence cs35l32_monitor_patch[] = {
+
+	{ 0x00, 0x99 },
+	{ 0x48, 0x17 },
+	{ 0x49, 0x56 },
+	{ 0x43, 0x01 },
+	{ 0x3B, 0x62 },
+	{ 0x3C, 0x80 },
+	{ 0x00, 0x00 },
+};
+
+static const struct regmap_config cs35l32_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = CS35L32_MAX_REGISTER,
+	.reg_defaults = cs35l32_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(cs35l32_reg_defaults),
+	.volatile_reg = cs35l32_volatile_register,
+	.readable_reg = cs35l32_readable_register,
+	.precious_reg = cs35l32_precious_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int cs35l32_handle_of_data(struct i2c_client *i2c_client,
+				    struct cs35l32_platform_data *pdata)
+{
+	struct device_node *np = i2c_client->dev.of_node;
+	unsigned int val;
+
+	if (of_property_read_u32(np, "cirrus,sdout-share", &val) >= 0)
+		pdata->sdout_share = val;
+
+	if (of_property_read_u32(np, "cirrus,boost-manager", &val))
+		val = -1u;
+
+	switch (val) {
+	case CS35L32_BOOST_MGR_AUTO:
+	case CS35L32_BOOST_MGR_AUTO_AUDIO:
+	case CS35L32_BOOST_MGR_BYPASS:
+	case CS35L32_BOOST_MGR_FIXED:
+		pdata->boost_mng = val;
+		break;
+	case -1u:
+	default:
+		dev_err(&i2c_client->dev,
+			"Wrong cirrus,boost-manager DT value %d\n", val);
+		pdata->boost_mng = CS35L32_BOOST_MGR_BYPASS;
+	}
+
+	if (of_property_read_u32(np, "cirrus,sdout-datacfg", &val))
+		val = -1u;
+	switch (val) {
+	case CS35L32_DATA_CFG_LR_VP:
+	case CS35L32_DATA_CFG_LR_STAT:
+	case CS35L32_DATA_CFG_LR:
+	case CS35L32_DATA_CFG_LR_VPSTAT:
+		pdata->sdout_datacfg = val;
+		break;
+	case -1u:
+	default:
+		dev_err(&i2c_client->dev,
+			"Wrong cirrus,sdout-datacfg DT value %d\n", val);
+		pdata->sdout_datacfg = CS35L32_DATA_CFG_LR;
+	}
+
+	if (of_property_read_u32(np, "cirrus,battery-threshold", &val))
+		val = -1u;
+	switch (val) {
+	case CS35L32_BATT_THRESH_3_1V:
+	case CS35L32_BATT_THRESH_3_2V:
+	case CS35L32_BATT_THRESH_3_3V:
+	case CS35L32_BATT_THRESH_3_4V:
+		pdata->batt_thresh = val;
+		break;
+	case -1u:
+	default:
+		dev_err(&i2c_client->dev,
+			"Wrong cirrus,battery-threshold DT value %d\n", val);
+		pdata->batt_thresh = CS35L32_BATT_THRESH_3_3V;
+	}
+
+	if (of_property_read_u32(np, "cirrus,battery-recovery", &val))
+		val = -1u;
+	switch (val) {
+	case CS35L32_BATT_RECOV_3_1V:
+	case CS35L32_BATT_RECOV_3_2V:
+	case CS35L32_BATT_RECOV_3_3V:
+	case CS35L32_BATT_RECOV_3_4V:
+	case CS35L32_BATT_RECOV_3_5V:
+	case CS35L32_BATT_RECOV_3_6V:
+		pdata->batt_recov = val;
+		break;
+	case -1u:
+	default:
+		dev_err(&i2c_client->dev,
+			"Wrong cirrus,battery-recovery DT value %d\n", val);
+		pdata->batt_recov = CS35L32_BATT_RECOV_3_4V;
+	}
+
+	return 0;
+}
+
+static int cs35l32_i2c_probe(struct i2c_client *i2c_client,
+				       const struct i2c_device_id *id)
+{
+	struct cs35l32_private *cs35l32;
+	struct cs35l32_platform_data *pdata =
+		dev_get_platdata(&i2c_client->dev);
+	int ret, i;
+	unsigned int devid = 0;
+	unsigned int reg;
+
+	cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(*cs35l32), GFP_KERNEL);
+	if (!cs35l32)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c_client, cs35l32);
+
+	cs35l32->regmap = devm_regmap_init_i2c(i2c_client, &cs35l32_regmap);
+	if (IS_ERR(cs35l32->regmap)) {
+		ret = PTR_ERR(cs35l32->regmap);
+		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	if (pdata) {
+		cs35l32->pdata = *pdata;
+	} else {
+		pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
+				     GFP_KERNEL);
+		if (!pdata)
+			return -ENOMEM;
+
+		if (i2c_client->dev.of_node) {
+			ret = cs35l32_handle_of_data(i2c_client,
+						     &cs35l32->pdata);
+			if (ret != 0)
+				return ret;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cs35l32->supplies); i++)
+		cs35l32->supplies[i].supply = cs35l32_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c_client->dev,
+				      ARRAY_SIZE(cs35l32->supplies),
+				      cs35l32->supplies);
+	if (ret != 0) {
+		dev_err(&i2c_client->dev,
+			"Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies),
+				    cs35l32->supplies);
+	if (ret != 0) {
+		dev_err(&i2c_client->dev,
+			"Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	/* Reset the Device */
+	cs35l32->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+		"reset", GPIOD_OUT_LOW);
+	if (IS_ERR(cs35l32->reset_gpio))
+		return PTR_ERR(cs35l32->reset_gpio);
+
+	gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
+
+	/* initialize codec */
+	ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, &reg);
+	devid = (reg & 0xFF) << 12;
+
+	ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_CD, &reg);
+	devid |= (reg & 0xFF) << 4;
+
+	ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_E, &reg);
+	devid |= (reg & 0xF0) >> 4;
+
+	if (devid != CS35L32_CHIP_ID) {
+		ret = -ENODEV;
+		dev_err(&i2c_client->dev,
+			"CS35L32 Device ID (%X). Expected %X\n",
+			devid, CS35L32_CHIP_ID);
+		return ret;
+	}
+
+	ret = regmap_read(cs35l32->regmap, CS35L32_REV_ID, &reg);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+		return ret;
+	}
+
+	ret = regmap_register_patch(cs35l32->regmap, cs35l32_monitor_patch,
+				    ARRAY_SIZE(cs35l32_monitor_patch));
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "Failed to apply errata patch\n");
+		return ret;
+	}
+
+	dev_info(&i2c_client->dev,
+		 "Cirrus Logic CS35L32, Revision: %02X\n", reg & 0xFF);
+
+	/* Setup VBOOST Management */
+	if (cs35l32->pdata.boost_mng)
+		regmap_update_bits(cs35l32->regmap, CS35L32_AUDIO_LED_MNGR,
+				   CS35L32_BOOST_MASK,
+				cs35l32->pdata.boost_mng);
+
+	/* Setup ADSP Format Config */
+	if (cs35l32->pdata.sdout_share)
+		regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL,
+				    CS35L32_ADSP_SHARE_MASK,
+				cs35l32->pdata.sdout_share << 3);
+
+	/* Setup ADSP Data Configuration */
+	if (cs35l32->pdata.sdout_datacfg)
+		regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL,
+				   CS35L32_ADSP_DATACFG_MASK,
+				cs35l32->pdata.sdout_datacfg << 4);
+
+	/* Setup Low Battery Recovery  */
+	if (cs35l32->pdata.batt_recov)
+		regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD,
+				   CS35L32_BATT_REC_MASK,
+				cs35l32->pdata.batt_recov << 1);
+
+	/* Setup Low Battery Threshold */
+	if (cs35l32->pdata.batt_thresh)
+		regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD,
+				   CS35L32_BATT_THRESH_MASK,
+				cs35l32->pdata.batt_thresh << 4);
+
+	/* Power down the AMP */
+	regmap_update_bits(cs35l32->regmap, CS35L32_PWRCTL1, CS35L32_PDN_AMP,
+			    CS35L32_PDN_AMP);
+
+	/* Clear MCLK Error Bit since we don't have the clock yet */
+	ret = regmap_read(cs35l32->regmap, CS35L32_INT_STATUS_1, &reg);
+
+	ret = devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_dev_cs35l32, cs35l32_dai,
+			ARRAY_SIZE(cs35l32_dai));
+	if (ret < 0)
+		goto err_disable;
+
+	return 0;
+
+err_disable:
+	regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
+			       cs35l32->supplies);
+	return ret;
+}
+
+static int cs35l32_i2c_remove(struct i2c_client *i2c_client)
+{
+	struct cs35l32_private *cs35l32 = i2c_get_clientdata(i2c_client);
+
+	/* Hold down reset */
+	gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int cs35l32_runtime_suspend(struct device *dev)
+{
+	struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
+
+	regcache_cache_only(cs35l32->regmap, true);
+	regcache_mark_dirty(cs35l32->regmap);
+
+	/* Hold down reset */
+	gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
+
+	/* remove power */
+	regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
+			       cs35l32->supplies);
+
+	return 0;
+}
+
+static int cs35l32_runtime_resume(struct device *dev)
+{
+	struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
+	int ret;
+
+	/* Enable power */
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies),
+				    cs35l32->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
+
+	regcache_cache_only(cs35l32->regmap, false);
+	regcache_sync(cs35l32->regmap);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops cs35l32_runtime_pm = {
+	SET_RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume,
+			   NULL)
+};
+
+static const struct of_device_id cs35l32_of_match[] = {
+	{ .compatible = "cirrus,cs35l32", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cs35l32_of_match);
+
+
+static const struct i2c_device_id cs35l32_id[] = {
+	{"cs35l32", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs35l32_id);
+
+static struct i2c_driver cs35l32_i2c_driver = {
+	.driver = {
+		   .name = "cs35l32",
+		   .pm = &cs35l32_runtime_pm,
+		   .of_match_table = cs35l32_of_match,
+		   },
+	.id_table = cs35l32_id,
+	.probe = cs35l32_i2c_probe,
+	.remove = cs35l32_i2c_remove,
+};
+
+module_i2c_driver(cs35l32_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS35L32 driver");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l32.h b/sound/soc/codecs/cs35l32.h
new file mode 100644
index 0000000..1d6c250
--- /dev/null
+++ b/sound/soc/codecs/cs35l32.h
@@ -0,0 +1,93 @@
+/*
+ * cs35l32.h -- CS35L32 ALSA SoC audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CS35L32_H__
+#define __CS35L32_H__
+
+struct cs35l32_platform_data {
+	/* Low Battery Threshold */
+	unsigned int batt_thresh;
+	/* Low Battery Recovery */
+	unsigned int batt_recov;
+	/* LED Current Management*/
+	unsigned int led_mng;
+	/* Audio Gain w/ LED */
+	unsigned int audiogain_mng;
+	/* Boost Management */
+	unsigned int boost_mng;
+	/* Data CFG for DUAL device */
+	unsigned int sdout_datacfg;
+	/* SDOUT Sharing */
+	unsigned int sdout_share;
+};
+
+#define CS35L32_CHIP_ID		0x00035A32
+#define CS35L32_DEVID_AB	0x01	/* Device ID A & B [RO] */
+#define CS35L32_DEVID_CD	0x02    /* Device ID C & D [RO] */
+#define CS35L32_DEVID_E		0x03    /* Device ID E [RO] */
+#define CS35L32_FAB_ID		0x04	/* Fab ID [RO] */
+#define CS35L32_REV_ID		0x05	/* Revision ID [RO] */
+#define CS35L32_PWRCTL1		0x06    /* Power Ctl 1 */
+#define CS35L32_PWRCTL2		0x07    /* Power Ctl 2 */
+#define CS35L32_CLK_CTL		0x08	/* Clock Ctl */
+#define CS35L32_BATT_THRESHOLD	0x09	/* Low Battery Threshold */
+#define CS35L32_VMON		0x0A	/* Voltage Monitor [RO] */
+#define CS35L32_BST_CPCP_CTL	0x0B	/* Conv Peak Curr Protection CTL */
+#define CS35L32_IMON_SCALING	0x0C	/* IMON Scaling */
+#define CS35L32_AUDIO_LED_MNGR	0x0D	/* Audio/LED Pwr Manager */
+#define CS35L32_ADSP_CTL	0x0F	/* Serial Port Control */
+#define CS35L32_CLASSD_CTL	0x10	/* Class D Amp CTL */
+#define CS35L32_PROTECT_CTL	0x11	/* Protection Release CTL */
+#define CS35L32_INT_MASK_1	0x12	/* Interrupt Mask 1 */
+#define CS35L32_INT_MASK_2	0x13	/* Interrupt Mask 2 */
+#define CS35L32_INT_MASK_3	0x14	/* Interrupt Mask 3 */
+#define CS35L32_INT_STATUS_1	0x15	/* Interrupt Status 1 [RO] */
+#define CS35L32_INT_STATUS_2	0x16	/* Interrupt Status 2 [RO] */
+#define CS35L32_INT_STATUS_3	0x17	/* Interrupt Status 3 [RO] */
+#define CS35L32_LED_STATUS	0x18	/* LED Lighting Status [RO] */
+#define CS35L32_FLASH_MODE	0x19	/* LED Flash Mode Current */
+#define CS35L32_MOVIE_MODE	0x1A	/* LED Movie Mode Current */
+#define CS35L32_FLASH_TIMER	0x1B	/* LED Flash Timer */
+#define CS35L32_FLASH_INHIBIT	0x1C	/* LED Flash Inhibit Current */
+#define CS35L32_MAX_REGISTER	0x1C
+
+#define CS35L32_MCLK_DIV2	0x01
+#define CS35L32_MCLK_RATIO	0x01
+#define CS35L32_MCLKDIS		0x80
+#define CS35L32_PDN_ALL		0x01
+#define CS35L32_PDN_AMP		0x80
+#define CS35L32_PDN_BOOST	0x04
+#define CS35L32_PDN_IMON	0x40
+#define CS35L32_PDN_VMON	0x80
+#define CS35L32_PDN_VPMON	0x20
+#define CS35L32_PDN_ADSP	0x08
+
+#define CS35L32_MCLK_DIV2_MASK		0x40
+#define CS35L32_MCLK_RATIO_MASK		0x01
+#define CS35L32_MCLK_MASK		0x41
+#define CS35L32_ADSP_MASTER_MASK	0x40
+#define CS35L32_BOOST_MASK		0x03
+#define CS35L32_GAIN_MGR_MASK		0x08
+#define CS35L32_ADSP_SHARE_MASK		0x08
+#define CS35L32_ADSP_DATACFG_MASK	0x30
+#define CS35L32_SDOUT_3ST		0x08
+#define CS35L32_BATT_REC_MASK		0x0E
+#define CS35L32_BATT_THRESH_MASK	0x30
+
+#define CS35L32_RATES (SNDRV_PCM_RATE_48000)
+#define CS35L32_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | \
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+
+#endif
diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c
new file mode 100644
index 0000000..668cd37
--- /dev/null
+++ b/sound/soc/codecs/cs35l33.c
@@ -0,0 +1,1296 @@
+/*
+ * cs35l33.c -- CS35L33 ALSA SoC audio driver
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: Paul Handrigan <paul.handrigan@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <sound/cs35l33.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+#include <linux/of_gpio.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+
+#include "cs35l33.h"
+
+#define CS35L33_BOOT_DELAY	50
+
+struct cs35l33_private {
+	struct snd_soc_component *component;
+	struct cs35l33_pdata pdata;
+	struct regmap *regmap;
+	struct gpio_desc *reset_gpio;
+	bool amp_cal;
+	int mclk_int;
+	struct regulator_bulk_data core_supplies[2];
+	int num_core_supplies;
+	bool is_tdm_mode;
+	bool enable_soft_ramp;
+};
+
+static const struct reg_default cs35l33_reg[] = {
+	{CS35L33_PWRCTL1, 0x85},
+	{CS35L33_PWRCTL2, 0xFE},
+	{CS35L33_CLK_CTL, 0x0C},
+	{CS35L33_BST_PEAK_CTL, 0x90},
+	{CS35L33_PROTECT_CTL, 0x55},
+	{CS35L33_BST_CTL1, 0x00},
+	{CS35L33_BST_CTL2, 0x01},
+	{CS35L33_ADSP_CTL, 0x00},
+	{CS35L33_ADC_CTL, 0xC8},
+	{CS35L33_DAC_CTL, 0x14},
+	{CS35L33_DIG_VOL_CTL, 0x00},
+	{CS35L33_CLASSD_CTL, 0x04},
+	{CS35L33_AMP_CTL, 0x90},
+	{CS35L33_INT_MASK_1, 0xFF},
+	{CS35L33_INT_MASK_2, 0xFF},
+	{CS35L33_DIAG_LOCK, 0x00},
+	{CS35L33_DIAG_CTRL_1, 0x40},
+	{CS35L33_DIAG_CTRL_2, 0x00},
+	{CS35L33_HG_MEMLDO_CTL, 0x62},
+	{CS35L33_HG_REL_RATE, 0x03},
+	{CS35L33_LDO_DEL, 0x12},
+	{CS35L33_HG_HEAD, 0x0A},
+	{CS35L33_HG_EN, 0x05},
+	{CS35L33_TX_VMON, 0x00},
+	{CS35L33_TX_IMON, 0x03},
+	{CS35L33_TX_VPMON, 0x02},
+	{CS35L33_TX_VBSTMON, 0x05},
+	{CS35L33_TX_FLAG, 0x06},
+	{CS35L33_TX_EN1, 0x00},
+	{CS35L33_TX_EN2, 0x00},
+	{CS35L33_TX_EN3, 0x00},
+	{CS35L33_TX_EN4, 0x00},
+	{CS35L33_RX_AUD, 0x40},
+	{CS35L33_RX_SPLY, 0x03},
+	{CS35L33_RX_ALIVE, 0x04},
+	{CS35L33_BST_CTL4, 0x63},
+};
+
+static const struct reg_sequence cs35l33_patch[] = {
+	{ 0x00,  0x99, 0 },
+	{ 0x59,  0x02, 0 },
+	{ 0x52,  0x30, 0 },
+	{ 0x39,  0x45, 0 },
+	{ 0x57,  0x30, 0 },
+	{ 0x2C,  0x68, 0 },
+	{ 0x00,  0x00, 0 },
+};
+
+static bool cs35l33_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS35L33_DEVID_AB:
+	case CS35L33_DEVID_CD:
+	case CS35L33_DEVID_E:
+	case CS35L33_REV_ID:
+	case CS35L33_INT_STATUS_1:
+	case CS35L33_INT_STATUS_2:
+	case CS35L33_HG_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs35l33_writeable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	/* these are read only registers */
+	case CS35L33_DEVID_AB:
+	case CS35L33_DEVID_CD:
+	case CS35L33_DEVID_E:
+	case CS35L33_REV_ID:
+	case CS35L33_INT_STATUS_1:
+	case CS35L33_INT_STATUS_2:
+	case CS35L33_HG_STATUS:
+		return false;
+	default:
+		return true;
+	}
+}
+
+static bool cs35l33_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS35L33_DEVID_AB:
+	case CS35L33_DEVID_CD:
+	case CS35L33_DEVID_E:
+	case CS35L33_REV_ID:
+	case CS35L33_PWRCTL1:
+	case CS35L33_PWRCTL2:
+	case CS35L33_CLK_CTL:
+	case CS35L33_BST_PEAK_CTL:
+	case CS35L33_PROTECT_CTL:
+	case CS35L33_BST_CTL1:
+	case CS35L33_BST_CTL2:
+	case CS35L33_ADSP_CTL:
+	case CS35L33_ADC_CTL:
+	case CS35L33_DAC_CTL:
+	case CS35L33_DIG_VOL_CTL:
+	case CS35L33_CLASSD_CTL:
+	case CS35L33_AMP_CTL:
+	case CS35L33_INT_MASK_1:
+	case CS35L33_INT_MASK_2:
+	case CS35L33_INT_STATUS_1:
+	case CS35L33_INT_STATUS_2:
+	case CS35L33_DIAG_LOCK:
+	case CS35L33_DIAG_CTRL_1:
+	case CS35L33_DIAG_CTRL_2:
+	case CS35L33_HG_MEMLDO_CTL:
+	case CS35L33_HG_REL_RATE:
+	case CS35L33_LDO_DEL:
+	case CS35L33_HG_HEAD:
+	case CS35L33_HG_EN:
+	case CS35L33_TX_VMON:
+	case CS35L33_TX_IMON:
+	case CS35L33_TX_VPMON:
+	case CS35L33_TX_VBSTMON:
+	case CS35L33_TX_FLAG:
+	case CS35L33_TX_EN1:
+	case CS35L33_TX_EN2:
+	case CS35L33_TX_EN3:
+	case CS35L33_TX_EN4:
+	case CS35L33_RX_AUD:
+	case CS35L33_RX_SPLY:
+	case CS35L33_RX_ALIVE:
+	case CS35L33_BST_CTL4:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static DECLARE_TLV_DB_SCALE(classd_ctl_tlv, 900, 100, 0);
+static DECLARE_TLV_DB_SCALE(dac_tlv, -10200, 50, 0);
+
+static const struct snd_kcontrol_new cs35l33_snd_controls[] = {
+
+	SOC_SINGLE_TLV("SPK Amp Volume", CS35L33_AMP_CTL,
+		       4, 0x09, 0, classd_ctl_tlv),
+	SOC_SINGLE_SX_TLV("DAC Volume", CS35L33_DIG_VOL_CTL,
+			0, 0x34, 0xE4, dac_tlv),
+};
+
+static int cs35l33_spkrdrv_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (!priv->amp_cal) {
+			usleep_range(8000, 9000);
+			priv->amp_cal = true;
+			regmap_update_bits(priv->regmap, CS35L33_CLASSD_CTL,
+				    CS35L33_AMP_CAL, 0);
+			dev_dbg(component->dev, "Amp calibration done\n");
+		}
+		dev_dbg(component->dev, "Amp turned on\n");
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		dev_dbg(component->dev, "Amp turned off\n");
+		break;
+	default:
+		dev_err(component->dev, "Invalid event = 0x%x\n", event);
+		break;
+	}
+
+	return 0;
+}
+
+static int cs35l33_sdin_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_update_bits(priv->regmap, CS35L33_PWRCTL1,
+				    CS35L33_PDN_BST, 0);
+		val = priv->is_tdm_mode ? 0 : CS35L33_PDN_TDM;
+		regmap_update_bits(priv->regmap, CS35L33_PWRCTL2,
+				    CS35L33_PDN_TDM, val);
+		dev_dbg(component->dev, "BST turned on\n");
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		dev_dbg(component->dev, "SDIN turned on\n");
+		if (!priv->amp_cal) {
+			regmap_update_bits(priv->regmap, CS35L33_CLASSD_CTL,
+				    CS35L33_AMP_CAL, CS35L33_AMP_CAL);
+			dev_dbg(component->dev, "Amp calibration started\n");
+			usleep_range(10000, 11000);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_update_bits(priv->regmap, CS35L33_PWRCTL2,
+				    CS35L33_PDN_TDM, CS35L33_PDN_TDM);
+		usleep_range(4000, 4100);
+		regmap_update_bits(priv->regmap, CS35L33_PWRCTL1,
+				    CS35L33_PDN_BST, CS35L33_PDN_BST);
+		dev_dbg(component->dev, "BST and SDIN turned off\n");
+		break;
+	default:
+		dev_err(component->dev, "Invalid event = 0x%x\n", event);
+
+	}
+
+	return 0;
+}
+
+static int cs35l33_sdout_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
+	unsigned int mask = CS35L33_SDOUT_3ST_I2S | CS35L33_PDN_TDM;
+	unsigned int mask2 = CS35L33_SDOUT_3ST_TDM;
+	unsigned int val, val2;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (priv->is_tdm_mode) {
+			/* set sdout_3st_i2s and reset pdn_tdm */
+			val = CS35L33_SDOUT_3ST_I2S;
+			/* reset sdout_3st_tdm */
+			val2 = 0;
+		} else {
+			/* reset sdout_3st_i2s and set pdn_tdm */
+			val = CS35L33_PDN_TDM;
+			/* set sdout_3st_tdm */
+			val2 = CS35L33_SDOUT_3ST_TDM;
+		}
+		dev_dbg(component->dev, "SDOUT turned on\n");
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		val = CS35L33_SDOUT_3ST_I2S | CS35L33_PDN_TDM;
+		val2 = CS35L33_SDOUT_3ST_TDM;
+		dev_dbg(component->dev, "SDOUT turned off\n");
+		break;
+	default:
+		dev_err(component->dev, "Invalid event = 0x%x\n", event);
+		return 0;
+	}
+
+	regmap_update_bits(priv->regmap, CS35L33_PWRCTL2,
+		mask, val);
+	regmap_update_bits(priv->regmap, CS35L33_CLK_CTL,
+		mask2, val2);
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget cs35l33_dapm_widgets[] = {
+
+	SND_SOC_DAPM_OUTPUT("SPK"),
+	SND_SOC_DAPM_OUT_DRV_E("SPKDRV", CS35L33_PWRCTL1, 7, 1, NULL, 0,
+		cs35l33_spkrdrv_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L33_PWRCTL2,
+		2, 1, cs35l33_sdin_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_INPUT("MON"),
+
+	SND_SOC_DAPM_ADC("VMON", NULL,
+		CS35L33_PWRCTL2, CS35L33_PDN_VMON_SHIFT, 1),
+	SND_SOC_DAPM_ADC("IMON", NULL,
+		CS35L33_PWRCTL2, CS35L33_PDN_IMON_SHIFT, 1),
+	SND_SOC_DAPM_ADC("VPMON", NULL,
+		CS35L33_PWRCTL2, CS35L33_PDN_VPMON_SHIFT, 1),
+	SND_SOC_DAPM_ADC("VBSTMON", NULL,
+		CS35L33_PWRCTL2, CS35L33_PDN_VBSTMON_SHIFT, 1),
+
+	SND_SOC_DAPM_AIF_OUT_E("SDOUT", NULL, 0, SND_SOC_NOPM, 0, 0,
+		cs35l33_sdout_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_PRE_PMD),
+};
+
+static const struct snd_soc_dapm_route cs35l33_audio_map[] = {
+	{"SDIN", NULL, "CS35L33 Playback"},
+	{"SPKDRV", NULL, "SDIN"},
+	{"SPK", NULL, "SPKDRV"},
+
+	{"VMON", NULL, "MON"},
+	{"IMON", NULL, "MON"},
+
+	{"SDOUT", NULL, "VMON"},
+	{"SDOUT", NULL, "IMON"},
+	{"CS35L33 Capture", NULL, "SDOUT"},
+};
+
+static const struct snd_soc_dapm_route cs35l33_vphg_auto_route[] = {
+	{"SPKDRV", NULL, "VPMON"},
+	{"VPMON", NULL, "CS35L33 Playback"},
+};
+
+static const struct snd_soc_dapm_route cs35l33_vp_vbst_mon_route[] = {
+	{"SDOUT", NULL, "VPMON"},
+	{"VPMON", NULL, "MON"},
+	{"SDOUT", NULL, "VBSTMON"},
+	{"VBSTMON", NULL, "MON"},
+};
+
+static int cs35l33_set_bias_level(struct snd_soc_component *component,
+				  enum snd_soc_bias_level level)
+{
+	unsigned int val;
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		regmap_update_bits(priv->regmap, CS35L33_PWRCTL1,
+				    CS35L33_PDN_ALL, 0);
+		regmap_update_bits(priv->regmap, CS35L33_CLK_CTL,
+				    CS35L33_MCLKDIS, 0);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		regmap_update_bits(priv->regmap, CS35L33_PWRCTL1,
+				    CS35L33_PDN_ALL, CS35L33_PDN_ALL);
+		regmap_read(priv->regmap, CS35L33_INT_STATUS_2, &val);
+		usleep_range(1000, 1100);
+		if (val & CS35L33_PDN_DONE)
+			regmap_update_bits(priv->regmap, CS35L33_CLK_CTL,
+					    CS35L33_MCLKDIS, CS35L33_MCLKDIS);
+		break;
+	case SND_SOC_BIAS_OFF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+struct cs35l33_mclk_div {
+	int mclk;
+	int srate;
+	u8 adsp_rate;
+	u8 int_fs_ratio;
+};
+
+static const struct cs35l33_mclk_div cs35l33_mclk_coeffs[] = {
+	/* MCLK, Sample Rate, adsp_rate, int_fs_ratio */
+	{5644800, 11025, 0x4, CS35L33_INT_FS_RATE},
+	{5644800, 22050, 0x8, CS35L33_INT_FS_RATE},
+	{5644800, 44100, 0xC, CS35L33_INT_FS_RATE},
+
+	{6000000,  8000, 0x1, 0},
+	{6000000, 11025, 0x2, 0},
+	{6000000, 11029, 0x3, 0},
+	{6000000, 12000, 0x4, 0},
+	{6000000, 16000, 0x5, 0},
+	{6000000, 22050, 0x6, 0},
+	{6000000, 22059, 0x7, 0},
+	{6000000, 24000, 0x8, 0},
+	{6000000, 32000, 0x9, 0},
+	{6000000, 44100, 0xA, 0},
+	{6000000, 44118, 0xB, 0},
+	{6000000, 48000, 0xC, 0},
+
+	{6144000,  8000, 0x1, CS35L33_INT_FS_RATE},
+	{6144000, 12000, 0x4, CS35L33_INT_FS_RATE},
+	{6144000, 16000, 0x5, CS35L33_INT_FS_RATE},
+	{6144000, 24000, 0x8, CS35L33_INT_FS_RATE},
+	{6144000, 32000, 0x9, CS35L33_INT_FS_RATE},
+	{6144000, 48000, 0xC, CS35L33_INT_FS_RATE},
+};
+
+static int cs35l33_get_mclk_coeff(int mclk, int srate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cs35l33_mclk_coeffs); i++) {
+		if (cs35l33_mclk_coeffs[i].mclk == mclk &&
+			cs35l33_mclk_coeffs[i].srate == srate)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static int cs35l33_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		regmap_update_bits(priv->regmap, CS35L33_ADSP_CTL,
+			CS35L33_MS_MASK, CS35L33_MS_MASK);
+		dev_dbg(component->dev, "Audio port in master mode\n");
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		regmap_update_bits(priv->regmap, CS35L33_ADSP_CTL,
+			CS35L33_MS_MASK, 0);
+		dev_dbg(component->dev, "Audio port in slave mode\n");
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		/*
+		 * tdm mode in cs35l33 resembles dsp-a mode very
+		 * closely, it is dsp-a with fsync shifted left by half bclk
+		 */
+		priv->is_tdm_mode = true;
+		dev_dbg(component->dev, "Audio port in TDM mode\n");
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		priv->is_tdm_mode = false;
+		dev_dbg(component->dev, "Audio port in I2S mode\n");
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cs35l33_pcm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
+	int sample_size = params_width(params);
+	int coeff = cs35l33_get_mclk_coeff(priv->mclk_int, params_rate(params));
+
+	if (coeff < 0)
+		return coeff;
+
+	regmap_update_bits(priv->regmap, CS35L33_CLK_CTL,
+		CS35L33_ADSP_FS | CS35L33_INT_FS_RATE,
+		cs35l33_mclk_coeffs[coeff].int_fs_ratio
+		| cs35l33_mclk_coeffs[coeff].adsp_rate);
+
+	if (priv->is_tdm_mode) {
+		sample_size = (sample_size / 8) - 1;
+		if (sample_size > 2)
+			sample_size = 2;
+		regmap_update_bits(priv->regmap, CS35L33_RX_AUD,
+			CS35L33_AUDIN_RX_DEPTH,
+			sample_size << CS35L33_AUDIN_RX_DEPTH_SHIFT);
+	}
+
+	dev_dbg(component->dev, "sample rate=%d, bits per sample=%d\n",
+		params_rate(params), params_width(params));
+
+	return 0;
+}
+
+static const unsigned int cs35l33_src_rates[] = {
+	8000, 11025, 11029, 12000, 16000, 22050,
+	22059, 24000, 32000, 44100, 44118, 48000
+};
+
+static const struct snd_pcm_hw_constraint_list cs35l33_constraints = {
+	.count  = ARRAY_SIZE(cs35l33_src_rates),
+	.list   = cs35l33_src_rates,
+};
+
+static int cs35l33_pcm_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+					SNDRV_PCM_HW_PARAM_RATE,
+					&cs35l33_constraints);
+	return 0;
+}
+
+static int cs35l33_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
+
+	if (tristate) {
+		regmap_update_bits(priv->regmap, CS35L33_PWRCTL2,
+			CS35L33_SDOUT_3ST_I2S, CS35L33_SDOUT_3ST_I2S);
+		regmap_update_bits(priv->regmap, CS35L33_CLK_CTL,
+			CS35L33_SDOUT_3ST_TDM, CS35L33_SDOUT_3ST_TDM);
+	} else {
+		regmap_update_bits(priv->regmap, CS35L33_PWRCTL2,
+			CS35L33_SDOUT_3ST_I2S, 0);
+		regmap_update_bits(priv->regmap, CS35L33_CLK_CTL,
+			CS35L33_SDOUT_3ST_TDM, 0);
+	}
+
+	return 0;
+}
+
+static int cs35l33_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+				unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
+	unsigned int reg, bit_pos, i;
+	int slot, slot_num;
+
+	if (slot_width != 8)
+		return -EINVAL;
+
+	/* scan rx_mask for aud slot */
+	slot = ffs(rx_mask) - 1;
+	if (slot >= 0) {
+		regmap_update_bits(priv->regmap, CS35L33_RX_AUD,
+			CS35L33_X_LOC, slot);
+		dev_dbg(component->dev, "Audio starts from slots %d", slot);
+	}
+
+	/*
+	 * scan tx_mask: vmon(2 slots); imon (2 slots);
+	 * vpmon (1 slot) vbstmon (1 slot)
+	 */
+	slot = ffs(tx_mask) - 1;
+	slot_num = 0;
+
+	for (i = 0; i < 2 ; i++) {
+		/* disable vpmon/vbstmon: enable later if set in tx_mask */
+		regmap_update_bits(priv->regmap, CS35L33_TX_VPMON + i,
+			CS35L33_X_STATE | CS35L33_X_LOC, CS35L33_X_STATE
+			| CS35L33_X_LOC);
+	}
+
+	/* disconnect {vp,vbst}_mon routes: eanble later if set in tx_mask*/
+	snd_soc_dapm_del_routes(dapm, cs35l33_vp_vbst_mon_route,
+		ARRAY_SIZE(cs35l33_vp_vbst_mon_route));
+
+	while (slot >= 0) {
+		/* configure VMON_TX_LOC */
+		if (slot_num == 0) {
+			regmap_update_bits(priv->regmap, CS35L33_TX_VMON,
+				CS35L33_X_STATE | CS35L33_X_LOC, slot);
+			dev_dbg(component->dev, "VMON enabled in slots %d-%d",
+				slot, slot + 1);
+		}
+
+		/* configure IMON_TX_LOC */
+		if (slot_num == 3) {
+			regmap_update_bits(priv->regmap, CS35L33_TX_IMON,
+				CS35L33_X_STATE | CS35L33_X_LOC, slot);
+			dev_dbg(component->dev, "IMON enabled in slots %d-%d",
+				slot, slot + 1);
+		}
+
+		/* configure VPMON_TX_LOC */
+		if (slot_num == 4) {
+			regmap_update_bits(priv->regmap, CS35L33_TX_VPMON,
+				CS35L33_X_STATE | CS35L33_X_LOC, slot);
+			snd_soc_dapm_add_routes(dapm,
+				&cs35l33_vp_vbst_mon_route[0], 2);
+			dev_dbg(component->dev, "VPMON enabled in slots %d", slot);
+		}
+
+		/* configure VBSTMON_TX_LOC */
+		if (slot_num == 5) {
+			regmap_update_bits(priv->regmap, CS35L33_TX_VBSTMON,
+				CS35L33_X_STATE | CS35L33_X_LOC, slot);
+			snd_soc_dapm_add_routes(dapm,
+				&cs35l33_vp_vbst_mon_route[2], 2);
+			dev_dbg(component->dev,
+				"VBSTMON enabled in slots %d", slot);
+		}
+
+		/* Enable the relevant tx slot */
+		reg = CS35L33_TX_EN4 - (slot/8);
+		bit_pos = slot - ((slot / 8) * (8));
+		regmap_update_bits(priv->regmap, reg,
+			1 << bit_pos, 1 << bit_pos);
+
+		tx_mask &= ~(1 << slot);
+		slot = ffs(tx_mask) - 1;
+		slot_num++;
+	}
+
+	return 0;
+}
+
+static int cs35l33_component_set_sysclk(struct snd_soc_component *component,
+		int clk_id, int source, unsigned int freq, int dir)
+{
+	struct cs35l33_private *cs35l33 = snd_soc_component_get_drvdata(component);
+
+	switch (freq) {
+	case CS35L33_MCLK_5644:
+	case CS35L33_MCLK_6:
+	case CS35L33_MCLK_6144:
+		regmap_update_bits(cs35l33->regmap, CS35L33_CLK_CTL,
+			CS35L33_MCLKDIV2, 0);
+		cs35l33->mclk_int = freq;
+		break;
+	case CS35L33_MCLK_11289:
+	case CS35L33_MCLK_12:
+	case CS35L33_MCLK_12288:
+		regmap_update_bits(cs35l33->regmap, CS35L33_CLK_CTL,
+			CS35L33_MCLKDIV2, CS35L33_MCLKDIV2);
+		cs35l33->mclk_int = freq/2;
+		break;
+	default:
+		cs35l33->mclk_int = 0;
+		return -EINVAL;
+	}
+
+	dev_dbg(component->dev, "external mclk freq=%d, internal mclk freq=%d\n",
+		freq, cs35l33->mclk_int);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops cs35l33_ops = {
+	.startup = cs35l33_pcm_startup,
+	.set_tristate = cs35l33_set_tristate,
+	.set_fmt = cs35l33_set_dai_fmt,
+	.hw_params = cs35l33_pcm_hw_params,
+	.set_tdm_slot = cs35l33_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver cs35l33_dai = {
+		.name = "cs35l33-dai",
+		.id = 0,
+		.playback = {
+			.stream_name = "CS35L33 Playback",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = CS35L33_RATES,
+			.formats = CS35L33_FORMATS,
+		},
+		.capture = {
+			.stream_name = "CS35L33 Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = CS35L33_RATES,
+			.formats = CS35L33_FORMATS,
+		},
+		.ops = &cs35l33_ops,
+		.symmetric_rates = 1,
+};
+
+static int cs35l33_set_hg_data(struct snd_soc_component *component,
+			       struct cs35l33_pdata *pdata)
+{
+	struct cs35l33_hg *hg_config = &pdata->hg_config;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
+
+	if (hg_config->enable_hg_algo) {
+		regmap_update_bits(priv->regmap, CS35L33_HG_MEMLDO_CTL,
+			CS35L33_MEM_DEPTH_MASK,
+			hg_config->mem_depth << CS35L33_MEM_DEPTH_SHIFT);
+		regmap_write(priv->regmap, CS35L33_HG_REL_RATE,
+			hg_config->release_rate);
+		regmap_update_bits(priv->regmap, CS35L33_HG_HEAD,
+			CS35L33_HD_RM_MASK,
+			hg_config->hd_rm << CS35L33_HD_RM_SHIFT);
+		regmap_update_bits(priv->regmap, CS35L33_HG_MEMLDO_CTL,
+			CS35L33_LDO_THLD_MASK,
+			hg_config->ldo_thld << CS35L33_LDO_THLD_SHIFT);
+		regmap_update_bits(priv->regmap, CS35L33_HG_MEMLDO_CTL,
+			CS35L33_LDO_DISABLE_MASK,
+			hg_config->ldo_path_disable <<
+				CS35L33_LDO_DISABLE_SHIFT);
+		regmap_update_bits(priv->regmap, CS35L33_LDO_DEL,
+			CS35L33_LDO_ENTRY_DELAY_MASK,
+			hg_config->ldo_entry_delay <<
+				CS35L33_LDO_ENTRY_DELAY_SHIFT);
+		if (hg_config->vp_hg_auto) {
+			regmap_update_bits(priv->regmap, CS35L33_HG_EN,
+				CS35L33_VP_HG_AUTO_MASK,
+				CS35L33_VP_HG_AUTO_MASK);
+			snd_soc_dapm_add_routes(dapm, cs35l33_vphg_auto_route,
+				ARRAY_SIZE(cs35l33_vphg_auto_route));
+		}
+		regmap_update_bits(priv->regmap, CS35L33_HG_EN,
+			CS35L33_VP_HG_MASK,
+			hg_config->vp_hg << CS35L33_VP_HG_SHIFT);
+		regmap_update_bits(priv->regmap, CS35L33_LDO_DEL,
+			CS35L33_VP_HG_RATE_MASK,
+			hg_config->vp_hg_rate << CS35L33_VP_HG_RATE_SHIFT);
+		regmap_update_bits(priv->regmap, CS35L33_LDO_DEL,
+			CS35L33_VP_HG_VA_MASK,
+			hg_config->vp_hg_va << CS35L33_VP_HG_VA_SHIFT);
+		regmap_update_bits(priv->regmap, CS35L33_HG_EN,
+			CS35L33_CLASS_HG_EN_MASK, CS35L33_CLASS_HG_EN_MASK);
+	}
+	return 0;
+}
+
+static int cs35l33_set_bst_ipk(struct snd_soc_component *component, unsigned int bst)
+{
+	struct cs35l33_private *cs35l33 = snd_soc_component_get_drvdata(component);
+	int ret = 0, steps = 0;
+
+	/* Boost current in uA */
+	if (bst > 3600000 || bst < 1850000) {
+		dev_err(component->dev, "Invalid boost current %d\n", bst);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (bst % 15625) {
+		dev_err(component->dev, "Current not a multiple of 15625uA (%d)\n",
+			bst);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	while (bst > 1850000) {
+		bst -= 15625;
+		steps++;
+	}
+
+	regmap_write(cs35l33->regmap, CS35L33_BST_PEAK_CTL,
+		steps+0x70);
+
+err:
+	return ret;
+}
+
+static int cs35l33_probe(struct snd_soc_component *component)
+{
+	struct cs35l33_private *cs35l33 = snd_soc_component_get_drvdata(component);
+
+	cs35l33->component = component;
+	pm_runtime_get_sync(component->dev);
+
+	regmap_update_bits(cs35l33->regmap, CS35L33_PROTECT_CTL,
+		CS35L33_ALIVE_WD_DIS, 0x8);
+	regmap_update_bits(cs35l33->regmap, CS35L33_BST_CTL2,
+				CS35L33_ALIVE_WD_DIS2,
+				CS35L33_ALIVE_WD_DIS2);
+
+	/* Set Platform Data */
+	regmap_update_bits(cs35l33->regmap, CS35L33_BST_CTL1,
+		CS35L33_BST_CTL_MASK, cs35l33->pdata.boost_ctl);
+	regmap_update_bits(cs35l33->regmap, CS35L33_CLASSD_CTL,
+		CS35L33_AMP_DRV_SEL_MASK,
+		cs35l33->pdata.amp_drv_sel << CS35L33_AMP_DRV_SEL_SHIFT);
+
+	if (cs35l33->pdata.boost_ipk)
+		cs35l33_set_bst_ipk(component, cs35l33->pdata.boost_ipk);
+
+	if (cs35l33->enable_soft_ramp) {
+		snd_soc_component_update_bits(component, CS35L33_DAC_CTL,
+			CS35L33_DIGSFT, CS35L33_DIGSFT);
+		snd_soc_component_update_bits(component, CS35L33_DAC_CTL,
+			CS35L33_DSR_RATE, cs35l33->pdata.ramp_rate);
+	} else {
+		snd_soc_component_update_bits(component, CS35L33_DAC_CTL,
+			CS35L33_DIGSFT, 0);
+	}
+
+	/* update IMON scaling rate if different from default of 0x8 */
+	if (cs35l33->pdata.imon_adc_scale != 0x8)
+		snd_soc_component_update_bits(component, CS35L33_ADC_CTL,
+			CS35L33_IMON_SCALE, cs35l33->pdata.imon_adc_scale);
+
+	cs35l33_set_hg_data(component, &(cs35l33->pdata));
+
+	/*
+	 * unmask important interrupts that causes the chip to enter
+	 * speaker safe mode and hence deserves user attention
+	 */
+	regmap_update_bits(cs35l33->regmap, CS35L33_INT_MASK_1,
+		CS35L33_M_OTE | CS35L33_M_OTW | CS35L33_M_AMP_SHORT |
+		CS35L33_M_CAL_ERR, 0);
+
+	pm_runtime_put_sync(component->dev);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_cs35l33 = {
+	.probe			= cs35l33_probe,
+	.set_bias_level		= cs35l33_set_bias_level,
+	.set_sysclk		= cs35l33_component_set_sysclk,
+	.controls		= cs35l33_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs35l33_snd_controls),
+	.dapm_widgets		= cs35l33_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs35l33_dapm_widgets),
+	.dapm_routes		= cs35l33_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs35l33_audio_map),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config cs35l33_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = CS35L33_MAX_REGISTER,
+	.reg_defaults = cs35l33_reg,
+	.num_reg_defaults = ARRAY_SIZE(cs35l33_reg),
+	.volatile_reg = cs35l33_volatile_register,
+	.readable_reg = cs35l33_readable_register,
+	.writeable_reg = cs35l33_writeable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.use_single_rw = true,
+};
+
+static int __maybe_unused cs35l33_runtime_resume(struct device *dev)
+{
+	struct cs35l33_private *cs35l33 = dev_get_drvdata(dev);
+	int ret;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	gpiod_set_value_cansleep(cs35l33->reset_gpio, 0);
+
+	ret = regulator_bulk_enable(cs35l33->num_core_supplies,
+		cs35l33->core_supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable core supplies: %d\n", ret);
+		return ret;
+	}
+
+	regcache_cache_only(cs35l33->regmap, false);
+
+	gpiod_set_value_cansleep(cs35l33->reset_gpio, 1);
+
+	msleep(CS35L33_BOOT_DELAY);
+
+	ret = regcache_sync(cs35l33->regmap);
+	if (ret != 0) {
+		dev_err(dev, "Failed to restore register cache\n");
+		goto err;
+	}
+
+	return 0;
+
+err:
+	regcache_cache_only(cs35l33->regmap, true);
+	regulator_bulk_disable(cs35l33->num_core_supplies,
+		cs35l33->core_supplies);
+
+	return ret;
+}
+
+static int __maybe_unused cs35l33_runtime_suspend(struct device *dev)
+{
+	struct cs35l33_private *cs35l33 = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	/* redo the calibration in next power up */
+	cs35l33->amp_cal = false;
+
+	regcache_cache_only(cs35l33->regmap, true);
+	regcache_mark_dirty(cs35l33->regmap);
+	regulator_bulk_disable(cs35l33->num_core_supplies,
+		cs35l33->core_supplies);
+
+	return 0;
+}
+
+static const struct dev_pm_ops cs35l33_pm_ops = {
+	SET_RUNTIME_PM_OPS(cs35l33_runtime_suspend,
+			   cs35l33_runtime_resume,
+			   NULL)
+};
+
+static int cs35l33_get_hg_data(const struct device_node *np,
+			       struct cs35l33_pdata *pdata)
+{
+	struct device_node *hg;
+	struct cs35l33_hg *hg_config = &pdata->hg_config;
+	u32 val32;
+
+	hg = of_get_child_by_name(np, "cirrus,hg-algo");
+	hg_config->enable_hg_algo = hg ? true : false;
+
+	if (hg_config->enable_hg_algo) {
+		if (of_property_read_u32(hg, "cirrus,mem-depth", &val32) >= 0)
+			hg_config->mem_depth = val32;
+		if (of_property_read_u32(hg, "cirrus,release-rate",
+				&val32) >= 0)
+			hg_config->release_rate = val32;
+		if (of_property_read_u32(hg, "cirrus,ldo-thld", &val32) >= 0)
+			hg_config->ldo_thld = val32;
+		if (of_property_read_u32(hg, "cirrus,ldo-path-disable",
+				&val32) >= 0)
+			hg_config->ldo_path_disable = val32;
+		if (of_property_read_u32(hg, "cirrus,ldo-entry-delay",
+				&val32) >= 0)
+			hg_config->ldo_entry_delay = val32;
+
+		hg_config->vp_hg_auto = of_property_read_bool(hg,
+			"cirrus,vp-hg-auto");
+
+		if (of_property_read_u32(hg, "cirrus,vp-hg", &val32) >= 0)
+			hg_config->vp_hg = val32;
+		if (of_property_read_u32(hg, "cirrus,vp-hg-rate", &val32) >= 0)
+			hg_config->vp_hg_rate = val32;
+		if (of_property_read_u32(hg, "cirrus,vp-hg-va", &val32) >= 0)
+			hg_config->vp_hg_va = val32;
+	}
+
+	of_node_put(hg);
+
+	return 0;
+}
+
+static irqreturn_t cs35l33_irq_thread(int irq, void *data)
+{
+	struct cs35l33_private *cs35l33 = data;
+	struct snd_soc_component *component = cs35l33->component;
+	unsigned int sticky_val1, sticky_val2, current_val, mask1, mask2;
+
+	regmap_read(cs35l33->regmap, CS35L33_INT_STATUS_2,
+		&sticky_val2);
+	regmap_read(cs35l33->regmap, CS35L33_INT_STATUS_1,
+		&sticky_val1);
+	regmap_read(cs35l33->regmap, CS35L33_INT_MASK_2, &mask2);
+	regmap_read(cs35l33->regmap, CS35L33_INT_MASK_1, &mask1);
+
+	/* Check to see if the unmasked bits are active,
+	 *  if not then exit.
+	 */
+	if (!(sticky_val1 & ~mask1) && !(sticky_val2 & ~mask2))
+		return IRQ_NONE;
+
+	regmap_read(cs35l33->regmap, CS35L33_INT_STATUS_1,
+		&current_val);
+
+	/* handle the interrupts */
+
+	if (sticky_val1 & CS35L33_AMP_SHORT) {
+		dev_crit(component->dev, "Amp short error\n");
+		if (!(current_val & CS35L33_AMP_SHORT)) {
+			dev_dbg(component->dev,
+				"Amp short error release\n");
+			regmap_update_bits(cs35l33->regmap,
+				CS35L33_AMP_CTL,
+				CS35L33_AMP_SHORT_RLS, 0);
+			regmap_update_bits(cs35l33->regmap,
+				CS35L33_AMP_CTL,
+				CS35L33_AMP_SHORT_RLS,
+				CS35L33_AMP_SHORT_RLS);
+			regmap_update_bits(cs35l33->regmap,
+				CS35L33_AMP_CTL, CS35L33_AMP_SHORT_RLS,
+				0);
+		}
+	}
+
+	if (sticky_val1 & CS35L33_CAL_ERR) {
+		dev_err(component->dev, "Cal error\n");
+
+		/* redo the calibration in next power up */
+		cs35l33->amp_cal = false;
+
+		if (!(current_val & CS35L33_CAL_ERR)) {
+			dev_dbg(component->dev, "Cal error release\n");
+			regmap_update_bits(cs35l33->regmap,
+				CS35L33_AMP_CTL, CS35L33_CAL_ERR_RLS,
+				0);
+			regmap_update_bits(cs35l33->regmap,
+				CS35L33_AMP_CTL, CS35L33_CAL_ERR_RLS,
+				CS35L33_CAL_ERR_RLS);
+			regmap_update_bits(cs35l33->regmap,
+				CS35L33_AMP_CTL, CS35L33_CAL_ERR_RLS,
+				0);
+		}
+	}
+
+	if (sticky_val1 & CS35L33_OTE) {
+		dev_crit(component->dev, "Over temperature error\n");
+		if (!(current_val & CS35L33_OTE)) {
+			dev_dbg(component->dev,
+				"Over temperature error release\n");
+			regmap_update_bits(cs35l33->regmap,
+				CS35L33_AMP_CTL, CS35L33_OTE_RLS, 0);
+			regmap_update_bits(cs35l33->regmap,
+				CS35L33_AMP_CTL, CS35L33_OTE_RLS,
+				CS35L33_OTE_RLS);
+			regmap_update_bits(cs35l33->regmap,
+				CS35L33_AMP_CTL, CS35L33_OTE_RLS, 0);
+		}
+	}
+
+	if (sticky_val1 & CS35L33_OTW) {
+		dev_err(component->dev, "Over temperature warning\n");
+		if (!(current_val & CS35L33_OTW)) {
+			dev_dbg(component->dev,
+				"Over temperature warning release\n");
+			regmap_update_bits(cs35l33->regmap,
+				CS35L33_AMP_CTL, CS35L33_OTW_RLS, 0);
+			regmap_update_bits(cs35l33->regmap,
+				CS35L33_AMP_CTL, CS35L33_OTW_RLS,
+				CS35L33_OTW_RLS);
+			regmap_update_bits(cs35l33->regmap,
+				CS35L33_AMP_CTL, CS35L33_OTW_RLS, 0);
+		}
+	}
+	if (CS35L33_ALIVE_ERR & sticky_val1)
+		dev_err(component->dev, "ERROR: ADSPCLK Interrupt\n");
+
+	if (CS35L33_MCLK_ERR & sticky_val1)
+		dev_err(component->dev, "ERROR: MCLK Interrupt\n");
+
+	if (CS35L33_VMON_OVFL & sticky_val2)
+		dev_err(component->dev,
+			"ERROR: VMON Overflow Interrupt\n");
+
+	if (CS35L33_IMON_OVFL & sticky_val2)
+		dev_err(component->dev,
+			"ERROR: IMON Overflow Interrupt\n");
+
+	if (CS35L33_VPMON_OVFL & sticky_val2)
+		dev_err(component->dev,
+			"ERROR: VPMON Overflow Interrupt\n");
+
+	return IRQ_HANDLED;
+}
+
+static const char * const cs35l33_core_supplies[] = {
+	"VA",
+	"VP",
+};
+
+static int cs35l33_of_get_pdata(struct device *dev,
+				struct cs35l33_private *cs35l33)
+{
+	struct device_node *np = dev->of_node;
+	struct cs35l33_pdata *pdata = &cs35l33->pdata;
+	u32 val32;
+
+	if (!np)
+		return 0;
+
+	if (of_property_read_u32(np, "cirrus,boost-ctl", &val32) >= 0) {
+		pdata->boost_ctl = val32;
+		pdata->amp_drv_sel = 1;
+	}
+
+	if (of_property_read_u32(np, "cirrus,ramp-rate", &val32) >= 0) {
+		pdata->ramp_rate = val32;
+		cs35l33->enable_soft_ramp = true;
+	}
+
+	if (of_property_read_u32(np, "cirrus,boost-ipk", &val32) >= 0)
+		pdata->boost_ipk = val32;
+
+	if (of_property_read_u32(np, "cirrus,imon-adc-scale", &val32) >= 0) {
+		if ((val32 == 0x0) || (val32 == 0x7) || (val32 == 0x6))
+			pdata->imon_adc_scale = val32;
+		else
+			/* use default value */
+			pdata->imon_adc_scale = 0x8;
+	} else {
+		/* use default value */
+		pdata->imon_adc_scale = 0x8;
+	}
+
+	cs35l33_get_hg_data(np, pdata);
+
+	return 0;
+}
+
+static int cs35l33_i2c_probe(struct i2c_client *i2c_client,
+				       const struct i2c_device_id *id)
+{
+	struct cs35l33_private *cs35l33;
+	struct cs35l33_pdata *pdata = dev_get_platdata(&i2c_client->dev);
+	int ret, devid, i;
+	unsigned int reg;
+
+	cs35l33 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l33_private),
+			       GFP_KERNEL);
+	if (!cs35l33)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c_client, cs35l33);
+	cs35l33->regmap = devm_regmap_init_i2c(i2c_client, &cs35l33_regmap);
+	if (IS_ERR(cs35l33->regmap)) {
+		ret = PTR_ERR(cs35l33->regmap);
+		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	regcache_cache_only(cs35l33->regmap, true);
+
+	for (i = 0; i < ARRAY_SIZE(cs35l33_core_supplies); i++)
+		cs35l33->core_supplies[i].supply
+			= cs35l33_core_supplies[i];
+	cs35l33->num_core_supplies = ARRAY_SIZE(cs35l33_core_supplies);
+
+	ret = devm_regulator_bulk_get(&i2c_client->dev,
+			cs35l33->num_core_supplies,
+			cs35l33->core_supplies);
+	if (ret != 0) {
+		dev_err(&i2c_client->dev,
+			"Failed to request core supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (pdata) {
+		cs35l33->pdata = *pdata;
+	} else {
+		cs35l33_of_get_pdata(&i2c_client->dev, cs35l33);
+		pdata = &cs35l33->pdata;
+	}
+
+	ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL,
+			cs35l33_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+			"cs35l33", cs35l33);
+	if (ret != 0)
+		dev_warn(&i2c_client->dev, "Failed to request IRQ: %d\n", ret);
+
+	/* We could issue !RST or skip it based on AMP topology */
+	cs35l33->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+			"reset-gpios", GPIOD_OUT_HIGH);
+	if (IS_ERR(cs35l33->reset_gpio)) {
+		dev_err(&i2c_client->dev, "%s ERROR: Can't get reset GPIO\n",
+			__func__);
+		return PTR_ERR(cs35l33->reset_gpio);
+	}
+
+	ret = regulator_bulk_enable(cs35l33->num_core_supplies,
+					cs35l33->core_supplies);
+	if (ret != 0) {
+		dev_err(&i2c_client->dev,
+			"Failed to enable core supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	gpiod_set_value_cansleep(cs35l33->reset_gpio, 1);
+
+	msleep(CS35L33_BOOT_DELAY);
+	regcache_cache_only(cs35l33->regmap, false);
+
+	/* initialize codec */
+	ret = regmap_read(cs35l33->regmap, CS35L33_DEVID_AB, &reg);
+	devid = (reg & 0xFF) << 12;
+	ret = regmap_read(cs35l33->regmap, CS35L33_DEVID_CD, &reg);
+	devid |= (reg & 0xFF) << 4;
+	ret = regmap_read(cs35l33->regmap, CS35L33_DEVID_E, &reg);
+	devid |= (reg & 0xF0) >> 4;
+
+	if (devid != CS35L33_CHIP_ID) {
+		dev_err(&i2c_client->dev,
+			"CS35L33 Device ID (%X). Expected ID %X\n",
+			devid, CS35L33_CHIP_ID);
+		goto err_enable;
+	}
+
+	ret = regmap_read(cs35l33->regmap, CS35L33_REV_ID, &reg);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+		goto err_enable;
+	}
+
+	dev_info(&i2c_client->dev,
+		 "Cirrus Logic CS35L33, Revision: %02X\n", reg & 0xFF);
+
+	ret = regmap_register_patch(cs35l33->regmap,
+			cs35l33_patch, ARRAY_SIZE(cs35l33_patch));
+	if (ret < 0) {
+		dev_err(&i2c_client->dev,
+			"Error in applying regmap patch: %d\n", ret);
+		goto err_enable;
+	}
+
+	/* disable mclk and tdm */
+	regmap_update_bits(cs35l33->regmap, CS35L33_CLK_CTL,
+		CS35L33_MCLKDIS | CS35L33_SDOUT_3ST_TDM,
+		CS35L33_MCLKDIS | CS35L33_SDOUT_3ST_TDM);
+
+	pm_runtime_set_autosuspend_delay(&i2c_client->dev, 100);
+	pm_runtime_use_autosuspend(&i2c_client->dev);
+	pm_runtime_set_active(&i2c_client->dev);
+	pm_runtime_enable(&i2c_client->dev);
+
+	ret = devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_dev_cs35l33, &cs35l33_dai, 1);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "%s: Register component failed\n",
+			__func__);
+		goto err_enable;
+	}
+
+	return 0;
+
+err_enable:
+	regulator_bulk_disable(cs35l33->num_core_supplies,
+			       cs35l33->core_supplies);
+
+	return ret;
+}
+
+static int cs35l33_i2c_remove(struct i2c_client *client)
+{
+	struct cs35l33_private *cs35l33 = i2c_get_clientdata(client);
+
+	gpiod_set_value_cansleep(cs35l33->reset_gpio, 0);
+
+	pm_runtime_disable(&client->dev);
+	regulator_bulk_disable(cs35l33->num_core_supplies,
+		cs35l33->core_supplies);
+
+	return 0;
+}
+
+static const struct of_device_id cs35l33_of_match[] = {
+	{ .compatible = "cirrus,cs35l33", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cs35l33_of_match);
+
+static const struct i2c_device_id cs35l33_id[] = {
+	{"cs35l33", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs35l33_id);
+
+static struct i2c_driver cs35l33_i2c_driver = {
+	.driver = {
+		.name = "cs35l33",
+		.pm = &cs35l33_pm_ops,
+		.of_match_table = cs35l33_of_match,
+
+		},
+	.id_table = cs35l33_id,
+	.probe = cs35l33_i2c_probe,
+	.remove = cs35l33_i2c_remove,
+
+};
+module_i2c_driver(cs35l33_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS35L33 driver");
+MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paul.handrigan@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l33.h b/sound/soc/codecs/cs35l33.h
new file mode 100644
index 0000000..c045737
--- /dev/null
+++ b/sound/soc/codecs/cs35l33.h
@@ -0,0 +1,221 @@
+/*
+ * cs35l33.h -- CS35L33 ALSA SoC audio driver
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: Paul Handrigan <paul.handrigan@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CS35L33_H__
+#define __CS35L33_H__
+
+#define CS35L33_CHIP_ID		0x00035A33
+#define CS35L33_DEVID_AB	0x01	/* Device ID A & B [RO] */
+#define CS35L33_DEVID_CD	0x02	/* Device ID C & D [RO] */
+#define CS35L33_DEVID_E		0x03	/* Device ID E [RO] */
+#define CS35L33_FAB_ID		0x04	/* Fab ID [RO] */
+#define CS35L33_REV_ID		0x05	/* Revision ID [RO] */
+#define CS35L33_PWRCTL1		0x06	/* Power Ctl 1 */
+#define CS35L33_PWRCTL2		0x07	/* Power Ctl 2 */
+#define CS35L33_CLK_CTL		0x08	/* Clock Ctl */
+#define CS35L33_BST_PEAK_CTL	0x09	/* Max Current for Boost */
+#define CS35L33_PROTECT_CTL	0x0A	/* Amp Protection Parameters */
+#define CS35L33_BST_CTL1	0x0B	/* Boost Converter CTL1 */
+#define CS35L33_BST_CTL2	0x0C	/* Boost Converter CTL2 */
+#define CS35L33_ADSP_CTL	0x0D	/* Serial Port Control */
+#define CS35L33_ADC_CTL		0x0E	/* ADC Control */
+#define CS35L33_DAC_CTL		0x0F	/* DAC Control */
+#define CS35L33_DIG_VOL_CTL	0x10	/* Digital Volume CTL */
+#define CS35L33_CLASSD_CTL	0x11	/* Class D Amp CTL */
+#define CS35L33_AMP_CTL		0x12	/* Amp Gain/Protecton Release CTL */
+#define CS35L33_INT_MASK_1	0x13	/* Interrupt Mask 1 */
+#define CS35L33_INT_MASK_2	0x14	/* Interrupt Mask 2 */
+#define CS35L33_INT_STATUS_1	0x15	/* Interrupt Status 1 [RO] */
+#define CS35L33_INT_STATUS_2	0x16	/* Interrupt Status 2 [RO] */
+#define CS35L33_DIAG_LOCK	0x17	/* Diagnostic Mode Register Lock */
+#define CS35L33_DIAG_CTRL_1	0x18	/* Diagnostic Mode Register Control */
+#define CS35L33_DIAG_CTRL_2	0x19	/* Diagnostic Mode Register Control 2 */
+#define CS35L33_HG_MEMLDO_CTL	0x23	/* H/G Memory/LDO CTL */
+#define CS35L33_HG_REL_RATE	0x24	/* H/G Release Rate */
+#define CS35L33_LDO_DEL		0x25	/* LDO Entry Delay/VPhg Control 1 */
+#define CS35L33_HG_HEAD		0x29	/* H/G Headroom */
+#define CS35L33_HG_EN		0x2A	/* H/G Enable/VPhg CNT2 */
+#define CS35L33_TX_VMON		0x2D	/* TDM TX Control 1 (VMON) */
+#define CS35L33_TX_IMON		0x2E	/* TDM TX Control 2 (IMON) */
+#define CS35L33_TX_VPMON	0x2F	/* TDM TX Control 3 (VPMON) */
+#define CS35L33_TX_VBSTMON	0x30	/* TDM TX Control 4 (VBSTMON) */
+#define CS35L33_TX_FLAG		0x31	/* TDM TX Control 5 (FLAG) */
+#define CS35L33_TX_EN1		0x32	/* TDM TX Enable 1 */
+#define CS35L33_TX_EN2		0x33	/* TDM TX Enable 2 */
+#define CS35L33_TX_EN3		0x34	/* TDM TX Enable 3 */
+#define CS35L33_TX_EN4		0x35	/* TDM TX Enable 4 */
+#define CS35L33_RX_AUD		0x36	/* TDM RX Control 1 */
+#define CS35L33_RX_SPLY		0x37	/* TDM RX Control 2 */
+#define CS35L33_RX_ALIVE	0x38	/* TDM RX Control 3 */
+#define CS35L33_BST_CTL4	0x39	/* Boost Converter Control 4 */
+#define CS35L33_HG_STATUS	0x3F	/* H/G Status */
+#define CS35L33_MAX_REGISTER	0x59
+
+#define CS35L33_MCLK_5644	5644800
+#define CS35L33_MCLK_6144	6144000
+#define CS35L33_MCLK_6		6000000
+#define CS35L33_MCLK_11289	11289600
+#define CS35L33_MCLK_12		12000000
+#define CS35L33_MCLK_12288	12288000
+
+/* CS35L33_PWRCTL1 */
+#define CS35L33_PDN_AMP			(1 << 7)
+#define CS35L33_PDN_BST			(1 << 2)
+#define CS35L33_PDN_ALL			1
+
+/* CS35L33_PWRCTL2 */
+#define CS35L33_PDN_VMON_SHIFT		7
+#define CS35L33_PDN_VMON		(1 << CS35L33_PDN_VMON_SHIFT)
+#define CS35L33_PDN_IMON_SHIFT		6
+#define CS35L33_PDN_IMON		(1 << CS35L33_PDN_IMON_SHIFT)
+#define CS35L33_PDN_VPMON_SHIFT		5
+#define CS35L33_PDN_VPMON		(1 << CS35L33_PDN_VPMON_SHIFT)
+#define CS35L33_PDN_VBSTMON_SHIFT	4
+#define CS35L33_PDN_VBSTMON		(1 << CS35L33_PDN_VBSTMON_SHIFT)
+#define CS35L33_SDOUT_3ST_I2S_SHIFT	3
+#define CS35L33_SDOUT_3ST_I2S		(1 << CS35L33_SDOUT_3ST_I2S_SHIFT)
+#define CS35L33_PDN_SDIN_SHIFT		2
+#define CS35L33_PDN_SDIN		(1 << CS35L33_PDN_SDIN_SHIFT)
+#define CS35L33_PDN_TDM_SHIFT		1
+#define CS35L33_PDN_TDM			(1 << CS35L33_PDN_TDM_SHIFT)
+
+/* CS35L33_CLK_CTL */
+#define CS35L33_MCLKDIS			(1 << 7)
+#define CS35L33_MCLKDIV2		(1 << 6)
+#define CS35L33_SDOUT_3ST_TDM		(1 << 5)
+#define CS35L33_INT_FS_RATE		(1 << 4)
+#define CS35L33_ADSP_FS			0xF
+
+/* CS35L33_PROTECT_CTL */
+#define CS35L33_ALIVE_WD_DIS		(3 << 2)
+
+/* CS35L33_BST_CTL1 */
+#define CS35L33_BST_CTL_SRC		(1 << 6)
+#define CS35L33_BST_CTL_SHIFT		(1 << 5)
+#define CS35L33_BST_CTL_MASK		0x3F
+
+/* CS35L33_BST_CTL2 */
+#define CS35L33_TDM_WD_SEL		(1 << 4)
+#define CS35L33_ALIVE_WD_DIS2		(1 << 3)
+#define CS35L33_VBST_SR_STEP		0x3
+
+/* CS35L33_ADSP_CTL */
+#define CS35L33_ADSP_DRIVE		(1 << 7)
+#define CS35L33_MS_MASK			(1 << 6)
+#define CS35L33_SDIN_LOC		(3 << 4)
+#define CS35L33_ALIVE_RATE		0x3
+
+/* CS35L33_ADC_CTL */
+#define CS35L33_INV_VMON		(1 << 7)
+#define CS35L33_INV_IMON		(1 << 6)
+#define CS35L33_ADC_NOTCH_DIS		(1 << 5)
+#define CS35L33_IMON_SCALE		0xF
+
+/* CS35L33_DAC_CTL */
+#define CS35L33_INV_DAC			(1 << 7)
+#define CS35L33_DAC_NOTCH_DIS		(1 << 5)
+#define CS35L33_DIGSFT			(1 << 4)
+#define CS35L33_DSR_RATE		0xF
+
+/* CS35L33_CLASSD_CTL */
+#define CS35L33_AMP_SD			(1 << 6)
+#define CS35L33_AMP_DRV_SEL_SRC		(1 << 5)
+#define CS35L33_AMP_DRV_SEL_MASK	0x10
+#define CS35L33_AMP_DRV_SEL_SHIFT	4
+#define CS35L33_AMP_CAL			(1 << 3)
+#define CS35L33_GAIN_CHG_ZC_MASK	0x04
+#define CS35L33_GAIN_CHG_ZC_SHIFT	2
+#define CS35L33_CLASS_D_CTL_MASK	0x3F
+
+/* CS35L33_AMP_CTL */
+#define CS35L33_AMP_GAIN		0xF0
+#define CS35L33_CAL_ERR_RLS		(1 << 3)
+#define CS35L33_AMP_SHORT_RLS		(1 << 2)
+#define CS35L33_OTW_RLS			(1 << 1)
+#define CS35L33_OTE_RLS			1
+
+/* CS35L33_INT_MASK_1 */
+#define CS35L33_M_CAL_ERR_SHIFT		6
+#define CS35L33_M_CAL_ERR		(1 << CS35L33_M_CAL_ERR_SHIFT)
+#define CS35L33_M_ALIVE_ERR_SHIFT	5
+#define CS35L33_M_ALIVE_ERR		(1 << CS35L33_M_ALIVE_ERR_SHIFT)
+#define CS35L33_M_AMP_SHORT_SHIFT	2
+#define CS35L33_M_AMP_SHORT		(1 << CS35L33_M_AMP_SHORT_SHIFT)
+#define CS35L33_M_OTW_SHIFT		1
+#define CS35L33_M_OTW			(1 << CS35L33_M_OTW_SHIFT)
+#define CS35L33_M_OTE_SHIFT		0
+#define CS35L33_M_OTE			(1 << CS35L33_M_OTE_SHIFT)
+
+/* CS35L33_INT_STATUS_1 */
+#define CS35L33_CAL_ERR			(1 << 6)
+#define CS35L33_ALIVE_ERR		(1 << 5)
+#define CS35L33_ADSPCLK_ERR		(1 << 4)
+#define CS35L33_MCLK_ERR		(1 << 3)
+#define CS35L33_AMP_SHORT		(1 << 2)
+#define CS35L33_OTW			(1 << 1)
+#define CS35L33_OTE			(1 << 0)
+
+/* CS35L33_INT_STATUS_2 */
+#define CS35L33_VMON_OVFL		(1 << 7)
+#define CS35L33_IMON_OVFL		(1 << 6)
+#define CS35L33_VPMON_OVFL		(1 << 5)
+#define CS35L33_VBSTMON_OVFL		(1 << 4)
+#define CS35L33_PDN_DONE		1
+
+/* CS35L33_BST_CTL4 */
+#define CS35L33_BST_RGS			0x70
+#define CS35L33_BST_COEFF3		0xF
+
+/* CS35L33_HG_MEMLDO_CTL */
+#define CS35L33_MEM_DEPTH_SHIFT		5
+#define CS35L33_MEM_DEPTH_MASK		(0x3 << CS35L33_MEM_DEPTH_SHIFT)
+#define CS35L33_LDO_THLD_SHIFT		1
+#define CS35L33_LDO_THLD_MASK		(0xF << CS35L33_LDO_THLD_SHIFT)
+#define CS35L33_LDO_DISABLE_SHIFT	0
+#define CS35L33_LDO_DISABLE_MASK	(0x1 << CS35L33_LDO_DISABLE_SHIFT)
+
+/* CS35L33_LDO_DEL */
+#define CS35L33_VP_HG_VA_SHIFT		5
+#define CS35L33_VP_HG_VA_MASK		(0x7 << CS35L33_VP_HG_VA_SHIFT)
+#define CS35L33_LDO_ENTRY_DELAY_SHIFT	2
+#define CS35L33_LDO_ENTRY_DELAY_MASK	(0x7 << CS35L33_LDO_ENTRY_DELAY_SHIFT)
+#define CS35L33_VP_HG_RATE_SHIFT	0
+#define CS35L33_VP_HG_RATE_MASK		(0x3 << CS35L33_VP_HG_RATE_SHIFT)
+
+/* CS35L33_HG_HEAD */
+#define CS35L33_HD_RM_SHIFT		0
+#define CS35L33_HD_RM_MASK		(0x7F << CS35L33_HD_RM_SHIFT)
+
+/* CS35L33_HG_EN */
+#define CS35L33_CLASS_HG_ENA_SHIFT	7
+#define CS35L33_CLASS_HG_EN_MASK	(0x1 << CS35L33_CLASS_HG_ENA_SHIFT)
+#define CS35L33_VP_HG_AUTO_SHIFT	6
+#define CS35L33_VP_HG_AUTO_MASK		(0x1 << 6)
+#define CS35L33_VP_HG_SHIFT		0
+#define CS35L33_VP_HG_MASK		(0x1F << CS35L33_VP_HG_SHIFT)
+
+#define CS35L33_RATES (SNDRV_PCM_RATE_8000_48000)
+#define CS35L33_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE)
+
+/* CS35L33_{RX,TX}_X */
+#define CS35L33_X_STATE_SHIFT		7
+#define CS35L33_X_STATE			(1 << CS35L33_X_STATE_SHIFT)
+#define CS35L33_X_LOC_SHIFT		0
+#define CS35L33_X_LOC			(0x1F << CS35L33_X_LOC_SHIFT)
+
+/* CS35L33_RX_AUD */
+#define CS35L33_AUDIN_RX_DEPTH_SHIFT	5
+#define CS35L33_AUDIN_RX_DEPTH		(0x7 << CS35L33_AUDIN_RX_DEPTH_SHIFT)
+
+#endif
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
new file mode 100644
index 0000000..5063c05
--- /dev/null
+++ b/sound/soc/codecs/cs35l34.c
@@ -0,0 +1,1242 @@
+/*
+ * cs35l34.c -- CS35l34 ALSA SoC audio driver
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: Paul Handrigan <Paul.Handrigan@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/cs35l34.h>
+
+#include "cs35l34.h"
+
+#define PDN_DONE_ATTEMPTS 10
+#define CS35L34_START_DELAY 50
+
+struct  cs35l34_private {
+	struct snd_soc_component *component;
+	struct cs35l34_platform_data pdata;
+	struct regmap *regmap;
+	struct regulator_bulk_data core_supplies[2];
+	int num_core_supplies;
+	int mclk_int;
+	bool tdm_mode;
+	struct gpio_desc *reset_gpio;	/* Active-low reset GPIO */
+};
+
+static const struct reg_default cs35l34_reg[] = {
+	{CS35L34_PWRCTL1, 0x01},
+	{CS35L34_PWRCTL2, 0x19},
+	{CS35L34_PWRCTL3, 0x01},
+	{CS35L34_ADSP_CLK_CTL, 0x08},
+	{CS35L34_MCLK_CTL, 0x11},
+	{CS35L34_AMP_INP_DRV_CTL, 0x01},
+	{CS35L34_AMP_DIG_VOL_CTL, 0x12},
+	{CS35L34_AMP_DIG_VOL, 0x00},
+	{CS35L34_AMP_ANLG_GAIN_CTL, 0x0F},
+	{CS35L34_PROTECT_CTL, 0x06},
+	{CS35L34_AMP_KEEP_ALIVE_CTL, 0x04},
+	{CS35L34_BST_CVTR_V_CTL, 0x00},
+	{CS35L34_BST_PEAK_I, 0x10},
+	{CS35L34_BST_RAMP_CTL, 0x87},
+	{CS35L34_BST_CONV_COEF_1, 0x24},
+	{CS35L34_BST_CONV_COEF_2, 0x24},
+	{CS35L34_BST_CONV_SLOPE_COMP, 0x4E},
+	{CS35L34_BST_CONV_SW_FREQ, 0x08},
+	{CS35L34_CLASS_H_CTL, 0x0D},
+	{CS35L34_CLASS_H_HEADRM_CTL, 0x0D},
+	{CS35L34_CLASS_H_RELEASE_RATE, 0x08},
+	{CS35L34_CLASS_H_FET_DRIVE_CTL, 0x41},
+	{CS35L34_CLASS_H_STATUS, 0x05},
+	{CS35L34_VPBR_CTL, 0x0A},
+	{CS35L34_VPBR_VOL_CTL, 0x90},
+	{CS35L34_VPBR_TIMING_CTL, 0x6A},
+	{CS35L34_PRED_MAX_ATTEN_SPK_LOAD, 0x95},
+	{CS35L34_PRED_BROWNOUT_THRESH, 0x1C},
+	{CS35L34_PRED_BROWNOUT_VOL_CTL, 0x00},
+	{CS35L34_PRED_BROWNOUT_RATE_CTL, 0x10},
+	{CS35L34_PRED_WAIT_CTL, 0x10},
+	{CS35L34_PRED_ZVP_INIT_IMP_CTL, 0x08},
+	{CS35L34_PRED_MAN_SAFE_VPI_CTL, 0x80},
+	{CS35L34_VPBR_ATTEN_STATUS, 0x00},
+	{CS35L34_PRED_BRWNOUT_ATT_STATUS, 0x00},
+	{CS35L34_SPKR_MON_CTL, 0xC6},
+	{CS35L34_ADSP_I2S_CTL, 0x00},
+	{CS35L34_ADSP_TDM_CTL, 0x00},
+	{CS35L34_TDM_TX_CTL_1_VMON, 0x00},
+	{CS35L34_TDM_TX_CTL_2_IMON, 0x04},
+	{CS35L34_TDM_TX_CTL_3_VPMON, 0x03},
+	{CS35L34_TDM_TX_CTL_4_VBSTMON, 0x07},
+	{CS35L34_TDM_TX_CTL_5_FLAG1, 0x08},
+	{CS35L34_TDM_TX_CTL_6_FLAG2, 0x09},
+	{CS35L34_TDM_TX_SLOT_EN_1, 0x00},
+	{CS35L34_TDM_TX_SLOT_EN_2, 0x00},
+	{CS35L34_TDM_TX_SLOT_EN_3, 0x00},
+	{CS35L34_TDM_TX_SLOT_EN_4, 0x00},
+	{CS35L34_TDM_RX_CTL_1_AUDIN, 0x40},
+	{CS35L34_TDM_RX_CTL_3_ALIVE, 0x04},
+	{CS35L34_MULT_DEV_SYNCH1, 0x00},
+	{CS35L34_MULT_DEV_SYNCH2, 0x80},
+	{CS35L34_PROT_RELEASE_CTL, 0x00},
+	{CS35L34_DIAG_MODE_REG_LOCK, 0x00},
+	{CS35L34_DIAG_MODE_CTL_1, 0x00},
+	{CS35L34_DIAG_MODE_CTL_2, 0x00},
+	{CS35L34_INT_MASK_1, 0xFF},
+	{CS35L34_INT_MASK_2, 0xFF},
+	{CS35L34_INT_MASK_3, 0xFF},
+	{CS35L34_INT_MASK_4, 0xFF},
+	{CS35L34_INT_STATUS_1, 0x30},
+	{CS35L34_INT_STATUS_2, 0x05},
+	{CS35L34_INT_STATUS_3, 0x00},
+	{CS35L34_INT_STATUS_4, 0x00},
+	{CS35L34_OTP_TRIM_STATUS, 0x00},
+};
+
+static bool cs35l34_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS35L34_DEVID_AB:
+	case CS35L34_DEVID_CD:
+	case CS35L34_DEVID_E:
+	case CS35L34_FAB_ID:
+	case CS35L34_REV_ID:
+	case CS35L34_INT_STATUS_1:
+	case CS35L34_INT_STATUS_2:
+	case CS35L34_INT_STATUS_3:
+	case CS35L34_INT_STATUS_4:
+	case CS35L34_CLASS_H_STATUS:
+	case CS35L34_VPBR_ATTEN_STATUS:
+	case CS35L34_OTP_TRIM_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs35l34_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case	CS35L34_DEVID_AB:
+	case	CS35L34_DEVID_CD:
+	case	CS35L34_DEVID_E:
+	case	CS35L34_FAB_ID:
+	case	CS35L34_REV_ID:
+	case	CS35L34_PWRCTL1:
+	case	CS35L34_PWRCTL2:
+	case	CS35L34_PWRCTL3:
+	case	CS35L34_ADSP_CLK_CTL:
+	case	CS35L34_MCLK_CTL:
+	case	CS35L34_AMP_INP_DRV_CTL:
+	case	CS35L34_AMP_DIG_VOL_CTL:
+	case	CS35L34_AMP_DIG_VOL:
+	case	CS35L34_AMP_ANLG_GAIN_CTL:
+	case	CS35L34_PROTECT_CTL:
+	case	CS35L34_AMP_KEEP_ALIVE_CTL:
+	case	CS35L34_BST_CVTR_V_CTL:
+	case	CS35L34_BST_PEAK_I:
+	case	CS35L34_BST_RAMP_CTL:
+	case	CS35L34_BST_CONV_COEF_1:
+	case	CS35L34_BST_CONV_COEF_2:
+	case	CS35L34_BST_CONV_SLOPE_COMP:
+	case	CS35L34_BST_CONV_SW_FREQ:
+	case	CS35L34_CLASS_H_CTL:
+	case	CS35L34_CLASS_H_HEADRM_CTL:
+	case	CS35L34_CLASS_H_RELEASE_RATE:
+	case	CS35L34_CLASS_H_FET_DRIVE_CTL:
+	case	CS35L34_CLASS_H_STATUS:
+	case	CS35L34_VPBR_CTL:
+	case	CS35L34_VPBR_VOL_CTL:
+	case	CS35L34_VPBR_TIMING_CTL:
+	case	CS35L34_PRED_MAX_ATTEN_SPK_LOAD:
+	case	CS35L34_PRED_BROWNOUT_THRESH:
+	case	CS35L34_PRED_BROWNOUT_VOL_CTL:
+	case	CS35L34_PRED_BROWNOUT_RATE_CTL:
+	case	CS35L34_PRED_WAIT_CTL:
+	case	CS35L34_PRED_ZVP_INIT_IMP_CTL:
+	case	CS35L34_PRED_MAN_SAFE_VPI_CTL:
+	case	CS35L34_VPBR_ATTEN_STATUS:
+	case	CS35L34_PRED_BRWNOUT_ATT_STATUS:
+	case	CS35L34_SPKR_MON_CTL:
+	case	CS35L34_ADSP_I2S_CTL:
+	case	CS35L34_ADSP_TDM_CTL:
+	case	CS35L34_TDM_TX_CTL_1_VMON:
+	case	CS35L34_TDM_TX_CTL_2_IMON:
+	case	CS35L34_TDM_TX_CTL_3_VPMON:
+	case	CS35L34_TDM_TX_CTL_4_VBSTMON:
+	case	CS35L34_TDM_TX_CTL_5_FLAG1:
+	case	CS35L34_TDM_TX_CTL_6_FLAG2:
+	case	CS35L34_TDM_TX_SLOT_EN_1:
+	case	CS35L34_TDM_TX_SLOT_EN_2:
+	case	CS35L34_TDM_TX_SLOT_EN_3:
+	case	CS35L34_TDM_TX_SLOT_EN_4:
+	case	CS35L34_TDM_RX_CTL_1_AUDIN:
+	case	CS35L34_TDM_RX_CTL_3_ALIVE:
+	case	CS35L34_MULT_DEV_SYNCH1:
+	case	CS35L34_MULT_DEV_SYNCH2:
+	case	CS35L34_PROT_RELEASE_CTL:
+	case	CS35L34_DIAG_MODE_REG_LOCK:
+	case	CS35L34_DIAG_MODE_CTL_1:
+	case	CS35L34_DIAG_MODE_CTL_2:
+	case	CS35L34_INT_MASK_1:
+	case	CS35L34_INT_MASK_2:
+	case	CS35L34_INT_MASK_3:
+	case	CS35L34_INT_MASK_4:
+	case	CS35L34_INT_STATUS_1:
+	case	CS35L34_INT_STATUS_2:
+	case	CS35L34_INT_STATUS_3:
+	case	CS35L34_INT_STATUS_4:
+	case	CS35L34_OTP_TRIM_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs35l34_precious_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS35L34_INT_STATUS_1:
+	case CS35L34_INT_STATUS_2:
+	case CS35L34_INT_STATUS_3:
+	case CS35L34_INT_STATUS_4:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int cs35l34_sdin_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l34_private *priv = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (priv->tdm_mode)
+			regmap_update_bits(priv->regmap, CS35L34_PWRCTL3,
+						CS35L34_PDN_TDM, 0x00);
+
+		ret = regmap_update_bits(priv->regmap, CS35L34_PWRCTL1,
+						CS35L34_PDN_ALL, 0);
+		if (ret < 0) {
+			dev_err(component->dev, "Cannot set Power bits %d\n", ret);
+			return ret;
+		}
+		usleep_range(5000, 5100);
+	break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (priv->tdm_mode) {
+			regmap_update_bits(priv->regmap, CS35L34_PWRCTL3,
+					CS35L34_PDN_TDM, CS35L34_PDN_TDM);
+		}
+		ret = regmap_update_bits(priv->regmap, CS35L34_PWRCTL1,
+					CS35L34_PDN_ALL, CS35L34_PDN_ALL);
+	break;
+	default:
+		pr_err("Invalid event = 0x%x\n", event);
+	}
+	return 0;
+}
+
+static int cs35l34_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+				unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs35l34_private *priv = snd_soc_component_get_drvdata(component);
+	unsigned int reg, bit_pos;
+	int slot, slot_num;
+
+	if (slot_width != 8)
+		return -EINVAL;
+
+	priv->tdm_mode = true;
+	/* scan rx_mask for aud slot */
+	slot = ffs(rx_mask) - 1;
+	if (slot >= 0)
+		snd_soc_component_update_bits(component, CS35L34_TDM_RX_CTL_1_AUDIN,
+					CS35L34_X_LOC, slot);
+
+	/* scan tx_mask: vmon(2 slots); imon (2 slots); vpmon (1 slot)
+	 * vbstmon (1 slot)
+	 */
+	slot = ffs(tx_mask) - 1;
+	slot_num = 0;
+
+	/* disable vpmon/vbstmon: enable later if set in tx_mask */
+	snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_3_VPMON,
+				CS35L34_X_STATE | CS35L34_X_LOC,
+				CS35L34_X_STATE | CS35L34_X_LOC);
+	snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_4_VBSTMON,
+				CS35L34_X_STATE | CS35L34_X_LOC,
+				CS35L34_X_STATE | CS35L34_X_LOC);
+
+	/* disconnect {vp,vbst}_mon routes: eanble later if set in tx_mask*/
+	while (slot >= 0) {
+		/* configure VMON_TX_LOC */
+		if (slot_num == 0)
+			snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_1_VMON,
+					CS35L34_X_STATE | CS35L34_X_LOC, slot);
+
+		/* configure IMON_TX_LOC */
+		if (slot_num == 4) {
+			snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_2_IMON,
+					CS35L34_X_STATE | CS35L34_X_LOC, slot);
+		}
+		/* configure VPMON_TX_LOC */
+		if (slot_num == 3) {
+			snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_3_VPMON,
+					CS35L34_X_STATE | CS35L34_X_LOC, slot);
+		}
+		/* configure VBSTMON_TX_LOC */
+		if (slot_num == 7) {
+			snd_soc_component_update_bits(component,
+				CS35L34_TDM_TX_CTL_4_VBSTMON,
+				CS35L34_X_STATE | CS35L34_X_LOC, slot);
+		}
+
+		/* Enable the relevant tx slot */
+		reg = CS35L34_TDM_TX_SLOT_EN_4 - (slot/8);
+		bit_pos = slot - ((slot / 8) * (8));
+		snd_soc_component_update_bits(component, reg,
+			1 << bit_pos, 1 << bit_pos);
+
+		tx_mask &= ~(1 << slot);
+		slot = ffs(tx_mask) - 1;
+		slot_num++;
+	}
+
+	return 0;
+}
+
+static int cs35l34_main_amp_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l34_private *priv = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(priv->regmap, CS35L34_BST_CVTR_V_CTL,
+				CS35L34_BST_CVTL_MASK, priv->pdata.boost_vtge);
+		usleep_range(5000, 5100);
+		regmap_update_bits(priv->regmap, CS35L34_PROTECT_CTL,
+						CS35L34_MUTE, 0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_update_bits(priv->regmap, CS35L34_BST_CVTR_V_CTL,
+			CS35L34_BST_CVTL_MASK, 0);
+		regmap_update_bits(priv->regmap, CS35L34_PROTECT_CTL,
+			CS35L34_MUTE, CS35L34_MUTE);
+		usleep_range(5000, 5100);
+		break;
+	default:
+		pr_err("Invalid event = 0x%x\n", event);
+	}
+	return 0;
+}
+
+static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 50, 0);
+
+static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 300, 100, 0);
+
+
+static const struct snd_kcontrol_new cs35l34_snd_controls[] = {
+	SOC_SINGLE_SX_TLV("Digital Volume", CS35L34_AMP_DIG_VOL,
+		      0, 0x34, 0xE4, dig_vol_tlv),
+	SOC_SINGLE_TLV("Amp Gain Volume", CS35L34_AMP_ANLG_GAIN_CTL,
+		      0, 0xF, 0, amp_gain_tlv),
+};
+
+
+static int cs35l34_mclk_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l34_private *priv = snd_soc_component_get_drvdata(component);
+	int ret, i;
+	unsigned int reg;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMD:
+		ret = regmap_read(priv->regmap, CS35L34_AMP_DIG_VOL_CTL,
+			&reg);
+		if (ret != 0) {
+			pr_err("%s regmap read failure %d\n", __func__, ret);
+			return ret;
+		}
+		if (reg & CS35L34_AMP_DIGSFT)
+			msleep(40);
+		else
+			usleep_range(2000, 2100);
+
+		for (i = 0; i < PDN_DONE_ATTEMPTS; i++) {
+			ret = regmap_read(priv->regmap, CS35L34_INT_STATUS_2,
+				&reg);
+			if (ret != 0) {
+				pr_err("%s regmap read failure %d\n",
+					__func__, ret);
+				return ret;
+			}
+			if (reg & CS35L34_PDN_DONE)
+				break;
+
+			usleep_range(5000, 5100);
+		}
+		if (i == PDN_DONE_ATTEMPTS)
+			pr_err("%s Device did not power down properly\n",
+				__func__);
+		break;
+	default:
+		pr_err("Invalid event = 0x%x\n", event);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget cs35l34_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L34_PWRCTL3,
+					1, 1, cs35l34_sdin_event,
+					SND_SOC_DAPM_PRE_PMU |
+					SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L34_PWRCTL3, 2, 1),
+
+	SND_SOC_DAPM_SUPPLY("EXTCLK", CS35L34_PWRCTL3, 7, 1,
+		cs35l34_mclk_event, SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_OUTPUT("SPK"),
+
+	SND_SOC_DAPM_INPUT("VP"),
+	SND_SOC_DAPM_INPUT("VPST"),
+	SND_SOC_DAPM_INPUT("ISENSE"),
+	SND_SOC_DAPM_INPUT("VSENSE"),
+
+	SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L34_PWRCTL2, 7, 1),
+	SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L34_PWRCTL2, 6, 1),
+	SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L34_PWRCTL3, 3, 1),
+	SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L34_PWRCTL3, 4, 1),
+	SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L34_PWRCTL2, 5, 1),
+	SND_SOC_DAPM_ADC("BOOST", NULL, CS35L34_PWRCTL2, 2, 1),
+
+	SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L34_PWRCTL2, 0, 1, NULL, 0,
+		cs35l34_main_amp_event, SND_SOC_DAPM_POST_PMU |
+			SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route cs35l34_audio_map[] = {
+	{"SDIN", NULL, "AMP Playback"},
+	{"BOOST", NULL, "SDIN"},
+	{"CLASS H", NULL, "BOOST"},
+	{"Main AMP", NULL, "CLASS H"},
+	{"SPK", NULL, "Main AMP"},
+
+	{"VPMON ADC", NULL, "CLASS H"},
+	{"VBSTMON ADC", NULL, "CLASS H"},
+	{"SPK", NULL, "VPMON ADC"},
+	{"SPK", NULL, "VBSTMON ADC"},
+
+	{"IMON ADC", NULL, "ISENSE"},
+	{"VMON ADC", NULL, "VSENSE"},
+	{"SDOUT", NULL, "IMON ADC"},
+	{"SDOUT", NULL, "VMON ADC"},
+	{"AMP Capture", NULL, "SDOUT"},
+
+	{"SDIN", NULL, "EXTCLK"},
+	{"SDOUT", NULL, "EXTCLK"},
+};
+
+struct cs35l34_mclk_div {
+	int mclk;
+	int srate;
+	u8 adsp_rate;
+};
+
+static struct cs35l34_mclk_div cs35l34_mclk_coeffs[] = {
+
+	/* MCLK, Sample Rate, adsp_rate */
+
+	{5644800, 11025, 0x1},
+	{5644800, 22050, 0x4},
+	{5644800, 44100, 0x7},
+
+	{6000000,  8000, 0x0},
+	{6000000, 11025, 0x1},
+	{6000000, 12000, 0x2},
+	{6000000, 16000, 0x3},
+	{6000000, 22050, 0x4},
+	{6000000, 24000, 0x5},
+	{6000000, 32000, 0x6},
+	{6000000, 44100, 0x7},
+	{6000000, 48000, 0x8},
+
+	{6144000,  8000, 0x0},
+	{6144000, 11025, 0x1},
+	{6144000, 12000, 0x2},
+	{6144000, 16000, 0x3},
+	{6144000, 22050, 0x4},
+	{6144000, 24000, 0x5},
+	{6144000, 32000, 0x6},
+	{6144000, 44100, 0x7},
+	{6144000, 48000, 0x8},
+};
+
+static int cs35l34_get_mclk_coeff(int mclk, int srate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cs35l34_mclk_coeffs); i++) {
+		if (cs35l34_mclk_coeffs[i].mclk == mclk &&
+			cs35l34_mclk_coeffs[i].srate == srate)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static int cs35l34_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs35l34_private *priv = snd_soc_component_get_drvdata(component);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL,
+				    0x80, 0x80);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL,
+				    0x80, 0x00);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cs35l34_pcm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs35l34_private *priv = snd_soc_component_get_drvdata(component);
+	int srate = params_rate(params);
+	int ret;
+
+	int coeff = cs35l34_get_mclk_coeff(priv->mclk_int, srate);
+
+	if (coeff < 0) {
+		dev_err(component->dev, "ERROR: Invalid mclk %d and/or srate %d\n",
+			priv->mclk_int, srate);
+		return coeff;
+	}
+
+	ret = regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL,
+		CS35L34_ADSP_RATE, cs35l34_mclk_coeffs[coeff].adsp_rate);
+	if (ret != 0)
+		dev_err(component->dev, "Failed to set clock state %d\n", ret);
+
+	return ret;
+}
+
+static const unsigned int cs35l34_src_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+
+static const struct snd_pcm_hw_constraint_list cs35l34_constraints = {
+	.count  = ARRAY_SIZE(cs35l34_src_rates),
+	.list   = cs35l34_src_rates,
+};
+
+static int cs35l34_pcm_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE, &cs35l34_constraints);
+	return 0;
+}
+
+
+static int cs35l34_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+
+	struct snd_soc_component *component = dai->component;
+
+	if (tristate)
+		snd_soc_component_update_bits(component, CS35L34_PWRCTL3,
+					CS35L34_PDN_SDOUT, CS35L34_PDN_SDOUT);
+	else
+		snd_soc_component_update_bits(component, CS35L34_PWRCTL3,
+					CS35L34_PDN_SDOUT, 0);
+	return 0;
+}
+
+static int cs35l34_dai_set_sysclk(struct snd_soc_dai *dai,
+				int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs35l34_private *cs35l34 = snd_soc_component_get_drvdata(component);
+	unsigned int value;
+
+	switch (freq) {
+	case CS35L34_MCLK_5644:
+		value = CS35L34_MCLK_RATE_5P6448;
+		cs35l34->mclk_int = freq;
+	break;
+	case CS35L34_MCLK_6:
+		value = CS35L34_MCLK_RATE_6P0000;
+		cs35l34->mclk_int = freq;
+	break;
+	case CS35L34_MCLK_6144:
+		value = CS35L34_MCLK_RATE_6P1440;
+		cs35l34->mclk_int = freq;
+	break;
+	case CS35L34_MCLK_11289:
+		value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_5P6448;
+		cs35l34->mclk_int = freq / 2;
+	break;
+	case CS35L34_MCLK_12:
+		value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_6P0000;
+		cs35l34->mclk_int = freq / 2;
+	break;
+	case CS35L34_MCLK_12288:
+		value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_6P1440;
+		cs35l34->mclk_int = freq / 2;
+	break;
+	default:
+		dev_err(component->dev, "ERROR: Invalid Frequency %d\n", freq);
+		cs35l34->mclk_int = 0;
+		return -EINVAL;
+	}
+	regmap_update_bits(cs35l34->regmap, CS35L34_MCLK_CTL,
+			CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_MASK, value);
+	return 0;
+}
+
+static const struct snd_soc_dai_ops cs35l34_ops = {
+	.startup = cs35l34_pcm_startup,
+	.set_tristate = cs35l34_set_tristate,
+	.set_fmt = cs35l34_set_dai_fmt,
+	.hw_params = cs35l34_pcm_hw_params,
+	.set_sysclk = cs35l34_dai_set_sysclk,
+	.set_tdm_slot = cs35l34_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver cs35l34_dai = {
+		.name = "cs35l34",
+		.id = 0,
+		.playback = {
+			.stream_name = "AMP Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = CS35L34_RATES,
+			.formats = CS35L34_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AMP Capture",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = CS35L34_RATES,
+			.formats = CS35L34_FORMATS,
+		},
+		.ops = &cs35l34_ops,
+		.symmetric_rates = 1,
+};
+
+static int cs35l34_boost_inductor(struct cs35l34_private *cs35l34,
+	unsigned int inductor)
+{
+	struct snd_soc_component *component = cs35l34->component;
+
+	switch (inductor) {
+	case 1000: /* 1 uH */
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x24);
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x24);
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP,
+			0x4E);
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 0);
+		break;
+	case 1200: /* 1.2 uH */
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x20);
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x20);
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP,
+			0x47);
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 1);
+		break;
+	case 1500: /* 1.5uH */
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x20);
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x20);
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP,
+			0x3C);
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 2);
+		break;
+	case 2200: /* 2.2uH */
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x19);
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x25);
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP,
+			0x23);
+		regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 3);
+		break;
+	default:
+		dev_err(component->dev, "%s Invalid Inductor Value %d uH\n",
+			__func__, inductor);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cs35l34_probe(struct snd_soc_component *component)
+{
+	int ret = 0;
+	struct cs35l34_private *cs35l34 = snd_soc_component_get_drvdata(component);
+
+	pm_runtime_get_sync(component->dev);
+
+	/* Set over temperature warning attenuation to 6 dB */
+	regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL,
+		 CS35L34_OTW_ATTN_MASK, 0x8);
+
+	/* Set Power control registers 2 and 3 to have everything
+	 * powered down at initialization
+	 */
+	regmap_write(cs35l34->regmap, CS35L34_PWRCTL2, 0xFD);
+	regmap_write(cs35l34->regmap, CS35L34_PWRCTL3, 0x1F);
+
+	/* Set mute bit at startup */
+	regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL,
+				CS35L34_MUTE, CS35L34_MUTE);
+
+	/* Set Platform Data */
+	if (cs35l34->pdata.boost_peak)
+		regmap_update_bits(cs35l34->regmap, CS35L34_BST_PEAK_I,
+				CS35L34_BST_PEAK_MASK,
+				cs35l34->pdata.boost_peak);
+
+	if (cs35l34->pdata.gain_zc_disable)
+		regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL,
+			CS35L34_GAIN_ZC_MASK, 0);
+	else
+		regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL,
+			CS35L34_GAIN_ZC_MASK, CS35L34_GAIN_ZC_MASK);
+
+	if (cs35l34->pdata.aif_half_drv)
+		regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_CLK_CTL,
+			CS35L34_ADSP_DRIVE, 0);
+
+	if (cs35l34->pdata.digsft_disable)
+		regmap_update_bits(cs35l34->regmap, CS35L34_AMP_DIG_VOL_CTL,
+			CS35L34_AMP_DIGSFT, 0);
+
+	if (cs35l34->pdata.amp_inv)
+		regmap_update_bits(cs35l34->regmap, CS35L34_AMP_DIG_VOL_CTL,
+			CS35L34_INV, CS35L34_INV);
+
+	if (cs35l34->pdata.boost_ind)
+		ret = cs35l34_boost_inductor(cs35l34, cs35l34->pdata.boost_ind);
+
+	if (cs35l34->pdata.i2s_sdinloc)
+		regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_I2S_CTL,
+			CS35L34_I2S_LOC_MASK,
+			cs35l34->pdata.i2s_sdinloc << CS35L34_I2S_LOC_SHIFT);
+
+	if (cs35l34->pdata.tdm_rising_edge)
+		regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_TDM_CTL,
+			1, 1);
+
+	pm_runtime_put_sync(component->dev);
+
+	return ret;
+}
+
+
+static const struct snd_soc_component_driver soc_component_dev_cs35l34 = {
+	.probe			= cs35l34_probe,
+	.dapm_widgets		= cs35l34_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs35l34_dapm_widgets),
+	.dapm_routes		= cs35l34_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs35l34_audio_map),
+	.controls		= cs35l34_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs35l34_snd_controls),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static struct regmap_config cs35l34_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = CS35L34_MAX_REGISTER,
+	.reg_defaults = cs35l34_reg,
+	.num_reg_defaults = ARRAY_SIZE(cs35l34_reg),
+	.volatile_reg = cs35l34_volatile_register,
+	.readable_reg = cs35l34_readable_register,
+	.precious_reg = cs35l34_precious_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int cs35l34_handle_of_data(struct i2c_client *i2c_client,
+				struct cs35l34_platform_data *pdata)
+{
+	struct device_node *np = i2c_client->dev.of_node;
+	unsigned int val;
+
+	if (of_property_read_u32(np, "cirrus,boost-vtge-millivolt",
+		&val) >= 0) {
+		/* Boost Voltage has a maximum of 8V */
+		if (val > 8000 || (val < 3300 && val > 0)) {
+			dev_err(&i2c_client->dev,
+				"Invalid Boost Voltage %d mV\n", val);
+			return -EINVAL;
+		}
+		if (val == 0)
+			pdata->boost_vtge = 0; /* Use VP */
+		else
+			pdata->boost_vtge = ((val - 3300)/100) + 1;
+	} else {
+		dev_warn(&i2c_client->dev,
+			"Boost Voltage not specified. Using VP\n");
+	}
+
+	if (of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val) >= 0) {
+		pdata->boost_ind = val;
+	} else {
+		dev_err(&i2c_client->dev, "Inductor not specified.\n");
+		return -EINVAL;
+	}
+
+	if (of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val) >= 0) {
+		if (val > 3840 || val < 1200) {
+			dev_err(&i2c_client->dev,
+				"Invalid Boost Peak Current %d mA\n", val);
+			return -EINVAL;
+		}
+		pdata->boost_peak = ((val - 1200)/80) + 1;
+	}
+
+	pdata->aif_half_drv = of_property_read_bool(np,
+		"cirrus,aif-half-drv");
+	pdata->digsft_disable = of_property_read_bool(np,
+		"cirrus,digsft-disable");
+
+	pdata->gain_zc_disable = of_property_read_bool(np,
+		"cirrus,gain-zc-disable");
+	pdata->amp_inv = of_property_read_bool(np, "cirrus,amp-inv");
+
+	if (of_property_read_u32(np, "cirrus,i2s-sdinloc", &val) >= 0)
+		pdata->i2s_sdinloc = val;
+	if (of_property_read_u32(np, "cirrus,tdm-rising-edge", &val) >= 0)
+		pdata->tdm_rising_edge = val;
+
+	return 0;
+}
+
+static irqreturn_t cs35l34_irq_thread(int irq, void *data)
+{
+	struct cs35l34_private *cs35l34 = data;
+	struct snd_soc_component *component = cs35l34->component;
+	unsigned int sticky1, sticky2, sticky3, sticky4;
+	unsigned int mask1, mask2, mask3, mask4, current1;
+
+
+	/* ack the irq by reading all status registers */
+	regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_4, &sticky4);
+	regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_3, &sticky3);
+	regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_2, &sticky2);
+	regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_1, &sticky1);
+
+	regmap_read(cs35l34->regmap, CS35L34_INT_MASK_4, &mask4);
+	regmap_read(cs35l34->regmap, CS35L34_INT_MASK_3, &mask3);
+	regmap_read(cs35l34->regmap, CS35L34_INT_MASK_2, &mask2);
+	regmap_read(cs35l34->regmap, CS35L34_INT_MASK_1, &mask1);
+
+	if (!(sticky1 & ~mask1) && !(sticky2 & ~mask2) && !(sticky3 & ~mask3)
+		&& !(sticky4 & ~mask4))
+		return IRQ_NONE;
+
+	regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_1, &current1);
+
+	if (sticky1 & CS35L34_CAL_ERR) {
+		dev_err(component->dev, "Cal error\n");
+
+		/* error is no longer asserted; safe to reset */
+		if (!(current1 & CS35L34_CAL_ERR)) {
+			dev_dbg(component->dev, "Cal error release\n");
+			regmap_update_bits(cs35l34->regmap,
+					CS35L34_PROT_RELEASE_CTL,
+					CS35L34_CAL_ERR_RLS, 0);
+			regmap_update_bits(cs35l34->regmap,
+					CS35L34_PROT_RELEASE_CTL,
+					CS35L34_CAL_ERR_RLS,
+					CS35L34_CAL_ERR_RLS);
+			regmap_update_bits(cs35l34->regmap,
+					CS35L34_PROT_RELEASE_CTL,
+					CS35L34_CAL_ERR_RLS, 0);
+			/* note: amp will re-calibrate on next resume */
+		}
+	}
+
+	if (sticky1 & CS35L34_ALIVE_ERR)
+		dev_err(component->dev, "Alive error\n");
+
+	if (sticky1 & CS35L34_AMP_SHORT) {
+		dev_crit(component->dev, "Amp short error\n");
+
+		/* error is no longer asserted; safe to reset */
+		if (!(current1 & CS35L34_AMP_SHORT)) {
+			dev_dbg(component->dev,
+				"Amp short error release\n");
+			regmap_update_bits(cs35l34->regmap,
+					CS35L34_PROT_RELEASE_CTL,
+					CS35L34_SHORT_RLS, 0);
+			regmap_update_bits(cs35l34->regmap,
+					CS35L34_PROT_RELEASE_CTL,
+					CS35L34_SHORT_RLS,
+					CS35L34_SHORT_RLS);
+			regmap_update_bits(cs35l34->regmap,
+					CS35L34_PROT_RELEASE_CTL,
+					CS35L34_SHORT_RLS, 0);
+		}
+	}
+
+	if (sticky1 & CS35L34_OTW) {
+		dev_crit(component->dev, "Over temperature warning\n");
+
+		/* error is no longer asserted; safe to reset */
+		if (!(current1 & CS35L34_OTW)) {
+			dev_dbg(component->dev,
+				"Over temperature warning release\n");
+			regmap_update_bits(cs35l34->regmap,
+					CS35L34_PROT_RELEASE_CTL,
+					CS35L34_OTW_RLS, 0);
+			regmap_update_bits(cs35l34->regmap,
+					CS35L34_PROT_RELEASE_CTL,
+					CS35L34_OTW_RLS,
+					CS35L34_OTW_RLS);
+			regmap_update_bits(cs35l34->regmap,
+					CS35L34_PROT_RELEASE_CTL,
+					CS35L34_OTW_RLS, 0);
+		}
+	}
+
+	if (sticky1 & CS35L34_OTE) {
+		dev_crit(component->dev, "Over temperature error\n");
+
+		/* error is no longer asserted; safe to reset */
+		if (!(current1 & CS35L34_OTE)) {
+			dev_dbg(component->dev,
+				"Over temperature error release\n");
+			regmap_update_bits(cs35l34->regmap,
+					CS35L34_PROT_RELEASE_CTL,
+					CS35L34_OTE_RLS, 0);
+			regmap_update_bits(cs35l34->regmap,
+					CS35L34_PROT_RELEASE_CTL,
+					CS35L34_OTE_RLS,
+					CS35L34_OTE_RLS);
+			regmap_update_bits(cs35l34->regmap,
+					CS35L34_PROT_RELEASE_CTL,
+					CS35L34_OTE_RLS, 0);
+		}
+	}
+
+	if (sticky3 & CS35L34_BST_HIGH) {
+		dev_crit(component->dev, "VBST too high error; powering off!\n");
+		regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL2,
+				CS35L34_PDN_AMP, CS35L34_PDN_AMP);
+		regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL1,
+				CS35L34_PDN_ALL, CS35L34_PDN_ALL);
+	}
+
+	if (sticky3 & CS35L34_LBST_SHORT) {
+		dev_crit(component->dev, "LBST short error; powering off!\n");
+		regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL2,
+				CS35L34_PDN_AMP, CS35L34_PDN_AMP);
+		regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL1,
+				CS35L34_PDN_ALL, CS35L34_PDN_ALL);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static const char * const cs35l34_core_supplies[] = {
+	"VA",
+	"VP",
+};
+
+static int cs35l34_i2c_probe(struct i2c_client *i2c_client,
+			      const struct i2c_device_id *id)
+{
+	struct cs35l34_private *cs35l34;
+	struct cs35l34_platform_data *pdata =
+		dev_get_platdata(&i2c_client->dev);
+	int i;
+	int ret;
+	unsigned int devid = 0;
+	unsigned int reg;
+
+	cs35l34 = devm_kzalloc(&i2c_client->dev, sizeof(*cs35l34), GFP_KERNEL);
+	if (!cs35l34)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c_client, cs35l34);
+	cs35l34->regmap = devm_regmap_init_i2c(i2c_client, &cs35l34_regmap);
+	if (IS_ERR(cs35l34->regmap)) {
+		ret = PTR_ERR(cs35l34->regmap);
+		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	cs35l34->num_core_supplies = ARRAY_SIZE(cs35l34_core_supplies);
+	for (i = 0; i < ARRAY_SIZE(cs35l34_core_supplies); i++)
+		cs35l34->core_supplies[i].supply = cs35l34_core_supplies[i];
+
+	ret = devm_regulator_bulk_get(&i2c_client->dev,
+		cs35l34->num_core_supplies,
+		cs35l34->core_supplies);
+	if (ret != 0) {
+		dev_err(&i2c_client->dev,
+			"Failed to request core supplies %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(cs35l34->num_core_supplies,
+					cs35l34->core_supplies);
+	if (ret != 0) {
+		dev_err(&i2c_client->dev,
+			"Failed to enable core supplies: %d\n", ret);
+		return ret;
+	}
+
+	if (pdata) {
+		cs35l34->pdata = *pdata;
+	} else {
+		pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
+				     GFP_KERNEL);
+		if (!pdata)
+			return -ENOMEM;
+
+		if (i2c_client->dev.of_node) {
+			ret = cs35l34_handle_of_data(i2c_client, pdata);
+			if (ret != 0)
+				return ret;
+
+		}
+		cs35l34->pdata = *pdata;
+	}
+
+	ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL,
+			cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+			"cs35l34", cs35l34);
+	if (ret != 0)
+		dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret);
+
+	cs35l34->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+				"reset-gpios", GPIOD_OUT_LOW);
+	if (IS_ERR(cs35l34->reset_gpio))
+		return PTR_ERR(cs35l34->reset_gpio);
+
+	gpiod_set_value_cansleep(cs35l34->reset_gpio, 1);
+
+	msleep(CS35L34_START_DELAY);
+
+	ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_AB, &reg);
+
+	devid = (reg & 0xFF) << 12;
+	ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_CD, &reg);
+	devid |= (reg & 0xFF) << 4;
+	ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_E, &reg);
+	devid |= (reg & 0xF0) >> 4;
+
+	if (devid != CS35L34_CHIP_ID) {
+		dev_err(&i2c_client->dev,
+			"CS35l34 Device ID (%X). Expected ID %X\n",
+			devid, CS35L34_CHIP_ID);
+		ret = -ENODEV;
+		goto err_regulator;
+	}
+
+	ret = regmap_read(cs35l34->regmap, CS35L34_REV_ID, &reg);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+		goto err_regulator;
+	}
+
+	dev_info(&i2c_client->dev,
+		 "Cirrus Logic CS35l34 (%x), Revision: %02X\n", devid,
+		reg & 0xFF);
+
+	/* Unmask critical interrupts */
+	regmap_update_bits(cs35l34->regmap, CS35L34_INT_MASK_1,
+				CS35L34_M_CAL_ERR | CS35L34_M_ALIVE_ERR |
+				CS35L34_M_AMP_SHORT | CS35L34_M_OTW |
+				CS35L34_M_OTE, 0);
+	regmap_update_bits(cs35l34->regmap, CS35L34_INT_MASK_3,
+				CS35L34_M_BST_HIGH | CS35L34_M_LBST_SHORT, 0);
+
+	pm_runtime_set_autosuspend_delay(&i2c_client->dev, 100);
+	pm_runtime_use_autosuspend(&i2c_client->dev);
+	pm_runtime_set_active(&i2c_client->dev);
+	pm_runtime_enable(&i2c_client->dev);
+
+	ret = devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_dev_cs35l34, &cs35l34_dai, 1);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev,
+			"%s: Register component failed\n", __func__);
+		goto err_regulator;
+	}
+
+	return 0;
+
+err_regulator:
+	regulator_bulk_disable(cs35l34->num_core_supplies,
+		cs35l34->core_supplies);
+
+	return ret;
+}
+
+static int cs35l34_i2c_remove(struct i2c_client *client)
+{
+	struct cs35l34_private *cs35l34 = i2c_get_clientdata(client);
+
+	gpiod_set_value_cansleep(cs35l34->reset_gpio, 0);
+
+	pm_runtime_disable(&client->dev);
+	regulator_bulk_disable(cs35l34->num_core_supplies,
+		cs35l34->core_supplies);
+
+	return 0;
+}
+
+static int __maybe_unused cs35l34_runtime_resume(struct device *dev)
+{
+	struct cs35l34_private *cs35l34 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_bulk_enable(cs35l34->num_core_supplies,
+		cs35l34->core_supplies);
+
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable core supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	regcache_cache_only(cs35l34->regmap, false);
+
+	gpiod_set_value_cansleep(cs35l34->reset_gpio, 1);
+	msleep(CS35L34_START_DELAY);
+
+	ret = regcache_sync(cs35l34->regmap);
+	if (ret != 0) {
+		dev_err(dev, "Failed to restore register cache\n");
+		goto err;
+	}
+	return 0;
+err:
+	regcache_cache_only(cs35l34->regmap, true);
+	regulator_bulk_disable(cs35l34->num_core_supplies,
+		cs35l34->core_supplies);
+
+	return ret;
+}
+
+static int __maybe_unused cs35l34_runtime_suspend(struct device *dev)
+{
+	struct cs35l34_private *cs35l34 = dev_get_drvdata(dev);
+
+	regcache_cache_only(cs35l34->regmap, true);
+	regcache_mark_dirty(cs35l34->regmap);
+
+	gpiod_set_value_cansleep(cs35l34->reset_gpio, 0);
+
+	regulator_bulk_disable(cs35l34->num_core_supplies,
+			cs35l34->core_supplies);
+
+	return 0;
+}
+
+static const struct dev_pm_ops cs35l34_pm_ops = {
+	SET_RUNTIME_PM_OPS(cs35l34_runtime_suspend,
+			   cs35l34_runtime_resume,
+			   NULL)
+};
+
+static const struct of_device_id cs35l34_of_match[] = {
+	{.compatible = "cirrus,cs35l34"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, cs35l34_of_match);
+
+static const struct i2c_device_id cs35l34_id[] = {
+	{"cs35l34", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, cs35l34_id);
+
+static struct i2c_driver cs35l34_i2c_driver = {
+	.driver = {
+		.name = "cs35l34",
+		.pm = &cs35l34_pm_ops,
+		.of_match_table = cs35l34_of_match,
+
+		},
+	.id_table = cs35l34_id,
+	.probe = cs35l34_i2c_probe,
+	.remove = cs35l34_i2c_remove,
+
+};
+
+static int __init cs35l34_modinit(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&cs35l34_i2c_driver);
+	if (ret != 0) {
+		pr_err("Failed to register CS35l34 I2C driver: %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+module_init(cs35l34_modinit);
+
+static void __exit cs35l34_exit(void)
+{
+	i2c_del_driver(&cs35l34_i2c_driver);
+}
+module_exit(cs35l34_exit);
+
+MODULE_DESCRIPTION("ASoC CS35l34 driver");
+MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <Paul.Handrigan@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l34.h b/sound/soc/codecs/cs35l34.h
new file mode 100644
index 0000000..bcd54f1
--- /dev/null
+++ b/sound/soc/codecs/cs35l34.h
@@ -0,0 +1,269 @@
+/*
+ * cs35l34.h -- CS35L34 ALSA SoC audio driver
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: Paul Handrigan <Paul.Handrigan@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CS35L34_H__
+#define __CS35L34_H__
+
+#define CS35L34_CHIP_ID			0x00035A34
+#define CS35L34_DEVID_AB		0x01	/* Device ID A & B [RO] */
+#define CS35L34_DEVID_CD		0x02    /* Device ID C & D [RO] */
+#define CS35L34_DEVID_E			0x03    /* Device ID E [RO] */
+#define CS35L34_FAB_ID			0x04	/* Fab ID [RO] */
+#define CS35L34_REV_ID			0x05	/* Revision ID [RO] */
+#define CS35L34_PWRCTL1			0x06    /* Power Ctl 1 */
+#define CS35L34_PWRCTL2			0x07    /* Power Ctl 2 */
+#define CS35L34_PWRCTL3			0x08	/* Power Ctl 3 */
+#define CS35L34_ADSP_CLK_CTL		0x0A	/* (ADSP) Clock Ctl */
+#define CS35L34_MCLK_CTL		0x0B	/* Master Clocking Ctl */
+#define CS35L34_AMP_INP_DRV_CTL		0x14	/* Amp Input Drive Ctl */
+#define CS35L34_AMP_DIG_VOL_CTL		0x15	/* Amplifier Dig Volume Ctl */
+#define CS35L34_AMP_DIG_VOL		0x16	/* Amplifier Dig Volume */
+#define CS35L34_AMP_ANLG_GAIN_CTL	0x17	/* Amplifier Analog Gain Ctl */
+#define CS35L34_PROTECT_CTL		0x18	/* Amp Gain - Prot Ctl Param */
+#define CS35L34_AMP_KEEP_ALIVE_CTL	0x1A	/* Amplifier Keep Alive Ctl */
+#define CS35L34_BST_CVTR_V_CTL		0x1D	/* Boost Conv Voltage Ctl */
+#define CS35L34_BST_PEAK_I		0x1E	/* Boost Conv Peak Current */
+#define CS35L34_BST_RAMP_CTL		0x20	/* Boost Conv Soft Ramp Ctl */
+#define CS35L34_BST_CONV_COEF_1		0x21	/* Boost Conv Coefficients 1 */
+#define CS35L34_BST_CONV_COEF_2		0x22	/* Boost Conv Coefficients 2 */
+#define CS35L34_BST_CONV_SLOPE_COMP	0x23	/* Boost Conv Slope Comp */
+#define CS35L34_BST_CONV_SW_FREQ	0x24	/* Boost Conv L BST SW Freq */
+#define CS35L34_CLASS_H_CTL		0x30	/* CLS H Control */
+#define CS35L34_CLASS_H_HEADRM_CTL	0x31	/* CLS H Headroom Ctl */
+#define CS35L34_CLASS_H_RELEASE_RATE	0x32	/* CLS H Release Rate */
+#define CS35L34_CLASS_H_FET_DRIVE_CTL	0x33	/* CLS H Weak FET Drive Ctl */
+#define CS35L34_CLASS_H_STATUS		0x38	/* CLS H Status */
+#define CS35L34_VPBR_CTL		0x3A	/* VPBR Ctl */
+#define CS35L34_VPBR_VOL_CTL		0x3B	/* VPBR Volume Ctl */
+#define CS35L34_VPBR_TIMING_CTL		0x3C	/* VPBR Timing Ctl */
+#define CS35L34_PRED_MAX_ATTEN_SPK_LOAD	0x40	/* PRD Max Atten / Spkr Load */
+#define CS35L34_PRED_BROWNOUT_THRESH	0x41	/* PRD Brownout Threshold */
+#define CS35L34_PRED_BROWNOUT_VOL_CTL	0x42	/* PRD Brownout Volume Ctl */
+#define CS35L34_PRED_BROWNOUT_RATE_CTL	0x43	/* PRD Brownout Rate Ctl */
+#define CS35L34_PRED_WAIT_CTL		0x44	/* PRD Wait Ctl */
+#define CS35L34_PRED_ZVP_INIT_IMP_CTL	0x46	/* PRD ZVP Initial Imp Ctl */
+#define CS35L34_PRED_MAN_SAFE_VPI_CTL	0x47	/* PRD Manual Safe VPI Ctl */
+#define CS35L34_VPBR_ATTEN_STATUS	0x4B	/* VPBR Attenuation Status */
+#define CS35L34_PRED_BRWNOUT_ATT_STATUS	0x4C	/* PRD Brownout Atten Status */
+#define CS35L34_SPKR_MON_CTL		0x4E	/* Speaker Monitoring Ctl */
+#define CS35L34_ADSP_I2S_CTL		0x50	/* ADSP I2S Ctl */
+#define CS35L34_ADSP_TDM_CTL		0x51	/* ADSP TDM Ctl */
+#define CS35L34_TDM_TX_CTL_1_VMON	0x52	/* TDM TX Ctl 1 (VMON) */
+#define CS35L34_TDM_TX_CTL_2_IMON	0x53	/* TDM TX Ctl 2 (IMON) */
+#define CS35L34_TDM_TX_CTL_3_VPMON	0x54	/* TDM TX Ctl 3 (VPMON) */
+#define CS35L34_TDM_TX_CTL_4_VBSTMON	0x55	/* TDM TX Ctl 4 (VBSTMON) */
+#define CS35L34_TDM_TX_CTL_5_FLAG1	0x56	/* TDM TX Ctl 5 (FLAG1) */
+#define CS35L34_TDM_TX_CTL_6_FLAG2	0x57	/* TDM TX Ctl 6 (FLAG2) */
+#define CS35L34_TDM_TX_SLOT_EN_1	0x5A	/* TDM TX Slot Enable */
+#define CS35L34_TDM_TX_SLOT_EN_2	0x5B	/* TDM TX Slot Enable */
+#define CS35L34_TDM_TX_SLOT_EN_3	0x5C	/* TDM TX Slot Enable */
+#define CS35L34_TDM_TX_SLOT_EN_4	0x5D	/* TDM TX Slot Enable */
+#define CS35L34_TDM_RX_CTL_1_AUDIN	0x5E	/* TDM RX Ctl 1 */
+#define CS35L34_TDM_RX_CTL_3_ALIVE	0x60	/* TDM RX Ctl 3 (ALIVE) */
+#define CS35L34_MULT_DEV_SYNCH1		0x62	/* Multidevice Synch */
+#define CS35L34_MULT_DEV_SYNCH2		0x63	/* Multidevice Synch 2 */
+#define CS35L34_PROT_RELEASE_CTL	0x64	/* Protection Release Ctl */
+#define CS35L34_DIAG_MODE_REG_LOCK	0x68	/* Diagnostic Mode Reg Lock */
+#define CS35L34_DIAG_MODE_CTL_1		0x69	/* Diagnostic Mode Ctl 1 */
+#define CS35L34_DIAG_MODE_CTL_2		0x6A	/* Diagnostic Mode Ctl 2 */
+#define CS35L34_INT_MASK_1		0x70	/* Interrupt Mask 1 */
+#define CS35L34_INT_MASK_2		0x71	/* Interrupt Mask 2 */
+#define CS35L34_INT_MASK_3		0x72	/* Interrupt Mask 3 */
+#define CS35L34_INT_MASK_4		0x73	/* Interrupt Mask 4 */
+#define CS35L34_INT_STATUS_1		0x74	/* Interrupt Status 1 */
+#define CS35L34_INT_STATUS_2		0x75	/* Interrupt Status 2 */
+#define CS35L34_INT_STATUS_3		0x76	/* Interrupt Status 3 */
+#define CS35L34_INT_STATUS_4		0x77	/* Interrupt Status 4 */
+#define CS35L34_OTP_TRIM_STATUS		0x7E	/* OTP Trim Status */
+
+#define CS35L34_MAX_REGISTER		0x7F
+#define CS35L34_REGISTER_COUNT		0x4E
+
+#define CS35L34_MCLK_5644		5644800
+#define CS35L34_MCLK_6144		6144000
+#define CS35L34_MCLK_6			6000000
+#define CS35L34_MCLK_11289		11289600
+#define CS35L34_MCLK_12			12000000
+#define CS35L34_MCLK_12288		12288000
+
+/* CS35L34_PWRCTL1 */
+#define CS35L34_SFT_RST			(1 << 7)
+#define CS35L34_DISCHG_FLT		(1 << 1)
+#define CS35L34_PDN_ALL			1
+
+/* CS35L34_PWRCTL2 */
+#define CS35L34_PDN_VMON		(1 << 7)
+#define CS35L34_PDN_IMON		(1 << 6)
+#define CS35L34_PDN_CLASSH		(1 << 5)
+#define CS35L34_PDN_VPBR		(1 << 4)
+#define CS35L34_PDN_PRED		(1 << 3)
+#define CS35L34_PDN_BST			(1 << 2)
+#define CS35L34_PDN_AMP			1
+
+/* CS35L34_PWRCTL3 */
+#define CS35L34_MCLK_DIS		(1 << 7)
+#define CS35L34_PDN_VBSTMON_OUT		(1 << 4)
+#define CS35L34_PDN_VMON_OUT		(1 << 3)
+/* Tristate the ADSP SDOUT when in I2C mode */
+#define CS35L34_PDN_SDOUT		(1 << 2)
+#define CS35L34_PDN_SDIN		(1 << 1)
+#define CS35L34_PDN_TDM			1
+
+/* CS35L34_ADSP_CLK_CTL */
+#define CS35L34_ADSP_RATE		0xF
+#define CS35L34_ADSP_DRIVE		(1 << 4)
+#define CS35L34_ADSP_M_S		(1 << 7)
+
+/* CS35L34_MCLK_CTL */
+#define CS35L34_MCLK_DIV		(1 << 4)
+#define CS35L34_MCLK_RATE_MASK		0x7
+#define CS35L34_MCLK_RATE_6P1440	0x2
+#define CS35L34_MCLK_RATE_6P0000	0x1
+#define CS35L34_MCLK_RATE_5P6448	0x0
+#define CS35L34_MCLKDIS			(1 << 7)
+#define CS35L34_MCLKDIV2		(1 << 6)
+#define CS35L34_SDOUT_3ST_TDM		(1 << 5)
+#define CS35L34_INT_FS_RATE		(1 << 4)
+#define CS35L34_ADSP_FS			0xF
+
+/* CS35L34_AMP_INP_DRV_CTL */
+#define CS35L34_DRV_STR_SRC		(1 << 1)
+#define CS35L34_DRV_STR			1
+
+/* CS35L34_AMP_DIG_VOL_CTL */
+#define CS35L34_AMP_DSR_RATE_MASK	0xF0
+#define CS35L34_AMP_DSR_RATE_SHIFT	(1 << 4)
+#define CS35L34_NOTCH_DIS		(1 << 3)
+#define CS35L34_AMP_DIGSFT		(1 << 1)
+#define CS35L34_INV			1
+
+/* CS35L34_PROTECT_CTL */
+#define CS35L34_OTW_ATTN_MASK		0xC
+#define CS35L34_OTW_THRD_MASK		0x3
+#define CS35L34_MUTE			(1 << 5)
+#define CS35L34_GAIN_ZC			(1 << 4)
+#define CS35L34_GAIN_ZC_MASK		0x10
+#define CS35L34_GAIN_ZC_SHIFT		4
+
+/* CS35L34_AMP_KEEP_ALIVE_CTL */
+#define CS35L34_ALIVE_WD_DIS		(1 << 2)
+
+/* CS35L34_BST_CVTR_V_CTL */
+#define CS35L34_BST_CVTL_MASK		0x3F
+
+/* CS35L34_BST_PEAK_I */
+#define CS35L34_BST_PEAK_MASK		0x3F
+
+/* CS35L34_ADSP_I2S_CTL */
+#define CS35L34_I2S_LOC_MASK		0xC
+#define CS35L34_I2S_LOC_SHIFT		2
+
+/* CS35L34_MULT_DEV_SYNCH2 */
+#define CS35L34_SYNC2_MASK		0xF
+
+/* CS35L34_PROT_RELEASE_CTL */
+#define CS35L34_CAL_ERR_RLS		(1 << 7)
+#define CS35L34_SHORT_RLS		(1 << 2)
+#define CS35L34_OTW_RLS			(1 << 1)
+#define CS35L34_OTE_RLS			1
+
+/* CS35L34_INT_MASK_1 */
+#define CS35L34_M_CAL_ERR_SHIFT		7
+#define CS35L34_M_CAL_ERR		(1 << CS35L34_M_CAL_ERR_SHIFT)
+#define CS35L34_M_ALIVE_ERR_SHIFT	5
+#define CS35L34_M_ALIVE_ERR		(1 << CS35L34_M_ALIVE_ERR_SHIFT)
+#define CS35L34_M_ADSP_CLK_SHIFT	4
+#define CS35L34_M_ADSP_CLK_ERR		(1 << CS35L34_M_ADSP_CLK_SHIFT)
+#define CS35L34_M_MCLK_SHIFT		3
+#define CS35L34_M_MCLK_ERR		(1 << CS35L34_M_MCLK_SHIFT)
+#define CS35L34_M_AMP_SHORT_SHIFT	2
+#define CS35L34_M_AMP_SHORT		(1 << CS35L34_M_AMP_SHORT_SHIFT)
+#define CS35L34_M_OTW_SHIFT		1
+#define CS35L34_M_OTW			(1 << CS35L34_M_OTW_SHIFT)
+#define CS35L34_M_OTE_SHIFT		0
+#define CS35L34_M_OTE			(1 << CS35L34_M_OTE_SHIFT)
+
+/* CS35L34_INT_MASK_2 */
+#define CS35L34_M_PDN_DONE_SHIFT	4
+#define CS35L34_M_PDN_DONE		(1 << CS35L34_M_PDN_DONE_SHIFT)
+#define CS35L34_M_PRED_SHIFT		3
+#define CS35L34_M_PRED_ERR		(1 << CS35L34_M_PRED_SHIFT)
+#define CS35L34_M_PRED_CLR_SHIFT	2
+#define CS35L34_M_PRED_CLR		(1 << CS35L34_M_PRED_CLR_SHIFT)
+#define CS35L34_M_VPBR_SHIFT		1
+#define CS35L34_M_VPBR_ERR		(1 << CS35L34_M_VPBR_SHIFT)
+#define CS35L34_M_VPBR_CLR_SHIFT	0
+#define CS35L34_M_VPBR_CLR		(1 << CS35L34_M_VPBR_CLR_SHIFT)
+
+/* CS35L34_INT_MASK_3 */
+#define CS35L34_M_BST_HIGH_SHIFT	4
+#define CS35L34_M_BST_HIGH		(1 << CS35L34_M_BST_HIGH_SHIFT)
+#define CS35L34_M_BST_HIGH_FLAG_SHIFT	3
+#define CS35L34_M_BST_HIGH_FLAG		(1 << CS35L34_M_BST_HIGH_FLAG_SHIFT)
+#define CS35L34_M_BST_IPK_FLAG_SHIFT	2
+#define CS35L34_M_BST_IPK_FLAG		(1 << CS35L34_M_BST_IPK_FLAG_SHIFT)
+#define CS35L34_M_LBST_SHORT_SHIFT	0
+#define CS35L34_M_LBST_SHORT		(1 << CS35L34_M_LBST_SHORT_SHIFT)
+
+/* CS35L34_INT_MASK_4 */
+#define CS35L34_M_VMON_OVFL_SHIFT	3
+#define CS35L34_M_VMON_OVFL		(1 << CS35L34_M_VMON_OVFL_SHIFT)
+#define CS35L34_M_IMON_OVFL_SHIFT	2
+#define CS35L34_M_IMON_OVFL		(1 << CS35L34_M_IMON_OVFL_SHIFT)
+#define CS35L34_M_VPMON_OVFL_SHIFT	1
+#define CS35L34_M_VPMON_OVFL		(1 << CS35L34_M_VPMON_OVFL_SHIFT)
+#define CS35L34_M_VBSTMON_OVFL_SHIFT	1
+#define CS35L34_M_VBSTMON_OVFL		(1 << CS35L34_M_VBSTMON_OVFL_SHIFT)
+
+/* CS35L34_INT_1 */
+#define CS35L34_CAL_ERR			(1 << CS35L34_M_CAL_ERR_SHIFT)
+#define CS35L34_ALIVE_ERR		(1 << CS35L34_M_ALIVE_ERR_SHIFT)
+#define CS35L34_M_ADSP_CLK_ERR		(1 << CS35L34_M_ADSP_CLK_SHIFT)
+#define CS35L34_MCLK_ERR		(1 << CS35L34_M_MCLK_SHIFT)
+#define CS35L34_AMP_SHORT		(1 << CS35L34_M_AMP_SHORT_SHIFT)
+#define CS35L34_OTW			(1 << CS35L34_M_OTW_SHIFT)
+#define CS35L34_OTE			(1 << CS35L34_M_OTE_SHIFT)
+
+/* CS35L34_INT_2 */
+#define CS35L34_PDN_DONE		(1 << CS35L34_M_PDN_DONE_SHIFT)
+#define CS35L34_PRED_ERR		(1 << CS35L34_M_PRED_SHIFT)
+#define CS35L34_PRED_CLR		(1 << CS35L34_M_PRED_CLR_SHIFT)
+#define CS35L34_VPBR_ERR		(1 << CS35L34_M_VPBR_SHIFT)
+#define CS35L34_VPBR_CLR		(1 << CS35L34_M_VPBR_CLR_SHIFT)
+
+/* CS35L34_INT_3 */
+#define CS35L34_BST_HIGH		(1 << CS35L34_M_BST_HIGH_SHIFT)
+#define CS35L34_BST_HIGH_FLAG		(1 << CS35L34_M_BST_HIGH_FLAG_SHIFT)
+#define CS35L34_BST_IPK_FLAG		(1 << CS35L34_M_BST_IPK_FLAG_SHIFT)
+#define CS35L34_LBST_SHORT		(1 << CS35L34_M_LBST_SHORT_SHIFT)
+
+/* CS35L34_INT_4 */
+#define CS35L34_VMON_OVFL		(1 << CS35L34_M_VMON_OVFL_SHIFT)
+#define CS35L34_IMON_OVFL		(1 << CS35L34_M_IMON_OVFL_SHIFT)
+#define CS35L34_VPMON_OVFL		(1 << CS35L34_M_VPMON_OVFL_SHIFT)
+#define CS35L34_VBSTMON_OVFL		(1 << CS35L34_M_VBSTMON_OVFL_SHIFT)
+
+/* CS35L34_{RX,TX}_X */
+#define CS35L34_X_STATE_SHIFT		7
+#define CS35L34_X_STATE			(1 << CS35L34_X_STATE_SHIFT)
+#define CS35L34_X_LOC_SHIFT		0
+#define CS35L34_X_LOC			(0x1F << CS35L34_X_LOC_SHIFT)
+
+#define CS35L34_RATES (SNDRV_PCM_RATE_48000 | \
+			SNDRV_PCM_RATE_44100 | \
+			SNDRV_PCM_RATE_32000)
+#define CS35L34_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | \
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+#endif
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
new file mode 100644
index 0000000..bd6226b
--- /dev/null
+++ b/sound/soc/codecs/cs35l35.c
@@ -0,0 +1,1663 @@
+/*
+ * cs35l35.c -- CS35L35 ALSA SoC audio driver
+ *
+ * Copyright 2017 Cirrus Logic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <linux/gpio.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/cs35l35.h>
+#include <linux/of_irq.h>
+#include <linux/completion.h>
+
+#include "cs35l35.h"
+
+/*
+ * Some fields take zero as a valid value so use a high bit flag that won't
+ * get written to the device to mark those.
+ */
+#define CS35L35_VALID_PDATA 0x80000000
+
+static const struct reg_default cs35l35_reg[] = {
+	{CS35L35_PWRCTL1,		0x01},
+	{CS35L35_PWRCTL2,		0x11},
+	{CS35L35_PWRCTL3,		0x00},
+	{CS35L35_CLK_CTL1,		0x04},
+	{CS35L35_CLK_CTL2,		0x12},
+	{CS35L35_CLK_CTL3,		0xCF},
+	{CS35L35_SP_FMT_CTL1,		0x20},
+	{CS35L35_SP_FMT_CTL2,		0x00},
+	{CS35L35_SP_FMT_CTL3,		0x02},
+	{CS35L35_MAG_COMP_CTL,		0x00},
+	{CS35L35_AMP_INP_DRV_CTL,	0x01},
+	{CS35L35_AMP_DIG_VOL_CTL,	0x12},
+	{CS35L35_AMP_DIG_VOL,		0x00},
+	{CS35L35_ADV_DIG_VOL,		0x00},
+	{CS35L35_PROTECT_CTL,		0x06},
+	{CS35L35_AMP_GAIN_AUD_CTL,	0x13},
+	{CS35L35_AMP_GAIN_PDM_CTL,	0x00},
+	{CS35L35_AMP_GAIN_ADV_CTL,	0x00},
+	{CS35L35_GPI_CTL,		0x00},
+	{CS35L35_BST_CVTR_V_CTL,	0x00},
+	{CS35L35_BST_PEAK_I,		0x07},
+	{CS35L35_BST_RAMP_CTL,		0x85},
+	{CS35L35_BST_CONV_COEF_1,	0x24},
+	{CS35L35_BST_CONV_COEF_2,	0x24},
+	{CS35L35_BST_CONV_SLOPE_COMP,	0x4E},
+	{CS35L35_BST_CONV_SW_FREQ,	0x04},
+	{CS35L35_CLASS_H_CTL,		0x0B},
+	{CS35L35_CLASS_H_HEADRM_CTL,	0x0B},
+	{CS35L35_CLASS_H_RELEASE_RATE,	0x08},
+	{CS35L35_CLASS_H_FET_DRIVE_CTL, 0x41},
+	{CS35L35_CLASS_H_VP_CTL,	0xC5},
+	{CS35L35_VPBR_CTL,		0x0A},
+	{CS35L35_VPBR_VOL_CTL,		0x90},
+	{CS35L35_VPBR_TIMING_CTL,	0x6A},
+	{CS35L35_VPBR_MODE_VOL_CTL,	0x00},
+	{CS35L35_SPKR_MON_CTL,		0xC0},
+	{CS35L35_IMON_SCALE_CTL,	0x30},
+	{CS35L35_AUDIN_RXLOC_CTL,	0x00},
+	{CS35L35_ADVIN_RXLOC_CTL,	0x80},
+	{CS35L35_VMON_TXLOC_CTL,	0x00},
+	{CS35L35_IMON_TXLOC_CTL,	0x80},
+	{CS35L35_VPMON_TXLOC_CTL,	0x04},
+	{CS35L35_VBSTMON_TXLOC_CTL,	0x84},
+	{CS35L35_VPBR_STATUS_TXLOC_CTL,	0x04},
+	{CS35L35_ZERO_FILL_LOC_CTL,	0x00},
+	{CS35L35_AUDIN_DEPTH_CTL,	0x0F},
+	{CS35L35_SPKMON_DEPTH_CTL,	0x0F},
+	{CS35L35_SUPMON_DEPTH_CTL,	0x0F},
+	{CS35L35_ZEROFILL_DEPTH_CTL,	0x00},
+	{CS35L35_MULT_DEV_SYNCH1,	0x02},
+	{CS35L35_MULT_DEV_SYNCH2,	0x80},
+	{CS35L35_PROT_RELEASE_CTL,	0x00},
+	{CS35L35_DIAG_MODE_REG_LOCK,	0x00},
+	{CS35L35_DIAG_MODE_CTL_1,	0x40},
+	{CS35L35_DIAG_MODE_CTL_2,	0x00},
+	{CS35L35_INT_MASK_1,		0xFF},
+	{CS35L35_INT_MASK_2,		0xFF},
+	{CS35L35_INT_MASK_3,		0xFF},
+	{CS35L35_INT_MASK_4,		0xFF},
+
+};
+
+static bool cs35l35_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS35L35_INT_STATUS_1:
+	case CS35L35_INT_STATUS_2:
+	case CS35L35_INT_STATUS_3:
+	case CS35L35_INT_STATUS_4:
+	case CS35L35_PLL_STATUS:
+	case CS35L35_OTP_TRIM_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs35l35_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS35L35_DEVID_AB ... CS35L35_PWRCTL3:
+	case CS35L35_CLK_CTL1 ... CS35L35_SP_FMT_CTL3:
+	case CS35L35_MAG_COMP_CTL ... CS35L35_AMP_GAIN_AUD_CTL:
+	case CS35L35_AMP_GAIN_PDM_CTL ... CS35L35_BST_PEAK_I:
+	case CS35L35_BST_RAMP_CTL ... CS35L35_BST_CONV_SW_FREQ:
+	case CS35L35_CLASS_H_CTL ... CS35L35_CLASS_H_VP_CTL:
+	case CS35L35_CLASS_H_STATUS:
+	case CS35L35_VPBR_CTL ... CS35L35_VPBR_MODE_VOL_CTL:
+	case CS35L35_VPBR_ATTEN_STATUS:
+	case CS35L35_SPKR_MON_CTL:
+	case CS35L35_IMON_SCALE_CTL ... CS35L35_ZEROFILL_DEPTH_CTL:
+	case CS35L35_MULT_DEV_SYNCH1 ... CS35L35_PROT_RELEASE_CTL:
+	case CS35L35_DIAG_MODE_REG_LOCK ... CS35L35_DIAG_MODE_CTL_2:
+	case CS35L35_INT_MASK_1 ... CS35L35_PLL_STATUS:
+	case CS35L35_OTP_TRIM_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs35l35_precious_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS35L35_INT_STATUS_1:
+	case CS35L35_INT_STATUS_2:
+	case CS35L35_INT_STATUS_3:
+	case CS35L35_INT_STATUS_4:
+	case CS35L35_PLL_STATUS:
+	case CS35L35_OTP_TRIM_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void cs35l35_reset(struct cs35l35_private *cs35l35)
+{
+	gpiod_set_value_cansleep(cs35l35->reset_gpio, 0);
+	usleep_range(2000, 2100);
+	gpiod_set_value_cansleep(cs35l35->reset_gpio, 1);
+	usleep_range(1000, 1100);
+}
+
+static int cs35l35_wait_for_pdn(struct cs35l35_private *cs35l35)
+{
+	int ret;
+
+	if (cs35l35->pdata.ext_bst) {
+		usleep_range(5000, 5500);
+		return 0;
+	}
+
+	reinit_completion(&cs35l35->pdn_done);
+
+	ret = wait_for_completion_timeout(&cs35l35->pdn_done,
+					  msecs_to_jiffies(100));
+	if (ret == 0) {
+		dev_err(cs35l35->dev, "PDN_DONE did not complete\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1,
+					CS35L35_MCLK_DIS_MASK,
+					0 << CS35L35_MCLK_DIS_SHIFT);
+		regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
+					CS35L35_DISCHG_FILT_MASK,
+					0 << CS35L35_DISCHG_FILT_SHIFT);
+		regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
+					CS35L35_PDN_ALL_MASK, 0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
+					CS35L35_DISCHG_FILT_MASK,
+					1 << CS35L35_DISCHG_FILT_SHIFT);
+		regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
+					  CS35L35_PDN_ALL_MASK, 1);
+
+		/* Already muted, so disable volume ramp for faster shutdown */
+		regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL,
+				   CS35L35_AMP_DIGSFT_MASK, 0);
+
+		ret = cs35l35_wait_for_pdn(cs35l35);
+
+		regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1,
+					CS35L35_MCLK_DIS_MASK,
+					1 << CS35L35_MCLK_DIS_SHIFT);
+
+		regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL,
+				   CS35L35_AMP_DIGSFT_MASK,
+				   1 << CS35L35_AMP_DIGSFT_SHIFT);
+		break;
+	default:
+		dev_err(component->dev, "Invalid event = 0x%x\n", event);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int cs35l35_main_amp_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
+	unsigned int reg[4];
+	int i;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (cs35l35->pdata.bst_pdn_fet_on)
+			regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+				CS35L35_PDN_BST_MASK,
+				0 << CS35L35_PDN_BST_FETON_SHIFT);
+		else
+			regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+				CS35L35_PDN_BST_MASK,
+				0 << CS35L35_PDN_BST_FETOFF_SHIFT);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(5000, 5100);
+		/* If in PDM mode we must use VP for Voltage control */
+		if (cs35l35->pdm_mode)
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_BST_CVTR_V_CTL,
+					CS35L35_BST_CTL_MASK,
+					0 << CS35L35_BST_CTL_SHIFT);
+
+		regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL,
+			CS35L35_AMP_MUTE_MASK, 0);
+
+		for (i = 0; i < 2; i++)
+			regmap_bulk_read(cs35l35->regmap, CS35L35_INT_STATUS_1,
+					&reg, ARRAY_SIZE(reg));
+
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL,
+				CS35L35_AMP_MUTE_MASK,
+				1 << CS35L35_AMP_MUTE_SHIFT);
+		if (cs35l35->pdata.bst_pdn_fet_on)
+			regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+				CS35L35_PDN_BST_MASK,
+				1 << CS35L35_PDN_BST_FETON_SHIFT);
+		else
+			regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+				CS35L35_PDN_BST_MASK,
+				1 << CS35L35_PDN_BST_FETOFF_SHIFT);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		usleep_range(5000, 5100);
+		/*
+		 * If PDM mode we should switch back to pdata value
+		 * for Voltage control when we go down
+		 */
+		if (cs35l35->pdm_mode)
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_BST_CVTR_V_CTL,
+					CS35L35_BST_CTL_MASK,
+					cs35l35->pdata.bst_vctl
+					<< CS35L35_BST_CTL_SHIFT);
+
+		break;
+	default:
+		dev_err(component->dev, "Invalid event = 0x%x\n", event);
+	}
+	return 0;
+}
+
+static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1);
+static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 50, 0);
+
+static const struct snd_kcontrol_new cs35l35_aud_controls[] = {
+	SOC_SINGLE_SX_TLV("Digital Audio Volume", CS35L35_AMP_DIG_VOL,
+		      0, 0x34, 0xE4, dig_vol_tlv),
+	SOC_SINGLE_TLV("Analog Audio Volume", CS35L35_AMP_GAIN_AUD_CTL, 0, 19, 0,
+			amp_gain_tlv),
+	SOC_SINGLE_TLV("PDM Volume", CS35L35_AMP_GAIN_PDM_CTL, 0, 19, 0,
+			amp_gain_tlv),
+};
+
+static const struct snd_kcontrol_new cs35l35_adv_controls[] = {
+	SOC_SINGLE_SX_TLV("Digital Advisory Volume", CS35L35_ADV_DIG_VOL,
+		      0, 0x34, 0xE4, dig_vol_tlv),
+	SOC_SINGLE_TLV("Analog Advisory Volume", CS35L35_AMP_GAIN_ADV_CTL, 0, 19, 0,
+			amp_gain_tlv),
+};
+
+static const struct snd_soc_dapm_widget cs35l35_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L35_PWRCTL3, 1, 1,
+				cs35l35_sdin_event, SND_SOC_DAPM_PRE_PMU |
+				SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L35_PWRCTL3, 2, 1),
+
+	SND_SOC_DAPM_OUTPUT("SPK"),
+
+	SND_SOC_DAPM_INPUT("VP"),
+	SND_SOC_DAPM_INPUT("VBST"),
+	SND_SOC_DAPM_INPUT("ISENSE"),
+	SND_SOC_DAPM_INPUT("VSENSE"),
+
+	SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L35_PWRCTL2, 7, 1),
+	SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L35_PWRCTL2, 6, 1),
+	SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L35_PWRCTL3, 3, 1),
+	SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L35_PWRCTL3, 4, 1),
+	SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L35_PWRCTL2, 5, 1),
+
+	SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L35_PWRCTL2, 0, 1, NULL, 0,
+		cs35l35_main_amp_event, SND_SOC_DAPM_PRE_PMU |
+				SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU |
+				SND_SOC_DAPM_PRE_PMD),
+};
+
+static const struct snd_soc_dapm_route cs35l35_audio_map[] = {
+	{"VPMON ADC", NULL, "VP"},
+	{"VBSTMON ADC", NULL, "VBST"},
+	{"IMON ADC", NULL, "ISENSE"},
+	{"VMON ADC", NULL, "VSENSE"},
+	{"SDOUT", NULL, "IMON ADC"},
+	{"SDOUT", NULL, "VMON ADC"},
+	{"SDOUT", NULL, "VBSTMON ADC"},
+	{"SDOUT", NULL, "VPMON ADC"},
+	{"AMP Capture", NULL, "SDOUT"},
+
+	{"SDIN", NULL, "AMP Playback"},
+	{"CLASS H", NULL, "SDIN"},
+	{"Main AMP", NULL, "CLASS H"},
+	{"SPK", NULL, "Main AMP"},
+};
+
+static int cs35l35_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1,
+				    CS35L35_MS_MASK, 1 << CS35L35_MS_SHIFT);
+		cs35l35->slave_mode = false;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1,
+				    CS35L35_MS_MASK, 0 << CS35L35_MS_SHIFT);
+		cs35l35->slave_mode = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		cs35l35->i2s_mode = true;
+		cs35l35->pdm_mode = false;
+		break;
+	case SND_SOC_DAIFMT_PDM:
+		cs35l35->pdm_mode = true;
+		cs35l35->i2s_mode = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+struct cs35l35_sysclk_config {
+	int sysclk;
+	int srate;
+	u8 clk_cfg;
+};
+
+static struct cs35l35_sysclk_config cs35l35_clk_ctl[] = {
+
+	/* SYSCLK, Sample Rate, Serial Port Cfg */
+	{5644800, 44100, 0x00},
+	{5644800, 88200, 0x40},
+	{6144000, 48000, 0x10},
+	{6144000, 96000, 0x50},
+	{11289600, 44100, 0x01},
+	{11289600, 88200, 0x41},
+	{11289600, 176400, 0x81},
+	{12000000, 44100, 0x03},
+	{12000000, 48000, 0x13},
+	{12000000, 88200, 0x43},
+	{12000000, 96000, 0x53},
+	{12000000, 176400, 0x83},
+	{12000000, 192000, 0x93},
+	{12288000, 48000, 0x11},
+	{12288000, 96000, 0x51},
+	{12288000, 192000, 0x91},
+	{13000000, 44100, 0x07},
+	{13000000, 48000, 0x17},
+	{13000000, 88200, 0x47},
+	{13000000, 96000, 0x57},
+	{13000000, 176400, 0x87},
+	{13000000, 192000, 0x97},
+	{22579200, 44100, 0x02},
+	{22579200, 88200, 0x42},
+	{22579200, 176400, 0x82},
+	{24000000, 44100, 0x0B},
+	{24000000, 48000, 0x1B},
+	{24000000, 88200, 0x4B},
+	{24000000, 96000, 0x5B},
+	{24000000, 176400, 0x8B},
+	{24000000, 192000, 0x9B},
+	{24576000, 48000, 0x12},
+	{24576000, 96000, 0x52},
+	{24576000, 192000, 0x92},
+	{26000000, 44100, 0x0F},
+	{26000000, 48000, 0x1F},
+	{26000000, 88200, 0x4F},
+	{26000000, 96000, 0x5F},
+	{26000000, 176400, 0x8F},
+	{26000000, 192000, 0x9F},
+};
+
+static int cs35l35_get_clk_config(int sysclk, int srate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cs35l35_clk_ctl); i++) {
+		if (cs35l35_clk_ctl[i].sysclk == sysclk &&
+			cs35l35_clk_ctl[i].srate == srate)
+			return cs35l35_clk_ctl[i].clk_cfg;
+	}
+	return -EINVAL;
+}
+
+static int cs35l35_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
+	struct classh_cfg *classh = &cs35l35->pdata.classh_algo;
+	int srate = params_rate(params);
+	int ret = 0;
+	u8 sp_sclks;
+	int audin_format;
+	int errata_chk;
+
+	int clk_ctl = cs35l35_get_clk_config(cs35l35->sysclk, srate);
+
+	if (clk_ctl < 0) {
+		dev_err(component->dev, "Invalid CLK:Rate %d:%d\n",
+			cs35l35->sysclk, srate);
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL2,
+			  CS35L35_CLK_CTL2_MASK, clk_ctl);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set port config %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * Rev A0 Errata
+	 * When configured for the weak-drive detection path (CH_WKFET_DIS = 0)
+	 * the Class H algorithm does not enable weak-drive operation for
+	 * nonzero values of CH_WKFET_DELAY if SP_RATE = 01 or 10
+	 */
+	errata_chk = clk_ctl & CS35L35_SP_RATE_MASK;
+
+	if (classh->classh_wk_fet_disable == 0x00 &&
+		(errata_chk == 0x01 || errata_chk == 0x03)) {
+		ret = regmap_update_bits(cs35l35->regmap,
+					CS35L35_CLASS_H_FET_DRIVE_CTL,
+					CS35L35_CH_WKFET_DEL_MASK,
+					0 << CS35L35_CH_WKFET_DEL_SHIFT);
+		if (ret != 0) {
+			dev_err(component->dev, "Failed to set fet config %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	/*
+	 * You can pull more Monitor data from the SDOUT pin than going to SDIN
+	 * Just make sure your SCLK is fast enough to fill the frame
+	 */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		switch (params_width(params)) {
+		case 8:
+			audin_format = CS35L35_SDIN_DEPTH_8;
+			break;
+		case 16:
+			audin_format = CS35L35_SDIN_DEPTH_16;
+			break;
+		case 24:
+			audin_format = CS35L35_SDIN_DEPTH_24;
+			break;
+		default:
+			dev_err(component->dev, "Unsupported Width %d\n",
+				params_width(params));
+			return -EINVAL;
+		}
+		regmap_update_bits(cs35l35->regmap,
+				CS35L35_AUDIN_DEPTH_CTL,
+				CS35L35_AUDIN_DEPTH_MASK,
+				audin_format <<
+				CS35L35_AUDIN_DEPTH_SHIFT);
+		if (cs35l35->pdata.stereo) {
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_AUDIN_DEPTH_CTL,
+					CS35L35_ADVIN_DEPTH_MASK,
+					audin_format <<
+					CS35L35_ADVIN_DEPTH_SHIFT);
+		}
+	}
+
+	if (cs35l35->i2s_mode) {
+		/* We have to take the SCLK to derive num sclks
+		 * to configure the CLOCK_CTL3 register correctly
+		 */
+		if ((cs35l35->sclk / srate) % 4) {
+			dev_err(component->dev, "Unsupported sclk/fs ratio %d:%d\n",
+					cs35l35->sclk, srate);
+			return -EINVAL;
+		}
+		sp_sclks = ((cs35l35->sclk / srate) / 4) - 1;
+
+		/* Only certain ratios are supported in I2S Slave Mode */
+		if (cs35l35->slave_mode) {
+			switch (sp_sclks) {
+			case CS35L35_SP_SCLKS_32FS:
+			case CS35L35_SP_SCLKS_48FS:
+			case CS35L35_SP_SCLKS_64FS:
+				break;
+			default:
+				dev_err(component->dev, "ratio not supported\n");
+				return -EINVAL;
+			}
+		} else {
+			/* Only certain ratios supported in I2S MASTER Mode */
+			switch (sp_sclks) {
+			case CS35L35_SP_SCLKS_32FS:
+			case CS35L35_SP_SCLKS_64FS:
+				break;
+			default:
+				dev_err(component->dev, "ratio not supported\n");
+				return -EINVAL;
+			}
+		}
+		ret = regmap_update_bits(cs35l35->regmap,
+					CS35L35_CLK_CTL3,
+					CS35L35_SP_SCLKS_MASK, sp_sclks <<
+					CS35L35_SP_SCLKS_SHIFT);
+		if (ret != 0) {
+			dev_err(component->dev, "Failed to set fsclk %d\n", ret);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static const unsigned int cs35l35_src_rates[] = {
+	44100, 48000, 88200, 96000, 176400, 192000
+};
+
+static const struct snd_pcm_hw_constraint_list cs35l35_constraints = {
+	.count  = ARRAY_SIZE(cs35l35_src_rates),
+	.list   = cs35l35_src_rates,
+};
+
+static int cs35l35_pcm_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
+
+	if (!substream->runtime)
+		return 0;
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE, &cs35l35_constraints);
+
+	regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL,
+					CS35L35_PDM_MODE_MASK,
+					0 << CS35L35_PDM_MODE_SHIFT);
+
+	return 0;
+}
+
+static const unsigned int cs35l35_pdm_rates[] = {
+	44100, 48000, 88200, 96000
+};
+
+static const struct snd_pcm_hw_constraint_list cs35l35_pdm_constraints = {
+	.count  = ARRAY_SIZE(cs35l35_pdm_rates),
+	.list   = cs35l35_pdm_rates,
+};
+
+static int cs35l35_pdm_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
+
+	if (!substream->runtime)
+		return 0;
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&cs35l35_pdm_constraints);
+
+	regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL,
+					CS35L35_PDM_MODE_MASK,
+					1 << CS35L35_PDM_MODE_SHIFT);
+
+	return 0;
+}
+
+static int cs35l35_dai_set_sysclk(struct snd_soc_dai *dai,
+				int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
+
+	/* Need the SCLK Frequency regardless of sysclk source for I2S */
+	cs35l35->sclk = freq;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops cs35l35_ops = {
+	.startup = cs35l35_pcm_startup,
+	.set_fmt = cs35l35_set_dai_fmt,
+	.hw_params = cs35l35_hw_params,
+	.set_sysclk = cs35l35_dai_set_sysclk,
+};
+
+static const struct snd_soc_dai_ops cs35l35_pdm_ops = {
+	.startup = cs35l35_pdm_startup,
+	.set_fmt = cs35l35_set_dai_fmt,
+	.hw_params = cs35l35_hw_params,
+};
+
+static struct snd_soc_dai_driver cs35l35_dai[] = {
+	{
+		.name = "cs35l35-pcm",
+		.id = 0,
+		.playback = {
+			.stream_name = "AMP Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS35L35_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AMP Capture",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS35L35_FORMATS,
+		},
+		.ops = &cs35l35_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "cs35l35-pdm",
+		.id = 1,
+		.playback = {
+			.stream_name = "PDM Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS35L35_FORMATS,
+		},
+		.ops = &cs35l35_pdm_ops,
+	},
+};
+
+static int cs35l35_component_set_sysclk(struct snd_soc_component *component,
+				int clk_id, int source, unsigned int freq,
+				int dir)
+{
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
+	int clksrc;
+	int ret = 0;
+
+	switch (clk_id) {
+	case 0:
+		clksrc = CS35L35_CLK_SOURCE_MCLK;
+		break;
+	case 1:
+		clksrc = CS35L35_CLK_SOURCE_SCLK;
+		break;
+	case 2:
+		clksrc = CS35L35_CLK_SOURCE_PDM;
+		break;
+	default:
+		dev_err(component->dev, "Invalid CLK Source\n");
+		return -EINVAL;
+	}
+
+	switch (freq) {
+	case 5644800:
+	case 6144000:
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 13000000:
+	case 22579200:
+	case 24000000:
+	case 24576000:
+	case 26000000:
+		cs35l35->sysclk = freq;
+		break;
+	default:
+		dev_err(component->dev, "Invalid CLK Frequency Input : %d\n", freq);
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1,
+				CS35L35_CLK_SOURCE_MASK,
+				clksrc << CS35L35_CLK_SOURCE_SHIFT);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set sysclk %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int cs35l35_boost_inductor(struct cs35l35_private *cs35l35,
+				  int inductor)
+{
+	struct regmap *regmap = cs35l35->regmap;
+	unsigned int bst_ipk = 0;
+
+	/*
+	 * Digital Boost Converter Configuration for feedback,
+	 * ramping, switching frequency, and estimation block seeding.
+	 */
+
+	regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+			   CS35L35_BST_CONV_SWFREQ_MASK, 0x00);
+
+	regmap_read(regmap, CS35L35_BST_PEAK_I, &bst_ipk);
+	bst_ipk &= CS35L35_BST_IPK_MASK;
+
+	switch (inductor) {
+	case 1000: /* 1 uH */
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x24);
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x24);
+		regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+				   CS35L35_BST_CONV_LBST_MASK, 0x00);
+
+		if (bst_ipk < 0x04)
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B);
+		else
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x4E);
+		break;
+	case 1200: /* 1.2 uH */
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x20);
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x20);
+		regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+				   CS35L35_BST_CONV_LBST_MASK, 0x01);
+
+		if (bst_ipk < 0x04)
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B);
+		else
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x47);
+		break;
+	case 1500: /* 1.5uH */
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x20);
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x20);
+		regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+				   CS35L35_BST_CONV_LBST_MASK, 0x02);
+
+		if (bst_ipk < 0x04)
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B);
+		else
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x3C);
+		break;
+	case 2200: /* 2.2uH */
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x19);
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x25);
+		regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+				   CS35L35_BST_CONV_LBST_MASK, 0x03);
+
+		if (bst_ipk < 0x04)
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B);
+		else
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x23);
+		break;
+	default:
+		dev_err(cs35l35->dev, "Invalid Inductor Value %d uH\n",
+			inductor);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cs35l35_component_probe(struct snd_soc_component *component)
+{
+	struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component);
+	struct classh_cfg *classh = &cs35l35->pdata.classh_algo;
+	struct monitor_cfg *monitor_config = &cs35l35->pdata.mon_cfg;
+	int ret;
+
+	/* Set Platform Data */
+	if (cs35l35->pdata.bst_vctl)
+		regmap_update_bits(cs35l35->regmap, CS35L35_BST_CVTR_V_CTL,
+				CS35L35_BST_CTL_MASK,
+				cs35l35->pdata.bst_vctl);
+
+	if (cs35l35->pdata.bst_ipk)
+		regmap_update_bits(cs35l35->regmap, CS35L35_BST_PEAK_I,
+				CS35L35_BST_IPK_MASK,
+				cs35l35->pdata.bst_ipk <<
+				CS35L35_BST_IPK_SHIFT);
+
+	ret = cs35l35_boost_inductor(cs35l35, cs35l35->pdata.boost_ind);
+	if (ret)
+		return ret;
+
+	if (cs35l35->pdata.gain_zc)
+		regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL,
+				CS35L35_AMP_GAIN_ZC_MASK,
+				cs35l35->pdata.gain_zc <<
+				CS35L35_AMP_GAIN_ZC_SHIFT);
+
+	if (cs35l35->pdata.aud_channel)
+		regmap_update_bits(cs35l35->regmap,
+				CS35L35_AUDIN_RXLOC_CTL,
+				CS35L35_AUD_IN_LR_MASK,
+				cs35l35->pdata.aud_channel <<
+				CS35L35_AUD_IN_LR_SHIFT);
+
+	if (cs35l35->pdata.stereo) {
+		regmap_update_bits(cs35l35->regmap,
+				CS35L35_ADVIN_RXLOC_CTL,
+				CS35L35_ADV_IN_LR_MASK,
+				cs35l35->pdata.adv_channel <<
+				CS35L35_ADV_IN_LR_SHIFT);
+		if (cs35l35->pdata.shared_bst)
+			regmap_update_bits(cs35l35->regmap, CS35L35_CLASS_H_CTL,
+					CS35L35_CH_STEREO_MASK,
+					1 << CS35L35_CH_STEREO_SHIFT);
+		ret = snd_soc_add_component_controls(component, cs35l35_adv_controls,
+					ARRAY_SIZE(cs35l35_adv_controls));
+		if (ret)
+			return ret;
+	}
+
+	if (cs35l35->pdata.sp_drv_str)
+		regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1,
+				CS35L35_SP_DRV_MASK,
+				cs35l35->pdata.sp_drv_str <<
+				CS35L35_SP_DRV_SHIFT);
+	if (cs35l35->pdata.sp_drv_unused)
+		regmap_update_bits(cs35l35->regmap, CS35L35_SP_FMT_CTL3,
+				   CS35L35_SP_I2S_DRV_MASK,
+				   cs35l35->pdata.sp_drv_unused <<
+				   CS35L35_SP_I2S_DRV_SHIFT);
+
+	if (classh->classh_algo_enable) {
+		if (classh->classh_bst_override)
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_CLASS_H_CTL,
+					CS35L35_CH_BST_OVR_MASK,
+					classh->classh_bst_override <<
+					CS35L35_CH_BST_OVR_SHIFT);
+		if (classh->classh_bst_max_limit)
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_CLASS_H_CTL,
+					CS35L35_CH_BST_LIM_MASK,
+					classh->classh_bst_max_limit <<
+					CS35L35_CH_BST_LIM_SHIFT);
+		if (classh->classh_mem_depth)
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_CLASS_H_CTL,
+					CS35L35_CH_MEM_DEPTH_MASK,
+					classh->classh_mem_depth <<
+					CS35L35_CH_MEM_DEPTH_SHIFT);
+		if (classh->classh_headroom)
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_CLASS_H_HEADRM_CTL,
+					CS35L35_CH_HDRM_CTL_MASK,
+					classh->classh_headroom <<
+					CS35L35_CH_HDRM_CTL_SHIFT);
+		if (classh->classh_release_rate)
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_CLASS_H_RELEASE_RATE,
+					CS35L35_CH_REL_RATE_MASK,
+					classh->classh_release_rate <<
+					CS35L35_CH_REL_RATE_SHIFT);
+		if (classh->classh_wk_fet_disable)
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_CLASS_H_FET_DRIVE_CTL,
+					CS35L35_CH_WKFET_DIS_MASK,
+					classh->classh_wk_fet_disable <<
+					CS35L35_CH_WKFET_DIS_SHIFT);
+		if (classh->classh_wk_fet_delay)
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_CLASS_H_FET_DRIVE_CTL,
+					CS35L35_CH_WKFET_DEL_MASK,
+					classh->classh_wk_fet_delay <<
+					CS35L35_CH_WKFET_DEL_SHIFT);
+		if (classh->classh_wk_fet_thld)
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_CLASS_H_FET_DRIVE_CTL,
+					CS35L35_CH_WKFET_THLD_MASK,
+					classh->classh_wk_fet_thld <<
+					CS35L35_CH_WKFET_THLD_SHIFT);
+		if (classh->classh_vpch_auto)
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_CLASS_H_VP_CTL,
+					CS35L35_CH_VP_AUTO_MASK,
+					classh->classh_vpch_auto <<
+					CS35L35_CH_VP_AUTO_SHIFT);
+		if (classh->classh_vpch_rate)
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_CLASS_H_VP_CTL,
+					CS35L35_CH_VP_RATE_MASK,
+					classh->classh_vpch_rate <<
+					CS35L35_CH_VP_RATE_SHIFT);
+		if (classh->classh_vpch_man)
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_CLASS_H_VP_CTL,
+					CS35L35_CH_VP_MAN_MASK,
+					classh->classh_vpch_man <<
+					CS35L35_CH_VP_MAN_SHIFT);
+	}
+
+	if (monitor_config->is_present) {
+		if (monitor_config->vmon_specs) {
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_SPKMON_DEPTH_CTL,
+					CS35L35_VMON_DEPTH_MASK,
+					monitor_config->vmon_dpth <<
+					CS35L35_VMON_DEPTH_SHIFT);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_VMON_TXLOC_CTL,
+					CS35L35_MON_TXLOC_MASK,
+					monitor_config->vmon_loc <<
+					CS35L35_MON_TXLOC_SHIFT);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_VMON_TXLOC_CTL,
+					CS35L35_MON_FRM_MASK,
+					monitor_config->vmon_frm <<
+					CS35L35_MON_FRM_SHIFT);
+		}
+		if (monitor_config->imon_specs) {
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_SPKMON_DEPTH_CTL,
+					CS35L35_IMON_DEPTH_MASK,
+					monitor_config->imon_dpth <<
+					CS35L35_IMON_DEPTH_SHIFT);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_IMON_TXLOC_CTL,
+					CS35L35_MON_TXLOC_MASK,
+					monitor_config->imon_loc <<
+					CS35L35_MON_TXLOC_SHIFT);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_IMON_TXLOC_CTL,
+					CS35L35_MON_FRM_MASK,
+					monitor_config->imon_frm <<
+					CS35L35_MON_FRM_SHIFT);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_IMON_SCALE_CTL,
+					CS35L35_IMON_SCALE_MASK,
+					monitor_config->imon_scale <<
+					CS35L35_IMON_SCALE_SHIFT);
+		}
+		if (monitor_config->vpmon_specs) {
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_SUPMON_DEPTH_CTL,
+					CS35L35_VPMON_DEPTH_MASK,
+					monitor_config->vpmon_dpth <<
+					CS35L35_VPMON_DEPTH_SHIFT);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_VPMON_TXLOC_CTL,
+					CS35L35_MON_TXLOC_MASK,
+					monitor_config->vpmon_loc <<
+					CS35L35_MON_TXLOC_SHIFT);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_VPMON_TXLOC_CTL,
+					CS35L35_MON_FRM_MASK,
+					monitor_config->vpmon_frm <<
+					CS35L35_MON_FRM_SHIFT);
+		}
+		if (monitor_config->vbstmon_specs) {
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_SUPMON_DEPTH_CTL,
+					CS35L35_VBSTMON_DEPTH_MASK,
+					monitor_config->vpmon_dpth <<
+					CS35L35_VBSTMON_DEPTH_SHIFT);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_VBSTMON_TXLOC_CTL,
+					CS35L35_MON_TXLOC_MASK,
+					monitor_config->vbstmon_loc <<
+					CS35L35_MON_TXLOC_SHIFT);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_VBSTMON_TXLOC_CTL,
+					CS35L35_MON_FRM_MASK,
+					monitor_config->vbstmon_frm <<
+					CS35L35_MON_FRM_SHIFT);
+		}
+		if (monitor_config->vpbrstat_specs) {
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_SUPMON_DEPTH_CTL,
+					CS35L35_VPBRSTAT_DEPTH_MASK,
+					monitor_config->vpbrstat_dpth <<
+					CS35L35_VPBRSTAT_DEPTH_SHIFT);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_VPBR_STATUS_TXLOC_CTL,
+					CS35L35_MON_TXLOC_MASK,
+					monitor_config->vpbrstat_loc <<
+					CS35L35_MON_TXLOC_SHIFT);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_VPBR_STATUS_TXLOC_CTL,
+					CS35L35_MON_FRM_MASK,
+					monitor_config->vpbrstat_frm <<
+					CS35L35_MON_FRM_SHIFT);
+		}
+		if (monitor_config->zerofill_specs) {
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_SUPMON_DEPTH_CTL,
+					CS35L35_ZEROFILL_DEPTH_MASK,
+					monitor_config->zerofill_dpth <<
+					CS35L35_ZEROFILL_DEPTH_SHIFT);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_ZERO_FILL_LOC_CTL,
+					CS35L35_MON_TXLOC_MASK,
+					monitor_config->zerofill_loc <<
+					CS35L35_MON_TXLOC_SHIFT);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_ZERO_FILL_LOC_CTL,
+					CS35L35_MON_FRM_MASK,
+					monitor_config->zerofill_frm <<
+					CS35L35_MON_FRM_SHIFT);
+		}
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_cs35l35 = {
+	.probe			= cs35l35_component_probe,
+	.set_sysclk		= cs35l35_component_set_sysclk,
+	.dapm_widgets		= cs35l35_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs35l35_dapm_widgets),
+	.dapm_routes		= cs35l35_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs35l35_audio_map),
+	.controls		= cs35l35_aud_controls,
+	.num_controls		= ARRAY_SIZE(cs35l35_aud_controls),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static struct regmap_config cs35l35_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = CS35L35_MAX_REGISTER,
+	.reg_defaults = cs35l35_reg,
+	.num_reg_defaults = ARRAY_SIZE(cs35l35_reg),
+	.volatile_reg = cs35l35_volatile_register,
+	.readable_reg = cs35l35_readable_register,
+	.precious_reg = cs35l35_precious_register,
+	.cache_type = REGCACHE_RBTREE,
+	.use_single_rw = true,
+};
+
+static irqreturn_t cs35l35_irq(int irq, void *data)
+{
+	struct cs35l35_private *cs35l35 = data;
+	unsigned int sticky1, sticky2, sticky3, sticky4;
+	unsigned int mask1, mask2, mask3, mask4, current1;
+
+	/* ack the irq by reading all status registers */
+	regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_4, &sticky4);
+	regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_3, &sticky3);
+	regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_2, &sticky2);
+	regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, &sticky1);
+
+	regmap_read(cs35l35->regmap, CS35L35_INT_MASK_4, &mask4);
+	regmap_read(cs35l35->regmap, CS35L35_INT_MASK_3, &mask3);
+	regmap_read(cs35l35->regmap, CS35L35_INT_MASK_2, &mask2);
+	regmap_read(cs35l35->regmap, CS35L35_INT_MASK_1, &mask1);
+
+	/* Check to see if unmasked bits are active */
+	if (!(sticky1 & ~mask1) && !(sticky2 & ~mask2) && !(sticky3 & ~mask3)
+			&& !(sticky4 & ~mask4))
+		return IRQ_NONE;
+
+	if (sticky2 & CS35L35_PDN_DONE)
+		complete(&cs35l35->pdn_done);
+
+	/* read the current values */
+	regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, &current1);
+
+	/* handle the interrupts */
+	if (sticky1 & CS35L35_CAL_ERR) {
+		dev_crit(cs35l35->dev, "Calibration Error\n");
+
+		/* error is no longer asserted; safe to reset */
+		if (!(current1 & CS35L35_CAL_ERR)) {
+			pr_debug("%s : Cal error release\n", __func__);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_PROT_RELEASE_CTL,
+					CS35L35_CAL_ERR_RLS, 0);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_PROT_RELEASE_CTL,
+					CS35L35_CAL_ERR_RLS,
+					CS35L35_CAL_ERR_RLS);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_PROT_RELEASE_CTL,
+					CS35L35_CAL_ERR_RLS, 0);
+		}
+	}
+
+	if (sticky1 & CS35L35_AMP_SHORT) {
+		dev_crit(cs35l35->dev, "AMP Short Error\n");
+		/* error is no longer asserted; safe to reset */
+		if (!(current1 & CS35L35_AMP_SHORT)) {
+			dev_dbg(cs35l35->dev, "Amp short error release\n");
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_PROT_RELEASE_CTL,
+					CS35L35_SHORT_RLS, 0);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_PROT_RELEASE_CTL,
+					CS35L35_SHORT_RLS,
+					CS35L35_SHORT_RLS);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_PROT_RELEASE_CTL,
+					CS35L35_SHORT_RLS, 0);
+		}
+	}
+
+	if (sticky1 & CS35L35_OTW) {
+		dev_warn(cs35l35->dev, "Over temperature warning\n");
+
+		/* error is no longer asserted; safe to reset */
+		if (!(current1 & CS35L35_OTW)) {
+			dev_dbg(cs35l35->dev, "Over temperature warn release\n");
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_PROT_RELEASE_CTL,
+					CS35L35_OTW_RLS, 0);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_PROT_RELEASE_CTL,
+					CS35L35_OTW_RLS,
+					CS35L35_OTW_RLS);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_PROT_RELEASE_CTL,
+					CS35L35_OTW_RLS, 0);
+		}
+	}
+
+	if (sticky1 & CS35L35_OTE) {
+		dev_crit(cs35l35->dev, "Over temperature error\n");
+		/* error is no longer asserted; safe to reset */
+		if (!(current1 & CS35L35_OTE)) {
+			dev_dbg(cs35l35->dev, "Over temperature error release\n");
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_PROT_RELEASE_CTL,
+					CS35L35_OTE_RLS, 0);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_PROT_RELEASE_CTL,
+					CS35L35_OTE_RLS,
+					CS35L35_OTE_RLS);
+			regmap_update_bits(cs35l35->regmap,
+					CS35L35_PROT_RELEASE_CTL,
+					CS35L35_OTE_RLS, 0);
+		}
+	}
+
+	if (sticky3 & CS35L35_BST_HIGH) {
+		dev_crit(cs35l35->dev, "VBST error: powering off!\n");
+		regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+			CS35L35_PDN_AMP, CS35L35_PDN_AMP);
+		regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
+			CS35L35_PDN_ALL, CS35L35_PDN_ALL);
+	}
+
+	if (sticky3 & CS35L35_LBST_SHORT) {
+		dev_crit(cs35l35->dev, "LBST error: powering off!\n");
+		regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+			CS35L35_PDN_AMP, CS35L35_PDN_AMP);
+		regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
+			CS35L35_PDN_ALL, CS35L35_PDN_ALL);
+	}
+
+	if (sticky2 & CS35L35_VPBR_ERR)
+		dev_dbg(cs35l35->dev, "Error: Reactive Brownout\n");
+
+	if (sticky4 & CS35L35_VMON_OVFL)
+		dev_dbg(cs35l35->dev, "Error: VMON overflow\n");
+
+	if (sticky4 & CS35L35_IMON_OVFL)
+		dev_dbg(cs35l35->dev, "Error: IMON overflow\n");
+
+	return IRQ_HANDLED;
+}
+
+
+static int cs35l35_handle_of_data(struct i2c_client *i2c_client,
+				struct cs35l35_platform_data *pdata)
+{
+	struct device_node *np = i2c_client->dev.of_node;
+	struct device_node *classh, *signal_format;
+	struct classh_cfg *classh_config = &pdata->classh_algo;
+	struct monitor_cfg *monitor_config = &pdata->mon_cfg;
+	unsigned int val32 = 0;
+	u8 monitor_array[4];
+	const int imon_array_size = ARRAY_SIZE(monitor_array);
+	const int mon_array_size = imon_array_size - 1;
+	int ret = 0;
+
+	if (!np)
+		return 0;
+
+	pdata->bst_pdn_fet_on = of_property_read_bool(np,
+					"cirrus,boost-pdn-fet-on");
+
+	ret = of_property_read_u32(np, "cirrus,boost-ctl-millivolt", &val32);
+	if (ret >= 0) {
+		if (val32 < 2600 || val32 > 9000) {
+			dev_err(&i2c_client->dev,
+				"Invalid Boost Voltage %d mV\n", val32);
+			return -EINVAL;
+		}
+		pdata->bst_vctl = ((val32 - 2600) / 100) + 1;
+	}
+
+	ret = of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val32);
+	if (ret >= 0) {
+		if (val32 < 1680 || val32 > 4480) {
+			dev_err(&i2c_client->dev,
+				"Invalid Boost Peak Current %u mA\n", val32);
+			return -EINVAL;
+		}
+
+		pdata->bst_ipk = ((val32 - 1680) / 110) | CS35L35_VALID_PDATA;
+	}
+
+	ret = of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val32);
+	if (ret >= 0) {
+		pdata->boost_ind = val32;
+	} else {
+		dev_err(&i2c_client->dev, "Inductor not specified.\n");
+		return -EINVAL;
+	}
+
+	if (of_property_read_u32(np, "cirrus,sp-drv-strength", &val32) >= 0)
+		pdata->sp_drv_str = val32;
+	if (of_property_read_u32(np, "cirrus,sp-drv-unused", &val32) >= 0)
+		pdata->sp_drv_unused = val32 | CS35L35_VALID_PDATA;
+
+	pdata->stereo = of_property_read_bool(np, "cirrus,stereo-config");
+
+	if (pdata->stereo) {
+		ret = of_property_read_u32(np, "cirrus,audio-channel", &val32);
+		if (ret >= 0)
+			pdata->aud_channel = val32;
+
+		ret = of_property_read_u32(np, "cirrus,advisory-channel",
+					   &val32);
+		if (ret >= 0)
+			pdata->adv_channel = val32;
+
+		pdata->shared_bst = of_property_read_bool(np,
+						"cirrus,shared-boost");
+	}
+
+	pdata->ext_bst = of_property_read_bool(np, "cirrus,external-boost");
+
+	pdata->gain_zc = of_property_read_bool(np, "cirrus,amp-gain-zc");
+
+	classh = of_get_child_by_name(np, "cirrus,classh-internal-algo");
+	classh_config->classh_algo_enable = classh ? true : false;
+
+	if (classh_config->classh_algo_enable) {
+		classh_config->classh_bst_override =
+			of_property_read_bool(np, "cirrus,classh-bst-overide");
+
+		ret = of_property_read_u32(classh,
+					   "cirrus,classh-bst-max-limit",
+					   &val32);
+		if (ret >= 0) {
+			val32 |= CS35L35_VALID_PDATA;
+			classh_config->classh_bst_max_limit = val32;
+		}
+
+		ret = of_property_read_u32(classh,
+					   "cirrus,classh-bst-max-limit",
+					   &val32);
+		if (ret >= 0) {
+			val32 |= CS35L35_VALID_PDATA;
+			classh_config->classh_bst_max_limit = val32;
+		}
+
+		ret = of_property_read_u32(classh, "cirrus,classh-mem-depth",
+					   &val32);
+		if (ret >= 0) {
+			val32 |= CS35L35_VALID_PDATA;
+			classh_config->classh_mem_depth = val32;
+		}
+
+		ret = of_property_read_u32(classh, "cirrus,classh-release-rate",
+					   &val32);
+		if (ret >= 0)
+			classh_config->classh_release_rate = val32;
+
+		ret = of_property_read_u32(classh, "cirrus,classh-headroom",
+					   &val32);
+		if (ret >= 0) {
+			val32 |= CS35L35_VALID_PDATA;
+			classh_config->classh_headroom = val32;
+		}
+
+		ret = of_property_read_u32(classh,
+					   "cirrus,classh-wk-fet-disable",
+					   &val32);
+		if (ret >= 0)
+			classh_config->classh_wk_fet_disable = val32;
+
+		ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-delay",
+					   &val32);
+		if (ret >= 0) {
+			val32 |= CS35L35_VALID_PDATA;
+			classh_config->classh_wk_fet_delay = val32;
+		}
+
+		ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-thld",
+					   &val32);
+		if (ret >= 0)
+			classh_config->classh_wk_fet_thld = val32;
+
+		ret = of_property_read_u32(classh, "cirrus,classh-vpch-auto",
+					   &val32);
+		if (ret >= 0) {
+			val32 |= CS35L35_VALID_PDATA;
+			classh_config->classh_vpch_auto = val32;
+		}
+
+		ret = of_property_read_u32(classh, "cirrus,classh-vpch-rate",
+					   &val32);
+		if (ret >= 0) {
+			val32 |= CS35L35_VALID_PDATA;
+			classh_config->classh_vpch_rate = val32;
+		}
+
+		ret = of_property_read_u32(classh, "cirrus,classh-vpch-man",
+					   &val32);
+		if (ret >= 0)
+			classh_config->classh_vpch_man = val32;
+	}
+	of_node_put(classh);
+
+	/* frame depth location */
+	signal_format = of_get_child_by_name(np, "cirrus,monitor-signal-format");
+	monitor_config->is_present = signal_format ? true : false;
+	if (monitor_config->is_present) {
+		ret = of_property_read_u8_array(signal_format, "cirrus,imon",
+						monitor_array, imon_array_size);
+		if (!ret) {
+			monitor_config->imon_specs = true;
+			monitor_config->imon_dpth = monitor_array[0];
+			monitor_config->imon_loc = monitor_array[1];
+			monitor_config->imon_frm = monitor_array[2];
+			monitor_config->imon_scale = monitor_array[3];
+		}
+		ret = of_property_read_u8_array(signal_format, "cirrus,vmon",
+						monitor_array, mon_array_size);
+		if (!ret) {
+			monitor_config->vmon_specs = true;
+			monitor_config->vmon_dpth = monitor_array[0];
+			monitor_config->vmon_loc = monitor_array[1];
+			monitor_config->vmon_frm = monitor_array[2];
+		}
+		ret = of_property_read_u8_array(signal_format, "cirrus,vpmon",
+						monitor_array, mon_array_size);
+		if (!ret) {
+			monitor_config->vpmon_specs = true;
+			monitor_config->vpmon_dpth = monitor_array[0];
+			monitor_config->vpmon_loc = monitor_array[1];
+			monitor_config->vpmon_frm = monitor_array[2];
+		}
+		ret = of_property_read_u8_array(signal_format, "cirrus,vbstmon",
+						monitor_array, mon_array_size);
+		if (!ret) {
+			monitor_config->vbstmon_specs = true;
+			monitor_config->vbstmon_dpth = monitor_array[0];
+			monitor_config->vbstmon_loc = monitor_array[1];
+			monitor_config->vbstmon_frm = monitor_array[2];
+		}
+		ret = of_property_read_u8_array(signal_format, "cirrus,vpbrstat",
+						monitor_array, mon_array_size);
+		if (!ret) {
+			monitor_config->vpbrstat_specs = true;
+			monitor_config->vpbrstat_dpth = monitor_array[0];
+			monitor_config->vpbrstat_loc = monitor_array[1];
+			monitor_config->vpbrstat_frm = monitor_array[2];
+		}
+		ret = of_property_read_u8_array(signal_format, "cirrus,zerofill",
+						monitor_array, mon_array_size);
+		if (!ret) {
+			monitor_config->zerofill_specs = true;
+			monitor_config->zerofill_dpth = monitor_array[0];
+			monitor_config->zerofill_loc = monitor_array[1];
+			monitor_config->zerofill_frm = monitor_array[2];
+		}
+	}
+	of_node_put(signal_format);
+
+	return 0;
+}
+
+/* Errata Rev A0 */
+static const struct reg_sequence cs35l35_errata_patch[] = {
+
+	{ 0x7F, 0x99 },
+	{ 0x00, 0x99 },
+	{ 0x52, 0x22 },
+	{ 0x04, 0x14 },
+	{ 0x6D, 0x44 },
+	{ 0x24, 0x10 },
+	{ 0x58, 0xC4 },
+	{ 0x00, 0x98 },
+	{ 0x18, 0x08 },
+	{ 0x00, 0x00 },
+	{ 0x7F, 0x00 },
+};
+
+static int cs35l35_i2c_probe(struct i2c_client *i2c_client,
+			      const struct i2c_device_id *id)
+{
+	struct cs35l35_private *cs35l35;
+	struct device *dev = &i2c_client->dev;
+	struct cs35l35_platform_data *pdata = dev_get_platdata(dev);
+	int i;
+	int ret;
+	unsigned int devid = 0;
+	unsigned int reg;
+
+	cs35l35 = devm_kzalloc(dev, sizeof(struct cs35l35_private), GFP_KERNEL);
+	if (!cs35l35)
+		return -ENOMEM;
+
+	cs35l35->dev = dev;
+
+	i2c_set_clientdata(i2c_client, cs35l35);
+	cs35l35->regmap = devm_regmap_init_i2c(i2c_client, &cs35l35_regmap);
+	if (IS_ERR(cs35l35->regmap)) {
+		ret = PTR_ERR(cs35l35->regmap);
+		dev_err(dev, "regmap_init() failed: %d\n", ret);
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cs35l35_supplies); i++)
+		cs35l35->supplies[i].supply = cs35l35_supplies[i];
+
+	cs35l35->num_supplies = ARRAY_SIZE(cs35l35_supplies);
+
+	ret = devm_regulator_bulk_get(dev, cs35l35->num_supplies,
+				      cs35l35->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to request core supplies: %d\n", ret);
+		return ret;
+	}
+
+	if (pdata) {
+		cs35l35->pdata = *pdata;
+	} else {
+		pdata = devm_kzalloc(dev, sizeof(struct cs35l35_platform_data),
+				     GFP_KERNEL);
+		if (!pdata)
+			return -ENOMEM;
+		if (i2c_client->dev.of_node) {
+			ret = cs35l35_handle_of_data(i2c_client, pdata);
+			if (ret != 0)
+				return ret;
+
+		}
+		cs35l35->pdata = *pdata;
+	}
+
+	ret = regulator_bulk_enable(cs35l35->num_supplies,
+					cs35l35->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable core supplies: %d\n", ret);
+		return ret;
+	}
+
+	/* returning NULL can be valid if in stereo mode */
+	cs35l35->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						      GPIOD_OUT_LOW);
+	if (IS_ERR(cs35l35->reset_gpio)) {
+		ret = PTR_ERR(cs35l35->reset_gpio);
+		cs35l35->reset_gpio = NULL;
+		if (ret == -EBUSY) {
+			dev_info(dev,
+				 "Reset line busy, assuming shared reset\n");
+		} else {
+			dev_err(dev, "Failed to get reset GPIO: %d\n", ret);
+			goto err;
+		}
+	}
+
+	cs35l35_reset(cs35l35);
+
+	init_completion(&cs35l35->pdn_done);
+
+	ret = devm_request_threaded_irq(dev, i2c_client->irq, NULL, cs35l35_irq,
+					IRQF_ONESHOT | IRQF_TRIGGER_LOW |
+					IRQF_SHARED, "cs35l35", cs35l35);
+	if (ret != 0) {
+		dev_err(dev, "Failed to request IRQ: %d\n", ret);
+		goto err;
+	}
+	/* initialize codec */
+	ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_AB, &reg);
+
+	devid = (reg & 0xFF) << 12;
+	ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_CD, &reg);
+	devid |= (reg & 0xFF) << 4;
+	ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_E, &reg);
+	devid |= (reg & 0xF0) >> 4;
+
+	if (devid != CS35L35_CHIP_ID) {
+		dev_err(dev, "CS35L35 Device ID (%X). Expected ID %X\n",
+			devid, CS35L35_CHIP_ID);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	ret = regmap_read(cs35l35->regmap, CS35L35_REV_ID, &reg);
+	if (ret < 0) {
+		dev_err(dev, "Get Revision ID failed: %d\n", ret);
+		goto err;
+	}
+
+	ret = regmap_register_patch(cs35l35->regmap, cs35l35_errata_patch,
+				    ARRAY_SIZE(cs35l35_errata_patch));
+	if (ret < 0) {
+		dev_err(dev, "Failed to apply errata patch: %d\n", ret);
+		goto err;
+	}
+
+	dev_info(dev, "Cirrus Logic CS35L35 (%x), Revision: %02X\n",
+		 devid, reg & 0xFF);
+
+	/* Set the INT Masks for critical errors */
+	regmap_write(cs35l35->regmap, CS35L35_INT_MASK_1,
+				CS35L35_INT1_CRIT_MASK);
+	regmap_write(cs35l35->regmap, CS35L35_INT_MASK_2,
+				CS35L35_INT2_CRIT_MASK);
+	regmap_write(cs35l35->regmap, CS35L35_INT_MASK_3,
+				CS35L35_INT3_CRIT_MASK);
+	regmap_write(cs35l35->regmap, CS35L35_INT_MASK_4,
+				CS35L35_INT4_CRIT_MASK);
+
+	regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+			CS35L35_PWR2_PDN_MASK,
+			CS35L35_PWR2_PDN_MASK);
+
+	if (cs35l35->pdata.bst_pdn_fet_on)
+		regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+					CS35L35_PDN_BST_MASK,
+					1 << CS35L35_PDN_BST_FETON_SHIFT);
+	else
+		regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+					CS35L35_PDN_BST_MASK,
+					1 << CS35L35_PDN_BST_FETOFF_SHIFT);
+
+	regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL3,
+			CS35L35_PWR3_PDN_MASK,
+			CS35L35_PWR3_PDN_MASK);
+
+	regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL,
+		CS35L35_AMP_MUTE_MASK, 1 << CS35L35_AMP_MUTE_SHIFT);
+
+	ret = devm_snd_soc_register_component(dev, &soc_component_dev_cs35l35,
+					cs35l35_dai, ARRAY_SIZE(cs35l35_dai));
+	if (ret < 0) {
+		dev_err(dev, "Failed to register component: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	regulator_bulk_disable(cs35l35->num_supplies,
+			       cs35l35->supplies);
+	gpiod_set_value_cansleep(cs35l35->reset_gpio, 0);
+
+	return ret;
+}
+
+static const struct of_device_id cs35l35_of_match[] = {
+	{.compatible = "cirrus,cs35l35"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, cs35l35_of_match);
+
+static const struct i2c_device_id cs35l35_id[] = {
+	{"cs35l35", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs35l35_id);
+
+static struct i2c_driver cs35l35_i2c_driver = {
+	.driver = {
+		.name = "cs35l35",
+		.of_match_table = cs35l35_of_match,
+	},
+	.id_table = cs35l35_id,
+	.probe = cs35l35_i2c_probe,
+};
+
+module_i2c_driver(cs35l35_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS35L35 driver");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l35.h b/sound/soc/codecs/cs35l35.h
new file mode 100644
index 0000000..621bfef
--- /dev/null
+++ b/sound/soc/codecs/cs35l35.h
@@ -0,0 +1,300 @@
+/*
+ * cs35l35.h -- CS35L35 ALSA SoC audio driver
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CS35L35_H__
+#define __CS35L35_H__
+
+#define CS35L35_FIRSTREG		0x01
+#define CS35L35_LASTREG			0x7E
+#define CS35L35_CHIP_ID			0x00035A35
+#define CS35L35_DEVID_AB		0x01	/* Device ID A & B [RO] */
+#define CS35L35_DEVID_CD		0x02    /* Device ID C & D [RO] */
+#define CS35L35_DEVID_E			0x03    /* Device ID E [RO] */
+#define CS35L35_FAB_ID			0x04	/* Fab ID [RO] */
+#define CS35L35_REV_ID			0x05	/* Revision ID [RO] */
+#define CS35L35_PWRCTL1			0x06    /* Power Ctl 1 */
+#define CS35L35_PWRCTL2			0x07    /* Power Ctl 2 */
+#define CS35L35_PWRCTL3			0x08	/* Power Ctl 3 */
+#define CS35L35_CLK_CTL1		0x0A	/* Clocking Ctl 1 */
+#define CS35L35_CLK_CTL2		0x0B	/* Clocking Ctl 2 */
+#define CS35L35_CLK_CTL3		0x0C	/* Clocking Ctl 3 */
+#define CS35L35_SP_FMT_CTL1		0x0D	/* Serial Port Format CTL1 */
+#define CS35L35_SP_FMT_CTL2		0x0E	/* Serial Port Format CTL2 */
+#define CS35L35_SP_FMT_CTL3		0x0F	/* Serial Port Format CTL3 */
+#define CS35L35_MAG_COMP_CTL		0x13	/* Magnitude Comp CTL */
+#define CS35L35_AMP_INP_DRV_CTL		0x14	/* Amp Input Drive Ctl */
+#define CS35L35_AMP_DIG_VOL_CTL		0x15	/* Amplifier Dig Volume Ctl */
+#define CS35L35_AMP_DIG_VOL		0x16	/* Amplifier Dig Volume */
+#define CS35L35_ADV_DIG_VOL		0x17	/* Advisory Digital Volume */
+#define CS35L35_PROTECT_CTL		0x18	/* Amp Gain - Prot Ctl Param */
+#define CS35L35_AMP_GAIN_AUD_CTL	0x19	/* Amp Serial Port Gain Ctl */
+#define CS35L35_AMP_GAIN_PDM_CTL	0x1A	/* Amplifier Gain PDM Ctl */
+#define CS35L35_AMP_GAIN_ADV_CTL	0x1B	/* Amplifier Gain Ctl */
+#define CS35L35_GPI_CTL			0x1C	/* GPI Ctl */
+#define CS35L35_BST_CVTR_V_CTL		0x1D	/* Boost Conv Voltage Ctl */
+#define CS35L35_BST_PEAK_I		0x1E	/* Boost Conv Peak Current */
+#define CS35L35_BST_RAMP_CTL		0x20	/* Boost Conv Soft Ramp Ctl */
+#define CS35L35_BST_CONV_COEF_1		0x21	/* Boost Conv Coefficients 1 */
+#define CS35L35_BST_CONV_COEF_2		0x22	/* Boost Conv Coefficients 2 */
+#define CS35L35_BST_CONV_SLOPE_COMP	0x23	/* Boost Conv Slope Comp */
+#define CS35L35_BST_CONV_SW_FREQ	0x24	/* Boost Conv L BST SW Freq */
+#define CS35L35_CLASS_H_CTL		0x30	/* CLS H Control */
+#define CS35L35_CLASS_H_HEADRM_CTL	0x31	/* CLS H Headroom Ctl */
+#define CS35L35_CLASS_H_RELEASE_RATE	0x32	/* CLS H Release Rate */
+#define CS35L35_CLASS_H_FET_DRIVE_CTL	0x33	/* CLS H Weak FET Drive Ctl */
+#define CS35L35_CLASS_H_VP_CTL		0x34	/* CLS H VP Ctl */
+#define CS35L35_CLASS_H_STATUS		0x38	/* CLS H Status */
+#define CS35L35_VPBR_CTL		0x3A	/* VPBR Ctl */
+#define CS35L35_VPBR_VOL_CTL		0x3B	/* VPBR Volume Ctl */
+#define CS35L35_VPBR_TIMING_CTL		0x3C	/* VPBR Timing Ctl */
+#define CS35L35_VPBR_MODE_VOL_CTL	0x3D	/* VPBR Mode/Attack Vol Ctl */
+#define CS35L35_VPBR_ATTEN_STATUS	0x4B	/* VPBR Attenuation Status */
+#define CS35L35_SPKR_MON_CTL		0x4E	/* Speaker Monitoring Ctl */
+#define CS35L35_IMON_SCALE_CTL		0x51	/* IMON Scale Ctl */
+#define CS35L35_AUDIN_RXLOC_CTL		0x52	/* Audio Input RX Loc Ctl */
+#define CS35L35_ADVIN_RXLOC_CTL		0x53	/* Advisory Input RX Loc Ctl */
+#define CS35L35_VMON_TXLOC_CTL		0x54	/* VMON TX Loc Ctl */
+#define CS35L35_IMON_TXLOC_CTL		0x55	/* IMON TX Loc Ctl */
+#define CS35L35_VPMON_TXLOC_CTL		0x56	/* VPMON TX Loc Ctl */
+#define CS35L35_VBSTMON_TXLOC_CTL	0x57	/* VBSTMON TX Loc Ctl */
+#define CS35L35_VPBR_STATUS_TXLOC_CTL	0x58	/* VPBR Status TX Loc Ctl */
+#define CS35L35_ZERO_FILL_LOC_CTL	0x59	/* Zero Fill Loc Ctl */
+#define CS35L35_AUDIN_DEPTH_CTL		0x5A	/* Audio Input Depth Ctl */
+#define CS35L35_SPKMON_DEPTH_CTL	0x5B	/* SPK Mon Output Depth Ctl */
+#define CS35L35_SUPMON_DEPTH_CTL	0x5C	/* Supply Mon Out Depth Ctl */
+#define CS35L35_ZEROFILL_DEPTH_CTL	0x5D	/* Zero Fill Mon Output Ctl */
+#define CS35L35_MULT_DEV_SYNCH1		0x62	/* Multidevice Synch */
+#define CS35L35_MULT_DEV_SYNCH2		0x63	/* Multidevice Synch 2 */
+#define CS35L35_PROT_RELEASE_CTL	0x64	/* Protection Release Ctl */
+#define CS35L35_DIAG_MODE_REG_LOCK	0x68	/* Diagnostic Mode Reg Lock */
+#define CS35L35_DIAG_MODE_CTL_1		0x69	/* Diagnostic Mode Ctl 1 */
+#define CS35L35_DIAG_MODE_CTL_2		0x6A	/* Diagnostic Mode Ctl 2 */
+#define CS35L35_INT_MASK_1		0x70	/* Interrupt Mask 1 */
+#define CS35L35_INT_MASK_2		0x71	/* Interrupt Mask 2 */
+#define CS35L35_INT_MASK_3		0x72	/* Interrupt Mask 3 */
+#define CS35L35_INT_MASK_4		0x73	/* Interrupt Mask 4 */
+#define CS35L35_INT_STATUS_1		0x74	/* Interrupt Status 1 */
+#define CS35L35_INT_STATUS_2		0x75	/* Interrupt Status 2 */
+#define CS35L35_INT_STATUS_3		0x76	/* Interrupt Status 3 */
+#define CS35L35_INT_STATUS_4		0x77	/* Interrupt Status 4 */
+#define CS35L35_PLL_STATUS		0x78	/* PLL Status */
+#define CS35L35_OTP_TRIM_STATUS		0x7E	/* OTP Trim Status */
+
+#define CS35L35_MAX_REGISTER		0x7F
+
+/* CS35L35_PWRCTL1 */
+#define CS35L35_SFT_RST			0x80
+#define CS35L35_DISCHG_FLT		0x02
+#define CS35L35_PDN_ALL			0x01
+
+/* CS35L35_PWRCTL2 */
+#define CS35L35_PDN_VMON		0x80
+#define CS35L35_PDN_IMON		0x40
+#define CS35L35_PDN_CLASSH		0x20
+#define CS35L35_PDN_VPBR		0x10
+#define CS35L35_PDN_BST			0x04
+#define CS35L35_PDN_AMP			0x01
+
+/* CS35L35_PWRCTL3 */
+#define CS35L35_PDN_VBSTMON_OUT		0x10
+#define CS35L35_PDN_VMON_OUT		0x08
+
+#define CS35L35_AUDIN_DEPTH_MASK	0x03
+#define CS35L35_AUDIN_DEPTH_SHIFT	0
+#define CS35L35_ADVIN_DEPTH_MASK	0x0C
+#define CS35L35_ADVIN_DEPTH_SHIFT	2
+#define CS35L35_SDIN_DEPTH_8		0x01
+#define CS35L35_SDIN_DEPTH_16		0x02
+#define CS35L35_SDIN_DEPTH_24		0x03
+
+#define CS35L35_SDOUT_DEPTH_8		0x01
+#define CS35L35_SDOUT_DEPTH_12		0x02
+#define CS35L35_SDOUT_DEPTH_16		0x03
+
+#define CS35L35_AUD_IN_LR_MASK		0x80
+#define CS35L35_AUD_IN_LR_SHIFT		7
+#define CS35L35_ADV_IN_LR_MASK		0x80
+#define CS35L35_ADV_IN_LR_SHIFT		7
+#define CS35L35_AUD_IN_LOC_MASK		0x0F
+#define CS35L35_AUD_IN_LOC_SHIFT	0
+#define CS35L35_ADV_IN_LOC_MASK		0x0F
+#define CS35L35_ADV_IN_LOC_SHIFT	0
+
+#define CS35L35_IMON_DEPTH_MASK		0x03
+#define CS35L35_IMON_DEPTH_SHIFT	0
+#define CS35L35_VMON_DEPTH_MASK		0x0C
+#define CS35L35_VMON_DEPTH_SHIFT	2
+#define CS35L35_VBSTMON_DEPTH_MASK	0x03
+#define CS35L35_VBSTMON_DEPTH_SHIFT	0
+#define CS35L35_VPMON_DEPTH_MASK	0x0C
+#define CS35L35_VPMON_DEPTH_SHIFT	2
+#define CS35L35_VPBRSTAT_DEPTH_MASK	0x30
+#define CS35L35_VPBRSTAT_DEPTH_SHIFT	4
+#define CS35L35_ZEROFILL_DEPTH_MASK	0x03
+#define CS35L35_ZEROFILL_DEPTH_SHIFT	0x00
+
+#define CS35L35_MON_TXLOC_MASK		0x3F
+#define CS35L35_MON_TXLOC_SHIFT		0
+#define CS35L35_MON_FRM_MASK		0x80
+#define CS35L35_MON_FRM_SHIFT		7
+
+#define CS35L35_IMON_SCALE_MASK		0xF8
+#define CS35L35_IMON_SCALE_SHIFT	3
+
+#define CS35L35_MS_MASK			0x80
+#define CS35L35_MS_SHIFT		7
+#define CS35L35_SPMODE_MASK		0x40
+#define CS35L35_SP_DRV_MASK		0x10
+#define CS35L35_SP_DRV_SHIFT		4
+#define CS35L35_CLK_CTL2_MASK		0xFF
+#define CS35L35_PDM_MODE_MASK		0x40
+#define CS35L35_PDM_MODE_SHIFT		6
+#define CS35L35_CLK_SOURCE_MASK		0x03
+#define CS35L35_CLK_SOURCE_SHIFT	0
+#define CS35L35_CLK_SOURCE_MCLK		0
+#define CS35L35_CLK_SOURCE_SCLK		1
+#define CS35L35_CLK_SOURCE_PDM		2
+
+#define CS35L35_SP_SCLKS_MASK		0x0F
+#define CS35L35_SP_SCLKS_SHIFT		0x00
+#define CS35L35_SP_SCLKS_16FS		0x03
+#define CS35L35_SP_SCLKS_32FS		0x07
+#define CS35L35_SP_SCLKS_48FS		0x0B
+#define CS35L35_SP_SCLKS_64FS		0x0F
+#define CS35L35_SP_RATE_MASK		0xC0
+
+#define CS35L35_PDN_BST_MASK		0x06
+#define CS35L35_PDN_BST_FETON_SHIFT	1
+#define CS35L35_PDN_BST_FETOFF_SHIFT	2
+#define CS35L35_PWR2_PDN_MASK		0xE0
+#define CS35L35_PWR3_PDN_MASK		0x1E
+#define CS35L35_PDN_ALL_MASK		0x01
+#define CS35L35_DISCHG_FILT_MASK	0x02
+#define CS35L35_DISCHG_FILT_SHIFT	1
+#define CS35L35_MCLK_DIS_MASK		0x04
+#define CS35L35_MCLK_DIS_SHIFT		2
+
+#define CS35L35_BST_CTL_MASK		0x7F
+#define CS35L35_BST_CTL_SHIFT		0
+#define CS35L35_BST_IPK_MASK		0x1F
+#define CS35L35_BST_IPK_SHIFT		0
+#define CS35L35_AMP_MUTE_MASK		0x20
+#define CS35L35_AMP_MUTE_SHIFT		5
+#define CS35L35_AMP_GAIN_ZC_MASK	0x10
+#define CS35L35_AMP_GAIN_ZC_SHIFT	4
+
+#define CS35L35_AMP_DIGSFT_MASK		0x02
+#define CS35L35_AMP_DIGSFT_SHIFT	1
+
+/* CS35L35_SP_FMT_CTL3 */
+#define CS35L35_SP_I2S_DRV_MASK		0x03
+#define CS35L35_SP_I2S_DRV_SHIFT	0
+
+/* Boost Converter Config */
+#define CS35L35_BST_CONV_COEFF_MASK	0xFF
+#define CS35L35_BST_CONV_SLOPE_MASK	0xFF
+#define CS35L35_BST_CONV_LBST_MASK	0x03
+#define CS35L35_BST_CONV_SWFREQ_MASK	0xF0
+
+/* Class H Algorithm Control */
+#define CS35L35_CH_STEREO_MASK		0x40
+#define CS35L35_CH_STEREO_SHIFT		6
+#define CS35L35_CH_BST_OVR_MASK		0x04
+#define CS35L35_CH_BST_OVR_SHIFT	2
+#define CS35L35_CH_BST_LIM_MASK		0x08
+#define CS35L35_CH_BST_LIM_SHIFT	3
+#define CS35L35_CH_MEM_DEPTH_MASK	0x01
+#define CS35L35_CH_MEM_DEPTH_SHIFT	0
+#define CS35L35_CH_HDRM_CTL_MASK	0x3F
+#define CS35L35_CH_HDRM_CTL_SHIFT	0
+#define CS35L35_CH_REL_RATE_MASK	0xFF
+#define CS35L35_CH_REL_RATE_SHIFT	0
+#define CS35L35_CH_WKFET_DIS_MASK	0x80
+#define CS35L35_CH_WKFET_DIS_SHIFT	7
+#define CS35L35_CH_WKFET_DEL_MASK	0x70
+#define CS35L35_CH_WKFET_DEL_SHIFT	4
+#define CS35L35_CH_WKFET_THLD_MASK	0x0F
+#define CS35L35_CH_WKFET_THLD_SHIFT	0
+#define CS35L35_CH_VP_AUTO_MASK		0x80
+#define CS35L35_CH_VP_AUTO_SHIFT	7
+#define CS35L35_CH_VP_RATE_MASK		0x60
+#define CS35L35_CH_VP_RATE_SHIFT	5
+#define CS35L35_CH_VP_MAN_MASK		0x1F
+#define CS35L35_CH_VP_MAN_SHIFT		0
+
+/* CS35L35_PROT_RELEASE_CTL */
+#define CS35L35_CAL_ERR_RLS		0x80
+#define CS35L35_SHORT_RLS		0x04
+#define CS35L35_OTW_RLS			0x02
+#define CS35L35_OTE_RLS			0x01
+
+/* INT Mask Registers */
+#define CS35L35_INT1_CRIT_MASK		0x38
+#define CS35L35_INT2_CRIT_MASK		0xEF
+#define CS35L35_INT3_CRIT_MASK		0xEE
+#define CS35L35_INT4_CRIT_MASK		0xFF
+
+/* PDN DONE Masks */
+#define CS35L35_M_PDN_DONE_SHIFT	4
+#define CS35L35_M_PDN_DONE_MASK		0x10
+
+/* CS35L35_INT_1 */
+#define CS35L35_CAL_ERR			0x80
+#define CS35L35_OTP_ERR			0x40
+#define CS35L35_LRCLK_ERR		0x20
+#define CS35L35_SPCLK_ERR		0x10
+#define CS35L35_MCLK_ERR		0x08
+#define CS35L35_AMP_SHORT		0x04
+#define CS35L35_OTW			0x02
+#define CS35L35_OTE			0x01
+
+/* CS35L35_INT_2 */
+#define CS35L35_PDN_DONE		0x10
+#define CS35L35_VPBR_ERR		0x02
+#define CS35L35_VPBR_CLR		0x01
+
+/* CS35L35_INT_3 */
+#define CS35L35_BST_HIGH		0x10
+#define CS35L35_BST_HIGH_FLAG		0x08
+#define CS35L35_BST_IPK_FLAG		0x04
+#define CS35L35_LBST_SHORT		0x01
+
+/* CS35L35_INT_4 */
+#define CS35L35_VMON_OVFL		0x08
+#define CS35L35_IMON_OVFL		0x04
+
+#define CS35L35_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct  cs35l35_private {
+	struct device *dev;
+	struct cs35l35_platform_data pdata;
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[2];
+	int num_supplies;
+	int sysclk;
+	int sclk;
+	bool pdm_mode;
+	bool i2s_mode;
+	bool slave_mode;
+	/* GPIO for /RST */
+	struct gpio_desc *reset_gpio;
+	struct completion pdn_done;
+};
+
+static const char * const cs35l35_supplies[] = {
+	"VA",
+	"VP",
+};
+
+#endif
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
new file mode 100644
index 0000000..4075541
--- /dev/null
+++ b/sound/soc/codecs/cs4265.c
@@ -0,0 +1,651 @@
+/*
+ * cs4265.c -- CS4265 ALSA SoC audio driver
+ *
+ * Copyright 2014 Cirrus Logic, Inc.
+ *
+ * Author: Paul Handrigan <paul.handrigan@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/gpio/consumer.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include "cs4265.h"
+
+struct cs4265_private {
+	struct regmap *regmap;
+	struct gpio_desc *reset_gpio;
+	u8 format;
+	u32 sysclk;
+};
+
+static const struct reg_default cs4265_reg_defaults[] = {
+	{ CS4265_PWRCTL, 0x0F },
+	{ CS4265_DAC_CTL, 0x08 },
+	{ CS4265_ADC_CTL, 0x00 },
+	{ CS4265_MCLK_FREQ, 0x00 },
+	{ CS4265_SIG_SEL, 0x40 },
+	{ CS4265_CHB_PGA_CTL, 0x00 },
+	{ CS4265_CHA_PGA_CTL, 0x00 },
+	{ CS4265_ADC_CTL2, 0x19 },
+	{ CS4265_DAC_CHA_VOL, 0x00 },
+	{ CS4265_DAC_CHB_VOL, 0x00 },
+	{ CS4265_DAC_CTL2, 0xC0 },
+	{ CS4265_SPDIF_CTL1, 0x00 },
+	{ CS4265_SPDIF_CTL2, 0x00 },
+	{ CS4265_INT_MASK, 0x00 },
+	{ CS4265_STATUS_MODE_MSB, 0x00 },
+	{ CS4265_STATUS_MODE_LSB, 0x00 },
+};
+
+static bool cs4265_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS4265_CHIP_ID ... CS4265_SPDIF_CTL2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs4265_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS4265_INT_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static DECLARE_TLV_DB_SCALE(pga_tlv, -1200, 50, 0);
+
+static DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 0);
+
+static const char * const digital_input_mux_text[] = {
+	"SDIN1", "SDIN2"
+};
+
+static SOC_ENUM_SINGLE_DECL(digital_input_mux_enum, CS4265_SIG_SEL, 7,
+		digital_input_mux_text);
+
+static const struct snd_kcontrol_new digital_input_mux =
+	SOC_DAPM_ENUM("Digital Input Mux", digital_input_mux_enum);
+
+static const char * const mic_linein_text[] = {
+	"MIC", "LINEIN"
+};
+
+static SOC_ENUM_SINGLE_DECL(mic_linein_enum, CS4265_ADC_CTL2, 0,
+		mic_linein_text);
+
+static const char * const cam_mode_text[] = {
+	"One Byte", "Two Byte"
+};
+
+static SOC_ENUM_SINGLE_DECL(cam_mode_enum, CS4265_SPDIF_CTL1, 5,
+		cam_mode_text);
+
+static const char * const cam_mono_stereo_text[] = {
+	"Stereo", "Mono"
+};
+
+static SOC_ENUM_SINGLE_DECL(spdif_mono_stereo_enum, CS4265_SPDIF_CTL2, 2,
+		cam_mono_stereo_text);
+
+static const char * const mono_select_text[] = {
+	"Channel A", "Channel B"
+};
+
+static SOC_ENUM_SINGLE_DECL(spdif_mono_select_enum, CS4265_SPDIF_CTL2, 0,
+		mono_select_text);
+
+static const struct snd_kcontrol_new mic_linein_mux =
+	SOC_DAPM_ENUM("ADC Input Capture Mux", mic_linein_enum);
+
+static const struct snd_kcontrol_new loopback_ctl =
+	SOC_DAPM_SINGLE("Switch", CS4265_SIG_SEL, 1, 1, 0);
+
+static const struct snd_kcontrol_new spdif_switch =
+	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 0, 0);
+
+static const struct snd_kcontrol_new dac_switch =
+	SOC_DAPM_SINGLE("Switch", CS4265_PWRCTL, 1, 1, 0);
+
+static const struct snd_kcontrol_new cs4265_snd_controls[] = {
+
+	SOC_DOUBLE_R_SX_TLV("PGA Volume", CS4265_CHA_PGA_CTL,
+			      CS4265_CHB_PGA_CTL, 0, 0x28, 0x30, pga_tlv),
+	SOC_DOUBLE_R_TLV("DAC Volume", CS4265_DAC_CHA_VOL,
+		      CS4265_DAC_CHB_VOL, 0, 0xFF, 1, dac_tlv),
+	SOC_SINGLE("De-emp 44.1kHz Switch", CS4265_DAC_CTL, 1,
+				1, 0),
+	SOC_SINGLE("DAC INV Switch", CS4265_DAC_CTL2, 5,
+				1, 0),
+	SOC_SINGLE("DAC Zero Cross Switch", CS4265_DAC_CTL2, 6,
+				1, 0),
+	SOC_SINGLE("DAC Soft Ramp Switch", CS4265_DAC_CTL2, 7,
+				1, 0),
+	SOC_SINGLE("ADC HPF Switch", CS4265_ADC_CTL, 1,
+				1, 0),
+	SOC_SINGLE("ADC Zero Cross Switch", CS4265_ADC_CTL2, 3,
+				1, 1),
+	SOC_SINGLE("ADC Soft Ramp Switch", CS4265_ADC_CTL2, 7,
+				1, 0),
+	SOC_SINGLE("E to F Buffer Disable Switch", CS4265_SPDIF_CTL1,
+				6, 1, 0),
+	SOC_ENUM("C Data Access", cam_mode_enum),
+	SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2,
+				3, 1, 0),
+	SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum),
+	SOC_SINGLE("MMTLR Data Switch", CS4265_SPDIF_CTL2,
+				0, 1, 0),
+	SOC_ENUM("Mono Channel Select", spdif_mono_select_enum),
+	SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24),
+};
+
+static const struct snd_soc_dapm_widget cs4265_dapm_widgets[] = {
+
+	SND_SOC_DAPM_INPUT("LINEINL"),
+	SND_SOC_DAPM_INPUT("LINEINR"),
+	SND_SOC_DAPM_INPUT("MICL"),
+	SND_SOC_DAPM_INPUT("MICR"),
+
+	SND_SOC_DAPM_AIF_OUT("DOUT", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SPDIFOUT", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MUX("ADC Mux", SND_SOC_NOPM, 0, 0, &mic_linein_mux),
+
+	SND_SOC_DAPM_ADC("ADC", NULL, CS4265_PWRCTL, 2, 1),
+	SND_SOC_DAPM_PGA("Pre-amp MIC", CS4265_PWRCTL, 3,
+			1, NULL, 0),
+
+	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM,
+			 0, 0, &digital_input_mux),
+
+	SND_SOC_DAPM_MIXER("SDIN1 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SDIN2 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SPDIF Transmitter", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH("Loopback", SND_SOC_NOPM, 0, 0,
+			&loopback_ctl),
+	SND_SOC_DAPM_SWITCH("SPDIF", SND_SOC_NOPM, 0, 0,
+			&spdif_switch),
+	SND_SOC_DAPM_SWITCH("DAC", CS4265_PWRCTL, 1, 1,
+			&dac_switch),
+
+	SND_SOC_DAPM_AIF_IN("DIN1", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DIN2", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("TXIN", NULL,  0,
+			CS4265_SPDIF_CTL2, 5, 1),
+
+	SND_SOC_DAPM_OUTPUT("LINEOUTL"),
+	SND_SOC_DAPM_OUTPUT("LINEOUTR"),
+
+};
+
+static const struct snd_soc_dapm_route cs4265_audio_map[] = {
+
+	{"DIN1", NULL, "DAI1 Playback"},
+	{"DIN2", NULL, "DAI2 Playback"},
+	{"SDIN1 Input Mixer", NULL, "DIN1"},
+	{"SDIN2 Input Mixer", NULL, "DIN2"},
+	{"Input Mux", "SDIN1", "SDIN1 Input Mixer"},
+	{"Input Mux", "SDIN2", "SDIN2 Input Mixer"},
+	{"DAC", "Switch", "Input Mux"},
+	{"SPDIF", "Switch", "Input Mux"},
+	{"LINEOUTL", NULL, "DAC"},
+	{"LINEOUTR", NULL, "DAC"},
+	{"SPDIFOUT", NULL, "SPDIF"},
+
+	{"ADC Mux", "LINEIN", "LINEINL"},
+	{"ADC Mux", "LINEIN", "LINEINR"},
+	{"ADC Mux", "MIC", "MICL"},
+	{"ADC Mux", "MIC", "MICR"},
+	{"ADC", NULL, "ADC Mux"},
+	{"DOUT", NULL, "ADC"},
+	{"DAI1 Capture", NULL, "DOUT"},
+	{"DAI2 Capture", NULL, "DOUT"},
+
+	/* Loopback */
+	{"Loopback", "Switch", "ADC"},
+	{"DAC", NULL, "Loopback"},
+};
+
+struct cs4265_clk_para {
+	u32 mclk;
+	u32 rate;
+	u8 fm_mode; /* values 1, 2, or 4 */
+	u8 mclkdiv;
+};
+
+static const struct cs4265_clk_para clk_map_table[] = {
+	/*32k*/
+	{8192000, 32000, 0, 0},
+	{12288000, 32000, 0, 1},
+	{16384000, 32000, 0, 2},
+	{24576000, 32000, 0, 3},
+	{32768000, 32000, 0, 4},
+
+	/*44.1k*/
+	{11289600, 44100, 0, 0},
+	{16934400, 44100, 0, 1},
+	{22579200, 44100, 0, 2},
+	{33868000, 44100, 0, 3},
+	{45158400, 44100, 0, 4},
+
+	/*48k*/
+	{12288000, 48000, 0, 0},
+	{18432000, 48000, 0, 1},
+	{24576000, 48000, 0, 2},
+	{36864000, 48000, 0, 3},
+	{49152000, 48000, 0, 4},
+
+	/*64k*/
+	{8192000, 64000, 1, 0},
+	{12288000, 64000, 1, 1},
+	{16934400, 64000, 1, 2},
+	{24576000, 64000, 1, 3},
+	{32768000, 64000, 1, 4},
+
+	/* 88.2k */
+	{11289600, 88200, 1, 0},
+	{16934400, 88200, 1, 1},
+	{22579200, 88200, 1, 2},
+	{33868000, 88200, 1, 3},
+	{45158400, 88200, 1, 4},
+
+	/* 96k */
+	{12288000, 96000, 1, 0},
+	{18432000, 96000, 1, 1},
+	{24576000, 96000, 1, 2},
+	{36864000, 96000, 1, 3},
+	{49152000, 96000, 1, 4},
+
+	/* 128k */
+	{8192000, 128000, 2, 0},
+	{12288000, 128000, 2, 1},
+	{16934400, 128000, 2, 2},
+	{24576000, 128000, 2, 3},
+	{32768000, 128000, 2, 4},
+
+	/* 176.4k */
+	{11289600, 176400, 2, 0},
+	{16934400, 176400, 2, 1},
+	{22579200, 176400, 2, 2},
+	{33868000, 176400, 2, 3},
+	{49152000, 176400, 2, 4},
+
+	/* 192k */
+	{12288000, 192000, 2, 0},
+	{18432000, 192000, 2, 1},
+	{24576000, 192000, 2, 2},
+	{36864000, 192000, 2, 3},
+	{49152000, 192000, 2, 4},
+};
+
+static int cs4265_get_clk_index(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
+		if (clk_map_table[i].rate == rate &&
+				clk_map_table[i].mclk == mclk)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static int cs4265_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
+			unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs4265_private *cs4265 = snd_soc_component_get_drvdata(component);
+	int i;
+
+	if (clk_id != 0) {
+		dev_err(component->dev, "Invalid clk_id %d\n", clk_id);
+		return -EINVAL;
+	}
+	for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
+		if (clk_map_table[i].mclk == freq) {
+			cs4265->sysclk = freq;
+			return 0;
+		}
+	}
+	cs4265->sysclk = 0;
+	dev_err(component->dev, "Invalid freq parameter %d\n", freq);
+	return -EINVAL;
+}
+
+static int cs4265_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs4265_private *cs4265 = snd_soc_component_get_drvdata(component);
+	u8 iface = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
+				CS4265_ADC_MASTER,
+				CS4265_ADC_MASTER);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
+				CS4265_ADC_MASTER,
+				0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	 /* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= SND_SOC_DAIFMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		iface |= SND_SOC_DAIFMT_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= SND_SOC_DAIFMT_LEFT_J;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	cs4265->format = iface;
+	return 0;
+}
+
+static int cs4265_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute) {
+		snd_soc_component_update_bits(component, CS4265_DAC_CTL,
+			CS4265_DAC_CTL_MUTE,
+			CS4265_DAC_CTL_MUTE);
+		snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
+			CS4265_SPDIF_CTL2_MUTE,
+			CS4265_SPDIF_CTL2_MUTE);
+	} else {
+		snd_soc_component_update_bits(component, CS4265_DAC_CTL,
+			CS4265_DAC_CTL_MUTE,
+			0);
+		snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
+			CS4265_SPDIF_CTL2_MUTE,
+			0);
+	}
+	return 0;
+}
+
+static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params,
+				     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs4265_private *cs4265 = snd_soc_component_get_drvdata(component);
+	int index;
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
+		((cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK)
+		== SND_SOC_DAIFMT_RIGHT_J))
+		return -EINVAL;
+
+	index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params));
+	if (index >= 0) {
+		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
+			CS4265_ADC_FM, clk_map_table[index].fm_mode << 6);
+		snd_soc_component_update_bits(component, CS4265_MCLK_FREQ,
+			CS4265_MCLK_FREQ_MASK,
+			clk_map_table[index].mclkdiv << 4);
+
+	} else {
+		dev_err(component->dev, "can't get correct mclk\n");
+		return -EINVAL;
+	}
+
+	switch (cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		snd_soc_component_update_bits(component, CS4265_DAC_CTL,
+			CS4265_DAC_CTL_DIF, (1 << 4));
+		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
+			CS4265_ADC_DIF, (1 << 4));
+		snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
+			CS4265_SPDIF_CTL2_DIF, (1 << 6));
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		if (params_width(params) == 16) {
+			snd_soc_component_update_bits(component, CS4265_DAC_CTL,
+				CS4265_DAC_CTL_DIF, (2 << 4));
+			snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
+				CS4265_SPDIF_CTL2_DIF, (2 << 6));
+		} else {
+			snd_soc_component_update_bits(component, CS4265_DAC_CTL,
+				CS4265_DAC_CTL_DIF, (3 << 4));
+			snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
+				CS4265_SPDIF_CTL2_DIF, (3 << 6));
+		}
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		snd_soc_component_update_bits(component, CS4265_DAC_CTL,
+			CS4265_DAC_CTL_DIF, 0);
+		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
+			CS4265_ADC_DIF, 0);
+		snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
+			CS4265_SPDIF_CTL2_DIF, 0);
+
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cs4265_set_bias_level(struct snd_soc_component *component,
+					enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		snd_soc_component_update_bits(component, CS4265_PWRCTL,
+			CS4265_PWRCTL_PDN, 0);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_component_update_bits(component, CS4265_PWRCTL,
+			CS4265_PWRCTL_PDN,
+			CS4265_PWRCTL_PDN);
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, CS4265_PWRCTL,
+			CS4265_PWRCTL_PDN,
+			CS4265_PWRCTL_PDN);
+		break;
+	}
+	return 0;
+}
+
+#define CS4265_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+			SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
+			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
+			SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
+
+#define CS4265_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE)
+
+static const struct snd_soc_dai_ops cs4265_ops = {
+	.hw_params	= cs4265_pcm_hw_params,
+	.digital_mute	= cs4265_digital_mute,
+	.set_fmt	= cs4265_set_fmt,
+	.set_sysclk	= cs4265_set_sysclk,
+};
+
+static struct snd_soc_dai_driver cs4265_dai[] = {
+	{
+		.name = "cs4265-dai1",
+		.playback = {
+			.stream_name = "DAI1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS4265_RATES,
+			.formats = CS4265_FORMATS,
+		},
+		.capture = {
+			.stream_name = "DAI1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS4265_RATES,
+			.formats = CS4265_FORMATS,
+		},
+		.ops = &cs4265_ops,
+	},
+	{
+		.name = "cs4265-dai2",
+		.playback = {
+			.stream_name = "DAI2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS4265_RATES,
+			.formats = CS4265_FORMATS,
+		},
+		.capture = {
+			.stream_name = "DAI2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS4265_RATES,
+			.formats = CS4265_FORMATS,
+		},
+		.ops = &cs4265_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_cs4265 = {
+	.set_bias_level		= cs4265_set_bias_level,
+	.controls		= cs4265_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs4265_snd_controls),
+	.dapm_widgets		= cs4265_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs4265_dapm_widgets),
+	.dapm_routes		= cs4265_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs4265_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config cs4265_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = CS4265_MAX_REGISTER,
+	.reg_defaults = cs4265_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(cs4265_reg_defaults),
+	.readable_reg = cs4265_readable_register,
+	.volatile_reg = cs4265_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int cs4265_i2c_probe(struct i2c_client *i2c_client,
+			     const struct i2c_device_id *id)
+{
+	struct cs4265_private *cs4265;
+	int ret = 0;
+	unsigned int devid = 0;
+	unsigned int reg;
+
+	cs4265 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4265_private),
+			       GFP_KERNEL);
+	if (cs4265 == NULL)
+		return -ENOMEM;
+
+	cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap);
+	if (IS_ERR(cs4265->regmap)) {
+		ret = PTR_ERR(cs4265->regmap);
+		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	cs4265->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+		"reset", GPIOD_OUT_LOW);
+	if (IS_ERR(cs4265->reset_gpio))
+		return PTR_ERR(cs4265->reset_gpio);
+
+	if (cs4265->reset_gpio) {
+		mdelay(1);
+		gpiod_set_value_cansleep(cs4265->reset_gpio, 1);
+	}
+
+	i2c_set_clientdata(i2c_client, cs4265);
+
+	ret = regmap_read(cs4265->regmap, CS4265_CHIP_ID, &reg);
+	devid = reg & CS4265_CHIP_ID_MASK;
+	if (devid != CS4265_CHIP_ID_VAL) {
+		ret = -ENODEV;
+		dev_err(&i2c_client->dev,
+			"CS4265 Device ID (%X). Expected %X\n",
+			devid, CS4265_CHIP_ID);
+		return ret;
+	}
+	dev_info(&i2c_client->dev,
+		"CS4265 Version %x\n",
+			reg & CS4265_REV_ID_MASK);
+
+	regmap_write(cs4265->regmap, CS4265_PWRCTL, 0x0F);
+
+	ret = devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_cs4265, cs4265_dai,
+			ARRAY_SIZE(cs4265_dai));
+	return ret;
+}
+
+static const struct of_device_id cs4265_of_match[] = {
+	{ .compatible = "cirrus,cs4265", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cs4265_of_match);
+
+static const struct i2c_device_id cs4265_id[] = {
+	{ "cs4265", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cs4265_id);
+
+static struct i2c_driver cs4265_i2c_driver = {
+	.driver = {
+		.name = "cs4265",
+		.of_match_table = cs4265_of_match,
+	},
+	.id_table = cs4265_id,
+	.probe =    cs4265_i2c_probe,
+};
+
+module_i2c_driver(cs4265_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS4265 driver");
+MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paul.handrigan@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs4265.h b/sound/soc/codecs/cs4265.h
new file mode 100644
index 0000000..0a80a8d
--- /dev/null
+++ b/sound/soc/codecs/cs4265.h
@@ -0,0 +1,64 @@
+/*
+ * cs4265.h -- CS4265 ALSA SoC audio driver
+ *
+ * Copyright 2014 Cirrus Logic, Inc.
+ *
+ * Author: Paul Handrigan <paul.handrigan@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CS4265_H__
+#define __CS4265_H__
+
+#define CS4265_CHIP_ID				0x1
+#define CS4265_CHIP_ID_VAL			0xD0
+#define CS4265_CHIP_ID_MASK			0xF0
+#define CS4265_REV_ID_MASK			0x0F
+
+#define CS4265_PWRCTL				0x02
+#define CS4265_PWRCTL_PDN			1
+
+#define CS4265_DAC_CTL				0x3
+#define CS4265_DAC_CTL_MUTE			(1 << 2)
+#define CS4265_DAC_CTL_DIF			(3 << 4)
+
+#define CS4265_ADC_CTL				0x4
+#define CS4265_ADC_MASTER			1
+#define CS4265_ADC_DIF				(1 << 4)
+#define CS4265_ADC_FM				(3 << 6)
+
+#define CS4265_MCLK_FREQ			0x5
+#define CS4265_MCLK_FREQ_MASK			(7 << 4)
+
+#define CS4265_SIG_SEL				0x6
+#define CS4265_SIG_SEL_LOOP			(1 << 1)
+
+#define CS4265_CHB_PGA_CTL			0x7
+#define CS4265_CHA_PGA_CTL			0x8
+
+#define CS4265_ADC_CTL2				0x9
+
+#define CS4265_DAC_CHA_VOL			0xA
+#define CS4265_DAC_CHB_VOL			0xB
+
+#define CS4265_DAC_CTL2				0xC
+
+#define CS4265_INT_STATUS			0xD
+#define CS4265_INT_MASK				0xE
+#define CS4265_STATUS_MODE_MSB			0xF
+#define CS4265_STATUS_MODE_LSB			0x10
+
+#define CS4265_SPDIF_CTL1			0x11
+
+#define CS4265_SPDIF_CTL2			0x12
+#define CS4265_SPDIF_CTL2_MUTE			(1 << 4)
+#define CS4265_SPDIF_CTL2_DIF			(3 << 6)
+
+#define CS4265_C_DATA_BUFF			0x13
+#define CS4265_MAX_REGISTER			0x2A
+
+#endif
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
new file mode 100644
index 0000000..3c266ee
--- /dev/null
+++ b/sound/soc/codecs/cs4270.c
@@ -0,0 +1,753 @@
+/*
+ * CS4270 ALSA SoC (ASoC) codec driver
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2007-2009 Freescale Semiconductor, Inc.  This file is licensed
+ * under the terms of the GNU General Public License version 2.  This
+ * program is licensed "as is" without any warranty of any kind, whether
+ * express or implied.
+ *
+ * This is an ASoC device driver for the Cirrus Logic CS4270 codec.
+ *
+ * Current features/limitations:
+ *
+ * - Software mode is supported.  Stand-alone mode is not supported.
+ * - Only I2C is supported, not SPI
+ * - Support for master and slave mode
+ * - The machine driver's 'startup' function must call
+ *   cs4270_set_dai_sysclk() with the value of MCLK.
+ * - Only I2S and left-justified modes are supported
+ * - Power management is supported
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+
+/*
+ * The codec isn't really big-endian or little-endian, since the I2S
+ * interface requires data to be sent serially with the MSbit first.
+ * However, to support BE and LE I2S devices, we specify both here.  That
+ * way, ALSA will always match the bit patterns.
+ */
+#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8      | \
+			SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
+			SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+			SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
+			SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE)
+
+/* CS4270 registers addresses */
+#define CS4270_CHIPID	0x01	/* Chip ID */
+#define CS4270_PWRCTL	0x02	/* Power Control */
+#define CS4270_MODE	0x03	/* Mode Control */
+#define CS4270_FORMAT	0x04	/* Serial Format, ADC/DAC Control */
+#define CS4270_TRANS	0x05	/* Transition Control */
+#define CS4270_MUTE	0x06	/* Mute Control */
+#define CS4270_VOLA	0x07	/* DAC Channel A Volume Control */
+#define CS4270_VOLB	0x08	/* DAC Channel B Volume Control */
+
+#define CS4270_FIRSTREG	0x01
+#define CS4270_LASTREG	0x08
+#define CS4270_NUMREGS	(CS4270_LASTREG - CS4270_FIRSTREG + 1)
+#define CS4270_I2C_INCR	0x80
+
+/* Bit masks for the CS4270 registers */
+#define CS4270_CHIPID_ID	0xF0
+#define CS4270_CHIPID_REV	0x0F
+#define CS4270_PWRCTL_FREEZE	0x80
+#define CS4270_PWRCTL_PDN_ADC	0x20
+#define CS4270_PWRCTL_PDN_DAC	0x02
+#define CS4270_PWRCTL_PDN	0x01
+#define CS4270_PWRCTL_PDN_ALL	\
+	(CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC | CS4270_PWRCTL_PDN)
+#define CS4270_MODE_SPEED_MASK	0x30
+#define CS4270_MODE_1X		0x00
+#define CS4270_MODE_2X		0x10
+#define CS4270_MODE_4X		0x20
+#define CS4270_MODE_SLAVE	0x30
+#define CS4270_MODE_DIV_MASK	0x0E
+#define CS4270_MODE_DIV1	0x00
+#define CS4270_MODE_DIV15	0x02
+#define CS4270_MODE_DIV2	0x04
+#define CS4270_MODE_DIV3	0x06
+#define CS4270_MODE_DIV4	0x08
+#define CS4270_MODE_POPGUARD	0x01
+#define CS4270_FORMAT_FREEZE_A	0x80
+#define CS4270_FORMAT_FREEZE_B	0x40
+#define CS4270_FORMAT_LOOPBACK	0x20
+#define CS4270_FORMAT_DAC_MASK	0x18
+#define CS4270_FORMAT_DAC_LJ	0x00
+#define CS4270_FORMAT_DAC_I2S	0x08
+#define CS4270_FORMAT_DAC_RJ16	0x18
+#define CS4270_FORMAT_DAC_RJ24	0x10
+#define CS4270_FORMAT_ADC_MASK	0x01
+#define CS4270_FORMAT_ADC_LJ	0x00
+#define CS4270_FORMAT_ADC_I2S	0x01
+#define CS4270_TRANS_ONE_VOL	0x80
+#define CS4270_TRANS_SOFT	0x40
+#define CS4270_TRANS_ZERO	0x20
+#define CS4270_TRANS_INV_ADC_A	0x08
+#define CS4270_TRANS_INV_ADC_B	0x10
+#define CS4270_TRANS_INV_DAC_A	0x02
+#define CS4270_TRANS_INV_DAC_B	0x04
+#define CS4270_TRANS_DEEMPH	0x01
+#define CS4270_MUTE_AUTO	0x20
+#define CS4270_MUTE_ADC_A	0x08
+#define CS4270_MUTE_ADC_B	0x10
+#define CS4270_MUTE_POLARITY	0x04
+#define CS4270_MUTE_DAC_A	0x01
+#define CS4270_MUTE_DAC_B	0x02
+
+/* Power-on default values for the registers
+ *
+ * This array contains the power-on default values of the registers, with the
+ * exception of the "CHIPID" register (01h).  The lower four bits of that
+ * register contain the hardware revision, so it is treated as volatile.
+ */
+static const struct reg_default cs4270_reg_defaults[] = {
+	{ 2, 0x00 },
+	{ 3, 0x30 },
+	{ 4, 0x00 },
+	{ 5, 0x60 },
+	{ 6, 0x20 },
+	{ 7, 0x00 },
+	{ 8, 0x00 },
+};
+
+static const char *supply_names[] = {
+	"va", "vd", "vlc"
+};
+
+/* Private data for the CS4270 */
+struct cs4270_private {
+	struct regmap *regmap;
+	unsigned int mclk; /* Input frequency of the MCLK pin */
+	unsigned int mode; /* The mode (I2S or left-justified) */
+	unsigned int slave_mode;
+	unsigned int manual_mute;
+
+	/* power domain regulators */
+	struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+};
+
+static const struct snd_soc_dapm_widget cs4270_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AINL"),
+SND_SOC_DAPM_INPUT("AINR"),
+
+SND_SOC_DAPM_OUTPUT("AOUTL"),
+SND_SOC_DAPM_OUTPUT("AOUTR"),
+};
+
+static const struct snd_soc_dapm_route cs4270_dapm_routes[] = {
+	{ "Capture", NULL, "AINL" },
+	{ "Capture", NULL, "AINR" },
+
+	{ "AOUTL", NULL, "Playback" },
+	{ "AOUTR", NULL, "Playback" },
+};
+
+/**
+ * struct cs4270_mode_ratios - clock ratio tables
+ * @ratio: the ratio of MCLK to the sample rate
+ * @speed_mode: the Speed Mode bits to set in the Mode Control register for
+ *              this ratio
+ * @mclk: the Ratio Select bits to set in the Mode Control register for this
+ *        ratio
+ *
+ * The data for this chart is taken from Table 5 of the CS4270 reference
+ * manual.
+ *
+ * This table is used to determine how to program the Mode Control register.
+ * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling
+ * rates the CS4270 currently supports.
+ *
+ * @speed_mode is the corresponding bit pattern to be written to the
+ * MODE bits of the Mode Control Register
+ *
+ * @mclk is the corresponding bit pattern to be wirten to the MCLK bits of
+ * the Mode Control Register.
+ *
+ * In situations where a single ratio is represented by multiple speed
+ * modes, we favor the slowest speed.  E.g, for a ratio of 128, we pick
+ * double-speed instead of quad-speed.  However, the CS4270 errata states
+ * that divide-By-1.5 can cause failures, so we avoid that mode where
+ * possible.
+ *
+ * Errata: There is an errata for the CS4270 where divide-by-1.5 does not
+ * work if Vd is 3.3V.  If this effects you, select the
+ * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will
+ * never select any sample rates that require divide-by-1.5.
+ */
+struct cs4270_mode_ratios {
+	unsigned int ratio;
+	u8 speed_mode;
+	u8 mclk;
+};
+
+static struct cs4270_mode_ratios cs4270_mode_ratios[] = {
+	{64, CS4270_MODE_4X, CS4270_MODE_DIV1},
+#ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA
+	{96, CS4270_MODE_4X, CS4270_MODE_DIV15},
+#endif
+	{128, CS4270_MODE_2X, CS4270_MODE_DIV1},
+	{192, CS4270_MODE_4X, CS4270_MODE_DIV3},
+	{256, CS4270_MODE_1X, CS4270_MODE_DIV1},
+	{384, CS4270_MODE_2X, CS4270_MODE_DIV3},
+	{512, CS4270_MODE_1X, CS4270_MODE_DIV2},
+	{768, CS4270_MODE_1X, CS4270_MODE_DIV3},
+	{1024, CS4270_MODE_1X, CS4270_MODE_DIV4}
+};
+
+/* The number of MCLK/LRCK ratios supported by the CS4270 */
+#define NUM_MCLK_RATIOS		ARRAY_SIZE(cs4270_mode_ratios)
+
+static bool cs4270_reg_is_readable(struct device *dev, unsigned int reg)
+{
+	return (reg >= CS4270_FIRSTREG) && (reg <= CS4270_LASTREG);
+}
+
+static bool cs4270_reg_is_volatile(struct device *dev, unsigned int reg)
+{
+	/* Unreadable registers are considered volatile */
+	if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG))
+		return true;
+
+	return reg == CS4270_CHIPID;
+}
+
+/**
+ * cs4270_set_dai_sysclk - determine the CS4270 samples rates.
+ * @codec_dai: the codec DAI
+ * @clk_id: the clock ID (ignored)
+ * @freq: the MCLK input frequency
+ * @dir: the clock direction (ignored)
+ *
+ * This function is used to tell the codec driver what the input MCLK
+ * frequency is.
+ *
+ * The value of MCLK is used to determine which sample rates are supported
+ * by the CS4270.  The ratio of MCLK / Fs must be equal to one of nine
+ * supported values - 64, 96, 128, 192, 256, 384, 512, 768, and 1024.
+ *
+ * This function calculates the nine ratios and determines which ones match
+ * a standard sample rate.  If there's a match, then it is added to the list
+ * of supported sample rates.
+ *
+ * This function must be called by the machine driver's 'startup' function,
+ * otherwise the list of supported sample rates will not be available in
+ * time for ALSA.
+ *
+ * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause
+ * theoretically possible sample rates to be enabled. Call it again with a
+ * proper value set one the external clock is set (most probably you would do
+ * that from a machine's driver 'hw_param' hook.
+ */
+static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
+
+	cs4270->mclk = freq;
+	return 0;
+}
+
+/**
+ * cs4270_set_dai_fmt - configure the codec for the selected audio format
+ * @codec_dai: the codec DAI
+ * @format: a SND_SOC_DAIFMT_x value indicating the data format
+ *
+ * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the
+ * codec accordingly.
+ *
+ * Currently, this function only supports SND_SOC_DAIFMT_I2S and
+ * SND_SOC_DAIFMT_LEFT_J.  The CS4270 codec also supports right-justified
+ * data for playback only, but ASoC currently does not support different
+ * formats for playback vs. record.
+ */
+static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int format)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
+
+	/* set DAI format */
+	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_LEFT_J:
+		cs4270->mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
+		break;
+	default:
+		dev_err(component->dev, "invalid dai format\n");
+		return -EINVAL;
+	}
+
+	/* set master/slave audio interface */
+	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		cs4270->slave_mode = 1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		cs4270->slave_mode = 0;
+		break;
+	default:
+		/* all other modes are unsupported by the hardware */
+		dev_err(component->dev, "Unknown master/slave configuration\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * cs4270_hw_params - program the CS4270 with the given hardware parameters.
+ * @substream: the audio stream
+ * @params: the hardware parameters to set
+ * @dai: the SOC DAI (ignored)
+ *
+ * This function programs the hardware with the values provided.
+ * Specifically, the sample rate and the data format.
+ *
+ * The .ops functions are used to provide board-specific data, like input
+ * frequencies, to this driver.  This function takes that information,
+ * combines it with the hardware parameters provided, and programs the
+ * hardware accordingly.
+ */
+static int cs4270_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
+	int ret;
+	unsigned int i;
+	unsigned int rate;
+	unsigned int ratio;
+	int reg;
+
+	/* Figure out which MCLK/LRCK ratio to use */
+
+	rate = params_rate(params);	/* Sampling rate, in Hz */
+	ratio = cs4270->mclk / rate;	/* MCLK/LRCK ratio */
+
+	for (i = 0; i < NUM_MCLK_RATIOS; i++) {
+		if (cs4270_mode_ratios[i].ratio == ratio)
+			break;
+	}
+
+	if (i == NUM_MCLK_RATIOS) {
+		/* We did not find a matching ratio */
+		dev_err(component->dev, "could not find matching ratio\n");
+		return -EINVAL;
+	}
+
+	/* Set the sample rate */
+
+	reg = snd_soc_component_read32(component, CS4270_MODE);
+	reg &= ~(CS4270_MODE_SPEED_MASK | CS4270_MODE_DIV_MASK);
+	reg |= cs4270_mode_ratios[i].mclk;
+
+	if (cs4270->slave_mode)
+		reg |= CS4270_MODE_SLAVE;
+	else
+		reg |= cs4270_mode_ratios[i].speed_mode;
+
+	ret = snd_soc_component_write(component, CS4270_MODE, reg);
+	if (ret < 0) {
+		dev_err(component->dev, "i2c write failed\n");
+		return ret;
+	}
+
+	/* Set the DAI format */
+
+	reg = snd_soc_component_read32(component, CS4270_FORMAT);
+	reg &= ~(CS4270_FORMAT_DAC_MASK | CS4270_FORMAT_ADC_MASK);
+
+	switch (cs4270->mode) {
+	case SND_SOC_DAIFMT_I2S:
+		reg |= CS4270_FORMAT_DAC_I2S | CS4270_FORMAT_ADC_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg |= CS4270_FORMAT_DAC_LJ | CS4270_FORMAT_ADC_LJ;
+		break;
+	default:
+		dev_err(component->dev, "unknown dai format\n");
+		return -EINVAL;
+	}
+
+	ret = snd_soc_component_write(component, CS4270_FORMAT, reg);
+	if (ret < 0) {
+		dev_err(component->dev, "i2c write failed\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+/**
+ * cs4270_dai_mute - enable/disable the CS4270 external mute
+ * @dai: the SOC DAI
+ * @mute: 0 = disable mute, 1 = enable mute
+ *
+ * This function toggles the mute bits in the MUTE register.  The CS4270's
+ * mute capability is intended for external muting circuitry, so if the
+ * board does not have the MUTEA or MUTEB pins connected to such circuitry,
+ * then this function will do nothing.
+ */
+static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
+	int reg6;
+
+	reg6 = snd_soc_component_read32(component, CS4270_MUTE);
+
+	if (mute)
+		reg6 |= CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B;
+	else {
+		reg6 &= ~(CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B);
+		reg6 |= cs4270->manual_mute;
+	}
+
+	return snd_soc_component_write(component, CS4270_MUTE, reg6);
+}
+
+/**
+ * cs4270_soc_put_mute - put callback for the 'Master Playback switch'
+ * 			 alsa control.
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * This function basically passes the arguments on to the generic
+ * snd_soc_put_volsw() function and saves the mute information in
+ * our private data structure. This is because we want to prevent
+ * cs4270_dai_mute() neglecting the user's decision to manually
+ * mute the codec's output.
+ *
+ * Returns 0 for success.
+ */
+static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
+	int left = !ucontrol->value.integer.value[0];
+	int right = !ucontrol->value.integer.value[1];
+
+	cs4270->manual_mute = (left ? CS4270_MUTE_DAC_A : 0) |
+			      (right ? CS4270_MUTE_DAC_B : 0);
+
+	return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+/* A list of non-DAPM controls that the CS4270 supports */
+static const struct snd_kcontrol_new cs4270_snd_controls[] = {
+	SOC_DOUBLE_R("Master Playback Volume",
+		CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1),
+	SOC_SINGLE("Digital Sidetone Switch", CS4270_FORMAT, 5, 1, 0),
+	SOC_SINGLE("Soft Ramp Switch", CS4270_TRANS, 6, 1, 0),
+	SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 1, 0),
+	SOC_SINGLE("De-emphasis filter", CS4270_TRANS, 0, 1, 0),
+	SOC_SINGLE("Popguard Switch", CS4270_MODE, 0, 1, 1),
+	SOC_SINGLE("Auto-Mute Switch", CS4270_MUTE, 5, 1, 0),
+	SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 1),
+	SOC_DOUBLE_EXT("Master Playback Switch", CS4270_MUTE, 0, 1, 1, 1,
+		snd_soc_get_volsw, cs4270_soc_put_mute),
+};
+
+static const struct snd_soc_dai_ops cs4270_dai_ops = {
+	.hw_params	= cs4270_hw_params,
+	.set_sysclk	= cs4270_set_dai_sysclk,
+	.set_fmt	= cs4270_set_dai_fmt,
+	.digital_mute	= cs4270_dai_mute,
+};
+
+static struct snd_soc_dai_driver cs4270_dai = {
+	.name = "cs4270-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_CONTINUOUS,
+		.rate_min = 4000,
+		.rate_max = 216000,
+		.formats = CS4270_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_CONTINUOUS,
+		.rate_min = 4000,
+		.rate_max = 216000,
+		.formats = CS4270_FORMATS,
+	},
+	.ops = &cs4270_dai_ops,
+};
+
+/**
+ * cs4270_probe - ASoC probe function
+ * @pdev: platform device
+ *
+ * This function is called when ASoC has all the pieces it needs to
+ * instantiate a sound driver.
+ */
+static int cs4270_probe(struct snd_soc_component *component)
+{
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	/* Disable auto-mute.  This feature appears to be buggy.  In some
+	 * situations, auto-mute will not deactivate when it should, so we want
+	 * this feature disabled by default.  An application (e.g. alsactl) can
+	 * re-enabled it by using the controls.
+	 */
+	ret = snd_soc_component_update_bits(component, CS4270_MUTE, CS4270_MUTE_AUTO, 0);
+	if (ret < 0) {
+		dev_err(component->dev, "i2c write failed\n");
+		return ret;
+	}
+
+	/* Disable automatic volume control.  The hardware enables, and it
+	 * causes volume change commands to be delayed, sometimes until after
+	 * playback has started.  An application (e.g. alsactl) can
+	 * re-enabled it by using the controls.
+	 */
+	ret = snd_soc_component_update_bits(component, CS4270_TRANS,
+		CS4270_TRANS_SOFT | CS4270_TRANS_ZERO, 0);
+	if (ret < 0) {
+		dev_err(component->dev, "i2c write failed\n");
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
+				    cs4270->supplies);
+
+	return ret;
+}
+
+/**
+ * cs4270_remove - ASoC remove function
+ * @pdev: platform device
+ *
+ * This function is the counterpart to cs4270_probe().
+ */
+static void cs4270_remove(struct snd_soc_component *component)
+{
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
+
+	regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
+};
+
+#ifdef CONFIG_PM
+
+/* This suspend/resume implementation can handle both - a simple standby
+ * where the codec remains powered, and a full suspend, where the voltage
+ * domain the codec is connected to is teared down and/or any other hardware
+ * reset condition is asserted.
+ *
+ * The codec's own power saving features are enabled in the suspend callback,
+ * and all registers are written back to the hardware when resuming.
+ */
+
+static int cs4270_soc_suspend(struct snd_soc_component *component)
+{
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
+	int reg, ret;
+
+	reg = snd_soc_component_read32(component, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL;
+	if (reg < 0)
+		return reg;
+
+	ret = snd_soc_component_write(component, CS4270_PWRCTL, reg);
+	if (ret < 0)
+		return ret;
+
+	regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies),
+			       cs4270->supplies);
+
+	return 0;
+}
+
+static int cs4270_soc_resume(struct snd_soc_component *component)
+{
+	struct cs4270_private *cs4270 = snd_soc_component_get_drvdata(component);
+	int reg, ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
+				    cs4270->supplies);
+	if (ret != 0)
+		return ret;
+
+	/* In case the device was put to hard reset during sleep, we need to
+	 * wait 500ns here before any I2C communication. */
+	ndelay(500);
+
+	/* first restore the entire register cache ... */
+	regcache_sync(cs4270->regmap);
+
+	/* ... then disable the power-down bits */
+	reg = snd_soc_component_read32(component, CS4270_PWRCTL);
+	reg &= ~CS4270_PWRCTL_PDN_ALL;
+
+	return snd_soc_component_write(component, CS4270_PWRCTL, reg);
+}
+#else
+#define cs4270_soc_suspend	NULL
+#define cs4270_soc_resume	NULL
+#endif /* CONFIG_PM */
+
+/*
+ * ASoC codec driver structure
+ */
+static const struct snd_soc_component_driver soc_component_device_cs4270 = {
+	.probe			= cs4270_probe,
+	.remove			= cs4270_remove,
+	.suspend		= cs4270_soc_suspend,
+	.resume			= cs4270_soc_resume,
+	.controls		= cs4270_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs4270_snd_controls),
+	.dapm_widgets		= cs4270_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs4270_dapm_widgets),
+	.dapm_routes		= cs4270_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs4270_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+/*
+ * cs4270_of_match - the device tree bindings
+ */
+static const struct of_device_id cs4270_of_match[] = {
+	{ .compatible = "cirrus,cs4270", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cs4270_of_match);
+
+static const struct regmap_config cs4270_regmap = {
+	.reg_bits =		8,
+	.val_bits =		8,
+	.max_register =		CS4270_LASTREG,
+	.reg_defaults =		cs4270_reg_defaults,
+	.num_reg_defaults =	ARRAY_SIZE(cs4270_reg_defaults),
+	.cache_type =		REGCACHE_RBTREE,
+
+	.readable_reg =		cs4270_reg_is_readable,
+	.volatile_reg =		cs4270_reg_is_volatile,
+};
+
+/**
+ * cs4270_i2c_probe - initialize the I2C interface of the CS4270
+ * @i2c_client: the I2C client object
+ * @id: the I2C device ID (ignored)
+ *
+ * This function is called whenever the I2C subsystem finds a device that
+ * matches the device ID given via a prior call to i2c_add_driver().
+ */
+static int cs4270_i2c_probe(struct i2c_client *i2c_client,
+	const struct i2c_device_id *id)
+{
+	struct device_node *np = i2c_client->dev.of_node;
+	struct cs4270_private *cs4270;
+	unsigned int val;
+	int ret, i;
+
+	cs4270 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4270_private),
+			      GFP_KERNEL);
+	if (!cs4270)
+		return -ENOMEM;
+
+	/* get the power supply regulators */
+	for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+		cs4270->supplies[i].supply = supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c_client->dev,
+				      ARRAY_SIZE(cs4270->supplies),
+				      cs4270->supplies);
+	if (ret < 0)
+		return ret;
+
+	/* See if we have a way to bring the codec out of reset */
+	if (np) {
+		enum of_gpio_flags flags;
+		int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
+
+		if (gpio_is_valid(gpio)) {
+			ret = devm_gpio_request_one(&i2c_client->dev, gpio,
+				     flags & OF_GPIO_ACTIVE_LOW ?
+					GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
+				     "cs4270 reset");
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap);
+	if (IS_ERR(cs4270->regmap))
+		return PTR_ERR(cs4270->regmap);
+
+	/* Verify that we have a CS4270 */
+	ret = regmap_read(cs4270->regmap, CS4270_CHIPID, &val);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
+		       i2c_client->addr);
+		return ret;
+	}
+	/* The top four bits of the chip ID should be 1100. */
+	if ((val & 0xF0) != 0xC0) {
+		dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
+		       i2c_client->addr);
+		return -ENODEV;
+	}
+
+	dev_info(&i2c_client->dev, "found device at i2c address %X\n",
+		i2c_client->addr);
+	dev_info(&i2c_client->dev, "hardware revision %X\n", val & 0xF);
+
+	i2c_set_clientdata(i2c_client, cs4270);
+
+	ret = devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_device_cs4270, &cs4270_dai, 1);
+	return ret;
+}
+
+/*
+ * cs4270_id - I2C device IDs supported by this driver
+ */
+static const struct i2c_device_id cs4270_id[] = {
+	{"cs4270", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, cs4270_id);
+
+/*
+ * cs4270_i2c_driver - I2C device identification
+ *
+ * This structure tells the I2C subsystem how to identify and support a
+ * given I2C device type.
+ */
+static struct i2c_driver cs4270_i2c_driver = {
+	.driver = {
+		.name = "cs4270",
+		.of_match_table = cs4270_of_match,
+	},
+	.id_table = cs4270_id,
+	.probe = cs4270_i2c_probe,
+};
+
+module_i2c_driver(cs4270_i2c_driver);
+
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs4271-i2c.c b/sound/soc/codecs/cs4271-i2c.c
new file mode 100644
index 0000000..ff73730
--- /dev/null
+++ b/sound/soc/codecs/cs4271-i2c.c
@@ -0,0 +1,54 @@
+/*
+ * CS4271 I2C audio driver
+ *
+ * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "cs4271.h"
+
+static int cs4271_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct regmap_config config;
+
+	config = cs4271_regmap_config;
+	config.reg_bits = 8;
+	config.val_bits = 8;
+
+	return cs4271_probe(&client->dev,
+			    devm_regmap_init_i2c(client, &config));
+}
+
+static const struct i2c_device_id cs4271_i2c_id[] = {
+	{ "cs4271", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id);
+
+static struct i2c_driver cs4271_i2c_driver = {
+	.driver = {
+		.name = "cs4271",
+		.of_match_table = of_match_ptr(cs4271_dt_ids),
+	},
+	.probe = cs4271_i2c_probe,
+	.id_table = cs4271_i2c_id,
+};
+module_i2c_driver(cs4271_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS4271 I2C Driver");
+MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs4271-spi.c b/sound/soc/codecs/cs4271-spi.c
new file mode 100644
index 0000000..217f6dc
--- /dev/null
+++ b/sound/soc/codecs/cs4271-spi.c
@@ -0,0 +1,47 @@
+/*
+ * CS4271 SPI audio driver
+ *
+ * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "cs4271.h"
+
+static int cs4271_spi_probe(struct spi_device *spi)
+{
+	struct regmap_config config;
+
+	config = cs4271_regmap_config;
+	config.reg_bits = 16;
+	config.val_bits = 8;
+	config.read_flag_mask = 0x21;
+	config.write_flag_mask = 0x20;
+
+	return cs4271_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
+}
+
+static struct spi_driver cs4271_spi_driver = {
+	.driver = {
+		.name	= "cs4271",
+		.of_match_table = of_match_ptr(cs4271_dt_ids),
+	},
+	.probe		= cs4271_spi_probe,
+};
+module_spi_driver(cs4271_spi_driver);
+
+MODULE_DESCRIPTION("ASoC CS4271 SPI Driver");
+MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
new file mode 100644
index 0000000..849fdb2
--- /dev/null
+++ b/sound/soc/codecs/cs4271.c
@@ -0,0 +1,730 @@
+/*
+ * CS4271 ASoC codec driver
+ *
+ * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
+ *
+ * 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.
+ *
+ * This driver support CS4271 codec being master or slave, working
+ * in control port mode, connected either via SPI or I2C.
+ * The data format accepted is I2S or left-justified.
+ * DAPM support not implemented.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/cs4271.h>
+#include "cs4271.h"
+
+#define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			    SNDRV_PCM_FMTBIT_S24_LE | \
+			    SNDRV_PCM_FMTBIT_S32_LE)
+#define CS4271_PCM_RATES SNDRV_PCM_RATE_8000_192000
+
+/*
+ * CS4271 registers
+ */
+#define CS4271_MODE1	0x01	/* Mode Control 1 */
+#define CS4271_DACCTL	0x02	/* DAC Control */
+#define CS4271_DACVOL	0x03	/* DAC Volume & Mixing Control */
+#define CS4271_VOLA	0x04	/* DAC Channel A Volume Control */
+#define CS4271_VOLB	0x05	/* DAC Channel B Volume Control */
+#define CS4271_ADCCTL	0x06	/* ADC Control */
+#define CS4271_MODE2	0x07	/* Mode Control 2 */
+#define CS4271_CHIPID	0x08	/* Chip ID */
+
+#define CS4271_FIRSTREG	CS4271_MODE1
+#define CS4271_LASTREG	CS4271_MODE2
+#define CS4271_NR_REGS	((CS4271_LASTREG & 0xFF) + 1)
+
+/* Bit masks for the CS4271 registers */
+#define CS4271_MODE1_MODE_MASK	0xC0
+#define CS4271_MODE1_MODE_1X	0x00
+#define CS4271_MODE1_MODE_2X	0x80
+#define CS4271_MODE1_MODE_4X	0xC0
+
+#define CS4271_MODE1_DIV_MASK	0x30
+#define CS4271_MODE1_DIV_1	0x00
+#define CS4271_MODE1_DIV_15	0x10
+#define CS4271_MODE1_DIV_2	0x20
+#define CS4271_MODE1_DIV_3	0x30
+
+#define CS4271_MODE1_MASTER	0x08
+
+#define CS4271_MODE1_DAC_DIF_MASK	0x07
+#define CS4271_MODE1_DAC_DIF_LJ		0x00
+#define CS4271_MODE1_DAC_DIF_I2S	0x01
+#define CS4271_MODE1_DAC_DIF_RJ16	0x02
+#define CS4271_MODE1_DAC_DIF_RJ24	0x03
+#define CS4271_MODE1_DAC_DIF_RJ20	0x04
+#define CS4271_MODE1_DAC_DIF_RJ18	0x05
+
+#define CS4271_DACCTL_AMUTE	0x80
+#define CS4271_DACCTL_IF_SLOW	0x40
+
+#define CS4271_DACCTL_DEM_MASK	0x30
+#define CS4271_DACCTL_DEM_DIS	0x00
+#define CS4271_DACCTL_DEM_441	0x10
+#define CS4271_DACCTL_DEM_48	0x20
+#define CS4271_DACCTL_DEM_32	0x30
+
+#define CS4271_DACCTL_SVRU	0x08
+#define CS4271_DACCTL_SRD	0x04
+#define CS4271_DACCTL_INVA	0x02
+#define CS4271_DACCTL_INVB	0x01
+
+#define CS4271_DACVOL_BEQUA	0x40
+#define CS4271_DACVOL_SOFT	0x20
+#define CS4271_DACVOL_ZEROC	0x10
+
+#define CS4271_DACVOL_ATAPI_MASK	0x0F
+#define CS4271_DACVOL_ATAPI_M_M		0x00
+#define CS4271_DACVOL_ATAPI_M_BR	0x01
+#define CS4271_DACVOL_ATAPI_M_BL	0x02
+#define CS4271_DACVOL_ATAPI_M_BLR2	0x03
+#define CS4271_DACVOL_ATAPI_AR_M	0x04
+#define CS4271_DACVOL_ATAPI_AR_BR	0x05
+#define CS4271_DACVOL_ATAPI_AR_BL	0x06
+#define CS4271_DACVOL_ATAPI_AR_BLR2	0x07
+#define CS4271_DACVOL_ATAPI_AL_M	0x08
+#define CS4271_DACVOL_ATAPI_AL_BR	0x09
+#define CS4271_DACVOL_ATAPI_AL_BL	0x0A
+#define CS4271_DACVOL_ATAPI_AL_BLR2	0x0B
+#define CS4271_DACVOL_ATAPI_ALR2_M	0x0C
+#define CS4271_DACVOL_ATAPI_ALR2_BR	0x0D
+#define CS4271_DACVOL_ATAPI_ALR2_BL	0x0E
+#define CS4271_DACVOL_ATAPI_ALR2_BLR2	0x0F
+
+#define CS4271_VOLA_MUTE	0x80
+#define CS4271_VOLA_VOL_MASK	0x7F
+#define CS4271_VOLB_MUTE	0x80
+#define CS4271_VOLB_VOL_MASK	0x7F
+
+#define CS4271_ADCCTL_DITHER16	0x20
+
+#define CS4271_ADCCTL_ADC_DIF_MASK	0x10
+#define CS4271_ADCCTL_ADC_DIF_LJ	0x00
+#define CS4271_ADCCTL_ADC_DIF_I2S	0x10
+
+#define CS4271_ADCCTL_MUTEA	0x08
+#define CS4271_ADCCTL_MUTEB	0x04
+#define CS4271_ADCCTL_HPFDA	0x02
+#define CS4271_ADCCTL_HPFDB	0x01
+
+#define CS4271_MODE2_LOOP	0x10
+#define CS4271_MODE2_MUTECAEQUB	0x08
+#define CS4271_MODE2_FREEZE	0x04
+#define CS4271_MODE2_CPEN	0x02
+#define CS4271_MODE2_PDN	0x01
+
+#define CS4271_CHIPID_PART_MASK	0xF0
+#define CS4271_CHIPID_REV_MASK	0x0F
+
+/*
+ * Default CS4271 power-up configuration
+ * Array contains non-existing in hw register at address 0
+ * Array do not include Chip ID, as codec driver does not use
+ * registers read operations at all
+ */
+static const struct reg_default cs4271_reg_defaults[] = {
+	{ CS4271_MODE1,		0, },
+	{ CS4271_DACCTL,	CS4271_DACCTL_AMUTE, },
+	{ CS4271_DACVOL,	CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR, },
+	{ CS4271_VOLA,		0, },
+	{ CS4271_VOLB,		0, },
+	{ CS4271_ADCCTL,	0, },
+	{ CS4271_MODE2,		0, },
+};
+
+static bool cs4271_volatile_reg(struct device *dev, unsigned int reg)
+{
+	return reg == CS4271_CHIPID;
+}
+
+static const char * const supply_names[] = {
+	"vd", "vl", "va"
+};
+
+struct cs4271_private {
+	unsigned int			mclk;
+	bool				master;
+	bool				deemph;
+	struct regmap			*regmap;
+	/* Current sample rate for de-emphasis control */
+	int				rate;
+	/* GPIO driving Reset pin, if any */
+	int				gpio_nreset;
+	/* GPIO that disable serial bus, if any */
+	int				gpio_disable;
+	/* enable soft reset workaround */
+	bool				enable_soft_reset;
+	struct regulator_bulk_data      supplies[ARRAY_SIZE(supply_names)];
+};
+
+static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AINA"),
+SND_SOC_DAPM_INPUT("AINB"),
+
+SND_SOC_DAPM_OUTPUT("AOUTA+"),
+SND_SOC_DAPM_OUTPUT("AOUTA-"),
+SND_SOC_DAPM_OUTPUT("AOUTB+"),
+SND_SOC_DAPM_OUTPUT("AOUTB-"),
+};
+
+static const struct snd_soc_dapm_route cs4271_dapm_routes[] = {
+	{ "Capture", NULL, "AINA" },
+	{ "Capture", NULL, "AINB" },
+
+	{ "AOUTA+", NULL, "Playback" },
+	{ "AOUTA-", NULL, "Playback" },
+	{ "AOUTB+", NULL, "Playback" },
+	{ "AOUTB-", NULL, "Playback" },
+};
+
+/*
+ * @freq is the desired MCLK rate
+ * MCLK rate should (c) be the sample rate, multiplied by one of the
+ * ratios listed in cs4271_mclk_fs_ratios table
+ */
+static int cs4271_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
+
+	cs4271->mclk = freq;
+	return 0;
+}
+
+static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int format)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
+	unsigned int val = 0;
+	int ret;
+
+	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		cs4271->master = 0;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		cs4271->master = 1;
+		val |= CS4271_MODE1_MASTER;
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_LEFT_J:
+		val |= CS4271_MODE1_DAC_DIF_LJ;
+		ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL,
+			CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_LJ);
+		if (ret < 0)
+			return ret;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		val |= CS4271_MODE1_DAC_DIF_I2S;
+		ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL,
+			CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_I2S);
+		if (ret < 0)
+			return ret;
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1,
+		CS4271_MODE1_DAC_DIF_MASK | CS4271_MODE1_MASTER, val);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static int cs4271_deemph[] = {0, 44100, 48000, 32000};
+
+static int cs4271_set_deemph(struct snd_soc_component *component)
+{
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
+	int i, ret;
+	int val = CS4271_DACCTL_DEM_DIS;
+
+	if (cs4271->deemph) {
+		/* Find closest de-emphasis freq */
+		val = 1;
+		for (i = 2; i < ARRAY_SIZE(cs4271_deemph); i++)
+			if (abs(cs4271_deemph[i] - cs4271->rate) <
+			    abs(cs4271_deemph[val] - cs4271->rate))
+				val = i;
+		val <<= 4;
+	}
+
+	ret = regmap_update_bits(cs4271->regmap, CS4271_DACCTL,
+		CS4271_DACCTL_DEM_MASK, val);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = cs4271->deemph;
+	return 0;
+}
+
+static int cs4271_put_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
+
+	cs4271->deemph = ucontrol->value.integer.value[0];
+	return cs4271_set_deemph(component);
+}
+
+struct cs4271_clk_cfg {
+	bool		master;		/* codec mode */
+	u8		speed_mode;	/* codec speed mode: 1x, 2x, 4x */
+	unsigned short	ratio;		/* MCLK / sample rate */
+	u8		ratio_mask;	/* ratio bit mask for Master mode */
+};
+
+static struct cs4271_clk_cfg cs4271_clk_tab[] = {
+	{1, CS4271_MODE1_MODE_1X, 256,  CS4271_MODE1_DIV_1},
+	{1, CS4271_MODE1_MODE_1X, 384,  CS4271_MODE1_DIV_15},
+	{1, CS4271_MODE1_MODE_1X, 512,  CS4271_MODE1_DIV_2},
+	{1, CS4271_MODE1_MODE_1X, 768,  CS4271_MODE1_DIV_3},
+	{1, CS4271_MODE1_MODE_2X, 128,  CS4271_MODE1_DIV_1},
+	{1, CS4271_MODE1_MODE_2X, 192,  CS4271_MODE1_DIV_15},
+	{1, CS4271_MODE1_MODE_2X, 256,  CS4271_MODE1_DIV_2},
+	{1, CS4271_MODE1_MODE_2X, 384,  CS4271_MODE1_DIV_3},
+	{1, CS4271_MODE1_MODE_4X, 64,   CS4271_MODE1_DIV_1},
+	{1, CS4271_MODE1_MODE_4X, 96,   CS4271_MODE1_DIV_15},
+	{1, CS4271_MODE1_MODE_4X, 128,  CS4271_MODE1_DIV_2},
+	{1, CS4271_MODE1_MODE_4X, 192,  CS4271_MODE1_DIV_3},
+	{0, CS4271_MODE1_MODE_1X, 256,  CS4271_MODE1_DIV_1},
+	{0, CS4271_MODE1_MODE_1X, 384,  CS4271_MODE1_DIV_1},
+	{0, CS4271_MODE1_MODE_1X, 512,  CS4271_MODE1_DIV_1},
+	{0, CS4271_MODE1_MODE_1X, 768,  CS4271_MODE1_DIV_2},
+	{0, CS4271_MODE1_MODE_1X, 1024, CS4271_MODE1_DIV_2},
+	{0, CS4271_MODE1_MODE_2X, 128,  CS4271_MODE1_DIV_1},
+	{0, CS4271_MODE1_MODE_2X, 192,  CS4271_MODE1_DIV_1},
+	{0, CS4271_MODE1_MODE_2X, 256,  CS4271_MODE1_DIV_1},
+	{0, CS4271_MODE1_MODE_2X, 384,  CS4271_MODE1_DIV_2},
+	{0, CS4271_MODE1_MODE_2X, 512,  CS4271_MODE1_DIV_2},
+	{0, CS4271_MODE1_MODE_4X, 64,   CS4271_MODE1_DIV_1},
+	{0, CS4271_MODE1_MODE_4X, 96,   CS4271_MODE1_DIV_1},
+	{0, CS4271_MODE1_MODE_4X, 128,  CS4271_MODE1_DIV_1},
+	{0, CS4271_MODE1_MODE_4X, 192,  CS4271_MODE1_DIV_2},
+	{0, CS4271_MODE1_MODE_4X, 256,  CS4271_MODE1_DIV_2},
+};
+
+#define CS4171_NR_RATIOS ARRAY_SIZE(cs4271_clk_tab)
+
+static int cs4271_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
+	int i, ret;
+	unsigned int ratio, val;
+
+	if (cs4271->enable_soft_reset) {
+		/*
+		 * Put the codec in soft reset and back again in case it's not
+		 * currently streaming data. This way of bringing the codec in
+		 * sync to the current clocks is not explicitly documented in
+		 * the data sheet, but it seems to work fine, and in contrast
+		 * to a read hardware reset, we don't have to sync back all
+		 * registers every time.
+		 */
+
+		if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+		     !dai->capture_active) ||
+		    (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
+		     !dai->playback_active)) {
+			ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+						 CS4271_MODE2_PDN,
+						 CS4271_MODE2_PDN);
+			if (ret < 0)
+				return ret;
+
+			ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+						 CS4271_MODE2_PDN, 0);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	cs4271->rate = params_rate(params);
+
+	/* Configure DAC */
+	if (cs4271->rate < 50000)
+		val = CS4271_MODE1_MODE_1X;
+	else if (cs4271->rate < 100000)
+		val = CS4271_MODE1_MODE_2X;
+	else
+		val = CS4271_MODE1_MODE_4X;
+
+	ratio = cs4271->mclk / cs4271->rate;
+	for (i = 0; i < CS4171_NR_RATIOS; i++)
+		if ((cs4271_clk_tab[i].master == cs4271->master) &&
+		    (cs4271_clk_tab[i].speed_mode == val) &&
+		    (cs4271_clk_tab[i].ratio == ratio))
+			break;
+
+	if (i == CS4171_NR_RATIOS) {
+		dev_err(component->dev, "Invalid sample rate\n");
+		return -EINVAL;
+	}
+
+	val |= cs4271_clk_tab[i].ratio_mask;
+
+	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1,
+		CS4271_MODE1_MODE_MASK | CS4271_MODE1_DIV_MASK, val);
+	if (ret < 0)
+		return ret;
+
+	return cs4271_set_deemph(component);
+}
+
+static int cs4271_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
+	int ret;
+	int val_a = 0;
+	int val_b = 0;
+
+	if (stream != SNDRV_PCM_STREAM_PLAYBACK)
+		return 0;
+
+	if (mute) {
+		val_a = CS4271_VOLA_MUTE;
+		val_b = CS4271_VOLB_MUTE;
+	}
+
+	ret = regmap_update_bits(cs4271->regmap, CS4271_VOLA,
+				 CS4271_VOLA_MUTE, val_a);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_update_bits(cs4271->regmap, CS4271_VOLB,
+				 CS4271_VOLB_MUTE, val_b);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+/* CS4271 controls */
+static DECLARE_TLV_DB_SCALE(cs4271_dac_tlv, -12700, 100, 0);
+
+static const struct snd_kcontrol_new cs4271_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("Master Playback Volume", CS4271_VOLA, CS4271_VOLB,
+		0, 0x7F, 1, cs4271_dac_tlv),
+	SOC_SINGLE("Digital Loopback Switch", CS4271_MODE2, 4, 1, 0),
+	SOC_SINGLE("Soft Ramp Switch", CS4271_DACVOL, 5, 1, 0),
+	SOC_SINGLE("Zero Cross Switch", CS4271_DACVOL, 4, 1, 0),
+	SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
+		cs4271_get_deemph, cs4271_put_deemph),
+	SOC_SINGLE("Auto-Mute Switch", CS4271_DACCTL, 7, 1, 0),
+	SOC_SINGLE("Slow Roll Off Filter Switch", CS4271_DACCTL, 6, 1, 0),
+	SOC_SINGLE("Soft Volume Ramp-Up Switch", CS4271_DACCTL, 3, 1, 0),
+	SOC_SINGLE("Soft Ramp-Down Switch", CS4271_DACCTL, 2, 1, 0),
+	SOC_SINGLE("Left Channel Inversion Switch", CS4271_DACCTL, 1, 1, 0),
+	SOC_SINGLE("Right Channel Inversion Switch", CS4271_DACCTL, 0, 1, 0),
+	SOC_DOUBLE("Master Capture Switch", CS4271_ADCCTL, 3, 2, 1, 1),
+	SOC_SINGLE("Dither 16-Bit Data Switch", CS4271_ADCCTL, 5, 1, 0),
+	SOC_DOUBLE("High Pass Filter Switch", CS4271_ADCCTL, 1, 0, 1, 1),
+	SOC_DOUBLE_R("Master Playback Switch", CS4271_VOLA, CS4271_VOLB,
+		7, 1, 1),
+};
+
+static const struct snd_soc_dai_ops cs4271_dai_ops = {
+	.hw_params	= cs4271_hw_params,
+	.set_sysclk	= cs4271_set_dai_sysclk,
+	.set_fmt	= cs4271_set_dai_fmt,
+	.mute_stream	= cs4271_mute_stream,
+};
+
+static struct snd_soc_dai_driver cs4271_dai = {
+	.name = "cs4271-hifi",
+	.playback = {
+		.stream_name	= "Playback",
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= CS4271_PCM_RATES,
+		.formats	= CS4271_PCM_FORMATS,
+	},
+	.capture = {
+		.stream_name	= "Capture",
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= CS4271_PCM_RATES,
+		.formats	= CS4271_PCM_FORMATS,
+	},
+	.ops = &cs4271_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int cs4271_reset(struct snd_soc_component *component)
+{
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
+
+	if (gpio_is_valid(cs4271->gpio_nreset)) {
+		gpio_direction_output(cs4271->gpio_nreset, 0);
+		mdelay(1);
+		gpio_set_value(cs4271->gpio_nreset, 1);
+		mdelay(1);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int cs4271_soc_suspend(struct snd_soc_component *component)
+{
+	int ret;
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
+
+	/* Set power-down bit */
+	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+				 CS4271_MODE2_PDN, CS4271_MODE2_PDN);
+	if (ret < 0)
+		return ret;
+
+	regcache_mark_dirty(cs4271->regmap);
+	regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
+
+	return 0;
+}
+
+static int cs4271_soc_resume(struct snd_soc_component *component)
+{
+	int ret;
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),
+				    cs4271->supplies);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to enable regulators: %d\n", ret);
+		return ret;
+	}
+
+	/* Do a proper reset after power up */
+	cs4271_reset(component);
+
+	/* Restore codec state */
+	ret = regcache_sync(cs4271->regmap);
+	if (ret < 0)
+		return ret;
+
+	/* then disable the power-down bit */
+	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+				 CS4271_MODE2_PDN, 0);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+#else
+#define cs4271_soc_suspend	NULL
+#define cs4271_soc_resume	NULL
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_OF
+const struct of_device_id cs4271_dt_ids[] = {
+	{ .compatible = "cirrus,cs4271", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cs4271_dt_ids);
+EXPORT_SYMBOL_GPL(cs4271_dt_ids);
+#endif
+
+static int cs4271_component_probe(struct snd_soc_component *component)
+{
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
+	struct cs4271_platform_data *cs4271plat = component->dev->platform_data;
+	int ret;
+	bool amutec_eq_bmutec = false;
+
+#ifdef CONFIG_OF
+	if (of_match_device(cs4271_dt_ids, component->dev)) {
+		if (of_get_property(component->dev->of_node,
+				     "cirrus,amutec-eq-bmutec", NULL))
+			amutec_eq_bmutec = true;
+
+		if (of_get_property(component->dev->of_node,
+				     "cirrus,enable-soft-reset", NULL))
+			cs4271->enable_soft_reset = true;
+	}
+#endif
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),
+				    cs4271->supplies);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to enable regulators: %d\n", ret);
+		return ret;
+	}
+
+	if (cs4271plat) {
+		amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
+		cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
+	}
+
+	/* Reset codec */
+	cs4271_reset(component);
+
+	ret = regcache_sync(cs4271->regmap);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+				 CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
+				 CS4271_MODE2_PDN | CS4271_MODE2_CPEN);
+	if (ret < 0)
+		return ret;
+	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+				 CS4271_MODE2_PDN, 0);
+	if (ret < 0)
+		return ret;
+	/* Power-up sequence requires 85 uS */
+	udelay(85);
+
+	if (amutec_eq_bmutec)
+		regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+				   CS4271_MODE2_MUTECAEQUB,
+				   CS4271_MODE2_MUTECAEQUB);
+
+	return 0;
+}
+
+static void cs4271_component_remove(struct snd_soc_component *component)
+{
+	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
+
+	if (gpio_is_valid(cs4271->gpio_nreset))
+		/* Set codec to the reset state */
+		gpio_set_value(cs4271->gpio_nreset, 0);
+
+	regcache_mark_dirty(cs4271->regmap);
+	regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
+};
+
+static const struct snd_soc_component_driver soc_component_dev_cs4271 = {
+	.probe			= cs4271_component_probe,
+	.remove			= cs4271_component_remove,
+	.suspend		= cs4271_soc_suspend,
+	.resume			= cs4271_soc_resume,
+	.controls		= cs4271_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs4271_snd_controls),
+	.dapm_widgets		= cs4271_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs4271_dapm_widgets),
+	.dapm_routes		= cs4271_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs4271_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int cs4271_common_probe(struct device *dev,
+			       struct cs4271_private **c)
+{
+	struct cs4271_platform_data *cs4271plat = dev->platform_data;
+	struct cs4271_private *cs4271;
+	int i, ret;
+
+	cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL);
+	if (!cs4271)
+		return -ENOMEM;
+
+	if (of_match_device(cs4271_dt_ids, dev))
+		cs4271->gpio_nreset =
+			of_get_named_gpio(dev->of_node, "reset-gpio", 0);
+
+	if (cs4271plat)
+		cs4271->gpio_nreset = cs4271plat->gpio_nreset;
+
+	if (gpio_is_valid(cs4271->gpio_nreset)) {
+		ret = devm_gpio_request(dev, cs4271->gpio_nreset,
+					"CS4271 Reset");
+		if (ret < 0)
+			return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+		cs4271->supplies[i].supply = supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs4271->supplies),
+					cs4271->supplies);
+
+	if (ret < 0) {
+		dev_err(dev, "Failed to get regulators: %d\n", ret);
+		return ret;
+	}
+
+	*c = cs4271;
+	return 0;
+}
+
+const struct regmap_config cs4271_regmap_config = {
+	.max_register = CS4271_LASTREG,
+
+	.reg_defaults = cs4271_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = cs4271_volatile_reg,
+};
+EXPORT_SYMBOL_GPL(cs4271_regmap_config);
+
+int cs4271_probe(struct device *dev, struct regmap *regmap)
+{
+	struct cs4271_private *cs4271;
+	int ret;
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	ret = cs4271_common_probe(dev, &cs4271);
+	if (ret < 0)
+		return ret;
+
+	dev_set_drvdata(dev, cs4271);
+	cs4271->regmap = regmap;
+
+	return devm_snd_soc_register_component(dev, &soc_component_dev_cs4271,
+					       &cs4271_dai, 1);
+}
+EXPORT_SYMBOL_GPL(cs4271_probe);
+
+MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
+MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs4271.h b/sound/soc/codecs/cs4271.h
new file mode 100644
index 0000000..290283a
--- /dev/null
+++ b/sound/soc/codecs/cs4271.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _CS4271_PRIV_H
+#define _CS4271_PRIV_H
+
+#include <linux/regmap.h>
+
+extern const struct of_device_id cs4271_dt_ids[];
+extern const struct regmap_config cs4271_regmap_config;
+
+int cs4271_probe(struct device *dev, struct regmap *regmap);
+
+#endif
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
new file mode 100644
index 0000000..651329b
--- /dev/null
+++ b/sound/soc/codecs/cs42l42.c
@@ -0,0 +1,1979 @@
+/*
+ * cs42l42.c -- CS42L42 ALSA SoC audio driver
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: James Schulman <james.schulman@cirrus.com>
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ * Author: Michael White <michael.white@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <dt-bindings/sound/cs42l42.h>
+
+#include "cs42l42.h"
+
+static const struct reg_default cs42l42_reg_defaults[] = {
+	{ CS42L42_FRZ_CTL,			0x00 },
+	{ CS42L42_SRC_CTL,			0x10 },
+	{ CS42L42_MCLK_STATUS,			0x02 },
+	{ CS42L42_MCLK_CTL,			0x02 },
+	{ CS42L42_SFTRAMP_RATE,			0xA4 },
+	{ CS42L42_I2C_DEBOUNCE,			0x88 },
+	{ CS42L42_I2C_STRETCH,			0x03 },
+	{ CS42L42_I2C_TIMEOUT,			0xB7 },
+	{ CS42L42_PWR_CTL1,			0xFF },
+	{ CS42L42_PWR_CTL2,			0x84 },
+	{ CS42L42_PWR_CTL3,			0x20 },
+	{ CS42L42_RSENSE_CTL1,			0x40 },
+	{ CS42L42_RSENSE_CTL2,			0x00 },
+	{ CS42L42_OSC_SWITCH,			0x00 },
+	{ CS42L42_OSC_SWITCH_STATUS,		0x05 },
+	{ CS42L42_RSENSE_CTL3,			0x1B },
+	{ CS42L42_TSENSE_CTL,			0x1B },
+	{ CS42L42_TSRS_INT_DISABLE,		0x00 },
+	{ CS42L42_TRSENSE_STATUS,		0x00 },
+	{ CS42L42_HSDET_CTL1,			0x77 },
+	{ CS42L42_HSDET_CTL2,			0x00 },
+	{ CS42L42_HS_SWITCH_CTL,		0xF3 },
+	{ CS42L42_HS_DET_STATUS,		0x00 },
+	{ CS42L42_HS_CLAMP_DISABLE,		0x00 },
+	{ CS42L42_MCLK_SRC_SEL,			0x00 },
+	{ CS42L42_SPDIF_CLK_CFG,		0x00 },
+	{ CS42L42_FSYNC_PW_LOWER,		0x00 },
+	{ CS42L42_FSYNC_PW_UPPER,		0x00 },
+	{ CS42L42_FSYNC_P_LOWER,		0xF9 },
+	{ CS42L42_FSYNC_P_UPPER,		0x00 },
+	{ CS42L42_ASP_CLK_CFG,			0x00 },
+	{ CS42L42_ASP_FRM_CFG,			0x10 },
+	{ CS42L42_FS_RATE_EN,			0x00 },
+	{ CS42L42_IN_ASRC_CLK,			0x00 },
+	{ CS42L42_OUT_ASRC_CLK,			0x00 },
+	{ CS42L42_PLL_DIV_CFG1,			0x00 },
+	{ CS42L42_ADC_OVFL_STATUS,		0x00 },
+	{ CS42L42_MIXER_STATUS,			0x00 },
+	{ CS42L42_SRC_STATUS,			0x00 },
+	{ CS42L42_ASP_RX_STATUS,		0x00 },
+	{ CS42L42_ASP_TX_STATUS,		0x00 },
+	{ CS42L42_CODEC_STATUS,			0x00 },
+	{ CS42L42_DET_INT_STATUS1,		0x00 },
+	{ CS42L42_DET_INT_STATUS2,		0x00 },
+	{ CS42L42_SRCPL_INT_STATUS,		0x00 },
+	{ CS42L42_VPMON_STATUS,			0x00 },
+	{ CS42L42_PLL_LOCK_STATUS,		0x00 },
+	{ CS42L42_TSRS_PLUG_STATUS,		0x00 },
+	{ CS42L42_ADC_OVFL_INT_MASK,		0x01 },
+	{ CS42L42_MIXER_INT_MASK,		0x0F },
+	{ CS42L42_SRC_INT_MASK,			0x0F },
+	{ CS42L42_ASP_RX_INT_MASK,		0x1F },
+	{ CS42L42_ASP_TX_INT_MASK,		0x0F },
+	{ CS42L42_CODEC_INT_MASK,		0x03 },
+	{ CS42L42_SRCPL_INT_MASK,		0xFF },
+	{ CS42L42_VPMON_INT_MASK,		0x01 },
+	{ CS42L42_PLL_LOCK_INT_MASK,		0x01 },
+	{ CS42L42_TSRS_PLUG_INT_MASK,		0x0F },
+	{ CS42L42_PLL_CTL1,			0x00 },
+	{ CS42L42_PLL_DIV_FRAC0,		0x00 },
+	{ CS42L42_PLL_DIV_FRAC1,		0x00 },
+	{ CS42L42_PLL_DIV_FRAC2,		0x00 },
+	{ CS42L42_PLL_DIV_INT,			0x40 },
+	{ CS42L42_PLL_CTL3,			0x10 },
+	{ CS42L42_PLL_CAL_RATIO,		0x80 },
+	{ CS42L42_PLL_CTL4,			0x03 },
+	{ CS42L42_LOAD_DET_RCSTAT,		0x00 },
+	{ CS42L42_LOAD_DET_DONE,		0x00 },
+	{ CS42L42_LOAD_DET_EN,			0x00 },
+	{ CS42L42_HSBIAS_SC_AUTOCTL,		0x03 },
+	{ CS42L42_WAKE_CTL,			0xC0 },
+	{ CS42L42_ADC_DISABLE_MUTE,		0x00 },
+	{ CS42L42_TIPSENSE_CTL,			0x02 },
+	{ CS42L42_MISC_DET_CTL,			0x03 },
+	{ CS42L42_MIC_DET_CTL1,			0x1F },
+	{ CS42L42_MIC_DET_CTL2,			0x2F },
+	{ CS42L42_DET_STATUS1,			0x00 },
+	{ CS42L42_DET_STATUS2,			0x00 },
+	{ CS42L42_DET_INT1_MASK,		0xE0 },
+	{ CS42L42_DET_INT2_MASK,		0xFF },
+	{ CS42L42_HS_BIAS_CTL,			0xC2 },
+	{ CS42L42_ADC_CTL,			0x00 },
+	{ CS42L42_ADC_VOLUME,			0x00 },
+	{ CS42L42_ADC_WNF_HPF_CTL,		0x71 },
+	{ CS42L42_DAC_CTL1,			0x00 },
+	{ CS42L42_DAC_CTL2,			0x02 },
+	{ CS42L42_HP_CTL,			0x0D },
+	{ CS42L42_CLASSH_CTL,			0x07 },
+	{ CS42L42_MIXER_CHA_VOL,		0x3F },
+	{ CS42L42_MIXER_ADC_VOL,		0x3F },
+	{ CS42L42_MIXER_CHB_VOL,		0x3F },
+	{ CS42L42_EQ_COEF_IN0,			0x22 },
+	{ CS42L42_EQ_COEF_IN1,			0x00 },
+	{ CS42L42_EQ_COEF_IN2,			0x00 },
+	{ CS42L42_EQ_COEF_IN3,			0x00 },
+	{ CS42L42_EQ_COEF_RW,			0x00 },
+	{ CS42L42_EQ_COEF_OUT0,			0x00 },
+	{ CS42L42_EQ_COEF_OUT1,			0x00 },
+	{ CS42L42_EQ_COEF_OUT2,			0x00 },
+	{ CS42L42_EQ_COEF_OUT3,			0x00 },
+	{ CS42L42_EQ_INIT_STAT,			0x00 },
+	{ CS42L42_EQ_START_FILT,		0x00 },
+	{ CS42L42_EQ_MUTE_CTL,			0x00 },
+	{ CS42L42_SP_RX_CH_SEL,			0x04 },
+	{ CS42L42_SP_RX_ISOC_CTL,		0x04 },
+	{ CS42L42_SP_RX_FS,			0x8C },
+	{ CS42l42_SPDIF_CH_SEL,			0x0E },
+	{ CS42L42_SP_TX_ISOC_CTL,		0x04 },
+	{ CS42L42_SP_TX_FS,			0xCC },
+	{ CS42L42_SPDIF_SW_CTL1,		0x3F },
+	{ CS42L42_SRC_SDIN_FS,			0x40 },
+	{ CS42L42_SRC_SDOUT_FS,			0x40 },
+	{ CS42L42_SPDIF_CTL1,			0x01 },
+	{ CS42L42_SPDIF_CTL2,			0x00 },
+	{ CS42L42_SPDIF_CTL3,			0x00 },
+	{ CS42L42_SPDIF_CTL4,			0x42 },
+	{ CS42L42_ASP_TX_SZ_EN,			0x00 },
+	{ CS42L42_ASP_TX_CH_EN,			0x00 },
+	{ CS42L42_ASP_TX_CH_AP_RES,		0x0F },
+	{ CS42L42_ASP_TX_CH1_BIT_MSB,		0x00 },
+	{ CS42L42_ASP_TX_CH1_BIT_LSB,		0x00 },
+	{ CS42L42_ASP_TX_HIZ_DLY_CFG,		0x00 },
+	{ CS42L42_ASP_TX_CH2_BIT_MSB,		0x00 },
+	{ CS42L42_ASP_TX_CH2_BIT_LSB,		0x00 },
+	{ CS42L42_ASP_RX_DAI0_EN,		0x00 },
+	{ CS42L42_ASP_RX_DAI0_CH1_AP_RES,	0x03 },
+	{ CS42L42_ASP_RX_DAI0_CH1_BIT_MSB,	0x00 },
+	{ CS42L42_ASP_RX_DAI0_CH1_BIT_LSB,	0x00 },
+	{ CS42L42_ASP_RX_DAI0_CH2_AP_RES,	0x03 },
+	{ CS42L42_ASP_RX_DAI0_CH2_BIT_MSB,	0x00 },
+	{ CS42L42_ASP_RX_DAI0_CH2_BIT_LSB,	0x00 },
+	{ CS42L42_ASP_RX_DAI0_CH3_AP_RES,	0x03 },
+	{ CS42L42_ASP_RX_DAI0_CH3_BIT_MSB,	0x00 },
+	{ CS42L42_ASP_RX_DAI0_CH3_BIT_LSB,	0x00 },
+	{ CS42L42_ASP_RX_DAI0_CH4_AP_RES,	0x03 },
+	{ CS42L42_ASP_RX_DAI0_CH4_BIT_MSB,	0x00 },
+	{ CS42L42_ASP_RX_DAI0_CH4_BIT_LSB,	0x00 },
+	{ CS42L42_ASP_RX_DAI1_CH1_AP_RES,	0x03 },
+	{ CS42L42_ASP_RX_DAI1_CH1_BIT_MSB,	0x00 },
+	{ CS42L42_ASP_RX_DAI1_CH1_BIT_LSB,	0x00 },
+	{ CS42L42_ASP_RX_DAI1_CH2_AP_RES,	0x03 },
+	{ CS42L42_ASP_RX_DAI1_CH2_BIT_MSB,	0x00 },
+	{ CS42L42_ASP_RX_DAI1_CH2_BIT_LSB,	0x00 },
+	{ CS42L42_SUB_REVID,			0x03 },
+};
+
+static bool cs42l42_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS42L42_PAGE_REGISTER:
+	case CS42L42_DEVID_AB:
+	case CS42L42_DEVID_CD:
+	case CS42L42_DEVID_E:
+	case CS42L42_FABID:
+	case CS42L42_REVID:
+	case CS42L42_FRZ_CTL:
+	case CS42L42_SRC_CTL:
+	case CS42L42_MCLK_STATUS:
+	case CS42L42_MCLK_CTL:
+	case CS42L42_SFTRAMP_RATE:
+	case CS42L42_I2C_DEBOUNCE:
+	case CS42L42_I2C_STRETCH:
+	case CS42L42_I2C_TIMEOUT:
+	case CS42L42_PWR_CTL1:
+	case CS42L42_PWR_CTL2:
+	case CS42L42_PWR_CTL3:
+	case CS42L42_RSENSE_CTL1:
+	case CS42L42_RSENSE_CTL2:
+	case CS42L42_OSC_SWITCH:
+	case CS42L42_OSC_SWITCH_STATUS:
+	case CS42L42_RSENSE_CTL3:
+	case CS42L42_TSENSE_CTL:
+	case CS42L42_TSRS_INT_DISABLE:
+	case CS42L42_TRSENSE_STATUS:
+	case CS42L42_HSDET_CTL1:
+	case CS42L42_HSDET_CTL2:
+	case CS42L42_HS_SWITCH_CTL:
+	case CS42L42_HS_DET_STATUS:
+	case CS42L42_HS_CLAMP_DISABLE:
+	case CS42L42_MCLK_SRC_SEL:
+	case CS42L42_SPDIF_CLK_CFG:
+	case CS42L42_FSYNC_PW_LOWER:
+	case CS42L42_FSYNC_PW_UPPER:
+	case CS42L42_FSYNC_P_LOWER:
+	case CS42L42_FSYNC_P_UPPER:
+	case CS42L42_ASP_CLK_CFG:
+	case CS42L42_ASP_FRM_CFG:
+	case CS42L42_FS_RATE_EN:
+	case CS42L42_IN_ASRC_CLK:
+	case CS42L42_OUT_ASRC_CLK:
+	case CS42L42_PLL_DIV_CFG1:
+	case CS42L42_ADC_OVFL_STATUS:
+	case CS42L42_MIXER_STATUS:
+	case CS42L42_SRC_STATUS:
+	case CS42L42_ASP_RX_STATUS:
+	case CS42L42_ASP_TX_STATUS:
+	case CS42L42_CODEC_STATUS:
+	case CS42L42_DET_INT_STATUS1:
+	case CS42L42_DET_INT_STATUS2:
+	case CS42L42_SRCPL_INT_STATUS:
+	case CS42L42_VPMON_STATUS:
+	case CS42L42_PLL_LOCK_STATUS:
+	case CS42L42_TSRS_PLUG_STATUS:
+	case CS42L42_ADC_OVFL_INT_MASK:
+	case CS42L42_MIXER_INT_MASK:
+	case CS42L42_SRC_INT_MASK:
+	case CS42L42_ASP_RX_INT_MASK:
+	case CS42L42_ASP_TX_INT_MASK:
+	case CS42L42_CODEC_INT_MASK:
+	case CS42L42_SRCPL_INT_MASK:
+	case CS42L42_VPMON_INT_MASK:
+	case CS42L42_PLL_LOCK_INT_MASK:
+	case CS42L42_TSRS_PLUG_INT_MASK:
+	case CS42L42_PLL_CTL1:
+	case CS42L42_PLL_DIV_FRAC0:
+	case CS42L42_PLL_DIV_FRAC1:
+	case CS42L42_PLL_DIV_FRAC2:
+	case CS42L42_PLL_DIV_INT:
+	case CS42L42_PLL_CTL3:
+	case CS42L42_PLL_CAL_RATIO:
+	case CS42L42_PLL_CTL4:
+	case CS42L42_LOAD_DET_RCSTAT:
+	case CS42L42_LOAD_DET_DONE:
+	case CS42L42_LOAD_DET_EN:
+	case CS42L42_HSBIAS_SC_AUTOCTL:
+	case CS42L42_WAKE_CTL:
+	case CS42L42_ADC_DISABLE_MUTE:
+	case CS42L42_TIPSENSE_CTL:
+	case CS42L42_MISC_DET_CTL:
+	case CS42L42_MIC_DET_CTL1:
+	case CS42L42_MIC_DET_CTL2:
+	case CS42L42_DET_STATUS1:
+	case CS42L42_DET_STATUS2:
+	case CS42L42_DET_INT1_MASK:
+	case CS42L42_DET_INT2_MASK:
+	case CS42L42_HS_BIAS_CTL:
+	case CS42L42_ADC_CTL:
+	case CS42L42_ADC_VOLUME:
+	case CS42L42_ADC_WNF_HPF_CTL:
+	case CS42L42_DAC_CTL1:
+	case CS42L42_DAC_CTL2:
+	case CS42L42_HP_CTL:
+	case CS42L42_CLASSH_CTL:
+	case CS42L42_MIXER_CHA_VOL:
+	case CS42L42_MIXER_ADC_VOL:
+	case CS42L42_MIXER_CHB_VOL:
+	case CS42L42_EQ_COEF_IN0:
+	case CS42L42_EQ_COEF_IN1:
+	case CS42L42_EQ_COEF_IN2:
+	case CS42L42_EQ_COEF_IN3:
+	case CS42L42_EQ_COEF_RW:
+	case CS42L42_EQ_COEF_OUT0:
+	case CS42L42_EQ_COEF_OUT1:
+	case CS42L42_EQ_COEF_OUT2:
+	case CS42L42_EQ_COEF_OUT3:
+	case CS42L42_EQ_INIT_STAT:
+	case CS42L42_EQ_START_FILT:
+	case CS42L42_EQ_MUTE_CTL:
+	case CS42L42_SP_RX_CH_SEL:
+	case CS42L42_SP_RX_ISOC_CTL:
+	case CS42L42_SP_RX_FS:
+	case CS42l42_SPDIF_CH_SEL:
+	case CS42L42_SP_TX_ISOC_CTL:
+	case CS42L42_SP_TX_FS:
+	case CS42L42_SPDIF_SW_CTL1:
+	case CS42L42_SRC_SDIN_FS:
+	case CS42L42_SRC_SDOUT_FS:
+	case CS42L42_SPDIF_CTL1:
+	case CS42L42_SPDIF_CTL2:
+	case CS42L42_SPDIF_CTL3:
+	case CS42L42_SPDIF_CTL4:
+	case CS42L42_ASP_TX_SZ_EN:
+	case CS42L42_ASP_TX_CH_EN:
+	case CS42L42_ASP_TX_CH_AP_RES:
+	case CS42L42_ASP_TX_CH1_BIT_MSB:
+	case CS42L42_ASP_TX_CH1_BIT_LSB:
+	case CS42L42_ASP_TX_HIZ_DLY_CFG:
+	case CS42L42_ASP_TX_CH2_BIT_MSB:
+	case CS42L42_ASP_TX_CH2_BIT_LSB:
+	case CS42L42_ASP_RX_DAI0_EN:
+	case CS42L42_ASP_RX_DAI0_CH1_AP_RES:
+	case CS42L42_ASP_RX_DAI0_CH1_BIT_MSB:
+	case CS42L42_ASP_RX_DAI0_CH1_BIT_LSB:
+	case CS42L42_ASP_RX_DAI0_CH2_AP_RES:
+	case CS42L42_ASP_RX_DAI0_CH2_BIT_MSB:
+	case CS42L42_ASP_RX_DAI0_CH2_BIT_LSB:
+	case CS42L42_ASP_RX_DAI0_CH3_AP_RES:
+	case CS42L42_ASP_RX_DAI0_CH3_BIT_MSB:
+	case CS42L42_ASP_RX_DAI0_CH3_BIT_LSB:
+	case CS42L42_ASP_RX_DAI0_CH4_AP_RES:
+	case CS42L42_ASP_RX_DAI0_CH4_BIT_MSB:
+	case CS42L42_ASP_RX_DAI0_CH4_BIT_LSB:
+	case CS42L42_ASP_RX_DAI1_CH1_AP_RES:
+	case CS42L42_ASP_RX_DAI1_CH1_BIT_MSB:
+	case CS42L42_ASP_RX_DAI1_CH1_BIT_LSB:
+	case CS42L42_ASP_RX_DAI1_CH2_AP_RES:
+	case CS42L42_ASP_RX_DAI1_CH2_BIT_MSB:
+	case CS42L42_ASP_RX_DAI1_CH2_BIT_LSB:
+	case CS42L42_SUB_REVID:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs42l42_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS42L42_DEVID_AB:
+	case CS42L42_DEVID_CD:
+	case CS42L42_DEVID_E:
+	case CS42L42_MCLK_STATUS:
+	case CS42L42_TRSENSE_STATUS:
+	case CS42L42_HS_DET_STATUS:
+	case CS42L42_ADC_OVFL_STATUS:
+	case CS42L42_MIXER_STATUS:
+	case CS42L42_SRC_STATUS:
+	case CS42L42_ASP_RX_STATUS:
+	case CS42L42_ASP_TX_STATUS:
+	case CS42L42_CODEC_STATUS:
+	case CS42L42_DET_INT_STATUS1:
+	case CS42L42_DET_INT_STATUS2:
+	case CS42L42_SRCPL_INT_STATUS:
+	case CS42L42_VPMON_STATUS:
+	case CS42L42_PLL_LOCK_STATUS:
+	case CS42L42_TSRS_PLUG_STATUS:
+	case CS42L42_LOAD_DET_RCSTAT:
+	case CS42L42_LOAD_DET_DONE:
+	case CS42L42_DET_STATUS1:
+	case CS42L42_DET_STATUS2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_range_cfg cs42l42_page_range = {
+	.name = "Pages",
+	.range_min = 0,
+	.range_max = CS42L42_MAX_REGISTER,
+	.selector_reg = CS42L42_PAGE_REGISTER,
+	.selector_mask = 0xff,
+	.selector_shift = 0,
+	.window_start = 0,
+	.window_len = 256,
+};
+
+static const struct regmap_config cs42l42_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.readable_reg = cs42l42_readable_register,
+	.volatile_reg = cs42l42_volatile_register,
+
+	.ranges = &cs42l42_page_range,
+	.num_ranges = 1,
+
+	.max_register = CS42L42_MAX_REGISTER,
+	.reg_defaults = cs42l42_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(cs42l42_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, false);
+static DECLARE_TLV_DB_SCALE(mixer_tlv, -6200, 100, false);
+
+static const char * const cs42l42_hpf_freq_text[] = {
+	"1.86Hz", "120Hz", "235Hz", "466Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l42_hpf_freq_enum, CS42L42_ADC_WNF_HPF_CTL,
+			    CS42L42_ADC_HPF_CF_SHIFT,
+			    cs42l42_hpf_freq_text);
+
+static const char * const cs42l42_wnf3_freq_text[] = {
+	"160Hz", "180Hz", "200Hz", "220Hz",
+	"240Hz", "260Hz", "280Hz", "300Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l42_wnf3_freq_enum, CS42L42_ADC_WNF_HPF_CTL,
+			    CS42L42_ADC_WNF_CF_SHIFT,
+			    cs42l42_wnf3_freq_text);
+
+static const char * const cs42l42_wnf05_freq_text[] = {
+	"280Hz", "315Hz", "350Hz", "385Hz",
+	"420Hz", "455Hz", "490Hz", "525Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l42_wnf05_freq_enum, CS42L42_ADC_WNF_HPF_CTL,
+			    CS42L42_ADC_WNF_CF_SHIFT,
+			    cs42l42_wnf05_freq_text);
+
+static const struct snd_kcontrol_new cs42l42_snd_controls[] = {
+	/* ADC Volume and Filter Controls */
+	SOC_SINGLE("ADC Notch Switch", CS42L42_ADC_CTL,
+				CS42L42_ADC_NOTCH_DIS_SHIFT, true, false),
+	SOC_SINGLE("ADC Weak Force Switch", CS42L42_ADC_CTL,
+				CS42L42_ADC_FORCE_WEAK_VCM_SHIFT, true, false),
+	SOC_SINGLE("ADC Invert Switch", CS42L42_ADC_CTL,
+				CS42L42_ADC_INV_SHIFT, true, false),
+	SOC_SINGLE("ADC Boost Switch", CS42L42_ADC_CTL,
+				CS42L42_ADC_DIG_BOOST_SHIFT, true, false),
+	SOC_SINGLE_SX_TLV("ADC Volume", CS42L42_ADC_VOLUME,
+				CS42L42_ADC_VOL_SHIFT, 0xA0, 0x6C, adc_tlv),
+	SOC_SINGLE("ADC WNF Switch", CS42L42_ADC_WNF_HPF_CTL,
+				CS42L42_ADC_WNF_EN_SHIFT, true, false),
+	SOC_SINGLE("ADC HPF Switch", CS42L42_ADC_WNF_HPF_CTL,
+				CS42L42_ADC_HPF_EN_SHIFT, true, false),
+	SOC_ENUM("HPF Corner Freq", cs42l42_hpf_freq_enum),
+	SOC_ENUM("WNF 3dB Freq", cs42l42_wnf3_freq_enum),
+	SOC_ENUM("WNF 05dB Freq", cs42l42_wnf05_freq_enum),
+
+	/* DAC Volume and Filter Controls */
+	SOC_SINGLE("DACA Invert Switch", CS42L42_DAC_CTL1,
+				CS42L42_DACA_INV_SHIFT, true, false),
+	SOC_SINGLE("DACB Invert Switch", CS42L42_DAC_CTL1,
+				CS42L42_DACB_INV_SHIFT, true, false),
+	SOC_SINGLE("DAC HPF Switch", CS42L42_DAC_CTL2,
+				CS42L42_DAC_HPF_EN_SHIFT, true, false),
+	SOC_DOUBLE_R_TLV("Mixer Volume", CS42L42_MIXER_CHA_VOL,
+			 CS42L42_MIXER_CHB_VOL, CS42L42_MIXER_CH_VOL_SHIFT,
+				0x3e, 1, mixer_tlv)
+};
+
+static int cs42l42_hpdrv_evt(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	if (event & SND_SOC_DAPM_POST_PMU) {
+		/* Enable the channels */
+		snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_EN,
+				CS42L42_ASP_RX0_CH_EN_MASK,
+				(CS42L42_ASP_RX0_CH1_EN |
+				CS42L42_ASP_RX0_CH2_EN) <<
+				CS42L42_ASP_RX0_CH_EN_SHIFT);
+
+		/* Power up */
+		snd_soc_component_update_bits(component, CS42L42_PWR_CTL1,
+			CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
+				CS42L42_HP_PDN_MASK, 0);
+	} else if (event & SND_SOC_DAPM_PRE_PMD) {
+		/* Disable the channels */
+		snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_EN,
+				CS42L42_ASP_RX0_CH_EN_MASK, 0);
+
+		/* Power down */
+		snd_soc_component_update_bits(component, CS42L42_PWR_CTL1,
+			CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
+				CS42L42_HP_PDN_MASK,
+			CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
+				CS42L42_HP_PDN_MASK);
+	} else {
+		dev_err(component->dev, "Invalid event 0x%x\n", event);
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget cs42l42_dapm_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("HP"),
+	SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0, CS42L42_ASP_CLK_CFG,
+					CS42L42_ASP_SCLK_EN_SHIFT, false),
+	SND_SOC_DAPM_OUT_DRV_E("HPDRV", SND_SOC_NOPM, 0,
+					0, NULL, 0, cs42l42_hpdrv_evt,
+					SND_SOC_DAPM_POST_PMU |
+					SND_SOC_DAPM_PRE_PMD)
+};
+
+static const struct snd_soc_dapm_route cs42l42_audio_map[] = {
+	{"SDIN", NULL, "Playback"},
+	{"HPDRV", NULL, "SDIN"},
+	{"HP", NULL, "HPDRV"}
+};
+
+static int cs42l42_set_bias_level(struct snd_soc_component *component,
+					enum snd_soc_bias_level level)
+{
+	struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			regcache_cache_only(cs42l42->regmap, false);
+			regcache_sync(cs42l42->regmap);
+			ret = regulator_bulk_enable(
+						ARRAY_SIZE(cs42l42->supplies),
+						cs42l42->supplies);
+			if (ret != 0) {
+				dev_err(component->dev,
+					"Failed to enable regulators: %d\n",
+					ret);
+				return ret;
+			}
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+
+		regcache_cache_only(cs42l42->regmap, true);
+		regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies),
+						    cs42l42->supplies);
+		break;
+	}
+
+	return 0;
+}
+
+static int cs42l42_component_probe(struct snd_soc_component *component)
+{
+	struct cs42l42_private *cs42l42 =
+		(struct cs42l42_private *)snd_soc_component_get_drvdata(component);
+
+	cs42l42->component = component;
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_cs42l42 = {
+	.probe			= cs42l42_component_probe,
+	.set_bias_level		= cs42l42_set_bias_level,
+	.dapm_widgets		= cs42l42_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs42l42_dapm_widgets),
+	.dapm_routes		= cs42l42_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs42l42_audio_map),
+	.controls		= cs42l42_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs42l42_snd_controls),
+	.idle_bias_on		= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+struct cs42l42_pll_params {
+	u32 sclk;
+	u8 mclk_div;
+	u8 mclk_src_sel;
+	u8 sclk_prediv;
+	u8 pll_div_int;
+	u32 pll_div_frac;
+	u8 pll_mode;
+	u8 pll_divout;
+	u32 mclk_int;
+	u8 pll_cal_ratio;
+};
+
+/*
+ * Common PLL Settings for given SCLK
+ * Table 4-5 from the Datasheet
+ */
+static const struct cs42l42_pll_params pll_ratio_table[] = {
+	{ 1536000, 0, 1, 0x00, 0x7D, 0x000000, 0x03, 0x10, 12000000, 125 },
+	{ 2822400, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 },
+	{ 3000000, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 },
+	{ 3072000, 0, 1, 0x00, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 },
+	{ 4000000, 0, 1, 0x00, 0x30, 0x800000, 0x03, 0x10, 12000000, 96 },
+	{ 4096000, 0, 1, 0x00, 0x2E, 0xE00000, 0x03, 0x10, 12000000, 94 },
+	{ 5644800, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 },
+	{ 6000000, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 },
+	{ 6144000, 0, 1, 0x01, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 },
+	{ 11289600, 0, 0, 0, 0, 0, 0, 0, 11289600, 0 },
+	{ 12000000, 0, 0, 0, 0, 0, 0, 0, 12000000, 0 },
+	{ 12288000, 0, 0, 0, 0, 0, 0, 0, 12288000, 0 },
+	{ 22579200, 1, 0, 0, 0, 0, 0, 0, 22579200, 0 },
+	{ 24000000, 1, 0, 0, 0, 0, 0, 0, 24000000, 0 },
+	{ 24576000, 1, 0, 0, 0, 0, 0, 0, 24576000, 0 }
+};
+
+static int cs42l42_pll_config(struct snd_soc_component *component)
+{
+	struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
+	int i;
+	u32 fsync;
+
+	for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
+		if (pll_ratio_table[i].sclk == cs42l42->sclk) {
+			/* Configure the internal sample rate */
+			snd_soc_component_update_bits(component, CS42L42_MCLK_CTL,
+					CS42L42_INTERNAL_FS_MASK,
+					((pll_ratio_table[i].mclk_int !=
+					12000000) &&
+					(pll_ratio_table[i].mclk_int !=
+					24000000)) <<
+					CS42L42_INTERNAL_FS_SHIFT);
+			/* Set the MCLK src (PLL or SCLK) and the divide
+			 * ratio
+			 */
+			snd_soc_component_update_bits(component, CS42L42_MCLK_SRC_SEL,
+					CS42L42_MCLK_SRC_SEL_MASK |
+					CS42L42_MCLKDIV_MASK,
+					(pll_ratio_table[i].mclk_src_sel
+					<< CS42L42_MCLK_SRC_SEL_SHIFT) |
+					(pll_ratio_table[i].mclk_div <<
+					CS42L42_MCLKDIV_SHIFT));
+			/* Set up the LRCLK */
+			fsync = cs42l42->sclk / cs42l42->srate;
+			if (((fsync * cs42l42->srate) != cs42l42->sclk)
+				|| ((fsync % 2) != 0)) {
+				dev_err(component->dev,
+					"Unsupported sclk %d/sample rate %d\n",
+					cs42l42->sclk,
+					cs42l42->srate);
+				return -EINVAL;
+			}
+			/* Set the LRCLK period */
+			snd_soc_component_update_bits(component,
+					CS42L42_FSYNC_P_LOWER,
+					CS42L42_FSYNC_PERIOD_MASK,
+					CS42L42_FRAC0_VAL(fsync - 1) <<
+					CS42L42_FSYNC_PERIOD_SHIFT);
+			snd_soc_component_update_bits(component,
+					CS42L42_FSYNC_P_UPPER,
+					CS42L42_FSYNC_PERIOD_MASK,
+					CS42L42_FRAC1_VAL(fsync - 1) <<
+					CS42L42_FSYNC_PERIOD_SHIFT);
+			/* Set the LRCLK to 50% duty cycle */
+			fsync = fsync / 2;
+			snd_soc_component_update_bits(component,
+					CS42L42_FSYNC_PW_LOWER,
+					CS42L42_FSYNC_PULSE_WIDTH_MASK,
+					CS42L42_FRAC0_VAL(fsync - 1) <<
+					CS42L42_FSYNC_PULSE_WIDTH_SHIFT);
+			snd_soc_component_update_bits(component,
+					CS42L42_FSYNC_PW_UPPER,
+					CS42L42_FSYNC_PULSE_WIDTH_MASK,
+					CS42L42_FRAC1_VAL(fsync - 1) <<
+					CS42L42_FSYNC_PULSE_WIDTH_SHIFT);
+			snd_soc_component_update_bits(component,
+					CS42L42_ASP_FRM_CFG,
+					CS42L42_ASP_5050_MASK,
+					CS42L42_ASP_5050_MASK);
+			/* Set the frame delay to 1.0 SCLK clocks */
+			snd_soc_component_update_bits(component, CS42L42_ASP_FRM_CFG,
+					CS42L42_ASP_FSD_MASK,
+					CS42L42_ASP_FSD_1_0 <<
+					CS42L42_ASP_FSD_SHIFT);
+			/* Set the sample rates (96k or lower) */
+			snd_soc_component_update_bits(component, CS42L42_FS_RATE_EN,
+					CS42L42_FS_EN_MASK,
+					(CS42L42_FS_EN_IASRC_96K |
+					CS42L42_FS_EN_OASRC_96K) <<
+					CS42L42_FS_EN_SHIFT);
+			/* Set the input/output internal MCLK clock ~12 MHz */
+			snd_soc_component_update_bits(component, CS42L42_IN_ASRC_CLK,
+					CS42L42_CLK_IASRC_SEL_MASK,
+					CS42L42_CLK_IASRC_SEL_12 <<
+					CS42L42_CLK_IASRC_SEL_SHIFT);
+			snd_soc_component_update_bits(component,
+					CS42L42_OUT_ASRC_CLK,
+					CS42L42_CLK_OASRC_SEL_MASK,
+					CS42L42_CLK_OASRC_SEL_12 <<
+					CS42L42_CLK_OASRC_SEL_SHIFT);
+			/* channel 1 on low LRCLK, 32 bit */
+			snd_soc_component_update_bits(component,
+					CS42L42_ASP_RX_DAI0_CH1_AP_RES,
+					CS42L42_ASP_RX_CH_AP_MASK |
+					CS42L42_ASP_RX_CH_RES_MASK,
+					(CS42L42_ASP_RX_CH_AP_LOW <<
+					CS42L42_ASP_RX_CH_AP_SHIFT) |
+					(CS42L42_ASP_RX_CH_RES_32 <<
+					CS42L42_ASP_RX_CH_RES_SHIFT));
+			/* Channel 2 on high LRCLK, 32 bit */
+			snd_soc_component_update_bits(component,
+					CS42L42_ASP_RX_DAI0_CH2_AP_RES,
+					CS42L42_ASP_RX_CH_AP_MASK |
+					CS42L42_ASP_RX_CH_RES_MASK,
+					(CS42L42_ASP_RX_CH_AP_HI <<
+					CS42L42_ASP_RX_CH_AP_SHIFT) |
+					(CS42L42_ASP_RX_CH_RES_32 <<
+					CS42L42_ASP_RX_CH_RES_SHIFT));
+			if (pll_ratio_table[i].mclk_src_sel == 0) {
+				/* Pass the clock straight through */
+				snd_soc_component_update_bits(component,
+					CS42L42_PLL_CTL1,
+					CS42L42_PLL_START_MASK,	0);
+			} else {
+				/* Configure PLL per table 4-5 */
+				snd_soc_component_update_bits(component,
+					CS42L42_PLL_DIV_CFG1,
+					CS42L42_SCLK_PREDIV_MASK,
+					pll_ratio_table[i].sclk_prediv
+					<< CS42L42_SCLK_PREDIV_SHIFT);
+				snd_soc_component_update_bits(component,
+					CS42L42_PLL_DIV_INT,
+					CS42L42_PLL_DIV_INT_MASK,
+					pll_ratio_table[i].pll_div_int
+					<< CS42L42_PLL_DIV_INT_SHIFT);
+				snd_soc_component_update_bits(component,
+					CS42L42_PLL_DIV_FRAC0,
+					CS42L42_PLL_DIV_FRAC_MASK,
+					CS42L42_FRAC0_VAL(
+					pll_ratio_table[i].pll_div_frac)
+					<< CS42L42_PLL_DIV_FRAC_SHIFT);
+				snd_soc_component_update_bits(component,
+					CS42L42_PLL_DIV_FRAC1,
+					CS42L42_PLL_DIV_FRAC_MASK,
+					CS42L42_FRAC1_VAL(
+					pll_ratio_table[i].pll_div_frac)
+					<< CS42L42_PLL_DIV_FRAC_SHIFT);
+				snd_soc_component_update_bits(component,
+					CS42L42_PLL_DIV_FRAC2,
+					CS42L42_PLL_DIV_FRAC_MASK,
+					CS42L42_FRAC2_VAL(
+					pll_ratio_table[i].pll_div_frac)
+					<< CS42L42_PLL_DIV_FRAC_SHIFT);
+				snd_soc_component_update_bits(component,
+					CS42L42_PLL_CTL4,
+					CS42L42_PLL_MODE_MASK,
+					pll_ratio_table[i].pll_mode
+					<< CS42L42_PLL_MODE_SHIFT);
+				snd_soc_component_update_bits(component,
+					CS42L42_PLL_CTL3,
+					CS42L42_PLL_DIVOUT_MASK,
+					pll_ratio_table[i].pll_divout
+					<< CS42L42_PLL_DIVOUT_SHIFT);
+				snd_soc_component_update_bits(component,
+					CS42L42_PLL_CAL_RATIO,
+					CS42L42_PLL_CAL_RATIO_MASK,
+					pll_ratio_table[i].pll_cal_ratio
+					<< CS42L42_PLL_CAL_RATIO_SHIFT);
+			}
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u32 asp_cfg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFM:
+		asp_cfg_val |= CS42L42_ASP_MASTER_MODE <<
+				CS42L42_ASP_MODE_SHIFT;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		asp_cfg_val |= CS42L42_ASP_SLAVE_MODE <<
+				CS42L42_ASP_MODE_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_LEFT_J:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Bitclock/frame inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		asp_cfg_val |= CS42L42_ASP_POL_INV <<
+				CS42L42_ASP_LCPOL_IN_SHIFT;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		asp_cfg_val |= CS42L42_ASP_POL_INV <<
+				CS42L42_ASP_SCPOL_IN_DAC_SHIFT;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		asp_cfg_val |= CS42L42_ASP_POL_INV <<
+				CS42L42_ASP_LCPOL_IN_SHIFT;
+		asp_cfg_val |= CS42L42_ASP_POL_INV <<
+				CS42L42_ASP_SCPOL_IN_DAC_SHIFT;
+		break;
+	}
+
+	snd_soc_component_update_bits(component, CS42L42_ASP_CLK_CFG,
+				CS42L42_ASP_MODE_MASK |
+				CS42L42_ASP_SCPOL_IN_DAC_MASK |
+				CS42L42_ASP_LCPOL_IN_MASK, asp_cfg_val);
+
+	return 0;
+}
+
+static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
+	int retval;
+
+	cs42l42->srate = params_rate(params);
+	cs42l42->swidth = params_width(params);
+
+	retval = cs42l42_pll_config(component);
+
+	return retval;
+}
+
+static int cs42l42_set_sysclk(struct snd_soc_dai *dai,
+				int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
+
+	cs42l42->sclk = freq;
+
+	return 0;
+}
+
+static int cs42l42_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int regval;
+	u8 fullScaleVol;
+
+	if (mute) {
+		/* Mark SCLK as not present to turn on the internal
+		 * oscillator.
+		 */
+		snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH,
+						CS42L42_SCLK_PRESENT_MASK, 0);
+
+		snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
+				CS42L42_PLL_START_MASK,
+				0 << CS42L42_PLL_START_SHIFT);
+
+		/* Mute the headphone */
+		snd_soc_component_update_bits(component, CS42L42_HP_CTL,
+				CS42L42_HP_ANA_AMUTE_MASK |
+				CS42L42_HP_ANA_BMUTE_MASK,
+				CS42L42_HP_ANA_AMUTE_MASK |
+				CS42L42_HP_ANA_BMUTE_MASK);
+	} else {
+		snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
+				CS42L42_PLL_START_MASK,
+				1 << CS42L42_PLL_START_SHIFT);
+		/* Read the headphone load */
+		regval = snd_soc_component_read32(component, CS42L42_LOAD_DET_RCSTAT);
+		if (((regval & CS42L42_RLA_STAT_MASK) >>
+			CS42L42_RLA_STAT_SHIFT) == CS42L42_RLA_STAT_15_OHM) {
+			fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK;
+		} else {
+			fullScaleVol = 0;
+		}
+
+		/* Un-mute the headphone, set the full scale volume flag */
+		snd_soc_component_update_bits(component, CS42L42_HP_CTL,
+				CS42L42_HP_ANA_AMUTE_MASK |
+				CS42L42_HP_ANA_BMUTE_MASK |
+				CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol);
+
+		/* Mark SCLK as present, turn off internal oscillator */
+		snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH,
+				CS42L42_SCLK_PRESENT_MASK,
+				CS42L42_SCLK_PRESENT_MASK);
+	}
+
+	return 0;
+}
+
+#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static const struct snd_soc_dai_ops cs42l42_ops = {
+	.hw_params	= cs42l42_pcm_hw_params,
+	.set_fmt	= cs42l42_set_dai_fmt,
+	.set_sysclk	= cs42l42_set_sysclk,
+	.digital_mute = cs42l42_digital_mute
+};
+
+static struct snd_soc_dai_driver cs42l42_dai = {
+		.name = "cs42l42",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = CS42L42_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = CS42L42_FORMATS,
+		},
+		.ops = &cs42l42_ops,
+};
+
+static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42)
+{
+	unsigned int hs_det_status;
+	unsigned int int_status;
+
+	/* Mask the auto detect interrupt */
+	regmap_update_bits(cs42l42->regmap,
+		CS42L42_CODEC_INT_MASK,
+		CS42L42_PDN_DONE_MASK |
+		CS42L42_HSDET_AUTO_DONE_MASK,
+		(1 << CS42L42_PDN_DONE_SHIFT) |
+		(1 << CS42L42_HSDET_AUTO_DONE_SHIFT));
+
+	/* Set hs detect to automatic, disabled mode */
+	regmap_update_bits(cs42l42->regmap,
+		CS42L42_HSDET_CTL2,
+		CS42L42_HSDET_CTRL_MASK |
+		CS42L42_HSDET_SET_MASK |
+		CS42L42_HSBIAS_REF_MASK |
+		CS42L42_HSDET_AUTO_TIME_MASK,
+		(2 << CS42L42_HSDET_CTRL_SHIFT) |
+		(2 << CS42L42_HSDET_SET_SHIFT) |
+		(0 << CS42L42_HSBIAS_REF_SHIFT) |
+		(3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+
+	/* Read and save the hs detection result */
+	regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status);
+
+	cs42l42->hs_type = (hs_det_status & CS42L42_HSDET_TYPE_MASK) >>
+				CS42L42_HSDET_TYPE_SHIFT;
+
+	/* Set up button detection */
+	if ((cs42l42->hs_type == CS42L42_PLUG_CTIA) ||
+	      (cs42l42->hs_type == CS42L42_PLUG_OMTP)) {
+		/* Set auto HS bias settings to default */
+		regmap_update_bits(cs42l42->regmap,
+			CS42L42_HSBIAS_SC_AUTOCTL,
+			CS42L42_HSBIAS_SENSE_EN_MASK |
+			CS42L42_AUTO_HSBIAS_HIZ_MASK |
+			CS42L42_TIP_SENSE_EN_MASK |
+			CS42L42_HSBIAS_SENSE_TRIP_MASK,
+			(0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) |
+			(0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) |
+			(0 << CS42L42_TIP_SENSE_EN_SHIFT) |
+			(3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT));
+
+		/* Set up hs detect level sensitivity */
+		regmap_update_bits(cs42l42->regmap,
+			CS42L42_MIC_DET_CTL1,
+			CS42L42_LATCH_TO_VP_MASK |
+			CS42L42_EVENT_STAT_SEL_MASK |
+			CS42L42_HS_DET_LEVEL_MASK,
+			(1 << CS42L42_LATCH_TO_VP_SHIFT) |
+			(0 << CS42L42_EVENT_STAT_SEL_SHIFT) |
+			(cs42l42->bias_thresholds[0] <<
+			CS42L42_HS_DET_LEVEL_SHIFT));
+
+		/* Set auto HS bias settings to default */
+		regmap_update_bits(cs42l42->regmap,
+			CS42L42_HSBIAS_SC_AUTOCTL,
+			CS42L42_HSBIAS_SENSE_EN_MASK |
+			CS42L42_AUTO_HSBIAS_HIZ_MASK |
+			CS42L42_TIP_SENSE_EN_MASK |
+			CS42L42_HSBIAS_SENSE_TRIP_MASK,
+			(1 << CS42L42_HSBIAS_SENSE_EN_SHIFT) |
+			(1 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) |
+			(0 << CS42L42_TIP_SENSE_EN_SHIFT) |
+			(3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT));
+
+		/* Turn on level detect circuitry */
+		regmap_update_bits(cs42l42->regmap,
+			CS42L42_MISC_DET_CTL,
+			CS42L42_DETECT_MODE_MASK |
+			CS42L42_HSBIAS_CTL_MASK |
+			CS42L42_PDN_MIC_LVL_DET_MASK,
+			(0 << CS42L42_DETECT_MODE_SHIFT) |
+			(3 << CS42L42_HSBIAS_CTL_SHIFT) |
+			(0 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+
+		msleep(cs42l42->btn_det_init_dbnce);
+
+		/* Clear any button interrupts before unmasking them */
+		regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2,
+			    &int_status);
+
+		/* Unmask button detect interrupts */
+		regmap_update_bits(cs42l42->regmap,
+			CS42L42_DET_INT2_MASK,
+			CS42L42_M_DETECT_TF_MASK |
+			CS42L42_M_DETECT_FT_MASK |
+			CS42L42_M_HSBIAS_HIZ_MASK |
+			CS42L42_M_SHORT_RLS_MASK |
+			CS42L42_M_SHORT_DET_MASK,
+			(0 << CS42L42_M_DETECT_TF_SHIFT) |
+			(0 << CS42L42_M_DETECT_FT_SHIFT) |
+			(0 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+			(1 << CS42L42_M_SHORT_RLS_SHIFT) |
+			(1 << CS42L42_M_SHORT_DET_SHIFT));
+	} else {
+		/* Make sure button detect and HS bias circuits are off */
+		regmap_update_bits(cs42l42->regmap,
+			CS42L42_MISC_DET_CTL,
+			CS42L42_DETECT_MODE_MASK |
+			CS42L42_HSBIAS_CTL_MASK |
+			CS42L42_PDN_MIC_LVL_DET_MASK,
+			(0 << CS42L42_DETECT_MODE_SHIFT) |
+			(1 << CS42L42_HSBIAS_CTL_SHIFT) |
+			(1 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+	}
+
+	regmap_update_bits(cs42l42->regmap,
+				CS42L42_DAC_CTL2,
+				CS42L42_HPOUT_PULLDOWN_MASK |
+				CS42L42_HPOUT_LOAD_MASK |
+				CS42L42_HPOUT_CLAMP_MASK |
+				CS42L42_DAC_HPF_EN_MASK |
+				CS42L42_DAC_MON_EN_MASK,
+				(0 << CS42L42_HPOUT_PULLDOWN_SHIFT) |
+				(0 << CS42L42_HPOUT_LOAD_SHIFT) |
+				(0 << CS42L42_HPOUT_CLAMP_SHIFT) |
+				(1 << CS42L42_DAC_HPF_EN_SHIFT) |
+				(0 << CS42L42_DAC_MON_EN_SHIFT));
+
+	/* Unmask tip sense interrupts */
+	regmap_update_bits(cs42l42->regmap,
+		CS42L42_TSRS_PLUG_INT_MASK,
+		CS42L42_RS_PLUG_MASK |
+		CS42L42_RS_UNPLUG_MASK |
+		CS42L42_TS_PLUG_MASK |
+		CS42L42_TS_UNPLUG_MASK,
+		(1 << CS42L42_RS_PLUG_SHIFT) |
+		(1 << CS42L42_RS_UNPLUG_SHIFT) |
+		(0 << CS42L42_TS_PLUG_SHIFT) |
+		(0 << CS42L42_TS_UNPLUG_SHIFT));
+}
+
+static void cs42l42_init_hs_type_detect(struct cs42l42_private *cs42l42)
+{
+	/* Mask tip sense interrupts */
+	regmap_update_bits(cs42l42->regmap,
+				CS42L42_TSRS_PLUG_INT_MASK,
+				CS42L42_RS_PLUG_MASK |
+				CS42L42_RS_UNPLUG_MASK |
+				CS42L42_TS_PLUG_MASK |
+				CS42L42_TS_UNPLUG_MASK,
+				(1 << CS42L42_RS_PLUG_SHIFT) |
+				(1 << CS42L42_RS_UNPLUG_SHIFT) |
+				(1 << CS42L42_TS_PLUG_SHIFT) |
+				(1 << CS42L42_TS_UNPLUG_SHIFT));
+
+	/* Make sure button detect and HS bias circuits are off */
+	regmap_update_bits(cs42l42->regmap,
+				CS42L42_MISC_DET_CTL,
+				CS42L42_DETECT_MODE_MASK |
+				CS42L42_HSBIAS_CTL_MASK |
+				CS42L42_PDN_MIC_LVL_DET_MASK,
+				(0 << CS42L42_DETECT_MODE_SHIFT) |
+				(1 << CS42L42_HSBIAS_CTL_SHIFT) |
+				(1 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+
+	/* Set auto HS bias settings to default */
+	regmap_update_bits(cs42l42->regmap,
+				CS42L42_HSBIAS_SC_AUTOCTL,
+				CS42L42_HSBIAS_SENSE_EN_MASK |
+				CS42L42_AUTO_HSBIAS_HIZ_MASK |
+				CS42L42_TIP_SENSE_EN_MASK |
+				CS42L42_HSBIAS_SENSE_TRIP_MASK,
+				(0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) |
+				(0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) |
+				(0 << CS42L42_TIP_SENSE_EN_SHIFT) |
+				(3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT));
+
+	/* Set hs detect to manual, disabled mode */
+	regmap_update_bits(cs42l42->regmap,
+				CS42L42_HSDET_CTL2,
+				CS42L42_HSDET_CTRL_MASK |
+				CS42L42_HSDET_SET_MASK |
+				CS42L42_HSBIAS_REF_MASK |
+				CS42L42_HSDET_AUTO_TIME_MASK,
+				(0 << CS42L42_HSDET_CTRL_SHIFT) |
+				(2 << CS42L42_HSDET_SET_SHIFT) |
+				(0 << CS42L42_HSBIAS_REF_SHIFT) |
+				(3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+
+	regmap_update_bits(cs42l42->regmap,
+				CS42L42_DAC_CTL2,
+				CS42L42_HPOUT_PULLDOWN_MASK |
+				CS42L42_HPOUT_LOAD_MASK |
+				CS42L42_HPOUT_CLAMP_MASK |
+				CS42L42_DAC_HPF_EN_MASK |
+				CS42L42_DAC_MON_EN_MASK,
+				(8 << CS42L42_HPOUT_PULLDOWN_SHIFT) |
+				(0 << CS42L42_HPOUT_LOAD_SHIFT) |
+				(1 << CS42L42_HPOUT_CLAMP_SHIFT) |
+				(1 << CS42L42_DAC_HPF_EN_SHIFT) |
+				(1 << CS42L42_DAC_MON_EN_SHIFT));
+
+	/* Power up HS bias to 2.7V */
+	regmap_update_bits(cs42l42->regmap,
+				CS42L42_MISC_DET_CTL,
+				CS42L42_DETECT_MODE_MASK |
+				CS42L42_HSBIAS_CTL_MASK |
+				CS42L42_PDN_MIC_LVL_DET_MASK,
+				(0 << CS42L42_DETECT_MODE_SHIFT) |
+				(3 << CS42L42_HSBIAS_CTL_SHIFT) |
+				(1 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+
+	/* Wait for HS bias to ramp up */
+	msleep(cs42l42->hs_bias_ramp_time);
+
+	/* Unmask auto detect interrupt */
+	regmap_update_bits(cs42l42->regmap,
+				CS42L42_CODEC_INT_MASK,
+				CS42L42_PDN_DONE_MASK |
+				CS42L42_HSDET_AUTO_DONE_MASK,
+				(1 << CS42L42_PDN_DONE_SHIFT) |
+				(0 << CS42L42_HSDET_AUTO_DONE_SHIFT));
+
+	/* Set hs detect to automatic, enabled mode */
+	regmap_update_bits(cs42l42->regmap,
+				CS42L42_HSDET_CTL2,
+				CS42L42_HSDET_CTRL_MASK |
+				CS42L42_HSDET_SET_MASK |
+				CS42L42_HSBIAS_REF_MASK |
+				CS42L42_HSDET_AUTO_TIME_MASK,
+				(3 << CS42L42_HSDET_CTRL_SHIFT) |
+				(2 << CS42L42_HSDET_SET_SHIFT) |
+				(0 << CS42L42_HSBIAS_REF_SHIFT) |
+				(3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+}
+
+static void cs42l42_cancel_hs_type_detect(struct cs42l42_private *cs42l42)
+{
+	/* Mask button detect interrupts */
+	regmap_update_bits(cs42l42->regmap,
+		CS42L42_DET_INT2_MASK,
+		CS42L42_M_DETECT_TF_MASK |
+		CS42L42_M_DETECT_FT_MASK |
+		CS42L42_M_HSBIAS_HIZ_MASK |
+		CS42L42_M_SHORT_RLS_MASK |
+		CS42L42_M_SHORT_DET_MASK,
+		(1 << CS42L42_M_DETECT_TF_SHIFT) |
+		(1 << CS42L42_M_DETECT_FT_SHIFT) |
+		(1 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+		(1 << CS42L42_M_SHORT_RLS_SHIFT) |
+		(1 << CS42L42_M_SHORT_DET_SHIFT));
+
+	/* Ground HS bias */
+	regmap_update_bits(cs42l42->regmap,
+				CS42L42_MISC_DET_CTL,
+				CS42L42_DETECT_MODE_MASK |
+				CS42L42_HSBIAS_CTL_MASK |
+				CS42L42_PDN_MIC_LVL_DET_MASK,
+				(0 << CS42L42_DETECT_MODE_SHIFT) |
+				(1 << CS42L42_HSBIAS_CTL_SHIFT) |
+				(1 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+
+	/* Set auto HS bias settings to default */
+	regmap_update_bits(cs42l42->regmap,
+				CS42L42_HSBIAS_SC_AUTOCTL,
+				CS42L42_HSBIAS_SENSE_EN_MASK |
+				CS42L42_AUTO_HSBIAS_HIZ_MASK |
+				CS42L42_TIP_SENSE_EN_MASK |
+				CS42L42_HSBIAS_SENSE_TRIP_MASK,
+				(0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) |
+				(0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) |
+				(0 << CS42L42_TIP_SENSE_EN_SHIFT) |
+				(3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT));
+
+	/* Set hs detect to manual, disabled mode */
+	regmap_update_bits(cs42l42->regmap,
+				CS42L42_HSDET_CTL2,
+				CS42L42_HSDET_CTRL_MASK |
+				CS42L42_HSDET_SET_MASK |
+				CS42L42_HSBIAS_REF_MASK |
+				CS42L42_HSDET_AUTO_TIME_MASK,
+				(0 << CS42L42_HSDET_CTRL_SHIFT) |
+				(2 << CS42L42_HSDET_SET_SHIFT) |
+				(0 << CS42L42_HSBIAS_REF_SHIFT) |
+				(3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+}
+
+static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42)
+{
+	int bias_level;
+	unsigned int detect_status;
+
+	/* Mask button detect interrupts */
+	regmap_update_bits(cs42l42->regmap,
+		CS42L42_DET_INT2_MASK,
+		CS42L42_M_DETECT_TF_MASK |
+		CS42L42_M_DETECT_FT_MASK |
+		CS42L42_M_HSBIAS_HIZ_MASK |
+		CS42L42_M_SHORT_RLS_MASK |
+		CS42L42_M_SHORT_DET_MASK,
+		(1 << CS42L42_M_DETECT_TF_SHIFT) |
+		(1 << CS42L42_M_DETECT_FT_SHIFT) |
+		(1 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+		(1 << CS42L42_M_SHORT_RLS_SHIFT) |
+		(1 << CS42L42_M_SHORT_DET_SHIFT));
+
+	usleep_range(cs42l42->btn_det_event_dbnce * 1000,
+		     cs42l42->btn_det_event_dbnce * 2000);
+
+	/* Test all 4 level detect biases */
+	bias_level = 1;
+	do {
+		/* Adjust button detect level sensitivity */
+		regmap_update_bits(cs42l42->regmap,
+			CS42L42_MIC_DET_CTL1,
+			CS42L42_LATCH_TO_VP_MASK |
+			CS42L42_EVENT_STAT_SEL_MASK |
+			CS42L42_HS_DET_LEVEL_MASK,
+			(1 << CS42L42_LATCH_TO_VP_SHIFT) |
+			(0 << CS42L42_EVENT_STAT_SEL_SHIFT) |
+			(cs42l42->bias_thresholds[bias_level] <<
+			CS42L42_HS_DET_LEVEL_SHIFT));
+
+		regmap_read(cs42l42->regmap, CS42L42_DET_STATUS2,
+				&detect_status);
+	} while ((detect_status & CS42L42_HS_TRUE_MASK) &&
+		(++bias_level < CS42L42_NUM_BIASES));
+
+	switch (bias_level) {
+	case 1: /* Function C button press */
+		dev_dbg(cs42l42->component->dev, "Function C button press\n");
+		break;
+	case 2: /* Function B button press */
+		dev_dbg(cs42l42->component->dev, "Function B button press\n");
+		break;
+	case 3: /* Function D button press */
+		dev_dbg(cs42l42->component->dev, "Function D button press\n");
+		break;
+	case 4: /* Function A button press */
+		dev_dbg(cs42l42->component->dev, "Function A button press\n");
+		break;
+	}
+
+	/* Set button detect level sensitivity back to default */
+	regmap_update_bits(cs42l42->regmap,
+		CS42L42_MIC_DET_CTL1,
+		CS42L42_LATCH_TO_VP_MASK |
+		CS42L42_EVENT_STAT_SEL_MASK |
+		CS42L42_HS_DET_LEVEL_MASK,
+		(1 << CS42L42_LATCH_TO_VP_SHIFT) |
+		(0 << CS42L42_EVENT_STAT_SEL_SHIFT) |
+		(cs42l42->bias_thresholds[0] << CS42L42_HS_DET_LEVEL_SHIFT));
+
+	/* Clear any button interrupts before unmasking them */
+	regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2,
+		    &detect_status);
+
+	/* Unmask button detect interrupts */
+	regmap_update_bits(cs42l42->regmap,
+		CS42L42_DET_INT2_MASK,
+		CS42L42_M_DETECT_TF_MASK |
+		CS42L42_M_DETECT_FT_MASK |
+		CS42L42_M_HSBIAS_HIZ_MASK |
+		CS42L42_M_SHORT_RLS_MASK |
+		CS42L42_M_SHORT_DET_MASK,
+		(0 << CS42L42_M_DETECT_TF_SHIFT) |
+		(0 << CS42L42_M_DETECT_FT_SHIFT) |
+		(0 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+		(1 << CS42L42_M_SHORT_RLS_SHIFT) |
+		(1 << CS42L42_M_SHORT_DET_SHIFT));
+}
+
+struct cs42l42_irq_params {
+	u16 status_addr;
+	u16 mask_addr;
+	u8 mask;
+};
+
+static const struct cs42l42_irq_params irq_params_table[] = {
+	{CS42L42_ADC_OVFL_STATUS, CS42L42_ADC_OVFL_INT_MASK,
+		CS42L42_ADC_OVFL_VAL_MASK},
+	{CS42L42_MIXER_STATUS, CS42L42_MIXER_INT_MASK,
+		CS42L42_MIXER_VAL_MASK},
+	{CS42L42_SRC_STATUS, CS42L42_SRC_INT_MASK,
+		CS42L42_SRC_VAL_MASK},
+	{CS42L42_ASP_RX_STATUS, CS42L42_ASP_RX_INT_MASK,
+		CS42L42_ASP_RX_VAL_MASK},
+	{CS42L42_ASP_TX_STATUS, CS42L42_ASP_TX_INT_MASK,
+		CS42L42_ASP_TX_VAL_MASK},
+	{CS42L42_CODEC_STATUS, CS42L42_CODEC_INT_MASK,
+		CS42L42_CODEC_VAL_MASK},
+	{CS42L42_DET_INT_STATUS1, CS42L42_DET_INT1_MASK,
+		CS42L42_DET_INT_VAL1_MASK},
+	{CS42L42_DET_INT_STATUS2, CS42L42_DET_INT2_MASK,
+		CS42L42_DET_INT_VAL2_MASK},
+	{CS42L42_SRCPL_INT_STATUS, CS42L42_SRCPL_INT_MASK,
+		CS42L42_SRCPL_VAL_MASK},
+	{CS42L42_VPMON_STATUS, CS42L42_VPMON_INT_MASK,
+		CS42L42_VPMON_VAL_MASK},
+	{CS42L42_PLL_LOCK_STATUS, CS42L42_PLL_LOCK_INT_MASK,
+		CS42L42_PLL_LOCK_VAL_MASK},
+	{CS42L42_TSRS_PLUG_STATUS, CS42L42_TSRS_PLUG_INT_MASK,
+		CS42L42_TSRS_PLUG_VAL_MASK}
+};
+
+static irqreturn_t cs42l42_irq_thread(int irq, void *data)
+{
+	struct cs42l42_private *cs42l42 = (struct cs42l42_private *)data;
+	struct snd_soc_component *component = cs42l42->component;
+	unsigned int stickies[12];
+	unsigned int masks[12];
+	unsigned int current_plug_status;
+	unsigned int current_button_status;
+	unsigned int i;
+
+	/* Read sticky registers to clear interurpt */
+	for (i = 0; i < ARRAY_SIZE(stickies); i++) {
+		regmap_read(cs42l42->regmap, irq_params_table[i].status_addr,
+				&(stickies[i]));
+		regmap_read(cs42l42->regmap, irq_params_table[i].mask_addr,
+				&(masks[i]));
+		stickies[i] = stickies[i] & (~masks[i]) &
+				irq_params_table[i].mask;
+	}
+
+	/* Read tip sense status before handling type detect */
+	current_plug_status = (stickies[11] &
+		(CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) >>
+		CS42L42_TS_PLUG_SHIFT;
+
+	/* Read button sense status */
+	current_button_status = stickies[7] &
+		(CS42L42_M_DETECT_TF_MASK |
+		CS42L42_M_DETECT_FT_MASK |
+		CS42L42_M_HSBIAS_HIZ_MASK);
+
+	/* Check auto-detect status */
+	if ((~masks[5]) & irq_params_table[5].mask) {
+		if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) {
+			cs42l42_process_hs_type_detect(cs42l42);
+			dev_dbg(component->dev,
+				"Auto detect done (%d)\n",
+				cs42l42->hs_type);
+		}
+	}
+
+	/* Check tip sense status */
+	if ((~masks[11]) & irq_params_table[11].mask) {
+		switch (current_plug_status) {
+		case CS42L42_TS_PLUG:
+			if (cs42l42->plug_state != CS42L42_TS_PLUG) {
+				cs42l42->plug_state = CS42L42_TS_PLUG;
+				cs42l42_init_hs_type_detect(cs42l42);
+			}
+			break;
+
+		case CS42L42_TS_UNPLUG:
+			if (cs42l42->plug_state != CS42L42_TS_UNPLUG) {
+				cs42l42->plug_state = CS42L42_TS_UNPLUG;
+				cs42l42_cancel_hs_type_detect(cs42l42);
+				dev_dbg(component->dev,
+					"Unplug event\n");
+			}
+			break;
+
+		default:
+			if (cs42l42->plug_state != CS42L42_TS_TRANS)
+				cs42l42->plug_state = CS42L42_TS_TRANS;
+		}
+	}
+
+	/* Check button detect status */
+	if ((~masks[7]) & irq_params_table[7].mask) {
+		if (!(current_button_status &
+			CS42L42_M_HSBIAS_HIZ_MASK)) {
+
+			if (current_button_status &
+				CS42L42_M_DETECT_TF_MASK) {
+				dev_dbg(component->dev,
+					"Button released\n");
+			} else if (current_button_status &
+				CS42L42_M_DETECT_FT_MASK) {
+				cs42l42_handle_button_press(cs42l42);
+			}
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void cs42l42_set_interrupt_masks(struct cs42l42_private *cs42l42)
+{
+	regmap_update_bits(cs42l42->regmap, CS42L42_ADC_OVFL_INT_MASK,
+			CS42L42_ADC_OVFL_MASK,
+			(1 << CS42L42_ADC_OVFL_SHIFT));
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_MIXER_INT_MASK,
+			CS42L42_MIX_CHB_OVFL_MASK |
+			CS42L42_MIX_CHA_OVFL_MASK |
+			CS42L42_EQ_OVFL_MASK |
+			CS42L42_EQ_BIQUAD_OVFL_MASK,
+			(1 << CS42L42_MIX_CHB_OVFL_SHIFT) |
+			(1 << CS42L42_MIX_CHA_OVFL_SHIFT) |
+			(1 << CS42L42_EQ_OVFL_SHIFT) |
+			(1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT));
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_SRC_INT_MASK,
+			CS42L42_SRC_ILK_MASK |
+			CS42L42_SRC_OLK_MASK |
+			CS42L42_SRC_IUNLK_MASK |
+			CS42L42_SRC_OUNLK_MASK,
+			(1 << CS42L42_SRC_ILK_SHIFT) |
+			(1 << CS42L42_SRC_OLK_SHIFT) |
+			(1 << CS42L42_SRC_IUNLK_SHIFT) |
+			(1 << CS42L42_SRC_OUNLK_SHIFT));
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_ASP_RX_INT_MASK,
+			CS42L42_ASPRX_NOLRCK_MASK |
+			CS42L42_ASPRX_EARLY_MASK |
+			CS42L42_ASPRX_LATE_MASK |
+			CS42L42_ASPRX_ERROR_MASK |
+			CS42L42_ASPRX_OVLD_MASK,
+			(1 << CS42L42_ASPRX_NOLRCK_SHIFT) |
+			(1 << CS42L42_ASPRX_EARLY_SHIFT) |
+			(1 << CS42L42_ASPRX_LATE_SHIFT) |
+			(1 << CS42L42_ASPRX_ERROR_SHIFT) |
+			(1 << CS42L42_ASPRX_OVLD_SHIFT));
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_ASP_TX_INT_MASK,
+			CS42L42_ASPTX_NOLRCK_MASK |
+			CS42L42_ASPTX_EARLY_MASK |
+			CS42L42_ASPTX_LATE_MASK |
+			CS42L42_ASPTX_SMERROR_MASK,
+			(1 << CS42L42_ASPTX_NOLRCK_SHIFT) |
+			(1 << CS42L42_ASPTX_EARLY_SHIFT) |
+			(1 << CS42L42_ASPTX_LATE_SHIFT) |
+			(1 << CS42L42_ASPTX_SMERROR_SHIFT));
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_CODEC_INT_MASK,
+			CS42L42_PDN_DONE_MASK |
+			CS42L42_HSDET_AUTO_DONE_MASK,
+			(1 << CS42L42_PDN_DONE_SHIFT) |
+			(1 << CS42L42_HSDET_AUTO_DONE_SHIFT));
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_SRCPL_INT_MASK,
+			CS42L42_SRCPL_ADC_LK_MASK |
+			CS42L42_SRCPL_DAC_LK_MASK |
+			CS42L42_SRCPL_ADC_UNLK_MASK |
+			CS42L42_SRCPL_DAC_UNLK_MASK,
+			(1 << CS42L42_SRCPL_ADC_LK_SHIFT) |
+			(1 << CS42L42_SRCPL_DAC_LK_SHIFT) |
+			(1 << CS42L42_SRCPL_ADC_UNLK_SHIFT) |
+			(1 << CS42L42_SRCPL_DAC_UNLK_SHIFT));
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT1_MASK,
+			CS42L42_TIP_SENSE_UNPLUG_MASK |
+			CS42L42_TIP_SENSE_PLUG_MASK |
+			CS42L42_HSBIAS_SENSE_MASK,
+			(1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT) |
+			(1 << CS42L42_TIP_SENSE_PLUG_SHIFT) |
+			(1 << CS42L42_HSBIAS_SENSE_SHIFT));
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT2_MASK,
+			CS42L42_M_DETECT_TF_MASK |
+			CS42L42_M_DETECT_FT_MASK |
+			CS42L42_M_HSBIAS_HIZ_MASK |
+			CS42L42_M_SHORT_RLS_MASK |
+			CS42L42_M_SHORT_DET_MASK,
+			(1 << CS42L42_M_DETECT_TF_SHIFT) |
+			(1 << CS42L42_M_DETECT_FT_SHIFT) |
+			(1 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+			(1 << CS42L42_M_SHORT_RLS_SHIFT) |
+			(1 << CS42L42_M_SHORT_DET_SHIFT));
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_VPMON_INT_MASK,
+			CS42L42_VPMON_MASK,
+			(1 << CS42L42_VPMON_SHIFT));
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_PLL_LOCK_INT_MASK,
+			CS42L42_PLL_LOCK_MASK,
+			(1 << CS42L42_PLL_LOCK_SHIFT));
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK,
+			CS42L42_RS_PLUG_MASK |
+			CS42L42_RS_UNPLUG_MASK |
+			CS42L42_TS_PLUG_MASK |
+			CS42L42_TS_UNPLUG_MASK,
+			(1 << CS42L42_RS_PLUG_SHIFT) |
+			(1 << CS42L42_RS_UNPLUG_SHIFT) |
+			(0 << CS42L42_TS_PLUG_SHIFT) |
+			(0 << CS42L42_TS_UNPLUG_SHIFT));
+}
+
+static void cs42l42_setup_hs_type_detect(struct cs42l42_private *cs42l42)
+{
+	unsigned int reg;
+
+	cs42l42->hs_type = CS42L42_PLUG_INVALID;
+
+	/* Latch analog controls to VP power domain */
+	regmap_update_bits(cs42l42->regmap, CS42L42_MIC_DET_CTL1,
+			CS42L42_LATCH_TO_VP_MASK |
+			CS42L42_EVENT_STAT_SEL_MASK |
+			CS42L42_HS_DET_LEVEL_MASK,
+			(1 << CS42L42_LATCH_TO_VP_SHIFT) |
+			(0 << CS42L42_EVENT_STAT_SEL_SHIFT) |
+			(cs42l42->bias_thresholds[0] <<
+			CS42L42_HS_DET_LEVEL_SHIFT));
+
+	/* Remove ground noise-suppression clamps */
+	regmap_update_bits(cs42l42->regmap,
+			CS42L42_HS_CLAMP_DISABLE,
+			CS42L42_HS_CLAMP_DISABLE_MASK,
+			(1 << CS42L42_HS_CLAMP_DISABLE_SHIFT));
+
+	/* Enable the tip sense circuit */
+	regmap_update_bits(cs42l42->regmap, CS42L42_TIPSENSE_CTL,
+			CS42L42_TIP_SENSE_CTRL_MASK |
+			CS42L42_TIP_SENSE_INV_MASK |
+			CS42L42_TIP_SENSE_DEBOUNCE_MASK,
+			(3 << CS42L42_TIP_SENSE_CTRL_SHIFT) |
+			(0 << CS42L42_TIP_SENSE_INV_SHIFT) |
+			(2 << CS42L42_TIP_SENSE_DEBOUNCE_SHIFT));
+
+	/* Save the initial status of the tip sense */
+	regmap_read(cs42l42->regmap,
+			  CS42L42_TSRS_PLUG_STATUS,
+			  &reg);
+	cs42l42->plug_state = (((char) reg) &
+		      (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) >>
+		      CS42L42_TS_PLUG_SHIFT;
+}
+
+static const unsigned int threshold_defaults[] = {
+	CS42L42_HS_DET_LEVEL_15,
+	CS42L42_HS_DET_LEVEL_8,
+	CS42L42_HS_DET_LEVEL_4,
+	CS42L42_HS_DET_LEVEL_1
+};
+
+static int cs42l42_handle_device_data(struct i2c_client *i2c_client,
+					struct cs42l42_private *cs42l42)
+{
+	struct device_node *np = i2c_client->dev.of_node;
+	unsigned int val;
+	unsigned int thresholds[CS42L42_NUM_BIASES];
+	int ret;
+	int i;
+
+	ret = of_property_read_u32(np, "cirrus,ts-inv", &val);
+
+	if (!ret) {
+		switch (val) {
+		case CS42L42_TS_INV_EN:
+		case CS42L42_TS_INV_DIS:
+			cs42l42->ts_inv = val;
+			break;
+		default:
+			dev_err(&i2c_client->dev,
+				"Wrong cirrus,ts-inv DT value %d\n",
+				val);
+			cs42l42->ts_inv = CS42L42_TS_INV_DIS;
+		}
+	} else {
+		cs42l42->ts_inv = CS42L42_TS_INV_DIS;
+	}
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL,
+			CS42L42_TS_INV_MASK,
+			(cs42l42->ts_inv << CS42L42_TS_INV_SHIFT));
+
+	ret = of_property_read_u32(np, "cirrus,ts-dbnc-rise", &val);
+
+	if (!ret) {
+		switch (val) {
+		case CS42L42_TS_DBNCE_0:
+		case CS42L42_TS_DBNCE_125:
+		case CS42L42_TS_DBNCE_250:
+		case CS42L42_TS_DBNCE_500:
+		case CS42L42_TS_DBNCE_750:
+		case CS42L42_TS_DBNCE_1000:
+		case CS42L42_TS_DBNCE_1250:
+		case CS42L42_TS_DBNCE_1500:
+			cs42l42->ts_dbnc_rise = val;
+			break;
+		default:
+			dev_err(&i2c_client->dev,
+				"Wrong cirrus,ts-dbnc-rise DT value %d\n",
+				val);
+			cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000;
+		}
+	} else {
+		cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000;
+	}
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL,
+			CS42L42_TS_RISE_DBNCE_TIME_MASK,
+			(cs42l42->ts_dbnc_rise <<
+			CS42L42_TS_RISE_DBNCE_TIME_SHIFT));
+
+	ret = of_property_read_u32(np, "cirrus,ts-dbnc-fall", &val);
+
+	if (!ret) {
+		switch (val) {
+		case CS42L42_TS_DBNCE_0:
+		case CS42L42_TS_DBNCE_125:
+		case CS42L42_TS_DBNCE_250:
+		case CS42L42_TS_DBNCE_500:
+		case CS42L42_TS_DBNCE_750:
+		case CS42L42_TS_DBNCE_1000:
+		case CS42L42_TS_DBNCE_1250:
+		case CS42L42_TS_DBNCE_1500:
+			cs42l42->ts_dbnc_fall = val;
+			break;
+		default:
+			dev_err(&i2c_client->dev,
+				"Wrong cirrus,ts-dbnc-fall DT value %d\n",
+				val);
+			cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0;
+		}
+	} else {
+		cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0;
+	}
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL,
+			CS42L42_TS_FALL_DBNCE_TIME_MASK,
+			(cs42l42->ts_dbnc_fall <<
+			CS42L42_TS_FALL_DBNCE_TIME_SHIFT));
+
+	ret = of_property_read_u32(np, "cirrus,btn-det-init-dbnce", &val);
+
+	if (!ret) {
+		if ((val >= CS42L42_BTN_DET_INIT_DBNCE_MIN) &&
+			(val <= CS42L42_BTN_DET_INIT_DBNCE_MAX))
+			cs42l42->btn_det_init_dbnce = val;
+		else {
+			dev_err(&i2c_client->dev,
+				"Wrong cirrus,btn-det-init-dbnce DT value %d\n",
+				val);
+			cs42l42->btn_det_init_dbnce =
+				CS42L42_BTN_DET_INIT_DBNCE_DEFAULT;
+		}
+	} else {
+		cs42l42->btn_det_init_dbnce =
+			CS42L42_BTN_DET_INIT_DBNCE_DEFAULT;
+	}
+
+	ret = of_property_read_u32(np, "cirrus,btn-det-event-dbnce", &val);
+
+	if (!ret) {
+		if ((val >= CS42L42_BTN_DET_EVENT_DBNCE_MIN) &&
+			(val <= CS42L42_BTN_DET_EVENT_DBNCE_MAX))
+			cs42l42->btn_det_event_dbnce = val;
+		else {
+			dev_err(&i2c_client->dev,
+			"Wrong cirrus,btn-det-event-dbnce DT value %d\n", val);
+			cs42l42->btn_det_event_dbnce =
+				CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT;
+		}
+	} else {
+		cs42l42->btn_det_event_dbnce =
+			CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT;
+	}
+
+	ret = of_property_read_u32_array(np, "cirrus,bias-lvls",
+				   (u32 *)thresholds, CS42L42_NUM_BIASES);
+
+	if (!ret) {
+		for (i = 0; i < CS42L42_NUM_BIASES; i++) {
+			if ((thresholds[i] >= CS42L42_HS_DET_LEVEL_MIN) &&
+				(thresholds[i] <= CS42L42_HS_DET_LEVEL_MAX))
+				cs42l42->bias_thresholds[i] = thresholds[i];
+			else {
+				dev_err(&i2c_client->dev,
+				"Wrong cirrus,bias-lvls[%d] DT value %d\n", i,
+					thresholds[i]);
+				cs42l42->bias_thresholds[i] =
+					threshold_defaults[i];
+			}
+		}
+	} else {
+		for (i = 0; i < CS42L42_NUM_BIASES; i++)
+			cs42l42->bias_thresholds[i] = threshold_defaults[i];
+	}
+
+	ret = of_property_read_u32(np, "cirrus,hs-bias-ramp-rate", &val);
+
+	if (!ret) {
+		switch (val) {
+		case CS42L42_HSBIAS_RAMP_FAST_RISE_SLOW_FALL:
+			cs42l42->hs_bias_ramp_rate = val;
+			cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME0;
+			break;
+		case CS42L42_HSBIAS_RAMP_FAST:
+			cs42l42->hs_bias_ramp_rate = val;
+			cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME1;
+			break;
+		case CS42L42_HSBIAS_RAMP_SLOW:
+			cs42l42->hs_bias_ramp_rate = val;
+			cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2;
+			break;
+		case CS42L42_HSBIAS_RAMP_SLOWEST:
+			cs42l42->hs_bias_ramp_rate = val;
+			cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME3;
+			break;
+		default:
+			dev_err(&i2c_client->dev,
+				"Wrong cirrus,hs-bias-ramp-rate DT value %d\n",
+				val);
+			cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW;
+			cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2;
+		}
+	} else {
+		cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW;
+		cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2;
+	}
+
+	regmap_update_bits(cs42l42->regmap, CS42L42_HS_BIAS_CTL,
+			CS42L42_HSBIAS_RAMP_MASK,
+			(cs42l42->hs_bias_ramp_rate <<
+			CS42L42_HSBIAS_RAMP_SHIFT));
+
+	return 0;
+}
+
+static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
+				       const struct i2c_device_id *id)
+{
+	struct cs42l42_private *cs42l42;
+	int ret, i;
+	unsigned int devid = 0;
+	unsigned int reg;
+
+	cs42l42 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l42_private),
+			       GFP_KERNEL);
+	if (!cs42l42)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c_client, cs42l42);
+
+	cs42l42->regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap);
+	if (IS_ERR(cs42l42->regmap)) {
+		ret = PTR_ERR(cs42l42->regmap);
+		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cs42l42->supplies); i++)
+		cs42l42->supplies[i].supply = cs42l42_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c_client->dev,
+				      ARRAY_SIZE(cs42l42->supplies),
+				      cs42l42->supplies);
+	if (ret != 0) {
+		dev_err(&i2c_client->dev,
+			"Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies),
+				    cs42l42->supplies);
+	if (ret != 0) {
+		dev_err(&i2c_client->dev,
+			"Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	/* Reset the Device */
+	cs42l42->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+		"reset", GPIOD_OUT_LOW);
+	if (IS_ERR(cs42l42->reset_gpio))
+		return PTR_ERR(cs42l42->reset_gpio);
+
+	if (cs42l42->reset_gpio) {
+		dev_dbg(&i2c_client->dev, "Found reset GPIO\n");
+		gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+	}
+	mdelay(3);
+
+	/* Request IRQ */
+	ret = devm_request_threaded_irq(&i2c_client->dev,
+			i2c_client->irq,
+			NULL, cs42l42_irq_thread,
+			IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+			"cs42l42", cs42l42);
+
+	if (ret != 0)
+		dev_err(&i2c_client->dev,
+			"Failed to request IRQ: %d\n", ret);
+
+	/* initialize codec */
+	ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_AB, &reg);
+	devid = (reg & 0xFF) << 12;
+
+	ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_CD, &reg);
+	devid |= (reg & 0xFF) << 4;
+
+	ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_E, &reg);
+	devid |= (reg & 0xF0) >> 4;
+
+	if (devid != CS42L42_CHIP_ID) {
+		ret = -ENODEV;
+		dev_err(&i2c_client->dev,
+			"CS42L42 Device ID (%X). Expected %X\n",
+			devid, CS42L42_CHIP_ID);
+		return ret;
+	}
+
+	ret = regmap_read(cs42l42->regmap, CS42L42_REVID, &reg);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+		return ret;
+	}
+
+	dev_info(&i2c_client->dev,
+		 "Cirrus Logic CS42L42, Revision: %02X\n", reg & 0xFF);
+
+	/* Power up the codec */
+	regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL1,
+			CS42L42_ASP_DAO_PDN_MASK |
+			CS42L42_ASP_DAI_PDN_MASK |
+			CS42L42_MIXER_PDN_MASK |
+			CS42L42_EQ_PDN_MASK |
+			CS42L42_HP_PDN_MASK |
+			CS42L42_ADC_PDN_MASK |
+			CS42L42_PDN_ALL_MASK,
+			(1 << CS42L42_ASP_DAO_PDN_SHIFT) |
+			(1 << CS42L42_ASP_DAI_PDN_SHIFT) |
+			(1 << CS42L42_MIXER_PDN_SHIFT) |
+			(1 << CS42L42_EQ_PDN_SHIFT) |
+			(1 << CS42L42_HP_PDN_SHIFT) |
+			(1 << CS42L42_ADC_PDN_SHIFT) |
+			(0 << CS42L42_PDN_ALL_SHIFT));
+
+	if (i2c_client->dev.of_node) {
+		ret = cs42l42_handle_device_data(i2c_client, cs42l42);
+		if (ret != 0)
+			return ret;
+	}
+
+	/* Setup headset detection */
+	cs42l42_setup_hs_type_detect(cs42l42);
+
+	/* Mask/Unmask Interrupts */
+	cs42l42_set_interrupt_masks(cs42l42);
+
+	/* Register codec for machine driver */
+	ret = devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_dev_cs42l42, &cs42l42_dai, 1);
+	if (ret < 0)
+		goto err_disable;
+	return 0;
+
+err_disable:
+	regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies),
+				cs42l42->supplies);
+	return ret;
+}
+
+static int cs42l42_i2c_remove(struct i2c_client *i2c_client)
+{
+	struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client);
+
+	/* Hold down reset */
+	gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int cs42l42_runtime_suspend(struct device *dev)
+{
+	struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
+
+	regcache_cache_only(cs42l42->regmap, true);
+	regcache_mark_dirty(cs42l42->regmap);
+
+	/* Hold down reset */
+	gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
+
+	/* remove power */
+	regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies),
+				cs42l42->supplies);
+
+	return 0;
+}
+
+static int cs42l42_runtime_resume(struct device *dev)
+{
+	struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
+	int ret;
+
+	/* Enable power */
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies),
+					cs42l42->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+
+	regcache_cache_only(cs42l42->regmap, false);
+	regcache_sync(cs42l42->regmap);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops cs42l42_runtime_pm = {
+	SET_RUNTIME_PM_OPS(cs42l42_runtime_suspend, cs42l42_runtime_resume,
+			   NULL)
+};
+
+static const struct of_device_id cs42l42_of_match[] = {
+	{ .compatible = "cirrus,cs42l42", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cs42l42_of_match);
+
+
+static const struct i2c_device_id cs42l42_id[] = {
+	{"cs42l42", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs42l42_id);
+
+static struct i2c_driver cs42l42_i2c_driver = {
+	.driver = {
+		.name = "cs42l42",
+		.pm = &cs42l42_runtime_pm,
+		.of_match_table = cs42l42_of_match,
+		},
+	.id_table = cs42l42_id,
+	.probe = cs42l42_i2c_probe,
+	.remove = cs42l42_i2c_remove,
+};
+
+module_i2c_driver(cs42l42_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L42 driver");
+MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_AUTHOR("Michael White, Cirrus Logic Inc, <michael.white@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h
new file mode 100644
index 0000000..09b0a93
--- /dev/null
+++ b/sound/soc/codecs/cs42l42.h
@@ -0,0 +1,776 @@
+/*
+ * cs42l42.h -- CS42L42 ALSA SoC audio driver header
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: James Schulman <james.schulman@cirrus.com>
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ * Author: Michael White <michael.white@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CS42L42_H__
+#define __CS42L42_H__
+
+#define CS42L42_PAGE_REGISTER	0x00	/* Page Select Register */
+#define CS42L42_WIN_START	0x00
+#define CS42L42_WIN_LEN		0x100
+#define CS42L42_RANGE_MIN	0x00
+#define CS42L42_RANGE_MAX	0x7F
+
+#define CS42L42_PAGE_10		0x1000
+#define CS42L42_PAGE_11		0x1100
+#define CS42L42_PAGE_12		0x1200
+#define CS42L42_PAGE_13		0x1300
+#define CS42L42_PAGE_15		0x1500
+#define CS42L42_PAGE_19		0x1900
+#define CS42L42_PAGE_1B		0x1B00
+#define CS42L42_PAGE_1C		0x1C00
+#define CS42L42_PAGE_1D		0x1D00
+#define CS42L42_PAGE_1F		0x1F00
+#define CS42L42_PAGE_20		0x2000
+#define CS42L42_PAGE_21		0x2100
+#define CS42L42_PAGE_23		0x2300
+#define CS42L42_PAGE_24		0x2400
+#define CS42L42_PAGE_25		0x2500
+#define CS42L42_PAGE_26		0x2600
+#define CS42L42_PAGE_28		0x2800
+#define CS42L42_PAGE_29		0x2900
+#define CS42L42_PAGE_2A		0x2A00
+#define CS42L42_PAGE_30		0x3000
+
+#define CS42L42_CHIP_ID		0x42A42
+
+/* Page 0x10 Global Registers */
+#define CS42L42_DEVID_AB		(CS42L42_PAGE_10 + 0x01)
+#define CS42L42_DEVID_CD		(CS42L42_PAGE_10 + 0x02)
+#define CS42L42_DEVID_E			(CS42L42_PAGE_10 + 0x03)
+#define CS42L42_FABID			(CS42L42_PAGE_10 + 0x04)
+#define CS42L42_REVID			(CS42L42_PAGE_10 + 0x05)
+#define CS42L42_FRZ_CTL			(CS42L42_PAGE_10 + 0x06)
+
+#define CS42L42_SRC_CTL			(CS42L42_PAGE_10 + 0x07)
+#define CS42L42_SRC_BYPASS_DAC_SHIFT	1
+#define CS42L42_SRC_BYPASS_DAC_MASK	(1 << CS42L42_SRC_BYPASS_DAC_SHIFT)
+
+#define CS42L42_MCLK_STATUS		(CS42L42_PAGE_10 + 0x08)
+
+#define CS42L42_MCLK_CTL		(CS42L42_PAGE_10 + 0x09)
+#define CS42L42_INTERNAL_FS_SHIFT	1
+#define CS42L42_INTERNAL_FS_MASK	(1 << CS42L42_INTERNAL_FS_SHIFT)
+
+#define CS42L42_SFTRAMP_RATE		(CS42L42_PAGE_10 + 0x0A)
+#define CS42L42_I2C_DEBOUNCE		(CS42L42_PAGE_10 + 0x0E)
+#define CS42L42_I2C_STRETCH		(CS42L42_PAGE_10 + 0x0F)
+#define CS42L42_I2C_TIMEOUT		(CS42L42_PAGE_10 + 0x10)
+
+/* Page 0x11 Power and Headset Detect Registers */
+#define CS42L42_PWR_CTL1		(CS42L42_PAGE_11 + 0x01)
+#define CS42L42_ASP_DAO_PDN_SHIFT	7
+#define CS42L42_ASP_DAO_PDN_MASK	(1 << CS42L42_ASP_DAO_PDN_SHIFT)
+#define CS42L42_ASP_DAI_PDN_SHIFT	6
+#define CS42L42_ASP_DAI_PDN_MASK	(1 << CS42L42_ASP_DAI_PDN_SHIFT)
+#define CS42L42_MIXER_PDN_SHIFT		5
+#define CS42L42_MIXER_PDN_MASK		(1 << CS42L42_MIXER_PDN_SHIFT)
+#define CS42L42_EQ_PDN_SHIFT		4
+#define CS42L42_EQ_PDN_MASK		(1 << CS42L42_EQ_PDN_SHIFT)
+#define CS42L42_HP_PDN_SHIFT		3
+#define CS42L42_HP_PDN_MASK		(1 << CS42L42_HP_PDN_SHIFT)
+#define CS42L42_ADC_PDN_SHIFT		2
+#define CS42L42_ADC_PDN_MASK		(1 << CS42L42_HP_PDN_SHIFT)
+#define CS42L42_PDN_ALL_SHIFT		0
+#define CS42L42_PDN_ALL_MASK		(1 << CS42L42_PDN_ALL_SHIFT)
+
+#define CS42L42_PWR_CTL2		(CS42L42_PAGE_11 + 0x02)
+#define CS42L42_ADC_SRC_PDNB_SHIFT	0
+#define CS42L42_ADC_SRC_PDNB_MASK	(1 << CS42L42_ADC_SRC_PDNB_SHIFT)
+#define CS42L42_DAC_SRC_PDNB_SHIFT	1
+#define CS42L42_DAC_SRC_PDNB_MASK	(1 << CS42L42_DAC_SRC_PDNB_SHIFT)
+#define CS42L42_ASP_DAI1_PDN_SHIFT	2
+#define CS42L42_ASP_DAI1_PDN_MASK	(1 << CS42L42_ASP_DAI1_PDN_SHIFT)
+#define CS42L42_SRC_PDN_OVERRIDE_SHIFT	3
+#define CS42L42_SRC_PDN_OVERRIDE_MASK	(1 << CS42L42_SRC_PDN_OVERRIDE_SHIFT)
+#define CS42L42_DISCHARGE_FILT_SHIFT	4
+#define CS42L42_DISCHARGE_FILT_MASK	(1 << CS42L42_DISCHARGE_FILT_SHIFT)
+
+#define CS42L42_PWR_CTL3			(CS42L42_PAGE_11 + 0x03)
+#define CS42L42_RING_SENSE_PDNB_SHIFT		1
+#define CS42L42_RING_SENSE_PDNB_MASK		(1 << \
+					CS42L42_RING_SENSE_PDNB_SHIFT)
+#define CS42L42_VPMON_PDNB_SHIFT		2
+#define CS42L42_VPMON_PDNB_MASK			(1 << \
+					CS42L42_VPMON_PDNB_SHIFT)
+#define CS42L42_SW_CLK_STP_STAT_SEL_SHIFT	5
+#define CS42L42_SW_CLK_STP_STAT_SEL_MASK	(3 << \
+					CS42L42_SW_CLK_STP_STAT_SEL_SHIFT)
+
+#define CS42L42_RSENSE_CTL1			(CS42L42_PAGE_11 + 0x04)
+#define CS42L42_RS_TRIM_R_SHIFT			0
+#define CS42L42_RS_TRIM_R_MASK			(1 << \
+					CS42L42_RS_TRIM_R_SHIFT)
+#define CS42L42_RS_TRIM_T_SHIFT			1
+#define CS42L42_RS_TRIM_T_MASK			(1 << \
+					CS42L42_RS_TRIM_T_SHIFT)
+#define CS42L42_HPREF_RS_SHIFT			2
+#define CS42L42_HPREF_RS_MASK			(1 << \
+					CS42L42_HPREF_RS_SHIFT)
+#define CS42L42_HSBIAS_FILT_REF_RS_SHIFT	3
+#define CS42L42_HSBIAS_FILT_REF_RS_MASK		(1 << \
+					CS42L42_HSBIAS_FILT_REF_RS_SHIFT)
+#define CS42L42_RING_SENSE_PU_HIZ_SHIFT		6
+#define CS42L42_RING_SENSE_PU_HIZ_MASK		(1 << \
+					CS42L42_RING_SENSE_PU_HIZ_SHIFT)
+
+#define CS42L42_RSENSE_CTL2		(CS42L42_PAGE_11 + 0x05)
+#define CS42L42_TS_RS_GATE_SHIFT	7
+#define CS42L42_TS_RS_GATE_MAS		(1 << CS42L42_TS_RS_GATE_SHIFT)
+
+#define CS42L42_OSC_SWITCH		(CS42L42_PAGE_11 + 0x07)
+#define CS42L42_SCLK_PRESENT_SHIFT	0
+#define CS42L42_SCLK_PRESENT_MASK	(1 << CS42L42_SCLK_PRESENT_SHIFT)
+
+#define CS42L42_OSC_SWITCH_STATUS	(CS42L42_PAGE_11 + 0x09)
+#define CS42L42_OSC_SW_SEL_STAT_SHIFT	0
+#define CS42L42_OSC_SW_SEL_STAT_MASK	(3 << CS42L42_OSC_SW_SEL_STAT_SHIFT)
+#define CS42L42_OSC_PDNB_STAT_SHIFT	2
+#define CS42L42_OSC_PDNB_STAT_MASK	(1 << CS42L42_OSC_SW_SEL_STAT_SHIFT)
+
+#define CS42L42_RSENSE_CTL3			(CS42L42_PAGE_11 + 0x12)
+#define CS42L42_RS_RISE_DBNCE_TIME_SHIFT	0
+#define CS42L42_RS_RISE_DBNCE_TIME_MASK		(7 << \
+					CS42L42_RS_RISE_DBNCE_TIME_SHIFT)
+#define CS42L42_RS_FALL_DBNCE_TIME_SHIFT	3
+#define CS42L42_RS_FALL_DBNCE_TIME_MASK		(7 << \
+					CS42L42_RS_FALL_DBNCE_TIME_SHIFT)
+#define CS42L42_RS_PU_EN_SHIFT			6
+#define CS42L42_RS_PU_EN_MASK			(1 << \
+					CS42L42_RS_PU_EN_SHIFT)
+#define CS42L42_RS_INV_SHIFT			7
+#define CS42L42_RS_INV_MASK			(1 << \
+					CS42L42_RS_INV_SHIFT)
+
+#define CS42L42_TSENSE_CTL			(CS42L42_PAGE_11 + 0x13)
+#define CS42L42_TS_RISE_DBNCE_TIME_SHIFT	0
+#define CS42L42_TS_RISE_DBNCE_TIME_MASK		(7 << \
+					CS42L42_TS_RISE_DBNCE_TIME_SHIFT)
+#define CS42L42_TS_FALL_DBNCE_TIME_SHIFT	3
+#define CS42L42_TS_FALL_DBNCE_TIME_MASK		(7 << \
+					CS42L42_TS_FALL_DBNCE_TIME_SHIFT)
+#define CS42L42_TS_INV_SHIFT			7
+#define CS42L42_TS_INV_MASK			(1 << \
+					CS42L42_TS_INV_SHIFT)
+
+#define CS42L42_TSRS_INT_DISABLE	(CS42L42_PAGE_11 + 0x14)
+#define CS42L42_D_RS_PLUG_DBNC_SHIFT	0
+#define CS42L42_D_RS_PLUG_DBNC_MASK	(1 << CS42L42_D_RS_PLUG_DBNC_SHIFT)
+#define CS42L42_D_RS_UNPLUG_DBNC_SHIFT	1
+#define CS42L42_D_RS_UNPLUG_DBNC_MASK	(1 << CS42L42_D_RS_UNPLUG_DBNC_SHIFT)
+#define CS42L42_D_TS_PLUG_DBNC_SHIFT	2
+#define CS42L42_D_TS_PLUG_DBNC_MASK	(1 << CS42L42_D_TS_PLUG_DBNC_SHIFT)
+#define CS42L42_D_TS_UNPLUG_DBNC_SHIFT	3
+#define CS42L42_D_TS_UNPLUG_DBNC_MASK	(1 << CS42L42_D_TS_UNPLUG_DBNC_SHIFT)
+
+#define CS42L42_TRSENSE_STATUS		(CS42L42_PAGE_11 + 0x15)
+#define CS42L42_RS_PLUG_DBNC_SHIFT	0
+#define CS42L42_RS_PLUG_DBNC_MASK	(1 << CS42L42_RS_PLUG_DBNC_SHIFT)
+#define CS42L42_RS_UNPLUG_DBNC_SHIFT	1
+#define CS42L42_RS_UNPLUG_DBNC_MASK	(1 << CS42L42_RS_UNPLUG_DBNC_SHIFT)
+#define CS42L42_TS_PLUG_DBNC_SHIFT	2
+#define CS42L42_TS_PLUG_DBNC_MASK	(1 << CS42L42_TS_PLUG_DBNC_SHIFT)
+#define CS42L42_TS_UNPLUG_DBNC_SHIFT	3
+#define CS42L42_TS_UNPLUG_DBNC_MASK	(1 << CS42L42_TS_UNPLUG_DBNC_SHIFT)
+
+#define CS42L42_HSDET_CTL1		(CS42L42_PAGE_11 + 0x1F)
+#define CS42L42_HSDET_COMP1_LVL_SHIFT	0
+#define CS42L42_HSDET_COMP1_LVL_MASK	(15 << CS42L42_HSDET_COMP1_LVL_SHIFT)
+#define CS42L42_HSDET_COMP2_LVL_SHIFT	4
+#define CS42L42_HSDET_COMP2_LVL_MASK	(15 << CS42L42_HSDET_COMP2_LVL_SHIFT)
+
+#define CS42L42_HSDET_CTL2		(CS42L42_PAGE_11 + 0x20)
+#define CS42L42_HSDET_AUTO_TIME_SHIFT	0
+#define CS42L42_HSDET_AUTO_TIME_MASK	(3 << CS42L42_HSDET_AUTO_TIME_SHIFT)
+#define CS42L42_HSBIAS_REF_SHIFT	3
+#define CS42L42_HSBIAS_REF_MASK		(1 << CS42L42_HSBIAS_REF_SHIFT)
+#define CS42L42_HSDET_SET_SHIFT		4
+#define CS42L42_HSDET_SET_MASK		(3 << CS42L42_HSDET_SET_SHIFT)
+#define CS42L42_HSDET_CTRL_SHIFT	6
+#define CS42L42_HSDET_CTRL_MASK		(3 << CS42L42_HSDET_CTRL_SHIFT)
+
+#define CS42L42_HS_SWITCH_CTL		(CS42L42_PAGE_11 + 0x21)
+#define CS42L42_SW_GNDHS_HS4_SHIFT	0
+#define CS42L42_SW_GNDHS_HS4_MASK	(1 << CS42L42_SW_GNDHS_HS4_SHIFT)
+#define CS42L42_SW_GNDHS_HS3_SHIFT	1
+#define CS42L42_SW_GNDHS_HS3_MASK	(1 << CS42L42_SW_GNDHS_HS3_SHIFT)
+#define CS42L42_SW_HSB_HS4_SHIFT	2
+#define CS42L42_SW_HSB_HS4_MASK		(1 << CS42L42_SW_HSB_HS4_SHIFT)
+#define CS42L42_SW_HSB_HS3_SHIFT	3
+#define CS42L42_SW_HSB_HS3_MASK		(1 << CS42L42_SW_HSB_HS3_SHIFT)
+#define CS42L42_SW_HSB_FILT_HS4_SHIFT	4
+#define CS42L42_SW_HSB_FILT_HS4_MASK	(1 << CS42L42_SW_HSB_FILT_HS4_SHIFT)
+#define CS42L42_SW_HSB_FILT_HS3_SHIFT	5
+#define CS42L42_SW_HSB_FILT_HS3_MASK	(1 << CS42L42_SW_HSB_FILT_HS3_SHIFT)
+#define CS42L42_SW_REF_HS4_SHIFT	6
+#define CS42L42_SW_REF_HS4_MASK		(1 << CS42L42_SW_REF_HS4_SHIFT)
+#define CS42L42_SW_REF_HS3_SHIFT	7
+#define CS42L42_SW_REF_HS3_MASK		(1 << CS42L42_SW_REF_HS3_SHIFT)
+
+#define CS42L42_HS_DET_STATUS		(CS42L42_PAGE_11 + 0x24)
+#define CS42L42_HSDET_TYPE_SHIFT	0
+#define CS42L42_HSDET_TYPE_MASK		(3 << CS42L42_HSDET_TYPE_SHIFT)
+#define CS42L42_HSDET_COMP1_OUT_SHIFT	6
+#define CS42L42_HSDET_COMP1_OUT_MASK	(1 << CS42L42_HSDET_COMP1_OUT_SHIFT)
+#define CS42L42_HSDET_COMP2_OUT_SHIFT	7
+#define CS42L42_HSDET_COMP2_OUT_MASK	(1 << CS42L42_HSDET_COMP2_OUT_SHIFT)
+#define CS42L42_PLUG_CTIA		0
+#define CS42L42_PLUG_OMTP		1
+#define CS42L42_PLUG_HEADPHONE		2
+#define CS42L42_PLUG_INVALID		3
+
+#define CS42L42_HS_CLAMP_DISABLE	(CS42L42_PAGE_11 + 0x29)
+#define CS42L42_HS_CLAMP_DISABLE_SHIFT	0
+#define CS42L42_HS_CLAMP_DISABLE_MASK	(1 << CS42L42_HS_CLAMP_DISABLE_SHIFT)
+
+/* Page 0x12 Clocking Registers */
+#define CS42L42_MCLK_SRC_SEL		(CS42L42_PAGE_12 + 0x01)
+#define CS42L42_MCLKDIV_SHIFT		1
+#define CS42L42_MCLKDIV_MASK		(1 << CS42L42_MCLKDIV_SHIFT)
+#define CS42L42_MCLK_SRC_SEL_SHIFT	0
+#define CS42L42_MCLK_SRC_SEL_MASK	(1 << CS42L42_MCLK_SRC_SEL_SHIFT)
+
+#define CS42L42_SPDIF_CLK_CFG		(CS42L42_PAGE_12 + 0x02)
+#define CS42L42_FSYNC_PW_LOWER		(CS42L42_PAGE_12 + 0x03)
+
+#define CS42L42_FSYNC_PW_UPPER			(CS42L42_PAGE_12 + 0x04)
+#define CS42L42_FSYNC_PULSE_WIDTH_SHIFT		0
+#define CS42L42_FSYNC_PULSE_WIDTH_MASK		(0xff << \
+					CS42L42_FSYNC_PULSE_WIDTH_SHIFT)
+
+#define CS42L42_FSYNC_P_LOWER		(CS42L42_PAGE_12 + 0x05)
+
+#define CS42L42_FSYNC_P_UPPER		(CS42L42_PAGE_12 + 0x06)
+#define CS42L42_FSYNC_PERIOD_SHIFT	0
+#define CS42L42_FSYNC_PERIOD_MASK	(0xff << CS42L42_FSYNC_PERIOD_SHIFT)
+
+#define CS42L42_ASP_CLK_CFG		(CS42L42_PAGE_12 + 0x07)
+#define CS42L42_ASP_SCLK_EN_SHIFT	5
+#define CS42L42_ASP_SCLK_EN_MASK	(1 << CS42L42_ASP_SCLK_EN_SHIFT)
+#define CS42L42_ASP_MASTER_MODE		0x01
+#define CS42L42_ASP_SLAVE_MODE		0x00
+#define CS42L42_ASP_MODE_SHIFT		4
+#define CS42L42_ASP_MODE_MASK		(1 << CS42L42_ASP_MODE_SHIFT)
+#define CS42L42_ASP_SCPOL_IN_DAC_SHIFT	2
+#define CS42L42_ASP_SCPOL_IN_DAC_MASK	(1 << CS42L42_ASP_SCPOL_IN_DAC_SHIFT)
+#define CS42L42_ASP_LCPOL_IN_SHIFT	0
+#define CS42L42_ASP_LCPOL_IN_MASK	(1 << CS42L42_ASP_LCPOL_IN_SHIFT)
+#define CS42L42_ASP_POL_INV		1
+
+#define CS42L42_ASP_FRM_CFG		(CS42L42_PAGE_12 + 0x08)
+#define CS42L42_ASP_STP_SHIFT		4
+#define CS42L42_ASP_STP_MASK		(1 << CS42L42_ASP_STP_SHIFT)
+#define CS42L42_ASP_5050_SHIFT		3
+#define CS42L42_ASP_5050_MASK		(1 << CS42L42_ASP_5050_SHIFT)
+#define CS42L42_ASP_FSD_SHIFT		0
+#define CS42L42_ASP_FSD_MASK		(7 << CS42L42_ASP_FSD_SHIFT)
+#define CS42L42_ASP_FSD_0_5		1
+#define CS42L42_ASP_FSD_1_0		2
+#define CS42L42_ASP_FSD_1_5		3
+#define CS42L42_ASP_FSD_2_0		4
+
+#define CS42L42_FS_RATE_EN		(CS42L42_PAGE_12 + 0x09)
+#define CS42L42_FS_EN_SHIFT		0
+#define CS42L42_FS_EN_MASK		(0xf << CS42L42_FS_EN_SHIFT)
+#define CS42L42_FS_EN_IASRC_96K		0x1
+#define CS42L42_FS_EN_OASRC_96K		0x2
+
+#define CS42L42_IN_ASRC_CLK		(CS42L42_PAGE_12 + 0x0A)
+#define CS42L42_CLK_IASRC_SEL_SHIFT	0
+#define CS42L42_CLK_IASRC_SEL_MASK	(1 << CS42L42_CLK_IASRC_SEL_SHIFT)
+#define CS42L42_CLK_IASRC_SEL_12	1
+
+#define CS42L42_OUT_ASRC_CLK		(CS42L42_PAGE_12 + 0x0B)
+#define CS42L42_CLK_OASRC_SEL_SHIFT	0
+#define CS42L42_CLK_OASRC_SEL_MASK	(1 << CS42L42_CLK_OASRC_SEL_SHIFT)
+#define CS42L42_CLK_OASRC_SEL_12	1
+
+#define CS42L42_PLL_DIV_CFG1		(CS42L42_PAGE_12 + 0x0C)
+#define CS42L42_SCLK_PREDIV_SHIFT	0
+#define CS42L42_SCLK_PREDIV_MASK	(3 << CS42L42_SCLK_PREDIV_SHIFT)
+
+/* Page 0x13 Interrupt Registers */
+/* Interrupts */
+#define CS42L42_ADC_OVFL_STATUS		(CS42L42_PAGE_13 + 0x01)
+#define CS42L42_MIXER_STATUS		(CS42L42_PAGE_13 + 0x02)
+#define CS42L42_SRC_STATUS		(CS42L42_PAGE_13 + 0x03)
+#define CS42L42_ASP_RX_STATUS		(CS42L42_PAGE_13 + 0x04)
+#define CS42L42_ASP_TX_STATUS		(CS42L42_PAGE_13 + 0x05)
+#define CS42L42_CODEC_STATUS		(CS42L42_PAGE_13 + 0x08)
+#define CS42L42_DET_INT_STATUS1		(CS42L42_PAGE_13 + 0x09)
+#define CS42L42_DET_INT_STATUS2		(CS42L42_PAGE_13 + 0x0A)
+#define CS42L42_SRCPL_INT_STATUS	(CS42L42_PAGE_13 + 0x0B)
+#define CS42L42_VPMON_STATUS		(CS42L42_PAGE_13 + 0x0D)
+#define CS42L42_PLL_LOCK_STATUS		(CS42L42_PAGE_13 + 0x0E)
+#define CS42L42_TSRS_PLUG_STATUS	(CS42L42_PAGE_13 + 0x0F)
+/* Masks */
+#define CS42L42_ADC_OVFL_INT_MASK	(CS42L42_PAGE_13 + 0x16)
+#define CS42L42_ADC_OVFL_SHIFT		0
+#define CS42L42_ADC_OVFL_MASK		(1 << CS42L42_ADC_OVFL_SHIFT)
+#define CS42L42_ADC_OVFL_VAL_MASK	CS42L42_ADC_OVFL_MASK
+
+#define CS42L42_MIXER_INT_MASK		(CS42L42_PAGE_13 + 0x17)
+#define CS42L42_MIX_CHB_OVFL_SHIFT	0
+#define CS42L42_MIX_CHB_OVFL_MASK	(1 << CS42L42_MIX_CHB_OVFL_SHIFT)
+#define CS42L42_MIX_CHA_OVFL_SHIFT	1
+#define CS42L42_MIX_CHA_OVFL_MASK	(1 << CS42L42_MIX_CHA_OVFL_SHIFT)
+#define CS42L42_EQ_OVFL_SHIFT		2
+#define CS42L42_EQ_OVFL_MASK		(1 << CS42L42_EQ_OVFL_SHIFT)
+#define CS42L42_EQ_BIQUAD_OVFL_SHIFT	3
+#define CS42L42_EQ_BIQUAD_OVFL_MASK	(1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT)
+#define CS42L42_MIXER_VAL_MASK		(CS42L42_MIX_CHB_OVFL_MASK | \
+					CS42L42_MIX_CHA_OVFL_MASK | \
+					CS42L42_EQ_OVFL_MASK | \
+					CS42L42_EQ_BIQUAD_OVFL_MASK)
+
+#define CS42L42_SRC_INT_MASK		(CS42L42_PAGE_13 + 0x18)
+#define CS42L42_SRC_ILK_SHIFT		0
+#define CS42L42_SRC_ILK_MASK		(1 << CS42L42_SRC_ILK_SHIFT)
+#define CS42L42_SRC_OLK_SHIFT		1
+#define CS42L42_SRC_OLK_MASK		(1 << CS42L42_SRC_OLK_SHIFT)
+#define CS42L42_SRC_IUNLK_SHIFT		2
+#define CS42L42_SRC_IUNLK_MASK		(1 << CS42L42_SRC_IUNLK_SHIFT)
+#define CS42L42_SRC_OUNLK_SHIFT		3
+#define CS42L42_SRC_OUNLK_MASK		(1 << CS42L42_SRC_OUNLK_SHIFT)
+#define CS42L42_SRC_VAL_MASK		(CS42L42_SRC_ILK_MASK | \
+					CS42L42_SRC_OLK_MASK | \
+					CS42L42_SRC_IUNLK_MASK | \
+					CS42L42_SRC_OUNLK_MASK)
+
+#define CS42L42_ASP_RX_INT_MASK		(CS42L42_PAGE_13 + 0x19)
+#define CS42L42_ASPRX_NOLRCK_SHIFT	0
+#define CS42L42_ASPRX_NOLRCK_MASK	(1 << CS42L42_ASPRX_NOLRCK_SHIFT)
+#define CS42L42_ASPRX_EARLY_SHIFT	1
+#define CS42L42_ASPRX_EARLY_MASK	(1 << CS42L42_ASPRX_EARLY_SHIFT)
+#define CS42L42_ASPRX_LATE_SHIFT	2
+#define CS42L42_ASPRX_LATE_MASK		(1 << CS42L42_ASPRX_LATE_SHIFT)
+#define CS42L42_ASPRX_ERROR_SHIFT	3
+#define CS42L42_ASPRX_ERROR_MASK	(1 << CS42L42_ASPRX_ERROR_SHIFT)
+#define CS42L42_ASPRX_OVLD_SHIFT	4
+#define CS42L42_ASPRX_OVLD_MASK		(1 << CS42L42_ASPRX_OVLD_SHIFT)
+#define CS42L42_ASP_RX_VAL_MASK		(CS42L42_ASPRX_NOLRCK_MASK | \
+					CS42L42_ASPRX_EARLY_MASK | \
+					CS42L42_ASPRX_LATE_MASK | \
+					CS42L42_ASPRX_ERROR_MASK | \
+					CS42L42_ASPRX_OVLD_MASK)
+
+#define CS42L42_ASP_TX_INT_MASK		(CS42L42_PAGE_13 + 0x1A)
+#define CS42L42_ASPTX_NOLRCK_SHIFT	0
+#define CS42L42_ASPTX_NOLRCK_MASK	(1 << CS42L42_ASPTX_NOLRCK_SHIFT)
+#define CS42L42_ASPTX_EARLY_SHIFT	1
+#define CS42L42_ASPTX_EARLY_MASK	(1 << CS42L42_ASPTX_EARLY_SHIFT)
+#define CS42L42_ASPTX_LATE_SHIFT	2
+#define CS42L42_ASPTX_LATE_MASK		(1 << CS42L42_ASPTX_LATE_SHIFT)
+#define CS42L42_ASPTX_SMERROR_SHIFT	3
+#define CS42L42_ASPTX_SMERROR_MASK	(1 << CS42L42_ASPTX_SMERROR_SHIFT)
+#define CS42L42_ASP_TX_VAL_MASK		(CS42L42_ASPTX_NOLRCK_MASK | \
+					CS42L42_ASPTX_EARLY_MASK | \
+					CS42L42_ASPTX_LATE_MASK | \
+					CS42L42_ASPTX_SMERROR_MASK)
+
+#define CS42L42_CODEC_INT_MASK		(CS42L42_PAGE_13 + 0x1B)
+#define CS42L42_PDN_DONE_SHIFT		0
+#define CS42L42_PDN_DONE_MASK		(1 << CS42L42_PDN_DONE_SHIFT)
+#define CS42L42_HSDET_AUTO_DONE_SHIFT	1
+#define CS42L42_HSDET_AUTO_DONE_MASK	(1 << CS42L42_HSDET_AUTO_DONE_SHIFT)
+#define CS42L42_CODEC_VAL_MASK		(CS42L42_PDN_DONE_MASK | \
+					CS42L42_HSDET_AUTO_DONE_MASK)
+
+#define CS42L42_SRCPL_INT_MASK		(CS42L42_PAGE_13 + 0x1C)
+#define CS42L42_SRCPL_ADC_LK_SHIFT	0
+#define CS42L42_SRCPL_ADC_LK_MASK	(1 << CS42L42_SRCPL_ADC_LK_SHIFT)
+#define CS42L42_SRCPL_DAC_LK_SHIFT	2
+#define CS42L42_SRCPL_DAC_LK_MASK	(1 << CS42L42_SRCPL_DAC_LK_SHIFT)
+#define CS42L42_SRCPL_ADC_UNLK_SHIFT	5
+#define CS42L42_SRCPL_ADC_UNLK_MASK	(1 << CS42L42_SRCPL_ADC_UNLK_SHIFT)
+#define CS42L42_SRCPL_DAC_UNLK_SHIFT	6
+#define CS42L42_SRCPL_DAC_UNLK_MASK	(1 << CS42L42_SRCPL_DAC_UNLK_SHIFT)
+#define CS42L42_SRCPL_VAL_MASK		(CS42L42_SRCPL_ADC_LK_MASK | \
+					CS42L42_SRCPL_DAC_LK_MASK | \
+					CS42L42_SRCPL_ADC_UNLK_MASK | \
+					CS42L42_SRCPL_DAC_UNLK_MASK)
+
+#define CS42L42_VPMON_INT_MASK		(CS42L42_PAGE_13 + 0x1E)
+#define CS42L42_VPMON_SHIFT		0
+#define CS42L42_VPMON_MASK		(1 << CS42L42_VPMON_SHIFT)
+#define CS42L42_VPMON_VAL_MASK		CS42L42_VPMON_MASK
+
+#define CS42L42_PLL_LOCK_INT_MASK	(CS42L42_PAGE_13 + 0x1F)
+#define CS42L42_PLL_LOCK_SHIFT		0
+#define CS42L42_PLL_LOCK_MASK		(1 << CS42L42_PLL_LOCK_SHIFT)
+#define CS42L42_PLL_LOCK_VAL_MASK	CS42L42_PLL_LOCK_MASK
+
+#define CS42L42_TSRS_PLUG_INT_MASK	(CS42L42_PAGE_13 + 0x20)
+#define CS42L42_RS_PLUG_SHIFT		0
+#define CS42L42_RS_PLUG_MASK		(1 << CS42L42_RS_PLUG_SHIFT)
+#define CS42L42_RS_UNPLUG_SHIFT		1
+#define CS42L42_RS_UNPLUG_MASK		(1 << CS42L42_RS_UNPLUG_SHIFT)
+#define CS42L42_TS_PLUG_SHIFT		2
+#define CS42L42_TS_PLUG_MASK		(1 << CS42L42_TS_PLUG_SHIFT)
+#define CS42L42_TS_UNPLUG_SHIFT		3
+#define CS42L42_TS_UNPLUG_MASK		(1 << CS42L42_TS_UNPLUG_SHIFT)
+#define CS42L42_TSRS_PLUG_VAL_MASK	(CS42L42_RS_PLUG_MASK | \
+					CS42L42_RS_UNPLUG_MASK | \
+					CS42L42_TS_PLUG_MASK | \
+					CS42L42_TS_UNPLUG_MASK)
+#define CS42L42_TS_PLUG			3
+#define CS42L42_TS_UNPLUG		0
+#define CS42L42_TS_TRANS		1
+
+/* Page 0x15 Fractional-N PLL Registers */
+#define CS42L42_PLL_CTL1		(CS42L42_PAGE_15 + 0x01)
+#define CS42L42_PLL_START_SHIFT		0
+#define CS42L42_PLL_START_MASK		(1 << CS42L42_PLL_START_SHIFT)
+
+#define CS42L42_PLL_DIV_FRAC0		(CS42L42_PAGE_15 + 0x02)
+#define CS42L42_PLL_DIV_FRAC_SHIFT	0
+#define CS42L42_PLL_DIV_FRAC_MASK	(0xff << CS42L42_PLL_DIV_FRAC_SHIFT)
+
+#define CS42L42_PLL_DIV_FRAC1		(CS42L42_PAGE_15 + 0x03)
+#define CS42L42_PLL_DIV_FRAC2		(CS42L42_PAGE_15 + 0x04)
+
+#define CS42L42_PLL_DIV_INT		(CS42L42_PAGE_15 + 0x05)
+#define CS42L42_PLL_DIV_INT_SHIFT	0
+#define CS42L42_PLL_DIV_INT_MASK	(0xff << CS42L42_PLL_DIV_INT_SHIFT)
+
+#define CS42L42_PLL_CTL3		(CS42L42_PAGE_15 + 0x08)
+#define CS42L42_PLL_DIVOUT_SHIFT	0
+#define CS42L42_PLL_DIVOUT_MASK		(0xff << CS42L42_PLL_DIVOUT_SHIFT)
+
+#define CS42L42_PLL_CAL_RATIO		(CS42L42_PAGE_15 + 0x0A)
+#define CS42L42_PLL_CAL_RATIO_SHIFT	0
+#define CS42L42_PLL_CAL_RATIO_MASK	(0xff << CS42L42_PLL_CAL_RATIO_SHIFT)
+
+#define CS42L42_PLL_CTL4		(CS42L42_PAGE_15 + 0x1B)
+#define CS42L42_PLL_MODE_SHIFT		0
+#define CS42L42_PLL_MODE_MASK		(3 << CS42L42_PLL_MODE_SHIFT)
+
+/* Page 0x19 HP Load Detect Registers */
+#define CS42L42_LOAD_DET_RCSTAT		(CS42L42_PAGE_19 + 0x25)
+#define CS42L42_RLA_STAT_SHIFT		0
+#define CS42L42_RLA_STAT_MASK		(3 << CS42L42_RLA_STAT_SHIFT)
+#define CS42L42_RLA_STAT_15_OHM		0
+
+#define CS42L42_LOAD_DET_DONE		(CS42L42_PAGE_19 + 0x26)
+#define CS42L42_HPLOAD_DET_DONE_SHIFT	0
+#define CS42L42_HPLOAD_DET_DONE_MASK	(1 << CS42L42_HPLOAD_DET_DONE_SHIFT)
+
+#define CS42L42_LOAD_DET_EN		(CS42L42_PAGE_19 + 0x27)
+#define CS42L42_HP_LD_EN_SHIFT		0
+#define CS42L42_HP_LD_EN_MASK		(1 << CS42L42_HP_LD_EN_SHIFT)
+
+/* Page 0x1B Headset Interface Registers */
+#define CS42L42_HSBIAS_SC_AUTOCTL		(CS42L42_PAGE_1B + 0x70)
+#define CS42L42_HSBIAS_SENSE_TRIP_SHIFT		0
+#define CS42L42_HSBIAS_SENSE_TRIP_MASK		(7 << \
+					CS42L42_HSBIAS_SENSE_TRIP_SHIFT)
+#define CS42L42_TIP_SENSE_EN_SHIFT		5
+#define CS42L42_TIP_SENSE_EN_MASK		(1 << \
+					CS42L42_TIP_SENSE_EN_SHIFT)
+#define CS42L42_AUTO_HSBIAS_HIZ_SHIFT		6
+#define CS42L42_AUTO_HSBIAS_HIZ_MASK		(1 << \
+					CS42L42_AUTO_HSBIAS_HIZ_SHIFT)
+#define CS42L42_HSBIAS_SENSE_EN_SHIFT		7
+#define CS42L42_HSBIAS_SENSE_EN_MASK		(1 << \
+					CS42L42_HSBIAS_SENSE_EN_SHIFT)
+
+#define CS42L42_WAKE_CTL		(CS42L42_PAGE_1B + 0x71)
+#define CS42L42_WAKEB_CLEAR_SHIFT	0
+#define CS42L42_WAKEB_CLEAR_MASK	(1 << CS42L42_WAKEB_CLEAR_SHIFT)
+#define CS42L42_WAKEB_MODE_SHIFT	5
+#define CS42L42_WAKEB_MODE_MASK		(1 << CS42L42_WAKEB_MODE_SHIFT)
+#define CS42L42_M_HP_WAKE_SHIFT		6
+#define CS42L42_M_HP_WAKE_MASK		(1 << CS42L42_M_HP_WAKE_SHIFT)
+#define CS42L42_M_MIC_WAKE_SHIFT	7
+#define CS42L42_M_MIC_WAKE_MASK		(1 << CS42L42_M_MIC_WAKE_SHIFT)
+
+#define CS42L42_ADC_DISABLE_MUTE		(CS42L42_PAGE_1B + 0x72)
+#define CS42L42_ADC_DISABLE_S0_MUTE_SHIFT	7
+#define CS42L42_ADC_DISABLE_S0_MUTE_MASK	(1 << \
+					CS42L42_ADC_DISABLE_S0_MUTE_SHIFT)
+
+#define CS42L42_TIPSENSE_CTL			(CS42L42_PAGE_1B + 0x73)
+#define CS42L42_TIP_SENSE_DEBOUNCE_SHIFT	0
+#define CS42L42_TIP_SENSE_DEBOUNCE_MASK		(3 << \
+					CS42L42_TIP_SENSE_DEBOUNCE_SHIFT)
+#define CS42L42_TIP_SENSE_INV_SHIFT		5
+#define CS42L42_TIP_SENSE_INV_MASK		(1 << \
+					CS42L42_TIP_SENSE_INV_SHIFT)
+#define CS42L42_TIP_SENSE_CTRL_SHIFT		6
+#define CS42L42_TIP_SENSE_CTRL_MASK		(3 << \
+					CS42L42_TIP_SENSE_CTRL_SHIFT)
+
+#define CS42L42_MISC_DET_CTL		(CS42L42_PAGE_1B + 0x74)
+#define CS42L42_PDN_MIC_LVL_DET_SHIFT	0
+#define CS42L42_PDN_MIC_LVL_DET_MASK	(1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)
+#define CS42L42_HSBIAS_CTL_SHIFT	1
+#define CS42L42_HSBIAS_CTL_MASK		(3 << CS42L42_HSBIAS_CTL_SHIFT)
+#define CS42L42_DETECT_MODE_SHIFT	3
+#define CS42L42_DETECT_MODE_MASK	(3 << CS42L42_DETECT_MODE_SHIFT)
+
+#define CS42L42_MIC_DET_CTL1		(CS42L42_PAGE_1B + 0x75)
+#define CS42L42_HS_DET_LEVEL_SHIFT	0
+#define CS42L42_HS_DET_LEVEL_MASK	(0x3F << CS42L42_HS_DET_LEVEL_SHIFT)
+#define CS42L42_EVENT_STAT_SEL_SHIFT	6
+#define CS42L42_EVENT_STAT_SEL_MASK	(1 << CS42L42_EVENT_STAT_SEL_SHIFT)
+#define CS42L42_LATCH_TO_VP_SHIFT	7
+#define CS42L42_LATCH_TO_VP_MASK	(1 << CS42L42_LATCH_TO_VP_SHIFT)
+
+#define CS42L42_MIC_DET_CTL2		(CS42L42_PAGE_1B + 0x76)
+#define CS42L42_DEBOUNCE_TIME_SHIFT	5
+#define CS42L42_DEBOUNCE_TIME_MASK	(0x07 << CS42L42_DEBOUNCE_TIME_SHIFT)
+
+#define CS42L42_DET_STATUS1		(CS42L42_PAGE_1B + 0x77)
+#define CS42L42_HSBIAS_HIZ_MODE_SHIFT	6
+#define CS42L42_HSBIAS_HIZ_MODE_MASK	(1 << CS42L42_HSBIAS_HIZ_MODE_SHIFT)
+#define CS42L42_TIP_SENSE_SHIFT		7
+#define CS42L42_TIP_SENSE_MASK		(1 << CS42L42_TIP_SENSE_SHIFT)
+
+#define CS42L42_DET_STATUS2		(CS42L42_PAGE_1B + 0x78)
+#define CS42L42_SHORT_TRUE_SHIFT	0
+#define CS42L42_SHORT_TRUE_MASK		(1 << CS42L42_SHORT_TRUE_SHIFT)
+#define CS42L42_HS_TRUE_SHIFT	1
+#define CS42L42_HS_TRUE_MASK		(1 << CS42L42_HS_TRUE_SHIFT)
+
+#define CS42L42_DET_INT1_MASK		(CS42L42_PAGE_1B + 0x79)
+#define CS42L42_TIP_SENSE_UNPLUG_SHIFT	5
+#define CS42L42_TIP_SENSE_UNPLUG_MASK	(1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT)
+#define CS42L42_TIP_SENSE_PLUG_SHIFT	6
+#define CS42L42_TIP_SENSE_PLUG_MASK	(1 << CS42L42_TIP_SENSE_PLUG_SHIFT)
+#define CS42L42_HSBIAS_SENSE_SHIFT	7
+#define CS42L42_HSBIAS_SENSE_MASK	(1 << CS42L42_HSBIAS_SENSE_SHIFT)
+#define CS42L42_DET_INT_VAL1_MASK	(CS42L42_TIP_SENSE_UNPLUG_MASK | \
+					CS42L42_TIP_SENSE_PLUG_MASK | \
+					CS42L42_HSBIAS_SENSE_MASK)
+
+#define CS42L42_DET_INT2_MASK		(CS42L42_PAGE_1B + 0x7A)
+#define CS42L42_M_SHORT_DET_SHIFT	0
+#define CS42L42_M_SHORT_DET_MASK	(1 << \
+					CS42L42_M_SHORT_DET_SHIFT)
+#define CS42L42_M_SHORT_RLS_SHIFT	1
+#define CS42L42_M_SHORT_RLS_MASK	(1 << \
+					CS42L42_M_SHORT_RLS_SHIFT)
+#define CS42L42_M_HSBIAS_HIZ_SHIFT	2
+#define CS42L42_M_HSBIAS_HIZ_MASK	(1 << \
+					CS42L42_M_HSBIAS_HIZ_SHIFT)
+#define CS42L42_M_DETECT_FT_SHIFT	6
+#define CS42L42_M_DETECT_FT_MASK	(1 << \
+					CS42L42_M_DETECT_FT_SHIFT)
+#define CS42L42_M_DETECT_TF_SHIFT	7
+#define CS42L42_M_DETECT_TF_MASK	(1 << \
+					CS42L42_M_DETECT_TF_SHIFT)
+#define CS42L42_DET_INT_VAL2_MASK	(CS42L42_M_SHORT_DET_MASK | \
+					CS42L42_M_SHORT_RLS_MASK | \
+					CS42L42_M_HSBIAS_HIZ_MASK | \
+					CS42L42_M_DETECT_FT_MASK | \
+					CS42L42_M_DETECT_TF_MASK)
+
+/* Page 0x1C Headset Bias Registers */
+#define CS42L42_HS_BIAS_CTL		(CS42L42_PAGE_1C + 0x03)
+#define CS42L42_HSBIAS_RAMP_SHIFT	0
+#define CS42L42_HSBIAS_RAMP_MASK	(3 << CS42L42_HSBIAS_RAMP_SHIFT)
+#define CS42L42_HSBIAS_PD_SHIFT		4
+#define CS42L42_HSBIAS_PD_MASK		(1 << CS42L42_HSBIAS_PD_SHIFT)
+#define CS42L42_HSBIAS_CAPLESS_SHIFT	7
+#define CS42L42_HSBIAS_CAPLESS_MASK	(1 << CS42L42_HSBIAS_CAPLESS_SHIFT)
+
+/* Page 0x1D ADC Registers */
+#define CS42L42_ADC_CTL			(CS42L42_PAGE_1D + 0x01)
+#define CS42L42_ADC_NOTCH_DIS_SHIFT		5
+#define CS42L42_ADC_FORCE_WEAK_VCM_SHIFT	4
+#define CS42L42_ADC_INV_SHIFT			2
+#define CS42L42_ADC_DIG_BOOST_SHIFT		0
+
+#define CS42L42_ADC_VOLUME		(CS42L42_PAGE_1D + 0x03)
+#define CS42L42_ADC_VOL_SHIFT		0
+
+#define CS42L42_ADC_WNF_HPF_CTL		(CS42L42_PAGE_1D + 0x04)
+#define CS42L42_ADC_WNF_CF_SHIFT	4
+#define CS42L42_ADC_WNF_EN_SHIFT	3
+#define CS42L42_ADC_HPF_CF_SHIFT	1
+#define CS42L42_ADC_HPF_EN_SHIFT	0
+
+/* Page 0x1F DAC Registers */
+#define CS42L42_DAC_CTL1		(CS42L42_PAGE_1F + 0x01)
+#define CS42L42_DACB_INV_SHIFT		1
+#define CS42L42_DACA_INV_SHIFT		0
+
+#define CS42L42_DAC_CTL2		(CS42L42_PAGE_1F + 0x06)
+#define CS42L42_HPOUT_PULLDOWN_SHIFT	4
+#define CS42L42_HPOUT_PULLDOWN_MASK	(15 << CS42L42_HPOUT_PULLDOWN_SHIFT)
+#define CS42L42_HPOUT_LOAD_SHIFT	3
+#define CS42L42_HPOUT_LOAD_MASK		(1 << CS42L42_HPOUT_LOAD_SHIFT)
+#define CS42L42_HPOUT_CLAMP_SHIFT	2
+#define CS42L42_HPOUT_CLAMP_MASK	(1 << CS42L42_HPOUT_CLAMP_SHIFT)
+#define CS42L42_DAC_HPF_EN_SHIFT	1
+#define CS42L42_DAC_HPF_EN_MASK		(1 << CS42L42_DAC_HPF_EN_SHIFT)
+#define CS42L42_DAC_MON_EN_SHIFT	0
+#define CS42L42_DAC_MON_EN_MASK		(1 << CS42L42_DAC_MON_EN_SHIFT)
+
+/* Page 0x20 HP CTL Registers */
+#define CS42L42_HP_CTL			(CS42L42_PAGE_20 + 0x01)
+#define CS42L42_HP_ANA_BMUTE_SHIFT	3
+#define CS42L42_HP_ANA_BMUTE_MASK	(1 << CS42L42_HP_ANA_BMUTE_SHIFT)
+#define CS42L42_HP_ANA_AMUTE_SHIFT	2
+#define CS42L42_HP_ANA_AMUTE_MASK	(1 << CS42L42_HP_ANA_AMUTE_SHIFT)
+#define CS42L42_HP_FULL_SCALE_VOL_SHIFT	1
+#define CS42L42_HP_FULL_SCALE_VOL_MASK	(1 << CS42L42_HP_FULL_SCALE_VOL_SHIFT)
+
+/* Page 0x21 Class H Registers */
+#define CS42L42_CLASSH_CTL		(CS42L42_PAGE_21 + 0x01)
+
+/* Page 0x23 Mixer Volume Registers */
+#define CS42L42_MIXER_CHA_VOL		(CS42L42_PAGE_23 + 0x01)
+#define CS42L42_MIXER_ADC_VOL		(CS42L42_PAGE_23 + 0x02)
+
+#define CS42L42_MIXER_CHB_VOL		(CS42L42_PAGE_23 + 0x03)
+#define CS42L42_MIXER_CH_VOL_SHIFT	0
+#define CS42L42_MIXER_CH_VOL_MASK	(0x3f << CS42L42_MIXER_CH_VOL_SHIFT)
+
+/* Page 0x24 EQ Registers */
+#define CS42L42_EQ_COEF_IN0		(CS42L42_PAGE_24 + 0x01)
+#define CS42L42_EQ_COEF_IN1		(CS42L42_PAGE_24 + 0x02)
+#define CS42L42_EQ_COEF_IN2		(CS42L42_PAGE_24 + 0x03)
+#define CS42L42_EQ_COEF_IN3		(CS42L42_PAGE_24 + 0x04)
+#define CS42L42_EQ_COEF_RW		(CS42L42_PAGE_24 + 0x06)
+#define CS42L42_EQ_COEF_OUT0		(CS42L42_PAGE_24 + 0x07)
+#define CS42L42_EQ_COEF_OUT1		(CS42L42_PAGE_24 + 0x08)
+#define CS42L42_EQ_COEF_OUT2		(CS42L42_PAGE_24 + 0x09)
+#define CS42L42_EQ_COEF_OUT3		(CS42L42_PAGE_24 + 0x0A)
+#define CS42L42_EQ_INIT_STAT		(CS42L42_PAGE_24 + 0x0B)
+#define CS42L42_EQ_START_FILT		(CS42L42_PAGE_24 + 0x0C)
+#define CS42L42_EQ_MUTE_CTL		(CS42L42_PAGE_24 + 0x0E)
+
+/* Page 0x25 Audio Port Registers */
+#define CS42L42_SP_RX_CH_SEL		(CS42L42_PAGE_25 + 0x01)
+
+#define CS42L42_SP_RX_ISOC_CTL		(CS42L42_PAGE_25 + 0x02)
+#define CS42L42_SP_RX_RSYNC_SHIFT	6
+#define CS42L42_SP_RX_RSYNC_MASK	(1 << CS42L42_SP_RX_RSYNC_SHIFT)
+#define CS42L42_SP_RX_NSB_POS_SHIFT	3
+#define CS42L42_SP_RX_NSB_POS_MASK	(7 << CS42L42_SP_RX_NSB_POS_SHIFT)
+#define CS42L42_SP_RX_NFS_NSBB_SHIFT	2
+#define CS42L42_SP_RX_NFS_NSBB_MASK	(1 << CS42L42_SP_RX_NFS_NSBB_SHIFT)
+#define CS42L42_SP_RX_ISOC_MODE_SHIFT	0
+#define CS42L42_SP_RX_ISOC_MODE_MASK	(3 << CS42L42_SP_RX_ISOC_MODE_SHIFT)
+
+#define CS42L42_SP_RX_FS		(CS42L42_PAGE_25 + 0x03)
+#define CS42l42_SPDIF_CH_SEL		(CS42L42_PAGE_25 + 0x04)
+#define CS42L42_SP_TX_ISOC_CTL		(CS42L42_PAGE_25 + 0x05)
+#define CS42L42_SP_TX_FS		(CS42L42_PAGE_25 + 0x06)
+#define CS42L42_SPDIF_SW_CTL1		(CS42L42_PAGE_25 + 0x07)
+
+/* Page 0x26 SRC Registers */
+#define CS42L42_SRC_SDIN_FS		(CS42L42_PAGE_26 + 0x01)
+#define CS42L42_SRC_SDIN_FS_SHIFT	0
+#define CS42L42_SRC_SDIN_FS_MASK	(0x1f << CS42L42_SRC_SDIN_FS_SHIFT)
+
+#define CS42L42_SRC_SDOUT_FS		(CS42L42_PAGE_26 + 0x09)
+
+/* Page 0x28 S/PDIF Registers */
+#define CS42L42_SPDIF_CTL1		(CS42L42_PAGE_28 + 0x01)
+#define CS42L42_SPDIF_CTL2		(CS42L42_PAGE_28 + 0x02)
+#define CS42L42_SPDIF_CTL3		(CS42L42_PAGE_28 + 0x03)
+#define CS42L42_SPDIF_CTL4		(CS42L42_PAGE_28 + 0x04)
+
+/* Page 0x29 Serial Port TX Registers */
+#define CS42L42_ASP_TX_SZ_EN		(CS42L42_PAGE_29 + 0x01)
+#define CS42L42_ASP_TX_CH_EN		(CS42L42_PAGE_29 + 0x02)
+#define CS42L42_ASP_TX_CH_AP_RES	(CS42L42_PAGE_29 + 0x03)
+#define CS42L42_ASP_TX_CH1_BIT_MSB	(CS42L42_PAGE_29 + 0x04)
+#define CS42L42_ASP_TX_CH1_BIT_LSB	(CS42L42_PAGE_29 + 0x05)
+#define CS42L42_ASP_TX_HIZ_DLY_CFG	(CS42L42_PAGE_29 + 0x06)
+#define CS42L42_ASP_TX_CH2_BIT_MSB	(CS42L42_PAGE_29 + 0x0A)
+#define CS42L42_ASP_TX_CH2_BIT_LSB	(CS42L42_PAGE_29 + 0x0B)
+
+/* Page 0x2A Serial Port RX Registers */
+#define CS42L42_ASP_RX_DAI0_EN		(CS42L42_PAGE_2A + 0x01)
+#define CS42L42_ASP_RX0_CH_EN_SHIFT	2
+#define CS42L42_ASP_RX0_CH_EN_MASK	(0xf << CS42L42_ASP_RX0_CH_EN_SHIFT)
+#define CS42L42_ASP_RX0_CH1_EN		1
+#define CS42L42_ASP_RX0_CH2_EN		2
+#define CS42L42_ASP_RX0_CH3_EN		4
+#define CS42L42_ASP_RX0_CH4_EN		8
+
+#define CS42L42_ASP_RX_DAI0_CH1_AP_RES	(CS42L42_PAGE_2A + 0x02)
+#define CS42L42_ASP_RX_DAI0_CH1_BIT_MSB	(CS42L42_PAGE_2A + 0x03)
+#define CS42L42_ASP_RX_DAI0_CH1_BIT_LSB	(CS42L42_PAGE_2A + 0x04)
+#define CS42L42_ASP_RX_DAI0_CH2_AP_RES	(CS42L42_PAGE_2A + 0x05)
+#define CS42L42_ASP_RX_DAI0_CH2_BIT_MSB	(CS42L42_PAGE_2A + 0x06)
+#define CS42L42_ASP_RX_DAI0_CH2_BIT_LSB	(CS42L42_PAGE_2A + 0x07)
+#define CS42L42_ASP_RX_DAI0_CH3_AP_RES	(CS42L42_PAGE_2A + 0x08)
+#define CS42L42_ASP_RX_DAI0_CH3_BIT_MSB	(CS42L42_PAGE_2A + 0x09)
+#define CS42L42_ASP_RX_DAI0_CH3_BIT_LSB	(CS42L42_PAGE_2A + 0x0A)
+#define CS42L42_ASP_RX_DAI0_CH4_AP_RES	(CS42L42_PAGE_2A + 0x0B)
+#define CS42L42_ASP_RX_DAI0_CH4_BIT_MSB	(CS42L42_PAGE_2A + 0x0C)
+#define CS42L42_ASP_RX_DAI0_CH4_BIT_LSB	(CS42L42_PAGE_2A + 0x0D)
+#define CS42L42_ASP_RX_DAI1_CH1_AP_RES	(CS42L42_PAGE_2A + 0x0E)
+#define CS42L42_ASP_RX_DAI1_CH1_BIT_MSB	(CS42L42_PAGE_2A + 0x0F)
+#define CS42L42_ASP_RX_DAI1_CH1_BIT_LSB	(CS42L42_PAGE_2A + 0x10)
+#define CS42L42_ASP_RX_DAI1_CH2_AP_RES	(CS42L42_PAGE_2A + 0x11)
+#define CS42L42_ASP_RX_DAI1_CH2_BIT_MSB	(CS42L42_PAGE_2A + 0x12)
+#define CS42L42_ASP_RX_DAI1_CH2_BIT_LSB	(CS42L42_PAGE_2A + 0x13)
+
+#define CS42L42_ASP_RX_CH_AP_SHIFT	6
+#define CS42L42_ASP_RX_CH_AP_MASK	(1 << CS42L42_ASP_RX_CH_AP_SHIFT)
+#define CS42L42_ASP_RX_CH_AP_LOW	0
+#define CS42L42_ASP_RX_CH_AP_HI		1
+#define CS42L42_ASP_RX_CH_RES_SHIFT	0
+#define CS42L42_ASP_RX_CH_RES_MASK	(3 << CS42L42_ASP_RX_CH_RES_SHIFT)
+#define CS42L42_ASP_RX_CH_RES_32	3
+#define CS42L42_ASP_RX_CH_RES_16	1
+#define CS42L42_ASP_RX_CH_BIT_ST_SHIFT	0
+#define CS42L42_ASP_RX_CH_BIT_ST_MASK	(0xff << CS42L42_ASP_RX_CH_BIT_ST_SHIFT)
+
+/* Page 0x30 ID Registers */
+#define CS42L42_SUB_REVID		(CS42L42_PAGE_30 + 0x14)
+#define CS42L42_MAX_REGISTER		(CS42L42_PAGE_30 + 0x14)
+
+/* Defines for fracturing values spread across multiple registers */
+#define CS42L42_FRAC0_VAL(val)	((val) & 0x0000ff)
+#define CS42L42_FRAC1_VAL(val)	(((val) & 0x00ff00) >> 8)
+#define CS42L42_FRAC2_VAL(val)	(((val) & 0xff0000) >> 16)
+
+#define CS42L42_NUM_SUPPLIES	5
+
+static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = {
+	"VA",
+	"VP",
+	"VCP",
+	"VD_FILT",
+	"VL",
+};
+
+struct  cs42l42_private {
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct regulator_bulk_data supplies[CS42L42_NUM_SUPPLIES];
+	struct gpio_desc *reset_gpio;
+	struct completion pdn_done;
+	u32 sclk;
+	u32 srate;
+	u32 swidth;
+	u8 plug_state;
+	u8 hs_type;
+	u8 ts_inv;
+	u8 ts_dbnc_rise;
+	u8 ts_dbnc_fall;
+	u8 btn_det_init_dbnce;
+	u8 btn_det_event_dbnce;
+	u8 bias_thresholds[CS42L42_NUM_BIASES];
+	u8 hs_bias_ramp_rate;
+	u8 hs_bias_ramp_time;
+};
+
+#endif /* __CS42L42_H__ */
diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c
new file mode 100644
index 0000000..4b5731a
--- /dev/null
+++ b/sound/soc/codecs/cs42l51-i2c.c
@@ -0,0 +1,51 @@
+/*
+ * cs42l56.c -- CS42L51 ALSA SoC I2C audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include "cs42l51.h"
+
+static struct i2c_device_id cs42l51_i2c_id[] = {
+	{"cs42l51", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id);
+
+static int cs42l51_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct regmap_config config;
+
+	config = cs42l51_regmap;
+	config.val_bits = 8;
+	config.reg_bits = 8;
+
+	return cs42l51_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &config));
+}
+
+static struct i2c_driver cs42l51_i2c_driver = {
+	.driver = {
+		.name = "cs42l51",
+		.of_match_table = cs42l51_of_match,
+	},
+	.probe = cs42l51_i2c_probe,
+	.id_table = cs42l51_i2c_id,
+};
+
+module_i2c_driver(cs42l51_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L51 I2C Driver");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
new file mode 100644
index 0000000..5080d7a
--- /dev/null
+++ b/sound/soc/codecs/cs42l51.c
@@ -0,0 +1,575 @@
+/*
+ * cs42l51.c
+ *
+ * ASoC Driver for Cirrus Logic CS42L51 codecs
+ *
+ * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * Based on cs4270.c - Copyright (c) Freescale Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * For now:
+ *  - Only I2C is support. Not SPI
+ *  - master mode *NOT* supported
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+#include <linux/regmap.h>
+
+#include "cs42l51.h"
+
+enum master_slave_mode {
+	MODE_SLAVE,
+	MODE_SLAVE_AUTO,
+	MODE_MASTER,
+};
+
+struct cs42l51_private {
+	unsigned int mclk;
+	unsigned int audio_mode;	/* The mode (I2S or left-justified) */
+	enum master_slave_mode func;
+};
+
+#define CS42L51_FORMATS ( \
+		SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
+		SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+		SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+		SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE)
+
+static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned long value = snd_soc_component_read32(component, CS42L51_PCM_MIXER)&3;
+
+	switch (value) {
+	default:
+	case 0:
+		ucontrol->value.enumerated.item[0] = 0;
+		break;
+	/* same value : (L+R)/2 and (R+L)/2 */
+	case 1:
+	case 2:
+		ucontrol->value.enumerated.item[0] = 1;
+		break;
+	case 3:
+		ucontrol->value.enumerated.item[0] = 2;
+		break;
+	}
+
+	return 0;
+}
+
+#define CHAN_MIX_NORMAL	0x00
+#define CHAN_MIX_BOTH	0x55
+#define CHAN_MIX_SWAP	0xFF
+
+static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned char val;
+
+	switch (ucontrol->value.enumerated.item[0]) {
+	default:
+	case 0:
+		val = CHAN_MIX_NORMAL;
+		break;
+	case 1:
+		val = CHAN_MIX_BOTH;
+		break;
+	case 2:
+		val = CHAN_MIX_SWAP;
+		break;
+	}
+
+	snd_soc_component_write(component, CS42L51_PCM_MIXER, val);
+
+	return 1;
+}
+
+static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);
+static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
+
+static const DECLARE_TLV_DB_SCALE(aout_tlv, -10200, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
+static const char *chan_mix[] = {
+	"L R",
+	"L+R",
+	"R L",
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(cs42l51_chan_mix, chan_mix);
+
+static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
+	SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
+			CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
+			0, 0x19, 0x7F, adc_pcm_tlv),
+	SOC_DOUBLE_R("PCM Playback Switch",
+			CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
+	SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
+			CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
+			0, 0x34, 0xE4, aout_tlv),
+	SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
+			CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
+			0, 0x19, 0x7F, adc_pcm_tlv),
+	SOC_DOUBLE_R("ADC Mixer Switch",
+			CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
+	SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
+	SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0),
+	SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0),
+	SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0),
+	SOC_DOUBLE_TLV("Mic Boost Volume",
+			CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv),
+	SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv),
+	SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv),
+	SOC_ENUM_EXT("PCM channel mixer",
+			cs42l51_chan_mix,
+			cs42l51_get_chan_mix, cs42l51_set_chan_mix),
+};
+
+/*
+ * to power down, one must:
+ * 1.) Enable the PDN bit
+ * 2.) enable power-down for the select channels
+ * 3.) disable the PDN bit.
+ */
+static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, CS42L51_POWER_CTL1,
+				    CS42L51_POWER_CTL1_PDN,
+				    CS42L51_POWER_CTL1_PDN);
+		break;
+	default:
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, CS42L51_POWER_CTL1,
+				    CS42L51_POWER_CTL1_PDN, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static const char *cs42l51_dac_names[] = {"Direct PCM",
+	"DSP PCM", "ADC"};
+static SOC_ENUM_SINGLE_DECL(cs42l51_dac_mux_enum,
+			    CS42L51_DAC_CTL, 6, cs42l51_dac_names);
+static const struct snd_kcontrol_new cs42l51_dac_mux_controls =
+	SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum);
+
+static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left",
+	"MIC Left", "MIC+preamp Left"};
+static SOC_ENUM_SINGLE_DECL(cs42l51_adcl_mux_enum,
+			    CS42L51_ADC_INPUT, 4, cs42l51_adcl_names);
+static const struct snd_kcontrol_new cs42l51_adcl_mux_controls =
+	SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum);
+
+static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right",
+	"MIC Right", "MIC+preamp Right"};
+static SOC_ENUM_SINGLE_DECL(cs42l51_adcr_mux_enum,
+			    CS42L51_ADC_INPUT, 6, cs42l51_adcr_names);
+static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
+	SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
+
+static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
+	SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1),
+	SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_ADC_E("Left ADC", "Left HiFi Capture",
+		CS42L51_POWER_CTL1, 1, 1,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture",
+		CS42L51_POWER_CTL1, 2, 1,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback",
+		CS42L51_POWER_CTL1, 5, 1,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback",
+		CS42L51_POWER_CTL1, 6, 1,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+
+	/* analog/mic */
+	SND_SOC_DAPM_INPUT("AIN1L"),
+	SND_SOC_DAPM_INPUT("AIN1R"),
+	SND_SOC_DAPM_INPUT("AIN2L"),
+	SND_SOC_DAPM_INPUT("AIN2R"),
+	SND_SOC_DAPM_INPUT("MICL"),
+	SND_SOC_DAPM_INPUT("MICR"),
+
+	SND_SOC_DAPM_MIXER("Mic Preamp Left",
+		CS42L51_MIC_POWER_CTL, 2, 1, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mic Preamp Right",
+		CS42L51_MIC_POWER_CTL, 3, 1, NULL, 0),
+
+	/* HP */
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+
+	/* mux */
+	SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0,
+		&cs42l51_dac_mux_controls),
+	SND_SOC_DAPM_MUX("PGA-ADC Mux Left", SND_SOC_NOPM, 0, 0,
+		&cs42l51_adcl_mux_controls),
+	SND_SOC_DAPM_MUX("PGA-ADC Mux Right", SND_SOC_NOPM, 0, 0,
+		&cs42l51_adcr_mux_controls),
+};
+
+static const struct snd_soc_dapm_route cs42l51_routes[] = {
+	{"HPL", NULL, "Left DAC"},
+	{"HPR", NULL, "Right DAC"},
+
+	{"Left ADC", NULL, "Left PGA"},
+	{"Right ADC", NULL, "Right PGA"},
+
+	{"Mic Preamp Left",  NULL,  "MICL"},
+	{"Mic Preamp Right", NULL,  "MICR"},
+
+	{"PGA-ADC Mux Left",  "AIN1 Left",        "AIN1L" },
+	{"PGA-ADC Mux Left",  "AIN2 Left",        "AIN2L" },
+	{"PGA-ADC Mux Left",  "MIC Left",         "MICL"  },
+	{"PGA-ADC Mux Left",  "MIC+preamp Left",  "Mic Preamp Left" },
+	{"PGA-ADC Mux Right", "AIN1 Right",       "AIN1R" },
+	{"PGA-ADC Mux Right", "AIN2 Right",       "AIN2R" },
+	{"PGA-ADC Mux Right", "MIC Right",        "MICR" },
+	{"PGA-ADC Mux Right", "MIC+preamp Right", "Mic Preamp Right" },
+
+	{"Left PGA", NULL, "PGA-ADC Mux Left"},
+	{"Right PGA", NULL, "PGA-ADC Mux Right"},
+};
+
+static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int format)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42l51_private *cs42l51 = snd_soc_component_get_drvdata(component);
+
+	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
+		cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
+		break;
+	default:
+		dev_err(component->dev, "invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		cs42l51->func = MODE_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		cs42l51->func = MODE_SLAVE_AUTO;
+		break;
+	default:
+		dev_err(component->dev, "Unknown master/slave configuration\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+struct cs42l51_ratios {
+	unsigned int ratio;
+	unsigned char speed_mode;
+	unsigned char mclk;
+};
+
+static struct cs42l51_ratios slave_ratios[] = {
+	{  512, CS42L51_QSM_MODE, 0 }, {  768, CS42L51_QSM_MODE, 0 },
+	{ 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
+	{ 2048, CS42L51_QSM_MODE, 0 }, { 3072, CS42L51_QSM_MODE, 0 },
+	{  256, CS42L51_HSM_MODE, 0 }, {  384, CS42L51_HSM_MODE, 0 },
+	{  512, CS42L51_HSM_MODE, 0 }, {  768, CS42L51_HSM_MODE, 0 },
+	{ 1024, CS42L51_HSM_MODE, 0 }, { 1536, CS42L51_HSM_MODE, 0 },
+	{  128, CS42L51_SSM_MODE, 0 }, {  192, CS42L51_SSM_MODE, 0 },
+	{  256, CS42L51_SSM_MODE, 0 }, {  384, CS42L51_SSM_MODE, 0 },
+	{  512, CS42L51_SSM_MODE, 0 }, {  768, CS42L51_SSM_MODE, 0 },
+	{  128, CS42L51_DSM_MODE, 0 }, {  192, CS42L51_DSM_MODE, 0 },
+	{  256, CS42L51_DSM_MODE, 0 }, {  384, CS42L51_DSM_MODE, 0 },
+};
+
+static struct cs42l51_ratios slave_auto_ratios[] = {
+	{ 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
+	{ 2048, CS42L51_QSM_MODE, 1 }, { 3072, CS42L51_QSM_MODE, 1 },
+	{  512, CS42L51_HSM_MODE, 0 }, {  768, CS42L51_HSM_MODE, 0 },
+	{ 1024, CS42L51_HSM_MODE, 1 }, { 1536, CS42L51_HSM_MODE, 1 },
+	{  256, CS42L51_SSM_MODE, 0 }, {  384, CS42L51_SSM_MODE, 0 },
+	{  512, CS42L51_SSM_MODE, 1 }, {  768, CS42L51_SSM_MODE, 1 },
+	{  128, CS42L51_DSM_MODE, 0 }, {  192, CS42L51_DSM_MODE, 0 },
+	{  256, CS42L51_DSM_MODE, 1 }, {  384, CS42L51_DSM_MODE, 1 },
+};
+
+static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42l51_private *cs42l51 = snd_soc_component_get_drvdata(component);
+
+	cs42l51->mclk = freq;
+	return 0;
+}
+
+static int cs42l51_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs42l51_private *cs42l51 = snd_soc_component_get_drvdata(component);
+	int ret;
+	unsigned int i;
+	unsigned int rate;
+	unsigned int ratio;
+	struct cs42l51_ratios *ratios = NULL;
+	int nr_ratios = 0;
+	int intf_ctl, power_ctl, fmt;
+
+	switch (cs42l51->func) {
+	case MODE_MASTER:
+		return -EINVAL;
+	case MODE_SLAVE:
+		ratios = slave_ratios;
+		nr_ratios = ARRAY_SIZE(slave_ratios);
+		break;
+	case MODE_SLAVE_AUTO:
+		ratios = slave_auto_ratios;
+		nr_ratios = ARRAY_SIZE(slave_auto_ratios);
+		break;
+	}
+
+	/* Figure out which MCLK/LRCK ratio to use */
+	rate = params_rate(params);     /* Sampling rate, in Hz */
+	ratio = cs42l51->mclk / rate;    /* MCLK/LRCK ratio */
+	for (i = 0; i < nr_ratios; i++) {
+		if (ratios[i].ratio == ratio)
+			break;
+	}
+
+	if (i == nr_ratios) {
+		/* We did not find a matching ratio */
+		dev_err(component->dev, "could not find matching ratio\n");
+		return -EINVAL;
+	}
+
+	intf_ctl = snd_soc_component_read32(component, CS42L51_INTF_CTL);
+	power_ctl = snd_soc_component_read32(component, CS42L51_MIC_POWER_CTL);
+
+	intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S
+			| CS42L51_INTF_CTL_DAC_FORMAT(7));
+	power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3)
+			| CS42L51_MIC_POWER_CTL_MCLK_DIV2);
+
+	switch (cs42l51->func) {
+	case MODE_MASTER:
+		intf_ctl |= CS42L51_INTF_CTL_MASTER;
+		power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
+		break;
+	case MODE_SLAVE:
+		power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
+		break;
+	case MODE_SLAVE_AUTO:
+		power_ctl |= CS42L51_MIC_POWER_CTL_AUTO;
+		break;
+	}
+
+	switch (cs42l51->audio_mode) {
+	case SND_SOC_DAIFMT_I2S:
+		intf_ctl |= CS42L51_INTF_CTL_ADC_I2S;
+		intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (params_width(params)) {
+		case 16:
+			fmt = CS42L51_DAC_DIF_RJ16;
+			break;
+		case 18:
+			fmt = CS42L51_DAC_DIF_RJ18;
+			break;
+		case 20:
+			fmt = CS42L51_DAC_DIF_RJ20;
+			break;
+		case 24:
+			fmt = CS42L51_DAC_DIF_RJ24;
+			break;
+		default:
+			dev_err(component->dev, "unknown format\n");
+			return -EINVAL;
+		}
+		intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt);
+		break;
+	default:
+		dev_err(component->dev, "unknown format\n");
+		return -EINVAL;
+	}
+
+	if (ratios[i].mclk)
+		power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2;
+
+	ret = snd_soc_component_write(component, CS42L51_INTF_CTL, intf_ctl);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_component_write(component, CS42L51_MIC_POWER_CTL, power_ctl);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	int reg;
+	int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE;
+
+	reg = snd_soc_component_read32(component, CS42L51_DAC_OUT_CTL);
+
+	if (mute)
+		reg |= mask;
+	else
+		reg &= ~mask;
+
+	return snd_soc_component_write(component, CS42L51_DAC_OUT_CTL, reg);
+}
+
+static const struct snd_soc_dai_ops cs42l51_dai_ops = {
+	.hw_params      = cs42l51_hw_params,
+	.set_sysclk     = cs42l51_set_dai_sysclk,
+	.set_fmt        = cs42l51_set_dai_fmt,
+	.digital_mute   = cs42l51_dai_mute,
+};
+
+static struct snd_soc_dai_driver cs42l51_dai = {
+	.name = "cs42l51-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = CS42L51_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = CS42L51_FORMATS,
+	},
+	.ops = &cs42l51_dai_ops,
+};
+
+static int cs42l51_component_probe(struct snd_soc_component *component)
+{
+	int ret, reg;
+
+	/*
+	 * DAC configuration
+	 * - Use signal processor
+	 * - auto mute
+	 * - vol changes immediate
+	 * - no de-emphasize
+	 */
+	reg = CS42L51_DAC_CTL_DATA_SEL(1)
+		| CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
+	ret = snd_soc_component_write(component, CS42L51_DAC_CTL, reg);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_device_cs42l51 = {
+	.probe			= cs42l51_component_probe,
+	.controls		= cs42l51_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs42l51_snd_controls),
+	.dapm_widgets		= cs42l51_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs42l51_dapm_widgets),
+	.dapm_routes		= cs42l51_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs42l51_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+const struct regmap_config cs42l51_regmap = {
+	.max_register = CS42L51_CHARGE_FREQ,
+	.cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(cs42l51_regmap);
+
+int cs42l51_probe(struct device *dev, struct regmap *regmap)
+{
+	struct cs42l51_private *cs42l51;
+	unsigned int val;
+	int ret;
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	cs42l51 = devm_kzalloc(dev, sizeof(struct cs42l51_private),
+			       GFP_KERNEL);
+	if (!cs42l51)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, cs42l51);
+
+	/* Verify that we have a CS42L51 */
+	ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val);
+	if (ret < 0) {
+		dev_err(dev, "failed to read I2C\n");
+		goto error;
+	}
+
+	if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
+	    (val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
+		dev_err(dev, "Invalid chip id: %x\n", val);
+		ret = -ENODEV;
+		goto error;
+	}
+	dev_info(dev, "Cirrus Logic CS42L51, Revision: %02X\n",
+		 val & CS42L51_CHIP_REV_MASK);
+
+	ret = devm_snd_soc_register_component(dev,
+			&soc_component_device_cs42l51, &cs42l51_dai, 1);
+error:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cs42l51_probe);
+
+const struct of_device_id cs42l51_of_match[] = {
+	{ .compatible = "cirrus,cs42l51", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cs42l51_of_match);
+EXPORT_SYMBOL_GPL(cs42l51_of_match);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
+MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h
new file mode 100644
index 0000000..0ca8054
--- /dev/null
+++ b/sound/soc/codecs/cs42l51.h
@@ -0,0 +1,168 @@
+/*
+ * cs42l51.h
+ *
+ * ASoC Driver for Cirrus Logic CS42L51 codecs
+ *
+ * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 _CS42L51_H
+#define _CS42L51_H
+
+struct device;
+
+extern const struct regmap_config cs42l51_regmap;
+int cs42l51_probe(struct device *dev, struct regmap *regmap);
+extern const struct of_device_id cs42l51_of_match[];
+
+#define CS42L51_CHIP_ID			0x1B
+#define CS42L51_CHIP_REV_A		0x00
+#define CS42L51_CHIP_REV_B		0x01
+#define CS42L51_CHIP_REV_MASK		0x07
+
+#define CS42L51_CHIP_REV_ID		0x01
+#define CS42L51_MK_CHIP_REV(a, b)	((a)<<3|(b))
+
+#define CS42L51_POWER_CTL1		0x02
+#define CS42L51_POWER_CTL1_PDN_DACB	(1<<6)
+#define CS42L51_POWER_CTL1_PDN_DACA	(1<<5)
+#define CS42L51_POWER_CTL1_PDN_PGAB	(1<<4)
+#define CS42L51_POWER_CTL1_PDN_PGAA	(1<<3)
+#define CS42L51_POWER_CTL1_PDN_ADCB	(1<<2)
+#define CS42L51_POWER_CTL1_PDN_ADCA	(1<<1)
+#define CS42L51_POWER_CTL1_PDN		(1<<0)
+
+#define CS42L51_MIC_POWER_CTL		0x03
+#define CS42L51_MIC_POWER_CTL_AUTO	(1<<7)
+#define CS42L51_MIC_POWER_CTL_SPEED(x)	(((x)&3)<<5)
+#define CS42L51_QSM_MODE		3
+#define CS42L51_HSM_MODE		2
+#define	CS42L51_SSM_MODE		1
+#define CS42L51_DSM_MODE		0
+#define CS42L51_MIC_POWER_CTL_3ST_SP	(1<<4)
+#define CS42L51_MIC_POWER_CTL_PDN_MICB	(1<<3)
+#define CS42L51_MIC_POWER_CTL_PDN_MICA	(1<<2)
+#define CS42L51_MIC_POWER_CTL_PDN_BIAS	(1<<1)
+#define CS42L51_MIC_POWER_CTL_MCLK_DIV2	(1<<0)
+
+#define CS42L51_INTF_CTL		0x04
+#define CS42L51_INTF_CTL_LOOPBACK	(1<<7)
+#define CS42L51_INTF_CTL_MASTER		(1<<6)
+#define CS42L51_INTF_CTL_DAC_FORMAT(x)	(((x)&7)<<3)
+#define CS42L51_DAC_DIF_LJ24		0x00
+#define CS42L51_DAC_DIF_I2S		0x01
+#define CS42L51_DAC_DIF_RJ24		0x02
+#define CS42L51_DAC_DIF_RJ20		0x03
+#define CS42L51_DAC_DIF_RJ18		0x04
+#define CS42L51_DAC_DIF_RJ16		0x05
+#define CS42L51_INTF_CTL_ADC_I2S	(1<<2)
+#define CS42L51_INTF_CTL_DIGMIX		(1<<1)
+#define CS42L51_INTF_CTL_MICMIX		(1<<0)
+
+#define CS42L51_MIC_CTL			0x05
+#define CS42L51_MIC_CTL_ADC_SNGVOL	(1<<7)
+#define CS42L51_MIC_CTL_ADCD_DBOOST	(1<<6)
+#define CS42L51_MIC_CTL_ADCA_DBOOST	(1<<5)
+#define CS42L51_MIC_CTL_MICBIAS_SEL	(1<<4)
+#define CS42L51_MIC_CTL_MICBIAS_LVL(x)	(((x)&3)<<2)
+#define CS42L51_MIC_CTL_MICB_BOOST	(1<<1)
+#define CS42L51_MIC_CTL_MICA_BOOST	(1<<0)
+
+#define CS42L51_ADC_CTL			0x06
+#define CS42L51_ADC_CTL_ADCB_HPFEN	(1<<7)
+#define CS42L51_ADC_CTL_ADCB_HPFRZ	(1<<6)
+#define CS42L51_ADC_CTL_ADCA_HPFEN	(1<<5)
+#define CS42L51_ADC_CTL_ADCA_HPFRZ	(1<<4)
+#define CS42L51_ADC_CTL_SOFTB		(1<<3)
+#define CS42L51_ADC_CTL_ZCROSSB		(1<<2)
+#define CS42L51_ADC_CTL_SOFTA		(1<<1)
+#define CS42L51_ADC_CTL_ZCROSSA		(1<<0)
+
+#define CS42L51_ADC_INPUT		0x07
+#define CS42L51_ADC_INPUT_AINB_MUX(x)	(((x)&3)<<6)
+#define CS42L51_ADC_INPUT_AINA_MUX(x)	(((x)&3)<<4)
+#define CS42L51_ADC_INPUT_INV_ADCB	(1<<3)
+#define CS42L51_ADC_INPUT_INV_ADCA	(1<<2)
+#define CS42L51_ADC_INPUT_ADCB_MUTE	(1<<1)
+#define CS42L51_ADC_INPUT_ADCA_MUTE	(1<<0)
+
+#define CS42L51_DAC_OUT_CTL		0x08
+#define CS42L51_DAC_OUT_CTL_HP_GAIN(x)	(((x)&7)<<5)
+#define CS42L51_DAC_OUT_CTL_DAC_SNGVOL	(1<<4)
+#define CS42L51_DAC_OUT_CTL_INV_PCMB	(1<<3)
+#define CS42L51_DAC_OUT_CTL_INV_PCMA	(1<<2)
+#define CS42L51_DAC_OUT_CTL_DACB_MUTE	(1<<1)
+#define CS42L51_DAC_OUT_CTL_DACA_MUTE	(1<<0)
+
+#define CS42L51_DAC_CTL			0x09
+#define CS42L51_DAC_CTL_DATA_SEL(x)	(((x)&3)<<6)
+#define CS42L51_DAC_CTL_FREEZE		(1<<5)
+#define CS42L51_DAC_CTL_DEEMPH		(1<<3)
+#define CS42L51_DAC_CTL_AMUTE		(1<<2)
+#define CS42L51_DAC_CTL_DACSZ(x)	(((x)&3)<<0)
+
+#define CS42L51_ALC_PGA_CTL		0x0A
+#define CS42L51_ALC_PGB_CTL		0x0B
+#define CS42L51_ALC_PGX_ALCX_SRDIS	(1<<7)
+#define CS42L51_ALC_PGX_ALCX_ZCDIS	(1<<6)
+#define CS42L51_ALC_PGX_PGX_VOL(x)	(((x)&0x1f)<<0)
+
+#define CS42L51_ADCA_ATT		0x0C
+#define CS42L51_ADCB_ATT		0x0D
+
+#define CS42L51_ADCA_VOL		0x0E
+#define CS42L51_ADCB_VOL		0x0F
+#define CS42L51_PCMA_VOL		0x10
+#define CS42L51_PCMB_VOL		0x11
+#define CS42L51_MIX_MUTE_ADCMIX		(1<<7)
+#define CS42L51_MIX_VOLUME(x)		(((x)&0x7f)<<0)
+
+#define CS42L51_BEEP_FREQ		0x12
+#define CS42L51_BEEP_VOL		0x13
+#define CS42L51_BEEP_CONF		0x14
+
+#define CS42L51_TONE_CTL		0x15
+#define CS42L51_TONE_CTL_TREB(x)	(((x)&0xf)<<4)
+#define CS42L51_TONE_CTL_BASS(x)	(((x)&0xf)<<0)
+
+#define CS42L51_AOUTA_VOL		0x16
+#define CS42L51_AOUTB_VOL		0x17
+#define CS42L51_PCM_MIXER		0x18
+#define CS42L51_LIMIT_THRES_DIS		0x19
+#define CS42L51_LIMIT_REL		0x1A
+#define CS42L51_LIMIT_ATT		0x1B
+#define CS42L51_ALC_EN			0x1C
+#define CS42L51_ALC_REL			0x1D
+#define CS42L51_ALC_THRES		0x1E
+#define CS42L51_NOISE_CONF		0x1F
+
+#define CS42L51_STATUS			0x20
+#define CS42L51_STATUS_SP_CLKERR	(1<<6)
+#define CS42L51_STATUS_SPEA_OVFL	(1<<5)
+#define CS42L51_STATUS_SPEB_OVFL	(1<<4)
+#define CS42L51_STATUS_PCMA_OVFL	(1<<3)
+#define CS42L51_STATUS_PCMB_OVFL	(1<<2)
+#define CS42L51_STATUS_ADCA_OVFL	(1<<1)
+#define CS42L51_STATUS_ADCB_OVFL	(1<<0)
+
+#define CS42L51_CHARGE_FREQ		0x21
+
+#define CS42L51_FIRSTREG	0x01
+/*
+ * Hack: with register 0x21, it makes 33 registers. Looks like someone in the
+ * i2c layer doesn't like i2c smbus block read of 33 regs. Workaround by using
+ * 32 regs
+ */
+#define CS42L51_LASTREG		0x20
+#define CS42L51_NUMREGS		(CS42L51_LASTREG - CS42L51_FIRSTREG + 1)
+
+#endif
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
new file mode 100644
index 0000000..3d83c1b
--- /dev/null
+++ b/sound/soc/codecs/cs42l52.c
@@ -0,0 +1,1238 @@
+/*
+ * cs42l52.c -- CS42L52 ALSA SoC audio driver
+ *
+ * Copyright 2012 CirrusLogic, Inc.
+ *
+ * Author: Georgi Vlaev <joe@nucleusys.com>
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/of_gpio.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/cs42l52.h>
+#include "cs42l52.h"
+
+struct sp_config {
+	u8 spc, format, spfs;
+	u32 srate;
+};
+
+struct  cs42l52_private {
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct device *dev;
+	struct sp_config config;
+	struct cs42l52_platform_data pdata;
+	u32 sysclk;
+	u8 mclksel;
+	u32 mclk;
+	u8 flags;
+	struct input_dev *beep;
+	struct work_struct beep_work;
+	int beep_rate;
+};
+
+static const struct reg_default cs42l52_reg_defaults[] = {
+	{ CS42L52_PWRCTL1, 0x9F },	/* r02 PWRCTL 1 */
+	{ CS42L52_PWRCTL2, 0x07 },	/* r03 PWRCTL 2 */
+	{ CS42L52_PWRCTL3, 0xFF },	/* r04 PWRCTL 3 */
+	{ CS42L52_CLK_CTL, 0xA0 },	/* r05 Clocking Ctl */
+	{ CS42L52_IFACE_CTL1, 0x00 },	/* r06 Interface Ctl 1 */
+	{ CS42L52_ADC_PGA_A, 0x80 },	/* r08 Input A Select */
+	{ CS42L52_ADC_PGA_B, 0x80 },	/* r09 Input B Select */
+	{ CS42L52_ANALOG_HPF_CTL, 0xA5 },	/* r0A Analog HPF Ctl */
+	{ CS42L52_ADC_HPF_FREQ, 0x00 },	/* r0B ADC HPF Corner Freq */
+	{ CS42L52_ADC_MISC_CTL, 0x00 },	/* r0C Misc. ADC Ctl */
+	{ CS42L52_PB_CTL1, 0x60 },	/* r0D Playback Ctl 1 */
+	{ CS42L52_MISC_CTL, 0x02 },	/* r0E Misc. Ctl */
+	{ CS42L52_PB_CTL2, 0x00 },	/* r0F Playback Ctl 2 */
+	{ CS42L52_MICA_CTL, 0x00 },	/* r10 MICA Amp Ctl */
+	{ CS42L52_MICB_CTL, 0x00 },	/* r11 MICB Amp Ctl */
+	{ CS42L52_PGAA_CTL, 0x00 },	/* r12 PGAA Vol, Misc. */
+	{ CS42L52_PGAB_CTL, 0x00 },	/* r13 PGAB Vol, Misc. */
+	{ CS42L52_PASSTHRUA_VOL, 0x00 },	/* r14 Bypass A Vol */
+	{ CS42L52_PASSTHRUB_VOL, 0x00 },	/* r15 Bypass B Vol */
+	{ CS42L52_ADCA_VOL, 0x00 },	/* r16 ADCA Volume */
+	{ CS42L52_ADCB_VOL, 0x00 },	/* r17 ADCB Volume */
+	{ CS42L52_ADCA_MIXER_VOL, 0x80 },	/* r18 ADCA Mixer Volume */
+	{ CS42L52_ADCB_MIXER_VOL, 0x80 },	/* r19 ADCB Mixer Volume */
+	{ CS42L52_PCMA_MIXER_VOL, 0x00 },	/* r1A PCMA Mixer Volume */
+	{ CS42L52_PCMB_MIXER_VOL, 0x00 },	/* r1B PCMB Mixer Volume */
+	{ CS42L52_BEEP_FREQ, 0x00 },	/* r1C Beep Freq on Time */
+	{ CS42L52_BEEP_VOL, 0x00 },	/* r1D Beep Volume off Time */
+	{ CS42L52_BEEP_TONE_CTL, 0x00 },	/* r1E Beep Tone Cfg. */
+	{ CS42L52_TONE_CTL, 0x00 },	/* r1F Tone Ctl */
+	{ CS42L52_MASTERA_VOL, 0x00 },	/* r20 Master A Volume */
+	{ CS42L52_MASTERB_VOL, 0x00 },	/* r21 Master B Volume */
+	{ CS42L52_HPA_VOL, 0x00 },	/* r22 Headphone A Volume */
+	{ CS42L52_HPB_VOL, 0x00 },	/* r23 Headphone B Volume */
+	{ CS42L52_SPKA_VOL, 0x00 },	/* r24 Speaker A Volume */
+	{ CS42L52_SPKB_VOL, 0x00 },	/* r25 Speaker B Volume */
+	{ CS42L52_ADC_PCM_MIXER, 0x00 },	/* r26 Channel Mixer and Swap */
+	{ CS42L52_LIMITER_CTL1, 0x00 },	/* r27 Limit Ctl 1 Thresholds */
+	{ CS42L52_LIMITER_CTL2, 0x7F },	/* r28 Limit Ctl 2 Release Rate */
+	{ CS42L52_LIMITER_AT_RATE, 0xC0 },	/* r29 Limiter Attack Rate */
+	{ CS42L52_ALC_CTL, 0x00 },	/* r2A ALC Ctl 1 Attack Rate */
+	{ CS42L52_ALC_RATE, 0x3F },	/* r2B ALC Release Rate */
+	{ CS42L52_ALC_THRESHOLD, 0x3f },	/* r2C ALC Thresholds */
+	{ CS42L52_NOISE_GATE_CTL, 0x00 },	/* r2D Noise Gate Ctl */
+	{ CS42L52_CLK_STATUS, 0x00 },	/* r2E Overflow and Clock Status */
+	{ CS42L52_BATT_COMPEN, 0x00 },	/* r2F battery Compensation */
+	{ CS42L52_BATT_LEVEL, 0x00 },	/* r30 VP Battery Level */
+	{ CS42L52_SPK_STATUS, 0x00 },	/* r31 Speaker Status */
+	{ CS42L52_TEM_CTL, 0x3B },	/* r32 Temp Ctl */
+	{ CS42L52_THE_FOLDBACK, 0x00 },	/* r33 Foldback */
+};
+
+static bool cs42l52_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS42L52_CHIP ... CS42L52_CHARGE_PUMP:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs42l52_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS42L52_IFACE_CTL2:
+	case CS42L52_CLK_STATUS:
+	case CS42L52_BATT_LEVEL:
+	case CS42L52_SPK_STATUS:
+	case CS42L52_CHARGE_PUMP:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static DECLARE_TLV_DB_SCALE(hl_tlv, -10200, 50, 0);
+
+static DECLARE_TLV_DB_SCALE(hpd_tlv, -9600, 50, 1);
+
+static DECLARE_TLV_DB_SCALE(ipd_tlv, -9600, 100, 0);
+
+static DECLARE_TLV_DB_SCALE(mic_tlv, 1600, 100, 0);
+
+static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
+
+static DECLARE_TLV_DB_SCALE(mix_tlv, -50, 50, 0);
+
+static DECLARE_TLV_DB_SCALE(beep_tlv, -56, 200, 0);
+
+static const DECLARE_TLV_DB_RANGE(limiter_tlv,
+	0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
+	3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0)
+);
+
+static const char * const cs42l52_adca_text[] = {
+	"Input1A", "Input2A", "Input3A", "Input4A", "PGA Input Left"};
+
+static const char * const cs42l52_adcb_text[] = {
+	"Input1B", "Input2B", "Input3B", "Input4B", "PGA Input Right"};
+
+static SOC_ENUM_SINGLE_DECL(adca_enum,
+			    CS42L52_ADC_PGA_A, 5, cs42l52_adca_text);
+
+static SOC_ENUM_SINGLE_DECL(adcb_enum,
+			    CS42L52_ADC_PGA_B, 5, cs42l52_adcb_text);
+
+static const struct snd_kcontrol_new adca_mux =
+	SOC_DAPM_ENUM("Left ADC Input Capture Mux", adca_enum);
+
+static const struct snd_kcontrol_new adcb_mux =
+	SOC_DAPM_ENUM("Right ADC Input Capture Mux", adcb_enum);
+
+static const char * const mic_bias_level_text[] = {
+	"0.5 +VA", "0.6 +VA", "0.7 +VA",
+	"0.8 +VA", "0.83 +VA", "0.91 +VA"
+};
+
+static SOC_ENUM_SINGLE_DECL(mic_bias_level_enum,
+			    CS42L52_IFACE_CTL2, 0, mic_bias_level_text);
+
+static const char * const cs42l52_mic_text[] = { "MIC1", "MIC2" };
+
+static SOC_ENUM_SINGLE_DECL(mica_enum,
+			    CS42L52_MICA_CTL, 5, cs42l52_mic_text);
+
+static SOC_ENUM_SINGLE_DECL(micb_enum,
+			    CS42L52_MICB_CTL, 5, cs42l52_mic_text);
+
+static const char * const digital_output_mux_text[] = {"ADC", "DSP"};
+
+static SOC_ENUM_SINGLE_DECL(digital_output_mux_enum,
+			    CS42L52_ADC_MISC_CTL, 6,
+			    digital_output_mux_text);
+
+static const struct snd_kcontrol_new digital_output_mux =
+	SOC_DAPM_ENUM("Digital Output Mux", digital_output_mux_enum);
+
+static const char * const hp_gain_num_text[] = {
+	"0.3959", "0.4571", "0.5111", "0.6047",
+	"0.7099", "0.8399", "1.000", "1.1430"
+};
+
+static SOC_ENUM_SINGLE_DECL(hp_gain_enum,
+			    CS42L52_PB_CTL1, 5,
+			    hp_gain_num_text);
+
+static const char * const beep_pitch_text[] = {
+	"C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",
+	"C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"
+};
+
+static SOC_ENUM_SINGLE_DECL(beep_pitch_enum,
+			    CS42L52_BEEP_FREQ, 4,
+			    beep_pitch_text);
+
+static const char * const beep_ontime_text[] = {
+	"86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s",
+	"1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s",
+	"3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"
+};
+
+static SOC_ENUM_SINGLE_DECL(beep_ontime_enum,
+			    CS42L52_BEEP_FREQ, 0,
+			    beep_ontime_text);
+
+static const char * const beep_offtime_text[] = {
+	"1.23 s", "2.58 s", "3.90 s", "5.20 s",
+	"6.60 s", "8.05 s", "9.35 s", "10.80 s"
+};
+
+static SOC_ENUM_SINGLE_DECL(beep_offtime_enum,
+			    CS42L52_BEEP_VOL, 5,
+			    beep_offtime_text);
+
+static const char * const beep_config_text[] = {
+	"Off", "Single", "Multiple", "Continuous"
+};
+
+static SOC_ENUM_SINGLE_DECL(beep_config_enum,
+			    CS42L52_BEEP_TONE_CTL, 6,
+			    beep_config_text);
+
+static const char * const beep_bass_text[] = {
+	"50 Hz", "100 Hz", "200 Hz", "250 Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(beep_bass_enum,
+			    CS42L52_BEEP_TONE_CTL, 1,
+			    beep_bass_text);
+
+static const char * const beep_treble_text[] = {
+	"5 kHz", "7 kHz", "10 kHz", " 15 kHz"
+};
+
+static SOC_ENUM_SINGLE_DECL(beep_treble_enum,
+			    CS42L52_BEEP_TONE_CTL, 3,
+			    beep_treble_text);
+
+static const char * const ng_threshold_text[] = {
+	"-34dB", "-37dB", "-40dB", "-43dB",
+	"-46dB", "-52dB", "-58dB", "-64dB"
+};
+
+static SOC_ENUM_SINGLE_DECL(ng_threshold_enum,
+			    CS42L52_NOISE_GATE_CTL, 2,
+			    ng_threshold_text);
+
+static const char * const cs42l52_ng_delay_text[] = {
+	"50ms", "100ms", "150ms", "200ms"};
+
+static SOC_ENUM_SINGLE_DECL(ng_delay_enum,
+			    CS42L52_NOISE_GATE_CTL, 0,
+			    cs42l52_ng_delay_text);
+
+static const char * const cs42l52_ng_type_text[] = {
+	"Apply Specific", "Apply All"
+};
+
+static SOC_ENUM_SINGLE_DECL(ng_type_enum,
+			    CS42L52_NOISE_GATE_CTL, 6,
+			    cs42l52_ng_type_text);
+
+static const char * const left_swap_text[] = {
+	"Left", "LR 2", "Right"};
+
+static const char * const right_swap_text[] = {
+	"Right", "LR 2", "Left"};
+
+static const unsigned int swap_values[] = { 0, 1, 3 };
+
+static const struct soc_enum adca_swap_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 2, 3,
+			      ARRAY_SIZE(left_swap_text),
+			      left_swap_text,
+			      swap_values);
+
+static const struct snd_kcontrol_new adca_mixer =
+	SOC_DAPM_ENUM("Route", adca_swap_enum);
+
+static const struct soc_enum pcma_swap_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 6, 3,
+			      ARRAY_SIZE(left_swap_text),
+			      left_swap_text,
+			      swap_values);
+
+static const struct snd_kcontrol_new pcma_mixer =
+	SOC_DAPM_ENUM("Route", pcma_swap_enum);
+
+static const struct soc_enum adcb_swap_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 0, 3,
+			      ARRAY_SIZE(right_swap_text),
+			      right_swap_text,
+			      swap_values);
+
+static const struct snd_kcontrol_new adcb_mixer =
+	SOC_DAPM_ENUM("Route", adcb_swap_enum);
+
+static const struct soc_enum pcmb_swap_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 4, 3,
+			      ARRAY_SIZE(right_swap_text),
+			      right_swap_text,
+			      swap_values);
+
+static const struct snd_kcontrol_new pcmb_mixer =
+	SOC_DAPM_ENUM("Route", pcmb_swap_enum);
+
+
+static const struct snd_kcontrol_new passthrul_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L52_MISC_CTL, 6, 1, 0);
+
+static const struct snd_kcontrol_new passthrur_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L52_MISC_CTL, 7, 1, 0);
+
+static const struct snd_kcontrol_new spkl_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 0, 1, 1);
+
+static const struct snd_kcontrol_new spkr_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 2, 1, 1);
+
+static const struct snd_kcontrol_new hpl_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 4, 1, 1);
+
+static const struct snd_kcontrol_new hpr_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 6, 1, 1);
+
+static const struct snd_kcontrol_new cs42l52_snd_controls[] = {
+
+	SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L52_MASTERA_VOL,
+			      CS42L52_MASTERB_VOL, 0, 0x34, 0xE4, hl_tlv),
+
+	SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L52_HPA_VOL,
+			      CS42L52_HPB_VOL, 0, 0x34, 0xC0, hpd_tlv),
+
+	SOC_ENUM("Headphone Analog Gain", hp_gain_enum),
+
+	SOC_DOUBLE_R_SX_TLV("Speaker Volume", CS42L52_SPKA_VOL,
+			      CS42L52_SPKB_VOL, 0, 0x40, 0xC0, hl_tlv),
+
+	SOC_DOUBLE_R_SX_TLV("Bypass Volume", CS42L52_PASSTHRUA_VOL,
+			      CS42L52_PASSTHRUB_VOL, 0, 0x88, 0x90, pga_tlv),
+
+	SOC_DOUBLE("Bypass Mute", CS42L52_MISC_CTL, 4, 5, 1, 0),
+
+	SOC_DOUBLE_R_TLV("MIC Gain Volume", CS42L52_MICA_CTL,
+			      CS42L52_MICB_CTL, 0, 0x10, 0, mic_tlv),
+
+	SOC_ENUM("MIC Bias Level", mic_bias_level_enum),
+
+	SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L52_ADCA_VOL,
+			      CS42L52_ADCB_VOL, 0, 0xA0, 0x78, ipd_tlv),
+	SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
+			     CS42L52_ADCA_MIXER_VOL, CS42L52_ADCB_MIXER_VOL,
+				0, 0x19, 0x7F, ipd_tlv),
+
+	SOC_DOUBLE("ADC Switch", CS42L52_ADC_MISC_CTL, 0, 1, 1, 0),
+
+	SOC_DOUBLE_R("ADC Mixer Switch", CS42L52_ADCA_MIXER_VOL,
+		     CS42L52_ADCB_MIXER_VOL, 7, 1, 1),
+
+	SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L52_PGAA_CTL,
+			    CS42L52_PGAB_CTL, 0, 0x28, 0x24, pga_tlv),
+
+	SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume",
+			    CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL,
+				0, 0x19, 0x7f, mix_tlv),
+	SOC_DOUBLE_R("PCM Mixer Switch",
+		     CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL, 7, 1, 1),
+
+	SOC_ENUM("Beep Config", beep_config_enum),
+	SOC_ENUM("Beep Pitch", beep_pitch_enum),
+	SOC_ENUM("Beep on Time", beep_ontime_enum),
+	SOC_ENUM("Beep off Time", beep_offtime_enum),
+	SOC_SINGLE_SX_TLV("Beep Volume", CS42L52_BEEP_VOL,
+			0, 0x07, 0x1f, beep_tlv),
+	SOC_SINGLE("Beep Mixer Switch", CS42L52_BEEP_TONE_CTL, 5, 1, 1),
+	SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum),
+	SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum),
+
+	SOC_SINGLE("Tone Control Switch", CS42L52_BEEP_TONE_CTL, 0, 1, 1),
+	SOC_SINGLE_TLV("Treble Gain Volume",
+			    CS42L52_TONE_CTL, 4, 15, 1, hl_tlv),
+	SOC_SINGLE_TLV("Bass Gain Volume",
+			    CS42L52_TONE_CTL, 0, 15, 1, hl_tlv),
+
+	/* Limiter */
+	SOC_SINGLE_TLV("Limiter Max Threshold Volume",
+		       CS42L52_LIMITER_CTL1, 5, 7, 0, limiter_tlv),
+	SOC_SINGLE_TLV("Limiter Cushion Threshold Volume",
+		       CS42L52_LIMITER_CTL1, 2, 7, 0, limiter_tlv),
+	SOC_SINGLE_TLV("Limiter Release Rate Volume",
+		       CS42L52_LIMITER_CTL2, 0, 63, 0, limiter_tlv),
+	SOC_SINGLE_TLV("Limiter Attack Rate Volume",
+		       CS42L52_LIMITER_AT_RATE, 0, 63, 0, limiter_tlv),
+
+	SOC_SINGLE("Limiter SR Switch", CS42L52_LIMITER_CTL1, 1, 1, 0),
+	SOC_SINGLE("Limiter ZC Switch", CS42L52_LIMITER_CTL1, 0, 1, 0),
+	SOC_SINGLE("Limiter Switch", CS42L52_LIMITER_CTL2, 7, 1, 0),
+
+	/* ALC */
+	SOC_SINGLE_TLV("ALC Attack Rate Volume", CS42L52_ALC_CTL,
+		       0, 63, 0, limiter_tlv),
+	SOC_SINGLE_TLV("ALC Release Rate Volume", CS42L52_ALC_RATE,
+		       0, 63, 0, limiter_tlv),
+	SOC_SINGLE_TLV("ALC Max Threshold Volume", CS42L52_ALC_THRESHOLD,
+		       5, 7, 0, limiter_tlv),
+	SOC_SINGLE_TLV("ALC Min Threshold Volume", CS42L52_ALC_THRESHOLD,
+		       2, 7, 0, limiter_tlv),
+
+	SOC_DOUBLE_R("ALC SR Capture Switch", CS42L52_PGAA_CTL,
+		     CS42L52_PGAB_CTL, 7, 1, 1),
+	SOC_DOUBLE_R("ALC ZC Capture Switch", CS42L52_PGAA_CTL,
+		     CS42L52_PGAB_CTL, 6, 1, 1),
+	SOC_DOUBLE("ALC Capture Switch", CS42L52_ALC_CTL, 6, 7, 1, 0),
+
+	/* Noise gate */
+	SOC_ENUM("NG Type Switch", ng_type_enum),
+	SOC_SINGLE("NG Enable Switch", CS42L52_NOISE_GATE_CTL, 6, 1, 0),
+	SOC_SINGLE("NG Boost Switch", CS42L52_NOISE_GATE_CTL, 5, 1, 1),
+	SOC_ENUM("NG Threshold", ng_threshold_enum),
+	SOC_ENUM("NG Delay", ng_delay_enum),
+
+	SOC_DOUBLE("HPF Switch", CS42L52_ANALOG_HPF_CTL, 5, 7, 1, 0),
+
+	SOC_DOUBLE("Analog SR Switch", CS42L52_ANALOG_HPF_CTL, 1, 3, 1, 1),
+	SOC_DOUBLE("Analog ZC Switch", CS42L52_ANALOG_HPF_CTL, 0, 2, 1, 1),
+	SOC_SINGLE("Digital SR Switch", CS42L52_MISC_CTL, 1, 1, 0),
+	SOC_SINGLE("Digital ZC Switch", CS42L52_MISC_CTL, 0, 1, 0),
+	SOC_SINGLE("Deemphasis Switch", CS42L52_MISC_CTL, 2, 1, 0),
+
+	SOC_SINGLE("Batt Compensation Switch", CS42L52_BATT_COMPEN, 7, 1, 0),
+	SOC_SINGLE("Batt VP Monitor Switch", CS42L52_BATT_COMPEN, 6, 1, 0),
+	SOC_SINGLE("Batt VP ref", CS42L52_BATT_COMPEN, 0, 0x0f, 0),
+
+	SOC_SINGLE("PGA AIN1L Switch", CS42L52_ADC_PGA_A, 0, 1, 0),
+	SOC_SINGLE("PGA AIN1R Switch", CS42L52_ADC_PGA_B, 0, 1, 0),
+	SOC_SINGLE("PGA AIN2L Switch", CS42L52_ADC_PGA_A, 1, 1, 0),
+	SOC_SINGLE("PGA AIN2R Switch", CS42L52_ADC_PGA_B, 1, 1, 0),
+
+	SOC_SINGLE("PGA AIN3L Switch", CS42L52_ADC_PGA_A, 2, 1, 0),
+	SOC_SINGLE("PGA AIN3R Switch", CS42L52_ADC_PGA_B, 2, 1, 0),
+
+	SOC_SINGLE("PGA AIN4L Switch", CS42L52_ADC_PGA_A, 3, 1, 0),
+	SOC_SINGLE("PGA AIN4R Switch", CS42L52_ADC_PGA_B, 3, 1, 0),
+
+	SOC_SINGLE("PGA MICA Switch", CS42L52_ADC_PGA_A, 4, 1, 0),
+	SOC_SINGLE("PGA MICB Switch", CS42L52_ADC_PGA_B, 4, 1, 0),
+
+};
+
+static const struct snd_kcontrol_new cs42l52_mica_controls[] = {
+	SOC_ENUM("MICA Select", mica_enum),
+};
+
+static const struct snd_kcontrol_new cs42l52_micb_controls[] = {
+	SOC_ENUM("MICB Select", micb_enum),
+};
+
+static int cs42l52_add_mic_controls(struct snd_soc_component *component)
+{
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
+	struct cs42l52_platform_data *pdata = &cs42l52->pdata;
+
+	if (!pdata->mica_diff_cfg)
+		snd_soc_add_component_controls(component, cs42l52_mica_controls,
+				     ARRAY_SIZE(cs42l52_mica_controls));
+
+	if (!pdata->micb_diff_cfg)
+		snd_soc_add_component_controls(component, cs42l52_micb_controls,
+				     ARRAY_SIZE(cs42l52_micb_controls));
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {
+
+	SND_SOC_DAPM_INPUT("AIN1L"),
+	SND_SOC_DAPM_INPUT("AIN1R"),
+	SND_SOC_DAPM_INPUT("AIN2L"),
+	SND_SOC_DAPM_INPUT("AIN2R"),
+	SND_SOC_DAPM_INPUT("AIN3L"),
+	SND_SOC_DAPM_INPUT("AIN3R"),
+	SND_SOC_DAPM_INPUT("AIN4L"),
+	SND_SOC_DAPM_INPUT("AIN4R"),
+	SND_SOC_DAPM_INPUT("MICA"),
+	SND_SOC_DAPM_INPUT("MICB"),
+	SND_SOC_DAPM_SIGGEN("Beep"),
+
+	SND_SOC_DAPM_AIF_OUT("AIFOUTL", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIFOUTR", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_ADC("ADC Left", NULL, CS42L52_PWRCTL1, 1, 1),
+	SND_SOC_DAPM_ADC("ADC Right", NULL, CS42L52_PWRCTL1, 2, 1),
+	SND_SOC_DAPM_PGA("PGA Left", CS42L52_PWRCTL1, 3, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("PGA Right", CS42L52_PWRCTL1, 4, 1, NULL, 0),
+
+	SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adca_mux),
+	SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcb_mux),
+
+	SND_SOC_DAPM_MUX("ADC Left Swap", SND_SOC_NOPM,
+			 0, 0, &adca_mixer),
+	SND_SOC_DAPM_MUX("ADC Right Swap", SND_SOC_NOPM,
+			 0, 0, &adcb_mixer),
+
+	SND_SOC_DAPM_MUX("Output Mux", SND_SOC_NOPM,
+			 0, 0, &digital_output_mux),
+
+	SND_SOC_DAPM_PGA("PGA MICA", CS42L52_PWRCTL2, 1, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("PGA MICB", CS42L52_PWRCTL2, 2, 1, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Mic Bias", CS42L52_PWRCTL2, 0, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L52_PWRCTL1, 7, 1, NULL, 0),
+
+	SND_SOC_DAPM_AIF_IN("AIFINL", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIFINR", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_DAC("DAC Left", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC Right", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SWITCH("Bypass Left", CS42L52_MISC_CTL,
+			    6, 0, &passthrul_ctl),
+	SND_SOC_DAPM_SWITCH("Bypass Right", CS42L52_MISC_CTL,
+			    7, 0, &passthrur_ctl),
+
+	SND_SOC_DAPM_MUX("PCM Left Swap", SND_SOC_NOPM,
+			 0, 0, &pcma_mixer),
+	SND_SOC_DAPM_MUX("PCM Right Swap", SND_SOC_NOPM,
+			 0, 0, &pcmb_mixer),
+
+	SND_SOC_DAPM_SWITCH("HP Left Amp", SND_SOC_NOPM, 0, 0, &hpl_ctl),
+	SND_SOC_DAPM_SWITCH("HP Right Amp", SND_SOC_NOPM, 0, 0, &hpr_ctl),
+
+	SND_SOC_DAPM_SWITCH("SPK Left Amp", SND_SOC_NOPM, 0, 0, &spkl_ctl),
+	SND_SOC_DAPM_SWITCH("SPK Right Amp", SND_SOC_NOPM, 0, 0, &spkr_ctl),
+
+	SND_SOC_DAPM_OUTPUT("HPOUTA"),
+	SND_SOC_DAPM_OUTPUT("HPOUTB"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTA"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTB"),
+
+};
+
+static const struct snd_soc_dapm_route cs42l52_audio_map[] = {
+
+	{"Capture", NULL, "AIFOUTL"},
+	{"Capture", NULL, "AIFOUTL"},
+
+	{"AIFOUTL", NULL, "Output Mux"},
+	{"AIFOUTR", NULL, "Output Mux"},
+
+	{"Output Mux", "ADC", "ADC Left"},
+	{"Output Mux", "ADC", "ADC Right"},
+
+	{"ADC Left", NULL, "Charge Pump"},
+	{"ADC Right", NULL, "Charge Pump"},
+
+	{"Charge Pump", NULL, "ADC Left Mux"},
+	{"Charge Pump", NULL, "ADC Right Mux"},
+
+	{"ADC Left Mux", "Input1A", "AIN1L"},
+	{"ADC Right Mux", "Input1B", "AIN1R"},
+	{"ADC Left Mux", "Input2A", "AIN2L"},
+	{"ADC Right Mux", "Input2B", "AIN2R"},
+	{"ADC Left Mux", "Input3A", "AIN3L"},
+	{"ADC Right Mux", "Input3B", "AIN3R"},
+	{"ADC Left Mux", "Input4A", "AIN4L"},
+	{"ADC Right Mux", "Input4B", "AIN4R"},
+	{"ADC Left Mux", "PGA Input Left", "PGA Left"},
+	{"ADC Right Mux", "PGA Input Right" , "PGA Right"},
+
+	{"PGA Left", "Switch", "AIN1L"},
+	{"PGA Right", "Switch", "AIN1R"},
+	{"PGA Left", "Switch", "AIN2L"},
+	{"PGA Right", "Switch", "AIN2R"},
+	{"PGA Left", "Switch", "AIN3L"},
+	{"PGA Right", "Switch", "AIN3R"},
+	{"PGA Left", "Switch", "AIN4L"},
+	{"PGA Right", "Switch", "AIN4R"},
+
+	{"PGA Left", "Switch", "PGA MICA"},
+	{"PGA MICA", NULL, "MICA"},
+
+	{"PGA Right", "Switch", "PGA MICB"},
+	{"PGA MICB", NULL, "MICB"},
+
+	{"HPOUTA", NULL, "HP Left Amp"},
+	{"HPOUTB", NULL, "HP Right Amp"},
+	{"HP Left Amp", NULL, "Bypass Left"},
+	{"HP Right Amp", NULL, "Bypass Right"},
+	{"Bypass Left", "Switch", "PGA Left"},
+	{"Bypass Right", "Switch", "PGA Right"},
+	{"HP Left Amp", "Switch", "DAC Left"},
+	{"HP Right Amp", "Switch", "DAC Right"},
+
+	{"SPKOUTA", NULL, "SPK Left Amp"},
+	{"SPKOUTB", NULL, "SPK Right Amp"},
+
+	{"SPK Left Amp", NULL, "Beep"},
+	{"SPK Right Amp", NULL, "Beep"},
+	{"SPK Left Amp", "Switch", "Playback"},
+	{"SPK Right Amp", "Switch", "Playback"},
+
+	{"DAC Left", NULL, "Beep"},
+	{"DAC Right", NULL, "Beep"},
+	{"DAC Left", NULL, "Playback"},
+	{"DAC Right", NULL, "Playback"},
+
+	{"Output Mux", "DSP", "Playback"},
+	{"Output Mux", "DSP", "Playback"},
+
+	{"AIFINL", NULL, "Playback"},
+	{"AIFINR", NULL, "Playback"},
+
+};
+
+struct cs42l52_clk_para {
+	u32 mclk;
+	u32 rate;
+	u8 speed;
+	u8 group;
+	u8 videoclk;
+	u8 ratio;
+	u8 mclkdiv2;
+};
+
+static const struct cs42l52_clk_para clk_map_table[] = {
+	/*8k*/
+	{12288000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+	{18432000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+	{12000000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
+	{24000000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
+	{27000000, 8000, CLK_QS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 0},
+
+	/*11.025k*/
+	{11289600, 11025, CLK_QS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{16934400, 11025, CLK_QS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+	/*16k*/
+	{12288000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+	{18432000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+	{12000000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
+	{24000000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
+	{27000000, 16000, CLK_HS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 1},
+
+	/*22.05k*/
+	{11289600, 22050, CLK_HS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{16934400, 22050, CLK_HS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+	/* 32k */
+	{12288000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+	{18432000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+	{12000000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
+	{24000000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
+	{27000000, 32000, CLK_SS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 0},
+
+	/* 44.1k */
+	{11289600, 44100, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{16934400, 44100, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+	/* 48k */
+	{12288000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{18432000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{12000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 0},
+	{24000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 1},
+	{27000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_27M_MCLK, CLK_R_125, 1},
+
+	/* 88.2k */
+	{11289600, 88200, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{16934400, 88200, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+	/* 96k */
+	{12288000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{18432000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+	{12000000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 0},
+	{24000000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 1},
+};
+
+static int cs42l52_get_clk(int mclk, int rate)
+{
+	int i, ret = -EINVAL;
+	u_int mclk1, mclk2 = 0;
+
+	for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
+		if (clk_map_table[i].rate == rate) {
+			mclk1 = clk_map_table[i].mclk;
+			if (abs(mclk - mclk1) < abs(mclk - mclk2)) {
+				mclk2 = mclk1;
+				ret = i;
+			}
+		}
+	}
+	return ret;
+}
+
+static int cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
+			int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
+
+	if ((freq >= CS42L52_MIN_CLK) && (freq <= CS42L52_MAX_CLK)) {
+		cs42l52->sysclk = freq;
+	} else {
+		dev_err(component->dev, "Invalid freq parameter\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cs42l52_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
+	u8 iface = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface = CS42L52_IFACE_CTL1_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		iface = CS42L52_IFACE_CTL1_SLAVE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	 /* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= CS42L52_IFACE_CTL1_ADC_FMT_I2S |
+				CS42L52_IFACE_CTL1_DAC_FMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		iface |= CS42L52_IFACE_CTL1_DAC_FMT_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= CS42L52_IFACE_CTL1_ADC_FMT_LEFT_J |
+				CS42L52_IFACE_CTL1_DAC_FMT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= CS42L52_IFACE_CTL1_DSP_MODE_EN;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= CS42L52_IFACE_CTL1_INV_SCLK;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= CS42L52_IFACE_CTL1_INV_SCLK;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		break;
+	default:
+		return -EINVAL;
+	}
+	cs42l52->config.format = iface;
+	snd_soc_component_write(component, CS42L52_IFACE_CTL1, cs42l52->config.format);
+
+	return 0;
+}
+
+static int cs42l52_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute)
+		snd_soc_component_update_bits(component, CS42L52_PB_CTL1,
+				    CS42L52_PB_CTL1_MUTE_MASK,
+				CS42L52_PB_CTL1_MUTE);
+	else
+		snd_soc_component_update_bits(component, CS42L52_PB_CTL1,
+				    CS42L52_PB_CTL1_MUTE_MASK,
+				CS42L52_PB_CTL1_UNMUTE);
+
+	return 0;
+}
+
+static int cs42l52_pcm_hw_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params,
+				     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
+	u32 clk = 0;
+	int index;
+
+	index = cs42l52_get_clk(cs42l52->sysclk, params_rate(params));
+	if (index >= 0) {
+		cs42l52->sysclk = clk_map_table[index].mclk;
+
+		clk |= (clk_map_table[index].speed << CLK_SPEED_SHIFT) |
+		(clk_map_table[index].group << CLK_32K_SR_SHIFT) |
+		(clk_map_table[index].videoclk << CLK_27M_MCLK_SHIFT) |
+		(clk_map_table[index].ratio << CLK_RATIO_SHIFT) |
+		clk_map_table[index].mclkdiv2;
+
+		snd_soc_component_write(component, CS42L52_CLK_CTL, clk);
+	} else {
+		dev_err(component->dev, "can't get correct mclk\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cs42l52_set_bias_level(struct snd_soc_component *component,
+					enum snd_soc_bias_level level)
+{
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		snd_soc_component_update_bits(component, CS42L52_PWRCTL1,
+				    CS42L52_PWRCTL1_PDN_CODEC, 0);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			regcache_cache_only(cs42l52->regmap, false);
+			regcache_sync(cs42l52->regmap);
+		}
+		snd_soc_component_write(component, CS42L52_PWRCTL1, CS42L52_PWRCTL1_PDN_ALL);
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_write(component, CS42L52_PWRCTL1, CS42L52_PWRCTL1_PDN_ALL);
+		regcache_cache_only(cs42l52->regmap, true);
+		break;
+	}
+
+	return 0;
+}
+
+#define CS42L52_RATES (SNDRV_PCM_RATE_8000_96000)
+
+#define CS42L52_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
+			SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_U18_3LE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE)
+
+static const struct snd_soc_dai_ops cs42l52_ops = {
+	.hw_params	= cs42l52_pcm_hw_params,
+	.digital_mute	= cs42l52_digital_mute,
+	.set_fmt	= cs42l52_set_fmt,
+	.set_sysclk	= cs42l52_set_sysclk,
+};
+
+static struct snd_soc_dai_driver cs42l52_dai = {
+		.name = "cs42l52",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS42L52_RATES,
+			.formats = CS42L52_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS42L52_RATES,
+			.formats = CS42L52_FORMATS,
+		},
+		.ops = &cs42l52_ops,
+};
+
+static int beep_rates[] = {
+	261, 522, 585, 667, 706, 774, 889, 1000,
+	1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
+};
+
+static void cs42l52_beep_work(struct work_struct *work)
+{
+	struct cs42l52_private *cs42l52 =
+		container_of(work, struct cs42l52_private, beep_work);
+	struct snd_soc_component *component = cs42l52->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int i;
+	int val = 0;
+	int best = 0;
+
+	if (cs42l52->beep_rate) {
+		for (i = 0; i < ARRAY_SIZE(beep_rates); i++) {
+			if (abs(cs42l52->beep_rate - beep_rates[i]) <
+			    abs(cs42l52->beep_rate - beep_rates[best]))
+				best = i;
+		}
+
+		dev_dbg(component->dev, "Set beep rate %dHz for requested %dHz\n",
+			beep_rates[best], cs42l52->beep_rate);
+
+		val = (best << CS42L52_BEEP_RATE_SHIFT);
+
+		snd_soc_dapm_enable_pin(dapm, "Beep");
+	} else {
+		dev_dbg(component->dev, "Disabling beep\n");
+		snd_soc_dapm_disable_pin(dapm, "Beep");
+	}
+
+	snd_soc_component_update_bits(component, CS42L52_BEEP_FREQ,
+			    CS42L52_BEEP_RATE_MASK, val);
+
+	snd_soc_dapm_sync(dapm);
+}
+
+/* For usability define a way of injecting beep events for the device -
+ * many systems will not have a keyboard.
+ */
+static int cs42l52_beep_event(struct input_dev *dev, unsigned int type,
+			     unsigned int code, int hz)
+{
+	struct snd_soc_component *component = input_get_drvdata(dev);
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "Beep event %x %x\n", code, hz);
+
+	switch (code) {
+	case SND_BELL:
+		if (hz)
+			hz = 261;
+	case SND_TONE:
+		break;
+	default:
+		return -1;
+	}
+
+	/* Kick the beep from a workqueue */
+	cs42l52->beep_rate = hz;
+	schedule_work(&cs42l52->beep_work);
+	return 0;
+}
+
+static ssize_t cs42l52_beep_set(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct cs42l52_private *cs42l52 = dev_get_drvdata(dev);
+	long int time;
+	int ret;
+
+	ret = kstrtol(buf, 10, &time);
+	if (ret != 0)
+		return ret;
+
+	input_event(cs42l52->beep, EV_SND, SND_TONE, time);
+
+	return count;
+}
+
+static DEVICE_ATTR(beep, 0200, NULL, cs42l52_beep_set);
+
+static void cs42l52_init_beep(struct snd_soc_component *component)
+{
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	cs42l52->beep = devm_input_allocate_device(component->dev);
+	if (!cs42l52->beep) {
+		dev_err(component->dev, "Failed to allocate beep device\n");
+		return;
+	}
+
+	INIT_WORK(&cs42l52->beep_work, cs42l52_beep_work);
+	cs42l52->beep_rate = 0;
+
+	cs42l52->beep->name = "CS42L52 Beep Generator";
+	cs42l52->beep->phys = dev_name(component->dev);
+	cs42l52->beep->id.bustype = BUS_I2C;
+
+	cs42l52->beep->evbit[0] = BIT_MASK(EV_SND);
+	cs42l52->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+	cs42l52->beep->event = cs42l52_beep_event;
+	cs42l52->beep->dev.parent = component->dev;
+	input_set_drvdata(cs42l52->beep, component);
+
+	ret = input_register_device(cs42l52->beep);
+	if (ret != 0) {
+		cs42l52->beep = NULL;
+		dev_err(component->dev, "Failed to register beep device\n");
+	}
+
+	ret = device_create_file(component->dev, &dev_attr_beep);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to create keyclick file: %d\n",
+			ret);
+	}
+}
+
+static void cs42l52_free_beep(struct snd_soc_component *component)
+{
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
+
+	device_remove_file(component->dev, &dev_attr_beep);
+	cancel_work_sync(&cs42l52->beep_work);
+	cs42l52->beep = NULL;
+
+	snd_soc_component_update_bits(component, CS42L52_BEEP_TONE_CTL,
+			    CS42L52_BEEP_EN_MASK, 0);
+}
+
+static int cs42l52_probe(struct snd_soc_component *component)
+{
+	struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(cs42l52->regmap, true);
+
+	cs42l52_add_mic_controls(component);
+
+	cs42l52_init_beep(component);
+
+	cs42l52->sysclk = CS42L52_DEFAULT_CLK;
+	cs42l52->config.format = CS42L52_DEFAULT_FORMAT;
+
+	return 0;
+}
+
+static void cs42l52_remove(struct snd_soc_component *component)
+{
+	cs42l52_free_beep(component);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_cs42l52 = {
+	.probe			= cs42l52_probe,
+	.remove			= cs42l52_remove,
+	.set_bias_level		= cs42l52_set_bias_level,
+	.controls		= cs42l52_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs42l52_snd_controls),
+	.dapm_widgets		= cs42l52_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs42l52_dapm_widgets),
+	.dapm_routes		= cs42l52_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs42l52_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+/* Current and threshold powerup sequence Pg37 */
+static const struct reg_sequence cs42l52_threshold_patch[] = {
+
+	{ 0x00, 0x99 },
+	{ 0x3E, 0xBA },
+	{ 0x47, 0x80 },
+	{ 0x32, 0xBB },
+	{ 0x32, 0x3B },
+	{ 0x00, 0x00 },
+
+};
+
+static const struct regmap_config cs42l52_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = CS42L52_MAX_REGISTER,
+	.reg_defaults = cs42l52_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(cs42l52_reg_defaults),
+	.readable_reg = cs42l52_readable_register,
+	.volatile_reg = cs42l52_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
+			     const struct i2c_device_id *id)
+{
+	struct cs42l52_private *cs42l52;
+	struct cs42l52_platform_data *pdata = dev_get_platdata(&i2c_client->dev);
+	int ret;
+	unsigned int devid = 0;
+	unsigned int reg;
+	u32 val32;
+
+	cs42l52 = devm_kzalloc(&i2c_client->dev, sizeof(*cs42l52), GFP_KERNEL);
+	if (cs42l52 == NULL)
+		return -ENOMEM;
+	cs42l52->dev = &i2c_client->dev;
+
+	cs42l52->regmap = devm_regmap_init_i2c(i2c_client, &cs42l52_regmap);
+	if (IS_ERR(cs42l52->regmap)) {
+		ret = PTR_ERR(cs42l52->regmap);
+		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+	if (pdata) {
+		cs42l52->pdata = *pdata;
+	} else {
+		pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
+				     GFP_KERNEL);
+		if (!pdata)
+			return -ENOMEM;
+
+		if (i2c_client->dev.of_node) {
+			if (of_property_read_bool(i2c_client->dev.of_node,
+				"cirrus,mica-differential-cfg"))
+				pdata->mica_diff_cfg = true;
+
+			if (of_property_read_bool(i2c_client->dev.of_node,
+				"cirrus,micb-differential-cfg"))
+				pdata->micb_diff_cfg = true;
+
+			if (of_property_read_u32(i2c_client->dev.of_node,
+				"cirrus,micbias-lvl", &val32) >= 0)
+				pdata->micbias_lvl = val32;
+
+			if (of_property_read_u32(i2c_client->dev.of_node,
+				"cirrus,chgfreq-divisor", &val32) >= 0)
+				pdata->chgfreq = val32;
+
+			pdata->reset_gpio =
+				of_get_named_gpio(i2c_client->dev.of_node,
+						"cirrus,reset-gpio", 0);
+		}
+		cs42l52->pdata = *pdata;
+	}
+
+	if (cs42l52->pdata.reset_gpio) {
+		ret = devm_gpio_request_one(&i2c_client->dev,
+					    cs42l52->pdata.reset_gpio,
+					    GPIOF_OUT_INIT_HIGH,
+					    "CS42L52 /RST");
+		if (ret < 0) {
+			dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n",
+				cs42l52->pdata.reset_gpio, ret);
+			return ret;
+		}
+		gpio_set_value_cansleep(cs42l52->pdata.reset_gpio, 0);
+		gpio_set_value_cansleep(cs42l52->pdata.reset_gpio, 1);
+	}
+
+	i2c_set_clientdata(i2c_client, cs42l52);
+
+	ret = regmap_register_patch(cs42l52->regmap, cs42l52_threshold_patch,
+				    ARRAY_SIZE(cs42l52_threshold_patch));
+	if (ret != 0)
+		dev_warn(cs42l52->dev, "Failed to apply regmap patch: %d\n",
+			 ret);
+
+	ret = regmap_read(cs42l52->regmap, CS42L52_CHIP, &reg);
+	devid = reg & CS42L52_CHIP_ID_MASK;
+	if (devid != CS42L52_CHIP_ID) {
+		ret = -ENODEV;
+		dev_err(&i2c_client->dev,
+			"CS42L52 Device ID (%X). Expected %X\n",
+			devid, CS42L52_CHIP_ID);
+		return ret;
+	}
+
+	dev_info(&i2c_client->dev, "Cirrus Logic CS42L52, Revision: %02X\n",
+		 reg & CS42L52_CHIP_REV_MASK);
+
+	/* Set Platform Data */
+	if (cs42l52->pdata.mica_diff_cfg)
+		regmap_update_bits(cs42l52->regmap, CS42L52_MICA_CTL,
+				   CS42L52_MIC_CTL_TYPE_MASK,
+				cs42l52->pdata.mica_diff_cfg <<
+				CS42L52_MIC_CTL_TYPE_SHIFT);
+
+	if (cs42l52->pdata.micb_diff_cfg)
+		regmap_update_bits(cs42l52->regmap, CS42L52_MICB_CTL,
+				   CS42L52_MIC_CTL_TYPE_MASK,
+				cs42l52->pdata.micb_diff_cfg <<
+				CS42L52_MIC_CTL_TYPE_SHIFT);
+
+	if (cs42l52->pdata.chgfreq)
+		regmap_update_bits(cs42l52->regmap, CS42L52_CHARGE_PUMP,
+				   CS42L52_CHARGE_PUMP_MASK,
+				cs42l52->pdata.chgfreq <<
+				CS42L52_CHARGE_PUMP_SHIFT);
+
+	if (cs42l52->pdata.micbias_lvl)
+		regmap_update_bits(cs42l52->regmap, CS42L52_IFACE_CTL2,
+				   CS42L52_IFACE_CTL2_BIAS_LVL,
+				cs42l52->pdata.micbias_lvl);
+
+	ret =  devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_dev_cs42l52, &cs42l52_dai, 1);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static const struct of_device_id cs42l52_of_match[] = {
+	{ .compatible = "cirrus,cs42l52", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cs42l52_of_match);
+
+
+static const struct i2c_device_id cs42l52_id[] = {
+	{ "cs42l52", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cs42l52_id);
+
+static struct i2c_driver cs42l52_i2c_driver = {
+	.driver = {
+		.name = "cs42l52",
+		.of_match_table = cs42l52_of_match,
+	},
+	.id_table = cs42l52_id,
+	.probe =    cs42l52_i2c_probe,
+};
+
+module_i2c_driver(cs42l52_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L52 driver");
+MODULE_AUTHOR("Georgi Vlaev, Nucleus Systems Ltd, <joe@nucleusys.com>");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l52.h b/sound/soc/codecs/cs42l52.h
new file mode 100644
index 0000000..ac44599
--- /dev/null
+++ b/sound/soc/codecs/cs42l52.h
@@ -0,0 +1,274 @@
+/*
+ * cs42l52.h -- CS42L52 ALSA SoC audio driver
+ *
+ * Copyright 2012 CirrusLogic, Inc.
+ *
+ * Author: Georgi Vlaev <joe@nucleusys.com>
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CS42L52_H__
+#define __CS42L52_H__
+
+#define CS42L52_NAME				"CS42L52"
+#define CS42L52_DEFAULT_CLK			12000000
+#define CS42L52_MIN_CLK				11000000
+#define CS42L52_MAX_CLK				27000000
+#define CS42L52_DEFAULT_FORMAT			SNDRV_PCM_FMTBIT_S16_LE
+#define CS42L52_DEFAULT_MAX_CHANS		2
+#define CS42L52_SYSCLK				1
+
+#define CS42L52_CHIP_SWICTH			(1 << 17)
+#define CS42L52_ALL_IN_ONE			(1 << 16)
+#define CS42L52_CHIP_ONE			0x00
+#define CS42L52_CHIP_TWO			0x01
+#define CS42L52_CHIP_THR			0x02
+#define CS42L52_CHIP_MASK			0x0f
+
+#define CS42L52_FIX_BITS_CTL			0x00
+#define CS42L52_CHIP				0x01
+#define CS42L52_CHIP_ID				0xE0
+#define CS42L52_CHIP_ID_MASK			0xF8
+#define CS42L52_CHIP_REV_A0			0x00
+#define CS42L52_CHIP_REV_A1			0x01
+#define CS42L52_CHIP_REV_B0			0x02
+#define CS42L52_CHIP_REV_MASK			0x07
+
+#define CS42L52_PWRCTL1				0x02
+#define CS42L52_PWRCTL1_PDN_ALL			0x9F
+#define CS42L52_PWRCTL1_PDN_CHRG		0x80
+#define CS42L52_PWRCTL1_PDN_PGAB		0x10
+#define CS42L52_PWRCTL1_PDN_PGAA		0x08
+#define CS42L52_PWRCTL1_PDN_ADCB		0x04
+#define CS42L52_PWRCTL1_PDN_ADCA		0x02
+#define CS42L52_PWRCTL1_PDN_CODEC		0x01
+
+#define CS42L52_PWRCTL2				0x03
+#define CS42L52_PWRCTL2_OVRDB			(1 << 4)
+#define CS42L52_PWRCTL2_OVRDA			(1 << 3)
+#define	CS42L52_PWRCTL2_PDN_MICB		(1 << 2)
+#define CS42L52_PWRCTL2_PDN_MICB_SHIFT		2
+#define CS42L52_PWRCTL2_PDN_MICA		(1 << 1)
+#define CS42L52_PWRCTL2_PDN_MICA_SHIFT		1
+#define CS42L52_PWRCTL2_PDN_MICBIAS		(1 << 0)
+#define CS42L52_PWRCTL2_PDN_MICBIAS_SHIFT	0
+
+#define CS42L52_PWRCTL3				0x04
+#define CS42L52_PWRCTL3_HPB_PDN_SHIFT		6
+#define CS42L52_PWRCTL3_HPB_ON_LOW		0x00
+#define CS42L52_PWRCTL3_HPB_ON_HIGH		0x01
+#define CS42L52_PWRCTL3_HPB_ALWAYS_ON		0x02
+#define CS42L52_PWRCTL3_HPB_ALWAYS_OFF		0x03
+#define CS42L52_PWRCTL3_HPA_PDN_SHIFT		4
+#define CS42L52_PWRCTL3_HPA_ON_LOW		0x00
+#define CS42L52_PWRCTL3_HPA_ON_HIGH		0x01
+#define CS42L52_PWRCTL3_HPA_ALWAYS_ON		0x02
+#define CS42L52_PWRCTL3_HPA_ALWAYS_OFF		0x03
+#define CS42L52_PWRCTL3_SPKB_PDN_SHIFT		2
+#define CS42L52_PWRCTL3_SPKB_ON_LOW		0x00
+#define CS42L52_PWRCTL3_SPKB_ON_HIGH		0x01
+#define CS42L52_PWRCTL3_SPKB_ALWAYS_ON		0x02
+#define CS42L52_PWRCTL3_PDN_SPKB		(1 << 2)
+#define CS42L52_PWRCTL3_PDN_SPKA		(1 << 0)
+#define CS42L52_PWRCTL3_SPKA_PDN_SHIFT		0
+#define CS42L52_PWRCTL3_SPKA_ON_LOW		0x00
+#define CS42L52_PWRCTL3_SPKA_ON_HIGH		0x01
+#define CS42L52_PWRCTL3_SPKA_ALWAYS_ON		0x02
+
+#define CS42L52_DEFAULT_OUTPUT_STATE		0x05
+#define CS42L52_PWRCTL3_CONF_MASK		0x03
+
+#define CS42L52_CLK_CTL				0x05
+#define CLK_AUTODECT_ENABLE			(1 << 7)
+#define CLK_SPEED_SHIFT				5
+#define CLK_DS_MODE				0x00
+#define CLK_SS_MODE				0x01
+#define CLK_HS_MODE				0x02
+#define CLK_QS_MODE				0x03
+#define CLK_32K_SR_SHIFT			4
+#define CLK_32K					0x01
+#define CLK_NO_32K				0x00
+#define CLK_27M_MCLK_SHIFT			3
+#define CLK_27M_MCLK				0x01
+#define CLK_NO_27M				0x00
+#define CLK_RATIO_SHIFT				1
+#define CLK_R_128				0x00
+#define CLK_R_125				0x01
+#define CLK_R_132				0x02
+#define CLK_R_136				0x03
+
+#define CS42L52_IFACE_CTL1			0x06
+#define CS42L52_IFACE_CTL1_MASTER		(1 << 7)
+#define CS42L52_IFACE_CTL1_SLAVE		(0 << 7)
+#define CS42L52_IFACE_CTL1_INV_SCLK		(1 << 6)
+#define CS42L52_IFACE_CTL1_ADC_FMT_I2S		(1 << 5)
+#define CS42L52_IFACE_CTL1_ADC_FMT_LEFT_J	(0 << 5)
+#define CS42L52_IFACE_CTL1_DSP_MODE_EN		(1 << 4)
+#define CS42L52_IFACE_CTL1_DAC_FMT_LEFT_J	(0 << 2)
+#define CS42L52_IFACE_CTL1_DAC_FMT_I2S		(1 << 2)
+#define CS42L52_IFACE_CTL1_DAC_FMT_RIGHT_J	(2 << 2)
+#define CS42L52_IFACE_CTL1_WL_32BIT		(0x00)
+#define CS42L52_IFACE_CTL1_WL_24BIT		(0x01)
+#define CS42L52_IFACE_CTL1_WL_20BIT		(0x02)
+#define CS42L52_IFACE_CTL1_WL_16BIT		(0x03)
+#define CS42L52_IFACE_CTL1_WL_MASK		0xFFFF
+
+#define CS42L52_IFACE_CTL2			0x07
+#define CS42L52_IFACE_CTL2_SC_MC_EQ		(1 << 6)
+#define CS42L52_IFACE_CTL2_LOOPBACK		(1 << 5)
+#define CS42L52_IFACE_CTL2_S_MODE_OUTPUT_EN	(0 << 4)
+#define CS42L52_IFACE_CTL2_S_MODE_OUTPUT_HIZ	(1 << 4)
+#define CS42L52_IFACE_CTL2_HP_SW_INV		(1 << 3)
+#define CS42L52_IFACE_CTL2_BIAS_LVL		0x07
+
+#define CS42L52_ADC_PGA_A			0x08
+#define CS42L52_ADC_PGA_B			0x09
+#define CS42L52_ADC_SEL_SHIFT			5
+#define CS42L52_ADC_SEL_AIN1			0x00
+#define CS42L52_ADC_SEL_AIN2			0x01
+#define CS42L52_ADC_SEL_AIN3			0x02
+#define CS42L52_ADC_SEL_AIN4			0x03
+#define CS42L52_ADC_SEL_PGA			0x04
+
+#define CS42L52_ANALOG_HPF_CTL			0x0A
+#define CS42L52_HPF_CTL_ANLGSFTB		(1 << 3)
+#define CS42L52_HPF_CTL_ANLGSFTA                (1 << 0)
+
+#define CS42L52_ADC_HPF_FREQ			0x0B
+#define CS42L52_ADC_MISC_CTL			0x0C
+#define CS42L52_ADC_MISC_CTL_SOURCE_DSP		(1 << 6)
+
+#define CS42L52_PB_CTL1				0x0D
+#define CS42L52_PB_CTL1_HP_GAIN_SHIFT		5
+#define CS42L52_PB_CTL1_HP_GAIN_03959		0x00
+#define CS42L52_PB_CTL1_HP_GAIN_04571		0x01
+#define CS42L52_PB_CTL1_HP_GAIN_05111		0x02
+#define CS42L52_PB_CTL1_HP_GAIN_06047		0x03
+#define CS42L52_PB_CTL1_HP_GAIN_07099		0x04
+#define CS42L52_PB_CTL1_HP_GAIN_08399		0x05
+#define CS42L52_PB_CTL1_HP_GAIN_10000		0x06
+#define CS42L52_PB_CTL1_HP_GAIN_11430		0x07
+#define CS42L52_PB_CTL1_INV_PCMB		(1 << 3)
+#define CS42L52_PB_CTL1_INV_PCMA		(1 << 2)
+#define CS42L52_PB_CTL1_MSTB_MUTE		(1 << 1)
+#define CS42L52_PB_CTL1_MSTA_MUTE		(1 << 0)
+#define CS42L52_PB_CTL1_MUTE_MASK		0x03
+#define CS42L52_PB_CTL1_MUTE			3
+#define CS42L52_PB_CTL1_UNMUTE			0
+
+#define CS42L52_MISC_CTL			0x0E
+#define CS42L52_MISC_CTL_DEEMPH			(1 << 2)
+#define CS42L52_MISC_CTL_DIGSFT			(1 << 1)
+#define CS42L52_MISC_CTL_DIGZC			(1 << 0)
+
+#define CS42L52_PB_CTL2				0x0F
+#define CS42L52_PB_CTL2_HPB_MUTE		(1 << 7)
+#define CS42L52_PB_CTL2_HPA_MUTE		(1 << 6)
+#define CS42L52_PB_CTL2_SPKB_MUTE		(1 << 5)
+#define CS42L52_PB_CTL2_SPKA_MUTE		(1 << 4)
+#define CS42L52_PB_CTL2_SPK_SWAP		(1 << 2)
+#define CS42L52_PB_CTL2_SPK_MONO		(1 << 1)
+#define CS42L52_PB_CTL2_SPK_MUTE50		(1 << 0)
+
+#define	CS42L52_MICA_CTL			0x10
+#define CS42L52_MICB_CTL			0x11
+#define	CS42L52_MIC_CTL_MIC_SEL_MASK		0xBF
+#define	CS42L52_MIC_CTL_MIC_SEL_SHIFT		6
+#define CS42L52_MIC_CTL_TYPE_MASK		0x20
+#define CS42L52_MIC_CTL_TYPE_SHIFT		5
+
+
+#define CS42L52_PGAA_CTL			0x12
+#define CS42L52_PGAB_CTL			0x13
+#define CS42L52_PGAX_CTL_VOL_12DB		24
+#define CS42L52_PGAX_CTL_VOL_6DB		12 /*step size 0.5db*/
+
+#define CS42L52_PASSTHRUA_VOL			0x14
+#define CS42L52_PASSTHRUB_VOL			0x15
+
+#define CS42L52_ADCA_VOL			0x16
+#define CS42L52_ADCB_VOL			0x17
+#define CS42L52_ADCX_VOL_24DB			24 /*step size 1db*/
+#define CS42L52_ADCX_VOL_12DB			12
+#define CS42L52_ADCX_VOL_6DB			6
+
+#define CS42L52_ADCA_MIXER_VOL			0x18
+#define CS42L52_ADCB_MIXER_VOL			0x19
+#define CS42L52_ADC_MIXER_VOL_12DB		0x18
+
+#define CS42L52_PCMA_MIXER_VOL			0x1A
+#define CS42L52_PCMB_MIXER_VOL			0x1B
+
+#define CS42L52_BEEP_FREQ			0x1C
+#define CS42L52_BEEP_VOL			0x1D
+#define CS42L52_BEEP_TONE_CTL			0x1E
+#define CS42L52_BEEP_RATE_SHIFT			4
+#define CS42L52_BEEP_RATE_MASK			0x0F
+
+#define CS42L52_TONE_CTL			0x1F
+#define CS42L52_BEEP_EN_MASK			0x3F
+
+#define CS42L52_MASTERA_VOL			0x20
+#define CS42L52_MASTERB_VOL			0x21
+
+#define CS42L52_HPA_VOL				0x22
+#define CS42L52_HPB_VOL				0x23
+#define CS42L52_DEFAULT_HP_VOL			0xF0
+
+#define CS42L52_SPKA_VOL			0x24
+#define CS42L52_SPKB_VOL			0x25
+#define CS42L52_DEFAULT_SPK_VOL			0xF0
+
+#define CS42L52_ADC_PCM_MIXER			0x26
+
+#define CS42L52_LIMITER_CTL1			0x27
+#define CS42L52_LIMITER_CTL2			0x28
+#define CS42L52_LIMITER_AT_RATE			0x29
+
+#define CS42L52_ALC_CTL				0x2A
+#define CS42L52_ALC_CTL_ALCB_ENABLE_SHIFT	7
+#define CS42L52_ALC_CTL_ALCA_ENABLE_SHIFT	6
+#define CS42L52_ALC_CTL_FASTEST_ATTACK		0
+
+#define CS42L52_ALC_RATE			0x2B
+#define CS42L52_ALC_SLOWEST_RELEASE		0x3F
+
+#define CS42L52_ALC_THRESHOLD			0x2C
+#define CS42L52_ALC_MAX_RATE_SHIFT		5
+#define CS42L52_ALC_MIN_RATE_SHIFT		2
+#define CS42L52_ALC_RATE_0DB			0
+#define CS42L52_ALC_RATE_3DB			1
+#define CS42L52_ALC_RATE_6DB			2
+
+#define CS42L52_NOISE_GATE_CTL			0x2D
+#define CS42L52_NG_ENABLE_SHIFT			6
+#define CS42L52_NG_THRESHOLD_SHIFT		2
+#define CS42L52_NG_MIN_70DB			2
+#define CS42L52_NG_DELAY_SHIFT			0
+#define CS42L52_NG_DELAY_100MS			1
+
+#define CS42L52_CLK_STATUS			0x2E
+#define CS42L52_BATT_COMPEN			0x2F
+
+#define CS42L52_BATT_LEVEL			0x30
+#define CS42L52_SPK_STATUS			0x31
+#define CS42L52_SPK_STATUS_PIN_SHIFT		3
+#define CS42L52_SPK_STATUS_PIN_HIGH		1
+
+#define CS42L52_TEM_CTL				0x32
+#define CS42L52_TEM_CTL_SET			0x80
+#define CS42L52_THE_FOLDBACK			0x33
+#define CS42L52_CHARGE_PUMP			0x34
+#define CS42L52_CHARGE_PUMP_MASK		0xF0
+#define CS42L52_CHARGE_PUMP_SHIFT		4
+#define CS42L52_FIX_BITS1			0x3E
+#define CS42L52_FIX_BITS2			0x47
+
+#define CS42L52_MAX_REGISTER			0x47
+
+#endif
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
new file mode 100644
index 0000000..a5c8736
--- /dev/null
+++ b/sound/soc/codecs/cs42l56.c
@@ -0,0 +1,1366 @@
+/*
+ * cs42l56.c -- CS42L56 ALSA SoC audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/cs42l56.h>
+#include "cs42l56.h"
+
+#define CS42L56_NUM_SUPPLIES 3
+static const char *const cs42l56_supply_names[CS42L56_NUM_SUPPLIES] = {
+	"VA",
+	"VCP",
+	"VLDO",
+};
+
+struct  cs42l56_private {
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct device *dev;
+	struct cs42l56_platform_data pdata;
+	struct regulator_bulk_data supplies[CS42L56_NUM_SUPPLIES];
+	u32 mclk;
+	u8 mclk_prediv;
+	u8 mclk_div2;
+	u8 mclk_ratio;
+	u8 iface;
+	u8 iface_fmt;
+	u8 iface_inv;
+#if IS_ENABLED(CONFIG_INPUT)
+	struct input_dev *beep;
+	struct work_struct beep_work;
+	int beep_rate;
+#endif
+};
+
+static const struct reg_default cs42l56_reg_defaults[] = {
+	{ 3, 0x7f },	/* r03	- Power Ctl 1 */
+	{ 4, 0xff },	/* r04	- Power Ctl 2 */
+	{ 5, 0x00 },	/* ro5	- Clocking Ctl 1 */
+	{ 6, 0x0b },	/* r06	- Clocking Ctl 2 */
+	{ 7, 0x00 },	/* r07	- Serial Format */
+	{ 8, 0x05 },	/* r08	- Class H Ctl */
+	{ 9, 0x0c },	/* r09	- Misc Ctl */
+	{ 10, 0x80 },	/* r0a	- INT Status */
+	{ 11, 0x00 },	/* r0b	- Playback Ctl */
+	{ 12, 0x0c },	/* r0c	- DSP Mute Ctl */
+	{ 13, 0x00 },	/* r0d	- ADCA Mixer Volume */
+	{ 14, 0x00 },	/* r0e	- ADCB Mixer Volume */
+	{ 15, 0x00 },	/* r0f	- PCMA Mixer Volume */
+	{ 16, 0x00 },	/* r10	- PCMB Mixer Volume */
+	{ 17, 0x00 },	/* r11	- Analog Input Advisory Volume */
+	{ 18, 0x00 },	/* r12	- Digital Input Advisory Volume */
+	{ 19, 0x00 },	/* r13	- Master A Volume */
+	{ 20, 0x00 },	/* r14	- Master B Volume */
+	{ 21, 0x00 },	/* r15	- Beep Freq / On Time */
+	{ 22, 0x00 },	/* r16	- Beep Volume / Off Time */
+	{ 23, 0x00 },	/* r17	- Beep Tone Ctl */
+	{ 24, 0x88 },	/* r18	- Tone Ctl */
+	{ 25, 0x00 },	/* r19	- Channel Mixer & Swap */
+	{ 26, 0x00 },	/* r1a	- AIN Ref Config / ADC Mux */
+	{ 27, 0xa0 },	/* r1b	- High-Pass Filter Ctl */
+	{ 28, 0x00 },	/* r1c	- Misc ADC Ctl */
+	{ 29, 0x00 },	/* r1d	- Gain & Bias Ctl */
+	{ 30, 0x00 },	/* r1e	- PGAA Mux & Volume */
+	{ 31, 0x00 },	/* r1f	- PGAB Mux & Volume */
+	{ 32, 0x00 },	/* r20	- ADCA Attenuator */
+	{ 33, 0x00 },	/* r21	- ADCB Attenuator */
+	{ 34, 0x00 },	/* r22	- ALC Enable & Attack Rate */
+	{ 35, 0xbf },	/* r23	- ALC Release Rate */
+	{ 36, 0x00 },	/* r24	- ALC Threshold */
+	{ 37, 0x00 },	/* r25	- Noise Gate Ctl */
+	{ 38, 0x00 },	/* r26	- ALC, Limiter, SFT, ZeroCross */
+	{ 39, 0x00 },	/* r27	- Analog Mute, LO & HP Mux */
+	{ 40, 0x00 },	/* r28	- HP A Volume */
+	{ 41, 0x00 },	/* r29	- HP B Volume */
+	{ 42, 0x00 },	/* r2a	- LINEOUT A Volume */
+	{ 43, 0x00 },	/* r2b	- LINEOUT B Volume */
+	{ 44, 0x00 },	/* r2c	- Limit Threshold Ctl */
+	{ 45, 0x7f },	/* r2d	- Limiter Ctl & Release Rate */
+	{ 46, 0x00 },	/* r2e	- Limiter Attack Rate */
+};
+
+static bool cs42l56_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS42L56_CHIP_ID_1 ... CS42L56_LIM_ATTACK_RATE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs42l56_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS42L56_INT_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static DECLARE_TLV_DB_SCALE(beep_tlv, -5000, 200, 0);
+static DECLARE_TLV_DB_SCALE(hl_tlv, -6000, 50, 0);
+static DECLARE_TLV_DB_SCALE(adv_tlv, -10200, 50, 0);
+static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, 0);
+static DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
+static DECLARE_TLV_DB_SCALE(preamp_tlv, 0, 1000, 0);
+static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
+
+static const DECLARE_TLV_DB_RANGE(ngnb_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(-8200, 600, 0),
+	2, 5, TLV_DB_SCALE_ITEM(-7600, 300, 0)
+);
+static const DECLARE_TLV_DB_RANGE(ngb_tlv,
+	0, 2, TLV_DB_SCALE_ITEM(-6400, 600, 0),
+	3, 7, TLV_DB_SCALE_ITEM(-4600, 300, 0)
+);
+static const DECLARE_TLV_DB_RANGE(alc_tlv,
+	0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
+	3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0)
+);
+
+static const char * const beep_config_text[] = {
+	"Off", "Single", "Multiple", "Continuous"
+};
+
+static const struct soc_enum beep_config_enum =
+	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 6,
+			ARRAY_SIZE(beep_config_text), beep_config_text);
+
+static const char * const beep_pitch_text[] = {
+	"C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",
+	"C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"
+};
+
+static const struct soc_enum beep_pitch_enum =
+	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 4,
+			ARRAY_SIZE(beep_pitch_text), beep_pitch_text);
+
+static const char * const beep_ontime_text[] = {
+	"86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s",
+	"1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s",
+	"3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"
+};
+
+static const struct soc_enum beep_ontime_enum =
+	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 0,
+			ARRAY_SIZE(beep_ontime_text), beep_ontime_text);
+
+static const char * const beep_offtime_text[] = {
+	"1.23 s", "2.58 s", "3.90 s", "5.20 s",
+	"6.60 s", "8.05 s", "9.35 s", "10.80 s"
+};
+
+static const struct soc_enum beep_offtime_enum =
+	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_OFFTIME, 5,
+			ARRAY_SIZE(beep_offtime_text), beep_offtime_text);
+
+static const char * const beep_treble_text[] = {
+	"5kHz", "7kHz", "10kHz", "15kHz"
+};
+
+static const struct soc_enum beep_treble_enum =
+	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 3,
+			ARRAY_SIZE(beep_treble_text), beep_treble_text);
+
+static const char * const beep_bass_text[] = {
+	"50Hz", "100Hz", "200Hz", "250Hz"
+};
+
+static const struct soc_enum beep_bass_enum =
+	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 1,
+			ARRAY_SIZE(beep_bass_text), beep_bass_text);
+
+static const char * const adc_swap_text[] = {
+	"None", "A+B/2", "A-B/2", "Swap"
+};
+
+static const struct soc_enum adc_swap_enum =
+	SOC_ENUM_SINGLE(CS42L56_MISC_ADC_CTL, 3,
+			ARRAY_SIZE(adc_swap_text), adc_swap_text);
+
+static const char * const pgaa_mux_text[] = {
+	"AIN1A", "AIN2A", "AIN3A"};
+
+static const struct soc_enum pgaa_mux_enum =
+	SOC_ENUM_SINGLE(CS42L56_PGAA_MUX_VOLUME, 0,
+			      ARRAY_SIZE(pgaa_mux_text),
+			      pgaa_mux_text);
+
+static const struct snd_kcontrol_new pgaa_mux =
+	SOC_DAPM_ENUM("Route", pgaa_mux_enum);
+
+static const char * const pgab_mux_text[] = {
+	"AIN1B", "AIN2B", "AIN3B"};
+
+static const struct soc_enum pgab_mux_enum =
+	SOC_ENUM_SINGLE(CS42L56_PGAB_MUX_VOLUME, 0,
+			      ARRAY_SIZE(pgab_mux_text),
+			      pgab_mux_text);
+
+static const struct snd_kcontrol_new pgab_mux =
+	SOC_DAPM_ENUM("Route", pgab_mux_enum);
+
+static const char * const adca_mux_text[] = {
+	"PGAA", "AIN1A", "AIN2A", "AIN3A"};
+
+static const struct soc_enum adca_mux_enum =
+	SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 0,
+			      ARRAY_SIZE(adca_mux_text),
+			      adca_mux_text);
+
+static const struct snd_kcontrol_new adca_mux =
+	SOC_DAPM_ENUM("Route", adca_mux_enum);
+
+static const char * const adcb_mux_text[] = {
+	"PGAB", "AIN1B", "AIN2B", "AIN3B"};
+
+static const struct soc_enum adcb_mux_enum =
+	SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 2,
+			      ARRAY_SIZE(adcb_mux_text),
+			      adcb_mux_text);
+
+static const struct snd_kcontrol_new adcb_mux =
+	SOC_DAPM_ENUM("Route", adcb_mux_enum);
+
+static const char * const left_swap_text[] = {
+	"Left", "LR 2", "Right"};
+
+static const char * const right_swap_text[] = {
+	"Right", "LR 2", "Left"};
+
+static const unsigned int swap_values[] = { 0, 1, 3 };
+
+static const struct soc_enum adca_swap_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 0, 3,
+			      ARRAY_SIZE(left_swap_text),
+			      left_swap_text,
+			      swap_values);
+static const struct snd_kcontrol_new adca_swap_mux =
+	SOC_DAPM_ENUM("Route", adca_swap_enum);
+
+static const struct soc_enum pcma_swap_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 4, 3,
+			      ARRAY_SIZE(left_swap_text),
+			      left_swap_text,
+			      swap_values);
+static const struct snd_kcontrol_new pcma_swap_mux =
+	SOC_DAPM_ENUM("Route", pcma_swap_enum);
+
+static const struct soc_enum adcb_swap_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 2, 3,
+			      ARRAY_SIZE(right_swap_text),
+			      right_swap_text,
+			      swap_values);
+static const struct snd_kcontrol_new adcb_swap_mux =
+	SOC_DAPM_ENUM("Route", adcb_swap_enum);
+
+static const struct soc_enum pcmb_swap_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 6, 3,
+			      ARRAY_SIZE(right_swap_text),
+			      right_swap_text,
+			      swap_values);
+static const struct snd_kcontrol_new pcmb_swap_mux =
+	SOC_DAPM_ENUM("Route", pcmb_swap_enum);
+
+static const struct snd_kcontrol_new hpa_switch =
+	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 6, 1, 1);
+
+static const struct snd_kcontrol_new hpb_switch =
+	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 4, 1, 1);
+
+static const struct snd_kcontrol_new loa_switch =
+	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 2, 1, 1);
+
+static const struct snd_kcontrol_new lob_switch =
+	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 0, 1, 1);
+
+static const char * const hploa_input_text[] = {
+	"DACA", "PGAA"};
+
+static const struct soc_enum lineouta_input_enum =
+	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 2,
+			      ARRAY_SIZE(hploa_input_text),
+			      hploa_input_text);
+
+static const struct snd_kcontrol_new lineouta_input =
+	SOC_DAPM_ENUM("Route", lineouta_input_enum);
+
+static const struct soc_enum hpa_input_enum =
+	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 0,
+			      ARRAY_SIZE(hploa_input_text),
+			      hploa_input_text);
+
+static const struct snd_kcontrol_new hpa_input =
+	SOC_DAPM_ENUM("Route", hpa_input_enum);
+
+static const char * const hplob_input_text[] = {
+	"DACB", "PGAB"};
+
+static const struct soc_enum lineoutb_input_enum =
+	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 3,
+			      ARRAY_SIZE(hplob_input_text),
+			      hplob_input_text);
+
+static const struct snd_kcontrol_new lineoutb_input =
+	SOC_DAPM_ENUM("Route", lineoutb_input_enum);
+
+static const struct soc_enum hpb_input_enum =
+	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 1,
+			      ARRAY_SIZE(hplob_input_text),
+			      hplob_input_text);
+
+static const struct snd_kcontrol_new hpb_input =
+	SOC_DAPM_ENUM("Route", hpb_input_enum);
+
+static const char * const dig_mux_text[] = {
+	"ADC", "DSP"};
+
+static const struct soc_enum dig_mux_enum =
+	SOC_ENUM_SINGLE(CS42L56_MISC_CTL, 7,
+			      ARRAY_SIZE(dig_mux_text),
+			      dig_mux_text);
+
+static const struct snd_kcontrol_new dig_mux =
+	SOC_DAPM_ENUM("Route", dig_mux_enum);
+
+static const char * const hpf_freq_text[] = {
+	"1.8Hz", "119Hz", "236Hz", "464Hz"
+};
+
+static const struct soc_enum hpfa_freq_enum =
+	SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 0,
+			ARRAY_SIZE(hpf_freq_text), hpf_freq_text);
+
+static const struct soc_enum hpfb_freq_enum =
+	SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 2,
+			ARRAY_SIZE(hpf_freq_text), hpf_freq_text);
+
+static const char * const ng_delay_text[] = {
+	"50ms", "100ms", "150ms", "200ms"
+};
+
+static const struct soc_enum ng_delay_enum =
+	SOC_ENUM_SINGLE(CS42L56_NOISE_GATE_CTL, 0,
+			ARRAY_SIZE(ng_delay_text), ng_delay_text);
+
+static const struct snd_kcontrol_new cs42l56_snd_controls[] = {
+
+	SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L56_MASTER_A_VOLUME,
+			      CS42L56_MASTER_B_VOLUME, 0, 0x34, 0xE4, adv_tlv),
+	SOC_DOUBLE("Master Mute Switch", CS42L56_DSP_MUTE_CTL, 0, 1, 1, 1),
+
+	SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L56_ADCA_MIX_VOLUME,
+			      CS42L56_ADCB_MIX_VOLUME, 0, 0x88, 0x90, hl_tlv),
+	SOC_DOUBLE("ADC Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 6, 7, 1, 1),
+
+	SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", CS42L56_PCMA_MIX_VOLUME,
+			      CS42L56_PCMB_MIX_VOLUME, 0, 0x88, 0x90, hl_tlv),
+	SOC_DOUBLE("PCM Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 4, 5, 1, 1),
+
+	SOC_SINGLE_TLV("Analog Advisory Volume",
+			  CS42L56_ANAINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv),
+	SOC_SINGLE_TLV("Digital Advisory Volume",
+			  CS42L56_DIGINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv),
+
+	SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L56_PGAA_MUX_VOLUME,
+			      CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0x24, pga_tlv),
+	SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR,
+			      CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv),
+	SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1),
+	SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1),
+
+	SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME,
+			      CS42L56_HPB_VOLUME, 0, 0x84, 0x48, hl_tlv),
+	SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME,
+			      CS42L56_LOB_VOLUME, 0, 0x84, 0x48, hl_tlv),
+
+	SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL,
+			0, 0x00, 1, tone_tlv),
+	SOC_SINGLE_TLV("Treble Shelving Volume", CS42L56_TONE_CTL,
+			4, 0x00, 1, tone_tlv),
+
+	SOC_DOUBLE_TLV("PGA Preamp Volume", CS42L56_GAIN_BIAS_CTL,
+			4, 6, 0x02, 1, preamp_tlv),
+
+	SOC_SINGLE("DSP Switch", CS42L56_PLAYBACK_CTL, 7, 1, 1),
+	SOC_SINGLE("Gang Playback Switch", CS42L56_PLAYBACK_CTL, 4, 1, 1),
+	SOC_SINGLE("Gang ADC Switch", CS42L56_MISC_ADC_CTL, 7, 1, 1),
+	SOC_SINGLE("Gang PGA Switch", CS42L56_MISC_ADC_CTL, 6, 1, 1),
+
+	SOC_SINGLE("PCMA Invert", CS42L56_PLAYBACK_CTL, 2, 1, 1),
+	SOC_SINGLE("PCMB Invert", CS42L56_PLAYBACK_CTL, 3, 1, 1),
+	SOC_SINGLE("ADCA Invert", CS42L56_MISC_ADC_CTL, 2, 1, 1),
+	SOC_SINGLE("ADCB Invert", CS42L56_MISC_ADC_CTL, 3, 1, 1),
+
+	SOC_DOUBLE("HPF Switch", CS42L56_HPF_CTL, 5, 7, 1, 1),
+	SOC_DOUBLE("HPF Freeze Switch", CS42L56_HPF_CTL, 4, 6, 1, 1),
+	SOC_ENUM("HPFA Corner Freq", hpfa_freq_enum),
+	SOC_ENUM("HPFB Corner Freq", hpfb_freq_enum),
+
+	SOC_SINGLE("Analog Soft Ramp", CS42L56_MISC_CTL, 4, 1, 1),
+	SOC_DOUBLE("Analog Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC,
+		7, 5, 1, 1),
+	SOC_SINGLE("Analog Zero Cross", CS42L56_MISC_CTL, 3, 1, 1),
+	SOC_DOUBLE("Analog Zero Cross Disable", CS42L56_ALC_LIM_SFT_ZC,
+		6, 4, 1, 1),
+	SOC_SINGLE("Digital Soft Ramp", CS42L56_MISC_CTL, 2, 1, 1),
+	SOC_SINGLE("Digital Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC,
+		3, 1, 1),
+
+	SOC_SINGLE("HL Deemphasis", CS42L56_PLAYBACK_CTL, 6, 1, 1),
+
+	SOC_SINGLE("ALC Switch", CS42L56_ALC_EN_ATTACK_RATE, 6, 1, 1),
+	SOC_SINGLE("ALC Limit All Switch", CS42L56_ALC_RELEASE_RATE, 7, 1, 1),
+	SOC_SINGLE_RANGE("ALC Attack", CS42L56_ALC_EN_ATTACK_RATE,
+			0, 0, 0x3f, 0),
+	SOC_SINGLE_RANGE("ALC Release", CS42L56_ALC_RELEASE_RATE,
+			0, 0x3f, 0, 0),
+	SOC_SINGLE_TLV("ALC MAX", CS42L56_ALC_THRESHOLD,
+			5, 0x07, 1, alc_tlv),
+	SOC_SINGLE_TLV("ALC MIN", CS42L56_ALC_THRESHOLD,
+			2, 0x07, 1, alc_tlv),
+
+	SOC_SINGLE("Limiter Switch", CS42L56_LIM_CTL_RELEASE_RATE, 7, 1, 1),
+	SOC_SINGLE("Limit All Switch", CS42L56_LIM_CTL_RELEASE_RATE, 6, 1, 1),
+	SOC_SINGLE_RANGE("Limiter Attack", CS42L56_LIM_ATTACK_RATE,
+			0, 0, 0x3f, 0),
+	SOC_SINGLE_RANGE("Limiter Release", CS42L56_LIM_CTL_RELEASE_RATE,
+			0, 0x3f, 0, 0),
+	SOC_SINGLE_TLV("Limiter MAX", CS42L56_LIM_THRESHOLD_CTL,
+			5, 0x07, 1, alc_tlv),
+	SOC_SINGLE_TLV("Limiter Cushion", CS42L56_ALC_THRESHOLD,
+			2, 0x07, 1, alc_tlv),
+
+	SOC_SINGLE("NG Switch", CS42L56_NOISE_GATE_CTL, 6, 1, 1),
+	SOC_SINGLE("NG All Switch", CS42L56_NOISE_GATE_CTL, 7, 1, 1),
+	SOC_SINGLE("NG Boost Switch", CS42L56_NOISE_GATE_CTL, 5, 1, 1),
+	SOC_SINGLE_TLV("NG Unboost Threshold", CS42L56_NOISE_GATE_CTL,
+			2, 0x07, 1, ngnb_tlv),
+	SOC_SINGLE_TLV("NG Boost Threshold", CS42L56_NOISE_GATE_CTL,
+			2, 0x07, 1, ngb_tlv),
+	SOC_ENUM("NG Delay", ng_delay_enum),
+
+	SOC_ENUM("Beep Config", beep_config_enum),
+	SOC_ENUM("Beep Pitch", beep_pitch_enum),
+	SOC_ENUM("Beep on Time", beep_ontime_enum),
+	SOC_ENUM("Beep off Time", beep_offtime_enum),
+	SOC_SINGLE_SX_TLV("Beep Volume", CS42L56_BEEP_FREQ_OFFTIME,
+			0, 0x07, 0x23, beep_tlv),
+	SOC_SINGLE("Beep Tone Ctl Switch", CS42L56_BEEP_TONE_CFG, 0, 1, 1),
+	SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum),
+	SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum),
+
+};
+
+static const struct snd_soc_dapm_widget cs42l56_dapm_widgets[] = {
+
+	SND_SOC_DAPM_SIGGEN("Beep"),
+	SND_SOC_DAPM_SUPPLY("VBUF", CS42L56_PWRCTL_1, 5, 1, NULL, 0),
+	SND_SOC_DAPM_MICBIAS("MIC1 Bias", CS42L56_PWRCTL_1, 4, 1),
+	SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L56_PWRCTL_1, 3, 1, NULL, 0),
+
+	SND_SOC_DAPM_INPUT("AIN1A"),
+	SND_SOC_DAPM_INPUT("AIN2A"),
+	SND_SOC_DAPM_INPUT("AIN1B"),
+	SND_SOC_DAPM_INPUT("AIN2B"),
+	SND_SOC_DAPM_INPUT("AIN3A"),
+	SND_SOC_DAPM_INPUT("AIN3B"),
+
+	SND_SOC_DAPM_AIF_OUT("SDOUT", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_IN("SDIN", NULL,  0,
+			SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MUX("Digital Output Mux", SND_SOC_NOPM,
+			 0, 0, &dig_mux),
+
+	SND_SOC_DAPM_PGA("PGAA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PGAB", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("PGAA Input Mux",
+			SND_SOC_NOPM, 0, 0, &pgaa_mux),
+	SND_SOC_DAPM_MUX("PGAB Input Mux",
+			SND_SOC_NOPM, 0, 0, &pgab_mux),
+
+	SND_SOC_DAPM_MUX("ADCA Mux", SND_SOC_NOPM,
+			 0, 0, &adca_mux),
+	SND_SOC_DAPM_MUX("ADCB Mux", SND_SOC_NOPM,
+			 0, 0, &adcb_mux),
+
+	SND_SOC_DAPM_ADC("ADCA", NULL, CS42L56_PWRCTL_1, 1, 1),
+	SND_SOC_DAPM_ADC("ADCB", NULL, CS42L56_PWRCTL_1, 2, 1),
+
+	SND_SOC_DAPM_MUX("ADCA Swap Mux", SND_SOC_NOPM, 0, 0,
+		&adca_swap_mux),
+	SND_SOC_DAPM_MUX("ADCB Swap Mux", SND_SOC_NOPM, 0, 0,
+		&adcb_swap_mux),
+
+	SND_SOC_DAPM_MUX("PCMA Swap Mux", SND_SOC_NOPM, 0, 0,
+		&pcma_swap_mux),
+	SND_SOC_DAPM_MUX("PCMB Swap Mux", SND_SOC_NOPM, 0, 0,
+		&pcmb_swap_mux),
+
+	SND_SOC_DAPM_DAC("DACA", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DACB", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPA"),
+	SND_SOC_DAPM_OUTPUT("LOA"),
+	SND_SOC_DAPM_OUTPUT("HPB"),
+	SND_SOC_DAPM_OUTPUT("LOB"),
+
+	SND_SOC_DAPM_SWITCH("Headphone Right",
+			    CS42L56_PWRCTL_2, 4, 1, &hpb_switch),
+	SND_SOC_DAPM_SWITCH("Headphone Left",
+			    CS42L56_PWRCTL_2, 6, 1, &hpa_switch),
+
+	SND_SOC_DAPM_SWITCH("Lineout Right",
+			    CS42L56_PWRCTL_2, 0, 1, &lob_switch),
+	SND_SOC_DAPM_SWITCH("Lineout Left",
+			    CS42L56_PWRCTL_2, 2, 1, &loa_switch),
+
+	SND_SOC_DAPM_MUX("LINEOUTA Input Mux", SND_SOC_NOPM,
+			 0, 0, &lineouta_input),
+	SND_SOC_DAPM_MUX("LINEOUTB Input Mux", SND_SOC_NOPM,
+			 0, 0, &lineoutb_input),
+	SND_SOC_DAPM_MUX("HPA Input Mux", SND_SOC_NOPM,
+			 0, 0, &hpa_input),
+	SND_SOC_DAPM_MUX("HPB Input Mux", SND_SOC_NOPM,
+			 0, 0, &hpb_input),
+
+};
+
+static const struct snd_soc_dapm_route cs42l56_audio_map[] = {
+
+	{"HiFi Capture", "DSP", "Digital Output Mux"},
+	{"HiFi Capture", "ADC", "Digital Output Mux"},
+
+	{"Digital Output Mux", NULL, "ADCA"},
+	{"Digital Output Mux", NULL, "ADCB"},
+
+	{"ADCB", NULL, "ADCB Swap Mux"},
+	{"ADCA", NULL, "ADCA Swap Mux"},
+
+	{"ADCA Swap Mux", NULL, "ADCA"},
+	{"ADCB Swap Mux", NULL, "ADCB"},
+
+	{"DACA", "Left", "ADCA Swap Mux"},
+	{"DACA", "LR 2", "ADCA Swap Mux"},
+	{"DACA", "Right", "ADCA Swap Mux"},
+
+	{"DACB", "Left", "ADCB Swap Mux"},
+	{"DACB", "LR 2", "ADCB Swap Mux"},
+	{"DACB", "Right", "ADCB Swap Mux"},
+
+	{"ADCA Mux", NULL, "AIN3A"},
+	{"ADCA Mux", NULL, "AIN2A"},
+	{"ADCA Mux", NULL, "AIN1A"},
+	{"ADCA Mux", NULL, "PGAA"},
+	{"ADCB Mux", NULL, "AIN3B"},
+	{"ADCB Mux", NULL, "AIN2B"},
+	{"ADCB Mux", NULL, "AIN1B"},
+	{"ADCB Mux", NULL, "PGAB"},
+
+	{"PGAA", "AIN1A", "PGAA Input Mux"},
+	{"PGAA", "AIN2A", "PGAA Input Mux"},
+	{"PGAA", "AIN3A", "PGAA Input Mux"},
+	{"PGAB", "AIN1B", "PGAB Input Mux"},
+	{"PGAB", "AIN2B", "PGAB Input Mux"},
+	{"PGAB", "AIN3B", "PGAB Input Mux"},
+
+	{"PGAA Input Mux", NULL, "AIN1A"},
+	{"PGAA Input Mux", NULL, "AIN2A"},
+	{"PGAA Input Mux", NULL, "AIN3A"},
+	{"PGAB Input Mux", NULL, "AIN1B"},
+	{"PGAB Input Mux", NULL, "AIN2B"},
+	{"PGAB Input Mux", NULL, "AIN3B"},
+
+	{"LOB", "Switch", "LINEOUTB Input Mux"},
+	{"LOA", "Switch", "LINEOUTA Input Mux"},
+
+	{"LINEOUTA Input Mux", "PGAA", "PGAA"},
+	{"LINEOUTB Input Mux", "PGAB", "PGAB"},
+	{"LINEOUTA Input Mux", "DACA", "DACA"},
+	{"LINEOUTB Input Mux", "DACB", "DACB"},
+
+	{"HPA", "Switch", "HPB Input Mux"},
+	{"HPB", "Switch", "HPA Input Mux"},
+
+	{"HPA Input Mux", "PGAA", "PGAA"},
+	{"HPB Input Mux", "PGAB", "PGAB"},
+	{"HPA Input Mux", "DACA", "DACA"},
+	{"HPB Input Mux", "DACB", "DACB"},
+
+	{"DACA", NULL, "PCMA Swap Mux"},
+	{"DACB", NULL, "PCMB Swap Mux"},
+
+	{"PCMB Swap Mux", "Left", "HiFi Playback"},
+	{"PCMB Swap Mux", "LR 2", "HiFi Playback"},
+	{"PCMB Swap Mux", "Right", "HiFi Playback"},
+
+	{"PCMA Swap Mux", "Left", "HiFi Playback"},
+	{"PCMA Swap Mux", "LR 2", "HiFi Playback"},
+	{"PCMA Swap Mux", "Right", "HiFi Playback"},
+
+};
+
+struct cs42l56_clk_para {
+	u32 mclk;
+	u32 srate;
+	u8 ratio;
+};
+
+static const struct cs42l56_clk_para clk_ratio_table[] = {
+	/* 8k */
+	{ 6000000, 8000, CS42L56_MCLK_LRCLK_768 },
+	{ 6144000, 8000, CS42L56_MCLK_LRCLK_750 },
+	{ 12000000, 8000, CS42L56_MCLK_LRCLK_768 },
+	{ 12288000, 8000, CS42L56_MCLK_LRCLK_750 },
+	{ 24000000, 8000, CS42L56_MCLK_LRCLK_768 },
+	{ 24576000, 8000, CS42L56_MCLK_LRCLK_750 },
+	/* 11.025k */
+	{ 5644800, 11025, CS42L56_MCLK_LRCLK_512},
+	{ 11289600, 11025, CS42L56_MCLK_LRCLK_512},
+	{ 22579200, 11025, CS42L56_MCLK_LRCLK_512 },
+	/* 11.0294k */
+	{ 6000000, 110294, CS42L56_MCLK_LRCLK_544 },
+	{ 12000000, 110294, CS42L56_MCLK_LRCLK_544 },
+	{ 24000000, 110294, CS42L56_MCLK_LRCLK_544 },
+	/* 12k */
+	{ 6000000, 12000, CS42L56_MCLK_LRCLK_500 },
+	{ 6144000, 12000, CS42L56_MCLK_LRCLK_512 },
+	{ 12000000, 12000, CS42L56_MCLK_LRCLK_500 },
+	{ 12288000, 12000, CS42L56_MCLK_LRCLK_512 },
+	{ 24000000, 12000, CS42L56_MCLK_LRCLK_500 },
+	{ 24576000, 12000, CS42L56_MCLK_LRCLK_512 },
+	/* 16k */
+	{ 6000000, 16000, CS42L56_MCLK_LRCLK_375 },
+	{ 6144000, 16000, CS42L56_MCLK_LRCLK_384 },
+	{ 12000000, 16000, CS42L56_MCLK_LRCLK_375 },
+	{ 12288000, 16000, CS42L56_MCLK_LRCLK_384 },
+	{ 24000000, 16000, CS42L56_MCLK_LRCLK_375 },
+	{ 24576000, 16000, CS42L56_MCLK_LRCLK_384 },
+	/* 22.050k */
+	{ 5644800, 22050, CS42L56_MCLK_LRCLK_256 },
+	{ 11289600, 22050, CS42L56_MCLK_LRCLK_256 },
+	{ 22579200, 22050, CS42L56_MCLK_LRCLK_256 },
+	/* 22.0588k */
+	{ 6000000, 220588, CS42L56_MCLK_LRCLK_272 },
+	{ 12000000, 220588, CS42L56_MCLK_LRCLK_272 },
+	{ 24000000, 220588, CS42L56_MCLK_LRCLK_272 },
+	/* 24k */
+	{ 6000000, 24000, CS42L56_MCLK_LRCLK_250 },
+	{ 6144000, 24000, CS42L56_MCLK_LRCLK_256 },
+	{ 12000000, 24000, CS42L56_MCLK_LRCLK_250 },
+	{ 12288000, 24000, CS42L56_MCLK_LRCLK_256 },
+	{ 24000000, 24000, CS42L56_MCLK_LRCLK_250 },
+	{ 24576000, 24000, CS42L56_MCLK_LRCLK_256 },
+	/* 32k */
+	{ 6000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
+	{ 6144000, 32000, CS42L56_MCLK_LRCLK_192 },
+	{ 12000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
+	{ 12288000, 32000, CS42L56_MCLK_LRCLK_192 },
+	{ 24000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
+	{ 24576000, 32000, CS42L56_MCLK_LRCLK_192 },
+	/* 44.118k */
+	{ 6000000, 44118, CS42L56_MCLK_LRCLK_136 },
+	{ 12000000, 44118, CS42L56_MCLK_LRCLK_136 },
+	{ 24000000, 44118, CS42L56_MCLK_LRCLK_136 },
+	/* 44.1k */
+	{ 5644800, 44100, CS42L56_MCLK_LRCLK_128 },
+	{ 11289600, 44100, CS42L56_MCLK_LRCLK_128 },
+	{ 22579200, 44100, CS42L56_MCLK_LRCLK_128 },
+	/* 48k */
+	{ 6000000, 48000, CS42L56_MCLK_LRCLK_125 },
+	{ 6144000, 48000, CS42L56_MCLK_LRCLK_128 },
+	{ 12000000, 48000, CS42L56_MCLK_LRCLK_125 },
+	{ 12288000, 48000, CS42L56_MCLK_LRCLK_128 },
+	{ 24000000, 48000, CS42L56_MCLK_LRCLK_125 },
+	{ 24576000, 48000, CS42L56_MCLK_LRCLK_128 },
+};
+
+static int cs42l56_get_mclk_ratio(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(clk_ratio_table); i++) {
+		if (clk_ratio_table[i].mclk == mclk &&
+		    clk_ratio_table[i].srate == rate)
+			return clk_ratio_table[i].ratio;
+	}
+	return -EINVAL;
+}
+
+static int cs42l56_set_sysclk(struct snd_soc_dai *codec_dai,
+			int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
+
+	switch (freq) {
+	case CS42L56_MCLK_5P6448MHZ:
+	case CS42L56_MCLK_6MHZ:
+	case CS42L56_MCLK_6P144MHZ:
+		cs42l56->mclk_div2 = 0;
+		cs42l56->mclk_prediv = 0;
+		break;
+	case CS42L56_MCLK_11P2896MHZ:
+	case CS42L56_MCLK_12MHZ:
+	case CS42L56_MCLK_12P288MHZ:
+		cs42l56->mclk_div2 = CS42L56_MCLK_DIV2;
+		cs42l56->mclk_prediv = 0;
+		break;
+	case CS42L56_MCLK_22P5792MHZ:
+	case CS42L56_MCLK_24MHZ:
+	case CS42L56_MCLK_24P576MHZ:
+		cs42l56->mclk_div2 = CS42L56_MCLK_DIV2;
+		cs42l56->mclk_prediv = CS42L56_MCLK_PREDIV;
+		break;
+	default:
+		return -EINVAL;
+	}
+	cs42l56->mclk = freq;
+
+	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
+			    CS42L56_MCLK_PREDIV_MASK,
+				cs42l56->mclk_prediv);
+	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
+			    CS42L56_MCLK_DIV2_MASK,
+				cs42l56->mclk_div2);
+
+	return 0;
+}
+
+static int cs42l56_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		cs42l56->iface = CS42L56_MASTER_MODE;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		cs42l56->iface = CS42L56_SLAVE_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	 /* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		cs42l56->iface_fmt = CS42L56_DIG_FMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		cs42l56->iface_fmt = CS42L56_DIG_FMT_LEFT_J;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* sclk inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		cs42l56->iface_inv = 0;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		cs42l56->iface_inv = CS42L56_SCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
+			    CS42L56_MS_MODE_MASK, cs42l56->iface);
+	snd_soc_component_update_bits(component, CS42L56_SERIAL_FMT,
+			    CS42L56_DIG_FMT_MASK, cs42l56->iface_fmt);
+	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
+			    CS42L56_SCLK_INV_MASK, cs42l56->iface_inv);
+	return 0;
+}
+
+static int cs42l56_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute) {
+		/* Hit the DSP Mixer first */
+		snd_soc_component_update_bits(component, CS42L56_DSP_MUTE_CTL,
+				    CS42L56_ADCAMIX_MUTE_MASK |
+				    CS42L56_ADCBMIX_MUTE_MASK |
+				    CS42L56_PCMAMIX_MUTE_MASK |
+				    CS42L56_PCMBMIX_MUTE_MASK |
+				    CS42L56_MSTB_MUTE_MASK |
+				    CS42L56_MSTA_MUTE_MASK,
+				    CS42L56_MUTE_ALL);
+		/* Mute ADC's */
+		snd_soc_component_update_bits(component, CS42L56_MISC_ADC_CTL,
+				    CS42L56_ADCA_MUTE_MASK |
+				    CS42L56_ADCB_MUTE_MASK,
+				    CS42L56_MUTE_ALL);
+		/* HP And LO */
+		snd_soc_component_update_bits(component, CS42L56_HPA_VOLUME,
+				    CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL);
+		snd_soc_component_update_bits(component, CS42L56_HPB_VOLUME,
+				    CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL);
+		snd_soc_component_update_bits(component, CS42L56_LOA_VOLUME,
+				    CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL);
+		snd_soc_component_update_bits(component, CS42L56_LOB_VOLUME,
+				    CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL);
+	} else {
+		snd_soc_component_update_bits(component, CS42L56_DSP_MUTE_CTL,
+				    CS42L56_ADCAMIX_MUTE_MASK |
+				    CS42L56_ADCBMIX_MUTE_MASK |
+				    CS42L56_PCMAMIX_MUTE_MASK |
+				    CS42L56_PCMBMIX_MUTE_MASK |
+				    CS42L56_MSTB_MUTE_MASK |
+				    CS42L56_MSTA_MUTE_MASK,
+				    CS42L56_UNMUTE);
+
+		snd_soc_component_update_bits(component, CS42L56_MISC_ADC_CTL,
+				    CS42L56_ADCA_MUTE_MASK |
+				    CS42L56_ADCB_MUTE_MASK,
+				    CS42L56_UNMUTE);
+
+		snd_soc_component_update_bits(component, CS42L56_HPA_VOLUME,
+				    CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE);
+		snd_soc_component_update_bits(component, CS42L56_HPB_VOLUME,
+				    CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE);
+		snd_soc_component_update_bits(component, CS42L56_LOA_VOLUME,
+				    CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE);
+		snd_soc_component_update_bits(component, CS42L56_LOB_VOLUME,
+				    CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE);
+	}
+	return 0;
+}
+
+static int cs42l56_pcm_hw_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params,
+				     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
+	int ratio;
+
+	ratio = cs42l56_get_mclk_ratio(cs42l56->mclk, params_rate(params));
+	if (ratio >= 0) {
+		snd_soc_component_update_bits(component, CS42L56_CLKCTL_2,
+				    CS42L56_CLK_RATIO_MASK, ratio);
+	} else {
+		dev_err(component->dev, "unsupported mclk/sclk/lrclk ratio\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cs42l56_set_bias_level(struct snd_soc_component *component,
+					enum snd_soc_bias_level level)
+{
+	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
+				    CS42L56_MCLK_DIS_MASK, 0);
+		snd_soc_component_update_bits(component, CS42L56_PWRCTL_1,
+				    CS42L56_PDN_ALL_MASK, 0);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			regcache_cache_only(cs42l56->regmap, false);
+			regcache_sync(cs42l56->regmap);
+			ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
+						    cs42l56->supplies);
+			if (ret != 0) {
+				dev_err(cs42l56->dev,
+					"Failed to enable regulators: %d\n",
+					ret);
+				return ret;
+			}
+		}
+		snd_soc_component_update_bits(component, CS42L56_PWRCTL_1,
+				    CS42L56_PDN_ALL_MASK, 1);
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, CS42L56_PWRCTL_1,
+				    CS42L56_PDN_ALL_MASK, 1);
+		snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
+				    CS42L56_MCLK_DIS_MASK, 1);
+		regcache_cache_only(cs42l56->regmap, true);
+		regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
+						    cs42l56->supplies);
+		break;
+	}
+
+	return 0;
+}
+
+#define CS42L56_RATES (SNDRV_PCM_RATE_8000_48000)
+
+#define CS42L56_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static const struct snd_soc_dai_ops cs42l56_ops = {
+	.hw_params	= cs42l56_pcm_hw_params,
+	.digital_mute	= cs42l56_digital_mute,
+	.set_fmt	= cs42l56_set_dai_fmt,
+	.set_sysclk	= cs42l56_set_sysclk,
+};
+
+static struct snd_soc_dai_driver cs42l56_dai = {
+		.name = "cs42l56",
+		.playback = {
+			.stream_name = "HiFi Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS42L56_RATES,
+			.formats = CS42L56_FORMATS,
+		},
+		.capture = {
+			.stream_name = "HiFi Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS42L56_RATES,
+			.formats = CS42L56_FORMATS,
+		},
+		.ops = &cs42l56_ops,
+};
+
+static int beep_freq[] = {
+	261, 522, 585, 667, 706, 774, 889, 1000,
+	1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
+};
+
+static void cs42l56_beep_work(struct work_struct *work)
+{
+	struct cs42l56_private *cs42l56 =
+		container_of(work, struct cs42l56_private, beep_work);
+	struct snd_soc_component *component = cs42l56->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int i;
+	int val = 0;
+	int best = 0;
+
+	if (cs42l56->beep_rate) {
+		for (i = 0; i < ARRAY_SIZE(beep_freq); i++) {
+			if (abs(cs42l56->beep_rate - beep_freq[i]) <
+			    abs(cs42l56->beep_rate - beep_freq[best]))
+				best = i;
+		}
+
+		dev_dbg(component->dev, "Set beep rate %dHz for requested %dHz\n",
+			beep_freq[best], cs42l56->beep_rate);
+
+		val = (best << CS42L56_BEEP_RATE_SHIFT);
+
+		snd_soc_dapm_enable_pin(dapm, "Beep");
+	} else {
+		dev_dbg(component->dev, "Disabling beep\n");
+		snd_soc_dapm_disable_pin(dapm, "Beep");
+	}
+
+	snd_soc_component_update_bits(component, CS42L56_BEEP_FREQ_ONTIME,
+			    CS42L56_BEEP_FREQ_MASK, val);
+
+	snd_soc_dapm_sync(dapm);
+}
+
+/* For usability define a way of injecting beep events for the device -
+ * many systems will not have a keyboard.
+ */
+static int cs42l56_beep_event(struct input_dev *dev, unsigned int type,
+			     unsigned int code, int hz)
+{
+	struct snd_soc_component *component = input_get_drvdata(dev);
+	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "Beep event %x %x\n", code, hz);
+
+	switch (code) {
+	case SND_BELL:
+		if (hz)
+			hz = 261;
+	case SND_TONE:
+		break;
+	default:
+		return -1;
+	}
+
+	/* Kick the beep from a workqueue */
+	cs42l56->beep_rate = hz;
+	schedule_work(&cs42l56->beep_work);
+	return 0;
+}
+
+static ssize_t cs42l56_beep_set(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct cs42l56_private *cs42l56 = dev_get_drvdata(dev);
+	long int time;
+	int ret;
+
+	ret = kstrtol(buf, 10, &time);
+	if (ret != 0)
+		return ret;
+
+	input_event(cs42l56->beep, EV_SND, SND_TONE, time);
+
+	return count;
+}
+
+static DEVICE_ATTR(beep, 0200, NULL, cs42l56_beep_set);
+
+static void cs42l56_init_beep(struct snd_soc_component *component)
+{
+	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	cs42l56->beep = devm_input_allocate_device(component->dev);
+	if (!cs42l56->beep) {
+		dev_err(component->dev, "Failed to allocate beep device\n");
+		return;
+	}
+
+	INIT_WORK(&cs42l56->beep_work, cs42l56_beep_work);
+	cs42l56->beep_rate = 0;
+
+	cs42l56->beep->name = "CS42L56 Beep Generator";
+	cs42l56->beep->phys = dev_name(component->dev);
+	cs42l56->beep->id.bustype = BUS_I2C;
+
+	cs42l56->beep->evbit[0] = BIT_MASK(EV_SND);
+	cs42l56->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+	cs42l56->beep->event = cs42l56_beep_event;
+	cs42l56->beep->dev.parent = component->dev;
+	input_set_drvdata(cs42l56->beep, component);
+
+	ret = input_register_device(cs42l56->beep);
+	if (ret != 0) {
+		cs42l56->beep = NULL;
+		dev_err(component->dev, "Failed to register beep device\n");
+	}
+
+	ret = device_create_file(component->dev, &dev_attr_beep);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to create keyclick file: %d\n",
+			ret);
+	}
+}
+
+static void cs42l56_free_beep(struct snd_soc_component *component)
+{
+	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
+
+	device_remove_file(component->dev, &dev_attr_beep);
+	cancel_work_sync(&cs42l56->beep_work);
+	cs42l56->beep = NULL;
+
+	snd_soc_component_update_bits(component, CS42L56_BEEP_TONE_CFG,
+			    CS42L56_BEEP_EN_MASK, 0);
+}
+
+static int cs42l56_probe(struct snd_soc_component *component)
+{
+	cs42l56_init_beep(component);
+
+	return 0;
+}
+
+static void cs42l56_remove(struct snd_soc_component *component)
+{
+	cs42l56_free_beep(component);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_cs42l56 = {
+	.probe			= cs42l56_probe,
+	.remove			= cs42l56_remove,
+	.set_bias_level		= cs42l56_set_bias_level,
+	.controls		= cs42l56_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs42l56_snd_controls),
+	.dapm_widgets		= cs42l56_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs42l56_dapm_widgets),
+	.dapm_routes		= cs42l56_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs42l56_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config cs42l56_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = CS42L56_MAX_REGISTER,
+	.reg_defaults = cs42l56_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(cs42l56_reg_defaults),
+	.readable_reg = cs42l56_readable_register,
+	.volatile_reg = cs42l56_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int cs42l56_handle_of_data(struct i2c_client *i2c_client,
+				    struct cs42l56_platform_data *pdata)
+{
+	struct device_node *np = i2c_client->dev.of_node;
+	u32 val32;
+
+	if (of_property_read_bool(np, "cirrus,ain1a-reference-cfg"))
+		pdata->ain1a_ref_cfg = true;
+
+	if (of_property_read_bool(np, "cirrus,ain2a-reference-cfg"))
+		pdata->ain2a_ref_cfg = true;
+
+	if (of_property_read_bool(np, "cirrus,ain1b-reference-cfg"))
+		pdata->ain1b_ref_cfg = true;
+
+	if (of_property_read_bool(np, "cirrus,ain2b-reference-cfg"))
+		pdata->ain2b_ref_cfg = true;
+
+	if (of_property_read_u32(np, "cirrus,micbias-lvl", &val32) >= 0)
+		pdata->micbias_lvl = val32;
+
+	if (of_property_read_u32(np, "cirrus,chgfreq-divisor", &val32) >= 0)
+		pdata->chgfreq = val32;
+
+	if (of_property_read_u32(np, "cirrus,adaptive-pwr-cfg", &val32) >= 0)
+		pdata->adaptive_pwr = val32;
+
+	if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
+		pdata->hpfa_freq = val32;
+
+	if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
+		pdata->hpfb_freq = val32;
+
+	pdata->gpio_nreset = of_get_named_gpio(np, "cirrus,gpio-nreset", 0);
+
+	return 0;
+}
+
+static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
+			     const struct i2c_device_id *id)
+{
+	struct cs42l56_private *cs42l56;
+	struct cs42l56_platform_data *pdata =
+		dev_get_platdata(&i2c_client->dev);
+	int ret, i;
+	unsigned int devid = 0;
+	unsigned int alpha_rev, metal_rev;
+	unsigned int reg;
+
+	cs42l56 = devm_kzalloc(&i2c_client->dev, sizeof(*cs42l56), GFP_KERNEL);
+	if (cs42l56 == NULL)
+		return -ENOMEM;
+	cs42l56->dev = &i2c_client->dev;
+
+	cs42l56->regmap = devm_regmap_init_i2c(i2c_client, &cs42l56_regmap);
+	if (IS_ERR(cs42l56->regmap)) {
+		ret = PTR_ERR(cs42l56->regmap);
+		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	if (pdata) {
+		cs42l56->pdata = *pdata;
+	} else {
+		pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
+				     GFP_KERNEL);
+		if (!pdata)
+			return -ENOMEM;
+
+		if (i2c_client->dev.of_node) {
+			ret = cs42l56_handle_of_data(i2c_client,
+						     &cs42l56->pdata);
+			if (ret != 0)
+				return ret;
+		}
+		cs42l56->pdata = *pdata;
+	}
+
+	if (cs42l56->pdata.gpio_nreset) {
+		ret = gpio_request_one(cs42l56->pdata.gpio_nreset,
+				       GPIOF_OUT_INIT_HIGH, "CS42L56 /RST");
+		if (ret < 0) {
+			dev_err(&i2c_client->dev,
+				"Failed to request /RST %d: %d\n",
+				cs42l56->pdata.gpio_nreset, ret);
+			return ret;
+		}
+		gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 0);
+		gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 1);
+	}
+
+
+	i2c_set_clientdata(i2c_client, cs42l56);
+
+	for (i = 0; i < ARRAY_SIZE(cs42l56->supplies); i++)
+		cs42l56->supplies[i].supply = cs42l56_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c_client->dev,
+				      ARRAY_SIZE(cs42l56->supplies),
+				      cs42l56->supplies);
+	if (ret != 0) {
+		dev_err(&i2c_client->dev,
+			"Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
+				    cs42l56->supplies);
+	if (ret != 0) {
+		dev_err(&i2c_client->dev,
+			"Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, &reg);
+	devid = reg & CS42L56_CHIP_ID_MASK;
+	if (devid != CS42L56_DEVID) {
+		dev_err(&i2c_client->dev,
+			"CS42L56 Device ID (%X). Expected %X\n",
+			devid, CS42L56_DEVID);
+		goto err_enable;
+	}
+	alpha_rev = reg & CS42L56_AREV_MASK;
+	metal_rev = reg & CS42L56_MTLREV_MASK;
+
+	dev_info(&i2c_client->dev, "Cirrus Logic CS42L56 ");
+	dev_info(&i2c_client->dev, "Alpha Rev %X Metal Rev %X\n",
+		 alpha_rev, metal_rev);
+
+	if (cs42l56->pdata.ain1a_ref_cfg)
+		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
+				   CS42L56_AIN1A_REF_MASK,
+				   CS42L56_AIN1A_REF_MASK);
+
+	if (cs42l56->pdata.ain1b_ref_cfg)
+		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
+				   CS42L56_AIN1B_REF_MASK,
+				   CS42L56_AIN1B_REF_MASK);
+
+	if (cs42l56->pdata.ain2a_ref_cfg)
+		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
+				   CS42L56_AIN2A_REF_MASK,
+				   CS42L56_AIN2A_REF_MASK);
+
+	if (cs42l56->pdata.ain2b_ref_cfg)
+		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
+				   CS42L56_AIN2B_REF_MASK,
+				   CS42L56_AIN2B_REF_MASK);
+
+	if (cs42l56->pdata.micbias_lvl)
+		regmap_update_bits(cs42l56->regmap, CS42L56_GAIN_BIAS_CTL,
+				   CS42L56_MIC_BIAS_MASK,
+				cs42l56->pdata.micbias_lvl);
+
+	if (cs42l56->pdata.chgfreq)
+		regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL,
+				   CS42L56_CHRG_FREQ_MASK,
+				cs42l56->pdata.chgfreq);
+
+	if (cs42l56->pdata.hpfb_freq)
+		regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL,
+				   CS42L56_HPFB_FREQ_MASK,
+				cs42l56->pdata.hpfb_freq);
+
+	if (cs42l56->pdata.hpfa_freq)
+		regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL,
+				   CS42L56_HPFA_FREQ_MASK,
+				cs42l56->pdata.hpfa_freq);
+
+	if (cs42l56->pdata.adaptive_pwr)
+		regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL,
+				   CS42L56_ADAPT_PWR_MASK,
+				cs42l56->pdata.adaptive_pwr);
+
+	ret =  devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_dev_cs42l56, &cs42l56_dai, 1);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
+			       cs42l56->supplies);
+	return ret;
+}
+
+static int cs42l56_i2c_remove(struct i2c_client *client)
+{
+	struct cs42l56_private *cs42l56 = i2c_get_clientdata(client);
+
+	regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
+			       cs42l56->supplies);
+	return 0;
+}
+
+static const struct of_device_id cs42l56_of_match[] = {
+	{ .compatible = "cirrus,cs42l56", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cs42l56_of_match);
+
+
+static const struct i2c_device_id cs42l56_id[] = {
+	{ "cs42l56", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cs42l56_id);
+
+static struct i2c_driver cs42l56_i2c_driver = {
+	.driver = {
+		.name = "cs42l56",
+		.of_match_table = cs42l56_of_match,
+	},
+	.id_table = cs42l56_id,
+	.probe =    cs42l56_i2c_probe,
+	.remove =   cs42l56_i2c_remove,
+};
+
+module_i2c_driver(cs42l56_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L56 driver");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l56.h b/sound/soc/codecs/cs42l56.h
new file mode 100644
index 0000000..5025ec9
--- /dev/null
+++ b/sound/soc/codecs/cs42l56.h
@@ -0,0 +1,177 @@
+/*
+ * cs42l52.h -- CS42L56 ALSA SoC audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CS42L56_H__
+#define __CS42L56_H__
+
+#define CS42L56_CHIP_ID_1		0x01
+#define CS42L56_CHIP_ID_2		0x02
+#define CS42L56_PWRCTL_1		0x03
+#define CS42L56_PWRCTL_2		0x04
+#define CS42L56_CLKCTL_1		0x05
+#define CS42L56_CLKCTL_2		0x06
+#define CS42L56_SERIAL_FMT		0x07
+#define CS42L56_CLASSH_CTL		0x08
+#define CS42L56_MISC_CTL		0x09
+#define CS42L56_INT_STATUS		0x0a
+#define CS42L56_PLAYBACK_CTL		0x0b
+#define CS42L56_DSP_MUTE_CTL		0x0c
+#define CS42L56_ADCA_MIX_VOLUME		0x0d
+#define CS42L56_ADCB_MIX_VOLUME		0x0e
+#define CS42L56_PCMA_MIX_VOLUME		0x0f
+#define CS42L56_PCMB_MIX_VOLUME		0x10
+#define CS42L56_ANAINPUT_ADV_VOLUME	0x11
+#define CS42L56_DIGINPUT_ADV_VOLUME	0x12
+#define CS42L56_MASTER_A_VOLUME		0x13
+#define CS42L56_MASTER_B_VOLUME		0x14
+#define CS42L56_BEEP_FREQ_ONTIME	0x15
+#define CS42L56_BEEP_FREQ_OFFTIME	0x16
+#define CS42L56_BEEP_TONE_CFG		0x17
+#define CS42L56_TONE_CTL		0x18
+#define CS42L56_CHAN_MIX_SWAP		0x19
+#define CS42L56_AIN_REFCFG_ADC_MUX	0x1a
+#define CS42L56_HPF_CTL			0x1b
+#define CS42L56_MISC_ADC_CTL		0x1c
+#define CS42L56_GAIN_BIAS_CTL		0x1d
+#define CS42L56_PGAA_MUX_VOLUME		0x1e
+#define CS42L56_PGAB_MUX_VOLUME		0x1f
+#define CS42L56_ADCA_ATTENUATOR		0x20
+#define CS42L56_ADCB_ATTENUATOR		0x21
+#define CS42L56_ALC_EN_ATTACK_RATE	0x22
+#define CS42L56_ALC_RELEASE_RATE	0x23
+#define CS42L56_ALC_THRESHOLD		0x24
+#define CS42L56_NOISE_GATE_CTL		0x25
+#define CS42L56_ALC_LIM_SFT_ZC		0x26
+#define CS42L56_AMUTE_HPLO_MUX		0x27
+#define CS42L56_HPA_VOLUME		0x28
+#define CS42L56_HPB_VOLUME		0x29
+#define CS42L56_LOA_VOLUME		0x2a
+#define CS42L56_LOB_VOLUME		0x2b
+#define CS42L56_LIM_THRESHOLD_CTL	0x2c
+#define CS42L56_LIM_CTL_RELEASE_RATE	0x2d
+#define CS42L56_LIM_ATTACK_RATE		0x2e
+
+/* Device ID and Rev ID Masks */
+#define CS42L56_DEVID			0x56
+#define CS42L56_CHIP_ID_MASK		0xff
+#define CS42L56_AREV_MASK		0x1c
+#define CS42L56_MTLREV_MASK		0x03
+
+/* Power bit masks */
+#define CS42L56_PDN_ALL_MASK		0x01
+#define CS42L56_PDN_ADCA_MASK		0x02
+#define CS42L56_PDN_ADCB_MASK		0x04
+#define CS42L56_PDN_CHRG_MASK		0x08
+#define CS42L56_PDN_BIAS_MASK		0x10
+#define CS42L56_PDN_VBUF_MASK		0x20
+#define CS42L56_PDN_LOA_MASK		0x03
+#define CS42L56_PDN_LOB_MASK		0x0c
+#define CS42L56_PDN_HPA_MASK		0x30
+#define CS42L56_PDN_HPB_MASK		0xc0
+
+/* serial port and clk masks */
+#define CS42L56_MASTER_MODE		0x40
+#define CS42L56_SLAVE_MODE		0
+#define CS42L56_MS_MODE_MASK		0x40
+#define CS42L56_SCLK_INV		0x20
+#define CS42L56_SCLK_INV_MASK		0x20
+#define CS42L56_SCLK_MCLK_MASK		0x18
+#define CS42L56_MCLK_PREDIV		0x04
+#define CS42L56_MCLK_PREDIV_MASK	0x04
+#define CS42L56_MCLK_DIV2		0x02
+#define CS42L56_MCLK_DIV2_MASK		0x02
+#define CS42L56_MCLK_DIS_MASK		0x01
+#define CS42L56_CLK_AUTO_MASK		0x20
+#define CS42L56_CLK_RATIO_MASK		0x1f
+#define CS42L56_DIG_FMT_I2S		0
+#define CS42L56_DIG_FMT_LEFT_J		0x08
+#define CS42L56_DIG_FMT_MASK		0x08
+
+/* Class H and misc ctl masks */
+#define CS42L56_ADAPT_PWR_MASK		0xc0
+#define CS42L56_CHRG_FREQ_MASK		0x0f
+#define CS42L56_DIG_MUX_MASK		0x80
+#define CS42L56_ANLGSFT_MASK		0x10
+#define CS42L56_ANLGZC_MASK		0x08
+#define CS42L56_DIGSFT_MASK		0x04
+#define CS42L56_FREEZE_MASK		0x01
+#define CS42L56_MIC_BIAS_MASK		0x03
+#define CS42L56_HPFA_FREQ_MASK		0x03
+#define CS42L56_HPFB_FREQ_MASK		0xc0
+#define CS42L56_AIN1A_REF_MASK		0x10
+#define CS42L56_AIN2A_REF_MASK		0x40
+#define CS42L56_AIN1B_REF_MASK		0x20
+#define CS42L56_AIN2B_REF_MASK		0x80
+
+/* Playback Capture ctl masks */
+#define CS42L56_PDN_DSP_MASK		0x80
+#define CS42L56_DEEMPH_MASK		0x40
+#define CS42L56_PLYBCK_GANG_MASK	0x10
+#define CS42L56_PCM_INV_MASK		0x0c
+#define CS42L56_MUTE_ALL		0xff
+#define CS42L56_UNMUTE			0
+#define CS42L56_ADCAMIX_MUTE_MASK	0x40
+#define CS42L56_ADCBMIX_MUTE_MASK	0x80
+#define CS42L56_PCMAMIX_MUTE_MASK	0x10
+#define CS42L56_PCMBMIX_MUTE_MASK	0x20
+#define CS42L56_MSTB_MUTE_MASK		0x02
+#define CS42L56_MSTA_MUTE_MASK		0x01
+#define CS42L56_ADCA_MUTE_MASK		0x01
+#define CS42L56_ADCB_MUTE_MASK		0x02
+#define CS42L56_HP_MUTE_MASK		0x80
+#define CS42L56_LO_MUTE_MASK		0x80
+
+/* Beep masks */
+#define CS42L56_BEEP_FREQ_MASK		0xf0
+#define CS42L56_BEEP_ONTIME_MASK	0x0f
+#define CS42L56_BEEP_OFFTIME_MASK	0xe0
+#define CS42L56_BEEP_CFG_MASK		0xc0
+#define CS42L56_BEEP_TREBCF_MASK	0x18
+#define CS42L56_BEEP_BASSCF_MASK	0x06
+#define CS42L56_BEEP_TCEN_MASK		0x01
+#define CS42L56_BEEP_RATE_SHIFT		4
+#define CS42L56_BEEP_EN_MASK		0x3f
+
+
+/* Supported MCLKS */
+#define CS42L56_MCLK_5P6448MHZ		5644800
+#define CS42L56_MCLK_6MHZ		6000000
+#define CS42L56_MCLK_6P144MHZ		6144000
+#define CS42L56_MCLK_11P2896MHZ		11289600
+#define CS42L56_MCLK_12MHZ		12000000
+#define CS42L56_MCLK_12P288MHZ		12288000
+#define CS42L56_MCLK_22P5792MHZ		22579200
+#define CS42L56_MCLK_24MHZ		24000000
+#define CS42L56_MCLK_24P576MHZ		24576000
+
+/* Clock ratios */
+#define CS42L56_MCLK_LRCLK_128		0x08
+#define CS42L56_MCLK_LRCLK_125		0x09
+#define CS42L56_MCLK_LRCLK_136		0x0b
+#define CS42L56_MCLK_LRCLK_192		0x0c
+#define CS42L56_MCLK_LRCLK_187P5	0x0d
+#define CS42L56_MCLK_LRCLK_256		0x10
+#define CS42L56_MCLK_LRCLK_250		0x11
+#define CS42L56_MCLK_LRCLK_272		0x13
+#define CS42L56_MCLK_LRCLK_384		0x14
+#define CS42L56_MCLK_LRCLK_375		0x15
+#define CS42L56_MCLK_LRCLK_512		0x18
+#define CS42L56_MCLK_LRCLK_500		0x19
+#define CS42L56_MCLK_LRCLK_544		0x1b
+#define CS42L56_MCLK_LRCLK_750		0x1c
+#define CS42L56_MCLK_LRCLK_768		0x1d
+
+
+#define CS42L56_MAX_REGISTER		0x34
+
+#endif
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
new file mode 100644
index 0000000..36b57ee
--- /dev/null
+++ b/sound/soc/codecs/cs42l73.c
@@ -0,0 +1,1401 @@
+/*
+ * cs42l73.c  --  CS42L73 ALSA Soc Audio driver
+ *
+ * Copyright 2011 Cirrus Logic, Inc.
+ *
+ * Authors: Georgi Vlaev, Nucleus Systems Ltd, <joe@nucleusys.com>
+ *	    Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/of_gpio.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/cs42l73.h>
+#include "cs42l73.h"
+
+struct sp_config {
+	u8 spc, mmcc, spfs;
+	u32 srate;
+};
+struct  cs42l73_private {
+	struct cs42l73_platform_data pdata;
+	struct sp_config config[3];
+	struct regmap *regmap;
+	u32 sysclk;
+	u8 mclksel;
+	u32 mclk;
+	int shutdwn_delay;
+};
+
+static const struct reg_default cs42l73_reg_defaults[] = {
+	{ 6, 0xF1 },	/* r06	- Power Ctl 1 */
+	{ 7, 0xDF },	/* r07	- Power Ctl 2 */
+	{ 8, 0x3F },	/* r08	- Power Ctl 3 */
+	{ 9, 0x50 },	/* r09	- Charge Pump Freq */
+	{ 10, 0x53 },	/* r0A	- Output Load MicBias Short Detect */
+	{ 11, 0x00 },	/* r0B	- DMIC Master Clock Ctl */
+	{ 12, 0x00 },	/* r0C	- Aux PCM Ctl */
+	{ 13, 0x15 },	/* r0D	- Aux PCM Master Clock Ctl */
+	{ 14, 0x00 },	/* r0E	- Audio PCM Ctl */
+	{ 15, 0x15 },	/* r0F	- Audio PCM Master Clock Ctl */
+	{ 16, 0x00 },	/* r10	- Voice PCM Ctl */
+	{ 17, 0x15 },	/* r11	- Voice PCM Master Clock Ctl */
+	{ 18, 0x00 },	/* r12	- Voice/Aux Sample Rate */
+	{ 19, 0x06 },	/* r13	- Misc I/O Path Ctl */
+	{ 20, 0x00 },	/* r14	- ADC Input Path Ctl */
+	{ 21, 0x00 },	/* r15	- MICA Preamp, PGA Volume */
+	{ 22, 0x00 },	/* r16	- MICB Preamp, PGA Volume */
+	{ 23, 0x00 },	/* r17	- Input Path A Digital Volume */
+	{ 24, 0x00 },	/* r18	- Input Path B Digital Volume */
+	{ 25, 0x00 },	/* r19	- Playback Digital Ctl */
+	{ 26, 0x00 },	/* r1A	- HP/LO Left Digital Volume */
+	{ 27, 0x00 },	/* r1B	- HP/LO Right Digital Volume */
+	{ 28, 0x00 },	/* r1C	- Speakerphone Digital Volume */
+	{ 29, 0x00 },	/* r1D	- Ear/SPKLO Digital Volume */
+	{ 30, 0x00 },	/* r1E	- HP Left Analog Volume */
+	{ 31, 0x00 },	/* r1F	- HP Right Analog Volume */
+	{ 32, 0x00 },	/* r20	- LO Left Analog Volume */
+	{ 33, 0x00 },	/* r21	- LO Right Analog Volume */
+	{ 34, 0x00 },	/* r22	- Stereo Input Path Advisory Volume */
+	{ 35, 0x00 },	/* r23	- Aux PCM Input Advisory Volume */
+	{ 36, 0x00 },	/* r24	- Audio PCM Input Advisory Volume */
+	{ 37, 0x00 },	/* r25	- Voice PCM Input Advisory Volume */
+	{ 38, 0x00 },	/* r26	- Limiter Attack Rate HP/LO */
+	{ 39, 0x7F },	/* r27	- Limter Ctl, Release Rate HP/LO */
+	{ 40, 0x00 },	/* r28	- Limter Threshold HP/LO */
+	{ 41, 0x00 },	/* r29	- Limiter Attack Rate Speakerphone */
+	{ 42, 0x3F },	/* r2A	- Limter Ctl, Release Rate Speakerphone */
+	{ 43, 0x00 },	/* r2B	- Limter Threshold Speakerphone */
+	{ 44, 0x00 },	/* r2C	- Limiter Attack Rate Ear/SPKLO */
+	{ 45, 0x3F },	/* r2D	- Limter Ctl, Release Rate Ear/SPKLO */
+	{ 46, 0x00 },	/* r2E	- Limter Threshold Ear/SPKLO */
+	{ 47, 0x00 },	/* r2F	- ALC Enable, Attack Rate Left/Right */
+	{ 48, 0x3F },	/* r30	- ALC Release Rate Left/Right */
+	{ 49, 0x00 },	/* r31	- ALC Threshold Left/Right */
+	{ 50, 0x00 },	/* r32	- Noise Gate Ctl Left/Right */
+	{ 51, 0x00 },	/* r33	- ALC/NG Misc Ctl */
+	{ 52, 0x18 },	/* r34	- Mixer Ctl */
+	{ 53, 0x3F },	/* r35	- HP/LO Left Mixer Input Path Volume */
+	{ 54, 0x3F },	/* r36	- HP/LO Right Mixer Input Path Volume */
+	{ 55, 0x3F },	/* r37	- HP/LO Left Mixer Aux PCM Volume */
+	{ 56, 0x3F },	/* r38	- HP/LO Right Mixer Aux PCM Volume */
+	{ 57, 0x3F },	/* r39	- HP/LO Left Mixer Audio PCM Volume */
+	{ 58, 0x3F },	/* r3A	- HP/LO Right Mixer Audio PCM Volume */
+	{ 59, 0x3F },	/* r3B	- HP/LO Left Mixer Voice PCM Mono Volume */
+	{ 60, 0x3F },	/* r3C	- HP/LO Right Mixer Voice PCM Mono Volume */
+	{ 61, 0x3F },	/* r3D	- Aux PCM Left Mixer Input Path Volume */
+	{ 62, 0x3F },	/* r3E	- Aux PCM Right Mixer Input Path Volume */
+	{ 63, 0x3F },	/* r3F	- Aux PCM Left Mixer Volume */
+	{ 64, 0x3F },	/* r40	- Aux PCM Left Mixer Volume */
+	{ 65, 0x3F },	/* r41	- Aux PCM Left Mixer Audio PCM L Volume */
+	{ 66, 0x3F },	/* r42	- Aux PCM Right Mixer Audio PCM R Volume */
+	{ 67, 0x3F },	/* r43	- Aux PCM Left Mixer Voice PCM Volume */
+	{ 68, 0x3F },	/* r44	- Aux PCM Right Mixer Voice PCM Volume */
+	{ 69, 0x3F },	/* r45	- Audio PCM Left Input Path Volume */
+	{ 70, 0x3F },	/* r46	- Audio PCM Right Input Path Volume */
+	{ 71, 0x3F },	/* r47	- Audio PCM Left Mixer Aux PCM L Volume */
+	{ 72, 0x3F },	/* r48	- Audio PCM Right Mixer Aux PCM R Volume */
+	{ 73, 0x3F },	/* r49	- Audio PCM Left Mixer Volume */
+	{ 74, 0x3F },	/* r4A	- Audio PCM Right Mixer Volume */
+	{ 75, 0x3F },	/* r4B	- Audio PCM Left Mixer Voice PCM Volume */
+	{ 76, 0x3F },	/* r4C	- Audio PCM Right Mixer Voice PCM Volume */
+	{ 77, 0x3F },	/* r4D	- Voice PCM Left Input Path Volume */
+	{ 78, 0x3F },	/* r4E	- Voice PCM Right Input Path Volume */
+	{ 79, 0x3F },	/* r4F	- Voice PCM Left Mixer Aux PCM L Volume */
+	{ 80, 0x3F },	/* r50	- Voice PCM Right Mixer Aux PCM R Volume */
+	{ 81, 0x3F },	/* r51	- Voice PCM Left Mixer Audio PCM L Volume */
+	{ 82, 0x3F },	/* r52	- Voice PCM Right Mixer Audio PCM R Volume */
+	{ 83, 0x3F },	/* r53	- Voice PCM Left Mixer Voice PCM Volume */
+	{ 84, 0x3F },	/* r54	- Voice PCM Right Mixer Voice PCM Volume */
+	{ 85, 0xAA },	/* r55	- Mono Mixer Ctl */
+	{ 86, 0x3F },	/* r56	- SPK Mono Mixer Input Path Volume */
+	{ 87, 0x3F },	/* r57	- SPK Mono Mixer Aux PCM Mono/L/R Volume */
+	{ 88, 0x3F },	/* r58	- SPK Mono Mixer Audio PCM Mono/L/R Volume */
+	{ 89, 0x3F },	/* r59	- SPK Mono Mixer Voice PCM Mono Volume */
+	{ 90, 0x3F },	/* r5A	- SPKLO Mono Mixer Input Path Mono Volume */
+	{ 91, 0x3F },	/* r5B	- SPKLO Mono Mixer Aux Mono/L/R Volume */
+	{ 92, 0x3F },	/* r5C	- SPKLO Mono Mixer Audio Mono/L/R Volume */
+	{ 93, 0x3F },	/* r5D	- SPKLO Mono Mixer Voice Mono Volume */
+	{ 94, 0x00 },	/* r5E	- Interrupt Mask 1 */
+	{ 95, 0x00 },	/* r5F	- Interrupt Mask 2 */
+};
+
+static bool cs42l73_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS42L73_IS1:
+	case CS42L73_IS2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs42l73_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS42L73_DEVID_AB ... CS42L73_DEVID_E:
+	case CS42L73_REVID ... CS42L73_IM2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_RANGE(hpaloa_tlv,
+	0, 13, TLV_DB_SCALE_ITEM(-7600, 200, 0),
+	14, 75, TLV_DB_SCALE_ITEM(-4900, 100, 0)
+);
+
+static DECLARE_TLV_DB_SCALE(adc_boost_tlv, 0, 2500, 0);
+
+static DECLARE_TLV_DB_SCALE(hl_tlv, -10200, 50, 0);
+
+static DECLARE_TLV_DB_SCALE(ipd_tlv, -9600, 100, 0);
+
+static DECLARE_TLV_DB_SCALE(micpga_tlv, -600, 50, 0);
+
+static const DECLARE_TLV_DB_RANGE(limiter_tlv,
+	0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
+	3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(attn_tlv, -6300, 100, 1);
+
+static const char * const cs42l73_pgaa_text[] = { "Line A", "Mic 1" };
+static const char * const cs42l73_pgab_text[] = { "Line B", "Mic 2" };
+
+static SOC_ENUM_SINGLE_DECL(pgaa_enum,
+			    CS42L73_ADCIPC, 3,
+			    cs42l73_pgaa_text);
+
+static SOC_ENUM_SINGLE_DECL(pgab_enum,
+			    CS42L73_ADCIPC, 7,
+			    cs42l73_pgab_text);
+
+static const struct snd_kcontrol_new pgaa_mux =
+	SOC_DAPM_ENUM("Left Analog Input Capture Mux", pgaa_enum);
+
+static const struct snd_kcontrol_new pgab_mux =
+	SOC_DAPM_ENUM("Right Analog Input Capture Mux", pgab_enum);
+
+static const struct snd_kcontrol_new input_left_mixer[] = {
+	SOC_DAPM_SINGLE("ADC Left Input", CS42L73_PWRCTL1,
+			5, 1, 1),
+	SOC_DAPM_SINGLE("DMIC Left Input", CS42L73_PWRCTL1,
+			4, 1, 1),
+};
+
+static const struct snd_kcontrol_new input_right_mixer[] = {
+	SOC_DAPM_SINGLE("ADC Right Input", CS42L73_PWRCTL1,
+			7, 1, 1),
+	SOC_DAPM_SINGLE("DMIC Right Input", CS42L73_PWRCTL1,
+			6, 1, 1),
+};
+
+static const char * const cs42l73_ng_delay_text[] = {
+	"50ms", "100ms", "150ms", "200ms" };
+
+static SOC_ENUM_SINGLE_DECL(ng_delay_enum,
+			    CS42L73_NGCAB, 0,
+			    cs42l73_ng_delay_text);
+
+static const char * const cs42l73_mono_mix_texts[] = {
+	"Left", "Right", "Mono Mix"};
+
+static const unsigned int cs42l73_mono_mix_values[] = { 0, 1, 2 };
+
+static const struct soc_enum spk_asp_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 6, 3,
+			      ARRAY_SIZE(cs42l73_mono_mix_texts),
+			      cs42l73_mono_mix_texts,
+			      cs42l73_mono_mix_values);
+
+static const struct snd_kcontrol_new spk_asp_mixer =
+	SOC_DAPM_ENUM("Route", spk_asp_enum);
+
+static const struct soc_enum spk_xsp_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 4, 3,
+			      ARRAY_SIZE(cs42l73_mono_mix_texts),
+			      cs42l73_mono_mix_texts,
+			      cs42l73_mono_mix_values);
+
+static const struct snd_kcontrol_new spk_xsp_mixer =
+	SOC_DAPM_ENUM("Route", spk_xsp_enum);
+
+static const struct soc_enum esl_asp_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 2, 3,
+			      ARRAY_SIZE(cs42l73_mono_mix_texts),
+			      cs42l73_mono_mix_texts,
+			      cs42l73_mono_mix_values);
+
+static const struct snd_kcontrol_new esl_asp_mixer =
+	SOC_DAPM_ENUM("Route", esl_asp_enum);
+
+static const struct soc_enum esl_xsp_enum =
+	SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 0, 3,
+			      ARRAY_SIZE(cs42l73_mono_mix_texts),
+			      cs42l73_mono_mix_texts,
+			      cs42l73_mono_mix_values);
+
+static const struct snd_kcontrol_new esl_xsp_mixer =
+	SOC_DAPM_ENUM("Route", esl_xsp_enum);
+
+static const char * const cs42l73_ip_swap_text[] = {
+	"Stereo", "Mono A", "Mono B", "Swap A-B"};
+
+static SOC_ENUM_SINGLE_DECL(ip_swap_enum,
+			    CS42L73_MIOPC, 6,
+			    cs42l73_ip_swap_text);
+
+static const char * const cs42l73_spo_mixer_text[] = {"Mono", "Stereo"};
+
+static SOC_ENUM_SINGLE_DECL(vsp_output_mux_enum,
+			    CS42L73_MIXERCTL, 5,
+			    cs42l73_spo_mixer_text);
+
+static SOC_ENUM_SINGLE_DECL(xsp_output_mux_enum,
+			    CS42L73_MIXERCTL, 4,
+			    cs42l73_spo_mixer_text);
+
+static const struct snd_kcontrol_new vsp_output_mux =
+	SOC_DAPM_ENUM("Route", vsp_output_mux_enum);
+
+static const struct snd_kcontrol_new xsp_output_mux =
+	SOC_DAPM_ENUM("Route", xsp_output_mux_enum);
+
+static const struct snd_kcontrol_new hp_amp_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 0, 1, 1);
+
+static const struct snd_kcontrol_new lo_amp_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 1, 1, 1);
+
+static const struct snd_kcontrol_new spk_amp_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 2, 1, 1);
+
+static const struct snd_kcontrol_new spklo_amp_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 4, 1, 1);
+
+static const struct snd_kcontrol_new ear_amp_ctl =
+	SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 3, 1, 1);
+
+static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
+	SOC_DOUBLE_R_SX_TLV("Headphone Analog Playback Volume",
+			CS42L73_HPAAVOL, CS42L73_HPBAVOL, 0,
+			0x41, 0x4B, hpaloa_tlv),
+
+	SOC_DOUBLE_R_SX_TLV("LineOut Analog Playback Volume", CS42L73_LOAAVOL,
+			CS42L73_LOBAVOL, 0, 0x41, 0x4B, hpaloa_tlv),
+
+	SOC_DOUBLE_R_SX_TLV("Input PGA Analog Volume", CS42L73_MICAPREPGAAVOL,
+			CS42L73_MICBPREPGABVOL, 0, 0x34,
+			0x24, micpga_tlv),
+
+	SOC_DOUBLE_R("MIC Preamp Switch", CS42L73_MICAPREPGAAVOL,
+			CS42L73_MICBPREPGABVOL, 6, 1, 1),
+
+	SOC_DOUBLE_R_SX_TLV("Input Path Digital Volume", CS42L73_IPADVOL,
+			CS42L73_IPBDVOL, 0, 0xA0, 0x6C, ipd_tlv),
+
+	SOC_DOUBLE_R_SX_TLV("HL Digital Playback Volume",
+			CS42L73_HLADVOL, CS42L73_HLBDVOL,
+			0, 0x34, 0xE4, hl_tlv),
+
+	SOC_SINGLE_TLV("ADC A Boost Volume",
+			CS42L73_ADCIPC, 2, 0x01, 1, adc_boost_tlv),
+
+	SOC_SINGLE_TLV("ADC B Boost Volume",
+		       CS42L73_ADCIPC, 6, 0x01, 1, adc_boost_tlv),
+
+	SOC_SINGLE_SX_TLV("Speakerphone Digital Volume",
+			    CS42L73_SPKDVOL, 0, 0x34, 0xE4, hl_tlv),
+
+	SOC_SINGLE_SX_TLV("Ear Speaker Digital Volume",
+			    CS42L73_ESLDVOL, 0, 0x34, 0xE4, hl_tlv),
+
+	SOC_DOUBLE_R("Headphone Analog Playback Switch", CS42L73_HPAAVOL,
+			CS42L73_HPBAVOL, 7, 1, 1),
+
+	SOC_DOUBLE_R("LineOut Analog Playback Switch", CS42L73_LOAAVOL,
+			CS42L73_LOBAVOL, 7, 1, 1),
+	SOC_DOUBLE("Input Path Digital Switch", CS42L73_ADCIPC, 0, 4, 1, 1),
+	SOC_DOUBLE("HL Digital Playback Switch", CS42L73_PBDC, 0,
+			1, 1, 1),
+	SOC_SINGLE("Speakerphone Digital Playback Switch", CS42L73_PBDC, 2, 1,
+			1),
+	SOC_SINGLE("Ear Speaker Digital Playback Switch", CS42L73_PBDC, 3, 1,
+			1),
+
+	SOC_SINGLE("PGA Soft-Ramp Switch", CS42L73_MIOPC, 3, 1, 0),
+	SOC_SINGLE("Analog Zero Cross Switch", CS42L73_MIOPC, 2, 1, 0),
+	SOC_SINGLE("Digital Soft-Ramp Switch", CS42L73_MIOPC, 1, 1, 0),
+	SOC_SINGLE("Analog Output Soft-Ramp Switch", CS42L73_MIOPC, 0, 1, 0),
+
+	SOC_DOUBLE("ADC Signal Polarity Switch", CS42L73_ADCIPC, 1, 5, 1,
+			0),
+
+	SOC_SINGLE("HL Limiter Attack Rate", CS42L73_LIMARATEHL, 0, 0x3F,
+			0),
+	SOC_SINGLE("HL Limiter Release Rate", CS42L73_LIMRRATEHL, 0,
+			0x3F, 0),
+
+
+	SOC_SINGLE("HL Limiter Switch", CS42L73_LIMRRATEHL, 7, 1, 0),
+	SOC_SINGLE("HL Limiter All Channels Switch", CS42L73_LIMRRATEHL, 6, 1,
+			0),
+
+	SOC_SINGLE_TLV("HL Limiter Max Threshold Volume", CS42L73_LMAXHL, 5, 7,
+			1, limiter_tlv),
+
+	SOC_SINGLE_TLV("HL Limiter Cushion Volume", CS42L73_LMAXHL, 2, 7, 1,
+			limiter_tlv),
+
+	SOC_SINGLE("SPK Limiter Attack Rate Volume", CS42L73_LIMARATESPK, 0,
+			0x3F, 0),
+	SOC_SINGLE("SPK Limiter Release Rate Volume", CS42L73_LIMRRATESPK, 0,
+			0x3F, 0),
+	SOC_SINGLE("SPK Limiter Switch", CS42L73_LIMRRATESPK, 7, 1, 0),
+	SOC_SINGLE("SPK Limiter All Channels Switch", CS42L73_LIMRRATESPK,
+			6, 1, 0),
+	SOC_SINGLE_TLV("SPK Limiter Max Threshold Volume", CS42L73_LMAXSPK, 5,
+			7, 1, limiter_tlv),
+
+	SOC_SINGLE_TLV("SPK Limiter Cushion Volume", CS42L73_LMAXSPK, 2, 7, 1,
+			limiter_tlv),
+
+	SOC_SINGLE("ESL Limiter Attack Rate Volume", CS42L73_LIMARATEESL, 0,
+			0x3F, 0),
+	SOC_SINGLE("ESL Limiter Release Rate Volume", CS42L73_LIMRRATEESL, 0,
+			0x3F, 0),
+	SOC_SINGLE("ESL Limiter Switch", CS42L73_LIMRRATEESL, 7, 1, 0),
+	SOC_SINGLE_TLV("ESL Limiter Max Threshold Volume", CS42L73_LMAXESL, 5,
+			7, 1, limiter_tlv),
+
+	SOC_SINGLE_TLV("ESL Limiter Cushion Volume", CS42L73_LMAXESL, 2, 7, 1,
+			limiter_tlv),
+
+	SOC_SINGLE("ALC Attack Rate Volume", CS42L73_ALCARATE, 0, 0x3F, 0),
+	SOC_SINGLE("ALC Release Rate Volume", CS42L73_ALCRRATE, 0, 0x3F, 0),
+	SOC_DOUBLE("ALC Switch", CS42L73_ALCARATE, 6, 7, 1, 0),
+	SOC_SINGLE_TLV("ALC Max Threshold Volume", CS42L73_ALCMINMAX, 5, 7, 0,
+			limiter_tlv),
+	SOC_SINGLE_TLV("ALC Min Threshold Volume", CS42L73_ALCMINMAX, 2, 7, 0,
+			limiter_tlv),
+
+	SOC_DOUBLE("NG Enable Switch", CS42L73_NGCAB, 6, 7, 1, 0),
+	SOC_SINGLE("NG Boost Switch", CS42L73_NGCAB, 5, 1, 0),
+	/*
+	    NG Threshold depends on NG_BOOTSAB, which selects
+	    between two threshold scales in decibels.
+	    Set linear values for now ..
+	*/
+	SOC_SINGLE("NG Threshold", CS42L73_NGCAB, 2, 7, 0),
+	SOC_ENUM("NG Delay", ng_delay_enum),
+
+	SOC_DOUBLE_R_TLV("XSP-IP Volume",
+			CS42L73_XSPAIPAA, CS42L73_XSPBIPBA, 0, 0x3F, 1,
+			attn_tlv),
+	SOC_DOUBLE_R_TLV("XSP-XSP Volume",
+			CS42L73_XSPAXSPAA, CS42L73_XSPBXSPBA, 0, 0x3F, 1,
+			attn_tlv),
+	SOC_DOUBLE_R_TLV("XSP-ASP Volume",
+			CS42L73_XSPAASPAA, CS42L73_XSPAASPBA, 0, 0x3F, 1,
+			attn_tlv),
+	SOC_DOUBLE_R_TLV("XSP-VSP Volume",
+			CS42L73_XSPAVSPMA, CS42L73_XSPBVSPMA, 0, 0x3F, 1,
+			attn_tlv),
+
+	SOC_DOUBLE_R_TLV("ASP-IP Volume",
+			CS42L73_ASPAIPAA, CS42L73_ASPBIPBA, 0, 0x3F, 1,
+			attn_tlv),
+	SOC_DOUBLE_R_TLV("ASP-XSP Volume",
+			CS42L73_ASPAXSPAA, CS42L73_ASPBXSPBA, 0, 0x3F, 1,
+			attn_tlv),
+	SOC_DOUBLE_R_TLV("ASP-ASP Volume",
+			CS42L73_ASPAASPAA, CS42L73_ASPBASPBA, 0, 0x3F, 1,
+			attn_tlv),
+	SOC_DOUBLE_R_TLV("ASP-VSP Volume",
+			CS42L73_ASPAVSPMA, CS42L73_ASPBVSPMA, 0, 0x3F, 1,
+			attn_tlv),
+
+	SOC_DOUBLE_R_TLV("VSP-IP Volume",
+			CS42L73_VSPAIPAA, CS42L73_VSPBIPBA, 0, 0x3F, 1,
+			attn_tlv),
+	SOC_DOUBLE_R_TLV("VSP-XSP Volume",
+			CS42L73_VSPAXSPAA, CS42L73_VSPBXSPBA, 0, 0x3F, 1,
+			attn_tlv),
+	SOC_DOUBLE_R_TLV("VSP-ASP Volume",
+			CS42L73_VSPAASPAA, CS42L73_VSPBASPBA, 0, 0x3F, 1,
+			attn_tlv),
+	SOC_DOUBLE_R_TLV("VSP-VSP Volume",
+			CS42L73_VSPAVSPMA, CS42L73_VSPBVSPMA, 0, 0x3F, 1,
+			attn_tlv),
+
+	SOC_DOUBLE_R_TLV("HL-IP Volume",
+			CS42L73_HLAIPAA, CS42L73_HLBIPBA, 0, 0x3F, 1,
+			attn_tlv),
+	SOC_DOUBLE_R_TLV("HL-XSP Volume",
+			CS42L73_HLAXSPAA, CS42L73_HLBXSPBA, 0, 0x3F, 1,
+			attn_tlv),
+	SOC_DOUBLE_R_TLV("HL-ASP Volume",
+			CS42L73_HLAASPAA, CS42L73_HLBASPBA, 0, 0x3F, 1,
+			attn_tlv),
+	SOC_DOUBLE_R_TLV("HL-VSP Volume",
+			CS42L73_HLAVSPMA, CS42L73_HLBVSPMA, 0, 0x3F, 1,
+			attn_tlv),
+
+	SOC_SINGLE_TLV("SPK-IP Mono Volume",
+			CS42L73_SPKMIPMA, 0, 0x3F, 1, attn_tlv),
+	SOC_SINGLE_TLV("SPK-XSP Mono Volume",
+			CS42L73_SPKMXSPA, 0, 0x3F, 1, attn_tlv),
+	SOC_SINGLE_TLV("SPK-ASP Mono Volume",
+			CS42L73_SPKMASPA, 0, 0x3F, 1, attn_tlv),
+	SOC_SINGLE_TLV("SPK-VSP Mono Volume",
+			CS42L73_SPKMVSPMA, 0, 0x3F, 1, attn_tlv),
+
+	SOC_SINGLE_TLV("ESL-IP Mono Volume",
+			CS42L73_ESLMIPMA, 0, 0x3F, 1, attn_tlv),
+	SOC_SINGLE_TLV("ESL-XSP Mono Volume",
+			CS42L73_ESLMXSPA, 0, 0x3F, 1, attn_tlv),
+	SOC_SINGLE_TLV("ESL-ASP Mono Volume",
+			CS42L73_ESLMASPA, 0, 0x3F, 1, attn_tlv),
+	SOC_SINGLE_TLV("ESL-VSP Mono Volume",
+			CS42L73_ESLMVSPMA, 0, 0x3F, 1, attn_tlv),
+
+	SOC_ENUM("IP Digital Swap/Mono Select", ip_swap_enum),
+
+	SOC_ENUM("VSPOUT Mono/Stereo Select", vsp_output_mux_enum),
+	SOC_ENUM("XSPOUT Mono/Stereo Select", xsp_output_mux_enum),
+};
+
+static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMD:
+		/* 150 ms delay between setting PDN and MCLKDIS */
+		priv->shutdwn_delay = 150;
+		break;
+	default:
+		pr_err("Invalid event = 0x%x\n", event);
+	}
+	return 0;
+}
+
+static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMD:
+		/* 50 ms delay between setting PDN and MCLKDIS */
+		if (priv->shutdwn_delay < 50)
+			priv->shutdwn_delay = 50;
+		break;
+	default:
+		pr_err("Invalid event = 0x%x\n", event);
+	}
+	return 0;
+}
+
+
+static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMD:
+		/* 30 ms delay between setting PDN and MCLKDIS */
+		if (priv->shutdwn_delay < 30)
+			priv->shutdwn_delay = 30;
+		break;
+	default:
+		pr_err("Invalid event = 0x%x\n", event);
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("DMICA"),
+	SND_SOC_DAPM_INPUT("DMICB"),
+	SND_SOC_DAPM_INPUT("LINEINA"),
+	SND_SOC_DAPM_INPUT("LINEINB"),
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_SUPPLY("MIC1 Bias", CS42L73_PWRCTL2, 6, 1, NULL, 0),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_SUPPLY("MIC2 Bias", CS42L73_PWRCTL2, 7, 1, NULL, 0),
+
+	SND_SOC_DAPM_AIF_OUT("XSPOUTL", NULL,  0,
+			CS42L73_PWRCTL2, 1, 1),
+	SND_SOC_DAPM_AIF_OUT("XSPOUTR", NULL,  0,
+			CS42L73_PWRCTL2, 1, 1),
+	SND_SOC_DAPM_AIF_OUT("ASPOUTL", NULL,  0,
+			CS42L73_PWRCTL2, 3, 1),
+	SND_SOC_DAPM_AIF_OUT("ASPOUTR", NULL,  0,
+			CS42L73_PWRCTL2, 3, 1),
+	SND_SOC_DAPM_AIF_OUT("VSPINOUT", NULL,  0,
+			CS42L73_PWRCTL2, 4, 1),
+
+	SND_SOC_DAPM_PGA("PGA Left", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PGA Right", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("PGA Left Mux", SND_SOC_NOPM, 0, 0, &pgaa_mux),
+	SND_SOC_DAPM_MUX("PGA Right Mux", SND_SOC_NOPM, 0, 0, &pgab_mux),
+
+	SND_SOC_DAPM_ADC("ADC Left", NULL, CS42L73_PWRCTL1, 7, 1),
+	SND_SOC_DAPM_ADC("ADC Right", NULL, CS42L73_PWRCTL1, 5, 1),
+	SND_SOC_DAPM_ADC("DMIC Left", NULL, CS42L73_PWRCTL1, 6, 1),
+	SND_SOC_DAPM_ADC("DMIC Right", NULL, CS42L73_PWRCTL1, 4, 1),
+
+	SND_SOC_DAPM_MIXER_NAMED_CTL("Input Left Capture", SND_SOC_NOPM,
+			 0, 0, input_left_mixer,
+			 ARRAY_SIZE(input_left_mixer)),
+
+	SND_SOC_DAPM_MIXER_NAMED_CTL("Input Right Capture", SND_SOC_NOPM,
+			0, 0, input_right_mixer,
+			ARRAY_SIZE(input_right_mixer)),
+
+	SND_SOC_DAPM_MIXER("ASPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("ASPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("XSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("XSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("VSP Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_AIF_IN("XSPINL", NULL, 0,
+				CS42L73_PWRCTL2, 0, 1),
+	SND_SOC_DAPM_AIF_IN("XSPINR", NULL, 0,
+				CS42L73_PWRCTL2, 0, 1),
+	SND_SOC_DAPM_AIF_IN("XSPINM", NULL, 0,
+				CS42L73_PWRCTL2, 0, 1),
+
+	SND_SOC_DAPM_AIF_IN("ASPINL", NULL, 0,
+				CS42L73_PWRCTL2, 2, 1),
+	SND_SOC_DAPM_AIF_IN("ASPINR", NULL, 0,
+				CS42L73_PWRCTL2, 2, 1),
+	SND_SOC_DAPM_AIF_IN("ASPINM", NULL, 0,
+				CS42L73_PWRCTL2, 2, 1),
+
+	SND_SOC_DAPM_AIF_IN("VSPINOUT", NULL, 0,
+				CS42L73_PWRCTL2, 4, 1),
+
+	SND_SOC_DAPM_MIXER("HL Left Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("HL Right Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SPK Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("ESL Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("ESL-XSP Mux", SND_SOC_NOPM,
+			 0, 0, &esl_xsp_mixer),
+
+	SND_SOC_DAPM_MUX("ESL-ASP Mux", SND_SOC_NOPM,
+			 0, 0, &esl_asp_mixer),
+
+	SND_SOC_DAPM_MUX("SPK-ASP Mux", SND_SOC_NOPM,
+			 0, 0, &spk_asp_mixer),
+
+	SND_SOC_DAPM_MUX("SPK-XSP Mux", SND_SOC_NOPM,
+			 0, 0, &spk_xsp_mixer),
+
+	SND_SOC_DAPM_PGA("HL Left DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HL Right DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SPK DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("ESL DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH_E("HP Amp",  CS42L73_PWRCTL3, 0, 1,
+			    &hp_amp_ctl, cs42l73_hp_amp_event,
+			SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SWITCH("LO Amp", CS42L73_PWRCTL3, 1, 1,
+			    &lo_amp_ctl),
+	SND_SOC_DAPM_SWITCH_E("SPK Amp", CS42L73_PWRCTL3, 2, 1,
+			&spk_amp_ctl, cs42l73_spklo_spk_amp_event,
+			SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SWITCH_E("EAR Amp", CS42L73_PWRCTL3, 3, 1,
+			    &ear_amp_ctl, cs42l73_ear_amp_event,
+			SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SWITCH_E("SPKLO Amp", CS42L73_PWRCTL3, 4, 1,
+			    &spklo_amp_ctl, cs42l73_spklo_spk_amp_event,
+			SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_OUTPUT("HPOUTA"),
+	SND_SOC_DAPM_OUTPUT("HPOUTB"),
+	SND_SOC_DAPM_OUTPUT("LINEOUTA"),
+	SND_SOC_DAPM_OUTPUT("LINEOUTB"),
+	SND_SOC_DAPM_OUTPUT("EAROUT"),
+	SND_SOC_DAPM_OUTPUT("SPKOUT"),
+	SND_SOC_DAPM_OUTPUT("SPKLINEOUT"),
+};
+
+static const struct snd_soc_dapm_route cs42l73_audio_map[] = {
+
+	/* SPKLO EARSPK Paths */
+	{"EAROUT", NULL, "EAR Amp"},
+	{"SPKLINEOUT", NULL, "SPKLO Amp"},
+
+	{"EAR Amp", "Switch", "ESL DAC"},
+	{"SPKLO Amp", "Switch", "ESL DAC"},
+
+	{"ESL DAC", "ESL-ASP Mono Volume", "ESL Mixer"},
+	{"ESL DAC", "ESL-XSP Mono Volume", "ESL Mixer"},
+	{"ESL DAC", "ESL-VSP Mono Volume", "VSPINOUT"},
+	/* Loopback */
+	{"ESL DAC", "ESL-IP Mono Volume", "Input Left Capture"},
+	{"ESL DAC", "ESL-IP Mono Volume", "Input Right Capture"},
+
+	{"ESL Mixer", NULL, "ESL-ASP Mux"},
+	{"ESL Mixer", NULL, "ESL-XSP Mux"},
+
+	{"ESL-ASP Mux", "Left", "ASPINL"},
+	{"ESL-ASP Mux", "Right", "ASPINR"},
+	{"ESL-ASP Mux", "Mono Mix", "ASPINM"},
+
+	{"ESL-XSP Mux", "Left", "XSPINL"},
+	{"ESL-XSP Mux", "Right", "XSPINR"},
+	{"ESL-XSP Mux", "Mono Mix", "XSPINM"},
+
+	/* Speakerphone Paths */
+	{"SPKOUT", NULL, "SPK Amp"},
+	{"SPK Amp", "Switch", "SPK DAC"},
+
+	{"SPK DAC", "SPK-ASP Mono Volume", "SPK Mixer"},
+	{"SPK DAC", "SPK-XSP Mono Volume", "SPK Mixer"},
+	{"SPK DAC", "SPK-VSP Mono Volume", "VSPINOUT"},
+	/* Loopback */
+	{"SPK DAC", "SPK-IP Mono Volume", "Input Left Capture"},
+	{"SPK DAC", "SPK-IP Mono Volume", "Input Right Capture"},
+
+	{"SPK Mixer", NULL, "SPK-ASP Mux"},
+	{"SPK Mixer", NULL, "SPK-XSP Mux"},
+
+	{"SPK-ASP Mux", "Left", "ASPINL"},
+	{"SPK-ASP Mux", "Mono Mix", "ASPINM"},
+	{"SPK-ASP Mux", "Right", "ASPINR"},
+
+	{"SPK-XSP Mux", "Left", "XSPINL"},
+	{"SPK-XSP Mux", "Mono Mix", "XSPINM"},
+	{"SPK-XSP Mux", "Right", "XSPINR"},
+
+	/* HP LineOUT Paths */
+	{"HPOUTA", NULL, "HP Amp"},
+	{"HPOUTB", NULL, "HP Amp"},
+	{"LINEOUTA", NULL, "LO Amp"},
+	{"LINEOUTB", NULL, "LO Amp"},
+
+	{"HP Amp", "Switch", "HL Left DAC"},
+	{"HP Amp", "Switch", "HL Right DAC"},
+	{"LO Amp", "Switch", "HL Left DAC"},
+	{"LO Amp", "Switch", "HL Right DAC"},
+
+	{"HL Left DAC", "HL-XSP Volume", "HL Left Mixer"},
+	{"HL Right DAC", "HL-XSP Volume", "HL Right Mixer"},
+	{"HL Left DAC", "HL-ASP Volume", "HL Left Mixer"},
+	{"HL Right DAC", "HL-ASP Volume", "HL Right Mixer"},
+	{"HL Left DAC", "HL-VSP Volume", "HL Left Mixer"},
+	{"HL Right DAC", "HL-VSP Volume", "HL Right Mixer"},
+	/* Loopback */
+	{"HL Left DAC", "HL-IP Volume", "HL Left Mixer"},
+	{"HL Right DAC", "HL-IP Volume", "HL Right Mixer"},
+	{"HL Left Mixer", NULL, "Input Left Capture"},
+	{"HL Right Mixer", NULL, "Input Right Capture"},
+
+	{"HL Left Mixer", NULL, "ASPINL"},
+	{"HL Right Mixer", NULL, "ASPINR"},
+	{"HL Left Mixer", NULL, "XSPINL"},
+	{"HL Right Mixer", NULL, "XSPINR"},
+	{"HL Left Mixer", NULL, "VSPINOUT"},
+	{"HL Right Mixer", NULL, "VSPINOUT"},
+
+	{"ASPINL", NULL, "ASP Playback"},
+	{"ASPINM", NULL, "ASP Playback"},
+	{"ASPINR", NULL, "ASP Playback"},
+	{"XSPINL", NULL, "XSP Playback"},
+	{"XSPINM", NULL, "XSP Playback"},
+	{"XSPINR", NULL, "XSP Playback"},
+	{"VSPINOUT", NULL, "VSP Playback"},
+
+	/* Capture Paths */
+	{"MIC1", NULL, "MIC1 Bias"},
+	{"PGA Left Mux", "Mic 1", "MIC1"},
+	{"MIC2", NULL, "MIC2 Bias"},
+	{"PGA Right Mux", "Mic 2", "MIC2"},
+
+	{"PGA Left Mux", "Line A", "LINEINA"},
+	{"PGA Right Mux", "Line B", "LINEINB"},
+
+	{"PGA Left", NULL, "PGA Left Mux"},
+	{"PGA Right", NULL, "PGA Right Mux"},
+
+	{"ADC Left", NULL, "PGA Left"},
+	{"ADC Right", NULL, "PGA Right"},
+	{"DMIC Left", NULL, "DMICA"},
+	{"DMIC Right", NULL, "DMICB"},
+
+	{"Input Left Capture", "ADC Left Input", "ADC Left"},
+	{"Input Right Capture", "ADC Right Input", "ADC Right"},
+	{"Input Left Capture", "DMIC Left Input", "DMIC Left"},
+	{"Input Right Capture", "DMIC Right Input", "DMIC Right"},
+
+	/* Audio Capture */
+	{"ASPL Output Mixer", NULL, "Input Left Capture"},
+	{"ASPR Output Mixer", NULL, "Input Right Capture"},
+
+	{"ASPOUTL", "ASP-IP Volume", "ASPL Output Mixer"},
+	{"ASPOUTR", "ASP-IP Volume", "ASPR Output Mixer"},
+
+	/* Auxillary Capture */
+	{"XSPL Output Mixer", NULL, "Input Left Capture"},
+	{"XSPR Output Mixer", NULL, "Input Right Capture"},
+
+	{"XSPOUTL", "XSP-IP Volume", "XSPL Output Mixer"},
+	{"XSPOUTR", "XSP-IP Volume", "XSPR Output Mixer"},
+
+	{"XSPOUTL", NULL, "XSPL Output Mixer"},
+	{"XSPOUTR", NULL, "XSPR Output Mixer"},
+
+	/* Voice Capture */
+	{"VSP Output Mixer", NULL, "Input Left Capture"},
+	{"VSP Output Mixer", NULL, "Input Right Capture"},
+
+	{"VSPINOUT", "VSP-IP Volume", "VSP Output Mixer"},
+
+	{"VSPINOUT", NULL, "VSP Output Mixer"},
+
+	{"ASP Capture", NULL, "ASPOUTL"},
+	{"ASP Capture", NULL, "ASPOUTR"},
+	{"XSP Capture", NULL, "XSPOUTL"},
+	{"XSP Capture", NULL, "XSPOUTR"},
+	{"VSP Capture", NULL, "VSPINOUT"},
+};
+
+struct cs42l73_mclk_div {
+	u32 mclk;
+	u32 srate;
+	u8 mmcc;
+};
+
+static const struct cs42l73_mclk_div cs42l73_mclk_coeffs[] = {
+	/* MCLK, Sample Rate, xMMCC[5:0] */
+	{5644800, 11025, 0x30},
+	{5644800, 22050, 0x20},
+	{5644800, 44100, 0x10},
+
+	{6000000,  8000, 0x39},
+	{6000000, 11025, 0x33},
+	{6000000, 12000, 0x31},
+	{6000000, 16000, 0x29},
+	{6000000, 22050, 0x23},
+	{6000000, 24000, 0x21},
+	{6000000, 32000, 0x19},
+	{6000000, 44100, 0x13},
+	{6000000, 48000, 0x11},
+
+	{6144000,  8000, 0x38},
+	{6144000, 12000, 0x30},
+	{6144000, 16000, 0x28},
+	{6144000, 24000, 0x20},
+	{6144000, 32000, 0x18},
+	{6144000, 48000, 0x10},
+
+	{6500000,  8000, 0x3C},
+	{6500000, 11025, 0x35},
+	{6500000, 12000, 0x34},
+	{6500000, 16000, 0x2C},
+	{6500000, 22050, 0x25},
+	{6500000, 24000, 0x24},
+	{6500000, 32000, 0x1C},
+	{6500000, 44100, 0x15},
+	{6500000, 48000, 0x14},
+
+	{6400000,  8000, 0x3E},
+	{6400000, 11025, 0x37},
+	{6400000, 12000, 0x36},
+	{6400000, 16000, 0x2E},
+	{6400000, 22050, 0x27},
+	{6400000, 24000, 0x26},
+	{6400000, 32000, 0x1E},
+	{6400000, 44100, 0x17},
+	{6400000, 48000, 0x16},
+};
+
+struct cs42l73_mclkx_div {
+	u32 mclkx;
+	u8 ratio;
+	u8 mclkdiv;
+};
+
+static const struct cs42l73_mclkx_div cs42l73_mclkx_coeffs[] = {
+	{5644800,  1, 0},	/* 5644800 */
+	{6000000,  1, 0},	/* 6000000 */
+	{6144000,  1, 0},	/* 6144000 */
+	{11289600, 2, 2},	/* 5644800 */
+	{12288000, 2, 2},	/* 6144000 */
+	{12000000, 2, 2},	/* 6000000 */
+	{13000000, 2, 2},	/* 6500000 */
+	{19200000, 3, 3},	/* 6400000 */
+	{24000000, 4, 4},	/* 6000000 */
+	{26000000, 4, 4},	/* 6500000 */
+	{38400000, 6, 5}	/* 6400000 */
+};
+
+static int cs42l73_get_mclkx_coeff(int mclkx)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cs42l73_mclkx_coeffs); i++) {
+		if (cs42l73_mclkx_coeffs[i].mclkx == mclkx)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static int cs42l73_get_mclk_coeff(int mclk, int srate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cs42l73_mclk_coeffs); i++) {
+		if (cs42l73_mclk_coeffs[i].mclk == mclk &&
+		    cs42l73_mclk_coeffs[i].srate == srate)
+			return i;
+	}
+	return -EINVAL;
+
+}
+
+static int cs42l73_set_mclk(struct snd_soc_dai *dai, unsigned int freq)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
+
+	int mclkx_coeff;
+	u32 mclk = 0;
+	u8 dmmcc = 0;
+
+	/* MCLKX -> MCLK */
+	mclkx_coeff = cs42l73_get_mclkx_coeff(freq);
+	if (mclkx_coeff < 0)
+		return mclkx_coeff;
+
+	mclk = cs42l73_mclkx_coeffs[mclkx_coeff].mclkx /
+		cs42l73_mclkx_coeffs[mclkx_coeff].ratio;
+
+	dev_dbg(component->dev, "MCLK%u %u  <-> internal MCLK %u\n",
+		 priv->mclksel + 1, cs42l73_mclkx_coeffs[mclkx_coeff].mclkx,
+		 mclk);
+
+	dmmcc = (priv->mclksel << 4) |
+		(cs42l73_mclkx_coeffs[mclkx_coeff].mclkdiv << 1);
+
+	snd_soc_component_write(component, CS42L73_DMMCC, dmmcc);
+
+	priv->sysclk = mclkx_coeff;
+	priv->mclk = mclk;
+
+	return 0;
+}
+
+static int cs42l73_set_sysclk(struct snd_soc_dai *dai,
+			      int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case CS42L73_CLKID_MCLK1:
+		break;
+	case CS42L73_CLKID_MCLK2:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if ((cs42l73_set_mclk(dai, freq)) < 0) {
+		dev_err(component->dev, "Unable to set MCLK for dai %s\n",
+			dai->name);
+		return -EINVAL;
+	}
+
+	priv->mclksel = clk_id;
+
+	return 0;
+}
+
+static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
+	u8 id = codec_dai->id;
+	unsigned int inv, format;
+	u8 spc, mmcc;
+
+	spc = snd_soc_component_read32(component, CS42L73_SPC(id));
+	mmcc = snd_soc_component_read32(component, CS42L73_MMCC(id));
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		mmcc |= CS42L73_MS_MASTER;
+		break;
+
+	case SND_SOC_DAIFMT_CBS_CFS:
+		mmcc &= ~CS42L73_MS_MASTER;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+	inv = (fmt & SND_SOC_DAIFMT_INV_MASK);
+
+	switch (format) {
+	case SND_SOC_DAIFMT_I2S:
+		spc &= ~CS42L73_SPDIF_PCM;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		if (mmcc & CS42L73_MS_MASTER) {
+			dev_err(component->dev,
+				"PCM format in slave mode only\n");
+			return -EINVAL;
+		}
+		if (id == CS42L73_ASP) {
+			dev_err(component->dev,
+				"PCM format is not supported on ASP port\n");
+			return -EINVAL;
+		}
+		spc |= CS42L73_SPDIF_PCM;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (spc & CS42L73_SPDIF_PCM) {
+		/* Clear PCM mode, clear PCM_BIT_ORDER bit for MSB->LSB */
+		spc &= ~(CS42L73_PCM_MODE_MASK | CS42L73_PCM_BIT_ORDER);
+		switch (format) {
+		case SND_SOC_DAIFMT_DSP_B:
+			if (inv == SND_SOC_DAIFMT_IB_IF)
+				spc |= CS42L73_PCM_MODE0;
+			if (inv == SND_SOC_DAIFMT_IB_NF)
+				spc |= CS42L73_PCM_MODE1;
+		break;
+		case SND_SOC_DAIFMT_DSP_A:
+			if (inv == SND_SOC_DAIFMT_IB_IF)
+				spc |= CS42L73_PCM_MODE1;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	priv->config[id].spc = spc;
+	priv->config[id].mmcc = mmcc;
+
+	return 0;
+}
+
+static const unsigned int cs42l73_asrc_rates[] = {
+	8000, 11025, 12000, 16000, 22050,
+	24000, 32000, 44100, 48000
+};
+
+static unsigned int cs42l73_get_xspfs_coeff(u32 rate)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(cs42l73_asrc_rates); i++) {
+		if (cs42l73_asrc_rates[i] == rate)
+			return i + 1;
+	}
+	return 0;		/* 0 = Don't know */
+}
+
+static void cs42l73_update_asrc(struct snd_soc_component *component, int id, int srate)
+{
+	u8 spfs = 0;
+
+	if (srate > 0)
+		spfs = cs42l73_get_xspfs_coeff(srate);
+
+	switch (id) {
+	case CS42L73_XSP:
+		snd_soc_component_update_bits(component, CS42L73_VXSPFS, 0x0f, spfs);
+	break;
+	case CS42L73_ASP:
+		snd_soc_component_update_bits(component, CS42L73_ASPC, 0x3c, spfs << 2);
+	break;
+	case CS42L73_VSP:
+		snd_soc_component_update_bits(component, CS42L73_VXSPFS, 0xf0, spfs << 4);
+	break;
+	default:
+	break;
+	}
+}
+
+static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
+	int id = dai->id;
+	int mclk_coeff;
+	int srate = params_rate(params);
+
+	if (priv->config[id].mmcc & CS42L73_MS_MASTER) {
+		/* CS42L73 Master */
+		/* MCLK -> srate */
+		mclk_coeff =
+		    cs42l73_get_mclk_coeff(priv->mclk, srate);
+
+		if (mclk_coeff < 0)
+			return -EINVAL;
+
+		dev_dbg(component->dev,
+			 "DAI[%d]: MCLK %u, srate %u, MMCC[5:0] = %x\n",
+			 id, priv->mclk, srate,
+			 cs42l73_mclk_coeffs[mclk_coeff].mmcc);
+
+		priv->config[id].mmcc &= 0xC0;
+		priv->config[id].mmcc |= cs42l73_mclk_coeffs[mclk_coeff].mmcc;
+		priv->config[id].spc &= 0xFC;
+		/* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */
+		if (priv->mclk >= 6400000)
+			priv->config[id].spc |= CS42L73_MCK_SCLK_64FS;
+		else
+			priv->config[id].spc |= CS42L73_MCK_SCLK_MCLK;
+	} else {
+		/* CS42L73 Slave */
+		priv->config[id].spc &= 0xFC;
+		priv->config[id].spc |= CS42L73_MCK_SCLK_64FS;
+	}
+	/* Update ASRCs */
+	priv->config[id].srate = srate;
+
+	snd_soc_component_write(component, CS42L73_SPC(id), priv->config[id].spc);
+	snd_soc_component_write(component, CS42L73_MMCC(id), priv->config[id].mmcc);
+
+	cs42l73_update_asrc(component, id, srate);
+
+	return 0;
+}
+
+static int cs42l73_set_bias_level(struct snd_soc_component *component,
+				  enum snd_soc_bias_level level)
+{
+	struct cs42l73_private *cs42l73 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_component_update_bits(component, CS42L73_DMMCC, CS42L73_MCLKDIS, 0);
+		snd_soc_component_update_bits(component, CS42L73_PWRCTL1, CS42L73_PDN, 0);
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			regcache_cache_only(cs42l73->regmap, false);
+			regcache_sync(cs42l73->regmap);
+		}
+		snd_soc_component_update_bits(component, CS42L73_PWRCTL1, CS42L73_PDN, 1);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, CS42L73_PWRCTL1, CS42L73_PDN, 1);
+		if (cs42l73->shutdwn_delay > 0) {
+			mdelay(cs42l73->shutdwn_delay);
+			cs42l73->shutdwn_delay = 0;
+		} else {
+			mdelay(15); /* Min amount of time requred to power
+				     * down.
+				     */
+		}
+		snd_soc_component_update_bits(component, CS42L73_DMMCC, CS42L73_MCLKDIS, 1);
+		break;
+	}
+	return 0;
+}
+
+static int cs42l73_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+	struct snd_soc_component *component = dai->component;
+	int id = dai->id;
+
+	return snd_soc_component_update_bits(component, CS42L73_SPC(id), CS42L73_SP_3ST,
+				   tristate << 7);
+}
+
+static const struct snd_pcm_hw_constraint_list constraints_12_24 = {
+	.count  = ARRAY_SIZE(cs42l73_asrc_rates),
+	.list   = cs42l73_asrc_rates,
+};
+
+static int cs42l73_pcm_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+					SNDRV_PCM_HW_PARAM_RATE,
+					&constraints_12_24);
+	return 0;
+}
+
+
+#define CS42L73_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops cs42l73_ops = {
+	.startup = cs42l73_pcm_startup,
+	.hw_params = cs42l73_pcm_hw_params,
+	.set_fmt = cs42l73_set_dai_fmt,
+	.set_sysclk = cs42l73_set_sysclk,
+	.set_tristate = cs42l73_set_tristate,
+};
+
+static struct snd_soc_dai_driver cs42l73_dai[] = {
+	{
+		.name = "cs42l73-xsp",
+		.id = CS42L73_XSP,
+		.playback = {
+			.stream_name = "XSP Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS42L73_FORMATS,
+		},
+		.capture = {
+			.stream_name = "XSP Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS42L73_FORMATS,
+		},
+		.ops = &cs42l73_ops,
+		.symmetric_rates = 1,
+	 },
+	{
+		.name = "cs42l73-asp",
+		.id = CS42L73_ASP,
+		.playback = {
+			.stream_name = "ASP Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS42L73_FORMATS,
+		},
+		.capture = {
+			.stream_name = "ASP Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS42L73_FORMATS,
+		},
+		.ops = &cs42l73_ops,
+		.symmetric_rates = 1,
+	 },
+	{
+		.name = "cs42l73-vsp",
+		.id = CS42L73_VSP,
+		.playback = {
+			.stream_name = "VSP Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS42L73_FORMATS,
+		},
+		.capture = {
+			.stream_name = "VSP Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS42L73_FORMATS,
+		},
+		.ops = &cs42l73_ops,
+		.symmetric_rates = 1,
+	 }
+};
+
+static int cs42l73_probe(struct snd_soc_component *component)
+{
+	struct cs42l73_private *cs42l73 = snd_soc_component_get_drvdata(component);
+
+	/* Set Charge Pump Frequency */
+	if (cs42l73->pdata.chgfreq)
+		snd_soc_component_update_bits(component, CS42L73_CPFCHC,
+				    CS42L73_CHARGEPUMP_MASK,
+					cs42l73->pdata.chgfreq << 4);
+
+	/* MCLK1 as master clk */
+	cs42l73->mclksel = CS42L73_CLKID_MCLK1;
+	cs42l73->mclk = 0;
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_cs42l73 = {
+	.probe			= cs42l73_probe,
+	.set_bias_level		= cs42l73_set_bias_level,
+	.controls		= cs42l73_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs42l73_snd_controls),
+	.dapm_widgets		= cs42l73_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs42l73_dapm_widgets),
+	.dapm_routes		= cs42l73_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cs42l73_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config cs42l73_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = CS42L73_MAX_REGISTER,
+	.reg_defaults = cs42l73_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(cs42l73_reg_defaults),
+	.volatile_reg = cs42l73_volatile_register,
+	.readable_reg = cs42l73_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
+			     const struct i2c_device_id *id)
+{
+	struct cs42l73_private *cs42l73;
+	struct cs42l73_platform_data *pdata = dev_get_platdata(&i2c_client->dev);
+	int ret;
+	unsigned int devid = 0;
+	unsigned int reg;
+	u32 val32;
+
+	cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(*cs42l73), GFP_KERNEL);
+	if (!cs42l73)
+		return -ENOMEM;
+
+	cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap);
+	if (IS_ERR(cs42l73->regmap)) {
+		ret = PTR_ERR(cs42l73->regmap);
+		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	if (pdata) {
+		cs42l73->pdata = *pdata;
+	} else {
+		pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
+				     GFP_KERNEL);
+		if (!pdata)
+			return -ENOMEM;
+
+		if (i2c_client->dev.of_node) {
+			if (of_property_read_u32(i2c_client->dev.of_node,
+				"chgfreq", &val32) >= 0)
+				pdata->chgfreq = val32;
+		}
+		pdata->reset_gpio = of_get_named_gpio(i2c_client->dev.of_node,
+						"reset-gpio", 0);
+		cs42l73->pdata = *pdata;
+	}
+
+	i2c_set_clientdata(i2c_client, cs42l73);
+
+	if (cs42l73->pdata.reset_gpio) {
+		ret = devm_gpio_request_one(&i2c_client->dev,
+					    cs42l73->pdata.reset_gpio,
+					    GPIOF_OUT_INIT_HIGH,
+					    "CS42L73 /RST");
+		if (ret < 0) {
+			dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n",
+				cs42l73->pdata.reset_gpio, ret);
+			return ret;
+		}
+		gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 0);
+		gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 1);
+	}
+
+	/* initialize codec */
+	ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, &reg);
+	devid = (reg & 0xFF) << 12;
+
+	ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_CD, &reg);
+	devid |= (reg & 0xFF) << 4;
+
+	ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_E, &reg);
+	devid |= (reg & 0xF0) >> 4;
+
+	if (devid != CS42L73_DEVID) {
+		ret = -ENODEV;
+		dev_err(&i2c_client->dev,
+			"CS42L73 Device ID (%X). Expected %X\n",
+			devid, CS42L73_DEVID);
+		return ret;
+	}
+
+	ret = regmap_read(cs42l73->regmap, CS42L73_REVID, &reg);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+		return ret;
+	}
+
+	dev_info(&i2c_client->dev,
+		 "Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF);
+
+	ret = devm_snd_soc_register_component(&i2c_client->dev,
+			&soc_component_dev_cs42l73, cs42l73_dai,
+			ARRAY_SIZE(cs42l73_dai));
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static const struct of_device_id cs42l73_of_match[] = {
+	{ .compatible = "cirrus,cs42l73", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cs42l73_of_match);
+
+static const struct i2c_device_id cs42l73_id[] = {
+	{"cs42l73", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs42l73_id);
+
+static struct i2c_driver cs42l73_i2c_driver = {
+	.driver = {
+		   .name = "cs42l73",
+		   .of_match_table = cs42l73_of_match,
+		   },
+	.id_table = cs42l73_id,
+	.probe = cs42l73_i2c_probe,
+
+};
+
+module_i2c_driver(cs42l73_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L73 driver");
+MODULE_AUTHOR("Georgi Vlaev, Nucleus Systems Ltd, <joe@nucleusys.com>");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l73.h b/sound/soc/codecs/cs42l73.h
new file mode 100644
index 0000000..4574618
--- /dev/null
+++ b/sound/soc/codecs/cs42l73.h
@@ -0,0 +1,226 @@
+/*
+ * ALSA SoC CS42L73 codec driver
+ *
+ * Copyright 2011 Cirrus Logic, Inc.
+ *
+ * Author: Georgi Vlaev <joe@nucleusys.com>
+ *	   Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __CS42L73_H__
+#define __CS42L73_H__
+
+/* I2C Registers */
+/* I2C Address: 1001010[R/W] - 10010100 = 0x94(Write); 10010101 = 0x95(Read) */
+#define CS42L73_CHIP_ID		0x4a
+#define CS42L73_DEVID_AB	0x01	/* Device ID A & B [RO]. */
+#define CS42L73_DEVID_CD	0x02    /* Device ID C & D [RO]. */
+#define CS42L73_DEVID_E		0x03    /* Device ID E [RO]. */
+#define CS42L73_REVID		0x05    /* Revision ID [RO]. */
+#define CS42L73_PWRCTL1		0x06    /* Power Control 1. */
+#define CS42L73_PWRCTL2		0x07    /* Power Control 2. */
+#define CS42L73_PWRCTL3		0x08    /* Power Control 3. */
+#define CS42L73_CPFCHC		0x09    /* Charge Pump Freq. Class H Ctl. */
+#define CS42L73_OLMBMSDC	0x0A    /* Output Load, MIC Bias, MIC2 SDT */
+#define CS42L73_DMMCC		0x0B    /* Digital MIC & Master Clock Ctl. */
+#define CS42L73_XSPC		0x0C    /* Auxiliary Serial Port (XSP) Ctl. */
+#define CS42L73_XSPMMCC		0x0D    /* XSP Master Mode Clocking Control. */
+#define CS42L73_ASPC		0x0E    /* Audio Serial Port (ASP) Control. */
+#define CS42L73_ASPMMCC		0x0F    /* ASP Master Mode Clocking Control. */
+#define CS42L73_VSPC		0x10    /* Voice Serial Port (VSP) Control. */
+#define CS42L73_VSPMMCC		0x11    /* VSP Master Mode Clocking Control. */
+#define CS42L73_VXSPFS		0x12    /* VSP & XSP Sample Rate. */
+#define CS42L73_MIOPC		0x13    /* Misc. Input & Output Path Control. */
+#define CS42L73_ADCIPC		0x14	/* ADC/IP Control. */
+#define CS42L73_MICAPREPGAAVOL	0x15	/* MIC 1 [A] PreAmp, PGAA Vol. */
+#define CS42L73_MICBPREPGABVOL	0x16	/* MIC 2 [B] PreAmp, PGAB Vol. */
+#define CS42L73_IPADVOL		0x17	/* Input Pat7h A Digital Volume. */
+#define CS42L73_IPBDVOL		0x18	/* Input Path B Digital Volume. */
+#define CS42L73_PBDC		0x19	/* Playback Digital Control. */
+#define CS42L73_HLADVOL		0x1A	/* HP/Line A Out Digital Vol. */
+#define CS42L73_HLBDVOL		0x1B	/* HP/Line B Out Digital Vol. */
+#define CS42L73_SPKDVOL		0x1C	/* Spkphone Out [A] Digital Vol. */
+#define CS42L73_ESLDVOL		0x1D	/* Ear/Spkphone LO [B] Digital */
+#define CS42L73_HPAAVOL		0x1E	/* HP A Analog Volume. */
+#define CS42L73_HPBAVOL		0x1F	/* HP B Analog Volume. */
+#define CS42L73_LOAAVOL		0x20	/* Line Out A Analog Volume. */
+#define CS42L73_LOBAVOL		0x21	/* Line Out B Analog Volume. */
+#define CS42L73_STRINV		0x22	/* Stereo Input Path Adv. Vol. */
+#define CS42L73_XSPINV		0x23	/* Auxiliary Port Input Advisory Vol. */
+#define CS42L73_ASPINV		0x24	/* Audio Port Input Advisory Vol. */
+#define CS42L73_VSPINV		0x25	/* Voice Port Input Advisory Vol. */
+#define CS42L73_LIMARATEHL	0x26	/* Lmtr Attack Rate HP/Line. */
+#define CS42L73_LIMRRATEHL	0x27	/* Lmtr Ctl, Rel.Rate HP/Line. */
+#define CS42L73_LMAXHL		0x28	/* Lmtr Thresholds HP/Line. */
+#define CS42L73_LIMARATESPK	0x29	/* Lmtr Attack Rate Spkphone [A]. */
+#define CS42L73_LIMRRATESPK	0x2A	/* Lmtr Ctl,Release Rate Spk. [A]. */
+#define CS42L73_LMAXSPK		0x2B	/* Lmtr Thresholds Spkphone [A]. */
+#define CS42L73_LIMARATEESL	0x2C	/* Lmtr Attack Rate  */
+#define CS42L73_LIMRRATEESL	0x2D	/* Lmtr Ctl,Release Rate */
+#define CS42L73_LMAXESL		0x2E	/* Lmtr Thresholds */
+#define CS42L73_ALCARATE	0x2F	/* ALC Enable, Attack Rate AB. */
+#define CS42L73_ALCRRATE	0x30	/* ALC Release Rate AB.  */
+#define CS42L73_ALCMINMAX	0x31	/* ALC Thresholds AB. */
+#define CS42L73_NGCAB		0x32	/* Noise Gate Ctl AB. */
+#define CS42L73_ALCNGMC		0x33	/* ALC & Noise Gate Misc Ctl. */
+#define CS42L73_MIXERCTL	0x34	/* Mixer Control. */
+#define CS42L73_HLAIPAA		0x35	/* HP/LO Left Mixer: L. */
+#define CS42L73_HLBIPBA		0x36	/* HP/LO Right Mixer: R.  */
+#define CS42L73_HLAXSPAA	0x37	/* HP/LO Left Mixer: XSP L */
+#define CS42L73_HLBXSPBA	0x38	/* HP/LO Right Mixer: XSP R */
+#define CS42L73_HLAASPAA	0x39	/* HP/LO Left Mixer: ASP L */
+#define CS42L73_HLBASPBA	0x3A	/* HP/LO Right Mixer: ASP R */
+#define CS42L73_HLAVSPMA	0x3B	/* HP/LO Left Mixer: VSP. */
+#define CS42L73_HLBVSPMA	0x3C	/* HP/LO Right Mixer: VSP */
+#define CS42L73_XSPAIPAA	0x3D	/* XSP Left Mixer: Left */
+#define CS42L73_XSPBIPBA	0x3E	/* XSP Rt. Mixer: Right */
+#define CS42L73_XSPAXSPAA	0x3F	/* XSP Left Mixer: XSP L */
+#define CS42L73_XSPBXSPBA	0x40	/* XSP Rt. Mixer: XSP R */
+#define CS42L73_XSPAASPAA	0x41	/* XSP Left Mixer: ASP L */
+#define CS42L73_XSPAASPBA	0x42	/* XSP Rt. Mixer: ASP R */
+#define CS42L73_XSPAVSPMA	0x43	/* XSP Left Mixer: VSP */
+#define CS42L73_XSPBVSPMA	0x44	/* XSP Rt. Mixer: VSP */
+#define CS42L73_ASPAIPAA	0x45	/* ASP Left Mixer: Left */
+#define CS42L73_ASPBIPBA	0x46	/* ASP Rt. Mixer: Right */
+#define CS42L73_ASPAXSPAA	0x47	/* ASP Left Mixer: XSP L */
+#define CS42L73_ASPBXSPBA	0x48	/* ASP Rt. Mixer: XSP R */
+#define CS42L73_ASPAASPAA	0x49	/* ASP Left Mixer: ASP L */
+#define CS42L73_ASPBASPBA	0x4A	/* ASP Rt. Mixer: ASP R */
+#define CS42L73_ASPAVSPMA	0x4B	/* ASP Left Mixer: VSP */
+#define CS42L73_ASPBVSPMA	0x4C	/* ASP Rt. Mixer: VSP */
+#define CS42L73_VSPAIPAA	0x4D	/* VSP Left Mixer: Left */
+#define CS42L73_VSPBIPBA	0x4E	/* VSP Rt. Mixer: Right */
+#define CS42L73_VSPAXSPAA	0x4F	/* VSP Left Mixer: XSP L */
+#define CS42L73_VSPBXSPBA	0x50	/* VSP Rt. Mixer: XSP R */
+#define CS42L73_VSPAASPAA	0x51	/* VSP Left Mixer: ASP Left */
+#define CS42L73_VSPBASPBA	0x52	/* VSP Rt. Mixer: ASP Right */
+#define CS42L73_VSPAVSPMA	0x53	/* VSP Left Mixer: VSP */
+#define CS42L73_VSPBVSPMA	0x54	/* VSP Rt. Mixer: VSP */
+#define CS42L73_MMIXCTL		0x55	/* Mono Mixer Controls. */
+#define CS42L73_SPKMIPMA	0x56	/* SPK Mono Mixer: In. Path */
+#define CS42L73_SPKMXSPA	0x57	/* SPK Mono Mixer: XSP Mono/L/R Att. */
+#define CS42L73_SPKMASPA	0x58	/* SPK Mono Mixer: ASP Mono/L/R Att. */
+#define CS42L73_SPKMVSPMA	0x59	/* SPK Mono Mixer: VSP Mono Atten. */
+#define CS42L73_ESLMIPMA	0x5A	/* Ear/SpLO Mono Mixer: */
+#define CS42L73_ESLMXSPA	0x5B	/* Ear/SpLO Mono Mixer: XSP */
+#define CS42L73_ESLMASPA	0x5C	/* Ear/SpLO Mono Mixer: ASP */
+#define CS42L73_ESLMVSPMA	0x5D	/* Ear/SpLO Mono Mixer: VSP */
+#define CS42L73_IM1		0x5E	/* Interrupt Mask 1.  */
+#define CS42L73_IM2		0x5F	/* Interrupt Mask 2. */
+#define CS42L73_IS1		0x60	/* Interrupt Status 1 [RO]. */
+#define CS42L73_IS2		0x61	/* Interrupt Status 2 [RO]. */
+#define CS42L73_MAX_REGISTER	0x61	/* Total Registers */
+/* Bitfield Definitions */
+
+/* CS42L73_PWRCTL1 */
+#define CS42L73_PDN_ADCB		(1 << 7)
+#define CS42L73_PDN_DMICB		(1 << 6)
+#define CS42L73_PDN_ADCA		(1 << 5)
+#define CS42L73_PDN_DMICA		(1 << 4)
+#define CS42L73_PDN_LDO			(1 << 2)
+#define CS42L73_DISCHG_FILT		(1 << 1)
+#define CS42L73_PDN			(1 << 0)
+
+/* CS42L73_PWRCTL2 */
+#define CS42L73_PDN_MIC2_BIAS		(1 << 7)
+#define CS42L73_PDN_MIC1_BIAS		(1 << 6)
+#define CS42L73_PDN_VSP			(1 << 4)
+#define CS42L73_PDN_ASP_SDOUT		(1 << 3)
+#define CS42L73_PDN_ASP_SDIN		(1 << 2)
+#define CS42L73_PDN_XSP_SDOUT		(1 << 1)
+#define CS42L73_PDN_XSP_SDIN		(1 << 0)
+
+/* CS42L73_PWRCTL3 */
+#define CS42L73_PDN_THMS		(1 << 5)
+#define CS42L73_PDN_SPKLO		(1 << 4)
+#define CS42L73_PDN_EAR			(1 << 3)
+#define CS42L73_PDN_SPK			(1 << 2)
+#define CS42L73_PDN_LO			(1 << 1)
+#define CS42L73_PDN_HP			(1 << 0)
+
+/* Thermal Overload Detect. Requires interrupt ... */
+#define CS42L73_THMOVLD_150C		0
+#define CS42L73_THMOVLD_132C		1
+#define CS42L73_THMOVLD_115C		2
+#define CS42L73_THMOVLD_098C		3
+
+#define CS42L73_CHARGEPUMP_MASK	(0xF0)
+
+/* CS42L73_ASPC, CS42L73_XSPC, CS42L73_VSPC */
+#define	CS42L73_SP_3ST			(1 << 7)
+#define CS42L73_SPDIF_I2S		(0 << 6)
+#define CS42L73_SPDIF_PCM		(1 << 6)
+#define CS42L73_PCM_MODE0		(0 << 4)
+#define CS42L73_PCM_MODE1		(1 << 4)
+#define CS42L73_PCM_MODE2		(2 << 4)
+#define CS42L73_PCM_MODE_MASK		(3 << 4)
+#define CS42L73_PCM_BIT_ORDER		(1 << 3)
+#define CS42L73_MCK_SCLK_64FS		(0 << 0)
+#define CS42L73_MCK_SCLK_MCLK		(2 << 0)
+#define CS42L73_MCK_SCLK_PREMCLK	(3 << 0)
+
+/* CS42L73_xSPMMCC */
+#define CS42L73_MS_MASTER		(1 << 7)
+
+
+/* CS42L73_DMMCC */
+#define CS42L73_MCLKDIS			(1 << 0)
+#define CS42L73_MCLKSEL_MCLK2		(1 << 4)
+#define CS42L73_MCLKSEL_MCLK1		(0 << 4)
+
+/* CS42L73 MCLK derived from MCLK1 or MCLK2 */
+#define CS42L73_CLKID_MCLK1     0
+#define CS42L73_CLKID_MCLK2     1
+
+#define CS42L73_MCLKXDIV	0
+#define CS42L73_MMCCDIV         1
+
+#define CS42L73_XSP		0
+#define CS42L73_ASP		1
+#define CS42L73_VSP		2
+
+/* IS1, IM1 */
+#define CS42L73_MIC2_SDET		(1 << 6)
+#define CS42L73_THMOVLD			(1 << 4)
+#define CS42L73_DIGMIXOVFL		(1 << 3)
+#define CS42L73_IPBOVFL			(1 << 1)
+#define CS42L73_IPAOVFL			(1 << 0)
+
+/* Analog Softramp */
+#define CS42L73_ANLGOSFT		(1 << 0)
+
+/* HP A/B Analog Mute */
+#define CS42L73_HPA_MUTE		(1 << 7)
+/* LO A/B Analog Mute	*/
+#define CS42L73_LOA_MUTE		(1 << 7)
+/* Digital Mute */
+#define CS42L73_HLAD_MUTE		(1 << 0)
+#define CS42L73_HLBD_MUTE		(1 << 1)
+#define CS42L73_SPKD_MUTE		(1 << 2)
+#define CS42L73_ESLD_MUTE		(1 << 3)
+
+/* Misc defines for codec */
+#define CS42L73_DEVID		0x00042A73
+#define CS42L73_MCLKX_MIN	5644800
+#define CS42L73_MCLKX_MAX	38400000
+
+#define CS42L73_SPC(id)		(CS42L73_XSPC + (id << 1))
+#define CS42L73_MMCC(id)	(CS42L73_XSPMMCC + (id << 1))
+#define CS42L73_SPFS(id)	((id == CS42L73_ASP) ? CS42L73_ASPC : CS42L73_VXSPFS)
+
+#endif	/* __CS42L73_H__ */
diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c
new file mode 100644
index 0000000..0214e3a
--- /dev/null
+++ b/sound/soc/codecs/cs42xx8-i2c.c
@@ -0,0 +1,63 @@
+/*
+ * Cirrus Logic CS42448/CS42888 Audio CODEC DAI I2C driver
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+
+#include "cs42xx8.h"
+
+static int cs42xx8_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	int ret = cs42xx8_probe(&i2c->dev,
+			devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config));
+	if (ret)
+		return ret;
+
+	pm_runtime_enable(&i2c->dev);
+	pm_request_idle(&i2c->dev);
+
+	return 0;
+}
+
+static int cs42xx8_i2c_remove(struct i2c_client *i2c)
+{
+	pm_runtime_disable(&i2c->dev);
+
+	return 0;
+}
+
+static struct i2c_device_id cs42xx8_i2c_id[] = {
+	{"cs42448", (kernel_ulong_t)&cs42448_data},
+	{"cs42888", (kernel_ulong_t)&cs42888_data},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id);
+
+static struct i2c_driver cs42xx8_i2c_driver = {
+	.driver = {
+		.name = "cs42xx8",
+		.pm = &cs42xx8_pm,
+		.of_match_table = cs42xx8_of_match,
+	},
+	.probe = cs42xx8_i2c_probe,
+	.remove = cs42xx8_i2c_remove,
+	.id_table = cs42xx8_i2c_id,
+};
+
+module_i2c_driver(cs42xx8_i2c_driver);
+
+MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec I2C Driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
new file mode 100644
index 0000000..ebb9e0c
--- /dev/null
+++ b/sound/soc/codecs/cs42xx8.c
@@ -0,0 +1,601 @@
+/*
+ * Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "cs42xx8.h"
+
+#define CS42XX8_NUM_SUPPLIES 4
+static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = {
+	"VA",
+	"VD",
+	"VLS",
+	"VLC",
+};
+
+#define CS42XX8_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
+			 SNDRV_PCM_FMTBIT_S20_3LE | \
+			 SNDRV_PCM_FMTBIT_S24_LE | \
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+/* codec private data */
+struct cs42xx8_priv {
+	struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES];
+	const struct cs42xx8_driver_data *drvdata;
+	struct regmap *regmap;
+	struct clk *clk;
+
+	bool slave_mode;
+	unsigned long sysclk;
+	u32 tx_channels;
+};
+
+/* -127.5dB to 0dB with step of 0.5dB */
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+/* -64dB to 24dB with step of 0.5dB */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0);
+
+static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" };
+static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross",
+					"Soft Ramp", "Soft Ramp on Zero Cross" };
+
+static const struct soc_enum adc1_single_enum =
+	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single);
+static const struct soc_enum adc2_single_enum =
+	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single);
+static const struct soc_enum adc3_single_enum =
+	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single);
+static const struct soc_enum dac_szc_enum =
+	SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc);
+static const struct soc_enum adc_szc_enum =
+	SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc);
+
+static const struct snd_kcontrol_new cs42xx8_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1,
+			 CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3,
+			 CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5,
+			 CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7,
+			 CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv),
+	SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1,
+			   CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv),
+	SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3,
+			   CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv),
+	SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0),
+	SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0),
+	SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0),
+	SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0),
+	SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0),
+	SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0),
+	SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1),
+	SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0),
+	SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum),
+	SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum),
+	SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0),
+	SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum),
+	SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0),
+	SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0),
+	SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0),
+	SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum),
+};
+
+static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = {
+	SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5,
+			   CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv),
+	SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0),
+	SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum),
+};
+
+static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1),
+	SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1),
+	SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1),
+	SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1),
+
+	SND_SOC_DAPM_OUTPUT("AOUT1L"),
+	SND_SOC_DAPM_OUTPUT("AOUT1R"),
+	SND_SOC_DAPM_OUTPUT("AOUT2L"),
+	SND_SOC_DAPM_OUTPUT("AOUT2R"),
+	SND_SOC_DAPM_OUTPUT("AOUT3L"),
+	SND_SOC_DAPM_OUTPUT("AOUT3R"),
+	SND_SOC_DAPM_OUTPUT("AOUT4L"),
+	SND_SOC_DAPM_OUTPUT("AOUT4R"),
+
+	SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1),
+	SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1),
+
+	SND_SOC_DAPM_INPUT("AIN1L"),
+	SND_SOC_DAPM_INPUT("AIN1R"),
+	SND_SOC_DAPM_INPUT("AIN2L"),
+	SND_SOC_DAPM_INPUT("AIN2R"),
+
+	SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = {
+	SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1),
+
+	SND_SOC_DAPM_INPUT("AIN3L"),
+	SND_SOC_DAPM_INPUT("AIN3R"),
+};
+
+static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = {
+	/* Playback */
+	{ "AOUT1L", NULL, "DAC1" },
+	{ "AOUT1R", NULL, "DAC1" },
+	{ "DAC1", NULL, "PWR" },
+
+	{ "AOUT2L", NULL, "DAC2" },
+	{ "AOUT2R", NULL, "DAC2" },
+	{ "DAC2", NULL, "PWR" },
+
+	{ "AOUT3L", NULL, "DAC3" },
+	{ "AOUT3R", NULL, "DAC3" },
+	{ "DAC3", NULL, "PWR" },
+
+	{ "AOUT4L", NULL, "DAC4" },
+	{ "AOUT4R", NULL, "DAC4" },
+	{ "DAC4", NULL, "PWR" },
+
+	/* Capture */
+	{ "ADC1", NULL, "AIN1L" },
+	{ "ADC1", NULL, "AIN1R" },
+	{ "ADC1", NULL, "PWR" },
+
+	{ "ADC2", NULL, "AIN2L" },
+	{ "ADC2", NULL, "AIN2R" },
+	{ "ADC2", NULL, "PWR" },
+};
+
+static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {
+	/* Capture */
+	{ "ADC3", NULL, "AIN3L" },
+	{ "ADC3", NULL, "AIN3R" },
+	{ "ADC3", NULL, "PWR" },
+};
+
+struct cs42xx8_ratios {
+	unsigned int ratio;
+	unsigned char speed;
+	unsigned char mclk;
+};
+
+static const struct cs42xx8_ratios cs42xx8_ratios[] = {
+	{ 64, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_256(4) },
+	{ 96, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_384(4) },
+	{ 128, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_512(4) },
+	{ 192, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_768(4) },
+	{ 256, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_256(1) },
+	{ 384, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_384(1) },
+	{ 512, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_512(1) },
+	{ 768, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_768(1) },
+	{ 1024, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_1024(1) }
+};
+
+static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
+
+	cs42xx8->sysclk = freq;
+
+	return 0;
+}
+
+static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			       unsigned int format)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
+	u32 val;
+
+	/* Set DAI format */
+	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_LEFT_J:
+		val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM;
+		break;
+	default:
+		dev_err(component->dev, "unsupported dai format\n");
+		return -EINVAL;
+	}
+
+	regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF,
+			   CS42XX8_INTF_DAC_DIF_MASK |
+			   CS42XX8_INTF_ADC_DIF_MASK, val);
+
+	/* Set master/slave audio interface */
+	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		cs42xx8->slave_mode = true;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		cs42xx8->slave_mode = false;
+		break;
+	default:
+		dev_err(component->dev, "unsupported master/slave mode\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	u32 ratio = cs42xx8->sysclk / params_rate(params);
+	u32 i, fm, val, mask;
+
+	if (tx)
+		cs42xx8->tx_channels = params_channels(params);
+
+	for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
+		if (cs42xx8_ratios[i].ratio == ratio)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(cs42xx8_ratios)) {
+		dev_err(component->dev, "unsupported sysclk ratio\n");
+		return -EINVAL;
+	}
+
+	mask = CS42XX8_FUNCMOD_MFREQ_MASK;
+	val = cs42xx8_ratios[i].mclk;
+
+	fm = cs42xx8->slave_mode ? CS42XX8_FM_AUTO : cs42xx8_ratios[i].speed;
+
+	regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
+			   CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,
+			   CS42XX8_FUNCMOD_xC_FM(tx, fm) | val);
+
+	return 0;
+}
+
+static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
+	u8 dac_unmute = cs42xx8->tx_channels ?
+		        ~((0x1 << cs42xx8->tx_channels) - 1) : 0;
+
+	regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE,
+		     mute ? CS42XX8_DACMUTE_ALL : dac_unmute);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops cs42xx8_dai_ops = {
+	.set_fmt	= cs42xx8_set_dai_fmt,
+	.set_sysclk	= cs42xx8_set_dai_sysclk,
+	.hw_params	= cs42xx8_hw_params,
+	.digital_mute	= cs42xx8_digital_mute,
+};
+
+static struct snd_soc_dai_driver cs42xx8_dai = {
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = CS42XX8_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = CS42XX8_FORMATS,
+	},
+	.ops = &cs42xx8_dai_ops,
+};
+
+static const struct reg_default cs42xx8_reg[] = {
+	{ 0x02, 0x00 },   /* Power Control */
+	{ 0x03, 0xF0 },   /* Functional Mode */
+	{ 0x04, 0x46 },   /* Interface Formats */
+	{ 0x05, 0x00 },   /* ADC Control & DAC De-Emphasis */
+	{ 0x06, 0x10 },   /* Transition Control */
+	{ 0x07, 0x00 },   /* DAC Channel Mute */
+	{ 0x08, 0x00 },   /* Volume Control AOUT1 */
+	{ 0x09, 0x00 },   /* Volume Control AOUT2 */
+	{ 0x0a, 0x00 },   /* Volume Control AOUT3 */
+	{ 0x0b, 0x00 },   /* Volume Control AOUT4 */
+	{ 0x0c, 0x00 },   /* Volume Control AOUT5 */
+	{ 0x0d, 0x00 },   /* Volume Control AOUT6 */
+	{ 0x0e, 0x00 },   /* Volume Control AOUT7 */
+	{ 0x0f, 0x00 },   /* Volume Control AOUT8 */
+	{ 0x10, 0x00 },   /* DAC Channel Invert */
+	{ 0x11, 0x00 },   /* Volume Control AIN1 */
+	{ 0x12, 0x00 },   /* Volume Control AIN2 */
+	{ 0x13, 0x00 },   /* Volume Control AIN3 */
+	{ 0x14, 0x00 },   /* Volume Control AIN4 */
+	{ 0x15, 0x00 },   /* Volume Control AIN5 */
+	{ 0x16, 0x00 },   /* Volume Control AIN6 */
+	{ 0x17, 0x00 },   /* ADC Channel Invert */
+	{ 0x18, 0x00 },   /* Status Control */
+	{ 0x1a, 0x00 },   /* Status Mask */
+	{ 0x1b, 0x00 },   /* MUTEC Pin Control */
+};
+
+static bool cs42xx8_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS42XX8_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs42xx8_writeable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS42XX8_CHIPID:
+	case CS42XX8_STATUS:
+		return false;
+	default:
+		return true;
+	}
+}
+
+const struct regmap_config cs42xx8_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = CS42XX8_LASTREG,
+	.reg_defaults = cs42xx8_reg,
+	.num_reg_defaults = ARRAY_SIZE(cs42xx8_reg),
+	.volatile_reg = cs42xx8_volatile_register,
+	.writeable_reg = cs42xx8_writeable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
+
+static int cs42xx8_component_probe(struct snd_soc_component *component)
+{
+	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	switch (cs42xx8->drvdata->num_adcs) {
+	case 3:
+		snd_soc_add_component_controls(component, cs42xx8_adc3_snd_controls,
+					ARRAY_SIZE(cs42xx8_adc3_snd_controls));
+		snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets,
+					ARRAY_SIZE(cs42xx8_adc3_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes,
+					ARRAY_SIZE(cs42xx8_adc3_dapm_routes));
+		break;
+	default:
+		break;
+	}
+
+	/* Mute all DAC channels */
+	regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver cs42xx8_driver = {
+	.probe			= cs42xx8_component_probe,
+	.controls		= cs42xx8_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs42xx8_snd_controls),
+	.dapm_widgets		= cs42xx8_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs42xx8_dapm_widgets),
+	.dapm_routes		= cs42xx8_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs42xx8_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+const struct cs42xx8_driver_data cs42448_data = {
+	.name = "cs42448",
+	.num_adcs = 3,
+};
+EXPORT_SYMBOL_GPL(cs42448_data);
+
+const struct cs42xx8_driver_data cs42888_data = {
+	.name = "cs42888",
+	.num_adcs = 2,
+};
+EXPORT_SYMBOL_GPL(cs42888_data);
+
+const struct of_device_id cs42xx8_of_match[] = {
+	{ .compatible = "cirrus,cs42448", .data = &cs42448_data, },
+	{ .compatible = "cirrus,cs42888", .data = &cs42888_data, },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
+EXPORT_SYMBOL_GPL(cs42xx8_of_match);
+
+int cs42xx8_probe(struct device *dev, struct regmap *regmap)
+{
+	const struct of_device_id *of_id;
+	struct cs42xx8_priv *cs42xx8;
+	int ret, val, i;
+
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		dev_err(dev, "failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL);
+	if (cs42xx8 == NULL)
+		return -ENOMEM;
+
+	cs42xx8->regmap = regmap;
+	dev_set_drvdata(dev, cs42xx8);
+
+	of_id = of_match_device(cs42xx8_of_match, dev);
+	if (of_id)
+		cs42xx8->drvdata = of_id->data;
+
+	if (!cs42xx8->drvdata) {
+		dev_err(dev, "failed to find driver data\n");
+		return -EINVAL;
+	}
+
+	cs42xx8->clk = devm_clk_get(dev, "mclk");
+	if (IS_ERR(cs42xx8->clk)) {
+		dev_err(dev, "failed to get the clock: %ld\n",
+				PTR_ERR(cs42xx8->clk));
+		return -EINVAL;
+	}
+
+	cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);
+
+	for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++)
+		cs42xx8->supplies[i].supply = cs42xx8_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev,
+			ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies);
+	if (ret) {
+		dev_err(dev, "failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
+				    cs42xx8->supplies);
+	if (ret) {
+		dev_err(dev, "failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	/* Make sure hardware reset done */
+	msleep(5);
+
+	/* Validate the chip ID */
+	ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);
+	if (ret < 0) {
+		dev_err(dev, "failed to get device ID, ret = %d", ret);
+		goto err_enable;
+	}
+
+	/* The top four bits of the chip ID should be 0000 */
+	if (((val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4) != 0x00) {
+		dev_err(dev, "unmatched chip ID: %d\n",
+			(val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4);
+		ret = -EINVAL;
+		goto err_enable;
+	}
+
+	dev_info(dev, "found device, revision %X\n",
+			val & CS42XX8_CHIPID_REV_ID_MASK);
+
+	cs42xx8_dai.name = cs42xx8->drvdata->name;
+
+	/* Each adc supports stereo input */
+	cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2;
+
+	ret = devm_snd_soc_register_component(dev, &cs42xx8_driver, &cs42xx8_dai, 1);
+	if (ret) {
+		dev_err(dev, "failed to register component:%d\n", ret);
+		goto err_enable;
+	}
+
+	regcache_cache_only(cs42xx8->regmap, true);
+
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
+			       cs42xx8->supplies);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cs42xx8_probe);
+
+#ifdef CONFIG_PM
+static int cs42xx8_runtime_resume(struct device *dev)
+{
+	struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(cs42xx8->clk);
+	if (ret) {
+		dev_err(dev, "failed to enable mclk: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
+				    cs42xx8->supplies);
+	if (ret) {
+		dev_err(dev, "failed to enable supplies: %d\n", ret);
+		goto err_clk;
+	}
+
+	/* Make sure hardware reset done */
+	msleep(5);
+
+	regcache_cache_only(cs42xx8->regmap, false);
+
+	ret = regcache_sync(cs42xx8->regmap);
+	if (ret) {
+		dev_err(dev, "failed to sync regmap: %d\n", ret);
+		goto err_bulk;
+	}
+
+	return 0;
+
+err_bulk:
+	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
+			       cs42xx8->supplies);
+err_clk:
+	clk_disable_unprepare(cs42xx8->clk);
+
+	return ret;
+}
+
+static int cs42xx8_runtime_suspend(struct device *dev)
+{
+	struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
+
+	regcache_cache_only(cs42xx8->regmap, true);
+
+	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
+			       cs42xx8->supplies);
+
+	clk_disable_unprepare(cs42xx8->clk);
+
+	return 0;
+}
+#endif
+
+const struct dev_pm_ops cs42xx8_pm = {
+	SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(cs42xx8_pm);
+
+MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h
new file mode 100644
index 0000000..d36c61b
--- /dev/null
+++ b/sound/soc/codecs/cs42xx8.h
@@ -0,0 +1,239 @@
+/*
+ * cs42xx8.h - Cirrus Logic CS42448/CS42888 Audio CODEC driver header file
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _CS42XX8_H
+#define _CS42XX8_H
+
+struct cs42xx8_driver_data {
+	char name[32];
+	int num_adcs;
+};
+
+extern const struct dev_pm_ops cs42xx8_pm;
+extern const struct cs42xx8_driver_data cs42448_data;
+extern const struct cs42xx8_driver_data cs42888_data;
+extern const struct regmap_config cs42xx8_regmap_config;
+extern const struct of_device_id cs42xx8_of_match[];
+int cs42xx8_probe(struct device *dev, struct regmap *regmap);
+
+/* CS42888 register map */
+#define CS42XX8_CHIPID				0x01	/* Chip ID */
+#define CS42XX8_PWRCTL				0x02	/* Power Control */
+#define CS42XX8_FUNCMOD				0x03	/* Functional Mode */
+#define CS42XX8_INTF				0x04	/* Interface Formats */
+#define CS42XX8_ADCCTL				0x05	/* ADC Control */
+#define CS42XX8_TXCTL				0x06	/* Transition Control */
+#define CS42XX8_DACMUTE				0x07	/* DAC Mute Control */
+#define CS42XX8_VOLAOUT1			0x08	/* Volume Control AOUT1 */
+#define CS42XX8_VOLAOUT2			0x09	/* Volume Control AOUT2 */
+#define CS42XX8_VOLAOUT3			0x0A	/* Volume Control AOUT3 */
+#define CS42XX8_VOLAOUT4			0x0B	/* Volume Control AOUT4 */
+#define CS42XX8_VOLAOUT5			0x0C	/* Volume Control AOUT5 */
+#define CS42XX8_VOLAOUT6			0x0D	/* Volume Control AOUT6 */
+#define CS42XX8_VOLAOUT7			0x0E	/* Volume Control AOUT7 */
+#define CS42XX8_VOLAOUT8			0x0F	/* Volume Control AOUT8 */
+#define CS42XX8_DACINV				0x10	/* DAC Channel Invert */
+#define CS42XX8_VOLAIN1				0x11	/* Volume Control AIN1 */
+#define CS42XX8_VOLAIN2				0x12	/* Volume Control AIN2 */
+#define CS42XX8_VOLAIN3				0x13	/* Volume Control AIN3 */
+#define CS42XX8_VOLAIN4				0x14	/* Volume Control AIN4 */
+#define CS42XX8_VOLAIN5				0x15	/* Volume Control AIN5 */
+#define CS42XX8_VOLAIN6				0x16	/* Volume Control AIN6 */
+#define CS42XX8_ADCINV				0x17	/* ADC Channel Invert */
+#define CS42XX8_STATUSCTL			0x18	/* Status Control */
+#define CS42XX8_STATUS				0x19	/* Status */
+#define CS42XX8_STATUSM				0x1A	/* Status Mask */
+#define CS42XX8_MUTEC				0x1B	/* MUTEC Pin Control */
+
+#define CS42XX8_FIRSTREG			CS42XX8_CHIPID
+#define CS42XX8_LASTREG				CS42XX8_MUTEC
+#define CS42XX8_NUMREGS				(CS42XX8_LASTREG - CS42XX8_FIRSTREG + 1)
+#define CS42XX8_I2C_INCR			0x80
+
+/* Chip I.D. and Revision Register (Address 01h) */
+#define CS42XX8_CHIPID_CHIP_ID_MASK		0xF0
+#define CS42XX8_CHIPID_REV_ID_MASK		0x0F
+
+/* Power Control (Address 02h) */
+#define CS42XX8_PWRCTL_PDN_ADC3_SHIFT		7
+#define CS42XX8_PWRCTL_PDN_ADC3_MASK		(1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC3			(1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC2_SHIFT		6
+#define CS42XX8_PWRCTL_PDN_ADC2_MASK		(1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC2			(1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC1_SHIFT		5
+#define CS42XX8_PWRCTL_PDN_ADC1_MASK		(1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC1			(1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC4_SHIFT		4
+#define CS42XX8_PWRCTL_PDN_DAC4_MASK		(1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC4			(1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC3_SHIFT		3
+#define CS42XX8_PWRCTL_PDN_DAC3_MASK		(1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC3			(1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC2_SHIFT		2
+#define CS42XX8_PWRCTL_PDN_DAC2_MASK		(1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC2			(1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC1_SHIFT		1
+#define CS42XX8_PWRCTL_PDN_DAC1_MASK		(1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC1			(1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_SHIFT		0
+#define CS42XX8_PWRCTL_PDN_MASK			(1 << CS42XX8_PWRCTL_PDN_SHIFT)
+#define CS42XX8_PWRCTL_PDN			(1 << CS42XX8_PWRCTL_PDN_SHIFT)
+
+/* Functional Mode (Address 03h) */
+#define CS42XX8_FUNCMOD_DAC_FM_SHIFT		6
+#define CS42XX8_FUNCMOD_DAC_FM_WIDTH		2
+#define CS42XX8_FUNCMOD_DAC_FM_MASK		(((1 << CS42XX8_FUNCMOD_DAC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_DAC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_DAC_FM(v)		((v) << CS42XX8_FUNCMOD_DAC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_ADC_FM_SHIFT		4
+#define CS42XX8_FUNCMOD_ADC_FM_WIDTH		2
+#define CS42XX8_FUNCMOD_ADC_FM_MASK		(((1 << CS42XX8_FUNCMOD_ADC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_ADC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_ADC_FM(v)		((v) << CS42XX8_FUNCMOD_ADC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_xC_FM_MASK(x)		((x) ? CS42XX8_FUNCMOD_DAC_FM_MASK : CS42XX8_FUNCMOD_ADC_FM_MASK)
+#define CS42XX8_FUNCMOD_xC_FM(x, v)		((x) ? CS42XX8_FUNCMOD_DAC_FM(v) : CS42XX8_FUNCMOD_ADC_FM(v))
+#define CS42XX8_FUNCMOD_MFREQ_SHIFT		1
+#define CS42XX8_FUNCMOD_MFREQ_WIDTH		3
+#define CS42XX8_FUNCMOD_MFREQ_MASK		(((1 << CS42XX8_FUNCMOD_MFREQ_WIDTH) - 1) << CS42XX8_FUNCMOD_MFREQ_SHIFT)
+#define CS42XX8_FUNCMOD_MFREQ_256(s)		((0 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_384(s)		((1 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_512(s)		((2 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_768(s)		((3 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_1024(s)		((4 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+
+#define CS42XX8_FM_SINGLE			0
+#define CS42XX8_FM_DOUBLE			1
+#define CS42XX8_FM_QUAD				2
+#define CS42XX8_FM_AUTO				3
+
+/* Interface Formats (Address 04h) */
+#define CS42XX8_INTF_FREEZE_SHIFT		7
+#define CS42XX8_INTF_FREEZE_MASK		(1 << CS42XX8_INTF_FREEZE_SHIFT)
+#define CS42XX8_INTF_FREEZE			(1 << CS42XX8_INTF_FREEZE_SHIFT)
+#define CS42XX8_INTF_AUX_DIF_SHIFT		6
+#define CS42XX8_INTF_AUX_DIF_MASK		(1 << CS42XX8_INTF_AUX_DIF_SHIFT)
+#define CS42XX8_INTF_AUX_DIF			(1 << CS42XX8_INTF_AUX_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_SHIFT		3
+#define CS42XX8_INTF_DAC_DIF_WIDTH		3
+#define CS42XX8_INTF_DAC_DIF_MASK		(((1 << CS42XX8_INTF_DAC_DIF_WIDTH) - 1) << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_LEFTJ		(0 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_I2S		(1 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_RIGHTJ		(2 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_RIGHTJ_16		(3 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_ONELINE_20		(4 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_ONELINE_24		(5 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_TDM		(6 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_SHIFT		0
+#define CS42XX8_INTF_ADC_DIF_WIDTH		3
+#define CS42XX8_INTF_ADC_DIF_MASK		(((1 << CS42XX8_INTF_ADC_DIF_WIDTH) - 1) << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_LEFTJ		(0 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_I2S		(1 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_RIGHTJ		(2 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_RIGHTJ_16		(3 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_ONELINE_20		(4 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_ONELINE_24		(5 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_TDM		(6 << CS42XX8_INTF_ADC_DIF_SHIFT)
+
+/* ADC Control & DAC De-Emphasis (Address 05h) */
+#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT	7
+#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_MASK	(1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT)
+#define CS42XX8_ADCCTL_ADC_HPF_FREEZE		(1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT)
+#define CS42XX8_ADCCTL_DAC_DEM_SHIFT		5
+#define CS42XX8_ADCCTL_DAC_DEM_MASK		(1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT)
+#define CS42XX8_ADCCTL_DAC_DEM			(1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT)
+#define CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT	4
+#define CS42XX8_ADCCTL_ADC1_SINGLE_MASK		(1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC1_SINGLE		(1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT	3
+#define CS42XX8_ADCCTL_ADC2_SINGLE_MASK		(1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC2_SINGLE		(1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT	2
+#define CS42XX8_ADCCTL_ADC3_SINGLE_MASK		(1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC3_SINGLE		(1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_AIN5_MUX_SHIFT		1
+#define CS42XX8_ADCCTL_AIN5_MUX_MASK		(1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT)
+#define CS42XX8_ADCCTL_AIN5_MUX			(1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT)
+#define CS42XX8_ADCCTL_AIN6_MUX_SHIFT		0
+#define CS42XX8_ADCCTL_AIN6_MUX_MASK		(1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT)
+#define CS42XX8_ADCCTL_AIN6_MUX			(1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT)
+
+/* Transition Control (Address 06h) */
+#define CS42XX8_TXCTL_DAC_SNGVOL_SHIFT		7
+#define CS42XX8_TXCTL_DAC_SNGVOL_MASK		(1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_DAC_SNGVOL		(1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_SHIFT		5
+#define CS42XX8_TXCTL_DAC_SZC_WIDTH		2
+#define CS42XX8_TXCTL_DAC_SZC_MASK		(((1 << CS42XX8_TXCTL_DAC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_IC		(0 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_ZC		(1 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_SR		(2 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_SRZC		(3 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_AMUTE_SHIFT		4
+#define CS42XX8_TXCTL_AMUTE_MASK		(1 << CS42XX8_TXCTL_AMUTE_SHIFT)
+#define CS42XX8_TXCTL_AMUTE			(1 << CS42XX8_TXCTL_AMUTE_SHIFT)
+#define CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT		3
+#define CS42XX8_TXCTL_MUTE_ADC_SP_MASK		(1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT)
+#define CS42XX8_TXCTL_MUTE_ADC_SP		(1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT)
+#define CS42XX8_TXCTL_ADC_SNGVOL_SHIFT		2
+#define CS42XX8_TXCTL_ADC_SNGVOL_MASK		(1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_ADC_SNGVOL		(1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_SHIFT		0
+#define CS42XX8_TXCTL_ADC_SZC_MASK		(((1 << CS42XX8_TXCTL_ADC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_IC		(0 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_ZC		(1 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_SR		(2 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_SRZC		(3 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+
+/* DAC Channel Mute (Address 07h) */
+#define CS42XX8_DACMUTE_AOUT(n)			(0x1 << n)
+#define CS42XX8_DACMUTE_ALL			0xff
+
+/* Status Control (Address 18h)*/
+#define CS42XX8_STATUSCTL_INI_SHIFT		2
+#define CS42XX8_STATUSCTL_INI_WIDTH		2
+#define CS42XX8_STATUSCTL_INI_MASK		(((1 << CS42XX8_STATUSCTL_INI_WIDTH) - 1) << CS42XX8_STATUSCTL_INI_SHIFT)
+#define CS42XX8_STATUSCTL_INT_ACTIVE_HIGH	(0 << CS42XX8_STATUSCTL_INI_SHIFT)
+#define CS42XX8_STATUSCTL_INT_ACTIVE_LOW	(1 << CS42XX8_STATUSCTL_INI_SHIFT)
+#define CS42XX8_STATUSCTL_INT_OPEN_DRAIN	(2 << CS42XX8_STATUSCTL_INI_SHIFT)
+
+/* Status (Address 19h)*/
+#define CS42XX8_STATUS_DAC_CLK_ERR_SHIFT	4
+#define CS42XX8_STATUS_DAC_CLK_ERR_MASK		(1 << CS42XX8_STATUS_DAC_CLK_ERR_SHIFT)
+#define CS42XX8_STATUS_ADC_CLK_ERR_SHIFT	3
+#define CS42XX8_STATUS_ADC_CLK_ERR_MASK		(1 << CS42XX8_STATUS_ADC_CLK_ERR_SHIFT)
+#define CS42XX8_STATUS_ADC3_OVFL_SHIFT		2
+#define CS42XX8_STATUS_ADC3_OVFL_MASK		(1 << CS42XX8_STATUS_ADC3_OVFL_SHIFT)
+#define CS42XX8_STATUS_ADC2_OVFL_SHIFT		1
+#define CS42XX8_STATUS_ADC2_OVFL_MASK		(1 << CS42XX8_STATUS_ADC2_OVFL_SHIFT)
+#define CS42XX8_STATUS_ADC1_OVFL_SHIFT		0
+#define CS42XX8_STATUS_ADC1_OVFL_MASK		(1 << CS42XX8_STATUS_ADC1_OVFL_SHIFT)
+
+/* Status Mask (Address 1Ah) */
+#define CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT	4
+#define CS42XX8_STATUS_DAC_CLK_ERR_M_MASK	(1 << CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT)
+#define CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT	3
+#define CS42XX8_STATUS_ADC_CLK_ERR_M_MASK	(1 << CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT)
+#define CS42XX8_STATUS_ADC3_OVFL_M_SHIFT	2
+#define CS42XX8_STATUS_ADC3_OVFL_M_MASK		(1 << CS42XX8_STATUS_ADC3_OVFL_M_SHIFT)
+#define CS42XX8_STATUS_ADC2_OVFL_M_SHIFT	1
+#define CS42XX8_STATUS_ADC2_OVFL_M_MASK		(1 << CS42XX8_STATUS_ADC2_OVFL_M_SHIFT)
+#define CS42XX8_STATUS_ADC1_OVFL_M_SHIFT	0
+#define CS42XX8_STATUS_ADC1_OVFL_M_MASK		(1 << CS42XX8_STATUS_ADC1_OVFL_M_SHIFT)
+
+/* MUTEC Pin Control (Address 1Bh) */
+#define CS42XX8_MUTEC_MCPOLARITY_SHIFT		1
+#define CS42XX8_MUTEC_MCPOLARITY_MASK		(1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
+#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_LOW	(0 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
+#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_HIGH	(1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
+#define CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT	0
+#define CS42XX8_MUTEC_MUTEC_ACTIVE_MASK		(1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT)
+#define CS42XX8_MUTEC_MUTEC_ACTIVE		(1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT)
+#endif /* _CS42XX8_H */
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c
new file mode 100644
index 0000000..80dc421
--- /dev/null
+++ b/sound/soc/codecs/cs43130.c
@@ -0,0 +1,2707 @@
+/*
+ * cs43130.c  --  CS43130 ALSA Soc Audio driver
+ *
+ * Copyright 2017 Cirrus Logic, Inc.
+ *
+ * Authors: Li Xu <li.xu@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_irq.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <sound/jack.h>
+
+#include "cs43130.h"
+
+static const struct reg_default cs43130_reg_defaults[] = {
+	{CS43130_SYS_CLK_CTL_1, 0x06},
+	{CS43130_SP_SRATE, 0x01},
+	{CS43130_SP_BITSIZE, 0x05},
+	{CS43130_PAD_INT_CFG, 0x03},
+	{CS43130_PWDN_CTL, 0xFE},
+	{CS43130_CRYSTAL_SET, 0x04},
+	{CS43130_PLL_SET_1, 0x00},
+	{CS43130_PLL_SET_2, 0x00},
+	{CS43130_PLL_SET_3, 0x00},
+	{CS43130_PLL_SET_4, 0x00},
+	{CS43130_PLL_SET_5, 0x40},
+	{CS43130_PLL_SET_6, 0x10},
+	{CS43130_PLL_SET_7, 0x80},
+	{CS43130_PLL_SET_8, 0x03},
+	{CS43130_PLL_SET_9, 0x02},
+	{CS43130_PLL_SET_10, 0x02},
+	{CS43130_CLKOUT_CTL, 0x00},
+	{CS43130_ASP_NUM_1, 0x01},
+	{CS43130_ASP_NUM_2, 0x00},
+	{CS43130_ASP_DEN_1, 0x08},
+	{CS43130_ASP_DEN_2, 0x00},
+	{CS43130_ASP_LRCK_HI_TIME_1, 0x1F},
+	{CS43130_ASP_LRCK_HI_TIME_2, 0x00},
+	{CS43130_ASP_LRCK_PERIOD_1, 0x3F},
+	{CS43130_ASP_LRCK_PERIOD_2, 0x00},
+	{CS43130_ASP_CLOCK_CONF, 0x0C},
+	{CS43130_ASP_FRAME_CONF, 0x0A},
+	{CS43130_XSP_NUM_1, 0x01},
+	{CS43130_XSP_NUM_2, 0x00},
+	{CS43130_XSP_DEN_1, 0x02},
+	{CS43130_XSP_DEN_2, 0x00},
+	{CS43130_XSP_LRCK_HI_TIME_1, 0x1F},
+	{CS43130_XSP_LRCK_HI_TIME_2, 0x00},
+	{CS43130_XSP_LRCK_PERIOD_1, 0x3F},
+	{CS43130_XSP_LRCK_PERIOD_2, 0x00},
+	{CS43130_XSP_CLOCK_CONF, 0x0C},
+	{CS43130_XSP_FRAME_CONF, 0x0A},
+	{CS43130_ASP_CH_1_LOC, 0x00},
+	{CS43130_ASP_CH_2_LOC, 0x00},
+	{CS43130_ASP_CH_1_SZ_EN, 0x06},
+	{CS43130_ASP_CH_2_SZ_EN, 0x0E},
+	{CS43130_XSP_CH_1_LOC, 0x00},
+	{CS43130_XSP_CH_2_LOC, 0x00},
+	{CS43130_XSP_CH_1_SZ_EN, 0x06},
+	{CS43130_XSP_CH_2_SZ_EN, 0x0E},
+	{CS43130_DSD_VOL_B, 0x78},
+	{CS43130_DSD_VOL_A, 0x78},
+	{CS43130_DSD_PATH_CTL_1, 0xA8},
+	{CS43130_DSD_INT_CFG, 0x00},
+	{CS43130_DSD_PATH_CTL_2, 0x02},
+	{CS43130_DSD_PCM_MIX_CTL, 0x00},
+	{CS43130_DSD_PATH_CTL_3, 0x40},
+	{CS43130_HP_OUT_CTL_1, 0x30},
+	{CS43130_PCM_FILT_OPT, 0x02},
+	{CS43130_PCM_VOL_B, 0x78},
+	{CS43130_PCM_VOL_A, 0x78},
+	{CS43130_PCM_PATH_CTL_1, 0xA8},
+	{CS43130_PCM_PATH_CTL_2, 0x00},
+	{CS43130_CLASS_H_CTL, 0x1E},
+	{CS43130_HP_DETECT, 0x04},
+	{CS43130_HP_LOAD_1, 0x00},
+	{CS43130_HP_MEAS_LOAD_1, 0x00},
+	{CS43130_HP_MEAS_LOAD_2, 0x00},
+	{CS43130_INT_MASK_1, 0xFF},
+	{CS43130_INT_MASK_2, 0xFF},
+	{CS43130_INT_MASK_3, 0xFF},
+	{CS43130_INT_MASK_4, 0xFF},
+	{CS43130_INT_MASK_5, 0xFF},
+};
+
+static bool cs43130_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5:
+	case CS43130_HP_DC_STAT_1 ... CS43130_HP_DC_STAT_2:
+	case CS43130_HP_AC_STAT_1 ... CS43130_HP_AC_STAT_2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs43130_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS43130_DEVID_AB ... CS43130_SYS_CLK_CTL_1:
+	case CS43130_SP_SRATE ... CS43130_PAD_INT_CFG:
+	case CS43130_PWDN_CTL:
+	case CS43130_CRYSTAL_SET:
+	case CS43130_PLL_SET_1 ... CS43130_PLL_SET_5:
+	case CS43130_PLL_SET_6:
+	case CS43130_PLL_SET_7:
+	case CS43130_PLL_SET_8:
+	case CS43130_PLL_SET_9:
+	case CS43130_PLL_SET_10:
+	case CS43130_CLKOUT_CTL:
+	case CS43130_ASP_NUM_1 ... CS43130_ASP_FRAME_CONF:
+	case CS43130_XSP_NUM_1 ... CS43130_XSP_FRAME_CONF:
+	case CS43130_ASP_CH_1_LOC:
+	case CS43130_ASP_CH_2_LOC:
+	case CS43130_ASP_CH_1_SZ_EN:
+	case CS43130_ASP_CH_2_SZ_EN:
+	case CS43130_XSP_CH_1_LOC:
+	case CS43130_XSP_CH_2_LOC:
+	case CS43130_XSP_CH_1_SZ_EN:
+	case CS43130_XSP_CH_2_SZ_EN:
+	case CS43130_DSD_VOL_B ... CS43130_DSD_PATH_CTL_3:
+	case CS43130_HP_OUT_CTL_1:
+	case CS43130_PCM_FILT_OPT ... CS43130_PCM_PATH_CTL_2:
+	case CS43130_CLASS_H_CTL:
+	case CS43130_HP_DETECT:
+	case CS43130_HP_STATUS:
+	case CS43130_HP_LOAD_1:
+	case CS43130_HP_MEAS_LOAD_1:
+	case CS43130_HP_MEAS_LOAD_2:
+	case CS43130_HP_DC_STAT_1:
+	case CS43130_HP_DC_STAT_2:
+	case CS43130_HP_AC_STAT_1:
+	case CS43130_HP_AC_STAT_2:
+	case CS43130_HP_LOAD_STAT:
+	case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5:
+	case CS43130_INT_MASK_1 ... CS43130_INT_MASK_5:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs43130_precious_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5:
+		return true;
+	default:
+		return false;
+	}
+}
+
+struct cs43130_pll_params {
+	unsigned int pll_in;
+	u8 sclk_prediv;
+	u8 pll_div_int;
+	u32 pll_div_frac;
+	u8 pll_mode;
+	u8 pll_divout;
+	unsigned int pll_out;
+	u8 pll_cal_ratio;
+};
+
+static const struct cs43130_pll_params pll_ratio_table[] = {
+	{9600000, 0x02, 0x49, 0x800000, 0x00, 0x08, 22579200, 151},
+	{9600000, 0x02, 0x50, 0x000000, 0x00, 0x08, 24576000, 164},
+
+	{11289600, 0x02, 0X40, 0, 0x01, 0x08, 22579200, 128},
+	{11289600, 0x02, 0x44, 0x06F700, 0x0, 0x08, 24576000, 139},
+
+	{12000000, 0x02, 0x49, 0x800000, 0x00, 0x0A, 22579200, 120},
+	{12000000, 0x02, 0x40, 0x000000, 0x00, 0x08, 24576000, 131},
+
+	{12288000, 0x02, 0x49, 0x800000, 0x01, 0x0A, 22579200, 118},
+	{12288000, 0x02, 0x40, 0x000000, 0x01, 0x08, 24576000, 128},
+
+	{13000000, 0x02, 0x45, 0x797680, 0x01, 0x0A, 22579200, 111},
+	{13000000, 0x02, 0x3C, 0x7EA940, 0x01, 0x08, 24576000, 121},
+
+	{19200000, 0x03, 0x49, 0x800000, 0x00, 0x08, 22579200, 151},
+	{19200000, 0x03, 0x50, 0x000000, 0x00, 0x08, 24576000, 164},
+
+	{22579200, 0, 0, 0, 0, 0, 22579200, 0},
+	{22579200, 0x03, 0x44, 0x06F700, 0x00, 0x08, 24576000, 139},
+
+	{24000000, 0x03, 0x49, 0x800000, 0x00, 0x0A, 22579200, 120},
+	{24000000, 0x03, 0x40, 0x000000, 0x00, 0x08, 24576000, 131},
+
+	{24576000, 0x03, 0x49, 0x800000, 0x01, 0x0A, 22579200, 118},
+	{24576000, 0, 0, 0, 0, 0, 24576000, 0},
+
+	{26000000, 0x03, 0x45, 0x797680, 0x01, 0x0A, 22579200, 111},
+	{26000000, 0x03, 0x3C, 0x7EA940, 0x01, 0x08, 24576000, 121},
+};
+
+static const struct cs43130_pll_params *cs43130_get_pll_table(
+		unsigned int freq_in, unsigned int freq_out)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
+		if (pll_ratio_table[i].pll_in == freq_in &&
+		    pll_ratio_table[i].pll_out == freq_out)
+			return &pll_ratio_table[i];
+	}
+
+	return NULL;
+}
+
+static int cs43130_pll_config(struct snd_soc_component *component)
+{
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+	const struct cs43130_pll_params *pll_entry;
+
+	dev_dbg(component->dev, "cs43130->mclk = %u, cs43130->mclk_int = %u\n",
+		cs43130->mclk, cs43130->mclk_int);
+
+	pll_entry = cs43130_get_pll_table(cs43130->mclk, cs43130->mclk_int);
+	if (!pll_entry)
+		return -EINVAL;
+
+	if (pll_entry->pll_cal_ratio == 0) {
+		regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_1,
+				   CS43130_PLL_START_MASK, 0);
+
+		cs43130->pll_bypass = true;
+		return 0;
+	}
+
+	cs43130->pll_bypass = false;
+
+	regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_2,
+			   CS43130_PLL_DIV_DATA_MASK,
+			   pll_entry->pll_div_frac >>
+			   CS43130_PLL_DIV_FRAC_0_DATA_SHIFT);
+	regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_3,
+			   CS43130_PLL_DIV_DATA_MASK,
+			   pll_entry->pll_div_frac >>
+			   CS43130_PLL_DIV_FRAC_1_DATA_SHIFT);
+	regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_4,
+			   CS43130_PLL_DIV_DATA_MASK,
+			   pll_entry->pll_div_frac >>
+			   CS43130_PLL_DIV_FRAC_2_DATA_SHIFT);
+	regmap_write(cs43130->regmap, CS43130_PLL_SET_5,
+		     pll_entry->pll_div_int);
+	regmap_write(cs43130->regmap, CS43130_PLL_SET_6, pll_entry->pll_divout);
+	regmap_write(cs43130->regmap, CS43130_PLL_SET_7,
+		     pll_entry->pll_cal_ratio);
+	regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_8,
+			   CS43130_PLL_MODE_MASK,
+			   pll_entry->pll_mode << CS43130_PLL_MODE_SHIFT);
+	regmap_write(cs43130->regmap, CS43130_PLL_SET_9,
+		     pll_entry->sclk_prediv);
+	regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_1,
+			   CS43130_PLL_START_MASK, 1);
+
+	return 0;
+}
+
+static int cs43130_set_pll(struct snd_soc_component *component, int pll_id, int source,
+			   unsigned int freq_in, unsigned int freq_out)
+{
+	int ret = 0;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+
+	switch (freq_in) {
+	case 9600000:
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 13000000:
+	case 19200000:
+	case 22579200:
+	case 24000000:
+	case 24576000:
+	case 26000000:
+		cs43130->mclk = freq_in;
+		break;
+	default:
+		dev_err(component->dev,
+			"unsupported pll input reference clock:%d\n", freq_in);
+		return -EINVAL;
+	}
+
+	switch (freq_out) {
+	case 22579200:
+		cs43130->mclk_int = freq_out;
+		break;
+	case 24576000:
+		cs43130->mclk_int = freq_out;
+		break;
+	default:
+		dev_err(component->dev,
+			"unsupported pll output ref clock: %u\n", freq_out);
+		return -EINVAL;
+	}
+
+	ret = cs43130_pll_config(component);
+	dev_dbg(component->dev, "cs43130->pll_bypass = %d", cs43130->pll_bypass);
+	return ret;
+}
+
+static int cs43130_change_clksrc(struct snd_soc_component *component,
+				 enum cs43130_mclk_src_sel src)
+{
+	int ret;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+	int mclk_int_decoded;
+
+	if (src == cs43130->mclk_int_src) {
+		/* clk source has not changed */
+		return 0;
+	}
+
+	switch (cs43130->mclk_int) {
+	case CS43130_MCLK_22M:
+		mclk_int_decoded = CS43130_MCLK_22P5;
+		break;
+	case CS43130_MCLK_24M:
+		mclk_int_decoded = CS43130_MCLK_24P5;
+		break;
+	default:
+		dev_err(component->dev, "Invalid MCLK INT freq: %u\n", cs43130->mclk_int);
+		return -EINVAL;
+	}
+
+	switch (src) {
+	case CS43130_MCLK_SRC_EXT:
+		cs43130->pll_bypass = true;
+		cs43130->mclk_int_src = CS43130_MCLK_SRC_EXT;
+		if (cs43130->xtal_ibias == CS43130_XTAL_UNUSED) {
+			regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+					   CS43130_PDN_XTAL_MASK,
+					   1 << CS43130_PDN_XTAL_SHIFT);
+		} else {
+			reinit_completion(&cs43130->xtal_rdy);
+			regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+					   CS43130_XTAL_RDY_INT_MASK, 0);
+			regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+					   CS43130_PDN_XTAL_MASK, 0);
+			ret = wait_for_completion_timeout(&cs43130->xtal_rdy,
+							  msecs_to_jiffies(100));
+			regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+					   CS43130_XTAL_RDY_INT_MASK,
+					   1 << CS43130_XTAL_RDY_INT_SHIFT);
+			if (ret == 0) {
+				dev_err(component->dev, "Timeout waiting for XTAL_READY interrupt\n");
+				return -ETIMEDOUT;
+			}
+		}
+
+		regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+				   CS43130_MCLK_SRC_SEL_MASK,
+				   src << CS43130_MCLK_SRC_SEL_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+				   CS43130_MCLK_INT_MASK,
+				   mclk_int_decoded << CS43130_MCLK_INT_SHIFT);
+		usleep_range(150, 200);
+
+		regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+				   CS43130_PDN_PLL_MASK,
+				   1 << CS43130_PDN_PLL_SHIFT);
+		break;
+	case CS43130_MCLK_SRC_PLL:
+		cs43130->pll_bypass = false;
+		cs43130->mclk_int_src = CS43130_MCLK_SRC_PLL;
+		if (cs43130->xtal_ibias == CS43130_XTAL_UNUSED) {
+			regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+					   CS43130_PDN_XTAL_MASK,
+					   1 << CS43130_PDN_XTAL_SHIFT);
+		} else {
+			reinit_completion(&cs43130->xtal_rdy);
+			regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+					   CS43130_XTAL_RDY_INT_MASK, 0);
+			regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+					   CS43130_PDN_XTAL_MASK, 0);
+			ret = wait_for_completion_timeout(&cs43130->xtal_rdy,
+							  msecs_to_jiffies(100));
+			regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+					   CS43130_XTAL_RDY_INT_MASK,
+					   1 << CS43130_XTAL_RDY_INT_SHIFT);
+			if (ret == 0) {
+				dev_err(component->dev, "Timeout waiting for XTAL_READY interrupt\n");
+				return -ETIMEDOUT;
+			}
+		}
+
+		reinit_completion(&cs43130->pll_rdy);
+		regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+				   CS43130_PLL_RDY_INT_MASK, 0);
+		regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+				   CS43130_PDN_PLL_MASK, 0);
+		ret = wait_for_completion_timeout(&cs43130->pll_rdy,
+						  msecs_to_jiffies(100));
+		regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+				   CS43130_PLL_RDY_INT_MASK,
+				   1 << CS43130_PLL_RDY_INT_SHIFT);
+		if (ret == 0) {
+			dev_err(component->dev, "Timeout waiting for PLL_READY interrupt\n");
+			return -ETIMEDOUT;
+		}
+
+		regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+				   CS43130_MCLK_SRC_SEL_MASK,
+				   src << CS43130_MCLK_SRC_SEL_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+				   CS43130_MCLK_INT_MASK,
+				   mclk_int_decoded << CS43130_MCLK_INT_SHIFT);
+		usleep_range(150, 200);
+		break;
+	case CS43130_MCLK_SRC_RCO:
+		cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO;
+
+		regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+				   CS43130_MCLK_SRC_SEL_MASK,
+				   src << CS43130_MCLK_SRC_SEL_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1,
+				   CS43130_MCLK_INT_MASK,
+				   CS43130_MCLK_22P5 << CS43130_MCLK_INT_SHIFT);
+		usleep_range(150, 200);
+
+		regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+				   CS43130_PDN_XTAL_MASK,
+				   1 << CS43130_PDN_XTAL_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL,
+				   CS43130_PDN_PLL_MASK,
+				   1 << CS43130_PDN_PLL_SHIFT);
+		break;
+	default:
+		dev_err(component->dev, "Invalid MCLK source value\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct cs43130_bitwidth_map cs43130_bitwidth_table[] = {
+	{8,	CS43130_SP_BIT_SIZE_8,	CS43130_CH_BIT_SIZE_8},
+	{16,	CS43130_SP_BIT_SIZE_16, CS43130_CH_BIT_SIZE_16},
+	{24,	CS43130_SP_BIT_SIZE_24, CS43130_CH_BIT_SIZE_24},
+	{32,	CS43130_SP_BIT_SIZE_32, CS43130_CH_BIT_SIZE_32},
+};
+
+static const struct cs43130_bitwidth_map *cs43130_get_bitwidth_table(
+				unsigned int bitwidth)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cs43130_bitwidth_table); i++) {
+		if (cs43130_bitwidth_table[i].bitwidth == bitwidth)
+			return &cs43130_bitwidth_table[i];
+	}
+
+	return NULL;
+}
+
+static int cs43130_set_bitwidth(int dai_id, unsigned int bitwidth_dai,
+			  struct regmap *regmap)
+{
+	const struct cs43130_bitwidth_map *bw_map;
+
+	bw_map = cs43130_get_bitwidth_table(bitwidth_dai);
+	if (!bw_map)
+		return -EINVAL;
+
+	switch (dai_id) {
+	case CS43130_ASP_PCM_DAI:
+	case CS43130_ASP_DOP_DAI:
+		regmap_update_bits(regmap, CS43130_ASP_CH_1_SZ_EN,
+				   CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
+		regmap_update_bits(regmap, CS43130_ASP_CH_2_SZ_EN,
+				   CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
+		regmap_update_bits(regmap, CS43130_SP_BITSIZE,
+				   CS43130_ASP_BITSIZE_MASK, bw_map->sp_bit);
+		break;
+	case CS43130_XSP_DOP_DAI:
+		regmap_update_bits(regmap, CS43130_XSP_CH_1_SZ_EN,
+				   CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
+		regmap_update_bits(regmap, CS43130_XSP_CH_2_SZ_EN,
+				   CS43130_CH_BITSIZE_MASK, bw_map->ch_bit);
+		regmap_update_bits(regmap, CS43130_SP_BITSIZE,
+				   CS43130_XSP_BITSIZE_MASK, bw_map->sp_bit <<
+				   CS43130_XSP_BITSIZE_SHIFT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct cs43130_rate_map cs43130_rate_table[] = {
+	{32000,		CS43130_ASP_SPRATE_32K},
+	{44100,		CS43130_ASP_SPRATE_44_1K},
+	{48000,		CS43130_ASP_SPRATE_48K},
+	{88200,		CS43130_ASP_SPRATE_88_2K},
+	{96000,		CS43130_ASP_SPRATE_96K},
+	{176400,	CS43130_ASP_SPRATE_176_4K},
+	{192000,	CS43130_ASP_SPRATE_192K},
+	{352800,	CS43130_ASP_SPRATE_352_8K},
+	{384000,	CS43130_ASP_SPRATE_384K},
+};
+
+static const struct cs43130_rate_map *cs43130_get_rate_table(int fs)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cs43130_rate_table); i++) {
+		if (cs43130_rate_table[i].fs == fs)
+			return &cs43130_rate_table[i];
+	}
+
+	return NULL;
+}
+
+static const struct cs43130_clk_gen *cs43130_get_clk_gen(int mclk_int, int fs,
+		const struct cs43130_clk_gen *clk_gen_table, int len_clk_gen_table)
+{
+	int i;
+
+	for (i = 0; i < len_clk_gen_table; i++) {
+		if (clk_gen_table[i].mclk_int == mclk_int &&
+		    clk_gen_table[i].fs == fs)
+			return &clk_gen_table[i];
+	}
+
+	return NULL;
+}
+
+static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk,
+			      struct snd_pcm_hw_params *params,
+			      struct cs43130_private *cs43130)
+{
+	u16 frm_size;
+	u16 hi_size;
+	u8 frm_delay;
+	u8 frm_phase;
+	u8 frm_data;
+	u8 sclk_edge;
+	u8 lrck_edge;
+	u8 clk_data;
+	u8 loc_ch1;
+	u8 loc_ch2;
+	u8 dai_mode_val;
+	const struct cs43130_clk_gen *clk_gen;
+
+	switch (cs43130->dais[dai_id].dai_format) {
+	case SND_SOC_DAIFMT_I2S:
+		hi_size = bitwidth_sclk;
+		frm_delay = 2;
+		frm_phase = 0;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		hi_size = bitwidth_sclk;
+		frm_delay = 2;
+		frm_phase = 1;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		hi_size = 1;
+		frm_delay = 2;
+		frm_phase = 1;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		hi_size = 1;
+		frm_delay = 0;
+		frm_phase = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (cs43130->dais[dai_id].dai_mode) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		dai_mode_val = 0;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		dai_mode_val = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	frm_size = bitwidth_sclk * params_channels(params);
+	sclk_edge = 1;
+	lrck_edge = 0;
+	loc_ch1 = 0;
+	loc_ch2 = bitwidth_sclk * (params_channels(params) - 1);
+
+	frm_data = frm_delay & CS43130_SP_FSD_MASK;
+	frm_data |= (frm_phase << CS43130_SP_STP_SHIFT) & CS43130_SP_STP_MASK;
+
+	clk_data = lrck_edge & CS43130_SP_LCPOL_IN_MASK;
+	clk_data |= (lrck_edge << CS43130_SP_LCPOL_OUT_SHIFT) &
+		    CS43130_SP_LCPOL_OUT_MASK;
+	clk_data |= (sclk_edge << CS43130_SP_SCPOL_IN_SHIFT) &
+		    CS43130_SP_SCPOL_IN_MASK;
+	clk_data |= (sclk_edge << CS43130_SP_SCPOL_OUT_SHIFT) &
+		    CS43130_SP_SCPOL_OUT_MASK;
+	clk_data |= (dai_mode_val << CS43130_SP_MODE_SHIFT) &
+		    CS43130_SP_MODE_MASK;
+
+	switch (dai_id) {
+	case CS43130_ASP_PCM_DAI:
+	case CS43130_ASP_DOP_DAI:
+		regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_PERIOD_1,
+			CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
+			CS43130_SP_LCPR_LSB_DATA_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_PERIOD_2,
+			CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
+			CS43130_SP_LCPR_MSB_DATA_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_HI_TIME_1,
+			CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
+			CS43130_SP_LCHI_LSB_DATA_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_HI_TIME_2,
+			CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
+			CS43130_SP_LCHI_MSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_ASP_FRAME_CONF, frm_data);
+		regmap_write(cs43130->regmap, CS43130_ASP_CH_1_LOC, loc_ch1);
+		regmap_write(cs43130->regmap, CS43130_ASP_CH_2_LOC, loc_ch2);
+		regmap_update_bits(cs43130->regmap, CS43130_ASP_CH_1_SZ_EN,
+			CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_ASP_CH_2_SZ_EN,
+			CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_ASP_CLOCK_CONF, clk_data);
+		break;
+	case CS43130_XSP_DOP_DAI:
+		regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_PERIOD_1,
+			CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
+			CS43130_SP_LCPR_LSB_DATA_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_PERIOD_2,
+			CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >>
+			CS43130_SP_LCPR_MSB_DATA_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_HI_TIME_1,
+			CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
+			CS43130_SP_LCHI_LSB_DATA_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_HI_TIME_2,
+			CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >>
+			CS43130_SP_LCHI_MSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_XSP_FRAME_CONF, frm_data);
+		regmap_write(cs43130->regmap, CS43130_XSP_CH_1_LOC, loc_ch1);
+		regmap_write(cs43130->regmap, CS43130_XSP_CH_2_LOC, loc_ch2);
+		regmap_update_bits(cs43130->regmap, CS43130_XSP_CH_1_SZ_EN,
+			CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_XSP_CH_2_SZ_EN,
+			CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_XSP_CLOCK_CONF, clk_data);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (frm_size) {
+	case 16:
+		clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
+					      params_rate(params),
+					      cs43130_16_clk_gen,
+					      ARRAY_SIZE(cs43130_16_clk_gen));
+		break;
+	case 32:
+		clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
+					      params_rate(params),
+					      cs43130_32_clk_gen,
+					      ARRAY_SIZE(cs43130_32_clk_gen));
+		break;
+	case 48:
+		clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
+					      params_rate(params),
+					      cs43130_48_clk_gen,
+					      ARRAY_SIZE(cs43130_48_clk_gen));
+		break;
+	case 64:
+		clk_gen = cs43130_get_clk_gen(cs43130->mclk_int,
+					      params_rate(params),
+					      cs43130_64_clk_gen,
+					      ARRAY_SIZE(cs43130_64_clk_gen));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (!clk_gen)
+		return -EINVAL;
+
+	switch (dai_id) {
+	case CS43130_ASP_PCM_DAI:
+	case CS43130_ASP_DOP_DAI:
+		regmap_write(cs43130->regmap, CS43130_ASP_DEN_1,
+			     (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >>
+			     CS43130_SP_M_LSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_ASP_DEN_2,
+			     (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >>
+			     CS43130_SP_M_MSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_ASP_NUM_1,
+			     (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >>
+			     CS43130_SP_N_LSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_ASP_NUM_2,
+			     (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >>
+			     CS43130_SP_N_MSB_DATA_SHIFT);
+		break;
+	case CS43130_XSP_DOP_DAI:
+		regmap_write(cs43130->regmap, CS43130_XSP_DEN_1,
+			     (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >>
+			     CS43130_SP_M_LSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_XSP_DEN_2,
+			     (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >>
+			     CS43130_SP_M_MSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_XSP_NUM_1,
+			     (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >>
+			     CS43130_SP_N_LSB_DATA_SHIFT);
+		regmap_write(cs43130->regmap, CS43130_XSP_NUM_2,
+			     (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >>
+			     CS43130_SP_N_MSB_DATA_SHIFT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cs43130_pcm_dsd_mix(bool en, struct regmap *regmap)
+{
+	if (en) {
+		regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL,
+				   CS43130_MIX_PCM_PREP_MASK,
+				   1 << CS43130_MIX_PCM_PREP_SHIFT);
+		usleep_range(6000, 6050);
+		regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL,
+				   CS43130_MIX_PCM_DSD_MASK,
+				   1 << CS43130_MIX_PCM_DSD_SHIFT);
+	} else {
+		regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL,
+				   CS43130_MIX_PCM_DSD_MASK,
+				   0 << CS43130_MIX_PCM_DSD_SHIFT);
+		usleep_range(1600, 1650);
+		regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL,
+				   CS43130_MIX_PCM_PREP_MASK,
+				   0 << CS43130_MIX_PCM_PREP_SHIFT);
+	}
+
+	return 0;
+}
+
+static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+	unsigned int required_clk;
+	u8 dsd_speed;
+
+	mutex_lock(&cs43130->clk_mutex);
+	if (!cs43130->clk_req) {
+		/* no DAI is currently using clk */
+		if (!(CS43130_MCLK_22M % params_rate(params)))
+			required_clk = CS43130_MCLK_22M;
+		else
+			required_clk = CS43130_MCLK_24M;
+
+		cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk);
+		if (cs43130->pll_bypass)
+			cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
+		else
+			cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
+	}
+
+	cs43130->clk_req++;
+	if (cs43130->clk_req == 2)
+		cs43130_pcm_dsd_mix(true, cs43130->regmap);
+	mutex_unlock(&cs43130->clk_mutex);
+
+	switch (params_rate(params)) {
+	case 176400:
+		dsd_speed = 0;
+		break;
+	case 352800:
+		dsd_speed = 1;
+		break;
+	default:
+		dev_err(component->dev, "Rate(%u) not supported\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	if (cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM)
+		regmap_update_bits(cs43130->regmap, CS43130_DSD_INT_CFG,
+				   CS43130_DSD_MASTER, CS43130_DSD_MASTER);
+	else
+		regmap_update_bits(cs43130->regmap, CS43130_DSD_INT_CFG,
+				   CS43130_DSD_MASTER, 0);
+
+	regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+			   CS43130_DSD_SPEED_MASK,
+			   dsd_speed << CS43130_DSD_SPEED_SHIFT);
+	regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+			   CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_DSD <<
+			   CS43130_DSD_SRC_SHIFT);
+
+	return 0;
+}
+
+static int cs43130_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+	const struct cs43130_rate_map *rate_map;
+	unsigned int sclk = cs43130->dais[dai->id].sclk;
+	unsigned int bitwidth_sclk;
+	unsigned int bitwidth_dai = (unsigned int)(params_width(params));
+	unsigned int required_clk;
+	u8 dsd_speed;
+
+	mutex_lock(&cs43130->clk_mutex);
+	if (!cs43130->clk_req) {
+		/* no DAI is currently using clk */
+		if (!(CS43130_MCLK_22M % params_rate(params)))
+			required_clk = CS43130_MCLK_22M;
+		else
+			required_clk = CS43130_MCLK_24M;
+
+		cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk);
+		if (cs43130->pll_bypass)
+			cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
+		else
+			cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
+	}
+
+	cs43130->clk_req++;
+	if (cs43130->clk_req == 2)
+		cs43130_pcm_dsd_mix(true, cs43130->regmap);
+	mutex_unlock(&cs43130->clk_mutex);
+
+	switch (dai->id) {
+	case CS43130_ASP_DOP_DAI:
+	case CS43130_XSP_DOP_DAI:
+		/* DoP bitwidth is always 24-bit */
+		bitwidth_dai = 24;
+		sclk = params_rate(params) * bitwidth_dai *
+		       params_channels(params);
+
+		switch (params_rate(params)) {
+		case 176400:
+			dsd_speed = 0;
+			break;
+		case 352800:
+			dsd_speed = 1;
+			break;
+		default:
+			dev_err(component->dev, "Rate(%u) not supported\n",
+				params_rate(params));
+			return -EINVAL;
+		}
+
+		regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+				   CS43130_DSD_SPEED_MASK,
+				   dsd_speed << CS43130_DSD_SPEED_SHIFT);
+		break;
+	case CS43130_ASP_PCM_DAI:
+		rate_map = cs43130_get_rate_table(params_rate(params));
+		if (!rate_map)
+			return -EINVAL;
+
+		regmap_write(cs43130->regmap, CS43130_SP_SRATE, rate_map->val);
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI (%d)\n", dai->id);
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case CS43130_ASP_DOP_DAI:
+		regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+				   CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_ASP <<
+				   CS43130_DSD_SRC_SHIFT);
+		break;
+	case CS43130_XSP_DOP_DAI:
+		regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
+				   CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_XSP <<
+				   CS43130_DSD_SRC_SHIFT);
+		break;
+	}
+
+	if (!sclk && cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM)
+		/* Calculate SCLK in master mode if unassigned */
+		sclk = params_rate(params) * bitwidth_dai *
+		       params_channels(params);
+
+	if (!sclk) {
+		/* at this point, SCLK must be set */
+		dev_err(component->dev, "SCLK freq is not set\n");
+		return -EINVAL;
+	}
+
+	bitwidth_sclk = (sclk / params_rate(params)) / params_channels(params);
+	if (bitwidth_sclk < bitwidth_dai) {
+		dev_err(component->dev, "Format not supported: SCLK freq is too low\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(component->dev,
+		"sclk = %u, fs = %d, bitwidth_dai = %u\n",
+		sclk, params_rate(params), bitwidth_dai);
+
+	dev_dbg(component->dev,
+		"bitwidth_sclk = %u, num_ch = %u\n",
+		bitwidth_sclk, params_channels(params));
+
+	cs43130_set_bitwidth(dai->id, bitwidth_dai, cs43130->regmap);
+	cs43130_set_sp_fmt(dai->id, bitwidth_sclk, params, cs43130);
+
+	return 0;
+}
+
+static int cs43130_hw_free(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+
+	mutex_lock(&cs43130->clk_mutex);
+	cs43130->clk_req--;
+	if (!cs43130->clk_req) {
+		/* no DAI is currently using clk */
+		cs43130_change_clksrc(component, CS43130_MCLK_SRC_RCO);
+		cs43130_pcm_dsd_mix(false, cs43130->regmap);
+	}
+	mutex_unlock(&cs43130->clk_mutex);
+
+	return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(pcm_vol_tlv, -12750, 50, 1);
+
+static const char * const pcm_ch_text[] = {
+	"Left-Right Ch",
+	"Left-Left Ch",
+	"Right-Left Ch",
+	"Right-Right Ch",
+};
+
+static const struct reg_sequence pcm_ch_en_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{0x180005, 0x8C},
+	{0x180007, 0xAB},
+	{0x180015, 0x31},
+	{0x180017, 0xB2},
+	{0x180025, 0x30},
+	{0x180027, 0x84},
+	{0x180035, 0x9C},
+	{0x180037, 0xAE},
+	{0x18000D, 0x24},
+	{0x18000F, 0xA3},
+	{0x18001D, 0x05},
+	{0x18001F, 0xD4},
+	{0x18002D, 0x0B},
+	{0x18002F, 0xC7},
+	{0x18003D, 0x71},
+	{0x18003F, 0xE7},
+	{CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence pcm_ch_dis_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{0x180005, 0x24},
+	{0x180007, 0xA3},
+	{0x180015, 0x05},
+	{0x180017, 0xD4},
+	{0x180025, 0x0B},
+	{0x180027, 0xC7},
+	{0x180035, 0x71},
+	{0x180037, 0xE7},
+	{0x18000D, 0x8C},
+	{0x18000F, 0xAB},
+	{0x18001D, 0x31},
+	{0x18001F, 0xB2},
+	{0x18002D, 0x30},
+	{0x18002F, 0x84},
+	{0x18003D, 0x9C},
+	{0x18003F, 0xAE},
+	{CS43130_DXD1, 0},
+};
+
+static int cs43130_pcm_ch_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	return snd_soc_get_enum_double(kcontrol, ucontrol);
+}
+
+static int cs43130_pcm_ch_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int *item = ucontrol->value.enumerated.item;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	if (item[0] >= e->items)
+		return -EINVAL;
+	val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+
+	switch (cs43130->dev_id) {
+	case CS43131_CHIP_ID:
+	case CS43198_CHIP_ID:
+		if (val >= 2)
+			regmap_multi_reg_write(cs43130->regmap, pcm_ch_en_seq,
+					       ARRAY_SIZE(pcm_ch_en_seq));
+		else
+			regmap_multi_reg_write(cs43130->regmap, pcm_ch_dis_seq,
+					       ARRAY_SIZE(pcm_ch_dis_seq));
+		break;
+	}
+
+	return snd_soc_put_enum_double(kcontrol, ucontrol);
+}
+
+static SOC_ENUM_SINGLE_DECL(pcm_ch_enum, CS43130_PCM_PATH_CTL_2, 0,
+			    pcm_ch_text);
+
+static const char * const pcm_spd_texts[] = {
+	"Fast",
+	"Slow",
+};
+
+static SOC_ENUM_SINGLE_DECL(pcm_spd_enum, CS43130_PCM_FILT_OPT, 7,
+			    pcm_spd_texts);
+
+static const char * const dsd_texts[] = {
+	"Off",
+	"BCKA Mode",
+	"BCKD Mode",
+};
+
+static const unsigned int dsd_values[] = {
+	CS43130_DSD_SRC_DSD,
+	CS43130_DSD_SRC_ASP,
+	CS43130_DSD_SRC_XSP,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(dsd_enum, CS43130_DSD_INT_CFG, 0, 0x03,
+				  dsd_texts, dsd_values);
+
+static const struct snd_kcontrol_new cs43130_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("Master Playback Volume",
+			 CS43130_PCM_VOL_A, CS43130_PCM_VOL_B, 0, 0xFF, 1,
+			 pcm_vol_tlv),
+	SOC_DOUBLE_R_TLV("Master DSD Playback Volume",
+			 CS43130_DSD_VOL_A, CS43130_DSD_VOL_B, 0, 0xFF, 1,
+			 pcm_vol_tlv),
+	SOC_ENUM_EXT("PCM Ch Select", pcm_ch_enum, cs43130_pcm_ch_get,
+		     cs43130_pcm_ch_put),
+	SOC_ENUM("PCM Filter Speed", pcm_spd_enum),
+	SOC_SINGLE("PCM Phase Compensation", CS43130_PCM_FILT_OPT, 6, 1, 0),
+	SOC_SINGLE("PCM Nonoversample Emulate", CS43130_PCM_FILT_OPT, 5, 1, 0),
+	SOC_SINGLE("PCM High-pass Filter", CS43130_PCM_FILT_OPT, 1, 1, 0),
+	SOC_SINGLE("PCM De-emphasis Filter", CS43130_PCM_FILT_OPT, 0, 1, 0),
+	SOC_ENUM("DSD Phase Modulation", dsd_enum),
+};
+
+static const struct reg_sequence pcm_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD7, 0x01},
+	{CS43130_DXD8, 0},
+	{CS43130_DXD9, 0x01},
+	{CS43130_DXD3, 0x12},
+	{CS43130_DXD4, 0},
+	{CS43130_DXD10, 0x28},
+	{CS43130_DXD11, 0x28},
+	{CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence dsd_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD7, 0x01},
+	{CS43130_DXD8, 0},
+	{CS43130_DXD9, 0x01},
+	{CS43130_DXD3, 0x12},
+	{CS43130_DXD4, 0},
+	{CS43130_DXD10, 0x1E},
+	{CS43130_DXD11, 0x20},
+	{CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence pop_free_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD12, 0x0A},
+	{CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence pop_free_seq2[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD13, 0x20},
+	{CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence mute_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD3, 0x12},
+	{CS43130_DXD5, 0x02},
+	{CS43130_DXD4, 0x12},
+	{CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence unmute_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD3, 0x10},
+	{CS43130_DXD5, 0},
+	{CS43130_DXD4, 0x16},
+	{CS43130_DXD1, 0},
+};
+
+static int cs43130_dsd_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, dsd_seq,
+					       ARRAY_SIZE(dsd_seq));
+			break;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_1,
+				   CS43130_MUTE_MASK, 0);
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, unmute_seq,
+					       ARRAY_SIZE(unmute_seq));
+			break;
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, mute_seq,
+					       ARRAY_SIZE(mute_seq));
+			regmap_update_bits(cs43130->regmap,
+					   CS43130_DSD_PATH_CTL_1,
+					   CS43130_MUTE_MASK, CS43130_MUTE_EN);
+			/*
+			 * DSD Power Down Sequence
+			 * According to Design, 130ms is preferred.
+			 */
+			msleep(130);
+			break;
+		case CS43131_CHIP_ID:
+		case CS43198_CHIP_ID:
+			regmap_update_bits(cs43130->regmap,
+					   CS43130_DSD_PATH_CTL_1,
+					   CS43130_MUTE_MASK, CS43130_MUTE_EN);
+			break;
+		}
+		break;
+	default:
+		dev_err(component->dev, "Invalid event = 0x%x\n", event);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cs43130_pcm_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, pcm_seq,
+					       ARRAY_SIZE(pcm_seq));
+			break;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(cs43130->regmap, CS43130_PCM_PATH_CTL_1,
+				   CS43130_MUTE_MASK, 0);
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, unmute_seq,
+					       ARRAY_SIZE(unmute_seq));
+			break;
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, mute_seq,
+					       ARRAY_SIZE(mute_seq));
+			regmap_update_bits(cs43130->regmap,
+					   CS43130_PCM_PATH_CTL_1,
+					   CS43130_MUTE_MASK, CS43130_MUTE_EN);
+			/*
+			 * PCM Power Down Sequence
+			 * According to Design, 130ms is preferred.
+			 */
+			msleep(130);
+			break;
+		case CS43131_CHIP_ID:
+		case CS43198_CHIP_ID:
+			regmap_update_bits(cs43130->regmap,
+					   CS43130_PCM_PATH_CTL_1,
+					   CS43130_MUTE_MASK, CS43130_MUTE_EN);
+			break;
+		}
+		break;
+	default:
+		dev_err(component->dev, "Invalid event = 0x%x\n", event);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct reg_sequence dac_postpmu_seq[] = {
+	{CS43130_DXD9, 0x0C},
+	{CS43130_DXD3, 0x10},
+	{CS43130_DXD4, 0x20},
+};
+
+static const struct reg_sequence dac_postpmd_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD6, 0x01},
+	{CS43130_DXD1, 0},
+};
+
+static int cs43130_dac_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, pop_free_seq,
+					       ARRAY_SIZE(pop_free_seq));
+			break;
+		case CS43131_CHIP_ID:
+		case CS43198_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, pop_free_seq2,
+					       ARRAY_SIZE(pop_free_seq2));
+			break;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(10000, 10050);
+
+		regmap_write(cs43130->regmap, CS43130_DXD1, 0x99);
+
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, dac_postpmu_seq,
+					       ARRAY_SIZE(dac_postpmu_seq));
+			/*
+			 * Per datasheet, Sec. PCM Power-Up Sequence.
+			 * According to Design, CS43130_DXD12 must be 0 to meet
+			 * THDN and Dynamic Range spec.
+			 */
+			msleep(1000);
+			regmap_write(cs43130->regmap, CS43130_DXD12, 0);
+			break;
+		case CS43131_CHIP_ID:
+		case CS43198_CHIP_ID:
+			usleep_range(12000, 12010);
+			regmap_write(cs43130->regmap, CS43130_DXD13, 0);
+			break;
+		}
+
+		regmap_write(cs43130->regmap, CS43130_DXD1, 0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		switch (cs43130->dev_id) {
+		case CS43130_CHIP_ID:
+		case CS4399_CHIP_ID:
+			regmap_multi_reg_write(cs43130->regmap, dac_postpmd_seq,
+					       ARRAY_SIZE(dac_postpmd_seq));
+			break;
+		}
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAC event = 0x%x\n", event);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct reg_sequence hpin_prepmd_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD15, 0x64},
+	{CS43130_DXD14, 0},
+	{CS43130_DXD2, 0},
+	{CS43130_DXD1, 0},
+};
+
+static const struct reg_sequence hpin_postpmu_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD2, 1},
+	{CS43130_DXD14, 0xDC},
+	{CS43130_DXD15, 0xE4},
+	{CS43130_DXD1, 0},
+};
+
+static int cs43130_hpin_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_multi_reg_write(cs43130->regmap, hpin_prepmd_seq,
+				       ARRAY_SIZE(hpin_prepmd_seq));
+		break;
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_multi_reg_write(cs43130->regmap, hpin_postpmu_seq,
+				       ARRAY_SIZE(hpin_postpmu_seq));
+		break;
+	default:
+		dev_err(component->dev, "Invalid HPIN event = 0x%x\n", event);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget digital_hp_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("HPOUTA"),
+	SND_SOC_DAPM_OUTPUT("HPOUTB"),
+
+	SND_SOC_DAPM_AIF_IN_E("ASPIN PCM", NULL, 0, CS43130_PWDN_CTL,
+			      CS43130_PDN_ASP_SHIFT, 1, cs43130_pcm_event,
+			      (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_PRE_PMD)),
+
+	SND_SOC_DAPM_AIF_IN_E("ASPIN DoP", NULL, 0, CS43130_PWDN_CTL,
+			      CS43130_PDN_ASP_SHIFT, 1, cs43130_dsd_event,
+			      (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_PRE_PMD)),
+
+	SND_SOC_DAPM_AIF_IN_E("XSPIN DoP", NULL, 0, CS43130_PWDN_CTL,
+			      CS43130_PDN_XSP_SHIFT, 1, cs43130_dsd_event,
+			      (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_PRE_PMD)),
+
+	SND_SOC_DAPM_AIF_IN_E("XSPIN DSD", NULL, 0, CS43130_PWDN_CTL,
+			      CS43130_PDN_DSDIF_SHIFT, 1, cs43130_dsd_event,
+			      (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_PRE_PMD)),
+
+	SND_SOC_DAPM_DAC("DSD", NULL, CS43130_DSD_PATH_CTL_2,
+			 CS43130_DSD_EN_SHIFT, 0),
+
+	SND_SOC_DAPM_DAC_E("HiFi DAC", NULL, CS43130_PWDN_CTL,
+			   CS43130_PDN_HP_SHIFT, 1, cs43130_dac_event,
+			   (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			    SND_SOC_DAPM_POST_PMD)),
+};
+
+static const struct snd_soc_dapm_widget analog_hp_widgets[] = {
+	SND_SOC_DAPM_DAC_E("Analog Playback", NULL, CS43130_HP_OUT_CTL_1,
+			   CS43130_HP_IN_EN_SHIFT, 0, cs43130_hpin_event,
+			   (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)),
+};
+
+static struct snd_soc_dapm_widget all_hp_widgets[
+			ARRAY_SIZE(digital_hp_widgets) +
+			ARRAY_SIZE(analog_hp_widgets)];
+
+static const struct snd_soc_dapm_route digital_hp_routes[] = {
+	{"ASPIN PCM", NULL, "ASP PCM Playback"},
+	{"ASPIN DoP", NULL, "ASP DoP Playback"},
+	{"XSPIN DoP", NULL, "XSP DoP Playback"},
+	{"XSPIN DSD", NULL, "XSP DSD Playback"},
+	{"DSD", NULL, "ASPIN DoP"},
+	{"DSD", NULL, "XSPIN DoP"},
+	{"DSD", NULL, "XSPIN DSD"},
+	{"HiFi DAC", NULL, "ASPIN PCM"},
+	{"HiFi DAC", NULL, "DSD"},
+	{"HPOUTA", NULL, "HiFi DAC"},
+	{"HPOUTB", NULL, "HiFi DAC"},
+};
+
+static const struct snd_soc_dapm_route analog_hp_routes[] = {
+	{"HPOUTA", NULL, "Analog Playback"},
+	{"HPOUTB", NULL, "Analog Playback"},
+};
+
+static struct snd_soc_dapm_route all_hp_routes[
+			ARRAY_SIZE(digital_hp_routes) +
+			ARRAY_SIZE(analog_hp_routes)];
+
+static const unsigned int cs43130_asp_src_rates[] = {
+	32000, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000
+};
+
+static const struct snd_pcm_hw_constraint_list cs43130_asp_constraints = {
+	.count	= ARRAY_SIZE(cs43130_asp_src_rates),
+	.list	= cs43130_asp_src_rates,
+};
+
+static int cs43130_pcm_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE,
+					  &cs43130_asp_constraints);
+}
+
+static const unsigned int cs43130_dop_src_rates[] = {
+	176400, 352800,
+};
+
+static const struct snd_pcm_hw_constraint_list cs43130_dop_constraints = {
+	.count	= ARRAY_SIZE(cs43130_dop_src_rates),
+	.list	= cs43130_dop_src_rates,
+};
+
+static int cs43130_dop_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE,
+					  &cs43130_dop_constraints);
+}
+
+static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM;
+		break;
+	default:
+		dev_err(component->dev, "unsupported mode\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_DSP_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_DSP_B;
+		break;
+	default:
+		dev_err(component->dev,
+			"unsupported audio format\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(component->dev, "dai_id = %d,  dai_mode = %u, dai_format = %u\n",
+		codec_dai->id,
+		cs43130->dais[codec_dai->id].dai_mode,
+		cs43130->dais[codec_dai->id].dai_format);
+
+	return 0;
+}
+
+static int cs43130_dsd_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported DAI format.\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(component->dev, "dai_mode = 0x%x\n",
+		cs43130->dais[codec_dai->id].dai_mode);
+
+	return 0;
+}
+
+static int cs43130_set_sysclk(struct snd_soc_dai *codec_dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+
+	cs43130->dais[codec_dai->id].sclk = freq;
+	dev_dbg(component->dev, "dai_id = %d,  sclk = %u\n", codec_dai->id,
+		cs43130->dais[codec_dai->id].sclk);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops cs43130_pcm_ops = {
+	.startup	= cs43130_pcm_startup,
+	.hw_params	= cs43130_hw_params,
+	.hw_free	= cs43130_hw_free,
+	.set_sysclk	= cs43130_set_sysclk,
+	.set_fmt	= cs43130_pcm_set_fmt,
+};
+
+static const struct snd_soc_dai_ops cs43130_dop_ops = {
+	.startup	= cs43130_dop_startup,
+	.hw_params	= cs43130_hw_params,
+	.hw_free	= cs43130_hw_free,
+	.set_sysclk	= cs43130_set_sysclk,
+	.set_fmt	= cs43130_pcm_set_fmt,
+};
+
+static const struct snd_soc_dai_ops cs43130_dsd_ops = {
+	.startup        = cs43130_dop_startup,
+	.hw_params	= cs43130_dsd_hw_params,
+	.hw_free	= cs43130_hw_free,
+	.set_fmt	= cs43130_dsd_set_fmt,
+};
+
+static struct snd_soc_dai_driver cs43130_dai[] = {
+	{
+		.name = "cs43130-asp-pcm",
+		.id = CS43130_ASP_PCM_DAI,
+		.playback = {
+			.stream_name = "ASP PCM Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS43130_PCM_FORMATS,
+		},
+		.ops = &cs43130_pcm_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "cs43130-asp-dop",
+		.id = CS43130_ASP_DOP_DAI,
+		.playback = {
+			.stream_name = "ASP DoP Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS43130_DOP_FORMATS,
+		},
+		.ops = &cs43130_dop_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "cs43130-xsp-dop",
+		.id = CS43130_XSP_DOP_DAI,
+		.playback = {
+			.stream_name = "XSP DoP Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS43130_DOP_FORMATS,
+		},
+		.ops = &cs43130_dop_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "cs43130-xsp-dsd",
+		.id = CS43130_XSP_DSD_DAI,
+		.playback = {
+			.stream_name = "XSP DSD Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_KNOT,
+			.formats = CS43130_DOP_FORMATS,
+		},
+		.ops = &cs43130_dsd_ops,
+	},
+
+};
+
+static int cs43130_component_set_sysclk(struct snd_soc_component *component,
+				    int clk_id, int source, unsigned int freq,
+				    int dir)
+{
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "clk_id = %d, source = %d, freq = %d, dir = %d\n",
+		clk_id, source, freq, dir);
+
+	switch (freq) {
+	case CS43130_MCLK_22M:
+	case CS43130_MCLK_24M:
+		cs43130->mclk = freq;
+		break;
+	default:
+		dev_err(component->dev, "Invalid MCLK INT freq: %u\n", freq);
+		return -EINVAL;
+	}
+
+	if (source == CS43130_MCLK_SRC_EXT) {
+		cs43130->pll_bypass = true;
+	} else {
+		dev_err(component->dev, "Invalid MCLK source\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline u16 cs43130_get_ac_reg_val(u16 ac_freq)
+{
+	/* AC freq is counted in 5.94Hz step. */
+	return ac_freq / 6;
+}
+
+static int cs43130_show_dc(struct device *dev, char *buf, u8 ch)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct cs43130_private *cs43130 = i2c_get_clientdata(client);
+
+	if (!cs43130->hpload_done)
+		return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n");
+	else
+		return scnprintf(buf, PAGE_SIZE, "%u\n",
+				 cs43130->hpload_dc[ch]);
+}
+
+static ssize_t cs43130_show_dc_l(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	return cs43130_show_dc(dev, buf, HP_LEFT);
+}
+
+static ssize_t cs43130_show_dc_r(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	return cs43130_show_dc(dev, buf, HP_RIGHT);
+}
+
+static u16 const cs43130_ac_freq[CS43130_AC_FREQ] = {
+	24,
+	43,
+	93,
+	200,
+	431,
+	928,
+	2000,
+	4309,
+	9283,
+	20000,
+};
+
+static int cs43130_show_ac(struct device *dev, char *buf, u8 ch)
+{
+	int i, j = 0, tmp;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct cs43130_private *cs43130 = i2c_get_clientdata(client);
+
+	if (cs43130->hpload_done && cs43130->ac_meas) {
+		for (i = 0; i < ARRAY_SIZE(cs43130_ac_freq); i++) {
+			tmp = scnprintf(buf + j, PAGE_SIZE - j, "%u\n",
+					cs43130->hpload_ac[i][ch]);
+			if (!tmp)
+				break;
+
+			j += tmp;
+		}
+
+		return j;
+	} else {
+		return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n");
+	}
+}
+
+static ssize_t cs43130_show_ac_l(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	return cs43130_show_ac(dev, buf, HP_LEFT);
+}
+
+static ssize_t cs43130_show_ac_r(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	return cs43130_show_ac(dev, buf, HP_RIGHT);
+}
+
+static DEVICE_ATTR(hpload_dc_l, 0444, cs43130_show_dc_l, NULL);
+static DEVICE_ATTR(hpload_dc_r, 0444, cs43130_show_dc_r, NULL);
+static DEVICE_ATTR(hpload_ac_l, 0444, cs43130_show_ac_l, NULL);
+static DEVICE_ATTR(hpload_ac_r, 0444, cs43130_show_ac_r, NULL);
+
+static struct reg_sequence hp_en_cal_seq[] = {
+	{CS43130_INT_MASK_4, CS43130_INT_MASK_ALL},
+	{CS43130_HP_MEAS_LOAD_1, 0},
+	{CS43130_HP_MEAS_LOAD_2, 0},
+	{CS43130_INT_MASK_4, 0},
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD16, 0xBB},
+	{CS43130_DXD12, 0x01},
+	{CS43130_DXD19, 0xCB},
+	{CS43130_DXD17, 0x95},
+	{CS43130_DXD18, 0x0B},
+	{CS43130_DXD1, 0},
+	{CS43130_HP_LOAD_1, 0x80},
+};
+
+static struct reg_sequence hp_en_cal_seq2[] = {
+	{CS43130_INT_MASK_4, CS43130_INT_MASK_ALL},
+	{CS43130_HP_MEAS_LOAD_1, 0},
+	{CS43130_HP_MEAS_LOAD_2, 0},
+	{CS43130_INT_MASK_4, 0},
+	{CS43130_HP_LOAD_1, 0x80},
+};
+
+static struct reg_sequence hp_dis_cal_seq[] = {
+	{CS43130_HP_LOAD_1, 0x80},
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD12, 0},
+	{CS43130_DXD1, 0},
+	{CS43130_HP_LOAD_1, 0},
+};
+
+static struct reg_sequence hp_dis_cal_seq2[] = {
+	{CS43130_HP_LOAD_1, 0x80},
+	{CS43130_HP_LOAD_1, 0},
+};
+
+static struct reg_sequence hp_dc_ch_l_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD19, 0x0A},
+	{CS43130_DXD17, 0x93},
+	{CS43130_DXD18, 0x0A},
+	{CS43130_DXD1, 0},
+	{CS43130_HP_LOAD_1, 0x80},
+	{CS43130_HP_LOAD_1, 0x81},
+};
+
+static struct reg_sequence hp_dc_ch_l_seq2[] = {
+	{CS43130_HP_LOAD_1, 0x80},
+	{CS43130_HP_LOAD_1, 0x81},
+};
+
+static struct reg_sequence hp_dc_ch_r_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD19, 0x8A},
+	{CS43130_DXD17, 0x15},
+	{CS43130_DXD18, 0x06},
+	{CS43130_DXD1, 0},
+	{CS43130_HP_LOAD_1, 0x90},
+	{CS43130_HP_LOAD_1, 0x91},
+};
+
+static struct reg_sequence hp_dc_ch_r_seq2[] = {
+	{CS43130_HP_LOAD_1, 0x90},
+	{CS43130_HP_LOAD_1, 0x91},
+};
+
+static struct reg_sequence hp_ac_ch_l_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD19, 0x0A},
+	{CS43130_DXD17, 0x93},
+	{CS43130_DXD18, 0x0A},
+	{CS43130_DXD1, 0},
+	{CS43130_HP_LOAD_1, 0x80},
+	{CS43130_HP_LOAD_1, 0x82},
+};
+
+static struct reg_sequence hp_ac_ch_l_seq2[] = {
+	{CS43130_HP_LOAD_1, 0x80},
+	{CS43130_HP_LOAD_1, 0x82},
+};
+
+static struct reg_sequence hp_ac_ch_r_seq[] = {
+	{CS43130_DXD1, 0x99},
+	{CS43130_DXD19, 0x8A},
+	{CS43130_DXD17, 0x15},
+	{CS43130_DXD18, 0x06},
+	{CS43130_DXD1, 0},
+	{CS43130_HP_LOAD_1, 0x90},
+	{CS43130_HP_LOAD_1, 0x92},
+};
+
+static struct reg_sequence hp_ac_ch_r_seq2[] = {
+	{CS43130_HP_LOAD_1, 0x90},
+	{CS43130_HP_LOAD_1, 0x92},
+};
+
+static struct reg_sequence hp_cln_seq[] = {
+	{CS43130_INT_MASK_4, CS43130_INT_MASK_ALL},
+	{CS43130_HP_MEAS_LOAD_1, 0},
+	{CS43130_HP_MEAS_LOAD_2, 0},
+};
+
+struct reg_sequences {
+	struct reg_sequence	*seq;
+	int			size;
+	unsigned int		msk;
+};
+
+static struct reg_sequences hpload_seq1[] = {
+	{
+		.seq	= hp_en_cal_seq,
+		.size	= ARRAY_SIZE(hp_en_cal_seq),
+		.msk	= CS43130_HPLOAD_ON_INT,
+	},
+	{
+		.seq	= hp_dc_ch_l_seq,
+		.size	= ARRAY_SIZE(hp_dc_ch_l_seq),
+		.msk	= CS43130_HPLOAD_DC_INT,
+	},
+	{
+		.seq	= hp_ac_ch_l_seq,
+		.size	= ARRAY_SIZE(hp_ac_ch_l_seq),
+		.msk	= CS43130_HPLOAD_AC_INT,
+	},
+	{
+		.seq	= hp_dis_cal_seq,
+		.size	= ARRAY_SIZE(hp_dis_cal_seq),
+		.msk	= CS43130_HPLOAD_OFF_INT,
+	},
+	{
+		.seq	= hp_en_cal_seq,
+		.size	= ARRAY_SIZE(hp_en_cal_seq),
+		.msk	= CS43130_HPLOAD_ON_INT,
+	},
+	{
+		.seq	= hp_dc_ch_r_seq,
+		.size	= ARRAY_SIZE(hp_dc_ch_r_seq),
+		.msk	= CS43130_HPLOAD_DC_INT,
+	},
+	{
+		.seq	= hp_ac_ch_r_seq,
+		.size	= ARRAY_SIZE(hp_ac_ch_r_seq),
+		.msk	= CS43130_HPLOAD_AC_INT,
+	},
+};
+
+static struct reg_sequences hpload_seq2[] = {
+	{
+		.seq	= hp_en_cal_seq2,
+		.size	= ARRAY_SIZE(hp_en_cal_seq2),
+		.msk	= CS43130_HPLOAD_ON_INT,
+	},
+	{
+		.seq	= hp_dc_ch_l_seq2,
+		.size	= ARRAY_SIZE(hp_dc_ch_l_seq2),
+		.msk	= CS43130_HPLOAD_DC_INT,
+	},
+	{
+		.seq	= hp_ac_ch_l_seq2,
+		.size	= ARRAY_SIZE(hp_ac_ch_l_seq2),
+		.msk	= CS43130_HPLOAD_AC_INT,
+	},
+	{
+		.seq	= hp_dis_cal_seq2,
+		.size	= ARRAY_SIZE(hp_dis_cal_seq2),
+		.msk	= CS43130_HPLOAD_OFF_INT,
+	},
+	{
+		.seq	= hp_en_cal_seq2,
+		.size	= ARRAY_SIZE(hp_en_cal_seq2),
+		.msk	= CS43130_HPLOAD_ON_INT,
+	},
+	{
+		.seq	= hp_dc_ch_r_seq2,
+		.size	= ARRAY_SIZE(hp_dc_ch_r_seq2),
+		.msk	= CS43130_HPLOAD_DC_INT,
+	},
+	{
+		.seq	= hp_ac_ch_r_seq2,
+		.size	= ARRAY_SIZE(hp_ac_ch_r_seq2),
+		.msk	= CS43130_HPLOAD_AC_INT,
+	},
+};
+
+static int cs43130_update_hpload(unsigned int msk, int ac_idx,
+				 struct cs43130_private *cs43130)
+{
+	bool left_ch = true;
+	unsigned int reg;
+	u32 addr;
+	u16 impedance;
+	struct snd_soc_component *component = cs43130->component;
+
+	switch (msk) {
+	case CS43130_HPLOAD_DC_INT:
+	case CS43130_HPLOAD_AC_INT:
+		break;
+	default:
+		return 0;
+	}
+
+	regmap_read(cs43130->regmap, CS43130_HP_LOAD_1, &reg);
+	if (reg & CS43130_HPLOAD_CHN_SEL)
+		left_ch = false;
+
+	if (msk == CS43130_HPLOAD_DC_INT)
+		addr = CS43130_HP_DC_STAT_1;
+	else
+		addr = CS43130_HP_AC_STAT_1;
+
+	regmap_read(cs43130->regmap, addr, &reg);
+	impedance = reg >> 3;
+	regmap_read(cs43130->regmap, addr + 1, &reg);
+	impedance |= reg << 5;
+
+	if (msk == CS43130_HPLOAD_DC_INT) {
+		if (left_ch)
+			cs43130->hpload_dc[HP_LEFT] = impedance;
+		else
+			cs43130->hpload_dc[HP_RIGHT] = impedance;
+
+		dev_dbg(component->dev, "HP DC impedance (Ch %u): %u\n", !left_ch,
+			impedance);
+	} else {
+		if (left_ch)
+			cs43130->hpload_ac[ac_idx][HP_LEFT] = impedance;
+		else
+			cs43130->hpload_ac[ac_idx][HP_RIGHT] = impedance;
+
+		dev_dbg(component->dev, "HP AC (%u Hz) impedance (Ch %u): %u\n",
+			cs43130->ac_freq[ac_idx], !left_ch, impedance);
+	}
+
+	return 0;
+}
+
+static int cs43130_hpload_proc(struct cs43130_private *cs43130,
+			       struct reg_sequence *seq, int seq_size,
+			       unsigned int rslt_msk, int ac_idx)
+{
+	int ret;
+	unsigned int msk;
+	u16 ac_reg_val;
+	struct snd_soc_component *component = cs43130->component;
+
+	reinit_completion(&cs43130->hpload_evt);
+
+	if (rslt_msk == CS43130_HPLOAD_AC_INT) {
+		ac_reg_val = cs43130_get_ac_reg_val(cs43130->ac_freq[ac_idx]);
+		regmap_update_bits(cs43130->regmap, CS43130_HP_LOAD_1,
+				   CS43130_HPLOAD_AC_START, 0);
+		regmap_update_bits(cs43130->regmap, CS43130_HP_MEAS_LOAD_1,
+				   CS43130_HP_MEAS_LOAD_MASK,
+				   ac_reg_val >> CS43130_HP_MEAS_LOAD_1_SHIFT);
+		regmap_update_bits(cs43130->regmap, CS43130_HP_MEAS_LOAD_2,
+				   CS43130_HP_MEAS_LOAD_MASK,
+				   ac_reg_val >> CS43130_HP_MEAS_LOAD_2_SHIFT);
+	}
+
+	regmap_multi_reg_write(cs43130->regmap, seq,
+			       seq_size);
+
+	ret = wait_for_completion_timeout(&cs43130->hpload_evt,
+					  msecs_to_jiffies(1000));
+	regmap_read(cs43130->regmap, CS43130_INT_MASK_4, &msk);
+	if (!ret) {
+		dev_err(component->dev, "Timeout waiting for HPLOAD interrupt\n");
+		return -1;
+	}
+
+	dev_dbg(component->dev, "HP load stat: %x, INT_MASK_4: %x\n",
+		cs43130->hpload_stat, msk);
+	if ((cs43130->hpload_stat & (CS43130_HPLOAD_NO_DC_INT |
+				     CS43130_HPLOAD_UNPLUG_INT |
+				     CS43130_HPLOAD_OOR_INT)) ||
+	    !(cs43130->hpload_stat & rslt_msk)) {
+		dev_dbg(component->dev, "HP load measure failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static const struct reg_sequence hv_seq[][2] = {
+	{
+		{CS43130_CLASS_H_CTL, 0x1C},
+		{CS43130_HP_OUT_CTL_1, 0x10},
+	},
+	{
+		{CS43130_CLASS_H_CTL, 0x1E},
+		{CS43130_HP_OUT_CTL_1, 0x20},
+	},
+	{
+		{CS43130_CLASS_H_CTL, 0x1E},
+		{CS43130_HP_OUT_CTL_1, 0x30},
+	},
+};
+
+static int cs43130_set_hv(struct regmap *regmap, u16 hpload_dc,
+			  const u16 *dc_threshold)
+{
+	int i;
+
+	for (i = 0; i < CS43130_DC_THRESHOLD; i++) {
+		if (hpload_dc <= dc_threshold[i])
+			break;
+	}
+
+	regmap_multi_reg_write(regmap, hv_seq[i], ARRAY_SIZE(hv_seq[i]));
+
+	return 0;
+}
+
+static void cs43130_imp_meas(struct work_struct *wk)
+{
+	unsigned int reg, seq_size;
+	int i, ret, ac_idx;
+	struct cs43130_private *cs43130;
+	struct snd_soc_component *component;
+	struct reg_sequences *hpload_seq;
+
+	cs43130 = container_of(wk, struct cs43130_private, work);
+	component = cs43130->component;
+
+	if (!cs43130->mclk)
+		return;
+
+	cs43130->hpload_done = false;
+
+	mutex_lock(&cs43130->clk_mutex);
+	if (!cs43130->clk_req) {
+		/* clk not in use */
+		cs43130_set_pll(component, 0, 0, cs43130->mclk, CS43130_MCLK_22M);
+		if (cs43130->pll_bypass)
+			cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
+		else
+			cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
+	}
+
+	cs43130->clk_req++;
+	mutex_unlock(&cs43130->clk_mutex);
+
+	regmap_read(cs43130->regmap, CS43130_INT_STATUS_4, &reg);
+
+	switch (cs43130->dev_id) {
+	case CS43130_CHIP_ID:
+		hpload_seq = hpload_seq1;
+		seq_size = ARRAY_SIZE(hpload_seq1);
+		break;
+	case CS43131_CHIP_ID:
+		hpload_seq = hpload_seq2;
+		seq_size = ARRAY_SIZE(hpload_seq2);
+		break;
+	default:
+		WARN(1, "Invalid dev_id for meas: %d", cs43130->dev_id);
+		return;
+	}
+
+	i = 0;
+	ac_idx = 0;
+	while (i < seq_size) {
+		ret = cs43130_hpload_proc(cs43130, hpload_seq[i].seq,
+					  hpload_seq[i].size,
+					  hpload_seq[i].msk, ac_idx);
+		if (ret < 0)
+			goto exit;
+
+		cs43130_update_hpload(hpload_seq[i].msk, ac_idx, cs43130);
+
+		if (cs43130->ac_meas &&
+		    hpload_seq[i].msk == CS43130_HPLOAD_AC_INT &&
+		    ac_idx < CS43130_AC_FREQ - 1) {
+			ac_idx++;
+		} else {
+			ac_idx = 0;
+			i++;
+		}
+	}
+	cs43130->hpload_done = true;
+
+	if (cs43130->hpload_dc[HP_LEFT] >= CS43130_LINEOUT_LOAD)
+		snd_soc_jack_report(&cs43130->jack, CS43130_JACK_LINEOUT,
+				    CS43130_JACK_MASK);
+	else
+		snd_soc_jack_report(&cs43130->jack, CS43130_JACK_HEADPHONE,
+				    CS43130_JACK_MASK);
+
+	dev_dbg(component->dev, "Set HP output control. DC threshold\n");
+	for (i = 0; i < CS43130_DC_THRESHOLD; i++)
+		dev_dbg(component->dev, "DC threshold[%d]: %u.\n", i,
+			cs43130->dc_threshold[i]);
+
+	cs43130_set_hv(cs43130->regmap, cs43130->hpload_dc[HP_LEFT],
+		       cs43130->dc_threshold);
+
+exit:
+	switch (cs43130->dev_id) {
+	case CS43130_CHIP_ID:
+		cs43130_hpload_proc(cs43130, hp_dis_cal_seq,
+				    ARRAY_SIZE(hp_dis_cal_seq),
+				    CS43130_HPLOAD_OFF_INT, ac_idx);
+		break;
+	case CS43131_CHIP_ID:
+		cs43130_hpload_proc(cs43130, hp_dis_cal_seq2,
+				    ARRAY_SIZE(hp_dis_cal_seq2),
+				    CS43130_HPLOAD_OFF_INT, ac_idx);
+		break;
+	}
+
+	regmap_multi_reg_write(cs43130->regmap, hp_cln_seq,
+			       ARRAY_SIZE(hp_cln_seq));
+
+	mutex_lock(&cs43130->clk_mutex);
+	cs43130->clk_req--;
+	/* clk not in use */
+	if (!cs43130->clk_req)
+		cs43130_change_clksrc(component, CS43130_MCLK_SRC_RCO);
+	mutex_unlock(&cs43130->clk_mutex);
+}
+
+static irqreturn_t cs43130_irq_thread(int irq, void *data)
+{
+	struct cs43130_private *cs43130 = (struct cs43130_private *)data;
+	struct snd_soc_component *component = cs43130->component;
+	unsigned int stickies[CS43130_NUM_INT];
+	unsigned int irq_occurrence = 0;
+	unsigned int masks[CS43130_NUM_INT];
+	int i, j;
+
+	for (i = 0; i < ARRAY_SIZE(stickies); i++) {
+		regmap_read(cs43130->regmap, CS43130_INT_STATUS_1 + i,
+			    &stickies[i]);
+		regmap_read(cs43130->regmap, CS43130_INT_MASK_1 + i,
+			    &masks[i]);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(stickies); i++) {
+		stickies[i] = stickies[i] & (~masks[i]);
+		for (j = 0; j < 8; j++)
+			irq_occurrence += (stickies[i] >> j) & 1;
+	}
+	dev_dbg(component->dev, "number of interrupts occurred (%u)\n",
+		irq_occurrence);
+
+	if (!irq_occurrence)
+		return IRQ_NONE;
+
+	if (stickies[0] & CS43130_XTAL_RDY_INT) {
+		complete(&cs43130->xtal_rdy);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[0] & CS43130_PLL_RDY_INT) {
+		complete(&cs43130->pll_rdy);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[3] & CS43130_HPLOAD_NO_DC_INT) {
+		cs43130->hpload_stat = stickies[3];
+		dev_err(component->dev,
+			"DC load has not completed before AC load (%x)\n",
+			cs43130->hpload_stat);
+		complete(&cs43130->hpload_evt);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[3] & CS43130_HPLOAD_UNPLUG_INT) {
+		cs43130->hpload_stat = stickies[3];
+		dev_err(component->dev, "HP unplugged during measurement (%x)\n",
+			cs43130->hpload_stat);
+		complete(&cs43130->hpload_evt);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[3] & CS43130_HPLOAD_OOR_INT) {
+		cs43130->hpload_stat = stickies[3];
+		dev_err(component->dev, "HP load out of range (%x)\n",
+			cs43130->hpload_stat);
+		complete(&cs43130->hpload_evt);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[3] & CS43130_HPLOAD_AC_INT) {
+		cs43130->hpload_stat = stickies[3];
+		dev_dbg(component->dev, "HP AC load measurement done (%x)\n",
+			cs43130->hpload_stat);
+		complete(&cs43130->hpload_evt);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[3] & CS43130_HPLOAD_DC_INT) {
+		cs43130->hpload_stat = stickies[3];
+		dev_dbg(component->dev, "HP DC load measurement done (%x)\n",
+			cs43130->hpload_stat);
+		complete(&cs43130->hpload_evt);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[3] & CS43130_HPLOAD_ON_INT) {
+		cs43130->hpload_stat = stickies[3];
+		dev_dbg(component->dev, "HP load state machine on done (%x)\n",
+			cs43130->hpload_stat);
+		complete(&cs43130->hpload_evt);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[3] & CS43130_HPLOAD_OFF_INT) {
+		cs43130->hpload_stat = stickies[3];
+		dev_dbg(component->dev, "HP load state machine off done (%x)\n",
+			cs43130->hpload_stat);
+		complete(&cs43130->hpload_evt);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[0] & CS43130_XTAL_ERR_INT) {
+		dev_err(component->dev, "Crystal err: clock is not running\n");
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[0] & CS43130_HP_UNPLUG_INT) {
+		dev_dbg(component->dev, "HP unplugged\n");
+		cs43130->hpload_done = false;
+		snd_soc_jack_report(&cs43130->jack, 0, CS43130_JACK_MASK);
+		return IRQ_HANDLED;
+	}
+
+	if (stickies[0] & CS43130_HP_PLUG_INT) {
+		if (cs43130->dc_meas && !cs43130->hpload_done &&
+		    !work_busy(&cs43130->work)) {
+			dev_dbg(component->dev, "HP load queue work\n");
+			queue_work(cs43130->wq, &cs43130->work);
+		}
+
+		snd_soc_jack_report(&cs43130->jack, SND_JACK_MECHANICAL,
+				    CS43130_JACK_MASK);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static int cs43130_probe(struct snd_soc_component *component)
+{
+	int ret;
+	struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_card *card = component->card;
+	unsigned int reg;
+
+	cs43130->component = component;
+
+	if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) {
+		regmap_update_bits(cs43130->regmap, CS43130_CRYSTAL_SET,
+				   CS43130_XTAL_IBIAS_MASK,
+				   cs43130->xtal_ibias);
+		regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+				   CS43130_XTAL_ERR_INT, 0);
+	}
+
+	ret = snd_soc_card_jack_new(card, "Headphone", CS43130_JACK_MASK,
+				    &cs43130->jack, NULL, 0);
+	if (ret < 0) {
+		dev_err(component->dev, "Cannot create jack\n");
+		return ret;
+	}
+
+	cs43130->hpload_done = false;
+	if (cs43130->dc_meas) {
+		ret = device_create_file(component->dev, &dev_attr_hpload_dc_l);
+		if (ret < 0)
+			return ret;
+
+		ret = device_create_file(component->dev, &dev_attr_hpload_dc_r);
+		if (ret < 0)
+			return ret;
+
+		ret = device_create_file(component->dev, &dev_attr_hpload_ac_l);
+		if (ret < 0)
+			return ret;
+
+		ret = device_create_file(component->dev, &dev_attr_hpload_ac_r);
+		if (ret < 0)
+			return ret;
+
+		cs43130->wq = create_singlethread_workqueue("cs43130_hp");
+		INIT_WORK(&cs43130->work, cs43130_imp_meas);
+	}
+
+	regmap_read(cs43130->regmap, CS43130_INT_STATUS_1, &reg);
+	regmap_read(cs43130->regmap, CS43130_HP_STATUS, &reg);
+	regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+			   CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT, 0);
+	regmap_update_bits(cs43130->regmap, CS43130_HP_DETECT,
+			   CS43130_HP_DETECT_CTRL_MASK, 0);
+	regmap_update_bits(cs43130->regmap, CS43130_HP_DETECT,
+			   CS43130_HP_DETECT_CTRL_MASK,
+			   CS43130_HP_DETECT_CTRL_MASK);
+
+	return 0;
+}
+
+static struct snd_soc_component_driver soc_component_dev_cs43130 = {
+	.probe			= cs43130_probe,
+	.controls		= cs43130_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs43130_snd_controls),
+	.set_sysclk		= cs43130_component_set_sysclk,
+	.set_pll		= cs43130_set_pll,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config cs43130_regmap = {
+	.reg_bits		= 24,
+	.pad_bits		= 8,
+	.val_bits		= 8,
+
+	.max_register		= CS43130_LASTREG,
+	.reg_defaults		= cs43130_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(cs43130_reg_defaults),
+	.readable_reg		= cs43130_readable_register,
+	.precious_reg		= cs43130_precious_register,
+	.volatile_reg		= cs43130_volatile_register,
+	.cache_type		= REGCACHE_RBTREE,
+	.use_single_rw		= true, /* needed for regcache_sync */
+};
+
+static u16 const cs43130_dc_threshold[CS43130_DC_THRESHOLD] = {
+	50,
+	120,
+};
+
+static int cs43130_handle_device_data(struct i2c_client *i2c_client,
+				      struct cs43130_private *cs43130)
+{
+	struct device_node *np = i2c_client->dev.of_node;
+	unsigned int val;
+	int i;
+
+	if (of_property_read_u32(np, "cirrus,xtal-ibias", &val) < 0) {
+		/* Crystal is unused. System clock is used for external MCLK */
+		cs43130->xtal_ibias = CS43130_XTAL_UNUSED;
+		return 0;
+	}
+
+	switch (val) {
+	case 1:
+		cs43130->xtal_ibias = CS43130_XTAL_IBIAS_7_5UA;
+		break;
+	case 2:
+		cs43130->xtal_ibias = CS43130_XTAL_IBIAS_12_5UA;
+		break;
+	case 3:
+		cs43130->xtal_ibias = CS43130_XTAL_IBIAS_15UA;
+		break;
+	default:
+		dev_err(&i2c_client->dev,
+			"Invalid cirrus,xtal-ibias value: %d\n", val);
+		return -EINVAL;
+	}
+
+	cs43130->dc_meas = of_property_read_bool(np, "cirrus,dc-measure");
+	cs43130->ac_meas = of_property_read_bool(np, "cirrus,ac-measure");
+
+	if (of_property_read_u16_array(np, "cirrus,ac-freq", cs43130->ac_freq,
+					CS43130_AC_FREQ) < 0) {
+		for (i = 0; i < CS43130_AC_FREQ; i++)
+			cs43130->ac_freq[i] = cs43130_ac_freq[i];
+	}
+
+	if (of_property_read_u16_array(np, "cirrus,dc-threshold",
+				       cs43130->dc_threshold,
+				       CS43130_DC_THRESHOLD) < 0) {
+		for (i = 0; i < CS43130_DC_THRESHOLD; i++)
+			cs43130->dc_threshold[i] = cs43130_dc_threshold[i];
+	}
+
+	return 0;
+}
+
+static int cs43130_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct cs43130_private *cs43130;
+	int ret;
+	unsigned int devid = 0;
+	unsigned int reg;
+	int i;
+
+	cs43130 = devm_kzalloc(&client->dev, sizeof(*cs43130), GFP_KERNEL);
+	if (!cs43130)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, cs43130);
+
+	cs43130->regmap = devm_regmap_init_i2c(client, &cs43130_regmap);
+	if (IS_ERR(cs43130->regmap)) {
+		ret = PTR_ERR(cs43130->regmap);
+		return ret;
+	}
+
+	if (client->dev.of_node) {
+		ret = cs43130_handle_device_data(client, cs43130);
+		if (ret != 0)
+			return ret;
+	}
+	for (i = 0; i < ARRAY_SIZE(cs43130->supplies); i++)
+		cs43130->supplies[i].supply = cs43130_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&client->dev,
+				      ARRAY_SIZE(cs43130->supplies),
+				      cs43130->supplies);
+	if (ret != 0) {
+		dev_err(&client->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs43130->supplies),
+				    cs43130->supplies);
+	if (ret != 0) {
+		dev_err(&client->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	cs43130->reset_gpio = devm_gpiod_get_optional(&client->dev,
+						      "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(cs43130->reset_gpio))
+		return PTR_ERR(cs43130->reset_gpio);
+
+	gpiod_set_value_cansleep(cs43130->reset_gpio, 1);
+
+	usleep_range(2000, 2050);
+
+	ret = regmap_read(cs43130->regmap, CS43130_DEVID_AB, &reg);
+
+	devid = (reg & 0xFF) << 12;
+	ret = regmap_read(cs43130->regmap, CS43130_DEVID_CD, &reg);
+	devid |= (reg & 0xFF) << 4;
+	ret = regmap_read(cs43130->regmap, CS43130_DEVID_E, &reg);
+	devid |= (reg & 0xF0) >> 4;
+
+	switch (devid) {
+	case CS43130_CHIP_ID:
+	case CS4399_CHIP_ID:
+	case CS43131_CHIP_ID:
+	case CS43198_CHIP_ID:
+		break;
+	default:
+		dev_err(&client->dev,
+			"CS43130 Device ID %X. Expected ID %X, %X, %X or %X\n",
+			devid, CS43130_CHIP_ID, CS4399_CHIP_ID,
+			CS43131_CHIP_ID, CS43198_CHIP_ID);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	cs43130->dev_id = devid;
+	ret = regmap_read(cs43130->regmap, CS43130_REV_ID, &reg);
+	if (ret < 0) {
+		dev_err(&client->dev, "Get Revision ID failed\n");
+		goto err;
+	}
+
+	dev_info(&client->dev,
+		 "Cirrus Logic CS43130 (%x), Revision: %02X\n", devid,
+		 reg & 0xFF);
+
+	mutex_init(&cs43130->clk_mutex);
+
+	init_completion(&cs43130->xtal_rdy);
+	init_completion(&cs43130->pll_rdy);
+	init_completion(&cs43130->hpload_evt);
+
+	ret = devm_request_threaded_irq(&client->dev, client->irq,
+					NULL, cs43130_irq_thread,
+					IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+					"cs43130", cs43130);
+	if (ret != 0) {
+		dev_err(&client->dev, "Failed to request IRQ: %d\n", ret);
+		return ret;
+	}
+
+	cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO;
+
+	pm_runtime_set_autosuspend_delay(&client->dev, 100);
+	pm_runtime_use_autosuspend(&client->dev);
+	pm_runtime_set_active(&client->dev);
+	pm_runtime_enable(&client->dev);
+
+	switch (cs43130->dev_id) {
+	case CS43130_CHIP_ID:
+	case CS43131_CHIP_ID:
+		memcpy(all_hp_widgets, digital_hp_widgets,
+		       sizeof(digital_hp_widgets));
+		memcpy(all_hp_widgets + ARRAY_SIZE(digital_hp_widgets),
+		       analog_hp_widgets, sizeof(analog_hp_widgets));
+		memcpy(all_hp_routes, digital_hp_routes,
+		       sizeof(digital_hp_routes));
+		memcpy(all_hp_routes + ARRAY_SIZE(digital_hp_routes),
+		       analog_hp_routes, sizeof(analog_hp_routes));
+
+		soc_component_dev_cs43130.dapm_widgets =
+			all_hp_widgets;
+		soc_component_dev_cs43130.num_dapm_widgets =
+			ARRAY_SIZE(all_hp_widgets);
+		soc_component_dev_cs43130.dapm_routes =
+			all_hp_routes;
+		soc_component_dev_cs43130.num_dapm_routes =
+			ARRAY_SIZE(all_hp_routes);
+		break;
+	case CS43198_CHIP_ID:
+	case CS4399_CHIP_ID:
+		soc_component_dev_cs43130.dapm_widgets =
+			digital_hp_widgets;
+		soc_component_dev_cs43130.num_dapm_widgets =
+			ARRAY_SIZE(digital_hp_widgets);
+		soc_component_dev_cs43130.dapm_routes =
+			digital_hp_routes;
+		soc_component_dev_cs43130.num_dapm_routes =
+			ARRAY_SIZE(digital_hp_routes);
+		break;
+	}
+
+	ret = devm_snd_soc_register_component(&client->dev,
+				     &soc_component_dev_cs43130,
+				     cs43130_dai, ARRAY_SIZE(cs43130_dai));
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"snd_soc_register_component failed with ret = %d\n", ret);
+		goto err;
+	}
+
+	regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG,
+			   CS43130_ASP_3ST_MASK, 0);
+	regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG,
+			   CS43130_XSP_3ST_MASK, 0);
+
+	return 0;
+err:
+	return ret;
+}
+
+static int cs43130_i2c_remove(struct i2c_client *client)
+{
+	struct cs43130_private *cs43130 = i2c_get_clientdata(client);
+
+	if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED)
+		regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+				   CS43130_XTAL_ERR_INT,
+				   1 << CS43130_XTAL_ERR_INT_SHIFT);
+
+	regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+			   CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT,
+			   CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT);
+
+	if (cs43130->dc_meas) {
+		cancel_work_sync(&cs43130->work);
+		flush_workqueue(cs43130->wq);
+
+		device_remove_file(&client->dev, &dev_attr_hpload_dc_l);
+		device_remove_file(&client->dev, &dev_attr_hpload_dc_r);
+		device_remove_file(&client->dev, &dev_attr_hpload_ac_l);
+		device_remove_file(&client->dev, &dev_attr_hpload_ac_r);
+	}
+
+	gpiod_set_value_cansleep(cs43130->reset_gpio, 0);
+
+	pm_runtime_disable(&client->dev);
+	regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies);
+
+	return 0;
+}
+
+static int __maybe_unused cs43130_runtime_suspend(struct device *dev)
+{
+	struct cs43130_private *cs43130 = dev_get_drvdata(dev);
+
+	if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED)
+		regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+				   CS43130_XTAL_ERR_INT,
+				   1 << CS43130_XTAL_ERR_INT_SHIFT);
+
+	regcache_cache_only(cs43130->regmap, true);
+	regcache_mark_dirty(cs43130->regmap);
+
+	gpiod_set_value_cansleep(cs43130->reset_gpio, 0);
+
+	regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies);
+
+	return 0;
+}
+
+static int __maybe_unused cs43130_runtime_resume(struct device *dev)
+{
+	struct cs43130_private *cs43130 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_bulk_enable(CS43130_NUM_SUPPLIES, cs43130->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	regcache_cache_only(cs43130->regmap, false);
+
+	gpiod_set_value_cansleep(cs43130->reset_gpio, 1);
+
+	usleep_range(2000, 2050);
+
+	ret = regcache_sync(cs43130->regmap);
+	if (ret != 0) {
+		dev_err(dev, "Failed to restore register cache\n");
+		goto err;
+	}
+
+	if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED)
+		regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1,
+				   CS43130_XTAL_ERR_INT, 0);
+
+	return 0;
+err:
+	regcache_cache_only(cs43130->regmap, true);
+	regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies);
+
+	return ret;
+}
+
+static const struct dev_pm_ops cs43130_runtime_pm = {
+	SET_RUNTIME_PM_OPS(cs43130_runtime_suspend, cs43130_runtime_resume,
+			   NULL)
+};
+
+static const struct of_device_id cs43130_of_match[] = {
+	{.compatible = "cirrus,cs43130",},
+	{.compatible = "cirrus,cs4399",},
+	{.compatible = "cirrus,cs43131",},
+	{.compatible = "cirrus,cs43198",},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, cs43130_of_match);
+
+static const struct i2c_device_id cs43130_i2c_id[] = {
+	{"cs43130", 0},
+	{"cs4399", 0},
+	{"cs43131", 0},
+	{"cs43198", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs43130_i2c_id);
+
+static struct i2c_driver cs43130_i2c_driver = {
+	.driver = {
+		.name		= "cs43130",
+		.of_match_table	= cs43130_of_match,
+		.pm             = &cs43130_runtime_pm,
+	},
+	.id_table	= cs43130_i2c_id,
+	.probe		= cs43130_i2c_probe,
+	.remove		= cs43130_i2c_remove,
+};
+
+module_i2c_driver(cs43130_i2c_driver);
+
+MODULE_AUTHOR("Li Xu <li.xu@cirrus.com>");
+MODULE_DESCRIPTION("Cirrus Logic CS43130 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h
new file mode 100644
index 0000000..c3c6eef
--- /dev/null
+++ b/sound/soc/codecs/cs43130.h
@@ -0,0 +1,546 @@
+/*
+ * ALSA SoC CS43130 codec driver
+ *
+ * Copyright 2017 Cirrus Logic, Inc.
+ *
+ * Author: Li Xu <li.xu@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#ifndef __CS43130_H__
+#define __CS43130_H__
+
+/* CS43130 registers addresses */
+/* all reg address is shifted by a byte for control byte to be LSB */
+#define CS43130_FIRSTREG	0x010000
+#define CS43130_LASTREG		0x190000
+#define CS43130_CHIP_ID		0x00043130
+#define CS4399_CHIP_ID		0x00043990
+#define CS43131_CHIP_ID		0x00043131
+#define CS43198_CHIP_ID		0x00043198
+#define CS43130_DEVID_AB	0x010000	/* Device ID A & B [RO] */
+#define CS43130_DEVID_CD	0x010001	/* Device ID C & D [RO] */
+#define CS43130_DEVID_E		0x010002	/* Device ID E [RO] */
+#define CS43130_FAB_ID		0x010003        /* Fab ID [RO] */
+#define CS43130_REV_ID		0x010004        /* Revision ID [RO] */
+#define CS43130_SUBREV_ID	0x010005        /* Subrevision ID */
+#define CS43130_SYS_CLK_CTL_1	0x010006	/* System Clocking Ctl 1 */
+#define CS43130_SP_SRATE	0x01000B        /* Serial Port Sample Rate */
+#define CS43130_SP_BITSIZE	0x01000C        /* Serial Port Bit Size */
+#define CS43130_PAD_INT_CFG	0x01000D	/* Pad Interface Config */
+#define CS43130_DXD1            0x010010        /* DXD1 */
+#define CS43130_DXD7            0x010025        /* DXD7 */
+#define CS43130_DXD19           0x010026        /* DXD19 */
+#define CS43130_DXD17           0x010027        /* DXD17 */
+#define CS43130_DXD18           0x010028        /* DXD18 */
+#define CS43130_DXD12           0x01002C        /* DXD12 */
+#define CS43130_DXD8            0x01002E        /* DXD8 */
+#define CS43130_PWDN_CTL	0x020000        /* Power Down Ctl */
+#define CS43130_DXD2            0x020019        /* DXD2 */
+#define CS43130_CRYSTAL_SET	0x020052	/* Crystal Setting */
+#define CS43130_PLL_SET_1	0x030001        /* PLL Setting 1 */
+#define CS43130_PLL_SET_2	0x030002        /* PLL Setting 2 */
+#define CS43130_PLL_SET_3	0x030003        /* PLL Setting 3 */
+#define CS43130_PLL_SET_4	0x030004        /* PLL Setting 4 */
+#define CS43130_PLL_SET_5	0x030005        /* PLL Setting 5 */
+#define CS43130_PLL_SET_6	0x030008        /* PLL Setting 6 */
+#define CS43130_PLL_SET_7	0x03000A        /* PLL Setting 7 */
+#define CS43130_PLL_SET_8	0x03001B        /* PLL Setting 8 */
+#define CS43130_PLL_SET_9	0x040002        /* PLL Setting 9 */
+#define CS43130_PLL_SET_10	0x040003        /* PLL Setting 10 */
+#define CS43130_CLKOUT_CTL	0x040004        /* CLKOUT Ctl */
+#define CS43130_ASP_NUM_1	0x040010        /* ASP Numerator 1 */
+#define CS43130_ASP_NUM_2	0x040011        /* ASP Numerator 2 */
+#define CS43130_ASP_DEN_1	0x040012	/* ASP Denominator 1 */
+#define CS43130_ASP_DEN_2	0x040013	/* ASP Denominator 2 */
+#define CS43130_ASP_LRCK_HI_TIME_1 0x040014	/* ASP LRCK High Time 1 */
+#define CS43130_ASP_LRCK_HI_TIME_2 0x040015	/* ASP LRCK High Time 2 */
+#define CS43130_ASP_LRCK_PERIOD_1  0x040016	/* ASP LRCK Period 1 */
+#define CS43130_ASP_LRCK_PERIOD_2  0x040017	/* ASP LRCK Period 2 */
+#define CS43130_ASP_CLOCK_CONF	0x040018	/* ASP Clock Config */
+#define CS43130_ASP_FRAME_CONF	0x040019	/* ASP Frame Config */
+#define CS43130_XSP_NUM_1	0x040020        /* XSP Numerator 1 */
+#define CS43130_XSP_NUM_2	0x040021        /* XSP Numerator 2 */
+#define CS43130_XSP_DEN_1	0x040022	/* XSP Denominator 1 */
+#define CS43130_XSP_DEN_2	0x040023	/* XSP Denominator 2 */
+#define CS43130_XSP_LRCK_HI_TIME_1 0x040024	/* XSP LRCK High Time 1 */
+#define CS43130_XSP_LRCK_HI_TIME_2 0x040025	/* XSP LRCK High Time 2 */
+#define CS43130_XSP_LRCK_PERIOD_1  0x040026	/* XSP LRCK Period 1 */
+#define CS43130_XSP_LRCK_PERIOD_2  0x040027	/* XSP LRCK Period 2 */
+#define CS43130_XSP_CLOCK_CONF	0x040028	/* XSP Clock Config */
+#define CS43130_XSP_FRAME_CONF	0x040029	/* XSP Frame Config */
+#define CS43130_ASP_CH_1_LOC	0x050000	/* ASP Chan 1 Location */
+#define CS43130_ASP_CH_2_LOC	0x050001	/* ASP Chan 2 Location */
+#define CS43130_ASP_CH_1_SZ_EN	0x05000A	/* ASP Chan 1 Size, Enable */
+#define CS43130_ASP_CH_2_SZ_EN	0x05000B	/* ASP Chan 2 Size, Enable */
+#define CS43130_XSP_CH_1_LOC	0x060000	/* XSP Chan 1 Location */
+#define CS43130_XSP_CH_2_LOC	0x060001	/* XSP Chan 2 Location */
+#define CS43130_XSP_CH_1_SZ_EN	0x06000A	/* XSP Chan 1 Size, Enable */
+#define CS43130_XSP_CH_2_SZ_EN	0x06000B	/* XSP Chan 2 Size, Enable */
+#define CS43130_DSD_VOL_B	0x070000        /* DSD Volume B */
+#define CS43130_DSD_VOL_A	0x070001        /* DSD Volume A */
+#define CS43130_DSD_PATH_CTL_1	0x070002	/* DSD Proc Path Sig Ctl 1 */
+#define CS43130_DSD_INT_CFG	0x070003	/* DSD Interface Config */
+#define CS43130_DSD_PATH_CTL_2	0x070004	/* DSD Proc Path Sig Ctl 2 */
+#define CS43130_DSD_PCM_MIX_CTL	0x070005	/* DSD and PCM Mixing Ctl */
+#define CS43130_DSD_PATH_CTL_3	0x070006	/* DSD Proc Path Sig Ctl 3 */
+#define CS43130_HP_OUT_CTL_1	0x080000	/* HP Output Ctl 1 */
+#define CS43130_DXD16		0x080024	/* DXD16 */
+#define CS43130_DXD13		0x080032	/* DXD13 */
+#define CS43130_PCM_FILT_OPT	0x090000	/* PCM Filter Option */
+#define CS43130_PCM_VOL_B	0x090001        /* PCM Volume B */
+#define CS43130_PCM_VOL_A	0x090002        /* PCM Volume A */
+#define CS43130_PCM_PATH_CTL_1	0x090003	/* PCM Path Signal Ctl 1 */
+#define CS43130_PCM_PATH_CTL_2	0x090004	/* PCM Path Signal Ctl 2 */
+#define CS43130_DXD6		0x090097	/* DXD6 */
+#define CS43130_CLASS_H_CTL	0x0B0000	/* Class H Ctl */
+#define CS43130_DXD15		0x0B0005	/* DXD15 */
+#define CS43130_DXD14		0x0B0006	/* DXD14 */
+#define CS43130_DXD3		0x0C0002	/* DXD3 */
+#define CS43130_DXD10		0x0C0003	/* DXD10 */
+#define CS43130_DXD11		0x0C0005	/* DXD11 */
+#define CS43130_DXD9		0x0C0006	/* DXD9 */
+#define CS43130_DXD4		0x0C0009	/* DXD4 */
+#define CS43130_DXD5		0x0C000E	/* DXD5 */
+#define CS43130_HP_DETECT	0x0D0000        /* HP Detect */
+#define CS43130_HP_STATUS	0x0D0001        /* HP Status [RO] */
+#define CS43130_HP_LOAD_1	0x0E0000        /* HP Load 1 */
+#define CS43130_HP_MEAS_LOAD_1	0x0E0003	/* HP Load Measurement 1 */
+#define CS43130_HP_MEAS_LOAD_2	0x0E0004	/* HP Load Measurement 2 */
+#define CS43130_HP_DC_STAT_1	0x0E000D	/* HP DC Load Status 0 [RO] */
+#define CS43130_HP_DC_STAT_2	0x0E000E	/* HP DC Load Status 1 [RO] */
+#define CS43130_HP_AC_STAT_1	0x0E0010	/* HP AC Load Status 0 [RO] */
+#define CS43130_HP_AC_STAT_2	0x0E0011	/* HP AC Load Status 1 [RO] */
+#define CS43130_HP_LOAD_STAT	0x0E001A	/* HP Load Status [RO] */
+#define CS43130_INT_STATUS_1	0x0F0000	/* Interrupt Status 1 */
+#define CS43130_INT_STATUS_2	0x0F0001	/* Interrupt Status 2 */
+#define CS43130_INT_STATUS_3	0x0F0002	/* Interrupt Status 3 */
+#define CS43130_INT_STATUS_4	0x0F0003	/* Interrupt Status 4 */
+#define CS43130_INT_STATUS_5	0x0F0004	/* Interrupt Status 5 */
+#define CS43130_INT_MASK_1	0x0F0010        /* Interrupt Mask 1 */
+#define CS43130_INT_MASK_2	0x0F0011	/* Interrupt Mask 2 */
+#define CS43130_INT_MASK_3	0x0F0012        /* Interrupt Mask 3 */
+#define CS43130_INT_MASK_4	0x0F0013        /* Interrupt Mask 4 */
+#define CS43130_INT_MASK_5	0x0F0014        /* Interrupt Mask 5 */
+
+#define CS43130_MCLK_SRC_SEL_MASK	0x03
+#define CS43130_MCLK_SRC_SEL_SHIFT	0
+#define CS43130_MCLK_INT_MASK		0x04
+#define CS43130_MCLK_INT_SHIFT		2
+#define CS43130_CH_BITSIZE_MASK		0x03
+#define CS43130_CH_EN_MASK		0x04
+#define CS43130_CH_EN_SHIFT		2
+#define CS43130_ASP_BITSIZE_MASK	0x03
+#define CS43130_XSP_BITSIZE_MASK	0x0C
+#define CS43130_XSP_BITSIZE_SHIFT	2
+#define CS43130_SP_BITSIZE_ASP_SHIFT	0
+#define CS43130_HP_DETECT_CTRL_SHIFT	6
+#define CS43130_HP_DETECT_CTRL_MASK     (0x03 << CS43130_HP_DETECT_CTRL_SHIFT)
+#define CS43130_HP_DETECT_INV_SHIFT	5
+#define CS43130_HP_DETECT_INV_MASK      (1 << CS43130_HP_DETECT_INV_SHIFT)
+
+/* CS43130_INT_MASK_1 */
+#define CS43130_HP_PLUG_INT_SHIFT       6
+#define CS43130_HP_PLUG_INT             (1 << CS43130_HP_PLUG_INT_SHIFT)
+#define CS43130_HP_UNPLUG_INT_SHIFT     5
+#define CS43130_HP_UNPLUG_INT           (1 << CS43130_HP_UNPLUG_INT_SHIFT)
+#define CS43130_XTAL_RDY_INT_SHIFT      4
+#define CS43130_XTAL_RDY_INT_MASK	0x10
+#define CS43130_XTAL_RDY_INT            (1 << CS43130_XTAL_RDY_INT_SHIFT)
+#define CS43130_XTAL_ERR_INT_SHIFT      3
+#define CS43130_XTAL_ERR_INT            (1 << CS43130_XTAL_ERR_INT_SHIFT)
+#define CS43130_PLL_RDY_INT_MASK	0x04
+#define CS43130_PLL_RDY_INT_SHIFT	2
+#define CS43130_PLL_RDY_INT		(1 << CS43130_PLL_RDY_INT_SHIFT)
+
+/* CS43130_INT_MASK_4 */
+#define CS43130_INT_MASK_ALL		0xFF
+#define CS43130_HPLOAD_NO_DC_INT_SHIFT	7
+#define CS43130_HPLOAD_NO_DC_INT	(1 << CS43130_HPLOAD_NO_DC_INT_SHIFT)
+#define CS43130_HPLOAD_UNPLUG_INT_SHIFT	6
+#define CS43130_HPLOAD_UNPLUG_INT	(1 << CS43130_HPLOAD_UNPLUG_INT_SHIFT)
+#define CS43130_HPLOAD_OOR_INT_SHIFT	4
+#define CS43130_HPLOAD_OOR_INT		(1 << CS43130_HPLOAD_OOR_INT_SHIFT)
+#define CS43130_HPLOAD_AC_INT_SHIFT	3
+#define CS43130_HPLOAD_AC_INT		(1 << CS43130_HPLOAD_AC_INT_SHIFT)
+#define CS43130_HPLOAD_DC_INT_SHIFT	2
+#define CS43130_HPLOAD_DC_INT		(1 << CS43130_HPLOAD_DC_INT_SHIFT)
+#define CS43130_HPLOAD_OFF_INT_SHIFT	1
+#define CS43130_HPLOAD_OFF_INT		(1 << CS43130_HPLOAD_OFF_INT_SHIFT)
+#define CS43130_HPLOAD_ON_INT		1
+
+/* CS43130_HP_LOAD_1 */
+#define CS43130_HPLOAD_EN_SHIFT		7
+#define CS43130_HPLOAD_EN		(1 << CS43130_HPLOAD_EN_SHIFT)
+#define CS43130_HPLOAD_CHN_SEL_SHIFT	4
+#define CS43130_HPLOAD_CHN_SEL		(1 << CS43130_HPLOAD_CHN_SEL_SHIFT)
+#define CS43130_HPLOAD_AC_START_SHIFT	1
+#define CS43130_HPLOAD_AC_START		(1 << CS43130_HPLOAD_AC_START_SHIFT)
+#define CS43130_HPLOAD_DC_START		1
+
+/* Reg CS43130_SP_BITSIZE */
+#define CS43130_SP_BIT_SIZE_8	0x03
+#define CS43130_SP_BIT_SIZE_16	0x02
+#define CS43130_SP_BIT_SIZE_24	0x01
+#define CS43130_SP_BIT_SIZE_32	0x00
+
+/* Reg CS43130_SP_CH_SZ_EN */
+#define CS43130_CH_BIT_SIZE_8	0x00
+#define CS43130_CH_BIT_SIZE_16	0x01
+#define CS43130_CH_BIT_SIZE_24	0x02
+#define CS43130_CH_BIT_SIZE_32	0x03
+
+/* PLL */
+#define CS43130_PLL_START_MASK	0x01
+#define CS43130_PLL_MODE_MASK	0x02
+#define CS43130_PLL_MODE_SHIFT	1
+
+#define CS43130_PLL_REF_PREDIV_MASK	0x3
+
+#define CS43130_SP_STP_MASK	0x10
+#define CS43130_SP_STP_SHIFT	4
+#define CS43130_SP_5050_MASK	0x08
+#define CS43130_SP_5050_SHIFT	3
+#define CS43130_SP_FSD_MASK	0x07
+
+#define CS43130_SP_MODE_MASK	0x10
+#define CS43130_SP_MODE_SHIFT	4
+#define CS43130_SP_SCPOL_OUT_MASK	0x08
+#define CS43130_SP_SCPOL_OUT_SHIFT	3
+#define CS43130_SP_SCPOL_IN_MASK	0x04
+#define CS43130_SP_SCPOL_IN_SHIFT	2
+#define CS43130_SP_LCPOL_OUT_MASK	0x02
+#define CS43130_SP_LCPOL_OUT_SHIFT	1
+#define CS43130_SP_LCPOL_IN_MASK	0x01
+#define CS43130_SP_LCPOL_IN_SHIFT	0
+
+/* Reg CS43130_PWDN_CTL */
+#define CS43130_PDN_XSP_MASK	0x80
+#define CS43130_PDN_XSP_SHIFT	7
+#define CS43130_PDN_ASP_MASK	0x40
+#define CS43130_PDN_ASP_SHIFT	6
+#define CS43130_PDN_DSPIF_MASK	0x20
+#define CS43130_PDN_DSDIF_SHIFT	5
+#define CS43130_PDN_HP_MASK	0x10
+#define CS43130_PDN_HP_SHIFT	4
+#define CS43130_PDN_XTAL_MASK	0x08
+#define CS43130_PDN_XTAL_SHIFT	3
+#define CS43130_PDN_PLL_MASK	0x04
+#define CS43130_PDN_PLL_SHIFT	2
+#define CS43130_PDN_CLKOUT_MASK	0x02
+#define CS43130_PDN_CLKOUT_SHIFT	1
+
+/* Reg CS43130_HP_OUT_CTL_1 */
+#define CS43130_HP_IN_EN_SHIFT		3
+#define CS43130_HP_IN_EN_MASK		0x08
+
+/* Reg CS43130_PAD_INT_CFG */
+#define CS43130_ASP_3ST_MASK		0x01
+#define CS43130_XSP_3ST_MASK		0x02
+
+/* Reg CS43130_PLL_SET_2 */
+#define CS43130_PLL_DIV_DATA_MASK	0x000000FF
+#define CS43130_PLL_DIV_FRAC_0_DATA_SHIFT	0
+
+/* Reg CS43130_PLL_SET_3 */
+#define CS43130_PLL_DIV_FRAC_1_DATA_SHIFT	8
+
+/* Reg CS43130_PLL_SET_4 */
+#define CS43130_PLL_DIV_FRAC_2_DATA_SHIFT	16
+
+/* Reg CS43130_SP_DEN_1 */
+#define CS43130_SP_M_LSB_DATA_MASK	0x00FF
+#define CS43130_SP_M_LSB_DATA_SHIFT	0
+
+/* Reg CS43130_SP_DEN_2 */
+#define CS43130_SP_M_MSB_DATA_MASK	0xFF00
+#define CS43130_SP_M_MSB_DATA_SHIFT	8
+
+/* Reg CS43130_SP_NUM_1 */
+#define CS43130_SP_N_LSB_DATA_MASK	0x00FF
+#define CS43130_SP_N_LSB_DATA_SHIFT	0
+
+/* Reg CS43130_SP_NUM_2 */
+#define CS43130_SP_N_MSB_DATA_MASK	0xFF00
+#define CS43130_SP_N_MSB_DATA_SHIFT	8
+
+/* Reg CS43130_SP_LRCK_HI_TIME_1 */
+#define	CS43130_SP_LCHI_DATA_MASK	0x00FF
+#define CS43130_SP_LCHI_LSB_DATA_SHIFT	0
+
+/* Reg CS43130_SP_LRCK_HI_TIME_2 */
+#define CS43130_SP_LCHI_MSB_DATA_SHIFT	8
+
+/* Reg CS43130_SP_LRCK_PERIOD_1 */
+#define CS43130_SP_LCPR_DATA_MASK	0x00FF
+#define CS43130_SP_LCPR_LSB_DATA_SHIFT	0
+
+/* Reg CS43130_SP_LRCK_PERIOD_2 */
+#define CS43130_SP_LCPR_MSB_DATA_SHIFT	8
+
+#define CS43130_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8  | \
+			SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | \
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+#define CS43130_DOP_FORMATS (SNDRV_PCM_FMTBIT_DSD_U16_LE | \
+			     SNDRV_PCM_FMTBIT_DSD_U16_BE | \
+			     SNDRV_PCM_FMTBIT_S24_LE)
+
+/* Reg CS43130_CRYSTAL_SET */
+#define CS43130_XTAL_IBIAS_MASK		0x07
+
+/* Reg CS43130_PATH_CTL_1 */
+#define CS43130_MUTE_MASK		0x03
+#define CS43130_MUTE_EN			0x03
+
+/* Reg CS43130_DSD_INT_CFG */
+#define CS43130_DSD_MASTER		0x04
+
+/* Reg CS43130_DSD_PATH_CTL_2 */
+#define CS43130_DSD_SRC_MASK		0x60
+#define CS43130_DSD_SRC_SHIFT		5
+#define CS43130_DSD_EN_SHIFT		4
+#define CS43130_DSD_SPEED_MASK		0x04
+#define CS43130_DSD_SPEED_SHIFT		2
+
+/* Reg CS43130_DSD_PCM_MIX_CTL	*/
+#define CS43130_MIX_PCM_PREP_SHIFT	1
+#define CS43130_MIX_PCM_PREP_MASK	0x02
+
+#define CS43130_MIX_PCM_DSD_SHIFT	0
+#define CS43130_MIX_PCM_DSD_MASK	0x01
+
+/* Reg CS43130_HP_MEAS_LOAD */
+#define CS43130_HP_MEAS_LOAD_MASK	0x000000FF
+#define CS43130_HP_MEAS_LOAD_1_SHIFT	0
+#define CS43130_HP_MEAS_LOAD_2_SHIFT	8
+
+#define CS43130_MCLK_22M		22579200
+#define CS43130_MCLK_24M		24576000
+
+#define CS43130_LINEOUT_LOAD		5000
+#define CS43130_JACK_LINEOUT		(SND_JACK_MECHANICAL | SND_JACK_LINEOUT)
+#define CS43130_JACK_HEADPHONE		(SND_JACK_MECHANICAL | \
+					 SND_JACK_HEADPHONE)
+#define CS43130_JACK_MASK		(SND_JACK_MECHANICAL | \
+					 SND_JACK_LINEOUT | \
+					 SND_JACK_HEADPHONE)
+
+enum cs43130_dsd_src {
+	CS43130_DSD_SRC_DSD = 0,
+	CS43130_DSD_SRC_ASP = 2,
+	CS43130_DSD_SRC_XSP = 3,
+};
+
+enum cs43130_asp_rate {
+	CS43130_ASP_SPRATE_32K = 0,
+	CS43130_ASP_SPRATE_44_1K,
+	CS43130_ASP_SPRATE_48K,
+	CS43130_ASP_SPRATE_88_2K,
+	CS43130_ASP_SPRATE_96K,
+	CS43130_ASP_SPRATE_176_4K,
+	CS43130_ASP_SPRATE_192K,
+	CS43130_ASP_SPRATE_352_8K,
+	CS43130_ASP_SPRATE_384K,
+};
+
+enum cs43130_mclk_src_sel {
+	CS43130_MCLK_SRC_EXT = 0,
+	CS43130_MCLK_SRC_PLL,
+	CS43130_MCLK_SRC_RCO
+};
+
+enum cs43130_mclk_int_freq {
+	CS43130_MCLK_24P5 = 0,
+	CS43130_MCLK_22P5,
+};
+
+enum cs43130_xtal_ibias {
+	CS43130_XTAL_UNUSED = -1,
+	CS43130_XTAL_IBIAS_15UA = 2,
+	CS43130_XTAL_IBIAS_12_5UA = 4,
+	CS43130_XTAL_IBIAS_7_5UA = 6,
+};
+
+enum cs43130_dai_id {
+	CS43130_ASP_PCM_DAI = 0,
+	CS43130_ASP_DOP_DAI,
+	CS43130_XSP_DOP_DAI,
+	CS43130_XSP_DSD_DAI,
+	CS43130_DAI_ID_MAX,
+};
+
+struct cs43130_clk_gen {
+	unsigned int	mclk_int;
+	int		fs;
+	u16		den;
+	u16		num;
+};
+
+/* frm_size = 16 */
+static const struct cs43130_clk_gen cs43130_16_clk_gen[] = {
+	{22579200,	32000,		441,		10,},
+	{22579200,	44100,		32,		1,},
+	{22579200,	48000,		147,		5,},
+	{22579200,	88200,		16,		1,},
+	{22579200,	96000,		147,		10,},
+	{22579200,	176400,		8,		1,},
+	{22579200,	192000,		147,		20,},
+	{22579200,	352800,		4,		1,},
+	{22579200,	384000,		147,		40,},
+	{24576000,	32000,		48,		1,},
+	{24576000,	44100,		5120,		147,},
+	{24576000,	48000,		32,		1,},
+	{24576000,	88200,		2560,		147,},
+	{24576000,	96000,		16,		1,},
+	{24576000,	176400,		1280,		147,},
+	{24576000,	192000,		8,		1,},
+	{24576000,	352800,		640,		147,},
+	{24576000,	384000,		4,		1,},
+};
+
+/* frm_size = 32 */
+static const struct cs43130_clk_gen cs43130_32_clk_gen[] = {
+	{22579200,	32000,		441,		20,},
+	{22579200,	44100,		16,		1,},
+	{22579200,	48000,		147,		10,},
+	{22579200,	88200,		8,		1,},
+	{22579200,	96000,		147,		20,},
+	{22579200,	176400,		4,		1,},
+	{22579200,	192000,		147,		40,},
+	{22579200,	352800,		2,		1,},
+	{22579200,	384000,		147,		80,},
+	{24576000,	32000,		24,		1,},
+	{24576000,	44100,		2560,		147,},
+	{24576000,	48000,		16,		1,},
+	{24576000,	88200,		1280,		147,},
+	{24576000,	96000,		8,		1,},
+	{24576000,	176400,		640,		147,},
+	{24576000,	192000,		4,		1,},
+	{24576000,	352800,		320,		147,},
+	{24576000,	384000,		2,		1,},
+};
+
+/* frm_size = 48 */
+static const struct cs43130_clk_gen cs43130_48_clk_gen[] = {
+	{22579200,	32000,		147,		100,},
+	{22579200,	44100,		32,		3,},
+	{22579200,	48000,		49,		5,},
+	{22579200,	88200,		16,		3,},
+	{22579200,	96000,		49,		10,},
+	{22579200,	176400,		8,		3,},
+	{22579200,	192000,		49,		20,},
+	{22579200,	352800,		4,		3,},
+	{22579200,	384000,		49,		40,},
+	{24576000,	32000,		16,		1,},
+	{24576000,	44100,		5120,		441,},
+	{24576000,	48000,		32,		3,},
+	{24576000,	88200,		2560,		441,},
+	{24576000,	96000,		16,		3,},
+	{24576000,	176400,		1280,		441,},
+	{24576000,	192000,		8,		3,},
+	{24576000,	352800,		640,		441,},
+	{24576000,	384000,		4,		3,},
+};
+
+/* frm_size = 64 */
+static const struct cs43130_clk_gen cs43130_64_clk_gen[] = {
+	{22579200,	32000,		441,		40,},
+	{22579200,	44100,		8,		1,},
+	{22579200,	48000,		147,		20,},
+	{22579200,	88200,		4,		1,},
+	{22579200,	96000,		147,		40,},
+	{22579200,	176400,		2,		1,},
+	{22579200,	192000,		147,		80,},
+	{22579200,	352800,		1,		1,},
+	{24576000,	32000,		12,		1,},
+	{24576000,	44100,		1280,		147,},
+	{24576000,	48000,		8,		1,},
+	{24576000,	88200,		640,		147,},
+	{24576000,	96000,		4,		1,},
+	{24576000,	176400,		320,		147,},
+	{24576000,	192000,		2,		1,},
+	{24576000,	352800,		160,		147,},
+	{24576000,	384000,		1,		1,},
+};
+
+struct cs43130_bitwidth_map {
+	unsigned int bitwidth;
+	u8 sp_bit;
+	u8 ch_bit;
+};
+
+struct cs43130_rate_map {
+	int fs;
+	int val;
+};
+
+#define HP_LEFT			0
+#define HP_RIGHT		1
+#define CS43130_AC_FREQ		10
+#define CS43130_DC_THRESHOLD	2
+
+#define CS43130_NUM_SUPPLIES	5
+static const char *const cs43130_supply_names[CS43130_NUM_SUPPLIES] = {
+	"VA",
+	"VP",
+	"VCP",
+	"VD",
+	"VL",
+};
+
+#define CS43130_NUM_INT		5       /* number of interrupt status reg */
+
+struct cs43130_dai {
+	unsigned int			sclk;
+	unsigned int			dai_format;
+	unsigned int			dai_mode;
+};
+
+struct	cs43130_private {
+	struct snd_soc_component	*component;
+	struct regmap			*regmap;
+	struct regulator_bulk_data	supplies[CS43130_NUM_SUPPLIES];
+	struct gpio_desc		*reset_gpio;
+	unsigned int			dev_id; /* codec device ID */
+	int				xtal_ibias;
+
+	/* shared by both DAIs */
+	struct mutex			clk_mutex;
+	int				clk_req;
+	bool				pll_bypass;
+	struct completion		xtal_rdy;
+	struct completion		pll_rdy;
+	unsigned int			mclk;
+	unsigned int			mclk_int;
+	int				mclk_int_src;
+
+	/* DAI specific */
+	struct cs43130_dai		dais[CS43130_DAI_ID_MAX];
+
+	/* HP load specific */
+	bool				dc_meas;
+	bool				ac_meas;
+	bool				hpload_done;
+	struct completion		hpload_evt;
+	unsigned int			hpload_stat;
+	u16				hpload_dc[2];
+	u16				dc_threshold[CS43130_DC_THRESHOLD];
+	u16				ac_freq[CS43130_AC_FREQ];
+	u16				hpload_ac[CS43130_AC_FREQ][2];
+	struct workqueue_struct		*wq;
+	struct work_struct		work;
+	struct snd_soc_jack		jack;
+};
+
+#endif	/* __CS43130_H__ */
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
new file mode 100644
index 0000000..bee0e34
--- /dev/null
+++ b/sound/soc/codecs/cs4349.c
@@ -0,0 +1,394 @@
+/*
+ * cs4349.c  --  CS4349 ALSA Soc Audio driver
+ *
+ * Copyright 2015 Cirrus Logic, Inc.
+ *
+ * Authors: Tim Howe <Tim.Howe@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include "cs4349.h"
+
+
+static const struct reg_default cs4349_reg_defaults[] = {
+	{ 2, 0x00 },	/* r02	- Mode Control */
+	{ 3, 0x09 },	/* r03	- Volume, Mixing and Inversion Control */
+	{ 4, 0x81 },	/* r04	- Mute Control */
+	{ 5, 0x00 },	/* r05	- Channel A Volume Control */
+	{ 6, 0x00 },	/* r06	- Channel B Volume Control */
+	{ 7, 0xB1 },	/* r07	- Ramp and Filter Control */
+	{ 8, 0x1C },	/* r08	- Misc. Control */
+};
+
+/* Private data for the CS4349 */
+struct  cs4349_private {
+	struct regmap			*regmap;
+	struct gpio_desc		*reset_gpio;
+	unsigned int			mode;
+	int				rate;
+};
+
+static bool cs4349_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS4349_CHIPID ... CS4349_MISC:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool cs4349_writeable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS4349_MODE ...  CS4349_MISC:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int cs4349_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int format)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct cs4349_private *cs4349 = snd_soc_component_get_drvdata(component);
+	unsigned int fmt;
+
+	fmt = format & SND_SOC_DAIFMT_FORMAT_MASK;
+
+	switch (fmt) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
+		cs4349->mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cs4349_pcm_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct cs4349_private *cs4349 = snd_soc_component_get_drvdata(component);
+	int fmt, ret;
+
+	cs4349->rate = params_rate(params);
+
+	switch (cs4349->mode) {
+	case SND_SOC_DAIFMT_I2S:
+		fmt = DIF_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		fmt = DIF_LEFT_JST;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (params_width(params)) {
+		case 16:
+			fmt = DIF_RGHT_JST16;
+			break;
+		case 24:
+			fmt = DIF_RGHT_JST24;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = snd_soc_component_update_bits(component, CS4349_MODE, DIF_MASK,
+				  MODE_FORMAT(fmt));
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int cs4349_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	int reg;
+
+	reg = 0;
+	if (mute)
+		reg = MUTE_AB_MASK;
+
+	return snd_soc_component_update_bits(component, CS4349_MUTE, MUTE_AB_MASK, reg);
+}
+
+static DECLARE_TLV_DB_SCALE(dig_tlv, -12750, 50, 0);
+
+static const char * const chan_mix_texts[] = {
+	"Mute", "MuteA", "MuteA SwapB", "MuteA MonoB", "SwapA MuteB",
+	"BothR", "Swap", "SwapA MonoB", "MuteB", "Normal", "BothL",
+	"MonoB", "MonoA MuteB", "MonoA", "MonoA SwapB", "Mono",
+	/*Normal == Channel A = Left, Channel B = Right*/
+};
+
+static const char * const fm_texts[] = {
+	"Auto", "Single", "Double", "Quad",
+};
+
+static const char * const deemph_texts[] = {
+	"None", "44.1k", "48k", "32k",
+};
+
+static const char * const softr_zeroc_texts[] = {
+	"Immediate", "Zero Cross", "Soft Ramp", "SR on ZC",
+};
+
+static int deemph_values[] = {
+	0, 4, 8, 12,
+};
+
+static int softr_zeroc_values[] = {
+	0, 64, 128, 192,
+};
+
+static const struct soc_enum chan_mix_enum =
+	SOC_ENUM_SINGLE(CS4349_VMI, 0,
+			ARRAY_SIZE(chan_mix_texts),
+			chan_mix_texts);
+
+static const struct soc_enum fm_mode_enum =
+	SOC_ENUM_SINGLE(CS4349_MODE, 0,
+			ARRAY_SIZE(fm_texts),
+			fm_texts);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(deemph_enum, CS4349_MODE, 0, DEM_MASK,
+				deemph_texts, deemph_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(softr_zeroc_enum, CS4349_RMPFLT, 0,
+				SR_ZC_MASK, softr_zeroc_texts,
+				softr_zeroc_values);
+
+static const struct snd_kcontrol_new cs4349_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("Master Playback Volume",
+			 CS4349_VOLA, CS4349_VOLB, 0, 0xFF, 1, dig_tlv),
+	SOC_ENUM("Functional Mode", fm_mode_enum),
+	SOC_ENUM("De-Emphasis Control", deemph_enum),
+	SOC_ENUM("Soft Ramp Zero Cross Control", softr_zeroc_enum),
+	SOC_ENUM("Channel Mixer", chan_mix_enum),
+	SOC_SINGLE("VolA = VolB Switch", CS4349_VMI, 7, 1, 0),
+	SOC_SINGLE("InvertA Switch", CS4349_VMI, 6, 1, 0),
+	SOC_SINGLE("InvertB Switch", CS4349_VMI, 5, 1, 0),
+	SOC_SINGLE("Auto-Mute Switch", CS4349_MUTE, 7, 1, 0),
+	SOC_SINGLE("MUTEC A = B Switch", CS4349_MUTE, 5, 1, 0),
+	SOC_SINGLE("Soft Ramp Up Switch", CS4349_RMPFLT, 5, 1, 0),
+	SOC_SINGLE("Soft Ramp Down Switch", CS4349_RMPFLT, 4, 1, 0),
+	SOC_SINGLE("Slow Roll Off Filter Switch", CS4349_RMPFLT, 2, 1, 0),
+	SOC_SINGLE("Freeze Switch", CS4349_MISC, 5, 1, 0),
+	SOC_SINGLE("Popguard Switch", CS4349_MISC, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget cs4349_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("HiFi DAC", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_OUTPUT("OutputA"),
+	SND_SOC_DAPM_OUTPUT("OutputB"),
+};
+
+static const struct snd_soc_dapm_route cs4349_routes[] = {
+	{"DAC Playback", NULL, "OutputA"},
+	{"DAC Playback", NULL, "OutputB"},
+
+	{"OutputA", NULL, "HiFi DAC"},
+	{"OutputB", NULL, "HiFi DAC"},
+};
+
+#define CS4349_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8  | \
+			SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
+			SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+			SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
+			SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE  | \
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+#define CS4349_PCM_RATES SNDRV_PCM_RATE_8000_192000
+
+static const struct snd_soc_dai_ops cs4349_dai_ops = {
+	.hw_params	= cs4349_pcm_hw_params,
+	.set_fmt	= cs4349_set_dai_fmt,
+	.digital_mute	= cs4349_digital_mute,
+};
+
+static struct snd_soc_dai_driver cs4349_dai = {
+	.name = "cs4349_hifi",
+	.playback = {
+		.stream_name	= "DAC Playback",
+		.channels_min	= 1,
+		.channels_max	= 2,
+		.rates		= CS4349_PCM_RATES,
+		.formats	= CS4349_PCM_FORMATS,
+	},
+	.ops = &cs4349_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static const struct snd_soc_component_driver soc_component_dev_cs4349 = {
+	.controls		= cs4349_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs4349_snd_controls),
+	.dapm_widgets		= cs4349_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs4349_dapm_widgets),
+	.dapm_routes		= cs4349_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs4349_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config cs4349_regmap = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+
+	.max_register		= CS4349_MISC,
+	.reg_defaults		= cs4349_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(cs4349_reg_defaults),
+	.readable_reg		= cs4349_readable_register,
+	.writeable_reg		= cs4349_writeable_register,
+	.cache_type		= REGCACHE_RBTREE,
+};
+
+static int cs4349_i2c_probe(struct i2c_client *client,
+				      const struct i2c_device_id *id)
+{
+	struct cs4349_private *cs4349;
+	int ret;
+
+	cs4349 = devm_kzalloc(&client->dev, sizeof(*cs4349), GFP_KERNEL);
+	if (!cs4349)
+		return -ENOMEM;
+
+	cs4349->regmap = devm_regmap_init_i2c(client, &cs4349_regmap);
+	if (IS_ERR(cs4349->regmap)) {
+		ret = PTR_ERR(cs4349->regmap);
+		dev_err(&client->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	/* Reset the Device */
+	cs4349->reset_gpio = devm_gpiod_get_optional(&client->dev,
+		"reset", GPIOD_OUT_LOW);
+	if (IS_ERR(cs4349->reset_gpio))
+		return PTR_ERR(cs4349->reset_gpio);
+
+	gpiod_set_value_cansleep(cs4349->reset_gpio, 1);
+
+	i2c_set_clientdata(client, cs4349);
+
+	return devm_snd_soc_register_component(&client->dev,
+		&soc_component_dev_cs4349,
+		&cs4349_dai, 1);
+}
+
+static int cs4349_i2c_remove(struct i2c_client *client)
+{
+	struct cs4349_private *cs4349 = i2c_get_clientdata(client);
+
+	/* Hold down reset */
+	gpiod_set_value_cansleep(cs4349->reset_gpio, 0);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int cs4349_runtime_suspend(struct device *dev)
+{
+	struct cs4349_private *cs4349 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regmap_update_bits(cs4349->regmap, CS4349_MISC, PWR_DWN, PWR_DWN);
+	if (ret < 0)
+		return ret;
+
+	regcache_cache_only(cs4349->regmap, true);
+
+	/* Hold down reset */
+	gpiod_set_value_cansleep(cs4349->reset_gpio, 0);
+
+	return 0;
+}
+
+static int cs4349_runtime_resume(struct device *dev)
+{
+	struct cs4349_private *cs4349 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regmap_update_bits(cs4349->regmap, CS4349_MISC, PWR_DWN, 0);
+	if (ret < 0)
+		return ret;
+
+	gpiod_set_value_cansleep(cs4349->reset_gpio, 1);
+
+	regcache_cache_only(cs4349->regmap, false);
+	regcache_sync(cs4349->regmap);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops cs4349_runtime_pm = {
+	SET_RUNTIME_PM_OPS(cs4349_runtime_suspend, cs4349_runtime_resume,
+			   NULL)
+};
+
+static const struct of_device_id cs4349_of_match[] = {
+	{ .compatible = "cirrus,cs4349", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, cs4349_of_match);
+
+static const struct i2c_device_id cs4349_i2c_id[] = {
+	{"cs4349", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs4349_i2c_id);
+
+static struct i2c_driver cs4349_i2c_driver = {
+	.driver = {
+		.name		= "cs4349",
+		.of_match_table	= cs4349_of_match,
+	},
+	.id_table	= cs4349_i2c_id,
+	.probe		= cs4349_i2c_probe,
+	.remove		= cs4349_i2c_remove,
+};
+
+module_i2c_driver(cs4349_i2c_driver);
+
+MODULE_AUTHOR("Tim Howe <tim.howe@cirrus.com>");
+MODULE_DESCRIPTION("Cirrus Logic CS4349 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs4349.h b/sound/soc/codecs/cs4349.h
new file mode 100644
index 0000000..d58c06a
--- /dev/null
+++ b/sound/soc/codecs/cs4349.h
@@ -0,0 +1,136 @@
+/*
+ * ALSA SoC CS4349 codec driver
+ *
+ * Copyright 2015 Cirrus Logic, Inc.
+ *
+ * Author: Tim Howe <Tim.Howe@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#ifndef __CS4349_H__
+#define __CS4349_H__
+
+/* CS4349 registers addresses */
+#define CS4349_CHIPID		0x01	/* Device and Rev ID, Read Only */
+#define CS4349_MODE		0x02	/* Mode Control */
+#define CS4349_VMI		0x03	/* Volume, Mixing, Inversion Control */
+#define CS4349_MUTE		0x04	/* Mute Control */
+#define CS4349_VOLA		0x05	/* DAC Channel A Volume Control */
+#define CS4349_VOLB		0x06	/* DAC Channel B Volume Control */
+#define CS4349_RMPFLT		0x07	/* Ramp and Filter Control */
+#define CS4349_MISC		0x08	/* Power Down,Freeze Control,Pop Stop*/
+
+#define CS4349_I2C_INCR		0x80
+
+
+/* Device and Revision ID */
+#define CS4349_REVA		0xF0	/* Rev A */
+#define CS4349_REVB		0xF1	/* Rev B */
+#define CS4349_REVC2		0xFF	/* Rev C2 */
+
+
+/* PDN_DONE Poll Maximum
+ * If soft ramp is set it will take much longer to power down
+ * the system.
+ */
+#define PDN_POLL_MAX		900
+
+
+/* Bitfield Definitions */
+
+/* CS4349_MODE */
+/* (Digital Interface Format, De-Emphasis Control, Functional Mode */
+#define DIF2			(1 << 6)
+#define DIF1			(1 << 5)
+#define DIF0			(1 << 4)
+#define DEM1			(1 << 3)
+#define DEM0			(1 << 2)
+#define FM1			(1 << 1)
+#define DIF_LEFT_JST		0x00
+#define DIF_I2S			0x01
+#define DIF_RGHT_JST16		0x02
+#define DIF_RGHT_JST24		0x03
+#define DIF_TDM0		0x04
+#define DIF_TDM1		0x05
+#define DIF_TDM2		0x06
+#define DIF_TDM3		0x07
+#define DIF_MASK		0x70
+#define MODE_FORMAT(x)		(((x)&7)<<4)
+#define DEM_MASK		0x0C
+#define NO_DEM			0x00
+#define DEM_441			0x04
+#define DEM_48K			0x08
+#define DEM_32K			0x0C
+#define FM_AUTO			0x00
+#define FM_SNGL			0x01
+#define FM_DBL			0x02
+#define FM_QUAD			0x03
+#define FM_SNGL_MIN		30000
+#define FM_SNGL_MAX		54000
+#define FM_DBL_MAX		108000
+#define FM_QUAD_MAX		216000
+#define FM_MASK			0x03
+
+/* CS4349_VMI (VMI = Volume, Mixing and Inversion Controls) */
+#define VOLBISA			(1 << 7)
+#define VOLAISB			(1 << 7)
+/* INVERT_A only available for Left Jstfd, Right Jstfd16 and Right Jstfd24 */
+#define INVERT_A		(1 << 6)
+/* INVERT_B only available for Left Jstfd, Right Jstfd16 and Right Jstfd24 */
+#define INVERT_B		(1 << 5)
+#define ATAPI3			(1 << 3)
+#define ATAPI2			(1 << 2)
+#define ATAPI1			(1 << 1)
+#define ATAPI0			(1 << 0)
+#define MUTEAB			0x00
+#define MUTEA_RIGHTB		0x01
+#define MUTEA_LEFTB		0x02
+#define MUTEA_SUMLRDIV2B	0x03
+#define RIGHTA_MUTEB		0x04
+#define RIGHTA_RIGHTB		0x05
+#define RIGHTA_LEFTB		0x06
+#define RIGHTA_SUMLRDIV2B	0x07
+#define LEFTA_MUTEB		0x08
+#define LEFTA_RIGHTB		0x09	/* Default */
+#define LEFTA_LEFTB		0x0A
+#define LEFTA_SUMLRDIV2B	0x0B
+#define SUMLRDIV2A_MUTEB	0x0C
+#define SUMLRDIV2A_RIGHTB	0x0D
+#define SUMLRDIV2A_LEFTB	0x0E
+#define SUMLRDIV2_AB		0x0F
+#define CHMIX_MASK		0x0F
+
+/* CS4349_MUTE */
+#define AUTOMUTE		(1 << 7)
+#define MUTEC_AB		(1 << 5)
+#define MUTE_A			(1 << 4)
+#define MUTE_B			(1 << 3)
+#define MUTE_AB_MASK		0x18
+
+/* CS4349_RMPFLT (Ramp and Filter Control) */
+#define SCZ1			(1 << 7)
+#define SCZ0			(1 << 6)
+#define RMP_UP			(1 << 5)
+#define RMP_DN			(1 << 4)
+#define FILT_SEL		(1 << 2)
+#define IMMDT_CHNG		0x31
+#define ZEROCRSS		0x71
+#define SOFT_RMP		0xB1
+#define SFTRMP_ZEROCRSS		0xF1
+#define SR_ZC_MASK		0xC0
+
+/* CS4349_MISC */
+#define PWR_DWN			(1 << 7)
+#define FREEZE			(1 << 5)
+#define POPG_EN			(1 << 4)
+
+#endif	/* __CS4349_H__ */
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
new file mode 100644
index 0000000..45e50fe
--- /dev/null
+++ b/sound/soc/codecs/cs47l24.c
@@ -0,0 +1,1355 @@
+/*
+ * cs47l24.h  --  ALSA SoC Audio driver for Cirrus Logic CS47L24
+ *
+ * Copyright 2015 Cirrus Logic Inc.
+ *
+ * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+#include "wm_adsp.h"
+#include "cs47l24.h"
+
+#define DRV_NAME "cs47l24-codec"
+
+struct cs47l24_priv {
+	struct arizona_priv core;
+	struct arizona_fll fll[2];
+};
+
+static const struct wm_adsp_region cs47l24_dsp2_regions[] = {
+	{ .type = WMFW_ADSP2_PM, .base = 0x200000 },
+	{ .type = WMFW_ADSP2_ZM, .base = 0x280000 },
+	{ .type = WMFW_ADSP2_XM, .base = 0x290000 },
+	{ .type = WMFW_ADSP2_YM, .base = 0x2a8000 },
+};
+
+static const struct wm_adsp_region cs47l24_dsp3_regions[] = {
+	{ .type = WMFW_ADSP2_PM, .base = 0x300000 },
+	{ .type = WMFW_ADSP2_ZM, .base = 0x380000 },
+	{ .type = WMFW_ADSP2_XM, .base = 0x390000 },
+	{ .type = WMFW_ADSP2_YM, .base = 0x3a8000 },
+};
+
+static const struct wm_adsp_region *cs47l24_dsp_regions[] = {
+	cs47l24_dsp2_regions,
+	cs47l24_dsp3_regions,
+};
+
+static int cs47l24_adsp_power_ev(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+	unsigned int v;
+	int ret;
+
+	ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to read SYSCLK state: %d\n", ret);
+		return ret;
+	}
+
+	v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
+
+	return wm_adsp2_early_event(w, kcontrol, event, v);
+}
+
+static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
+static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
+
+#define CS47L24_NG_SRC(name, base) \
+	SOC_SINGLE(name " NG HPOUT1L Switch",  base,  0, 1, 0), \
+	SOC_SINGLE(name " NG HPOUT1R Switch",  base,  1, 1, 0), \
+	SOC_SINGLE(name " NG SPKOUT Switch",  base,  6, 1, 0)
+
+static const struct snd_kcontrol_new cs47l24_snd_controls[] = {
+SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]),
+SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
+
+SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum),
+
+SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL,
+	   ARIZONA_IN1L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL,
+	   ARIZONA_IN1R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2L HPF Switch", ARIZONA_IN2L_CONTROL,
+	   ARIZONA_IN2L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2R HPF Switch", ARIZONA_IN2R_CONTROL,
+	   ARIZONA_IN2R_HPF_SHIFT, 1, 0),
+
+SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
+	       ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
+	       ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
+	       ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R,
+	       ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+
+SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
+SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
+
+ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
+
+ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2),
+SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2),
+SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC2L", ARIZONA_DRC2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC2R", ARIZONA_DRC2RMIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
+		   ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
+SND_SOC_BYTES_MASK("DRC2", ARIZONA_DRC2_CTRL1, 5,
+		   ARIZONA_DRC2R_ENA | ARIZONA_DRC2L_ENA),
+
+ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
+
+ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2),
+ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
+ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
+ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2),
+
+SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
+SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
+SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
+SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
+
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]),
+SOC_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]),
+SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
+SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
+SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
+
+WM_ADSP2_PRELOAD_SWITCH("DSP2", 2),
+WM_ADSP2_PRELOAD_SWITCH("DSP3", 3),
+
+ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP3R", ARIZONA_DSP3RMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR,
+	       ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv),
+
+ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUT", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE("HPOUT1 SC Protect Switch", ARIZONA_HP1_SHORT_CIRCUIT_CTRL,
+	   ARIZONA_HP1_SC_ENA_SHIFT, 1, 0),
+
+SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_SINGLE("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	   ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	       ARIZONA_OUT4L_VOL_SHIFT, 0xbf, 0, digital_tlv),
+
+SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
+SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
+
+SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
+	   ARIZONA_NGATE_ENA_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
+	       ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
+SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
+
+CS47L24_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L),
+CS47L24_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R),
+CS47L24_NG_SRC("SPKOUT", ARIZONA_NOISE_GATE_SELECT_4L),
+
+ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+
+WM_ADSP_FW_CONTROL("DSP2", 1),
+WM_ADSP_FW_CONTROL("DSP3", 2),
+};
+
+ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC2L, ARIZONA_DRC2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC2R, ARIZONA_DRC2RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP2L, ARIZONA_DSP2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP2R, ARIZONA_DSP2RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP2, ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP3L, ARIZONA_DSP3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP3R, ARIZONA_DSP3RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP3, ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUT, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT3, ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT4, ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC3, ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC4, ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT3, ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT4, ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC3, ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC4, ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC3INT1, ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT2, ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT3, ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT4, ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC3DEC1, ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC2, ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC3, ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC4, ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE);
+
+static const char * const cs47l24_aec_loopback_texts[] = {
+	"HPOUT1L", "HPOUT1R", "SPKOUT",
+};
+
+static const unsigned int cs47l24_aec_loopback_values[] = {
+	0, 1, 6,
+};
+
+static const struct soc_enum cs47l24_aec_loopback =
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
+			      ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+			      ARRAY_SIZE(cs47l24_aec_loopback_texts),
+			      cs47l24_aec_loopback_texts,
+			      cs47l24_aec_loopback_values);
+
+static const struct snd_kcontrol_new cs47l24_aec_loopback_mux =
+	SOC_DAPM_ENUM("AEC Loopback", cs47l24_aec_loopback);
+
+static const struct snd_soc_dapm_widget cs47l24_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1,
+		    ARIZONA_SYSCLK_ENA_SHIFT, 0, arizona_clk_ev,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
+		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+		    ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDD", 0, 0),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_SIGGEN("NOISE"),
+SND_SOC_DAPM_SIGGEN("HAPTICS"),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"),
+
+SND_SOC_DAPM_OUTPUT("DSP Voice Trigger"),
+
+SND_SOC_DAPM_SWITCH("DSP3 Voice Trigger", SND_SOC_NOPM, 2, 0,
+		    &arizona_voice_trigger_switch[2]),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR,
+		 ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC2L", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC2R", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT,
+		 0, NULL, 0),
+SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT,
+		 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ASRC1L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("ASRC1R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1R_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+WM_ADSP2("DSP2", 1, cs47l24_adsp_power_ev),
+WM_ADSP2("DSP3", 2, cs47l24_adsp_power_ev),
+
+SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT3", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT4", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC3", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC4", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT3", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT4", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC3", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC4", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3INT1", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT2", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT3", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT4", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3DEC1", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC2", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+		 ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &cs47l24_aec_loopback_mux),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0,
+		     ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0,
+		     ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
+		    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
+		    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+		   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+		   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"),
+ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"),
+
+ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"),
+ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"),
+ARIZONA_MIXER_WIDGETS(DRC2L, "DRC2L"),
+ARIZONA_MIXER_WIDGETS(DRC2R, "DRC2R"),
+
+ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
+ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
+ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"),
+ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"),
+ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"),
+
+ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),
+ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),
+ARIZONA_MIXER_WIDGETS(SPKOUT, "SPKOUT"),
+
+ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
+ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
+
+ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
+ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"),
+ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"),
+ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"),
+ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"),
+
+ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
+ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
+
+ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"),
+ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
+ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
+ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"),
+
+ARIZONA_DSP_WIDGETS(DSP2, "DSP2"),
+ARIZONA_DSP_WIDGETS(DSP3, "DSP3"),
+
+ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
+ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
+ARIZONA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"),
+ARIZONA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC3, "ISRC2DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC4, "ISRC2DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
+ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
+ARIZONA_MUX_WIDGETS(ISRC2INT3, "ISRC2INT3"),
+ARIZONA_MUX_WIDGETS(ISRC2INT4, "ISRC2INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC3DEC1, "ISRC3DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC2, "ISRC3DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC3, "ISRC3DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC4, "ISRC3DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC3INT1, "ISRC3INT1"),
+ARIZONA_MUX_WIDGETS(ISRC3INT2, "ISRC3INT2"),
+ARIZONA_MUX_WIDGETS(ISRC3INT3, "ISRC3INT3"),
+ARIZONA_MUX_WIDGETS(ISRC3INT4, "ISRC3INT4"),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+
+SND_SOC_DAPM_OUTPUT("MICSUPP"),
+};
+
+#define ARIZONA_MIXER_INPUT_ROUTES(name)	\
+	{ name, "Noise Generator", "Noise Generator" }, \
+	{ name, "Tone Generator 1", "Tone Generator 1" }, \
+	{ name, "Tone Generator 2", "Tone Generator 2" }, \
+	{ name, "Haptics", "HAPTICS" }, \
+	{ name, "AEC", "AEC Loopback" }, \
+	{ name, "IN1L", "IN1L PGA" }, \
+	{ name, "IN1R", "IN1R PGA" }, \
+	{ name, "IN2L", "IN2L PGA" }, \
+	{ name, "IN2R", "IN2R PGA" }, \
+	{ name, "AIF1RX1", "AIF1RX1" }, \
+	{ name, "AIF1RX2", "AIF1RX2" }, \
+	{ name, "AIF1RX3", "AIF1RX3" }, \
+	{ name, "AIF1RX4", "AIF1RX4" }, \
+	{ name, "AIF1RX5", "AIF1RX5" }, \
+	{ name, "AIF1RX6", "AIF1RX6" }, \
+	{ name, "AIF1RX7", "AIF1RX7" }, \
+	{ name, "AIF1RX8", "AIF1RX8" }, \
+	{ name, "AIF2RX1", "AIF2RX1" }, \
+	{ name, "AIF2RX2", "AIF2RX2" }, \
+	{ name, "AIF2RX3", "AIF2RX3" }, \
+	{ name, "AIF2RX4", "AIF2RX4" }, \
+	{ name, "AIF2RX5", "AIF2RX5" }, \
+	{ name, "AIF2RX6", "AIF2RX6" }, \
+	{ name, "AIF3RX1", "AIF3RX1" }, \
+	{ name, "AIF3RX2", "AIF3RX2" }, \
+	{ name, "EQ1", "EQ1" }, \
+	{ name, "EQ2", "EQ2" }, \
+	{ name, "DRC1L", "DRC1L" }, \
+	{ name, "DRC1R", "DRC1R" }, \
+	{ name, "DRC2L", "DRC2L" }, \
+	{ name, "DRC2R", "DRC2R" }, \
+	{ name, "LHPF1", "LHPF1" }, \
+	{ name, "LHPF2", "LHPF2" }, \
+	{ name, "LHPF3", "LHPF3" }, \
+	{ name, "LHPF4", "LHPF4" }, \
+	{ name, "ASRC1L", "ASRC1L" }, \
+	{ name, "ASRC1R", "ASRC1R" }, \
+	{ name, "ASRC2L", "ASRC2L" }, \
+	{ name, "ASRC2R", "ASRC2R" }, \
+	{ name, "ISRC1DEC1", "ISRC1DEC1" }, \
+	{ name, "ISRC1DEC2", "ISRC1DEC2" }, \
+	{ name, "ISRC1DEC3", "ISRC1DEC3" }, \
+	{ name, "ISRC1DEC4", "ISRC1DEC4" }, \
+	{ name, "ISRC1INT1", "ISRC1INT1" }, \
+	{ name, "ISRC1INT2", "ISRC1INT2" }, \
+	{ name, "ISRC1INT3", "ISRC1INT3" }, \
+	{ name, "ISRC1INT4", "ISRC1INT4" }, \
+	{ name, "ISRC2DEC1", "ISRC2DEC1" }, \
+	{ name, "ISRC2DEC2", "ISRC2DEC2" }, \
+	{ name, "ISRC2DEC3", "ISRC2DEC3" }, \
+	{ name, "ISRC2DEC4", "ISRC2DEC4" }, \
+	{ name, "ISRC2INT1", "ISRC2INT1" }, \
+	{ name, "ISRC2INT2", "ISRC2INT2" }, \
+	{ name, "ISRC2INT3", "ISRC2INT3" }, \
+	{ name, "ISRC2INT4", "ISRC2INT4" }, \
+	{ name, "ISRC3DEC1", "ISRC3DEC1" }, \
+	{ name, "ISRC3DEC2", "ISRC3DEC2" }, \
+	{ name, "ISRC3DEC3", "ISRC3DEC3" }, \
+	{ name, "ISRC3DEC4", "ISRC3DEC4" }, \
+	{ name, "ISRC3INT1", "ISRC3INT1" }, \
+	{ name, "ISRC3INT2", "ISRC3INT2" }, \
+	{ name, "ISRC3INT3", "ISRC3INT3" }, \
+	{ name, "ISRC3INT4", "ISRC3INT4" }, \
+	{ name, "DSP2.1", "DSP2" }, \
+	{ name, "DSP2.2", "DSP2" }, \
+	{ name, "DSP2.3", "DSP2" }, \
+	{ name, "DSP2.4", "DSP2" }, \
+	{ name, "DSP2.5", "DSP2" }, \
+	{ name, "DSP2.6", "DSP2" }, \
+	{ name, "DSP3.1", "DSP3" }, \
+	{ name, "DSP3.2", "DSP3" }, \
+	{ name, "DSP3.3", "DSP3" }, \
+	{ name, "DSP3.4", "DSP3" }, \
+	{ name, "DSP3.5", "DSP3" }, \
+	{ name, "DSP3.6", "DSP3" }
+
+static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = {
+	{ "OUT1L", NULL, "CPVDD" },
+	{ "OUT1R", NULL, "CPVDD" },
+
+	{ "OUT4L", NULL, "SPKVDD" },
+
+	{ "OUT1L", NULL, "SYSCLK" },
+	{ "OUT1R", NULL, "SYSCLK" },
+	{ "OUT4L", NULL, "SYSCLK" },
+
+	{ "IN1L", NULL, "SYSCLK" },
+	{ "IN1R", NULL, "SYSCLK" },
+	{ "IN2L", NULL, "SYSCLK" },
+	{ "IN2R", NULL, "SYSCLK" },
+
+	{ "ASRC1L", NULL, "SYSCLK" },
+	{ "ASRC1R", NULL, "SYSCLK" },
+	{ "ASRC2L", NULL, "SYSCLK" },
+	{ "ASRC2R", NULL, "SYSCLK" },
+
+	{ "ASRC1L", NULL, "ASYNCCLK" },
+	{ "ASRC1R", NULL, "ASYNCCLK" },
+	{ "ASRC2L", NULL, "ASYNCCLK" },
+	{ "ASRC2R", NULL, "ASYNCCLK" },
+
+	{ "MICBIAS1", NULL, "MICVDD" },
+	{ "MICBIAS2", NULL, "MICVDD" },
+
+	{ "Noise Generator", NULL, "SYSCLK" },
+	{ "Tone Generator 1", NULL, "SYSCLK" },
+	{ "Tone Generator 2", NULL, "SYSCLK" },
+
+	{ "Noise Generator", NULL, "NOISE" },
+	{ "Tone Generator 1", NULL, "TONE" },
+	{ "Tone Generator 2", NULL, "TONE" },
+
+	{ "AIF1 Capture", NULL, "AIF1TX1" },
+	{ "AIF1 Capture", NULL, "AIF1TX2" },
+	{ "AIF1 Capture", NULL, "AIF1TX3" },
+	{ "AIF1 Capture", NULL, "AIF1TX4" },
+	{ "AIF1 Capture", NULL, "AIF1TX5" },
+	{ "AIF1 Capture", NULL, "AIF1TX6" },
+	{ "AIF1 Capture", NULL, "AIF1TX7" },
+	{ "AIF1 Capture", NULL, "AIF1TX8" },
+
+	{ "AIF1RX1", NULL, "AIF1 Playback" },
+	{ "AIF1RX2", NULL, "AIF1 Playback" },
+	{ "AIF1RX3", NULL, "AIF1 Playback" },
+	{ "AIF1RX4", NULL, "AIF1 Playback" },
+	{ "AIF1RX5", NULL, "AIF1 Playback" },
+	{ "AIF1RX6", NULL, "AIF1 Playback" },
+	{ "AIF1RX7", NULL, "AIF1 Playback" },
+	{ "AIF1RX8", NULL, "AIF1 Playback" },
+
+	{ "AIF2 Capture", NULL, "AIF2TX1" },
+	{ "AIF2 Capture", NULL, "AIF2TX2" },
+	{ "AIF2 Capture", NULL, "AIF2TX3" },
+	{ "AIF2 Capture", NULL, "AIF2TX4" },
+	{ "AIF2 Capture", NULL, "AIF2TX5" },
+	{ "AIF2 Capture", NULL, "AIF2TX6" },
+
+	{ "AIF2RX1", NULL, "AIF2 Playback" },
+	{ "AIF2RX2", NULL, "AIF2 Playback" },
+	{ "AIF2RX3", NULL, "AIF2 Playback" },
+	{ "AIF2RX4", NULL, "AIF2 Playback" },
+	{ "AIF2RX5", NULL, "AIF2 Playback" },
+	{ "AIF2RX6", NULL, "AIF2 Playback" },
+
+	{ "AIF3 Capture", NULL, "AIF3TX1" },
+	{ "AIF3 Capture", NULL, "AIF3TX2" },
+
+	{ "AIF3RX1", NULL, "AIF3 Playback" },
+	{ "AIF3RX2", NULL, "AIF3 Playback" },
+
+	{ "AIF1 Playback", NULL, "SYSCLK" },
+	{ "AIF2 Playback", NULL, "SYSCLK" },
+	{ "AIF3 Playback", NULL, "SYSCLK" },
+
+	{ "AIF1 Capture", NULL, "SYSCLK" },
+	{ "AIF2 Capture", NULL, "SYSCLK" },
+	{ "AIF3 Capture", NULL, "SYSCLK" },
+
+	{ "Voice Control DSP", NULL, "DSP3" },
+
+	{ "IN1L PGA", NULL, "IN1L" },
+	{ "IN1R PGA", NULL, "IN1R" },
+
+	{ "IN2L PGA", NULL, "IN2L" },
+	{ "IN2R PGA", NULL, "IN2R" },
+
+	{ "Audio Trace DSP", NULL, "DSP2" },
+
+	ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
+	ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
+
+	ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUT"),
+
+	ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"),
+	ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"),
+
+	ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+	ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+	ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+	ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+	ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+	ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+	ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
+	ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
+
+	ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
+	ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+	ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"),
+	ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"),
+	ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"),
+	ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"),
+
+	ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
+	ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
+
+	ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
+	ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
+
+	ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"),
+	ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"),
+	ARIZONA_MIXER_ROUTES("DRC2L", "DRC2L"),
+	ARIZONA_MIXER_ROUTES("DRC2R", "DRC2R"),
+
+	ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
+	ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
+	ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
+	ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+	ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"),
+	ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"),
+	ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
+	ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
+
+	ARIZONA_DSP_ROUTES("DSP2"),
+	ARIZONA_DSP_ROUTES("DSP3"),
+
+	ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+	ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+	ARIZONA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"),
+	ARIZONA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"),
+
+	ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"),
+
+	ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+	ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+	ARIZONA_MUX_ROUTES("ISRC2INT3", "ISRC2INT3"),
+	ARIZONA_MUX_ROUTES("ISRC2INT4", "ISRC2INT4"),
+
+	ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC3", "ISRC2DEC3"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC4", "ISRC2DEC4"),
+
+	ARIZONA_MUX_ROUTES("ISRC3INT1", "ISRC3INT1"),
+	ARIZONA_MUX_ROUTES("ISRC3INT2", "ISRC3INT2"),
+	ARIZONA_MUX_ROUTES("ISRC3INT3", "ISRC3INT3"),
+	ARIZONA_MUX_ROUTES("ISRC3INT4", "ISRC3INT4"),
+
+	ARIZONA_MUX_ROUTES("ISRC3DEC1", "ISRC3DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC3DEC2", "ISRC3DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC3DEC3", "ISRC3DEC3"),
+	ARIZONA_MUX_ROUTES("ISRC3DEC4", "ISRC3DEC4"),
+
+	{ "AEC Loopback", "HPOUT1L", "OUT1L" },
+	{ "AEC Loopback", "HPOUT1R", "OUT1R" },
+	{ "HPOUT1L", NULL, "OUT1L" },
+	{ "HPOUT1R", NULL, "OUT1R" },
+
+	{ "AEC Loopback", "SPKOUT", "OUT4L" },
+	{ "SPKOUTN", NULL, "OUT4L" },
+	{ "SPKOUTP", NULL, "OUT4L" },
+
+	{ "MICSUPP", NULL, "SYSCLK" },
+
+	{ "DRC1 Signal Activity", NULL, "SYSCLK" },
+	{ "DRC2 Signal Activity", NULL, "SYSCLK" },
+	{ "DRC1 Signal Activity", NULL, "DRC1L" },
+	{ "DRC1 Signal Activity", NULL, "DRC1R" },
+	{ "DRC2 Signal Activity", NULL, "DRC2L" },
+	{ "DRC2 Signal Activity", NULL, "DRC2R" },
+
+	{ "DSP Voice Trigger", NULL, "SYSCLK" },
+	{ "DSP Voice Trigger", NULL, "DSP3 Voice Trigger" },
+	{ "DSP3 Voice Trigger", "Switch", "DSP3" },
+};
+
+static int cs47l24_set_fll(struct snd_soc_component *component, int fll_id,
+			   int source, unsigned int Fref, unsigned int Fout)
+{
+	struct cs47l24_priv *cs47l24 = snd_soc_component_get_drvdata(component);
+
+	switch (fll_id) {
+	case CS47L24_FLL1:
+		return arizona_set_fll(&cs47l24->fll[0], source, Fref, Fout);
+	case CS47L24_FLL2:
+		return arizona_set_fll(&cs47l24->fll[1], source, Fref, Fout);
+	case CS47L24_FLL1_REFCLK:
+		return arizona_set_fll_refclk(&cs47l24->fll[0], source, Fref,
+					      Fout);
+	case CS47L24_FLL2_REFCLK:
+		return arizona_set_fll_refclk(&cs47l24->fll[1], source, Fref,
+					      Fout);
+	default:
+		return -EINVAL;
+	}
+}
+
+#define CS47L24_RATES SNDRV_PCM_RATE_KNOT
+
+#define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver cs47l24_dai[] = {
+	{
+		.name = "cs47l24-aif1",
+		.id = 1,
+		.base = ARIZONA_AIF1_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = CS47L24_RATES,
+			.formats = CS47L24_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 8,
+			 .rates = CS47L24_RATES,
+			 .formats = CS47L24_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "cs47l24-aif2",
+		.id = 2,
+		.base = ARIZONA_AIF2_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = CS47L24_RATES,
+			.formats = CS47L24_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 6,
+			 .rates = CS47L24_RATES,
+			 .formats = CS47L24_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "cs47l24-aif3",
+		.id = 3,
+		.base = ARIZONA_AIF3_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS47L24_RATES,
+			.formats = CS47L24_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF3 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = CS47L24_RATES,
+			 .formats = CS47L24_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "cs47l24-cpu-voicectrl",
+		.capture = {
+			.stream_name = "Voice Control CPU",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = CS47L24_RATES,
+			.formats = CS47L24_FORMATS,
+		},
+		.compress_new = snd_soc_new_compress,
+	},
+	{
+		.name = "cs47l24-dsp-voicectrl",
+		.capture = {
+			.stream_name = "Voice Control DSP",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = CS47L24_RATES,
+			.formats = CS47L24_FORMATS,
+		},
+	},
+	{
+		.name = "cs47l24-cpu-trace",
+		.capture = {
+			.stream_name = "Audio Trace CPU",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = CS47L24_RATES,
+			.formats = CS47L24_FORMATS,
+		},
+		.compress_new = snd_soc_new_compress,
+	},
+	{
+		.name = "cs47l24-dsp-trace",
+		.capture = {
+			.stream_name = "Audio Trace DSP",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = CS47L24_RATES,
+			.formats = CS47L24_FORMATS,
+		},
+	},
+};
+
+static int cs47l24_open(struct snd_compr_stream *stream)
+{
+	struct snd_soc_pcm_runtime *rtd = stream->private_data;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct cs47l24_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->core.arizona;
+	int n_adsp;
+
+	if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-voicectrl") == 0) {
+		n_adsp = 2;
+	} else if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-trace") == 0) {
+		n_adsp = 1;
+	} else {
+		dev_err(arizona->dev,
+			"No suitable compressed stream for DAI '%s'\n",
+			rtd->codec_dai->name);
+		return -EINVAL;
+	}
+
+	return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream);
+}
+
+static irqreturn_t cs47l24_adsp2_irq(int irq, void *data)
+{
+	struct cs47l24_priv *priv = data;
+	struct arizona *arizona = priv->core.arizona;
+	struct arizona_voice_trigger_info info;
+	int serviced = 0;
+	int i, ret;
+
+	for (i = 1; i <= 2; ++i) {
+		ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]);
+		if (ret != -ENODEV)
+			serviced++;
+		if (ret == WM_ADSP_COMPR_VOICE_TRIGGER) {
+			info.core = i;
+			arizona_call_notifiers(arizona,
+					       ARIZONA_NOTIFY_VOICE_TRIGGER,
+					       &info);
+		}
+	}
+
+	if (!serviced) {
+		dev_err(arizona->dev, "Spurious compressed data IRQ\n");
+		return IRQ_NONE;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int cs47l24_component_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct cs47l24_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->core.arizona;
+	int ret;
+
+	arizona->dapm = dapm;
+	snd_soc_component_init_regmap(component, arizona->regmap);
+
+	ret = arizona_init_spk(component);
+	if (ret < 0)
+		return ret;
+
+	arizona_init_gpio(component);
+	arizona_init_mono(component);
+
+	ret = wm_adsp2_component_probe(&priv->core.adsp[1], component);
+	if (ret)
+		goto err_adsp2_codec_probe;
+
+	ret = wm_adsp2_component_probe(&priv->core.adsp[2], component);
+	if (ret)
+		goto err_adsp2_codec_probe;
+
+	ret = snd_soc_add_component_controls(component,
+					     &arizona_adsp2_rate_controls[1],
+					     2);
+	if (ret)
+		goto err_adsp2_codec_probe;
+
+	snd_soc_component_disable_pin(component, "HAPTICS");
+
+	return 0;
+
+err_adsp2_codec_probe:
+	wm_adsp2_component_remove(&priv->core.adsp[1], component);
+	wm_adsp2_component_remove(&priv->core.adsp[2], component);
+
+	return ret;
+}
+
+static void cs47l24_component_remove(struct snd_soc_component *component)
+{
+	struct cs47l24_priv *priv = snd_soc_component_get_drvdata(component);
+
+	wm_adsp2_component_remove(&priv->core.adsp[1], component);
+	wm_adsp2_component_remove(&priv->core.adsp[2], component);
+
+	priv->core.arizona->dapm = NULL;
+}
+
+#define CS47L24_DIG_VU 0x0200
+
+static unsigned int cs47l24_digital_vu[] = {
+	ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	ARIZONA_DAC_DIGITAL_VOLUME_1R,
+	ARIZONA_DAC_DIGITAL_VOLUME_4L,
+};
+
+static struct snd_compr_ops cs47l24_compr_ops = {
+	.open		= cs47l24_open,
+	.free		= wm_adsp_compr_free,
+	.set_params	= wm_adsp_compr_set_params,
+	.get_caps	= wm_adsp_compr_get_caps,
+	.trigger	= wm_adsp_compr_trigger,
+	.pointer	= wm_adsp_compr_pointer,
+	.copy		= wm_adsp_compr_copy,
+};
+
+static const struct snd_soc_component_driver soc_component_dev_cs47l24 = {
+	.probe			= cs47l24_component_probe,
+	.remove			= cs47l24_component_remove,
+	.set_sysclk		= arizona_set_sysclk,
+	.set_pll		= cs47l24_set_fll,
+	.name			= DRV_NAME,
+	.compr_ops		= &cs47l24_compr_ops,
+	.controls		= cs47l24_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs47l24_snd_controls),
+	.dapm_widgets		= cs47l24_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs47l24_dapm_widgets),
+	.dapm_routes		= cs47l24_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs47l24_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int cs47l24_probe(struct platform_device *pdev)
+{
+	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+	struct cs47l24_priv *cs47l24;
+	int i, ret;
+
+	BUILD_BUG_ON(ARRAY_SIZE(cs47l24_dai) > ARIZONA_MAX_DAI);
+
+	cs47l24 = devm_kzalloc(&pdev->dev, sizeof(struct cs47l24_priv),
+			       GFP_KERNEL);
+	if (!cs47l24)
+		return -ENOMEM;
+
+	if (IS_ENABLED(CONFIG_OF)) {
+		if (!dev_get_platdata(arizona->dev)) {
+			ret = arizona_of_get_audio_pdata(arizona);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	platform_set_drvdata(pdev, cs47l24);
+
+	cs47l24->core.arizona = arizona;
+	cs47l24->core.num_inputs = 4;
+
+	for (i = 1; i <= 2; i++) {
+		cs47l24->core.adsp[i].part = "cs47l24";
+		cs47l24->core.adsp[i].num = i + 1;
+		cs47l24->core.adsp[i].type = WMFW_ADSP2;
+		cs47l24->core.adsp[i].dev = arizona->dev;
+		cs47l24->core.adsp[i].regmap = arizona->regmap;
+
+		cs47l24->core.adsp[i].base = ARIZONA_DSP1_CONTROL_1 +
+					     (0x100 * i);
+		cs47l24->core.adsp[i].mem = cs47l24_dsp_regions[i - 1];
+		cs47l24->core.adsp[i].num_mems =
+				ARRAY_SIZE(cs47l24_dsp2_regions);
+
+		ret = wm_adsp2_init(&cs47l24->core.adsp[i]);
+		if (ret != 0)
+			return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cs47l24->fll); i++)
+		cs47l24->fll[i].vco_mult = 3;
+
+	arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK,
+			 &cs47l24->fll[0]);
+	arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
+			 &cs47l24->fll[1]);
+
+	/* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
+			   ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
+			   ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
+
+	for (i = 0; i < ARRAY_SIZE(cs47l24_dai); i++)
+		arizona_init_dai(&cs47l24->core, i);
+
+	/* Latch volume update bits */
+	for (i = 0; i < ARRAY_SIZE(cs47l24_digital_vu); i++)
+		regmap_update_bits(arizona->regmap, cs47l24_digital_vu[i],
+				   CS47L24_DIG_VU, CS47L24_DIG_VU);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_idle(&pdev->dev);
+
+	ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
+				  "ADSP2 Compressed IRQ", cs47l24_adsp2_irq,
+				  cs47l24);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret);
+		return ret;
+	}
+
+	ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 1);
+	if (ret != 0)
+		dev_warn(&pdev->dev,
+			 "Failed to set compressed IRQ as a wake source: %d\n",
+			 ret);
+
+	arizona_init_common(arizona);
+
+	ret = arizona_init_vol_limit(arizona);
+	if (ret < 0)
+		goto err_dsp_irq;
+	ret = arizona_init_spk_irqs(arizona);
+	if (ret < 0)
+		goto err_dsp_irq;
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					      &soc_component_dev_cs47l24,
+					      cs47l24_dai,
+					      ARRAY_SIZE(cs47l24_dai));
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
+		goto err_spk_irqs;
+	}
+
+	return ret;
+
+err_spk_irqs:
+	arizona_free_spk_irqs(arizona);
+err_dsp_irq:
+	arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
+	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, cs47l24);
+
+	return ret;
+}
+
+static int cs47l24_remove(struct platform_device *pdev)
+{
+	struct cs47l24_priv *cs47l24 = platform_get_drvdata(pdev);
+	struct arizona *arizona = cs47l24->core.arizona;
+
+	pm_runtime_disable(&pdev->dev);
+
+	wm_adsp2_remove(&cs47l24->core.adsp[1]);
+	wm_adsp2_remove(&cs47l24->core.adsp[2]);
+
+	arizona_free_spk_irqs(arizona);
+
+	arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
+	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, cs47l24);
+
+	return 0;
+}
+
+static struct platform_driver cs47l24_codec_driver = {
+	.driver = {
+		.name = "cs47l24-codec",
+	},
+	.probe = cs47l24_probe,
+	.remove = cs47l24_remove,
+};
+
+module_platform_driver(cs47l24_codec_driver);
+
+MODULE_DESCRIPTION("ASoC CS47L24 driver");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:cs47l24-codec");
diff --git a/sound/soc/codecs/cs47l24.h b/sound/soc/codecs/cs47l24.h
new file mode 100644
index 0000000..77ab2b7
--- /dev/null
+++ b/sound/soc/codecs/cs47l24.h
@@ -0,0 +1,23 @@
+/*
+ * cs47l24.h  --  ALSA SoC Audio driver for Cirrus Logic CS47L24
+ *
+ * Copyright 2015 Cirrus Logic Inc.
+ *
+ * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _CS47L24_H
+#define _CS47L24_H
+
+#include "arizona.h"
+
+#define CS47L24_FLL1        1
+#define CS47L24_FLL2        2
+#define CS47L24_FLL1_REFCLK 3
+#define CS47L24_FLL2_REFCLK 4
+
+#endif
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
new file mode 100644
index 0000000..8995ea4
--- /dev/null
+++ b/sound/soc/codecs/cs53l30.c
@@ -0,0 +1,1137 @@
+/*
+ * cs53l30.c  --  CS53l30 ALSA Soc Audio driver
+ *
+ * Copyright 2015 Cirrus Logic, Inc.
+ *
+ * Authors: Paul Handrigan <Paul.Handrigan@cirrus.com>,
+ *          Tim Howe <Tim.Howe@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "cs53l30.h"
+
+#define CS53L30_NUM_SUPPLIES 2
+static const char *const cs53l30_supply_names[CS53L30_NUM_SUPPLIES] = {
+	"VA",
+	"VP",
+};
+
+struct cs53l30_private {
+	struct regulator_bulk_data	supplies[CS53L30_NUM_SUPPLIES];
+	struct regmap			*regmap;
+	struct gpio_desc		*reset_gpio;
+	struct gpio_desc		*mute_gpio;
+	struct clk			*mclk;
+	bool				use_sdout2;
+	u32				mclk_rate;
+};
+
+static const struct reg_default cs53l30_reg_defaults[] = {
+	{ CS53L30_PWRCTL,		CS53L30_PWRCTL_DEFAULT },
+	{ CS53L30_MCLKCTL,		CS53L30_MCLKCTL_DEFAULT },
+	{ CS53L30_INT_SR_CTL,		CS53L30_INT_SR_CTL_DEFAULT },
+	{ CS53L30_MICBIAS_CTL,		CS53L30_MICBIAS_CTL_DEFAULT },
+	{ CS53L30_ASPCFG_CTL,		CS53L30_ASPCFG_CTL_DEFAULT },
+	{ CS53L30_ASP_CTL1,		CS53L30_ASP_CTL1_DEFAULT },
+	{ CS53L30_ASP_TDMTX_CTL1,	CS53L30_ASP_TDMTX_CTLx_DEFAULT },
+	{ CS53L30_ASP_TDMTX_CTL2,	CS53L30_ASP_TDMTX_CTLx_DEFAULT },
+	{ CS53L30_ASP_TDMTX_CTL3,	CS53L30_ASP_TDMTX_CTLx_DEFAULT },
+	{ CS53L30_ASP_TDMTX_CTL4,	CS53L30_ASP_TDMTX_CTLx_DEFAULT },
+	{ CS53L30_ASP_TDMTX_EN1,	CS53L30_ASP_TDMTX_ENx_DEFAULT },
+	{ CS53L30_ASP_TDMTX_EN2,	CS53L30_ASP_TDMTX_ENx_DEFAULT },
+	{ CS53L30_ASP_TDMTX_EN3,	CS53L30_ASP_TDMTX_ENx_DEFAULT },
+	{ CS53L30_ASP_TDMTX_EN4,	CS53L30_ASP_TDMTX_ENx_DEFAULT },
+	{ CS53L30_ASP_TDMTX_EN5,	CS53L30_ASP_TDMTX_ENx_DEFAULT },
+	{ CS53L30_ASP_TDMTX_EN6,	CS53L30_ASP_TDMTX_ENx_DEFAULT },
+	{ CS53L30_ASP_CTL2,		CS53L30_ASP_CTL2_DEFAULT },
+	{ CS53L30_SFT_RAMP,		CS53L30_SFT_RMP_DEFAULT },
+	{ CS53L30_LRCK_CTL1,		CS53L30_LRCK_CTLx_DEFAULT },
+	{ CS53L30_LRCK_CTL2,		CS53L30_LRCK_CTLx_DEFAULT },
+	{ CS53L30_MUTEP_CTL1,		CS53L30_MUTEP_CTL1_DEFAULT },
+	{ CS53L30_MUTEP_CTL2,		CS53L30_MUTEP_CTL2_DEFAULT },
+	{ CS53L30_INBIAS_CTL1,		CS53L30_INBIAS_CTL1_DEFAULT },
+	{ CS53L30_INBIAS_CTL2,		CS53L30_INBIAS_CTL2_DEFAULT },
+	{ CS53L30_DMIC1_STR_CTL,	CS53L30_DMIC1_STR_CTL_DEFAULT },
+	{ CS53L30_DMIC2_STR_CTL,	CS53L30_DMIC2_STR_CTL_DEFAULT },
+	{ CS53L30_ADCDMIC1_CTL1,	CS53L30_ADCDMICx_CTL1_DEFAULT },
+	{ CS53L30_ADCDMIC1_CTL2,	CS53L30_ADCDMIC1_CTL2_DEFAULT },
+	{ CS53L30_ADC1_CTL3,		CS53L30_ADCx_CTL3_DEFAULT },
+	{ CS53L30_ADC1_NG_CTL,		CS53L30_ADCx_NG_CTL_DEFAULT },
+	{ CS53L30_ADC1A_AFE_CTL,	CS53L30_ADCxy_AFE_CTL_DEFAULT },
+	{ CS53L30_ADC1B_AFE_CTL,	CS53L30_ADCxy_AFE_CTL_DEFAULT },
+	{ CS53L30_ADC1A_DIG_VOL,	CS53L30_ADCxy_DIG_VOL_DEFAULT },
+	{ CS53L30_ADC1B_DIG_VOL,	CS53L30_ADCxy_DIG_VOL_DEFAULT },
+	{ CS53L30_ADCDMIC2_CTL1,	CS53L30_ADCDMICx_CTL1_DEFAULT },
+	{ CS53L30_ADCDMIC2_CTL2,	CS53L30_ADCDMIC1_CTL2_DEFAULT },
+	{ CS53L30_ADC2_CTL3,		CS53L30_ADCx_CTL3_DEFAULT },
+	{ CS53L30_ADC2_NG_CTL,		CS53L30_ADCx_NG_CTL_DEFAULT },
+	{ CS53L30_ADC2A_AFE_CTL,	CS53L30_ADCxy_AFE_CTL_DEFAULT },
+	{ CS53L30_ADC2B_AFE_CTL,	CS53L30_ADCxy_AFE_CTL_DEFAULT },
+	{ CS53L30_ADC2A_DIG_VOL,	CS53L30_ADCxy_DIG_VOL_DEFAULT },
+	{ CS53L30_ADC2B_DIG_VOL,	CS53L30_ADCxy_DIG_VOL_DEFAULT },
+	{ CS53L30_INT_MASK,		CS53L30_DEVICE_INT_MASK },
+};
+
+static bool cs53l30_volatile_register(struct device *dev, unsigned int reg)
+{
+	if (reg == CS53L30_IS)
+		return true;
+	else
+		return false;
+}
+
+static bool cs53l30_writeable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS53L30_DEVID_AB:
+	case CS53L30_DEVID_CD:
+	case CS53L30_DEVID_E:
+	case CS53L30_REVID:
+	case CS53L30_IS:
+		return false;
+	default:
+		return true;
+	}
+}
+
+static bool cs53l30_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CS53L30_DEVID_AB:
+	case CS53L30_DEVID_CD:
+	case CS53L30_DEVID_E:
+	case CS53L30_REVID:
+	case CS53L30_PWRCTL:
+	case CS53L30_MCLKCTL:
+	case CS53L30_INT_SR_CTL:
+	case CS53L30_MICBIAS_CTL:
+	case CS53L30_ASPCFG_CTL:
+	case CS53L30_ASP_CTL1:
+	case CS53L30_ASP_TDMTX_CTL1:
+	case CS53L30_ASP_TDMTX_CTL2:
+	case CS53L30_ASP_TDMTX_CTL3:
+	case CS53L30_ASP_TDMTX_CTL4:
+	case CS53L30_ASP_TDMTX_EN1:
+	case CS53L30_ASP_TDMTX_EN2:
+	case CS53L30_ASP_TDMTX_EN3:
+	case CS53L30_ASP_TDMTX_EN4:
+	case CS53L30_ASP_TDMTX_EN5:
+	case CS53L30_ASP_TDMTX_EN6:
+	case CS53L30_ASP_CTL2:
+	case CS53L30_SFT_RAMP:
+	case CS53L30_LRCK_CTL1:
+	case CS53L30_LRCK_CTL2:
+	case CS53L30_MUTEP_CTL1:
+	case CS53L30_MUTEP_CTL2:
+	case CS53L30_INBIAS_CTL1:
+	case CS53L30_INBIAS_CTL2:
+	case CS53L30_DMIC1_STR_CTL:
+	case CS53L30_DMIC2_STR_CTL:
+	case CS53L30_ADCDMIC1_CTL1:
+	case CS53L30_ADCDMIC1_CTL2:
+	case CS53L30_ADC1_CTL3:
+	case CS53L30_ADC1_NG_CTL:
+	case CS53L30_ADC1A_AFE_CTL:
+	case CS53L30_ADC1B_AFE_CTL:
+	case CS53L30_ADC1A_DIG_VOL:
+	case CS53L30_ADC1B_DIG_VOL:
+	case CS53L30_ADCDMIC2_CTL1:
+	case CS53L30_ADCDMIC2_CTL2:
+	case CS53L30_ADC2_CTL3:
+	case CS53L30_ADC2_NG_CTL:
+	case CS53L30_ADC2A_AFE_CTL:
+	case CS53L30_ADC2B_AFE_CTL:
+	case CS53L30_ADC2A_DIG_VOL:
+	case CS53L30_ADC2B_DIG_VOL:
+	case CS53L30_INT_MASK:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static DECLARE_TLV_DB_SCALE(adc_boost_tlv, 0, 2000, 0);
+static DECLARE_TLV_DB_SCALE(adc_ng_boost_tlv, 0, 3000, 0);
+static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
+static DECLARE_TLV_DB_SCALE(dig_tlv, -9600, 100, 1);
+static DECLARE_TLV_DB_SCALE(pga_preamp_tlv, 0, 10000, 0);
+
+static const char * const input1_sel_text[] = {
+	"DMIC1 On AB In",
+	"DMIC1 On A In",
+	"DMIC1 On B In",
+	"ADC1 On AB In",
+	"ADC1 On A In",
+	"ADC1 On B In",
+	"DMIC1 Off ADC1 Off",
+};
+
+static unsigned int const input1_sel_values[] = {
+	CS53L30_CH_TYPE,
+	CS53L30_ADCxB_PDN | CS53L30_CH_TYPE,
+	CS53L30_ADCxA_PDN | CS53L30_CH_TYPE,
+	CS53L30_DMICx_PDN,
+	CS53L30_ADCxB_PDN | CS53L30_DMICx_PDN,
+	CS53L30_ADCxA_PDN | CS53L30_DMICx_PDN,
+	CS53L30_ADCxA_PDN | CS53L30_ADCxB_PDN | CS53L30_DMICx_PDN,
+};
+
+static const char * const input2_sel_text[] = {
+	"DMIC2 On AB In",
+	"DMIC2 On A In",
+	"DMIC2 On B In",
+	"ADC2 On AB In",
+	"ADC2 On A In",
+	"ADC2 On B In",
+	"DMIC2 Off ADC2 Off",
+};
+
+static unsigned int const input2_sel_values[] = {
+	0x0,
+	CS53L30_ADCxB_PDN,
+	CS53L30_ADCxA_PDN,
+	CS53L30_DMICx_PDN,
+	CS53L30_ADCxB_PDN | CS53L30_DMICx_PDN,
+	CS53L30_ADCxA_PDN | CS53L30_DMICx_PDN,
+	CS53L30_ADCxA_PDN | CS53L30_ADCxB_PDN | CS53L30_DMICx_PDN,
+};
+
+static const char * const input1_route_sel_text[] = {
+	"ADC1_SEL", "DMIC1_SEL",
+};
+
+static const struct soc_enum input1_route_sel_enum =
+	SOC_ENUM_SINGLE(CS53L30_ADCDMIC1_CTL1, CS53L30_CH_TYPE_SHIFT,
+			ARRAY_SIZE(input1_route_sel_text),
+			input1_route_sel_text);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(input1_sel_enum, CS53L30_ADCDMIC1_CTL1, 0,
+				  CS53L30_ADCDMICx_PDN_MASK, input1_sel_text,
+				  input1_sel_values);
+
+static const struct snd_kcontrol_new input1_route_sel_mux =
+	SOC_DAPM_ENUM("Input 1 Route", input1_route_sel_enum);
+
+static const char * const input2_route_sel_text[] = {
+	"ADC2_SEL", "DMIC2_SEL",
+};
+
+/* Note: CS53L30_ADCDMIC1_CTL1 CH_TYPE controls inputs 1 and 2 */
+static const struct soc_enum input2_route_sel_enum =
+	SOC_ENUM_SINGLE(CS53L30_ADCDMIC1_CTL1, 0,
+			ARRAY_SIZE(input2_route_sel_text),
+			input2_route_sel_text);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(input2_sel_enum, CS53L30_ADCDMIC2_CTL1, 0,
+				  CS53L30_ADCDMICx_PDN_MASK, input2_sel_text,
+				  input2_sel_values);
+
+static const struct snd_kcontrol_new input2_route_sel_mux =
+	SOC_DAPM_ENUM("Input 2 Route", input2_route_sel_enum);
+
+/*
+ * TB = 6144*(MCLK(int) scaling factor)/MCLK(internal)
+ * TB - Time base
+ * NOTE: If MCLK_INT_SCALE = 0, then TB=1
+ */
+static const char * const cs53l30_ng_delay_text[] = {
+	"TB*50ms", "TB*100ms", "TB*150ms", "TB*200ms",
+};
+
+static const struct soc_enum adc1_ng_delay_enum =
+	SOC_ENUM_SINGLE(CS53L30_ADC1_NG_CTL, CS53L30_ADCx_NG_DELAY_SHIFT,
+			ARRAY_SIZE(cs53l30_ng_delay_text),
+			cs53l30_ng_delay_text);
+
+static const struct soc_enum adc2_ng_delay_enum =
+	SOC_ENUM_SINGLE(CS53L30_ADC2_NG_CTL, CS53L30_ADCx_NG_DELAY_SHIFT,
+			ARRAY_SIZE(cs53l30_ng_delay_text),
+			cs53l30_ng_delay_text);
+
+/* The noise gate threshold selected will depend on NG Boost */
+static const char * const cs53l30_ng_thres_text[] = {
+	"-64dB/-34dB", "-66dB/-36dB", "-70dB/-40dB", "-73dB/-43dB",
+	"-76dB/-46dB", "-82dB/-52dB", "-58dB", "-64dB",
+};
+
+static const struct soc_enum adc1_ng_thres_enum =
+	SOC_ENUM_SINGLE(CS53L30_ADC1_NG_CTL, CS53L30_ADCx_NG_THRESH_SHIFT,
+			ARRAY_SIZE(cs53l30_ng_thres_text),
+			cs53l30_ng_thres_text);
+
+static const struct soc_enum adc2_ng_thres_enum =
+	SOC_ENUM_SINGLE(CS53L30_ADC2_NG_CTL, CS53L30_ADCx_NG_THRESH_SHIFT,
+			ARRAY_SIZE(cs53l30_ng_thres_text),
+			cs53l30_ng_thres_text);
+
+/* Corner frequencies are with an Fs of 48kHz. */
+static const char * const hpf_corner_freq_text[] = {
+	"1.86Hz", "120Hz", "235Hz", "466Hz",
+};
+
+static const struct soc_enum adc1_hpf_enum =
+	SOC_ENUM_SINGLE(CS53L30_ADC1_CTL3, CS53L30_ADCx_HPF_CF_SHIFT,
+			ARRAY_SIZE(hpf_corner_freq_text), hpf_corner_freq_text);
+
+static const struct soc_enum adc2_hpf_enum =
+	SOC_ENUM_SINGLE(CS53L30_ADC2_CTL3, CS53L30_ADCx_HPF_CF_SHIFT,
+			ARRAY_SIZE(hpf_corner_freq_text), hpf_corner_freq_text);
+
+static const struct snd_kcontrol_new cs53l30_snd_controls[] = {
+	SOC_SINGLE("Digital Soft-Ramp Switch", CS53L30_SFT_RAMP,
+		   CS53L30_DIGSFT_SHIFT, 1, 0),
+	SOC_SINGLE("ADC1 Noise Gate Ganging Switch", CS53L30_ADC1_CTL3,
+		   CS53L30_ADCx_NG_ALL_SHIFT, 1, 0),
+	SOC_SINGLE("ADC2 Noise Gate Ganging Switch", CS53L30_ADC2_CTL3,
+		   CS53L30_ADCx_NG_ALL_SHIFT, 1, 0),
+	SOC_SINGLE("ADC1A Noise Gate Enable Switch", CS53L30_ADC1_NG_CTL,
+		   CS53L30_ADCxA_NG_SHIFT, 1, 0),
+	SOC_SINGLE("ADC1B Noise Gate Enable Switch", CS53L30_ADC1_NG_CTL,
+		   CS53L30_ADCxB_NG_SHIFT, 1, 0),
+	SOC_SINGLE("ADC2A Noise Gate Enable Switch", CS53L30_ADC2_NG_CTL,
+		   CS53L30_ADCxA_NG_SHIFT, 1, 0),
+	SOC_SINGLE("ADC2B Noise Gate Enable Switch", CS53L30_ADC2_NG_CTL,
+		   CS53L30_ADCxB_NG_SHIFT, 1, 0),
+	SOC_SINGLE("ADC1 Notch Filter Switch", CS53L30_ADCDMIC1_CTL2,
+		   CS53L30_ADCx_NOTCH_DIS_SHIFT, 1, 1),
+	SOC_SINGLE("ADC2 Notch Filter Switch", CS53L30_ADCDMIC2_CTL2,
+		   CS53L30_ADCx_NOTCH_DIS_SHIFT, 1, 1),
+	SOC_SINGLE("ADC1A Invert Switch", CS53L30_ADCDMIC1_CTL2,
+		   CS53L30_ADCxA_INV_SHIFT, 1, 0),
+	SOC_SINGLE("ADC1B Invert Switch", CS53L30_ADCDMIC1_CTL2,
+		   CS53L30_ADCxB_INV_SHIFT, 1, 0),
+	SOC_SINGLE("ADC2A Invert Switch", CS53L30_ADCDMIC2_CTL2,
+		   CS53L30_ADCxA_INV_SHIFT, 1, 0),
+	SOC_SINGLE("ADC2B Invert Switch", CS53L30_ADCDMIC2_CTL2,
+		   CS53L30_ADCxB_INV_SHIFT, 1, 0),
+
+	SOC_SINGLE_TLV("ADC1A Digital Boost Volume", CS53L30_ADCDMIC1_CTL2,
+		       CS53L30_ADCxA_DIG_BOOST_SHIFT, 1, 0, adc_boost_tlv),
+	SOC_SINGLE_TLV("ADC1B Digital Boost Volume", CS53L30_ADCDMIC1_CTL2,
+		       CS53L30_ADCxB_DIG_BOOST_SHIFT, 1, 0, adc_boost_tlv),
+	SOC_SINGLE_TLV("ADC2A Digital Boost Volume", CS53L30_ADCDMIC2_CTL2,
+		       CS53L30_ADCxA_DIG_BOOST_SHIFT, 1, 0, adc_boost_tlv),
+	SOC_SINGLE_TLV("ADC2B Digital Boost Volume", CS53L30_ADCDMIC2_CTL2,
+		       CS53L30_ADCxB_DIG_BOOST_SHIFT, 1, 0, adc_boost_tlv),
+	SOC_SINGLE_TLV("ADC1 NG Boost Volume", CS53L30_ADC1_NG_CTL,
+		       CS53L30_ADCx_NG_BOOST_SHIFT, 1, 0, adc_ng_boost_tlv),
+	SOC_SINGLE_TLV("ADC2 NG Boost Volume", CS53L30_ADC2_NG_CTL,
+		       CS53L30_ADCx_NG_BOOST_SHIFT, 1, 0, adc_ng_boost_tlv),
+
+	SOC_DOUBLE_R_TLV("ADC1 Preamplifier Volume", CS53L30_ADC1A_AFE_CTL,
+			 CS53L30_ADC1B_AFE_CTL, CS53L30_ADCxy_PREAMP_SHIFT,
+			 2, 0, pga_preamp_tlv),
+	SOC_DOUBLE_R_TLV("ADC2 Preamplifier Volume", CS53L30_ADC2A_AFE_CTL,
+			 CS53L30_ADC2B_AFE_CTL, CS53L30_ADCxy_PREAMP_SHIFT,
+			 2, 0, pga_preamp_tlv),
+
+	SOC_ENUM("Input 1 Channel Select", input1_sel_enum),
+	SOC_ENUM("Input 2 Channel Select", input2_sel_enum),
+
+	SOC_ENUM("ADC1 HPF Select", adc1_hpf_enum),
+	SOC_ENUM("ADC2 HPF Select", adc2_hpf_enum),
+	SOC_ENUM("ADC1 NG Threshold", adc1_ng_thres_enum),
+	SOC_ENUM("ADC2 NG Threshold", adc2_ng_thres_enum),
+	SOC_ENUM("ADC1 NG Delay", adc1_ng_delay_enum),
+	SOC_ENUM("ADC2 NG Delay", adc2_ng_delay_enum),
+
+	SOC_SINGLE_SX_TLV("ADC1A PGA Volume",
+		    CS53L30_ADC1A_AFE_CTL, 0, 0x34, 0x18, pga_tlv),
+	SOC_SINGLE_SX_TLV("ADC1B PGA Volume",
+		    CS53L30_ADC1B_AFE_CTL, 0, 0x34, 0x18, pga_tlv),
+	SOC_SINGLE_SX_TLV("ADC2A PGA Volume",
+		    CS53L30_ADC2A_AFE_CTL, 0, 0x34, 0x18, pga_tlv),
+	SOC_SINGLE_SX_TLV("ADC2B PGA Volume",
+		    CS53L30_ADC2B_AFE_CTL, 0, 0x34, 0x18, pga_tlv),
+
+	SOC_SINGLE_SX_TLV("ADC1A Digital Volume",
+		    CS53L30_ADC1A_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv),
+	SOC_SINGLE_SX_TLV("ADC1B Digital Volume",
+		    CS53L30_ADC1B_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv),
+	SOC_SINGLE_SX_TLV("ADC2A Digital Volume",
+		    CS53L30_ADC2A_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv),
+	SOC_SINGLE_SX_TLV("ADC2B Digital Volume",
+		    CS53L30_ADC2B_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv),
+};
+
+static const struct snd_soc_dapm_widget cs53l30_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("IN1_DMIC1"),
+	SND_SOC_DAPM_INPUT("IN2"),
+	SND_SOC_DAPM_INPUT("IN3_DMIC2"),
+	SND_SOC_DAPM_INPUT("IN4"),
+	SND_SOC_DAPM_SUPPLY("MIC1 Bias", CS53L30_MICBIAS_CTL,
+			    CS53L30_MIC1_BIAS_PDN_SHIFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MIC2 Bias", CS53L30_MICBIAS_CTL,
+			    CS53L30_MIC2_BIAS_PDN_SHIFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MIC3 Bias", CS53L30_MICBIAS_CTL,
+			    CS53L30_MIC3_BIAS_PDN_SHIFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MIC4 Bias", CS53L30_MICBIAS_CTL,
+			    CS53L30_MIC4_BIAS_PDN_SHIFT, 1, NULL, 0),
+
+	SND_SOC_DAPM_AIF_OUT("ASP_SDOUT1", NULL, 0, CS53L30_ASP_CTL1,
+			     CS53L30_ASP_SDOUTx_PDN_SHIFT, 1),
+	SND_SOC_DAPM_AIF_OUT("ASP_SDOUT2", NULL, 0, CS53L30_ASP_CTL2,
+			     CS53L30_ASP_SDOUTx_PDN_SHIFT, 1),
+
+	SND_SOC_DAPM_MUX("Input Mux 1", SND_SOC_NOPM, 0, 0,
+			 &input1_route_sel_mux),
+	SND_SOC_DAPM_MUX("Input Mux 2", SND_SOC_NOPM, 0, 0,
+			 &input2_route_sel_mux),
+
+	SND_SOC_DAPM_ADC("ADC1A", NULL, CS53L30_ADCDMIC1_CTL1,
+			 CS53L30_ADCxA_PDN_SHIFT, 1),
+	SND_SOC_DAPM_ADC("ADC1B", NULL, CS53L30_ADCDMIC1_CTL1,
+			 CS53L30_ADCxB_PDN_SHIFT, 1),
+	SND_SOC_DAPM_ADC("ADC2A", NULL, CS53L30_ADCDMIC2_CTL1,
+			 CS53L30_ADCxA_PDN_SHIFT, 1),
+	SND_SOC_DAPM_ADC("ADC2B", NULL, CS53L30_ADCDMIC2_CTL1,
+			 CS53L30_ADCxB_PDN_SHIFT, 1),
+	SND_SOC_DAPM_ADC("DMIC1", NULL, CS53L30_ADCDMIC1_CTL1,
+			 CS53L30_DMICx_PDN_SHIFT, 1),
+	SND_SOC_DAPM_ADC("DMIC2", NULL, CS53L30_ADCDMIC2_CTL1,
+			 CS53L30_DMICx_PDN_SHIFT, 1),
+};
+
+static const struct snd_soc_dapm_route cs53l30_dapm_routes[] = {
+	/* ADC Input Paths */
+	{"ADC1A", NULL, "IN1_DMIC1"},
+	{"Input Mux 1", "ADC1_SEL", "ADC1A"},
+	{"ADC1B", NULL, "IN2"},
+
+	{"ADC2A", NULL, "IN3_DMIC2"},
+	{"Input Mux 2", "ADC2_SEL", "ADC2A"},
+	{"ADC2B", NULL, "IN4"},
+
+	/* MIC Bias Paths */
+	{"ADC1A", NULL, "MIC1 Bias"},
+	{"ADC1B", NULL, "MIC2 Bias"},
+	{"ADC2A", NULL, "MIC3 Bias"},
+	{"ADC2B", NULL, "MIC4 Bias"},
+
+	/* DMIC Paths */
+	{"DMIC1", NULL, "IN1_DMIC1"},
+	{"Input Mux 1", "DMIC1_SEL", "DMIC1"},
+
+	{"DMIC2", NULL, "IN3_DMIC2"},
+	{"Input Mux 2", "DMIC2_SEL", "DMIC2"},
+};
+
+static const struct snd_soc_dapm_route cs53l30_dapm_routes_sdout1[] = {
+	/* Output Paths when using SDOUT1 only */
+	{"ASP_SDOUT1", NULL, "ADC1A" },
+	{"ASP_SDOUT1", NULL, "Input Mux 1"},
+	{"ASP_SDOUT1", NULL, "ADC1B"},
+
+	{"ASP_SDOUT1", NULL, "ADC2A"},
+	{"ASP_SDOUT1", NULL, "Input Mux 2"},
+	{"ASP_SDOUT1", NULL, "ADC2B"},
+
+	{"Capture", NULL, "ASP_SDOUT1"},
+};
+
+static const struct snd_soc_dapm_route cs53l30_dapm_routes_sdout2[] = {
+	/* Output Paths when using both SDOUT1 and SDOUT2 */
+	{"ASP_SDOUT1", NULL, "ADC1A" },
+	{"ASP_SDOUT1", NULL, "Input Mux 1"},
+	{"ASP_SDOUT1", NULL, "ADC1B"},
+
+	{"ASP_SDOUT2", NULL, "ADC2A"},
+	{"ASP_SDOUT2", NULL, "Input Mux 2"},
+	{"ASP_SDOUT2", NULL, "ADC2B"},
+
+	{"Capture", NULL, "ASP_SDOUT1"},
+	{"Capture", NULL, "ASP_SDOUT2"},
+};
+
+struct cs53l30_mclk_div {
+	u32 mclk_rate;
+	u32 srate;
+	u8 asp_rate;
+	u8 internal_fs_ratio;
+	u8 mclk_int_scale;
+};
+
+static const struct cs53l30_mclk_div cs53l30_mclk_coeffs[] = {
+	/* NOTE: Enable MCLK_INT_SCALE to save power. */
+
+	/* MCLK, Sample Rate, asp_rate, internal_fs_ratio, mclk_int_scale */
+	{5644800, 11025, 0x4, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{5644800, 22050, 0x8, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{5644800, 44100, 0xC, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+
+	{6000000,  8000, 0x1, 0, CS53L30_MCLK_INT_SCALE},
+	{6000000, 11025, 0x2, 0, CS53L30_MCLK_INT_SCALE},
+	{6000000, 12000, 0x4, 0, CS53L30_MCLK_INT_SCALE},
+	{6000000, 16000, 0x5, 0, CS53L30_MCLK_INT_SCALE},
+	{6000000, 22050, 0x6, 0, CS53L30_MCLK_INT_SCALE},
+	{6000000, 24000, 0x8, 0, CS53L30_MCLK_INT_SCALE},
+	{6000000, 32000, 0x9, 0, CS53L30_MCLK_INT_SCALE},
+	{6000000, 44100, 0xA, 0, CS53L30_MCLK_INT_SCALE},
+	{6000000, 48000, 0xC, 0, CS53L30_MCLK_INT_SCALE},
+
+	{6144000,  8000, 0x1, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6144000, 11025, 0x2, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6144000, 12000, 0x4, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6144000, 16000, 0x5, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6144000, 22050, 0x6, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6144000, 24000, 0x8, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6144000, 32000, 0x9, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6144000, 44100, 0xA, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6144000, 48000, 0xC, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+
+	{6400000,  8000, 0x1, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6400000, 11025, 0x2, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6400000, 12000, 0x4, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6400000, 16000, 0x5, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6400000, 22050, 0x6, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6400000, 24000, 0x8, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6400000, 32000, 0x9, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6400000, 44100, 0xA, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+	{6400000, 48000, 0xC, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE},
+};
+
+struct cs53l30_mclkx_div {
+	u32 mclkx;
+	u8 ratio;
+	u8 mclkdiv;
+};
+
+static const struct cs53l30_mclkx_div cs53l30_mclkx_coeffs[] = {
+	{5644800,  1, CS53L30_MCLK_DIV_BY_1},
+	{6000000,  1, CS53L30_MCLK_DIV_BY_1},
+	{6144000,  1, CS53L30_MCLK_DIV_BY_1},
+	{11289600, 2, CS53L30_MCLK_DIV_BY_2},
+	{12288000, 2, CS53L30_MCLK_DIV_BY_2},
+	{12000000, 2, CS53L30_MCLK_DIV_BY_2},
+	{19200000, 3, CS53L30_MCLK_DIV_BY_3},
+};
+
+static int cs53l30_get_mclkx_coeff(int mclkx)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cs53l30_mclkx_coeffs); i++) {
+		if (cs53l30_mclkx_coeffs[i].mclkx == mclkx)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static int cs53l30_get_mclk_coeff(int mclk_rate, int srate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cs53l30_mclk_coeffs); i++) {
+		if (cs53l30_mclk_coeffs[i].mclk_rate == mclk_rate &&
+		    cs53l30_mclk_coeffs[i].srate == srate)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static int cs53l30_set_sysclk(struct snd_soc_dai *dai,
+			      int clk_id, unsigned int freq, int dir)
+{
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(dai->component);
+	int mclkx_coeff;
+	u32 mclk_rate;
+
+	/* MCLKX -> MCLK */
+	mclkx_coeff = cs53l30_get_mclkx_coeff(freq);
+	if (mclkx_coeff < 0)
+		return mclkx_coeff;
+
+	mclk_rate = cs53l30_mclkx_coeffs[mclkx_coeff].mclkx /
+		    cs53l30_mclkx_coeffs[mclkx_coeff].ratio;
+
+	regmap_update_bits(priv->regmap, CS53L30_MCLKCTL,
+			   CS53L30_MCLK_DIV_MASK,
+			   cs53l30_mclkx_coeffs[mclkx_coeff].mclkdiv);
+
+	priv->mclk_rate = mclk_rate;
+
+	return 0;
+}
+
+static int cs53l30_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(dai->component);
+	u8 aspcfg = 0, aspctl1 = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aspcfg |= CS53L30_ASP_MS;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* DAI mode */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		/* Set TDM_PDN to turn off TDM mode -- Reset default */
+		aspctl1 |= CS53L30_ASP_TDM_PDN;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		/*
+		 * Clear TDM_PDN to turn on TDM mode; Use ASP_SCLK_INV = 0
+		 * with SHIFT_LEFT = 1 combination as Figure 4-13 shows in
+		 * the CS53L30 datasheet
+		 */
+		aspctl1 |= CS53L30_SHIFT_LEFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Check to see if the SCLK is inverted */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_NF:
+	case SND_SOC_DAIFMT_IB_IF:
+		aspcfg ^= CS53L30_ASP_SCLK_INV;
+		break;
+	default:
+		break;
+	}
+
+	regmap_update_bits(priv->regmap, CS53L30_ASPCFG_CTL,
+			   CS53L30_ASP_MS | CS53L30_ASP_SCLK_INV, aspcfg);
+
+	regmap_update_bits(priv->regmap, CS53L30_ASP_CTL1,
+			   CS53L30_ASP_TDM_PDN | CS53L30_SHIFT_LEFT, aspctl1);
+
+	return 0;
+}
+
+static int cs53l30_pcm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(dai->component);
+	int srate = params_rate(params);
+	int mclk_coeff;
+
+	/* MCLK -> srate */
+	mclk_coeff = cs53l30_get_mclk_coeff(priv->mclk_rate, srate);
+	if (mclk_coeff < 0)
+		return -EINVAL;
+
+	regmap_update_bits(priv->regmap, CS53L30_INT_SR_CTL,
+			   CS53L30_INTRNL_FS_RATIO_MASK,
+			   cs53l30_mclk_coeffs[mclk_coeff].internal_fs_ratio);
+
+	regmap_update_bits(priv->regmap, CS53L30_MCLKCTL,
+			   CS53L30_MCLK_INT_SCALE_MASK,
+			   cs53l30_mclk_coeffs[mclk_coeff].mclk_int_scale);
+
+	regmap_update_bits(priv->regmap, CS53L30_ASPCFG_CTL,
+			   CS53L30_ASP_RATE_MASK,
+			   cs53l30_mclk_coeffs[mclk_coeff].asp_rate);
+
+	return 0;
+}
+
+static int cs53l30_set_bias_level(struct snd_soc_component *component,
+				  enum snd_soc_bias_level level)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(component);
+	unsigned int reg;
+	int i, inter_max_check, ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
+			regmap_update_bits(priv->regmap, CS53L30_PWRCTL,
+					   CS53L30_PDN_LP_MASK, 0);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (dapm->bias_level == SND_SOC_BIAS_OFF) {
+			ret = clk_prepare_enable(priv->mclk);
+			if (ret) {
+				dev_err(component->dev,
+					"failed to enable MCLK: %d\n", ret);
+				return ret;
+			}
+			regmap_update_bits(priv->regmap, CS53L30_MCLKCTL,
+					   CS53L30_MCLK_DIS_MASK, 0);
+			regmap_update_bits(priv->regmap, CS53L30_PWRCTL,
+					   CS53L30_PDN_ULP_MASK, 0);
+			msleep(50);
+		} else {
+			regmap_update_bits(priv->regmap, CS53L30_PWRCTL,
+					   CS53L30_PDN_ULP_MASK,
+					   CS53L30_PDN_ULP);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		regmap_update_bits(priv->regmap, CS53L30_INT_MASK,
+				   CS53L30_PDN_DONE, 0);
+		/*
+		 * If digital softramp is set, the amount of time required
+		 * for power down increases and depends on the digital
+		 * volume setting.
+		 */
+
+		/* Set the max possible time if digsft is set */
+		regmap_read(priv->regmap, CS53L30_SFT_RAMP, &reg);
+		if (reg & CS53L30_DIGSFT_MASK)
+			inter_max_check = CS53L30_PDN_POLL_MAX;
+		else
+			inter_max_check = 10;
+
+		regmap_update_bits(priv->regmap, CS53L30_PWRCTL,
+				   CS53L30_PDN_ULP_MASK,
+				   CS53L30_PDN_ULP);
+		/* PDN_DONE will take a min of 20ms to be set.*/
+		msleep(20);
+		/* Clr status */
+		regmap_read(priv->regmap, CS53L30_IS, &reg);
+		for (i = 0; i < inter_max_check; i++) {
+			if (inter_max_check < 10) {
+				usleep_range(1000, 1100);
+				regmap_read(priv->regmap, CS53L30_IS, &reg);
+				if (reg & CS53L30_PDN_DONE)
+					break;
+			} else {
+				usleep_range(10000, 10100);
+				regmap_read(priv->regmap, CS53L30_IS, &reg);
+				if (reg & CS53L30_PDN_DONE)
+					break;
+			}
+		}
+		/* PDN_DONE is set. We now can disable the MCLK */
+		regmap_update_bits(priv->regmap, CS53L30_INT_MASK,
+				   CS53L30_PDN_DONE, CS53L30_PDN_DONE);
+		regmap_update_bits(priv->regmap, CS53L30_MCLKCTL,
+				   CS53L30_MCLK_DIS_MASK,
+				   CS53L30_MCLK_DIS);
+		clk_disable_unprepare(priv->mclk);
+		break;
+	}
+
+	return 0;
+}
+
+static int cs53l30_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(dai->component);
+	u8 val = tristate ? CS53L30_ASP_3ST : 0;
+
+	return regmap_update_bits(priv->regmap, CS53L30_ASP_CTL1,
+				  CS53L30_ASP_3ST_MASK, val);
+}
+
+static unsigned int const cs53l30_src_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static const struct snd_pcm_hw_constraint_list src_constraints = {
+	.count = ARRAY_SIZE(cs53l30_src_rates),
+	.list = cs53l30_src_rates,
+};
+
+static int cs53l30_pcm_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+				   SNDRV_PCM_HW_PARAM_RATE, &src_constraints);
+
+	return 0;
+}
+
+/*
+ * Note: CS53L30 counts the slot number per byte while ASoC counts the slot
+ * number per slot_width. So there is a difference between the slots of ASoC
+ * and the slots of CS53L30.
+ */
+static int cs53l30_set_dai_tdm_slot(struct snd_soc_dai *dai,
+				    unsigned int tx_mask, unsigned int rx_mask,
+				    int slots, int slot_width)
+{
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(dai->component);
+	unsigned int loc[CS53L30_TDM_SLOT_MAX] = {48, 48, 48, 48};
+	unsigned int slot_next, slot_step;
+	u64 tx_enable = 0;
+	int i;
+
+	if (!rx_mask) {
+		dev_err(dai->dev, "rx masks must not be 0\n");
+		return -EINVAL;
+	}
+
+	/* Assuming slot_width is not supposed to be greater than 64 */
+	if (slots <= 0 || slot_width <= 0 || slot_width > 64) {
+		dev_err(dai->dev, "invalid slot number or slot width\n");
+		return -EINVAL;
+	}
+
+	if (slot_width & 0x7) {
+		dev_err(dai->dev, "slot width must count in byte\n");
+		return -EINVAL;
+	}
+
+	/* How many bytes in each ASoC slot */
+	slot_step = slot_width >> 3;
+
+	for (i = 0; rx_mask && i < CS53L30_TDM_SLOT_MAX; i++) {
+		/* Find the first slot from LSB */
+		slot_next = __ffs(rx_mask);
+		/* Save the slot location by converting to CS53L30 slot */
+		loc[i] = slot_next * slot_step;
+		/* Create the mask of CS53L30 slot */
+		tx_enable |= (u64)((u64)(1 << slot_step) - 1) << (u64)loc[i];
+		/* Clear this slot from rx_mask */
+		rx_mask &= ~(1 << slot_next);
+	}
+
+	/* Error out to avoid slot shift */
+	if (rx_mask && i == CS53L30_TDM_SLOT_MAX) {
+		dev_err(dai->dev, "rx_mask exceeds max slot number: %d\n",
+			CS53L30_TDM_SLOT_MAX);
+		return -EINVAL;
+	}
+
+	/* Validate the last active CS53L30 slot */
+	slot_next = loc[i - 1] + slot_step - 1;
+	if (slot_next > 47) {
+		dev_err(dai->dev, "slot selection out of bounds: %u\n",
+			slot_next);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < CS53L30_TDM_SLOT_MAX && loc[i] != 48; i++) {
+		regmap_update_bits(priv->regmap, CS53L30_ASP_TDMTX_CTL(i),
+				   CS53L30_ASP_CHx_TX_LOC_MASK, loc[i]);
+		dev_dbg(dai->dev, "loc[%d]=%x\n", i, loc[i]);
+	}
+
+	for (i = 0; i < CS53L30_ASP_TDMTX_ENx_MAX && tx_enable; i++) {
+		regmap_write(priv->regmap, CS53L30_ASP_TDMTX_ENx(i),
+			     tx_enable & 0xff);
+		tx_enable >>= 8;
+		dev_dbg(dai->dev, "en_reg=%x, tx_enable=%llx\n",
+			CS53L30_ASP_TDMTX_ENx(i), tx_enable & 0xff);
+	}
+
+	return 0;
+}
+
+static int cs53l30_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(dai->component);
+
+	gpiod_set_value_cansleep(priv->mute_gpio, mute);
+
+	return 0;
+}
+
+/* SNDRV_PCM_RATE_KNOT -> 12000, 24000 Hz, limit with constraint list */
+#define CS53L30_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
+
+#define CS53L30_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops cs53l30_ops = {
+	.startup = cs53l30_pcm_startup,
+	.hw_params = cs53l30_pcm_hw_params,
+	.set_fmt = cs53l30_set_dai_fmt,
+	.set_sysclk = cs53l30_set_sysclk,
+	.set_tristate = cs53l30_set_tristate,
+	.set_tdm_slot = cs53l30_set_dai_tdm_slot,
+	.mute_stream = cs53l30_mute_stream,
+};
+
+static struct snd_soc_dai_driver cs53l30_dai = {
+	.name = "cs53l30",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 4,
+		.rates = CS53L30_RATES,
+		.formats = CS53L30_FORMATS,
+	},
+	.ops = &cs53l30_ops,
+	.symmetric_rates = 1,
+};
+
+static int cs53l30_component_probe(struct snd_soc_component *component)
+{
+	struct cs53l30_private *priv = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	if (priv->use_sdout2)
+		snd_soc_dapm_add_routes(dapm, cs53l30_dapm_routes_sdout2,
+					ARRAY_SIZE(cs53l30_dapm_routes_sdout2));
+	else
+		snd_soc_dapm_add_routes(dapm, cs53l30_dapm_routes_sdout1,
+					ARRAY_SIZE(cs53l30_dapm_routes_sdout1));
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver cs53l30_driver = {
+	.probe			= cs53l30_component_probe,
+	.set_bias_level		= cs53l30_set_bias_level,
+	.controls		= cs53l30_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs53l30_snd_controls),
+	.dapm_widgets		= cs53l30_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs53l30_dapm_widgets),
+	.dapm_routes		= cs53l30_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs53l30_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static struct regmap_config cs53l30_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = CS53L30_MAX_REGISTER,
+	.reg_defaults = cs53l30_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(cs53l30_reg_defaults),
+	.volatile_reg = cs53l30_volatile_register,
+	.writeable_reg = cs53l30_writeable_register,
+	.readable_reg = cs53l30_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int cs53l30_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	const struct device_node *np = client->dev.of_node;
+	struct device *dev = &client->dev;
+	struct cs53l30_private *cs53l30;
+	unsigned int devid = 0;
+	unsigned int reg;
+	int ret = 0, i;
+	u8 val;
+
+	cs53l30 = devm_kzalloc(dev, sizeof(*cs53l30), GFP_KERNEL);
+	if (!cs53l30)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(cs53l30->supplies); i++)
+		cs53l30->supplies[i].supply = cs53l30_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs53l30->supplies),
+				      cs53l30->supplies);
+	if (ret) {
+		dev_err(dev, "failed to get supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs53l30->supplies),
+				    cs53l30->supplies);
+	if (ret) {
+		dev_err(dev, "failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	/* Reset the Device */
+	cs53l30->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						      GPIOD_OUT_LOW);
+	if (IS_ERR(cs53l30->reset_gpio)) {
+		ret = PTR_ERR(cs53l30->reset_gpio);
+		goto error;
+	}
+
+	gpiod_set_value_cansleep(cs53l30->reset_gpio, 1);
+
+	i2c_set_clientdata(client, cs53l30);
+
+	cs53l30->mclk_rate = 0;
+
+	cs53l30->regmap = devm_regmap_init_i2c(client, &cs53l30_regmap);
+	if (IS_ERR(cs53l30->regmap)) {
+		ret = PTR_ERR(cs53l30->regmap);
+		dev_err(dev, "regmap_init() failed: %d\n", ret);
+		goto error;
+	}
+
+	/* Initialize codec */
+	ret = regmap_read(cs53l30->regmap, CS53L30_DEVID_AB, &reg);
+	devid = reg << 12;
+
+	ret = regmap_read(cs53l30->regmap, CS53L30_DEVID_CD, &reg);
+	devid |= reg << 4;
+
+	ret = regmap_read(cs53l30->regmap, CS53L30_DEVID_E, &reg);
+	devid |= (reg & 0xF0) >> 4;
+
+	if (devid != CS53L30_DEVID) {
+		ret = -ENODEV;
+		dev_err(dev, "Device ID (%X). Expected %X\n",
+			devid, CS53L30_DEVID);
+		goto error;
+	}
+
+	ret = regmap_read(cs53l30->regmap, CS53L30_REVID, &reg);
+	if (ret < 0) {
+		dev_err(dev, "failed to get Revision ID: %d\n", ret);
+		goto error;
+	}
+
+	/* Check if MCLK provided */
+	cs53l30->mclk = devm_clk_get(dev, "mclk");
+	if (IS_ERR(cs53l30->mclk)) {
+		if (PTR_ERR(cs53l30->mclk) != -ENOENT) {
+			ret = PTR_ERR(cs53l30->mclk);
+			goto error;
+		}
+		/* Otherwise mark the mclk pointer to NULL */
+		cs53l30->mclk = NULL;
+	}
+
+	/* Fetch the MUTE control */
+	cs53l30->mute_gpio = devm_gpiod_get_optional(dev, "mute",
+						     GPIOD_OUT_HIGH);
+	if (IS_ERR(cs53l30->mute_gpio)) {
+		ret = PTR_ERR(cs53l30->mute_gpio);
+		goto error;
+	}
+
+	if (cs53l30->mute_gpio) {
+		/* Enable MUTE controls via MUTE pin */
+		regmap_write(cs53l30->regmap, CS53L30_MUTEP_CTL1,
+			     CS53L30_MUTEP_CTL1_MUTEALL);
+		/* Flip the polarity of MUTE pin */
+		if (gpiod_is_active_low(cs53l30->mute_gpio))
+			regmap_update_bits(cs53l30->regmap, CS53L30_MUTEP_CTL2,
+					   CS53L30_MUTE_PIN_POLARITY, 0);
+	}
+
+	if (!of_property_read_u8(np, "cirrus,micbias-lvl", &val))
+		regmap_update_bits(cs53l30->regmap, CS53L30_MICBIAS_CTL,
+				   CS53L30_MIC_BIAS_CTRL_MASK, val);
+
+	if (of_property_read_bool(np, "cirrus,use-sdout2"))
+		cs53l30->use_sdout2 = true;
+
+	dev_info(dev, "Cirrus Logic CS53L30, Revision: %02X\n", reg & 0xFF);
+
+	ret = devm_snd_soc_register_component(dev, &cs53l30_driver, &cs53l30_dai, 1);
+	if (ret) {
+		dev_err(dev, "failed to register component: %d\n", ret);
+		goto error;
+	}
+
+	return 0;
+
+error:
+	regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies),
+			       cs53l30->supplies);
+	return ret;
+}
+
+static int cs53l30_i2c_remove(struct i2c_client *client)
+{
+	struct cs53l30_private *cs53l30 = i2c_get_clientdata(client);
+
+	/* Hold down reset */
+	gpiod_set_value_cansleep(cs53l30->reset_gpio, 0);
+
+	regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies),
+			       cs53l30->supplies);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int cs53l30_runtime_suspend(struct device *dev)
+{
+	struct cs53l30_private *cs53l30 = dev_get_drvdata(dev);
+
+	regcache_cache_only(cs53l30->regmap, true);
+
+	/* Hold down reset */
+	gpiod_set_value_cansleep(cs53l30->reset_gpio, 0);
+
+	regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies),
+			       cs53l30->supplies);
+
+	return 0;
+}
+
+static int cs53l30_runtime_resume(struct device *dev)
+{
+	struct cs53l30_private *cs53l30 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(cs53l30->supplies),
+				    cs53l30->supplies);
+	if (ret) {
+		dev_err(dev, "failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	gpiod_set_value_cansleep(cs53l30->reset_gpio, 1);
+
+	regcache_cache_only(cs53l30->regmap, false);
+	ret = regcache_sync(cs53l30->regmap);
+	if (ret) {
+		dev_err(dev, "failed to synchronize regcache: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops cs53l30_runtime_pm = {
+	SET_RUNTIME_PM_OPS(cs53l30_runtime_suspend, cs53l30_runtime_resume,
+			   NULL)
+};
+
+static const struct of_device_id cs53l30_of_match[] = {
+	{ .compatible = "cirrus,cs53l30", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, cs53l30_of_match);
+
+static const struct i2c_device_id cs53l30_id[] = {
+	{ "cs53l30", 0 },
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs53l30_id);
+
+static struct i2c_driver cs53l30_i2c_driver = {
+	.driver = {
+		.name = "cs53l30",
+		.of_match_table = cs53l30_of_match,
+		.pm = &cs53l30_runtime_pm,
+	},
+	.id_table = cs53l30_id,
+	.probe = cs53l30_i2c_probe,
+	.remove = cs53l30_i2c_remove,
+};
+
+module_i2c_driver(cs53l30_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS53L30 driver");
+MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <Paul.Handrigan@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs53l30.h b/sound/soc/codecs/cs53l30.h
new file mode 100644
index 0000000..5e39da5
--- /dev/null
+++ b/sound/soc/codecs/cs53l30.h
@@ -0,0 +1,459 @@
+/*
+ * ALSA SoC CS53L30 codec driver
+ *
+ * Copyright 2015 Cirrus Logic, Inc.
+ *
+ * Author: Paul Handrigan <Paul.Handrigan@cirrus.com>,
+ *         Tim Howe <Tim.Howe@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CS53L30_H__
+#define __CS53L30_H__
+
+/* I2C Registers */
+#define CS53L30_DEVID_AB	0x01	 /* Device ID A & B [RO]. */
+#define CS53L30_DEVID_CD	0x02     /* Device ID C & D [RO]. */
+#define CS53L30_DEVID_E		0x03     /* Device ID E [RO]. */
+#define CS53L30_REVID		0x05     /* Revision ID [RO]. */
+#define CS53L30_PWRCTL		0x06     /* Power Control. */
+#define CS53L30_MCLKCTL		0x07     /* MCLK Control. */
+#define CS53L30_INT_SR_CTL	0x08     /* Internal Sample Rate Control. */
+#define CS53L30_MICBIAS_CTL	0x0A     /* Mic Bias Control. */
+#define CS53L30_ASPCFG_CTL	0x0C     /* ASP Config Control. */
+#define CS53L30_ASP_CTL1	0x0D     /* ASP1 Control. */
+#define CS53L30_ASP_TDMTX_CTL1	0x0E     /* ASP1 TDM TX Control 1 */
+#define CS53L30_ASP_TDMTX_CTL2	0x0F     /* ASP1 TDM TX Control 2 */
+#define CS53L30_ASP_TDMTX_CTL3	0x10     /* ASP1 TDM TX Control 3 */
+#define CS53L30_ASP_TDMTX_CTL4	0x11     /* ASP1 TDM TX Control 4 */
+#define CS53L30_ASP_TDMTX_EN1	0x12     /* ASP1 TDM TX Enable 1 */
+#define CS53L30_ASP_TDMTX_EN2	0x13     /* ASP1 TDM TX Enable 2 */
+#define CS53L30_ASP_TDMTX_EN3	0x14     /* ASP1 TDM TX Enable 3 */
+#define CS53L30_ASP_TDMTX_EN4	0x15     /* ASP1 TDM TX Enable 4 */
+#define CS53L30_ASP_TDMTX_EN5	0x16     /* ASP1 TDM TX Enable 5 */
+#define CS53L30_ASP_TDMTX_EN6	0x17     /* ASP1 TDM TX Enable 6 */
+#define CS53L30_ASP_CTL2	0x18     /* ASP2 Control. */
+#define CS53L30_SFT_RAMP	0x1A     /* Soft Ramp Control. */
+#define CS53L30_LRCK_CTL1	0x1B     /* LRCK Control 1. */
+#define CS53L30_LRCK_CTL2	0x1C     /* LRCK Control 2. */
+#define CS53L30_MUTEP_CTL1	0x1F     /* Mute Pin Control 1. */
+#define CS53L30_MUTEP_CTL2	0x20     /* Mute Pin Control 2. */
+#define CS53L30_INBIAS_CTL1	0x21     /* Input Bias Control 1. */
+#define CS53L30_INBIAS_CTL2	0x22     /* Input Bias Control 2. */
+#define CS53L30_DMIC1_STR_CTL   0x23     /* DMIC1 Stereo Control. */
+#define CS53L30_DMIC2_STR_CTL   0x24     /* DMIC2 Stereo Control. */
+#define CS53L30_ADCDMIC1_CTL1   0x25     /* ADC1/DMIC1 Control 1. */
+#define CS53L30_ADCDMIC1_CTL2   0x26     /* ADC1/DMIC1 Control 2. */
+#define CS53L30_ADC1_CTL3	0x27     /* ADC1 Control 3. */
+#define CS53L30_ADC1_NG_CTL	0x28     /* ADC1 Noise Gate Control. */
+#define CS53L30_ADC1A_AFE_CTL	0x29     /* ADC1A AFE Control. */
+#define CS53L30_ADC1B_AFE_CTL	0x2A     /* ADC1B AFE Control. */
+#define CS53L30_ADC1A_DIG_VOL	0x2B     /* ADC1A Digital Volume. */
+#define CS53L30_ADC1B_DIG_VOL	0x2C     /* ADC1B Digital Volume. */
+#define CS53L30_ADCDMIC2_CTL1   0x2D     /* ADC2/DMIC2 Control 1. */
+#define CS53L30_ADCDMIC2_CTL2   0x2E     /* ADC2/DMIC2 Control 2. */
+#define CS53L30_ADC2_CTL3	0x2F     /* ADC2 Control 3. */
+#define CS53L30_ADC2_NG_CTL	0x30     /* ADC2 Noise Gate Control. */
+#define CS53L30_ADC2A_AFE_CTL	0x31     /* ADC2A AFE Control. */
+#define CS53L30_ADC2B_AFE_CTL	0x32     /* ADC2B AFE Control. */
+#define CS53L30_ADC2A_DIG_VOL	0x33     /* ADC2A Digital Volume. */
+#define CS53L30_ADC2B_DIG_VOL	0x34     /* ADC2B Digital Volume. */
+#define CS53L30_INT_MASK	0x35     /* Interrupt Mask. */
+#define CS53L30_IS		0x36     /* Interrupt Status. */
+#define CS53L30_MAX_REGISTER	0x36
+
+#define CS53L30_TDM_SLOT_MAX		4
+#define CS53L30_ASP_TDMTX_CTL(x)	(CS53L30_ASP_TDMTX_CTL1 + (x))
+/* x : index for registers; n : index for slot; 8 slots per register */
+#define CS53L30_ASP_TDMTX_ENx(x)	(CS53L30_ASP_TDMTX_EN6 - (x))
+#define CS53L30_ASP_TDMTX_ENn(n)	CS53L30_ASP_TDMTX_ENx((n) >> 3)
+#define CS53L30_ASP_TDMTX_ENx_MAX	6
+
+/* Device ID */
+#define CS53L30_DEVID		0x53A30
+
+/* PDN_DONE Poll Maximum
+ * If soft ramp is set it will take much longer to power down
+ * the system.
+ */
+#define CS53L30_PDN_POLL_MAX	90
+
+/* Bitfield Definitions */
+
+/* R6 (0x06) CS53L30_PWRCTL - Power Control */
+#define CS53L30_PDN_ULP_SHIFT		7
+#define CS53L30_PDN_ULP_MASK		(1 << CS53L30_PDN_ULP_SHIFT)
+#define CS53L30_PDN_ULP			(1 << CS53L30_PDN_ULP_SHIFT)
+#define CS53L30_PDN_LP_SHIFT		6
+#define CS53L30_PDN_LP_MASK		(1 << CS53L30_PDN_LP_SHIFT)
+#define CS53L30_PDN_LP			(1 << CS53L30_PDN_LP_SHIFT)
+#define CS53L30_DISCHARGE_FILT_SHIFT	5
+#define CS53L30_DISCHARGE_FILT_MASK	(1 << CS53L30_DISCHARGE_FILT_SHIFT)
+#define CS53L30_DISCHARGE_FILT		(1 << CS53L30_DISCHARGE_FILT_SHIFT)
+#define CS53L30_THMS_PDN_SHIFT		4
+#define CS53L30_THMS_PDN_MASK		(1 << CS53L30_THMS_PDN_SHIFT)
+#define CS53L30_THMS_PDN		(1 << CS53L30_THMS_PDN_SHIFT)
+
+#define CS53L30_PWRCTL_DEFAULT		(CS53L30_THMS_PDN)
+
+/* R7 (0x07) CS53L30_MCLKCTL - MCLK Control */
+#define CS53L30_MCLK_DIS_SHIFT		7
+#define CS53L30_MCLK_DIS_MASK		(1 << CS53L30_MCLK_DIS_SHIFT)
+#define CS53L30_MCLK_DIS		(1 << CS53L30_MCLK_DIS_SHIFT)
+#define CS53L30_MCLK_INT_SCALE_SHIFT	6
+#define CS53L30_MCLK_INT_SCALE_MASK	(1 << CS53L30_MCLK_INT_SCALE_SHIFT)
+#define CS53L30_MCLK_INT_SCALE		(1 << CS53L30_MCLK_INT_SCALE_SHIFT)
+#define CS53L30_DMIC_DRIVE_SHIFT	5
+#define CS53L30_DMIC_DRIVE_MASK		(1 << CS53L30_DMIC_DRIVE_SHIFT)
+#define CS53L30_DMIC_DRIVE		(1 << CS53L30_DMIC_DRIVE_SHIFT)
+#define CS53L30_MCLK_DIV_SHIFT		2
+#define CS53L30_MCLK_DIV_WIDTH		2
+#define CS53L30_MCLK_DIV_MASK		(((1 << CS53L30_MCLK_DIV_WIDTH) - 1) << CS53L30_MCLK_DIV_SHIFT)
+#define CS53L30_MCLK_DIV_BY_1		(0x0 << CS53L30_MCLK_DIV_SHIFT)
+#define CS53L30_MCLK_DIV_BY_2		(0x1 << CS53L30_MCLK_DIV_SHIFT)
+#define CS53L30_MCLK_DIV_BY_3		(0x2 << CS53L30_MCLK_DIV_SHIFT)
+#define CS53L30_SYNC_EN_SHIFT		1
+#define CS53L30_SYNC_EN_MASK		(1 << CS53L30_SYNC_EN_SHIFT)
+#define CS53L30_SYNC_EN			(1 << CS53L30_SYNC_EN_SHIFT)
+
+#define CS53L30_MCLKCTL_DEFAULT		(CS53L30_MCLK_DIV_BY_2)
+
+/* R8 (0x08) CS53L30_INT_SR_CTL - Internal Sample Rate Control */
+#define CS53L30_INTRNL_FS_RATIO_SHIFT	4
+#define CS53L30_INTRNL_FS_RATIO_MASK	(1 << CS53L30_INTRNL_FS_RATIO_SHIFT)
+#define CS53L30_INTRNL_FS_RATIO		(1 << CS53L30_INTRNL_FS_RATIO_SHIFT)
+#define CS53L30_MCLK_19MHZ_EN_SHIFT	0
+#define CS53L30_MCLK_19MHZ_EN_MASK	(1 << CS53L30_MCLK_19MHZ_EN_SHIFT)
+#define CS53L30_MCLK_19MHZ_EN		(1 << CS53L30_MCLK_19MHZ_EN_SHIFT)
+
+/* 0x6 << 1 is reserved bits */
+#define CS53L30_INT_SR_CTL_DEFAULT	(CS53L30_INTRNL_FS_RATIO | 0x6 << 1)
+
+/* R10 (0x0A) CS53L30_MICBIAS_CTL - Mic Bias Control */
+#define CS53L30_MIC4_BIAS_PDN_SHIFT	7
+#define CS53L30_MIC4_BIAS_PDN_MASK	(1 << CS53L30_MIC4_BIAS_PDN_SHIFT)
+#define CS53L30_MIC4_BIAS_PDN		(1 << CS53L30_MIC4_BIAS_PDN_SHIFT)
+#define CS53L30_MIC3_BIAS_PDN_SHIFT	6
+#define CS53L30_MIC3_BIAS_PDN_MASK	(1 << CS53L30_MIC3_BIAS_PDN_SHIFT)
+#define CS53L30_MIC3_BIAS_PDN		(1 << CS53L30_MIC3_BIAS_PDN_SHIFT)
+#define CS53L30_MIC2_BIAS_PDN_SHIFT	5
+#define CS53L30_MIC2_BIAS_PDN_MASK	(1 << CS53L30_MIC2_BIAS_PDN_SHIFT)
+#define CS53L30_MIC2_BIAS_PDN		(1 << CS53L30_MIC2_BIAS_PDN_SHIFT)
+#define CS53L30_MIC1_BIAS_PDN_SHIFT	4
+#define CS53L30_MIC1_BIAS_PDN_MASK	(1 << CS53L30_MIC1_BIAS_PDN_SHIFT)
+#define CS53L30_MIC1_BIAS_PDN		(1 << CS53L30_MIC1_BIAS_PDN_SHIFT)
+#define CS53L30_MICx_BIAS_PDN		(0xf << CS53L30_MIC1_BIAS_PDN_SHIFT)
+#define CS53L30_VP_MIN_SHIFT		2
+#define CS53L30_VP_MIN_MASK		(1 << CS53L30_VP_MIN_SHIFT)
+#define CS53L30_VP_MIN			(1 << CS53L30_VP_MIN_SHIFT)
+#define CS53L30_MIC_BIAS_CTRL_SHIFT	0
+#define CS53L30_MIC_BIAS_CTRL_WIDTH	2
+#define CS53L30_MIC_BIAS_CTRL_MASK	(((1 << CS53L30_MIC_BIAS_CTRL_WIDTH) - 1) << CS53L30_MIC_BIAS_CTRL_SHIFT)
+#define CS53L30_MIC_BIAS_CTRL_HIZ	(0 << CS53L30_MIC_BIAS_CTRL_SHIFT)
+#define CS53L30_MIC_BIAS_CTRL_1V8	(1 << CS53L30_MIC_BIAS_CTRL_SHIFT)
+#define CS53L30_MIC_BIAS_CTRL_2V75	(2 << CS53L30_MIC_BIAS_CTRL_SHIFT)
+
+#define CS53L30_MICBIAS_CTL_DEFAULT	(CS53L30_MICx_BIAS_PDN | CS53L30_VP_MIN)
+
+/* R12 (0x0C) CS53L30_ASPCFG_CTL - ASP Configuration Control */
+#define CS53L30_ASP_MS_SHIFT		7
+#define CS53L30_ASP_MS_MASK		(1 << CS53L30_ASP_MS_SHIFT)
+#define CS53L30_ASP_MS			(1 << CS53L30_ASP_MS_SHIFT)
+#define CS53L30_ASP_SCLK_INV_SHIFT	4
+#define CS53L30_ASP_SCLK_INV_MASK	(1 << CS53L30_ASP_SCLK_INV_SHIFT)
+#define CS53L30_ASP_SCLK_INV		(1 << CS53L30_ASP_SCLK_INV_SHIFT)
+#define CS53L30_ASP_RATE_SHIFT		0
+#define CS53L30_ASP_RATE_WIDTH		4
+#define CS53L30_ASP_RATE_MASK		(((1 << CS53L30_ASP_RATE_WIDTH) - 1) << CS53L30_ASP_RATE_SHIFT)
+#define CS53L30_ASP_RATE_48K		(0xc << CS53L30_ASP_RATE_SHIFT)
+
+#define CS53L30_ASPCFG_CTL_DEFAULT	(CS53L30_ASP_RATE_48K)
+
+/* R13/R24 (0x0D/0x18) CS53L30_ASP_CTL1 & CS53L30_ASP_CTL2 - ASP Control 1~2 */
+#define CS53L30_ASP_TDM_PDN_SHIFT	7
+#define CS53L30_ASP_TDM_PDN_MASK	(1 << CS53L30_ASP_TDM_PDN_SHIFT)
+#define CS53L30_ASP_TDM_PDN		(1 << CS53L30_ASP_TDM_PDN_SHIFT)
+#define CS53L30_ASP_SDOUTx_PDN_SHIFT	6
+#define CS53L30_ASP_SDOUTx_PDN_MASK	(1 << CS53L30_ASP_SDOUTx_PDN_SHIFT)
+#define CS53L30_ASP_SDOUTx_PDN		(1 << CS53L30_ASP_SDOUTx_PDN_SHIFT)
+#define CS53L30_ASP_3ST_SHIFT		5
+#define CS53L30_ASP_3ST_MASK		(1 << CS53L30_ASP_3ST_SHIFT)
+#define CS53L30_ASP_3ST			(1 << CS53L30_ASP_3ST_SHIFT)
+#define CS53L30_SHIFT_LEFT_SHIFT	4
+#define CS53L30_SHIFT_LEFT_MASK		(1 << CS53L30_SHIFT_LEFT_SHIFT)
+#define CS53L30_SHIFT_LEFT		(1 << CS53L30_SHIFT_LEFT_SHIFT)
+#define CS53L30_ASP_SDOUTx_DRIVE_SHIFT	0
+#define CS53L30_ASP_SDOUTx_DRIVE_MASK	(1 << CS53L30_ASP_SDOUTx_DRIVE_SHIFT)
+#define CS53L30_ASP_SDOUTx_DRIVE	(1 << CS53L30_ASP_SDOUTx_DRIVE_SHIFT)
+
+#define CS53L30_ASP_CTL1_DEFAULT	(CS53L30_ASP_TDM_PDN)
+#define CS53L30_ASP_CTL2_DEFAULT	(0)
+
+/* R14 (0x0E) ~ R17 (0x11) CS53L30_ASP_TDMTX_CTLx - ASP TDM TX Control 1~4 */
+#define CS53L30_ASP_CHx_TX_STATE_SHIFT	7
+#define CS53L30_ASP_CHx_TX_STATE_MASK	(1 << CS53L30_ASP_CHx_TX_STATE_SHIFT)
+#define CS53L30_ASP_CHx_TX_STATE	(1 << CS53L30_ASP_CHx_TX_STATE_SHIFT)
+#define CS53L30_ASP_CHx_TX_LOC_SHIFT	0
+#define CS53L30_ASP_CHx_TX_LOC_WIDTH	6
+#define CS53L30_ASP_CHx_TX_LOC_MASK	(((1 << CS53L30_ASP_CHx_TX_LOC_WIDTH) - 1) << CS53L30_ASP_CHx_TX_LOC_SHIFT)
+#define CS53L30_ASP_CHx_TX_LOC_MAX	(47 << CS53L30_ASP_CHx_TX_LOC_SHIFT)
+#define CS53L30_ASP_CHx_TX_LOC(x)	((x) << CS53L30_ASP_CHx_TX_LOC_SHIFT)
+
+#define CS53L30_ASP_TDMTX_CTLx_DEFAULT	(CS53L30_ASP_CHx_TX_LOC_MAX)
+
+/* R18 (0x12) ~ R23 (0x17) CS53L30_ASP_TDMTX_ENx - ASP TDM TX Enable 1~6 */
+#define CS53L30_ASP_TDMTX_ENx_DEFAULT	(0)
+
+/* R26 (0x1A) CS53L30_SFT_RAMP - Soft Ramp Control */
+#define CS53L30_DIGSFT_SHIFT		5
+#define CS53L30_DIGSFT_MASK		(1 << CS53L30_DIGSFT_SHIFT)
+#define CS53L30_DIGSFT			(1 << CS53L30_DIGSFT_SHIFT)
+
+#define CS53L30_SFT_RMP_DEFAULT		(0)
+
+/* R28 (0x1C) CS53L30_LRCK_CTL2 - LRCK Control 2 */
+#define CS53L30_LRCK_50_NPW_SHIFT	3
+#define CS53L30_LRCK_50_NPW_MASK	(1 << CS53L30_LRCK_50_NPW_SHIFT)
+#define CS53L30_LRCK_50_NPW		(1 << CS53L30_LRCK_50_NPW_SHIFT)
+#define CS53L30_LRCK_TPWH_SHIFT		0
+#define CS53L30_LRCK_TPWH_WIDTH		3
+#define CS53L30_LRCK_TPWH_MASK		(((1 << CS53L30_LRCK_TPWH_WIDTH) - 1) << CS53L30_LRCK_TPWH_SHIFT)
+#define CS53L30_LRCK_TPWH(x)		(((x) << CS53L30_LRCK_TPWH_SHIFT) & CS53L30_LRCK_TPWH_MASK)
+
+#define CS53L30_LRCK_CTLx_DEFAULT	(0)
+
+/* R31 (0x1F) CS53L30_MUTEP_CTL1 - MUTE Pin Control 1 */
+#define CS53L30_MUTE_PDN_ULP_SHIFT	7
+#define CS53L30_MUTE_PDN_ULP_MASK	(1 << CS53L30_MUTE_PDN_ULP_SHIFT)
+#define CS53L30_MUTE_PDN_ULP		(1 << CS53L30_MUTE_PDN_ULP_SHIFT)
+#define CS53L30_MUTE_PDN_LP_SHIFT	6
+#define CS53L30_MUTE_PDN_LP_MASK	(1 << CS53L30_MUTE_PDN_LP_SHIFT)
+#define CS53L30_MUTE_PDN_LP		(1 << CS53L30_MUTE_PDN_LP_SHIFT)
+#define CS53L30_MUTE_M4B_PDN_SHIFT	4
+#define CS53L30_MUTE_M4B_PDN_MASK	(1 << CS53L30_MUTE_M4B_PDN_SHIFT)
+#define CS53L30_MUTE_M4B_PDN		(1 << CS53L30_MUTE_M4B_PDN_SHIFT)
+#define CS53L30_MUTE_M3B_PDN_SHIFT	3
+#define CS53L30_MUTE_M3B_PDN_MASK	(1 << CS53L30_MUTE_M3B_PDN_SHIFT)
+#define CS53L30_MUTE_M3B_PDN		(1 << CS53L30_MUTE_M3B_PDN_SHIFT)
+#define CS53L30_MUTE_M2B_PDN_SHIFT	2
+#define CS53L30_MUTE_M2B_PDN_MASK	(1 << CS53L30_MUTE_M2B_PDN_SHIFT)
+#define CS53L30_MUTE_M2B_PDN		(1 << CS53L30_MUTE_M2B_PDN_SHIFT)
+#define CS53L30_MUTE_M1B_PDN_SHIFT	1
+#define CS53L30_MUTE_M1B_PDN_MASK	(1 << CS53L30_MUTE_M1B_PDN_SHIFT)
+#define CS53L30_MUTE_M1B_PDN		(1 << CS53L30_MUTE_M1B_PDN_SHIFT)
+/* Note: be careful - x starts from 0 */
+#define CS53L30_MUTE_MxB_PDN_SHIFT(x)	(CS53L30_MUTE_M1B_PDN_SHIFT + (x))
+#define CS53L30_MUTE_MxB_PDN_MASK(x)	(1 << CS53L30_MUTE_MxB_PDN_SHIFT(x))
+#define CS53L30_MUTE_MxB_PDN(x)		(1 << CS53L30_MUTE_MxB_PDN_SHIFT(x))
+#define CS53L30_MUTE_MB_ALL_PDN_SHIFT	0
+#define CS53L30_MUTE_MB_ALL_PDN_MASK	(1 << CS53L30_MUTE_MB_ALL_PDN_SHIFT)
+#define CS53L30_MUTE_MB_ALL_PDN		(1 << CS53L30_MUTE_MB_ALL_PDN_SHIFT)
+
+#define CS53L30_MUTEP_CTL1_MUTEALL	(0xdf)
+#define CS53L30_MUTEP_CTL1_DEFAULT	(0)
+
+/* R32 (0x20) CS53L30_MUTEP_CTL2 - MUTE Pin Control 2 */
+#define CS53L30_MUTE_PIN_POLARITY_SHIFT	7
+#define CS53L30_MUTE_PIN_POLARITY_MASK	(1 << CS53L30_MUTE_PIN_POLARITY_SHIFT)
+#define CS53L30_MUTE_PIN_POLARITY	(1 << CS53L30_MUTE_PIN_POLARITY_SHIFT)
+#define CS53L30_MUTE_ASP_TDM_PDN_SHIFT	6
+#define CS53L30_MUTE_ASP_TDM_PDN_MASK	(1 << CS53L30_MUTE_ASP_TDM_PDN_SHIFT)
+#define CS53L30_MUTE_ASP_TDM_PDN	(1 << CS53L30_MUTE_ASP_TDM_PDN_SHIFT)
+#define CS53L30_MUTE_ASP_SDOUT2_PDN_SHIFT 5
+#define CS53L30_MUTE_ASP_SDOUT2_PDN_MASK (1 << CS53L30_MUTE_ASP_SDOUT2_PDN_SHIFT)
+#define CS53L30_MUTE_ASP_SDOUT2_PDN	(1 << CS53L30_MUTE_ASP_SDOUT2_PDN_SHIFT)
+#define CS53L30_MUTE_ASP_SDOUT1_PDN_SHIFT 4
+#define CS53L30_MUTE_ASP_SDOUT1_PDN_MASK (1 << CS53L30_MUTE_ASP_SDOUT1_PDN_SHIFT)
+#define CS53L30_MUTE_ASP_SDOUT1_PDN	(1 << CS53L30_MUTE_ASP_SDOUT1_PDN_SHIFT)
+/* Note: be careful - x starts from 0 */
+#define CS53L30_MUTE_ASP_SDOUTx_PDN_SHIFT(x) ((x) + CS53L30_MUTE_ASP_SDOUT1_PDN_SHIFT)
+#define CS53L30_MUTE_ASP_SDOUTx_PDN_MASK(x) (1 << CS53L30_MUTE_ASP_SDOUTx_PDN_SHIFT(x))
+#define CS53L30_MUTE_ASP_SDOUTx_PDN	(1 << CS53L30_MUTE_ASP_SDOUTx_PDN_SHIFT(x))
+#define CS53L30_MUTE_ADC2B_PDN_SHIFT	3
+#define CS53L30_MUTE_ADC2B_PDN_MASK	(1 << CS53L30_MUTE_ADC2B_PDN_SHIFT)
+#define CS53L30_MUTE_ADC2B_PDN		(1 << CS53L30_MUTE_ADC2B_PDN_SHIFT)
+#define CS53L30_MUTE_ADC2A_PDN_SHIFT	2
+#define CS53L30_MUTE_ADC2A_PDN_MASK	(1 << CS53L30_MUTE_ADC2A_PDN_SHIFT)
+#define CS53L30_MUTE_ADC2A_PDN		(1 << CS53L30_MUTE_ADC2A_PDN_SHIFT)
+#define CS53L30_MUTE_ADC1B_PDN_SHIFT	1
+#define CS53L30_MUTE_ADC1B_PDN_MASK	(1 << CS53L30_MUTE_ADC1B_PDN_SHIFT)
+#define CS53L30_MUTE_ADC1B_PDN		(1 << CS53L30_MUTE_ADC1B_PDN_SHIFT)
+#define CS53L30_MUTE_ADC1A_PDN_SHIFT	0
+#define CS53L30_MUTE_ADC1A_PDN_MASK	(1 << CS53L30_MUTE_ADC1A_PDN_SHIFT)
+#define CS53L30_MUTE_ADC1A_PDN		(1 << CS53L30_MUTE_ADC1A_PDN_SHIFT)
+
+#define CS53L30_MUTEP_CTL2_DEFAULT	(CS53L30_MUTE_PIN_POLARITY)
+
+/* R33 (0x21) CS53L30_INBIAS_CTL1 - Input Bias Control 1 */
+#define CS53L30_IN4M_BIAS_SHIFT		6
+#define CS53L30_IN4M_BIAS_WIDTH		2
+#define CS53L30_IN4M_BIAS_MASK		(((1 << CS53L30_IN4M_BIAS_WIDTH) - 1) << CS53L30_IN4M_BIAS_SHIFT)
+#define CS53L30_IN4M_BIAS_OPEN		(0 << CS53L30_IN4M_BIAS_SHIFT)
+#define CS53L30_IN4M_BIAS_PULL_DOWN	(1 << CS53L30_IN4M_BIAS_SHIFT)
+#define CS53L30_IN4M_BIAS_VCM		(2 << CS53L30_IN4M_BIAS_SHIFT)
+#define CS53L30_IN4P_BIAS_SHIFT		4
+#define CS53L30_IN4P_BIAS_WIDTH		2
+#define CS53L30_IN4P_BIAS_MASK		(((1 << CS53L30_IN4P_BIAS_WIDTH) - 1) << CS53L30_IN4P_BIAS_SHIFT)
+#define CS53L30_IN4P_BIAS_OPEN		(0 << CS53L30_IN4P_BIAS_SHIFT)
+#define CS53L30_IN4P_BIAS_PULL_DOWN	(1 << CS53L30_IN4P_BIAS_SHIFT)
+#define CS53L30_IN4P_BIAS_VCM		(2 << CS53L30_IN4P_BIAS_SHIFT)
+#define CS53L30_IN3M_BIAS_SHIFT		2
+#define CS53L30_IN3M_BIAS_WIDTH		2
+#define CS53L30_IN3M_BIAS_MASK		(((1 << CS53L30_IN3M_BIAS_WIDTH) - 1) << CS53L30_IN4M_BIAS_SHIFT)
+#define CS53L30_IN3M_BIAS_OPEN		(0 << CS53L30_IN3M_BIAS_SHIFT)
+#define CS53L30_IN3M_BIAS_PULL_DOWN	(1 << CS53L30_IN3M_BIAS_SHIFT)
+#define CS53L30_IN3M_BIAS_VCM		(2 << CS53L30_IN3M_BIAS_SHIFT)
+#define CS53L30_IN3P_BIAS_SHIFT		0
+#define CS53L30_IN3P_BIAS_WIDTH		2
+#define CS53L30_IN3P_BIAS_MASK		(((1 << CS53L30_IN3P_BIAS_WIDTH) - 1) << CS53L30_IN3P_BIAS_SHIFT)
+#define CS53L30_IN3P_BIAS_OPEN		(0 << CS53L30_IN3P_BIAS_SHIFT)
+#define CS53L30_IN3P_BIAS_PULL_DOWN	(1 << CS53L30_IN3P_BIAS_SHIFT)
+#define CS53L30_IN3P_BIAS_VCM		(2 << CS53L30_IN3P_BIAS_SHIFT)
+
+#define CS53L30_INBIAS_CTL1_DEFAULT	(CS53L30_IN4M_BIAS_VCM | CS53L30_IN4P_BIAS_VCM |\
+					 CS53L30_IN3M_BIAS_VCM | CS53L30_IN3P_BIAS_VCM)
+
+/* R34 (0x22) CS53L30_INBIAS_CTL2 - Input Bias Control 2 */
+#define CS53L30_IN2M_BIAS_SHIFT		6
+#define CS53L30_IN2M_BIAS_WIDTH		2
+#define CS53L30_IN2M_BIAS_MASK		(((1 << CS53L30_IN2M_BIAS_WIDTH) - 1) << CS53L30_IN2M_BIAS_SHIFT)
+#define CS53L30_IN2M_BIAS_OPEN		(0 << CS53L30_IN2M_BIAS_SHIFT)
+#define CS53L30_IN2M_BIAS_PULL_DOWN	(1 << CS53L30_IN2M_BIAS_SHIFT)
+#define CS53L30_IN2M_BIAS_VCM		(2 << CS53L30_IN2M_BIAS_SHIFT)
+#define CS53L30_IN2P_BIAS_SHIFT		4
+#define CS53L30_IN2P_BIAS_WIDTH		2
+#define CS53L30_IN2P_BIAS_MASK		(((1 << CS53L30_IN2P_BIAS_WIDTH) - 1) << CS53L30_IN2P_BIAS_SHIFT)
+#define CS53L30_IN2P_BIAS_OPEN		(0 << CS53L30_IN2P_BIAS_SHIFT)
+#define CS53L30_IN2P_BIAS_PULL_DOWN	(1 << CS53L30_IN2P_BIAS_SHIFT)
+#define CS53L30_IN2P_BIAS_VCM		(2 << CS53L30_IN2P_BIAS_SHIFT)
+#define CS53L30_IN1M_BIAS_SHIFT		2
+#define CS53L30_IN1M_BIAS_WIDTH		2
+#define CS53L30_IN1M_BIAS_MASK		(((1 << CS53L30_IN1M_BIAS_WIDTH) - 1) << CS53L30_IN1M_BIAS_SHIFT)
+#define CS53L30_IN1M_BIAS_OPEN		(0 << CS53L30_IN1M_BIAS_SHIFT)
+#define CS53L30_IN1M_BIAS_PULL_DOWN	(1 << CS53L30_IN1M_BIAS_SHIFT)
+#define CS53L30_IN1M_BIAS_VCM		(2 << CS53L30_IN1M_BIAS_SHIFT)
+#define CS53L30_IN1P_BIAS_SHIFT		0
+#define CS53L30_IN1P_BIAS_WIDTH		2
+#define CS53L30_IN1P_BIAS_MASK		(((1 << CS53L30_IN1P_BIAS_WIDTH) - 1) << CS53L30_IN1P_BIAS_SHIFT)
+#define CS53L30_IN1P_BIAS_OPEN		(0 << CS53L30_IN1P_BIAS_SHIFT)
+#define CS53L30_IN1P_BIAS_PULL_DOWN	(1 << CS53L30_IN1P_BIAS_SHIFT)
+#define CS53L30_IN1P_BIAS_VCM		(2 << CS53L30_IN1P_BIAS_SHIFT)
+
+#define CS53L30_INBIAS_CTL2_DEFAULT	(CS53L30_IN2M_BIAS_VCM | CS53L30_IN2P_BIAS_VCM |\
+					 CS53L30_IN1M_BIAS_VCM | CS53L30_IN1P_BIAS_VCM)
+
+/* R35 (0x23) & R36 (0x24) CS53L30_DMICx_STR_CTL - DMIC1 & DMIC2 Stereo Control */
+#define CS53L30_DMICx_STEREO_ENB_SHIFT	5
+#define CS53L30_DMICx_STEREO_ENB_MASK	(1 << CS53L30_DMICx_STEREO_ENB_SHIFT)
+#define CS53L30_DMICx_STEREO_ENB	(1 << CS53L30_DMICx_STEREO_ENB_SHIFT)
+
+/* 0x88 and 0xCC are reserved bits */
+#define CS53L30_DMIC1_STR_CTL_DEFAULT	(CS53L30_DMICx_STEREO_ENB | 0x88)
+#define CS53L30_DMIC2_STR_CTL_DEFAULT	(CS53L30_DMICx_STEREO_ENB | 0xCC)
+
+/* R37/R45 (0x25/0x2D) CS53L30_ADCDMICx_CTL1 - ADC1/DMIC1 & ADC2/DMIC2 Control 1 */
+#define CS53L30_ADCxB_PDN_SHIFT		7
+#define CS53L30_ADCxB_PDN_MASK		(1 << CS53L30_ADCxB_PDN_SHIFT)
+#define CS53L30_ADCxB_PDN		(1 << CS53L30_ADCxB_PDN_SHIFT)
+#define CS53L30_ADCxA_PDN_SHIFT		6
+#define CS53L30_ADCxA_PDN_MASK		(1 << CS53L30_ADCxA_PDN_SHIFT)
+#define CS53L30_ADCxA_PDN		(1 << CS53L30_ADCxA_PDN_SHIFT)
+#define CS53L30_DMICx_PDN_SHIFT		2
+#define CS53L30_DMICx_PDN_MASK		(1 << CS53L30_DMICx_PDN_SHIFT)
+#define CS53L30_DMICx_PDN		(1 << CS53L30_DMICx_PDN_SHIFT)
+#define CS53L30_DMICx_SCLK_DIV_SHIFT	1
+#define CS53L30_DMICx_SCLK_DIV_MASK	(1 << CS53L30_DMICx_SCLK_DIV_SHIFT)
+#define CS53L30_DMICx_SCLK_DIV		(1 << CS53L30_DMICx_SCLK_DIV_SHIFT)
+#define CS53L30_CH_TYPE_SHIFT		0
+#define CS53L30_CH_TYPE_MASK		(1 << CS53L30_CH_TYPE_SHIFT)
+#define CS53L30_CH_TYPE			(1 << CS53L30_CH_TYPE_SHIFT)
+
+#define CS53L30_ADCDMICx_PDN_MASK	0xFF
+#define CS53L30_ADCDMICx_CTL1_DEFAULT	(CS53L30_DMICx_PDN)
+
+/* R38/R46 (0x26/0x2E) CS53L30_ADCDMICx_CTL2 - ADC1/DMIC1 & ADC2/DMIC2 Control 2 */
+#define CS53L30_ADCx_NOTCH_DIS_SHIFT	7
+#define CS53L30_ADCx_NOTCH_DIS_MASK	(1 << CS53L30_ADCx_NOTCH_DIS_SHIFT)
+#define CS53L30_ADCx_NOTCH_DIS		(1 << CS53L30_ADCx_NOTCH_DIS_SHIFT)
+#define CS53L30_ADCxB_INV_SHIFT		5
+#define CS53L30_ADCxB_INV_MASK		(1 << CS53L30_ADCxB_INV_SHIFT)
+#define CS53L30_ADCxB_INV		(1 << CS53L30_ADCxB_INV_SHIFT)
+#define CS53L30_ADCxA_INV_SHIFT		4
+#define CS53L30_ADCxA_INV_MASK		(1 << CS53L30_ADCxA_INV_SHIFT)
+#define CS53L30_ADCxA_INV		(1 << CS53L30_ADCxA_INV_SHIFT)
+#define CS53L30_ADCxB_DIG_BOOST_SHIFT	1
+#define CS53L30_ADCxB_DIG_BOOST_MASK	(1 << CS53L30_ADCxB_DIG_BOOST_SHIFT)
+#define CS53L30_ADCxB_DIG_BOOST		(1 << CS53L30_ADCxB_DIG_BOOST_SHIFT)
+#define CS53L30_ADCxA_DIG_BOOST_SHIFT	0
+#define CS53L30_ADCxA_DIG_BOOST_MASK	(1 << CS53L30_ADCxA_DIG_BOOST_SHIFT)
+#define CS53L30_ADCxA_DIG_BOOST		(1 << CS53L30_ADCxA_DIG_BOOST_SHIFT)
+
+#define CS53L30_ADCDMIC1_CTL2_DEFAULT	(0)
+
+/* R39/R47 (0x27/0x2F) CS53L30_ADCx_CTL3 - ADC1/ADC2 Control 3 */
+#define CS53L30_ADCx_HPF_EN_SHIFT	3
+#define CS53L30_ADCx_HPF_EN_MASK	(1 << CS53L30_ADCx_HPF_EN_SHIFT)
+#define CS53L30_ADCx_HPF_EN		(1 << CS53L30_ADCx_HPF_EN_SHIFT)
+#define CS53L30_ADCx_HPF_CF_SHIFT	1
+#define CS53L30_ADCx_HPF_CF_WIDTH	2
+#define CS53L30_ADCx_HPF_CF_MASK	(((1 << CS53L30_ADCx_HPF_CF_WIDTH) - 1) << CS53L30_ADCx_HPF_CF_SHIFT)
+#define CS53L30_ADCx_HPF_CF_1HZ86	(0 << CS53L30_ADCx_HPF_CF_SHIFT)
+#define CS53L30_ADCx_HPF_CF_120HZ	(1 << CS53L30_ADCx_HPF_CF_SHIFT)
+#define CS53L30_ADCx_HPF_CF_235HZ	(2 << CS53L30_ADCx_HPF_CF_SHIFT)
+#define CS53L30_ADCx_HPF_CF_466HZ	(3 << CS53L30_ADCx_HPF_CF_SHIFT)
+#define CS53L30_ADCx_NG_ALL_SHIFT	0
+#define CS53L30_ADCx_NG_ALL_MASK	(1 << CS53L30_ADCx_NG_ALL_SHIFT)
+#define CS53L30_ADCx_NG_ALL		(1 << CS53L30_ADCx_NG_ALL_SHIFT)
+
+#define CS53L30_ADCx_CTL3_DEFAULT	(CS53L30_ADCx_HPF_EN)
+
+/* R40/R48 (0x28/0x30) CS53L30_ADCx_NG_CTL - ADC1/ADC2 Noise Gate Control */
+#define CS53L30_ADCxB_NG_SHIFT		7
+#define CS53L30_ADCxB_NG_MASK		(1 << CS53L30_ADCxB_NG_SHIFT)
+#define CS53L30_ADCxB_NG		(1 << CS53L30_ADCxB_NG_SHIFT)
+#define CS53L30_ADCxA_NG_SHIFT		6
+#define CS53L30_ADCxA_NG_MASK		(1 << CS53L30_ADCxA_NG_SHIFT)
+#define CS53L30_ADCxA_NG		(1 << CS53L30_ADCxA_NG_SHIFT)
+#define CS53L30_ADCx_NG_BOOST_SHIFT	5
+#define CS53L30_ADCx_NG_BOOST_MASK	(1 << CS53L30_ADCx_NG_BOOST_SHIFT)
+#define CS53L30_ADCx_NG_BOOST		(1 << CS53L30_ADCx_NG_BOOST_SHIFT)
+#define CS53L30_ADCx_NG_THRESH_SHIFT	2
+#define CS53L30_ADCx_NG_THRESH_WIDTH	3
+#define CS53L30_ADCx_NG_THRESH_MASK	(((1 << CS53L30_ADCx_NG_THRESH_WIDTH) - 1) << CS53L30_ADCx_NG_THRESH_SHIFT)
+#define CS53L30_ADCx_NG_DELAY_SHIFT	0
+#define CS53L30_ADCx_NG_DELAY_WIDTH	2
+#define CS53L30_ADCx_NG_DELAY_MASK	(((1 << CS53L30_ADCx_NG_DELAY_WIDTH) - 1) << CS53L30_ADCx_NG_DELAY_SHIFT)
+
+#define CS53L30_ADCx_NG_CTL_DEFAULT	(0)
+
+/* R41/R42/R49/R50 (0x29/0x2A/0x31/0x32) CS53L30_ADCxy_AFE_CTL - ADC1A/1B/2A/2B AFE Control */
+#define CS53L30_ADCxy_PREAMP_SHIFT	6
+#define CS53L30_ADCxy_PREAMP_WIDTH	2
+#define CS53L30_ADCxy_PREAMP_MASK	(((1 << CS53L30_ADCxy_PREAMP_WIDTH) - 1) << CS53L30_ADCxy_PREAMP_SHIFT)
+#define CS53L30_ADCxy_PGA_VOL_SHIFT	0
+#define CS53L30_ADCxy_PGA_VOL_WIDTH	6
+#define CS53L30_ADCxy_PGA_VOL_MASK	(((1 << CS53L30_ADCxy_PGA_VOL_WIDTH) - 1) << CS53L30_ADCxy_PGA_VOL_SHIFT)
+
+#define CS53L30_ADCxy_AFE_CTL_DEFAULT	(0)
+
+/* R43/R44/R51/R52 (0x2B/0x2C/0x33/0x34) CS53L30_ADCxy_DIG_VOL - ADC1A/1B/2A/2B Digital Volume */
+#define CS53L30_ADCxy_VOL_MUTE		(0x80)
+
+#define CS53L30_ADCxy_DIG_VOL_DEFAULT	(0x0)
+
+/* CS53L30_INT */
+#define CS53L30_PDN_DONE		(1 << 7)
+#define CS53L30_THMS_TRIP		(1 << 6)
+#define CS53L30_SYNC_DONE		(1 << 5)
+#define CS53L30_ADC2B_OVFL		(1 << 4)
+#define CS53L30_ADC2A_OVFL		(1 << 3)
+#define CS53L30_ADC1B_OVFL		(1 << 2)
+#define CS53L30_ADC1A_OVFL		(1 << 1)
+#define CS53L30_MUTE_PIN		(1 << 0)
+#define CS53L30_DEVICE_INT_MASK		0xFF
+
+#endif	/* __CS53L30_H__ */
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
new file mode 100644
index 0000000..ab174b5
--- /dev/null
+++ b/sound/soc/codecs/cx20442.c
@@ -0,0 +1,447 @@
+/*
+ * cx20442.c  --  CX20442 ALSA Soc Audio driver
+ *
+ * Copyright 2009 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *
+ * Initially based on sound/soc/codecs/wm8400.c
+ * Copyright 2008, 2009 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "cx20442.h"
+
+
+struct cx20442_priv {
+	struct tty_struct *tty;
+	struct regulator *por;
+	u8 reg_cache;
+};
+
+#define CX20442_PM		0x0
+
+#define CX20442_TELIN		0
+#define CX20442_TELOUT		1
+#define CX20442_MIC		2
+#define CX20442_SPKOUT		3
+#define CX20442_AGC		4
+
+static const struct snd_soc_dapm_widget cx20442_dapm_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("TELOUT"),
+	SND_SOC_DAPM_OUTPUT("SPKOUT"),
+	SND_SOC_DAPM_OUTPUT("AGCOUT"),
+
+	SND_SOC_DAPM_MIXER("SPKOUT Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("TELOUT Amp", CX20442_PM, CX20442_TELOUT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SPKOUT Amp", CX20442_PM, CX20442_SPKOUT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SPKOUT AGC", CX20442_PM, CX20442_AGC, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MICBIAS("TELIN Bias", CX20442_PM, CX20442_TELIN, 0),
+	SND_SOC_DAPM_MICBIAS("MIC Bias", CX20442_PM, CX20442_MIC, 0),
+
+	SND_SOC_DAPM_PGA("MIC AGC", CX20442_PM, CX20442_AGC, 0, NULL, 0),
+
+	SND_SOC_DAPM_INPUT("TELIN"),
+	SND_SOC_DAPM_INPUT("MIC"),
+	SND_SOC_DAPM_INPUT("AGCIN"),
+};
+
+static const struct snd_soc_dapm_route cx20442_audio_map[] = {
+	{"TELOUT", NULL, "TELOUT Amp"},
+
+	{"SPKOUT", NULL, "SPKOUT Mixer"},
+	{"SPKOUT Mixer", NULL, "SPKOUT Amp"},
+
+	{"TELOUT Amp", NULL, "DAC"},
+	{"SPKOUT Amp", NULL, "DAC"},
+
+	{"SPKOUT Mixer", NULL, "SPKOUT AGC"},
+	{"SPKOUT AGC", NULL, "AGCIN"},
+
+	{"AGCOUT", NULL, "MIC AGC"},
+	{"MIC AGC", NULL, "MIC"},
+
+	{"MIC Bias", NULL, "MIC"},
+	{"Input Mixer", NULL, "MIC Bias"},
+
+	{"TELIN Bias", NULL, "TELIN"},
+	{"Input Mixer", NULL, "TELIN Bias"},
+
+	{"ADC", NULL, "Input Mixer"},
+};
+
+static unsigned int cx20442_read_reg_cache(struct snd_soc_component *component,
+					   unsigned int reg)
+{
+	struct cx20442_priv *cx20442 = snd_soc_component_get_drvdata(component);
+
+	if (reg >= 1)
+		return -EINVAL;
+
+	return cx20442->reg_cache;
+}
+
+enum v253_vls {
+	V253_VLS_NONE = 0,
+	V253_VLS_T,
+	V253_VLS_L,
+	V253_VLS_LT,
+	V253_VLS_S,
+	V253_VLS_ST,
+	V253_VLS_M,
+	V253_VLS_MST,
+	V253_VLS_S1,
+	V253_VLS_S1T,
+	V253_VLS_MS1T,
+	V253_VLS_M1,
+	V253_VLS_M1ST,
+	V253_VLS_M1S1T,
+	V253_VLS_H,
+	V253_VLS_HT,
+	V253_VLS_MS,
+	V253_VLS_MS1,
+	V253_VLS_M1S,
+	V253_VLS_M1S1,
+	V253_VLS_TEST,
+};
+
+static int cx20442_pm_to_v253_vls(u8 value)
+{
+	switch (value & ~(1 << CX20442_AGC)) {
+	case 0:
+		return V253_VLS_T;
+	case (1 << CX20442_SPKOUT):
+	case (1 << CX20442_MIC):
+	case (1 << CX20442_SPKOUT) | (1 << CX20442_MIC):
+		return V253_VLS_M1S1;
+	case (1 << CX20442_TELOUT):
+	case (1 << CX20442_TELIN):
+	case (1 << CX20442_TELOUT) | (1 << CX20442_TELIN):
+		return V253_VLS_L;
+	case (1 << CX20442_TELOUT) | (1 << CX20442_MIC):
+		return V253_VLS_NONE;
+	}
+	return -EINVAL;
+}
+static int cx20442_pm_to_v253_vsp(u8 value)
+{
+	switch (value & ~(1 << CX20442_AGC)) {
+	case (1 << CX20442_SPKOUT):
+	case (1 << CX20442_MIC):
+	case (1 << CX20442_SPKOUT) | (1 << CX20442_MIC):
+		return (bool)(value & (1 << CX20442_AGC));
+	}
+	return (value & (1 << CX20442_AGC)) ? -EINVAL : 0;
+}
+
+static int cx20442_write(struct snd_soc_component *component, unsigned int reg,
+							unsigned int value)
+{
+	struct cx20442_priv *cx20442 = snd_soc_component_get_drvdata(component);
+	int vls, vsp, old, len;
+	char buf[18];
+
+	if (reg >= 1)
+		return -EINVAL;
+
+	/* tty and write pointers required for talking to the modem
+	 * are expected to be set by the line discipline initialization code */
+	if (!cx20442->tty || !cx20442->tty->ops->write)
+		return -EIO;
+
+	old = cx20442->reg_cache;
+	cx20442->reg_cache = value;
+
+	vls = cx20442_pm_to_v253_vls(value);
+	if (vls < 0)
+		return vls;
+
+	vsp = cx20442_pm_to_v253_vsp(value);
+	if (vsp < 0)
+		return vsp;
+
+	if ((vls == V253_VLS_T) ||
+			(vls == cx20442_pm_to_v253_vls(old))) {
+		if (vsp == cx20442_pm_to_v253_vsp(old))
+			return 0;
+		len = snprintf(buf, ARRAY_SIZE(buf), "at+vsp=%d\r", vsp);
+	} else if (vsp == cx20442_pm_to_v253_vsp(old))
+		len = snprintf(buf, ARRAY_SIZE(buf), "at+vls=%d\r", vls);
+	else
+		len = snprintf(buf, ARRAY_SIZE(buf),
+					"at+vls=%d;+vsp=%d\r", vls, vsp);
+
+	if (unlikely(len > (ARRAY_SIZE(buf) - 1)))
+		return -ENOMEM;
+
+	dev_dbg(component->dev, "%s: %s\n", __func__, buf);
+	if (cx20442->tty->ops->write(cx20442->tty, buf, len) != len)
+		return -EIO;
+
+	return 0;
+}
+
+/*
+ * Line discpline related code
+ *
+ * Any of the callback functions below can be used in two ways:
+ * 1) registerd by a machine driver as one of line discipline operations,
+ * 2) called from a machine's provided line discipline callback function
+ *    in case when extra machine specific code must be run as well.
+ */
+
+/* Modem init: echo off, digital speaker off, quiet off, voice mode */
+static const char *v253_init = "ate0m0q0+fclass=8\r";
+
+/* Line discipline .open() */
+static int v253_open(struct tty_struct *tty)
+{
+	int ret, len = strlen(v253_init);
+
+	/* Doesn't make sense without write callback */
+	if (!tty->ops->write)
+		return -EINVAL;
+
+	/* Won't work if no codec pointer has been passed by a card driver */
+	if (!tty->disc_data)
+		return -ENODEV;
+
+	tty->receive_room = 16;
+	if (tty->ops->write(tty, v253_init, len) != len) {
+		ret = -EIO;
+		goto err;
+	}
+	/* Actual setup will be performed after the modem responds. */
+	return 0;
+err:
+	tty->disc_data = NULL;
+	return ret;
+}
+
+/* Line discipline .close() */
+static void v253_close(struct tty_struct *tty)
+{
+	struct snd_soc_component *component = tty->disc_data;
+	struct cx20442_priv *cx20442;
+
+	tty->disc_data = NULL;
+
+	if (!component)
+		return;
+
+	cx20442 = snd_soc_component_get_drvdata(component);
+
+	/* Prevent the codec driver from further accessing the modem */
+	cx20442->tty = NULL;
+	component->card->pop_time = 0;
+}
+
+/* Line discipline .hangup() */
+static int v253_hangup(struct tty_struct *tty)
+{
+	v253_close(tty);
+	return 0;
+}
+
+/* Line discipline .receive_buf() */
+static void v253_receive(struct tty_struct *tty,
+				const unsigned char *cp, char *fp, int count)
+{
+	struct snd_soc_component *component = tty->disc_data;
+	struct cx20442_priv *cx20442;
+
+	if (!component)
+		return;
+
+	cx20442 = snd_soc_component_get_drvdata(component);
+
+	if (!cx20442->tty) {
+		/* First modem response, complete setup procedure */
+
+		/* Set up codec driver access to modem controls */
+		cx20442->tty = tty;
+		component->card->pop_time = 1;
+	}
+}
+
+/* Line discipline .write_wakeup() */
+static void v253_wakeup(struct tty_struct *tty)
+{
+}
+
+struct tty_ldisc_ops v253_ops = {
+	.magic = TTY_LDISC_MAGIC,
+	.name = "cx20442",
+	.owner = THIS_MODULE,
+	.open = v253_open,
+	.close = v253_close,
+	.hangup = v253_hangup,
+	.receive_buf = v253_receive,
+	.write_wakeup = v253_wakeup,
+};
+EXPORT_SYMBOL_GPL(v253_ops);
+
+
+/*
+ * Codec DAI
+ */
+
+static struct snd_soc_dai_driver cx20442_dai = {
+	.name = "cx20442-voice",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+};
+
+static int cx20442_set_bias_level(struct snd_soc_component *component,
+		enum snd_soc_bias_level level)
+{
+	struct cx20442_priv *cx20442 = snd_soc_component_get_drvdata(component);
+	int err = 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_STANDBY)
+			break;
+		if (IS_ERR(cx20442->por))
+			err = PTR_ERR(cx20442->por);
+		else
+			err = regulator_enable(cx20442->por);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_PREPARE)
+			break;
+		if (IS_ERR(cx20442->por))
+			err = PTR_ERR(cx20442->por);
+		else
+			err = regulator_disable(cx20442->por);
+		break;
+	default:
+		break;
+	}
+
+	return err;
+}
+
+static int cx20442_component_probe(struct snd_soc_component *component)
+{
+	struct cx20442_priv *cx20442;
+
+	cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
+	if (cx20442 == NULL)
+		return -ENOMEM;
+
+	cx20442->por = regulator_get(component->dev, "POR");
+	if (IS_ERR(cx20442->por)) {
+		int err = PTR_ERR(cx20442->por);
+
+		dev_warn(component->dev, "failed to get POR supply (%d)", err);
+		/*
+		 * When running on a non-dt platform and requested regulator
+		 * is not available, regulator_get() never returns
+		 * -EPROBE_DEFER as it is not able to justify if the regulator
+		 * may still appear later.  On the other hand, the board can
+		 * still set full constraints flag at late_initcall in order
+		 * to instruct regulator_get() to return a dummy one if
+		 * sufficient.  Hence, if we get -ENODEV here, let's convert
+		 * it to -EPROBE_DEFER and wait for the board to decide or
+		 * let Deferred Probe infrastructure handle this error.
+		 */
+		if (err == -ENODEV)
+			err = -EPROBE_DEFER;
+		kfree(cx20442);
+		return err;
+	}
+
+	cx20442->tty = NULL;
+
+	snd_soc_component_set_drvdata(component, cx20442);
+	component->card->pop_time = 0;
+
+	return 0;
+}
+
+/* power down chip */
+static void cx20442_component_remove(struct snd_soc_component *component)
+{
+	struct cx20442_priv *cx20442 = snd_soc_component_get_drvdata(component);
+
+	if (cx20442->tty) {
+		struct tty_struct *tty = cx20442->tty;
+		tty_hangup(tty);
+	}
+
+	if (!IS_ERR(cx20442->por)) {
+		/* should be already in STANDBY, hence disabled */
+		regulator_put(cx20442->por);
+	}
+
+	snd_soc_component_set_drvdata(component, NULL);
+	kfree(cx20442);
+}
+
+static const struct snd_soc_component_driver cx20442_component_dev = {
+	.probe			= cx20442_component_probe,
+	.remove			= cx20442_component_remove,
+	.set_bias_level		= cx20442_set_bias_level,
+	.read			= cx20442_read_reg_cache,
+	.write			= cx20442_write,
+	.dapm_widgets		= cx20442_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cx20442_dapm_widgets),
+	.dapm_routes		= cx20442_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(cx20442_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int cx20442_platform_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&cx20442_component_dev, &cx20442_dai, 1);
+}
+
+static struct platform_driver cx20442_platform_driver = {
+	.driver = {
+		.name = "cx20442-codec",
+		},
+	.probe = cx20442_platform_probe,
+};
+
+module_platform_driver(cx20442_platform_driver);
+
+MODULE_DESCRIPTION("ASoC CX20442-11 voice modem codec driver");
+MODULE_AUTHOR("Janusz Krzysztofik");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:cx20442-codec");
diff --git a/sound/soc/codecs/cx20442.h b/sound/soc/codecs/cx20442.h
new file mode 100644
index 0000000..c7a7c79
--- /dev/null
+++ b/sound/soc/codecs/cx20442.h
@@ -0,0 +1,18 @@
+/*
+ * cx20442.h  --  audio driver for CX20442
+ *
+ * Copyright 2009 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef _CX20442_CODEC_H
+#define _CX20442_CODEC_H
+
+extern struct tty_ldisc_ops v253_ops;
+
+#endif
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
new file mode 100644
index 0000000..e172913
--- /dev/null
+++ b/sound/soc/codecs/da7210.c
@@ -0,0 +1,1361 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// DA7210 ALSA Soc codec driver
+//
+// Copyright (c) 2009 Dialog Semiconductor
+// Written by David Chen <Dajun.chen@diasemi.com>
+//
+// Copyright (C) 2009 Renesas Solutions Corp.
+// Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.com>
+//
+// Tested on SuperH Ecovec24 board with S16/S24 LE in 48KHz using I2S
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+/* DA7210 register space */
+#define DA7210_PAGE_CONTROL		0x00
+#define DA7210_CONTROL			0x01
+#define DA7210_STATUS			0x02
+#define DA7210_STARTUP1			0x03
+#define DA7210_STARTUP2			0x04
+#define DA7210_STARTUP3			0x05
+#define DA7210_MIC_L			0x07
+#define DA7210_MIC_R			0x08
+#define DA7210_AUX1_L			0x09
+#define DA7210_AUX1_R			0x0A
+#define DA7210_AUX2			0x0B
+#define DA7210_IN_GAIN			0x0C
+#define DA7210_INMIX_L			0x0D
+#define DA7210_INMIX_R			0x0E
+#define DA7210_ADC_HPF			0x0F
+#define DA7210_ADC			0x10
+#define DA7210_ADC_EQ1_2		0X11
+#define DA7210_ADC_EQ3_4		0x12
+#define DA7210_ADC_EQ5			0x13
+#define DA7210_DAC_HPF			0x14
+#define DA7210_DAC_L			0x15
+#define DA7210_DAC_R			0x16
+#define DA7210_DAC_SEL			0x17
+#define DA7210_SOFTMUTE			0x18
+#define DA7210_DAC_EQ1_2		0x19
+#define DA7210_DAC_EQ3_4		0x1A
+#define DA7210_DAC_EQ5			0x1B
+#define DA7210_OUTMIX_L			0x1C
+#define DA7210_OUTMIX_R			0x1D
+#define DA7210_OUT1_L			0x1E
+#define DA7210_OUT1_R			0x1F
+#define DA7210_OUT2			0x20
+#define DA7210_HP_L_VOL			0x21
+#define DA7210_HP_R_VOL			0x22
+#define DA7210_HP_CFG			0x23
+#define DA7210_ZERO_CROSS		0x24
+#define DA7210_DAI_SRC_SEL		0x25
+#define DA7210_DAI_CFG1			0x26
+#define DA7210_DAI_CFG3			0x28
+#define DA7210_PLL_DIV1			0x29
+#define DA7210_PLL_DIV2			0x2A
+#define DA7210_PLL_DIV3			0x2B
+#define DA7210_PLL			0x2C
+#define DA7210_ALC_MAX			0x83
+#define DA7210_ALC_MIN			0x84
+#define DA7210_ALC_NOIS			0x85
+#define DA7210_ALC_ATT			0x86
+#define DA7210_ALC_REL			0x87
+#define DA7210_ALC_DEL			0x88
+#define DA7210_A_HID_UNLOCK		0x8A
+#define DA7210_A_TEST_UNLOCK		0x8B
+#define DA7210_A_PLL1			0x90
+#define DA7210_A_CP_MODE		0xA7
+
+/* STARTUP1 bit fields */
+#define DA7210_SC_MST_EN		(1 << 0)
+
+/* MIC_L bit fields */
+#define DA7210_MICBIAS_EN		(1 << 6)
+#define DA7210_MIC_L_EN			(1 << 7)
+
+/* MIC_R bit fields */
+#define DA7210_MIC_R_EN			(1 << 7)
+
+/* INMIX_L bit fields */
+#define DA7210_IN_L_EN			(1 << 7)
+
+/* INMIX_R bit fields */
+#define DA7210_IN_R_EN			(1 << 7)
+
+/* ADC bit fields */
+#define DA7210_ADC_ALC_EN		(1 << 0)
+#define DA7210_ADC_L_EN			(1 << 3)
+#define DA7210_ADC_R_EN			(1 << 7)
+
+/* DAC/ADC HPF fields */
+#define DA7210_VOICE_F0_MASK		(0x7 << 4)
+#define DA7210_VOICE_F0_25		(1 << 4)
+#define DA7210_VOICE_EN			(1 << 7)
+
+/* DAC_SEL bit fields */
+#define DA7210_DAC_L_SRC_DAI_L		(4 << 0)
+#define DA7210_DAC_L_EN			(1 << 3)
+#define DA7210_DAC_R_SRC_DAI_R		(5 << 4)
+#define DA7210_DAC_R_EN			(1 << 7)
+
+/* OUTMIX_L bit fields */
+#define DA7210_OUT_L_EN			(1 << 7)
+
+/* OUTMIX_R bit fields */
+#define DA7210_OUT_R_EN			(1 << 7)
+
+/* HP_CFG bit fields */
+#define DA7210_HP_2CAP_MODE		(1 << 1)
+#define DA7210_HP_SENSE_EN		(1 << 2)
+#define DA7210_HP_L_EN			(1 << 3)
+#define DA7210_HP_MODE			(1 << 6)
+#define DA7210_HP_R_EN			(1 << 7)
+
+/* DAI_SRC_SEL bit fields */
+#define DA7210_DAI_OUT_L_SRC		(6 << 0)
+#define DA7210_DAI_OUT_R_SRC		(7 << 4)
+
+/* DAI_CFG1 bit fields */
+#define DA7210_DAI_WORD_S16_LE		(0 << 0)
+#define DA7210_DAI_WORD_S20_3LE		(1 << 0)
+#define DA7210_DAI_WORD_S24_LE		(2 << 0)
+#define DA7210_DAI_WORD_S32_LE		(3 << 0)
+#define DA7210_DAI_FLEN_64BIT		(1 << 2)
+#define DA7210_DAI_MODE_SLAVE		(0 << 7)
+#define DA7210_DAI_MODE_MASTER		(1 << 7)
+
+/* DAI_CFG3 bit fields */
+#define DA7210_DAI_FORMAT_I2SMODE	(0 << 0)
+#define DA7210_DAI_FORMAT_LEFT_J	(1 << 0)
+#define DA7210_DAI_FORMAT_RIGHT_J	(2 << 0)
+#define DA7210_DAI_OE			(1 << 3)
+#define DA7210_DAI_EN			(1 << 7)
+
+/*PLL_DIV3 bit fields */
+#define DA7210_PLL_DIV_L_MASK		(0xF << 0)
+#define DA7210_MCLK_RANGE_10_20_MHZ	(1 << 4)
+#define DA7210_PLL_BYP			(1 << 6)
+
+/* PLL bit fields */
+#define DA7210_PLL_FS_MASK		(0xF << 0)
+#define DA7210_PLL_FS_8000		(0x1 << 0)
+#define DA7210_PLL_FS_11025		(0x2 << 0)
+#define DA7210_PLL_FS_12000		(0x3 << 0)
+#define DA7210_PLL_FS_16000		(0x5 << 0)
+#define DA7210_PLL_FS_22050		(0x6 << 0)
+#define DA7210_PLL_FS_24000		(0x7 << 0)
+#define DA7210_PLL_FS_32000		(0x9 << 0)
+#define DA7210_PLL_FS_44100		(0xA << 0)
+#define DA7210_PLL_FS_48000		(0xB << 0)
+#define DA7210_PLL_FS_88200		(0xE << 0)
+#define DA7210_PLL_FS_96000		(0xF << 0)
+#define DA7210_MCLK_DET_EN		(0x1 << 5)
+#define DA7210_MCLK_SRM_EN		(0x1 << 6)
+#define DA7210_PLL_EN			(0x1 << 7)
+
+/* SOFTMUTE bit fields */
+#define DA7210_RAMP_EN			(1 << 6)
+
+/* CONTROL bit fields */
+#define DA7210_REG_EN			(1 << 0)
+#define DA7210_BIAS_EN			(1 << 2)
+#define DA7210_NOISE_SUP_EN		(1 << 3)
+
+/* IN_GAIN bit fields */
+#define DA7210_INPGA_L_VOL		(0x0F << 0)
+#define DA7210_INPGA_R_VOL		(0xF0 << 0)
+
+/* ZERO_CROSS bit fields */
+#define DA7210_AUX1_L_ZC		(1 << 0)
+#define DA7210_AUX1_R_ZC		(1 << 1)
+#define DA7210_HP_L_ZC			(1 << 6)
+#define DA7210_HP_R_ZC			(1 << 7)
+
+/* AUX1_L bit fields */
+#define DA7210_AUX1_L_VOL		(0x3F << 0)
+#define DA7210_AUX1_L_EN		(1 << 7)
+
+/* AUX1_R bit fields */
+#define DA7210_AUX1_R_VOL		(0x3F << 0)
+#define DA7210_AUX1_R_EN		(1 << 7)
+
+/* AUX2 bit fields */
+#define DA7210_AUX2_EN			(1 << 3)
+
+/* Minimum INPGA and AUX1 volume to enable noise suppression */
+#define DA7210_INPGA_MIN_VOL_NS		0x0A  /* 10.5dB */
+#define DA7210_AUX1_MIN_VOL_NS		0x35  /* 6dB */
+
+/* OUT1_L bit fields */
+#define DA7210_OUT1_L_EN		(1 << 7)
+
+/* OUT1_R bit fields */
+#define DA7210_OUT1_R_EN		(1 << 7)
+
+/* OUT2 bit fields */
+#define DA7210_OUT2_OUTMIX_R		(1 << 5)
+#define DA7210_OUT2_OUTMIX_L		(1 << 6)
+#define DA7210_OUT2_EN			(1 << 7)
+
+struct pll_div {
+	int fref;
+	int fout;
+	u8 div1;
+	u8 div2;
+	u8 div3;
+	u8 mode;	/* 0 = slave, 1 = master */
+};
+
+/* PLL dividers table */
+static const struct pll_div da7210_pll_div[] = {
+	/* for MASTER mode, fs = 44.1Khz */
+	{ 12000000, 2822400, 0xE8, 0x6C, 0x2, 1},	/* MCLK=12Mhz */
+	{ 13000000, 2822400, 0xDF, 0x28, 0xC, 1},	/* MCLK=13Mhz */
+	{ 13500000, 2822400, 0xDB, 0x0A, 0xD, 1},	/* MCLK=13.5Mhz */
+	{ 14400000, 2822400, 0xD4, 0x5A, 0x2, 1},	/* MCLK=14.4Mhz */
+	{ 19200000, 2822400, 0xBB, 0x43, 0x9, 1},	/* MCLK=19.2Mhz */
+	{ 19680000, 2822400, 0xB9, 0x6D, 0xA, 1},	/* MCLK=19.68Mhz */
+	{ 19800000, 2822400, 0xB8, 0xFB, 0xB, 1},	/* MCLK=19.8Mhz */
+	/* for MASTER mode, fs = 48Khz */
+	{ 12000000, 3072000, 0xF3, 0x12, 0x7, 1},	/* MCLK=12Mhz */
+	{ 13000000, 3072000, 0xE8, 0xFD, 0x5, 1},	/* MCLK=13Mhz */
+	{ 13500000, 3072000, 0xE4, 0x82, 0x3, 1},	/* MCLK=13.5Mhz */
+	{ 14400000, 3072000, 0xDD, 0x3A, 0x0, 1},	/* MCLK=14.4Mhz */
+	{ 19200000, 3072000, 0xC1, 0xEB, 0x8, 1},	/* MCLK=19.2Mhz */
+	{ 19680000, 3072000, 0xBF, 0xEC, 0x0, 1},	/* MCLK=19.68Mhz */
+	{ 19800000, 3072000, 0xBF, 0x70, 0x0, 1},	/* MCLK=19.8Mhz */
+	/* for SLAVE mode with SRM */
+	{ 12000000, 2822400, 0xED, 0xBF, 0x5, 0},	/* MCLK=12Mhz */
+	{ 13000000, 2822400, 0xE4, 0x13, 0x0, 0},	/* MCLK=13Mhz */
+	{ 13500000, 2822400, 0xDF, 0xC6, 0x8, 0},	/* MCLK=13.5Mhz */
+	{ 14400000, 2822400, 0xD8, 0xCA, 0x1, 0},	/* MCLK=14.4Mhz */
+	{ 19200000, 2822400, 0xBE, 0x97, 0x9, 0},	/* MCLK=19.2Mhz */
+	{ 19680000, 2822400, 0xBC, 0xAC, 0xD, 0},	/* MCLK=19.68Mhz */
+	{ 19800000, 2822400, 0xBC, 0x35, 0xE, 0},	/* MCLK=19.8Mhz  */
+};
+
+enum clk_src {
+	DA7210_CLKSRC_MCLK
+};
+
+#define DA7210_VERSION "0.0.1"
+
+/*
+ * Playback Volume
+ *
+ * max		: 0x3F (+15.0 dB)
+ *		   (1.5 dB step)
+ * min		: 0x11 (-54.0 dB)
+ * mute		: 0x10
+ * reserved	: 0x00 - 0x0F
+ *
+ * Reserved area are considered as "mute".
+ */
+static const DECLARE_TLV_DB_RANGE(hp_out_tlv,
+	0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+	/* -54 dB to +15 dB */
+	0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(lineout_vol_tlv,
+	0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+	/* -54dB to 15dB */
+	0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(mono_vol_tlv,
+	0x0, 0x2, TLV_DB_SCALE_ITEM(-1800, 0, 1),
+	/* -18dB to 6dB */
+	0x3, 0x7, TLV_DB_SCALE_ITEM(-1800, 600, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(aux1_vol_tlv,
+	0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+	/* -48dB to 21dB */
+	0x11, 0x3f, TLV_DB_SCALE_ITEM(-4800, 150, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_eq_master_gain_tlv, -1800, 600, 1);
+static const DECLARE_TLV_DB_SCALE(dac_gain_tlv, -7725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(aux2_vol_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(inpga_gain_tlv, -450, 150, 0);
+
+/* ADC and DAC high pass filter f0 value */
+static const char * const da7210_hpf_cutoff_txt[] = {
+	"Fs/8192*pi", "Fs/4096*pi", "Fs/2048*pi", "Fs/1024*pi"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7210_dac_hpf_cutoff,
+			    DA7210_DAC_HPF, 0, da7210_hpf_cutoff_txt);
+
+static SOC_ENUM_SINGLE_DECL(da7210_adc_hpf_cutoff,
+			    DA7210_ADC_HPF, 0, da7210_hpf_cutoff_txt);
+
+/* ADC and DAC voice (8kHz) high pass cutoff value */
+static const char * const da7210_vf_cutoff_txt[] = {
+	"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7210_dac_vf_cutoff,
+			    DA7210_DAC_HPF, 4, da7210_vf_cutoff_txt);
+
+static SOC_ENUM_SINGLE_DECL(da7210_adc_vf_cutoff,
+			    DA7210_ADC_HPF, 4, da7210_vf_cutoff_txt);
+
+static const char *da7210_hp_mode_txt[] = {
+	"Class H", "Class G"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7210_hp_mode_sel,
+			    DA7210_HP_CFG, 0, da7210_hp_mode_txt);
+
+/* ALC can be enabled only if noise suppression is disabled */
+static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+
+	if (ucontrol->value.integer.value[0]) {
+		/* Check if noise suppression is enabled */
+		if (snd_soc_component_read32(component, DA7210_CONTROL) & DA7210_NOISE_SUP_EN) {
+			dev_dbg(component->dev,
+				"Disable noise suppression to enable ALC\n");
+			return -EINVAL;
+		}
+	}
+	/* If all conditions are met or we are actually disabling ALC */
+	return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+/* Noise suppression can be enabled only if following conditions are met
+ *  ALC disabled
+ *  ZC enabled for HP and AUX1 PGA
+ *  INPGA_L_VOL and INPGA_R_VOL >= 10.5 dB
+ *  AUX1_L_VOL and AUX1_R_VOL >= 6 dB
+ */
+static int da7210_put_noise_sup_sw(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	u8 val;
+
+	if (ucontrol->value.integer.value[0]) {
+		/* Check if ALC is enabled */
+		if (snd_soc_component_read32(component, DA7210_ADC) & DA7210_ADC_ALC_EN)
+			goto err;
+
+		/* Check ZC for HP and AUX1 PGA */
+		if ((snd_soc_component_read32(component, DA7210_ZERO_CROSS) &
+			(DA7210_AUX1_L_ZC | DA7210_AUX1_R_ZC | DA7210_HP_L_ZC |
+			DA7210_HP_R_ZC)) != (DA7210_AUX1_L_ZC |
+			DA7210_AUX1_R_ZC | DA7210_HP_L_ZC | DA7210_HP_R_ZC))
+			goto err;
+
+		/* Check INPGA_L_VOL and INPGA_R_VOL */
+		val = snd_soc_component_read32(component, DA7210_IN_GAIN);
+		if (((val & DA7210_INPGA_L_VOL) < DA7210_INPGA_MIN_VOL_NS) ||
+			(((val & DA7210_INPGA_R_VOL) >> 4) <
+			DA7210_INPGA_MIN_VOL_NS))
+			goto err;
+
+		/* Check AUX1_L_VOL and AUX1_R_VOL */
+		if (((snd_soc_component_read32(component, DA7210_AUX1_L) & DA7210_AUX1_L_VOL) <
+		    DA7210_AUX1_MIN_VOL_NS) ||
+		    ((snd_soc_component_read32(component, DA7210_AUX1_R) & DA7210_AUX1_R_VOL) <
+		    DA7210_AUX1_MIN_VOL_NS))
+			goto err;
+	}
+	/* If all conditions are met or we are actually disabling Noise sup */
+	return snd_soc_put_volsw(kcontrol, ucontrol);
+
+err:
+	return -EINVAL;
+}
+
+static const struct snd_kcontrol_new da7210_snd_controls[] = {
+
+	SOC_DOUBLE_R_TLV("HeadPhone Playback Volume",
+			 DA7210_HP_L_VOL, DA7210_HP_R_VOL,
+			 0, 0x3F, 0, hp_out_tlv),
+	SOC_DOUBLE_R_TLV("Digital Playback Volume",
+			 DA7210_DAC_L, DA7210_DAC_R,
+			 0, 0x77, 1, dac_gain_tlv),
+	SOC_DOUBLE_R_TLV("Lineout Playback Volume",
+			 DA7210_OUT1_L, DA7210_OUT1_R,
+			 0, 0x3f, 0, lineout_vol_tlv),
+	SOC_SINGLE_TLV("Mono Playback Volume", DA7210_OUT2, 0, 0x7, 0,
+		       mono_vol_tlv),
+
+	SOC_DOUBLE_R_TLV("Mic Capture Volume",
+			 DA7210_MIC_L, DA7210_MIC_R,
+			 0, 0x5, 0, mic_vol_tlv),
+	SOC_DOUBLE_R_TLV("Aux1 Capture Volume",
+			 DA7210_AUX1_L, DA7210_AUX1_R,
+			 0, 0x3f, 0, aux1_vol_tlv),
+	SOC_SINGLE_TLV("Aux2 Capture Volume", DA7210_AUX2, 0, 0x3, 0,
+		       aux2_vol_tlv),
+	SOC_DOUBLE_TLV("In PGA Capture Volume", DA7210_IN_GAIN, 0, 4, 0xF, 0,
+		       inpga_gain_tlv),
+
+	/* DAC Equalizer  controls */
+	SOC_SINGLE("DAC EQ Switch", DA7210_DAC_EQ5, 7, 1, 0),
+	SOC_SINGLE_TLV("DAC EQ1 Volume", DA7210_DAC_EQ1_2, 0, 0xf, 1,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ2 Volume", DA7210_DAC_EQ1_2, 4, 0xf, 1,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ3 Volume", DA7210_DAC_EQ3_4, 0, 0xf, 1,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ4 Volume", DA7210_DAC_EQ3_4, 4, 0xf, 1,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ5 Volume", DA7210_DAC_EQ5, 0, 0xf, 1,
+		       eq_gain_tlv),
+
+	/* ADC Equalizer  controls */
+	SOC_SINGLE("ADC EQ Switch", DA7210_ADC_EQ5, 7, 1, 0),
+	SOC_SINGLE_TLV("ADC EQ Master Volume", DA7210_ADC_EQ5, 4, 0x3,
+		       1, adc_eq_master_gain_tlv),
+	SOC_SINGLE_TLV("ADC EQ1 Volume", DA7210_ADC_EQ1_2, 0, 0xf, 1,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("ADC EQ2 Volume", DA7210_ADC_EQ1_2, 4, 0xf, 1,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("ADC EQ3 Volume", DA7210_ADC_EQ3_4, 0, 0xf, 1,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("ADC EQ4 Volume", DA7210_ADC_EQ3_4, 4, 0xf, 1,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("ADC EQ5 Volume", DA7210_ADC_EQ5, 0, 0xf, 1,
+		       eq_gain_tlv),
+
+	SOC_SINGLE("DAC HPF Switch", DA7210_DAC_HPF, 3, 1, 0),
+	SOC_ENUM("DAC HPF Cutoff", da7210_dac_hpf_cutoff),
+	SOC_SINGLE("DAC Voice Mode Switch", DA7210_DAC_HPF, 7, 1, 0),
+	SOC_ENUM("DAC Voice Cutoff", da7210_dac_vf_cutoff),
+
+	SOC_SINGLE("ADC HPF Switch", DA7210_ADC_HPF, 3, 1, 0),
+	SOC_ENUM("ADC HPF Cutoff", da7210_adc_hpf_cutoff),
+	SOC_SINGLE("ADC Voice Mode Switch", DA7210_ADC_HPF, 7, 1, 0),
+	SOC_ENUM("ADC Voice Cutoff", da7210_adc_vf_cutoff),
+
+	/* Mute controls */
+	SOC_DOUBLE_R("Mic Capture Switch", DA7210_MIC_L, DA7210_MIC_R, 3, 1, 0),
+	SOC_SINGLE("Aux2 Capture Switch", DA7210_AUX2, 2, 1, 0),
+	SOC_DOUBLE("ADC Capture Switch", DA7210_ADC, 2, 6, 1, 0),
+	SOC_SINGLE("Digital Soft Mute Switch", DA7210_SOFTMUTE, 7, 1, 0),
+	SOC_SINGLE("Digital Soft Mute Rate", DA7210_SOFTMUTE, 0, 0x7, 0),
+
+	/* Zero cross controls */
+	SOC_DOUBLE("Aux1 ZC Switch", DA7210_ZERO_CROSS, 0, 1, 1, 0),
+	SOC_DOUBLE("In PGA ZC Switch", DA7210_ZERO_CROSS, 2, 3, 1, 0),
+	SOC_DOUBLE("Lineout ZC Switch", DA7210_ZERO_CROSS, 4, 5, 1, 0),
+	SOC_DOUBLE("Headphone ZC Switch", DA7210_ZERO_CROSS, 6, 7, 1, 0),
+
+	SOC_ENUM("Headphone Class", da7210_hp_mode_sel),
+
+	/* ALC controls */
+	SOC_SINGLE_EXT("ALC Enable Switch", DA7210_ADC, 0, 1, 0,
+		       snd_soc_get_volsw, da7210_put_alc_sw),
+	SOC_SINGLE("ALC Capture Max Volume", DA7210_ALC_MAX, 0, 0x3F, 0),
+	SOC_SINGLE("ALC Capture Min Volume", DA7210_ALC_MIN, 0, 0x3F, 0),
+	SOC_SINGLE("ALC Capture Noise Volume", DA7210_ALC_NOIS, 0, 0x3F, 0),
+	SOC_SINGLE("ALC Capture Attack Rate", DA7210_ALC_ATT, 0, 0xFF, 0),
+	SOC_SINGLE("ALC Capture Release Rate", DA7210_ALC_REL, 0, 0xFF, 0),
+	SOC_SINGLE("ALC Capture Release Delay", DA7210_ALC_DEL, 0, 0xFF, 0),
+
+	SOC_SINGLE_EXT("Noise Suppression Enable Switch", DA7210_CONTROL, 3, 1,
+		       0, snd_soc_get_volsw, da7210_put_noise_sup_sw),
+};
+
+/*
+ * DAPM Controls
+ *
+ * Current DAPM implementation covers almost all codec components e.g. IOs,
+ * mixers, PGAs,ADC and DAC.
+ */
+/* In Mixer Left */
+static const struct snd_kcontrol_new da7210_dapm_inmixl_controls[] = {
+	SOC_DAPM_SINGLE("Mic Left Switch", DA7210_INMIX_L, 0, 1, 0),
+	SOC_DAPM_SINGLE("Mic Right Switch", DA7210_INMIX_L, 1, 1, 0),
+	SOC_DAPM_SINGLE("Aux1 Left Switch", DA7210_INMIX_L, 2, 1, 0),
+	SOC_DAPM_SINGLE("Aux2 Switch", DA7210_INMIX_L, 3, 1, 0),
+	SOC_DAPM_SINGLE("Outmix Left Switch", DA7210_INMIX_L, 4, 1, 0),
+};
+
+/* In Mixer Right */
+static const struct snd_kcontrol_new da7210_dapm_inmixr_controls[] = {
+	SOC_DAPM_SINGLE("Mic Right Switch", DA7210_INMIX_R, 0, 1, 0),
+	SOC_DAPM_SINGLE("Mic Left Switch", DA7210_INMIX_R, 1, 1, 0),
+	SOC_DAPM_SINGLE("Aux1 Right Switch", DA7210_INMIX_R, 2, 1, 0),
+	SOC_DAPM_SINGLE("Aux2 Switch", DA7210_INMIX_R, 3, 1, 0),
+	SOC_DAPM_SINGLE("Outmix Right Switch", DA7210_INMIX_R, 4, 1, 0),
+};
+
+/* Out Mixer Left */
+static const struct snd_kcontrol_new da7210_dapm_outmixl_controls[] = {
+	SOC_DAPM_SINGLE("Aux1 Left Switch", DA7210_OUTMIX_L, 0, 1, 0),
+	SOC_DAPM_SINGLE("Aux2 Switch", DA7210_OUTMIX_L, 1, 1, 0),
+	SOC_DAPM_SINGLE("INPGA Left Switch", DA7210_OUTMIX_L, 2, 1, 0),
+	SOC_DAPM_SINGLE("INPGA Right Switch", DA7210_OUTMIX_L, 3, 1, 0),
+	SOC_DAPM_SINGLE("DAC Left Switch", DA7210_OUTMIX_L, 4, 1, 0),
+};
+
+/* Out Mixer Right */
+static const struct snd_kcontrol_new da7210_dapm_outmixr_controls[] = {
+	SOC_DAPM_SINGLE("Aux1 Right Switch", DA7210_OUTMIX_R, 0, 1, 0),
+	SOC_DAPM_SINGLE("Aux2 Switch", DA7210_OUTMIX_R, 1, 1, 0),
+	SOC_DAPM_SINGLE("INPGA Left Switch", DA7210_OUTMIX_R, 2, 1, 0),
+	SOC_DAPM_SINGLE("INPGA Right Switch", DA7210_OUTMIX_R, 3, 1, 0),
+	SOC_DAPM_SINGLE("DAC Right Switch", DA7210_OUTMIX_R, 4, 1, 0),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new da7210_dapm_monomix_controls[] = {
+	SOC_DAPM_SINGLE("INPGA Right Switch", DA7210_OUT2, 3, 1, 0),
+	SOC_DAPM_SINGLE("INPGA Left Switch", DA7210_OUT2, 4, 1, 0),
+	SOC_DAPM_SINGLE("Outmix Right Switch", DA7210_OUT2, 5, 1, 0),
+	SOC_DAPM_SINGLE("Outmix Left Switch", DA7210_OUT2, 6, 1, 0),
+};
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget da7210_dapm_widgets[] = {
+	/* Input Side */
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("MICL"),
+	SND_SOC_DAPM_INPUT("MICR"),
+	SND_SOC_DAPM_INPUT("AUX1L"),
+	SND_SOC_DAPM_INPUT("AUX1R"),
+	SND_SOC_DAPM_INPUT("AUX2"),
+
+	/* Input PGAs */
+	SND_SOC_DAPM_PGA("Mic Left", DA7210_STARTUP3, 0, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Mic Right", DA7210_STARTUP3, 1, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Aux1 Left", DA7210_STARTUP3, 2, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Aux1 Right", DA7210_STARTUP3, 3, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Aux2 Mono", DA7210_STARTUP3, 4, 1, NULL, 0),
+
+	SND_SOC_DAPM_PGA("INPGA Left", DA7210_INMIX_L, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INPGA Right", DA7210_INMIX_R, 7, 0, NULL, 0),
+
+	/* MICBIAS */
+	SND_SOC_DAPM_SUPPLY("Mic Bias", DA7210_MIC_L, 6, 0, NULL, 0),
+
+	/* Input Mixers */
+	SND_SOC_DAPM_MIXER("In Mixer Left", SND_SOC_NOPM, 0, 0,
+		&da7210_dapm_inmixl_controls[0],
+		ARRAY_SIZE(da7210_dapm_inmixl_controls)),
+
+	SND_SOC_DAPM_MIXER("In Mixer Right", SND_SOC_NOPM, 0, 0,
+		&da7210_dapm_inmixr_controls[0],
+		ARRAY_SIZE(da7210_dapm_inmixr_controls)),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC Left", "Capture", DA7210_STARTUP3, 5, 1),
+	SND_SOC_DAPM_ADC("ADC Right", "Capture", DA7210_STARTUP3, 6, 1),
+
+	/* Output Side */
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC Left", "Playback", DA7210_STARTUP2, 5, 1),
+	SND_SOC_DAPM_DAC("DAC Right", "Playback", DA7210_STARTUP2, 6, 1),
+
+	/* Output Mixers */
+	SND_SOC_DAPM_MIXER("Out Mixer Left", SND_SOC_NOPM, 0, 0,
+		&da7210_dapm_outmixl_controls[0],
+		ARRAY_SIZE(da7210_dapm_outmixl_controls)),
+
+	SND_SOC_DAPM_MIXER("Out Mixer Right", SND_SOC_NOPM, 0, 0,
+		&da7210_dapm_outmixr_controls[0],
+		ARRAY_SIZE(da7210_dapm_outmixr_controls)),
+
+	SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
+		&da7210_dapm_monomix_controls[0],
+		ARRAY_SIZE(da7210_dapm_monomix_controls)),
+
+	/* Output PGAs */
+	SND_SOC_DAPM_PGA("OUTPGA Left Enable", DA7210_OUTMIX_L, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OUTPGA Right Enable", DA7210_OUTMIX_R, 7, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Out1 Left", DA7210_STARTUP2, 0, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Out1 Right", DA7210_STARTUP2, 1, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Out2 Mono", DA7210_STARTUP2, 2, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Headphone Left", DA7210_STARTUP2, 3, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Headphone Right", DA7210_STARTUP2, 4, 1, NULL, 0),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("OUT1L"),
+	SND_SOC_DAPM_OUTPUT("OUT1R"),
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("OUT2"),
+};
+
+/* DAPM audio route definition */
+static const struct snd_soc_dapm_route da7210_audio_map[] = {
+	/* Dest       Connecting Widget    source */
+	/* Input path */
+	{"Mic Left", NULL, "MICL"},
+	{"Mic Right", NULL, "MICR"},
+	{"Aux1 Left", NULL, "AUX1L"},
+	{"Aux1 Right", NULL, "AUX1R"},
+	{"Aux2 Mono", NULL, "AUX2"},
+
+	{"In Mixer Left", "Mic Left Switch", "Mic Left"},
+	{"In Mixer Left", "Mic Right Switch", "Mic Right"},
+	{"In Mixer Left", "Aux1 Left Switch", "Aux1 Left"},
+	{"In Mixer Left", "Aux2 Switch", "Aux2 Mono"},
+	{"In Mixer Left", "Outmix Left Switch", "Out Mixer Left"},
+
+	{"In Mixer Right", "Mic Right Switch", "Mic Right"},
+	{"In Mixer Right", "Mic Left Switch", "Mic Left"},
+	{"In Mixer Right", "Aux1 Right Switch", "Aux1 Right"},
+	{"In Mixer Right", "Aux2 Switch", "Aux2 Mono"},
+	{"In Mixer Right", "Outmix Right Switch", "Out Mixer Right"},
+
+	{"INPGA Left", NULL, "In Mixer Left"},
+	{"ADC Left", NULL, "INPGA Left"},
+
+	{"INPGA Right", NULL, "In Mixer Right"},
+	{"ADC Right", NULL, "INPGA Right"},
+
+	/* Output path */
+	{"Out Mixer Left", "Aux1 Left Switch", "Aux1 Left"},
+	{"Out Mixer Left", "Aux2 Switch", "Aux2 Mono"},
+	{"Out Mixer Left", "INPGA Left Switch", "INPGA Left"},
+	{"Out Mixer Left", "INPGA Right Switch", "INPGA Right"},
+	{"Out Mixer Left", "DAC Left Switch", "DAC Left"},
+
+	{"Out Mixer Right", "Aux1 Right Switch", "Aux1 Right"},
+	{"Out Mixer Right", "Aux2 Switch", "Aux2 Mono"},
+	{"Out Mixer Right", "INPGA Right Switch", "INPGA Right"},
+	{"Out Mixer Right", "INPGA Left Switch", "INPGA Left"},
+	{"Out Mixer Right", "DAC Right Switch", "DAC Right"},
+
+	{"Mono Mixer", "INPGA Right Switch", "INPGA Right"},
+	{"Mono Mixer", "INPGA Left Switch", "INPGA Left"},
+	{"Mono Mixer", "Outmix Right Switch", "Out Mixer Right"},
+	{"Mono Mixer", "Outmix Left Switch", "Out Mixer Left"},
+
+	{"OUTPGA Left Enable", NULL, "Out Mixer Left"},
+	{"OUTPGA Right Enable", NULL, "Out Mixer Right"},
+
+	{"Out1 Left", NULL, "OUTPGA Left Enable"},
+	{"OUT1L", NULL, "Out1 Left"},
+
+	{"Out1 Right", NULL, "OUTPGA Right Enable"},
+	{"OUT1R", NULL, "Out1 Right"},
+
+	{"Headphone Left", NULL, "OUTPGA Left Enable"},
+	{"HPL", NULL, "Headphone Left"},
+
+	{"Headphone Right", NULL, "OUTPGA Right Enable"},
+	{"HPR", NULL, "Headphone Right"},
+
+	{"Out2 Mono", NULL, "Mono Mixer"},
+	{"OUT2", NULL, "Out2 Mono"},
+};
+
+/* Codec private data */
+struct da7210_priv {
+	struct regmap *regmap;
+	unsigned int mclk_rate;
+	int master;
+};
+
+static const struct reg_default da7210_reg_defaults[] = {
+	{ 0x00, 0x00 },
+	{ 0x01, 0x11 },
+	{ 0x03, 0x00 },
+	{ 0x04, 0x00 },
+	{ 0x05, 0x00 },
+	{ 0x06, 0x00 },
+	{ 0x07, 0x00 },
+	{ 0x08, 0x00 },
+	{ 0x09, 0x00 },
+	{ 0x0a, 0x00 },
+	{ 0x0b, 0x00 },
+	{ 0x0c, 0x00 },
+	{ 0x0d, 0x00 },
+	{ 0x0e, 0x00 },
+	{ 0x0f, 0x08 },
+	{ 0x10, 0x00 },
+	{ 0x11, 0x00 },
+	{ 0x12, 0x00 },
+	{ 0x13, 0x00 },
+	{ 0x14, 0x08 },
+	{ 0x15, 0x10 },
+	{ 0x16, 0x10 },
+	{ 0x17, 0x54 },
+	{ 0x18, 0x40 },
+	{ 0x19, 0x00 },
+	{ 0x1a, 0x00 },
+	{ 0x1b, 0x00 },
+	{ 0x1c, 0x00 },
+	{ 0x1d, 0x00 },
+	{ 0x1e, 0x00 },
+	{ 0x1f, 0x00 },
+	{ 0x20, 0x00 },
+	{ 0x21, 0x00 },
+	{ 0x22, 0x00 },
+	{ 0x23, 0x02 },
+	{ 0x24, 0x00 },
+	{ 0x25, 0x76 },
+	{ 0x26, 0x00 },
+	{ 0x27, 0x00 },
+	{ 0x28, 0x04 },
+	{ 0x29, 0x00 },
+	{ 0x2a, 0x00 },
+	{ 0x2b, 0x30 },
+	{ 0x2c, 0x2A },
+	{ 0x83, 0x00 },
+	{ 0x84, 0x00 },
+	{ 0x85, 0x00 },
+	{ 0x86, 0x00 },
+	{ 0x87, 0x00 },
+	{ 0x88, 0x00 },
+};
+
+static bool da7210_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case DA7210_A_HID_UNLOCK:
+	case DA7210_A_TEST_UNLOCK:
+	case DA7210_A_PLL1:
+	case DA7210_A_CP_MODE:
+		return false;
+	default:
+		return true;
+	}
+}
+
+static bool da7210_volatile_register(struct device *dev,
+				    unsigned int reg)
+{
+	switch (reg) {
+	case DA7210_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/*
+ * Set PCM DAI word length.
+ */
+static int da7210_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct da7210_priv *da7210 = snd_soc_component_get_drvdata(component);
+	u32 dai_cfg1;
+	u32 fs, sysclk;
+
+	/* set DAI source to Left and Right ADC */
+	snd_soc_component_write(component, DA7210_DAI_SRC_SEL,
+		     DA7210_DAI_OUT_R_SRC | DA7210_DAI_OUT_L_SRC);
+
+	/* Enable DAI */
+	snd_soc_component_write(component, DA7210_DAI_CFG3, DA7210_DAI_OE | DA7210_DAI_EN);
+
+	dai_cfg1 = 0xFC & snd_soc_component_read32(component, DA7210_DAI_CFG1);
+
+	switch (params_width(params)) {
+	case 16:
+		dai_cfg1 |= DA7210_DAI_WORD_S16_LE;
+		break;
+	case 20:
+		dai_cfg1 |= DA7210_DAI_WORD_S20_3LE;
+		break;
+	case 24:
+		dai_cfg1 |= DA7210_DAI_WORD_S24_LE;
+		break;
+	case 32:
+		dai_cfg1 |= DA7210_DAI_WORD_S32_LE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, DA7210_DAI_CFG1, dai_cfg1);
+
+	switch (params_rate(params)) {
+	case 8000:
+		fs		= DA7210_PLL_FS_8000;
+		sysclk		= 3072000;
+		break;
+	case 11025:
+		fs		= DA7210_PLL_FS_11025;
+		sysclk		= 2822400;
+		break;
+	case 12000:
+		fs		= DA7210_PLL_FS_12000;
+		sysclk		= 3072000;
+		break;
+	case 16000:
+		fs		= DA7210_PLL_FS_16000;
+		sysclk		= 3072000;
+		break;
+	case 22050:
+		fs		= DA7210_PLL_FS_22050;
+		sysclk		= 2822400;
+		break;
+	case 32000:
+		fs		= DA7210_PLL_FS_32000;
+		sysclk		= 3072000;
+		break;
+	case 44100:
+		fs		= DA7210_PLL_FS_44100;
+		sysclk		= 2822400;
+		break;
+	case 48000:
+		fs		= DA7210_PLL_FS_48000;
+		sysclk		= 3072000;
+		break;
+	case 88200:
+		fs		= DA7210_PLL_FS_88200;
+		sysclk		= 2822400;
+		break;
+	case 96000:
+		fs		= DA7210_PLL_FS_96000;
+		sysclk		= 3072000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Disable active mode */
+	snd_soc_component_update_bits(component, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
+
+	snd_soc_component_update_bits(component, DA7210_PLL, DA7210_PLL_FS_MASK, fs);
+
+	if (da7210->mclk_rate && (da7210->mclk_rate != sysclk)) {
+		/* PLL mode, disable PLL bypass */
+		snd_soc_component_update_bits(component, DA7210_PLL_DIV3, DA7210_PLL_BYP, 0);
+
+		if (!da7210->master) {
+			/* PLL slave mode, also enable SRM */
+			snd_soc_component_update_bits(component, DA7210_PLL,
+						   (DA7210_MCLK_SRM_EN |
+						    DA7210_MCLK_DET_EN),
+						   (DA7210_MCLK_SRM_EN |
+						    DA7210_MCLK_DET_EN));
+		}
+	} else {
+		/* PLL bypass mode, enable PLL bypass and Auto Detection */
+		snd_soc_component_update_bits(component, DA7210_PLL, DA7210_MCLK_DET_EN,
+						       DA7210_MCLK_DET_EN);
+		snd_soc_component_update_bits(component, DA7210_PLL_DIV3, DA7210_PLL_BYP,
+							    DA7210_PLL_BYP);
+	}
+	/* Enable active mode */
+	snd_soc_component_update_bits(component, DA7210_STARTUP1,
+			    DA7210_SC_MST_EN, DA7210_SC_MST_EN);
+
+	return 0;
+}
+
+/*
+ * Set DAI mode and Format
+ */
+static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7210_priv *da7210 = snd_soc_component_get_drvdata(component);
+	u32 dai_cfg1;
+	u32 dai_cfg3;
+
+	dai_cfg1 = 0x7f & snd_soc_component_read32(component, DA7210_DAI_CFG1);
+	dai_cfg3 = 0xfc & snd_soc_component_read32(component, DA7210_DAI_CFG3);
+
+	if ((snd_soc_component_read32(component, DA7210_PLL) & DA7210_PLL_EN) &&
+		(!(snd_soc_component_read32(component, DA7210_PLL_DIV3) & DA7210_PLL_BYP)))
+		return -EINVAL;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		da7210->master = 1;
+		dai_cfg1 |= DA7210_DAI_MODE_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		da7210->master = 0;
+		dai_cfg1 |= DA7210_DAI_MODE_SLAVE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* FIXME
+	 *
+	 * It support I2S only now
+	 */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		dai_cfg3 |= DA7210_DAI_FORMAT_I2SMODE;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		dai_cfg3 |= DA7210_DAI_FORMAT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		dai_cfg3 |= DA7210_DAI_FORMAT_RIGHT_J;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* FIXME
+	 *
+	 * It support 64bit data transmission only now
+	 */
+	dai_cfg1 |= DA7210_DAI_FLEN_64BIT;
+
+	snd_soc_component_write(component, DA7210_DAI_CFG1, dai_cfg1);
+	snd_soc_component_write(component, DA7210_DAI_CFG3, dai_cfg3);
+
+	return 0;
+}
+
+static int da7210_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 mute_reg = snd_soc_component_read32(component, DA7210_DAC_HPF) & 0xFB;
+
+	if (mute)
+		snd_soc_component_write(component, DA7210_DAC_HPF, mute_reg | 0x4);
+	else
+		snd_soc_component_write(component, DA7210_DAC_HPF, mute_reg);
+	return 0;
+}
+
+#define DA7210_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static int da7210_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7210_priv *da7210 = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case DA7210_CLKSRC_MCLK:
+		switch (freq) {
+		case 12000000:
+		case 13000000:
+		case 13500000:
+		case 14400000:
+		case 19200000:
+		case 19680000:
+		case 19800000:
+			da7210->mclk_rate = freq;
+			return 0;
+		default:
+			dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+				freq);
+			return -EINVAL;
+		}
+		break;
+	default:
+		dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+		return -EINVAL;
+	}
+}
+
+/**
+ * da7210_set_dai_pll	:Configure the codec PLL
+ * @param codec_dai	: pointer to codec DAI
+ * @param pll_id	: da7210 has only one pll, so pll_id is always zero
+ * @param fref		: MCLK frequency, should be < 20MHz
+ * @param fout		: FsDM value, Refer page 44 & 45 of datasheet
+ * @return int		: Zero for success, negative error code for error
+ *
+ * Note: Supported PLL input frequencies are 12MHz, 13MHz, 13.5MHz, 14.4MHz,
+ *       19.2MHz, 19.6MHz and 19.8MHz
+ */
+static int da7210_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+			      int source, unsigned int fref, unsigned int fout)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7210_priv *da7210 = snd_soc_component_get_drvdata(component);
+
+	u8 pll_div1, pll_div2, pll_div3, cnt;
+
+	/* In slave mode, there is only one set of divisors */
+	if (!da7210->master)
+		fout = 2822400;
+
+	/* Search pll div array for correct divisors */
+	for (cnt = 0; cnt < ARRAY_SIZE(da7210_pll_div); cnt++) {
+		/* check fref, mode  and fout */
+		if ((fref == da7210_pll_div[cnt].fref) &&
+		    (da7210->master ==  da7210_pll_div[cnt].mode) &&
+		    (fout == da7210_pll_div[cnt].fout)) {
+			/* all match, pick up divisors */
+			pll_div1 = da7210_pll_div[cnt].div1;
+			pll_div2 = da7210_pll_div[cnt].div2;
+			pll_div3 = da7210_pll_div[cnt].div3;
+			break;
+		}
+	}
+	if (cnt >= ARRAY_SIZE(da7210_pll_div))
+		goto err;
+
+	/* Disable active mode */
+	snd_soc_component_update_bits(component, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
+	/* Write PLL dividers */
+	snd_soc_component_write(component, DA7210_PLL_DIV1, pll_div1);
+	snd_soc_component_write(component, DA7210_PLL_DIV2, pll_div2);
+	snd_soc_component_update_bits(component, DA7210_PLL_DIV3,
+				   DA7210_PLL_DIV_L_MASK, pll_div3);
+
+	/* Enable PLL */
+	snd_soc_component_update_bits(component, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
+
+	/* Enable active mode */
+	snd_soc_component_update_bits(component, DA7210_STARTUP1, DA7210_SC_MST_EN,
+						    DA7210_SC_MST_EN);
+	return 0;
+err:
+	dev_err(codec_dai->dev, "Unsupported PLL input frequency %d\n", fref);
+	return -EINVAL;
+}
+
+/* DAI operations */
+static const struct snd_soc_dai_ops da7210_dai_ops = {
+	.hw_params	= da7210_hw_params,
+	.set_fmt	= da7210_set_dai_fmt,
+	.set_sysclk	= da7210_set_dai_sysclk,
+	.set_pll	= da7210_set_dai_pll,
+	.digital_mute	= da7210_mute,
+};
+
+static struct snd_soc_dai_driver da7210_dai = {
+	.name = "da7210-hifi",
+	/* playback capabilities */
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = DA7210_FORMATS,
+	},
+	/* capture capabilities */
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = DA7210_FORMATS,
+	},
+	.ops = &da7210_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int da7210_probe(struct snd_soc_component *component)
+{
+	struct da7210_priv *da7210 = snd_soc_component_get_drvdata(component);
+
+	dev_info(component->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
+
+	da7210->mclk_rate       = 0;    /* This will be set from set_sysclk() */
+	da7210->master          = 0;    /* This will be set from set_fmt() */
+
+	/* Enable internal regulator & bias current */
+	snd_soc_component_write(component, DA7210_CONTROL, DA7210_REG_EN | DA7210_BIAS_EN);
+
+	/*
+	 * ADC settings
+	 */
+
+	/* Enable Left & Right MIC PGA and Mic Bias */
+	snd_soc_component_write(component, DA7210_MIC_L, DA7210_MIC_L_EN | DA7210_MICBIAS_EN);
+	snd_soc_component_write(component, DA7210_MIC_R, DA7210_MIC_R_EN);
+
+	/* Enable Left and Right input PGA */
+	snd_soc_component_write(component, DA7210_INMIX_L, DA7210_IN_L_EN);
+	snd_soc_component_write(component, DA7210_INMIX_R, DA7210_IN_R_EN);
+
+	/* Enable Left and Right ADC */
+	snd_soc_component_write(component, DA7210_ADC, DA7210_ADC_L_EN | DA7210_ADC_R_EN);
+
+	/*
+	 * DAC settings
+	 */
+
+	/* Enable Left and Right DAC */
+	snd_soc_component_write(component, DA7210_DAC_SEL,
+		     DA7210_DAC_L_SRC_DAI_L | DA7210_DAC_L_EN |
+		     DA7210_DAC_R_SRC_DAI_R | DA7210_DAC_R_EN);
+
+	/* Enable Left and Right out PGA */
+	snd_soc_component_write(component, DA7210_OUTMIX_L, DA7210_OUT_L_EN);
+	snd_soc_component_write(component, DA7210_OUTMIX_R, DA7210_OUT_R_EN);
+
+	/* Enable Left and Right HeadPhone PGA */
+	snd_soc_component_write(component, DA7210_HP_CFG,
+		     DA7210_HP_2CAP_MODE | DA7210_HP_SENSE_EN |
+		     DA7210_HP_L_EN | DA7210_HP_MODE | DA7210_HP_R_EN);
+
+	/* Enable ramp mode for DAC gain update */
+	snd_soc_component_write(component, DA7210_SOFTMUTE, DA7210_RAMP_EN);
+
+	/*
+	 * For DA7210 codec, there are two ways to enable/disable analog IOs
+	 * and ADC/DAC,
+	 * (1) Using "Enable Bit" of register associated with that IO
+	 * (or ADC/DAC)
+	 *	e.g. Mic Left can be enabled using bit 7 of MIC_L(0x7) reg
+	 *
+	 * (2) Using "Standby Bit" of STARTUP2 or STARTUP3 register
+	 *	e.g. Mic left can be put to STANDBY using bit 0 of STARTUP3(0x5)
+	 *
+	 * Out of these two methods, the one using STANDBY bits is preferred
+	 * way to enable/disable individual blocks. This is because STANDBY
+	 * registers are part of system controller which allows system power
+	 * up/down in a controlled, pop-free manner. Also, as per application
+	 * note of DA7210, STANDBY register bits are only effective if a
+	 * particular IO (or ADC/DAC) is already enabled using enable/disable
+	 * register bits. Keeping these things in mind, current DAPM
+	 * implementation manipulates only STANDBY bits.
+	 *
+	 * Overall implementation can be outlined as below,
+	 *
+	 * - "Enable bit" of an IO or ADC/DAC is used to enable it in probe()
+	 * - "STANDBY bit" is controlled by DAPM
+	 */
+
+	/* Enable Line out amplifiers */
+	snd_soc_component_write(component, DA7210_OUT1_L, DA7210_OUT1_L_EN);
+	snd_soc_component_write(component, DA7210_OUT1_R, DA7210_OUT1_R_EN);
+	snd_soc_component_write(component, DA7210_OUT2, DA7210_OUT2_EN |
+		     DA7210_OUT2_OUTMIX_L | DA7210_OUT2_OUTMIX_R);
+
+	/* Enable Aux1 */
+	snd_soc_component_write(component, DA7210_AUX1_L, DA7210_AUX1_L_EN);
+	snd_soc_component_write(component, DA7210_AUX1_R, DA7210_AUX1_R_EN);
+	/* Enable Aux2 */
+	snd_soc_component_write(component, DA7210_AUX2, DA7210_AUX2_EN);
+
+	/* Set PLL Master clock range 10-20 MHz, enable PLL bypass */
+	snd_soc_component_write(component, DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ |
+					      DA7210_PLL_BYP);
+
+	/* Diable PLL and bypass it */
+	snd_soc_component_write(component, DA7210_PLL, DA7210_PLL_FS_48000);
+
+	/* Activate all enabled subsystem */
+	snd_soc_component_write(component, DA7210_STARTUP1, DA7210_SC_MST_EN);
+
+	dev_info(component->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_da7210 = {
+	.probe			= da7210_probe,
+	.controls		= da7210_snd_controls,
+	.num_controls		= ARRAY_SIZE(da7210_snd_controls),
+	.dapm_widgets		= da7210_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(da7210_dapm_widgets),
+	.dapm_routes		= da7210_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(da7210_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+#if IS_ENABLED(CONFIG_I2C)
+
+static const struct reg_sequence da7210_regmap_i2c_patch[] = {
+
+	/* System controller master disable */
+	{ DA7210_STARTUP1, 0x00 },
+	/* Set PLL Master clock range 10-20 MHz */
+	{ DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ },
+
+	/* to unlock */
+	{ DA7210_A_HID_UNLOCK, 0x8B},
+	{ DA7210_A_TEST_UNLOCK, 0xB4},
+	{ DA7210_A_PLL1, 0x01},
+	{ DA7210_A_CP_MODE, 0x7C},
+	/* to re-lock */
+	{ DA7210_A_HID_UNLOCK, 0x00},
+	{ DA7210_A_TEST_UNLOCK, 0x00},
+};
+
+static const struct regmap_config da7210_regmap_config_i2c = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.reg_defaults = da7210_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(da7210_reg_defaults),
+	.volatile_reg = da7210_volatile_register,
+	.readable_reg = da7210_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int da7210_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct da7210_priv *da7210;
+	int ret;
+
+	da7210 = devm_kzalloc(&i2c->dev, sizeof(struct da7210_priv),
+			      GFP_KERNEL);
+	if (!da7210)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, da7210);
+
+	da7210->regmap = devm_regmap_init_i2c(i2c, &da7210_regmap_config_i2c);
+	if (IS_ERR(da7210->regmap)) {
+		ret = PTR_ERR(da7210->regmap);
+		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_register_patch(da7210->regmap, da7210_regmap_i2c_patch,
+				    ARRAY_SIZE(da7210_regmap_i2c_patch));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	ret =  devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_da7210, &da7210_dai, 1);
+	if (ret < 0)
+		dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
+
+	return ret;
+}
+
+static const struct i2c_device_id da7210_i2c_id[] = {
+	{ "da7210", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, da7210_i2c_id);
+
+/* I2C codec control layer */
+static struct i2c_driver da7210_i2c_driver = {
+	.driver = {
+		.name = "da7210",
+	},
+	.probe		= da7210_i2c_probe,
+	.id_table	= da7210_i2c_id,
+};
+#endif
+
+#if defined(CONFIG_SPI_MASTER)
+
+static const struct reg_sequence da7210_regmap_spi_patch[] = {
+	/* Dummy read to give two pulses over nCS for SPI */
+	{ DA7210_AUX2, 0x00 },
+	{ DA7210_AUX2, 0x00 },
+
+	/* System controller master disable */
+	{ DA7210_STARTUP1, 0x00 },
+	/* Set PLL Master clock range 10-20 MHz */
+	{ DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ },
+
+	/* to set PAGE1 of SPI register space */
+	{ DA7210_PAGE_CONTROL, 0x80 },
+	/* to unlock */
+	{ DA7210_A_HID_UNLOCK, 0x8B},
+	{ DA7210_A_TEST_UNLOCK, 0xB4},
+	{ DA7210_A_PLL1, 0x01},
+	{ DA7210_A_CP_MODE, 0x7C},
+	/* to re-lock */
+	{ DA7210_A_HID_UNLOCK, 0x00},
+	{ DA7210_A_TEST_UNLOCK, 0x00},
+	/* to set back PAGE0 of SPI register space */
+	{ DA7210_PAGE_CONTROL, 0x00 },
+};
+
+static const struct regmap_config da7210_regmap_config_spi = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.read_flag_mask = 0x01,
+	.write_flag_mask = 0x00,
+
+	.reg_defaults = da7210_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(da7210_reg_defaults),
+	.volatile_reg = da7210_volatile_register,
+	.readable_reg = da7210_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int da7210_spi_probe(struct spi_device *spi)
+{
+	struct da7210_priv *da7210;
+	int ret;
+
+	da7210 = devm_kzalloc(&spi->dev, sizeof(struct da7210_priv),
+			      GFP_KERNEL);
+	if (!da7210)
+		return -ENOMEM;
+
+	spi_set_drvdata(spi, da7210);
+	da7210->regmap = devm_regmap_init_spi(spi, &da7210_regmap_config_spi);
+	if (IS_ERR(da7210->regmap)) {
+		ret = PTR_ERR(da7210->regmap);
+		dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_register_patch(da7210->regmap, da7210_regmap_spi_patch,
+				    ARRAY_SIZE(da7210_regmap_spi_patch));
+	if (ret != 0)
+		dev_warn(&spi->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_da7210, &da7210_dai, 1);
+
+	return ret;
+}
+
+static struct spi_driver da7210_spi_driver = {
+	.driver = {
+		.name = "da7210",
+	},
+	.probe = da7210_spi_probe,
+};
+#endif
+
+static int __init da7210_modinit(void)
+{
+	int ret = 0;
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&da7210_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&da7210_spi_driver);
+	if (ret) {
+		printk(KERN_ERR "Failed to register da7210 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return ret;
+}
+module_init(da7210_modinit);
+
+static void __exit da7210_exit(void)
+{
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&da7210_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&da7210_spi_driver);
+#endif
+}
+module_exit(da7210_exit);
+
+MODULE_DESCRIPTION("ASoC DA7210 driver");
+MODULE_AUTHOR("David Chen, Kuninori Morimoto");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
new file mode 100644
index 0000000..92d006a
--- /dev/null
+++ b/sound/soc/codecs/da7213.c
@@ -0,0 +1,1900 @@
+/*
+ * DA7213 ALSA SoC Codec Driver
+ *
+ * Copyright (c) 2013 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ * Based on DA9055 ALSA SoC codec driver.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/acpi.h>
+#include <linux/of_device.h>
+#include <linux/property.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <sound/da7213.h>
+#include "da7213.h"
+
+
+/* Gain and Volume */
+static const DECLARE_TLV_DB_RANGE(aux_vol_tlv,
+	/* -54dB */
+	0x0, 0x11, TLV_DB_SCALE_ITEM(-5400, 0, 0),
+	/* -52.5dB to 15dB */
+	0x12, 0x3f, TLV_DB_SCALE_ITEM(-5250, 150, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(digital_gain_tlv,
+	0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+	/* -78dB to 12dB */
+	0x08, 0x7f, TLV_DB_SCALE_ITEM(-7800, 75, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(alc_analog_gain_tlv,
+	0x0, 0x0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+	/* 0dB to 36dB */
+	0x01, 0x07, TLV_DB_SCALE_ITEM(0, 600, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(mixin_gain_tlv, -450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lineout_vol_tlv, -4800, 100, 0);
+static const DECLARE_TLV_DB_SCALE(alc_threshold_tlv, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(alc_gain_tlv, 0, 600, 0);
+
+/* ADC and DAC voice mode (8kHz) high pass cutoff value */
+static const char * const da7213_voice_hpf_corner_txt[] = {
+	"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7213_dac_voice_hpf_corner,
+			    DA7213_DAC_FILTERS1,
+			    DA7213_VOICE_HPF_CORNER_SHIFT,
+			    da7213_voice_hpf_corner_txt);
+
+static SOC_ENUM_SINGLE_DECL(da7213_adc_voice_hpf_corner,
+			    DA7213_ADC_FILTERS1,
+			    DA7213_VOICE_HPF_CORNER_SHIFT,
+			    da7213_voice_hpf_corner_txt);
+
+/* ADC and DAC high pass filter cutoff value */
+static const char * const da7213_audio_hpf_corner_txt[] = {
+	"Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7213_dac_audio_hpf_corner,
+			    DA7213_DAC_FILTERS1
+			    , DA7213_AUDIO_HPF_CORNER_SHIFT,
+			    da7213_audio_hpf_corner_txt);
+
+static SOC_ENUM_SINGLE_DECL(da7213_adc_audio_hpf_corner,
+			    DA7213_ADC_FILTERS1,
+			    DA7213_AUDIO_HPF_CORNER_SHIFT,
+			    da7213_audio_hpf_corner_txt);
+
+/* Gain ramping rate value */
+static const char * const da7213_gain_ramp_rate_txt[] = {
+	"nominal rate * 8", "nominal rate * 16", "nominal rate / 16",
+	"nominal rate / 32"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7213_gain_ramp_rate,
+			    DA7213_GAIN_RAMP_CTRL,
+			    DA7213_GAIN_RAMP_RATE_SHIFT,
+			    da7213_gain_ramp_rate_txt);
+
+/* DAC noise gate setup time value */
+static const char * const da7213_dac_ng_setup_time_txt[] = {
+	"256 samples", "512 samples", "1024 samples", "2048 samples"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_setup_time,
+			    DA7213_DAC_NG_SETUP_TIME,
+			    DA7213_DAC_NG_SETUP_TIME_SHIFT,
+			    da7213_dac_ng_setup_time_txt);
+
+/* DAC noise gate rampup rate value */
+static const char * const da7213_dac_ng_rampup_txt[] = {
+	"0.02 ms/dB", "0.16 ms/dB"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_rampup_rate,
+			    DA7213_DAC_NG_SETUP_TIME,
+			    DA7213_DAC_NG_RAMPUP_RATE_SHIFT,
+			    da7213_dac_ng_rampup_txt);
+
+/* DAC noise gate rampdown rate value */
+static const char * const da7213_dac_ng_rampdown_txt[] = {
+	"0.64 ms/dB", "20.48 ms/dB"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_rampdown_rate,
+			    DA7213_DAC_NG_SETUP_TIME,
+			    DA7213_DAC_NG_RAMPDN_RATE_SHIFT,
+			    da7213_dac_ng_rampdown_txt);
+
+/* DAC soft mute rate value */
+static const char * const da7213_dac_soft_mute_rate_txt[] = {
+	"1", "2", "4", "8", "16", "32", "64"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7213_dac_soft_mute_rate,
+			    DA7213_DAC_FILTERS5,
+			    DA7213_DAC_SOFTMUTE_RATE_SHIFT,
+			    da7213_dac_soft_mute_rate_txt);
+
+/* ALC Attack Rate select */
+static const char * const da7213_alc_attack_rate_txt[] = {
+	"44/fs", "88/fs", "176/fs", "352/fs", "704/fs", "1408/fs", "2816/fs",
+	"5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7213_alc_attack_rate,
+			    DA7213_ALC_CTRL2,
+			    DA7213_ALC_ATTACK_SHIFT,
+			    da7213_alc_attack_rate_txt);
+
+/* ALC Release Rate select */
+static const char * const da7213_alc_release_rate_txt[] = {
+	"176/fs", "352/fs", "704/fs", "1408/fs", "2816/fs", "5632/fs",
+	"11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7213_alc_release_rate,
+			    DA7213_ALC_CTRL2,
+			    DA7213_ALC_RELEASE_SHIFT,
+			    da7213_alc_release_rate_txt);
+
+/* ALC Hold Time select */
+static const char * const da7213_alc_hold_time_txt[] = {
+	"62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs",
+	"7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs",
+	"253952/fs", "507904/fs", "1015808/fs", "2031616/fs"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7213_alc_hold_time,
+			    DA7213_ALC_CTRL3,
+			    DA7213_ALC_HOLD_SHIFT,
+			    da7213_alc_hold_time_txt);
+
+/* ALC Input Signal Tracking rate select */
+static const char * const da7213_alc_integ_rate_txt[] = {
+	"1/4", "1/16", "1/256", "1/65536"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_attack_rate,
+			    DA7213_ALC_CTRL3,
+			    DA7213_ALC_INTEG_ATTACK_SHIFT,
+			    da7213_alc_integ_rate_txt);
+
+static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_release_rate,
+			    DA7213_ALC_CTRL3,
+			    DA7213_ALC_INTEG_RELEASE_SHIFT,
+			    da7213_alc_integ_rate_txt);
+
+
+/*
+ * Control Functions
+ */
+
+static int da7213_get_alc_data(struct snd_soc_component *component, u8 reg_val)
+{
+	int mid_data, top_data;
+	int sum = 0;
+	u8 iteration;
+
+	for (iteration = 0; iteration < DA7213_ALC_AVG_ITERATIONS;
+	     iteration++) {
+		/* Select the left or right channel and capture data */
+		snd_soc_component_write(component, DA7213_ALC_CIC_OP_LVL_CTRL, reg_val);
+
+		/* Select middle 8 bits for read back from data register */
+		snd_soc_component_write(component, DA7213_ALC_CIC_OP_LVL_CTRL,
+			      reg_val | DA7213_ALC_DATA_MIDDLE);
+		mid_data = snd_soc_component_read32(component, DA7213_ALC_CIC_OP_LVL_DATA);
+
+		/* Select top 8 bits for read back from data register */
+		snd_soc_component_write(component, DA7213_ALC_CIC_OP_LVL_CTRL,
+			      reg_val | DA7213_ALC_DATA_TOP);
+		top_data = snd_soc_component_read32(component, DA7213_ALC_CIC_OP_LVL_DATA);
+
+		sum += ((mid_data << 8) | (top_data << 16));
+	}
+
+	return sum / DA7213_ALC_AVG_ITERATIONS;
+}
+
+static void da7213_alc_calib_man(struct snd_soc_component *component)
+{
+	u8 reg_val;
+	int avg_left_data, avg_right_data, offset_l, offset_r;
+
+	/* Calculate average for Left and Right data */
+	/* Left Data */
+	avg_left_data = da7213_get_alc_data(component,
+			DA7213_ALC_CIC_OP_CHANNEL_LEFT);
+	/* Right Data */
+	avg_right_data = da7213_get_alc_data(component,
+			 DA7213_ALC_CIC_OP_CHANNEL_RIGHT);
+
+	/* Calculate DC offset */
+	offset_l = -avg_left_data;
+	offset_r = -avg_right_data;
+
+	reg_val = (offset_l & DA7213_ALC_OFFSET_15_8) >> 8;
+	snd_soc_component_write(component, DA7213_ALC_OFFSET_MAN_M_L, reg_val);
+	reg_val = (offset_l & DA7213_ALC_OFFSET_19_16) >> 16;
+	snd_soc_component_write(component, DA7213_ALC_OFFSET_MAN_U_L, reg_val);
+
+	reg_val = (offset_r & DA7213_ALC_OFFSET_15_8) >> 8;
+	snd_soc_component_write(component, DA7213_ALC_OFFSET_MAN_M_R, reg_val);
+	reg_val = (offset_r & DA7213_ALC_OFFSET_19_16) >> 16;
+	snd_soc_component_write(component, DA7213_ALC_OFFSET_MAN_U_R, reg_val);
+
+	/* Enable analog/digital gain mode & offset cancellation */
+	snd_soc_component_update_bits(component, DA7213_ALC_CTRL1,
+			    DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE,
+			    DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE);
+}
+
+static void da7213_alc_calib_auto(struct snd_soc_component *component)
+{
+	u8 alc_ctrl1;
+
+	/* Begin auto calibration and wait for completion */
+	snd_soc_component_update_bits(component, DA7213_ALC_CTRL1, DA7213_ALC_AUTO_CALIB_EN,
+			    DA7213_ALC_AUTO_CALIB_EN);
+	do {
+		alc_ctrl1 = snd_soc_component_read32(component, DA7213_ALC_CTRL1);
+	} while (alc_ctrl1 & DA7213_ALC_AUTO_CALIB_EN);
+
+	/* If auto calibration fails, fall back to digital gain only mode */
+	if (alc_ctrl1 & DA7213_ALC_CALIB_OVERFLOW) {
+		dev_warn(component->dev,
+			 "ALC auto calibration failed with overflow\n");
+		snd_soc_component_update_bits(component, DA7213_ALC_CTRL1,
+				    DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE,
+				    0);
+	} else {
+		/* Enable analog/digital gain mode & offset cancellation */
+		snd_soc_component_update_bits(component, DA7213_ALC_CTRL1,
+				    DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE,
+				    DA7213_ALC_OFFSET_EN | DA7213_ALC_SYNC_MODE);
+	}
+
+}
+
+static void da7213_alc_calib(struct snd_soc_component *component)
+{
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+	u8 adc_l_ctrl, adc_r_ctrl;
+	u8 mixin_l_sel, mixin_r_sel;
+	u8 mic_1_ctrl, mic_2_ctrl;
+
+	/* Save current values from ADC control registers */
+	adc_l_ctrl = snd_soc_component_read32(component, DA7213_ADC_L_CTRL);
+	adc_r_ctrl = snd_soc_component_read32(component, DA7213_ADC_R_CTRL);
+
+	/* Save current values from MIXIN_L/R_SELECT registers */
+	mixin_l_sel = snd_soc_component_read32(component, DA7213_MIXIN_L_SELECT);
+	mixin_r_sel = snd_soc_component_read32(component, DA7213_MIXIN_R_SELECT);
+
+	/* Save current values from MIC control registers */
+	mic_1_ctrl = snd_soc_component_read32(component, DA7213_MIC_1_CTRL);
+	mic_2_ctrl = snd_soc_component_read32(component, DA7213_MIC_2_CTRL);
+
+	/* Enable ADC Left and Right */
+	snd_soc_component_update_bits(component, DA7213_ADC_L_CTRL, DA7213_ADC_EN,
+			    DA7213_ADC_EN);
+	snd_soc_component_update_bits(component, DA7213_ADC_R_CTRL, DA7213_ADC_EN,
+			    DA7213_ADC_EN);
+
+	/* Enable MIC paths */
+	snd_soc_component_update_bits(component, DA7213_MIXIN_L_SELECT,
+			    DA7213_MIXIN_L_MIX_SELECT_MIC_1 |
+			    DA7213_MIXIN_L_MIX_SELECT_MIC_2,
+			    DA7213_MIXIN_L_MIX_SELECT_MIC_1 |
+			    DA7213_MIXIN_L_MIX_SELECT_MIC_2);
+	snd_soc_component_update_bits(component, DA7213_MIXIN_R_SELECT,
+			    DA7213_MIXIN_R_MIX_SELECT_MIC_2 |
+			    DA7213_MIXIN_R_MIX_SELECT_MIC_1,
+			    DA7213_MIXIN_R_MIX_SELECT_MIC_2 |
+			    DA7213_MIXIN_R_MIX_SELECT_MIC_1);
+
+	/* Mute MIC PGAs */
+	snd_soc_component_update_bits(component, DA7213_MIC_1_CTRL, DA7213_MUTE_EN,
+			    DA7213_MUTE_EN);
+	snd_soc_component_update_bits(component, DA7213_MIC_2_CTRL, DA7213_MUTE_EN,
+			    DA7213_MUTE_EN);
+
+	/* Perform calibration */
+	if (da7213->alc_calib_auto)
+		da7213_alc_calib_auto(component);
+	else
+		da7213_alc_calib_man(component);
+
+	/* Restore MIXIN_L/R_SELECT registers to their original states */
+	snd_soc_component_write(component, DA7213_MIXIN_L_SELECT, mixin_l_sel);
+	snd_soc_component_write(component, DA7213_MIXIN_R_SELECT, mixin_r_sel);
+
+	/* Restore ADC control registers to their original states */
+	snd_soc_component_write(component, DA7213_ADC_L_CTRL, adc_l_ctrl);
+	snd_soc_component_write(component, DA7213_ADC_R_CTRL, adc_r_ctrl);
+
+	/* Restore original values of MIC control registers */
+	snd_soc_component_write(component, DA7213_MIC_1_CTRL, mic_1_ctrl);
+	snd_soc_component_write(component, DA7213_MIC_2_CTRL, mic_2_ctrl);
+}
+
+static int da7213_put_mixin_gain(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
+
+	/* If ALC in operation, make sure calibrated offsets are updated */
+	if ((!ret) && (da7213->alc_en))
+		da7213_alc_calib(component);
+
+	return ret;
+}
+
+static int da7213_put_alc_sw(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+
+	/* Force ALC offset calibration if enabling ALC */
+	if (ucontrol->value.integer.value[0] ||
+	    ucontrol->value.integer.value[1]) {
+		if (!da7213->alc_en) {
+			da7213_alc_calib(component);
+			da7213->alc_en = true;
+		}
+	} else {
+		da7213->alc_en = false;
+	}
+
+	return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+
+/*
+ * KControls
+ */
+
+static const struct snd_kcontrol_new da7213_snd_controls[] = {
+
+	/* Volume controls */
+	SOC_SINGLE_TLV("Mic 1 Volume", DA7213_MIC_1_GAIN,
+		       DA7213_MIC_AMP_GAIN_SHIFT, DA7213_MIC_AMP_GAIN_MAX,
+		       DA7213_NO_INVERT, mic_vol_tlv),
+	SOC_SINGLE_TLV("Mic 2 Volume", DA7213_MIC_2_GAIN,
+		       DA7213_MIC_AMP_GAIN_SHIFT, DA7213_MIC_AMP_GAIN_MAX,
+		       DA7213_NO_INVERT, mic_vol_tlv),
+	SOC_DOUBLE_R_TLV("Aux Volume", DA7213_AUX_L_GAIN, DA7213_AUX_R_GAIN,
+			 DA7213_AUX_AMP_GAIN_SHIFT, DA7213_AUX_AMP_GAIN_MAX,
+			 DA7213_NO_INVERT, aux_vol_tlv),
+	SOC_DOUBLE_R_EXT_TLV("Mixin PGA Volume", DA7213_MIXIN_L_GAIN,
+			     DA7213_MIXIN_R_GAIN, DA7213_MIXIN_AMP_GAIN_SHIFT,
+			     DA7213_MIXIN_AMP_GAIN_MAX, DA7213_NO_INVERT,
+			     snd_soc_get_volsw_2r, da7213_put_mixin_gain,
+			     mixin_gain_tlv),
+	SOC_DOUBLE_R_TLV("ADC Volume", DA7213_ADC_L_GAIN, DA7213_ADC_R_GAIN,
+			 DA7213_ADC_AMP_GAIN_SHIFT, DA7213_ADC_AMP_GAIN_MAX,
+			 DA7213_NO_INVERT, digital_gain_tlv),
+	SOC_DOUBLE_R_TLV("DAC Volume", DA7213_DAC_L_GAIN, DA7213_DAC_R_GAIN,
+			 DA7213_DAC_AMP_GAIN_SHIFT, DA7213_DAC_AMP_GAIN_MAX,
+			 DA7213_NO_INVERT, digital_gain_tlv),
+	SOC_DOUBLE_R_TLV("Headphone Volume", DA7213_HP_L_GAIN, DA7213_HP_R_GAIN,
+			 DA7213_HP_AMP_GAIN_SHIFT, DA7213_HP_AMP_GAIN_MAX,
+			 DA7213_NO_INVERT, hp_vol_tlv),
+	SOC_SINGLE_TLV("Lineout Volume", DA7213_LINE_GAIN,
+		       DA7213_LINE_AMP_GAIN_SHIFT, DA7213_LINE_AMP_GAIN_MAX,
+		       DA7213_NO_INVERT, lineout_vol_tlv),
+
+	/* DAC Equalizer controls */
+	SOC_SINGLE("DAC EQ Switch", DA7213_DAC_FILTERS4, DA7213_DAC_EQ_EN_SHIFT,
+		   DA7213_DAC_EQ_EN_MAX, DA7213_NO_INVERT),
+	SOC_SINGLE_TLV("DAC EQ1 Volume", DA7213_DAC_FILTERS2,
+		       DA7213_DAC_EQ_BAND1_SHIFT, DA7213_DAC_EQ_BAND_MAX,
+		       DA7213_NO_INVERT, eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ2 Volume", DA7213_DAC_FILTERS2,
+		       DA7213_DAC_EQ_BAND2_SHIFT, DA7213_DAC_EQ_BAND_MAX,
+		       DA7213_NO_INVERT, eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ3 Volume", DA7213_DAC_FILTERS3,
+		       DA7213_DAC_EQ_BAND3_SHIFT, DA7213_DAC_EQ_BAND_MAX,
+		       DA7213_NO_INVERT, eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ4 Volume", DA7213_DAC_FILTERS3,
+		       DA7213_DAC_EQ_BAND4_SHIFT, DA7213_DAC_EQ_BAND_MAX,
+		       DA7213_NO_INVERT, eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ5 Volume", DA7213_DAC_FILTERS4,
+		       DA7213_DAC_EQ_BAND5_SHIFT, DA7213_DAC_EQ_BAND_MAX,
+		       DA7213_NO_INVERT, eq_gain_tlv),
+
+	/* High Pass Filter and Voice Mode controls */
+	SOC_SINGLE("ADC HPF Switch", DA7213_ADC_FILTERS1, DA7213_HPF_EN_SHIFT,
+		   DA7213_HPF_EN_MAX, DA7213_NO_INVERT),
+	SOC_ENUM("ADC HPF Cutoff", da7213_adc_audio_hpf_corner),
+	SOC_SINGLE("ADC Voice Mode Switch", DA7213_ADC_FILTERS1,
+		   DA7213_VOICE_EN_SHIFT, DA7213_VOICE_EN_MAX,
+		   DA7213_NO_INVERT),
+	SOC_ENUM("ADC Voice Cutoff", da7213_adc_voice_hpf_corner),
+
+	SOC_SINGLE("DAC HPF Switch", DA7213_DAC_FILTERS1, DA7213_HPF_EN_SHIFT,
+		   DA7213_HPF_EN_MAX, DA7213_NO_INVERT),
+	SOC_ENUM("DAC HPF Cutoff", da7213_dac_audio_hpf_corner),
+	SOC_SINGLE("DAC Voice Mode Switch", DA7213_DAC_FILTERS1,
+		   DA7213_VOICE_EN_SHIFT, DA7213_VOICE_EN_MAX,
+		   DA7213_NO_INVERT),
+	SOC_ENUM("DAC Voice Cutoff", da7213_dac_voice_hpf_corner),
+
+	/* Mute controls */
+	SOC_SINGLE("Mic 1 Switch", DA7213_MIC_1_CTRL, DA7213_MUTE_EN_SHIFT,
+		   DA7213_MUTE_EN_MAX, DA7213_INVERT),
+	SOC_SINGLE("Mic 2 Switch", DA7213_MIC_2_CTRL, DA7213_MUTE_EN_SHIFT,
+		   DA7213_MUTE_EN_MAX, DA7213_INVERT),
+	SOC_DOUBLE_R("Aux Switch", DA7213_AUX_L_CTRL, DA7213_AUX_R_CTRL,
+		     DA7213_MUTE_EN_SHIFT, DA7213_MUTE_EN_MAX, DA7213_INVERT),
+	SOC_DOUBLE_R("Mixin PGA Switch", DA7213_MIXIN_L_CTRL,
+		     DA7213_MIXIN_R_CTRL, DA7213_MUTE_EN_SHIFT,
+		     DA7213_MUTE_EN_MAX, DA7213_INVERT),
+	SOC_DOUBLE_R("ADC Switch", DA7213_ADC_L_CTRL, DA7213_ADC_R_CTRL,
+		     DA7213_MUTE_EN_SHIFT, DA7213_MUTE_EN_MAX, DA7213_INVERT),
+	SOC_DOUBLE_R("Headphone Switch", DA7213_HP_L_CTRL, DA7213_HP_R_CTRL,
+		     DA7213_MUTE_EN_SHIFT, DA7213_MUTE_EN_MAX, DA7213_INVERT),
+	SOC_SINGLE("Lineout Switch", DA7213_LINE_CTRL, DA7213_MUTE_EN_SHIFT,
+		   DA7213_MUTE_EN_MAX, DA7213_INVERT),
+	SOC_SINGLE("DAC Soft Mute Switch", DA7213_DAC_FILTERS5,
+		   DA7213_DAC_SOFTMUTE_EN_SHIFT, DA7213_DAC_SOFTMUTE_EN_MAX,
+		   DA7213_NO_INVERT),
+	SOC_ENUM("DAC Soft Mute Rate", da7213_dac_soft_mute_rate),
+
+	/* Zero Cross controls */
+	SOC_DOUBLE_R("Aux ZC Switch", DA7213_AUX_L_CTRL, DA7213_AUX_R_CTRL,
+		     DA7213_ZC_EN_SHIFT, DA7213_ZC_EN_MAX, DA7213_NO_INVERT),
+	SOC_DOUBLE_R("Mixin PGA ZC Switch", DA7213_MIXIN_L_CTRL,
+		     DA7213_MIXIN_R_CTRL, DA7213_ZC_EN_SHIFT, DA7213_ZC_EN_MAX,
+		     DA7213_NO_INVERT),
+	SOC_DOUBLE_R("Headphone ZC Switch", DA7213_HP_L_CTRL, DA7213_HP_R_CTRL,
+		     DA7213_ZC_EN_SHIFT, DA7213_ZC_EN_MAX, DA7213_NO_INVERT),
+
+	/* Gain Ramping controls */
+	SOC_DOUBLE_R("Aux Gain Ramping Switch", DA7213_AUX_L_CTRL,
+		     DA7213_AUX_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT,
+		     DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT),
+	SOC_DOUBLE_R("Mixin Gain Ramping Switch", DA7213_MIXIN_L_CTRL,
+		     DA7213_MIXIN_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT,
+		     DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT),
+	SOC_DOUBLE_R("ADC Gain Ramping Switch", DA7213_ADC_L_CTRL,
+		     DA7213_ADC_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT,
+		     DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT),
+	SOC_DOUBLE_R("DAC Gain Ramping Switch", DA7213_DAC_L_CTRL,
+		     DA7213_DAC_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT,
+		     DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT),
+	SOC_DOUBLE_R("Headphone Gain Ramping Switch", DA7213_HP_L_CTRL,
+		     DA7213_HP_R_CTRL, DA7213_GAIN_RAMP_EN_SHIFT,
+		     DA7213_GAIN_RAMP_EN_MAX, DA7213_NO_INVERT),
+	SOC_SINGLE("Lineout Gain Ramping Switch", DA7213_LINE_CTRL,
+		   DA7213_GAIN_RAMP_EN_SHIFT, DA7213_GAIN_RAMP_EN_MAX,
+		   DA7213_NO_INVERT),
+	SOC_ENUM("Gain Ramping Rate", da7213_gain_ramp_rate),
+
+	/* DAC Noise Gate controls */
+	SOC_SINGLE("DAC NG Switch", DA7213_DAC_NG_CTRL, DA7213_DAC_NG_EN_SHIFT,
+		   DA7213_DAC_NG_EN_MAX, DA7213_NO_INVERT),
+	SOC_ENUM("DAC NG Setup Time", da7213_dac_ng_setup_time),
+	SOC_ENUM("DAC NG Rampup Rate", da7213_dac_ng_rampup_rate),
+	SOC_ENUM("DAC NG Rampdown Rate", da7213_dac_ng_rampdown_rate),
+	SOC_SINGLE("DAC NG OFF Threshold", DA7213_DAC_NG_OFF_THRESHOLD,
+		   DA7213_DAC_NG_THRESHOLD_SHIFT, DA7213_DAC_NG_THRESHOLD_MAX,
+		   DA7213_NO_INVERT),
+	SOC_SINGLE("DAC NG ON Threshold", DA7213_DAC_NG_ON_THRESHOLD,
+		   DA7213_DAC_NG_THRESHOLD_SHIFT, DA7213_DAC_NG_THRESHOLD_MAX,
+		   DA7213_NO_INVERT),
+
+	/* DAC Routing & Inversion */
+	SOC_DOUBLE("DAC Mono Switch", DA7213_DIG_ROUTING_DAC,
+		   DA7213_DAC_L_MONO_SHIFT, DA7213_DAC_R_MONO_SHIFT,
+		   DA7213_DAC_MONO_MAX, DA7213_NO_INVERT),
+	SOC_DOUBLE("DAC Invert Switch", DA7213_DIG_CTRL, DA7213_DAC_L_INV_SHIFT,
+		   DA7213_DAC_R_INV_SHIFT, DA7213_DAC_INV_MAX,
+		   DA7213_NO_INVERT),
+
+	/* DMIC controls */
+	SOC_DOUBLE_R("DMIC Switch", DA7213_MIXIN_L_SELECT,
+		     DA7213_MIXIN_R_SELECT, DA7213_DMIC_EN_SHIFT,
+		     DA7213_DMIC_EN_MAX, DA7213_NO_INVERT),
+
+	/* ALC Controls */
+	SOC_DOUBLE_EXT("ALC Switch", DA7213_ALC_CTRL1, DA7213_ALC_L_EN_SHIFT,
+		       DA7213_ALC_R_EN_SHIFT, DA7213_ALC_EN_MAX,
+		       DA7213_NO_INVERT, snd_soc_get_volsw, da7213_put_alc_sw),
+	SOC_ENUM("ALC Attack Rate", da7213_alc_attack_rate),
+	SOC_ENUM("ALC Release Rate", da7213_alc_release_rate),
+	SOC_ENUM("ALC Hold Time", da7213_alc_hold_time),
+	/*
+	 * Rate at which input signal envelope is tracked as the signal gets
+	 * larger
+	 */
+	SOC_ENUM("ALC Integ Attack Rate", da7213_alc_integ_attack_rate),
+	/*
+	 * Rate at which input signal envelope is tracked as the signal gets
+	 * smaller
+	 */
+	SOC_ENUM("ALC Integ Release Rate", da7213_alc_integ_release_rate),
+	SOC_SINGLE_TLV("ALC Noise Threshold Volume", DA7213_ALC_NOISE,
+		       DA7213_ALC_THRESHOLD_SHIFT, DA7213_ALC_THRESHOLD_MAX,
+		       DA7213_INVERT, alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Min Threshold Volume", DA7213_ALC_TARGET_MIN,
+		       DA7213_ALC_THRESHOLD_SHIFT, DA7213_ALC_THRESHOLD_MAX,
+		       DA7213_INVERT, alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Max Threshold Volume", DA7213_ALC_TARGET_MAX,
+		       DA7213_ALC_THRESHOLD_SHIFT, DA7213_ALC_THRESHOLD_MAX,
+		       DA7213_INVERT, alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Max Attenuation Volume", DA7213_ALC_GAIN_LIMITS,
+		       DA7213_ALC_ATTEN_MAX_SHIFT,
+		       DA7213_ALC_ATTEN_GAIN_MAX_MAX, DA7213_NO_INVERT,
+		       alc_gain_tlv),
+	SOC_SINGLE_TLV("ALC Max Gain Volume", DA7213_ALC_GAIN_LIMITS,
+		       DA7213_ALC_GAIN_MAX_SHIFT, DA7213_ALC_ATTEN_GAIN_MAX_MAX,
+		       DA7213_NO_INVERT, alc_gain_tlv),
+	SOC_SINGLE_TLV("ALC Min Analog Gain Volume", DA7213_ALC_ANA_GAIN_LIMITS,
+		       DA7213_ALC_ANA_GAIN_MIN_SHIFT, DA7213_ALC_ANA_GAIN_MAX,
+		       DA7213_NO_INVERT, alc_analog_gain_tlv),
+	SOC_SINGLE_TLV("ALC Max Analog Gain Volume", DA7213_ALC_ANA_GAIN_LIMITS,
+		       DA7213_ALC_ANA_GAIN_MAX_SHIFT, DA7213_ALC_ANA_GAIN_MAX,
+		       DA7213_NO_INVERT, alc_analog_gain_tlv),
+	SOC_SINGLE("ALC Anticlip Mode Switch", DA7213_ALC_ANTICLIP_CTRL,
+		   DA7213_ALC_ANTICLIP_EN_SHIFT, DA7213_ALC_ANTICLIP_EN_MAX,
+		   DA7213_NO_INVERT),
+	SOC_SINGLE("ALC Anticlip Level", DA7213_ALC_ANTICLIP_LEVEL,
+		   DA7213_ALC_ANTICLIP_LEVEL_SHIFT,
+		   DA7213_ALC_ANTICLIP_LEVEL_MAX, DA7213_NO_INVERT),
+};
+
+
+/*
+ * DAPM
+ */
+
+/*
+ * Enums
+ */
+
+/* MIC PGA source select */
+static const char * const da7213_mic_amp_in_sel_txt[] = {
+	"Differential", "MIC_P", "MIC_N"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7213_mic_1_amp_in_sel,
+			    DA7213_MIC_1_CTRL,
+			    DA7213_MIC_AMP_IN_SEL_SHIFT,
+			    da7213_mic_amp_in_sel_txt);
+static const struct snd_kcontrol_new da7213_mic_1_amp_in_sel_mux =
+	SOC_DAPM_ENUM("Mic 1 Amp Source MUX", da7213_mic_1_amp_in_sel);
+
+static SOC_ENUM_SINGLE_DECL(da7213_mic_2_amp_in_sel,
+			    DA7213_MIC_2_CTRL,
+			    DA7213_MIC_AMP_IN_SEL_SHIFT,
+			    da7213_mic_amp_in_sel_txt);
+static const struct snd_kcontrol_new da7213_mic_2_amp_in_sel_mux =
+	SOC_DAPM_ENUM("Mic 2 Amp Source MUX", da7213_mic_2_amp_in_sel);
+
+/* DAI routing select */
+static const char * const da7213_dai_src_txt[] = {
+	"ADC Left", "ADC Right", "DAI Input Left", "DAI Input Right"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7213_dai_l_src,
+			    DA7213_DIG_ROUTING_DAI,
+			    DA7213_DAI_L_SRC_SHIFT,
+			    da7213_dai_src_txt);
+static const struct snd_kcontrol_new da7213_dai_l_src_mux =
+	SOC_DAPM_ENUM("DAI Left Source MUX", da7213_dai_l_src);
+
+static SOC_ENUM_SINGLE_DECL(da7213_dai_r_src,
+			    DA7213_DIG_ROUTING_DAI,
+			    DA7213_DAI_R_SRC_SHIFT,
+			    da7213_dai_src_txt);
+static const struct snd_kcontrol_new da7213_dai_r_src_mux =
+	SOC_DAPM_ENUM("DAI Right Source MUX", da7213_dai_r_src);
+
+/* DAC routing select */
+static const char * const da7213_dac_src_txt[] = {
+	"ADC Output Left", "ADC Output Right", "DAI Input Left",
+	"DAI Input Right"
+};
+
+static SOC_ENUM_SINGLE_DECL(da7213_dac_l_src,
+			    DA7213_DIG_ROUTING_DAC,
+			    DA7213_DAC_L_SRC_SHIFT,
+			    da7213_dac_src_txt);
+static const struct snd_kcontrol_new da7213_dac_l_src_mux =
+	SOC_DAPM_ENUM("DAC Left Source MUX", da7213_dac_l_src);
+
+static SOC_ENUM_SINGLE_DECL(da7213_dac_r_src,
+			    DA7213_DIG_ROUTING_DAC,
+			    DA7213_DAC_R_SRC_SHIFT,
+			    da7213_dac_src_txt);
+static const struct snd_kcontrol_new da7213_dac_r_src_mux =
+	SOC_DAPM_ENUM("DAC Right Source MUX", da7213_dac_r_src);
+
+/*
+ * Mixer Controls
+ */
+
+/* Mixin Left */
+static const struct snd_kcontrol_new da7213_dapm_mixinl_controls[] = {
+	SOC_DAPM_SINGLE("Aux Left Switch", DA7213_MIXIN_L_SELECT,
+			DA7213_MIXIN_L_MIX_SELECT_AUX_L_SHIFT,
+			DA7213_MIXIN_L_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Mic 1 Switch", DA7213_MIXIN_L_SELECT,
+			DA7213_MIXIN_L_MIX_SELECT_MIC_1_SHIFT,
+			DA7213_MIXIN_L_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Mic 2 Switch", DA7213_MIXIN_L_SELECT,
+			DA7213_MIXIN_L_MIX_SELECT_MIC_2_SHIFT,
+			DA7213_MIXIN_L_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Mixin Right Switch", DA7213_MIXIN_L_SELECT,
+			DA7213_MIXIN_L_MIX_SELECT_MIXIN_R_SHIFT,
+			DA7213_MIXIN_L_MIX_SELECT_MAX, DA7213_NO_INVERT),
+};
+
+/* Mixin Right */
+static const struct snd_kcontrol_new da7213_dapm_mixinr_controls[] = {
+	SOC_DAPM_SINGLE("Aux Right Switch", DA7213_MIXIN_R_SELECT,
+			DA7213_MIXIN_R_MIX_SELECT_AUX_R_SHIFT,
+			DA7213_MIXIN_R_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Mic 2 Switch", DA7213_MIXIN_R_SELECT,
+			DA7213_MIXIN_R_MIX_SELECT_MIC_2_SHIFT,
+			DA7213_MIXIN_R_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Mic 1 Switch", DA7213_MIXIN_R_SELECT,
+			DA7213_MIXIN_R_MIX_SELECT_MIC_1_SHIFT,
+			DA7213_MIXIN_R_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Mixin Left Switch", DA7213_MIXIN_R_SELECT,
+			DA7213_MIXIN_R_MIX_SELECT_MIXIN_L_SHIFT,
+			DA7213_MIXIN_R_MIX_SELECT_MAX, DA7213_NO_INVERT),
+};
+
+/* Mixout Left */
+static const struct snd_kcontrol_new da7213_dapm_mixoutl_controls[] = {
+	SOC_DAPM_SINGLE("Aux Left Switch", DA7213_MIXOUT_L_SELECT,
+			DA7213_MIXOUT_L_MIX_SELECT_AUX_L_SHIFT,
+			DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Mixin Left Switch", DA7213_MIXOUT_L_SELECT,
+			DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_SHIFT,
+			DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Mixin Right Switch", DA7213_MIXOUT_L_SELECT,
+			DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_SHIFT,
+			DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("DAC Left Switch", DA7213_MIXOUT_L_SELECT,
+			DA7213_MIXOUT_L_MIX_SELECT_DAC_L_SHIFT,
+			DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Aux Left Invert Switch", DA7213_MIXOUT_L_SELECT,
+			DA7213_MIXOUT_L_MIX_SELECT_AUX_L_INVERTED_SHIFT,
+			DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Mixin Left Invert Switch", DA7213_MIXOUT_L_SELECT,
+			DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_INVERTED_SHIFT,
+			DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Mixin Right Invert Switch", DA7213_MIXOUT_L_SELECT,
+			DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_INVERTED_SHIFT,
+			DA7213_MIXOUT_L_MIX_SELECT_MAX, DA7213_NO_INVERT),
+};
+
+/* Mixout Right */
+static const struct snd_kcontrol_new da7213_dapm_mixoutr_controls[] = {
+	SOC_DAPM_SINGLE("Aux Right Switch", DA7213_MIXOUT_R_SELECT,
+			DA7213_MIXOUT_R_MIX_SELECT_AUX_R_SHIFT,
+			DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Mixin Right Switch", DA7213_MIXOUT_R_SELECT,
+			DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_SHIFT,
+			DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Mixin Left Switch", DA7213_MIXOUT_R_SELECT,
+			DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_SHIFT,
+			DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("DAC Right Switch", DA7213_MIXOUT_R_SELECT,
+			DA7213_MIXOUT_R_MIX_SELECT_DAC_R_SHIFT,
+			DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Aux Right Invert Switch", DA7213_MIXOUT_R_SELECT,
+			DA7213_MIXOUT_R_MIX_SELECT_AUX_R_INVERTED_SHIFT,
+			DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Mixin Right Invert Switch", DA7213_MIXOUT_R_SELECT,
+			DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_INVERTED_SHIFT,
+			DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT),
+	SOC_DAPM_SINGLE("Mixin Left Invert Switch", DA7213_MIXOUT_R_SELECT,
+			DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_INVERTED_SHIFT,
+			DA7213_MIXOUT_R_MIX_SELECT_MAX, DA7213_NO_INVERT),
+};
+
+
+/*
+ * DAPM Events
+ */
+
+static int da7213_dai_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+	u8 pll_ctrl, pll_status;
+	int i = 0;
+	bool srm_lock = false;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Enable DAI clks for master mode */
+		if (da7213->master)
+			snd_soc_component_update_bits(component, DA7213_DAI_CLK_MODE,
+					    DA7213_DAI_CLK_EN_MASK,
+					    DA7213_DAI_CLK_EN_MASK);
+
+		/* PC synchronised to DAI */
+		snd_soc_component_update_bits(component, DA7213_PC_COUNT,
+				    DA7213_PC_FREERUN_MASK, 0);
+
+		/* If SRM not enabled then nothing more to do */
+		pll_ctrl = snd_soc_component_read32(component, DA7213_PLL_CTRL);
+		if (!(pll_ctrl & DA7213_PLL_SRM_EN))
+			return 0;
+
+		/* Assist 32KHz mode PLL lock */
+		if (pll_ctrl & DA7213_PLL_32K_MODE) {
+			snd_soc_component_write(component, 0xF0, 0x8B);
+			snd_soc_component_write(component, 0xF2, 0x03);
+			snd_soc_component_write(component, 0xF0, 0x00);
+		}
+
+		/* Check SRM has locked */
+		do {
+			pll_status = snd_soc_component_read32(component, DA7213_PLL_STATUS);
+			if (pll_status & DA7219_PLL_SRM_LOCK) {
+				srm_lock = true;
+			} else {
+				++i;
+				msleep(50);
+			}
+		} while ((i < DA7213_SRM_CHECK_RETRIES) && (!srm_lock));
+
+		if (!srm_lock)
+			dev_warn(component->dev, "SRM failed to lock\n");
+
+		return 0;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Revert 32KHz PLL lock udpates if applied previously */
+		pll_ctrl = snd_soc_component_read32(component, DA7213_PLL_CTRL);
+		if (pll_ctrl & DA7213_PLL_32K_MODE) {
+			snd_soc_component_write(component, 0xF0, 0x8B);
+			snd_soc_component_write(component, 0xF2, 0x01);
+			snd_soc_component_write(component, 0xF0, 0x00);
+		}
+
+		/* PC free-running */
+		snd_soc_component_update_bits(component, DA7213_PC_COUNT,
+				    DA7213_PC_FREERUN_MASK,
+				    DA7213_PC_FREERUN_MASK);
+
+		/* Disable DAI clks if in master mode */
+		if (da7213->master)
+			snd_soc_component_update_bits(component, DA7213_DAI_CLK_MODE,
+					    DA7213_DAI_CLK_EN_MASK, 0);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+
+/*
+ * DAPM widgets
+ */
+
+static const struct snd_soc_dapm_widget da7213_dapm_widgets[] = {
+	/*
+	 * Input & Output
+	 */
+
+	/* Use a supply here as this controls both input & output DAIs */
+	SND_SOC_DAPM_SUPPLY("DAI", DA7213_DAI_CTRL, DA7213_DAI_EN_SHIFT,
+			    DA7213_NO_INVERT, da7213_dai_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/*
+	 * Input
+	 */
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("AUXL"),
+	SND_SOC_DAPM_INPUT("AUXR"),
+
+	/* MUXs for Mic PGA source selection */
+	SND_SOC_DAPM_MUX("Mic 1 Amp Source MUX", SND_SOC_NOPM, 0, 0,
+			 &da7213_mic_1_amp_in_sel_mux),
+	SND_SOC_DAPM_MUX("Mic 2 Amp Source MUX", SND_SOC_NOPM, 0, 0,
+			 &da7213_mic_2_amp_in_sel_mux),
+
+	/* Input PGAs */
+	SND_SOC_DAPM_PGA("Mic 1 PGA", DA7213_MIC_1_CTRL, DA7213_AMP_EN_SHIFT,
+			 DA7213_NO_INVERT, NULL, 0),
+	SND_SOC_DAPM_PGA("Mic 2 PGA", DA7213_MIC_2_CTRL, DA7213_AMP_EN_SHIFT,
+			 DA7213_NO_INVERT, NULL, 0),
+	SND_SOC_DAPM_PGA("Aux Left PGA", DA7213_AUX_L_CTRL, DA7213_AMP_EN_SHIFT,
+			 DA7213_NO_INVERT, NULL, 0),
+	SND_SOC_DAPM_PGA("Aux Right PGA", DA7213_AUX_R_CTRL,
+			 DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0),
+	SND_SOC_DAPM_PGA("Mixin Left PGA", DA7213_MIXIN_L_CTRL,
+			 DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0),
+	SND_SOC_DAPM_PGA("Mixin Right PGA", DA7213_MIXIN_R_CTRL,
+			 DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0),
+
+	/* Mic Biases */
+	SND_SOC_DAPM_SUPPLY("Mic Bias 1", DA7213_MICBIAS_CTRL,
+			    DA7213_MICBIAS1_EN_SHIFT, DA7213_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Bias 2", DA7213_MICBIAS_CTRL,
+			    DA7213_MICBIAS2_EN_SHIFT, DA7213_NO_INVERT,
+			    NULL, 0),
+
+	/* Input Mixers */
+	SND_SOC_DAPM_MIXER("Mixin Left", SND_SOC_NOPM, 0, 0,
+			   &da7213_dapm_mixinl_controls[0],
+			   ARRAY_SIZE(da7213_dapm_mixinl_controls)),
+	SND_SOC_DAPM_MIXER("Mixin Right", SND_SOC_NOPM, 0, 0,
+			   &da7213_dapm_mixinr_controls[0],
+			   ARRAY_SIZE(da7213_dapm_mixinr_controls)),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC Left", NULL, DA7213_ADC_L_CTRL,
+			 DA7213_ADC_EN_SHIFT, DA7213_NO_INVERT),
+	SND_SOC_DAPM_ADC("ADC Right", NULL, DA7213_ADC_R_CTRL,
+			 DA7213_ADC_EN_SHIFT, DA7213_NO_INVERT),
+
+	/* DAI */
+	SND_SOC_DAPM_MUX("DAI Left Source MUX", SND_SOC_NOPM, 0, 0,
+			 &da7213_dai_l_src_mux),
+	SND_SOC_DAPM_MUX("DAI Right Source MUX", SND_SOC_NOPM, 0, 0,
+			 &da7213_dai_r_src_mux),
+	SND_SOC_DAPM_AIF_OUT("DAIOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("DAIOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0),
+
+	/*
+	 * Output
+	 */
+
+	/* DAI */
+	SND_SOC_DAPM_AIF_IN("DAIINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DAIINR", "Playback", 1, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_MUX("DAC Left Source MUX", SND_SOC_NOPM, 0, 0,
+			 &da7213_dac_l_src_mux),
+	SND_SOC_DAPM_MUX("DAC Right Source MUX", SND_SOC_NOPM, 0, 0,
+			 &da7213_dac_r_src_mux),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC Left", NULL, DA7213_DAC_L_CTRL,
+			 DA7213_DAC_EN_SHIFT, DA7213_NO_INVERT),
+	SND_SOC_DAPM_DAC("DAC Right", NULL, DA7213_DAC_R_CTRL,
+			 DA7213_DAC_EN_SHIFT, DA7213_NO_INVERT),
+
+	/* Output Mixers */
+	SND_SOC_DAPM_MIXER("Mixout Left", SND_SOC_NOPM, 0, 0,
+			   &da7213_dapm_mixoutl_controls[0],
+			   ARRAY_SIZE(da7213_dapm_mixoutl_controls)),
+	SND_SOC_DAPM_MIXER("Mixout Right", SND_SOC_NOPM, 0, 0,
+			   &da7213_dapm_mixoutr_controls[0],
+			   ARRAY_SIZE(da7213_dapm_mixoutr_controls)),
+
+	/* Output PGAs */
+	SND_SOC_DAPM_PGA("Mixout Left PGA", DA7213_MIXOUT_L_CTRL,
+			 DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0),
+	SND_SOC_DAPM_PGA("Mixout Right PGA", DA7213_MIXOUT_R_CTRL,
+			 DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0),
+	SND_SOC_DAPM_PGA("Lineout PGA", DA7213_LINE_CTRL, DA7213_AMP_EN_SHIFT,
+			 DA7213_NO_INVERT, NULL, 0),
+	SND_SOC_DAPM_PGA("Headphone Left PGA", DA7213_HP_L_CTRL,
+			 DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0),
+	SND_SOC_DAPM_PGA("Headphone Right PGA", DA7213_HP_R_CTRL,
+			 DA7213_AMP_EN_SHIFT, DA7213_NO_INVERT, NULL, 0),
+
+	/* Charge Pump */
+	SND_SOC_DAPM_SUPPLY("Charge Pump", DA7213_CP_CTRL, DA7213_CP_EN_SHIFT,
+			    DA7213_NO_INVERT, NULL, 0),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("LINE"),
+};
+
+
+/*
+ * DAPM audio route definition
+ */
+
+static const struct snd_soc_dapm_route da7213_audio_map[] = {
+	/* Dest       Connecting Widget    source */
+
+	/* Input path */
+	{"MIC1", NULL, "Mic Bias 1"},
+	{"MIC2", NULL, "Mic Bias 2"},
+
+	{"Mic 1 Amp Source MUX", "Differential", "MIC1"},
+	{"Mic 1 Amp Source MUX", "MIC_P", "MIC1"},
+	{"Mic 1 Amp Source MUX", "MIC_N", "MIC1"},
+
+	{"Mic 2 Amp Source MUX", "Differential", "MIC2"},
+	{"Mic 2 Amp Source MUX", "MIC_P", "MIC2"},
+	{"Mic 2 Amp Source MUX", "MIC_N", "MIC2"},
+
+	{"Mic 1 PGA", NULL, "Mic 1 Amp Source MUX"},
+	{"Mic 2 PGA", NULL, "Mic 2 Amp Source MUX"},
+
+	{"Aux Left PGA", NULL, "AUXL"},
+	{"Aux Right PGA", NULL, "AUXR"},
+
+	{"Mixin Left", "Aux Left Switch", "Aux Left PGA"},
+	{"Mixin Left", "Mic 1 Switch", "Mic 1 PGA"},
+	{"Mixin Left", "Mic 2 Switch", "Mic 2 PGA"},
+	{"Mixin Left", "Mixin Right Switch", "Mixin Right PGA"},
+
+	{"Mixin Right", "Aux Right Switch", "Aux Right PGA"},
+	{"Mixin Right", "Mic 2 Switch", "Mic 2 PGA"},
+	{"Mixin Right", "Mic 1 Switch", "Mic 1 PGA"},
+	{"Mixin Right", "Mixin Left Switch", "Mixin Left PGA"},
+
+	{"Mixin Left PGA", NULL, "Mixin Left"},
+	{"ADC Left", NULL, "Mixin Left PGA"},
+
+	{"Mixin Right PGA", NULL, "Mixin Right"},
+	{"ADC Right", NULL, "Mixin Right PGA"},
+
+	{"DAI Left Source MUX", "ADC Left", "ADC Left"},
+	{"DAI Left Source MUX", "ADC Right", "ADC Right"},
+	{"DAI Left Source MUX", "DAI Input Left", "DAIINL"},
+	{"DAI Left Source MUX", "DAI Input Right", "DAIINR"},
+
+	{"DAI Right Source MUX", "ADC Left", "ADC Left"},
+	{"DAI Right Source MUX", "ADC Right", "ADC Right"},
+	{"DAI Right Source MUX", "DAI Input Left", "DAIINL"},
+	{"DAI Right Source MUX", "DAI Input Right", "DAIINR"},
+
+	{"DAIOUTL", NULL, "DAI Left Source MUX"},
+	{"DAIOUTR", NULL, "DAI Right Source MUX"},
+
+	{"DAIOUTL", NULL, "DAI"},
+	{"DAIOUTR", NULL, "DAI"},
+
+	/* Output path */
+	{"DAIINL", NULL, "DAI"},
+	{"DAIINR", NULL, "DAI"},
+
+	{"DAC Left Source MUX", "ADC Output Left", "ADC Left"},
+	{"DAC Left Source MUX", "ADC Output Right", "ADC Right"},
+	{"DAC Left Source MUX", "DAI Input Left", "DAIINL"},
+	{"DAC Left Source MUX", "DAI Input Right", "DAIINR"},
+
+	{"DAC Right Source MUX", "ADC Output Left", "ADC Left"},
+	{"DAC Right Source MUX", "ADC Output Right", "ADC Right"},
+	{"DAC Right Source MUX", "DAI Input Left", "DAIINL"},
+	{"DAC Right Source MUX", "DAI Input Right", "DAIINR"},
+
+	{"DAC Left", NULL, "DAC Left Source MUX"},
+	{"DAC Right", NULL, "DAC Right Source MUX"},
+
+	{"Mixout Left", "Aux Left Switch", "Aux Left PGA"},
+	{"Mixout Left", "Mixin Left Switch", "Mixin Left PGA"},
+	{"Mixout Left", "Mixin Right Switch", "Mixin Right PGA"},
+	{"Mixout Left", "DAC Left Switch", "DAC Left"},
+	{"Mixout Left", "Aux Left Invert Switch", "Aux Left PGA"},
+	{"Mixout Left", "Mixin Left Invert Switch", "Mixin Left PGA"},
+	{"Mixout Left", "Mixin Right Invert Switch", "Mixin Right PGA"},
+
+	{"Mixout Right", "Aux Right Switch", "Aux Right PGA"},
+	{"Mixout Right", "Mixin Right Switch", "Mixin Right PGA"},
+	{"Mixout Right", "Mixin Left Switch", "Mixin Left PGA"},
+	{"Mixout Right", "DAC Right Switch", "DAC Right"},
+	{"Mixout Right", "Aux Right Invert Switch", "Aux Right PGA"},
+	{"Mixout Right", "Mixin Right Invert Switch", "Mixin Right PGA"},
+	{"Mixout Right", "Mixin Left Invert Switch", "Mixin Left PGA"},
+
+	{"Mixout Left PGA", NULL, "Mixout Left"},
+	{"Mixout Right PGA", NULL, "Mixout Right"},
+
+	{"Headphone Left PGA", NULL, "Mixout Left PGA"},
+	{"Headphone Left PGA", NULL, "Charge Pump"},
+	{"HPL", NULL, "Headphone Left PGA"},
+
+	{"Headphone Right PGA", NULL, "Mixout Right PGA"},
+	{"Headphone Right PGA", NULL, "Charge Pump"},
+	{"HPR", NULL, "Headphone Right PGA"},
+
+	{"Lineout PGA", NULL, "Mixout Right PGA"},
+	{"LINE", NULL, "Lineout PGA"},
+};
+
+static const struct reg_default da7213_reg_defaults[] = {
+	{ DA7213_DIG_ROUTING_DAI, 0x10 },
+	{ DA7213_SR, 0x0A },
+	{ DA7213_REFERENCES, 0x80 },
+	{ DA7213_PLL_FRAC_TOP, 0x00 },
+	{ DA7213_PLL_FRAC_BOT, 0x00 },
+	{ DA7213_PLL_INTEGER, 0x20 },
+	{ DA7213_PLL_CTRL, 0x0C },
+	{ DA7213_DAI_CLK_MODE, 0x01 },
+	{ DA7213_DAI_CTRL, 0x08 },
+	{ DA7213_DIG_ROUTING_DAC, 0x32 },
+	{ DA7213_AUX_L_GAIN, 0x35 },
+	{ DA7213_AUX_R_GAIN, 0x35 },
+	{ DA7213_MIXIN_L_SELECT, 0x00 },
+	{ DA7213_MIXIN_R_SELECT, 0x00 },
+	{ DA7213_MIXIN_L_GAIN, 0x03 },
+	{ DA7213_MIXIN_R_GAIN, 0x03 },
+	{ DA7213_ADC_L_GAIN, 0x6F },
+	{ DA7213_ADC_R_GAIN, 0x6F },
+	{ DA7213_ADC_FILTERS1, 0x80 },
+	{ DA7213_MIC_1_GAIN, 0x01 },
+	{ DA7213_MIC_2_GAIN, 0x01 },
+	{ DA7213_DAC_FILTERS5, 0x00 },
+	{ DA7213_DAC_FILTERS2, 0x88 },
+	{ DA7213_DAC_FILTERS3, 0x88 },
+	{ DA7213_DAC_FILTERS4, 0x08 },
+	{ DA7213_DAC_FILTERS1, 0x80 },
+	{ DA7213_DAC_L_GAIN, 0x6F },
+	{ DA7213_DAC_R_GAIN, 0x6F },
+	{ DA7213_CP_CTRL, 0x61 },
+	{ DA7213_HP_L_GAIN, 0x39 },
+	{ DA7213_HP_R_GAIN, 0x39 },
+	{ DA7213_LINE_GAIN, 0x30 },
+	{ DA7213_MIXOUT_L_SELECT, 0x00 },
+	{ DA7213_MIXOUT_R_SELECT, 0x00 },
+	{ DA7213_SYSTEM_MODES_INPUT, 0x00 },
+	{ DA7213_SYSTEM_MODES_OUTPUT, 0x00 },
+	{ DA7213_AUX_L_CTRL, 0x44 },
+	{ DA7213_AUX_R_CTRL, 0x44 },
+	{ DA7213_MICBIAS_CTRL, 0x11 },
+	{ DA7213_MIC_1_CTRL, 0x40 },
+	{ DA7213_MIC_2_CTRL, 0x40 },
+	{ DA7213_MIXIN_L_CTRL, 0x40 },
+	{ DA7213_MIXIN_R_CTRL, 0x40 },
+	{ DA7213_ADC_L_CTRL, 0x40 },
+	{ DA7213_ADC_R_CTRL, 0x40 },
+	{ DA7213_DAC_L_CTRL, 0x48 },
+	{ DA7213_DAC_R_CTRL, 0x40 },
+	{ DA7213_HP_L_CTRL, 0x41 },
+	{ DA7213_HP_R_CTRL, 0x40 },
+	{ DA7213_LINE_CTRL, 0x40 },
+	{ DA7213_MIXOUT_L_CTRL, 0x10 },
+	{ DA7213_MIXOUT_R_CTRL, 0x10 },
+	{ DA7213_LDO_CTRL, 0x00 },
+	{ DA7213_IO_CTRL, 0x00 },
+	{ DA7213_GAIN_RAMP_CTRL, 0x00},
+	{ DA7213_MIC_CONFIG, 0x00 },
+	{ DA7213_PC_COUNT, 0x00 },
+	{ DA7213_CP_VOL_THRESHOLD1, 0x32 },
+	{ DA7213_CP_DELAY, 0x95 },
+	{ DA7213_CP_DETECTOR, 0x00 },
+	{ DA7213_DAI_OFFSET, 0x00 },
+	{ DA7213_DIG_CTRL, 0x00 },
+	{ DA7213_ALC_CTRL2, 0x00 },
+	{ DA7213_ALC_CTRL3, 0x00 },
+	{ DA7213_ALC_NOISE, 0x3F },
+	{ DA7213_ALC_TARGET_MIN, 0x3F },
+	{ DA7213_ALC_TARGET_MAX, 0x00 },
+	{ DA7213_ALC_GAIN_LIMITS, 0xFF },
+	{ DA7213_ALC_ANA_GAIN_LIMITS, 0x71 },
+	{ DA7213_ALC_ANTICLIP_CTRL, 0x00 },
+	{ DA7213_ALC_ANTICLIP_LEVEL, 0x00 },
+	{ DA7213_ALC_OFFSET_MAN_M_L, 0x00 },
+	{ DA7213_ALC_OFFSET_MAN_U_L, 0x00 },
+	{ DA7213_ALC_OFFSET_MAN_M_R, 0x00 },
+	{ DA7213_ALC_OFFSET_MAN_U_R, 0x00 },
+	{ DA7213_ALC_CIC_OP_LVL_CTRL, 0x00 },
+	{ DA7213_DAC_NG_SETUP_TIME, 0x00 },
+	{ DA7213_DAC_NG_OFF_THRESHOLD, 0x00 },
+	{ DA7213_DAC_NG_ON_THRESHOLD, 0x00 },
+	{ DA7213_DAC_NG_CTRL, 0x00 },
+};
+
+static bool da7213_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case DA7213_STATUS1:
+	case DA7213_PLL_STATUS:
+	case DA7213_AUX_L_GAIN_STATUS:
+	case DA7213_AUX_R_GAIN_STATUS:
+	case DA7213_MIC_1_GAIN_STATUS:
+	case DA7213_MIC_2_GAIN_STATUS:
+	case DA7213_MIXIN_L_GAIN_STATUS:
+	case DA7213_MIXIN_R_GAIN_STATUS:
+	case DA7213_ADC_L_GAIN_STATUS:
+	case DA7213_ADC_R_GAIN_STATUS:
+	case DA7213_DAC_L_GAIN_STATUS:
+	case DA7213_DAC_R_GAIN_STATUS:
+	case DA7213_HP_L_GAIN_STATUS:
+	case DA7213_HP_R_GAIN_STATUS:
+	case DA7213_LINE_GAIN_STATUS:
+	case DA7213_ALC_CTRL1:
+	case DA7213_ALC_OFFSET_AUTO_M_L:
+	case DA7213_ALC_OFFSET_AUTO_U_L:
+	case DA7213_ALC_OFFSET_AUTO_M_R:
+	case DA7213_ALC_OFFSET_AUTO_U_R:
+	case DA7213_ALC_CIC_OP_LVL_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int da7213_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 dai_ctrl = 0;
+	u8 fs;
+
+	/* Set DAI format */
+	switch (params_width(params)) {
+	case 16:
+		dai_ctrl |= DA7213_DAI_WORD_LENGTH_S16_LE;
+		break;
+	case 20:
+		dai_ctrl |= DA7213_DAI_WORD_LENGTH_S20_LE;
+		break;
+	case 24:
+		dai_ctrl |= DA7213_DAI_WORD_LENGTH_S24_LE;
+		break;
+	case 32:
+		dai_ctrl |= DA7213_DAI_WORD_LENGTH_S32_LE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Set sampling rate */
+	switch (params_rate(params)) {
+	case 8000:
+		fs = DA7213_SR_8000;
+		break;
+	case 11025:
+		fs = DA7213_SR_11025;
+		break;
+	case 12000:
+		fs = DA7213_SR_12000;
+		break;
+	case 16000:
+		fs = DA7213_SR_16000;
+		break;
+	case 22050:
+		fs = DA7213_SR_22050;
+		break;
+	case 32000:
+		fs = DA7213_SR_32000;
+		break;
+	case 44100:
+		fs = DA7213_SR_44100;
+		break;
+	case 48000:
+		fs = DA7213_SR_48000;
+		break;
+	case 88200:
+		fs = DA7213_SR_88200;
+		break;
+	case 96000:
+		fs = DA7213_SR_96000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, DA7213_DAI_CTRL, DA7213_DAI_WORD_LENGTH_MASK,
+			    dai_ctrl);
+	snd_soc_component_write(component, DA7213_SR, fs);
+
+	return 0;
+}
+
+static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+	u8 dai_clk_mode = 0, dai_ctrl = 0;
+	u8 dai_offset = 0;
+
+	/* Set master/slave mode */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		da7213->master = true;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		da7213->master = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Set clock normal/inverted */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			dai_clk_mode |= DA7213_DAI_WCLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			dai_clk_mode |= DA7213_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			dai_clk_mode |= DA7213_DAI_WCLK_POL_INV |
+					DA7213_DAI_CLK_POL_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAI_FORMAT_DSP_A:
+	case SND_SOC_DAI_FORMAT_DSP_B:
+		/* The bclk is inverted wrt ASoC conventions */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			dai_clk_mode |= DA7213_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			dai_clk_mode |= DA7213_DAI_WCLK_POL_INV |
+					DA7213_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			dai_clk_mode |= DA7213_DAI_WCLK_POL_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Only I2S is supported */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		dai_ctrl |= DA7213_DAI_FORMAT_I2S_MODE;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		dai_ctrl |= DA7213_DAI_FORMAT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		dai_ctrl |= DA7213_DAI_FORMAT_RIGHT_J;
+		break;
+	case SND_SOC_DAI_FORMAT_DSP_A: /* L data MSB after FRM LRC */
+		dai_ctrl |= DA7213_DAI_FORMAT_DSP;
+		dai_offset = 1;
+		break;
+	case SND_SOC_DAI_FORMAT_DSP_B: /* L data MSB during FRM LRC */
+		dai_ctrl |= DA7213_DAI_FORMAT_DSP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* By default only 64 BCLK per WCLK is supported */
+	dai_clk_mode |= DA7213_DAI_BCLKS_PER_WCLK_64;
+
+	snd_soc_component_write(component, DA7213_DAI_CLK_MODE, dai_clk_mode);
+	snd_soc_component_update_bits(component, DA7213_DAI_CTRL, DA7213_DAI_FORMAT_MASK,
+			    dai_ctrl);
+	snd_soc_component_write(component, DA7213_DAI_OFFSET, dai_offset);
+
+	return 0;
+}
+
+static int da7213_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute) {
+		snd_soc_component_update_bits(component, DA7213_DAC_L_CTRL,
+				    DA7213_MUTE_EN, DA7213_MUTE_EN);
+		snd_soc_component_update_bits(component, DA7213_DAC_R_CTRL,
+				    DA7213_MUTE_EN, DA7213_MUTE_EN);
+	} else {
+		snd_soc_component_update_bits(component, DA7213_DAC_L_CTRL,
+				    DA7213_MUTE_EN, 0);
+		snd_soc_component_update_bits(component, DA7213_DAC_R_CTRL,
+				    DA7213_MUTE_EN, 0);
+	}
+
+	return 0;
+}
+
+#define DA7213_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	if ((da7213->clk_src == clk_id) && (da7213->mclk_rate == freq))
+		return 0;
+
+	if (((freq < 5000000) && (freq != 32768)) || (freq > 54000000)) {
+		dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+			freq);
+		return -EINVAL;
+	}
+
+	switch (clk_id) {
+	case DA7213_CLKSRC_MCLK:
+		snd_soc_component_update_bits(component, DA7213_PLL_CTRL,
+				    DA7213_PLL_MCLK_SQR_EN, 0);
+		break;
+	case DA7213_CLKSRC_MCLK_SQR:
+		snd_soc_component_update_bits(component, DA7213_PLL_CTRL,
+				    DA7213_PLL_MCLK_SQR_EN,
+				    DA7213_PLL_MCLK_SQR_EN);
+		break;
+	default:
+		dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	da7213->clk_src = clk_id;
+
+	if (da7213->mclk) {
+		freq = clk_round_rate(da7213->mclk, freq);
+		ret = clk_set_rate(da7213->mclk, freq);
+		if (ret) {
+			dev_err(codec_dai->dev, "Failed to set clock rate %d\n",
+				freq);
+			return ret;
+		}
+	}
+
+	da7213->mclk_rate = freq;
+
+	return 0;
+}
+
+/* Supported PLL input frequencies are 32KHz, 5MHz - 54MHz. */
+static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+			      int source, unsigned int fref, unsigned int fout)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+
+	u8 pll_ctrl, indiv_bits, indiv;
+	u8 pll_frac_top, pll_frac_bot, pll_integer;
+	u32 freq_ref;
+	u64 frac_div;
+
+	/* Workout input divider based on MCLK rate */
+	if (da7213->mclk_rate == 32768) {
+		if (!da7213->master) {
+			dev_err(component->dev,
+				"32KHz only valid if codec is clock master\n");
+			return -EINVAL;
+		}
+
+		/* 32KHz PLL Mode */
+		indiv_bits = DA7213_PLL_INDIV_9_TO_18_MHZ;
+		indiv = DA7213_PLL_INDIV_9_TO_18_MHZ_VAL;
+		source = DA7213_SYSCLK_PLL_32KHZ;
+		freq_ref = 3750000;
+
+	} else {
+		if (da7213->mclk_rate < 5000000) {
+			dev_err(component->dev,
+				"PLL input clock %d below valid range\n",
+				da7213->mclk_rate);
+			return -EINVAL;
+		} else if (da7213->mclk_rate <= 9000000) {
+			indiv_bits = DA7213_PLL_INDIV_5_TO_9_MHZ;
+			indiv = DA7213_PLL_INDIV_5_TO_9_MHZ_VAL;
+		} else if (da7213->mclk_rate <= 18000000) {
+			indiv_bits = DA7213_PLL_INDIV_9_TO_18_MHZ;
+			indiv = DA7213_PLL_INDIV_9_TO_18_MHZ_VAL;
+		} else if (da7213->mclk_rate <= 36000000) {
+			indiv_bits = DA7213_PLL_INDIV_18_TO_36_MHZ;
+			indiv = DA7213_PLL_INDIV_18_TO_36_MHZ_VAL;
+		} else if (da7213->mclk_rate <= 54000000) {
+			indiv_bits = DA7213_PLL_INDIV_36_TO_54_MHZ;
+			indiv = DA7213_PLL_INDIV_36_TO_54_MHZ_VAL;
+		} else {
+			dev_err(component->dev,
+				"PLL input clock %d above valid range\n",
+				da7213->mclk_rate);
+			return -EINVAL;
+		}
+		freq_ref = (da7213->mclk_rate / indiv);
+	}
+
+	pll_ctrl = indiv_bits;
+
+	/* Configure PLL */
+	switch (source) {
+	case DA7213_SYSCLK_MCLK:
+		snd_soc_component_update_bits(component, DA7213_PLL_CTRL,
+				    DA7213_PLL_INDIV_MASK |
+				    DA7213_PLL_MODE_MASK, pll_ctrl);
+		return 0;
+	case DA7213_SYSCLK_PLL:
+		break;
+	case DA7213_SYSCLK_PLL_SRM:
+		pll_ctrl |= DA7213_PLL_SRM_EN;
+		fout = DA7213_PLL_FREQ_OUT_94310400;
+		break;
+	case DA7213_SYSCLK_PLL_32KHZ:
+		if (da7213->mclk_rate != 32768) {
+			dev_err(component->dev,
+				"32KHz mode only valid with 32KHz MCLK\n");
+			return -EINVAL;
+		}
+
+		pll_ctrl |= DA7213_PLL_32K_MODE | DA7213_PLL_SRM_EN;
+		fout = DA7213_PLL_FREQ_OUT_94310400;
+		break;
+	default:
+		dev_err(component->dev, "Invalid PLL config\n");
+		return -EINVAL;
+	}
+
+	/* Calculate dividers for PLL */
+	pll_integer = fout / freq_ref;
+	frac_div = (u64)(fout % freq_ref) * 8192ULL;
+	do_div(frac_div, freq_ref);
+	pll_frac_top = (frac_div >> DA7213_BYTE_SHIFT) & DA7213_BYTE_MASK;
+	pll_frac_bot = (frac_div) & DA7213_BYTE_MASK;
+
+	/* Write PLL dividers */
+	snd_soc_component_write(component, DA7213_PLL_FRAC_TOP, pll_frac_top);
+	snd_soc_component_write(component, DA7213_PLL_FRAC_BOT, pll_frac_bot);
+	snd_soc_component_write(component, DA7213_PLL_INTEGER, pll_integer);
+
+	/* Enable PLL */
+	pll_ctrl |= DA7213_PLL_EN;
+	snd_soc_component_update_bits(component, DA7213_PLL_CTRL,
+			    DA7213_PLL_INDIV_MASK | DA7213_PLL_MODE_MASK,
+			    pll_ctrl);
+
+	/* Assist 32KHz mode PLL lock */
+	if (source == DA7213_SYSCLK_PLL_32KHZ) {
+		snd_soc_component_write(component, 0xF0, 0x8B);
+		snd_soc_component_write(component, 0xF1, 0x03);
+		snd_soc_component_write(component, 0xF1, 0x01);
+		snd_soc_component_write(component, 0xF0, 0x00);
+	}
+
+	return 0;
+}
+
+/* DAI operations */
+static const struct snd_soc_dai_ops da7213_dai_ops = {
+	.hw_params	= da7213_hw_params,
+	.set_fmt	= da7213_set_dai_fmt,
+	.set_sysclk	= da7213_set_dai_sysclk,
+	.set_pll	= da7213_set_dai_pll,
+	.digital_mute	= da7213_mute,
+};
+
+static struct snd_soc_dai_driver da7213_dai = {
+	.name = "da7213-hifi",
+	/* Playback Capabilities */
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = DA7213_FORMATS,
+	},
+	/* Capture Capabilities */
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = DA7213_FORMATS,
+	},
+	.ops = &da7213_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int da7213_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* Enable MCLK for transition to ON state */
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) {
+			if (da7213->mclk) {
+				ret = clk_prepare_enable(da7213->mclk);
+				if (ret) {
+					dev_err(component->dev,
+						"Failed to enable mclk\n");
+					return ret;
+				}
+			}
+		}
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/* Enable VMID reference & master bias */
+			snd_soc_component_update_bits(component, DA7213_REFERENCES,
+					    DA7213_VMID_EN | DA7213_BIAS_EN,
+					    DA7213_VMID_EN | DA7213_BIAS_EN);
+		} else {
+			/* Remove MCLK */
+			if (da7213->mclk)
+				clk_disable_unprepare(da7213->mclk);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* Disable VMID reference & master bias */
+		snd_soc_component_update_bits(component, DA7213_REFERENCES,
+				    DA7213_VMID_EN | DA7213_BIAS_EN, 0);
+		break;
+	}
+	return 0;
+}
+
+#if defined(CONFIG_OF)
+/* DT */
+static const struct of_device_id da7213_of_match[] = {
+	{ .compatible = "dlg,da7213", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, da7213_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id da7213_acpi_match[] = {
+	{ "DLGS7212", 0},
+	{ "DLGS7213", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, da7213_acpi_match);
+#endif
+
+static enum da7213_micbias_voltage
+	da7213_of_micbias_lvl(struct snd_soc_component *component, u32 val)
+{
+	switch (val) {
+	case 1600:
+		return DA7213_MICBIAS_1_6V;
+	case 2200:
+		return DA7213_MICBIAS_2_2V;
+	case 2500:
+		return DA7213_MICBIAS_2_5V;
+	case 3000:
+		return DA7213_MICBIAS_3_0V;
+	default:
+		dev_warn(component->dev, "Invalid micbias level\n");
+		return DA7213_MICBIAS_2_2V;
+	}
+}
+
+static enum da7213_dmic_data_sel
+	da7213_of_dmic_data_sel(struct snd_soc_component *component, const char *str)
+{
+	if (!strcmp(str, "lrise_rfall")) {
+		return DA7213_DMIC_DATA_LRISE_RFALL;
+	} else if (!strcmp(str, "lfall_rrise")) {
+		return DA7213_DMIC_DATA_LFALL_RRISE;
+	} else {
+		dev_warn(component->dev, "Invalid DMIC data select type\n");
+		return DA7213_DMIC_DATA_LRISE_RFALL;
+	}
+}
+
+static enum da7213_dmic_samplephase
+	da7213_of_dmic_samplephase(struct snd_soc_component *component, const char *str)
+{
+	if (!strcmp(str, "on_clkedge")) {
+		return DA7213_DMIC_SAMPLE_ON_CLKEDGE;
+	} else if (!strcmp(str, "between_clkedge")) {
+		return DA7213_DMIC_SAMPLE_BETWEEN_CLKEDGE;
+	} else {
+		dev_warn(component->dev, "Invalid DMIC sample phase\n");
+		return DA7213_DMIC_SAMPLE_ON_CLKEDGE;
+	}
+}
+
+static enum da7213_dmic_clk_rate
+	da7213_of_dmic_clkrate(struct snd_soc_component *component, u32 val)
+{
+	switch (val) {
+	case 1500000:
+		return DA7213_DMIC_CLK_1_5MHZ;
+	case 3000000:
+		return DA7213_DMIC_CLK_3_0MHZ;
+	default:
+		dev_warn(component->dev, "Invalid DMIC clock rate\n");
+		return DA7213_DMIC_CLK_1_5MHZ;
+	}
+}
+
+static struct da7213_platform_data
+	*da7213_fw_to_pdata(struct snd_soc_component *component)
+{
+	struct device *dev = component->dev;
+	struct da7213_platform_data *pdata;
+	const char *fw_str;
+	u32 fw_val32;
+
+	pdata = devm_kzalloc(component->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	if (device_property_read_u32(dev, "dlg,micbias1-lvl", &fw_val32) >= 0)
+		pdata->micbias1_lvl = da7213_of_micbias_lvl(component, fw_val32);
+	else
+		pdata->micbias1_lvl = DA7213_MICBIAS_2_2V;
+
+	if (device_property_read_u32(dev, "dlg,micbias2-lvl", &fw_val32) >= 0)
+		pdata->micbias2_lvl = da7213_of_micbias_lvl(component, fw_val32);
+	else
+		pdata->micbias2_lvl = DA7213_MICBIAS_2_2V;
+
+	if (!device_property_read_string(dev, "dlg,dmic-data-sel", &fw_str))
+		pdata->dmic_data_sel = da7213_of_dmic_data_sel(component, fw_str);
+	else
+		pdata->dmic_data_sel = DA7213_DMIC_DATA_LRISE_RFALL;
+
+	if (!device_property_read_string(dev, "dlg,dmic-samplephase", &fw_str))
+		pdata->dmic_samplephase =
+			da7213_of_dmic_samplephase(component, fw_str);
+	else
+		pdata->dmic_samplephase = DA7213_DMIC_SAMPLE_ON_CLKEDGE;
+
+	if (device_property_read_u32(dev, "dlg,dmic-clkrate", &fw_val32) >= 0)
+		pdata->dmic_clk_rate = da7213_of_dmic_clkrate(component, fw_val32);
+	else
+		pdata->dmic_clk_rate = DA7213_DMIC_CLK_3_0MHZ;
+
+	return pdata;
+}
+
+
+static int da7213_probe(struct snd_soc_component *component)
+{
+	struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+
+	/* Default to using ALC auto offset calibration mode. */
+	snd_soc_component_update_bits(component, DA7213_ALC_CTRL1,
+			    DA7213_ALC_CALIB_MODE_MAN, 0);
+	da7213->alc_calib_auto = true;
+
+	/* Default PC counter to free-running */
+	snd_soc_component_update_bits(component, DA7213_PC_COUNT, DA7213_PC_FREERUN_MASK,
+			    DA7213_PC_FREERUN_MASK);
+
+	/* Enable all Gain Ramps */
+	snd_soc_component_update_bits(component, DA7213_AUX_L_CTRL,
+			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
+	snd_soc_component_update_bits(component, DA7213_AUX_R_CTRL,
+			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
+	snd_soc_component_update_bits(component, DA7213_MIXIN_L_CTRL,
+			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
+	snd_soc_component_update_bits(component, DA7213_MIXIN_R_CTRL,
+			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
+	snd_soc_component_update_bits(component, DA7213_ADC_L_CTRL,
+			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
+	snd_soc_component_update_bits(component, DA7213_ADC_R_CTRL,
+			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
+	snd_soc_component_update_bits(component, DA7213_DAC_L_CTRL,
+			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
+	snd_soc_component_update_bits(component, DA7213_DAC_R_CTRL,
+			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
+	snd_soc_component_update_bits(component, DA7213_HP_L_CTRL,
+			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
+	snd_soc_component_update_bits(component, DA7213_HP_R_CTRL,
+			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
+	snd_soc_component_update_bits(component, DA7213_LINE_CTRL,
+			    DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN);
+
+	/*
+	 * There are two separate control bits for input and output mixers as
+	 * well as headphone and line outs.
+	 * One to enable corresponding amplifier and other to enable its
+	 * output. As amplifier bits are related to power control, they are
+	 * being managed by DAPM while other (non power related) bits are
+	 * enabled here
+	 */
+	snd_soc_component_update_bits(component, DA7213_MIXIN_L_CTRL,
+			    DA7213_MIXIN_MIX_EN, DA7213_MIXIN_MIX_EN);
+	snd_soc_component_update_bits(component, DA7213_MIXIN_R_CTRL,
+			    DA7213_MIXIN_MIX_EN, DA7213_MIXIN_MIX_EN);
+
+	snd_soc_component_update_bits(component, DA7213_MIXOUT_L_CTRL,
+			    DA7213_MIXOUT_MIX_EN, DA7213_MIXOUT_MIX_EN);
+	snd_soc_component_update_bits(component, DA7213_MIXOUT_R_CTRL,
+			    DA7213_MIXOUT_MIX_EN, DA7213_MIXOUT_MIX_EN);
+
+	snd_soc_component_update_bits(component, DA7213_HP_L_CTRL,
+			    DA7213_HP_AMP_OE, DA7213_HP_AMP_OE);
+	snd_soc_component_update_bits(component, DA7213_HP_R_CTRL,
+			    DA7213_HP_AMP_OE, DA7213_HP_AMP_OE);
+
+	snd_soc_component_update_bits(component, DA7213_LINE_CTRL,
+			    DA7213_LINE_AMP_OE, DA7213_LINE_AMP_OE);
+
+	/* Handle DT/Platform data */
+	da7213->pdata = dev_get_platdata(component->dev);
+	if (!da7213->pdata)
+		da7213->pdata = da7213_fw_to_pdata(component);
+
+	/* Set platform data values */
+	if (da7213->pdata) {
+		struct da7213_platform_data *pdata = da7213->pdata;
+		u8 micbias_lvl = 0, dmic_cfg = 0;
+
+		/* Set Mic Bias voltages */
+		switch (pdata->micbias1_lvl) {
+		case DA7213_MICBIAS_1_6V:
+		case DA7213_MICBIAS_2_2V:
+		case DA7213_MICBIAS_2_5V:
+		case DA7213_MICBIAS_3_0V:
+			micbias_lvl |= (pdata->micbias1_lvl <<
+					DA7213_MICBIAS1_LEVEL_SHIFT);
+			break;
+		}
+		switch (pdata->micbias2_lvl) {
+		case DA7213_MICBIAS_1_6V:
+		case DA7213_MICBIAS_2_2V:
+		case DA7213_MICBIAS_2_5V:
+		case DA7213_MICBIAS_3_0V:
+			micbias_lvl |= (pdata->micbias2_lvl <<
+					 DA7213_MICBIAS2_LEVEL_SHIFT);
+			break;
+		}
+		snd_soc_component_update_bits(component, DA7213_MICBIAS_CTRL,
+				    DA7213_MICBIAS1_LEVEL_MASK |
+				    DA7213_MICBIAS2_LEVEL_MASK, micbias_lvl);
+
+		/* Set DMIC configuration */
+		switch (pdata->dmic_data_sel) {
+		case DA7213_DMIC_DATA_LFALL_RRISE:
+		case DA7213_DMIC_DATA_LRISE_RFALL:
+			dmic_cfg |= (pdata->dmic_data_sel <<
+				     DA7213_DMIC_DATA_SEL_SHIFT);
+			break;
+		}
+		switch (pdata->dmic_samplephase) {
+		case DA7213_DMIC_SAMPLE_ON_CLKEDGE:
+		case DA7213_DMIC_SAMPLE_BETWEEN_CLKEDGE:
+			dmic_cfg |= (pdata->dmic_samplephase <<
+				     DA7213_DMIC_SAMPLEPHASE_SHIFT);
+			break;
+		}
+		switch (pdata->dmic_clk_rate) {
+		case DA7213_DMIC_CLK_3_0MHZ:
+		case DA7213_DMIC_CLK_1_5MHZ:
+			dmic_cfg |= (pdata->dmic_clk_rate <<
+				     DA7213_DMIC_CLK_RATE_SHIFT);
+			break;
+		}
+		snd_soc_component_update_bits(component, DA7213_MIC_CONFIG,
+				    DA7213_DMIC_DATA_SEL_MASK |
+				    DA7213_DMIC_SAMPLEPHASE_MASK |
+				    DA7213_DMIC_CLK_RATE_MASK, dmic_cfg);
+	}
+
+	/* Check if MCLK provided */
+	da7213->mclk = devm_clk_get(component->dev, "mclk");
+	if (IS_ERR(da7213->mclk)) {
+		if (PTR_ERR(da7213->mclk) != -ENOENT)
+			return PTR_ERR(da7213->mclk);
+		else
+			da7213->mclk = NULL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_da7213 = {
+	.probe			= da7213_probe,
+	.set_bias_level		= da7213_set_bias_level,
+	.controls		= da7213_snd_controls,
+	.num_controls		= ARRAY_SIZE(da7213_snd_controls),
+	.dapm_widgets		= da7213_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(da7213_dapm_widgets),
+	.dapm_routes		= da7213_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(da7213_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config da7213_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.reg_defaults = da7213_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(da7213_reg_defaults),
+	.volatile_reg = da7213_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int da7213_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct da7213_priv *da7213;
+	int ret;
+
+	da7213 = devm_kzalloc(&i2c->dev, sizeof(*da7213), GFP_KERNEL);
+	if (!da7213)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, da7213);
+
+	da7213->regmap = devm_regmap_init_i2c(i2c, &da7213_regmap_config);
+	if (IS_ERR(da7213->regmap)) {
+		ret = PTR_ERR(da7213->regmap);
+		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_da7213, &da7213_dai, 1);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register da7213 component: %d\n",
+			ret);
+	}
+	return ret;
+}
+
+static const struct i2c_device_id da7213_i2c_id[] = {
+	{ "da7213", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, da7213_i2c_id);
+
+/* I2C codec control layer */
+static struct i2c_driver da7213_i2c_driver = {
+	.driver = {
+		.name = "da7213",
+		.of_match_table = of_match_ptr(da7213_of_match),
+		.acpi_match_table = ACPI_PTR(da7213_acpi_match),
+	},
+	.probe		= da7213_i2c_probe,
+	.id_table	= da7213_i2c_id,
+};
+
+module_i2c_driver(da7213_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC DA7213 Codec driver");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h
new file mode 100644
index 0000000..5a78dba
--- /dev/null
+++ b/sound/soc/codecs/da7213.h
@@ -0,0 +1,537 @@
+/*
+ * da7213.h - DA7213 ASoC Codec Driver
+ *
+ * Copyright (c) 2013 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _DA7213_H
+#define _DA7213_H
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <sound/da7213.h>
+
+/*
+ * Registers
+ */
+
+/* Status Registers */
+#define DA7213_STATUS1			0x02
+#define DA7213_PLL_STATUS		0x03
+#define DA7213_AUX_L_GAIN_STATUS	0x04
+#define DA7213_AUX_R_GAIN_STATUS	0x05
+#define DA7213_MIC_1_GAIN_STATUS	0x06
+#define DA7213_MIC_2_GAIN_STATUS	0x07
+#define DA7213_MIXIN_L_GAIN_STATUS	0x08
+#define DA7213_MIXIN_R_GAIN_STATUS	0x09
+#define DA7213_ADC_L_GAIN_STATUS	0x0A
+#define DA7213_ADC_R_GAIN_STATUS	0x0B
+#define DA7213_DAC_L_GAIN_STATUS	0x0C
+#define DA7213_DAC_R_GAIN_STATUS	0x0D
+#define DA7213_HP_L_GAIN_STATUS		0x0E
+#define DA7213_HP_R_GAIN_STATUS		0x0F
+#define DA7213_LINE_GAIN_STATUS		0x10
+
+/* System Initialisation Registers */
+#define DA7213_DIG_ROUTING_DAI		0x21
+#define DA7213_SR			0x22
+#define DA7213_REFERENCES		0x23
+#define DA7213_PLL_FRAC_TOP		0x24
+#define DA7213_PLL_FRAC_BOT		0x25
+#define DA7213_PLL_INTEGER		0x26
+#define DA7213_PLL_CTRL			0x27
+#define DA7213_DAI_CLK_MODE		0x28
+#define DA7213_DAI_CTRL			0x29
+#define DA7213_DIG_ROUTING_DAC		0x2A
+#define DA7213_ALC_CTRL1		0x2B
+
+/* Input - Gain, Select and Filter Registers */
+#define DA7213_AUX_L_GAIN		0x30
+#define DA7213_AUX_R_GAIN		0x31
+#define DA7213_MIXIN_L_SELECT		0x32
+#define DA7213_MIXIN_R_SELECT		0x33
+#define DA7213_MIXIN_L_GAIN		0x34
+#define DA7213_MIXIN_R_GAIN		0x35
+#define DA7213_ADC_L_GAIN		0x36
+#define DA7213_ADC_R_GAIN		0x37
+#define DA7213_ADC_FILTERS1		0x38
+#define DA7213_MIC_1_GAIN		0x39
+#define DA7213_MIC_2_GAIN		0x3A
+
+/* Output - Gain, Select and Filter Registers */
+#define DA7213_DAC_FILTERS5		0x40
+#define DA7213_DAC_FILTERS2		0x41
+#define DA7213_DAC_FILTERS3		0x42
+#define DA7213_DAC_FILTERS4		0x43
+#define DA7213_DAC_FILTERS1		0x44
+#define DA7213_DAC_L_GAIN		0x45
+#define DA7213_DAC_R_GAIN		0x46
+#define DA7213_CP_CTRL			0x47
+#define DA7213_HP_L_GAIN		0x48
+#define DA7213_HP_R_GAIN		0x49
+#define DA7213_LINE_GAIN		0x4A
+#define DA7213_MIXOUT_L_SELECT		0x4B
+#define DA7213_MIXOUT_R_SELECT		0x4C
+
+/* System Controller Registers */
+#define DA7213_SYSTEM_MODES_INPUT	0x50
+#define DA7213_SYSTEM_MODES_OUTPUT	0x51
+
+/* Control Registers */
+#define DA7213_AUX_L_CTRL		0x60
+#define DA7213_AUX_R_CTRL		0x61
+#define DA7213_MICBIAS_CTRL		0x62
+#define DA7213_MIC_1_CTRL		0x63
+#define DA7213_MIC_2_CTRL		0x64
+#define DA7213_MIXIN_L_CTRL		0x65
+#define DA7213_MIXIN_R_CTRL		0x66
+#define DA7213_ADC_L_CTRL		0x67
+#define DA7213_ADC_R_CTRL		0x68
+#define DA7213_DAC_L_CTRL		0x69
+#define DA7213_DAC_R_CTRL		0x6A
+#define DA7213_HP_L_CTRL		0x6B
+#define DA7213_HP_R_CTRL		0x6C
+#define DA7213_LINE_CTRL		0x6D
+#define DA7213_MIXOUT_L_CTRL		0x6E
+#define DA7213_MIXOUT_R_CTRL		0x6F
+
+/* Configuration Registers */
+#define DA7213_LDO_CTRL			0x90
+#define DA7213_IO_CTRL			0x91
+#define DA7213_GAIN_RAMP_CTRL		0x92
+#define DA7213_MIC_CONFIG		0x93
+#define DA7213_PC_COUNT			0x94
+#define DA7213_CP_VOL_THRESHOLD1	0x95
+#define DA7213_CP_DELAY			0x96
+#define DA7213_CP_DETECTOR		0x97
+#define DA7213_DAI_OFFSET		0x98
+#define DA7213_DIG_CTRL			0x99
+#define DA7213_ALC_CTRL2		0x9A
+#define DA7213_ALC_CTRL3		0x9B
+#define DA7213_ALC_NOISE		0x9C
+#define DA7213_ALC_TARGET_MIN		0x9D
+#define DA7213_ALC_TARGET_MAX		0x9E
+#define DA7213_ALC_GAIN_LIMITS		0x9F
+#define DA7213_ALC_ANA_GAIN_LIMITS	0xA0
+#define DA7213_ALC_ANTICLIP_CTRL	0xA1
+#define DA7213_ALC_ANTICLIP_LEVEL	0xA2
+
+#define DA7213_ALC_OFFSET_AUTO_M_L	0xA3
+#define DA7213_ALC_OFFSET_AUTO_U_L	0xA4
+#define DA7213_ALC_OFFSET_MAN_M_L	0xA6
+#define DA7213_ALC_OFFSET_MAN_U_L	0xA7
+#define DA7213_ALC_OFFSET_AUTO_M_R	0xA8
+#define DA7213_ALC_OFFSET_AUTO_U_R	0xA9
+#define DA7213_ALC_OFFSET_MAN_M_R	0xAB
+#define DA7213_ALC_OFFSET_MAN_U_R	0xAC
+#define DA7213_ALC_CIC_OP_LVL_CTRL	0xAD
+#define DA7213_ALC_CIC_OP_LVL_DATA	0xAE
+#define DA7213_DAC_NG_SETUP_TIME	0xAF
+#define DA7213_DAC_NG_OFF_THRESHOLD	0xB0
+#define DA7213_DAC_NG_ON_THRESHOLD	0xB1
+#define DA7213_DAC_NG_CTRL		0xB2
+
+
+/*
+ * Bit fields
+ */
+
+/* DA7213_PLL_STATUS = 0x03 */
+#define DA7219_PLL_SRM_LOCK					(0x1 << 1)
+
+/* DA7213_SR = 0x22 */
+#define DA7213_SR_8000						(0x1 << 0)
+#define DA7213_SR_11025						(0x2 << 0)
+#define DA7213_SR_12000						(0x3 << 0)
+#define DA7213_SR_16000						(0x5 << 0)
+#define DA7213_SR_22050						(0x6 << 0)
+#define DA7213_SR_24000						(0x7 << 0)
+#define DA7213_SR_32000						(0x9 << 0)
+#define DA7213_SR_44100						(0xA << 0)
+#define DA7213_SR_48000						(0xB << 0)
+#define DA7213_SR_88200						(0xE << 0)
+#define DA7213_SR_96000						(0xF << 0)
+
+/* DA7213_REFERENCES = 0x23 */
+#define DA7213_BIAS_EN						(0x1 << 3)
+#define DA7213_VMID_EN						(0x1 << 7)
+
+/* DA7213_PLL_CTRL = 0x27 */
+#define DA7213_PLL_INDIV_5_TO_9_MHZ				(0x0 << 2)
+#define DA7213_PLL_INDIV_9_TO_18_MHZ				(0x1 << 2)
+#define DA7213_PLL_INDIV_18_TO_36_MHZ				(0x2 << 2)
+#define DA7213_PLL_INDIV_36_TO_54_MHZ				(0x3 << 2)
+#define DA7213_PLL_INDIV_MASK					(0x3 << 2)
+#define DA7213_PLL_MCLK_SQR_EN					(0x1 << 4)
+#define DA7213_PLL_32K_MODE					(0x1 << 5)
+#define DA7213_PLL_SRM_EN					(0x1 << 6)
+#define DA7213_PLL_EN						(0x1 << 7)
+#define DA7213_PLL_MODE_MASK					(0x7 << 5)
+
+/* DA7213_DAI_CLK_MODE = 0x28 */
+#define DA7213_DAI_BCLKS_PER_WCLK_32				(0x0 << 0)
+#define DA7213_DAI_BCLKS_PER_WCLK_64				(0x1 << 0)
+#define DA7213_DAI_BCLKS_PER_WCLK_128				(0x2 << 0)
+#define DA7213_DAI_BCLKS_PER_WCLK_256				(0x3 << 0)
+#define DA7213_DAI_BCLKS_PER_WCLK_MASK				(0x3 << 0)
+#define DA7213_DAI_CLK_POL_INV					(0x1 << 2)
+#define DA7213_DAI_WCLK_POL_INV					(0x1 << 3)
+#define DA7213_DAI_CLK_EN_MASK					(0x1 << 7)
+
+/* DA7213_DAI_CTRL = 0x29 */
+#define DA7213_DAI_FORMAT_I2S_MODE				(0x0 << 0)
+#define DA7213_DAI_FORMAT_LEFT_J				(0x1 << 0)
+#define DA7213_DAI_FORMAT_RIGHT_J				(0x2 << 0)
+#define DA7213_DAI_FORMAT_DSP					(0x3 << 0)
+#define DA7213_DAI_FORMAT_MASK					(0x3 << 0)
+#define DA7213_DAI_WORD_LENGTH_S16_LE				(0x0 << 2)
+#define DA7213_DAI_WORD_LENGTH_S20_LE				(0x1 << 2)
+#define DA7213_DAI_WORD_LENGTH_S24_LE				(0x2 << 2)
+#define DA7213_DAI_WORD_LENGTH_S32_LE				(0x3 << 2)
+#define DA7213_DAI_WORD_LENGTH_MASK				(0x3 << 2)
+#define DA7213_DAI_EN_SHIFT					7
+
+/* DA7213_DIG_ROUTING_DAI = 0x21 */
+#define DA7213_DAI_L_SRC_SHIFT					0
+#define DA7213_DAI_R_SRC_SHIFT					4
+#define DA7213_DAI_SRC_MAX					4
+
+/* DA7213_DIG_ROUTING_DAC = 0x2A */
+#define DA7213_DAC_L_SRC_SHIFT					0
+#define DA7213_DAC_L_MONO_SHIFT					3
+#define DA7213_DAC_R_SRC_SHIFT					4
+#define DA7213_DAC_R_MONO_SHIFT					7
+#define DA7213_DAC_SRC_MAX					4
+#define DA7213_DAC_MONO_MAX					0x1
+
+/* DA7213_ALC_CTRL1 = 0x2B */
+#define DA7213_ALC_OFFSET_EN_SHIFT				0
+#define DA7213_ALC_OFFSET_EN_MAX				0x1
+#define DA7213_ALC_OFFSET_EN					(0x1 << 0)
+#define DA7213_ALC_SYNC_MODE					(0x1 << 1)
+#define DA7213_ALC_CALIB_MODE_MAN				(0x1 << 2)
+#define DA7213_ALC_L_EN_SHIFT					3
+#define DA7213_ALC_AUTO_CALIB_EN				(0x1 << 4)
+#define DA7213_ALC_CALIB_OVERFLOW				(0x1 << 5)
+#define DA7213_ALC_R_EN_SHIFT					7
+#define DA7213_ALC_EN_MAX					0x1
+
+/* DA7213_AUX_L/R_GAIN = 0x30/0x31 */
+#define DA7213_AUX_AMP_GAIN_SHIFT				0
+#define DA7213_AUX_AMP_GAIN_MAX					0x3F
+
+/* DA7213_MIXIN_L/R_SELECT = 0x32/0x33 */
+#define DA7213_DMIC_EN_SHIFT					7
+#define DA7213_DMIC_EN_MAX					0x1
+
+/* DA7213_MIXIN_L_SELECT = 0x32 */
+#define DA7213_MIXIN_L_MIX_SELECT_AUX_L_SHIFT			0
+#define DA7213_MIXIN_L_MIX_SELECT_MIC_1_SHIFT			1
+#define DA7213_MIXIN_L_MIX_SELECT_MIC_1				(0x1 << 1)
+#define DA7213_MIXIN_L_MIX_SELECT_MIC_2_SHIFT			2
+#define DA7213_MIXIN_L_MIX_SELECT_MIC_2				(0x1 << 2)
+#define DA7213_MIXIN_L_MIX_SELECT_MIXIN_R_SHIFT			3
+#define DA7213_MIXIN_L_MIX_SELECT_MAX				0x1
+
+/* DA7213_MIXIN_R_SELECT =  0x33 */
+#define DA7213_MIXIN_R_MIX_SELECT_AUX_R_SHIFT			0
+#define DA7213_MIXIN_R_MIX_SELECT_MIC_2_SHIFT			1
+#define DA7213_MIXIN_R_MIX_SELECT_MIC_2				(0x1 << 1)
+#define DA7213_MIXIN_R_MIX_SELECT_MIC_1_SHIFT			2
+#define DA7213_MIXIN_R_MIX_SELECT_MIC_1				(0x1 << 2)
+#define DA7213_MIXIN_R_MIX_SELECT_MIXIN_L_SHIFT			3
+#define DA7213_MIXIN_R_MIX_SELECT_MAX				0x1
+#define DA7213_MIC_BIAS_OUTPUT_SELECT_2				(0x1 << 6)
+
+/* DA7213_MIXIN_L/R_GAIN = 0x34/0x35 */
+#define DA7213_MIXIN_AMP_GAIN_SHIFT				0
+#define DA7213_MIXIN_AMP_GAIN_MAX				0xF
+
+/* DA7213_ADC_L/R_GAIN = 0x36/0x37 */
+#define DA7213_ADC_AMP_GAIN_SHIFT				0
+#define DA7213_ADC_AMP_GAIN_MAX					0x7F
+
+/* DA7213_ADC/DAC_FILTERS1 = 0x38/0x44 */
+#define DA7213_VOICE_HPF_CORNER_SHIFT				0
+#define DA7213_VOICE_HPF_CORNER_MAX				8
+#define DA7213_VOICE_EN_SHIFT					3
+#define DA7213_VOICE_EN_MAX					0x1
+#define DA7213_AUDIO_HPF_CORNER_SHIFT				4
+#define DA7213_AUDIO_HPF_CORNER_MAX				4
+#define DA7213_HPF_EN_SHIFT					7
+#define DA7213_HPF_EN_MAX					0x1
+
+/* DA7213_MIC_1/2_GAIN = 0x39/0x3A */
+#define DA7213_MIC_AMP_GAIN_SHIFT				0
+#define DA7213_MIC_AMP_GAIN_MAX					0x7
+
+/* DA7213_DAC_FILTERS5 = 0x40 */
+#define DA7213_DAC_SOFTMUTE_EN_SHIFT				7
+#define DA7213_DAC_SOFTMUTE_EN_MAX				0x1
+#define DA7213_DAC_SOFTMUTE_RATE_SHIFT				4
+#define DA7213_DAC_SOFTMUTE_RATE_MAX				7
+
+/* DA7213_DAC_FILTERS2/3/4 = 0x41/0x42/0x43 */
+#define DA7213_DAC_EQ_BAND_MAX					0xF
+
+/* DA7213_DAC_FILTERS2 = 0x41 */
+#define DA7213_DAC_EQ_BAND1_SHIFT				0
+#define DA7213_DAC_EQ_BAND2_SHIFT				4
+
+/* DA7213_DAC_FILTERS2 = 0x42 */
+#define DA7213_DAC_EQ_BAND3_SHIFT				0
+#define DA7213_DAC_EQ_BAND4_SHIFT				4
+
+/* DA7213_DAC_FILTERS4 = 0x43 */
+#define DA7213_DAC_EQ_BAND5_SHIFT				0
+#define DA7213_DAC_EQ_EN_SHIFT					7
+#define DA7213_DAC_EQ_EN_MAX					0x1
+
+/* DA7213_DAC_L/R_GAIN = 0x45/0x46 */
+#define DA7213_DAC_AMP_GAIN_SHIFT				0
+#define DA7213_DAC_AMP_GAIN_MAX					0x7F
+
+/* DA7213_HP_L/R_GAIN = 0x45/0x46 */
+#define DA7213_HP_AMP_GAIN_SHIFT				0
+#define DA7213_HP_AMP_GAIN_MAX					0x3F
+
+/* DA7213_CP_CTRL = 0x47 */
+#define DA7213_CP_EN_SHIFT					7
+
+/* DA7213_LINE_GAIN = 0x4A */
+#define DA7213_LINE_AMP_GAIN_SHIFT				0
+#define DA7213_LINE_AMP_GAIN_MAX				0x3F
+
+/* DA7213_MIXOUT_L_SELECT = 0x4B */
+#define DA7213_MIXOUT_L_MIX_SELECT_AUX_L_SHIFT			0
+#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_SHIFT		1
+#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_SHIFT		2
+#define DA7213_MIXOUT_L_MIX_SELECT_DAC_L_SHIFT			3
+#define DA7213_MIXOUT_L_MIX_SELECT_AUX_L_INVERTED_SHIFT		4
+#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_L_INVERTED_SHIFT	5
+#define DA7213_MIXOUT_L_MIX_SELECT_MIXIN_R_INVERTED_SHIFT	6
+#define DA7213_MIXOUT_L_MIX_SELECT_MAX				0x1
+
+/* DA7213_MIXOUT_R_SELECT = 0x4C */
+#define DA7213_MIXOUT_R_MIX_SELECT_AUX_R_SHIFT			0
+#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_SHIFT		1
+#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_SHIFT		2
+#define DA7213_MIXOUT_R_MIX_SELECT_DAC_R_SHIFT			3
+#define DA7213_MIXOUT_R_MIX_SELECT_AUX_R_INVERTED_SHIFT		4
+#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_R_INVERTED_SHIFT	5
+#define DA7213_MIXOUT_R_MIX_SELECT_MIXIN_L_INVERTED_SHIFT	6
+#define DA7213_MIXOUT_R_MIX_SELECT_MAX				0x1
+
+/*
+ * DA7213_AUX_L/R_CTRL = 0x60/0x61,
+ * DA7213_MIC_1/2_CTRL = 0x63/0x64,
+ * DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
+ * DA7213_ADC_L/R_CTRL = 0x65/0x66,
+ * DA7213_DAC_L/R_CTRL = 0x69/0x6A,
+ * DA7213_HP_L/R_CTRL = 0x6B/0x6C,
+ * DA7213_LINE_CTRL = 0x6D
+ */
+#define DA7213_MUTE_EN_SHIFT					6
+#define DA7213_MUTE_EN_MAX					0x1
+#define DA7213_MUTE_EN						(0x1 << 6)
+
+/*
+ * DA7213_AUX_L/R_CTRL = 0x60/0x61,
+ * DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
+ * DA7213_ADC_L/R_CTRL = 0x65/0x66,
+ * DA7213_DAC_L/R_CTRL = 0x69/0x6A,
+ * DA7213_HP_L/R_CTRL = 0x6B/0x6C,
+ * DA7213_LINE_CTRL = 0x6D
+ */
+#define DA7213_GAIN_RAMP_EN_SHIFT				5
+#define DA7213_GAIN_RAMP_EN_MAX					0x1
+#define DA7213_GAIN_RAMP_EN					(0x1 << 5)
+
+/*
+ * DA7213_AUX_L/R_CTRL = 0x60/0x61,
+ * DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
+ * DA7213_HP_L/R_CTRL = 0x6B/0x6C,
+ * DA7213_LINE_CTRL = 0x6D
+ */
+#define DA7213_ZC_EN_SHIFT					4
+#define DA7213_ZC_EN_MAX					0x1
+
+/*
+ * DA7213_AUX_L/R_CTRL = 0x60/0x61,
+ * DA7213_MIC_1/2_CTRL = 0x63/0x64,
+ * DA7213_MIXIN_L/R_CTRL = 0x65/0x66,
+ * DA7213_HP_L/R_CTRL = 0x6B/0x6C,
+ * DA7213_MIXOUT_L/R_CTRL = 0x6E/0x6F,
+ * DA7213_LINE_CTRL = 0x6D
+ */
+#define DA7213_AMP_EN_SHIFT					7
+
+/* DA7213_MIC_1/2_CTRL = 0x63/0x64 */
+#define DA7213_MIC_AMP_IN_SEL_SHIFT				2
+#define DA7213_MIC_AMP_IN_SEL_MAX				3
+
+/* DA7213_MICBIAS_CTRL = 0x62 */
+#define DA7213_MICBIAS1_LEVEL_SHIFT				0
+#define DA7213_MICBIAS1_LEVEL_MASK				(0x3 << 0)
+#define DA7213_MICBIAS1_EN_SHIFT				3
+#define DA7213_MICBIAS2_LEVEL_SHIFT				4
+#define DA7213_MICBIAS2_LEVEL_MASK				(0x3 << 4)
+#define DA7213_MICBIAS2_EN_SHIFT				7
+
+/* DA7213_MIXIN_L/R_CTRL = 0x65/0x66 */
+#define DA7213_MIXIN_MIX_EN					(0x1 << 3)
+
+/* DA7213_ADC_L/R_CTRL = 0x67/0x68 */
+#define DA7213_ADC_EN_SHIFT					7
+#define DA7213_ADC_EN						(0x1 << 7)
+
+/* DA7213_DAC_L/R_CTRL =  0x69/0x6A*/
+#define DA7213_DAC_EN_SHIFT					7
+
+/* DA7213_HP_L/R_CTRL = 0x6B/0x6C */
+#define DA7213_HP_AMP_OE					(0x1 << 3)
+
+/* DA7213_LINE_CTRL = 0x6D */
+#define DA7213_LINE_AMP_OE					(0x1 << 3)
+
+/* DA7213_MIXOUT_L/R_CTRL = 0x6E/0x6F */
+#define DA7213_MIXOUT_MIX_EN					(0x1 << 3)
+
+/* DA7213_GAIN_RAMP_CTRL = 0x92 */
+#define DA7213_GAIN_RAMP_RATE_SHIFT				0
+#define DA7213_GAIN_RAMP_RATE_MAX				4
+
+/* DA7213_MIC_CONFIG = 0x93 */
+#define DA7213_DMIC_DATA_SEL_SHIFT				0
+#define DA7213_DMIC_DATA_SEL_MASK				(0x1 << 0)
+#define DA7213_DMIC_SAMPLEPHASE_SHIFT				1
+#define DA7213_DMIC_SAMPLEPHASE_MASK				(0x1 << 1)
+#define DA7213_DMIC_CLK_RATE_SHIFT				2
+#define DA7213_DMIC_CLK_RATE_MASK				(0x1 << 2)
+
+/* DA7213_PC_COUNT = 0x94 */
+#define DA7213_PC_FREERUN_MASK					(0x1 << 0)
+
+/* DA7213_DIG_CTRL = 0x99 */
+#define DA7213_DAC_L_INV_SHIFT					3
+#define DA7213_DAC_R_INV_SHIFT					7
+#define DA7213_DAC_INV_MAX					0x1
+
+/* DA7213_ALC_CTRL2 = 0x9A */
+#define DA7213_ALC_ATTACK_SHIFT					0
+#define DA7213_ALC_ATTACK_MAX					13
+#define DA7213_ALC_RELEASE_SHIFT				4
+#define DA7213_ALC_RELEASE_MAX					11
+
+/* DA7213_ALC_CTRL3 = 0x9B */
+#define DA7213_ALC_HOLD_SHIFT					0
+#define DA7213_ALC_HOLD_MAX					16
+#define DA7213_ALC_INTEG_ATTACK_SHIFT				4
+#define DA7213_ALC_INTEG_RELEASE_SHIFT				6
+#define DA7213_ALC_INTEG_MAX					4
+
+/*
+ * DA7213_ALC_NOISE = 0x9C,
+ * DA7213_ALC_TARGET_MIN/MAX = 0x9D/0x9E
+ */
+#define DA7213_ALC_THRESHOLD_SHIFT				0
+#define DA7213_ALC_THRESHOLD_MAX				0x3F
+
+/* DA7213_ALC_GAIN_LIMITS = 0x9F */
+#define DA7213_ALC_ATTEN_MAX_SHIFT				0
+#define DA7213_ALC_GAIN_MAX_SHIFT				4
+#define DA7213_ALC_ATTEN_GAIN_MAX_MAX				0xF
+
+/* DA7213_ALC_ANA_GAIN_LIMITS = 0xA0 */
+#define DA7213_ALC_ANA_GAIN_MIN_SHIFT				0
+#define DA7213_ALC_ANA_GAIN_MAX_SHIFT				4
+#define DA7213_ALC_ANA_GAIN_MAX					0x7
+
+/* DA7213_ALC_ANTICLIP_CTRL = 0xA1 */
+#define DA7213_ALC_ANTICLIP_EN_SHIFT				7
+#define DA7213_ALC_ANTICLIP_EN_MAX				0x1
+
+/* DA7213_ALC_ANTICLIP_LEVEL = 0xA2 */
+#define DA7213_ALC_ANTICLIP_LEVEL_SHIFT				0
+#define DA7213_ALC_ANTICLIP_LEVEL_MAX				0x7F
+
+/* DA7213_ALC_CIC_OP_LVL_CTRL = 0xAD */
+#define DA7213_ALC_DATA_MIDDLE					(0x2 << 0)
+#define DA7213_ALC_DATA_TOP					(0x3 << 0)
+#define DA7213_ALC_CIC_OP_CHANNEL_LEFT				(0x0 << 7)
+#define DA7213_ALC_CIC_OP_CHANNEL_RIGHT				(0x1 << 7)
+
+/* DA7213_DAC_NG_SETUP_TIME = 0xAF */
+#define DA7213_DAC_NG_SETUP_TIME_SHIFT				0
+#define DA7213_DAC_NG_SETUP_TIME_MAX				4
+#define DA7213_DAC_NG_RAMPUP_RATE_SHIFT				2
+#define DA7213_DAC_NG_RAMPDN_RATE_SHIFT				3
+#define DA7213_DAC_NG_RAMP_RATE_MAX				2
+
+/* DA7213_DAC_NG_OFF/ON_THRESH = 0xB0/0xB1 */
+#define DA7213_DAC_NG_THRESHOLD_SHIFT				0
+#define DA7213_DAC_NG_THRESHOLD_MAX				0x7
+
+/* DA7213_DAC_NG_CTRL = 0xB2 */
+#define DA7213_DAC_NG_EN_SHIFT					7
+#define DA7213_DAC_NG_EN_MAX					0x1
+
+
+/*
+ * General defines
+ */
+
+/* Register inversion */
+#define DA7213_NO_INVERT		0
+#define DA7213_INVERT			1
+
+/* Byte related defines */
+#define DA7213_BYTE_SHIFT		8
+#define DA7213_BYTE_MASK		0xFF
+
+/* ALC related */
+#define DA7213_ALC_OFFSET_15_8		0x00FF00
+#define DA7213_ALC_OFFSET_19_16		0x0F0000
+#define DA7213_ALC_AVG_ITERATIONS	5
+
+/* PLL related */
+#define DA7213_PLL_FREQ_OUT_90316800		90316800
+#define DA7213_PLL_FREQ_OUT_98304000		98304000
+#define DA7213_PLL_FREQ_OUT_94310400		94310400
+#define DA7213_PLL_INDIV_5_TO_9_MHZ_VAL		2
+#define DA7213_PLL_INDIV_9_TO_18_MHZ_VAL	4
+#define DA7213_PLL_INDIV_18_TO_36_MHZ_VAL	8
+#define DA7213_PLL_INDIV_36_TO_54_MHZ_VAL	16
+#define DA7213_SRM_CHECK_RETRIES		8
+
+enum da7213_clk_src {
+	DA7213_CLKSRC_MCLK = 0,
+	DA7213_CLKSRC_MCLK_SQR,
+};
+
+enum da7213_sys_clk {
+	DA7213_SYSCLK_MCLK = 0,
+	DA7213_SYSCLK_PLL,
+	DA7213_SYSCLK_PLL_SRM,
+	DA7213_SYSCLK_PLL_32KHZ
+};
+
+/* Codec private data */
+struct da7213_priv {
+	struct regmap *regmap;
+	struct clk *mclk;
+	unsigned int mclk_rate;
+	int clk_src;
+	bool master;
+	bool alc_calib_auto;
+	bool alc_en;
+	struct da7213_platform_data *pdata;
+};
+
+#endif /* _DA7213_H */
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
new file mode 100644
index 0000000..ddc90ac
--- /dev/null
+++ b/sound/soc/codecs/da7218.c
@@ -0,0 +1,3326 @@
+/*
+ * da7218.c - DA7218 ALSA SoC Codec Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+
+#include <sound/da7218.h>
+#include "da7218.h"
+
+
+/*
+ * TLVs and Enums
+ */
+
+/* Input TLVs */
+static const DECLARE_TLV_DB_SCALE(da7218_mic_gain_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_mixin_gain_tlv, -450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_in_dig_gain_tlv, -8325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_ags_trigger_tlv, -9000, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_ags_att_max_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_alc_threshold_tlv, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_alc_gain_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_alc_ana_gain_tlv, 0, 600, 0);
+
+/* Input/Output TLVs */
+static const DECLARE_TLV_DB_SCALE(da7218_dmix_gain_tlv, -4200, 150, 0);
+
+/* Output TLVs */
+static const DECLARE_TLV_DB_SCALE(da7218_dgs_trigger_tlv, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_dgs_anticlip_tlv, -4200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_dgs_signal_tlv, -9000, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_out_eq_band_tlv, -1050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_out_dig_gain_tlv, -8325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_dac_ng_threshold_tlv, -10200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_mixout_gain_tlv, -100, 50, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_hp_gain_tlv, -5700, 150, 0);
+
+/* Input Enums */
+static const char * const da7218_alc_attack_rate_txt[] = {
+	"7.33/fs", "14.66/fs", "29.32/fs", "58.64/fs", "117.3/fs", "234.6/fs",
+	"469.1/fs", "938.2/fs", "1876/fs", "3753/fs", "7506/fs", "15012/fs",
+	"30024/fs",
+};
+
+static const struct soc_enum da7218_alc_attack_rate =
+	SOC_ENUM_SINGLE(DA7218_ALC_CTRL2, DA7218_ALC_ATTACK_SHIFT,
+			DA7218_ALC_ATTACK_MAX, da7218_alc_attack_rate_txt);
+
+static const char * const da7218_alc_release_rate_txt[] = {
+	"28.66/fs", "57.33/fs", "114.6/fs", "229.3/fs", "458.6/fs", "917.1/fs",
+	"1834/fs", "3668/fs", "7337/fs", "14674/fs", "29348/fs",
+};
+
+static const struct soc_enum da7218_alc_release_rate =
+	SOC_ENUM_SINGLE(DA7218_ALC_CTRL2, DA7218_ALC_RELEASE_SHIFT,
+			DA7218_ALC_RELEASE_MAX, da7218_alc_release_rate_txt);
+
+static const char * const da7218_alc_hold_time_txt[] = {
+	"62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs",
+	"7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs",
+	"253952/fs", "507904/fs", "1015808/fs", "2031616/fs"
+};
+
+static const struct soc_enum da7218_alc_hold_time =
+	SOC_ENUM_SINGLE(DA7218_ALC_CTRL3, DA7218_ALC_HOLD_SHIFT,
+			DA7218_ALC_HOLD_MAX, da7218_alc_hold_time_txt);
+
+static const char * const da7218_alc_anticlip_step_txt[] = {
+	"0.034dB/fs", "0.068dB/fs", "0.136dB/fs", "0.272dB/fs",
+};
+
+static const struct soc_enum da7218_alc_anticlip_step =
+	SOC_ENUM_SINGLE(DA7218_ALC_ANTICLIP_CTRL,
+			DA7218_ALC_ANTICLIP_STEP_SHIFT,
+			DA7218_ALC_ANTICLIP_STEP_MAX,
+			da7218_alc_anticlip_step_txt);
+
+static const char * const da7218_integ_rate_txt[] = {
+	"1/4", "1/16", "1/256", "1/65536"
+};
+
+static const struct soc_enum da7218_integ_attack_rate =
+	SOC_ENUM_SINGLE(DA7218_ENV_TRACK_CTRL, DA7218_INTEG_ATTACK_SHIFT,
+			DA7218_INTEG_MAX, da7218_integ_rate_txt);
+
+static const struct soc_enum da7218_integ_release_rate =
+	SOC_ENUM_SINGLE(DA7218_ENV_TRACK_CTRL, DA7218_INTEG_RELEASE_SHIFT,
+			DA7218_INTEG_MAX, da7218_integ_rate_txt);
+
+/* Input/Output Enums */
+static const char * const da7218_gain_ramp_rate_txt[] = {
+	"Nominal Rate * 8", "Nominal Rate", "Nominal Rate / 8",
+	"Nominal Rate / 16",
+};
+
+static const struct soc_enum da7218_gain_ramp_rate =
+	SOC_ENUM_SINGLE(DA7218_GAIN_RAMP_CTRL, DA7218_GAIN_RAMP_RATE_SHIFT,
+			DA7218_GAIN_RAMP_RATE_MAX, da7218_gain_ramp_rate_txt);
+
+static const char * const da7218_hpf_mode_txt[] = {
+	"Disabled", "Audio", "Voice",
+};
+
+static const unsigned int da7218_hpf_mode_val[] = {
+	DA7218_HPF_DISABLED, DA7218_HPF_AUDIO_EN, DA7218_HPF_VOICE_EN,
+};
+
+static const struct soc_enum da7218_in1_hpf_mode =
+	SOC_VALUE_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL,
+			      DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK,
+			      DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt,
+			      da7218_hpf_mode_val);
+
+static const struct soc_enum da7218_in2_hpf_mode =
+	SOC_VALUE_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL,
+			      DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK,
+			      DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt,
+			      da7218_hpf_mode_val);
+
+static const struct soc_enum da7218_out1_hpf_mode =
+	SOC_VALUE_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL,
+			      DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK,
+			      DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt,
+			      da7218_hpf_mode_val);
+
+static const char * const da7218_audio_hpf_corner_txt[] = {
+	"2Hz", "4Hz", "8Hz", "16Hz",
+};
+
+static const struct soc_enum da7218_in1_audio_hpf_corner =
+	SOC_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL,
+			DA7218_IN_1_AUDIO_HPF_CORNER_SHIFT,
+			DA7218_AUDIO_HPF_CORNER_MAX,
+			da7218_audio_hpf_corner_txt);
+
+static const struct soc_enum da7218_in2_audio_hpf_corner =
+	SOC_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL,
+			DA7218_IN_2_AUDIO_HPF_CORNER_SHIFT,
+			DA7218_AUDIO_HPF_CORNER_MAX,
+			da7218_audio_hpf_corner_txt);
+
+static const struct soc_enum da7218_out1_audio_hpf_corner =
+	SOC_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL,
+			DA7218_OUT_1_AUDIO_HPF_CORNER_SHIFT,
+			DA7218_AUDIO_HPF_CORNER_MAX,
+			da7218_audio_hpf_corner_txt);
+
+static const char * const da7218_voice_hpf_corner_txt[] = {
+	"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz",
+};
+
+static const struct soc_enum da7218_in1_voice_hpf_corner =
+	SOC_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL,
+			DA7218_IN_1_VOICE_HPF_CORNER_SHIFT,
+			DA7218_VOICE_HPF_CORNER_MAX,
+			da7218_voice_hpf_corner_txt);
+
+static const struct soc_enum da7218_in2_voice_hpf_corner =
+	SOC_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL,
+			DA7218_IN_2_VOICE_HPF_CORNER_SHIFT,
+			DA7218_VOICE_HPF_CORNER_MAX,
+			da7218_voice_hpf_corner_txt);
+
+static const struct soc_enum da7218_out1_voice_hpf_corner =
+	SOC_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL,
+			DA7218_OUT_1_VOICE_HPF_CORNER_SHIFT,
+			DA7218_VOICE_HPF_CORNER_MAX,
+			da7218_voice_hpf_corner_txt);
+
+static const char * const da7218_tonegen_dtmf_key_txt[] = {
+	"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D",
+	"*", "#"
+};
+
+static const struct soc_enum da7218_tonegen_dtmf_key =
+	SOC_ENUM_SINGLE(DA7218_TONE_GEN_CFG1, DA7218_DTMF_REG_SHIFT,
+			DA7218_DTMF_REG_MAX, da7218_tonegen_dtmf_key_txt);
+
+static const char * const da7218_tonegen_swg_sel_txt[] = {
+	"Sum", "SWG1", "SWG2", "SWG1_1-Cos"
+};
+
+static const struct soc_enum da7218_tonegen_swg_sel =
+	SOC_ENUM_SINGLE(DA7218_TONE_GEN_CFG2, DA7218_SWG_SEL_SHIFT,
+			DA7218_SWG_SEL_MAX, da7218_tonegen_swg_sel_txt);
+
+/* Output Enums */
+static const char * const da7218_dgs_rise_coeff_txt[] = {
+	"1/1", "1/16", "1/64", "1/256", "1/1024", "1/4096", "1/16384",
+};
+
+static const struct soc_enum da7218_dgs_rise_coeff =
+	SOC_ENUM_SINGLE(DA7218_DGS_RISE_FALL, DA7218_DGS_RISE_COEFF_SHIFT,
+			DA7218_DGS_RISE_COEFF_MAX, da7218_dgs_rise_coeff_txt);
+
+static const char * const da7218_dgs_fall_coeff_txt[] = {
+	"1/4", "1/16", "1/64", "1/256", "1/1024", "1/4096", "1/16384", "1/65536",
+};
+
+static const struct soc_enum da7218_dgs_fall_coeff =
+	SOC_ENUM_SINGLE(DA7218_DGS_RISE_FALL, DA7218_DGS_FALL_COEFF_SHIFT,
+			DA7218_DGS_FALL_COEFF_MAX, da7218_dgs_fall_coeff_txt);
+
+static const char * const da7218_dac_ng_setup_time_txt[] = {
+	"256 Samples", "512 Samples", "1024 Samples", "2048 Samples"
+};
+
+static const struct soc_enum da7218_dac_ng_setup_time =
+	SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME,
+			DA7218_DAC_NG_SETUP_TIME_SHIFT,
+			DA7218_DAC_NG_SETUP_TIME_MAX,
+			da7218_dac_ng_setup_time_txt);
+
+static const char * const da7218_dac_ng_rampup_txt[] = {
+	"0.22ms/dB", "0.0138ms/dB"
+};
+
+static const struct soc_enum da7218_dac_ng_rampup_rate =
+	SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME,
+			DA7218_DAC_NG_RAMPUP_RATE_SHIFT,
+			DA7218_DAC_NG_RAMPUP_RATE_MAX,
+			da7218_dac_ng_rampup_txt);
+
+static const char * const da7218_dac_ng_rampdown_txt[] = {
+	"0.88ms/dB", "14.08ms/dB"
+};
+
+static const struct soc_enum da7218_dac_ng_rampdown_rate =
+	SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME,
+			DA7218_DAC_NG_RAMPDN_RATE_SHIFT,
+			DA7218_DAC_NG_RAMPDN_RATE_MAX,
+			da7218_dac_ng_rampdown_txt);
+
+static const char * const da7218_cp_mchange_txt[] = {
+	"Largest Volume", "DAC Volume", "Signal Magnitude"
+};
+
+static const unsigned int da7218_cp_mchange_val[] = {
+	DA7218_CP_MCHANGE_LARGEST_VOL, DA7218_CP_MCHANGE_DAC_VOL,
+	DA7218_CP_MCHANGE_SIG_MAG
+};
+
+static const struct soc_enum da7218_cp_mchange =
+	SOC_VALUE_ENUM_SINGLE(DA7218_CP_CTRL, DA7218_CP_MCHANGE_SHIFT,
+			      DA7218_CP_MCHANGE_REL_MASK, DA7218_CP_MCHANGE_MAX,
+			      da7218_cp_mchange_txt, da7218_cp_mchange_val);
+
+static const char * const da7218_cp_fcontrol_txt[] = {
+	"1MHz", "500KHz", "250KHz", "125KHz", "63KHz", "0KHz"
+};
+
+static const struct soc_enum da7218_cp_fcontrol =
+	SOC_ENUM_SINGLE(DA7218_CP_DELAY, DA7218_CP_FCONTROL_SHIFT,
+			DA7218_CP_FCONTROL_MAX, da7218_cp_fcontrol_txt);
+
+static const char * const da7218_cp_tau_delay_txt[] = {
+	"0ms", "2ms", "4ms", "16ms", "64ms", "128ms", "256ms", "512ms"
+};
+
+static const struct soc_enum da7218_cp_tau_delay =
+	SOC_ENUM_SINGLE(DA7218_CP_DELAY, DA7218_CP_TAU_DELAY_SHIFT,
+			DA7218_CP_TAU_DELAY_MAX, da7218_cp_tau_delay_txt);
+
+/*
+ * Control Functions
+ */
+
+/* ALC */
+static void da7218_alc_calib(struct snd_soc_component *component)
+{
+	u8 mic_1_ctrl, mic_2_ctrl;
+	u8 mixin_1_ctrl, mixin_2_ctrl;
+	u8 in_1l_filt_ctrl, in_1r_filt_ctrl, in_2l_filt_ctrl, in_2r_filt_ctrl;
+	u8 in_1_hpf_ctrl, in_2_hpf_ctrl;
+	u8 calib_ctrl;
+	int i = 0;
+	bool calibrated = false;
+
+	/* Save current state of MIC control registers */
+	mic_1_ctrl = snd_soc_component_read32(component, DA7218_MIC_1_CTRL);
+	mic_2_ctrl = snd_soc_component_read32(component, DA7218_MIC_2_CTRL);
+
+	/* Save current state of input mixer control registers */
+	mixin_1_ctrl = snd_soc_component_read32(component, DA7218_MIXIN_1_CTRL);
+	mixin_2_ctrl = snd_soc_component_read32(component, DA7218_MIXIN_2_CTRL);
+
+	/* Save current state of input filter control registers */
+	in_1l_filt_ctrl = snd_soc_component_read32(component, DA7218_IN_1L_FILTER_CTRL);
+	in_1r_filt_ctrl = snd_soc_component_read32(component, DA7218_IN_1R_FILTER_CTRL);
+	in_2l_filt_ctrl = snd_soc_component_read32(component, DA7218_IN_2L_FILTER_CTRL);
+	in_2r_filt_ctrl = snd_soc_component_read32(component, DA7218_IN_2R_FILTER_CTRL);
+
+	/* Save current state of input HPF control registers */
+	in_1_hpf_ctrl = snd_soc_component_read32(component, DA7218_IN_1_HPF_FILTER_CTRL);
+	in_2_hpf_ctrl = snd_soc_component_read32(component, DA7218_IN_2_HPF_FILTER_CTRL);
+
+	/* Enable then Mute MIC PGAs */
+	snd_soc_component_update_bits(component, DA7218_MIC_1_CTRL, DA7218_MIC_1_AMP_EN_MASK,
+			    DA7218_MIC_1_AMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_MIC_2_CTRL, DA7218_MIC_2_AMP_EN_MASK,
+			    DA7218_MIC_2_AMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_MIC_1_CTRL,
+			    DA7218_MIC_1_AMP_MUTE_EN_MASK,
+			    DA7218_MIC_1_AMP_MUTE_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_MIC_2_CTRL,
+			    DA7218_MIC_2_AMP_MUTE_EN_MASK,
+			    DA7218_MIC_2_AMP_MUTE_EN_MASK);
+
+	/* Enable input mixers unmuted */
+	snd_soc_component_update_bits(component, DA7218_MIXIN_1_CTRL,
+			    DA7218_MIXIN_1_AMP_EN_MASK |
+			    DA7218_MIXIN_1_AMP_MUTE_EN_MASK,
+			    DA7218_MIXIN_1_AMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_MIXIN_2_CTRL,
+			    DA7218_MIXIN_2_AMP_EN_MASK |
+			    DA7218_MIXIN_2_AMP_MUTE_EN_MASK,
+			    DA7218_MIXIN_2_AMP_EN_MASK);
+
+	/* Enable input filters unmuted */
+	snd_soc_component_update_bits(component, DA7218_IN_1L_FILTER_CTRL,
+			    DA7218_IN_1L_FILTER_EN_MASK |
+			    DA7218_IN_1L_MUTE_EN_MASK,
+			    DA7218_IN_1L_FILTER_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_IN_1R_FILTER_CTRL,
+			    DA7218_IN_1R_FILTER_EN_MASK |
+			    DA7218_IN_1R_MUTE_EN_MASK,
+			    DA7218_IN_1R_FILTER_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_IN_2L_FILTER_CTRL,
+			    DA7218_IN_2L_FILTER_EN_MASK |
+			    DA7218_IN_2L_MUTE_EN_MASK,
+			    DA7218_IN_2L_FILTER_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_IN_2R_FILTER_CTRL,
+			    DA7218_IN_2R_FILTER_EN_MASK |
+			    DA7218_IN_2R_MUTE_EN_MASK,
+			    DA7218_IN_2R_FILTER_EN_MASK);
+
+	/*
+	 * Make sure input HPFs voice mode is disabled, otherwise for sampling
+	 * rates above 32KHz the ADC signals will be stopped and will cause
+	 * calibration to lock up.
+	 */
+	snd_soc_component_update_bits(component, DA7218_IN_1_HPF_FILTER_CTRL,
+			    DA7218_IN_1_VOICE_EN_MASK, 0);
+	snd_soc_component_update_bits(component, DA7218_IN_2_HPF_FILTER_CTRL,
+			    DA7218_IN_2_VOICE_EN_MASK, 0);
+
+	/* Perform auto calibration */
+	snd_soc_component_update_bits(component, DA7218_CALIB_CTRL, DA7218_CALIB_AUTO_EN_MASK,
+			    DA7218_CALIB_AUTO_EN_MASK);
+	do {
+		calib_ctrl = snd_soc_component_read32(component, DA7218_CALIB_CTRL);
+		if (calib_ctrl & DA7218_CALIB_AUTO_EN_MASK) {
+			++i;
+			usleep_range(DA7218_ALC_CALIB_DELAY_MIN,
+				     DA7218_ALC_CALIB_DELAY_MAX);
+		} else {
+			calibrated = true;
+		}
+
+	} while ((i < DA7218_ALC_CALIB_MAX_TRIES) && (!calibrated));
+
+	/* If auto calibration fails, disable DC offset, hybrid ALC */
+	if ((!calibrated) || (calib_ctrl & DA7218_CALIB_OVERFLOW_MASK)) {
+		dev_warn(component->dev,
+			 "ALC auto calibration failed - %s\n",
+			 (calibrated) ? "overflow" : "timeout");
+		snd_soc_component_update_bits(component, DA7218_CALIB_CTRL,
+				    DA7218_CALIB_OFFSET_EN_MASK, 0);
+		snd_soc_component_update_bits(component, DA7218_ALC_CTRL1,
+				    DA7218_ALC_SYNC_MODE_MASK, 0);
+
+	} else {
+		/* Enable DC offset cancellation */
+		snd_soc_component_update_bits(component, DA7218_CALIB_CTRL,
+				    DA7218_CALIB_OFFSET_EN_MASK,
+				    DA7218_CALIB_OFFSET_EN_MASK);
+
+		/* Enable ALC hybrid mode */
+		snd_soc_component_update_bits(component, DA7218_ALC_CTRL1,
+				    DA7218_ALC_SYNC_MODE_MASK,
+				    DA7218_ALC_SYNC_MODE_CH1 |
+				    DA7218_ALC_SYNC_MODE_CH2);
+	}
+
+	/* Restore input HPF control registers to original states */
+	snd_soc_component_write(component, DA7218_IN_1_HPF_FILTER_CTRL, in_1_hpf_ctrl);
+	snd_soc_component_write(component, DA7218_IN_2_HPF_FILTER_CTRL, in_2_hpf_ctrl);
+
+	/* Restore input filter control registers to original states */
+	snd_soc_component_write(component, DA7218_IN_1L_FILTER_CTRL, in_1l_filt_ctrl);
+	snd_soc_component_write(component, DA7218_IN_1R_FILTER_CTRL, in_1r_filt_ctrl);
+	snd_soc_component_write(component, DA7218_IN_2L_FILTER_CTRL, in_2l_filt_ctrl);
+	snd_soc_component_write(component, DA7218_IN_2R_FILTER_CTRL, in_2r_filt_ctrl);
+
+	/* Restore input mixer control registers to original state */
+	snd_soc_component_write(component, DA7218_MIXIN_1_CTRL, mixin_1_ctrl);
+	snd_soc_component_write(component, DA7218_MIXIN_2_CTRL, mixin_2_ctrl);
+
+	/* Restore MIC control registers to original states */
+	snd_soc_component_write(component, DA7218_MIC_1_CTRL, mic_1_ctrl);
+	snd_soc_component_write(component, DA7218_MIC_2_CTRL, mic_2_ctrl);
+}
+
+static int da7218_mixin_gain_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+	/*
+	 * If ALC in operation and value of control has been updated,
+	 * make sure calibrated offsets are updated.
+	 */
+	if ((ret == 1) && (da7218->alc_en))
+		da7218_alc_calib(component);
+
+	return ret;
+}
+
+static int da7218_alc_sw_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *) kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	unsigned int lvalue = ucontrol->value.integer.value[0];
+	unsigned int rvalue = ucontrol->value.integer.value[1];
+	unsigned int lshift = mc->shift;
+	unsigned int rshift = mc->rshift;
+	unsigned int mask = (mc->max << lshift) | (mc->max << rshift);
+
+	/* Force ALC offset calibration if enabling ALC */
+	if ((lvalue || rvalue) && (!da7218->alc_en))
+		da7218_alc_calib(component);
+
+	/* Update bits to detail which channels are enabled/disabled */
+	da7218->alc_en &= ~mask;
+	da7218->alc_en |= (lvalue << lshift) | (rvalue << rshift);
+
+	return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+/* ToneGen */
+static int da7218_tonegen_freq_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	struct soc_mixer_control *mixer_ctrl =
+		(struct soc_mixer_control *) kcontrol->private_value;
+	unsigned int reg = mixer_ctrl->reg;
+	u16 val;
+	int ret;
+
+	/*
+	 * Frequency value spans two 8-bit registers, lower then upper byte.
+	 * Therefore we need to convert to host endianness here.
+	 */
+	ret = regmap_raw_read(da7218->regmap, reg, &val, 2);
+	if (ret)
+		return ret;
+
+	ucontrol->value.integer.value[0] = le16_to_cpu(val);
+
+	return 0;
+}
+
+static int da7218_tonegen_freq_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	struct soc_mixer_control *mixer_ctrl =
+		(struct soc_mixer_control *) kcontrol->private_value;
+	unsigned int reg = mixer_ctrl->reg;
+	u16 val;
+
+	/*
+	 * Frequency value spans two 8-bit registers, lower then upper byte.
+	 * Therefore we need to convert to little endian here to align with
+	 * HW registers.
+	 */
+	val = cpu_to_le16(ucontrol->value.integer.value[0]);
+
+	return regmap_raw_write(da7218->regmap, reg, &val, 2);
+}
+
+static int da7218_mic_lvl_det_sw_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	struct soc_mixer_control *mixer_ctrl =
+		(struct soc_mixer_control *) kcontrol->private_value;
+	unsigned int lvalue = ucontrol->value.integer.value[0];
+	unsigned int rvalue = ucontrol->value.integer.value[1];
+	unsigned int lshift = mixer_ctrl->shift;
+	unsigned int rshift = mixer_ctrl->rshift;
+	unsigned int mask = (mixer_ctrl->max << lshift) |
+			    (mixer_ctrl->max << rshift);
+	da7218->mic_lvl_det_en &= ~mask;
+	da7218->mic_lvl_det_en |= (lvalue << lshift) | (rvalue << rshift);
+
+	/*
+	 * Here we only enable the feature on paths which are already
+	 * powered. If a channel is enabled here for level detect, but that path
+	 * isn't powered, then the channel will actually be enabled when we do
+	 * power the path (IN_FILTER widget events). This handling avoids
+	 * unwanted level detect events.
+	 */
+	return snd_soc_component_write(component, mixer_ctrl->reg,
+			     (da7218->in_filt_en & da7218->mic_lvl_det_en));
+}
+
+static int da7218_mic_lvl_det_sw_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	struct soc_mixer_control *mixer_ctrl =
+		(struct soc_mixer_control *) kcontrol->private_value;
+	unsigned int lshift = mixer_ctrl->shift;
+	unsigned int rshift = mixer_ctrl->rshift;
+	unsigned int lmask = (mixer_ctrl->max << lshift);
+	unsigned int rmask = (mixer_ctrl->max << rshift);
+
+	ucontrol->value.integer.value[0] =
+		(da7218->mic_lvl_det_en & lmask) >> lshift;
+	ucontrol->value.integer.value[1] =
+		(da7218->mic_lvl_det_en & rmask) >> rshift;
+
+	return 0;
+}
+
+static int da7218_biquad_coeff_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	struct soc_bytes_ext *bytes_ext =
+		(struct soc_bytes_ext *) kcontrol->private_value;
+
+	/* Determine which BiQuads we're setting based on size of config data */
+	switch (bytes_ext->max) {
+	case DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE:
+		memcpy(ucontrol->value.bytes.data, da7218->biq_5stage_coeff,
+		       bytes_ext->max);
+		break;
+	case DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE:
+		memcpy(ucontrol->value.bytes.data, da7218->stbiq_3stage_coeff,
+		       bytes_ext->max);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int da7218_biquad_coeff_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	struct soc_bytes_ext *bytes_ext =
+		(struct soc_bytes_ext *) kcontrol->private_value;
+	u8 reg, out_filt1l;
+	u8 cfg[DA7218_BIQ_CFG_SIZE];
+	int i;
+
+	/*
+	 * Determine which BiQuads we're setting based on size of config data,
+	 * and stored the data for use by get function.
+	 */
+	switch (bytes_ext->max) {
+	case DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE:
+		reg = DA7218_OUT_1_BIQ_5STAGE_DATA;
+		memcpy(da7218->biq_5stage_coeff, ucontrol->value.bytes.data,
+		       bytes_ext->max);
+		break;
+	case DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE:
+		reg = DA7218_SIDETONE_BIQ_3STAGE_DATA;
+		memcpy(da7218->stbiq_3stage_coeff, ucontrol->value.bytes.data,
+		       bytes_ext->max);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Make sure at least out filter1 enabled to allow programming */
+	out_filt1l = snd_soc_component_read32(component, DA7218_OUT_1L_FILTER_CTRL);
+	snd_soc_component_write(component, DA7218_OUT_1L_FILTER_CTRL,
+		      out_filt1l | DA7218_OUT_1L_FILTER_EN_MASK);
+
+	for (i = 0; i < bytes_ext->max; ++i) {
+		cfg[DA7218_BIQ_CFG_DATA] = ucontrol->value.bytes.data[i];
+		cfg[DA7218_BIQ_CFG_ADDR] = i;
+		regmap_raw_write(da7218->regmap, reg, cfg, DA7218_BIQ_CFG_SIZE);
+	}
+
+	/* Restore filter to previous setting */
+	snd_soc_component_write(component, DA7218_OUT_1L_FILTER_CTRL, out_filt1l);
+
+	return 0;
+}
+
+
+/*
+ * KControls
+ */
+
+static const struct snd_kcontrol_new da7218_snd_controls[] = {
+	/* Mics */
+	SOC_SINGLE_TLV("Mic1 Volume", DA7218_MIC_1_GAIN,
+		       DA7218_MIC_1_AMP_GAIN_SHIFT, DA7218_MIC_AMP_GAIN_MAX,
+		       DA7218_NO_INVERT, da7218_mic_gain_tlv),
+	SOC_SINGLE("Mic1 Switch", DA7218_MIC_1_CTRL,
+		   DA7218_MIC_1_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+	SOC_SINGLE_TLV("Mic2 Volume", DA7218_MIC_2_GAIN,
+		       DA7218_MIC_2_AMP_GAIN_SHIFT, DA7218_MIC_AMP_GAIN_MAX,
+		       DA7218_NO_INVERT, da7218_mic_gain_tlv),
+	SOC_SINGLE("Mic2 Switch", DA7218_MIC_2_CTRL,
+		   DA7218_MIC_2_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+
+	/* Mixer Input */
+	SOC_SINGLE_EXT_TLV("Mixin1 Volume", DA7218_MIXIN_1_GAIN,
+			   DA7218_MIXIN_1_AMP_GAIN_SHIFT,
+			   DA7218_MIXIN_AMP_GAIN_MAX, DA7218_NO_INVERT,
+			   snd_soc_get_volsw, da7218_mixin_gain_put,
+			   da7218_mixin_gain_tlv),
+	SOC_SINGLE("Mixin1 Switch", DA7218_MIXIN_1_CTRL,
+		   DA7218_MIXIN_1_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+	SOC_SINGLE("Mixin1 Gain Ramp Switch", DA7218_MIXIN_1_CTRL,
+		   DA7218_MIXIN_1_AMP_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("Mixin1 ZC Gain Switch", DA7218_MIXIN_1_CTRL,
+		   DA7218_MIXIN_1_AMP_ZC_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE_EXT_TLV("Mixin2 Volume", DA7218_MIXIN_2_GAIN,
+			   DA7218_MIXIN_2_AMP_GAIN_SHIFT,
+			   DA7218_MIXIN_AMP_GAIN_MAX, DA7218_NO_INVERT,
+			   snd_soc_get_volsw, da7218_mixin_gain_put,
+			   da7218_mixin_gain_tlv),
+	SOC_SINGLE("Mixin2 Switch", DA7218_MIXIN_2_CTRL,
+		   DA7218_MIXIN_2_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+	SOC_SINGLE("Mixin2 Gain Ramp Switch", DA7218_MIXIN_2_CTRL,
+		   DA7218_MIXIN_2_AMP_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("Mixin2 ZC Gain Switch", DA7218_MIXIN_2_CTRL,
+		   DA7218_MIXIN_2_AMP_ZC_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+
+	/* ADCs */
+	SOC_SINGLE("ADC1 AAF Switch", DA7218_ADC_1_CTRL,
+		   DA7218_ADC_1_AAF_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("ADC2 AAF Switch", DA7218_ADC_2_CTRL,
+		   DA7218_ADC_2_AAF_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("ADC LP Mode Switch", DA7218_ADC_MODE,
+		   DA7218_ADC_LP_MODE_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+
+	/* Input Filters */
+	SOC_SINGLE_TLV("In Filter1L Volume", DA7218_IN_1L_GAIN,
+		       DA7218_IN_1L_DIGITAL_GAIN_SHIFT,
+		       DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_in_dig_gain_tlv),
+	SOC_SINGLE("In Filter1L Switch", DA7218_IN_1L_FILTER_CTRL,
+		   DA7218_IN_1L_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+	SOC_SINGLE("In Filter1L Gain Ramp Switch", DA7218_IN_1L_FILTER_CTRL,
+		   DA7218_IN_1L_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE_TLV("In Filter1R Volume", DA7218_IN_1R_GAIN,
+		       DA7218_IN_1R_DIGITAL_GAIN_SHIFT,
+		       DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_in_dig_gain_tlv),
+	SOC_SINGLE("In Filter1R Switch", DA7218_IN_1R_FILTER_CTRL,
+		   DA7218_IN_1R_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+	SOC_SINGLE("In Filter1R Gain Ramp Switch",
+		   DA7218_IN_1R_FILTER_CTRL, DA7218_IN_1R_RAMP_EN_SHIFT,
+		   DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+	SOC_SINGLE_TLV("In Filter2L Volume", DA7218_IN_2L_GAIN,
+		       DA7218_IN_2L_DIGITAL_GAIN_SHIFT,
+		       DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_in_dig_gain_tlv),
+	SOC_SINGLE("In Filter2L Switch", DA7218_IN_2L_FILTER_CTRL,
+		   DA7218_IN_2L_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+	SOC_SINGLE("In Filter2L Gain Ramp Switch", DA7218_IN_2L_FILTER_CTRL,
+		   DA7218_IN_2L_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE_TLV("In Filter2R Volume", DA7218_IN_2R_GAIN,
+		       DA7218_IN_2R_DIGITAL_GAIN_SHIFT,
+		       DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_in_dig_gain_tlv),
+	SOC_SINGLE("In Filter2R Switch", DA7218_IN_2R_FILTER_CTRL,
+		   DA7218_IN_2R_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+	SOC_SINGLE("In Filter2R Gain Ramp Switch",
+		   DA7218_IN_2R_FILTER_CTRL, DA7218_IN_2R_RAMP_EN_SHIFT,
+		   DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+
+	/* AGS */
+	SOC_SINGLE_TLV("AGS Trigger", DA7218_AGS_TRIGGER,
+		       DA7218_AGS_TRIGGER_SHIFT, DA7218_AGS_TRIGGER_MAX,
+		       DA7218_INVERT, da7218_ags_trigger_tlv),
+	SOC_SINGLE_TLV("AGS Max Attenuation", DA7218_AGS_ATT_MAX,
+		       DA7218_AGS_ATT_MAX_SHIFT, DA7218_AGS_ATT_MAX_MAX,
+		       DA7218_NO_INVERT, da7218_ags_att_max_tlv),
+	SOC_SINGLE("AGS Anticlip Switch", DA7218_AGS_ANTICLIP_CTRL,
+		   DA7218_AGS_ANTICLIP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("AGS Channel1 Switch", DA7218_AGS_ENABLE,
+		   DA7218_AGS_ENABLE_CHAN1_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("AGS Channel2 Switch", DA7218_AGS_ENABLE,
+		   DA7218_AGS_ENABLE_CHAN2_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+
+	/* ALC */
+	SOC_ENUM("ALC Attack Rate", da7218_alc_attack_rate),
+	SOC_ENUM("ALC Release Rate", da7218_alc_release_rate),
+	SOC_ENUM("ALC Hold Time", da7218_alc_hold_time),
+	SOC_SINGLE_TLV("ALC Noise Threshold", DA7218_ALC_NOISE,
+		       DA7218_ALC_NOISE_SHIFT, DA7218_ALC_THRESHOLD_MAX,
+		       DA7218_INVERT, da7218_alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Min Threshold", DA7218_ALC_TARGET_MIN,
+		       DA7218_ALC_THRESHOLD_MIN_SHIFT, DA7218_ALC_THRESHOLD_MAX,
+		       DA7218_INVERT, da7218_alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Max Threshold", DA7218_ALC_TARGET_MAX,
+		       DA7218_ALC_THRESHOLD_MAX_SHIFT, DA7218_ALC_THRESHOLD_MAX,
+		       DA7218_INVERT, da7218_alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Max Attenuation", DA7218_ALC_GAIN_LIMITS,
+		       DA7218_ALC_ATTEN_MAX_SHIFT, DA7218_ALC_ATTEN_GAIN_MAX,
+		       DA7218_NO_INVERT, da7218_alc_gain_tlv),
+	SOC_SINGLE_TLV("ALC Max Gain", DA7218_ALC_GAIN_LIMITS,
+		       DA7218_ALC_GAIN_MAX_SHIFT, DA7218_ALC_ATTEN_GAIN_MAX,
+		       DA7218_NO_INVERT, da7218_alc_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("ALC Min Analog Gain", DA7218_ALC_ANA_GAIN_LIMITS,
+			     DA7218_ALC_ANA_GAIN_MIN_SHIFT,
+			     DA7218_ALC_ANA_GAIN_MIN, DA7218_ALC_ANA_GAIN_MAX,
+			     DA7218_NO_INVERT, da7218_alc_ana_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("ALC Max Analog Gain", DA7218_ALC_ANA_GAIN_LIMITS,
+			     DA7218_ALC_ANA_GAIN_MAX_SHIFT,
+			     DA7218_ALC_ANA_GAIN_MIN, DA7218_ALC_ANA_GAIN_MAX,
+			     DA7218_NO_INVERT, da7218_alc_ana_gain_tlv),
+	SOC_ENUM("ALC Anticlip Step", da7218_alc_anticlip_step),
+	SOC_SINGLE("ALC Anticlip Switch", DA7218_ALC_ANTICLIP_CTRL,
+		   DA7218_ALC_ANTICLIP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_DOUBLE_EXT("ALC Channel1 Switch", DA7218_ALC_CTRL1,
+		       DA7218_ALC_CHAN1_L_EN_SHIFT, DA7218_ALC_CHAN1_R_EN_SHIFT,
+		       DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT,
+		       snd_soc_get_volsw, da7218_alc_sw_put),
+	SOC_DOUBLE_EXT("ALC Channel2 Switch", DA7218_ALC_CTRL1,
+		       DA7218_ALC_CHAN2_L_EN_SHIFT, DA7218_ALC_CHAN2_R_EN_SHIFT,
+		       DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT,
+		       snd_soc_get_volsw, da7218_alc_sw_put),
+
+	/* Envelope Tracking */
+	SOC_ENUM("Envelope Tracking Attack Rate", da7218_integ_attack_rate),
+	SOC_ENUM("Envelope Tracking Release Rate", da7218_integ_release_rate),
+
+	/* Input High-Pass Filters */
+	SOC_ENUM("In Filter1 HPF Mode", da7218_in1_hpf_mode),
+	SOC_ENUM("In Filter1 HPF Corner Audio", da7218_in1_audio_hpf_corner),
+	SOC_ENUM("In Filter1 HPF Corner Voice", da7218_in1_voice_hpf_corner),
+	SOC_ENUM("In Filter2 HPF Mode", da7218_in2_hpf_mode),
+	SOC_ENUM("In Filter2 HPF Corner Audio", da7218_in2_audio_hpf_corner),
+	SOC_ENUM("In Filter2 HPF Corner Voice", da7218_in2_voice_hpf_corner),
+
+	/* Mic Level Detect */
+	SOC_DOUBLE_EXT("Mic Level Detect Channel1 Switch", DA7218_LVL_DET_CTRL,
+		       DA7218_LVL_DET_EN_CHAN1L_SHIFT,
+		       DA7218_LVL_DET_EN_CHAN1R_SHIFT, DA7218_SWITCH_EN_MAX,
+		       DA7218_NO_INVERT, da7218_mic_lvl_det_sw_get,
+		       da7218_mic_lvl_det_sw_put),
+	SOC_DOUBLE_EXT("Mic Level Detect Channel2 Switch", DA7218_LVL_DET_CTRL,
+		       DA7218_LVL_DET_EN_CHAN2L_SHIFT,
+		       DA7218_LVL_DET_EN_CHAN2R_SHIFT, DA7218_SWITCH_EN_MAX,
+		       DA7218_NO_INVERT, da7218_mic_lvl_det_sw_get,
+		       da7218_mic_lvl_det_sw_put),
+	SOC_SINGLE("Mic Level Detect Level", DA7218_LVL_DET_LEVEL,
+		   DA7218_LVL_DET_LEVEL_SHIFT, DA7218_LVL_DET_LEVEL_MAX,
+		   DA7218_NO_INVERT),
+
+	/* Digital Mixer (Input) */
+	SOC_SINGLE_TLV("DMix In Filter1L Out1 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN,
+		       DA7218_OUTDAI_1L_INFILT_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1L Out1 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN,
+		       DA7218_OUTDAI_1R_INFILT_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1L Out2 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN,
+		       DA7218_OUTDAI_2L_INFILT_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1L Out2 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN,
+		       DA7218_OUTDAI_2R_INFILT_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In Filter1R Out1 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN,
+		       DA7218_OUTDAI_1L_INFILT_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1R Out1 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN,
+		       DA7218_OUTDAI_1R_INFILT_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1R Out2 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN,
+		       DA7218_OUTDAI_2L_INFILT_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1R Out2 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN,
+		       DA7218_OUTDAI_2R_INFILT_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In Filter2L Out1 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN,
+		       DA7218_OUTDAI_1L_INFILT_2L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2L Out1 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN,
+		       DA7218_OUTDAI_1R_INFILT_2L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2L Out2 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN,
+		       DA7218_OUTDAI_2L_INFILT_2L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2L Out2 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN,
+		       DA7218_OUTDAI_2R_INFILT_2L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In Filter2R Out1 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN,
+		       DA7218_OUTDAI_1L_INFILT_2R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2R Out1 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN,
+		       DA7218_OUTDAI_1R_INFILT_2R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2R Out2 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN,
+		       DA7218_OUTDAI_2L_INFILT_2R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2R Out2 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN,
+		       DA7218_OUTDAI_2R_INFILT_2R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix ToneGen Out1 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN,
+		       DA7218_OUTDAI_1L_TONEGEN_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix ToneGen Out1 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN,
+		       DA7218_OUTDAI_1R_TONEGEN_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix ToneGen Out2 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN,
+		       DA7218_OUTDAI_2L_TONEGEN_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix ToneGen Out2 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN,
+		       DA7218_OUTDAI_2R_TONEGEN_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In DAIL Out1 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN,
+		       DA7218_OUTDAI_1L_INDAI_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIL Out1 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN,
+		       DA7218_OUTDAI_1R_INDAI_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIL Out2 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN,
+		       DA7218_OUTDAI_2L_INDAI_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIL Out2 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN,
+		       DA7218_OUTDAI_2R_INDAI_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In DAIR Out1 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN,
+		       DA7218_OUTDAI_1L_INDAI_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIR Out1 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN,
+		       DA7218_OUTDAI_1R_INDAI_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIR Out2 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN,
+		       DA7218_OUTDAI_2L_INDAI_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIR Out2 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN,
+		       DA7218_OUTDAI_2R_INDAI_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	/* Digital Mixer (Output) */
+	SOC_SINGLE_TLV("DMix In Filter1L Out FilterL Volume",
+		       DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN,
+		       DA7218_OUTFILT_1L_INFILT_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1L Out FilterR Volume",
+		       DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN,
+		       DA7218_OUTFILT_1R_INFILT_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In Filter1R Out FilterL Volume",
+		       DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN,
+		       DA7218_OUTFILT_1L_INFILT_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1R Out FilterR Volume",
+		       DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN,
+		       DA7218_OUTFILT_1R_INFILT_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In Filter2L Out FilterL Volume",
+		       DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN,
+		       DA7218_OUTFILT_1L_INFILT_2L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2L Out FilterR Volume",
+		       DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN,
+		       DA7218_OUTFILT_1R_INFILT_2L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In Filter2R Out FilterL Volume",
+		       DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN,
+		       DA7218_OUTFILT_1L_INFILT_2R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2R Out FilterR Volume",
+		       DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN,
+		       DA7218_OUTFILT_1R_INFILT_2R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix ToneGen Out FilterL Volume",
+		       DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN,
+		       DA7218_OUTFILT_1L_TONEGEN_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix ToneGen Out FilterR Volume",
+		       DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN,
+		       DA7218_OUTFILT_1R_TONEGEN_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In DAIL Out FilterL Volume",
+		       DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN,
+		       DA7218_OUTFILT_1L_INDAI_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIL Out FilterR Volume",
+		       DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN,
+		       DA7218_OUTFILT_1R_INDAI_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In DAIR Out FilterL Volume",
+		       DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN,
+		       DA7218_OUTFILT_1L_INDAI_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIR Out FilterR Volume",
+		       DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN,
+		       DA7218_OUTFILT_1R_INDAI_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	/* Sidetone Filter */
+	SND_SOC_BYTES_EXT("Sidetone BiQuad Coefficients",
+			  DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE,
+			  da7218_biquad_coeff_get, da7218_biquad_coeff_put),
+	SOC_SINGLE_TLV("Sidetone Volume", DA7218_SIDETONE_GAIN,
+		       DA7218_SIDETONE_GAIN_SHIFT, DA7218_DMIX_GAIN_MAX,
+		       DA7218_NO_INVERT, da7218_dmix_gain_tlv),
+	SOC_SINGLE("Sidetone Switch", DA7218_SIDETONE_CTRL,
+		   DA7218_SIDETONE_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+
+	/* Tone Generator */
+	SOC_ENUM("ToneGen DTMF Key", da7218_tonegen_dtmf_key),
+	SOC_SINGLE("ToneGen DTMF Switch", DA7218_TONE_GEN_CFG1,
+		   DA7218_DTMF_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_ENUM("ToneGen Sinewave Gen Type", da7218_tonegen_swg_sel),
+	SOC_SINGLE_EXT("ToneGen Sinewave1 Freq", DA7218_TONE_GEN_FREQ1_L,
+		       DA7218_FREQ1_L_SHIFT, DA7218_FREQ_MAX, DA7218_NO_INVERT,
+		       da7218_tonegen_freq_get, da7218_tonegen_freq_put),
+	SOC_SINGLE_EXT("ToneGen Sinewave2 Freq", DA7218_TONE_GEN_FREQ2_L,
+		       DA7218_FREQ2_L_SHIFT, DA7218_FREQ_MAX, DA7218_NO_INVERT,
+		       da7218_tonegen_freq_get, da7218_tonegen_freq_put),
+	SOC_SINGLE("ToneGen On Time", DA7218_TONE_GEN_ON_PER,
+		   DA7218_BEEP_ON_PER_SHIFT, DA7218_BEEP_ON_OFF_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("ToneGen Off Time", DA7218_TONE_GEN_OFF_PER,
+		   DA7218_BEEP_OFF_PER_SHIFT, DA7218_BEEP_ON_OFF_MAX,
+		   DA7218_NO_INVERT),
+
+	/* Gain ramping */
+	SOC_ENUM("Gain Ramp Rate", da7218_gain_ramp_rate),
+
+	/* DGS */
+	SOC_SINGLE_TLV("DGS Trigger", DA7218_DGS_TRIGGER,
+		       DA7218_DGS_TRIGGER_LVL_SHIFT, DA7218_DGS_TRIGGER_MAX,
+		       DA7218_INVERT, da7218_dgs_trigger_tlv),
+	SOC_ENUM("DGS Rise Coefficient", da7218_dgs_rise_coeff),
+	SOC_ENUM("DGS Fall Coefficient", da7218_dgs_fall_coeff),
+	SOC_SINGLE("DGS Sync Delay", DA7218_DGS_SYNC_DELAY,
+		   DA7218_DGS_SYNC_DELAY_SHIFT, DA7218_DGS_SYNC_DELAY_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("DGS Fast SR Sync Delay", DA7218_DGS_SYNC_DELAY2,
+		   DA7218_DGS_SYNC_DELAY2_SHIFT, DA7218_DGS_SYNC_DELAY_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("DGS Voice Filter Sync Delay", DA7218_DGS_SYNC_DELAY3,
+		   DA7218_DGS_SYNC_DELAY3_SHIFT, DA7218_DGS_SYNC_DELAY3_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE_TLV("DGS Anticlip Level", DA7218_DGS_LEVELS,
+		       DA7218_DGS_ANTICLIP_LVL_SHIFT,
+		       DA7218_DGS_ANTICLIP_LVL_MAX, DA7218_INVERT,
+		       da7218_dgs_anticlip_tlv),
+	SOC_SINGLE_TLV("DGS Signal Level", DA7218_DGS_LEVELS,
+		       DA7218_DGS_SIGNAL_LVL_SHIFT, DA7218_DGS_SIGNAL_LVL_MAX,
+		       DA7218_INVERT, da7218_dgs_signal_tlv),
+	SOC_SINGLE("DGS Gain Subrange Switch", DA7218_DGS_GAIN_CTRL,
+		   DA7218_DGS_SUBR_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("DGS Gain Ramp Switch", DA7218_DGS_GAIN_CTRL,
+		   DA7218_DGS_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("DGS Gain Steps", DA7218_DGS_GAIN_CTRL,
+		   DA7218_DGS_STEPS_SHIFT, DA7218_DGS_STEPS_MAX,
+		   DA7218_NO_INVERT),
+	SOC_DOUBLE("DGS Switch", DA7218_DGS_ENABLE, DA7218_DGS_ENABLE_L_SHIFT,
+		   DA7218_DGS_ENABLE_R_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+
+	/* Output High-Pass Filter */
+	SOC_ENUM("Out Filter HPF Mode", da7218_out1_hpf_mode),
+	SOC_ENUM("Out Filter HPF Corner Audio", da7218_out1_audio_hpf_corner),
+	SOC_ENUM("Out Filter HPF Corner Voice", da7218_out1_voice_hpf_corner),
+
+	/* 5-Band Equaliser */
+	SOC_SINGLE_TLV("Out EQ Band1 Volume", DA7218_OUT_1_EQ_12_FILTER_CTRL,
+		       DA7218_OUT_1_EQ_BAND1_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+		       DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+	SOC_SINGLE_TLV("Out EQ Band2 Volume", DA7218_OUT_1_EQ_12_FILTER_CTRL,
+		       DA7218_OUT_1_EQ_BAND2_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+		       DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+	SOC_SINGLE_TLV("Out EQ Band3 Volume", DA7218_OUT_1_EQ_34_FILTER_CTRL,
+		       DA7218_OUT_1_EQ_BAND3_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+		       DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+	SOC_SINGLE_TLV("Out EQ Band4 Volume", DA7218_OUT_1_EQ_34_FILTER_CTRL,
+		       DA7218_OUT_1_EQ_BAND4_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+		       DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+	SOC_SINGLE_TLV("Out EQ Band5 Volume", DA7218_OUT_1_EQ_5_FILTER_CTRL,
+		       DA7218_OUT_1_EQ_BAND5_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+		       DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+	SOC_SINGLE("Out EQ Switch", DA7218_OUT_1_EQ_5_FILTER_CTRL,
+		   DA7218_OUT_1_EQ_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+
+	/* BiQuad Filters */
+	SND_SOC_BYTES_EXT("BiQuad Coefficients",
+			  DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE,
+			  da7218_biquad_coeff_get, da7218_biquad_coeff_put),
+	SOC_SINGLE("BiQuad Filter Switch", DA7218_OUT_1_BIQ_5STAGE_CTRL,
+		   DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+
+	/* Output Filters */
+	SOC_DOUBLE_R_RANGE_TLV("Out Filter Volume", DA7218_OUT_1L_GAIN,
+			       DA7218_OUT_1R_GAIN,
+			       DA7218_OUT_1L_DIGITAL_GAIN_SHIFT,
+			       DA7218_OUT_DIGITAL_GAIN_MIN,
+			       DA7218_OUT_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+			       da7218_out_dig_gain_tlv),
+	SOC_DOUBLE_R("Out Filter Switch", DA7218_OUT_1L_FILTER_CTRL,
+		     DA7218_OUT_1R_FILTER_CTRL, DA7218_OUT_1L_MUTE_EN_SHIFT,
+		     DA7218_SWITCH_EN_MAX, DA7218_INVERT),
+	SOC_DOUBLE_R("Out Filter Gain Subrange Switch",
+		     DA7218_OUT_1L_FILTER_CTRL, DA7218_OUT_1R_FILTER_CTRL,
+		     DA7218_OUT_1L_SUBRANGE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		     DA7218_NO_INVERT),
+	SOC_DOUBLE_R("Out Filter Gain Ramp Switch", DA7218_OUT_1L_FILTER_CTRL,
+		     DA7218_OUT_1R_FILTER_CTRL, DA7218_OUT_1L_RAMP_EN_SHIFT,
+		     DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+
+	/* Mixer Output */
+	SOC_DOUBLE_R_RANGE_TLV("Mixout Volume", DA7218_MIXOUT_L_GAIN,
+			       DA7218_MIXOUT_R_GAIN,
+			       DA7218_MIXOUT_L_AMP_GAIN_SHIFT,
+			       DA7218_MIXOUT_AMP_GAIN_MIN,
+			       DA7218_MIXOUT_AMP_GAIN_MAX, DA7218_NO_INVERT,
+			       da7218_mixout_gain_tlv),
+
+	/* DAC Noise Gate */
+	SOC_ENUM("DAC NG Setup Time", da7218_dac_ng_setup_time),
+	SOC_ENUM("DAC NG Rampup Rate", da7218_dac_ng_rampup_rate),
+	SOC_ENUM("DAC NG Rampdown Rate", da7218_dac_ng_rampdown_rate),
+	SOC_SINGLE_TLV("DAC NG Off Threshold", DA7218_DAC_NG_OFF_THRESH,
+		       DA7218_DAC_NG_OFF_THRESHOLD_SHIFT,
+		       DA7218_DAC_NG_THRESHOLD_MAX, DA7218_NO_INVERT,
+		       da7218_dac_ng_threshold_tlv),
+	SOC_SINGLE_TLV("DAC NG On Threshold", DA7218_DAC_NG_ON_THRESH,
+		       DA7218_DAC_NG_ON_THRESHOLD_SHIFT,
+		       DA7218_DAC_NG_THRESHOLD_MAX, DA7218_NO_INVERT,
+		       da7218_dac_ng_threshold_tlv),
+	SOC_SINGLE("DAC NG Switch", DA7218_DAC_NG_CTRL, DA7218_DAC_NG_EN_SHIFT,
+		   DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+
+	/* CP */
+	SOC_ENUM("Charge Pump Track Mode", da7218_cp_mchange),
+	SOC_ENUM("Charge Pump Frequency", da7218_cp_fcontrol),
+	SOC_ENUM("Charge Pump Decay Rate", da7218_cp_tau_delay),
+	SOC_SINGLE("Charge Pump Threshold", DA7218_CP_VOL_THRESHOLD1,
+		   DA7218_CP_THRESH_VDD2_SHIFT, DA7218_CP_THRESH_VDD2_MAX,
+		   DA7218_NO_INVERT),
+
+	/* Headphones */
+	SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", DA7218_HP_L_GAIN,
+			       DA7218_HP_R_GAIN, DA7218_HP_L_AMP_GAIN_SHIFT,
+			       DA7218_HP_AMP_GAIN_MIN, DA7218_HP_AMP_GAIN_MAX,
+			       DA7218_NO_INVERT, da7218_hp_gain_tlv),
+	SOC_DOUBLE_R("Headphone Switch", DA7218_HP_L_CTRL, DA7218_HP_R_CTRL,
+		     DA7218_HP_L_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		     DA7218_INVERT),
+	SOC_DOUBLE_R("Headphone Gain Ramp Switch", DA7218_HP_L_CTRL,
+		     DA7218_HP_R_CTRL, DA7218_HP_L_AMP_RAMP_EN_SHIFT,
+		     DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+	SOC_DOUBLE_R("Headphone ZC Gain Switch", DA7218_HP_L_CTRL,
+		     DA7218_HP_R_CTRL, DA7218_HP_L_AMP_ZC_EN_SHIFT,
+		     DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+};
+
+
+/*
+ * DAPM Mux Controls
+ */
+
+static const char * const da7218_mic_sel_text[] = { "Analog", "Digital" };
+
+static const struct soc_enum da7218_mic1_sel =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(da7218_mic_sel_text),
+			    da7218_mic_sel_text);
+
+static const struct snd_kcontrol_new da7218_mic1_sel_mux =
+	SOC_DAPM_ENUM("Mic1 Mux", da7218_mic1_sel);
+
+static const struct soc_enum da7218_mic2_sel =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(da7218_mic_sel_text),
+			    da7218_mic_sel_text);
+
+static const struct snd_kcontrol_new da7218_mic2_sel_mux =
+	SOC_DAPM_ENUM("Mic2 Mux", da7218_mic2_sel);
+
+static const char * const da7218_sidetone_in_sel_txt[] = {
+	"In Filter1L", "In Filter1R", "In Filter2L", "In Filter2R"
+};
+
+static const struct soc_enum da7218_sidetone_in_sel =
+	SOC_ENUM_SINGLE(DA7218_SIDETONE_IN_SELECT,
+			DA7218_SIDETONE_IN_SELECT_SHIFT,
+			DA7218_SIDETONE_IN_SELECT_MAX,
+			da7218_sidetone_in_sel_txt);
+
+static const struct snd_kcontrol_new da7218_sidetone_in_sel_mux =
+	SOC_DAPM_ENUM("Sidetone Mux", da7218_sidetone_in_sel);
+
+static const char * const da7218_out_filt_biq_sel_txt[] = {
+	"Bypass", "Enabled"
+};
+
+static const struct soc_enum da7218_out_filtl_biq_sel =
+	SOC_ENUM_SINGLE(DA7218_OUT_1L_FILTER_CTRL,
+			DA7218_OUT_1L_BIQ_5STAGE_SEL_SHIFT,
+			DA7218_OUT_BIQ_5STAGE_SEL_MAX,
+			da7218_out_filt_biq_sel_txt);
+
+static const struct snd_kcontrol_new da7218_out_filtl_biq_sel_mux =
+	SOC_DAPM_ENUM("Out FilterL BiQuad Mux", da7218_out_filtl_biq_sel);
+
+static const struct soc_enum da7218_out_filtr_biq_sel =
+	SOC_ENUM_SINGLE(DA7218_OUT_1R_FILTER_CTRL,
+			DA7218_OUT_1R_BIQ_5STAGE_SEL_SHIFT,
+			DA7218_OUT_BIQ_5STAGE_SEL_MAX,
+			da7218_out_filt_biq_sel_txt);
+
+static const struct snd_kcontrol_new da7218_out_filtr_biq_sel_mux =
+	SOC_DAPM_ENUM("Out FilterR BiQuad Mux", da7218_out_filtr_biq_sel);
+
+
+/*
+ * DAPM Mixer Controls
+ */
+
+#define DA7218_DMIX_CTRLS(reg)						\
+	SOC_DAPM_SINGLE("In Filter1L Switch", reg,			\
+			DA7218_DMIX_SRC_INFILT1L,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("In Filter1R Switch", reg,			\
+			DA7218_DMIX_SRC_INFILT1R,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("In Filter2L Switch", reg,			\
+			DA7218_DMIX_SRC_INFILT2L,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("In Filter2R Switch", reg,			\
+			DA7218_DMIX_SRC_INFILT2R,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("ToneGen Switch", reg,				\
+			DA7218_DMIX_SRC_TONEGEN,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("DAIL Switch", reg, DA7218_DMIX_SRC_DAIL,	\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("DAIR Switch", reg, DA7218_DMIX_SRC_DAIR,	\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT)
+
+static const struct snd_kcontrol_new da7218_out_dai1l_mix_controls[] = {
+	DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_1L),
+};
+
+static const struct snd_kcontrol_new da7218_out_dai1r_mix_controls[] = {
+	DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_1R),
+};
+
+static const struct snd_kcontrol_new da7218_out_dai2l_mix_controls[] = {
+	DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_2L),
+};
+
+static const struct snd_kcontrol_new da7218_out_dai2r_mix_controls[] = {
+	DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_2R),
+};
+
+static const struct snd_kcontrol_new da7218_out_filtl_mix_controls[] = {
+	DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTFILT_1L),
+};
+
+static const struct snd_kcontrol_new da7218_out_filtr_mix_controls[] = {
+	DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTFILT_1R),
+};
+
+#define DA7218_DMIX_ST_CTRLS(reg)					\
+	SOC_DAPM_SINGLE("Out FilterL Switch", reg,			\
+			DA7218_DMIX_ST_SRC_OUTFILT1L,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("Out FilterR Switch", reg,			\
+			DA7218_DMIX_ST_SRC_OUTFILT1R,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("Sidetone Switch", reg,				\
+			DA7218_DMIX_ST_SRC_SIDETONE,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT)		\
+
+static const struct snd_kcontrol_new da7218_st_out_filtl_mix_controls[] = {
+	DA7218_DMIX_ST_CTRLS(DA7218_DROUTING_ST_OUTFILT_1L),
+};
+
+static const struct snd_kcontrol_new da7218_st_out_filtr_mix_controls[] = {
+	DA7218_DMIX_ST_CTRLS(DA7218_DROUTING_ST_OUTFILT_1R),
+};
+
+
+/*
+ * DAPM Events
+ */
+
+/*
+ * We keep track of which input filters are enabled. This is used in the logic
+ * for controlling the mic level detect feature.
+ */
+static int da7218_in_filter_event(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	u8 mask;
+
+	switch (w->reg) {
+	case DA7218_IN_1L_FILTER_CTRL:
+		mask = (1 << DA7218_LVL_DET_EN_CHAN1L_SHIFT);
+		break;
+	case DA7218_IN_1R_FILTER_CTRL:
+		mask = (1 << DA7218_LVL_DET_EN_CHAN1R_SHIFT);
+		break;
+	case DA7218_IN_2L_FILTER_CTRL:
+		mask = (1 << DA7218_LVL_DET_EN_CHAN2L_SHIFT);
+		break;
+	case DA7218_IN_2R_FILTER_CTRL:
+		mask = (1 << DA7218_LVL_DET_EN_CHAN2R_SHIFT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		da7218->in_filt_en |= mask;
+		/*
+		 * If we're enabling path for mic level detect, wait for path
+		 * to settle before enabling feature to avoid incorrect and
+		 * unwanted detect events.
+		 */
+		if (mask & da7218->mic_lvl_det_en)
+			msleep(DA7218_MIC_LVL_DET_DELAY);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		da7218->in_filt_en &= ~mask;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Enable configured level detection paths */
+	snd_soc_component_write(component, DA7218_LVL_DET_CTRL,
+		      (da7218->in_filt_en & da7218->mic_lvl_det_en));
+
+	return 0;
+}
+
+static int da7218_dai_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	u8 pll_ctrl, pll_status, refosc_cal;
+	int i;
+	bool success;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (da7218->master)
+			/* Enable DAI clks for master mode */
+			snd_soc_component_update_bits(component, DA7218_DAI_CLK_MODE,
+					    DA7218_DAI_CLK_EN_MASK,
+					    DA7218_DAI_CLK_EN_MASK);
+
+		/* Tune reference oscillator */
+		snd_soc_component_write(component, DA7218_PLL_REFOSC_CAL,
+			      DA7218_PLL_REFOSC_CAL_START_MASK);
+		snd_soc_component_write(component, DA7218_PLL_REFOSC_CAL,
+			      DA7218_PLL_REFOSC_CAL_START_MASK |
+			      DA7218_PLL_REFOSC_CAL_EN_MASK);
+
+		/* Check tuning complete */
+		i = 0;
+		success = false;
+		do {
+			refosc_cal = snd_soc_component_read32(component, DA7218_PLL_REFOSC_CAL);
+			if (!(refosc_cal & DA7218_PLL_REFOSC_CAL_START_MASK)) {
+				success = true;
+			} else {
+				++i;
+				usleep_range(DA7218_REF_OSC_CHECK_DELAY_MIN,
+					     DA7218_REF_OSC_CHECK_DELAY_MAX);
+			}
+		} while ((i < DA7218_REF_OSC_CHECK_TRIES) && (!success));
+
+		if (!success)
+			dev_warn(component->dev,
+				 "Reference oscillator failed calibration\n");
+
+		/* PC synchronised to DAI */
+		snd_soc_component_write(component, DA7218_PC_COUNT,
+			      DA7218_PC_RESYNC_AUTO_MASK);
+
+		/* If SRM not enabled, we don't need to check status */
+		pll_ctrl = snd_soc_component_read32(component, DA7218_PLL_CTRL);
+		if ((pll_ctrl & DA7218_PLL_MODE_MASK) != DA7218_PLL_MODE_SRM)
+			return 0;
+
+		/* Check SRM has locked */
+		i = 0;
+		success = false;
+		do {
+			pll_status = snd_soc_component_read32(component, DA7218_PLL_STATUS);
+			if (pll_status & DA7218_PLL_SRM_STATUS_SRM_LOCK) {
+				success = true;
+			} else {
+				++i;
+				msleep(DA7218_SRM_CHECK_DELAY);
+			}
+		} while ((i < DA7218_SRM_CHECK_TRIES) && (!success));
+
+		if (!success)
+			dev_warn(component->dev, "SRM failed to lock\n");
+
+		return 0;
+	case SND_SOC_DAPM_POST_PMD:
+		/* PC free-running */
+		snd_soc_component_write(component, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK);
+
+		if (da7218->master)
+			/* Disable DAI clks for master mode */
+			snd_soc_component_update_bits(component, DA7218_DAI_CLK_MODE,
+					    DA7218_DAI_CLK_EN_MASK, 0);
+
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int da7218_cp_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+
+	/*
+	 * If this is DA7217 and we're using single supply for differential
+	 * output, we really don't want to touch the charge pump.
+	 */
+	if (da7218->hp_single_supply)
+		return 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component, DA7218_CP_CTRL, DA7218_CP_EN_MASK,
+				    DA7218_CP_EN_MASK);
+		return 0;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, DA7218_CP_CTRL, DA7218_CP_EN_MASK,
+				    0);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int da7218_hp_pga_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Enable headphone output */
+		snd_soc_component_update_bits(component, w->reg, DA7218_HP_AMP_OE_MASK,
+				    DA7218_HP_AMP_OE_MASK);
+		return 0;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Headphone output high impedance */
+		snd_soc_component_update_bits(component, w->reg, DA7218_HP_AMP_OE_MASK, 0);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+
+/*
+ * DAPM Widgets
+ */
+
+static const struct snd_soc_dapm_widget da7218_dapm_widgets[] = {
+	/* Input Supplies */
+	SND_SOC_DAPM_SUPPLY("Mic Bias1", DA7218_MICBIAS_EN,
+			    DA7218_MICBIAS_1_EN_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Bias2", DA7218_MICBIAS_EN,
+			    DA7218_MICBIAS_2_EN_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMic1 Left", DA7218_DMIC_1_CTRL,
+			    DA7218_DMIC_1L_EN_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMic1 Right", DA7218_DMIC_1_CTRL,
+			    DA7218_DMIC_1R_EN_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMic2 Left", DA7218_DMIC_2_CTRL,
+			    DA7218_DMIC_2L_EN_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMic2 Right", DA7218_DMIC_2_CTRL,
+			    DA7218_DMIC_2R_EN_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("DMIC1L"),
+	SND_SOC_DAPM_INPUT("DMIC1R"),
+	SND_SOC_DAPM_INPUT("DMIC2L"),
+	SND_SOC_DAPM_INPUT("DMIC2R"),
+
+	/* Input Mixer Supplies */
+	SND_SOC_DAPM_SUPPLY("Mixin1 Supply", DA7218_MIXIN_1_CTRL,
+			    DA7218_MIXIN_1_MIX_SEL_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mixin2 Supply", DA7218_MIXIN_2_CTRL,
+			    DA7218_MIXIN_2_MIX_SEL_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+
+	/* Input PGAs */
+	SND_SOC_DAPM_PGA("Mic1 PGA", DA7218_MIC_1_CTRL,
+			 DA7218_MIC_1_AMP_EN_SHIFT, DA7218_NO_INVERT,
+			 NULL, 0),
+	SND_SOC_DAPM_PGA("Mic2 PGA", DA7218_MIC_2_CTRL,
+			 DA7218_MIC_2_AMP_EN_SHIFT, DA7218_NO_INVERT,
+			 NULL, 0),
+	SND_SOC_DAPM_PGA("Mixin1 PGA", DA7218_MIXIN_1_CTRL,
+			 DA7218_MIXIN_1_AMP_EN_SHIFT, DA7218_NO_INVERT,
+			 NULL, 0),
+	SND_SOC_DAPM_PGA("Mixin2 PGA", DA7218_MIXIN_2_CTRL,
+			 DA7218_MIXIN_2_AMP_EN_SHIFT, DA7218_NO_INVERT,
+			 NULL, 0),
+
+	/* Mic/DMic Muxes */
+	SND_SOC_DAPM_MUX("Mic1 Mux", SND_SOC_NOPM, 0, 0, &da7218_mic1_sel_mux),
+	SND_SOC_DAPM_MUX("Mic2 Mux", SND_SOC_NOPM, 0, 0, &da7218_mic2_sel_mux),
+
+	/* Input Filters */
+	SND_SOC_DAPM_ADC_E("In Filter1L", NULL, DA7218_IN_1L_FILTER_CTRL,
+			   DA7218_IN_1L_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+			   da7218_in_filter_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_ADC_E("In Filter1R", NULL, DA7218_IN_1R_FILTER_CTRL,
+			   DA7218_IN_1R_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+			   da7218_in_filter_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_ADC_E("In Filter2L", NULL, DA7218_IN_2L_FILTER_CTRL,
+			   DA7218_IN_2L_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+			   da7218_in_filter_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_ADC_E("In Filter2R", NULL, DA7218_IN_2R_FILTER_CTRL,
+			   DA7218_IN_2R_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+			   da7218_in_filter_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	/* Tone Generator */
+	SND_SOC_DAPM_SIGGEN("TONE"),
+	SND_SOC_DAPM_PGA("Tone Generator", DA7218_TONE_GEN_CFG1,
+			 DA7218_START_STOPN_SHIFT, DA7218_NO_INVERT, NULL, 0),
+
+	/* Sidetone Input */
+	SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0,
+			 &da7218_sidetone_in_sel_mux),
+	SND_SOC_DAPM_ADC("Sidetone Filter", NULL, DA7218_SIDETONE_CTRL,
+			 DA7218_SIDETONE_FILTER_EN_SHIFT, DA7218_NO_INVERT),
+
+	/* Input Mixers */
+	SND_SOC_DAPM_MIXER("Mixer DAI1L", SND_SOC_NOPM, 0, 0,
+			   da7218_out_dai1l_mix_controls,
+			   ARRAY_SIZE(da7218_out_dai1l_mix_controls)),
+	SND_SOC_DAPM_MIXER("Mixer DAI1R", SND_SOC_NOPM, 0, 0,
+			   da7218_out_dai1r_mix_controls,
+			   ARRAY_SIZE(da7218_out_dai1r_mix_controls)),
+	SND_SOC_DAPM_MIXER("Mixer DAI2L", SND_SOC_NOPM, 0, 0,
+			   da7218_out_dai2l_mix_controls,
+			   ARRAY_SIZE(da7218_out_dai2l_mix_controls)),
+	SND_SOC_DAPM_MIXER("Mixer DAI2R", SND_SOC_NOPM, 0, 0,
+			   da7218_out_dai2r_mix_controls,
+			   ARRAY_SIZE(da7218_out_dai2r_mix_controls)),
+
+	/* DAI Supply */
+	SND_SOC_DAPM_SUPPLY("DAI", DA7218_DAI_CTRL, DA7218_DAI_EN_SHIFT,
+			    DA7218_NO_INVERT, da7218_dai_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* DAI */
+	SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, DA7218_DAI_TDM_CTRL,
+			     DA7218_DAI_OE_SHIFT, DA7218_NO_INVERT),
+	SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Mixers */
+	SND_SOC_DAPM_MIXER("Mixer Out FilterL", SND_SOC_NOPM, 0, 0,
+			   da7218_out_filtl_mix_controls,
+			   ARRAY_SIZE(da7218_out_filtl_mix_controls)),
+	SND_SOC_DAPM_MIXER("Mixer Out FilterR", SND_SOC_NOPM, 0, 0,
+			   da7218_out_filtr_mix_controls,
+			   ARRAY_SIZE(da7218_out_filtr_mix_controls)),
+
+	/* BiQuad Filters */
+	SND_SOC_DAPM_MUX("Out FilterL BiQuad Mux", SND_SOC_NOPM, 0, 0,
+			 &da7218_out_filtl_biq_sel_mux),
+	SND_SOC_DAPM_MUX("Out FilterR BiQuad Mux", SND_SOC_NOPM, 0, 0,
+			 &da7218_out_filtr_biq_sel_mux),
+	SND_SOC_DAPM_DAC("BiQuad Filter", NULL, DA7218_OUT_1_BIQ_5STAGE_CTRL,
+			 DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_SHIFT,
+			 DA7218_NO_INVERT),
+
+	/* Sidetone Mixers */
+	SND_SOC_DAPM_MIXER("ST Mixer Out FilterL", SND_SOC_NOPM, 0, 0,
+			   da7218_st_out_filtl_mix_controls,
+			   ARRAY_SIZE(da7218_st_out_filtl_mix_controls)),
+	SND_SOC_DAPM_MIXER("ST Mixer Out FilterR", SND_SOC_NOPM, 0, 0,
+			   da7218_st_out_filtr_mix_controls,
+			   ARRAY_SIZE(da7218_st_out_filtr_mix_controls)),
+
+	/* Output Filters */
+	SND_SOC_DAPM_DAC("Out FilterL", NULL, DA7218_OUT_1L_FILTER_CTRL,
+			 DA7218_OUT_1L_FILTER_EN_SHIFT, DA7218_NO_INVERT),
+	SND_SOC_DAPM_DAC("Out FilterR", NULL, DA7218_OUT_1R_FILTER_CTRL,
+			 DA7218_IN_1R_FILTER_EN_SHIFT, DA7218_NO_INVERT),
+
+	/* Output PGAs */
+	SND_SOC_DAPM_PGA("Mixout Left PGA", DA7218_MIXOUT_L_CTRL,
+			 DA7218_MIXOUT_L_AMP_EN_SHIFT, DA7218_NO_INVERT,
+			 NULL, 0),
+	SND_SOC_DAPM_PGA("Mixout Right PGA", DA7218_MIXOUT_R_CTRL,
+			 DA7218_MIXOUT_R_AMP_EN_SHIFT, DA7218_NO_INVERT,
+			 NULL, 0),
+	SND_SOC_DAPM_PGA_E("Headphone Left PGA", DA7218_HP_L_CTRL,
+			   DA7218_HP_L_AMP_EN_SHIFT, DA7218_NO_INVERT, NULL, 0,
+			   da7218_hp_pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA_E("Headphone Right PGA", DA7218_HP_R_CTRL,
+			   DA7218_HP_R_AMP_EN_SHIFT, DA7218_NO_INVERT, NULL, 0,
+			   da7218_hp_pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	/* Output Supplies */
+	SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0, da7218_cp_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+
+/*
+ * DAPM Mixer Routes
+ */
+
+#define DA7218_DMIX_ROUTES(name)				\
+	{name, "In Filter1L Switch", "In Filter1L"},		\
+	{name, "In Filter1R Switch", "In Filter1R"},		\
+	{name, "In Filter2L Switch", "In Filter2L"},		\
+	{name, "In Filter2R Switch", "In Filter2R"},		\
+	{name, "ToneGen Switch", "Tone Generator"},		\
+	{name, "DAIL Switch", "DAIIN"},				\
+	{name, "DAIR Switch", "DAIIN"}
+
+#define DA7218_DMIX_ST_ROUTES(name)				\
+	{name, "Out FilterL Switch", "Out FilterL BiQuad Mux"},	\
+	{name, "Out FilterR Switch", "Out FilterR BiQuad Mux"},	\
+	{name, "Sidetone Switch", "Sidetone Filter"}
+
+
+/*
+ * DAPM audio route definition
+ */
+
+static const struct snd_soc_dapm_route da7218_audio_map[] = {
+	/* Input paths */
+	{"MIC1", NULL, "Mic Bias1"},
+	{"MIC2", NULL, "Mic Bias2"},
+	{"DMIC1L", NULL, "Mic Bias1"},
+	{"DMIC1L", NULL, "DMic1 Left"},
+	{"DMIC1R", NULL, "Mic Bias1"},
+	{"DMIC1R", NULL, "DMic1 Right"},
+	{"DMIC2L", NULL, "Mic Bias2"},
+	{"DMIC2L", NULL, "DMic2 Left"},
+	{"DMIC2R", NULL, "Mic Bias2"},
+	{"DMIC2R", NULL, "DMic2 Right"},
+
+	{"Mic1 PGA", NULL, "MIC1"},
+	{"Mic2 PGA", NULL, "MIC2"},
+
+	{"Mixin1 PGA", NULL, "Mixin1 Supply"},
+	{"Mixin2 PGA", NULL, "Mixin2 Supply"},
+
+	{"Mixin1 PGA", NULL, "Mic1 PGA"},
+	{"Mixin2 PGA", NULL, "Mic2 PGA"},
+
+	{"Mic1 Mux", "Analog", "Mixin1 PGA"},
+	{"Mic1 Mux", "Digital", "DMIC1L"},
+	{"Mic1 Mux", "Digital", "DMIC1R"},
+	{"Mic2 Mux", "Analog", "Mixin2 PGA"},
+	{"Mic2 Mux", "Digital", "DMIC2L"},
+	{"Mic2 Mux", "Digital", "DMIC2R"},
+
+	{"In Filter1L", NULL, "Mic1 Mux"},
+	{"In Filter1R", NULL, "Mic1 Mux"},
+	{"In Filter2L", NULL, "Mic2 Mux"},
+	{"In Filter2R", NULL, "Mic2 Mux"},
+
+	{"Tone Generator", NULL, "TONE"},
+
+	{"Sidetone Mux", "In Filter1L", "In Filter1L"},
+	{"Sidetone Mux", "In Filter1R", "In Filter1R"},
+	{"Sidetone Mux", "In Filter2L", "In Filter2L"},
+	{"Sidetone Mux", "In Filter2R", "In Filter2R"},
+	{"Sidetone Filter", NULL, "Sidetone Mux"},
+
+	DA7218_DMIX_ROUTES("Mixer DAI1L"),
+	DA7218_DMIX_ROUTES("Mixer DAI1R"),
+	DA7218_DMIX_ROUTES("Mixer DAI2L"),
+	DA7218_DMIX_ROUTES("Mixer DAI2R"),
+
+	{"DAIOUT", NULL, "Mixer DAI1L"},
+	{"DAIOUT", NULL, "Mixer DAI1R"},
+	{"DAIOUT", NULL, "Mixer DAI2L"},
+	{"DAIOUT", NULL, "Mixer DAI2R"},
+
+	{"DAIOUT", NULL, "DAI"},
+
+	/* Output paths */
+	{"DAIIN", NULL, "DAI"},
+
+	DA7218_DMIX_ROUTES("Mixer Out FilterL"),
+	DA7218_DMIX_ROUTES("Mixer Out FilterR"),
+
+	{"BiQuad Filter", NULL, "Mixer Out FilterL"},
+	{"BiQuad Filter", NULL, "Mixer Out FilterR"},
+
+	{"Out FilterL BiQuad Mux", "Bypass", "Mixer Out FilterL"},
+	{"Out FilterL BiQuad Mux", "Enabled", "BiQuad Filter"},
+	{"Out FilterR BiQuad Mux", "Bypass", "Mixer Out FilterR"},
+	{"Out FilterR BiQuad Mux", "Enabled", "BiQuad Filter"},
+
+	DA7218_DMIX_ST_ROUTES("ST Mixer Out FilterL"),
+	DA7218_DMIX_ST_ROUTES("ST Mixer Out FilterR"),
+
+	{"Out FilterL", NULL, "ST Mixer Out FilterL"},
+	{"Out FilterR", NULL, "ST Mixer Out FilterR"},
+
+	{"Mixout Left PGA", NULL, "Out FilterL"},
+	{"Mixout Right PGA", NULL, "Out FilterR"},
+
+	{"Headphone Left PGA", NULL, "Mixout Left PGA"},
+	{"Headphone Right PGA", NULL, "Mixout Right PGA"},
+
+	{"HPL", NULL, "Headphone Left PGA"},
+	{"HPR", NULL, "Headphone Right PGA"},
+
+	{"HPL", NULL, "Charge Pump"},
+	{"HPR", NULL, "Charge Pump"},
+};
+
+
+/*
+ * DAI operations
+ */
+
+static int da7218_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	if (da7218->mclk_rate == freq)
+		return 0;
+
+	if ((freq < 2000000) || (freq > 54000000)) {
+		dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+			freq);
+		return -EINVAL;
+	}
+
+	switch (clk_id) {
+	case DA7218_CLKSRC_MCLK_SQR:
+		snd_soc_component_update_bits(component, DA7218_PLL_CTRL,
+				    DA7218_PLL_MCLK_SQR_EN_MASK,
+				    DA7218_PLL_MCLK_SQR_EN_MASK);
+		break;
+	case DA7218_CLKSRC_MCLK:
+		snd_soc_component_update_bits(component, DA7218_PLL_CTRL,
+				    DA7218_PLL_MCLK_SQR_EN_MASK, 0);
+		break;
+	default:
+		dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	if (da7218->mclk) {
+		freq = clk_round_rate(da7218->mclk, freq);
+		ret = clk_set_rate(da7218->mclk, freq);
+		if (ret) {
+			dev_err(codec_dai->dev, "Failed to set clock rate %d\n",
+				freq);
+			return ret;
+		}
+	}
+
+	da7218->mclk_rate = freq;
+
+	return 0;
+}
+
+static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+			      int source, unsigned int fref, unsigned int fout)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+
+	u8 pll_ctrl, indiv_bits, indiv;
+	u8 pll_frac_top, pll_frac_bot, pll_integer;
+	u32 freq_ref;
+	u64 frac_div;
+
+	/* Verify 2MHz - 54MHz MCLK provided, and set input divider */
+	if (da7218->mclk_rate < 2000000) {
+		dev_err(component->dev, "PLL input clock %d below valid range\n",
+			da7218->mclk_rate);
+		return -EINVAL;
+	} else if (da7218->mclk_rate <= 4500000) {
+		indiv_bits = DA7218_PLL_INDIV_2_TO_4_5_MHZ;
+		indiv = DA7218_PLL_INDIV_2_TO_4_5_MHZ_VAL;
+	} else if (da7218->mclk_rate <= 9000000) {
+		indiv_bits = DA7218_PLL_INDIV_4_5_TO_9_MHZ;
+		indiv = DA7218_PLL_INDIV_4_5_TO_9_MHZ_VAL;
+	} else if (da7218->mclk_rate <= 18000000) {
+		indiv_bits = DA7218_PLL_INDIV_9_TO_18_MHZ;
+		indiv = DA7218_PLL_INDIV_9_TO_18_MHZ_VAL;
+	} else if (da7218->mclk_rate <= 36000000) {
+		indiv_bits = DA7218_PLL_INDIV_18_TO_36_MHZ;
+		indiv = DA7218_PLL_INDIV_18_TO_36_MHZ_VAL;
+	} else if (da7218->mclk_rate <= 54000000) {
+		indiv_bits = DA7218_PLL_INDIV_36_TO_54_MHZ;
+		indiv = DA7218_PLL_INDIV_36_TO_54_MHZ_VAL;
+	} else {
+		dev_err(component->dev, "PLL input clock %d above valid range\n",
+			da7218->mclk_rate);
+		return -EINVAL;
+	}
+	freq_ref = (da7218->mclk_rate / indiv);
+	pll_ctrl = indiv_bits;
+
+	/* Configure PLL */
+	switch (source) {
+	case DA7218_SYSCLK_MCLK:
+		pll_ctrl |= DA7218_PLL_MODE_BYPASS;
+		snd_soc_component_update_bits(component, DA7218_PLL_CTRL,
+				    DA7218_PLL_INDIV_MASK |
+				    DA7218_PLL_MODE_MASK, pll_ctrl);
+		return 0;
+	case DA7218_SYSCLK_PLL:
+		pll_ctrl |= DA7218_PLL_MODE_NORMAL;
+		break;
+	case DA7218_SYSCLK_PLL_SRM:
+		pll_ctrl |= DA7218_PLL_MODE_SRM;
+		break;
+	default:
+		dev_err(component->dev, "Invalid PLL config\n");
+		return -EINVAL;
+	}
+
+	/* Calculate dividers for PLL */
+	pll_integer = fout / freq_ref;
+	frac_div = (u64)(fout % freq_ref) * 8192ULL;
+	do_div(frac_div, freq_ref);
+	pll_frac_top = (frac_div >> DA7218_BYTE_SHIFT) & DA7218_BYTE_MASK;
+	pll_frac_bot = (frac_div) & DA7218_BYTE_MASK;
+
+	/* Write PLL config & dividers */
+	snd_soc_component_write(component, DA7218_PLL_FRAC_TOP, pll_frac_top);
+	snd_soc_component_write(component, DA7218_PLL_FRAC_BOT, pll_frac_bot);
+	snd_soc_component_write(component, DA7218_PLL_INTEGER, pll_integer);
+	snd_soc_component_update_bits(component, DA7218_PLL_CTRL,
+			    DA7218_PLL_MODE_MASK | DA7218_PLL_INDIV_MASK,
+			    pll_ctrl);
+
+	return 0;
+}
+
+static int da7218_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	u8 dai_clk_mode = 0, dai_ctrl = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		da7218->master = true;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		da7218->master = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			dai_clk_mode |= DA7218_DAI_WCLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			dai_clk_mode |= DA7218_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			dai_clk_mode |= DA7218_DAI_WCLK_POL_INV |
+					DA7218_DAI_CLK_POL_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			dai_clk_mode |= DA7218_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			dai_clk_mode |= DA7218_DAI_WCLK_POL_INV |
+					DA7218_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			dai_clk_mode |= DA7218_DAI_WCLK_POL_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		dai_ctrl |= DA7218_DAI_FORMAT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		dai_ctrl |= DA7218_DAI_FORMAT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		dai_ctrl |= DA7218_DAI_FORMAT_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		dai_ctrl |= DA7218_DAI_FORMAT_DSP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* By default 64 BCLKs per WCLK is supported */
+	dai_clk_mode |= DA7218_DAI_BCLKS_PER_WCLK_64;
+
+	snd_soc_component_write(component, DA7218_DAI_CLK_MODE, dai_clk_mode);
+	snd_soc_component_update_bits(component, DA7218_DAI_CTRL, DA7218_DAI_FORMAT_MASK,
+			    dai_ctrl);
+
+	return 0;
+}
+
+static int da7218_set_dai_tdm_slot(struct snd_soc_dai *dai,
+				   unsigned int tx_mask, unsigned int rx_mask,
+				   int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 dai_bclks_per_wclk;
+	u32 frame_size;
+
+	/* No channels enabled so disable TDM, revert to 64-bit frames */
+	if (!tx_mask) {
+		snd_soc_component_update_bits(component, DA7218_DAI_TDM_CTRL,
+				    DA7218_DAI_TDM_CH_EN_MASK |
+				    DA7218_DAI_TDM_MODE_EN_MASK, 0);
+		snd_soc_component_update_bits(component, DA7218_DAI_CLK_MODE,
+				    DA7218_DAI_BCLKS_PER_WCLK_MASK,
+				    DA7218_DAI_BCLKS_PER_WCLK_64);
+		return 0;
+	}
+
+	/* Check we have valid slots */
+	if (fls(tx_mask) > DA7218_DAI_TDM_MAX_SLOTS) {
+		dev_err(component->dev, "Invalid number of slots, max = %d\n",
+			DA7218_DAI_TDM_MAX_SLOTS);
+		return -EINVAL;
+	}
+
+	/* Check we have a valid offset given (first 2 bytes of rx_mask) */
+	if (rx_mask >> DA7218_2BYTE_SHIFT) {
+		dev_err(component->dev, "Invalid slot offset, max = %d\n",
+			DA7218_2BYTE_MASK);
+		return -EINVAL;
+	}
+
+	/* Calculate & validate frame size based on slot info provided. */
+	frame_size = slots * slot_width;
+	switch (frame_size) {
+	case 32:
+		dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_32;
+		break;
+	case 64:
+		dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_64;
+		break;
+	case 128:
+		dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_128;
+		break;
+	case 256:
+		dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_256;
+		break;
+	default:
+		dev_err(component->dev, "Invalid frame size\n");
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, DA7218_DAI_CLK_MODE,
+			    DA7218_DAI_BCLKS_PER_WCLK_MASK,
+			    dai_bclks_per_wclk);
+	snd_soc_component_write(component, DA7218_DAI_OFFSET_LOWER,
+		      (rx_mask & DA7218_BYTE_MASK));
+	snd_soc_component_write(component, DA7218_DAI_OFFSET_UPPER,
+		      ((rx_mask >> DA7218_BYTE_SHIFT) & DA7218_BYTE_MASK));
+	snd_soc_component_update_bits(component, DA7218_DAI_TDM_CTRL,
+			    DA7218_DAI_TDM_CH_EN_MASK |
+			    DA7218_DAI_TDM_MODE_EN_MASK,
+			    (tx_mask << DA7218_DAI_TDM_CH_EN_SHIFT) |
+			    DA7218_DAI_TDM_MODE_EN_MASK);
+
+	return 0;
+}
+
+static int da7218_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 dai_ctrl = 0, fs;
+	unsigned int channels;
+
+	switch (params_width(params)) {
+	case 16:
+		dai_ctrl |= DA7218_DAI_WORD_LENGTH_S16_LE;
+		break;
+	case 20:
+		dai_ctrl |= DA7218_DAI_WORD_LENGTH_S20_LE;
+		break;
+	case 24:
+		dai_ctrl |= DA7218_DAI_WORD_LENGTH_S24_LE;
+		break;
+	case 32:
+		dai_ctrl |= DA7218_DAI_WORD_LENGTH_S32_LE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	channels = params_channels(params);
+	if ((channels < 1) || (channels > DA7218_DAI_CH_NUM_MAX)) {
+		dev_err(component->dev,
+			"Invalid number of channels, only 1 to %d supported\n",
+			DA7218_DAI_CH_NUM_MAX);
+		return -EINVAL;
+	}
+	dai_ctrl |= channels << DA7218_DAI_CH_NUM_SHIFT;
+
+	switch (params_rate(params)) {
+	case 8000:
+		fs = DA7218_SR_8000;
+		break;
+	case 11025:
+		fs = DA7218_SR_11025;
+		break;
+	case 12000:
+		fs = DA7218_SR_12000;
+		break;
+	case 16000:
+		fs = DA7218_SR_16000;
+		break;
+	case 22050:
+		fs = DA7218_SR_22050;
+		break;
+	case 24000:
+		fs = DA7218_SR_24000;
+		break;
+	case 32000:
+		fs = DA7218_SR_32000;
+		break;
+	case 44100:
+		fs = DA7218_SR_44100;
+		break;
+	case 48000:
+		fs = DA7218_SR_48000;
+		break;
+	case 88200:
+		fs = DA7218_SR_88200;
+		break;
+	case 96000:
+		fs = DA7218_SR_96000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, DA7218_DAI_CTRL,
+			    DA7218_DAI_WORD_LENGTH_MASK | DA7218_DAI_CH_NUM_MASK,
+			    dai_ctrl);
+	/* SRs tied for ADCs and DACs. */
+	snd_soc_component_write(component, DA7218_SR,
+		      (fs << DA7218_SR_DAC_SHIFT) | (fs << DA7218_SR_ADC_SHIFT));
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops da7218_dai_ops = {
+	.hw_params	= da7218_hw_params,
+	.set_sysclk	= da7218_set_dai_sysclk,
+	.set_pll	= da7218_set_dai_pll,
+	.set_fmt	= da7218_set_dai_fmt,
+	.set_tdm_slot	= da7218_set_dai_tdm_slot,
+};
+
+#define DA7218_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver da7218_dai = {
+	.name = "da7218-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 4,	/* Only 2 channels of data */
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = DA7218_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 4,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = DA7218_FORMATS,
+	},
+	.ops = &da7218_dai_ops,
+	.symmetric_rates = 1,
+	.symmetric_channels = 1,
+	.symmetric_samplebits = 1,
+};
+
+
+/*
+ * HP Detect
+ */
+
+int da7218_hpldet(struct snd_soc_component *component, struct snd_soc_jack *jack)
+{
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+
+	if (da7218->dev_id == DA7217_DEV_ID)
+		return -EINVAL;
+
+	da7218->jack = jack;
+	snd_soc_component_update_bits(component, DA7218_HPLDET_JACK,
+			    DA7218_HPLDET_JACK_EN_MASK,
+			    jack ? DA7218_HPLDET_JACK_EN_MASK : 0);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(da7218_hpldet);
+
+static void da7218_micldet_irq(struct snd_soc_component *component)
+{
+	char *envp[] = {
+		"EVENT=MIC_LEVEL_DETECT",
+		NULL,
+	};
+
+	kobject_uevent_env(&component->dev->kobj, KOBJ_CHANGE, envp);
+}
+
+static void da7218_hpldet_irq(struct snd_soc_component *component)
+{
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	u8 jack_status;
+	int report;
+
+	jack_status = snd_soc_component_read32(component, DA7218_EVENT_STATUS);
+
+	if (jack_status & DA7218_HPLDET_JACK_STS_MASK)
+		report = SND_JACK_HEADPHONE;
+	else
+		report = 0;
+
+	snd_soc_jack_report(da7218->jack, report, SND_JACK_HEADPHONE);
+}
+
+/*
+ * IRQ
+ */
+
+static irqreturn_t da7218_irq_thread(int irq, void *data)
+{
+	struct snd_soc_component *component = data;
+	u8 status;
+
+	/* Read IRQ status reg */
+	status = snd_soc_component_read32(component, DA7218_EVENT);
+	if (!status)
+		return IRQ_NONE;
+
+	/* Mic level detect */
+	if (status & DA7218_LVL_DET_EVENT_MASK)
+		da7218_micldet_irq(component);
+
+	/* HP detect */
+	if (status & DA7218_HPLDET_JACK_EVENT_MASK)
+		da7218_hpldet_irq(component);
+
+	/* Clear interrupts */
+	snd_soc_component_write(component, DA7218_EVENT, status);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * DT
+ */
+
+static const struct of_device_id da7218_of_match[] = {
+	{ .compatible = "dlg,da7217", .data = (void *) DA7217_DEV_ID },
+	{ .compatible = "dlg,da7218", .data = (void *) DA7218_DEV_ID },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, da7218_of_match);
+
+static inline int da7218_of_get_id(struct device *dev)
+{
+	const struct of_device_id *id = of_match_device(da7218_of_match, dev);
+
+	if (id)
+		return (uintptr_t)id->data;
+	else
+		return -EINVAL;
+}
+
+static enum da7218_micbias_voltage
+	da7218_of_micbias_lvl(struct snd_soc_component *component, u32 val)
+{
+	switch (val) {
+	case 1200:
+		return DA7218_MICBIAS_1_2V;
+	case 1600:
+		return DA7218_MICBIAS_1_6V;
+	case 1800:
+		return DA7218_MICBIAS_1_8V;
+	case 2000:
+		return DA7218_MICBIAS_2_0V;
+	case 2200:
+		return DA7218_MICBIAS_2_2V;
+	case 2400:
+		return DA7218_MICBIAS_2_4V;
+	case 2600:
+		return DA7218_MICBIAS_2_6V;
+	case 2800:
+		return DA7218_MICBIAS_2_8V;
+	case 3000:
+		return DA7218_MICBIAS_3_0V;
+	default:
+		dev_warn(component->dev, "Invalid micbias level");
+		return DA7218_MICBIAS_1_6V;
+	}
+}
+
+static enum da7218_mic_amp_in_sel
+	da7218_of_mic_amp_in_sel(struct snd_soc_component *component, const char *str)
+{
+	if (!strcmp(str, "diff")) {
+		return DA7218_MIC_AMP_IN_SEL_DIFF;
+	} else if (!strcmp(str, "se_p")) {
+		return DA7218_MIC_AMP_IN_SEL_SE_P;
+	} else if (!strcmp(str, "se_n")) {
+		return DA7218_MIC_AMP_IN_SEL_SE_N;
+	} else {
+		dev_warn(component->dev, "Invalid mic input type selection");
+		return DA7218_MIC_AMP_IN_SEL_DIFF;
+	}
+}
+
+static enum da7218_dmic_data_sel
+	da7218_of_dmic_data_sel(struct snd_soc_component *component, const char *str)
+{
+	if (!strcmp(str, "lrise_rfall")) {
+		return DA7218_DMIC_DATA_LRISE_RFALL;
+	} else if (!strcmp(str, "lfall_rrise")) {
+		return DA7218_DMIC_DATA_LFALL_RRISE;
+	} else {
+		dev_warn(component->dev, "Invalid DMIC data type selection");
+		return DA7218_DMIC_DATA_LRISE_RFALL;
+	}
+}
+
+static enum da7218_dmic_samplephase
+	da7218_of_dmic_samplephase(struct snd_soc_component *component, const char *str)
+{
+	if (!strcmp(str, "on_clkedge")) {
+		return DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+	} else if (!strcmp(str, "between_clkedge")) {
+		return DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE;
+	} else {
+		dev_warn(component->dev, "Invalid DMIC sample phase");
+		return DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+	}
+}
+
+static enum da7218_dmic_clk_rate
+	da7218_of_dmic_clkrate(struct snd_soc_component *component, u32 val)
+{
+	switch (val) {
+	case 1500000:
+		return DA7218_DMIC_CLK_1_5MHZ;
+	case 3000000:
+		return DA7218_DMIC_CLK_3_0MHZ;
+	default:
+		dev_warn(component->dev, "Invalid DMIC clock rate");
+		return DA7218_DMIC_CLK_3_0MHZ;
+	}
+}
+
+static enum da7218_hpldet_jack_rate
+	da7218_of_jack_rate(struct snd_soc_component *component, u32 val)
+{
+	switch (val) {
+	case 5:
+		return DA7218_HPLDET_JACK_RATE_5US;
+	case 10:
+		return DA7218_HPLDET_JACK_RATE_10US;
+	case 20:
+		return DA7218_HPLDET_JACK_RATE_20US;
+	case 40:
+		return DA7218_HPLDET_JACK_RATE_40US;
+	case 80:
+		return DA7218_HPLDET_JACK_RATE_80US;
+	case 160:
+		return DA7218_HPLDET_JACK_RATE_160US;
+	case 320:
+		return DA7218_HPLDET_JACK_RATE_320US;
+	case 640:
+		return DA7218_HPLDET_JACK_RATE_640US;
+	default:
+		dev_warn(component->dev, "Invalid jack detect rate");
+		return DA7218_HPLDET_JACK_RATE_40US;
+	}
+}
+
+static enum da7218_hpldet_jack_debounce
+	da7218_of_jack_debounce(struct snd_soc_component *component, u32 val)
+{
+	switch (val) {
+	case 0:
+		return DA7218_HPLDET_JACK_DEBOUNCE_OFF;
+	case 2:
+		return DA7218_HPLDET_JACK_DEBOUNCE_2;
+	case 3:
+		return DA7218_HPLDET_JACK_DEBOUNCE_3;
+	case 4:
+		return DA7218_HPLDET_JACK_DEBOUNCE_4;
+	default:
+		dev_warn(component->dev, "Invalid jack debounce");
+		return DA7218_HPLDET_JACK_DEBOUNCE_2;
+	}
+}
+
+static enum da7218_hpldet_jack_thr
+	da7218_of_jack_thr(struct snd_soc_component *component, u32 val)
+{
+	switch (val) {
+	case 84:
+		return DA7218_HPLDET_JACK_THR_84PCT;
+	case 88:
+		return DA7218_HPLDET_JACK_THR_88PCT;
+	case 92:
+		return DA7218_HPLDET_JACK_THR_92PCT;
+	case 96:
+		return DA7218_HPLDET_JACK_THR_96PCT;
+	default:
+		dev_warn(component->dev, "Invalid jack threshold level");
+		return DA7218_HPLDET_JACK_THR_84PCT;
+	}
+}
+
+static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_component *component)
+{
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	struct device_node *np = component->dev->of_node;
+	struct device_node *hpldet_np;
+	struct da7218_pdata *pdata;
+	struct da7218_hpldet_pdata *hpldet_pdata;
+	const char *of_str;
+	u32 of_val32;
+
+	pdata = devm_kzalloc(component->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	if (of_property_read_u32(np, "dlg,micbias1-lvl-millivolt", &of_val32) >= 0)
+		pdata->micbias1_lvl = da7218_of_micbias_lvl(component, of_val32);
+	else
+		pdata->micbias1_lvl = DA7218_MICBIAS_1_6V;
+
+	if (of_property_read_u32(np, "dlg,micbias2-lvl-millivolt", &of_val32) >= 0)
+		pdata->micbias2_lvl = da7218_of_micbias_lvl(component, of_val32);
+	else
+		pdata->micbias2_lvl = DA7218_MICBIAS_1_6V;
+
+	if (!of_property_read_string(np, "dlg,mic1-amp-in-sel", &of_str))
+		pdata->mic1_amp_in_sel =
+			da7218_of_mic_amp_in_sel(component, of_str);
+	else
+		pdata->mic1_amp_in_sel = DA7218_MIC_AMP_IN_SEL_DIFF;
+
+	if (!of_property_read_string(np, "dlg,mic2-amp-in-sel", &of_str))
+		pdata->mic2_amp_in_sel =
+			da7218_of_mic_amp_in_sel(component, of_str);
+	else
+		pdata->mic2_amp_in_sel = DA7218_MIC_AMP_IN_SEL_DIFF;
+
+	if (!of_property_read_string(np, "dlg,dmic1-data-sel", &of_str))
+		pdata->dmic1_data_sel =	da7218_of_dmic_data_sel(component, of_str);
+	else
+		pdata->dmic1_data_sel =	DA7218_DMIC_DATA_LRISE_RFALL;
+
+	if (!of_property_read_string(np, "dlg,dmic1-samplephase", &of_str))
+		pdata->dmic1_samplephase =
+			da7218_of_dmic_samplephase(component, of_str);
+	else
+		pdata->dmic1_samplephase = DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+
+	if (of_property_read_u32(np, "dlg,dmic1-clkrate-hz", &of_val32) >= 0)
+		pdata->dmic1_clk_rate = da7218_of_dmic_clkrate(component, of_val32);
+	else
+		pdata->dmic1_clk_rate = DA7218_DMIC_CLK_3_0MHZ;
+
+	if (!of_property_read_string(np, "dlg,dmic2-data-sel", &of_str))
+		pdata->dmic2_data_sel = da7218_of_dmic_data_sel(component, of_str);
+	else
+		pdata->dmic2_data_sel =	DA7218_DMIC_DATA_LRISE_RFALL;
+
+	if (!of_property_read_string(np, "dlg,dmic2-samplephase", &of_str))
+		pdata->dmic2_samplephase =
+			da7218_of_dmic_samplephase(component, of_str);
+	else
+		pdata->dmic2_samplephase = DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+
+	if (of_property_read_u32(np, "dlg,dmic2-clkrate-hz", &of_val32) >= 0)
+		pdata->dmic2_clk_rate = da7218_of_dmic_clkrate(component, of_val32);
+	else
+		pdata->dmic2_clk_rate = DA7218_DMIC_CLK_3_0MHZ;
+
+	if (da7218->dev_id == DA7217_DEV_ID) {
+		if (of_property_read_bool(np, "dlg,hp-diff-single-supply"))
+			pdata->hp_diff_single_supply = true;
+	}
+
+	if (da7218->dev_id == DA7218_DEV_ID) {
+		hpldet_np = of_get_child_by_name(np, "da7218_hpldet");
+		if (!hpldet_np)
+			return pdata;
+
+		hpldet_pdata = devm_kzalloc(component->dev, sizeof(*hpldet_pdata),
+					    GFP_KERNEL);
+		if (!hpldet_pdata) {
+			of_node_put(hpldet_np);
+			return pdata;
+		}
+		pdata->hpldet_pdata = hpldet_pdata;
+
+		if (of_property_read_u32(hpldet_np, "dlg,jack-rate-us",
+					 &of_val32) >= 0)
+			hpldet_pdata->jack_rate =
+				da7218_of_jack_rate(component, of_val32);
+		else
+			hpldet_pdata->jack_rate = DA7218_HPLDET_JACK_RATE_40US;
+
+		if (of_property_read_u32(hpldet_np, "dlg,jack-debounce",
+					 &of_val32) >= 0)
+			hpldet_pdata->jack_debounce =
+				da7218_of_jack_debounce(component, of_val32);
+		else
+			hpldet_pdata->jack_debounce =
+				DA7218_HPLDET_JACK_DEBOUNCE_2;
+
+		if (of_property_read_u32(hpldet_np, "dlg,jack-threshold-pct",
+					 &of_val32) >= 0)
+			hpldet_pdata->jack_thr =
+				da7218_of_jack_thr(component, of_val32);
+		else
+			hpldet_pdata->jack_thr = DA7218_HPLDET_JACK_THR_84PCT;
+
+		if (of_property_read_bool(hpldet_np, "dlg,comp-inv"))
+			hpldet_pdata->comp_inv = true;
+
+		if (of_property_read_bool(hpldet_np, "dlg,hyst"))
+			hpldet_pdata->hyst = true;
+
+		if (of_property_read_bool(hpldet_np, "dlg,discharge"))
+			hpldet_pdata->discharge = true;
+
+		of_node_put(hpldet_np);
+	}
+
+	return pdata;
+}
+
+
+/*
+ * Codec driver functions
+ */
+
+static int da7218_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* Enable MCLK for transition to ON state */
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) {
+			if (da7218->mclk) {
+				ret = clk_prepare_enable(da7218->mclk);
+				if (ret) {
+					dev_err(component->dev, "Failed to enable mclk\n");
+					return ret;
+				}
+			}
+		}
+
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/* Master bias */
+			snd_soc_component_update_bits(component, DA7218_REFERENCES,
+					    DA7218_BIAS_EN_MASK,
+					    DA7218_BIAS_EN_MASK);
+
+			/* Internal LDO */
+			snd_soc_component_update_bits(component, DA7218_LDO_CTRL,
+					    DA7218_LDO_EN_MASK,
+					    DA7218_LDO_EN_MASK);
+		} else {
+			/* Remove MCLK */
+			if (da7218->mclk)
+				clk_disable_unprepare(da7218->mclk);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* Only disable if jack detection disabled */
+		if (!da7218->jack) {
+			/* Internal LDO */
+			snd_soc_component_update_bits(component, DA7218_LDO_CTRL,
+					    DA7218_LDO_EN_MASK, 0);
+
+			/* Master bias */
+			snd_soc_component_update_bits(component, DA7218_REFERENCES,
+					    DA7218_BIAS_EN_MASK, 0);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static const char *da7218_supply_names[DA7218_NUM_SUPPLIES] = {
+	[DA7218_SUPPLY_VDD] = "VDD",
+	[DA7218_SUPPLY_VDDMIC] = "VDDMIC",
+	[DA7218_SUPPLY_VDDIO] = "VDDIO",
+};
+
+static int da7218_handle_supplies(struct snd_soc_component *component)
+{
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	struct regulator *vddio;
+	u8 io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_2_5V_3_6V;
+	int i, ret;
+
+	/* Get required supplies */
+	for (i = 0; i < DA7218_NUM_SUPPLIES; ++i)
+		da7218->supplies[i].supply = da7218_supply_names[i];
+
+	ret = devm_regulator_bulk_get(component->dev, DA7218_NUM_SUPPLIES,
+				      da7218->supplies);
+	if (ret) {
+		dev_err(component->dev, "Failed to get supplies\n");
+		return ret;
+	}
+
+	/* Determine VDDIO voltage provided */
+	vddio = da7218->supplies[DA7218_SUPPLY_VDDIO].consumer;
+	ret = regulator_get_voltage(vddio);
+	if (ret < 1500000)
+		dev_warn(component->dev, "Invalid VDDIO voltage\n");
+	else if (ret < 2500000)
+		io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_1_5V_2_5V;
+
+	/* Enable main supplies */
+	ret = regulator_bulk_enable(DA7218_NUM_SUPPLIES, da7218->supplies);
+	if (ret) {
+		dev_err(component->dev, "Failed to enable supplies\n");
+		return ret;
+	}
+
+	/* Ensure device in active mode */
+	snd_soc_component_write(component, DA7218_SYSTEM_ACTIVE, DA7218_SYSTEM_ACTIVE_MASK);
+
+	/* Update IO voltage level range */
+	snd_soc_component_write(component, DA7218_IO_CTRL, io_voltage_lvl);
+
+	return 0;
+}
+
+static void da7218_handle_pdata(struct snd_soc_component *component)
+{
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	struct da7218_pdata *pdata = da7218->pdata;
+
+	if (pdata) {
+		u8 micbias_lvl = 0, dmic_cfg = 0;
+
+		/* Mic Bias voltages */
+		switch (pdata->micbias1_lvl) {
+		case DA7218_MICBIAS_1_2V:
+			micbias_lvl |= DA7218_MICBIAS_1_LP_MODE_MASK;
+			break;
+		case DA7218_MICBIAS_1_6V:
+		case DA7218_MICBIAS_1_8V:
+		case DA7218_MICBIAS_2_0V:
+		case DA7218_MICBIAS_2_2V:
+		case DA7218_MICBIAS_2_4V:
+		case DA7218_MICBIAS_2_6V:
+		case DA7218_MICBIAS_2_8V:
+		case DA7218_MICBIAS_3_0V:
+			micbias_lvl |= (pdata->micbias1_lvl <<
+					DA7218_MICBIAS_1_LEVEL_SHIFT);
+			break;
+		}
+
+		switch (pdata->micbias2_lvl) {
+		case DA7218_MICBIAS_1_2V:
+			micbias_lvl |= DA7218_MICBIAS_2_LP_MODE_MASK;
+			break;
+		case DA7218_MICBIAS_1_6V:
+		case DA7218_MICBIAS_1_8V:
+		case DA7218_MICBIAS_2_0V:
+		case DA7218_MICBIAS_2_2V:
+		case DA7218_MICBIAS_2_4V:
+		case DA7218_MICBIAS_2_6V:
+		case DA7218_MICBIAS_2_8V:
+		case DA7218_MICBIAS_3_0V:
+			micbias_lvl |= (pdata->micbias2_lvl <<
+					 DA7218_MICBIAS_2_LEVEL_SHIFT);
+			break;
+		}
+
+		snd_soc_component_write(component, DA7218_MICBIAS_CTRL, micbias_lvl);
+
+		/* Mic */
+		switch (pdata->mic1_amp_in_sel) {
+		case DA7218_MIC_AMP_IN_SEL_DIFF:
+		case DA7218_MIC_AMP_IN_SEL_SE_P:
+		case DA7218_MIC_AMP_IN_SEL_SE_N:
+			snd_soc_component_write(component, DA7218_MIC_1_SELECT,
+				      pdata->mic1_amp_in_sel);
+			break;
+		}
+
+		switch (pdata->mic2_amp_in_sel) {
+		case DA7218_MIC_AMP_IN_SEL_DIFF:
+		case DA7218_MIC_AMP_IN_SEL_SE_P:
+		case DA7218_MIC_AMP_IN_SEL_SE_N:
+			snd_soc_component_write(component, DA7218_MIC_2_SELECT,
+				      pdata->mic2_amp_in_sel);
+			break;
+		}
+
+		/* DMic */
+		switch (pdata->dmic1_data_sel) {
+		case DA7218_DMIC_DATA_LFALL_RRISE:
+		case DA7218_DMIC_DATA_LRISE_RFALL:
+			dmic_cfg |= (pdata->dmic1_data_sel <<
+				     DA7218_DMIC_1_DATA_SEL_SHIFT);
+			break;
+		}
+
+		switch (pdata->dmic1_samplephase) {
+		case DA7218_DMIC_SAMPLE_ON_CLKEDGE:
+		case DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE:
+			dmic_cfg |= (pdata->dmic1_samplephase <<
+				     DA7218_DMIC_1_SAMPLEPHASE_SHIFT);
+			break;
+		}
+
+		switch (pdata->dmic1_clk_rate) {
+		case DA7218_DMIC_CLK_3_0MHZ:
+		case DA7218_DMIC_CLK_1_5MHZ:
+			dmic_cfg |= (pdata->dmic1_clk_rate <<
+				     DA7218_DMIC_1_CLK_RATE_SHIFT);
+			break;
+		}
+
+		snd_soc_component_update_bits(component, DA7218_DMIC_1_CTRL,
+				    DA7218_DMIC_1_DATA_SEL_MASK |
+				    DA7218_DMIC_1_SAMPLEPHASE_MASK |
+				    DA7218_DMIC_1_CLK_RATE_MASK, dmic_cfg);
+
+		dmic_cfg = 0;
+		switch (pdata->dmic2_data_sel) {
+		case DA7218_DMIC_DATA_LFALL_RRISE:
+		case DA7218_DMIC_DATA_LRISE_RFALL:
+			dmic_cfg |= (pdata->dmic2_data_sel <<
+				     DA7218_DMIC_2_DATA_SEL_SHIFT);
+			break;
+		}
+
+		switch (pdata->dmic2_samplephase) {
+		case DA7218_DMIC_SAMPLE_ON_CLKEDGE:
+		case DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE:
+			dmic_cfg |= (pdata->dmic2_samplephase <<
+				     DA7218_DMIC_2_SAMPLEPHASE_SHIFT);
+			break;
+		}
+
+		switch (pdata->dmic2_clk_rate) {
+		case DA7218_DMIC_CLK_3_0MHZ:
+		case DA7218_DMIC_CLK_1_5MHZ:
+			dmic_cfg |= (pdata->dmic2_clk_rate <<
+				     DA7218_DMIC_2_CLK_RATE_SHIFT);
+			break;
+		}
+
+		snd_soc_component_update_bits(component, DA7218_DMIC_2_CTRL,
+				    DA7218_DMIC_2_DATA_SEL_MASK |
+				    DA7218_DMIC_2_SAMPLEPHASE_MASK |
+				    DA7218_DMIC_2_CLK_RATE_MASK, dmic_cfg);
+
+		/* DA7217 Specific */
+		if (da7218->dev_id == DA7217_DEV_ID) {
+			da7218->hp_single_supply =
+				pdata->hp_diff_single_supply;
+
+			if (da7218->hp_single_supply) {
+				snd_soc_component_write(component, DA7218_HP_DIFF_UNLOCK,
+					      DA7218_HP_DIFF_UNLOCK_VAL);
+				snd_soc_component_update_bits(component, DA7218_HP_DIFF_CTRL,
+						    DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK,
+						    DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK);
+			}
+		}
+
+		/* DA7218 Specific */
+		if ((da7218->dev_id == DA7218_DEV_ID) &&
+		    (pdata->hpldet_pdata)) {
+			struct da7218_hpldet_pdata *hpldet_pdata =
+				pdata->hpldet_pdata;
+			u8 hpldet_cfg = 0;
+
+			switch (hpldet_pdata->jack_rate) {
+			case DA7218_HPLDET_JACK_RATE_5US:
+			case DA7218_HPLDET_JACK_RATE_10US:
+			case DA7218_HPLDET_JACK_RATE_20US:
+			case DA7218_HPLDET_JACK_RATE_40US:
+			case DA7218_HPLDET_JACK_RATE_80US:
+			case DA7218_HPLDET_JACK_RATE_160US:
+			case DA7218_HPLDET_JACK_RATE_320US:
+			case DA7218_HPLDET_JACK_RATE_640US:
+				hpldet_cfg |=
+					(hpldet_pdata->jack_rate <<
+					 DA7218_HPLDET_JACK_RATE_SHIFT);
+				break;
+			}
+
+			switch (hpldet_pdata->jack_debounce) {
+			case DA7218_HPLDET_JACK_DEBOUNCE_OFF:
+			case DA7218_HPLDET_JACK_DEBOUNCE_2:
+			case DA7218_HPLDET_JACK_DEBOUNCE_3:
+			case DA7218_HPLDET_JACK_DEBOUNCE_4:
+				hpldet_cfg |=
+					(hpldet_pdata->jack_debounce <<
+					 DA7218_HPLDET_JACK_DEBOUNCE_SHIFT);
+				break;
+			}
+
+			switch (hpldet_pdata->jack_thr) {
+			case DA7218_HPLDET_JACK_THR_84PCT:
+			case DA7218_HPLDET_JACK_THR_88PCT:
+			case DA7218_HPLDET_JACK_THR_92PCT:
+			case DA7218_HPLDET_JACK_THR_96PCT:
+				hpldet_cfg |=
+					(hpldet_pdata->jack_thr <<
+					 DA7218_HPLDET_JACK_THR_SHIFT);
+				break;
+			}
+			snd_soc_component_update_bits(component, DA7218_HPLDET_JACK,
+					    DA7218_HPLDET_JACK_RATE_MASK |
+					    DA7218_HPLDET_JACK_DEBOUNCE_MASK |
+					    DA7218_HPLDET_JACK_THR_MASK,
+					    hpldet_cfg);
+
+			hpldet_cfg = 0;
+			if (hpldet_pdata->comp_inv)
+				hpldet_cfg |= DA7218_HPLDET_COMP_INV_MASK;
+
+			if (hpldet_pdata->hyst)
+				hpldet_cfg |= DA7218_HPLDET_HYST_EN_MASK;
+
+			if (hpldet_pdata->discharge)
+				hpldet_cfg |= DA7218_HPLDET_DISCHARGE_EN_MASK;
+
+			snd_soc_component_write(component, DA7218_HPLDET_CTRL, hpldet_cfg);
+		}
+	}
+}
+
+static int da7218_probe(struct snd_soc_component *component)
+{
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	/* Regulator configuration */
+	ret = da7218_handle_supplies(component);
+	if (ret)
+		return ret;
+
+	/* Handle DT/Platform data */
+	if (component->dev->of_node)
+		da7218->pdata = da7218_of_to_pdata(component);
+	else
+		da7218->pdata = dev_get_platdata(component->dev);
+
+	da7218_handle_pdata(component);
+
+	/* Check if MCLK provided, if not the clock is NULL */
+	da7218->mclk = devm_clk_get(component->dev, "mclk");
+	if (IS_ERR(da7218->mclk)) {
+		if (PTR_ERR(da7218->mclk) != -ENOENT) {
+			ret = PTR_ERR(da7218->mclk);
+			goto err_disable_reg;
+		} else {
+			da7218->mclk = NULL;
+		}
+	}
+
+	/* Default PC to free-running */
+	snd_soc_component_write(component, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK);
+
+	/*
+	 * Default Output Filter mixers to off otherwise DAPM will power
+	 * Mic to HP passthrough paths by default at startup.
+	 */
+	snd_soc_component_write(component, DA7218_DROUTING_OUTFILT_1L, 0);
+	snd_soc_component_write(component, DA7218_DROUTING_OUTFILT_1R, 0);
+
+	/* Default CP to normal load, power mode */
+	snd_soc_component_update_bits(component, DA7218_CP_CTRL,
+			    DA7218_CP_SMALL_SWITCH_FREQ_EN_MASK, 0);
+
+	/* Default gain ramping */
+	snd_soc_component_update_bits(component, DA7218_MIXIN_1_CTRL,
+			    DA7218_MIXIN_1_AMP_RAMP_EN_MASK,
+			    DA7218_MIXIN_1_AMP_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_MIXIN_2_CTRL,
+			    DA7218_MIXIN_2_AMP_RAMP_EN_MASK,
+			    DA7218_MIXIN_2_AMP_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_IN_1L_FILTER_CTRL,
+			    DA7218_IN_1L_RAMP_EN_MASK,
+			    DA7218_IN_1L_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_IN_1R_FILTER_CTRL,
+			    DA7218_IN_1R_RAMP_EN_MASK,
+			    DA7218_IN_1R_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_IN_2L_FILTER_CTRL,
+			    DA7218_IN_2L_RAMP_EN_MASK,
+			    DA7218_IN_2L_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_IN_2R_FILTER_CTRL,
+			    DA7218_IN_2R_RAMP_EN_MASK,
+			    DA7218_IN_2R_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_DGS_GAIN_CTRL,
+			    DA7218_DGS_RAMP_EN_MASK, DA7218_DGS_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_OUT_1L_FILTER_CTRL,
+			    DA7218_OUT_1L_RAMP_EN_MASK,
+			    DA7218_OUT_1L_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_OUT_1R_FILTER_CTRL,
+			    DA7218_OUT_1R_RAMP_EN_MASK,
+			    DA7218_OUT_1R_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_HP_L_CTRL,
+			    DA7218_HP_L_AMP_RAMP_EN_MASK,
+			    DA7218_HP_L_AMP_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7218_HP_R_CTRL,
+			    DA7218_HP_R_AMP_RAMP_EN_MASK,
+			    DA7218_HP_R_AMP_RAMP_EN_MASK);
+
+	/* Default infinite tone gen, start/stop by Kcontrol */
+	snd_soc_component_write(component, DA7218_TONE_GEN_CYCLES, DA7218_BEEP_CYCLES_MASK);
+
+	/* DA7217 specific config */
+	if (da7218->dev_id == DA7217_DEV_ID) {
+		snd_soc_component_update_bits(component, DA7218_HP_DIFF_CTRL,
+				    DA7218_HP_AMP_DIFF_MODE_EN_MASK,
+				    DA7218_HP_AMP_DIFF_MODE_EN_MASK);
+
+		/* Only DA7218 supports HP detect, mask off for DA7217 */
+		snd_soc_component_write(component, DA7218_EVENT_MASK,
+			      DA7218_HPLDET_JACK_EVENT_IRQ_MSK_MASK);
+	}
+
+	if (da7218->irq) {
+		ret = devm_request_threaded_irq(component->dev, da7218->irq, NULL,
+						da7218_irq_thread,
+						IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+						"da7218", component);
+		if (ret != 0) {
+			dev_err(component->dev, "Failed to request IRQ %d: %d\n",
+				da7218->irq, ret);
+			goto err_disable_reg;
+		}
+
+	}
+
+	return 0;
+
+err_disable_reg:
+	regulator_bulk_disable(DA7218_NUM_SUPPLIES, da7218->supplies);
+
+	return ret;
+}
+
+static void da7218_remove(struct snd_soc_component *component)
+{
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+
+	regulator_bulk_disable(DA7218_NUM_SUPPLIES, da7218->supplies);
+}
+
+#ifdef CONFIG_PM
+static int da7218_suspend(struct snd_soc_component *component)
+{
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+
+	da7218_set_bias_level(component, SND_SOC_BIAS_OFF);
+
+	/* Put device into standby mode if jack detection disabled */
+	if (!da7218->jack)
+		snd_soc_component_write(component, DA7218_SYSTEM_ACTIVE, 0);
+
+	return 0;
+}
+
+static int da7218_resume(struct snd_soc_component *component)
+{
+	struct da7218_priv *da7218 = snd_soc_component_get_drvdata(component);
+
+	/* Put device into active mode if previously moved to standby */
+	if (!da7218->jack)
+		snd_soc_component_write(component, DA7218_SYSTEM_ACTIVE,
+			      DA7218_SYSTEM_ACTIVE_MASK);
+
+	da7218_set_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+#else
+#define da7218_suspend NULL
+#define da7218_resume NULL
+#endif
+
+static const struct snd_soc_component_driver soc_component_dev_da7218 = {
+	.probe			= da7218_probe,
+	.remove			= da7218_remove,
+	.suspend		= da7218_suspend,
+	.resume			= da7218_resume,
+	.set_bias_level		= da7218_set_bias_level,
+	.controls		= da7218_snd_controls,
+	.num_controls		= ARRAY_SIZE(da7218_snd_controls),
+	.dapm_widgets		= da7218_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(da7218_dapm_widgets),
+	.dapm_routes		= da7218_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(da7218_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+
+/*
+ * Regmap configs
+ */
+
+static struct reg_default da7218_reg_defaults[] = {
+	{ DA7218_SYSTEM_ACTIVE, 0x00 },
+	{ DA7218_CIF_CTRL, 0x00 },
+	{ DA7218_SPARE1, 0x00 },
+	{ DA7218_SR, 0xAA },
+	{ DA7218_PC_COUNT, 0x02 },
+	{ DA7218_GAIN_RAMP_CTRL, 0x00 },
+	{ DA7218_CIF_TIMEOUT_CTRL, 0x01 },
+	{ DA7218_SYSTEM_MODES_INPUT, 0x00 },
+	{ DA7218_SYSTEM_MODES_OUTPUT, 0x00 },
+	{ DA7218_IN_1L_FILTER_CTRL, 0x00 },
+	{ DA7218_IN_1R_FILTER_CTRL, 0x00 },
+	{ DA7218_IN_2L_FILTER_CTRL, 0x00 },
+	{ DA7218_IN_2R_FILTER_CTRL, 0x00 },
+	{ DA7218_OUT_1L_FILTER_CTRL, 0x40 },
+	{ DA7218_OUT_1R_FILTER_CTRL, 0x40 },
+	{ DA7218_OUT_1_HPF_FILTER_CTRL, 0x80 },
+	{ DA7218_OUT_1_EQ_12_FILTER_CTRL, 0x77 },
+	{ DA7218_OUT_1_EQ_34_FILTER_CTRL, 0x77 },
+	{ DA7218_OUT_1_EQ_5_FILTER_CTRL, 0x07 },
+	{ DA7218_OUT_1_BIQ_5STAGE_CTRL, 0x40 },
+	{ DA7218_OUT_1_BIQ_5STAGE_DATA, 0x00 },
+	{ DA7218_OUT_1_BIQ_5STAGE_ADDR, 0x00 },
+	{ DA7218_MIXIN_1_CTRL, 0x48 },
+	{ DA7218_MIXIN_1_GAIN, 0x03 },
+	{ DA7218_MIXIN_2_CTRL, 0x48 },
+	{ DA7218_MIXIN_2_GAIN, 0x03 },
+	{ DA7218_ALC_CTRL1, 0x00 },
+	{ DA7218_ALC_CTRL2, 0x00 },
+	{ DA7218_ALC_CTRL3, 0x00 },
+	{ DA7218_ALC_NOISE, 0x3F },
+	{ DA7218_ALC_TARGET_MIN, 0x3F },
+	{ DA7218_ALC_TARGET_MAX, 0x00 },
+	{ DA7218_ALC_GAIN_LIMITS, 0xFF },
+	{ DA7218_ALC_ANA_GAIN_LIMITS, 0x71 },
+	{ DA7218_ALC_ANTICLIP_CTRL, 0x00 },
+	{ DA7218_AGS_ENABLE, 0x00 },
+	{ DA7218_AGS_TRIGGER, 0x09 },
+	{ DA7218_AGS_ATT_MAX, 0x00 },
+	{ DA7218_AGS_TIMEOUT, 0x00 },
+	{ DA7218_AGS_ANTICLIP_CTRL, 0x00 },
+	{ DA7218_ENV_TRACK_CTRL, 0x00 },
+	{ DA7218_LVL_DET_CTRL, 0x00 },
+	{ DA7218_LVL_DET_LEVEL, 0x7F },
+	{ DA7218_DGS_TRIGGER, 0x24 },
+	{ DA7218_DGS_ENABLE, 0x00 },
+	{ DA7218_DGS_RISE_FALL, 0x50 },
+	{ DA7218_DGS_SYNC_DELAY, 0xA3 },
+	{ DA7218_DGS_SYNC_DELAY2, 0x31 },
+	{ DA7218_DGS_SYNC_DELAY3, 0x11 },
+	{ DA7218_DGS_LEVELS, 0x01 },
+	{ DA7218_DGS_GAIN_CTRL, 0x74 },
+	{ DA7218_DROUTING_OUTDAI_1L, 0x01 },
+	{ DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN, 0x1C },
+	{ DA7218_DROUTING_OUTDAI_1R, 0x04 },
+	{ DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN, 0x1C },
+	{ DA7218_DROUTING_OUTFILT_1L, 0x01 },
+	{ DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN, 0x1C },
+	{ DA7218_DROUTING_OUTFILT_1R, 0x04 },
+	{ DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN, 0x1C },
+	{ DA7218_DROUTING_OUTDAI_2L, 0x04 },
+	{ DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN, 0x1C },
+	{ DA7218_DROUTING_OUTDAI_2R, 0x08 },
+	{ DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN, 0x1C },
+	{ DA7218_DAI_CTRL, 0x28 },
+	{ DA7218_DAI_TDM_CTRL, 0x40 },
+	{ DA7218_DAI_OFFSET_LOWER, 0x00 },
+	{ DA7218_DAI_OFFSET_UPPER, 0x00 },
+	{ DA7218_DAI_CLK_MODE, 0x01 },
+	{ DA7218_PLL_CTRL, 0x04 },
+	{ DA7218_PLL_FRAC_TOP, 0x00 },
+	{ DA7218_PLL_FRAC_BOT, 0x00 },
+	{ DA7218_PLL_INTEGER, 0x20 },
+	{ DA7218_DAC_NG_CTRL, 0x00 },
+	{ DA7218_DAC_NG_SETUP_TIME, 0x00 },
+	{ DA7218_DAC_NG_OFF_THRESH, 0x00 },
+	{ DA7218_DAC_NG_ON_THRESH, 0x00 },
+	{ DA7218_TONE_GEN_CFG2, 0x00 },
+	{ DA7218_TONE_GEN_FREQ1_L, 0x55 },
+	{ DA7218_TONE_GEN_FREQ1_U, 0x15 },
+	{ DA7218_TONE_GEN_FREQ2_L, 0x00 },
+	{ DA7218_TONE_GEN_FREQ2_U, 0x40 },
+	{ DA7218_TONE_GEN_CYCLES, 0x00 },
+	{ DA7218_TONE_GEN_ON_PER, 0x02 },
+	{ DA7218_TONE_GEN_OFF_PER, 0x01 },
+	{ DA7218_CP_CTRL, 0x60 },
+	{ DA7218_CP_DELAY, 0x11 },
+	{ DA7218_CP_VOL_THRESHOLD1, 0x0E },
+	{ DA7218_MIC_1_CTRL, 0x40 },
+	{ DA7218_MIC_1_GAIN, 0x01 },
+	{ DA7218_MIC_1_SELECT, 0x00 },
+	{ DA7218_MIC_2_CTRL, 0x40 },
+	{ DA7218_MIC_2_GAIN, 0x01 },
+	{ DA7218_MIC_2_SELECT, 0x00 },
+	{ DA7218_IN_1_HPF_FILTER_CTRL, 0x80 },
+	{ DA7218_IN_2_HPF_FILTER_CTRL, 0x80 },
+	{ DA7218_ADC_1_CTRL, 0x07 },
+	{ DA7218_ADC_2_CTRL, 0x07 },
+	{ DA7218_MIXOUT_L_CTRL, 0x00 },
+	{ DA7218_MIXOUT_L_GAIN, 0x03 },
+	{ DA7218_MIXOUT_R_CTRL, 0x00 },
+	{ DA7218_MIXOUT_R_GAIN, 0x03 },
+	{ DA7218_HP_L_CTRL, 0x40 },
+	{ DA7218_HP_L_GAIN, 0x3B },
+	{ DA7218_HP_R_CTRL, 0x40 },
+	{ DA7218_HP_R_GAIN, 0x3B },
+	{ DA7218_HP_DIFF_CTRL, 0x00 },
+	{ DA7218_HP_DIFF_UNLOCK, 0xC3 },
+	{ DA7218_HPLDET_JACK, 0x0B },
+	{ DA7218_HPLDET_CTRL, 0x00 },
+	{ DA7218_REFERENCES, 0x08 },
+	{ DA7218_IO_CTRL, 0x00 },
+	{ DA7218_LDO_CTRL, 0x00 },
+	{ DA7218_SIDETONE_CTRL, 0x40 },
+	{ DA7218_SIDETONE_IN_SELECT, 0x00 },
+	{ DA7218_SIDETONE_GAIN, 0x1C },
+	{ DA7218_DROUTING_ST_OUTFILT_1L, 0x01 },
+	{ DA7218_DROUTING_ST_OUTFILT_1R, 0x02 },
+	{ DA7218_SIDETONE_BIQ_3STAGE_DATA, 0x00 },
+	{ DA7218_SIDETONE_BIQ_3STAGE_ADDR, 0x00 },
+	{ DA7218_EVENT_MASK, 0x00 },
+	{ DA7218_DMIC_1_CTRL, 0x00 },
+	{ DA7218_DMIC_2_CTRL, 0x00 },
+	{ DA7218_IN_1L_GAIN, 0x6F },
+	{ DA7218_IN_1R_GAIN, 0x6F },
+	{ DA7218_IN_2L_GAIN, 0x6F },
+	{ DA7218_IN_2R_GAIN, 0x6F },
+	{ DA7218_OUT_1L_GAIN, 0x6F },
+	{ DA7218_OUT_1R_GAIN, 0x6F },
+	{ DA7218_MICBIAS_CTRL, 0x00 },
+	{ DA7218_MICBIAS_EN, 0x00 },
+};
+
+static bool da7218_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case DA7218_STATUS1:
+	case DA7218_SOFT_RESET:
+	case DA7218_SYSTEM_STATUS:
+	case DA7218_CALIB_CTRL:
+	case DA7218_CALIB_OFFSET_AUTO_M_1:
+	case DA7218_CALIB_OFFSET_AUTO_U_1:
+	case DA7218_CALIB_OFFSET_AUTO_M_2:
+	case DA7218_CALIB_OFFSET_AUTO_U_2:
+	case DA7218_PLL_STATUS:
+	case DA7218_PLL_REFOSC_CAL:
+	case DA7218_TONE_GEN_CFG1:
+	case DA7218_ADC_MODE:
+	case DA7218_HP_SNGL_CTRL:
+	case DA7218_HPLDET_TEST:
+	case DA7218_EVENT_STATUS:
+	case DA7218_EVENT:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config da7218_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = DA7218_MICBIAS_EN,
+	.reg_defaults = da7218_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(da7218_reg_defaults),
+	.volatile_reg = da7218_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+
+/*
+ * I2C layer
+ */
+
+static int da7218_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct da7218_priv *da7218;
+	int ret;
+
+	da7218 = devm_kzalloc(&i2c->dev, sizeof(*da7218), GFP_KERNEL);
+	if (!da7218)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, da7218);
+
+	if (i2c->dev.of_node)
+		da7218->dev_id = da7218_of_get_id(&i2c->dev);
+	else
+		da7218->dev_id = id->driver_data;
+
+	if ((da7218->dev_id != DA7217_DEV_ID) &&
+	    (da7218->dev_id != DA7218_DEV_ID)) {
+		dev_err(&i2c->dev, "Invalid device Id\n");
+		return -EINVAL;
+	}
+
+	da7218->irq = i2c->irq;
+
+	da7218->regmap = devm_regmap_init_i2c(i2c, &da7218_regmap_config);
+	if (IS_ERR(da7218->regmap)) {
+		ret = PTR_ERR(da7218->regmap);
+		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_da7218, &da7218_dai, 1);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register da7218 component: %d\n",
+			ret);
+	}
+	return ret;
+}
+
+static const struct i2c_device_id da7218_i2c_id[] = {
+	{ "da7217", DA7217_DEV_ID },
+	{ "da7218", DA7218_DEV_ID },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, da7218_i2c_id);
+
+static struct i2c_driver da7218_i2c_driver = {
+	.driver = {
+		.name = "da7218",
+		.of_match_table = of_match_ptr(da7218_of_match),
+	},
+	.probe		= da7218_i2c_probe,
+	.id_table	= da7218_i2c_id,
+};
+
+module_i2c_driver(da7218_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC DA7218 Codec driver");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da7218.h b/sound/soc/codecs/da7218.h
new file mode 100644
index 0000000..19e6cee
--- /dev/null
+++ b/sound/soc/codecs/da7218.h
@@ -0,0 +1,1415 @@
+/*
+ * da7218.h - DA7218 ALSA SoC Codec Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _DA7218_H
+#define _DA7218_H
+
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/da7218.h>
+
+
+/*
+ * Registers
+ */
+#define DA7218_SYSTEM_ACTIVE			0x0
+#define DA7218_CIF_CTRL				0x1
+#define DA7218_CHIP_ID1				0x4
+#define DA7218_CHIP_ID2				0x5
+#define DA7218_CHIP_REVISION			0x6
+#define DA7218_SPARE1				0x7
+#define DA7218_STATUS1				0x8
+#define DA7218_SOFT_RESET			0x9
+#define DA7218_SR				0xB
+#define DA7218_PC_COUNT				0xC
+#define DA7218_GAIN_RAMP_CTRL			0xD
+#define DA7218_CIF_TIMEOUT_CTRL			0x10
+#define DA7218_SYSTEM_MODES_INPUT		0x14
+#define DA7218_SYSTEM_MODES_OUTPUT		0x15
+#define DA7218_SYSTEM_STATUS			0x16
+#define DA7218_IN_1L_FILTER_CTRL		0x18
+#define DA7218_IN_1R_FILTER_CTRL		0x19
+#define DA7218_IN_2L_FILTER_CTRL		0x1A
+#define DA7218_IN_2R_FILTER_CTRL		0x1B
+#define DA7218_OUT_1L_FILTER_CTRL		0x20
+#define DA7218_OUT_1R_FILTER_CTRL		0x21
+#define DA7218_OUT_1_HPF_FILTER_CTRL		0x24
+#define DA7218_OUT_1_EQ_12_FILTER_CTRL		0x25
+#define DA7218_OUT_1_EQ_34_FILTER_CTRL		0x26
+#define DA7218_OUT_1_EQ_5_FILTER_CTRL		0x27
+#define DA7218_OUT_1_BIQ_5STAGE_CTRL		0x28
+#define DA7218_OUT_1_BIQ_5STAGE_DATA		0x29
+#define DA7218_OUT_1_BIQ_5STAGE_ADDR		0x2A
+#define DA7218_MIXIN_1_CTRL			0x2C
+#define DA7218_MIXIN_1_GAIN			0x2D
+#define DA7218_MIXIN_2_CTRL			0x2E
+#define DA7218_MIXIN_2_GAIN			0x2F
+#define DA7218_ALC_CTRL1			0x30
+#define DA7218_ALC_CTRL2			0x31
+#define DA7218_ALC_CTRL3			0x32
+#define DA7218_ALC_NOISE			0x33
+#define DA7218_ALC_TARGET_MIN			0x34
+#define DA7218_ALC_TARGET_MAX			0x35
+#define DA7218_ALC_GAIN_LIMITS			0x36
+#define DA7218_ALC_ANA_GAIN_LIMITS		0x37
+#define DA7218_ALC_ANTICLIP_CTRL		0x38
+#define DA7218_AGS_ENABLE			0x3C
+#define DA7218_AGS_TRIGGER			0x3D
+#define DA7218_AGS_ATT_MAX			0x3E
+#define DA7218_AGS_TIMEOUT			0x3F
+#define DA7218_AGS_ANTICLIP_CTRL		0x40
+#define DA7218_CALIB_CTRL			0x44
+#define DA7218_CALIB_OFFSET_AUTO_M_1		0x45
+#define DA7218_CALIB_OFFSET_AUTO_U_1		0x46
+#define DA7218_CALIB_OFFSET_AUTO_M_2		0x47
+#define DA7218_CALIB_OFFSET_AUTO_U_2		0x48
+#define DA7218_ENV_TRACK_CTRL			0x4C
+#define DA7218_LVL_DET_CTRL			0x50
+#define DA7218_LVL_DET_LEVEL			0x51
+#define DA7218_DGS_TRIGGER			0x54
+#define DA7218_DGS_ENABLE			0x55
+#define DA7218_DGS_RISE_FALL			0x56
+#define DA7218_DGS_SYNC_DELAY			0x57
+#define DA7218_DGS_SYNC_DELAY2			0x58
+#define DA7218_DGS_SYNC_DELAY3			0x59
+#define DA7218_DGS_LEVELS			0x5A
+#define DA7218_DGS_GAIN_CTRL			0x5B
+#define DA7218_DROUTING_OUTDAI_1L		0x5C
+#define DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN	0x5D
+#define DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN	0x5E
+#define DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN	0x5F
+#define DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN	0x60
+#define DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN	0x61
+#define DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN	0x62
+#define DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN	0x63
+#define DA7218_DROUTING_OUTDAI_1R		0x64
+#define DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN	0x65
+#define DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN	0x66
+#define DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN	0x67
+#define DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN	0x68
+#define DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN	0x69
+#define DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN	0x6A
+#define DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN	0x6B
+#define DA7218_DROUTING_OUTFILT_1L		0x6C
+#define DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN	0x6D
+#define DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN	0x6E
+#define DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN	0x6F
+#define DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN	0x70
+#define DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN	0x71
+#define DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN	0x72
+#define DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN	0x73
+#define DA7218_DROUTING_OUTFILT_1R		0x74
+#define DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN	0x75
+#define DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN	0x76
+#define DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN	0x77
+#define DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN	0x78
+#define DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN	0x79
+#define DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN	0x7A
+#define DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN	0x7B
+#define DA7218_DROUTING_OUTDAI_2L		0x7C
+#define DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN	0x7D
+#define DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN	0x7E
+#define DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN	0x7F
+#define DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN	0x80
+#define DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN	0x81
+#define DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN	0x82
+#define DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN	0x83
+#define DA7218_DROUTING_OUTDAI_2R		0x84
+#define DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN	0x85
+#define DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN	0x86
+#define DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN	0x87
+#define DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN	0x88
+#define DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN	0x89
+#define DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN	0x8A
+#define DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN	0x8B
+#define DA7218_DAI_CTRL				0x8C
+#define DA7218_DAI_TDM_CTRL			0x8D
+#define DA7218_DAI_OFFSET_LOWER			0x8E
+#define DA7218_DAI_OFFSET_UPPER			0x8F
+#define DA7218_DAI_CLK_MODE			0x90
+#define DA7218_PLL_CTRL				0x91
+#define DA7218_PLL_FRAC_TOP			0x92
+#define DA7218_PLL_FRAC_BOT			0x93
+#define DA7218_PLL_INTEGER			0x94
+#define DA7218_PLL_STATUS			0x95
+#define DA7218_PLL_REFOSC_CAL			0x98
+#define DA7218_DAC_NG_CTRL			0x9C
+#define DA7218_DAC_NG_SETUP_TIME		0x9D
+#define DA7218_DAC_NG_OFF_THRESH		0x9E
+#define DA7218_DAC_NG_ON_THRESH			0x9F
+#define DA7218_TONE_GEN_CFG1			0xA0
+#define DA7218_TONE_GEN_CFG2			0xA1
+#define DA7218_TONE_GEN_FREQ1_L			0xA2
+#define DA7218_TONE_GEN_FREQ1_U			0xA3
+#define DA7218_TONE_GEN_FREQ2_L			0xA4
+#define DA7218_TONE_GEN_FREQ2_U			0xA5
+#define DA7218_TONE_GEN_CYCLES			0xA6
+#define DA7218_TONE_GEN_ON_PER			0xA7
+#define DA7218_TONE_GEN_OFF_PER			0xA8
+#define DA7218_CP_CTRL				0xAC
+#define DA7218_CP_DELAY				0xAD
+#define DA7218_CP_VOL_THRESHOLD1		0xAE
+#define DA7218_MIC_1_CTRL			0xB4
+#define DA7218_MIC_1_GAIN			0xB5
+#define DA7218_MIC_1_SELECT			0xB7
+#define DA7218_MIC_2_CTRL			0xB8
+#define DA7218_MIC_2_GAIN			0xB9
+#define DA7218_MIC_2_SELECT			0xBB
+#define DA7218_IN_1_HPF_FILTER_CTRL		0xBC
+#define DA7218_IN_2_HPF_FILTER_CTRL		0xBD
+#define DA7218_ADC_1_CTRL			0xC0
+#define DA7218_ADC_2_CTRL			0xC1
+#define DA7218_ADC_MODE				0xC2
+#define DA7218_MIXOUT_L_CTRL			0xCC
+#define DA7218_MIXOUT_L_GAIN			0xCD
+#define DA7218_MIXOUT_R_CTRL			0xCE
+#define DA7218_MIXOUT_R_GAIN			0xCF
+#define DA7218_HP_L_CTRL			0xD0
+#define DA7218_HP_L_GAIN			0xD1
+#define DA7218_HP_R_CTRL			0xD2
+#define DA7218_HP_R_GAIN			0xD3
+#define DA7218_HP_SNGL_CTRL			0xD4
+#define DA7218_HP_DIFF_CTRL			0xD5
+#define DA7218_HP_DIFF_UNLOCK			0xD7
+#define DA7218_HPLDET_JACK			0xD8
+#define DA7218_HPLDET_CTRL			0xD9
+#define DA7218_HPLDET_TEST			0xDA
+#define DA7218_REFERENCES			0xDC
+#define DA7218_IO_CTRL				0xE0
+#define DA7218_LDO_CTRL				0xE1
+#define DA7218_SIDETONE_CTRL			0xE4
+#define DA7218_SIDETONE_IN_SELECT		0xE5
+#define DA7218_SIDETONE_GAIN			0xE6
+#define DA7218_DROUTING_ST_OUTFILT_1L		0xE8
+#define DA7218_DROUTING_ST_OUTFILT_1R		0xE9
+#define DA7218_SIDETONE_BIQ_3STAGE_DATA		0xEA
+#define DA7218_SIDETONE_BIQ_3STAGE_ADDR		0xEB
+#define DA7218_EVENT_STATUS			0xEC
+#define DA7218_EVENT				0xED
+#define DA7218_EVENT_MASK			0xEE
+#define DA7218_DMIC_1_CTRL			0xF0
+#define DA7218_DMIC_2_CTRL			0xF1
+#define DA7218_IN_1L_GAIN			0xF4
+#define DA7218_IN_1R_GAIN			0xF5
+#define DA7218_IN_2L_GAIN			0xF6
+#define DA7218_IN_2R_GAIN			0xF7
+#define DA7218_OUT_1L_GAIN			0xF8
+#define DA7218_OUT_1R_GAIN			0xF9
+#define DA7218_MICBIAS_CTRL			0xFC
+#define DA7218_MICBIAS_EN			0xFD
+
+
+/*
+ * Bit Fields
+ */
+
+#define DA7218_SWITCH_EN_MAX		0x1
+
+/* DA7218_SYSTEM_ACTIVE = 0x0 */
+#define DA7218_SYSTEM_ACTIVE_SHIFT	0
+#define DA7218_SYSTEM_ACTIVE_MASK	(0x1 << 0)
+
+/* DA7218_CIF_CTRL = 0x1 */
+#define DA7218_CIF_I2C_WRITE_MODE_SHIFT	0
+#define DA7218_CIF_I2C_WRITE_MODE_MASK	(0x1 << 0)
+
+/* DA7218_CHIP_ID1 = 0x4 */
+#define DA7218_CHIP_ID1_SHIFT	0
+#define DA7218_CHIP_ID1_MASK	(0xFF << 0)
+
+/* DA7218_CHIP_ID2 = 0x5 */
+#define DA7218_CHIP_ID2_SHIFT	0
+#define DA7218_CHIP_ID2_MASK	(0xFF << 0)
+
+/* DA7218_CHIP_REVISION = 0x6 */
+#define DA7218_CHIP_MINOR_SHIFT	0
+#define DA7218_CHIP_MINOR_MASK	(0xF << 0)
+#define DA7218_CHIP_MAJOR_SHIFT	4
+#define DA7218_CHIP_MAJOR_MASK	(0xF << 4)
+
+/* DA7218_SPARE1 = 0x7 */
+#define DA7218_SPARE1_SHIFT	0
+#define DA7218_SPARE1_MASK	(0xFF << 0)
+
+/* DA7218_STATUS1 = 0x8 */
+#define DA7218_STATUS_SPARE1_SHIFT	0
+#define DA7218_STATUS_SPARE1_MASK	(0xFF << 0)
+
+/* DA7218_SOFT_RESET = 0x9 */
+#define DA7218_CIF_REG_SOFT_RESET_SHIFT	7
+#define DA7218_CIF_REG_SOFT_RESET_MASK	(0x1 << 7)
+
+/* DA7218_SR = 0xB */
+#define DA7218_SR_ADC_SHIFT	0
+#define DA7218_SR_ADC_MASK	(0xF << 0)
+#define DA7218_SR_DAC_SHIFT	4
+#define DA7218_SR_DAC_MASK	(0xF << 4)
+#define DA7218_SR_8000		0x01
+#define DA7218_SR_11025		0x02
+#define DA7218_SR_12000		0x03
+#define DA7218_SR_16000		0x05
+#define DA7218_SR_22050		0x06
+#define DA7218_SR_24000		0x07
+#define DA7218_SR_32000		0x09
+#define DA7218_SR_44100		0x0A
+#define DA7218_SR_48000		0x0B
+#define DA7218_SR_88200		0x0E
+#define DA7218_SR_96000		0x0F
+
+/* DA7218_PC_COUNT = 0xC */
+#define DA7218_PC_FREERUN_SHIFT		0
+#define DA7218_PC_FREERUN_MASK		(0x1 << 0)
+#define DA7218_PC_RESYNC_AUTO_SHIFT	1
+#define DA7218_PC_RESYNC_AUTO_MASK	(0x1 << 1)
+
+/* DA7218_GAIN_RAMP_CTRL = 0xD */
+#define DA7218_GAIN_RAMP_RATE_SHIFT	0
+#define DA7218_GAIN_RAMP_RATE_MASK	(0x3 << 0)
+#define DA7218_GAIN_RAMP_RATE_MAX	4
+
+/* DA7218_CIF_TIMEOUT_CTRL = 0x10 */
+#define DA7218_I2C_TIMEOUT_EN_SHIFT	0
+#define DA7218_I2C_TIMEOUT_EN_MASK	(0x1 << 0)
+
+/* DA7218_SYSTEM_MODES_INPUT = 0x14 */
+#define DA7218_MODE_SUBMIT_SHIFT	0
+#define DA7218_MODE_SUBMIT_MASK		(0x1 << 0)
+#define DA7218_ADC_MODE_SHIFT		1
+#define DA7218_ADC_MODE_MASK		(0x7F << 1)
+
+/* DA7218_SYSTEM_MODES_OUTPUT = 0x15 */
+#define DA7218_MODE_SUBMIT_SHIFT	0
+#define DA7218_MODE_SUBMIT_MASK		(0x1 << 0)
+#define DA7218_DAC_MODE_SHIFT		1
+#define DA7218_DAC_MODE_MASK		(0x7F << 1)
+
+/* DA7218_SYSTEM_STATUS = 0x16 */
+#define DA7218_SC1_BUSY_SHIFT	0
+#define DA7218_SC1_BUSY_MASK	(0x1 << 0)
+#define DA7218_SC2_BUSY_SHIFT	1
+#define DA7218_SC2_BUSY_MASK	(0x1 << 1)
+
+/* DA7218_IN_1L_FILTER_CTRL = 0x18 */
+#define DA7218_IN_1L_RAMP_EN_SHIFT	5
+#define DA7218_IN_1L_RAMP_EN_MASK	(0x1 << 5)
+#define DA7218_IN_1L_MUTE_EN_SHIFT	6
+#define DA7218_IN_1L_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_IN_1L_FILTER_EN_SHIFT	7
+#define DA7218_IN_1L_FILTER_EN_MASK	(0x1 << 7)
+
+/* DA7218_IN_1R_FILTER_CTRL = 0x19 */
+#define DA7218_IN_1R_RAMP_EN_SHIFT	5
+#define DA7218_IN_1R_RAMP_EN_MASK	(0x1 << 5)
+#define DA7218_IN_1R_MUTE_EN_SHIFT	6
+#define DA7218_IN_1R_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_IN_1R_FILTER_EN_SHIFT	7
+#define DA7218_IN_1R_FILTER_EN_MASK	(0x1 << 7)
+
+/* DA7218_IN_2L_FILTER_CTRL = 0x1A */
+#define DA7218_IN_2L_RAMP_EN_SHIFT	5
+#define DA7218_IN_2L_RAMP_EN_MASK	(0x1 << 5)
+#define DA7218_IN_2L_MUTE_EN_SHIFT	6
+#define DA7218_IN_2L_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_IN_2L_FILTER_EN_SHIFT	7
+#define DA7218_IN_2L_FILTER_EN_MASK	(0x1 << 7)
+
+/* DA7218_IN_2R_FILTER_CTRL = 0x1B */
+#define DA7218_IN_2R_RAMP_EN_SHIFT	5
+#define DA7218_IN_2R_RAMP_EN_MASK	(0x1 << 5)
+#define DA7218_IN_2R_MUTE_EN_SHIFT	6
+#define DA7218_IN_2R_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_IN_2R_FILTER_EN_SHIFT	7
+#define DA7218_IN_2R_FILTER_EN_MASK	(0x1 << 7)
+
+/* DA7218_OUT_1L_FILTER_CTRL = 0x20 */
+#define DA7218_OUT_1L_BIQ_5STAGE_SEL_SHIFT	3
+#define DA7218_OUT_1L_BIQ_5STAGE_SEL_MASK	(0x1 << 3)
+#define DA7218_OUT_BIQ_5STAGE_SEL_MAX		2
+#define DA7218_OUT_1L_SUBRANGE_EN_SHIFT		4
+#define DA7218_OUT_1L_SUBRANGE_EN_MASK		(0x1 << 4)
+#define DA7218_OUT_1L_RAMP_EN_SHIFT		5
+#define DA7218_OUT_1L_RAMP_EN_MASK		(0x1 << 5)
+#define DA7218_OUT_1L_MUTE_EN_SHIFT		6
+#define DA7218_OUT_1L_MUTE_EN_MASK		(0x1 << 6)
+#define DA7218_OUT_1L_FILTER_EN_SHIFT		7
+#define DA7218_OUT_1L_FILTER_EN_MASK		(0x1 << 7)
+
+/* DA7218_OUT_1R_FILTER_CTRL = 0x21 */
+#define DA7218_OUT_1R_BIQ_5STAGE_SEL_SHIFT	3
+#define DA7218_OUT_1R_BIQ_5STAGE_SEL_MASK	(0x1 << 3)
+#define DA7218_OUT_1R_SUBRANGE_EN_SHIFT		4
+#define DA7218_OUT_1R_SUBRANGE_EN_MASK		(0x1 << 4)
+#define DA7218_OUT_1R_RAMP_EN_SHIFT		5
+#define DA7218_OUT_1R_RAMP_EN_MASK		(0x1 << 5)
+#define DA7218_OUT_1R_MUTE_EN_SHIFT		6
+#define DA7218_OUT_1R_MUTE_EN_MASK		(0x1 << 6)
+#define DA7218_OUT_1R_FILTER_EN_SHIFT		7
+#define DA7218_OUT_1R_FILTER_EN_MASK		(0x1 << 7)
+
+/* DA7218_OUT_1_HPF_FILTER_CTRL = 0x24 */
+#define DA7218_OUT_1_VOICE_HPF_CORNER_SHIFT	0
+#define DA7218_OUT_1_VOICE_HPF_CORNER_MASK	(0x7 << 0)
+#define DA7218_VOICE_HPF_CORNER_MAX		8
+#define DA7218_OUT_1_VOICE_EN_SHIFT		3
+#define DA7218_OUT_1_VOICE_EN_MASK		(0x1 << 3)
+#define DA7218_OUT_1_AUDIO_HPF_CORNER_SHIFT	4
+#define DA7218_OUT_1_AUDIO_HPF_CORNER_MASK	(0x3 << 4)
+#define DA7218_AUDIO_HPF_CORNER_MAX		4
+#define DA7218_OUT_1_HPF_EN_SHIFT		7
+#define DA7218_OUT_1_HPF_EN_MASK		(0x1 << 7)
+#define DA7218_HPF_MODE_SHIFT			0
+#define DA7218_HPF_DISABLED			((0x0 << 3) | (0x0 << 7))
+#define DA7218_HPF_AUDIO_EN			((0x0 << 3) | (0x1 << 7))
+#define DA7218_HPF_VOICE_EN			((0x1 << 3) | (0x1 << 7))
+#define DA7218_HPF_MODE_MASK			((0x1 << 3) | (0x1 << 7))
+#define DA7218_HPF_MODE_MAX			3
+
+/* DA7218_OUT_1_EQ_12_FILTER_CTRL = 0x25 */
+#define DA7218_OUT_1_EQ_BAND1_SHIFT	0
+#define DA7218_OUT_1_EQ_BAND1_MASK	(0xF << 0)
+#define DA7218_OUT_EQ_BAND_MAX		0xF
+#define DA7218_OUT_1_EQ_BAND2_SHIFT	4
+#define DA7218_OUT_1_EQ_BAND2_MASK	(0xF << 4)
+
+/* DA7218_OUT_1_EQ_34_FILTER_CTRL = 0x26 */
+#define DA7218_OUT_1_EQ_BAND3_SHIFT	0
+#define DA7218_OUT_1_EQ_BAND3_MASK	(0xF << 0)
+#define DA7218_OUT_1_EQ_BAND4_SHIFT	4
+#define DA7218_OUT_1_EQ_BAND4_MASK	(0xF << 4)
+
+/* DA7218_OUT_1_EQ_5_FILTER_CTRL = 0x27 */
+#define DA7218_OUT_1_EQ_BAND5_SHIFT	0
+#define DA7218_OUT_1_EQ_BAND5_MASK	(0xF << 0)
+#define DA7218_OUT_1_EQ_EN_SHIFT	7
+#define DA7218_OUT_1_EQ_EN_MASK		(0x1 << 7)
+
+/* DA7218_OUT_1_BIQ_5STAGE_CTRL = 0x28 */
+#define DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_SHIFT	6
+#define DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_SHIFT	7
+#define DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_MASK	(0x1 << 7)
+
+/* DA7218_OUT_1_BIQ_5STAGE_DATA = 0x29 */
+#define DA7218_OUT_1_BIQ_5STAGE_DATA_SHIFT	0
+#define DA7218_OUT_1_BIQ_5STAGE_DATA_MASK	(0xFF << 0)
+
+/* DA7218_OUT_1_BIQ_5STAGE_ADDR = 0x2A */
+#define DA7218_OUT_1_BIQ_5STAGE_ADDR_SHIFT	0
+#define DA7218_OUT_1_BIQ_5STAGE_ADDR_MASK	(0x3F << 0)
+#define DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE	50
+
+/* DA7218_MIXIN_1_CTRL = 0x2C */
+#define DA7218_MIXIN_1_MIX_SEL_SHIFT		3
+#define DA7218_MIXIN_1_MIX_SEL_MASK		(0x1 << 3)
+#define DA7218_MIXIN_1_AMP_ZC_EN_SHIFT		4
+#define DA7218_MIXIN_1_AMP_ZC_EN_MASK		(0x1 << 4)
+#define DA7218_MIXIN_1_AMP_RAMP_EN_SHIFT	5
+#define DA7218_MIXIN_1_AMP_RAMP_EN_MASK		(0x1 << 5)
+#define DA7218_MIXIN_1_AMP_MUTE_EN_SHIFT	6
+#define DA7218_MIXIN_1_AMP_MUTE_EN_MASK		(0x1 << 6)
+#define DA7218_MIXIN_1_AMP_EN_SHIFT		7
+#define DA7218_MIXIN_1_AMP_EN_MASK		(0x1 << 7)
+
+/* DA7218_MIXIN_1_GAIN = 0x2D */
+#define DA7218_MIXIN_1_AMP_GAIN_SHIFT	0
+#define DA7218_MIXIN_1_AMP_GAIN_MASK	(0xF << 0)
+#define DA7218_MIXIN_AMP_GAIN_MAX	0xF
+
+/* DA7218_MIXIN_2_CTRL = 0x2E */
+#define DA7218_MIXIN_2_MIX_SEL_SHIFT		3
+#define DA7218_MIXIN_2_MIX_SEL_MASK		(0x1 << 3)
+#define DA7218_MIXIN_2_AMP_ZC_EN_SHIFT		4
+#define DA7218_MIXIN_2_AMP_ZC_EN_MASK		(0x1 << 4)
+#define DA7218_MIXIN_2_AMP_RAMP_EN_SHIFT	5
+#define DA7218_MIXIN_2_AMP_RAMP_EN_MASK		(0x1 << 5)
+#define DA7218_MIXIN_2_AMP_MUTE_EN_SHIFT	6
+#define DA7218_MIXIN_2_AMP_MUTE_EN_MASK		(0x1 << 6)
+#define DA7218_MIXIN_2_AMP_EN_SHIFT		7
+#define DA7218_MIXIN_2_AMP_EN_MASK		(0x1 << 7)
+
+/* DA7218_MIXIN_2_GAIN = 0x2F */
+#define DA7218_MIXIN_2_AMP_GAIN_SHIFT	0
+#define DA7218_MIXIN_2_AMP_GAIN_MASK	(0xF << 0)
+
+/* DA7218_ALC_CTRL1 = 0x30 */
+#define DA7218_ALC_EN_SHIFT		0
+#define DA7218_ALC_EN_MASK		(0xF << 0)
+#define DA7218_ALC_CHAN1_L_EN_SHIFT	0
+#define DA7218_ALC_CHAN1_R_EN_SHIFT	1
+#define DA7218_ALC_CHAN2_L_EN_SHIFT	2
+#define DA7218_ALC_CHAN2_R_EN_SHIFT	3
+#define DA7218_ALC_SYNC_MODE_SHIFT	4
+#define DA7218_ALC_SYNC_MODE_MASK	(0xF << 4)
+#define DA7218_ALC_SYNC_MODE_CH1	(0x1 << 4)
+#define DA7218_ALC_SYNC_MODE_CH2	(0x4 << 4)
+
+/* DA7218_ALC_CTRL2 = 0x31 */
+#define DA7218_ALC_ATTACK_SHIFT		0
+#define DA7218_ALC_ATTACK_MASK		(0xF << 0)
+#define DA7218_ALC_ATTACK_MAX		13
+#define DA7218_ALC_RELEASE_SHIFT	4
+#define DA7218_ALC_RELEASE_MASK		(0xF << 4)
+#define DA7218_ALC_RELEASE_MAX		11
+
+/* DA7218_ALC_CTRL3 = 0x32 */
+#define DA7218_ALC_HOLD_SHIFT	0
+#define DA7218_ALC_HOLD_MASK	(0xF << 0)
+#define DA7218_ALC_HOLD_MAX	16
+
+/* DA7218_ALC_NOISE = 0x33 */
+#define DA7218_ALC_NOISE_SHIFT		0
+#define DA7218_ALC_NOISE_MASK		(0x3F << 0)
+#define DA7218_ALC_THRESHOLD_MAX	0x3F
+
+/* DA7218_ALC_TARGET_MIN = 0x34 */
+#define DA7218_ALC_THRESHOLD_MIN_SHIFT	0
+#define DA7218_ALC_THRESHOLD_MIN_MASK	(0x3F << 0)
+
+/* DA7218_ALC_TARGET_MAX = 0x35 */
+#define DA7218_ALC_THRESHOLD_MAX_SHIFT	0
+#define DA7218_ALC_THRESHOLD_MAX_MASK	(0x3F << 0)
+
+/* DA7218_ALC_GAIN_LIMITS = 0x36 */
+#define DA7218_ALC_ATTEN_MAX_SHIFT	0
+#define DA7218_ALC_ATTEN_MAX_MASK	(0xF << 0)
+#define DA7218_ALC_ATTEN_GAIN_MAX	0xF
+#define DA7218_ALC_GAIN_MAX_SHIFT	4
+#define DA7218_ALC_GAIN_MAX_MASK	(0xF << 4)
+
+/* DA7218_ALC_ANA_GAIN_LIMITS = 0x37 */
+#define DA7218_ALC_ANA_GAIN_MIN_SHIFT	0
+#define DA7218_ALC_ANA_GAIN_MIN_MASK	(0x7 << 0)
+#define DA7218_ALC_ANA_GAIN_MIN		0x1
+#define DA7218_ALC_ANA_GAIN_MAX		0x7
+#define DA7218_ALC_ANA_GAIN_MAX_SHIFT	4
+#define DA7218_ALC_ANA_GAIN_MAX_MASK	(0x7 << 4)
+
+/* DA7218_ALC_ANTICLIP_CTRL = 0x38 */
+#define DA7218_ALC_ANTICLIP_STEP_SHIFT	0
+#define DA7218_ALC_ANTICLIP_STEP_MASK	(0x3 << 0)
+#define DA7218_ALC_ANTICLIP_STEP_MAX	4
+#define DA7218_ALC_ANTICLIP_EN_SHIFT	7
+#define DA7218_ALC_ANTICLIP_EN_MASK	(0x1 << 7)
+
+/* DA7218_AGS_ENABLE = 0x3C */
+#define DA7218_AGS_ENABLE_SHIFT		0
+#define DA7218_AGS_ENABLE_MASK		(0x3 << 0)
+#define DA7218_AGS_ENABLE_CHAN1_SHIFT	0
+#define DA7218_AGS_ENABLE_CHAN2_SHIFT	1
+
+/* DA7218_AGS_TRIGGER = 0x3D */
+#define DA7218_AGS_TRIGGER_SHIFT	0
+#define DA7218_AGS_TRIGGER_MASK		(0xF << 0)
+#define DA7218_AGS_TRIGGER_MAX		0xF
+
+/* DA7218_AGS_ATT_MAX = 0x3E */
+#define DA7218_AGS_ATT_MAX_SHIFT	0
+#define DA7218_AGS_ATT_MAX_MASK		(0x7 << 0)
+#define DA7218_AGS_ATT_MAX_MAX		0x7
+
+/* DA7218_AGS_TIMEOUT = 0x3F */
+#define DA7218_AGS_TIMEOUT_EN_SHIFT	0
+#define DA7218_AGS_TIMEOUT_EN_MASK	(0x1 << 0)
+
+/* DA7218_AGS_ANTICLIP_CTRL = 0x40 */
+#define DA7218_AGS_ANTICLIP_EN_SHIFT	7
+#define DA7218_AGS_ANTICLIP_EN_MASK	(0x1 << 7)
+
+/* DA7218_CALIB_CTRL = 0x44 */
+#define DA7218_CALIB_OFFSET_EN_SHIFT	0
+#define DA7218_CALIB_OFFSET_EN_MASK	(0x1 << 0)
+#define DA7218_CALIB_AUTO_EN_SHIFT	2
+#define DA7218_CALIB_AUTO_EN_MASK	(0x1 << 2)
+#define DA7218_CALIB_OVERFLOW_SHIFT	3
+#define DA7218_CALIB_OVERFLOW_MASK	(0x1 << 3)
+
+/* DA7218_CALIB_OFFSET_AUTO_M_1 = 0x45 */
+#define DA7218_CALIB_OFFSET_AUTO_M_1_SHIFT	0
+#define DA7218_CALIB_OFFSET_AUTO_M_1_MASK	(0xFF << 0)
+
+/* DA7218_CALIB_OFFSET_AUTO_U_1 = 0x46 */
+#define DA7218_CALIB_OFFSET_AUTO_U_1_SHIFT	0
+#define DA7218_CALIB_OFFSET_AUTO_U_1_MASK	(0xF << 0)
+
+/* DA7218_CALIB_OFFSET_AUTO_M_2 = 0x47 */
+#define DA7218_CALIB_OFFSET_AUTO_M_2_SHIFT	0
+#define DA7218_CALIB_OFFSET_AUTO_M_2_MASK	(0xFF << 0)
+
+/* DA7218_CALIB_OFFSET_AUTO_U_2 = 0x48 */
+#define DA7218_CALIB_OFFSET_AUTO_U_2_SHIFT	0
+#define DA7218_CALIB_OFFSET_AUTO_U_2_MASK	(0xF << 0)
+
+/* DA7218_ENV_TRACK_CTRL = 0x4C */
+#define DA7218_INTEG_ATTACK_SHIFT	0
+#define DA7218_INTEG_ATTACK_MASK	(0x3 << 0)
+#define DA7218_INTEG_RELEASE_SHIFT	4
+#define DA7218_INTEG_RELEASE_MASK	(0x3 << 4)
+#define DA7218_INTEG_MAX		4
+
+/* DA7218_LVL_DET_CTRL = 0x50 */
+#define DA7218_LVL_DET_EN_SHIFT		0
+#define DA7218_LVL_DET_EN_MASK		(0xF << 0)
+#define DA7218_LVL_DET_EN_CHAN1L_SHIFT	0
+#define DA7218_LVL_DET_EN_CHAN1R_SHIFT	1
+#define DA7218_LVL_DET_EN_CHAN2L_SHIFT	2
+#define DA7218_LVL_DET_EN_CHAN2R_SHIFT	3
+
+/* DA7218_LVL_DET_LEVEL = 0x51 */
+#define DA7218_LVL_DET_LEVEL_SHIFT	0
+#define DA7218_LVL_DET_LEVEL_MASK	(0x7F << 0)
+#define DA7218_LVL_DET_LEVEL_MAX	0x7F
+
+/* DA7218_DGS_TRIGGER = 0x54 */
+#define DA7218_DGS_TRIGGER_LVL_SHIFT	0
+#define DA7218_DGS_TRIGGER_LVL_MASK	(0x3F << 0)
+#define DA7218_DGS_TRIGGER_MAX		0x3F
+
+/* DA7218_DGS_ENABLE = 0x55 */
+#define DA7218_DGS_ENABLE_SHIFT		0
+#define DA7218_DGS_ENABLE_MASK		(0x3 << 0)
+#define DA7218_DGS_ENABLE_L_SHIFT	0
+#define DA7218_DGS_ENABLE_R_SHIFT	1
+
+/* DA7218_DGS_RISE_FALL = 0x56 */
+#define DA7218_DGS_RISE_COEFF_SHIFT	0
+#define DA7218_DGS_RISE_COEFF_MASK	(0x7 << 0)
+#define DA7218_DGS_RISE_COEFF_MAX	7
+#define DA7218_DGS_FALL_COEFF_SHIFT	4
+#define DA7218_DGS_FALL_COEFF_MASK	(0x7 << 4)
+#define DA7218_DGS_FALL_COEFF_MAX	8
+
+/* DA7218_DGS_SYNC_DELAY = 0x57 */
+#define DA7218_DGS_SYNC_DELAY_SHIFT	0
+#define DA7218_DGS_SYNC_DELAY_MASK	(0xFF << 0)
+#define DA7218_DGS_SYNC_DELAY_MAX	0xFF
+
+/* DA7218_DGS_SYNC_DELAY2 = 0x58 */
+#define DA7218_DGS_SYNC_DELAY2_SHIFT	0
+#define DA7218_DGS_SYNC_DELAY2_MASK	(0xFF << 0)
+
+/* DA7218_DGS_SYNC_DELAY3 = 0x59 */
+#define DA7218_DGS_SYNC_DELAY3_SHIFT	0
+#define DA7218_DGS_SYNC_DELAY3_MASK	(0x7F << 0)
+#define DA7218_DGS_SYNC_DELAY3_MAX	0x7F
+
+/* DA7218_DGS_LEVELS = 0x5A */
+#define DA7218_DGS_ANTICLIP_LVL_SHIFT	0
+#define DA7218_DGS_ANTICLIP_LVL_MASK	(0x7 << 0)
+#define DA7218_DGS_ANTICLIP_LVL_MAX	0x7
+#define DA7218_DGS_SIGNAL_LVL_SHIFT	4
+#define DA7218_DGS_SIGNAL_LVL_MASK	(0xF << 4)
+#define DA7218_DGS_SIGNAL_LVL_MAX	0xF
+
+/* DA7218_DGS_GAIN_CTRL = 0x5B */
+#define DA7218_DGS_STEPS_SHIFT		0
+#define DA7218_DGS_STEPS_MASK		(0x1F << 0)
+#define DA7218_DGS_STEPS_MAX		0x1F
+#define DA7218_DGS_RAMP_EN_SHIFT	5
+#define DA7218_DGS_RAMP_EN_MASK		(0x1 << 5)
+#define DA7218_DGS_SUBR_EN_SHIFT	6
+#define DA7218_DGS_SUBR_EN_MASK		(0x1 << 6)
+
+/* DA7218_DROUTING_OUTDAI_1L = 0x5C */
+#define DA7218_OUTDAI_1L_SRC_SHIFT	0
+#define DA7218_OUTDAI_1L_SRC_MASK	(0x7F << 0)
+#define DA7218_DMIX_SRC_INFILT1L	0
+#define DA7218_DMIX_SRC_INFILT1R	1
+#define DA7218_DMIX_SRC_INFILT2L	2
+#define DA7218_DMIX_SRC_INFILT2R	3
+#define DA7218_DMIX_SRC_TONEGEN		4
+#define DA7218_DMIX_SRC_DAIL		5
+#define DA7218_DMIX_SRC_DAIR		6
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN = 0x5D */
+#define DA7218_OUTDAI_1L_INFILT_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1L_INFILT_1L_GAIN_MASK	(0x1F << 0)
+#define DA7218_DMIX_GAIN_MAX			0x1F
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN = 0x5E */
+#define DA7218_OUTDAI_1L_INFILT_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1L_INFILT_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN = 0x5F */
+#define DA7218_OUTDAI_1L_INFILT_2L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1L_INFILT_2L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN = 0x60 */
+#define DA7218_OUTDAI_1L_INFILT_2R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1L_INFILT_2R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN = 0x61 */
+#define DA7218_OUTDAI_1L_TONEGEN_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1L_TONEGEN_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN = 0x62 */
+#define DA7218_OUTDAI_1L_INDAI_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1L_INDAI_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN = 0x63 */
+#define DA7218_OUTDAI_1L_INDAI_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1L_INDAI_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DROUTING_OUTDAI_1R = 0x64 */
+#define DA7218_OUTDAI_1R_SRC_SHIFT	0
+#define DA7218_OUTDAI_1R_SRC_MASK	(0x7F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN = 0x65 */
+#define DA7218_OUTDAI_1R_INFILT_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1R_INFILT_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN = 0x66 */
+#define DA7218_OUTDAI_1R_INFILT_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1R_INFILT_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN = 0x67 */
+#define DA7218_OUTDAI_1R_INFILT_2L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1R_INFILT_2L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN = 0x68 */
+#define DA7218_OUTDAI_1R_INFILT_2R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1R_INFILT_2R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN = 0x69 */
+#define DA7218_OUTDAI_1R_TONEGEN_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1R_TONEGEN_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN = 0x6A */
+#define DA7218_OUTDAI_1R_INDAI_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1R_INDAI_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN = 0x6B */
+#define DA7218_OUTDAI_1R_INDAI_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1R_INDAI_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DROUTING_OUTFILT_1L = 0x6C */
+#define DA7218_OUTFILT_1L_SRC_SHIFT	0
+#define DA7218_OUTFILT_1L_SRC_MASK	(0x7F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN = 0x6D */
+#define DA7218_OUTFILT_1L_INFILT_1L_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1L_INFILT_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN = 0x6E */
+#define DA7218_OUTFILT_1L_INFILT_1R_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1L_INFILT_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN = 0x6F */
+#define DA7218_OUTFILT_1L_INFILT_2L_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1L_INFILT_2L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN = 0x70 */
+#define DA7218_OUTFILT_1L_INFILT_2R_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1L_INFILT_2R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN = 0x71 */
+#define DA7218_OUTFILT_1L_TONEGEN_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1L_TONEGEN_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN = 0x72 */
+#define DA7218_OUTFILT_1L_INDAI_1L_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1L_INDAI_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN = 0x73 */
+#define DA7218_OUTFILT_1L_INDAI_1R_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1L_INDAI_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DROUTING_OUTFILT_1R = 0x74 */
+#define DA7218_OUTFILT_1R_SRC_SHIFT	0
+#define DA7218_OUTFILT_1R_SRC_MASK	(0x7F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN = 0x75 */
+#define DA7218_OUTFILT_1R_INFILT_1L_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1R_INFILT_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN = 0x76 */
+#define DA7218_OUTFILT_1R_INFILT_1R_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1R_INFILT_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN = 0x77 */
+#define DA7218_OUTFILT_1R_INFILT_2L_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1R_INFILT_2L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN = 0x78 */
+#define DA7218_OUTFILT_1R_INFILT_2R_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1R_INFILT_2R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN = 0x79 */
+#define DA7218_OUTFILT_1R_TONEGEN_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1R_TONEGEN_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN = 0x7A */
+#define DA7218_OUTFILT_1R_INDAI_1L_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1R_INDAI_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN = 0x7B */
+#define DA7218_OUTFILT_1R_INDAI_1R_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1R_INDAI_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DROUTING_OUTDAI_2L = 0x7C */
+#define DA7218_OUTDAI_2L_SRC_SHIFT	0
+#define DA7218_OUTDAI_2L_SRC_MASK	(0x7F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN = 0x7D */
+#define DA7218_OUTDAI_2L_INFILT_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2L_INFILT_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN = 0x7E */
+#define DA7218_OUTDAI_2L_INFILT_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2L_INFILT_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN = 0x7F */
+#define DA7218_OUTDAI_2L_INFILT_2L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2L_INFILT_2L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN = 0x80 */
+#define DA7218_OUTDAI_2L_INFILT_2R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2L_INFILT_2R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN = 0x81 */
+#define DA7218_OUTDAI_2L_TONEGEN_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2L_TONEGEN_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN = 0x82 */
+#define DA7218_OUTDAI_2L_INDAI_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2L_INDAI_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN = 0x83 */
+#define DA7218_OUTDAI_2L_INDAI_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2L_INDAI_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DROUTING_OUTDAI_2R = 0x84 */
+#define DA7218_OUTDAI_2R_SRC_SHIFT	0
+#define DA7218_OUTDAI_2R_SRC_MASK	(0x7F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN = 0x85 */
+#define DA7218_OUTDAI_2R_INFILT_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2R_INFILT_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN = 0x86 */
+#define DA7218_OUTDAI_2R_INFILT_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2R_INFILT_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN = 0x87 */
+#define DA7218_OUTDAI_2R_INFILT_2L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2R_INFILT_2L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN = 0x88 */
+#define DA7218_OUTDAI_2R_INFILT_2R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2R_INFILT_2R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN = 0x89 */
+#define DA7218_OUTDAI_2R_TONEGEN_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2R_TONEGEN_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN = 0x8A */
+#define DA7218_OUTDAI_2R_INDAI_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2R_INDAI_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN = 0x8B */
+#define DA7218_OUTDAI_2R_INDAI_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2R_INDAI_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DAI_CTRL = 0x8C */
+#define DA7218_DAI_FORMAT_SHIFT		0
+#define DA7218_DAI_FORMAT_MASK		(0x3 << 0)
+#define DA7218_DAI_FORMAT_I2S		(0x0 << 0)
+#define DA7218_DAI_FORMAT_LEFT_J	(0x1 << 0)
+#define DA7218_DAI_FORMAT_RIGHT_J	(0x2 << 0)
+#define DA7218_DAI_FORMAT_DSP		(0x3 << 0)
+#define DA7218_DAI_WORD_LENGTH_SHIFT	2
+#define DA7218_DAI_WORD_LENGTH_MASK	(0x3 << 2)
+#define DA7218_DAI_WORD_LENGTH_S16_LE	(0x0 << 2)
+#define DA7218_DAI_WORD_LENGTH_S20_LE	(0x1 << 2)
+#define DA7218_DAI_WORD_LENGTH_S24_LE	(0x2 << 2)
+#define DA7218_DAI_WORD_LENGTH_S32_LE	(0x3 << 2)
+#define DA7218_DAI_CH_NUM_SHIFT		4
+#define DA7218_DAI_CH_NUM_MASK		(0x7 << 4)
+#define DA7218_DAI_CH_NUM_MAX		4
+#define DA7218_DAI_EN_SHIFT		7
+#define DA7218_DAI_EN_MASK		(0x1 << 7)
+
+/* DA7218_DAI_TDM_CTRL = 0x8D */
+#define DA7218_DAI_TDM_CH_EN_SHIFT	0
+#define DA7218_DAI_TDM_CH_EN_MASK	(0xF << 0)
+#define DA7218_DAI_TDM_MAX_SLOTS	4
+#define DA7218_DAI_OE_SHIFT		6
+#define DA7218_DAI_OE_MASK		(0x1 << 6)
+#define DA7218_DAI_TDM_MODE_EN_SHIFT	7
+#define DA7218_DAI_TDM_MODE_EN_MASK	(0x1 << 7)
+
+/* DA7218_DAI_OFFSET_LOWER = 0x8E */
+#define DA7218_DAI_OFFSET_LOWER_SHIFT	0
+#define DA7218_DAI_OFFSET_LOWER_MASK	(0xFF << 0)
+
+/* DA7218_DAI_OFFSET_UPPER = 0x8F */
+#define DA7218_DAI_OFFSET_UPPER_SHIFT	0
+#define DA7218_DAI_OFFSET_UPPER_MASK	(0x7 << 0)
+
+/* DA7218_DAI_CLK_MODE = 0x90 */
+#define DA7218_DAI_BCLKS_PER_WCLK_SHIFT	0
+#define DA7218_DAI_BCLKS_PER_WCLK_MASK	(0x3 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_32	(0x0 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_64	(0x1 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_128	(0x2 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_256	(0x3 << 0)
+#define DA7218_DAI_CLK_POL_SHIFT	2
+#define DA7218_DAI_CLK_POL_MASK		(0x1 << 2)
+#define DA7218_DAI_CLK_POL_INV		(0x1 << 2)
+#define DA7218_DAI_WCLK_POL_SHIFT	3
+#define DA7218_DAI_WCLK_POL_MASK	(0x1 << 3)
+#define DA7218_DAI_WCLK_POL_INV		(0x1 << 3)
+#define DA7218_DAI_WCLK_TRI_STATE_SHIFT	4
+#define DA7218_DAI_WCLK_TRI_STATE_MASK	(0x1 << 4)
+#define DA7218_DAI_CLK_EN_SHIFT		7
+#define DA7218_DAI_CLK_EN_MASK		(0x1 << 7)
+
+/* DA7218_PLL_CTRL = 0x91 */
+#define DA7218_PLL_INDIV_SHIFT		0
+#define DA7218_PLL_INDIV_MASK		(0x7 << 0)
+#define DA7218_PLL_INDIV_2_TO_4_5_MHZ	(0x0 << 0)
+#define DA7218_PLL_INDIV_4_5_TO_9_MHZ	(0x1 << 0)
+#define DA7218_PLL_INDIV_9_TO_18_MHZ	(0x2 << 0)
+#define DA7218_PLL_INDIV_18_TO_36_MHZ	(0x3 << 0)
+#define DA7218_PLL_INDIV_36_TO_54_MHZ	(0x4 << 0)
+#define DA7218_PLL_MCLK_SQR_EN_SHIFT	4
+#define DA7218_PLL_MCLK_SQR_EN_MASK	(0x1 << 4)
+#define DA7218_PLL_MODE_SHIFT		6
+#define DA7218_PLL_MODE_MASK		(0x3 << 6)
+#define DA7218_PLL_MODE_BYPASS		(0x0 << 6)
+#define DA7218_PLL_MODE_NORMAL		(0x1 << 6)
+#define DA7218_PLL_MODE_SRM		(0x2 << 6)
+
+/* DA7218_PLL_FRAC_TOP = 0x92 */
+#define DA7218_PLL_FBDIV_FRAC_TOP_SHIFT	0
+#define DA7218_PLL_FBDIV_FRAC_TOP_MASK	(0x1F << 0)
+
+/* DA7218_PLL_FRAC_BOT = 0x93 */
+#define DA7218_PLL_FBDIV_FRAC_BOT_SHIFT	0
+#define DA7218_PLL_FBDIV_FRAC_BOT_MASK	(0xFF << 0)
+
+/* DA7218_PLL_INTEGER = 0x94 */
+#define DA7218_PLL_FBDIV_INTEGER_SHIFT	0
+#define DA7218_PLL_FBDIV_INTEGER_MASK	(0x7F << 0)
+
+/* DA7218_PLL_STATUS = 0x95 */
+#define DA7218_PLL_SRM_STATUS_SHIFT	0
+#define DA7218_PLL_SRM_STATUS_MASK	(0xFF << 0)
+#define DA7218_PLL_SRM_STATUS_SRM_LOCK	(0x1 << 7)
+
+/* DA7218_PLL_REFOSC_CAL = 0x98 */
+#define DA7218_PLL_REFOSC_CAL_CTRL_SHIFT	0
+#define DA7218_PLL_REFOSC_CAL_CTRL_MASK		(0x1F << 0)
+#define DA7218_PLL_REFOSC_CAL_START_SHIFT	6
+#define DA7218_PLL_REFOSC_CAL_START_MASK	(0x1 << 6)
+#define DA7218_PLL_REFOSC_CAL_EN_SHIFT		7
+#define DA7218_PLL_REFOSC_CAL_EN_MASK		(0x1 << 7)
+
+/* DA7218_DAC_NG_CTRL = 0x9C */
+#define DA7218_DAC_NG_EN_SHIFT	7
+#define DA7218_DAC_NG_EN_MASK	(0x1 << 7)
+
+/* DA7218_DAC_NG_SETUP_TIME = 0x9D */
+#define DA7218_DAC_NG_SETUP_TIME_SHIFT	0
+#define DA7218_DAC_NG_SETUP_TIME_MASK	(0x3 << 0)
+#define DA7218_DAC_NG_SETUP_TIME_MAX	4
+#define DA7218_DAC_NG_RAMPUP_RATE_SHIFT	2
+#define DA7218_DAC_NG_RAMPUP_RATE_MASK	(0x1 << 2)
+#define DA7218_DAC_NG_RAMPUP_RATE_MAX	2
+#define DA7218_DAC_NG_RAMPDN_RATE_SHIFT	3
+#define DA7218_DAC_NG_RAMPDN_RATE_MASK	(0x1 << 3)
+#define DA7218_DAC_NG_RAMPDN_RATE_MAX	2
+
+/* DA7218_DAC_NG_OFF_THRESH = 0x9E */
+#define DA7218_DAC_NG_OFF_THRESHOLD_SHIFT	0
+#define DA7218_DAC_NG_OFF_THRESHOLD_MASK	(0x7 << 0)
+#define DA7218_DAC_NG_THRESHOLD_MAX		0x7
+
+/* DA7218_DAC_NG_ON_THRESH = 0x9F */
+#define DA7218_DAC_NG_ON_THRESHOLD_SHIFT	0
+#define DA7218_DAC_NG_ON_THRESHOLD_MASK		(0x7 << 0)
+
+/* DA7218_TONE_GEN_CFG1 = 0xA0 */
+#define DA7218_DTMF_REG_SHIFT		0
+#define DA7218_DTMF_REG_MASK		(0xF << 0)
+#define DA7218_DTMF_REG_MAX		16
+#define DA7218_DTMF_EN_SHIFT		4
+#define DA7218_DTMF_EN_MASK		(0x1 << 4)
+#define DA7218_START_STOPN_SHIFT	7
+#define DA7218_START_STOPN_MASK		(0x1 << 7)
+
+/* DA7218_TONE_GEN_CFG2 = 0xA1 */
+#define DA7218_SWG_SEL_SHIFT	0
+#define DA7218_SWG_SEL_MASK	(0x3 << 0)
+#define DA7218_SWG_SEL_MAX	4
+
+/* DA7218_TONE_GEN_FREQ1_L = 0xA2 */
+#define DA7218_FREQ1_L_SHIFT	0
+#define DA7218_FREQ1_L_MASK	(0xFF << 0)
+#define DA7218_FREQ_MAX		0xFFFF
+
+/* DA7218_TONE_GEN_FREQ1_U = 0xA3 */
+#define DA7218_FREQ1_U_SHIFT	0
+#define DA7218_FREQ1_U_MASK	(0xFF << 0)
+
+/* DA7218_TONE_GEN_FREQ2_L = 0xA4 */
+#define DA7218_FREQ2_L_SHIFT	0
+#define DA7218_FREQ2_L_MASK	(0xFF << 0)
+
+/* DA7218_TONE_GEN_FREQ2_U = 0xA5 */
+#define DA7218_FREQ2_U_SHIFT	0
+#define DA7218_FREQ2_U_MASK	(0xFF << 0)
+
+/* DA7218_TONE_GEN_CYCLES = 0xA6 */
+#define DA7218_BEEP_CYCLES_SHIFT	0
+#define DA7218_BEEP_CYCLES_MASK		(0x7 << 0)
+
+/* DA7218_TONE_GEN_ON_PER = 0xA7 */
+#define DA7218_BEEP_ON_PER_SHIFT	0
+#define DA7218_BEEP_ON_PER_MASK		(0x3F << 0)
+
+/* DA7218_TONE_GEN_OFF_PER = 0xA8 */
+#define DA7218_BEEP_OFF_PER_SHIFT	0
+#define DA7218_BEEP_OFF_PER_MASK	(0x3F << 0)
+#define DA7218_BEEP_ON_OFF_MAX		0x3F
+
+/* DA7218_CP_CTRL = 0xAC */
+#define DA7218_CP_MOD_SHIFT			2
+#define DA7218_CP_MOD_MASK			(0x3 << 2)
+#define DA7218_CP_MCHANGE_SHIFT			4
+#define DA7218_CP_MCHANGE_MASK			(0x3 << 4)
+#define DA7218_CP_MCHANGE_REL_MASK		0x3
+#define DA7218_CP_MCHANGE_MAX			3
+#define DA7218_CP_MCHANGE_LARGEST_VOL		0x1
+#define DA7218_CP_MCHANGE_DAC_VOL		0x2
+#define DA7218_CP_MCHANGE_SIG_MAG		0x3
+#define DA7218_CP_SMALL_SWITCH_FREQ_EN_SHIFT	6
+#define DA7218_CP_SMALL_SWITCH_FREQ_EN_MASK	(0x1 << 6)
+#define DA7218_CP_EN_SHIFT			7
+#define DA7218_CP_EN_MASK			(0x1 << 7)
+
+/* DA7218_CP_DELAY = 0xAD */
+#define DA7218_CP_FCONTROL_SHIFT	0
+#define DA7218_CP_FCONTROL_MASK		(0x7 << 0)
+#define DA7218_CP_FCONTROL_MAX		6
+#define DA7218_CP_TAU_DELAY_SHIFT	3
+#define DA7218_CP_TAU_DELAY_MASK	(0x7 << 3)
+#define DA7218_CP_TAU_DELAY_MAX		8
+
+/* DA7218_CP_VOL_THRESHOLD1 = 0xAE */
+#define DA7218_CP_THRESH_VDD2_SHIFT	0
+#define DA7218_CP_THRESH_VDD2_MASK	(0x3F << 0)
+#define DA7218_CP_THRESH_VDD2_MAX	0x3F
+
+/* DA7218_MIC_1_CTRL = 0xB4 */
+#define DA7218_MIC_1_AMP_MUTE_EN_SHIFT	6
+#define DA7218_MIC_1_AMP_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_MIC_1_AMP_EN_SHIFT	7
+#define DA7218_MIC_1_AMP_EN_MASK	(0x1 << 7)
+
+/* DA7218_MIC_1_GAIN = 0xB5 */
+#define DA7218_MIC_1_AMP_GAIN_SHIFT	0
+#define DA7218_MIC_1_AMP_GAIN_MASK	(0x7 << 0)
+#define DA7218_MIC_AMP_GAIN_MAX		0x7
+
+/* DA7218_MIC_1_SELECT = 0xB7 */
+#define DA7218_MIC_1_AMP_IN_SEL_SHIFT	0
+#define DA7218_MIC_1_AMP_IN_SEL_MASK	(0x3 << 0)
+
+/* DA7218_MIC_2_CTRL = 0xB8 */
+#define DA7218_MIC_2_AMP_MUTE_EN_SHIFT	6
+#define DA7218_MIC_2_AMP_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_MIC_2_AMP_EN_SHIFT	7
+#define DA7218_MIC_2_AMP_EN_MASK	(0x1 << 7)
+
+/* DA7218_MIC_2_GAIN = 0xB9 */
+#define DA7218_MIC_2_AMP_GAIN_SHIFT	0
+#define DA7218_MIC_2_AMP_GAIN_MASK	(0x7 << 0)
+
+/* DA7218_MIC_2_SELECT = 0xBB */
+#define DA7218_MIC_2_AMP_IN_SEL_SHIFT	0
+#define DA7218_MIC_2_AMP_IN_SEL_MASK	(0x3 << 0)
+
+/* DA7218_IN_1_HPF_FILTER_CTRL = 0xBC */
+#define DA7218_IN_1_VOICE_HPF_CORNER_SHIFT	0
+#define DA7218_IN_1_VOICE_HPF_CORNER_MASK	(0x7 << 0)
+#define DA7218_IN_VOICE_HPF_CORNER_MAX		8
+#define DA7218_IN_1_VOICE_EN_SHIFT		3
+#define DA7218_IN_1_VOICE_EN_MASK		(0x1 << 3)
+#define DA7218_IN_1_AUDIO_HPF_CORNER_SHIFT	4
+#define DA7218_IN_1_AUDIO_HPF_CORNER_MASK	(0x3 << 4)
+#define DA7218_IN_1_HPF_EN_SHIFT		7
+#define DA7218_IN_1_HPF_EN_MASK			(0x1 << 7)
+
+/* DA7218_IN_2_HPF_FILTER_CTRL = 0xBD */
+#define DA7218_IN_2_VOICE_HPF_CORNER_SHIFT	0
+#define DA7218_IN_2_VOICE_HPF_CORNER_MASK	(0x7 << 0)
+#define DA7218_IN_2_VOICE_EN_SHIFT		3
+#define DA7218_IN_2_VOICE_EN_MASK		(0x1 << 3)
+#define DA7218_IN_2_AUDIO_HPF_CORNER_SHIFT	4
+#define DA7218_IN_2_AUDIO_HPF_CORNER_MASK	(0x3 << 4)
+#define DA7218_IN_2_HPF_EN_SHIFT		7
+#define DA7218_IN_2_HPF_EN_MASK			(0x1 << 7)
+
+/* DA7218_ADC_1_CTRL = 0xC0 */
+#define DA7218_ADC_1_AAF_EN_SHIFT	2
+#define DA7218_ADC_1_AAF_EN_MASK	(0x1 << 2)
+
+/* DA7218_ADC_2_CTRL = 0xC1 */
+#define DA7218_ADC_2_AAF_EN_SHIFT	2
+#define DA7218_ADC_2_AAF_EN_MASK	(0x1 << 2)
+
+/* DA7218_ADC_MODE = 0xC2 */
+#define DA7218_ADC_LP_MODE_SHIFT		0
+#define DA7218_ADC_LP_MODE_MASK			(0x1 << 0)
+#define DA7218_ADC_LVLDET_MODE_SHIFT		1
+#define DA7218_ADC_LVLDET_MODE_MASK		(0x1 << 1)
+#define DA7218_ADC_LVLDET_AUTO_EXIT_SHIFT	2
+#define DA7218_ADC_LVLDET_AUTO_EXIT_MASK	(0x1 << 2)
+
+/* DA7218_MIXOUT_L_CTRL = 0xCC */
+#define DA7218_MIXOUT_L_AMP_EN_SHIFT	7
+#define DA7218_MIXOUT_L_AMP_EN_MASK	(0x1 << 7)
+
+/* DA7218_MIXOUT_L_GAIN = 0xCD */
+#define DA7218_MIXOUT_L_AMP_GAIN_SHIFT	0
+#define DA7218_MIXOUT_L_AMP_GAIN_MASK	(0x3 << 0)
+#define DA7218_MIXOUT_AMP_GAIN_MIN	0x1
+#define DA7218_MIXOUT_AMP_GAIN_MAX	0x3
+
+/* DA7218_MIXOUT_R_CTRL = 0xCE */
+#define DA7218_MIXOUT_R_AMP_EN_SHIFT	7
+#define DA7218_MIXOUT_R_AMP_EN_MASK	(0x1 << 7)
+
+/* DA7218_MIXOUT_R_GAIN = 0xCF */
+#define DA7218_MIXOUT_R_AMP_GAIN_SHIFT	0
+#define DA7218_MIXOUT_R_AMP_GAIN_MASK	(0x3 << 0)
+
+/* DA7218_HP_L_CTRL = 0xD0 */
+#define DA7218_HP_L_AMP_MIN_GAIN_EN_SHIFT	2
+#define DA7218_HP_L_AMP_MIN_GAIN_EN_MASK	(0x1 << 2)
+#define DA7218_HP_L_AMP_OE_SHIFT		3
+#define DA7218_HP_L_AMP_OE_MASK			(0x1 << 3)
+#define DA7218_HP_L_AMP_ZC_EN_SHIFT		4
+#define DA7218_HP_L_AMP_ZC_EN_MASK		(0x1 << 4)
+#define DA7218_HP_L_AMP_RAMP_EN_SHIFT		5
+#define DA7218_HP_L_AMP_RAMP_EN_MASK		(0x1 << 5)
+#define DA7218_HP_L_AMP_MUTE_EN_SHIFT		6
+#define DA7218_HP_L_AMP_MUTE_EN_MASK		(0x1 << 6)
+#define DA7218_HP_L_AMP_EN_SHIFT		7
+#define DA7218_HP_L_AMP_EN_MASK			(0x1 << 7)
+#define DA7218_HP_AMP_OE_MASK			(0x1 << 3)
+
+/* DA7218_HP_L_GAIN = 0xD1 */
+#define DA7218_HP_L_AMP_GAIN_SHIFT	0
+#define DA7218_HP_L_AMP_GAIN_MASK	(0x3F << 0)
+#define DA7218_HP_AMP_GAIN_MIN		0x15
+#define DA7218_HP_AMP_GAIN_MAX		0x3F
+
+/* DA7218_HP_R_CTRL = 0xD2 */
+#define DA7218_HP_R_AMP_MIN_GAIN_EN_SHIFT	2
+#define DA7218_HP_R_AMP_MIN_GAIN_EN_MASK	(0x1 << 2)
+#define DA7218_HP_R_AMP_OE_SHIFT		3
+#define DA7218_HP_R_AMP_OE_MASK			(0x1 << 3)
+#define DA7218_HP_R_AMP_ZC_EN_SHIFT		4
+#define DA7218_HP_R_AMP_ZC_EN_MASK		(0x1 << 4)
+#define DA7218_HP_R_AMP_RAMP_EN_SHIFT		5
+#define DA7218_HP_R_AMP_RAMP_EN_MASK		(0x1 << 5)
+#define DA7218_HP_R_AMP_MUTE_EN_SHIFT		6
+#define DA7218_HP_R_AMP_MUTE_EN_MASK		(0x1 << 6)
+#define DA7218_HP_R_AMP_EN_SHIFT		7
+#define DA7218_HP_R_AMP_EN_MASK			(0x1 << 7)
+
+/* DA7218_HP_R_GAIN = 0xD3 */
+#define DA7218_HP_R_AMP_GAIN_SHIFT	0
+#define DA7218_HP_R_AMP_GAIN_MASK	(0x3F << 0)
+
+/* DA7218_HP_SNGL_CTRL = 0xD4 */
+#define DA7218_HP_AMP_STEREO_DETECT_STATUS_SHIFT	0
+#define DA7218_HP_AMP_STEREO_DETECT_STATUS_MASK		(0x1 << 0)
+#define DA7218_HPL_AMP_LOAD_DETECT_STATUS_SHIFT		1
+#define DA7218_HPL_AMP_LOAD_DETECT_STATUS_MASK		(0x1 << 1)
+#define DA7218_HPR_AMP_LOAD_DETECT_STATUS_SHIFT		2
+#define DA7218_HPR_AMP_LOAD_DETECT_STATUS_MASK		(0x1 << 2)
+#define DA7218_HP_AMP_LOAD_DETECT_EN_SHIFT		6
+#define DA7218_HP_AMP_LOAD_DETECT_EN_MASK		(0x1 << 6)
+#define DA7218_HP_AMP_STEREO_DETECT_EN_SHIFT		7
+#define DA7218_HP_AMP_STEREO_DETECT_EN_MASK		(0x1 << 7)
+
+/* DA7218_HP_DIFF_CTRL = 0xD5 */
+#define DA7218_HP_AMP_DIFF_MODE_EN_SHIFT	0
+#define DA7218_HP_AMP_DIFF_MODE_EN_MASK		(0x1 << 0)
+#define DA7218_HP_AMP_SINGLE_SUPPLY_EN_SHIFT	4
+#define DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK	(0x1 << 4)
+
+/* DA7218_HP_DIFF_UNLOCK = 0xD7 */
+#define DA7218_HP_DIFF_UNLOCK_SHIFT	0
+#define DA7218_HP_DIFF_UNLOCK_MASK	(0x1 << 0)
+#define DA7218_HP_DIFF_UNLOCK_VAL	0xC3
+
+/* DA7218_HPLDET_JACK = 0xD8 */
+#define DA7218_HPLDET_JACK_RATE_SHIFT		0
+#define DA7218_HPLDET_JACK_RATE_MASK		(0x7 << 0)
+#define DA7218_HPLDET_JACK_DEBOUNCE_SHIFT	3
+#define DA7218_HPLDET_JACK_DEBOUNCE_MASK	(0x3 << 3)
+#define DA7218_HPLDET_JACK_THR_SHIFT		5
+#define DA7218_HPLDET_JACK_THR_MASK		(0x3 << 5)
+#define DA7218_HPLDET_JACK_EN_SHIFT		7
+#define DA7218_HPLDET_JACK_EN_MASK		(0x1 << 7)
+
+/* DA7218_HPLDET_CTRL = 0xD9 */
+#define DA7218_HPLDET_COMP_INV_SHIFT		0
+#define DA7218_HPLDET_COMP_INV_MASK		(0x1 << 0)
+#define DA7218_HPLDET_HYST_EN_SHIFT		1
+#define DA7218_HPLDET_HYST_EN_MASK		(0x1 << 1)
+#define DA7218_HPLDET_DISCHARGE_EN_SHIFT	7
+#define DA7218_HPLDET_DISCHARGE_EN_MASK		(0x1 << 7)
+
+/* DA7218_HPLDET_TEST = 0xDA */
+#define DA7218_HPLDET_COMP_STS_SHIFT	4
+#define DA7218_HPLDET_COMP_STS_MASK	(0x1 << 4)
+
+/* DA7218_REFERENCES = 0xDC */
+#define DA7218_BIAS_EN_SHIFT	3
+#define DA7218_BIAS_EN_MASK	(0x1 << 3)
+
+/* DA7218_IO_CTRL = 0xE0 */
+#define DA7218_IO_VOLTAGE_LEVEL_SHIFT		0
+#define DA7218_IO_VOLTAGE_LEVEL_MASK		(0x1 << 0)
+#define DA7218_IO_VOLTAGE_LEVEL_2_5V_3_6V	0
+#define DA7218_IO_VOLTAGE_LEVEL_1_5V_2_5V	1
+
+/* DA7218_LDO_CTRL = 0xE1 */
+#define DA7218_LDO_LEVEL_SELECT_SHIFT	4
+#define DA7218_LDO_LEVEL_SELECT_MASK	(0x3 << 4)
+#define DA7218_LDO_EN_SHIFT		7
+#define DA7218_LDO_EN_MASK		(0x1 << 7)
+
+/* DA7218_SIDETONE_CTRL = 0xE4 */
+#define DA7218_SIDETONE_MUTE_EN_SHIFT	6
+#define DA7218_SIDETONE_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_SIDETONE_FILTER_EN_SHIFT	7
+#define DA7218_SIDETONE_FILTER_EN_MASK	(0x1 << 7)
+
+/* DA7218_SIDETONE_IN_SELECT = 0xE5 */
+#define DA7218_SIDETONE_IN_SELECT_SHIFT	0
+#define DA7218_SIDETONE_IN_SELECT_MASK	(0x3 << 0)
+#define DA7218_SIDETONE_IN_SELECT_MAX	4
+
+/* DA7218_SIDETONE_GAIN = 0xE6 */
+#define DA7218_SIDETONE_GAIN_SHIFT	0
+#define DA7218_SIDETONE_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DROUTING_ST_OUTFILT_1L = 0xE8 */
+#define DA7218_OUTFILT_ST_1L_SRC_SHIFT	0
+#define DA7218_OUTFILT_ST_1L_SRC_MASK	(0x7 << 0)
+#define DA7218_DMIX_ST_SRC_OUTFILT1L	0
+#define DA7218_DMIX_ST_SRC_OUTFILT1R	1
+#define DA7218_DMIX_ST_SRC_SIDETONE	2
+
+/* DA7218_DROUTING_ST_OUTFILT_1R = 0xE9 */
+#define DA7218_OUTFILT_ST_1R_SRC_SHIFT	0
+#define DA7218_OUTFILT_ST_1R_SRC_MASK	(0x7 << 0)
+
+/* DA7218_SIDETONE_BIQ_3STAGE_DATA = 0xEA */
+#define DA7218_SIDETONE_BIQ_3STAGE_DATA_SHIFT	0
+#define DA7218_SIDETONE_BIQ_3STAGE_DATA_MASK	(0xFF << 0)
+
+/* DA7218_SIDETONE_BIQ_3STAGE_ADDR = 0xEB */
+#define DA7218_SIDETONE_BIQ_3STAGE_ADDR_SHIFT	0
+#define DA7218_SIDETONE_BIQ_3STAGE_ADDR_MASK	(0x1F << 0)
+#define DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE	30
+
+/* DA7218_EVENT_STATUS = 0xEC */
+#define DA7218_HPLDET_JACK_STS_SHIFT	7
+#define DA7218_HPLDET_JACK_STS_MASK	(0x1 << 7)
+
+/* DA7218_EVENT = 0xED */
+#define DA7218_LVL_DET_EVENT_SHIFT	0
+#define DA7218_LVL_DET_EVENT_MASK	(0x1 << 0)
+#define DA7218_HPLDET_JACK_EVENT_SHIFT	7
+#define DA7218_HPLDET_JACK_EVENT_MASK	(0x1 << 7)
+
+/* DA7218_EVENT_MASK	= 0xEE */
+#define DA7218_LVL_DET_EVENT_MSK_SHIFT		0
+#define DA7218_LVL_DET_EVENT_MSK_MASK		(0x1 << 0)
+#define DA7218_HPLDET_JACK_EVENT_IRQ_MSK_SHIFT	7
+#define DA7218_HPLDET_JACK_EVENT_IRQ_MSK_MASK	(0x1 << 7)
+
+/* DA7218_DMIC_1_CTRL = 0xF0 */
+#define DA7218_DMIC_1_DATA_SEL_SHIFT	0
+#define DA7218_DMIC_1_DATA_SEL_MASK	(0x1 << 0)
+#define DA7218_DMIC_1_SAMPLEPHASE_SHIFT	1
+#define DA7218_DMIC_1_SAMPLEPHASE_MASK	(0x1 << 1)
+#define DA7218_DMIC_1_CLK_RATE_SHIFT	2
+#define DA7218_DMIC_1_CLK_RATE_MASK	(0x1 << 2)
+#define DA7218_DMIC_1L_EN_SHIFT		6
+#define DA7218_DMIC_1L_EN_MASK		(0x1 << 6)
+#define DA7218_DMIC_1R_EN_SHIFT		7
+#define DA7218_DMIC_1R_EN_MASK		(0x1 << 7)
+
+/* DA7218_DMIC_2_CTRL = 0xF1 */
+#define DA7218_DMIC_2_DATA_SEL_SHIFT	0
+#define DA7218_DMIC_2_DATA_SEL_MASK	(0x1 << 0)
+#define DA7218_DMIC_2_SAMPLEPHASE_SHIFT	1
+#define DA7218_DMIC_2_SAMPLEPHASE_MASK	(0x1 << 1)
+#define DA7218_DMIC_2_CLK_RATE_SHIFT	2
+#define DA7218_DMIC_2_CLK_RATE_MASK	(0x1 << 2)
+#define DA7218_DMIC_2L_EN_SHIFT		6
+#define DA7218_DMIC_2L_EN_MASK		(0x1 << 6)
+#define DA7218_DMIC_2R_EN_SHIFT		7
+#define DA7218_DMIC_2R_EN_MASK		(0x1 << 7)
+
+/* DA7218_IN_1L_GAIN = 0xF4 */
+#define DA7218_IN_1L_DIGITAL_GAIN_SHIFT	0
+#define DA7218_IN_1L_DIGITAL_GAIN_MASK	(0x7F << 0)
+#define DA7218_IN_DIGITAL_GAIN_MAX	0x7F
+
+/* DA7218_IN_1R_GAIN = 0xF5 */
+#define DA7218_IN_1R_DIGITAL_GAIN_SHIFT	0
+#define DA7218_IN_1R_DIGITAL_GAIN_MASK	(0x7F << 0)
+
+/* DA7218_IN_2L_GAIN = 0xF6 */
+#define DA7218_IN_2L_DIGITAL_GAIN_SHIFT	0
+#define DA7218_IN_2L_DIGITAL_GAIN_MASK	(0x7F << 0)
+
+/* DA7218_IN_2R_GAIN = 0xF7 */
+#define DA7218_IN_2R_DIGITAL_GAIN_SHIFT	0
+#define DA7218_IN_2R_DIGITAL_GAIN_MASK	(0x7F << 0)
+
+/* DA7218_OUT_1L_GAIN = 0xF8 */
+#define DA7218_OUT_1L_DIGITAL_GAIN_SHIFT	0
+#define DA7218_OUT_1L_DIGITAL_GAIN_MASK		(0xFF << 0)
+#define DA7218_OUT_DIGITAL_GAIN_MIN		0x0
+#define DA7218_OUT_DIGITAL_GAIN_MAX		0x97
+
+/* DA7218_OUT_1R_GAIN = 0xF9 */
+#define DA7218_OUT_1R_DIGITAL_GAIN_SHIFT	0
+#define DA7218_OUT_1R_DIGITAL_GAIN_MASK		(0xFF << 0)
+
+/* DA7218_MICBIAS_CTRL = 0xFC */
+#define DA7218_MICBIAS_1_LEVEL_SHIFT	0
+#define DA7218_MICBIAS_1_LEVEL_MASK	(0x7 << 0)
+#define DA7218_MICBIAS_1_LP_MODE_SHIFT	3
+#define DA7218_MICBIAS_1_LP_MODE_MASK	(0x1 << 3)
+#define DA7218_MICBIAS_2_LEVEL_SHIFT	4
+#define DA7218_MICBIAS_2_LEVEL_MASK	(0x7 << 4)
+#define DA7218_MICBIAS_2_LP_MODE_SHIFT	7
+#define DA7218_MICBIAS_2_LP_MODE_MASK	(0x1 << 7)
+
+/* DA7218_MICBIAS_EN = 0xFD */
+#define DA7218_MICBIAS_1_EN_SHIFT	0
+#define DA7218_MICBIAS_1_EN_MASK	(0x1 << 0)
+#define DA7218_MICBIAS_2_EN_SHIFT	4
+#define DA7218_MICBIAS_2_EN_MASK	(0x1 << 4)
+
+
+/*
+ * General defines & data
+ */
+
+/* Register inversion */
+#define DA7218_NO_INVERT	0
+#define DA7218_INVERT		1
+
+/* Byte related defines */
+#define DA7218_BYTE_SHIFT	8
+#define DA7218_BYTE_MASK	0xFF
+#define DA7218_2BYTE_SHIFT	16
+#define DA7218_2BYTE_MASK	0xFFFF
+
+/* PLL Output Frequencies */
+#define DA7218_PLL_FREQ_OUT_90316	90316800
+#define DA7218_PLL_FREQ_OUT_98304	98304000
+
+/* PLL Frequency Dividers */
+#define DA7218_PLL_INDIV_2_TO_4_5_MHZ_VAL	1
+#define DA7218_PLL_INDIV_4_5_TO_9_MHZ_VAL	2
+#define DA7218_PLL_INDIV_9_TO_18_MHZ_VAL	4
+#define DA7218_PLL_INDIV_18_TO_36_MHZ_VAL	8
+#define DA7218_PLL_INDIV_36_TO_54_MHZ_VAL	16
+
+/* ALC Calibration */
+#define DA7218_ALC_CALIB_DELAY_MIN	2500
+#define DA7218_ALC_CALIB_DELAY_MAX	5000
+#define DA7218_ALC_CALIB_MAX_TRIES	5
+
+/* Ref Oscillator */
+#define DA7218_REF_OSC_CHECK_DELAY_MIN	5000
+#define DA7218_REF_OSC_CHECK_DELAY_MAX	10000
+#define DA7218_REF_OSC_CHECK_TRIES	4
+
+/* SRM */
+#define DA7218_SRM_CHECK_DELAY		50
+#define DA7218_SRM_CHECK_TRIES		8
+
+/* Mic Level Detect */
+#define DA7218_MIC_LVL_DET_DELAY	50
+
+enum da7218_biq_cfg {
+	DA7218_BIQ_CFG_DATA = 0,
+	DA7218_BIQ_CFG_ADDR,
+	DA7218_BIQ_CFG_SIZE,
+};
+
+enum da7218_clk_src {
+	DA7218_CLKSRC_MCLK = 0,
+	DA7218_CLKSRC_MCLK_SQR,
+};
+
+enum da7218_sys_clk {
+	DA7218_SYSCLK_MCLK = 0,
+	DA7218_SYSCLK_PLL,
+	DA7218_SYSCLK_PLL_SRM,
+};
+
+enum da7218_dev_id {
+	DA7217_DEV_ID = 0,
+	DA7218_DEV_ID,
+};
+
+/* Regulators */
+enum da7218_supplies {
+	DA7218_SUPPLY_VDD = 0,
+	DA7218_SUPPLY_VDDMIC,
+	DA7218_SUPPLY_VDDIO,
+	DA7218_NUM_SUPPLIES,
+};
+
+/* Private data */
+struct da7218_priv {
+	struct da7218_pdata *pdata;
+
+	struct regulator_bulk_data supplies[DA7218_NUM_SUPPLIES];
+	struct regmap *regmap;
+	int dev_id;
+
+	struct snd_soc_jack *jack;
+	int irq;
+
+	struct clk *mclk;
+	unsigned int mclk_rate;
+
+	bool hp_single_supply;
+	bool master;
+	u8 alc_en;
+	u8 in_filt_en;
+	u8 mic_lvl_det_en;
+
+	u8 biq_5stage_coeff[DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE];
+	u8 stbiq_3stage_coeff[DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE];
+};
+
+/* HP detect control */
+int da7218_hpldet(struct snd_soc_component *component, struct snd_soc_jack *jack);
+
+#endif /* _DA7218_H */
diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c
new file mode 100644
index 0000000..2c7d508
--- /dev/null
+++ b/sound/soc/codecs/da7219-aad.c
@@ -0,0 +1,956 @@
+/*
+ * da7219-aad.c - Dialog DA7219 ALSA SoC AAD Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor Ltd.
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/property.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/da7219.h>
+
+#include "da7219.h"
+#include "da7219-aad.h"
+
+
+/*
+ * Detection control
+ */
+
+void da7219_aad_jack_det(struct snd_soc_component *component, struct snd_soc_jack *jack)
+{
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+
+	da7219->aad->jack = jack;
+	da7219->aad->jack_inserted = false;
+
+	/* Send an initial empty report */
+	snd_soc_jack_report(jack, 0, DA7219_AAD_REPORT_ALL_MASK);
+
+	/* Enable/Disable jack detection */
+	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
+			    DA7219_ACCDET_EN_MASK,
+			    (jack ? DA7219_ACCDET_EN_MASK : 0));
+}
+EXPORT_SYMBOL_GPL(da7219_aad_jack_det);
+
+/*
+ * Button/HPTest work
+ */
+
+static void da7219_aad_btn_det_work(struct work_struct *work)
+{
+	struct da7219_aad_priv *da7219_aad =
+		container_of(work, struct da7219_aad_priv, btn_det_work);
+	struct snd_soc_component *component = da7219_aad->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	u8 statusa, micbias_ctrl;
+	bool micbias_up = false;
+	int retries = 0;
+
+	/* Drive headphones/lineout */
+	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
+			    DA7219_HP_L_AMP_OE_MASK,
+			    DA7219_HP_L_AMP_OE_MASK);
+	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
+			    DA7219_HP_R_AMP_OE_MASK,
+			    DA7219_HP_R_AMP_OE_MASK);
+
+	/* Make sure mic bias is up */
+	snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
+	snd_soc_dapm_sync(dapm);
+
+	do {
+		statusa = snd_soc_component_read32(component, DA7219_ACCDET_STATUS_A);
+		if (statusa & DA7219_MICBIAS_UP_STS_MASK)
+			micbias_up = true;
+		else if (retries++ < DA7219_AAD_MICBIAS_CHK_RETRIES)
+			msleep(DA7219_AAD_MICBIAS_CHK_DELAY);
+	} while ((!micbias_up) && (retries < DA7219_AAD_MICBIAS_CHK_RETRIES));
+
+	if (retries >= DA7219_AAD_MICBIAS_CHK_RETRIES)
+		dev_warn(component->dev, "Mic bias status check timed out");
+
+	da7219->micbias_on_event = true;
+
+	/*
+	 * Mic bias pulse required to enable mic, must be done before enabling
+	 * button detection to prevent erroneous button readings.
+	 */
+	if (da7219_aad->micbias_pulse_lvl && da7219_aad->micbias_pulse_time) {
+		/* Pulse higher level voltage */
+		micbias_ctrl = snd_soc_component_read32(component, DA7219_MICBIAS_CTRL);
+		snd_soc_component_update_bits(component, DA7219_MICBIAS_CTRL,
+				    DA7219_MICBIAS1_LEVEL_MASK,
+				    da7219_aad->micbias_pulse_lvl);
+		msleep(da7219_aad->micbias_pulse_time);
+		snd_soc_component_write(component, DA7219_MICBIAS_CTRL, micbias_ctrl);
+
+	}
+
+	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
+			    DA7219_BUTTON_CONFIG_MASK,
+			    da7219_aad->btn_cfg);
+}
+
+static void da7219_aad_hptest_work(struct work_struct *work)
+{
+	struct da7219_aad_priv *da7219_aad =
+		container_of(work, struct da7219_aad_priv, hptest_work);
+	struct snd_soc_component *component = da7219_aad->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+
+	u16 tonegen_freq_hptest;
+	u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8;
+	int report = 0, ret = 0;
+
+	/* Lock DAPM, Kcontrols affected by this test and the PLL */
+	snd_soc_dapm_mutex_lock(dapm);
+	mutex_lock(&da7219->ctrl_lock);
+	mutex_lock(&da7219->pll_lock);
+
+	/* Ensure MCLK is available for HP test procedure */
+	if (da7219->mclk) {
+		ret = clk_prepare_enable(da7219->mclk);
+		if (ret) {
+			dev_err(component->dev, "Failed to enable mclk - %d\n", ret);
+			mutex_unlock(&da7219->pll_lock);
+			mutex_unlock(&da7219->ctrl_lock);
+			snd_soc_dapm_mutex_unlock(dapm);
+			return;
+		}
+	}
+
+	/*
+	 * If MCLK not present, then we're using the internal oscillator and
+	 * require different frequency settings to achieve the same result.
+	 *
+	 * If MCLK is present, but PLL is not enabled then we enable it here to
+	 * ensure a consistent detection procedure.
+	 */
+	pll_srm_sts = snd_soc_component_read32(component, DA7219_PLL_SRM_STS);
+	if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) {
+		tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ);
+
+		pll_ctrl = snd_soc_component_read32(component, DA7219_PLL_CTRL);
+		if ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS)
+			da7219_set_pll(component, DA7219_SYSCLK_PLL,
+				       DA7219_PLL_FREQ_OUT_98304);
+	} else {
+		tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC);
+	}
+
+	/* Ensure gain ramping at fastest rate */
+	gain_ramp_ctrl = snd_soc_component_read32(component, DA7219_GAIN_RAMP_CTRL);
+	snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8);
+
+	/* Bypass cache so it saves current settings */
+	regcache_cache_bypass(da7219->regmap, true);
+
+	/* Make sure Tone Generator is disabled */
+	snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, 0);
+
+	/* Enable HPTest block, 1KOhms check */
+	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_8,
+			    DA7219_HPTEST_EN_MASK | DA7219_HPTEST_RES_SEL_MASK,
+			    DA7219_HPTEST_EN_MASK |
+			    DA7219_HPTEST_RES_SEL_1KOHMS);
+
+	/* Set gains to 0db */
+	snd_soc_component_write(component, DA7219_DAC_L_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
+	snd_soc_component_write(component, DA7219_DAC_R_GAIN, DA7219_DAC_DIGITAL_GAIN_0DB);
+	snd_soc_component_write(component, DA7219_HP_L_GAIN, DA7219_HP_AMP_GAIN_0DB);
+	snd_soc_component_write(component, DA7219_HP_R_GAIN, DA7219_HP_AMP_GAIN_0DB);
+
+	/* Disable DAC filters, EQs and soft mute */
+	snd_soc_component_update_bits(component, DA7219_DAC_FILTERS1, DA7219_HPF_MODE_MASK,
+			    0);
+	snd_soc_component_update_bits(component, DA7219_DAC_FILTERS4, DA7219_DAC_EQ_EN_MASK,
+			    0);
+	snd_soc_component_update_bits(component, DA7219_DAC_FILTERS5,
+			    DA7219_DAC_SOFTMUTE_EN_MASK, 0);
+
+	/* Enable HP left & right paths */
+	snd_soc_component_update_bits(component, DA7219_CP_CTRL, DA7219_CP_EN_MASK,
+			    DA7219_CP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7219_DIG_ROUTING_DAC,
+			    DA7219_DAC_L_SRC_MASK | DA7219_DAC_R_SRC_MASK,
+			    DA7219_DAC_L_SRC_TONEGEN |
+			    DA7219_DAC_R_SRC_TONEGEN);
+	snd_soc_component_update_bits(component, DA7219_DAC_L_CTRL,
+			    DA7219_DAC_L_EN_MASK | DA7219_DAC_L_MUTE_EN_MASK,
+			    DA7219_DAC_L_EN_MASK);
+	snd_soc_component_update_bits(component, DA7219_DAC_R_CTRL,
+			    DA7219_DAC_R_EN_MASK | DA7219_DAC_R_MUTE_EN_MASK,
+			    DA7219_DAC_R_EN_MASK);
+	snd_soc_component_update_bits(component, DA7219_MIXOUT_L_SELECT,
+			    DA7219_MIXOUT_L_MIX_SELECT_MASK,
+			    DA7219_MIXOUT_L_MIX_SELECT_MASK);
+	snd_soc_component_update_bits(component, DA7219_MIXOUT_R_SELECT,
+			    DA7219_MIXOUT_R_MIX_SELECT_MASK,
+			    DA7219_MIXOUT_R_MIX_SELECT_MASK);
+	snd_soc_component_update_bits(component, DA7219_DROUTING_ST_OUTFILT_1L,
+			    DA7219_OUTFILT_ST_1L_SRC_MASK,
+			    DA7219_DMIX_ST_SRC_OUTFILT1L);
+	snd_soc_component_update_bits(component, DA7219_DROUTING_ST_OUTFILT_1R,
+			    DA7219_OUTFILT_ST_1R_SRC_MASK,
+			    DA7219_DMIX_ST_SRC_OUTFILT1R);
+	snd_soc_component_update_bits(component, DA7219_MIXOUT_L_CTRL,
+			    DA7219_MIXOUT_L_AMP_EN_MASK,
+			    DA7219_MIXOUT_L_AMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7219_MIXOUT_R_CTRL,
+			    DA7219_MIXOUT_R_AMP_EN_MASK,
+			    DA7219_MIXOUT_R_AMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
+			    DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK,
+			    DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
+			    DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK,
+			    DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK);
+	msleep(DA7219_SETTLING_DELAY);
+	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
+			    DA7219_HP_L_AMP_MUTE_EN_MASK |
+			    DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, 0);
+	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
+			    DA7219_HP_R_AMP_MUTE_EN_MASK |
+			    DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, 0);
+
+	/*
+	 * If we're running from the internal oscillator then give audio paths
+	 * time to settle before running test.
+	 */
+	if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))
+		msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
+
+	/* Configure & start Tone Generator */
+	snd_soc_component_write(component, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK);
+	regmap_raw_write(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
+			 &tonegen_freq_hptest, sizeof(tonegen_freq_hptest));
+	snd_soc_component_update_bits(component, DA7219_TONE_GEN_CFG2,
+			    DA7219_SWG_SEL_MASK | DA7219_TONE_GEN_GAIN_MASK,
+			    DA7219_SWG_SEL_SRAMP |
+			    DA7219_TONE_GEN_GAIN_MINUS_15DB);
+	snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, DA7219_START_STOPN_MASK);
+
+	msleep(DA7219_AAD_HPTEST_PERIOD);
+
+	/* Grab comparator reading */
+	accdet_cfg8 = snd_soc_component_read32(component, DA7219_ACCDET_CONFIG_8);
+	if (accdet_cfg8 & DA7219_HPTEST_COMP_MASK)
+		report |= SND_JACK_HEADPHONE;
+	else
+		report |= SND_JACK_LINEOUT;
+
+	/* Stop tone generator */
+	snd_soc_component_write(component, DA7219_TONE_GEN_CFG1, 0);
+
+	msleep(DA7219_AAD_HPTEST_PERIOD);
+
+	/* Restore original settings from cache */
+	regcache_mark_dirty(da7219->regmap);
+	regcache_sync_region(da7219->regmap, DA7219_HP_L_CTRL,
+			     DA7219_HP_R_CTRL);
+	msleep(DA7219_SETTLING_DELAY);
+	regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_CTRL,
+			     DA7219_MIXOUT_R_CTRL);
+	regcache_sync_region(da7219->regmap, DA7219_DROUTING_ST_OUTFILT_1L,
+			     DA7219_DROUTING_ST_OUTFILT_1R);
+	regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_SELECT,
+			     DA7219_MIXOUT_R_SELECT);
+	regcache_sync_region(da7219->regmap, DA7219_DAC_L_CTRL,
+			     DA7219_DAC_R_CTRL);
+	regcache_sync_region(da7219->regmap, DA7219_DIG_ROUTING_DAC,
+			     DA7219_DIG_ROUTING_DAC);
+	regcache_sync_region(da7219->regmap, DA7219_CP_CTRL, DA7219_CP_CTRL);
+	regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS5,
+			     DA7219_DAC_FILTERS5);
+	regcache_sync_region(da7219->regmap, DA7219_DAC_FILTERS4,
+			     DA7219_DAC_FILTERS1);
+	regcache_sync_region(da7219->regmap, DA7219_HP_L_GAIN,
+			     DA7219_HP_R_GAIN);
+	regcache_sync_region(da7219->regmap, DA7219_DAC_L_GAIN,
+			     DA7219_DAC_R_GAIN);
+	regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_ON_PER,
+			     DA7219_TONE_GEN_ON_PER);
+	regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_FREQ1_L,
+			     DA7219_TONE_GEN_FREQ1_U);
+	regcache_sync_region(da7219->regmap, DA7219_TONE_GEN_CFG1,
+			     DA7219_TONE_GEN_CFG2);
+
+	regcache_cache_bypass(da7219->regmap, false);
+
+	/* Disable HPTest block */
+	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_8,
+			    DA7219_HPTEST_EN_MASK, 0);
+
+	/*
+	 * If we're running from the internal oscillator then give audio paths
+	 * time to settle before allowing headphones to be driven as required.
+	 */
+	if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK))
+		msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY);
+
+	/* Restore gain ramping rate */
+	snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL, gain_ramp_ctrl);
+
+	/* Drive Headphones/lineout */
+	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK,
+			    DA7219_HP_L_AMP_OE_MASK);
+	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK,
+			    DA7219_HP_R_AMP_OE_MASK);
+
+	/* Restore PLL to previous configuration, if re-configured */
+	if ((pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) &&
+	    ((pll_ctrl & DA7219_PLL_MODE_MASK) == DA7219_PLL_MODE_BYPASS))
+		da7219_set_pll(component, DA7219_SYSCLK_MCLK, 0);
+
+	/* Remove MCLK, if previously enabled */
+	if (da7219->mclk)
+		clk_disable_unprepare(da7219->mclk);
+
+	mutex_unlock(&da7219->pll_lock);
+	mutex_unlock(&da7219->ctrl_lock);
+	snd_soc_dapm_mutex_unlock(dapm);
+
+	/*
+	 * Only send report if jack hasn't been removed during process,
+	 * otherwise it's invalid and we drop it.
+	 */
+	if (da7219_aad->jack_inserted)
+		snd_soc_jack_report(da7219_aad->jack, report,
+				    SND_JACK_HEADSET | SND_JACK_LINEOUT);
+}
+
+
+/*
+ * IRQ
+ */
+
+static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
+{
+	struct da7219_aad_priv *da7219_aad = data;
+	struct snd_soc_component *component = da7219_aad->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	u8 events[DA7219_AAD_IRQ_REG_MAX];
+	u8 statusa;
+	int i, report = 0, mask = 0;
+
+	/* Read current IRQ events */
+	regmap_bulk_read(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
+			 events, DA7219_AAD_IRQ_REG_MAX);
+
+	if (!events[DA7219_AAD_IRQ_REG_A] && !events[DA7219_AAD_IRQ_REG_B])
+		return IRQ_NONE;
+
+	/* Read status register for jack insertion & type status */
+	statusa = snd_soc_component_read32(component, DA7219_ACCDET_STATUS_A);
+
+	/* Clear events */
+	regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_EVENT_A,
+			  events, DA7219_AAD_IRQ_REG_MAX);
+
+	dev_dbg(component->dev, "IRQ events = 0x%x|0x%x, status = 0x%x\n",
+		events[DA7219_AAD_IRQ_REG_A], events[DA7219_AAD_IRQ_REG_B],
+		statusa);
+
+	if (statusa & DA7219_JACK_INSERTION_STS_MASK) {
+		/* Jack Insertion */
+		if (events[DA7219_AAD_IRQ_REG_A] &
+		    DA7219_E_JACK_INSERTED_MASK) {
+			report |= SND_JACK_MECHANICAL;
+			mask |= SND_JACK_MECHANICAL;
+			da7219_aad->jack_inserted = true;
+		}
+
+		/* Jack type detection */
+		if (events[DA7219_AAD_IRQ_REG_A] &
+		    DA7219_E_JACK_DETECT_COMPLETE_MASK) {
+			/*
+			 * If 4-pole, then enable button detection, else perform
+			 * HP impedance test to determine output type to report.
+			 *
+			 * We schedule work here as the tasks themselves can
+			 * take time to complete, and in particular for hptest
+			 * we want to be able to check if the jack was removed
+			 * during the procedure as this will invalidate the
+			 * result. By doing this as work, the IRQ thread can
+			 * handle a removal, and we can check at the end of
+			 * hptest if we have a valid result or not.
+			 */
+			if (statusa & DA7219_JACK_TYPE_STS_MASK) {
+				report |= SND_JACK_HEADSET;
+				mask |=	SND_JACK_HEADSET | SND_JACK_LINEOUT;
+				schedule_work(&da7219_aad->btn_det_work);
+			} else {
+				schedule_work(&da7219_aad->hptest_work);
+			}
+		}
+
+		/* Button support for 4-pole jack */
+		if (statusa & DA7219_JACK_TYPE_STS_MASK) {
+			for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) {
+				/* Button Press */
+				if (events[DA7219_AAD_IRQ_REG_B] &
+				    (DA7219_E_BUTTON_A_PRESSED_MASK << i)) {
+					report |= SND_JACK_BTN_0 >> i;
+					mask |= SND_JACK_BTN_0 >> i;
+				}
+			}
+			snd_soc_jack_report(da7219_aad->jack, report, mask);
+
+			for (i = 0; i < DA7219_AAD_MAX_BUTTONS; ++i) {
+				/* Button Release */
+				if (events[DA7219_AAD_IRQ_REG_B] &
+				    (DA7219_E_BUTTON_A_RELEASED_MASK >> i)) {
+					report &= ~(SND_JACK_BTN_0 >> i);
+					mask |= SND_JACK_BTN_0 >> i;
+				}
+			}
+		}
+	} else {
+		/* Jack removal */
+		if (events[DA7219_AAD_IRQ_REG_A] & DA7219_E_JACK_REMOVED_MASK) {
+			report = 0;
+			mask |= DA7219_AAD_REPORT_ALL_MASK;
+			da7219_aad->jack_inserted = false;
+
+			/* Un-drive headphones/lineout */
+			snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
+					    DA7219_HP_R_AMP_OE_MASK, 0);
+			snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
+					    DA7219_HP_L_AMP_OE_MASK, 0);
+
+			/* Ensure button detection disabled */
+			snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
+					    DA7219_BUTTON_CONFIG_MASK, 0);
+
+			da7219->micbias_on_event = false;
+
+			/* Disable mic bias */
+			snd_soc_dapm_disable_pin(dapm, "Mic Bias");
+			snd_soc_dapm_sync(dapm);
+
+			/* Cancel any pending work */
+			cancel_work_sync(&da7219_aad->btn_det_work);
+			cancel_work_sync(&da7219_aad->hptest_work);
+		}
+	}
+
+	snd_soc_jack_report(da7219_aad->jack, report, mask);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * DT/ACPI to pdata conversion
+ */
+
+static enum da7219_aad_micbias_pulse_lvl
+	da7219_aad_fw_micbias_pulse_lvl(struct snd_soc_component *component, u32 val)
+{
+	switch (val) {
+	case 2800:
+		return DA7219_AAD_MICBIAS_PULSE_LVL_2_8V;
+	case 2900:
+		return DA7219_AAD_MICBIAS_PULSE_LVL_2_9V;
+	default:
+		dev_warn(component->dev, "Invalid micbias pulse level");
+		return DA7219_AAD_MICBIAS_PULSE_LVL_OFF;
+	}
+}
+
+static enum da7219_aad_btn_cfg
+	da7219_aad_fw_btn_cfg(struct snd_soc_component *component, u32 val)
+{
+	switch (val) {
+	case 2:
+		return DA7219_AAD_BTN_CFG_2MS;
+	case 5:
+		return DA7219_AAD_BTN_CFG_5MS;
+	case 10:
+		return DA7219_AAD_BTN_CFG_10MS;
+	case 50:
+		return DA7219_AAD_BTN_CFG_50MS;
+	case 100:
+		return DA7219_AAD_BTN_CFG_100MS;
+	case 200:
+		return DA7219_AAD_BTN_CFG_200MS;
+	case 500:
+		return DA7219_AAD_BTN_CFG_500MS;
+	default:
+		dev_warn(component->dev, "Invalid button config");
+		return DA7219_AAD_BTN_CFG_10MS;
+	}
+}
+
+static enum da7219_aad_mic_det_thr
+	da7219_aad_fw_mic_det_thr(struct snd_soc_component *component, u32 val)
+{
+	switch (val) {
+	case 200:
+		return DA7219_AAD_MIC_DET_THR_200_OHMS;
+	case 500:
+		return DA7219_AAD_MIC_DET_THR_500_OHMS;
+	case 750:
+		return DA7219_AAD_MIC_DET_THR_750_OHMS;
+	case 1000:
+		return DA7219_AAD_MIC_DET_THR_1000_OHMS;
+	default:
+		dev_warn(component->dev, "Invalid mic detect threshold");
+		return DA7219_AAD_MIC_DET_THR_500_OHMS;
+	}
+}
+
+static enum da7219_aad_jack_ins_deb
+	da7219_aad_fw_jack_ins_deb(struct snd_soc_component *component, u32 val)
+{
+	switch (val) {
+	case 5:
+		return DA7219_AAD_JACK_INS_DEB_5MS;
+	case 10:
+		return DA7219_AAD_JACK_INS_DEB_10MS;
+	case 20:
+		return DA7219_AAD_JACK_INS_DEB_20MS;
+	case 50:
+		return DA7219_AAD_JACK_INS_DEB_50MS;
+	case 100:
+		return DA7219_AAD_JACK_INS_DEB_100MS;
+	case 200:
+		return DA7219_AAD_JACK_INS_DEB_200MS;
+	case 500:
+		return DA7219_AAD_JACK_INS_DEB_500MS;
+	case 1000:
+		return DA7219_AAD_JACK_INS_DEB_1S;
+	default:
+		dev_warn(component->dev, "Invalid jack insert debounce");
+		return DA7219_AAD_JACK_INS_DEB_20MS;
+	}
+}
+
+static enum da7219_aad_jack_det_rate
+	da7219_aad_fw_jack_det_rate(struct snd_soc_component *component, const char *str)
+{
+	if (!strcmp(str, "32ms_64ms")) {
+		return DA7219_AAD_JACK_DET_RATE_32_64MS;
+	} else if (!strcmp(str, "64ms_128ms")) {
+		return DA7219_AAD_JACK_DET_RATE_64_128MS;
+	} else if (!strcmp(str, "128ms_256ms")) {
+		return DA7219_AAD_JACK_DET_RATE_128_256MS;
+	} else if (!strcmp(str, "256ms_512ms")) {
+		return DA7219_AAD_JACK_DET_RATE_256_512MS;
+	} else {
+		dev_warn(component->dev, "Invalid jack detect rate");
+		return DA7219_AAD_JACK_DET_RATE_256_512MS;
+	}
+}
+
+static enum da7219_aad_jack_rem_deb
+	da7219_aad_fw_jack_rem_deb(struct snd_soc_component *component, u32 val)
+{
+	switch (val) {
+	case 1:
+		return DA7219_AAD_JACK_REM_DEB_1MS;
+	case 5:
+		return DA7219_AAD_JACK_REM_DEB_5MS;
+	case 10:
+		return DA7219_AAD_JACK_REM_DEB_10MS;
+	case 20:
+		return DA7219_AAD_JACK_REM_DEB_20MS;
+	default:
+		dev_warn(component->dev, "Invalid jack removal debounce");
+		return DA7219_AAD_JACK_REM_DEB_1MS;
+	}
+}
+
+static enum da7219_aad_btn_avg
+	da7219_aad_fw_btn_avg(struct snd_soc_component *component, u32 val)
+{
+	switch (val) {
+	case 1:
+		return DA7219_AAD_BTN_AVG_1;
+	case 2:
+		return DA7219_AAD_BTN_AVG_2;
+	case 4:
+		return DA7219_AAD_BTN_AVG_4;
+	case 8:
+		return DA7219_AAD_BTN_AVG_8;
+	default:
+		dev_warn(component->dev, "Invalid button average value");
+		return DA7219_AAD_BTN_AVG_2;
+	}
+}
+
+static enum da7219_aad_adc_1bit_rpt
+	da7219_aad_fw_adc_1bit_rpt(struct snd_soc_component *component, u32 val)
+{
+	switch (val) {
+	case 1:
+		return DA7219_AAD_ADC_1BIT_RPT_1;
+	case 2:
+		return DA7219_AAD_ADC_1BIT_RPT_2;
+	case 4:
+		return DA7219_AAD_ADC_1BIT_RPT_4;
+	case 8:
+		return DA7219_AAD_ADC_1BIT_RPT_8;
+	default:
+		dev_warn(component->dev, "Invalid ADC 1-bit repeat value");
+		return DA7219_AAD_ADC_1BIT_RPT_1;
+	}
+}
+
+static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct snd_soc_component *component)
+{
+	struct device *dev = component->dev;
+	struct i2c_client *i2c = to_i2c_client(dev);
+	struct fwnode_handle *aad_np;
+	struct da7219_aad_pdata *aad_pdata;
+	const char *fw_str;
+	u32 fw_val32;
+
+	aad_np = device_get_named_child_node(dev, "da7219_aad");
+	if (!aad_np)
+		return NULL;
+
+	aad_pdata = devm_kzalloc(dev, sizeof(*aad_pdata), GFP_KERNEL);
+	if (!aad_pdata)
+		return NULL;
+
+	aad_pdata->irq = i2c->irq;
+
+	if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-lvl",
+				     &fw_val32) >= 0)
+		aad_pdata->micbias_pulse_lvl =
+			da7219_aad_fw_micbias_pulse_lvl(component, fw_val32);
+	else
+		aad_pdata->micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF;
+
+	if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-time",
+				     &fw_val32) >= 0)
+		aad_pdata->micbias_pulse_time = fw_val32;
+
+	if (fwnode_property_read_u32(aad_np, "dlg,btn-cfg", &fw_val32) >= 0)
+		aad_pdata->btn_cfg = da7219_aad_fw_btn_cfg(component, fw_val32);
+	else
+		aad_pdata->btn_cfg = DA7219_AAD_BTN_CFG_10MS;
+
+	if (fwnode_property_read_u32(aad_np, "dlg,mic-det-thr", &fw_val32) >= 0)
+		aad_pdata->mic_det_thr =
+			da7219_aad_fw_mic_det_thr(component, fw_val32);
+	else
+		aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_500_OHMS;
+
+	if (fwnode_property_read_u32(aad_np, "dlg,jack-ins-deb", &fw_val32) >= 0)
+		aad_pdata->jack_ins_deb =
+			da7219_aad_fw_jack_ins_deb(component, fw_val32);
+	else
+		aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS;
+
+	if (!fwnode_property_read_string(aad_np, "dlg,jack-det-rate", &fw_str))
+		aad_pdata->jack_det_rate =
+			da7219_aad_fw_jack_det_rate(component, fw_str);
+	else
+		aad_pdata->jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS;
+
+	if (fwnode_property_read_u32(aad_np, "dlg,jack-rem-deb", &fw_val32) >= 0)
+		aad_pdata->jack_rem_deb =
+			da7219_aad_fw_jack_rem_deb(component, fw_val32);
+	else
+		aad_pdata->jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS;
+
+	if (fwnode_property_read_u32(aad_np, "dlg,a-d-btn-thr", &fw_val32) >= 0)
+		aad_pdata->a_d_btn_thr = (u8) fw_val32;
+	else
+		aad_pdata->a_d_btn_thr = 0xA;
+
+	if (fwnode_property_read_u32(aad_np, "dlg,d-b-btn-thr", &fw_val32) >= 0)
+		aad_pdata->d_b_btn_thr = (u8) fw_val32;
+	else
+		aad_pdata->d_b_btn_thr = 0x16;
+
+	if (fwnode_property_read_u32(aad_np, "dlg,b-c-btn-thr", &fw_val32) >= 0)
+		aad_pdata->b_c_btn_thr = (u8) fw_val32;
+	else
+		aad_pdata->b_c_btn_thr = 0x21;
+
+	if (fwnode_property_read_u32(aad_np, "dlg,c-mic-btn-thr", &fw_val32) >= 0)
+		aad_pdata->c_mic_btn_thr = (u8) fw_val32;
+	else
+		aad_pdata->c_mic_btn_thr = 0x3E;
+
+	if (fwnode_property_read_u32(aad_np, "dlg,btn-avg", &fw_val32) >= 0)
+		aad_pdata->btn_avg = da7219_aad_fw_btn_avg(component, fw_val32);
+	else
+		aad_pdata->btn_avg = DA7219_AAD_BTN_AVG_2;
+
+	if (fwnode_property_read_u32(aad_np, "dlg,adc-1bit-rpt", &fw_val32) >= 0)
+		aad_pdata->adc_1bit_rpt =
+			da7219_aad_fw_adc_1bit_rpt(component, fw_val32);
+	else
+		aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1;
+
+	return aad_pdata;
+}
+
+static void da7219_aad_handle_pdata(struct snd_soc_component *component)
+{
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	struct da7219_aad_priv *da7219_aad = da7219->aad;
+	struct da7219_pdata *pdata = da7219->pdata;
+
+	if ((pdata) && (pdata->aad_pdata)) {
+		struct da7219_aad_pdata *aad_pdata = pdata->aad_pdata;
+		u8 cfg, mask;
+
+		da7219_aad->irq = aad_pdata->irq;
+
+		switch (aad_pdata->micbias_pulse_lvl) {
+		case DA7219_AAD_MICBIAS_PULSE_LVL_2_8V:
+		case DA7219_AAD_MICBIAS_PULSE_LVL_2_9V:
+			da7219_aad->micbias_pulse_lvl =
+				(aad_pdata->micbias_pulse_lvl <<
+				 DA7219_MICBIAS1_LEVEL_SHIFT);
+			break;
+		default:
+			break;
+		}
+
+		da7219_aad->micbias_pulse_time = aad_pdata->micbias_pulse_time;
+
+		switch (aad_pdata->btn_cfg) {
+		case DA7219_AAD_BTN_CFG_2MS:
+		case DA7219_AAD_BTN_CFG_5MS:
+		case DA7219_AAD_BTN_CFG_10MS:
+		case DA7219_AAD_BTN_CFG_50MS:
+		case DA7219_AAD_BTN_CFG_100MS:
+		case DA7219_AAD_BTN_CFG_200MS:
+		case DA7219_AAD_BTN_CFG_500MS:
+			da7219_aad->btn_cfg  = (aad_pdata->btn_cfg <<
+						DA7219_BUTTON_CONFIG_SHIFT);
+		}
+
+		cfg = 0;
+		mask = 0;
+		switch (aad_pdata->mic_det_thr) {
+		case DA7219_AAD_MIC_DET_THR_200_OHMS:
+		case DA7219_AAD_MIC_DET_THR_500_OHMS:
+		case DA7219_AAD_MIC_DET_THR_750_OHMS:
+		case DA7219_AAD_MIC_DET_THR_1000_OHMS:
+			cfg |= (aad_pdata->mic_det_thr <<
+				DA7219_MIC_DET_THRESH_SHIFT);
+			mask |= DA7219_MIC_DET_THRESH_MASK;
+		}
+		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1, mask, cfg);
+
+		cfg = 0;
+		mask = 0;
+		switch (aad_pdata->jack_ins_deb) {
+		case DA7219_AAD_JACK_INS_DEB_5MS:
+		case DA7219_AAD_JACK_INS_DEB_10MS:
+		case DA7219_AAD_JACK_INS_DEB_20MS:
+		case DA7219_AAD_JACK_INS_DEB_50MS:
+		case DA7219_AAD_JACK_INS_DEB_100MS:
+		case DA7219_AAD_JACK_INS_DEB_200MS:
+		case DA7219_AAD_JACK_INS_DEB_500MS:
+		case DA7219_AAD_JACK_INS_DEB_1S:
+			cfg |= (aad_pdata->jack_ins_deb <<
+				DA7219_JACKDET_DEBOUNCE_SHIFT);
+			mask |= DA7219_JACKDET_DEBOUNCE_MASK;
+		}
+		switch (aad_pdata->jack_det_rate) {
+		case DA7219_AAD_JACK_DET_RATE_32_64MS:
+		case DA7219_AAD_JACK_DET_RATE_64_128MS:
+		case DA7219_AAD_JACK_DET_RATE_128_256MS:
+		case DA7219_AAD_JACK_DET_RATE_256_512MS:
+			cfg |= (aad_pdata->jack_det_rate <<
+				DA7219_JACK_DETECT_RATE_SHIFT);
+			mask |= DA7219_JACK_DETECT_RATE_MASK;
+		}
+		switch (aad_pdata->jack_rem_deb) {
+		case DA7219_AAD_JACK_REM_DEB_1MS:
+		case DA7219_AAD_JACK_REM_DEB_5MS:
+		case DA7219_AAD_JACK_REM_DEB_10MS:
+		case DA7219_AAD_JACK_REM_DEB_20MS:
+			cfg |= (aad_pdata->jack_rem_deb <<
+				DA7219_JACKDET_REM_DEB_SHIFT);
+			mask |= DA7219_JACKDET_REM_DEB_MASK;
+		}
+		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_2, mask, cfg);
+
+		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_3,
+			      aad_pdata->a_d_btn_thr);
+		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_4,
+			      aad_pdata->d_b_btn_thr);
+		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_5,
+			      aad_pdata->b_c_btn_thr);
+		snd_soc_component_write(component, DA7219_ACCDET_CONFIG_6,
+			      aad_pdata->c_mic_btn_thr);
+
+		cfg = 0;
+		mask = 0;
+		switch (aad_pdata->btn_avg) {
+		case DA7219_AAD_BTN_AVG_1:
+		case DA7219_AAD_BTN_AVG_2:
+		case DA7219_AAD_BTN_AVG_4:
+		case DA7219_AAD_BTN_AVG_8:
+			cfg |= (aad_pdata->btn_avg <<
+				DA7219_BUTTON_AVERAGE_SHIFT);
+			mask |= DA7219_BUTTON_AVERAGE_MASK;
+		}
+		switch (aad_pdata->adc_1bit_rpt) {
+		case DA7219_AAD_ADC_1BIT_RPT_1:
+		case DA7219_AAD_ADC_1BIT_RPT_2:
+		case DA7219_AAD_ADC_1BIT_RPT_4:
+		case DA7219_AAD_ADC_1BIT_RPT_8:
+			cfg |= (aad_pdata->adc_1bit_rpt <<
+			       DA7219_ADC_1_BIT_REPEAT_SHIFT);
+			mask |= DA7219_ADC_1_BIT_REPEAT_MASK;
+		}
+		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_7, mask, cfg);
+	}
+}
+
+
+/*
+ * Suspend/Resume
+ */
+
+void da7219_aad_suspend(struct snd_soc_component *component)
+{
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	struct da7219_aad_priv *da7219_aad = da7219->aad;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	u8 micbias_ctrl;
+
+	if (da7219_aad->jack) {
+		/* Disable jack detection during suspend */
+		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
+				    DA7219_ACCDET_EN_MASK, 0);
+
+		/*
+		 * If we have a 4-pole jack inserted, then micbias will be
+		 * enabled. We can disable micbias here, and keep a note to
+		 * re-enable it on resume. If jack removal occurred during
+		 * suspend then this will be dealt with through the IRQ handler.
+		 */
+		if (da7219_aad->jack_inserted) {
+			micbias_ctrl = snd_soc_component_read32(component, DA7219_MICBIAS_CTRL);
+			if (micbias_ctrl & DA7219_MICBIAS1_EN_MASK) {
+				snd_soc_dapm_disable_pin(dapm, "Mic Bias");
+				snd_soc_dapm_sync(dapm);
+				da7219_aad->micbias_resume_enable = true;
+			}
+		}
+	}
+}
+
+void da7219_aad_resume(struct snd_soc_component *component)
+{
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	struct da7219_aad_priv *da7219_aad = da7219->aad;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	if (da7219_aad->jack) {
+		/* Re-enable micbias if previously enabled for 4-pole jack */
+		if (da7219_aad->jack_inserted &&
+		    da7219_aad->micbias_resume_enable) {
+			snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
+			snd_soc_dapm_sync(dapm);
+			da7219_aad->micbias_resume_enable = false;
+		}
+
+		/* Re-enable jack detection */
+		snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
+				    DA7219_ACCDET_EN_MASK,
+				    DA7219_ACCDET_EN_MASK);
+	}
+}
+
+
+/*
+ * Init/Exit
+ */
+
+int da7219_aad_init(struct snd_soc_component *component)
+{
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	struct da7219_aad_priv *da7219_aad;
+	u8 mask[DA7219_AAD_IRQ_REG_MAX];
+	int ret;
+
+	da7219_aad = devm_kzalloc(component->dev, sizeof(*da7219_aad), GFP_KERNEL);
+	if (!da7219_aad)
+		return -ENOMEM;
+
+	da7219->aad = da7219_aad;
+	da7219_aad->component = component;
+
+	/* Handle any DT/ACPI/platform data */
+	if (da7219->pdata && !da7219->pdata->aad_pdata)
+		da7219->pdata->aad_pdata = da7219_aad_fw_to_pdata(component);
+
+	da7219_aad_handle_pdata(component);
+
+	/* Disable button detection */
+	snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
+			    DA7219_BUTTON_CONFIG_MASK, 0);
+
+	INIT_WORK(&da7219_aad->btn_det_work, da7219_aad_btn_det_work);
+	INIT_WORK(&da7219_aad->hptest_work, da7219_aad_hptest_work);
+
+	ret = request_threaded_irq(da7219_aad->irq, NULL,
+				   da7219_aad_irq_thread,
+				   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				   "da7219-aad", da7219_aad);
+	if (ret) {
+		dev_err(component->dev, "Failed to request IRQ: %d\n", ret);
+		return ret;
+	}
+
+	/* Unmask AAD IRQs */
+	memset(mask, 0, DA7219_AAD_IRQ_REG_MAX);
+	regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,
+			  &mask, DA7219_AAD_IRQ_REG_MAX);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(da7219_aad_init);
+
+void da7219_aad_exit(struct snd_soc_component *component)
+{
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	struct da7219_aad_priv *da7219_aad = da7219->aad;
+	u8 mask[DA7219_AAD_IRQ_REG_MAX];
+
+	/* Mask off AAD IRQs */
+	memset(mask, DA7219_BYTE_MASK, DA7219_AAD_IRQ_REG_MAX);
+	regmap_bulk_write(da7219->regmap, DA7219_ACCDET_IRQ_MASK_A,
+			  mask, DA7219_AAD_IRQ_REG_MAX);
+
+	free_irq(da7219_aad->irq, da7219_aad);
+
+	cancel_work_sync(&da7219_aad->btn_det_work);
+	cancel_work_sync(&da7219_aad->hptest_work);
+}
+EXPORT_SYMBOL_GPL(da7219_aad_exit);
+
+MODULE_DESCRIPTION("ASoC DA7219 AAD Driver");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da7219-aad.h b/sound/soc/codecs/da7219-aad.h
new file mode 100644
index 0000000..b9c4a27
--- /dev/null
+++ b/sound/soc/codecs/da7219-aad.h
@@ -0,0 +1,219 @@
+/*
+ * da7219-aad.h - DA7322 ASoC AAD Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor Ltd.
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __DA7219_AAD_H
+#define __DA7219_AAD_H
+
+#include <linux/timer.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/da7219-aad.h>
+
+/*
+ * Registers
+ */
+
+#define DA7219_ACCDET_STATUS_A		0xC0
+#define DA7219_ACCDET_STATUS_B		0xC1
+#define DA7219_ACCDET_IRQ_EVENT_A	0xC2
+#define DA7219_ACCDET_IRQ_EVENT_B	0xC3
+#define DA7219_ACCDET_IRQ_MASK_A	0xC4
+#define DA7219_ACCDET_IRQ_MASK_B	0xC5
+#define DA7219_ACCDET_CONFIG_1		0xC6
+#define DA7219_ACCDET_CONFIG_2		0xC7
+#define DA7219_ACCDET_CONFIG_3		0xC8
+#define DA7219_ACCDET_CONFIG_4		0xC9
+#define DA7219_ACCDET_CONFIG_5		0xCA
+#define DA7219_ACCDET_CONFIG_6		0xCB
+#define DA7219_ACCDET_CONFIG_7		0xCC
+#define DA7219_ACCDET_CONFIG_8		0xCD
+
+
+/*
+ * Bit Fields
+ */
+
+/* DA7219_ACCDET_STATUS_A = 0xC0 */
+#define DA7219_JACK_INSERTION_STS_SHIFT	0
+#define DA7219_JACK_INSERTION_STS_MASK	(0x1 << 0)
+#define DA7219_JACK_TYPE_STS_SHIFT	1
+#define DA7219_JACK_TYPE_STS_MASK	(0x1 << 1)
+#define DA7219_JACK_PIN_ORDER_STS_SHIFT	2
+#define DA7219_JACK_PIN_ORDER_STS_MASK	(0x1 << 2)
+#define DA7219_MICBIAS_UP_STS_SHIFT	3
+#define DA7219_MICBIAS_UP_STS_MASK	(0x1 << 3)
+
+/* DA7219_ACCDET_STATUS_B = 0xC1 */
+#define DA7219_BUTTON_TYPE_STS_SHIFT	0
+#define DA7219_BUTTON_TYPE_STS_MASK	(0xFF << 0)
+
+/* DA7219_ACCDET_IRQ_EVENT_A = 0xC2 */
+#define DA7219_E_JACK_INSERTED_SHIFT		0
+#define DA7219_E_JACK_INSERTED_MASK		(0x1 << 0)
+#define DA7219_E_JACK_REMOVED_SHIFT		1
+#define DA7219_E_JACK_REMOVED_MASK		(0x1 << 1)
+#define DA7219_E_JACK_DETECT_COMPLETE_SHIFT	2
+#define DA7219_E_JACK_DETECT_COMPLETE_MASK	(0x1 << 2)
+
+/* DA7219_ACCDET_IRQ_EVENT_B = 0xC3 */
+#define DA7219_E_BUTTON_A_PRESSED_SHIFT		0
+#define DA7219_E_BUTTON_A_PRESSED_MASK		(0x1 << 0)
+#define DA7219_E_BUTTON_B_PRESSED_SHIFT		1
+#define DA7219_E_BUTTON_B_PRESSED_MASK		(0x1 << 1)
+#define DA7219_E_BUTTON_C_PRESSED_SHIFT		2
+#define DA7219_E_BUTTON_C_PRESSED_MASK		(0x1 << 2)
+#define DA7219_E_BUTTON_D_PRESSED_SHIFT		3
+#define DA7219_E_BUTTON_D_PRESSED_MASK		(0x1 << 3)
+#define DA7219_E_BUTTON_D_RELEASED_SHIFT	4
+#define DA7219_E_BUTTON_D_RELEASED_MASK		(0x1 << 4)
+#define DA7219_E_BUTTON_C_RELEASED_SHIFT	5
+#define DA7219_E_BUTTON_C_RELEASED_MASK		(0x1 << 5)
+#define DA7219_E_BUTTON_B_RELEASED_SHIFT	6
+#define DA7219_E_BUTTON_B_RELEASED_MASK		(0x1 << 6)
+#define DA7219_E_BUTTON_A_RELEASED_SHIFT	7
+#define DA7219_E_BUTTON_A_RELEASED_MASK		(0x1 << 7)
+
+/* DA7219_ACCDET_IRQ_MASK_A = 0xC4 */
+#define DA7219_M_JACK_INSERTED_SHIFT		0
+#define DA7219_M_JACK_INSERTED_MASK		(0x1 << 0)
+#define DA7219_M_JACK_REMOVED_SHIFT		1
+#define DA7219_M_JACK_REMOVED_MASK		(0x1 << 1)
+#define DA7219_M_JACK_DETECT_COMPLETE_SHIFT	2
+#define DA7219_M_JACK_DETECT_COMPLETE_MASK	(0x1 << 2)
+
+/* DA7219_ACCDET_IRQ_MASK_B = 0xC5 */
+#define DA7219_M_BUTTON_A_PRESSED_SHIFT		0
+#define DA7219_M_BUTTON_A_PRESSED_MASK		(0x1 << 0)
+#define DA7219_M_BUTTON_B_PRESSED_SHIFT		1
+#define DA7219_M_BUTTON_B_PRESSED_MASK		(0x1 << 1)
+#define DA7219_M_BUTTON_C_PRESSED_SHIFT		2
+#define DA7219_M_BUTTON_C_PRESSED_MASK		(0x1 << 2)
+#define DA7219_M_BUTTON_D_PRESSED_SHIFT		3
+#define DA7219_M_BUTTON_D_PRESSED_MASK		(0x1 << 3)
+#define DA7219_M_BUTTON_D_RELEASED_SHIFT	4
+#define DA7219_M_BUTTON_D_RELEASED_MASK		(0x1 << 4)
+#define DA7219_M_BUTTON_C_RELEASED_SHIFT	5
+#define DA7219_M_BUTTON_C_RELEASED_MASK		(0x1 << 5)
+#define DA7219_M_BUTTON_B_RELEASED_SHIFT	6
+#define DA7219_M_BUTTON_B_RELEASED_MASK		(0x1 << 6)
+#define DA7219_M_BUTTON_A_RELEASED_SHIFT	7
+#define DA7219_M_BUTTON_A_RELEASED_MASK		(0x1 << 7)
+
+/* DA7219_ACCDET_CONFIG_1 = 0xC6 */
+#define DA7219_ACCDET_EN_SHIFT		0
+#define DA7219_ACCDET_EN_MASK		(0x1 << 0)
+#define DA7219_BUTTON_CONFIG_SHIFT	1
+#define DA7219_BUTTON_CONFIG_MASK	(0x7 << 1)
+#define DA7219_MIC_DET_THRESH_SHIFT	4
+#define DA7219_MIC_DET_THRESH_MASK	(0x3 << 4)
+#define DA7219_JACK_TYPE_DET_EN_SHIFT	6
+#define DA7219_JACK_TYPE_DET_EN_MASK	(0x1 << 6)
+#define DA7219_PIN_ORDER_DET_EN_SHIFT	7
+#define DA7219_PIN_ORDER_DET_EN_MASK	(0x1 << 7)
+
+/* DA7219_ACCDET_CONFIG_2 = 0xC7 */
+#define DA7219_ACCDET_PAUSE_SHIFT	0
+#define DA7219_ACCDET_PAUSE_MASK	(0x1 << 0)
+#define DA7219_JACKDET_DEBOUNCE_SHIFT	1
+#define DA7219_JACKDET_DEBOUNCE_MASK	(0x7 << 1)
+#define DA7219_JACK_DETECT_RATE_SHIFT	4
+#define DA7219_JACK_DETECT_RATE_MASK	(0x3 << 4)
+#define DA7219_JACKDET_REM_DEB_SHIFT	6
+#define DA7219_JACKDET_REM_DEB_MASK	(0x3 << 6)
+
+/* DA7219_ACCDET_CONFIG_3 = 0xC8 */
+#define DA7219_A_D_BUTTON_THRESH_SHIFT	0
+#define DA7219_A_D_BUTTON_THRESH_MASK	(0xFF << 0)
+
+/* DA7219_ACCDET_CONFIG_4 = 0xC9 */
+#define DA7219_D_B_BUTTON_THRESH_SHIFT	0
+#define DA7219_D_B_BUTTON_THRESH_MASK	(0xFF << 0)
+
+/* DA7219_ACCDET_CONFIG_5 = 0xCA */
+#define DA7219_B_C_BUTTON_THRESH_SHIFT	0
+#define DA7219_B_C_BUTTON_THRESH_MASK	(0xFF << 0)
+
+/* DA7219_ACCDET_CONFIG_6 = 0xCB */
+#define DA7219_C_MIC_BUTTON_THRESH_SHIFT	0
+#define DA7219_C_MIC_BUTTON_THRESH_MASK		(0xFF << 0)
+
+/* DA7219_ACCDET_CONFIG_7 = 0xCC */
+#define DA7219_BUTTON_AVERAGE_SHIFT	0
+#define DA7219_BUTTON_AVERAGE_MASK	(0x3 << 0)
+#define DA7219_ADC_1_BIT_REPEAT_SHIFT	2
+#define DA7219_ADC_1_BIT_REPEAT_MASK	(0x3 << 2)
+#define DA7219_PIN_ORDER_FORCE_SHIFT	4
+#define DA7219_PIN_ORDER_FORCE_MASK	(0x1 << 4)
+#define DA7219_JACK_TYPE_FORCE_SHIFT	5
+#define DA7219_JACK_TYPE_FORCE_MASK	(0x1 << 5)
+
+/* DA7219_ACCDET_CONFIG_8 = 0xCD */
+#define DA7219_HPTEST_EN_SHIFT		0
+#define DA7219_HPTEST_EN_MASK		(0x1 << 0)
+#define DA7219_HPTEST_RES_SEL_SHIFT	1
+#define DA7219_HPTEST_RES_SEL_MASK	(0x3 << 1)
+#define DA7219_HPTEST_RES_SEL_1KOHMS	(0x0 << 1)
+#define DA7219_HPTEST_COMP_SHIFT	4
+#define DA7219_HPTEST_COMP_MASK		(0x1 << 4)
+
+
+#define DA7219_AAD_MAX_BUTTONS		4
+#define DA7219_AAD_REPORT_ALL_MASK	(SND_JACK_MECHANICAL |			\
+					 SND_JACK_HEADSET | SND_JACK_LINEOUT |	\
+					 SND_JACK_BTN_0 | SND_JACK_BTN_1 |	\
+					 SND_JACK_BTN_2 | SND_JACK_BTN_3)
+
+#define DA7219_AAD_MICBIAS_CHK_DELAY	10
+#define DA7219_AAD_MICBIAS_CHK_RETRIES	5
+
+#define DA7219_AAD_HPTEST_RAMP_FREQ		0x28
+#define DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC	0x4D
+#define DA7219_AAD_HPTEST_PERIOD		65
+#define DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY	20
+
+enum da7219_aad_event_regs {
+	DA7219_AAD_IRQ_REG_A = 0,
+	DA7219_AAD_IRQ_REG_B,
+	DA7219_AAD_IRQ_REG_MAX,
+};
+
+/* Private data */
+struct da7219_aad_priv {
+	struct snd_soc_component *component;
+	int irq;
+
+	u8 micbias_pulse_lvl;
+	u32 micbias_pulse_time;
+
+	u8 btn_cfg;
+
+	struct work_struct btn_det_work;
+	struct work_struct hptest_work;
+
+	struct snd_soc_jack *jack;
+	bool micbias_resume_enable;
+	bool jack_inserted;
+};
+
+/* AAD control */
+void da7219_aad_jack_det(struct snd_soc_component *component, struct snd_soc_jack *jack);
+
+/* Suspend/Resume */
+void da7219_aad_suspend(struct snd_soc_component *component);
+void da7219_aad_resume(struct snd_soc_component *component);
+
+/* Init/Exit */
+int da7219_aad_init(struct snd_soc_component *component);
+void da7219_aad_exit(struct snd_soc_component *component);
+
+#endif /* __DA7219_AAD_H */
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
new file mode 100644
index 0000000..e46e9f4
--- /dev/null
+++ b/sound/soc/codecs/da7219.c
@@ -0,0 +1,2288 @@
+/*
+ * da7219.c - DA7219 ALSA SoC Codec Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+
+#include <sound/da7219.h>
+#include "da7219.h"
+#include "da7219-aad.h"
+
+
+/*
+ * TLVs and Enums
+ */
+
+/* Input TLVs */
+static const DECLARE_TLV_DB_SCALE(da7219_mic_gain_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_mixin_gain_tlv, -450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_adc_dig_gain_tlv, -8325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_alc_threshold_tlv, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_alc_gain_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_alc_ana_gain_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_sidetone_gain_tlv, -4200, 300, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_tonegen_gain_tlv, -4500, 300, 0);
+
+/* Output TLVs */
+static const DECLARE_TLV_DB_SCALE(da7219_dac_eq_band_tlv, -1050, 150, 0);
+
+static const DECLARE_TLV_DB_RANGE(da7219_dac_dig_gain_tlv,
+	0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+	/* -77.25dB to 12dB */
+	0x08, 0x7f, TLV_DB_SCALE_ITEM(-7725, 75, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(da7219_dac_ng_threshold_tlv, -10200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7219_hp_gain_tlv, -5700, 100, 0);
+
+/* Input Enums */
+static const char * const da7219_alc_attack_rate_txt[] = {
+	"7.33/fs", "14.66/fs", "29.32/fs", "58.64/fs", "117.3/fs", "234.6/fs",
+	"469.1/fs", "938.2/fs", "1876/fs", "3753/fs", "7506/fs", "15012/fs",
+	"30024/fs"
+};
+
+static const struct soc_enum da7219_alc_attack_rate =
+	SOC_ENUM_SINGLE(DA7219_ALC_CTRL2, DA7219_ALC_ATTACK_SHIFT,
+			DA7219_ALC_ATTACK_MAX, da7219_alc_attack_rate_txt);
+
+static const char * const da7219_alc_release_rate_txt[] = {
+	"28.66/fs", "57.33/fs", "114.6/fs", "229.3/fs", "458.6/fs", "917.1/fs",
+	"1834/fs", "3668/fs", "7337/fs", "14674/fs", "29348/fs"
+};
+
+static const struct soc_enum da7219_alc_release_rate =
+	SOC_ENUM_SINGLE(DA7219_ALC_CTRL2, DA7219_ALC_RELEASE_SHIFT,
+			DA7219_ALC_RELEASE_MAX, da7219_alc_release_rate_txt);
+
+static const char * const da7219_alc_hold_time_txt[] = {
+	"62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs",
+	"7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs",
+	"253952/fs", "507904/fs", "1015808/fs", "2031616/fs"
+};
+
+static const struct soc_enum da7219_alc_hold_time =
+	SOC_ENUM_SINGLE(DA7219_ALC_CTRL3, DA7219_ALC_HOLD_SHIFT,
+			DA7219_ALC_HOLD_MAX, da7219_alc_hold_time_txt);
+
+static const char * const da7219_alc_env_rate_txt[] = {
+	"1/4", "1/16", "1/256", "1/65536"
+};
+
+static const struct soc_enum da7219_alc_env_attack_rate =
+	SOC_ENUM_SINGLE(DA7219_ALC_CTRL3, DA7219_ALC_INTEG_ATTACK_SHIFT,
+			DA7219_ALC_INTEG_MAX, da7219_alc_env_rate_txt);
+
+static const struct soc_enum da7219_alc_env_release_rate =
+	SOC_ENUM_SINGLE(DA7219_ALC_CTRL3, DA7219_ALC_INTEG_RELEASE_SHIFT,
+			DA7219_ALC_INTEG_MAX, da7219_alc_env_rate_txt);
+
+static const char * const da7219_alc_anticlip_step_txt[] = {
+	"0.034dB/fs", "0.068dB/fs", "0.136dB/fs", "0.272dB/fs"
+};
+
+static const struct soc_enum da7219_alc_anticlip_step =
+	SOC_ENUM_SINGLE(DA7219_ALC_ANTICLIP_CTRL,
+			DA7219_ALC_ANTICLIP_STEP_SHIFT,
+			DA7219_ALC_ANTICLIP_STEP_MAX,
+			da7219_alc_anticlip_step_txt);
+
+/* Input/Output Enums */
+static const char * const da7219_gain_ramp_rate_txt[] = {
+	"Nominal Rate * 8", "Nominal Rate", "Nominal Rate / 8",
+	"Nominal Rate / 16"
+};
+
+static const struct soc_enum da7219_gain_ramp_rate =
+	SOC_ENUM_SINGLE(DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_SHIFT,
+			DA7219_GAIN_RAMP_RATE_MAX, da7219_gain_ramp_rate_txt);
+
+static const char * const da7219_hpf_mode_txt[] = {
+	"Disabled", "Audio", "Voice"
+};
+
+static const unsigned int da7219_hpf_mode_val[] = {
+	DA7219_HPF_DISABLED, DA7219_HPF_AUDIO_EN, DA7219_HPF_VOICE_EN,
+};
+
+static const struct soc_enum da7219_adc_hpf_mode =
+	SOC_VALUE_ENUM_SINGLE(DA7219_ADC_FILTERS1, DA7219_HPF_MODE_SHIFT,
+			      DA7219_HPF_MODE_MASK, DA7219_HPF_MODE_MAX,
+			      da7219_hpf_mode_txt, da7219_hpf_mode_val);
+
+static const struct soc_enum da7219_dac_hpf_mode =
+	SOC_VALUE_ENUM_SINGLE(DA7219_DAC_FILTERS1, DA7219_HPF_MODE_SHIFT,
+			      DA7219_HPF_MODE_MASK, DA7219_HPF_MODE_MAX,
+			      da7219_hpf_mode_txt, da7219_hpf_mode_val);
+
+static const char * const da7219_audio_hpf_corner_txt[] = {
+	"2Hz", "4Hz", "8Hz", "16Hz"
+};
+
+static const struct soc_enum da7219_adc_audio_hpf_corner =
+	SOC_ENUM_SINGLE(DA7219_ADC_FILTERS1,
+			DA7219_ADC_AUDIO_HPF_CORNER_SHIFT,
+			DA7219_AUDIO_HPF_CORNER_MAX,
+			da7219_audio_hpf_corner_txt);
+
+static const struct soc_enum da7219_dac_audio_hpf_corner =
+	SOC_ENUM_SINGLE(DA7219_DAC_FILTERS1,
+			DA7219_DAC_AUDIO_HPF_CORNER_SHIFT,
+			DA7219_AUDIO_HPF_CORNER_MAX,
+			da7219_audio_hpf_corner_txt);
+
+static const char * const da7219_voice_hpf_corner_txt[] = {
+	"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static const struct soc_enum da7219_adc_voice_hpf_corner =
+	SOC_ENUM_SINGLE(DA7219_ADC_FILTERS1,
+			DA7219_ADC_VOICE_HPF_CORNER_SHIFT,
+			DA7219_VOICE_HPF_CORNER_MAX,
+			da7219_voice_hpf_corner_txt);
+
+static const struct soc_enum da7219_dac_voice_hpf_corner =
+	SOC_ENUM_SINGLE(DA7219_DAC_FILTERS1,
+			DA7219_DAC_VOICE_HPF_CORNER_SHIFT,
+			DA7219_VOICE_HPF_CORNER_MAX,
+			da7219_voice_hpf_corner_txt);
+
+static const char * const da7219_tonegen_dtmf_key_txt[] = {
+	"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D",
+	"*", "#"
+};
+
+static const struct soc_enum da7219_tonegen_dtmf_key =
+	SOC_ENUM_SINGLE(DA7219_TONE_GEN_CFG1, DA7219_DTMF_REG_SHIFT,
+			DA7219_DTMF_REG_MAX, da7219_tonegen_dtmf_key_txt);
+
+static const char * const da7219_tonegen_swg_sel_txt[] = {
+	"Sum", "SWG1", "SWG2", "SWG1_1-Cos"
+};
+
+static const struct soc_enum da7219_tonegen_swg_sel =
+	SOC_ENUM_SINGLE(DA7219_TONE_GEN_CFG2, DA7219_SWG_SEL_SHIFT,
+			DA7219_SWG_SEL_MAX, da7219_tonegen_swg_sel_txt);
+
+/* Output Enums */
+static const char * const da7219_dac_softmute_rate_txt[] = {
+	"1 Sample", "2 Samples", "4 Samples", "8 Samples", "16 Samples",
+	"32 Samples", "64 Samples"
+};
+
+static const struct soc_enum da7219_dac_softmute_rate =
+	SOC_ENUM_SINGLE(DA7219_DAC_FILTERS5, DA7219_DAC_SOFTMUTE_RATE_SHIFT,
+			DA7219_DAC_SOFTMUTE_RATE_MAX,
+			da7219_dac_softmute_rate_txt);
+
+static const char * const da7219_dac_ng_setup_time_txt[] = {
+	"256 Samples", "512 Samples", "1024 Samples", "2048 Samples"
+};
+
+static const struct soc_enum da7219_dac_ng_setup_time =
+	SOC_ENUM_SINGLE(DA7219_DAC_NG_SETUP_TIME,
+			DA7219_DAC_NG_SETUP_TIME_SHIFT,
+			DA7219_DAC_NG_SETUP_TIME_MAX,
+			da7219_dac_ng_setup_time_txt);
+
+static const char * const da7219_dac_ng_rampup_txt[] = {
+	"0.22ms/dB", "0.0138ms/dB"
+};
+
+static const struct soc_enum da7219_dac_ng_rampup_rate =
+	SOC_ENUM_SINGLE(DA7219_DAC_NG_SETUP_TIME,
+			DA7219_DAC_NG_RAMPUP_RATE_SHIFT,
+			DA7219_DAC_NG_RAMP_RATE_MAX,
+			da7219_dac_ng_rampup_txt);
+
+static const char * const da7219_dac_ng_rampdown_txt[] = {
+	"0.88ms/dB", "14.08ms/dB"
+};
+
+static const struct soc_enum da7219_dac_ng_rampdown_rate =
+	SOC_ENUM_SINGLE(DA7219_DAC_NG_SETUP_TIME,
+			DA7219_DAC_NG_RAMPDN_RATE_SHIFT,
+			DA7219_DAC_NG_RAMP_RATE_MAX,
+			da7219_dac_ng_rampdown_txt);
+
+
+static const char * const da7219_cp_track_mode_txt[] = {
+	"Largest Volume", "DAC Volume", "Signal Magnitude"
+};
+
+static const unsigned int da7219_cp_track_mode_val[] = {
+	DA7219_CP_MCHANGE_LARGEST_VOL, DA7219_CP_MCHANGE_DAC_VOL,
+	DA7219_CP_MCHANGE_SIG_MAG
+};
+
+static const struct soc_enum da7219_cp_track_mode =
+	SOC_VALUE_ENUM_SINGLE(DA7219_CP_CTRL, DA7219_CP_MCHANGE_SHIFT,
+			      DA7219_CP_MCHANGE_REL_MASK, DA7219_CP_MCHANGE_MAX,
+			      da7219_cp_track_mode_txt,
+			      da7219_cp_track_mode_val);
+
+
+/*
+ * Control Functions
+ */
+
+/* Locked Kcontrol calls */
+static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	mutex_lock(&da7219->ctrl_lock);
+	ret = snd_soc_get_volsw(kcontrol, ucontrol);
+	mutex_unlock(&da7219->ctrl_lock);
+
+	return ret;
+}
+
+static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	mutex_lock(&da7219->ctrl_lock);
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+	mutex_unlock(&da7219->ctrl_lock);
+
+	return ret;
+}
+
+static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	mutex_lock(&da7219->ctrl_lock);
+	ret = snd_soc_get_enum_double(kcontrol, ucontrol);
+	mutex_unlock(&da7219->ctrl_lock);
+
+	return ret;
+}
+
+static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	mutex_lock(&da7219->ctrl_lock);
+	ret = snd_soc_put_enum_double(kcontrol, ucontrol);
+	mutex_unlock(&da7219->ctrl_lock);
+
+	return ret;
+}
+
+/* ALC */
+static void da7219_alc_calib(struct snd_soc_component *component)
+{
+	u8 mic_ctrl, mixin_ctrl, adc_ctrl, calib_ctrl;
+
+	/* Save current state of mic control register */
+	mic_ctrl = snd_soc_component_read32(component, DA7219_MIC_1_CTRL);
+
+	/* Save current state of input mixer control register */
+	mixin_ctrl = snd_soc_component_read32(component, DA7219_MIXIN_L_CTRL);
+
+	/* Save current state of input ADC control register */
+	adc_ctrl = snd_soc_component_read32(component, DA7219_ADC_L_CTRL);
+
+	/* Enable then Mute MIC PGAs */
+	snd_soc_component_update_bits(component, DA7219_MIC_1_CTRL, DA7219_MIC_1_AMP_EN_MASK,
+			    DA7219_MIC_1_AMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7219_MIC_1_CTRL,
+			    DA7219_MIC_1_AMP_MUTE_EN_MASK,
+			    DA7219_MIC_1_AMP_MUTE_EN_MASK);
+
+	/* Enable input mixers unmuted */
+	snd_soc_component_update_bits(component, DA7219_MIXIN_L_CTRL,
+			    DA7219_MIXIN_L_AMP_EN_MASK |
+			    DA7219_MIXIN_L_AMP_MUTE_EN_MASK,
+			    DA7219_MIXIN_L_AMP_EN_MASK);
+
+	/* Enable input filters unmuted */
+	snd_soc_component_update_bits(component, DA7219_ADC_L_CTRL,
+			    DA7219_ADC_L_MUTE_EN_MASK | DA7219_ADC_L_EN_MASK,
+			    DA7219_ADC_L_EN_MASK);
+
+	/* Perform auto calibration */
+	snd_soc_component_update_bits(component, DA7219_ALC_CTRL1,
+			    DA7219_ALC_AUTO_CALIB_EN_MASK,
+			    DA7219_ALC_AUTO_CALIB_EN_MASK);
+	do {
+		calib_ctrl = snd_soc_component_read32(component, DA7219_ALC_CTRL1);
+	} while (calib_ctrl & DA7219_ALC_AUTO_CALIB_EN_MASK);
+
+	/* If auto calibration fails, disable DC offset, hybrid ALC */
+	if (calib_ctrl & DA7219_ALC_CALIB_OVERFLOW_MASK) {
+		dev_warn(component->dev,
+			 "ALC auto calibration failed with overflow\n");
+		snd_soc_component_update_bits(component, DA7219_ALC_CTRL1,
+				    DA7219_ALC_OFFSET_EN_MASK |
+				    DA7219_ALC_SYNC_MODE_MASK, 0);
+	} else {
+		/* Enable DC offset cancellation, hybrid mode */
+		snd_soc_component_update_bits(component, DA7219_ALC_CTRL1,
+				    DA7219_ALC_OFFSET_EN_MASK |
+				    DA7219_ALC_SYNC_MODE_MASK,
+				    DA7219_ALC_OFFSET_EN_MASK |
+				    DA7219_ALC_SYNC_MODE_MASK);
+	}
+
+	/* Restore input filter control register to original state */
+	snd_soc_component_write(component, DA7219_ADC_L_CTRL, adc_ctrl);
+
+	/* Restore input mixer control registers to original state */
+	snd_soc_component_write(component, DA7219_MIXIN_L_CTRL, mixin_ctrl);
+
+	/* Restore MIC control registers to original states */
+	snd_soc_component_write(component, DA7219_MIC_1_CTRL, mic_ctrl);
+}
+
+static int da7219_mixin_gain_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+	/*
+	 * If ALC in operation and value of control has been updated,
+	 * make sure calibrated offsets are updated.
+	 */
+	if ((ret == 1) && (da7219->alc_en))
+		da7219_alc_calib(component);
+
+	return ret;
+}
+
+static int da7219_alc_sw_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+
+
+	/* Force ALC offset calibration if enabling ALC */
+	if ((ucontrol->value.integer.value[0]) && (!da7219->alc_en)) {
+		da7219_alc_calib(component);
+		da7219->alc_en = true;
+	} else {
+		da7219->alc_en = false;
+	}
+
+	return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+/* ToneGen */
+static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	struct soc_mixer_control *mixer_ctrl =
+		(struct soc_mixer_control *) kcontrol->private_value;
+	unsigned int reg = mixer_ctrl->reg;
+	u16 val;
+	int ret;
+
+	mutex_lock(&da7219->ctrl_lock);
+	ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val));
+	mutex_unlock(&da7219->ctrl_lock);
+
+	if (ret)
+		return ret;
+
+	/*
+	 * Frequency value spans two 8-bit registers, lower then upper byte.
+	 * Therefore we need to convert to host endianness here.
+	 */
+	ucontrol->value.integer.value[0] = le16_to_cpu(val);
+
+	return 0;
+}
+
+static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	struct soc_mixer_control *mixer_ctrl =
+		(struct soc_mixer_control *) kcontrol->private_value;
+	unsigned int reg = mixer_ctrl->reg;
+	u16 val;
+	int ret;
+
+	/*
+	 * Frequency value spans two 8-bit registers, lower then upper byte.
+	 * Therefore we need to convert to little endian here to align with
+	 * HW registers.
+	 */
+	val = cpu_to_le16(ucontrol->value.integer.value[0]);
+
+	mutex_lock(&da7219->ctrl_lock);
+	ret = regmap_raw_write(da7219->regmap, reg, &val, sizeof(val));
+	mutex_unlock(&da7219->ctrl_lock);
+
+	return ret;
+}
+
+
+/*
+ * KControls
+ */
+
+static const struct snd_kcontrol_new da7219_snd_controls[] = {
+	/* Mics */
+	SOC_SINGLE_TLV("Mic Volume", DA7219_MIC_1_GAIN,
+		       DA7219_MIC_1_AMP_GAIN_SHIFT, DA7219_MIC_1_AMP_GAIN_MAX,
+		       DA7219_NO_INVERT, da7219_mic_gain_tlv),
+	SOC_SINGLE("Mic Switch", DA7219_MIC_1_CTRL,
+		   DA7219_MIC_1_AMP_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+		   DA7219_INVERT),
+
+	/* Mixer Input */
+	SOC_SINGLE_EXT_TLV("Mixin Volume", DA7219_MIXIN_L_GAIN,
+			   DA7219_MIXIN_L_AMP_GAIN_SHIFT,
+			   DA7219_MIXIN_L_AMP_GAIN_MAX, DA7219_NO_INVERT,
+			   snd_soc_get_volsw, da7219_mixin_gain_put,
+			   da7219_mixin_gain_tlv),
+	SOC_SINGLE("Mixin Switch", DA7219_MIXIN_L_CTRL,
+		   DA7219_MIXIN_L_AMP_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+		   DA7219_INVERT),
+	SOC_SINGLE("Mixin Gain Ramp Switch", DA7219_MIXIN_L_CTRL,
+		   DA7219_MIXIN_L_AMP_RAMP_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+		   DA7219_NO_INVERT),
+	SOC_SINGLE("Mixin ZC Gain Switch", DA7219_MIXIN_L_CTRL,
+		   DA7219_MIXIN_L_AMP_ZC_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+		   DA7219_NO_INVERT),
+
+	/* ADC */
+	SOC_SINGLE_TLV("Capture Digital Volume", DA7219_ADC_L_GAIN,
+		       DA7219_ADC_L_DIGITAL_GAIN_SHIFT,
+		       DA7219_ADC_L_DIGITAL_GAIN_MAX, DA7219_NO_INVERT,
+		       da7219_adc_dig_gain_tlv),
+	SOC_SINGLE("Capture Digital Switch", DA7219_ADC_L_CTRL,
+		   DA7219_ADC_L_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+		   DA7219_INVERT),
+	SOC_SINGLE("Capture Digital Gain Ramp Switch", DA7219_ADC_L_CTRL,
+		   DA7219_ADC_L_RAMP_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+		   DA7219_NO_INVERT),
+
+	/* ALC */
+	SOC_ENUM("ALC Attack Rate", da7219_alc_attack_rate),
+	SOC_ENUM("ALC Release Rate", da7219_alc_release_rate),
+	SOC_ENUM("ALC Hold Time", da7219_alc_hold_time),
+	SOC_ENUM("ALC Envelope Attack Rate", da7219_alc_env_attack_rate),
+	SOC_ENUM("ALC Envelope Release Rate", da7219_alc_env_release_rate),
+	SOC_SINGLE_TLV("ALC Noise Threshold", DA7219_ALC_NOISE,
+		       DA7219_ALC_NOISE_SHIFT, DA7219_ALC_THRESHOLD_MAX,
+		       DA7219_INVERT, da7219_alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Min Threshold", DA7219_ALC_TARGET_MIN,
+		       DA7219_ALC_THRESHOLD_MIN_SHIFT, DA7219_ALC_THRESHOLD_MAX,
+		       DA7219_INVERT, da7219_alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Max Threshold", DA7219_ALC_TARGET_MAX,
+		       DA7219_ALC_THRESHOLD_MAX_SHIFT, DA7219_ALC_THRESHOLD_MAX,
+		       DA7219_INVERT, da7219_alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Max Attenuation", DA7219_ALC_GAIN_LIMITS,
+		       DA7219_ALC_ATTEN_MAX_SHIFT, DA7219_ALC_ATTEN_GAIN_MAX,
+		       DA7219_NO_INVERT, da7219_alc_gain_tlv),
+	SOC_SINGLE_TLV("ALC Max Volume", DA7219_ALC_GAIN_LIMITS,
+		       DA7219_ALC_GAIN_MAX_SHIFT, DA7219_ALC_ATTEN_GAIN_MAX,
+		       DA7219_NO_INVERT, da7219_alc_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("ALC Min Analog Volume", DA7219_ALC_ANA_GAIN_LIMITS,
+			     DA7219_ALC_ANA_GAIN_MIN_SHIFT,
+			     DA7219_ALC_ANA_GAIN_MIN, DA7219_ALC_ANA_GAIN_MAX,
+			     DA7219_NO_INVERT, da7219_alc_ana_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("ALC Max Analog Volume", DA7219_ALC_ANA_GAIN_LIMITS,
+			     DA7219_ALC_ANA_GAIN_MAX_SHIFT,
+			     DA7219_ALC_ANA_GAIN_MIN, DA7219_ALC_ANA_GAIN_MAX,
+			     DA7219_NO_INVERT, da7219_alc_ana_gain_tlv),
+	SOC_ENUM("ALC Anticlip Step", da7219_alc_anticlip_step),
+	SOC_SINGLE("ALC Anticlip Switch", DA7219_ALC_ANTICLIP_CTRL,
+		   DA7219_ALC_ANTIPCLIP_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+		   DA7219_NO_INVERT),
+	SOC_SINGLE_EXT("ALC Switch", DA7219_ALC_CTRL1, DA7219_ALC_EN_SHIFT,
+		       DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT,
+		       snd_soc_get_volsw, da7219_alc_sw_put),
+
+	/* Input High-Pass Filters */
+	SOC_ENUM("ADC HPF Mode", da7219_adc_hpf_mode),
+	SOC_ENUM("ADC HPF Corner Audio", da7219_adc_audio_hpf_corner),
+	SOC_ENUM("ADC HPF Corner Voice", da7219_adc_voice_hpf_corner),
+
+	/* Sidetone Filter */
+	SOC_SINGLE_TLV("Sidetone Volume", DA7219_SIDETONE_GAIN,
+		       DA7219_SIDETONE_GAIN_SHIFT, DA7219_SIDETONE_GAIN_MAX,
+		       DA7219_NO_INVERT, da7219_sidetone_gain_tlv),
+	SOC_SINGLE("Sidetone Switch", DA7219_SIDETONE_CTRL,
+		   DA7219_SIDETONE_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+		   DA7219_INVERT),
+
+	/* Tone Generator */
+	SOC_SINGLE_EXT_TLV("ToneGen Volume", DA7219_TONE_GEN_CFG2,
+			   DA7219_TONE_GEN_GAIN_SHIFT, DA7219_TONE_GEN_GAIN_MAX,
+			   DA7219_NO_INVERT, da7219_volsw_locked_get,
+			   da7219_volsw_locked_put, da7219_tonegen_gain_tlv),
+	SOC_ENUM_EXT("ToneGen DTMF Key", da7219_tonegen_dtmf_key,
+		     da7219_enum_locked_get, da7219_enum_locked_put),
+	SOC_SINGLE_EXT("ToneGen DTMF Switch", DA7219_TONE_GEN_CFG1,
+		       DA7219_DTMF_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+		       DA7219_NO_INVERT, da7219_volsw_locked_get,
+		       da7219_volsw_locked_put),
+	SOC_ENUM_EXT("ToneGen Sinewave Gen Type", da7219_tonegen_swg_sel,
+		     da7219_enum_locked_get, da7219_enum_locked_put),
+	SOC_SINGLE_EXT("ToneGen Sinewave1 Freq", DA7219_TONE_GEN_FREQ1_L,
+		       DA7219_FREQ1_L_SHIFT, DA7219_FREQ_MAX, DA7219_NO_INVERT,
+		       da7219_tonegen_freq_get, da7219_tonegen_freq_put),
+	SOC_SINGLE_EXT("ToneGen Sinewave2 Freq", DA7219_TONE_GEN_FREQ2_L,
+		       DA7219_FREQ2_L_SHIFT, DA7219_FREQ_MAX, DA7219_NO_INVERT,
+		       da7219_tonegen_freq_get, da7219_tonegen_freq_put),
+	SOC_SINGLE_EXT("ToneGen On Time", DA7219_TONE_GEN_ON_PER,
+		       DA7219_BEEP_ON_PER_SHIFT, DA7219_BEEP_ON_OFF_MAX,
+		       DA7219_NO_INVERT, da7219_volsw_locked_get,
+		       da7219_volsw_locked_put),
+	SOC_SINGLE("ToneGen Off Time", DA7219_TONE_GEN_OFF_PER,
+		   DA7219_BEEP_OFF_PER_SHIFT, DA7219_BEEP_ON_OFF_MAX,
+		   DA7219_NO_INVERT),
+
+	/* Gain ramping */
+	SOC_ENUM("Gain Ramp Rate", da7219_gain_ramp_rate),
+
+	/* DAC High-Pass Filter */
+	SOC_ENUM_EXT("DAC HPF Mode", da7219_dac_hpf_mode,
+		     da7219_enum_locked_get, da7219_enum_locked_put),
+	SOC_ENUM("DAC HPF Corner Audio", da7219_dac_audio_hpf_corner),
+	SOC_ENUM("DAC HPF Corner Voice", da7219_dac_voice_hpf_corner),
+
+	/* DAC 5-Band Equaliser */
+	SOC_SINGLE_TLV("DAC EQ Band1 Volume", DA7219_DAC_FILTERS2,
+		       DA7219_DAC_EQ_BAND1_SHIFT, DA7219_DAC_EQ_BAND_MAX,
+		       DA7219_NO_INVERT, da7219_dac_eq_band_tlv),
+	SOC_SINGLE_TLV("DAC EQ Band2 Volume", DA7219_DAC_FILTERS2,
+		       DA7219_DAC_EQ_BAND2_SHIFT, DA7219_DAC_EQ_BAND_MAX,
+		       DA7219_NO_INVERT, da7219_dac_eq_band_tlv),
+	SOC_SINGLE_TLV("DAC EQ Band3 Volume", DA7219_DAC_FILTERS3,
+		       DA7219_DAC_EQ_BAND3_SHIFT, DA7219_DAC_EQ_BAND_MAX,
+		       DA7219_NO_INVERT, da7219_dac_eq_band_tlv),
+	SOC_SINGLE_TLV("DAC EQ Band4 Volume", DA7219_DAC_FILTERS3,
+		       DA7219_DAC_EQ_BAND4_SHIFT, DA7219_DAC_EQ_BAND_MAX,
+		       DA7219_NO_INVERT, da7219_dac_eq_band_tlv),
+	SOC_SINGLE_TLV("DAC EQ Band5 Volume", DA7219_DAC_FILTERS4,
+		       DA7219_DAC_EQ_BAND5_SHIFT, DA7219_DAC_EQ_BAND_MAX,
+		       DA7219_NO_INVERT, da7219_dac_eq_band_tlv),
+	SOC_SINGLE_EXT("DAC EQ Switch", DA7219_DAC_FILTERS4,
+		       DA7219_DAC_EQ_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+		       DA7219_NO_INVERT, da7219_volsw_locked_get,
+		       da7219_volsw_locked_put),
+
+	/* DAC Softmute */
+	SOC_ENUM("DAC Soft Mute Rate", da7219_dac_softmute_rate),
+	SOC_SINGLE_EXT("DAC Soft Mute Switch", DA7219_DAC_FILTERS5,
+		       DA7219_DAC_SOFTMUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+		       DA7219_NO_INVERT, da7219_volsw_locked_get,
+		       da7219_volsw_locked_put),
+
+	/* DAC Noise Gate */
+	SOC_ENUM("DAC NG Setup Time", da7219_dac_ng_setup_time),
+	SOC_ENUM("DAC NG Rampup Rate", da7219_dac_ng_rampup_rate),
+	SOC_ENUM("DAC NG Rampdown Rate", da7219_dac_ng_rampdown_rate),
+	SOC_SINGLE_TLV("DAC NG Off Threshold", DA7219_DAC_NG_OFF_THRESH,
+		       DA7219_DAC_NG_OFF_THRESHOLD_SHIFT,
+		       DA7219_DAC_NG_THRESHOLD_MAX, DA7219_NO_INVERT,
+		       da7219_dac_ng_threshold_tlv),
+	SOC_SINGLE_TLV("DAC NG On Threshold", DA7219_DAC_NG_ON_THRESH,
+		       DA7219_DAC_NG_ON_THRESHOLD_SHIFT,
+		       DA7219_DAC_NG_THRESHOLD_MAX, DA7219_NO_INVERT,
+		       da7219_dac_ng_threshold_tlv),
+	SOC_SINGLE("DAC NG Switch", DA7219_DAC_NG_CTRL, DA7219_DAC_NG_EN_SHIFT,
+		   DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),
+
+	/* DACs */
+	SOC_DOUBLE_R_EXT_TLV("Playback Digital Volume", DA7219_DAC_L_GAIN,
+			     DA7219_DAC_R_GAIN, DA7219_DAC_L_DIGITAL_GAIN_SHIFT,
+			     DA7219_DAC_DIGITAL_GAIN_MAX, DA7219_NO_INVERT,
+			     da7219_volsw_locked_get, da7219_volsw_locked_put,
+			     da7219_dac_dig_gain_tlv),
+	SOC_DOUBLE_R_EXT("Playback Digital Switch", DA7219_DAC_L_CTRL,
+			 DA7219_DAC_R_CTRL, DA7219_DAC_L_MUTE_EN_SHIFT,
+			 DA7219_SWITCH_EN_MAX, DA7219_INVERT,
+			 da7219_volsw_locked_get, da7219_volsw_locked_put),
+	SOC_DOUBLE_R("Playback Digital Gain Ramp Switch", DA7219_DAC_L_CTRL,
+		     DA7219_DAC_R_CTRL, DA7219_DAC_L_RAMP_EN_SHIFT,
+		     DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),
+
+	/* CP */
+	SOC_ENUM("Charge Pump Track Mode", da7219_cp_track_mode),
+	SOC_SINGLE("Charge Pump Threshold", DA7219_CP_VOL_THRESHOLD1,
+		   DA7219_CP_THRESH_VDD2_SHIFT, DA7219_CP_THRESH_VDD2_MAX,
+		   DA7219_NO_INVERT),
+
+	/* Headphones */
+	SOC_DOUBLE_R_EXT_TLV("Headphone Volume", DA7219_HP_L_GAIN,
+			     DA7219_HP_R_GAIN, DA7219_HP_L_AMP_GAIN_SHIFT,
+			     DA7219_HP_AMP_GAIN_MAX, DA7219_NO_INVERT,
+			     da7219_volsw_locked_get, da7219_volsw_locked_put,
+			     da7219_hp_gain_tlv),
+	SOC_DOUBLE_R_EXT("Headphone Switch", DA7219_HP_L_CTRL, DA7219_HP_R_CTRL,
+			 DA7219_HP_L_AMP_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX,
+			 DA7219_INVERT, da7219_volsw_locked_get,
+			 da7219_volsw_locked_put),
+	SOC_DOUBLE_R("Headphone Gain Ramp Switch", DA7219_HP_L_CTRL,
+		     DA7219_HP_R_CTRL, DA7219_HP_L_AMP_RAMP_EN_SHIFT,
+		     DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),
+	SOC_DOUBLE_R("Headphone ZC Gain Switch", DA7219_HP_L_CTRL,
+		     DA7219_HP_R_CTRL, DA7219_HP_L_AMP_ZC_EN_SHIFT,
+		     DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),
+};
+
+
+/*
+ * DAPM Mux Controls
+ */
+
+static const char * const da7219_out_sel_txt[] = {
+	"ADC", "Tone Generator", "DAIL", "DAIR"
+};
+
+static const struct soc_enum da7219_out_dail_sel =
+	SOC_ENUM_SINGLE(DA7219_DIG_ROUTING_DAI,
+			DA7219_DAI_L_SRC_SHIFT,
+			DA7219_OUT_SRC_MAX,
+			da7219_out_sel_txt);
+
+static const struct snd_kcontrol_new da7219_out_dail_sel_mux =
+	SOC_DAPM_ENUM("Out DAIL Mux", da7219_out_dail_sel);
+
+static const struct soc_enum da7219_out_dair_sel =
+	SOC_ENUM_SINGLE(DA7219_DIG_ROUTING_DAI,
+			DA7219_DAI_R_SRC_SHIFT,
+			DA7219_OUT_SRC_MAX,
+			da7219_out_sel_txt);
+
+static const struct snd_kcontrol_new da7219_out_dair_sel_mux =
+	SOC_DAPM_ENUM("Out DAIR Mux", da7219_out_dair_sel);
+
+static const struct soc_enum da7219_out_dacl_sel =
+	SOC_ENUM_SINGLE(DA7219_DIG_ROUTING_DAC,
+			DA7219_DAC_L_SRC_SHIFT,
+			DA7219_OUT_SRC_MAX,
+			da7219_out_sel_txt);
+
+static const struct snd_kcontrol_new da7219_out_dacl_sel_mux =
+	SOC_DAPM_ENUM("Out DACL Mux", da7219_out_dacl_sel);
+
+static const struct soc_enum da7219_out_dacr_sel =
+	SOC_ENUM_SINGLE(DA7219_DIG_ROUTING_DAC,
+			DA7219_DAC_R_SRC_SHIFT,
+			DA7219_OUT_SRC_MAX,
+			da7219_out_sel_txt);
+
+static const struct snd_kcontrol_new da7219_out_dacr_sel_mux =
+	SOC_DAPM_ENUM("Out DACR Mux", da7219_out_dacr_sel);
+
+
+/*
+ * DAPM Mixer Controls
+ */
+
+static const struct snd_kcontrol_new da7219_mixin_controls[] = {
+	SOC_DAPM_SINGLE("Mic Switch", DA7219_MIXIN_L_SELECT,
+			DA7219_MIXIN_L_MIX_SELECT_SHIFT,
+			DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),
+};
+
+static const struct snd_kcontrol_new da7219_mixout_l_controls[] = {
+	SOC_DAPM_SINGLE("DACL Switch", DA7219_MIXOUT_L_SELECT,
+			DA7219_MIXOUT_L_MIX_SELECT_SHIFT,
+			DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),
+};
+
+static const struct snd_kcontrol_new da7219_mixout_r_controls[] = {
+	SOC_DAPM_SINGLE("DACR Switch", DA7219_MIXOUT_R_SELECT,
+			DA7219_MIXOUT_R_MIX_SELECT_SHIFT,
+			DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),
+};
+
+#define DA7219_DMIX_ST_CTRLS(reg)					\
+	SOC_DAPM_SINGLE("Out FilterL Switch", reg,			\
+			DA7219_DMIX_ST_SRC_OUTFILT1L_SHIFT,		\
+			DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),	\
+	SOC_DAPM_SINGLE("Out FilterR Switch", reg,			\
+			DA7219_DMIX_ST_SRC_OUTFILT1R_SHIFT,		\
+			DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT),	\
+	SOC_DAPM_SINGLE("Sidetone Switch", reg,				\
+			DA7219_DMIX_ST_SRC_SIDETONE_SHIFT,		\
+			DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT)		\
+
+static const struct snd_kcontrol_new da7219_st_out_filtl_mix_controls[] = {
+	DA7219_DMIX_ST_CTRLS(DA7219_DROUTING_ST_OUTFILT_1L),
+};
+
+static const struct snd_kcontrol_new da7219_st_out_filtr_mix_controls[] = {
+	DA7219_DMIX_ST_CTRLS(DA7219_DROUTING_ST_OUTFILT_1R),
+};
+
+
+/*
+ * DAPM Events
+ */
+
+static int da7219_mic_pga_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (da7219->micbias_on_event) {
+			/*
+			 * Delay only for first capture after bias enabled to
+			 * avoid possible DC offset related noise.
+			 */
+			da7219->micbias_on_event = false;
+			msleep(da7219->mic_pga_delay);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int da7219_dai_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	u8 pll_ctrl, pll_status;
+	int i = 0, ret;
+	bool srm_lock = false;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (da7219->master) {
+			/* Enable DAI clks for master mode */
+			if (da7219->dai_clks) {
+				ret = clk_prepare_enable(da7219->dai_clks);
+				if (ret) {
+					dev_err(component->dev,
+						"Failed to enable dai_clks\n");
+					return ret;
+				}
+			} else {
+				snd_soc_component_update_bits(component,
+							      DA7219_DAI_CLK_MODE,
+							      DA7219_DAI_CLK_EN_MASK,
+							      DA7219_DAI_CLK_EN_MASK);
+			}
+		}
+
+		/* PC synchronised to DAI */
+		snd_soc_component_update_bits(component, DA7219_PC_COUNT,
+				    DA7219_PC_FREERUN_MASK, 0);
+
+		/* Slave mode, if SRM not enabled no need for status checks */
+		pll_ctrl = snd_soc_component_read32(component, DA7219_PLL_CTRL);
+		if ((pll_ctrl & DA7219_PLL_MODE_MASK) != DA7219_PLL_MODE_SRM)
+			return 0;
+
+		/* Check SRM has locked */
+		do {
+			pll_status = snd_soc_component_read32(component, DA7219_PLL_SRM_STS);
+			if (pll_status & DA7219_PLL_SRM_STS_SRM_LOCK) {
+				srm_lock = true;
+			} else {
+				++i;
+				msleep(50);
+			}
+		} while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock));
+
+		if (!srm_lock)
+			dev_warn(component->dev, "SRM failed to lock\n");
+
+		return 0;
+	case SND_SOC_DAPM_POST_PMD:
+		/* PC free-running */
+		snd_soc_component_update_bits(component, DA7219_PC_COUNT,
+				    DA7219_PC_FREERUN_MASK,
+				    DA7219_PC_FREERUN_MASK);
+
+		/* Disable DAI clks if in master mode */
+		if (da7219->master) {
+			if (da7219->dai_clks)
+				clk_disable_unprepare(da7219->dai_clks);
+			else
+				snd_soc_component_update_bits(component,
+							      DA7219_DAI_CLK_MODE,
+							      DA7219_DAI_CLK_EN_MASK,
+							      0);
+		}
+
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int da7219_settling_event(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+	case SND_SOC_DAPM_POST_PMD:
+		msleep(DA7219_SETTLING_DELAY);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int da7219_mixout_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u8 hp_ctrl, min_gain_mask;
+
+	switch (w->reg) {
+	case DA7219_MIXOUT_L_CTRL:
+		hp_ctrl = DA7219_HP_L_CTRL;
+		min_gain_mask = DA7219_HP_L_AMP_MIN_GAIN_EN_MASK;
+		break;
+	case DA7219_MIXOUT_R_CTRL:
+		hp_ctrl = DA7219_HP_R_CTRL;
+		min_gain_mask = DA7219_HP_R_AMP_MIN_GAIN_EN_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Enable minimum gain on HP to avoid pops */
+		snd_soc_component_update_bits(component, hp_ctrl, min_gain_mask,
+				    min_gain_mask);
+
+		msleep(DA7219_MIN_GAIN_DELAY);
+
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* Remove minimum gain on HP */
+		snd_soc_component_update_bits(component, hp_ctrl, min_gain_mask, 0);
+
+		break;
+	}
+
+	return 0;
+}
+
+static int da7219_gain_ramp_event(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Ensure nominal gain ramping for DAPM sequence */
+		da7219->gain_ramp_ctrl =
+			snd_soc_component_read32(component, DA7219_GAIN_RAMP_CTRL);
+		snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL,
+			      DA7219_GAIN_RAMP_RATE_NOMINAL);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+	case SND_SOC_DAPM_POST_PMD:
+		/* Restore previous gain ramp settings */
+		snd_soc_component_write(component, DA7219_GAIN_RAMP_CTRL,
+			      da7219->gain_ramp_ctrl);
+		break;
+	}
+
+	return 0;
+}
+
+
+/*
+ * DAPM Widgets
+ */
+
+static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = {
+	/* Input Supplies */
+	SND_SOC_DAPM_SUPPLY("Mic Bias", DA7219_MICBIAS_CTRL,
+			    DA7219_MICBIAS1_EN_SHIFT, DA7219_NO_INVERT,
+			    NULL, 0),
+
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("MIC"),
+
+	/* Input PGAs */
+	SND_SOC_DAPM_PGA_E("Mic PGA", DA7219_MIC_1_CTRL,
+			   DA7219_MIC_1_AMP_EN_SHIFT, DA7219_NO_INVERT,
+			   NULL, 0, da7219_mic_pga_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_E("Mixin PGA", DA7219_MIXIN_L_CTRL,
+			   DA7219_MIXIN_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
+			   NULL, 0, da7219_settling_event, SND_SOC_DAPM_POST_PMU),
+
+	/* Input Filters */
+	SND_SOC_DAPM_ADC("ADC", NULL, DA7219_ADC_L_CTRL, DA7219_ADC_L_EN_SHIFT,
+			 DA7219_NO_INVERT),
+
+	/* Tone Generator */
+	SND_SOC_DAPM_SIGGEN("TONE"),
+	SND_SOC_DAPM_PGA("Tone Generator", DA7219_TONE_GEN_CFG1,
+			 DA7219_START_STOPN_SHIFT, DA7219_NO_INVERT, NULL, 0),
+
+	/* Sidetone Input */
+	SND_SOC_DAPM_ADC("Sidetone Filter", NULL, DA7219_SIDETONE_CTRL,
+			 DA7219_SIDETONE_EN_SHIFT, DA7219_NO_INVERT),
+
+	/* Input Mixer Supply */
+	SND_SOC_DAPM_SUPPLY("Mixer In Supply", DA7219_MIXIN_L_CTRL,
+			    DA7219_MIXIN_L_MIX_EN_SHIFT, DA7219_NO_INVERT,
+			    NULL, 0),
+
+	/* Input Mixer */
+	SND_SOC_DAPM_MIXER("Mixer In", SND_SOC_NOPM, 0, 0,
+			   da7219_mixin_controls,
+			   ARRAY_SIZE(da7219_mixin_controls)),
+
+	/* Input Muxes */
+	SND_SOC_DAPM_MUX("Out DAIL Mux", SND_SOC_NOPM, 0, 0,
+			 &da7219_out_dail_sel_mux),
+	SND_SOC_DAPM_MUX("Out DAIR Mux", SND_SOC_NOPM, 0, 0,
+			 &da7219_out_dair_sel_mux),
+
+	/* DAI Supply */
+	SND_SOC_DAPM_SUPPLY("DAI", DA7219_DAI_CTRL, DA7219_DAI_EN_SHIFT,
+			    DA7219_NO_INVERT, da7219_dai_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* DAI */
+	SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, DA7219_DAI_TDM_CTRL,
+			     DA7219_DAI_OE_SHIFT, DA7219_NO_INVERT),
+	SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Muxes */
+	SND_SOC_DAPM_MUX("Out DACL Mux", SND_SOC_NOPM, 0, 0,
+			 &da7219_out_dacl_sel_mux),
+	SND_SOC_DAPM_MUX("Out DACR Mux", SND_SOC_NOPM, 0, 0,
+			 &da7219_out_dacr_sel_mux),
+
+	/* Output Mixers */
+	SND_SOC_DAPM_MIXER("Mixer Out FilterL", SND_SOC_NOPM, 0, 0,
+			   da7219_mixout_l_controls,
+			   ARRAY_SIZE(da7219_mixout_l_controls)),
+	SND_SOC_DAPM_MIXER("Mixer Out FilterR", SND_SOC_NOPM, 0, 0,
+			   da7219_mixout_r_controls,
+			   ARRAY_SIZE(da7219_mixout_r_controls)),
+
+	/* Sidetone Mixers */
+	SND_SOC_DAPM_MIXER("ST Mixer Out FilterL", SND_SOC_NOPM, 0, 0,
+			   da7219_st_out_filtl_mix_controls,
+			   ARRAY_SIZE(da7219_st_out_filtl_mix_controls)),
+	SND_SOC_DAPM_MIXER("ST Mixer Out FilterR", SND_SOC_NOPM, 0,
+			   0, da7219_st_out_filtr_mix_controls,
+			   ARRAY_SIZE(da7219_st_out_filtr_mix_controls)),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC_E("DACL", NULL, DA7219_DAC_L_CTRL,
+			   DA7219_DAC_L_EN_SHIFT, DA7219_NO_INVERT,
+			   da7219_settling_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("DACR", NULL, DA7219_DAC_R_CTRL,
+			   DA7219_DAC_R_EN_SHIFT, DA7219_NO_INVERT,
+			   da7219_settling_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* Output PGAs */
+	SND_SOC_DAPM_PGA_E("Mixout Left PGA", DA7219_MIXOUT_L_CTRL,
+			   DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
+			   NULL, 0, da7219_mixout_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA_E("Mixout Right PGA", DA7219_MIXOUT_R_CTRL,
+			   DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT,
+			   NULL, 0, da7219_mixout_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY_S("Headphone Left PGA", 1, DA7219_HP_L_CTRL,
+			      DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
+			      da7219_settling_event,
+			      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("Headphone Right PGA", 1, DA7219_HP_R_CTRL,
+			      DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT,
+			      da7219_settling_event,
+			      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* Output Supplies */
+	SND_SOC_DAPM_SUPPLY_S("Charge Pump", 0, DA7219_CP_CTRL,
+			      DA7219_CP_EN_SHIFT, DA7219_NO_INVERT,
+			      da7219_settling_event,
+			      SND_SOC_DAPM_POST_PMU),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+
+	/* Pre/Post Power */
+	SND_SOC_DAPM_PRE("Pre Power Gain Ramp", da7219_gain_ramp_event),
+	SND_SOC_DAPM_POST("Post Power Gain Ramp", da7219_gain_ramp_event),
+};
+
+
+/*
+ * DAPM Mux Routes
+ */
+
+#define DA7219_OUT_DAI_MUX_ROUTES(name)			\
+	{name, "ADC", "Mixer In"},			\
+	{name, "Tone Generator", "Tone Generator"},	\
+	{name, "DAIL", "DAIOUT"},			\
+	{name, "DAIR", "DAIOUT"}
+
+#define DA7219_OUT_DAC_MUX_ROUTES(name)			\
+	{name, "ADC", "Mixer In"},			\
+	{name, "Tone Generator", "Tone Generator"},		\
+	{name, "DAIL", "DAIIN"},			\
+	{name, "DAIR", "DAIIN"}
+
+/*
+ * DAPM Mixer Routes
+ */
+
+#define DA7219_DMIX_ST_ROUTES(name)				\
+	{name, "Out FilterL Switch", "Mixer Out FilterL"},	\
+	{name, "Out FilterR Switch", "Mixer Out FilterR"},	\
+	{name, "Sidetone Switch", "Sidetone Filter"}
+
+
+/*
+ * DAPM audio route definition
+ */
+
+static const struct snd_soc_dapm_route da7219_audio_map[] = {
+	/* Input paths */
+	{"MIC", NULL, "Mic Bias"},
+	{"Mic PGA", NULL, "MIC"},
+	{"Mixin PGA", NULL, "Mic PGA"},
+	{"ADC", NULL, "Mixin PGA"},
+
+	{"Mixer In", NULL, "Mixer In Supply"},
+	{"Mixer In", "Mic Switch", "ADC"},
+
+	{"Sidetone Filter", NULL, "Mixer In"},
+
+	{"Tone Generator", NULL, "TONE"},
+
+	DA7219_OUT_DAI_MUX_ROUTES("Out DAIL Mux"),
+	DA7219_OUT_DAI_MUX_ROUTES("Out DAIR Mux"),
+
+	{"DAIOUT", NULL, "Out DAIL Mux"},
+	{"DAIOUT", NULL, "Out DAIR Mux"},
+	{"DAIOUT", NULL, "DAI"},
+
+	/* Output paths */
+	{"DAIIN", NULL, "DAI"},
+
+	DA7219_OUT_DAC_MUX_ROUTES("Out DACL Mux"),
+	DA7219_OUT_DAC_MUX_ROUTES("Out DACR Mux"),
+
+	{"Mixer Out FilterL", "DACL Switch", "Out DACL Mux"},
+	{"Mixer Out FilterR", "DACR Switch", "Out DACR Mux"},
+
+	DA7219_DMIX_ST_ROUTES("ST Mixer Out FilterL"),
+	DA7219_DMIX_ST_ROUTES("ST Mixer Out FilterR"),
+
+	{"DACL", NULL, "ST Mixer Out FilterL"},
+	{"DACR", NULL, "ST Mixer Out FilterR"},
+
+	{"Mixout Left PGA", NULL, "DACL"},
+	{"Mixout Right PGA", NULL, "DACR"},
+
+	{"HPL", NULL, "Mixout Left PGA"},
+	{"HPR", NULL, "Mixout Right PGA"},
+
+	{"HPL", NULL, "Headphone Left PGA"},
+	{"HPR", NULL, "Headphone Right PGA"},
+
+	{"HPL", NULL, "Charge Pump"},
+	{"HPR", NULL, "Charge Pump"},
+};
+
+
+/*
+ * DAI operations
+ */
+
+static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq))
+		return 0;
+
+	if ((freq < 2000000) || (freq > 54000000)) {
+		dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+			freq);
+		return -EINVAL;
+	}
+
+	mutex_lock(&da7219->pll_lock);
+
+	switch (clk_id) {
+	case DA7219_CLKSRC_MCLK_SQR:
+		snd_soc_component_update_bits(component, DA7219_PLL_CTRL,
+				    DA7219_PLL_MCLK_SQR_EN_MASK,
+				    DA7219_PLL_MCLK_SQR_EN_MASK);
+		break;
+	case DA7219_CLKSRC_MCLK:
+		snd_soc_component_update_bits(component, DA7219_PLL_CTRL,
+				    DA7219_PLL_MCLK_SQR_EN_MASK, 0);
+		break;
+	default:
+		dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+		mutex_unlock(&da7219->pll_lock);
+		return -EINVAL;
+	}
+
+	da7219->clk_src = clk_id;
+
+	if (da7219->mclk) {
+		freq = clk_round_rate(da7219->mclk, freq);
+		ret = clk_set_rate(da7219->mclk, freq);
+		if (ret) {
+			dev_err(codec_dai->dev, "Failed to set clock rate %d\n",
+				freq);
+			mutex_unlock(&da7219->pll_lock);
+			return ret;
+		}
+	}
+
+	da7219->mclk_rate = freq;
+
+	mutex_unlock(&da7219->pll_lock);
+
+	return 0;
+}
+
+int da7219_set_pll(struct snd_soc_component *component, int source, unsigned int fout)
+{
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+
+	u8 pll_ctrl, indiv_bits, indiv;
+	u8 pll_frac_top, pll_frac_bot, pll_integer;
+	u32 freq_ref;
+	u64 frac_div;
+
+	/* Verify 2MHz - 54MHz MCLK provided, and set input divider */
+	if (da7219->mclk_rate < 2000000) {
+		dev_err(component->dev, "PLL input clock %d below valid range\n",
+			da7219->mclk_rate);
+		return -EINVAL;
+	} else if (da7219->mclk_rate <= 4500000) {
+		indiv_bits = DA7219_PLL_INDIV_2_TO_4_5_MHZ;
+		indiv = DA7219_PLL_INDIV_2_TO_4_5_MHZ_VAL;
+	} else if (da7219->mclk_rate <= 9000000) {
+		indiv_bits = DA7219_PLL_INDIV_4_5_TO_9_MHZ;
+		indiv = DA7219_PLL_INDIV_4_5_TO_9_MHZ_VAL;
+	} else if (da7219->mclk_rate <= 18000000) {
+		indiv_bits = DA7219_PLL_INDIV_9_TO_18_MHZ;
+		indiv = DA7219_PLL_INDIV_9_TO_18_MHZ_VAL;
+	} else if (da7219->mclk_rate <= 36000000) {
+		indiv_bits = DA7219_PLL_INDIV_18_TO_36_MHZ;
+		indiv = DA7219_PLL_INDIV_18_TO_36_MHZ_VAL;
+	} else if (da7219->mclk_rate <= 54000000) {
+		indiv_bits = DA7219_PLL_INDIV_36_TO_54_MHZ;
+		indiv = DA7219_PLL_INDIV_36_TO_54_MHZ_VAL;
+	} else {
+		dev_err(component->dev, "PLL input clock %d above valid range\n",
+			da7219->mclk_rate);
+		return -EINVAL;
+	}
+	freq_ref = (da7219->mclk_rate / indiv);
+	pll_ctrl = indiv_bits;
+
+	/* Configure PLL */
+	switch (source) {
+	case DA7219_SYSCLK_MCLK:
+		pll_ctrl |= DA7219_PLL_MODE_BYPASS;
+		snd_soc_component_update_bits(component, DA7219_PLL_CTRL,
+				    DA7219_PLL_INDIV_MASK |
+				    DA7219_PLL_MODE_MASK, pll_ctrl);
+		return 0;
+	case DA7219_SYSCLK_PLL:
+		pll_ctrl |= DA7219_PLL_MODE_NORMAL;
+		break;
+	case DA7219_SYSCLK_PLL_SRM:
+		pll_ctrl |= DA7219_PLL_MODE_SRM;
+		break;
+	default:
+		dev_err(component->dev, "Invalid PLL config\n");
+		return -EINVAL;
+	}
+
+	/* Calculate dividers for PLL */
+	pll_integer = fout / freq_ref;
+	frac_div = (u64)(fout % freq_ref) * 8192ULL;
+	do_div(frac_div, freq_ref);
+	pll_frac_top = (frac_div >> DA7219_BYTE_SHIFT) & DA7219_BYTE_MASK;
+	pll_frac_bot = (frac_div) & DA7219_BYTE_MASK;
+
+	/* Write PLL config & dividers */
+	snd_soc_component_write(component, DA7219_PLL_FRAC_TOP, pll_frac_top);
+	snd_soc_component_write(component, DA7219_PLL_FRAC_BOT, pll_frac_bot);
+	snd_soc_component_write(component, DA7219_PLL_INTEGER, pll_integer);
+	snd_soc_component_update_bits(component, DA7219_PLL_CTRL,
+			    DA7219_PLL_INDIV_MASK | DA7219_PLL_MODE_MASK,
+			    pll_ctrl);
+
+	return 0;
+}
+
+static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+			      int source, unsigned int fref, unsigned int fout)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	mutex_lock(&da7219->pll_lock);
+	ret = da7219_set_pll(component, source, fout);
+	mutex_unlock(&da7219->pll_lock);
+
+	return ret;
+}
+
+static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	u8 dai_clk_mode = 0, dai_ctrl = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		da7219->master = true;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		da7219->master = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
+					DA7219_DAI_CLK_POL_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
+					DA7219_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		dai_ctrl |= DA7219_DAI_FORMAT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		dai_ctrl |= DA7219_DAI_FORMAT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		dai_ctrl |= DA7219_DAI_FORMAT_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		dai_ctrl |= DA7219_DAI_FORMAT_DSP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* By default 64 BCLKs per WCLK is supported */
+	dai_clk_mode |= DA7219_DAI_BCLKS_PER_WCLK_64;
+
+	snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
+			    DA7219_DAI_BCLKS_PER_WCLK_MASK |
+			    DA7219_DAI_CLK_POL_MASK | DA7219_DAI_WCLK_POL_MASK,
+			    dai_clk_mode);
+	snd_soc_component_update_bits(component, DA7219_DAI_CTRL, DA7219_DAI_FORMAT_MASK,
+			    dai_ctrl);
+
+	return 0;
+}
+
+static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai,
+				   unsigned int tx_mask, unsigned int rx_mask,
+				   int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	u8 dai_bclks_per_wclk;
+	u16 offset;
+	u32 frame_size;
+
+	/* No channels enabled so disable TDM, revert to 64-bit frames */
+	if (!tx_mask) {
+		snd_soc_component_update_bits(component, DA7219_DAI_TDM_CTRL,
+				    DA7219_DAI_TDM_CH_EN_MASK |
+				    DA7219_DAI_TDM_MODE_EN_MASK, 0);
+		snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
+				    DA7219_DAI_BCLKS_PER_WCLK_MASK,
+				    DA7219_DAI_BCLKS_PER_WCLK_64);
+		return 0;
+	}
+
+	/* Check we have valid slots */
+	if (fls(tx_mask) > DA7219_DAI_TDM_MAX_SLOTS) {
+		dev_err(component->dev, "Invalid number of slots, max = %d\n",
+			DA7219_DAI_TDM_MAX_SLOTS);
+		return -EINVAL;
+	}
+
+	/* Check we have a valid offset given */
+	if (rx_mask > DA7219_DAI_OFFSET_MAX) {
+		dev_err(component->dev, "Invalid slot offset, max = %d\n",
+			DA7219_DAI_OFFSET_MAX);
+		return -EINVAL;
+	}
+
+	/* Calculate & validate frame size based on slot info provided. */
+	frame_size = slots * slot_width;
+	switch (frame_size) {
+	case 32:
+		dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32;
+		break;
+	case 64:
+		dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64;
+		break;
+	case 128:
+		dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128;
+		break;
+	case 256:
+		dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256;
+		break;
+	default:
+		dev_err(component->dev, "Invalid frame size %d\n", frame_size);
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
+			    DA7219_DAI_BCLKS_PER_WCLK_MASK,
+			    dai_bclks_per_wclk);
+
+	offset = cpu_to_le16(rx_mask);
+	regmap_bulk_write(da7219->regmap, DA7219_DAI_OFFSET_LOWER,
+			  &offset, sizeof(offset));
+
+	snd_soc_component_update_bits(component, DA7219_DAI_TDM_CTRL,
+			    DA7219_DAI_TDM_CH_EN_MASK |
+			    DA7219_DAI_TDM_MODE_EN_MASK,
+			    (tx_mask << DA7219_DAI_TDM_CH_EN_SHIFT) |
+			    DA7219_DAI_TDM_MODE_EN_MASK);
+
+	return 0;
+}
+
+static int da7219_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 dai_ctrl = 0, fs;
+	unsigned int channels;
+
+	switch (params_width(params)) {
+	case 16:
+		dai_ctrl |= DA7219_DAI_WORD_LENGTH_S16_LE;
+		break;
+	case 20:
+		dai_ctrl |= DA7219_DAI_WORD_LENGTH_S20_LE;
+		break;
+	case 24:
+		dai_ctrl |= DA7219_DAI_WORD_LENGTH_S24_LE;
+		break;
+	case 32:
+		dai_ctrl |= DA7219_DAI_WORD_LENGTH_S32_LE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	channels = params_channels(params);
+	if ((channels < 1) || (channels > DA7219_DAI_CH_NUM_MAX)) {
+		dev_err(component->dev,
+			"Invalid number of channels, only 1 to %d supported\n",
+			DA7219_DAI_CH_NUM_MAX);
+		return -EINVAL;
+	}
+	dai_ctrl |= channels << DA7219_DAI_CH_NUM_SHIFT;
+
+	switch (params_rate(params)) {
+	case 8000:
+		fs = DA7219_SR_8000;
+		break;
+	case 11025:
+		fs = DA7219_SR_11025;
+		break;
+	case 12000:
+		fs = DA7219_SR_12000;
+		break;
+	case 16000:
+		fs = DA7219_SR_16000;
+		break;
+	case 22050:
+		fs = DA7219_SR_22050;
+		break;
+	case 24000:
+		fs = DA7219_SR_24000;
+		break;
+	case 32000:
+		fs = DA7219_SR_32000;
+		break;
+	case 44100:
+		fs = DA7219_SR_44100;
+		break;
+	case 48000:
+		fs = DA7219_SR_48000;
+		break;
+	case 88200:
+		fs = DA7219_SR_88200;
+		break;
+	case 96000:
+		fs = DA7219_SR_96000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, DA7219_DAI_CTRL,
+			    DA7219_DAI_WORD_LENGTH_MASK |
+			    DA7219_DAI_CH_NUM_MASK,
+			    dai_ctrl);
+	snd_soc_component_write(component, DA7219_SR, fs);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops da7219_dai_ops = {
+	.hw_params	= da7219_hw_params,
+	.set_sysclk	= da7219_set_dai_sysclk,
+	.set_pll	= da7219_set_dai_pll,
+	.set_fmt	= da7219_set_dai_fmt,
+	.set_tdm_slot	= da7219_set_dai_tdm_slot,
+};
+
+#define DA7219_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver da7219_dai = {
+	.name = "da7219-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = DA7219_DAI_CH_NUM_MAX,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = DA7219_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = DA7219_DAI_CH_NUM_MAX,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = DA7219_FORMATS,
+	},
+	.ops = &da7219_dai_ops,
+	.symmetric_rates = 1,
+	.symmetric_channels = 1,
+	.symmetric_samplebits = 1,
+};
+
+
+/*
+ * DT/ACPI
+ */
+
+static const struct of_device_id da7219_of_match[] = {
+	{ .compatible = "dlg,da7219", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, da7219_of_match);
+
+static const struct acpi_device_id da7219_acpi_match[] = {
+	{ .id = "DLGS7219", },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, da7219_acpi_match);
+
+static enum da7219_micbias_voltage
+	da7219_fw_micbias_lvl(struct device *dev, u32 val)
+{
+	switch (val) {
+	case 1600:
+		return DA7219_MICBIAS_1_6V;
+	case 1800:
+		return DA7219_MICBIAS_1_8V;
+	case 2000:
+		return DA7219_MICBIAS_2_0V;
+	case 2200:
+		return DA7219_MICBIAS_2_2V;
+	case 2400:
+		return DA7219_MICBIAS_2_4V;
+	case 2600:
+		return DA7219_MICBIAS_2_6V;
+	default:
+		dev_warn(dev, "Invalid micbias level");
+		return DA7219_MICBIAS_2_2V;
+	}
+}
+
+static enum da7219_mic_amp_in_sel
+	da7219_fw_mic_amp_in_sel(struct device *dev, const char *str)
+{
+	if (!strcmp(str, "diff")) {
+		return DA7219_MIC_AMP_IN_SEL_DIFF;
+	} else if (!strcmp(str, "se_p")) {
+		return DA7219_MIC_AMP_IN_SEL_SE_P;
+	} else if (!strcmp(str, "se_n")) {
+		return DA7219_MIC_AMP_IN_SEL_SE_N;
+	} else {
+		dev_warn(dev, "Invalid mic input type selection");
+		return DA7219_MIC_AMP_IN_SEL_DIFF;
+	}
+}
+
+static struct da7219_pdata *da7219_fw_to_pdata(struct snd_soc_component *component)
+{
+	struct device *dev = component->dev;
+	struct da7219_pdata *pdata;
+	const char *of_str;
+	u32 of_val32;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	pdata->wakeup_source = device_property_read_bool(dev, "wakeup-source");
+
+	pdata->dai_clks_name = "da7219-dai-clks";
+	if (device_property_read_string(dev, "clock-output-names",
+					&pdata->dai_clks_name))
+		dev_warn(dev, "Using default clk name: %s\n",
+			 pdata->dai_clks_name);
+
+	if (device_property_read_u32(dev, "dlg,micbias-lvl", &of_val32) >= 0)
+		pdata->micbias_lvl = da7219_fw_micbias_lvl(dev, of_val32);
+	else
+		pdata->micbias_lvl = DA7219_MICBIAS_2_2V;
+
+	if (!device_property_read_string(dev, "dlg,mic-amp-in-sel", &of_str))
+		pdata->mic_amp_in_sel = da7219_fw_mic_amp_in_sel(dev, of_str);
+	else
+		pdata->mic_amp_in_sel = DA7219_MIC_AMP_IN_SEL_DIFF;
+
+	return pdata;
+}
+
+
+/*
+ * Codec driver functions
+ */
+
+static int da7219_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* Enable MCLK for transition to ON state */
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) {
+			if (da7219->mclk) {
+				ret = clk_prepare_enable(da7219->mclk);
+				if (ret) {
+					dev_err(component->dev,
+						"Failed to enable mclk\n");
+					return ret;
+				}
+			}
+		}
+
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			/* Master bias */
+			snd_soc_component_update_bits(component, DA7219_REFERENCES,
+					    DA7219_BIAS_EN_MASK,
+					    DA7219_BIAS_EN_MASK);
+
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE) {
+			/* Remove MCLK */
+			if (da7219->mclk)
+				clk_disable_unprepare(da7219->mclk);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* Only disable master bias if we're not a wake-up source */
+		if (!da7219->wakeup_source)
+			snd_soc_component_update_bits(component, DA7219_REFERENCES,
+					    DA7219_BIAS_EN_MASK, 0);
+
+		break;
+	}
+
+	return 0;
+}
+
+static const char *da7219_supply_names[DA7219_NUM_SUPPLIES] = {
+	[DA7219_SUPPLY_VDD] = "VDD",
+	[DA7219_SUPPLY_VDDMIC] = "VDDMIC",
+	[DA7219_SUPPLY_VDDIO] = "VDDIO",
+};
+
+static int da7219_handle_supplies(struct snd_soc_component *component)
+{
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	struct regulator *vddio;
+	u8 io_voltage_lvl = DA7219_IO_VOLTAGE_LEVEL_2_5V_3_6V;
+	int i, ret;
+
+	/* Get required supplies */
+	for (i = 0; i < DA7219_NUM_SUPPLIES; ++i)
+		da7219->supplies[i].supply = da7219_supply_names[i];
+
+	ret = devm_regulator_bulk_get(component->dev, DA7219_NUM_SUPPLIES,
+				      da7219->supplies);
+	if (ret) {
+		dev_err(component->dev, "Failed to get supplies");
+		return ret;
+	}
+
+	/* Determine VDDIO voltage provided */
+	vddio = da7219->supplies[DA7219_SUPPLY_VDDIO].consumer;
+	ret = regulator_get_voltage(vddio);
+	if (ret < 1200000)
+		dev_warn(component->dev, "Invalid VDDIO voltage\n");
+	else if (ret < 2800000)
+		io_voltage_lvl = DA7219_IO_VOLTAGE_LEVEL_1_2V_2_8V;
+
+	/* Enable main supplies */
+	ret = regulator_bulk_enable(DA7219_NUM_SUPPLIES, da7219->supplies);
+	if (ret) {
+		dev_err(component->dev, "Failed to enable supplies");
+		return ret;
+	}
+
+	/* Ensure device in active mode */
+	snd_soc_component_write(component, DA7219_SYSTEM_ACTIVE, DA7219_SYSTEM_ACTIVE_MASK);
+
+	/* Update IO voltage level range */
+	snd_soc_component_write(component, DA7219_IO_CTRL, io_voltage_lvl);
+
+	return 0;
+}
+
+#ifdef CONFIG_COMMON_CLK
+static int da7219_dai_clks_prepare(struct clk_hw *hw)
+{
+	struct da7219_priv *da7219 =
+		container_of(hw, struct da7219_priv, dai_clks_hw);
+	struct snd_soc_component *component = da7219->aad->component;
+
+	snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
+				      DA7219_DAI_CLK_EN_MASK,
+				      DA7219_DAI_CLK_EN_MASK);
+
+	return 0;
+}
+
+static void da7219_dai_clks_unprepare(struct clk_hw *hw)
+{
+	struct da7219_priv *da7219 =
+		container_of(hw, struct da7219_priv, dai_clks_hw);
+	struct snd_soc_component *component = da7219->aad->component;
+
+	snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
+				      DA7219_DAI_CLK_EN_MASK, 0);
+}
+
+static int da7219_dai_clks_is_prepared(struct clk_hw *hw)
+{
+	struct da7219_priv *da7219 =
+		container_of(hw, struct da7219_priv, dai_clks_hw);
+	struct snd_soc_component *component = da7219->aad->component;
+	u8 clk_reg;
+
+	clk_reg = snd_soc_component_read32(component, DA7219_DAI_CLK_MODE);
+
+	return !!(clk_reg & DA7219_DAI_CLK_EN_MASK);
+}
+
+static const struct clk_ops da7219_dai_clks_ops = {
+	.prepare = da7219_dai_clks_prepare,
+	.unprepare = da7219_dai_clks_unprepare,
+	.is_prepared = da7219_dai_clks_is_prepared,
+};
+
+static void da7219_register_dai_clks(struct snd_soc_component *component)
+{
+	struct device *dev = component->dev;
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	struct da7219_pdata *pdata = da7219->pdata;
+	struct clk_init_data init = {};
+	struct clk *dai_clks;
+	struct clk_lookup *dai_clks_lookup;
+
+	init.parent_names = NULL;
+	init.num_parents = 0;
+	init.name = pdata->dai_clks_name;
+	init.ops = &da7219_dai_clks_ops;
+	da7219->dai_clks_hw.init = &init;
+
+	dai_clks = devm_clk_register(dev, &da7219->dai_clks_hw);
+	if (IS_ERR(dai_clks)) {
+		dev_warn(dev, "Failed to register DAI clocks: %ld\n",
+			 PTR_ERR(dai_clks));
+		return;
+	}
+	da7219->dai_clks = dai_clks;
+
+	/* If we're using DT, then register as provider accordingly */
+	if (dev->of_node) {
+		devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+					    &da7219->dai_clks_hw);
+	} else {
+		dai_clks_lookup = clkdev_create(dai_clks, pdata->dai_clks_name,
+						"%s", dev_name(dev));
+		if (!dai_clks_lookup)
+			dev_warn(dev, "Failed to create DAI clkdev");
+		else
+			da7219->dai_clks_lookup = dai_clks_lookup;
+	}
+}
+#else
+static inline void da7219_register_dai_clks(struct snd_soc_component *component) {}
+#endif /* CONFIG_COMMON_CLK */
+
+static void da7219_handle_pdata(struct snd_soc_component *component)
+{
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	struct da7219_pdata *pdata = da7219->pdata;
+
+	if (pdata) {
+		u8 micbias_lvl = 0;
+
+		da7219->wakeup_source = pdata->wakeup_source;
+
+		da7219_register_dai_clks(component);
+
+		/* Mic Bias voltages */
+		switch (pdata->micbias_lvl) {
+		case DA7219_MICBIAS_1_6V:
+		case DA7219_MICBIAS_1_8V:
+		case DA7219_MICBIAS_2_0V:
+		case DA7219_MICBIAS_2_2V:
+		case DA7219_MICBIAS_2_4V:
+		case DA7219_MICBIAS_2_6V:
+			micbias_lvl |= (pdata->micbias_lvl <<
+					DA7219_MICBIAS1_LEVEL_SHIFT);
+			break;
+		}
+
+		snd_soc_component_write(component, DA7219_MICBIAS_CTRL, micbias_lvl);
+
+		/*
+		 * Calculate delay required to compensate for DC offset in
+		 * Mic PGA, based on Mic Bias voltage.
+		 */
+		da7219->mic_pga_delay =  DA7219_MIC_PGA_BASE_DELAY +
+					(pdata->micbias_lvl *
+					 DA7219_MIC_PGA_OFFSET_DELAY);
+
+		/* Mic */
+		switch (pdata->mic_amp_in_sel) {
+		case DA7219_MIC_AMP_IN_SEL_DIFF:
+		case DA7219_MIC_AMP_IN_SEL_SE_P:
+		case DA7219_MIC_AMP_IN_SEL_SE_N:
+			snd_soc_component_write(component, DA7219_MIC_1_SELECT,
+				      pdata->mic_amp_in_sel);
+			break;
+		}
+	}
+}
+
+static struct reg_sequence da7219_rev_aa_patch[] = {
+	{ DA7219_REFERENCES, 0x08 },
+};
+
+static int da7219_probe(struct snd_soc_component *component)
+{
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+	unsigned int rev;
+	int ret;
+
+	mutex_init(&da7219->ctrl_lock);
+	mutex_init(&da7219->pll_lock);
+
+	/* Regulator configuration */
+	ret = da7219_handle_supplies(component);
+	if (ret)
+		return ret;
+
+	ret = regmap_read(da7219->regmap, DA7219_CHIP_REVISION, &rev);
+	if (ret) {
+		dev_err(component->dev, "Failed to read chip revision: %d\n", ret);
+		goto err_disable_reg;
+	}
+
+	switch (rev & DA7219_CHIP_MINOR_MASK) {
+	case 0:
+		ret = regmap_register_patch(da7219->regmap, da7219_rev_aa_patch,
+					    ARRAY_SIZE(da7219_rev_aa_patch));
+		if (ret) {
+			dev_err(component->dev, "Failed to register AA patch: %d\n",
+				ret);
+			goto err_disable_reg;
+		}
+		break;
+	default:
+		break;
+	}
+
+	/* Handle DT/ACPI/Platform data */
+	da7219->pdata = dev_get_platdata(component->dev);
+	if (!da7219->pdata)
+		da7219->pdata = da7219_fw_to_pdata(component);
+
+	da7219_handle_pdata(component);
+
+	/* Check if MCLK provided */
+	da7219->mclk = devm_clk_get(component->dev, "mclk");
+	if (IS_ERR(da7219->mclk)) {
+		if (PTR_ERR(da7219->mclk) != -ENOENT) {
+			ret = PTR_ERR(da7219->mclk);
+			goto err_disable_reg;
+		} else {
+			da7219->mclk = NULL;
+		}
+	}
+
+	/* Default PC counter to free-running */
+	snd_soc_component_update_bits(component, DA7219_PC_COUNT, DA7219_PC_FREERUN_MASK,
+			    DA7219_PC_FREERUN_MASK);
+
+	/* Default gain ramping */
+	snd_soc_component_update_bits(component, DA7219_MIXIN_L_CTRL,
+			    DA7219_MIXIN_L_AMP_RAMP_EN_MASK,
+			    DA7219_MIXIN_L_AMP_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7219_ADC_L_CTRL, DA7219_ADC_L_RAMP_EN_MASK,
+			    DA7219_ADC_L_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7219_DAC_L_CTRL, DA7219_DAC_L_RAMP_EN_MASK,
+			    DA7219_DAC_L_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7219_DAC_R_CTRL, DA7219_DAC_R_RAMP_EN_MASK,
+			    DA7219_DAC_R_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
+			    DA7219_HP_L_AMP_RAMP_EN_MASK,
+			    DA7219_HP_L_AMP_RAMP_EN_MASK);
+	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
+			    DA7219_HP_R_AMP_RAMP_EN_MASK,
+			    DA7219_HP_R_AMP_RAMP_EN_MASK);
+
+	/* Default minimum gain on HP to avoid pops during DAPM sequencing */
+	snd_soc_component_update_bits(component, DA7219_HP_L_CTRL,
+			    DA7219_HP_L_AMP_MIN_GAIN_EN_MASK,
+			    DA7219_HP_L_AMP_MIN_GAIN_EN_MASK);
+	snd_soc_component_update_bits(component, DA7219_HP_R_CTRL,
+			    DA7219_HP_R_AMP_MIN_GAIN_EN_MASK,
+			    DA7219_HP_R_AMP_MIN_GAIN_EN_MASK);
+
+	/* Default infinite tone gen, start/stop by Kcontrol */
+	snd_soc_component_write(component, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK);
+
+	/* Initialise AAD block */
+	ret = da7219_aad_init(component);
+	if (ret)
+		goto err_disable_reg;
+
+	return 0;
+
+err_disable_reg:
+	regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies);
+
+	return ret;
+}
+
+static void da7219_remove(struct snd_soc_component *component)
+{
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+
+	da7219_aad_exit(component);
+
+#ifdef CONFIG_COMMON_CLK
+	if (da7219->dai_clks_lookup)
+		clkdev_drop(da7219->dai_clks_lookup);
+#endif
+
+	/* Supplies */
+	regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies);
+}
+
+#ifdef CONFIG_PM
+static int da7219_suspend(struct snd_soc_component *component)
+{
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+
+	/* Suspend AAD if we're not a wake-up source */
+	if (!da7219->wakeup_source)
+		da7219_aad_suspend(component);
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int da7219_resume(struct snd_soc_component *component)
+{
+	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	/* Resume AAD if previously suspended */
+	if (!da7219->wakeup_source)
+		da7219_aad_resume(component);
+
+	return 0;
+}
+#else
+#define da7219_suspend NULL
+#define da7219_resume NULL
+#endif
+
+static const struct snd_soc_component_driver soc_component_dev_da7219 = {
+	.probe			= da7219_probe,
+	.remove			= da7219_remove,
+	.suspend		= da7219_suspend,
+	.resume			= da7219_resume,
+	.set_bias_level		= da7219_set_bias_level,
+	.controls		= da7219_snd_controls,
+	.num_controls		= ARRAY_SIZE(da7219_snd_controls),
+	.dapm_widgets		= da7219_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(da7219_dapm_widgets),
+	.dapm_routes		= da7219_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(da7219_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+
+/*
+ * Regmap configs
+ */
+
+static struct reg_default da7219_reg_defaults[] = {
+	{ DA7219_MIC_1_SELECT, 0x00 },
+	{ DA7219_CIF_TIMEOUT_CTRL, 0x01 },
+	{ DA7219_SR_24_48, 0x00 },
+	{ DA7219_SR, 0x0A },
+	{ DA7219_CIF_I2C_ADDR_CFG, 0x02 },
+	{ DA7219_PLL_CTRL, 0x10 },
+	{ DA7219_PLL_FRAC_TOP, 0x00 },
+	{ DA7219_PLL_FRAC_BOT, 0x00 },
+	{ DA7219_PLL_INTEGER, 0x20 },
+	{ DA7219_DIG_ROUTING_DAI, 0x10 },
+	{ DA7219_DAI_CLK_MODE, 0x01 },
+	{ DA7219_DAI_CTRL, 0x28 },
+	{ DA7219_DAI_TDM_CTRL, 0x40 },
+	{ DA7219_DIG_ROUTING_DAC, 0x32 },
+	{ DA7219_DAI_OFFSET_LOWER, 0x00 },
+	{ DA7219_DAI_OFFSET_UPPER, 0x00 },
+	{ DA7219_REFERENCES, 0x08 },
+	{ DA7219_MIXIN_L_SELECT, 0x00 },
+	{ DA7219_MIXIN_L_GAIN, 0x03 },
+	{ DA7219_ADC_L_GAIN, 0x6F },
+	{ DA7219_ADC_FILTERS1, 0x80 },
+	{ DA7219_MIC_1_GAIN, 0x01 },
+	{ DA7219_SIDETONE_CTRL, 0x40 },
+	{ DA7219_SIDETONE_GAIN, 0x0E },
+	{ DA7219_DROUTING_ST_OUTFILT_1L, 0x01 },
+	{ DA7219_DROUTING_ST_OUTFILT_1R, 0x02 },
+	{ DA7219_DAC_FILTERS5, 0x00 },
+	{ DA7219_DAC_FILTERS2, 0x88 },
+	{ DA7219_DAC_FILTERS3, 0x88 },
+	{ DA7219_DAC_FILTERS4, 0x08 },
+	{ DA7219_DAC_FILTERS1, 0x80 },
+	{ DA7219_DAC_L_GAIN, 0x6F },
+	{ DA7219_DAC_R_GAIN, 0x6F },
+	{ DA7219_CP_CTRL, 0x20 },
+	{ DA7219_HP_L_GAIN, 0x39 },
+	{ DA7219_HP_R_GAIN, 0x39 },
+	{ DA7219_MIXOUT_L_SELECT, 0x00 },
+	{ DA7219_MIXOUT_R_SELECT, 0x00 },
+	{ DA7219_MICBIAS_CTRL, 0x03 },
+	{ DA7219_MIC_1_CTRL, 0x40 },
+	{ DA7219_MIXIN_L_CTRL, 0x40 },
+	{ DA7219_ADC_L_CTRL, 0x40 },
+	{ DA7219_DAC_L_CTRL, 0x40 },
+	{ DA7219_DAC_R_CTRL, 0x40 },
+	{ DA7219_HP_L_CTRL, 0x40 },
+	{ DA7219_HP_R_CTRL, 0x40 },
+	{ DA7219_MIXOUT_L_CTRL, 0x10 },
+	{ DA7219_MIXOUT_R_CTRL, 0x10 },
+	{ DA7219_CHIP_ID1, 0x23 },
+	{ DA7219_CHIP_ID2, 0x93 },
+	{ DA7219_IO_CTRL, 0x00 },
+	{ DA7219_GAIN_RAMP_CTRL, 0x00 },
+	{ DA7219_PC_COUNT, 0x02 },
+	{ DA7219_CP_VOL_THRESHOLD1, 0x0E },
+	{ DA7219_DIG_CTRL, 0x00 },
+	{ DA7219_ALC_CTRL2, 0x00 },
+	{ DA7219_ALC_CTRL3, 0x00 },
+	{ DA7219_ALC_NOISE, 0x3F },
+	{ DA7219_ALC_TARGET_MIN, 0x3F },
+	{ DA7219_ALC_TARGET_MAX, 0x00 },
+	{ DA7219_ALC_GAIN_LIMITS, 0xFF },
+	{ DA7219_ALC_ANA_GAIN_LIMITS, 0x71 },
+	{ DA7219_ALC_ANTICLIP_CTRL, 0x00 },
+	{ DA7219_ALC_ANTICLIP_LEVEL, 0x00 },
+	{ DA7219_DAC_NG_SETUP_TIME, 0x00 },
+	{ DA7219_DAC_NG_OFF_THRESH, 0x00 },
+	{ DA7219_DAC_NG_ON_THRESH, 0x00 },
+	{ DA7219_DAC_NG_CTRL, 0x00 },
+	{ DA7219_TONE_GEN_CFG1, 0x00 },
+	{ DA7219_TONE_GEN_CFG2, 0x00 },
+	{ DA7219_TONE_GEN_CYCLES, 0x00 },
+	{ DA7219_TONE_GEN_FREQ1_L, 0x55 },
+	{ DA7219_TONE_GEN_FREQ1_U, 0x15 },
+	{ DA7219_TONE_GEN_FREQ2_L, 0x00 },
+	{ DA7219_TONE_GEN_FREQ2_U, 0x40 },
+	{ DA7219_TONE_GEN_ON_PER, 0x02 },
+	{ DA7219_TONE_GEN_OFF_PER, 0x01 },
+	{ DA7219_ACCDET_IRQ_MASK_A, 0x00 },
+	{ DA7219_ACCDET_IRQ_MASK_B, 0x00 },
+	{ DA7219_ACCDET_CONFIG_1, 0xD6 },
+	{ DA7219_ACCDET_CONFIG_2, 0x34 },
+	{ DA7219_ACCDET_CONFIG_3, 0x0A },
+	{ DA7219_ACCDET_CONFIG_4, 0x16 },
+	{ DA7219_ACCDET_CONFIG_5, 0x21 },
+	{ DA7219_ACCDET_CONFIG_6, 0x3E },
+	{ DA7219_ACCDET_CONFIG_7, 0x01 },
+	{ DA7219_SYSTEM_ACTIVE, 0x00 },
+};
+
+static bool da7219_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case DA7219_MIC_1_GAIN_STATUS:
+	case DA7219_MIXIN_L_GAIN_STATUS:
+	case DA7219_ADC_L_GAIN_STATUS:
+	case DA7219_DAC_L_GAIN_STATUS:
+	case DA7219_DAC_R_GAIN_STATUS:
+	case DA7219_HP_L_GAIN_STATUS:
+	case DA7219_HP_R_GAIN_STATUS:
+	case DA7219_CIF_CTRL:
+	case DA7219_PLL_SRM_STS:
+	case DA7219_ALC_CTRL1:
+	case DA7219_SYSTEM_MODES_INPUT:
+	case DA7219_SYSTEM_MODES_OUTPUT:
+	case DA7219_ALC_OFFSET_AUTO_M_L:
+	case DA7219_ALC_OFFSET_AUTO_U_L:
+	case DA7219_TONE_GEN_CFG1:
+	case DA7219_ACCDET_STATUS_A:
+	case DA7219_ACCDET_STATUS_B:
+	case DA7219_ACCDET_IRQ_EVENT_A:
+	case DA7219_ACCDET_IRQ_EVENT_B:
+	case DA7219_ACCDET_CONFIG_8:
+	case DA7219_SYSTEM_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config da7219_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = DA7219_SYSTEM_ACTIVE,
+	.reg_defaults = da7219_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(da7219_reg_defaults),
+	.volatile_reg = da7219_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+
+/*
+ * I2C layer
+ */
+
+static int da7219_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct da7219_priv *da7219;
+	unsigned int system_active, system_status;
+	int i, ret;
+
+	da7219 = devm_kzalloc(&i2c->dev, sizeof(struct da7219_priv),
+			      GFP_KERNEL);
+	if (!da7219)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, da7219);
+
+	da7219->regmap = devm_regmap_init_i2c(i2c, &da7219_regmap_config);
+	if (IS_ERR(da7219->regmap)) {
+		ret = PTR_ERR(da7219->regmap);
+		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	regcache_cache_bypass(da7219->regmap, true);
+
+	/* Disable audio paths if still active from previous start */
+	regmap_read(da7219->regmap, DA7219_SYSTEM_ACTIVE, &system_active);
+	if (system_active) {
+		regmap_write(da7219->regmap, DA7219_GAIN_RAMP_CTRL,
+			     DA7219_GAIN_RAMP_RATE_NOMINAL);
+		regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_INPUT, 0x00);
+		regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_OUTPUT, 0x01);
+
+		for (i = 0; i < DA7219_SYS_STAT_CHECK_RETRIES; ++i) {
+			regmap_read(da7219->regmap, DA7219_SYSTEM_STATUS,
+				    &system_status);
+			if (!system_status)
+				break;
+
+			msleep(DA7219_SYS_STAT_CHECK_DELAY);
+		}
+	}
+
+	/* Soft reset component */
+	regmap_write_bits(da7219->regmap, DA7219_ACCDET_CONFIG_1,
+			  DA7219_ACCDET_EN_MASK, 0);
+	regmap_write_bits(da7219->regmap, DA7219_CIF_CTRL,
+			  DA7219_CIF_REG_SOFT_RESET_MASK,
+			  DA7219_CIF_REG_SOFT_RESET_MASK);
+	regmap_write_bits(da7219->regmap, DA7219_SYSTEM_ACTIVE,
+			  DA7219_SYSTEM_ACTIVE_MASK, 0);
+
+	regcache_cache_bypass(da7219->regmap, false);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_da7219,
+				     &da7219_dai, 1);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register da7219 component: %d\n",
+			ret);
+	}
+	return ret;
+}
+
+static int da7219_i2c_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id da7219_i2c_id[] = {
+	{ "da7219", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, da7219_i2c_id);
+
+static struct i2c_driver da7219_i2c_driver = {
+	.driver = {
+		.name = "da7219",
+		.of_match_table = of_match_ptr(da7219_of_match),
+		.acpi_match_table = ACPI_PTR(da7219_acpi_match),
+	},
+	.probe		= da7219_i2c_probe,
+	.remove		= da7219_i2c_remove,
+	.id_table	= da7219_i2c_id,
+};
+
+module_i2c_driver(da7219_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC DA7219 Codec Driver");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h
new file mode 100644
index 0000000..3a00686
--- /dev/null
+++ b/sound/soc/codecs/da7219.h
@@ -0,0 +1,840 @@
+/*
+ * da7219.h - DA7219 ALSA SoC Codec Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __DA7219_H
+#define __DA7219_H
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/da7219.h>
+
+/*
+ * Registers
+ */
+
+#define DA7219_MIC_1_GAIN_STATUS	0x6
+#define DA7219_MIXIN_L_GAIN_STATUS	0x8
+#define DA7219_ADC_L_GAIN_STATUS	0xA
+#define DA7219_DAC_L_GAIN_STATUS	0xC
+#define DA7219_DAC_R_GAIN_STATUS	0xD
+#define DA7219_HP_L_GAIN_STATUS		0xE
+#define DA7219_HP_R_GAIN_STATUS		0xF
+#define DA7219_MIC_1_SELECT		0x10
+#define DA7219_CIF_TIMEOUT_CTRL		0x12
+#define DA7219_CIF_CTRL			0x13
+#define DA7219_SR_24_48			0x16
+#define DA7219_SR			0x17
+#define DA7219_CIF_I2C_ADDR_CFG		0x1B
+#define DA7219_PLL_CTRL			0x20
+#define DA7219_PLL_FRAC_TOP		0x22
+#define DA7219_PLL_FRAC_BOT		0x23
+#define DA7219_PLL_INTEGER		0x24
+#define DA7219_PLL_SRM_STS		0x25
+#define DA7219_DIG_ROUTING_DAI		0x2A
+#define DA7219_DAI_CLK_MODE		0x2B
+#define DA7219_DAI_CTRL			0x2C
+#define DA7219_DAI_TDM_CTRL		0x2D
+#define DA7219_DIG_ROUTING_DAC		0x2E
+#define DA7219_ALC_CTRL1		0x2F
+#define DA7219_DAI_OFFSET_LOWER		0x30
+#define DA7219_DAI_OFFSET_UPPER		0x31
+#define DA7219_REFERENCES		0x32
+#define DA7219_MIXIN_L_SELECT		0x33
+#define DA7219_MIXIN_L_GAIN		0x34
+#define DA7219_ADC_L_GAIN		0x36
+#define DA7219_ADC_FILTERS1		0x38
+#define DA7219_MIC_1_GAIN		0x39
+#define DA7219_SIDETONE_CTRL		0x3A
+#define DA7219_SIDETONE_GAIN		0x3B
+#define DA7219_DROUTING_ST_OUTFILT_1L	0x3C
+#define DA7219_DROUTING_ST_OUTFILT_1R	0x3D
+#define DA7219_DAC_FILTERS5		0x40
+#define DA7219_DAC_FILTERS2		0x41
+#define DA7219_DAC_FILTERS3		0x42
+#define DA7219_DAC_FILTERS4		0x43
+#define DA7219_DAC_FILTERS1		0x44
+#define DA7219_DAC_L_GAIN		0x45
+#define DA7219_DAC_R_GAIN		0x46
+#define DA7219_CP_CTRL			0x47
+#define DA7219_HP_L_GAIN		0x48
+#define DA7219_HP_R_GAIN		0x49
+#define DA7219_MIXOUT_L_SELECT		0x4B
+#define DA7219_MIXOUT_R_SELECT		0x4C
+#define DA7219_SYSTEM_MODES_INPUT	0x50
+#define DA7219_SYSTEM_MODES_OUTPUT	0x51
+#define DA7219_MICBIAS_CTRL		0x62
+#define DA7219_MIC_1_CTRL		0x63
+#define DA7219_MIXIN_L_CTRL		0x65
+#define DA7219_ADC_L_CTRL		0x67
+#define DA7219_DAC_L_CTRL		0x69
+#define DA7219_DAC_R_CTRL		0x6A
+#define DA7219_HP_L_CTRL		0x6B
+#define DA7219_HP_R_CTRL		0x6C
+#define DA7219_MIXOUT_L_CTRL		0x6E
+#define DA7219_MIXOUT_R_CTRL		0x6F
+#define DA7219_CHIP_ID1			0x81
+#define DA7219_CHIP_ID2			0x82
+#define DA7219_CHIP_REVISION		0x83
+#define DA7219_IO_CTRL			0x91
+#define DA7219_GAIN_RAMP_CTRL		0x92
+#define DA7219_PC_COUNT			0x94
+#define DA7219_CP_VOL_THRESHOLD1	0x95
+#define DA7219_CP_DELAY			0x96
+#define DA7219_DIG_CTRL			0x99
+#define DA7219_ALC_CTRL2		0x9A
+#define DA7219_ALC_CTRL3		0x9B
+#define DA7219_ALC_NOISE		0x9C
+#define DA7219_ALC_TARGET_MIN		0x9D
+#define DA7219_ALC_TARGET_MAX		0x9E
+#define DA7219_ALC_GAIN_LIMITS		0x9F
+#define DA7219_ALC_ANA_GAIN_LIMITS	0xA0
+#define DA7219_ALC_ANTICLIP_CTRL	0xA1
+#define DA7219_ALC_ANTICLIP_LEVEL	0xA2
+#define DA7219_ALC_OFFSET_AUTO_M_L	0xA3
+#define DA7219_ALC_OFFSET_AUTO_U_L	0xA4
+#define DA7219_DAC_NG_SETUP_TIME	0xAF
+#define DA7219_DAC_NG_OFF_THRESH	0xB0
+#define DA7219_DAC_NG_ON_THRESH		0xB1
+#define DA7219_DAC_NG_CTRL		0xB2
+#define DA7219_TONE_GEN_CFG1		0xB4
+#define DA7219_TONE_GEN_CFG2		0xB5
+#define DA7219_TONE_GEN_CYCLES		0xB6
+#define DA7219_TONE_GEN_FREQ1_L		0xB7
+#define DA7219_TONE_GEN_FREQ1_U		0xB8
+#define DA7219_TONE_GEN_FREQ2_L		0xB9
+#define DA7219_TONE_GEN_FREQ2_U		0xBA
+#define DA7219_TONE_GEN_ON_PER		0xBB
+#define DA7219_TONE_GEN_OFF_PER		0xBC
+#define DA7219_SYSTEM_STATUS		0xE0
+#define DA7219_SYSTEM_ACTIVE		0xFD
+
+
+/*
+ * Bit Fields
+ */
+
+#define DA7219_SWITCH_EN_MAX		0x1
+
+/* DA7219_MIC_1_GAIN_STATUS = 0x6 */
+#define DA7219_MIC_1_AMP_GAIN_STATUS_SHIFT	0
+#define DA7219_MIC_1_AMP_GAIN_STATUS_MASK	(0x7 << 0)
+#define DA7219_MIC_1_AMP_GAIN_MAX		0x7
+
+/* DA7219_MIXIN_L_GAIN_STATUS = 0x8 */
+#define DA7219_MIXIN_L_AMP_GAIN_STATUS_SHIFT	0
+#define DA7219_MIXIN_L_AMP_GAIN_STATUS_MASK	(0xF << 0)
+
+/* DA7219_ADC_L_GAIN_STATUS = 0xA */
+#define DA7219_ADC_L_DIGITAL_GAIN_STATUS_SHIFT	0
+#define DA7219_ADC_L_DIGITAL_GAIN_STATUS_MASK	(0x7F << 0)
+
+/* DA7219_DAC_L_GAIN_STATUS = 0xC */
+#define DA7219_DAC_L_DIGITAL_GAIN_STATUS_SHIFT	0
+#define DA7219_DAC_L_DIGITAL_GAIN_STATUS_MASK	(0x7F << 0)
+
+/* DA7219_DAC_R_GAIN_STATUS = 0xD */
+#define DA7219_DAC_R_DIGITAL_GAIN_STATUS_SHIFT	0
+#define DA7219_DAC_R_DIGITAL_GAIN_STATUS_MASK	(0x7F << 0)
+
+/* DA7219_HP_L_GAIN_STATUS = 0xE */
+#define DA7219_HP_L_AMP_GAIN_STATUS_SHIFT	0
+#define DA7219_HP_L_AMP_GAIN_STATUS_MASK	(0x3F << 0)
+
+/* DA7219_HP_R_GAIN_STATUS = 0xF */
+#define DA7219_HP_R_AMP_GAIN_STATUS_SHIFT	0
+#define DA7219_HP_R_AMP_GAIN_STATUS_MASK	(0x3F << 0)
+
+/* DA7219_MIC_1_SELECT = 0x10 */
+#define DA7219_MIC_1_AMP_IN_SEL_SHIFT	0
+#define DA7219_MIC_1_AMP_IN_SEL_MASK	(0x3 << 0)
+
+/* DA7219_CIF_TIMEOUT_CTRL = 0x12 */
+#define DA7219_I2C_TIMEOUT_EN_SHIFT	0
+#define DA7219_I2C_TIMEOUT_EN_MASK	(0x1 << 0)
+
+/* DA7219_CIF_CTRL = 0x13 */
+#define DA7219_CIF_I2C_WRITE_MODE_SHIFT		0
+#define DA7219_CIF_I2C_WRITE_MODE_MASK		(0x1 << 0)
+#define DA7219_CIF_REG_SOFT_RESET_SHIFT		7
+#define DA7219_CIF_REG_SOFT_RESET_MASK		(0x1 << 7)
+
+/* DA7219_SR_24_48 = 0x16 */
+#define DA7219_SR_24_48_SHIFT	0
+#define DA7219_SR_24_48_MASK	(0x1 << 0)
+
+/* DA7219_SR = 0x17 */
+#define DA7219_SR_SHIFT		0
+#define DA7219_SR_MASK		(0xF << 0)
+#define DA7219_SR_8000		(0x01 << 0)
+#define DA7219_SR_11025		(0x02 << 0)
+#define DA7219_SR_12000		(0x03 << 0)
+#define DA7219_SR_16000		(0x05 << 0)
+#define DA7219_SR_22050		(0x06 << 0)
+#define DA7219_SR_24000		(0x07 << 0)
+#define DA7219_SR_32000		(0x09 << 0)
+#define DA7219_SR_44100		(0x0A << 0)
+#define DA7219_SR_48000		(0x0B << 0)
+#define DA7219_SR_88200		(0x0E << 0)
+#define DA7219_SR_96000		(0x0F << 0)
+
+/* DA7219_CIF_I2C_ADDR_CFG = 0x1B */
+#define DA7219_CIF_I2C_ADDR_CFG_SHIFT	0
+#define DA7219_CIF_I2C_ADDR_CFG_MASK	(0x3 << 0)
+
+/* DA7219_PLL_CTRL = 0x20 */
+#define DA7219_PLL_INDIV_SHIFT		2
+#define DA7219_PLL_INDIV_MASK		(0x7 << 2)
+#define DA7219_PLL_INDIV_2_TO_4_5_MHZ	(0x0 << 2)
+#define DA7219_PLL_INDIV_4_5_TO_9_MHZ	(0x1 << 2)
+#define DA7219_PLL_INDIV_9_TO_18_MHZ	(0x2 << 2)
+#define DA7219_PLL_INDIV_18_TO_36_MHZ	(0x3 << 2)
+#define DA7219_PLL_INDIV_36_TO_54_MHZ	(0x4 << 2)
+#define DA7219_PLL_MCLK_SQR_EN_SHIFT	5
+#define DA7219_PLL_MCLK_SQR_EN_MASK	(0x1 << 5)
+#define DA7219_PLL_MODE_SHIFT		6
+#define DA7219_PLL_MODE_MASK		(0x3 << 6)
+#define DA7219_PLL_MODE_BYPASS		(0x0 << 6)
+#define DA7219_PLL_MODE_NORMAL		(0x1 << 6)
+#define DA7219_PLL_MODE_SRM		(0x2 << 6)
+
+/* DA7219_PLL_FRAC_TOP = 0x22 */
+#define DA7219_PLL_FBDIV_FRAC_TOP_SHIFT	0
+#define DA7219_PLL_FBDIV_FRAC_TOP_MASK	(0x1F << 0)
+
+/* DA7219_PLL_FRAC_BOT = 0x23 */
+#define DA7219_PLL_FBDIV_FRAC_BOT_SHIFT	0
+#define DA7219_PLL_FBDIV_FRAC_BOT_MASK	(0xFF << 0)
+
+/* DA7219_PLL_INTEGER = 0x24 */
+#define DA7219_PLL_FBDIV_INTEGER_SHIFT	0
+#define DA7219_PLL_FBDIV_INTEGER_MASK	(0x7F << 0)
+
+/* DA7219_PLL_SRM_STS = 0x25 */
+#define DA7219_PLL_SRM_STATE_SHIFT	0
+#define DA7219_PLL_SRM_STATE_MASK	(0xF << 0)
+#define DA7219_PLL_SRM_STATUS_SHIFT	4
+#define DA7219_PLL_SRM_STATUS_MASK	(0xF << 4)
+#define DA7219_PLL_SRM_STS_MCLK		(0x1 << 4)
+#define DA7219_PLL_SRM_STS_SRM_LOCK	(0x1 << 7)
+
+/* DA7219_DIG_ROUTING_DAI = 0x2A */
+#define DA7219_DAI_L_SRC_SHIFT	0
+#define DA7219_DAI_L_SRC_MASK	(0x3 << 0)
+#define DA7219_DAI_R_SRC_SHIFT	4
+#define DA7219_DAI_R_SRC_MASK	(0x3 << 4)
+#define DA7219_OUT_SRC_MAX	4
+
+/* DA7219_DAI_CLK_MODE = 0x2B */
+#define DA7219_DAI_BCLKS_PER_WCLK_SHIFT	0
+#define DA7219_DAI_BCLKS_PER_WCLK_MASK	(0x3 << 0)
+#define DA7219_DAI_BCLKS_PER_WCLK_32	(0x0 << 0)
+#define DA7219_DAI_BCLKS_PER_WCLK_64	(0x1 << 0)
+#define DA7219_DAI_BCLKS_PER_WCLK_128	(0x2 << 0)
+#define DA7219_DAI_BCLKS_PER_WCLK_256	(0x3 << 0)
+#define DA7219_DAI_CLK_POL_SHIFT	2
+#define DA7219_DAI_CLK_POL_MASK		(0x1 << 2)
+#define DA7219_DAI_CLK_POL_INV		(0x1 << 2)
+#define DA7219_DAI_WCLK_POL_SHIFT	3
+#define DA7219_DAI_WCLK_POL_MASK	(0x1 << 3)
+#define DA7219_DAI_WCLK_POL_INV		(0x1 << 3)
+#define DA7219_DAI_WCLK_TRI_STATE_SHIFT	4
+#define DA7219_DAI_WCLK_TRI_STATE_MASK	(0x1 << 4)
+#define DA7219_DAI_CLK_EN_SHIFT		7
+#define DA7219_DAI_CLK_EN_MASK		(0x1 << 7)
+
+/* DA7219_DAI_CTRL = 0x2C */
+#define DA7219_DAI_FORMAT_SHIFT		0
+#define DA7219_DAI_FORMAT_MASK		(0x3 << 0)
+#define DA7219_DAI_FORMAT_I2S		(0x0 << 0)
+#define DA7219_DAI_FORMAT_LEFT_J	(0x1 << 0)
+#define DA7219_DAI_FORMAT_RIGHT_J	(0x2 << 0)
+#define DA7219_DAI_FORMAT_DSP		(0x3 << 0)
+#define DA7219_DAI_WORD_LENGTH_SHIFT	2
+#define DA7219_DAI_WORD_LENGTH_MASK	(0x3 << 2)
+#define DA7219_DAI_WORD_LENGTH_S16_LE	(0x0 << 2)
+#define DA7219_DAI_WORD_LENGTH_S20_LE	(0x1 << 2)
+#define DA7219_DAI_WORD_LENGTH_S24_LE	(0x2 << 2)
+#define DA7219_DAI_WORD_LENGTH_S32_LE	(0x3 << 2)
+#define DA7219_DAI_CH_NUM_SHIFT		4
+#define DA7219_DAI_CH_NUM_MASK		(0x3 << 4)
+#define DA7219_DAI_CH_NUM_MAX		2
+#define DA7219_DAI_EN_SHIFT		7
+#define DA7219_DAI_EN_MASK		(0x1 << 7)
+
+/* DA7219_DAI_TDM_CTRL = 0x2D */
+#define DA7219_DAI_TDM_CH_EN_SHIFT	0
+#define DA7219_DAI_TDM_CH_EN_MASK	(0x3 << 0)
+#define DA7219_DAI_OE_SHIFT		6
+#define DA7219_DAI_OE_MASK		(0x1 << 6)
+#define DA7219_DAI_TDM_MODE_EN_SHIFT	7
+#define DA7219_DAI_TDM_MODE_EN_MASK	(0x1 << 7)
+#define DA7219_DAI_TDM_MAX_SLOTS	2
+
+/* DA7219_DIG_ROUTING_DAC = 0x2E */
+#define DA7219_DAC_L_SRC_SHIFT		0
+#define DA7219_DAC_L_SRC_MASK		(0x3 << 0)
+#define DA7219_DAC_L_SRC_TONEGEN	(0x1 << 0)
+#define DA7219_DAC_L_MONO_SHIFT		3
+#define DA7219_DAC_L_MONO_MASK		(0x1 << 3)
+#define DA7219_DAC_R_SRC_SHIFT		4
+#define DA7219_DAC_R_SRC_MASK		(0x3 << 4)
+#define DA7219_DAC_R_SRC_TONEGEN	(0x1 << 4)
+#define DA7219_DAC_R_MONO_SHIFT		7
+#define DA7219_DAC_R_MONO_MASK		(0x1 << 7)
+
+/* DA7219_ALC_CTRL1 = 0x2F */
+#define DA7219_ALC_OFFSET_EN_SHIFT	0
+#define DA7219_ALC_OFFSET_EN_MASK	(0x1 << 0)
+#define DA7219_ALC_SYNC_MODE_SHIFT	1
+#define DA7219_ALC_SYNC_MODE_MASK	(0x1 << 1)
+#define DA7219_ALC_EN_SHIFT		3
+#define DA7219_ALC_EN_MASK		(0x1 << 3)
+#define DA7219_ALC_AUTO_CALIB_EN_SHIFT	4
+#define DA7219_ALC_AUTO_CALIB_EN_MASK	(0x1 << 4)
+#define DA7219_ALC_CALIB_OVERFLOW_SHIFT	5
+#define DA7219_ALC_CALIB_OVERFLOW_MASK	(0x1 << 5)
+
+/* DA7219_DAI_OFFSET_LOWER = 0x30 */
+#define DA7219_DAI_OFFSET_LOWER_SHIFT	0
+#define DA7219_DAI_OFFSET_LOWER_MASK	(0xFF << 0)
+
+/* DA7219_DAI_OFFSET_UPPER = 0x31 */
+#define DA7219_DAI_OFFSET_UPPER_SHIFT	0
+#define DA7219_DAI_OFFSET_UPPER_MASK	(0x7 << 0)
+#define DA7219_DAI_OFFSET_MAX		0x2FF
+
+/* DA7219_REFERENCES = 0x32 */
+#define DA7219_BIAS_EN_SHIFT		3
+#define DA7219_BIAS_EN_MASK		(0x1 << 3)
+#define DA7219_VMID_FAST_CHARGE_SHIFT	4
+#define DA7219_VMID_FAST_CHARGE_MASK	(0x1 << 4)
+
+/* DA7219_MIXIN_L_SELECT = 0x33 */
+#define DA7219_MIXIN_L_MIX_SELECT_SHIFT	0
+#define DA7219_MIXIN_L_MIX_SELECT_MASK	(0x1 << 0)
+
+/* DA7219_MIXIN_L_GAIN = 0x34 */
+#define DA7219_MIXIN_L_AMP_GAIN_SHIFT	0
+#define DA7219_MIXIN_L_AMP_GAIN_MASK	(0xF << 0)
+#define DA7219_MIXIN_L_AMP_GAIN_MAX	0xF
+
+/* DA7219_ADC_L_GAIN = 0x36 */
+#define DA7219_ADC_L_DIGITAL_GAIN_SHIFT	0
+#define DA7219_ADC_L_DIGITAL_GAIN_MASK	(0x7F << 0)
+#define DA7219_ADC_L_DIGITAL_GAIN_MAX	0x7F
+
+/* DA7219_ADC_FILTERS1 = 0x38 */
+#define DA7219_ADC_VOICE_HPF_CORNER_SHIFT	0
+#define DA7219_ADC_VOICE_HPF_CORNER_MASK	(0x7 << 0)
+#define DA7219_VOICE_HPF_CORNER_MAX		8
+#define DA7219_ADC_VOICE_EN_SHIFT		3
+#define DA7219_ADC_VOICE_EN_MASK		(0x1 << 3)
+#define DA7219_ADC_AUDIO_HPF_CORNER_SHIFT	4
+#define DA7219_ADC_AUDIO_HPF_CORNER_MASK	(0x3 << 4)
+#define DA7219_AUDIO_HPF_CORNER_MAX		4
+#define DA7219_ADC_HPF_EN_SHIFT			7
+#define DA7219_ADC_HPF_EN_MASK			(0x1 << 7)
+#define DA7219_HPF_MODE_SHIFT			0
+#define DA7219_HPF_DISABLED			((0x0 << 3) | (0x0 << 7))
+#define DA7219_HPF_AUDIO_EN			((0x0 << 3) | (0x1 << 7))
+#define DA7219_HPF_VOICE_EN			((0x1 << 3) | (0x1 << 7))
+#define DA7219_HPF_MODE_MASK			((0x1 << 3) | (0x1 << 7))
+#define DA7219_HPF_MODE_MAX			3
+
+/* DA7219_MIC_1_GAIN = 0x39 */
+#define DA7219_MIC_1_AMP_GAIN_SHIFT	0
+#define DA7219_MIC_1_AMP_GAIN_MASK	(0x7 << 0)
+
+/* DA7219_SIDETONE_CTRL = 0x3A */
+#define DA7219_SIDETONE_MUTE_EN_SHIFT	6
+#define DA7219_SIDETONE_MUTE_EN_MASK	(0x1 << 6)
+#define DA7219_SIDETONE_EN_SHIFT	7
+#define DA7219_SIDETONE_EN_MASK		(0x1 << 7)
+
+/* DA7219_SIDETONE_GAIN = 0x3B */
+#define DA7219_SIDETONE_GAIN_SHIFT	0
+#define DA7219_SIDETONE_GAIN_MASK	(0xF << 0)
+#define DA7219_SIDETONE_GAIN_MAX	0xE
+
+/* DA7219_DROUTING_ST_OUTFILT_1L = 0x3C */
+#define DA7219_OUTFILT_ST_1L_SRC_SHIFT		0
+#define DA7219_OUTFILT_ST_1L_SRC_MASK		(0x7 << 0)
+#define DA7219_DMIX_ST_SRC_OUTFILT1L_SHIFT	0
+#define DA7219_DMIX_ST_SRC_OUTFILT1R_SHIFT	1
+#define DA7219_DMIX_ST_SRC_SIDETONE_SHIFT	2
+#define DA7219_DMIX_ST_SRC_OUTFILT1L		(0x1 << 0)
+#define DA7219_DMIX_ST_SRC_OUTFILT1R		(0x1 << 1)
+
+/* DA7219_DROUTING_ST_OUTFILT_1R = 0x3D */
+#define DA7219_OUTFILT_ST_1R_SRC_SHIFT	0
+#define DA7219_OUTFILT_ST_1R_SRC_MASK	(0x7 << 0)
+
+/* DA7219_DAC_FILTERS5 = 0x40 */
+#define DA7219_DAC_SOFTMUTE_RATE_SHIFT	4
+#define DA7219_DAC_SOFTMUTE_RATE_MASK	(0x7 << 4)
+#define DA7219_DAC_SOFTMUTE_RATE_MAX	7
+#define DA7219_DAC_SOFTMUTE_EN_SHIFT	7
+#define DA7219_DAC_SOFTMUTE_EN_MASK	(0x1 << 7)
+
+/* DA7219_DAC_FILTERS2 = 0x41 */
+#define DA7219_DAC_EQ_BAND1_SHIFT	0
+#define DA7219_DAC_EQ_BAND1_MASK	(0xF << 0)
+#define DA7219_DAC_EQ_BAND2_SHIFT	4
+#define DA7219_DAC_EQ_BAND2_MASK	(0xF << 4)
+#define DA7219_DAC_EQ_BAND_MAX		0xF
+
+/* DA7219_DAC_FILTERS3 = 0x42 */
+#define DA7219_DAC_EQ_BAND3_SHIFT	0
+#define DA7219_DAC_EQ_BAND3_MASK	(0xF << 0)
+#define DA7219_DAC_EQ_BAND4_SHIFT	4
+#define DA7219_DAC_EQ_BAND4_MASK	(0xF << 4)
+
+/* DA7219_DAC_FILTERS4 = 0x43 */
+#define DA7219_DAC_EQ_BAND5_SHIFT	0
+#define DA7219_DAC_EQ_BAND5_MASK	(0xF << 0)
+#define DA7219_DAC_EQ_EN_SHIFT		7
+#define DA7219_DAC_EQ_EN_MASK		(0x1 << 7)
+
+/* DA7219_DAC_FILTERS1 = 0x44 */
+#define DA7219_DAC_VOICE_HPF_CORNER_SHIFT	0
+#define DA7219_DAC_VOICE_HPF_CORNER_MASK	(0x7 << 0)
+#define DA7219_DAC_VOICE_EN_SHIFT		3
+#define DA7219_DAC_VOICE_EN_MASK		(0x1 << 3)
+#define DA7219_DAC_AUDIO_HPF_CORNER_SHIFT	4
+#define DA7219_DAC_AUDIO_HPF_CORNER_MASK	(0x3 << 4)
+#define DA7219_DAC_HPF_EN_SHIFT			7
+#define DA7219_DAC_HPF_EN_MASK			(0x1 << 7)
+
+/* DA7219_DAC_L_GAIN = 0x45 */
+#define DA7219_DAC_L_DIGITAL_GAIN_SHIFT	0
+#define DA7219_DAC_L_DIGITAL_GAIN_MASK	(0x7F << 0)
+#define DA7219_DAC_DIGITAL_GAIN_MAX	0x7F
+#define DA7219_DAC_DIGITAL_GAIN_0DB	(0x6F << 0)
+
+/* DA7219_DAC_R_GAIN = 0x46 */
+#define DA7219_DAC_R_DIGITAL_GAIN_SHIFT	0
+#define DA7219_DAC_R_DIGITAL_GAIN_MASK	(0x7F << 0)
+
+/* DA7219_CP_CTRL = 0x47 */
+#define DA7219_CP_MCHANGE_SHIFT		4
+#define DA7219_CP_MCHANGE_MASK		(0x3 << 4)
+#define DA7219_CP_MCHANGE_REL_MASK	0x3
+#define DA7219_CP_MCHANGE_MAX		3
+#define DA7219_CP_MCHANGE_LARGEST_VOL	0x1
+#define DA7219_CP_MCHANGE_DAC_VOL	0x2
+#define DA7219_CP_MCHANGE_SIG_MAG	0x3
+#define DA7219_CP_EN_SHIFT		7
+#define DA7219_CP_EN_MASK		(0x1 << 7)
+
+/* DA7219_HP_L_GAIN = 0x48 */
+#define DA7219_HP_L_AMP_GAIN_SHIFT	0
+#define DA7219_HP_L_AMP_GAIN_MASK	(0x3F << 0)
+#define DA7219_HP_AMP_GAIN_MAX		0x3F
+#define DA7219_HP_AMP_GAIN_0DB		(0x39 << 0)
+
+/* DA7219_HP_R_GAIN = 0x49 */
+#define DA7219_HP_R_AMP_GAIN_SHIFT	0
+#define DA7219_HP_R_AMP_GAIN_MASK	(0x3F << 0)
+
+/* DA7219_MIXOUT_L_SELECT = 0x4B */
+#define DA7219_MIXOUT_L_MIX_SELECT_SHIFT	0
+#define DA7219_MIXOUT_L_MIX_SELECT_MASK		(0x1 << 0)
+
+/* DA7219_MIXOUT_R_SELECT = 0x4C */
+#define DA7219_MIXOUT_R_MIX_SELECT_SHIFT	0
+#define DA7219_MIXOUT_R_MIX_SELECT_MASK		(0x1 << 0)
+
+/* DA7219_SYSTEM_MODES_INPUT = 0x50 */
+#define DA7219_MODE_SUBMIT_SHIFT	0
+#define DA7219_MODE_SUBMIT_MASK		(0x1 << 0)
+#define DA7219_ADC_MODE_SHIFT		1
+#define DA7219_ADC_MODE_MASK		(0x7F << 1)
+
+/* DA7219_SYSTEM_MODES_OUTPUT = 0x51 */
+#define DA7219_MODE_SUBMIT_SHIFT	0
+#define DA7219_MODE_SUBMIT_MASK		(0x1 << 0)
+#define DA7219_DAC_MODE_SHIFT		1
+#define DA7219_DAC_MODE_MASK		(0x7F << 1)
+
+/* DA7219_MICBIAS_CTRL = 0x62 */
+#define DA7219_MICBIAS1_LEVEL_SHIFT	0
+#define DA7219_MICBIAS1_LEVEL_MASK	(0x7 << 0)
+#define DA7219_MICBIAS1_EN_SHIFT	3
+#define DA7219_MICBIAS1_EN_MASK		(0x1 << 3)
+
+/* DA7219_MIC_1_CTRL = 0x63 */
+#define DA7219_MIC_1_AMP_RAMP_EN_SHIFT	5
+#define DA7219_MIC_1_AMP_RAMP_EN_MASK	(0x1 << 5)
+#define DA7219_MIC_1_AMP_MUTE_EN_SHIFT	6
+#define DA7219_MIC_1_AMP_MUTE_EN_MASK	(0x1 << 6)
+#define DA7219_MIC_1_AMP_EN_SHIFT	7
+#define DA7219_MIC_1_AMP_EN_MASK	(0x1 << 7)
+
+/* DA7219_MIXIN_L_CTRL = 0x65 */
+#define DA7219_MIXIN_L_MIX_EN_SHIFT		3
+#define DA7219_MIXIN_L_MIX_EN_MASK		(0x1 << 3)
+#define DA7219_MIXIN_L_AMP_ZC_EN_SHIFT		4
+#define DA7219_MIXIN_L_AMP_ZC_EN_MASK		(0x1 << 4)
+#define DA7219_MIXIN_L_AMP_RAMP_EN_SHIFT	5
+#define DA7219_MIXIN_L_AMP_RAMP_EN_MASK		(0x1 << 5)
+#define DA7219_MIXIN_L_AMP_MUTE_EN_SHIFT	6
+#define DA7219_MIXIN_L_AMP_MUTE_EN_MASK		(0x1 << 6)
+#define DA7219_MIXIN_L_AMP_EN_SHIFT		7
+#define DA7219_MIXIN_L_AMP_EN_MASK		(0x1 << 7)
+
+/* DA7219_ADC_L_CTRL = 0x67 */
+#define DA7219_ADC_L_BIAS_SHIFT		0
+#define DA7219_ADC_L_BIAS_MASK		(0x3 << 0)
+#define DA7219_ADC_L_RAMP_EN_SHIFT	5
+#define DA7219_ADC_L_RAMP_EN_MASK	(0x1 << 5)
+#define DA7219_ADC_L_MUTE_EN_SHIFT	6
+#define DA7219_ADC_L_MUTE_EN_MASK	(0x1 << 6)
+#define DA7219_ADC_L_EN_SHIFT		7
+#define DA7219_ADC_L_EN_MASK		(0x1 << 7)
+
+/* DA7219_DAC_L_CTRL = 0x69 */
+#define DA7219_DAC_L_RAMP_EN_SHIFT	5
+#define DA7219_DAC_L_RAMP_EN_MASK	(0x1 << 5)
+#define DA7219_DAC_L_MUTE_EN_SHIFT	6
+#define DA7219_DAC_L_MUTE_EN_MASK	(0x1 << 6)
+#define DA7219_DAC_L_EN_SHIFT		7
+#define DA7219_DAC_L_EN_MASK		(0x1 << 7)
+
+/* DA7219_DAC_R_CTRL = 0x6A */
+#define DA7219_DAC_R_RAMP_EN_SHIFT	5
+#define DA7219_DAC_R_RAMP_EN_MASK	(0x1 << 5)
+#define DA7219_DAC_R_MUTE_EN_SHIFT	6
+#define DA7219_DAC_R_MUTE_EN_MASK	(0x1 << 6)
+#define DA7219_DAC_R_EN_SHIFT		7
+#define DA7219_DAC_R_EN_MASK		(0x1 << 7)
+
+/* DA7219_HP_L_CTRL = 0x6B */
+#define DA7219_HP_L_AMP_MIN_GAIN_EN_SHIFT	2
+#define DA7219_HP_L_AMP_MIN_GAIN_EN_MASK	(0x1 << 2)
+#define DA7219_HP_L_AMP_OE_SHIFT		3
+#define DA7219_HP_L_AMP_OE_MASK			(0x1 << 3)
+#define DA7219_HP_L_AMP_ZC_EN_SHIFT		4
+#define DA7219_HP_L_AMP_ZC_EN_MASK		(0x1 << 4)
+#define DA7219_HP_L_AMP_RAMP_EN_SHIFT		5
+#define DA7219_HP_L_AMP_RAMP_EN_MASK		(0x1 << 5)
+#define DA7219_HP_L_AMP_MUTE_EN_SHIFT		6
+#define DA7219_HP_L_AMP_MUTE_EN_MASK		(0x1 << 6)
+#define DA7219_HP_L_AMP_EN_SHIFT		7
+#define DA7219_HP_L_AMP_EN_MASK			(0x1 << 7)
+
+/* DA7219_HP_R_CTRL = 0x6C */
+#define DA7219_HP_R_AMP_MIN_GAIN_EN_SHIFT	2
+#define DA7219_HP_R_AMP_MIN_GAIN_EN_MASK	(0x1 << 2)
+#define DA7219_HP_R_AMP_OE_SHIFT		3
+#define DA7219_HP_R_AMP_OE_MASK			(0x1 << 3)
+#define DA7219_HP_R_AMP_ZC_EN_SHIFT		4
+#define DA7219_HP_R_AMP_ZC_EN_MASK		(0x1 << 4)
+#define DA7219_HP_R_AMP_RAMP_EN_SHIFT		5
+#define DA7219_HP_R_AMP_RAMP_EN_MASK		(0x1 << 5)
+#define DA7219_HP_R_AMP_MUTE_EN_SHIFT		6
+#define DA7219_HP_R_AMP_MUTE_EN_MASK		(0x1 << 6)
+#define DA7219_HP_R_AMP_EN_SHIFT		7
+#define DA7219_HP_R_AMP_EN_MASK			(0x1 << 7)
+
+/* DA7219_MIXOUT_L_CTRL = 0x6E */
+#define DA7219_MIXOUT_L_AMP_EN_SHIFT	7
+#define DA7219_MIXOUT_L_AMP_EN_MASK	(0x1 << 7)
+
+/* DA7219_MIXOUT_R_CTRL = 0x6F */
+#define DA7219_MIXOUT_R_AMP_EN_SHIFT	7
+#define DA7219_MIXOUT_R_AMP_EN_MASK	(0x1 << 7)
+
+/* DA7219_CHIP_ID1 = 0x81 */
+#define DA7219_CHIP_ID1_SHIFT	0
+#define DA7219_CHIP_ID1_MASK	(0xFF << 0)
+
+/* DA7219_CHIP_ID2 = 0x82 */
+#define DA7219_CHIP_ID2_SHIFT	0
+#define DA7219_CHIP_ID2_MASK	(0xFF << 0)
+
+/* DA7219_CHIP_REVISION = 0x83 */
+#define DA7219_CHIP_MINOR_SHIFT	0
+#define DA7219_CHIP_MINOR_MASK	(0xF << 0)
+#define DA7219_CHIP_MAJOR_SHIFT	4
+#define DA7219_CHIP_MAJOR_MASK	(0xF << 4)
+
+/* DA7219_IO_CTRL = 0x91 */
+#define DA7219_IO_VOLTAGE_LEVEL_SHIFT		0
+#define DA7219_IO_VOLTAGE_LEVEL_MASK		(0x1 << 0)
+#define DA7219_IO_VOLTAGE_LEVEL_2_5V_3_6V	0
+#define DA7219_IO_VOLTAGE_LEVEL_1_2V_2_8V	1
+
+/* DA7219_GAIN_RAMP_CTRL = 0x92 */
+#define DA7219_GAIN_RAMP_RATE_SHIFT	0
+#define DA7219_GAIN_RAMP_RATE_MASK	(0x3 << 0)
+#define DA7219_GAIN_RAMP_RATE_X8	(0x0 << 0)
+#define DA7219_GAIN_RAMP_RATE_NOMINAL	(0x1 << 0)
+#define DA7219_GAIN_RAMP_RATE_MAX	4
+
+/* DA7219_PC_COUNT = 0x94 */
+#define DA7219_PC_FREERUN_SHIFT		0
+#define DA7219_PC_FREERUN_MASK		(0x1 << 0)
+#define DA7219_PC_RESYNC_AUTO_SHIFT	1
+#define DA7219_PC_RESYNC_AUTO_MASK	(0x1 << 1)
+
+/* DA7219_CP_VOL_THRESHOLD1 = 0x95 */
+#define DA7219_CP_THRESH_VDD2_SHIFT	0
+#define DA7219_CP_THRESH_VDD2_MASK	(0x3F << 0)
+#define DA7219_CP_THRESH_VDD2_MAX	0x3F
+
+/* DA7219_DIG_CTRL = 0x99 */
+#define DA7219_DAC_L_INV_SHIFT	3
+#define DA7219_DAC_L_INV_MASK	(0x1 << 3)
+#define DA7219_DAC_R_INV_SHIFT	7
+#define DA7219_DAC_R_INV_MASK	(0x1 << 7)
+
+/* DA7219_ALC_CTRL2 = 0x9A */
+#define DA7219_ALC_ATTACK_SHIFT		0
+#define DA7219_ALC_ATTACK_MASK		(0xF << 0)
+#define DA7219_ALC_ATTACK_MAX		13
+#define DA7219_ALC_RELEASE_SHIFT	4
+#define DA7219_ALC_RELEASE_MASK		(0xF << 4)
+#define DA7219_ALC_RELEASE_MAX		11
+
+/* DA7219_ALC_CTRL3 = 0x9B */
+#define DA7219_ALC_HOLD_SHIFT		0
+#define DA7219_ALC_HOLD_MASK		(0xF << 0)
+#define DA7219_ALC_HOLD_MAX		16
+#define DA7219_ALC_INTEG_ATTACK_SHIFT	4
+#define DA7219_ALC_INTEG_ATTACK_MASK	(0x3 << 4)
+#define DA7219_ALC_INTEG_RELEASE_SHIFT	6
+#define DA7219_ALC_INTEG_RELEASE_MASK	(0x3 << 6)
+#define DA7219_ALC_INTEG_MAX		4
+
+/* DA7219_ALC_NOISE = 0x9C */
+#define DA7219_ALC_NOISE_SHIFT		0
+#define DA7219_ALC_NOISE_MASK		(0x3F << 0)
+#define DA7219_ALC_THRESHOLD_MAX	0x3F
+
+/* DA7219_ALC_TARGET_MIN = 0x9D */
+#define DA7219_ALC_THRESHOLD_MIN_SHIFT	0
+#define DA7219_ALC_THRESHOLD_MIN_MASK	(0x3F << 0)
+
+/* DA7219_ALC_TARGET_MAX = 0x9E */
+#define DA7219_ALC_THRESHOLD_MAX_SHIFT	0
+#define DA7219_ALC_THRESHOLD_MAX_MASK	(0x3F << 0)
+
+/* DA7219_ALC_GAIN_LIMITS = 0x9F */
+#define DA7219_ALC_ATTEN_MAX_SHIFT	0
+#define DA7219_ALC_ATTEN_MAX_MASK	(0xF << 0)
+#define DA7219_ALC_GAIN_MAX_SHIFT	4
+#define DA7219_ALC_GAIN_MAX_MASK	(0xF << 4)
+#define DA7219_ALC_ATTEN_GAIN_MAX	0xF
+
+/* DA7219_ALC_ANA_GAIN_LIMITS = 0xA0 */
+#define DA7219_ALC_ANA_GAIN_MIN_SHIFT	0
+#define DA7219_ALC_ANA_GAIN_MIN_MASK	(0x7 << 0)
+#define DA7219_ALC_ANA_GAIN_MIN		0x1
+#define DA7219_ALC_ANA_GAIN_MAX_SHIFT	4
+#define DA7219_ALC_ANA_GAIN_MAX_MASK	(0x7 << 4)
+#define DA7219_ALC_ANA_GAIN_MAX		0x7
+
+/* DA7219_ALC_ANTICLIP_CTRL = 0xA1 */
+#define DA7219_ALC_ANTICLIP_STEP_SHIFT	0
+#define DA7219_ALC_ANTICLIP_STEP_MASK	(0x3 << 0)
+#define DA7219_ALC_ANTICLIP_STEP_MAX	4
+#define DA7219_ALC_ANTIPCLIP_EN_SHIFT	7
+#define DA7219_ALC_ANTIPCLIP_EN_MASK	(0x1 << 7)
+
+/* DA7219_ALC_ANTICLIP_LEVEL = 0xA2 */
+#define DA7219_ALC_ANTICLIP_LEVEL_SHIFT	0
+#define DA7219_ALC_ANTICLIP_LEVEL_MASK	(0x7F << 0)
+
+/* DA7219_ALC_OFFSET_AUTO_M_L = 0xA3 */
+#define DA7219_ALC_OFFSET_AUTO_M_L_SHIFT	0
+#define DA7219_ALC_OFFSET_AUTO_M_L_MASK		(0xFF << 0)
+
+/* DA7219_ALC_OFFSET_AUTO_U_L = 0xA4 */
+#define DA7219_ALC_OFFSET_AUTO_U_L_SHIFT	0
+#define DA7219_ALC_OFFSET_AUTO_U_L_MASK		(0xF << 0)
+
+/* DA7219_DAC_NG_SETUP_TIME = 0xAF */
+#define DA7219_DAC_NG_SETUP_TIME_SHIFT	0
+#define DA7219_DAC_NG_SETUP_TIME_MASK	(0x3 << 0)
+#define DA7219_DAC_NG_SETUP_TIME_MAX	4
+#define DA7219_DAC_NG_RAMPUP_RATE_SHIFT	2
+#define DA7219_DAC_NG_RAMPUP_RATE_MASK	(0x1 << 2)
+#define DA7219_DAC_NG_RAMPDN_RATE_SHIFT	3
+#define DA7219_DAC_NG_RAMPDN_RATE_MASK	(0x1 << 3)
+#define DA7219_DAC_NG_RAMP_RATE_MAX	2
+
+/* DA7219_DAC_NG_OFF_THRESH = 0xB0 */
+#define DA7219_DAC_NG_OFF_THRESHOLD_SHIFT	0
+#define DA7219_DAC_NG_OFF_THRESHOLD_MASK	(0x7 << 0)
+#define DA7219_DAC_NG_THRESHOLD_MAX		0x7
+
+/* DA7219_DAC_NG_ON_THRESH = 0xB1 */
+#define DA7219_DAC_NG_ON_THRESHOLD_SHIFT	0
+#define DA7219_DAC_NG_ON_THRESHOLD_MASK		(0x7 << 0)
+
+/* DA7219_DAC_NG_CTRL = 0xB2 */
+#define DA7219_DAC_NG_EN_SHIFT	7
+#define DA7219_DAC_NG_EN_MASK	(0x1 << 7)
+
+/* DA7219_TONE_GEN_CFG1 = 0xB4 */
+#define DA7219_DTMF_REG_SHIFT		0
+#define DA7219_DTMF_REG_MASK		(0xF << 0)
+#define DA7219_DTMF_REG_MAX		16
+#define DA7219_DTMF_EN_SHIFT		4
+#define DA7219_DTMF_EN_MASK		(0x1 << 4)
+#define DA7219_START_STOPN_SHIFT	7
+#define DA7219_START_STOPN_MASK		(0x1 << 7)
+
+/* DA7219_TONE_GEN_CFG2 = 0xB5 */
+#define DA7219_SWG_SEL_SHIFT		0
+#define DA7219_SWG_SEL_MASK		(0x3 << 0)
+#define DA7219_SWG_SEL_MAX		4
+#define DA7219_SWG_SEL_SRAMP		(0x3 << 0)
+#define DA7219_TONE_GEN_GAIN_SHIFT	4
+#define DA7219_TONE_GEN_GAIN_MASK	(0xF << 4)
+#define DA7219_TONE_GEN_GAIN_MAX	0xF
+#define DA7219_TONE_GEN_GAIN_MINUS_9DB	(0x3 << 4)
+#define DA7219_TONE_GEN_GAIN_MINUS_15DB	(0x5 << 4)
+
+/* DA7219_TONE_GEN_CYCLES = 0xB6 */
+#define DA7219_BEEP_CYCLES_SHIFT	0
+#define DA7219_BEEP_CYCLES_MASK		(0x7 << 0)
+
+/* DA7219_TONE_GEN_FREQ1_L = 0xB7 */
+#define DA7219_FREQ1_L_SHIFT	0
+#define DA7219_FREQ1_L_MASK	(0xFF << 0)
+#define DA7219_FREQ_MAX		0xFFFF
+
+/* DA7219_TONE_GEN_FREQ1_U = 0xB8 */
+#define DA7219_FREQ1_U_SHIFT	0
+#define DA7219_FREQ1_U_MASK	(0xFF << 0)
+
+/* DA7219_TONE_GEN_FREQ2_L = 0xB9 */
+#define DA7219_FREQ2_L_SHIFT	0
+#define DA7219_FREQ2_L_MASK	(0xFF << 0)
+
+/* DA7219_TONE_GEN_FREQ2_U = 0xBA */
+#define DA7219_FREQ2_U_SHIFT	0
+#define DA7219_FREQ2_U_MASK	(0xFF << 0)
+
+/* DA7219_TONE_GEN_ON_PER = 0xBB */
+#define DA7219_BEEP_ON_PER_SHIFT	0
+#define DA7219_BEEP_ON_PER_MASK		(0x3F << 0)
+#define DA7219_BEEP_ON_OFF_MAX		0x3F
+
+/* DA7219_TONE_GEN_OFF_PER = 0xBC */
+#define DA7219_BEEP_OFF_PER_SHIFT	0
+#define DA7219_BEEP_OFF_PER_MASK	(0x3F << 0)
+
+/* DA7219_SYSTEM_STATUS = 0xE0 */
+#define DA7219_SC1_BUSY_SHIFT	0
+#define DA7219_SC1_BUSY_MASK	(0x1 << 0)
+#define DA7219_SC2_BUSY_SHIFT	1
+#define DA7219_SC2_BUSY_MASK	(0x1 << 1)
+
+/* DA7219_SYSTEM_ACTIVE = 0xFD */
+#define DA7219_SYSTEM_ACTIVE_SHIFT	0
+#define DA7219_SYSTEM_ACTIVE_MASK	(0x1 << 0)
+
+
+/*
+ * General defines & data
+ */
+
+/* Register inversion */
+#define DA7219_NO_INVERT	0
+#define DA7219_INVERT		1
+
+/* Byte related defines */
+#define DA7219_BYTE_SHIFT	8
+#define DA7219_BYTE_MASK	0xFF
+
+/* PLL Output Frequencies */
+#define DA7219_PLL_FREQ_OUT_90316	90316800
+#define DA7219_PLL_FREQ_OUT_98304	98304000
+
+/* PLL Frequency Dividers */
+#define DA7219_PLL_INDIV_2_TO_4_5_MHZ_VAL	1
+#define DA7219_PLL_INDIV_4_5_TO_9_MHZ_VAL	2
+#define DA7219_PLL_INDIV_9_TO_18_MHZ_VAL	4
+#define DA7219_PLL_INDIV_18_TO_36_MHZ_VAL	8
+#define DA7219_PLL_INDIV_36_TO_54_MHZ_VAL	16
+
+/* SRM */
+#define DA7219_SRM_CHECK_RETRIES	8
+
+/* System Controller */
+#define DA7219_SYS_STAT_CHECK_RETRIES	6
+#define DA7219_SYS_STAT_CHECK_DELAY	50
+
+/* Power up/down Delays */
+#define DA7219_SETTLING_DELAY		40
+#define DA7219_MIN_GAIN_DELAY		30
+#define DA7219_MIC_PGA_BASE_DELAY	100
+#define DA7219_MIC_PGA_OFFSET_DELAY	40
+
+enum da7219_clk_src {
+	DA7219_CLKSRC_MCLK = 0,
+	DA7219_CLKSRC_MCLK_SQR,
+};
+
+enum da7219_sys_clk {
+	DA7219_SYSCLK_MCLK = 0,
+	DA7219_SYSCLK_PLL,
+	DA7219_SYSCLK_PLL_SRM,
+};
+
+/* Regulators */
+enum da7219_supplies {
+	DA7219_SUPPLY_VDD = 0,
+	DA7219_SUPPLY_VDDMIC,
+	DA7219_SUPPLY_VDDIO,
+	DA7219_NUM_SUPPLIES,
+};
+
+struct da7219_aad_priv;
+
+/* Private data */
+struct da7219_priv {
+	struct da7219_aad_priv *aad;
+	struct da7219_pdata *pdata;
+
+	bool wakeup_source;
+	struct regulator_bulk_data supplies[DA7219_NUM_SUPPLIES];
+	struct regmap *regmap;
+	struct mutex ctrl_lock;
+	struct mutex pll_lock;
+
+#ifdef CONFIG_COMMON_CLK
+	struct clk_hw dai_clks_hw;
+#endif
+	struct clk_lookup *dai_clks_lookup;
+	struct clk *dai_clks;
+
+	struct clk *mclk;
+	unsigned int mclk_rate;
+	int clk_src;
+
+	bool master;
+	bool alc_en;
+	bool micbias_on_event;
+	unsigned int mic_pga_delay;
+	u8 gain_ramp_ctrl;
+};
+
+int da7219_set_pll(struct snd_soc_component *component, int source, unsigned int fout);
+
+#endif /* __DA7219_H */
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
new file mode 100644
index 0000000..de275df
--- /dev/null
+++ b/sound/soc/codecs/da732x.c
@@ -0,0 +1,1583 @@
+/*
+ * da732x.c --- Dialog DA732X ALSA SoC Audio Driver
+ *
+ * Copyright (C) 2012 Dialog Semiconductor GmbH
+ *
+ * Author: Michal Hajduk <Michal.Hajduk@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+
+#include "da732x.h"
+#include "da732x_reg.h"
+
+
+struct da732x_priv {
+	struct regmap *regmap;
+
+	unsigned int sysclk;
+	bool pll_en;
+};
+
+/*
+ * da732x register cache - default settings
+ */
+static const struct reg_default da732x_reg_cache[] = {
+	{ DA732X_REG_REF1		, 0x02 },
+	{ DA732X_REG_BIAS_EN		, 0x80 },
+	{ DA732X_REG_BIAS1		, 0x00 },
+	{ DA732X_REG_BIAS2		, 0x00 },
+	{ DA732X_REG_BIAS3		, 0x00 },
+	{ DA732X_REG_BIAS4		, 0x00 },
+	{ DA732X_REG_MICBIAS2		, 0x00 },
+	{ DA732X_REG_MICBIAS1		, 0x00 },
+	{ DA732X_REG_MICDET		, 0x00 },
+	{ DA732X_REG_MIC1_PRE		, 0x01 },
+	{ DA732X_REG_MIC1		, 0x40 },
+	{ DA732X_REG_MIC2_PRE		, 0x01 },
+	{ DA732X_REG_MIC2		, 0x40 },
+	{ DA732X_REG_AUX1L		, 0x75 },
+	{ DA732X_REG_AUX1R		, 0x75 },
+	{ DA732X_REG_MIC3_PRE		, 0x01 },
+	{ DA732X_REG_MIC3		, 0x40 },
+	{ DA732X_REG_INP_PINBIAS	, 0x00 },
+	{ DA732X_REG_INP_ZC_EN		, 0x00 },
+	{ DA732X_REG_INP_MUX		, 0x50 },
+	{ DA732X_REG_HP_DET		, 0x00 },
+	{ DA732X_REG_HPL_DAC_OFFSET	, 0x00 },
+	{ DA732X_REG_HPL_DAC_OFF_CNTL	, 0x00 },
+	{ DA732X_REG_HPL_OUT_OFFSET	, 0x00 },
+	{ DA732X_REG_HPL		, 0x40 },
+	{ DA732X_REG_HPL_VOL		, 0x0F },
+	{ DA732X_REG_HPR_DAC_OFFSET	, 0x00 },
+	{ DA732X_REG_HPR_DAC_OFF_CNTL	, 0x00 },
+	{ DA732X_REG_HPR_OUT_OFFSET	, 0x00 },
+	{ DA732X_REG_HPR		, 0x40 },
+	{ DA732X_REG_HPR_VOL		, 0x0F },
+	{ DA732X_REG_LIN2		, 0x4F },
+	{ DA732X_REG_LIN3		, 0x4F },
+	{ DA732X_REG_LIN4		, 0x4F },
+	{ DA732X_REG_OUT_ZC_EN		, 0x00 },
+	{ DA732X_REG_HP_LIN1_GNDSEL	, 0x00 },
+	{ DA732X_REG_CP_HP1		, 0x0C },
+	{ DA732X_REG_CP_HP2		, 0x03 },
+	{ DA732X_REG_CP_CTRL1		, 0x00 },
+	{ DA732X_REG_CP_CTRL2		, 0x99 },
+	{ DA732X_REG_CP_CTRL3		, 0x25 },
+	{ DA732X_REG_CP_LEVEL_MASK	, 0x3F },
+	{ DA732X_REG_CP_DET		, 0x00 },
+	{ DA732X_REG_CP_STATUS		, 0x00 },
+	{ DA732X_REG_CP_THRESH1		, 0x00 },
+	{ DA732X_REG_CP_THRESH2		, 0x00 },
+	{ DA732X_REG_CP_THRESH3		, 0x00 },
+	{ DA732X_REG_CP_THRESH4		, 0x00 },
+	{ DA732X_REG_CP_THRESH5		, 0x00 },
+	{ DA732X_REG_CP_THRESH6		, 0x00 },
+	{ DA732X_REG_CP_THRESH7		, 0x00 },
+	{ DA732X_REG_CP_THRESH8		, 0x00 },
+	{ DA732X_REG_PLL_DIV_LO		, 0x00 },
+	{ DA732X_REG_PLL_DIV_MID	, 0x00 },
+	{ DA732X_REG_PLL_DIV_HI		, 0x00 },
+	{ DA732X_REG_PLL_CTRL		, 0x02 },
+	{ DA732X_REG_CLK_CTRL		, 0xaa },
+	{ DA732X_REG_CLK_DSP		, 0x07 },
+	{ DA732X_REG_CLK_EN1		, 0x00 },
+	{ DA732X_REG_CLK_EN2		, 0x00 },
+	{ DA732X_REG_CLK_EN3		, 0x00 },
+	{ DA732X_REG_CLK_EN4		, 0x00 },
+	{ DA732X_REG_CLK_EN5		, 0x00 },
+	{ DA732X_REG_AIF_MCLK		, 0x00 },
+	{ DA732X_REG_AIFA1		, 0x02 },
+	{ DA732X_REG_AIFA2		, 0x00 },
+	{ DA732X_REG_AIFA3		, 0x08 },
+	{ DA732X_REG_AIFB1		, 0x02 },
+	{ DA732X_REG_AIFB2		, 0x00 },
+	{ DA732X_REG_AIFB3		, 0x08 },
+	{ DA732X_REG_PC_CTRL		, 0xC0 },
+	{ DA732X_REG_DATA_ROUTE		, 0x00 },
+	{ DA732X_REG_DSP_CTRL		, 0x00 },
+	{ DA732X_REG_CIF_CTRL2		, 0x00 },
+	{ DA732X_REG_HANDSHAKE		, 0x00 },
+	{ DA732X_REG_SPARE1_OUT		, 0x00 },
+	{ DA732X_REG_SPARE2_OUT		, 0x00 },
+	{ DA732X_REG_SPARE1_IN		, 0x00 },
+	{ DA732X_REG_ADC1_PD		, 0x00 },
+	{ DA732X_REG_ADC1_HPF		, 0x00 },
+	{ DA732X_REG_ADC1_SEL		, 0x00 },
+	{ DA732X_REG_ADC1_EQ12		, 0x00 },
+	{ DA732X_REG_ADC1_EQ34		, 0x00 },
+	{ DA732X_REG_ADC1_EQ5		, 0x00 },
+	{ DA732X_REG_ADC2_PD		, 0x00 },
+	{ DA732X_REG_ADC2_HPF		, 0x00 },
+	{ DA732X_REG_ADC2_SEL		, 0x00 },
+	{ DA732X_REG_ADC2_EQ12		, 0x00 },
+	{ DA732X_REG_ADC2_EQ34		, 0x00 },
+	{ DA732X_REG_ADC2_EQ5		, 0x00 },
+	{ DA732X_REG_DAC1_HPF		, 0x00 },
+	{ DA732X_REG_DAC1_L_VOL		, 0x00 },
+	{ DA732X_REG_DAC1_R_VOL		, 0x00 },
+	{ DA732X_REG_DAC1_SEL		, 0x00 },
+	{ DA732X_REG_DAC1_SOFTMUTE	, 0x00 },
+	{ DA732X_REG_DAC1_EQ12		, 0x00 },
+	{ DA732X_REG_DAC1_EQ34		, 0x00 },
+	{ DA732X_REG_DAC1_EQ5		, 0x00 },
+	{ DA732X_REG_DAC2_HPF		, 0x00 },
+	{ DA732X_REG_DAC2_L_VOL		, 0x00 },
+	{ DA732X_REG_DAC2_R_VOL		, 0x00 },
+	{ DA732X_REG_DAC2_SEL		, 0x00 },
+	{ DA732X_REG_DAC2_SOFTMUTE	, 0x00 },
+	{ DA732X_REG_DAC2_EQ12		, 0x00 },
+	{ DA732X_REG_DAC2_EQ34		, 0x00 },
+	{ DA732X_REG_DAC2_EQ5		, 0x00 },
+	{ DA732X_REG_DAC3_HPF		, 0x00 },
+	{ DA732X_REG_DAC3_VOL		, 0x00 },
+	{ DA732X_REG_DAC3_SEL		, 0x00 },
+	{ DA732X_REG_DAC3_SOFTMUTE	, 0x00 },
+	{ DA732X_REG_DAC3_EQ12		, 0x00 },
+	{ DA732X_REG_DAC3_EQ34		, 0x00 },
+	{ DA732X_REG_DAC3_EQ5		, 0x00 },
+	{ DA732X_REG_BIQ_BYP		, 0x00 },
+	{ DA732X_REG_DMA_CMD		, 0x00 },
+	{ DA732X_REG_DMA_ADDR0		, 0x00 },
+	{ DA732X_REG_DMA_ADDR1		, 0x00 },
+	{ DA732X_REG_DMA_DATA0		, 0x00 },
+	{ DA732X_REG_DMA_DATA1		, 0x00 },
+	{ DA732X_REG_DMA_DATA2		, 0x00 },
+	{ DA732X_REG_DMA_DATA3		, 0x00 },
+	{ DA732X_REG_UNLOCK		, 0x00 },
+};
+
+static inline int da732x_get_input_div(struct snd_soc_component *component, int sysclk)
+{
+	int val;
+	int ret;
+
+	if (sysclk < DA732X_MCLK_10MHZ) {
+		val = DA732X_MCLK_RET_0_10MHZ;
+		ret = DA732X_MCLK_VAL_0_10MHZ;
+	} else if ((sysclk >= DA732X_MCLK_10MHZ) &&
+	    (sysclk < DA732X_MCLK_20MHZ)) {
+		val = DA732X_MCLK_RET_10_20MHZ;
+		ret = DA732X_MCLK_VAL_10_20MHZ;
+	} else if ((sysclk >= DA732X_MCLK_20MHZ) &&
+	    (sysclk < DA732X_MCLK_40MHZ)) {
+		val = DA732X_MCLK_RET_20_40MHZ;
+		ret = DA732X_MCLK_VAL_20_40MHZ;
+	} else if ((sysclk >= DA732X_MCLK_40MHZ) &&
+	    (sysclk <= DA732X_MCLK_54MHZ)) {
+		val = DA732X_MCLK_RET_40_54MHZ;
+		ret = DA732X_MCLK_VAL_40_54MHZ;
+	} else {
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, DA732X_REG_PLL_CTRL, val);
+
+	return ret;
+}
+
+static void da732x_set_charge_pump(struct snd_soc_component *component, int state)
+{
+	switch (state) {
+	case DA732X_ENABLE_CP:
+		snd_soc_component_write(component, DA732X_REG_CLK_EN2, DA732X_CP_CLK_EN);
+		snd_soc_component_write(component, DA732X_REG_CP_HP2, DA732X_HP_CP_EN |
+			      DA732X_HP_CP_REG | DA732X_HP_CP_PULSESKIP);
+		snd_soc_component_write(component, DA732X_REG_CP_CTRL1, DA732X_CP_EN |
+			      DA732X_CP_CTRL_CPVDD1);
+		snd_soc_component_write(component, DA732X_REG_CP_CTRL2,
+			      DA732X_CP_MANAGE_MAGNITUDE | DA732X_CP_BOOST);
+		snd_soc_component_write(component, DA732X_REG_CP_CTRL3, DA732X_CP_1MHZ);
+		break;
+	case DA732X_DISABLE_CP:
+		snd_soc_component_write(component, DA732X_REG_CLK_EN2, DA732X_CP_CLK_DIS);
+		snd_soc_component_write(component, DA732X_REG_CP_HP2, DA732X_HP_CP_DIS);
+		snd_soc_component_write(component, DA732X_REG_CP_CTRL1, DA723X_CP_DIS);
+		break;
+	default:
+		pr_err("Wrong charge pump state\n");
+		break;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(mic_boost_tlv, DA732X_MIC_PRE_VOL_DB_MIN,
+				  DA732X_MIC_PRE_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, DA732X_MIC_VOL_DB_MIN,
+				  DA732X_MIC_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(aux_pga_tlv, DA732X_AUX_VOL_DB_MIN,
+				  DA732X_AUX_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(hp_pga_tlv, DA732X_HP_VOL_DB_MIN,
+				  DA732X_AUX_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(lin2_pga_tlv, DA732X_LIN2_VOL_DB_MIN,
+				  DA732X_LIN2_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(lin3_pga_tlv, DA732X_LIN3_VOL_DB_MIN,
+				  DA732X_LIN3_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(lin4_pga_tlv, DA732X_LIN4_VOL_DB_MIN,
+				  DA732X_LIN4_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(adc_pga_tlv, DA732X_ADC_VOL_DB_MIN,
+				  DA732X_ADC_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(dac_pga_tlv, DA732X_DAC_VOL_DB_MIN,
+				  DA732X_DAC_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(eq_band_pga_tlv, DA732X_EQ_BAND_VOL_DB_MIN,
+				  DA732X_EQ_BAND_VOL_DB_INC, 0);
+
+static const DECLARE_TLV_DB_SCALE(eq_overall_tlv, DA732X_EQ_OVERALL_VOL_DB_MIN,
+				  DA732X_EQ_OVERALL_VOL_DB_INC, 0);
+
+/* High Pass Filter */
+static const char *da732x_hpf_mode[] = {
+	"Disable", "Music", "Voice",
+};
+
+static const char *da732x_hpf_music[] = {
+	"1.8Hz", "3.75Hz", "7.5Hz", "15Hz",
+};
+
+static const char *da732x_hpf_voice[] = {
+	"2.5Hz", "25Hz", "50Hz", "100Hz",
+	"150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(da732x_dac1_hpf_mode_enum,
+			    DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT,
+			    da732x_hpf_mode);
+
+static SOC_ENUM_SINGLE_DECL(da732x_dac2_hpf_mode_enum,
+			    DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT,
+			    da732x_hpf_mode);
+
+static SOC_ENUM_SINGLE_DECL(da732x_dac3_hpf_mode_enum,
+			    DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT,
+			    da732x_hpf_mode);
+
+static SOC_ENUM_SINGLE_DECL(da732x_adc1_hpf_mode_enum,
+			    DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT,
+			    da732x_hpf_mode);
+
+static SOC_ENUM_SINGLE_DECL(da732x_adc2_hpf_mode_enum,
+			    DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT,
+			    da732x_hpf_mode);
+
+static SOC_ENUM_SINGLE_DECL(da732x_dac1_hp_filter_enum,
+			    DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT,
+			    da732x_hpf_music);
+
+static SOC_ENUM_SINGLE_DECL(da732x_dac2_hp_filter_enum,
+			    DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT,
+			    da732x_hpf_music);
+
+static SOC_ENUM_SINGLE_DECL(da732x_dac3_hp_filter_enum,
+			    DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT,
+			    da732x_hpf_music);
+
+static SOC_ENUM_SINGLE_DECL(da732x_adc1_hp_filter_enum,
+			    DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT,
+			    da732x_hpf_music);
+
+static SOC_ENUM_SINGLE_DECL(da732x_adc2_hp_filter_enum,
+			    DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT,
+			    da732x_hpf_music);
+
+static SOC_ENUM_SINGLE_DECL(da732x_dac1_voice_filter_enum,
+			    DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT,
+			    da732x_hpf_voice);
+
+static SOC_ENUM_SINGLE_DECL(da732x_dac2_voice_filter_enum,
+			    DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT,
+			    da732x_hpf_voice);
+
+static SOC_ENUM_SINGLE_DECL(da732x_dac3_voice_filter_enum,
+			    DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT,
+			    da732x_hpf_voice);
+
+static SOC_ENUM_SINGLE_DECL(da732x_adc1_voice_filter_enum,
+			    DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT,
+			    da732x_hpf_voice);
+
+static SOC_ENUM_SINGLE_DECL(da732x_adc2_voice_filter_enum,
+			    DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT,
+			    da732x_hpf_voice);
+
+static int da732x_hpf_set(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
+	unsigned int reg = enum_ctrl->reg;
+	unsigned int sel = ucontrol->value.enumerated.item[0];
+	unsigned int bits;
+
+	switch (sel) {
+	case DA732X_HPF_DISABLED:
+		bits = DA732X_HPF_DIS;
+		break;
+	case DA732X_HPF_VOICE:
+		bits = DA732X_HPF_VOICE_EN;
+		break;
+	case DA732X_HPF_MUSIC:
+		bits = DA732X_HPF_MUSIC_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, reg, DA732X_HPF_MASK, bits);
+
+	return 0;
+}
+
+static int da732x_hpf_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
+	unsigned int reg = enum_ctrl->reg;
+	int val;
+
+	val = snd_soc_component_read32(component, reg) & DA732X_HPF_MASK;
+
+	switch (val) {
+	case DA732X_HPF_VOICE_EN:
+		ucontrol->value.enumerated.item[0] = DA732X_HPF_VOICE;
+		break;
+	case DA732X_HPF_MUSIC_EN:
+		ucontrol->value.enumerated.item[0] = DA732X_HPF_MUSIC;
+		break;
+	default:
+		ucontrol->value.enumerated.item[0] = DA732X_HPF_DISABLED;
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new da732x_snd_controls[] = {
+	/* Input PGAs */
+	SOC_SINGLE_RANGE_TLV("MIC1 Boost Volume", DA732X_REG_MIC1_PRE,
+			     DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN,
+			     DA732X_MICBOOST_MAX, 0, mic_boost_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC2 Boost Volume", DA732X_REG_MIC2_PRE,
+			     DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN,
+			     DA732X_MICBOOST_MAX, 0, mic_boost_tlv),
+	SOC_SINGLE_RANGE_TLV("MIC3 Boost Volume", DA732X_REG_MIC3_PRE,
+			     DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN,
+			     DA732X_MICBOOST_MAX, 0, mic_boost_tlv),
+
+	/* MICs */
+	SOC_SINGLE("MIC1 Switch", DA732X_REG_MIC1, DA732X_MIC_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_RANGE_TLV("MIC1 Volume", DA732X_REG_MIC1,
+			     DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN,
+			     DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv),
+	SOC_SINGLE("MIC2 Switch", DA732X_REG_MIC2, DA732X_MIC_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_RANGE_TLV("MIC2 Volume", DA732X_REG_MIC2,
+			     DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN,
+			     DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv),
+	SOC_SINGLE("MIC3 Switch", DA732X_REG_MIC3, DA732X_MIC_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_RANGE_TLV("MIC3 Volume", DA732X_REG_MIC3,
+			     DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN,
+			     DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv),
+
+	/* AUXs */
+	SOC_SINGLE("AUX1L Switch", DA732X_REG_AUX1L, DA732X_AUX_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("AUX1L Volume", DA732X_REG_AUX1L,
+		       DA732X_AUX_VOL_SHIFT, DA732X_AUX_VOL_VAL_MAX,
+		       DA732X_NO_INVERT, aux_pga_tlv),
+	SOC_SINGLE("AUX1R Switch", DA732X_REG_AUX1R, DA732X_AUX_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("AUX1R Volume", DA732X_REG_AUX1R,
+		       DA732X_AUX_VOL_SHIFT, DA732X_AUX_VOL_VAL_MAX,
+		       DA732X_NO_INVERT, aux_pga_tlv),
+
+	/* ADCs */
+	SOC_DOUBLE_TLV("ADC1 Volume", DA732X_REG_ADC1_SEL,
+		       DA732X_ADCL_VOL_SHIFT, DA732X_ADCR_VOL_SHIFT,
+		       DA732X_ADC_VOL_VAL_MAX, DA732X_INVERT, adc_pga_tlv),
+
+	SOC_DOUBLE_TLV("ADC2 Volume", DA732X_REG_ADC2_SEL,
+		       DA732X_ADCL_VOL_SHIFT, DA732X_ADCR_VOL_SHIFT,
+		       DA732X_ADC_VOL_VAL_MAX, DA732X_INVERT, adc_pga_tlv),
+
+	/* DACs */
+	SOC_DOUBLE("Digital Playback DAC12 Switch", DA732X_REG_DAC1_SEL,
+		   DA732X_DACL_MUTE_SHIFT, DA732X_DACR_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_DOUBLE_R_TLV("Digital Playback DAC12 Volume", DA732X_REG_DAC1_L_VOL,
+			 DA732X_REG_DAC1_R_VOL, DA732X_DAC_VOL_SHIFT,
+			 DA732X_DAC_VOL_VAL_MAX, DA732X_INVERT, dac_pga_tlv),
+	SOC_SINGLE("Digital Playback DAC3 Switch", DA732X_REG_DAC2_SEL,
+		   DA732X_DACL_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("Digital Playback DAC3 Volume", DA732X_REG_DAC2_L_VOL,
+			DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX,
+			DA732X_INVERT, dac_pga_tlv),
+	SOC_SINGLE("Digital Playback DAC4 Switch", DA732X_REG_DAC2_SEL,
+		   DA732X_DACR_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("Digital Playback DAC4 Volume", DA732X_REG_DAC2_R_VOL,
+		       DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX,
+		       DA732X_INVERT, dac_pga_tlv),
+	SOC_SINGLE("Digital Playback DAC5 Switch", DA732X_REG_DAC3_SEL,
+		   DA732X_DACL_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("Digital Playback DAC5 Volume", DA732X_REG_DAC3_VOL,
+		       DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX,
+		       DA732X_INVERT, dac_pga_tlv),
+
+	/* High Pass Filters */
+	SOC_ENUM_EXT("DAC1 High Pass Filter Mode",
+		     da732x_dac1_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+	SOC_ENUM("DAC1 High Pass Filter", da732x_dac1_hp_filter_enum),
+	SOC_ENUM("DAC1 Voice Filter", da732x_dac1_voice_filter_enum),
+
+	SOC_ENUM_EXT("DAC2 High Pass Filter Mode",
+		     da732x_dac2_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+	SOC_ENUM("DAC2 High Pass Filter", da732x_dac2_hp_filter_enum),
+	SOC_ENUM("DAC2 Voice Filter", da732x_dac2_voice_filter_enum),
+
+	SOC_ENUM_EXT("DAC3 High Pass Filter Mode",
+		     da732x_dac3_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+	SOC_ENUM("DAC3 High Pass Filter", da732x_dac3_hp_filter_enum),
+	SOC_ENUM("DAC3 Filter Mode", da732x_dac3_voice_filter_enum),
+
+	SOC_ENUM_EXT("ADC1 High Pass Filter Mode",
+		     da732x_adc1_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+	SOC_ENUM("ADC1 High Pass Filter", da732x_adc1_hp_filter_enum),
+	SOC_ENUM("ADC1 Voice Filter", da732x_adc1_voice_filter_enum),
+
+	SOC_ENUM_EXT("ADC2 High Pass Filter Mode",
+		     da732x_adc2_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set),
+	SOC_ENUM("ADC2 High Pass Filter", da732x_adc2_hp_filter_enum),
+	SOC_ENUM("ADC2 Voice Filter", da732x_adc2_voice_filter_enum),
+
+	/* Equalizers */
+	SOC_SINGLE("ADC1 EQ Switch", DA732X_REG_ADC1_EQ5,
+		   DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+	SOC_SINGLE_TLV("ADC1 EQ Band 1 Volume", DA732X_REG_ADC1_EQ12,
+		       DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC1 EQ Band 2 Volume", DA732X_REG_ADC1_EQ12,
+		       DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC1 EQ Band 3 Volume", DA732X_REG_ADC1_EQ34,
+		       DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC1 EQ Band 4 Volume", DA732X_REG_ADC1_EQ34,
+		       DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC1 EQ Band 5 Volume", DA732X_REG_ADC1_EQ5,
+		       DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC1 EQ Overall Volume", DA732X_REG_ADC1_EQ5,
+		       DA732X_EQ_OVERALL_SHIFT, DA732X_EQ_OVERALL_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_overall_tlv),
+
+	SOC_SINGLE("ADC2 EQ Switch", DA732X_REG_ADC2_EQ5,
+		   DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+	SOC_SINGLE_TLV("ADC2 EQ Band 1 Volume", DA732X_REG_ADC2_EQ12,
+		       DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC2 EQ Band 2 Volume", DA732X_REG_ADC2_EQ12,
+		       DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC2 EQ Band 3 Volume", DA732X_REG_ADC2_EQ34,
+		       DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ACD2 EQ Band 4 Volume", DA732X_REG_ADC2_EQ34,
+		       DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ACD2 EQ Band 5 Volume", DA732X_REG_ADC2_EQ5,
+		       DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("ADC2 EQ Overall Volume", DA732X_REG_ADC1_EQ5,
+		       DA732X_EQ_OVERALL_SHIFT, DA732X_EQ_OVERALL_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_overall_tlv),
+
+	SOC_SINGLE("DAC1 EQ Switch", DA732X_REG_DAC1_EQ5,
+		   DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+	SOC_SINGLE_TLV("DAC1 EQ Band 1 Volume", DA732X_REG_DAC1_EQ12,
+		       DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC1 EQ Band 2 Volume", DA732X_REG_DAC1_EQ12,
+		       DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC1 EQ Band 3 Volume", DA732X_REG_DAC1_EQ34,
+		       DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC1 EQ Band 4 Volume", DA732X_REG_DAC1_EQ34,
+		       DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC1 EQ Band 5 Volume", DA732X_REG_DAC1_EQ5,
+		       DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+
+	SOC_SINGLE("DAC2 EQ Switch", DA732X_REG_DAC2_EQ5,
+		   DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+	SOC_SINGLE_TLV("DAC2 EQ Band 1 Volume", DA732X_REG_DAC2_EQ12,
+		       DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC2 EQ Band 2 Volume", DA732X_REG_DAC2_EQ12,
+		       DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC2 EQ Band 3 Volume", DA732X_REG_DAC2_EQ34,
+		       DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC2 EQ Band 4 Volume", DA732X_REG_DAC2_EQ34,
+		       DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC2 EQ Band 5 Volume", DA732X_REG_DAC2_EQ5,
+		       DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+
+	SOC_SINGLE("DAC3 EQ Switch", DA732X_REG_DAC3_EQ5,
+		   DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT),
+	SOC_SINGLE_TLV("DAC3 EQ Band 1 Volume", DA732X_REG_DAC3_EQ12,
+		       DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC3 EQ Band 2 Volume", DA732X_REG_DAC3_EQ12,
+		       DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC3 EQ Band 3 Volume", DA732X_REG_DAC3_EQ34,
+		       DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC3 EQ Band 4 Volume", DA732X_REG_DAC3_EQ34,
+		       DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+	SOC_SINGLE_TLV("DAC3 EQ Band 5 Volume", DA732X_REG_DAC3_EQ5,
+		       DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX,
+		       DA732X_INVERT, eq_band_pga_tlv),
+
+	/* Lineout 2 Reciever*/
+	SOC_SINGLE("Lineout 2 Switch", DA732X_REG_LIN2, DA732X_LOUT_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("Lineout 2 Volume", DA732X_REG_LIN2,
+		       DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX,
+		       DA732X_NO_INVERT, lin2_pga_tlv),
+
+	/* Lineout 3 SPEAKER*/
+	SOC_SINGLE("Lineout 3 Switch", DA732X_REG_LIN3, DA732X_LOUT_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("Lineout 3 Volume", DA732X_REG_LIN3,
+		       DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX,
+		       DA732X_NO_INVERT, lin3_pga_tlv),
+
+	/* Lineout 4 */
+	SOC_SINGLE("Lineout 4 Switch", DA732X_REG_LIN4, DA732X_LOUT_MUTE_SHIFT,
+		   DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_SINGLE_TLV("Lineout 4 Volume", DA732X_REG_LIN4,
+		       DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX,
+		       DA732X_NO_INVERT, lin4_pga_tlv),
+
+	/* Headphones */
+	SOC_DOUBLE_R("Headphone Switch", DA732X_REG_HPR, DA732X_REG_HPL,
+		     DA732X_HP_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT),
+	SOC_DOUBLE_R_TLV("Headphone Volume", DA732X_REG_HPL_VOL,
+			 DA732X_REG_HPR_VOL, DA732X_HP_VOL_SHIFT,
+			 DA732X_HP_VOL_VAL_MAX, DA732X_NO_INVERT, hp_pga_tlv),
+};
+
+static int da732x_adc_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		switch (w->reg) {
+		case DA732X_REG_ADC1_PD:
+			snd_soc_component_update_bits(component, DA732X_REG_CLK_EN3,
+					    DA732X_ADCA_BB_CLK_EN,
+					    DA732X_ADCA_BB_CLK_EN);
+			break;
+		case DA732X_REG_ADC2_PD:
+			snd_soc_component_update_bits(component, DA732X_REG_CLK_EN3,
+					    DA732X_ADCC_BB_CLK_EN,
+					    DA732X_ADCC_BB_CLK_EN);
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		snd_soc_component_update_bits(component, w->reg, DA732X_ADC_RST_MASK,
+				    DA732X_ADC_SET_ACT);
+		snd_soc_component_update_bits(component, w->reg, DA732X_ADC_PD_MASK,
+				    DA732X_ADC_ON);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, w->reg, DA732X_ADC_PD_MASK,
+				    DA732X_ADC_OFF);
+		snd_soc_component_update_bits(component, w->reg, DA732X_ADC_RST_MASK,
+				    DA732X_ADC_SET_RST);
+
+		switch (w->reg) {
+		case DA732X_REG_ADC1_PD:
+			snd_soc_component_update_bits(component, DA732X_REG_CLK_EN3,
+					    DA732X_ADCA_BB_CLK_EN, 0);
+			break;
+		case DA732X_REG_ADC2_PD:
+			snd_soc_component_update_bits(component, DA732X_REG_CLK_EN3,
+					    DA732X_ADCC_BB_CLK_EN, 0);
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int da732x_out_pga_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, w->reg,
+				    (1 << w->shift) | DA732X_OUT_HIZ_EN,
+				    (1 << w->shift) | DA732X_OUT_HIZ_EN);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, w->reg,
+				    (1 << w->shift) | DA732X_OUT_HIZ_EN,
+				    (1 << w->shift) | DA732X_OUT_HIZ_DIS);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const char *adcl_text[] = {
+	"AUX1L", "MIC1"
+};
+
+static const char *adcr_text[] = {
+	"AUX1R", "MIC2", "MIC3"
+};
+
+static const char *enable_text[] = {
+	"Disabled",
+	"Enabled"
+};
+
+/* ADC1LMUX */
+static SOC_ENUM_SINGLE_DECL(adc1l_enum,
+			    DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT,
+			    adcl_text);
+static const struct snd_kcontrol_new adc1l_mux =
+	SOC_DAPM_ENUM("ADC Route", adc1l_enum);
+
+/* ADC1RMUX */
+static SOC_ENUM_SINGLE_DECL(adc1r_enum,
+			    DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT,
+			    adcr_text);
+static const struct snd_kcontrol_new adc1r_mux =
+	SOC_DAPM_ENUM("ADC Route", adc1r_enum);
+
+/* ADC2LMUX */
+static SOC_ENUM_SINGLE_DECL(adc2l_enum,
+			    DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT,
+			    adcl_text);
+static const struct snd_kcontrol_new adc2l_mux =
+	SOC_DAPM_ENUM("ADC Route", adc2l_enum);
+
+/* ADC2RMUX */
+static SOC_ENUM_SINGLE_DECL(adc2r_enum,
+			    DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT,
+			    adcr_text);
+
+static const struct snd_kcontrol_new adc2r_mux =
+	SOC_DAPM_ENUM("ADC Route", adc2r_enum);
+
+static SOC_ENUM_SINGLE_DECL(da732x_hp_left_output,
+			    DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT,
+			    enable_text);
+
+static const struct snd_kcontrol_new hpl_mux =
+	SOC_DAPM_ENUM("HPL Switch", da732x_hp_left_output);
+
+static SOC_ENUM_SINGLE_DECL(da732x_hp_right_output,
+			    DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT,
+			    enable_text);
+
+static const struct snd_kcontrol_new hpr_mux =
+	SOC_DAPM_ENUM("HPR Switch", da732x_hp_right_output);
+
+static SOC_ENUM_SINGLE_DECL(da732x_speaker_output,
+			    DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT,
+			    enable_text);
+
+static const struct snd_kcontrol_new spk_mux =
+	SOC_DAPM_ENUM("SPK Switch", da732x_speaker_output);
+
+static SOC_ENUM_SINGLE_DECL(da732x_lout4_output,
+			    DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT,
+			    enable_text);
+
+static const struct snd_kcontrol_new lout4_mux =
+	SOC_DAPM_ENUM("LOUT4 Switch", da732x_lout4_output);
+
+static SOC_ENUM_SINGLE_DECL(da732x_lout2_output,
+			    DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT,
+			    enable_text);
+
+static const struct snd_kcontrol_new lout2_mux =
+	SOC_DAPM_ENUM("LOUT2 Switch", da732x_lout2_output);
+
+static const struct snd_soc_dapm_widget da732x_dapm_widgets[] = {
+	/* Supplies */
+	SND_SOC_DAPM_SUPPLY("ADC1 Supply", DA732X_REG_ADC1_PD, 0,
+			    DA732X_NO_INVERT, da732x_adc_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("ADC2 Supply", DA732X_REG_ADC2_PD, 0,
+			    DA732X_NO_INVERT, da732x_adc_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("DAC1 CLK", DA732X_REG_CLK_EN4,
+			    DA732X_DACA_BB_CLK_SHIFT, DA732X_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC2 CLK", DA732X_REG_CLK_EN4,
+			    DA732X_DACC_BB_CLK_SHIFT, DA732X_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC3 CLK", DA732X_REG_CLK_EN5,
+			    DA732X_DACE_BB_CLK_SHIFT, DA732X_NO_INVERT,
+			    NULL, 0),
+
+	/* Micbias */
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", DA732X_REG_MICBIAS1,
+			    DA732X_MICBIAS_EN_SHIFT,
+			    DA732X_NO_INVERT, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", DA732X_REG_MICBIAS2,
+			    DA732X_MICBIAS_EN_SHIFT,
+			    DA732X_NO_INVERT, NULL, 0),
+
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("MIC3"),
+	SND_SOC_DAPM_INPUT("AUX1L"),
+	SND_SOC_DAPM_INPUT("AUX1R"),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("LOUTL"),
+	SND_SOC_DAPM_OUTPUT("LOUTR"),
+	SND_SOC_DAPM_OUTPUT("ClassD"),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC1L", NULL, DA732X_REG_ADC1_SEL,
+			 DA732X_ADCL_EN_SHIFT, DA732X_NO_INVERT),
+	SND_SOC_DAPM_ADC("ADC1R", NULL, DA732X_REG_ADC1_SEL,
+			 DA732X_ADCR_EN_SHIFT, DA732X_NO_INVERT),
+	SND_SOC_DAPM_ADC("ADC2L", NULL, DA732X_REG_ADC2_SEL,
+			 DA732X_ADCL_EN_SHIFT, DA732X_NO_INVERT),
+	SND_SOC_DAPM_ADC("ADC2R", NULL, DA732X_REG_ADC2_SEL,
+			 DA732X_ADCR_EN_SHIFT, DA732X_NO_INVERT),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC1L", NULL, DA732X_REG_DAC1_SEL,
+			 DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT),
+	SND_SOC_DAPM_DAC("DAC1R", NULL, DA732X_REG_DAC1_SEL,
+			 DA732X_DACR_EN_SHIFT, DA732X_NO_INVERT),
+	SND_SOC_DAPM_DAC("DAC2L", NULL, DA732X_REG_DAC2_SEL,
+			 DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT),
+	SND_SOC_DAPM_DAC("DAC2R", NULL, DA732X_REG_DAC2_SEL,
+			 DA732X_DACR_EN_SHIFT, DA732X_NO_INVERT),
+	SND_SOC_DAPM_DAC("DAC3", NULL, DA732X_REG_DAC3_SEL,
+			 DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT),
+
+	/* Input Pgas */
+	SND_SOC_DAPM_PGA("MIC1 PGA", DA732X_REG_MIC1, DA732X_MIC_EN_SHIFT,
+			 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MIC2 PGA", DA732X_REG_MIC2, DA732X_MIC_EN_SHIFT,
+			 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MIC3 PGA", DA732X_REG_MIC3, DA732X_MIC_EN_SHIFT,
+			 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUX1L PGA", DA732X_REG_AUX1L, DA732X_AUX_EN_SHIFT,
+			 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUX1R PGA", DA732X_REG_AUX1R, DA732X_AUX_EN_SHIFT,
+			 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA_E("HP Left", DA732X_REG_HPL, DA732X_HP_OUT_EN_SHIFT,
+			   0, NULL, 0, da732x_out_pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HP Right", DA732X_REG_HPR, DA732X_HP_OUT_EN_SHIFT,
+			   0, NULL, 0, da732x_out_pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LIN2", DA732X_REG_LIN2, DA732X_LIN_OUT_EN_SHIFT,
+			   0, NULL, 0, da732x_out_pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LIN3", DA732X_REG_LIN3, DA732X_LIN_OUT_EN_SHIFT,
+			   0, NULL, 0, da732x_out_pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LIN4", DA732X_REG_LIN4, DA732X_LIN_OUT_EN_SHIFT,
+			   0, NULL, 0, da732x_out_pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* MUXs */
+	SND_SOC_DAPM_MUX("ADC1 Left MUX", SND_SOC_NOPM, 0, 0, &adc1l_mux),
+	SND_SOC_DAPM_MUX("ADC1 Right MUX", SND_SOC_NOPM, 0, 0, &adc1r_mux),
+	SND_SOC_DAPM_MUX("ADC2 Left MUX", SND_SOC_NOPM, 0, 0, &adc2l_mux),
+	SND_SOC_DAPM_MUX("ADC2 Right MUX", SND_SOC_NOPM, 0, 0, &adc2r_mux),
+
+	SND_SOC_DAPM_MUX("HP Left MUX", SND_SOC_NOPM, 0, 0, &hpl_mux),
+	SND_SOC_DAPM_MUX("HP Right MUX", SND_SOC_NOPM, 0, 0, &hpr_mux),
+	SND_SOC_DAPM_MUX("Speaker MUX", SND_SOC_NOPM, 0, 0, &spk_mux),
+	SND_SOC_DAPM_MUX("LOUT2 MUX", SND_SOC_NOPM, 0, 0, &lout2_mux),
+	SND_SOC_DAPM_MUX("LOUT4 MUX", SND_SOC_NOPM, 0, 0, &lout4_mux),
+
+	/* AIF interfaces */
+	SND_SOC_DAPM_AIF_OUT("AIFA Output", "AIFA Capture", 0, DA732X_REG_AIFA3,
+			     DA732X_AIF_EN_SHIFT, 0),
+	SND_SOC_DAPM_AIF_IN("AIFA Input", "AIFA Playback", 0, DA732X_REG_AIFA3,
+			    DA732X_AIF_EN_SHIFT, 0),
+
+	SND_SOC_DAPM_AIF_OUT("AIFB Output", "AIFB Capture", 0, DA732X_REG_AIFB3,
+			     DA732X_AIF_EN_SHIFT, 0),
+	SND_SOC_DAPM_AIF_IN("AIFB Input", "AIFB Playback", 0, DA732X_REG_AIFB3,
+			    DA732X_AIF_EN_SHIFT, 0),
+};
+
+static const struct snd_soc_dapm_route da732x_dapm_routes[] = {
+	/* Inputs */
+	{"AUX1L PGA", NULL, "AUX1L"},
+	{"AUX1R PGA", NULL, "AUX1R"},
+	{"MIC1 PGA", NULL, "MIC1"},
+	{"MIC2 PGA", NULL, "MIC2"},
+	{"MIC3 PGA", NULL, "MIC3"},
+
+	/* Capture Path */
+	{"ADC1 Left MUX", "MIC1", "MIC1 PGA"},
+	{"ADC1 Left MUX", "AUX1L", "AUX1L PGA"},
+
+	{"ADC1 Right MUX", "AUX1R", "AUX1R PGA"},
+	{"ADC1 Right MUX", "MIC2", "MIC2 PGA"},
+	{"ADC1 Right MUX", "MIC3", "MIC3 PGA"},
+
+	{"ADC2 Left MUX", "AUX1L", "AUX1L PGA"},
+	{"ADC2 Left MUX", "MIC1", "MIC1 PGA"},
+
+	{"ADC2 Right MUX", "AUX1R", "AUX1R PGA"},
+	{"ADC2 Right MUX", "MIC2", "MIC2 PGA"},
+	{"ADC2 Right MUX", "MIC3", "MIC3 PGA"},
+
+	{"ADC1L", NULL, "ADC1 Supply"},
+	{"ADC1R", NULL, "ADC1 Supply"},
+	{"ADC2L", NULL, "ADC2 Supply"},
+	{"ADC2R", NULL, "ADC2 Supply"},
+
+	{"ADC1L", NULL, "ADC1 Left MUX"},
+	{"ADC1R", NULL, "ADC1 Right MUX"},
+	{"ADC2L", NULL, "ADC2 Left MUX"},
+	{"ADC2R", NULL, "ADC2 Right MUX"},
+
+	{"AIFA Output", NULL, "ADC1L"},
+	{"AIFA Output", NULL, "ADC1R"},
+	{"AIFB Output", NULL, "ADC2L"},
+	{"AIFB Output", NULL, "ADC2R"},
+
+	{"HP Left MUX", "Enabled", "AIFA Input"},
+	{"HP Right MUX", "Enabled", "AIFA Input"},
+	{"Speaker MUX", "Enabled", "AIFB Input"},
+	{"LOUT2 MUX", "Enabled", "AIFB Input"},
+	{"LOUT4 MUX", "Enabled", "AIFB Input"},
+
+	{"DAC1L", NULL, "DAC1 CLK"},
+	{"DAC1R", NULL, "DAC1 CLK"},
+	{"DAC2L", NULL, "DAC2 CLK"},
+	{"DAC2R", NULL, "DAC2 CLK"},
+	{"DAC3", NULL, "DAC3 CLK"},
+
+	{"DAC1L", NULL, "HP Left MUX"},
+	{"DAC1R", NULL, "HP Right MUX"},
+	{"DAC2L", NULL, "Speaker MUX"},
+	{"DAC2R", NULL, "LOUT4 MUX"},
+	{"DAC3", NULL, "LOUT2 MUX"},
+
+	/* Output Pgas */
+	{"HP Left", NULL, "DAC1L"},
+	{"HP Right", NULL, "DAC1R"},
+	{"LIN3", NULL, "DAC2L"},
+	{"LIN4", NULL, "DAC2R"},
+	{"LIN2", NULL, "DAC3"},
+
+	/* Outputs */
+	{"ClassD", NULL, "LIN3"},
+	{"LOUTL", NULL, "LIN2"},
+	{"LOUTR", NULL, "LIN4"},
+	{"HPL", NULL, "HP Left"},
+	{"HPR", NULL, "HP Right"},
+};
+
+static int da732x_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u32 aif = 0;
+	u32 reg_aif;
+	u32 fs;
+
+	reg_aif = dai->driver->base;
+
+	switch (params_width(params)) {
+	case 16:
+		aif |= DA732X_AIF_WORD_16;
+		break;
+	case 20:
+		aif |= DA732X_AIF_WORD_20;
+		break;
+	case 24:
+		aif |= DA732X_AIF_WORD_24;
+		break;
+	case 32:
+		aif |= DA732X_AIF_WORD_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params_rate(params)) {
+	case 8000:
+		fs = DA732X_SR_8KHZ;
+		break;
+	case 11025:
+		fs = DA732X_SR_11_025KHZ;
+		break;
+	case 12000:
+		fs = DA732X_SR_12KHZ;
+		break;
+	case 16000:
+		fs = DA732X_SR_16KHZ;
+		break;
+	case 22050:
+		fs = DA732X_SR_22_05KHZ;
+		break;
+	case 24000:
+		fs = DA732X_SR_24KHZ;
+		break;
+	case 32000:
+		fs = DA732X_SR_32KHZ;
+		break;
+	case 44100:
+		fs = DA732X_SR_44_1KHZ;
+		break;
+	case 48000:
+		fs = DA732X_SR_48KHZ;
+		break;
+	case 88100:
+		fs = DA732X_SR_88_1KHZ;
+		break;
+	case 96000:
+		fs = DA732X_SR_96KHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, reg_aif, DA732X_AIF_WORD_MASK, aif);
+	snd_soc_component_update_bits(component, DA732X_REG_CLK_CTRL, DA732X_SR1_MASK, fs);
+
+	return 0;
+}
+
+static int da732x_set_dai_fmt(struct snd_soc_dai *dai, u32 fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	u32 aif_mclk, pc_count;
+	u32 reg_aif1, aif1;
+	u32 reg_aif3, aif3;
+
+	switch (dai->id) {
+	case DA732X_DAI_ID1:
+		reg_aif1 = DA732X_REG_AIFA1;
+		reg_aif3 = DA732X_REG_AIFA3;
+		pc_count = DA732X_PC_PULSE_AIFA | DA732X_PC_RESYNC_NOT_AUT |
+			   DA732X_PC_SAME;
+		break;
+	case DA732X_DAI_ID2:
+		reg_aif1 = DA732X_REG_AIFB1;
+		reg_aif3 = DA732X_REG_AIFB3;
+		pc_count = DA732X_PC_PULSE_AIFB | DA732X_PC_RESYNC_NOT_AUT |
+			   DA732X_PC_SAME;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		aif1 = DA732X_AIF_SLAVE;
+		aif_mclk = DA732X_AIFM_FRAME_64 | DA732X_AIFM_SRC_SEL_AIFA;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif1 = DA732X_AIF_CLK_FROM_SRC;
+		aif_mclk = DA732X_CLK_GENERATION_AIF_A;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		aif3 = DA732X_AIF_I2S_MODE;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		aif3 = DA732X_AIF_RIGHT_J_MODE;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif3 = DA732X_AIF_LEFT_J_MODE;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		aif3 = DA732X_AIF_DSP_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_B:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif3 |= DA732X_AIF_BCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			aif3 |= DA732X_AIF_BCLK_INV | DA732X_AIF_WCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif3 |= DA732X_AIF_BCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			aif3 |= DA732X_AIF_WCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, DA732X_REG_AIF_MCLK, aif_mclk);
+	snd_soc_component_update_bits(component, reg_aif1, DA732X_AIF1_CLK_MASK, aif1);
+	snd_soc_component_update_bits(component, reg_aif3, DA732X_AIF_BCLK_INV |
+			    DA732X_AIF_WCLK_INV | DA732X_AIF_MODE_MASK, aif3);
+	snd_soc_component_write(component, DA732X_REG_PC_CTRL, pc_count);
+
+	return 0;
+}
+
+
+
+static int da732x_set_dai_pll(struct snd_soc_component *component, int pll_id,
+			      int source, unsigned int freq_in,
+			      unsigned int freq_out)
+{
+	struct da732x_priv *da732x = snd_soc_component_get_drvdata(component);
+	int fref, indiv;
+	u8 div_lo, div_mid, div_hi;
+	u64 frac_div;
+
+	/* Disable PLL */
+	if (freq_out == 0) {
+		snd_soc_component_update_bits(component, DA732X_REG_PLL_CTRL,
+				    DA732X_PLL_EN, 0);
+		da732x->pll_en = false;
+		return 0;
+	}
+
+	if (da732x->pll_en)
+		return -EBUSY;
+
+	if (source == DA732X_SRCCLK_MCLK) {
+		/* Validate Sysclk rate */
+		switch (da732x->sysclk) {
+		case 11290000:
+		case 12288000:
+		case 22580000:
+		case 24576000:
+		case 45160000:
+		case 49152000:
+			snd_soc_component_write(component, DA732X_REG_PLL_CTRL,
+				      DA732X_PLL_BYPASS);
+			return 0;
+		default:
+			dev_err(component->dev,
+				"Cannot use PLL Bypass, invalid SYSCLK rate\n");
+			return -EINVAL;
+		}
+	}
+
+	indiv = da732x_get_input_div(component, da732x->sysclk);
+	if (indiv < 0)
+		return indiv;
+
+	fref = (da732x->sysclk / indiv);
+	div_hi = freq_out / fref;
+	frac_div = (u64)(freq_out % fref) * 8192ULL;
+	do_div(frac_div, fref);
+	div_mid = (frac_div >> DA732X_1BYTE_SHIFT) & DA732X_U8_MASK;
+	div_lo = (frac_div) & DA732X_U8_MASK;
+
+	snd_soc_component_write(component, DA732X_REG_PLL_DIV_LO, div_lo);
+	snd_soc_component_write(component, DA732X_REG_PLL_DIV_MID, div_mid);
+	snd_soc_component_write(component, DA732X_REG_PLL_DIV_HI, div_hi);
+
+	snd_soc_component_update_bits(component, DA732X_REG_PLL_CTRL, DA732X_PLL_EN,
+			    DA732X_PLL_EN);
+
+	da732x->pll_en = true;
+
+	return 0;
+}
+
+static int da732x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+				 unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct da732x_priv *da732x = snd_soc_component_get_drvdata(component);
+
+	da732x->sysclk = freq;
+
+	return 0;
+}
+
+#define DA732X_RATES	SNDRV_PCM_RATE_8000_96000
+
+#define	DA732X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops da732x_dai_ops = {
+	.hw_params	= da732x_hw_params,
+	.set_fmt	= da732x_set_dai_fmt,
+	.set_sysclk	= da732x_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver da732x_dai[] = {
+	{
+		.name	= "DA732X_AIFA",
+		.id	= DA732X_DAI_ID1,
+		.base	= DA732X_REG_AIFA1,
+		.playback = {
+			.stream_name = "AIFA Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = DA732X_RATES,
+			.formats = DA732X_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIFA Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = DA732X_RATES,
+			.formats = DA732X_FORMATS,
+		},
+		.ops = &da732x_dai_ops,
+	},
+	{
+		.name	= "DA732X_AIFB",
+		.id	= DA732X_DAI_ID2,
+		.base	= DA732X_REG_AIFB1,
+		.playback = {
+			.stream_name = "AIFB Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = DA732X_RATES,
+			.formats = DA732X_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIFB Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = DA732X_RATES,
+			.formats = DA732X_FORMATS,
+		},
+		.ops = &da732x_dai_ops,
+	},
+};
+
+static bool da732x_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case DA732X_REG_HPL_DAC_OFF_CNTL:
+	case DA732X_REG_HPR_DAC_OFF_CNTL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config da732x_regmap = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+
+	.max_register		= DA732X_MAX_REG,
+	.volatile_reg		= da732x_volatile,
+	.reg_defaults		= da732x_reg_cache,
+	.num_reg_defaults	= ARRAY_SIZE(da732x_reg_cache),
+	.cache_type		= REGCACHE_RBTREE,
+};
+
+
+static void da732x_dac_offset_adjust(struct snd_soc_component *component)
+{
+	u8 offset[DA732X_HP_DACS];
+	u8 sign[DA732X_HP_DACS];
+	u8 step = DA732X_DAC_OFFSET_STEP;
+
+	/* Initialize DAC offset calibration circuits and registers */
+	snd_soc_component_write(component, DA732X_REG_HPL_DAC_OFFSET,
+		      DA732X_HP_DAC_OFFSET_TRIM_VAL);
+	snd_soc_component_write(component, DA732X_REG_HPR_DAC_OFFSET,
+		      DA732X_HP_DAC_OFFSET_TRIM_VAL);
+	snd_soc_component_write(component, DA732X_REG_HPL_DAC_OFF_CNTL,
+		      DA732X_HP_DAC_OFF_CALIBRATION |
+		      DA732X_HP_DAC_OFF_SCALE_STEPS);
+	snd_soc_component_write(component, DA732X_REG_HPR_DAC_OFF_CNTL,
+		      DA732X_HP_DAC_OFF_CALIBRATION |
+		      DA732X_HP_DAC_OFF_SCALE_STEPS);
+
+	/* Wait for voltage stabilization */
+	msleep(DA732X_WAIT_FOR_STABILIZATION);
+
+	/* Check DAC offset sign */
+	sign[DA732X_HPL_DAC] = (snd_soc_component_read32(component, DA732X_REG_HPL_DAC_OFF_CNTL) &
+				DA732X_HP_DAC_OFF_CNTL_COMPO);
+	sign[DA732X_HPR_DAC] = (snd_soc_component_read32(component, DA732X_REG_HPR_DAC_OFF_CNTL) &
+				DA732X_HP_DAC_OFF_CNTL_COMPO);
+
+	/* Binary search DAC offset values (both channels at once) */
+	offset[DA732X_HPL_DAC] = sign[DA732X_HPL_DAC] << DA732X_HP_DAC_COMPO_SHIFT;
+	offset[DA732X_HPR_DAC] = sign[DA732X_HPR_DAC] << DA732X_HP_DAC_COMPO_SHIFT;
+
+	do {
+		offset[DA732X_HPL_DAC] |= step;
+		offset[DA732X_HPR_DAC] |= step;
+		snd_soc_component_write(component, DA732X_REG_HPL_DAC_OFFSET,
+			      ~offset[DA732X_HPL_DAC] & DA732X_HP_DAC_OFF_MASK);
+		snd_soc_component_write(component, DA732X_REG_HPR_DAC_OFFSET,
+			      ~offset[DA732X_HPR_DAC] & DA732X_HP_DAC_OFF_MASK);
+
+		msleep(DA732X_WAIT_FOR_STABILIZATION);
+
+		if ((snd_soc_component_read32(component, DA732X_REG_HPL_DAC_OFF_CNTL) &
+		     DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPL_DAC])
+			offset[DA732X_HPL_DAC] &= ~step;
+		if ((snd_soc_component_read32(component, DA732X_REG_HPR_DAC_OFF_CNTL) &
+		     DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPR_DAC])
+			offset[DA732X_HPR_DAC] &= ~step;
+
+		step >>= 1;
+	} while (step);
+
+	/* Write final DAC offsets to registers */
+	snd_soc_component_write(component, DA732X_REG_HPL_DAC_OFFSET,
+		      ~offset[DA732X_HPL_DAC] &	DA732X_HP_DAC_OFF_MASK);
+	snd_soc_component_write(component, DA732X_REG_HPR_DAC_OFFSET,
+		      ~offset[DA732X_HPR_DAC] &	DA732X_HP_DAC_OFF_MASK);
+
+	/* End DAC calibration mode */
+	snd_soc_component_write(component, DA732X_REG_HPL_DAC_OFF_CNTL,
+		DA732X_HP_DAC_OFF_SCALE_STEPS);
+	snd_soc_component_write(component, DA732X_REG_HPR_DAC_OFF_CNTL,
+		DA732X_HP_DAC_OFF_SCALE_STEPS);
+}
+
+static void da732x_output_offset_adjust(struct snd_soc_component *component)
+{
+	u8 offset[DA732X_HP_AMPS];
+	u8 sign[DA732X_HP_AMPS];
+	u8 step = DA732X_OUTPUT_OFFSET_STEP;
+
+	offset[DA732X_HPL_AMP] = DA732X_HP_OUT_TRIM_VAL;
+	offset[DA732X_HPR_AMP] = DA732X_HP_OUT_TRIM_VAL;
+
+	/* Initialize output offset calibration circuits and registers  */
+	snd_soc_component_write(component, DA732X_REG_HPL_OUT_OFFSET, DA732X_HP_OUT_TRIM_VAL);
+	snd_soc_component_write(component, DA732X_REG_HPR_OUT_OFFSET, DA732X_HP_OUT_TRIM_VAL);
+	snd_soc_component_write(component, DA732X_REG_HPL,
+		      DA732X_HP_OUT_COMP | DA732X_HP_OUT_EN);
+	snd_soc_component_write(component, DA732X_REG_HPR,
+		      DA732X_HP_OUT_COMP | DA732X_HP_OUT_EN);
+
+	/* Wait for voltage stabilization */
+	msleep(DA732X_WAIT_FOR_STABILIZATION);
+
+	/* Check output offset sign */
+	sign[DA732X_HPL_AMP] = snd_soc_component_read32(component, DA732X_REG_HPL) &
+			       DA732X_HP_OUT_COMPO;
+	sign[DA732X_HPR_AMP] = snd_soc_component_read32(component, DA732X_REG_HPR) &
+			       DA732X_HP_OUT_COMPO;
+
+	snd_soc_component_write(component, DA732X_REG_HPL, DA732X_HP_OUT_COMP |
+		      (sign[DA732X_HPL_AMP] >> DA732X_HP_OUT_COMPO_SHIFT) |
+		      DA732X_HP_OUT_EN);
+	snd_soc_component_write(component, DA732X_REG_HPR, DA732X_HP_OUT_COMP |
+		      (sign[DA732X_HPR_AMP] >> DA732X_HP_OUT_COMPO_SHIFT) |
+		      DA732X_HP_OUT_EN);
+
+	/* Binary search output offset values (both channels at once) */
+	do {
+		offset[DA732X_HPL_AMP] |= step;
+		offset[DA732X_HPR_AMP] |= step;
+		snd_soc_component_write(component, DA732X_REG_HPL_OUT_OFFSET,
+			      offset[DA732X_HPL_AMP]);
+		snd_soc_component_write(component, DA732X_REG_HPR_OUT_OFFSET,
+			      offset[DA732X_HPR_AMP]);
+
+		msleep(DA732X_WAIT_FOR_STABILIZATION);
+
+		if ((snd_soc_component_read32(component, DA732X_REG_HPL) &
+		     DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPL_AMP])
+			offset[DA732X_HPL_AMP] &= ~step;
+		if ((snd_soc_component_read32(component, DA732X_REG_HPR) &
+		     DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPR_AMP])
+			offset[DA732X_HPR_AMP] &= ~step;
+
+		step >>= 1;
+	} while (step);
+
+	/* Write final DAC offsets to registers */
+	snd_soc_component_write(component, DA732X_REG_HPL_OUT_OFFSET, offset[DA732X_HPL_AMP]);
+	snd_soc_component_write(component, DA732X_REG_HPR_OUT_OFFSET, offset[DA732X_HPR_AMP]);
+}
+
+static void da732x_hp_dc_offset_cancellation(struct snd_soc_component *component)
+{
+	/* Make sure that we have Soft Mute enabled */
+	snd_soc_component_write(component, DA732X_REG_DAC1_SOFTMUTE, DA732X_SOFTMUTE_EN |
+		      DA732X_GAIN_RAMPED | DA732X_16_SAMPLES);
+	snd_soc_component_write(component, DA732X_REG_DAC1_SEL, DA732X_DACL_EN |
+		      DA732X_DACR_EN | DA732X_DACL_SDM | DA732X_DACR_SDM |
+		      DA732X_DACL_MUTE | DA732X_DACR_MUTE);
+	snd_soc_component_write(component, DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN |
+		      DA732X_HP_OUT_MUTE | DA732X_HP_OUT_EN);
+	snd_soc_component_write(component, DA732X_REG_HPR, DA732X_HP_OUT_EN |
+		      DA732X_HP_OUT_MUTE | DA732X_HP_OUT_DAC_EN);
+
+	da732x_dac_offset_adjust(component);
+	da732x_output_offset_adjust(component);
+
+	snd_soc_component_write(component, DA732X_REG_DAC1_SEL, DA732X_DACS_DIS);
+	snd_soc_component_write(component, DA732X_REG_HPL, DA732X_HP_DIS);
+	snd_soc_component_write(component, DA732X_REG_HPR, DA732X_HP_DIS);
+}
+
+static int da732x_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct da732x_priv *da732x = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_component_update_bits(component, DA732X_REG_BIAS_EN,
+				    DA732X_BIAS_BOOST_MASK,
+				    DA732X_BIAS_BOOST_100PC);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/* Init Codec */
+			snd_soc_component_write(component, DA732X_REG_REF1,
+				      DA732X_VMID_FASTCHG);
+			snd_soc_component_write(component, DA732X_REG_BIAS_EN,
+				      DA732X_BIAS_EN);
+
+			mdelay(DA732X_STARTUP_DELAY);
+
+			/* Disable Fast Charge and enable DAC ref voltage */
+			snd_soc_component_write(component, DA732X_REG_REF1,
+				      DA732X_REFBUFX2_EN);
+
+			/* Enable bypass DSP routing */
+			snd_soc_component_write(component, DA732X_REG_DATA_ROUTE,
+				      DA732X_BYPASS_DSP);
+
+			/* Enable Digital subsystem */
+			snd_soc_component_write(component, DA732X_REG_DSP_CTRL,
+				      DA732X_DIGITAL_EN);
+
+			snd_soc_component_write(component, DA732X_REG_SPARE1_OUT,
+				      DA732X_HP_DRIVER_EN |
+				      DA732X_HP_GATE_LOW |
+				      DA732X_HP_LOOP_GAIN_CTRL);
+			snd_soc_component_write(component, DA732X_REG_HP_LIN1_GNDSEL,
+				      DA732X_HP_OUT_GNDSEL);
+
+			da732x_set_charge_pump(component, DA732X_ENABLE_CP);
+
+			snd_soc_component_write(component, DA732X_REG_CLK_EN1,
+			      DA732X_SYS3_CLK_EN | DA732X_PC_CLK_EN);
+
+			/* Enable Zero Crossing */
+			snd_soc_component_write(component, DA732X_REG_INP_ZC_EN,
+				      DA732X_MIC1_PRE_ZC_EN |
+				      DA732X_MIC1_ZC_EN |
+				      DA732X_MIC2_PRE_ZC_EN |
+				      DA732X_MIC2_ZC_EN |
+				      DA732X_AUXL_ZC_EN |
+				      DA732X_AUXR_ZC_EN |
+				      DA732X_MIC3_PRE_ZC_EN |
+				      DA732X_MIC3_ZC_EN);
+			snd_soc_component_write(component, DA732X_REG_OUT_ZC_EN,
+				      DA732X_HPL_ZC_EN | DA732X_HPR_ZC_EN |
+				      DA732X_LIN2_ZC_EN | DA732X_LIN3_ZC_EN |
+				      DA732X_LIN4_ZC_EN);
+
+			da732x_hp_dc_offset_cancellation(component);
+
+			regcache_cache_only(da732x->regmap, false);
+			regcache_sync(da732x->regmap);
+		} else {
+			snd_soc_component_update_bits(component, DA732X_REG_BIAS_EN,
+					    DA732X_BIAS_BOOST_MASK,
+					    DA732X_BIAS_BOOST_50PC);
+			snd_soc_component_update_bits(component, DA732X_REG_PLL_CTRL,
+					    DA732X_PLL_EN, 0);
+			da732x->pll_en = false;
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		regcache_cache_only(da732x->regmap, true);
+		da732x_set_charge_pump(component, DA732X_DISABLE_CP);
+		snd_soc_component_update_bits(component, DA732X_REG_BIAS_EN, DA732X_BIAS_EN,
+				    DA732X_BIAS_DIS);
+		da732x->pll_en = false;
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_da732x = {
+	.set_bias_level		= da732x_set_bias_level,
+	.controls		= da732x_snd_controls,
+	.num_controls		= ARRAY_SIZE(da732x_snd_controls),
+	.dapm_widgets		= da732x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(da732x_dapm_widgets),
+	.dapm_routes		= da732x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(da732x_dapm_routes),
+	.set_pll		= da732x_set_dai_pll,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int da732x_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct da732x_priv *da732x;
+	unsigned int reg;
+	int ret;
+
+	da732x = devm_kzalloc(&i2c->dev, sizeof(struct da732x_priv),
+			      GFP_KERNEL);
+	if (!da732x)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, da732x);
+
+	da732x->regmap = devm_regmap_init_i2c(i2c, &da732x_regmap);
+	if (IS_ERR(da732x->regmap)) {
+		ret = PTR_ERR(da732x->regmap);
+		dev_err(&i2c->dev, "Failed to initialize regmap\n");
+		goto err;
+	}
+
+	ret = regmap_read(da732x->regmap, DA732X_REG_ID, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
+		goto err;
+	}
+
+	dev_info(&i2c->dev, "Revision: %d.%d\n",
+		 (reg & DA732X_ID_MAJOR_MASK) >> 4,
+		 (reg & DA732X_ID_MINOR_MASK));
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_da732x,
+				     da732x_dai, ARRAY_SIZE(da732x_dai));
+	if (ret != 0)
+		dev_err(&i2c->dev, "Failed to register component.\n");
+
+err:
+	return ret;
+}
+
+static int da732x_i2c_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id da732x_i2c_id[] = {
+	{ "da7320", 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, da732x_i2c_id);
+
+static struct i2c_driver da732x_i2c_driver = {
+	.driver		= {
+		.name	= "da7320",
+	},
+	.probe		= da732x_i2c_probe,
+	.remove		= da732x_i2c_remove,
+	.id_table	= da732x_i2c_id,
+};
+
+module_i2c_driver(da732x_i2c_driver);
+
+
+MODULE_DESCRIPTION("ASoC DA732X driver");
+MODULE_AUTHOR("Michal Hajduk <michal.hajduk@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h
new file mode 100644
index 0000000..f586cbd
--- /dev/null
+++ b/sound/soc/codecs/da732x.h
@@ -0,0 +1,130 @@
+/*
+ * da732x.h -- Dialog DA732X ALSA SoC Audio Driver Header File
+ *
+ * Copyright (C) 2012 Dialog Semiconductor GmbH
+ *
+ * Author: Michal Hajduk <Michal.Hajduk@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DA732X_H_
+#define __DA732X_H_
+
+#include <sound/soc.h>
+
+/* General */
+#define	DA732X_U8_MASK			0xFF
+#define	DA732X_4BYTES			4
+#define	DA732X_3BYTES			3
+#define	DA732X_2BYTES			2
+#define	DA732X_1BYTE			1
+#define	DA732X_1BYTE_SHIFT		8
+#define	DA732X_2BYTES_SHIFT		16
+#define	DA732X_3BYTES_SHIFT		24
+#define	DA732X_4BYTES_SHIFT		32
+
+#define	DA732X_DACS_DIS			0x0
+#define	DA732X_HP_DIS			0x0
+#define	DA732X_CLEAR_REG		0x0
+
+/* Calibration */
+#define	DA732X_DAC_OFFSET_STEP		0x20
+#define	DA732X_OUTPUT_OFFSET_STEP	0x80
+#define	DA732X_HP_OUT_TRIM_VAL		0x0
+#define	DA732X_WAIT_FOR_STABILIZATION	1
+#define	DA732X_HPL_DAC			0
+#define	DA732X_HPR_DAC			1
+#define	DA732X_HP_DACS			2
+#define	DA732X_HPL_AMP			0
+#define	DA732X_HPR_AMP			1
+#define	DA732X_HP_AMPS			2
+
+/* Clock settings */
+#define DA732X_STARTUP_DELAY		100
+#define	DA732X_PLL_OUT_196608		196608000
+#define	DA732X_PLL_OUT_180634		180633600
+#define	DA732X_PLL_OUT_SRM		188620800
+#define	DA732X_MCLK_10MHZ		10000000
+#define	DA732X_MCLK_20MHZ		20000000
+#define	DA732X_MCLK_40MHZ		40000000
+#define	DA732X_MCLK_54MHZ		54000000
+#define	DA732X_MCLK_RET_0_10MHZ		0
+#define	DA732X_MCLK_VAL_0_10MHZ		1
+#define	DA732X_MCLK_RET_10_20MHZ	1
+#define	DA732X_MCLK_VAL_10_20MHZ	2
+#define	DA732X_MCLK_RET_20_40MHZ	2
+#define	DA732X_MCLK_VAL_20_40MHZ	4
+#define	DA732X_MCLK_RET_40_54MHZ	3
+#define	DA732X_MCLK_VAL_40_54MHZ	8
+#define	DA732X_DAI_ID1			0
+#define	DA732X_DAI_ID2			1
+#define	DA732X_SRCCLK_PLL		0
+#define	DA732X_SRCCLK_MCLK		1
+
+#define	DA732X_LIN_LP_VOL		0x4F
+#define	DA732X_LP_VOL			0x40
+
+/* Kcontrols */
+#define	DA732X_DAC_EN_MAX		2
+#define	DA732X_ADCL_MUX_MAX		2
+#define	DA732X_ADCR_MUX_MAX		3
+#define	DA732X_HPF_MODE_MAX		3
+#define	DA732X_HPF_MODE_SHIFT		4
+#define	DA732X_HPF_MUSIC_SHIFT		0
+#define	DA732X_HPF_MUSIC_MAX		4
+#define	DA732X_HPF_VOICE_SHIFT		4
+#define	DA732X_HPF_VOICE_MAX		8
+#define	DA732X_EQ_EN_MAX		1
+#define	DA732X_HPF_VOICE		1
+#define	DA732X_HPF_MUSIC		2
+#define	DA732X_HPF_DISABLED		0
+#define	DA732X_NO_INVERT		0
+#define	DA732X_INVERT			1
+#define	DA732X_SWITCH_MAX		1
+#define	DA732X_ENABLE_CP		1
+#define	DA732X_DISABLE_CP		0
+#define	DA732X_DISABLE_ALL_CLKS		0
+#define	DA732X_RESET_ADCS		0
+
+/* dB values */
+#define DA732X_MIC_VOL_DB_MIN		0
+#define DA732X_MIC_VOL_DB_INC		50
+#define DA732X_MIC_PRE_VOL_DB_MIN	0
+#define DA732X_MIC_PRE_VOL_DB_INC	600
+#define DA732X_AUX_VOL_DB_MIN		-6000
+#define DA732X_AUX_VOL_DB_INC		150
+#define DA732X_HP_VOL_DB_MIN		-2250
+#define DA732X_HP_VOL_DB_INC		150
+#define	DA732X_LIN2_VOL_DB_MIN		-1650
+#define	DA732X_LIN2_VOL_DB_INC		150
+#define	DA732X_LIN3_VOL_DB_MIN		-1650
+#define DA732X_LIN3_VOL_DB_INC		150
+#define	DA732X_LIN4_VOL_DB_MIN		-2250
+#define DA732X_LIN4_VOL_DB_INC		150
+#define	DA732X_EQ_BAND_VOL_DB_MIN	-1050
+#define	DA732X_EQ_BAND_VOL_DB_INC	150
+#define DA732X_DAC_VOL_DB_MIN		-7725
+#define DA732X_DAC_VOL_DB_INC		75
+#define DA732X_ADC_VOL_DB_MIN		0
+#define DA732X_ADC_VOL_DB_INC		-1
+#define	DA732X_EQ_OVERALL_VOL_DB_MIN	-1800
+#define	DA732X_EQ_OVERALL_VOL_DB_INC	600
+
+enum da732x_sysctl {
+	DA732X_SR_8KHZ		= 0x1,
+	DA732X_SR_11_025KHZ	= 0x2,
+	DA732X_SR_12KHZ		= 0x3,
+	DA732X_SR_16KHZ		= 0x5,
+	DA732X_SR_22_05KHZ	= 0x6,
+	DA732X_SR_24KHZ		= 0x7,
+	DA732X_SR_32KHZ		= 0x9,
+	DA732X_SR_44_1KHZ	= 0xA,
+	DA732X_SR_48KHZ		= 0xB,
+	DA732X_SR_88_1KHZ	= 0xE,
+	DA732X_SR_96KHZ		= 0xF,
+};
+
+#endif /* __DA732X_H_ */
diff --git a/sound/soc/codecs/da732x_reg.h b/sound/soc/codecs/da732x_reg.h
new file mode 100644
index 0000000..bdd03ca
--- /dev/null
+++ b/sound/soc/codecs/da732x_reg.h
@@ -0,0 +1,654 @@
+/*
+ * da732x_reg.h --- Dialog DA732X ALSA SoC Audio Registers Header File
+ *
+ * Copyright (C) 2012 Dialog Semiconductor GmbH
+ *
+ * Author: Michal Hajduk <Michal.Hajduk@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DA732X_REG_H_
+#define __DA732X_REG_H_
+
+/* DA732X registers */
+#define	DA732X_REG_STATUS_EXT		0x00
+#define DA732X_REG_STATUS		0x01
+#define DA732X_REG_REF1			0x02
+#define DA732X_REG_BIAS_EN		0x03
+#define DA732X_REG_BIAS1		0x04
+#define DA732X_REG_BIAS2		0x05
+#define DA732X_REG_BIAS3		0x06
+#define DA732X_REG_BIAS4		0x07
+#define DA732X_REG_MICBIAS2		0x0F
+#define DA732X_REG_MICBIAS1		0x10
+#define DA732X_REG_MICDET		0x11
+#define DA732X_REG_MIC1_PRE		0x12
+#define DA732X_REG_MIC1			0x13
+#define DA732X_REG_MIC2_PRE		0x14
+#define DA732X_REG_MIC2			0x15
+#define DA732X_REG_AUX1L		0x16
+#define DA732X_REG_AUX1R		0x17
+#define DA732X_REG_MIC3_PRE		0x18
+#define DA732X_REG_MIC3			0x19
+#define DA732X_REG_INP_PINBIAS		0x1A
+#define DA732X_REG_INP_ZC_EN		0x1B
+#define DA732X_REG_INP_MUX		0x1D
+#define DA732X_REG_HP_DET		0x20
+#define DA732X_REG_HPL_DAC_OFFSET	0x21
+#define DA732X_REG_HPL_DAC_OFF_CNTL	0x22
+#define DA732X_REG_HPL_OUT_OFFSET	0x23
+#define DA732X_REG_HPL			0x24
+#define DA732X_REG_HPL_VOL		0x25
+#define DA732X_REG_HPR_DAC_OFFSET	0x26
+#define DA732X_REG_HPR_DAC_OFF_CNTL	0x27
+#define DA732X_REG_HPR_OUT_OFFSET	0x28
+#define DA732X_REG_HPR			0x29
+#define DA732X_REG_HPR_VOL		0x2A
+#define DA732X_REG_LIN2			0x2B
+#define DA732X_REG_LIN3			0x2C
+#define DA732X_REG_LIN4			0x2D
+#define DA732X_REG_OUT_ZC_EN		0x2E
+#define DA732X_REG_HP_LIN1_GNDSEL	0x37
+#define DA732X_REG_CP_HP1		0x3A
+#define DA732X_REG_CP_HP2		0x3B
+#define DA732X_REG_CP_CTRL1		0x40
+#define DA732X_REG_CP_CTRL2		0x41
+#define DA732X_REG_CP_CTRL3		0x42
+#define DA732X_REG_CP_LEVEL_MASK	0x43
+#define DA732X_REG_CP_DET		0x44
+#define DA732X_REG_CP_STATUS		0x45
+#define DA732X_REG_CP_THRESH1		0x46
+#define DA732X_REG_CP_THRESH2		0x47
+#define DA732X_REG_CP_THRESH3		0x48
+#define DA732X_REG_CP_THRESH4		0x49
+#define DA732X_REG_CP_THRESH5		0x4A
+#define DA732X_REG_CP_THRESH6		0x4B
+#define DA732X_REG_CP_THRESH7		0x4C
+#define DA732X_REG_CP_THRESH8		0x4D
+#define DA732X_REG_PLL_DIV_LO		0x50
+#define DA732X_REG_PLL_DIV_MID		0x51
+#define DA732X_REG_PLL_DIV_HI		0x52
+#define DA732X_REG_PLL_CTRL		0x53
+#define DA732X_REG_CLK_CTRL		0x54
+#define DA732X_REG_CLK_DSP		0x5A
+#define DA732X_REG_CLK_EN1		0x5B
+#define DA732X_REG_CLK_EN2		0x5C
+#define DA732X_REG_CLK_EN3		0x5D
+#define DA732X_REG_CLK_EN4		0x5E
+#define DA732X_REG_CLK_EN5		0x5F
+#define DA732X_REG_AIF_MCLK		0x60
+#define DA732X_REG_AIFA1		0x61
+#define DA732X_REG_AIFA2		0x62
+#define DA732X_REG_AIFA3		0x63
+#define DA732X_REG_AIFB1		0x64
+#define DA732X_REG_AIFB2		0x65
+#define DA732X_REG_AIFB3		0x66
+#define DA732X_REG_PC_CTRL		0x6A
+#define DA732X_REG_DATA_ROUTE		0x70
+#define DA732X_REG_DSP_CTRL		0x71
+#define DA732X_REG_CIF_CTRL2		0x74
+#define DA732X_REG_HANDSHAKE		0x75
+#define DA732X_REG_MBOX0		0x76
+#define DA732X_REG_MBOX1		0x77
+#define DA732X_REG_MBOX2		0x78
+#define DA732X_REG_MBOX_STATUS		0x79
+#define DA732X_REG_SPARE1_OUT		0x7D
+#define DA732X_REG_SPARE2_OUT		0x7E
+#define DA732X_REG_SPARE1_IN		0x7F
+#define DA732X_REG_ID			0x81
+#define DA732X_REG_ADC1_PD		0x90
+#define DA732X_REG_ADC1_HPF		0x93
+#define DA732X_REG_ADC1_SEL		0x94
+#define DA732X_REG_ADC1_EQ12		0x95
+#define DA732X_REG_ADC1_EQ34		0x96
+#define DA732X_REG_ADC1_EQ5		0x97
+#define DA732X_REG_ADC2_PD		0x98
+#define DA732X_REG_ADC2_HPF		0x9B
+#define DA732X_REG_ADC2_SEL		0x9C
+#define DA732X_REG_ADC2_EQ12		0x9D
+#define DA732X_REG_ADC2_EQ34		0x9E
+#define DA732X_REG_ADC2_EQ5		0x9F
+#define DA732X_REG_DAC1_HPF		0xA0
+#define DA732X_REG_DAC1_L_VOL		0xA1
+#define DA732X_REG_DAC1_R_VOL		0xA2
+#define DA732X_REG_DAC1_SEL		0xA3
+#define DA732X_REG_DAC1_SOFTMUTE	0xA4
+#define DA732X_REG_DAC1_EQ12		0xA5
+#define DA732X_REG_DAC1_EQ34		0xA6
+#define DA732X_REG_DAC1_EQ5		0xA7
+#define DA732X_REG_DAC2_HPF		0xB0
+#define DA732X_REG_DAC2_L_VOL		0xB1
+#define DA732X_REG_DAC2_R_VOL		0xB2
+#define DA732X_REG_DAC2_SEL		0xB3
+#define DA732X_REG_DAC2_SOFTMUTE	0xB4
+#define DA732X_REG_DAC2_EQ12		0xB5
+#define DA732X_REG_DAC2_EQ34		0xB6
+#define DA732X_REG_DAC2_EQ5		0xB7
+#define DA732X_REG_DAC3_HPF		0xC0
+#define DA732X_REG_DAC3_VOL		0xC1
+#define DA732X_REG_DAC3_SEL		0xC3
+#define DA732X_REG_DAC3_SOFTMUTE	0xC4
+#define DA732X_REG_DAC3_EQ12		0xC5
+#define DA732X_REG_DAC3_EQ34		0xC6
+#define DA732X_REG_DAC3_EQ5		0xC7
+#define DA732X_REG_BIQ_BYP		0xD2
+#define DA732X_REG_DMA_CMD		0xD3
+#define DA732X_REG_DMA_ADDR0		0xD4
+#define DA732X_REG_DMA_ADDR1		0xD5
+#define DA732X_REG_DMA_DATA0		0xD6
+#define DA732X_REG_DMA_DATA1		0xD7
+#define DA732X_REG_DMA_DATA2		0xD8
+#define DA732X_REG_DMA_DATA3		0xD9
+#define DA732X_REG_DMA_STATUS		0xDA
+#define DA732X_REG_BROWNOUT		0xDF
+#define DA732X_REG_UNLOCK		0xE0
+
+#define	DA732X_MAX_REG			DA732X_REG_UNLOCK
+/*
+ * Bits
+ */
+
+/* DA732X_REG_STATUS_EXT (addr=0x00) */
+#define	DA732X_STATUS_EXT_DSP			(1 << 4)
+#define	DA732X_STATUS_EXT_CLEAR			(0 << 0)
+
+/* DA732X_REG_STATUS	(addr=0x01) */
+#define DA732X_STATUS_PLL_LOCK			(1 << 0)
+#define DA732X_STATUS_PLL_MCLK_DET		(1 << 1)
+#define DA732X_STATUS_HPDET_OUT			(1 << 2)
+#define DA732X_STATUS_INP_MIXDET_1		(1 << 3)
+#define DA732X_STATUS_INP_MIXDET_2		(1 << 4)
+#define DA732X_STATUS_BO_STATUS			(1 << 5)
+
+/* DA732X_REG_REF1	(addr=0x02) */
+#define DA732X_VMID_FASTCHG			(1 << 1)
+#define DA732X_VMID_FASTDISCHG			(1 << 2)
+#define DA732X_REFBUFX2_EN			(1 << 6)
+#define DA732X_REFBUFX2_DIS			(0 << 6)
+
+/* DA732X_REG_BIAS_EN	(addr=0x03) */
+#define DA732X_BIAS_BOOST_MASK			(3 << 0)
+#define DA732X_BIAS_BOOST_100PC			(0 << 0)
+#define DA732X_BIAS_BOOST_133PC			(1 << 0)
+#define DA732X_BIAS_BOOST_88PC			(2 << 0)
+#define DA732X_BIAS_BOOST_50PC			(3 << 0)
+#define DA732X_BIAS_EN				(1 << 7)
+#define DA732X_BIAS_DIS				(0 << 7)
+
+/* DA732X_REG_BIAS1	(addr=0x04) */
+#define DA732X_BIAS1_HP_DAC_BIAS_MASK		(3 << 0)
+#define DA732X_BIAS1_HP_DAC_BIAS_100PC		(0 << 0)
+#define DA732X_BIAS1_HP_DAC_BIAS_150PC		(1 << 0)
+#define DA732X_BIAS1_HP_DAC_BIAS_50PC		(2 << 0)
+#define DA732X_BIAS1_HP_DAC_BIAS_75PC		(3 << 0)
+#define DA732X_BIAS1_HP_OUT_BIAS_MASK		(7 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_100PC		(0 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_125PC		(1 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_150PC		(2 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_175PC		(3 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_200PC		(4 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_250PC		(5 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_300PC		(6 << 4)
+#define DA732X_BIAS1_HP_OUT_BIAS_350PC		(7 << 4)
+
+/* DA732X_REG_BIAS2	(addr=0x05) */
+#define DA732X_BIAS2_LINE2_DAC_BIAS_MASK	(3 << 0)
+#define DA732X_BIAS2_LINE2_DAC_BIAS_100PC	(0 << 0)
+#define DA732X_BIAS2_LINE2_DAC_BIAS_150PC	(1 << 0)
+#define DA732X_BIAS2_LINE2_DAC_BIAS_50PC	(2 << 0)
+#define DA732X_BIAS2_LINE2_DAC_BIAS_75PC	(3 << 0)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_MASK	(7 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_100PC	(0 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_125PC	(1 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_150PC	(2 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_175PC	(3 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_200PC	(4 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_250PC	(5 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_300PC	(6 << 4)
+#define DA732X_BIAS2_LINE2_OUT_BIAS_350PC	(7 << 4)
+
+/* DA732X_REG_BIAS3	(addr=0x06) */
+#define DA732X_BIAS3_LINE3_DAC_BIAS_MASK	(3 << 0)
+#define DA732X_BIAS3_LINE3_DAC_BIAS_100PC	(0 << 0)
+#define DA732X_BIAS3_LINE3_DAC_BIAS_150PC	(1 << 0)
+#define DA732X_BIAS3_LINE3_DAC_BIAS_50PC	(2 << 0)
+#define DA732X_BIAS3_LINE3_DAC_BIAS_75PC	(3 << 0)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_MASK	(7 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_100PC	(0 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_125PC	(1 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_150PC	(2 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_175PC	(3 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_200PC	(4 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_250PC	(5 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_300PC	(6 << 4)
+#define DA732X_BIAS3_LINE3_OUT_BIAS_350PC	(7 << 4)
+
+/* DA732X_REG_BIAS4	(addr=0x07) */
+#define DA732X_BIAS4_LINE4_DAC_BIAS_MASK	(3 << 0)
+#define DA732X_BIAS4_LINE4_DAC_BIAS_100PC	(0 << 0)
+#define DA732X_BIAS4_LINE4_DAC_BIAS_150PC	(1 << 0)
+#define DA732X_BIAS4_LINE4_DAC_BIAS_50PC	(2 << 0)
+#define DA732X_BIAS4_LINE4_DAC_BIAS_75PC	(3 << 0)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_MASK	(7 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_100PC	(0 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_125PC	(1 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_150PC	(2 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_175PC	(3 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_200PC	(4 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_250PC	(5 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_300PC	(6 << 4)
+#define DA732X_BIAS4_LINE4_OUT_BIAS_350PC	(7 << 4)
+
+/* DA732X_REG_SIF_VDD_SEL	(addr=0x08) */
+#define DA732X_SIF_VDD_SEL_AIFA_VDD2		(1 << 0)
+#define DA732X_SIF_VDD_SEL_AIFB_VDD2		(1 << 1)
+#define DA732X_SIF_VDD_SEL_CIFA_VDD2		(1 << 4)
+
+/* DA732X_REG_MICBIAS2/1	(addr=0x0F/0x10) */
+#define DA732X_MICBIAS_VOLTAGE_MASK		(0x0F << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V		(0x00 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V05		(0x01 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V1		(0x02 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V15		(0x03 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V2		(0x04 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V25		(0x05 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V3		(0x06 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V35		(0x07 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V4		(0x08 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V45		(0x09 << 0)
+#define DA732X_MICBIAS_VOLTAGE_2V5		(0x0A << 0)
+#define DA732X_MICBIAS_EN			(1 << 7)
+#define DA732X_MICBIAS_EN_SHIFT			7
+#define DA732X_MICBIAS_VOLTAGE_SHIFT		0
+#define	DA732X_MICBIAS_VOLTAGE_MAX		0x0B
+
+/* DA732X_REG_MICDET	(addr=0x11) */
+#define DA732X_MICDET_INP_MICRES		(1 << 0)
+#define DA732X_MICDET_INP_MICHOOK		(1 << 1)
+#define DA732X_MICDET_INP_DEBOUNCE_PRD_8MS	(0 << 0)
+#define DA732X_MICDET_INP_DEBOUNCE_PRD_16MS	(1 << 0)
+#define DA732X_MICDET_INP_DEBOUNCE_PRD_32MS	(2 << 0)
+#define DA732X_MICDET_INP_DEBOUNCE_PRD_64MS	(3 << 0)
+#define DA732X_MICDET_INP_MICDET_EN		(1 << 7)
+
+/* DA732X_REG_MIC1/2/3_PRE (addr=0x11/0x14/0x18) */
+#define	DA732X_MICBOOST_MASK			0x7
+#define	DA732X_MICBOOST_SHIFT			0
+#define	DA732X_MICBOOST_MIN			0x1
+#define	DA732X_MICBOOST_MAX			DA732X_MICBOOST_MASK
+
+/* DA732X_REG_MIC1/2/3	(addr=0x13/0x15/0x19) */
+#define	DA732X_MIC_VOL_SHIFT			0
+#define	DA732X_MIC_VOL_VAL_MASK			0x1F
+#define DA732X_MIC_MUTE_SHIFT			6
+#define DA732X_MIC_EN_SHIFT			7
+#define DA732X_MIC_VOL_VAL_MIN			0x7
+#define	DA732X_MIC_VOL_VAL_MAX			DA732X_MIC_VOL_VAL_MASK
+
+/* DA732X_REG_AUX1L/R	(addr=0x16/0x17) */
+#define	DA732X_AUX_VOL_SHIFT			0
+#define	DA732X_AUX_VOL_MASK			0x7
+#define DA732X_AUX_MUTE_SHIFT			6
+#define DA732X_AUX_EN_SHIFT			7
+#define	DA732X_AUX_VOL_VAL_MAX			DA732X_AUX_VOL_MASK
+
+/* DA732X_REG_INP_PINBIAS	(addr=0x1A) */
+#define DA732X_INP_MICL_PINBIAS_EN		(1 << 0)
+#define DA732X_INP_MICR_PINBIAS_EN		(1 << 1)
+#define DA732X_INP_AUX1L_PINBIAS_EN		(1 << 2)
+#define DA732X_INP_AUX1R_PINBIAS_EN		(1 << 3)
+#define DA732X_INP_AUX2_PINBIAS_EN		(1 << 4)
+
+/* DA732X_REG_INP_ZC_EN	(addr=0x1B) */
+#define	DA732X_MIC1_PRE_ZC_EN			(1 << 0)
+#define	DA732X_MIC1_ZC_EN			(1 << 1)
+#define	DA732X_MIC2_PRE_ZC_EN			(1 << 2)
+#define	DA732X_MIC2_ZC_EN			(1 << 3)
+#define	DA732X_AUXL_ZC_EN			(1 << 4)
+#define	DA732X_AUXR_ZC_EN			(1 << 5)
+#define	DA732X_MIC3_PRE_ZC_EN			(1 << 6)
+#define	DA732X_MIC3_ZC_EN			(1 << 7)
+
+/* DA732X_REG_INP_MUX	(addr=0x1D) */
+#define DA732X_INP_ADC1L_MUX_SEL_AUX1L		(0 << 0)
+#define DA732X_INP_ADC1L_MUX_SEL_MIC1		(1 << 0)
+#define DA732X_INP_ADC1R_MUX_SEL_MASK		(3 << 2)
+#define DA732X_INP_ADC1R_MUX_SEL_AUX1R		(0 << 2)
+#define DA732X_INP_ADC1R_MUX_SEL_MIC2		(1 << 2)
+#define DA732X_INP_ADC1R_MUX_SEL_MIC3		(2 << 2)
+#define DA732X_INP_ADC2L_MUX_SEL_AUX1L		(0 << 4)
+#define DA732X_INP_ADC2L_MUX_SEL_MICL		(1 << 4)
+#define DA732X_INP_ADC2R_MUX_SEL_MASK		(3 << 6)
+#define DA732X_INP_ADC2R_MUX_SEL_AUX1R		(0 << 6)
+#define DA732X_INP_ADC2R_MUX_SEL_MICR		(1 << 6)
+#define DA732X_INP_ADC2R_MUX_SEL_AUX2		(2 << 6)
+#define	DA732X_ADC1L_MUX_SEL_SHIFT		0
+#define	DA732X_ADC1R_MUX_SEL_SHIFT		2
+#define	DA732X_ADC2L_MUX_SEL_SHIFT		4
+#define	DA732X_ADC2R_MUX_SEL_SHIFT		6
+
+/* DA732X_REG_HP_DET		(addr=0x20) */
+#define DA732X_HP_DET_AZ			(1 << 0)
+#define DA732X_HP_DET_SEL1			(1 << 1)
+#define DA732X_HP_DET_IS_MASK			(3 << 2)
+#define DA732X_HP_DET_IS_0_5UA			(0 << 2)
+#define DA732X_HP_DET_IS_1UA			(1 << 2)
+#define DA732X_HP_DET_IS_2UA			(2 << 2)
+#define DA732X_HP_DET_IS_4UA			(3 << 2)
+#define DA732X_HP_DET_RS_MASK			(3 << 4)
+#define DA732X_HP_DET_RS_INFINITE		(0 << 4)
+#define DA732X_HP_DET_RS_100KOHM		(1 << 4)
+#define DA732X_HP_DET_RS_10KOHM			(2 << 4)
+#define DA732X_HP_DET_RS_1KOHM			(3 << 4)
+#define DA732X_HP_DET_EN			(1 << 7)
+
+/* DA732X_REG_HPL_DAC_OFFSET	(addr=0x21/0x26) */
+#define DA732X_HP_DAC_OFFSET_TRIM_MASK		(0x3F << 0)
+#define DA732X_HP_DAC_OFFSET_DAC_SIGN		(1 << 6)
+
+/* DA732X_REG_HPL_DAC_OFF_CNTL	(addr=0x22/0x27) */
+#define DA732X_HP_DAC_OFF_CNTL_CONT_MASK	(7 << 0)
+#define DA732X_HP_DAC_OFF_CNTL_COMPO		(1 << 3)
+#define	DA732X_HP_DAC_OFF_CALIBRATION		(1 << 0)
+#define	DA732X_HP_DAC_OFF_SCALE_STEPS		(1 << 1)
+#define	DA732X_HP_DAC_OFF_MASK			0x7F
+#define DA732X_HP_DAC_COMPO_SHIFT		3
+
+/* DA732X_REG_HPL_OUT_OFFSET	(addr=0x23/0x28) */
+#define DA732X_HP_OUT_OFFSET_MASK		(0xFF << 0)
+#define	DA732X_HP_DAC_OFFSET_TRIM_VAL		0x7F
+
+/* DA732X_REG_HPL/R	(addr=0x24/0x29) */
+#define DA732X_HP_OUT_SIGN			(1 << 0)
+#define DA732X_HP_OUT_COMP			(1 << 1)
+#define DA732X_HP_OUT_RESERVED			(1 << 2)
+#define DA732X_HP_OUT_COMPO			(1 << 3)
+#define DA732X_HP_OUT_DAC_EN			(1 << 4)
+#define DA732X_HP_OUT_HIZ_EN			(1 << 5)
+#define	DA732X_HP_OUT_HIZ_DIS			(0 << 5)
+#define DA732X_HP_OUT_MUTE			(1 << 6)
+#define DA732X_HP_OUT_EN			(1 << 7)
+#define	DA732X_HP_OUT_COMPO_SHIFT		3
+#define	DA732X_HP_OUT_DAC_EN_SHIFT		4
+#define	DA732X_HP_HIZ_SHIFT			5
+#define	DA732X_HP_MUTE_SHIFT			6
+#define DA732X_HP_OUT_EN_SHIFT			7
+
+#define DA732X_OUT_HIZ_EN			(1 << 5)
+#define	DA732X_OUT_HIZ_DIS			(0 << 5)
+
+/* DA732X_REG_HPL/R_VOL	(addr=0x25/0x2A) */
+#define	DA732X_HP_VOL_VAL_MASK			0xF
+#define	DA732X_HP_VOL_SHIFT			0
+#define	DA732X_HP_VOL_VAL_MAX			DA732X_HP_VOL_VAL_MASK
+
+/* DA732X_REG_LIN2/3/4	(addr=0x2B/0x2C/0x2D) */
+#define DA732X_LOUT_VOL_SHIFT			0
+#define DA732X_LOUT_VOL_MASK			0x0F
+#define DA732X_LOUT_DAC_OFF			(0 << 4)
+#define DA732X_LOUT_DAC_EN			(1 << 4)
+#define DA732X_LOUT_HIZ_N_DIS			(0 << 5)
+#define DA732X_LOUT_HIZ_N_EN			(1 << 5)
+#define DA732X_LOUT_UNMUTED			(0 << 6)
+#define DA732X_LOUT_MUTED			(1 << 6)
+#define DA732X_LOUT_EN				(0 << 7)
+#define DA732X_LOUT_DIS				(1 << 7)
+#define DA732X_LOUT_DAC_EN_SHIFT		4
+#define	DA732X_LOUT_MUTE_SHIFT			6
+#define DA732X_LIN_OUT_EN_SHIFT			7
+#define DA732X_LOUT_VOL_VAL_MAX			DA732X_LOUT_VOL_MASK
+
+/* DA732X_REG_OUT_ZC_EN		(addr=0x2E) */
+#define	DA732X_HPL_ZC_EN_SHIFT			0
+#define DA732X_HPR_ZC_EN_SHIFT			1
+#define DA732X_HPL_ZC_EN			(1 << 0)
+#define DA732X_HPL_ZC_DIS			(0 << 0)
+#define DA732X_HPR_ZC_EN			(1 << 1)
+#define DA732X_HPR_ZC_DIS			(0 << 1)
+#define DA732X_LIN2_ZC_EN			(1 << 2)
+#define DA732X_LIN2_ZC_DIS			(0 << 2)
+#define DA732X_LIN3_ZC_EN			(1 << 3)
+#define DA732X_LIN3_ZC_DIS			(0 << 3)
+#define DA732X_LIN4_ZC_EN			(1 << 4)
+#define DA732X_LIN4_ZC_DIS			(0 << 4)
+
+/* DA732X_REG_HP_LIN1_GNDSEL (addr=0x37) */
+#define	DA732X_HP_OUT_GNDSEL			(1 << 0)
+
+/* DA732X_REG_CP_HP2 (addr=0x3a) */
+#define	DA732X_HP_CP_PULSESKIP			(1 << 0)
+#define	DA732X_HP_CP_REG			(1 << 1)
+#define DA732X_HP_CP_EN				(1 << 3)
+#define DA732X_HP_CP_DIS			(0 << 3)
+
+/* DA732X_REG_CP_CTRL1 (addr=0x40) */
+#define	DA732X_CP_MODE_MASK			(7 << 1)
+#define	DA732X_CP_CTRL_STANDBY			(0 << 1)
+#define	DA732X_CP_CTRL_CPVDD6			(2 << 1)
+#define	DA732X_CP_CTRL_CPVDD5			(3 << 1)
+#define	DA732X_CP_CTRL_CPVDD4			(4 << 1)
+#define	DA732X_CP_CTRL_CPVDD3			(5 << 1)
+#define	DA732X_CP_CTRL_CPVDD2			(6 << 1)
+#define	DA732X_CP_CTRL_CPVDD1			(7 << 1)
+#define	DA723X_CP_DIS				(0 << 7)
+#define	DA732X_CP_EN				(1 << 7)
+
+/* DA732X_REG_CP_CTRL2 (addr=0x41) */
+#define	DA732X_CP_BOOST				(1 << 0)
+#define	DA732X_CP_MANAGE_MAGNITUDE		(2 << 2)
+
+/* DA732X_REG_CP_CTRL3 (addr=0x42) */
+#define	DA732X_CP_1MHZ				(0 << 0)
+#define	DA732X_CP_500KHZ			(1 << 0)
+#define	DA732X_CP_250KHZ			(2 << 0)
+#define	DA732X_CP_125KHZ			(3 << 0)
+#define	DA732X_CP_63KHZ				(4 << 0)
+#define	DA732X_CP_0KHZ				(5 << 0)
+
+/* DA732X_REG_PLL_CTRL (addr=0x53) */
+#define	DA732X_PLL_INDIV_MASK			(3 << 0)
+#define	DA732X_PLL_SRM_EN			(1 << 2)
+#define	DA732X_PLL_EN				(1 << 7)
+#define	DA732X_PLL_BYPASS			(0 << 0)
+
+/* DA732X_REG_CLK_CTRL (addr=0x54) */
+#define	DA732X_SR1_MASK				(0xF)
+#define	DA732X_SR2_MASK				(0xF0)
+
+/* DA732X_REG_CLK_DSP (addr=0x5A) */
+#define	DA732X_DSP_FREQ_MASK			(7 << 0)
+#define	DA732X_DSP_FREQ_12MHZ			(0 << 0)
+#define	DA732X_DSP_FREQ_24MHZ			(1 << 0)
+#define	DA732X_DSP_FREQ_36MHZ			(2 << 0)
+#define	DA732X_DSP_FREQ_48MHZ			(3 << 0)
+#define	DA732X_DSP_FREQ_60MHZ			(4 << 0)
+#define	DA732X_DSP_FREQ_72MHZ			(5 << 0)
+#define	DA732X_DSP_FREQ_84MHZ			(6 << 0)
+#define	DA732X_DSP_FREQ_96MHZ			(7 << 0)
+
+/* DA732X_REG_CLK_EN1 (addr=0x5B) */
+#define	DA732X_DSP_CLK_EN			(1 << 0)
+#define	DA732X_SYS3_CLK_EN			(1 << 1)
+#define	DA732X_DSP12_CLK_EN			(1 << 2)
+#define	DA732X_PC_CLK_EN			(1 << 3)
+#define	DA732X_MCLK_SQR_EN			(1 << 7)
+
+/* DA732X_REG_CLK_EN2 (addr=0x5C) */
+#define	DA732X_UART_CLK_EN			(1 << 1)
+#define	DA732X_CP_CLK_EN			(1 << 2)
+#define	DA732X_CP_CLK_DIS			(0 << 2)
+
+/* DA732X_REG_CLK_EN3 (addr=0x5D) */
+#define	DA732X_ADCA_BB_CLK_EN			(1 << 0)
+#define	DA732X_ADCC_BB_CLK_EN			(1 << 4)
+
+/* DA732X_REG_CLK_EN4 (addr=0x5E) */
+#define	DA732X_DACA_BB_CLK_EN			(1 << 0)
+#define	DA732X_DACC_BB_CLK_EN			(1 << 4)
+#define DA732X_DACA_BB_CLK_SHIFT		0
+#define DA732X_DACC_BB_CLK_SHIFT		4
+
+/* DA732X_REG_CLK_EN5 (addr=0x5F) */
+#define	DA732X_DACE_BB_CLK_EN			(1 << 0)
+#define DA732X_DACE_BB_CLK_SHIFT		0
+
+/* DA732X_REG_AIF_MCLK (addr=0x60) */
+#define DA732X_AIFM_FRAME_64			(1 << 2)
+#define	DA732X_AIFM_SRC_SEL_AIFA		(1 << 6)
+#define	DA732X_CLK_GENERATION_AIF_A		(1 << 4)
+#define	DA732X_NO_CLK_GENERATION		0x0
+
+/* DA732X_REG_AIFA1 (addr=0x61) */
+#define	DA732X_AIF_WORD_MASK			(0x3 << 0)
+#define	DA732X_AIF_WORD_16			(0 << 0)
+#define	DA732X_AIF_WORD_20			(1 << 0)
+#define	DA732X_AIF_WORD_24			(2 << 0)
+#define	DA732X_AIF_WORD_32			(3 << 0)
+#define	DA732X_AIF_TDM_MONO_SHIFT		(1 << 6)
+#define	DA732X_AIF1_CLK_MASK			(1 << 7)
+#define	DA732X_AIF_SLAVE			(0 << 7)
+#define DA732X_AIF_CLK_FROM_SRC			(1 << 7)
+
+/* DA732X_REG_AIFA3 (addr=0x63) */
+#define	DA732X_AIF_MODE_SHIFT			0
+#define	DA732X_AIF_MODE_MASK			0x3
+#define	DA732X_AIF_I2S_MODE			(0 << 0)
+#define	DA732X_AIF_LEFT_J_MODE			(1 << 0)
+#define	DA732X_AIF_RIGHT_J_MODE			(2 << 0)
+#define	DA732X_AIF_DSP_MODE			(3 << 0)
+#define DA732X_AIF_WCLK_INV			(1 << 4)
+#define DA732X_AIF_BCLK_INV			(1 << 5)
+#define	DA732X_AIF_EN				(1 << 7)
+#define	DA732X_AIF_EN_SHIFT			7
+
+/* DA732X_REG_PC_CTRL (addr=0x6a) */
+#define	DA732X_PC_PULSE_AIFA			(0 << 0)
+#define	DA732X_PC_PULSE_AIFB			(1 << 0)
+#define	DA732X_PC_RESYNC_AUT			(1 << 6)
+#define	DA732X_PC_RESYNC_NOT_AUT		(0 << 6)
+#define	DA732X_PC_SAME				(1 << 7)
+
+/* DA732X_REG_DATA_ROUTE (addr=0x70) */
+#define DA732X_ADC1_TO_AIFA			(0 << 0)
+#define DA732X_DSP_TO_AIFA			(1 << 0)
+#define DA732X_ADC2_TO_AIFB			(0 << 1)
+#define DA732X_DSP_TO_AIFB			(1 << 1)
+#define DA732X_AIFA_TO_DAC1L			(0 << 2)
+#define DA732X_DSP_TO_DAC1L			(1 << 2)
+#define DA732X_AIFA_TO_DAC1R			(0 << 3)
+#define DA732X_DSP_TO_DAC1R			(1 << 3)
+#define DA732X_AIFB_TO_DAC2L			(0 << 4)
+#define DA732X_DSP_TO_DAC2L			(1 << 4)
+#define DA732X_AIFB_TO_DAC2R			(0 << 5)
+#define DA732X_DSP_TO_DAC2R			(1 << 5)
+#define DA732X_AIFB_TO_DAC3			(0 << 6)
+#define DA732X_DSP_TO_DAC3			(1 << 6)
+#define	DA732X_BYPASS_DSP			(0 << 0)
+#define	DA732X_ALL_TO_DSP			(0x7F << 0)
+
+/* DA732X_REG_DSP_CTRL (addr=0x71) */
+#define	DA732X_DIGITAL_EN			(1 << 0)
+#define	DA732X_DIGITAL_RESET			(0 << 0)
+#define	DA732X_DSP_CORE_EN			(1 << 1)
+#define	DA732X_DSP_CORE_RESET			(0 << 1)
+
+/* DA732X_REG_SPARE1_OUT (addr=0x7D)*/
+#define	DA732X_HP_DRIVER_EN			(1 << 0)
+#define	DA732X_HP_GATE_LOW			(1 << 2)
+#define DA732X_HP_LOOP_GAIN_CTRL		(1 << 3)
+
+/* DA732X_REG_ID (addr=0x81)*/
+#define DA732X_ID_MINOR_MASK			(0xF << 0)
+#define DA732X_ID_MAJOR_MASK			(0xF << 4)
+
+/* DA732X_REG_ADC1/2_PD (addr=0x90/0x98) */
+#define	DA732X_ADC_RST_MASK			(0x3 << 0)
+#define	DA732X_ADC_PD_MASK			(0x3 << 2)
+#define	DA732X_ADC_SET_ACT			(0x3 << 0)
+#define	DA732X_ADC_SET_RST			(0x0 << 0)
+#define	DA732X_ADC_ON				(0x3 << 2)
+#define	DA732X_ADC_OFF				(0x0 << 2)
+
+/* DA732X_REG_ADC1/2_SEL (addr=0x94/0x9C) */
+#define	DA732X_ADC_VOL_VAL_MASK			0x7
+#define	DA732X_ADCL_VOL_SHIFT			0
+#define	DA732X_ADCR_VOL_SHIFT			4
+#define DA732X_ADCL_EN_SHIFT			2
+#define DA732X_ADCR_EN_SHIFT			3
+#define	DA732X_ADCL_EN				(1 << 2)
+#define	DA732X_ADCR_EN				(1 << 3)
+#define	DA732X_ADC_VOL_VAL_MAX			DA732X_ADC_VOL_VAL_MASK
+
+/*
+ * DA732X_REG_ADC1/2_HPF (addr=0x93/0x9b)
+ * DA732x_REG_DAC1/2/3_HPG	(addr=0xA5/0xB5/0xC5)
+ */
+#define	DA732X_HPF_MUSIC_EN			(1 << 3)
+#define	DA732X_HPF_VOICE_EN			((1 << 3) | (1 << 7))
+#define	DA732X_HPF_MASK				((1 << 3) | (1 << 7))
+#define DA732X_HPF_DIS				((0 << 3) | (0 << 7))
+
+/* DA732X_REG_DAC1/2/3_VOL */
+#define DA732X_DAC_VOL_VAL_MASK			0x7F
+#define DA732X_DAC_VOL_SHIFT			0
+#define DA732X_DAC_VOL_VAL_MAX			DA732X_DAC_VOL_VAL_MASK
+
+/* DA732X_REG_DAC1/2/3_SEL (addr=0xA3/0xB3/0xC3) */
+#define DA732X_DACL_EN_SHIFT			3
+#define	DA732X_DACR_EN_SHIFT			7
+#define DA732X_DACL_MUTE_SHIFT			2
+#define	DA732X_DACR_MUTE_SHIFT			6
+#define DA732X_DACL_EN				(1 << 3)
+#define	DA732X_DACR_EN				(1 << 7)
+#define	DA732X_DACL_SDM				(1 << 0)
+#define	DA732X_DACR_SDM				(1 << 4)
+#define	DA732X_DACL_MUTE			(1 << 2)
+#define	DA732X_DACR_MUTE			(1 << 6)
+
+/* DA732X_REG_DAC_SOFTMUTE (addr=0xA4/0xB4/0xC4) */
+#define	DA732X_SOFTMUTE_EN			(1 << 7)
+#define	DA732X_GAIN_RAMPED			(1 << 6)
+#define	DA732X_16_SAMPLES			(4 << 0)
+#define	DA732X_SOFTMUTE_MASK			(1 << 7)
+#define	DA732X_SOFTMUTE_SHIFT			7
+
+/*
+ * DA732x_REG_ADC1/2_EQ12	(addr=0x95/0x9D)
+ * DA732x_REG_ADC1/2_EQ34	(addr=0x96/0x9E)
+ * DA732x_REG_ADC1/2_EQ5	(addr=0x97/0x9F)
+ * DA732x_REG_DAC1/2/3_EQ12	(addr=0xA5/0xB5/0xC5)
+ * DA732x_REG_DAC1/2/3_EQ34	(addr=0xA6/0xB6/0xC6)
+ * DA732x_REG_DAC1/2/3_EQ5	(addr=0xA7/0xB7/0xB7)
+ */
+#define	DA732X_EQ_VOL_VAL_MASK			0xF
+#define	DA732X_EQ_BAND1_SHIFT			0
+#define	DA732X_EQ_BAND2_SHIFT			4
+#define	DA732X_EQ_BAND3_SHIFT			0
+#define	DA732X_EQ_BAND4_SHIFT			4
+#define	DA732X_EQ_BAND5_SHIFT			0
+#define	DA732X_EQ_OVERALL_SHIFT			4
+#define	DA732X_EQ_OVERALL_VOL_VAL_MASK		0x3
+#define	DA732X_EQ_DIS				(0 << 7)
+#define	DA732X_EQ_EN				(1 << 7)
+#define	DA732X_EQ_EN_SHIFT			7
+#define	DA732X_EQ_VOL_VAL_MAX			DA732X_EQ_VOL_VAL_MASK
+#define	DA732X_EQ_OVERALL_VOL_VAL_MAX		DA732X_EQ_OVERALL_VOL_VAL_MASK
+
+/* DA732X_REG_DMA_CMD (addr=0xD3) */
+#define	DA732X_SEL_DSP_DMA_MASK			(3 << 0)
+#define	DA732X_SEL_DSP_DMA_DIS			(0 << 0)
+#define	DA732X_SEL_DSP_DMA_PMEM			(1 << 0)
+#define	DA732X_SEL_DSP_DMA_XMEM			(2 << 0)
+#define	DA732X_SEL_DSP_DMA_YMEM			(3 << 0)
+#define	DA732X_DSP_RW_MASK			(1 << 4)
+#define	DA732X_DSP_DMA_WRITE			(0 << 4)
+#define	DA732X_DSP_DMA_READ			(1 << 4)
+
+/* DA732X_REG_DMA_STATUS (addr=0xDA) */
+#define	DA732X_DSP_DMA_FREE			(0 << 0)
+#define	DA732X_DSP_DMA_BUSY			(1 << 0)
+
+#endif /* __DA732X_REG_H_ */
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
new file mode 100644
index 0000000..f6a7bf9
--- /dev/null
+++ b/sound/soc/codecs/da9055.c
@@ -0,0 +1,1545 @@
+/*
+ * DA9055 ALSA Soc codec driver
+ *
+ * Copyright (c) 2012 Dialog Semiconductor
+ *
+ * Tested on (Samsung SMDK6410 board + DA9055 EVB) using I2S and I2C
+ * Written by David Chen <david.chen@diasemi.com> and
+ * Ashish Chavan <ashish.chavan@kpitcummins.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/da9055.h>
+
+/* DA9055 register space */
+
+/* Status Registers */
+#define DA9055_STATUS1			0x02
+#define DA9055_PLL_STATUS		0x03
+#define DA9055_AUX_L_GAIN_STATUS	0x04
+#define DA9055_AUX_R_GAIN_STATUS	0x05
+#define DA9055_MIC_L_GAIN_STATUS	0x06
+#define DA9055_MIC_R_GAIN_STATUS	0x07
+#define DA9055_MIXIN_L_GAIN_STATUS	0x08
+#define DA9055_MIXIN_R_GAIN_STATUS	0x09
+#define DA9055_ADC_L_GAIN_STATUS	0x0A
+#define DA9055_ADC_R_GAIN_STATUS	0x0B
+#define DA9055_DAC_L_GAIN_STATUS	0x0C
+#define DA9055_DAC_R_GAIN_STATUS	0x0D
+#define DA9055_HP_L_GAIN_STATUS		0x0E
+#define DA9055_HP_R_GAIN_STATUS		0x0F
+#define DA9055_LINE_GAIN_STATUS		0x10
+
+/* System Initialisation Registers */
+#define DA9055_CIF_CTRL			0x20
+#define DA9055_DIG_ROUTING_AIF		0X21
+#define DA9055_SR			0x22
+#define DA9055_REFERENCES		0x23
+#define DA9055_PLL_FRAC_TOP		0x24
+#define DA9055_PLL_FRAC_BOT		0x25
+#define DA9055_PLL_INTEGER		0x26
+#define DA9055_PLL_CTRL			0x27
+#define DA9055_AIF_CLK_MODE		0x28
+#define DA9055_AIF_CTRL			0x29
+#define DA9055_DIG_ROUTING_DAC		0x2A
+#define DA9055_ALC_CTRL1		0x2B
+
+/* Input - Gain, Select and Filter Registers */
+#define DA9055_AUX_L_GAIN		0x30
+#define DA9055_AUX_R_GAIN		0x31
+#define DA9055_MIXIN_L_SELECT		0x32
+#define DA9055_MIXIN_R_SELECT		0x33
+#define DA9055_MIXIN_L_GAIN		0x34
+#define DA9055_MIXIN_R_GAIN		0x35
+#define DA9055_ADC_L_GAIN		0x36
+#define DA9055_ADC_R_GAIN		0x37
+#define DA9055_ADC_FILTERS1		0x38
+#define DA9055_MIC_L_GAIN		0x39
+#define DA9055_MIC_R_GAIN		0x3A
+
+/* Output - Gain, Select and Filter Registers */
+#define DA9055_DAC_FILTERS5		0x40
+#define DA9055_DAC_FILTERS2		0x41
+#define DA9055_DAC_FILTERS3		0x42
+#define DA9055_DAC_FILTERS4		0x43
+#define DA9055_DAC_FILTERS1		0x44
+#define DA9055_DAC_L_GAIN		0x45
+#define DA9055_DAC_R_GAIN		0x46
+#define DA9055_CP_CTRL			0x47
+#define DA9055_HP_L_GAIN		0x48
+#define DA9055_HP_R_GAIN		0x49
+#define DA9055_LINE_GAIN		0x4A
+#define DA9055_MIXOUT_L_SELECT		0x4B
+#define DA9055_MIXOUT_R_SELECT		0x4C
+
+/* System Controller Registers */
+#define DA9055_SYSTEM_MODES_INPUT	0x50
+#define DA9055_SYSTEM_MODES_OUTPUT	0x51
+
+/* Control Registers */
+#define DA9055_AUX_L_CTRL		0x60
+#define DA9055_AUX_R_CTRL		0x61
+#define DA9055_MIC_BIAS_CTRL		0x62
+#define DA9055_MIC_L_CTRL		0x63
+#define DA9055_MIC_R_CTRL		0x64
+#define DA9055_MIXIN_L_CTRL		0x65
+#define DA9055_MIXIN_R_CTRL		0x66
+#define DA9055_ADC_L_CTRL		0x67
+#define DA9055_ADC_R_CTRL		0x68
+#define DA9055_DAC_L_CTRL		0x69
+#define DA9055_DAC_R_CTRL		0x6A
+#define DA9055_HP_L_CTRL		0x6B
+#define DA9055_HP_R_CTRL		0x6C
+#define DA9055_LINE_CTRL		0x6D
+#define DA9055_MIXOUT_L_CTRL		0x6E
+#define DA9055_MIXOUT_R_CTRL		0x6F
+
+/* Configuration Registers */
+#define DA9055_LDO_CTRL			0x90
+#define DA9055_IO_CTRL			0x91
+#define DA9055_GAIN_RAMP_CTRL		0x92
+#define DA9055_MIC_CONFIG		0x93
+#define DA9055_PC_COUNT			0x94
+#define DA9055_CP_VOL_THRESHOLD1	0x95
+#define DA9055_CP_DELAY			0x96
+#define DA9055_CP_DETECTOR		0x97
+#define DA9055_AIF_OFFSET		0x98
+#define DA9055_DIG_CTRL			0x99
+#define DA9055_ALC_CTRL2		0x9A
+#define DA9055_ALC_CTRL3		0x9B
+#define DA9055_ALC_NOISE		0x9C
+#define DA9055_ALC_TARGET_MIN		0x9D
+#define DA9055_ALC_TARGET_MAX		0x9E
+#define DA9055_ALC_GAIN_LIMITS		0x9F
+#define DA9055_ALC_ANA_GAIN_LIMITS	0xA0
+#define DA9055_ALC_ANTICLIP_CTRL	0xA1
+#define DA9055_ALC_ANTICLIP_LEVEL	0xA2
+#define DA9055_ALC_OFFSET_OP2M_L	0xA6
+#define DA9055_ALC_OFFSET_OP2U_L	0xA7
+#define DA9055_ALC_OFFSET_OP2M_R	0xAB
+#define DA9055_ALC_OFFSET_OP2U_R	0xAC
+#define DA9055_ALC_CIC_OP_LVL_CTRL	0xAD
+#define DA9055_ALC_CIC_OP_LVL_DATA	0xAE
+#define DA9055_DAC_NG_SETUP_TIME	0xAF
+#define DA9055_DAC_NG_OFF_THRESHOLD	0xB0
+#define DA9055_DAC_NG_ON_THRESHOLD	0xB1
+#define DA9055_DAC_NG_CTRL		0xB2
+
+/* SR bit fields */
+#define DA9055_SR_8000			(0x1 << 0)
+#define DA9055_SR_11025			(0x2 << 0)
+#define DA9055_SR_12000			(0x3 << 0)
+#define DA9055_SR_16000			(0x5 << 0)
+#define DA9055_SR_22050			(0x6 << 0)
+#define DA9055_SR_24000			(0x7 << 0)
+#define DA9055_SR_32000			(0x9 << 0)
+#define DA9055_SR_44100			(0xA << 0)
+#define DA9055_SR_48000			(0xB << 0)
+#define DA9055_SR_88200			(0xE << 0)
+#define DA9055_SR_96000			(0xF << 0)
+
+/* REFERENCES bit fields */
+#define DA9055_BIAS_EN			(1 << 3)
+#define DA9055_VMID_EN			(1 << 7)
+
+/* PLL_CTRL bit fields */
+#define DA9055_PLL_INDIV_10_20_MHZ	(1 << 2)
+#define DA9055_PLL_SRM_EN		(1 << 6)
+#define DA9055_PLL_EN			(1 << 7)
+
+/* AIF_CLK_MODE bit fields */
+#define DA9055_AIF_BCLKS_PER_WCLK_32	(0 << 0)
+#define DA9055_AIF_BCLKS_PER_WCLK_64	(1 << 0)
+#define DA9055_AIF_BCLKS_PER_WCLK_128	(2 << 0)
+#define DA9055_AIF_BCLKS_PER_WCLK_256	(3 << 0)
+#define DA9055_AIF_CLK_EN_SLAVE_MODE	(0 << 7)
+#define DA9055_AIF_CLK_EN_MASTER_MODE	(1 << 7)
+
+/* AIF_CTRL bit fields */
+#define DA9055_AIF_FORMAT_I2S_MODE	(0 << 0)
+#define DA9055_AIF_FORMAT_LEFT_J	(1 << 0)
+#define DA9055_AIF_FORMAT_RIGHT_J	(2 << 0)
+#define DA9055_AIF_FORMAT_DSP		(3 << 0)
+#define DA9055_AIF_WORD_S16_LE		(0 << 2)
+#define DA9055_AIF_WORD_S20_3LE		(1 << 2)
+#define DA9055_AIF_WORD_S24_LE		(2 << 2)
+#define DA9055_AIF_WORD_S32_LE		(3 << 2)
+
+/* MIC_L_CTRL bit fields */
+#define DA9055_MIC_L_MUTE_EN		(1 << 6)
+
+/* MIC_R_CTRL bit fields */
+#define DA9055_MIC_R_MUTE_EN		(1 << 6)
+
+/* MIXIN_L_CTRL bit fields */
+#define DA9055_MIXIN_L_MIX_EN		(1 << 3)
+
+/* MIXIN_R_CTRL bit fields */
+#define DA9055_MIXIN_R_MIX_EN		(1 << 3)
+
+/* ADC_L_CTRL bit fields */
+#define DA9055_ADC_L_EN			(1 << 7)
+
+/* ADC_R_CTRL bit fields */
+#define DA9055_ADC_R_EN			(1 << 7)
+
+/* DAC_L_CTRL bit fields */
+#define DA9055_DAC_L_MUTE_EN		(1 << 6)
+
+/* DAC_R_CTRL bit fields */
+#define DA9055_DAC_R_MUTE_EN		(1 << 6)
+
+/* HP_L_CTRL bit fields */
+#define DA9055_HP_L_AMP_OE		(1 << 3)
+
+/* HP_R_CTRL bit fields */
+#define DA9055_HP_R_AMP_OE		(1 << 3)
+
+/* LINE_CTRL bit fields */
+#define DA9055_LINE_AMP_OE		(1 << 3)
+
+/* MIXOUT_L_CTRL bit fields */
+#define DA9055_MIXOUT_L_MIX_EN		(1 << 3)
+
+/* MIXOUT_R_CTRL bit fields */
+#define DA9055_MIXOUT_R_MIX_EN		(1 << 3)
+
+/* MIC bias select bit fields */
+#define DA9055_MICBIAS2_EN		(1 << 6)
+
+/* ALC_CIC_OP_LEVEL_CTRL bit fields */
+#define DA9055_ALC_DATA_MIDDLE		(2 << 0)
+#define DA9055_ALC_DATA_TOP		(3 << 0)
+#define DA9055_ALC_CIC_OP_CHANNEL_LEFT	(0 << 7)
+#define DA9055_ALC_CIC_OP_CHANNEL_RIGHT	(1 << 7)
+
+#define DA9055_AIF_BCLK_MASK		(3 << 0)
+#define DA9055_AIF_CLK_MODE_MASK	(1 << 7)
+#define DA9055_AIF_FORMAT_MASK		(3 << 0)
+#define DA9055_AIF_WORD_LENGTH_MASK	(3 << 2)
+#define DA9055_GAIN_RAMPING_EN		(1 << 5)
+#define DA9055_MICBIAS_LEVEL_MASK	(3 << 4)
+
+#define DA9055_ALC_OFFSET_15_8		0x00FF00
+#define DA9055_ALC_OFFSET_17_16		0x030000
+#define DA9055_ALC_AVG_ITERATIONS	5
+
+struct pll_div {
+	int fref;
+	int fout;
+	u8 frac_top;
+	u8 frac_bot;
+	u8 integer;
+	u8 mode;	/* 0 = slave, 1 = master */
+};
+
+/* PLL divisor table */
+static const struct pll_div da9055_pll_div[] = {
+	/* for MASTER mode, fs = 44.1Khz and its harmonics */
+	{11289600, 2822400, 0x00, 0x00, 0x20, 1},	/* MCLK=11.2896Mhz */
+	{12000000, 2822400, 0x03, 0x61, 0x1E, 1},	/* MCLK=12Mhz */
+	{12288000, 2822400, 0x0C, 0xCC, 0x1D, 1},	/* MCLK=12.288Mhz */
+	{13000000, 2822400, 0x19, 0x45, 0x1B, 1},	/* MCLK=13Mhz */
+	{13500000, 2822400, 0x18, 0x56, 0x1A, 1},	/* MCLK=13.5Mhz */
+	{14400000, 2822400, 0x02, 0xD0, 0x19, 1},	/* MCLK=14.4Mhz */
+	{19200000, 2822400, 0x1A, 0x1C, 0x12, 1},	/* MCLK=19.2Mhz */
+	{19680000, 2822400, 0x0B, 0x6D, 0x12, 1},	/* MCLK=19.68Mhz */
+	{19800000, 2822400, 0x07, 0xDD, 0x12, 1},	/* MCLK=19.8Mhz */
+	/* for MASTER mode, fs = 48Khz and its harmonics */
+	{11289600, 3072000, 0x1A, 0x8E, 0x22, 1},	/* MCLK=11.2896Mhz */
+	{12000000, 3072000, 0x18, 0x93, 0x20, 1},	/* MCLK=12Mhz */
+	{12288000, 3072000, 0x00, 0x00, 0x20, 1},	/* MCLK=12.288Mhz */
+	{13000000, 3072000, 0x07, 0xEA, 0x1E, 1},	/* MCLK=13Mhz */
+	{13500000, 3072000, 0x04, 0x11, 0x1D, 1},	/* MCLK=13.5Mhz */
+	{14400000, 3072000, 0x09, 0xD0, 0x1B, 1},	/* MCLK=14.4Mhz */
+	{19200000, 3072000, 0x0F, 0x5C, 0x14, 1},	/* MCLK=19.2Mhz */
+	{19680000, 3072000, 0x1F, 0x60, 0x13, 1},	/* MCLK=19.68Mhz */
+	{19800000, 3072000, 0x1B, 0x80, 0x13, 1},	/* MCLK=19.8Mhz */
+	/* for SLAVE mode with SRM */
+	{11289600, 2822400, 0x0D, 0x47, 0x21, 0},	/* MCLK=11.2896Mhz */
+	{12000000, 2822400, 0x0D, 0xFA, 0x1F, 0},	/* MCLK=12Mhz */
+	{12288000, 2822400, 0x16, 0x66, 0x1E, 0},	/* MCLK=12.288Mhz */
+	{13000000, 2822400, 0x00, 0x98, 0x1D, 0},	/* MCLK=13Mhz */
+	{13500000, 2822400, 0x1E, 0x33, 0x1B, 0},	/* MCLK=13.5Mhz */
+	{14400000, 2822400, 0x06, 0x50, 0x1A, 0},	/* MCLK=14.4Mhz */
+	{19200000, 2822400, 0x14, 0xBC, 0x13, 0},	/* MCLK=19.2Mhz */
+	{19680000, 2822400, 0x05, 0x66, 0x13, 0},	/* MCLK=19.68Mhz */
+	{19800000, 2822400, 0x01, 0xAE, 0x13, 0},	/* MCLK=19.8Mhz  */
+};
+
+enum clk_src {
+	DA9055_CLKSRC_MCLK
+};
+
+/* Gain and Volume */
+
+static const DECLARE_TLV_DB_RANGE(aux_vol_tlv,
+	0x0, 0x10, TLV_DB_SCALE_ITEM(-5400, 0, 0),
+	/* -54dB to 15dB */
+	0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(digital_gain_tlv,
+	0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+	/* -78dB to 12dB */
+	0x08, 0x7f, TLV_DB_SCALE_ITEM(-7800, 75, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(alc_analog_gain_tlv,
+	0x0, 0x0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+	/* 0dB to 36dB */
+	0x01, 0x07, TLV_DB_SCALE_ITEM(0, 600, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(mixin_gain_tlv, -450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lineout_vol_tlv, -4800, 100, 0);
+static const DECLARE_TLV_DB_SCALE(alc_threshold_tlv, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(alc_gain_tlv, 0, 600, 0);
+
+/* ADC and DAC high pass filter cutoff value */
+static const char * const da9055_hpf_cutoff_txt[] = {
+	"Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000"
+};
+
+static SOC_ENUM_SINGLE_DECL(da9055_dac_hpf_cutoff,
+			    DA9055_DAC_FILTERS1, 4, da9055_hpf_cutoff_txt);
+
+static SOC_ENUM_SINGLE_DECL(da9055_adc_hpf_cutoff,
+			    DA9055_ADC_FILTERS1, 4, da9055_hpf_cutoff_txt);
+
+/* ADC and DAC voice mode (8kHz) high pass cutoff value */
+static const char * const da9055_vf_cutoff_txt[] = {
+	"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(da9055_dac_vf_cutoff,
+			    DA9055_DAC_FILTERS1, 0, da9055_vf_cutoff_txt);
+
+static SOC_ENUM_SINGLE_DECL(da9055_adc_vf_cutoff,
+			    DA9055_ADC_FILTERS1, 0, da9055_vf_cutoff_txt);
+
+/* Gain ramping rate value */
+static const char * const da9055_gain_ramping_txt[] = {
+	"nominal rate", "nominal rate * 4", "nominal rate * 8",
+	"nominal rate / 8"
+};
+
+static SOC_ENUM_SINGLE_DECL(da9055_gain_ramping_rate,
+			    DA9055_GAIN_RAMP_CTRL, 0, da9055_gain_ramping_txt);
+
+/* DAC noise gate setup time value */
+static const char * const da9055_dac_ng_setup_time_txt[] = {
+	"256 samples", "512 samples", "1024 samples", "2048 samples"
+};
+
+static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_setup_time,
+			    DA9055_DAC_NG_SETUP_TIME, 0,
+			    da9055_dac_ng_setup_time_txt);
+
+/* DAC noise gate rampup rate value */
+static const char * const da9055_dac_ng_rampup_txt[] = {
+	"0.02 ms/dB", "0.16 ms/dB"
+};
+
+static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampup_rate,
+			    DA9055_DAC_NG_SETUP_TIME, 2,
+			    da9055_dac_ng_rampup_txt);
+
+/* DAC noise gate rampdown rate value */
+static const char * const da9055_dac_ng_rampdown_txt[] = {
+	"0.64 ms/dB", "20.48 ms/dB"
+};
+
+static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampdown_rate,
+			    DA9055_DAC_NG_SETUP_TIME, 3,
+			    da9055_dac_ng_rampdown_txt);
+
+/* DAC soft mute rate value */
+static const char * const da9055_dac_soft_mute_rate_txt[] = {
+	"1", "2", "4", "8", "16", "32", "64"
+};
+
+static SOC_ENUM_SINGLE_DECL(da9055_dac_soft_mute_rate,
+			    DA9055_DAC_FILTERS5, 4,
+			    da9055_dac_soft_mute_rate_txt);
+
+/* DAC routing select */
+static const char * const da9055_dac_src_txt[] = {
+	"ADC output left", "ADC output right", "AIF input left",
+	"AIF input right"
+};
+
+static SOC_ENUM_SINGLE_DECL(da9055_dac_l_src,
+			    DA9055_DIG_ROUTING_DAC, 0, da9055_dac_src_txt);
+
+static SOC_ENUM_SINGLE_DECL(da9055_dac_r_src,
+			    DA9055_DIG_ROUTING_DAC, 4, da9055_dac_src_txt);
+
+/* MIC PGA Left source select */
+static const char * const da9055_mic_l_src_txt[] = {
+	"MIC1_P_N", "MIC1_P", "MIC1_N", "MIC2_L"
+};
+
+static SOC_ENUM_SINGLE_DECL(da9055_mic_l_src,
+			    DA9055_MIXIN_L_SELECT, 4, da9055_mic_l_src_txt);
+
+/* MIC PGA Right source select */
+static const char * const da9055_mic_r_src_txt[] = {
+	"MIC2_R_L", "MIC2_R", "MIC2_L"
+};
+
+static SOC_ENUM_SINGLE_DECL(da9055_mic_r_src,
+			    DA9055_MIXIN_R_SELECT, 4, da9055_mic_r_src_txt);
+
+/* ALC Input Signal Tracking rate select */
+static const char * const da9055_signal_tracking_rate_txt[] = {
+	"1/4", "1/16", "1/256", "1/65536"
+};
+
+static SOC_ENUM_SINGLE_DECL(da9055_integ_attack_rate,
+			    DA9055_ALC_CTRL3, 4,
+			    da9055_signal_tracking_rate_txt);
+
+static SOC_ENUM_SINGLE_DECL(da9055_integ_release_rate,
+			    DA9055_ALC_CTRL3, 6,
+			    da9055_signal_tracking_rate_txt);
+
+/* ALC Attack Rate select */
+static const char * const da9055_attack_rate_txt[] = {
+	"44/fs", "88/fs", "176/fs", "352/fs", "704/fs", "1408/fs", "2816/fs",
+	"5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
+};
+
+static SOC_ENUM_SINGLE_DECL(da9055_attack_rate,
+			    DA9055_ALC_CTRL2, 0, da9055_attack_rate_txt);
+
+/* ALC Release Rate select */
+static const char * const da9055_release_rate_txt[] = {
+	"176/fs", "352/fs", "704/fs", "1408/fs", "2816/fs", "5632/fs",
+	"11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
+};
+
+static SOC_ENUM_SINGLE_DECL(da9055_release_rate,
+			    DA9055_ALC_CTRL2, 4, da9055_release_rate_txt);
+
+/* ALC Hold Time select */
+static const char * const da9055_hold_time_txt[] = {
+	"62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs",
+	"7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs",
+	"253952/fs", "507904/fs", "1015808/fs", "2031616/fs"
+};
+
+static SOC_ENUM_SINGLE_DECL(da9055_hold_time,
+			    DA9055_ALC_CTRL3, 0, da9055_hold_time_txt);
+
+static int da9055_get_alc_data(struct snd_soc_component *component, u8 reg_val)
+{
+	int mid_data, top_data;
+	int sum = 0;
+	u8 iteration;
+
+	for (iteration = 0; iteration < DA9055_ALC_AVG_ITERATIONS;
+	     iteration++) {
+		/* Select the left or right channel and capture data */
+		snd_soc_component_write(component, DA9055_ALC_CIC_OP_LVL_CTRL, reg_val);
+
+		/* Select middle 8 bits for read back from data register */
+		snd_soc_component_write(component, DA9055_ALC_CIC_OP_LVL_CTRL,
+			      reg_val | DA9055_ALC_DATA_MIDDLE);
+		mid_data = snd_soc_component_read32(component, DA9055_ALC_CIC_OP_LVL_DATA);
+
+		/* Select top 8 bits for read back from data register */
+		snd_soc_component_write(component, DA9055_ALC_CIC_OP_LVL_CTRL,
+			      reg_val | DA9055_ALC_DATA_TOP);
+		top_data = snd_soc_component_read32(component, DA9055_ALC_CIC_OP_LVL_DATA);
+
+		sum += ((mid_data << 8) | (top_data << 16));
+	}
+
+	return sum / DA9055_ALC_AVG_ITERATIONS;
+}
+
+static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	u8 reg_val, adc_left, adc_right, mic_left, mic_right;
+	int avg_left_data, avg_right_data, offset_l, offset_r;
+
+	if (ucontrol->value.integer.value[0]) {
+		/*
+		 * While enabling ALC (or ALC sync mode), calibration of the DC
+		 * offsets must be done first
+		 */
+
+		/* Save current values from Mic control registers */
+		mic_left = snd_soc_component_read32(component, DA9055_MIC_L_CTRL);
+		mic_right = snd_soc_component_read32(component, DA9055_MIC_R_CTRL);
+
+		/* Mute Mic PGA Left and Right */
+		snd_soc_component_update_bits(component, DA9055_MIC_L_CTRL,
+				    DA9055_MIC_L_MUTE_EN, DA9055_MIC_L_MUTE_EN);
+		snd_soc_component_update_bits(component, DA9055_MIC_R_CTRL,
+				    DA9055_MIC_R_MUTE_EN, DA9055_MIC_R_MUTE_EN);
+
+		/* Save current values from ADC control registers */
+		adc_left = snd_soc_component_read32(component, DA9055_ADC_L_CTRL);
+		adc_right = snd_soc_component_read32(component, DA9055_ADC_R_CTRL);
+
+		/* Enable ADC Left and Right */
+		snd_soc_component_update_bits(component, DA9055_ADC_L_CTRL,
+				    DA9055_ADC_L_EN, DA9055_ADC_L_EN);
+		snd_soc_component_update_bits(component, DA9055_ADC_R_CTRL,
+				    DA9055_ADC_R_EN, DA9055_ADC_R_EN);
+
+		/* Calculate average for Left and Right data */
+		/* Left Data */
+		avg_left_data = da9055_get_alc_data(component,
+				DA9055_ALC_CIC_OP_CHANNEL_LEFT);
+		/* Right Data */
+		avg_right_data = da9055_get_alc_data(component,
+				 DA9055_ALC_CIC_OP_CHANNEL_RIGHT);
+
+		/* Calculate DC offset */
+		offset_l = -avg_left_data;
+		offset_r = -avg_right_data;
+
+		reg_val = (offset_l & DA9055_ALC_OFFSET_15_8) >> 8;
+		snd_soc_component_write(component, DA9055_ALC_OFFSET_OP2M_L, reg_val);
+		reg_val = (offset_l & DA9055_ALC_OFFSET_17_16) >> 16;
+		snd_soc_component_write(component, DA9055_ALC_OFFSET_OP2U_L, reg_val);
+
+		reg_val = (offset_r & DA9055_ALC_OFFSET_15_8) >> 8;
+		snd_soc_component_write(component, DA9055_ALC_OFFSET_OP2M_R, reg_val);
+		reg_val = (offset_r & DA9055_ALC_OFFSET_17_16) >> 16;
+		snd_soc_component_write(component, DA9055_ALC_OFFSET_OP2U_R, reg_val);
+
+		/* Restore original values of ADC control registers */
+		snd_soc_component_write(component, DA9055_ADC_L_CTRL, adc_left);
+		snd_soc_component_write(component, DA9055_ADC_R_CTRL, adc_right);
+
+		/* Restore original values of Mic control registers */
+		snd_soc_component_write(component, DA9055_MIC_L_CTRL, mic_left);
+		snd_soc_component_write(component, DA9055_MIC_R_CTRL, mic_right);
+	}
+
+	return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+static const struct snd_kcontrol_new da9055_snd_controls[] = {
+
+	/* Volume controls */
+	SOC_DOUBLE_R_TLV("Mic Volume",
+			 DA9055_MIC_L_GAIN, DA9055_MIC_R_GAIN,
+			 0, 0x7, 0, mic_vol_tlv),
+	SOC_DOUBLE_R_TLV("Aux Volume",
+			 DA9055_AUX_L_GAIN, DA9055_AUX_R_GAIN,
+			 0, 0x3f, 0, aux_vol_tlv),
+	SOC_DOUBLE_R_TLV("Mixin PGA Volume",
+			 DA9055_MIXIN_L_GAIN, DA9055_MIXIN_R_GAIN,
+			 0, 0xf, 0, mixin_gain_tlv),
+	SOC_DOUBLE_R_TLV("ADC Volume",
+			 DA9055_ADC_L_GAIN, DA9055_ADC_R_GAIN,
+			 0, 0x7f, 0, digital_gain_tlv),
+
+	SOC_DOUBLE_R_TLV("DAC Volume",
+			 DA9055_DAC_L_GAIN, DA9055_DAC_R_GAIN,
+			 0, 0x7f, 0, digital_gain_tlv),
+	SOC_DOUBLE_R_TLV("Headphone Volume",
+			 DA9055_HP_L_GAIN, DA9055_HP_R_GAIN,
+			 0, 0x3f, 0, hp_vol_tlv),
+	SOC_SINGLE_TLV("Lineout Volume", DA9055_LINE_GAIN, 0, 0x3f, 0,
+		       lineout_vol_tlv),
+
+	/* DAC Equalizer controls */
+	SOC_SINGLE("DAC EQ Switch", DA9055_DAC_FILTERS4, 7, 1, 0),
+	SOC_SINGLE_TLV("DAC EQ1 Volume", DA9055_DAC_FILTERS2, 0, 0xf, 0,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ2 Volume", DA9055_DAC_FILTERS2, 4, 0xf, 0,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ3 Volume", DA9055_DAC_FILTERS3, 0, 0xf, 0,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ4 Volume", DA9055_DAC_FILTERS3, 4, 0xf, 0,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ5 Volume", DA9055_DAC_FILTERS4, 0, 0xf, 0,
+		       eq_gain_tlv),
+
+	/* High Pass Filter and Voice Mode controls */
+	SOC_SINGLE("ADC HPF Switch", DA9055_ADC_FILTERS1, 7, 1, 0),
+	SOC_ENUM("ADC HPF Cutoff", da9055_adc_hpf_cutoff),
+	SOC_SINGLE("ADC Voice Mode Switch", DA9055_ADC_FILTERS1, 3, 1, 0),
+	SOC_ENUM("ADC Voice Cutoff", da9055_adc_vf_cutoff),
+
+	SOC_SINGLE("DAC HPF Switch", DA9055_DAC_FILTERS1, 7, 1, 0),
+	SOC_ENUM("DAC HPF Cutoff", da9055_dac_hpf_cutoff),
+	SOC_SINGLE("DAC Voice Mode Switch", DA9055_DAC_FILTERS1, 3, 1, 0),
+	SOC_ENUM("DAC Voice Cutoff", da9055_dac_vf_cutoff),
+
+	/* Mute controls */
+	SOC_DOUBLE_R("Mic Switch", DA9055_MIC_L_CTRL,
+		     DA9055_MIC_R_CTRL, 6, 1, 0),
+	SOC_DOUBLE_R("Aux Switch", DA9055_AUX_L_CTRL,
+		     DA9055_AUX_R_CTRL, 6, 1, 0),
+	SOC_DOUBLE_R("Mixin PGA Switch", DA9055_MIXIN_L_CTRL,
+		     DA9055_MIXIN_R_CTRL, 6, 1, 0),
+	SOC_DOUBLE_R("ADC Switch", DA9055_ADC_L_CTRL,
+		     DA9055_ADC_R_CTRL, 6, 1, 0),
+	SOC_DOUBLE_R("Headphone Switch", DA9055_HP_L_CTRL,
+		     DA9055_HP_R_CTRL, 6, 1, 0),
+	SOC_SINGLE("Lineout Switch", DA9055_LINE_CTRL, 6, 1, 0),
+	SOC_SINGLE("DAC Soft Mute Switch", DA9055_DAC_FILTERS5, 7, 1, 0),
+	SOC_ENUM("DAC Soft Mute Rate", da9055_dac_soft_mute_rate),
+
+	/* Zero Cross controls */
+	SOC_DOUBLE_R("Aux ZC Switch", DA9055_AUX_L_CTRL,
+		     DA9055_AUX_R_CTRL, 4, 1, 0),
+	SOC_DOUBLE_R("Mixin PGA ZC Switch", DA9055_MIXIN_L_CTRL,
+		     DA9055_MIXIN_R_CTRL, 4, 1, 0),
+	SOC_DOUBLE_R("Headphone ZC Switch", DA9055_HP_L_CTRL,
+		     DA9055_HP_R_CTRL, 4, 1, 0),
+	SOC_SINGLE("Lineout ZC Switch", DA9055_LINE_CTRL, 4, 1, 0),
+
+	/* Gain Ramping controls */
+	SOC_DOUBLE_R("Aux Gain Ramping Switch", DA9055_AUX_L_CTRL,
+		     DA9055_AUX_R_CTRL, 5, 1, 0),
+	SOC_DOUBLE_R("Mixin Gain Ramping Switch", DA9055_MIXIN_L_CTRL,
+		     DA9055_MIXIN_R_CTRL, 5, 1, 0),
+	SOC_DOUBLE_R("ADC Gain Ramping Switch", DA9055_ADC_L_CTRL,
+		     DA9055_ADC_R_CTRL, 5, 1, 0),
+	SOC_DOUBLE_R("DAC Gain Ramping Switch", DA9055_DAC_L_CTRL,
+		     DA9055_DAC_R_CTRL, 5, 1, 0),
+	SOC_DOUBLE_R("Headphone Gain Ramping Switch", DA9055_HP_L_CTRL,
+		     DA9055_HP_R_CTRL, 5, 1, 0),
+	SOC_SINGLE("Lineout Gain Ramping Switch", DA9055_LINE_CTRL, 5, 1, 0),
+	SOC_ENUM("Gain Ramping Rate", da9055_gain_ramping_rate),
+
+	/* DAC Noise Gate controls */
+	SOC_SINGLE("DAC NG Switch", DA9055_DAC_NG_CTRL, 7, 1, 0),
+	SOC_SINGLE("DAC NG ON Threshold", DA9055_DAC_NG_ON_THRESHOLD,
+		   0, 0x7, 0),
+	SOC_SINGLE("DAC NG OFF Threshold", DA9055_DAC_NG_OFF_THRESHOLD,
+		   0, 0x7, 0),
+	SOC_ENUM("DAC NG Setup Time", da9055_dac_ng_setup_time),
+	SOC_ENUM("DAC NG Rampup Rate", da9055_dac_ng_rampup_rate),
+	SOC_ENUM("DAC NG Rampdown Rate", da9055_dac_ng_rampdown_rate),
+
+	/* DAC Invertion control */
+	SOC_SINGLE("DAC Left Invert", DA9055_DIG_CTRL, 3, 1, 0),
+	SOC_SINGLE("DAC Right Invert", DA9055_DIG_CTRL, 7, 1, 0),
+
+	/* DMIC controls */
+	SOC_DOUBLE_R("DMIC Switch", DA9055_MIXIN_L_SELECT,
+		     DA9055_MIXIN_R_SELECT, 7, 1, 0),
+
+	/* ALC Controls */
+	SOC_DOUBLE_EXT("ALC Switch", DA9055_ALC_CTRL1, 3, 7, 1, 0,
+		       snd_soc_get_volsw, da9055_put_alc_sw),
+	SOC_SINGLE_EXT("ALC Sync Mode Switch", DA9055_ALC_CTRL1, 1, 1, 0,
+		       snd_soc_get_volsw, da9055_put_alc_sw),
+	SOC_SINGLE("ALC Offset Switch", DA9055_ALC_CTRL1, 0, 1, 0),
+	SOC_SINGLE("ALC Anticlip Mode Switch", DA9055_ALC_ANTICLIP_CTRL,
+		   7, 1, 0),
+	SOC_SINGLE("ALC Anticlip Level", DA9055_ALC_ANTICLIP_LEVEL,
+		   0, 0x7f, 0),
+	SOC_SINGLE_TLV("ALC Min Threshold Volume", DA9055_ALC_TARGET_MIN,
+		       0, 0x3f, 1, alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Max Threshold Volume", DA9055_ALC_TARGET_MAX,
+		       0, 0x3f, 1, alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Noise Threshold Volume", DA9055_ALC_NOISE,
+		       0, 0x3f, 1, alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Max Gain Volume", DA9055_ALC_GAIN_LIMITS,
+		       4, 0xf, 0, alc_gain_tlv),
+	SOC_SINGLE_TLV("ALC Max Attenuation Volume", DA9055_ALC_GAIN_LIMITS,
+		       0, 0xf, 0, alc_gain_tlv),
+	SOC_SINGLE_TLV("ALC Min Analog Gain Volume",
+		       DA9055_ALC_ANA_GAIN_LIMITS,
+		       0, 0x7, 0, alc_analog_gain_tlv),
+	SOC_SINGLE_TLV("ALC Max Analog Gain Volume",
+		       DA9055_ALC_ANA_GAIN_LIMITS,
+		       4, 0x7, 0, alc_analog_gain_tlv),
+	SOC_ENUM("ALC Attack Rate", da9055_attack_rate),
+	SOC_ENUM("ALC Release Rate", da9055_release_rate),
+	SOC_ENUM("ALC Hold Time", da9055_hold_time),
+	/*
+	 * Rate at which input signal envelope is tracked as the signal gets
+	 * larger
+	 */
+	SOC_ENUM("ALC Integ Attack Rate", da9055_integ_attack_rate),
+	/*
+	 * Rate at which input signal envelope is tracked as the signal gets
+	 * smaller
+	 */
+	SOC_ENUM("ALC Integ Release Rate", da9055_integ_release_rate),
+};
+
+/* DAPM Controls */
+
+/* Mic PGA Left Source */
+static const struct snd_kcontrol_new da9055_mic_l_mux_controls =
+SOC_DAPM_ENUM("Route", da9055_mic_l_src);
+
+/* Mic PGA Right Source */
+static const struct snd_kcontrol_new da9055_mic_r_mux_controls =
+SOC_DAPM_ENUM("Route", da9055_mic_r_src);
+
+/* In Mixer Left */
+static const struct snd_kcontrol_new da9055_dapm_mixinl_controls[] = {
+	SOC_DAPM_SINGLE("Aux Left Switch", DA9055_MIXIN_L_SELECT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Mic Left Switch", DA9055_MIXIN_L_SELECT, 1, 1, 0),
+	SOC_DAPM_SINGLE("Mic Right Switch", DA9055_MIXIN_L_SELECT, 2, 1, 0),
+};
+
+/* In Mixer Right */
+static const struct snd_kcontrol_new da9055_dapm_mixinr_controls[] = {
+	SOC_DAPM_SINGLE("Aux Right Switch", DA9055_MIXIN_R_SELECT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Mic Right Switch", DA9055_MIXIN_R_SELECT, 1, 1, 0),
+	SOC_DAPM_SINGLE("Mic Left Switch", DA9055_MIXIN_R_SELECT, 2, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Left Switch", DA9055_MIXIN_R_SELECT, 3, 1, 0),
+};
+
+/* DAC Left Source */
+static const struct snd_kcontrol_new da9055_dac_l_mux_controls =
+SOC_DAPM_ENUM("Route", da9055_dac_l_src);
+
+/* DAC Right Source */
+static const struct snd_kcontrol_new da9055_dac_r_mux_controls =
+SOC_DAPM_ENUM("Route", da9055_dac_r_src);
+
+/* Out Mixer Left */
+static const struct snd_kcontrol_new da9055_dapm_mixoutl_controls[] = {
+	SOC_DAPM_SINGLE("Aux Left Switch", DA9055_MIXOUT_L_SELECT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Left Switch", DA9055_MIXOUT_L_SELECT, 1, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Right Switch", DA9055_MIXOUT_L_SELECT, 2, 1, 0),
+	SOC_DAPM_SINGLE("DAC Left Switch", DA9055_MIXOUT_L_SELECT, 3, 1, 0),
+	SOC_DAPM_SINGLE("Aux Left Invert Switch", DA9055_MIXOUT_L_SELECT,
+			4, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Left Invert Switch", DA9055_MIXOUT_L_SELECT,
+			5, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Right Invert Switch", DA9055_MIXOUT_L_SELECT,
+			6, 1, 0),
+};
+
+/* Out Mixer Right */
+static const struct snd_kcontrol_new da9055_dapm_mixoutr_controls[] = {
+	SOC_DAPM_SINGLE("Aux Right Switch", DA9055_MIXOUT_R_SELECT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Right Switch", DA9055_MIXOUT_R_SELECT, 1, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Left Switch", DA9055_MIXOUT_R_SELECT, 2, 1, 0),
+	SOC_DAPM_SINGLE("DAC Right Switch", DA9055_MIXOUT_R_SELECT, 3, 1, 0),
+	SOC_DAPM_SINGLE("Aux Right Invert Switch", DA9055_MIXOUT_R_SELECT,
+			4, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Right Invert Switch", DA9055_MIXOUT_R_SELECT,
+			5, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Left Invert Switch", DA9055_MIXOUT_R_SELECT,
+			6, 1, 0),
+};
+
+/* Headphone Output Enable */
+static const struct snd_kcontrol_new da9055_dapm_hp_l_control =
+SOC_DAPM_SINGLE("Switch", DA9055_HP_L_CTRL, 3, 1, 0);
+
+static const struct snd_kcontrol_new da9055_dapm_hp_r_control =
+SOC_DAPM_SINGLE("Switch", DA9055_HP_R_CTRL, 3, 1, 0);
+
+/* Lineout Output Enable */
+static const struct snd_kcontrol_new da9055_dapm_lineout_control =
+SOC_DAPM_SINGLE("Switch", DA9055_LINE_CTRL, 3, 1, 0);
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget da9055_dapm_widgets[] = {
+	/* Input Side */
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("AUXL"),
+	SND_SOC_DAPM_INPUT("AUXR"),
+
+	/* MUXs for Mic PGA source selection */
+	SND_SOC_DAPM_MUX("Mic Left Source", SND_SOC_NOPM, 0, 0,
+			 &da9055_mic_l_mux_controls),
+	SND_SOC_DAPM_MUX("Mic Right Source", SND_SOC_NOPM, 0, 0,
+			 &da9055_mic_r_mux_controls),
+
+	/* Input PGAs */
+	SND_SOC_DAPM_PGA("Mic Left", DA9055_MIC_L_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mic Right", DA9055_MIC_R_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Aux Left", DA9055_AUX_L_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Aux Right", DA9055_AUX_R_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MIXIN Left", DA9055_MIXIN_L_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MIXIN Right", DA9055_MIXIN_R_CTRL, 7, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Mic Bias", DA9055_MIC_BIAS_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AIF", DA9055_AIF_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Charge Pump", DA9055_CP_CTRL, 7, 0, NULL, 0),
+
+	/* Input Mixers */
+	SND_SOC_DAPM_MIXER("In Mixer Left", SND_SOC_NOPM, 0, 0,
+			   &da9055_dapm_mixinl_controls[0],
+			   ARRAY_SIZE(da9055_dapm_mixinl_controls)),
+	SND_SOC_DAPM_MIXER("In Mixer Right", SND_SOC_NOPM, 0, 0,
+			   &da9055_dapm_mixinr_controls[0],
+			   ARRAY_SIZE(da9055_dapm_mixinr_controls)),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC Left", "Capture", DA9055_ADC_L_CTRL, 7, 0),
+	SND_SOC_DAPM_ADC("ADC Right", "Capture", DA9055_ADC_R_CTRL, 7, 0),
+
+	/* Output Side */
+
+	/* MUXs for DAC source selection */
+	SND_SOC_DAPM_MUX("DAC Left Source", SND_SOC_NOPM, 0, 0,
+			 &da9055_dac_l_mux_controls),
+	SND_SOC_DAPM_MUX("DAC Right Source", SND_SOC_NOPM, 0, 0,
+			 &da9055_dac_r_mux_controls),
+
+	/* AIF input */
+	SND_SOC_DAPM_AIF_IN("AIFIN Left", "Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIFIN Right", "Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC Left", "Playback", DA9055_DAC_L_CTRL, 7, 0),
+	SND_SOC_DAPM_DAC("DAC Right", "Playback", DA9055_DAC_R_CTRL, 7, 0),
+
+	/* Output Mixers */
+	SND_SOC_DAPM_MIXER("Out Mixer Left", SND_SOC_NOPM, 0, 0,
+			   &da9055_dapm_mixoutl_controls[0],
+			   ARRAY_SIZE(da9055_dapm_mixoutl_controls)),
+	SND_SOC_DAPM_MIXER("Out Mixer Right", SND_SOC_NOPM, 0, 0,
+			   &da9055_dapm_mixoutr_controls[0],
+			   ARRAY_SIZE(da9055_dapm_mixoutr_controls)),
+
+	/* Output Enable Switches */
+	SND_SOC_DAPM_SWITCH("Headphone Left Enable", SND_SOC_NOPM, 0, 0,
+			    &da9055_dapm_hp_l_control),
+	SND_SOC_DAPM_SWITCH("Headphone Right Enable", SND_SOC_NOPM, 0, 0,
+			    &da9055_dapm_hp_r_control),
+	SND_SOC_DAPM_SWITCH("Lineout Enable", SND_SOC_NOPM, 0, 0,
+			    &da9055_dapm_lineout_control),
+
+	/* Output PGAs */
+	SND_SOC_DAPM_PGA("MIXOUT Left", DA9055_MIXOUT_L_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MIXOUT Right", DA9055_MIXOUT_R_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Lineout", DA9055_LINE_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Headphone Left", DA9055_HP_L_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Headphone Right", DA9055_HP_R_CTRL, 7, 0, NULL, 0),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("LINE"),
+};
+
+/* DAPM audio route definition */
+static const struct snd_soc_dapm_route da9055_audio_map[] = {
+	/* Dest       Connecting Widget    source */
+
+	/* Input path */
+	{"Mic Left Source", "MIC1_P_N", "MIC1"},
+	{"Mic Left Source", "MIC1_P", "MIC1"},
+	{"Mic Left Source", "MIC1_N", "MIC1"},
+	{"Mic Left Source", "MIC2_L", "MIC2"},
+
+	{"Mic Right Source", "MIC2_R_L", "MIC2"},
+	{"Mic Right Source", "MIC2_R", "MIC2"},
+	{"Mic Right Source", "MIC2_L", "MIC2"},
+
+	{"Mic Left", NULL, "Mic Left Source"},
+	{"Mic Right", NULL, "Mic Right Source"},
+
+	{"Aux Left", NULL, "AUXL"},
+	{"Aux Right", NULL, "AUXR"},
+
+	{"In Mixer Left", "Mic Left Switch", "Mic Left"},
+	{"In Mixer Left", "Mic Right Switch", "Mic Right"},
+	{"In Mixer Left", "Aux Left Switch", "Aux Left"},
+
+	{"In Mixer Right", "Mic Right Switch", "Mic Right"},
+	{"In Mixer Right", "Mic Left Switch", "Mic Left"},
+	{"In Mixer Right", "Aux Right Switch", "Aux Right"},
+	{"In Mixer Right", "Mixin Left Switch", "MIXIN Left"},
+
+	{"MIXIN Left", NULL, "In Mixer Left"},
+	{"ADC Left", NULL, "MIXIN Left"},
+
+	{"MIXIN Right", NULL, "In Mixer Right"},
+	{"ADC Right", NULL, "MIXIN Right"},
+
+	{"ADC Left", NULL, "AIF"},
+	{"ADC Right", NULL, "AIF"},
+
+	/* Output path */
+	{"AIFIN Left", NULL, "AIF"},
+	{"AIFIN Right", NULL, "AIF"},
+
+	{"DAC Left Source", "ADC output left", "ADC Left"},
+	{"DAC Left Source", "ADC output right", "ADC Right"},
+	{"DAC Left Source", "AIF input left", "AIFIN Left"},
+	{"DAC Left Source", "AIF input right", "AIFIN Right"},
+
+	{"DAC Right Source", "ADC output left", "ADC Left"},
+	{"DAC Right Source", "ADC output right", "ADC Right"},
+	{"DAC Right Source", "AIF input left", "AIFIN Left"},
+	{"DAC Right Source", "AIF input right", "AIFIN Right"},
+
+	{"DAC Left", NULL, "DAC Left Source"},
+	{"DAC Right", NULL, "DAC Right Source"},
+
+	{"Out Mixer Left", "Aux Left Switch", "Aux Left"},
+	{"Out Mixer Left", "Mixin Left Switch", "MIXIN Left"},
+	{"Out Mixer Left", "Mixin Right Switch", "MIXIN Right"},
+	{"Out Mixer Left", "Aux Left Invert Switch", "Aux Left"},
+	{"Out Mixer Left", "Mixin Left Invert Switch", "MIXIN Left"},
+	{"Out Mixer Left", "Mixin Right Invert Switch", "MIXIN Right"},
+	{"Out Mixer Left", "DAC Left Switch", "DAC Left"},
+
+	{"Out Mixer Right", "Aux Right Switch", "Aux Right"},
+	{"Out Mixer Right", "Mixin Right Switch", "MIXIN Right"},
+	{"Out Mixer Right", "Mixin Left Switch", "MIXIN Left"},
+	{"Out Mixer Right", "Aux Right Invert Switch", "Aux Right"},
+	{"Out Mixer Right", "Mixin Right Invert Switch", "MIXIN Right"},
+	{"Out Mixer Right", "Mixin Left Invert Switch", "MIXIN Left"},
+	{"Out Mixer Right", "DAC Right Switch", "DAC Right"},
+
+	{"MIXOUT Left", NULL, "Out Mixer Left"},
+	{"Headphone Left Enable", "Switch", "MIXOUT Left"},
+	{"Headphone Left", NULL, "Headphone Left Enable"},
+	{"Headphone Left", NULL, "Charge Pump"},
+	{"HPL", NULL, "Headphone Left"},
+
+	{"MIXOUT Right", NULL, "Out Mixer Right"},
+	{"Headphone Right Enable", "Switch", "MIXOUT Right"},
+	{"Headphone Right", NULL, "Headphone Right Enable"},
+	{"Headphone Right", NULL, "Charge Pump"},
+	{"HPR", NULL, "Headphone Right"},
+
+	{"MIXOUT Right", NULL, "Out Mixer Right"},
+	{"Lineout Enable", "Switch", "MIXOUT Right"},
+	{"Lineout", NULL, "Lineout Enable"},
+	{"LINE", NULL, "Lineout"},
+};
+
+/* Codec private data */
+struct da9055_priv {
+	struct regmap *regmap;
+	unsigned int mclk_rate;
+	int master;
+	struct da9055_platform_data *pdata;
+};
+
+static const struct reg_default da9055_reg_defaults[] = {
+	{ 0x21, 0x10 },
+	{ 0x22, 0x0A },
+	{ 0x23, 0x00 },
+	{ 0x24, 0x00 },
+	{ 0x25, 0x00 },
+	{ 0x26, 0x00 },
+	{ 0x27, 0x0C },
+	{ 0x28, 0x01 },
+	{ 0x29, 0x08 },
+	{ 0x2A, 0x32 },
+	{ 0x2B, 0x00 },
+	{ 0x30, 0x35 },
+	{ 0x31, 0x35 },
+	{ 0x32, 0x00 },
+	{ 0x33, 0x00 },
+	{ 0x34, 0x03 },
+	{ 0x35, 0x03 },
+	{ 0x36, 0x6F },
+	{ 0x37, 0x6F },
+	{ 0x38, 0x80 },
+	{ 0x39, 0x01 },
+	{ 0x3A, 0x01 },
+	{ 0x40, 0x00 },
+	{ 0x41, 0x88 },
+	{ 0x42, 0x88 },
+	{ 0x43, 0x08 },
+	{ 0x44, 0x80 },
+	{ 0x45, 0x6F },
+	{ 0x46, 0x6F },
+	{ 0x47, 0x61 },
+	{ 0x48, 0x35 },
+	{ 0x49, 0x35 },
+	{ 0x4A, 0x35 },
+	{ 0x4B, 0x00 },
+	{ 0x4C, 0x00 },
+	{ 0x60, 0x44 },
+	{ 0x61, 0x44 },
+	{ 0x62, 0x00 },
+	{ 0x63, 0x40 },
+	{ 0x64, 0x40 },
+	{ 0x65, 0x40 },
+	{ 0x66, 0x40 },
+	{ 0x67, 0x40 },
+	{ 0x68, 0x40 },
+	{ 0x69, 0x48 },
+	{ 0x6A, 0x40 },
+	{ 0x6B, 0x41 },
+	{ 0x6C, 0x40 },
+	{ 0x6D, 0x40 },
+	{ 0x6E, 0x10 },
+	{ 0x6F, 0x10 },
+	{ 0x90, 0x80 },
+	{ 0x92, 0x02 },
+	{ 0x93, 0x00 },
+	{ 0x99, 0x00 },
+	{ 0x9A, 0x00 },
+	{ 0x9B, 0x00 },
+	{ 0x9C, 0x3F },
+	{ 0x9D, 0x00 },
+	{ 0x9E, 0x3F },
+	{ 0x9F, 0xFF },
+	{ 0xA0, 0x71 },
+	{ 0xA1, 0x00 },
+	{ 0xA2, 0x00 },
+	{ 0xA6, 0x00 },
+	{ 0xA7, 0x00 },
+	{ 0xAB, 0x00 },
+	{ 0xAC, 0x00 },
+	{ 0xAD, 0x00 },
+	{ 0xAF, 0x08 },
+	{ 0xB0, 0x00 },
+	{ 0xB1, 0x00 },
+	{ 0xB2, 0x00 },
+};
+
+static bool da9055_volatile_register(struct device *dev,
+				     unsigned int reg)
+{
+	switch (reg) {
+	case DA9055_STATUS1:
+	case DA9055_PLL_STATUS:
+	case DA9055_AUX_L_GAIN_STATUS:
+	case DA9055_AUX_R_GAIN_STATUS:
+	case DA9055_MIC_L_GAIN_STATUS:
+	case DA9055_MIC_R_GAIN_STATUS:
+	case DA9055_MIXIN_L_GAIN_STATUS:
+	case DA9055_MIXIN_R_GAIN_STATUS:
+	case DA9055_ADC_L_GAIN_STATUS:
+	case DA9055_ADC_R_GAIN_STATUS:
+	case DA9055_DAC_L_GAIN_STATUS:
+	case DA9055_DAC_R_GAIN_STATUS:
+	case DA9055_HP_L_GAIN_STATUS:
+	case DA9055_HP_R_GAIN_STATUS:
+	case DA9055_LINE_GAIN_STATUS:
+	case DA9055_ALC_CIC_OP_LVL_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/* Set DAI word length */
+static int da9055_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct da9055_priv *da9055 = snd_soc_component_get_drvdata(component);
+	u8 aif_ctrl, fs;
+	u32 sysclk;
+
+	switch (params_width(params)) {
+	case 16:
+		aif_ctrl = DA9055_AIF_WORD_S16_LE;
+		break;
+	case 20:
+		aif_ctrl = DA9055_AIF_WORD_S20_3LE;
+		break;
+	case 24:
+		aif_ctrl = DA9055_AIF_WORD_S24_LE;
+		break;
+	case 32:
+		aif_ctrl = DA9055_AIF_WORD_S32_LE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Set AIF format */
+	snd_soc_component_update_bits(component, DA9055_AIF_CTRL, DA9055_AIF_WORD_LENGTH_MASK,
+			    aif_ctrl);
+
+	switch (params_rate(params)) {
+	case 8000:
+		fs		= DA9055_SR_8000;
+		sysclk		= 3072000;
+		break;
+	case 11025:
+		fs		= DA9055_SR_11025;
+		sysclk		= 2822400;
+		break;
+	case 12000:
+		fs		= DA9055_SR_12000;
+		sysclk		= 3072000;
+		break;
+	case 16000:
+		fs		= DA9055_SR_16000;
+		sysclk		= 3072000;
+		break;
+	case 22050:
+		fs		= DA9055_SR_22050;
+		sysclk		= 2822400;
+		break;
+	case 32000:
+		fs		= DA9055_SR_32000;
+		sysclk		= 3072000;
+		break;
+	case 44100:
+		fs		= DA9055_SR_44100;
+		sysclk		= 2822400;
+		break;
+	case 48000:
+		fs		= DA9055_SR_48000;
+		sysclk		= 3072000;
+		break;
+	case 88200:
+		fs		= DA9055_SR_88200;
+		sysclk		= 2822400;
+		break;
+	case 96000:
+		fs		= DA9055_SR_96000;
+		sysclk		= 3072000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (da9055->mclk_rate) {
+		/* PLL Mode, Write actual FS */
+		snd_soc_component_write(component, DA9055_SR, fs);
+	} else {
+		/*
+		 * Non-PLL Mode
+		 * When PLL is bypassed, chip assumes constant MCLK of
+		 * 12.288MHz and uses sample rate value to divide this MCLK
+		 * to derive its sys clk. As sys clk has to be 256 * Fs, we
+		 * need to write constant sample rate i.e. 48KHz.
+		 */
+		snd_soc_component_write(component, DA9055_SR, DA9055_SR_48000);
+	}
+
+	if (da9055->mclk_rate && (da9055->mclk_rate != sysclk)) {
+		/* PLL Mode */
+		if (!da9055->master) {
+			/* PLL slave mode, enable PLL and also SRM */
+			snd_soc_component_update_bits(component, DA9055_PLL_CTRL,
+					    DA9055_PLL_EN | DA9055_PLL_SRM_EN,
+					    DA9055_PLL_EN | DA9055_PLL_SRM_EN);
+		} else {
+			/* PLL master mode, only enable PLL */
+			snd_soc_component_update_bits(component, DA9055_PLL_CTRL,
+					    DA9055_PLL_EN, DA9055_PLL_EN);
+		}
+	} else {
+		/* Non PLL Mode, disable PLL */
+		snd_soc_component_update_bits(component, DA9055_PLL_CTRL, DA9055_PLL_EN, 0);
+	}
+
+	return 0;
+}
+
+/* Set DAI mode and Format */
+static int da9055_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da9055_priv *da9055 = snd_soc_component_get_drvdata(component);
+	u8 aif_clk_mode, aif_ctrl, mode;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* DA9055 in I2S Master Mode */
+		mode = 1;
+		aif_clk_mode = DA9055_AIF_CLK_EN_MASTER_MODE;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* DA9055 in I2S Slave Mode */
+		mode = 0;
+		aif_clk_mode = DA9055_AIF_CLK_EN_SLAVE_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Don't allow change of mode if PLL is enabled */
+	if ((snd_soc_component_read32(component, DA9055_PLL_CTRL) & DA9055_PLL_EN) &&
+	    (da9055->master != mode))
+		return -EINVAL;
+
+	da9055->master = mode;
+
+	/* Only I2S is supported */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		aif_ctrl = DA9055_AIF_FORMAT_I2S_MODE;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif_ctrl = DA9055_AIF_FORMAT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		aif_ctrl = DA9055_AIF_FORMAT_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		aif_ctrl = DA9055_AIF_FORMAT_DSP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* By default only 32 BCLK per WCLK is supported */
+	aif_clk_mode |= DA9055_AIF_BCLKS_PER_WCLK_32;
+
+	snd_soc_component_update_bits(component, DA9055_AIF_CLK_MODE,
+			    (DA9055_AIF_CLK_MODE_MASK | DA9055_AIF_BCLK_MASK),
+			    aif_clk_mode);
+	snd_soc_component_update_bits(component, DA9055_AIF_CTRL, DA9055_AIF_FORMAT_MASK,
+			    aif_ctrl);
+	return 0;
+}
+
+static int da9055_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute) {
+		snd_soc_component_update_bits(component, DA9055_DAC_L_CTRL,
+				    DA9055_DAC_L_MUTE_EN, DA9055_DAC_L_MUTE_EN);
+		snd_soc_component_update_bits(component, DA9055_DAC_R_CTRL,
+				    DA9055_DAC_R_MUTE_EN, DA9055_DAC_R_MUTE_EN);
+	} else {
+		snd_soc_component_update_bits(component, DA9055_DAC_L_CTRL,
+				    DA9055_DAC_L_MUTE_EN, 0);
+		snd_soc_component_update_bits(component, DA9055_DAC_R_CTRL,
+				    DA9055_DAC_R_MUTE_EN, 0);
+	}
+
+	return 0;
+}
+
+#define DA9055_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static int da9055_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da9055_priv *da9055 = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case DA9055_CLKSRC_MCLK:
+		switch (freq) {
+		case 11289600:
+		case 12000000:
+		case 12288000:
+		case 13000000:
+		case 13500000:
+		case 14400000:
+		case 19200000:
+		case 19680000:
+		case 19800000:
+			da9055->mclk_rate = freq;
+			return 0;
+		default:
+			dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+				freq);
+			return -EINVAL;
+		}
+		break;
+	default:
+		dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+		return -EINVAL;
+	}
+}
+
+/*
+ * da9055_set_dai_pll	: Configure the codec PLL
+ * @param codec_dai	: Pointer to codec DAI
+ * @param pll_id	: da9055 has only one pll, so pll_id is always zero
+ * @param fref		: Input MCLK frequency
+ * @param fout		: FsDM value
+ * @return int		: Zero for success, negative error code for error
+ *
+ * Note: Supported PLL input frequencies are 11.2896MHz, 12MHz, 12.288MHz,
+ *	 13MHz, 13.5MHz, 14.4MHz, 19.2MHz, 19.6MHz and 19.8MHz
+ */
+static int da9055_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+			      int source, unsigned int fref, unsigned int fout)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct da9055_priv *da9055 = snd_soc_component_get_drvdata(component);
+
+	u8 pll_frac_top, pll_frac_bot, pll_integer, cnt;
+
+	/* Disable PLL before setting the divisors */
+	snd_soc_component_update_bits(component, DA9055_PLL_CTRL, DA9055_PLL_EN, 0);
+
+	/* In slave mode, there is only one set of divisors */
+	if (!da9055->master && (fout != 2822400))
+		goto pll_err;
+
+	/* Search pll div array for correct divisors */
+	for (cnt = 0; cnt < ARRAY_SIZE(da9055_pll_div); cnt++) {
+		/* Check fref, mode  and fout */
+		if ((fref == da9055_pll_div[cnt].fref) &&
+		    (da9055->master ==  da9055_pll_div[cnt].mode) &&
+		    (fout == da9055_pll_div[cnt].fout)) {
+			/* All match, pick up divisors */
+			pll_frac_top = da9055_pll_div[cnt].frac_top;
+			pll_frac_bot = da9055_pll_div[cnt].frac_bot;
+			pll_integer = da9055_pll_div[cnt].integer;
+			break;
+		}
+	}
+	if (cnt >= ARRAY_SIZE(da9055_pll_div))
+		goto pll_err;
+
+	/* Write PLL dividers */
+	snd_soc_component_write(component, DA9055_PLL_FRAC_TOP, pll_frac_top);
+	snd_soc_component_write(component, DA9055_PLL_FRAC_BOT, pll_frac_bot);
+	snd_soc_component_write(component, DA9055_PLL_INTEGER, pll_integer);
+
+	return 0;
+pll_err:
+	dev_err(codec_dai->dev, "Error in setting up PLL\n");
+	return -EINVAL;
+}
+
+/* DAI operations */
+static const struct snd_soc_dai_ops da9055_dai_ops = {
+	.hw_params	= da9055_hw_params,
+	.set_fmt	= da9055_set_dai_fmt,
+	.set_sysclk	= da9055_set_dai_sysclk,
+	.set_pll	= da9055_set_dai_pll,
+	.digital_mute	= da9055_mute,
+};
+
+static struct snd_soc_dai_driver da9055_dai = {
+	.name = "da9055-hifi",
+	/* Playback Capabilities */
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = DA9055_FORMATS,
+	},
+	/* Capture Capabilities */
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = DA9055_FORMATS,
+	},
+	.ops = &da9055_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int da9055_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/* Enable VMID reference & master bias */
+			snd_soc_component_update_bits(component, DA9055_REFERENCES,
+					    DA9055_VMID_EN | DA9055_BIAS_EN,
+					    DA9055_VMID_EN | DA9055_BIAS_EN);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* Disable VMID reference & master bias */
+		snd_soc_component_update_bits(component, DA9055_REFERENCES,
+				    DA9055_VMID_EN | DA9055_BIAS_EN, 0);
+		break;
+	}
+	return 0;
+}
+
+static int da9055_probe(struct snd_soc_component *component)
+{
+	struct da9055_priv *da9055 = snd_soc_component_get_drvdata(component);
+
+	/* Enable all Gain Ramps */
+	snd_soc_component_update_bits(component, DA9055_AUX_L_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_component_update_bits(component, DA9055_AUX_R_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_component_update_bits(component, DA9055_MIXIN_L_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_component_update_bits(component, DA9055_MIXIN_R_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_component_update_bits(component, DA9055_ADC_L_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_component_update_bits(component, DA9055_ADC_R_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_component_update_bits(component, DA9055_DAC_L_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_component_update_bits(component, DA9055_DAC_R_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_component_update_bits(component, DA9055_HP_L_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_component_update_bits(component, DA9055_HP_R_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_component_update_bits(component, DA9055_LINE_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+
+	/*
+	 * There are two separate control bits for input and output mixers.
+	 * One to enable corresponding amplifier and other to enable its
+	 * output. As amplifier bits are related to power control, they are
+	 * being managed by DAPM while other (non power related) bits are
+	 * enabled here
+	 */
+	snd_soc_component_update_bits(component, DA9055_MIXIN_L_CTRL,
+			    DA9055_MIXIN_L_MIX_EN, DA9055_MIXIN_L_MIX_EN);
+	snd_soc_component_update_bits(component, DA9055_MIXIN_R_CTRL,
+			    DA9055_MIXIN_R_MIX_EN, DA9055_MIXIN_R_MIX_EN);
+
+	snd_soc_component_update_bits(component, DA9055_MIXOUT_L_CTRL,
+			    DA9055_MIXOUT_L_MIX_EN, DA9055_MIXOUT_L_MIX_EN);
+	snd_soc_component_update_bits(component, DA9055_MIXOUT_R_CTRL,
+			    DA9055_MIXOUT_R_MIX_EN, DA9055_MIXOUT_R_MIX_EN);
+
+	/* Set this as per your system configuration */
+	snd_soc_component_write(component, DA9055_PLL_CTRL, DA9055_PLL_INDIV_10_20_MHZ);
+
+	/* Set platform data values */
+	if (da9055->pdata) {
+		/* set mic bias source */
+		if (da9055->pdata->micbias_source) {
+			snd_soc_component_update_bits(component, DA9055_MIXIN_R_SELECT,
+					    DA9055_MICBIAS2_EN,
+					    DA9055_MICBIAS2_EN);
+		} else {
+			snd_soc_component_update_bits(component, DA9055_MIXIN_R_SELECT,
+					    DA9055_MICBIAS2_EN, 0);
+		}
+		/* set mic bias voltage */
+		switch (da9055->pdata->micbias) {
+		case DA9055_MICBIAS_2_2V:
+		case DA9055_MICBIAS_2_1V:
+		case DA9055_MICBIAS_1_8V:
+		case DA9055_MICBIAS_1_6V:
+			snd_soc_component_update_bits(component, DA9055_MIC_CONFIG,
+					    DA9055_MICBIAS_LEVEL_MASK,
+					    (da9055->pdata->micbias) << 4);
+			break;
+		}
+	}
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_da9055 = {
+	.probe			= da9055_probe,
+	.set_bias_level		= da9055_set_bias_level,
+	.controls		= da9055_snd_controls,
+	.num_controls		= ARRAY_SIZE(da9055_snd_controls),
+	.dapm_widgets		= da9055_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(da9055_dapm_widgets),
+	.dapm_routes		= da9055_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(da9055_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config da9055_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.reg_defaults = da9055_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(da9055_reg_defaults),
+	.volatile_reg = da9055_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int da9055_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct da9055_priv *da9055;
+	struct da9055_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	int ret;
+
+	da9055 = devm_kzalloc(&i2c->dev, sizeof(struct da9055_priv),
+			      GFP_KERNEL);
+	if (!da9055)
+		return -ENOMEM;
+
+	if (pdata)
+		da9055->pdata = pdata;
+
+	i2c_set_clientdata(i2c, da9055);
+
+	da9055->regmap = devm_regmap_init_i2c(i2c, &da9055_regmap_config);
+	if (IS_ERR(da9055->regmap)) {
+		ret = PTR_ERR(da9055->regmap);
+		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_da9055, &da9055_dai, 1);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register da9055 component: %d\n",
+			ret);
+	}
+	return ret;
+}
+
+/*
+ * DO NOT change the device Ids. The naming is intentionally specific as both
+ * the CODEC and PMIC parts of this chip are instantiated separately as I2C
+ * devices (both have configurable I2C addresses, and are to all intents and
+ * purposes separate). As a result there are specific DA9055 Ids for CODEC
+ * and PMIC, which must be different to operate together.
+ */
+static const struct i2c_device_id da9055_i2c_id[] = {
+	{ "da9055-codec", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
+
+static const struct of_device_id da9055_of_match[] = {
+	{ .compatible = "dlg,da9055-codec", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, da9055_of_match);
+
+/* I2C codec control layer */
+static struct i2c_driver da9055_i2c_driver = {
+	.driver = {
+		.name = "da9055-codec",
+		.of_match_table = of_match_ptr(da9055_of_match),
+	},
+	.probe		= da9055_i2c_probe,
+	.id_table	= da9055_i2c_id,
+};
+
+module_i2c_driver(da9055_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC DA9055 Codec driver");
+MODULE_AUTHOR("David Chen, Ashish Chavan");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
new file mode 100644
index 0000000..8c4926d
--- /dev/null
+++ b/sound/soc/codecs/dmic.c
@@ -0,0 +1,164 @@
+/*
+ * dmic.c  --  SoC audio for Generic Digital MICs
+ *
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+struct dmic {
+	struct gpio_desc *gpio_en;
+	int wakeup_delay;
+};
+
+static int dmic_aif_event(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol, int event) {
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct dmic *dmic = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (dmic->gpio_en)
+			gpiod_set_value(dmic->gpio_en, 1);
+
+		if (dmic->wakeup_delay)
+			msleep(dmic->wakeup_delay);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (dmic->gpio_en)
+			gpiod_set_value(dmic->gpio_en, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_driver dmic_dai = {
+	.name = "dmic-hifi",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_CONTINUOUS,
+		.formats = SNDRV_PCM_FMTBIT_S32_LE
+			| SNDRV_PCM_FMTBIT_S24_LE
+			| SNDRV_PCM_FMTBIT_S16_LE,
+	},
+};
+
+static int dmic_component_probe(struct snd_soc_component *component)
+{
+	struct dmic *dmic;
+
+	dmic = devm_kzalloc(component->dev, sizeof(*dmic), GFP_KERNEL);
+	if (!dmic)
+		return -ENOMEM;
+
+	dmic->gpio_en = devm_gpiod_get_optional(component->dev,
+						"dmicen", GPIOD_OUT_LOW);
+	if (IS_ERR(dmic->gpio_en))
+		return PTR_ERR(dmic->gpio_en);
+
+	device_property_read_u32(component->dev, "wakeup-delay-ms",
+				 &dmic->wakeup_delay);
+
+	snd_soc_component_set_drvdata(component, dmic);
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_OUT_E("DMIC AIF", "Capture", 0,
+			       SND_SOC_NOPM, 0, 0, dmic_aif_event,
+			       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_INPUT("DMic"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	{"DMIC AIF", NULL, "DMic"},
+};
+
+static const struct snd_soc_component_driver soc_dmic = {
+	.probe			= dmic_component_probe,
+	.dapm_widgets		= dmic_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(dmic_dapm_widgets),
+	.dapm_routes		= intercon,
+	.num_dapm_routes	= ARRAY_SIZE(intercon),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int dmic_dev_probe(struct platform_device *pdev)
+{
+	int err;
+	u32 chans;
+	struct snd_soc_dai_driver *dai_drv = &dmic_dai;
+
+	if (pdev->dev.of_node) {
+		err = of_property_read_u32(pdev->dev.of_node, "num-channels", &chans);
+		if (err && (err != -EINVAL))
+			return err;
+
+		if (!err) {
+			if (chans < 1 || chans > 8)
+				return -EINVAL;
+
+			dai_drv = devm_kzalloc(&pdev->dev, sizeof(*dai_drv), GFP_KERNEL);
+			if (!dai_drv)
+				return -ENOMEM;
+
+			memcpy(dai_drv, &dmic_dai, sizeof(*dai_drv));
+			dai_drv->capture.channels_max = chans;
+		}
+	}
+
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_dmic, dai_drv, 1);
+}
+
+MODULE_ALIAS("platform:dmic-codec");
+
+static const struct of_device_id dmic_dev_match[] = {
+	{.compatible = "dmic-codec"},
+	{}
+};
+
+static struct platform_driver dmic_driver = {
+	.driver = {
+		.name = "dmic-codec",
+		.of_match_table = dmic_dev_match,
+	},
+	.probe = dmic_dev_probe,
+};
+
+module_platform_driver(dmic_driver);
+
+MODULE_DESCRIPTION("Generic DMIC driver");
+MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es7134.c b/sound/soc/codecs/es7134.c
new file mode 100644
index 0000000..6d7bca7
--- /dev/null
+++ b/sound/soc/codecs/es7134.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2017 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ */
+
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+
+/*
+ * The everest 7134 is a very simple DA converter with no register
+ */
+
+struct es7134_clock_mode {
+	unsigned int rate_min;
+	unsigned int rate_max;
+	unsigned int *mclk_fs;
+	unsigned int mclk_fs_num;
+};
+
+struct es7134_chip {
+	struct snd_soc_dai_driver *dai_drv;
+	const struct es7134_clock_mode *modes;
+	unsigned int mode_num;
+	const struct snd_soc_dapm_widget *extra_widgets;
+	unsigned int extra_widget_num;
+	const struct snd_soc_dapm_route *extra_routes;
+	unsigned int extra_route_num;
+};
+
+struct es7134_data {
+	unsigned int mclk;
+	const struct es7134_chip *chip;
+};
+
+static int es7134_check_mclk(struct snd_soc_dai *dai,
+			     struct es7134_data *priv,
+			     unsigned int rate)
+{
+	unsigned int mfs = priv->mclk / rate;
+	int i, j;
+
+	for (i = 0; i < priv->chip->mode_num; i++) {
+		const struct es7134_clock_mode *mode = &priv->chip->modes[i];
+
+		if (rate < mode->rate_min || rate > mode->rate_max)
+			continue;
+
+		for (j = 0; j < mode->mclk_fs_num; j++) {
+			if (mode->mclk_fs[j] == mfs)
+				return 0;
+		}
+
+		dev_err(dai->dev, "unsupported mclk_fs %u for rate %u\n",
+			mfs, rate);
+		return -EINVAL;
+	}
+
+	/* should not happen */
+	dev_err(dai->dev, "unsupported rate: %u\n", rate);
+	return -EINVAL;
+}
+
+static int es7134_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct es7134_data *priv = snd_soc_dai_get_drvdata(dai);
+
+	/* mclk has not been provided, assume it is OK */
+	if (!priv->mclk)
+		return 0;
+
+	return es7134_check_mclk(dai, priv, params_rate(params));
+}
+
+static int es7134_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+			     unsigned int freq, int dir)
+{
+	struct es7134_data *priv = snd_soc_dai_get_drvdata(dai);
+
+	if (dir == SND_SOC_CLOCK_IN && clk_id == 0) {
+		priv->mclk = freq;
+		return 0;
+	}
+
+	return -ENOTSUPP;
+}
+
+static int es7134_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK |
+		SND_SOC_DAIFMT_MASTER_MASK);
+
+	if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+		    SND_SOC_DAIFMT_CBS_CFS)) {
+		dev_err(codec_dai->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int es7134_component_probe(struct snd_soc_component *c)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(c);
+	struct es7134_data *priv = snd_soc_component_get_drvdata(c);
+	const struct es7134_chip *chip = priv->chip;
+	int ret;
+
+	if (chip->extra_widget_num) {
+		ret = snd_soc_dapm_new_controls(dapm, chip->extra_widgets,
+						chip->extra_widget_num);
+		if (ret) {
+			dev_err(c->dev, "failed to add extra widgets\n");
+			return ret;
+		}
+	}
+
+	if (chip->extra_route_num) {
+		ret = snd_soc_dapm_add_routes(dapm, chip->extra_routes,
+					      chip->extra_route_num);
+		if (ret) {
+			dev_err(c->dev, "failed to add extra routes\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops es7134_dai_ops = {
+	.set_fmt	= es7134_set_fmt,
+	.hw_params	= es7134_hw_params,
+	.set_sysclk	= es7134_set_sysclk,
+};
+
+static struct snd_soc_dai_driver es7134_dai = {
+	.name = "es7134-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = (SNDRV_PCM_RATE_8000_48000 |
+			  SNDRV_PCM_RATE_88200      |
+			  SNDRV_PCM_RATE_96000      |
+			  SNDRV_PCM_RATE_176400     |
+			  SNDRV_PCM_RATE_192000),
+		.formats = (SNDRV_PCM_FMTBIT_S16_LE  |
+			    SNDRV_PCM_FMTBIT_S18_3LE |
+			    SNDRV_PCM_FMTBIT_S20_3LE |
+			    SNDRV_PCM_FMTBIT_S24_3LE |
+			    SNDRV_PCM_FMTBIT_S24_LE),
+	},
+	.ops = &es7134_dai_ops,
+};
+
+static const struct es7134_clock_mode es7134_modes[] = {
+	{
+		/* Single speed mode */
+		.rate_min = 8000,
+		.rate_max = 50000,
+		.mclk_fs = (unsigned int[]) { 256, 384, 512, 768, 1024 },
+		.mclk_fs_num = 5,
+	}, {
+		/* Double speed mode */
+		.rate_min = 84000,
+		.rate_max = 100000,
+		.mclk_fs = (unsigned int[]) { 128, 192, 256, 384, 512 },
+		.mclk_fs_num = 5,
+	}, {
+		/* Quad speed mode */
+		.rate_min = 167000,
+		.rate_max = 192000,
+		.mclk_fs = (unsigned int[]) { 128, 192, 256 },
+		.mclk_fs_num = 3,
+	},
+};
+
+/* Digital I/O are also supplied by VDD on the es7134 */
+static const struct snd_soc_dapm_route es7134_extra_routes[] = {
+	{ "Playback", NULL, "VDD", }
+};
+
+static const struct es7134_chip es7134_chip = {
+	.dai_drv = &es7134_dai,
+	.modes = es7134_modes,
+	.mode_num = ARRAY_SIZE(es7134_modes),
+	.extra_routes = es7134_extra_routes,
+	.extra_route_num = ARRAY_SIZE(es7134_extra_routes),
+};
+
+static const struct snd_soc_dapm_widget es7134_dapm_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("AOUTL"),
+	SND_SOC_DAPM_OUTPUT("AOUTR"),
+	SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("VDD", 0, 0),
+};
+
+static const struct snd_soc_dapm_route es7134_dapm_routes[] = {
+	{ "AOUTL", NULL, "DAC" },
+	{ "AOUTR", NULL, "DAC" },
+	{ "DAC", NULL, "VDD" },
+};
+
+static const struct snd_soc_component_driver es7134_component_driver = {
+	.probe			= es7134_component_probe,
+	.dapm_widgets		= es7134_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(es7134_dapm_widgets),
+	.dapm_routes		= es7134_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(es7134_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static struct snd_soc_dai_driver es7154_dai = {
+	.name = "es7154-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = (SNDRV_PCM_RATE_8000_48000 |
+			  SNDRV_PCM_RATE_88200      |
+			  SNDRV_PCM_RATE_96000),
+		.formats = (SNDRV_PCM_FMTBIT_S16_LE  |
+			    SNDRV_PCM_FMTBIT_S18_3LE |
+			    SNDRV_PCM_FMTBIT_S20_3LE |
+			    SNDRV_PCM_FMTBIT_S24_3LE |
+			    SNDRV_PCM_FMTBIT_S24_LE),
+	},
+	.ops = &es7134_dai_ops,
+};
+
+static const struct es7134_clock_mode es7154_modes[] = {
+	{
+		/* Single speed mode */
+		.rate_min = 8000,
+		.rate_max = 50000,
+		.mclk_fs = (unsigned int[]) { 32, 64, 128, 192, 256,
+					      384, 512, 768, 1024 },
+		.mclk_fs_num = 9,
+	}, {
+		/* Double speed mode */
+		.rate_min = 84000,
+		.rate_max = 100000,
+		.mclk_fs = (unsigned int[]) { 128, 192, 256, 384, 512,
+					      768, 1024},
+		.mclk_fs_num = 7,
+	}
+};
+
+/* Es7154 has a separate supply for digital I/O  */
+static const struct snd_soc_dapm_widget es7154_extra_widgets[] = {
+	SND_SOC_DAPM_REGULATOR_SUPPLY("PVDD", 0, 0),
+};
+
+static const struct snd_soc_dapm_route es7154_extra_routes[] = {
+	{ "Playback", NULL, "PVDD", }
+};
+
+static const struct es7134_chip es7154_chip = {
+	.dai_drv = &es7154_dai,
+	.modes = es7154_modes,
+	.mode_num = ARRAY_SIZE(es7154_modes),
+	.extra_routes = es7154_extra_routes,
+	.extra_route_num = ARRAY_SIZE(es7154_extra_routes),
+	.extra_widgets = es7154_extra_widgets,
+	.extra_widget_num = ARRAY_SIZE(es7154_extra_widgets),
+};
+
+static int es7134_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct es7134_data *priv;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, priv);
+
+	priv->chip = of_device_get_match_data(dev);
+	if (!priv->chip) {
+		dev_err(dev, "failed to match device\n");
+		return -ENODEV;
+	}
+
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &es7134_component_driver,
+				      priv->chip->dai_drv, 1);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id es7134_ids[] = {
+	{ .compatible = "everest,es7134", .data = &es7134_chip },
+	{ .compatible = "everest,es7144", .data = &es7134_chip },
+	{ .compatible = "everest,es7154", .data = &es7154_chip },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, es7134_ids);
+#endif
+
+static struct platform_driver es7134_driver = {
+	.driver = {
+		.name = "es7134",
+		.of_match_table = of_match_ptr(es7134_ids),
+	},
+	.probe = es7134_probe,
+};
+
+module_platform_driver(es7134_driver);
+
+MODULE_DESCRIPTION("ASoC ES7134 audio codec driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es7241.c b/sound/soc/codecs/es7241.c
new file mode 100644
index 0000000..87991bd
--- /dev/null
+++ b/sound/soc/codecs/es7241.c
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/gpio/consumer.h>
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+
+struct es7241_clock_mode {
+	unsigned int rate_min;
+	unsigned int rate_max;
+	unsigned int *slv_mfs;
+	unsigned int slv_mfs_num;
+	unsigned int mst_mfs;
+	unsigned int mst_m0:1;
+	unsigned int mst_m1:1;
+};
+
+struct es7241_chip {
+	const struct es7241_clock_mode *modes;
+	unsigned int mode_num;
+};
+
+struct es7241_data {
+	struct gpio_desc *reset;
+	struct gpio_desc *m0;
+	struct gpio_desc *m1;
+	unsigned int fmt;
+	unsigned int mclk;
+	bool is_slave;
+	const struct es7241_chip *chip;
+};
+
+static void es7241_set_mode(struct es7241_data *priv,  int m0, int m1)
+{
+	/* put the device in reset */
+	gpiod_set_value_cansleep(priv->reset, 0);
+
+	/* set the mode */
+	gpiod_set_value_cansleep(priv->m0, m0);
+	gpiod_set_value_cansleep(priv->m1, m1);
+
+	/* take the device out of reset - datasheet does not specify a delay */
+	gpiod_set_value_cansleep(priv->reset, 1);
+}
+
+static int es7241_set_slave_mode(struct es7241_data *priv,
+				 const struct es7241_clock_mode *mode,
+				 unsigned int mfs)
+{
+	int j;
+
+	if (!mfs)
+		goto out_ok;
+
+	for (j = 0; j < mode->slv_mfs_num; j++) {
+		if (mode->slv_mfs[j] == mfs)
+			goto out_ok;
+	}
+
+	return -EINVAL;
+
+out_ok:
+	es7241_set_mode(priv, 1, 1);
+	return 0;
+}
+
+static int es7241_set_master_mode(struct es7241_data *priv,
+				  const struct es7241_clock_mode *mode,
+				  unsigned int mfs)
+{
+	/*
+	 * We can't really set clock ratio, if the mclk/lrclk is different
+	 * from what we provide, then error out
+	 */
+	if (mfs && mfs != mode->mst_mfs)
+		return -EINVAL;
+
+	es7241_set_mode(priv, mode->mst_m0, mode->mst_m1);
+
+	return 0;
+}
+
+static int es7241_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
+	unsigned int rate = params_rate(params);
+	unsigned int mfs = priv->mclk / rate;
+	int i;
+
+	for (i = 0; i < priv->chip->mode_num; i++) {
+		const struct es7241_clock_mode *mode = &priv->chip->modes[i];
+
+		if (rate < mode->rate_min || rate >= mode->rate_max)
+			continue;
+
+		if (priv->is_slave)
+			return es7241_set_slave_mode(priv, mode, mfs);
+		else
+			return es7241_set_master_mode(priv, mode, mfs);
+	}
+
+	/* should not happen */
+	dev_err(dai->dev, "unsupported rate: %u\n", rate);
+	return -EINVAL;
+}
+
+static int es7241_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+			     unsigned int freq, int dir)
+{
+	struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
+
+	if (dir == SND_SOC_CLOCK_IN && clk_id == 0) {
+		priv->mclk = freq;
+		return 0;
+	}
+
+	return -ENOTSUPP;
+}
+
+static int es7241_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
+
+	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
+		dev_err(dai->dev, "Unsupported dai clock inversion\n");
+		return -EINVAL;
+	}
+
+	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != priv->fmt) {
+		dev_err(dai->dev, "Invalid dai format\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		priv->is_slave = true;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		priv->is_slave = false;
+		break;
+
+	default:
+		dev_err(dai->dev, "Unsupported clock configuration\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops es7241_dai_ops = {
+	.set_fmt	= es7241_set_fmt,
+	.hw_params	= es7241_hw_params,
+	.set_sysclk	= es7241_set_sysclk,
+};
+
+static struct snd_soc_dai_driver es7241_dai = {
+	.name = "es7241-hifi",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = (SNDRV_PCM_FMTBIT_S16_LE  |
+			    SNDRV_PCM_FMTBIT_S24_3LE |
+			    SNDRV_PCM_FMTBIT_S24_LE),
+	},
+	.ops = &es7241_dai_ops,
+};
+
+static const struct es7241_clock_mode es7241_modes[] = {
+	{
+		/* Single speed mode */
+		.rate_min = 8000,
+		.rate_max = 50000,
+		.slv_mfs = (unsigned int[]) { 256, 384, 512, 768, 1024 },
+		.slv_mfs_num = 5,
+		.mst_mfs = 256,
+		.mst_m0 = 0,
+		.mst_m1 = 0,
+	}, {
+		/* Double speed mode */
+		.rate_min = 50000,
+		.rate_max = 100000,
+		.slv_mfs = (unsigned int[]) { 128, 192 },
+		.slv_mfs_num = 2,
+		.mst_mfs = 128,
+		.mst_m0 = 1,
+		.mst_m1 = 0,
+	}, {
+		/* Quad speed mode */
+		.rate_min = 100000,
+		.rate_max = 200000,
+		.slv_mfs = (unsigned int[]) { 64 },
+		.slv_mfs_num = 1,
+		.mst_mfs = 64,
+		.mst_m0 = 0,
+		.mst_m1 = 1,
+	},
+};
+
+static const struct es7241_chip es7241_chip = {
+	.modes = es7241_modes,
+	.mode_num = ARRAY_SIZE(es7241_modes),
+};
+
+static const struct snd_soc_dapm_widget es7241_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("AINL"),
+	SND_SOC_DAPM_INPUT("AINR"),
+	SND_SOC_DAPM_DAC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("VDDP", 0, 0),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("VDDD", 0, 0),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("VDDA", 0, 0),
+};
+
+static const struct snd_soc_dapm_route es7241_dapm_routes[] = {
+	{ "ADC", NULL, "AINL", },
+	{ "ADC", NULL, "AINR", },
+	{ "ADC", NULL, "VDDA", },
+	{ "Capture", NULL, "VDDP", },
+	{ "Capture", NULL, "VDDD", },
+};
+
+static const struct snd_soc_component_driver es7241_component_driver = {
+	.dapm_widgets		= es7241_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(es7241_dapm_widgets),
+	.dapm_routes		= es7241_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(es7241_dapm_routes),
+	.idle_bias_on		= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static void es7241_parse_fmt(struct device *dev, struct es7241_data *priv)
+{
+	bool is_leftj;
+
+	/*
+	 * The format is given by a pull resistor on the SDOUT pin:
+	 * pull-up for i2s, pull-down for left justified.
+	 */
+	is_leftj = of_property_read_bool(dev->of_node,
+					 "everest,sdout-pull-down");
+	if (is_leftj)
+		priv->fmt = SND_SOC_DAIFMT_LEFT_J;
+	else
+		priv->fmt = SND_SOC_DAIFMT_I2S;
+}
+
+static int es7241_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct es7241_data *priv;
+	int err;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, priv);
+
+	priv->chip = of_device_get_match_data(dev);
+	if (!priv->chip) {
+		dev_err(dev, "failed to match device\n");
+		return -ENODEV;
+	}
+
+	es7241_parse_fmt(dev, priv);
+
+	priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(priv->reset)) {
+		err = PTR_ERR(priv->reset);
+		if (err != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get 'reset' gpio: %d", err);
+		return err;
+	}
+
+	priv->m0 = devm_gpiod_get_optional(dev, "m0", GPIOD_OUT_LOW);
+	if (IS_ERR(priv->m0)) {
+		err = PTR_ERR(priv->m0);
+		if (err != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get 'm0' gpio: %d", err);
+		return err;
+	}
+
+	priv->m1 = devm_gpiod_get_optional(dev, "m1", GPIOD_OUT_LOW);
+	if (IS_ERR(priv->m1)) {
+		err = PTR_ERR(priv->m1);
+		if (err != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get 'm1' gpio: %d", err);
+		return err;
+	}
+
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &es7241_component_driver,
+				      &es7241_dai, 1);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id es7241_ids[] = {
+	{ .compatible = "everest,es7241", .data = &es7241_chip },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, es7241_ids);
+#endif
+
+static struct platform_driver es7241_driver = {
+	.driver = {
+		.name = "es7241",
+		.of_match_table = of_match_ptr(es7241_ids),
+	},
+	.probe = es7241_probe,
+};
+
+module_platform_driver(es7241_driver);
+
+MODULE_DESCRIPTION("ASoC ES7241 audio codec driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
new file mode 100644
index 0000000..e97d12d
--- /dev/null
+++ b/sound/soc/codecs/es8316.c
@@ -0,0 +1,629 @@
+/*
+ * es8316.c -- es8316 ALSA SoC audio driver
+ * Copyright Everest Semiconductor Co.,Ltd
+ *
+ * Authors: David Yang <yangxiaohua@everest-semi.com>,
+ *          Daniel Drake <drake@endlessm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "es8316.h"
+
+/* In slave mode at single speed, the codec is documented as accepting 5
+ * MCLK/LRCK ratios, but we also add ratio 400, which is commonly used on
+ * Intel Cherry Trail platforms (19.2MHz MCLK, 48kHz LRCK).
+ */
+#define NR_SUPPORTED_MCLK_LRCK_RATIOS 6
+static const unsigned int supported_mclk_lrck_ratios[] = {
+	256, 384, 400, 512, 768, 1024
+};
+
+struct es8316_priv {
+	unsigned int sysclk;
+	unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS];
+	struct snd_pcm_hw_constraint_list sysclk_constraints;
+};
+
+/*
+ * ES8316 controls
+ */
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9600, 50, 1);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9600, 50, 1);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_max_gain_tlv, -650, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_min_gain_tlv, -1200, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_target_tlv, -1650, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(hpmixer_gain_tlv, -1200, 150, 0);
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(adc_pga_gain_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(-350, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(0, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(250, 0, 0),
+	3, 3, TLV_DB_SCALE_ITEM(450, 0, 0),
+	4, 4, TLV_DB_SCALE_ITEM(700, 0, 0),
+	5, 5, TLV_DB_SCALE_ITEM(1000, 0, 0),
+	6, 6, TLV_DB_SCALE_ITEM(1300, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(1600, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(1800, 0, 0),
+	9, 9, TLV_DB_SCALE_ITEM(2100, 0, 0),
+	10, 10, TLV_DB_SCALE_ITEM(2400, 0, 0),
+);
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(hpout_vol_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(-4800, 0, 0),
+	1, 3, TLV_DB_SCALE_ITEM(-2400, 1200, 0),
+);
+
+static const char * const ng_type_txt[] =
+	{ "Constant PGA Gain", "Mute ADC Output" };
+static const struct soc_enum ng_type =
+	SOC_ENUM_SINGLE(ES8316_ADC_ALC_NG, 6, 2, ng_type_txt);
+
+static const char * const adcpol_txt[] = { "Normal", "Invert" };
+static const struct soc_enum adcpol =
+	SOC_ENUM_SINGLE(ES8316_ADC_MUTE, 1, 2, adcpol_txt);
+static const char *const dacpol_txt[] =
+	{ "Normal", "R Invert", "L Invert", "L + R Invert" };
+static const struct soc_enum dacpol =
+	SOC_ENUM_SINGLE(ES8316_DAC_SET1, 0, 4, dacpol_txt);
+
+static const struct snd_kcontrol_new es8316_snd_controls[] = {
+	SOC_DOUBLE_TLV("Headphone Playback Volume", ES8316_CPHP_ICAL_VOL,
+		       4, 0, 3, 1, hpout_vol_tlv),
+	SOC_DOUBLE_TLV("Headphone Mixer Volume", ES8316_HPMIX_VOL,
+		       0, 4, 7, 0, hpmixer_gain_tlv),
+
+	SOC_ENUM("Playback Polarity", dacpol),
+	SOC_DOUBLE_R_TLV("DAC Playback Volume", ES8316_DAC_VOLL,
+			 ES8316_DAC_VOLR, 0, 0xc0, 1, dac_vol_tlv),
+	SOC_SINGLE("DAC Soft Ramp Switch", ES8316_DAC_SET1, 4, 1, 1),
+	SOC_SINGLE("DAC Soft Ramp Rate", ES8316_DAC_SET1, 2, 4, 0),
+	SOC_SINGLE("DAC Notch Filter Switch", ES8316_DAC_SET2, 6, 1, 0),
+	SOC_SINGLE("DAC Double Fs Switch", ES8316_DAC_SET2, 7, 1, 0),
+	SOC_SINGLE("DAC Stereo Enhancement", ES8316_DAC_SET3, 0, 7, 0),
+
+	SOC_ENUM("Capture Polarity", adcpol),
+	SOC_SINGLE("Mic Boost Switch", ES8316_ADC_D2SEPGA, 0, 1, 0),
+	SOC_SINGLE_TLV("ADC Capture Volume", ES8316_ADC_VOLUME,
+		       0, 0xc0, 1, adc_vol_tlv),
+	SOC_SINGLE_TLV("ADC PGA Gain Volume", ES8316_ADC_PGAGAIN,
+		       4, 10, 0, adc_pga_gain_tlv),
+	SOC_SINGLE("ADC Soft Ramp Switch", ES8316_ADC_MUTE, 4, 1, 0),
+	SOC_SINGLE("ADC Double Fs Switch", ES8316_ADC_DMIC, 4, 1, 0),
+
+	SOC_SINGLE("ALC Capture Switch", ES8316_ADC_ALC1, 6, 1, 0),
+	SOC_SINGLE_TLV("ALC Capture Max Volume", ES8316_ADC_ALC1, 0, 28, 0,
+		       alc_max_gain_tlv),
+	SOC_SINGLE_TLV("ALC Capture Min Volume", ES8316_ADC_ALC2, 0, 28, 0,
+		       alc_min_gain_tlv),
+	SOC_SINGLE_TLV("ALC Capture Target Volume", ES8316_ADC_ALC3, 4, 10, 0,
+		       alc_target_tlv),
+	SOC_SINGLE("ALC Capture Hold Time", ES8316_ADC_ALC3, 0, 10, 0),
+	SOC_SINGLE("ALC Capture Decay Time", ES8316_ADC_ALC4, 4, 10, 0),
+	SOC_SINGLE("ALC Capture Attack Time", ES8316_ADC_ALC4, 0, 10, 0),
+	SOC_SINGLE("ALC Capture Noise Gate Switch", ES8316_ADC_ALC_NG,
+		   5, 1, 0),
+	SOC_SINGLE("ALC Capture Noise Gate Threshold", ES8316_ADC_ALC_NG,
+		   0, 31, 0),
+	SOC_ENUM("ALC Capture Noise Gate Type", ng_type),
+};
+
+/* Analog Input Mux */
+static const char * const es8316_analog_in_txt[] = {
+		"lin1-rin1",
+		"lin2-rin2",
+		"lin1-rin1 with 20db Boost",
+		"lin2-rin2 with 20db Boost"
+};
+static const unsigned int es8316_analog_in_values[] = { 0, 1, 2, 3 };
+static const struct soc_enum es8316_analog_input_enum =
+	SOC_VALUE_ENUM_SINGLE(ES8316_ADC_PDN_LINSEL, 4, 3,
+			      ARRAY_SIZE(es8316_analog_in_txt),
+			      es8316_analog_in_txt,
+			      es8316_analog_in_values);
+static const struct snd_kcontrol_new es8316_analog_in_mux_controls =
+	SOC_DAPM_ENUM("Route", es8316_analog_input_enum);
+
+static const char * const es8316_dmic_txt[] = {
+		"dmic disable",
+		"dmic data at high level",
+		"dmic data at low level",
+};
+static const unsigned int es8316_dmic_values[] = { 0, 1, 2 };
+static const struct soc_enum es8316_dmic_src_enum =
+	SOC_VALUE_ENUM_SINGLE(ES8316_ADC_DMIC, 0, 3,
+			      ARRAY_SIZE(es8316_dmic_txt),
+			      es8316_dmic_txt,
+			      es8316_dmic_values);
+static const struct snd_kcontrol_new es8316_dmic_src_controls =
+	SOC_DAPM_ENUM("Route", es8316_dmic_src_enum);
+
+/* hp mixer mux */
+static const char * const es8316_hpmux_texts[] = {
+	"lin1-rin1",
+	"lin2-rin2",
+	"lin-rin with Boost",
+	"lin-rin with Boost and PGA"
+};
+
+static const unsigned int es8316_hpmux_values[] = { 0, 1, 2, 3 };
+
+static SOC_ENUM_SINGLE_DECL(es8316_left_hpmux_enum, ES8316_HPMIX_SEL,
+	4, es8316_hpmux_texts);
+
+static const struct snd_kcontrol_new es8316_left_hpmux_controls =
+	SOC_DAPM_ENUM("Route", es8316_left_hpmux_enum);
+
+static SOC_ENUM_SINGLE_DECL(es8316_right_hpmux_enum, ES8316_HPMIX_SEL,
+	0, es8316_hpmux_texts);
+
+static const struct snd_kcontrol_new es8316_right_hpmux_controls =
+	SOC_DAPM_ENUM("Route", es8316_right_hpmux_enum);
+
+/* headphone Output Mixer */
+static const struct snd_kcontrol_new es8316_out_left_mix[] = {
+	SOC_DAPM_SINGLE("LLIN Switch", ES8316_HPMIX_SWITCH, 6, 1, 0),
+	SOC_DAPM_SINGLE("Left DAC Switch", ES8316_HPMIX_SWITCH, 7, 1, 0),
+};
+static const struct snd_kcontrol_new es8316_out_right_mix[] = {
+	SOC_DAPM_SINGLE("RLIN Switch", ES8316_HPMIX_SWITCH, 2, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC Switch", ES8316_HPMIX_SWITCH, 3, 1, 0),
+};
+
+/* DAC data source mux */
+static const char * const es8316_dacsrc_texts[] = {
+	"LDATA TO LDAC, RDATA TO RDAC",
+	"LDATA TO LDAC, LDATA TO RDAC",
+	"RDATA TO LDAC, RDATA TO RDAC",
+	"RDATA TO LDAC, LDATA TO RDAC",
+};
+
+static const unsigned int es8316_dacsrc_values[] = { 0, 1, 2, 3 };
+
+static SOC_ENUM_SINGLE_DECL(es8316_dacsrc_mux_enum, ES8316_DAC_SET1,
+	6, es8316_dacsrc_texts);
+
+static const struct snd_kcontrol_new es8316_dacsrc_mux_controls =
+	SOC_DAPM_ENUM("Route", es8316_dacsrc_mux_enum);
+
+static const struct snd_soc_dapm_widget es8316_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("Bias", ES8316_SYS_PDN, 3, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Analog power", ES8316_SYS_PDN, 4, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Bias", ES8316_SYS_PDN, 5, 1, NULL, 0),
+
+	SND_SOC_DAPM_INPUT("DMIC"),
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+
+	/* Input Mux */
+	SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+			 &es8316_analog_in_mux_controls),
+
+	SND_SOC_DAPM_SUPPLY("ADC Vref", ES8316_SYS_PDN, 1, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC bias", ES8316_SYS_PDN, 2, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Clock", ES8316_CLKMGR_CLKSW, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Line input PGA", ES8316_ADC_PDN_LINSEL,
+			 7, 1, NULL, 0),
+	SND_SOC_DAPM_ADC("Mono ADC", NULL, ES8316_ADC_PDN_LINSEL, 6, 1),
+	SND_SOC_DAPM_MUX("Digital Mic Mux", SND_SOC_NOPM, 0, 0,
+			 &es8316_dmic_src_controls),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture",  1,
+			     ES8316_SERDATA_ADC, 6, 1),
+	SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0,
+			    SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MUX("DAC Source Mux", SND_SOC_NOPM, 0, 0,
+			 &es8316_dacsrc_mux_controls),
+
+	SND_SOC_DAPM_SUPPLY("DAC Vref", ES8316_SYS_PDN, 0, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Clock", ES8316_CLKMGR_CLKSW, 2, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("Right DAC", NULL, ES8316_DAC_PDN, 0, 1),
+	SND_SOC_DAPM_DAC("Left DAC", NULL, ES8316_DAC_PDN, 4, 1),
+
+	/* Headphone Output Side */
+	SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0,
+			 &es8316_left_hpmux_controls),
+	SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0,
+			 &es8316_right_hpmux_controls),
+	SND_SOC_DAPM_MIXER("Left Headphone Mixer", ES8316_HPMIX_PDN,
+			   5, 1, &es8316_out_left_mix[0],
+			   ARRAY_SIZE(es8316_out_left_mix)),
+	SND_SOC_DAPM_MIXER("Right Headphone Mixer", ES8316_HPMIX_PDN,
+			   1, 1, &es8316_out_right_mix[0],
+			   ARRAY_SIZE(es8316_out_right_mix)),
+	SND_SOC_DAPM_PGA("Left Headphone Mixer Out", ES8316_HPMIX_PDN,
+			 4, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Headphone Mixer Out", ES8316_HPMIX_PDN,
+			 0, 1, NULL, 0),
+
+	SND_SOC_DAPM_OUT_DRV("Left Headphone Charge Pump", ES8316_CPHP_OUTEN,
+			     6, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Right Headphone Charge Pump", ES8316_CPHP_OUTEN,
+			     2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8316_CPHP_PDN2,
+			    5, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Charge Pump Clock", ES8316_CLKMGR_CLKSW,
+			    4, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUT_DRV("Left Headphone Driver", ES8316_CPHP_OUTEN,
+			     5, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Right Headphone Driver", ES8316_CPHP_OUTEN,
+			     1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Out", ES8316_CPHP_PDN1, 2, 1, NULL, 0),
+
+	/* pdn_Lical and pdn_Rical bits are documented as Reserved, but must
+	 * be explicitly unset in order to enable HP output
+	 */
+	SND_SOC_DAPM_SUPPLY("Left Headphone ical", ES8316_CPHP_ICAL_VOL,
+			    7, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Right Headphone ical", ES8316_CPHP_ICAL_VOL,
+			    3, 1, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_route es8316_dapm_routes[] = {
+	/* Recording */
+	{"MIC1", NULL, "Mic Bias"},
+	{"MIC2", NULL, "Mic Bias"},
+	{"MIC1", NULL, "Bias"},
+	{"MIC2", NULL, "Bias"},
+	{"MIC1", NULL, "Analog power"},
+	{"MIC2", NULL, "Analog power"},
+
+	{"Differential Mux", "lin1-rin1", "MIC1"},
+	{"Differential Mux", "lin2-rin2", "MIC2"},
+	{"Line input PGA", NULL, "Differential Mux"},
+
+	{"Mono ADC", NULL, "ADC Clock"},
+	{"Mono ADC", NULL, "ADC Vref"},
+	{"Mono ADC", NULL, "ADC bias"},
+	{"Mono ADC", NULL, "Line input PGA"},
+
+	/* It's not clear why, but to avoid recording only silence,
+	 * the DAC clock must be running for the ADC to work.
+	 */
+	{"Mono ADC", NULL, "DAC Clock"},
+
+	{"Digital Mic Mux", "dmic disable", "Mono ADC"},
+
+	{"I2S OUT", NULL, "Digital Mic Mux"},
+
+	/* Playback */
+	{"DAC Source Mux", "LDATA TO LDAC, RDATA TO RDAC", "I2S IN"},
+
+	{"Left DAC", NULL, "DAC Clock"},
+	{"Right DAC", NULL, "DAC Clock"},
+
+	{"Left DAC", NULL, "DAC Vref"},
+	{"Right DAC", NULL, "DAC Vref"},
+
+	{"Left DAC", NULL, "DAC Source Mux"},
+	{"Right DAC", NULL, "DAC Source Mux"},
+
+	{"Left Headphone Mux", "lin-rin with Boost and PGA", "Line input PGA"},
+	{"Right Headphone Mux", "lin-rin with Boost and PGA", "Line input PGA"},
+
+	{"Left Headphone Mixer", "LLIN Switch", "Left Headphone Mux"},
+	{"Left Headphone Mixer", "Left DAC Switch", "Left DAC"},
+
+	{"Right Headphone Mixer", "RLIN Switch", "Right Headphone Mux"},
+	{"Right Headphone Mixer", "Right DAC Switch", "Right DAC"},
+
+	{"Left Headphone Mixer Out", NULL, "Left Headphone Mixer"},
+	{"Right Headphone Mixer Out", NULL, "Right Headphone Mixer"},
+
+	{"Left Headphone Charge Pump", NULL, "Left Headphone Mixer Out"},
+	{"Right Headphone Charge Pump", NULL, "Right Headphone Mixer Out"},
+
+	{"Left Headphone Charge Pump", NULL, "Headphone Charge Pump"},
+	{"Right Headphone Charge Pump", NULL, "Headphone Charge Pump"},
+
+	{"Left Headphone Charge Pump", NULL, "Headphone Charge Pump Clock"},
+	{"Right Headphone Charge Pump", NULL, "Headphone Charge Pump Clock"},
+
+	{"Left Headphone Driver", NULL, "Left Headphone Charge Pump"},
+	{"Right Headphone Driver", NULL, "Right Headphone Charge Pump"},
+
+	{"HPOL", NULL, "Left Headphone Driver"},
+	{"HPOR", NULL, "Right Headphone Driver"},
+
+	{"HPOL", NULL, "Left Headphone ical"},
+	{"HPOR", NULL, "Right Headphone ical"},
+
+	{"Headphone Out", NULL, "Bias"},
+	{"Headphone Out", NULL, "Analog power"},
+	{"HPOL", NULL, "Headphone Out"},
+	{"HPOR", NULL, "Headphone Out"},
+};
+
+static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
+	int i;
+	int count = 0;
+
+	es8316->sysclk = freq;
+
+	if (freq == 0)
+		return 0;
+
+	/* Limit supported sample rates to ones that can be autodetected
+	 * by the codec running in slave mode.
+	 */
+	for (i = 0; i < NR_SUPPORTED_MCLK_LRCK_RATIOS; i++) {
+		const unsigned int ratio = supported_mclk_lrck_ratios[i];
+
+		if (freq % ratio == 0)
+			es8316->allowed_rates[count++] = freq / ratio;
+	}
+
+	es8316->sysclk_constraints.list = es8316->allowed_rates;
+	es8316->sysclk_constraints.count = count;
+
+	return 0;
+}
+
+static int es8316_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u8 serdata1 = 0;
+	u8 serdata2 = 0;
+	u8 clksw;
+	u8 mask;
+
+	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+		dev_err(component->dev, "Codec driver only supports slave mode\n");
+		return -EINVAL;
+	}
+
+	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
+		dev_err(component->dev, "Codec driver only supports I2S format\n");
+		return -EINVAL;
+	}
+
+	/* Clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		serdata1 |= ES8316_SERDATA1_BCLK_INV;
+		serdata2 |= ES8316_SERDATA2_ADCLRP;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		serdata1 |= ES8316_SERDATA1_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		serdata2 |= ES8316_SERDATA2_ADCLRP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mask = ES8316_SERDATA1_MASTER | ES8316_SERDATA1_BCLK_INV;
+	snd_soc_component_update_bits(component, ES8316_SERDATA1, mask, serdata1);
+
+	mask = ES8316_SERDATA2_FMT_MASK | ES8316_SERDATA2_ADCLRP;
+	snd_soc_component_update_bits(component, ES8316_SERDATA_ADC, mask, serdata2);
+	snd_soc_component_update_bits(component, ES8316_SERDATA_DAC, mask, serdata2);
+
+	/* Enable BCLK and MCLK inputs in slave mode */
+	clksw = ES8316_CLKMGR_CLKSW_MCLK_ON | ES8316_CLKMGR_CLKSW_BCLK_ON;
+	snd_soc_component_update_bits(component, ES8316_CLKMGR_CLKSW, clksw, clksw);
+
+	return 0;
+}
+
+static int es8316_pcm_startup(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
+
+	if (es8316->sysclk == 0) {
+		dev_err(component->dev, "No sysclk provided\n");
+		return -EINVAL;
+	}
+
+	/* The set of sample rates that can be supported depends on the
+	 * MCLK supplied to the CODEC.
+	 */
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+				   SNDRV_PCM_HW_PARAM_RATE,
+				   &es8316->sysclk_constraints);
+
+	return 0;
+}
+
+static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
+	u8 wordlen = 0;
+
+	if (!es8316->sysclk) {
+		dev_err(component->dev, "No MCLK configured\n");
+		return -EINVAL;
+	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		wordlen = ES8316_SERDATA2_LEN_16;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		wordlen = ES8316_SERDATA2_LEN_20;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		wordlen = ES8316_SERDATA2_LEN_24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		wordlen = ES8316_SERDATA2_LEN_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, ES8316_SERDATA_DAC,
+			    ES8316_SERDATA2_LEN_MASK, wordlen);
+	snd_soc_component_update_bits(component, ES8316_SERDATA_ADC,
+			    ES8316_SERDATA2_LEN_MASK, wordlen);
+	return 0;
+}
+
+static int es8316_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_component_update_bits(dai->component, ES8316_DAC_SET1, 0x20,
+			    mute ? 0x20 : 0);
+	return 0;
+}
+
+#define ES8316_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops es8316_ops = {
+	.startup = es8316_pcm_startup,
+	.hw_params = es8316_pcm_hw_params,
+	.set_fmt = es8316_set_dai_fmt,
+	.set_sysclk = es8316_set_dai_sysclk,
+	.digital_mute = es8316_mute,
+};
+
+static struct snd_soc_dai_driver es8316_dai = {
+	.name = "ES8316 HiFi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = ES8316_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = ES8316_FORMATS,
+	},
+	.ops = &es8316_ops,
+	.symmetric_rates = 1,
+};
+
+static int es8316_probe(struct snd_soc_component *component)
+{
+	/* Reset codec and enable current state machine */
+	snd_soc_component_write(component, ES8316_RESET, 0x3f);
+	usleep_range(5000, 5500);
+	snd_soc_component_write(component, ES8316_RESET, ES8316_RESET_CSM_ON);
+	msleep(30);
+
+	/*
+	 * Documentation is unclear, but this value from the vendor driver is
+	 * needed otherwise audio output is silent.
+	 */
+	snd_soc_component_write(component, ES8316_SYS_VMIDSEL, 0xff);
+
+	/*
+	 * Documentation for this register is unclear and incomplete,
+	 * but here is a vendor-provided value that improves volume
+	 * and quality for Intel CHT platforms.
+	 */
+	snd_soc_component_write(component, ES8316_CLKMGR_ADCOSR, 0x32);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_es8316 = {
+	.probe			= es8316_probe,
+	.controls		= es8316_snd_controls,
+	.num_controls		= ARRAY_SIZE(es8316_snd_controls),
+	.dapm_widgets		= es8316_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(es8316_dapm_widgets),
+	.dapm_routes		= es8316_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(es8316_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config es8316_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = 0x53,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int es8316_i2c_probe(struct i2c_client *i2c_client,
+			    const struct i2c_device_id *id)
+{
+	struct es8316_priv *es8316;
+	struct regmap *regmap;
+
+	es8316 = devm_kzalloc(&i2c_client->dev, sizeof(struct es8316_priv),
+			      GFP_KERNEL);
+	if (es8316 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c_client, es8316);
+
+	regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return devm_snd_soc_register_component(&i2c_client->dev,
+				      &soc_component_dev_es8316,
+				      &es8316_dai, 1);
+}
+
+static const struct i2c_device_id es8316_i2c_id[] = {
+	{"es8316", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, es8316_i2c_id);
+
+static const struct of_device_id es8316_of_match[] = {
+	{ .compatible = "everest,es8316", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, es8316_of_match);
+
+static const struct acpi_device_id es8316_acpi_match[] = {
+	{"ESSX8316", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, es8316_acpi_match);
+
+static struct i2c_driver es8316_i2c_driver = {
+	.driver = {
+		.name			= "es8316",
+		.acpi_match_table	= ACPI_PTR(es8316_acpi_match),
+		.of_match_table		= of_match_ptr(es8316_of_match),
+	},
+	.probe		= es8316_i2c_probe,
+	.id_table	= es8316_i2c_id,
+};
+module_i2c_driver(es8316_i2c_driver);
+
+MODULE_DESCRIPTION("Everest Semi ES8316 ALSA SoC Codec Driver");
+MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/es8316.h b/sound/soc/codecs/es8316.h
new file mode 100644
index 0000000..6bcdd63
--- /dev/null
+++ b/sound/soc/codecs/es8316.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright Everest Semiconductor Co.,Ltd
+ *
+ * Author: David Yang <yangxiaohua@everest-semi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _ES8316_H
+#define _ES8316_H
+
+/*
+ * ES8316 register space
+ */
+
+/* Reset Control */
+#define ES8316_RESET		0x00
+
+/* Clock Management */
+#define ES8316_CLKMGR_CLKSW	0x01
+#define ES8316_CLKMGR_CLKSEL	0x02
+#define ES8316_CLKMGR_ADCOSR	0x03
+#define ES8316_CLKMGR_ADCDIV1	0x04
+#define ES8316_CLKMGR_ADCDIV2	0x05
+#define ES8316_CLKMGR_DACDIV1	0x06
+#define ES8316_CLKMGR_DACDIV2	0x07
+#define ES8316_CLKMGR_CPDIV	0x08
+
+/* Serial Data Port Control */
+#define ES8316_SERDATA1		0x09
+#define ES8316_SERDATA_ADC	0x0a
+#define ES8316_SERDATA_DAC	0x0b
+
+/* System Control */
+#define ES8316_SYS_VMIDSEL	0x0c
+#define ES8316_SYS_PDN		0x0d
+#define ES8316_SYS_LP1		0x0e
+#define ES8316_SYS_LP2		0x0f
+#define ES8316_SYS_VMIDLOW	0x10
+#define ES8316_SYS_VSEL		0x11
+#define ES8316_SYS_REF		0x12
+
+/* Headphone Mixer */
+#define ES8316_HPMIX_SEL	0x13
+#define ES8316_HPMIX_SWITCH	0x14
+#define ES8316_HPMIX_PDN	0x15
+#define ES8316_HPMIX_VOL	0x16
+
+/* Charge Pump Headphone driver */
+#define ES8316_CPHP_OUTEN	0x17
+#define ES8316_CPHP_ICAL_VOL	0x18
+#define ES8316_CPHP_PDN1	0x19
+#define ES8316_CPHP_PDN2	0x1a
+#define ES8316_CPHP_LDOCTL	0x1b
+
+/* Calibration */
+#define ES8316_CAL_TYPE		0x1c
+#define ES8316_CAL_SET		0x1d
+#define ES8316_CAL_HPLIV	0x1e
+#define ES8316_CAL_HPRIV	0x1f
+#define ES8316_CAL_HPLMV	0x20
+#define ES8316_CAL_HPRMV	0x21
+
+/* ADC Control */
+#define ES8316_ADC_PDN_LINSEL	0x22
+#define ES8316_ADC_PGAGAIN	0x23
+#define ES8316_ADC_D2SEPGA	0x24
+#define ES8316_ADC_DMIC		0x25
+#define ES8316_ADC_MUTE		0x26
+#define ES8316_ADC_VOLUME	0x27
+#define ES8316_ADC_ALC1		0x29
+#define ES8316_ADC_ALC2		0x2a
+#define ES8316_ADC_ALC3		0x2b
+#define ES8316_ADC_ALC4		0x2c
+#define ES8316_ADC_ALC5		0x2d
+#define ES8316_ADC_ALC_NG	0x2e
+
+/* DAC Control */
+#define ES8316_DAC_PDN		0x2f
+#define ES8316_DAC_SET1		0x30
+#define ES8316_DAC_SET2		0x31
+#define ES8316_DAC_SET3		0x32
+#define ES8316_DAC_VOLL		0x33
+#define ES8316_DAC_VOLR		0x34
+
+/* GPIO */
+#define ES8316_GPIO_SEL		0x4d
+#define ES8316_GPIO_DEBOUNCE	0x4e
+#define ES8316_GPIO_FLAG	0x4f
+
+/* Test mode */
+#define ES8316_TESTMODE		0x50
+#define ES8316_TEST1		0x51
+#define ES8316_TEST2		0x52
+#define ES8316_TEST3		0x53
+
+/*
+ * Field definitions
+ */
+
+/* ES8316_RESET */
+#define ES8316_RESET_CSM_ON		0x80
+
+/* ES8316_CLKMGR_CLKSW */
+#define ES8316_CLKMGR_CLKSW_MCLK_ON	0x40
+#define ES8316_CLKMGR_CLKSW_BCLK_ON	0x20
+
+/* ES8316_SERDATA1 */
+#define ES8316_SERDATA1_MASTER		0x80
+#define ES8316_SERDATA1_BCLK_INV	0x20
+
+/* ES8316_SERDATA_ADC and _DAC */
+#define ES8316_SERDATA2_FMT_MASK	0x3
+#define ES8316_SERDATA2_FMT_I2S		0x00
+#define ES8316_SERDATA2_FMT_LEFTJ	0x01
+#define ES8316_SERDATA2_FMT_RIGHTJ	0x02
+#define ES8316_SERDATA2_FMT_PCM		0x03
+#define ES8316_SERDATA2_ADCLRP		0x20
+#define ES8316_SERDATA2_LEN_MASK	0x1c
+#define ES8316_SERDATA2_LEN_24		0x00
+#define ES8316_SERDATA2_LEN_20		0x04
+#define ES8316_SERDATA2_LEN_18		0x08
+#define ES8316_SERDATA2_LEN_16		0x0c
+#define ES8316_SERDATA2_LEN_32		0x10
+
+#endif
diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c
new file mode 100644
index 0000000..19baa32
--- /dev/null
+++ b/sound/soc/codecs/es8328-i2c.c
@@ -0,0 +1,55 @@
+/*
+ * es8328-i2c.c  --  ES8328 ALSA SoC I2C Audio driver
+ *
+ * Copyright 2014 Sutajio Ko-Usagi PTE LTD
+ *
+ * Author: Sean Cross <xobs@kosagi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "es8328.h"
+
+static const struct i2c_device_id es8328_id[] = {
+	{ "es8328", 0 },
+	{ "es8388", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, es8328_id);
+
+static const struct of_device_id es8328_of_match[] = {
+	{ .compatible = "everest,es8328", },
+	{ .compatible = "everest,es8388", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, es8328_of_match);
+
+static int es8328_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	return es8328_probe(&i2c->dev,
+			devm_regmap_init_i2c(i2c, &es8328_regmap_config));
+}
+
+static struct i2c_driver es8328_i2c_driver = {
+	.driver = {
+		.name		= "es8328",
+		.of_match_table = es8328_of_match,
+	},
+	.probe    = es8328_i2c_probe,
+	.id_table = es8328_id,
+};
+
+module_i2c_driver(es8328_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ES8328 audio CODEC I2C driver");
+MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8328-spi.c b/sound/soc/codecs/es8328-spi.c
new file mode 100644
index 0000000..d242bd1
--- /dev/null
+++ b/sound/soc/codecs/es8328-spi.c
@@ -0,0 +1,42 @@
+/*
+ * es8328.c  --  ES8328 ALSA SoC SPI Audio driver
+ *
+ * Copyright 2014 Sutajio Ko-Usagi PTE LTD
+ *
+ * Author: Sean Cross <xobs@kosagi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+#include "es8328.h"
+
+static const struct of_device_id es8328_of_match[] = {
+	{ .compatible = "everest,es8328", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, es8328_of_match);
+
+static int es8328_spi_probe(struct spi_device *spi)
+{
+	return es8328_probe(&spi->dev,
+			devm_regmap_init_spi(spi, &es8328_regmap_config));
+}
+
+static struct spi_driver es8328_spi_driver = {
+	.driver = {
+		.name		= "es8328",
+		.of_match_table	= es8328_of_match,
+	},
+	.probe	= es8328_spi_probe,
+};
+
+module_spi_driver(es8328_spi_driver);
+MODULE_DESCRIPTION("ASoC ES8328 audio CODEC SPI driver");
+MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
new file mode 100644
index 0000000..e9fc2fd
--- /dev/null
+++ b/sound/soc/codecs/es8328.c
@@ -0,0 +1,884 @@
+/*
+ * es8328.c  --  ES8328 ALSA SoC Audio driver
+ *
+ * Copyright 2014 Sutajio Ko-Usagi PTE LTD
+ *
+ * Author: Sean Cross <xobs@kosagi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "es8328.h"
+
+static const unsigned int rates_12288[] = {
+	8000, 12000, 16000, 24000, 32000, 48000, 96000,
+};
+
+static const int ratios_12288[] = {
+	10, 7, 6, 4, 3, 2, 0,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_12288 = {
+	.count	= ARRAY_SIZE(rates_12288),
+	.list	= rates_12288,
+};
+
+static const unsigned int rates_11289[] = {
+	8018, 11025, 22050, 44100, 88200,
+};
+
+static const int ratios_11289[] = {
+	9, 7, 4, 2, 0,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_11289 = {
+	.count	= ARRAY_SIZE(rates_11289),
+	.list	= rates_11289,
+};
+
+/* regulator supplies for sgtl5000, VDDD is an optional external supply */
+enum sgtl5000_regulator_supplies {
+	DVDD,
+	AVDD,
+	PVDD,
+	HPVDD,
+	ES8328_SUPPLY_NUM
+};
+
+/* vddd is optional supply */
+static const char * const supply_names[ES8328_SUPPLY_NUM] = {
+	"DVDD",
+	"AVDD",
+	"PVDD",
+	"HPVDD",
+};
+
+#define ES8328_RATES (SNDRV_PCM_RATE_192000 | \
+		SNDRV_PCM_RATE_96000 | \
+		SNDRV_PCM_RATE_88200 | \
+		SNDRV_PCM_RATE_8000_48000)
+#define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+		SNDRV_PCM_FMTBIT_S18_3LE | \
+		SNDRV_PCM_FMTBIT_S20_3LE | \
+		SNDRV_PCM_FMTBIT_S24_LE | \
+		SNDRV_PCM_FMTBIT_S32_LE)
+
+struct es8328_priv {
+	struct regmap *regmap;
+	struct clk *clk;
+	int playback_fs;
+	bool deemph;
+	int mclkdiv2;
+	const struct snd_pcm_hw_constraint_list *sysclk_constraints;
+	const int *mclk_ratios;
+	bool master;
+	struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM];
+};
+
+/*
+ * ES8328 Controls
+ */
+
+static const char * const adcpol_txt[] = {"Normal", "L Invert", "R Invert",
+					  "L + R Invert"};
+static SOC_ENUM_SINGLE_DECL(adcpol,
+			    ES8328_ADCCONTROL6, 6, adcpol_txt);
+
+static const DECLARE_TLV_DB_SCALE(play_tlv, -3000, 100, 0);
+static const DECLARE_TLV_DB_SCALE(dac_adc_tlv, -9600, 50, 0);
+static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0);
+
+static const struct {
+	int rate;
+	unsigned int val;
+} deemph_settings[] = {
+	{ 0,     ES8328_DACCONTROL6_DEEMPH_OFF },
+	{ 32000, ES8328_DACCONTROL6_DEEMPH_32k },
+	{ 44100, ES8328_DACCONTROL6_DEEMPH_44_1k },
+	{ 48000, ES8328_DACCONTROL6_DEEMPH_48k },
+};
+
+static int es8328_set_deemph(struct snd_soc_component *component)
+{
+	struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
+	int val, i, best;
+
+	/*
+	 * If we're using deemphasis select the nearest available sample
+	 * rate.
+	 */
+	if (es8328->deemph) {
+		best = 0;
+		for (i = 1; i < ARRAY_SIZE(deemph_settings); i++) {
+			if (abs(deemph_settings[i].rate - es8328->playback_fs) <
+			    abs(deemph_settings[best].rate - es8328->playback_fs))
+				best = i;
+		}
+
+		val = deemph_settings[best].val;
+	} else {
+		val = ES8328_DACCONTROL6_DEEMPH_OFF;
+	}
+
+	dev_dbg(component->dev, "Set deemphasis %d\n", val);
+
+	return snd_soc_component_update_bits(component, ES8328_DACCONTROL6,
+			ES8328_DACCONTROL6_DEEMPH_MASK, val);
+}
+
+static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = es8328->deemph;
+	return 0;
+}
+
+static int es8328_put_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
+	unsigned int deemph = ucontrol->value.integer.value[0];
+	int ret;
+
+	if (deemph > 1)
+		return -EINVAL;
+
+	ret = es8328_set_deemph(component);
+	if (ret < 0)
+		return ret;
+
+	es8328->deemph = deemph;
+
+	return 0;
+}
+
+
+
+static const struct snd_kcontrol_new es8328_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("Capture Digital Volume",
+		ES8328_ADCCONTROL8, ES8328_ADCCONTROL9,
+		 0, 0xc0, 1, dac_adc_tlv),
+	SOC_SINGLE("Capture ZC Switch", ES8328_ADCCONTROL7, 6, 1, 0),
+
+	SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
+		    es8328_get_deemph, es8328_put_deemph),
+
+	SOC_ENUM("Capture Polarity", adcpol),
+
+	SOC_SINGLE_TLV("Left Mixer Left Bypass Volume",
+			ES8328_DACCONTROL17, 3, 7, 1, bypass_tlv),
+	SOC_SINGLE_TLV("Left Mixer Right Bypass Volume",
+			ES8328_DACCONTROL19, 3, 7, 1, bypass_tlv),
+	SOC_SINGLE_TLV("Right Mixer Left Bypass Volume",
+			ES8328_DACCONTROL18, 3, 7, 1, bypass_tlv),
+	SOC_SINGLE_TLV("Right Mixer Right Bypass Volume",
+			ES8328_DACCONTROL20, 3, 7, 1, bypass_tlv),
+
+	SOC_DOUBLE_R_TLV("PCM Volume",
+			ES8328_LDACVOL, ES8328_RDACVOL,
+			0, ES8328_DACVOL_MAX, 1, dac_adc_tlv),
+
+	SOC_DOUBLE_R_TLV("Output 1 Playback Volume",
+			ES8328_LOUT1VOL, ES8328_ROUT1VOL,
+			0, ES8328_OUT1VOL_MAX, 0, play_tlv),
+
+	SOC_DOUBLE_R_TLV("Output 2 Playback Volume",
+			ES8328_LOUT2VOL, ES8328_ROUT2VOL,
+			0, ES8328_OUT2VOL_MAX, 0, play_tlv),
+
+	SOC_DOUBLE_TLV("Mic PGA Volume", ES8328_ADCCONTROL1,
+			4, 0, 8, 0, mic_tlv),
+};
+
+/*
+ * DAPM Controls
+ */
+
+static const char * const es8328_line_texts[] = {
+	"Line 1", "Line 2", "PGA", "Differential"};
+
+static const struct soc_enum es8328_lline_enum =
+	SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 3,
+			      ARRAY_SIZE(es8328_line_texts),
+			      es8328_line_texts);
+static const struct snd_kcontrol_new es8328_left_line_controls =
+	SOC_DAPM_ENUM("Route", es8328_lline_enum);
+
+static const struct soc_enum es8328_rline_enum =
+	SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 0,
+			      ARRAY_SIZE(es8328_line_texts),
+			      es8328_line_texts);
+static const struct snd_kcontrol_new es8328_right_line_controls =
+	SOC_DAPM_ENUM("Route", es8328_lline_enum);
+
+/* Left Mixer */
+static const struct snd_kcontrol_new es8328_left_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 7, 1, 0),
+	SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 6, 1, 0),
+	SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 7, 1, 0),
+	SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 6, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new es8328_right_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 7, 1, 0),
+	SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 6, 1, 0),
+	SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 7, 1, 0),
+	SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 6, 1, 0),
+};
+
+static const char * const es8328_pga_sel[] = {
+	"Line 1", "Line 2", "Line 3", "Differential"};
+
+/* Left PGA Mux */
+static const struct soc_enum es8328_lpga_enum =
+	SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 6,
+			      ARRAY_SIZE(es8328_pga_sel),
+			      es8328_pga_sel);
+static const struct snd_kcontrol_new es8328_left_pga_controls =
+	SOC_DAPM_ENUM("Route", es8328_lpga_enum);
+
+/* Right PGA Mux */
+static const struct soc_enum es8328_rpga_enum =
+	SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 4,
+			      ARRAY_SIZE(es8328_pga_sel),
+			      es8328_pga_sel);
+static const struct snd_kcontrol_new es8328_right_pga_controls =
+	SOC_DAPM_ENUM("Route", es8328_rpga_enum);
+
+/* Differential Mux */
+static const char * const es8328_diff_sel[] = {"Line 1", "Line 2"};
+static SOC_ENUM_SINGLE_DECL(diffmux,
+			    ES8328_ADCCONTROL3, 7, es8328_diff_sel);
+static const struct snd_kcontrol_new es8328_diffmux_controls =
+	SOC_DAPM_ENUM("Route", diffmux);
+
+/* Mono ADC Mux */
+static const char * const es8328_mono_mux[] = {"Stereo", "Mono (Left)",
+	"Mono (Right)", "Digital Mono"};
+static SOC_ENUM_SINGLE_DECL(monomux,
+			    ES8328_ADCCONTROL3, 3, es8328_mono_mux);
+static const struct snd_kcontrol_new es8328_monomux_controls =
+	SOC_DAPM_ENUM("Route", monomux);
+
+static const struct snd_soc_dapm_widget es8328_dapm_widgets[] = {
+	SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+		&es8328_diffmux_controls),
+	SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
+		&es8328_monomux_controls),
+	SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
+		&es8328_monomux_controls),
+
+	SND_SOC_DAPM_MUX("Left PGA Mux", ES8328_ADCPOWER,
+			ES8328_ADCPOWER_AINL_OFF, 1,
+			&es8328_left_pga_controls),
+	SND_SOC_DAPM_MUX("Right PGA Mux", ES8328_ADCPOWER,
+			ES8328_ADCPOWER_AINR_OFF, 1,
+			&es8328_right_pga_controls),
+
+	SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
+		&es8328_left_line_controls),
+	SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
+		&es8328_right_line_controls),
+
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ES8328_ADCPOWER,
+			ES8328_ADCPOWER_ADCR_OFF, 1),
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ES8328_ADCPOWER,
+			ES8328_ADCPOWER_ADCL_OFF, 1),
+
+	SND_SOC_DAPM_SUPPLY("Mic Bias", ES8328_ADCPOWER,
+			ES8328_ADCPOWER_MIC_BIAS_OFF, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Bias Gen", ES8328_ADCPOWER,
+			ES8328_ADCPOWER_ADC_BIAS_GEN_OFF, 1, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DAC STM", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_DACSTM_RESET, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC STM", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_ADCSTM_RESET, 1, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DAC DIG", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_DACDIG_OFF, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC DIG", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_ADCDIG_OFF, 1, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DAC DLL", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_DACDLL_OFF, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC DLL", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_ADCDLL_OFF, 1, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC Vref", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_ADCVREF_OFF, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Vref", ES8328_CHIPPOWER,
+			ES8328_CHIPPOWER_DACVREF_OFF, 1, NULL, 0),
+
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", ES8328_DACPOWER,
+			ES8328_DACPOWER_RDAC_OFF, 1),
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8328_DACPOWER,
+			ES8328_DACPOWER_LDAC_OFF, 1),
+
+	SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+		&es8328_left_mixer_controls[0],
+		ARRAY_SIZE(es8328_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+		&es8328_right_mixer_controls[0],
+		ARRAY_SIZE(es8328_right_mixer_controls)),
+
+	SND_SOC_DAPM_PGA("Right Out 2", ES8328_DACPOWER,
+			ES8328_DACPOWER_ROUT2_ON, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 2", ES8328_DACPOWER,
+			ES8328_DACPOWER_LOUT2_ON, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Out 1", ES8328_DACPOWER,
+			ES8328_DACPOWER_ROUT1_ON, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 1", ES8328_DACPOWER,
+			ES8328_DACPOWER_LOUT1_ON, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("LOUT1"),
+	SND_SOC_DAPM_OUTPUT("ROUT1"),
+	SND_SOC_DAPM_OUTPUT("LOUT2"),
+	SND_SOC_DAPM_OUTPUT("ROUT2"),
+
+	SND_SOC_DAPM_INPUT("LINPUT1"),
+	SND_SOC_DAPM_INPUT("LINPUT2"),
+	SND_SOC_DAPM_INPUT("RINPUT1"),
+	SND_SOC_DAPM_INPUT("RINPUT2"),
+};
+
+static const struct snd_soc_dapm_route es8328_dapm_routes[] = {
+
+	{ "Left Line Mux", "Line 1", "LINPUT1" },
+	{ "Left Line Mux", "Line 2", "LINPUT2" },
+	{ "Left Line Mux", "PGA", "Left PGA Mux" },
+	{ "Left Line Mux", "Differential", "Differential Mux" },
+
+	{ "Right Line Mux", "Line 1", "RINPUT1" },
+	{ "Right Line Mux", "Line 2", "RINPUT2" },
+	{ "Right Line Mux", "PGA", "Right PGA Mux" },
+	{ "Right Line Mux", "Differential", "Differential Mux" },
+
+	{ "Left PGA Mux", "Line 1", "LINPUT1" },
+	{ "Left PGA Mux", "Line 2", "LINPUT2" },
+	{ "Left PGA Mux", "Differential", "Differential Mux" },
+
+	{ "Right PGA Mux", "Line 1", "RINPUT1" },
+	{ "Right PGA Mux", "Line 2", "RINPUT2" },
+	{ "Right PGA Mux", "Differential", "Differential Mux" },
+
+	{ "Differential Mux", "Line 1", "LINPUT1" },
+	{ "Differential Mux", "Line 1", "RINPUT1" },
+	{ "Differential Mux", "Line 2", "LINPUT2" },
+	{ "Differential Mux", "Line 2", "RINPUT2" },
+
+	{ "Left ADC Mux", "Stereo", "Left PGA Mux" },
+	{ "Left ADC Mux", "Mono (Left)", "Left PGA Mux" },
+	{ "Left ADC Mux", "Digital Mono", "Left PGA Mux" },
+
+	{ "Right ADC Mux", "Stereo", "Right PGA Mux" },
+	{ "Right ADC Mux", "Mono (Right)", "Right PGA Mux" },
+	{ "Right ADC Mux", "Digital Mono", "Right PGA Mux" },
+
+	{ "Left ADC", NULL, "Left ADC Mux" },
+	{ "Right ADC", NULL, "Right ADC Mux" },
+
+	{ "ADC DIG", NULL, "ADC STM" },
+	{ "ADC DIG", NULL, "ADC Vref" },
+	{ "ADC DIG", NULL, "ADC DLL" },
+
+	{ "Left ADC", NULL, "ADC DIG" },
+	{ "Right ADC", NULL, "ADC DIG" },
+
+	{ "Mic Bias", NULL, "Mic Bias Gen" },
+
+	{ "Left Line Mux", "Line 1", "LINPUT1" },
+	{ "Left Line Mux", "Line 2", "LINPUT2" },
+	{ "Left Line Mux", "PGA", "Left PGA Mux" },
+	{ "Left Line Mux", "Differential", "Differential Mux" },
+
+	{ "Right Line Mux", "Line 1", "RINPUT1" },
+	{ "Right Line Mux", "Line 2", "RINPUT2" },
+	{ "Right Line Mux", "PGA", "Right PGA Mux" },
+	{ "Right Line Mux", "Differential", "Differential Mux" },
+
+	{ "Left Out 1", NULL, "Left DAC" },
+	{ "Right Out 1", NULL, "Right DAC" },
+	{ "Left Out 2", NULL, "Left DAC" },
+	{ "Right Out 2", NULL, "Right DAC" },
+
+	{ "Left Mixer", "Playback Switch", "Left DAC" },
+	{ "Left Mixer", "Left Bypass Switch", "Left Line Mux" },
+	{ "Left Mixer", "Right Playback Switch", "Right DAC" },
+	{ "Left Mixer", "Right Bypass Switch", "Right Line Mux" },
+
+	{ "Right Mixer", "Left Playback Switch", "Left DAC" },
+	{ "Right Mixer", "Left Bypass Switch", "Left Line Mux" },
+	{ "Right Mixer", "Playback Switch", "Right DAC" },
+	{ "Right Mixer", "Right Bypass Switch", "Right Line Mux" },
+
+	{ "DAC DIG", NULL, "DAC STM" },
+	{ "DAC DIG", NULL, "DAC Vref" },
+	{ "DAC DIG", NULL, "DAC DLL" },
+
+	{ "Left DAC", NULL, "DAC DIG" },
+	{ "Right DAC", NULL, "DAC DIG" },
+
+	{ "Left Out 1", NULL, "Left Mixer" },
+	{ "LOUT1", NULL, "Left Out 1" },
+	{ "Right Out 1", NULL, "Right Mixer" },
+	{ "ROUT1", NULL, "Right Out 1" },
+
+	{ "Left Out 2", NULL, "Left Mixer" },
+	{ "LOUT2", NULL, "Left Out 2" },
+	{ "Right Out 2", NULL, "Right Mixer" },
+	{ "ROUT2", NULL, "Right Out 2" },
+};
+
+static int es8328_mute(struct snd_soc_dai *dai, int mute)
+{
+	return snd_soc_component_update_bits(dai->component, ES8328_DACCONTROL3,
+			ES8328_DACCONTROL3_DACMUTE,
+			mute ? ES8328_DACCONTROL3_DACMUTE : 0);
+}
+
+static int es8328_startup(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
+
+	if (es8328->master && es8328->sysclk_constraints)
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				es8328->sysclk_constraints);
+
+	return 0;
+}
+
+static int es8328_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
+	int i;
+	int reg;
+	int wl;
+	int ratio;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		reg = ES8328_DACCONTROL2;
+	else
+		reg = ES8328_ADCCONTROL5;
+
+	if (es8328->master) {
+		if (!es8328->sysclk_constraints) {
+			dev_err(component->dev, "No MCLK configured\n");
+			return -EINVAL;
+		}
+
+		for (i = 0; i < es8328->sysclk_constraints->count; i++)
+			if (es8328->sysclk_constraints->list[i] ==
+			    params_rate(params))
+				break;
+
+		if (i == es8328->sysclk_constraints->count) {
+			dev_err(component->dev,
+				"LRCLK %d unsupported with current clock\n",
+				params_rate(params));
+			return -EINVAL;
+		}
+		ratio = es8328->mclk_ratios[i];
+	} else {
+		ratio = 0;
+		es8328->mclkdiv2 = 0;
+	}
+
+	snd_soc_component_update_bits(component, ES8328_MASTERMODE,
+			ES8328_MASTERMODE_MCLKDIV2,
+			es8328->mclkdiv2 ? ES8328_MASTERMODE_MCLKDIV2 : 0);
+
+	switch (params_width(params)) {
+	case 16:
+		wl = 3;
+		break;
+	case 18:
+		wl = 2;
+		break;
+	case 20:
+		wl = 1;
+		break;
+	case 24:
+		wl = 0;
+		break;
+	case 32:
+		wl = 4;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		snd_soc_component_update_bits(component, ES8328_DACCONTROL1,
+				ES8328_DACCONTROL1_DACWL_MASK,
+				wl << ES8328_DACCONTROL1_DACWL_SHIFT);
+
+		es8328->playback_fs = params_rate(params);
+		es8328_set_deemph(component);
+	} else
+		snd_soc_component_update_bits(component, ES8328_ADCCONTROL4,
+				ES8328_ADCCONTROL4_ADCWL_MASK,
+				wl << ES8328_ADCCONTROL4_ADCWL_SHIFT);
+
+	return snd_soc_component_update_bits(component, reg, ES8328_RATEMASK, ratio);
+}
+
+static int es8328_set_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
+	int mclkdiv2 = 0;
+
+	switch (freq) {
+	case 0:
+		es8328->sysclk_constraints = NULL;
+		es8328->mclk_ratios = NULL;
+		break;
+	case 22579200:
+		mclkdiv2 = 1;
+		/* fallthru */
+	case 11289600:
+		es8328->sysclk_constraints = &constraints_11289;
+		es8328->mclk_ratios = ratios_11289;
+		break;
+	case 24576000:
+		mclkdiv2 = 1;
+		/* fallthru */
+	case 12288000:
+		es8328->sysclk_constraints = &constraints_12288;
+		es8328->mclk_ratios = ratios_12288;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	es8328->mclkdiv2 = mclkdiv2;
+	return 0;
+}
+
+static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct es8328_priv *es8328 = snd_soc_component_get_drvdata(component);
+	u8 dac_mode = 0;
+	u8 adc_mode = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* Master serial port mode, with BCLK generated automatically */
+		snd_soc_component_update_bits(component, ES8328_MASTERMODE,
+				    ES8328_MASTERMODE_MSC,
+				    ES8328_MASTERMODE_MSC);
+		es8328->master = true;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* Slave serial port mode */
+		snd_soc_component_update_bits(component, ES8328_MASTERMODE,
+				    ES8328_MASTERMODE_MSC, 0);
+		es8328->master = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		dac_mode |= ES8328_DACCONTROL1_DACFORMAT_I2S;
+		adc_mode |= ES8328_ADCCONTROL4_ADCFORMAT_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		dac_mode |= ES8328_DACCONTROL1_DACFORMAT_RJUST;
+		adc_mode |= ES8328_ADCCONTROL4_ADCFORMAT_RJUST;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		dac_mode |= ES8328_DACCONTROL1_DACFORMAT_LJUST;
+		adc_mode |= ES8328_ADCCONTROL4_ADCFORMAT_LJUST;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF)
+		return -EINVAL;
+
+	snd_soc_component_update_bits(component, ES8328_DACCONTROL1,
+			ES8328_DACCONTROL1_DACFORMAT_MASK, dac_mode);
+	snd_soc_component_update_bits(component, ES8328_ADCCONTROL4,
+			ES8328_ADCCONTROL4_ADCFORMAT_MASK, adc_mode);
+
+	return 0;
+}
+
+static int es8328_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* VREF, VMID=2x50k, digital enabled */
+		snd_soc_component_write(component, ES8328_CHIPPOWER, 0);
+		snd_soc_component_update_bits(component, ES8328_CONTROL1,
+				ES8328_CONTROL1_VMIDSEL_MASK |
+				ES8328_CONTROL1_ENREF,
+				ES8328_CONTROL1_VMIDSEL_50k |
+				ES8328_CONTROL1_ENREF);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_update_bits(component, ES8328_CONTROL1,
+					ES8328_CONTROL1_VMIDSEL_MASK |
+					ES8328_CONTROL1_ENREF,
+					ES8328_CONTROL1_VMIDSEL_5k |
+					ES8328_CONTROL1_ENREF);
+
+			/* Charge caps */
+			msleep(100);
+		}
+
+		snd_soc_component_write(component, ES8328_CONTROL2,
+				ES8328_CONTROL2_OVERCURRENT_ON |
+				ES8328_CONTROL2_THERMAL_SHUTDOWN_ON);
+
+		/* VREF, VMID=2*500k, digital stopped */
+		snd_soc_component_update_bits(component, ES8328_CONTROL1,
+				ES8328_CONTROL1_VMIDSEL_MASK |
+				ES8328_CONTROL1_ENREF,
+				ES8328_CONTROL1_VMIDSEL_500k |
+				ES8328_CONTROL1_ENREF);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, ES8328_CONTROL1,
+				ES8328_CONTROL1_VMIDSEL_MASK |
+				ES8328_CONTROL1_ENREF,
+				0);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops es8328_dai_ops = {
+	.startup	= es8328_startup,
+	.hw_params	= es8328_hw_params,
+	.digital_mute	= es8328_mute,
+	.set_sysclk	= es8328_set_sysclk,
+	.set_fmt	= es8328_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver es8328_dai = {
+	.name = "es8328-hifi-analog",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = ES8328_RATES,
+		.formats = ES8328_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = ES8328_RATES,
+		.formats = ES8328_FORMATS,
+	},
+	.ops = &es8328_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int es8328_suspend(struct snd_soc_component *component)
+{
+	struct es8328_priv *es8328;
+	int ret;
+
+	es8328 = snd_soc_component_get_drvdata(component);
+
+	clk_disable_unprepare(es8328->clk);
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
+			es8328->supplies);
+	if (ret) {
+		dev_err(component->dev, "unable to disable regulators\n");
+		return ret;
+	}
+	return 0;
+}
+
+static int es8328_resume(struct snd_soc_component *component)
+{
+	struct regmap *regmap = dev_get_regmap(component->dev, NULL);
+	struct es8328_priv *es8328;
+	int ret;
+
+	es8328 = snd_soc_component_get_drvdata(component);
+
+	ret = clk_prepare_enable(es8328->clk);
+	if (ret) {
+		dev_err(component->dev, "unable to enable clock\n");
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies),
+					es8328->supplies);
+	if (ret) {
+		dev_err(component->dev, "unable to enable regulators\n");
+		return ret;
+	}
+
+	regcache_mark_dirty(regmap);
+	ret = regcache_sync(regmap);
+	if (ret) {
+		dev_err(component->dev, "unable to sync regcache\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int es8328_component_probe(struct snd_soc_component *component)
+{
+	struct es8328_priv *es8328;
+	int ret;
+
+	es8328 = snd_soc_component_get_drvdata(component);
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies),
+					es8328->supplies);
+	if (ret) {
+		dev_err(component->dev, "unable to enable regulators\n");
+		return ret;
+	}
+
+	/* Setup clocks */
+	es8328->clk = devm_clk_get(component->dev, NULL);
+	if (IS_ERR(es8328->clk)) {
+		dev_err(component->dev, "codec clock missing or invalid\n");
+		ret = PTR_ERR(es8328->clk);
+		goto clk_fail;
+	}
+
+	ret = clk_prepare_enable(es8328->clk);
+	if (ret) {
+		dev_err(component->dev, "unable to prepare codec clk\n");
+		goto clk_fail;
+	}
+
+	return 0;
+
+clk_fail:
+	regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
+			       es8328->supplies);
+	return ret;
+}
+
+static void es8328_remove(struct snd_soc_component *component)
+{
+	struct es8328_priv *es8328;
+
+	es8328 = snd_soc_component_get_drvdata(component);
+
+	if (es8328->clk)
+		clk_disable_unprepare(es8328->clk);
+
+	regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
+			       es8328->supplies);
+}
+
+const struct regmap_config es8328_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= ES8328_REG_MAX,
+	.cache_type	= REGCACHE_RBTREE,
+	.use_single_rw	= true,
+};
+EXPORT_SYMBOL_GPL(es8328_regmap_config);
+
+static const struct snd_soc_component_driver es8328_component_driver = {
+	.probe			= es8328_component_probe,
+	.remove			= es8328_remove,
+	.suspend		= es8328_suspend,
+	.resume			= es8328_resume,
+	.set_bias_level		= es8328_set_bias_level,
+	.controls		= es8328_snd_controls,
+	.num_controls		= ARRAY_SIZE(es8328_snd_controls),
+	.dapm_widgets		= es8328_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(es8328_dapm_widgets),
+	.dapm_routes		= es8328_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(es8328_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+int es8328_probe(struct device *dev, struct regmap *regmap)
+{
+	struct es8328_priv *es8328;
+	int ret;
+	int i;
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	es8328 = devm_kzalloc(dev, sizeof(*es8328), GFP_KERNEL);
+	if (es8328 == NULL)
+		return -ENOMEM;
+
+	es8328->regmap = regmap;
+
+	for (i = 0; i < ARRAY_SIZE(es8328->supplies); i++)
+		es8328->supplies[i].supply = supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(es8328->supplies),
+				es8328->supplies);
+	if (ret) {
+		dev_err(dev, "unable to get regulators\n");
+		return ret;
+	}
+
+	dev_set_drvdata(dev, es8328);
+
+	return devm_snd_soc_register_component(dev,
+			&es8328_component_driver, &es8328_dai, 1);
+}
+EXPORT_SYMBOL_GPL(es8328_probe);
+
+MODULE_DESCRIPTION("ASoC ES8328 driver");
+MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8328.h b/sound/soc/codecs/es8328.h
new file mode 100644
index 0000000..9109f6b
--- /dev/null
+++ b/sound/soc/codecs/es8328.h
@@ -0,0 +1,290 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * es8328.h  --  ES8328 ALSA SoC Audio driver
+ */
+
+#ifndef _ES8328_H
+#define _ES8328_H
+
+#include <linux/regmap.h>
+
+struct device;
+
+extern const struct regmap_config es8328_regmap_config;
+int es8328_probe(struct device *dev, struct regmap *regmap);
+
+#define ES8328_DACLVOL 46
+#define ES8328_DACRVOL 47
+#define ES8328_DACCTL 28
+#define ES8328_RATEMASK (0x1f << 0)
+
+#define ES8328_CONTROL1		0x00
+#define ES8328_CONTROL1_VMIDSEL_OFF (0 << 0)
+#define ES8328_CONTROL1_VMIDSEL_50k (1 << 0)
+#define ES8328_CONTROL1_VMIDSEL_500k (2 << 0)
+#define ES8328_CONTROL1_VMIDSEL_5k (3 << 0)
+#define ES8328_CONTROL1_VMIDSEL_MASK (3 << 0)
+#define ES8328_CONTROL1_ENREF (1 << 2)
+#define ES8328_CONTROL1_SEQEN (1 << 3)
+#define ES8328_CONTROL1_SAMEFS (1 << 4)
+#define ES8328_CONTROL1_DACMCLK_ADC (0 << 5)
+#define ES8328_CONTROL1_DACMCLK_DAC (1 << 5)
+#define ES8328_CONTROL1_LRCM (1 << 6)
+#define ES8328_CONTROL1_SCP_RESET (1 << 7)
+
+#define ES8328_CONTROL2		0x01
+#define ES8328_CONTROL2_VREF_BUF_OFF (1 << 0)
+#define ES8328_CONTROL2_VREF_LOWPOWER (1 << 1)
+#define ES8328_CONTROL2_IBIASGEN_OFF (1 << 2)
+#define ES8328_CONTROL2_ANALOG_OFF (1 << 3)
+#define ES8328_CONTROL2_VREF_BUF_LOWPOWER (1 << 4)
+#define ES8328_CONTROL2_VCM_MOD_LOWPOWER (1 << 5)
+#define ES8328_CONTROL2_OVERCURRENT_ON (1 << 6)
+#define ES8328_CONTROL2_THERMAL_SHUTDOWN_ON (1 << 7)
+
+#define ES8328_CHIPPOWER	0x02
+#define ES8328_CHIPPOWER_DACVREF_OFF 0
+#define ES8328_CHIPPOWER_ADCVREF_OFF 1
+#define ES8328_CHIPPOWER_DACDLL_OFF 2
+#define ES8328_CHIPPOWER_ADCDLL_OFF 3
+#define ES8328_CHIPPOWER_DACSTM_RESET 4
+#define ES8328_CHIPPOWER_ADCSTM_RESET 5
+#define ES8328_CHIPPOWER_DACDIG_OFF 6
+#define ES8328_CHIPPOWER_ADCDIG_OFF 7
+
+#define ES8328_ADCPOWER		0x03
+#define ES8328_ADCPOWER_INT1_LOWPOWER 0
+#define ES8328_ADCPOWER_FLASH_ADC_LOWPOWER 1
+#define ES8328_ADCPOWER_ADC_BIAS_GEN_OFF 2
+#define ES8328_ADCPOWER_MIC_BIAS_OFF 3
+#define ES8328_ADCPOWER_ADCR_OFF 4
+#define ES8328_ADCPOWER_ADCL_OFF 5
+#define ES8328_ADCPOWER_AINR_OFF 6
+#define ES8328_ADCPOWER_AINL_OFF 7
+
+#define ES8328_DACPOWER		0x04
+#define ES8328_DACPOWER_OUT3_ON 0
+#define ES8328_DACPOWER_MONO_ON 1
+#define ES8328_DACPOWER_ROUT2_ON 2
+#define ES8328_DACPOWER_LOUT2_ON 3
+#define ES8328_DACPOWER_ROUT1_ON 4
+#define ES8328_DACPOWER_LOUT1_ON 5
+#define ES8328_DACPOWER_RDAC_OFF 6
+#define ES8328_DACPOWER_LDAC_OFF 7
+
+#define ES8328_CHIPLOPOW1	0x05
+#define ES8328_CHIPLOPOW2	0x06
+#define ES8328_ANAVOLMANAG	0x07
+
+#define ES8328_MASTERMODE	0x08
+#define ES8328_MASTERMODE_BCLKDIV (0 << 0)
+#define ES8328_MASTERMODE_BCLK_INV (1 << 5)
+#define ES8328_MASTERMODE_MCLKDIV2 (1 << 6)
+#define ES8328_MASTERMODE_MSC (1 << 7)
+
+#define ES8328_ADCCONTROL1	0x09
+#define ES8328_ADCCONTROL2	0x0a
+#define ES8328_ADCCONTROL3	0x0b
+
+#define ES8328_ADCCONTROL4	0x0c
+#define ES8328_ADCCONTROL4_ADCFORMAT_MASK (3 << 0)
+#define ES8328_ADCCONTROL4_ADCFORMAT_I2S (0 << 0)
+#define ES8328_ADCCONTROL4_ADCFORMAT_LJUST (1 << 0)
+#define ES8328_ADCCONTROL4_ADCFORMAT_RJUST (2 << 0)
+#define ES8328_ADCCONTROL4_ADCFORMAT_PCM (3 << 0)
+#define ES8328_ADCCONTROL4_ADCWL_SHIFT 2
+#define ES8328_ADCCONTROL4_ADCWL_MASK (7 << 2)
+#define ES8328_ADCCONTROL4_ADCLRP_I2S_POL_NORMAL (0 << 5)
+#define ES8328_ADCCONTROL4_ADCLRP_I2S_POL_INV (1 << 5)
+#define ES8328_ADCCONTROL4_ADCLRP_PCM_MSB_CLK2 (0 << 5)
+#define ES8328_ADCCONTROL4_ADCLRP_PCM_MSB_CLK1 (1 << 5)
+
+#define ES8328_ADCCONTROL5	0x0d
+#define ES8328_ADCCONTROL5_RATEMASK (0x1f << 0)
+
+#define ES8328_ADCCONTROL6	0x0e
+
+#define ES8328_ADCCONTROL7	0x0f
+#define ES8328_ADCCONTROL7_ADC_MUTE (1 << 2)
+#define ES8328_ADCCONTROL7_ADC_LER (1 << 3)
+#define ES8328_ADCCONTROL7_ADC_ZERO_CROSS (1 << 4)
+#define ES8328_ADCCONTROL7_ADC_SOFT_RAMP (1 << 5)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_4 (0 << 6)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_8 (1 << 6)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_16 (2 << 6)
+#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_32 (3 << 6)
+
+#define ES8328_ADCCONTROL8	0x10
+#define ES8328_ADCCONTROL9	0x11
+#define ES8328_ADCCONTROL10	0x12
+#define ES8328_ADCCONTROL11	0x13
+#define ES8328_ADCCONTROL12	0x14
+#define ES8328_ADCCONTROL13	0x15
+#define ES8328_ADCCONTROL14	0x16
+
+#define ES8328_DACCONTROL1	0x17
+#define ES8328_DACCONTROL1_DACFORMAT_MASK (3 << 1)
+#define ES8328_DACCONTROL1_DACFORMAT_I2S (0 << 1)
+#define ES8328_DACCONTROL1_DACFORMAT_LJUST (1 << 1)
+#define ES8328_DACCONTROL1_DACFORMAT_RJUST (2 << 1)
+#define ES8328_DACCONTROL1_DACFORMAT_PCM (3 << 1)
+#define ES8328_DACCONTROL1_DACWL_SHIFT 3
+#define ES8328_DACCONTROL1_DACWL_MASK (7 << 3)
+#define ES8328_DACCONTROL1_DACLRP_I2S_POL_NORMAL (0 << 6)
+#define ES8328_DACCONTROL1_DACLRP_I2S_POL_INV (1 << 6)
+#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK2 (0 << 6)
+#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK1 (1 << 6)
+#define ES8328_DACCONTROL1_LRSWAP (1 << 7)
+
+#define ES8328_DACCONTROL2	0x18
+#define ES8328_DACCONTROL2_RATEMASK (0x1f << 0)
+#define ES8328_DACCONTROL2_DOUBLESPEED (1 << 5)
+
+#define ES8328_DACCONTROL3	0x19
+#define ES8328_DACCONTROL3_AUTOMUTE (1 << 2)
+#define ES8328_DACCONTROL3_DACMUTE (1 << 2)
+#define ES8328_DACCONTROL3_LEFTGAINVOL (1 << 3)
+#define ES8328_DACCONTROL3_DACZEROCROSS (1 << 4)
+#define ES8328_DACCONTROL3_DACSOFTRAMP (1 << 5)
+#define ES8328_DACCONTROL3_DACRAMPRATE (3 << 6)
+
+#define ES8328_LDACVOL 0x1a
+#define ES8328_LDACVOL_MASK (0 << 0)
+#define ES8328_LDACVOL_MAX (0xc0)
+
+#define ES8328_RDACVOL 0x1b
+#define ES8328_RDACVOL_MASK (0 << 0)
+#define ES8328_RDACVOL_MAX (0xc0)
+
+#define ES8328_DACVOL_MAX (0xc0)
+
+#define ES8328_DACCONTROL4	0x1a
+#define ES8328_DACCONTROL5	0x1b
+
+#define ES8328_DACCONTROL6	0x1c
+#define ES8328_DACCONTROL6_CLICKFREE (1 << 3)
+#define ES8328_DACCONTROL6_DAC_INVR (1 << 4)
+#define ES8328_DACCONTROL6_DAC_INVL (1 << 5)
+#define ES8328_DACCONTROL6_DEEMPH_MASK (3 << 6)
+#define ES8328_DACCONTROL6_DEEMPH_OFF (0 << 6)
+#define ES8328_DACCONTROL6_DEEMPH_32k (1 << 6)
+#define ES8328_DACCONTROL6_DEEMPH_44_1k (2 << 6)
+#define ES8328_DACCONTROL6_DEEMPH_48k (3 << 6)
+
+#define ES8328_DACCONTROL7	0x1d
+#define ES8328_DACCONTROL7_VPP_SCALE_3p5	(0 << 0)
+#define ES8328_DACCONTROL7_VPP_SCALE_4p0	(1 << 0)
+#define ES8328_DACCONTROL7_VPP_SCALE_3p0	(2 << 0)
+#define ES8328_DACCONTROL7_VPP_SCALE_2p5	(3 << 0)
+#define ES8328_DACCONTROL7_SHELVING_STRENGTH (1 << 2) /* In eights */
+#define ES8328_DACCONTROL7_MONO		(1 << 5)
+#define ES8328_DACCONTROL7_ZEROR	(1 << 6)
+#define ES8328_DACCONTROL7_ZEROL	(1 << 7)
+
+/* Shelving filter */
+#define ES8328_DACCONTROL8	0x1e
+#define ES8328_DACCONTROL9	0x1f
+#define ES8328_DACCONTROL10	0x20
+#define ES8328_DACCONTROL11	0x21
+#define ES8328_DACCONTROL12	0x22
+#define ES8328_DACCONTROL13	0x23
+#define ES8328_DACCONTROL14	0x24
+#define ES8328_DACCONTROL15	0x25
+
+#define ES8328_DACCONTROL16	0x26
+#define ES8328_DACCONTROL16_RMIXSEL_RIN1 (0 << 0)
+#define ES8328_DACCONTROL16_RMIXSEL_RIN2 (1 << 0)
+#define ES8328_DACCONTROL16_RMIXSEL_RIN3 (2 << 0)
+#define ES8328_DACCONTROL16_RMIXSEL_RADC (3 << 0)
+#define ES8328_DACCONTROL16_LMIXSEL_LIN1 (0 << 3)
+#define ES8328_DACCONTROL16_LMIXSEL_LIN2 (1 << 3)
+#define ES8328_DACCONTROL16_LMIXSEL_LIN3 (2 << 3)
+#define ES8328_DACCONTROL16_LMIXSEL_LADC (3 << 3)
+
+#define ES8328_DACCONTROL17	0x27
+#define ES8328_DACCONTROL17_LI2LOVOL (7 << 3)
+#define ES8328_DACCONTROL17_LI2LO (1 << 6)
+#define ES8328_DACCONTROL17_LD2LO (1 << 7)
+
+#define ES8328_DACCONTROL18	0x28
+#define ES8328_DACCONTROL18_RI2LOVOL (7 << 3)
+#define ES8328_DACCONTROL18_RI2LO (1 << 6)
+#define ES8328_DACCONTROL18_RD2LO (1 << 7)
+
+#define ES8328_DACCONTROL19	0x29
+#define ES8328_DACCONTROL19_LI2ROVOL (7 << 3)
+#define ES8328_DACCONTROL19_LI2RO (1 << 6)
+#define ES8328_DACCONTROL19_LD2RO (1 << 7)
+
+#define ES8328_DACCONTROL20	0x2a
+#define ES8328_DACCONTROL20_RI2ROVOL (7 << 3)
+#define ES8328_DACCONTROL20_RI2RO (1 << 6)
+#define ES8328_DACCONTROL20_RD2RO (1 << 7)
+
+#define ES8328_DACCONTROL21	0x2b
+#define ES8328_DACCONTROL21_LI2MOVOL (7 << 3)
+#define ES8328_DACCONTROL21_LI2MO (1 << 6)
+#define ES8328_DACCONTROL21_LD2MO (1 << 7)
+
+#define ES8328_DACCONTROL22	0x2c
+#define ES8328_DACCONTROL22_RI2MOVOL (7 << 3)
+#define ES8328_DACCONTROL22_RI2MO (1 << 6)
+#define ES8328_DACCONTROL22_RD2MO (1 << 7)
+
+#define ES8328_DACCONTROL23	0x2d
+#define ES8328_DACCONTROL23_MOUTINV		(1 << 1)
+#define ES8328_DACCONTROL23_HPSWPOL		(1 << 2)
+#define ES8328_DACCONTROL23_HPSWEN		(1 << 3)
+#define ES8328_DACCONTROL23_VROI_1p5k		(0 << 4)
+#define ES8328_DACCONTROL23_VROI_40k		(1 << 4)
+#define ES8328_DACCONTROL23_OUT3_VREF		(0 << 5)
+#define ES8328_DACCONTROL23_OUT3_ROUT1		(1 << 5)
+#define ES8328_DACCONTROL23_OUT3_MONOOUT	(2 << 5)
+#define ES8328_DACCONTROL23_OUT3_RIGHT_MIXER	(3 << 5)
+#define ES8328_DACCONTROL23_ROUT2INV		(1 << 7)
+
+/* LOUT1 Amplifier */
+#define ES8328_LOUT1VOL 0x2e
+#define ES8328_LOUT1VOL_MASK (0 << 5)
+#define ES8328_LOUT1VOL_MAX (0x24)
+
+/* ROUT1 Amplifier */
+#define ES8328_ROUT1VOL 0x2f
+#define ES8328_ROUT1VOL_MASK (0 << 5)
+#define ES8328_ROUT1VOL_MAX (0x24)
+
+#define ES8328_OUT1VOL_MAX (0x24)
+
+/* LOUT2 Amplifier */
+#define ES8328_LOUT2VOL 0x30
+#define ES8328_LOUT2VOL_MASK (0 << 5)
+#define ES8328_LOUT2VOL_MAX (0x24)
+
+/* ROUT2 Amplifier */
+#define ES8328_ROUT2VOL 0x31
+#define ES8328_ROUT2VOL_MASK (0 << 5)
+#define ES8328_ROUT2VOL_MAX (0x24)
+
+#define ES8328_OUT2VOL_MAX (0x24)
+
+/* Mono Out Amplifier */
+#define ES8328_MONOOUTVOL 0x32
+#define ES8328_MONOOUTVOL_MASK (0 << 5)
+#define ES8328_MONOOUTVOL_MAX (0x24)
+
+#define ES8328_DACCONTROL29	0x33
+#define ES8328_DACCONTROL30	0x34
+
+#define ES8328_SYSCLK		0
+
+#define ES8328_REG_MAX		0x35
+
+#define ES8328_1536FS		1536
+#define ES8328_1024FS		1024
+#define ES8328_768FS		768
+#define ES8328_512FS		512
+#define ES8328_384FS		384
+#define ES8328_256FS		256
+#define ES8328_128FS		128
+
+#endif
diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c
new file mode 100644
index 0000000..c11ed60
--- /dev/null
+++ b/sound/soc/codecs/gtm601.c
@@ -0,0 +1,91 @@
+/*
+ * This is a simple driver for the GTM601 Voice PCM interface
+ *
+ * Copyright (C) 2015 Goldelico GmbH
+ *
+ * Author: Marek Belisko <marek@goldelico.com>
+ *
+ * Based on wm8727.c driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+static const struct snd_soc_dapm_widget gtm601_dapm_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("AOUT"),
+	SND_SOC_DAPM_INPUT("AIN"),
+};
+
+static const struct snd_soc_dapm_route gtm601_dapm_routes[] = {
+	{ "AOUT", NULL, "Playback" },
+	{ "Capture", NULL, "AIN" },
+};
+
+static struct snd_soc_dai_driver gtm601_dai = {
+	.name = "gtm601",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_gtm601 = {
+	.dapm_widgets		= gtm601_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(gtm601_dapm_widgets),
+	.dapm_routes		= gtm601_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(gtm601_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int gtm601_platform_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_gtm601, &gtm601_dai, 1);
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id gtm601_codec_of_match[] = {
+	{ .compatible = "option,gtm601", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, gtm601_codec_of_match);
+#endif
+
+static struct platform_driver gtm601_codec_driver = {
+	.driver = {
+		.name = "gtm601",
+		.of_match_table = of_match_ptr(gtm601_codec_of_match),
+	},
+	.probe = gtm601_platform_probe,
+};
+
+module_platform_driver(gtm601_codec_driver);
+
+MODULE_DESCRIPTION("ASoC gtm601 driver");
+MODULE_AUTHOR("Marek Belisko <marek@goldelico.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gtm601");
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
new file mode 100644
index 0000000..b61d518
--- /dev/null
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -0,0 +1,2289 @@
+/*
+ *  hdac_hdmi.c - ASoc HDA-HDMI codec driver for Intel platforms
+ *
+ *  Copyright (C) 2014-2015 Intel Corp
+ *  Author: Samreen Nilofer <samreen.nilofer@intel.com>
+ *	    Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/hdmi.h>
+#include <drm/drm_edid.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/hdaudio_ext.h>
+#include <sound/hda_i915.h>
+#include <sound/pcm_drm_eld.h>
+#include <sound/hda_chmap.h>
+#include "../../hda/local.h"
+#include "hdac_hdmi.h"
+
+#define NAME_SIZE	32
+
+#define AMP_OUT_MUTE		0xb080
+#define AMP_OUT_UNMUTE		0xb000
+#define PIN_OUT			(AC_PINCTL_OUT_EN)
+
+#define HDA_MAX_CONNECTIONS     32
+
+#define HDA_MAX_CVTS		3
+#define HDA_MAX_PORTS		3
+
+#define ELD_MAX_SIZE    256
+#define ELD_FIXED_BYTES	20
+
+#define ELD_VER_CEA_861D 2
+#define ELD_VER_PARTIAL 31
+#define ELD_MAX_MNL     16
+
+struct hdac_hdmi_cvt_params {
+	unsigned int channels_min;
+	unsigned int channels_max;
+	u32 rates;
+	u64 formats;
+	unsigned int maxbps;
+};
+
+struct hdac_hdmi_cvt {
+	struct list_head head;
+	hda_nid_t nid;
+	const char *name;
+	struct hdac_hdmi_cvt_params params;
+};
+
+/* Currently only spk_alloc, more to be added */
+struct hdac_hdmi_parsed_eld {
+	u8 spk_alloc;
+};
+
+struct hdac_hdmi_eld {
+	bool	monitor_present;
+	bool	eld_valid;
+	int	eld_size;
+	char    eld_buffer[ELD_MAX_SIZE];
+	struct	hdac_hdmi_parsed_eld info;
+};
+
+struct hdac_hdmi_pin {
+	struct list_head head;
+	hda_nid_t nid;
+	bool mst_capable;
+	struct hdac_hdmi_port *ports;
+	int num_ports;
+	struct hdac_device *hdev;
+};
+
+struct hdac_hdmi_port {
+	struct list_head head;
+	int id;
+	struct hdac_hdmi_pin *pin;
+	int num_mux_nids;
+	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+	struct hdac_hdmi_eld eld;
+	const char *jack_pin;
+	struct snd_soc_dapm_context *dapm;
+	const char *output_pin;
+};
+
+struct hdac_hdmi_pcm {
+	struct list_head head;
+	int pcm_id;
+	struct list_head port_list;
+	struct hdac_hdmi_cvt *cvt;
+	struct snd_soc_jack *jack;
+	int stream_tag;
+	int channels;
+	int format;
+	bool chmap_set;
+	unsigned char chmap[8]; /* ALSA API channel-map */
+	struct mutex lock;
+	int jack_event;
+};
+
+struct hdac_hdmi_dai_port_map {
+	int dai_id;
+	struct hdac_hdmi_port *port;
+	struct hdac_hdmi_cvt *cvt;
+};
+
+struct hdac_hdmi_drv_data {
+	unsigned int vendor_nid;
+};
+
+struct hdac_hdmi_priv {
+	struct hdac_device *hdev;
+	struct snd_soc_component *component;
+	struct snd_card *card;
+	struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS];
+	struct list_head pin_list;
+	struct list_head cvt_list;
+	struct list_head pcm_list;
+	int num_pin;
+	int num_cvt;
+	int num_ports;
+	struct mutex pin_mutex;
+	struct hdac_chmap chmap;
+	struct hdac_hdmi_drv_data *drv_data;
+	struct snd_soc_dai_driver *dai_drv;
+};
+
+#define hdev_to_hdmi_priv(_hdev) dev_get_drvdata(&(_hdev)->dev)
+
+static struct hdac_hdmi_pcm *
+hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi,
+			   struct hdac_hdmi_cvt *cvt)
+{
+	struct hdac_hdmi_pcm *pcm = NULL;
+
+	list_for_each_entry(pcm, &hdmi->pcm_list, head) {
+		if (pcm->cvt == cvt)
+			break;
+	}
+
+	return pcm;
+}
+
+static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm,
+		struct hdac_hdmi_port *port, bool is_connect)
+{
+	struct hdac_device *hdev = port->pin->hdev;
+
+	if (is_connect)
+		snd_soc_dapm_enable_pin(port->dapm, port->jack_pin);
+	else
+		snd_soc_dapm_disable_pin(port->dapm, port->jack_pin);
+
+	if (is_connect) {
+		/*
+		 * Report Jack connect event when a device is connected
+		 * for the first time where same PCM is attached to multiple
+		 * ports.
+		 */
+		if (pcm->jack_event == 0) {
+			dev_dbg(&hdev->dev,
+					"jack report for pcm=%d\n",
+					pcm->pcm_id);
+			snd_soc_jack_report(pcm->jack, SND_JACK_AVOUT,
+						SND_JACK_AVOUT);
+		}
+		pcm->jack_event++;
+	} else {
+		/*
+		 * Report Jack disconnect event when a device is disconnected
+		 * is the only last connected device when same PCM is attached
+		 * to multiple ports.
+		 */
+		if (pcm->jack_event == 1)
+			snd_soc_jack_report(pcm->jack, 0, SND_JACK_AVOUT);
+		if (pcm->jack_event > 0)
+			pcm->jack_event--;
+	}
+
+	snd_soc_dapm_sync(port->dapm);
+}
+
+/* MST supported verbs */
+/*
+ * Get the no devices that can be connected to a port on the Pin widget.
+ */
+static int hdac_hdmi_get_port_len(struct hdac_device *hdev, hda_nid_t nid)
+{
+	unsigned int caps;
+	unsigned int type, param;
+
+	caps = get_wcaps(hdev, nid);
+	type = get_wcaps_type(caps);
+
+	if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN))
+		return 0;
+
+	param = snd_hdac_read_parm_uncached(hdev, nid, AC_PAR_DEVLIST_LEN);
+	if (param == -1)
+		return param;
+
+	return param & AC_DEV_LIST_LEN_MASK;
+}
+
+/*
+ * Get the port entry select on the pin. Return the port entry
+ * id selected on the pin. Return 0 means the first port entry
+ * is selected or MST is not supported.
+ */
+static int hdac_hdmi_port_select_get(struct hdac_device *hdev,
+					struct hdac_hdmi_port *port)
+{
+	return snd_hdac_codec_read(hdev, port->pin->nid,
+				0, AC_VERB_GET_DEVICE_SEL, 0);
+}
+
+/*
+ * Sets the selected port entry for the configuring Pin widget verb.
+ * returns error if port set is not equal to port get otherwise success
+ */
+static int hdac_hdmi_port_select_set(struct hdac_device *hdev,
+					struct hdac_hdmi_port *port)
+{
+	int num_ports;
+
+	if (!port->pin->mst_capable)
+		return 0;
+
+	/* AC_PAR_DEVLIST_LEN is 0 based. */
+	num_ports = hdac_hdmi_get_port_len(hdev, port->pin->nid);
+	if (num_ports < 0)
+		return -EIO;
+	/*
+	 * Device List Length is a 0 based integer value indicating the
+	 * number of sink device that a MST Pin Widget can support.
+	 */
+	if (num_ports + 1  < port->id)
+		return 0;
+
+	snd_hdac_codec_write(hdev, port->pin->nid, 0,
+			AC_VERB_SET_DEVICE_SEL, port->id);
+
+	if (port->id != hdac_hdmi_port_select_get(hdev, port))
+		return -EIO;
+
+	dev_dbg(&hdev->dev, "Selected the port=%d\n", port->id);
+
+	return 0;
+}
+
+static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi,
+						int pcm_idx)
+{
+	struct hdac_hdmi_pcm *pcm;
+
+	list_for_each_entry(pcm, &hdmi->pcm_list, head) {
+		if (pcm->pcm_id == pcm_idx)
+			return pcm;
+	}
+
+	return NULL;
+}
+
+static unsigned int sad_format(const u8 *sad)
+{
+	return ((sad[0] >> 0x3) & 0x1f);
+}
+
+static unsigned int sad_sample_bits_lpcm(const u8 *sad)
+{
+	return (sad[2] & 7);
+}
+
+static int hdac_hdmi_eld_limit_formats(struct snd_pcm_runtime *runtime,
+						void *eld)
+{
+	u64 formats = SNDRV_PCM_FMTBIT_S16;
+	int i;
+	const u8 *sad, *eld_buf = eld;
+
+	sad = drm_eld_sad(eld_buf);
+	if (!sad)
+		goto format_constraint;
+
+	for (i = drm_eld_sad_count(eld_buf); i > 0; i--, sad += 3) {
+		if (sad_format(sad) == 1) { /* AUDIO_CODING_TYPE_LPCM */
+
+			/*
+			 * the controller support 20 and 24 bits in 32 bit
+			 * container so we set S32
+			 */
+			if (sad_sample_bits_lpcm(sad) & 0x6)
+				formats |= SNDRV_PCM_FMTBIT_S32;
+		}
+	}
+
+format_constraint:
+	return snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT,
+				formats);
+
+}
+
+static void
+hdac_hdmi_set_dip_index(struct hdac_device *hdev, hda_nid_t pin_nid,
+				int packet_index, int byte_index)
+{
+	int val;
+
+	val = (packet_index << 5) | (byte_index & 0x1f);
+	snd_hdac_codec_write(hdev, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
+}
+
+struct dp_audio_infoframe {
+	u8 type; /* 0x84 */
+	u8 len;  /* 0x1b */
+	u8 ver;  /* 0x11 << 2 */
+
+	u8 CC02_CT47;	/* match with HDMI infoframe from this on */
+	u8 SS01_SF24;
+	u8 CXT04;
+	u8 CA;
+	u8 LFEPBL01_LSV36_DM_INH7;
+};
+
+static int hdac_hdmi_setup_audio_infoframe(struct hdac_device *hdev,
+		   struct hdac_hdmi_pcm *pcm, struct hdac_hdmi_port *port)
+{
+	uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
+	struct hdmi_audio_infoframe frame;
+	struct hdac_hdmi_pin *pin = port->pin;
+	struct dp_audio_infoframe dp_ai;
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_cvt *cvt = pcm->cvt;
+	u8 *dip;
+	int ret;
+	int i;
+	const u8 *eld_buf;
+	u8 conn_type;
+	int channels, ca;
+
+	ca = snd_hdac_channel_allocation(hdev, port->eld.info.spk_alloc,
+			pcm->channels, pcm->chmap_set, true, pcm->chmap);
+
+	channels = snd_hdac_get_active_channels(ca);
+	hdmi->chmap.ops.set_channel_count(hdev, cvt->nid, channels);
+
+	snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca,
+				pcm->channels, pcm->chmap, pcm->chmap_set);
+
+	eld_buf = port->eld.eld_buffer;
+	conn_type = drm_eld_get_conn_type(eld_buf);
+
+	switch (conn_type) {
+	case DRM_ELD_CONN_TYPE_HDMI:
+		hdmi_audio_infoframe_init(&frame);
+
+		frame.channels = channels;
+		frame.channel_allocation = ca;
+
+		ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
+		if (ret < 0)
+			return ret;
+
+		break;
+
+	case DRM_ELD_CONN_TYPE_DP:
+		memset(&dp_ai, 0, sizeof(dp_ai));
+		dp_ai.type	= 0x84;
+		dp_ai.len	= 0x1b;
+		dp_ai.ver	= 0x11 << 2;
+		dp_ai.CC02_CT47	= channels - 1;
+		dp_ai.CA	= ca;
+
+		dip = (u8 *)&dp_ai;
+		break;
+
+	default:
+		dev_err(&hdev->dev, "Invalid connection type: %d\n", conn_type);
+		return -EIO;
+	}
+
+	/* stop infoframe transmission */
+	hdac_hdmi_set_dip_index(hdev, pin->nid, 0x0, 0x0);
+	snd_hdac_codec_write(hdev, pin->nid, 0,
+			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
+
+
+	/*  Fill infoframe. Index auto-incremented */
+	hdac_hdmi_set_dip_index(hdev, pin->nid, 0x0, 0x0);
+	if (conn_type == DRM_ELD_CONN_TYPE_HDMI) {
+		for (i = 0; i < sizeof(buffer); i++)
+			snd_hdac_codec_write(hdev, pin->nid, 0,
+				AC_VERB_SET_HDMI_DIP_DATA, buffer[i]);
+	} else {
+		for (i = 0; i < sizeof(dp_ai); i++)
+			snd_hdac_codec_write(hdev, pin->nid, 0,
+				AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
+	}
+
+	/* Start infoframe */
+	hdac_hdmi_set_dip_index(hdev, pin->nid, 0x0, 0x0);
+	snd_hdac_codec_write(hdev, pin->nid, 0,
+			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
+
+	return 0;
+}
+
+static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai,
+		unsigned int tx_mask, unsigned int rx_mask,
+		int slots, int slot_width)
+{
+	struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
+	struct hdac_device *hdev = hdmi->hdev;
+	struct hdac_hdmi_dai_port_map *dai_map;
+	struct hdac_hdmi_pcm *pcm;
+
+	dev_dbg(&hdev->dev, "%s: strm_tag: %d\n", __func__, tx_mask);
+
+	dai_map = &hdmi->dai_map[dai->id];
+
+	pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
+
+	if (pcm)
+		pcm->stream_tag = (tx_mask << 4);
+
+	return 0;
+}
+
+static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
+{
+	struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
+	struct hdac_device *hdev = hdmi->hdev;
+	struct hdac_hdmi_dai_port_map *dai_map;
+	struct hdac_hdmi_port *port;
+	struct hdac_hdmi_pcm *pcm;
+	int format;
+
+	dai_map = &hdmi->dai_map[dai->id];
+	port = dai_map->port;
+
+	if (!port)
+		return -ENODEV;
+
+	if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) {
+		dev_err(&hdev->dev,
+			"device is not configured for this pin:port%d:%d\n",
+					port->pin->nid, port->id);
+		return -ENODEV;
+	}
+
+	format = snd_hdac_calc_stream_format(params_rate(hparams),
+			params_channels(hparams), params_format(hparams),
+			dai->driver->playback.sig_bits, 0);
+
+	pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
+	if (!pcm)
+		return -EIO;
+
+	pcm->format = format;
+	pcm->channels = params_channels(hparams);
+
+	return 0;
+}
+
+static int hdac_hdmi_query_port_connlist(struct hdac_device *hdev,
+					struct hdac_hdmi_pin *pin,
+					struct hdac_hdmi_port *port)
+{
+	if (!(get_wcaps(hdev, pin->nid) & AC_WCAP_CONN_LIST)) {
+		dev_warn(&hdev->dev,
+			"HDMI: pin %d wcaps %#x does not support connection list\n",
+			pin->nid, get_wcaps(hdev, pin->nid));
+		return -EINVAL;
+	}
+
+	if (hdac_hdmi_port_select_set(hdev, port) < 0)
+		return -EIO;
+
+	port->num_mux_nids = snd_hdac_get_connections(hdev, pin->nid,
+			port->mux_nids, HDA_MAX_CONNECTIONS);
+	if (port->num_mux_nids == 0)
+		dev_warn(&hdev->dev,
+			"No connections found for pin:port %d:%d\n",
+						pin->nid, port->id);
+
+	dev_dbg(&hdev->dev, "num_mux_nids %d for pin:port %d:%d\n",
+			port->num_mux_nids, pin->nid, port->id);
+
+	return port->num_mux_nids;
+}
+
+/*
+ * Query pcm list and return port to which stream is routed.
+ *
+ * Also query connection list of the pin, to validate the cvt to port map.
+ *
+ * Same stream rendering to multiple ports simultaneously can be done
+ * possibly, but not supported for now in driver. So return the first port
+ * connected.
+ */
+static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
+			struct hdac_device *hdev,
+			struct hdac_hdmi_priv *hdmi,
+			struct hdac_hdmi_cvt *cvt)
+{
+	struct hdac_hdmi_pcm *pcm;
+	struct hdac_hdmi_port *port = NULL;
+	int ret, i;
+
+	list_for_each_entry(pcm, &hdmi->pcm_list, head) {
+		if (pcm->cvt == cvt) {
+			if (list_empty(&pcm->port_list))
+				continue;
+
+			list_for_each_entry(port, &pcm->port_list, head) {
+				mutex_lock(&pcm->lock);
+				ret = hdac_hdmi_query_port_connlist(hdev,
+							port->pin, port);
+				mutex_unlock(&pcm->lock);
+				if (ret < 0)
+					continue;
+
+				for (i = 0; i < port->num_mux_nids; i++) {
+					if (port->mux_nids[i] == cvt->nid &&
+						port->eld.monitor_present &&
+						port->eld.eld_valid)
+						return port;
+				}
+			}
+		}
+	}
+
+	return NULL;
+}
+
+/*
+ * This tries to get a valid pin and set the HW constraints based on the
+ * ELD. Even if a valid pin is not found return success so that device open
+ * doesn't fail.
+ */
+static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
+	struct hdac_device *hdev = hdmi->hdev;
+	struct hdac_hdmi_dai_port_map *dai_map;
+	struct hdac_hdmi_cvt *cvt;
+	struct hdac_hdmi_port *port;
+	int ret;
+
+	dai_map = &hdmi->dai_map[dai->id];
+
+	cvt = dai_map->cvt;
+	port = hdac_hdmi_get_port_from_cvt(hdev, hdmi, cvt);
+
+	/*
+	 * To make PA and other userland happy.
+	 * userland scans devices so returning error does not help.
+	 */
+	if (!port)
+		return 0;
+	if ((!port->eld.monitor_present) ||
+			(!port->eld.eld_valid)) {
+
+		dev_warn(&hdev->dev,
+			"Failed: present?:%d ELD valid?:%d pin:port: %d:%d\n",
+			port->eld.monitor_present, port->eld.eld_valid,
+			port->pin->nid, port->id);
+
+		return 0;
+	}
+
+	dai_map->port = port;
+
+	ret = hdac_hdmi_eld_limit_formats(substream->runtime,
+				port->eld.eld_buffer);
+	if (ret < 0)
+		return ret;
+
+	return snd_pcm_hw_constraint_eld(substream->runtime,
+				port->eld.eld_buffer);
+}
+
+static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
+	struct hdac_hdmi_dai_port_map *dai_map;
+	struct hdac_hdmi_pcm *pcm;
+
+	dai_map = &hdmi->dai_map[dai->id];
+
+	pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
+
+	if (pcm) {
+		mutex_lock(&pcm->lock);
+		pcm->chmap_set = false;
+		memset(pcm->chmap, 0, sizeof(pcm->chmap));
+		pcm->channels = 0;
+		mutex_unlock(&pcm->lock);
+	}
+
+	if (dai_map->port)
+		dai_map->port = NULL;
+}
+
+static int
+hdac_hdmi_query_cvt_params(struct hdac_device *hdev, struct hdac_hdmi_cvt *cvt)
+{
+	unsigned int chans;
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	int err;
+
+	chans = get_wcaps(hdev, cvt->nid);
+	chans = get_wcaps_channels(chans);
+
+	cvt->params.channels_min = 2;
+
+	cvt->params.channels_max = chans;
+	if (chans > hdmi->chmap.channels_max)
+		hdmi->chmap.channels_max = chans;
+
+	err = snd_hdac_query_supported_pcm(hdev, cvt->nid,
+			&cvt->params.rates,
+			&cvt->params.formats,
+			&cvt->params.maxbps);
+	if (err < 0)
+		dev_err(&hdev->dev,
+			"Failed to query pcm params for nid %d: %d\n",
+			cvt->nid, err);
+
+	return err;
+}
+
+static int hdac_hdmi_fill_widget_info(struct device *dev,
+		struct snd_soc_dapm_widget *w, enum snd_soc_dapm_type id,
+		void *priv, const char *wname, const char *stream,
+		struct snd_kcontrol_new *wc, int numkc,
+		int (*event)(struct snd_soc_dapm_widget *,
+		struct snd_kcontrol *, int), unsigned short event_flags)
+{
+	w->id = id;
+	w->name = devm_kstrdup(dev, wname, GFP_KERNEL);
+	if (!w->name)
+		return -ENOMEM;
+
+	w->sname = stream;
+	w->reg = SND_SOC_NOPM;
+	w->shift = 0;
+	w->kcontrol_news = wc;
+	w->num_kcontrols = numkc;
+	w->priv = priv;
+	w->event = event;
+	w->event_flags = event_flags;
+
+	return 0;
+}
+
+static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
+		const char *sink, const char *control, const char *src,
+		int (*handler)(struct snd_soc_dapm_widget *src,
+			struct snd_soc_dapm_widget *sink))
+{
+	route->sink = sink;
+	route->source = src;
+	route->control = control;
+	route->connected = handler;
+}
+
+static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_device *hdev,
+					struct hdac_hdmi_port *port)
+{
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_pcm *pcm = NULL;
+	struct hdac_hdmi_port *p;
+
+	list_for_each_entry(pcm, &hdmi->pcm_list, head) {
+		if (list_empty(&pcm->port_list))
+			continue;
+
+		list_for_each_entry(p, &pcm->port_list, head) {
+			if (p->id == port->id && port->pin == p->pin)
+				return pcm;
+		}
+	}
+
+	return NULL;
+}
+
+static void hdac_hdmi_set_power_state(struct hdac_device *hdev,
+			     hda_nid_t nid, unsigned int pwr_state)
+{
+	int count;
+	unsigned int state;
+
+	if (get_wcaps(hdev, nid) & AC_WCAP_POWER) {
+		if (!snd_hdac_check_power_state(hdev, nid, pwr_state)) {
+			for (count = 0; count < 10; count++) {
+				snd_hdac_codec_read(hdev, nid, 0,
+						AC_VERB_SET_POWER_STATE,
+						pwr_state);
+				state = snd_hdac_sync_power_state(hdev,
+						nid, pwr_state);
+				if (!(state & AC_PWRST_ERROR))
+					break;
+			}
+		}
+	}
+}
+
+static void hdac_hdmi_set_amp(struct hdac_device *hdev,
+				   hda_nid_t nid, int val)
+{
+	if (get_wcaps(hdev, nid) & AC_WCAP_OUT_AMP)
+		snd_hdac_codec_write(hdev, nid, 0,
+					AC_VERB_SET_AMP_GAIN_MUTE, val);
+}
+
+
+static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *kc, int event)
+{
+	struct hdac_hdmi_port *port = w->priv;
+	struct hdac_device *hdev = dev_to_hdac_dev(w->dapm->dev);
+	struct hdac_hdmi_pcm *pcm;
+
+	dev_dbg(&hdev->dev, "%s: widget: %s event: %x\n",
+			__func__, w->name, event);
+
+	pcm = hdac_hdmi_get_pcm(hdev, port);
+	if (!pcm)
+		return -EIO;
+
+	/* set the device if pin is mst_capable */
+	if (hdac_hdmi_port_select_set(hdev, port) < 0)
+		return -EIO;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		hdac_hdmi_set_power_state(hdev, port->pin->nid, AC_PWRST_D0);
+
+		/* Enable out path for this pin widget */
+		snd_hdac_codec_write(hdev, port->pin->nid, 0,
+				AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+		hdac_hdmi_set_amp(hdev, port->pin->nid, AMP_OUT_UNMUTE);
+
+		return hdac_hdmi_setup_audio_infoframe(hdev, pcm, port);
+
+	case SND_SOC_DAPM_POST_PMD:
+		hdac_hdmi_set_amp(hdev, port->pin->nid, AMP_OUT_MUTE);
+
+		/* Disable out path for this pin widget */
+		snd_hdac_codec_write(hdev, port->pin->nid, 0,
+				AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+
+		hdac_hdmi_set_power_state(hdev, port->pin->nid, AC_PWRST_D3);
+		break;
+
+	}
+
+	return 0;
+}
+
+static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *kc, int event)
+{
+	struct hdac_hdmi_cvt *cvt = w->priv;
+	struct hdac_device *hdev = dev_to_hdac_dev(w->dapm->dev);
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_pcm *pcm;
+
+	dev_dbg(&hdev->dev, "%s: widget: %s event: %x\n",
+			__func__, w->name, event);
+
+	pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, cvt);
+	if (!pcm)
+		return -EIO;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		hdac_hdmi_set_power_state(hdev, cvt->nid, AC_PWRST_D0);
+
+		/* Enable transmission */
+		snd_hdac_codec_write(hdev, cvt->nid, 0,
+			AC_VERB_SET_DIGI_CONVERT_1, 1);
+
+		/* Category Code (CC) to zero */
+		snd_hdac_codec_write(hdev, cvt->nid, 0,
+			AC_VERB_SET_DIGI_CONVERT_2, 0);
+
+		snd_hdac_codec_write(hdev, cvt->nid, 0,
+				AC_VERB_SET_CHANNEL_STREAMID, pcm->stream_tag);
+		snd_hdac_codec_write(hdev, cvt->nid, 0,
+				AC_VERB_SET_STREAM_FORMAT, pcm->format);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_hdac_codec_write(hdev, cvt->nid, 0,
+				AC_VERB_SET_CHANNEL_STREAMID, 0);
+		snd_hdac_codec_write(hdev, cvt->nid, 0,
+				AC_VERB_SET_STREAM_FORMAT, 0);
+
+		hdac_hdmi_set_power_state(hdev, cvt->nid, AC_PWRST_D3);
+		break;
+
+	}
+
+	return 0;
+}
+
+static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *kc, int event)
+{
+	struct hdac_hdmi_port *port = w->priv;
+	struct hdac_device *hdev = dev_to_hdac_dev(w->dapm->dev);
+	int mux_idx;
+
+	dev_dbg(&hdev->dev, "%s: widget: %s event: %x\n",
+			__func__, w->name, event);
+
+	if (!kc)
+		kc  = w->kcontrols[0];
+
+	mux_idx = dapm_kcontrol_get_value(kc);
+
+	/* set the device if pin is mst_capable */
+	if (hdac_hdmi_port_select_set(hdev, port) < 0)
+		return -EIO;
+
+	if (mux_idx > 0) {
+		snd_hdac_codec_write(hdev, port->pin->nid, 0,
+			AC_VERB_SET_CONNECT_SEL, (mux_idx - 1));
+	}
+
+	return 0;
+}
+
+/*
+ * Based on user selection, map the PINs with the PCMs.
+ */
+static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	int ret;
+	struct hdac_hdmi_port *p, *p_next;
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct hdac_hdmi_port *port = w->priv;
+	struct hdac_device *hdev = dev_to_hdac_dev(dapm->dev);
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_pcm *pcm = NULL;
+	const char *cvt_name =  e->texts[ucontrol->value.enumerated.item[0]];
+
+	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+	if (ret < 0)
+		return ret;
+
+	if (port == NULL)
+		return -EINVAL;
+
+	mutex_lock(&hdmi->pin_mutex);
+	list_for_each_entry(pcm, &hdmi->pcm_list, head) {
+		if (list_empty(&pcm->port_list))
+			continue;
+
+		list_for_each_entry_safe(p, p_next, &pcm->port_list, head) {
+			if (p == port && p->id == port->id &&
+					p->pin == port->pin) {
+				hdac_hdmi_jack_report(pcm, port, false);
+				list_del(&p->head);
+			}
+		}
+	}
+
+	/*
+	 * Jack status is not reported during device probe as the
+	 * PCMs are not registered by then. So report it here.
+	 */
+	list_for_each_entry(pcm, &hdmi->pcm_list, head) {
+		if (!strcmp(cvt_name, pcm->cvt->name)) {
+			list_add_tail(&port->head, &pcm->port_list);
+			if (port->eld.monitor_present && port->eld.eld_valid) {
+				hdac_hdmi_jack_report(pcm, port, true);
+				mutex_unlock(&hdmi->pin_mutex);
+				return ret;
+			}
+		}
+	}
+	mutex_unlock(&hdmi->pin_mutex);
+
+	return ret;
+}
+
+/*
+ * Ideally the Mux inputs should be based on the num_muxs enumerated, but
+ * the display driver seem to be programming the connection list for the pin
+ * widget runtime.
+ *
+ * So programming all the possible inputs for the mux, the user has to take
+ * care of selecting the right one and leaving all other inputs selected to
+ * "NONE"
+ */
+static int hdac_hdmi_create_pin_port_muxs(struct hdac_device *hdev,
+				struct hdac_hdmi_port *port,
+				struct snd_soc_dapm_widget *widget,
+				const char *widget_name)
+{
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_pin *pin = port->pin;
+	struct snd_kcontrol_new *kc;
+	struct hdac_hdmi_cvt *cvt;
+	struct soc_enum *se;
+	char kc_name[NAME_SIZE];
+	char mux_items[NAME_SIZE];
+	/* To hold inputs to the Pin mux */
+	char *items[HDA_MAX_CONNECTIONS];
+	int i = 0;
+	int num_items = hdmi->num_cvt + 1;
+
+	kc = devm_kzalloc(&hdev->dev, sizeof(*kc), GFP_KERNEL);
+	if (!kc)
+		return -ENOMEM;
+
+	se = devm_kzalloc(&hdev->dev, sizeof(*se), GFP_KERNEL);
+	if (!se)
+		return -ENOMEM;
+
+	snprintf(kc_name, NAME_SIZE, "Pin %d port %d Input",
+						pin->nid, port->id);
+	kc->name = devm_kstrdup(&hdev->dev, kc_name, GFP_KERNEL);
+	if (!kc->name)
+		return -ENOMEM;
+
+	kc->private_value = (long)se;
+	kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	kc->access = 0;
+	kc->info = snd_soc_info_enum_double;
+	kc->put = hdac_hdmi_set_pin_port_mux;
+	kc->get = snd_soc_dapm_get_enum_double;
+
+	se->reg = SND_SOC_NOPM;
+
+	/* enum texts: ["NONE", "cvt #", "cvt #", ...] */
+	se->items = num_items;
+	se->mask = roundup_pow_of_two(se->items) - 1;
+
+	sprintf(mux_items, "NONE");
+	items[i] = devm_kstrdup(&hdev->dev, mux_items, GFP_KERNEL);
+	if (!items[i])
+		return -ENOMEM;
+
+	list_for_each_entry(cvt, &hdmi->cvt_list, head) {
+		i++;
+		sprintf(mux_items, "cvt %d", cvt->nid);
+		items[i] = devm_kstrdup(&hdev->dev, mux_items, GFP_KERNEL);
+		if (!items[i])
+			return -ENOMEM;
+	}
+
+	se->texts = devm_kmemdup(&hdev->dev, items,
+			(num_items  * sizeof(char *)), GFP_KERNEL);
+	if (!se->texts)
+		return -ENOMEM;
+
+	return hdac_hdmi_fill_widget_info(&hdev->dev, widget,
+			snd_soc_dapm_mux, port, widget_name, NULL, kc, 1,
+			hdac_hdmi_pin_mux_widget_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_REG);
+}
+
+/* Add cvt <- input <- mux route map */
+static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_device *hdev,
+			struct snd_soc_dapm_widget *widgets,
+			struct snd_soc_dapm_route *route, int rindex)
+{
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	const struct snd_kcontrol_new *kc;
+	struct soc_enum *se;
+	int mux_index = hdmi->num_cvt + hdmi->num_ports;
+	int i, j;
+
+	for (i = 0; i < hdmi->num_ports; i++) {
+		kc = widgets[mux_index].kcontrol_news;
+		se = (struct soc_enum *)kc->private_value;
+		for (j = 0; j < hdmi->num_cvt; j++) {
+			hdac_hdmi_fill_route(&route[rindex],
+					widgets[mux_index].name,
+					se->texts[j + 1],
+					widgets[j].name, NULL);
+
+			rindex++;
+		}
+
+		mux_index++;
+	}
+}
+
+/*
+ * Widgets are added in the below sequence
+ *	Converter widgets for num converters enumerated
+ *	Pin-port widgets for num ports for Pins enumerated
+ *	Pin-port mux widgets to represent connenction list of pin widget
+ *
+ * For each port, one Mux and One output widget is added
+ * Total widgets elements = num_cvt + (num_ports * 2);
+ *
+ * Routes are added as below:
+ *	pin-port mux -> pin (based on num_ports)
+ *	cvt -> "Input sel control" -> pin-port_mux
+ *
+ * Total route elements:
+ *	num_ports + (pin_muxes * num_cvt)
+ */
+static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
+{
+	struct snd_soc_dapm_widget *widgets;
+	struct snd_soc_dapm_route *route;
+	struct hdac_device *hdev = dev_to_hdac_dev(dapm->dev);
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct snd_soc_dai_driver *dai_drv = hdmi->dai_drv;
+	char widget_name[NAME_SIZE];
+	struct hdac_hdmi_cvt *cvt;
+	struct hdac_hdmi_pin *pin;
+	int ret, i = 0, num_routes = 0, j;
+
+	if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
+		return -EINVAL;
+
+	widgets = devm_kzalloc(dapm->dev, (sizeof(*widgets) *
+				((2 * hdmi->num_ports) + hdmi->num_cvt)),
+				GFP_KERNEL);
+
+	if (!widgets)
+		return -ENOMEM;
+
+	/* DAPM widgets to represent each converter widget */
+	list_for_each_entry(cvt, &hdmi->cvt_list, head) {
+		sprintf(widget_name, "Converter %d", cvt->nid);
+		ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
+			snd_soc_dapm_aif_in, cvt,
+			widget_name, dai_drv[i].playback.stream_name, NULL, 0,
+			hdac_hdmi_cvt_output_widget_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
+		if (ret < 0)
+			return ret;
+		i++;
+	}
+
+	list_for_each_entry(pin, &hdmi->pin_list, head) {
+		for (j = 0; j < pin->num_ports; j++) {
+			sprintf(widget_name, "hif%d-%d Output",
+				pin->nid, pin->ports[j].id);
+			ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
+					snd_soc_dapm_output, &pin->ports[j],
+					widget_name, NULL, NULL, 0,
+					hdac_hdmi_pin_output_widget_event,
+					SND_SOC_DAPM_PRE_PMU |
+					SND_SOC_DAPM_POST_PMD);
+			if (ret < 0)
+				return ret;
+			pin->ports[j].output_pin = widgets[i].name;
+			i++;
+		}
+	}
+
+	/* DAPM widgets to represent the connection list to pin widget */
+	list_for_each_entry(pin, &hdmi->pin_list, head) {
+		for (j = 0; j < pin->num_ports; j++) {
+			sprintf(widget_name, "Pin%d-Port%d Mux",
+				pin->nid, pin->ports[j].id);
+			ret = hdac_hdmi_create_pin_port_muxs(hdev,
+						&pin->ports[j], &widgets[i],
+						widget_name);
+			if (ret < 0)
+				return ret;
+			i++;
+
+			/* For cvt to pin_mux mapping */
+			num_routes += hdmi->num_cvt;
+
+			/* For pin_mux to pin mapping */
+			num_routes++;
+		}
+	}
+
+	route = devm_kzalloc(dapm->dev, (sizeof(*route) * num_routes),
+							GFP_KERNEL);
+	if (!route)
+		return -ENOMEM;
+
+	i = 0;
+	/* Add pin <- NULL <- mux route map */
+	list_for_each_entry(pin, &hdmi->pin_list, head) {
+		for (j = 0; j < pin->num_ports; j++) {
+			int sink_index = i + hdmi->num_cvt;
+			int src_index = sink_index + pin->num_ports *
+						hdmi->num_pin;
+
+			hdac_hdmi_fill_route(&route[i],
+				widgets[sink_index].name, NULL,
+				widgets[src_index].name, NULL);
+			i++;
+		}
+	}
+
+	hdac_hdmi_add_pinmux_cvt_route(hdev, widgets, route, i);
+
+	snd_soc_dapm_new_controls(dapm, widgets,
+		((2 * hdmi->num_ports) + hdmi->num_cvt));
+
+	snd_soc_dapm_add_routes(dapm, route, num_routes);
+	snd_soc_dapm_new_widgets(dapm->card);
+
+	return 0;
+
+}
+
+static int hdac_hdmi_init_dai_map(struct hdac_device *hdev)
+{
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_dai_port_map *dai_map;
+	struct hdac_hdmi_cvt *cvt;
+	int dai_id = 0;
+
+	if (list_empty(&hdmi->cvt_list))
+		return -EINVAL;
+
+	list_for_each_entry(cvt, &hdmi->cvt_list, head) {
+		dai_map = &hdmi->dai_map[dai_id];
+		dai_map->dai_id = dai_id;
+		dai_map->cvt = cvt;
+
+		dai_id++;
+
+		if (dai_id == HDA_MAX_CVTS) {
+			dev_warn(&hdev->dev,
+				"Max dais supported: %d\n", dai_id);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int hdac_hdmi_add_cvt(struct hdac_device *hdev, hda_nid_t nid)
+{
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_cvt *cvt;
+	char name[NAME_SIZE];
+
+	cvt = kzalloc(sizeof(*cvt), GFP_KERNEL);
+	if (!cvt)
+		return -ENOMEM;
+
+	cvt->nid = nid;
+	sprintf(name, "cvt %d", cvt->nid);
+	cvt->name = kstrdup(name, GFP_KERNEL);
+
+	list_add_tail(&cvt->head, &hdmi->cvt_list);
+	hdmi->num_cvt++;
+
+	return hdac_hdmi_query_cvt_params(hdev, cvt);
+}
+
+static int hdac_hdmi_parse_eld(struct hdac_device *hdev,
+			struct hdac_hdmi_port *port)
+{
+	unsigned int ver, mnl;
+
+	ver = (port->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK)
+						>> DRM_ELD_VER_SHIFT;
+
+	if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) {
+		dev_err(&hdev->dev, "HDMI: Unknown ELD version %d\n", ver);
+		return -EINVAL;
+	}
+
+	mnl = (port->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] &
+		DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT;
+
+	if (mnl > ELD_MAX_MNL) {
+		dev_err(&hdev->dev, "HDMI: MNL Invalid %d\n", mnl);
+		return -EINVAL;
+	}
+
+	port->eld.info.spk_alloc = port->eld.eld_buffer[DRM_ELD_SPEAKER];
+
+	return 0;
+}
+
+static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
+				    struct hdac_hdmi_port *port)
+{
+	struct hdac_device *hdev = pin->hdev;
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_pcm *pcm;
+	int size = 0;
+	int port_id = -1;
+
+	if (!hdmi)
+		return;
+
+	/*
+	 * In case of non MST pin, get_eld info API expectes port
+	 * to be -1.
+	 */
+	mutex_lock(&hdmi->pin_mutex);
+	port->eld.monitor_present = false;
+
+	if (pin->mst_capable)
+		port_id = port->id;
+
+	size = snd_hdac_acomp_get_eld(hdev, pin->nid, port_id,
+				&port->eld.monitor_present,
+				port->eld.eld_buffer,
+				ELD_MAX_SIZE);
+
+	if (size > 0) {
+		size = min(size, ELD_MAX_SIZE);
+		if (hdac_hdmi_parse_eld(hdev, port) < 0)
+			size = -EINVAL;
+	}
+
+	if (size > 0) {
+		port->eld.eld_valid = true;
+		port->eld.eld_size = size;
+	} else {
+		port->eld.eld_valid = false;
+		port->eld.eld_size = 0;
+	}
+
+	pcm = hdac_hdmi_get_pcm(hdev, port);
+
+	if (!port->eld.monitor_present || !port->eld.eld_valid) {
+
+		dev_err(&hdev->dev, "%s: disconnect for pin:port %d:%d\n",
+						__func__, pin->nid, port->id);
+
+		/*
+		 * PCMs are not registered during device probe, so don't
+		 * report jack here. It will be done in usermode mux
+		 * control select.
+		 */
+		if (pcm)
+			hdac_hdmi_jack_report(pcm, port, false);
+
+		mutex_unlock(&hdmi->pin_mutex);
+		return;
+	}
+
+	if (port->eld.monitor_present && port->eld.eld_valid) {
+		if (pcm)
+			hdac_hdmi_jack_report(pcm, port, true);
+
+		print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1,
+			  port->eld.eld_buffer, port->eld.eld_size, false);
+
+	}
+	mutex_unlock(&hdmi->pin_mutex);
+}
+
+static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi,
+				struct hdac_hdmi_pin *pin)
+{
+	struct hdac_hdmi_port *ports;
+	int max_ports = HDA_MAX_PORTS;
+	int i;
+
+	/*
+	 * FIXME: max_port may vary for each platform, so pass this as
+	 * as driver data or query from i915 interface when this API is
+	 * implemented.
+	 */
+
+	ports = kcalloc(max_ports, sizeof(*ports), GFP_KERNEL);
+	if (!ports)
+		return -ENOMEM;
+
+	for (i = 0; i < max_ports; i++) {
+		ports[i].id = i;
+		ports[i].pin = pin;
+	}
+	pin->ports = ports;
+	pin->num_ports = max_ports;
+	return 0;
+}
+
+static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid)
+{
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_pin *pin;
+	int ret;
+
+	pin = kzalloc(sizeof(*pin), GFP_KERNEL);
+	if (!pin)
+		return -ENOMEM;
+
+	pin->nid = nid;
+	pin->mst_capable = false;
+	pin->hdev = hdev;
+	ret = hdac_hdmi_add_ports(hdmi, pin);
+	if (ret < 0)
+		return ret;
+
+	list_add_tail(&pin->head, &hdmi->pin_list);
+	hdmi->num_pin++;
+	hdmi->num_ports += pin->num_ports;
+
+	return 0;
+}
+
+#define INTEL_VENDOR_NID 0x08
+#define INTEL_GLK_VENDOR_NID 0x0b
+#define INTEL_GET_VENDOR_VERB 0xf81
+#define INTEL_SET_VENDOR_VERB 0x781
+#define INTEL_EN_DP12			0x02 /* enable DP 1.2 features */
+#define INTEL_EN_ALL_PIN_CVTS	0x01 /* enable 2nd & 3rd pins and convertors */
+
+static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev)
+{
+	unsigned int vendor_param;
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	unsigned int vendor_nid = hdmi->drv_data->vendor_nid;
+
+	vendor_param = snd_hdac_codec_read(hdev, vendor_nid, 0,
+				INTEL_GET_VENDOR_VERB, 0);
+	if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
+		return;
+
+	vendor_param |= INTEL_EN_ALL_PIN_CVTS;
+	vendor_param = snd_hdac_codec_read(hdev, vendor_nid, 0,
+				INTEL_SET_VENDOR_VERB, vendor_param);
+	if (vendor_param == -1)
+		return;
+}
+
+static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdev)
+{
+	unsigned int vendor_param;
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	unsigned int vendor_nid = hdmi->drv_data->vendor_nid;
+
+	vendor_param = snd_hdac_codec_read(hdev, vendor_nid, 0,
+				INTEL_GET_VENDOR_VERB, 0);
+	if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
+		return;
+
+	/* enable DP1.2 mode */
+	vendor_param |= INTEL_EN_DP12;
+	vendor_param = snd_hdac_codec_read(hdev, vendor_nid, 0,
+				INTEL_SET_VENDOR_VERB, vendor_param);
+	if (vendor_param == -1)
+		return;
+
+}
+
+static const struct snd_soc_dai_ops hdmi_dai_ops = {
+	.startup = hdac_hdmi_pcm_open,
+	.shutdown = hdac_hdmi_pcm_close,
+	.hw_params = hdac_hdmi_set_hw_params,
+	.set_tdm_slot = hdac_hdmi_set_tdm_slot,
+};
+
+/*
+ * Each converter can support a stream independently. So a dai is created
+ * based on the number of converter queried.
+ */
+static int hdac_hdmi_create_dais(struct hdac_device *hdev,
+		struct snd_soc_dai_driver **dais,
+		struct hdac_hdmi_priv *hdmi, int num_dais)
+{
+	struct snd_soc_dai_driver *hdmi_dais;
+	struct hdac_hdmi_cvt *cvt;
+	char name[NAME_SIZE], dai_name[NAME_SIZE];
+	int i = 0;
+	u32 rates, bps;
+	unsigned int rate_max = 384000, rate_min = 8000;
+	u64 formats;
+	int ret;
+
+	hdmi_dais = devm_kzalloc(&hdev->dev,
+			(sizeof(*hdmi_dais) * num_dais),
+			GFP_KERNEL);
+	if (!hdmi_dais)
+		return -ENOMEM;
+
+	list_for_each_entry(cvt, &hdmi->cvt_list, head) {
+		ret = snd_hdac_query_supported_pcm(hdev, cvt->nid,
+					&rates,	&formats, &bps);
+		if (ret)
+			return ret;
+
+		sprintf(dai_name, "intel-hdmi-hifi%d", i+1);
+		hdmi_dais[i].name = devm_kstrdup(&hdev->dev,
+					dai_name, GFP_KERNEL);
+
+		if (!hdmi_dais[i].name)
+			return -ENOMEM;
+
+		snprintf(name, sizeof(name), "hifi%d", i+1);
+		hdmi_dais[i].playback.stream_name =
+				devm_kstrdup(&hdev->dev, name, GFP_KERNEL);
+		if (!hdmi_dais[i].playback.stream_name)
+			return -ENOMEM;
+
+		/*
+		 * Set caps based on capability queried from the converter.
+		 * It will be constrained runtime based on ELD queried.
+		 */
+		hdmi_dais[i].playback.formats = formats;
+		hdmi_dais[i].playback.rates = rates;
+		hdmi_dais[i].playback.rate_max = rate_max;
+		hdmi_dais[i].playback.rate_min = rate_min;
+		hdmi_dais[i].playback.channels_min = 2;
+		hdmi_dais[i].playback.channels_max = 2;
+		hdmi_dais[i].playback.sig_bits = bps;
+		hdmi_dais[i].ops = &hdmi_dai_ops;
+		i++;
+	}
+
+	*dais = hdmi_dais;
+	hdmi->dai_drv = hdmi_dais;
+
+	return 0;
+}
+
+/*
+ * Parse all nodes and store the cvt/pin nids in array
+ * Add one time initialization for pin and cvt widgets
+ */
+static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev,
+		struct snd_soc_dai_driver **dais, int *num_dais)
+{
+	hda_nid_t nid;
+	int i, num_nodes;
+	struct hdac_hdmi_cvt *temp_cvt, *cvt_next;
+	struct hdac_hdmi_pin *temp_pin, *pin_next;
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	int ret;
+
+	hdac_hdmi_skl_enable_all_pins(hdev);
+	hdac_hdmi_skl_enable_dp12(hdev);
+
+	num_nodes = snd_hdac_get_sub_nodes(hdev, hdev->afg, &nid);
+	if (!nid || num_nodes <= 0) {
+		dev_warn(&hdev->dev, "HDMI: failed to get afg sub nodes\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_nodes; i++, nid++) {
+		unsigned int caps;
+		unsigned int type;
+
+		caps = get_wcaps(hdev, nid);
+		type = get_wcaps_type(caps);
+
+		if (!(caps & AC_WCAP_DIGITAL))
+			continue;
+
+		switch (type) {
+
+		case AC_WID_AUD_OUT:
+			ret = hdac_hdmi_add_cvt(hdev, nid);
+			if (ret < 0)
+				goto free_widgets;
+			break;
+
+		case AC_WID_PIN:
+			ret = hdac_hdmi_add_pin(hdev, nid);
+			if (ret < 0)
+				goto free_widgets;
+			break;
+		}
+	}
+
+	if (!hdmi->num_pin || !hdmi->num_cvt) {
+		ret = -EIO;
+		goto free_widgets;
+	}
+
+	ret = hdac_hdmi_create_dais(hdev, dais, hdmi, hdmi->num_cvt);
+	if (ret) {
+		dev_err(&hdev->dev, "Failed to create dais with err: %d\n",
+							ret);
+		goto free_widgets;
+	}
+
+	*num_dais = hdmi->num_cvt;
+	ret = hdac_hdmi_init_dai_map(hdev);
+	if (ret < 0)
+		goto free_widgets;
+
+	return ret;
+
+free_widgets:
+	list_for_each_entry_safe(temp_cvt, cvt_next, &hdmi->cvt_list, head) {
+		list_del(&temp_cvt->head);
+		kfree(temp_cvt->name);
+		kfree(temp_cvt);
+	}
+
+	list_for_each_entry_safe(temp_pin, pin_next, &hdmi->pin_list, head) {
+		for (i = 0; i < temp_pin->num_ports; i++)
+			temp_pin->ports[i].pin = NULL;
+		kfree(temp_pin->ports);
+		list_del(&temp_pin->head);
+		kfree(temp_pin);
+	}
+
+	return ret;
+}
+
+static int hdac_hdmi_pin2port(void *aptr, int pin)
+{
+	return pin - 4; /* map NID 0x05 -> port #1 */
+}
+
+static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
+{
+	struct hdac_device *hdev = aptr;
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_pin *pin = NULL;
+	struct hdac_hdmi_port *hport = NULL;
+	struct snd_soc_component *component = hdmi->component;
+	int i;
+
+	/* Don't know how this mapping is derived */
+	hda_nid_t pin_nid = port + 0x04;
+
+	dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__,
+							pin_nid, pipe);
+
+	/*
+	 * skip notification during system suspend (but not in runtime PM);
+	 * the state will be updated at resume. Also since the ELD and
+	 * connection states are updated in anyway at the end of the resume,
+	 * we can skip it when received during PM process.
+	 */
+	if (snd_power_get_state(component->card->snd_card) !=
+			SNDRV_CTL_POWER_D0)
+		return;
+
+	if (atomic_read(&hdev->in_pm))
+		return;
+
+	list_for_each_entry(pin, &hdmi->pin_list, head) {
+		if (pin->nid != pin_nid)
+			continue;
+
+		/* In case of non MST pin, pipe is -1 */
+		if (pipe == -1) {
+			pin->mst_capable = false;
+			/* if not MST, default is port[0] */
+			hport = &pin->ports[0];
+		} else {
+			for (i = 0; i < pin->num_ports; i++) {
+				pin->mst_capable = true;
+				if (pin->ports[i].id == pipe) {
+					hport = &pin->ports[i];
+					break;
+				}
+			}
+		}
+
+		if (hport)
+			hdac_hdmi_present_sense(pin, hport);
+	}
+
+}
+
+static struct drm_audio_component_audio_ops aops = {
+	.pin2port	= hdac_hdmi_pin2port,
+	.pin_eld_notify	= hdac_hdmi_eld_notify_cb,
+};
+
+static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card,
+						int device)
+{
+	struct snd_soc_pcm_runtime *rtd;
+
+	list_for_each_entry(rtd, &card->rtd_list, list) {
+		if (rtd->pcm && (rtd->pcm->device == device))
+			return rtd->pcm;
+	}
+
+	return NULL;
+}
+
+/* create jack pin kcontrols */
+static int create_fill_jack_kcontrols(struct snd_soc_card *card,
+				    struct hdac_device *hdev)
+{
+	struct hdac_hdmi_pin *pin;
+	struct snd_kcontrol_new *kc;
+	char kc_name[NAME_SIZE], xname[NAME_SIZE];
+	char *name;
+	int i = 0, j;
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct snd_soc_component *component = hdmi->component;
+
+	kc = devm_kcalloc(component->dev, hdmi->num_ports,
+				sizeof(*kc), GFP_KERNEL);
+
+	if (!kc)
+		return -ENOMEM;
+
+	list_for_each_entry(pin, &hdmi->pin_list, head) {
+		for (j = 0; j < pin->num_ports; j++) {
+			snprintf(xname, sizeof(xname), "hif%d-%d Jack",
+						pin->nid, pin->ports[j].id);
+			name = devm_kstrdup(component->dev, xname, GFP_KERNEL);
+			if (!name)
+				return -ENOMEM;
+			snprintf(kc_name, sizeof(kc_name), "%s Switch", xname);
+			kc[i].name = devm_kstrdup(component->dev, kc_name,
+							GFP_KERNEL);
+			if (!kc[i].name)
+				return -ENOMEM;
+
+			kc[i].private_value = (unsigned long)name;
+			kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+			kc[i].access = 0;
+			kc[i].info = snd_soc_dapm_info_pin_switch;
+			kc[i].put = snd_soc_dapm_put_pin_switch;
+			kc[i].get = snd_soc_dapm_get_pin_switch;
+			i++;
+		}
+	}
+
+	return snd_soc_add_card_controls(card, kc, i);
+}
+
+int hdac_hdmi_jack_port_init(struct snd_soc_component *component,
+			struct snd_soc_dapm_context *dapm)
+{
+	struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
+	struct hdac_device *hdev = hdmi->hdev;
+	struct hdac_hdmi_pin *pin;
+	struct snd_soc_dapm_widget *widgets;
+	struct snd_soc_dapm_route *route;
+	char w_name[NAME_SIZE];
+	int i = 0, j, ret;
+
+	widgets = devm_kcalloc(dapm->dev, hdmi->num_ports,
+				sizeof(*widgets), GFP_KERNEL);
+
+	if (!widgets)
+		return -ENOMEM;
+
+	route = devm_kcalloc(dapm->dev, hdmi->num_ports,
+				sizeof(*route), GFP_KERNEL);
+	if (!route)
+		return -ENOMEM;
+
+	/* create Jack DAPM widget */
+	list_for_each_entry(pin, &hdmi->pin_list, head) {
+		for (j = 0; j < pin->num_ports; j++) {
+			snprintf(w_name, sizeof(w_name), "hif%d-%d Jack",
+						pin->nid, pin->ports[j].id);
+
+			ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
+					snd_soc_dapm_spk, NULL,
+					w_name, NULL, NULL, 0, NULL, 0);
+			if (ret < 0)
+				return ret;
+
+			pin->ports[j].jack_pin = widgets[i].name;
+			pin->ports[j].dapm = dapm;
+
+			/* add to route from Jack widget to output */
+			hdac_hdmi_fill_route(&route[i], pin->ports[j].jack_pin,
+					NULL, pin->ports[j].output_pin, NULL);
+
+			i++;
+		}
+	}
+
+	/* Add Route from Jack widget to the output widget */
+	ret = snd_soc_dapm_new_controls(dapm, widgets, hdmi->num_ports);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dapm_add_routes(dapm, route, hdmi->num_ports);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dapm_new_widgets(dapm->card);
+	if (ret < 0)
+		return ret;
+
+	/* Add Jack Pin switch Kcontrol */
+	ret = create_fill_jack_kcontrols(dapm->card, hdev);
+
+	if (ret < 0)
+		return ret;
+
+	/* default set the Jack Pin switch to OFF */
+	list_for_each_entry(pin, &hdmi->pin_list, head) {
+		for (j = 0; j < pin->num_ports; j++)
+			snd_soc_dapm_disable_pin(pin->ports[j].dapm,
+						pin->ports[j].jack_pin);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hdac_hdmi_jack_port_init);
+
+int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
+				struct snd_soc_jack *jack)
+{
+	struct snd_soc_component *component = dai->component;
+	struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
+	struct hdac_device *hdev = hdmi->hdev;
+	struct hdac_hdmi_pcm *pcm;
+	struct snd_pcm *snd_pcm;
+	int err;
+
+	/*
+	 * this is a new PCM device, create new pcm and
+	 * add to the pcm list
+	 */
+	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
+	if (!pcm)
+		return -ENOMEM;
+	pcm->pcm_id = device;
+	pcm->cvt = hdmi->dai_map[dai->id].cvt;
+	pcm->jack_event = 0;
+	pcm->jack = jack;
+	mutex_init(&pcm->lock);
+	INIT_LIST_HEAD(&pcm->port_list);
+	snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device);
+	if (snd_pcm) {
+		err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap);
+		if (err < 0) {
+			dev_err(&hdev->dev,
+				"chmap control add failed with err: %d for pcm: %d\n",
+				err, device);
+			kfree(pcm);
+			return err;
+		}
+	}
+
+	list_add_tail(&pcm->head, &hdmi->pcm_list);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init);
+
+static void hdac_hdmi_present_sense_all_pins(struct hdac_device *hdev,
+			struct hdac_hdmi_priv *hdmi, bool detect_pin_caps)
+{
+	int i;
+	struct hdac_hdmi_pin *pin;
+
+	list_for_each_entry(pin, &hdmi->pin_list, head) {
+		if (detect_pin_caps) {
+
+			if (hdac_hdmi_get_port_len(hdev, pin->nid)  == 0)
+				pin->mst_capable = false;
+			else
+				pin->mst_capable = true;
+		}
+
+		for (i = 0; i < pin->num_ports; i++) {
+			if (!pin->mst_capable && i > 0)
+				continue;
+
+			hdac_hdmi_present_sense(pin, &pin->ports[i]);
+		}
+	}
+}
+
+static int hdmi_codec_probe(struct snd_soc_component *component)
+{
+	struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
+	struct hdac_device *hdev = hdmi->hdev;
+	struct snd_soc_dapm_context *dapm =
+		snd_soc_component_get_dapm(component);
+	struct hdac_ext_link *hlink = NULL;
+	int ret;
+
+	hdmi->component = component;
+
+	/*
+	 * hold the ref while we probe, also no need to drop the ref on
+	 * exit, we call pm_runtime_suspend() so that will do for us
+	 */
+	hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+	if (!hlink) {
+		dev_err(&hdev->dev, "hdac link not found\n");
+		return -EIO;
+	}
+
+	snd_hdac_ext_bus_link_get(hdev->bus, hlink);
+
+	ret = create_fill_widget_route_map(dapm);
+	if (ret < 0)
+		return ret;
+
+	aops.audio_ptr = hdev;
+	ret = snd_hdac_acomp_register_notifier(hdev->bus, &aops);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "notifier register failed: err: %d\n", ret);
+		return ret;
+	}
+
+	hdac_hdmi_present_sense_all_pins(hdev, hdmi, true);
+	/* Imp: Store the card pointer in hda_codec */
+	hdmi->card = dapm->card->snd_card;
+
+	/*
+	 * hdac_device core already sets the state to active and calls
+	 * get_noresume. So enable runtime and set the device to suspend.
+	 */
+	pm_runtime_enable(&hdev->dev);
+	pm_runtime_put(&hdev->dev);
+	pm_runtime_suspend(&hdev->dev);
+
+	return 0;
+}
+
+static void hdmi_codec_remove(struct snd_soc_component *component)
+{
+	struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
+	struct hdac_device *hdev = hdmi->hdev;
+
+	pm_runtime_disable(&hdev->dev);
+}
+
+#ifdef CONFIG_PM
+static int hdmi_codec_prepare(struct device *dev)
+{
+	struct hdac_device *hdev = dev_to_hdac_dev(dev);
+
+	pm_runtime_get_sync(&hdev->dev);
+
+	/*
+	 * Power down afg.
+	 * codec_read is preferred over codec_write to set the power state.
+	 * This way verb is send to set the power state and response
+	 * is received. So setting power state is ensured without using loop
+	 * to read the state.
+	 */
+	snd_hdac_codec_read(hdev, hdev->afg, 0,	AC_VERB_SET_POWER_STATE,
+							AC_PWRST_D3);
+
+	return 0;
+}
+
+static void hdmi_codec_complete(struct device *dev)
+{
+	struct hdac_device *hdev = dev_to_hdac_dev(dev);
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+
+	/* Power up afg */
+	snd_hdac_codec_read(hdev, hdev->afg, 0,	AC_VERB_SET_POWER_STATE,
+							AC_PWRST_D0);
+
+	hdac_hdmi_skl_enable_all_pins(hdev);
+	hdac_hdmi_skl_enable_dp12(hdev);
+
+	/*
+	 * As the ELD notify callback request is not entertained while the
+	 * device is in suspend state. Need to manually check detection of
+	 * all pins here. pin capablity change is not support, so use the
+	 * already set pin caps.
+	 */
+	hdac_hdmi_present_sense_all_pins(hdev, hdmi, false);
+
+	pm_runtime_put_sync(&hdev->dev);
+}
+#else
+#define hdmi_codec_prepare NULL
+#define hdmi_codec_complete NULL
+#endif
+
+static const struct snd_soc_component_driver hdmi_hda_codec = {
+	.probe			= hdmi_codec_probe,
+	.remove			= hdmi_codec_remove,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static void hdac_hdmi_get_chmap(struct hdac_device *hdev, int pcm_idx,
+					unsigned char *chmap)
+{
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
+
+	memcpy(chmap, pcm->chmap, ARRAY_SIZE(pcm->chmap));
+}
+
+static void hdac_hdmi_set_chmap(struct hdac_device *hdev, int pcm_idx,
+				unsigned char *chmap, int prepared)
+{
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
+	struct hdac_hdmi_port *port;
+
+	if (!pcm)
+		return;
+
+	if (list_empty(&pcm->port_list))
+		return;
+
+	mutex_lock(&pcm->lock);
+	pcm->chmap_set = true;
+	memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap));
+	list_for_each_entry(port, &pcm->port_list, head)
+		if (prepared)
+			hdac_hdmi_setup_audio_infoframe(hdev, pcm, port);
+	mutex_unlock(&pcm->lock);
+}
+
+static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdev, int pcm_idx)
+{
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
+
+	if (!pcm)
+		return false;
+
+	if (list_empty(&pcm->port_list))
+		return false;
+
+	return true;
+}
+
+static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx)
+{
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
+	struct hdac_hdmi_port *port;
+
+	if (!pcm)
+		return 0;
+
+	if (list_empty(&pcm->port_list))
+		return 0;
+
+	port = list_first_entry(&pcm->port_list, struct hdac_hdmi_port, head);
+
+	if (!port)
+		return 0;
+
+	if (!port || !port->eld.eld_valid)
+		return 0;
+
+	return port->eld.info.spk_alloc;
+}
+
+static struct hdac_hdmi_drv_data intel_glk_drv_data  = {
+	.vendor_nid = INTEL_GLK_VENDOR_NID,
+};
+
+static struct hdac_hdmi_drv_data intel_drv_data  = {
+	.vendor_nid = INTEL_VENDOR_NID,
+};
+
+static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
+{
+	struct hdac_hdmi_priv *hdmi_priv = NULL;
+	struct snd_soc_dai_driver *hdmi_dais = NULL;
+	struct hdac_ext_link *hlink = NULL;
+	int num_dais = 0;
+	int ret = 0;
+	struct hdac_driver *hdrv = drv_to_hdac_driver(hdev->dev.driver);
+	const struct hda_device_id *hdac_id = hdac_get_device_id(hdev, hdrv);
+
+	/* hold the ref while we probe */
+	hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+	if (!hlink) {
+		dev_err(&hdev->dev, "hdac link not found\n");
+		return -EIO;
+	}
+
+	snd_hdac_ext_bus_link_get(hdev->bus, hlink);
+
+	hdmi_priv = devm_kzalloc(&hdev->dev, sizeof(*hdmi_priv), GFP_KERNEL);
+	if (hdmi_priv == NULL)
+		return -ENOMEM;
+
+	snd_hdac_register_chmap_ops(hdev, &hdmi_priv->chmap);
+	hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap;
+	hdmi_priv->chmap.ops.set_chmap = hdac_hdmi_set_chmap;
+	hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached;
+	hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
+	hdmi_priv->hdev = hdev;
+
+	if (!hdac_id)
+		return -ENODEV;
+
+	if (hdac_id->driver_data)
+		hdmi_priv->drv_data =
+			(struct hdac_hdmi_drv_data *)hdac_id->driver_data;
+	else
+		hdmi_priv->drv_data = &intel_drv_data;
+
+	dev_set_drvdata(&hdev->dev, hdmi_priv);
+
+	INIT_LIST_HEAD(&hdmi_priv->pin_list);
+	INIT_LIST_HEAD(&hdmi_priv->cvt_list);
+	INIT_LIST_HEAD(&hdmi_priv->pcm_list);
+	mutex_init(&hdmi_priv->pin_mutex);
+
+	/*
+	 * Turned off in the runtime_suspend during the first explicit
+	 * pm_runtime_suspend call.
+	 */
+	ret = snd_hdac_display_power(hdev->bus, true);
+	if (ret < 0) {
+		dev_err(&hdev->dev,
+			"Cannot turn on display power on i915 err: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = hdac_hdmi_parse_and_map_nid(hdev, &hdmi_dais, &num_dais);
+	if (ret < 0) {
+		dev_err(&hdev->dev,
+			"Failed in parse and map nid with err: %d\n", ret);
+		return ret;
+	}
+	snd_hdac_refresh_widgets(hdev, true);
+
+	/* ASoC specific initialization */
+	ret = devm_snd_soc_register_component(&hdev->dev, &hdmi_hda_codec,
+					hdmi_dais, num_dais);
+
+	snd_hdac_ext_bus_link_put(hdev->bus, hlink);
+
+	return ret;
+}
+
+static int hdac_hdmi_dev_remove(struct hdac_device *hdev)
+{
+	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+	struct hdac_hdmi_pin *pin, *pin_next;
+	struct hdac_hdmi_cvt *cvt, *cvt_next;
+	struct hdac_hdmi_pcm *pcm, *pcm_next;
+	struct hdac_hdmi_port *port, *port_next;
+	int i;
+
+	list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) {
+		pcm->cvt = NULL;
+		if (list_empty(&pcm->port_list))
+			continue;
+
+		list_for_each_entry_safe(port, port_next,
+					&pcm->port_list, head)
+			list_del(&port->head);
+
+		list_del(&pcm->head);
+		kfree(pcm);
+	}
+
+	list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) {
+		list_del(&cvt->head);
+		kfree(cvt->name);
+		kfree(cvt);
+	}
+
+	list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) {
+		for (i = 0; i < pin->num_ports; i++)
+			pin->ports[i].pin = NULL;
+		kfree(pin->ports);
+		list_del(&pin->head);
+		kfree(pin);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * Power management sequences
+ * ==========================
+ *
+ * The following explains the PM handling of HDAC HDMI with its parent
+ * device SKL and display power usage
+ *
+ * Probe
+ * -----
+ * In SKL probe,
+ * 1. skl_probe_work() powers up the display (refcount++ -> 1)
+ * 2. enumerates the codecs on the link
+ * 3. powers down the display  (refcount-- -> 0)
+ *
+ * In HDAC HDMI probe,
+ * 1. hdac_hdmi_dev_probe() powers up the display (refcount++ -> 1)
+ * 2. probe the codec
+ * 3. put the HDAC HDMI device to runtime suspend
+ * 4. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0)
+ *
+ * Once children are runtime suspended, SKL device also goes to runtime
+ * suspend
+ *
+ * HDMI Playback
+ * -------------
+ * Open HDMI device,
+ * 1. skl_runtime_resume() invoked
+ * 2. hdac_hdmi_runtime_resume() powers up the display (refcount++ -> 1)
+ *
+ * Close HDMI device,
+ * 1. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0)
+ * 2. skl_runtime_suspend() invoked
+ *
+ * S0/S3 Cycle with playback in progress
+ * -------------------------------------
+ * When the device is opened for playback, the device is runtime active
+ * already and the display refcount is 1 as explained above.
+ *
+ * Entering to S3,
+ * 1. hdmi_codec_prepare() invoke the runtime resume of codec which just
+ *    increments the PM runtime usage count of the codec since the device
+ *    is in use already
+ * 2. skl_suspend() powers down the display (refcount-- -> 0)
+ *
+ * Wakeup from S3,
+ * 1. skl_resume() powers up the display (refcount++ -> 1)
+ * 2. hdmi_codec_complete() invokes the runtime suspend of codec which just
+ *    decrements the PM runtime usage count of the codec since the device
+ *    is in use already
+ *
+ * Once playback is stopped, the display refcount is set to 0 as explained
+ * above in the HDMI playback sequence. The PM handlings are designed in
+ * such way that to balance the refcount of display power when the codec
+ * device put to S3 while playback is going on.
+ *
+ * S0/S3 Cycle without playback in progress
+ * ----------------------------------------
+ * Entering to S3,
+ * 1. hdmi_codec_prepare() invoke the runtime resume of codec
+ * 2. skl_runtime_resume() invoked
+ * 3. hdac_hdmi_runtime_resume() powers up the display (refcount++ -> 1)
+ * 4. skl_suspend() powers down the display (refcount-- -> 0)
+ *
+ * Wakeup from S3,
+ * 1. skl_resume() powers up the display (refcount++ -> 1)
+ * 2. hdmi_codec_complete() invokes the runtime suspend of codec
+ * 3. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0)
+ * 4. skl_runtime_suspend() invoked
+ */
+static int hdac_hdmi_runtime_suspend(struct device *dev)
+{
+	struct hdac_device *hdev = dev_to_hdac_dev(dev);
+	struct hdac_bus *bus = hdev->bus;
+	struct hdac_ext_link *hlink = NULL;
+	int err;
+
+	dev_dbg(dev, "Enter: %s\n", __func__);
+
+	/* controller may not have been initialized for the first time */
+	if (!bus)
+		return 0;
+
+	/*
+	 * Power down afg.
+	 * codec_read is preferred over codec_write to set the power state.
+	 * This way verb is send to set the power state and response
+	 * is received. So setting power state is ensured without using loop
+	 * to read the state.
+	 */
+	snd_hdac_codec_read(hdev, hdev->afg, 0,	AC_VERB_SET_POWER_STATE,
+							AC_PWRST_D3);
+
+	hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev));
+	if (!hlink) {
+		dev_err(dev, "hdac link not found\n");
+		return -EIO;
+	}
+
+	snd_hdac_ext_bus_link_put(bus, hlink);
+
+	err = snd_hdac_display_power(bus, false);
+	if (err < 0)
+		dev_err(dev, "Cannot turn off display power on i915\n");
+
+	return err;
+}
+
+static int hdac_hdmi_runtime_resume(struct device *dev)
+{
+	struct hdac_device *hdev = dev_to_hdac_dev(dev);
+	struct hdac_bus *bus = hdev->bus;
+	struct hdac_ext_link *hlink = NULL;
+	int err;
+
+	dev_dbg(dev, "Enter: %s\n", __func__);
+
+	/* controller may not have been initialized for the first time */
+	if (!bus)
+		return 0;
+
+	hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev));
+	if (!hlink) {
+		dev_err(dev, "hdac link not found\n");
+		return -EIO;
+	}
+
+	snd_hdac_ext_bus_link_get(bus, hlink);
+
+	err = snd_hdac_display_power(bus, true);
+	if (err < 0) {
+		dev_err(dev, "Cannot turn on display power on i915\n");
+		return err;
+	}
+
+	hdac_hdmi_skl_enable_all_pins(hdev);
+	hdac_hdmi_skl_enable_dp12(hdev);
+
+	/* Power up afg */
+	snd_hdac_codec_read(hdev, hdev->afg, 0,	AC_VERB_SET_POWER_STATE,
+							AC_PWRST_D0);
+
+	return 0;
+}
+#else
+#define hdac_hdmi_runtime_suspend NULL
+#define hdac_hdmi_runtime_resume NULL
+#endif
+
+static const struct dev_pm_ops hdac_hdmi_pm = {
+	SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
+	.prepare = hdmi_codec_prepare,
+	.complete = hdmi_codec_complete,
+};
+
+static const struct hda_device_id hdmi_list[] = {
+	HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
+	HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0),
+	HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0),
+	HDA_CODEC_EXT_ENTRY(0x8086280c, 0x100000, "Cannonlake HDMI",
+						   &intel_glk_drv_data),
+	HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI",
+						   &intel_glk_drv_data),
+	{}
+};
+
+MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
+
+static struct hdac_driver hdmi_driver = {
+	.driver = {
+		.name   = "HDMI HDA Codec",
+		.pm = &hdac_hdmi_pm,
+	},
+	.id_table       = hdmi_list,
+	.probe          = hdac_hdmi_dev_probe,
+	.remove         = hdac_hdmi_dev_remove,
+};
+
+static int __init hdmi_init(void)
+{
+	return snd_hda_ext_driver_register(&hdmi_driver);
+}
+
+static void __exit hdmi_exit(void)
+{
+	snd_hda_ext_driver_unregister(&hdmi_driver);
+}
+
+module_init(hdmi_init);
+module_exit(hdmi_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("HDMI HD codec");
+MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>");
+MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");
diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h
new file mode 100644
index 0000000..4fa2fc9
--- /dev/null
+++ b/sound/soc/codecs/hdac_hdmi.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __HDAC_HDMI_H__
+#define __HDAC_HDMI_H__
+
+int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm,
+				struct snd_soc_jack *jack);
+
+int hdac_hdmi_jack_port_init(struct snd_soc_component *component,
+			struct snd_soc_dapm_context *dapm);
+#endif /* __HDAC_HDMI_H__ */
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
new file mode 100644
index 0000000..d00734d
--- /dev/null
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -0,0 +1,822 @@
+/*
+ * ALSA SoC codec for HDMI encoder drivers
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Jyri Sarha <jsarha@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/string.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/pcm_drm_eld.h>
+#include <sound/hdmi-codec.h>
+#include <sound/pcm_iec958.h>
+
+#include <drm/drm_crtc.h> /* This is only to get MAX_ELD_BYTES */
+
+#define HDMI_CODEC_CHMAP_IDX_UNKNOWN  -1
+
+struct hdmi_codec_channel_map_table {
+	unsigned char map;	/* ALSA API channel map position */
+	unsigned long spk_mask;		/* speaker position bit mask */
+};
+
+/*
+ * CEA speaker placement for HDMI 1.4:
+ *
+ *  FL  FLC   FC   FRC   FR   FRW
+ *
+ *                                  LFE
+ *
+ *  RL  RLC   RC   RRC   RR
+ *
+ *  Speaker placement has to be extended to support HDMI 2.0
+ */
+enum hdmi_codec_cea_spk_placement {
+	FL  = BIT(0),	/* Front Left           */
+	FC  = BIT(1),	/* Front Center         */
+	FR  = BIT(2),	/* Front Right          */
+	FLC = BIT(3),	/* Front Left Center    */
+	FRC = BIT(4),	/* Front Right Center   */
+	RL  = BIT(5),	/* Rear Left            */
+	RC  = BIT(6),	/* Rear Center          */
+	RR  = BIT(7),	/* Rear Right           */
+	RLC = BIT(8),	/* Rear Left Center     */
+	RRC = BIT(9),	/* Rear Right Center    */
+	LFE = BIT(10),	/* Low Frequency Effect */
+};
+
+/*
+ * cea Speaker allocation structure
+ */
+struct hdmi_codec_cea_spk_alloc {
+	const int ca_id;
+	unsigned int n_ch;
+	unsigned long mask;
+};
+
+/* Channel maps  stereo HDMI */
+static const struct snd_pcm_chmap_elem hdmi_codec_stereo_chmaps[] = {
+	{ .channels = 2,
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+	{ }
+};
+
+/* Channel maps for multi-channel playbacks, up to 8 n_ch */
+static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = {
+	{ .channels = 2, /* CA_ID 0x00 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+	{ .channels = 4, /* CA_ID 0x01 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_NA } },
+	{ .channels = 4, /* CA_ID 0x02 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FC } },
+	{ .channels = 4, /* CA_ID 0x03 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_FC } },
+	{ .channels = 6, /* CA_ID 0x04 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+	{ .channels = 6, /* CA_ID 0x05 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+	{ .channels = 6, /* CA_ID 0x06 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+	{ .channels = 6, /* CA_ID 0x07 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+	{ .channels = 6, /* CA_ID 0x08 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+	{ .channels = 6, /* CA_ID 0x09 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+	{ .channels = 6, /* CA_ID 0x0A */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+	{ .channels = 6, /* CA_ID 0x0B */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+	{ .channels = 8, /* CA_ID 0x0C */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+		   SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+	{ .channels = 8, /* CA_ID 0x0D */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+		   SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+	{ .channels = 8, /* CA_ID 0x0E */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+		   SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+	{ .channels = 8, /* CA_ID 0x0F */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+		   SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+	{ .channels = 8, /* CA_ID 0x10 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+		   SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
+	{ .channels = 8, /* CA_ID 0x11 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+		   SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
+	{ .channels = 8, /* CA_ID 0x12 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+		   SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
+	{ .channels = 8, /* CA_ID 0x13 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+		   SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
+	{ .channels = 8, /* CA_ID 0x14 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+	{ .channels = 8, /* CA_ID 0x15 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+	{ .channels = 8, /* CA_ID 0x16 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+	{ .channels = 8, /* CA_ID 0x17 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+	{ .channels = 8, /* CA_ID 0x18 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+	{ .channels = 8, /* CA_ID 0x19 */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+	{ .channels = 8, /* CA_ID 0x1A */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+	{ .channels = 8, /* CA_ID 0x1B */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+	{ .channels = 8, /* CA_ID 0x1C */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+	{ .channels = 8, /* CA_ID 0x1D */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+	{ .channels = 8, /* CA_ID 0x1E */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+	{ .channels = 8, /* CA_ID 0x1F */
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+		   SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+		   SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+	{ }
+};
+
+/*
+ * hdmi_codec_channel_alloc: speaker configuration available for CEA
+ *
+ * This is an ordered list that must match with hdmi_codec_8ch_chmaps struct
+ * The preceding ones have better chances to be selected by
+ * hdmi_codec_get_ch_alloc_table_idx().
+ */
+static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = {
+	{ .ca_id = 0x00, .n_ch = 2,
+	  .mask = FL | FR},
+	/* 2.1 */
+	{ .ca_id = 0x01, .n_ch = 4,
+	  .mask = FL | FR | LFE},
+	/* Dolby Surround */
+	{ .ca_id = 0x02, .n_ch = 4,
+	  .mask = FL | FR | FC },
+	/* surround51 */
+	{ .ca_id = 0x0b, .n_ch = 6,
+	  .mask = FL | FR | LFE | FC | RL | RR},
+	/* surround40 */
+	{ .ca_id = 0x08, .n_ch = 6,
+	  .mask = FL | FR | RL | RR },
+	/* surround41 */
+	{ .ca_id = 0x09, .n_ch = 6,
+	  .mask = FL | FR | LFE | RL | RR },
+	/* surround50 */
+	{ .ca_id = 0x0a, .n_ch = 6,
+	  .mask = FL | FR | FC | RL | RR },
+	/* 6.1 */
+	{ .ca_id = 0x0f, .n_ch = 8,
+	  .mask = FL | FR | LFE | FC | RL | RR | RC },
+	/* surround71 */
+	{ .ca_id = 0x13, .n_ch = 8,
+	  .mask = FL | FR | LFE | FC | RL | RR | RLC | RRC },
+	/* others */
+	{ .ca_id = 0x03, .n_ch = 8,
+	  .mask = FL | FR | LFE | FC },
+	{ .ca_id = 0x04, .n_ch = 8,
+	  .mask = FL | FR | RC},
+	{ .ca_id = 0x05, .n_ch = 8,
+	  .mask = FL | FR | LFE | RC },
+	{ .ca_id = 0x06, .n_ch = 8,
+	  .mask = FL | FR | FC | RC },
+	{ .ca_id = 0x07, .n_ch = 8,
+	  .mask = FL | FR | LFE | FC | RC },
+	{ .ca_id = 0x0c, .n_ch = 8,
+	  .mask = FL | FR | RC | RL | RR },
+	{ .ca_id = 0x0d, .n_ch = 8,
+	  .mask = FL | FR | LFE | RL | RR | RC },
+	{ .ca_id = 0x0e, .n_ch = 8,
+	  .mask = FL | FR | FC | RL | RR | RC },
+	{ .ca_id = 0x10, .n_ch = 8,
+	  .mask = FL | FR | RL | RR | RLC | RRC },
+	{ .ca_id = 0x11, .n_ch = 8,
+	  .mask = FL | FR | LFE | RL | RR | RLC | RRC },
+	{ .ca_id = 0x12, .n_ch = 8,
+	  .mask = FL | FR | FC | RL | RR | RLC | RRC },
+	{ .ca_id = 0x14, .n_ch = 8,
+	  .mask = FL | FR | FLC | FRC },
+	{ .ca_id = 0x15, .n_ch = 8,
+	  .mask = FL | FR | LFE | FLC | FRC },
+	{ .ca_id = 0x16, .n_ch = 8,
+	  .mask = FL | FR | FC | FLC | FRC },
+	{ .ca_id = 0x17, .n_ch = 8,
+	  .mask = FL | FR | LFE | FC | FLC | FRC },
+	{ .ca_id = 0x18, .n_ch = 8,
+	  .mask = FL | FR | RC | FLC | FRC },
+	{ .ca_id = 0x19, .n_ch = 8,
+	  .mask = FL | FR | LFE | RC | FLC | FRC },
+	{ .ca_id = 0x1a, .n_ch = 8,
+	  .mask = FL | FR | RC | FC | FLC | FRC },
+	{ .ca_id = 0x1b, .n_ch = 8,
+	  .mask = FL | FR | LFE | RC | FC | FLC | FRC },
+	{ .ca_id = 0x1c, .n_ch = 8,
+	  .mask = FL | FR | RL | RR | FLC | FRC },
+	{ .ca_id = 0x1d, .n_ch = 8,
+	  .mask = FL | FR | LFE | RL | RR | FLC | FRC },
+	{ .ca_id = 0x1e, .n_ch = 8,
+	  .mask = FL | FR | FC | RL | RR | FLC | FRC },
+	{ .ca_id = 0x1f, .n_ch = 8,
+	  .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC },
+};
+
+struct hdmi_codec_priv {
+	struct hdmi_codec_pdata hcd;
+	struct snd_soc_dai_driver *daidrv;
+	struct hdmi_codec_daifmt daifmt[2];
+	struct mutex current_stream_lock;
+	struct snd_pcm_substream *current_stream;
+	uint8_t eld[MAX_ELD_BYTES];
+	struct snd_pcm_chmap *chmap_info;
+	unsigned int chmap_idx;
+};
+
+static const struct snd_soc_dapm_widget hdmi_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+enum {
+	DAI_ID_I2S = 0,
+	DAI_ID_SPDIF,
+};
+
+static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = FIELD_SIZEOF(struct hdmi_codec_priv, eld);
+
+	return 0;
+}
+
+static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component);
+
+	memcpy(ucontrol->value.bytes.data, hcp->eld, sizeof(hcp->eld));
+
+	return 0;
+}
+
+static unsigned long hdmi_codec_spk_mask_from_alloc(int spk_alloc)
+{
+	int i;
+	static const unsigned long hdmi_codec_eld_spk_alloc_bits[] = {
+		[0] = FL | FR, [1] = LFE, [2] = FC, [3] = RL | RR,
+		[4] = RC, [5] = FLC | FRC, [6] = RLC | RRC,
+	};
+	unsigned long spk_mask = 0;
+
+	for (i = 0; i < ARRAY_SIZE(hdmi_codec_eld_spk_alloc_bits); i++) {
+		if (spk_alloc & (1 << i))
+			spk_mask |= hdmi_codec_eld_spk_alloc_bits[i];
+	}
+
+	return spk_mask;
+}
+
+static void hdmi_codec_eld_chmap(struct hdmi_codec_priv *hcp)
+{
+	u8 spk_alloc;
+	unsigned long spk_mask;
+
+	spk_alloc = drm_eld_get_spk_alloc(hcp->eld);
+	spk_mask = hdmi_codec_spk_mask_from_alloc(spk_alloc);
+
+	/* Detect if only stereo supported, else return 8 channels mappings */
+	if ((spk_mask & ~(FL | FR)) && hcp->chmap_info->max_channels > 2)
+		hcp->chmap_info->chmap = hdmi_codec_8ch_chmaps;
+	else
+		hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps;
+}
+
+static int hdmi_codec_get_ch_alloc_table_idx(struct hdmi_codec_priv *hcp,
+					     unsigned char channels)
+{
+	int i;
+	u8 spk_alloc;
+	unsigned long spk_mask;
+	const struct hdmi_codec_cea_spk_alloc *cap = hdmi_codec_channel_alloc;
+
+	spk_alloc = drm_eld_get_spk_alloc(hcp->eld);
+	spk_mask = hdmi_codec_spk_mask_from_alloc(spk_alloc);
+
+	for (i = 0; i < ARRAY_SIZE(hdmi_codec_channel_alloc); i++, cap++) {
+		/* If spk_alloc == 0, HDMI is unplugged return stereo config*/
+		if (!spk_alloc && cap->ca_id == 0)
+			return i;
+		if (cap->n_ch != channels)
+			continue;
+		if (!(cap->mask == (spk_mask & cap->mask)))
+			continue;
+		return i;
+	}
+
+	return -EINVAL;
+}
+static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned const char *map;
+	unsigned int i;
+	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+	struct hdmi_codec_priv *hcp = info->private_data;
+
+	map = info->chmap[hcp->chmap_idx].map;
+
+	for (i = 0; i < info->max_channels; i++) {
+		if (hcp->chmap_idx == HDMI_CODEC_CHMAP_IDX_UNKNOWN)
+			ucontrol->value.integer.value[i] = 0;
+		else
+			ucontrol->value.integer.value[i] = map[i];
+	}
+
+	return 0;
+}
+
+static int hdmi_codec_new_stream(struct snd_pcm_substream *substream,
+				 struct snd_soc_dai *dai)
+{
+	struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
+	int ret = 0;
+
+	mutex_lock(&hcp->current_stream_lock);
+	if (!hcp->current_stream) {
+		hcp->current_stream = substream;
+	} else if (hcp->current_stream != substream) {
+		dev_err(dai->dev, "Only one simultaneous stream supported!\n");
+		ret = -EINVAL;
+	}
+	mutex_unlock(&hcp->current_stream_lock);
+
+	return ret;
+}
+
+static int hdmi_codec_startup(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
+	int ret = 0;
+
+	dev_dbg(dai->dev, "%s()\n", __func__);
+
+	ret = hdmi_codec_new_stream(substream, dai);
+	if (ret)
+		return ret;
+
+	if (hcp->hcd.ops->audio_startup) {
+		ret = hcp->hcd.ops->audio_startup(dai->dev->parent, hcp->hcd.data);
+		if (ret) {
+			mutex_lock(&hcp->current_stream_lock);
+			hcp->current_stream = NULL;
+			mutex_unlock(&hcp->current_stream_lock);
+			return ret;
+		}
+	}
+
+	if (hcp->hcd.ops->get_eld) {
+		ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data,
+					    hcp->eld, sizeof(hcp->eld));
+
+		if (!ret) {
+			ret = snd_pcm_hw_constraint_eld(substream->runtime,
+							hcp->eld);
+			if (ret)
+				return ret;
+		}
+		/* Select chmap supported */
+		hdmi_codec_eld_chmap(hcp);
+	}
+	return 0;
+}
+
+static void hdmi_codec_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
+
+	dev_dbg(dai->dev, "%s()\n", __func__);
+
+	WARN_ON(hcp->current_stream != substream);
+
+	hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
+	hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data);
+
+	mutex_lock(&hcp->current_stream_lock);
+	hcp->current_stream = NULL;
+	mutex_unlock(&hcp->current_stream_lock);
+}
+
+static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
+	struct hdmi_codec_params hp = {
+		.iec = {
+			.status = { 0 },
+			.subcode = { 0 },
+			.pad = 0,
+			.dig_subframe = { 0 },
+		}
+	};
+	int ret, idx;
+
+	dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__,
+		params_width(params), params_rate(params),
+		params_channels(params));
+
+	if (params_width(params) > 24)
+		params->msbits = 24;
+
+	ret = snd_pcm_create_iec958_consumer_hw_params(params, hp.iec.status,
+						       sizeof(hp.iec.status));
+	if (ret < 0) {
+		dev_err(dai->dev, "Creating IEC958 channel status failed %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = hdmi_codec_new_stream(substream, dai);
+	if (ret)
+		return ret;
+
+	hdmi_audio_infoframe_init(&hp.cea);
+	hp.cea.channels = params_channels(params);
+	hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
+	hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
+	hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
+
+	/* Select a channel allocation that matches with ELD and pcm channels */
+	idx = hdmi_codec_get_ch_alloc_table_idx(hcp, hp.cea.channels);
+	if (idx < 0) {
+		dev_err(dai->dev, "Not able to map channels to speakers (%d)\n",
+			idx);
+		hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
+		return idx;
+	}
+	hp.cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id;
+	hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id;
+
+	hp.sample_width = params_width(params);
+	hp.sample_rate = params_rate(params);
+	hp.channels = params_channels(params);
+
+	return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data,
+				       &hcp->daifmt[dai->id], &hp);
+}
+
+static int hdmi_codec_set_fmt(struct snd_soc_dai *dai,
+			      unsigned int fmt)
+{
+	struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
+	struct hdmi_codec_daifmt cf = { 0 };
+	int ret = 0;
+
+	dev_dbg(dai->dev, "%s()\n", __func__);
+
+	if (dai->id == DAI_ID_SPDIF) {
+		cf.fmt = HDMI_SPDIF;
+	} else {
+		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+		case SND_SOC_DAIFMT_CBM_CFM:
+			cf.bit_clk_master = 1;
+			cf.frame_clk_master = 1;
+			break;
+		case SND_SOC_DAIFMT_CBS_CFM:
+			cf.frame_clk_master = 1;
+			break;
+		case SND_SOC_DAIFMT_CBM_CFS:
+			cf.bit_clk_master = 1;
+			break;
+		case SND_SOC_DAIFMT_CBS_CFS:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			cf.frame_clk_inv = 1;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			cf.bit_clk_inv = 1;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			cf.frame_clk_inv = 1;
+			cf.bit_clk_inv = 1;
+			break;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+		case SND_SOC_DAIFMT_I2S:
+			cf.fmt = HDMI_I2S;
+			break;
+		case SND_SOC_DAIFMT_DSP_A:
+			cf.fmt = HDMI_DSP_A;
+			break;
+		case SND_SOC_DAIFMT_DSP_B:
+			cf.fmt = HDMI_DSP_B;
+			break;
+		case SND_SOC_DAIFMT_RIGHT_J:
+			cf.fmt = HDMI_RIGHT_J;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			cf.fmt = HDMI_LEFT_J;
+			break;
+		case SND_SOC_DAIFMT_AC97:
+			cf.fmt = HDMI_AC97;
+			break;
+		default:
+			dev_err(dai->dev, "Invalid DAI interface format\n");
+			return -EINVAL;
+		}
+	}
+
+	hcp->daifmt[dai->id] = cf;
+
+	return ret;
+}
+
+static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
+
+	dev_dbg(dai->dev, "%s()\n", __func__);
+
+	if (hcp->hcd.ops->digital_mute)
+		return hcp->hcd.ops->digital_mute(dai->dev->parent,
+						  hcp->hcd.data, mute);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops hdmi_dai_ops = {
+	.startup	= hdmi_codec_startup,
+	.shutdown	= hdmi_codec_shutdown,
+	.hw_params	= hdmi_codec_hw_params,
+	.set_fmt	= hdmi_codec_set_fmt,
+	.digital_mute	= hdmi_codec_digital_mute,
+};
+
+
+#define HDMI_RATES	(SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+			 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
+			 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
+			 SNDRV_PCM_RATE_192000)
+
+#define SPDIF_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\
+			 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\
+			 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\
+			 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE)
+
+/*
+ * This list is only for formats allowed on the I2S bus. So there is
+ * some formats listed that are not supported by HDMI interface. For
+ * instance allowing the 32-bit formats enables 24-precision with CPU
+ * DAIs that do not support 24-bit formats. If the extra formats cause
+ * problems, we should add the video side driver an option to disable
+ * them.
+ */
+#define I2S_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\
+			 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\
+			 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\
+			 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
+			 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE)
+
+static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_dai_driver *drv = dai->driver;
+	struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
+	struct snd_kcontrol *kctl;
+	struct snd_kcontrol_new hdmi_eld_ctl = {
+		.access	= SNDRV_CTL_ELEM_ACCESS_READ |
+			  SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.iface	= SNDRV_CTL_ELEM_IFACE_PCM,
+		.name	= "ELD",
+		.info	= hdmi_eld_ctl_info,
+		.get	= hdmi_eld_ctl_get,
+		.device	= rtd->pcm->device,
+	};
+	int ret;
+
+	dev_dbg(dai->dev, "%s()\n", __func__);
+
+	ret =  snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				      NULL, drv->playback.channels_max, 0,
+				      &hcp->chmap_info);
+	if (ret < 0)
+		return ret;
+
+	/* override handlers */
+	hcp->chmap_info->private_data = hcp;
+	hcp->chmap_info->kctl->get = hdmi_codec_chmap_ctl_get;
+
+	/* default chmap supported is stereo */
+	hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps;
+	hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
+
+	/* add ELD ctl with the device number corresponding to the PCM stream */
+	kctl = snd_ctl_new1(&hdmi_eld_ctl, dai->component);
+	if (!kctl)
+		return -ENOMEM;
+
+	return snd_ctl_add(rtd->card->snd_card, kctl);
+}
+
+static int hdmi_dai_probe(struct snd_soc_dai *dai)
+{
+	struct snd_soc_dapm_context *dapm;
+	struct snd_soc_dapm_route route = {
+		.sink = "TX",
+		.source = dai->driver->playback.stream_name,
+	};
+
+	dapm = snd_soc_component_get_dapm(dai->component);
+
+	return snd_soc_dapm_add_routes(dapm, &route, 1);
+}
+
+static const struct snd_soc_dai_driver hdmi_i2s_dai = {
+	.name = "i2s-hifi",
+	.id = DAI_ID_I2S,
+	.probe = hdmi_dai_probe,
+	.playback = {
+		.stream_name = "I2S Playback",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = HDMI_RATES,
+		.formats = I2S_FORMATS,
+		.sig_bits = 24,
+	},
+	.ops = &hdmi_dai_ops,
+	.pcm_new = hdmi_codec_pcm_new,
+};
+
+static const struct snd_soc_dai_driver hdmi_spdif_dai = {
+	.name = "spdif-hifi",
+	.id = DAI_ID_SPDIF,
+	.probe = hdmi_dai_probe,
+	.playback = {
+		.stream_name = "SPDIF Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = HDMI_RATES,
+		.formats = SPDIF_FORMATS,
+	},
+	.ops = &hdmi_dai_ops,
+	.pcm_new = hdmi_codec_pcm_new,
+};
+
+static int hdmi_of_xlate_dai_id(struct snd_soc_component *component,
+				 struct device_node *endpoint)
+{
+	struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component);
+	int ret = -ENOTSUPP; /* see snd_soc_get_dai_id() */
+
+	if (hcp->hcd.ops->get_dai_id)
+		ret = hcp->hcd.ops->get_dai_id(component, endpoint);
+
+	return ret;
+}
+
+static const struct snd_soc_component_driver hdmi_driver = {
+	.dapm_widgets		= hdmi_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(hdmi_widgets),
+	.of_xlate_dai_id	= hdmi_of_xlate_dai_id,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int hdmi_codec_probe(struct platform_device *pdev)
+{
+	struct hdmi_codec_pdata *hcd = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct hdmi_codec_priv *hcp;
+	int dai_count, i = 0;
+	int ret;
+
+	dev_dbg(dev, "%s()\n", __func__);
+
+	if (!hcd) {
+		dev_err(dev, "%s: No plalform data\n", __func__);
+		return -EINVAL;
+	}
+
+	dai_count = hcd->i2s + hcd->spdif;
+	if (dai_count < 1 || !hcd->ops || !hcd->ops->hw_params ||
+	    !hcd->ops->audio_shutdown) {
+		dev_err(dev, "%s: Invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hcp = devm_kzalloc(dev, sizeof(*hcp), GFP_KERNEL);
+	if (!hcp)
+		return -ENOMEM;
+
+	hcp->hcd = *hcd;
+	mutex_init(&hcp->current_stream_lock);
+
+	hcp->daidrv = devm_kcalloc(dev, dai_count, sizeof(*hcp->daidrv),
+				   GFP_KERNEL);
+	if (!hcp->daidrv)
+		return -ENOMEM;
+
+	if (hcd->i2s) {
+		hcp->daidrv[i] = hdmi_i2s_dai;
+		hcp->daidrv[i].playback.channels_max =
+			hcd->max_i2s_channels;
+		i++;
+	}
+
+	if (hcd->spdif)
+		hcp->daidrv[i] = hdmi_spdif_dai;
+
+	ret = devm_snd_soc_register_component(dev, &hdmi_driver, hcp->daidrv,
+				     dai_count);
+	if (ret) {
+		dev_err(dev, "%s: snd_soc_register_component() failed (%d)\n",
+			__func__, ret);
+		return ret;
+	}
+
+	dev_set_drvdata(dev, hcp);
+	return 0;
+}
+
+static struct platform_driver hdmi_codec_driver = {
+	.driver = {
+		.name = HDMI_CODEC_DRV_NAME,
+	},
+	.probe = hdmi_codec_probe,
+};
+
+module_platform_driver(hdmi_codec_driver);
+
+MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>");
+MODULE_DESCRIPTION("HDMI Audio Codec Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" HDMI_CODEC_DRV_NAME);
diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c
new file mode 100644
index 0000000..148d6d6
--- /dev/null
+++ b/sound/soc/codecs/ics43432.c
@@ -0,0 +1,74 @@
+/*
+ * I2S MEMS microphone driver for InvenSense ICS-43432
+ *
+ * - Non configurable.
+ * - I2S interface, 64 BCLs per frame, 32 bits per channel, 24 bit data
+ *
+ * Copyright (c) 2015 Axis Communications AB
+ *
+ * Licensed under GPL v2.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#define ICS43432_RATE_MIN 7190 /* Hz, from data sheet */
+#define ICS43432_RATE_MAX 52800  /* Hz, from data sheet */
+
+#define ICS43432_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32)
+
+static struct snd_soc_dai_driver ics43432_dai = {
+	.name = "ics43432-hifi",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min = ICS43432_RATE_MIN,
+		.rate_max = ICS43432_RATE_MAX,
+		.rates = SNDRV_PCM_RATE_CONTINUOUS,
+		.formats = ICS43432_FORMATS,
+	},
+};
+
+static const struct snd_soc_component_driver ics43432_component_driver = {
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int ics43432_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&ics43432_component_driver,
+			&ics43432_dai, 1);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id ics43432_ids[] = {
+	{ .compatible = "invensense,ics43432", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ics43432_ids);
+#endif
+
+static struct platform_driver ics43432_driver = {
+	.driver = {
+		.name = "ics43432",
+		.of_match_table = of_match_ptr(ics43432_ids),
+	},
+	.probe = ics43432_probe,
+};
+
+module_platform_driver(ics43432_driver);
+
+MODULE_DESCRIPTION("ASoC ICS43432 driver");
+MODULE_AUTHOR("Ricard Wanderlof <ricardw@axis.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
new file mode 100644
index 0000000..85a336b
--- /dev/null
+++ b/sound/soc/codecs/inno_rk3036.c
@@ -0,0 +1,492 @@
+/*
+ * Driver of Inno codec for rk3036 by Rockchip Inc.
+ *
+ * Author: Rockchip Inc.
+ * Author: Zheng ShunQian<zhengsq@rock-chips.com>
+ */
+
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-dai.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/io.h>
+
+#include "inno_rk3036.h"
+
+struct rk3036_codec_priv {
+	void __iomem *base;
+	struct clk *pclk;
+	struct regmap *regmap;
+	struct device *dev;
+};
+
+static const DECLARE_TLV_DB_MINMAX(rk3036_codec_hp_tlv, -39, 0);
+
+static int rk3036_codec_antipop_info(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+
+	return 0;
+}
+
+static int rk3036_codec_antipop_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	int val, ret, regval;
+
+	ret = snd_soc_component_read(component, INNO_R09, &regval);
+	if (ret)
+		return ret;
+	val = ((regval >> INNO_R09_HPL_ANITPOP_SHIFT) &
+	       INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON;
+	ucontrol->value.integer.value[0] = val;
+
+	val = ((regval >> INNO_R09_HPR_ANITPOP_SHIFT) &
+	       INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON;
+	ucontrol->value.integer.value[1] = val;
+
+	return 0;
+}
+
+static int rk3036_codec_antipop_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	int val, ret, regmsk;
+
+	val = (ucontrol->value.integer.value[0] ?
+	       INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) <<
+	      INNO_R09_HPL_ANITPOP_SHIFT;
+	val |= (ucontrol->value.integer.value[1] ?
+		INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) <<
+	       INNO_R09_HPR_ANITPOP_SHIFT;
+
+	regmsk = INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPL_ANITPOP_SHIFT |
+		 INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPR_ANITPOP_SHIFT;
+
+	ret = snd_soc_component_update_bits(component, INNO_R09,
+					    regmsk, val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+#define SOC_RK3036_CODEC_ANTIPOP_DECL(xname) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = rk3036_codec_antipop_info, .get = rk3036_codec_antipop_get, \
+	.put = rk3036_codec_antipop_put, }
+
+static const struct snd_kcontrol_new rk3036_codec_dapm_controls[] = {
+	SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", INNO_R07, INNO_R08,
+		INNO_HP_GAIN_SHIFT, INNO_HP_GAIN_N39DB,
+		INNO_HP_GAIN_0DB, 0, rk3036_codec_hp_tlv),
+	SOC_DOUBLE("Zero Cross Switch", INNO_R06, INNO_R06_VOUTL_CZ_SHIFT,
+		INNO_R06_VOUTR_CZ_SHIFT, 1, 0),
+	SOC_DOUBLE("Headphone Switch", INNO_R09, INNO_R09_HPL_MUTE_SHIFT,
+		INNO_R09_HPR_MUTE_SHIFT, 1, 0),
+	SOC_RK3036_CODEC_ANTIPOP_DECL("Anti-pop Switch"),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpl_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Left Out Switch", INNO_R09,
+			INNO_R09_DACL_SWITCH_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpr_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Right Out Switch", INNO_R09,
+			INNO_R09_DACR_SWITCH_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpl_switch_controls[] = {
+	SOC_DAPM_SINGLE("HP Left Out Switch", INNO_R05,
+			INNO_R05_HPL_WORK_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpr_switch_controls[] = {
+	SOC_DAPM_SINGLE("HP Right Out Switch", INNO_R05,
+			INNO_R05_HPR_WORK_SHIFT, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget rk3036_codec_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY_S("DAC PWR", 1, INNO_R06,
+			      INNO_R06_DAC_EN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DACL VREF", 2, INNO_R04,
+			      INNO_R04_DACL_VREF_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DACR VREF", 2, INNO_R04,
+			      INNO_R04_DACR_VREF_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DACL HiLo VREF", 3, INNO_R06,
+			      INNO_R06_DACL_HILO_VREF_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DACR HiLo VREF", 3, INNO_R06,
+			      INNO_R06_DACR_HILO_VREF_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DACR CLK", 3, INNO_R04,
+			      INNO_R04_DACR_CLK_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DACL CLK", 3, INNO_R04,
+			      INNO_R04_DACL_CLK_SHIFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("DACL", "Left Playback", INNO_R04,
+			 INNO_R04_DACL_SW_SHIFT, 0),
+	SND_SOC_DAPM_DAC("DACR", "Right Playback", INNO_R04,
+			 INNO_R04_DACR_SW_SHIFT, 0),
+
+	SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0,
+		rk3036_codec_hpl_mixer_controls,
+		ARRAY_SIZE(rk3036_codec_hpl_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0,
+		rk3036_codec_hpr_mixer_controls,
+		ARRAY_SIZE(rk3036_codec_hpr_mixer_controls)),
+
+	SND_SOC_DAPM_PGA("HP Left Out", INNO_R05,
+			 INNO_R05_HPL_EN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HP Right Out", INNO_R05,
+			 INNO_R05_HPR_EN_SHIFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("HP Left Switch",  SND_SOC_NOPM, 0, 0,
+			   rk3036_codec_hpl_switch_controls,
+			   ARRAY_SIZE(rk3036_codec_hpl_switch_controls)),
+	SND_SOC_DAPM_MIXER("HP Right Switch",  SND_SOC_NOPM, 0, 0,
+			   rk3036_codec_hpr_switch_controls,
+			   ARRAY_SIZE(rk3036_codec_hpr_switch_controls)),
+
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+static const struct snd_soc_dapm_route rk3036_codec_dapm_routes[] = {
+	{"DACL VREF", NULL, "DAC PWR"},
+	{"DACR VREF", NULL, "DAC PWR"},
+	{"DACL HiLo VREF", NULL, "DAC PWR"},
+	{"DACR HiLo VREF", NULL, "DAC PWR"},
+	{"DACL CLK", NULL, "DAC PWR"},
+	{"DACR CLK", NULL, "DAC PWR"},
+
+	{"DACL", NULL, "DACL VREF"},
+	{"DACL", NULL, "DACL HiLo VREF"},
+	{"DACL", NULL, "DACL CLK"},
+	{"DACR", NULL, "DACR VREF"},
+	{"DACR", NULL, "DACR HiLo VREF"},
+	{"DACR", NULL, "DACR CLK"},
+
+	{"Left Headphone Mixer", "DAC Left Out Switch", "DACL"},
+	{"Right Headphone Mixer", "DAC Right Out Switch", "DACR"},
+	{"HP Left Out", NULL, "Left Headphone Mixer"},
+	{"HP Right Out", NULL, "Right Headphone Mixer"},
+
+	{"HP Left Switch", "HP Left Out Switch", "HP Left Out"},
+	{"HP Right Switch", "HP Right Out Switch", "HP Right Out"},
+
+	{"HPL", NULL, "HP Left Switch"},
+	{"HPR", NULL, "HP Right Switch"},
+};
+
+static int rk3036_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int reg01_val = 0,  reg02_val = 0, reg03_val = 0;
+
+	dev_dbg(component->dev, "rk3036_codec dai set fmt : %08x\n", fmt);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg01_val |= INNO_R01_PINDIR_IN_SLAVE |
+			     INNO_R01_I2SMODE_SLAVE;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		reg01_val |= INNO_R01_PINDIR_OUT_MASTER |
+			     INNO_R01_I2SMODE_MASTER;
+		break;
+	default:
+		dev_err(component->dev, "invalid fmt\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		reg02_val |= INNO_R02_DACM_PCM;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		reg02_val |= INNO_R02_DACM_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		reg02_val |= INNO_R02_DACM_RJM;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg02_val |= INNO_R02_DACM_LJM;
+		break;
+	default:
+		dev_err(component->dev, "set dai format failed\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		reg02_val |= INNO_R02_LRCP_NORMAL;
+		reg03_val |= INNO_R03_BCP_NORMAL;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		reg02_val |= INNO_R02_LRCP_REVERSAL;
+		reg03_val |= INNO_R03_BCP_REVERSAL;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg02_val |= INNO_R02_LRCP_REVERSAL;
+		reg03_val |= INNO_R03_BCP_NORMAL;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		reg02_val |= INNO_R02_LRCP_NORMAL;
+		reg03_val |= INNO_R03_BCP_REVERSAL;
+		break;
+	default:
+		dev_err(component->dev, "set dai format failed\n");
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, INNO_R01, INNO_R01_I2SMODE_MSK |
+			    INNO_R01_PINDIR_MSK, reg01_val);
+	snd_soc_component_update_bits(component, INNO_R02, INNO_R02_LRCP_MSK |
+			    INNO_R02_DACM_MSK, reg02_val);
+	snd_soc_component_update_bits(component, INNO_R03, INNO_R03_BCP_MSK, reg03_val);
+
+	return 0;
+}
+
+static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream,
+				      struct snd_pcm_hw_params *hw_params,
+				      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int reg02_val = 0, reg03_val = 0;
+
+	switch (params_format(hw_params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		reg02_val |= INNO_R02_VWL_16BIT;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		reg02_val |= INNO_R02_VWL_20BIT;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		reg02_val |= INNO_R02_VWL_24BIT;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		reg02_val |= INNO_R02_VWL_32BIT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	reg02_val |= INNO_R02_LRCP_NORMAL;
+	reg03_val |= INNO_R03_FWL_32BIT | INNO_R03_DACR_WORK;
+
+	snd_soc_component_update_bits(component, INNO_R02, INNO_R02_LRCP_MSK |
+			    INNO_R02_VWL_MSK, reg02_val);
+	snd_soc_component_update_bits(component, INNO_R03, INNO_R03_DACR_MSK |
+			    INNO_R03_FWL_MSK, reg03_val);
+	return 0;
+}
+
+#define RK3036_CODEC_RATES (SNDRV_PCM_RATE_8000  | \
+			    SNDRV_PCM_RATE_16000 | \
+			    SNDRV_PCM_RATE_32000 | \
+			    SNDRV_PCM_RATE_44100 | \
+			    SNDRV_PCM_RATE_48000 | \
+			    SNDRV_PCM_RATE_96000)
+
+#define RK3036_CODEC_FMTS (SNDRV_PCM_FMTBIT_S16_LE  | \
+			   SNDRV_PCM_FMTBIT_S20_3LE | \
+			   SNDRV_PCM_FMTBIT_S24_LE  | \
+			   SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops rk3036_codec_dai_ops = {
+	.set_fmt	= rk3036_codec_dai_set_fmt,
+	.hw_params	= rk3036_codec_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver rk3036_codec_dai_driver[] = {
+	{
+		.name = "rk3036-codec-dai",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RK3036_CODEC_RATES,
+			.formats = RK3036_CODEC_FMTS,
+		},
+		.ops = &rk3036_codec_dai_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static void rk3036_codec_reset(struct snd_soc_component *component)
+{
+	snd_soc_component_write(component, INNO_R00,
+		      INNO_R00_CSR_RESET | INNO_R00_CDCR_RESET);
+	snd_soc_component_write(component, INNO_R00,
+		      INNO_R00_CSR_WORK | INNO_R00_CDCR_WORK);
+}
+
+static int rk3036_codec_probe(struct snd_soc_component *component)
+{
+	rk3036_codec_reset(component);
+	return 0;
+}
+
+static void rk3036_codec_remove(struct snd_soc_component *component)
+{
+	rk3036_codec_reset(component);
+}
+
+static int rk3036_codec_set_bias_level(struct snd_soc_component *component,
+				       enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_STANDBY:
+		/* set a big current for capacitor charging. */
+		snd_soc_component_write(component, INNO_R10, INNO_R10_MAX_CUR);
+		/* start precharge */
+		snd_soc_component_write(component, INNO_R06, INNO_R06_DAC_PRECHARGE);
+
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* set a big current for capacitor discharging. */
+		snd_soc_component_write(component, INNO_R10, INNO_R10_MAX_CUR);
+		/* start discharge. */
+		snd_soc_component_write(component, INNO_R06, INNO_R06_DAC_DISCHARGE);
+
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver rk3036_codec_driver = {
+	.probe			= rk3036_codec_probe,
+	.remove			= rk3036_codec_remove,
+	.set_bias_level		= rk3036_codec_set_bias_level,
+	.controls		= rk3036_codec_dapm_controls,
+	.num_controls		= ARRAY_SIZE(rk3036_codec_dapm_controls),
+	.dapm_routes		= rk3036_codec_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rk3036_codec_dapm_routes),
+	.dapm_widgets		= rk3036_codec_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rk3036_codec_dapm_widgets),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rk3036_codec_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+};
+
+#define GRF_SOC_CON0		0x00140
+#define GRF_ACODEC_SEL		(BIT(10) | BIT(16 + 10))
+
+static int rk3036_codec_platform_probe(struct platform_device *pdev)
+{
+	struct rk3036_codec_priv *priv;
+	struct device_node *of_node = pdev->dev.of_node;
+	struct resource *res;
+	void __iomem *base;
+	struct regmap *grf;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	priv->base = base;
+	priv->regmap = devm_regmap_init_mmio(&pdev->dev, priv->base,
+					     &rk3036_codec_regmap_config);
+	if (IS_ERR(priv->regmap)) {
+		dev_err(&pdev->dev, "init regmap failed\n");
+		return PTR_ERR(priv->regmap);
+	}
+
+	grf = syscon_regmap_lookup_by_phandle(of_node, "rockchip,grf");
+	if (IS_ERR(grf)) {
+		dev_err(&pdev->dev, "needs 'rockchip,grf' property\n");
+		return PTR_ERR(grf);
+	}
+	ret = regmap_write(grf, GRF_SOC_CON0, GRF_ACODEC_SEL);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not write to GRF: %d\n", ret);
+		return ret;
+	}
+
+	priv->pclk = devm_clk_get(&pdev->dev, "acodec_pclk");
+	if (IS_ERR(priv->pclk))
+		return PTR_ERR(priv->pclk);
+
+	ret = clk_prepare_enable(priv->pclk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to enable clk\n");
+		return ret;
+	}
+
+	priv->dev = &pdev->dev;
+	dev_set_drvdata(&pdev->dev, priv);
+
+	ret = devm_snd_soc_register_component(&pdev->dev, &rk3036_codec_driver,
+				     rk3036_codec_dai_driver,
+				     ARRAY_SIZE(rk3036_codec_dai_driver));
+	if (ret) {
+		clk_disable_unprepare(priv->pclk);
+		dev_set_drvdata(&pdev->dev, NULL);
+	}
+
+	return ret;
+}
+
+static int rk3036_codec_platform_remove(struct platform_device *pdev)
+{
+	struct rk3036_codec_priv *priv = dev_get_drvdata(&pdev->dev);
+
+	clk_disable_unprepare(priv->pclk);
+
+	return 0;
+}
+
+static const struct of_device_id rk3036_codec_of_match[] = {
+	{ .compatible = "rockchip,rk3036-codec", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, rk3036_codec_of_match);
+
+static struct platform_driver rk3036_codec_platform_driver = {
+	.driver = {
+		.name = "rk3036-codec-platform",
+		.of_match_table = of_match_ptr(rk3036_codec_of_match),
+	},
+	.probe = rk3036_codec_platform_probe,
+	.remove = rk3036_codec_platform_remove,
+};
+
+module_platform_driver(rk3036_codec_platform_driver);
+
+MODULE_AUTHOR("Rockchip Inc.");
+MODULE_DESCRIPTION("Rockchip rk3036 codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/inno_rk3036.h b/sound/soc/codecs/inno_rk3036.h
new file mode 100644
index 0000000..44bb240
--- /dev/null
+++ b/sound/soc/codecs/inno_rk3036.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Driver of Inno Codec for rk3036 by Rockchip Inc.
+ *
+ * Author: Zheng ShunQian<zhengsq@rock-chips.com>
+ */
+
+#ifndef _INNO_RK3036_CODEC_H
+#define _INNO_RK3036_CODEC_H
+
+/* codec registers */
+#define INNO_R00	0x00
+#define INNO_R01	0x0c
+#define INNO_R02	0x10
+#define INNO_R03	0x14
+#define INNO_R04	0x88
+#define INNO_R05	0x8c
+#define INNO_R06	0x90
+#define INNO_R07	0x94
+#define INNO_R08	0x98
+#define INNO_R09	0x9c
+#define INNO_R10	0xa0
+
+/* register bit filed */
+#define INNO_R00_CSR_RESET		(0x0 << 0) /*codec system reset*/
+#define INNO_R00_CSR_WORK		(0x1 << 0)
+#define INNO_R00_CDCR_RESET		(0x0 << 1) /*codec digital core reset*/
+#define INNO_R00_CDCR_WORK		(0x1 << 1)
+#define INNO_R00_PRB_DISABLE		(0x0 << 6) /*power reset bypass*/
+#define INNO_R00_PRB_ENABLE		(0x1 << 6)
+
+#define INNO_R01_I2SMODE_MSK		(0x1 << 4)
+#define INNO_R01_I2SMODE_SLAVE		(0x0 << 4)
+#define INNO_R01_I2SMODE_MASTER		(0x1 << 4)
+#define INNO_R01_PINDIR_MSK		(0x1 << 5)
+#define INNO_R01_PINDIR_IN_SLAVE	(0x0 << 5) /*direction of pin*/
+#define INNO_R01_PINDIR_OUT_MASTER	(0x1 << 5)
+
+#define INNO_R02_LRS_MSK		(0x1 << 2)
+#define INNO_R02_LRS_NORMAL		(0x0 << 2) /*DAC Left Right Swap*/
+#define INNO_R02_LRS_SWAP		(0x1 << 2)
+#define INNO_R02_DACM_MSK		(0x3 << 3)
+#define INNO_R02_DACM_PCM		(0x3 << 3) /*DAC Mode*/
+#define INNO_R02_DACM_I2S		(0x2 << 3)
+#define INNO_R02_DACM_LJM		(0x1 << 3)
+#define INNO_R02_DACM_RJM		(0x0 << 3)
+#define INNO_R02_VWL_MSK		(0x3 << 5)
+#define INNO_R02_VWL_32BIT		(0x3 << 5) /*1/2Frame Valid Word Len*/
+#define INNO_R02_VWL_24BIT		(0x2 << 5)
+#define INNO_R02_VWL_20BIT		(0x1 << 5)
+#define INNO_R02_VWL_16BIT		(0x0 << 5)
+#define INNO_R02_LRCP_MSK		(0x1 << 7)
+#define INNO_R02_LRCP_NORMAL		(0x0 << 7) /*Left Right Polarity*/
+#define INNO_R02_LRCP_REVERSAL		(0x1 << 7)
+
+#define INNO_R03_BCP_MSK		(0x1 << 0)
+#define INNO_R03_BCP_NORMAL		(0x0 << 0) /*DAC bit clock polarity*/
+#define INNO_R03_BCP_REVERSAL		(0x1 << 0)
+#define INNO_R03_DACR_MSK		(0x1 << 1)
+#define INNO_R03_DACR_RESET		(0x0 << 1) /*DAC Reset*/
+#define INNO_R03_DACR_WORK		(0x1 << 1)
+#define INNO_R03_FWL_MSK		(0x3 << 2)
+#define INNO_R03_FWL_32BIT		(0x3 << 2) /*1/2Frame Word Length*/
+#define INNO_R03_FWL_24BIT		(0x2 << 2)
+#define INNO_R03_FWL_20BIT		(0x1 << 2)
+#define INNO_R03_FWL_16BIT		(0x0 << 2)
+
+#define INNO_R04_DACR_SW_SHIFT		0
+#define INNO_R04_DACL_SW_SHIFT		1
+#define INNO_R04_DACR_CLK_SHIFT		2
+#define INNO_R04_DACL_CLK_SHIFT		3
+#define INNO_R04_DACR_VREF_SHIFT	4
+#define INNO_R04_DACL_VREF_SHIFT	5
+
+#define INNO_R05_HPR_EN_SHIFT		0
+#define INNO_R05_HPL_EN_SHIFT		1
+#define INNO_R05_HPR_WORK_SHIFT		2
+#define INNO_R05_HPL_WORK_SHIFT		3
+
+#define INNO_R06_VOUTR_CZ_SHIFT		0
+#define INNO_R06_VOUTL_CZ_SHIFT		1
+#define INNO_R06_DACR_HILO_VREF_SHIFT	2
+#define INNO_R06_DACL_HILO_VREF_SHIFT	3
+#define INNO_R06_DAC_EN_SHIFT		5
+
+#define INNO_R06_DAC_PRECHARGE		(0x0 << 4) /*PreCharge control for DAC*/
+#define INNO_R06_DAC_DISCHARGE		(0x1 << 4)
+
+#define INNO_HP_GAIN_SHIFT		0
+/* Gain of output, 1.5db step: -39db(0x0) ~ 0db(0x1a) ~ 6db(0x1f) */
+#define INNO_HP_GAIN_0DB		0x1a
+#define INNO_HP_GAIN_N39DB		0x0
+
+#define INNO_R09_HP_ANTIPOP_MSK		0x3
+#define INNO_R09_HP_ANTIPOP_OFF		0x1
+#define INNO_R09_HP_ANTIPOP_ON		0x2
+#define INNO_R09_HPR_ANITPOP_SHIFT	0
+#define INNO_R09_HPL_ANITPOP_SHIFT	2
+#define INNO_R09_HPR_MUTE_SHIFT		4
+#define INNO_R09_HPL_MUTE_SHIFT		5
+#define INNO_R09_DACR_SWITCH_SHIFT	6
+#define INNO_R09_DACL_SWITCH_SHIFT	7
+
+#define INNO_R10_CHARGE_SEL_CUR_400I_YES	(0x0 << 0)
+#define INNO_R10_CHARGE_SEL_CUR_400I_NO		(0x1 << 0)
+#define INNO_R10_CHARGE_SEL_CUR_260I_YES	(0x0 << 1)
+#define INNO_R10_CHARGE_SEL_CUR_260I_NO		(0x1 << 1)
+#define INNO_R10_CHARGE_SEL_CUR_130I_YES	(0x0 << 2)
+#define INNO_R10_CHARGE_SEL_CUR_130I_NO		(0x1 << 2)
+#define INNO_R10_CHARGE_SEL_CUR_100I_YES	(0x0 << 3)
+#define INNO_R10_CHARGE_SEL_CUR_100I_NO		(0x1 << 3)
+#define INNO_R10_CHARGE_SEL_CUR_050I_YES	(0x0 << 4)
+#define INNO_R10_CHARGE_SEL_CUR_050I_NO		(0x1 << 4)
+#define INNO_R10_CHARGE_SEL_CUR_027I_YES	(0x0 << 5)
+#define INNO_R10_CHARGE_SEL_CUR_027I_NO		(0x1 << 5)
+
+#define INNO_R10_MAX_CUR (INNO_R10_CHARGE_SEL_CUR_400I_YES | \
+			  INNO_R10_CHARGE_SEL_CUR_260I_YES | \
+			  INNO_R10_CHARGE_SEL_CUR_130I_YES | \
+			  INNO_R10_CHARGE_SEL_CUR_100I_YES | \
+			  INNO_R10_CHARGE_SEL_CUR_050I_YES | \
+			  INNO_R10_CHARGE_SEL_CUR_027I_YES)
+
+#endif
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
new file mode 100644
index 0000000..1664203
--- /dev/null
+++ b/sound/soc/codecs/isabelle.c
@@ -0,0 +1,1158 @@
+/*
+ * isabelle.c - Low power high fidelity audio codec driver
+ *
+ * Copyright (c) 2012 Texas Instruments, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ *
+ * Initially based on sound/soc/codecs/twl6040.c
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <asm/div64.h>
+#include "isabelle.h"
+
+
+/* Register default values for ISABELLE driver. */
+static const struct reg_default isabelle_reg_defs[] = {
+	{ 0, 0x00 },
+	{ 1, 0x00 },
+	{ 2, 0x00 },
+	{ 3, 0x00 },
+	{ 4, 0x00 },
+	{ 5, 0x00 },
+	{ 6, 0x00 },
+	{ 7, 0x00 },
+	{ 8, 0x00 },
+	{ 9, 0x00 },
+	{ 10, 0x00 },
+	{ 11, 0x00 },
+	{ 12, 0x00 },
+	{ 13, 0x00 },
+	{ 14, 0x00 },
+	{ 15, 0x00 },
+	{ 16, 0x00 },
+	{ 17, 0x00 },
+	{ 18, 0x00 },
+	{ 19, 0x00 },
+	{ 20, 0x00 },
+	{ 21, 0x02 },
+	{ 22, 0x02 },
+	{ 23, 0x02 },
+	{ 24, 0x02 },
+	{ 25, 0x0F },
+	{ 26, 0x8F },
+	{ 27, 0x0F },
+	{ 28, 0x8F },
+	{ 29, 0x00 },
+	{ 30, 0x00 },
+	{ 31, 0x00 },
+	{ 32, 0x00 },
+	{ 33, 0x00 },
+	{ 34, 0x00 },
+	{ 35, 0x00 },
+	{ 36, 0x00 },
+	{ 37, 0x00 },
+	{ 38, 0x00 },
+	{ 39, 0x00 },
+	{ 40, 0x00 },
+	{ 41, 0x00 },
+	{ 42, 0x00 },
+	{ 43, 0x00 },
+	{ 44, 0x00 },
+	{ 45, 0x00 },
+	{ 46, 0x00 },
+	{ 47, 0x00 },
+	{ 48, 0x00 },
+	{ 49, 0x00 },
+	{ 50, 0x00 },
+	{ 51, 0x00 },
+	{ 52, 0x00 },
+	{ 53, 0x00 },
+	{ 54, 0x00 },
+	{ 55, 0x00 },
+	{ 56, 0x00 },
+	{ 57, 0x00 },
+	{ 58, 0x00 },
+	{ 59, 0x00 },
+	{ 60, 0x00 },
+	{ 61, 0x00 },
+	{ 62, 0x00 },
+	{ 63, 0x00 },
+	{ 64, 0x00 },
+	{ 65, 0x00 },
+	{ 66, 0x00 },
+	{ 67, 0x00 },
+	{ 68, 0x00 },
+	{ 69, 0x90 },
+	{ 70, 0x90 },
+	{ 71, 0x90 },
+	{ 72, 0x00 },
+	{ 73, 0x00 },
+	{ 74, 0x00 },
+	{ 75, 0x00 },
+	{ 76, 0x00 },
+	{ 77, 0x00 },
+	{ 78, 0x00 },
+	{ 79, 0x00 },
+	{ 80, 0x00 },
+	{ 81, 0x00 },
+	{ 82, 0x00 },
+	{ 83, 0x00 },
+	{ 84, 0x00 },
+	{ 85, 0x07 },
+	{ 86, 0x00 },
+	{ 87, 0x00 },
+	{ 88, 0x00 },
+	{ 89, 0x07 },
+	{ 90, 0x80 },
+	{ 91, 0x07 },
+	{ 92, 0x07 },
+	{ 93, 0x00 },
+	{ 94, 0x00 },
+	{ 95, 0x00 },
+	{ 96, 0x00 },
+	{ 97, 0x00 },
+	{ 98, 0x00 },
+	{ 99, 0x00 },
+};
+
+static const char *isabelle_rx1_texts[] = {"VRX1", "ARX1"};
+static const char *isabelle_rx2_texts[] = {"VRX2", "ARX2"};
+
+static const struct soc_enum isabelle_rx1_enum[] = {
+	SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3,
+			ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts),
+	SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5,
+			ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts),
+};
+
+static const struct soc_enum isabelle_rx2_enum[] = {
+	SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2,
+			ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts),
+	SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4,
+			ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts),
+};
+
+/* Headset DAC playback switches */
+static const struct snd_kcontrol_new rx1_mux_controls =
+	SOC_DAPM_ENUM("Route", isabelle_rx1_enum);
+
+static const struct snd_kcontrol_new rx2_mux_controls =
+	SOC_DAPM_ENUM("Route", isabelle_rx2_enum);
+
+/* TX input selection */
+static const char *isabelle_atx_texts[] = {"AMIC1", "DMIC"};
+static const char *isabelle_vtx_texts[] = {"AMIC2", "DMIC"};
+
+static const struct soc_enum isabelle_atx_enum[] = {
+	SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7,
+			ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts),
+	SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0,
+			ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts),
+};
+
+static const struct soc_enum isabelle_vtx_enum[] = {
+	SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6,
+			ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts),
+	SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0,
+			ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts),
+};
+
+static const struct snd_kcontrol_new atx_mux_controls =
+	SOC_DAPM_ENUM("Route", isabelle_atx_enum);
+
+static const struct snd_kcontrol_new vtx_mux_controls =
+	SOC_DAPM_ENUM("Route", isabelle_vtx_enum);
+
+/* Left analog microphone selection */
+static const char *isabelle_amic1_texts[] = {
+	"Main Mic", "Headset Mic", "Aux/FM Left"};
+
+/* Left analog microphone selection */
+static const char *isabelle_amic2_texts[] = {"Sub Mic", "Aux/FM Right"};
+
+static SOC_ENUM_SINGLE_DECL(isabelle_amic1_enum,
+			    ISABELLE_AMIC_CFG_REG, 5,
+			    isabelle_amic1_texts);
+
+static SOC_ENUM_SINGLE_DECL(isabelle_amic2_enum,
+			    ISABELLE_AMIC_CFG_REG, 4,
+			    isabelle_amic2_texts);
+
+static const struct snd_kcontrol_new amic1_control =
+	SOC_DAPM_ENUM("Route", isabelle_amic1_enum);
+
+static const struct snd_kcontrol_new amic2_control =
+	SOC_DAPM_ENUM("Route", isabelle_amic2_enum);
+
+static const char *isabelle_st_audio_texts[] = {"ATX1", "ATX2"};
+
+static const char *isabelle_st_voice_texts[] = {"VTX1", "VTX2"};
+
+static const struct soc_enum isabelle_st_audio_enum[] = {
+	SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7,
+			ARRAY_SIZE(isabelle_st_audio_texts),
+			isabelle_st_audio_texts),
+	SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7,
+			ARRAY_SIZE(isabelle_st_audio_texts),
+			isabelle_st_audio_texts),
+};
+
+static const struct soc_enum isabelle_st_voice_enum[] = {
+	SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7,
+			ARRAY_SIZE(isabelle_st_voice_texts),
+			isabelle_st_voice_texts),
+	SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7,
+			ARRAY_SIZE(isabelle_st_voice_texts),
+			isabelle_st_voice_texts),
+};
+
+static const struct snd_kcontrol_new st_audio_control =
+	SOC_DAPM_ENUM("Route", isabelle_st_audio_enum);
+
+static const struct snd_kcontrol_new st_voice_control =
+	SOC_DAPM_ENUM("Route", isabelle_st_voice_enum);
+
+/* Mixer controls */
+static const struct snd_kcontrol_new isabelle_hs_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC1L Playback Switch", ISABELLE_HSDRV_CFG1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_HSDRV_CFG1_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_hs_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC1R Playback Switch", ISABELLE_HSDRV_CFG1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_HSDRV_CFG1_REG, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_hf_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC2L Playback Switch", ISABELLE_HFLPGA_CFG_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_HFLPGA_CFG_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_hf_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC2R Playback Switch", ISABELLE_HFRPGA_CFG_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_HFRPGA_CFG_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_ep_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC2L Playback Switch", ISABELLE_EARDRV_CFG1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_EARDRV_CFG1_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_aux_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC3L Playback Switch", ISABELLE_LINEAMP_CFG_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_LINEAMP_CFG_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_aux_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("DAC3R Playback Switch", ISABELLE_LINEAMP_CFG_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_LINEAMP_CFG_REG, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga1_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga1_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga2_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga2_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("USNC Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga3_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_dpga3_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx1_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DL1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx2_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("DL2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx3_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("DL3 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx4_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DL4 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx5_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DL5 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new isabelle_rx6_mixer_controls[] = {
+SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("DL6 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new ep_path_enable_control =
+	SOC_DAPM_SINGLE("Switch", ISABELLE_EARDRV_CFG2_REG, 0, 1, 0);
+
+/* TLV Declarations */
+static const DECLARE_TLV_DB_SCALE(mic_amp_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(afm_amp_tlv, -3300, 300, 0);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -1200, 200, 0);
+static const DECLARE_TLV_DB_SCALE(hf_tlv, -5000, 200, 0);
+
+/* from -63 to 0 dB in 1 dB steps */
+static const DECLARE_TLV_DB_SCALE(dpga_tlv, -6300, 100, 1);
+
+/* from -63 to 9 dB in 1 dB steps */
+static const DECLARE_TLV_DB_SCALE(rx_tlv, -6300, 100, 1);
+
+static const DECLARE_TLV_DB_SCALE(st_tlv, -2700, 300, 1);
+static const DECLARE_TLV_DB_SCALE(tx_tlv, -600, 100, 0);
+
+static const struct snd_kcontrol_new isabelle_snd_controls[] = {
+	SOC_DOUBLE_TLV("Headset Playback Volume", ISABELLE_HSDRV_GAIN_REG,
+			4, 0, 0xF, 0, dac_tlv),
+	SOC_DOUBLE_R_TLV("Handsfree Playback Volume",
+			ISABELLE_HFLPGA_CFG_REG, ISABELLE_HFRPGA_CFG_REG,
+			0, 0x1F, 0, hf_tlv),
+	SOC_DOUBLE_TLV("Aux Playback Volume", ISABELLE_LINEAMP_GAIN_REG,
+			4, 0, 0xF, 0, dac_tlv),
+	SOC_SINGLE_TLV("Earpiece Playback Volume", ISABELLE_EARDRV_CFG1_REG,
+			0, 0xF, 0, dac_tlv),
+
+	SOC_DOUBLE_TLV("Aux FM Volume", ISABELLE_APGA_GAIN_REG, 4, 0, 0xF, 0,
+			afm_amp_tlv),
+	SOC_SINGLE_TLV("Mic1 Capture Volume", ISABELLE_MIC1_GAIN_REG, 3, 0x1F,
+			0, mic_amp_tlv),
+	SOC_SINGLE_TLV("Mic2 Capture Volume", ISABELLE_MIC2_GAIN_REG, 3, 0x1F,
+			0, mic_amp_tlv),
+
+	SOC_DOUBLE_R_TLV("DPGA1 Volume", ISABELLE_DPGA1L_GAIN_REG,
+			ISABELLE_DPGA1R_GAIN_REG, 0, 0x3F, 0, dpga_tlv),
+	SOC_DOUBLE_R_TLV("DPGA2 Volume", ISABELLE_DPGA2L_GAIN_REG,
+			ISABELLE_DPGA2R_GAIN_REG, 0, 0x3F, 0, dpga_tlv),
+	SOC_DOUBLE_R_TLV("DPGA3 Volume", ISABELLE_DPGA3L_GAIN_REG,
+			ISABELLE_DPGA3R_GAIN_REG, 0, 0x3F, 0, dpga_tlv),
+
+	SOC_SINGLE_TLV("Sidetone Audio TX1 Volume",
+			ISABELLE_ATX_STPGA1_CFG_REG, 0, 0xF, 0, st_tlv),
+	SOC_SINGLE_TLV("Sidetone Audio TX2 Volume",
+			ISABELLE_ATX_STPGA2_CFG_REG, 0, 0xF, 0, st_tlv),
+	SOC_SINGLE_TLV("Sidetone Voice TX1 Volume",
+			ISABELLE_VTX_STPGA1_CFG_REG, 0, 0xF, 0, st_tlv),
+	SOC_SINGLE_TLV("Sidetone Voice TX2 Volume",
+			ISABELLE_VTX2_STPGA2_CFG_REG, 0, 0xF, 0, st_tlv),
+
+	SOC_SINGLE_TLV("Audio TX1 Volume", ISABELLE_ATX1_DPGA_REG, 4, 0xF, 0,
+			tx_tlv),
+	SOC_SINGLE_TLV("Audio TX2 Volume", ISABELLE_ATX2_DPGA_REG, 4, 0xF, 0,
+			tx_tlv),
+	SOC_SINGLE_TLV("Voice TX1 Volume", ISABELLE_VTX1_DPGA_REG, 4, 0xF, 0,
+			tx_tlv),
+	SOC_SINGLE_TLV("Voice TX2 Volume", ISABELLE_VTX2_DPGA_REG, 4, 0xF, 0,
+			tx_tlv),
+
+	SOC_SINGLE_TLV("RX1 DPGA Volume", ISABELLE_RX1_DPGA_REG, 0, 0x3F, 0,
+			rx_tlv),
+	SOC_SINGLE_TLV("RX2 DPGA Volume", ISABELLE_RX2_DPGA_REG, 0, 0x3F, 0,
+			rx_tlv),
+	SOC_SINGLE_TLV("RX3 DPGA Volume", ISABELLE_RX3_DPGA_REG, 0, 0x3F, 0,
+			rx_tlv),
+	SOC_SINGLE_TLV("RX4 DPGA Volume", ISABELLE_RX4_DPGA_REG, 0, 0x3F, 0,
+			rx_tlv),
+	SOC_SINGLE_TLV("RX5 DPGA Volume", ISABELLE_RX5_DPGA_REG, 0, 0x3F, 0,
+			rx_tlv),
+	SOC_SINGLE_TLV("RX6 DPGA Volume", ISABELLE_RX6_DPGA_REG, 0, 0x3F, 0,
+			rx_tlv),
+
+	SOC_SINGLE("Headset Noise Gate", ISABELLE_HS_NG_CFG1_REG, 7, 1, 0),
+	SOC_SINGLE("Handsfree Noise Gate", ISABELLE_HF_NG_CFG1_REG, 7, 1, 0),
+
+	SOC_SINGLE("ATX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		7, 1, 0),
+	SOC_SINGLE("ATX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		6, 1, 0),
+	SOC_SINGLE("ARX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		5, 1, 0),
+	SOC_SINGLE("ARX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		4, 1, 0),
+	SOC_SINGLE("ARX3 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		3, 1, 0),
+	SOC_SINGLE("ARX4 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		2, 1, 0),
+	SOC_SINGLE("ARX5 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		1, 1, 0),
+	SOC_SINGLE("ARX6 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		0, 1, 0),
+	SOC_SINGLE("VRX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		3, 1, 0),
+	SOC_SINGLE("VRX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG,
+		2, 1, 0),
+
+	SOC_SINGLE("ATX1 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG,
+		7, 1, 0),
+	SOC_SINGLE("ATX2 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG,
+		6, 1, 0),
+	SOC_SINGLE("VTX1 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG,
+		5, 1, 0),
+	SOC_SINGLE("VTX2 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG,
+		4, 1, 0),
+	SOC_SINGLE("RX1 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+		5, 1, 0),
+	SOC_SINGLE("RX2 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+		4, 1, 0),
+	SOC_SINGLE("RX3 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+		3, 1, 0),
+	SOC_SINGLE("RX4 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+		2, 1, 0),
+	SOC_SINGLE("RX5 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+		1, 1, 0),
+	SOC_SINGLE("RX6 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG,
+		0, 1, 0),
+
+	SOC_SINGLE("ULATX12 Capture Switch", ISABELLE_ULATX12_INTF_CFG_REG,
+		7, 1, 0),
+
+	SOC_SINGLE("DL12 Playback Switch", ISABELLE_DL12_INTF_CFG_REG,
+		7, 1, 0),
+	SOC_SINGLE("DL34 Playback Switch", ISABELLE_DL34_INTF_CFG_REG,
+		7, 1, 0),
+	SOC_SINGLE("DL56 Playback Switch", ISABELLE_DL56_INTF_CFG_REG,
+		7, 1, 0),
+
+	/* DMIC Switch */
+	SOC_SINGLE("DMIC Switch", ISABELLE_DMIC_CFG_REG, 0, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget isabelle_dapm_widgets[] = {
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("MAINMIC"),
+	SND_SOC_DAPM_INPUT("HSMIC"),
+	SND_SOC_DAPM_INPUT("SUBMIC"),
+	SND_SOC_DAPM_INPUT("LINEIN1"),
+	SND_SOC_DAPM_INPUT("LINEIN2"),
+	SND_SOC_DAPM_INPUT("DMICDAT"),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("HSOL"),
+	SND_SOC_DAPM_OUTPUT("HSOR"),
+	SND_SOC_DAPM_OUTPUT("HFL"),
+	SND_SOC_DAPM_OUTPUT("HFR"),
+	SND_SOC_DAPM_OUTPUT("EP"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+
+	SND_SOC_DAPM_PGA("DL1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DL2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DL3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DL4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DL5", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DL6", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Analog input muxes for the capture amplifiers */
+	SND_SOC_DAPM_MUX("Analog Left Capture Route",
+			SND_SOC_NOPM, 0, 0, &amic1_control),
+	SND_SOC_DAPM_MUX("Analog Right Capture Route",
+			SND_SOC_NOPM, 0, 0, &amic2_control),
+
+	SND_SOC_DAPM_MUX("Sidetone Audio Playback", SND_SOC_NOPM, 0, 0,
+			&st_audio_control),
+	SND_SOC_DAPM_MUX("Sidetone Voice Playback", SND_SOC_NOPM, 0, 0,
+			&st_voice_control),
+
+	/* AIF */
+	SND_SOC_DAPM_AIF_IN("INTF1_SDI", NULL, 0, ISABELLE_INTF_EN_REG, 7, 0),
+	SND_SOC_DAPM_AIF_IN("INTF2_SDI", NULL, 0, ISABELLE_INTF_EN_REG, 6, 0),
+
+	SND_SOC_DAPM_AIF_OUT("INTF1_SDO", NULL, 0, ISABELLE_INTF_EN_REG, 5, 0),
+	SND_SOC_DAPM_AIF_OUT("INTF2_SDO", NULL, 0, ISABELLE_INTF_EN_REG, 4, 0),
+
+	SND_SOC_DAPM_OUT_DRV("ULATX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("ULATX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("ULVTX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("ULVTX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Analog Capture PGAs */
+	SND_SOC_DAPM_PGA("MicAmp1", ISABELLE_AMIC_CFG_REG, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MicAmp2", ISABELLE_AMIC_CFG_REG, 4, 0, NULL, 0),
+
+	/* Auxiliary FM PGAs */
+	SND_SOC_DAPM_PGA("APGA1", ISABELLE_APGA_CFG_REG, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("APGA2", ISABELLE_APGA_CFG_REG, 6, 0, NULL, 0),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC1", "Left Front Capture",
+			ISABELLE_AMIC_CFG_REG, 7, 0),
+	SND_SOC_DAPM_ADC("ADC2", "Right Front Capture",
+			ISABELLE_AMIC_CFG_REG, 6, 0),
+
+	/* Microphone Bias */
+	SND_SOC_DAPM_SUPPLY("Headset Mic Bias", ISABELLE_ABIAS_CFG_REG,
+			3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Main Mic Bias", ISABELLE_ABIAS_CFG_REG,
+			2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Digital Mic1 Bias",
+			ISABELLE_DBIAS_CFG_REG, 3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Digital Mic2 Bias",
+			ISABELLE_DBIAS_CFG_REG, 2, 0, NULL, 0),
+
+	/* Mixers */
+	SND_SOC_DAPM_MIXER("Headset Left Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_hs_left_mixer_controls,
+			ARRAY_SIZE(isabelle_hs_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Headset Right Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_hs_right_mixer_controls,
+			ARRAY_SIZE(isabelle_hs_right_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Handsfree Left Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_hf_left_mixer_controls,
+			ARRAY_SIZE(isabelle_hf_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Handsfree Right Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_hf_right_mixer_controls,
+			ARRAY_SIZE(isabelle_hf_right_mixer_controls)),
+	SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_aux_left_mixer_controls,
+			ARRAY_SIZE(isabelle_aux_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_aux_right_mixer_controls,
+			ARRAY_SIZE(isabelle_aux_right_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Earphone Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_ep_mixer_controls,
+			ARRAY_SIZE(isabelle_ep_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("DPGA1L Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_dpga1_left_mixer_controls,
+			ARRAY_SIZE(isabelle_dpga1_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("DPGA1R Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_dpga1_right_mixer_controls,
+			ARRAY_SIZE(isabelle_dpga1_right_mixer_controls)),
+	SND_SOC_DAPM_MIXER("DPGA2L Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_dpga2_left_mixer_controls,
+			ARRAY_SIZE(isabelle_dpga2_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("DPGA2R Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_dpga2_right_mixer_controls,
+			ARRAY_SIZE(isabelle_dpga2_right_mixer_controls)),
+	SND_SOC_DAPM_MIXER("DPGA3L Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_dpga3_left_mixer_controls,
+			ARRAY_SIZE(isabelle_dpga3_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("DPGA3R Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_dpga3_right_mixer_controls,
+			ARRAY_SIZE(isabelle_dpga3_right_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("RX1 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_rx1_mixer_controls,
+			ARRAY_SIZE(isabelle_rx1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("RX2 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_rx2_mixer_controls,
+			ARRAY_SIZE(isabelle_rx2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("RX3 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_rx3_mixer_controls,
+			ARRAY_SIZE(isabelle_rx3_mixer_controls)),
+	SND_SOC_DAPM_MIXER("RX4 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_rx4_mixer_controls,
+			ARRAY_SIZE(isabelle_rx4_mixer_controls)),
+	SND_SOC_DAPM_MIXER("RX5 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_rx5_mixer_controls,
+			ARRAY_SIZE(isabelle_rx5_mixer_controls)),
+	SND_SOC_DAPM_MIXER("RX6 Mixer", SND_SOC_NOPM, 0, 0,
+			isabelle_rx6_mixer_controls,
+			ARRAY_SIZE(isabelle_rx6_mixer_controls)),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC1L", "Headset Playback", ISABELLE_DAC_CFG_REG,
+			5, 0),
+	SND_SOC_DAPM_DAC("DAC1R", "Headset Playback", ISABELLE_DAC_CFG_REG,
+			4, 0),
+	SND_SOC_DAPM_DAC("DAC2L", "Handsfree Playback", ISABELLE_DAC_CFG_REG,
+			3, 0),
+	SND_SOC_DAPM_DAC("DAC2R", "Handsfree Playback", ISABELLE_DAC_CFG_REG,
+			2, 0),
+	SND_SOC_DAPM_DAC("DAC3L", "Lineout Playback", ISABELLE_DAC_CFG_REG,
+			1, 0),
+	SND_SOC_DAPM_DAC("DAC3R", "Lineout Playback", ISABELLE_DAC_CFG_REG,
+			0, 0),
+
+	/* Analog Playback PGAs */
+	SND_SOC_DAPM_PGA("Sidetone Audio PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Sidetone Voice PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HF Left PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HF Right PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DPGA1L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DPGA1R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DPGA2L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DPGA2R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DPGA3L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DPGA3R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Analog Playback Mux */
+	SND_SOC_DAPM_MUX("RX1 Playback", ISABELLE_ALU_RX_EN_REG, 5, 0,
+			&rx1_mux_controls),
+	SND_SOC_DAPM_MUX("RX2 Playback", ISABELLE_ALU_RX_EN_REG, 4, 0,
+			&rx2_mux_controls),
+
+	/* TX Select */
+	SND_SOC_DAPM_MUX("ATX Select", ISABELLE_TX_INPUT_CFG_REG,
+			7, 0, &atx_mux_controls),
+	SND_SOC_DAPM_MUX("VTX Select", ISABELLE_TX_INPUT_CFG_REG,
+			6, 0, &vtx_mux_controls),
+
+	SND_SOC_DAPM_SWITCH("Earphone Playback", SND_SOC_NOPM, 0, 0,
+			&ep_path_enable_control),
+
+	/* Output Drivers */
+	SND_SOC_DAPM_OUT_DRV("HS Left Driver", ISABELLE_HSDRV_CFG2_REG,
+			1, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("HS Right Driver", ISABELLE_HSDRV_CFG2_REG,
+			0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("LINEOUT1 Left Driver", ISABELLE_LINEAMP_CFG_REG,
+			1, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("LINEOUT2 Right Driver", ISABELLE_LINEAMP_CFG_REG,
+			0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Earphone Driver", ISABELLE_EARDRV_CFG2_REG,
+			1, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUT_DRV("HF Left Driver", ISABELLE_HFDRV_CFG_REG,
+			1, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("HF Right Driver", ISABELLE_HFDRV_CFG_REG,
+			0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route isabelle_intercon[] = {
+	/* Interface mapping */
+	{ "DL1", "DL12 Playback Switch", "INTF1_SDI" },
+	{ "DL2", "DL12 Playback Switch", "INTF1_SDI" },
+	{ "DL3", "DL34 Playback Switch", "INTF1_SDI" },
+	{ "DL4", "DL34 Playback Switch", "INTF1_SDI" },
+	{ "DL5", "DL56 Playback Switch", "INTF1_SDI" },
+	{ "DL6", "DL56 Playback Switch", "INTF1_SDI" },
+
+	{ "DL1", "DL12 Playback Switch", "INTF2_SDI" },
+	{ "DL2", "DL12 Playback Switch", "INTF2_SDI" },
+	{ "DL3", "DL34 Playback Switch", "INTF2_SDI" },
+	{ "DL4", "DL34 Playback Switch", "INTF2_SDI" },
+	{ "DL5", "DL56 Playback Switch", "INTF2_SDI" },
+	{ "DL6", "DL56 Playback Switch", "INTF2_SDI" },
+
+	/* Input side mapping */
+	{ "Sidetone Audio PGA", NULL, "Sidetone Audio Playback" },
+	{ "Sidetone Voice PGA", NULL, "Sidetone Voice Playback" },
+
+	{ "RX1 Mixer", "ST1 Playback Switch", "Sidetone Audio PGA" },
+
+	{ "RX1 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" },
+	{ "RX1 Mixer", "DL1 Playback Switch", "DL1" },
+
+	{ "RX2 Mixer", "ST2 Playback Switch", "Sidetone Audio PGA" },
+
+	{ "RX2 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" },
+	{ "RX2 Mixer", "DL2 Playback Switch", "DL2" },
+
+	{ "RX3 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" },
+	{ "RX3 Mixer", "DL3 Playback Switch", "DL3" },
+
+	{ "RX4 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" },
+	{ "RX4 Mixer", "DL4 Playback Switch", "DL4" },
+
+	{ "RX5 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" },
+	{ "RX5 Mixer", "DL5 Playback Switch", "DL5" },
+
+	{ "RX6 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" },
+	{ "RX6 Mixer", "DL6 Playback Switch", "DL6" },
+
+	/* Capture path */
+	{ "Analog Left Capture Route", "Headset Mic", "HSMIC" },
+	{ "Analog Left Capture Route", "Main Mic", "MAINMIC" },
+	{ "Analog Left Capture Route", "Aux/FM Left", "LINEIN1" },
+
+	{ "Analog Right Capture Route", "Sub Mic", "SUBMIC" },
+	{ "Analog Right Capture Route", "Aux/FM Right", "LINEIN2" },
+
+	{ "MicAmp1", NULL, "Analog Left Capture Route" },
+	{ "MicAmp2", NULL, "Analog Right Capture Route" },
+
+	{ "ADC1", NULL, "MicAmp1" },
+	{ "ADC2", NULL, "MicAmp2" },
+
+	{ "ATX Select", "AMIC1", "ADC1" },
+	{ "ATX Select", "DMIC", "DMICDAT" },
+	{ "ATX Select", "AMIC2", "ADC2" },
+
+	{ "VTX Select", "AMIC1", "ADC1" },
+	{ "VTX Select", "DMIC", "DMICDAT" },
+	{ "VTX Select", "AMIC2", "ADC2" },
+
+	{ "ULATX1", "ATX1 Filter Enable Switch", "ATX Select" },
+	{ "ULATX1", "ATX1 Filter Bypass Switch", "ATX Select" },
+	{ "ULATX2", "ATX2 Filter Enable Switch", "ATX Select" },
+	{ "ULATX2", "ATX2 Filter Bypass Switch", "ATX Select" },
+
+	{ "ULVTX1", "VTX1 Filter Enable Switch", "VTX Select" },
+	{ "ULVTX1", "VTX1 Filter Bypass Switch", "VTX Select" },
+	{ "ULVTX2", "VTX2 Filter Enable Switch", "VTX Select" },
+	{ "ULVTX2", "VTX2 Filter Bypass Switch", "VTX Select" },
+
+	{ "INTF1_SDO", "ULATX12 Capture Switch", "ULATX1" },
+	{ "INTF1_SDO", "ULATX12 Capture Switch", "ULATX2" },
+	{ "INTF2_SDO", "ULATX12 Capture Switch", "ULATX1" },
+	{ "INTF2_SDO", "ULATX12 Capture Switch", "ULATX2" },
+
+	{ "INTF1_SDO", NULL, "ULVTX1" },
+	{ "INTF1_SDO", NULL, "ULVTX2" },
+	{ "INTF2_SDO", NULL, "ULVTX1" },
+	{ "INTF2_SDO", NULL, "ULVTX2" },
+
+	/* AFM Path */
+	{ "APGA1", NULL, "LINEIN1" },
+	{ "APGA2", NULL, "LINEIN2" },
+
+	{ "RX1 Playback", "VRX1 Filter Bypass Switch", "RX1 Mixer" },
+	{ "RX1 Playback", "ARX1 Filter Bypass Switch", "RX1 Mixer" },
+	{ "RX1 Playback", "RX1 Filter Enable Switch", "RX1 Mixer" },
+
+	{ "RX2 Playback", "VRX2 Filter Bypass Switch", "RX2 Mixer" },
+	{ "RX2 Playback", "ARX2 Filter Bypass Switch", "RX2 Mixer" },
+	{ "RX2 Playback", "RX2 Filter Enable Switch", "RX2 Mixer" },
+
+	{ "RX3 Playback", "ARX3 Filter Bypass Switch", "RX3 Mixer" },
+	{ "RX3 Playback", "RX3 Filter Enable Switch", "RX3 Mixer" },
+
+	{ "RX4 Playback", "ARX4 Filter Bypass Switch", "RX4 Mixer" },
+	{ "RX4 Playback", "RX4 Filter Enable Switch", "RX4 Mixer" },
+
+	{ "RX5 Playback", "ARX5 Filter Bypass Switch", "RX5 Mixer" },
+	{ "RX5 Playback", "RX5 Filter Enable Switch", "RX5 Mixer" },
+
+	{ "RX6 Playback", "ARX6 Filter Bypass Switch", "RX6 Mixer" },
+	{ "RX6 Playback", "RX6 Filter Enable Switch", "RX6 Mixer" },
+
+	{ "DPGA1L Mixer", "RX1 Playback Switch", "RX1 Playback" },
+	{ "DPGA1L Mixer", "RX3 Playback Switch", "RX3 Playback" },
+	{ "DPGA1L Mixer", "RX5 Playback Switch", "RX5 Playback" },
+
+	{ "DPGA1R Mixer", "RX2 Playback Switch", "RX2 Playback" },
+	{ "DPGA1R Mixer", "RX4 Playback Switch", "RX4 Playback" },
+	{ "DPGA1R Mixer", "RX6 Playback Switch", "RX6 Playback" },
+
+	{ "DPGA1L", NULL, "DPGA1L Mixer" },
+	{ "DPGA1R", NULL, "DPGA1R Mixer" },
+
+	{ "DAC1L", NULL, "DPGA1L" },
+	{ "DAC1R", NULL, "DPGA1R" },
+
+	{ "DPGA2L Mixer", "RX1 Playback Switch", "RX1 Playback" },
+	{ "DPGA2L Mixer", "RX2 Playback Switch", "RX2 Playback" },
+	{ "DPGA2L Mixer", "RX3 Playback Switch", "RX3 Playback" },
+	{ "DPGA2L Mixer", "RX4 Playback Switch", "RX4 Playback" },
+	{ "DPGA2L Mixer", "RX5 Playback Switch", "RX5 Playback" },
+	{ "DPGA2L Mixer", "RX6 Playback Switch", "RX6 Playback" },
+
+	{ "DPGA2R Mixer", "RX2 Playback Switch", "RX2 Playback" },
+	{ "DPGA2R Mixer", "RX4 Playback Switch", "RX4 Playback" },
+	{ "DPGA2R Mixer", "RX6 Playback Switch", "RX6 Playback" },
+
+	{ "DPGA2L", NULL, "DPGA2L Mixer" },
+	{ "DPGA2R", NULL, "DPGA2R Mixer" },
+
+	{ "DAC2L", NULL, "DPGA2L" },
+	{ "DAC2R", NULL, "DPGA2R" },
+
+	{ "DPGA3L Mixer", "RX1 Playback Switch", "RX1 Playback" },
+	{ "DPGA3L Mixer", "RX3 Playback Switch", "RX3 Playback" },
+	{ "DPGA3L Mixer", "RX5 Playback Switch", "RX5 Playback" },
+
+	{ "DPGA3R Mixer", "RX2 Playback Switch", "RX2 Playback" },
+	{ "DPGA3R Mixer", "RX4 Playback Switch", "RX4 Playback" },
+	{ "DPGA3R Mixer", "RX6 Playback Switch", "RX6 Playback" },
+
+	{ "DPGA3L", NULL, "DPGA3L Mixer" },
+	{ "DPGA3R", NULL, "DPGA3R Mixer" },
+
+	{ "DAC3L", NULL, "DPGA3L" },
+	{ "DAC3R", NULL, "DPGA3R" },
+
+	{ "Headset Left Mixer", "DAC1L Playback Switch", "DAC1L" },
+	{ "Headset Left Mixer", "APGA1 Playback Switch", "APGA1" },
+
+	{ "Headset Right Mixer", "DAC1R Playback Switch", "DAC1R" },
+	{ "Headset Right Mixer", "APGA2 Playback Switch", "APGA2" },
+
+	{ "HS Left Driver", NULL, "Headset Left Mixer" },
+	{ "HS Right Driver", NULL, "Headset Right Mixer" },
+
+	{ "HSOL", NULL, "HS Left Driver" },
+	{ "HSOR", NULL, "HS Right Driver" },
+
+	/* Earphone playback path */
+	{ "Earphone Mixer", "DAC2L Playback Switch", "DAC2L" },
+	{ "Earphone Mixer", "APGA1 Playback Switch", "APGA1" },
+
+	{ "Earphone Playback", "Switch", "Earphone Mixer" },
+	{ "Earphone Driver", NULL, "Earphone Playback" },
+	{ "EP", NULL, "Earphone Driver" },
+
+	{ "Handsfree Left Mixer", "DAC2L Playback Switch", "DAC2L" },
+	{ "Handsfree Left Mixer", "APGA1 Playback Switch", "APGA1" },
+
+	{ "Handsfree Right Mixer", "DAC2R Playback Switch", "DAC2R" },
+	{ "Handsfree Right Mixer", "APGA2 Playback Switch", "APGA2" },
+
+	{ "HF Left PGA", NULL, "Handsfree Left Mixer" },
+	{ "HF Right PGA", NULL, "Handsfree Right Mixer" },
+
+	{ "HF Left Driver", NULL, "HF Left PGA" },
+	{ "HF Right Driver", NULL, "HF Right PGA" },
+
+	{ "HFL", NULL, "HF Left Driver" },
+	{ "HFR", NULL, "HF Right Driver" },
+
+	{ "LINEOUT1 Mixer", "DAC3L Playback Switch", "DAC3L" },
+	{ "LINEOUT1 Mixer", "APGA1 Playback Switch", "APGA1" },
+
+	{ "LINEOUT2 Mixer", "DAC3R Playback Switch", "DAC3R" },
+	{ "LINEOUT2 Mixer", "APGA2 Playback Switch", "APGA2" },
+
+	{ "LINEOUT1 Driver", NULL, "LINEOUT1 Mixer" },
+	{ "LINEOUT2 Driver", NULL, "LINEOUT2 Mixer" },
+
+	{ "LINEOUT1", NULL, "LINEOUT1 Driver" },
+	{ "LINEOUT2", NULL, "LINEOUT2 Driver" },
+};
+
+static int isabelle_hs_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_component_update_bits(dai->component, ISABELLE_DAC1_SOFTRAMP_REG,
+			BIT(4), (mute ? BIT(4) : 0));
+
+	return 0;
+}
+
+static int isabelle_hf_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_component_update_bits(dai->component, ISABELLE_DAC2_SOFTRAMP_REG,
+			BIT(4), (mute ? BIT(4) : 0));
+
+	return 0;
+}
+
+static int isabelle_line_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_component_update_bits(dai->component, ISABELLE_DAC3_SOFTRAMP_REG,
+			BIT(4), (mute ? BIT(4) : 0));
+
+	return 0;
+}
+
+static int isabelle_set_bias_level(struct snd_soc_component *component,
+				enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_component_update_bits(component, ISABELLE_PWR_EN_REG,
+				ISABELLE_CHIP_EN, BIT(0));
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, ISABELLE_PWR_EN_REG,
+				ISABELLE_CHIP_EN, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static int isabelle_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 aif = 0;
+	unsigned int fs_val = 0;
+
+	switch (params_rate(params)) {
+	case 8000:
+		fs_val = ISABELLE_FS_RATE_8;
+		break;
+	case 11025:
+		fs_val = ISABELLE_FS_RATE_11;
+		break;
+	case 12000:
+		fs_val = ISABELLE_FS_RATE_12;
+		break;
+	case 16000:
+		fs_val = ISABELLE_FS_RATE_16;
+		break;
+	case 22050:
+		fs_val = ISABELLE_FS_RATE_22;
+		break;
+	case 24000:
+		fs_val = ISABELLE_FS_RATE_24;
+		break;
+	case 32000:
+		fs_val = ISABELLE_FS_RATE_32;
+		break;
+	case 44100:
+		fs_val = ISABELLE_FS_RATE_44;
+		break;
+	case 48000:
+		fs_val = ISABELLE_FS_RATE_48;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, ISABELLE_FS_RATE_CFG_REG,
+			ISABELLE_FS_RATE_MASK, fs_val);
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 20:
+		aif |= ISABELLE_AIF_LENGTH_20;
+		break;
+	case 32:
+		aif |= ISABELLE_AIF_LENGTH_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, ISABELLE_INTF_CFG_REG,
+			ISABELLE_AIF_LENGTH_MASK, aif);
+
+	return 0;
+}
+
+static int isabelle_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	unsigned int aif_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		aif_val &= ~ISABELLE_AIF_MS;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif_val |= ISABELLE_AIF_MS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		aif_val |= ISABELLE_I2S_MODE;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif_val |= ISABELLE_LEFT_J_MODE;
+		break;
+	case SND_SOC_DAIFMT_PDM:
+		aif_val |= ISABELLE_PDM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, ISABELLE_INTF_CFG_REG,
+			(ISABELLE_AIF_MS | ISABELLE_AIF_FMT_MASK), aif_val);
+
+	return 0;
+}
+
+/* Rates supported by Isabelle driver */
+#define ISABELLE_RATES		SNDRV_PCM_RATE_8000_48000
+
+/* Formates supported by Isabelle driver. */
+#define ISABELLE_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops isabelle_hs_dai_ops = {
+	.hw_params	= isabelle_hw_params,
+	.set_fmt	= isabelle_set_dai_fmt,
+	.digital_mute	= isabelle_hs_mute,
+};
+
+static const struct snd_soc_dai_ops isabelle_hf_dai_ops = {
+	.hw_params	= isabelle_hw_params,
+	.set_fmt	= isabelle_set_dai_fmt,
+	.digital_mute	= isabelle_hf_mute,
+};
+
+static const struct snd_soc_dai_ops isabelle_line_dai_ops = {
+	.hw_params	= isabelle_hw_params,
+	.set_fmt	= isabelle_set_dai_fmt,
+	.digital_mute	= isabelle_line_mute,
+};
+
+static const struct snd_soc_dai_ops isabelle_ul_dai_ops = {
+	.hw_params	= isabelle_hw_params,
+	.set_fmt	= isabelle_set_dai_fmt,
+};
+
+/* ISABELLE dai structure */
+static struct snd_soc_dai_driver isabelle_dai[] = {
+	{
+		.name = "isabelle-dl1",
+		.playback = {
+			.stream_name = "Headset Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = ISABELLE_RATES,
+			.formats = ISABELLE_FORMATS,
+		},
+		.ops = &isabelle_hs_dai_ops,
+	},
+	{
+		.name = "isabelle-dl2",
+		.playback = {
+			.stream_name = "Handsfree Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = ISABELLE_RATES,
+			.formats = ISABELLE_FORMATS,
+		},
+		.ops = &isabelle_hf_dai_ops,
+	},
+	{
+		.name = "isabelle-lineout",
+		.playback = {
+			.stream_name = "Lineout Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = ISABELLE_RATES,
+			.formats = ISABELLE_FORMATS,
+		},
+		.ops = &isabelle_line_dai_ops,
+	},
+	{
+		.name = "isabelle-ul",
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = ISABELLE_RATES,
+			.formats = ISABELLE_FORMATS,
+		},
+		.ops = &isabelle_ul_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_isabelle = {
+	.set_bias_level		= isabelle_set_bias_level,
+	.controls		= isabelle_snd_controls,
+	.num_controls		= ARRAY_SIZE(isabelle_snd_controls),
+	.dapm_widgets		= isabelle_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(isabelle_dapm_widgets),
+	.dapm_routes		= isabelle_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(isabelle_intercon),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config isabelle_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = ISABELLE_MAX_REGISTER,
+	.reg_defaults = isabelle_reg_defs,
+	.num_reg_defaults = ARRAY_SIZE(isabelle_reg_defs),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int isabelle_i2c_probe(struct i2c_client *i2c,
+			      const struct i2c_device_id *id)
+{
+	struct regmap *isabelle_regmap;
+	int ret = 0;
+
+	isabelle_regmap = devm_regmap_init_i2c(i2c, &isabelle_regmap_config);
+	if (IS_ERR(isabelle_regmap)) {
+		ret = PTR_ERR(isabelle_regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+	i2c_set_clientdata(i2c, isabelle_regmap);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				&soc_component_dev_isabelle, isabelle_dai,
+				ARRAY_SIZE(isabelle_dai));
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static const struct i2c_device_id isabelle_i2c_id[] = {
+	{ "isabelle", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, isabelle_i2c_id);
+
+static struct i2c_driver isabelle_i2c_driver = {
+	.driver = {
+		.name = "isabelle",
+	},
+	.probe = isabelle_i2c_probe,
+	.id_table = isabelle_i2c_id,
+};
+
+module_i2c_driver(isabelle_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ISABELLE driver");
+MODULE_AUTHOR("Vishwas A Deshpande <vishwas.a.deshpande@ti.com>");
+MODULE_AUTHOR("M R Swami Reddy <MR.Swami.Reddy@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/isabelle.h b/sound/soc/codecs/isabelle.h
new file mode 100644
index 0000000..96d839a
--- /dev/null
+++ b/sound/soc/codecs/isabelle.h
@@ -0,0 +1,143 @@
+/*
+ * isabelle.h - Low power high fidelity audio codec driver header file
+ *
+ * Copyright (c) 2012 Texas Instruments, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ */
+
+#ifndef _ISABELLE_H
+#define _ISABELLE_H
+
+#include <linux/bitops.h>
+
+/* ISABELLE REGISTERS */
+
+#define ISABELLE_PWR_CFG_REG		0x01
+#define ISABELLE_PWR_EN_REG		0x02
+#define ISABELLE_PS_EN1_REG		0x03
+#define ISABELLE_INT1_STATUS_REG	0x04
+#define ISABELLE_INT1_MASK_REG		0x05
+#define ISABELLE_INT2_STATUS_REG	0x06
+#define ISABELLE_INT2_MASK_REG		0x07
+#define ISABELLE_HKCTL1_REG		0x08
+#define ISABELLE_HKCTL2_REG		0x09
+#define ISABELLE_HKCTL3_REG		0x0A
+#define ISABELLE_ACCDET_STATUS_REG	0x0B
+#define ISABELLE_BUTTON_ID_REG		0x0C
+#define ISABELLE_PLL_CFG_REG		0x10
+#define ISABELLE_PLL_EN_REG		0x11
+#define ISABELLE_FS_RATE_CFG_REG	0x12
+#define ISABELLE_INTF_CFG_REG		0x13
+#define ISABELLE_INTF_EN_REG		0x14
+#define ISABELLE_ULATX12_INTF_CFG_REG	0x15
+#define ISABELLE_DL12_INTF_CFG_REG	0x16
+#define ISABELLE_DL34_INTF_CFG_REG	0x17
+#define ISABELLE_DL56_INTF_CFG_REG	0x18
+#define ISABELLE_ATX_STPGA1_CFG_REG	0x19
+#define ISABELLE_ATX_STPGA2_CFG_REG	0x1A
+#define ISABELLE_VTX_STPGA1_CFG_REG	0x1B
+#define ISABELLE_VTX2_STPGA2_CFG_REG	0x1C
+#define ISABELLE_ATX1_DPGA_REG		0x1D
+#define ISABELLE_ATX2_DPGA_REG		0x1E
+#define ISABELLE_VTX1_DPGA_REG		0x1F
+#define ISABELLE_VTX2_DPGA_REG		0x20
+#define ISABELLE_TX_INPUT_CFG_REG	0x21
+#define ISABELLE_RX_INPUT_CFG_REG	0x22
+#define ISABELLE_RX_INPUT_CFG2_REG	0x23
+#define ISABELLE_VOICE_HPF_CFG_REG	0x24
+#define ISABELLE_AUDIO_HPF_CFG_REG	0x25
+#define ISABELLE_RX1_DPGA_REG		0x26
+#define ISABELLE_RX2_DPGA_REG		0x27
+#define ISABELLE_RX3_DPGA_REG		0x28
+#define ISABELLE_RX4_DPGA_REG		0x29
+#define ISABELLE_RX5_DPGA_REG		0x2A
+#define ISABELLE_RX6_DPGA_REG		0x2B
+#define ISABELLE_ALU_TX_EN_REG		0x2C
+#define ISABELLE_ALU_RX_EN_REG		0x2D
+#define ISABELLE_IIR_RESYNC_REG		0x2E
+#define ISABELLE_ABIAS_CFG_REG		0x30
+#define ISABELLE_DBIAS_CFG_REG		0x31
+#define ISABELLE_MIC1_GAIN_REG		0x32
+#define ISABELLE_MIC2_GAIN_REG		0x33
+#define ISABELLE_AMIC_CFG_REG		0x34
+#define ISABELLE_DMIC_CFG_REG		0x35
+#define ISABELLE_APGA_GAIN_REG		0x36
+#define ISABELLE_APGA_CFG_REG		0x37
+#define ISABELLE_TX_GAIN_DLY_REG	0x38
+#define ISABELLE_RX_GAIN_DLY_REG	0x39
+#define ISABELLE_RX_PWR_CTRL_REG	0x3A
+#define ISABELLE_DPGA1LR_IN_SEL_REG	0x3B
+#define ISABELLE_DPGA1L_GAIN_REG	0x3C
+#define ISABELLE_DPGA1R_GAIN_REG	0x3D
+#define ISABELLE_DPGA2L_IN_SEL_REG	0x3E
+#define ISABELLE_DPGA2R_IN_SEL_REG	0x3F
+#define ISABELLE_DPGA2L_GAIN_REG	0x40
+#define ISABELLE_DPGA2R_GAIN_REG	0x41
+#define ISABELLE_DPGA3LR_IN_SEL_REG	0x42
+#define ISABELLE_DPGA3L_GAIN_REG	0x43
+#define ISABELLE_DPGA3R_GAIN_REG	0x44
+#define ISABELLE_DAC1_SOFTRAMP_REG	0x45
+#define ISABELLE_DAC2_SOFTRAMP_REG	0x46
+#define ISABELLE_DAC3_SOFTRAMP_REG	0x47
+#define ISABELLE_DAC_CFG_REG		0x48
+#define ISABELLE_EARDRV_CFG1_REG	0x49
+#define ISABELLE_EARDRV_CFG2_REG	0x4A
+#define ISABELLE_HSDRV_GAIN_REG		0x4B
+#define ISABELLE_HSDRV_CFG1_REG		0x4C
+#define ISABELLE_HSDRV_CFG2_REG		0x4D
+#define ISABELLE_HS_NG_CFG1_REG		0x4E
+#define ISABELLE_HS_NG_CFG2_REG		0x4F
+#define ISABELLE_LINEAMP_GAIN_REG	0x50
+#define ISABELLE_LINEAMP_CFG_REG	0x51
+#define ISABELLE_HFL_VOL_CTRL_REG	0x52
+#define ISABELLE_HFL_SFTVOL_CTRL_REG	0x53
+#define ISABELLE_HFL_LIM_CTRL_1_REG	0x54
+#define ISABELLE_HFL_LIM_CTRL_2_REG	0x55
+#define ISABELLE_HFR_VOL_CTRL_REG	0x56
+#define ISABELLE_HFR_SFTVOL_CTRL_REG	0x57
+#define ISABELLE_HFR_LIM_CTRL_1_REG	0x58
+#define ISABELLE_HFR_LIM_CTRL_2_REG	0x59
+#define ISABELLE_HF_MODE_REG		0x5A
+#define ISABELLE_HFLPGA_CFG_REG		0x5B
+#define ISABELLE_HFRPGA_CFG_REG		0x5C
+#define ISABELLE_HFDRV_CFG_REG		0x5D
+#define ISABELLE_PDMOUT_CFG1_REG	0x5E
+#define ISABELLE_PDMOUT_CFG2_REG	0x5F
+#define ISABELLE_PDMOUT_L_WM_REG	0x60
+#define ISABELLE_PDMOUT_R_WM_REG	0x61
+#define ISABELLE_HF_NG_CFG1_REG		0x62
+#define ISABELLE_HF_NG_CFG2_REG		0x63
+
+/* ISABELLE_PWR_EN_REG (0x02h) */
+#define ISABELLE_CHIP_EN		BIT(0)
+
+/* ISABELLE DAI FORMATS */
+#define ISABELLE_AIF_FMT_MASK		0x70
+#define ISABELLE_I2S_MODE		0x0
+#define ISABELLE_LEFT_J_MODE		0x1
+#define ISABELLE_PDM_MODE		0x2
+
+#define ISABELLE_AIF_LENGTH_MASK	0x30
+#define ISABELLE_AIF_LENGTH_20		0x00
+#define ISABELLE_AIF_LENGTH_32		0x10
+
+#define ISABELLE_AIF_MS			0x80
+
+#define ISABELLE_FS_RATE_MASK		0xF
+#define ISABELLE_FS_RATE_8		0x0
+#define ISABELLE_FS_RATE_11		0x1
+#define ISABELLE_FS_RATE_12		0x2
+#define ISABELLE_FS_RATE_16		0x4
+#define ISABELLE_FS_RATE_22		0x5
+#define ISABELLE_FS_RATE_24		0x6
+#define ISABELLE_FS_RATE_32		0x8
+#define ISABELLE_FS_RATE_44		0x9
+#define ISABELLE_FS_RATE_48		0xA
+
+#define ISABELLE_MAX_REGISTER		0xFF
+
+#endif
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
new file mode 100644
index 0000000..9395b58
--- /dev/null
+++ b/sound/soc/codecs/jz4740.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/regmap.h>
+
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#define JZ4740_REG_CODEC_1 0x0
+#define JZ4740_REG_CODEC_2 0x4
+
+#define JZ4740_CODEC_1_LINE_ENABLE BIT(29)
+#define JZ4740_CODEC_1_MIC_ENABLE BIT(28)
+#define JZ4740_CODEC_1_SW1_ENABLE BIT(27)
+#define JZ4740_CODEC_1_ADC_ENABLE BIT(26)
+#define JZ4740_CODEC_1_SW2_ENABLE BIT(25)
+#define JZ4740_CODEC_1_DAC_ENABLE BIT(24)
+#define JZ4740_CODEC_1_VREF_DISABLE BIT(20)
+#define JZ4740_CODEC_1_VREF_AMP_DISABLE BIT(19)
+#define JZ4740_CODEC_1_VREF_PULLDOWN BIT(18)
+#define JZ4740_CODEC_1_VREF_LOW_CURRENT BIT(17)
+#define JZ4740_CODEC_1_VREF_HIGH_CURRENT BIT(16)
+#define JZ4740_CODEC_1_HEADPHONE_DISABLE BIT(14)
+#define JZ4740_CODEC_1_HEADPHONE_AMP_CHANGE_ANY BIT(13)
+#define JZ4740_CODEC_1_HEADPHONE_CHARGE BIT(12)
+#define JZ4740_CODEC_1_HEADPHONE_PULLDOWN (BIT(11) | BIT(10))
+#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M BIT(9)
+#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN BIT(8)
+#define JZ4740_CODEC_1_SUSPEND BIT(1)
+#define JZ4740_CODEC_1_RESET BIT(0)
+
+#define JZ4740_CODEC_1_LINE_ENABLE_OFFSET 29
+#define JZ4740_CODEC_1_MIC_ENABLE_OFFSET 28
+#define JZ4740_CODEC_1_SW1_ENABLE_OFFSET 27
+#define JZ4740_CODEC_1_ADC_ENABLE_OFFSET 26
+#define JZ4740_CODEC_1_SW2_ENABLE_OFFSET 25
+#define JZ4740_CODEC_1_DAC_ENABLE_OFFSET 24
+#define JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET 14
+#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN_OFFSET 8
+
+#define JZ4740_CODEC_2_INPUT_VOLUME_MASK		0x1f0000
+#define JZ4740_CODEC_2_SAMPLE_RATE_MASK			0x000f00
+#define JZ4740_CODEC_2_MIC_BOOST_GAIN_MASK		0x000030
+#define JZ4740_CODEC_2_HEADPHONE_VOLUME_MASK	0x000003
+
+#define JZ4740_CODEC_2_INPUT_VOLUME_OFFSET		16
+#define JZ4740_CODEC_2_SAMPLE_RATE_OFFSET		 8
+#define JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET	 4
+#define JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET	 0
+
+static const struct reg_default jz4740_codec_reg_defaults[] = {
+	{ JZ4740_REG_CODEC_1, 0x021b2302 },
+	{ JZ4740_REG_CODEC_2, 0x00170803 },
+};
+
+struct jz4740_codec {
+	struct regmap *regmap;
+};
+
+static const DECLARE_TLV_DB_RANGE(jz4740_mic_tlv,
+	0, 2, TLV_DB_SCALE_ITEM(0, 600, 0),
+	3, 3, TLV_DB_SCALE_ITEM(2000, 0, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(jz4740_out_tlv, 0, 200, 0);
+static const DECLARE_TLV_DB_SCALE(jz4740_in_tlv, -3450, 150, 0);
+
+static const struct snd_kcontrol_new jz4740_codec_controls[] = {
+	SOC_SINGLE_TLV("Master Playback Volume", JZ4740_REG_CODEC_2,
+			JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0,
+			jz4740_out_tlv),
+	SOC_SINGLE_TLV("Master Capture Volume", JZ4740_REG_CODEC_2,
+			JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0,
+			jz4740_in_tlv),
+	SOC_SINGLE("Master Playback Switch", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET, 1, 1),
+	SOC_SINGLE_TLV("Mic Capture Volume", JZ4740_REG_CODEC_2,
+			JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0,
+			jz4740_mic_tlv),
+};
+
+static const struct snd_kcontrol_new jz4740_codec_output_controls[] = {
+	SOC_DAPM_SINGLE("Bypass Switch", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_SW1_ENABLE_OFFSET, 1, 0),
+	SOC_DAPM_SINGLE("DAC Switch", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_SW2_ENABLE_OFFSET, 1, 0),
+};
+
+static const struct snd_kcontrol_new jz4740_codec_input_controls[] = {
+	SOC_DAPM_SINGLE("Line Capture Switch", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_LINE_ENABLE_OFFSET, 1, 0),
+	SOC_DAPM_SINGLE("Mic Capture Switch", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_MIC_ENABLE_OFFSET, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget jz4740_codec_dapm_widgets[] = {
+	SND_SOC_DAPM_ADC("ADC", "Capture", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_ADC_ENABLE_OFFSET, 0),
+	SND_SOC_DAPM_DAC("DAC", "Playback", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_DAC_ENABLE_OFFSET, 0),
+
+	SND_SOC_DAPM_MIXER("Output Mixer", JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_HEADPHONE_POWERDOWN_OFFSET, 1,
+			jz4740_codec_output_controls,
+			ARRAY_SIZE(jz4740_codec_output_controls)),
+
+	SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0,
+			jz4740_codec_input_controls,
+			ARRAY_SIZE(jz4740_codec_input_controls)),
+	SND_SOC_DAPM_MIXER("Line Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+	SND_SOC_DAPM_OUTPUT("ROUT"),
+
+	SND_SOC_DAPM_INPUT("MIC"),
+	SND_SOC_DAPM_INPUT("LIN"),
+	SND_SOC_DAPM_INPUT("RIN"),
+};
+
+static const struct snd_soc_dapm_route jz4740_codec_dapm_routes[] = {
+	{"Line Input", NULL, "LIN"},
+	{"Line Input", NULL, "RIN"},
+
+	{"Input Mixer", "Line Capture Switch", "Line Input"},
+	{"Input Mixer", "Mic Capture Switch", "MIC"},
+
+	{"ADC", NULL, "Input Mixer"},
+
+	{"Output Mixer", "Bypass Switch", "Input Mixer"},
+	{"Output Mixer", "DAC Switch", "DAC"},
+
+	{"LOUT", NULL, "Output Mixer"},
+	{"ROUT", NULL, "Output Mixer"},
+};
+
+static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct jz4740_codec *jz4740_codec = snd_soc_component_get_drvdata(dai->component);
+	uint32_t val;
+
+	switch (params_rate(params)) {
+	case 8000:
+		val = 0;
+		break;
+	case 11025:
+		val = 1;
+		break;
+	case 12000:
+		val = 2;
+		break;
+	case 16000:
+		val = 3;
+		break;
+	case 22050:
+		val = 4;
+		break;
+	case 24000:
+		val = 5;
+		break;
+	case 32000:
+		val = 6;
+		break;
+	case 44100:
+		val = 7;
+		break;
+	case 48000:
+		val = 8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val <<= JZ4740_CODEC_2_SAMPLE_RATE_OFFSET;
+
+	regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_2,
+				JZ4740_CODEC_2_SAMPLE_RATE_MASK, val);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops jz4740_codec_dai_ops = {
+	.hw_params = jz4740_codec_hw_params,
+};
+
+static struct snd_soc_dai_driver jz4740_codec_dai = {
+	.name = "jz4740-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
+	},
+	.ops = &jz4740_codec_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static void jz4740_codec_wakeup(struct regmap *regmap)
+{
+	regmap_update_bits(regmap, JZ4740_REG_CODEC_1,
+		JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET);
+	udelay(2);
+
+	regmap_update_bits(regmap, JZ4740_REG_CODEC_1,
+		JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0);
+
+	regcache_sync(regmap);
+}
+
+static int jz4740_codec_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	struct jz4740_codec *jz4740_codec = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = jz4740_codec->regmap;
+	unsigned int mask;
+	unsigned int value;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		mask = JZ4740_CODEC_1_VREF_DISABLE |
+				JZ4740_CODEC_1_VREF_AMP_DISABLE |
+				JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
+		value = 0;
+
+		regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* The only way to clear the suspend flag is to reset the codec */
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			jz4740_codec_wakeup(regmap);
+
+		mask = JZ4740_CODEC_1_VREF_DISABLE |
+			JZ4740_CODEC_1_VREF_AMP_DISABLE |
+			JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
+		value = JZ4740_CODEC_1_VREF_DISABLE |
+			JZ4740_CODEC_1_VREF_AMP_DISABLE |
+			JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
+
+		regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
+		break;
+	case SND_SOC_BIAS_OFF:
+		mask = JZ4740_CODEC_1_SUSPEND;
+		value = JZ4740_CODEC_1_SUSPEND;
+
+		regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
+		regcache_mark_dirty(regmap);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int jz4740_codec_dev_probe(struct snd_soc_component *component)
+{
+	struct jz4740_codec *jz4740_codec = snd_soc_component_get_drvdata(component);
+
+	regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_1,
+			JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_jz4740_codec = {
+	.probe			= jz4740_codec_dev_probe,
+	.set_bias_level		= jz4740_codec_set_bias_level,
+	.controls		= jz4740_codec_controls,
+	.num_controls		= ARRAY_SIZE(jz4740_codec_controls),
+	.dapm_widgets		= jz4740_codec_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(jz4740_codec_dapm_widgets),
+	.dapm_routes		= jz4740_codec_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(jz4740_codec_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+
+};
+
+static const struct regmap_config jz4740_codec_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = JZ4740_REG_CODEC_2,
+
+	.reg_defaults = jz4740_codec_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(jz4740_codec_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int jz4740_codec_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct jz4740_codec *jz4740_codec;
+	struct resource *mem;
+	void __iomem *base;
+
+	jz4740_codec = devm_kzalloc(&pdev->dev, sizeof(*jz4740_codec),
+				    GFP_KERNEL);
+	if (!jz4740_codec)
+		return -ENOMEM;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	jz4740_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+					    &jz4740_codec_regmap_config);
+	if (IS_ERR(jz4740_codec->regmap))
+		return PTR_ERR(jz4740_codec->regmap);
+
+	platform_set_drvdata(pdev, jz4740_codec);
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+			&soc_codec_dev_jz4740_codec, &jz4740_codec_dai, 1);
+	if (ret)
+		dev_err(&pdev->dev, "Failed to register codec\n");
+
+	return ret;
+}
+
+static struct platform_driver jz4740_codec_driver = {
+	.probe = jz4740_codec_probe,
+	.driver = {
+		.name = "jz4740-codec",
+	},
+};
+
+module_platform_driver(jz4740_codec_driver);
+
+MODULE_DESCRIPTION("JZ4740 SoC internal codec driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:jz4740-codec");
diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c
new file mode 100644
index 0000000..a10ea3c
--- /dev/null
+++ b/sound/soc/codecs/l3.c
@@ -0,0 +1,138 @@
+/*
+ * L3 code
+ *
+ *  Copyright (C) 2008, Christian Pellegrin <chripell@evolware.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *
+ * based on:
+ *
+ * L3 bus algorithm module.
+ *
+ *  Copyright (C) 2001 Russell King, All Rights Reserved.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+
+#include <sound/l3.h>
+
+/*
+ * Send one byte of data to the chip.  Data is latched into the chip on
+ * the rising edge of the clock.
+ */
+static void sendbyte(struct l3_pins *adap, unsigned int byte)
+{
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		adap->setclk(adap, 0);
+		udelay(adap->data_hold);
+		adap->setdat(adap, byte & 1);
+		udelay(adap->data_setup);
+		adap->setclk(adap, 1);
+		udelay(adap->clock_high);
+		byte >>= 1;
+	}
+}
+
+/*
+ * Send a set of bytes to the chip.  We need to pulse the MODE line
+ * between each byte, but never at the start nor at the end of the
+ * transfer.
+ */
+static void sendbytes(struct l3_pins *adap, const u8 *buf,
+		      int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++) {
+		if (i) {
+			udelay(adap->mode_hold);
+			adap->setmode(adap, 0);
+			udelay(adap->mode);
+		}
+		adap->setmode(adap, 1);
+		udelay(adap->mode_setup);
+		sendbyte(adap, buf[i]);
+	}
+}
+
+int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len)
+{
+	adap->setclk(adap, 1);
+	adap->setdat(adap, 1);
+	adap->setmode(adap, 1);
+	udelay(adap->mode);
+
+	adap->setmode(adap, 0);
+	udelay(adap->mode_setup);
+	sendbyte(adap, addr);
+	udelay(adap->mode_hold);
+
+	sendbytes(adap, data, len);
+
+	adap->setclk(adap, 1);
+	adap->setdat(adap, 1);
+	adap->setmode(adap, 0);
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(l3_write);
+
+
+static void l3_set_clk(struct l3_pins *adap, int val)
+{
+	gpio_set_value(adap->gpio_clk, val);
+}
+
+static void l3_set_data(struct l3_pins *adap, int val)
+{
+	gpio_set_value(adap->gpio_data, val);
+}
+
+static void l3_set_mode(struct l3_pins *adap, int val)
+{
+	gpio_set_value(adap->gpio_mode, val);
+}
+
+int l3_set_gpio_ops(struct device *dev, struct l3_pins *adap)
+{
+	int ret;
+
+	if (!adap->use_gpios)
+		return -EINVAL;
+
+	ret = devm_gpio_request_one(dev, adap->gpio_data,
+				GPIOF_OUT_INIT_LOW, "l3_data");
+	if (ret < 0)
+		return ret;
+	adap->setdat = l3_set_data;
+
+	ret = devm_gpio_request_one(dev, adap->gpio_clk,
+				GPIOF_OUT_INIT_LOW, "l3_clk");
+	if (ret < 0)
+		return ret;
+	adap->setclk = l3_set_clk;
+
+	ret = devm_gpio_request_one(dev, adap->gpio_mode,
+				GPIOF_OUT_INIT_LOW, "l3_mode");
+	if (ret < 0)
+		return ret;
+	adap->setmode = l3_set_mode;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(l3_set_gpio_ops);
+
+MODULE_DESCRIPTION("L3 bit-banging driver");
+MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c
new file mode 100644
index 0000000..1e96407
--- /dev/null
+++ b/sound/soc/codecs/lm4857.c
@@ -0,0 +1,154 @@
+/*
+ * LM4857 AMP driver
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com
+ * Copyright 2011 Lars-Peter Clausen <lars@metafoo.de>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+static const struct reg_default lm4857_default_regs[] = {
+	{ 0x0, 0x00 },
+	{ 0x1, 0x00 },
+	{ 0x2, 0x00 },
+	{ 0x3, 0x00 },
+};
+
+/* The register offsets in the cache array */
+#define LM4857_MVOL 0
+#define LM4857_LVOL 1
+#define LM4857_RVOL 2
+#define LM4857_CTRL 3
+
+/* the shifts required to set these bits */
+#define LM4857_3D 5
+#define LM4857_WAKEUP 5
+#define LM4857_EPGAIN 4
+
+static const unsigned int lm4857_mode_values[] = {
+	0,
+	6,
+	7,
+	8,
+	9,
+};
+
+static const char * const lm4857_mode_texts[] = {
+	"Off",
+	"Earpiece",
+	"Loudspeaker",
+	"Loudspeaker + Headphone",
+	"Headphone",
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(lm4857_mode_enum,
+	LM4857_CTRL, 0, 0xf, lm4857_mode_texts, lm4857_mode_values);
+
+static const struct snd_kcontrol_new lm4857_mode_ctrl =
+	SOC_DAPM_ENUM("Mode", lm4857_mode_enum);
+
+static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("IN"),
+
+	SND_SOC_DAPM_DEMUX("Mode", SND_SOC_NOPM, 0, 0, &lm4857_mode_ctrl),
+
+	SND_SOC_DAPM_OUTPUT("LS"),
+	SND_SOC_DAPM_OUTPUT("HP"),
+	SND_SOC_DAPM_OUTPUT("EP"),
+};
+
+static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0);
+
+static const struct snd_kcontrol_new lm4857_controls[] = {
+	SOC_SINGLE_TLV("Left Playback Volume", LM4857_LVOL, 0, 31, 0,
+		stereo_tlv),
+	SOC_SINGLE_TLV("Right Playback Volume", LM4857_RVOL, 0, 31, 0,
+		stereo_tlv),
+	SOC_SINGLE_TLV("Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
+		mono_tlv),
+	SOC_SINGLE("Spk 3D Playback Switch", LM4857_LVOL, LM4857_3D, 1, 0),
+	SOC_SINGLE("HP 3D Playback Switch", LM4857_RVOL, LM4857_3D, 1, 0),
+	SOC_SINGLE("Fast Wakeup Playback Switch", LM4857_CTRL,
+		LM4857_WAKEUP, 1, 0),
+	SOC_SINGLE("Earpiece 6dB Playback Switch", LM4857_CTRL,
+		LM4857_EPGAIN, 1, 0),
+};
+
+static const struct snd_soc_dapm_route lm4857_routes[] = {
+	{ "Mode", NULL, "IN" },
+	{ "LS", "Loudspeaker", "Mode" },
+	{ "LS", "Loudspeaker + Headphone", "Mode" },
+	{ "HP", "Headphone", "Mode" },
+	{ "HP", "Loudspeaker + Headphone", "Mode" },
+	{ "EP", "Earpiece", "Mode" },
+};
+
+static const struct snd_soc_component_driver lm4857_component_driver = {
+	.controls = lm4857_controls,
+	.num_controls = ARRAY_SIZE(lm4857_controls),
+	.dapm_widgets = lm4857_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(lm4857_dapm_widgets),
+	.dapm_routes = lm4857_routes,
+	.num_dapm_routes = ARRAY_SIZE(lm4857_routes),
+};
+
+static const struct regmap_config lm4857_regmap_config = {
+	.val_bits = 6,
+	.reg_bits = 2,
+
+	.max_register = LM4857_CTRL,
+
+	.cache_type = REGCACHE_FLAT,
+	.reg_defaults = lm4857_default_regs,
+	.num_reg_defaults = ARRAY_SIZE(lm4857_default_regs),
+};
+
+static int lm4857_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return devm_snd_soc_register_component(&i2c->dev,
+		&lm4857_component_driver, NULL, 0);
+}
+
+static const struct i2c_device_id lm4857_i2c_id[] = {
+	{ "lm4857", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm4857_i2c_id);
+
+static struct i2c_driver lm4857_i2c_driver = {
+	.driver = {
+		.name = "lm4857",
+	},
+	.probe = lm4857_i2c_probe,
+	.id_table = lm4857_i2c_id,
+};
+
+module_i2c_driver(lm4857_i2c_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("LM4857 amplifier driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
new file mode 100644
index 0000000..59a646c
--- /dev/null
+++ b/sound/soc/codecs/lm49453.c
@@ -0,0 +1,1470 @@
+/*
+ * lm49453.c  -  LM49453 ALSA Soc Audio driver
+ *
+ * Copyright (c) 2012 Texas Instruments, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * Initially based on sound/soc/codecs/wm8350.c
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <asm/div64.h>
+#include "lm49453.h"
+
+static const struct reg_default lm49453_reg_defs[] = {
+	{ 0, 0x00 },
+	{ 1, 0x00 },
+	{ 2, 0x00 },
+	{ 3, 0x00 },
+	{ 4, 0x00 },
+	{ 5, 0x00 },
+	{ 6, 0x00 },
+	{ 7, 0x00 },
+	{ 8, 0x00 },
+	{ 9, 0x00 },
+	{ 10, 0x00 },
+	{ 11, 0x00 },
+	{ 12, 0x00 },
+	{ 13, 0x00 },
+	{ 14, 0x00 },
+	{ 15, 0x00 },
+	{ 16, 0x00 },
+	{ 17, 0x00 },
+	{ 18, 0x00 },
+	{ 19, 0x00 },
+	{ 20, 0x00 },
+	{ 21, 0x00 },
+	{ 22, 0x00 },
+	{ 23, 0x00 },
+	{ 32, 0x00 },
+	{ 33, 0x00 },
+	{ 35, 0x00 },
+	{ 36, 0x00 },
+	{ 37, 0x00 },
+	{ 46, 0x00 },
+	{ 48, 0x00 },
+	{ 49, 0x00 },
+	{ 51, 0x00 },
+	{ 56, 0x00 },
+	{ 58, 0x00 },
+	{ 59, 0x00 },
+	{ 60, 0x00 },
+	{ 61, 0x00 },
+	{ 62, 0x00 },
+	{ 63, 0x00 },
+	{ 64, 0x00 },
+	{ 65, 0x00 },
+	{ 66, 0x00 },
+	{ 67, 0x00 },
+	{ 68, 0x00 },
+	{ 69, 0x00 },
+	{ 70, 0x00 },
+	{ 71, 0x00 },
+	{ 72, 0x00 },
+	{ 73, 0x00 },
+	{ 74, 0x00 },
+	{ 75, 0x00 },
+	{ 76, 0x00 },
+	{ 77, 0x00 },
+	{ 78, 0x00 },
+	{ 79, 0x00 },
+	{ 80, 0x00 },
+	{ 81, 0x00 },
+	{ 82, 0x00 },
+	{ 83, 0x00 },
+	{ 85, 0x00 },
+	{ 85, 0x00 },
+	{ 86, 0x00 },
+	{ 87, 0x00 },
+	{ 88, 0x00 },
+	{ 89, 0x00 },
+	{ 90, 0x00 },
+	{ 91, 0x00 },
+	{ 92, 0x00 },
+	{ 93, 0x00 },
+	{ 94, 0x00 },
+	{ 95, 0x00 },
+	{ 96, 0x01 },
+	{ 97, 0x00 },
+	{ 98, 0x00 },
+	{ 99, 0x00 },
+	{ 100, 0x00 },
+	{ 101, 0x00 },
+	{ 102, 0x00 },
+	{ 103, 0x01 },
+	{ 104, 0x01 },
+	{ 105, 0x00 },
+	{ 106, 0x01 },
+	{ 107, 0x00 },
+	{ 108, 0x00 },
+	{ 109, 0x00 },
+	{ 110, 0x00 },
+	{ 111, 0x02 },
+	{ 112, 0x02 },
+	{ 113, 0x00 },
+	{ 121, 0x80 },
+	{ 122, 0xBB },
+	{ 123, 0x80 },
+	{ 124, 0xBB },
+	{ 128, 0x00 },
+	{ 130, 0x00 },
+	{ 131, 0x00 },
+	{ 132, 0x00 },
+	{ 133, 0x0A },
+	{ 134, 0x0A },
+	{ 135, 0x0A },
+	{ 136, 0x0F },
+	{ 137, 0x00 },
+	{ 138, 0x73 },
+	{ 139, 0x33 },
+	{ 140, 0x73 },
+	{ 141, 0x33 },
+	{ 142, 0x73 },
+	{ 143, 0x33 },
+	{ 144, 0x73 },
+	{ 145, 0x33 },
+	{ 146, 0x73 },
+	{ 147, 0x33 },
+	{ 148, 0x73 },
+	{ 149, 0x33 },
+	{ 150, 0x73 },
+	{ 151, 0x33 },
+	{ 152, 0x00 },
+	{ 153, 0x00 },
+	{ 154, 0x00 },
+	{ 155, 0x00 },
+	{ 176, 0x00 },
+	{ 177, 0x00 },
+	{ 178, 0x00 },
+	{ 179, 0x00 },
+	{ 180, 0x00 },
+	{ 181, 0x00 },
+	{ 182, 0x00 },
+	{ 183, 0x00 },
+	{ 184, 0x00 },
+	{ 185, 0x00 },
+	{ 186, 0x00 },
+	{ 187, 0x00 },
+	{ 188, 0x00 },
+	{ 189, 0x00 },
+	{ 208, 0x06 },
+	{ 209, 0x00 },
+	{ 210, 0x08 },
+	{ 211, 0x54 },
+	{ 212, 0x14 },
+	{ 213, 0x0d },
+	{ 214, 0x0d },
+	{ 215, 0x14 },
+	{ 216, 0x60 },
+	{ 221, 0x00 },
+	{ 222, 0x00 },
+	{ 223, 0x00 },
+	{ 224, 0x00 },
+	{ 248, 0x00 },
+	{ 249, 0x00 },
+	{ 250, 0x00 },
+	{ 255, 0x00 },
+};
+
+/* codec private data */
+struct lm49453_priv {
+	struct regmap *regmap;
+};
+
+/* capture path controls */
+
+static const char *lm49453_mic2mode_text[] = {"Single Ended", "Differential"};
+
+static SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5,
+			    lm49453_mic2mode_text);
+
+static const char *lm49453_dmic_cfg_text[] = {"DMICDAT1", "DMICDAT2"};
+
+static SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum,
+			    LM49453_P0_DIGITAL_MIC1_CONFIG_REG, 7,
+			    lm49453_dmic_cfg_text);
+
+static SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum,
+			    LM49453_P0_DIGITAL_MIC2_CONFIG_REG, 7,
+			    lm49453_dmic_cfg_text);
+
+/* MUX Controls */
+static const char *lm49453_adcl_mux_text[] = { "MIC1", "Aux_L" };
+
+static const char *lm49453_adcr_mux_text[] = { "MIC2", "Aux_R" };
+
+static SOC_ENUM_SINGLE_DECL(lm49453_adcl_enum,
+			    LM49453_P0_ANALOG_MIXER_ADC_REG, 0,
+			    lm49453_adcl_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(lm49453_adcr_enum,
+			    LM49453_P0_ANALOG_MIXER_ADC_REG, 1,
+			    lm49453_adcr_mux_text);
+
+static const struct snd_kcontrol_new lm49453_adcl_mux_control =
+	SOC_DAPM_ENUM("ADC Left Mux", lm49453_adcl_enum);
+
+static const struct snd_kcontrol_new lm49453_adcr_mux_control =
+	SOC_DAPM_ENUM("ADC Right Mux", lm49453_adcr_enum);
+
+static const struct snd_kcontrol_new lm49453_headset_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHPL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHPL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHPL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHPL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHPL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHPL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHPL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHPL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHPL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHPL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHPL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHPL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHPL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHPL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHPL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHPL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 0, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_headset_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHPR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHPR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHPR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHPR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHPR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHPR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHPR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHPR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHPR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHPR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHPR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHPR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHPR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHPR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHPR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHPR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 1, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_speaker_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLSL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLSL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLSL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLSL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLSL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLSL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLSL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLSL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLSL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLSL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLSL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLSL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLSL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLSL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLSL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLSL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 2, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_speaker_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLSR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLSR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLSR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLSR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLSR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLSR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLSR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLSR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLSR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLSR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLSR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLSR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLSR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLSR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLSR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLSR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 3, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_haptic_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHAL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHAL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHAL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHAL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHAL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHAL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHAL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHAL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHAL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHAL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHAL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHAL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHAL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHAL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHAL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHAL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 4, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_haptic_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHAR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHAR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHAR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHAR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHAR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHAR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHAR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHAR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHAR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHAR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHAR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHAR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHAR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHAR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHAR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHAR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 5, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_lineout_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLOL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLOL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLOL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLOL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLOL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLOL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLOL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLOL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLOL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLOL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLOL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLOL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLOL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLOL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLOL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLOL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 6, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_lineout_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLOR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLOR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLOR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLOR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLOR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLOR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLOR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLOR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLOR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLOR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLOR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLOR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLOR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLOR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLOR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLOR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 7, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx1_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_PORT1_TX1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_PORT1_TX1_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx2_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_PORT1_TX2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_PORT1_TX2_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx3_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX3_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX3_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX3_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX3_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX3_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX3_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_PORT1_TX3_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx4_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX4_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX4_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX4_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX4_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX4_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX4_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_PORT1_TX4_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx5_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX5_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX5_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX5_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX5_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX5_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX5_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_PORT1_TX5_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx6_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX6_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX6_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX6_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX6_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX6_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX6_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_PORT1_TX6_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx7_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX7_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX7_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX7_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX7_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX7_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX7_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_PORT1_TX7_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx8_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX8_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX8_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX8_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX8_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX8_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX8_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_PORT1_TX8_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port2_tx1_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT2_TX1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT2_TX1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT2_TX1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT2_TX1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT2_TX1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT2_TX1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_PORT2_TX1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_PORT2_TX1_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port2_tx2_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT2_TX2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT2_TX2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT2_TX2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT2_TX2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT2_TX2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT2_TX2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_PORT2_TX2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_PORT2_TX2_REG, 7, 1, 0),
+};
+
+/* TLV Declarations */
+static const DECLARE_TLV_DB_SCALE(adc_dac_tlv, -7650, 150, 1);
+static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 200, 1);
+static const DECLARE_TLV_DB_SCALE(port_tlv, -1800, 600, 0);
+static const DECLARE_TLV_DB_SCALE(stn_tlv, -7200, 150, 0);
+
+static const struct snd_kcontrol_new lm49453_sidetone_mixer_controls[] = {
+/* Sidetone supports mono only */
+SOC_DAPM_SINGLE_TLV("Sidetone ADCL Volume", LM49453_P0_STN_VOL_ADCL_REG,
+		     0, 0x3F, 0, stn_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone ADCR Volume", LM49453_P0_STN_VOL_ADCR_REG,
+		     0, 0x3F, 0, stn_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC1L Volume", LM49453_P0_STN_VOL_DMIC1L_REG,
+		     0, 0x3F, 0, stn_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC1R Volume", LM49453_P0_STN_VOL_DMIC1R_REG,
+		     0, 0x3F, 0, stn_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC2L Volume", LM49453_P0_STN_VOL_DMIC2L_REG,
+		     0, 0x3F, 0, stn_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC2R Volume", LM49453_P0_STN_VOL_DMIC2R_REG,
+		     0, 0x3F, 0, stn_tlv),
+};
+
+static const struct snd_kcontrol_new lm49453_snd_controls[] = {
+	/* mic1 and mic2 supports mono only */
+	SOC_SINGLE_TLV("Mic1 Volume", LM49453_P0_MICL_REG, 0, 15, 0, mic_tlv),
+	SOC_SINGLE_TLV("Mic2 Volume", LM49453_P0_MICR_REG, 0, 15, 0, mic_tlv),
+
+	SOC_SINGLE_TLV("ADCL Volume", LM49453_P0_ADC_LEVELL_REG, 0, 63,
+			0, adc_dac_tlv),
+	SOC_SINGLE_TLV("ADCR Volume", LM49453_P0_ADC_LEVELR_REG, 0, 63,
+			0, adc_dac_tlv),
+
+	SOC_DOUBLE_R_TLV("DMIC1 Volume", LM49453_P0_DMIC1_LEVELL_REG,
+			  LM49453_P0_DMIC1_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
+	SOC_DOUBLE_R_TLV("DMIC2 Volume", LM49453_P0_DMIC2_LEVELL_REG,
+			  LM49453_P0_DMIC2_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
+
+	SOC_DAPM_ENUM("Mic2Mode", lm49453_mic2mode_enum),
+	SOC_DAPM_ENUM("DMIC12 SRC", lm49453_dmic12_cfg_enum),
+	SOC_DAPM_ENUM("DMIC34 SRC", lm49453_dmic34_cfg_enum),
+
+	/* Capture path filter enable */
+	SOC_SINGLE("DMIC1 HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+					    0, 1, 0),
+	SOC_SINGLE("DMIC2 HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+					    1, 1, 0),
+	SOC_SINGLE("ADC HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+					  2, 1, 0),
+
+	SOC_DOUBLE_R_TLV("DAC HP Volume", LM49453_P0_DAC_HP_LEVELL_REG,
+			  LM49453_P0_DAC_HP_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC LO Volume", LM49453_P0_DAC_LO_LEVELL_REG,
+			  LM49453_P0_DAC_LO_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC LS Volume", LM49453_P0_DAC_LS_LEVELL_REG,
+			  LM49453_P0_DAC_LS_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
+	SOC_DOUBLE_R_TLV("DAC HA Volume", LM49453_P0_DAC_HA_LEVELL_REG,
+			  LM49453_P0_DAC_HA_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
+
+	SOC_SINGLE_TLV("EP Volume", LM49453_P0_DAC_LS_LEVELL_REG,
+			0, 63, 0, adc_dac_tlv),
+
+	SOC_SINGLE_TLV("PORT1_1_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+			0, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_2_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+			2, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_3_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+			4, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_4_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+			6, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_5_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+			0, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_6_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+			2, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_7_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+			4, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT1_8_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+			6, 3, 0, port_tlv),
+
+	SOC_SINGLE_TLV("PORT2_1_RX_LVL Volume", LM49453_P0_PORT2_RX_LVL_REG,
+			0, 3, 0, port_tlv),
+	SOC_SINGLE_TLV("PORT2_2_RX_LVL Volume", LM49453_P0_PORT2_RX_LVL_REG,
+			2, 3, 0, port_tlv),
+
+	SOC_SINGLE("Port1 Playback Switch", LM49453_P0_AUDIO_PORT1_BASIC_REG,
+		    1, 1, 0),
+	SOC_SINGLE("Port2 Playback Switch", LM49453_P0_AUDIO_PORT2_BASIC_REG,
+		    1, 1, 0),
+	SOC_SINGLE("Port1 Capture Switch", LM49453_P0_AUDIO_PORT1_BASIC_REG,
+		    2, 1, 0),
+	SOC_SINGLE("Port2 Capture Switch", LM49453_P0_AUDIO_PORT2_BASIC_REG,
+		    2, 1, 0)
+
+};
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget lm49453_dapm_widgets[] = {
+
+	/* All end points HP,EP, LS, Lineout and Haptic */
+	SND_SOC_DAPM_OUTPUT("HPOUTL"),
+	SND_SOC_DAPM_OUTPUT("HPOUTR"),
+	SND_SOC_DAPM_OUTPUT("EPOUT"),
+	SND_SOC_DAPM_OUTPUT("LSOUTL"),
+	SND_SOC_DAPM_OUTPUT("LSOUTR"),
+	SND_SOC_DAPM_OUTPUT("LOOUTR"),
+	SND_SOC_DAPM_OUTPUT("LOOUTL"),
+	SND_SOC_DAPM_OUTPUT("HAOUTL"),
+	SND_SOC_DAPM_OUTPUT("HAOUTR"),
+
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_INPUT("DMIC1DAT"),
+	SND_SOC_DAPM_INPUT("DMIC2DAT"),
+	SND_SOC_DAPM_INPUT("AUXL"),
+	SND_SOC_DAPM_INPUT("AUXR"),
+
+	SND_SOC_DAPM_PGA("PORT1_1_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_2_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_3_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_4_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_5_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_6_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_7_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT1_8_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT2_1_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PORT2_2_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("AMIC1Bias", LM49453_P0_MICL_REG, 6, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AMIC2Bias", LM49453_P0_MICR_REG, 6, 0, NULL, 0),
+
+	/* playback path driver enables */
+	SND_SOC_DAPM_OUT_DRV("Headset Switch",
+			LM49453_P0_PMC_SETUP_REG, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Earpiece Switch",
+			LM49453_P0_EP_REG, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Speaker Left Switch",
+			LM49453_P0_DIS_PKVL_FB_REG, 0, 1, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Speaker Right Switch",
+			LM49453_P0_DIS_PKVL_FB_REG, 1, 1, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Haptic Left Switch",
+			LM49453_P0_DIS_PKVL_FB_REG, 2, 1, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Haptic Right Switch",
+			LM49453_P0_DIS_PKVL_FB_REG, 3, 1, NULL, 0),
+
+	/* DAC */
+	SND_SOC_DAPM_DAC("HPL DAC", "Headset", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("HPR DAC", "Headset", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("LSL DAC", "Speaker", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("LSR DAC", "Speaker", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("HAL DAC", "Haptic", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("HAR DAC", "Haptic", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("LOL DAC", "Lineout", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("LOR DAC", "Lineout", SND_SOC_NOPM, 0, 0),
+
+
+	SND_SOC_DAPM_PGA("AUXL Input",
+			LM49453_P0_ANALOG_MIXER_ADC_REG, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUXR Input",
+			LM49453_P0_ANALOG_MIXER_ADC_REG, 3, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Sidetone", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC("DMIC1 Left", "Capture", SND_SOC_NOPM, 1, 0),
+	SND_SOC_DAPM_ADC("DMIC1 Right", "Capture", SND_SOC_NOPM, 1, 0),
+	SND_SOC_DAPM_ADC("DMIC2 Left", "Capture", SND_SOC_NOPM, 1, 0),
+	SND_SOC_DAPM_ADC("DMIC2 Right", "Capture", SND_SOC_NOPM, 1, 0),
+
+	SND_SOC_DAPM_ADC("ADC Left", "Capture", SND_SOC_NOPM, 1, 0),
+	SND_SOC_DAPM_ADC("ADC Right", "Capture", SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MUX("ADCL Mux", SND_SOC_NOPM, 0, 0,
+			  &lm49453_adcl_mux_control),
+	SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0,
+			  &lm49453_adcr_mux_control),
+
+	SND_SOC_DAPM_MUX("Mic1 Input",
+			SND_SOC_NOPM, 0, 0, &lm49453_adcl_mux_control),
+
+	SND_SOC_DAPM_MUX("Mic2 Input",
+			SND_SOC_NOPM, 0, 0, &lm49453_adcr_mux_control),
+
+	/* AIF */
+	SND_SOC_DAPM_AIF_IN("PORT1_SDI", NULL, 0,
+			    LM49453_P0_PULL_CONFIG1_REG, 2, 0),
+	SND_SOC_DAPM_AIF_IN("PORT2_SDI", NULL, 0,
+			    LM49453_P0_PULL_CONFIG1_REG, 6, 0),
+
+	SND_SOC_DAPM_AIF_OUT("PORT1_SDO", NULL, 0,
+			     LM49453_P0_PULL_CONFIG1_REG, 3, 0),
+	SND_SOC_DAPM_AIF_OUT("PORT2_SDO", NULL, 0,
+			      LM49453_P0_PULL_CONFIG1_REG, 7, 0),
+
+	/* Port1 TX controls */
+	SND_SOC_DAPM_OUT_DRV("P1_1_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_2_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_3_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_4_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_5_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_6_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_7_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P1_8_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Port2 TX controls */
+	SND_SOC_DAPM_OUT_DRV("P2_1_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("P2_2_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Sidetone Mixer */
+	SND_SOC_DAPM_MIXER("Sidetone Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_sidetone_mixer_controls,
+			    ARRAY_SIZE(lm49453_sidetone_mixer_controls)),
+
+	/* DAC MIXERS */
+	SND_SOC_DAPM_MIXER("HPL Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_headset_left_mixer,
+			    ARRAY_SIZE(lm49453_headset_left_mixer)),
+	SND_SOC_DAPM_MIXER("HPR Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_headset_right_mixer,
+			    ARRAY_SIZE(lm49453_headset_right_mixer)),
+	SND_SOC_DAPM_MIXER("LOL Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_lineout_left_mixer,
+			    ARRAY_SIZE(lm49453_lineout_left_mixer)),
+	SND_SOC_DAPM_MIXER("LOR Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_lineout_right_mixer,
+			    ARRAY_SIZE(lm49453_lineout_right_mixer)),
+	SND_SOC_DAPM_MIXER("LSL Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_speaker_left_mixer,
+			    ARRAY_SIZE(lm49453_speaker_left_mixer)),
+	SND_SOC_DAPM_MIXER("LSR Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_speaker_right_mixer,
+			    ARRAY_SIZE(lm49453_speaker_right_mixer)),
+	SND_SOC_DAPM_MIXER("HAL Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_haptic_left_mixer,
+			    ARRAY_SIZE(lm49453_haptic_left_mixer)),
+	SND_SOC_DAPM_MIXER("HAR Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_haptic_right_mixer,
+			    ARRAY_SIZE(lm49453_haptic_right_mixer)),
+
+	/* Capture Mixer */
+	SND_SOC_DAPM_MIXER("Port1_1 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx1_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx1_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_2 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx2_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx2_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_3 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx3_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx3_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_4 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx4_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx4_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_5 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx5_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx5_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_6 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx6_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx6_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_7 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx7_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx7_mixer)),
+	SND_SOC_DAPM_MIXER("Port1_8 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port1_tx8_mixer,
+			    ARRAY_SIZE(lm49453_port1_tx8_mixer)),
+
+	SND_SOC_DAPM_MIXER("Port2_1 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port2_tx1_mixer,
+			    ARRAY_SIZE(lm49453_port2_tx1_mixer)),
+	SND_SOC_DAPM_MIXER("Port2_2 Mixer", SND_SOC_NOPM, 0, 0,
+			    lm49453_port2_tx2_mixer,
+			    ARRAY_SIZE(lm49453_port2_tx2_mixer)),
+};
+
+static const struct snd_soc_dapm_route lm49453_audio_map[] = {
+	/* Port SDI mapping */
+	{ "PORT1_1_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_2_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_3_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_4_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_5_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_6_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_7_RX", "Port1 Playback Switch", "PORT1_SDI" },
+	{ "PORT1_8_RX", "Port1 Playback Switch", "PORT1_SDI" },
+
+	{ "PORT2_1_RX", "Port2 Playback Switch", "PORT2_SDI" },
+	{ "PORT2_2_RX", "Port2 Playback Switch", "PORT2_SDI" },
+
+	/* HP mapping */
+	{ "HPL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "HPL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "HPL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "HPL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "HPL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "HPL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "HPL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "HPL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	{ "HPL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "HPL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "HPL Mixer", "ADCL Switch", "ADC Left" },
+	{ "HPL Mixer", "ADCR Switch", "ADC Right" },
+	{ "HPL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "HPL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "HPL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "HPL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "HPL Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "HPL DAC", NULL, "HPL Mixer" },
+
+	{ "HPR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "HPR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "HPR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "HPR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "HPR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "HPR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "HPR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "HPR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "HPR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "HPR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "HPR Mixer", "ADCL Switch", "ADC Left" },
+	{ "HPR Mixer", "ADCR Switch", "ADC Right" },
+	{ "HPR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "HPR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "HPR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "HPR Mixer", "DMIC2L Switch", "DMIC2 Right" },
+	{ "HPR Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "HPR DAC", NULL, "HPR Mixer" },
+
+	{ "HPOUTL", "Headset Switch", "HPL DAC"},
+	{ "HPOUTR", "Headset Switch", "HPR DAC"},
+
+	/* EP map */
+	{ "EPOUT", "Earpiece Switch", "HPL DAC" },
+
+	/* Speaker map */
+	{ "LSL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "LSL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "LSL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "LSL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "LSL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "LSL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "LSL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "LSL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "LSL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "LSL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "LSL Mixer", "ADCL Switch", "ADC Left" },
+	{ "LSL Mixer", "ADCR Switch", "ADC Right" },
+	{ "LSL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "LSL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "LSL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "LSL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "LSL Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "LSL DAC", NULL, "LSL Mixer" },
+
+	{ "LSR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "LSR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "LSR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "LSR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "LSR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "LSR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "LSR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "LSR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "LSR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "LSR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "LSR Mixer", "ADCL Switch", "ADC Left" },
+	{ "LSR Mixer", "ADCR Switch", "ADC Right" },
+	{ "LSR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "LSR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "LSR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "LSR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "LSR Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "LSR DAC", NULL, "LSR Mixer" },
+
+	{ "LSOUTL", "Speaker Left Switch", "LSL DAC"},
+	{ "LSOUTR", "Speaker Left Switch", "LSR DAC"},
+
+	/* Haptic map */
+	{ "HAL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "HAL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "HAL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "HAL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "HAL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "HAL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "HAL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "HAL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "HAL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "HAL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "HAL Mixer", "ADCL Switch", "ADC Left" },
+	{ "HAL Mixer", "ADCR Switch", "ADC Right" },
+	{ "HAL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "HAL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "HAL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "HAL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "HAL Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "HAL DAC", NULL, "HAL Mixer" },
+
+	{ "HAR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "HAR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "HAR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "HAR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "HAR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "HAR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "HAR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "HAR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "HAR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "HAR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "HAR Mixer", "ADCL Switch", "ADC Left" },
+	{ "HAR Mixer", "ADCR Switch", "ADC Right" },
+	{ "HAR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "HAR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "HAR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "HAR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "HAR Mixer", "Sideton Switch", "Sidetone" },
+
+	{ "HAR DAC", NULL, "HAR Mixer" },
+
+	{ "HAOUTL", "Haptic Left Switch", "HAL DAC" },
+	{ "HAOUTR", "Haptic Right Switch", "HAR DAC" },
+
+	/* Lineout map */
+	{ "LOL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "LOL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "LOL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "LOL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "LOL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "LOL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "LOL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "LOL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "LOL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "LOL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "LOL Mixer", "ADCL Switch", "ADC Left" },
+	{ "LOL Mixer", "ADCR Switch", "ADC Right" },
+	{ "LOL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "LOL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "LOL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "LOL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "LOL Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "LOL DAC", NULL, "LOL Mixer" },
+
+	{ "LOR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+	{ "LOR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+	{ "LOR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+	{ "LOR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+	{ "LOR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+	{ "LOR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+	{ "LOR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+	{ "LOR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+	/* Port 2 */
+	{ "LOR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+	{ "LOR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+	{ "LOR Mixer", "ADCL Switch", "ADC Left" },
+	{ "LOR Mixer", "ADCR Switch", "ADC Right" },
+	{ "LOR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "LOR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "LOR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "LOR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+	{ "LOR Mixer", "Sidetone Switch", "Sidetone" },
+
+	{ "LOR DAC", NULL, "LOR Mixer" },
+
+	{ "LOOUTL", NULL, "LOL DAC" },
+	{ "LOOUTR", NULL, "LOR DAC" },
+
+	/* TX map */
+	/* Port1 mappings */
+	{ "Port1_1 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_1 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_1 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_1 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_1 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_1 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_2 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_2 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_2 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_2 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_2 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_2 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_3 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_3 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_3 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_3 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_3 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_3 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_4 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_4 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_4 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_4 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_4 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_4 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_5 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_5 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_5 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_5 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_5 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_5 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_6 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_6 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_6 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_6 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_6 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_6 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_7 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_7 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_7 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_7 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_7 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_7 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port1_8 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port1_8 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port1_8 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port1_8 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port1_8 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port1_8 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port2_1 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port2_1 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port2_1 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port2_1 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port2_1 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port2_1 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "Port2_2 Mixer", "ADCL Switch", "ADC Left" },
+	{ "Port2_2 Mixer", "ADCR Switch", "ADC Right" },
+	{ "Port2_2 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+	{ "Port2_2 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+	{ "Port2_2 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+	{ "Port2_2 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+	{ "P1_1_TX", NULL, "Port1_1 Mixer" },
+	{ "P1_2_TX", NULL, "Port1_2 Mixer" },
+	{ "P1_3_TX", NULL, "Port1_3 Mixer" },
+	{ "P1_4_TX", NULL, "Port1_4 Mixer" },
+	{ "P1_5_TX", NULL, "Port1_5 Mixer" },
+	{ "P1_6_TX", NULL, "Port1_6 Mixer" },
+	{ "P1_7_TX", NULL, "Port1_7 Mixer" },
+	{ "P1_8_TX", NULL, "Port1_8 Mixer" },
+
+	{ "P2_1_TX", NULL, "Port2_1 Mixer" },
+	{ "P2_2_TX", NULL, "Port2_2 Mixer" },
+
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_1_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_2_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_3_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_4_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_5_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_6_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_7_TX"},
+	{ "PORT1_SDO", "Port1 Capture Switch", "P1_8_TX"},
+
+	{ "PORT2_SDO", "Port2 Capture Switch", "P2_1_TX"},
+	{ "PORT2_SDO", "Port2 Capture Switch", "P2_2_TX"},
+
+	{ "Mic1 Input", NULL, "AMIC1" },
+	{ "Mic2 Input", NULL, "AMIC2" },
+
+	{ "AUXL Input", NULL, "AUXL" },
+	{ "AUXR Input", NULL, "AUXR" },
+
+	/* AUX connections */
+	{ "ADCL Mux", "Aux_L", "AUXL Input" },
+	{ "ADCL Mux", "MIC1", "Mic1 Input" },
+
+	{ "ADCR Mux", "Aux_R", "AUXR Input" },
+	{ "ADCR Mux", "MIC2", "Mic2 Input" },
+
+	/* ADC connection */
+	{ "ADC Left", NULL, "ADCL Mux"},
+	{ "ADC Right", NULL, "ADCR Mux"},
+
+	{ "DMIC1 Left", NULL, "DMIC1DAT"},
+	{ "DMIC1 Right", NULL, "DMIC1DAT"},
+	{ "DMIC2 Left", NULL, "DMIC2DAT"},
+	{ "DMIC2 Right", NULL, "DMIC2DAT"},
+
+	/* Sidetone map */
+	{ "Sidetone Mixer", NULL, "ADC Left" },
+	{ "Sidetone Mixer", NULL, "ADC Right" },
+	{ "Sidetone Mixer", NULL, "DMIC1 Left" },
+	{ "Sidetone Mixer", NULL, "DMIC1 Right" },
+	{ "Sidetone Mixer", NULL, "DMIC2 Left" },
+	{ "Sidetone Mixer", NULL, "DMIC2 Right" },
+
+	{ "Sidetone", "Sidetone Switch", "Sidetone Mixer" },
+};
+
+static int lm49453_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 clk_div = 0;
+
+	/* Setting DAC clock dividers based on substream sample rate. */
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 32000:
+	case 24000:
+	case 48000:
+		clk_div = 256;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk_div = 216;
+		break;
+	case 96000:
+		clk_div = 127;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, LM49453_P0_ADC_CLK_DIV_REG, clk_div);
+	snd_soc_component_write(component, LM49453_P0_DAC_HP_CLK_DIV_REG, clk_div);
+
+	return 0;
+}
+
+static int lm49453_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+
+	u16 aif_val;
+	int mode = 0;
+	int clk_phase = 0;
+	int clk_shift = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		aif_val = 0;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		aif_val = LM49453_AUDIO_PORT1_BASIC_SYNC_MS;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		aif_val = LM49453_AUDIO_PORT1_BASIC_CLK_MS;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif_val = LM49453_AUDIO_PORT1_BASIC_CLK_MS |
+			  LM49453_AUDIO_PORT1_BASIC_SYNC_MS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		mode = 1;
+		clk_phase = (1 << 5);
+		clk_shift = 1;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		mode = 1;
+		clk_phase = (1 << 5);
+		clk_shift = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, LM49453_P0_AUDIO_PORT1_BASIC_REG,
+			    LM49453_AUDIO_PORT1_BASIC_FMT_MASK|BIT(0)|BIT(5),
+			    (aif_val | mode | clk_phase));
+
+	snd_soc_component_write(component, LM49453_P0_AUDIO_PORT1_RX_MSB_REG, clk_shift);
+
+	return 0;
+}
+
+static int lm49453_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+				  unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 pll_clk = 0;
+
+	switch (freq) {
+	case 12288000:
+	case 26000000:
+	case 19200000:
+		/* pll clk slection */
+		pll_clk = 0;
+		break;
+	case 48000:
+	case 32576:
+		/* fll clk slection */
+		pll_clk = BIT(4);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, LM49453_P0_PMC_SETUP_REG, BIT(4), pll_clk);
+
+	return 0;
+}
+
+static int lm49453_hp_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_component_update_bits(dai->component, LM49453_P0_DAC_DSP_REG, BIT(1)|BIT(0),
+			    (mute ? (BIT(1)|BIT(0)) : 0));
+	return 0;
+}
+
+static int lm49453_lo_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_component_update_bits(dai->component, LM49453_P0_DAC_DSP_REG, BIT(3)|BIT(2),
+			    (mute ? (BIT(3)|BIT(2)) : 0));
+	return 0;
+}
+
+static int lm49453_ls_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_component_update_bits(dai->component, LM49453_P0_DAC_DSP_REG, BIT(5)|BIT(4),
+			    (mute ? (BIT(5)|BIT(4)) : 0));
+	return 0;
+}
+
+static int lm49453_ep_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_component_update_bits(dai->component, LM49453_P0_DAC_DSP_REG, BIT(4),
+			    (mute ? BIT(4) : 0));
+	return 0;
+}
+
+static int lm49453_ha_mute(struct snd_soc_dai *dai, int mute)
+{
+	snd_soc_component_update_bits(dai->component, LM49453_P0_DAC_DSP_REG, BIT(7)|BIT(6),
+			    (mute ? (BIT(7)|BIT(6)) : 0));
+	return 0;
+}
+
+static int lm49453_set_bias_level(struct snd_soc_component *component,
+				  enum snd_soc_bias_level level)
+{
+	struct lm49453_priv *lm49453 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			regcache_sync(lm49453->regmap);
+
+		snd_soc_component_update_bits(component, LM49453_P0_PMC_SETUP_REG,
+				    LM49453_PMC_SETUP_CHIP_EN, LM49453_CHIP_EN);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, LM49453_P0_PMC_SETUP_REG,
+				    LM49453_PMC_SETUP_CHIP_EN, 0);
+		break;
+	}
+
+	return 0;
+}
+
+/* Formates supported by LM49453 driver. */
+#define LM49453_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops lm49453_headset_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_hp_mute,
+};
+
+static const struct snd_soc_dai_ops lm49453_speaker_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_ls_mute,
+};
+
+static const struct snd_soc_dai_ops lm49453_haptic_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_ha_mute,
+};
+
+static const struct snd_soc_dai_ops lm49453_ep_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_ep_mute,
+};
+
+static const struct snd_soc_dai_ops lm49453_lineout_dai_ops = {
+	.hw_params	= lm49453_hw_params,
+	.set_sysclk	= lm49453_set_dai_sysclk,
+	.set_fmt	= lm49453_set_dai_fmt,
+	.digital_mute	= lm49453_lo_mute,
+};
+
+/* LM49453 dai structure. */
+static struct snd_soc_dai_driver lm49453_dai[] = {
+	{
+		.name = "LM49453 Headset",
+		.playback = {
+			.stream_name = "Headset",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 5,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_headset_dai_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "LM49453 Speaker",
+		.playback = {
+			.stream_name = "Speaker",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_speaker_dai_ops,
+	},
+	{
+		.name = "LM49453 Haptic",
+		.playback = {
+			.stream_name = "Haptic",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_haptic_dai_ops,
+	},
+	{
+		.name = "LM49453 Earpiece",
+		.playback = {
+			.stream_name = "Earpiece",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_ep_dai_ops,
+	},
+	{
+		.name = "LM49453 line out",
+		.playback = {
+			.stream_name = "Lineout",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = LM49453_FORMATS,
+		},
+		.ops = &lm49453_lineout_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_lm49453 = {
+	.set_bias_level		= lm49453_set_bias_level,
+	.controls		= lm49453_snd_controls,
+	.num_controls		= ARRAY_SIZE(lm49453_snd_controls),
+	.dapm_widgets		= lm49453_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(lm49453_dapm_widgets),
+	.dapm_routes		= lm49453_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(lm49453_audio_map),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config lm49453_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = LM49453_MAX_REGISTER,
+	.reg_defaults = lm49453_reg_defs,
+	.num_reg_defaults = ARRAY_SIZE(lm49453_reg_defs),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int lm49453_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct lm49453_priv *lm49453;
+	int ret = 0;
+
+	lm49453 = devm_kzalloc(&i2c->dev, sizeof(struct lm49453_priv),
+				GFP_KERNEL);
+
+	if (lm49453 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, lm49453);
+
+	lm49453->regmap = devm_regmap_init_i2c(i2c, &lm49453_regmap_config);
+	if (IS_ERR(lm49453->regmap)) {
+		ret = PTR_ERR(lm49453->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret =  devm_snd_soc_register_component(&i2c->dev,
+				      &soc_component_dev_lm49453,
+				      lm49453_dai, ARRAY_SIZE(lm49453_dai));
+	if (ret < 0)
+		dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
+
+	return ret;
+}
+
+static int lm49453_i2c_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id lm49453_i2c_id[] = {
+	{ "lm49453", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lm49453_i2c_id);
+
+static struct i2c_driver lm49453_i2c_driver = {
+	.driver = {
+		.name = "lm49453",
+	},
+	.probe = lm49453_i2c_probe,
+	.remove = lm49453_i2c_remove,
+	.id_table = lm49453_i2c_id,
+};
+
+module_i2c_driver(lm49453_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC LM49453 driver");
+MODULE_AUTHOR("M R Swami Reddy <MR.Swami.Reddy@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/lm49453.h b/sound/soc/codecs/lm49453.h
new file mode 100644
index 0000000..a63cfa5
--- /dev/null
+++ b/sound/soc/codecs/lm49453.h
@@ -0,0 +1,380 @@
+/*
+ * lm49453.h  -  LM49453 ALSA Soc Audio drive
+ *
+ * Copyright (c) 2012  Texas Instruments, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ */
+
+#ifndef _LM49453_H
+#define _LM49453_H
+
+#include <linux/bitops.h>
+
+/* LM49453_P0 register space for page0 */
+#define LM49453_P0_PMC_SETUP_REG			0x00
+#define LM49453_P0_PLL_CLK_SEL1_REG			0x01
+#define LM49453_P0_PLL_CLK_SEL2_REG			0x02
+#define LM49453_P0_PMC_CLK_DIV_REG			0x03
+#define LM49453_P0_HSDET_CLK_DIV_REG			0x04
+#define LM49453_P0_DMIC_CLK_DIV_REG			0x05
+#define LM49453_P0_ADC_CLK_DIV_REG			0x06
+#define LM49453_P0_DAC_OT_CLK_DIV_REG			0x07
+#define LM49453_P0_PLL_HF_M_REG				0x08
+#define LM49453_P0_PLL_LF_M_REG				0x09
+#define LM49453_P0_PLL_NL_REG				0x0A
+#define LM49453_P0_PLL_N_MODL_REG			0x0B
+#define LM49453_P0_PLL_N_MODH_REG			0x0C
+#define LM49453_P0_PLL_P1_REG				0x0D
+#define LM49453_P0_PLL_P2_REG				0x0E
+#define LM49453_P0_FLL_REF_FREQL_REG			0x0F
+#define LM49453_P0_FLL_REF_FREQH_REG			0x10
+#define LM49453_P0_VCO_TARGETLL_REG			0x11
+#define LM49453_P0_VCO_TARGETLH_REG			0x12
+#define LM49453_P0_VCO_TARGETHL_REG			0x13
+#define LM49453_P0_VCO_TARGETHH_REG			0x14
+#define LM49453_P0_PLL_CONFIG_REG			0x15
+#define LM49453_P0_DAC_CLK_SEL_REG			0x16
+#define LM49453_P0_DAC_HP_CLK_DIV_REG			0x17
+
+/* Analog Mixer Input Stages */
+#define LM49453_P0_MICL_REG				0x20
+#define LM49453_P0_MICR_REG				0x21
+#define LM49453_P0_EP_REG				0x24
+#define LM49453_P0_DIS_PKVL_FB_REG			0x25
+
+/* Analog Mixer Output Stages */
+#define LM49453_P0_ANALOG_MIXER_ADC_REG			0x2E
+
+/*ADC or DAC */
+#define LM49453_P0_ADC_DSP_REG				0x30
+#define LM49453_P0_DAC_DSP_REG				0x31
+
+/* EFFECTS ENABLES */
+#define LM49453_P0_ADC_FX_ENABLES_REG			0x33
+
+/* GPIO */
+#define LM49453_P0_GPIO1_REG				0x38
+#define LM49453_P0_GPIO2_REG				0x39
+#define LM49453_P0_GPIO3_REG				0x3A
+#define LM49453_P0_HAP_CTL_REG				0x3B
+#define LM49453_P0_HAP_FREQ_PROG_LEFTL_REG		0x3C
+#define LM49453_P0_HAP_FREQ_PROG_LEFTH_REG		0x3D
+#define LM49453_P0_HAP_FREQ_PROG_RIGHTL_REG		0x3E
+#define LM49453_P0_HAP_FREQ_PROG_RIGHTH_REG		0x3F
+
+/* DIGITAL MIXER */
+#define LM49453_P0_DMIX_CLK_SEL_REG			0x40
+#define LM49453_P0_PORT1_RX_LVL1_REG			0x41
+#define LM49453_P0_PORT1_RX_LVL2_REG			0x42
+#define LM49453_P0_PORT2_RX_LVL_REG			0x43
+#define LM49453_P0_PORT1_TX1_REG			0x44
+#define LM49453_P0_PORT1_TX2_REG			0x45
+#define LM49453_P0_PORT1_TX3_REG			0x46
+#define LM49453_P0_PORT1_TX4_REG			0x47
+#define LM49453_P0_PORT1_TX5_REG			0x48
+#define LM49453_P0_PORT1_TX6_REG			0x49
+#define LM49453_P0_PORT1_TX7_REG			0x4A
+#define LM49453_P0_PORT1_TX8_REG			0x4B
+#define LM49453_P0_PORT2_TX1_REG			0x4C
+#define LM49453_P0_PORT2_TX2_REG			0x4D
+#define LM49453_P0_STN_SEL_REG				0x4F
+#define LM49453_P0_DACHPL1_REG				0x50
+#define LM49453_P0_DACHPL2_REG				0x51
+#define LM49453_P0_DACHPR1_REG				0x52
+#define LM49453_P0_DACHPR2_REG				0x53
+#define LM49453_P0_DACLOL1_REG				0x54
+#define LM49453_P0_DACLOL2_REG				0x55
+#define LM49453_P0_DACLOR1_REG				0x56
+#define LM49453_P0_DACLOR2_REG				0x57
+#define LM49453_P0_DACLSL1_REG				0x58
+#define LM49453_P0_DACLSL2_REG				0x59
+#define LM49453_P0_DACLSR1_REG				0x5A
+#define LM49453_P0_DACLSR2_REG				0x5B
+#define LM49453_P0_DACHAL1_REG				0x5C
+#define LM49453_P0_DACHAL2_REG				0x5D
+#define LM49453_P0_DACHAR1_REG				0x5E
+#define LM49453_P0_DACHAR2_REG				0x5F
+
+/* AUDIO PORT 1 (TDM) */
+#define LM49453_P0_AUDIO_PORT1_BASIC_REG		0x60
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN1_REG		0x61
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN2_REG		0x62
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN3_REG		0x63
+#define LM49453_P0_AUDIO_PORT1_SYNC_RATE_REG		0x64
+#define LM49453_P0_AUDIO_PORT1_SYNC_SDO_SETUP_REG	0x65
+#define LM49453_P0_AUDIO_PORT1_DATA_WIDTH_REG		0x66
+#define LM49453_P0_AUDIO_PORT1_RX_MSB_REG		0x67
+#define LM49453_P0_AUDIO_PORT1_TX_MSB_REG		0x68
+#define LM49453_P0_AUDIO_PORT1_TDM_CHANNELS_REG		0x69
+
+/* AUDIO PORT 2 */
+#define LM49453_P0_AUDIO_PORT2_BASIC_REG		0x6A
+#define LM49453_P0_AUDIO_PORT2_CLK_GEN1_REG		0x6B
+#define LM49453_P0_AUDIO_PORT2_CLK_GEN2_REG		0x6C
+#define LM49453_P0_AUDIO_PORT2_SYNC_GEN_REG		0x6D
+#define LM49453_P0_AUDIO_PORT2_DATA_WIDTH_REG		0x6E
+#define LM49453_P0_AUDIO_PORT2_RX_MODE_REG		0x6F
+#define LM49453_P0_AUDIO_PORT2_TX_MODE_REG		0x70
+
+/* SAMPLE RATE */
+#define LM49453_P0_PORT1_SR_LSB_REG			0x79
+#define LM49453_P0_PORT1_SR_MSB_REG			0x7A
+#define LM49453_P0_PORT2_SR_LSB_REG			0x7B
+#define LM49453_P0_PORT2_SR_MSB_REG			0x7C
+
+/* EFFECTS - HPFs */
+#define LM49453_P0_HPF_REG				0x80
+
+/* EFFECTS ADC ALC */
+#define LM49453_P0_ADC_ALC1_REG				0x82
+#define LM49453_P0_ADC_ALC2_REG				0x83
+#define LM49453_P0_ADC_ALC3_REG				0x84
+#define LM49453_P0_ADC_ALC4_REG				0x85
+#define LM49453_P0_ADC_ALC5_REG				0x86
+#define LM49453_P0_ADC_ALC6_REG				0x87
+#define LM49453_P0_ADC_ALC7_REG				0x88
+#define LM49453_P0_ADC_ALC8_REG				0x89
+#define LM49453_P0_DMIC1_LEVELL_REG			0x8A
+#define LM49453_P0_DMIC1_LEVELR_REG			0x8B
+#define LM49453_P0_DMIC2_LEVELL_REG			0x8C
+#define LM49453_P0_DMIC2_LEVELR_REG			0x8D
+#define LM49453_P0_ADC_LEVELL_REG			0x8E
+#define LM49453_P0_ADC_LEVELR_REG			0x8F
+#define LM49453_P0_DAC_HP_LEVELL_REG			0x90
+#define LM49453_P0_DAC_HP_LEVELR_REG			0x91
+#define LM49453_P0_DAC_LO_LEVELL_REG			0x92
+#define LM49453_P0_DAC_LO_LEVELR_REG			0x93
+#define LM49453_P0_DAC_LS_LEVELL_REG			0x94
+#define LM49453_P0_DAC_LS_LEVELR_REG			0x95
+#define LM49453_P0_DAC_HA_LEVELL_REG			0x96
+#define LM49453_P0_DAC_HA_LEVELR_REG			0x97
+#define LM49453_P0_SOFT_MUTE_REG			0x98
+#define LM49453_P0_DMIC_MUTE_CFG_REG			0x99
+#define LM49453_P0_ADC_MUTE_CFG_REG			0x9A
+#define LM49453_P0_DAC_MUTE_CFG_REG			0x9B
+
+/*DIGITAL MIC1 */
+#define LM49453_P0_DIGITAL_MIC1_CONFIG_REG		0xB0
+#define LM49453_P0_DIGITAL_MIC1_DATA_DELAYL_REG		0xB1
+#define LM49453_P0_DIGITAL_MIC1_DATA_DELAYR_REG		0xB2
+
+/*DIGITAL MIC2 */
+#define LM49453_P0_DIGITAL_MIC2_CONFIG_REG		0xB3
+#define LM49453_P0_DIGITAL_MIC2_DATA_DELAYL_REG		0xB4
+#define LM49453_P0_DIGITAL_MIC2_DATA_DELAYR_REG		0xB5
+
+/* ADC DECIMATOR */
+#define LM49453_P0_ADC_DECIMATOR_REG			0xB6
+
+/* DAC CONFIGURE */
+#define LM49453_P0_DAC_CONFIG_REG			0xB7
+
+/* SIDETONE */
+#define LM49453_P0_STN_VOL_ADCL_REG			0xB8
+#define LM49453_P0_STN_VOL_ADCR_REG			0xB9
+#define LM49453_P0_STN_VOL_DMIC1L_REG			0xBA
+#define LM49453_P0_STN_VOL_DMIC1R_REG			0xBB
+#define LM49453_P0_STN_VOL_DMIC2L_REG			0xBC
+#define LM49453_P0_STN_VOL_DMIC2R_REG			0xBD
+
+/* ADC/DAC CLIPPING MONITORS (Read Only/Write to Clear) */
+#define LM49453_P0_ADC_DEC_CLIP_REG			0xC2
+#define LM49453_P0_ADC_HPF_CLIP_REG			0xC3
+#define LM49453_P0_ADC_LVL_CLIP_REG			0xC4
+#define LM49453_P0_DAC_LVL_CLIP_REG			0xC5
+
+/* ADC ALC EFFECT MONITORS (Read Only) */
+#define LM49453_P0_ADC_LVLMONL_REG			0xC8
+#define LM49453_P0_ADC_LVLMONR_REG			0xC9
+#define LM49453_P0_ADC_ALCMONL_REG			0xCA
+#define LM49453_P0_ADC_ALCMONR_REG			0xCB
+#define LM49453_P0_ADC_MUTED_REG			0xCC
+#define LM49453_P0_DAC_MUTED_REG			0xCD
+
+/* HEADSET DETECT */
+#define LM49453_P0_HSD_PPB_LONG_CNT_LIMITL_REG		0xD0
+#define LM49453_P0_HSD_PPB_LONG_CNT_LIMITR_REG		0xD1
+#define LM49453_P0_HSD_PIN3_4_EX_LOOP_CNT_LIMITL_REG	0xD2
+#define LM49453_P0_HSD_PIN3_4_EX_LOOP_CNT_LIMITH_REG	0xD3
+#define LM49453_P0_HSD_TIMEOUT1_REG			0xD4
+#define LM49453_P0_HSD_TIMEOUT2_REG			0xD5
+#define LM49453_P0_HSD_TIMEOUT3_REG			0xD6
+#define LM49453_P0_HSD_PIN3_4_CFG_REG			0xD7
+#define LM49453_P0_HSD_IRQ1_REG				0xD8
+#define LM49453_P0_HSD_IRQ2_REG				0xD9
+#define LM49453_P0_HSD_IRQ3_REG				0xDA
+#define LM49453_P0_HSD_IRQ4_REG				0xDB
+#define LM49453_P0_HSD_IRQ_MASK1_REG			0xDC
+#define LM49453_P0_HSD_IRQ_MASK2_REG			0xDD
+#define LM49453_P0_HSD_IRQ_MASK3_REG			0xDE
+#define LM49453_P0_HSD_R_HPLL_REG			0xE0
+#define LM49453_P0_HSD_R_HPLH_REG			0xE1
+#define LM49453_P0_HSD_R_HPLU_REG			0xE2
+#define LM49453_P0_HSD_R_HPRL_REG			0xE3
+#define LM49453_P0_HSD_R_HPRH_REG			0xE4
+#define LM49453_P0_HSD_R_HPRU_REG			0xE5
+#define LM49453_P0_HSD_VEL_L_FINALL_REG			0xE6
+#define LM49453_P0_HSD_VEL_L_FINALH_REG			0xE7
+#define LM49453_P0_HSD_VEL_L_FINALU_REG			0xE8
+#define LM49453_P0_HSD_RO_FINALL_REG			0xE9
+#define LM49453_P0_HSD_RO_FINALH_REG			0xEA
+#define LM49453_P0_HSD_RO_FINALU_REG			0xEB
+#define LM49453_P0_HSD_VMIC_BIAS_FINALL_REG		0xEC
+#define LM49453_P0_HSD_VMIC_BIAS_FINALH_REG		0xED
+#define LM49453_P0_HSD_VMIC_BIAS_FINALU_REG		0xEE
+#define LM49453_P0_HSD_PIN_CONFIG_REG			0xEF
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS1_REG	0xF1
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS2_REG	0xF2
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS3_REG	0xF3
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATEL_REG	0xF4
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATEH_REG	0xF5
+
+/* I/O PULLDOWN CONFIG */
+#define LM49453_P0_PULL_CONFIG1_REG			0xF8
+#define LM49453_P0_PULL_CONFIG2_REG			0xF9
+#define LM49453_P0_PULL_CONFIG3_REG			0xFA
+
+/* RESET */
+#define LM49453_P0_RESET_REG				0xFE
+
+/* PAGE */
+#define LM49453_PAGE_REG				0xFF
+
+#define LM49453_MAX_REGISTER				(0xFF+1)
+
+/* LM49453_P0_PMC_SETUP_REG (0x00h) */
+#define LM49453_PMC_SETUP_CHIP_EN			(BIT(1)|BIT(0))
+#define LM49453_PMC_SETUP_PLL_EN			BIT(2)
+#define LM49453_PMC_SETUP_PLL_P2_EN			BIT(3)
+#define LM49453_PMC_SETUP_PLL_FLL			BIT(4)
+#define LM49453_PMC_SETUP_MCLK_OVER			BIT(5)
+#define LM49453_PMC_SETUP_RTC_CLK_OVER			BIT(6)
+#define LM49453_PMC_SETUP_CHIP_ACTIVE			BIT(7)
+
+/* Chip Enable bits */
+#define LM49453_CHIP_EN_SHUTDOWN			0x00
+#define LM49453_CHIP_EN					0x01
+#define LM49453_CHIP_EN_HSD_DETECT			0x02
+#define LM49453_CHIP_EN_INVALID_HSD			0x03
+
+/* LM49453_P0_PLL_CLK_SEL1_REG (0x01h) */
+#define LM49453_CLK_SEL1_MCLK_SEL			0x11
+#define LM49453_CLK_SEL1_RTC_SEL			0x11
+#define LM49453_CLK_SEL1_PORT1_SEL			0x10
+#define LM49453_CLK_SEL1_PORT2_SEL			0x11
+
+/* LM49453_P0_PLL_CLK_SEL2_REG (0x02h) */
+#define LM49453_CLK_SEL2_ADC_CLK_SEL			0x38
+
+/* LM49453_P0_FLL_REF_FREQL_REG (0x0F) */
+#define LM49453_FLL_REF_FREQ_VAL			0x8ca0001
+
+/* LM49453_P0_VCO_TARGETLL_REG (0x11) */
+#define LM49453_VCO_TARGET_VAL				0x8ca0001
+
+/* LM49453_P0_ADC_DSP_REG (0x30h) */
+#define LM49453_ADC_DSP_ADC_MUTEL			BIT(0)
+#define LM49453_ADC_DSP_ADC_MUTER			BIT(1)
+#define LM49453_ADC_DSP_DMIC1_MUTEL			BIT(2)
+#define LM49453_ADC_DSP_DMIC1_MUTER			BIT(3)
+#define LM49453_ADC_DSP_DMIC2_MUTEL			BIT(4)
+#define LM49453_ADC_DSP_DMIC2_MUTER			BIT(5)
+#define LM49453_ADC_DSP_MUTE_ALL			0x3F
+
+/* LM49453_P0_DAC_DSP_REG (0x31h) */
+#define LM49453_DAC_DSP_MUTE_ALL			0xFF
+
+/* LM49453_P0_AUDIO_PORT1_BASIC_REG (0x60h) */
+#define LM49453_AUDIO_PORT1_BASIC_FMT_MASK		(BIT(4)|BIT(3))
+#define LM49453_AUDIO_PORT1_BASIC_CLK_MS		BIT(3)
+#define LM49453_AUDIO_PORT1_BASIC_SYNC_MS		BIT(4)
+
+/* LM49453_P0_RESET_REG (0xFEh) */
+#define LM49453_RESET_REG_RST				BIT(0)
+
+/* Page select register bits (0xFF) */
+#define LM49453_PAGE0_SELECT				0x0
+#define LM49453_PAGE1_SELECT				0x1
+
+/* LM49453_P0_HSD_PIN3_4_CFG_REG (Jack Pin config - 0xD7) */
+#define LM49453_JACK_DISABLE				0x00
+#define LM49453_JACK_CONFIG1				0x01
+#define LM49453_JACK_CONFIG2				0x02
+#define LM49453_JACK_CONFIG3				0x03
+#define LM49453_JACK_CONFIG4				0x04
+#define LM49453_JACK_CONFIG5				0x05
+
+/* Page 1 REGISTERS */
+
+/* SIDETONE */
+#define LM49453_P1_SIDETONE_SA0L_REG			0x80
+#define LM49453_P1_SIDETONE_SA0H_REG			0x81
+#define LM49453_P1_SIDETONE_SAB0U_REG			0x82
+#define LM49453_P1_SIDETONE_SB0L_REG			0x83
+#define LM49453_P1_SIDETONE_SB0H_REG			0x84
+#define LM49453_P1_SIDETONE_SH0L_REG			0x85
+#define LM49453_P1_SIDETONE_SH0H_REG			0x86
+#define LM49453_P1_SIDETONE_SH0U_REG			0x87
+#define LM49453_P1_SIDETONE_SA1L_REG			0x88
+#define LM49453_P1_SIDETONE_SA1H_REG			0x89
+#define LM49453_P1_SIDETONE_SAB1U_REG			0x8A
+#define LM49453_P1_SIDETONE_SB1L_REG			0x8B
+#define LM49453_P1_SIDETONE_SB1H_REG			0x8C
+#define LM49453_P1_SIDETONE_SH1L_REG			0x8D
+#define LM49453_P1_SIDETONE_SH1H_REG			0x8E
+#define LM49453_P1_SIDETONE_SH1U_REG			0x8F
+#define LM49453_P1_SIDETONE_SA2L_REG			0x90
+#define LM49453_P1_SIDETONE_SA2H_REG			0x91
+#define LM49453_P1_SIDETONE_SAB2U_REG			0x92
+#define LM49453_P1_SIDETONE_SB2L_REG			0x93
+#define LM49453_P1_SIDETONE_SB2H_REG			0x94
+#define LM49453_P1_SIDETONE_SH2L_REG			0x95
+#define LM49453_P1_SIDETONE_SH2H_REG			0x96
+#define LM49453_P1_SIDETONE_SH2U_REG			0x97
+#define LM49453_P1_SIDETONE_SA3L_REG			0x98
+#define LM49453_P1_SIDETONE_SA3H_REG			0x99
+#define LM49453_P1_SIDETONE_SAB3U_REG			0x9A
+#define LM49453_P1_SIDETONE_SB3L_REG			0x9B
+#define LM49453_P1_SIDETONE_SB3H_REG			0x9C
+#define LM49453_P1_SIDETONE_SH3L_REG			0x9D
+#define LM49453_P1_SIDETONE_SH3H_REG			0x9E
+#define LM49453_P1_SIDETONE_SH3U_REG			0x9F
+#define LM49453_P1_SIDETONE_SA4L_REG			0xA0
+#define LM49453_P1_SIDETONE_SA4H_REG			0xA1
+#define LM49453_P1_SIDETONE_SAB4U_REG			0xA2
+#define LM49453_P1_SIDETONE_SB4L_REG			0xA3
+#define LM49453_P1_SIDETONE_SB4H_REG			0xA4
+#define LM49453_P1_SIDETONE_SH4L_REG			0xA5
+#define LM49453_P1_SIDETONE_SH4H_REG			0xA6
+#define LM49453_P1_SIDETONE_SH4U_REG			0xA7
+#define LM49453_P1_SIDETONE_SA5L_REG			0xA8
+#define LM49453_P1_SIDETONE_SA5H_REG			0xA9
+#define LM49453_P1_SIDETONE_SAB5U_REG			0xAA
+#define LM49453_P1_SIDETONE_SB5L_REG			0xAB
+#define LM49453_P1_SIDETONE_SB5H_REG			0xAC
+#define LM49453_P1_SIDETONE_SH5L_REG			0xAD
+#define LM49453_P1_SIDETONE_SH5H_REG			0xAE
+#define LM49453_P1_SIDETONE_SH5U_REG			0xAF
+
+/* CHARGE PUMP CONFIG */
+#define LM49453_P1_CP_CONFIG1_REG			0xB0
+#define LM49453_P1_CP_CONFIG2_REG			0xB1
+#define LM49453_P1_CP_CONFIG3_REG			0xB2
+#define LM49453_P1_CP_CONFIG4_REG			0xB3
+#define LM49453_P1_CP_LA_VTH1L_REG			0xB4
+#define LM49453_P1_CP_LA_VTH1M_REG			0xB5
+#define LM49453_P1_CP_LA_VTH2L_REG			0xB6
+#define LM49453_P1_CP_LA_VTH2M_REG			0xB7
+#define LM49453_P1_CP_LA_VTH3L_REG			0xB8
+#define LM49453_P1_CP_LA_VTH3H_REG			0xB9
+#define LM49453_P1_CP_CLK_DIV_REG			0xBA
+
+/* DAC */
+#define LM49453_P1_DAC_CHOP_REG				0xC0
+
+#define	LM49453_CLK_SRC_MCLK				1
+#endif
diff --git a/sound/soc/codecs/max9759.c b/sound/soc/codecs/max9759.c
new file mode 100644
index 0000000..ecfb4a8
--- /dev/null
+++ b/sound/soc/codecs/max9759.c
@@ -0,0 +1,207 @@
+// SPDX-Licence-Identifier: GPL-2.0
+/*
+ * MAX9759 Amplifier Driver
+ *
+ * Copyright (c) 2017 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#define DRV_NAME "max9759"
+
+struct max9759 {
+	struct gpio_desc *gpiod_shutdown;
+	struct gpio_desc *gpiod_mute;
+	struct gpio_descs *gpiod_gain;
+	bool is_mute;
+	unsigned int gain;
+};
+
+static int pga_event(struct snd_soc_dapm_widget *w,
+		     struct snd_kcontrol *control, int event)
+{
+	struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+	struct max9759 *priv = snd_soc_component_get_drvdata(c);
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		gpiod_set_value_cansleep(priv->gpiod_shutdown, 0);
+	else
+		gpiod_set_value_cansleep(priv->gpiod_shutdown, 1);
+
+	return 0;
+}
+
+/* From 6dB to 24dB in steps of 6dB */
+static const DECLARE_TLV_DB_SCALE(speaker_gain_tlv, 600, 600, 0);
+
+static int speaker_gain_control_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+	struct max9759 *priv = snd_soc_component_get_drvdata(c);
+
+	ucontrol->value.integer.value[0] = priv->gain;
+
+	return 0;
+}
+
+static const bool speaker_gain_table[4][2] = {
+	/* G1, G2 */
+	{true, true},	/* +6dB */
+	{false, true},	/* +12dB */
+	{true, false},	/* +18dB */
+	{false, false},	/* +24dB */
+};
+
+static int speaker_gain_control_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+	struct max9759 *priv = snd_soc_component_get_drvdata(c);
+
+	if (ucontrol->value.integer.value[0] > 3)
+		return -EINVAL;
+
+	priv->gain = ucontrol->value.integer.value[0];
+
+	/* G1 */
+	gpiod_set_value_cansleep(priv->gpiod_gain->desc[0],
+				 speaker_gain_table[priv->gain][0]);
+	/* G2 */
+	gpiod_set_value_cansleep(priv->gpiod_gain->desc[1],
+				 speaker_gain_table[priv->gain][1]);
+
+	return 1;
+}
+
+static int speaker_mute_get(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+	struct max9759 *priv = snd_soc_component_get_drvdata(c);
+
+	ucontrol->value.integer.value[0] = !priv->is_mute;
+
+	return 0;
+}
+
+static int speaker_mute_put(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+	struct max9759 *priv = snd_soc_component_get_drvdata(c);
+
+	priv->is_mute = !ucontrol->value.integer.value[0];
+
+	gpiod_set_value_cansleep(priv->gpiod_mute, priv->is_mute);
+
+	return 1;
+}
+
+static const struct snd_kcontrol_new max9759_dapm_controls[] = {
+	SOC_SINGLE_EXT_TLV("Speaker Gain Volume", 0, 0, 3, 0,
+			   speaker_gain_control_get, speaker_gain_control_put,
+			   speaker_gain_tlv),
+	SOC_SINGLE_BOOL_EXT("Playback Switch", 0,
+			    speaker_mute_get, speaker_mute_put),
+};
+
+static const struct snd_soc_dapm_widget max9759_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("INL"),
+	SND_SOC_DAPM_INPUT("INR"),
+	SND_SOC_DAPM_PGA_E("PGA", SND_SOC_NOPM, 0, 0, NULL, 0, pga_event,
+			   (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)),
+	SND_SOC_DAPM_OUTPUT("OUTL"),
+	SND_SOC_DAPM_OUTPUT("OUTR"),
+};
+
+static const struct snd_soc_dapm_route max9759_dapm_routes[] = {
+	{ "PGA", NULL, "INL" },
+	{ "PGA", NULL, "INR" },
+	{ "OUTL", NULL, "PGA" },
+	{ "OUTR", NULL, "PGA" },
+};
+
+static const struct snd_soc_component_driver max9759_component_driver = {
+	.controls		= max9759_dapm_controls,
+	.num_controls		= ARRAY_SIZE(max9759_dapm_controls),
+	.dapm_widgets		= max9759_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max9759_dapm_widgets),
+	.dapm_routes		= max9759_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(max9759_dapm_routes),
+};
+
+static int max9759_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct max9759 *priv;
+	int err;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, priv);
+
+	priv->gpiod_shutdown = devm_gpiod_get(dev, "shutdown", GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->gpiod_shutdown)) {
+		err = PTR_ERR(priv->gpiod_shutdown);
+		if (err != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get 'shutdown' gpio: %d", err);
+		return err;
+	}
+
+	priv->gpiod_mute = devm_gpiod_get(dev, "mute", GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->gpiod_mute)) {
+		err = PTR_ERR(priv->gpiod_mute);
+		if (err != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get 'mute' gpio: %d", err);
+		return err;
+	}
+	priv->is_mute = true;
+
+	priv->gpiod_gain = devm_gpiod_get_array(dev, "gain", GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->gpiod_gain)) {
+		err = PTR_ERR(priv->gpiod_gain);
+		if (err != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get 'gain' gpios: %d", err);
+		return err;
+	}
+	priv->gain = 0;
+
+	if (priv->gpiod_gain->ndescs != 2) {
+		dev_err(dev, "Invalid 'gain' gpios count: %d",
+			priv->gpiod_gain->ndescs);
+		return -EINVAL;
+	}
+
+	return devm_snd_soc_register_component(dev, &max9759_component_driver,
+					       NULL, 0);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id max9759_ids[] = {
+	{ .compatible = "maxim,max9759", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max9759_ids);
+#endif
+
+static struct platform_driver max9759_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = of_match_ptr(max9759_ids),
+	},
+	.probe = max9759_probe,
+};
+
+module_platform_driver(max9759_driver);
+
+MODULE_DESCRIPTION("ASoC MAX9759 amplifier driver");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c
new file mode 100644
index 0000000..7017c03
--- /dev/null
+++ b/sound/soc/codecs/max9768.c
@@ -0,0 +1,228 @@
+/*
+ * MAX9768 AMP driver
+ *
+ * Copyright (C) 2011, 2012 by Wolfram Sang, Pengutronix e.K.
+ *
+ * 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; version 2 of the License.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/max9768.h>
+
+/* "Registers" */
+#define MAX9768_VOL 0
+#define MAX9768_CTRL 3
+
+/* Commands */
+#define MAX9768_CTRL_PWM 0x15
+#define MAX9768_CTRL_FILTERLESS 0x16
+
+struct max9768 {
+	struct regmap *regmap;
+	int mute_gpio;
+	int shdn_gpio;
+	u32 flags;
+};
+
+static const struct reg_default max9768_default_regs[] = {
+	{ 0, 0 },
+	{ 3,  MAX9768_CTRL_FILTERLESS},
+};
+
+static int max9768_get_gpio(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+	struct max9768 *max9768 = snd_soc_component_get_drvdata(c);
+	int val = gpio_get_value_cansleep(max9768->mute_gpio);
+
+	ucontrol->value.integer.value[0] = !val;
+
+	return 0;
+}
+
+static int max9768_set_gpio(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+	struct max9768 *max9768 = snd_soc_component_get_drvdata(c);
+
+	gpio_set_value_cansleep(max9768->mute_gpio, !ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static const DECLARE_TLV_DB_RANGE(volume_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(-16150, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(-9280, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(-9030, 0, 0),
+	3, 3, TLV_DB_SCALE_ITEM(-8680, 0, 0),
+	4, 4, TLV_DB_SCALE_ITEM(-8430, 0, 0),
+	5, 5, TLV_DB_SCALE_ITEM(-8080, 0, 0),
+	6, 6, TLV_DB_SCALE_ITEM(-7830, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(-7470, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(-7220, 0, 0),
+	9, 9, TLV_DB_SCALE_ITEM(-6870, 0, 0),
+	10, 10, TLV_DB_SCALE_ITEM(-6620, 0, 0),
+	11, 11, TLV_DB_SCALE_ITEM(-6270, 0, 0),
+	12, 12, TLV_DB_SCALE_ITEM(-6020, 0, 0),
+	13, 13, TLV_DB_SCALE_ITEM(-5670, 0, 0),
+	14, 14, TLV_DB_SCALE_ITEM(-5420, 0, 0),
+	15, 17, TLV_DB_SCALE_ITEM(-5060, 250, 0),
+	18, 18, TLV_DB_SCALE_ITEM(-4370, 0, 0),
+	19, 19, TLV_DB_SCALE_ITEM(-4210, 0, 0),
+	20, 20, TLV_DB_SCALE_ITEM(-3960, 0, 0),
+	21, 21, TLV_DB_SCALE_ITEM(-3760, 0, 0),
+	22, 22, TLV_DB_SCALE_ITEM(-3600, 0, 0),
+	23, 23, TLV_DB_SCALE_ITEM(-3340, 0, 0),
+	24, 24, TLV_DB_SCALE_ITEM(-3150, 0, 0),
+	25, 25, TLV_DB_SCALE_ITEM(-2980, 0, 0),
+	26, 26, TLV_DB_SCALE_ITEM(-2720, 0, 0),
+	27, 27, TLV_DB_SCALE_ITEM(-2520, 0, 0),
+	28, 30, TLV_DB_SCALE_ITEM(-2350, 190, 0),
+	31, 31, TLV_DB_SCALE_ITEM(-1750, 0, 0),
+	32, 34, TLV_DB_SCALE_ITEM(-1640, 100, 0),
+	35, 37, TLV_DB_SCALE_ITEM(-1310, 110, 0),
+	38, 39, TLV_DB_SCALE_ITEM(-990, 100, 0),
+	40, 40, TLV_DB_SCALE_ITEM(-710, 0, 0),
+	41, 41, TLV_DB_SCALE_ITEM(-600, 0, 0),
+	42, 42, TLV_DB_SCALE_ITEM(-500, 0, 0),
+	43, 43, TLV_DB_SCALE_ITEM(-340, 0, 0),
+	44, 44, TLV_DB_SCALE_ITEM(-190, 0, 0),
+	45, 45, TLV_DB_SCALE_ITEM(-50, 0, 0),
+	46, 46, TLV_DB_SCALE_ITEM(50, 0, 0),
+	47, 50, TLV_DB_SCALE_ITEM(120, 40, 0),
+	51, 57, TLV_DB_SCALE_ITEM(290, 50, 0),
+	58, 58, TLV_DB_SCALE_ITEM(650, 0, 0),
+	59, 62, TLV_DB_SCALE_ITEM(700, 60, 0),
+	63, 63, TLV_DB_SCALE_ITEM(950, 0, 0)
+);
+
+static const struct snd_kcontrol_new max9768_volume[] = {
+	SOC_SINGLE_TLV("Playback Volume", MAX9768_VOL, 0, 63, 0, volume_tlv),
+};
+
+static const struct snd_kcontrol_new max9768_mute[] = {
+	SOC_SINGLE_BOOL_EXT("Playback Switch", 0, max9768_get_gpio, max9768_set_gpio),
+};
+
+static const struct snd_soc_dapm_widget max9768_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN"),
+
+SND_SOC_DAPM_OUTPUT("OUT+"),
+SND_SOC_DAPM_OUTPUT("OUT-"),
+};
+
+static const struct snd_soc_dapm_route max9768_dapm_routes[] = {
+	{ "OUT+", NULL, "IN" },
+	{ "OUT-", NULL, "IN" },
+};
+
+static int max9768_probe(struct snd_soc_component *component)
+{
+	struct max9768 *max9768 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	if (max9768->flags & MAX9768_FLAG_CLASSIC_PWM) {
+		ret = regmap_write(max9768->regmap, MAX9768_CTRL,
+			MAX9768_CTRL_PWM);
+		if (ret)
+			return ret;
+	}
+
+	if (gpio_is_valid(max9768->mute_gpio)) {
+		ret = snd_soc_add_component_controls(component, max9768_mute,
+				ARRAY_SIZE(max9768_mute));
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver max9768_component_driver = {
+	.probe = max9768_probe,
+	.controls = max9768_volume,
+	.num_controls = ARRAY_SIZE(max9768_volume),
+	.dapm_widgets = max9768_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(max9768_dapm_widgets),
+	.dapm_routes = max9768_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(max9768_dapm_routes),
+};
+
+static const struct regmap_config max9768_i2c_regmap_config = {
+	.reg_bits = 2,
+	.val_bits = 6,
+	.max_register = 3,
+	.reg_defaults = max9768_default_regs,
+	.num_reg_defaults = ARRAY_SIZE(max9768_default_regs),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int max9768_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct max9768 *max9768;
+	struct max9768_pdata *pdata = client->dev.platform_data;
+	int err;
+
+	max9768 = devm_kzalloc(&client->dev, sizeof(*max9768), GFP_KERNEL);
+	if (!max9768)
+		return -ENOMEM;
+
+	if (pdata) {
+		/* Mute on powerup to avoid clicks */
+		err = devm_gpio_request_one(&client->dev, pdata->mute_gpio,
+				GPIOF_INIT_HIGH, "MAX9768 Mute");
+		max9768->mute_gpio = err ?: pdata->mute_gpio;
+
+		/* Activate chip by releasing shutdown, enables I2C */
+		err = devm_gpio_request_one(&client->dev, pdata->shdn_gpio,
+				GPIOF_INIT_HIGH, "MAX9768 Shutdown");
+		max9768->shdn_gpio = err ?: pdata->shdn_gpio;
+
+		max9768->flags = pdata->flags;
+	} else {
+		max9768->shdn_gpio = -EINVAL;
+		max9768->mute_gpio = -EINVAL;
+	}
+
+	i2c_set_clientdata(client, max9768);
+
+	max9768->regmap = devm_regmap_init_i2c(client, &max9768_i2c_regmap_config);
+	if (IS_ERR(max9768->regmap))
+		return PTR_ERR(max9768->regmap);
+
+	return devm_snd_soc_register_component(&client->dev,
+		&max9768_component_driver, NULL, 0);
+}
+
+static const struct i2c_device_id max9768_i2c_id[] = {
+	{ "max9768", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max9768_i2c_id);
+
+static struct i2c_driver max9768_i2c_driver = {
+	.driver = {
+		.name = "max9768",
+	},
+	.probe = max9768_i2c_probe,
+	.id_table = max9768_i2c_id,
+};
+module_i2c_driver(max9768_i2c_driver);
+
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("ASoC MAX9768 amplifier driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
new file mode 100644
index 0000000..fb515aa
--- /dev/null
+++ b/sound/soc/codecs/max98088.c
@@ -0,0 +1,1757 @@
+/*
+ * max98088.c -- MAX98088 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+#include <sound/max98088.h>
+#include "max98088.h"
+
+enum max98088_type {
+       MAX98088,
+       MAX98089,
+};
+
+struct max98088_cdata {
+       unsigned int rate;
+       unsigned int fmt;
+       int eq_sel;
+};
+
+struct max98088_priv {
+	struct regmap *regmap;
+	enum max98088_type devtype;
+	struct max98088_pdata *pdata;
+	unsigned int sysclk;
+	struct max98088_cdata dai[2];
+	int eq_textcnt;
+	const char **eq_texts;
+	struct soc_enum eq_enum;
+	u8 ina_state;
+	u8 inb_state;
+	unsigned int ex_mode;
+	unsigned int digmic;
+	unsigned int mic1pre;
+	unsigned int mic2pre;
+	unsigned int extmic_mode;
+};
+
+static const struct reg_default max98088_reg[] = {
+	{  0xf, 0x00 }, /* 0F interrupt enable */
+
+	{ 0x10, 0x00 }, /* 10 master clock */
+	{ 0x11, 0x00 }, /* 11 DAI1 clock mode */
+	{ 0x12, 0x00 }, /* 12 DAI1 clock control */
+	{ 0x13, 0x00 }, /* 13 DAI1 clock control */
+	{ 0x14, 0x00 }, /* 14 DAI1 format */
+	{ 0x15, 0x00 }, /* 15 DAI1 clock */
+	{ 0x16, 0x00 }, /* 16 DAI1 config */
+	{ 0x17, 0x00 }, /* 17 DAI1 TDM */
+	{ 0x18, 0x00 }, /* 18 DAI1 filters */
+	{ 0x19, 0x00 }, /* 19 DAI2 clock mode */
+	{ 0x1a, 0x00 }, /* 1A DAI2 clock control */
+	{ 0x1b, 0x00 }, /* 1B DAI2 clock control */
+	{ 0x1c, 0x00 }, /* 1C DAI2 format */
+	{ 0x1d, 0x00 }, /* 1D DAI2 clock */
+	{ 0x1e, 0x00 }, /* 1E DAI2 config */
+	{ 0x1f, 0x00 }, /* 1F DAI2 TDM */
+
+	{ 0x20, 0x00 }, /* 20 DAI2 filters */
+	{ 0x21, 0x00 }, /* 21 data config */
+	{ 0x22, 0x00 }, /* 22 DAC mixer */
+	{ 0x23, 0x00 }, /* 23 left ADC mixer */
+	{ 0x24, 0x00 }, /* 24 right ADC mixer */
+	{ 0x25, 0x00 }, /* 25 left HP mixer */
+	{ 0x26, 0x00 }, /* 26 right HP mixer */
+	{ 0x27, 0x00 }, /* 27 HP control */
+	{ 0x28, 0x00 }, /* 28 left REC mixer */
+	{ 0x29, 0x00 }, /* 29 right REC mixer */
+	{ 0x2a, 0x00 }, /* 2A REC control */
+	{ 0x2b, 0x00 }, /* 2B left SPK mixer */
+	{ 0x2c, 0x00 }, /* 2C right SPK mixer */
+	{ 0x2d, 0x00 }, /* 2D SPK control */
+	{ 0x2e, 0x00 }, /* 2E sidetone */
+	{ 0x2f, 0x00 }, /* 2F DAI1 playback level */
+
+	{ 0x30, 0x00 }, /* 30 DAI1 playback level */
+	{ 0x31, 0x00 }, /* 31 DAI2 playback level */
+	{ 0x32, 0x00 }, /* 32 DAI2 playbakc level */
+	{ 0x33, 0x00 }, /* 33 left ADC level */
+	{ 0x34, 0x00 }, /* 34 right ADC level */
+	{ 0x35, 0x00 }, /* 35 MIC1 level */
+	{ 0x36, 0x00 }, /* 36 MIC2 level */
+	{ 0x37, 0x00 }, /* 37 INA level */
+	{ 0x38, 0x00 }, /* 38 INB level */
+	{ 0x39, 0x00 }, /* 39 left HP volume */
+	{ 0x3a, 0x00 }, /* 3A right HP volume */
+	{ 0x3b, 0x00 }, /* 3B left REC volume */
+	{ 0x3c, 0x00 }, /* 3C right REC volume */
+	{ 0x3d, 0x00 }, /* 3D left SPK volume */
+	{ 0x3e, 0x00 }, /* 3E right SPK volume */
+	{ 0x3f, 0x00 }, /* 3F MIC config */
+
+	{ 0x40, 0x00 }, /* 40 MIC threshold */
+	{ 0x41, 0x00 }, /* 41 excursion limiter filter */
+	{ 0x42, 0x00 }, /* 42 excursion limiter threshold */
+	{ 0x43, 0x00 }, /* 43 ALC */
+	{ 0x44, 0x00 }, /* 44 power limiter threshold */
+	{ 0x45, 0x00 }, /* 45 power limiter config */
+	{ 0x46, 0x00 }, /* 46 distortion limiter config */
+	{ 0x47, 0x00 }, /* 47 audio input */
+        { 0x48, 0x00 }, /* 48 microphone */
+	{ 0x49, 0x00 }, /* 49 level control */
+	{ 0x4a, 0x00 }, /* 4A bypass switches */
+	{ 0x4b, 0x00 }, /* 4B jack detect */
+	{ 0x4c, 0x00 }, /* 4C input enable */
+	{ 0x4d, 0x00 }, /* 4D output enable */
+	{ 0x4e, 0xF0 }, /* 4E bias control */
+	{ 0x4f, 0x00 }, /* 4F DAC power */
+
+	{ 0x50, 0x0F }, /* 50 DAC power */
+	{ 0x51, 0x00 }, /* 51 system */
+	{ 0x52, 0x00 }, /* 52 DAI1 EQ1 */
+	{ 0x53, 0x00 }, /* 53 DAI1 EQ1 */
+	{ 0x54, 0x00 }, /* 54 DAI1 EQ1 */
+	{ 0x55, 0x00 }, /* 55 DAI1 EQ1 */
+	{ 0x56, 0x00 }, /* 56 DAI1 EQ1 */
+	{ 0x57, 0x00 }, /* 57 DAI1 EQ1 */
+	{ 0x58, 0x00 }, /* 58 DAI1 EQ1 */
+	{ 0x59, 0x00 }, /* 59 DAI1 EQ1 */
+	{ 0x5a, 0x00 }, /* 5A DAI1 EQ1 */
+	{ 0x5b, 0x00 }, /* 5B DAI1 EQ1 */
+	{ 0x5c, 0x00 }, /* 5C DAI1 EQ2 */
+	{ 0x5d, 0x00 }, /* 5D DAI1 EQ2 */
+	{ 0x5e, 0x00 }, /* 5E DAI1 EQ2 */
+	{ 0x5f, 0x00 }, /* 5F DAI1 EQ2 */
+
+	{ 0x60, 0x00 }, /* 60 DAI1 EQ2 */
+	{ 0x61, 0x00 }, /* 61 DAI1 EQ2 */
+	{ 0x62, 0x00 }, /* 62 DAI1 EQ2 */
+	{ 0x63, 0x00 }, /* 63 DAI1 EQ2 */
+	{ 0x64, 0x00 }, /* 64 DAI1 EQ2 */
+	{ 0x65, 0x00 }, /* 65 DAI1 EQ2 */
+	{ 0x66, 0x00 }, /* 66 DAI1 EQ3 */
+	{ 0x67, 0x00 }, /* 67 DAI1 EQ3 */
+	{ 0x68, 0x00 }, /* 68 DAI1 EQ3 */
+	{ 0x69, 0x00 }, /* 69 DAI1 EQ3 */
+	{ 0x6a, 0x00 }, /* 6A DAI1 EQ3 */
+	{ 0x6b, 0x00 }, /* 6B DAI1 EQ3 */
+	{ 0x6c, 0x00 }, /* 6C DAI1 EQ3 */
+	{ 0x6d, 0x00 }, /* 6D DAI1 EQ3 */
+	{ 0x6e, 0x00 }, /* 6E DAI1 EQ3 */
+	{ 0x6f, 0x00 }, /* 6F DAI1 EQ3 */
+
+	{ 0x70, 0x00 }, /* 70 DAI1 EQ4 */
+	{ 0x71, 0x00 }, /* 71 DAI1 EQ4 */
+	{ 0x72, 0x00 }, /* 72 DAI1 EQ4 */
+	{ 0x73, 0x00 }, /* 73 DAI1 EQ4 */
+	{ 0x74, 0x00 }, /* 74 DAI1 EQ4 */
+	{ 0x75, 0x00 }, /* 75 DAI1 EQ4 */
+	{ 0x76, 0x00 }, /* 76 DAI1 EQ4 */
+	{ 0x77, 0x00 }, /* 77 DAI1 EQ4 */
+	{ 0x78, 0x00 }, /* 78 DAI1 EQ4 */
+	{ 0x79, 0x00 }, /* 79 DAI1 EQ4 */
+	{ 0x7a, 0x00 }, /* 7A DAI1 EQ5 */
+	{ 0x7b, 0x00 }, /* 7B DAI1 EQ5 */
+	{ 0x7c, 0x00 }, /* 7C DAI1 EQ5 */
+	{ 0x7d, 0x00 }, /* 7D DAI1 EQ5 */
+	{ 0x7e, 0x00 }, /* 7E DAI1 EQ5 */
+	{ 0x7f, 0x00 }, /* 7F DAI1 EQ5 */
+
+	{ 0x80, 0x00 }, /* 80 DAI1 EQ5 */
+	{ 0x81, 0x00 }, /* 81 DAI1 EQ5 */
+	{ 0x82, 0x00 }, /* 82 DAI1 EQ5 */
+	{ 0x83, 0x00 }, /* 83 DAI1 EQ5 */
+	{ 0x84, 0x00 }, /* 84 DAI2 EQ1 */
+	{ 0x85, 0x00 }, /* 85 DAI2 EQ1 */
+	{ 0x86, 0x00 }, /* 86 DAI2 EQ1 */
+	{ 0x87, 0x00 }, /* 87 DAI2 EQ1 */
+	{ 0x88, 0x00 }, /* 88 DAI2 EQ1 */
+	{ 0x89, 0x00 }, /* 89 DAI2 EQ1 */
+	{ 0x8a, 0x00 }, /* 8A DAI2 EQ1 */
+	{ 0x8b, 0x00 }, /* 8B DAI2 EQ1 */
+	{ 0x8c, 0x00 }, /* 8C DAI2 EQ1 */
+	{ 0x8d, 0x00 }, /* 8D DAI2 EQ1 */
+	{ 0x8e, 0x00 }, /* 8E DAI2 EQ2 */
+	{ 0x8f, 0x00 }, /* 8F DAI2 EQ2 */
+
+	{ 0x90, 0x00 }, /* 90 DAI2 EQ2 */
+	{ 0x91, 0x00 }, /* 91 DAI2 EQ2 */
+	{ 0x92, 0x00 }, /* 92 DAI2 EQ2 */
+	{ 0x93, 0x00 }, /* 93 DAI2 EQ2 */
+	{ 0x94, 0x00 }, /* 94 DAI2 EQ2 */
+	{ 0x95, 0x00 }, /* 95 DAI2 EQ2 */
+	{ 0x96, 0x00 }, /* 96 DAI2 EQ2 */
+	{ 0x97, 0x00 }, /* 97 DAI2 EQ2 */
+	{ 0x98, 0x00 }, /* 98 DAI2 EQ3 */
+	{ 0x99, 0x00 }, /* 99 DAI2 EQ3 */
+	{ 0x9a, 0x00 }, /* 9A DAI2 EQ3 */
+        { 0x9b, 0x00 }, /* 9B DAI2 EQ3 */
+	{ 0x9c, 0x00 }, /* 9C DAI2 EQ3 */
+	{ 0x9d, 0x00 }, /* 9D DAI2 EQ3 */
+	{ 0x9e, 0x00 }, /* 9E DAI2 EQ3 */
+	{ 0x9f, 0x00 }, /* 9F DAI2 EQ3 */
+
+	{ 0xa0, 0x00 }, /* A0 DAI2 EQ3 */
+	{ 0xa1, 0x00 }, /* A1 DAI2 EQ3 */
+	{ 0xa2, 0x00 }, /* A2 DAI2 EQ4 */
+	{ 0xa3, 0x00 }, /* A3 DAI2 EQ4 */
+	{ 0xa4, 0x00 }, /* A4 DAI2 EQ4 */
+	{ 0xa5, 0x00 }, /* A5 DAI2 EQ4 */
+	{ 0xa6, 0x00 }, /* A6 DAI2 EQ4 */
+	{ 0xa7, 0x00 }, /* A7 DAI2 EQ4 */
+	{ 0xa8, 0x00 }, /* A8 DAI2 EQ4 */
+	{ 0xa9, 0x00 }, /* A9 DAI2 EQ4 */
+	{ 0xaa, 0x00 }, /* AA DAI2 EQ4 */
+	{ 0xab, 0x00 }, /* AB DAI2 EQ4 */
+	{ 0xac, 0x00 }, /* AC DAI2 EQ5 */
+	{ 0xad, 0x00 }, /* AD DAI2 EQ5 */
+	{ 0xae, 0x00 }, /* AE DAI2 EQ5 */
+	{ 0xaf, 0x00 }, /* AF DAI2 EQ5 */
+
+	{ 0xb0, 0x00 }, /* B0 DAI2 EQ5 */
+	{ 0xb1, 0x00 }, /* B1 DAI2 EQ5 */
+	{ 0xb2, 0x00 }, /* B2 DAI2 EQ5 */
+	{ 0xb3, 0x00 }, /* B3 DAI2 EQ5 */
+	{ 0xb4, 0x00 }, /* B4 DAI2 EQ5 */
+	{ 0xb5, 0x00 }, /* B5 DAI2 EQ5 */
+	{ 0xb6, 0x00 }, /* B6 DAI1 biquad */
+	{ 0xb7, 0x00 }, /* B7 DAI1 biquad */
+	{ 0xb8 ,0x00 }, /* B8 DAI1 biquad */
+	{ 0xb9, 0x00 }, /* B9 DAI1 biquad */
+	{ 0xba, 0x00 }, /* BA DAI1 biquad */
+	{ 0xbb, 0x00 }, /* BB DAI1 biquad */
+	{ 0xbc, 0x00 }, /* BC DAI1 biquad */
+	{ 0xbd, 0x00 }, /* BD DAI1 biquad */
+	{ 0xbe, 0x00 }, /* BE DAI1 biquad */
+        { 0xbf, 0x00 }, /* BF DAI1 biquad */
+
+	{ 0xc0, 0x00 }, /* C0 DAI2 biquad */
+	{ 0xc1, 0x00 }, /* C1 DAI2 biquad */
+	{ 0xc2, 0x00 }, /* C2 DAI2 biquad */
+	{ 0xc3, 0x00 }, /* C3 DAI2 biquad */
+	{ 0xc4, 0x00 }, /* C4 DAI2 biquad */
+	{ 0xc5, 0x00 }, /* C5 DAI2 biquad */
+	{ 0xc6, 0x00 }, /* C6 DAI2 biquad */
+	{ 0xc7, 0x00 }, /* C7 DAI2 biquad */
+	{ 0xc8, 0x00 }, /* C8 DAI2 biquad */
+	{ 0xc9, 0x00 }, /* C9 DAI2 biquad */
+};
+
+static bool max98088_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case M98088_REG_00_IRQ_STATUS ... 0xC9:
+	case M98088_REG_FF_REV_ID:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max98088_writeable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case M98088_REG_03_BATTERY_VOLTAGE ... 0xC9:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max98088_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case M98088_REG_00_IRQ_STATUS ... M98088_REG_03_BATTERY_VOLTAGE:
+	case M98088_REG_FF_REV_ID:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config max98088_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.readable_reg = max98088_readable_register,
+	.writeable_reg = max98088_writeable_register,
+	.volatile_reg = max98088_volatile_register,
+	.max_register = 0xff,
+
+	.reg_defaults = max98088_reg,
+	.num_reg_defaults = ARRAY_SIZE(max98088_reg),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+/*
+ * Load equalizer DSP coefficient configurations registers
+ */
+static void m98088_eq_band(struct snd_soc_component *component, unsigned int dai,
+                   unsigned int band, u16 *coefs)
+{
+       unsigned int eq_reg;
+       unsigned int i;
+
+	if (WARN_ON(band > 4) ||
+	    WARN_ON(dai > 1))
+		return;
+
+       /* Load the base register address */
+       eq_reg = dai ? M98088_REG_84_DAI2_EQ_BASE : M98088_REG_52_DAI1_EQ_BASE;
+
+       /* Add the band address offset, note adjustment for word address */
+       eq_reg += band * (M98088_COEFS_PER_BAND << 1);
+
+       /* Step through the registers and coefs */
+       for (i = 0; i < M98088_COEFS_PER_BAND; i++) {
+               snd_soc_component_write(component, eq_reg++, M98088_BYTE1(coefs[i]));
+               snd_soc_component_write(component, eq_reg++, M98088_BYTE0(coefs[i]));
+       }
+}
+
+/*
+ * Excursion limiter modes
+ */
+static const char *max98088_exmode_texts[] = {
+       "Off", "100Hz", "400Hz", "600Hz", "800Hz", "1000Hz", "200-400Hz",
+       "400-600Hz", "400-800Hz",
+};
+
+static const unsigned int max98088_exmode_values[] = {
+       0x00, 0x43, 0x10, 0x20, 0x30, 0x40, 0x11, 0x22, 0x32
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(max98088_exmode_enum,
+				  M98088_REG_41_SPKDHP, 0, 127,
+				  max98088_exmode_texts,
+				  max98088_exmode_values);
+
+static const char *max98088_ex_thresh[] = { /* volts PP */
+       "0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"};
+static SOC_ENUM_SINGLE_DECL(max98088_ex_thresh_enum,
+			    M98088_REG_42_SPKDHP_THRESH, 0,
+			    max98088_ex_thresh);
+
+static const char *max98088_fltr_mode[] = {"Voice", "Music" };
+static SOC_ENUM_SINGLE_DECL(max98088_filter_mode_enum,
+			    M98088_REG_18_DAI1_FILTERS, 7,
+			    max98088_fltr_mode);
+
+static const char *max98088_extmic_text[] = { "None", "MIC1", "MIC2" };
+
+static SOC_ENUM_SINGLE_DECL(max98088_extmic_enum,
+			    M98088_REG_48_CFG_MIC, 0,
+			    max98088_extmic_text);
+
+static const struct snd_kcontrol_new max98088_extmic_mux =
+       SOC_DAPM_ENUM("External MIC Mux", max98088_extmic_enum);
+
+static const char *max98088_dai1_fltr[] = {
+       "Off", "fc=258/fs=16k", "fc=500/fs=16k",
+       "fc=258/fs=8k", "fc=500/fs=8k", "fc=200"};
+static SOC_ENUM_SINGLE_DECL(max98088_dai1_dac_filter_enum,
+			    M98088_REG_18_DAI1_FILTERS, 0,
+			    max98088_dai1_fltr);
+static SOC_ENUM_SINGLE_DECL(max98088_dai1_adc_filter_enum,
+			    M98088_REG_18_DAI1_FILTERS, 4,
+			    max98088_dai1_fltr);
+
+static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       unsigned int sel = ucontrol->value.integer.value[0];
+
+       max98088->mic1pre = sel;
+       snd_soc_component_update_bits(component, M98088_REG_35_LVL_MIC1, M98088_MICPRE_MASK,
+               (1+sel)<<M98088_MICPRE_SHIFT);
+
+       return 0;
+}
+
+static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] = max98088->mic1pre;
+       return 0;
+}
+
+static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       unsigned int sel = ucontrol->value.integer.value[0];
+
+       max98088->mic2pre = sel;
+       snd_soc_component_update_bits(component, M98088_REG_36_LVL_MIC2, M98088_MICPRE_MASK,
+               (1+sel)<<M98088_MICPRE_SHIFT);
+
+       return 0;
+}
+
+static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] = max98088->mic2pre;
+       return 0;
+}
+
+static const DECLARE_TLV_DB_RANGE(max98088_micboost_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+	2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(max98088_hp_tlv,
+	0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0),
+	7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0),
+	15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0),
+	22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0),
+	28, 31, TLV_DB_SCALE_ITEM(150, 50, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(max98088_spk_tlv,
+	0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0),
+	7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0),
+	15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0),
+	22, 27, TLV_DB_SCALE_ITEM(100, 100, 0),
+	28, 31, TLV_DB_SCALE_ITEM(650, 50, 0)
+);
+
+static const struct snd_kcontrol_new max98088_snd_controls[] = {
+
+	SOC_DOUBLE_R_TLV("Headphone Volume", M98088_REG_39_LVL_HP_L,
+			 M98088_REG_3A_LVL_HP_R, 0, 31, 0, max98088_hp_tlv),
+	SOC_DOUBLE_R_TLV("Speaker Volume", M98088_REG_3D_LVL_SPK_L,
+			 M98088_REG_3E_LVL_SPK_R, 0, 31, 0, max98088_spk_tlv),
+	SOC_DOUBLE_R_TLV("Receiver Volume", M98088_REG_3B_LVL_REC_L,
+			 M98088_REG_3C_LVL_REC_R, 0, 31, 0, max98088_spk_tlv),
+
+       SOC_DOUBLE_R("Headphone Switch", M98088_REG_39_LVL_HP_L,
+               M98088_REG_3A_LVL_HP_R, 7, 1, 1),
+       SOC_DOUBLE_R("Speaker Switch", M98088_REG_3D_LVL_SPK_L,
+               M98088_REG_3E_LVL_SPK_R, 7, 1, 1),
+       SOC_DOUBLE_R("Receiver Switch", M98088_REG_3B_LVL_REC_L,
+               M98088_REG_3C_LVL_REC_R, 7, 1, 1),
+
+       SOC_SINGLE("MIC1 Volume", M98088_REG_35_LVL_MIC1, 0, 31, 1),
+       SOC_SINGLE("MIC2 Volume", M98088_REG_36_LVL_MIC2, 0, 31, 1),
+
+       SOC_SINGLE_EXT_TLV("MIC1 Boost Volume",
+                       M98088_REG_35_LVL_MIC1, 5, 2, 0,
+                       max98088_mic1pre_get, max98088_mic1pre_set,
+                       max98088_micboost_tlv),
+       SOC_SINGLE_EXT_TLV("MIC2 Boost Volume",
+                       M98088_REG_36_LVL_MIC2, 5, 2, 0,
+                       max98088_mic2pre_get, max98088_mic2pre_set,
+                       max98088_micboost_tlv),
+
+       SOC_SINGLE("INA Volume", M98088_REG_37_LVL_INA, 0, 7, 1),
+       SOC_SINGLE("INB Volume", M98088_REG_38_LVL_INB, 0, 7, 1),
+
+       SOC_SINGLE("ADCL Volume", M98088_REG_33_LVL_ADC_L, 0, 15, 0),
+       SOC_SINGLE("ADCR Volume", M98088_REG_34_LVL_ADC_R, 0, 15, 0),
+
+       SOC_SINGLE("ADCL Boost Volume", M98088_REG_33_LVL_ADC_L, 4, 3, 0),
+       SOC_SINGLE("ADCR Boost Volume", M98088_REG_34_LVL_ADC_R, 4, 3, 0),
+
+       SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0),
+       SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0),
+
+       SOC_ENUM("EX Limiter Mode", max98088_exmode_enum),
+       SOC_ENUM("EX Limiter Threshold", max98088_ex_thresh_enum),
+
+       SOC_ENUM("DAI1 Filter Mode", max98088_filter_mode_enum),
+       SOC_ENUM("DAI1 DAC Filter", max98088_dai1_dac_filter_enum),
+       SOC_ENUM("DAI1 ADC Filter", max98088_dai1_adc_filter_enum),
+       SOC_SINGLE("DAI2 DC Block Switch", M98088_REG_20_DAI2_FILTERS,
+               0, 1, 0),
+
+       SOC_SINGLE("ALC Switch", M98088_REG_43_SPKALC_COMP, 7, 1, 0),
+       SOC_SINGLE("ALC Threshold", M98088_REG_43_SPKALC_COMP, 0, 7, 0),
+       SOC_SINGLE("ALC Multiband", M98088_REG_43_SPKALC_COMP, 3, 1, 0),
+       SOC_SINGLE("ALC Release Time", M98088_REG_43_SPKALC_COMP, 4, 7, 0),
+
+       SOC_SINGLE("PWR Limiter Threshold", M98088_REG_44_PWRLMT_CFG,
+               4, 15, 0),
+       SOC_SINGLE("PWR Limiter Weight", M98088_REG_44_PWRLMT_CFG, 0, 7, 0),
+       SOC_SINGLE("PWR Limiter Time1", M98088_REG_45_PWRLMT_TIME, 0, 15, 0),
+       SOC_SINGLE("PWR Limiter Time2", M98088_REG_45_PWRLMT_TIME, 4, 15, 0),
+
+       SOC_SINGLE("THD Limiter Threshold", M98088_REG_46_THDLMT_CFG, 4, 15, 0),
+       SOC_SINGLE("THD Limiter Time", M98088_REG_46_THDLMT_CFG, 0, 7, 0),
+};
+
+/* Left speaker mixer switch */
+static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 4, 1, 0),
+};
+
+/* Right speaker mixer switch */
+static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 4, 1, 0),
+};
+
+/* Left headphone mixer switch */
+static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_25_MIX_HP_LEFT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_25_MIX_HP_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_25_MIX_HP_LEFT, 4, 1, 0),
+};
+
+/* Right headphone mixer switch */
+static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_26_MIX_HP_RIGHT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_26_MIX_HP_RIGHT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_26_MIX_HP_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_26_MIX_HP_RIGHT, 4, 1, 0),
+};
+
+/* Left earpiece/receiver mixer switch */
+static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_28_MIX_REC_LEFT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_28_MIX_REC_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_28_MIX_REC_LEFT, 4, 1, 0),
+};
+
+/* Right earpiece/receiver mixer switch */
+static const struct snd_kcontrol_new max98088_right_rec_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_29_MIX_REC_RIGHT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_29_MIX_REC_RIGHT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_29_MIX_REC_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_29_MIX_REC_RIGHT, 4, 1, 0),
+};
+
+/* Left ADC mixer switch */
+static const struct snd_kcontrol_new max98088_left_ADC_mixer_controls[] = {
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_23_MIX_ADC_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_23_MIX_ADC_LEFT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_23_MIX_ADC_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_23_MIX_ADC_LEFT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_23_MIX_ADC_LEFT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_23_MIX_ADC_LEFT, 0, 1, 0),
+};
+
+/* Right ADC mixer switch */
+static const struct snd_kcontrol_new max98088_right_ADC_mixer_controls[] = {
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 0, 1, 0),
+};
+
+static int max98088_mic_event(struct snd_soc_dapm_widget *w,
+                            struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               if (w->reg == M98088_REG_35_LVL_MIC1) {
+                       snd_soc_component_update_bits(component, w->reg, M98088_MICPRE_MASK,
+                               (1+max98088->mic1pre)<<M98088_MICPRE_SHIFT);
+               } else {
+                       snd_soc_component_update_bits(component, w->reg, M98088_MICPRE_MASK,
+                               (1+max98088->mic2pre)<<M98088_MICPRE_SHIFT);
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_component_update_bits(component, w->reg, M98088_MICPRE_MASK, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * The line inputs are 2-channel stereo inputs with the left
+ * and right channels sharing a common PGA power control signal.
+ */
+static int max98088_line_pga(struct snd_soc_dapm_widget *w,
+                            int event, int line, u8 channel)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       u8 *state;
+
+	if (WARN_ON(!(channel == 1 || channel == 2)))
+		return -EINVAL;
+
+       switch (line) {
+       case LINE_INA:
+               state = &max98088->ina_state;
+               break;
+       case LINE_INB:
+               state = &max98088->inb_state;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               *state |= channel;
+               snd_soc_component_update_bits(component, w->reg,
+                       (1 << w->shift), (1 << w->shift));
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               *state &= ~channel;
+               if (*state == 0) {
+                       snd_soc_component_update_bits(component, w->reg,
+                               (1 << w->shift), 0);
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int max98088_pga_ina1_event(struct snd_soc_dapm_widget *w,
+                                  struct snd_kcontrol *k, int event)
+{
+       return max98088_line_pga(w, event, LINE_INA, 1);
+}
+
+static int max98088_pga_ina2_event(struct snd_soc_dapm_widget *w,
+                                  struct snd_kcontrol *k, int event)
+{
+       return max98088_line_pga(w, event, LINE_INA, 2);
+}
+
+static int max98088_pga_inb1_event(struct snd_soc_dapm_widget *w,
+                                  struct snd_kcontrol *k, int event)
+{
+       return max98088_line_pga(w, event, LINE_INB, 1);
+}
+
+static int max98088_pga_inb2_event(struct snd_soc_dapm_widget *w,
+                                  struct snd_kcontrol *k, int event)
+{
+       return max98088_line_pga(w, event, LINE_INB, 2);
+}
+
+static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
+
+       SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 1, 0),
+       SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 0, 0),
+
+       SND_SOC_DAPM_DAC("DACL1", "HiFi Playback",
+               M98088_REG_4D_PWR_EN_OUT, 1, 0),
+       SND_SOC_DAPM_DAC("DACR1", "HiFi Playback",
+               M98088_REG_4D_PWR_EN_OUT, 0, 0),
+       SND_SOC_DAPM_DAC("DACL2", "Aux Playback",
+               M98088_REG_4D_PWR_EN_OUT, 1, 0),
+       SND_SOC_DAPM_DAC("DACR2", "Aux Playback",
+               M98088_REG_4D_PWR_EN_OUT, 0, 0),
+
+       SND_SOC_DAPM_PGA("HP Left Out", M98088_REG_4D_PWR_EN_OUT,
+               7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HP Right Out", M98088_REG_4D_PWR_EN_OUT,
+               6, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("SPK Left Out", M98088_REG_4D_PWR_EN_OUT,
+               5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("SPK Right Out", M98088_REG_4D_PWR_EN_OUT,
+               4, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("REC Left Out", M98088_REG_4D_PWR_EN_OUT,
+               3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("REC Right Out", M98088_REG_4D_PWR_EN_OUT,
+               2, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX("External MIC", SND_SOC_NOPM, 0, 0,
+               &max98088_extmic_mux),
+
+       SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_left_hp_mixer_controls[0],
+               ARRAY_SIZE(max98088_left_hp_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_right_hp_mixer_controls[0],
+               ARRAY_SIZE(max98088_right_hp_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Left SPK Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_left_speaker_mixer_controls[0],
+               ARRAY_SIZE(max98088_left_speaker_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right SPK Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_right_speaker_mixer_controls[0],
+               ARRAY_SIZE(max98088_right_speaker_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Left REC Mixer", SND_SOC_NOPM, 0, 0,
+         &max98088_left_rec_mixer_controls[0],
+               ARRAY_SIZE(max98088_left_rec_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right REC Mixer", SND_SOC_NOPM, 0, 0,
+         &max98088_right_rec_mixer_controls[0],
+               ARRAY_SIZE(max98088_right_rec_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_left_ADC_mixer_controls[0],
+               ARRAY_SIZE(max98088_left_ADC_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_right_ADC_mixer_controls[0],
+               ARRAY_SIZE(max98088_right_ADC_mixer_controls)),
+
+       SND_SOC_DAPM_PGA_E("MIC1 Input", M98088_REG_35_LVL_MIC1,
+               5, 0, NULL, 0, max98088_mic_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("MIC2 Input", M98088_REG_36_LVL_MIC2,
+               5, 0, NULL, 0, max98088_mic_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("INA1 Input", M98088_REG_4C_PWR_EN_IN,
+               7, 0, NULL, 0, max98088_pga_ina1_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("INA2 Input", M98088_REG_4C_PWR_EN_IN,
+               7, 0, NULL, 0, max98088_pga_ina2_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("INB1 Input", M98088_REG_4C_PWR_EN_IN,
+               6, 0, NULL, 0, max98088_pga_inb1_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("INB2 Input", M98088_REG_4C_PWR_EN_IN,
+               6, 0, NULL, 0, max98088_pga_inb2_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MICBIAS("MICBIAS", M98088_REG_4C_PWR_EN_IN, 3, 0),
+
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+       SND_SOC_DAPM_OUTPUT("SPKL"),
+       SND_SOC_DAPM_OUTPUT("SPKR"),
+       SND_SOC_DAPM_OUTPUT("RECL"),
+       SND_SOC_DAPM_OUTPUT("RECR"),
+
+       SND_SOC_DAPM_INPUT("MIC1"),
+       SND_SOC_DAPM_INPUT("MIC2"),
+       SND_SOC_DAPM_INPUT("INA1"),
+       SND_SOC_DAPM_INPUT("INA2"),
+       SND_SOC_DAPM_INPUT("INB1"),
+       SND_SOC_DAPM_INPUT("INB2"),
+};
+
+static const struct snd_soc_dapm_route max98088_audio_map[] = {
+       /* Left headphone output mixer */
+       {"Left HP Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Left HP Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Left HP Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Left HP Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Left HP Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left HP Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left HP Mixer", "INA1 Switch", "INA1 Input"},
+       {"Left HP Mixer", "INA2 Switch", "INA2 Input"},
+       {"Left HP Mixer", "INB1 Switch", "INB1 Input"},
+       {"Left HP Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Right headphone output mixer */
+       {"Right HP Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Right HP Mixer", "Left DAC2 Switch", "DACL2"  },
+       {"Right HP Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Right HP Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Right HP Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right HP Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right HP Mixer", "INA1 Switch", "INA1 Input"},
+       {"Right HP Mixer", "INA2 Switch", "INA2 Input"},
+       {"Right HP Mixer", "INB1 Switch", "INB1 Input"},
+       {"Right HP Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Left speaker output mixer */
+       {"Left SPK Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Left SPK Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Left SPK Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Left SPK Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Left SPK Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left SPK Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left SPK Mixer", "INA1 Switch", "INA1 Input"},
+       {"Left SPK Mixer", "INA2 Switch", "INA2 Input"},
+       {"Left SPK Mixer", "INB1 Switch", "INB1 Input"},
+       {"Left SPK Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Right speaker output mixer */
+       {"Right SPK Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Right SPK Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Right SPK Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Right SPK Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Right SPK Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right SPK Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right SPK Mixer", "INA1 Switch", "INA1 Input"},
+       {"Right SPK Mixer", "INA2 Switch", "INA2 Input"},
+       {"Right SPK Mixer", "INB1 Switch", "INB1 Input"},
+       {"Right SPK Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Earpiece/Receiver output mixer */
+       {"Left REC Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Left REC Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Left REC Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Left REC Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Left REC Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left REC Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left REC Mixer", "INA1 Switch", "INA1 Input"},
+       {"Left REC Mixer", "INA2 Switch", "INA2 Input"},
+       {"Left REC Mixer", "INB1 Switch", "INB1 Input"},
+       {"Left REC Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Earpiece/Receiver output mixer */
+       {"Right REC Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Right REC Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Right REC Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Right REC Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Right REC Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right REC Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right REC Mixer", "INA1 Switch", "INA1 Input"},
+       {"Right REC Mixer", "INA2 Switch", "INA2 Input"},
+       {"Right REC Mixer", "INB1 Switch", "INB1 Input"},
+       {"Right REC Mixer", "INB2 Switch", "INB2 Input"},
+
+       {"HP Left Out", NULL, "Left HP Mixer"},
+       {"HP Right Out", NULL, "Right HP Mixer"},
+       {"SPK Left Out", NULL, "Left SPK Mixer"},
+       {"SPK Right Out", NULL, "Right SPK Mixer"},
+       {"REC Left Out", NULL, "Left REC Mixer"},
+       {"REC Right Out", NULL, "Right REC Mixer"},
+
+       {"HPL", NULL, "HP Left Out"},
+       {"HPR", NULL, "HP Right Out"},
+       {"SPKL", NULL, "SPK Left Out"},
+       {"SPKR", NULL, "SPK Right Out"},
+       {"RECL", NULL, "REC Left Out"},
+       {"RECR", NULL, "REC Right Out"},
+
+       /* Left ADC input mixer */
+       {"Left ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left ADC Mixer", "INA1 Switch", "INA1 Input"},
+       {"Left ADC Mixer", "INA2 Switch", "INA2 Input"},
+       {"Left ADC Mixer", "INB1 Switch", "INB1 Input"},
+       {"Left ADC Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Right ADC input mixer */
+       {"Right ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right ADC Mixer", "INA1 Switch", "INA1 Input"},
+       {"Right ADC Mixer", "INA2 Switch", "INA2 Input"},
+       {"Right ADC Mixer", "INB1 Switch", "INB1 Input"},
+       {"Right ADC Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Inputs */
+       {"ADCL", NULL, "Left ADC Mixer"},
+       {"ADCR", NULL, "Right ADC Mixer"},
+       {"INA1 Input", NULL, "INA1"},
+       {"INA2 Input", NULL, "INA2"},
+       {"INB1 Input", NULL, "INB1"},
+       {"INB2 Input", NULL, "INB2"},
+       {"MIC1 Input", NULL, "MIC1"},
+       {"MIC2 Input", NULL, "MIC2"},
+};
+
+/* codec mclk clock divider coefficients */
+static const struct {
+       u32 rate;
+       u8  sr;
+} rate_table[] = {
+       {8000,  0x10},
+       {11025, 0x20},
+       {16000, 0x30},
+       {22050, 0x40},
+       {24000, 0x50},
+       {32000, 0x60},
+       {44100, 0x70},
+       {48000, 0x80},
+       {88200, 0x90},
+       {96000, 0xA0},
+};
+
+static inline int rate_value(int rate, u8 *value)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+               if (rate_table[i].rate >= rate) {
+                       *value = rate_table[i].sr;
+                       return 0;
+               }
+       }
+       *value = rate_table[0].sr;
+       return -EINVAL;
+}
+
+static int max98088_dai1_hw_params(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_hw_params *params,
+                                  struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       struct max98088_cdata *cdata;
+       unsigned long long ni;
+       unsigned int rate;
+       u8 regval;
+
+       cdata = &max98088->dai[0];
+
+       rate = params_rate(params);
+
+       switch (params_width(params)) {
+       case 16:
+               snd_soc_component_update_bits(component, M98088_REG_14_DAI1_FORMAT,
+                       M98088_DAI_WS, 0);
+               break;
+       case 24:
+               snd_soc_component_update_bits(component, M98088_REG_14_DAI1_FORMAT,
+                       M98088_DAI_WS, M98088_DAI_WS);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_component_update_bits(component, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+
+       if (rate_value(rate, &regval))
+               return -EINVAL;
+
+       snd_soc_component_update_bits(component, M98088_REG_11_DAI1_CLKMODE,
+               M98088_CLKMODE_MASK, regval);
+       cdata->rate = rate;
+
+       /* Configure NI when operating as master */
+       if (snd_soc_component_read32(component, M98088_REG_14_DAI1_FORMAT)
+               & M98088_DAI_MAS) {
+               if (max98088->sysclk == 0) {
+                       dev_err(component->dev, "Invalid system clock frequency\n");
+                       return -EINVAL;
+               }
+               ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+                               * (unsigned long long int)rate;
+               do_div(ni, (unsigned long long int)max98088->sysclk);
+               snd_soc_component_write(component, M98088_REG_12_DAI1_CLKCFG_HI,
+                       (ni >> 8) & 0x7F);
+               snd_soc_component_write(component, M98088_REG_13_DAI1_CLKCFG_LO,
+                       ni & 0xFF);
+       }
+
+       /* Update sample rate mode */
+       if (rate < 50000)
+               snd_soc_component_update_bits(component, M98088_REG_18_DAI1_FILTERS,
+                       M98088_DAI_DHF, 0);
+       else
+               snd_soc_component_update_bits(component, M98088_REG_18_DAI1_FILTERS,
+                       M98088_DAI_DHF, M98088_DAI_DHF);
+
+       snd_soc_component_update_bits(component, M98088_REG_51_PWR_SYS, M98088_SHDNRUN,
+               M98088_SHDNRUN);
+
+       return 0;
+}
+
+static int max98088_dai2_hw_params(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_hw_params *params,
+                                  struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       struct max98088_cdata *cdata;
+       unsigned long long ni;
+       unsigned int rate;
+       u8 regval;
+
+       cdata = &max98088->dai[1];
+
+       rate = params_rate(params);
+
+       switch (params_width(params)) {
+       case 16:
+               snd_soc_component_update_bits(component, M98088_REG_1C_DAI2_FORMAT,
+                       M98088_DAI_WS, 0);
+               break;
+       case 24:
+               snd_soc_component_update_bits(component, M98088_REG_1C_DAI2_FORMAT,
+                       M98088_DAI_WS, M98088_DAI_WS);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_component_update_bits(component, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+
+       if (rate_value(rate, &regval))
+               return -EINVAL;
+
+       snd_soc_component_update_bits(component, M98088_REG_19_DAI2_CLKMODE,
+               M98088_CLKMODE_MASK, regval);
+       cdata->rate = rate;
+
+       /* Configure NI when operating as master */
+       if (snd_soc_component_read32(component, M98088_REG_1C_DAI2_FORMAT)
+               & M98088_DAI_MAS) {
+               if (max98088->sysclk == 0) {
+                       dev_err(component->dev, "Invalid system clock frequency\n");
+                       return -EINVAL;
+               }
+               ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+                               * (unsigned long long int)rate;
+               do_div(ni, (unsigned long long int)max98088->sysclk);
+               snd_soc_component_write(component, M98088_REG_1A_DAI2_CLKCFG_HI,
+                       (ni >> 8) & 0x7F);
+               snd_soc_component_write(component, M98088_REG_1B_DAI2_CLKCFG_LO,
+                       ni & 0xFF);
+       }
+
+       /* Update sample rate mode */
+       if (rate < 50000)
+               snd_soc_component_update_bits(component, M98088_REG_20_DAI2_FILTERS,
+                       M98088_DAI_DHF, 0);
+       else
+               snd_soc_component_update_bits(component, M98088_REG_20_DAI2_FILTERS,
+                       M98088_DAI_DHF, M98088_DAI_DHF);
+
+       snd_soc_component_update_bits(component, M98088_REG_51_PWR_SYS, M98088_SHDNRUN,
+               M98088_SHDNRUN);
+
+       return 0;
+}
+
+static int max98088_dai_set_sysclk(struct snd_soc_dai *dai,
+                                  int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_component *component = dai->component;
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+
+       /* Requested clock frequency is already setup */
+       if (freq == max98088->sysclk)
+               return 0;
+
+       /* Setup clocks for slave mode, and using the PLL
+        * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+        *         0x02 (when master clk is 20MHz to 30MHz)..
+        */
+       if ((freq >= 10000000) && (freq < 20000000)) {
+               snd_soc_component_write(component, M98088_REG_10_SYS_CLK, 0x10);
+       } else if ((freq >= 20000000) && (freq < 30000000)) {
+               snd_soc_component_write(component, M98088_REG_10_SYS_CLK, 0x20);
+       } else {
+               dev_err(component->dev, "Invalid master clock frequency\n");
+               return -EINVAL;
+       }
+
+       if (snd_soc_component_read32(component, M98088_REG_51_PWR_SYS)  & M98088_SHDNRUN) {
+               snd_soc_component_update_bits(component, M98088_REG_51_PWR_SYS,
+                       M98088_SHDNRUN, 0);
+               snd_soc_component_update_bits(component, M98088_REG_51_PWR_SYS,
+                       M98088_SHDNRUN, M98088_SHDNRUN);
+       }
+
+       dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+       max98088->sysclk = freq;
+       return 0;
+}
+
+static int max98088_dai1_set_fmt(struct snd_soc_dai *codec_dai,
+                                unsigned int fmt)
+{
+       struct snd_soc_component *component = codec_dai->component;
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       struct max98088_cdata *cdata;
+       u8 reg15val;
+       u8 reg14val = 0;
+
+       cdata = &max98088->dai[0];
+
+       if (fmt != cdata->fmt) {
+               cdata->fmt = fmt;
+
+               switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBS_CFS:
+                       /* Slave mode PLL */
+                       snd_soc_component_write(component, M98088_REG_12_DAI1_CLKCFG_HI,
+                               0x80);
+                       snd_soc_component_write(component, M98088_REG_13_DAI1_CLKCFG_LO,
+                               0x00);
+                       break;
+               case SND_SOC_DAIFMT_CBM_CFM:
+                       /* Set to master mode */
+                       reg14val |= M98088_DAI_MAS;
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFM:
+               case SND_SOC_DAIFMT_CBM_CFS:
+               default:
+                       dev_err(component->dev, "Clock mode unsupported");
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+               case SND_SOC_DAIFMT_I2S:
+                       reg14val |= M98088_DAI_DLY;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       reg14val |= M98088_DAI_WCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       reg14val |= M98088_DAI_BCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       reg14val |= M98088_DAI_BCI|M98088_DAI_WCI;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               snd_soc_component_update_bits(component, M98088_REG_14_DAI1_FORMAT,
+                       M98088_DAI_MAS | M98088_DAI_DLY | M98088_DAI_BCI |
+                       M98088_DAI_WCI, reg14val);
+
+               reg15val = M98088_DAI_BSEL64;
+               if (max98088->digmic)
+                       reg15val |= M98088_DAI_OSR64;
+               snd_soc_component_write(component, M98088_REG_15_DAI1_CLOCK, reg15val);
+       }
+
+       return 0;
+}
+
+static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
+                                unsigned int fmt)
+{
+       struct snd_soc_component *component = codec_dai->component;
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       struct max98088_cdata *cdata;
+       u8 reg1Cval = 0;
+
+       cdata = &max98088->dai[1];
+
+       if (fmt != cdata->fmt) {
+               cdata->fmt = fmt;
+
+               switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBS_CFS:
+                       /* Slave mode PLL */
+                       snd_soc_component_write(component, M98088_REG_1A_DAI2_CLKCFG_HI,
+                               0x80);
+                       snd_soc_component_write(component, M98088_REG_1B_DAI2_CLKCFG_LO,
+                               0x00);
+                       break;
+               case SND_SOC_DAIFMT_CBM_CFM:
+                       /* Set to master mode */
+                       reg1Cval |= M98088_DAI_MAS;
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFM:
+               case SND_SOC_DAIFMT_CBM_CFS:
+               default:
+                       dev_err(component->dev, "Clock mode unsupported");
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+               case SND_SOC_DAIFMT_I2S:
+                       reg1Cval |= M98088_DAI_DLY;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       reg1Cval |= M98088_DAI_WCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       reg1Cval |= M98088_DAI_BCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       reg1Cval |= M98088_DAI_BCI|M98088_DAI_WCI;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               snd_soc_component_update_bits(component, M98088_REG_1C_DAI2_FORMAT,
+                       M98088_DAI_MAS | M98088_DAI_DLY | M98088_DAI_BCI |
+                       M98088_DAI_WCI, reg1Cval);
+
+               snd_soc_component_write(component, M98088_REG_1D_DAI2_CLOCK,
+                       M98088_DAI_BSEL64);
+       }
+
+       return 0;
+}
+
+static int max98088_dai1_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_component *component = codec_dai->component;
+       int reg;
+
+       if (mute)
+               reg = M98088_DAI_MUTE;
+       else
+               reg = 0;
+
+       snd_soc_component_update_bits(component, M98088_REG_2F_LVL_DAI1_PLAY,
+                           M98088_DAI_MUTE_MASK, reg);
+       return 0;
+}
+
+static int max98088_dai2_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_component *component = codec_dai->component;
+       int reg;
+
+       if (mute)
+               reg = M98088_DAI_MUTE;
+       else
+               reg = 0;
+
+       snd_soc_component_update_bits(component, M98088_REG_31_LVL_DAI2_PLAY,
+                           M98088_DAI_MUTE_MASK, reg);
+       return 0;
+}
+
+static int max98088_set_bias_level(struct snd_soc_component *component,
+                                  enum snd_soc_bias_level level)
+{
+	struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			regcache_sync(max98088->regmap);
+
+		snd_soc_component_update_bits(component, M98088_REG_4C_PWR_EN_IN,
+				   M98088_MBEN, M98088_MBEN);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, M98088_REG_4C_PWR_EN_IN,
+				    M98088_MBEN, 0);
+		regcache_mark_dirty(max98088->regmap);
+		break;
+	}
+	return 0;
+}
+
+#define MAX98088_RATES SNDRV_PCM_RATE_8000_96000
+#define MAX98088_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops max98088_dai1_ops = {
+       .set_sysclk = max98088_dai_set_sysclk,
+       .set_fmt = max98088_dai1_set_fmt,
+       .hw_params = max98088_dai1_hw_params,
+       .digital_mute = max98088_dai1_digital_mute,
+};
+
+static const struct snd_soc_dai_ops max98088_dai2_ops = {
+       .set_sysclk = max98088_dai_set_sysclk,
+       .set_fmt = max98088_dai2_set_fmt,
+       .hw_params = max98088_dai2_hw_params,
+       .digital_mute = max98088_dai2_digital_mute,
+};
+
+static struct snd_soc_dai_driver max98088_dai[] = {
+{
+       .name = "HiFi",
+       .playback = {
+               .stream_name = "HiFi Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = MAX98088_RATES,
+               .formats = MAX98088_FORMATS,
+       },
+       .capture = {
+               .stream_name = "HiFi Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = MAX98088_RATES,
+               .formats = MAX98088_FORMATS,
+       },
+        .ops = &max98088_dai1_ops,
+},
+{
+       .name = "Aux",
+       .playback = {
+               .stream_name = "Aux Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = MAX98088_RATES,
+               .formats = MAX98088_FORMATS,
+       },
+       .ops = &max98088_dai2_ops,
+}
+};
+
+static const char *eq_mode_name[] = {"EQ1 Mode", "EQ2 Mode"};
+
+static int max98088_get_channel(struct snd_soc_component *component, const char *name)
+{
+	int ret;
+
+	ret = match_string(eq_mode_name, ARRAY_SIZE(eq_mode_name), name);
+	if (ret < 0)
+		dev_err(component->dev, "Bad EQ channel name '%s'\n", name);
+	return ret;
+}
+
+static void max98088_setup_eq1(struct snd_soc_component *component)
+{
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       struct max98088_pdata *pdata = max98088->pdata;
+       struct max98088_eq_cfg *coef_set;
+       int best, best_val, save, i, sel, fs;
+       struct max98088_cdata *cdata;
+
+       cdata = &max98088->dai[0];
+
+       if (!pdata || !max98088->eq_textcnt)
+               return;
+
+       /* Find the selected configuration with nearest sample rate */
+       fs = cdata->rate;
+       sel = cdata->eq_sel;
+
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < pdata->eq_cfgcnt; i++) {
+               if (strcmp(pdata->eq_cfg[i].name, max98088->eq_texts[sel]) == 0 &&
+                   abs(pdata->eq_cfg[i].rate - fs) < best_val) {
+                       best = i;
+                       best_val = abs(pdata->eq_cfg[i].rate - fs);
+               }
+       }
+
+       dev_dbg(component->dev, "Selected %s/%dHz for %dHz sample rate\n",
+               pdata->eq_cfg[best].name,
+               pdata->eq_cfg[best].rate, fs);
+
+       /* Disable EQ while configuring, and save current on/off state */
+       save = snd_soc_component_read32(component, M98088_REG_49_CFG_LEVEL);
+       snd_soc_component_update_bits(component, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, 0);
+
+       coef_set = &pdata->eq_cfg[sel];
+
+       m98088_eq_band(component, 0, 0, coef_set->band1);
+       m98088_eq_band(component, 0, 1, coef_set->band2);
+       m98088_eq_band(component, 0, 2, coef_set->band3);
+       m98088_eq_band(component, 0, 3, coef_set->band4);
+       m98088_eq_band(component, 0, 4, coef_set->band5);
+
+       /* Restore the original on/off state */
+       snd_soc_component_update_bits(component, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, save);
+}
+
+static void max98088_setup_eq2(struct snd_soc_component *component)
+{
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       struct max98088_pdata *pdata = max98088->pdata;
+       struct max98088_eq_cfg *coef_set;
+       int best, best_val, save, i, sel, fs;
+       struct max98088_cdata *cdata;
+
+       cdata = &max98088->dai[1];
+
+       if (!pdata || !max98088->eq_textcnt)
+               return;
+
+       /* Find the selected configuration with nearest sample rate */
+       fs = cdata->rate;
+
+       sel = cdata->eq_sel;
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < pdata->eq_cfgcnt; i++) {
+               if (strcmp(pdata->eq_cfg[i].name, max98088->eq_texts[sel]) == 0 &&
+                   abs(pdata->eq_cfg[i].rate - fs) < best_val) {
+                       best = i;
+                       best_val = abs(pdata->eq_cfg[i].rate - fs);
+               }
+       }
+
+       dev_dbg(component->dev, "Selected %s/%dHz for %dHz sample rate\n",
+               pdata->eq_cfg[best].name,
+               pdata->eq_cfg[best].rate, fs);
+
+       /* Disable EQ while configuring, and save current on/off state */
+       save = snd_soc_component_read32(component, M98088_REG_49_CFG_LEVEL);
+       snd_soc_component_update_bits(component, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN, 0);
+
+       coef_set = &pdata->eq_cfg[sel];
+
+       m98088_eq_band(component, 1, 0, coef_set->band1);
+       m98088_eq_band(component, 1, 1, coef_set->band2);
+       m98088_eq_band(component, 1, 2, coef_set->band3);
+       m98088_eq_band(component, 1, 3, coef_set->band4);
+       m98088_eq_band(component, 1, 4, coef_set->band5);
+
+       /* Restore the original on/off state */
+       snd_soc_component_update_bits(component, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN,
+               save);
+}
+
+static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       struct max98088_pdata *pdata = max98088->pdata;
+       int channel = max98088_get_channel(component, kcontrol->id.name);
+       struct max98088_cdata *cdata;
+	int sel = ucontrol->value.enumerated.item[0];
+
+       if (channel < 0)
+	       return channel;
+
+       cdata = &max98088->dai[channel];
+
+       if (sel >= pdata->eq_cfgcnt)
+               return -EINVAL;
+
+       cdata->eq_sel = sel;
+
+       switch (channel) {
+       case 0:
+               max98088_setup_eq1(component);
+               break;
+       case 1:
+               max98088_setup_eq2(component);
+               break;
+       }
+
+       return 0;
+}
+
+static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       int channel = max98088_get_channel(component, kcontrol->id.name);
+       struct max98088_cdata *cdata;
+
+       if (channel < 0)
+	       return channel;
+
+       cdata = &max98088->dai[channel];
+       ucontrol->value.enumerated.item[0] = cdata->eq_sel;
+       return 0;
+}
+
+static void max98088_handle_eq_pdata(struct snd_soc_component *component)
+{
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       struct max98088_pdata *pdata = max98088->pdata;
+       struct max98088_eq_cfg *cfg;
+       unsigned int cfgcnt;
+       int i, j;
+       const char **t;
+       int ret;
+       struct snd_kcontrol_new controls[] = {
+               SOC_ENUM_EXT((char *)eq_mode_name[0],
+                       max98088->eq_enum,
+                       max98088_get_eq_enum,
+                       max98088_put_eq_enum),
+               SOC_ENUM_EXT((char *)eq_mode_name[1],
+                       max98088->eq_enum,
+                       max98088_get_eq_enum,
+                       max98088_put_eq_enum),
+       };
+       BUILD_BUG_ON(ARRAY_SIZE(controls) != ARRAY_SIZE(eq_mode_name));
+
+       cfg = pdata->eq_cfg;
+       cfgcnt = pdata->eq_cfgcnt;
+
+       /* Setup an array of texts for the equalizer enum.
+        * This is based on Mark Brown's equalizer driver code.
+        */
+       max98088->eq_textcnt = 0;
+       max98088->eq_texts = NULL;
+       for (i = 0; i < cfgcnt; i++) {
+               for (j = 0; j < max98088->eq_textcnt; j++) {
+                       if (strcmp(cfg[i].name, max98088->eq_texts[j]) == 0)
+                               break;
+               }
+
+               if (j != max98088->eq_textcnt)
+                       continue;
+
+               /* Expand the array */
+               t = krealloc(max98088->eq_texts,
+                            sizeof(char *) * (max98088->eq_textcnt + 1),
+                            GFP_KERNEL);
+               if (t == NULL)
+                       continue;
+
+               /* Store the new entry */
+               t[max98088->eq_textcnt] = cfg[i].name;
+               max98088->eq_textcnt++;
+               max98088->eq_texts = t;
+       }
+
+       /* Now point the soc_enum to .texts array items */
+       max98088->eq_enum.texts = max98088->eq_texts;
+       max98088->eq_enum.items = max98088->eq_textcnt;
+
+       ret = snd_soc_add_component_controls(component, controls, ARRAY_SIZE(controls));
+       if (ret != 0)
+               dev_err(component->dev, "Failed to add EQ control: %d\n", ret);
+}
+
+static void max98088_handle_pdata(struct snd_soc_component *component)
+{
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       struct max98088_pdata *pdata = max98088->pdata;
+       u8 regval = 0;
+
+       if (!pdata) {
+               dev_dbg(component->dev, "No platform data\n");
+               return;
+       }
+
+       /* Configure mic for analog/digital mic mode */
+       if (pdata->digmic_left_mode)
+               regval |= M98088_DIGMIC_L;
+
+       if (pdata->digmic_right_mode)
+               regval |= M98088_DIGMIC_R;
+
+       max98088->digmic = (regval ? 1 : 0);
+
+       snd_soc_component_write(component, M98088_REG_48_CFG_MIC, regval);
+
+       /* Configure receiver output */
+       regval = ((pdata->receiver_mode) ? M98088_REC_LINEMODE : 0);
+       snd_soc_component_update_bits(component, M98088_REG_2A_MIC_REC_CNTL,
+               M98088_REC_LINEMODE_MASK, regval);
+
+       /* Configure equalizers */
+       if (pdata->eq_cfgcnt)
+               max98088_handle_eq_pdata(component);
+}
+
+static int max98088_probe(struct snd_soc_component *component)
+{
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+       struct max98088_cdata *cdata;
+       int ret = 0;
+
+       regcache_mark_dirty(max98088->regmap);
+
+       /* initialize private data */
+
+       max98088->sysclk = (unsigned)-1;
+       max98088->eq_textcnt = 0;
+
+       cdata = &max98088->dai[0];
+       cdata->rate = (unsigned)-1;
+       cdata->fmt  = (unsigned)-1;
+       cdata->eq_sel = 0;
+
+       cdata = &max98088->dai[1];
+       cdata->rate = (unsigned)-1;
+       cdata->fmt  = (unsigned)-1;
+       cdata->eq_sel = 0;
+
+       max98088->ina_state = 0;
+       max98088->inb_state = 0;
+       max98088->ex_mode = 0;
+       max98088->digmic = 0;
+       max98088->mic1pre = 0;
+       max98088->mic2pre = 0;
+
+       ret = snd_soc_component_read32(component, M98088_REG_FF_REV_ID);
+       if (ret < 0) {
+               dev_err(component->dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_access;
+       }
+       dev_info(component->dev, "revision %c\n", ret - 0x40 + 'A');
+
+       snd_soc_component_write(component, M98088_REG_51_PWR_SYS, M98088_PWRSV);
+
+       snd_soc_component_write(component, M98088_REG_0F_IRQ_ENABLE, 0x00);
+
+       snd_soc_component_write(component, M98088_REG_22_MIX_DAC,
+               M98088_DAI1L_TO_DACL|M98088_DAI2L_TO_DACL|
+               M98088_DAI1R_TO_DACR|M98088_DAI2R_TO_DACR);
+
+       snd_soc_component_write(component, M98088_REG_4E_BIAS_CNTL, 0xF0);
+       snd_soc_component_write(component, M98088_REG_50_DAC_BIAS2, 0x0F);
+
+       snd_soc_component_write(component, M98088_REG_16_DAI1_IOCFG,
+               M98088_S1NORMAL|M98088_SDATA);
+
+       snd_soc_component_write(component, M98088_REG_1E_DAI2_IOCFG,
+               M98088_S2NORMAL|M98088_SDATA);
+
+       max98088_handle_pdata(component);
+
+err_access:
+       return ret;
+}
+
+static void max98088_remove(struct snd_soc_component *component)
+{
+       struct max98088_priv *max98088 = snd_soc_component_get_drvdata(component);
+
+       kfree(max98088->eq_texts);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_max98088 = {
+	.probe			= max98088_probe,
+	.remove			= max98088_remove,
+	.set_bias_level		= max98088_set_bias_level,
+	.controls		= max98088_snd_controls,
+	.num_controls		= ARRAY_SIZE(max98088_snd_controls),
+	.dapm_widgets		= max98088_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98088_dapm_widgets),
+	.dapm_routes		= max98088_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max98088_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int max98088_i2c_probe(struct i2c_client *i2c,
+			      const struct i2c_device_id *id)
+{
+       struct max98088_priv *max98088;
+       int ret;
+
+       max98088 = devm_kzalloc(&i2c->dev, sizeof(struct max98088_priv),
+			       GFP_KERNEL);
+       if (max98088 == NULL)
+               return -ENOMEM;
+
+       max98088->regmap = devm_regmap_init_i2c(i2c, &max98088_regmap);
+       if (IS_ERR(max98088->regmap))
+	       return PTR_ERR(max98088->regmap);
+
+       max98088->devtype = id->driver_data;
+
+       i2c_set_clientdata(i2c, max98088);
+       max98088->pdata = i2c->dev.platform_data;
+
+       ret = devm_snd_soc_register_component(&i2c->dev,
+                       &soc_component_dev_max98088, &max98088_dai[0], 2);
+       return ret;
+}
+
+static const struct i2c_device_id max98088_i2c_id[] = {
+       { "max98088", MAX98088 },
+       { "max98089", MAX98089 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
+
+static struct i2c_driver max98088_i2c_driver = {
+	.driver = {
+		.name = "max98088",
+	},
+	.probe  = max98088_i2c_probe,
+	.id_table = max98088_i2c_id,
+};
+
+module_i2c_driver(max98088_i2c_driver);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98088 driver");
+MODULE_AUTHOR("Peter Hsiang, Jesse Marroquin");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98088.h b/sound/soc/codecs/max98088.h
new file mode 100644
index 0000000..efa39bf
--- /dev/null
+++ b/sound/soc/codecs/max98088.h
@@ -0,0 +1,206 @@
+/*
+ * max98088.h -- MAX98088 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX98088_H
+#define _MAX98088_H
+
+/*
+ * MAX98088 Registers Definition
+ */
+#define M98088_REG_00_IRQ_STATUS            0x00
+#define M98088_REG_01_MIC_STATUS            0x01
+#define M98088_REG_02_JACK_STATUS           0x02
+#define M98088_REG_03_BATTERY_VOLTAGE       0x03
+#define M98088_REG_0F_IRQ_ENABLE            0x0F
+#define M98088_REG_10_SYS_CLK               0x10
+#define M98088_REG_11_DAI1_CLKMODE          0x11
+#define M98088_REG_12_DAI1_CLKCFG_HI        0x12
+#define M98088_REG_13_DAI1_CLKCFG_LO        0x13
+#define M98088_REG_14_DAI1_FORMAT           0x14
+#define M98088_REG_15_DAI1_CLOCK            0x15
+#define M98088_REG_16_DAI1_IOCFG            0x16
+#define M98088_REG_17_DAI1_TDM              0x17
+#define M98088_REG_18_DAI1_FILTERS          0x18
+#define M98088_REG_19_DAI2_CLKMODE          0x19
+#define M98088_REG_1A_DAI2_CLKCFG_HI        0x1A
+#define M98088_REG_1B_DAI2_CLKCFG_LO        0x1B
+#define M98088_REG_1C_DAI2_FORMAT           0x1C
+#define M98088_REG_1D_DAI2_CLOCK            0x1D
+#define M98088_REG_1E_DAI2_IOCFG            0x1E
+#define M98088_REG_1F_DAI2_TDM              0x1F
+#define M98088_REG_20_DAI2_FILTERS          0x20
+#define M98088_REG_21_SRC                   0x21
+#define M98088_REG_22_MIX_DAC               0x22
+#define M98088_REG_23_MIX_ADC_LEFT          0x23
+#define M98088_REG_24_MIX_ADC_RIGHT         0x24
+#define M98088_REG_25_MIX_HP_LEFT           0x25
+#define M98088_REG_26_MIX_HP_RIGHT          0x26
+#define M98088_REG_27_MIX_HP_CNTL           0x27
+#define M98088_REG_28_MIX_REC_LEFT          0x28
+#define M98088_REG_29_MIX_REC_RIGHT         0x29
+#define M98088_REG_2A_MIC_REC_CNTL          0x2A
+#define M98088_REG_2B_MIX_SPK_LEFT          0x2B
+#define M98088_REG_2C_MIX_SPK_RIGHT         0x2C
+#define M98088_REG_2D_MIX_SPK_CNTL          0x2D
+#define M98088_REG_2E_LVL_SIDETONE          0x2E
+#define M98088_REG_2F_LVL_DAI1_PLAY         0x2F
+#define M98088_REG_30_LVL_DAI1_PLAY_EQ      0x30
+#define M98088_REG_31_LVL_DAI2_PLAY         0x31
+#define M98088_REG_32_LVL_DAI2_PLAY_EQ      0x32
+#define M98088_REG_33_LVL_ADC_L             0x33
+#define M98088_REG_34_LVL_ADC_R             0x34
+#define M98088_REG_35_LVL_MIC1              0x35
+#define M98088_REG_36_LVL_MIC2              0x36
+#define M98088_REG_37_LVL_INA               0x37
+#define M98088_REG_38_LVL_INB               0x38
+#define M98088_REG_39_LVL_HP_L              0x39
+#define M98088_REG_3A_LVL_HP_R              0x3A
+#define M98088_REG_3B_LVL_REC_L             0x3B
+#define M98088_REG_3C_LVL_REC_R             0x3C
+#define M98088_REG_3D_LVL_SPK_L             0x3D
+#define M98088_REG_3E_LVL_SPK_R             0x3E
+#define M98088_REG_3F_MICAGC_CFG            0x3F
+#define M98088_REG_40_MICAGC_THRESH         0x40
+#define M98088_REG_41_SPKDHP                0x41
+#define M98088_REG_42_SPKDHP_THRESH         0x42
+#define M98088_REG_43_SPKALC_COMP           0x43
+#define M98088_REG_44_PWRLMT_CFG            0x44
+#define M98088_REG_45_PWRLMT_TIME           0x45
+#define M98088_REG_46_THDLMT_CFG            0x46
+#define M98088_REG_47_CFG_AUDIO_IN          0x47
+#define M98088_REG_48_CFG_MIC               0x48
+#define M98088_REG_49_CFG_LEVEL             0x49
+#define M98088_REG_4A_CFG_BYPASS            0x4A
+#define M98088_REG_4B_CFG_JACKDET           0x4B
+#define M98088_REG_4C_PWR_EN_IN             0x4C
+#define M98088_REG_4D_PWR_EN_OUT            0x4D
+#define M98088_REG_4E_BIAS_CNTL             0x4E
+#define M98088_REG_4F_DAC_BIAS1             0x4F
+#define M98088_REG_50_DAC_BIAS2             0x50
+#define M98088_REG_51_PWR_SYS               0x51
+#define M98088_REG_52_DAI1_EQ_BASE          0x52
+#define M98088_REG_84_DAI2_EQ_BASE          0x84
+#define M98088_REG_B6_DAI1_BIQUAD_BASE      0xB6
+#define M98088_REG_C0_DAI2_BIQUAD_BASE      0xC0
+#define M98088_REG_FF_REV_ID                0xFF
+
+#define M98088_REG_CNT                      (0xFF+1)
+
+/* MAX98088 Registers Bit Fields */
+
+/* M98088_REG_11_DAI1_CLKMODE, M98088_REG_19_DAI2_CLKMODE */
+       #define M98088_CLKMODE_MASK             0xFF
+
+/* M98088_REG_14_DAI1_FORMAT, M98088_REG_1C_DAI2_FORMAT */
+       #define M98088_DAI_MAS                  (1<<7)
+       #define M98088_DAI_WCI                  (1<<6)
+       #define M98088_DAI_BCI                  (1<<5)
+       #define M98088_DAI_DLY                  (1<<4)
+       #define M98088_DAI_TDM                  (1<<2)
+       #define M98088_DAI_FSW                  (1<<1)
+       #define M98088_DAI_WS                   (1<<0)
+
+/* M98088_REG_15_DAI1_CLOCK, M98088_REG_1D_DAI2_CLOCK */
+       #define M98088_DAI_BSEL64               (1<<0)
+       #define M98088_DAI_OSR64                (1<<6)
+
+/* M98088_REG_16_DAI1_IOCFG, M98088_REG_1E_DAI2_IOCFG */
+       #define M98088_S1NORMAL                 (1<<6)
+       #define M98088_S2NORMAL                 (2<<6)
+       #define M98088_SDATA                    (3<<0)
+
+/* M98088_REG_18_DAI1_FILTERS, M98088_REG_20_DAI2_FILTERS */
+       #define M98088_DAI_DHF                  (1<<3)
+
+/* M98088_REG_22_MIX_DAC */
+       #define M98088_DAI1L_TO_DACL            (1<<7)
+       #define M98088_DAI1R_TO_DACL            (1<<6)
+       #define M98088_DAI2L_TO_DACL            (1<<5)
+       #define M98088_DAI2R_TO_DACL            (1<<4)
+       #define M98088_DAI1L_TO_DACR            (1<<3)
+       #define M98088_DAI1R_TO_DACR            (1<<2)
+       #define M98088_DAI2L_TO_DACR            (1<<1)
+       #define M98088_DAI2R_TO_DACR            (1<<0)
+
+/* M98088_REG_2A_MIC_REC_CNTL */
+       #define M98088_REC_LINEMODE             (1<<7)
+       #define M98088_REC_LINEMODE_MASK        (1<<7)
+
+/* M98088_REG_2D_MIX_SPK_CNTL */
+       #define M98088_MIX_SPKR_GAIN_MASK       (3<<2)
+       #define M98088_MIX_SPKR_GAIN_SHIFT      2
+       #define M98088_MIX_SPKL_GAIN_MASK       (3<<0)
+       #define M98088_MIX_SPKL_GAIN_SHIFT      0
+
+/* M98088_REG_2F_LVL_DAI1_PLAY, M98088_REG_31_LVL_DAI2_PLAY */
+       #define M98088_DAI_MUTE                 (1<<7)
+       #define M98088_DAI_MUTE_MASK            (1<<7)
+       #define M98088_DAI_VOICE_GAIN_MASK      (3<<4)
+       #define M98088_DAI_ATTENUATION_MASK     (0xF<<0)
+       #define M98088_DAI_ATTENUATION_SHIFT    0
+
+/* M98088_REG_35_LVL_MIC1, M98088_REG_36_LVL_MIC2 */
+       #define M98088_MICPRE_MASK              (3<<5)
+       #define M98088_MICPRE_SHIFT             5
+
+/* M98088_REG_3A_LVL_HP_R */
+       #define M98088_HP_MUTE                  (1<<7)
+
+/* M98088_REG_3C_LVL_REC_R */
+       #define M98088_REC_MUTE                 (1<<7)
+
+/* M98088_REG_3E_LVL_SPK_R */
+       #define M98088_SP_MUTE                  (1<<7)
+
+/* M98088_REG_48_CFG_MIC */
+       #define M98088_EXTMIC_MASK              (3<<0)
+       #define M98088_DIGMIC_L                 (1<<5)
+       #define M98088_DIGMIC_R                 (1<<4)
+
+/* M98088_REG_49_CFG_LEVEL */
+       #define M98088_VSEN                     (1<<6)
+       #define M98088_ZDEN                     (1<<5)
+       #define M98088_EQ2EN                    (1<<1)
+       #define M98088_EQ1EN                    (1<<0)
+
+/* M98088_REG_4C_PWR_EN_IN */
+       #define M98088_INAEN                    (1<<7)
+       #define M98088_INBEN                    (1<<6)
+       #define M98088_MBEN                     (1<<3)
+       #define M98088_ADLEN                    (1<<1)
+       #define M98088_ADREN                    (1<<0)
+
+/* M98088_REG_4D_PWR_EN_OUT */
+       #define M98088_HPLEN                    (1<<7)
+       #define M98088_HPREN                    (1<<6)
+       #define M98088_HPEN                     ((1<<7)|(1<<6))
+       #define M98088_SPLEN                    (1<<5)
+       #define M98088_SPREN                    (1<<4)
+       #define M98088_RECEN                    (1<<3)
+       #define M98088_DALEN                    (1<<1)
+       #define M98088_DAREN                    (1<<0)
+
+/* M98088_REG_51_PWR_SYS */
+       #define M98088_SHDNRUN                  (1<<7)
+       #define M98088_PERFMODE                 (1<<3)
+       #define M98088_HPPLYBACK                (1<<2)
+       #define M98088_PWRSV8K                  (1<<1)
+       #define M98088_PWRSV                    (1<<0)
+
+/* Line inputs */
+#define LINE_INA  0
+#define LINE_INB  1
+
+#define M98088_COEFS_PER_BAND               5
+
+#define M98088_BYTE1(w) ((w >> 8) & 0xff)
+#define M98088_BYTE0(w) (w & 0xff)
+
+#endif
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
new file mode 100644
index 0000000..c97f218
--- /dev/null
+++ b/sound/soc/codecs/max98090.c
@@ -0,0 +1,2696 @@
+/*
+ * max98090.c -- MAX98090 ALSA SoC Audio driver
+ *
+ * Copyright 2011-2012 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/max98090.h>
+#include "max98090.h"
+
+/* Allows for sparsely populated register maps */
+static const struct reg_default max98090_reg[] = {
+	{ 0x00, 0x00 }, /* 00 Software Reset */
+	{ 0x03, 0x04 }, /* 03 Interrupt Masks */
+	{ 0x04, 0x00 }, /* 04 System Clock Quick */
+	{ 0x05, 0x00 }, /* 05 Sample Rate Quick */
+	{ 0x06, 0x00 }, /* 06 DAI Interface Quick */
+	{ 0x07, 0x00 }, /* 07 DAC Path Quick */
+	{ 0x08, 0x00 }, /* 08 Mic/Direct to ADC Quick */
+	{ 0x09, 0x00 }, /* 09 Line to ADC Quick */
+	{ 0x0A, 0x00 }, /* 0A Analog Mic Loop Quick */
+	{ 0x0B, 0x00 }, /* 0B Analog Line Loop Quick */
+	{ 0x0C, 0x00 }, /* 0C Reserved */
+	{ 0x0D, 0x00 }, /* 0D Input Config */
+	{ 0x0E, 0x1B }, /* 0E Line Input Level */
+	{ 0x0F, 0x00 }, /* 0F Line Config */
+
+	{ 0x10, 0x14 }, /* 10 Mic1 Input Level */
+	{ 0x11, 0x14 }, /* 11 Mic2 Input Level */
+	{ 0x12, 0x00 }, /* 12 Mic Bias Voltage */
+	{ 0x13, 0x00 }, /* 13 Digital Mic Config */
+	{ 0x14, 0x00 }, /* 14 Digital Mic Mode */
+	{ 0x15, 0x00 }, /* 15 Left ADC Mixer */
+	{ 0x16, 0x00 }, /* 16 Right ADC Mixer */
+	{ 0x17, 0x03 }, /* 17 Left ADC Level */
+	{ 0x18, 0x03 }, /* 18 Right ADC Level */
+	{ 0x19, 0x00 }, /* 19 ADC Biquad Level */
+	{ 0x1A, 0x00 }, /* 1A ADC Sidetone */
+	{ 0x1B, 0x00 }, /* 1B System Clock */
+	{ 0x1C, 0x00 }, /* 1C Clock Mode */
+	{ 0x1D, 0x00 }, /* 1D Any Clock 1 */
+	{ 0x1E, 0x00 }, /* 1E Any Clock 2 */
+	{ 0x1F, 0x00 }, /* 1F Any Clock 3 */
+
+	{ 0x20, 0x00 }, /* 20 Any Clock 4 */
+	{ 0x21, 0x00 }, /* 21 Master Mode */
+	{ 0x22, 0x00 }, /* 22 Interface Format */
+	{ 0x23, 0x00 }, /* 23 TDM Format 1*/
+	{ 0x24, 0x00 }, /* 24 TDM Format 2*/
+	{ 0x25, 0x00 }, /* 25 I/O Configuration */
+	{ 0x26, 0x80 }, /* 26 Filter Config */
+	{ 0x27, 0x00 }, /* 27 DAI Playback Level */
+	{ 0x28, 0x00 }, /* 28 EQ Playback Level */
+	{ 0x29, 0x00 }, /* 29 Left HP Mixer */
+	{ 0x2A, 0x00 }, /* 2A Right HP Mixer */
+	{ 0x2B, 0x00 }, /* 2B HP Control */
+	{ 0x2C, 0x1A }, /* 2C Left HP Volume */
+	{ 0x2D, 0x1A }, /* 2D Right HP Volume */
+	{ 0x2E, 0x00 }, /* 2E Left Spk Mixer */
+	{ 0x2F, 0x00 }, /* 2F Right Spk Mixer */
+
+	{ 0x30, 0x00 }, /* 30 Spk Control */
+	{ 0x31, 0x2C }, /* 31 Left Spk Volume */
+	{ 0x32, 0x2C }, /* 32 Right Spk Volume */
+	{ 0x33, 0x00 }, /* 33 ALC Timing */
+	{ 0x34, 0x00 }, /* 34 ALC Compressor */
+	{ 0x35, 0x00 }, /* 35 ALC Expander */
+	{ 0x36, 0x00 }, /* 36 ALC Gain */
+	{ 0x37, 0x00 }, /* 37 Rcv/Line OutL Mixer */
+	{ 0x38, 0x00 }, /* 38 Rcv/Line OutL Control */
+	{ 0x39, 0x15 }, /* 39 Rcv/Line OutL Volume */
+	{ 0x3A, 0x00 }, /* 3A Line OutR Mixer */
+	{ 0x3B, 0x00 }, /* 3B Line OutR Control */
+	{ 0x3C, 0x15 }, /* 3C Line OutR Volume */
+	{ 0x3D, 0x00 }, /* 3D Jack Detect */
+	{ 0x3E, 0x00 }, /* 3E Input Enable */
+	{ 0x3F, 0x00 }, /* 3F Output Enable */
+
+	{ 0x40, 0x00 }, /* 40 Level Control */
+	{ 0x41, 0x00 }, /* 41 DSP Filter Enable */
+	{ 0x42, 0x00 }, /* 42 Bias Control */
+	{ 0x43, 0x00 }, /* 43 DAC Control */
+	{ 0x44, 0x06 }, /* 44 ADC Control */
+	{ 0x45, 0x00 }, /* 45 Device Shutdown */
+	{ 0x46, 0x00 }, /* 46 Equalizer Band 1 Coefficient B0 */
+	{ 0x47, 0x00 }, /* 47 Equalizer Band 1 Coefficient B0 */
+	{ 0x48, 0x00 }, /* 48 Equalizer Band 1 Coefficient B0 */
+	{ 0x49, 0x00 }, /* 49 Equalizer Band 1 Coefficient B1 */
+	{ 0x4A, 0x00 }, /* 4A Equalizer Band 1 Coefficient B1 */
+	{ 0x4B, 0x00 }, /* 4B Equalizer Band 1 Coefficient B1 */
+	{ 0x4C, 0x00 }, /* 4C Equalizer Band 1 Coefficient B2 */
+	{ 0x4D, 0x00 }, /* 4D Equalizer Band 1 Coefficient B2 */
+	{ 0x4E, 0x00 }, /* 4E Equalizer Band 1 Coefficient B2 */
+	{ 0x4F, 0x00 }, /* 4F Equalizer Band 1 Coefficient A1 */
+
+	{ 0x50, 0x00 }, /* 50 Equalizer Band 1 Coefficient A1 */
+	{ 0x51, 0x00 }, /* 51 Equalizer Band 1 Coefficient A1 */
+	{ 0x52, 0x00 }, /* 52 Equalizer Band 1 Coefficient A2 */
+	{ 0x53, 0x00 }, /* 53 Equalizer Band 1 Coefficient A2 */
+	{ 0x54, 0x00 }, /* 54 Equalizer Band 1 Coefficient A2 */
+	{ 0x55, 0x00 }, /* 55 Equalizer Band 2 Coefficient B0 */
+	{ 0x56, 0x00 }, /* 56 Equalizer Band 2 Coefficient B0 */
+	{ 0x57, 0x00 }, /* 57 Equalizer Band 2 Coefficient B0 */
+	{ 0x58, 0x00 }, /* 58 Equalizer Band 2 Coefficient B1 */
+	{ 0x59, 0x00 }, /* 59 Equalizer Band 2 Coefficient B1 */
+	{ 0x5A, 0x00 }, /* 5A Equalizer Band 2 Coefficient B1 */
+	{ 0x5B, 0x00 }, /* 5B Equalizer Band 2 Coefficient B2 */
+	{ 0x5C, 0x00 }, /* 5C Equalizer Band 2 Coefficient B2 */
+	{ 0x5D, 0x00 }, /* 5D Equalizer Band 2 Coefficient B2 */
+	{ 0x5E, 0x00 }, /* 5E Equalizer Band 2 Coefficient A1 */
+	{ 0x5F, 0x00 }, /* 5F Equalizer Band 2 Coefficient A1 */
+
+	{ 0x60, 0x00 }, /* 60 Equalizer Band 2 Coefficient A1 */
+	{ 0x61, 0x00 }, /* 61 Equalizer Band 2 Coefficient A2 */
+	{ 0x62, 0x00 }, /* 62 Equalizer Band 2 Coefficient A2 */
+	{ 0x63, 0x00 }, /* 63 Equalizer Band 2 Coefficient A2 */
+	{ 0x64, 0x00 }, /* 64 Equalizer Band 3 Coefficient B0 */
+	{ 0x65, 0x00 }, /* 65 Equalizer Band 3 Coefficient B0 */
+	{ 0x66, 0x00 }, /* 66 Equalizer Band 3 Coefficient B0 */
+	{ 0x67, 0x00 }, /* 67 Equalizer Band 3 Coefficient B1 */
+	{ 0x68, 0x00 }, /* 68 Equalizer Band 3 Coefficient B1 */
+	{ 0x69, 0x00 }, /* 69 Equalizer Band 3 Coefficient B1 */
+	{ 0x6A, 0x00 }, /* 6A Equalizer Band 3 Coefficient B2 */
+	{ 0x6B, 0x00 }, /* 6B Equalizer Band 3 Coefficient B2 */
+	{ 0x6C, 0x00 }, /* 6C Equalizer Band 3 Coefficient B2 */
+	{ 0x6D, 0x00 }, /* 6D Equalizer Band 3 Coefficient A1 */
+	{ 0x6E, 0x00 }, /* 6E Equalizer Band 3 Coefficient A1 */
+	{ 0x6F, 0x00 }, /* 6F Equalizer Band 3 Coefficient A1 */
+
+	{ 0x70, 0x00 }, /* 70 Equalizer Band 3 Coefficient A2 */
+	{ 0x71, 0x00 }, /* 71 Equalizer Band 3 Coefficient A2 */
+	{ 0x72, 0x00 }, /* 72 Equalizer Band 3 Coefficient A2 */
+	{ 0x73, 0x00 }, /* 73 Equalizer Band 4 Coefficient B0 */
+	{ 0x74, 0x00 }, /* 74 Equalizer Band 4 Coefficient B0 */
+	{ 0x75, 0x00 }, /* 75 Equalizer Band 4 Coefficient B0 */
+	{ 0x76, 0x00 }, /* 76 Equalizer Band 4 Coefficient B1 */
+	{ 0x77, 0x00 }, /* 77 Equalizer Band 4 Coefficient B1 */
+	{ 0x78, 0x00 }, /* 78 Equalizer Band 4 Coefficient B1 */
+	{ 0x79, 0x00 }, /* 79 Equalizer Band 4 Coefficient B2 */
+	{ 0x7A, 0x00 }, /* 7A Equalizer Band 4 Coefficient B2 */
+	{ 0x7B, 0x00 }, /* 7B Equalizer Band 4 Coefficient B2 */
+	{ 0x7C, 0x00 }, /* 7C Equalizer Band 4 Coefficient A1 */
+	{ 0x7D, 0x00 }, /* 7D Equalizer Band 4 Coefficient A1 */
+	{ 0x7E, 0x00 }, /* 7E Equalizer Band 4 Coefficient A1 */
+	{ 0x7F, 0x00 }, /* 7F Equalizer Band 4 Coefficient A2 */
+
+	{ 0x80, 0x00 }, /* 80 Equalizer Band 4 Coefficient A2 */
+	{ 0x81, 0x00 }, /* 81 Equalizer Band 4 Coefficient A2 */
+	{ 0x82, 0x00 }, /* 82 Equalizer Band 5 Coefficient B0 */
+	{ 0x83, 0x00 }, /* 83 Equalizer Band 5 Coefficient B0 */
+	{ 0x84, 0x00 }, /* 84 Equalizer Band 5 Coefficient B0 */
+	{ 0x85, 0x00 }, /* 85 Equalizer Band 5 Coefficient B1 */
+	{ 0x86, 0x00 }, /* 86 Equalizer Band 5 Coefficient B1 */
+	{ 0x87, 0x00 }, /* 87 Equalizer Band 5 Coefficient B1 */
+	{ 0x88, 0x00 }, /* 88 Equalizer Band 5 Coefficient B2 */
+	{ 0x89, 0x00 }, /* 89 Equalizer Band 5 Coefficient B2 */
+	{ 0x8A, 0x00 }, /* 8A Equalizer Band 5 Coefficient B2 */
+	{ 0x8B, 0x00 }, /* 8B Equalizer Band 5 Coefficient A1 */
+	{ 0x8C, 0x00 }, /* 8C Equalizer Band 5 Coefficient A1 */
+	{ 0x8D, 0x00 }, /* 8D Equalizer Band 5 Coefficient A1 */
+	{ 0x8E, 0x00 }, /* 8E Equalizer Band 5 Coefficient A2 */
+	{ 0x8F, 0x00 }, /* 8F Equalizer Band 5 Coefficient A2 */
+
+	{ 0x90, 0x00 }, /* 90 Equalizer Band 5 Coefficient A2 */
+	{ 0x91, 0x00 }, /* 91 Equalizer Band 6 Coefficient B0 */
+	{ 0x92, 0x00 }, /* 92 Equalizer Band 6 Coefficient B0 */
+	{ 0x93, 0x00 }, /* 93 Equalizer Band 6 Coefficient B0 */
+	{ 0x94, 0x00 }, /* 94 Equalizer Band 6 Coefficient B1 */
+	{ 0x95, 0x00 }, /* 95 Equalizer Band 6 Coefficient B1 */
+	{ 0x96, 0x00 }, /* 96 Equalizer Band 6 Coefficient B1 */
+	{ 0x97, 0x00 }, /* 97 Equalizer Band 6 Coefficient B2 */
+	{ 0x98, 0x00 }, /* 98 Equalizer Band 6 Coefficient B2 */
+	{ 0x99, 0x00 }, /* 99 Equalizer Band 6 Coefficient B2 */
+	{ 0x9A, 0x00 }, /* 9A Equalizer Band 6 Coefficient A1 */
+	{ 0x9B, 0x00 }, /* 9B Equalizer Band 6 Coefficient A1 */
+	{ 0x9C, 0x00 }, /* 9C Equalizer Band 6 Coefficient A1 */
+	{ 0x9D, 0x00 }, /* 9D Equalizer Band 6 Coefficient A2 */
+	{ 0x9E, 0x00 }, /* 9E Equalizer Band 6 Coefficient A2 */
+	{ 0x9F, 0x00 }, /* 9F Equalizer Band 6 Coefficient A2 */
+
+	{ 0xA0, 0x00 }, /* A0 Equalizer Band 7 Coefficient B0 */
+	{ 0xA1, 0x00 }, /* A1 Equalizer Band 7 Coefficient B0 */
+	{ 0xA2, 0x00 }, /* A2 Equalizer Band 7 Coefficient B0 */
+	{ 0xA3, 0x00 }, /* A3 Equalizer Band 7 Coefficient B1 */
+	{ 0xA4, 0x00 }, /* A4 Equalizer Band 7 Coefficient B1 */
+	{ 0xA5, 0x00 }, /* A5 Equalizer Band 7 Coefficient B1 */
+	{ 0xA6, 0x00 }, /* A6 Equalizer Band 7 Coefficient B2 */
+	{ 0xA7, 0x00 }, /* A7 Equalizer Band 7 Coefficient B2 */
+	{ 0xA8, 0x00 }, /* A8 Equalizer Band 7 Coefficient B2 */
+	{ 0xA9, 0x00 }, /* A9 Equalizer Band 7 Coefficient A1 */
+	{ 0xAA, 0x00 }, /* AA Equalizer Band 7 Coefficient A1 */
+	{ 0xAB, 0x00 }, /* AB Equalizer Band 7 Coefficient A1 */
+	{ 0xAC, 0x00 }, /* AC Equalizer Band 7 Coefficient A2 */
+	{ 0xAD, 0x00 }, /* AD Equalizer Band 7 Coefficient A2 */
+	{ 0xAE, 0x00 }, /* AE Equalizer Band 7 Coefficient A2 */
+	{ 0xAF, 0x00 }, /* AF ADC Biquad Coefficient B0 */
+
+	{ 0xB0, 0x00 }, /* B0 ADC Biquad Coefficient B0 */
+	{ 0xB1, 0x00 }, /* B1 ADC Biquad Coefficient B0 */
+	{ 0xB2, 0x00 }, /* B2 ADC Biquad Coefficient B1 */
+	{ 0xB3, 0x00 }, /* B3 ADC Biquad Coefficient B1 */
+	{ 0xB4, 0x00 }, /* B4 ADC Biquad Coefficient B1 */
+	{ 0xB5, 0x00 }, /* B5 ADC Biquad Coefficient B2 */
+	{ 0xB6, 0x00 }, /* B6 ADC Biquad Coefficient B2 */
+	{ 0xB7, 0x00 }, /* B7 ADC Biquad Coefficient B2 */
+	{ 0xB8, 0x00 }, /* B8 ADC Biquad Coefficient A1 */
+	{ 0xB9, 0x00 }, /* B9 ADC Biquad Coefficient A1 */
+	{ 0xBA, 0x00 }, /* BA ADC Biquad Coefficient A1 */
+	{ 0xBB, 0x00 }, /* BB ADC Biquad Coefficient A2 */
+	{ 0xBC, 0x00 }, /* BC ADC Biquad Coefficient A2 */
+	{ 0xBD, 0x00 }, /* BD ADC Biquad Coefficient A2 */
+	{ 0xBE, 0x00 }, /* BE Digital Mic 3 Volume */
+	{ 0xBF, 0x00 }, /* BF Digital Mic 4 Volume */
+
+	{ 0xC0, 0x00 }, /* C0 Digital Mic 34 Biquad Pre Atten */
+	{ 0xC1, 0x00 }, /* C1 Record TDM Slot */
+	{ 0xC2, 0x00 }, /* C2 Sample Rate */
+	{ 0xC3, 0x00 }, /* C3 Digital Mic 34 Biquad Coefficient C3 */
+	{ 0xC4, 0x00 }, /* C4 Digital Mic 34 Biquad Coefficient C4 */
+	{ 0xC5, 0x00 }, /* C5 Digital Mic 34 Biquad Coefficient C5 */
+	{ 0xC6, 0x00 }, /* C6 Digital Mic 34 Biquad Coefficient C6 */
+	{ 0xC7, 0x00 }, /* C7 Digital Mic 34 Biquad Coefficient C7 */
+	{ 0xC8, 0x00 }, /* C8 Digital Mic 34 Biquad Coefficient C8 */
+	{ 0xC9, 0x00 }, /* C9 Digital Mic 34 Biquad Coefficient C9 */
+	{ 0xCA, 0x00 }, /* CA Digital Mic 34 Biquad Coefficient CA */
+	{ 0xCB, 0x00 }, /* CB Digital Mic 34 Biquad Coefficient CB */
+	{ 0xCC, 0x00 }, /* CC Digital Mic 34 Biquad Coefficient CC */
+	{ 0xCD, 0x00 }, /* CD Digital Mic 34 Biquad Coefficient CD */
+	{ 0xCE, 0x00 }, /* CE Digital Mic 34 Biquad Coefficient CE */
+	{ 0xCF, 0x00 }, /* CF Digital Mic 34 Biquad Coefficient CF */
+
+	{ 0xD0, 0x00 }, /* D0 Digital Mic 34 Biquad Coefficient D0 */
+	{ 0xD1, 0x00 }, /* D1 Digital Mic 34 Biquad Coefficient D1 */
+};
+
+static bool max98090_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case M98090_REG_SOFTWARE_RESET:
+	case M98090_REG_DEVICE_STATUS:
+	case M98090_REG_JACK_STATUS:
+	case M98090_REG_REVISION_ID:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max98090_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case M98090_REG_DEVICE_STATUS ... M98090_REG_INTERRUPT_S:
+	case M98090_REG_LINE_INPUT_CONFIG ... 0xD1:
+	case M98090_REG_REVISION_ID:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int max98090_reset(struct max98090_priv *max98090)
+{
+	int ret;
+
+	/* Reset the codec by writing to this write-only reset register */
+	ret = regmap_write(max98090->regmap, M98090_REG_SOFTWARE_RESET,
+		M98090_SWRESET_MASK);
+	if (ret < 0) {
+		dev_err(max98090->component->dev,
+			"Failed to reset codec: %d\n", ret);
+		return ret;
+	}
+
+	msleep(20);
+	return ret;
+}
+
+static const DECLARE_TLV_DB_RANGE(max98090_micboost_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+	2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(max98090_mic_tlv, 0, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(max98090_line_single_ended_tlv,
+	-600, 600, 0);
+
+static const DECLARE_TLV_DB_RANGE(max98090_line_tlv,
+	0, 3, TLV_DB_SCALE_ITEM(-600, 300, 0),
+	4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(max98090_avg_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(max98090_av_tlv, -1200, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(max98090_dvg_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(max98090_dv_tlv, -1500, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(max98090_sidetone_tlv, -6050, 200, 0);
+
+static const DECLARE_TLV_DB_SCALE(max98090_alc_tlv, -1500, 100, 0);
+static const DECLARE_TLV_DB_SCALE(max98090_alcmakeup_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(max98090_alccomp_tlv, -3100, 100, 0);
+static const DECLARE_TLV_DB_SCALE(max98090_drcexp_tlv, -6600, 100, 0);
+static const DECLARE_TLV_DB_SCALE(max98090_sdg_tlv, 50, 200, 0);
+
+static const DECLARE_TLV_DB_RANGE(max98090_mixout_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(-1200, 250, 0),
+	2, 3, TLV_DB_SCALE_ITEM(-600, 600, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(max98090_hp_tlv,
+	0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0),
+	7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0),
+	15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0),
+	22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0),
+	28, 31, TLV_DB_SCALE_ITEM(150, 50, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(max98090_spk_tlv,
+	0, 4, TLV_DB_SCALE_ITEM(-4800, 400, 0),
+	5, 10, TLV_DB_SCALE_ITEM(-2900, 300, 0),
+	11, 14, TLV_DB_SCALE_ITEM(-1200, 200, 0),
+	15, 29, TLV_DB_SCALE_ITEM(-500, 100, 0),
+	30, 39, TLV_DB_SCALE_ITEM(950, 50, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(max98090_rcv_lout_tlv,
+	0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0),
+	7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0),
+	15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0),
+	22, 27, TLV_DB_SCALE_ITEM(100, 100, 0),
+	28, 31, TLV_DB_SCALE_ITEM(650, 50, 0)
+);
+
+static int max98090_get_enab_tlv(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned int mask = (1 << fls(mc->max)) - 1;
+	unsigned int val = snd_soc_component_read32(component, mc->reg);
+	unsigned int *select;
+
+	switch (mc->reg) {
+	case M98090_REG_MIC1_INPUT_LEVEL:
+		select = &(max98090->pa1en);
+		break;
+	case M98090_REG_MIC2_INPUT_LEVEL:
+		select = &(max98090->pa2en);
+		break;
+	case M98090_REG_ADC_SIDETONE:
+		select = &(max98090->sidetone);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val = (val >> mc->shift) & mask;
+
+	if (val >= 1) {
+		/* If on, return the volume */
+		val = val - 1;
+		*select = val;
+	} else {
+		/* If off, return last stored value */
+		val = *select;
+	}
+
+	ucontrol->value.integer.value[0] = val;
+	return 0;
+}
+
+static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned int mask = (1 << fls(mc->max)) - 1;
+	unsigned int sel = ucontrol->value.integer.value[0];
+	unsigned int val = snd_soc_component_read32(component, mc->reg);
+	unsigned int *select;
+
+	switch (mc->reg) {
+	case M98090_REG_MIC1_INPUT_LEVEL:
+		select = &(max98090->pa1en);
+		break;
+	case M98090_REG_MIC2_INPUT_LEVEL:
+		select = &(max98090->pa2en);
+		break;
+	case M98090_REG_ADC_SIDETONE:
+		select = &(max98090->sidetone);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val = (val >> mc->shift) & mask;
+
+	*select = sel;
+
+	/* Setting a volume is only valid if it is already On */
+	if (val >= 1) {
+		sel = sel + 1;
+	} else {
+		/* Write what was already there */
+		sel = val;
+	}
+
+	snd_soc_component_update_bits(component, mc->reg,
+		mask << mc->shift,
+		sel << mc->shift);
+
+	return 0;
+}
+
+static const char *max98090_perf_pwr_text[] =
+	{ "High Performance", "Low Power" };
+static const char *max98090_pwr_perf_text[] =
+	{ "Low Power", "High Performance" };
+
+static SOC_ENUM_SINGLE_DECL(max98090_vcmbandgap_enum,
+			    M98090_REG_BIAS_CONTROL,
+			    M98090_VCM_MODE_SHIFT,
+			    max98090_pwr_perf_text);
+
+static const char *max98090_osr128_text[] = { "64*fs", "128*fs" };
+
+static SOC_ENUM_SINGLE_DECL(max98090_osr128_enum,
+			    M98090_REG_ADC_CONTROL,
+			    M98090_OSR128_SHIFT,
+			    max98090_osr128_text);
+
+static const char *max98090_mode_text[] = { "Voice", "Music" };
+
+static SOC_ENUM_SINGLE_DECL(max98090_mode_enum,
+			    M98090_REG_FILTER_CONFIG,
+			    M98090_MODE_SHIFT,
+			    max98090_mode_text);
+
+static SOC_ENUM_SINGLE_DECL(max98090_filter_dmic34mode_enum,
+			    M98090_REG_FILTER_CONFIG,
+			    M98090_FLT_DMIC34MODE_SHIFT,
+			    max98090_mode_text);
+
+static const char *max98090_drcatk_text[] =
+	{ "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" };
+
+static SOC_ENUM_SINGLE_DECL(max98090_drcatk_enum,
+			    M98090_REG_DRC_TIMING,
+			    M98090_DRCATK_SHIFT,
+			    max98090_drcatk_text);
+
+static const char *max98090_drcrls_text[] =
+	{ "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" };
+
+static SOC_ENUM_SINGLE_DECL(max98090_drcrls_enum,
+			    M98090_REG_DRC_TIMING,
+			    M98090_DRCRLS_SHIFT,
+			    max98090_drcrls_text);
+
+static const char *max98090_alccmp_text[] =
+	{ "1:1", "1:1.5", "1:2", "1:4", "1:INF" };
+
+static SOC_ENUM_SINGLE_DECL(max98090_alccmp_enum,
+			    M98090_REG_DRC_COMPRESSOR,
+			    M98090_DRCCMP_SHIFT,
+			    max98090_alccmp_text);
+
+static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" };
+
+static SOC_ENUM_SINGLE_DECL(max98090_drcexp_enum,
+			    M98090_REG_DRC_EXPANDER,
+			    M98090_DRCEXP_SHIFT,
+			    max98090_drcexp_text);
+
+static SOC_ENUM_SINGLE_DECL(max98090_dac_perfmode_enum,
+			    M98090_REG_DAC_CONTROL,
+			    M98090_PERFMODE_SHIFT,
+			    max98090_perf_pwr_text);
+
+static SOC_ENUM_SINGLE_DECL(max98090_dachp_enum,
+			    M98090_REG_DAC_CONTROL,
+			    M98090_DACHP_SHIFT,
+			    max98090_pwr_perf_text);
+
+static SOC_ENUM_SINGLE_DECL(max98090_adchp_enum,
+			    M98090_REG_ADC_CONTROL,
+			    M98090_ADCHP_SHIFT,
+			    max98090_pwr_perf_text);
+
+static const struct snd_kcontrol_new max98090_snd_controls[] = {
+	SOC_ENUM("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum),
+
+	SOC_SINGLE("DMIC MIC Comp Filter Config", M98090_REG_DIGITAL_MIC_CONFIG,
+		M98090_DMIC_COMP_SHIFT, M98090_DMIC_COMP_NUM - 1, 0),
+
+	SOC_SINGLE_EXT_TLV("MIC1 Boost Volume",
+		M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT,
+		M98090_MIC_PA1EN_NUM - 1, 0, max98090_get_enab_tlv,
+		max98090_put_enab_tlv, max98090_micboost_tlv),
+
+	SOC_SINGLE_EXT_TLV("MIC2 Boost Volume",
+		M98090_REG_MIC2_INPUT_LEVEL, M98090_MIC_PA2EN_SHIFT,
+		M98090_MIC_PA2EN_NUM - 1, 0, max98090_get_enab_tlv,
+		max98090_put_enab_tlv, max98090_micboost_tlv),
+
+	SOC_SINGLE_TLV("MIC1 Volume", M98090_REG_MIC1_INPUT_LEVEL,
+		M98090_MIC_PGAM1_SHIFT, M98090_MIC_PGAM1_NUM - 1, 1,
+		max98090_mic_tlv),
+
+	SOC_SINGLE_TLV("MIC2 Volume", M98090_REG_MIC2_INPUT_LEVEL,
+		M98090_MIC_PGAM2_SHIFT, M98090_MIC_PGAM2_NUM - 1, 1,
+		max98090_mic_tlv),
+
+	SOC_SINGLE_RANGE_TLV("LINEA Single Ended Volume",
+		M98090_REG_LINE_INPUT_LEVEL, M98090_MIXG135_SHIFT, 0,
+		M98090_MIXG135_NUM - 1, 1, max98090_line_single_ended_tlv),
+
+	SOC_SINGLE_RANGE_TLV("LINEB Single Ended Volume",
+		M98090_REG_LINE_INPUT_LEVEL, M98090_MIXG246_SHIFT, 0,
+		M98090_MIXG246_NUM - 1, 1, max98090_line_single_ended_tlv),
+
+	SOC_SINGLE_RANGE_TLV("LINEA Volume", M98090_REG_LINE_INPUT_LEVEL,
+		M98090_LINAPGA_SHIFT, 0, M98090_LINAPGA_NUM - 1, 1,
+		max98090_line_tlv),
+
+	SOC_SINGLE_RANGE_TLV("LINEB Volume", M98090_REG_LINE_INPUT_LEVEL,
+		M98090_LINBPGA_SHIFT, 0, M98090_LINBPGA_NUM - 1, 1,
+		max98090_line_tlv),
+
+	SOC_SINGLE("LINEA Ext Resistor Gain Mode", M98090_REG_INPUT_MODE,
+		M98090_EXTBUFA_SHIFT, M98090_EXTBUFA_NUM - 1, 0),
+	SOC_SINGLE("LINEB Ext Resistor Gain Mode", M98090_REG_INPUT_MODE,
+		M98090_EXTBUFB_SHIFT, M98090_EXTBUFB_NUM - 1, 0),
+
+	SOC_SINGLE_TLV("ADCL Boost Volume", M98090_REG_LEFT_ADC_LEVEL,
+		M98090_AVLG_SHIFT, M98090_AVLG_NUM - 1, 0,
+		max98090_avg_tlv),
+	SOC_SINGLE_TLV("ADCR Boost Volume", M98090_REG_RIGHT_ADC_LEVEL,
+		M98090_AVRG_SHIFT, M98090_AVLG_NUM - 1, 0,
+		max98090_avg_tlv),
+
+	SOC_SINGLE_TLV("ADCL Volume", M98090_REG_LEFT_ADC_LEVEL,
+		M98090_AVL_SHIFT, M98090_AVL_NUM - 1, 1,
+		max98090_av_tlv),
+	SOC_SINGLE_TLV("ADCR Volume", M98090_REG_RIGHT_ADC_LEVEL,
+		M98090_AVR_SHIFT, M98090_AVR_NUM - 1, 1,
+		max98090_av_tlv),
+
+	SOC_ENUM("ADC Oversampling Rate", max98090_osr128_enum),
+	SOC_SINGLE("ADC Quantizer Dither", M98090_REG_ADC_CONTROL,
+		M98090_ADCDITHER_SHIFT, M98090_ADCDITHER_NUM - 1, 0),
+	SOC_ENUM("ADC High Performance Mode", max98090_adchp_enum),
+
+	SOC_SINGLE("DAC Mono Mode", M98090_REG_IO_CONFIGURATION,
+		M98090_DMONO_SHIFT, M98090_DMONO_NUM - 1, 0),
+	SOC_SINGLE("SDIN Mode", M98090_REG_IO_CONFIGURATION,
+		M98090_SDIEN_SHIFT, M98090_SDIEN_NUM - 1, 0),
+	SOC_SINGLE("SDOUT Mode", M98090_REG_IO_CONFIGURATION,
+		M98090_SDOEN_SHIFT, M98090_SDOEN_NUM - 1, 0),
+	SOC_SINGLE("SDOUT Hi-Z Mode", M98090_REG_IO_CONFIGURATION,
+		M98090_HIZOFF_SHIFT, M98090_HIZOFF_NUM - 1, 1),
+	SOC_ENUM("Filter Mode", max98090_mode_enum),
+	SOC_SINGLE("Record Path DC Blocking", M98090_REG_FILTER_CONFIG,
+		M98090_AHPF_SHIFT, M98090_AHPF_NUM - 1, 0),
+	SOC_SINGLE("Playback Path DC Blocking", M98090_REG_FILTER_CONFIG,
+		M98090_DHPF_SHIFT, M98090_DHPF_NUM - 1, 0),
+	SOC_SINGLE_TLV("Digital BQ Volume", M98090_REG_ADC_BIQUAD_LEVEL,
+		M98090_AVBQ_SHIFT, M98090_AVBQ_NUM - 1, 1, max98090_dv_tlv),
+	SOC_SINGLE_EXT_TLV("Digital Sidetone Volume",
+		M98090_REG_ADC_SIDETONE, M98090_DVST_SHIFT,
+		M98090_DVST_NUM - 1, 1, max98090_get_enab_tlv,
+		max98090_put_enab_tlv, max98090_sdg_tlv),
+	SOC_SINGLE_TLV("Digital Coarse Volume", M98090_REG_DAI_PLAYBACK_LEVEL,
+		M98090_DVG_SHIFT, M98090_DVG_NUM - 1, 0,
+		max98090_dvg_tlv),
+	SOC_SINGLE_TLV("Digital Volume", M98090_REG_DAI_PLAYBACK_LEVEL,
+		M98090_DV_SHIFT, M98090_DV_NUM - 1, 1,
+		max98090_dv_tlv),
+	SND_SOC_BYTES("EQ Coefficients", M98090_REG_EQUALIZER_BASE, 105),
+	SOC_SINGLE("Digital EQ 3 Band Switch", M98090_REG_DSP_FILTER_ENABLE,
+		M98090_EQ3BANDEN_SHIFT, M98090_EQ3BANDEN_NUM - 1, 0),
+	SOC_SINGLE("Digital EQ 5 Band Switch", M98090_REG_DSP_FILTER_ENABLE,
+		M98090_EQ5BANDEN_SHIFT, M98090_EQ5BANDEN_NUM - 1, 0),
+	SOC_SINGLE("Digital EQ 7 Band Switch", M98090_REG_DSP_FILTER_ENABLE,
+		M98090_EQ7BANDEN_SHIFT, M98090_EQ7BANDEN_NUM - 1, 0),
+	SOC_SINGLE("Digital EQ Clipping Detection", M98090_REG_DAI_PLAYBACK_LEVEL_EQ,
+		M98090_EQCLPN_SHIFT, M98090_EQCLPN_NUM - 1,
+		1),
+	SOC_SINGLE_TLV("Digital EQ Volume", M98090_REG_DAI_PLAYBACK_LEVEL_EQ,
+		M98090_DVEQ_SHIFT, M98090_DVEQ_NUM - 1, 1,
+		max98090_dv_tlv),
+
+	SOC_SINGLE("ALC Enable", M98090_REG_DRC_TIMING,
+		M98090_DRCEN_SHIFT, M98090_DRCEN_NUM - 1, 0),
+	SOC_ENUM("ALC Attack Time", max98090_drcatk_enum),
+	SOC_ENUM("ALC Release Time", max98090_drcrls_enum),
+	SOC_SINGLE_TLV("ALC Make Up Volume", M98090_REG_DRC_GAIN,
+		M98090_DRCG_SHIFT, M98090_DRCG_NUM - 1, 0,
+		max98090_alcmakeup_tlv),
+	SOC_ENUM("ALC Compression Ratio", max98090_alccmp_enum),
+	SOC_ENUM("ALC Expansion Ratio", max98090_drcexp_enum),
+	SOC_SINGLE_TLV("ALC Compression Threshold Volume",
+		M98090_REG_DRC_COMPRESSOR, M98090_DRCTHC_SHIFT,
+		M98090_DRCTHC_NUM - 1, 1, max98090_alccomp_tlv),
+	SOC_SINGLE_TLV("ALC Expansion Threshold Volume",
+		M98090_REG_DRC_EXPANDER, M98090_DRCTHE_SHIFT,
+		M98090_DRCTHE_NUM - 1, 1, max98090_drcexp_tlv),
+
+	SOC_ENUM("DAC HP Playback Performance Mode",
+		max98090_dac_perfmode_enum),
+	SOC_ENUM("DAC High Performance Mode", max98090_dachp_enum),
+
+	SOC_SINGLE_TLV("Headphone Left Mixer Volume",
+		M98090_REG_HP_CONTROL, M98090_MIXHPLG_SHIFT,
+		M98090_MIXHPLG_NUM - 1, 1, max98090_mixout_tlv),
+	SOC_SINGLE_TLV("Headphone Right Mixer Volume",
+		M98090_REG_HP_CONTROL, M98090_MIXHPRG_SHIFT,
+		M98090_MIXHPRG_NUM - 1, 1, max98090_mixout_tlv),
+
+	SOC_SINGLE_TLV("Speaker Left Mixer Volume",
+		M98090_REG_SPK_CONTROL, M98090_MIXSPLG_SHIFT,
+		M98090_MIXSPLG_NUM - 1, 1, max98090_mixout_tlv),
+	SOC_SINGLE_TLV("Speaker Right Mixer Volume",
+		M98090_REG_SPK_CONTROL, M98090_MIXSPRG_SHIFT,
+		M98090_MIXSPRG_NUM - 1, 1, max98090_mixout_tlv),
+
+	SOC_SINGLE_TLV("Receiver Left Mixer Volume",
+		M98090_REG_RCV_LOUTL_CONTROL, M98090_MIXRCVLG_SHIFT,
+		M98090_MIXRCVLG_NUM - 1, 1, max98090_mixout_tlv),
+	SOC_SINGLE_TLV("Receiver Right Mixer Volume",
+		M98090_REG_LOUTR_CONTROL, M98090_MIXRCVRG_SHIFT,
+		M98090_MIXRCVRG_NUM - 1, 1, max98090_mixout_tlv),
+
+	SOC_DOUBLE_R_TLV("Headphone Volume", M98090_REG_LEFT_HP_VOLUME,
+		M98090_REG_RIGHT_HP_VOLUME, M98090_HPVOLL_SHIFT,
+		M98090_HPVOLL_NUM - 1, 0, max98090_hp_tlv),
+
+	SOC_DOUBLE_R_RANGE_TLV("Speaker Volume",
+		M98090_REG_LEFT_SPK_VOLUME, M98090_REG_RIGHT_SPK_VOLUME,
+		M98090_SPVOLL_SHIFT, 24, M98090_SPVOLL_NUM - 1 + 24,
+		0, max98090_spk_tlv),
+
+	SOC_DOUBLE_R_TLV("Receiver Volume", M98090_REG_RCV_LOUTL_VOLUME,
+		M98090_REG_LOUTR_VOLUME, M98090_RCVLVOL_SHIFT,
+		M98090_RCVLVOL_NUM - 1, 0, max98090_rcv_lout_tlv),
+
+	SOC_SINGLE("Headphone Left Switch", M98090_REG_LEFT_HP_VOLUME,
+		M98090_HPLM_SHIFT, 1, 1),
+	SOC_SINGLE("Headphone Right Switch", M98090_REG_RIGHT_HP_VOLUME,
+		M98090_HPRM_SHIFT, 1, 1),
+
+	SOC_SINGLE("Speaker Left Switch", M98090_REG_LEFT_SPK_VOLUME,
+		M98090_SPLM_SHIFT, 1, 1),
+	SOC_SINGLE("Speaker Right Switch", M98090_REG_RIGHT_SPK_VOLUME,
+		M98090_SPRM_SHIFT, 1, 1),
+
+	SOC_SINGLE("Receiver Left Switch", M98090_REG_RCV_LOUTL_VOLUME,
+		M98090_RCVLM_SHIFT, 1, 1),
+	SOC_SINGLE("Receiver Right Switch", M98090_REG_LOUTR_VOLUME,
+		M98090_RCVRM_SHIFT, 1, 1),
+
+	SOC_SINGLE("Zero-Crossing Detection", M98090_REG_LEVEL_CONTROL,
+		M98090_ZDENN_SHIFT, M98090_ZDENN_NUM - 1, 1),
+	SOC_SINGLE("Enhanced Vol Smoothing", M98090_REG_LEVEL_CONTROL,
+		M98090_VS2ENN_SHIFT, M98090_VS2ENN_NUM - 1, 1),
+	SOC_SINGLE("Volume Adjustment Smoothing", M98090_REG_LEVEL_CONTROL,
+		M98090_VSENN_SHIFT, M98090_VSENN_NUM - 1, 1),
+
+	SND_SOC_BYTES("Biquad Coefficients", M98090_REG_RECORD_BIQUAD_BASE, 15),
+	SOC_SINGLE("Biquad Switch", M98090_REG_DSP_FILTER_ENABLE,
+		M98090_ADCBQEN_SHIFT, M98090_ADCBQEN_NUM - 1, 0),
+};
+
+static const struct snd_kcontrol_new max98091_snd_controls[] = {
+
+	SOC_SINGLE("DMIC34 Zeropad", M98090_REG_SAMPLE_RATE,
+		M98090_DMIC34_ZEROPAD_SHIFT,
+		M98090_DMIC34_ZEROPAD_NUM - 1, 0),
+
+	SOC_ENUM("Filter DMIC34 Mode", max98090_filter_dmic34mode_enum),
+	SOC_SINGLE("DMIC34 DC Blocking", M98090_REG_FILTER_CONFIG,
+		M98090_FLT_DMIC34HPF_SHIFT,
+		M98090_FLT_DMIC34HPF_NUM - 1, 0),
+
+	SOC_SINGLE_TLV("DMIC3 Boost Volume", M98090_REG_DMIC3_VOLUME,
+		M98090_DMIC_AV3G_SHIFT, M98090_DMIC_AV3G_NUM - 1, 0,
+		max98090_avg_tlv),
+	SOC_SINGLE_TLV("DMIC4 Boost Volume", M98090_REG_DMIC4_VOLUME,
+		M98090_DMIC_AV4G_SHIFT, M98090_DMIC_AV4G_NUM - 1, 0,
+		max98090_avg_tlv),
+
+	SOC_SINGLE_TLV("DMIC3 Volume", M98090_REG_DMIC3_VOLUME,
+		M98090_DMIC_AV3_SHIFT, M98090_DMIC_AV3_NUM - 1, 1,
+		max98090_av_tlv),
+	SOC_SINGLE_TLV("DMIC4 Volume", M98090_REG_DMIC4_VOLUME,
+		M98090_DMIC_AV4_SHIFT, M98090_DMIC_AV4_NUM - 1, 1,
+		max98090_av_tlv),
+
+	SND_SOC_BYTES("DMIC34 Biquad Coefficients",
+		M98090_REG_DMIC34_BIQUAD_BASE, 15),
+	SOC_SINGLE("DMIC34 Biquad Switch", M98090_REG_DSP_FILTER_ENABLE,
+		M98090_DMIC34BQEN_SHIFT, M98090_DMIC34BQEN_NUM - 1, 0),
+
+	SOC_SINGLE_TLV("DMIC34 BQ PreAttenuation Volume",
+		M98090_REG_DMIC34_BQ_PREATTEN, M98090_AV34BQ_SHIFT,
+		M98090_AV34BQ_NUM - 1, 1, max98090_dv_tlv),
+};
+
+static int max98090_micinput_event(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+
+	unsigned int val = snd_soc_component_read32(component, w->reg);
+
+	if (w->reg == M98090_REG_MIC1_INPUT_LEVEL)
+		val = (val & M98090_MIC_PA1EN_MASK) >> M98090_MIC_PA1EN_SHIFT;
+	else
+		val = (val & M98090_MIC_PA2EN_MASK) >> M98090_MIC_PA2EN_SHIFT;
+
+	if (val >= 1) {
+		if (w->reg == M98090_REG_MIC1_INPUT_LEVEL) {
+			max98090->pa1en = val - 1; /* Update for volatile */
+		} else {
+			max98090->pa2en = val - 1; /* Update for volatile */
+		}
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* If turning on, set to most recently selected volume */
+		if (w->reg == M98090_REG_MIC1_INPUT_LEVEL)
+			val = max98090->pa1en + 1;
+		else
+			val = max98090->pa2en + 1;
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* If turning off, turn off */
+		val = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (w->reg == M98090_REG_MIC1_INPUT_LEVEL)
+		snd_soc_component_update_bits(component, w->reg, M98090_MIC_PA1EN_MASK,
+			val << M98090_MIC_PA1EN_SHIFT);
+	else
+		snd_soc_component_update_bits(component, w->reg, M98090_MIC_PA2EN_MASK,
+			val << M98090_MIC_PA2EN_SHIFT);
+
+	return 0;
+}
+
+static int max98090_shdn_event(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+
+	if (event & SND_SOC_DAPM_POST_PMU)
+		max98090->shdn_pending = true;
+
+	return 0;
+
+}
+
+static const char *mic1_mux_text[] = { "IN12", "IN56" };
+
+static SOC_ENUM_SINGLE_DECL(mic1_mux_enum,
+			    M98090_REG_INPUT_MODE,
+			    M98090_EXTMIC1_SHIFT,
+			    mic1_mux_text);
+
+static const struct snd_kcontrol_new max98090_mic1_mux =
+	SOC_DAPM_ENUM("MIC1 Mux", mic1_mux_enum);
+
+static const char *mic2_mux_text[] = { "IN34", "IN56" };
+
+static SOC_ENUM_SINGLE_DECL(mic2_mux_enum,
+			    M98090_REG_INPUT_MODE,
+			    M98090_EXTMIC2_SHIFT,
+			    mic2_mux_text);
+
+static const struct snd_kcontrol_new max98090_mic2_mux =
+	SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum);
+
+static const char *dmic_mux_text[] = { "ADC", "DMIC" };
+
+static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text);
+
+static const struct snd_kcontrol_new max98090_dmic_mux =
+	SOC_DAPM_ENUM("DMIC Mux", dmic_mux_enum);
+
+static const char *max98090_micpre_text[] = { "Off", "On" };
+
+static SOC_ENUM_SINGLE_DECL(max98090_pa1en_enum,
+			    M98090_REG_MIC1_INPUT_LEVEL,
+			    M98090_MIC_PA1EN_SHIFT,
+			    max98090_micpre_text);
+
+static SOC_ENUM_SINGLE_DECL(max98090_pa2en_enum,
+			    M98090_REG_MIC2_INPUT_LEVEL,
+			    M98090_MIC_PA2EN_SHIFT,
+			    max98090_micpre_text);
+
+/* LINEA mixer switch */
+static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = {
+	SOC_DAPM_SINGLE("IN1 Switch", M98090_REG_LINE_INPUT_CONFIG,
+		M98090_IN1SEEN_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("IN3 Switch", M98090_REG_LINE_INPUT_CONFIG,
+		M98090_IN3SEEN_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("IN5 Switch", M98090_REG_LINE_INPUT_CONFIG,
+		M98090_IN5SEEN_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("IN34 Switch", M98090_REG_LINE_INPUT_CONFIG,
+		M98090_IN34DIFF_SHIFT, 1, 0),
+};
+
+/* LINEB mixer switch */
+static const struct snd_kcontrol_new max98090_lineb_mixer_controls[] = {
+	SOC_DAPM_SINGLE("IN2 Switch", M98090_REG_LINE_INPUT_CONFIG,
+		M98090_IN2SEEN_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("IN4 Switch", M98090_REG_LINE_INPUT_CONFIG,
+		M98090_IN4SEEN_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("IN6 Switch", M98090_REG_LINE_INPUT_CONFIG,
+		M98090_IN6SEEN_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("IN56 Switch", M98090_REG_LINE_INPUT_CONFIG,
+		M98090_IN56DIFF_SHIFT, 1, 0),
+};
+
+/* Left ADC mixer switch */
+static const struct snd_kcontrol_new max98090_left_adc_mixer_controls[] = {
+	SOC_DAPM_SINGLE("IN12 Switch", M98090_REG_LEFT_ADC_MIXER,
+		M98090_MIXADL_IN12DIFF_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("IN34 Switch", M98090_REG_LEFT_ADC_MIXER,
+		M98090_MIXADL_IN34DIFF_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("IN56 Switch", M98090_REG_LEFT_ADC_MIXER,
+		M98090_MIXADL_IN65DIFF_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_LEFT_ADC_MIXER,
+		M98090_MIXADL_LINEA_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_LEFT_ADC_MIXER,
+		M98090_MIXADL_LINEB_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_LEFT_ADC_MIXER,
+		M98090_MIXADL_MIC1_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_LEFT_ADC_MIXER,
+		M98090_MIXADL_MIC2_SHIFT, 1, 0),
+};
+
+/* Right ADC mixer switch */
+static const struct snd_kcontrol_new max98090_right_adc_mixer_controls[] = {
+	SOC_DAPM_SINGLE("IN12 Switch", M98090_REG_RIGHT_ADC_MIXER,
+		M98090_MIXADR_IN12DIFF_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("IN34 Switch", M98090_REG_RIGHT_ADC_MIXER,
+		M98090_MIXADR_IN34DIFF_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("IN56 Switch", M98090_REG_RIGHT_ADC_MIXER,
+		M98090_MIXADR_IN65DIFF_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_RIGHT_ADC_MIXER,
+		M98090_MIXADR_LINEA_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_RIGHT_ADC_MIXER,
+		M98090_MIXADR_LINEB_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_RIGHT_ADC_MIXER,
+		M98090_MIXADR_MIC1_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_RIGHT_ADC_MIXER,
+		M98090_MIXADR_MIC2_SHIFT, 1, 0),
+};
+
+static const char *lten_mux_text[] = { "Normal", "Loopthrough" };
+
+static SOC_ENUM_SINGLE_DECL(ltenl_mux_enum,
+			    M98090_REG_IO_CONFIGURATION,
+			    M98090_LTEN_SHIFT,
+			    lten_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(ltenr_mux_enum,
+			    M98090_REG_IO_CONFIGURATION,
+			    M98090_LTEN_SHIFT,
+			    lten_mux_text);
+
+static const struct snd_kcontrol_new max98090_ltenl_mux =
+	SOC_DAPM_ENUM("LTENL Mux", ltenl_mux_enum);
+
+static const struct snd_kcontrol_new max98090_ltenr_mux =
+	SOC_DAPM_ENUM("LTENR Mux", ltenr_mux_enum);
+
+static const char *lben_mux_text[] = { "Normal", "Loopback" };
+
+static SOC_ENUM_SINGLE_DECL(lbenl_mux_enum,
+			    M98090_REG_IO_CONFIGURATION,
+			    M98090_LBEN_SHIFT,
+			    lben_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(lbenr_mux_enum,
+			    M98090_REG_IO_CONFIGURATION,
+			    M98090_LBEN_SHIFT,
+			    lben_mux_text);
+
+static const struct snd_kcontrol_new max98090_lbenl_mux =
+	SOC_DAPM_ENUM("LBENL Mux", lbenl_mux_enum);
+
+static const struct snd_kcontrol_new max98090_lbenr_mux =
+	SOC_DAPM_ENUM("LBENR Mux", lbenr_mux_enum);
+
+static const char *stenl_mux_text[] = { "Normal", "Sidetone Left" };
+
+static const char *stenr_mux_text[] = { "Normal", "Sidetone Right" };
+
+static SOC_ENUM_SINGLE_DECL(stenl_mux_enum,
+			    M98090_REG_ADC_SIDETONE,
+			    M98090_DSTSL_SHIFT,
+			    stenl_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(stenr_mux_enum,
+			    M98090_REG_ADC_SIDETONE,
+			    M98090_DSTSR_SHIFT,
+			    stenr_mux_text);
+
+static const struct snd_kcontrol_new max98090_stenl_mux =
+	SOC_DAPM_ENUM("STENL Mux", stenl_mux_enum);
+
+static const struct snd_kcontrol_new max98090_stenr_mux =
+	SOC_DAPM_ENUM("STENR Mux", stenr_mux_enum);
+
+/* Left speaker mixer switch */
+static const struct
+	snd_kcontrol_new max98090_left_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC Switch", M98090_REG_LEFT_SPK_MIXER,
+		M98090_MIXSPL_DACL_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC Switch", M98090_REG_LEFT_SPK_MIXER,
+		M98090_MIXSPL_DACR_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_LEFT_SPK_MIXER,
+		M98090_MIXSPL_LINEA_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_LEFT_SPK_MIXER,
+		M98090_MIXSPL_LINEB_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_LEFT_SPK_MIXER,
+		M98090_MIXSPL_MIC1_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_LEFT_SPK_MIXER,
+		M98090_MIXSPL_MIC2_SHIFT, 1, 0),
+};
+
+/* Right speaker mixer switch */
+static const struct
+	snd_kcontrol_new max98090_right_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC Switch", M98090_REG_RIGHT_SPK_MIXER,
+		M98090_MIXSPR_DACL_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC Switch", M98090_REG_RIGHT_SPK_MIXER,
+		M98090_MIXSPR_DACR_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_RIGHT_SPK_MIXER,
+		M98090_MIXSPR_LINEA_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_RIGHT_SPK_MIXER,
+		M98090_MIXSPR_LINEB_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_RIGHT_SPK_MIXER,
+		M98090_MIXSPR_MIC1_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_RIGHT_SPK_MIXER,
+		M98090_MIXSPR_MIC2_SHIFT, 1, 0),
+};
+
+/* Left headphone mixer switch */
+static const struct snd_kcontrol_new max98090_left_hp_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC Switch", M98090_REG_LEFT_HP_MIXER,
+		M98090_MIXHPL_DACL_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC Switch", M98090_REG_LEFT_HP_MIXER,
+		M98090_MIXHPL_DACR_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_LEFT_HP_MIXER,
+		M98090_MIXHPL_LINEA_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_LEFT_HP_MIXER,
+		M98090_MIXHPL_LINEB_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_LEFT_HP_MIXER,
+		M98090_MIXHPL_MIC1_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_LEFT_HP_MIXER,
+		M98090_MIXHPL_MIC2_SHIFT, 1, 0),
+};
+
+/* Right headphone mixer switch */
+static const struct snd_kcontrol_new max98090_right_hp_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC Switch", M98090_REG_RIGHT_HP_MIXER,
+		M98090_MIXHPR_DACL_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC Switch", M98090_REG_RIGHT_HP_MIXER,
+		M98090_MIXHPR_DACR_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_RIGHT_HP_MIXER,
+		M98090_MIXHPR_LINEA_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_RIGHT_HP_MIXER,
+		M98090_MIXHPR_LINEB_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_RIGHT_HP_MIXER,
+		M98090_MIXHPR_MIC1_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_RIGHT_HP_MIXER,
+		M98090_MIXHPR_MIC2_SHIFT, 1, 0),
+};
+
+/* Left receiver mixer switch */
+static const struct snd_kcontrol_new max98090_left_rcv_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC Switch", M98090_REG_RCV_LOUTL_MIXER,
+		M98090_MIXRCVL_DACL_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC Switch", M98090_REG_RCV_LOUTL_MIXER,
+		M98090_MIXRCVL_DACR_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_RCV_LOUTL_MIXER,
+		M98090_MIXRCVL_LINEA_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_RCV_LOUTL_MIXER,
+		M98090_MIXRCVL_LINEB_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_RCV_LOUTL_MIXER,
+		M98090_MIXRCVL_MIC1_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_RCV_LOUTL_MIXER,
+		M98090_MIXRCVL_MIC2_SHIFT, 1, 0),
+};
+
+/* Right receiver mixer switch */
+static const struct snd_kcontrol_new max98090_right_rcv_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC Switch", M98090_REG_LOUTR_MIXER,
+		M98090_MIXRCVR_DACL_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC Switch", M98090_REG_LOUTR_MIXER,
+		M98090_MIXRCVR_DACR_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEA Switch", M98090_REG_LOUTR_MIXER,
+		M98090_MIXRCVR_LINEA_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LINEB Switch", M98090_REG_LOUTR_MIXER,
+		M98090_MIXRCVR_LINEB_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98090_REG_LOUTR_MIXER,
+		M98090_MIXRCVR_MIC1_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98090_REG_LOUTR_MIXER,
+		M98090_MIXRCVR_MIC2_SHIFT, 1, 0),
+};
+
+static const char *linmod_mux_text[] = { "Left Only", "Left and Right" };
+
+static SOC_ENUM_SINGLE_DECL(linmod_mux_enum,
+			    M98090_REG_LOUTR_MIXER,
+			    M98090_LINMOD_SHIFT,
+			    linmod_mux_text);
+
+static const struct snd_kcontrol_new max98090_linmod_mux =
+	SOC_DAPM_ENUM("LINMOD Mux", linmod_mux_enum);
+
+static const char *mixhpsel_mux_text[] = { "DAC Only", "HP Mixer" };
+
+/*
+ * This is a mux as it selects the HP output, but to DAPM it is a Mixer enable
+ */
+static SOC_ENUM_SINGLE_DECL(mixhplsel_mux_enum,
+			    M98090_REG_HP_CONTROL,
+			    M98090_MIXHPLSEL_SHIFT,
+			    mixhpsel_mux_text);
+
+static const struct snd_kcontrol_new max98090_mixhplsel_mux =
+	SOC_DAPM_ENUM("MIXHPLSEL Mux", mixhplsel_mux_enum);
+
+static SOC_ENUM_SINGLE_DECL(mixhprsel_mux_enum,
+			    M98090_REG_HP_CONTROL,
+			    M98090_MIXHPRSEL_SHIFT,
+			    mixhpsel_mux_text);
+
+static const struct snd_kcontrol_new max98090_mixhprsel_mux =
+	SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum);
+
+static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("DMICL"),
+	SND_SOC_DAPM_INPUT("DMICR"),
+	SND_SOC_DAPM_INPUT("IN1"),
+	SND_SOC_DAPM_INPUT("IN2"),
+	SND_SOC_DAPM_INPUT("IN3"),
+	SND_SOC_DAPM_INPUT("IN4"),
+	SND_SOC_DAPM_INPUT("IN5"),
+	SND_SOC_DAPM_INPUT("IN6"),
+	SND_SOC_DAPM_INPUT("IN12"),
+	SND_SOC_DAPM_INPUT("IN34"),
+	SND_SOC_DAPM_INPUT("IN56"),
+
+	SND_SOC_DAPM_SUPPLY("MICBIAS", M98090_REG_INPUT_ENABLE,
+		M98090_MBEN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("SHDN", M98090_REG_DEVICE_SHUTDOWN,
+		M98090_SHDNN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("SDIEN", M98090_REG_IO_CONFIGURATION,
+		M98090_SDIEN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("SDOEN", M98090_REG_IO_CONFIGURATION,
+		M98090_SDOEN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMICL_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
+		 M98090_DIGMICL_SHIFT, 0, max98090_shdn_event,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("DMICR_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
+		 M98090_DIGMICR_SHIFT, 0, max98090_shdn_event,
+			 SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("AHPF", M98090_REG_FILTER_CONFIG,
+		M98090_AHPF_SHIFT, 0, NULL, 0),
+
+/*
+ * Note: Sysclk and misc power supplies are taken care of by SHDN
+ */
+
+	SND_SOC_DAPM_MUX("MIC1 Mux", SND_SOC_NOPM,
+		0, 0, &max98090_mic1_mux),
+
+	SND_SOC_DAPM_MUX("MIC2 Mux", SND_SOC_NOPM,
+		0, 0, &max98090_mic2_mux),
+
+	SND_SOC_DAPM_MUX("DMIC Mux", SND_SOC_NOPM, 0, 0, &max98090_dmic_mux),
+
+	SND_SOC_DAPM_PGA_E("MIC1 Input", M98090_REG_MIC1_INPUT_LEVEL,
+		M98090_MIC_PA1EN_SHIFT, 0, NULL, 0, max98090_micinput_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("MIC2 Input", M98090_REG_MIC2_INPUT_LEVEL,
+		M98090_MIC_PA2EN_SHIFT, 0, NULL, 0, max98090_micinput_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER("LINEA Mixer", SND_SOC_NOPM, 0, 0,
+		&max98090_linea_mixer_controls[0],
+		ARRAY_SIZE(max98090_linea_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("LINEB Mixer", SND_SOC_NOPM, 0, 0,
+		&max98090_lineb_mixer_controls[0],
+		ARRAY_SIZE(max98090_lineb_mixer_controls)),
+
+	SND_SOC_DAPM_PGA("LINEA Input", M98090_REG_INPUT_ENABLE,
+		M98090_LINEAEN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("LINEB Input", M98090_REG_INPUT_ENABLE,
+		M98090_LINEBEN_SHIFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+		&max98090_left_adc_mixer_controls[0],
+		ARRAY_SIZE(max98090_left_adc_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+		&max98090_right_adc_mixer_controls[0],
+		ARRAY_SIZE(max98090_right_adc_mixer_controls)),
+
+	SND_SOC_DAPM_ADC_E("ADCL", NULL, M98090_REG_INPUT_ENABLE,
+		M98090_ADLEN_SHIFT, 0, max98090_shdn_event,
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_ADC_E("ADCR", NULL, M98090_REG_INPUT_ENABLE,
+		M98090_ADREN_SHIFT, 0, max98090_shdn_event,
+		SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_AIF_OUT("AIFOUTL", "HiFi Capture", 0,
+		SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIFOUTR", "HiFi Capture", 1,
+		SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MUX("LBENL Mux", SND_SOC_NOPM,
+		0, 0, &max98090_lbenl_mux),
+
+	SND_SOC_DAPM_MUX("LBENR Mux", SND_SOC_NOPM,
+		0, 0, &max98090_lbenr_mux),
+
+	SND_SOC_DAPM_MUX("LTENL Mux", SND_SOC_NOPM,
+		0, 0, &max98090_ltenl_mux),
+
+	SND_SOC_DAPM_MUX("LTENR Mux", SND_SOC_NOPM,
+		0, 0, &max98090_ltenr_mux),
+
+	SND_SOC_DAPM_MUX("STENL Mux", SND_SOC_NOPM,
+		0, 0, &max98090_stenl_mux),
+
+	SND_SOC_DAPM_MUX("STENR Mux", SND_SOC_NOPM,
+		0, 0, &max98090_stenr_mux),
+
+	SND_SOC_DAPM_AIF_IN("AIFINL", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIFINR", "HiFi Playback", 1, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_DAC("DACL", NULL, M98090_REG_OUTPUT_ENABLE,
+		M98090_DALEN_SHIFT, 0),
+	SND_SOC_DAPM_DAC("DACR", NULL, M98090_REG_OUTPUT_ENABLE,
+		M98090_DAREN_SHIFT, 0),
+
+	SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0,
+		&max98090_left_hp_mixer_controls[0],
+		ARRAY_SIZE(max98090_left_hp_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0,
+		&max98090_right_hp_mixer_controls[0],
+		ARRAY_SIZE(max98090_right_hp_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left Speaker Mixer", SND_SOC_NOPM, 0, 0,
+		&max98090_left_speaker_mixer_controls[0],
+		ARRAY_SIZE(max98090_left_speaker_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Speaker Mixer", SND_SOC_NOPM, 0, 0,
+		&max98090_right_speaker_mixer_controls[0],
+		ARRAY_SIZE(max98090_right_speaker_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left Receiver Mixer", SND_SOC_NOPM, 0, 0,
+		&max98090_left_rcv_mixer_controls[0],
+		ARRAY_SIZE(max98090_left_rcv_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Receiver Mixer", SND_SOC_NOPM, 0, 0,
+		&max98090_right_rcv_mixer_controls[0],
+		ARRAY_SIZE(max98090_right_rcv_mixer_controls)),
+
+	SND_SOC_DAPM_MUX("LINMOD Mux", M98090_REG_LOUTR_MIXER,
+		M98090_LINMOD_SHIFT, 0, &max98090_linmod_mux),
+
+	SND_SOC_DAPM_MUX("MIXHPLSEL Mux", M98090_REG_HP_CONTROL,
+		M98090_MIXHPLSEL_SHIFT, 0, &max98090_mixhplsel_mux),
+
+	SND_SOC_DAPM_MUX("MIXHPRSEL Mux", M98090_REG_HP_CONTROL,
+		M98090_MIXHPRSEL_SHIFT, 0, &max98090_mixhprsel_mux),
+
+	SND_SOC_DAPM_PGA("HP Left Out", M98090_REG_OUTPUT_ENABLE,
+		M98090_HPLEN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HP Right Out", M98090_REG_OUTPUT_ENABLE,
+		M98090_HPREN_SHIFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("SPK Left Out", M98090_REG_OUTPUT_ENABLE,
+		M98090_SPLEN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SPK Right Out", M98090_REG_OUTPUT_ENABLE,
+		M98090_SPREN_SHIFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("RCV Left Out", M98090_REG_OUTPUT_ENABLE,
+		M98090_RCVLEN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("RCV Right Out", M98090_REG_OUTPUT_ENABLE,
+		M98090_RCVREN_SHIFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("SPKL"),
+	SND_SOC_DAPM_OUTPUT("SPKR"),
+	SND_SOC_DAPM_OUTPUT("RCVL"),
+	SND_SOC_DAPM_OUTPUT("RCVR"),
+};
+
+static const struct snd_soc_dapm_widget max98091_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("DMIC3"),
+	SND_SOC_DAPM_INPUT("DMIC4"),
+
+	SND_SOC_DAPM_SUPPLY("DMIC3_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
+		 M98090_DIGMIC3_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC4_ENA", M98090_REG_DIGITAL_MIC_ENABLE,
+		 M98090_DIGMIC4_SHIFT, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
+	{"MIC1 Input", NULL, "MIC1"},
+	{"MIC2 Input", NULL, "MIC2"},
+
+	{"DMICL", NULL, "DMICL_ENA"},
+	{"DMICL", NULL, "DMICR_ENA"},
+	{"DMICR", NULL, "DMICL_ENA"},
+	{"DMICR", NULL, "DMICR_ENA"},
+	{"DMICL", NULL, "AHPF"},
+	{"DMICR", NULL, "AHPF"},
+
+	/* MIC1 input mux */
+	{"MIC1 Mux", "IN12", "IN12"},
+	{"MIC1 Mux", "IN56", "IN56"},
+
+	/* MIC2 input mux */
+	{"MIC2 Mux", "IN34", "IN34"},
+	{"MIC2 Mux", "IN56", "IN56"},
+
+	{"MIC1 Input", NULL, "MIC1 Mux"},
+	{"MIC2 Input", NULL, "MIC2 Mux"},
+
+	/* Left ADC input mixer */
+	{"Left ADC Mixer", "IN12 Switch", "IN12"},
+	{"Left ADC Mixer", "IN34 Switch", "IN34"},
+	{"Left ADC Mixer", "IN56 Switch", "IN56"},
+	{"Left ADC Mixer", "LINEA Switch", "LINEA Input"},
+	{"Left ADC Mixer", "LINEB Switch", "LINEB Input"},
+	{"Left ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+
+	/* Right ADC input mixer */
+	{"Right ADC Mixer", "IN12 Switch", "IN12"},
+	{"Right ADC Mixer", "IN34 Switch", "IN34"},
+	{"Right ADC Mixer", "IN56 Switch", "IN56"},
+	{"Right ADC Mixer", "LINEA Switch", "LINEA Input"},
+	{"Right ADC Mixer", "LINEB Switch", "LINEB Input"},
+	{"Right ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+
+	/* Line A input mixer */
+	{"LINEA Mixer", "IN1 Switch", "IN1"},
+	{"LINEA Mixer", "IN3 Switch", "IN3"},
+	{"LINEA Mixer", "IN5 Switch", "IN5"},
+	{"LINEA Mixer", "IN34 Switch", "IN34"},
+
+	/* Line B input mixer */
+	{"LINEB Mixer", "IN2 Switch", "IN2"},
+	{"LINEB Mixer", "IN4 Switch", "IN4"},
+	{"LINEB Mixer", "IN6 Switch", "IN6"},
+	{"LINEB Mixer", "IN56 Switch", "IN56"},
+
+	{"LINEA Input", NULL, "LINEA Mixer"},
+	{"LINEB Input", NULL, "LINEB Mixer"},
+
+	/* Inputs */
+	{"ADCL", NULL, "Left ADC Mixer"},
+	{"ADCR", NULL, "Right ADC Mixer"},
+	{"ADCL", NULL, "SHDN"},
+	{"ADCR", NULL, "SHDN"},
+
+	{"DMIC Mux", "ADC", "ADCL"},
+	{"DMIC Mux", "ADC", "ADCR"},
+	{"DMIC Mux", "DMIC", "DMICL"},
+	{"DMIC Mux", "DMIC", "DMICR"},
+
+	{"LBENL Mux", "Normal", "DMIC Mux"},
+	{"LBENL Mux", "Loopback", "LTENL Mux"},
+	{"LBENR Mux", "Normal", "DMIC Mux"},
+	{"LBENR Mux", "Loopback", "LTENR Mux"},
+
+	{"AIFOUTL", NULL, "LBENL Mux"},
+	{"AIFOUTR", NULL, "LBENR Mux"},
+	{"AIFOUTL", NULL, "SHDN"},
+	{"AIFOUTR", NULL, "SHDN"},
+	{"AIFOUTL", NULL, "SDOEN"},
+	{"AIFOUTR", NULL, "SDOEN"},
+
+	{"LTENL Mux", "Normal", "AIFINL"},
+	{"LTENL Mux", "Loopthrough", "LBENL Mux"},
+	{"LTENR Mux", "Normal", "AIFINR"},
+	{"LTENR Mux", "Loopthrough", "LBENR Mux"},
+
+	{"DACL", NULL, "LTENL Mux"},
+	{"DACR", NULL, "LTENR Mux"},
+
+	{"STENL Mux", "Sidetone Left", "ADCL"},
+	{"STENL Mux", "Sidetone Left", "DMICL"},
+	{"STENR Mux", "Sidetone Right", "ADCR"},
+	{"STENR Mux", "Sidetone Right", "DMICR"},
+	{"DACL", NULL, "STENL Mux"},
+	{"DACR", NULL, "STENR Mux"},
+
+	{"AIFINL", NULL, "SHDN"},
+	{"AIFINR", NULL, "SHDN"},
+	{"AIFINL", NULL, "SDIEN"},
+	{"AIFINR", NULL, "SDIEN"},
+	{"DACL", NULL, "SHDN"},
+	{"DACR", NULL, "SHDN"},
+
+	/* Left headphone output mixer */
+	{"Left Headphone Mixer", "Left DAC Switch", "DACL"},
+	{"Left Headphone Mixer", "Right DAC Switch", "DACR"},
+	{"Left Headphone Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left Headphone Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left Headphone Mixer", "LINEA Switch", "LINEA Input"},
+	{"Left Headphone Mixer", "LINEB Switch", "LINEB Input"},
+
+	/* Right headphone output mixer */
+	{"Right Headphone Mixer", "Left DAC Switch", "DACL"},
+	{"Right Headphone Mixer", "Right DAC Switch", "DACR"},
+	{"Right Headphone Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right Headphone Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right Headphone Mixer", "LINEA Switch", "LINEA Input"},
+	{"Right Headphone Mixer", "LINEB Switch", "LINEB Input"},
+
+	/* Left speaker output mixer */
+	{"Left Speaker Mixer", "Left DAC Switch", "DACL"},
+	{"Left Speaker Mixer", "Right DAC Switch", "DACR"},
+	{"Left Speaker Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left Speaker Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left Speaker Mixer", "LINEA Switch", "LINEA Input"},
+	{"Left Speaker Mixer", "LINEB Switch", "LINEB Input"},
+
+	/* Right speaker output mixer */
+	{"Right Speaker Mixer", "Left DAC Switch", "DACL"},
+	{"Right Speaker Mixer", "Right DAC Switch", "DACR"},
+	{"Right Speaker Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right Speaker Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right Speaker Mixer", "LINEA Switch", "LINEA Input"},
+	{"Right Speaker Mixer", "LINEB Switch", "LINEB Input"},
+
+	/* Left Receiver output mixer */
+	{"Left Receiver Mixer", "Left DAC Switch", "DACL"},
+	{"Left Receiver Mixer", "Right DAC Switch", "DACR"},
+	{"Left Receiver Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left Receiver Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left Receiver Mixer", "LINEA Switch", "LINEA Input"},
+	{"Left Receiver Mixer", "LINEB Switch", "LINEB Input"},
+
+	/* Right Receiver output mixer */
+	{"Right Receiver Mixer", "Left DAC Switch", "DACL"},
+	{"Right Receiver Mixer", "Right DAC Switch", "DACR"},
+	{"Right Receiver Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right Receiver Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right Receiver Mixer", "LINEA Switch", "LINEA Input"},
+	{"Right Receiver Mixer", "LINEB Switch", "LINEB Input"},
+
+	{"MIXHPLSEL Mux", "HP Mixer", "Left Headphone Mixer"},
+
+	/*
+	 * Disable this for lowest power if bypassing
+	 * the DAC with an analog signal
+	 */
+	{"HP Left Out", NULL, "DACL"},
+	{"HP Left Out", NULL, "MIXHPLSEL Mux"},
+
+	{"MIXHPRSEL Mux", "HP Mixer", "Right Headphone Mixer"},
+
+	/*
+	 * Disable this for lowest power if bypassing
+	 * the DAC with an analog signal
+	 */
+	{"HP Right Out", NULL, "DACR"},
+	{"HP Right Out", NULL, "MIXHPRSEL Mux"},
+
+	{"SPK Left Out", NULL, "Left Speaker Mixer"},
+	{"SPK Right Out", NULL, "Right Speaker Mixer"},
+	{"RCV Left Out", NULL, "Left Receiver Mixer"},
+
+	{"LINMOD Mux", "Left and Right", "Right Receiver Mixer"},
+	{"LINMOD Mux", "Left Only",  "Left Receiver Mixer"},
+	{"RCV Right Out", NULL, "LINMOD Mux"},
+
+	{"HPL", NULL, "HP Left Out"},
+	{"HPR", NULL, "HP Right Out"},
+	{"SPKL", NULL, "SPK Left Out"},
+	{"SPKR", NULL, "SPK Right Out"},
+	{"RCVL", NULL, "RCV Left Out"},
+	{"RCVR", NULL, "RCV Right Out"},
+};
+
+static const struct snd_soc_dapm_route max98091_dapm_routes[] = {
+	/* DMIC inputs */
+	{"DMIC3", NULL, "DMIC3_ENA"},
+	{"DMIC4", NULL, "DMIC4_ENA"},
+	{"DMIC3", NULL, "AHPF"},
+	{"DMIC4", NULL, "AHPF"},
+};
+
+static int max98090_add_widgets(struct snd_soc_component *component)
+{
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_add_component_controls(component, max98090_snd_controls,
+		ARRAY_SIZE(max98090_snd_controls));
+
+	if (max98090->devtype == MAX98091) {
+		snd_soc_add_component_controls(component, max98091_snd_controls,
+			ARRAY_SIZE(max98091_snd_controls));
+	}
+
+	snd_soc_dapm_new_controls(dapm, max98090_dapm_widgets,
+		ARRAY_SIZE(max98090_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, max98090_dapm_routes,
+		ARRAY_SIZE(max98090_dapm_routes));
+
+	if (max98090->devtype == MAX98091) {
+		snd_soc_dapm_new_controls(dapm, max98091_dapm_widgets,
+			ARRAY_SIZE(max98091_dapm_widgets));
+
+		snd_soc_dapm_add_routes(dapm, max98091_dapm_routes,
+			ARRAY_SIZE(max98091_dapm_routes));
+	}
+
+	return 0;
+}
+
+static const int pclk_rates[] = {
+	12000000, 12000000, 13000000, 13000000,
+	16000000, 16000000, 19200000, 19200000
+};
+
+static const int lrclk_rates[] = {
+	8000, 16000, 8000, 16000,
+	8000, 16000, 8000, 16000
+};
+
+static const int user_pclk_rates[] = {
+	13000000, 13000000, 19200000, 19200000,
+};
+
+static const int user_lrclk_rates[] = {
+	44100, 48000, 44100, 48000,
+};
+
+static const unsigned long long ni_value[] = {
+	3528, 768, 441, 8
+};
+
+static const unsigned long long mi_value[] = {
+	8125, 1625, 1500, 25
+};
+
+static void max98090_configure_bclk(struct snd_soc_component *component)
+{
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+	unsigned long long ni;
+	int i;
+
+	if (!max98090->sysclk) {
+		dev_err(component->dev, "No SYSCLK configured\n");
+		return;
+	}
+
+	if (!max98090->bclk || !max98090->lrclk) {
+		dev_err(component->dev, "No audio clocks configured\n");
+		return;
+	}
+
+	/* Skip configuration when operating as slave */
+	if (!(snd_soc_component_read32(component, M98090_REG_MASTER_MODE) &
+		M98090_MAS_MASK)) {
+		return;
+	}
+
+	/* Check for supported PCLK to LRCLK ratios */
+	for (i = 0; i < ARRAY_SIZE(pclk_rates); i++) {
+		if ((pclk_rates[i] == max98090->sysclk) &&
+			(lrclk_rates[i] == max98090->lrclk)) {
+			dev_dbg(component->dev,
+				"Found supported PCLK to LRCLK rates 0x%x\n",
+				i + 0x8);
+
+			snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
+				M98090_FREQ_MASK,
+				(i + 0x8) << M98090_FREQ_SHIFT);
+			snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
+				M98090_USE_M1_MASK, 0);
+			return;
+		}
+	}
+
+	/* Check for user calculated MI and NI ratios */
+	for (i = 0; i < ARRAY_SIZE(user_pclk_rates); i++) {
+		if ((user_pclk_rates[i] == max98090->sysclk) &&
+			(user_lrclk_rates[i] == max98090->lrclk)) {
+			dev_dbg(component->dev,
+				"Found user supported PCLK to LRCLK rates\n");
+			dev_dbg(component->dev, "i %d ni %lld mi %lld\n",
+				i, ni_value[i], mi_value[i]);
+
+			snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
+				M98090_FREQ_MASK, 0);
+			snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
+				M98090_USE_M1_MASK,
+					1 << M98090_USE_M1_SHIFT);
+
+			snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_MSB,
+				(ni_value[i] >> 8) & 0x7F);
+			snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_LSB,
+				ni_value[i] & 0xFF);
+			snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_MI_MSB,
+				(mi_value[i] >> 8) & 0x7F);
+			snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_MI_LSB,
+				mi_value[i] & 0xFF);
+
+			return;
+		}
+	}
+
+	/*
+	 * Calculate based on MI = 65536 (not as good as either method above)
+	 */
+	snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
+		M98090_FREQ_MASK, 0);
+	snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
+		M98090_USE_M1_MASK, 0);
+
+	/*
+	 * Configure NI when operating as master
+	 * Note: There is a small, but significant audio quality improvement
+	 * by calculating ni and mi.
+	 */
+	ni = 65536ULL * (max98090->lrclk < 50000 ? 96ULL : 48ULL)
+			* (unsigned long long int)max98090->lrclk;
+	do_div(ni, (unsigned long long int)max98090->sysclk);
+	dev_info(component->dev, "No better method found\n");
+	dev_info(component->dev, "Calculating ni %lld with mi 65536\n", ni);
+	snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_MSB,
+		(ni >> 8) & 0x7F);
+	snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_LSB, ni & 0xFF);
+}
+
+static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
+				 unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+	struct max98090_cdata *cdata;
+	u8 regval;
+
+	max98090->dai_fmt = fmt;
+	cdata = &max98090->dai[0];
+
+	if (fmt != cdata->fmt) {
+		cdata->fmt = fmt;
+
+		regval = 0;
+		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+		case SND_SOC_DAIFMT_CBS_CFS:
+			/* Set to slave mode PLL - MAS mode off */
+			snd_soc_component_write(component,
+				M98090_REG_CLOCK_RATIO_NI_MSB, 0x00);
+			snd_soc_component_write(component,
+				M98090_REG_CLOCK_RATIO_NI_LSB, 0x00);
+			snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE,
+				M98090_USE_M1_MASK, 0);
+			max98090->master = false;
+			break;
+		case SND_SOC_DAIFMT_CBM_CFM:
+			/* Set to master mode */
+			if (max98090->tdm_slots == 4) {
+				/* TDM */
+				regval |= M98090_MAS_MASK |
+					M98090_BSEL_64;
+			} else if (max98090->tdm_slots == 3) {
+				/* TDM */
+				regval |= M98090_MAS_MASK |
+					M98090_BSEL_48;
+			} else {
+				/* Few TDM slots, or No TDM */
+				regval |= M98090_MAS_MASK |
+					M98090_BSEL_32;
+			}
+			max98090->master = true;
+			break;
+		case SND_SOC_DAIFMT_CBS_CFM:
+		case SND_SOC_DAIFMT_CBM_CFS:
+		default:
+			dev_err(component->dev, "DAI clock mode unsupported");
+			return -EINVAL;
+		}
+		snd_soc_component_write(component, M98090_REG_MASTER_MODE, regval);
+
+		regval = 0;
+		switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+		case SND_SOC_DAIFMT_I2S:
+			regval |= M98090_DLY_MASK;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			break;
+		case SND_SOC_DAIFMT_RIGHT_J:
+			regval |= M98090_RJ_MASK;
+			break;
+		case SND_SOC_DAIFMT_DSP_A:
+			/* Not supported mode */
+		default:
+			dev_err(component->dev, "DAI format unsupported");
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			regval |= M98090_WCI_MASK;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			regval |= M98090_BCI_MASK;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			regval |= M98090_BCI_MASK|M98090_WCI_MASK;
+			break;
+		default:
+			dev_err(component->dev, "DAI invert mode unsupported");
+			return -EINVAL;
+		}
+
+		/*
+		 * This accommodates an inverted logic in the MAX98090 chip
+		 * for Bit Clock Invert (BCI). The inverted logic is only
+		 * seen for the case of TDM mode. The remaining cases have
+		 * normal logic.
+		 */
+		if (max98090->tdm_slots > 1)
+			regval ^= M98090_BCI_MASK;
+
+		snd_soc_component_write(component,
+			M98090_REG_INTERFACE_FORMAT, regval);
+	}
+
+	return 0;
+}
+
+static int max98090_set_tdm_slot(struct snd_soc_dai *codec_dai,
+	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+	struct max98090_cdata *cdata;
+	cdata = &max98090->dai[0];
+
+	if (slots < 0 || slots > 4)
+		return -EINVAL;
+
+	max98090->tdm_slots = slots;
+	max98090->tdm_width = slot_width;
+
+	if (max98090->tdm_slots > 1) {
+		/* SLOTL SLOTR SLOTDLY */
+		snd_soc_component_write(component, M98090_REG_TDM_FORMAT,
+			0 << M98090_TDM_SLOTL_SHIFT |
+			1 << M98090_TDM_SLOTR_SHIFT |
+			0 << M98090_TDM_SLOTDLY_SHIFT);
+
+		/* FSW TDM */
+		snd_soc_component_update_bits(component, M98090_REG_TDM_CONTROL,
+			M98090_TDM_MASK,
+			M98090_TDM_MASK);
+	}
+
+	/*
+	 * Normally advisable to set TDM first, but this permits either order
+	 */
+	cdata->fmt = 0;
+	max98090_dai_set_fmt(codec_dai, max98090->dai_fmt);
+
+	return 0;
+}
+
+static int max98090_set_bias_level(struct snd_soc_component *component,
+				   enum snd_soc_bias_level level)
+{
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/*
+		 * SND_SOC_BIAS_PREPARE is called while preparing for a
+		 * transition to ON or away from ON. If current bias_level
+		 * is SND_SOC_BIAS_ON, then it is preparing for a transition
+		 * away from ON. Disable the clock in that case, otherwise
+		 * enable it.
+		 */
+		if (IS_ERR(max98090->mclk))
+			break;
+
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
+			clk_disable_unprepare(max98090->mclk);
+		} else {
+			ret = clk_prepare_enable(max98090->mclk);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regcache_sync(max98090->regmap);
+			if (ret != 0) {
+				dev_err(component->dev,
+					"Failed to sync cache: %d\n", ret);
+				return ret;
+			}
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* Set internal pull-up to lowest power mode */
+		snd_soc_component_update_bits(component, M98090_REG_JACK_DETECT,
+			M98090_JDWK_MASK, M98090_JDWK_MASK);
+		regcache_mark_dirty(max98090->regmap);
+		break;
+	}
+	return 0;
+}
+
+static const int dmic_divisors[] = { 2, 3, 4, 5, 6, 8 };
+
+static const int comp_lrclk_rates[] = {
+	8000, 16000, 32000, 44100, 48000, 96000
+};
+
+struct dmic_table {
+	int pclk;
+	struct {
+		int freq;
+		int comp[6]; /* One each for 8, 16, 32, 44.1, 48, and 96 kHz */
+	} settings[6]; /* One for each dmic divisor. */
+};
+
+static const struct dmic_table dmic_table[] = { /* One for each pclk freq. */
+	{
+		.pclk = 11289600,
+		.settings = {
+			{ .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+		},
+	},
+	{
+		.pclk = 12000000,
+		.settings = {
+			{ .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+		}
+	},
+	{
+		.pclk = 12288000,
+		.settings = {
+			{ .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+			{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+		}
+	},
+	{
+		.pclk = 13000000,
+		.settings = {
+			{ .freq = 2, .comp = { 7, 8, 1, 1, 1, 1 } },
+			{ .freq = 1, .comp = { 7, 8, 0, 0, 0, 0 } },
+			{ .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
+			{ .freq = 0, .comp = { 7, 8, 4, 4, 5, 5 } },
+			{ .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
+			{ .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
+		}
+	},
+	{
+		.pclk = 19200000,
+		.settings = {
+			{ .freq = 2, .comp = { 0, 0, 0, 0, 0, 0 } },
+			{ .freq = 1, .comp = { 7, 8, 1, 1, 1, 1 } },
+			{ .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
+			{ .freq = 0, .comp = { 7, 8, 2, 2, 3, 3 } },
+			{ .freq = 0, .comp = { 7, 8, 1, 1, 2, 2 } },
+			{ .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
+		}
+	},
+};
+
+static int max98090_find_divisor(int target_freq, int pclk)
+{
+	int current_diff = INT_MAX;
+	int test_diff = INT_MAX;
+	int divisor_index = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dmic_divisors); i++) {
+		test_diff = abs(target_freq - (pclk / dmic_divisors[i]));
+		if (test_diff < current_diff) {
+			current_diff = test_diff;
+			divisor_index = i;
+		}
+	}
+
+	return divisor_index;
+}
+
+static int max98090_find_closest_pclk(int pclk)
+{
+	int m1;
+	int m2;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dmic_table); i++) {
+		if (pclk == dmic_table[i].pclk)
+			return i;
+		if (pclk < dmic_table[i].pclk) {
+			if (i == 0)
+				return i;
+			m1 = pclk - dmic_table[i-1].pclk;
+			m2 = dmic_table[i].pclk - pclk;
+			if (m1 < m2)
+				return i - 1;
+			else
+				return i;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int max98090_configure_dmic(struct max98090_priv *max98090,
+				   int target_dmic_clk, int pclk, int fs)
+{
+	int micclk_index;
+	int pclk_index;
+	int dmic_freq;
+	int dmic_comp;
+	int i;
+
+	pclk_index = max98090_find_closest_pclk(pclk);
+	if (pclk_index < 0)
+		return pclk_index;
+
+	micclk_index = max98090_find_divisor(target_dmic_clk, pclk);
+
+	for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) {
+		if (fs <= (comp_lrclk_rates[i] + comp_lrclk_rates[i+1]) / 2)
+			break;
+	}
+
+	dmic_freq = dmic_table[pclk_index].settings[micclk_index].freq;
+	dmic_comp = dmic_table[pclk_index].settings[micclk_index].comp[i];
+
+	regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_ENABLE,
+			   M98090_MICCLK_MASK,
+			   micclk_index << M98090_MICCLK_SHIFT);
+
+	regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_CONFIG,
+			   M98090_DMIC_COMP_MASK | M98090_DMIC_FREQ_MASK,
+			   dmic_comp << M98090_DMIC_COMP_SHIFT |
+			   dmic_freq << M98090_DMIC_FREQ_SHIFT);
+
+	return 0;
+}
+
+static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+	struct max98090_cdata *cdata;
+
+	cdata = &max98090->dai[0];
+	max98090->bclk = snd_soc_params_to_bclk(params);
+	if (params_channels(params) == 1)
+		max98090->bclk *= 2;
+
+	max98090->lrclk = params_rate(params);
+
+	switch (params_width(params)) {
+	case 16:
+		snd_soc_component_update_bits(component, M98090_REG_INTERFACE_FORMAT,
+			M98090_WS_MASK, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (max98090->master)
+		max98090_configure_bclk(component);
+
+	cdata->rate = max98090->lrclk;
+
+	/* Update filter mode */
+	if (max98090->lrclk < 24000)
+		snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG,
+			M98090_MODE_MASK, 0);
+	else
+		snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG,
+			M98090_MODE_MASK, M98090_MODE_MASK);
+
+	/* Update sample rate mode */
+	if (max98090->lrclk < 50000)
+		snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG,
+			M98090_DHF_MASK, 0);
+	else
+		snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG,
+			M98090_DHF_MASK, M98090_DHF_MASK);
+
+	max98090_configure_dmic(max98090, max98090->dmic_freq, max98090->pclk,
+				max98090->lrclk);
+
+	return 0;
+}
+
+/*
+ * PLL / Sysclk
+ */
+static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
+				   int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+
+	/* Requested clock frequency is already setup */
+	if (freq == max98090->sysclk)
+		return 0;
+
+	if (!IS_ERR(max98090->mclk)) {
+		freq = clk_round_rate(max98090->mclk, freq);
+		clk_set_rate(max98090->mclk, freq);
+	}
+
+	/* Setup clocks for slave mode, and using the PLL
+	 * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+	 *		 0x02 (when master clk is 20MHz to 40MHz)..
+	 *		 0x03 (when master clk is 40MHz to 60MHz)..
+	 */
+	if ((freq >= 10000000) && (freq <= 20000000)) {
+		snd_soc_component_write(component, M98090_REG_SYSTEM_CLOCK,
+			M98090_PSCLK_DIV1);
+		max98090->pclk = freq;
+	} else if ((freq > 20000000) && (freq <= 40000000)) {
+		snd_soc_component_write(component, M98090_REG_SYSTEM_CLOCK,
+			M98090_PSCLK_DIV2);
+		max98090->pclk = freq >> 1;
+	} else if ((freq > 40000000) && (freq <= 60000000)) {
+		snd_soc_component_write(component, M98090_REG_SYSTEM_CLOCK,
+			M98090_PSCLK_DIV4);
+		max98090->pclk = freq >> 2;
+	} else {
+		dev_err(component->dev, "Invalid master clock frequency\n");
+		return -EINVAL;
+	}
+
+	max98090->sysclk = freq;
+
+	return 0;
+}
+
+static int max98090_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	int regval;
+
+	regval = mute ? M98090_DVM_MASK : 0;
+	snd_soc_component_update_bits(component, M98090_REG_DAI_PLAYBACK_LEVEL,
+		M98090_DVM_MASK, regval);
+
+	return 0;
+}
+
+static int max98090_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (!max98090->master && dai->active == 1)
+			queue_delayed_work(system_power_efficient_wq,
+					   &max98090->pll_det_enable_work,
+					   msecs_to_jiffies(10));
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (!max98090->master && dai->active == 1)
+			schedule_work(&max98090->pll_det_disable_work);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static void max98090_pll_det_enable_work(struct work_struct *work)
+{
+	struct max98090_priv *max98090 =
+		container_of(work, struct max98090_priv,
+			     pll_det_enable_work.work);
+	struct snd_soc_component *component = max98090->component;
+	unsigned int status, mask;
+
+	/*
+	 * Clear status register in order to clear possibly already occurred
+	 * PLL unlock. If PLL hasn't still locked, the status will be set
+	 * again and PLL unlock interrupt will occur.
+	 * Note this will clear all status bits
+	 */
+	regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status);
+
+	/*
+	 * Queue jack work in case jack state has just changed but handler
+	 * hasn't run yet
+	 */
+	regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask);
+	status &= mask;
+	if (status & M98090_JDET_MASK)
+		queue_delayed_work(system_power_efficient_wq,
+				   &max98090->jack_work,
+				   msecs_to_jiffies(100));
+
+	/* Enable PLL unlock interrupt */
+	snd_soc_component_update_bits(component, M98090_REG_INTERRUPT_S,
+			    M98090_IULK_MASK,
+			    1 << M98090_IULK_SHIFT);
+}
+
+static void max98090_pll_det_disable_work(struct work_struct *work)
+{
+	struct max98090_priv *max98090 =
+		container_of(work, struct max98090_priv, pll_det_disable_work);
+	struct snd_soc_component *component = max98090->component;
+
+	cancel_delayed_work_sync(&max98090->pll_det_enable_work);
+
+	/* Disable PLL unlock interrupt */
+	snd_soc_component_update_bits(component, M98090_REG_INTERRUPT_S,
+			    M98090_IULK_MASK, 0);
+}
+
+static void max98090_pll_work(struct work_struct *work)
+{
+	struct max98090_priv *max98090 =
+		container_of(work, struct max98090_priv, pll_work);
+	struct snd_soc_component *component = max98090->component;
+
+	if (!snd_soc_component_is_active(component))
+		return;
+
+	dev_info_ratelimited(component->dev, "PLL unlocked\n");
+
+	/* Toggle shutdown OFF then ON */
+	snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
+			    M98090_SHDNN_MASK, 0);
+	msleep(10);
+	snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
+			    M98090_SHDNN_MASK, M98090_SHDNN_MASK);
+
+	/* Give PLL time to lock */
+	msleep(10);
+}
+
+static void max98090_jack_work(struct work_struct *work)
+{
+	struct max98090_priv *max98090 = container_of(work,
+		struct max98090_priv,
+		jack_work.work);
+	struct snd_soc_component *component = max98090->component;
+	int status = 0;
+	int reg;
+
+	/* Read a second time */
+	if (max98090->jack_state == M98090_JACK_STATE_NO_HEADSET) {
+
+		/* Strong pull up allows mic detection */
+		snd_soc_component_update_bits(component, M98090_REG_JACK_DETECT,
+			M98090_JDWK_MASK, 0);
+
+		msleep(50);
+
+		reg = snd_soc_component_read32(component, M98090_REG_JACK_STATUS);
+
+		/* Weak pull up allows only insertion detection */
+		snd_soc_component_update_bits(component, M98090_REG_JACK_DETECT,
+			M98090_JDWK_MASK, M98090_JDWK_MASK);
+	} else {
+		reg = snd_soc_component_read32(component, M98090_REG_JACK_STATUS);
+	}
+
+	reg = snd_soc_component_read32(component, M98090_REG_JACK_STATUS);
+
+	switch (reg & (M98090_LSNS_MASK | M98090_JKSNS_MASK)) {
+		case M98090_LSNS_MASK | M98090_JKSNS_MASK:
+			dev_dbg(component->dev, "No Headset Detected\n");
+
+			max98090->jack_state = M98090_JACK_STATE_NO_HEADSET;
+
+			status |= 0;
+
+			break;
+
+		case 0:
+			if (max98090->jack_state ==
+				M98090_JACK_STATE_HEADSET) {
+
+				dev_dbg(component->dev,
+					"Headset Button Down Detected\n");
+
+				/*
+				 * max98090_headset_button_event(codec)
+				 * could be defined, then called here.
+				 */
+
+				status |= SND_JACK_HEADSET;
+				status |= SND_JACK_BTN_0;
+
+				break;
+			}
+
+			/* Line is reported as Headphone */
+			/* Nokia Headset is reported as Headphone */
+			/* Mono Headphone is reported as Headphone */
+			dev_dbg(component->dev, "Headphone Detected\n");
+
+			max98090->jack_state = M98090_JACK_STATE_HEADPHONE;
+
+			status |= SND_JACK_HEADPHONE;
+
+			break;
+
+		case M98090_JKSNS_MASK:
+			dev_dbg(component->dev, "Headset Detected\n");
+
+			max98090->jack_state = M98090_JACK_STATE_HEADSET;
+
+			status |= SND_JACK_HEADSET;
+
+			break;
+
+		default:
+			dev_dbg(component->dev, "Unrecognized Jack Status\n");
+			break;
+	}
+
+	snd_soc_jack_report(max98090->jack, status,
+			    SND_JACK_HEADSET | SND_JACK_BTN_0);
+}
+
+static irqreturn_t max98090_interrupt(int irq, void *data)
+{
+	struct max98090_priv *max98090 = data;
+	struct snd_soc_component *component = max98090->component;
+	int ret;
+	unsigned int mask;
+	unsigned int active;
+
+	/* Treat interrupt before codec is initialized as spurious */
+	if (component == NULL)
+		return IRQ_NONE;
+
+	dev_dbg(component->dev, "***** max98090_interrupt *****\n");
+
+	ret = regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask);
+
+	if (ret != 0) {
+		dev_err(component->dev,
+			"failed to read M98090_REG_INTERRUPT_S: %d\n",
+			ret);
+		return IRQ_NONE;
+	}
+
+	ret = regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &active);
+
+	if (ret != 0) {
+		dev_err(component->dev,
+			"failed to read M98090_REG_DEVICE_STATUS: %d\n",
+			ret);
+		return IRQ_NONE;
+	}
+
+	dev_dbg(component->dev, "active=0x%02x mask=0x%02x -> active=0x%02x\n",
+		active, mask, active & mask);
+
+	active &= mask;
+
+	if (!active)
+		return IRQ_NONE;
+
+	if (active & M98090_CLD_MASK)
+		dev_err(component->dev, "M98090_CLD_MASK\n");
+
+	if (active & M98090_SLD_MASK)
+		dev_dbg(component->dev, "M98090_SLD_MASK\n");
+
+	if (active & M98090_ULK_MASK) {
+		dev_dbg(component->dev, "M98090_ULK_MASK\n");
+		schedule_work(&max98090->pll_work);
+	}
+
+	if (active & M98090_JDET_MASK) {
+		dev_dbg(component->dev, "M98090_JDET_MASK\n");
+
+		pm_wakeup_event(component->dev, 100);
+
+		queue_delayed_work(system_power_efficient_wq,
+				   &max98090->jack_work,
+				   msecs_to_jiffies(100));
+	}
+
+	if (active & M98090_DRCACT_MASK)
+		dev_dbg(component->dev, "M98090_DRCACT_MASK\n");
+
+	if (active & M98090_DRCCLP_MASK)
+		dev_err(component->dev, "M98090_DRCCLP_MASK\n");
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * max98090_mic_detect - Enable microphone detection via the MAX98090 IRQ
+ *
+ * @component:  MAX98090 component
+ * @jack:   jack to report detection events on
+ *
+ * Enable microphone detection via IRQ on the MAX98090.  If GPIOs are
+ * being used to bring out signals to the processor then only platform
+ * data configuration is needed for MAX98090 and processor GPIOs should
+ * be configured using snd_soc_jack_add_gpios() instead.
+ *
+ * If no jack is supplied detection will be disabled.
+ */
+int max98090_mic_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *jack)
+{
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "max98090_mic_detect\n");
+
+	max98090->jack = jack;
+	if (jack) {
+		snd_soc_component_update_bits(component, M98090_REG_INTERRUPT_S,
+			M98090_IJDET_MASK,
+			1 << M98090_IJDET_SHIFT);
+	} else {
+		snd_soc_component_update_bits(component, M98090_REG_INTERRUPT_S,
+			M98090_IJDET_MASK,
+			0);
+	}
+
+	/* Send an initial empty report */
+	snd_soc_jack_report(max98090->jack, 0,
+			    SND_JACK_HEADSET | SND_JACK_BTN_0);
+
+	queue_delayed_work(system_power_efficient_wq,
+			   &max98090->jack_work,
+			   msecs_to_jiffies(100));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(max98090_mic_detect);
+
+#define MAX98090_RATES SNDRV_PCM_RATE_8000_96000
+#define MAX98090_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops max98090_dai_ops = {
+	.set_sysclk = max98090_dai_set_sysclk,
+	.set_fmt = max98090_dai_set_fmt,
+	.set_tdm_slot = max98090_set_tdm_slot,
+	.hw_params = max98090_dai_hw_params,
+	.digital_mute = max98090_dai_digital_mute,
+	.trigger = max98090_dai_trigger,
+};
+
+static struct snd_soc_dai_driver max98090_dai[] = {
+{
+	.name = "HiFi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = MAX98090_RATES,
+		.formats = MAX98090_FORMATS,
+	},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = MAX98090_RATES,
+		.formats = MAX98090_FORMATS,
+	},
+	 .ops = &max98090_dai_ops,
+}
+};
+
+static int max98090_probe(struct snd_soc_component *component)
+{
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+	struct max98090_cdata *cdata;
+	enum max98090_type devtype;
+	int ret = 0;
+	int err;
+	unsigned int micbias;
+
+	dev_dbg(component->dev, "max98090_probe\n");
+
+	max98090->mclk = devm_clk_get(component->dev, "mclk");
+	if (PTR_ERR(max98090->mclk) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	max98090->component = component;
+
+	/* Reset the codec, the DSP core, and disable all interrupts */
+	max98090_reset(max98090);
+
+	/* Initialize private data */
+
+	max98090->sysclk = (unsigned)-1;
+	max98090->pclk = (unsigned)-1;
+	max98090->master = false;
+
+	cdata = &max98090->dai[0];
+	cdata->rate = (unsigned)-1;
+	cdata->fmt  = (unsigned)-1;
+
+	max98090->lin_state = 0;
+	max98090->pa1en = 0;
+	max98090->pa2en = 0;
+
+	ret = snd_soc_component_read32(component, M98090_REG_REVISION_ID);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to read device revision: %d\n",
+			ret);
+		goto err_access;
+	}
+
+	if ((ret >= M98090_REVA) && (ret <= M98090_REVA + 0x0f)) {
+		devtype = MAX98090;
+		dev_info(component->dev, "MAX98090 REVID=0x%02x\n", ret);
+	} else if ((ret >= M98091_REVA) && (ret <= M98091_REVA + 0x0f)) {
+		devtype = MAX98091;
+		dev_info(component->dev, "MAX98091 REVID=0x%02x\n", ret);
+	} else {
+		devtype = MAX98090;
+		dev_err(component->dev, "Unrecognized revision 0x%02x\n", ret);
+	}
+
+	if (max98090->devtype != devtype) {
+		dev_warn(component->dev, "Mismatch in DT specified CODEC type.\n");
+		max98090->devtype = devtype;
+	}
+
+	max98090->jack_state = M98090_JACK_STATE_NO_HEADSET;
+
+	INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work);
+	INIT_DELAYED_WORK(&max98090->pll_det_enable_work,
+			  max98090_pll_det_enable_work);
+	INIT_WORK(&max98090->pll_det_disable_work,
+		  max98090_pll_det_disable_work);
+	INIT_WORK(&max98090->pll_work, max98090_pll_work);
+
+	/* Enable jack detection */
+	snd_soc_component_write(component, M98090_REG_JACK_DETECT,
+		M98090_JDETEN_MASK | M98090_JDEB_25MS);
+
+	/*
+	 * Clear any old interrupts.
+	 * An old interrupt ocurring prior to installing the ISR
+	 * can keep a new interrupt from generating a trigger.
+	 */
+	snd_soc_component_read32(component, M98090_REG_DEVICE_STATUS);
+
+	/* High Performance is default */
+	snd_soc_component_update_bits(component, M98090_REG_DAC_CONTROL,
+		M98090_DACHP_MASK,
+		1 << M98090_DACHP_SHIFT);
+	snd_soc_component_update_bits(component, M98090_REG_DAC_CONTROL,
+		M98090_PERFMODE_MASK,
+		0 << M98090_PERFMODE_SHIFT);
+	snd_soc_component_update_bits(component, M98090_REG_ADC_CONTROL,
+		M98090_ADCHP_MASK,
+		1 << M98090_ADCHP_SHIFT);
+
+	/* Turn on VCM bandgap reference */
+	snd_soc_component_write(component, M98090_REG_BIAS_CONTROL,
+		M98090_VCM_MODE_MASK);
+
+	err = device_property_read_u32(component->dev, "maxim,micbias", &micbias);
+	if (err) {
+		micbias = M98090_MBVSEL_2V8;
+		dev_info(component->dev, "use default 2.8v micbias\n");
+	} else if (micbias > M98090_MBVSEL_2V8) {
+		dev_err(component->dev, "micbias out of range 0x%x\n", micbias);
+		micbias = M98090_MBVSEL_2V8;
+	}
+
+	snd_soc_component_update_bits(component, M98090_REG_MIC_BIAS_VOLTAGE,
+		M98090_MBVSEL_MASK, micbias);
+
+	max98090_add_widgets(component);
+
+err_access:
+	return ret;
+}
+
+static void max98090_remove(struct snd_soc_component *component)
+{
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+
+	cancel_delayed_work_sync(&max98090->jack_work);
+	cancel_delayed_work_sync(&max98090->pll_det_enable_work);
+	cancel_work_sync(&max98090->pll_det_disable_work);
+	cancel_work_sync(&max98090->pll_work);
+	max98090->component = NULL;
+}
+
+static void max98090_seq_notifier(struct snd_soc_component *component,
+	enum snd_soc_dapm_type event, int subseq)
+{
+	struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
+
+	if (max98090->shdn_pending) {
+		snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
+				M98090_SHDNN_MASK, 0);
+		msleep(40);
+		snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN,
+				M98090_SHDNN_MASK, M98090_SHDNN_MASK);
+		max98090->shdn_pending = false;
+	}
+}
+
+static const struct snd_soc_component_driver soc_component_dev_max98090 = {
+	.probe			= max98090_probe,
+	.remove			= max98090_remove,
+	.seq_notifier		= max98090_seq_notifier,
+	.set_bias_level		= max98090_set_bias_level,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config max98090_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = MAX98090_MAX_REGISTER,
+	.reg_defaults = max98090_reg,
+	.num_reg_defaults = ARRAY_SIZE(max98090_reg),
+	.volatile_reg = max98090_volatile_register,
+	.readable_reg = max98090_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int max98090_i2c_probe(struct i2c_client *i2c,
+				 const struct i2c_device_id *i2c_id)
+{
+	struct max98090_priv *max98090;
+	const struct acpi_device_id *acpi_id;
+	kernel_ulong_t driver_data = 0;
+	int ret;
+
+	pr_debug("max98090_i2c_probe\n");
+
+	max98090 = devm_kzalloc(&i2c->dev, sizeof(struct max98090_priv),
+		GFP_KERNEL);
+	if (max98090 == NULL)
+		return -ENOMEM;
+
+	if (ACPI_HANDLE(&i2c->dev)) {
+		acpi_id = acpi_match_device(i2c->dev.driver->acpi_match_table,
+					    &i2c->dev);
+		if (!acpi_id) {
+			dev_err(&i2c->dev, "No driver data\n");
+			return -EINVAL;
+		}
+		driver_data = acpi_id->driver_data;
+	} else if (i2c_id) {
+		driver_data = i2c_id->driver_data;
+	}
+
+	max98090->devtype = driver_data;
+	i2c_set_clientdata(i2c, max98090);
+	max98090->pdata = i2c->dev.platform_data;
+
+	ret = of_property_read_u32(i2c->dev.of_node, "maxim,dmic-freq",
+				   &max98090->dmic_freq);
+	if (ret < 0)
+		max98090->dmic_freq = MAX98090_DEFAULT_DMIC_FREQ;
+
+	max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap);
+	if (IS_ERR(max98090->regmap)) {
+		ret = PTR_ERR(max98090->regmap);
+		dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
+		goto err_enable;
+	}
+
+	ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+		max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+		"max98090_interrupt", max98090);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "request_irq failed: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_max98090, max98090_dai,
+			ARRAY_SIZE(max98090_dai));
+err_enable:
+	return ret;
+}
+
+static void max98090_i2c_shutdown(struct i2c_client *i2c)
+{
+	struct max98090_priv *max98090 = dev_get_drvdata(&i2c->dev);
+
+	/*
+	 * Enable volume smoothing, disable zero cross.  This will cause
+	 * a quick 40ms ramp to mute on shutdown.
+	 */
+	regmap_write(max98090->regmap,
+		M98090_REG_LEVEL_CONTROL, M98090_VSENN_MASK);
+	regmap_write(max98090->regmap,
+		M98090_REG_DEVICE_SHUTDOWN, 0x00);
+	msleep(40);
+}
+
+static int max98090_i2c_remove(struct i2c_client *client)
+{
+	max98090_i2c_shutdown(client);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int max98090_runtime_resume(struct device *dev)
+{
+	struct max98090_priv *max98090 = dev_get_drvdata(dev);
+
+	regcache_cache_only(max98090->regmap, false);
+
+	max98090_reset(max98090);
+
+	regcache_sync(max98090->regmap);
+
+	return 0;
+}
+
+static int max98090_runtime_suspend(struct device *dev)
+{
+	struct max98090_priv *max98090 = dev_get_drvdata(dev);
+
+	regcache_cache_only(max98090->regmap, true);
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int max98090_resume(struct device *dev)
+{
+	struct max98090_priv *max98090 = dev_get_drvdata(dev);
+	unsigned int status;
+
+	regcache_mark_dirty(max98090->regmap);
+
+	max98090_reset(max98090);
+
+	/* clear IRQ status */
+	regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status);
+
+	regcache_sync(max98090->regmap);
+
+	return 0;
+}
+
+static int max98090_suspend(struct device *dev)
+{
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops max98090_pm = {
+	SET_RUNTIME_PM_OPS(max98090_runtime_suspend,
+		max98090_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(max98090_suspend, max98090_resume)
+};
+
+static const struct i2c_device_id max98090_i2c_id[] = {
+	{ "max98090", MAX98090 },
+	{ "max98091", MAX98091 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max98090_i2c_id);
+
+static const struct of_device_id max98090_of_match[] = {
+	{ .compatible = "maxim,max98090", },
+	{ .compatible = "maxim,max98091", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max98090_of_match);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id max98090_acpi_match[] = {
+	{ "193C9890", MAX98090 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, max98090_acpi_match);
+#endif
+
+static struct i2c_driver max98090_i2c_driver = {
+	.driver = {
+		.name = "max98090",
+		.pm = &max98090_pm,
+		.of_match_table = of_match_ptr(max98090_of_match),
+		.acpi_match_table = ACPI_PTR(max98090_acpi_match),
+	},
+	.probe  = max98090_i2c_probe,
+	.shutdown = max98090_i2c_shutdown,
+	.remove = max98090_i2c_remove,
+	.id_table = max98090_i2c_id,
+};
+
+module_i2c_driver(max98090_i2c_driver);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98090 driver");
+MODULE_AUTHOR("Peter Hsiang, Jesse Marroqin, Jerry Wong");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h
new file mode 100644
index 0000000..b1572a2
--- /dev/null
+++ b/sound/soc/codecs/max98090.h
@@ -0,0 +1,1552 @@
+/*
+ * max98090.h -- MAX98090 ALSA SoC Audio driver
+ *
+ * Copyright 2011-2012 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX98090_H
+#define _MAX98090_H
+
+/*
+ * The default operating frequency for a DMIC attached to the codec.
+ * This can be overridden by a device tree property.
+ */
+#define MAX98090_DEFAULT_DMIC_FREQ		2500000
+
+/*
+ * MAX98090 Register Definitions
+ */
+
+#define M98090_REG_SOFTWARE_RESET		0x00
+#define M98090_REG_DEVICE_STATUS		0x01
+#define M98090_REG_JACK_STATUS			0x02
+#define M98090_REG_INTERRUPT_S			0x03
+#define M98090_REG_QUICK_SYSTEM_CLOCK		0x04
+#define M98090_REG_QUICK_SAMPLE_RATE		0x05
+#define M98090_REG_DAI_INTERFACE		0x06
+#define M98090_REG_DAC_PATH			0x07
+#define M98090_REG_MIC_DIRECT_TO_ADC		0x08
+#define M98090_REG_LINE_TO_ADC			0x09
+#define M98090_REG_ANALOG_MIC_LOOP		0x0A
+#define M98090_REG_ANALOG_LINE_LOOP		0x0B
+#define M98090_REG_RESERVED			0x0C
+#define M98090_REG_LINE_INPUT_CONFIG		0x0D
+#define M98090_REG_LINE_INPUT_LEVEL		0x0E
+#define M98090_REG_INPUT_MODE			0x0F
+#define M98090_REG_MIC1_INPUT_LEVEL		0x10
+#define M98090_REG_MIC2_INPUT_LEVEL		0x11
+#define M98090_REG_MIC_BIAS_VOLTAGE		0x12
+#define M98090_REG_DIGITAL_MIC_ENABLE		0x13
+#define M98090_REG_DIGITAL_MIC_CONFIG		0x14
+#define M98090_REG_LEFT_ADC_MIXER		0x15
+#define M98090_REG_RIGHT_ADC_MIXER		0x16
+#define M98090_REG_LEFT_ADC_LEVEL		0x17
+#define M98090_REG_RIGHT_ADC_LEVEL		0x18
+#define M98090_REG_ADC_BIQUAD_LEVEL		0x19
+#define M98090_REG_ADC_SIDETONE			0x1A
+#define M98090_REG_SYSTEM_CLOCK			0x1B
+#define M98090_REG_CLOCK_MODE			0x1C
+#define M98090_REG_CLOCK_RATIO_NI_MSB		0x1D
+#define M98090_REG_CLOCK_RATIO_NI_LSB		0x1E
+#define M98090_REG_CLOCK_RATIO_MI_MSB		0x1F
+#define M98090_REG_CLOCK_RATIO_MI_LSB		0x20
+#define M98090_REG_MASTER_MODE			0x21
+#define M98090_REG_INTERFACE_FORMAT		0x22
+#define M98090_REG_TDM_CONTROL			0x23
+#define M98090_REG_TDM_FORMAT			0x24
+#define M98090_REG_IO_CONFIGURATION		0x25
+#define M98090_REG_FILTER_CONFIG		0x26
+#define M98090_REG_DAI_PLAYBACK_LEVEL		0x27
+#define M98090_REG_DAI_PLAYBACK_LEVEL_EQ	0x28
+#define M98090_REG_LEFT_HP_MIXER		0x29
+#define M98090_REG_RIGHT_HP_MIXER		0x2A
+#define M98090_REG_HP_CONTROL			0x2B
+#define M98090_REG_LEFT_HP_VOLUME		0x2C
+#define M98090_REG_RIGHT_HP_VOLUME		0x2D
+#define M98090_REG_LEFT_SPK_MIXER		0x2E
+#define M98090_REG_RIGHT_SPK_MIXER		0x2F
+#define M98090_REG_SPK_CONTROL			0x30
+#define M98090_REG_LEFT_SPK_VOLUME		0x31
+#define M98090_REG_RIGHT_SPK_VOLUME		0x32
+#define M98090_REG_DRC_TIMING			0x33
+#define M98090_REG_DRC_COMPRESSOR		0x34
+#define M98090_REG_DRC_EXPANDER			0x35
+#define M98090_REG_DRC_GAIN			0x36
+#define M98090_REG_RCV_LOUTL_MIXER		0x37
+#define M98090_REG_RCV_LOUTL_CONTROL		0x38
+#define M98090_REG_RCV_LOUTL_VOLUME		0x39
+#define M98090_REG_LOUTR_MIXER			0x3A
+#define M98090_REG_LOUTR_CONTROL		0x3B
+#define M98090_REG_LOUTR_VOLUME			0x3C
+#define M98090_REG_JACK_DETECT			0x3D
+#define M98090_REG_INPUT_ENABLE			0x3E
+#define M98090_REG_OUTPUT_ENABLE		0x3F
+#define M98090_REG_LEVEL_CONTROL		0x40
+#define M98090_REG_DSP_FILTER_ENABLE		0x41
+#define M98090_REG_BIAS_CONTROL			0x42
+#define M98090_REG_DAC_CONTROL			0x43
+#define M98090_REG_ADC_CONTROL			0x44
+#define M98090_REG_DEVICE_SHUTDOWN		0x45
+#define M98090_REG_EQUALIZER_BASE		0x46
+#define M98090_REG_RECORD_BIQUAD_BASE		0xAF
+#define M98090_REG_DMIC3_VOLUME			0xBE
+#define M98090_REG_DMIC4_VOLUME			0xBF
+#define M98090_REG_DMIC34_BQ_PREATTEN		0xC0
+#define M98090_REG_RECORD_TDM_SLOT		0xC1
+#define M98090_REG_SAMPLE_RATE			0xC2
+#define M98090_REG_DMIC34_BIQUAD_BASE		0xC3
+#define M98090_REG_REVISION_ID			0xFF
+
+#define M98090_REG_CNT				(0xFF+1)
+#define MAX98090_MAX_REGISTER			0xFF
+
+/* MAX98090 Register Bit Fields */
+
+/*
+ * M98090_REG_SOFTWARE_RESET
+ */
+#define M98090_SWRESET_MASK		(1<<7)
+#define M98090_SWRESET_SHIFT		7
+#define M98090_SWRESET_WIDTH		1
+
+/*
+ * M98090_REG_DEVICE_STATUS
+ */
+#define M98090_CLD_MASK			(1<<7)
+#define M98090_CLD_SHIFT		7
+#define M98090_CLD_WIDTH		1
+#define M98090_SLD_MASK			(1<<6)
+#define M98090_SLD_SHIFT		6
+#define M98090_SLD_WIDTH		1
+#define M98090_ULK_MASK			(1<<5)
+#define M98090_ULK_SHIFT		5
+#define M98090_ULK_WIDTH		1
+#define M98090_JDET_MASK		(1<<2)
+#define M98090_JDET_SHIFT		2
+#define M98090_JDET_WIDTH		1
+#define M98090_DRCACT_MASK		(1<<1)
+#define M98090_DRCACT_SHIFT		1
+#define M98090_DRCACT_WIDTH		1
+#define M98090_DRCCLP_MASK		(1<<0)
+#define M98090_DRCCLP_SHIFT		0
+#define M98090_DRCCLP_WIDTH		1
+
+/*
+ * M98090_REG_JACK_STATUS
+ */
+#define M98090_LSNS_MASK		(1<<2)
+#define M98090_LSNS_SHIFT		2
+#define M98090_LSNS_WIDTH		1
+#define M98090_JKSNS_MASK		(1<<1)
+#define M98090_JKSNS_SHIFT		1
+#define M98090_JKSNS_WIDTH		1
+
+/*
+ * M98090_REG_INTERRUPT_S
+ */
+#define M98090_ICLD_MASK		(1<<7)
+#define M98090_ICLD_SHIFT		7
+#define M98090_ICLD_WIDTH		1
+#define M98090_ISLD_MASK		(1<<6)
+#define M98090_ISLD_SHIFT		6
+#define M98090_ISLD_WIDTH		1
+#define M98090_IULK_MASK		(1<<5)
+#define M98090_IULK_SHIFT		5
+#define M98090_IULK_WIDTH		1
+#define M98090_IJDET_MASK		(1<<2)
+#define M98090_IJDET_SHIFT		2
+#define M98090_IJDET_WIDTH		1
+#define M98090_IDRCACT_MASK		(1<<1)
+#define M98090_IDRCACT_SHIFT		1
+#define M98090_IDRCACT_WIDTH		1
+#define M98090_IDRCCLP_MASK		(1<<0)
+#define M98090_IDRCCLP_SHIFT		0
+#define M98090_IDRCCLP_WIDTH		1
+
+/*
+ * M98090_REG_QUICK_SYSTEM_CLOCK
+ */
+#define M98090_26M_MASK			(1<<7)
+#define M98090_26M_SHIFT		7
+#define M98090_26M_WIDTH		1
+#define M98090_19P2M_MASK		(1<<6)
+#define M98090_19P2M_SHIFT		6
+#define M98090_19P2M_WIDTH		1
+#define M98090_13M_MASK			(1<<5)
+#define M98090_13M_SHIFT		5
+#define M98090_13M_WIDTH		1
+#define M98090_12P288M_MASK		(1<<4)
+#define M98090_12P288M_SHIFT		4
+#define M98090_12P288M_WIDTH		1
+#define M98090_12M_MASK			(1<<3)
+#define M98090_12M_SHIFT		3
+#define M98090_12M_WIDTH		1
+#define M98090_11P2896M_MASK		(1<<2)
+#define M98090_11P2896M_SHIFT		2
+#define M98090_11P2896M_WIDTH		1
+#define M98090_256FS_MASK		(1<<0)
+#define M98090_256FS_SHIFT		0
+#define M98090_256FS_WIDTH		1
+#define M98090_CLK_ALL_SHIFT		0
+#define M98090_CLK_ALL_WIDTH		8
+#define M98090_CLK_ALL_NUM		(1<<M98090_CLK_ALL_WIDTH)
+
+/*
+ * M98090_REG_QUICK_SAMPLE_RATE
+ */
+#define M98090_SR_96K_MASK		(1<<5)
+#define M98090_SR_96K_SHIFT		5
+#define M98090_SR_96K_WIDTH		1
+#define M98090_SR_32K_MASK		(1<<4)
+#define M98090_SR_32K_SHIFT		4
+#define M98090_SR_32K_WIDTH		1
+#define M98090_SR_48K_MASK		(1<<3)
+#define M98090_SR_48K_SHIFT		3
+#define M98090_SR_48K_WIDTH		1
+#define M98090_SR_44K1_MASK		(1<<2)
+#define M98090_SR_44K1_SHIFT		2
+#define M98090_SR_44K1_WIDTH		1
+#define M98090_SR_16K_MASK		(1<<1)
+#define M98090_SR_16K_SHIFT		1
+#define M98090_SR_16K_WIDTH		1
+#define M98090_SR_8K_MASK		(1<<0)
+#define M98090_SR_8K_SHIFT		0
+#define M98090_SR_8K_WIDTH		1
+#define M98090_SR_MASK			0x3F
+#define M98090_SR_ALL_SHIFT		0
+#define M98090_SR_ALL_WIDTH		8
+#define M98090_SR_ALL_NUM		(1<<M98090_SR_ALL_WIDTH)
+
+/*
+ * M98090_REG_DAI_INTERFACE
+ */
+#define M98090_RJ_M_MASK		(1<<5)
+#define M98090_RJ_M_SHIFT		5
+#define M98090_RJ_M_WIDTH		1
+#define M98090_RJ_S_MASK		(1<<4)
+#define M98090_RJ_S_SHIFT		4
+#define M98090_RJ_S_WIDTH		1
+#define M98090_LJ_M_MASK		(1<<3)
+#define M98090_LJ_M_SHIFT		3
+#define M98090_LJ_M_WIDTH		1
+#define M98090_LJ_S_MASK		(1<<2)
+#define M98090_LJ_S_SHIFT		2
+#define M98090_LJ_S_WIDTH		1
+#define M98090_I2S_M_MASK		(1<<1)
+#define M98090_I2S_M_SHIFT		1
+#define M98090_I2S_M_WIDTH		1
+#define M98090_I2S_S_MASK		(1<<0)
+#define M98090_I2S_S_SHIFT		0
+#define M98090_I2S_S_WIDTH		1
+#define M98090_DAI_ALL_SHIFT		0
+#define M98090_DAI_ALL_WIDTH		8
+#define M98090_DAI_ALL_NUM		(1<<M98090_DAI_ALL_WIDTH)
+
+/*
+ * M98090_REG_DAC_PATH
+ */
+#define M98090_DIG2_HP_MASK		(1<<7)
+#define M98090_DIG2_HP_SHIFT		7
+#define M98090_DIG2_HP_WIDTH		1
+#define M98090_DIG2_EAR_MASK		(1<<6)
+#define M98090_DIG2_EAR_SHIFT		6
+#define M98090_DIG2_EAR_WIDTH		1
+#define M98090_DIG2_SPK_MASK		(1<<5)
+#define M98090_DIG2_SPK_SHIFT		5
+#define M98090_DIG2_SPK_WIDTH		1
+#define M98090_DIG2_LOUT_MASK		(1<<4)
+#define M98090_DIG2_LOUT_SHIFT		4
+#define M98090_DIG2_LOUT_WIDTH		1
+#define M98090_DIG2_ALL_SHIFT		0
+#define M98090_DIG2_ALL_WIDTH		8
+#define M98090_DIG2_ALL_NUM		(1<<M98090_DIG2_ALL_WIDTH)
+
+/*
+ * M98090_REG_MIC_DIRECT_TO_ADC
+ */
+#define M98090_IN12_MIC1_MASK		(1<<7)
+#define M98090_IN12_MIC1_SHIFT		7
+#define M98090_IN12_MIC1_WIDTH		1
+#define M98090_IN34_MIC2_MASK		(1<<6)
+#define M98090_IN34_MIC2_SHIFT		6
+#define M98090_IN34_MIC2_WIDTH		1
+#define M98090_IN56_MIC1_MASK		(1<<5)
+#define M98090_IN56_MIC1_SHIFT		5
+#define M98090_IN56_MIC1_WIDTH		1
+#define M98090_IN56_MIC2_MASK		(1<<4)
+#define M98090_IN56_MIC2_SHIFT		4
+#define M98090_IN56_MIC2_WIDTH		1
+#define M98090_IN12_DADC_MASK		(1<<3)
+#define M98090_IN12_DADC_SHIFT		3
+#define M98090_IN12_DADC_WIDTH		1
+#define M98090_IN34_DADC_MASK		(1<<2)
+#define M98090_IN34_DADC_SHIFT		2
+#define M98090_IN34_DADC_WIDTH		1
+#define M98090_IN56_DADC_MASK		(1<<1)
+#define M98090_IN56_DADC_SHIFT		1
+#define M98090_IN56_DADC_WIDTH		1
+#define M98090_MIC_ALL_SHIFT		0
+#define M98090_MIC_ALL_WIDTH		8
+#define M98090_MIC_ALL_NUM		(1<<M98090_MIC_ALL_WIDTH)
+
+/*
+ * M98090_REG_LINE_TO_ADC
+ */
+#define M98090_IN12S_AB_MASK		(1<<7)
+#define M98090_IN12S_AB_SHIFT		7
+#define M98090_IN12S_AB_WIDTH		1
+#define M98090_IN34S_AB_MASK		(1<<6)
+#define M98090_IN34S_AB_SHIFT		6
+#define M98090_IN34S_AB_WIDTH		1
+#define M98090_IN56S_AB_MASK		(1<<5)
+#define M98090_IN56S_AB_SHIFT		5
+#define M98090_IN56S_AB_WIDTH		1
+#define M98090_IN34D_A_MASK		(1<<4)
+#define M98090_IN34D_A_SHIFT		4
+#define M98090_IN34D_A_WIDTH		1
+#define M98090_IN56D_B_MASK		(1<<3)
+#define M98090_IN56D_B_SHIFT		3
+#define M98090_IN56D_B_WIDTH		1
+#define M98090_LINE_ALL_SHIFT		0
+#define M98090_LINE_ALL_WIDTH		8
+#define M98090_LINE_ALL_NUM		(1<<M98090_LINE_ALL_WIDTH)
+
+/*
+ * M98090_REG_ANALOG_MIC_LOOP
+ */
+#define M98090_IN12_M1HPL_MASK		(1<<7)
+#define M98090_IN12_M1HPL_SHIFT		7
+#define M98090_IN12_M1HPL_WIDTH		1
+#define M98090_IN12_M1SPKL_MASK		(1<<6)
+#define M98090_IN12_M1SPKL_SHIFT	6
+#define M98090_IN12_M1SPKL_WIDTH	1
+#define M98090_IN12_M1EAR_MASK		(1<<5)
+#define M98090_IN12_M1EAR_SHIFT		5
+#define M98090_IN12_M1EAR_WIDTH		1
+#define M98090_IN12_M1LOUTL_MASK	(1<<4)
+#define M98090_IN12_M1LOUTL_SHIFT	4
+#define M98090_IN12_M1LOUTL_WIDTH	1
+#define M98090_IN34_M2HPR_MASK		(1<<3)
+#define M98090_IN34_M2HPR_SHIFT		3
+#define M98090_IN34_M2HPR_WIDTH		1
+#define M98090_IN34_M2SPKR_MASK		(1<<2)
+#define M98090_IN34_M2SPKR_SHIFT	2
+#define M98090_IN34_M2SPKR_WIDTH	1
+#define M98090_IN34_M2EAR_MASK		(1<<1)
+#define M98090_IN34_M2EAR_SHIFT		1
+#define M98090_IN34_M2EAR_WIDTH		1
+#define M98090_IN34_M2LOUTR_MASK	(1<<0)
+#define M98090_IN34_M2LOUTR_SHIFT	0
+#define M98090_IN34_M2LOUTR_WIDTH	1
+#define M98090_AMIC_ALL_SHIFT		0
+#define M98090_AMIC_ALL_WIDTH		8
+#define M98090_AMIC_ALL_NUM		(1<<M98090_AMIC_ALL_WIDTH)
+
+/*
+ * M98090_REG_ANALOG_LINE_LOOP
+ */
+#define M98090_IN12S_ABHP_MASK		(1<<7)
+#define M98090_IN12S_ABHP_SHIFT		7
+#define M98090_IN12S_ABHP_WIDTH		1
+#define M98090_IN34D_ASPKL_MASK		(1<<6)
+#define M98090_IN34D_ASPKL_SHIFT	6
+#define M98090_IN34D_ASPKL_WIDTH	1
+#define M98090_IN34D_AEAR_MASK		(1<<5)
+#define M98090_IN34D_AEAR_SHIFT		5
+#define M98090_IN34D_AEAR_WIDTH		1
+#define M98090_IN12S_ABLOUT_MASK	(1<<4)
+#define M98090_IN12S_ABLOUT_SHIFT	4
+#define M98090_IN12S_ABLOUT_WIDTH	1
+#define M98090_IN34S_ABHP_MASK		(1<<3)
+#define M98090_IN34S_ABHP_SHIFT		3
+#define M98090_IN34S_ABHP_WIDTH		1
+#define M98090_IN56D_BSPKR_MASK		(1<<2)
+#define M98090_IN56D_BSPKR_SHIFT	2
+#define M98090_IN56D_BSPKR_WIDTH	1
+#define M98090_IN56D_BEAR_MASK		(1<<1)
+#define M98090_IN56D_BEAR_SHIFT		1
+#define M98090_IN56D_BEAR_WIDTH		1
+#define M98090_IN34S_ABLOUT_MASK	(1<<0)
+#define M98090_IN34S_ABLOUT_SHIFT	0
+#define M98090_IN34S_ABLOUT_WIDTH	1
+#define M98090_ALIN_ALL_SHIFT		0
+#define M98090_ALIN_ALL_WIDTH		8
+#define M98090_ALIN_ALL_NUM		(1<<M98090_ALIN_ALL_WIDTH)
+
+/*
+ * M98090_REG_RESERVED
+ */
+
+/*
+ * M98090_REG_LINE_INPUT_CONFIG
+ */
+#define M98090_IN34DIFF_MASK		(1<<7)
+#define M98090_IN34DIFF_SHIFT		7
+#define M98090_IN34DIFF_WIDTH		1
+#define M98090_IN56DIFF_MASK		(1<<6)
+#define M98090_IN56DIFF_SHIFT		6
+#define M98090_IN56DIFF_WIDTH		1
+#define M98090_IN1SEEN_MASK		(1<<5)
+#define M98090_IN1SEEN_SHIFT		5
+#define M98090_IN1SEEN_WIDTH		1
+#define M98090_IN2SEEN_MASK		(1<<4)
+#define M98090_IN2SEEN_SHIFT		4
+#define M98090_IN2SEEN_WIDTH		1
+#define M98090_IN3SEEN_MASK		(1<<3)
+#define M98090_IN3SEEN_SHIFT		3
+#define M98090_IN3SEEN_WIDTH		1
+#define M98090_IN4SEEN_MASK		(1<<2)
+#define M98090_IN4SEEN_SHIFT		2
+#define M98090_IN4SEEN_WIDTH		1
+#define M98090_IN5SEEN_MASK		(1<<1)
+#define M98090_IN5SEEN_SHIFT		1
+#define M98090_IN5SEEN_WIDTH		1
+#define M98090_IN6SEEN_MASK		(1<<0)
+#define M98090_IN6SEEN_SHIFT		0
+#define M98090_IN6SEEN_WIDTH		1
+
+/*
+ * M98090_REG_LINE_INPUT_LEVEL
+ */
+#define M98090_MIXG135_MASK		(1<<7)
+#define M98090_MIXG135_SHIFT		7
+#define M98090_MIXG135_WIDTH		1
+#define M98090_MIXG135_NUM		(1<<M98090_MIXG135_WIDTH)
+#define M98090_MIXG246_MASK		(1<<6)
+#define M98090_MIXG246_SHIFT		6
+#define M98090_MIXG246_WIDTH		1
+#define M98090_MIXG246_NUM		(1<<M98090_MIXG246_WIDTH)
+#define M98090_LINAPGA_MASK		(7<<3)
+#define M98090_LINAPGA_SHIFT		3
+#define M98090_LINAPGA_WIDTH		3
+#define M98090_LINAPGA_NUM		6
+#define M98090_LINBPGA_MASK		(7<<0)
+#define M98090_LINBPGA_SHIFT		0
+#define M98090_LINBPGA_WIDTH		3
+#define M98090_LINBPGA_NUM		6
+
+/*
+ * M98090_REG_INPUT_MODE
+ */
+#define M98090_EXTBUFA_MASK		(1<<7)
+#define M98090_EXTBUFA_SHIFT		7
+#define M98090_EXTBUFA_WIDTH		1
+#define M98090_EXTBUFA_NUM		(1<<M98090_EXTBUFA_WIDTH)
+#define M98090_EXTBUFB_MASK		(1<<6)
+#define M98090_EXTBUFB_SHIFT		6
+#define M98090_EXTBUFB_WIDTH		1
+#define M98090_EXTBUFB_NUM		(1<<M98090_EXTBUFB_WIDTH)
+#define M98090_EXTMIC_MASK		(3<<0)
+#define M98090_EXTMIC_SHIFT		0
+#define M98090_EXTMIC1_SHIFT		0
+#define M98090_EXTMIC2_SHIFT		1
+#define M98090_EXTMIC_WIDTH		2
+#define M98090_EXTMIC_NONE		(0<<0)
+#define M98090_EXTMIC_MIC1		(1<<0)
+#define M98090_EXTMIC_MIC2		(2<<0)
+
+/*
+ * M98090_REG_MIC1_INPUT_LEVEL
+ */
+#define M98090_MIC_PA1EN_MASK		(3<<5)
+#define M98090_MIC_PA1EN_SHIFT		5
+#define M98090_MIC_PA1EN_WIDTH		2
+#define M98090_MIC_PA1EN_NUM		3
+#define M98090_MIC_PGAM1_MASK		(31<<0)
+#define M98090_MIC_PGAM1_SHIFT		0
+#define M98090_MIC_PGAM1_WIDTH		5
+#define M98090_MIC_PGAM1_NUM		21
+
+/*
+ * M98090_REG_MIC2_INPUT_LEVEL
+ */
+#define M98090_MIC_PA2EN_MASK		(3<<5)
+#define M98090_MIC_PA2EN_SHIFT		5
+#define M98090_MIC_PA2EN_WIDTH		2
+#define M98090_MIC_PA2EN_NUM		3
+#define M98090_MIC_PGAM2_MASK		(31<<0)
+#define M98090_MIC_PGAM2_SHIFT		0
+#define M98090_MIC_PGAM2_WIDTH		5
+#define M98090_MIC_PGAM2_NUM		21
+
+/*
+ * M98090_REG_MIC_BIAS_VOLTAGE
+ */
+#define M98090_MBVSEL_MASK		(3<<0)
+#define M98090_MBVSEL_SHIFT		0
+#define M98090_MBVSEL_WIDTH		2
+#define M98090_MBVSEL_2V8		(3<<0)
+#define M98090_MBVSEL_2V55		(2<<0)
+#define M98090_MBVSEL_2V4		(1<<0)
+#define M98090_MBVSEL_2V2		(0<<0)
+
+/*
+ * M98090_REG_DIGITAL_MIC_ENABLE
+ */
+#define M98090_MICCLK_MASK		(7<<4)
+#define M98090_MICCLK_SHIFT		4
+#define M98090_MICCLK_WIDTH		3
+#define M98090_DIGMIC4_MASK		(1<<3)
+#define M98090_DIGMIC4_SHIFT		3
+#define M98090_DIGMIC4_WIDTH		1
+#define M98090_DIGMIC4_NUM		(1<<M98090_DIGMIC4_WIDTH)
+#define M98090_DIGMIC3_MASK		(1<<2)
+#define M98090_DIGMIC3_SHIFT		2
+#define M98090_DIGMIC3_WIDTH		1
+#define M98090_DIGMIC3_NUM		(1<<M98090_DIGMIC3_WIDTH)
+#define M98090_DIGMICR_MASK		(1<<1)
+#define M98090_DIGMICR_SHIFT		1
+#define M98090_DIGMICR_WIDTH		1
+#define M98090_DIGMICR_NUM		(1<<M98090_DIGMICR_WIDTH)
+#define M98090_DIGMICL_MASK		(1<<0)
+#define M98090_DIGMICL_SHIFT		0
+#define M98090_DIGMICL_WIDTH		1
+#define M98090_DIGMICL_NUM		(1<<M98090_DIGMICL_WIDTH)
+
+/*
+ * M98090_REG_DIGITAL_MIC_CONFIG
+ */
+#define M98090_DMIC_COMP_MASK		(15<<4)
+#define M98090_DMIC_COMP_SHIFT		4
+#define M98090_DMIC_COMP_WIDTH		4
+#define M98090_DMIC_COMP_NUM		(1<<M98090_DMIC_COMP_WIDTH)
+#define M98090_DMIC_FREQ_MASK		(3<<0)
+#define M98090_DMIC_FREQ_SHIFT		0
+#define M98090_DMIC_FREQ_WIDTH		2
+
+/*
+ * M98090_REG_LEFT_ADC_MIXER
+ */
+#define M98090_MIXADL_MIC2_MASK		(1<<6)
+#define M98090_MIXADL_MIC2_SHIFT	6
+#define M98090_MIXADL_MIC2_WIDTH	1
+#define M98090_MIXADL_MIC1_MASK		(1<<5)
+#define M98090_MIXADL_MIC1_SHIFT	5
+#define M98090_MIXADL_MIC1_WIDTH	1
+#define M98090_MIXADL_LINEB_MASK	(1<<4)
+#define M98090_MIXADL_LINEB_SHIFT	4
+#define M98090_MIXADL_LINEB_WIDTH	1
+#define M98090_MIXADL_LINEA_MASK	(1<<3)
+#define M98090_MIXADL_LINEA_SHIFT	3
+#define M98090_MIXADL_LINEA_WIDTH	1
+#define M98090_MIXADL_IN65DIFF_MASK	(1<<2)
+#define M98090_MIXADL_IN65DIFF_SHIFT	2
+#define M98090_MIXADL_IN65DIFF_WIDTH	1
+#define M98090_MIXADL_IN34DIFF_MASK	(1<<1)
+#define M98090_MIXADL_IN34DIFF_SHIFT	1
+#define M98090_MIXADL_IN34DIFF_WIDTH	1
+#define M98090_MIXADL_IN12DIFF_MASK	(1<<0)
+#define M98090_MIXADL_IN12DIFF_SHIFT	0
+#define M98090_MIXADL_IN12DIFF_WIDTH	1
+#define M98090_MIXADL_MASK		(255<<0)
+#define M98090_MIXADL_SHIFT		0
+#define M98090_MIXADL_WIDTH		8
+
+/*
+ * M98090_REG_RIGHT_ADC_MIXER
+ */
+#define M98090_MIXADR_MIC2_MASK		(1<<6)
+#define M98090_MIXADR_MIC2_SHIFT	6
+#define M98090_MIXADR_MIC2_WIDTH	1
+#define M98090_MIXADR_MIC1_MASK		(1<<5)
+#define M98090_MIXADR_MIC1_SHIFT	5
+#define M98090_MIXADR_MIC1_WIDTH	1
+#define M98090_MIXADR_LINEB_MASK	(1<<4)
+#define M98090_MIXADR_LINEB_SHIFT	4
+#define M98090_MIXADR_LINEB_WIDTH	1
+#define M98090_MIXADR_LINEA_MASK	(1<<3)
+#define M98090_MIXADR_LINEA_SHIFT	3
+#define M98090_MIXADR_LINEA_WIDTH	1
+#define M98090_MIXADR_IN65DIFF_MASK	(1<<2)
+#define M98090_MIXADR_IN65DIFF_SHIFT	2
+#define M98090_MIXADR_IN65DIFF_WIDTH	1
+#define M98090_MIXADR_IN34DIFF_MASK	(1<<1)
+#define M98090_MIXADR_IN34DIFF_SHIFT	1
+#define M98090_MIXADR_IN34DIFF_WIDTH	1
+#define M98090_MIXADR_IN12DIFF_MASK	(1<<0)
+#define M98090_MIXADR_IN12DIFF_SHIFT	0
+#define M98090_MIXADR_IN12DIFF_WIDTH	1
+#define M98090_MIXADR_MASK		(255<<0)
+#define M98090_MIXADR_SHIFT		0
+#define M98090_MIXADR_WIDTH		8
+
+/*
+ * M98090_REG_LEFT_ADC_LEVEL
+ */
+#define M98090_AVLG_MASK		(7<<4)
+#define M98090_AVLG_SHIFT		4
+#define M98090_AVLG_WIDTH		3
+#define M98090_AVLG_NUM			(1<<M98090_AVLG_WIDTH)
+#define M98090_AVL_MASK			(15<<0)
+#define M98090_AVL_SHIFT		0
+#define M98090_AVL_WIDTH		4
+#define M98090_AVL_NUM			(1<<M98090_AVL_WIDTH)
+
+/*
+ * M98090_REG_RIGHT_ADC_LEVEL
+ */
+#define M98090_AVRG_MASK		(7<<4)
+#define M98090_AVRG_SHIFT		4
+#define M98090_AVRG_WIDTH		3
+#define M98090_AVRG_NUM			(1<<M98090_AVRG_WIDTH)
+#define M98090_AVR_MASK			(15<<0)
+#define M98090_AVR_SHIFT		0
+#define M98090_AVR_WIDTH		4
+#define M98090_AVR_NUM			(1<<M98090_AVR_WIDTH)
+
+/*
+ * M98090_REG_ADC_BIQUAD_LEVEL
+ */
+#define M98090_AVBQ_MASK		(15<<0)
+#define M98090_AVBQ_SHIFT		0
+#define M98090_AVBQ_WIDTH		4
+#define M98090_AVBQ_NUM			(1<<M98090_AVBQ_WIDTH)
+
+/*
+ * M98090_REG_ADC_SIDETONE
+ */
+#define M98090_DSTSR_MASK		(1<<7)
+#define M98090_DSTSR_SHIFT		7
+#define M98090_DSTSR_WIDTH		1
+#define M98090_DSTSL_MASK		(1<<6)
+#define M98090_DSTSL_SHIFT		6
+#define M98090_DSTSL_WIDTH		1
+#define M98090_DVST_MASK		(31<<0)
+#define M98090_DVST_SHIFT		0
+#define M98090_DVST_WIDTH		5
+#define M98090_DVST_NUM			31
+
+/*
+ * M98090_REG_SYSTEM_CLOCK
+ */
+#define M98090_PSCLK_MASK		(3<<4)
+#define M98090_PSCLK_SHIFT		4
+#define M98090_PSCLK_WIDTH		2
+#define M98090_PSCLK_DISABLED		(0<<4)
+#define M98090_PSCLK_DIV1		(1<<4)
+#define M98090_PSCLK_DIV2		(2<<4)
+#define M98090_PSCLK_DIV4		(3<<4)
+
+/*
+ * M98090_REG_CLOCK_MODE
+ */
+#define M98090_FREQ_MASK		(15<<4)
+#define M98090_FREQ_SHIFT		4
+#define M98090_FREQ_WIDTH		4
+#define M98090_USE_M1_MASK		(1<<0)
+#define M98090_USE_M1_SHIFT		0
+#define M98090_USE_M1_WIDTH		1
+#define M98090_USE_M1_NUM		(1<<M98090_USE_M1_WIDTH)
+
+/*
+ * M98090_REG_CLOCK_RATIO_NI_MSB
+ */
+#define M98090_NI_HI_MASK		(127<<0)
+#define M98090_NI_HI_SHIFT		0
+#define M98090_NI_HI_WIDTH		7
+#define M98090_NI_HI_NUM		(1<<M98090_NI_HI_WIDTH)
+
+/*
+ * M98090_REG_CLOCK_RATIO_NI_LSB
+ */
+#define M98090_NI_LO_MASK		(255<<0)
+#define M98090_NI_LO_SHIFT		0
+#define M98090_NI_LO_WIDTH		8
+#define M98090_NI_LO_NUM		(1<<M98090_NI_LO_WIDTH)
+
+/*
+ * M98090_REG_CLOCK_RATIO_MI_MSB
+ */
+#define M98090_MI_HI_MASK		(255<<0)
+#define M98090_MI_HI_SHIFT		0
+#define M98090_MI_HI_WIDTH		8
+#define M98090_MI_HI_NUM		(1<<M98090_MI_HI_WIDTH)
+
+/*
+ * M98090_REG_CLOCK_RATIO_MI_LSB
+ */
+#define M98090_MI_LO_MASK		(255<<0)
+#define M98090_MI_LO_SHIFT		0
+#define M98090_MI_LO_WIDTH		8
+#define M98090_MI_LO_NUM		(1<<M98090_MI_LO_WIDTH)
+
+/*
+ * M98090_REG_MASTER_MODE
+ */
+#define M98090_MAS_MASK			(1<<7)
+#define M98090_MAS_SHIFT		7
+#define M98090_MAS_WIDTH		1
+#define M98090_BSEL_MASK		(1<<0)
+#define M98090_BSEL_SHIFT		0
+#define M98090_BSEL_WIDTH		1
+#define M98090_BSEL_32			(1<<0)
+#define M98090_BSEL_48			(2<<0)
+#define M98090_BSEL_64			(3<<0)
+
+/*
+ * M98090_REG_INTERFACE_FORMAT
+ */
+#define M98090_RJ_MASK			(1<<5)
+#define M98090_RJ_SHIFT			5
+#define M98090_RJ_WIDTH			1
+#define M98090_WCI_MASK			(1<<4)
+#define M98090_WCI_SHIFT		4
+#define M98090_WCI_WIDTH		1
+#define M98090_BCI_MASK			(1<<3)
+#define M98090_BCI_SHIFT		3
+#define M98090_BCI_WIDTH		1
+#define M98090_DLY_MASK			(1<<2)
+#define M98090_DLY_SHIFT		2
+#define M98090_DLY_WIDTH		1
+#define M98090_WS_MASK			(3<<0)
+#define M98090_WS_SHIFT			0
+#define M98090_WS_WIDTH			2
+#define M98090_WS_NUM			(1<<M98090_WS_WIDTH)
+
+/*
+ * M98090_REG_TDM_CONTROL
+ */
+#define M98090_FSW_MASK			(1<<1)
+#define M98090_FSW_SHIFT		1
+#define M98090_FSW_WIDTH		1
+#define M98090_TDM_MASK			(1<<0)
+#define M98090_TDM_SHIFT		0
+#define M98090_TDM_WIDTH		1
+#define M98090_TDM_NUM			(1<<M98090_TDM_WIDTH)
+
+/*
+ * M98090_REG_TDM_FORMAT
+ */
+#define M98090_TDM_SLOTL_MASK		(3<<6)
+#define M98090_TDM_SLOTL_SHIFT		6
+#define M98090_TDM_SLOTL_WIDTH		2
+#define M98090_TDM_SLOTL_NUM		(1<<M98090_TDM_SLOTL_WIDTH)
+#define M98090_TDM_SLOTR_MASK		(3<<4)
+#define M98090_TDM_SLOTR_SHIFT		4
+#define M98090_TDM_SLOTR_WIDTH		2
+#define M98090_TDM_SLOTR_NUM		(1<<M98090_TDM_SLOTR_WIDTH)
+#define M98090_TDM_SLOTDLY_MASK		(15<<0)
+#define M98090_TDM_SLOTDLY_SHIFT	0
+#define M98090_TDM_SLOTDLY_WIDTH	4
+#define M98090_TDM_SLOTDLY_NUM		(1<<M98090_TDM_SLOTDLY_WIDTH)
+
+/*
+ * M98090_REG_IO_CONFIGURATION
+ */
+#define M98090_LTEN_MASK		(1<<5)
+#define M98090_LTEN_SHIFT		5
+#define M98090_LTEN_WIDTH		1
+#define M98090_LTEN_NUM			(1<<M98090_LTEN_WIDTH)
+#define M98090_LBEN_MASK		(1<<4)
+#define M98090_LBEN_SHIFT		4
+#define M98090_LBEN_WIDTH		1
+#define M98090_LBEN_NUM			(1<<M98090_LBEN_WIDTH)
+#define M98090_DMONO_MASK		(1<<3)
+#define M98090_DMONO_SHIFT		3
+#define M98090_DMONO_WIDTH		1
+#define M98090_DMONO_NUM		(1<<M98090_DMONO_WIDTH)
+#define M98090_HIZOFF_MASK		(1<<2)
+#define M98090_HIZOFF_SHIFT		2
+#define M98090_HIZOFF_WIDTH		1
+#define M98090_HIZOFF_NUM		(1<<M98090_HIZOFF_WIDTH)
+#define M98090_SDOEN_MASK		(1<<1)
+#define M98090_SDOEN_SHIFT		1
+#define M98090_SDOEN_WIDTH		1
+#define M98090_SDOEN_NUM		(1<<M98090_SDOEN_WIDTH)
+#define M98090_SDIEN_MASK		(1<<0)
+#define M98090_SDIEN_SHIFT		0
+#define M98090_SDIEN_WIDTH		1
+#define M98090_SDIEN_NUM		(1<<M98090_SDIEN_WIDTH)
+
+/*
+ * M98090_REG_FILTER_CONFIG
+ */
+#define M98090_MODE_MASK		(1<<7)
+#define M98090_MODE_SHIFT		7
+#define M98090_MODE_WIDTH		1
+#define M98090_AHPF_MASK		(1<<6)
+#define M98090_AHPF_SHIFT		6
+#define M98090_AHPF_WIDTH		1
+#define M98090_AHPF_NUM			(1<<M98090_AHPF_WIDTH)
+#define M98090_DHPF_MASK		(1<<5)
+#define M98090_DHPF_SHIFT		5
+#define M98090_DHPF_WIDTH		1
+#define M98090_DHPF_NUM			(1<<M98090_DHPF_WIDTH)
+#define M98090_DHF_MASK			(1<<4)
+#define M98090_DHF_SHIFT		4
+#define M98090_DHF_WIDTH		1
+#define M98090_FLT_DMIC34MODE_MASK	(1<<3)
+#define M98090_FLT_DMIC34MODE_SHIFT	3
+#define M98090_FLT_DMIC34MODE_WIDTH	1
+#define M98090_FLT_DMIC34HPF_MASK	(1<<2)
+#define M98090_FLT_DMIC34HPF_SHIFT	2
+#define M98090_FLT_DMIC34HPF_WIDTH	1
+#define M98090_FLT_DMIC34HPF_NUM	(1<<M98090_FLT_DMIC34HPF_WIDTH)
+
+/*
+ * M98090_REG_DAI_PLAYBACK_LEVEL
+ */
+#define M98090_DVM_MASK			(1<<7)
+#define M98090_DVM_SHIFT		7
+#define M98090_DVM_WIDTH		1
+#define M98090_DVG_MASK			(3<<4)
+#define M98090_DVG_SHIFT		4
+#define M98090_DVG_WIDTH		2
+#define M98090_DVG_NUM			(1<<M98090_DVG_WIDTH)
+#define M98090_DV_MASK			(15<<0)
+#define M98090_DV_SHIFT			0
+#define M98090_DV_WIDTH			4
+#define M98090_DV_NUM			(1<<M98090_DV_WIDTH)
+
+/*
+ * M98090_REG_DAI_PLAYBACK_LEVEL_EQ
+ */
+#define M98090_EQCLPN_MASK		(1<<4)
+#define M98090_EQCLPN_SHIFT		4
+#define M98090_EQCLPN_WIDTH		1
+#define M98090_EQCLPN_NUM		(1<<M98090_EQCLPN_WIDTH)
+#define M98090_DVEQ_MASK		(15<<0)
+#define M98090_DVEQ_SHIFT		0
+#define M98090_DVEQ_WIDTH		4
+#define M98090_DVEQ_NUM			(1<<M98090_DVEQ_WIDTH)
+
+/*
+ * M98090_REG_LEFT_HP_MIXER
+ */
+#define M98090_MIXHPL_MIC2_MASK		(1<<5)
+#define M98090_MIXHPL_MIC2_SHIFT	5
+#define M98090_MIXHPL_MIC2_WIDTH	1
+#define M98090_MIXHPL_MIC1_MASK		(1<<4)
+#define M98090_MIXHPL_MIC1_SHIFT	4
+#define M98090_MIXHPL_MIC1_WIDTH	1
+#define M98090_MIXHPL_LINEB_MASK	(1<<3)
+#define M98090_MIXHPL_LINEB_SHIFT	3
+#define M98090_MIXHPL_LINEB_WIDTH	1
+#define M98090_MIXHPL_LINEA_MASK	(1<<2)
+#define M98090_MIXHPL_LINEA_SHIFT	2
+#define M98090_MIXHPL_LINEA_WIDTH	1
+#define M98090_MIXHPL_DACR_MASK		(1<<1)
+#define M98090_MIXHPL_DACR_SHIFT	1
+#define M98090_MIXHPL_DACR_WIDTH	1
+#define M98090_MIXHPL_DACL_MASK		(1<<0)
+#define M98090_MIXHPL_DACL_SHIFT	0
+#define M98090_MIXHPL_DACL_WIDTH	1
+#define M98090_MIXHPL_MASK		(63<<0)
+#define M98090_MIXHPL_SHIFT		0
+#define M98090_MIXHPL_WIDTH		6
+
+/*
+ * M98090_REG_RIGHT_HP_MIXER
+ */
+#define M98090_MIXHPR_MIC2_MASK		(1<<5)
+#define M98090_MIXHPR_MIC2_SHIFT	5
+#define M98090_MIXHPR_MIC2_WIDTH	1
+#define M98090_MIXHPR_MIC1_MASK		(1<<4)
+#define M98090_MIXHPR_MIC1_SHIFT	4
+#define M98090_MIXHPR_MIC1_WIDTH	1
+#define M98090_MIXHPR_LINEB_MASK	(1<<3)
+#define M98090_MIXHPR_LINEB_SHIFT	3
+#define M98090_MIXHPR_LINEB_WIDTH	1
+#define M98090_MIXHPR_LINEA_MASK	(1<<2)
+#define M98090_MIXHPR_LINEA_SHIFT	2
+#define M98090_MIXHPR_LINEA_WIDTH	1
+#define M98090_MIXHPR_DACR_MASK		(1<<1)
+#define M98090_MIXHPR_DACR_SHIFT	1
+#define M98090_MIXHPR_DACR_WIDTH	1
+#define M98090_MIXHPR_DACL_MASK		(1<<0)
+#define M98090_MIXHPR_DACL_SHIFT	0
+#define M98090_MIXHPR_DACL_WIDTH	1
+#define M98090_MIXHPR_MASK		(63<<0)
+#define M98090_MIXHPR_SHIFT		0
+#define M98090_MIXHPR_WIDTH		6
+
+/*
+ * M98090_REG_HP_CONTROL
+ */
+#define M98090_MIXHPRSEL_MASK		(1<<5)
+#define M98090_MIXHPRSEL_SHIFT		5
+#define M98090_MIXHPRSEL_WIDTH		1
+#define M98090_MIXHPLSEL_MASK		(1<<4)
+#define M98090_MIXHPLSEL_SHIFT		4
+#define M98090_MIXHPLSEL_WIDTH		1
+#define M98090_MIXHPRG_MASK		(3<<2)
+#define M98090_MIXHPRG_SHIFT		2
+#define M98090_MIXHPRG_WIDTH		2
+#define M98090_MIXHPRG_NUM		(1<<M98090_MIXHPRG_WIDTH)
+#define M98090_MIXHPLG_MASK		(3<<0)
+#define M98090_MIXHPLG_SHIFT		0
+#define M98090_MIXHPLG_WIDTH		2
+#define M98090_MIXHPLG_NUM		(1<<M98090_MIXHPLG_WIDTH)
+
+/*
+ * M98090_REG_LEFT_HP_VOLUME
+ */
+#define M98090_HPLM_MASK		(1<<7)
+#define M98090_HPLM_SHIFT		7
+#define M98090_HPLM_WIDTH		1
+#define M98090_HPVOLL_MASK		(31<<0)
+#define M98090_HPVOLL_SHIFT		0
+#define M98090_HPVOLL_WIDTH		5
+#define M98090_HPVOLL_NUM		(1<<M98090_HPVOLL_WIDTH)
+
+/*
+ * M98090_REG_RIGHT_HP_VOLUME
+ */
+#define M98090_HPRM_MASK		(1<<7)
+#define M98090_HPRM_SHIFT		7
+#define M98090_HPRM_WIDTH		1
+#define M98090_HPVOLR_MASK		(31<<0)
+#define M98090_HPVOLR_SHIFT		0
+#define M98090_HPVOLR_WIDTH		5
+#define M98090_HPVOLR_NUM		(1<<M98090_HPVOLR_WIDTH)
+
+/*
+ * M98090_REG_LEFT_SPK_MIXER
+ */
+#define M98090_MIXSPL_MIC2_MASK		(1<<5)
+#define M98090_MIXSPL_MIC2_SHIFT	5
+#define M98090_MIXSPL_MIC2_WIDTH	1
+#define M98090_MIXSPL_MIC1_MASK		(1<<4)
+#define M98090_MIXSPL_MIC1_SHIFT	4
+#define M98090_MIXSPL_MIC1_WIDTH	1
+#define M98090_MIXSPL_LINEB_MASK	(1<<3)
+#define M98090_MIXSPL_LINEB_SHIFT	3
+#define M98090_MIXSPL_LINEB_WIDTH	1
+#define M98090_MIXSPL_LINEA_MASK	(1<<2)
+#define M98090_MIXSPL_LINEA_SHIFT	2
+#define M98090_MIXSPL_LINEA_WIDTH	1
+#define M98090_MIXSPL_DACR_MASK		(1<<1)
+#define M98090_MIXSPL_DACR_SHIFT	1
+#define M98090_MIXSPL_DACR_WIDTH	1
+#define M98090_MIXSPL_DACL_MASK		(1<<0)
+#define M98090_MIXSPL_DACL_SHIFT	0
+#define M98090_MIXSPL_DACL_WIDTH	1
+#define M98090_MIXSPL_MASK		(63<<0)
+#define M98090_MIXSPL_SHIFT		0
+#define M98090_MIXSPL_WIDTH		6
+#define M98090_MIXSPR_DACR_MASK		(1<<1)
+#define M98090_MIXSPR_DACR_SHIFT	1
+#define M98090_MIXSPR_DACR_WIDTH	1
+
+
+/*
+ * M98090_REG_RIGHT_SPK_MIXER
+ */
+#define M98090_SPK_SLAVE_MASK		(1<<6)
+#define M98090_SPK_SLAVE_SHIFT		6
+#define M98090_SPK_SLAVE_WIDTH		1
+#define M98090_MIXSPR_MIC2_MASK		(1<<5)
+#define M98090_MIXSPR_MIC2_SHIFT	5
+#define M98090_MIXSPR_MIC2_WIDTH	1
+#define M98090_MIXSPR_MIC1_MASK		(1<<4)
+#define M98090_MIXSPR_MIC1_SHIFT	4
+#define M98090_MIXSPR_MIC1_WIDTH	1
+#define M98090_MIXSPR_LINEB_MASK	(1<<3)
+#define M98090_MIXSPR_LINEB_SHIFT	3
+#define M98090_MIXSPR_LINEB_WIDTH	1
+#define M98090_MIXSPR_LINEA_MASK	(1<<2)
+#define M98090_MIXSPR_LINEA_SHIFT	2
+#define M98090_MIXSPR_LINEA_WIDTH	1
+#define M98090_MIXSPR_DACR_MASK		(1<<1)
+#define M98090_MIXSPR_DACR_SHIFT	1
+#define M98090_MIXSPR_DACR_WIDTH	1
+#define M98090_MIXSPR_DACL_MASK		(1<<0)
+#define M98090_MIXSPR_DACL_SHIFT	0
+#define M98090_MIXSPR_DACL_WIDTH	1
+#define M98090_MIXSPR_MASK		(63<<0)
+#define M98090_MIXSPR_SHIFT		0
+#define M98090_MIXSPR_WIDTH		6
+
+/*
+ * M98090_REG_SPK_CONTROL
+ */
+#define M98090_MIXSPRG_MASK		(3<<2)
+#define M98090_MIXSPRG_SHIFT		2
+#define M98090_MIXSPRG_WIDTH		2
+#define M98090_MIXSPRG_NUM		(1<<M98090_MIXSPRG_WIDTH)
+#define M98090_MIXSPLG_MASK		(3<<0)
+#define M98090_MIXSPLG_SHIFT		0
+#define M98090_MIXSPLG_WIDTH		2
+#define M98090_MIXSPLG_NUM		(1<<M98090_MIXSPLG_WIDTH)
+
+/*
+ * M98090_REG_LEFT_SPK_VOLUME
+ */
+#define M98090_SPLM_MASK		(1<<7)
+#define M98090_SPLM_SHIFT		7
+#define M98090_SPLM_WIDTH		1
+#define M98090_SPVOLL_MASK		(63<<0)
+#define M98090_SPVOLL_SHIFT		0
+#define M98090_SPVOLL_WIDTH		6
+#define M98090_SPVOLL_NUM		40
+
+/*
+ * M98090_REG_RIGHT_SPK_VOLUME
+ */
+#define M98090_SPRM_MASK		(1<<7)
+#define M98090_SPRM_SHIFT		7
+#define M98090_SPRM_WIDTH		1
+#define M98090_SPVOLR_MASK		(63<<0)
+#define M98090_SPVOLR_SHIFT		0
+#define M98090_SPVOLR_WIDTH		6
+#define M98090_SPVOLR_NUM		40
+
+/*
+ * M98090_REG_DRC_TIMING
+ */
+#define M98090_DRCEN_MASK		(1<<7)
+#define M98090_DRCEN_SHIFT		7
+#define M98090_DRCEN_WIDTH		1
+#define M98090_DRCEN_NUM		(1<<M98090_DRCEN_WIDTH)
+#define M98090_DRCRLS_MASK		(7<<4)
+#define M98090_DRCRLS_SHIFT		4
+#define M98090_DRCRLS_WIDTH		3
+#define M98090_DRCATK_MASK		(7<<0)
+#define M98090_DRCATK_SHIFT		0
+#define M98090_DRCATK_WIDTH		3
+
+/*
+ * M98090_REG_DRC_COMPRESSOR
+ */
+#define M98090_DRCCMP_MASK		(7<<5)
+#define M98090_DRCCMP_SHIFT		5
+#define M98090_DRCCMP_WIDTH		3
+#define M98090_DRCTHC_MASK		(31<<0)
+#define M98090_DRCTHC_SHIFT		0
+#define M98090_DRCTHC_WIDTH		5
+#define M98090_DRCTHC_NUM		(1<<M98090_DRCTHC_WIDTH)
+
+/*
+ * M98090_REG_DRC_EXPANDER
+ */
+#define M98090_DRCEXP_MASK		(7<<5)
+#define M98090_DRCEXP_SHIFT		5
+#define M98090_DRCEXP_WIDTH		3
+#define M98090_DRCTHE_MASK		(31<<0)
+#define M98090_DRCTHE_SHIFT		0
+#define M98090_DRCTHE_WIDTH		5
+#define M98090_DRCTHE_NUM		(1<<M98090_DRCTHE_WIDTH)
+
+/*
+ * M98090_REG_DRC_GAIN
+ */
+#define M98090_DRCG_MASK		(31<<0)
+#define M98090_DRCG_SHIFT		0
+#define M98090_DRCG_WIDTH		5
+#define M98090_DRCG_NUM			13
+
+/*
+ * M98090_REG_RCV_LOUTL_MIXER
+ */
+#define M98090_MIXRCVL_MIC2_MASK	(1<<5)
+#define M98090_MIXRCVL_MIC2_SHIFT	5
+#define M98090_MIXRCVL_MIC2_WIDTH	1
+#define M98090_MIXRCVL_MIC1_MASK	(1<<4)
+#define M98090_MIXRCVL_MIC1_SHIFT	4
+#define M98090_MIXRCVL_MIC1_WIDTH	1
+#define M98090_MIXRCVL_LINEB_MASK	(1<<3)
+#define M98090_MIXRCVL_LINEB_SHIFT	3
+#define M98090_MIXRCVL_LINEB_WIDTH	1
+#define M98090_MIXRCVL_LINEA_MASK	(1<<2)
+#define M98090_MIXRCVL_LINEA_SHIFT	2
+#define M98090_MIXRCVL_LINEA_WIDTH	1
+#define M98090_MIXRCVL_DACR_MASK	(1<<1)
+#define M98090_MIXRCVL_DACR_SHIFT	1
+#define M98090_MIXRCVL_DACR_WIDTH	1
+#define M98090_MIXRCVL_DACL_MASK	(1<<0)
+#define M98090_MIXRCVL_DACL_SHIFT	0
+#define M98090_MIXRCVL_DACL_WIDTH	1
+#define M98090_MIXRCVL_MASK		(63<<0)
+#define M98090_MIXRCVL_SHIFT		0
+#define M98090_MIXRCVL_WIDTH		6
+
+/*
+ * M98090_REG_RCV_LOUTL_CONTROL
+ */
+#define M98090_MIXRCVLG_MASK		(3<<0)
+#define M98090_MIXRCVLG_SHIFT		0
+#define M98090_MIXRCVLG_WIDTH		2
+#define M98090_MIXRCVLG_NUM		(1<<M98090_MIXRCVLG_WIDTH)
+
+/*
+ * M98090_REG_RCV_LOUTL_VOLUME
+ */
+#define M98090_RCVLM_MASK		(1<<7)
+#define M98090_RCVLM_SHIFT		7
+#define M98090_RCVLM_WIDTH		1
+#define M98090_RCVLVOL_MASK		(31<<0)
+#define M98090_RCVLVOL_SHIFT		0
+#define M98090_RCVLVOL_WIDTH		5
+#define M98090_RCVLVOL_NUM		(1<<M98090_RCVLVOL_WIDTH)
+
+/*
+ * M98090_REG_LOUTR_MIXER
+ */
+#define M98090_LINMOD_MASK		(1<<7)
+#define M98090_LINMOD_SHIFT		7
+#define M98090_LINMOD_WIDTH		1
+#define M98090_MIXRCVR_MIC2_MASK	(1<<5)
+#define M98090_MIXRCVR_MIC2_SHIFT	5
+#define M98090_MIXRCVR_MIC2_WIDTH	1
+#define M98090_MIXRCVR_MIC1_MASK	(1<<4)
+#define M98090_MIXRCVR_MIC1_SHIFT	4
+#define M98090_MIXRCVR_MIC1_WIDTH	1
+#define M98090_MIXRCVR_LINEB_MASK	(1<<3)
+#define M98090_MIXRCVR_LINEB_SHIFT	3
+#define M98090_MIXRCVR_LINEB_WIDTH	1
+#define M98090_MIXRCVR_LINEA_MASK	(1<<2)
+#define M98090_MIXRCVR_LINEA_SHIFT	2
+#define M98090_MIXRCVR_LINEA_WIDTH	1
+#define M98090_MIXRCVR_DACR_MASK	(1<<1)
+#define M98090_MIXRCVR_DACR_SHIFT	1
+#define M98090_MIXRCVR_DACR_WIDTH	1
+#define M98090_MIXRCVR_DACL_MASK	(1<<0)
+#define M98090_MIXRCVR_DACL_SHIFT	0
+#define M98090_MIXRCVR_DACL_WIDTH	1
+#define M98090_MIXRCVR_MASK		(63<<0)
+#define M98090_MIXRCVR_SHIFT		0
+#define M98090_MIXRCVR_WIDTH		6
+
+/*
+ * M98090_REG_LOUTR_CONTROL
+ */
+#define M98090_MIXRCVRG_MASK		(3<<0)
+#define M98090_MIXRCVRG_SHIFT		0
+#define M98090_MIXRCVRG_WIDTH		2
+#define M98090_MIXRCVRG_NUM		(1<<M98090_MIXRCVRG_WIDTH)
+
+/*
+ * M98090_REG_LOUTR_VOLUME
+ */
+#define M98090_RCVRM_MASK		(1<<7)
+#define M98090_RCVRM_SHIFT		7
+#define M98090_RCVRM_WIDTH		1
+#define M98090_RCVRVOL_MASK		(31<<0)
+#define M98090_RCVRVOL_SHIFT		0
+#define M98090_RCVRVOL_WIDTH		5
+#define M98090_RCVRVOL_NUM		(1<<M98090_RCVRVOL_WIDTH)
+
+/*
+ * M98090_REG_JACK_DETECT
+ */
+#define M98090_JDETEN_MASK		(1<<7)
+#define M98090_JDETEN_SHIFT		7
+#define M98090_JDETEN_WIDTH		1
+#define M98090_JDWK_MASK		(1<<6)
+#define M98090_JDWK_SHIFT		6
+#define M98090_JDWK_WIDTH		1
+#define M98090_JDEB_MASK		(3<<0)
+#define M98090_JDEB_SHIFT		0
+#define M98090_JDEB_WIDTH		2
+#define M98090_JDEB_25MS		(0<<0)
+#define M98090_JDEB_50MS		(1<<0)
+#define M98090_JDEB_100MS		(2<<0)
+#define M98090_JDEB_200MS		(3<<0)
+
+/*
+ * M98090_REG_INPUT_ENABLE
+ */
+#define M98090_MBEN_MASK		(1<<4)
+#define M98090_MBEN_SHIFT		4
+#define M98090_MBEN_WIDTH		1
+#define M98090_LINEAEN_MASK		(1<<3)
+#define M98090_LINEAEN_SHIFT		3
+#define M98090_LINEAEN_WIDTH		1
+#define M98090_LINEBEN_MASK		(1<<2)
+#define M98090_LINEBEN_SHIFT		2
+#define M98090_LINEBEN_WIDTH		1
+#define M98090_ADREN_MASK		(1<<1)
+#define M98090_ADREN_SHIFT		1
+#define M98090_ADREN_WIDTH		1
+#define M98090_ADLEN_MASK		(1<<0)
+#define M98090_ADLEN_SHIFT		0
+#define M98090_ADLEN_WIDTH		1
+
+/*
+ * M98090_REG_OUTPUT_ENABLE
+ */
+#define M98090_HPREN_MASK		(1<<7)
+#define M98090_HPREN_SHIFT		7
+#define M98090_HPREN_WIDTH		1
+#define M98090_HPLEN_MASK		(1<<6)
+#define M98090_HPLEN_SHIFT		6
+#define M98090_HPLEN_WIDTH		1
+#define M98090_SPREN_MASK		(1<<5)
+#define M98090_SPREN_SHIFT		5
+#define M98090_SPREN_WIDTH		1
+#define M98090_SPLEN_MASK		(1<<4)
+#define M98090_SPLEN_SHIFT		4
+#define M98090_SPLEN_WIDTH		1
+#define M98090_RCVLEN_MASK		(1<<3)
+#define M98090_RCVLEN_SHIFT		3
+#define M98090_RCVLEN_WIDTH		1
+#define M98090_RCVREN_MASK		(1<<2)
+#define M98090_RCVREN_SHIFT		2
+#define M98090_RCVREN_WIDTH		1
+#define M98090_DAREN_MASK		(1<<1)
+#define M98090_DAREN_SHIFT		1
+#define M98090_DAREN_WIDTH		1
+#define M98090_DALEN_MASK		(1<<0)
+#define M98090_DALEN_SHIFT		0
+#define M98090_DALEN_WIDTH		1
+
+/*
+ * M98090_REG_LEVEL_CONTROL
+ */
+#define M98090_ZDENN_MASK		(1<<2)
+#define M98090_ZDENN_SHIFT		2
+#define M98090_ZDENN_WIDTH		1
+#define M98090_ZDENN_NUM		(1<<M98090_ZDENN_WIDTH)
+#define M98090_VS2ENN_MASK		(1<<1)
+#define M98090_VS2ENN_SHIFT		1
+#define M98090_VS2ENN_WIDTH		1
+#define M98090_VS2ENN_NUM		(1<<M98090_VS2ENN_WIDTH)
+#define M98090_VSENN_MASK		(1<<0)
+#define M98090_VSENN_SHIFT		0
+#define M98090_VSENN_WIDTH		1
+#define M98090_VSENN_NUM		(1<<M98090_VSENN_WIDTH)
+
+/*
+ * M98090_REG_DSP_FILTER_ENABLE
+ */
+#define M98090_DMIC34BQEN_MASK		(1<<4)
+#define M98090_DMIC34BQEN_SHIFT		4
+#define M98090_DMIC34BQEN_WIDTH		1
+#define M98090_DMIC34BQEN_NUM		(1<<M98090_DMIC34BQEN_WIDTH)
+#define M98090_ADCBQEN_MASK		(1<<3)
+#define M98090_ADCBQEN_SHIFT		3
+#define M98090_ADCBQEN_WIDTH		1
+#define M98090_ADCBQEN_NUM		(1<<M98090_ADCBQEN_WIDTH)
+#define M98090_EQ3BANDEN_MASK		(1<<2)
+#define M98090_EQ3BANDEN_SHIFT		2
+#define M98090_EQ3BANDEN_WIDTH		1
+#define M98090_EQ3BANDEN_NUM		(1<<M98090_EQ3BANDEN_WIDTH)
+#define M98090_EQ5BANDEN_MASK		(1<<1)
+#define M98090_EQ5BANDEN_SHIFT		1
+#define M98090_EQ5BANDEN_WIDTH		1
+#define M98090_EQ5BANDEN_NUM		(1<<M98090_EQ5BANDEN_WIDTH)
+#define M98090_EQ7BANDEN_MASK		(1<<0)
+#define M98090_EQ7BANDEN_SHIFT		0
+#define M98090_EQ7BANDEN_WIDTH		1
+#define M98090_EQ7BANDEN_NUM		(1<<M98090_EQ7BANDEN_WIDTH)
+
+/*
+ * M98090_REG_BIAS_CONTROL
+ */
+#define M98090_VCM_MODE_MASK		(1<<0)
+#define M98090_VCM_MODE_SHIFT		0
+#define M98090_VCM_MODE_WIDTH		1
+#define M98090_VCM_MODE_NUM		(1<<M98090_VCM_MODE_WIDTH)
+
+/*
+ * M98090_REG_DAC_CONTROL
+ */
+#define M98090_PERFMODE_MASK		(1<<1)
+#define M98090_PERFMODE_SHIFT		1
+#define M98090_PERFMODE_WIDTH		1
+#define M98090_PERFMODE_NUM		(1<<M98090_PERFMODE_WIDTH)
+#define M98090_DACHP_MASK		(1<<0)
+#define M98090_DACHP_SHIFT		0
+#define M98090_DACHP_WIDTH		1
+#define M98090_DACHP_NUM		(1<<M98090_DACHP_WIDTH)
+
+/*
+ * M98090_REG_ADC_CONTROL
+ */
+#define M98090_OSR128_MASK		(1<<2)
+#define M98090_OSR128_SHIFT		2
+#define M98090_OSR128_WIDTH		1
+#define M98090_ADCDITHER_MASK		(1<<1)
+#define M98090_ADCDITHER_SHIFT		1
+#define M98090_ADCDITHER_WIDTH		1
+#define M98090_ADCDITHER_NUM		(1<<M98090_ADCDITHER_WIDTH)
+#define M98090_ADCHP_MASK		(1<<0)
+#define M98090_ADCHP_SHIFT		0
+#define M98090_ADCHP_WIDTH		1
+#define M98090_ADCHP_NUM		(1<<M98090_ADCHP_WIDTH)
+
+/*
+ * M98090_REG_DEVICE_SHUTDOWN
+ */
+#define M98090_SHDNN_MASK		(1<<7)
+#define M98090_SHDNN_SHIFT		7
+#define M98090_SHDNN_WIDTH		1
+
+/*
+ * M98090_REG_EQUALIZER_BASE
+ */
+#define M98090_B0_1_HI_MASK		(255<<0)
+#define M98090_B0_1_HI_SHIFT		0
+#define M98090_B0_1_HI_WIDTH		8
+#define M98090_B0_1_MID_MASK		(255<<0)
+#define M98090_B0_1_MID_SHIFT		0
+#define M98090_B0_1_MID_WIDTH		8
+#define M98090_B0_1_LO_MASK		(255<<0)
+#define M98090_B0_1_LO_SHIFT		0
+#define M98090_B0_1_LO_WIDTH		8
+#define M98090_B1_1_HI_MASK		(255<<0)
+#define M98090_B1_1_HI_SHIFT		0
+#define M98090_B1_1_HI_WIDTH		8
+#define M98090_B1_1_MID_MASK		(255<<0)
+#define M98090_B1_1_MID_SHIFT		0
+#define M98090_B1_1_MID_WIDTH		8
+#define M98090_B1_1_LO_MASK		(255<<0)
+#define M98090_B1_1_LO_SHIFT		0
+#define M98090_B1_1_LO_WIDTH		8
+#define M98090_B2_1_HI_MASK		(255<<0)
+#define M98090_B2_1_HI_SHIFT		0
+#define M98090_B2_1_HI_WIDTH		8
+#define M98090_B2_1_MID_MASK		(255<<0)
+#define M98090_B2_1_MID_SHIFT		0
+#define M98090_B2_1_MID_WIDTH		8
+#define M98090_B2_1_LO_MASK		(255<<0)
+#define M98090_B2_1_LO_SHIFT		0
+#define M98090_B2_1_LO_WIDTH		8
+#define M98090_A1_1_HI_MASK		(255<<0)
+#define M98090_A1_1_HI_SHIFT		0
+#define M98090_A1_1_HI_WIDTH		8
+#define M98090_A1_1_MID_MASK		(255<<0)
+#define M98090_A1_1_MID_SHIFT		0
+#define M98090_A1_1_MID_WIDTH		8
+#define M98090_A1_1_LO_MASK		(255<<0)
+#define M98090_A1_1_LO_SHIFT		0
+#define M98090_A1_1_LO_WIDTH		8
+#define M98090_A2_1_HI_MASK		(255<<0)
+#define M98090_A2_1_HI_SHIFT		0
+#define M98090_A2_1_HI_WIDTH		8
+#define M98090_A2_1_MID_MASK		(255<<0)
+#define M98090_A2_1_MID_SHIFT		0
+#define M98090_A2_1_MID_WIDTH		8
+#define M98090_A2_1_LO_MASK		(255<<0)
+#define M98090_A2_1_LO_SHIFT		0
+#define M98090_A2_1_LO_WIDTH		8
+
+#define M98090_COEFS_PER_BAND		5
+#define M98090_COEFS_BLK_SZ		(M98090_COEFS_PER_BAND * 3)
+#define M98090_COEFS_MAX_SZ		(M98090_COEFS_BLK_SZ * 7)
+
+/*
+ * M98090_REG_RECORD_BIQUAD_BASE
+ */
+#define M98090_REC_B0_HI_MASK		(255<<0)
+#define M98090_REC_B0_HI_SHIFT		0
+#define M98090_REC_B0_HI_WIDTH		8
+#define M98090_REC_B0_MID_MASK		(255<<0)
+#define M98090_REC_B0_MID_SHIFT		0
+#define M98090_REC_B0_MID_WIDTH		8
+#define M98090_REC_B0_LO_MASK		(255<<0)
+#define M98090_REC_B0_LO_SHIFT		0
+#define M98090_REC_B0_LO_WIDTH		8
+#define M98090_REC_B1_HI_MASK		(255<<0)
+#define M98090_REC_B1_HI_SHIFT		0
+#define M98090_REC_B1_HI_WIDTH		8
+#define M98090_REC_B1_MID_MASK		(255<<0)
+#define M98090_REC_B1_MID_SHIFT		0
+#define M98090_REC_B1_MID_WIDTH		8
+#define M98090_REC_B1_LO_MASK		(255<<0)
+#define M98090_REC_B1_LO_SHIFT		0
+#define M98090_REC_B1_LO_WIDTH		8
+#define M98090_REC_B2_HI_MASK		(255<<0)
+#define M98090_REC_B2_HI_SHIFT		0
+#define M98090_REC_B2_HI_WIDTH		8
+#define M98090_REC_B2_MID_MASK		(255<<0)
+#define M98090_REC_B2_MID_SHIFT		0
+#define M98090_REC_B2_MID_WIDTH		8
+#define M98090_REC_B2_LO_MASK		(255<<0)
+#define M98090_REC_B2_LO_SHIFT		0
+#define M98090_REC_B2_LO_WIDTH		8
+#define M98090_REC_A1_HI_MASK		(255<<0)
+#define M98090_REC_A1_HI_SHIFT		0
+#define M98090_REC_A1_HI_WIDTH		8
+#define M98090_REC_A1_MID_MASK		(255<<0)
+#define M98090_REC_A1_MID_SHIFT		0
+#define M98090_REC_A1_MID_WIDTH		8
+#define M98090_REC_A1_LO_MASK		(255<<0)
+#define M98090_REC_A1_LO_SHIFT		0
+#define M98090_REC_A1_LO_WIDTH		8
+#define M98090_REC_A2_HI_MASK		(255<<0)
+#define M98090_REC_A2_HI_SHIFT		0
+#define M98090_REC_A2_HI_WIDTH		8
+#define M98090_REC_A2_MID_MASK		(255<<0)
+#define M98090_REC_A2_MID_SHIFT		0
+#define M98090_REC_A2_MID_WIDTH		8
+#define M98090_REC_A2_LO_MASK		(255<<0)
+#define M98090_REC_A2_LO_SHIFT		0
+#define M98090_REC_A2_LO_WIDTH		8
+
+/*
+ * M98090_REG_DMIC3_VOLUME
+ */
+#define M98090_DMIC_AV3G_MASK		(7<<4)
+#define M98090_DMIC_AV3G_SHIFT		4
+#define M98090_DMIC_AV3G_WIDTH		3
+#define M98090_DMIC_AV3G_NUM		(1<<M98090_DMIC_AV3G_WIDTH)
+#define M98090_DMIC_AV3_MASK		(15<<0)
+#define M98090_DMIC_AV3_SHIFT		0
+#define M98090_DMIC_AV3_WIDTH		4
+#define M98090_DMIC_AV3_NUM		(1<<M98090_DMIC_AV3_WIDTH)
+
+/*
+ * M98090_REG_DMIC4_VOLUME
+ */
+#define M98090_DMIC_AV4G_MASK		(7<<4)
+#define M98090_DMIC_AV4G_SHIFT		4
+#define M98090_DMIC_AV4G_WIDTH		3
+#define M98090_DMIC_AV4G_NUM		(1<<M98090_DMIC_AV4G_WIDTH)
+#define M98090_DMIC_AV4_MASK		(15<<0)
+#define M98090_DMIC_AV4_SHIFT		0
+#define M98090_DMIC_AV4_WIDTH		4
+#define M98090_DMIC_AV4_NUM		(1<<M98090_DMIC_AV4_WIDTH)
+
+/*
+ * M98090_REG_DMIC34_BQ_PREATTEN
+ */
+#define M98090_AV34BQ_MASK		(15<<0)
+#define M98090_AV34BQ_SHIFT		0
+#define M98090_AV34BQ_WIDTH		4
+#define M98090_AV34BQ_NUM		(1<<M98090_AV34BQ_WIDTH)
+
+/*
+ * M98090_REG_RECORD_TDM_SLOT
+ */
+#define M98090_TDM_SLOTADCL_MASK	(3<<6)
+#define M98090_TDM_SLOTADCL_SHIFT	6
+#define M98090_TDM_SLOTADCL_WIDTH	2
+#define M98090_TDM_SLOTADCL_NUM		(1<<M98090_TDM_SLOTADCL_WIDTH)
+#define M98090_TDM_SLOTADCR_MASK	(3<<4)
+#define M98090_TDM_SLOTADCR_SHIFT	4
+#define M98090_TDM_SLOTADCR_WIDTH	2
+#define M98090_TDM_SLOTADCR_NUM		(1<<M98090_TDM_SLOTADCR_WIDTH)
+#define M98090_TDM_SLOTDMIC3_MASK	(3<<2)
+#define M98090_TDM_SLOTDMIC3_SHIFT	2
+#define M98090_TDM_SLOTDMIC3_WIDTH	2
+#define M98090_TDM_SLOTDMIC3_NUM	(1<<M98090_TDM_SLOTDMIC3_WIDTH)
+#define M98090_TDM_SLOTDMIC4_MASK	(3<<0)
+#define M98090_TDM_SLOTDMIC4_SHIFT	0
+#define M98090_TDM_SLOTDMIC4_WIDTH	2
+#define M98090_TDM_SLOTDMIC4_NUM	(1<<M98090_TDM_SLOTDMIC4_WIDTH)
+
+/*
+ * M98090_REG_SAMPLE_RATE
+ */
+#define M98090_DMIC34_ZEROPAD_MASK	(1<<4)
+#define M98090_DMIC34_ZEROPAD_SHIFT	4
+#define M98090_DMIC34_ZEROPAD_WIDTH	1
+#define M98090_DMIC34_ZEROPAD_NUM	(1<<M98090_DIGMIC4_WIDTH)
+#define M98090_DMIC34_SRDIV_MASK	(7<<0)
+#define M98090_DMIC34_SRDIV_SHIFT	0
+#define M98090_DMIC34_SRDIV_WIDTH	3
+
+/*
+ * M98090_REG_DMIC34_BIQUAD_BASE
+ */
+#define M98090_DMIC34_B0_HI_MASK	(255<<0)
+#define M98090_DMIC34_B0_HI_SHIFT	0
+#define M98090_DMIC34_B0_HI_WIDTH	8
+#define M98090_DMIC34_B0_MID_MASK	(255<<0)
+#define M98090_DMIC34_B0_MID_SHIFT	0
+#define M98090_DMIC34_B0_MID_WIDTH	8
+#define M98090_DMIC34_B0_LO_MASK	(255<<0)
+#define M98090_DMIC34_B0_LO_SHIFT	0
+#define M98090_DMIC34_B0_LO_WIDTH	8
+#define M98090_DMIC34_B1_HI_MASK	(255<<0)
+#define M98090_DMIC34_B1_HI_SHIFT	0
+#define M98090_DMIC34_B1_HI_WIDTH	8
+#define M98090_DMIC34_B1_MID_MASK	(255<<0)
+#define M98090_DMIC34_B1_MID_SHIFT	0
+#define M98090_DMIC34_B1_MID_WIDTH	8
+#define M98090_DMIC34_B1_LO_MASK	(255<<0)
+#define M98090_DMIC34_B1_LO_SHIFT	0
+#define M98090_DMIC34_B1_LO_WIDTH	8
+#define M98090_DMIC34_B2_HI_MASK	(255<<0)
+#define M98090_DMIC34_B2_HI_SHIFT	0
+#define M98090_DMIC34_B2_HI_WIDTH	8
+#define M98090_DMIC34_B2_MID_MASK	(255<<0)
+#define M98090_DMIC34_B2_MID_SHIFT	0
+#define M98090_DMIC34_B2_MID_WIDTH	8
+#define M98090_DMIC34_B2_LO_MASK	(255<<0)
+#define M98090_DMIC34_B2_LO_SHIFT	0
+#define M98090_DMIC34_B2_LO_WIDTH	8
+#define M98090_DMIC34_A1_HI_MASK	(255<<0)
+#define M98090_DMIC34_A1_HI_SHIFT	0
+#define M98090_DMIC34_A1_HI_WIDTH	8
+#define M98090_DMIC34_A1_MID_MASK	(255<<0)
+#define M98090_DMIC34_A1_MID_SHIFT	0
+#define M98090_DMIC34_A1_MID_WIDTH	8
+#define M98090_DMIC34_A1_LO_MASK	(255<<0)
+#define M98090_DMIC34_A1_LO_SHIFT	0
+#define M98090_DMIC34_A1_LO_WIDTH	8
+#define M98090_DMIC34_A2_HI_MASK	(255<<0)
+#define M98090_DMIC34_A2_HI_SHIFT	0
+#define M98090_DMIC34_A2_HI_WIDTH	8
+#define M98090_DMIC34_A2_MID_MASK	(255<<0)
+#define M98090_DMIC34_A2_MID_SHIFT	0
+#define M98090_DMIC34_A2_MID_WIDTH	8
+#define M98090_DMIC34_A2_LO_MASK	(255<<0)
+#define M98090_DMIC34_A2_LO_SHIFT	0
+#define M98090_DMIC34_A2_LO_WIDTH	8
+
+#define M98090_JACK_STATE_NO_HEADSET	0
+#define M98090_JACK_STATE_NO_HEADSET_2	1
+#define M98090_JACK_STATE_HEADPHONE	2
+#define M98090_JACK_STATE_HEADSET	3
+
+/*
+ * M98090_REG_REVISION_ID
+ */
+#define M98090_REVID_MASK		(255<<0)
+#define M98090_REVID_SHIFT		0
+#define M98090_REVID_WIDTH		8
+#define M98090_REVID_NUM		(1<<M98090_REVID_WIDTH)
+
+/* Silicon revision number */
+#define M98090_REVA			0x40
+#define M98091_REVA			0x50
+
+enum max98090_type {
+	MAX98090,
+	MAX98091,
+};
+
+struct max98090_cdata {
+	unsigned int rate;
+	unsigned int fmt;
+};
+
+struct max98090_priv {
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	enum max98090_type devtype;
+	struct max98090_pdata *pdata;
+	struct clk *mclk;
+	unsigned int sysclk;
+	unsigned int pclk;
+	unsigned int bclk;
+	unsigned int lrclk;
+	u32 dmic_freq;
+	struct max98090_cdata dai[1];
+	int jack_state;
+	struct delayed_work jack_work;
+	struct delayed_work pll_det_enable_work;
+	struct work_struct pll_det_disable_work;
+	struct work_struct pll_work;
+	struct snd_soc_jack *jack;
+	unsigned int dai_fmt;
+	int tdm_slots;
+	int tdm_width;
+	u8 lin_state;
+	unsigned int pa1en;
+	unsigned int pa2en;
+	unsigned int sidetone;
+	bool master;
+	bool shdn_pending;
+};
+
+int max98090_mic_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *jack);
+
+#endif
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
new file mode 100644
index 0000000..3b3a10d
--- /dev/null
+++ b/sound/soc/codecs/max98095.c
@@ -0,0 +1,2173 @@
+/*
+ * max98095.c -- MAX98095 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+#include <sound/max98095.h>
+#include <sound/jack.h>
+#include "max98095.h"
+
+enum max98095_type {
+	MAX98095,
+};
+
+struct max98095_cdata {
+	unsigned int rate;
+	unsigned int fmt;
+	int eq_sel;
+	int bq_sel;
+};
+
+struct max98095_priv {
+	struct regmap *regmap;
+	enum max98095_type devtype;
+	struct max98095_pdata *pdata;
+	struct clk *mclk;
+	unsigned int sysclk;
+	struct max98095_cdata dai[3];
+	const char **eq_texts;
+	const char **bq_texts;
+	struct soc_enum eq_enum;
+	struct soc_enum bq_enum;
+	int eq_textcnt;
+	int bq_textcnt;
+	u8 lin_state;
+	unsigned int mic1pre;
+	unsigned int mic2pre;
+	struct snd_soc_jack *headphone_jack;
+	struct snd_soc_jack *mic_jack;
+	struct mutex lock;
+};
+
+static const struct reg_default max98095_reg_def[] = {
+	{  0xf, 0x00 }, /* 0F */
+	{ 0x10, 0x00 }, /* 10 */
+	{ 0x11, 0x00 }, /* 11 */
+	{ 0x12, 0x00 }, /* 12 */
+	{ 0x13, 0x00 }, /* 13 */
+	{ 0x14, 0x00 }, /* 14 */
+	{ 0x15, 0x00 }, /* 15 */
+	{ 0x16, 0x00 }, /* 16 */
+	{ 0x17, 0x00 }, /* 17 */
+	{ 0x18, 0x00 }, /* 18 */
+	{ 0x19, 0x00 }, /* 19 */
+	{ 0x1a, 0x00 }, /* 1A */
+	{ 0x1b, 0x00 }, /* 1B */
+	{ 0x1c, 0x00 }, /* 1C */
+	{ 0x1d, 0x00 }, /* 1D */
+	{ 0x1e, 0x00 }, /* 1E */
+	{ 0x1f, 0x00 }, /* 1F */
+	{ 0x20, 0x00 }, /* 20 */
+	{ 0x21, 0x00 }, /* 21 */
+	{ 0x22, 0x00 }, /* 22 */
+	{ 0x23, 0x00 }, /* 23 */
+	{ 0x24, 0x00 }, /* 24 */
+	{ 0x25, 0x00 }, /* 25 */
+	{ 0x26, 0x00 }, /* 26 */
+	{ 0x27, 0x00 }, /* 27 */
+	{ 0x28, 0x00 }, /* 28 */
+	{ 0x29, 0x00 }, /* 29 */
+	{ 0x2a, 0x00 }, /* 2A */
+	{ 0x2b, 0x00 }, /* 2B */
+	{ 0x2c, 0x00 }, /* 2C */
+	{ 0x2d, 0x00 }, /* 2D */
+	{ 0x2e, 0x00 }, /* 2E */
+	{ 0x2f, 0x00 }, /* 2F */
+	{ 0x30, 0x00 }, /* 30 */
+	{ 0x31, 0x00 }, /* 31 */
+	{ 0x32, 0x00 }, /* 32 */
+	{ 0x33, 0x00 }, /* 33 */
+	{ 0x34, 0x00 }, /* 34 */
+	{ 0x35, 0x00 }, /* 35 */
+	{ 0x36, 0x00 }, /* 36 */
+	{ 0x37, 0x00 }, /* 37 */
+	{ 0x38, 0x00 }, /* 38 */
+	{ 0x39, 0x00 }, /* 39 */
+	{ 0x3a, 0x00 }, /* 3A */
+	{ 0x3b, 0x00 }, /* 3B */
+	{ 0x3c, 0x00 }, /* 3C */
+	{ 0x3d, 0x00 }, /* 3D */
+	{ 0x3e, 0x00 }, /* 3E */
+	{ 0x3f, 0x00 }, /* 3F */
+	{ 0x40, 0x00 }, /* 40 */
+	{ 0x41, 0x00 }, /* 41 */
+	{ 0x42, 0x00 }, /* 42 */
+	{ 0x43, 0x00 }, /* 43 */
+	{ 0x44, 0x00 }, /* 44 */
+	{ 0x45, 0x00 }, /* 45 */
+	{ 0x46, 0x00 }, /* 46 */
+	{ 0x47, 0x00 }, /* 47 */
+	{ 0x48, 0x00 }, /* 48 */
+	{ 0x49, 0x00 }, /* 49 */
+	{ 0x4a, 0x00 }, /* 4A */
+	{ 0x4b, 0x00 }, /* 4B */
+	{ 0x4c, 0x00 }, /* 4C */
+	{ 0x4d, 0x00 }, /* 4D */
+	{ 0x4e, 0x00 }, /* 4E */
+	{ 0x4f, 0x00 }, /* 4F */
+	{ 0x50, 0x00 }, /* 50 */
+	{ 0x51, 0x00 }, /* 51 */
+	{ 0x52, 0x00 }, /* 52 */
+	{ 0x53, 0x00 }, /* 53 */
+	{ 0x54, 0x00 }, /* 54 */
+	{ 0x55, 0x00 }, /* 55 */
+	{ 0x56, 0x00 }, /* 56 */
+	{ 0x57, 0x00 }, /* 57 */
+	{ 0x58, 0x00 }, /* 58 */
+	{ 0x59, 0x00 }, /* 59 */
+	{ 0x5a, 0x00 }, /* 5A */
+	{ 0x5b, 0x00 }, /* 5B */
+	{ 0x5c, 0x00 }, /* 5C */
+	{ 0x5d, 0x00 }, /* 5D */
+	{ 0x5e, 0x00 }, /* 5E */
+	{ 0x5f, 0x00 }, /* 5F */
+	{ 0x60, 0x00 }, /* 60 */
+	{ 0x61, 0x00 }, /* 61 */
+	{ 0x62, 0x00 }, /* 62 */
+	{ 0x63, 0x00 }, /* 63 */
+	{ 0x64, 0x00 }, /* 64 */
+	{ 0x65, 0x00 }, /* 65 */
+	{ 0x66, 0x00 }, /* 66 */
+	{ 0x67, 0x00 }, /* 67 */
+	{ 0x68, 0x00 }, /* 68 */
+	{ 0x69, 0x00 }, /* 69 */
+	{ 0x6a, 0x00 }, /* 6A */
+	{ 0x6b, 0x00 }, /* 6B */
+	{ 0x6c, 0x00 }, /* 6C */
+	{ 0x6d, 0x00 }, /* 6D */
+	{ 0x6e, 0x00 }, /* 6E */
+	{ 0x6f, 0x00 }, /* 6F */
+	{ 0x70, 0x00 }, /* 70 */
+	{ 0x71, 0x00 }, /* 71 */
+	{ 0x72, 0x00 }, /* 72 */
+	{ 0x73, 0x00 }, /* 73 */
+	{ 0x74, 0x00 }, /* 74 */
+	{ 0x75, 0x00 }, /* 75 */
+	{ 0x76, 0x00 }, /* 76 */
+	{ 0x77, 0x00 }, /* 77 */
+	{ 0x78, 0x00 }, /* 78 */
+	{ 0x79, 0x00 }, /* 79 */
+	{ 0x7a, 0x00 }, /* 7A */
+	{ 0x7b, 0x00 }, /* 7B */
+	{ 0x7c, 0x00 }, /* 7C */
+	{ 0x7d, 0x00 }, /* 7D */
+	{ 0x7e, 0x00 }, /* 7E */
+	{ 0x7f, 0x00 }, /* 7F */
+	{ 0x80, 0x00 }, /* 80 */
+	{ 0x81, 0x00 }, /* 81 */
+	{ 0x82, 0x00 }, /* 82 */
+	{ 0x83, 0x00 }, /* 83 */
+	{ 0x84, 0x00 }, /* 84 */
+	{ 0x85, 0x00 }, /* 85 */
+	{ 0x86, 0x00 }, /* 86 */
+	{ 0x87, 0x00 }, /* 87 */
+	{ 0x88, 0x00 }, /* 88 */
+	{ 0x89, 0x00 }, /* 89 */
+	{ 0x8a, 0x00 }, /* 8A */
+	{ 0x8b, 0x00 }, /* 8B */
+	{ 0x8c, 0x00 }, /* 8C */
+	{ 0x8d, 0x00 }, /* 8D */
+	{ 0x8e, 0x00 }, /* 8E */
+	{ 0x8f, 0x00 }, /* 8F */
+	{ 0x90, 0x00 }, /* 90 */
+	{ 0x91, 0x00 }, /* 91 */
+	{ 0x92, 0x30 }, /* 92 */
+	{ 0x93, 0xF0 }, /* 93 */
+	{ 0x94, 0x00 }, /* 94 */
+	{ 0x95, 0x00 }, /* 95 */
+	{ 0x96, 0x3F }, /* 96 */
+	{ 0x97, 0x00 }, /* 97 */
+	{ 0xff, 0x00 }, /* FF */
+};
+
+static bool max98095_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case M98095_001_HOST_INT_STS ... M98095_097_PWR_SYS:
+	case M98095_0FF_REV_ID:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max98095_writeable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case M98095_00F_HOST_CFG ... M98095_097_PWR_SYS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max98095_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case M98095_000_HOST_DATA ... M98095_00E_TEMP_SENSOR_STS:
+	case M98095_REG_MAX_CACHED + 1 ... M98095_0FF_REV_ID:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config max98095_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.reg_defaults = max98095_reg_def,
+	.num_reg_defaults = ARRAY_SIZE(max98095_reg_def),
+	.max_register = M98095_0FF_REV_ID,
+	.cache_type = REGCACHE_RBTREE,
+
+	.readable_reg = max98095_readable,
+	.writeable_reg = max98095_writeable,
+	.volatile_reg = max98095_volatile,
+};
+
+/*
+ * Load equalizer DSP coefficient configurations registers
+ */
+static void m98095_eq_band(struct snd_soc_component *component, unsigned int dai,
+		    unsigned int band, u16 *coefs)
+{
+	unsigned int eq_reg;
+	unsigned int i;
+
+	if (WARN_ON(band > 4) ||
+	    WARN_ON(dai > 1))
+		return;
+
+	/* Load the base register address */
+	eq_reg = dai ? M98095_142_DAI2_EQ_BASE : M98095_110_DAI1_EQ_BASE;
+
+	/* Add the band address offset, note adjustment for word address */
+	eq_reg += band * (M98095_COEFS_PER_BAND << 1);
+
+	/* Step through the registers and coefs */
+	for (i = 0; i < M98095_COEFS_PER_BAND; i++) {
+		snd_soc_component_write(component, eq_reg++, M98095_BYTE1(coefs[i]));
+		snd_soc_component_write(component, eq_reg++, M98095_BYTE0(coefs[i]));
+	}
+}
+
+/*
+ * Load biquad filter coefficient configurations registers
+ */
+static void m98095_biquad_band(struct snd_soc_component *component, unsigned int dai,
+		    unsigned int band, u16 *coefs)
+{
+	unsigned int bq_reg;
+	unsigned int i;
+
+	if (WARN_ON(band > 1) ||
+	    WARN_ON(dai > 1))
+		return;
+
+	/* Load the base register address */
+	bq_reg = dai ? M98095_17E_DAI2_BQ_BASE : M98095_174_DAI1_BQ_BASE;
+
+	/* Add the band address offset, note adjustment for word address */
+	bq_reg += band * (M98095_COEFS_PER_BAND << 1);
+
+	/* Step through the registers and coefs */
+	for (i = 0; i < M98095_COEFS_PER_BAND; i++) {
+		snd_soc_component_write(component, bq_reg++, M98095_BYTE1(coefs[i]));
+		snd_soc_component_write(component, bq_reg++, M98095_BYTE0(coefs[i]));
+	}
+}
+
+static const char * const max98095_fltr_mode[] = { "Voice", "Music" };
+static SOC_ENUM_SINGLE_DECL(max98095_dai1_filter_mode_enum,
+			    M98095_02E_DAI1_FILTERS, 7,
+			    max98095_fltr_mode);
+static SOC_ENUM_SINGLE_DECL(max98095_dai2_filter_mode_enum,
+			    M98095_038_DAI2_FILTERS, 7,
+			    max98095_fltr_mode);
+
+static const char * const max98095_extmic_text[] = { "None", "MIC1", "MIC2" };
+
+static SOC_ENUM_SINGLE_DECL(max98095_extmic_enum,
+			    M98095_087_CFG_MIC, 0,
+			    max98095_extmic_text);
+
+static const struct snd_kcontrol_new max98095_extmic_mux =
+	SOC_DAPM_ENUM("External MIC Mux", max98095_extmic_enum);
+
+static const char * const max98095_linein_text[] = { "INA", "INB" };
+
+static SOC_ENUM_SINGLE_DECL(max98095_linein_enum,
+			    M98095_086_CFG_LINE, 6,
+			    max98095_linein_text);
+
+static const struct snd_kcontrol_new max98095_linein_mux =
+	SOC_DAPM_ENUM("Linein Input Mux", max98095_linein_enum);
+
+static const char * const max98095_line_mode_text[] = {
+	"Stereo", "Differential"};
+
+static SOC_ENUM_SINGLE_DECL(max98095_linein_mode_enum,
+			    M98095_086_CFG_LINE, 7,
+			    max98095_line_mode_text);
+
+static SOC_ENUM_SINGLE_DECL(max98095_lineout_mode_enum,
+			    M98095_086_CFG_LINE, 4,
+			    max98095_line_mode_text);
+
+static const char * const max98095_dai_fltr[] = {
+	"Off", "Elliptical-HPF-16k", "Butterworth-HPF-16k",
+	"Elliptical-HPF-8k", "Butterworth-HPF-8k", "Butterworth-HPF-Fs/240"};
+static SOC_ENUM_SINGLE_DECL(max98095_dai1_dac_filter_enum,
+			    M98095_02E_DAI1_FILTERS, 0,
+			    max98095_dai_fltr);
+static SOC_ENUM_SINGLE_DECL(max98095_dai2_dac_filter_enum,
+			    M98095_038_DAI2_FILTERS, 0,
+			    max98095_dai_fltr);
+static SOC_ENUM_SINGLE_DECL(max98095_dai3_dac_filter_enum,
+			    M98095_042_DAI3_FILTERS, 0,
+			    max98095_dai_fltr);
+
+static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	unsigned int sel = ucontrol->value.integer.value[0];
+
+	max98095->mic1pre = sel;
+	snd_soc_component_update_bits(component, M98095_05F_LVL_MIC1, M98095_MICPRE_MASK,
+		(1+sel)<<M98095_MICPRE_SHIFT);
+
+	return 0;
+}
+
+static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = max98095->mic1pre;
+	return 0;
+}
+
+static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	unsigned int sel = ucontrol->value.integer.value[0];
+
+	max98095->mic2pre = sel;
+	snd_soc_component_update_bits(component, M98095_060_LVL_MIC2, M98095_MICPRE_MASK,
+		(1+sel)<<M98095_MICPRE_SHIFT);
+
+	return 0;
+}
+
+static int max98095_mic2pre_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = max98095->mic2pre;
+	return 0;
+}
+
+static const DECLARE_TLV_DB_RANGE(max98095_micboost_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+	2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(max98095_mic_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(max98095_adc_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(max98095_adcboost_tlv, 0, 600, 0);
+
+static const DECLARE_TLV_DB_RANGE(max98095_hp_tlv,
+	0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0),
+	7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0),
+	15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0),
+	22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0),
+	28, 31, TLV_DB_SCALE_ITEM(150, 50, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(max98095_spk_tlv,
+	0, 10, TLV_DB_SCALE_ITEM(-5900, 400, 0),
+	11, 18, TLV_DB_SCALE_ITEM(-1700, 200, 0),
+	19, 27, TLV_DB_SCALE_ITEM(-200, 100, 0),
+	28, 39, TLV_DB_SCALE_ITEM(650, 50, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(max98095_rcv_lout_tlv,
+	0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0),
+	7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0),
+	15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0),
+	22, 27, TLV_DB_SCALE_ITEM(100, 100, 0),
+	28, 31, TLV_DB_SCALE_ITEM(650, 50, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(max98095_lin_tlv,
+	0, 2, TLV_DB_SCALE_ITEM(-600, 300, 0),
+	3, 3, TLV_DB_SCALE_ITEM(300, 1100, 0),
+	4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0)
+);
+
+static const struct snd_kcontrol_new max98095_snd_controls[] = {
+
+	SOC_DOUBLE_R_TLV("Headphone Volume", M98095_064_LVL_HP_L,
+		M98095_065_LVL_HP_R, 0, 31, 0, max98095_hp_tlv),
+
+	SOC_DOUBLE_R_TLV("Speaker Volume", M98095_067_LVL_SPK_L,
+		M98095_068_LVL_SPK_R, 0, 39, 0, max98095_spk_tlv),
+
+	SOC_SINGLE_TLV("Receiver Volume", M98095_066_LVL_RCV,
+		0, 31, 0, max98095_rcv_lout_tlv),
+
+	SOC_DOUBLE_R_TLV("Lineout Volume", M98095_062_LVL_LINEOUT1,
+		M98095_063_LVL_LINEOUT2, 0, 31, 0, max98095_rcv_lout_tlv),
+
+	SOC_DOUBLE_R("Headphone Switch", M98095_064_LVL_HP_L,
+		M98095_065_LVL_HP_R, 7, 1, 1),
+
+	SOC_DOUBLE_R("Speaker Switch", M98095_067_LVL_SPK_L,
+		M98095_068_LVL_SPK_R, 7, 1, 1),
+
+	SOC_SINGLE("Receiver Switch", M98095_066_LVL_RCV, 7, 1, 1),
+
+	SOC_DOUBLE_R("Lineout Switch", M98095_062_LVL_LINEOUT1,
+		M98095_063_LVL_LINEOUT2, 7, 1, 1),
+
+	SOC_SINGLE_TLV("MIC1 Volume", M98095_05F_LVL_MIC1, 0, 20, 1,
+		max98095_mic_tlv),
+
+	SOC_SINGLE_TLV("MIC2 Volume", M98095_060_LVL_MIC2, 0, 20, 1,
+		max98095_mic_tlv),
+
+	SOC_SINGLE_EXT_TLV("MIC1 Boost Volume",
+			M98095_05F_LVL_MIC1, 5, 2, 0,
+			max98095_mic1pre_get, max98095_mic1pre_set,
+			max98095_micboost_tlv),
+	SOC_SINGLE_EXT_TLV("MIC2 Boost Volume",
+			M98095_060_LVL_MIC2, 5, 2, 0,
+			max98095_mic2pre_get, max98095_mic2pre_set,
+			max98095_micboost_tlv),
+
+	SOC_SINGLE_TLV("Linein Volume", M98095_061_LVL_LINEIN, 0, 5, 1,
+		max98095_lin_tlv),
+
+	SOC_SINGLE_TLV("ADCL Volume", M98095_05D_LVL_ADC_L, 0, 15, 1,
+		max98095_adc_tlv),
+	SOC_SINGLE_TLV("ADCR Volume", M98095_05E_LVL_ADC_R, 0, 15, 1,
+		max98095_adc_tlv),
+
+	SOC_SINGLE_TLV("ADCL Boost Volume", M98095_05D_LVL_ADC_L, 4, 3, 0,
+		max98095_adcboost_tlv),
+	SOC_SINGLE_TLV("ADCR Boost Volume", M98095_05E_LVL_ADC_R, 4, 3, 0,
+		max98095_adcboost_tlv),
+
+	SOC_SINGLE("EQ1 Switch", M98095_088_CFG_LEVEL, 0, 1, 0),
+	SOC_SINGLE("EQ2 Switch", M98095_088_CFG_LEVEL, 1, 1, 0),
+
+	SOC_SINGLE("Biquad1 Switch", M98095_088_CFG_LEVEL, 2, 1, 0),
+	SOC_SINGLE("Biquad2 Switch", M98095_088_CFG_LEVEL, 3, 1, 0),
+
+	SOC_ENUM("DAI1 Filter Mode", max98095_dai1_filter_mode_enum),
+	SOC_ENUM("DAI2 Filter Mode", max98095_dai2_filter_mode_enum),
+	SOC_ENUM("DAI1 DAC Filter", max98095_dai1_dac_filter_enum),
+	SOC_ENUM("DAI2 DAC Filter", max98095_dai2_dac_filter_enum),
+	SOC_ENUM("DAI3 DAC Filter", max98095_dai3_dac_filter_enum),
+
+	SOC_ENUM("Linein Mode", max98095_linein_mode_enum),
+	SOC_ENUM("Lineout Mode", max98095_lineout_mode_enum),
+};
+
+/* Left speaker mixer switch */
+static const struct snd_kcontrol_new max98095_left_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_050_MIX_SPK_LEFT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_050_MIX_SPK_LEFT, 6, 1, 0),
+	SOC_DAPM_SINGLE("Mono DAC2 Switch", M98095_050_MIX_SPK_LEFT, 3, 1, 0),
+	SOC_DAPM_SINGLE("Mono DAC3 Switch", M98095_050_MIX_SPK_LEFT, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_050_MIX_SPK_LEFT, 4, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_050_MIX_SPK_LEFT, 5, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_050_MIX_SPK_LEFT, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_050_MIX_SPK_LEFT, 2, 1, 0),
+};
+
+/* Right speaker mixer switch */
+static const struct snd_kcontrol_new max98095_right_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_051_MIX_SPK_RIGHT, 6, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_051_MIX_SPK_RIGHT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Mono DAC2 Switch", M98095_051_MIX_SPK_RIGHT, 3, 1, 0),
+	SOC_DAPM_SINGLE("Mono DAC3 Switch", M98095_051_MIX_SPK_RIGHT, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_051_MIX_SPK_RIGHT, 5, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_051_MIX_SPK_RIGHT, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_051_MIX_SPK_RIGHT, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_051_MIX_SPK_RIGHT, 2, 1, 0),
+};
+
+/* Left headphone mixer switch */
+static const struct snd_kcontrol_new max98095_left_hp_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04C_MIX_HP_LEFT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04C_MIX_HP_LEFT, 5, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04C_MIX_HP_LEFT, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04C_MIX_HP_LEFT, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04C_MIX_HP_LEFT, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04C_MIX_HP_LEFT, 2, 1, 0),
+};
+
+/* Right headphone mixer switch */
+static const struct snd_kcontrol_new max98095_right_hp_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04D_MIX_HP_RIGHT, 5, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04D_MIX_HP_RIGHT, 0, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04D_MIX_HP_RIGHT, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04D_MIX_HP_RIGHT, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04D_MIX_HP_RIGHT, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04D_MIX_HP_RIGHT, 2, 1, 0),
+};
+
+/* Receiver earpiece mixer switch */
+static const struct snd_kcontrol_new max98095_mono_rcv_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04F_MIX_RCV, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04F_MIX_RCV, 5, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04F_MIX_RCV, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04F_MIX_RCV, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04F_MIX_RCV, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04F_MIX_RCV, 2, 1, 0),
+};
+
+/* Left lineout mixer switch */
+static const struct snd_kcontrol_new max98095_left_lineout_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_053_MIX_LINEOUT1, 5, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_053_MIX_LINEOUT1, 0, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_053_MIX_LINEOUT1, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_053_MIX_LINEOUT1, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_053_MIX_LINEOUT1, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_053_MIX_LINEOUT1, 2, 1, 0),
+};
+
+/* Right lineout mixer switch */
+static const struct snd_kcontrol_new max98095_right_lineout_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_054_MIX_LINEOUT2, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_054_MIX_LINEOUT2, 5, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_054_MIX_LINEOUT2, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_054_MIX_LINEOUT2, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_054_MIX_LINEOUT2, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_054_MIX_LINEOUT2, 2, 1, 0),
+};
+
+/* Left ADC mixer switch */
+static const struct snd_kcontrol_new max98095_left_ADC_mixer_controls[] = {
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04A_MIX_ADC_LEFT, 7, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04A_MIX_ADC_LEFT, 6, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04A_MIX_ADC_LEFT, 3, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04A_MIX_ADC_LEFT, 2, 1, 0),
+};
+
+/* Right ADC mixer switch */
+static const struct snd_kcontrol_new max98095_right_ADC_mixer_controls[] = {
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04B_MIX_ADC_RIGHT, 7, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04B_MIX_ADC_RIGHT, 6, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04B_MIX_ADC_RIGHT, 3, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04B_MIX_ADC_RIGHT, 2, 1, 0),
+};
+
+static int max98095_mic_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (w->reg == M98095_05F_LVL_MIC1) {
+			snd_soc_component_update_bits(component, w->reg, M98095_MICPRE_MASK,
+				(1+max98095->mic1pre)<<M98095_MICPRE_SHIFT);
+		} else {
+			snd_soc_component_update_bits(component, w->reg, M98095_MICPRE_MASK,
+				(1+max98095->mic2pre)<<M98095_MICPRE_SHIFT);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, w->reg, M98095_MICPRE_MASK, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * The line inputs are stereo inputs with the left and right
+ * channels sharing a common PGA power control signal.
+ */
+static int max98095_line_pga(struct snd_soc_dapm_widget *w,
+			     int event, u8 channel)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	u8 *state;
+
+	if (WARN_ON(!(channel == 1 || channel == 2)))
+		return -EINVAL;
+
+	state = &max98095->lin_state;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		*state |= channel;
+		snd_soc_component_update_bits(component, w->reg,
+			(1 << w->shift), (1 << w->shift));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		*state &= ~channel;
+		if (*state == 0) {
+			snd_soc_component_update_bits(component, w->reg,
+				(1 << w->shift), 0);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int max98095_pga_in1_event(struct snd_soc_dapm_widget *w,
+				   struct snd_kcontrol *k, int event)
+{
+	return max98095_line_pga(w, event, 1);
+}
+
+static int max98095_pga_in2_event(struct snd_soc_dapm_widget *w,
+				   struct snd_kcontrol *k, int event)
+{
+	return max98095_line_pga(w, event, 2);
+}
+
+/*
+ * The stereo line out mixer outputs to two stereo line outs.
+ * The 2nd pair has a separate set of enables.
+ */
+static int max98095_lineout_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, w->reg,
+			(1 << (w->shift+2)), (1 << (w->shift+2)));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, w->reg,
+			(1 << (w->shift+2)), 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget max98095_dapm_widgets[] = {
+
+	SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98095_090_PWR_EN_IN, 0, 0),
+	SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98095_090_PWR_EN_IN, 1, 0),
+
+	SND_SOC_DAPM_DAC("DACL1", "HiFi Playback",
+		M98095_091_PWR_EN_OUT, 0, 0),
+	SND_SOC_DAPM_DAC("DACR1", "HiFi Playback",
+		M98095_091_PWR_EN_OUT, 1, 0),
+	SND_SOC_DAPM_DAC("DACM2", "Aux Playback",
+		M98095_091_PWR_EN_OUT, 2, 0),
+	SND_SOC_DAPM_DAC("DACM3", "Voice Playback",
+		M98095_091_PWR_EN_OUT, 2, 0),
+
+	SND_SOC_DAPM_PGA("HP Left Out", M98095_091_PWR_EN_OUT,
+		6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HP Right Out", M98095_091_PWR_EN_OUT,
+		7, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("SPK Left Out", M98095_091_PWR_EN_OUT,
+		4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SPK Right Out", M98095_091_PWR_EN_OUT,
+		5, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("RCV Mono Out", M98095_091_PWR_EN_OUT,
+		3, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA_E("LINE Left Out", M98095_092_PWR_EN_OUT,
+		0, 0, NULL, 0, max98095_lineout_event, SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA_E("LINE Right Out", M98095_092_PWR_EN_OUT,
+		1, 0, NULL, 0, max98095_lineout_event, SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_MUX("External MIC", SND_SOC_NOPM, 0, 0,
+		&max98095_extmic_mux),
+
+	SND_SOC_DAPM_MUX("Linein Mux", SND_SOC_NOPM, 0, 0,
+		&max98095_linein_mux),
+
+	SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_left_hp_mixer_controls[0],
+		ARRAY_SIZE(max98095_left_hp_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_right_hp_mixer_controls[0],
+		ARRAY_SIZE(max98095_right_hp_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left Speaker Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_left_speaker_mixer_controls[0],
+		ARRAY_SIZE(max98095_left_speaker_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Speaker Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_right_speaker_mixer_controls[0],
+		ARRAY_SIZE(max98095_right_speaker_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Receiver Mixer", SND_SOC_NOPM, 0, 0,
+	  &max98095_mono_rcv_mixer_controls[0],
+		ARRAY_SIZE(max98095_mono_rcv_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left Lineout Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_left_lineout_mixer_controls[0],
+		ARRAY_SIZE(max98095_left_lineout_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Lineout Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_right_lineout_mixer_controls[0],
+		ARRAY_SIZE(max98095_right_lineout_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_left_ADC_mixer_controls[0],
+		ARRAY_SIZE(max98095_left_ADC_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_right_ADC_mixer_controls[0],
+		ARRAY_SIZE(max98095_right_ADC_mixer_controls)),
+
+	SND_SOC_DAPM_PGA_E("MIC1 Input", M98095_05F_LVL_MIC1,
+		5, 0, NULL, 0, max98095_mic_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("MIC2 Input", M98095_060_LVL_MIC2,
+		5, 0, NULL, 0, max98095_mic_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("IN1 Input", M98095_090_PWR_EN_IN,
+		7, 0, NULL, 0, max98095_pga_in1_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("IN2 Input", M98095_090_PWR_EN_IN,
+		7, 0, NULL, 0, max98095_pga_in2_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MICBIAS("MICBIAS1", M98095_090_PWR_EN_IN, 2, 0),
+	SND_SOC_DAPM_MICBIAS("MICBIAS2", M98095_090_PWR_EN_IN, 3, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("SPKL"),
+	SND_SOC_DAPM_OUTPUT("SPKR"),
+	SND_SOC_DAPM_OUTPUT("RCV"),
+	SND_SOC_DAPM_OUTPUT("OUT1"),
+	SND_SOC_DAPM_OUTPUT("OUT2"),
+	SND_SOC_DAPM_OUTPUT("OUT3"),
+	SND_SOC_DAPM_OUTPUT("OUT4"),
+
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("INA1"),
+	SND_SOC_DAPM_INPUT("INA2"),
+	SND_SOC_DAPM_INPUT("INB1"),
+	SND_SOC_DAPM_INPUT("INB2"),
+};
+
+static const struct snd_soc_dapm_route max98095_audio_map[] = {
+	/* Left headphone output mixer */
+	{"Left Headphone Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Left Headphone Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Left Headphone Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left Headphone Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left Headphone Mixer", "IN1 Switch", "IN1 Input"},
+	{"Left Headphone Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Right headphone output mixer */
+	{"Right Headphone Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Right Headphone Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Right Headphone Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right Headphone Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right Headphone Mixer", "IN1 Switch", "IN1 Input"},
+	{"Right Headphone Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Left speaker output mixer */
+	{"Left Speaker Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Left Speaker Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Left Speaker Mixer", "Mono DAC2 Switch", "DACM2"},
+	{"Left Speaker Mixer", "Mono DAC3 Switch", "DACM3"},
+	{"Left Speaker Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left Speaker Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left Speaker Mixer", "IN1 Switch", "IN1 Input"},
+	{"Left Speaker Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Right speaker output mixer */
+	{"Right Speaker Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Right Speaker Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Right Speaker Mixer", "Mono DAC2 Switch", "DACM2"},
+	{"Right Speaker Mixer", "Mono DAC3 Switch", "DACM3"},
+	{"Right Speaker Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right Speaker Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right Speaker Mixer", "IN1 Switch", "IN1 Input"},
+	{"Right Speaker Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Earpiece/Receiver output mixer */
+	{"Receiver Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Receiver Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Receiver Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Receiver Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Receiver Mixer", "IN1 Switch", "IN1 Input"},
+	{"Receiver Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Left Lineout output mixer */
+	{"Left Lineout Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Left Lineout Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Left Lineout Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left Lineout Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left Lineout Mixer", "IN1 Switch", "IN1 Input"},
+	{"Left Lineout Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Right lineout output mixer */
+	{"Right Lineout Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Right Lineout Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Right Lineout Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right Lineout Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right Lineout Mixer", "IN1 Switch", "IN1 Input"},
+	{"Right Lineout Mixer", "IN2 Switch", "IN2 Input"},
+
+	{"HP Left Out", NULL, "Left Headphone Mixer"},
+	{"HP Right Out", NULL, "Right Headphone Mixer"},
+	{"SPK Left Out", NULL, "Left Speaker Mixer"},
+	{"SPK Right Out", NULL, "Right Speaker Mixer"},
+	{"RCV Mono Out", NULL, "Receiver Mixer"},
+	{"LINE Left Out", NULL, "Left Lineout Mixer"},
+	{"LINE Right Out", NULL, "Right Lineout Mixer"},
+
+	{"HPL", NULL, "HP Left Out"},
+	{"HPR", NULL, "HP Right Out"},
+	{"SPKL", NULL, "SPK Left Out"},
+	{"SPKR", NULL, "SPK Right Out"},
+	{"RCV", NULL, "RCV Mono Out"},
+	{"OUT1", NULL, "LINE Left Out"},
+	{"OUT2", NULL, "LINE Right Out"},
+	{"OUT3", NULL, "LINE Left Out"},
+	{"OUT4", NULL, "LINE Right Out"},
+
+	/* Left ADC input mixer */
+	{"Left ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left ADC Mixer", "IN1 Switch", "IN1 Input"},
+	{"Left ADC Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Right ADC input mixer */
+	{"Right ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right ADC Mixer", "IN1 Switch", "IN1 Input"},
+	{"Right ADC Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Inputs */
+	{"ADCL", NULL, "Left ADC Mixer"},
+	{"ADCR", NULL, "Right ADC Mixer"},
+
+	{"IN1 Input", NULL, "INA1"},
+	{"IN2 Input", NULL, "INA2"},
+
+	{"MIC1 Input", NULL, "MIC1"},
+	{"MIC2 Input", NULL, "MIC2"},
+};
+
+/* codec mclk clock divider coefficients */
+static const struct {
+	u32 rate;
+	u8  sr;
+} rate_table[] = {
+	{8000,  0x01},
+	{11025, 0x02},
+	{16000, 0x03},
+	{22050, 0x04},
+	{24000, 0x05},
+	{32000, 0x06},
+	{44100, 0x07},
+	{48000, 0x08},
+	{88200, 0x09},
+	{96000, 0x0A},
+};
+
+static int rate_value(int rate, u8 *value)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+		if (rate_table[i].rate >= rate) {
+			*value = rate_table[i].sr;
+			return 0;
+		}
+	}
+	*value = rate_table[0].sr;
+	return -EINVAL;
+}
+
+static int max98095_dai1_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct max98095_cdata *cdata;
+	unsigned long long ni;
+	unsigned int rate;
+	u8 regval;
+
+	cdata = &max98095->dai[0];
+
+	rate = params_rate(params);
+
+	switch (params_width(params)) {
+	case 16:
+		snd_soc_component_update_bits(component, M98095_02A_DAI1_FORMAT,
+			M98095_DAI_WS, 0);
+		break;
+	case 24:
+		snd_soc_component_update_bits(component, M98095_02A_DAI1_FORMAT,
+			M98095_DAI_WS, M98095_DAI_WS);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (rate_value(rate, &regval))
+		return -EINVAL;
+
+	snd_soc_component_update_bits(component, M98095_027_DAI1_CLKMODE,
+		M98095_CLKMODE_MASK, regval);
+	cdata->rate = rate;
+
+	/* Configure NI when operating as master */
+	if (snd_soc_component_read32(component, M98095_02A_DAI1_FORMAT) & M98095_DAI_MAS) {
+		if (max98095->sysclk == 0) {
+			dev_err(component->dev, "Invalid system clock frequency\n");
+			return -EINVAL;
+		}
+		ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+				* (unsigned long long int)rate;
+		do_div(ni, (unsigned long long int)max98095->sysclk);
+		snd_soc_component_write(component, M98095_028_DAI1_CLKCFG_HI,
+			(ni >> 8) & 0x7F);
+		snd_soc_component_write(component, M98095_029_DAI1_CLKCFG_LO,
+			ni & 0xFF);
+	}
+
+	/* Update sample rate mode */
+	if (rate < 50000)
+		snd_soc_component_update_bits(component, M98095_02E_DAI1_FILTERS,
+			M98095_DAI_DHF, 0);
+	else
+		snd_soc_component_update_bits(component, M98095_02E_DAI1_FILTERS,
+			M98095_DAI_DHF, M98095_DAI_DHF);
+
+	return 0;
+}
+
+static int max98095_dai2_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct max98095_cdata *cdata;
+	unsigned long long ni;
+	unsigned int rate;
+	u8 regval;
+
+	cdata = &max98095->dai[1];
+
+	rate = params_rate(params);
+
+	switch (params_width(params)) {
+	case 16:
+		snd_soc_component_update_bits(component, M98095_034_DAI2_FORMAT,
+			M98095_DAI_WS, 0);
+		break;
+	case 24:
+		snd_soc_component_update_bits(component, M98095_034_DAI2_FORMAT,
+			M98095_DAI_WS, M98095_DAI_WS);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (rate_value(rate, &regval))
+		return -EINVAL;
+
+	snd_soc_component_update_bits(component, M98095_031_DAI2_CLKMODE,
+		M98095_CLKMODE_MASK, regval);
+	cdata->rate = rate;
+
+	/* Configure NI when operating as master */
+	if (snd_soc_component_read32(component, M98095_034_DAI2_FORMAT) & M98095_DAI_MAS) {
+		if (max98095->sysclk == 0) {
+			dev_err(component->dev, "Invalid system clock frequency\n");
+			return -EINVAL;
+		}
+		ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+				* (unsigned long long int)rate;
+		do_div(ni, (unsigned long long int)max98095->sysclk);
+		snd_soc_component_write(component, M98095_032_DAI2_CLKCFG_HI,
+			(ni >> 8) & 0x7F);
+		snd_soc_component_write(component, M98095_033_DAI2_CLKCFG_LO,
+			ni & 0xFF);
+	}
+
+	/* Update sample rate mode */
+	if (rate < 50000)
+		snd_soc_component_update_bits(component, M98095_038_DAI2_FILTERS,
+			M98095_DAI_DHF, 0);
+	else
+		snd_soc_component_update_bits(component, M98095_038_DAI2_FILTERS,
+			M98095_DAI_DHF, M98095_DAI_DHF);
+
+	return 0;
+}
+
+static int max98095_dai3_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct max98095_cdata *cdata;
+	unsigned long long ni;
+	unsigned int rate;
+	u8 regval;
+
+	cdata = &max98095->dai[2];
+
+	rate = params_rate(params);
+
+	switch (params_width(params)) {
+	case 16:
+		snd_soc_component_update_bits(component, M98095_03E_DAI3_FORMAT,
+			M98095_DAI_WS, 0);
+		break;
+	case 24:
+		snd_soc_component_update_bits(component, M98095_03E_DAI3_FORMAT,
+			M98095_DAI_WS, M98095_DAI_WS);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (rate_value(rate, &regval))
+		return -EINVAL;
+
+	snd_soc_component_update_bits(component, M98095_03B_DAI3_CLKMODE,
+		M98095_CLKMODE_MASK, regval);
+	cdata->rate = rate;
+
+	/* Configure NI when operating as master */
+	if (snd_soc_component_read32(component, M98095_03E_DAI3_FORMAT) & M98095_DAI_MAS) {
+		if (max98095->sysclk == 0) {
+			dev_err(component->dev, "Invalid system clock frequency\n");
+			return -EINVAL;
+		}
+		ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+				* (unsigned long long int)rate;
+		do_div(ni, (unsigned long long int)max98095->sysclk);
+		snd_soc_component_write(component, M98095_03C_DAI3_CLKCFG_HI,
+			(ni >> 8) & 0x7F);
+		snd_soc_component_write(component, M98095_03D_DAI3_CLKCFG_LO,
+			ni & 0xFF);
+	}
+
+	/* Update sample rate mode */
+	if (rate < 50000)
+		snd_soc_component_update_bits(component, M98095_042_DAI3_FILTERS,
+			M98095_DAI_DHF, 0);
+	else
+		snd_soc_component_update_bits(component, M98095_042_DAI3_FILTERS,
+			M98095_DAI_DHF, M98095_DAI_DHF);
+
+	return 0;
+}
+
+static int max98095_dai_set_sysclk(struct snd_soc_dai *dai,
+				   int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+
+	/* Requested clock frequency is already setup */
+	if (freq == max98095->sysclk)
+		return 0;
+
+	if (!IS_ERR(max98095->mclk)) {
+		freq = clk_round_rate(max98095->mclk, freq);
+		clk_set_rate(max98095->mclk, freq);
+	}
+
+	/* Setup clocks for slave mode, and using the PLL
+	 * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+	 *         0x02 (when master clk is 20MHz to 40MHz)..
+	 *         0x03 (when master clk is 40MHz to 60MHz)..
+	 */
+	if ((freq >= 10000000) && (freq < 20000000)) {
+		snd_soc_component_write(component, M98095_026_SYS_CLK, 0x10);
+	} else if ((freq >= 20000000) && (freq < 40000000)) {
+		snd_soc_component_write(component, M98095_026_SYS_CLK, 0x20);
+	} else if ((freq >= 40000000) && (freq < 60000000)) {
+		snd_soc_component_write(component, M98095_026_SYS_CLK, 0x30);
+	} else {
+		dev_err(component->dev, "Invalid master clock frequency\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+	max98095->sysclk = freq;
+	return 0;
+}
+
+static int max98095_dai1_set_fmt(struct snd_soc_dai *codec_dai,
+				 unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct max98095_cdata *cdata;
+	u8 regval = 0;
+
+	cdata = &max98095->dai[0];
+
+	if (fmt != cdata->fmt) {
+		cdata->fmt = fmt;
+
+		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+		case SND_SOC_DAIFMT_CBS_CFS:
+			/* Slave mode PLL */
+			snd_soc_component_write(component, M98095_028_DAI1_CLKCFG_HI,
+				0x80);
+			snd_soc_component_write(component, M98095_029_DAI1_CLKCFG_LO,
+				0x00);
+			break;
+		case SND_SOC_DAIFMT_CBM_CFM:
+			/* Set to master mode */
+			regval |= M98095_DAI_MAS;
+			break;
+		case SND_SOC_DAIFMT_CBS_CFM:
+		case SND_SOC_DAIFMT_CBM_CFS:
+		default:
+			dev_err(component->dev, "Clock mode unsupported");
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+		case SND_SOC_DAIFMT_I2S:
+			regval |= M98095_DAI_DLY;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			regval |= M98095_DAI_WCI;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			regval |= M98095_DAI_BCI;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			regval |= M98095_DAI_BCI|M98095_DAI_WCI;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		snd_soc_component_update_bits(component, M98095_02A_DAI1_FORMAT,
+			M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
+			M98095_DAI_WCI, regval);
+
+		snd_soc_component_write(component, M98095_02B_DAI1_CLOCK, M98095_DAI_BSEL64);
+	}
+
+	return 0;
+}
+
+static int max98095_dai2_set_fmt(struct snd_soc_dai *codec_dai,
+				 unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct max98095_cdata *cdata;
+	u8 regval = 0;
+
+	cdata = &max98095->dai[1];
+
+	if (fmt != cdata->fmt) {
+		cdata->fmt = fmt;
+
+		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+		case SND_SOC_DAIFMT_CBS_CFS:
+			/* Slave mode PLL */
+			snd_soc_component_write(component, M98095_032_DAI2_CLKCFG_HI,
+				0x80);
+			snd_soc_component_write(component, M98095_033_DAI2_CLKCFG_LO,
+				0x00);
+			break;
+		case SND_SOC_DAIFMT_CBM_CFM:
+			/* Set to master mode */
+			regval |= M98095_DAI_MAS;
+			break;
+		case SND_SOC_DAIFMT_CBS_CFM:
+		case SND_SOC_DAIFMT_CBM_CFS:
+		default:
+			dev_err(component->dev, "Clock mode unsupported");
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+		case SND_SOC_DAIFMT_I2S:
+			regval |= M98095_DAI_DLY;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			regval |= M98095_DAI_WCI;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			regval |= M98095_DAI_BCI;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			regval |= M98095_DAI_BCI|M98095_DAI_WCI;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		snd_soc_component_update_bits(component, M98095_034_DAI2_FORMAT,
+			M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
+			M98095_DAI_WCI, regval);
+
+		snd_soc_component_write(component, M98095_035_DAI2_CLOCK,
+			M98095_DAI_BSEL64);
+	}
+
+	return 0;
+}
+
+static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai,
+				 unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct max98095_cdata *cdata;
+	u8 regval = 0;
+
+	cdata = &max98095->dai[2];
+
+	if (fmt != cdata->fmt) {
+		cdata->fmt = fmt;
+
+		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+		case SND_SOC_DAIFMT_CBS_CFS:
+			/* Slave mode PLL */
+			snd_soc_component_write(component, M98095_03C_DAI3_CLKCFG_HI,
+				0x80);
+			snd_soc_component_write(component, M98095_03D_DAI3_CLKCFG_LO,
+				0x00);
+			break;
+		case SND_SOC_DAIFMT_CBM_CFM:
+			/* Set to master mode */
+			regval |= M98095_DAI_MAS;
+			break;
+		case SND_SOC_DAIFMT_CBS_CFM:
+		case SND_SOC_DAIFMT_CBM_CFS:
+		default:
+			dev_err(component->dev, "Clock mode unsupported");
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+		case SND_SOC_DAIFMT_I2S:
+			regval |= M98095_DAI_DLY;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			regval |= M98095_DAI_WCI;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			regval |= M98095_DAI_BCI;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			regval |= M98095_DAI_BCI|M98095_DAI_WCI;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		snd_soc_component_update_bits(component, M98095_03E_DAI3_FORMAT,
+			M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
+			M98095_DAI_WCI, regval);
+
+		snd_soc_component_write(component, M98095_03F_DAI3_CLOCK,
+			M98095_DAI_BSEL64);
+	}
+
+	return 0;
+}
+
+static int max98095_set_bias_level(struct snd_soc_component *component,
+				   enum snd_soc_bias_level level)
+{
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/*
+		 * SND_SOC_BIAS_PREPARE is called while preparing for a
+		 * transition to ON or away from ON. If current bias_level
+		 * is SND_SOC_BIAS_ON, then it is preparing for a transition
+		 * away from ON. Disable the clock in that case, otherwise
+		 * enable it.
+		 */
+		if (IS_ERR(max98095->mclk))
+			break;
+
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
+			clk_disable_unprepare(max98095->mclk);
+		} else {
+			ret = clk_prepare_enable(max98095->mclk);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regcache_sync(max98095->regmap);
+
+			if (ret != 0) {
+				dev_err(component->dev, "Failed to sync cache: %d\n", ret);
+				return ret;
+			}
+		}
+
+		snd_soc_component_update_bits(component, M98095_090_PWR_EN_IN,
+				M98095_MBEN, M98095_MBEN);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, M98095_090_PWR_EN_IN,
+				M98095_MBEN, 0);
+		regcache_mark_dirty(max98095->regmap);
+		break;
+	}
+	return 0;
+}
+
+#define MAX98095_RATES SNDRV_PCM_RATE_8000_96000
+#define MAX98095_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops max98095_dai1_ops = {
+	.set_sysclk = max98095_dai_set_sysclk,
+	.set_fmt = max98095_dai1_set_fmt,
+	.hw_params = max98095_dai1_hw_params,
+};
+
+static const struct snd_soc_dai_ops max98095_dai2_ops = {
+	.set_sysclk = max98095_dai_set_sysclk,
+	.set_fmt = max98095_dai2_set_fmt,
+	.hw_params = max98095_dai2_hw_params,
+};
+
+static const struct snd_soc_dai_ops max98095_dai3_ops = {
+	.set_sysclk = max98095_dai_set_sysclk,
+	.set_fmt = max98095_dai3_set_fmt,
+	.hw_params = max98095_dai3_hw_params,
+};
+
+static struct snd_soc_dai_driver max98095_dai[] = {
+{
+	.name = "HiFi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = MAX98095_RATES,
+		.formats = MAX98095_FORMATS,
+	},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = MAX98095_RATES,
+		.formats = MAX98095_FORMATS,
+	},
+	 .ops = &max98095_dai1_ops,
+},
+{
+	.name = "Aux",
+	.playback = {
+		.stream_name = "Aux Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = MAX98095_RATES,
+		.formats = MAX98095_FORMATS,
+	},
+	.ops = &max98095_dai2_ops,
+},
+{
+	.name = "Voice",
+	.playback = {
+		.stream_name = "Voice Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = MAX98095_RATES,
+		.formats = MAX98095_FORMATS,
+	},
+	.ops = &max98095_dai3_ops,
+}
+
+};
+
+static int max98095_get_eq_channel(const char *name)
+{
+	if (strcmp(name, "EQ1 Mode") == 0)
+		return 0;
+	if (strcmp(name, "EQ2 Mode") == 0)
+		return 1;
+	return -EINVAL;
+}
+
+static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct max98095_pdata *pdata = max98095->pdata;
+	int channel = max98095_get_eq_channel(kcontrol->id.name);
+	struct max98095_cdata *cdata;
+	unsigned int sel = ucontrol->value.enumerated.item[0];
+	struct max98095_eq_cfg *coef_set;
+	int fs, best, best_val, i;
+	int regmask, regsave;
+
+	if (WARN_ON(channel > 1))
+		return -EINVAL;
+
+	if (!pdata || !max98095->eq_textcnt)
+		return 0;
+
+	if (sel >= pdata->eq_cfgcnt)
+		return -EINVAL;
+
+	cdata = &max98095->dai[channel];
+	cdata->eq_sel = sel;
+	fs = cdata->rate;
+
+	/* Find the selected configuration with nearest sample rate */
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < pdata->eq_cfgcnt; i++) {
+		if (strcmp(pdata->eq_cfg[i].name, max98095->eq_texts[sel]) == 0 &&
+			abs(pdata->eq_cfg[i].rate - fs) < best_val) {
+			best = i;
+			best_val = abs(pdata->eq_cfg[i].rate - fs);
+		}
+	}
+
+	dev_dbg(component->dev, "Selected %s/%dHz for %dHz sample rate\n",
+		pdata->eq_cfg[best].name,
+		pdata->eq_cfg[best].rate, fs);
+
+	coef_set = &pdata->eq_cfg[best];
+
+	regmask = (channel == 0) ? M98095_EQ1EN : M98095_EQ2EN;
+
+	/* Disable filter while configuring, and save current on/off state */
+	regsave = snd_soc_component_read32(component, M98095_088_CFG_LEVEL);
+	snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, 0);
+
+	mutex_lock(&max98095->lock);
+	snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
+	m98095_eq_band(component, channel, 0, coef_set->band1);
+	m98095_eq_band(component, channel, 1, coef_set->band2);
+	m98095_eq_band(component, channel, 2, coef_set->band3);
+	m98095_eq_band(component, channel, 3, coef_set->band4);
+	m98095_eq_band(component, channel, 4, coef_set->band5);
+	snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, 0);
+	mutex_unlock(&max98095->lock);
+
+	/* Restore the original on/off state */
+	snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, regsave);
+	return 0;
+}
+
+static int max98095_get_eq_enum(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	int channel = max98095_get_eq_channel(kcontrol->id.name);
+	struct max98095_cdata *cdata;
+
+	cdata = &max98095->dai[channel];
+	ucontrol->value.enumerated.item[0] = cdata->eq_sel;
+
+	return 0;
+}
+
+static void max98095_handle_eq_pdata(struct snd_soc_component *component)
+{
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct max98095_pdata *pdata = max98095->pdata;
+	struct max98095_eq_cfg *cfg;
+	unsigned int cfgcnt;
+	int i, j;
+	const char **t;
+	int ret;
+
+	struct snd_kcontrol_new controls[] = {
+		SOC_ENUM_EXT("EQ1 Mode",
+			max98095->eq_enum,
+			max98095_get_eq_enum,
+			max98095_put_eq_enum),
+		SOC_ENUM_EXT("EQ2 Mode",
+			max98095->eq_enum,
+			max98095_get_eq_enum,
+			max98095_put_eq_enum),
+	};
+
+	cfg = pdata->eq_cfg;
+	cfgcnt = pdata->eq_cfgcnt;
+
+	/* Setup an array of texts for the equalizer enum.
+	 * This is based on Mark Brown's equalizer driver code.
+	 */
+	max98095->eq_textcnt = 0;
+	max98095->eq_texts = NULL;
+	for (i = 0; i < cfgcnt; i++) {
+		for (j = 0; j < max98095->eq_textcnt; j++) {
+			if (strcmp(cfg[i].name, max98095->eq_texts[j]) == 0)
+				break;
+		}
+
+		if (j != max98095->eq_textcnt)
+			continue;
+
+		/* Expand the array */
+		t = krealloc(max98095->eq_texts,
+			     sizeof(char *) * (max98095->eq_textcnt + 1),
+			     GFP_KERNEL);
+		if (t == NULL)
+			continue;
+
+		/* Store the new entry */
+		t[max98095->eq_textcnt] = cfg[i].name;
+		max98095->eq_textcnt++;
+		max98095->eq_texts = t;
+	}
+
+	/* Now point the soc_enum to .texts array items */
+	max98095->eq_enum.texts = max98095->eq_texts;
+	max98095->eq_enum.items = max98095->eq_textcnt;
+
+	ret = snd_soc_add_component_controls(component, controls, ARRAY_SIZE(controls));
+	if (ret != 0)
+		dev_err(component->dev, "Failed to add EQ control: %d\n", ret);
+}
+
+static const char *bq_mode_name[] = {"Biquad1 Mode", "Biquad2 Mode"};
+
+static int max98095_get_bq_channel(struct snd_soc_component *component,
+				   const char *name)
+{
+	int ret;
+
+	ret = match_string(bq_mode_name, ARRAY_SIZE(bq_mode_name), name);
+	if (ret < 0)
+		dev_err(component->dev, "Bad biquad channel name '%s'\n", name);
+	return ret;
+}
+
+static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct max98095_pdata *pdata = max98095->pdata;
+	int channel = max98095_get_bq_channel(component, kcontrol->id.name);
+	struct max98095_cdata *cdata;
+	unsigned int sel = ucontrol->value.enumerated.item[0];
+	struct max98095_biquad_cfg *coef_set;
+	int fs, best, best_val, i;
+	int regmask, regsave;
+
+	if (channel < 0)
+		return channel;
+
+	if (!pdata || !max98095->bq_textcnt)
+		return 0;
+
+	if (sel >= pdata->bq_cfgcnt)
+		return -EINVAL;
+
+	cdata = &max98095->dai[channel];
+	cdata->bq_sel = sel;
+	fs = cdata->rate;
+
+	/* Find the selected configuration with nearest sample rate */
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < pdata->bq_cfgcnt; i++) {
+		if (strcmp(pdata->bq_cfg[i].name, max98095->bq_texts[sel]) == 0 &&
+			abs(pdata->bq_cfg[i].rate - fs) < best_val) {
+			best = i;
+			best_val = abs(pdata->bq_cfg[i].rate - fs);
+		}
+	}
+
+	dev_dbg(component->dev, "Selected %s/%dHz for %dHz sample rate\n",
+		pdata->bq_cfg[best].name,
+		pdata->bq_cfg[best].rate, fs);
+
+	coef_set = &pdata->bq_cfg[best];
+
+	regmask = (channel == 0) ? M98095_BQ1EN : M98095_BQ2EN;
+
+	/* Disable filter while configuring, and save current on/off state */
+	regsave = snd_soc_component_read32(component, M98095_088_CFG_LEVEL);
+	snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, 0);
+
+	mutex_lock(&max98095->lock);
+	snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
+	m98095_biquad_band(component, channel, 0, coef_set->band1);
+	m98095_biquad_band(component, channel, 1, coef_set->band2);
+	snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, 0);
+	mutex_unlock(&max98095->lock);
+
+	/* Restore the original on/off state */
+	snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, regsave);
+	return 0;
+}
+
+static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	int channel = max98095_get_bq_channel(component, kcontrol->id.name);
+	struct max98095_cdata *cdata;
+
+	if (channel < 0)
+		return channel;
+
+	cdata = &max98095->dai[channel];
+	ucontrol->value.enumerated.item[0] = cdata->bq_sel;
+
+	return 0;
+}
+
+static void max98095_handle_bq_pdata(struct snd_soc_component *component)
+{
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct max98095_pdata *pdata = max98095->pdata;
+	struct max98095_biquad_cfg *cfg;
+	unsigned int cfgcnt;
+	int i, j;
+	const char **t;
+	int ret;
+
+	struct snd_kcontrol_new controls[] = {
+		SOC_ENUM_EXT((char *)bq_mode_name[0],
+			max98095->bq_enum,
+			max98095_get_bq_enum,
+			max98095_put_bq_enum),
+		SOC_ENUM_EXT((char *)bq_mode_name[1],
+			max98095->bq_enum,
+			max98095_get_bq_enum,
+			max98095_put_bq_enum),
+	};
+	BUILD_BUG_ON(ARRAY_SIZE(controls) != ARRAY_SIZE(bq_mode_name));
+
+	cfg = pdata->bq_cfg;
+	cfgcnt = pdata->bq_cfgcnt;
+
+	/* Setup an array of texts for the biquad enum.
+	 * This is based on Mark Brown's equalizer driver code.
+	 */
+	max98095->bq_textcnt = 0;
+	max98095->bq_texts = NULL;
+	for (i = 0; i < cfgcnt; i++) {
+		for (j = 0; j < max98095->bq_textcnt; j++) {
+			if (strcmp(cfg[i].name, max98095->bq_texts[j]) == 0)
+				break;
+		}
+
+		if (j != max98095->bq_textcnt)
+			continue;
+
+		/* Expand the array */
+		t = krealloc(max98095->bq_texts,
+			     sizeof(char *) * (max98095->bq_textcnt + 1),
+			     GFP_KERNEL);
+		if (t == NULL)
+			continue;
+
+		/* Store the new entry */
+		t[max98095->bq_textcnt] = cfg[i].name;
+		max98095->bq_textcnt++;
+		max98095->bq_texts = t;
+	}
+
+	/* Now point the soc_enum to .texts array items */
+	max98095->bq_enum.texts = max98095->bq_texts;
+	max98095->bq_enum.items = max98095->bq_textcnt;
+
+	ret = snd_soc_add_component_controls(component, controls, ARRAY_SIZE(controls));
+	if (ret != 0)
+		dev_err(component->dev, "Failed to add Biquad control: %d\n", ret);
+}
+
+static void max98095_handle_pdata(struct snd_soc_component *component)
+{
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct max98095_pdata *pdata = max98095->pdata;
+	u8 regval = 0;
+
+	if (!pdata) {
+		dev_dbg(component->dev, "No platform data\n");
+		return;
+	}
+
+	/* Configure mic for analog/digital mic mode */
+	if (pdata->digmic_left_mode)
+		regval |= M98095_DIGMIC_L;
+
+	if (pdata->digmic_right_mode)
+		regval |= M98095_DIGMIC_R;
+
+	snd_soc_component_write(component, M98095_087_CFG_MIC, regval);
+
+	/* Configure equalizers */
+	if (pdata->eq_cfgcnt)
+		max98095_handle_eq_pdata(component);
+
+	/* Configure bi-quad filters */
+	if (pdata->bq_cfgcnt)
+		max98095_handle_bq_pdata(component);
+}
+
+static irqreturn_t max98095_report_jack(int irq, void *data)
+{
+	struct snd_soc_component *component = data;
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	unsigned int value;
+	int hp_report = 0;
+	int mic_report = 0;
+
+	/* Read the Jack Status Register */
+	value = snd_soc_component_read32(component, M98095_007_JACK_AUTO_STS);
+
+	/* If ddone is not set, then detection isn't finished yet */
+	if ((value & M98095_DDONE) == 0)
+		return IRQ_NONE;
+
+	/* if hp, check its bit, and if set, clear it */
+	if ((value & M98095_HP_IN || value & M98095_LO_IN) &&
+		max98095->headphone_jack)
+		hp_report |= SND_JACK_HEADPHONE;
+
+	/* if mic, check its bit, and if set, clear it */
+	if ((value & M98095_MIC_IN) && max98095->mic_jack)
+		mic_report |= SND_JACK_MICROPHONE;
+
+	if (max98095->headphone_jack == max98095->mic_jack) {
+		snd_soc_jack_report(max98095->headphone_jack,
+					hp_report | mic_report,
+					SND_JACK_HEADSET);
+	} else {
+		if (max98095->headphone_jack)
+			snd_soc_jack_report(max98095->headphone_jack,
+					hp_report, SND_JACK_HEADPHONE);
+		if (max98095->mic_jack)
+			snd_soc_jack_report(max98095->mic_jack,
+					mic_report, SND_JACK_MICROPHONE);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int max98095_jack_detect_enable(struct snd_soc_component *component)
+{
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+	int detect_enable = M98095_JDEN;
+	unsigned int slew = M98095_DEFAULT_SLEW_DELAY;
+
+	if (max98095->pdata->jack_detect_pin5en)
+		detect_enable |= M98095_PIN5EN;
+
+	if (max98095->pdata->jack_detect_delay)
+		slew = max98095->pdata->jack_detect_delay;
+
+	ret = snd_soc_component_write(component, M98095_08E_JACK_DC_SLEW, slew);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to cfg auto detect %d\n", ret);
+		return ret;
+	}
+
+	/* configure auto detection to be enabled */
+	ret = snd_soc_component_write(component, M98095_089_JACK_DET_AUTO, detect_enable);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to cfg auto detect %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int max98095_jack_detect_disable(struct snd_soc_component *component)
+{
+	int ret = 0;
+
+	/* configure auto detection to be disabled */
+	ret = snd_soc_component_write(component, M98095_089_JACK_DET_AUTO, 0x0);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to cfg auto detect %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+int max98095_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack)
+{
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct i2c_client *client = to_i2c_client(component->dev);
+	int ret = 0;
+
+	max98095->headphone_jack = hp_jack;
+	max98095->mic_jack = mic_jack;
+
+	/* only progress if we have at least 1 jack pointer */
+	if (!hp_jack && !mic_jack)
+		return -EINVAL;
+
+	max98095_jack_detect_enable(component);
+
+	/* enable interrupts for headphone jack detection */
+	ret = snd_soc_component_update_bits(component, M98095_013_JACK_INT_EN,
+		M98095_IDDONE, M98095_IDDONE);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to cfg jack irqs %d\n", ret);
+		return ret;
+	}
+
+	max98095_report_jack(client->irq, component);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(max98095_jack_detect);
+
+#ifdef CONFIG_PM
+static int max98095_suspend(struct snd_soc_component *component)
+{
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+
+	if (max98095->headphone_jack || max98095->mic_jack)
+		max98095_jack_detect_disable(component);
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int max98095_resume(struct snd_soc_component *component)
+{
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct i2c_client *client = to_i2c_client(component->dev);
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	if (max98095->headphone_jack || max98095->mic_jack) {
+		max98095_jack_detect_enable(component);
+		max98095_report_jack(client->irq, component);
+	}
+
+	return 0;
+}
+#else
+#define max98095_suspend NULL
+#define max98095_resume NULL
+#endif
+
+static int max98095_reset(struct snd_soc_component *component)
+{
+	int i, ret;
+
+	/* Gracefully reset the DSP core and the codec hardware
+	 * in a proper sequence */
+	ret = snd_soc_component_write(component, M98095_00F_HOST_CFG, 0);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to reset DSP: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_write(component, M98095_097_PWR_SYS, 0);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to reset component: %d\n", ret);
+		return ret;
+	}
+
+	/* Reset to hardware default for registers, as there is not
+	 * a soft reset hardware control register */
+	for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) {
+		ret = snd_soc_component_write(component, i, snd_soc_component_read32(component, i));
+		if (ret < 0) {
+			dev_err(component->dev, "Failed to reset: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int max98095_probe(struct snd_soc_component *component)
+{
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct max98095_cdata *cdata;
+	struct i2c_client *client;
+	int ret = 0;
+
+	max98095->mclk = devm_clk_get(component->dev, "mclk");
+	if (PTR_ERR(max98095->mclk) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	/* reset the codec, the DSP core, and disable all interrupts */
+	max98095_reset(component);
+
+	client = to_i2c_client(component->dev);
+
+	/* initialize private data */
+
+	max98095->sysclk = (unsigned)-1;
+	max98095->eq_textcnt = 0;
+	max98095->bq_textcnt = 0;
+
+	cdata = &max98095->dai[0];
+	cdata->rate = (unsigned)-1;
+	cdata->fmt  = (unsigned)-1;
+	cdata->eq_sel = 0;
+	cdata->bq_sel = 0;
+
+	cdata = &max98095->dai[1];
+	cdata->rate = (unsigned)-1;
+	cdata->fmt  = (unsigned)-1;
+	cdata->eq_sel = 0;
+	cdata->bq_sel = 0;
+
+	cdata = &max98095->dai[2];
+	cdata->rate = (unsigned)-1;
+	cdata->fmt  = (unsigned)-1;
+	cdata->eq_sel = 0;
+	cdata->bq_sel = 0;
+
+	max98095->lin_state = 0;
+	max98095->mic1pre = 0;
+	max98095->mic2pre = 0;
+
+	if (client->irq) {
+		/* register an audio interrupt */
+		ret = request_threaded_irq(client->irq, NULL,
+			max98095_report_jack,
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+			IRQF_ONESHOT, "max98095", component);
+		if (ret) {
+			dev_err(component->dev, "Failed to request IRQ: %d\n", ret);
+			goto err_access;
+		}
+	}
+
+	ret = snd_soc_component_read32(component, M98095_0FF_REV_ID);
+	if (ret < 0) {
+		dev_err(component->dev, "Failure reading hardware revision: %d\n",
+			ret);
+		goto err_irq;
+	}
+	dev_info(component->dev, "Hardware revision: %c\n", ret - 0x40 + 'A');
+
+	snd_soc_component_write(component, M98095_097_PWR_SYS, M98095_PWRSV);
+
+	snd_soc_component_write(component, M98095_048_MIX_DAC_LR,
+		M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR);
+
+	snd_soc_component_write(component, M98095_049_MIX_DAC_M,
+		M98095_DAI2M_TO_DACM|M98095_DAI3M_TO_DACM);
+
+	snd_soc_component_write(component, M98095_092_PWR_EN_OUT, M98095_SPK_SPREADSPECTRUM);
+	snd_soc_component_write(component, M98095_045_CFG_DSP, M98095_DSPNORMAL);
+	snd_soc_component_write(component, M98095_04E_CFG_HP, M98095_HPNORMAL);
+
+	snd_soc_component_write(component, M98095_02C_DAI1_IOCFG,
+		M98095_S1NORMAL|M98095_SDATA);
+
+	snd_soc_component_write(component, M98095_036_DAI2_IOCFG,
+		M98095_S2NORMAL|M98095_SDATA);
+
+	snd_soc_component_write(component, M98095_040_DAI3_IOCFG,
+		M98095_S3NORMAL|M98095_SDATA);
+
+	max98095_handle_pdata(component);
+
+	/* take the codec out of the shut down */
+	snd_soc_component_update_bits(component, M98095_097_PWR_SYS, M98095_SHDNRUN,
+		M98095_SHDNRUN);
+
+	return 0;
+
+err_irq:
+	if (client->irq)
+		free_irq(client->irq, component);
+err_access:
+	return ret;
+}
+
+static void max98095_remove(struct snd_soc_component *component)
+{
+	struct max98095_priv *max98095 = snd_soc_component_get_drvdata(component);
+	struct i2c_client *client = to_i2c_client(component->dev);
+
+	if (max98095->headphone_jack || max98095->mic_jack)
+		max98095_jack_detect_disable(component);
+
+	if (client->irq)
+		free_irq(client->irq, component);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_max98095 = {
+	.probe			= max98095_probe,
+	.remove			= max98095_remove,
+	.suspend		= max98095_suspend,
+	.resume			= max98095_resume,
+	.set_bias_level		= max98095_set_bias_level,
+	.controls		= max98095_snd_controls,
+	.num_controls		= ARRAY_SIZE(max98095_snd_controls),
+	.dapm_widgets		= max98095_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98095_dapm_widgets),
+	.dapm_routes		= max98095_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max98095_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int max98095_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct max98095_priv *max98095;
+	int ret;
+
+	max98095 = devm_kzalloc(&i2c->dev, sizeof(struct max98095_priv),
+				GFP_KERNEL);
+	if (max98095 == NULL)
+		return -ENOMEM;
+
+	mutex_init(&max98095->lock);
+
+	max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap);
+	if (IS_ERR(max98095->regmap)) {
+		ret = PTR_ERR(max98095->regmap);
+		dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	max98095->devtype = id->driver_data;
+	i2c_set_clientdata(i2c, max98095);
+	max98095->pdata = i2c->dev.platform_data;
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_max98095,
+				     max98095_dai, ARRAY_SIZE(max98095_dai));
+	return ret;
+}
+
+static const struct i2c_device_id max98095_i2c_id[] = {
+	{ "max98095", MAX98095 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max98095_i2c_id);
+
+static const struct of_device_id max98095_of_match[] = {
+	{ .compatible = "maxim,max98095", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max98095_of_match);
+
+static struct i2c_driver max98095_i2c_driver = {
+	.driver = {
+		.name = "max98095",
+		.of_match_table = of_match_ptr(max98095_of_match),
+	},
+	.probe  = max98095_i2c_probe,
+	.id_table = max98095_i2c_id,
+};
+
+module_i2c_driver(max98095_i2c_driver);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98095 driver");
+MODULE_AUTHOR("Peter Hsiang");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98095.h b/sound/soc/codecs/max98095.h
new file mode 100644
index 0000000..67886ca
--- /dev/null
+++ b/sound/soc/codecs/max98095.h
@@ -0,0 +1,321 @@
+/*
+ * max98095.h -- MAX98095 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX98095_H
+#define _MAX98095_H
+
+/*
+ * MAX98095 Registers Definition
+ */
+
+#define M98095_000_HOST_DATA                0x00
+#define M98095_001_HOST_INT_STS             0x01
+#define M98095_002_HOST_RSP_STS             0x02
+#define M98095_003_HOST_CMD_STS             0x03
+#define M98095_004_CODEC_STS                0x04
+#define M98095_005_DAI1_ALC_STS             0x05
+#define M98095_006_DAI2_ALC_STS             0x06
+#define M98095_007_JACK_AUTO_STS            0x07
+#define M98095_008_JACK_MANUAL_STS          0x08
+#define M98095_009_JACK_VBAT_STS            0x09
+#define M98095_00A_ACC_ADC_STS              0x0A
+#define M98095_00B_MIC_NG_AGC_STS           0x0B
+#define M98095_00C_SPK_L_VOLT_STS           0x0C
+#define M98095_00D_SPK_R_VOLT_STS           0x0D
+#define M98095_00E_TEMP_SENSOR_STS          0x0E
+#define M98095_00F_HOST_CFG                 0x0F
+#define M98095_010_HOST_INT_CFG             0x10
+#define M98095_011_HOST_INT_EN              0x11
+#define M98095_012_CODEC_INT_EN             0x12
+#define M98095_013_JACK_INT_EN              0x13
+#define M98095_014_JACK_INT_EN              0x14
+#define M98095_015_DEC                      0x15
+#define M98095_016_RESERVED                 0x16
+#define M98095_017_RESERVED                 0x17
+#define M98095_018_KEYCODE3                 0x18
+#define M98095_019_KEYCODE2                 0x19
+#define M98095_01A_KEYCODE1                 0x1A
+#define M98095_01B_KEYCODE0                 0x1B
+#define M98095_01C_OEMCODE1                 0x1C
+#define M98095_01D_OEMCODE0                 0x1D
+#define M98095_01E_XCFG1                    0x1E
+#define M98095_01F_XCFG2                    0x1F
+#define M98095_020_XCFG3                    0x20
+#define M98095_021_XCFG4                    0x21
+#define M98095_022_XCFG5                    0x22
+#define M98095_023_XCFG6                    0x23
+#define M98095_024_XGPIO                    0x24
+#define M98095_025_XCLKCFG                  0x25
+#define M98095_026_SYS_CLK                  0x26
+#define M98095_027_DAI1_CLKMODE             0x27
+#define M98095_028_DAI1_CLKCFG_HI           0x28
+#define M98095_029_DAI1_CLKCFG_LO           0x29
+#define M98095_02A_DAI1_FORMAT              0x2A
+#define M98095_02B_DAI1_CLOCK               0x2B
+#define M98095_02C_DAI1_IOCFG               0x2C
+#define M98095_02D_DAI1_TDM                 0x2D
+#define M98095_02E_DAI1_FILTERS             0x2E
+#define M98095_02F_DAI1_LVL1                0x2F
+#define M98095_030_DAI1_LVL2                0x30
+#define M98095_031_DAI2_CLKMODE             0x31
+#define M98095_032_DAI2_CLKCFG_HI           0x32
+#define M98095_033_DAI2_CLKCFG_LO           0x33
+#define M98095_034_DAI2_FORMAT              0x34
+#define M98095_035_DAI2_CLOCK               0x35
+#define M98095_036_DAI2_IOCFG               0x36
+#define M98095_037_DAI2_TDM                 0x37
+#define M98095_038_DAI2_FILTERS             0x38
+#define M98095_039_DAI2_LVL1                0x39
+#define M98095_03A_DAI2_LVL2                0x3A
+#define M98095_03B_DAI3_CLKMODE             0x3B
+#define M98095_03C_DAI3_CLKCFG_HI           0x3C
+#define M98095_03D_DAI3_CLKCFG_LO           0x3D
+#define M98095_03E_DAI3_FORMAT              0x3E
+#define M98095_03F_DAI3_CLOCK               0x3F
+#define M98095_040_DAI3_IOCFG               0x40
+#define M98095_041_DAI3_TDM                 0x41
+#define M98095_042_DAI3_FILTERS             0x42
+#define M98095_043_DAI3_LVL1                0x43
+#define M98095_044_DAI3_LVL2                0x44
+#define M98095_045_CFG_DSP                  0x45
+#define M98095_046_DAC_CTRL1                0x46
+#define M98095_047_DAC_CTRL2                0x47
+#define M98095_048_MIX_DAC_LR               0x48
+#define M98095_049_MIX_DAC_M                0x49
+#define M98095_04A_MIX_ADC_LEFT             0x4A
+#define M98095_04B_MIX_ADC_RIGHT            0x4B
+#define M98095_04C_MIX_HP_LEFT              0x4C
+#define M98095_04D_MIX_HP_RIGHT             0x4D
+#define M98095_04E_CFG_HP                   0x4E
+#define M98095_04F_MIX_RCV                  0x4F
+#define M98095_050_MIX_SPK_LEFT             0x50
+#define M98095_051_MIX_SPK_RIGHT            0x51
+#define M98095_052_MIX_SPK_CFG              0x52
+#define M98095_053_MIX_LINEOUT1             0x53
+#define M98095_054_MIX_LINEOUT2             0x54
+#define M98095_055_MIX_LINEOUT_CFG          0x55
+#define M98095_056_LVL_SIDETONE_DAI12       0x56
+#define M98095_057_LVL_SIDETONE_DAI3        0x57
+#define M98095_058_LVL_DAI1_PLAY            0x58
+#define M98095_059_LVL_DAI1_EQ              0x59
+#define M98095_05A_LVL_DAI2_PLAY            0x5A
+#define M98095_05B_LVL_DAI2_EQ              0x5B
+#define M98095_05C_LVL_DAI3_PLAY            0x5C
+#define M98095_05D_LVL_ADC_L                0x5D
+#define M98095_05E_LVL_ADC_R                0x5E
+#define M98095_05F_LVL_MIC1                 0x5F
+#define M98095_060_LVL_MIC2                 0x60
+#define M98095_061_LVL_LINEIN               0x61
+#define M98095_062_LVL_LINEOUT1             0x62
+#define M98095_063_LVL_LINEOUT2             0x63
+#define M98095_064_LVL_HP_L                 0x64
+#define M98095_065_LVL_HP_R                 0x65
+#define M98095_066_LVL_RCV                  0x66
+#define M98095_067_LVL_SPK_L                0x67
+#define M98095_068_LVL_SPK_R                0x68
+#define M98095_069_MICAGC_CFG               0x69
+#define M98095_06A_MICAGC_THRESH            0x6A
+#define M98095_06B_SPK_NOISEGATE            0x6B
+#define M98095_06C_DAI1_ALC1_TIME           0x6C
+#define M98095_06D_DAI1_ALC1_COMP           0x6D
+#define M98095_06E_DAI1_ALC1_EXPN           0x6E
+#define M98095_06F_DAI1_ALC1_GAIN           0x6F
+#define M98095_070_DAI1_ALC2_TIME           0x70
+#define M98095_071_DAI1_ALC2_COMP           0x71
+#define M98095_072_DAI1_ALC2_EXPN           0x72
+#define M98095_073_DAI1_ALC2_GAIN           0x73
+#define M98095_074_DAI1_ALC3_TIME           0x74
+#define M98095_075_DAI1_ALC3_COMP           0x75
+#define M98095_076_DAI1_ALC3_EXPN           0x76
+#define M98095_077_DAI1_ALC3_GAIN           0x77
+#define M98095_078_DAI2_ALC1_TIME           0x78
+#define M98095_079_DAI2_ALC1_COMP           0x79
+#define M98095_07A_DAI2_ALC1_EXPN           0x7A
+#define M98095_07B_DAI2_ALC1_GAIN           0x7B
+#define M98095_07C_DAI2_ALC2_TIME           0x7C
+#define M98095_07D_DAI2_ALC2_COMP           0x7D
+#define M98095_07E_DAI2_ALC2_EXPN           0x7E
+#define M98095_07F_DAI2_ALC2_GAIN           0x7F
+#define M98095_080_DAI2_ALC3_TIME           0x80
+#define M98095_081_DAI2_ALC3_COMP           0x81
+#define M98095_082_DAI2_ALC3_EXPN           0x82
+#define M98095_083_DAI2_ALC3_GAIN           0x83
+#define M98095_084_HP_NOISE_GATE            0x84
+#define M98095_085_AUX_ADC                  0x85
+#define M98095_086_CFG_LINE                 0x86
+#define M98095_087_CFG_MIC                  0x87
+#define M98095_088_CFG_LEVEL                0x88
+#define M98095_089_JACK_DET_AUTO            0x89
+#define M98095_08A_JACK_DET_MANUAL          0x8A
+#define M98095_08B_JACK_KEYSCAN_DBC         0x8B
+#define M98095_08C_JACK_KEYSCAN_DLY         0x8C
+#define M98095_08D_JACK_KEY_THRESH          0x8D
+#define M98095_08E_JACK_DC_SLEW             0x8E
+#define M98095_08F_JACK_TEST_CFG            0x8F
+#define M98095_090_PWR_EN_IN                0x90
+#define M98095_091_PWR_EN_OUT               0x91
+#define M98095_092_PWR_EN_OUT               0x92
+#define M98095_093_BIAS_CTRL                0x93
+#define M98095_094_PWR_DAC_21               0x94
+#define M98095_095_PWR_DAC_03               0x95
+#define M98095_096_PWR_DAC_CK               0x96
+#define M98095_097_PWR_SYS                  0x97
+
+#define M98095_0FF_REV_ID                   0xFF
+
+#define M98095_REG_CNT                      (0xFF+1)
+#define M98095_REG_MAX_CACHED               0X97
+
+/* MAX98095 Registers Bit Fields */
+
+/* M98095_007_JACK_AUTO_STS */
+	#define M98095_MIC_IN			(1<<3)
+	#define M98095_LO_IN			(1<<5)
+	#define M98095_HP_IN			(1<<6)
+	#define M98095_DDONE			(1<<7)
+
+/* M98095_00F_HOST_CFG */
+	#define M98095_SEG                      (1<<0)
+	#define M98095_XTEN                     (1<<1)
+	#define M98095_MDLLEN                   (1<<2)
+
+/* M98095_013_JACK_INT_EN */
+	#define M98095_IMIC_IN			(1<<3)
+	#define M98095_ILO_IN			(1<<5)
+	#define M98095_IHP_IN			(1<<6)
+	#define M98095_IDDONE			(1<<7)
+
+/* M98095_027_DAI1_CLKMODE, M98095_031_DAI2_CLKMODE, M98095_03B_DAI3_CLKMODE */
+	#define M98095_CLKMODE_MASK             0xFF
+
+/* M98095_02A_DAI1_FORMAT, M98095_034_DAI2_FORMAT, M98095_03E_DAI3_FORMAT */
+	#define M98095_DAI_MAS                  (1<<7)
+	#define M98095_DAI_WCI                  (1<<6)
+	#define M98095_DAI_BCI                  (1<<5)
+	#define M98095_DAI_DLY                  (1<<4)
+	#define M98095_DAI_TDM                  (1<<2)
+	#define M98095_DAI_FSW                  (1<<1)
+	#define M98095_DAI_WS                   (1<<0)
+
+/* M98095_02B_DAI1_CLOCK, M98095_035_DAI2_CLOCK, M98095_03F_DAI3_CLOCK */
+	#define M98095_DAI_BSEL64               (1<<0)
+	#define M98095_DAI_DOSR_DIV2            (0<<5)
+	#define M98095_DAI_DOSR_DIV4            (1<<5)
+
+/* M98095_02C_DAI1_IOCFG, M98095_036_DAI2_IOCFG, M98095_040_DAI3_IOCFG */
+	#define M98095_S1NORMAL                 (1<<6)
+	#define M98095_S2NORMAL                 (2<<6)
+	#define M98095_S3NORMAL                 (3<<6)
+	#define M98095_SDATA                    (3<<0)
+
+/* M98095_02E_DAI1_FILTERS, M98095_038_DAI2_FILTERS, M98095_042_DAI3_FILTERS */
+	#define M98095_DAI_DHF                  (1<<3)
+
+/* M98095_045_DSP_CFG */
+	#define M98095_DSPNORMAL                (5<<4)
+
+/* M98095_048_MIX_DAC_LR */
+	#define M98095_DAI1L_TO_DACR            (1<<7)
+	#define M98095_DAI1R_TO_DACR            (1<<6)
+	#define M98095_DAI2M_TO_DACR            (1<<5)
+	#define M98095_DAI1L_TO_DACL            (1<<3)
+	#define M98095_DAI1R_TO_DACL            (1<<2)
+	#define M98095_DAI2M_TO_DACL            (1<<1)
+	#define M98095_DAI3M_TO_DACL            (1<<0)
+
+/* M98095_049_MIX_DAC_M */
+	#define M98095_DAI1L_TO_DACM            (1<<3)
+	#define M98095_DAI1R_TO_DACM            (1<<2)
+	#define M98095_DAI2M_TO_DACM            (1<<1)
+	#define M98095_DAI3M_TO_DACM            (1<<0)
+
+/* M98095_04E_MIX_HP_CFG */
+	#define M98095_HPNORMAL                 (3<<4)
+
+/* M98095_05F_LVL_MIC1, M98095_060_LVL_MIC2 */
+	#define M98095_MICPRE_MASK              (3<<5)
+	#define M98095_MICPRE_SHIFT             5
+
+/* M98095_064_LVL_HP_L, M98095_065_LVL_HP_R */
+	#define M98095_HP_MUTE                  (1<<7)
+
+/* M98095_066_LVL_RCV */
+	#define M98095_REC_MUTE                 (1<<7)
+
+/* M98095_067_LVL_SPK_L, M98095_068_LVL_SPK_R */
+	#define M98095_SP_MUTE                  (1<<7)
+
+/* M98095_087_CFG_MIC */
+	#define M98095_MICSEL_MASK              (3<<0)
+	#define M98095_DIGMIC_L                 (1<<2)
+	#define M98095_DIGMIC_R                 (1<<3)
+	#define M98095_DIGMIC2L                 (1<<4)
+	#define M98095_DIGMIC2R                 (1<<5)
+
+/* M98095_088_CFG_LEVEL */
+	#define M98095_VSEN                     (1<<6)
+	#define M98095_ZDEN                     (1<<5)
+	#define M98095_BQ2EN                    (1<<3)
+	#define M98095_BQ1EN                    (1<<2)
+	#define M98095_EQ2EN                    (1<<1)
+	#define M98095_EQ1EN                    (1<<0)
+
+/* M98095_089_JACK_DET_AUTO */
+	#define M98095_PIN5EN			(1<<2)
+	#define M98095_JDEN			(1<<7)
+
+/* M98095_090_PWR_EN_IN */
+	#define M98095_INEN                     (1<<7)
+	#define M98095_MB2EN                    (1<<3)
+	#define M98095_MB1EN                    (1<<2)
+	#define M98095_MBEN                     (3<<2)
+	#define M98095_ADREN                    (1<<1)
+	#define M98095_ADLEN                    (1<<0)
+
+/* M98095_091_PWR_EN_OUT */
+	#define M98095_HPLEN                    (1<<7)
+	#define M98095_HPREN                    (1<<6)
+	#define M98095_SPLEN                    (1<<5)
+	#define M98095_SPREN                    (1<<4)
+	#define M98095_RECEN                    (1<<3)
+	#define M98095_DALEN                    (1<<1)
+	#define M98095_DAREN                    (1<<0)
+
+/* M98095_092_PWR_EN_OUT */
+	#define M98095_SPK_FIXEDSPECTRUM        (0<<4)
+	#define M98095_SPK_SPREADSPECTRUM       (1<<4)
+
+/* M98095_097_PWR_SYS */
+	#define M98095_SHDNRUN                  (1<<7)
+	#define M98095_PERFMODE                 (1<<3)
+	#define M98095_HPPLYBACK                (1<<2)
+	#define M98095_PWRSV8K                  (1<<1)
+	#define M98095_PWRSV                    (1<<0)
+
+#define M98095_COEFS_PER_BAND            5
+
+#define M98095_BYTE1(w) ((w >> 8) & 0xff)
+#define M98095_BYTE0(w) (w & 0xff)
+
+/* Equalizer filter coefficients */
+#define M98095_110_DAI1_EQ_BASE             0x10
+#define M98095_142_DAI2_EQ_BASE             0x42
+
+/* Biquad filter coefficients */
+#define M98095_174_DAI1_BQ_BASE             0x74
+#define M98095_17E_DAI2_BQ_BASE             0x7E
+
+/* Default Delay used in Slew Rate Calculation for Jack detection */
+#define M98095_DEFAULT_SLEW_DELAY		0x18
+
+extern int max98095_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack);
+
+#endif
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
new file mode 100644
index 0000000..d469576
--- /dev/null
+++ b/sound/soc/codecs/max98357a.c
@@ -0,0 +1,150 @@
+/* Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * max98357a.c -- MAX98357A ALSA SoC Codec driver
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+
+static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
+		int cmd, struct snd_soc_dai *dai)
+{
+	struct gpio_desc *sdmode = snd_soc_dai_get_drvdata(dai);
+
+	if (!sdmode)
+		return 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		gpiod_set_value(sdmode, 1);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		gpiod_set_value(sdmode, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget max98357a_dapm_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("Speaker"),
+};
+
+static const struct snd_soc_dapm_route max98357a_dapm_routes[] = {
+	{"Speaker", NULL, "HiFi Playback"},
+};
+
+static int max98357a_component_probe(struct snd_soc_component *component)
+{
+	struct gpio_desc *sdmode;
+
+	sdmode = devm_gpiod_get_optional(component->dev, "sdmode", GPIOD_OUT_LOW);
+	if (IS_ERR(sdmode))
+		return PTR_ERR(sdmode);
+
+	snd_soc_component_set_drvdata(component, sdmode);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver max98357a_component_driver = {
+	.probe			= max98357a_component_probe,
+	.dapm_widgets		= max98357a_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98357a_dapm_widgets),
+	.dapm_routes		= max98357a_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(max98357a_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct snd_soc_dai_ops max98357a_dai_ops = {
+	.trigger	= max98357a_daiops_trigger,
+};
+
+static struct snd_soc_dai_driver max98357a_dai_driver = {
+	.name = "HiFi",
+	.playback = {
+		.stream_name	= "HiFi Playback",
+		.formats	= SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S24 |
+					SNDRV_PCM_FMTBIT_S32,
+		.rates		= SNDRV_PCM_RATE_8000 |
+					SNDRV_PCM_RATE_16000 |
+					SNDRV_PCM_RATE_48000 |
+					SNDRV_PCM_RATE_96000,
+		.rate_min	= 8000,
+		.rate_max	= 96000,
+		.channels_min	= 1,
+		.channels_max	= 2,
+	},
+	.ops    = &max98357a_dai_ops,
+};
+
+static int max98357a_platform_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&max98357a_component_driver,
+			&max98357a_dai_driver, 1);
+}
+
+static int max98357a_platform_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id max98357a_device_id[] = {
+	{ .compatible = "maxim,max98357a" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, max98357a_device_id);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id max98357a_acpi_match[] = {
+	{ "MX98357A", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, max98357a_acpi_match);
+#endif
+
+static struct platform_driver max98357a_platform_driver = {
+	.driver = {
+		.name = "max98357a",
+		.of_match_table = of_match_ptr(max98357a_device_id),
+		.acpi_match_table = ACPI_PTR(max98357a_acpi_match),
+	},
+	.probe	= max98357a_platform_probe,
+	.remove = max98357a_platform_remove,
+};
+module_platform_driver(max98357a_platform_driver);
+
+MODULE_DESCRIPTION("Maxim MAX98357A Codec Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c
new file mode 100644
index 0000000..d4ba139
--- /dev/null
+++ b/sound/soc/codecs/max98371.c
@@ -0,0 +1,438 @@
+/*
+ * max98371.c -- ALSA SoC Stereo MAX98371 driver
+ *
+ * Copyright 2015-16 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "max98371.h"
+
+static const char *const monomix_text[] = {
+	"Left", "Right", "LeftRightDiv2",
+};
+
+static const char *const hpf_cutoff_txt[] = {
+	"Disable", "DC Block", "50Hz",
+	"100Hz", "200Hz", "400Hz", "800Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(max98371_monomix, MAX98371_MONOMIX_CFG, 0,
+		monomix_text);
+
+static SOC_ENUM_SINGLE_DECL(max98371_hpf_cutoff, MAX98371_HPF, 0,
+		hpf_cutoff_txt);
+
+static const DECLARE_TLV_DB_RANGE(max98371_dht_min_gain,
+	0, 1, TLV_DB_SCALE_ITEM(537, 66, 0),
+	2, 3, TLV_DB_SCALE_ITEM(677, 82, 0),
+	4, 5, TLV_DB_SCALE_ITEM(852, 104, 0),
+	6, 7, TLV_DB_SCALE_ITEM(1072, 131, 0),
+	8, 9, TLV_DB_SCALE_ITEM(1350, 165, 0),
+	10, 11, TLV_DB_SCALE_ITEM(1699, 101, 0),
+);
+
+static const DECLARE_TLV_DB_RANGE(max98371_dht_max_gain,
+	0, 1, TLV_DB_SCALE_ITEM(537, 66, 0),
+	2, 3, TLV_DB_SCALE_ITEM(677, 82, 0),
+	4, 5, TLV_DB_SCALE_ITEM(852, 104, 0),
+	6, 7, TLV_DB_SCALE_ITEM(1072, 131, 0),
+	8, 9, TLV_DB_SCALE_ITEM(1350, 165, 0),
+	10, 11, TLV_DB_SCALE_ITEM(1699, 208, 0),
+);
+
+static const DECLARE_TLV_DB_RANGE(max98371_dht_rot_gain,
+	0, 1, TLV_DB_SCALE_ITEM(-50, -50, 0),
+	2, 6, TLV_DB_SCALE_ITEM(-100, -100, 0),
+	7, 8, TLV_DB_SCALE_ITEM(-800, -200, 0),
+	9, 11, TLV_DB_SCALE_ITEM(-1200, -300, 0),
+	12, 13, TLV_DB_SCALE_ITEM(-2000, -200, 0),
+	14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0),
+);
+
+static const struct reg_default max98371_reg[] = {
+	{ 0x01, 0x00 },
+	{ 0x02, 0x00 },
+	{ 0x03, 0x00 },
+	{ 0x04, 0x00 },
+	{ 0x05, 0x00 },
+	{ 0x06, 0x00 },
+	{ 0x07, 0x00 },
+	{ 0x08, 0x00 },
+	{ 0x09, 0x00 },
+	{ 0x0A, 0x00 },
+	{ 0x10, 0x06 },
+	{ 0x11, 0x08 },
+	{ 0x14, 0x80 },
+	{ 0x15, 0x00 },
+	{ 0x16, 0x00 },
+	{ 0x18, 0x00 },
+	{ 0x19, 0x00 },
+	{ 0x1C, 0x00 },
+	{ 0x1D, 0x00 },
+	{ 0x1E, 0x00 },
+	{ 0x1F, 0x00 },
+	{ 0x20, 0x00 },
+	{ 0x21, 0x00 },
+	{ 0x22, 0x00 },
+	{ 0x23, 0x00 },
+	{ 0x24, 0x00 },
+	{ 0x25, 0x00 },
+	{ 0x26, 0x00 },
+	{ 0x27, 0x00 },
+	{ 0x28, 0x00 },
+	{ 0x29, 0x00 },
+	{ 0x2A, 0x00 },
+	{ 0x2B, 0x00 },
+	{ 0x2C, 0x00 },
+	{ 0x2D, 0x00 },
+	{ 0x2E, 0x0B },
+	{ 0x31, 0x00 },
+	{ 0x32, 0x18 },
+	{ 0x33, 0x00 },
+	{ 0x34, 0x00 },
+	{ 0x36, 0x00 },
+	{ 0x37, 0x00 },
+	{ 0x38, 0x00 },
+	{ 0x39, 0x00 },
+	{ 0x3A, 0x00 },
+	{ 0x3B, 0x00 },
+	{ 0x3C, 0x00 },
+	{ 0x3D, 0x00 },
+	{ 0x3E, 0x00 },
+	{ 0x3F, 0x00 },
+	{ 0x40, 0x00 },
+	{ 0x41, 0x00 },
+	{ 0x42, 0x00 },
+	{ 0x43, 0x00 },
+	{ 0x4A, 0x00 },
+	{ 0x4B, 0x00 },
+	{ 0x4C, 0x00 },
+	{ 0x4D, 0x00 },
+	{ 0x4E, 0x00 },
+	{ 0x50, 0x00 },
+	{ 0x51, 0x00 },
+	{ 0x55, 0x00 },
+	{ 0x58, 0x00 },
+	{ 0x59, 0x00 },
+	{ 0x5C, 0x00 },
+	{ 0xFF, 0x43 },
+};
+
+static bool max98371_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98371_IRQ_CLEAR1:
+	case MAX98371_IRQ_CLEAR2:
+	case MAX98371_IRQ_CLEAR3:
+	case MAX98371_VERSION:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max98371_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98371_SOFT_RESET:
+		return false;
+	default:
+		return true;
+	}
+};
+
+static const DECLARE_TLV_DB_RANGE(max98371_gain_tlv,
+	0, 7, TLV_DB_SCALE_ITEM(0, 50, 0),
+	8, 10, TLV_DB_SCALE_ITEM(400, 100, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(max98371_noload_gain_tlv,
+	0, 11, TLV_DB_SCALE_ITEM(950, 100, 0),
+);
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -6300, 50, 1);
+
+static const struct snd_kcontrol_new max98371_snd_controls[] = {
+	SOC_SINGLE_TLV("Speaker Volume", MAX98371_GAIN,
+			MAX98371_GAIN_SHIFT, (1<<MAX98371_GAIN_WIDTH)-1, 0,
+			max98371_gain_tlv),
+	SOC_SINGLE_TLV("Digital Volume", MAX98371_DIGITAL_GAIN, 0,
+			(1<<MAX98371_DIGITAL_GAIN_WIDTH)-1, 1, digital_tlv),
+	SOC_SINGLE_TLV("Speaker DHT Max Volume", MAX98371_GAIN,
+			0, (1<<MAX98371_DHT_MAX_WIDTH)-1, 0,
+			max98371_dht_max_gain),
+	SOC_SINGLE_TLV("Speaker DHT Min Volume", MAX98371_DHT_GAIN,
+			0, (1<<MAX98371_DHT_GAIN_WIDTH)-1, 0,
+			max98371_dht_min_gain),
+	SOC_SINGLE_TLV("Speaker DHT Rotation Volume", MAX98371_DHT_GAIN,
+			0, (1<<MAX98371_DHT_ROT_WIDTH)-1, 0,
+			max98371_dht_rot_gain),
+	SOC_SINGLE("DHT Attack Step", MAX98371_DHT, MAX98371_DHT_STEP, 3, 0),
+	SOC_SINGLE("DHT Attack Rate", MAX98371_DHT, 0, 7, 0),
+	SOC_ENUM("Monomix Select", max98371_monomix),
+	SOC_ENUM("HPF Cutoff", max98371_hpf_cutoff),
+};
+
+static int max98371_dai_set_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98371_priv *max98371 = snd_soc_component_get_drvdata(component);
+	unsigned int val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		dev_err(component->dev, "DAI clock mode unsupported");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		val |= 0;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val |= MAX98371_DAI_RIGHT;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val |= MAX98371_DAI_LEFT;
+		break;
+	default:
+		dev_err(component->dev, "DAI wrong mode unsupported");
+		return -EINVAL;
+	}
+	regmap_update_bits(max98371->regmap, MAX98371_FMT,
+			MAX98371_FMT_MODE_MASK, val);
+	return 0;
+}
+
+static int max98371_dai_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98371_priv *max98371 = snd_soc_component_get_drvdata(component);
+	int blr_clk_ratio, ch_size, channels = params_channels(params);
+	int rate = params_rate(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_16);
+		ch_size = 8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_16);
+		ch_size = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_32);
+		ch_size = 24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		regmap_update_bits(max98371->regmap, MAX98371_FMT,
+				MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_32);
+		ch_size = 32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* BCLK/LRCLK ratio calculation */
+	blr_clk_ratio = channels * ch_size;
+	switch (blr_clk_ratio) {
+	case 32:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_32);
+		break;
+	case 48:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_48);
+		break;
+	case 64:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_DAI_CLK,
+			MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_64);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (rate) {
+	case 32000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_32);
+		break;
+	case 44100:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_44);
+		break;
+	case 48000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_48);
+		break;
+	case 88200:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_88);
+		break;
+	case 96000:
+		regmap_update_bits(max98371->regmap,
+			MAX98371_SPK_SR,
+			MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_96);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* enabling both the RX channels*/
+	regmap_update_bits(max98371->regmap, MAX98371_MONOMIX_SRC,
+			MAX98371_MONOMIX_SRC_MASK, MONOMIX_RX_0_1);
+	regmap_update_bits(max98371->regmap, MAX98371_DAI_CHANNEL,
+			MAX98371_CHANNEL_MASK, MAX98371_CHANNEL_MASK);
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget max98371_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", NULL, MAX98371_SPK_ENABLE, 0, 0),
+	SND_SOC_DAPM_SUPPLY("Global Enable", MAX98371_GLOBAL_ENABLE,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+};
+
+static const struct snd_soc_dapm_route max98371_audio_map[] = {
+	{"DAC", NULL, "HiFi Playback"},
+	{"SPK_OUT", NULL, "DAC"},
+	{"SPK_OUT", NULL, "Global Enable"},
+};
+
+#define MAX98371_RATES SNDRV_PCM_RATE_8000_48000
+#define MAX98371_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
+		SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
+
+static const struct snd_soc_dai_ops max98371_dai_ops = {
+	.set_fmt = max98371_dai_set_fmt,
+	.hw_params = max98371_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver max98371_dai[] = {
+	{
+		.name = "max98371-aif1",
+		.playback = {
+			.stream_name = "HiFi Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = MAX98371_FORMATS,
+		},
+		.ops = &max98371_dai_ops,
+	}
+};
+
+static const struct snd_soc_component_driver max98371_component = {
+	.controls		= max98371_snd_controls,
+	.num_controls		= ARRAY_SIZE(max98371_snd_controls),
+	.dapm_routes		= max98371_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max98371_audio_map),
+	.dapm_widgets		= max98371_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98371_dapm_widgets),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config max98371_regmap = {
+	.reg_bits         = 8,
+	.val_bits         = 8,
+	.max_register     = MAX98371_VERSION,
+	.reg_defaults     = max98371_reg,
+	.num_reg_defaults = ARRAY_SIZE(max98371_reg),
+	.volatile_reg     = max98371_volatile_register,
+	.readable_reg     = max98371_readable_register,
+	.cache_type       = REGCACHE_RBTREE,
+};
+
+static int max98371_i2c_probe(struct i2c_client *i2c,
+		const struct i2c_device_id *id)
+{
+	struct max98371_priv *max98371;
+	int ret, reg;
+
+	max98371 = devm_kzalloc(&i2c->dev,
+			sizeof(*max98371), GFP_KERNEL);
+	if (!max98371)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, max98371);
+	max98371->regmap = devm_regmap_init_i2c(i2c, &max98371_regmap);
+	if (IS_ERR(max98371->regmap)) {
+		ret = PTR_ERR(max98371->regmap);
+		dev_err(&i2c->dev,
+				"Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(max98371->regmap, MAX98371_VERSION, &reg);
+	if (ret < 0) {
+		dev_info(&i2c->dev, "device error %d\n", ret);
+		return ret;
+	}
+	dev_info(&i2c->dev, "device version %x\n", reg);
+
+	ret = devm_snd_soc_register_component(&i2c->dev, &max98371_component,
+			max98371_dai, ARRAY_SIZE(max98371_dai));
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
+		return ret;
+	}
+	return ret;
+}
+
+static const struct i2c_device_id max98371_i2c_id[] = {
+	{ "max98371", 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, max98371_i2c_id);
+
+static const struct of_device_id max98371_of_match[] = {
+	{ .compatible = "maxim,max98371", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max98371_of_match);
+
+static struct i2c_driver max98371_i2c_driver = {
+	.driver = {
+		.name = "max98371",
+		.pm = NULL,
+		.of_match_table = of_match_ptr(max98371_of_match),
+	},
+	.probe  = max98371_i2c_probe,
+	.id_table = max98371_i2c_id,
+};
+
+module_i2c_driver(max98371_i2c_driver);
+
+MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC MAX98371 driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98371.h b/sound/soc/codecs/max98371.h
new file mode 100644
index 0000000..06e9ba7
--- /dev/null
+++ b/sound/soc/codecs/max98371.h
@@ -0,0 +1,66 @@
+/*
+ * max98371.h -- MAX98371 ALSA SoC Audio driver
+ *
+ * Copyright 2011-2012 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX98371_H
+#define _MAX98371_H
+
+#define MAX98371_IRQ_CLEAR1			0x01
+#define MAX98371_IRQ_CLEAR2			0x02
+#define MAX98371_IRQ_CLEAR3			0x03
+#define MAX98371_DAI_CLK			0x10
+#define MAX98371_DAI_BSEL_MASK			0xF
+#define MAX98371_DAI_BSEL_32			2
+#define MAX98371_DAI_BSEL_48			3
+#define MAX98371_DAI_BSEL_64			4
+#define MAX98371_SPK_SR				0x11
+#define MAX98371_SPK_SR_MASK			0xF
+#define MAX98371_SPK_SR_32			6
+#define MAX98371_SPK_SR_44			7
+#define MAX98371_SPK_SR_48			8
+#define MAX98371_SPK_SR_88			10
+#define MAX98371_SPK_SR_96			11
+#define MAX98371_DAI_CHANNEL			0x15
+#define MAX98371_CHANNEL_MASK			0x3
+#define MAX98371_MONOMIX_SRC			0x18
+#define MAX98371_MONOMIX_CFG			0x19
+#define MAX98371_HPF				0x1C
+#define MAX98371_MONOMIX_SRC_MASK		0xFF
+#define MONOMIX_RX_0_1				((0x1)<<(4))
+#define M98371_DAI_CHANNEL_I2S			0x3
+#define MAX98371_DIGITAL_GAIN			0x2D
+#define MAX98371_DIGITAL_GAIN_WIDTH		0x7
+#define MAX98371_GAIN				0x2E
+#define MAX98371_GAIN_SHIFT			0x4
+#define MAX98371_GAIN_WIDTH			0x4
+#define MAX98371_DHT_MAX_WIDTH			4
+#define MAX98371_FMT				0x14
+#define MAX98371_CHANSZ_WIDTH			6
+#define MAX98371_FMT_MASK		        ((0x3)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_FMT_MODE_MASK		        ((0x7)<<(3))
+#define MAX98371_DAI_LEFT		        ((0x1)<<(3))
+#define MAX98371_DAI_RIGHT		        ((0x2)<<(3))
+#define MAX98371_DAI_CHANSZ_16                  ((1)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DAI_CHANSZ_24                  ((2)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DAI_CHANSZ_32                  ((3)<<(MAX98371_CHANSZ_WIDTH))
+#define MAX98371_DHT  0x32
+#define MAX98371_DHT_STEP			0x3
+#define MAX98371_DHT_GAIN			0x31
+#define MAX98371_DHT_GAIN_WIDTH			0x4
+#define MAX98371_DHT_ROT_WIDTH			0x4
+#define MAX98371_SPK_ENABLE			0x4A
+#define MAX98371_GLOBAL_ENABLE			0x50
+#define MAX98371_SOFT_RESET			0x51
+#define MAX98371_VERSION			0xFF
+
+
+struct max98371_priv {
+	struct regmap *regmap;
+};
+#endif
diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c
new file mode 100644
index 0000000..1093f76
--- /dev/null
+++ b/sound/soc/codecs/max98373.c
@@ -0,0 +1,973 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017, Maxim Integrated
+
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/tlv.h>
+#include "max98373.h"
+
+static struct reg_default max98373_reg[] = {
+	{MAX98373_R2000_SW_RESET, 0x00},
+	{MAX98373_R2001_INT_RAW1, 0x00},
+	{MAX98373_R2002_INT_RAW2, 0x00},
+	{MAX98373_R2003_INT_RAW3, 0x00},
+	{MAX98373_R2004_INT_STATE1, 0x00},
+	{MAX98373_R2005_INT_STATE2, 0x00},
+	{MAX98373_R2006_INT_STATE3, 0x00},
+	{MAX98373_R2007_INT_FLAG1, 0x00},
+	{MAX98373_R2008_INT_FLAG2, 0x00},
+	{MAX98373_R2009_INT_FLAG3, 0x00},
+	{MAX98373_R200A_INT_EN1, 0x00},
+	{MAX98373_R200B_INT_EN2, 0x00},
+	{MAX98373_R200C_INT_EN3, 0x00},
+	{MAX98373_R200D_INT_FLAG_CLR1, 0x00},
+	{MAX98373_R200E_INT_FLAG_CLR2, 0x00},
+	{MAX98373_R200F_INT_FLAG_CLR3, 0x00},
+	{MAX98373_R2010_IRQ_CTRL, 0x00},
+	{MAX98373_R2014_THERM_WARN_THRESH, 0x10},
+	{MAX98373_R2015_THERM_SHDN_THRESH, 0x27},
+	{MAX98373_R2016_THERM_HYSTERESIS, 0x01},
+	{MAX98373_R2017_THERM_FOLDBACK_SET, 0xC0},
+	{MAX98373_R2018_THERM_FOLDBACK_EN, 0x00},
+	{MAX98373_R201E_PIN_DRIVE_STRENGTH, 0x55},
+	{MAX98373_R2020_PCM_TX_HIZ_EN_1, 0xFE},
+	{MAX98373_R2021_PCM_TX_HIZ_EN_2, 0xFF},
+	{MAX98373_R2022_PCM_TX_SRC_1, 0x00},
+	{MAX98373_R2023_PCM_TX_SRC_2, 0x00},
+	{MAX98373_R2024_PCM_DATA_FMT_CFG, 0xC0},
+	{MAX98373_R2025_AUDIO_IF_MODE, 0x00},
+	{MAX98373_R2026_PCM_CLOCK_RATIO, 0x04},
+	{MAX98373_R2027_PCM_SR_SETUP_1, 0x08},
+	{MAX98373_R2028_PCM_SR_SETUP_2, 0x88},
+	{MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1, 0x00},
+	{MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2, 0x00},
+	{MAX98373_R202B_PCM_RX_EN, 0x00},
+	{MAX98373_R202C_PCM_TX_EN, 0x00},
+	{MAX98373_R202E_ICC_RX_CH_EN_1, 0x00},
+	{MAX98373_R202F_ICC_RX_CH_EN_2, 0x00},
+	{MAX98373_R2030_ICC_TX_HIZ_EN_1, 0xFF},
+	{MAX98373_R2031_ICC_TX_HIZ_EN_2, 0xFF},
+	{MAX98373_R2032_ICC_LINK_EN_CFG, 0x30},
+	{MAX98373_R2034_ICC_TX_CNTL, 0x00},
+	{MAX98373_R2035_ICC_TX_EN, 0x00},
+	{MAX98373_R2036_SOUNDWIRE_CTRL, 0x05},
+	{MAX98373_R203D_AMP_DIG_VOL_CTRL, 0x00},
+	{MAX98373_R203E_AMP_PATH_GAIN, 0x08},
+	{MAX98373_R203F_AMP_DSP_CFG, 0x02},
+	{MAX98373_R2040_TONE_GEN_CFG, 0x00},
+	{MAX98373_R2041_AMP_CFG, 0x03},
+	{MAX98373_R2042_AMP_EDGE_RATE_CFG, 0x00},
+	{MAX98373_R2043_AMP_EN, 0x00},
+	{MAX98373_R2046_IV_SENSE_ADC_DSP_CFG, 0x04},
+	{MAX98373_R2047_IV_SENSE_ADC_EN, 0x00},
+	{MAX98373_R2051_MEAS_ADC_SAMPLING_RATE, 0x00},
+	{MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG, 0x00},
+	{MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG, 0x00},
+	{MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0x00},
+	{MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0x00},
+	{MAX98373_R2056_MEAS_ADC_PVDD_CH_EN, 0x00},
+	{MAX98373_R2090_BDE_LVL_HOLD, 0x00},
+	{MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0x00},
+	{MAX98373_R2092_BDE_CLIPPER_MODE, 0x00},
+	{MAX98373_R2097_BDE_L1_THRESH, 0x00},
+	{MAX98373_R2098_BDE_L2_THRESH, 0x00},
+	{MAX98373_R2099_BDE_L3_THRESH, 0x00},
+	{MAX98373_R209A_BDE_L4_THRESH, 0x00},
+	{MAX98373_R209B_BDE_THRESH_HYST, 0x00},
+	{MAX98373_R20A8_BDE_L1_CFG_1, 0x00},
+	{MAX98373_R20A9_BDE_L1_CFG_2, 0x00},
+	{MAX98373_R20AA_BDE_L1_CFG_3, 0x00},
+	{MAX98373_R20AB_BDE_L2_CFG_1, 0x00},
+	{MAX98373_R20AC_BDE_L2_CFG_2, 0x00},
+	{MAX98373_R20AD_BDE_L2_CFG_3, 0x00},
+	{MAX98373_R20AE_BDE_L3_CFG_1, 0x00},
+	{MAX98373_R20AF_BDE_L3_CFG_2, 0x00},
+	{MAX98373_R20B0_BDE_L3_CFG_3, 0x00},
+	{MAX98373_R20B1_BDE_L4_CFG_1, 0x00},
+	{MAX98373_R20B2_BDE_L4_CFG_2, 0x00},
+	{MAX98373_R20B3_BDE_L4_CFG_3, 0x00},
+	{MAX98373_R20B4_BDE_INFINITE_HOLD_RELEASE, 0x00},
+	{MAX98373_R20B5_BDE_EN, 0x00},
+	{MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0x00},
+	{MAX98373_R20D1_DHT_CFG, 0x01},
+	{MAX98373_R20D2_DHT_ATTACK_CFG, 0x02},
+	{MAX98373_R20D3_DHT_RELEASE_CFG, 0x03},
+	{MAX98373_R20D4_DHT_EN, 0x00},
+	{MAX98373_R20E0_LIMITER_THRESH_CFG, 0x00},
+	{MAX98373_R20E1_LIMITER_ATK_REL_RATES, 0x00},
+	{MAX98373_R20E2_LIMITER_EN, 0x00},
+	{MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG, 0x00},
+	{MAX98373_R20FF_GLOBAL_SHDN, 0x00},
+	{MAX98373_R21FF_REV_ID, 0x42},
+};
+
+static int max98373_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
+	unsigned int format = 0;
+	unsigned int invert = 0;
+
+	dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		invert = MAX98373_PCM_MODE_CFG_PCM_BCLKEDGE;
+		break;
+	default:
+		dev_err(component->dev, "DAI invert mode unsupported\n");
+		return -EINVAL;
+	}
+
+	regmap_update_bits(max98373->regmap,
+		MAX98373_R2026_PCM_CLOCK_RATIO,
+		MAX98373_PCM_MODE_CFG_PCM_BCLKEDGE,
+		invert);
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		format = MAX98373_PCM_FORMAT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		format = MAX98373_PCM_FORMAT_LJ;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		format = MAX98373_PCM_FORMAT_TDM_MODE1;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		format = MAX98373_PCM_FORMAT_TDM_MODE0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(max98373->regmap,
+		MAX98373_R2024_PCM_DATA_FMT_CFG,
+		MAX98373_PCM_MODE_CFG_FORMAT_MASK,
+		format << MAX98373_PCM_MODE_CFG_FORMAT_SHIFT);
+
+	return 0;
+}
+
+/* BCLKs per LRCLK */
+static const int bclk_sel_table[] = {
+	32, 48, 64, 96, 128, 192, 256, 384, 512, 320,
+};
+
+static int max98373_get_bclk_sel(int bclk)
+{
+	int i;
+	/* match BCLKs per LRCLK */
+	for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) {
+		if (bclk_sel_table[i] == bclk)
+			return i + 2;
+	}
+	return 0;
+}
+
+static int max98373_set_clock(struct snd_soc_component *component,
+	struct snd_pcm_hw_params *params)
+{
+	struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
+	/* BCLK/LRCLK ratio calculation */
+	int blr_clk_ratio = params_channels(params) * max98373->ch_size;
+	int value;
+
+	if (!max98373->tdm_mode) {
+		/* BCLK configuration */
+		value = max98373_get_bclk_sel(blr_clk_ratio);
+		if (!value) {
+			dev_err(component->dev, "format unsupported %d\n",
+				params_format(params));
+			return -EINVAL;
+		}
+
+		regmap_update_bits(max98373->regmap,
+			MAX98373_R2026_PCM_CLOCK_RATIO,
+			MAX98373_PCM_CLK_SETUP_BSEL_MASK,
+			value);
+	}
+	return 0;
+}
+
+static int max98373_dai_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
+	unsigned int sampling_rate = 0;
+	unsigned int chan_sz = 0;
+
+	/* pcm mode configuration */
+	switch (snd_pcm_format_width(params_format(params))) {
+	case 16:
+		chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_16;
+		break;
+	case 24:
+		chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_24;
+		break;
+	case 32:
+		chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_32;
+		break;
+	default:
+		dev_err(component->dev, "format unsupported %d\n",
+			params_format(params));
+		goto err;
+	}
+
+	max98373->ch_size = snd_pcm_format_width(params_format(params));
+
+	regmap_update_bits(max98373->regmap,
+		MAX98373_R2024_PCM_DATA_FMT_CFG,
+		MAX98373_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+
+	dev_dbg(component->dev, "format supported %d",
+		params_format(params));
+
+	/* sampling rate configuration */
+	switch (params_rate(params)) {
+	case 8000:
+		sampling_rate = MAX98373_PCM_SR_SET1_SR_8000;
+		break;
+	case 11025:
+		sampling_rate = MAX98373_PCM_SR_SET1_SR_11025;
+		break;
+	case 12000:
+		sampling_rate = MAX98373_PCM_SR_SET1_SR_12000;
+		break;
+	case 16000:
+		sampling_rate = MAX98373_PCM_SR_SET1_SR_16000;
+		break;
+	case 22050:
+		sampling_rate = MAX98373_PCM_SR_SET1_SR_22050;
+		break;
+	case 24000:
+		sampling_rate = MAX98373_PCM_SR_SET1_SR_24000;
+		break;
+	case 32000:
+		sampling_rate = MAX98373_PCM_SR_SET1_SR_32000;
+		break;
+	case 44100:
+		sampling_rate = MAX98373_PCM_SR_SET1_SR_44100;
+		break;
+	case 48000:
+		sampling_rate = MAX98373_PCM_SR_SET1_SR_48000;
+		break;
+	default:
+		dev_err(component->dev, "rate %d not supported\n",
+			params_rate(params));
+		goto err;
+	}
+
+	/* set DAI_SR to correct LRCLK frequency */
+	regmap_update_bits(max98373->regmap,
+		MAX98373_R2027_PCM_SR_SETUP_1,
+		MAX98373_PCM_SR_SET1_SR_MASK,
+		sampling_rate);
+	regmap_update_bits(max98373->regmap,
+		MAX98373_R2028_PCM_SR_SETUP_2,
+		MAX98373_PCM_SR_SET2_SR_MASK,
+		sampling_rate << MAX98373_PCM_SR_SET2_SR_SHIFT);
+
+	/* set sampling rate of IV */
+	if (max98373->interleave_mode &&
+	    sampling_rate > MAX98373_PCM_SR_SET1_SR_16000)
+		regmap_update_bits(max98373->regmap,
+			MAX98373_R2028_PCM_SR_SETUP_2,
+			MAX98373_PCM_SR_SET2_IVADC_SR_MASK,
+			sampling_rate - 3);
+	else
+		regmap_update_bits(max98373->regmap,
+			MAX98373_R2028_PCM_SR_SETUP_2,
+			MAX98373_PCM_SR_SET2_IVADC_SR_MASK,
+			sampling_rate);
+
+	return max98373_set_clock(component, params);
+err:
+	return -EINVAL;
+}
+
+static int max98373_dai_tdm_slot(struct snd_soc_dai *dai,
+	unsigned int tx_mask, unsigned int rx_mask,
+	int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
+	int bsel = 0;
+	unsigned int chan_sz = 0;
+	unsigned int mask;
+	int x, slot_found;
+
+	if (!tx_mask && !rx_mask && !slots && !slot_width)
+		max98373->tdm_mode = false;
+	else
+		max98373->tdm_mode = true;
+
+	/* BCLK configuration */
+	bsel = max98373_get_bclk_sel(slots * slot_width);
+	if (bsel == 0) {
+		dev_err(component->dev, "BCLK %d not supported\n",
+			slots * slot_width);
+		return -EINVAL;
+	}
+
+	regmap_update_bits(max98373->regmap,
+		MAX98373_R2026_PCM_CLOCK_RATIO,
+		MAX98373_PCM_CLK_SETUP_BSEL_MASK,
+		bsel);
+
+	/* Channel size configuration */
+	switch (slot_width) {
+	case 16:
+		chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_16;
+		break;
+	case 24:
+		chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_24;
+		break;
+	case 32:
+		chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_32;
+		break;
+	default:
+		dev_err(component->dev, "format unsupported %d\n",
+			slot_width);
+		return -EINVAL;
+	}
+
+	regmap_update_bits(max98373->regmap,
+		MAX98373_R2024_PCM_DATA_FMT_CFG,
+		MAX98373_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+
+	/* Rx slot configuration */
+	slot_found = 0;
+	mask = rx_mask;
+	for (x = 0 ; x < 16 ; x++, mask >>= 1) {
+		if (mask & 0x1) {
+			if (slot_found == 0)
+				regmap_update_bits(max98373->regmap,
+					MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1,
+					MAX98373_PCM_TO_SPK_CH0_SRC_MASK, x);
+			else
+				regmap_write(max98373->regmap,
+					MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2,
+					x);
+			slot_found++;
+			if (slot_found > 1)
+				break;
+		}
+	}
+
+	/* Tx slot Hi-Z configuration */
+	regmap_write(max98373->regmap,
+		MAX98373_R2020_PCM_TX_HIZ_EN_1,
+		~tx_mask & 0xFF);
+	regmap_write(max98373->regmap,
+		MAX98373_R2021_PCM_TX_HIZ_EN_2,
+		(~tx_mask & 0xFF00) >> 8);
+
+	return 0;
+}
+
+#define MAX98373_RATES SNDRV_PCM_RATE_8000_96000
+
+#define MAX98373_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops max98373_dai_ops = {
+	.set_fmt = max98373_dai_set_fmt,
+	.hw_params = max98373_dai_hw_params,
+	.set_tdm_slot = max98373_dai_tdm_slot,
+};
+
+static int max98373_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(max98373->regmap,
+			MAX98373_R20FF_GLOBAL_SHDN,
+			MAX98373_GLOBAL_EN_MASK, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_update_bits(max98373->regmap,
+			MAX98373_R20FF_GLOBAL_SHDN,
+			MAX98373_GLOBAL_EN_MASK, 0);
+		max98373->tdm_mode = 0;
+		break;
+	default:
+		return 0;
+	}
+	return 0;
+}
+
+static const char * const max98373_switch_text[] = {
+	"Left", "Right", "LeftRight"};
+
+static const struct soc_enum dai_sel_enum =
+	SOC_ENUM_SINGLE(MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1,
+		MAX98373_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
+		3, max98373_switch_text);
+
+static const struct snd_kcontrol_new max98373_dai_controls =
+	SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
+
+static const struct snd_kcontrol_new max98373_vi_control =
+	SOC_DAPM_SINGLE("Switch", MAX98373_R202C_PCM_TX_EN, 0, 1, 0);
+
+static const struct snd_kcontrol_new max98373_spkfb_control =
+	SOC_DAPM_SINGLE("Switch", MAX98373_R2043_AMP_EN, 1, 1, 0);
+
+static const struct snd_soc_dapm_widget max98373_dapm_widgets[] = {
+SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback",
+	MAX98373_R202B_PCM_RX_EN, 0, 0, max98373_dac_event,
+	SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
+	&max98373_dai_controls),
+SND_SOC_DAPM_OUTPUT("BE_OUT"),
+SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0,
+	MAX98373_R2047_IV_SENSE_ADC_EN, 0, 0),
+SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0,
+	MAX98373_R2047_IV_SENSE_ADC_EN, 1, 0),
+SND_SOC_DAPM_AIF_OUT("Speaker FB Sense", "HiFi Capture", 0,
+	SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0,
+	&max98373_vi_control),
+SND_SOC_DAPM_SWITCH("SpkFB Sense", SND_SOC_NOPM, 0, 0,
+	&max98373_spkfb_control),
+SND_SOC_DAPM_SIGGEN("VMON"),
+SND_SOC_DAPM_SIGGEN("IMON"),
+SND_SOC_DAPM_SIGGEN("FBMON"),
+};
+
+static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, 0, -50, 0);
+static const DECLARE_TLV_DB_RANGE(max98373_spk_tlv,
+	0, 8, TLV_DB_SCALE_ITEM(0, 50, 0),
+	9, 10, TLV_DB_SCALE_ITEM(500, 100, 0),
+);
+static const DECLARE_TLV_DB_RANGE(max98373_spkgain_max_tlv,
+	0, 9, TLV_DB_SCALE_ITEM(800, 100, 0),
+);
+static const DECLARE_TLV_DB_RANGE(max98373_dht_step_size_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(25, 25, 0),
+	2, 4, TLV_DB_SCALE_ITEM(100, 100, 0),
+);
+static const DECLARE_TLV_DB_RANGE(max98373_dht_spkgain_min_tlv,
+	0, 9, TLV_DB_SCALE_ITEM(800, 100, 0),
+);
+static const DECLARE_TLV_DB_RANGE(max98373_dht_rotation_point_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(-50, -50, 0),
+	2, 7, TLV_DB_SCALE_ITEM(-200, -100, 0),
+	8, 9, TLV_DB_SCALE_ITEM(-1000, -200, 0),
+	10, 11, TLV_DB_SCALE_ITEM(-1500, -300, 0),
+	12, 13, TLV_DB_SCALE_ITEM(-2000, -200, 0),
+	14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0),
+);
+static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv,
+	0, 15, TLV_DB_SCALE_ITEM(0, -100, 0),
+);
+
+static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv,
+	0, 60, TLV_DB_SCALE_ITEM(0, -25, 0),
+);
+
+static bool max98373_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98373_R2000_SW_RESET:
+	case MAX98373_R2001_INT_RAW1 ... MAX98373_R200C_INT_EN3:
+	case MAX98373_R2010_IRQ_CTRL:
+	case MAX98373_R2014_THERM_WARN_THRESH
+		... MAX98373_R2018_THERM_FOLDBACK_EN:
+	case MAX98373_R201E_PIN_DRIVE_STRENGTH
+		... MAX98373_R2036_SOUNDWIRE_CTRL:
+	case MAX98373_R203D_AMP_DIG_VOL_CTRL ... MAX98373_R2043_AMP_EN:
+	case MAX98373_R2046_IV_SENSE_ADC_DSP_CFG
+		... MAX98373_R2047_IV_SENSE_ADC_EN:
+	case MAX98373_R2051_MEAS_ADC_SAMPLING_RATE
+		... MAX98373_R2056_MEAS_ADC_PVDD_CH_EN:
+	case MAX98373_R2090_BDE_LVL_HOLD ... MAX98373_R2092_BDE_CLIPPER_MODE:
+	case MAX98373_R2097_BDE_L1_THRESH
+		... MAX98373_R209B_BDE_THRESH_HYST:
+	case MAX98373_R20A8_BDE_L1_CFG_1 ... MAX98373_R20B3_BDE_L4_CFG_3:
+	case MAX98373_R20B5_BDE_EN ... MAX98373_R20B6_BDE_CUR_STATE_READBACK:
+	case MAX98373_R20D1_DHT_CFG ... MAX98373_R20D4_DHT_EN:
+	case MAX98373_R20E0_LIMITER_THRESH_CFG ... MAX98373_R20E2_LIMITER_EN:
+	case MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG
+		... MAX98373_R20FF_GLOBAL_SHDN:
+	case MAX98373_R21FF_REV_ID:
+		return true;
+	default:
+		return false;
+	}
+};
+
+static bool max98373_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98373_R2000_SW_RESET ... MAX98373_R2009_INT_FLAG3:
+	case MAX98373_R203E_AMP_PATH_GAIN:
+	case MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK:
+	case MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK:
+	case MAX98373_R20B6_BDE_CUR_STATE_READBACK:
+	case MAX98373_R21FF_REV_ID:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const char * const max98373_output_voltage_lvl_text[] = {
+	"5.43V", "6.09V", "6.83V", "7.67V", "8.60V",
+	"9.65V", "10.83V", "12.15V", "13.63V", "15.29V"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98373_out_volt_enum,
+			    MAX98373_R203E_AMP_PATH_GAIN, 0,
+			    max98373_output_voltage_lvl_text);
+
+static const char * const max98373_dht_attack_rate_text[] = {
+	"17.5us", "35us", "70us", "140us",
+	"280us", "560us", "1120us", "2240us"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98373_dht_attack_rate_enum,
+			    MAX98373_R20D2_DHT_ATTACK_CFG, 0,
+			    max98373_dht_attack_rate_text);
+
+static const char * const max98373_dht_release_rate_text[] = {
+	"45ms", "225ms", "450ms", "1150ms",
+	"2250ms", "3100ms", "4500ms", "6750ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98373_dht_release_rate_enum,
+			    MAX98373_R20D3_DHT_RELEASE_CFG, 0,
+			    max98373_dht_release_rate_text);
+
+static const char * const max98373_limiter_attack_rate_text[] = {
+	"10us", "20us", "40us", "80us",
+	"160us", "320us", "640us", "1.28ms",
+	"2.56ms", "5.12ms", "10.24ms", "20.48ms",
+	"40.96ms", "81.92ms", "16.384ms", "32.768ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98373_limiter_attack_rate_enum,
+			    MAX98373_R20E1_LIMITER_ATK_REL_RATES, 4,
+			    max98373_limiter_attack_rate_text);
+
+static const char * const max98373_limiter_release_rate_text[] = {
+	"40us", "80us", "160us", "320us",
+	"640us", "1.28ms", "2.56ms", "5.120ms",
+	"10.24ms", "20.48ms", "40.96ms", "81.92ms",
+	"163.84ms", "327.68ms", "655.36ms", "1310.72ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98373_limiter_release_rate_enum,
+			    MAX98373_R20E1_LIMITER_ATK_REL_RATES, 0,
+			    max98373_limiter_release_rate_text);
+
+static const char * const max98373_ADC_samplerate_text[] = {
+	"333kHz", "192kHz", "64kHz", "48kHz"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98373_adc_samplerate_enum,
+			    MAX98373_R2051_MEAS_ADC_SAMPLING_RATE, 0,
+			    max98373_ADC_samplerate_text);
+
+static const struct snd_kcontrol_new max98373_snd_controls[] = {
+SOC_SINGLE("Digital Vol Sel Switch", MAX98373_R203F_AMP_DSP_CFG,
+	MAX98373_AMP_VOL_SEL_SHIFT, 1, 0),
+SOC_SINGLE("Volume Location Switch", MAX98373_R203F_AMP_DSP_CFG,
+	MAX98373_AMP_VOL_SEL_SHIFT, 1, 0),
+SOC_SINGLE("Ramp Up Switch", MAX98373_R203F_AMP_DSP_CFG,
+	MAX98373_AMP_DSP_CFG_RMP_UP_SHIFT, 1, 0),
+SOC_SINGLE("Ramp Down Switch", MAX98373_R203F_AMP_DSP_CFG,
+	MAX98373_AMP_DSP_CFG_RMP_DN_SHIFT, 1, 0),
+SOC_SINGLE("CLK Monitor Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG,
+	MAX98373_CLOCK_MON_SHIFT, 1, 0),
+SOC_SINGLE("Dither Switch", MAX98373_R203F_AMP_DSP_CFG,
+	MAX98373_AMP_DSP_CFG_DITH_SHIFT, 1, 0),
+SOC_SINGLE("DC Blocker Switch", MAX98373_R203F_AMP_DSP_CFG,
+	MAX98373_AMP_DSP_CFG_DCBLK_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Digital Volume", MAX98373_R203D_AMP_DIG_VOL_CTRL,
+	0, 0x7F, 0, max98373_digital_tlv),
+SOC_SINGLE_TLV("Speaker Volume", MAX98373_R203E_AMP_PATH_GAIN,
+	MAX98373_SPK_DIGI_GAIN_SHIFT, 10, 0, max98373_spk_tlv),
+SOC_SINGLE_TLV("FS Max Volume", MAX98373_R203E_AMP_PATH_GAIN,
+	MAX98373_FS_GAIN_MAX_SHIFT, 9, 0, max98373_spkgain_max_tlv),
+SOC_ENUM("Output Voltage", max98373_out_volt_enum),
+/* Dynamic Headroom Tracking */
+SOC_SINGLE("DHT Switch", MAX98373_R20D4_DHT_EN,
+	MAX98373_DHT_EN_SHIFT, 1, 0),
+SOC_SINGLE_TLV("DHT Min Volume", MAX98373_R20D1_DHT_CFG,
+	MAX98373_DHT_SPK_GAIN_MIN_SHIFT, 9, 0, max98373_dht_spkgain_min_tlv),
+SOC_SINGLE_TLV("DHT Rot Pnt Volume", MAX98373_R20D1_DHT_CFG,
+	MAX98373_DHT_ROT_PNT_SHIFT, 15, 0, max98373_dht_rotation_point_tlv),
+SOC_SINGLE_TLV("DHT Attack Step Volume", MAX98373_R20D2_DHT_ATTACK_CFG,
+	MAX98373_DHT_ATTACK_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv),
+SOC_SINGLE_TLV("DHT Release Step Volume", MAX98373_R20D3_DHT_RELEASE_CFG,
+	MAX98373_DHT_RELEASE_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv),
+SOC_ENUM("DHT Attack Rate", max98373_dht_attack_rate_enum),
+SOC_ENUM("DHT Release Rate", max98373_dht_release_rate_enum),
+/* ADC configuration */
+SOC_SINGLE("ADC PVDD CH Switch", MAX98373_R2056_MEAS_ADC_PVDD_CH_EN, 0, 1, 0),
+SOC_SINGLE("ADC PVDD FLT Switch", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
+	MAX98373_FLT_EN_SHIFT, 1, 0),
+SOC_SINGLE("ADC TEMP FLT Switch", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
+	MAX98373_FLT_EN_SHIFT, 1, 0),
+SOC_SINGLE("ADC PVDD", MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0, 0xFF, 0),
+SOC_SINGLE("ADC TEMP", MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0, 0xFF, 0),
+SOC_SINGLE("ADC PVDD FLT Coeff", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
+	0, 0x3, 0),
+SOC_SINGLE("ADC TEMP FLT Coeff", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
+	0, 0x3, 0),
+SOC_ENUM("ADC SampleRate", max98373_adc_samplerate_enum),
+/* Brownout Detection Engine */
+SOC_SINGLE("BDE Switch", MAX98373_R20B5_BDE_EN, MAX98373_BDE_EN_SHIFT, 1, 0),
+SOC_SINGLE("BDE LVL4 Mute Switch", MAX98373_R20B2_BDE_L4_CFG_2,
+	MAX98373_LVL4_MUTE_EN_SHIFT, 1, 0),
+SOC_SINGLE("BDE LVL4 Hold Switch", MAX98373_R20B2_BDE_L4_CFG_2,
+	MAX98373_LVL4_HOLD_EN_SHIFT, 1, 0),
+SOC_SINGLE("BDE LVL1 Thresh", MAX98373_R2097_BDE_L1_THRESH, 0, 0xFF, 0),
+SOC_SINGLE("BDE LVL2 Thresh", MAX98373_R2098_BDE_L2_THRESH, 0, 0xFF, 0),
+SOC_SINGLE("BDE LVL3 Thresh", MAX98373_R2099_BDE_L3_THRESH, 0, 0xFF, 0),
+SOC_SINGLE("BDE LVL4 Thresh", MAX98373_R209A_BDE_L4_THRESH, 0, 0xFF, 0),
+SOC_SINGLE("BDE Active Level", MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0, 8, 0),
+SOC_SINGLE("BDE Clip Mode Switch", MAX98373_R2092_BDE_CLIPPER_MODE, 0, 1, 0),
+SOC_SINGLE("BDE Thresh Hysteresis", MAX98373_R209B_BDE_THRESH_HYST, 0, 0xFF, 0),
+SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0),
+SOC_SINGLE("BDE Attack Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 4, 0xF, 0),
+SOC_SINGLE("BDE Release Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0, 0xF, 0),
+SOC_SINGLE_TLV("BDE LVL1 Clip Thresh Volume", MAX98373_R20A9_BDE_L1_CFG_2,
+	0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL2 Clip Thresh Volume", MAX98373_R20AC_BDE_L2_CFG_2,
+	0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL3 Clip Thresh Volume", MAX98373_R20AF_BDE_L3_CFG_2,
+	0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL4 Clip Thresh Volume", MAX98373_R20B2_BDE_L4_CFG_2,
+	0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL1 Clip Reduction Volume", MAX98373_R20AA_BDE_L1_CFG_3,
+	0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL2 Clip Reduction Volume", MAX98373_R20AD_BDE_L2_CFG_3,
+	0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL3 Clip Reduction Volume", MAX98373_R20B0_BDE_L3_CFG_3,
+	0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL4 Clip Reduction Volume", MAX98373_R20B3_BDE_L4_CFG_3,
+	0, 0x3C, 0, max98373_bde_gain_tlv),
+SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh Volume", MAX98373_R20A8_BDE_L1_CFG_1,
+	0, 0xF, 0, max98373_limiter_thresh_tlv),
+SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh Volume", MAX98373_R20AB_BDE_L2_CFG_1,
+	0, 0xF, 0, max98373_limiter_thresh_tlv),
+SOC_SINGLE_TLV("BDE LVL3 Limiter Thresh Volume", MAX98373_R20AE_BDE_L3_CFG_1,
+	0, 0xF, 0, max98373_limiter_thresh_tlv),
+SOC_SINGLE_TLV("BDE LVL4 Limiter Thresh Volume", MAX98373_R20B1_BDE_L4_CFG_1,
+	0, 0xF, 0, max98373_limiter_thresh_tlv),
+/* Limiter */
+SOC_SINGLE("Limiter Switch", MAX98373_R20E2_LIMITER_EN,
+	MAX98373_LIMITER_EN_SHIFT, 1, 0),
+SOC_SINGLE("Limiter Src Switch", MAX98373_R20E0_LIMITER_THRESH_CFG,
+	MAX98373_LIMITER_THRESH_SRC_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Limiter Thresh Volume", MAX98373_R20E0_LIMITER_THRESH_CFG,
+	MAX98373_LIMITER_THRESH_SHIFT, 15, 0, max98373_limiter_thresh_tlv),
+SOC_ENUM("Limiter Attack Rate", max98373_limiter_attack_rate_enum),
+SOC_ENUM("Limiter Release Rate", max98373_limiter_release_rate_enum),
+};
+
+static const struct snd_soc_dapm_route max98373_audio_map[] = {
+	/* Plabyack */
+	{"DAI Sel Mux", "Left", "Amp Enable"},
+	{"DAI Sel Mux", "Right", "Amp Enable"},
+	{"DAI Sel Mux", "LeftRight", "Amp Enable"},
+	{"BE_OUT", NULL, "DAI Sel Mux"},
+	/* Capture */
+	{ "VI Sense", "Switch", "VMON" },
+	{ "VI Sense", "Switch", "IMON" },
+	{ "SpkFB Sense", "Switch", "FBMON" },
+	{ "Voltage Sense", NULL, "VI Sense" },
+	{ "Current Sense", NULL, "VI Sense" },
+	{ "Speaker FB Sense", NULL, "SpkFB Sense" },
+};
+
+static struct snd_soc_dai_driver max98373_dai[] = {
+	{
+		.name = "max98373-aif1",
+		.playback = {
+			.stream_name = "HiFi Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MAX98373_RATES,
+			.formats = MAX98373_FORMATS,
+		},
+		.capture = {
+			.stream_name = "HiFi Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MAX98373_RATES,
+			.formats = MAX98373_FORMATS,
+		},
+		.ops = &max98373_dai_ops,
+	}
+};
+
+static int max98373_probe(struct snd_soc_component *component)
+{
+	struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
+
+	/* Software Reset */
+	regmap_write(max98373->regmap,
+		MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET);
+	usleep_range(10000, 11000);
+
+	/* IV default slot configuration */
+	regmap_write(max98373->regmap,
+		MAX98373_R2020_PCM_TX_HIZ_EN_1,
+		0xFF);
+	regmap_write(max98373->regmap,
+		MAX98373_R2021_PCM_TX_HIZ_EN_2,
+		0xFF);
+	/* L/R mix configuration */
+	regmap_write(max98373->regmap,
+		MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1,
+		0x80);
+	regmap_write(max98373->regmap,
+		MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2,
+		0x1);
+	/* Set inital volume (0dB) */
+	regmap_write(max98373->regmap,
+		MAX98373_R203D_AMP_DIG_VOL_CTRL,
+		0x00);
+	regmap_write(max98373->regmap,
+		MAX98373_R203E_AMP_PATH_GAIN,
+		0x00);
+	/* Enable DC blocker */
+	regmap_write(max98373->regmap,
+		MAX98373_R203F_AMP_DSP_CFG,
+		0x3);
+	/* Enable IMON VMON DC blocker */
+	regmap_write(max98373->regmap,
+		MAX98373_R2046_IV_SENSE_ADC_DSP_CFG,
+		0x7);
+	/* voltage, current slot configuration */
+	regmap_write(max98373->regmap,
+		MAX98373_R2022_PCM_TX_SRC_1,
+		(max98373->i_slot << MAX98373_PCM_TX_CH_SRC_A_I_SHIFT |
+		max98373->v_slot) & 0xFF);
+	if (max98373->v_slot < 8)
+		regmap_update_bits(max98373->regmap,
+			MAX98373_R2020_PCM_TX_HIZ_EN_1,
+			1 << max98373->v_slot, 0);
+	else
+		regmap_update_bits(max98373->regmap,
+			MAX98373_R2021_PCM_TX_HIZ_EN_2,
+			1 << (max98373->v_slot - 8), 0);
+
+	if (max98373->i_slot < 8)
+		regmap_update_bits(max98373->regmap,
+			MAX98373_R2020_PCM_TX_HIZ_EN_1,
+			1 << max98373->i_slot, 0);
+	else
+		regmap_update_bits(max98373->regmap,
+			MAX98373_R2021_PCM_TX_HIZ_EN_2,
+			1 << (max98373->i_slot - 8), 0);
+
+	/* speaker feedback slot configuration */
+	regmap_write(max98373->regmap,
+		MAX98373_R2023_PCM_TX_SRC_2,
+		max98373->spkfb_slot & 0xFF);
+
+	/* Set interleave mode */
+	if (max98373->interleave_mode)
+		regmap_update_bits(max98373->regmap,
+			MAX98373_R2024_PCM_DATA_FMT_CFG,
+			MAX98373_PCM_TX_CH_INTERLEAVE_MASK,
+			MAX98373_PCM_TX_CH_INTERLEAVE_MASK);
+
+	/* Speaker enable */
+	regmap_update_bits(max98373->regmap,
+		MAX98373_R2043_AMP_EN,
+		MAX98373_SPK_EN_MASK, 1);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max98373_suspend(struct device *dev)
+{
+	struct max98373_priv *max98373 = dev_get_drvdata(dev);
+
+	regcache_cache_only(max98373->regmap, true);
+	regcache_mark_dirty(max98373->regmap);
+	return 0;
+}
+static int max98373_resume(struct device *dev)
+{
+	struct max98373_priv *max98373 = dev_get_drvdata(dev);
+
+	regmap_write(max98373->regmap,
+		MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET);
+	usleep_range(10000, 11000);
+	regcache_cache_only(max98373->regmap, false);
+	regcache_sync(max98373->regmap);
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops max98373_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(max98373_suspend, max98373_resume)
+};
+
+static const struct snd_soc_component_driver soc_codec_dev_max98373 = {
+	.probe			= max98373_probe,
+	.controls		= max98373_snd_controls,
+	.num_controls		= ARRAY_SIZE(max98373_snd_controls),
+	.dapm_widgets		= max98373_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98373_dapm_widgets),
+	.dapm_routes		= max98373_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max98373_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config max98373_regmap = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.max_register = MAX98373_R21FF_REV_ID,
+	.reg_defaults  = max98373_reg,
+	.num_reg_defaults = ARRAY_SIZE(max98373_reg),
+	.readable_reg = max98373_readable_register,
+	.volatile_reg = max98373_volatile_reg,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static void max98373_slot_config(struct i2c_client *i2c,
+	struct max98373_priv *max98373)
+{
+	int value;
+	struct device *dev = &i2c->dev;
+
+	if (!device_property_read_u32(dev, "maxim,vmon-slot-no", &value))
+		max98373->v_slot = value & 0xF;
+	else
+		max98373->v_slot = 0;
+
+	if (!device_property_read_u32(dev, "maxim,imon-slot-no", &value))
+		max98373->i_slot = value & 0xF;
+	else
+		max98373->i_slot = 1;
+
+	if (!device_property_read_u32(dev, "maxim,spkfb-slot-no", &value))
+		max98373->spkfb_slot = value & 0xF;
+	else
+		max98373->spkfb_slot = 2;
+}
+
+static int max98373_i2c_probe(struct i2c_client *i2c,
+	const struct i2c_device_id *id)
+{
+
+	int ret = 0;
+	int reg = 0;
+	struct max98373_priv *max98373 = NULL;
+
+	max98373 = devm_kzalloc(&i2c->dev, sizeof(*max98373), GFP_KERNEL);
+
+	if (!max98373) {
+		ret = -ENOMEM;
+		return ret;
+	}
+	i2c_set_clientdata(i2c, max98373);
+
+	/* update interleave mode info */
+	if (device_property_read_bool(&i2c->dev, "maxim,interleave_mode"))
+		max98373->interleave_mode = 1;
+	else
+		max98373->interleave_mode = 0;
+
+
+	/* regmap initialization */
+	max98373->regmap
+		= devm_regmap_init_i2c(i2c, &max98373_regmap);
+	if (IS_ERR(max98373->regmap)) {
+		ret = PTR_ERR(max98373->regmap);
+		dev_err(&i2c->dev,
+			"Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	/* Check Revision ID */
+	ret = regmap_read(max98373->regmap,
+		MAX98373_R21FF_REV_ID, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev,
+			"Failed to read: 0x%02X\n", MAX98373_R21FF_REV_ID);
+		return ret;
+	}
+	dev_info(&i2c->dev, "MAX98373 revisionID: 0x%02X\n", reg);
+
+	/* voltage/current slot configuration */
+	max98373_slot_config(i2c, max98373);
+
+	/* codec registeration */
+	ret = devm_snd_soc_register_component(&i2c->dev, &soc_codec_dev_max98373,
+		max98373_dai, ARRAY_SIZE(max98373_dai));
+	if (ret < 0)
+		dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+
+	return ret;
+}
+
+static const struct i2c_device_id max98373_i2c_id[] = {
+	{ "max98373", 0},
+	{ },
+};
+
+MODULE_DEVICE_TABLE(i2c, max98373_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id max98373_of_match[] = {
+	{ .compatible = "maxim,max98373", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max98373_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id max98373_acpi_match[] = {
+	{ "MX98373", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, max98373_acpi_match);
+#endif
+
+static struct i2c_driver max98373_i2c_driver = {
+	.driver = {
+		.name = "max98373",
+		.of_match_table = of_match_ptr(max98373_of_match),
+		.acpi_match_table = ACPI_PTR(max98373_acpi_match),
+		.pm = &max98373_pm,
+	},
+	.probe = max98373_i2c_probe,
+	.id_table = max98373_i2c_id,
+};
+
+module_i2c_driver(max98373_i2c_driver)
+
+MODULE_DESCRIPTION("ALSA SoC MAX98373 driver");
+MODULE_AUTHOR("Ryan Lee <ryans.lee@maximintegrated.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98373.h b/sound/soc/codecs/max98373.h
new file mode 100644
index 0000000..f6a37aa
--- /dev/null
+++ b/sound/soc/codecs/max98373.h
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017, Maxim Integrated
+
+#ifndef _MAX98373_H
+#define _MAX98373_H
+
+#define MAX98373_R2000_SW_RESET 0x2000
+#define MAX98373_R2001_INT_RAW1 0x2001
+#define MAX98373_R2002_INT_RAW2 0x2002
+#define MAX98373_R2003_INT_RAW3 0x2003
+#define MAX98373_R2004_INT_STATE1 0x2004
+#define MAX98373_R2005_INT_STATE2 0x2005
+#define MAX98373_R2006_INT_STATE3 0x2006
+#define MAX98373_R2007_INT_FLAG1 0x2007
+#define MAX98373_R2008_INT_FLAG2 0x2008
+#define MAX98373_R2009_INT_FLAG3 0x2009
+#define MAX98373_R200A_INT_EN1 0x200A
+#define MAX98373_R200B_INT_EN2 0x200B
+#define MAX98373_R200C_INT_EN3 0x200C
+#define MAX98373_R200D_INT_FLAG_CLR1 0x200D
+#define MAX98373_R200E_INT_FLAG_CLR2 0x200E
+#define MAX98373_R200F_INT_FLAG_CLR3 0x200F
+#define MAX98373_R2010_IRQ_CTRL 0x2010
+#define MAX98373_R2014_THERM_WARN_THRESH 0x2014
+#define MAX98373_R2015_THERM_SHDN_THRESH 0x2015
+#define MAX98373_R2016_THERM_HYSTERESIS 0x2016
+#define MAX98373_R2017_THERM_FOLDBACK_SET 0x2017
+#define MAX98373_R2018_THERM_FOLDBACK_EN 0x2018
+#define MAX98373_R201E_PIN_DRIVE_STRENGTH 0x201E
+#define MAX98373_R2020_PCM_TX_HIZ_EN_1 0x2020
+#define MAX98373_R2021_PCM_TX_HIZ_EN_2 0x2021
+#define MAX98373_R2022_PCM_TX_SRC_1 0x2022
+#define MAX98373_R2023_PCM_TX_SRC_2 0x2023
+#define MAX98373_R2024_PCM_DATA_FMT_CFG	0x2024
+#define MAX98373_R2025_AUDIO_IF_MODE 0x2025
+#define MAX98373_R2026_PCM_CLOCK_RATIO 0x2026
+#define MAX98373_R2027_PCM_SR_SETUP_1 0x2027
+#define MAX98373_R2028_PCM_SR_SETUP_2 0x2028
+#define MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1 0x2029
+#define MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2 0x202A
+#define MAX98373_R202B_PCM_RX_EN 0x202B
+#define MAX98373_R202C_PCM_TX_EN 0x202C
+#define MAX98373_R202E_ICC_RX_CH_EN_1 0x202E
+#define MAX98373_R202F_ICC_RX_CH_EN_2 0x202F
+#define MAX98373_R2030_ICC_TX_HIZ_EN_1 0x2030
+#define MAX98373_R2031_ICC_TX_HIZ_EN_2 0x2031
+#define MAX98373_R2032_ICC_LINK_EN_CFG 0x2032
+#define MAX98373_R2034_ICC_TX_CNTL 0x2034
+#define MAX98373_R2035_ICC_TX_EN 0x2035
+#define MAX98373_R2036_SOUNDWIRE_CTRL 0x2036
+#define MAX98373_R203D_AMP_DIG_VOL_CTRL 0x203D
+#define MAX98373_R203E_AMP_PATH_GAIN 0x203E
+#define MAX98373_R203F_AMP_DSP_CFG 0x203F
+#define MAX98373_R2040_TONE_GEN_CFG 0x2040
+#define MAX98373_R2041_AMP_CFG 0x2041
+#define MAX98373_R2042_AMP_EDGE_RATE_CFG 0x2042
+#define MAX98373_R2043_AMP_EN 0x2043
+#define MAX98373_R2046_IV_SENSE_ADC_DSP_CFG 0x2046
+#define MAX98373_R2047_IV_SENSE_ADC_EN 0x2047
+#define MAX98373_R2051_MEAS_ADC_SAMPLING_RATE 0x2051
+#define MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG 0x2052
+#define MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG 0x2053
+#define MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK 0x2054
+#define MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK 0x2055
+#define MAX98373_R2056_MEAS_ADC_PVDD_CH_EN 0x2056
+#define MAX98373_R2090_BDE_LVL_HOLD 0x2090
+#define MAX98373_R2091_BDE_GAIN_ATK_REL_RATE 0x2091
+#define MAX98373_R2092_BDE_CLIPPER_MODE 0x2092
+#define MAX98373_R2097_BDE_L1_THRESH 0x2097
+#define MAX98373_R2098_BDE_L2_THRESH 0x2098
+#define MAX98373_R2099_BDE_L3_THRESH 0x2099
+#define MAX98373_R209A_BDE_L4_THRESH 0x209A
+#define MAX98373_R209B_BDE_THRESH_HYST 0x209B
+#define MAX98373_R20A8_BDE_L1_CFG_1 0x20A8
+#define MAX98373_R20A9_BDE_L1_CFG_2 0x20A9
+#define MAX98373_R20AA_BDE_L1_CFG_3 0x20AA
+#define MAX98373_R20AB_BDE_L2_CFG_1 0x20AB
+#define MAX98373_R20AC_BDE_L2_CFG_2 0x20AC
+#define MAX98373_R20AD_BDE_L2_CFG_3 0x20AD
+#define MAX98373_R20AE_BDE_L3_CFG_1 0x20AE
+#define MAX98373_R20AF_BDE_L3_CFG_2 0x20AF
+#define MAX98373_R20B0_BDE_L3_CFG_3 0x20B0
+#define MAX98373_R20B1_BDE_L4_CFG_1 0x20B1
+#define MAX98373_R20B2_BDE_L4_CFG_2 0x20B2
+#define MAX98373_R20B3_BDE_L4_CFG_3 0x20B3
+#define MAX98373_R20B4_BDE_INFINITE_HOLD_RELEASE 0x20B4
+#define MAX98373_R20B5_BDE_EN 0x20B5
+#define MAX98373_R20B6_BDE_CUR_STATE_READBACK 0x20B6
+#define MAX98373_R20D1_DHT_CFG 0x20D1
+#define MAX98373_R20D2_DHT_ATTACK_CFG 0x20D2
+#define MAX98373_R20D3_DHT_RELEASE_CFG 0x20D3
+#define MAX98373_R20D4_DHT_EN 0x20D4
+#define MAX98373_R20E0_LIMITER_THRESH_CFG 0x20E0
+#define MAX98373_R20E1_LIMITER_ATK_REL_RATES 0x20E1
+#define MAX98373_R20E2_LIMITER_EN 0x20E2
+#define MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG 0x20FE
+#define MAX98373_R20FF_GLOBAL_SHDN 0x20FF
+#define MAX98373_R21FF_REV_ID 0x21FF
+
+/* MAX98373_R2022_PCM_TX_SRC_1 */
+#define MAX98373_PCM_TX_CH_SRC_A_V_SHIFT (0)
+#define MAX98373_PCM_TX_CH_SRC_A_I_SHIFT (4)
+
+/* MAX98373_R2024_PCM_DATA_FMT_CFG */
+#define MAX98373_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3)
+#define MAX98373_PCM_MODE_CFG_FORMAT_SHIFT (3)
+#define MAX98373_PCM_TX_CH_INTERLEAVE_MASK (0x1 << 2)
+#define MAX98373_PCM_FORMAT_I2S (0x0 << 0)
+#define MAX98373_PCM_FORMAT_LJ (0x1 << 0)
+#define MAX98373_PCM_FORMAT_TDM_MODE0 (0x3 << 0)
+#define MAX98373_PCM_FORMAT_TDM_MODE1 (0x4 << 0)
+#define MAX98373_PCM_FORMAT_TDM_MODE2 (0x5 << 0)
+#define MAX98373_PCM_MODE_CFG_CHANSZ_MASK (0x3 << 6)
+#define MAX98373_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6)
+#define MAX98373_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6)
+#define MAX98373_PCM_MODE_CFG_CHANSZ_32 (0x3 << 6)
+
+/* MAX98373_R2026_PCM_CLOCK_RATIO */
+#define MAX98373_PCM_MODE_CFG_PCM_BCLKEDGE (0x1 << 4)
+#define MAX98373_PCM_CLK_SETUP_BSEL_MASK (0xF << 0)
+
+/* MAX98373_R2027_PCM_SR_SETUP_1 */
+#define MAX98373_PCM_SR_SET1_SR_MASK (0xF << 0)
+#define MAX98373_PCM_SR_SET1_SR_8000 (0x0 << 0)
+#define MAX98373_PCM_SR_SET1_SR_11025 (0x1 << 0)
+#define MAX98373_PCM_SR_SET1_SR_12000 (0x2 << 0)
+#define MAX98373_PCM_SR_SET1_SR_16000 (0x3 << 0)
+#define MAX98373_PCM_SR_SET1_SR_22050 (0x4 << 0)
+#define MAX98373_PCM_SR_SET1_SR_24000 (0x5 << 0)
+#define MAX98373_PCM_SR_SET1_SR_32000 (0x6 << 0)
+#define MAX98373_PCM_SR_SET1_SR_44100 (0x7 << 0)
+#define MAX98373_PCM_SR_SET1_SR_48000 (0x8 << 0)
+
+/* MAX98373_R2028_PCM_SR_SETUP_2 */
+#define MAX98373_PCM_SR_SET2_SR_MASK (0xF << 4)
+#define MAX98373_PCM_SR_SET2_SR_SHIFT (4)
+#define MAX98373_PCM_SR_SET2_IVADC_SR_MASK (0xF << 0)
+
+/* MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1 */
+#define MAX98373_PCM_TO_SPK_MONOMIX_CFG_MASK (0x3 << 6)
+#define MAX98373_PCM_TO_SPK_MONOMIX_CFG_SHIFT (6)
+#define MAX98373_PCM_TO_SPK_CH0_SRC_MASK (0xF << 0)
+
+/* MAX98373_R203E_AMP_PATH_GAIN */
+#define MAX98373_SPK_DIGI_GAIN_MASK (0xF << 4)
+#define MAX98373_SPK_DIGI_GAIN_SHIFT (4)
+#define MAX98373_FS_GAIN_MAX_MASK (0xF << 0)
+#define MAX98373_FS_GAIN_MAX_SHIFT (0)
+
+/* MAX98373_R203F_AMP_DSP_CFG */
+#define MAX98373_AMP_DSP_CFG_DCBLK_SHIFT (0)
+#define MAX98373_AMP_DSP_CFG_DITH_SHIFT (1)
+#define MAX98373_AMP_DSP_CFG_RMP_UP_SHIFT (2)
+#define MAX98373_AMP_DSP_CFG_RMP_DN_SHIFT (3)
+#define MAX98373_AMP_DSP_CFG_DAC_INV_SHIFT (5)
+#define MAX98373_AMP_VOL_SEL_SHIFT (7)
+
+/* MAX98373_R2043_AMP_EN */
+#define MAX98373_SPKFB_EN_MASK (0x1 << 1)
+#define MAX98373_SPK_EN_MASK (0x1 << 0)
+#define MAX98373_SPKFB_EN_SHIFT (1)
+
+/*MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG */
+#define MAX98373_FLT_EN_SHIFT (4)
+
+/* MAX98373_R20B2_BDE_L4_CFG_2 */
+#define MAX98373_LVL4_MUTE_EN_SHIFT (7)
+#define MAX98373_LVL4_HOLD_EN_SHIFT (6)
+
+/* MAX98373_R20B5_BDE_EN */
+#define MAX98373_BDE_EN_SHIFT (0)
+
+/* MAX98373_R20D1_DHT_CFG */
+#define MAX98373_DHT_SPK_GAIN_MIN_SHIFT	(4)
+#define MAX98373_DHT_ROT_PNT_SHIFT	(0)
+
+/* MAX98373_R20D2_DHT_ATTACK_CFG */
+#define MAX98373_DHT_ATTACK_STEP_SHIFT (3)
+#define MAX98373_DHT_ATTACK_RATE_SHIFT (0)
+
+/* MAX98373_R20D3_DHT_RELEASE_CFG */
+#define MAX98373_DHT_RELEASE_STEP_SHIFT (3)
+#define MAX98373_DHT_RELEASE_RATE_SHIFT (0)
+
+/* MAX98373_R20D4_DHT_EN */
+#define MAX98373_DHT_EN_SHIFT (0)
+
+/* MAX98373_R20E0_LIMITER_THRESH_CFG */
+#define MAX98373_LIMITER_THRESH_SHIFT (2)
+#define MAX98373_LIMITER_THRESH_SRC_SHIFT (0)
+
+/* MAX98373_R20E2_LIMITER_EN */
+#define MAX98373_LIMITER_EN_SHIFT (0)
+
+/* MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG */
+#define MAX98373_CLOCK_MON_SHIFT (0)
+
+/* MAX98373_R20FF_GLOBAL_SHDN */
+#define MAX98373_GLOBAL_EN_MASK (0x1 << 0)
+
+/* MAX98373_R2000_SW_RESET */
+#define MAX98373_SOFT_RESET (0x1 << 0)
+
+struct max98373_priv {
+	struct regmap *regmap;
+	unsigned int v_slot;
+	unsigned int i_slot;
+	unsigned int spkfb_slot;
+	bool interleave_mode;
+	unsigned int ch_size;
+	bool tdm_mode;
+};
+#endif
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
new file mode 100644
index 0000000..6e61345
--- /dev/null
+++ b/sound/soc/codecs/max9850.c
@@ -0,0 +1,360 @@
+/*
+ * max9850.c  --  codec driver for max9850
+ *
+ * Copyright (C) 2011 taskit GmbH
+ *
+ * Author: Christian Glindkamp <christian.glindkamp@taskit.de>
+ *
+ * Initial development of this code was funded by
+ * MICRONIC Computer Systeme GmbH, http://www.mcsberlin.de/
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "max9850.h"
+
+struct max9850_priv {
+	struct regmap *regmap;
+	unsigned int sysclk;
+};
+
+/* max9850 register cache */
+static const struct reg_default max9850_reg[] = {
+	{  2, 0x0c },
+	{  3, 0x00 },
+	{  4, 0x00 },
+	{  5, 0x00 },
+	{  6, 0x00 },
+	{  7, 0x00 },
+	{  8, 0x00 },
+	{  9, 0x00 },
+	{ 10, 0x00 },
+};
+
+/* these registers are not used at the moment but provided for the sake of
+ * completeness */
+static bool max9850_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX9850_STATUSA:
+	case MAX9850_STATUSB:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config max9850_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = MAX9850_DIGITAL_AUDIO,
+	.volatile_reg = max9850_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const DECLARE_TLV_DB_RANGE(max9850_tlv,
+	0x18, 0x1f, TLV_DB_SCALE_ITEM(-7450, 400, 0),
+	0x20, 0x33, TLV_DB_SCALE_ITEM(-4150, 200, 0),
+	0x34, 0x37, TLV_DB_SCALE_ITEM(-150, 100, 0),
+	0x38, 0x3f, TLV_DB_SCALE_ITEM(250, 50, 0)
+);
+
+static const struct snd_kcontrol_new max9850_controls[] = {
+SOC_SINGLE_TLV("Headphone Volume", MAX9850_VOLUME, 0, 0x3f, 1, max9850_tlv),
+SOC_SINGLE("Headphone Switch", MAX9850_VOLUME, 7, 1, 1),
+SOC_SINGLE("Mono Switch", MAX9850_GENERAL_PURPOSE, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new max9850_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line In Switch", MAX9850_ENABLE, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget max9850_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("Charge Pump 1", MAX9850_ENABLE, 4, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("Charge Pump 2", MAX9850_ENABLE, 5, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MCLK", MAX9850_ENABLE, 6, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("SHDN", MAX9850_ENABLE, 7, 0, NULL, 0),
+SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer", MAX9850_ENABLE, 2, 0,
+		&max9850_mixer_controls[0],
+		ARRAY_SIZE(max9850_mixer_controls)),
+SND_SOC_DAPM_PGA("Headphone Output", MAX9850_ENABLE, 3, 0, NULL, 0),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", MAX9850_ENABLE, 0, 0),
+SND_SOC_DAPM_OUTPUT("OUTL"),
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("OUTR"),
+SND_SOC_DAPM_OUTPUT("HPR"),
+SND_SOC_DAPM_MIXER("Line Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_INPUT("INL"),
+SND_SOC_DAPM_INPUT("INR"),
+};
+
+static const struct snd_soc_dapm_route max9850_dapm_routes[] = {
+	/* output mixer */
+	{"Output Mixer", NULL, "DAC"},
+	{"Output Mixer", "Line In Switch", "Line Input"},
+
+	/* outputs */
+	{"Headphone Output", NULL, "Output Mixer"},
+	{"HPL", NULL, "Headphone Output"},
+	{"HPR", NULL, "Headphone Output"},
+	{"OUTL", NULL, "Output Mixer"},
+	{"OUTR", NULL, "Output Mixer"},
+
+	/* inputs */
+	{"Line Input", NULL, "INL"},
+	{"Line Input", NULL, "INR"},
+
+	/* supplies */
+	{"Output Mixer", NULL, "Charge Pump 1"},
+	{"Output Mixer", NULL, "Charge Pump 2"},
+	{"Output Mixer", NULL, "SHDN"},
+	{"DAC", NULL, "MCLK"},
+};
+
+static int max9850_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max9850_priv *max9850 = snd_soc_component_get_drvdata(component);
+	u64 lrclk_div;
+	u8 sf, da;
+
+	if (!max9850->sysclk)
+		return -EINVAL;
+
+	/* lrclk_div = 2^22 * rate / iclk with iclk = mclk / sf */
+	sf = (snd_soc_component_read32(component, MAX9850_CLOCK) >> 2) + 1;
+	lrclk_div = (1 << 22);
+	lrclk_div *= params_rate(params);
+	lrclk_div *= sf;
+	do_div(lrclk_div, max9850->sysclk);
+
+	snd_soc_component_write(component, MAX9850_LRCLK_MSB, (lrclk_div >> 8) & 0x7f);
+	snd_soc_component_write(component, MAX9850_LRCLK_LSB, lrclk_div & 0xff);
+
+	switch (params_width(params)) {
+	case 16:
+		da = 0;
+		break;
+	case 20:
+		da = 0x2;
+		break;
+	case 24:
+		da = 0x3;
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, MAX9850_DIGITAL_AUDIO, 0x3, da);
+
+	return 0;
+}
+
+static int max9850_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct max9850_priv *max9850 = snd_soc_component_get_drvdata(component);
+
+	/* calculate mclk -> iclk divider */
+	if (freq <= 13000000)
+		snd_soc_component_write(component, MAX9850_CLOCK, 0x0);
+	else if (freq <= 26000000)
+		snd_soc_component_write(component, MAX9850_CLOCK, 0x4);
+	else if (freq <= 40000000)
+		snd_soc_component_write(component, MAX9850_CLOCK, 0x8);
+	else
+		return -EINVAL;
+
+	max9850->sysclk = freq;
+	return 0;
+}
+
+static int max9850_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u8 da = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		da |= MAX9850_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		da |= MAX9850_DLY;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		da |= MAX9850_RTJ;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		da |= MAX9850_BCINV | MAX9850_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		da |= MAX9850_BCINV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		da |= MAX9850_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set da */
+	snd_soc_component_write(component, MAX9850_DIGITAL_AUDIO, da);
+
+	return 0;
+}
+
+static int max9850_set_bias_level(struct snd_soc_component *component,
+				  enum snd_soc_bias_level level)
+{
+	struct max9850_priv *max9850 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regcache_sync(max9850->regmap);
+			if (ret) {
+				dev_err(component->dev,
+					"Failed to sync cache: %d\n", ret);
+				return ret;
+			}
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		break;
+	}
+	return 0;
+}
+
+#define MAX9850_RATES SNDRV_PCM_RATE_8000_48000
+
+#define MAX9850_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops max9850_dai_ops = {
+	.hw_params	= max9850_hw_params,
+	.set_sysclk	= max9850_set_dai_sysclk,
+	.set_fmt	= max9850_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver max9850_dai = {
+	.name = "max9850-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = MAX9850_RATES,
+		.formats = MAX9850_FORMATS
+	},
+	.ops = &max9850_dai_ops,
+};
+
+static int max9850_probe(struct snd_soc_component *component)
+{
+	/* enable zero-detect */
+	snd_soc_component_update_bits(component, MAX9850_GENERAL_PURPOSE, 1, 1);
+	/* enable slew-rate control */
+	snd_soc_component_update_bits(component, MAX9850_VOLUME, 0x40, 0x40);
+	/* set slew-rate 125ms */
+	snd_soc_component_update_bits(component, MAX9850_CHARGE_PUMP, 0xff, 0xc0);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_max9850 = {
+	.probe			= max9850_probe,
+	.set_bias_level		= max9850_set_bias_level,
+	.controls		= max9850_controls,
+	.num_controls		= ARRAY_SIZE(max9850_controls),
+	.dapm_widgets		= max9850_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max9850_dapm_widgets),
+	.dapm_routes		= max9850_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(max9850_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int max9850_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct max9850_priv *max9850;
+	int ret;
+
+	max9850 = devm_kzalloc(&i2c->dev, sizeof(struct max9850_priv),
+			       GFP_KERNEL);
+	if (max9850 == NULL)
+		return -ENOMEM;
+
+	max9850->regmap = devm_regmap_init_i2c(i2c, &max9850_regmap);
+	if (IS_ERR(max9850->regmap))
+		return PTR_ERR(max9850->regmap);
+
+	i2c_set_clientdata(i2c, max9850);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_max9850, &max9850_dai, 1);
+	return ret;
+}
+
+static const struct i2c_device_id max9850_i2c_id[] = {
+	{ "max9850", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max9850_i2c_id);
+
+static struct i2c_driver max9850_i2c_driver = {
+	.driver = {
+		.name = "max9850",
+	},
+	.probe = max9850_i2c_probe,
+	.id_table = max9850_i2c_id,
+};
+
+module_i2c_driver(max9850_i2c_driver);
+
+MODULE_AUTHOR("Christian Glindkamp <christian.glindkamp@taskit.de>");
+MODULE_DESCRIPTION("ASoC MAX9850 codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max9850.h b/sound/soc/codecs/max9850.h
new file mode 100644
index 0000000..72b1ddb
--- /dev/null
+++ b/sound/soc/codecs/max9850.h
@@ -0,0 +1,38 @@
+/*
+ * max9850.h  --  codec driver for max9850
+ *
+ * Copyright (C) 2011 taskit GmbH
+ * Author: Christian Glindkamp <christian.glindkamp@taskit.de>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef _MAX9850_H
+#define _MAX9850_H
+
+#define MAX9850_STATUSA			0x00
+#define MAX9850_STATUSB			0x01
+#define MAX9850_VOLUME			0x02
+#define MAX9850_GENERAL_PURPOSE		0x03
+#define MAX9850_INTERRUPT		0x04
+#define MAX9850_ENABLE			0x05
+#define MAX9850_CLOCK			0x06
+#define MAX9850_CHARGE_PUMP		0x07
+#define MAX9850_LRCLK_MSB		0x08
+#define MAX9850_LRCLK_LSB		0x09
+#define MAX9850_DIGITAL_AUDIO		0x0a
+
+#define MAX9850_CACHEREGNUM 11
+
+/* MAX9850_DIGITAL_AUDIO */
+#define MAX9850_MASTER			(1<<7)
+#define MAX9850_INV			(1<<6)
+#define MAX9850_BCINV			(1<<5)
+#define MAX9850_DLY			(1<<3)
+#define MAX9850_RTJ			(1<<2)
+
+#endif
diff --git a/sound/soc/codecs/max98504.c b/sound/soc/codecs/max98504.c
new file mode 100644
index 0000000..a7320e7
--- /dev/null
+++ b/sound/soc/codecs/max98504.c
@@ -0,0 +1,383 @@
+/*
+ * MAX98504 ALSA SoC Audio driver
+ *
+ * Copyright 2013 - 2014 Maxim Integrated Products
+ * Copyright 2016 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <sound/soc.h>
+
+#include "max98504.h"
+
+static const char * const max98504_supply_names[] = {
+	"DVDD",
+	"DIOVDD",
+	"PVDD",
+};
+#define MAX98504_NUM_SUPPLIES ARRAY_SIZE(max98504_supply_names)
+
+struct max98504_priv {
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[MAX98504_NUM_SUPPLIES];
+	unsigned int pcm_rx_channels;
+	bool brownout_enable;
+	unsigned int brownout_threshold;
+	unsigned int brownout_attenuation;
+	unsigned int brownout_attack_hold;
+	unsigned int brownout_timed_hold;
+	unsigned int brownout_release_rate;
+};
+
+static struct reg_default max98504_reg_defaults[] = {
+	{ 0x01,	0},
+	{ 0x02,	0},
+	{ 0x03,	0},
+	{ 0x04,	0},
+	{ 0x10, 0},
+	{ 0x11, 0},
+	{ 0x12, 0},
+	{ 0x13, 0},
+	{ 0x14, 0},
+	{ 0x15, 0},
+	{ 0x16, 0},
+	{ 0x17, 0},
+	{ 0x18, 0},
+	{ 0x19, 0},
+	{ 0x1A, 0},
+	{ 0x20, 0},
+	{ 0x21, 0},
+	{ 0x22, 0},
+	{ 0x23, 0},
+	{ 0x24, 0},
+	{ 0x25, 0},
+	{ 0x26, 0},
+	{ 0x27, 0},
+	{ 0x28, 0},
+	{ 0x30, 0},
+	{ 0x31, 0},
+	{ 0x32, 0},
+	{ 0x33, 0},
+	{ 0x34, 0},
+	{ 0x35, 0},
+	{ 0x36, 0},
+	{ 0x37, 0},
+	{ 0x38, 0},
+	{ 0x39, 0},
+	{ 0x40, 0},
+	{ 0x41, 0},
+};
+
+static bool max98504_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98504_INTERRUPT_STATUS:
+	case MAX98504_INTERRUPT_FLAGS:
+	case MAX98504_INTERRUPT_FLAG_CLEARS:
+	case MAX98504_WATCHDOG_CLEAR:
+	case MAX98504_GLOBAL_ENABLE:
+	case MAX98504_SOFTWARE_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max98504_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98504_SOFTWARE_RESET:
+	case MAX98504_WATCHDOG_CLEAR:
+	case MAX98504_INTERRUPT_FLAG_CLEARS:
+		return false;
+	default:
+		return true;
+	}
+}
+
+static int max98504_pcm_rx_ev(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+	struct max98504_priv *max98504 = snd_soc_component_get_drvdata(c);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_write(max98504->regmap, MAX98504_PCM_RX_ENABLE,
+			     max98504->pcm_rx_channels);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_write(max98504->regmap, MAX98504_PCM_RX_ENABLE, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static int max98504_component_probe(struct snd_soc_component *c)
+{
+	struct max98504_priv *max98504 = snd_soc_component_get_drvdata(c);
+	struct regmap *map = max98504->regmap;
+	int ret;
+
+	ret = regulator_bulk_enable(MAX98504_NUM_SUPPLIES, max98504->supplies);
+	if (ret < 0)
+		return ret;
+
+	regmap_write(map, MAX98504_SOFTWARE_RESET, 0x1);
+	msleep(20);
+
+	if (!max98504->brownout_enable)
+		return 0;
+
+	regmap_write(map, MAX98504_PVDD_BROWNOUT_ENABLE, 0x1);
+
+	regmap_write(map, MAX98504_PVDD_BROWNOUT_CONFIG_1,
+		     (max98504->brownout_threshold & 0x1f) << 3 |
+		     (max98504->brownout_attenuation & 0x3));
+
+	regmap_write(map, MAX98504_PVDD_BROWNOUT_CONFIG_2,
+		     max98504->brownout_attack_hold & 0xff);
+
+	regmap_write(map, MAX98504_PVDD_BROWNOUT_CONFIG_3,
+		     max98504->brownout_timed_hold & 0xff);
+
+	regmap_write(map, MAX98504_PVDD_BROWNOUT_CONFIG_4,
+		     max98504->brownout_release_rate & 0xff);
+
+	return 0;
+}
+
+static void max98504_component_remove(struct snd_soc_component *c)
+{
+	struct max98504_priv *max98504 = snd_soc_component_get_drvdata(c);
+
+	regulator_bulk_disable(MAX98504_NUM_SUPPLIES, max98504->supplies);
+}
+
+static const char *spk_source_mux_text[] = {
+	"PCM Monomix", "Analog In", "PDM Left", "PDM Right"
+};
+
+static const struct soc_enum spk_source_mux_enum =
+	SOC_ENUM_SINGLE(MAX98504_SPEAKER_SOURCE_SELECT,
+			0, ARRAY_SIZE(spk_source_mux_text),
+			spk_source_mux_text);
+
+static const struct snd_kcontrol_new spk_source_mux =
+	SOC_DAPM_ENUM("SPK Source", spk_source_mux_enum);
+
+static const struct snd_soc_dapm_route max98504_dapm_routes[] = {
+	{ "SPKOUT", NULL, "Global Enable" },
+	{ "SPK Source", "PCM Monomix", "DAC PCM" },
+	{ "SPK Source", "Analog In", "AIN" },
+	{ "SPK Source", "PDM Left", "DAC PDM" },
+	{ "SPK Source", "PDM Right", "DAC PDM" },
+};
+
+static const struct snd_soc_dapm_widget max98504_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("Global Enable", MAX98504_GLOBAL_ENABLE,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_INPUT("AIN"),
+	SND_SOC_DAPM_AIF_OUT("AIF2OUTL", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2OUTR", "AIF2 Capture", 1, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC_E("DAC PCM", NULL, SND_SOC_NOPM, 0, 0,
+		max98504_pcm_rx_ev,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_DAC("DAC PDM", NULL, MAX98504_PDM_RX_ENABLE, 0, 0),
+	SND_SOC_DAPM_MUX("SPK Source", SND_SOC_NOPM, 0, 0, &spk_source_mux),
+	SND_SOC_DAPM_REG(snd_soc_dapm_spk, "SPKOUT",
+		MAX98504_SPEAKER_ENABLE, 0, 1, 1, 0),
+};
+
+static int max98504_set_tdm_slot(struct snd_soc_dai *dai,
+		unsigned int tx_mask, unsigned int rx_mask,
+		int slots, int slot_width)
+{
+	struct max98504_priv *max98504 = snd_soc_dai_get_drvdata(dai);
+	struct regmap *map = max98504->regmap;
+
+
+	switch (dai->id) {
+	case MAX98504_DAI_ID_PCM:
+		regmap_write(map, MAX98504_PCM_TX_ENABLE, tx_mask);
+		max98504->pcm_rx_channels = rx_mask;
+		break;
+
+	case MAX98504_DAI_ID_PDM:
+		regmap_write(map, MAX98504_PDM_TX_ENABLE, tx_mask);
+		break;
+	default:
+		WARN_ON(1);
+	}
+
+	return 0;
+}
+static int max98504_set_channel_map(struct snd_soc_dai *dai,
+		unsigned int tx_num, unsigned int *tx_slot,
+		unsigned int rx_num, unsigned int *rx_slot)
+{
+	struct max98504_priv *max98504 = snd_soc_dai_get_drvdata(dai);
+	struct regmap *map = max98504->regmap;
+	unsigned int i, sources = 0;
+
+	for (i = 0; i < tx_num; i++)
+		if (tx_slot[i])
+			sources |= (1 << i);
+
+	switch (dai->id) {
+	case MAX98504_DAI_ID_PCM:
+		regmap_write(map, MAX98504_PCM_TX_CHANNEL_SOURCES,
+			     sources);
+		break;
+
+	case MAX98504_DAI_ID_PDM:
+		regmap_write(map, MAX98504_PDM_TX_CONTROL, sources);
+		break;
+	default:
+		WARN_ON(1);
+	}
+
+	regmap_write(map, MAX98504_MEASUREMENT_ENABLE, sources ? 0x3 : 0x01);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops max98504_dai_ops = {
+	.set_tdm_slot		= max98504_set_tdm_slot,
+	.set_channel_map	= max98504_set_channel_map,
+};
+
+#define MAX98504_FORMATS	(SNDRV_PCM_FMTBIT_S8|SNDRV_PCM_FMTBIT_S16_LE|\
+				SNDRV_PCM_FMTBIT_S24_LE|SNDRV_PCM_FMTBIT_S32_LE)
+#define MAX98504_PDM_RATES	(SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
+				SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100|\
+				SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_88200|\
+				SNDRV_PCM_RATE_96000)
+
+static struct snd_soc_dai_driver max98504_dai[] = {
+	/* TODO: Add the PCM interface definitions */
+	{
+		.name = "max98504-aif2",
+		.id = MAX98504_DAI_ID_PDM,
+		.playback = {
+			.stream_name	= "AIF2 Playback",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= MAX98504_PDM_RATES,
+			.formats	= MAX98504_FORMATS,
+		},
+		.capture = {
+			.stream_name	= "AIF2 Capture",
+			.channels_min	= 1,
+			.channels_max	= 2,
+			.rates		= MAX98504_PDM_RATES,
+			.formats	= MAX98504_FORMATS,
+		},
+		.ops = &max98504_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver max98504_component_driver = {
+	.probe			= max98504_component_probe,
+	.remove			= max98504_component_remove,
+	.dapm_widgets		= max98504_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98504_dapm_widgets),
+	.dapm_routes		= max98504_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(max98504_dapm_routes),
+};
+
+static const struct regmap_config max98504_regmap = {
+	.reg_bits		= 16,
+	.val_bits		= 8,
+	.max_register		= MAX98504_MAX_REGISTER,
+	.reg_defaults		= max98504_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(max98504_reg_defaults),
+	.volatile_reg		= max98504_volatile_register,
+	.readable_reg		= max98504_readable_register,
+	.cache_type		= REGCACHE_RBTREE,
+};
+
+static int max98504_i2c_probe(struct i2c_client *client,
+			      const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device_node *node = dev->of_node;
+	struct max98504_priv *max98504;
+	int i, ret;
+
+	max98504 = devm_kzalloc(dev, sizeof(*max98504), GFP_KERNEL);
+	if (!max98504)
+		return -ENOMEM;
+
+	if (node) {
+		if (!of_property_read_u32(node, "maxim,brownout-threshold",
+					&max98504->brownout_threshold))
+			max98504->brownout_enable = true;
+
+		of_property_read_u32(node, "maxim,brownout-attenuation",
+					&max98504->brownout_attenuation);
+		of_property_read_u32(node, "maxim,brownout-attack-hold-ms",
+					&max98504->brownout_attack_hold);
+		of_property_read_u32(node, "maxim,brownout-timed-hold-ms",
+					&max98504->brownout_timed_hold);
+		of_property_read_u32(node, "maxim,brownout-release-rate-ms",
+					&max98504->brownout_release_rate);
+	}
+
+	max98504->regmap = devm_regmap_init_i2c(client, &max98504_regmap);
+	if (IS_ERR(max98504->regmap)) {
+		ret = PTR_ERR(max98504->regmap);
+		dev_err(&client->dev, "regmap initialization failed: %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0; i < MAX98504_NUM_SUPPLIES; i++)
+		max98504->supplies[i].supply = max98504_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, MAX98504_NUM_SUPPLIES,
+				      max98504->supplies);
+	if (ret < 0)
+		return ret;
+
+	i2c_set_clientdata(client, max98504);
+
+	return devm_snd_soc_register_component(dev, &max98504_component_driver,
+				max98504_dai, ARRAY_SIZE(max98504_dai));
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id max98504_of_match[] = {
+	{ .compatible = "maxim,max98504" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, max98504_of_match);
+#endif
+
+static const struct i2c_device_id max98504_i2c_id[] = {
+	{ "max98504" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max98504_i2c_id);
+
+static struct i2c_driver max98504_i2c_driver = {
+	.driver = {
+		.name = "max98504",
+		.of_match_table = of_match_ptr(max98504_of_match),
+	},
+	.probe = max98504_i2c_probe,
+	.id_table = max98504_i2c_id,
+};
+module_i2c_driver(max98504_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC MAX98504 driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98504.h b/sound/soc/codecs/max98504.h
new file mode 100644
index 0000000..afbefad
--- /dev/null
+++ b/sound/soc/codecs/max98504.h
@@ -0,0 +1,59 @@
+/*
+ * MAX98504 ALSA SoC Audio driver
+ *
+ * Copyright 2011 - 2012 Maxim Integrated Products
+ * Copyright 2016 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef MAX98504_H_
+#define MAX98504_H_
+
+/*
+ * MAX98504 Register Definitions
+ */
+#define MAX98504_INTERRUPT_STATUS		0x01
+#define MAX98504_INTERRUPT_FLAGS		0x02
+#define MAX98504_INTERRUPT_ENABLE		0x03
+#define MAX98504_INTERRUPT_FLAG_CLEARS		0x04
+#define MAX98504_GPIO_ENABLE			0x10
+#define MAX98504_GPIO_CONFIG			0x11
+#define MAX98504_WATCHDOG_ENABLE		0x12
+#define MAX98504_WATCHDOG_CONFIG		0x13
+#define MAX98504_WATCHDOG_CLEAR			0x14
+#define MAX98504_CLOCK_MONITOR_ENABLE		0x15
+#define MAX98504_PVDD_BROWNOUT_ENABLE		0x16
+#define MAX98504_PVDD_BROWNOUT_CONFIG_1		0x17
+#define MAX98504_PVDD_BROWNOUT_CONFIG_2		0x18
+#define MAX98504_PVDD_BROWNOUT_CONFIG_3		0x19
+#define MAX98504_PVDD_BROWNOUT_CONFIG_4		0x1a
+#define MAX98504_PCM_RX_ENABLE			0x20
+#define MAX98504_PCM_TX_ENABLE			0x21
+#define MAX98504_PCM_TX_HIZ_CONTROL		0x22
+#define MAX98504_PCM_TX_CHANNEL_SOURCES		0x23
+#define MAX98504_PCM_MODE_CONFIG		0x24
+#define MAX98504_PCM_DSP_CONFIG			0x25
+#define MAX98504_PCM_CLOCK_SETUP		0x26
+#define MAX98504_PCM_SAMPLE_RATE_SETUP		0x27
+#define MAX98504_PCM_TO_SPEAKER_MONOMIX		0x28
+#define MAX98504_PDM_TX_ENABLE			0x30
+#define MAX98504_PDM_TX_HIZ_CONTROL		0x31
+#define MAX98504_PDM_TX_CONTROL			0x32
+#define MAX98504_PDM_RX_ENABLE			0x33
+#define MAX98504_SPEAKER_ENABLE			0x34
+#define MAX98504_SPEAKER_SOURCE_SELECT		0x35
+#define MAX98504_MEASUREMENT_ENABLE		0x36
+#define MAX98504_ANALOGUE_INPUT_GAIN		0x37
+#define MAX98504_TEMPERATURE_LIMIT_CONFIG	0x38
+#define MAX98504_GLOBAL_ENABLE			0x40
+#define MAX98504_SOFTWARE_RESET			0x41
+#define MAX98504_REV_ID				0x7fff
+
+#define MAX98504_MAX_REGISTER			0x7fff
+
+#define MAX98504_DAI_ID_PCM			1
+#define MAX98504_DAI_ID_PDM			2
+
+#endif /* MAX98504_H_ */
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c
new file mode 100644
index 0000000..de3d44e
--- /dev/null
+++ b/sound/soc/codecs/max9860.c
@@ -0,0 +1,745 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Driver for the MAX9860 Mono Audio Voice Codec
+//
+// https://datasheets.maximintegrated.com/en/ds/MAX9860.pdf
+//
+// The driver does not support sidetone since the DVST register field is
+// backwards with the mute near the maximum level instead of the minimum.
+//
+// Author: Peter Rosin <peda@axentia.s>
+//         Copyright 2016 Axentia Technologies
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/regulator/consumer.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#include "max9860.h"
+
+struct max9860_priv {
+	struct regmap *regmap;
+	struct regulator *dvddio;
+	struct notifier_block dvddio_nb;
+	u8 psclk;
+	unsigned long pclk_rate;
+	int fmt;
+};
+
+static int max9860_dvddio_event(struct notifier_block *nb,
+				unsigned long event, void *data)
+{
+	struct max9860_priv *max9860 = container_of(nb, struct max9860_priv,
+						    dvddio_nb);
+	if (event & REGULATOR_EVENT_DISABLE) {
+		regcache_mark_dirty(max9860->regmap);
+		regcache_cache_only(max9860->regmap, true);
+	}
+
+	return 0;
+}
+
+static const struct reg_default max9860_reg_defaults[] = {
+	{ MAX9860_PWRMAN,       0x00 },
+	{ MAX9860_INTEN,        0x00 },
+	{ MAX9860_SYSCLK,       0x00 },
+	{ MAX9860_AUDIOCLKHIGH, 0x00 },
+	{ MAX9860_AUDIOCLKLOW,  0x00 },
+	{ MAX9860_IFC1A,        0x00 },
+	{ MAX9860_IFC1B,        0x00 },
+	{ MAX9860_VOICEFLTR,    0x00 },
+	{ MAX9860_DACATTN,      0x00 },
+	{ MAX9860_ADCLEVEL,     0x00 },
+	{ MAX9860_DACGAIN,      0x00 },
+	{ MAX9860_MICGAIN,      0x00 },
+	{ MAX9860_MICADC,       0x00 },
+	{ MAX9860_NOISEGATE,    0x00 },
+};
+
+static bool max9860_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX9860_INTRSTATUS ... MAX9860_MICGAIN:
+	case MAX9860_MICADC ... MAX9860_PWRMAN:
+	case MAX9860_REVISION:
+		return true;
+	}
+
+	return false;
+}
+
+static bool max9860_writeable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX9860_INTEN ... MAX9860_MICGAIN:
+	case MAX9860_MICADC ... MAX9860_PWRMAN:
+		return true;
+	}
+
+	return false;
+}
+
+static bool max9860_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX9860_INTRSTATUS:
+	case MAX9860_MICREADBACK:
+		return true;
+	}
+
+	return false;
+}
+
+static bool max9860_precious(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX9860_INTRSTATUS:
+		return true;
+	}
+
+	return false;
+}
+
+static const struct regmap_config max9860_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.readable_reg = max9860_readable,
+	.writeable_reg = max9860_writeable,
+	.volatile_reg = max9860_volatile,
+	.precious_reg = max9860_precious,
+
+	.max_register = MAX9860_MAX_REGISTER,
+	.reg_defaults = max9860_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(max9860_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const DECLARE_TLV_DB_SCALE(dva_tlv, -9100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(dvg_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_RANGE(pam_tlv,
+	0, MAX9860_PAM_MAX - 1,             TLV_DB_SCALE_ITEM(-2000, 2000, 1),
+	MAX9860_PAM_MAX, MAX9860_PAM_MAX,   TLV_DB_SCALE_ITEM(3000, 0, 0));
+static const DECLARE_TLV_DB_SCALE(pgam_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(anth_tlv, -7600, 400, 1);
+static const DECLARE_TLV_DB_SCALE(agcth_tlv, -1800, 100, 0);
+
+static const char * const agchld_text[] = {
+	"AGC Disabled", "50ms", "100ms", "400ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(agchld_enum, MAX9860_MICADC,
+			    MAX9860_AGCHLD_SHIFT, agchld_text);
+
+static const char * const agcsrc_text[] = {
+	"Left ADC", "Left/Right ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(agcsrc_enum, MAX9860_MICADC,
+			    MAX9860_AGCSRC_SHIFT, agcsrc_text);
+
+static const char * const agcatk_text[] = {
+	"3ms", "12ms", "50ms", "200ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(agcatk_enum, MAX9860_MICADC,
+			    MAX9860_AGCATK_SHIFT, agcatk_text);
+
+static const char * const agcrls_text[] = {
+	"78ms", "156ms", "312ms", "625ms",
+	"1.25s", "2.5s", "5s", "10s"
+};
+
+static SOC_ENUM_SINGLE_DECL(agcrls_enum, MAX9860_MICADC,
+			    MAX9860_AGCRLS_SHIFT, agcrls_text);
+
+static const char * const filter_text[] = {
+	"Disabled",
+	"Elliptical HP 217Hz notch (16kHz)",
+	"Butterworth HP 500Hz (16kHz)",
+	"Elliptical HP 217Hz notch (8kHz)",
+	"Butterworth HP 500Hz (8kHz)",
+	"Butterworth HP 200Hz (48kHz)"
+};
+
+static SOC_ENUM_SINGLE_DECL(avflt_enum, MAX9860_VOICEFLTR,
+			    MAX9860_AVFLT_SHIFT, filter_text);
+
+static SOC_ENUM_SINGLE_DECL(dvflt_enum, MAX9860_VOICEFLTR,
+			    MAX9860_DVFLT_SHIFT, filter_text);
+
+static const struct snd_kcontrol_new max9860_controls[] = {
+SOC_SINGLE_TLV("Master Playback Volume", MAX9860_DACATTN,
+	       MAX9860_DVA_SHIFT, MAX9860_DVA_MUTE, 1, dva_tlv),
+SOC_SINGLE_TLV("DAC Gain Volume", MAX9860_DACGAIN,
+	       MAX9860_DVG_SHIFT, MAX9860_DVG_MAX, 0, dvg_tlv),
+SOC_DOUBLE_TLV("Line Capture Volume", MAX9860_ADCLEVEL,
+	       MAX9860_ADCLL_SHIFT, MAX9860_ADCRL_SHIFT, MAX9860_ADCxL_MIN, 1,
+	       adc_tlv),
+
+SOC_ENUM("AGC Hold Time", agchld_enum),
+SOC_ENUM("AGC/Noise Gate Source", agcsrc_enum),
+SOC_ENUM("AGC Attack Time", agcatk_enum),
+SOC_ENUM("AGC Release Time", agcrls_enum),
+
+SOC_SINGLE_TLV("Noise Gate Threshold Volume", MAX9860_NOISEGATE,
+	       MAX9860_ANTH_SHIFT, MAX9860_ANTH_MAX, 0, anth_tlv),
+SOC_SINGLE_TLV("AGC Signal Threshold Volume", MAX9860_NOISEGATE,
+	       MAX9860_AGCTH_SHIFT, MAX9860_AGCTH_MIN, 1, agcth_tlv),
+
+SOC_SINGLE_TLV("Mic PGA Volume", MAX9860_MICGAIN,
+	       MAX9860_PGAM_SHIFT, MAX9860_PGAM_MIN, 1, pgam_tlv),
+SOC_SINGLE_TLV("Mic Preamp Volume", MAX9860_MICGAIN,
+	       MAX9860_PAM_SHIFT, MAX9860_PAM_MAX, 0, pam_tlv),
+
+SOC_ENUM("ADC Filter", avflt_enum),
+SOC_ENUM("DAC Filter", dvflt_enum),
+};
+
+static const struct snd_soc_dapm_widget max9860_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("MICL"),
+SND_SOC_DAPM_INPUT("MICR"),
+
+SND_SOC_DAPM_ADC("ADCL", NULL, MAX9860_PWRMAN, MAX9860_ADCLEN_SHIFT, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, MAX9860_PWRMAN, MAX9860_ADCREN_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_DAC("DAC", NULL, MAX9860_PWRMAN, MAX9860_DACEN_SHIFT, 0),
+
+SND_SOC_DAPM_OUTPUT("OUT"),
+
+SND_SOC_DAPM_SUPPLY("Supply", SND_SOC_NOPM, 0, 0,
+		    NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_REGULATOR_SUPPLY("AVDD", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("DVDD", 0, 0),
+SND_SOC_DAPM_CLOCK_SUPPLY("mclk"),
+};
+
+static const struct snd_soc_dapm_route max9860_dapm_routes[] = {
+	{ "ADCL", NULL, "MICL" },
+	{ "ADCR", NULL, "MICR" },
+	{ "AIFOUTL", NULL, "ADCL" },
+	{ "AIFOUTR", NULL, "ADCR" },
+
+	{ "DAC", NULL, "AIFINL" },
+	{ "DAC", NULL, "AIFINR" },
+	{ "OUT", NULL, "DAC" },
+
+	{ "Supply", NULL, "AVDD" },
+	{ "Supply", NULL, "DVDD" },
+	{ "Supply", NULL, "mclk" },
+
+	{ "DAC", NULL, "Supply" },
+	{ "ADCL", NULL, "Supply" },
+	{ "ADCR", NULL, "Supply" },
+};
+
+static int max9860_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max9860_priv *max9860 = snd_soc_component_get_drvdata(component);
+	u8 master;
+	u8 ifc1a = 0;
+	u8 ifc1b = 0;
+	u8 sysclk = 0;
+	unsigned long n;
+	int ret;
+
+	dev_dbg(component->dev, "hw_params %u Hz, %u channels\n",
+		params_rate(params),
+		params_channels(params));
+
+	if (params_channels(params) == 2)
+		ifc1b |= MAX9860_ST;
+
+	switch (max9860->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		master = 0;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		master = MAX9860_MASTER;
+		break;
+	default:
+		return -EINVAL;
+	}
+	ifc1a |= master;
+
+	if (master) {
+		if (params_width(params) * params_channels(params) > 48)
+			ifc1b |= MAX9860_BSEL_64X;
+		else
+			ifc1b |= MAX9860_BSEL_48X;
+	}
+
+	switch (max9860->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		ifc1a |= MAX9860_DDLY;
+		ifc1b |= MAX9860_ADLY;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ifc1a |= MAX9860_WCI;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		if (params_width(params) != 16) {
+			dev_err(component->dev,
+				"DSP_A works for 16 bits per sample only.\n");
+			return -EINVAL;
+		}
+		ifc1a |= MAX9860_DDLY | MAX9860_WCI | MAX9860_HIZ | MAX9860_TDM;
+		ifc1b |= MAX9860_ADLY;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		if (params_width(params) != 16) {
+			dev_err(component->dev,
+				"DSP_B works for 16 bits per sample only.\n");
+			return -EINVAL;
+		}
+		ifc1a |= MAX9860_WCI | MAX9860_HIZ | MAX9860_TDM;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (max9860->fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		switch (max9860->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+		case SND_SOC_DAIFMT_DSP_A:
+		case SND_SOC_DAIFMT_DSP_B:
+			return -EINVAL;
+		}
+		ifc1a ^= MAX9860_WCI;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		switch (max9860->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+		case SND_SOC_DAIFMT_DSP_A:
+		case SND_SOC_DAIFMT_DSP_B:
+			return -EINVAL;
+		}
+		ifc1a ^= MAX9860_WCI;
+		/* fall through */
+	case SND_SOC_DAIFMT_IB_NF:
+		ifc1a ^= MAX9860_DBCI;
+		ifc1b ^= MAX9860_ABCI;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dev_dbg(component->dev, "IFC1A  %02x\n", ifc1a);
+	ret = regmap_write(max9860->regmap, MAX9860_IFC1A, ifc1a);
+	if (ret) {
+		dev_err(component->dev, "Failed to set IFC1A: %d\n", ret);
+		return ret;
+	}
+	dev_dbg(component->dev, "IFC1B  %02x\n", ifc1b);
+	ret = regmap_write(max9860->regmap, MAX9860_IFC1B, ifc1b);
+	if (ret) {
+		dev_err(component->dev, "Failed to set IFC1B: %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * Check if Integer Clock Mode is possible, but avoid it in slave mode
+	 * since we then do not know if lrclk is derived from pclk and the
+	 * datasheet mentions that the frequencies have to match exactly in
+	 * order for this to work.
+	 */
+	if (params_rate(params) == 8000 || params_rate(params) == 16000) {
+		if (master) {
+			switch (max9860->pclk_rate) {
+			case 12000000:
+				sysclk = MAX9860_FREQ_12MHZ;
+				break;
+			case 13000000:
+				sysclk = MAX9860_FREQ_13MHZ;
+				break;
+			case 19200000:
+				sysclk = MAX9860_FREQ_19_2MHZ;
+				break;
+			default:
+				/*
+				 * Integer Clock Mode not possible. Leave
+				 * sysclk at zero and fall through to the
+				 * code below for PLL mode.
+				 */
+				break;
+			}
+
+			if (sysclk && params_rate(params) == 16000)
+				sysclk |= MAX9860_16KHZ;
+		}
+	}
+
+	/*
+	 * Largest possible n:
+	 *    65536 * 96 * 48kHz / 10MHz -> 30199
+	 * Smallest possible n:
+	 *    65536 * 96 *  8kHz / 20MHz -> 2517
+	 * Both fit nicely in the available 15 bits, no need to apply any mask.
+	 */
+	n = DIV_ROUND_CLOSEST_ULL(65536ULL * 96 * params_rate(params),
+				  max9860->pclk_rate);
+
+	if (!sysclk) {
+		/* PLL mode */
+		if (params_rate(params) > 24000)
+			sysclk |= MAX9860_16KHZ;
+
+		if (!master)
+			n |= 1; /* trigger rapid pll lock mode */
+	}
+
+	sysclk |= max9860->psclk;
+	dev_dbg(component->dev, "SYSCLK %02x\n", sysclk);
+	ret = regmap_write(max9860->regmap,
+			   MAX9860_SYSCLK, sysclk);
+	if (ret) {
+		dev_err(component->dev, "Failed to set SYSCLK: %d\n", ret);
+		return ret;
+	}
+	dev_dbg(component->dev, "N %lu\n", n);
+	ret = regmap_write(max9860->regmap,
+			   MAX9860_AUDIOCLKHIGH, n >> 8);
+	if (ret) {
+		dev_err(component->dev, "Failed to set NHI: %d\n", ret);
+		return ret;
+	}
+	ret = regmap_write(max9860->regmap,
+			   MAX9860_AUDIOCLKLOW, n & 0xff);
+	if (ret) {
+		dev_err(component->dev, "Failed to set NLO: %d\n", ret);
+		return ret;
+	}
+
+	if (!master) {
+		dev_dbg(component->dev, "Enable PLL\n");
+		ret = regmap_update_bits(max9860->regmap, MAX9860_AUDIOCLKHIGH,
+					 MAX9860_PLL, MAX9860_PLL);
+		if (ret) {
+			dev_err(component->dev, "Failed to enable PLL: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int max9860_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max9860_priv *max9860 = snd_soc_component_get_drvdata(component);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+	case SND_SOC_DAIFMT_CBS_CFS:
+		max9860->fmt = fmt;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct snd_soc_dai_ops max9860_dai_ops = {
+	.hw_params = max9860_hw_params,
+	.set_fmt = max9860_set_fmt,
+};
+
+static struct snd_soc_dai_driver max9860_dai = {
+	.name = "max9860-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_CONTINUOUS,
+		.rate_min = 8000,
+		.rate_max = 48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			   SNDRV_PCM_FMTBIT_S24_LE |
+			   SNDRV_PCM_FMTBIT_S32_LE,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_CONTINUOUS,
+		.rate_min = 8000,
+		.rate_max = 48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			   SNDRV_PCM_FMTBIT_S24_LE |
+			   SNDRV_PCM_FMTBIT_S32_LE,
+	},
+	.ops = &max9860_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int max9860_set_bias_level(struct snd_soc_component *component,
+				  enum snd_soc_bias_level level)
+{
+	struct max9860_priv *max9860 = dev_get_drvdata(component->dev);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		ret = regmap_update_bits(max9860->regmap, MAX9860_PWRMAN,
+					 MAX9860_SHDN, MAX9860_SHDN);
+		if (ret) {
+			dev_err(component->dev, "Failed to remove SHDN: %d\n",
+				ret);
+			return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		ret = regmap_update_bits(max9860->regmap, MAX9860_PWRMAN,
+					 MAX9860_SHDN, 0);
+		if (ret) {
+			dev_err(component->dev, "Failed to request SHDN: %d\n",
+				ret);
+			return ret;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver max9860_component_driver = {
+	.set_bias_level		= max9860_set_bias_level,
+	.controls		= max9860_controls,
+	.num_controls		= ARRAY_SIZE(max9860_controls),
+	.dapm_widgets		= max9860_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max9860_dapm_widgets),
+	.dapm_routes		= max9860_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(max9860_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+#ifdef CONFIG_PM
+static int max9860_suspend(struct device *dev)
+{
+	struct max9860_priv *max9860 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regmap_update_bits(max9860->regmap, MAX9860_SYSCLK,
+				 MAX9860_PSCLK, MAX9860_PSCLK_OFF);
+	if (ret) {
+		dev_err(dev, "Failed to disable clock: %d\n", ret);
+		return ret;
+	}
+
+	regulator_disable(max9860->dvddio);
+
+	return 0;
+}
+
+static int max9860_resume(struct device *dev)
+{
+	struct max9860_priv *max9860 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_enable(max9860->dvddio);
+	if (ret) {
+		dev_err(dev, "Failed to enable DVDDIO: %d\n", ret);
+		return ret;
+	}
+
+	regcache_cache_only(max9860->regmap, false);
+	ret = regcache_sync(max9860->regmap);
+	if (ret) {
+		dev_err(dev, "Failed to sync cache: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_update_bits(max9860->regmap, MAX9860_SYSCLK,
+				 MAX9860_PSCLK, max9860->psclk);
+	if (ret) {
+		dev_err(dev, "Failed to enable clock: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops max9860_pm_ops = {
+	SET_RUNTIME_PM_OPS(max9860_suspend, max9860_resume, NULL)
+};
+
+static int max9860_probe(struct i2c_client *i2c)
+{
+	struct device *dev = &i2c->dev;
+	struct max9860_priv *max9860;
+	int ret;
+	struct clk *mclk;
+	unsigned long mclk_rate;
+	int i;
+	int intr;
+
+	max9860 = devm_kzalloc(dev, sizeof(struct max9860_priv), GFP_KERNEL);
+	if (!max9860)
+		return -ENOMEM;
+
+	max9860->dvddio = devm_regulator_get(dev, "DVDDIO");
+	if (IS_ERR(max9860->dvddio)) {
+		ret = PTR_ERR(max9860->dvddio);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get DVDDIO supply: %d\n", ret);
+		return ret;
+	}
+
+	max9860->dvddio_nb.notifier_call = max9860_dvddio_event;
+
+	ret = regulator_register_notifier(max9860->dvddio, &max9860->dvddio_nb);
+	if (ret)
+		dev_err(dev, "Failed to register DVDDIO notifier: %d\n", ret);
+
+	ret = regulator_enable(max9860->dvddio);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable DVDDIO: %d\n", ret);
+		return ret;
+	}
+
+	max9860->regmap = devm_regmap_init_i2c(i2c, &max9860_regmap);
+	if (IS_ERR(max9860->regmap)) {
+		ret = PTR_ERR(max9860->regmap);
+		goto err_regulator;
+	}
+
+	dev_set_drvdata(dev, max9860);
+
+	/*
+	 * mclk has to be in the 10MHz to 60MHz range.
+	 * psclk is used to scale mclk into pclk so that
+	 * pclk is in the 10MHz to 20MHz range.
+	 */
+	mclk = clk_get(dev, "mclk");
+
+	if (IS_ERR(mclk)) {
+		ret = PTR_ERR(mclk);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get MCLK: %d\n", ret);
+		goto err_regulator;
+	}
+
+	mclk_rate = clk_get_rate(mclk);
+	clk_put(mclk);
+
+	if (mclk_rate > 60000000 || mclk_rate < 10000000) {
+		dev_err(dev, "Bad mclk %luHz (needs 10MHz - 60MHz)\n",
+			mclk_rate);
+		ret = -EINVAL;
+		goto err_regulator;
+	}
+	if (mclk_rate >= 40000000)
+		max9860->psclk = 3;
+	else if (mclk_rate >= 20000000)
+		max9860->psclk = 2;
+	else
+		max9860->psclk = 1;
+	max9860->pclk_rate = mclk_rate >> (max9860->psclk - 1);
+	max9860->psclk <<= MAX9860_PSCLK_SHIFT;
+	dev_dbg(dev, "mclk %lu pclk %lu\n", mclk_rate, max9860->pclk_rate);
+
+	regcache_cache_bypass(max9860->regmap, true);
+	for (i = 0; i < max9860_regmap.num_reg_defaults; ++i) {
+		ret = regmap_write(max9860->regmap,
+				   max9860_regmap.reg_defaults[i].reg,
+				   max9860_regmap.reg_defaults[i].def);
+		if (ret) {
+			dev_err(dev, "Failed to initialize register %u: %d\n",
+				max9860_regmap.reg_defaults[i].reg, ret);
+			goto err_regulator;
+		}
+	}
+	regcache_cache_bypass(max9860->regmap, false);
+
+	ret = regmap_read(max9860->regmap, MAX9860_INTRSTATUS, &intr);
+	if (ret) {
+		dev_err(dev, "Failed to clear INTRSTATUS: %d\n", ret);
+		goto err_regulator;
+	}
+
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	pm_runtime_idle(dev);
+
+	ret = devm_snd_soc_register_component(dev, &max9860_component_driver,
+					      &max9860_dai, 1);
+	if (ret) {
+		dev_err(dev, "Failed to register CODEC: %d\n", ret);
+		goto err_pm;
+	}
+
+	return 0;
+
+err_pm:
+	pm_runtime_disable(dev);
+err_regulator:
+	regulator_disable(max9860->dvddio);
+	return ret;
+}
+
+static int max9860_remove(struct i2c_client *i2c)
+{
+	struct device *dev = &i2c->dev;
+	struct max9860_priv *max9860 = dev_get_drvdata(dev);
+
+	pm_runtime_disable(dev);
+	regulator_disable(max9860->dvddio);
+	return 0;
+}
+
+static const struct i2c_device_id max9860_i2c_id[] = {
+	{ "max9860", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max9860_i2c_id);
+
+static const struct of_device_id max9860_of_match[] = {
+	{ .compatible = "maxim,max9860", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max9860_of_match);
+
+static struct i2c_driver max9860_i2c_driver = {
+	.probe_new      = max9860_probe,
+	.remove         = max9860_remove,
+	.id_table       = max9860_i2c_id,
+	.driver         = {
+		.name           = "max9860",
+		.of_match_table = max9860_of_match,
+		.pm             = &max9860_pm_ops,
+	},
+};
+
+module_i2c_driver(max9860_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC MAX9860 Mono Audio Voice Codec driver");
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/max9860.h b/sound/soc/codecs/max9860.h
new file mode 100644
index 0000000..e07b905
--- /dev/null
+++ b/sound/soc/codecs/max9860.h
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Driver for the MAX9860 Mono Audio Voice Codec
+ *
+ * Author: Peter Rosin <peda@axentia.s>
+ *         Copyright 2016 Axentia Technologies
+ */
+
+#ifndef _SND_SOC_MAX9860
+#define _SND_SOC_MAX9860
+
+#define MAX9860_INTRSTATUS   0x00
+#define MAX9860_MICREADBACK  0x01
+#define MAX9860_INTEN        0x02
+#define MAX9860_SYSCLK       0x03
+#define MAX9860_AUDIOCLKHIGH 0x04
+#define MAX9860_AUDIOCLKLOW  0x05
+#define MAX9860_IFC1A        0x06
+#define MAX9860_IFC1B        0x07
+#define MAX9860_VOICEFLTR    0x08
+#define MAX9860_DACATTN      0x09
+#define MAX9860_ADCLEVEL     0x0a
+#define MAX9860_DACGAIN      0x0b
+#define MAX9860_MICGAIN      0x0c
+#define MAX9860_RESERVED     0x0d
+#define MAX9860_MICADC       0x0e
+#define MAX9860_NOISEGATE    0x0f
+#define MAX9860_PWRMAN       0x10
+#define MAX9860_REVISION     0xff
+
+#define MAX9860_MAX_REGISTER 0xff
+
+/* INTRSTATUS */
+#define MAX9860_CLD          0x80
+#define MAX9860_SLD          0x40
+#define MAX9860_ULK          0x20
+
+/* MICREADBACK */
+#define MAX9860_NG           0xe0
+#define MAX9860_AGC          0x1f
+
+/* INTEN */
+#define MAX9860_ICLD         0x80
+#define MAX9860_ISLD         0x40
+#define MAX9860_IULK         0x20
+
+/* SYSCLK */
+#define MAX9860_PSCLK        0x30
+#define MAX9860_PSCLK_OFF    0x00
+#define MAX9860_PSCLK_SHIFT  4
+#define MAX9860_FREQ         0x06
+#define MAX9860_FREQ_NORMAL  0x00
+#define MAX9860_FREQ_12MHZ   0x02
+#define MAX9860_FREQ_13MHZ   0x04
+#define MAX9860_FREQ_19_2MHZ 0x06
+#define MAX9860_16KHZ        0x01
+
+/* AUDIOCLKHIGH */
+#define MAX9860_PLL          0x80
+#define MAX9860_NHI          0x7f
+
+/* AUDIOCLKLOW */
+#define MAX9860_NLO          0xff
+
+/* IFC1A */
+#define MAX9860_MASTER       0x80
+#define MAX9860_WCI          0x40
+#define MAX9860_DBCI         0x20
+#define MAX9860_DDLY         0x10
+#define MAX9860_HIZ          0x08
+#define MAX9860_TDM          0x04
+
+/* IFC1B */
+#define MAX9860_ABCI         0x20
+#define MAX9860_ADLY         0x10
+#define MAX9860_ST           0x08
+#define MAX9860_BSEL         0x07
+#define MAX9860_BSEL_OFF     0x00
+#define MAX9860_BSEL_64X     0x01
+#define MAX9860_BSEL_48X     0x02
+#define MAX9860_BSEL_PCLK_2  0x04
+#define MAX9860_BSEL_PCLK_4  0x05
+#define MAX9860_BSEL_PCLK_8  0x06
+#define MAX9860_BSEL_PCLK_16 0x07
+
+/* VOICEFLTR */
+#define MAX9860_AVFLT        0xf0
+#define MAX9860_AVFLT_SHIFT  4
+#define MAX9860_AVFLT_COUNT  6
+#define MAX9860_DVFLT        0x0f
+#define MAX9860_DVFLT_SHIFT  0
+#define MAX9860_DVFLT_COUNT  6
+
+/* DACATTN */
+#define MAX9860_DVA          0xfe
+#define MAX9860_DVA_SHIFT    1
+#define MAX9860_DVA_MUTE     0x5e
+
+/* ADCLEVEL */
+#define MAX9860_ADCRL        0xf0
+#define MAX9860_ADCRL_SHIFT  4
+#define MAX9860_ADCLL        0x0f
+#define MAX9860_ADCLL_SHIFT  0
+#define MAX9860_ADCxL_MIN    15
+
+/* DACGAIN */
+#define MAX9860_DVG          0x60
+#define MAX9860_DVG_SHIFT    5
+#define MAX9860_DVG_MAX      3
+#define MAX9860_DVST         0x1f
+#define MAX9860_DVST_SHIFT   0
+#define MAX9860_DVST_MIN     31
+
+/* MICGAIN */
+#define MAX9860_PAM          0x60
+#define MAX9860_PAM_SHIFT    5
+#define MAX9860_PAM_MAX      3
+#define MAX9860_PGAM         0x1f
+#define MAX9860_PGAM_SHIFT   0
+#define MAX9860_PGAM_MIN     20
+
+/* MICADC */
+#define MAX9860_AGCSRC       0x80
+#define MAX9860_AGCSRC_SHIFT 7
+#define MAX9860_AGCSRC_COUNT 2
+#define MAX9860_AGCRLS       0x70
+#define MAX9860_AGCRLS_SHIFT 4
+#define MAX9860_AGCRLS_COUNT 8
+#define MAX9860_AGCATK       0x0c
+#define MAX9860_AGCATK_SHIFT 2
+#define MAX9860_AGCATK_COUNT 4
+#define MAX9860_AGCHLD       0x03
+#define MAX9860_AGCHLD_OFF   0x00
+#define MAX9860_AGCHLD_SHIFT 0
+#define MAX9860_AGCHLD_COUNT 4
+
+/* NOISEGATE */
+#define MAX9860_ANTH         0xf0
+#define MAX9860_ANTH_SHIFT   4
+#define MAX9860_ANTH_MAX     15
+#define MAX9860_AGCTH        0x0f
+#define MAX9860_AGCTH_SHIFT  0
+#define MAX9860_AGCTH_MIN    15
+
+/* PWRMAN */
+#define MAX9860_SHDN         0x80
+#define MAX9860_DACEN        0x08
+#define MAX9860_DACEN_SHIFT  3
+#define MAX9860_ADCLEN       0x02
+#define MAX9860_ADCLEN_SHIFT 1
+#define MAX9860_ADCREN       0x01
+#define MAX9860_ADCREN_SHIFT 0
+
+#endif /* _SND_SOC_MAX9860 */
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
new file mode 100644
index 0000000..4ea3287
--- /dev/null
+++ b/sound/soc/codecs/max9867.c
@@ -0,0 +1,539 @@
+/*
+ * max9867.c -- max9867 ALSA SoC Audio driver
+ *
+ * Copyright 2013-15 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "max9867.h"
+
+static const char *const max9867_spmode[] = {
+	"Stereo Diff", "Mono Diff",
+	"Stereo Cap", "Mono Cap",
+	"Stereo Single", "Mono Single",
+	"Stereo Single Fast", "Mono Single Fast"
+};
+static const char *const max9867_sidetone_text[] = {
+	"None", "Left", "Right", "LeftRight", "LeftRightDiv2",
+};
+static const char *const max9867_filter_text[] = {"IIR", "FIR"};
+
+static SOC_ENUM_SINGLE_DECL(max9867_filter, MAX9867_CODECFLTR, 7,
+	max9867_filter_text);
+static SOC_ENUM_SINGLE_DECL(max9867_spkmode, MAX9867_MODECONFIG, 0,
+	max9867_spmode);
+static SOC_ENUM_SINGLE_DECL(max9867_sidetone, MAX9867_DACGAIN, 6,
+	max9867_sidetone_text);
+static DECLARE_TLV_DB_SCALE(max9860_capture_tlv, -600, 200, 0);
+static DECLARE_TLV_DB_SCALE(max9860_mic_tlv, 2000, 100, 1);
+static DECLARE_TLV_DB_SCALE(max9860_adc_left_tlv, -1200, 100, 1);
+static DECLARE_TLV_DB_SCALE(max9860_adc_right_tlv, -1200, 100, 1);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max98088_micboost_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+	2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
+);
+
+static const struct snd_kcontrol_new max9867_snd_controls[] = {
+	SOC_DOUBLE_R("Master Playback Volume", MAX9867_LEFTVOL,
+				MAX9867_RIGHTVOL, 0, 63, 1),
+	SOC_DOUBLE_R_TLV("Capture Volume", MAX9867_LEFTMICGAIN,
+			MAX9867_RIGHTMICGAIN,
+			0, 15, 1, max9860_capture_tlv),
+	SOC_DOUBLE_R_TLV("Mic Volume", MAX9867_LEFTMICGAIN,
+			MAX9867_RIGHTMICGAIN, 0, 31, 1, max9860_mic_tlv),
+	SOC_DOUBLE_R_TLV("Mic Boost Volume", MAX9867_LEFTMICGAIN,
+			MAX9867_RIGHTMICGAIN, 5, 3, 0, max98088_micboost_tlv),
+	SOC_ENUM("Digital Sidetone Src", max9867_sidetone),
+	SOC_SINGLE("Sidetone Volume", MAX9867_DACGAIN, 0, 31, 1),
+	SOC_SINGLE("DAC Volume", MAX9867_DACLEVEL, 4, 3, 0),
+	SOC_SINGLE("DAC Attenuation", MAX9867_DACLEVEL, 0, 15, 1),
+	SOC_SINGLE_TLV("ADC Left Volume", MAX9867_ADCLEVEL,
+			4, 15, 1, max9860_adc_left_tlv),
+	SOC_SINGLE_TLV("ADC Right Volume", MAX9867_ADCLEVEL,
+			0, 15, 1, max9860_adc_right_tlv),
+	SOC_ENUM("Speaker Mode", max9867_spkmode),
+	SOC_SINGLE("Volume Smoothing Switch", MAX9867_MODECONFIG, 6, 1, 0),
+	SOC_SINGLE("ZCD Switch", MAX9867_MODECONFIG, 5, 1, 0),
+	SOC_ENUM("DSP Filter", max9867_filter),
+};
+
+static const char *const max9867_mux[] = {"None", "Mic", "Line", "Mic_Line"};
+
+static SOC_ENUM_SINGLE_DECL(max9867_mux_enum,
+	MAX9867_INPUTCONFIG, MAX9867_INPUT_SHIFT,
+	max9867_mux);
+
+static const struct snd_kcontrol_new max9867_dapm_mux_controls =
+	SOC_DAPM_ENUM("Route", max9867_mux_enum);
+
+static const struct snd_kcontrol_new max9867_left_dapm_control =
+	SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 6, 1, 0);
+static const struct snd_kcontrol_new max9867_right_dapm_control =
+	SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 5, 1, 0);
+static const struct snd_kcontrol_new max9867_line_dapm_control =
+	SOC_DAPM_SINGLE("Switch", MAX9867_LEFTLINELVL, 6, 1, 1);
+
+static const struct snd_soc_dapm_widget max9867_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("Left DAC", NULL, MAX9867_PWRMAN, 3, 0),
+	SND_SOC_DAPM_DAC("Right DAC", NULL, MAX9867_PWRMAN, 2, 0),
+	SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("HPOUT"),
+
+	SND_SOC_DAPM_AIF_IN("DAI_IN", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("Left ADC", "HiFi Capture", MAX9867_PWRMAN, 1, 0),
+	SND_SOC_DAPM_ADC("Right ADC", "HiFi Capture", MAX9867_PWRMAN, 0, 0),
+	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+		&max9867_dapm_mux_controls),
+
+	SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SWITCH("Left Line", MAX9867_LEFTLINELVL, 6, 1,
+		&max9867_left_dapm_control),
+	SND_SOC_DAPM_SWITCH("Right Line", MAX9867_RIGTHLINELVL, 6, 1,
+		&max9867_right_dapm_control),
+	SND_SOC_DAPM_SWITCH("Line Mixer", SND_SOC_NOPM, 0, 0,
+		&max9867_line_dapm_control),
+	SND_SOC_DAPM_INPUT("LINE_IN"),
+};
+
+static const struct snd_soc_dapm_route max9867_audio_map[] = {
+	{"Left DAC", NULL, "DAI_OUT"},
+	{"Right DAC", NULL, "DAI_OUT"},
+	{"Output Mixer", NULL, "Left DAC"},
+	{"Output Mixer", NULL, "Right DAC"},
+	{"HPOUT", NULL, "Output Mixer"},
+
+	{"Left ADC", NULL, "DAI_IN"},
+	{"Right ADC", NULL, "DAI_IN"},
+	{"Input Mixer", NULL, "Left ADC"},
+	{"Input Mixer", NULL, "Right ADC"},
+	{"Input Mux", "Line", "Input Mixer"},
+	{"Input Mux", "Mic", "Input Mixer"},
+	{"Input Mux", "Mic_Line", "Input Mixer"},
+	{"Right Line", "Switch", "Input Mux"},
+	{"Left Line", "Switch", "Input Mux"},
+	{"LINE_IN", NULL, "Left Line"},
+	{"LINE_IN", NULL, "Right Line"},
+};
+
+enum rates {
+	pcm_rate_8, pcm_rate_16, pcm_rate_24,
+	pcm_rate_32, pcm_rate_44,
+	pcm_rate_48, max_pcm_rate,
+};
+
+static const struct ni_div_rates {
+	u32 mclk;
+	u16 ni[max_pcm_rate];
+} ni_div[] = {
+	{11289600, {0x116A, 0x22D4, 0x343F, 0x45A9, 0x6000, 0x687D} },
+	{12000000, {0x1062, 0x20C5, 0x3127, 0x4189, 0x5A51, 0x624E} },
+	{12288000, {0x1000, 0x2000, 0x3000, 0x4000, 0x5833, 0x6000} },
+	{13000000, {0x0F20, 0x1E3F, 0x2D5F, 0x3C7F, 0x535F, 0x5ABE} },
+	{19200000, {0x0A3D, 0x147B, 0x1EB8, 0x28F6, 0x3873, 0x3D71} },
+	{24000000, {0x1062, 0x20C5, 0x1893, 0x4189, 0x5A51, 0x624E} },
+	{26000000, {0x0F20, 0x1E3F, 0x16AF, 0x3C7F, 0x535F, 0x5ABE} },
+	{27000000, {0x0E90, 0x1D21, 0x15D8, 0x3A41, 0x5048, 0x5762} },
+};
+
+static inline int get_ni_value(int mclk, int rate)
+{
+	int i, ret = 0;
+
+	/* find the closest rate index*/
+	for (i = 0; i < ARRAY_SIZE(ni_div); i++) {
+		if (ni_div[i].mclk >= mclk)
+			break;
+	}
+	if (i == ARRAY_SIZE(ni_div))
+		return -EINVAL;
+
+	switch (rate) {
+	case 8000:
+		return ni_div[i].ni[pcm_rate_8];
+	case 16000:
+		return ni_div[i].ni[pcm_rate_16];
+	case 32000:
+		return ni_div[i].ni[pcm_rate_32];
+	case 44100:
+		return ni_div[i].ni[pcm_rate_44];
+	case 48000:
+		return ni_div[i].ni[pcm_rate_48];
+	default:
+		pr_err("%s wrong rate %d\n", __func__, rate);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
+	unsigned int ni_h, ni_l;
+	int value;
+
+	value = get_ni_value(max9867->sysclk, params_rate(params));
+	if (value < 0)
+		return value;
+
+	ni_h = (0xFF00 & value) >> 8;
+	ni_l = 0x00FF & value;
+	/* set up the ni value */
+	regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
+		MAX9867_NI_HIGH_MASK, ni_h);
+	regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
+		MAX9867_NI_LOW_MASK, ni_l);
+	if (!max9867->master) {
+		/*
+		 * digital pll locks on to any externally supplied LRCLK signal
+		 * and also enable rapid lock mode.
+		 */
+		regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
+			MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK);
+		regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
+			MAX9867_PLL, MAX9867_PLL);
+	} else {
+		unsigned long int bclk_rate, pclk_bclk_ratio;
+		int bclk_value;
+
+		bclk_rate = params_rate(params) * 2 * params_width(params);
+		pclk_bclk_ratio = max9867->pclk/bclk_rate;
+		switch (params_width(params)) {
+		case 8:
+		case 16:
+			switch (pclk_bclk_ratio) {
+			case 2:
+				bclk_value = MAX9867_IFC1B_PCLK_2;
+				break;
+			case 4:
+				bclk_value = MAX9867_IFC1B_PCLK_4;
+				break;
+			case 8:
+				bclk_value = MAX9867_IFC1B_PCLK_8;
+				break;
+			case 16:
+				bclk_value = MAX9867_IFC1B_PCLK_16;
+				break;
+			default:
+				dev_err(component->dev,
+					"unsupported sampling rate\n");
+				return -EINVAL;
+			}
+			break;
+		case 24:
+			bclk_value = MAX9867_IFC1B_24BIT;
+			break;
+		case 32:
+			bclk_value = MAX9867_IFC1B_32BIT;
+			break;
+		default:
+			dev_err(component->dev, "unsupported sampling rate\n");
+			return -EINVAL;
+		}
+		regmap_update_bits(max9867->regmap, MAX9867_IFC1B,
+			MAX9867_IFC1B_BCLK_MASK, bclk_value);
+	}
+	return 0;
+}
+
+static int max9867_prepare(struct snd_pcm_substream *substream,
+			 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
+
+	regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
+		MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK);
+	return 0;
+}
+
+static int max9867_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
+
+	if (mute)
+		regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
+			MAX9867_DAC_MUTE_MASK, MAX9867_DAC_MUTE_MASK);
+	else
+		regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
+			MAX9867_DAC_MUTE_MASK, 0);
+	return 0;
+}
+
+static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
+	int value = 0;
+
+	/* Set the prescaler based on the master clock frequency*/
+	if (freq >= 10000000 && freq <= 20000000) {
+		value |= MAX9867_PSCLK_10_20;
+		max9867->pclk =  freq;
+	} else if (freq >= 20000000 && freq <= 40000000) {
+		value |= MAX9867_PSCLK_20_40;
+		max9867->pclk =  freq/2;
+	} else if (freq >= 40000000 && freq <= 60000000) {
+		value |= MAX9867_PSCLK_40_60;
+		max9867->pclk =  freq/4;
+	} else {
+		dev_err(component->dev,
+			"Invalid clock frequency %uHz (required 10-60MHz)\n",
+			freq);
+		return -EINVAL;
+	}
+	value = value << MAX9867_PSCLK_SHIFT;
+	max9867->sysclk = freq;
+	/* exact integer mode is not supported */
+	value &= ~MAX9867_FREQ_MASK;
+	regmap_update_bits(max9867->regmap, MAX9867_SYSCLK,
+			MAX9867_PSCLK_MASK, value);
+	return 0;
+}
+
+static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
+	u8 iface1A = 0, iface1B = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		max9867->master = 1;
+		iface1A |= MAX9867_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		max9867->master = 0;
+		iface1A &= ~MAX9867_MASTER;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface1A |= MAX9867_I2S_DLY;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface1A |= MAX9867_TDM_MODE | MAX9867_SDOUT_HIZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Clock inversion bits, BCI and WCI */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface1A |= MAX9867_WCI_MODE | MAX9867_BCI_MODE;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface1A |= MAX9867_BCI_MODE;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface1A |= MAX9867_WCI_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A);
+	regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B);
+	return 0;
+}
+
+static const struct snd_soc_dai_ops max9867_dai_ops = {
+	.set_fmt = max9867_dai_set_fmt,
+	.set_sysclk	= max9867_set_dai_sysclk,
+	.prepare	= max9867_prepare,
+	.digital_mute	= max9867_mute,
+	.hw_params = max9867_dai_hw_params,
+};
+
+#define MAX9867_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+	SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define MAX9867_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+static struct snd_soc_dai_driver max9867_dai[] = {
+	{
+	.name = "max9867-aif1",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = MAX9867_RATES,
+		.formats = MAX9867_FORMATS,
+	},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = MAX9867_RATES,
+		.formats = MAX9867_FORMATS,
+	},
+	.ops = &max9867_dai_ops,
+	.symmetric_rates = 1,
+	}
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int max9867_suspend(struct device *dev)
+{
+	struct max9867_priv *max9867 = dev_get_drvdata(dev);
+
+	/* Drop down to power saving mode when system is suspended */
+	regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
+		MAX9867_SHTDOWN_MASK, ~MAX9867_SHTDOWN_MASK);
+	return 0;
+}
+
+static int max9867_resume(struct device *dev)
+{
+	struct max9867_priv *max9867 = dev_get_drvdata(dev);
+
+	regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
+		MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK);
+	return 0;
+}
+#endif
+
+static const struct snd_soc_component_driver max9867_component = {
+	.controls		= max9867_snd_controls,
+	.num_controls		= ARRAY_SIZE(max9867_snd_controls),
+	.dapm_routes		= max9867_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max9867_audio_map),
+	.dapm_widgets		= max9867_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max9867_dapm_widgets),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static bool max9867_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX9867_STATUS:
+	case MAX9867_JACKSTATUS:
+	case MAX9867_AUXHIGH:
+	case MAX9867_AUXLOW:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct reg_default max9867_reg[] = {
+	{ 0x04, 0x00 },
+	{ 0x05, 0x00 },
+	{ 0x06, 0x00 },
+	{ 0x07, 0x00 },
+	{ 0x08, 0x00 },
+	{ 0x09, 0x00 },
+	{ 0x0A, 0x00 },
+	{ 0x0B, 0x00 },
+	{ 0x0C, 0x00 },
+	{ 0x0D, 0x00 },
+	{ 0x0E, 0x00 },
+	{ 0x0F, 0x00 },
+	{ 0x10, 0x00 },
+	{ 0x11, 0x00 },
+	{ 0x12, 0x00 },
+	{ 0x13, 0x00 },
+	{ 0x14, 0x00 },
+	{ 0x15, 0x00 },
+	{ 0x16, 0x00 },
+	{ 0x17, 0x00 },
+};
+
+static const struct regmap_config max9867_regmap = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= MAX9867_REVISION,
+	.reg_defaults	= max9867_reg,
+	.num_reg_defaults = ARRAY_SIZE(max9867_reg),
+	.volatile_reg	= max9867_volatile_register,
+	.cache_type	= REGCACHE_RBTREE,
+};
+
+static int max9867_i2c_probe(struct i2c_client *i2c,
+		const struct i2c_device_id *id)
+{
+	struct max9867_priv *max9867;
+	int ret = 0, reg;
+
+	max9867 = devm_kzalloc(&i2c->dev,
+			sizeof(*max9867), GFP_KERNEL);
+	if (!max9867)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, max9867);
+	max9867->regmap = devm_regmap_init_i2c(i2c, &max9867_regmap);
+	if (IS_ERR(max9867->regmap)) {
+		ret = PTR_ERR(max9867->regmap);
+		dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+	ret = regmap_read(max9867->regmap,
+			MAX9867_REVISION, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read: %d\n", ret);
+		return ret;
+	}
+	dev_info(&i2c->dev, "device revision: %x\n", reg);
+	ret = devm_snd_soc_register_component(&i2c->dev, &max9867_component,
+			max9867_dai, ARRAY_SIZE(max9867_dai));
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
+		return ret;
+	}
+	return ret;
+}
+
+static const struct i2c_device_id max9867_i2c_id[] = {
+	{ "max9867", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max9867_i2c_id);
+
+static const struct of_device_id max9867_of_match[] = {
+	{ .compatible = "maxim,max9867", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max9867_of_match);
+
+static const struct dev_pm_ops max9867_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(max9867_suspend, max9867_resume)
+};
+
+static struct i2c_driver max9867_i2c_driver = {
+	.driver = {
+		.name = "max9867",
+		.of_match_table = of_match_ptr(max9867_of_match),
+		.pm = &max9867_pm_ops,
+	},
+	.probe  = max9867_i2c_probe,
+	.id_table = max9867_i2c_id,
+};
+
+module_i2c_driver(max9867_i2c_driver);
+
+MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC MAX9867 driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max9867.h b/sound/soc/codecs/max9867.h
new file mode 100644
index 0000000..55cd997
--- /dev/null
+++ b/sound/soc/codecs/max9867.h
@@ -0,0 +1,82 @@
+/*
+ * max9867.h -- MAX9867 ALSA SoC Audio driver
+ *
+ * Copyright 2013-2015 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX9867_H
+#define _MAX9867_H
+
+/* MAX9867 register space */
+
+#define MAX9867_STATUS        0x00
+#define MAX9867_JACKSTATUS   0x01
+#define MAX9867_AUXHIGH      0x02
+#define MAX9867_AUXLOW       0x03
+#define MAX9867_INTEN        0x04
+#define MAX9867_SYSCLK       0x05
+#define MAX9867_FREQ_MASK    0xF
+#define MAX9867_PSCLK_SHIFT  0x4
+#define MAX9867_PSCLK_WIDTH  0x2
+#define MAX9867_PSCLK_MASK   (0x03<<MAX9867_PSCLK_SHIFT)
+#define MAX9867_PSCLK_10_20  0x1
+#define MAX9867_PSCLK_20_40  0x2
+#define MAX9867_PSCLK_40_60  0x3
+#define MAX9867_AUDIOCLKHIGH 0x06
+#define MAX9867_NI_HIGH_WIDTH 0x7
+#define MAX9867_NI_HIGH_MASK 0x7F
+#define MAX9867_NI_LOW_MASK 0x7F
+#define MAX9867_NI_LOW_SHIFT 0x1
+#define MAX9867_PLL     (1<<7)
+#define MAX9867_AUDIOCLKLOW  0x07
+#define MAX9867_RAPID_LOCK   0x01
+#define MAX9867_IFC1A        0x08
+#define MAX9867_MASTER       (1<<7)
+#define MAX9867_I2S_DLY      (1<<4)
+#define MAX9867_SDOUT_HIZ    (1<<3)
+#define MAX9867_TDM_MODE     (1<<2)
+#define MAX9867_WCI_MODE     (1<<6)
+#define MAX9867_BCI_MODE     (1<<5)
+#define MAX9867_IFC1B        0x09
+#define MAX9867_IFC1B_BCLK_MASK 7
+#define MAX9867_IFC1B_32BIT  0x01
+#define MAX9867_IFC1B_24BIT  0x02
+#define MAX9867_IFC1B_PCLK_2 4
+#define MAX9867_IFC1B_PCLK_4 5
+#define MAX9867_IFC1B_PCLK_8 6
+#define MAX9867_IFC1B_PCLK_16 7
+#define MAX9867_CODECFLTR    0x0a
+#define MAX9867_DACGAIN      0x0b
+#define MAX9867_DACLEVEL     0x0c
+#define MAX9867_DAC_MUTE_SHIFT 0x6
+#define MAX9867_DAC_MUTE_WIDTH 0x1
+#define MAX9867_DAC_MUTE_MASK (0x1<<MAX9867_DAC_MUTE_SHIFT)
+#define MAX9867_ADCLEVEL     0x0d
+#define MAX9867_LEFTLINELVL  0x0e
+#define MAX9867_RIGTHLINELVL 0x0f
+#define MAX9867_LEFTVOL      0x10
+#define MAX9867_RIGHTVOL     0x11
+#define MAX9867_LEFTMICGAIN  0x12
+#define MAX9867_RIGHTMICGAIN 0x13
+#define MAX9867_INPUTCONFIG  0x14
+#define MAX9867_INPUT_SHIFT  0x6
+#define MAX9867_MICCONFIG    0x15
+#define MAX9867_MODECONFIG   0x16
+#define MAX9867_PWRMAN       0x17
+#define MAX9867_SHTDOWN_MASK (1<<7)
+#define MAX9867_REVISION     0xff
+
+#define MAX9867_CACHEREGNUM 10
+
+/* codec private data */
+struct max9867_priv {
+	struct regmap *regmap;
+	unsigned int sysclk;
+	unsigned int pclk;
+	unsigned int master;
+};
+#endif
diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c
new file mode 100644
index 0000000..61cc18e
--- /dev/null
+++ b/sound/soc/codecs/max9877.c
@@ -0,0 +1,177 @@
+/*
+ * max9877.c  --  amp driver for max9877
+ *
+ * Copyright (C) 2009 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "max9877.h"
+
+static const struct reg_default max9877_regs[] = {
+	{ 0, 0x40 },
+	{ 1, 0x00 },
+	{ 2, 0x00 },
+	{ 3, 0x00 },
+	{ 4, 0x49 },
+};
+
+static const DECLARE_TLV_DB_RANGE(max9877_pgain_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(0, 900, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0)
+);
+
+static const DECLARE_TLV_DB_RANGE(max9877_output_tlv,
+	0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1),
+	8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0),
+	16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0),
+	24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0)
+);
+
+static const char *max9877_out_mode[] = {
+	"INA -> SPK",
+	"INA -> HP",
+	"INA -> SPK and HP",
+	"INB -> SPK",
+	"INB -> HP",
+	"INB -> SPK and HP",
+	"INA + INB -> SPK",
+	"INA + INB -> HP",
+	"INA + INB -> SPK and HP",
+};
+
+static const char *max9877_osc_mode[] = {
+	"1176KHz",
+	"1100KHz",
+	"700KHz",
+};
+
+static const struct soc_enum max9877_enum[] = {
+	SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, 0, ARRAY_SIZE(max9877_out_mode),
+			max9877_out_mode),
+	SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, MAX9877_OSC_OFFSET,
+			ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode),
+};
+
+static const struct snd_kcontrol_new max9877_controls[] = {
+	SOC_SINGLE_TLV("MAX9877 PGAINA Playback Volume",
+		       MAX9877_INPUT_MODE, 0, 2, 0, max9877_pgain_tlv),
+	SOC_SINGLE_TLV("MAX9877 PGAINB Playback Volume",
+		       MAX9877_INPUT_MODE, 2, 2, 0, max9877_pgain_tlv),
+	SOC_SINGLE_TLV("MAX9877 Amp Speaker Playback Volume",
+		       MAX9877_SPK_VOLUME, 0, 31, 0, max9877_output_tlv),
+	SOC_DOUBLE_R_TLV("MAX9877 Amp HP Playback Volume",
+			 MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0,
+			 max9877_output_tlv),
+	SOC_SINGLE("MAX9877 INB Stereo Switch",
+		   MAX9877_INPUT_MODE, 4, 1, 1),
+	SOC_SINGLE("MAX9877 INA Stereo Switch",
+		   MAX9877_INPUT_MODE, 5, 1, 1),
+	SOC_SINGLE("MAX9877 Zero-crossing detection Switch",
+		   MAX9877_INPUT_MODE, 6, 1, 0),
+	SOC_SINGLE("MAX9877 Bypass Mode Switch",
+		   MAX9877_OUTPUT_MODE, 6, 1, 0),
+	SOC_ENUM("MAX9877 Output Mode", max9877_enum[0]),
+	SOC_ENUM("MAX9877 Oscillator Mode", max9877_enum[1]),
+};
+
+static const struct snd_soc_dapm_widget max9877_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("INA1"),
+SND_SOC_DAPM_INPUT("INA2"),
+SND_SOC_DAPM_INPUT("INB1"),
+SND_SOC_DAPM_INPUT("INB2"),
+SND_SOC_DAPM_INPUT("RXIN+"),
+SND_SOC_DAPM_INPUT("RXIN-"),
+
+SND_SOC_DAPM_PGA("SHDN", MAX9877_OUTPUT_MODE, 7, 1, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("OUT+"),
+SND_SOC_DAPM_OUTPUT("OUT-"),
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+static const struct snd_soc_dapm_route max9877_dapm_routes[] = {
+	{ "SHDN", NULL, "INA1" },
+	{ "SHDN", NULL, "INA2" },
+	{ "SHDN", NULL, "INB1" },
+	{ "SHDN", NULL, "INB2" },
+
+	{ "OUT+", NULL, "RXIN+" },
+	{ "OUT+", NULL, "SHDN" },
+
+	{ "OUT-", NULL, "SHDN" },
+	{ "OUT-", NULL, "RXIN-" },
+
+	{ "HPL", NULL, "SHDN" },
+	{ "HPR", NULL, "SHDN" },
+};
+
+static const struct snd_soc_component_driver max9877_component_driver = {
+	.controls = max9877_controls,
+	.num_controls = ARRAY_SIZE(max9877_controls),
+
+	.dapm_widgets = max9877_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(max9877_dapm_widgets),
+	.dapm_routes = max9877_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(max9877_dapm_routes),
+};
+
+static const struct regmap_config max9877_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.reg_defaults = max9877_regs,
+	.num_reg_defaults = ARRAY_SIZE(max9877_regs),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int max9877_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	int i;
+
+	regmap = devm_regmap_init_i2c(client, &max9877_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	/* Ensure the device is in reset state */
+	for (i = 0; i < ARRAY_SIZE(max9877_regs); i++)
+		regmap_write(regmap, max9877_regs[i].reg, max9877_regs[i].def);
+
+	return devm_snd_soc_register_component(&client->dev,
+			&max9877_component_driver, NULL, 0);
+}
+
+static const struct i2c_device_id max9877_i2c_id[] = {
+	{ "max9877", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max9877_i2c_id);
+
+static struct i2c_driver max9877_i2c_driver = {
+	.driver = {
+		.name = "max9877",
+	},
+	.probe = max9877_i2c_probe,
+	.id_table = max9877_i2c_id,
+};
+
+module_i2c_driver(max9877_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC MAX9877 amp driver");
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max9877.h b/sound/soc/codecs/max9877.h
new file mode 100644
index 0000000..368343f
--- /dev/null
+++ b/sound/soc/codecs/max9877.h
@@ -0,0 +1,35 @@
+/*
+ * max9877.h  --  amp driver for max9877
+ *
+ * Copyright (C) 2009 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef _MAX9877_H
+#define _MAX9877_H
+
+#define MAX9877_INPUT_MODE		0x00
+#define MAX9877_SPK_VOLUME		0x01
+#define MAX9877_HPL_VOLUME		0x02
+#define MAX9877_HPR_VOLUME		0x03
+#define MAX9877_OUTPUT_MODE		0x04
+
+/* MAX9877_INPUT_MODE */
+#define MAX9877_INB			(1 << 4)
+#define MAX9877_INA			(1 << 5)
+#define MAX9877_ZCD			(1 << 6)
+
+/* MAX9877_OUTPUT_MODE */
+#define MAX9877_OUTMODE_MASK		(15 << 0)
+#define MAX9877_OSC_MASK		(3 << 4)
+#define MAX9877_OSC_OFFSET		4
+#define MAX9877_BYPASS			(1 << 6)
+#define MAX9877_SHDN			(1 << 7)
+
+#endif
diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c
new file mode 100644
index 0000000..2987773
--- /dev/null
+++ b/sound/soc/codecs/max98925.c
@@ -0,0 +1,652 @@
+/*
+ * max98925.c -- ALSA SoC Stereo MAX98925 driver
+ * Copyright 2013-15 Maxim Integrated Products
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "max98925.h"
+
+static const char *const dai_text[] = {
+	"Left", "Right", "LeftRight", "LeftRightDiv2",
+};
+
+static const char * const max98925_boost_voltage_text[] = {
+	"8.5V", "8.25V", "8.0V", "7.75V", "7.5V", "7.25V", "7.0V", "6.75V",
+	"6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V",	"6.5V", "6.5V"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98925_boost_voltage,
+	MAX98925_CONFIGURATION, M98925_BST_VOUT_SHIFT,
+	max98925_boost_voltage_text);
+
+static const char *const hpf_text[] = {
+	"Disable", "DC Block", "100Hz",	"200Hz", "400Hz", "800Hz",
+};
+
+static const struct reg_default max98925_reg[] = {
+	{ 0x0B, 0x00 }, /* IRQ Enable0 */
+	{ 0x0C, 0x00 }, /* IRQ Enable1 */
+	{ 0x0D, 0x00 }, /* IRQ Enable2 */
+	{ 0x0E, 0x00 }, /* IRQ Clear0 */
+	{ 0x0F, 0x00 }, /* IRQ Clear1 */
+	{ 0x10, 0x00 }, /* IRQ Clear2 */
+	{ 0x11, 0xC0 }, /* Map0 */
+	{ 0x12, 0x00 }, /* Map1 */
+	{ 0x13, 0x00 }, /* Map2 */
+	{ 0x14, 0xF0 }, /* Map3 */
+	{ 0x15, 0x00 }, /* Map4 */
+	{ 0x16, 0xAB }, /* Map5 */
+	{ 0x17, 0x89 }, /* Map6 */
+	{ 0x18, 0x00 }, /* Map7 */
+	{ 0x19, 0x00 }, /* Map8 */
+	{ 0x1A, 0x06 }, /* DAI Clock Mode 1 */
+	{ 0x1B, 0xC0 }, /* DAI Clock Mode 2 */
+	{ 0x1C, 0x00 }, /* DAI Clock Divider Denominator MSBs */
+	{ 0x1D, 0x00 }, /* DAI Clock Divider Denominator LSBs */
+	{ 0x1E, 0xF0 }, /* DAI Clock Divider Numerator MSBs */
+	{ 0x1F, 0x00 }, /* DAI Clock Divider Numerator LSBs */
+	{ 0x20, 0x50 }, /* Format */
+	{ 0x21, 0x00 }, /* TDM Slot Select */
+	{ 0x22, 0x00 }, /* DOUT Configuration VMON */
+	{ 0x23, 0x00 }, /* DOUT Configuration IMON */
+	{ 0x24, 0x00 }, /* DOUT Configuration VBAT */
+	{ 0x25, 0x00 }, /* DOUT Configuration VBST */
+	{ 0x26, 0x00 }, /* DOUT Configuration FLAG */
+	{ 0x27, 0xFF }, /* DOUT HiZ Configuration 1 */
+	{ 0x28, 0xFF }, /* DOUT HiZ Configuration 2 */
+	{ 0x29, 0xFF }, /* DOUT HiZ Configuration 3 */
+	{ 0x2A, 0xFF }, /* DOUT HiZ Configuration 4 */
+	{ 0x2B, 0x02 }, /* DOUT Drive Strength */
+	{ 0x2C, 0x90 }, /* Filters */
+	{ 0x2D, 0x00 }, /* Gain */
+	{ 0x2E, 0x02 }, /* Gain Ramping */
+	{ 0x2F, 0x00 }, /* Speaker Amplifier */
+	{ 0x30, 0x0A }, /* Threshold */
+	{ 0x31, 0x00 }, /* ALC Attack */
+	{ 0x32, 0x80 }, /* ALC Atten and Release */
+	{ 0x33, 0x00 }, /* ALC Infinite Hold Release */
+	{ 0x34, 0x92 }, /* ALC Configuration */
+	{ 0x35, 0x01 }, /* Boost Converter */
+	{ 0x36, 0x00 }, /* Block Enable */
+	{ 0x37, 0x00 }, /* Configuration */
+	{ 0x38, 0x00 }, /* Global Enable */
+	{ 0x3A, 0x00 }, /* Boost Limiter */
+};
+
+static const struct soc_enum max98925_dai_enum =
+	SOC_ENUM_SINGLE(MAX98925_GAIN, 5, ARRAY_SIZE(dai_text), dai_text);
+
+static const struct soc_enum max98925_hpf_enum =
+	SOC_ENUM_SINGLE(MAX98925_FILTERS, 0, ARRAY_SIZE(hpf_text), hpf_text);
+
+static const struct snd_kcontrol_new max98925_hpf_sel_mux =
+	SOC_DAPM_ENUM("Rc Filter MUX Mux", max98925_hpf_enum);
+
+static const struct snd_kcontrol_new max98925_dai_sel_mux =
+	SOC_DAPM_ENUM("DAI IN MUX Mux", max98925_dai_enum);
+
+static int max98925_dac_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct max98925_priv *max98925 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_update_bits(max98925->regmap,
+			MAX98925_BLOCK_ENABLE,
+			M98925_BST_EN_MASK |
+			M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK,
+			M98925_BST_EN_MASK |
+			M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_update_bits(max98925->regmap,
+			MAX98925_BLOCK_ENABLE, M98925_BST_EN_MASK |
+			M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK, 0);
+		break;
+	default:
+		return 0;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget max98925_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_MUX("DAI IN MUX", SND_SOC_NOPM, 0, 0,
+				&max98925_dai_sel_mux),
+	SND_SOC_DAPM_MUX("Rc Filter MUX", SND_SOC_NOPM, 0, 0,
+				&max98925_hpf_sel_mux),
+	SND_SOC_DAPM_DAC_E("Amp Enable", NULL, MAX98925_BLOCK_ENABLE,
+			M98925_SPK_EN_SHIFT, 0, max98925_dac_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("Global Enable", MAX98925_GLOBAL_ENABLE,
+			M98925_EN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("BE_OUT"),
+};
+
+static const struct snd_soc_dapm_route max98925_audio_map[] = {
+	{"DAI IN MUX", "Left", "DAI_OUT"},
+	{"DAI IN MUX", "Right", "DAI_OUT"},
+	{"DAI IN MUX", "LeftRight", "DAI_OUT"},
+	{"DAI IN MUX", "LeftRightDiv2", "DAI_OUT"},
+	{"Rc Filter MUX", "Disable", "DAI IN MUX"},
+	{"Rc Filter MUX", "DC Block", "DAI IN MUX"},
+	{"Rc Filter MUX", "100Hz", "DAI IN MUX"},
+	{"Rc Filter MUX", "200Hz", "DAI IN MUX"},
+	{"Rc Filter MUX", "400Hz", "DAI IN MUX"},
+	{"Rc Filter MUX", "800Hz", "DAI IN MUX"},
+	{"Amp Enable", NULL, "Rc Filter MUX"},
+	{"BE_OUT", NULL, "Amp Enable"},
+	{"BE_OUT", NULL, "Global Enable"},
+};
+
+static bool max98925_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98925_VBAT_DATA:
+	case MAX98925_VBST_DATA:
+	case MAX98925_LIVE_STATUS0:
+	case MAX98925_LIVE_STATUS1:
+	case MAX98925_LIVE_STATUS2:
+	case MAX98925_STATE0:
+	case MAX98925_STATE1:
+	case MAX98925_STATE2:
+	case MAX98925_FLAG0:
+	case MAX98925_FLAG1:
+	case MAX98925_FLAG2:
+	case MAX98925_REV_VERSION:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max98925_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98925_IRQ_CLEAR0:
+	case MAX98925_IRQ_CLEAR1:
+	case MAX98925_IRQ_CLEAR2:
+	case MAX98925_ALC_HOLD_RLS:
+		return false;
+	default:
+		return true;
+	}
+}
+
+static DECLARE_TLV_DB_SCALE(max98925_spk_tlv, -600, 100, 0);
+
+static const struct snd_kcontrol_new max98925_snd_controls[] = {
+	SOC_SINGLE_TLV("Speaker Volume", MAX98925_GAIN,
+		M98925_SPK_GAIN_SHIFT, (1<<M98925_SPK_GAIN_WIDTH)-1, 0,
+		max98925_spk_tlv),
+	SOC_SINGLE("Ramp Switch", MAX98925_GAIN_RAMPING,
+				M98925_SPK_RMP_EN_SHIFT, 1, 0),
+	SOC_SINGLE("ZCD Switch", MAX98925_GAIN_RAMPING,
+				M98925_SPK_ZCD_EN_SHIFT, 1, 0),
+	SOC_SINGLE("ALC Switch", MAX98925_THRESHOLD,
+				M98925_ALC_EN_SHIFT, 1, 0),
+	SOC_SINGLE("ALC Threshold", MAX98925_THRESHOLD, M98925_ALC_TH_SHIFT,
+				(1<<M98925_ALC_TH_WIDTH)-1, 0),
+	SOC_ENUM("Boost Output Voltage", max98925_boost_voltage),
+};
+
+/* codec sample rate and n/m dividers parameter table */
+static const struct {
+	int rate;
+	int  sr;
+	int divisors[3][2];
+} rate_table[] = {
+	{
+		.rate = 8000,
+		.sr = 0,
+		.divisors = { {1, 375}, {5, 1764}, {1, 384} }
+	},
+	{
+		.rate = 11025,
+		.sr = 1,
+		.divisors = { {147, 40000}, {1, 256}, {147, 40960} }
+	},
+	{
+		.rate = 12000,
+		.sr = 2,
+		.divisors = { {1, 250}, {5, 1176}, {1, 256} }
+	},
+	{
+		.rate = 16000,
+		.sr = 3,
+		.divisors = { {2, 375}, {5, 882}, {1, 192} }
+	},
+	{
+		.rate = 22050,
+		.sr = 4,
+		.divisors = { {147, 20000}, {1, 128}, {147, 20480} }
+	},
+	{
+		.rate = 24000,
+		.sr = 5,
+		.divisors = { {1, 125}, {5, 588}, {1, 128} }
+	},
+	{
+		.rate = 32000,
+		.sr = 6,
+		.divisors = { {4, 375}, {5, 441}, {1, 96} }
+	},
+	{
+		.rate = 44100,
+		.sr = 7,
+		.divisors = { {147, 10000}, {1, 64}, {147, 10240} }
+	},
+	{
+		.rate = 48000,
+		.sr = 8,
+		.divisors = { {2, 125}, {5, 294}, {1, 64} }
+	},
+};
+
+static inline int max98925_rate_value(struct snd_soc_component *component,
+		int rate, int clock, int *value, int *n, int *m)
+{
+	int ret = -EINVAL;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+		if (rate_table[i].rate >= rate) {
+			*value = rate_table[i].sr;
+			*n = rate_table[i].divisors[clock][0];
+			*m = rate_table[i].divisors[clock][1];
+			ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
+static void max98925_set_sense_data(struct max98925_priv *max98925)
+{
+	/* set VMON slots */
+	regmap_update_bits(max98925->regmap,
+		MAX98925_DOUT_CFG_VMON,
+		M98925_DAI_VMON_EN_MASK, M98925_DAI_VMON_EN_MASK);
+	regmap_update_bits(max98925->regmap,
+		MAX98925_DOUT_CFG_VMON,
+		M98925_DAI_VMON_SLOT_MASK,
+		max98925->v_slot << M98925_DAI_VMON_SLOT_SHIFT);
+	/* set IMON slots */
+	regmap_update_bits(max98925->regmap,
+		MAX98925_DOUT_CFG_IMON,
+		M98925_DAI_IMON_EN_MASK, M98925_DAI_IMON_EN_MASK);
+	regmap_update_bits(max98925->regmap,
+		MAX98925_DOUT_CFG_IMON,
+		M98925_DAI_IMON_SLOT_MASK,
+		max98925->i_slot << M98925_DAI_IMON_SLOT_SHIFT);
+}
+
+static int max98925_dai_set_fmt(struct snd_soc_dai *codec_dai,
+				 unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98925_priv *max98925 = snd_soc_component_get_drvdata(component);
+	unsigned int invert = 0;
+
+	dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* set DAI to slave mode */
+		regmap_update_bits(max98925->regmap,
+			MAX98925_DAI_CLK_MODE2,
+			M98925_DAI_MAS_MASK, 0);
+		max98925_set_sense_data(max98925);
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/*
+		 * set left channel DAI to master mode,
+		 * right channel always slave
+		 */
+		regmap_update_bits(max98925->regmap,
+			MAX98925_DAI_CLK_MODE2,
+			M98925_DAI_MAS_MASK, M98925_DAI_MAS_MASK);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	default:
+		dev_err(component->dev, "DAI clock mode unsupported");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		invert = M98925_DAI_WCI_MASK;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		invert = M98925_DAI_BCI_MASK;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		invert = M98925_DAI_BCI_MASK | M98925_DAI_WCI_MASK;
+		break;
+	default:
+		dev_err(component->dev, "DAI invert mode unsupported");
+		return -EINVAL;
+	}
+
+	regmap_update_bits(max98925->regmap, MAX98925_FORMAT,
+			M98925_DAI_BCI_MASK | M98925_DAI_WCI_MASK, invert);
+	return 0;
+}
+
+static int max98925_set_clock(struct max98925_priv *max98925,
+		struct snd_pcm_hw_params *params)
+{
+	unsigned int dai_sr = 0, clock, mdll, n, m;
+	struct snd_soc_component *component = max98925->component;
+	int rate = params_rate(params);
+	/* BCLK/LRCLK ratio calculation */
+	int blr_clk_ratio = params_channels(params) * max98925->ch_size;
+
+	switch (blr_clk_ratio) {
+	case 32:
+		regmap_update_bits(max98925->regmap,
+			MAX98925_DAI_CLK_MODE2,
+			M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_32);
+		break;
+	case 48:
+		regmap_update_bits(max98925->regmap,
+			MAX98925_DAI_CLK_MODE2,
+			M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_48);
+		break;
+	case 64:
+		regmap_update_bits(max98925->regmap,
+			MAX98925_DAI_CLK_MODE2,
+			M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_64);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (max98925->sysclk) {
+	case 6000000:
+		clock = 0;
+		mdll  = M98925_MDLL_MULT_MCLKx16;
+		break;
+	case 11289600:
+		clock = 1;
+		mdll  = M98925_MDLL_MULT_MCLKx8;
+		break;
+	case 12000000:
+		clock = 0;
+		mdll  = M98925_MDLL_MULT_MCLKx8;
+		break;
+	case 12288000:
+		clock = 2;
+		mdll  = M98925_MDLL_MULT_MCLKx8;
+		break;
+	default:
+		dev_info(max98925->component->dev, "unsupported sysclk %d\n",
+					max98925->sysclk);
+		return -EINVAL;
+	}
+
+	if (max98925_rate_value(component, rate, clock, &dai_sr, &n, &m))
+		return -EINVAL;
+
+	/* set DAI_SR to correct LRCLK frequency */
+	regmap_update_bits(max98925->regmap,
+			MAX98925_DAI_CLK_MODE2,
+			M98925_DAI_SR_MASK, dai_sr << M98925_DAI_SR_SHIFT);
+	/* set DAI m divider */
+	regmap_write(max98925->regmap,
+		MAX98925_DAI_CLK_DIV_M_MSBS, m >> 8);
+	regmap_write(max98925->regmap,
+		MAX98925_DAI_CLK_DIV_M_LSBS, m & 0xFF);
+	/* set DAI n divider */
+	regmap_write(max98925->regmap,
+		MAX98925_DAI_CLK_DIV_N_MSBS, n >> 8);
+	regmap_write(max98925->regmap,
+		MAX98925_DAI_CLK_DIV_N_LSBS, n & 0xFF);
+	/* set MDLL */
+	regmap_update_bits(max98925->regmap, MAX98925_DAI_CLK_MODE1,
+			M98925_MDLL_MULT_MASK, mdll << M98925_MDLL_MULT_SHIFT);
+	return 0;
+}
+
+static int max98925_dai_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98925_priv *max98925 = snd_soc_component_get_drvdata(component);
+
+	switch (params_width(params)) {
+	case 16:
+		regmap_update_bits(max98925->regmap,
+				MAX98925_FORMAT,
+				M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_16);
+		max98925->ch_size = 16;
+		break;
+	case 24:
+		regmap_update_bits(max98925->regmap,
+				MAX98925_FORMAT,
+				M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_24);
+		max98925->ch_size = 24;
+		break;
+	case 32:
+		regmap_update_bits(max98925->regmap,
+				MAX98925_FORMAT,
+				M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_32);
+		max98925->ch_size = 32;
+		break;
+	default:
+		pr_err("%s: format unsupported %d",
+				__func__, params_format(params));
+		return -EINVAL;
+	}
+	dev_dbg(component->dev, "%s: format supported %d",
+				__func__, params_format(params));
+	return max98925_set_clock(max98925, params);
+}
+
+static int max98925_dai_set_sysclk(struct snd_soc_dai *dai,
+				   int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98925_priv *max98925 = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case 0:
+		/* use MCLK for Left channel, right channel always BCLK */
+		regmap_update_bits(max98925->regmap,
+				MAX98925_DAI_CLK_MODE1,
+				M98925_DAI_CLK_SOURCE_MASK, 0);
+		break;
+	case 1:
+		/* configure dai clock source to BCLK instead of MCLK */
+		regmap_update_bits(max98925->regmap,
+				MAX98925_DAI_CLK_MODE1,
+				M98925_DAI_CLK_SOURCE_MASK,
+				M98925_DAI_CLK_SOURCE_MASK);
+		break;
+	default:
+		return -EINVAL;
+	}
+	max98925->sysclk = freq;
+	return 0;
+}
+
+#define MAX98925_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops max98925_dai_ops = {
+	.set_sysclk = max98925_dai_set_sysclk,
+	.set_fmt = max98925_dai_set_fmt,
+	.hw_params = max98925_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver max98925_dai[] = {
+	{
+		.name = "max98925-aif1",
+		.playback = {
+			.stream_name = "HiFi Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = MAX98925_FORMATS,
+		},
+		.capture = {
+			.stream_name = "HiFi Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = MAX98925_FORMATS,
+		},
+		.ops = &max98925_dai_ops,
+	}
+};
+
+static int max98925_probe(struct snd_soc_component *component)
+{
+	struct max98925_priv *max98925 = snd_soc_component_get_drvdata(component);
+
+	max98925->component = component;
+	regmap_write(max98925->regmap, MAX98925_GLOBAL_ENABLE, 0x00);
+	/* It's not the default but we need to set DAI_DLY */
+	regmap_write(max98925->regmap,
+			MAX98925_FORMAT, M98925_DAI_DLY_MASK);
+	regmap_write(max98925->regmap, MAX98925_TDM_SLOT_SELECT, 0xC8);
+	regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG1, 0xFF);
+	regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG2, 0xFF);
+	regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG3, 0xFF);
+	regmap_write(max98925->regmap, MAX98925_DOUT_HIZ_CFG4, 0xF0);
+	regmap_write(max98925->regmap, MAX98925_FILTERS, 0xD8);
+	regmap_write(max98925->regmap, MAX98925_ALC_CONFIGURATION, 0xF8);
+	regmap_write(max98925->regmap, MAX98925_CONFIGURATION, 0xF0);
+	/* Disable ALC muting */
+	regmap_write(max98925->regmap, MAX98925_BOOST_LIMITER, 0xF8);
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_max98925 = {
+	.probe			= max98925_probe,
+	.controls		= max98925_snd_controls,
+	.num_controls		= ARRAY_SIZE(max98925_snd_controls),
+	.dapm_routes		= max98925_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max98925_audio_map),
+	.dapm_widgets		= max98925_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98925_dapm_widgets),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config max98925_regmap = {
+	.reg_bits         = 8,
+	.val_bits         = 8,
+	.max_register     = MAX98925_REV_VERSION,
+	.reg_defaults     = max98925_reg,
+	.num_reg_defaults = ARRAY_SIZE(max98925_reg),
+	.volatile_reg     = max98925_volatile_register,
+	.readable_reg     = max98925_readable_register,
+	.cache_type       = REGCACHE_RBTREE,
+};
+
+static int max98925_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	int ret, reg;
+	u32 value;
+	struct max98925_priv *max98925;
+
+	max98925 = devm_kzalloc(&i2c->dev,
+			sizeof(*max98925), GFP_KERNEL);
+	if (!max98925)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, max98925);
+	max98925->regmap = devm_regmap_init_i2c(i2c, &max98925_regmap);
+	if (IS_ERR(max98925->regmap)) {
+		ret = PTR_ERR(max98925->regmap);
+		dev_err(&i2c->dev,
+				"Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) {
+		if (value > M98925_DAI_VMON_SLOT_1E_1F) {
+			dev_err(&i2c->dev, "vmon slot number is wrong:\n");
+			return -EINVAL;
+		}
+		max98925->v_slot = value;
+	}
+	if (!of_property_read_u32(i2c->dev.of_node, "imon-slot-no", &value)) {
+		if (value > M98925_DAI_IMON_SLOT_1E_1F) {
+			dev_err(&i2c->dev, "imon slot number is wrong:\n");
+			return -EINVAL;
+		}
+		max98925->i_slot = value;
+	}
+
+	ret = regmap_read(max98925->regmap, MAX98925_REV_VERSION, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Read revision failed\n");
+		return ret;
+	}
+
+	if ((reg != MAX98925_VERSION) && (reg != MAX98925_VERSION1)) {
+		ret = -ENODEV;
+		dev_err(&i2c->dev, "Invalid revision (%d 0x%02X)\n",
+			ret, reg);
+		return ret;
+	}
+
+	dev_info(&i2c->dev, "device version 0x%02X\n", reg);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_max98925,
+			max98925_dai, ARRAY_SIZE(max98925_dai));
+	if (ret < 0)
+		dev_err(&i2c->dev,
+				"Failed to register component: %d\n", ret);
+	return ret;
+}
+
+static const struct i2c_device_id max98925_i2c_id[] = {
+	{ "max98925", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max98925_i2c_id);
+
+static const struct of_device_id max98925_of_match[] = {
+	{ .compatible = "maxim,max98925", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max98925_of_match);
+
+static struct i2c_driver max98925_i2c_driver = {
+	.driver = {
+		.name = "max98925",
+		.of_match_table = of_match_ptr(max98925_of_match),
+		.pm = NULL,
+	},
+	.probe  = max98925_i2c_probe,
+	.id_table = max98925_i2c_id,
+};
+
+module_i2c_driver(max98925_i2c_driver)
+
+MODULE_DESCRIPTION("ALSA SoC MAX98925 driver");
+MODULE_AUTHOR("Ralph Birt <rdbirt@gmail.com>, Anish kumar <anish.kumar@maximintegrated.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98925.h b/sound/soc/codecs/max98925.h
new file mode 100644
index 0000000..96f9708
--- /dev/null
+++ b/sound/soc/codecs/max98925.h
@@ -0,0 +1,832 @@
+/*
+ * max98925.h -- MAX98925 ALSA SoC Audio driver
+ *
+ * Copyright 2013-2015 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX98925_H
+#define _MAX98925_H
+
+#define	MAX98925_VERSION	0x51
+#define	MAX98925_VERSION1	0x80
+#define MAX98925_VBAT_DATA		0x00
+#define MAX98925_VBST_DATA		0x01
+#define MAX98925_LIVE_STATUS0		0x02
+#define MAX98925_LIVE_STATUS1		0x03
+#define MAX98925_LIVE_STATUS2		0x04
+#define MAX98925_STATE0			0x05
+#define MAX98925_STATE1			0x06
+#define MAX98925_STATE2			0x07
+#define MAX98925_FLAG0			0x08
+#define MAX98925_FLAG1			0x09
+#define MAX98925_FLAG2			0x0A
+#define MAX98925_IRQ_ENABLE0		0x0B
+#define MAX98925_IRQ_ENABLE1		0x0C
+#define MAX98925_IRQ_ENABLE2		0x0D
+#define MAX98925_IRQ_CLEAR0		0x0E
+#define MAX98925_IRQ_CLEAR1		0x0F
+#define MAX98925_IRQ_CLEAR2		0x10
+#define MAX98925_MAP0			0x11
+#define MAX98925_MAP1			0x12
+#define MAX98925_MAP2			0x13
+#define MAX98925_MAP3			0x14
+#define MAX98925_MAP4			0x15
+#define MAX98925_MAP5			0x16
+#define MAX98925_MAP6			0x17
+#define MAX98925_MAP7			0x18
+#define MAX98925_MAP8			0x19
+#define MAX98925_DAI_CLK_MODE1		0x1A
+#define MAX98925_DAI_CLK_MODE2		0x1B
+#define MAX98925_DAI_CLK_DIV_M_MSBS	0x1C
+#define MAX98925_DAI_CLK_DIV_M_LSBS	0x1D
+#define MAX98925_DAI_CLK_DIV_N_MSBS	0x1E
+#define MAX98925_DAI_CLK_DIV_N_LSBS	0x1F
+#define MAX98925_FORMAT			0x20
+#define MAX98925_TDM_SLOT_SELECT	0x21
+#define MAX98925_DOUT_CFG_VMON		0x22
+#define MAX98925_DOUT_CFG_IMON		0x23
+#define MAX98925_DOUT_CFG_VBAT		0x24
+#define MAX98925_DOUT_CFG_VBST		0x25
+#define MAX98925_DOUT_CFG_FLAG		0x26
+#define MAX98925_DOUT_HIZ_CFG1		0x27
+#define MAX98925_DOUT_HIZ_CFG2		0x28
+#define MAX98925_DOUT_HIZ_CFG3		0x29
+#define MAX98925_DOUT_HIZ_CFG4		0x2A
+#define MAX98925_DOUT_DRV_STRENGTH	0x2B
+#define MAX98925_FILTERS		0x2C
+#define MAX98925_GAIN			0x2D
+#define MAX98925_GAIN_RAMPING		0x2E
+#define MAX98925_SPK_AMP		0x2F
+#define MAX98925_THRESHOLD		0x30
+#define MAX98925_ALC_ATTACK		0x31
+#define MAX98925_ALC_ATTEN_RLS		0x32
+#define MAX98925_ALC_HOLD_RLS		0x33
+#define MAX98925_ALC_CONFIGURATION	0x34
+#define MAX98925_BOOST_CONVERTER	0x35
+#define MAX98925_BLOCK_ENABLE		0x36
+#define MAX98925_CONFIGURATION		0x37
+#define MAX98925_GLOBAL_ENABLE		0x38
+#define MAX98925_BOOST_LIMITER		0x3A
+#define MAX98925_REV_VERSION		0xFF
+
+#define MAX98925_REG_CNT               (MAX98925_R03A_BOOST_LIMITER+1)
+
+/* MAX98925 Register Bit Fields */
+
+/* MAX98925_R002_LIVE_STATUS0 */
+#define M98925_THERMWARN_STATUS_MASK			(1<<3)
+#define M98925_THERMWARN_STATUS_SHIFT			3
+#define M98925_THERMWARN_STATUS_WIDTH			1
+#define M98925_THERMSHDN_STATUS_MASK			(1<<1)
+#define M98925_THERMSHDN_STATUS_SHIFT			1
+#define M98925_THERMSHDN_STATUS_WIDTH			1
+
+/* MAX98925_R003_LIVE_STATUS1 */
+#define M98925_SPKCURNT_STATUS_MASK			(1<<5)
+#define M98925_SPKCURNT_STATUS_SHIFT			5
+#define M98925_SPKCURNT_STATUS_WIDTH			1
+#define M98925_WATCHFAIL_STATUS_MASK			(1<<4)
+#define M98925_WATCHFAIL_STATUS_SHIFT			4
+#define M98925_WATCHFAIL_STATUS_WIDTH			1
+#define M98925_ALCINFH_STATUS_MASK			(1<<3)
+#define M98925_ALCINFH_STATUS_SHIFT			3
+#define M98925_ALCINFH_STATUS_WIDTH			1
+#define M98925_ALCACT_STATUS_MASK			(1<<2)
+#define M98925_ALCACT_STATUS_SHIFT			2
+#define M98925_ALCACT_STATUS_WIDTH			1
+#define M98925_ALCMUT_STATUS_MASK			(1<<1)
+#define M98925_ALCMUT_STATUS_SHIFT			1
+#define M98925_ALCMUT_STATUS_WIDTH			1
+#define M98925_ACLP_STATUS_MASK				(1<<0)
+#define M98925_ACLP_STATUS_SHIFT			0
+#define M98925_ACLP_STATUS_WIDTH			1
+
+/* MAX98925_R004_LIVE_STATUS2 */
+#define M98925_SLOTOVRN_STATUS_MASK			(1<<6)
+#define M98925_SLOTOVRN_STATUS_SHIFT			6
+#define M98925_SLOTOVRN_STATUS_WIDTH			1
+#define M98925_INVALSLOT_STATUS_MASK			(1<<5)
+#define M98925_INVALSLOT_STATUS_SHIFT			5
+#define M98925_INVALSLOT_STATUS_WIDTH			1
+#define M98925_SLOTCNFLT_STATUS_MASK			(1<<4)
+#define M98925_SLOTCNFLT_STATUS_SHIFT			4
+#define M98925_SLOTCNFLT_STATUS_WIDTH			1
+#define M98925_VBSTOVFL_STATUS_MASK			(1<<3)
+#define M98925_VBSTOVFL_STATUS_SHIFT			3
+#define M98925_VBSTOVFL_STATUS_WIDTH			1
+#define M98925_VBATOVFL_STATUS_MASK			(1<<2)
+#define M98925_VBATOVFL_STATUS_SHIFT			2
+#define M98925_VBATOVFL_STATUS_WIDTH			1
+#define M98925_IMONOVFL_STATUS_MASK			(1<<1)
+#define M98925_IMONOVFL_STATUS_SHIFT			1
+#define M98925_IMONOVFL_STATUS_WIDTH			1
+#define M98925_VMONOVFL_STATUS_MASK			(1<<0)
+#define M98925_VMONOVFL_STATUS_SHIFT			0
+#define M98925_VMONOVFL_STATUS_WIDTH			1
+
+/* MAX98925_R005_STATE0 */
+#define M98925_THERMWARN_END_STATE_MASK			(1<<3)
+#define M98925_THERMWARN_END_STATE_SHIFT		3
+#define M98925_THERMWARN_END_STATE_WIDTH		1
+#define M98925_THERMWARN_BGN_STATE_MASK			(1<<2)
+#define M98925_THERMWARN_BGN_STATE_SHIFT		1
+#define M98925_THERMWARN_BGN_STATE_WIDTH		1
+#define M98925_THERMSHDN_END_STATE_MASK			(1<<1)
+#define M98925_THERMSHDN_END_STATE_SHIFT		1
+#define M98925_THERMSHDN_END_STATE_WIDTH		1
+#define M98925_THERMSHDN_BGN_STATE_MASK			(1<<0)
+#define M98925_THERMSHDN_BGN_STATE_SHIFT		0
+#define M98925_THERMSHDN_BGN_STATE_WIDTH		1
+
+/* MAX98925_R006_STATE1 */
+#define M98925_SPRCURNT_STATE_MASK			(1<<5)
+#define M98925_SPRCURNT_STATE_SHIFT			5
+#define M98925_SPRCURNT_STATE_WIDTH			1
+#define M98925_WATCHFAIL_STATE_MASK			(1<<4)
+#define M98925_WATCHFAIL_STATE_SHIFT			4
+#define M98925_WATCHFAIL_STATE_WIDTH			1
+#define M98925_ALCINFH_STATE_MASK			(1<<3)
+#define M98925_ALCINFH_STATE_SHIFT			3
+#define M98925_ALCINFH_STATE_WIDTH			1
+#define M98925_ALCACT_STATE_MASK			(1<<2)
+#define M98925_ALCACT_STATE_SHIFT			2
+#define M98925_ALCACT_STATE_WIDTH			1
+#define M98925_ALCMUT_STATE_MASK			(1<<1)
+#define M98925_ALCMUT_STATE_SHIFT			1
+#define M98925_ALCMUT_STATE_WIDTH			1
+#define M98925_ALCP_STATE_MASK				(1<<0)
+#define M98925_ALCP_STATE_SHIFT				0
+#define M98925_ALCP_STATE_WIDTH				1
+
+/* MAX98925_R007_STATE2 */
+#define M98925_SLOTOVRN_STATE_MASK			(1<<6)
+#define M98925_SLOTOVRN_STATE_SHIFT			6
+#define M98925_SLOTOVRN_STATE_WIDTH			1
+#define M98925_INVALSLOT_STATE_MASK			(1<<5)
+#define M98925_INVALSLOT_STATE_SHIFT			5
+#define M98925_INVALSLOT_STATE_WIDTH			1
+#define M98925_SLOTCNFLT_STATE_MASK			(1<<4)
+#define M98925_SLOTCNFLT_STATE_SHIFT			4
+#define M98925_SLOTCNFLT_STATE_WIDTH			1
+#define M98925_VBSTOVFL_STATE_MASK			(1<<3)
+#define M98925_VBSTOVFL_STATE_SHIFT			3
+#define M98925_VBSTOVFL_STATE_WIDTH			1
+#define M98925_VBATOVFL_STATE_MASK			(1<<2)
+#define M98925_VBATOVFL_STATE_SHIFT			2
+#define M98925_VBATOVFL_STATE_WIDTH			1
+#define M98925_IMONOVFL_STATE_MASK			(1<<1)
+#define M98925_IMONOVFL_STATE_SHIFT			1
+#define M98925_IMONOVFL_STATE_WIDTH			1
+#define M98925_VMONOVFL_STATE_MASK			(1<<0)
+#define M98925_VMONOVFL_STATE_SHIFT			0
+#define M98925_VMONOVFL_STATE_WIDTH			1
+
+/* MAX98925_R008_FLAG0 */
+#define M98925_THERMWARN_END_FLAG_MASK			(1<<3)
+#define M98925_THERMWARN_END_FLAG_SHIFT			3
+#define M98925_THERMWARN_END_FLAG_WIDTH			1
+#define M98925_THERMWARN_BGN_FLAG_MASK			(1<<2)
+#define M98925_THERMWARN_BGN_FLAG_SHIFT			2
+#define M98925_THERMWARN_BGN_FLAG_WIDTH			1
+#define M98925_THERMSHDN_END_FLAG_MASK			(1<<1)
+#define M98925_THERMSHDN_END_FLAG_SHIFT			1
+#define M98925_THERMSHDN_END_FLAG_WIDTH			1
+#define M98925_THERMSHDN_BGN_FLAG_MASK			(1<<0)
+#define M98925_THERMSHDN_BGN_FLAG_SHIFT			0
+#define M98925_THERMSHDN_BGN_FLAG_WIDTH			1
+
+/* MAX98925_R009_FLAG1 */
+#define M98925_SPKCURNT_FLAG_MASK			(1<<5)
+#define M98925_SPKCURNT_FLAG_SHIFT			5
+#define M98925_SPKCURNT_FLAG_WIDTH			1
+#define M98925_WATCHFAIL_FLAG_MASK			(1<<4)
+#define M98925_WATCHFAIL_FLAG_SHIFT			4
+#define M98925_WATCHFAIL_FLAG_WIDTH			1
+#define M98925_ALCINFH_FLAG_MASK			(1<<3)
+#define M98925_ALCINFH_FLAG_SHIFT			3
+#define M98925_ALCINFH_FLAG_WIDTH			1
+#define M98925_ALCACT_FLAG_MASK				(1<<2)
+#define M98925_ALCACT_FLAG_SHIFT			2
+#define M98925_ALCACT_FLAG_WIDTH			1
+#define M98925_ALCMUT_FLAG_MASK				(1<<1)
+#define M98925_ALCMUT_FLAG_SHIFT			1
+#define M98925_ALCMUT_FLAG_WIDTH			1
+#define M98925_ALCP_FLAG_MASK				(1<<0)
+#define M98925_ALCP_FLAG_SHIFT				0
+#define M98925_ALCP_FLAG_WIDTH				1
+
+/* MAX98925_R00A_FLAG2 */
+#define M98925_SLOTOVRN_FLAG_MASK			(1<<6)
+#define M98925_SLOTOVRN_FLAG_SHIFT			6
+#define M98925_SLOTOVRN_FLAG_WIDTH			1
+#define M98925_INVALSLOT_FLAG_MASK			(1<<5)
+#define M98925_INVALSLOT_FLAG_SHIFT			5
+#define M98925_INVALSLOT_FLAG_WIDTH			1
+#define M98925_SLOTCNFLT_FLAG_MASK			(1<<4)
+#define M98925_SLOTCNFLT_FLAG_SHIFT			4
+#define M98925_SLOTCNFLT_FLAG_WIDTH			1
+#define M98925_VBSTOVFL_FLAG_MASK			(1<<3)
+#define M98925_VBSTOVFL_FLAG_SHIFT			3
+#define M98925_VBSTOVFL_FLAG_WIDTH			1
+#define M98925_VBATOVFL_FLAG_MASK			(1<<2)
+#define M98925_VBATOVFL_FLAG_SHIFT			2
+#define M98925_VBATOVFL_FLAG_WIDTH			1
+#define M98925_IMONOVFL_FLAG_MASK			(1<<1)
+#define M98925_IMONOVFL_FLAG_SHIFT			1
+#define M98925_IMONOVFL_FLAG_WIDTH			1
+#define M98925_VMONOVFL_FLAG_MASK			(1<<0)
+#define M98925_VMONOVFL_FLAG_SHIFT			0
+#define M98925_VMONOVFL_FLAG_WIDTH			1
+
+/* MAX98925_R00B_IRQ_ENABLE0 */
+#define M98925_THERMWARN_END_EN_MASK			(1<<3)
+#define M98925_THERMWARN_END_EN_SHIFT			3
+#define M98925_THERMWARN_END_EN_WIDTH			1
+#define M98925_THERMWARN_BGN_EN_MASK			(1<<2)
+#define M98925_THERMWARN_BGN_EN_SHIFT			2
+#define M98925_THERMWARN_BGN_EN_WIDTH			1
+#define M98925_THERMSHDN_END_EN_MASK			(1<<1)
+#define M98925_THERMSHDN_END_EN_SHIFT			1
+#define M98925_THERMSHDN_END_EN_WIDTH			1
+#define M98925_THERMSHDN_BGN_EN_MASK			(1<<0)
+#define M98925_THERMSHDN_BGN_EN_SHIFT			0
+#define M98925_THERMSHDN_BGN_EN_WIDTH			1
+
+/* MAX98925_R00C_IRQ_ENABLE1 */
+#define M98925_SPKCURNT_EN_MASK				(1<<5)
+#define M98925_SPKCURNT_EN_SHIFT			5
+#define M98925_SPKCURNT_EN_WIDTH			1
+#define M98925_WATCHFAIL_EN_MASK			(1<<4)
+#define M98925_WATCHFAIL_EN_SHIFT			4
+#define M98925_WATCHFAIL_EN_WIDTH			1
+#define M98925_ALCINFH_EN_MASK				(1<<3)
+#define M98925_ALCINFH_EN_SHIFT				3
+#define M98925_ALCINFH_EN_WIDTH				1
+#define M98925_ALCACT_EN_MASK				(1<<2)
+#define M98925_ALCACT_EN_SHIFT				2
+#define M98925_ALCACT_EN_WIDTH				1
+#define M98925_ALCMUT_EN_MASK				(1<<1)
+#define M98925_ALCMUT_EN_SHIFT				1
+#define M98925_ALCMUT_EN_WIDTH				1
+#define M98925_ALCP_EN_MASK					(1<<0)
+#define M98925_ALCP_EN_SHIFT				0
+#define M98925_ALCP_EN_WIDTH				1
+
+/* MAX98925_R00D_IRQ_ENABLE2 */
+#define M98925_SLOTOVRN_EN_MASK					(1<<6)
+#define M98925_SLOTOVRN_EN_SHIFT				6
+#define M98925_SLOTOVRN_EN_WIDTH				1
+#define M98925_INVALSLOT_EN_MASK				(1<<5)
+#define M98925_INVALSLOT_EN_SHIFT				5
+#define M98925_INVALSLOT_EN_WIDTH				1
+#define M98925_SLOTCNFLT_EN_MASK				(1<<4)
+#define M98925_SLOTCNFLT_EN_SHIFT				4
+#define M98925_SLOTCNFLT_EN_WIDTH				1
+#define M98925_VBSTOVFL_EN_MASK					(1<<3)
+#define M98925_VBSTOVFL_EN_SHIFT				3
+#define M98925_VBSTOVFL_EN_WIDTH				1
+#define M98925_VBATOVFL_EN_MASK					(1<<2)
+#define M98925_VBATOVFL_EN_SHIFT				2
+#define M98925_VBATOVFL_EN_WIDTH				1
+#define M98925_IMONOVFL_EN_MASK					(1<<1)
+#define M98925_IMONOVFL_EN_SHIFT				1
+#define M98925_IMONOVFL_EN_WIDTH				1
+#define M98925_VMONOVFL_EN_MASK					(1<<0)
+#define M98925_VMONOVFL_EN_SHIFT				0
+#define M98925_VMONOVFL_EN_WIDTH				1
+
+/* MAX98925_R00E_IRQ_CLEAR0 */
+#define M98925_THERMWARN_END_CLR_MASK			(1<<3)
+#define M98925_THERMWARN_END_CLR_SHIFT			3
+#define M98925_THERMWARN_END_CLR_WIDTH			1
+#define M98925_THERMWARN_BGN_CLR_MASK			(1<<2)
+#define M98925_THERMWARN_BGN_CLR_SHIFT			2
+#define M98925_THERMWARN_BGN_CLR_WIDTH			1
+#define M98925_THERMSHDN_END_CLR_MASK			(1<<1)
+#define M98925_THERMSHDN_END_CLR_SHIFT			1
+#define M98925_THERMSHDN_END_CLR_WIDTH			1
+#define M98925_THERMSHDN_BGN_CLR_MASK			(1<<0)
+#define M98925_THERMSHDN_BGN_CLR_SHIFT			0
+#define M98925_THERMSHDN_BGN_CLR_WIDTH			1
+
+/* MAX98925_R00F_IRQ_CLEAR1 */
+#define M98925_SPKCURNT_CLR_MASK				(1<<5)
+#define M98925_SPKCURNT_CLR_SHIFT				5
+#define M98925_SPKCURNT_CLR_WIDTH				1
+#define M98925_WATCHFAIL_CLR_MASK				(1<<4)
+#define M98925_WATCHFAIL_CLR_SHIFT				4
+#define M98925_WATCHFAIL_CLR_WIDTH				1
+#define M98925_ALCINFH_CLR_MASK					(1<<3)
+#define M98925_ALCINFH_CLR_SHIFT				3
+#define M98925_ALCINFH_CLR_WIDTH				1
+#define M98925_ALCACT_CLR_MASK					(1<<2)
+#define M98925_ALCACT_CLR_SHIFT					2
+#define M98925_ALCACT_CLR_WIDTH					1
+#define M98925_ALCMUT_CLR_MASK					(1<<1)
+#define M98925_ALCMUT_CLR_SHIFT					1
+#define M98925_ALCMUT_CLR_WIDTH					1
+#define M98925_ALCP_CLR_MASK					(1<<0)
+#define M98925_ALCP_CLR_SHIFT					0
+#define M98925_ALCP_CLR_WIDTH					1
+
+/* MAX98925_R010_IRQ_CLEAR2 */
+#define M98925_SLOTOVRN_CLR_MASK				(1<<6)
+#define M98925_SLOTOVRN_CLR_SHIFT				6
+#define M98925_SLOTOVRN_CLR_WIDTH				1
+#define M98925_INVALSLOT_CLR_MASK				(1<<5)
+#define M98925_INVALSLOT_CLR_SHIFT				5
+#define M98925_INVALSLOT_CLR_WIDTH				1
+#define M98925_SLOTCNFLT_CLR_MASK				(1<<4)
+#define M98925_SLOTCNFLT_CLR_SHIFT				4
+#define M98925_SLOTCNFLT_CLR_WIDTH				1
+#define M98925_VBSTOVFL_CLR_MASK				(1<<3)
+#define M98925_VBSTOVFL_CLR_SHIFT				3
+#define M98925_VBSTOVFL_CLR_WIDTH				1
+#define M98925_VBATOVFL_CLR_MASK				(1<<2)
+#define M98925_VBATOVFL_CLR_SHIFT				2
+#define M98925_VBATOVFL_CLR_WIDTH				1
+#define M98925_IMONOVFL_CLR_MASK				(1<<1)
+#define M98925_IMONOVFL_CLR_SHIFT				1
+#define M98925_IMONOVFL_CLR_WIDTH				1
+#define M98925_VMONOVFL_CLR_MASK				(1<<0)
+#define M98925_VMONOVFL_CLR_SHIFT				0
+#define M98925_VMONOVFL_CLR_WIDTH				1
+
+/* MAX98925_R011_MAP0 */
+#define M98925_ER_THERMWARN_EN_MASK				(1<<7)
+#define M98925_ER_THERMWARN_EN_SHIFT			7
+#define M98925_ER_THERMWARN_EN_WIDTH			1
+#define M98925_ER_THERMWARN_MAP_MASK			(0x07<<4)
+#define M98925_ER_THERMWARN_MAP_SHIFT			4
+#define M98925_ER_THERMWARN_MAP_WIDTH			3
+
+/* MAX98925_R012_MAP1 */
+#define M98925_ER_ALCMUT_EN_MASK				(1<<7)
+#define M98925_ER_ALCMUT_EN_SHIFT				7
+#define M98925_ER_ALCMUT_EN_WIDTH				1
+#define M98925_ER_ALCMUT_MAP_MASK				(0x07<<4)
+#define M98925_ER_ALCMUT_MAP_SHIFT				4
+#define M98925_ER_ALCMUT_MAP_WIDTH				3
+#define M98925_ER_ALCP_EN_MASK					(1<<3)
+#define M98925_ER_ALCP_EN_SHIFT					3
+#define M98925_ER_ALCP_EN_WIDTH					1
+#define M98925_ER_ALCP_MAP_MASK					(0x07<<0)
+#define M98925_ER_ALCP_MAP_SHIFT				0
+#define M98925_ER_ALCP_MAP_WIDTH				3
+
+/* MAX98925_R013_MAP2 */
+#define M98925_ER_ALCINFH_EN_MASK				(1<<7)
+#define M98925_ER_ALCINFH_EN_SHIFT				7
+#define M98925_ER_ALCINFH_EN_WIDTH				1
+#define M98925_ER_ALCINFH_MAP_MASK				(0x07<<4)
+#define M98925_ER_ALCINFH_MAP_SHIFT				4
+#define M98925_ER_ALCINFH_MAP_WIDTH				3
+#define M98925_ER_ALCACT_EN_MASK				(1<<3)
+#define M98925_ER_ALCACT_EN_SHIFT				3
+#define M98925_ER_ALCACT_EN_WIDTH				1
+#define M98925_ER_ALCACT_MAP_MASK				(0x07<<0)
+#define M98925_ER_ALCACT_MAP_SHIFT				0
+#define M98925_ER_ALCACT_MAP_WIDTH				3
+
+/* MAX98925_R014_MAP3 */
+#define M98925_ER_SPKCURNT_EN_MASK				(1<<7)
+#define M98925_ER_SPKCURNT_EN_SHIFT				7
+#define M98925_ER_SPKCURNT_EN_WIDTH				1
+#define M98925_ER_SPKCURNT_MAP_MASK				(0x07<<4)
+#define M98925_ER_SPKCURNT_MAP_SHIFT			4
+#define M98925_ER_SPKCURNT_MAP_WIDTH			3
+
+/* MAX98925_R015_MAP4 */
+/* RESERVED */
+
+/* MAX98925_R016_MAP5 */
+#define M98925_ER_IMONOVFL_EN_MASK				(1<<7)
+#define M98925_ER_IMONOVFL_EN_SHIFT				7
+#define M98925_ER_IMONOVFL_EN_WIDTH				1
+#define M98925_ER_IMONOVFL_MAP_MASK				(0x07<<4)
+#define M98925_ER_IMONOVFL_MAP_SHIFT			4
+#define M98925_ER_IMONOVFL_MAP_WIDTH			3
+#define M98925_ER_VMONOVFL_EN_MASK				(1<<3)
+#define M98925_ER_VMONOVFL_EN_SHIFT				3
+#define M98925_ER_VMONOVFL_EN_WIDTH				1
+#define M98925_ER_VMONOVFL_MAP_MASK				(0x07<<0)
+#define M98925_ER_VMONOVFL_MAP_SHIFT			0
+#define M98925_ER_VMONOVFL_MAP_WIDTH			3
+
+/* MAX98925_R017_MAP6 */
+#define M98925_ER_VBSTOVFL_EN_MASK				(1<<7)
+#define M98925_ER_VBSTOVFL_EN_SHIFT				7
+#define M98925_ER_VBSTOVFL_EN_WIDTH				1
+#define M98925_ER_VBSTOVFL_MAP_MASK				(0x07<<4)
+#define M98925_ER_VBSTOVFL_MAP_SHIFT			4
+#define M98925_ER_VBSTOVFL_MAP_WIDTH			3
+#define M98925_ER_VBATOVFL_EN_MASK				(1<<3)
+#define M98925_ER_VBATOVFL_EN_SHIFT				3
+#define M98925_ER_VBATOVFL_EN_WIDTH				1
+#define M98925_ER_VBATOVFL_MAP_MASK				(0x07<<0)
+#define M98925_ER_VBATOVFL_MAP_SHIFT			0
+#define M98925_ER_VBATOVFL_MAP_WIDTH			3
+
+/* MAX98925_R018_MAP7 */
+#define M98925_ER_INVALSLOT_EN_MASK				(1<<7)
+#define M98925_ER_INVALSLOT_EN_SHIFT			7
+#define M98925_ER_INVALSLOT_EN_WIDTH			1
+#define M98925_ER_INVALSLOT_MAP_MASK			(0x07<<4)
+#define M98925_ER_INVALSLOT_MAP_SHIFT			4
+#define M98925_ER_INVALSLOT_MAP_WIDTH			3
+#define M98925_ER_SLOTCNFLT_EN_MASK				(1<<3)
+#define M98925_ER_SLOTCNFLT_EN_SHIFT			3
+#define M98925_ER_SLOTCNFLT_EN_WIDTH			1
+#define M98925_ER_SLOTCNFLT_MAP_MASK			(0x07<<0)
+#define M98925_ER_SLOTCNFLT_MAP_SHIFT			0
+#define M98925_ER_SLOTCNFLT_MAP_WIDTH			3
+
+/* MAX98925_R019_MAP8 */
+#define M98925_ER_SLOTOVRN_EN_MASK	(1<<3)
+#define M98925_ER_SLOTOVRN_EN_SHIFT	3
+#define M98925_ER_SLOTOVRN_EN_WIDTH	1
+#define M98925_ER_SLOTOVRN_MAP_MASK	(0x07<<0)
+#define M98925_ER_SLOTOVRN_MAP_SHIFT	0
+#define M98925_ER_SLOTOVRN_MAP_WIDTH	3
+
+/* MAX98925_R01A_DAI_CLK_MODE1 */
+#define M98925_DAI_CLK_SOURCE_MASK	(1<<6)
+#define M98925_DAI_CLK_SOURCE_SHIFT	6
+#define M98925_DAI_CLK_SOURCE_WIDTH	1
+#define M98925_MDLL_MULT_MASK		(0x0F<<0)
+#define M98925_MDLL_MULT_SHIFT		0
+#define M98925_MDLL_MULT_WIDTH		4
+
+#define M98925_MDLL_MULT_MCLKx8		6
+#define M98925_MDLL_MULT_MCLKx16	8
+
+/* MAX98925_R01B_DAI_CLK_MODE2 */
+#define M98925_DAI_SR_MASK			(0x0F<<4)
+#define M98925_DAI_SR_SHIFT			4
+#define M98925_DAI_SR_WIDTH			4
+#define M98925_DAI_MAS_MASK			(1<<3)
+#define M98925_DAI_MAS_SHIFT			3
+#define M98925_DAI_MAS_WIDTH			1
+#define M98925_DAI_BSEL_MASK			(0x07<<0)
+#define M98925_DAI_BSEL_SHIFT			0
+#define M98925_DAI_BSEL_WIDTH			3
+
+#define M98925_DAI_BSEL_32 (0 << M98925_DAI_BSEL_SHIFT)
+#define M98925_DAI_BSEL_48 (1 << M98925_DAI_BSEL_SHIFT)
+#define M98925_DAI_BSEL_64 (2 << M98925_DAI_BSEL_SHIFT)
+#define M98925_DAI_BSEL_256 (6 << M98925_DAI_BSEL_SHIFT)
+
+/* MAX98925_R01C_DAI_CLK_DIV_M_MSBS */
+#define M98925_DAI_M_MSBS_MASK					(0xFF<<0)
+#define M98925_DAI_M_MSBS_SHIFT					0
+#define M98925_DAI_M_MSBS_WIDTH					8
+
+/* MAX98925_R01D_DAI_CLK_DIV_M_LSBS */
+#define M98925_DAI_M_LSBS_MASK					(0xFF<<0)
+#define M98925_DAI_M_LSBS_SHIFT					0
+#define M98925_DAI_M_LSBS_WIDTH					8
+
+/* MAX98925_R01E_DAI_CLK_DIV_N_MSBS */
+#define M98925_DAI_N_MSBS_MASK					(0x7F<<0)
+#define M98925_DAI_N_MSBS_SHIFT					0
+#define M98925_DAI_N_MSBS_WIDTH					7
+
+/* MAX98925_R01F_DAI_CLK_DIV_N_LSBS */
+#define M98925_DAI_N_LSBS_MASK					(0xFF<<0)
+#define M98925_DAI_N_LSBS_SHIFT					0
+#define M98925_DAI_N_LSBS_WIDTH					8
+
+/* MAX98925_R020_FORMAT */
+#define M98925_DAI_CHANSZ_MASK					(0x03<<6)
+#define M98925_DAI_CHANSZ_SHIFT					6
+#define M98925_DAI_CHANSZ_WIDTH					2
+#define M98925_DAI_EXTBCLK_HIZ_MASK				(1<<4)
+#define M98925_DAI_EXTBCLK_HIZ_SHIFT			4
+#define M98925_DAI_EXTBCLK_HIZ_WIDTH			1
+#define M98925_DAI_WCI_MASK						(1<<3)
+#define M98925_DAI_WCI_SHIFT					3
+#define M98925_DAI_WCI_WIDTH					1
+#define M98925_DAI_BCI_MASK						(1<<2)
+#define M98925_DAI_BCI_SHIFT					2
+#define M98925_DAI_BCI_WIDTH					1
+#define M98925_DAI_DLY_MASK						(1<<1)
+#define M98925_DAI_DLY_SHIFT					1
+#define M98925_DAI_DLY_WIDTH					1
+#define M98925_DAI_TDM_MASK						(1<<0)
+#define M98925_DAI_TDM_SHIFT					0
+#define M98925_DAI_TDM_WIDTH					1
+
+#define M98925_DAI_CHANSZ_16 (1 << M98925_DAI_CHANSZ_SHIFT)
+#define M98925_DAI_CHANSZ_24 (2 << M98925_DAI_CHANSZ_SHIFT)
+#define M98925_DAI_CHANSZ_32 (3 << M98925_DAI_CHANSZ_SHIFT)
+
+/* MAX98925_R021_TDM_SLOT_SELECT */
+#define M98925_DAI_DO_EN_MASK					(1<<7)
+#define M98925_DAI_DO_EN_SHIFT					7
+#define M98925_DAI_DO_EN_WIDTH					1
+#define M98925_DAI_DIN_EN_MASK					(1<<6)
+#define M98925_DAI_DIN_EN_SHIFT					6
+#define M98925_DAI_DIN_EN_WIDTH					1
+#define M98925_DAI_INR_SOURCE_MASK				(0x07<<3)
+#define M98925_DAI_INR_SOURCE_SHIFT				3
+#define M98925_DAI_INR_SOURCE_WIDTH				3
+#define M98925_DAI_INL_SOURCE_MASK				(0x07<<0)
+#define M98925_DAI_INL_SOURCE_SHIFT				0
+#define M98925_DAI_INL_SOURCE_WIDTH				3
+
+/* MAX98925_R022_DOUT_CFG_VMON */
+#define M98925_DAI_VMON_EN_MASK					(1<<5)
+#define M98925_DAI_VMON_EN_SHIFT				5
+#define M98925_DAI_VMON_EN_WIDTH				1
+#define M98925_DAI_VMON_SLOT_MASK				(0x1F<<0)
+#define M98925_DAI_VMON_SLOT_SHIFT				0
+#define M98925_DAI_VMON_SLOT_WIDTH				5
+
+#define M98925_DAI_VMON_SLOT_00_01 (0 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_01_02 (1 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_02_03 (2 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_03_04 (3 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_04_05 (4 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_05_06 (5 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_06_07 (6 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_07_08 (7 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_08_09 (8 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_09_0A (9 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0A_0B (10 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0B_0C (11 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0C_0D (12 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0D_0E (13 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0E_0F (14 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_0F_10 (15 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_10_11 (16 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_11_12 (17 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_12_13 (18 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_13_14 (19 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_14_15 (20 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_15_16 (21 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_16_17 (22 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_17_18 (23 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_18_19 (24 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_19_1A (25 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1A_1B (26 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1B_1C (27 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1C_1D (28 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1D_1E (29 << M98925_DAI_VMON_SLOT_SHIFT)
+#define M98925_DAI_VMON_SLOT_1E_1F (30 << M98925_DAI_VMON_SLOT_SHIFT)
+
+/* MAX98925_R023_DOUT_CFG_IMON */
+#define M98925_DAI_IMON_EN_MASK					(1<<5)
+#define M98925_DAI_IMON_EN_SHIFT				5
+#define M98925_DAI_IMON_EN_WIDTH				1
+#define M98925_DAI_IMON_SLOT_MASK				(0x1F<<0)
+#define M98925_DAI_IMON_SLOT_SHIFT				0
+#define M98925_DAI_IMON_SLOT_WIDTH				5
+
+#define M98925_DAI_IMON_SLOT_00_01 (0 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_01_02 (1 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_02_03 (2 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_03_04 (3 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_04_05 (4 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_05_06 (5 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_06_07 (6 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_07_08 (7 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_08_09 (8 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_09_0A (9 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0A_0B (10 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0B_0C (11 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0C_0D (12 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0D_0E (13 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0E_0F (14 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_0F_10 (15 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_10_11 (16 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_11_12 (17 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_12_13 (18 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_13_14 (19 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_14_15 (20 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_15_16 (21 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_16_17 (22 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_17_18 (23 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_18_19 (24 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_19_1A (25 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1A_1B (26 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1B_1C (27 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1C_1D (28 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1D_1E (29 << M98925_DAI_IMON_SLOT_SHIFT)
+#define M98925_DAI_IMON_SLOT_1E_1F (30 << M98925_DAI_IMON_SLOT_SHIFT)
+
+/* MAX98925_R024_DOUT_CFG_VBAT */
+#define M98925_DAI_VBAT_EN_MASK					(1<<5)
+#define M98925_DAI_VBAT_EN_SHIFT				5
+#define M98925_DAI_VBAT_EN_WIDTH				1
+#define M98925_DAI_VBAT_SLOT_MASK				(0x1F<<0)
+#define M98925_DAI_VBAT_SLOT_SHIFT				0
+#define M98925_DAI_VBAT_SLOT_WIDTH				5
+
+/* MAX98925_R025_DOUT_CFG_VBST */
+#define M98925_DAI_VBST_EN_MASK					(1<<5)
+#define M98925_DAI_VBST_EN_SHIFT				5
+#define M98925_DAI_VBST_EN_WIDTH				1
+#define M98925_DAI_VBST_SLOT_MASK				(0x1F<<0)
+#define M98925_DAI_VBST_SLOT_SHIFT				0
+#define M98925_DAI_VBST_SLOT_WIDTH				5
+
+/* MAX98925_R026_DOUT_CFG_FLAG */
+#define M98925_DAI_FLAG_EN_MASK					(1<<5)
+#define M98925_DAI_FLAG_EN_SHIFT				5
+#define M98925_DAI_FLAG_EN_WIDTH				1
+#define M98925_DAI_FLAG_SLOT_MASK				(0x1F<<0)
+#define M98925_DAI_FLAG_SLOT_SHIFT				0
+#define M98925_DAI_FLAG_SLOT_WIDTH				5
+
+/* MAX98925_R027_DOUT_HIZ_CFG1 */
+#define M98925_DAI_SLOT_HIZ_CFG1_MASK			(0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG1_SHIFT			0
+#define M98925_DAI_SLOT_HIZ_CFG1_WIDTH			8
+
+/* MAX98925_R028_DOUT_HIZ_CFG2 */
+#define M98925_DAI_SLOT_HIZ_CFG2_MASK			(0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG2_SHIFT			0
+#define M98925_DAI_SLOT_HIZ_CFG2_WIDTH			8
+
+/* MAX98925_R029_DOUT_HIZ_CFG3 */
+#define M98925_DAI_SLOT_HIZ_CFG3_MASK			(0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG3_SHIFT			0
+#define M98925_DAI_SLOT_HIZ_CFG3_WIDTH			8
+
+/* MAX98925_R02A_DOUT_HIZ_CFG4 */
+#define M98925_DAI_SLOT_HIZ_CFG4_MASK			(0xFF<<0)
+#define M98925_DAI_SLOT_HIZ_CFG4_SHIFT			0
+#define M98925_DAI_SLOT_HIZ_CFG4_WIDTH			8
+
+/* MAX98925_R02B_DOUT_DRV_STRENGTH */
+#define M98925_DAI_OUT_DRIVE_MASK				(0x03<<0)
+#define M98925_DAI_OUT_DRIVE_SHIFT				0
+#define M98925_DAI_OUT_DRIVE_WIDTH				2
+
+/* MAX98925_R02C_FILTERS */
+#define M98925_ADC_DITHER_EN_MASK				(1<<7)
+#define M98925_ADC_DITHER_EN_SHIFT				7
+#define M98925_ADC_DITHER_EN_WIDTH				1
+#define M98925_IV_DCB_EN_MASK					(1<<6)
+#define M98925_IV_DCB_EN_SHIFT					6
+#define M98925_IV_DCB_EN_WIDTH					1
+#define M98925_DAC_DITHER_EN_MASK				(1<<4)
+#define M98925_DAC_DITHER_EN_SHIFT				4
+#define M98925_DAC_DITHER_EN_WIDTH				1
+#define M98925_DAC_FILTER_MODE_MASK				(1<<3)
+#define M98925_DAC_FILTER_MODE_SHIFT			3
+#define M98925_DAC_FILTER_MODE_WIDTH			1
+#define M98925_DAC_HPF_MASK				(0x07<<0)
+#define M98925_DAC_HPF_SHIFT					0
+#define M98925_DAC_HPF_WIDTH					3
+#define M98925_DAC_HPF_DISABLE		(0 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_DC_BLOCK		(1 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_100		(2 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_200		(3 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_400		(4 << M98925_DAC_HPF_SHIFT)
+#define M98925_DAC_HPF_EN_800		(5 << M98925_DAC_HPF_SHIFT)
+
+/* MAX98925_R02D_GAIN */
+#define M98925_DAC_IN_SEL_MASK					(0x03<<5)
+#define M98925_DAC_IN_SEL_SHIFT					5
+#define M98925_DAC_IN_SEL_WIDTH					2
+#define M98925_SPK_GAIN_MASK					(0x1F<<0)
+#define M98925_SPK_GAIN_SHIFT					0
+#define M98925_SPK_GAIN_WIDTH					5
+
+#define M98925_DAC_IN_SEL_LEFT_DAI (0 << M98925_DAC_IN_SEL_SHIFT)
+#define M98925_DAC_IN_SEL_RIGHT_DAI (1 << M98925_DAC_IN_SEL_SHIFT)
+#define M98925_DAC_IN_SEL_SUMMED_DAI (2 << M98925_DAC_IN_SEL_SHIFT)
+#define M98925_DAC_IN_SEL_DIV2_SUMMED_DAI (3 << M98925_DAC_IN_SEL_SHIFT)
+
+/* MAX98925_R02E_GAIN_RAMPING */
+#define M98925_SPK_RMP_EN_MASK		(1<<1)
+#define M98925_SPK_RMP_EN_SHIFT		1
+#define M98925_SPK_RMP_EN_WIDTH		1
+#define M98925_SPK_ZCD_EN_MASK		(1<<0)
+#define M98925_SPK_ZCD_EN_SHIFT		0
+#define M98925_SPK_ZCD_EN_WIDTH		1
+
+/* MAX98925_R02F_SPK_AMP */
+#define M98925_SPK_MODE_MASK		(1<<0)
+#define M98925_SPK_MODE_SHIFT		0
+#define M98925_SPK_MODE_WIDTH		1
+
+/* MAX98925_R030_THRESHOLD */
+#define M98925_ALC_EN_MASK			(1<<5)
+#define M98925_ALC_EN_SHIFT			5
+#define M98925_ALC_EN_WIDTH			1
+#define M98925_ALC_TH_MASK			(0x1F<<0)
+#define M98925_ALC_TH_SHIFT			0
+#define M98925_ALC_TH_WIDTH			5
+
+/* MAX98925_R031_ALC_ATTACK */
+#define M98925_ALC_ATK_STEP_MASK	(0x0F<<4)
+#define M98925_ALC_ATK_STEP_SHIFT	4
+#define M98925_ALC_ATK_STEP_WIDTH	4
+#define M98925_ALC_ATK_RATE_MASK	(0x7<<0)
+#define M98925_ALC_ATK_RATE_SHIFT	0
+#define M98925_ALC_ATK_RATE_WIDTH	3
+
+/* MAX98925_R032_ALC_ATTEN_RLS */
+#define M98925_ALC_MAX_ATTEN_MASK	(0x0F<<4)
+#define M98925_ALC_MAX_ATTEN_SHIFT	4
+#define M98925_ALC_MAX_ATTEN_WIDTH	4
+#define M98925_ALC_RLS_RATE_MASK	(0x7<<0)
+#define M98925_ALC_RLS_RATE_SHIFT	0
+#define M98925_ALC_RLS_RATE_WIDTH	3
+
+/* MAX98925_R033_ALC_HOLD_RLS */
+#define M98925_ALC_RLS_TGR_MASK		(1<<0)
+#define M98925_ALC_RLS_TGR_SHIFT	0
+#define M98925_ALC_RLS_TGR_WIDTH	1
+
+/* MAX98925_R034_ALC_CONFIGURATION */
+#define M98925_ALC_MUTE_EN_MASK		(1<<7)
+#define M98925_ALC_MUTE_EN_SHIFT	7
+#define M98925_ALC_MUTE_EN_WIDTH	1
+#define M98925_ALC_MUTE_DLY_MASK	(0x07<<4)
+#define M98925_ALC_MUTE_DLY_SHIFT	4
+#define M98925_ALC_MUTE_DLY_WIDTH	3
+#define M98925_ALC_RLS_DBT_MASK		(0x07<<0)
+#define M98925_ALC_RLS_DBT_SHIFT	0
+#define M98925_ALC_RLS_DBT_WIDTH	3
+
+/* MAX98925_R035_BOOST_CONVERTER */
+#define M98925_BST_SYNC_MASK		(1<<7)
+#define M98925_BST_SYNC_SHIFT		7
+#define M98925_BST_SYNC_WIDTH		1
+#define M98925_BST_PHASE_MASK		(0x03<<4)
+#define M98925_BST_PHASE_SHIFT		4
+#define M98925_BST_PHASE_WIDTH		2
+#define M98925_BST_SKIP_MODE_MASK	(0x03<<0)
+#define M98925_BST_SKIP_MODE_SHIFT	0
+#define M98925_BST_SKIP_MODE_WIDTH	2
+
+/* MAX98925_R036_BLOCK_ENABLE */
+#define M98925_BST_EN_MASK			(1<<7)
+#define M98925_BST_EN_SHIFT			7
+#define M98925_BST_EN_WIDTH			1
+#define M98925_WATCH_EN_MASK		(1<<6)
+#define M98925_WATCH_EN_SHIFT		6
+#define M98925_WATCH_EN_WIDTH		1
+#define M98925_CLKMON_EN_MASK		(1<<5)
+#define M98925_CLKMON_EN_SHIFT		5
+#define M98925_CLKMON_EN_WIDTH		1
+#define M98925_SPK_EN_MASK			(1<<4)
+#define M98925_SPK_EN_SHIFT			4
+#define M98925_SPK_EN_WIDTH			1
+#define M98925_ADC_VBST_EN_MASK		(1<<3)
+#define M98925_ADC_VBST_EN_SHIFT	3
+#define M98925_ADC_VBST_EN_WIDTH	1
+#define M98925_ADC_VBAT_EN_MASK		(1<<2)
+#define M98925_ADC_VBAT_EN_SHIFT	2
+#define M98925_ADC_VBAT_EN_WIDTH	1
+#define M98925_ADC_IMON_EN_MASK		(1<<1)
+#define M98925_ADC_IMON_EN_SHIFT	1
+#define M98925_ADC_IMON_EN_WIDTH	1
+#define M98925_ADC_VMON_EN_MASK		(1<<0)
+#define M98925_ADC_VMON_EN_SHIFT	0
+#define M98925_ADC_VMON_EN_WIDTH	1
+
+/* MAX98925_R037_CONFIGURATION */
+#define M98925_BST_VOUT_MASK		(0x0F<<4)
+#define M98925_BST_VOUT_SHIFT		4
+#define M98925_BST_VOUT_WIDTH		4
+#define M98925_THERMWARN_LEVEL_MASK	(0x03<<2)
+#define M98925_THERMWARN_LEVEL_SHIFT			2
+#define M98925_THERMWARN_LEVEL_WIDTH			2
+#define M98925_WATCH_TIME_MASK			(0x03<<0)
+#define M98925_WATCH_TIME_SHIFT			0
+#define M98925_WATCH_TIME_WIDTH			2
+
+/* MAX98925_R038_GLOBAL_ENABLE */
+#define M98925_EN_MASK			(1<<7)
+#define M98925_EN_SHIFT			7
+#define M98925_EN_WIDTH			1
+
+/* MAX98925_R03A_BOOST_LIMITER */
+#define M98925_BST_ILIM_MASK	(0x1F<<3)
+#define M98925_BST_ILIM_SHIFT	3
+#define M98925_BST_ILIM_WIDTH	5
+
+/* MAX98925_R0FF_VERSION */
+#define M98925_REV_ID_MASK	(0xFF<<0)
+#define M98925_REV_ID_SHIFT	0
+#define M98925_REV_ID_WIDTH	8
+
+struct max98925_priv {
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct max98925_pdata *pdata;
+	unsigned int sysclk;
+	unsigned int v_slot;
+	unsigned int i_slot;
+	unsigned int spk_gain;
+	unsigned int ch_size;
+};
+#endif
diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c
new file mode 100644
index 0000000..d9b1f68
--- /dev/null
+++ b/sound/soc/codecs/max98926.c
@@ -0,0 +1,604 @@
+/*
+ * max98926.c -- ALSA SoC MAX98926 driver
+ * Copyright 2013-15 Maxim Integrated Products
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "max98926.h"
+
+static const char * const max98926_boost_voltage_txt[] = {
+	"8.5V", "8.25V", "8.0V", "7.75V", "7.5V", "7.25V", "7.0V", "6.75V",
+	"6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V"
+};
+
+static const char * const max98926_boost_current_txt[] = {
+	"0.6", "0.8", "1.0", "1.2", "1.4", "1.6", "1.8", "2.0",
+	"2.2", "2.4", "2.6", "2.8", "3.2", "3.6", "4.0", "4.4"
+};
+
+static const char *const max98926_dai_txt[] = {
+	"Left", "Right", "LeftRight", "LeftRightDiv2",
+};
+
+static const char *const max98926_pdm_ch_text[] = {
+	"Current", "Voltage",
+};
+
+static const char *const max98926_hpf_cutoff_txt[] = {
+	"Disable", "DC Block", "100Hz",
+	"200Hz", "400Hz", "800Hz",
+};
+
+static const struct reg_default max98926_reg[] = {
+	{ 0x0B, 0x00 }, /* IRQ Enable0 */
+	{ 0x0C, 0x00 }, /* IRQ Enable1 */
+	{ 0x0D, 0x00 }, /* IRQ Enable2 */
+	{ 0x0E, 0x00 }, /* IRQ Clear0 */
+	{ 0x0F, 0x00 }, /* IRQ Clear1 */
+	{ 0x10, 0x00 }, /* IRQ Clear2 */
+	{ 0x11, 0xC0 }, /* Map0 */
+	{ 0x12, 0x00 }, /* Map1 */
+	{ 0x13, 0x00 }, /* Map2 */
+	{ 0x14, 0xF0 }, /* Map3 */
+	{ 0x15, 0x00 }, /* Map4 */
+	{ 0x16, 0xAB }, /* Map5 */
+	{ 0x17, 0x89 }, /* Map6 */
+	{ 0x18, 0x00 }, /* Map7 */
+	{ 0x19, 0x00 }, /* Map8 */
+	{ 0x1A, 0x04 }, /* DAI Clock Mode 1 */
+	{ 0x1B, 0x00 }, /* DAI Clock Mode 2 */
+	{ 0x1C, 0x00 }, /* DAI Clock Divider Denominator MSBs */
+	{ 0x1D, 0x00 }, /* DAI Clock Divider Denominator LSBs */
+	{ 0x1E, 0xF0 }, /* DAI Clock Divider Numerator MSBs */
+	{ 0x1F, 0x00 }, /* DAI Clock Divider Numerator LSBs */
+	{ 0x20, 0x50 }, /* Format */
+	{ 0x21, 0x00 }, /* TDM Slot Select */
+	{ 0x22, 0x00 }, /* DOUT Configuration VMON */
+	{ 0x23, 0x00 }, /* DOUT Configuration IMON */
+	{ 0x24, 0x00 }, /* DOUT Configuration VBAT */
+	{ 0x25, 0x00 }, /* DOUT Configuration VBST */
+	{ 0x26, 0x00 }, /* DOUT Configuration FLAG */
+	{ 0x27, 0xFF }, /* DOUT HiZ Configuration 1 */
+	{ 0x28, 0xFF }, /* DOUT HiZ Configuration 2 */
+	{ 0x29, 0xFF }, /* DOUT HiZ Configuration 3 */
+	{ 0x2A, 0xFF }, /* DOUT HiZ Configuration 4 */
+	{ 0x2B, 0x02 }, /* DOUT Drive Strength */
+	{ 0x2C, 0x90 }, /* Filters */
+	{ 0x2D, 0x00 }, /* Gain */
+	{ 0x2E, 0x02 }, /* Gain Ramping */
+	{ 0x2F, 0x00 }, /* Speaker Amplifier */
+	{ 0x30, 0x0A }, /* Threshold */
+	{ 0x31, 0x00 }, /* ALC Attack */
+	{ 0x32, 0x80 }, /* ALC Atten and Release */
+	{ 0x33, 0x00 }, /* ALC Infinite Hold Release */
+	{ 0x34, 0x92 }, /* ALC Configuration */
+	{ 0x35, 0x01 }, /* Boost Converter */
+	{ 0x36, 0x00 }, /* Block Enable */
+	{ 0x37, 0x00 }, /* Configuration */
+	{ 0x38, 0x00 }, /* Global Enable */
+	{ 0x3A, 0x00 }, /* Boost Limiter */
+};
+
+static const struct soc_enum max98926_voltage_enum[] = {
+	SOC_ENUM_SINGLE(MAX98926_DAI_CLK_DIV_N_LSBS, 0,
+		ARRAY_SIZE(max98926_pdm_ch_text),
+		max98926_pdm_ch_text),
+};
+
+static const struct snd_kcontrol_new max98926_voltage_control =
+	SOC_DAPM_ENUM("Route", max98926_voltage_enum);
+
+static const struct soc_enum max98926_current_enum[] = {
+	SOC_ENUM_SINGLE(MAX98926_DAI_CLK_DIV_N_LSBS,
+		MAX98926_PDM_SOURCE_1_SHIFT,
+		ARRAY_SIZE(max98926_pdm_ch_text),
+		max98926_pdm_ch_text),
+};
+
+static const struct snd_kcontrol_new max98926_current_control =
+	SOC_DAPM_ENUM("Route", max98926_current_enum);
+
+static const struct snd_kcontrol_new max98926_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PCM Single Switch", MAX98926_SPK_AMP,
+		MAX98926_INSELECT_MODE_SHIFT, 0, 0),
+	SOC_DAPM_SINGLE("PDM Single Switch", MAX98926_SPK_AMP,
+		MAX98926_INSELECT_MODE_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new max98926_dai_controls[] = {
+	SOC_DAPM_SINGLE("Left", MAX98926_GAIN,
+		MAX98926_DAC_IN_SEL_SHIFT, 0, 0),
+	SOC_DAPM_SINGLE("Right", MAX98926_GAIN,
+		MAX98926_DAC_IN_SEL_SHIFT, 1, 0),
+	SOC_DAPM_SINGLE("LeftRight", MAX98926_GAIN,
+		MAX98926_DAC_IN_SEL_SHIFT, 2, 0),
+	SOC_DAPM_SINGLE("(Left+Right)/2 Switch", MAX98926_GAIN,
+		MAX98926_DAC_IN_SEL_SHIFT, 3, 0),
+};
+
+static const struct snd_soc_dapm_widget max98926_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0,
+		SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("Amp Enable", NULL, MAX98926_BLOCK_ENABLE,
+		MAX98926_SPK_EN_SHIFT, 0),
+	SND_SOC_DAPM_SUPPLY("Global Enable", MAX98926_GLOBAL_ENABLE,
+		MAX98926_EN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VI Enable", MAX98926_BLOCK_ENABLE,
+		MAX98926_ADC_IMON_EN_WIDTH |
+		MAX98926_ADC_VMON_EN_SHIFT,
+		0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST Enable", MAX98926_BLOCK_ENABLE,
+		MAX98926_BST_EN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("BE_OUT"),
+	SND_SOC_DAPM_MIXER("PCM Sel", MAX98926_SPK_AMP,
+		MAX98926_INSELECT_MODE_SHIFT, 0,
+		&max98926_mixer_controls[0],
+		ARRAY_SIZE(max98926_mixer_controls)),
+	SND_SOC_DAPM_MIXER("DAI Sel",
+		MAX98926_GAIN, MAX98926_DAC_IN_SEL_SHIFT, 0,
+		&max98926_dai_controls[0],
+		ARRAY_SIZE(max98926_dai_controls)),
+	SND_SOC_DAPM_MUX("PDM CH1 Source",
+		MAX98926_DAI_CLK_DIV_N_LSBS,
+		MAX98926_PDM_CURRENT_SHIFT,
+		0, &max98926_current_control),
+	SND_SOC_DAPM_MUX("PDM CH0 Source",
+		MAX98926_DAI_CLK_DIV_N_LSBS,
+		MAX98926_PDM_VOLTAGE_SHIFT,
+		0, &max98926_voltage_control),
+};
+
+static const struct snd_soc_dapm_route max98926_audio_map[] = {
+	{"VI Enable", NULL, "DAI_OUT"},
+	{"DAI Sel", "Left", "VI Enable"},
+	{"DAI Sel", "Right", "VI Enable"},
+	{"DAI Sel", "LeftRight", "VI Enable"},
+	{"DAI Sel", "LeftRightDiv2", "VI Enable"},
+	{"PCM Sel", "PCM", "DAI Sel"},
+
+	{"PDM CH1 Source", "Current", "DAI_OUT"},
+	{"PDM CH1 Source", "Voltage", "DAI_OUT"},
+	{"PDM CH0 Source", "Current", "DAI_OUT"},
+	{"PDM CH0 Source", "Voltage", "DAI_OUT"},
+	{"PCM Sel", "Analog", "PDM CH1 Source"},
+	{"PCM Sel", "Analog", "PDM CH0 Source"},
+	{"Amp Enable", NULL, "PCM Sel"},
+
+	{"BST Enable", NULL, "Amp Enable"},
+	{"BE_OUT", NULL, "BST Enable"},
+};
+
+static bool max98926_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98926_VBAT_DATA:
+	case MAX98926_VBST_DATA:
+	case MAX98926_LIVE_STATUS0:
+	case MAX98926_LIVE_STATUS1:
+	case MAX98926_LIVE_STATUS2:
+	case MAX98926_STATE0:
+	case MAX98926_STATE1:
+	case MAX98926_STATE2:
+	case MAX98926_FLAG0:
+	case MAX98926_FLAG1:
+	case MAX98926_FLAG2:
+	case MAX98926_VERSION:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max98926_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98926_IRQ_CLEAR0:
+	case MAX98926_IRQ_CLEAR1:
+	case MAX98926_IRQ_CLEAR2:
+	case MAX98926_ALC_HOLD_RLS:
+		return false;
+	default:
+		return true;
+	}
+};
+
+static DECLARE_TLV_DB_SCALE(max98926_spk_tlv, -600, 100, 0);
+static DECLARE_TLV_DB_RANGE(max98926_current_tlv,
+	0, 11, TLV_DB_SCALE_ITEM(20, 20, 0),
+	12, 15, TLV_DB_SCALE_ITEM(320, 40, 0),
+);
+
+static SOC_ENUM_SINGLE_DECL(max98926_dac_hpf_cutoff,
+		MAX98926_FILTERS, MAX98926_DAC_HPF_SHIFT,
+		max98926_hpf_cutoff_txt);
+
+static SOC_ENUM_SINGLE_DECL(max98926_boost_voltage,
+		MAX98926_CONFIGURATION, MAX98926_BST_VOUT_SHIFT,
+		max98926_boost_voltage_txt);
+
+static const struct snd_kcontrol_new max98926_snd_controls[] = {
+	SOC_SINGLE_TLV("Speaker Volume", MAX98926_GAIN,
+		MAX98926_SPK_GAIN_SHIFT,
+		(1<<MAX98926_SPK_GAIN_WIDTH)-1, 0,
+		max98926_spk_tlv),
+	SOC_SINGLE("Ramp Switch", MAX98926_GAIN_RAMPING,
+		MAX98926_SPK_RMP_EN_SHIFT, 1, 0),
+	SOC_SINGLE("ZCD Switch", MAX98926_GAIN_RAMPING,
+		MAX98926_SPK_ZCD_EN_SHIFT, 1, 0),
+	SOC_SINGLE("ALC Switch", MAX98926_THRESHOLD,
+		MAX98926_ALC_EN_SHIFT, 1, 0),
+	SOC_SINGLE("ALC Threshold", MAX98926_THRESHOLD,
+		MAX98926_ALC_TH_SHIFT,
+		(1<<MAX98926_ALC_TH_WIDTH)-1, 0),
+	SOC_ENUM("Boost Output Voltage", max98926_boost_voltage),
+	SOC_SINGLE_TLV("Boost Current Limit", MAX98926_BOOST_LIMITER,
+		MAX98926_BST_ILIM_SHIFT,
+		(1<<MAX98926_BST_ILIM_SHIFT)-1, 0,
+		max98926_current_tlv),
+	SOC_ENUM("DAC HPF Cutoff", max98926_dac_hpf_cutoff),
+	SOC_DOUBLE("PDM Channel One", MAX98926_DAI_CLK_DIV_N_LSBS,
+		MAX98926_PDM_CHANNEL_1_SHIFT,
+		MAX98926_PDM_CHANNEL_1_HIZ, 1, 0),
+	SOC_DOUBLE("PDM Channel Zero", MAX98926_DAI_CLK_DIV_N_LSBS,
+		MAX98926_PDM_CHANNEL_0_SHIFT,
+		MAX98926_PDM_CHANNEL_0_HIZ, 1, 0),
+};
+
+static const struct {
+	int rate;
+	int  sr;
+} rate_table[] = {
+	{
+		.rate = 8000,
+		.sr = 0,
+	},
+	{
+		.rate = 11025,
+		.sr = 1,
+	},
+	{
+		.rate = 12000,
+		.sr = 2,
+	},
+	{
+		.rate = 16000,
+		.sr = 3,
+	},
+	{
+		.rate = 22050,
+		.sr = 4,
+	},
+	{
+		.rate = 24000,
+		.sr = 5,
+	},
+	{
+		.rate = 32000,
+		.sr = 6,
+	},
+	{
+		.rate = 44100,
+		.sr = 7,
+	},
+	{
+		.rate = 48000,
+		.sr = 8,
+	},
+};
+
+static void max98926_set_sense_data(struct max98926_priv *max98926)
+{
+	regmap_update_bits(max98926->regmap,
+		MAX98926_DOUT_CFG_VMON,
+		MAX98926_DAI_VMON_EN_MASK,
+		MAX98926_DAI_VMON_EN_MASK);
+	regmap_update_bits(max98926->regmap,
+		MAX98926_DOUT_CFG_IMON,
+		MAX98926_DAI_IMON_EN_MASK,
+		MAX98926_DAI_IMON_EN_MASK);
+
+	if (!max98926->interleave_mode) {
+		/* set VMON slots */
+		regmap_update_bits(max98926->regmap,
+			MAX98926_DOUT_CFG_VMON,
+			MAX98926_DAI_VMON_SLOT_MASK,
+			max98926->v_slot);
+		/* set IMON slots */
+		regmap_update_bits(max98926->regmap,
+			MAX98926_DOUT_CFG_IMON,
+			MAX98926_DAI_IMON_SLOT_MASK,
+			max98926->i_slot);
+	} else {
+		/* enable interleave mode */
+		regmap_update_bits(max98926->regmap,
+			MAX98926_FORMAT,
+			MAX98926_DAI_INTERLEAVE_MASK,
+			MAX98926_DAI_INTERLEAVE_MASK);
+		/* set interleave slots */
+		regmap_update_bits(max98926->regmap,
+			MAX98926_DOUT_CFG_VBAT,
+			MAX98926_DAI_INTERLEAVE_SLOT_MASK,
+			max98926->v_slot);
+	}
+}
+
+static int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98926_priv *max98926 = snd_soc_component_get_drvdata(component);
+	unsigned int invert = 0;
+
+	dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		max98926_set_sense_data(max98926);
+		break;
+	default:
+		dev_err(component->dev, "DAI clock mode unsupported\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		invert = MAX98926_DAI_WCI_MASK;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		invert = MAX98926_DAI_BCI_MASK;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		invert = MAX98926_DAI_BCI_MASK | MAX98926_DAI_WCI_MASK;
+		break;
+	default:
+		dev_err(component->dev, "DAI invert mode unsupported\n");
+		return -EINVAL;
+	}
+
+	regmap_write(max98926->regmap,
+			MAX98926_FORMAT, MAX98926_DAI_DLY_MASK);
+	regmap_update_bits(max98926->regmap, MAX98926_FORMAT,
+			MAX98926_DAI_BCI_MASK, invert);
+	return 0;
+}
+
+static int max98926_dai_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	int dai_sr = -EINVAL;
+	int rate = params_rate(params), i;
+	struct snd_soc_component *component = dai->component;
+	struct max98926_priv *max98926 = snd_soc_component_get_drvdata(component);
+	int blr_clk_ratio;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		regmap_update_bits(max98926->regmap,
+			MAX98926_FORMAT,
+			MAX98926_DAI_CHANSZ_MASK,
+			MAX98926_DAI_CHANSZ_16);
+		max98926->ch_size = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		regmap_update_bits(max98926->regmap,
+			MAX98926_FORMAT,
+			MAX98926_DAI_CHANSZ_MASK,
+			MAX98926_DAI_CHANSZ_24);
+		max98926->ch_size = 24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		regmap_update_bits(max98926->regmap,
+			MAX98926_FORMAT,
+			MAX98926_DAI_CHANSZ_MASK,
+			MAX98926_DAI_CHANSZ_32);
+		max98926->ch_size = 32;
+		break;
+	default:
+		dev_dbg(component->dev, "format unsupported %d\n",
+			params_format(params));
+		return -EINVAL;
+	}
+
+	/* BCLK/LRCLK ratio calculation */
+	blr_clk_ratio = params_channels(params) * max98926->ch_size;
+
+	switch (blr_clk_ratio) {
+	case 32:
+		regmap_update_bits(max98926->regmap,
+			MAX98926_DAI_CLK_MODE2,
+			MAX98926_DAI_BSEL_MASK,
+			MAX98926_DAI_BSEL_32);
+		break;
+	case 48:
+		regmap_update_bits(max98926->regmap,
+			MAX98926_DAI_CLK_MODE2,
+			MAX98926_DAI_BSEL_MASK,
+			MAX98926_DAI_BSEL_48);
+		break;
+	case 64:
+		regmap_update_bits(max98926->regmap,
+			MAX98926_DAI_CLK_MODE2,
+			MAX98926_DAI_BSEL_MASK,
+			MAX98926_DAI_BSEL_64);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* find the closest rate */
+	for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+		if (rate_table[i].rate >= rate) {
+			dai_sr = rate_table[i].sr;
+			break;
+		}
+	}
+	if (dai_sr < 0)
+		return -EINVAL;
+
+	/* set DAI_SR to correct LRCLK frequency */
+	regmap_update_bits(max98926->regmap,
+		MAX98926_DAI_CLK_MODE2,
+		MAX98926_DAI_SR_MASK, dai_sr << MAX98926_DAI_SR_SHIFT);
+	return 0;
+}
+
+#define MAX98926_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops max98926_dai_ops = {
+	.set_fmt = max98926_dai_set_fmt,
+	.hw_params = max98926_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver max98926_dai[] = {
+{
+	.name = "max98926-aif1",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = MAX98926_FORMATS,
+	},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = MAX98926_FORMATS,
+	},
+	.ops = &max98926_dai_ops,
+}
+};
+
+static int max98926_probe(struct snd_soc_component *component)
+{
+	struct max98926_priv *max98926 = snd_soc_component_get_drvdata(component);
+
+	max98926->component = component;
+
+	/* Hi-Z all the slots */
+	regmap_write(max98926->regmap, MAX98926_DOUT_HIZ_CFG4, 0xF0);
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_max98926 = {
+	.probe			= max98926_probe,
+	.controls		= max98926_snd_controls,
+	.num_controls		= ARRAY_SIZE(max98926_snd_controls),
+	.dapm_routes		= max98926_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max98926_audio_map),
+	.dapm_widgets		= max98926_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98926_dapm_widgets),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config max98926_regmap = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= MAX98926_VERSION,
+	.reg_defaults	= max98926_reg,
+	.num_reg_defaults = ARRAY_SIZE(max98926_reg),
+	.volatile_reg	= max98926_volatile_register,
+	.readable_reg	= max98926_readable_register,
+	.cache_type		= REGCACHE_RBTREE,
+};
+
+static int max98926_i2c_probe(struct i2c_client *i2c,
+		const struct i2c_device_id *id)
+{
+	int ret, reg;
+	u32 value;
+	struct max98926_priv *max98926;
+
+	max98926 = devm_kzalloc(&i2c->dev,
+			sizeof(*max98926), GFP_KERNEL);
+	if (!max98926)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, max98926);
+	max98926->regmap = devm_regmap_init_i2c(i2c, &max98926_regmap);
+	if (IS_ERR(max98926->regmap)) {
+		ret = PTR_ERR(max98926->regmap);
+		dev_err(&i2c->dev,
+				"Failed to allocate regmap: %d\n", ret);
+		goto err_out;
+	}
+	if (of_property_read_bool(i2c->dev.of_node, "interleave-mode"))
+		max98926->interleave_mode = true;
+
+	if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) {
+		if (value > MAX98926_DAI_VMON_SLOT_1E_1F) {
+			dev_err(&i2c->dev, "vmon slot number is wrong:\n");
+			return -EINVAL;
+		}
+		max98926->v_slot = value;
+	}
+	if (!of_property_read_u32(i2c->dev.of_node, "imon-slot-no", &value)) {
+		if (value > MAX98926_DAI_IMON_SLOT_1E_1F) {
+			dev_err(&i2c->dev, "imon slot number is wrong:\n");
+			return -EINVAL;
+		}
+		max98926->i_slot = value;
+	}
+	ret = regmap_read(max98926->regmap,
+			MAX98926_VERSION, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read: %x\n", reg);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_max98926,
+			max98926_dai, ARRAY_SIZE(max98926_dai));
+	if (ret < 0)
+		dev_err(&i2c->dev,
+				"Failed to register component: %d\n", ret);
+	dev_info(&i2c->dev, "device version: %x\n", reg);
+err_out:
+	return ret;
+}
+
+static const struct i2c_device_id max98926_i2c_id[] = {
+	{ "max98926", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max98926_i2c_id);
+
+static const struct of_device_id max98926_of_match[] = {
+	{ .compatible = "maxim,max98926", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max98926_of_match);
+
+static struct i2c_driver max98926_i2c_driver = {
+	.driver = {
+		.name = "max98926",
+		.of_match_table = of_match_ptr(max98926_of_match),
+		.pm = NULL,
+	},
+	.probe	= max98926_i2c_probe,
+	.id_table = max98926_i2c_id,
+};
+
+module_i2c_driver(max98926_i2c_driver)
+MODULE_DESCRIPTION("ALSA SoC MAX98926 driver");
+MODULE_AUTHOR("Anish kumar <anish.kumar@maximintegrated.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98926.h b/sound/soc/codecs/max98926.h
new file mode 100644
index 0000000..ccf2c3f
--- /dev/null
+++ b/sound/soc/codecs/max98926.h
@@ -0,0 +1,848 @@
+/*
+ * max98926.h -- MAX98926 ALSA SoC Audio driver
+ * Copyright 2013-2015 Maxim Integrated Products
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX98926_H
+#define _MAX98926_H
+
+#define MAX98926_CHIP_VERSION   0x40
+#define MAX98926_CHIP_VERSION1  0x50
+
+#define MAX98926_VBAT_DATA          0x00
+#define MAX98926_VBST_DATA          0x01
+#define MAX98926_LIVE_STATUS0       0x02
+#define MAX98926_LIVE_STATUS1       0x03
+#define MAX98926_LIVE_STATUS2       0x04
+#define MAX98926_STATE0         0x05
+#define MAX98926_STATE1         0x06
+#define MAX98926_STATE2         0x07
+#define MAX98926_FLAG0          0x08
+#define MAX98926_FLAG1          0x09
+#define MAX98926_FLAG2          0x0A
+#define MAX98926_IRQ_ENABLE0        0x0B
+#define MAX98926_IRQ_ENABLE1        0x0C
+#define MAX98926_IRQ_ENABLE2        0x0D
+#define MAX98926_IRQ_CLEAR0     0x0E
+#define MAX98926_IRQ_CLEAR1     0x0F
+#define MAX98926_IRQ_CLEAR2     0x10
+#define MAX98926_MAP0           0x11
+#define MAX98926_MAP1           0x12
+#define MAX98926_MAP2           0x13
+#define MAX98926_MAP3           0x14
+#define MAX98926_MAP4           0x15
+#define MAX98926_MAP5           0x16
+#define MAX98926_MAP6           0x17
+#define MAX98926_MAP7           0x18
+#define MAX98926_MAP8           0x19
+#define MAX98926_DAI_CLK_MODE1      0x1A
+#define MAX98926_DAI_CLK_MODE2      0x1B
+#define MAX98926_DAI_CLK_DIV_M_MSBS 0x1C
+#define MAX98926_DAI_CLK_DIV_M_LSBS 0x1D
+#define MAX98926_DAI_CLK_DIV_N_MSBS 0x1E
+#define MAX98926_DAI_CLK_DIV_N_LSBS 0x1F
+#define MAX98926_FORMAT         0x20
+#define MAX98926_TDM_SLOT_SELECT        0x21
+#define MAX98926_DOUT_CFG_VMON      0x22
+#define MAX98926_DOUT_CFG_IMON      0x23
+#define MAX98926_DOUT_CFG_VBAT      0x24
+#define MAX98926_DOUT_CFG_VBST      0x25
+#define MAX98926_DOUT_CFG_FLAG      0x26
+#define MAX98926_DOUT_HIZ_CFG1      0x27
+#define MAX98926_DOUT_HIZ_CFG2      0x28
+#define MAX98926_DOUT_HIZ_CFG3      0x29
+#define MAX98926_DOUT_HIZ_CFG4      0x2A
+#define MAX98926_DOUT_DRV_STRENGTH      0x2B
+#define MAX98926_FILTERS            0x2C
+#define MAX98926_GAIN           0x2D
+#define MAX98926_GAIN_RAMPING       0x2E
+#define MAX98926_SPK_AMP            0x2F
+#define MAX98926_THRESHOLD          0x30
+#define MAX98926_ALC_ATTACK     0x31
+#define MAX98926_ALC_ATTEN_RLS      0x32
+#define MAX98926_ALC_HOLD_RLS       0x33
+#define MAX98926_ALC_CONFIGURATION      0x34
+#define MAX98926_BOOST_CONVERTER        0x35
+#define MAX98926_BLOCK_ENABLE       0x36
+#define MAX98926_CONFIGURATION      0x37
+#define MAX98926_GLOBAL_ENABLE      0x38
+#define MAX98926_BOOST_LIMITER      0x3A
+#define MAX98926_VERSION            0xFF
+
+#define MAX98926_REG_CNT               (MAX98926_R03A_BOOST_LIMITER+1)
+
+#define MAX98926_PDM_CURRENT_MASK (1<<7)
+#define MAX98926_PDM_CURRENT_SHIFT 7
+#define MAX98926_PDM_VOLTAGE_MASK (1<<3)
+#define MAX98926_PDM_VOLTAGE_SHIFT 3
+#define MAX98926_PDM_CHANNEL_0_MASK (1<<2)
+#define MAX98926_PDM_CHANNEL_0_SHIFT 2
+#define MAX98926_PDM_CHANNEL_1_MASK (1<<6)
+#define MAX98926_PDM_CHANNEL_1_SHIFT 6
+#define MAX98926_PDM_CHANNEL_1_HIZ 5
+#define MAX98926_PDM_CHANNEL_0_HIZ 1
+#define MAX98926_PDM_SOURCE_0_SHIFT 0
+#define MAX98926_PDM_SOURCE_0_MASK (1<<0)
+#define MAX98926_PDM_SOURCE_1_MASK (1<<4)
+#define MAX98926_PDM_SOURCE_1_SHIFT 4
+
+/* MAX98926 Register Bit Fields */
+
+/* MAX98926_R002_LIVE_STATUS0 */
+#define MAX98926_THERMWARN_STATUS_MASK          (1<<3)
+#define MAX98926_THERMWARN_STATUS_SHIFT         3
+#define MAX98926_THERMWARN_STATUS_WIDTH         1
+#define MAX98926_THERMSHDN_STATUS_MASK          (1<<1)
+#define MAX98926_THERMSHDN_STATUS_SHIFT         1
+#define MAX98926_THERMSHDN_STATUS_WIDTH         1
+
+/* MAX98926_R003_LIVE_STATUS1 */
+#define MAX98926_SPKCURNT_STATUS_MASK               (1<<5)
+#define MAX98926_SPKCURNT_STATUS_SHIFT          5
+#define MAX98926_SPKCURNT_STATUS_WIDTH          1
+#define MAX98926_WATCHFAIL_STATUS_MASK          (1<<4)
+#define MAX98926_WATCHFAIL_STATUS_SHIFT         4
+#define MAX98926_WATCHFAIL_STATUS_WIDTH         1
+#define MAX98926_ALCINFH_STATUS_MASK                (1<<3)
+#define MAX98926_ALCINFH_STATUS_SHIFT               3
+#define MAX98926_ALCINFH_STATUS_WIDTH               1
+#define MAX98926_ALCACT_STATUS_MASK             (1<<2)
+#define MAX98926_ALCACT_STATUS_SHIFT                2
+#define MAX98926_ALCACT_STATUS_WIDTH                1
+#define MAX98926_ALCMUT_STATUS_MASK             (1<<1)
+#define MAX98926_ALCMUT_STATUS_SHIFT                1
+#define MAX98926_ALCMUT_STATUS_WIDTH                1
+#define MAX98926_ACLP_STATUS_MASK                   (1<<0)
+#define MAX98926_ACLP_STATUS_SHIFT              0
+#define MAX98926_ACLP_STATUS_WIDTH              1
+
+/* MAX98926_R004_LIVE_STATUS2 */
+#define MAX98926_SLOTOVRN_STATUS_MASK               (1<<6)
+#define MAX98926_SLOTOVRN_STATUS_SHIFT          6
+#define MAX98926_SLOTOVRN_STATUS_WIDTH          1
+#define MAX98926_INVALSLOT_STATUS_MASK          (1<<5)
+#define MAX98926_INVALSLOT_STATUS_SHIFT         5
+#define MAX98926_INVALSLOT_STATUS_WIDTH         1
+#define MAX98926_SLOTCNFLT_STATUS_MASK          (1<<4)
+#define MAX98926_SLOTCNFLT_STATUS_SHIFT         4
+#define MAX98926_SLOTCNFLT_STATUS_WIDTH         1
+#define MAX98926_VBSTOVFL_STATUS_MASK               (1<<3)
+#define MAX98926_VBSTOVFL_STATUS_SHIFT          3
+#define MAX98926_VBSTOVFL_STATUS_WIDTH          1
+#define MAX98926_VBATOVFL_STATUS_MASK               (1<<2)
+#define MAX98926_VBATOVFL_STATUS_SHIFT          2
+#define MAX98926_VBATOVFL_STATUS_WIDTH          1
+#define MAX98926_IMONOVFL_STATUS_MASK               (1<<1)
+#define MAX98926_IMONOVFL_STATUS_SHIFT          1
+#define MAX98926_IMONOVFL_STATUS_WIDTH          1
+#define MAX98926_VMONOVFL_STATUS_MASK               (1<<0)
+#define MAX98926_VMONOVFL_STATUS_SHIFT          0
+#define MAX98926_VMONOVFL_STATUS_WIDTH          1
+
+/* MAX98926_R005_STATE0 */
+#define MAX98926_THERMWARN_END_STATE_MASK           (1<<3)
+#define MAX98926_THERMWARN_END_STATE_SHIFT      3
+#define MAX98926_THERMWARN_END_STATE_WIDTH      1
+#define MAX98926_THERMWARN_BGN_STATE_MASK           (1<<2)
+#define MAX98926_THERMWARN_BGN_STATE_SHIFT      1
+#define MAX98926_THERMWARN_BGN_STATE_WIDTH      1
+#define MAX98926_THERMSHDN_END_STATE_MASK           (1<<1)
+#define MAX98926_THERMSHDN_END_STATE_SHIFT      1
+#define MAX98926_THERMSHDN_END_STATE_WIDTH      1
+#define MAX98926_THERMSHDN_BGN_STATE_MASK           (1<<0)
+#define MAX98926_THERMSHDN_BGN_STATE_SHIFT      0
+#define MAX98926_THERMSHDN_BGN_STATE_WIDTH      1
+
+/* MAX98926_R006_STATE1 */
+#define MAX98926_SPRCURNT_STATE_MASK                (1<<5)
+#define MAX98926_SPRCURNT_STATE_SHIFT               5
+#define MAX98926_SPRCURNT_STATE_WIDTH               1
+#define MAX98926_WATCHFAIL_STATE_MASK               (1<<4)
+#define MAX98926_WATCHFAIL_STATE_SHIFT          4
+#define MAX98926_WATCHFAIL_STATE_WIDTH          1
+#define MAX98926_ALCINFH_STATE_MASK             (1<<3)
+#define MAX98926_ALCINFH_STATE_SHIFT                3
+#define MAX98926_ALCINFH_STATE_WIDTH                1
+#define MAX98926_ALCACT_STATE_MASK              (1<<2)
+#define MAX98926_ALCACT_STATE_SHIFT             2
+#define MAX98926_ALCACT_STATE_WIDTH             1
+#define MAX98926_ALCMUT_STATE_MASK              (1<<1)
+#define MAX98926_ALCMUT_STATE_SHIFT             1
+#define MAX98926_ALCMUT_STATE_WIDTH             1
+#define MAX98926_ALCP_STATE_MASK                    (1<<0)
+#define MAX98926_ALCP_STATE_SHIFT                   0
+#define MAX98926_ALCP_STATE_WIDTH                   1
+
+/* MAX98926_R007_STATE2 */
+#define MAX98926_SLOTOVRN_STATE_MASK                (1<<6)
+#define MAX98926_SLOTOVRN_STATE_SHIFT               6
+#define MAX98926_SLOTOVRN_STATE_WIDTH               1
+#define MAX98926_INVALSLOT_STATE_MASK               (1<<5)
+#define MAX98926_INVALSLOT_STATE_SHIFT          5
+#define MAX98926_INVALSLOT_STATE_WIDTH          1
+#define MAX98926_SLOTCNFLT_STATE_MASK               (1<<4)
+#define MAX98926_SLOTCNFLT_STATE_SHIFT          4
+#define MAX98926_SLOTCNFLT_STATE_WIDTH          1
+#define MAX98926_VBSTOVFL_STATE_MASK                (1<<3)
+#define MAX98926_VBSTOVFL_STATE_SHIFT               3
+#define MAX98926_VBSTOVFL_STATE_WIDTH               1
+#define MAX98926_VBATOVFL_STATE_MASK                (1<<2)
+#define MAX98926_VBATOVFL_STATE_SHIFT               2
+#define MAX98926_VBATOVFL_STATE_WIDTH               1
+#define MAX98926_IMONOVFL_STATE_MASK                (1<<1)
+#define MAX98926_IMONOVFL_STATE_SHIFT               1
+#define MAX98926_IMONOVFL_STATE_WIDTH               1
+#define MAX98926_VMONOVFL_STATE_MASK                (1<<0)
+#define MAX98926_VMONOVFL_STATE_SHIFT               0
+#define MAX98926_VMONOVFL_STATE_WIDTH               1
+
+/* MAX98926_R008_FLAG0 */
+#define MAX98926_THERMWARN_END_FLAG_MASK            (1<<3)
+#define MAX98926_THERMWARN_END_FLAG_SHIFT           3
+#define MAX98926_THERMWARN_END_FLAG_WIDTH           1
+#define MAX98926_THERMWARN_BGN_FLAG_MASK            (1<<2)
+#define MAX98926_THERMWARN_BGN_FLAG_SHIFT           2
+#define MAX98926_THERMWARN_BGN_FLAG_WIDTH           1
+#define MAX98926_THERMSHDN_END_FLAG_MASK            (1<<1)
+#define MAX98926_THERMSHDN_END_FLAG_SHIFT           1
+#define MAX98926_THERMSHDN_END_FLAG_WIDTH           1
+#define MAX98926_THERMSHDN_BGN_FLAG_MASK            (1<<0)
+#define MAX98926_THERMSHDN_BGN_FLAG_SHIFT           0
+#define MAX98926_THERMSHDN_BGN_FLAG_WIDTH           1
+
+/* MAX98926_R009_FLAG1 */
+#define MAX98926_SPKCURNT_FLAG_MASK             (1<<5)
+#define MAX98926_SPKCURNT_FLAG_SHIFT                5
+#define MAX98926_SPKCURNT_FLAG_WIDTH                1
+#define MAX98926_WATCHFAIL_FLAG_MASK                (1<<4)
+#define MAX98926_WATCHFAIL_FLAG_SHIFT               4
+#define MAX98926_WATCHFAIL_FLAG_WIDTH               1
+#define MAX98926_ALCINFH_FLAG_MASK              (1<<3)
+#define MAX98926_ALCINFH_FLAG_SHIFT             3
+#define MAX98926_ALCINFH_FLAG_WIDTH             1
+#define MAX98926_ALCACT_FLAG_MASK                   (1<<2)
+#define MAX98926_ALCACT_FLAG_SHIFT              2
+#define MAX98926_ALCACT_FLAG_WIDTH              1
+#define MAX98926_ALCMUT_FLAG_MASK                   (1<<1)
+#define MAX98926_ALCMUT_FLAG_SHIFT              1
+#define MAX98926_ALCMUT_FLAG_WIDTH              1
+#define MAX98926_ALCP_FLAG_MASK                 (1<<0)
+#define MAX98926_ALCP_FLAG_SHIFT                    0
+#define MAX98926_ALCP_FLAG_WIDTH                    1
+
+/* MAX98926_R00A_FLAG2 */
+#define MAX98926_SLOTOVRN_FLAG_MASK             (1<<6)
+#define MAX98926_SLOTOVRN_FLAG_SHIFT                6
+#define MAX98926_SLOTOVRN_FLAG_WIDTH                1
+#define MAX98926_INVALSLOT_FLAG_MASK                (1<<5)
+#define MAX98926_INVALSLOT_FLAG_SHIFT               5
+#define MAX98926_INVALSLOT_FLAG_WIDTH               1
+#define MAX98926_SLOTCNFLT_FLAG_MASK                (1<<4)
+#define MAX98926_SLOTCNFLT_FLAG_SHIFT               4
+#define MAX98926_SLOTCNFLT_FLAG_WIDTH               1
+#define MAX98926_VBSTOVFL_FLAG_MASK             (1<<3)
+#define MAX98926_VBSTOVFL_FLAG_SHIFT                3
+#define MAX98926_VBSTOVFL_FLAG_WIDTH                1
+#define MAX98926_VBATOVFL_FLAG_MASK             (1<<2)
+#define MAX98926_VBATOVFL_FLAG_SHIFT                2
+#define MAX98926_VBATOVFL_FLAG_WIDTH                1
+#define MAX98926_IMONOVFL_FLAG_MASK             (1<<1)
+#define MAX98926_IMONOVFL_FLAG_SHIFT                1
+#define MAX98926_IMONOVFL_FLAG_WIDTH                1
+#define MAX98926_VMONOVFL_FLAG_MASK             (1<<0)
+#define MAX98926_VMONOVFL_FLAG_SHIFT                0
+#define MAX98926_VMONOVFL_FLAG_WIDTH                1
+
+/* MAX98926_R00B_IRQ_ENABLE0 */
+#define MAX98926_THERMWARN_END_EN_MASK          (1<<3)
+#define MAX98926_THERMWARN_END_EN_SHIFT         3
+#define MAX98926_THERMWARN_END_EN_WIDTH         1
+#define MAX98926_THERMWARN_BGN_EN_MASK          (1<<2)
+#define MAX98926_THERMWARN_BGN_EN_SHIFT         2
+#define MAX98926_THERMWARN_BGN_EN_WIDTH         1
+#define MAX98926_THERMSHDN_END_EN_MASK          (1<<1)
+#define MAX98926_THERMSHDN_END_EN_SHIFT         1
+#define MAX98926_THERMSHDN_END_EN_WIDTH         1
+#define MAX98926_THERMSHDN_BGN_EN_MASK          (1<<0)
+#define MAX98926_THERMSHDN_BGN_EN_SHIFT         0
+#define MAX98926_THERMSHDN_BGN_EN_WIDTH         1
+
+/* MAX98926_R00C_IRQ_ENABLE1 */
+#define MAX98926_SPKCURNT_EN_MASK       (1<<5)
+#define MAX98926_SPKCURNT_EN_SHIFT  5
+#define MAX98926_SPKCURNT_EN_WIDTH  1
+#define MAX98926_WATCHFAIL_EN_MASK  (1<<4)
+#define MAX98926_WATCHFAIL_EN_SHIFT 4
+#define MAX98926_WATCHFAIL_EN_WIDTH 1
+#define MAX98926_ALCINFH_EN_MASK        (1<<3)
+#define MAX98926_ALCINFH_EN_SHIFT       3
+#define MAX98926_ALCINFH_EN_WIDTH       1
+#define MAX98926_ALCACT_EN_MASK     (1<<2)
+#define MAX98926_ALCACT_EN_SHIFT        2
+#define MAX98926_ALCACT_EN_WIDTH        1
+#define MAX98926_ALCMUT_EN_MASK     (1<<1)
+#define MAX98926_ALCMUT_EN_SHIFT        1
+#define MAX98926_ALCMUT_EN_WIDTH        1
+#define MAX98926_ALCP_EN_MASK           (1<<0)
+#define MAX98926_ALCP_EN_SHIFT      0
+#define MAX98926_ALCP_EN_WIDTH      1
+
+/* MAX98926_R00D_IRQ_ENABLE2 */
+#define MAX98926_SLOTOVRN_EN_MASK       (1<<6)
+#define MAX98926_SLOTOVRN_EN_SHIFT  6
+#define MAX98926_SLOTOVRN_EN_WIDTH  1
+#define MAX98926_INVALSLOT_EN_MASK  (1<<5)
+#define MAX98926_INVALSLOT_EN_SHIFT 5
+#define MAX98926_INVALSLOT_EN_WIDTH 1
+#define MAX98926_SLOTCNFLT_EN_MASK  (1<<4)
+#define MAX98926_SLOTCNFLT_EN_SHIFT 4
+#define MAX98926_SLOTCNFLT_EN_WIDTH 1
+#define MAX98926_VBSTOVFL_EN_MASK       (1<<3)
+#define MAX98926_VBSTOVFL_EN_SHIFT  3
+#define MAX98926_VBSTOVFL_EN_WIDTH  1
+#define MAX98926_VBATOVFL_EN_MASK       (1<<2)
+#define MAX98926_VBATOVFL_EN_SHIFT  2
+#define MAX98926_VBATOVFL_EN_WIDTH  1
+#define MAX98926_IMONOVFL_EN_MASK       (1<<1)
+#define MAX98926_IMONOVFL_EN_SHIFT  1
+#define MAX98926_IMONOVFL_EN_WIDTH  1
+#define MAX98926_VMONOVFL_EN_MASK       (1<<0)
+#define MAX98926_VMONOVFL_EN_SHIFT  0
+#define MAX98926_VMONOVFL_EN_WIDTH  1
+
+/* MAX98926_R00E_IRQ_CLEAR0 */
+#define MAX98926_THERMWARN_END_CLR_MASK         (1<<3)
+#define MAX98926_THERMWARN_END_CLR_SHIFT            3
+#define MAX98926_THERMWARN_END_CLR_WIDTH            1
+#define MAX98926_THERMWARN_BGN_CLR_MASK         (1<<2)
+#define MAX98926_THERMWARN_BGN_CLR_SHIFT            2
+#define MAX98926_THERMWARN_BGN_CLR_WIDTH            1
+#define MAX98926_THERMSHDN_END_CLR_MASK         (1<<1)
+#define MAX98926_THERMSHDN_END_CLR_SHIFT            1
+#define MAX98926_THERMSHDN_END_CLR_WIDTH            1
+#define MAX98926_THERMSHDN_BGN_CLR_MASK         (1<<0)
+#define MAX98926_THERMSHDN_BGN_CLR_SHIFT            0
+#define MAX98926_THERMSHDN_BGN_CLR_WIDTH            1
+
+/* MAX98926_R00F_IRQ_CLEAR1 */
+#define MAX98926_SPKCURNT_CLR_MASK      (1<<5)
+#define MAX98926_SPKCURNT_CLR_SHIFT     5
+#define MAX98926_SPKCURNT_CLR_WIDTH     1
+#define MAX98926_WATCHFAIL_CLR_MASK     (1<<4)
+#define MAX98926_WATCHFAIL_CLR_SHIFT        4
+#define MAX98926_WATCHFAIL_CLR_WIDTH        1
+#define MAX98926_ALCINFH_CLR_MASK           (1<<3)
+#define MAX98926_ALCINFH_CLR_SHIFT      3
+#define MAX98926_ALCINFH_CLR_WIDTH      1
+#define MAX98926_ALCACT_CLR_MASK            (1<<2)
+#define MAX98926_ALCACT_CLR_SHIFT           2
+#define MAX98926_ALCACT_CLR_WIDTH           1
+#define MAX98926_ALCMUT_CLR_MASK            (1<<1)
+#define MAX98926_ALCMUT_CLR_SHIFT           1
+#define MAX98926_ALCMUT_CLR_WIDTH           1
+#define MAX98926_ALCP_CLR_MASK          (1<<0)
+#define MAX98926_ALCP_CLR_SHIFT         0
+#define MAX98926_ALCP_CLR_WIDTH         1
+
+/* MAX98926_R010_IRQ_CLEAR2 */
+#define MAX98926_SLOTOVRN_CLR_MASK      (1<<6)
+#define MAX98926_SLOTOVRN_CLR_SHIFT     6
+#define MAX98926_SLOTOVRN_CLR_WIDTH     1
+#define MAX98926_INVALSLOT_CLR_MASK     (1<<5)
+#define MAX98926_INVALSLOT_CLR_SHIFT        5
+#define MAX98926_INVALSLOT_CLR_WIDTH        1
+#define MAX98926_SLOTCNFLT_CLR_MASK     (1<<4)
+#define MAX98926_SLOTCNFLT_CLR_SHIFT        4
+#define MAX98926_SLOTCNFLT_CLR_WIDTH        1
+#define MAX98926_VBSTOVFL_CLR_MASK      (1<<3)
+#define MAX98926_VBSTOVFL_CLR_SHIFT     3
+#define MAX98926_VBSTOVFL_CLR_WIDTH     1
+#define MAX98926_VBATOVFL_CLR_MASK      (1<<2)
+#define MAX98926_VBATOVFL_CLR_SHIFT     2
+#define MAX98926_VBATOVFL_CLR_WIDTH     1
+#define MAX98926_IMONOVFL_CLR_MASK      (1<<1)
+#define MAX98926_IMONOVFL_CLR_SHIFT     1
+#define MAX98926_IMONOVFL_CLR_WIDTH     1
+#define MAX98926_VMONOVFL_CLR_MASK          (1<<0)
+#define MAX98926_VMONOVFL_CLR_SHIFT         0
+#define MAX98926_VMONOVFL_CLR_WIDTH         1
+
+/* MAX98926_R011_MAP0 */
+#define MAX98926_ER_THERMWARN_EN_MASK               (1<<7)
+#define MAX98926_ER_THERMWARN_EN_SHIFT          7
+#define MAX98926_ER_THERMWARN_EN_WIDTH          1
+#define MAX98926_ER_THERMWARN_MAP_MASK          (0x07<<4)
+#define MAX98926_ER_THERMWARN_MAP_SHIFT         4
+#define MAX98926_ER_THERMWARN_MAP_WIDTH         3
+
+/* MAX98926_R012_MAP1 */
+#define MAX98926_ER_ALCMUT_EN_MASK      (1<<7)
+#define MAX98926_ER_ALCMUT_EN_SHIFT     7
+#define MAX98926_ER_ALCMUT_EN_WIDTH     1
+#define MAX98926_ER_ALCMUT_MAP_MASK     (0x07<<4)
+#define MAX98926_ER_ALCMUT_MAP_SHIFT        4
+#define MAX98926_ER_ALCMUT_MAP_WIDTH        3
+#define MAX98926_ER_ALCP_EN_MASK            (1<<3)
+#define MAX98926_ER_ALCP_EN_SHIFT           3
+#define MAX98926_ER_ALCP_EN_WIDTH           1
+#define MAX98926_ER_ALCP_MAP_MASK           (0x07<<0)
+#define MAX98926_ER_ALCP_MAP_SHIFT      0
+#define MAX98926_ER_ALCP_MAP_WIDTH      3
+
+/* MAX98926_R013_MAP2 */
+#define MAX98926_ER_ALCINFH_EN_MASK     (1<<7)
+#define MAX98926_ER_ALCINFH_EN_SHIFT        7
+#define MAX98926_ER_ALCINFH_EN_WIDTH        1
+#define MAX98926_ER_ALCINFH_MAP_MASK        (0x07<<4)
+#define MAX98926_ER_ALCINFH_MAP_SHIFT       4
+#define MAX98926_ER_ALCINFH_MAP_WIDTH       3
+#define MAX98926_ER_ALCACT_EN_MASK      (1<<3)
+#define MAX98926_ER_ALCACT_EN_SHIFT     3
+#define MAX98926_ER_ALCACT_EN_WIDTH     1
+#define MAX98926_ER_ALCACT_MAP_MASK     (0x07<<0)
+#define MAX98926_ER_ALCACT_MAP_SHIFT        0
+#define MAX98926_ER_ALCACT_MAP_WIDTH        3
+
+/* MAX98926_R014_MAP3 */
+#define MAX98926_ER_SPKCURNT_EN_MASK            (1<<7)
+#define MAX98926_ER_SPKCURNT_EN_SHIFT           7
+#define MAX98926_ER_SPKCURNT_EN_WIDTH           1
+#define MAX98926_ER_SPKCURNT_MAP_MASK           (0x07<<4)
+#define MAX98926_ER_SPKCURNT_MAP_SHIFT          4
+#define MAX98926_ER_SPKCURNT_MAP_WIDTH          3
+
+/* MAX98926_R015_MAP4 */
+/* RESERVED */
+
+/* MAX98926_R016_MAP5 */
+#define MAX98926_ER_IMONOVFL_EN_MASK            (1<<7)
+#define MAX98926_ER_IMONOVFL_EN_SHIFT           7
+#define MAX98926_ER_IMONOVFL_EN_WIDTH           1
+#define MAX98926_ER_IMONOVFL_MAP_MASK           (0x07<<4)
+#define MAX98926_ER_IMONOVFL_MAP_SHIFT          4
+#define MAX98926_ER_IMONOVFL_MAP_WIDTH          3
+#define MAX98926_ER_VMONOVFL_EN_MASK            (1<<3)
+#define MAX98926_ER_VMONOVFL_EN_SHIFT           3
+#define MAX98926_ER_VMONOVFL_EN_WIDTH           1
+#define MAX98926_ER_VMONOVFL_MAP_MASK           (0x07<<0)
+#define MAX98926_ER_VMONOVFL_MAP_SHIFT          0
+#define MAX98926_ER_VMONOVFL_MAP_WIDTH          3
+
+/* MAX98926_R017_MAP6 */
+#define MAX98926_ER_VBSTOVFL_EN_MASK            (1<<7)
+#define MAX98926_ER_VBSTOVFL_EN_SHIFT           7
+#define MAX98926_ER_VBSTOVFL_EN_WIDTH           1
+#define MAX98926_ER_VBSTOVFL_MAP_MASK           (0x07<<4)
+#define MAX98926_ER_VBSTOVFL_MAP_SHIFT          4
+#define MAX98926_ER_VBSTOVFL_MAP_WIDTH          3
+#define MAX98926_ER_VBATOVFL_EN_MASK            (1<<3)
+#define MAX98926_ER_VBATOVFL_EN_SHIFT           3
+#define MAX98926_ER_VBATOVFL_EN_WIDTH           1
+#define MAX98926_ER_VBATOVFL_MAP_MASK           (0x07<<0)
+#define MAX98926_ER_VBATOVFL_MAP_SHIFT          0
+#define MAX98926_ER_VBATOVFL_MAP_WIDTH          3
+
+/* MAX98926_R018_MAP7 */
+#define MAX98926_ER_INVALSLOT_EN_MASK               (1<<7)
+#define MAX98926_ER_INVALSLOT_EN_SHIFT          7
+#define MAX98926_ER_INVALSLOT_EN_WIDTH          1
+#define MAX98926_ER_INVALSLOT_MAP_MASK          (0x07<<4)
+#define MAX98926_ER_INVALSLOT_MAP_SHIFT         4
+#define MAX98926_ER_INVALSLOT_MAP_WIDTH         3
+#define MAX98926_ER_SLOTCNFLT_EN_MASK               (1<<3)
+#define MAX98926_ER_SLOTCNFLT_EN_SHIFT          3
+#define MAX98926_ER_SLOTCNFLT_EN_WIDTH          1
+#define MAX98926_ER_SLOTCNFLT_MAP_MASK          (0x07<<0)
+#define MAX98926_ER_SLOTCNFLT_MAP_SHIFT         0
+#define MAX98926_ER_SLOTCNFLT_MAP_WIDTH         3
+
+/* MAX98926_R019_MAP8 */
+#define MAX98926_ER_SLOTOVRN_EN_MASK    (1<<3)
+#define MAX98926_ER_SLOTOVRN_EN_SHIFT   3
+#define MAX98926_ER_SLOTOVRN_EN_WIDTH   1
+#define MAX98926_ER_SLOTOVRN_MAP_MASK   (0x07<<0)
+#define MAX98926_ER_SLOTOVRN_MAP_SHIFT  0
+#define MAX98926_ER_SLOTOVRN_MAP_WIDTH  3
+
+/* MAX98926_R01A_DAI_CLK_MODE1 */
+#define MAX98926_DAI_CLK_SOURCE_MASK    (1<<6)
+#define MAX98926_DAI_CLK_SOURCE_SHIFT   6
+#define MAX98926_DAI_CLK_SOURCE_WIDTH   1
+#define MAX98926_MDLL_MULT_MASK     (0x0F<<0)
+#define MAX98926_MDLL_MULT_SHIFT        0
+#define MAX98926_MDLL_MULT_WIDTH        4
+
+#define MAX98926_MDLL_MULT_MCLKx8       6
+#define MAX98926_MDLL_MULT_MCLKx16  8
+
+/* MAX98926_R01B_DAI_CLK_MODE2 */
+#define MAX98926_DAI_SR_MASK            (0x0F<<4)
+#define MAX98926_DAI_SR_SHIFT           4
+#define MAX98926_DAI_SR_WIDTH           4
+#define MAX98926_DAI_MAS_MASK           (1<<3)
+#define MAX98926_DAI_MAS_SHIFT          3
+#define MAX98926_DAI_MAS_WIDTH          1
+#define MAX98926_DAI_BSEL_MASK          (0x07<<0)
+#define MAX98926_DAI_BSEL_SHIFT         0
+#define MAX98926_DAI_BSEL_WIDTH         3
+
+#define MAX98926_DAI_BSEL_32 (0 << MAX98926_DAI_BSEL_SHIFT)
+#define MAX98926_DAI_BSEL_48 (1 << MAX98926_DAI_BSEL_SHIFT)
+#define MAX98926_DAI_BSEL_64 (2 << MAX98926_DAI_BSEL_SHIFT)
+#define MAX98926_DAI_BSEL_256 (6 << MAX98926_DAI_BSEL_SHIFT)
+
+/* MAX98926_R01C_DAI_CLK_DIV_M_MSBS */
+#define MAX98926_DAI_M_MSBS_MASK        (0xFF<<0)
+#define MAX98926_DAI_M_MSBS_SHIFT       0
+#define MAX98926_DAI_M_MSBS_WIDTH       8
+
+/* MAX98926_R01D_DAI_CLK_DIV_M_LSBS */
+#define MAX98926_DAI_M_LSBS_MASK        (0xFF<<0)
+#define MAX98926_DAI_M_LSBS_SHIFT       0
+#define MAX98926_DAI_M_LSBS_WIDTH       8
+
+/* MAX98926_R01E_DAI_CLK_DIV_N_MSBS */
+#define MAX98926_DAI_N_MSBS_MASK        (0x7F<<0)
+#define MAX98926_DAI_N_MSBS_SHIFT       0
+#define MAX98926_DAI_N_MSBS_WIDTH       7
+
+/* MAX98926_R01F_DAI_CLK_DIV_N_LSBS */
+#define MAX98926_DAI_N_LSBS_MASK        (0xFF<<0)
+#define MAX98926_DAI_N_LSBS_SHIFT       0
+#define MAX98926_DAI_N_LSBS_WIDTH       8
+
+/* MAX98926_R020_FORMAT */
+#define MAX98926_DAI_CHANSZ_MASK    (0x03<<6)
+#define MAX98926_DAI_CHANSZ_SHIFT   6
+#define MAX98926_DAI_CHANSZ_WIDTH   2
+#define MAX98926_DAI_INTERLEAVE_MASK        (1<<5)
+#define MAX98926_DAI_INTERLEAVE_SHIFT       5
+#define MAX98926_DAI_INTERLEAVE_WIDTH       1
+#define MAX98926_DAI_EXTBCLK_HIZ_MASK       (1<<4)
+#define MAX98926_DAI_EXTBCLK_HIZ_SHIFT      4
+#define MAX98926_DAI_EXTBCLK_HIZ_WIDTH      1
+#define MAX98926_DAI_WCI_MASK           (1<<3)
+#define MAX98926_DAI_WCI_SHIFT      3
+#define MAX98926_DAI_WCI_WIDTH      1
+#define MAX98926_DAI_BCI_MASK           (1<<2)
+#define MAX98926_DAI_BCI_SHIFT      2
+#define MAX98926_DAI_BCI_WIDTH      1
+#define MAX98926_DAI_DLY_MASK           (1<<1)
+#define MAX98926_DAI_DLY_SHIFT      1
+#define MAX98926_DAI_DLY_WIDTH      1
+#define MAX98926_DAI_TDM_MASK           (1<<0)
+#define MAX98926_DAI_TDM_SHIFT      0
+#define MAX98926_DAI_TDM_WIDTH      1
+
+#define MAX98926_DAI_CHANSZ_16 (1 << MAX98926_DAI_CHANSZ_SHIFT)
+#define MAX98926_DAI_CHANSZ_24 (2 << MAX98926_DAI_CHANSZ_SHIFT)
+#define MAX98926_DAI_CHANSZ_32 (3 << MAX98926_DAI_CHANSZ_SHIFT)
+
+/* MAX98926_R021_TDM_SLOT_SELECT */
+#define MAX98926_DAI_DO_EN_MASK     (1<<7)
+#define MAX98926_DAI_DO_EN_SHIFT        7
+#define MAX98926_DAI_DO_EN_WIDTH        1
+#define MAX98926_DAI_DIN_EN_MASK        (1<<6)
+#define MAX98926_DAI_DIN_EN_SHIFT       6
+#define MAX98926_DAI_DIN_EN_WIDTH       1
+#define MAX98926_DAI_INR_SOURCE_MASK    (0x07<<3)
+#define MAX98926_DAI_INR_SOURCE_SHIFT   3
+#define MAX98926_DAI_INR_SOURCE_WIDTH   3
+#define MAX98926_DAI_INL_SOURCE_MASK    (0x07<<0)
+#define MAX98926_DAI_INL_SOURCE_SHIFT   0
+#define MAX98926_DAI_INL_SOURCE_WIDTH   3
+
+/* MAX98926_R022_DOUT_CFG_VMON */
+#define MAX98926_DAI_VMON_EN_MASK       (1<<5)
+#define MAX98926_DAI_VMON_EN_SHIFT  5
+#define MAX98926_DAI_VMON_EN_WIDTH  1
+#define MAX98926_DAI_VMON_SLOT_MASK (0x1F<<0)
+#define MAX98926_DAI_VMON_SLOT_SHIFT    0
+#define MAX98926_DAI_VMON_SLOT_WIDTH    5
+
+#define MAX98926_DAI_VMON_SLOT_00_01 (0 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_01_02 (1 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_02_03 (2 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_03_04 (3 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_04_05 (4 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_05_06 (5 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_06_07 (6 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_07_08 (7 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_08_09 (8 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_09_0A (9 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_0A_0B (10 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_0B_0C (11 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_0C_0D (12 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_0D_0E (13 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_0E_0F (14 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_0F_10 (15 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_10_11 (16 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_11_12 (17 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_12_13 (18 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_13_14 (19 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_14_15 (20 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_15_16 (21 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_16_17 (22 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_17_18 (23 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_18_19 (24 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_19_1A (25 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_1A_1B (26 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_1B_1C (27 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_1C_1D (28 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_1D_1E (29 << MAX98926_DAI_VMON_SLOT_SHIFT)
+#define MAX98926_DAI_VMON_SLOT_1E_1F (30 << MAX98926_DAI_VMON_SLOT_SHIFT)
+
+/* MAX98926_R023_DOUT_CFG_IMON */
+#define MAX98926_DAI_IMON_EN_MASK       (1<<5)
+#define MAX98926_DAI_IMON_EN_SHIFT  5
+#define MAX98926_DAI_IMON_EN_WIDTH  1
+#define MAX98926_DAI_IMON_SLOT_MASK (0x1F<<0)
+#define MAX98926_DAI_IMON_SLOT_SHIFT    0
+#define MAX98926_DAI_IMON_SLOT_WIDTH    5
+
+#define MAX98926_DAI_IMON_SLOT_00_01 (0 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_01_02 (1 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_02_03 (2 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_03_04 (3 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_04_05 (4 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_05_06 (5 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_06_07 (6 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_07_08 (7 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_08_09 (8 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_09_0A (9 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_0A_0B (10 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_0B_0C (11 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_0C_0D (12 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_0D_0E (13 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_0E_0F (14 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_0F_10 (15 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_10_11 (16 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_11_12 (17 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_12_13 (18 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_13_14 (19 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_14_15 (20 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_15_16 (21 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_16_17 (22 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_17_18 (23 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_18_19 (24 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_19_1A (25 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_1A_1B (26 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_1B_1C (27 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_1C_1D (28 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_1D_1E (29 << MAX98926_DAI_IMON_SLOT_SHIFT)
+#define MAX98926_DAI_IMON_SLOT_1E_1F (30 << MAX98926_DAI_IMON_SLOT_SHIFT)
+
+/* MAX98926_R024_DOUT_CFG_VBAT */
+#define MAX98926_DAI_INTERLEAVE_SLOT_MASK       (0x1F<<0)
+#define MAX98926_DAI_INTERLEAVE_SLOT_SHIFT      0
+#define MAX98926_DAI_INTERLEAVE_SLOT_WIDTH      5
+
+/* MAX98926_R025_DOUT_CFG_VBST */
+#define MAX98926_DAI_VBST_EN_MASK               (1<<5)
+#define MAX98926_DAI_VBST_EN_SHIFT          5
+#define MAX98926_DAI_VBST_EN_WIDTH          1
+#define MAX98926_DAI_VBST_SLOT_MASK         (0x1F<<0)
+#define MAX98926_DAI_VBST_SLOT_SHIFT            0
+#define MAX98926_DAI_VBST_SLOT_WIDTH            5
+
+/* MAX98926_R026_DOUT_CFG_FLAG */
+#define MAX98926_DAI_FLAG_EN_MASK               (1<<5)
+#define MAX98926_DAI_FLAG_EN_SHIFT          5
+#define MAX98926_DAI_FLAG_EN_WIDTH          1
+#define MAX98926_DAI_FLAG_SLOT_MASK         (0x1F<<0)
+#define MAX98926_DAI_FLAG_SLOT_SHIFT            0
+#define MAX98926_DAI_FLAG_SLOT_WIDTH            5
+
+/* MAX98926_R027_DOUT_HIZ_CFG1 */
+#define MAX98926_DAI_SLOT_HIZ_CFG1_MASK         (0xFF<<0)
+#define MAX98926_DAI_SLOT_HIZ_CFG1_SHIFT            0
+#define MAX98926_DAI_SLOT_HIZ_CFG1_WIDTH            8
+
+/* MAX98926_R028_DOUT_HIZ_CFG2 */
+#define MAX98926_DAI_SLOT_HIZ_CFG2_MASK         (0xFF<<0)
+#define MAX98926_DAI_SLOT_HIZ_CFG2_SHIFT            0
+#define MAX98926_DAI_SLOT_HIZ_CFG2_WIDTH            8
+
+/* MAX98926_R029_DOUT_HIZ_CFG3 */
+#define MAX98926_DAI_SLOT_HIZ_CFG3_MASK         (0xFF<<0)
+#define MAX98926_DAI_SLOT_HIZ_CFG3_SHIFT            0
+#define MAX98926_DAI_SLOT_HIZ_CFG3_WIDTH            8
+
+/* MAX98926_R02A_DOUT_HIZ_CFG4 */
+#define MAX98926_DAI_SLOT_HIZ_CFG4_MASK         (0xFF<<0)
+#define MAX98926_DAI_SLOT_HIZ_CFG4_SHIFT            0
+#define MAX98926_DAI_SLOT_HIZ_CFG4_WIDTH            8
+
+/* MAX98926_R02B_DOUT_DRV_STRENGTH */
+#define MAX98926_DAI_OUT_DRIVE_MASK             (0x03<<0)
+#define MAX98926_DAI_OUT_DRIVE_SHIFT                0
+#define MAX98926_DAI_OUT_DRIVE_WIDTH                2
+
+/* MAX98926_R02C_FILTERS */
+#define MAX98926_ADC_DITHER_EN_MASK             (1<<7)
+#define MAX98926_ADC_DITHER_EN_SHIFT                7
+#define MAX98926_ADC_DITHER_EN_WIDTH                1
+#define MAX98926_IV_DCB_EN_MASK                 (1<<6)
+#define MAX98926_IV_DCB_EN_SHIFT                    6
+#define MAX98926_IV_DCB_EN_WIDTH                    1
+#define MAX98926_DAC_DITHER_EN_MASK             (1<<4)
+#define MAX98926_DAC_DITHER_EN_SHIFT                4
+#define MAX98926_DAC_DITHER_EN_WIDTH                1
+#define MAX98926_DAC_FILTER_MODE_MASK               (1<<3)
+#define MAX98926_DAC_FILTER_MODE_SHIFT          3
+#define MAX98926_DAC_FILTER_MODE_WIDTH          1
+#define MAX98926_DAC_HPF_MASK               (0x07<<0)
+#define MAX98926_DAC_HPF_SHIFT                  0
+#define MAX98926_DAC_HPF_WIDTH                  3
+#define MAX98926_DAC_HPF_DISABLE        (0 << MAX98926_DAC_HPF_SHIFT)
+#define MAX98926_DAC_HPF_DC_BLOCK       (1 << MAX98926_DAC_HPF_SHIFT)
+#define MAX98926_DAC_HPF_EN_100     (2 << MAX98926_DAC_HPF_SHIFT)
+#define MAX98926_DAC_HPF_EN_200     (3 << MAX98926_DAC_HPF_SHIFT)
+#define MAX98926_DAC_HPF_EN_400     (4 << MAX98926_DAC_HPF_SHIFT)
+#define MAX98926_DAC_HPF_EN_800     (5 << MAX98926_DAC_HPF_SHIFT)
+
+/* MAX98926_R02D_GAIN */
+#define MAX98926_DAC_IN_SEL_MASK    (0x03<<5)
+#define MAX98926_DAC_IN_SEL_SHIFT   5
+#define MAX98926_DAC_IN_SEL_WIDTH   2
+#define MAX98926_SPK_GAIN_MASK      (0x1F<<0)
+#define MAX98926_SPK_GAIN_SHIFT     0
+#define MAX98926_SPK_GAIN_WIDTH     5
+
+#define MAX98926_DAC_IN_SEL_LEFT_DAI (0 << MAX98926_DAC_IN_SEL_SHIFT)
+#define MAX98926_DAC_IN_SEL_RIGHT_DAI (1 << MAX98926_DAC_IN_SEL_SHIFT)
+#define MAX98926_DAC_IN_SEL_SUMMED_DAI (2 << MAX98926_DAC_IN_SEL_SHIFT)
+#define MAX98926_DAC_IN_SEL_DIV2_SUMMED_DAI (3 << MAX98926_DAC_IN_SEL_SHIFT)
+
+/* MAX98926_R02E_GAIN_RAMPING */
+#define MAX98926_SPK_RMP_EN_MASK        (1<<1)
+#define MAX98926_SPK_RMP_EN_SHIFT       1
+#define MAX98926_SPK_RMP_EN_WIDTH       1
+#define MAX98926_SPK_ZCD_EN_MASK        (1<<0)
+#define MAX98926_SPK_ZCD_EN_SHIFT       0
+#define MAX98926_SPK_ZCD_EN_WIDTH       1
+
+/* MAX98926_R02F_SPK_AMP */
+#define MAX98926_SPK_MODE_MASK      (1<<0)
+#define MAX98926_SPK_MODE_SHIFT     0
+#define MAX98926_SPK_MODE_WIDTH     1
+#define MAX98926_INSELECT_MODE_MASK (1<<1)
+#define MAX98926_INSELECT_MODE_SHIFT    1
+#define MAX98926_INSELECT_MODE_WIDTH    1
+
+/* MAX98926_R030_THRESHOLD */
+#define MAX98926_ALC_EN_MASK            (1<<5)
+#define MAX98926_ALC_EN_SHIFT           5
+#define MAX98926_ALC_EN_WIDTH           1
+#define MAX98926_ALC_TH_MASK            (0x1F<<0)
+#define MAX98926_ALC_TH_SHIFT           0
+#define MAX98926_ALC_TH_WIDTH           5
+
+/* MAX98926_R031_ALC_ATTACK */
+#define MAX98926_ALC_ATK_STEP_MASK  (0x0F<<4)
+#define MAX98926_ALC_ATK_STEP_SHIFT 4
+#define MAX98926_ALC_ATK_STEP_WIDTH 4
+#define MAX98926_ALC_ATK_RATE_MASK  (0x7<<0)
+#define MAX98926_ALC_ATK_RATE_SHIFT 0
+#define MAX98926_ALC_ATK_RATE_WIDTH 3
+
+/* MAX98926_R032_ALC_ATTEN_RLS */
+#define MAX98926_ALC_MAX_ATTEN_MASK (0x0F<<4)
+#define MAX98926_ALC_MAX_ATTEN_SHIFT    4
+#define MAX98926_ALC_MAX_ATTEN_WIDTH    4
+#define MAX98926_ALC_RLS_RATE_MASK  (0x7<<0)
+#define MAX98926_ALC_RLS_RATE_SHIFT 0
+#define MAX98926_ALC_RLS_RATE_WIDTH 3
+
+/* MAX98926_R033_ALC_HOLD_RLS */
+#define MAX98926_ALC_RLS_TGR_MASK       (1<<0)
+#define MAX98926_ALC_RLS_TGR_SHIFT  0
+#define MAX98926_ALC_RLS_TGR_WIDTH  1
+
+/* MAX98926_R034_ALC_CONFIGURATION */
+#define MAX98926_ALC_MUTE_EN_MASK       (1<<7)
+#define MAX98926_ALC_MUTE_EN_SHIFT  7
+#define MAX98926_ALC_MUTE_EN_WIDTH  1
+#define MAX98926_ALC_MUTE_DLY_MASK  (0x07<<4)
+#define MAX98926_ALC_MUTE_DLY_SHIFT 4
+#define MAX98926_ALC_MUTE_DLY_WIDTH 3
+#define MAX98926_ALC_RLS_DBT_MASK       (0x07<<0)
+#define MAX98926_ALC_RLS_DBT_SHIFT  0
+#define MAX98926_ALC_RLS_DBT_WIDTH  3
+
+/* MAX98926_R035_BOOST_CONVERTER */
+#define MAX98926_BST_SYNC_MASK      (1<<7)
+#define MAX98926_BST_SYNC_SHIFT     7
+#define MAX98926_BST_SYNC_WIDTH     1
+#define MAX98926_BST_PHASE_MASK     (0x03<<4)
+#define MAX98926_BST_PHASE_SHIFT        4
+#define MAX98926_BST_PHASE_WIDTH        2
+#define MAX98926_BST_SKIP_MODE_MASK (0x03<<0)
+#define MAX98926_BST_SKIP_MODE_SHIFT    0
+#define MAX98926_BST_SKIP_MODE_WIDTH    2
+
+/* MAX98926_R036_BLOCK_ENABLE */
+#define MAX98926_BST_EN_MASK            (1<<7)
+#define MAX98926_BST_EN_SHIFT           7
+#define MAX98926_BST_EN_WIDTH           1
+#define MAX98926_WATCH_EN_MASK      (1<<6)
+#define MAX98926_WATCH_EN_SHIFT     6
+#define MAX98926_WATCH_EN_WIDTH     1
+#define MAX98926_CLKMON_EN_MASK     (1<<5)
+#define MAX98926_CLKMON_EN_SHIFT        5
+#define MAX98926_CLKMON_EN_WIDTH        1
+#define MAX98926_SPK_EN_MASK            (1<<4)
+#define MAX98926_SPK_EN_SHIFT           4
+#define MAX98926_SPK_EN_WIDTH           1
+#define MAX98926_ADC_VBST_EN_MASK       (1<<3)
+#define MAX98926_ADC_VBST_EN_SHIFT  3
+#define MAX98926_ADC_VBST_EN_WIDTH  1
+#define MAX98926_ADC_VBAT_EN_MASK       (1<<2)
+#define MAX98926_ADC_VBAT_EN_SHIFT  2
+#define MAX98926_ADC_VBAT_EN_WIDTH  1
+#define MAX98926_ADC_IMON_EN_MASK       (1<<1)
+#define MAX98926_ADC_IMON_EN_SHIFT  1
+#define MAX98926_ADC_IMON_EN_WIDTH  1
+#define MAX98926_ADC_VMON_EN_MASK       (1<<0)
+#define MAX98926_ADC_VMON_EN_SHIFT  0
+#define MAX98926_ADC_VMON_EN_WIDTH  1
+
+/* MAX98926_R037_CONFIGURATION */
+#define MAX98926_BST_VOUT_MASK      (0x0F<<4)
+#define MAX98926_BST_VOUT_SHIFT     4
+#define MAX98926_BST_VOUT_WIDTH     4
+#define MAX98926_THERMWARN_LEVEL_MASK   (0x03<<2)
+#define MAX98926_THERMWARN_LEVEL_SHIFT          2
+#define MAX98926_THERMWARN_LEVEL_WIDTH          2
+#define MAX98926_WATCH_TIME_MASK            (0x03<<0)
+#define MAX98926_WATCH_TIME_SHIFT           0
+#define MAX98926_WATCH_TIME_WIDTH           2
+
+/* MAX98926_R038_GLOBAL_ENABLE */
+#define MAX98926_EN_MASK            (1<<7)
+#define MAX98926_EN_SHIFT           7
+#define MAX98926_EN_WIDTH           1
+
+/* MAX98926_R03A_BOOST_LIMITER */
+#define MAX98926_BST_ILIM_MASK  (0xF<<4)
+#define MAX98926_BST_ILIM_SHIFT 4
+#define MAX98926_BST_ILIM_WIDTH 4
+
+/* MAX98926_R0FF_VERSION */
+#define MAX98926_REV_ID_MASK    (0xFF<<0)
+#define MAX98926_REV_ID_SHIFT   0
+#define MAX98926_REV_ID_WIDTH   8
+
+struct max98926_priv {
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	unsigned int sysclk;
+	unsigned int v_slot;
+	unsigned int i_slot;
+	unsigned int ch_size;
+	unsigned int interleave_mode;
+};
+#endif
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
new file mode 100644
index 0000000..065303a
--- /dev/null
+++ b/sound/soc/codecs/max98927.c
@@ -0,0 +1,966 @@
+/*
+ * max98927.c  --  MAX98927 ALSA Soc Audio driver
+ *
+ * Copyright (C) 2016-2017 Maxim Integrated Products
+ * Author: Ryan Lee <ryans.lee@maximintegrated.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/tlv.h>
+#include "max98927.h"
+
+static struct reg_default max98927_reg[] = {
+	{MAX98927_R0001_INT_RAW1,  0x00},
+	{MAX98927_R0002_INT_RAW2,  0x00},
+	{MAX98927_R0003_INT_RAW3,  0x00},
+	{MAX98927_R0004_INT_STATE1,  0x00},
+	{MAX98927_R0005_INT_STATE2,  0x00},
+	{MAX98927_R0006_INT_STATE3,  0x00},
+	{MAX98927_R0007_INT_FLAG1,  0x00},
+	{MAX98927_R0008_INT_FLAG2,  0x00},
+	{MAX98927_R0009_INT_FLAG3,  0x00},
+	{MAX98927_R000A_INT_EN1,  0x00},
+	{MAX98927_R000B_INT_EN2,  0x00},
+	{MAX98927_R000C_INT_EN3,  0x00},
+	{MAX98927_R000D_INT_FLAG_CLR1,  0x00},
+	{MAX98927_R000E_INT_FLAG_CLR2,  0x00},
+	{MAX98927_R000F_INT_FLAG_CLR3,  0x00},
+	{MAX98927_R0010_IRQ_CTRL,  0x00},
+	{MAX98927_R0011_CLK_MON,  0x00},
+	{MAX98927_R0012_WDOG_CTRL,  0x00},
+	{MAX98927_R0013_WDOG_RST,  0x00},
+	{MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH,  0x75},
+	{MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH,  0x8c},
+	{MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS,  0x08},
+	{MAX98927_R0017_PIN_CFG,  0x55},
+	{MAX98927_R0018_PCM_RX_EN_A,  0x00},
+	{MAX98927_R0019_PCM_RX_EN_B,  0x00},
+	{MAX98927_R001A_PCM_TX_EN_A,  0x00},
+	{MAX98927_R001B_PCM_TX_EN_B,  0x00},
+	{MAX98927_R001C_PCM_TX_HIZ_CTRL_A,  0x00},
+	{MAX98927_R001D_PCM_TX_HIZ_CTRL_B,  0x00},
+	{MAX98927_R001E_PCM_TX_CH_SRC_A,  0x00},
+	{MAX98927_R001F_PCM_TX_CH_SRC_B,  0x00},
+	{MAX98927_R0020_PCM_MODE_CFG,  0x40},
+	{MAX98927_R0021_PCM_MASTER_MODE,  0x00},
+	{MAX98927_R0022_PCM_CLK_SETUP,  0x22},
+	{MAX98927_R0023_PCM_SR_SETUP1,  0x00},
+	{MAX98927_R0024_PCM_SR_SETUP2,  0x00},
+	{MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,  0x00},
+	{MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,  0x00},
+	{MAX98927_R0027_ICC_RX_EN_A,  0x00},
+	{MAX98927_R0028_ICC_RX_EN_B,  0x00},
+	{MAX98927_R002B_ICC_TX_EN_A,  0x00},
+	{MAX98927_R002C_ICC_TX_EN_B,  0x00},
+	{MAX98927_R002E_ICC_HIZ_MANUAL_MODE,  0x00},
+	{MAX98927_R002F_ICC_TX_HIZ_EN_A,  0x00},
+	{MAX98927_R0030_ICC_TX_HIZ_EN_B,  0x00},
+	{MAX98927_R0031_ICC_LNK_EN,  0x00},
+	{MAX98927_R0032_PDM_TX_EN,  0x00},
+	{MAX98927_R0033_PDM_TX_HIZ_CTRL,  0x00},
+	{MAX98927_R0034_PDM_TX_CTRL,  0x00},
+	{MAX98927_R0035_PDM_RX_CTRL,  0x00},
+	{MAX98927_R0036_AMP_VOL_CTRL,  0x00},
+	{MAX98927_R0037_AMP_DSP_CFG,  0x02},
+	{MAX98927_R0038_TONE_GEN_DC_CFG,  0x00},
+	{MAX98927_R0039_DRE_CTRL,  0x01},
+	{MAX98927_R003A_AMP_EN,  0x00},
+	{MAX98927_R003B_SPK_SRC_SEL,  0x00},
+	{MAX98927_R003C_SPK_GAIN,  0x00},
+	{MAX98927_R003D_SSM_CFG,  0x04},
+	{MAX98927_R003E_MEAS_EN,  0x00},
+	{MAX98927_R003F_MEAS_DSP_CFG,  0x04},
+	{MAX98927_R0040_BOOST_CTRL0,  0x00},
+	{MAX98927_R0041_BOOST_CTRL3,  0x00},
+	{MAX98927_R0042_BOOST_CTRL1,  0x00},
+	{MAX98927_R0043_MEAS_ADC_CFG,  0x00},
+	{MAX98927_R0044_MEAS_ADC_BASE_MSB,  0x01},
+	{MAX98927_R0045_MEAS_ADC_BASE_LSB,  0x00},
+	{MAX98927_R0046_ADC_CH0_DIVIDE,  0x00},
+	{MAX98927_R0047_ADC_CH1_DIVIDE,  0x00},
+	{MAX98927_R0048_ADC_CH2_DIVIDE,  0x00},
+	{MAX98927_R0049_ADC_CH0_FILT_CFG,  0x00},
+	{MAX98927_R004A_ADC_CH1_FILT_CFG,  0x00},
+	{MAX98927_R004B_ADC_CH2_FILT_CFG,  0x00},
+	{MAX98927_R004C_MEAS_ADC_CH0_READ,  0x00},
+	{MAX98927_R004D_MEAS_ADC_CH1_READ,  0x00},
+	{MAX98927_R004E_MEAS_ADC_CH2_READ,  0x00},
+	{MAX98927_R0051_BROWNOUT_STATUS,  0x00},
+	{MAX98927_R0052_BROWNOUT_EN,  0x00},
+	{MAX98927_R0053_BROWNOUT_INFINITE_HOLD,  0x00},
+	{MAX98927_R0054_BROWNOUT_INFINITE_HOLD_CLR,  0x00},
+	{MAX98927_R0055_BROWNOUT_LVL_HOLD,  0x00},
+	{MAX98927_R005A_BROWNOUT_LVL1_THRESH,  0x00},
+	{MAX98927_R005B_BROWNOUT_LVL2_THRESH,  0x00},
+	{MAX98927_R005C_BROWNOUT_LVL3_THRESH,  0x00},
+	{MAX98927_R005D_BROWNOUT_LVL4_THRESH,  0x00},
+	{MAX98927_R005E_BROWNOUT_THRESH_HYSTERYSIS,  0x00},
+	{MAX98927_R005F_BROWNOUT_AMP_LIMITER_ATK_REL,  0x00},
+	{MAX98927_R0060_BROWNOUT_AMP_GAIN_ATK_REL,  0x00},
+	{MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE,  0x00},
+	{MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT,  0x00},
+	{MAX98927_R0073_BROWNOUT_LVL1_AMP1_CTRL1,  0x00},
+	{MAX98927_R0074_BROWNOUT_LVL1_AMP1_CTRL2,  0x00},
+	{MAX98927_R0075_BROWNOUT_LVL1_AMP1_CTRL3,  0x00},
+	{MAX98927_R0076_BROWNOUT_LVL2_CUR_LIMIT,  0x00},
+	{MAX98927_R0077_BROWNOUT_LVL2_AMP1_CTRL1,  0x00},
+	{MAX98927_R0078_BROWNOUT_LVL2_AMP1_CTRL2,  0x00},
+	{MAX98927_R0079_BROWNOUT_LVL2_AMP1_CTRL3,  0x00},
+	{MAX98927_R007A_BROWNOUT_LVL3_CUR_LIMIT,  0x00},
+	{MAX98927_R007B_BROWNOUT_LVL3_AMP1_CTRL1,  0x00},
+	{MAX98927_R007C_BROWNOUT_LVL3_AMP1_CTRL2,  0x00},
+	{MAX98927_R007D_BROWNOUT_LVL3_AMP1_CTRL3,  0x00},
+	{MAX98927_R007E_BROWNOUT_LVL4_CUR_LIMIT,  0x00},
+	{MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,  0x00},
+	{MAX98927_R0080_BROWNOUT_LVL4_AMP1_CTRL2,  0x00},
+	{MAX98927_R0081_BROWNOUT_LVL4_AMP1_CTRL3,  0x00},
+	{MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,  0x00},
+	{MAX98927_R0083_ENV_TRACK_BOOST_VOUT_DELAY,  0x00},
+	{MAX98927_R0084_ENV_TRACK_REL_RATE,  0x00},
+	{MAX98927_R0085_ENV_TRACK_HOLD_RATE,  0x00},
+	{MAX98927_R0086_ENV_TRACK_CTRL,  0x00},
+	{MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,  0x00},
+	{MAX98927_R00FF_GLOBAL_SHDN,  0x00},
+	{MAX98927_R0100_SOFT_RESET,  0x00},
+	{MAX98927_R01FF_REV_ID,  0x40},
+};
+
+static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component);
+	unsigned int mode = 0;
+	unsigned int format = 0;
+	bool use_pdm = false;
+	unsigned int invert = 0;
+
+	dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		mode = MAX98927_PCM_MASTER_MODE_SLAVE;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		max98927->master = true;
+		mode = MAX98927_PCM_MASTER_MODE_MASTER;
+		break;
+	default:
+		dev_err(component->dev, "DAI clock mode unsupported\n");
+		return -EINVAL;
+	}
+
+	regmap_update_bits(max98927->regmap,
+		MAX98927_R0021_PCM_MASTER_MODE,
+		MAX98927_PCM_MASTER_MODE_MASK,
+		mode);
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		invert = MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE;
+		break;
+	default:
+		dev_err(component->dev, "DAI invert mode unsupported\n");
+		return -EINVAL;
+	}
+
+	regmap_update_bits(max98927->regmap,
+		MAX98927_R0020_PCM_MODE_CFG,
+		MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE,
+		invert);
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		format = MAX98927_PCM_FORMAT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		format = MAX98927_PCM_FORMAT_LJ;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		format = MAX98927_PCM_FORMAT_TDM_MODE1;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		format = MAX98927_PCM_FORMAT_TDM_MODE0;
+		break;
+	case SND_SOC_DAIFMT_PDM:
+		use_pdm = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+	max98927->iface = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+	if (!use_pdm) {
+		/* pcm channel configuration */
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R0018_PCM_RX_EN_A,
+			MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
+			MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN);
+
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R0020_PCM_MODE_CFG,
+			MAX98927_PCM_MODE_CFG_FORMAT_MASK,
+			format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT);
+
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R003B_SPK_SRC_SEL,
+			MAX98927_SPK_SRC_MASK, 0);
+
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R0035_PDM_RX_CTRL,
+			MAX98927_PDM_RX_EN_MASK, 0);
+	} else {
+		/* pdm channel configuration */
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R0035_PDM_RX_CTRL,
+			MAX98927_PDM_RX_EN_MASK, 1);
+
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R003B_SPK_SRC_SEL,
+			MAX98927_SPK_SRC_MASK, 3);
+
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R0018_PCM_RX_EN_A,
+			MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0);
+	}
+	return 0;
+}
+
+/* codec MCLK rate in master mode */
+static const int rate_table[] = {
+	5644800, 6000000, 6144000, 6500000,
+	9600000, 11289600, 12000000, 12288000,
+	13000000, 19200000,
+};
+
+/* BCLKs per LRCLK */
+static const int bclk_sel_table[] = {
+	32, 48, 64, 96, 128, 192, 256, 384, 512,
+};
+
+static int max98927_get_bclk_sel(int bclk)
+{
+	int i;
+	/* match BCLKs per LRCLK */
+	for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) {
+		if (bclk_sel_table[i] == bclk)
+			return i + 2;
+	}
+	return 0;
+}
+static int max98927_set_clock(struct max98927_priv *max98927,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_component *component = max98927->component;
+	/* BCLK/LRCLK ratio calculation */
+	int blr_clk_ratio = params_channels(params) * max98927->ch_size;
+	int value;
+
+	if (max98927->master) {
+		int i;
+		/* match rate to closest value */
+		for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+			if (rate_table[i] >= max98927->sysclk)
+				break;
+		}
+		if (i == ARRAY_SIZE(rate_table)) {
+			dev_err(component->dev, "failed to find proper clock rate.\n");
+			return -EINVAL;
+		}
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R0021_PCM_MASTER_MODE,
+			MAX98927_PCM_MASTER_MODE_MCLK_MASK,
+			i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
+	}
+
+	if (!max98927->tdm_mode) {
+		/* BCLK configuration */
+		value = max98927_get_bclk_sel(blr_clk_ratio);
+		if (!value) {
+			dev_err(component->dev, "format unsupported %d\n",
+				params_format(params));
+			return -EINVAL;
+		}
+
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R0022_PCM_CLK_SETUP,
+			MAX98927_PCM_CLK_SETUP_BSEL_MASK,
+			value);
+	}
+	return 0;
+}
+
+static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component);
+	unsigned int sampling_rate = 0;
+	unsigned int chan_sz = 0;
+
+	/* pcm mode configuration */
+	switch (snd_pcm_format_width(params_format(params))) {
+	case 16:
+		chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_16;
+		break;
+	case 24:
+		chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_24;
+		break;
+	case 32:
+		chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
+		break;
+	default:
+		dev_err(component->dev, "format unsupported %d\n",
+			params_format(params));
+		goto err;
+	}
+
+	max98927->ch_size = snd_pcm_format_width(params_format(params));
+
+	regmap_update_bits(max98927->regmap,
+		MAX98927_R0020_PCM_MODE_CFG,
+		MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+
+	dev_dbg(component->dev, "format supported %d",
+		params_format(params));
+
+	/* sampling rate configuration */
+	switch (params_rate(params)) {
+	case 8000:
+		sampling_rate = MAX98927_PCM_SR_SET1_SR_8000;
+		break;
+	case 11025:
+		sampling_rate = MAX98927_PCM_SR_SET1_SR_11025;
+		break;
+	case 12000:
+		sampling_rate = MAX98927_PCM_SR_SET1_SR_12000;
+		break;
+	case 16000:
+		sampling_rate = MAX98927_PCM_SR_SET1_SR_16000;
+		break;
+	case 22050:
+		sampling_rate = MAX98927_PCM_SR_SET1_SR_22050;
+		break;
+	case 24000:
+		sampling_rate = MAX98927_PCM_SR_SET1_SR_24000;
+		break;
+	case 32000:
+		sampling_rate = MAX98927_PCM_SR_SET1_SR_32000;
+		break;
+	case 44100:
+		sampling_rate = MAX98927_PCM_SR_SET1_SR_44100;
+		break;
+	case 48000:
+		sampling_rate = MAX98927_PCM_SR_SET1_SR_48000;
+		break;
+	default:
+		dev_err(component->dev, "rate %d not supported\n",
+			params_rate(params));
+		goto err;
+	}
+	/* set DAI_SR to correct LRCLK frequency */
+	regmap_update_bits(max98927->regmap,
+		MAX98927_R0023_PCM_SR_SETUP1,
+		MAX98927_PCM_SR_SET1_SR_MASK,
+		sampling_rate);
+	regmap_update_bits(max98927->regmap,
+		MAX98927_R0024_PCM_SR_SETUP2,
+		MAX98927_PCM_SR_SET2_SR_MASK,
+		sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT);
+
+	/* set sampling rate of IV */
+	if (max98927->interleave_mode &&
+	    sampling_rate > MAX98927_PCM_SR_SET1_SR_16000)
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R0024_PCM_SR_SETUP2,
+			MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
+			sampling_rate - 3);
+	else
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R0024_PCM_SR_SETUP2,
+			MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
+			sampling_rate);
+	return max98927_set_clock(max98927, params);
+err:
+	return -EINVAL;
+}
+
+static int max98927_dai_tdm_slot(struct snd_soc_dai *dai,
+	unsigned int tx_mask, unsigned int rx_mask,
+	int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component);
+	int bsel = 0;
+	unsigned int chan_sz = 0;
+
+	max98927->tdm_mode = true;
+
+	/* BCLK configuration */
+	bsel = max98927_get_bclk_sel(slots * slot_width);
+	if (bsel == 0) {
+		dev_err(component->dev, "BCLK %d not supported\n",
+			slots * slot_width);
+		return -EINVAL;
+	}
+
+	regmap_update_bits(max98927->regmap,
+		MAX98927_R0022_PCM_CLK_SETUP,
+		MAX98927_PCM_CLK_SETUP_BSEL_MASK,
+		bsel);
+
+	/* Channel size configuration */
+	switch (slot_width) {
+	case 16:
+		chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_16;
+		break;
+	case 24:
+		chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_24;
+		break;
+	case 32:
+		chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
+		break;
+	default:
+		dev_err(component->dev, "format unsupported %d\n",
+			slot_width);
+		return -EINVAL;
+	}
+
+	regmap_update_bits(max98927->regmap,
+		MAX98927_R0020_PCM_MODE_CFG,
+		MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+
+	/* Rx slot configuration */
+	regmap_write(max98927->regmap,
+		MAX98927_R0018_PCM_RX_EN_A,
+		rx_mask & 0xFF);
+	regmap_write(max98927->regmap,
+		MAX98927_R0019_PCM_RX_EN_B,
+		(rx_mask & 0xFF00) >> 8);
+
+	/* Tx slot configuration */
+	regmap_write(max98927->regmap,
+		MAX98927_R001A_PCM_TX_EN_A,
+		tx_mask & 0xFF);
+	regmap_write(max98927->regmap,
+		MAX98927_R001B_PCM_TX_EN_B,
+		(tx_mask & 0xFF00) >> 8);
+
+	/* Tx slot Hi-Z configuration */
+	regmap_write(max98927->regmap,
+		MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+		~tx_mask & 0xFF);
+	regmap_write(max98927->regmap,
+		MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+		(~tx_mask & 0xFF00) >> 8);
+
+	return 0;
+}
+
+#define MAX98927_RATES SNDRV_PCM_RATE_8000_48000
+
+#define MAX98927_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static int max98927_dai_set_sysclk(struct snd_soc_dai *dai,
+	int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component);
+
+	max98927->sysclk = freq;
+	return 0;
+}
+
+static const struct snd_soc_dai_ops max98927_dai_ops = {
+	.set_sysclk = max98927_dai_set_sysclk,
+	.set_fmt = max98927_dai_set_fmt,
+	.hw_params = max98927_dai_hw_params,
+	.set_tdm_slot = max98927_dai_tdm_slot,
+};
+
+static int max98927_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		max98927->tdm_mode = 0;
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R003A_AMP_EN,
+			MAX98927_AMP_EN_MASK, 1);
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R00FF_GLOBAL_SHDN,
+			MAX98927_GLOBAL_EN_MASK, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R00FF_GLOBAL_SHDN,
+			MAX98927_GLOBAL_EN_MASK, 0);
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R003A_AMP_EN,
+			MAX98927_AMP_EN_MASK, 0);
+		break;
+	default:
+		return 0;
+	}
+	return 0;
+}
+
+static const char * const max98927_switch_text[] = {
+	"Left", "Right", "LeftRight"};
+
+static const struct soc_enum dai_sel_enum =
+	SOC_ENUM_SINGLE(MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
+		MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
+		3, max98927_switch_text);
+
+static const struct snd_kcontrol_new max98927_dai_controls =
+	SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
+
+static const struct snd_kcontrol_new max98927_vi_control =
+	SOC_DAPM_SINGLE("Switch", MAX98927_R003F_MEAS_DSP_CFG, 2, 1, 0);
+
+static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN,
+		0, 0, max98927_dac_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
+		&max98927_dai_controls),
+	SND_SOC_DAPM_OUTPUT("BE_OUT"),
+	SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture",  0,
+		MAX98927_R003E_MEAS_EN, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture",  0,
+		MAX98927_R003E_MEAS_EN, 1, 0),
+	SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0,
+		&max98927_vi_control),
+	SND_SOC_DAPM_SIGGEN("VMON"),
+	SND_SOC_DAPM_SIGGEN("IMON"),
+};
+
+static DECLARE_TLV_DB_SCALE(max98927_spk_tlv, 300, 300, 0);
+static DECLARE_TLV_DB_SCALE(max98927_digital_tlv, -1600, 25, 0);
+
+static bool max98927_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98927_R0001_INT_RAW1 ... MAX98927_R0028_ICC_RX_EN_B:
+	case MAX98927_R002B_ICC_TX_EN_A ... MAX98927_R002C_ICC_TX_EN_B:
+	case MAX98927_R002E_ICC_HIZ_MANUAL_MODE
+		... MAX98927_R004E_MEAS_ADC_CH2_READ:
+	case MAX98927_R0051_BROWNOUT_STATUS
+		... MAX98927_R0055_BROWNOUT_LVL_HOLD:
+	case MAX98927_R005A_BROWNOUT_LVL1_THRESH
+		... MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE:
+	case MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT
+		... MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ:
+	case MAX98927_R00FF_GLOBAL_SHDN:
+	case MAX98927_R0100_SOFT_RESET:
+	case MAX98927_R01FF_REV_ID:
+		return true;
+	default:
+		return false;
+	}
+};
+
+static bool max98927_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX98927_R0001_INT_RAW1 ... MAX98927_R0009_INT_FLAG3:
+	case MAX98927_R004C_MEAS_ADC_CH0_READ:
+	case MAX98927_R004D_MEAS_ADC_CH1_READ:
+	case MAX98927_R004E_MEAS_ADC_CH2_READ:
+	case MAX98927_R0051_BROWNOUT_STATUS:
+	case MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ:
+	case MAX98927_R01FF_REV_ID:
+	case MAX98927_R0100_SOFT_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const char * const max98927_boost_voltage_text[] = {
+	"6.5V", "6.625V", "6.75V", "6.875V", "7V", "7.125V", "7.25V", "7.375V",
+	"7.5V", "7.625V", "7.75V", "7.875V", "8V", "8.125V", "8.25V", "8.375V",
+	"8.5V", "8.625V", "8.75V", "8.875V", "9V", "9.125V", "9.25V", "9.375V",
+	"9.5V", "9.625V", "9.75V", "9.875V", "10V"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98927_boost_voltage,
+		MAX98927_R0040_BOOST_CTRL0, 0,
+		max98927_boost_voltage_text);
+
+static const char * const max98927_current_limit_text[] = {
+	"1.00A", "1.10A", "1.20A", "1.30A", "1.40A", "1.50A", "1.60A", "1.70A",
+	"1.80A", "1.90A", "2.00A", "2.10A", "2.20A", "2.30A", "2.40A", "2.50A",
+	"2.60A", "2.70A", "2.80A", "2.90A", "3.00A", "3.10A", "3.20A", "3.30A",
+	"3.40A", "3.50A", "3.60A", "3.70A", "3.80A", "3.90A", "4.00A", "4.10A"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98927_current_limit,
+		MAX98927_R0042_BOOST_CTRL1, 1,
+		max98927_current_limit_text);
+
+static const struct snd_kcontrol_new max98927_snd_controls[] = {
+	SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN,
+		0, 6, 0,
+		max98927_spk_tlv),
+	SOC_SINGLE_TLV("Digital Volume", MAX98927_R0036_AMP_VOL_CTRL,
+		0, (1<<MAX98927_AMP_VOL_WIDTH)-1, 0,
+		max98927_digital_tlv),
+	SOC_SINGLE("Amp DSP Switch", MAX98927_R0052_BROWNOUT_EN,
+		MAX98927_BROWNOUT_DSP_SHIFT, 1, 0),
+	SOC_SINGLE("Ramp Switch", MAX98927_R0037_AMP_DSP_CFG,
+		MAX98927_AMP_DSP_CFG_RMP_SHIFT, 1, 0),
+	SOC_SINGLE("DRE Switch", MAX98927_R0039_DRE_CTRL,
+		MAX98927_DRE_EN_SHIFT, 1, 0),
+	SOC_SINGLE("Volume Location Switch", MAX98927_R0036_AMP_VOL_CTRL,
+		MAX98927_AMP_VOL_SEL_SHIFT, 1, 0),
+	SOC_ENUM("Boost Output Voltage", max98927_boost_voltage),
+	SOC_ENUM("Current Limit", max98927_current_limit),
+};
+
+static const struct snd_soc_dapm_route max98927_audio_map[] = {
+	/* Plabyack */
+	{"DAI Sel Mux", "Left", "Amp Enable"},
+	{"DAI Sel Mux", "Right", "Amp Enable"},
+	{"DAI Sel Mux", "LeftRight", "Amp Enable"},
+	{"BE_OUT", NULL, "DAI Sel Mux"},
+	/* Capture */
+	{ "VI Sense", "Switch", "VMON" },
+	{ "VI Sense", "Switch", "IMON" },
+	{ "Voltage Sense", NULL, "VI Sense" },
+	{ "Current Sense", NULL, "VI Sense" },
+};
+
+static struct snd_soc_dai_driver max98927_dai[] = {
+	{
+		.name = "max98927-aif1",
+		.playback = {
+			.stream_name = "HiFi Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MAX98927_RATES,
+			.formats = MAX98927_FORMATS,
+		},
+		.capture = {
+			.stream_name = "HiFi Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MAX98927_RATES,
+			.formats = MAX98927_FORMATS,
+		},
+		.ops = &max98927_dai_ops,
+	}
+};
+
+static int max98927_probe(struct snd_soc_component *component)
+{
+	struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component);
+
+	max98927->component = component;
+
+	/* Software Reset */
+	regmap_write(max98927->regmap,
+		MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
+
+	/* IV default slot configuration */
+	regmap_write(max98927->regmap,
+		MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+		0xFF);
+	regmap_write(max98927->regmap,
+		MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+		0xFF);
+	regmap_write(max98927->regmap,
+		MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
+		0x80);
+	regmap_write(max98927->regmap,
+		MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,
+		0x1);
+	/* Set inital volume (+13dB) */
+	regmap_write(max98927->regmap,
+		MAX98927_R0036_AMP_VOL_CTRL,
+		0x38);
+	regmap_write(max98927->regmap,
+		MAX98927_R003C_SPK_GAIN,
+		0x05);
+	/* Enable DC blocker */
+	regmap_write(max98927->regmap,
+		MAX98927_R0037_AMP_DSP_CFG,
+		0x03);
+	/* Enable IMON VMON DC blocker */
+	regmap_write(max98927->regmap,
+		MAX98927_R003F_MEAS_DSP_CFG,
+		0xF7);
+	/* Boost Output Voltage & Current limit */
+	regmap_write(max98927->regmap,
+		MAX98927_R0040_BOOST_CTRL0,
+		0x1C);
+	regmap_write(max98927->regmap,
+		MAX98927_R0042_BOOST_CTRL1,
+		0x3E);
+	/* Measurement ADC config */
+	regmap_write(max98927->regmap,
+		MAX98927_R0043_MEAS_ADC_CFG,
+		0x04);
+	regmap_write(max98927->regmap,
+		MAX98927_R0044_MEAS_ADC_BASE_MSB,
+		0x00);
+	regmap_write(max98927->regmap,
+		MAX98927_R0045_MEAS_ADC_BASE_LSB,
+		0x24);
+	/* Brownout Level */
+	regmap_write(max98927->regmap,
+		MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,
+		0x06);
+	/* Envelope Tracking configuration */
+	regmap_write(max98927->regmap,
+		MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,
+		0x08);
+	regmap_write(max98927->regmap,
+		MAX98927_R0086_ENV_TRACK_CTRL,
+		0x01);
+	regmap_write(max98927->regmap,
+		MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,
+		0x10);
+
+	/* voltage, current slot configuration */
+	regmap_write(max98927->regmap,
+		MAX98927_R001E_PCM_TX_CH_SRC_A,
+		(max98927->i_l_slot<<MAX98927_PCM_TX_CH_SRC_A_I_SHIFT|
+		max98927->v_l_slot)&0xFF);
+
+	if (max98927->v_l_slot < 8) {
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+			1 << max98927->v_l_slot, 0);
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R001A_PCM_TX_EN_A,
+			1 << max98927->v_l_slot,
+			1 << max98927->v_l_slot);
+	} else {
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+			1 << (max98927->v_l_slot - 8), 0);
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R001B_PCM_TX_EN_B,
+			1 << (max98927->v_l_slot - 8),
+			1 << (max98927->v_l_slot - 8));
+	}
+
+	if (max98927->i_l_slot < 8) {
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+			1 << max98927->i_l_slot, 0);
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R001A_PCM_TX_EN_A,
+			1 << max98927->i_l_slot,
+			1 << max98927->i_l_slot);
+	} else {
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+			1 << (max98927->i_l_slot - 8), 0);
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R001B_PCM_TX_EN_B,
+			1 << (max98927->i_l_slot - 8),
+			1 << (max98927->i_l_slot - 8));
+	}
+
+	/* Set interleave mode */
+	if (max98927->interleave_mode)
+		regmap_update_bits(max98927->regmap,
+			MAX98927_R001F_PCM_TX_CH_SRC_B,
+			MAX98927_PCM_TX_CH_INTERLEAVE_MASK,
+			MAX98927_PCM_TX_CH_INTERLEAVE_MASK);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max98927_suspend(struct device *dev)
+{
+	struct max98927_priv *max98927 = dev_get_drvdata(dev);
+
+	regcache_cache_only(max98927->regmap, true);
+	regcache_mark_dirty(max98927->regmap);
+	return 0;
+}
+static int max98927_resume(struct device *dev)
+{
+	struct max98927_priv *max98927 = dev_get_drvdata(dev);
+
+	regmap_write(max98927->regmap,
+		MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
+	regcache_cache_only(max98927->regmap, false);
+	regcache_sync(max98927->regmap);
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops max98927_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(max98927_suspend, max98927_resume)
+};
+
+static const struct snd_soc_component_driver soc_component_dev_max98927 = {
+	.probe			= max98927_probe,
+	.controls		= max98927_snd_controls,
+	.num_controls		= ARRAY_SIZE(max98927_snd_controls),
+	.dapm_widgets		= max98927_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(max98927_dapm_widgets),
+	.dapm_routes		= max98927_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(max98927_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config max98927_regmap = {
+	.reg_bits         = 16,
+	.val_bits         = 8,
+	.max_register     = MAX98927_R01FF_REV_ID,
+	.reg_defaults     = max98927_reg,
+	.num_reg_defaults = ARRAY_SIZE(max98927_reg),
+	.readable_reg	  = max98927_readable_register,
+	.volatile_reg	  = max98927_volatile_reg,
+	.cache_type       = REGCACHE_RBTREE,
+};
+
+static void max98927_slot_config(struct i2c_client *i2c,
+	struct max98927_priv *max98927)
+{
+	int value;
+	struct device *dev = &i2c->dev;
+
+	if (!device_property_read_u32(dev, "vmon-slot-no", &value))
+		max98927->v_l_slot = value & 0xF;
+	else
+		max98927->v_l_slot = 0;
+
+	if (!device_property_read_u32(dev, "imon-slot-no", &value))
+		max98927->i_l_slot = value & 0xF;
+	else
+		max98927->i_l_slot = 1;
+}
+
+static int max98927_i2c_probe(struct i2c_client *i2c,
+	const struct i2c_device_id *id)
+{
+
+	int ret = 0, value;
+	int reg = 0;
+	struct max98927_priv *max98927 = NULL;
+
+	max98927 = devm_kzalloc(&i2c->dev,
+		sizeof(*max98927), GFP_KERNEL);
+
+	if (!max98927) {
+		ret = -ENOMEM;
+		return ret;
+	}
+	i2c_set_clientdata(i2c, max98927);
+
+	/* update interleave mode info */
+	if (!of_property_read_u32(i2c->dev.of_node,
+		"interleave_mode", &value)) {
+		if (value > 0)
+			max98927->interleave_mode = 1;
+		else
+			max98927->interleave_mode = 0;
+	} else
+		max98927->interleave_mode = 0;
+
+	/* regmap initialization */
+	max98927->regmap
+		= devm_regmap_init_i2c(i2c, &max98927_regmap);
+	if (IS_ERR(max98927->regmap)) {
+		ret = PTR_ERR(max98927->regmap);
+		dev_err(&i2c->dev,
+			"Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	/* Check Revision ID */
+	ret = regmap_read(max98927->regmap,
+		MAX98927_R01FF_REV_ID, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev,
+			"Failed to read: 0x%02X\n", MAX98927_R01FF_REV_ID);
+		return ret;
+	}
+	dev_info(&i2c->dev, "MAX98927 revisionID: 0x%02X\n", reg);
+
+	/* voltage/current slot configuration */
+	max98927_slot_config(i2c, max98927);
+
+	/* codec registeration */
+	ret = devm_snd_soc_register_component(&i2c->dev,
+		&soc_component_dev_max98927,
+		max98927_dai, ARRAY_SIZE(max98927_dai));
+	if (ret < 0)
+		dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
+
+	return ret;
+}
+
+static const struct i2c_device_id max98927_i2c_id[] = {
+	{ "max98927", 0},
+	{ },
+};
+
+MODULE_DEVICE_TABLE(i2c, max98927_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id max98927_of_match[] = {
+	{ .compatible = "maxim,max98927", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max98927_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id max98927_acpi_match[] = {
+	{ "MX98927", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, max98927_acpi_match);
+#endif
+
+static struct i2c_driver max98927_i2c_driver = {
+	.driver = {
+		.name = "max98927",
+		.of_match_table = of_match_ptr(max98927_of_match),
+		.acpi_match_table = ACPI_PTR(max98927_acpi_match),
+		.pm = &max98927_pm,
+	},
+	.probe  = max98927_i2c_probe,
+	.id_table = max98927_i2c_id,
+};
+
+module_i2c_driver(max98927_i2c_driver)
+
+MODULE_DESCRIPTION("ALSA SoC MAX98927 driver");
+MODULE_AUTHOR("Ryan Lee <ryans.lee@maximintegrated.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98927.h b/sound/soc/codecs/max98927.h
new file mode 100644
index 0000000..42a9a24
--- /dev/null
+++ b/sound/soc/codecs/max98927.h
@@ -0,0 +1,275 @@
+/*
+ * max98927.h  --  MAX98927 ALSA Soc Audio driver
+ *
+ * Copyright (C) 2016-2017 Maxim Integrated Products
+ * Author: Ryan Lee <ryans.lee@maximintegrated.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+#ifndef _MAX98927_H
+#define _MAX98927_H
+
+/* Register Values */
+#define MAX98927_R0001_INT_RAW1 0x0001
+#define MAX98927_R0002_INT_RAW2 0x0002
+#define MAX98927_R0003_INT_RAW3 0x0003
+#define MAX98927_R0004_INT_STATE1 0x0004
+#define MAX98927_R0005_INT_STATE2 0x0005
+#define MAX98927_R0006_INT_STATE3 0x0006
+#define MAX98927_R0007_INT_FLAG1 0x0007
+#define MAX98927_R0008_INT_FLAG2 0x0008
+#define MAX98927_R0009_INT_FLAG3 0x0009
+#define MAX98927_R000A_INT_EN1 0x000A
+#define MAX98927_R000B_INT_EN2 0x000B
+#define MAX98927_R000C_INT_EN3 0x000C
+#define MAX98927_R000D_INT_FLAG_CLR1	0x000D
+#define MAX98927_R000E_INT_FLAG_CLR2	0x000E
+#define MAX98927_R000F_INT_FLAG_CLR3	0x000F
+#define MAX98927_R0010_IRQ_CTRL 0x0010
+#define MAX98927_R0011_CLK_MON 0x0011
+#define MAX98927_R0012_WDOG_CTRL 0x0012
+#define MAX98927_R0013_WDOG_RST 0x0013
+#define MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH 0x0014
+#define MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH 0x0015
+#define MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS 0x0016
+#define MAX98927_R0017_PIN_CFG 0x0017
+#define MAX98927_R0018_PCM_RX_EN_A 0x0018
+#define MAX98927_R0019_PCM_RX_EN_B 0x0019
+#define MAX98927_R001A_PCM_TX_EN_A 0x001A
+#define MAX98927_R001B_PCM_TX_EN_B 0x001B
+#define MAX98927_R001C_PCM_TX_HIZ_CTRL_A 0x001C
+#define MAX98927_R001D_PCM_TX_HIZ_CTRL_B 0x001D
+#define MAX98927_R001E_PCM_TX_CH_SRC_A 0x001E
+#define MAX98927_R001F_PCM_TX_CH_SRC_B 0x001F
+#define MAX98927_R0020_PCM_MODE_CFG 0x0020
+#define MAX98927_R0021_PCM_MASTER_MODE 0x0021
+#define MAX98927_R0022_PCM_CLK_SETUP 0x0022
+#define MAX98927_R0023_PCM_SR_SETUP1 0x0023
+#define MAX98927_R0024_PCM_SR_SETUP2	0x0024
+#define MAX98927_R0025_PCM_TO_SPK_MONOMIX_A 0x0025
+#define MAX98927_R0026_PCM_TO_SPK_MONOMIX_B 0x0026
+#define MAX98927_R0027_ICC_RX_EN_A 0x0027
+#define MAX98927_R0028_ICC_RX_EN_B 0x0028
+#define MAX98927_R002B_ICC_TX_EN_A 0x002B
+#define MAX98927_R002C_ICC_TX_EN_B 0x002C
+#define MAX98927_R002E_ICC_HIZ_MANUAL_MODE 0x002E
+#define MAX98927_R002F_ICC_TX_HIZ_EN_A 0x002F
+#define MAX98927_R0030_ICC_TX_HIZ_EN_B 0x0030
+#define MAX98927_R0031_ICC_LNK_EN 0x0031
+#define MAX98927_R0032_PDM_TX_EN 0x0032
+#define MAX98927_R0033_PDM_TX_HIZ_CTRL 0x0033
+#define MAX98927_R0034_PDM_TX_CTRL 0x0034
+#define MAX98927_R0035_PDM_RX_CTRL 0x0035
+#define MAX98927_R0036_AMP_VOL_CTRL 0x0036
+#define MAX98927_R0037_AMP_DSP_CFG 0x0037
+#define MAX98927_R0038_TONE_GEN_DC_CFG 0x0038
+#define MAX98927_R0039_DRE_CTRL 0x0039
+#define MAX98927_R003A_AMP_EN 0x003A
+#define MAX98927_R003B_SPK_SRC_SEL 0x003B
+#define MAX98927_R003C_SPK_GAIN 0x003C
+#define MAX98927_R003D_SSM_CFG 0x003D
+#define MAX98927_R003E_MEAS_EN 0x003E
+#define MAX98927_R003F_MEAS_DSP_CFG 0x003F
+#define MAX98927_R0040_BOOST_CTRL0 0x0040
+#define MAX98927_R0041_BOOST_CTRL3 0x0041
+#define MAX98927_R0042_BOOST_CTRL1 0x0042
+#define MAX98927_R0043_MEAS_ADC_CFG 0x0043
+#define MAX98927_R0044_MEAS_ADC_BASE_MSB 0x0044
+#define MAX98927_R0045_MEAS_ADC_BASE_LSB 0x0045
+#define MAX98927_R0046_ADC_CH0_DIVIDE 0x0046
+#define MAX98927_R0047_ADC_CH1_DIVIDE 0x0047
+#define MAX98927_R0048_ADC_CH2_DIVIDE 0x0048
+#define MAX98927_R0049_ADC_CH0_FILT_CFG 0x0049
+#define MAX98927_R004A_ADC_CH1_FILT_CFG 0x004A
+#define MAX98927_R004B_ADC_CH2_FILT_CFG 0x004B
+#define MAX98927_R004C_MEAS_ADC_CH0_READ 0x004C
+#define MAX98927_R004D_MEAS_ADC_CH1_READ 0x004D
+#define MAX98927_R004E_MEAS_ADC_CH2_READ 0x004E
+#define MAX98927_R0051_BROWNOUT_STATUS 0x0051
+#define MAX98927_R0052_BROWNOUT_EN 0x0052
+#define MAX98927_R0053_BROWNOUT_INFINITE_HOLD 0x0053
+#define MAX98927_R0054_BROWNOUT_INFINITE_HOLD_CLR 0x0054
+#define MAX98927_R0055_BROWNOUT_LVL_HOLD 0x0055
+#define MAX98927_R005A_BROWNOUT_LVL1_THRESH 0x005A
+#define MAX98927_R005B_BROWNOUT_LVL2_THRESH 0x005B
+#define MAX98927_R005C_BROWNOUT_LVL3_THRESH 0x005C
+#define MAX98927_R005D_BROWNOUT_LVL4_THRESH 0x005D
+#define MAX98927_R005E_BROWNOUT_THRESH_HYSTERYSIS 0x005E
+#define MAX98927_R005F_BROWNOUT_AMP_LIMITER_ATK_REL 0x005F
+#define MAX98927_R0060_BROWNOUT_AMP_GAIN_ATK_REL 0x0060
+#define MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE 0x0061
+#define MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT 0x0072
+#define MAX98927_R0073_BROWNOUT_LVL1_AMP1_CTRL1 0x0073
+#define MAX98927_R0074_BROWNOUT_LVL1_AMP1_CTRL2 0x0074
+#define MAX98927_R0075_BROWNOUT_LVL1_AMP1_CTRL3 0x0075
+#define MAX98927_R0076_BROWNOUT_LVL2_CUR_LIMIT 0x0076
+#define MAX98927_R0077_BROWNOUT_LVL2_AMP1_CTRL1 0x0077
+#define MAX98927_R0078_BROWNOUT_LVL2_AMP1_CTRL2 0x0078
+#define MAX98927_R0079_BROWNOUT_LVL2_AMP1_CTRL3 0x0079
+#define MAX98927_R007A_BROWNOUT_LVL3_CUR_LIMIT 0x007A
+#define MAX98927_R007B_BROWNOUT_LVL3_AMP1_CTRL1 0x007B
+#define MAX98927_R007C_BROWNOUT_LVL3_AMP1_CTRL2 0x007C
+#define MAX98927_R007D_BROWNOUT_LVL3_AMP1_CTRL3 0x007D
+#define MAX98927_R007E_BROWNOUT_LVL4_CUR_LIMIT 0x007E
+#define MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1 0x007F
+#define MAX98927_R0080_BROWNOUT_LVL4_AMP1_CTRL2 0x0080
+#define MAX98927_R0081_BROWNOUT_LVL4_AMP1_CTRL3 0x0081
+#define MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM 0x0082
+#define MAX98927_R0083_ENV_TRACK_BOOST_VOUT_DELAY 0x0083
+#define MAX98927_R0084_ENV_TRACK_REL_RATE 0x0084
+#define MAX98927_R0085_ENV_TRACK_HOLD_RATE 0x0085
+#define MAX98927_R0086_ENV_TRACK_CTRL 0x0086
+#define MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ 0x0087
+#define MAX98927_R00FF_GLOBAL_SHDN 0x00FF
+#define MAX98927_R0100_SOFT_RESET 0x0100
+#define MAX98927_R01FF_REV_ID 0x01FF
+
+/* MAX98927_R0018_PCM_RX_EN_A */
+#define MAX98927_PCM_RX_CH0_EN (0x1 << 0)
+#define MAX98927_PCM_RX_CH1_EN (0x1 << 1)
+#define MAX98927_PCM_RX_CH2_EN (0x1 << 2)
+#define MAX98927_PCM_RX_CH3_EN (0x1 << 3)
+#define MAX98927_PCM_RX_CH4_EN (0x1 << 4)
+#define MAX98927_PCM_RX_CH5_EN (0x1 << 5)
+#define MAX98927_PCM_RX_CH6_EN (0x1 << 6)
+#define MAX98927_PCM_RX_CH7_EN (0x1 << 7)
+
+/* MAX98927_R001A_PCM_TX_EN_A */
+#define MAX98927_PCM_TX_CH0_EN (0x1 << 0)
+#define MAX98927_PCM_TX_CH1_EN (0x1 << 1)
+#define MAX98927_PCM_TX_CH2_EN (0x1 << 2)
+#define MAX98927_PCM_TX_CH3_EN (0x1 << 3)
+#define MAX98927_PCM_TX_CH4_EN (0x1 << 4)
+#define MAX98927_PCM_TX_CH5_EN (0x1 << 5)
+#define MAX98927_PCM_TX_CH6_EN (0x1 << 6)
+#define MAX98927_PCM_TX_CH7_EN (0x1 << 7)
+
+/* MAX98927_R001E_PCM_TX_CH_SRC_A */
+#define MAX98927_PCM_TX_CH_SRC_A_V_SHIFT (0)
+#define MAX98927_PCM_TX_CH_SRC_A_I_SHIFT (4)
+
+/* MAX98927_R001F_PCM_TX_CH_SRC_B */
+#define MAX98927_PCM_TX_CH_INTERLEAVE_MASK (0x1 << 5)
+
+/* MAX98927_R0020_PCM_MODE_CFG */
+#define MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE (0x1 << 2)
+#define MAX98927_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3)
+#define MAX98927_PCM_MODE_CFG_FORMAT_SHIFT (3)
+#define MAX98927_PCM_FORMAT_I2S (0x0 << 0)
+#define MAX98927_PCM_FORMAT_LJ (0x1 << 0)
+#define MAX98927_PCM_FORMAT_TDM_MODE0 (0x3 << 0)
+#define MAX98927_PCM_FORMAT_TDM_MODE1 (0x4 << 0)
+#define MAX98927_PCM_FORMAT_TDM_MODE2 (0x5 << 0)
+#define MAX98927_PCM_MODE_CFG_CHANSZ_MASK (0x3 << 6)
+#define MAX98927_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6)
+#define MAX98927_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6)
+#define MAX98927_PCM_MODE_CFG_CHANSZ_32 (0x3 << 6)
+
+/* MAX98927_R0021_PCM_MASTER_MODE */
+#define MAX98927_PCM_MASTER_MODE_MASK (0x3 << 0)
+#define MAX98927_PCM_MASTER_MODE_SLAVE (0x0 << 0)
+#define MAX98927_PCM_MASTER_MODE_MASTER (0x3 << 0)
+
+#define MAX98927_PCM_MASTER_MODE_MCLK_MASK (0xF << 2)
+#define MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT (2)
+
+/* MAX98927_R0022_PCM_CLK_SETUP */
+#define MAX98927_PCM_CLK_SETUP_BSEL_MASK (0xF << 0)
+
+/* MAX98927_R0023_PCM_SR_SETUP1 */
+#define MAX98927_PCM_SR_SET1_SR_MASK (0xF << 0)
+
+#define MAX98927_PCM_SR_SET1_SR_8000 (0x0 << 0)
+#define MAX98927_PCM_SR_SET1_SR_11025 (0x1 << 0)
+#define MAX98927_PCM_SR_SET1_SR_12000 (0x2 << 0)
+#define MAX98927_PCM_SR_SET1_SR_16000 (0x3 << 0)
+#define MAX98927_PCM_SR_SET1_SR_22050 (0x4 << 0)
+#define MAX98927_PCM_SR_SET1_SR_24000 (0x5 << 0)
+#define MAX98927_PCM_SR_SET1_SR_32000 (0x6 << 0)
+#define MAX98927_PCM_SR_SET1_SR_44100 (0x7 << 0)
+#define MAX98927_PCM_SR_SET1_SR_48000 (0x8 << 0)
+
+/* MAX98927_R0024_PCM_SR_SETUP2 */
+#define MAX98927_PCM_SR_SET2_SR_MASK (0xF << 4)
+#define MAX98927_PCM_SR_SET2_SR_SHIFT (4)
+#define MAX98927_PCM_SR_SET2_IVADC_SR_MASK (0xf << 0)
+
+/* MAX98927_R0025_PCM_TO_SPK_MONOMIX_A */
+#define MAX98927_PCM_TO_SPK_MONOMIX_CFG_MASK (0x3 << 6)
+#define MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT (6)
+
+/* MAX98927_R0035_PDM_RX_CTRL */
+#define MAX98927_PDM_RX_EN_MASK (0x1 << 0)
+
+/* MAX98927_R0036_AMP_VOL_CTRL */
+#define MAX98927_AMP_VOL_SEL (0x1 << 7)
+#define MAX98927_AMP_VOL_SEL_WIDTH (1)
+#define MAX98927_AMP_VOL_SEL_SHIFT (7)
+#define MAX98927_AMP_VOL_MASK (0x7f << 0)
+#define MAX98927_AMP_VOL_WIDTH (7)
+#define MAX98927_AMP_VOL_SHIFT (0)
+
+/* MAX98927_R0037_AMP_DSP_CFG */
+#define MAX98927_AMP_DSP_CFG_DCBLK_EN (0x1 << 0)
+#define MAX98927_AMP_DSP_CFG_DITH_EN (0x1 << 1)
+#define MAX98927_AMP_DSP_CFG_RMP_BYPASS (0x1 << 4)
+#define MAX98927_AMP_DSP_CFG_DAC_INV (0x1 << 5)
+#define MAX98927_AMP_DSP_CFG_RMP_SHIFT (4)
+
+/* MAX98927_R0039_DRE_CTRL */
+#define MAX98927_DRE_CTRL_DRE_EN	(0x1 << 0)
+#define MAX98927_DRE_EN_SHIFT 0x1
+
+/* MAX98927_R003A_AMP_EN */
+#define MAX98927_AMP_EN_MASK (0x1 << 0)
+
+/* MAX98927_R003B_SPK_SRC_SEL */
+#define MAX98927_SPK_SRC_MASK (0x3 << 0)
+
+/* MAX98927_R003C_SPK_GAIN */
+#define MAX98927_SPK_PCM_GAIN_MASK (0x7 << 0)
+#define MAX98927_SPK_PDM_GAIN_MASK (0x7 << 4)
+#define MAX98927_SPK_GAIN_WIDTH (3)
+
+/* MAX98927_R003E_MEAS_EN */
+#define MAX98927_MEAS_V_EN (0x1 << 0)
+#define MAX98927_MEAS_I_EN (0x1 << 1)
+
+/* MAX98927_R0040_BOOST_CTRL0 */
+#define MAX98927_BOOST_CTRL0_VOUT_MASK (0x1f << 0)
+#define MAX98927_BOOST_CTRL0_PVDD_MASK (0x1 << 7)
+#define MAX98927_BOOST_CTRL0_PVDD_EN_SHIFT (7)
+
+/* MAX98927_R0052_BROWNOUT_EN */
+#define MAX98927_BROWNOUT_BDE_EN (0x1 << 0)
+#define MAX98927_BROWNOUT_AMP_EN (0x1 << 1)
+#define MAX98927_BROWNOUT_DSP_EN (0x1 << 2)
+#define MAX98927_BROWNOUT_DSP_SHIFT (2)
+
+/* MAX98927_R0100_SOFT_RESET */
+#define MAX98927_SOFT_RESET (0x1 << 0)
+
+/* MAX98927_R00FF_GLOBAL_SHDN */
+#define MAX98927_GLOBAL_EN_MASK (0x1 << 0)
+
+struct max98927_priv {
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct max98927_pdata *pdata;
+	unsigned int spk_gain;
+	unsigned int sysclk;
+	unsigned int v_l_slot;
+	unsigned int i_l_slot;
+	bool interleave_mode;
+	unsigned int ch_size;
+	unsigned int rate;
+	unsigned int iface;
+	unsigned int master;
+	unsigned int digital_gain;
+	bool tdm_mode;
+};
+#endif
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
new file mode 100644
index 0000000..7b0d261
--- /dev/null
+++ b/sound/soc/codecs/mc13783.c
@@ -0,0 +1,810 @@
+/*
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ * Copyright 2009 Sascha Hauer, s.hauer@pengutronix.de
+ * Copyright 2012 Philippe Retornaz, philippe.retornaz@epfl.ch
+ *
+ * Initial development of this code was funded by
+ * Phytec Messtechnik GmbH, http://www.phytec.de
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/mfd/mc13xxx.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/soc-dapm.h>
+#include <linux/regmap.h>
+
+#include "mc13783.h"
+
+#define AUDIO_RX0_ALSPEN		(1 << 5)
+#define AUDIO_RX0_ALSPSEL		(1 << 7)
+#define AUDIO_RX0_ADDCDC		(1 << 21)
+#define AUDIO_RX0_ADDSTDC		(1 << 22)
+#define AUDIO_RX0_ADDRXIN		(1 << 23)
+
+#define AUDIO_RX1_PGARXEN		(1 << 0);
+#define AUDIO_RX1_PGASTEN		(1 << 5)
+#define AUDIO_RX1_ARXINEN		(1 << 10)
+
+#define AUDIO_TX_AMC1REN		(1 << 5)
+#define AUDIO_TX_AMC1LEN		(1 << 7)
+#define AUDIO_TX_AMC2EN			(1 << 9)
+#define AUDIO_TX_ATXINEN		(1 << 11)
+#define AUDIO_TX_RXINREC		(1 << 13)
+
+#define SSI_NETWORK_CDCTXRXSLOT(x)	(((x) & 0x3) << 2)
+#define SSI_NETWORK_CDCTXSECSLOT(x)	(((x) & 0x3) << 4)
+#define SSI_NETWORK_CDCRXSECSLOT(x)	(((x) & 0x3) << 6)
+#define SSI_NETWORK_CDCRXSECGAIN(x)	(((x) & 0x3) << 8)
+#define SSI_NETWORK_CDCSUMGAIN(x)	(1 << 10)
+#define SSI_NETWORK_CDCFSDLY(x)		(1 << 11)
+#define SSI_NETWORK_DAC_SLOTS_8		(1 << 12)
+#define SSI_NETWORK_DAC_SLOTS_4		(2 << 12)
+#define SSI_NETWORK_DAC_SLOTS_2		(3 << 12)
+#define SSI_NETWORK_DAC_SLOT_MASK	(3 << 12)
+#define SSI_NETWORK_DAC_RXSLOT_0_1	(0 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_2_3	(1 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_4_5	(2 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_6_7	(3 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_MASK	(3 << 14)
+#define SSI_NETWORK_STDCRXSECSLOT(x)	(((x) & 0x3) << 16)
+#define SSI_NETWORK_STDCRXSECGAIN(x)	(((x) & 0x3) << 18)
+#define SSI_NETWORK_STDCSUMGAIN		(1 << 20)
+
+/*
+ * MC13783_AUDIO_CODEC and MC13783_AUDIO_DAC mostly share the same
+ * register layout
+ */
+#define AUDIO_SSI_SEL			(1 << 0)
+#define AUDIO_CLK_SEL			(1 << 1)
+#define AUDIO_CSM			(1 << 2)
+#define AUDIO_BCL_INV			(1 << 3)
+#define AUDIO_CFS_INV			(1 << 4)
+#define AUDIO_CFS(x)			(((x) & 0x3) << 5)
+#define AUDIO_CLK(x)			(((x) & 0x7) << 7)
+#define AUDIO_C_EN			(1 << 11)
+#define AUDIO_C_CLK_EN			(1 << 12)
+#define AUDIO_C_RESET			(1 << 15)
+
+#define AUDIO_CODEC_CDCFS8K16K		(1 << 10)
+#define AUDIO_DAC_CFS_DLY_B		(1 << 10)
+
+struct mc13783_priv {
+	struct mc13xxx *mc13xxx;
+	struct regmap *regmap;
+
+	enum mc13783_ssi_port adc_ssi_port;
+	enum mc13783_ssi_port dac_ssi_port;
+};
+
+/* Mapping between sample rates and register value */
+static unsigned int mc13783_rates[] = {
+	8000, 11025, 12000, 16000,
+	22050, 24000, 32000, 44100,
+	48000, 64000, 96000
+};
+
+static int mc13783_pcm_hw_params_dac(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int rate = params_rate(params);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mc13783_rates); i++) {
+		if (rate == mc13783_rates[i]) {
+			snd_soc_component_update_bits(component, MC13783_AUDIO_DAC,
+					0xf << 17, i << 17);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int mc13783_pcm_hw_params_codec(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int rate = params_rate(params);
+	unsigned int val;
+
+	switch (rate) {
+	case 8000:
+		val = 0;
+		break;
+	case 16000:
+		val = AUDIO_CODEC_CDCFS8K16K;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, MC13783_AUDIO_CODEC, AUDIO_CODEC_CDCFS8K16K,
+			val);
+
+	return 0;
+}
+
+static int mc13783_pcm_hw_params_sync(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return mc13783_pcm_hw_params_dac(substream, params, dai);
+	else
+		return mc13783_pcm_hw_params_codec(substream, params, dai);
+}
+
+static int mc13783_set_fmt(struct snd_soc_dai *dai, unsigned int fmt,
+			unsigned int reg)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int val = 0;
+	unsigned int mask = AUDIO_CFS(3) | AUDIO_BCL_INV | AUDIO_CFS_INV |
+				AUDIO_CSM | AUDIO_C_CLK_EN | AUDIO_C_RESET;
+
+
+	/* DAI mode */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		val |= AUDIO_CFS(2);
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		val |= AUDIO_CFS(1);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* DAI clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		val |= AUDIO_BCL_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		val |= AUDIO_BCL_INV | AUDIO_CFS_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		val |= AUDIO_CFS_INV;
+		break;
+	}
+
+	/* DAI clock master masks */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		val |= AUDIO_C_CLK_EN;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		val |= AUDIO_CSM;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+	case SND_SOC_DAIFMT_CBS_CFM:
+		return -EINVAL;
+	}
+
+	val |= AUDIO_C_RESET;
+
+	snd_soc_component_update_bits(component, reg, mask, val);
+
+	return 0;
+}
+
+static int mc13783_set_fmt_async(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	if (dai->id == MC13783_ID_STEREO_DAC)
+		return mc13783_set_fmt(dai, fmt, MC13783_AUDIO_DAC);
+	else
+		return mc13783_set_fmt(dai, fmt, MC13783_AUDIO_CODEC);
+}
+
+static int mc13783_set_fmt_sync(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	int ret;
+
+	ret = mc13783_set_fmt(dai, fmt, MC13783_AUDIO_DAC);
+	if (ret)
+		return ret;
+
+	/*
+	 * In synchronous mode force the voice codec into slave mode
+	 * so that the clock / framesync from the stereo DAC is used
+	 */
+	fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+	fmt |= SND_SOC_DAIFMT_CBS_CFS;
+	ret = mc13783_set_fmt(dai, fmt, MC13783_AUDIO_CODEC);
+
+	return ret;
+}
+
+static int mc13783_sysclk[] = {
+	13000000,
+	15360000,
+	16800000,
+	-1,
+	26000000,
+	-1, /* 12000000, invalid for voice codec */
+	-1, /* 3686400, invalid for voice codec */
+	33600000,
+};
+
+static int mc13783_set_sysclk(struct snd_soc_dai *dai,
+				  int clk_id, unsigned int freq, int dir,
+				  unsigned int reg)
+{
+	struct snd_soc_component *component = dai->component;
+	int clk;
+	unsigned int val = 0;
+	unsigned int mask = AUDIO_CLK(0x7) | AUDIO_CLK_SEL;
+
+	for (clk = 0; clk < ARRAY_SIZE(mc13783_sysclk); clk++) {
+		if (mc13783_sysclk[clk] < 0)
+			continue;
+		if (mc13783_sysclk[clk] == freq)
+			break;
+	}
+
+	if (clk == ARRAY_SIZE(mc13783_sysclk))
+		return -EINVAL;
+
+	if (clk_id == MC13783_CLK_CLIB)
+		val |= AUDIO_CLK_SEL;
+
+	val |= AUDIO_CLK(clk);
+
+	snd_soc_component_update_bits(component, reg, mask, val);
+
+	return 0;
+}
+
+static int mc13783_set_sysclk_dac(struct snd_soc_dai *dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_DAC);
+}
+
+static int mc13783_set_sysclk_codec(struct snd_soc_dai *dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_CODEC);
+}
+
+static int mc13783_set_sysclk_sync(struct snd_soc_dai *dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	int ret;
+
+	ret = mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_DAC);
+	if (ret)
+		return ret;
+
+	return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_CODEC);
+}
+
+static int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai,
+	unsigned int tx_mask, unsigned int rx_mask, int slots,
+	int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int val = 0;
+	unsigned int mask = SSI_NETWORK_DAC_SLOT_MASK |
+				SSI_NETWORK_DAC_RXSLOT_MASK;
+
+	switch (slots) {
+	case 2:
+		val |= SSI_NETWORK_DAC_SLOTS_2;
+		break;
+	case 4:
+		val |= SSI_NETWORK_DAC_SLOTS_4;
+		break;
+	case 8:
+		val |= SSI_NETWORK_DAC_SLOTS_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (rx_mask) {
+	case 0x03:
+		val |= SSI_NETWORK_DAC_RXSLOT_0_1;
+		break;
+	case 0x0c:
+		val |= SSI_NETWORK_DAC_RXSLOT_2_3;
+		break;
+	case 0x30:
+		val |= SSI_NETWORK_DAC_RXSLOT_4_5;
+		break;
+	case 0xc0:
+		val |= SSI_NETWORK_DAC_RXSLOT_6_7;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, MC13783_SSI_NETWORK, mask, val);
+
+	return 0;
+}
+
+static int mc13783_set_tdm_slot_codec(struct snd_soc_dai *dai,
+	unsigned int tx_mask, unsigned int rx_mask, int slots,
+	int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int val = 0;
+	unsigned int mask = 0x3f;
+
+	if (slots != 4)
+		return -EINVAL;
+
+	if (tx_mask != 0x3)
+		return -EINVAL;
+
+	val |= (0x00 << 2);	/* primary timeslot RX/TX(?) is 0 */
+	val |= (0x01 << 4);	/* secondary timeslot TX is 1 */
+
+	snd_soc_component_update_bits(component, MC13783_SSI_NETWORK, mask, val);
+
+	return 0;
+}
+
+static int mc13783_set_tdm_slot_sync(struct snd_soc_dai *dai,
+	unsigned int tx_mask, unsigned int rx_mask, int slots,
+	int slot_width)
+{
+	int ret;
+
+	ret = mc13783_set_tdm_slot_dac(dai, tx_mask, rx_mask, slots,
+			slot_width);
+	if (ret)
+		return ret;
+
+	ret = mc13783_set_tdm_slot_codec(dai, tx_mask, rx_mask, slots,
+			slot_width);
+
+	return ret;
+}
+
+static const struct snd_kcontrol_new mc1l_amp_ctl =
+	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 7, 1, 0);
+
+static const struct snd_kcontrol_new mc1r_amp_ctl =
+	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 5, 1, 0);
+
+static const struct snd_kcontrol_new mc2_amp_ctl =
+	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 9, 1, 0);
+
+static const struct snd_kcontrol_new atx_amp_ctl =
+	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 11, 1, 0);
+
+
+/* Virtual mux. The chip does the input selection automatically
+ * as soon as we enable one input. */
+static const char * const adcl_enum_text[] = {
+	"MC1L", "RXINL",
+};
+
+static SOC_ENUM_SINGLE_VIRT_DECL(adcl_enum, adcl_enum_text);
+
+static const struct snd_kcontrol_new left_input_mux =
+	SOC_DAPM_ENUM("Route", adcl_enum);
+
+static const char * const adcr_enum_text[] = {
+	"MC1R", "MC2", "RXINR", "TXIN",
+};
+
+static SOC_ENUM_SINGLE_VIRT_DECL(adcr_enum, adcr_enum_text);
+
+static const struct snd_kcontrol_new right_input_mux =
+	SOC_DAPM_ENUM("Route", adcr_enum);
+
+static const struct snd_kcontrol_new samp_ctl =
+	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0);
+
+static const char * const speaker_amp_source_text[] = {
+	"CODEC", "Right"
+};
+static SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4,
+			    speaker_amp_source_text);
+static const struct snd_kcontrol_new speaker_amp_source_mux =
+	SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source);
+
+static const char * const headset_amp_source_text[] = {
+	"CODEC", "Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11,
+			    headset_amp_source_text);
+static const struct snd_kcontrol_new headset_amp_source_mux =
+	SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source);
+
+static const struct snd_kcontrol_new cdcout_ctl =
+	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 18, 1, 0);
+
+static const struct snd_kcontrol_new adc_bypass_ctl =
+	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_CODEC, 16, 1, 0);
+
+static const struct snd_kcontrol_new lamp_ctl =
+	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 5, 1, 0);
+
+static const struct snd_kcontrol_new hlamp_ctl =
+	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 10, 1, 0);
+
+static const struct snd_kcontrol_new hramp_ctl =
+	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 9, 1, 0);
+
+static const struct snd_kcontrol_new llamp_ctl =
+	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 16, 1, 0);
+
+static const struct snd_kcontrol_new lramp_ctl =
+	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 15, 1, 0);
+
+static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
+/* Input */
+	SND_SOC_DAPM_INPUT("MC1LIN"),
+	SND_SOC_DAPM_INPUT("MC1RIN"),
+	SND_SOC_DAPM_INPUT("MC2IN"),
+	SND_SOC_DAPM_INPUT("RXINR"),
+	SND_SOC_DAPM_INPUT("RXINL"),
+	SND_SOC_DAPM_INPUT("TXIN"),
+
+	SND_SOC_DAPM_SUPPLY("MC1 Bias", MC13783_AUDIO_TX, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MC2 Bias", MC13783_AUDIO_TX, 1, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH("MC1L Amp", MC13783_AUDIO_TX, 7, 0, &mc1l_amp_ctl),
+	SND_SOC_DAPM_SWITCH("MC1R Amp", MC13783_AUDIO_TX, 5, 0, &mc1r_amp_ctl),
+	SND_SOC_DAPM_SWITCH("MC2 Amp", MC13783_AUDIO_TX, 9, 0, &mc2_amp_ctl),
+	SND_SOC_DAPM_SWITCH("TXIN Amp", MC13783_AUDIO_TX, 11, 0, &atx_amp_ctl),
+
+	SND_SOC_DAPM_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0,
+			      &left_input_mux),
+	SND_SOC_DAPM_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0,
+			      &right_input_mux),
+
+	SND_SOC_DAPM_MUX("Speaker Amp Source MUX", SND_SOC_NOPM, 0, 0,
+			 &speaker_amp_source_mux),
+
+	SND_SOC_DAPM_MUX("Headset Amp Source MUX", SND_SOC_NOPM, 0, 0,
+			 &headset_amp_source_mux),
+
+	SND_SOC_DAPM_PGA("PGA Left Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PGA Right Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_ADC("ADC", "Capture", MC13783_AUDIO_CODEC, 11, 0),
+	SND_SOC_DAPM_SUPPLY("ADC_Reset", MC13783_AUDIO_CODEC, 15, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Voice CODEC PGA", MC13783_AUDIO_RX1, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SWITCH("Voice CODEC Bypass", MC13783_AUDIO_CODEC, 16, 0,
+			&adc_bypass_ctl),
+
+/* Output */
+	SND_SOC_DAPM_SUPPLY("DAC_E", MC13783_AUDIO_DAC, 11, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC_Reset", MC13783_AUDIO_DAC, 15, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("RXOUTL"),
+	SND_SOC_DAPM_OUTPUT("RXOUTR"),
+	SND_SOC_DAPM_OUTPUT("HSL"),
+	SND_SOC_DAPM_OUTPUT("HSR"),
+	SND_SOC_DAPM_OUTPUT("LSPL"),
+	SND_SOC_DAPM_OUTPUT("LSP"),
+	SND_SOC_DAPM_OUTPUT("SP"),
+	SND_SOC_DAPM_OUTPUT("CDCOUT"),
+
+	SND_SOC_DAPM_SWITCH("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 0,
+			&cdcout_ctl),
+	SND_SOC_DAPM_SWITCH("Speaker Amp Switch", MC13783_AUDIO_RX0, 3, 0,
+			&samp_ctl),
+	SND_SOC_DAPM_SWITCH("Loudspeaker Amp", SND_SOC_NOPM, 0, 0, &lamp_ctl),
+	SND_SOC_DAPM_SWITCH("Headset Amp Left", MC13783_AUDIO_RX0, 10, 0,
+			&hlamp_ctl),
+	SND_SOC_DAPM_SWITCH("Headset Amp Right", MC13783_AUDIO_RX0, 9, 0,
+			&hramp_ctl),
+	SND_SOC_DAPM_SWITCH("Line out Amp Left", MC13783_AUDIO_RX0, 16, 0,
+			&llamp_ctl),
+	SND_SOC_DAPM_SWITCH("Line out Amp Right", MC13783_AUDIO_RX0, 15, 0,
+			&lramp_ctl),
+	SND_SOC_DAPM_DAC("DAC", "Playback", MC13783_AUDIO_RX0, 22, 0),
+	SND_SOC_DAPM_PGA("DAC PGA", MC13783_AUDIO_RX1, 5, 0, NULL, 0),
+};
+
+static struct snd_soc_dapm_route mc13783_routes[] = {
+/* Input */
+	{ "MC1L Amp", NULL, "MC1LIN"},
+	{ "MC1R Amp", NULL, "MC1RIN" },
+	{ "MC2 Amp", NULL, "MC2IN" },
+	{ "TXIN Amp", NULL, "TXIN"},
+
+	{ "PGA Left Input Mux", "MC1L", "MC1L Amp" },
+	{ "PGA Left Input Mux", "RXINL", "RXINL"},
+	{ "PGA Right Input Mux", "MC1R", "MC1R Amp" },
+	{ "PGA Right Input Mux", "MC2",  "MC2 Amp"},
+	{ "PGA Right Input Mux", "TXIN", "TXIN Amp"},
+	{ "PGA Right Input Mux", "RXINR", "RXINR"},
+
+	{ "PGA Left Input", NULL, "PGA Left Input Mux"},
+	{ "PGA Right Input", NULL, "PGA Right Input Mux"},
+
+	{ "ADC", NULL, "PGA Left Input"},
+	{ "ADC", NULL, "PGA Right Input"},
+	{ "ADC", NULL, "ADC_Reset"},
+
+	{ "Voice CODEC PGA", "Voice CODEC Bypass", "ADC" },
+
+	{ "Speaker Amp Source MUX", "CODEC", "Voice CODEC PGA"},
+	{ "Speaker Amp Source MUX", "Right", "DAC PGA"},
+
+	{ "Headset Amp Source MUX", "CODEC", "Voice CODEC PGA"},
+	{ "Headset Amp Source MUX", "Mixer", "DAC PGA"},
+
+/* Output */
+	{ "HSL", NULL, "Headset Amp Left" },
+	{ "HSR", NULL, "Headset Amp Right"},
+	{ "RXOUTL", NULL, "Line out Amp Left"},
+	{ "RXOUTR", NULL, "Line out Amp Right"},
+	{ "SP", "Speaker Amp Switch", "Speaker Amp Source MUX"},
+	{ "LSP", "Loudspeaker Amp", "Speaker Amp Source MUX"},
+	{ "HSL", "Headset Amp Left", "Headset Amp Source MUX"},
+	{ "HSR", "Headset Amp Right", "Headset Amp Source MUX"},
+	{ "Line out Amp Left", NULL, "DAC PGA"},
+	{ "Line out Amp Right", NULL, "DAC PGA"},
+	{ "DAC PGA", NULL, "DAC"},
+	{ "DAC", NULL, "DAC_E"},
+	{ "CDCOUT", "CDCOUT Switch", "Voice CODEC PGA"},
+};
+
+static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix",
+						"Mono", "Mono Mix"};
+
+static SOC_ENUM_SINGLE_DECL(mc13783_enum_3d_mixer,
+			    MC13783_AUDIO_RX1, 16,
+			    mc13783_3d_mixer);
+
+static struct snd_kcontrol_new mc13783_control_list[] = {
+	SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0),
+	SOC_SINGLE("PCM Playback Volume", MC13783_AUDIO_RX1, 6, 15, 0),
+	SOC_SINGLE("PCM Playback Switch", MC13783_AUDIO_RX1, 5, 1, 0),
+	SOC_DOUBLE("PCM Capture Volume", MC13783_AUDIO_TX, 19, 14, 31, 0),
+	SOC_ENUM("3D Control", mc13783_enum_3d_mixer),
+
+	SOC_SINGLE("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 1, 0),
+	SOC_SINGLE("Earpiece Amp Switch", MC13783_AUDIO_RX0, 3, 1, 0),
+	SOC_DOUBLE("Headset Amp Switch", MC13783_AUDIO_RX0, 10, 9, 1, 0),
+	SOC_DOUBLE("Line out Amp Switch", MC13783_AUDIO_RX0, 16, 15, 1, 0),
+
+	SOC_SINGLE("PCM Capture Mixin Switch", MC13783_AUDIO_RX0, 22, 1, 0),
+	SOC_SINGLE("Line in Capture Mixin Switch", MC13783_AUDIO_RX0, 23, 1, 0),
+
+	SOC_SINGLE("CODEC Capture Volume", MC13783_AUDIO_RX1, 1, 15, 0),
+	SOC_SINGLE("CODEC Capture Mixin Switch", MC13783_AUDIO_RX0, 21, 1, 0),
+
+	SOC_SINGLE("Line in Capture Volume", MC13783_AUDIO_RX1, 12, 15, 0),
+	SOC_SINGLE("Line in Capture Switch", MC13783_AUDIO_RX1, 10, 1, 0),
+
+	SOC_SINGLE("MC1 Capture Bias Switch", MC13783_AUDIO_TX, 0, 1, 0),
+	SOC_SINGLE("MC2 Capture Bias Switch", MC13783_AUDIO_TX, 1, 1, 0),
+};
+
+static int mc13783_probe(struct snd_soc_component *component)
+{
+	struct mc13783_priv *priv = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_init_regmap(component,
+				  dev_get_regmap(component->dev->parent, NULL));
+
+	/* these are the reset values */
+	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893);
+	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX1, 0x00d35A);
+	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_TX, 0x420000);
+	mc13xxx_reg_write(priv->mc13xxx, MC13783_SSI_NETWORK, 0x013060);
+	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_CODEC, 0x180027);
+	mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_DAC, 0x0e0004);
+
+	if (priv->adc_ssi_port == MC13783_SSI1_PORT)
+		mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_CODEC,
+				AUDIO_SSI_SEL, 0);
+	else
+		mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_CODEC,
+				AUDIO_SSI_SEL, AUDIO_SSI_SEL);
+
+	if (priv->dac_ssi_port == MC13783_SSI1_PORT)
+		mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
+				AUDIO_SSI_SEL, 0);
+	else
+		mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
+				AUDIO_SSI_SEL, AUDIO_SSI_SEL);
+
+	return 0;
+}
+
+static void mc13783_remove(struct snd_soc_component *component)
+{
+	struct mc13783_priv *priv = snd_soc_component_get_drvdata(component);
+
+	/* Make sure VAUDIOON is off */
+	mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_RX0, 0x3, 0);
+}
+
+#define MC13783_RATES_RECORD (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
+
+#define MC13783_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops mc13783_ops_dac = {
+	.hw_params	= mc13783_pcm_hw_params_dac,
+	.set_fmt	= mc13783_set_fmt_async,
+	.set_sysclk	= mc13783_set_sysclk_dac,
+	.set_tdm_slot	= mc13783_set_tdm_slot_dac,
+};
+
+static const struct snd_soc_dai_ops mc13783_ops_codec = {
+	.hw_params	= mc13783_pcm_hw_params_codec,
+	.set_fmt	= mc13783_set_fmt_async,
+	.set_sysclk	= mc13783_set_sysclk_codec,
+	.set_tdm_slot	= mc13783_set_tdm_slot_codec,
+};
+
+/*
+ * The mc13783 has two SSI ports, both of them can be routed either
+ * to the voice codec or the stereo DAC. When two different SSI ports
+ * are used for the voice codec and the stereo DAC we can do different
+ * formats and sysclock settings for playback and capture
+ * (mc13783-hifi-playback and mc13783-hifi-capture). Using the same port
+ * forces us to use symmetric rates (mc13783-hifi).
+ */
+static struct snd_soc_dai_driver mc13783_dai_async[] = {
+	{
+		.name = "mc13783-hifi-playback",
+		.id = MC13783_ID_STEREO_DAC,
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_96000,
+			.formats = MC13783_FORMATS,
+		},
+		.ops = &mc13783_ops_dac,
+	}, {
+		.name = "mc13783-hifi-capture",
+		.id = MC13783_ID_STEREO_CODEC,
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = MC13783_RATES_RECORD,
+			.formats = MC13783_FORMATS,
+		},
+		.ops = &mc13783_ops_codec,
+	},
+};
+
+static const struct snd_soc_dai_ops mc13783_ops_sync = {
+	.hw_params	= mc13783_pcm_hw_params_sync,
+	.set_fmt	= mc13783_set_fmt_sync,
+	.set_sysclk	= mc13783_set_sysclk_sync,
+	.set_tdm_slot	= mc13783_set_tdm_slot_sync,
+};
+
+static struct snd_soc_dai_driver mc13783_dai_sync[] = {
+	{
+		.name = "mc13783-hifi",
+		.id = MC13783_ID_SYNC,
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_96000,
+			.formats = MC13783_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = MC13783_RATES_RECORD,
+			.formats = MC13783_FORMATS,
+		},
+		.ops = &mc13783_ops_sync,
+		.symmetric_rates = 1,
+	}
+};
+
+static const struct snd_soc_component_driver soc_component_dev_mc13783 = {
+	.probe			= mc13783_probe,
+	.remove			= mc13783_remove,
+	.controls		= mc13783_control_list,
+	.num_controls		= ARRAY_SIZE(mc13783_control_list),
+	.dapm_widgets		= mc13783_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(mc13783_dapm_widgets),
+	.dapm_routes		= mc13783_routes,
+	.num_dapm_routes	= ARRAY_SIZE(mc13783_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int __init mc13783_codec_probe(struct platform_device *pdev)
+{
+	struct mc13783_priv *priv;
+	struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
+	struct device_node *np;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	if (pdata) {
+		priv->adc_ssi_port = pdata->adc_ssi_port;
+		priv->dac_ssi_port = pdata->dac_ssi_port;
+	} else {
+		np = of_get_child_by_name(pdev->dev.parent->of_node, "codec");
+		if (!np)
+			return -ENOSYS;
+
+		ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port);
+		if (ret) {
+			of_node_put(np);
+			return ret;
+		}
+
+		ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port);
+		if (ret) {
+			of_node_put(np);
+			return ret;
+		}
+
+		of_node_put(np);
+	}
+
+	dev_set_drvdata(&pdev->dev, priv);
+	priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
+
+	if (priv->adc_ssi_port == priv->dac_ssi_port)
+		ret = devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_mc13783,
+			mc13783_dai_sync, ARRAY_SIZE(mc13783_dai_sync));
+	else
+		ret = devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_mc13783,
+			mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async));
+
+	return ret;
+}
+
+static int mc13783_codec_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver mc13783_codec_driver = {
+	.driver = {
+		.name	= "mc13783-codec",
+	},
+	.remove = mc13783_codec_remove,
+};
+module_platform_driver_probe(mc13783_codec_driver, mc13783_codec_probe);
+
+MODULE_DESCRIPTION("ASoC MC13783 driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
+MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/mc13783.h b/sound/soc/codecs/mc13783.h
new file mode 100644
index 0000000..3a6d199
--- /dev/null
+++ b/sound/soc/codecs/mc13783.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef MC13783_MIXER_H
+#define MC13783_MIXER_H
+
+#define MC13783_CLK_CLIA	1
+#define MC13783_CLK_CLIB	2
+
+#define MC13783_ID_STEREO_DAC	1
+#define MC13783_ID_STEREO_CODEC	2
+#define MC13783_ID_SYNC		3
+
+#endif /* MC13783_MIXER_H */
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
new file mode 100644
index 0000000..a5fa490
--- /dev/null
+++ b/sound/soc/codecs/ml26124.c
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "ml26124.h"
+
+#define DVOL_CTL_DVMUTE_ON		BIT(4)	/* Digital volume MUTE On */
+#define DVOL_CTL_DVMUTE_OFF		0	/* Digital volume MUTE Off */
+#define ML26124_SAI_NO_DELAY	BIT(1)
+#define ML26124_SAI_FRAME_SYNC	(BIT(5) | BIT(0)) /* For mono (Telecodec) */
+#define ML26134_CACHESIZE 212
+#define ML26124_VMID	BIT(1)
+#define ML26124_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 |\
+		       SNDRV_PCM_RATE_48000)
+#define ML26124_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |\
+			 SNDRV_PCM_FMTBIT_S32_LE)
+#define ML26124_NUM_REGISTER ML26134_CACHESIZE
+
+struct ml26124_priv {
+	u32 mclk;
+	u32 rate;
+	struct regmap *regmap;
+	int clk_in;
+	struct snd_pcm_substream *substream;
+};
+
+struct clk_coeff {
+	u32 mclk;
+	u32 rate;
+	u8 pllnl;
+	u8 pllnh;
+	u8 pllml;
+	u8 pllmh;
+	u8 plldiv;
+};
+
+/* ML26124 configuration */
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7150, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(alclvl, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(mingain, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(maxgain, -675, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_vol, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0);
+
+static const char * const ml26124_companding[] = {"16bit PCM", "u-law",
+						  "A-law"};
+
+static SOC_ENUM_SINGLE_DECL(ml26124_adc_companding_enum,
+			    ML26124_SAI_TRANS_CTL, 6, ml26124_companding);
+
+static SOC_ENUM_SINGLE_DECL(ml26124_dac_companding_enum,
+			    ML26124_SAI_RCV_CTL, 6, ml26124_companding);
+
+static const struct snd_kcontrol_new ml26124_snd_controls[] = {
+	SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("Playback Digital Volume", ML26124_PLBAK_DIG_VOL, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("Digital Boost Volume", ML26124_DIGI_BOOST_VOL, 0,
+			0x3f, 0, boost_vol),
+	SOC_SINGLE_TLV("EQ Band0 Volume", ML26124_EQ_GAIN_BRAND0, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("EQ Band1 Volume", ML26124_EQ_GAIN_BRAND1, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("EQ Band2 Volume", ML26124_EQ_GAIN_BRAND2, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("EQ Band3 Volume", ML26124_EQ_GAIN_BRAND3, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("EQ Band4 Volume", ML26124_EQ_GAIN_BRAND4, 0,
+			0xff, 1, digital_tlv),
+	SOC_SINGLE_TLV("ALC Target Level", ML26124_ALC_TARGET_LEV, 0,
+			0xf, 1, alclvl),
+	SOC_SINGLE_TLV("ALC Min Input Volume", ML26124_ALC_MAXMIN_GAIN, 0,
+			7, 0, mingain),
+	SOC_SINGLE_TLV("ALC Max Input Volume", ML26124_ALC_MAXMIN_GAIN, 4,
+			7, 1, maxgain),
+	SOC_SINGLE_TLV("Playback Limiter Min Input Volume",
+			ML26124_PL_MAXMIN_GAIN, 0, 7, 0, mingain),
+	SOC_SINGLE_TLV("Playback Limiter Max Input Volume",
+			ML26124_PL_MAXMIN_GAIN, 4, 7, 1, maxgain),
+	SOC_SINGLE_TLV("Playback Boost Volume", ML26124_PLYBAK_BOST_VOL, 0,
+			0x3f, 0, boost_vol),
+	SOC_SINGLE("DC High Pass Filter Switch", ML26124_FILTER_EN, 0, 1, 0),
+	SOC_SINGLE("Noise High Pass Filter Switch", ML26124_FILTER_EN, 1, 1, 0),
+	SOC_SINGLE("ZC Switch", ML26124_PW_ZCCMP_PW_MNG, 1,
+		    1, 0),
+	SOC_SINGLE("EQ Band0 Switch", ML26124_FILTER_EN, 2, 1, 0),
+	SOC_SINGLE("EQ Band1 Switch", ML26124_FILTER_EN, 3, 1, 0),
+	SOC_SINGLE("EQ Band2 Switch", ML26124_FILTER_EN, 4, 1, 0),
+	SOC_SINGLE("EQ Band3 Switch", ML26124_FILTER_EN, 5, 1, 0),
+	SOC_SINGLE("EQ Band4 Switch", ML26124_FILTER_EN, 6, 1, 0),
+	SOC_SINGLE("Play Limiter", ML26124_DVOL_CTL, 0, 1, 0),
+	SOC_SINGLE("Capture Limiter", ML26124_DVOL_CTL, 1, 1, 0),
+	SOC_SINGLE("Digital Volume Fade Switch", ML26124_DVOL_CTL, 3, 1, 0),
+	SOC_SINGLE("Digital Switch", ML26124_DVOL_CTL, 4, 1, 0),
+	SOC_ENUM("DAC Companding", ml26124_dac_companding_enum),
+	SOC_ENUM("ADC Companding", ml26124_adc_companding_enum),
+};
+
+static const struct snd_kcontrol_new ml26124_output_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Switch", ML26124_SPK_AMP_OUT, 1, 1, 0),
+	SOC_DAPM_SINGLE("Line in loopback Switch", ML26124_SPK_AMP_OUT, 3, 1,
+			 0),
+	SOC_DAPM_SINGLE("PGA Switch", ML26124_SPK_AMP_OUT, 5, 1, 0),
+};
+
+/* Input mux */
+static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in",
+				"Digital MIC in", "Analog MIC Differential in"};
+
+static SOC_ENUM_SINGLE_DECL(ml26124_insel_enum,
+			    ML26124_MIC_IF_CTL, 0, ml26124_input_select);
+
+static const struct snd_kcontrol_new ml26124_input_mux_controls =
+	SOC_DAPM_ENUM("Input Select", ml26124_insel_enum);
+
+static const struct snd_kcontrol_new ml26124_line_control =
+	SOC_DAPM_SINGLE("Switch", ML26124_PW_LOUT_PW_MNG, 1, 1, 0);
+
+static const struct snd_soc_dapm_widget ml26124_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("MCLKEN", ML26124_CLK_EN, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLLEN", ML26124_CLK_EN, 1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLLOE", ML26124_CLK_EN, 2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS", ML26124_PW_REF_PW_MNG, 2, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
+			   &ml26124_output_mixer_controls[0],
+			   ARRAY_SIZE(ml26124_output_mixer_controls)),
+	SND_SOC_DAPM_DAC("DAC", "Playback", ML26124_PW_DAC_PW_MNG, 1, 0),
+	SND_SOC_DAPM_ADC("ADC", "Capture", ML26124_PW_IN_PW_MNG, 1, 0),
+	SND_SOC_DAPM_PGA("PGA", ML26124_PW_IN_PW_MNG, 3, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+			  &ml26124_input_mux_controls),
+	SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0,
+			     &ml26124_line_control),
+	SND_SOC_DAPM_INPUT("MDIN"),
+	SND_SOC_DAPM_INPUT("MIN"),
+	SND_SOC_DAPM_INPUT("LIN"),
+	SND_SOC_DAPM_OUTPUT("SPOUT"),
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+};
+
+static const struct snd_soc_dapm_route ml26124_intercon[] = {
+	/* Supply */
+	{"DAC", NULL, "MCLKEN"},
+	{"ADC", NULL, "MCLKEN"},
+	{"DAC", NULL, "PLLEN"},
+	{"ADC", NULL, "PLLEN"},
+	{"DAC", NULL, "PLLOE"},
+	{"ADC", NULL, "PLLOE"},
+
+	/* output mixer */
+	{"Output Mixer", "DAC Switch", "DAC"},
+	{"Output Mixer", "Line in loopback Switch", "LIN"},
+
+	/* outputs */
+	{"LOUT", NULL, "Output Mixer"},
+	{"SPOUT", NULL, "Output Mixer"},
+	{"Line Out Enable", NULL, "LOUT"},
+
+	/* input */
+	{"ADC", NULL, "Input Mux"},
+	{"Input Mux", "Analog MIC SingleEnded in", "PGA"},
+	{"Input Mux", "Analog MIC Differential in", "PGA"},
+	{"PGA", NULL, "MIN"},
+};
+
+/* PLLOutputFreq(Hz) = InputMclkFreq(Hz) * PLLM / (PLLN * PLLDIV) */
+static const struct clk_coeff coeff_div[] = {
+	{12288000, 16000, 0xc, 0x0, 0x20, 0x0, 0x4},
+	{12288000, 32000, 0xc, 0x0, 0x20, 0x0, 0x4},
+	{12288000, 48000, 0xc, 0x0, 0x30, 0x0, 0x4},
+};
+
+static const struct reg_default ml26124_reg[] = {
+	/* CLOCK control Register */
+	{0x00, 0x00 },	/* Sampling Rate */
+	{0x02, 0x00},	/* PLL NL */
+	{0x04, 0x00},	/* PLLNH */
+	{0x06, 0x00},	/* PLLML */
+	{0x08, 0x00},	/* MLLMH */
+	{0x0a, 0x00},	/* PLLDIV */
+	{0x0c, 0x00},	/* Clock Enable */
+	{0x0e, 0x00},	/* CLK Input/Output Control */
+
+	/* System Control Register */
+	{0x10, 0x00},	/* Software RESET */
+	{0x12, 0x00},	/* Record/Playback Run */
+	{0x14, 0x00},	/* Mic Input/Output control */
+
+	/* Power Management Register */
+	{0x20, 0x00},	/* Reference Power Management */
+	{0x22, 0x00},	/* Input Power Management */
+	{0x24, 0x00},	/* DAC Power Management */
+	{0x26, 0x00},	/* SP-AMP Power Management */
+	{0x28, 0x00},	/* LINEOUT Power Management */
+	{0x2a, 0x00},	/* VIDEO Power Management */
+	{0x2e, 0x00},	/* AC-CMP Power Management */
+
+	/* Analog reference Control Register */
+	{0x30, 0x04},	/* MICBIAS Voltage Control */
+
+	/* Input/Output Amplifier Control Register */
+	{0x32, 0x10},	/* MIC Input Volume */
+	{0x38, 0x00},	/* Mic Boost Volume */
+	{0x3a, 0x33},	/* Speaker AMP Volume */
+	{0x48, 0x00},	/* AMP Volume Control Function Enable */
+	{0x4a, 0x00},	/* Amplifier Volume Fader Control */
+
+	/* Analog Path Control Register */
+	{0x54, 0x00},	/* Speaker AMP Output Control */
+	{0x5a, 0x00},	/* Mic IF Control */
+	{0xe8, 0x01},	/* Mic Select Control */
+
+	/* Audio Interface Control Register */
+	{0x60, 0x00},	/* SAI-Trans Control */
+	{0x62, 0x00},	/* SAI-Receive Control */
+	{0x64, 0x00},	/* SAI Mode select */
+
+	/* DSP Control Register */
+	{0x66, 0x01},	/* Filter Func Enable */
+	{0x68, 0x00},	/* Volume Control Func Enable */
+	{0x6A, 0x00},	/* Mixer & Volume Control*/
+	{0x6C, 0xff},	/* Record Digital Volume */
+	{0x70, 0xff},	/* Playback Digital Volume */
+	{0x72, 0x10},	/* Digital Boost Volume */
+	{0x74, 0xe7},	/* EQ gain Band0 */
+	{0x76, 0xe7},	/* EQ gain Band1 */
+	{0x78, 0xe7},	/* EQ gain Band2 */
+	{0x7A, 0xe7},	/* EQ gain Band3 */
+	{0x7C, 0xe7},	/* EQ gain Band4 */
+	{0x7E, 0x00},	/* HPF2 CutOff*/
+	{0x80, 0x00},	/* EQ Band0 Coef0L */
+	{0x82, 0x00},	/* EQ Band0 Coef0H */
+	{0x84, 0x00},	/* EQ Band0 Coef0L */
+	{0x86, 0x00},	/* EQ Band0 Coef0H */
+	{0x88, 0x00},	/* EQ Band1 Coef0L */
+	{0x8A, 0x00},	/* EQ Band1 Coef0H */
+	{0x8C, 0x00},	/* EQ Band1 Coef0L */
+	{0x8E, 0x00},	/* EQ Band1 Coef0H */
+	{0x90, 0x00},	/* EQ Band2 Coef0L */
+	{0x92, 0x00},	/* EQ Band2 Coef0H */
+	{0x94, 0x00},	/* EQ Band2 Coef0L */
+	{0x96, 0x00},	/* EQ Band2 Coef0H */
+	{0x98, 0x00},	/* EQ Band3 Coef0L */
+	{0x9A, 0x00},	/* EQ Band3 Coef0H */
+	{0x9C, 0x00},	/* EQ Band3 Coef0L */
+	{0x9E, 0x00},	/* EQ Band3 Coef0H */
+	{0xA0, 0x00},	/* EQ Band4 Coef0L */
+	{0xA2, 0x00},	/* EQ Band4 Coef0H */
+	{0xA4, 0x00},	/* EQ Band4 Coef0L */
+	{0xA6, 0x00},	/* EQ Band4 Coef0H */
+
+	/* ALC Control Register */
+	{0xb0, 0x00},	/* ALC Mode */
+	{0xb2, 0x02},	/* ALC Attack Time */
+	{0xb4, 0x03},	/* ALC Decay Time */
+	{0xb6, 0x00},	/* ALC Hold Time */
+	{0xb8, 0x0b},	/* ALC Target Level */
+	{0xba, 0x70},	/* ALC Max/Min Gain */
+	{0xbc, 0x00},	/* Noise Gate Threshold */
+	{0xbe, 0x00},	/* ALC ZeroCross TimeOut */
+
+	/* Playback Limiter Control Register */
+	{0xc0, 0x04},	/* PL Attack Time */
+	{0xc2, 0x05},	/* PL Decay Time */
+	{0xc4, 0x0d},	/* PL Target Level */
+	{0xc6, 0x70},	/* PL Max/Min Gain */
+	{0xc8, 0x10},	/* Playback Boost Volume */
+	{0xca, 0x00},	/* PL ZeroCross TimeOut */
+
+	/* Video Amplifier Control Register */
+	{0xd0, 0x01},	/* VIDEO AMP Gain Control */
+	{0xd2, 0x01},	/* VIDEO AMP Setup 1 */
+	{0xd4, 0x01},	/* VIDEO AMP Control2 */
+};
+
+/* Get sampling rate value of sampling rate setting register (0x0) */
+static inline int get_srate(int rate)
+{
+	int srate;
+
+	switch (rate) {
+	case 16000:
+		srate = 3;
+		break;
+	case 32000:
+		srate = 6;
+		break;
+	case 48000:
+		srate = 8;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return srate;
+}
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static int ml26124_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *hw_params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ml26124_priv *priv = snd_soc_component_get_drvdata(component);
+	int i = get_coeff(priv->mclk, params_rate(hw_params));
+	int srate;
+
+	if (i < 0)
+		return i;
+	priv->substream = substream;
+	priv->rate = params_rate(hw_params);
+
+	if (priv->clk_in) {
+		switch (priv->mclk / params_rate(hw_params)) {
+		case 256:
+			snd_soc_component_update_bits(component, ML26124_CLK_CTL,
+					    BIT(0) | BIT(1), 1);
+			break;
+		case 512:
+			snd_soc_component_update_bits(component, ML26124_CLK_CTL,
+					    BIT(0) | BIT(1), 2);
+			break;
+		case 1024:
+			snd_soc_component_update_bits(component, ML26124_CLK_CTL,
+					    BIT(0) | BIT(1), 3);
+			break;
+		default:
+			dev_err(component->dev, "Unsupported MCLKI\n");
+			break;
+		}
+	} else {
+		snd_soc_component_update_bits(component, ML26124_CLK_CTL,
+				    BIT(0) | BIT(1), 0);
+	}
+
+	srate = get_srate(params_rate(hw_params));
+	if (srate < 0)
+		return srate;
+
+	snd_soc_component_update_bits(component, ML26124_SMPLING_RATE, 0xf, srate);
+	snd_soc_component_update_bits(component, ML26124_PLLNL, 0xff, coeff_div[i].pllnl);
+	snd_soc_component_update_bits(component, ML26124_PLLNH, 0x1, coeff_div[i].pllnh);
+	snd_soc_component_update_bits(component, ML26124_PLLML, 0xff, coeff_div[i].pllml);
+	snd_soc_component_update_bits(component, ML26124_PLLMH, 0x3f, coeff_div[i].pllmh);
+	snd_soc_component_update_bits(component, ML26124_PLLDIV, 0x1f, coeff_div[i].plldiv);
+
+	return 0;
+}
+
+static int ml26124_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ml26124_priv *priv = snd_soc_component_get_drvdata(component);
+
+	switch (priv->substream->stream) {
+	case SNDRV_PCM_STREAM_CAPTURE:
+		snd_soc_component_update_bits(component, ML26124_REC_PLYBAK_RUN, BIT(0), 1);
+		break;
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		snd_soc_component_update_bits(component, ML26124_REC_PLYBAK_RUN, BIT(1), 2);
+		break;
+	}
+
+	if (mute)
+		snd_soc_component_update_bits(component, ML26124_DVOL_CTL, BIT(4),
+				    DVOL_CTL_DVMUTE_ON);
+	else
+		snd_soc_component_update_bits(component, ML26124_DVOL_CTL, BIT(4),
+				    DVOL_CTL_DVMUTE_OFF);
+
+	return 0;
+}
+
+static int ml26124_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	unsigned char mode;
+	struct snd_soc_component *component = codec_dai->component;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		mode = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		mode = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, ML26124_SAI_MODE_SEL, BIT(0), mode);
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ml26124_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct ml26124_priv *priv = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case ML26124_USE_PLLOUT:
+		priv->clk_in = ML26124_USE_PLLOUT;
+		break;
+	case ML26124_USE_MCLKI:
+		priv->clk_in = ML26124_USE_MCLKI;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	priv->mclk = freq;
+
+	return 0;
+}
+
+static int ml26124_set_bias_level(struct snd_soc_component *component,
+		enum snd_soc_bias_level level)
+{
+	struct ml26124_priv *priv = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_component_update_bits(component, ML26124_PW_SPAMP_PW_MNG,
+				    ML26124_R26_MASK, ML26124_BLT_PREAMP_ON);
+		msleep(100);
+		snd_soc_component_update_bits(component, ML26124_PW_SPAMP_PW_MNG,
+				    ML26124_R26_MASK,
+				    ML26124_MICBEN_ON | ML26124_BLT_ALL_ON);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* VMID ON */
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_update_bits(component, ML26124_PW_REF_PW_MNG,
+					    ML26124_VMID, ML26124_VMID);
+			msleep(500);
+			regcache_sync(priv->regmap);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* VMID OFF */
+		snd_soc_component_update_bits(component, ML26124_PW_REF_PW_MNG,
+				    ML26124_VMID, 0);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops ml26124_dai_ops = {
+	.hw_params	= ml26124_hw_params,
+	.digital_mute	= ml26124_mute,
+	.set_fmt	= ml26124_set_dai_fmt,
+	.set_sysclk	= ml26124_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver ml26124_dai = {
+	.name = "ml26124-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ML26124_RATES,
+		.formats = ML26124_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ML26124_RATES,
+		.formats = ML26124_FORMATS,},
+	.ops = &ml26124_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int ml26124_probe(struct snd_soc_component *component)
+{
+	/* Software Reset */
+	snd_soc_component_update_bits(component, ML26124_SW_RST, 0x01, 1);
+	snd_soc_component_update_bits(component, ML26124_SW_RST, 0x01, 0);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_ml26124 = {
+	.probe			= ml26124_probe,
+	.set_bias_level		= ml26124_set_bias_level,
+	.controls		= ml26124_snd_controls,
+	.num_controls		= ARRAY_SIZE(ml26124_snd_controls),
+	.dapm_widgets		= ml26124_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ml26124_dapm_widgets),
+	.dapm_routes		= ml26124_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(ml26124_intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config ml26124_i2c_regmap = {
+	.val_bits = 8,
+	.reg_bits = 8,
+	.max_register = ML26124_NUM_REGISTER,
+	.reg_defaults = ml26124_reg,
+	.num_reg_defaults = ARRAY_SIZE(ml26124_reg),
+	.cache_type = REGCACHE_RBTREE,
+	.write_flag_mask = 0x01,
+};
+
+static int ml26124_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct ml26124_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, priv);
+
+	priv->regmap = devm_regmap_init_i2c(i2c, &ml26124_i2c_regmap);
+	if (IS_ERR(priv->regmap)) {
+		ret = PTR_ERR(priv->regmap);
+		dev_err(&i2c->dev, "regmap_init_i2c() failed: %d\n", ret);
+		return ret;
+	}
+
+	return devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_ml26124, &ml26124_dai, 1);
+}
+
+static const struct i2c_device_id ml26124_i2c_id[] = {
+	{ "ml26124", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ml26124_i2c_id);
+
+static struct i2c_driver ml26124_i2c_driver = {
+	.driver = {
+		.name = "ml26124",
+	},
+	.probe = ml26124_i2c_probe,
+	.id_table = ml26124_i2c_id,
+};
+
+module_i2c_driver(ml26124_i2c_driver);
+
+MODULE_AUTHOR("Tomoya MORINAGA <tomoya.rohm@gmail.com>");
+MODULE_DESCRIPTION("LAPIS Semiconductor ML26124 ALSA SoC codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ml26124.h b/sound/soc/codecs/ml26124.h
new file mode 100644
index 0000000..5ea0cbb
--- /dev/null
+++ b/sound/soc/codecs/ml26124.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef ML26124_H
+#define ML26124_H
+
+/* Clock Control Register */
+#define ML26124_SMPLING_RATE		0x00
+#define ML26124_PLLNL			0x02
+#define ML26124_PLLNH			0x04
+#define ML26124_PLLML			0x06
+#define ML26124_PLLMH			0x08
+#define ML26124_PLLDIV			0x0a
+#define ML26124_CLK_EN			0x0c
+#define ML26124_CLK_CTL			0x0e
+
+/* System Control Register */
+#define ML26124_SW_RST			0x10
+#define ML26124_REC_PLYBAK_RUN		0x12
+#define ML26124_MIC_TIM			0x14
+
+/* Power Mnagement Register */
+#define ML26124_PW_REF_PW_MNG		0x20
+#define ML26124_PW_IN_PW_MNG		0x22
+#define ML26124_PW_DAC_PW_MNG		0x24
+#define ML26124_PW_SPAMP_PW_MNG		0x26
+#define ML26124_PW_LOUT_PW_MNG		0x28
+#define ML26124_PW_VOUT_PW_MNG		0x2a
+#define ML26124_PW_ZCCMP_PW_MNG		0x2e
+
+/* Analog Reference Control Register */
+#define ML26124_PW_MICBIAS_VOL		0x30
+
+/* Input/Output Amplifier Control Register */
+#define ML26124_PW_MIC_IN_VOL		0x32
+#define ML26124_PW_MIC_BOST_VOL		0x38
+#define ML26124_PW_SPK_AMP_VOL		0x3a
+#define ML26124_PW_AMP_VOL_FUNC		0x48
+#define ML26124_PW_AMP_VOL_FADE		0x4a
+
+/* Analog Path Control Register */
+#define ML26124_SPK_AMP_OUT		0x54
+#define ML26124_MIC_IF_CTL		0x5a
+#define ML26124_MIC_SELECT		0xe8
+
+/* Audio Interface Control Register */
+#define ML26124_SAI_TRANS_CTL		0x60
+#define ML26124_SAI_RCV_CTL		0x62
+#define ML26124_SAI_MODE_SEL		0x64
+
+/* DSP Control Register */
+#define ML26124_FILTER_EN		0x66
+#define ML26124_DVOL_CTL		0x68
+#define ML26124_MIXER_VOL_CTL		0x6a
+#define ML26124_RECORD_DIG_VOL		0x6c
+#define ML26124_PLBAK_DIG_VOL		0x70
+#define ML26124_DIGI_BOOST_VOL		0x72
+#define ML26124_EQ_GAIN_BRAND0		0x74
+#define ML26124_EQ_GAIN_BRAND1		0x76
+#define ML26124_EQ_GAIN_BRAND2		0x78
+#define ML26124_EQ_GAIN_BRAND3		0x7a
+#define ML26124_EQ_GAIN_BRAND4		0x7c
+#define ML26124_HPF2_CUTOFF		0x7e
+#define ML26124_EQBRAND0_F0L		0x80
+#define ML26124_EQBRAND0_F0H		0x82
+#define ML26124_EQBRAND0_F1L		0x84
+#define ML26124_EQBRAND0_F1H		0x86
+#define ML26124_EQBRAND1_F0L		0x88
+#define ML26124_EQBRAND1_F0H		0x8a
+#define ML26124_EQBRAND1_F1L		0x8c
+#define ML26124_EQBRAND1_F1H		0x8e
+#define ML26124_EQBRAND2_F0L		0x90
+#define ML26124_EQBRAND2_F0H		0x92
+#define ML26124_EQBRAND2_F1L		0x94
+#define ML26124_EQBRAND2_F1H		0x96
+#define ML26124_EQBRAND3_F0L		0x98
+#define ML26124_EQBRAND3_F0H		0x9a
+#define ML26124_EQBRAND3_F1L		0x9c
+#define ML26124_EQBRAND3_F1H		0x9e
+#define ML26124_EQBRAND4_F0L		0xa0
+#define ML26124_EQBRAND4_F0H		0xa2
+#define ML26124_EQBRAND4_F1L		0xa4
+#define ML26124_EQBRAND4_F1H		0xa6
+
+/* ALC Control Register */
+#define ML26124_ALC_MODE		0xb0
+#define ML26124_ALC_ATTACK_TIM		0xb2
+#define ML26124_ALC_DECAY_TIM		0xb4
+#define ML26124_ALC_HOLD_TIM		0xb6
+#define ML26124_ALC_TARGET_LEV		0xb8
+#define ML26124_ALC_MAXMIN_GAIN		0xba
+#define ML26124_NOIS_GATE_THRSH		0xbc
+#define ML26124_ALC_ZERO_TIMOUT		0xbe
+
+/* Playback Limiter Control Register */
+#define ML26124_PL_ATTACKTIME		0xc0
+#define ML26124_PL_DECAYTIME		0xc2
+#define ML26124_PL_TARGETTIME		0xc4
+#define ML26124_PL_MAXMIN_GAIN		0xc6
+#define ML26124_PLYBAK_BOST_VOL		0xc8
+#define ML26124_PL_0CROSS_TIMOUT	0xca
+
+/* Video Amplifer Control Register */
+#define ML26124_VIDEO_AMP_GAIN_CTL	0xd0
+#define ML26124_VIDEO_AMP_SETUP1	0xd2
+#define ML26124_VIDEO_AMP_CTL2		0xd4
+
+/* Clock select for machine driver */
+#define ML26124_USE_PLL			0
+#define ML26124_USE_MCLKI_256FS		1
+#define ML26124_USE_MCLKI_512FS		2
+#define ML26124_USE_MCLKI_1024FS	3
+
+/* Register Mask */
+#define ML26124_R0_MASK	0xf
+#define ML26124_R2_MASK	0xff
+#define ML26124_R4_MASK	0x1
+#define ML26124_R6_MASK	0xf
+#define ML26124_R8_MASK	0x3f
+#define ML26124_Ra_MASK	0x1f
+#define ML26124_Rc_MASK	0x1f
+#define ML26124_Re_MASK	0x7
+#define ML26124_R10_MASK	0x1
+#define ML26124_R12_MASK	0x17
+#define ML26124_R14_MASK	0x3f
+#define ML26124_R20_MASK	0x47
+#define ML26124_R22_MASK	0xa
+#define ML26124_R24_MASK	0x2
+#define ML26124_R26_MASK	0x1f
+#define ML26124_R28_MASK	0x2
+#define ML26124_R2a_MASK	0x2
+#define ML26124_R2e_MASK	0x2
+#define ML26124_R30_MASK	0x7
+#define ML26124_R32_MASK	0x3f
+#define ML26124_R38_MASK	0x38
+#define ML26124_R3a_MASK	0x3f
+#define ML26124_R48_MASK	0x3
+#define ML26124_R4a_MASK	0x7
+#define ML26124_R54_MASK	0x2a
+#define ML26124_R5a_MASK	0x3
+#define ML26124_Re8_MASK	0x3
+#define ML26124_R60_MASK	0xff
+#define ML26124_R62_MASK	0xff
+#define ML26124_R64_MASK	0x1
+#define ML26124_R66_MASK	0xff
+#define ML26124_R68_MASK	0x3b
+#define ML26124_R6a_MASK	0xf3
+#define ML26124_R6c_MASK	0xff
+#define ML26124_R70_MASK	0xff
+
+#define ML26124_MCLKEN		BIT(0)
+#define ML26124_PLLEN		BIT(1)
+#define ML26124_PLLOE		BIT(2)
+#define ML26124_MCLKOE		BIT(3)
+
+#define ML26124_BLT_ALL_ON	0x1f
+#define ML26124_BLT_PREAMP_ON	0x13
+
+#define ML26124_MICBEN_ON	BIT(2)
+
+enum ml26124_regs {
+	ML26124_MCLK = 0,
+};
+
+enum ml26124_clk_in {
+	ML26124_USE_PLLOUT = 0,
+	ML26124_USE_MCLKI,
+};
+
+#endif
diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c
new file mode 100644
index 0000000..b7cf7cc
--- /dev/null
+++ b/sound/soc/codecs/msm8916-wcd-analog.c
@@ -0,0 +1,1265 @@
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+
+#define CDC_D_REVISION1			(0xf000)
+#define CDC_D_PERPH_SUBTYPE		(0xf005)
+#define CDC_D_INT_EN_SET		(0x015)
+#define CDC_D_INT_EN_CLR		(0x016)
+#define MBHC_SWITCH_INT			BIT(7)
+#define MBHC_MIC_ELECTRICAL_INS_REM_DET	BIT(6)
+#define MBHC_BUTTON_PRESS_DET		BIT(5)
+#define MBHC_BUTTON_RELEASE_DET		BIT(4)
+#define CDC_D_CDC_RST_CTL		(0xf046)
+#define RST_CTL_DIG_SW_RST_N_MASK	BIT(7)
+#define RST_CTL_DIG_SW_RST_N_RESET	0
+#define RST_CTL_DIG_SW_RST_N_REMOVE_RESET BIT(7)
+
+#define CDC_D_CDC_TOP_CLK_CTL		(0xf048)
+#define TOP_CLK_CTL_A_MCLK_MCLK2_EN_MASK (BIT(2) | BIT(3))
+#define TOP_CLK_CTL_A_MCLK_EN_ENABLE	 BIT(2)
+#define TOP_CLK_CTL_A_MCLK2_EN_ENABLE	BIT(3)
+
+#define CDC_D_CDC_ANA_CLK_CTL		(0xf049)
+#define ANA_CLK_CTL_EAR_HPHR_CLK_EN_MASK BIT(0)
+#define ANA_CLK_CTL_EAR_HPHR_CLK_EN	BIT(0)
+#define ANA_CLK_CTL_EAR_HPHL_CLK_EN	BIT(1)
+#define ANA_CLK_CTL_SPKR_CLK_EN_MASK	BIT(4)
+#define ANA_CLK_CTL_SPKR_CLK_EN	BIT(4)
+#define ANA_CLK_CTL_TXA_CLK25_EN	BIT(5)
+
+#define CDC_D_CDC_DIG_CLK_CTL		(0xf04A)
+#define DIG_CLK_CTL_RXD1_CLK_EN		BIT(0)
+#define DIG_CLK_CTL_RXD2_CLK_EN		BIT(1)
+#define DIG_CLK_CTL_RXD3_CLK_EN		BIT(2)
+#define DIG_CLK_CTL_D_MBHC_CLK_EN_MASK	BIT(3)
+#define DIG_CLK_CTL_D_MBHC_CLK_EN	BIT(3)
+#define DIG_CLK_CTL_TXD_CLK_EN		BIT(4)
+#define DIG_CLK_CTL_NCP_CLK_EN_MASK	BIT(6)
+#define DIG_CLK_CTL_NCP_CLK_EN		BIT(6)
+#define DIG_CLK_CTL_RXD_PDM_CLK_EN_MASK	BIT(7)
+#define DIG_CLK_CTL_RXD_PDM_CLK_EN	BIT(7)
+
+#define CDC_D_CDC_CONN_TX1_CTL		(0xf050)
+#define CONN_TX1_SERIAL_TX1_MUX		GENMASK(1, 0)
+#define CONN_TX1_SERIAL_TX1_ADC_1	0x0
+#define CONN_TX1_SERIAL_TX1_RX_PDM_LB	0x1
+#define CONN_TX1_SERIAL_TX1_ZERO	0x2
+
+#define CDC_D_CDC_CONN_TX2_CTL		(0xf051)
+#define CONN_TX2_SERIAL_TX2_MUX		GENMASK(1, 0)
+#define CONN_TX2_SERIAL_TX2_ADC_2	0x0
+#define CONN_TX2_SERIAL_TX2_RX_PDM_LB	0x1
+#define CONN_TX2_SERIAL_TX2_ZERO	0x2
+#define CDC_D_CDC_CONN_HPHR_DAC_CTL	(0xf052)
+#define CDC_D_CDC_CONN_RX1_CTL		(0xf053)
+#define CDC_D_CDC_CONN_RX2_CTL		(0xf054)
+#define CDC_D_CDC_CONN_RX3_CTL		(0xf055)
+#define CDC_D_CDC_CONN_RX_LB_CTL	(0xf056)
+#define CDC_D_SEC_ACCESS		(0xf0D0)
+#define CDC_D_PERPH_RESET_CTL3		(0xf0DA)
+#define CDC_D_PERPH_RESET_CTL4		(0xf0DB)
+#define CDC_A_REVISION1			(0xf100)
+#define CDC_A_REVISION2			(0xf101)
+#define CDC_A_REVISION3			(0xf102)
+#define CDC_A_REVISION4			(0xf103)
+#define CDC_A_PERPH_TYPE		(0xf104)
+#define CDC_A_PERPH_SUBTYPE		(0xf105)
+#define CDC_A_INT_RT_STS		(0xf110)
+#define CDC_A_INT_SET_TYPE		(0xf111)
+#define CDC_A_INT_POLARITY_HIGH		(0xf112)
+#define CDC_A_INT_POLARITY_LOW		(0xf113)
+#define CDC_A_INT_LATCHED_CLR		(0xf114)
+#define CDC_A_INT_EN_SET		(0xf115)
+#define CDC_A_INT_EN_CLR		(0xf116)
+#define CDC_A_INT_LATCHED_STS		(0xf118)
+#define CDC_A_INT_PENDING_STS		(0xf119)
+#define CDC_A_INT_MID_SEL		(0xf11A)
+#define CDC_A_INT_PRIORITY		(0xf11B)
+#define CDC_A_MICB_1_EN			(0xf140)
+#define MICB_1_EN_MICB_ENABLE		BIT(7)
+#define MICB_1_EN_BYP_CAP_MASK		BIT(6)
+#define MICB_1_EN_NO_EXT_BYP_CAP	BIT(6)
+#define MICB_1_EN_EXT_BYP_CAP		0
+#define MICB_1_EN_PULL_DOWN_EN_MASK	BIT(5)
+#define MICB_1_EN_PULL_DOWN_EN_ENABLE	BIT(5)
+#define MICB_1_EN_OPA_STG2_TAIL_CURR_MASK GENMASK(3, 1)
+#define MICB_1_EN_OPA_STG2_TAIL_CURR_1_60UA	(0x4)
+#define MICB_1_EN_PULL_UP_EN_MASK	BIT(4)
+#define MICB_1_EN_TX3_GND_SEL_MASK	BIT(0)
+#define MICB_1_EN_TX3_GND_SEL_TX_GND	0
+
+#define CDC_A_MICB_1_VAL		(0xf141)
+#define MICB_MIN_VAL 1600
+#define MICB_STEP_SIZE 50
+#define MICB_VOLTAGE_REGVAL(v)		(((v - MICB_MIN_VAL)/MICB_STEP_SIZE) << 3)
+#define MICB_1_VAL_MICB_OUT_VAL_MASK	GENMASK(7, 3)
+#define MICB_1_VAL_MICB_OUT_VAL_V2P70V	((0x16)  << 3)
+#define MICB_1_VAL_MICB_OUT_VAL_V1P80V	((0x4)  << 3)
+#define CDC_A_MICB_1_CTL		(0xf142)
+
+#define MICB_1_CTL_CFILT_REF_SEL_MASK		BIT(1)
+#define MICB_1_CTL_CFILT_REF_SEL_HPF_REF	BIT(1)
+#define MICB_1_CTL_EXT_PRECHARG_EN_MASK		BIT(5)
+#define MICB_1_CTL_EXT_PRECHARG_EN_ENABLE	BIT(5)
+#define MICB_1_CTL_INT_PRECHARG_BYP_MASK	BIT(6)
+#define MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL	BIT(6)
+
+#define CDC_A_MICB_1_INT_RBIAS			(0xf143)
+#define MICB_1_INT_TX1_INT_RBIAS_EN_MASK	BIT(7)
+#define MICB_1_INT_TX1_INT_RBIAS_EN_ENABLE	BIT(7)
+#define MICB_1_INT_TX1_INT_RBIAS_EN_DISABLE	0
+
+#define MICB_1_INT_TX1_INT_PULLUP_EN_MASK	BIT(6)
+#define MICB_1_INT_TX1_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(6)
+#define MICB_1_INT_TX1_INT_PULLUP_EN_TX1N_TO_GND	0
+
+#define MICB_1_INT_TX2_INT_RBIAS_EN_MASK	BIT(4)
+#define MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE	BIT(4)
+#define MICB_1_INT_TX2_INT_RBIAS_EN_DISABLE	0
+#define MICB_1_INT_TX2_INT_PULLUP_EN_MASK	BIT(3)
+#define MICB_1_INT_TX2_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(3)
+#define MICB_1_INT_TX2_INT_PULLUP_EN_TX1N_TO_GND	0
+
+#define MICB_1_INT_TX3_INT_RBIAS_EN_MASK	BIT(1)
+#define MICB_1_INT_TX3_INT_RBIAS_EN_ENABLE	BIT(1)
+#define MICB_1_INT_TX3_INT_RBIAS_EN_DISABLE	0
+#define MICB_1_INT_TX3_INT_PULLUP_EN_MASK	BIT(0)
+#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(0)
+#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_GND	0
+
+#define CDC_A_MICB_2_EN			(0xf144)
+#define CDC_A_MICB_2_EN_ENABLE		BIT(7)
+#define CDC_A_MICB_2_PULL_DOWN_EN_MASK	BIT(5)
+#define CDC_A_MICB_2_PULL_DOWN_EN	BIT(5)
+#define CDC_A_TX_1_2_ATEST_CTL_2	(0xf145)
+#define CDC_A_MASTER_BIAS_CTL		(0xf146)
+#define CDC_A_MBHC_DET_CTL_1		(0xf147)
+#define CDC_A_MBHC_DET_CTL_L_DET_EN			BIT(7)
+#define CDC_A_MBHC_DET_CTL_GND_DET_EN			BIT(6)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION	BIT(5)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_REMOVAL	(0)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK		BIT(5)
+#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT		(5)
+#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO		BIT(4)
+#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_MANUAL		BIT(3)
+#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_MASK		GENMASK(4, 3)
+#define CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN			BIT(2)
+#define CDC_A_MBHC_DET_CTL_2		(0xf150)
+#define CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0	(BIT(7) | BIT(6))
+#define CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD	BIT(5)
+#define CDC_A_PLUG_TYPE_MASK				GENMASK(4, 3)
+#define CDC_A_HPHL_PLUG_TYPE_NO				BIT(4)
+#define CDC_A_GND_PLUG_TYPE_NO				BIT(3)
+#define CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN_MASK	BIT(0)
+#define CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN		BIT(0)
+#define CDC_A_MBHC_FSM_CTL		(0xf151)
+#define CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN			BIT(7)
+#define CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK		BIT(7)
+#define CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA	(0x3 << 4)
+#define CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK		GENMASK(6, 4)
+#define CDC_A_MBHC_DBNC_TIMER		(0xf152)
+#define CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS		BIT(3)
+#define CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS	(0x9 << 4)
+#define CDC_A_MBHC_BTN0_ZDET_CTL_0	(0xf153)
+#define CDC_A_MBHC_BTN1_ZDET_CTL_1	(0xf154)
+#define CDC_A_MBHC_BTN2_ZDET_CTL_2	(0xf155)
+#define CDC_A_MBHC_BTN3_CTL		(0xf156)
+#define CDC_A_MBHC_BTN4_CTL		(0xf157)
+#define CDC_A_MBHC_BTN_VREF_FINE_SHIFT	(2)
+#define CDC_A_MBHC_BTN_VREF_FINE_MASK	GENMASK(4, 2)
+#define CDC_A_MBHC_BTN_VREF_COARSE_MASK	GENMASK(7, 5)
+#define CDC_A_MBHC_BTN_VREF_COARSE_SHIFT (5)
+#define CDC_A_MBHC_BTN_VREF_MASK	(CDC_A_MBHC_BTN_VREF_COARSE_MASK | \
+					CDC_A_MBHC_BTN_VREF_FINE_MASK)
+#define CDC_A_MBHC_RESULT_1		(0xf158)
+#define CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK	GENMASK(4, 0)
+#define CDC_A_TX_1_EN			(0xf160)
+#define CDC_A_TX_2_EN			(0xf161)
+#define CDC_A_TX_1_2_TEST_CTL_1		(0xf162)
+#define CDC_A_TX_1_2_TEST_CTL_2		(0xf163)
+#define CDC_A_TX_1_2_ATEST_CTL		(0xf164)
+#define CDC_A_TX_1_2_OPAMP_BIAS		(0xf165)
+#define CDC_A_TX_3_EN			(0xf167)
+#define CDC_A_NCP_EN			(0xf180)
+#define CDC_A_NCP_CLK			(0xf181)
+#define CDC_A_NCP_FBCTRL		(0xf183)
+#define CDC_A_NCP_FBCTRL_FB_CLK_INV_MASK	BIT(5)
+#define CDC_A_NCP_FBCTRL_FB_CLK_INV		BIT(5)
+#define CDC_A_NCP_BIAS			(0xf184)
+#define CDC_A_NCP_VCTRL			(0xf185)
+#define CDC_A_NCP_TEST			(0xf186)
+#define CDC_A_NCP_CLIM_ADDR		(0xf187)
+#define CDC_A_RX_CLOCK_DIVIDER		(0xf190)
+#define CDC_A_RX_COM_OCP_CTL		(0xf191)
+#define CDC_A_RX_COM_OCP_COUNT		(0xf192)
+#define CDC_A_RX_COM_BIAS_DAC		(0xf193)
+#define RX_COM_BIAS_DAC_RX_BIAS_EN_MASK		BIT(7)
+#define RX_COM_BIAS_DAC_RX_BIAS_EN_ENABLE	BIT(7)
+#define RX_COM_BIAS_DAC_DAC_REF_EN_MASK		BIT(0)
+#define RX_COM_BIAS_DAC_DAC_REF_EN_ENABLE	BIT(0)
+
+#define CDC_A_RX_HPH_BIAS_PA		(0xf194)
+#define CDC_A_RX_HPH_BIAS_LDO_OCP	(0xf195)
+#define CDC_A_RX_HPH_BIAS_CNP		(0xf196)
+#define CDC_A_RX_HPH_CNP_EN		(0xf197)
+#define CDC_A_RX_HPH_L_PA_DAC_CTL	(0xf19B)
+#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_MASK	BIT(1)
+#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_RESET	BIT(1)
+#define CDC_A_RX_HPH_R_PA_DAC_CTL	(0xf19D)
+#define RX_HPH_R_PA_DAC_CTL_DATA_RESET	BIT(1)
+#define RX_HPH_R_PA_DAC_CTL_DATA_RESET_MASK BIT(1)
+
+#define CDC_A_RX_EAR_CTL			(0xf19E)
+#define RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK		BIT(0)
+#define RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE	BIT(0)
+
+#define CDC_A_SPKR_DAC_CTL		(0xf1B0)
+#define SPKR_DAC_CTL_DAC_RESET_MASK	BIT(4)
+#define SPKR_DAC_CTL_DAC_RESET_NORMAL	0
+
+#define CDC_A_SPKR_DRV_CTL		(0xf1B2)
+#define SPKR_DRV_CTL_DEF_MASK		0xEF
+#define SPKR_DRV_CLASSD_PA_EN_MASK	BIT(7)
+#define SPKR_DRV_CLASSD_PA_EN_ENABLE	BIT(7)
+#define SPKR_DRV_CAL_EN			BIT(6)
+#define SPKR_DRV_SETTLE_EN		BIT(5)
+#define SPKR_DRV_FW_EN			BIT(3)
+#define SPKR_DRV_BOOST_SET		BIT(2)
+#define SPKR_DRV_CMFB_SET		BIT(1)
+#define SPKR_DRV_GAIN_SET		BIT(0)
+#define SPKR_DRV_CTL_DEF_VAL (SPKR_DRV_CLASSD_PA_EN_ENABLE | \
+		SPKR_DRV_CAL_EN | SPKR_DRV_SETTLE_EN | \
+		SPKR_DRV_FW_EN | SPKR_DRV_BOOST_SET | \
+		SPKR_DRV_CMFB_SET | SPKR_DRV_GAIN_SET)
+#define CDC_A_SPKR_OCP_CTL		(0xf1B4)
+#define CDC_A_SPKR_PWRSTG_CTL		(0xf1B5)
+#define SPKR_PWRSTG_CTL_DAC_EN_MASK	BIT(0)
+#define SPKR_PWRSTG_CTL_DAC_EN		BIT(0)
+#define SPKR_PWRSTG_CTL_MASK		0xE0
+#define SPKR_PWRSTG_CTL_BBM_MASK	BIT(7)
+#define SPKR_PWRSTG_CTL_BBM_EN		BIT(7)
+#define SPKR_PWRSTG_CTL_HBRDGE_EN_MASK	BIT(6)
+#define SPKR_PWRSTG_CTL_HBRDGE_EN	BIT(6)
+#define SPKR_PWRSTG_CTL_CLAMP_EN_MASK	BIT(5)
+#define SPKR_PWRSTG_CTL_CLAMP_EN	BIT(5)
+
+#define CDC_A_SPKR_DRV_DBG		(0xf1B7)
+#define CDC_A_CURRENT_LIMIT		(0xf1C0)
+#define CDC_A_BOOST_EN_CTL		(0xf1C3)
+#define CDC_A_SLOPE_COMP_IP_ZERO	(0xf1C4)
+#define CDC_A_SEC_ACCESS		(0xf1D0)
+#define CDC_A_PERPH_RESET_CTL3		(0xf1DA)
+#define CDC_A_PERPH_RESET_CTL4		(0xf1DB)
+
+#define MSM8916_WCD_ANALOG_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+#define MSM8916_WCD_ANALOG_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+				    SNDRV_PCM_FMTBIT_S32_LE)
+
+static int btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+	       SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4;
+static int hs_jack_mask = SND_JACK_HEADPHONE | SND_JACK_HEADSET;
+
+static const char * const supply_names[] = {
+	"vdd-cdc-io",
+	"vdd-cdc-tx-rx-cx",
+};
+
+#define MBHC_MAX_BUTTONS	(5)
+
+struct pm8916_wcd_analog_priv {
+	u16 pmic_rev;
+	u16 codec_version;
+	bool	mbhc_btn_enabled;
+	/* special event to detect accessory type */
+	int	mbhc_btn0_released;
+	bool	detect_accessory_type;
+	struct clk *mclk;
+	struct snd_soc_component *component;
+	struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+	struct snd_soc_jack *jack;
+	bool hphl_jack_type_normally_open;
+	bool gnd_jack_type_normally_open;
+	/* Voltage threshold when internal current source of 100uA is used */
+	u32 vref_btn_cs[MBHC_MAX_BUTTONS];
+	/* Voltage threshold when microphone bias is ON */
+	u32 vref_btn_micb[MBHC_MAX_BUTTONS];
+	unsigned int micbias1_cap_mode;
+	unsigned int micbias2_cap_mode;
+	unsigned int micbias_mv;
+};
+
+static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
+static const char *const rdac2_mux_text[] = { "ZERO", "RX2", "RX1" };
+static const char *const hph_text[] = { "ZERO", "Switch", };
+
+static const struct soc_enum hph_enum = SOC_ENUM_SINGLE_VIRT(
+					ARRAY_SIZE(hph_text), hph_text);
+
+static const struct snd_kcontrol_new hphl_mux = SOC_DAPM_ENUM("HPHL", hph_enum);
+static const struct snd_kcontrol_new hphr_mux = SOC_DAPM_ENUM("HPHR", hph_enum);
+
+/* ADC2 MUX */
+static const struct soc_enum adc2_enum = SOC_ENUM_SINGLE_VIRT(
+			ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
+/* RDAC2 MUX */
+static const struct soc_enum rdac2_mux_enum = SOC_ENUM_SINGLE(
+			CDC_D_CDC_CONN_HPHR_DAC_CTL, 0, 3, rdac2_mux_text);
+
+static const struct snd_kcontrol_new spkr_switch[] = {
+	SOC_DAPM_SINGLE("Switch", CDC_A_SPKR_DAC_CTL, 7, 1, 0)
+};
+
+static const struct snd_kcontrol_new rdac2_mux = SOC_DAPM_ENUM(
+					"RDAC2 MUX Mux", rdac2_mux_enum);
+static const struct snd_kcontrol_new tx_adc2_mux = SOC_DAPM_ENUM(
+					"ADC2 MUX Mux", adc2_enum);
+
+/* Analog Gain control 0 dB to +24 dB in 6 dB steps */
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 600, 0);
+
+static const struct snd_kcontrol_new pm8916_wcd_analog_snd_controls[] = {
+	SOC_SINGLE_TLV("ADC1 Volume", CDC_A_TX_1_EN, 3, 8, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC2 Volume", CDC_A_TX_2_EN, 3, 8, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC3 Volume", CDC_A_TX_3_EN, 3, 8, 0, analog_gain),
+};
+
+static void pm8916_wcd_analog_micbias_enable(struct snd_soc_component *component)
+{
+	struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_update_bits(component, CDC_A_MICB_1_CTL,
+			    MICB_1_CTL_EXT_PRECHARG_EN_MASK |
+			    MICB_1_CTL_INT_PRECHARG_BYP_MASK,
+			    MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL
+			    | MICB_1_CTL_EXT_PRECHARG_EN_ENABLE);
+
+	if (wcd->micbias_mv) {
+		snd_soc_component_update_bits(component, CDC_A_MICB_1_VAL,
+				    MICB_1_VAL_MICB_OUT_VAL_MASK,
+				    MICB_VOLTAGE_REGVAL(wcd->micbias_mv));
+		/*
+		 * Special headset needs MICBIAS as 2.7V so wait for
+		 * 50 msec for the MICBIAS to reach 2.7 volts.
+		 */
+		if (wcd->micbias_mv >= 2700)
+			msleep(50);
+	}
+
+	snd_soc_component_update_bits(component, CDC_A_MICB_1_CTL,
+			    MICB_1_CTL_EXT_PRECHARG_EN_MASK |
+			    MICB_1_CTL_INT_PRECHARG_BYP_MASK, 0);
+
+}
+
+static int pm8916_wcd_analog_enable_micbias_ext(struct snd_soc_component
+						 *component, int event,
+						 int reg, unsigned int cap_mode)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		pm8916_wcd_analog_micbias_enable(component);
+		snd_soc_component_update_bits(component, CDC_A_MICB_1_EN,
+				    MICB_1_EN_BYP_CAP_MASK, cap_mode);
+		break;
+	}
+
+	return 0;
+}
+
+static int pm8916_wcd_analog_enable_micbias_int(struct snd_soc_component
+						 *component, int event,
+						 int reg, u32 cap_mode)
+{
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component, CDC_A_MICB_1_INT_RBIAS,
+				    MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
+				    MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
+		snd_soc_component_update_bits(component, reg, MICB_1_EN_PULL_DOWN_EN_MASK, 0);
+		snd_soc_component_update_bits(component, CDC_A_MICB_1_EN,
+				    MICB_1_EN_OPA_STG2_TAIL_CURR_MASK,
+				    MICB_1_EN_OPA_STG2_TAIL_CURR_1_60UA);
+
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		pm8916_wcd_analog_micbias_enable(component);
+		snd_soc_component_update_bits(component, CDC_A_MICB_1_EN,
+				    MICB_1_EN_BYP_CAP_MASK, cap_mode);
+		break;
+	}
+
+	return 0;
+}
+
+static int pm8916_wcd_analog_enable_micbias_ext1(struct
+						  snd_soc_dapm_widget
+						  *w, struct snd_kcontrol
+						  *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
+
+	return pm8916_wcd_analog_enable_micbias_ext(component, event, w->reg,
+						     wcd->micbias1_cap_mode);
+}
+
+static int pm8916_wcd_analog_enable_micbias_ext2(struct
+						  snd_soc_dapm_widget
+						  *w, struct snd_kcontrol
+						  *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
+
+	return pm8916_wcd_analog_enable_micbias_ext(component, event, w->reg,
+						     wcd->micbias2_cap_mode);
+
+}
+
+static int pm8916_wcd_analog_enable_micbias_int1(struct
+						  snd_soc_dapm_widget
+						  *w, struct snd_kcontrol
+						  *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
+
+	return pm8916_wcd_analog_enable_micbias_int(component, event, w->reg,
+						     wcd->micbias1_cap_mode);
+}
+
+static int pm8916_mbhc_configure_bias(struct pm8916_wcd_analog_priv *priv,
+				      bool micbias2_enabled)
+{
+	struct snd_soc_component *component = priv->component;
+	u32 coarse, fine, reg_val, reg_addr;
+	int *vrefs, i;
+
+	if (!micbias2_enabled) { /* use internal 100uA Current source */
+		/* Enable internal 2.2k Internal Rbias Resistor */
+		snd_soc_component_update_bits(component, CDC_A_MICB_1_INT_RBIAS,
+				    MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
+				    MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
+		/* Remove pull down on MIC BIAS2 */
+		snd_soc_component_update_bits(component, CDC_A_MICB_2_EN,
+				   CDC_A_MICB_2_PULL_DOWN_EN_MASK,
+				   0);
+		/* enable 100uA internal current source */
+		snd_soc_component_update_bits(component, CDC_A_MBHC_FSM_CTL,
+				    CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK,
+				    CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA);
+	}
+	snd_soc_component_update_bits(component, CDC_A_MBHC_FSM_CTL,
+			CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK,
+			CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN);
+
+	if (micbias2_enabled)
+		vrefs = &priv->vref_btn_micb[0];
+	else
+		vrefs = &priv->vref_btn_cs[0];
+
+	/* program vref ranges for all the buttons */
+	reg_addr = CDC_A_MBHC_BTN0_ZDET_CTL_0;
+	for (i = 0; i <  MBHC_MAX_BUTTONS; i++) {
+		/* split mv in to coarse parts of 100mv & fine parts of 12mv */
+		coarse = (vrefs[i] / 100);
+		fine = ((vrefs[i] % 100) / 12);
+		reg_val = (coarse << CDC_A_MBHC_BTN_VREF_COARSE_SHIFT) |
+			 (fine << CDC_A_MBHC_BTN_VREF_FINE_SHIFT);
+		snd_soc_component_update_bits(component, reg_addr,
+			       CDC_A_MBHC_BTN_VREF_MASK,
+			       reg_val);
+		reg_addr++;
+	}
+
+	return 0;
+}
+
+static void pm8916_wcd_setup_mbhc(struct pm8916_wcd_analog_priv *wcd)
+{
+	struct snd_soc_component *component = wcd->component;
+	bool micbias_enabled = false;
+	u32 plug_type = 0;
+	u32 int_en_mask;
+
+	snd_soc_component_write(component, CDC_A_MBHC_DET_CTL_1,
+		      CDC_A_MBHC_DET_CTL_L_DET_EN |
+		      CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION |
+		      CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO |
+		      CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN);
+
+	if (wcd->hphl_jack_type_normally_open)
+		plug_type |= CDC_A_HPHL_PLUG_TYPE_NO;
+
+	if (wcd->gnd_jack_type_normally_open)
+		plug_type |= CDC_A_GND_PLUG_TYPE_NO;
+
+	snd_soc_component_write(component, CDC_A_MBHC_DET_CTL_2,
+		      CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 |
+		      CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD |
+		      plug_type |
+		      CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN);
+
+
+	snd_soc_component_write(component, CDC_A_MBHC_DBNC_TIMER,
+		      CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS |
+		      CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS);
+
+	/* enable MBHC clock */
+	snd_soc_component_update_bits(component, CDC_D_CDC_DIG_CLK_CTL,
+			    DIG_CLK_CTL_D_MBHC_CLK_EN_MASK,
+			    DIG_CLK_CTL_D_MBHC_CLK_EN);
+
+	if (snd_soc_component_read32(component, CDC_A_MICB_2_EN) & CDC_A_MICB_2_EN_ENABLE)
+		micbias_enabled = true;
+
+	pm8916_mbhc_configure_bias(wcd, micbias_enabled);
+
+	int_en_mask = MBHC_SWITCH_INT;
+	if (wcd->mbhc_btn_enabled)
+		int_en_mask |= MBHC_BUTTON_PRESS_DET | MBHC_BUTTON_RELEASE_DET;
+
+	snd_soc_component_update_bits(component, CDC_D_INT_EN_CLR, int_en_mask, 0);
+	snd_soc_component_update_bits(component, CDC_D_INT_EN_SET, int_en_mask, int_en_mask);
+	wcd->mbhc_btn0_released = false;
+	wcd->detect_accessory_type = true;
+}
+
+static int pm8916_wcd_analog_enable_micbias_int2(struct
+						  snd_soc_dapm_widget
+						  *w, struct snd_kcontrol
+						  *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		pm8916_mbhc_configure_bias(wcd, true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		pm8916_mbhc_configure_bias(wcd, false);
+		break;
+	}
+
+	return pm8916_wcd_analog_enable_micbias_int(component, event, w->reg,
+						     wcd->micbias2_cap_mode);
+}
+
+static int pm8916_wcd_analog_enable_adc(struct snd_soc_dapm_widget *w,
+					 struct snd_kcontrol *kcontrol,
+					 int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 adc_reg = CDC_A_TX_1_2_TEST_CTL_2;
+	u8 init_bit_shift;
+
+	if (w->reg == CDC_A_TX_1_EN)
+		init_bit_shift = 5;
+	else
+		init_bit_shift = 4;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (w->reg == CDC_A_TX_2_EN)
+			snd_soc_component_update_bits(component, CDC_A_MICB_1_CTL,
+					    MICB_1_CTL_CFILT_REF_SEL_MASK,
+					    MICB_1_CTL_CFILT_REF_SEL_HPF_REF);
+		/*
+		 * Add delay of 10 ms to give sufficient time for the voltage
+		 * to shoot up and settle so that the txfe init does not
+		 * happen when the input voltage is changing too much.
+		 */
+		usleep_range(10000, 10010);
+		snd_soc_component_update_bits(component, adc_reg, 1 << init_bit_shift,
+				    1 << init_bit_shift);
+		switch (w->reg) {
+		case CDC_A_TX_1_EN:
+			snd_soc_component_update_bits(component, CDC_D_CDC_CONN_TX1_CTL,
+					    CONN_TX1_SERIAL_TX1_MUX,
+					    CONN_TX1_SERIAL_TX1_ADC_1);
+			break;
+		case CDC_A_TX_2_EN:
+		case CDC_A_TX_3_EN:
+			snd_soc_component_update_bits(component, CDC_D_CDC_CONN_TX2_CTL,
+					    CONN_TX2_SERIAL_TX2_MUX,
+					    CONN_TX2_SERIAL_TX2_ADC_2);
+			break;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/*
+		 * Add delay of 12 ms before deasserting the init
+		 * to reduce the tx pop
+		 */
+		usleep_range(12000, 12010);
+		snd_soc_component_update_bits(component, adc_reg, 1 << init_bit_shift, 0x00);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		switch (w->reg) {
+		case CDC_A_TX_1_EN:
+			snd_soc_component_update_bits(component, CDC_D_CDC_CONN_TX1_CTL,
+					    CONN_TX1_SERIAL_TX1_MUX,
+					    CONN_TX1_SERIAL_TX1_ZERO);
+			break;
+		case CDC_A_TX_2_EN:
+			snd_soc_component_update_bits(component, CDC_A_MICB_1_CTL,
+					    MICB_1_CTL_CFILT_REF_SEL_MASK, 0);
+			/* fall through */
+		case CDC_A_TX_3_EN:
+			snd_soc_component_update_bits(component, CDC_D_CDC_CONN_TX2_CTL,
+					    CONN_TX2_SERIAL_TX2_MUX,
+					    CONN_TX2_SERIAL_TX2_ZERO);
+			break;
+		}
+
+
+		break;
+	}
+	return 0;
+}
+
+static int pm8916_wcd_analog_enable_spk_pa(struct snd_soc_dapm_widget *w,
+					    struct snd_kcontrol *kcontrol,
+					    int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component, CDC_A_SPKR_PWRSTG_CTL,
+				    SPKR_PWRSTG_CTL_DAC_EN_MASK |
+				    SPKR_PWRSTG_CTL_BBM_MASK |
+				    SPKR_PWRSTG_CTL_HBRDGE_EN_MASK |
+				    SPKR_PWRSTG_CTL_CLAMP_EN_MASK,
+				    SPKR_PWRSTG_CTL_DAC_EN|
+				    SPKR_PWRSTG_CTL_BBM_EN |
+				    SPKR_PWRSTG_CTL_HBRDGE_EN |
+				    SPKR_PWRSTG_CTL_CLAMP_EN);
+
+		snd_soc_component_update_bits(component, CDC_A_RX_EAR_CTL,
+				    RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK,
+				    RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, CDC_A_SPKR_DRV_CTL,
+				    SPKR_DRV_CTL_DEF_MASK,
+				    SPKR_DRV_CTL_DEF_VAL);
+		snd_soc_component_update_bits(component, w->reg,
+				    SPKR_DRV_CLASSD_PA_EN_MASK,
+				    SPKR_DRV_CLASSD_PA_EN_ENABLE);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, CDC_A_SPKR_PWRSTG_CTL,
+				    SPKR_PWRSTG_CTL_DAC_EN_MASK|
+				    SPKR_PWRSTG_CTL_BBM_MASK |
+				    SPKR_PWRSTG_CTL_HBRDGE_EN_MASK |
+				    SPKR_PWRSTG_CTL_CLAMP_EN_MASK, 0);
+
+		snd_soc_component_update_bits(component, CDC_A_SPKR_DAC_CTL,
+				    SPKR_DAC_CTL_DAC_RESET_MASK,
+				    SPKR_DAC_CTL_DAC_RESET_NORMAL);
+		snd_soc_component_update_bits(component, CDC_A_RX_EAR_CTL,
+				    RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK, 0);
+		break;
+	}
+	return 0;
+}
+
+static const struct reg_default wcd_reg_defaults_2_0[] = {
+	{CDC_A_RX_COM_OCP_CTL, 0xD1},
+	{CDC_A_RX_COM_OCP_COUNT, 0xFF},
+	{CDC_D_SEC_ACCESS, 0xA5},
+	{CDC_D_PERPH_RESET_CTL3, 0x0F},
+	{CDC_A_TX_1_2_OPAMP_BIAS, 0x4F},
+	{CDC_A_NCP_FBCTRL, 0x28},
+	{CDC_A_SPKR_DRV_CTL, 0x69},
+	{CDC_A_SPKR_DRV_DBG, 0x01},
+	{CDC_A_BOOST_EN_CTL, 0x5F},
+	{CDC_A_SLOPE_COMP_IP_ZERO, 0x88},
+	{CDC_A_SEC_ACCESS, 0xA5},
+	{CDC_A_PERPH_RESET_CTL3, 0x0F},
+	{CDC_A_CURRENT_LIMIT, 0x82},
+	{CDC_A_SPKR_DAC_CTL, 0x03},
+	{CDC_A_SPKR_OCP_CTL, 0xE1},
+	{CDC_A_MASTER_BIAS_CTL, 0x30},
+};
+
+static int pm8916_wcd_analog_probe(struct snd_soc_component *component)
+{
+	struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev);
+	int err, reg;
+
+	err = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
+	if (err != 0) {
+		dev_err(component->dev, "failed to enable regulators (%d)\n", err);
+		return err;
+	}
+
+	snd_soc_component_init_regmap(component,
+				  dev_get_regmap(component->dev->parent, NULL));
+	snd_soc_component_set_drvdata(component, priv);
+	priv->pmic_rev = snd_soc_component_read32(component, CDC_D_REVISION1);
+	priv->codec_version = snd_soc_component_read32(component, CDC_D_PERPH_SUBTYPE);
+
+	dev_info(component->dev, "PMIC REV: %d\t CODEC Version: %d\n",
+		 priv->pmic_rev, priv->codec_version);
+
+	snd_soc_component_write(component, CDC_D_PERPH_RESET_CTL4, 0x01);
+	snd_soc_component_write(component, CDC_A_PERPH_RESET_CTL4, 0x01);
+
+	for (reg = 0; reg < ARRAY_SIZE(wcd_reg_defaults_2_0); reg++)
+		snd_soc_component_write(component, wcd_reg_defaults_2_0[reg].reg,
+			      wcd_reg_defaults_2_0[reg].def);
+
+	priv->component = component;
+
+	snd_soc_component_update_bits(component, CDC_D_CDC_RST_CTL,
+			    RST_CTL_DIG_SW_RST_N_MASK,
+			    RST_CTL_DIG_SW_RST_N_REMOVE_RESET);
+
+	pm8916_wcd_setup_mbhc(priv);
+
+	return 0;
+}
+
+static void pm8916_wcd_analog_remove(struct snd_soc_component *component)
+{
+	struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev);
+
+	snd_soc_component_update_bits(component, CDC_D_CDC_RST_CTL,
+			    RST_CTL_DIG_SW_RST_N_MASK, 0);
+
+	regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
+				      priv->supplies);
+}
+
+static const struct snd_soc_dapm_route pm8916_wcd_analog_audio_map[] = {
+
+	{"PDM_RX1", NULL, "PDM Playback"},
+	{"PDM_RX2", NULL, "PDM Playback"},
+	{"PDM_RX3", NULL, "PDM Playback"},
+	{"PDM Capture", NULL, "PDM_TX"},
+
+	/* ADC Connections */
+	{"PDM_TX", NULL, "ADC2"},
+	{"PDM_TX", NULL, "ADC3"},
+	{"ADC2", NULL, "ADC2 MUX"},
+	{"ADC3", NULL, "ADC2 MUX"},
+	{"ADC2 MUX", "INP2", "ADC2_INP2"},
+	{"ADC2 MUX", "INP3", "ADC2_INP3"},
+
+	{"PDM_TX", NULL, "ADC1"},
+	{"ADC1", NULL, "AMIC1"},
+	{"ADC2_INP2", NULL, "AMIC2"},
+	{"ADC2_INP3", NULL, "AMIC3"},
+
+	/* RDAC Connections */
+	{"HPHR DAC", NULL, "RDAC2 MUX"},
+	{"RDAC2 MUX", "RX1", "PDM_RX1"},
+	{"RDAC2 MUX", "RX2", "PDM_RX2"},
+	{"HPHL DAC", NULL, "PDM_RX1"},
+	{"PDM_RX1", NULL, "RXD1_CLK"},
+	{"PDM_RX2", NULL, "RXD2_CLK"},
+	{"PDM_RX3", NULL, "RXD3_CLK"},
+
+	{"PDM_RX1", NULL, "RXD_PDM_CLK"},
+	{"PDM_RX2", NULL, "RXD_PDM_CLK"},
+	{"PDM_RX3", NULL, "RXD_PDM_CLK"},
+
+	{"ADC1", NULL, "TXD_CLK"},
+	{"ADC2", NULL, "TXD_CLK"},
+	{"ADC3", NULL, "TXD_CLK"},
+
+	{"ADC1", NULL, "TXA_CLK25"},
+	{"ADC2", NULL, "TXA_CLK25"},
+	{"ADC3", NULL, "TXA_CLK25"},
+
+	{"PDM_RX1", NULL, "A_MCLK2"},
+	{"PDM_RX2", NULL, "A_MCLK2"},
+	{"PDM_RX3", NULL, "A_MCLK2"},
+
+	{"PDM_TX", NULL, "A_MCLK2"},
+	{"A_MCLK2", NULL, "A_MCLK"},
+
+	/* Headset (RX MIX1 and RX MIX2) */
+	{"HEADPHONE", NULL, "HPHL PA"},
+	{"HEADPHONE", NULL, "HPHR PA"},
+
+	{"HPHL PA", NULL, "EAR_HPHL_CLK"},
+	{"HPHR PA", NULL, "EAR_HPHR_CLK"},
+
+	{"CP", NULL, "NCP_CLK"},
+
+	{"HPHL PA", NULL, "HPHL"},
+	{"HPHR PA", NULL, "HPHR"},
+	{"HPHL PA", NULL, "CP"},
+	{"HPHL PA", NULL, "RX_BIAS"},
+	{"HPHR PA", NULL, "CP"},
+	{"HPHR PA", NULL, "RX_BIAS"},
+	{"HPHL", "Switch", "HPHL DAC"},
+	{"HPHR", "Switch", "HPHR DAC"},
+
+	{"RX_BIAS", NULL, "DAC_REF"},
+
+	{"SPK_OUT", NULL, "SPK PA"},
+	{"SPK PA", NULL, "RX_BIAS"},
+	{"SPK PA", NULL, "SPKR_CLK"},
+	{"SPK PA", NULL, "SPK DAC"},
+	{"SPK DAC", "Switch", "PDM_RX3"},
+
+	{"MIC BIAS Internal1", NULL, "INT_LDO_H"},
+	{"MIC BIAS Internal2", NULL, "INT_LDO_H"},
+	{"MIC BIAS External1", NULL, "INT_LDO_H"},
+	{"MIC BIAS External2", NULL, "INT_LDO_H"},
+	{"MIC BIAS Internal1", NULL, "vdd-micbias"},
+	{"MIC BIAS Internal2", NULL, "vdd-micbias"},
+	{"MIC BIAS External1", NULL, "vdd-micbias"},
+	{"MIC BIAS External2", NULL, "vdd-micbias"},
+};
+
+static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = {
+
+	SND_SOC_DAPM_AIF_IN("PDM_RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PDM_RX2", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PDM_RX3", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("PDM_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_INPUT("AMIC3"),
+	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+
+	/* RX stuff */
+	SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, &hphl_mux),
+	SND_SOC_DAPM_MIXER("HPHL DAC", CDC_A_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL,
+			   0),
+	SND_SOC_DAPM_PGA("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, &hphr_mux),
+	SND_SOC_DAPM_MIXER("HPHR DAC", CDC_A_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL,
+			   0),
+	SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0,
+			   spkr_switch, ARRAY_SIZE(spkr_switch)),
+
+	/* Speaker */
+	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+	SND_SOC_DAPM_PGA_E("SPK PA", CDC_A_SPKR_DRV_CTL,
+			   6, 0, NULL, 0,
+			   pm8916_wcd_analog_enable_spk_pa,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-micbias", 0, 0),
+	SND_SOC_DAPM_SUPPLY("CP", CDC_A_NCP_EN, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DAC_REF", CDC_A_RX_COM_BIAS_DAC, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RX_BIAS", CDC_A_RX_COM_BIAS_DAC, 7, 0, NULL, 0),
+
+	/* TX */
+	SND_SOC_DAPM_SUPPLY("MIC BIAS Internal1", CDC_A_MICB_1_EN, 7, 0,
+			    pm8916_wcd_analog_enable_micbias_int1,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("MIC BIAS Internal2", CDC_A_MICB_2_EN, 7, 0,
+			    pm8916_wcd_analog_enable_micbias_int2,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			    SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY("MIC BIAS External1", CDC_A_MICB_1_EN, 7, 0,
+			    pm8916_wcd_analog_enable_micbias_ext1,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("MIC BIAS External2", CDC_A_MICB_2_EN, 7, 0,
+			    pm8916_wcd_analog_enable_micbias_ext2,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, CDC_A_TX_1_EN, 7, 0,
+			   pm8916_wcd_analog_enable_adc,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2_INP2", NULL, CDC_A_TX_2_EN, 7, 0,
+			   pm8916_wcd_analog_enable_adc,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2_INP3", NULL, CDC_A_TX_3_EN, 7, 0,
+			   pm8916_wcd_analog_enable_adc,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux),
+	SND_SOC_DAPM_MUX("RDAC2 MUX", SND_SOC_NOPM, 0, 0, &rdac2_mux),
+
+	/* Analog path clocks */
+	SND_SOC_DAPM_SUPPLY("EAR_HPHR_CLK", CDC_D_CDC_ANA_CLK_CTL, 0, 0, NULL,
+			    0),
+	SND_SOC_DAPM_SUPPLY("EAR_HPHL_CLK", CDC_D_CDC_ANA_CLK_CTL, 1, 0, NULL,
+			    0),
+	SND_SOC_DAPM_SUPPLY("SPKR_CLK", CDC_D_CDC_ANA_CLK_CTL, 4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("TXA_CLK25", CDC_D_CDC_ANA_CLK_CTL, 5, 0, NULL, 0),
+
+	/* Digital path clocks */
+
+	SND_SOC_DAPM_SUPPLY("RXD1_CLK", CDC_D_CDC_DIG_CLK_CTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RXD2_CLK", CDC_D_CDC_DIG_CLK_CTL, 1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RXD3_CLK", CDC_D_CDC_DIG_CLK_CTL, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("TXD_CLK", CDC_D_CDC_DIG_CLK_CTL, 4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("NCP_CLK", CDC_D_CDC_DIG_CLK_CTL, 6, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RXD_PDM_CLK", CDC_D_CDC_DIG_CLK_CTL, 7, 0, NULL,
+			    0),
+
+	/* System Clock source */
+	SND_SOC_DAPM_SUPPLY("A_MCLK", CDC_D_CDC_TOP_CLK_CTL, 2, 0, NULL, 0),
+	/* TX ADC and RX DAC Clock source. */
+	SND_SOC_DAPM_SUPPLY("A_MCLK2", CDC_D_CDC_TOP_CLK_CTL, 3, 0, NULL, 0),
+};
+
+static int pm8916_wcd_analog_set_jack(struct snd_soc_component *component,
+				      struct snd_soc_jack *jack,
+				      void *data)
+{
+	struct pm8916_wcd_analog_priv *wcd = snd_soc_component_get_drvdata(component);
+
+	wcd->jack = jack;
+
+	return 0;
+}
+
+static irqreturn_t mbhc_btn_release_irq_handler(int irq, void *arg)
+{
+	struct pm8916_wcd_analog_priv *priv = arg;
+
+	if (priv->detect_accessory_type) {
+		struct snd_soc_component *component = priv->component;
+		u32 val = snd_soc_component_read32(component, CDC_A_MBHC_RESULT_1);
+
+		/* check if its BTN0 thats released */
+		if ((val != -1) && !(val & CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK))
+			priv->mbhc_btn0_released = true;
+
+	} else {
+		snd_soc_jack_report(priv->jack, 0, btn_mask);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mbhc_btn_press_irq_handler(int irq, void *arg)
+{
+	struct pm8916_wcd_analog_priv *priv = arg;
+	struct snd_soc_component *component = priv->component;
+	u32 btn_result;
+
+	btn_result = snd_soc_component_read32(component, CDC_A_MBHC_RESULT_1) &
+				  CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK;
+
+	switch (btn_result) {
+	case 0xf:
+		snd_soc_jack_report(priv->jack, SND_JACK_BTN_4, btn_mask);
+		break;
+	case 0x7:
+		snd_soc_jack_report(priv->jack, SND_JACK_BTN_3, btn_mask);
+		break;
+	case 0x3:
+		snd_soc_jack_report(priv->jack, SND_JACK_BTN_2, btn_mask);
+		break;
+	case 0x1:
+		snd_soc_jack_report(priv->jack, SND_JACK_BTN_1, btn_mask);
+		break;
+	case 0x0:
+		/* handle BTN_0 specially for type detection */
+		if (!priv->detect_accessory_type)
+			snd_soc_jack_report(priv->jack,
+					    SND_JACK_BTN_0, btn_mask);
+		break;
+	default:
+		dev_err(component->dev,
+			"Unexpected button press result (%x)", btn_result);
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t pm8916_mbhc_switch_irq_handler(int irq, void *arg)
+{
+	struct pm8916_wcd_analog_priv *priv = arg;
+	struct snd_soc_component *component = priv->component;
+	bool ins = false;
+
+	if (snd_soc_component_read32(component, CDC_A_MBHC_DET_CTL_1) &
+				CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK)
+		ins = true;
+
+	/* Set the detection type appropriately */
+	snd_soc_component_update_bits(component, CDC_A_MBHC_DET_CTL_1,
+			    CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK,
+			    (!ins << CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT));
+
+
+	if (ins) { /* hs insertion */
+		bool micbias_enabled = false;
+
+		if (snd_soc_component_read32(component, CDC_A_MICB_2_EN) &
+				CDC_A_MICB_2_EN_ENABLE)
+			micbias_enabled = true;
+
+		pm8916_mbhc_configure_bias(priv, micbias_enabled);
+
+		/*
+		 * if only a btn0 press event is receive just before
+		 * insert event then its a 3 pole headphone else if
+		 * both press and release event received then its
+		 * a headset.
+		 */
+		if (priv->mbhc_btn0_released)
+			snd_soc_jack_report(priv->jack,
+					    SND_JACK_HEADSET, hs_jack_mask);
+		else
+			snd_soc_jack_report(priv->jack,
+					    SND_JACK_HEADPHONE, hs_jack_mask);
+
+		priv->detect_accessory_type = false;
+
+	} else { /* removal */
+		snd_soc_jack_report(priv->jack, 0, hs_jack_mask);
+		priv->detect_accessory_type = true;
+		priv->mbhc_btn0_released = false;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
+	[0] = {
+	       .name = "pm8916_wcd_analog_pdm_rx",
+	       .id = 0,
+	       .playback = {
+			    .stream_name = "PDM Playback",
+			    .rates = MSM8916_WCD_ANALOG_RATES,
+			    .formats = MSM8916_WCD_ANALOG_FORMATS,
+			    .channels_min = 1,
+			    .channels_max = 3,
+			    },
+	       },
+	[1] = {
+	       .name = "pm8916_wcd_analog_pdm_tx",
+	       .id = 1,
+	       .capture = {
+			   .stream_name = "PDM Capture",
+			   .rates = MSM8916_WCD_ANALOG_RATES,
+			   .formats = MSM8916_WCD_ANALOG_FORMATS,
+			   .channels_min = 1,
+			   .channels_max = 4,
+			   },
+	       },
+};
+
+static const struct snd_soc_component_driver pm8916_wcd_analog = {
+	.probe			= pm8916_wcd_analog_probe,
+	.remove			= pm8916_wcd_analog_remove,
+	.set_jack		= pm8916_wcd_analog_set_jack,
+	.controls		= pm8916_wcd_analog_snd_controls,
+	.num_controls		= ARRAY_SIZE(pm8916_wcd_analog_snd_controls),
+	.dapm_widgets		= pm8916_wcd_analog_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pm8916_wcd_analog_dapm_widgets),
+	.dapm_routes		= pm8916_wcd_analog_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(pm8916_wcd_analog_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int pm8916_wcd_analog_parse_dt(struct device *dev,
+				       struct pm8916_wcd_analog_priv *priv)
+{
+	int rval;
+
+	if (of_property_read_bool(dev->of_node, "qcom,micbias1-ext-cap"))
+		priv->micbias1_cap_mode = MICB_1_EN_EXT_BYP_CAP;
+	else
+		priv->micbias1_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP;
+
+	if (of_property_read_bool(dev->of_node, "qcom,micbias2-ext-cap"))
+		priv->micbias2_cap_mode = MICB_1_EN_EXT_BYP_CAP;
+	else
+		priv->micbias2_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP;
+
+	of_property_read_u32(dev->of_node, "qcom,micbias-lvl",
+			     &priv->micbias_mv);
+
+	if (of_property_read_bool(dev->of_node,
+				  "qcom,hphl-jack-type-normally-open"))
+		priv->hphl_jack_type_normally_open = true;
+	else
+		priv->hphl_jack_type_normally_open = false;
+
+	if (of_property_read_bool(dev->of_node,
+				  "qcom,gnd-jack-type-normally-open"))
+		priv->gnd_jack_type_normally_open = true;
+	else
+		priv->gnd_jack_type_normally_open = false;
+
+	priv->mbhc_btn_enabled = true;
+	rval = of_property_read_u32_array(dev->of_node,
+					  "qcom,mbhc-vthreshold-low",
+					  &priv->vref_btn_cs[0],
+					  MBHC_MAX_BUTTONS);
+	if (rval < 0) {
+		priv->mbhc_btn_enabled = false;
+	} else {
+		rval = of_property_read_u32_array(dev->of_node,
+						  "qcom,mbhc-vthreshold-high",
+						  &priv->vref_btn_micb[0],
+						  MBHC_MAX_BUTTONS);
+		if (rval < 0)
+			priv->mbhc_btn_enabled = false;
+	}
+
+	if (!priv->mbhc_btn_enabled)
+		dev_err(dev,
+			"DT property missing, MBHC btn detection disabled\n");
+
+
+	return 0;
+}
+
+static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
+{
+	struct pm8916_wcd_analog_priv *priv;
+	struct device *dev = &pdev->dev;
+	int ret, i, irq;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	ret = pm8916_wcd_analog_parse_dt(dev, priv);
+	if (ret < 0)
+		return ret;
+
+	priv->mclk = devm_clk_get(dev, "mclk");
+	if (IS_ERR(priv->mclk)) {
+		dev_err(dev, "failed to get mclk\n");
+		return PTR_ERR(priv->mclk);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+		priv->supplies[i].supply = supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
+				    priv->supplies);
+	if (ret) {
+		dev_err(dev, "Failed to get regulator supplies %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(priv->mclk);
+	if (ret < 0) {
+		dev_err(dev, "failed to enable mclk %d\n", ret);
+		return ret;
+	}
+
+	irq = platform_get_irq_byname(pdev, "mbhc_switch_int");
+	if (irq < 0) {
+		dev_err(dev, "failed to get mbhc switch irq\n");
+		return irq;
+	}
+
+	ret = devm_request_threaded_irq(dev, irq, NULL,
+			       pm8916_mbhc_switch_irq_handler,
+			       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+			       IRQF_ONESHOT,
+			       "mbhc switch irq", priv);
+	if (ret)
+		dev_err(dev, "cannot request mbhc switch irq\n");
+
+	if (priv->mbhc_btn_enabled) {
+		irq = platform_get_irq_byname(pdev, "mbhc_but_press_det");
+		if (irq < 0) {
+			dev_err(dev, "failed to get button press irq\n");
+			return irq;
+		}
+
+		ret = devm_request_threaded_irq(dev, irq, NULL,
+				       mbhc_btn_press_irq_handler,
+				       IRQF_TRIGGER_RISING |
+				       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				       "mbhc btn press irq", priv);
+		if (ret)
+			dev_err(dev, "cannot request mbhc button press irq\n");
+
+		irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det");
+		if (irq < 0) {
+			dev_err(dev, "failed to get button release irq\n");
+			return irq;
+		}
+
+		ret = devm_request_threaded_irq(dev, irq, NULL,
+				       mbhc_btn_release_irq_handler,
+				       IRQF_TRIGGER_RISING |
+				       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				       "mbhc btn release irq", priv);
+		if (ret)
+			dev_err(dev, "cannot request mbhc button release irq\n");
+
+	}
+
+	dev_set_drvdata(dev, priv);
+
+	return devm_snd_soc_register_component(dev, &pm8916_wcd_analog,
+				      pm8916_wcd_analog_dai,
+				      ARRAY_SIZE(pm8916_wcd_analog_dai));
+}
+
+static int pm8916_wcd_analog_spmi_remove(struct platform_device *pdev)
+{
+	struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(&pdev->dev);
+
+	clk_disable_unprepare(priv->mclk);
+
+	return 0;
+}
+
+static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = {
+	{ .compatible = "qcom,pm8916-wcd-analog-codec", },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, pm8916_wcd_analog_spmi_match_table);
+
+static struct platform_driver pm8916_wcd_analog_spmi_driver = {
+	.driver = {
+		   .name = "qcom,pm8916-wcd-spmi-codec",
+		   .of_match_table = pm8916_wcd_analog_spmi_match_table,
+	},
+	.probe = pm8916_wcd_analog_spmi_probe,
+	.remove = pm8916_wcd_analog_spmi_remove,
+};
+
+module_platform_driver(pm8916_wcd_analog_spmi_driver);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");
+MODULE_DESCRIPTION("PMIC PM8916 WCD Analog Codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c
new file mode 100644
index 0000000..3063ded
--- /dev/null
+++ b/sound/soc/codecs/msm8916-wcd-digital.c
@@ -0,0 +1,955 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#define LPASS_CDC_CLK_RX_RESET_CTL		(0x000)
+#define LPASS_CDC_CLK_TX_RESET_B1_CTL		(0x004)
+#define CLK_RX_RESET_B1_CTL_TX1_RESET_MASK	BIT(0)
+#define CLK_RX_RESET_B1_CTL_TX2_RESET_MASK	BIT(1)
+#define LPASS_CDC_CLK_DMIC_B1_CTL		(0x008)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_MASK		GENMASK(3, 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV2		(0x0 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3		(0x1 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV4		(0x2 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV6		(0x3 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV16		(0x4 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_EN_MASK		BIT(0)
+#define DMIC_B1_CTL_DMIC0_CLK_EN_ENABLE		BIT(0)
+
+#define LPASS_CDC_CLK_RX_I2S_CTL		(0x00C)
+#define RX_I2S_CTL_RX_I2S_MODE_MASK		BIT(5)
+#define RX_I2S_CTL_RX_I2S_MODE_16		BIT(5)
+#define RX_I2S_CTL_RX_I2S_MODE_32		0
+#define RX_I2S_CTL_RX_I2S_FS_RATE_MASK		GENMASK(2, 0)
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ	0x0
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ	0x1
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ	0x2
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ	0x3
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_96_KHZ	0x4
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_192_KHZ	0x5
+#define LPASS_CDC_CLK_TX_I2S_CTL		(0x010)
+#define TX_I2S_CTL_TX_I2S_MODE_MASK		BIT(5)
+#define TX_I2S_CTL_TX_I2S_MODE_16		BIT(5)
+#define TX_I2S_CTL_TX_I2S_MODE_32		0
+#define TX_I2S_CTL_TX_I2S_FS_RATE_MASK		GENMASK(2, 0)
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ	0x0
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ	0x1
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ	0x2
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ	0x3
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_96_KHZ	0x4
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_192_KHZ	0x5
+
+#define LPASS_CDC_CLK_OTHR_RESET_B1_CTL		(0x014)
+#define LPASS_CDC_CLK_TX_CLK_EN_B1_CTL		(0x018)
+#define LPASS_CDC_CLK_OTHR_CTL			(0x01C)
+#define LPASS_CDC_CLK_RX_B1_CTL			(0x020)
+#define LPASS_CDC_CLK_MCLK_CTL			(0x024)
+#define MCLK_CTL_MCLK_EN_MASK			BIT(0)
+#define MCLK_CTL_MCLK_EN_ENABLE			BIT(0)
+#define MCLK_CTL_MCLK_EN_DISABLE		0
+#define LPASS_CDC_CLK_PDM_CTL			(0x028)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_EN_MASK	BIT(0)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_EN		BIT(0)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK	BIT(1)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB	BIT(1)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_PDM_CLK	0
+
+#define LPASS_CDC_CLK_SD_CTL			(0x02C)
+#define LPASS_CDC_RX1_B1_CTL			(0x040)
+#define LPASS_CDC_RX2_B1_CTL			(0x060)
+#define LPASS_CDC_RX3_B1_CTL			(0x080)
+#define LPASS_CDC_RX1_B2_CTL			(0x044)
+#define LPASS_CDC_RX2_B2_CTL			(0x064)
+#define LPASS_CDC_RX3_B2_CTL			(0x084)
+#define LPASS_CDC_RX1_B3_CTL			(0x048)
+#define LPASS_CDC_RX2_B3_CTL			(0x068)
+#define LPASS_CDC_RX3_B3_CTL			(0x088)
+#define LPASS_CDC_RX1_B4_CTL			(0x04C)
+#define LPASS_CDC_RX2_B4_CTL			(0x06C)
+#define LPASS_CDC_RX3_B4_CTL			(0x08C)
+#define LPASS_CDC_RX1_B5_CTL			(0x050)
+#define LPASS_CDC_RX2_B5_CTL			(0x070)
+#define LPASS_CDC_RX3_B5_CTL			(0x090)
+#define LPASS_CDC_RX1_B6_CTL			(0x054)
+#define RXn_B6_CTL_MUTE_MASK			BIT(0)
+#define RXn_B6_CTL_MUTE_ENABLE			BIT(0)
+#define RXn_B6_CTL_MUTE_DISABLE			0
+#define LPASS_CDC_RX2_B6_CTL			(0x074)
+#define LPASS_CDC_RX3_B6_CTL			(0x094)
+#define LPASS_CDC_RX1_VOL_CTL_B1_CTL		(0x058)
+#define LPASS_CDC_RX2_VOL_CTL_B1_CTL		(0x078)
+#define LPASS_CDC_RX3_VOL_CTL_B1_CTL		(0x098)
+#define LPASS_CDC_RX1_VOL_CTL_B2_CTL		(0x05C)
+#define LPASS_CDC_RX2_VOL_CTL_B2_CTL		(0x07C)
+#define LPASS_CDC_RX3_VOL_CTL_B2_CTL		(0x09C)
+#define LPASS_CDC_TOP_GAIN_UPDATE		(0x0A0)
+#define LPASS_CDC_TOP_CTL			(0x0A4)
+#define TOP_CTL_DIG_MCLK_FREQ_MASK		BIT(0)
+#define TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ	0
+#define TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ		BIT(0)
+
+#define LPASS_CDC_DEBUG_DESER1_CTL		(0x0E0)
+#define LPASS_CDC_DEBUG_DESER2_CTL		(0x0E4)
+#define LPASS_CDC_DEBUG_B1_CTL_CFG		(0x0E8)
+#define LPASS_CDC_DEBUG_B2_CTL_CFG		(0x0EC)
+#define LPASS_CDC_DEBUG_B3_CTL_CFG		(0x0F0)
+#define LPASS_CDC_IIR1_GAIN_B1_CTL		(0x100)
+#define LPASS_CDC_IIR2_GAIN_B1_CTL		(0x140)
+#define LPASS_CDC_IIR1_GAIN_B2_CTL		(0x104)
+#define LPASS_CDC_IIR2_GAIN_B2_CTL		(0x144)
+#define LPASS_CDC_IIR1_GAIN_B3_CTL		(0x108)
+#define LPASS_CDC_IIR2_GAIN_B3_CTL		(0x148)
+#define LPASS_CDC_IIR1_GAIN_B4_CTL		(0x10C)
+#define LPASS_CDC_IIR2_GAIN_B4_CTL		(0x14C)
+#define LPASS_CDC_IIR1_GAIN_B5_CTL		(0x110)
+#define LPASS_CDC_IIR2_GAIN_B5_CTL		(0x150)
+#define LPASS_CDC_IIR1_GAIN_B6_CTL		(0x114)
+#define LPASS_CDC_IIR2_GAIN_B6_CTL		(0x154)
+#define LPASS_CDC_IIR1_GAIN_B7_CTL		(0x118)
+#define LPASS_CDC_IIR2_GAIN_B7_CTL		(0x158)
+#define LPASS_CDC_IIR1_GAIN_B8_CTL		(0x11C)
+#define LPASS_CDC_IIR2_GAIN_B8_CTL		(0x15C)
+#define LPASS_CDC_IIR1_CTL			(0x120)
+#define LPASS_CDC_IIR2_CTL			(0x160)
+#define LPASS_CDC_IIR1_GAIN_TIMER_CTL		(0x124)
+#define LPASS_CDC_IIR2_GAIN_TIMER_CTL		(0x164)
+#define LPASS_CDC_IIR1_COEF_B1_CTL		(0x128)
+#define LPASS_CDC_IIR2_COEF_B1_CTL		(0x168)
+#define LPASS_CDC_IIR1_COEF_B2_CTL		(0x12C)
+#define LPASS_CDC_IIR2_COEF_B2_CTL		(0x16C)
+#define LPASS_CDC_CONN_RX1_B1_CTL		(0x180)
+#define LPASS_CDC_CONN_RX1_B2_CTL		(0x184)
+#define LPASS_CDC_CONN_RX1_B3_CTL		(0x188)
+#define LPASS_CDC_CONN_RX2_B1_CTL		(0x18C)
+#define LPASS_CDC_CONN_RX2_B2_CTL		(0x190)
+#define LPASS_CDC_CONN_RX2_B3_CTL		(0x194)
+#define LPASS_CDC_CONN_RX3_B1_CTL		(0x198)
+#define LPASS_CDC_CONN_RX3_B2_CTL		(0x19C)
+#define LPASS_CDC_CONN_TX_B1_CTL		(0x1A0)
+#define LPASS_CDC_CONN_EQ1_B1_CTL		(0x1A8)
+#define LPASS_CDC_CONN_EQ1_B2_CTL		(0x1AC)
+#define LPASS_CDC_CONN_EQ1_B3_CTL		(0x1B0)
+#define LPASS_CDC_CONN_EQ1_B4_CTL		(0x1B4)
+#define LPASS_CDC_CONN_EQ2_B1_CTL		(0x1B8)
+#define LPASS_CDC_CONN_EQ2_B2_CTL		(0x1BC)
+#define LPASS_CDC_CONN_EQ2_B3_CTL		(0x1C0)
+#define LPASS_CDC_CONN_EQ2_B4_CTL		(0x1C4)
+#define LPASS_CDC_CONN_TX_I2S_SD1_CTL		(0x1C8)
+#define LPASS_CDC_TX1_VOL_CTL_TIMER		(0x280)
+#define LPASS_CDC_TX2_VOL_CTL_TIMER		(0x2A0)
+#define LPASS_CDC_TX1_VOL_CTL_GAIN		(0x284)
+#define LPASS_CDC_TX2_VOL_CTL_GAIN		(0x2A4)
+#define LPASS_CDC_TX1_VOL_CTL_CFG		(0x288)
+#define TX_VOL_CTL_CFG_MUTE_EN_MASK		BIT(0)
+#define TX_VOL_CTL_CFG_MUTE_EN_ENABLE		BIT(0)
+
+#define LPASS_CDC_TX2_VOL_CTL_CFG		(0x2A8)
+#define LPASS_CDC_TX1_MUX_CTL			(0x28C)
+#define TX_MUX_CTL_CUT_OFF_FREQ_MASK		GENMASK(5, 4)
+#define TX_MUX_CTL_CUT_OFF_FREQ_SHIFT		4
+#define TX_MUX_CTL_CF_NEG_3DB_4HZ		(0x0 << 4)
+#define TX_MUX_CTL_CF_NEG_3DB_75HZ		(0x1 << 4)
+#define TX_MUX_CTL_CF_NEG_3DB_150HZ		(0x2 << 4)
+#define TX_MUX_CTL_HPF_BP_SEL_MASK		BIT(3)
+#define TX_MUX_CTL_HPF_BP_SEL_BYPASS		BIT(3)
+#define TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS		0
+
+#define LPASS_CDC_TX2_MUX_CTL			(0x2AC)
+#define LPASS_CDC_TX1_CLK_FS_CTL		(0x290)
+#define LPASS_CDC_TX2_CLK_FS_CTL		(0x2B0)
+#define LPASS_CDC_TX1_DMIC_CTL			(0x294)
+#define LPASS_CDC_TX2_DMIC_CTL			(0x2B4)
+#define TXN_DMIC_CTL_CLK_SEL_MASK		GENMASK(2, 0)
+#define TXN_DMIC_CTL_CLK_SEL_DIV2		0x0
+#define TXN_DMIC_CTL_CLK_SEL_DIV3		0x1
+#define TXN_DMIC_CTL_CLK_SEL_DIV4		0x2
+#define TXN_DMIC_CTL_CLK_SEL_DIV6		0x3
+#define TXN_DMIC_CTL_CLK_SEL_DIV16		0x4
+
+#define MSM8916_WCD_DIGITAL_RATES (SNDRV_PCM_RATE_8000 | \
+				   SNDRV_PCM_RATE_16000 | \
+				   SNDRV_PCM_RATE_32000 | \
+				   SNDRV_PCM_RATE_48000)
+#define MSM8916_WCD_DIGITAL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+				     SNDRV_PCM_FMTBIT_S32_LE)
+
+struct msm8916_wcd_digital_priv {
+	struct clk *ahbclk, *mclk;
+};
+
+static const unsigned long rx_gain_reg[] = {
+	LPASS_CDC_RX1_VOL_CTL_B2_CTL,
+	LPASS_CDC_RX2_VOL_CTL_B2_CTL,
+	LPASS_CDC_RX3_VOL_CTL_B2_CTL,
+};
+
+static const unsigned long tx_gain_reg[] = {
+	LPASS_CDC_TX1_VOL_CTL_GAIN,
+	LPASS_CDC_TX2_VOL_CTL_GAIN,
+};
+
+static const char *const rx_mix1_text[] = {
+	"ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
+};
+
+static const char *const dec_mux_text[] = {
+	"ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2"
+};
+
+static const char *const cic_mux_text[] = { "AMIC", "DMIC" };
+static const char *const rx_mix2_text[] = { "ZERO", "IIR1", "IIR2" };
+static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
+
+/* RX1 MIX1 */
+static const struct soc_enum rx_mix1_inp_enum[] = {
+	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text),
+	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text),
+	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text),
+};
+
+/* RX1 MIX2 */
+static const struct soc_enum rx_mix2_inp1_chain_enum = SOC_ENUM_SINGLE(
+				LPASS_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text);
+
+/* RX2 MIX1 */
+static const struct soc_enum rx2_mix1_inp_enum[] = {
+	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text),
+	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text),
+	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B2_CTL, 0, 6, rx_mix1_text),
+};
+
+/* RX2 MIX2 */
+static const struct soc_enum rx2_mix2_inp1_chain_enum = SOC_ENUM_SINGLE(
+				LPASS_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text);
+
+/* RX3 MIX1 */
+static const struct soc_enum rx3_mix1_inp_enum[] = {
+	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text),
+	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text),
+	SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B2_CTL, 0, 6, rx_mix1_text),
+};
+
+/* DEC */
+static const struct soc_enum dec1_mux_enum = SOC_ENUM_SINGLE(
+				LPASS_CDC_CONN_TX_B1_CTL, 0, 6, dec_mux_text);
+static const struct soc_enum dec2_mux_enum = SOC_ENUM_SINGLE(
+				LPASS_CDC_CONN_TX_B1_CTL, 3, 6, dec_mux_text);
+
+/* CIC */
+static const struct soc_enum cic1_mux_enum = SOC_ENUM_SINGLE(
+				LPASS_CDC_TX1_MUX_CTL, 0, 2, cic_mux_text);
+static const struct soc_enum cic2_mux_enum = SOC_ENUM_SINGLE(
+				LPASS_CDC_TX2_MUX_CTL, 0, 2, cic_mux_text);
+
+/* RDAC2 MUX */
+static const struct snd_kcontrol_new dec1_mux = SOC_DAPM_ENUM(
+				"DEC1 MUX Mux", dec1_mux_enum);
+static const struct snd_kcontrol_new dec2_mux = SOC_DAPM_ENUM(
+				"DEC2 MUX Mux",	dec2_mux_enum);
+static const struct snd_kcontrol_new cic1_mux = SOC_DAPM_ENUM(
+				"CIC1 MUX Mux", cic1_mux_enum);
+static const struct snd_kcontrol_new cic2_mux = SOC_DAPM_ENUM(
+				"CIC2 MUX Mux",	cic2_mux_enum);
+static const struct snd_kcontrol_new rx_mix1_inp1_mux = SOC_DAPM_ENUM(
+				"RX1 MIX1 INP1 Mux", rx_mix1_inp_enum[0]);
+static const struct snd_kcontrol_new rx_mix1_inp2_mux = SOC_DAPM_ENUM(
+				"RX1 MIX1 INP2 Mux", rx_mix1_inp_enum[1]);
+static const struct snd_kcontrol_new rx_mix1_inp3_mux = SOC_DAPM_ENUM(
+				"RX1 MIX1 INP3 Mux", rx_mix1_inp_enum[2]);
+static const struct snd_kcontrol_new rx2_mix1_inp1_mux = SOC_DAPM_ENUM(
+				"RX2 MIX1 INP1 Mux", rx2_mix1_inp_enum[0]);
+static const struct snd_kcontrol_new rx2_mix1_inp2_mux = SOC_DAPM_ENUM(
+				"RX2 MIX1 INP2 Mux", rx2_mix1_inp_enum[1]);
+static const struct snd_kcontrol_new rx2_mix1_inp3_mux = SOC_DAPM_ENUM(
+				"RX2 MIX1 INP3 Mux", rx2_mix1_inp_enum[2]);
+static const struct snd_kcontrol_new rx3_mix1_inp1_mux = SOC_DAPM_ENUM(
+				"RX3 MIX1 INP1 Mux", rx3_mix1_inp_enum[0]);
+static const struct snd_kcontrol_new rx3_mix1_inp2_mux = SOC_DAPM_ENUM(
+				"RX3 MIX1 INP2 Mux", rx3_mix1_inp_enum[1]);
+static const struct snd_kcontrol_new rx3_mix1_inp3_mux = SOC_DAPM_ENUM(
+				"RX3 MIX1 INP3 Mux", rx3_mix1_inp_enum[2]);
+
+/* Digital Gain control -38.4 dB to +38.4 dB in 0.3 dB steps */
+static const DECLARE_TLV_DB_SCALE(digital_gain, -3840, 30, 0);
+
+/* Cutoff Freq for High Pass Filter at -3dB */
+static const char * const hpf_cutoff_text[] = {
+	"4Hz", "75Hz", "150Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(tx1_hpf_cutoff_enum, LPASS_CDC_TX1_MUX_CTL, 4,
+			    hpf_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(tx2_hpf_cutoff_enum, LPASS_CDC_TX2_MUX_CTL, 4,
+			    hpf_cutoff_text);
+
+/* cut off for dc blocker inside rx chain */
+static const char * const dc_blocker_cutoff_text[] = {
+	"4Hz", "75Hz", "150Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(rx1_dcb_cutoff_enum, LPASS_CDC_RX1_B4_CTL, 0,
+			    dc_blocker_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(rx2_dcb_cutoff_enum, LPASS_CDC_RX2_B4_CTL, 0,
+			    dc_blocker_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(rx3_dcb_cutoff_enum, LPASS_CDC_RX3_B4_CTL, 0,
+			    dc_blocker_cutoff_text);
+
+static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = {
+	SOC_SINGLE_S8_TLV("RX1 Digital Volume", LPASS_CDC_RX1_VOL_CTL_B2_CTL,
+			  -128, 127, digital_gain),
+	SOC_SINGLE_S8_TLV("RX2 Digital Volume", LPASS_CDC_RX2_VOL_CTL_B2_CTL,
+			  -128, 127, digital_gain),
+	SOC_SINGLE_S8_TLV("RX3 Digital Volume", LPASS_CDC_RX3_VOL_CTL_B2_CTL,
+			  -128, 127, digital_gain),
+	SOC_SINGLE_S8_TLV("TX1 Digital Volume", LPASS_CDC_TX1_VOL_CTL_GAIN,
+			  -128, 127, digital_gain),
+	SOC_SINGLE_S8_TLV("TX2 Digital Volume", LPASS_CDC_TX2_VOL_CTL_GAIN,
+			  -128, 127, digital_gain),
+	SOC_ENUM("TX1 HPF Cutoff", tx1_hpf_cutoff_enum),
+	SOC_ENUM("TX2 HPF Cutoff", tx2_hpf_cutoff_enum),
+	SOC_SINGLE("TX1 HPF Switch", LPASS_CDC_TX1_MUX_CTL, 3, 1, 0),
+	SOC_SINGLE("TX2 HPF Switch", LPASS_CDC_TX2_MUX_CTL, 3, 1, 0),
+	SOC_ENUM("RX1 DCB Cutoff", rx1_dcb_cutoff_enum),
+	SOC_ENUM("RX2 DCB Cutoff", rx2_dcb_cutoff_enum),
+	SOC_ENUM("RX3 DCB Cutoff", rx3_dcb_cutoff_enum),
+	SOC_SINGLE("RX1 DCB Switch", LPASS_CDC_RX1_B5_CTL, 2, 1, 0),
+	SOC_SINGLE("RX2 DCB Switch", LPASS_CDC_RX2_B5_CTL, 2, 1, 0),
+	SOC_SINGLE("RX3 DCB Switch", LPASS_CDC_RX3_B5_CTL, 2, 1, 0),
+	SOC_SINGLE("RX1 Mute Switch", LPASS_CDC_RX1_B6_CTL, 0, 1, 0),
+	SOC_SINGLE("RX2 Mute Switch", LPASS_CDC_RX2_B6_CTL, 0, 1, 0),
+	SOC_SINGLE("RX3 Mute Switch", LPASS_CDC_RX3_B6_CTL, 0, 1, 0),
+};
+
+static int msm8916_wcd_digital_enable_interpolator(
+						struct snd_soc_dapm_widget *w,
+						struct snd_kcontrol *kcontrol,
+						int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* apply the digital gain after the interpolator is enabled */
+		usleep_range(10000, 10100);
+		snd_soc_component_write(component, rx_gain_reg[w->shift],
+			      snd_soc_component_read32(component, rx_gain_reg[w->shift]));
+		break;
+	}
+	return 0;
+}
+
+static int msm8916_wcd_digital_enable_dec(struct snd_soc_dapm_widget *w,
+					  struct snd_kcontrol *kcontrol,
+					  int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	unsigned int decimator = w->shift + 1;
+	u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
+	u8 dec_hpf_cut_of_freq;
+
+	dec_reset_reg = LPASS_CDC_CLK_TX_RESET_B1_CTL;
+	tx_vol_ctl_reg = LPASS_CDC_TX1_VOL_CTL_CFG + 32 * (decimator - 1);
+	tx_mux_ctl_reg = LPASS_CDC_TX1_MUX_CTL + 32 * (decimator - 1);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Enable TX digital mute */
+		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
+				    TX_VOL_CTL_CFG_MUTE_EN_MASK,
+				    TX_VOL_CTL_CFG_MUTE_EN_ENABLE);
+		dec_hpf_cut_of_freq = snd_soc_component_read32(component, tx_mux_ctl_reg) &
+					TX_MUX_CTL_CUT_OFF_FREQ_MASK;
+		dec_hpf_cut_of_freq >>= TX_MUX_CTL_CUT_OFF_FREQ_SHIFT;
+		if (dec_hpf_cut_of_freq != TX_MUX_CTL_CF_NEG_3DB_150HZ) {
+			/* set cut of freq to CF_MIN_3DB_150HZ (0x1) */
+			snd_soc_component_update_bits(component, tx_mux_ctl_reg,
+					    TX_MUX_CTL_CUT_OFF_FREQ_MASK,
+					    TX_MUX_CTL_CF_NEG_3DB_150HZ);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* enable HPF */
+		snd_soc_component_update_bits(component, tx_mux_ctl_reg,
+				    TX_MUX_CTL_HPF_BP_SEL_MASK,
+				    TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS);
+		/* apply the digital gain after the decimator is enabled */
+		snd_soc_component_write(component, tx_gain_reg[w->shift],
+			      snd_soc_component_read32(component, tx_gain_reg[w->shift]));
+		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
+				    TX_VOL_CTL_CFG_MUTE_EN_MASK, 0);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
+				    TX_VOL_CTL_CFG_MUTE_EN_MASK,
+				    TX_VOL_CTL_CFG_MUTE_EN_ENABLE);
+		snd_soc_component_update_bits(component, tx_mux_ctl_reg,
+				    TX_MUX_CTL_HPF_BP_SEL_MASK,
+				    TX_MUX_CTL_HPF_BP_SEL_BYPASS);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, dec_reset_reg, 1 << w->shift,
+				    1 << w->shift);
+		snd_soc_component_update_bits(component, dec_reset_reg, 1 << w->shift, 0x0);
+		snd_soc_component_update_bits(component, tx_mux_ctl_reg,
+				    TX_MUX_CTL_HPF_BP_SEL_MASK,
+				    TX_MUX_CTL_HPF_BP_SEL_BYPASS);
+		snd_soc_component_update_bits(component, tx_vol_ctl_reg,
+				    TX_VOL_CTL_CFG_MUTE_EN_MASK, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static int msm8916_wcd_digital_enable_dmic(struct snd_soc_dapm_widget *w,
+					   struct snd_kcontrol *kcontrol,
+					   int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	unsigned int dmic;
+	int ret;
+	/* get dmic number out of widget name */
+	char *dmic_num = strpbrk(w->name, "12");
+
+	if (dmic_num == NULL) {
+		dev_err(component->dev, "Invalid DMIC\n");
+		return -EINVAL;
+	}
+	ret = kstrtouint(dmic_num, 10, &dmic);
+	if (ret < 0 || dmic > 2) {
+		dev_err(component->dev, "Invalid DMIC line on the component\n");
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component, LPASS_CDC_CLK_DMIC_B1_CTL,
+				    DMIC_B1_CTL_DMIC0_CLK_SEL_MASK,
+				    DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3);
+		switch (dmic) {
+		case 1:
+			snd_soc_component_update_bits(component, LPASS_CDC_TX1_DMIC_CTL,
+					    TXN_DMIC_CTL_CLK_SEL_MASK,
+					    TXN_DMIC_CTL_CLK_SEL_DIV3);
+			break;
+		case 2:
+			snd_soc_component_update_bits(component, LPASS_CDC_TX2_DMIC_CTL,
+					    TXN_DMIC_CTL_CLK_SEL_MASK,
+					    TXN_DMIC_CTL_CLK_SEL_DIV3);
+			break;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = {
+	/*RX stuff */
+	SND_SOC_DAPM_AIF_IN("I2S RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("I2S RX2", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("I2S RX3", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_OUTPUT("PDM_RX1"),
+	SND_SOC_DAPM_OUTPUT("PDM_RX2"),
+	SND_SOC_DAPM_OUTPUT("PDM_RX3"),
+
+	SND_SOC_DAPM_INPUT("LPASS_PDM_TX"),
+
+	SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Interpolator */
+	SND_SOC_DAPM_MIXER_E("RX1 INT", LPASS_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
+			     0, msm8916_wcd_digital_enable_interpolator,
+			     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX2 INT", LPASS_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
+			     0, msm8916_wcd_digital_enable_interpolator,
+			     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER_E("RX3 INT", LPASS_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
+			     0, msm8916_wcd_digital_enable_interpolator,
+			     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+			 &rx_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+			 &rx_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+			 &rx_mix1_inp3_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+			 &rx2_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+			 &rx2_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+			 &rx2_mix1_inp3_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+			 &rx3_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+			 &rx3_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+			 &rx3_mix1_inp3_mux),
+
+	SND_SOC_DAPM_MUX("CIC1 MUX", SND_SOC_NOPM, 0, 0, &cic1_mux),
+	SND_SOC_DAPM_MUX("CIC2 MUX", SND_SOC_NOPM, 0, 0, &cic2_mux),
+	/* TX */
+	SND_SOC_DAPM_MIXER("ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX_E("DEC1 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
+			   &dec1_mux, msm8916_wcd_digital_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("DEC2 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
+			   &dec2_mux, msm8916_wcd_digital_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_OUT("I2S TX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S TX2", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S TX3", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+	/* Digital Mic Inputs */
+	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+			   msm8916_wcd_digital_enable_dmic,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+			   msm8916_wcd_digital_enable_dmic,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("DMIC_CLK", LPASS_CDC_CLK_DMIC_B1_CTL, 0, 0,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", LPASS_CDC_CLK_RX_I2S_CTL,
+			    4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", LPASS_CDC_CLK_TX_I2S_CTL, 4, 0,
+			    NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PDM_CLK", LPASS_CDC_CLK_PDM_CTL, 0, 0, NULL, 0),
+	/* Connectivity Clock */
+	SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, LPASS_CDC_CLK_OTHR_CTL, 2, 0,
+			      NULL, 0),
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+
+};
+
+static int msm8916_wcd_digital_get_clks(struct platform_device *pdev,
+					struct msm8916_wcd_digital_priv	*priv)
+{
+	struct device *dev = &pdev->dev;
+
+	priv->ahbclk = devm_clk_get(dev, "ahbix-clk");
+	if (IS_ERR(priv->ahbclk)) {
+		dev_err(dev, "failed to get ahbix clk\n");
+		return PTR_ERR(priv->ahbclk);
+	}
+
+	priv->mclk = devm_clk_get(dev, "mclk");
+	if (IS_ERR(priv->mclk)) {
+		dev_err(dev, "failed to get mclk\n");
+		return PTR_ERR(priv->mclk);
+	}
+
+	return 0;
+}
+
+static int msm8916_wcd_digital_component_probe(struct snd_soc_component *component)
+{
+	struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(component->dev);
+
+	snd_soc_component_set_drvdata(component, priv);
+
+	return 0;
+}
+
+static int msm8916_wcd_digital_component_set_sysclk(struct snd_soc_component *component,
+						int clk_id, int source,
+						unsigned int freq, int dir)
+{
+	struct msm8916_wcd_digital_priv *p = dev_get_drvdata(component->dev);
+
+	return clk_set_rate(p->mclk, freq);
+}
+
+static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream,
+					 struct snd_pcm_hw_params *params,
+					 struct snd_soc_dai *dai)
+{
+	u8 tx_fs_rate;
+	u8 rx_fs_rate;
+
+	switch (params_rate(params)) {
+	case 8000:
+		tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ;
+		rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ;
+		break;
+	case 16000:
+		tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ;
+		rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ;
+		break;
+	case 32000:
+		tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ;
+		rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ;
+		break;
+	case 48000:
+		tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ;
+		rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ;
+		break;
+	default:
+		dev_err(dai->component->dev, "Invalid sampling rate %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_CAPTURE:
+		snd_soc_component_update_bits(dai->component, LPASS_CDC_CLK_TX_I2S_CTL,
+				    TX_I2S_CTL_TX_I2S_FS_RATE_MASK, tx_fs_rate);
+		break;
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		snd_soc_component_update_bits(dai->component, LPASS_CDC_CLK_RX_I2S_CTL,
+				    RX_I2S_CTL_RX_I2S_FS_RATE_MASK, rx_fs_rate);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		snd_soc_component_update_bits(dai->component, LPASS_CDC_CLK_TX_I2S_CTL,
+				    TX_I2S_CTL_TX_I2S_MODE_MASK,
+				    TX_I2S_CTL_TX_I2S_MODE_16);
+		snd_soc_component_update_bits(dai->component, LPASS_CDC_CLK_RX_I2S_CTL,
+				    RX_I2S_CTL_RX_I2S_MODE_MASK,
+				    RX_I2S_CTL_RX_I2S_MODE_16);
+		break;
+
+	case SNDRV_PCM_FORMAT_S32_LE:
+		snd_soc_component_update_bits(dai->component, LPASS_CDC_CLK_TX_I2S_CTL,
+				    TX_I2S_CTL_TX_I2S_MODE_MASK,
+				    TX_I2S_CTL_TX_I2S_MODE_32);
+		snd_soc_component_update_bits(dai->component, LPASS_CDC_CLK_RX_I2S_CTL,
+				    RX_I2S_CTL_RX_I2S_MODE_MASK,
+				    RX_I2S_CTL_RX_I2S_MODE_32);
+		break;
+	default:
+		dev_err(dai->dev, "%s: wrong format selected\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = {
+
+	{"I2S RX1",  NULL, "AIF1 Playback"},
+	{"I2S RX2",  NULL, "AIF1 Playback"},
+	{"I2S RX3",  NULL, "AIF1 Playback"},
+
+	{"AIF1 Capture", NULL, "I2S TX1"},
+	{"AIF1 Capture", NULL, "I2S TX2"},
+	{"AIF1 Capture", NULL, "I2S TX3"},
+
+	{"CIC1 MUX", "DMIC", "DEC1 MUX"},
+	{"CIC1 MUX", "AMIC", "DEC1 MUX"},
+	{"CIC2 MUX", "DMIC", "DEC2 MUX"},
+	{"CIC2 MUX", "AMIC", "DEC2 MUX"},
+
+	/* Decimator Inputs */
+	{"DEC1 MUX", "DMIC1", "DMIC1"},
+	{"DEC1 MUX", "DMIC2", "DMIC2"},
+	{"DEC1 MUX", "ADC1", "ADC1"},
+	{"DEC1 MUX", "ADC2", "ADC2"},
+	{"DEC1 MUX", "ADC3", "ADC3"},
+	{"DEC1 MUX", NULL, "CDC_CONN"},
+
+	{"DEC2 MUX", "DMIC1", "DMIC1"},
+	{"DEC2 MUX", "DMIC2", "DMIC2"},
+	{"DEC2 MUX", "ADC1", "ADC1"},
+	{"DEC2 MUX", "ADC2", "ADC2"},
+	{"DEC2 MUX", "ADC3", "ADC3"},
+	{"DEC2 MUX", NULL, "CDC_CONN"},
+
+	{"DMIC1", NULL, "DMIC_CLK"},
+	{"DMIC2", NULL, "DMIC_CLK"},
+
+	{"I2S TX1", NULL, "CIC1 MUX"},
+	{"I2S TX2", NULL, "CIC2 MUX"},
+
+	{"I2S TX1", NULL, "TX_I2S_CLK"},
+	{"I2S TX2", NULL, "TX_I2S_CLK"},
+
+	{"TX_I2S_CLK", NULL, "MCLK"},
+	{"TX_I2S_CLK", NULL, "PDM_CLK"},
+
+	{"ADC1", NULL, "LPASS_PDM_TX"},
+	{"ADC2", NULL, "LPASS_PDM_TX"},
+	{"ADC3", NULL, "LPASS_PDM_TX"},
+
+	{"I2S RX1", NULL, "RX_I2S_CLK"},
+	{"I2S RX2", NULL, "RX_I2S_CLK"},
+	{"I2S RX3", NULL, "RX_I2S_CLK"},
+
+	{"RX_I2S_CLK", NULL, "PDM_CLK"},
+	{"RX_I2S_CLK", NULL, "MCLK"},
+	{"RX_I2S_CLK", NULL, "CDC_CONN"},
+
+	/* RX1 PATH.. */
+	{"PDM_RX1", NULL, "RX1 INT"},
+	{"RX1 INT", NULL, "RX1 MIX1"},
+
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
+	{"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
+
+	{"RX1 MIX1 INP1", "RX1", "I2S RX1"},
+	{"RX1 MIX1 INP1", "RX2", "I2S RX2"},
+	{"RX1 MIX1 INP1", "RX3", "I2S RX3"},
+
+	{"RX1 MIX1 INP2", "RX1", "I2S RX1"},
+	{"RX1 MIX1 INP2", "RX2", "I2S RX2"},
+	{"RX1 MIX1 INP2", "RX3", "I2S RX3"},
+
+	{"RX1 MIX1 INP3", "RX1", "I2S RX1"},
+	{"RX1 MIX1 INP3", "RX2", "I2S RX2"},
+	{"RX1 MIX1 INP3", "RX3", "I2S RX3"},
+
+	/* RX2 PATH */
+	{"PDM_RX2", NULL, "RX2 INT"},
+	{"RX2 INT", NULL, "RX2 MIX1"},
+
+	{"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
+	{"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
+	{"RX2 MIX1", NULL, "RX2 MIX1 INP3"},
+
+	{"RX2 MIX1 INP1", "RX1", "I2S RX1"},
+	{"RX2 MIX1 INP1", "RX2", "I2S RX2"},
+	{"RX2 MIX1 INP1", "RX3", "I2S RX3"},
+
+	{"RX2 MIX1 INP2", "RX1", "I2S RX1"},
+	{"RX2 MIX1 INP2", "RX2", "I2S RX2"},
+	{"RX2 MIX1 INP2", "RX3", "I2S RX3"},
+
+	{"RX2 MIX1 INP3", "RX1", "I2S RX1"},
+	{"RX2 MIX1 INP3", "RX2", "I2S RX2"},
+	{"RX2 MIX1 INP3", "RX3", "I2S RX3"},
+
+	/* RX3 PATH */
+	{"PDM_RX3", NULL, "RX3 INT"},
+	{"RX3 INT", NULL, "RX3 MIX1"},
+
+	{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
+	{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
+	{"RX3 MIX1", NULL, "RX3 MIX1 INP3"},
+
+	{"RX3 MIX1 INP1", "RX1", "I2S RX1"},
+	{"RX3 MIX1 INP1", "RX2", "I2S RX2"},
+	{"RX3 MIX1 INP1", "RX3", "I2S RX3"},
+
+	{"RX3 MIX1 INP2", "RX1", "I2S RX1"},
+	{"RX3 MIX1 INP2", "RX2", "I2S RX2"},
+	{"RX3 MIX1 INP2", "RX3", "I2S RX3"},
+
+	{"RX3 MIX1 INP3", "RX1", "I2S RX1"},
+	{"RX3 MIX1 INP3", "RX2", "I2S RX2"},
+	{"RX3 MIX1 INP3", "RX3", "I2S RX3"},
+
+};
+
+static int msm8916_wcd_digital_startup(struct snd_pcm_substream *substream,
+				       struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct msm8916_wcd_digital_priv *msm8916_wcd;
+	unsigned long mclk_rate;
+
+	msm8916_wcd = snd_soc_component_get_drvdata(component);
+	snd_soc_component_update_bits(component, LPASS_CDC_CLK_MCLK_CTL,
+			    MCLK_CTL_MCLK_EN_MASK,
+			    MCLK_CTL_MCLK_EN_ENABLE);
+	snd_soc_component_update_bits(component, LPASS_CDC_CLK_PDM_CTL,
+			    LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK,
+			    LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB);
+
+	mclk_rate = clk_get_rate(msm8916_wcd->mclk);
+	switch (mclk_rate) {
+	case 12288000:
+		snd_soc_component_update_bits(component, LPASS_CDC_TOP_CTL,
+				    TOP_CTL_DIG_MCLK_FREQ_MASK,
+				    TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ);
+		break;
+	case 9600000:
+		snd_soc_component_update_bits(component, LPASS_CDC_TOP_CTL,
+				    TOP_CTL_DIG_MCLK_FREQ_MASK,
+				    TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ);
+		break;
+	default:
+		dev_err(component->dev, "Invalid mclk rate %ld\n", mclk_rate);
+		break;
+	}
+	return 0;
+}
+
+static void msm8916_wcd_digital_shutdown(struct snd_pcm_substream *substream,
+					 struct snd_soc_dai *dai)
+{
+	snd_soc_component_update_bits(dai->component, LPASS_CDC_CLK_PDM_CTL,
+			    LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, 0);
+}
+
+static const struct snd_soc_dai_ops msm8916_wcd_digital_dai_ops = {
+	.startup = msm8916_wcd_digital_startup,
+	.shutdown = msm8916_wcd_digital_shutdown,
+	.hw_params = msm8916_wcd_digital_hw_params,
+};
+
+static struct snd_soc_dai_driver msm8916_wcd_digital_dai[] = {
+	[0] = {
+	       .name = "msm8916_wcd_digital_i2s_rx1",
+	       .id = 0,
+	       .playback = {
+			    .stream_name = "AIF1 Playback",
+			    .rates = MSM8916_WCD_DIGITAL_RATES,
+			    .formats = MSM8916_WCD_DIGITAL_FORMATS,
+			    .channels_min = 1,
+			    .channels_max = 3,
+			    },
+	       .ops = &msm8916_wcd_digital_dai_ops,
+	       },
+	[1] = {
+	       .name = "msm8916_wcd_digital_i2s_tx1",
+	       .id = 1,
+	       .capture = {
+			   .stream_name = "AIF1 Capture",
+			   .rates = MSM8916_WCD_DIGITAL_RATES,
+			   .formats = MSM8916_WCD_DIGITAL_FORMATS,
+			   .channels_min = 1,
+			   .channels_max = 4,
+			   },
+	       .ops = &msm8916_wcd_digital_dai_ops,
+	       },
+};
+
+static const struct snd_soc_component_driver msm8916_wcd_digital = {
+	.probe			= msm8916_wcd_digital_component_probe,
+	.set_sysclk		= msm8916_wcd_digital_component_set_sysclk,
+	.controls		= msm8916_wcd_digital_snd_controls,
+	.num_controls		= ARRAY_SIZE(msm8916_wcd_digital_snd_controls),
+	.dapm_widgets		= msm8916_wcd_digital_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(msm8916_wcd_digital_dapm_widgets),
+	.dapm_routes		= msm8916_wcd_digital_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(msm8916_wcd_digital_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config msm8916_codec_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = LPASS_CDC_TX2_DMIC_CTL,
+	.cache_type = REGCACHE_FLAT,
+};
+
+static int msm8916_wcd_digital_probe(struct platform_device *pdev)
+{
+	struct msm8916_wcd_digital_priv *priv;
+	struct device *dev = &pdev->dev;
+	void __iomem *base;
+	struct resource *mem_res;
+	struct regmap *digital_map;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, mem_res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	digital_map =
+	    devm_regmap_init_mmio(&pdev->dev, base,
+				  &msm8916_codec_regmap_config);
+	if (IS_ERR(digital_map))
+		return PTR_ERR(digital_map);
+
+	ret = msm8916_wcd_digital_get_clks(pdev, priv);
+	if (ret < 0)
+		return ret;
+
+	ret = clk_prepare_enable(priv->ahbclk);
+	if (ret < 0) {
+		dev_err(dev, "failed to enable ahbclk %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(priv->mclk);
+	if (ret < 0) {
+		dev_err(dev, "failed to enable mclk %d\n", ret);
+		return ret;
+	}
+
+	dev_set_drvdata(dev, priv);
+
+	return devm_snd_soc_register_component(dev, &msm8916_wcd_digital,
+				      msm8916_wcd_digital_dai,
+				      ARRAY_SIZE(msm8916_wcd_digital_dai));
+}
+
+static int msm8916_wcd_digital_remove(struct platform_device *pdev)
+{
+	struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(&pdev->dev);
+
+	clk_disable_unprepare(priv->mclk);
+	clk_disable_unprepare(priv->ahbclk);
+
+	return 0;
+}
+
+static const struct of_device_id msm8916_wcd_digital_match_table[] = {
+	{ .compatible = "qcom,msm8916-wcd-digital-codec" },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, msm8916_wcd_digital_match_table);
+
+static struct platform_driver msm8916_wcd_digital_driver = {
+	.driver = {
+		   .name = "msm8916-wcd-digital-codec",
+		   .of_match_table = msm8916_wcd_digital_match_table,
+	},
+	.probe = msm8916_wcd_digital_probe,
+	.remove = msm8916_wcd_digital_remove,
+};
+
+module_platform_driver(msm8916_wcd_digital_driver);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");
+MODULE_DESCRIPTION("MSM8916 WCD Digital Codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/mt6351.c b/sound/soc/codecs/mt6351.c
new file mode 100644
index 0000000..f73dcd7
--- /dev/null
+++ b/sound/soc/codecs/mt6351.c
@@ -0,0 +1,1505 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt6351.c  --  mt6351 ALSA SoC audio codec driver
+//
+// Copyright (c) 2018 MediaTek Inc.
+// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "mt6351.h"
+
+/* MT6351_TOP_CLKSQ */
+#define RG_CLKSQ_EN_AUD_BIT (0)
+
+/* MT6351_TOP_CKPDN_CON0 */
+#define RG_AUDNCP_CK_PDN_BIT (12)
+#define RG_AUDIF_CK_PDN_BIT (13)
+#define RG_AUD_CK_PDN_BIT (14)
+#define RG_ZCD13M_CK_PDN_BIT (15)
+
+/* MT6351_AUDDEC_ANA_CON0 */
+#define RG_AUDDACLPWRUP_VAUDP32_BIT (0)
+#define RG_AUDDACRPWRUP_VAUDP32_BIT (1)
+#define RG_AUD_DAC_PWR_UP_VA32_BIT (2)
+#define RG_AUD_DAC_PWL_UP_VA32_BIT (3)
+
+#define RG_AUDHSPWRUP_VAUDP32_BIT (4)
+
+#define RG_AUDHPLPWRUP_VAUDP32_BIT (5)
+#define RG_AUDHPRPWRUP_VAUDP32_BIT (6)
+
+#define RG_AUDHSMUXINPUTSEL_VAUDP32_SFT (7)
+#define RG_AUDHSMUXINPUTSEL_VAUDP32_MASK (0x3)
+
+#define RG_AUDHPLMUXINPUTSEL_VAUDP32_SFT (9)
+#define RG_AUDHPLMUXINPUTSEL_VAUDP32_MASK (0x3)
+
+#define RG_AUDHPRMUXINPUTSEL_VAUDP32_SFT (11)
+#define RG_AUDHPRMUXINPUTSEL_VAUDP32_MASK (0x3)
+
+#define RG_AUDHSSCDISABLE_VAUDP32 (13)
+#define RG_AUDHPLSCDISABLE_VAUDP32_BIT (14)
+#define RG_AUDHPRSCDISABLE_VAUDP32_BIT (15)
+
+/* MT6351_AUDDEC_ANA_CON1 */
+#define RG_HSOUTPUTSTBENH_VAUDP32_BIT (8)
+
+/* MT6351_AUDDEC_ANA_CON3 */
+#define RG_AUDLOLPWRUP_VAUDP32_BIT (2)
+
+#define RG_AUDLOLMUXINPUTSEL_VAUDP32_SFT (3)
+#define RG_AUDLOLMUXINPUTSEL_VAUDP32_MASK (0x3)
+
+#define RG_AUDLOLSCDISABLE_VAUDP32_BIT (5)
+#define RG_LOOUTPUTSTBENH_VAUDP32_BIT (9)
+
+/* MT6351_AUDDEC_ANA_CON6 */
+#define RG_ABIDEC_RSVD0_VAUDP32_HPL_BIT (8)
+#define RG_ABIDEC_RSVD0_VAUDP32_HPR_BIT (9)
+#define RG_ABIDEC_RSVD0_VAUDP32_HS_BIT (10)
+#define RG_ABIDEC_RSVD0_VAUDP32_LOL_BIT (11)
+
+/* MT6351_AUDDEC_ANA_CON9 */
+#define RG_AUDIBIASPWRDN_VAUDP32_BIT (8)
+#define RG_RSTB_DECODER_VA32_BIT (9)
+#define RG_AUDGLB_PWRDN_VA32_BIT (12)
+
+#define RG_LCLDO_DEC_EN_VA32_BIT (13)
+#define RG_LCLDO_DEC_REMOTE_SENSE_VA18_BIT (15)
+/* MT6351_AUDDEC_ANA_CON10 */
+#define RG_NVREG_EN_VAUDP32_BIT (8)
+
+#define RG_AUDGLB_LP2_VOW_EN_VA32 10
+
+/* MT6351_AFE_UL_DL_CON0 */
+#define RG_AFE_ON_BIT (0)
+
+/* MT6351_AFE_DL_SRC2_CON0_L */
+#define RG_DL_2_SRC_ON_TMP_CTL_PRE_BIT (0)
+
+/* MT6351_AFE_UL_SRC_CON0_L */
+#define UL_SRC_ON_TMP_CTL (0)
+
+/* MT6351_AFE_TOP_CON0 */
+#define RG_DL_SINE_ON_SFT (0)
+#define RG_DL_SINE_ON_MASK (0x1)
+
+#define RG_UL_SINE_ON_SFT (1)
+#define RG_UL_SINE_ON_MASK (0x1)
+
+/* MT6351_AUDIO_TOP_CON0 */
+#define AUD_TOP_PDN_RESERVED_BIT 0
+#define AUD_TOP_PWR_CLK_DIS_CTL_BIT 2
+#define AUD_TOP_PDN_ADC_CTL_BIT 5
+#define AUD_TOP_PDN_DAC_CTL_BIT 6
+#define AUD_TOP_PDN_AFE_CTL_BIT 7
+
+/* MT6351_AFE_SGEN_CFG0 */
+#define SGEN_C_MUTE_SW_CTL_BIT 6
+#define SGEN_C_DAC_EN_CTL_BIT 7
+
+/* MT6351_AFE_NCP_CFG0 */
+#define RG_NCP_ON_BIT 0
+
+/* MT6351_LDO_VUSB33_CON0 */
+#define RG_VUSB33_EN 1
+#define RG_VUSB33_ON_CTRL 3
+
+/* MT6351_LDO_VA18_CON0 */
+#define RG_VA18_EN 1
+#define RG_VA18_ON_CTRL 3
+
+/* MT6351_AUDENC_ANA_CON0 */
+#define RG_AUDPREAMPLON 0
+#define RG_AUDPREAMPLDCCEN 1
+#define RG_AUDPREAMPLDCPRECHARGE 2
+
+#define RG_AUDPREAMPLINPUTSEL_SFT (4)
+#define RG_AUDPREAMPLINPUTSEL_MASK (0x3)
+
+#define RG_AUDADCLPWRUP 12
+
+#define RG_AUDADCLINPUTSEL_SFT (13)
+#define RG_AUDADCLINPUTSEL_MASK (0x3)
+
+/* MT6351_AUDENC_ANA_CON1 */
+#define RG_AUDPREAMPRON 0
+#define RG_AUDPREAMPRDCCEN 1
+#define RG_AUDPREAMPRDCPRECHARGE 2
+
+#define RG_AUDPREAMPRINPUTSEL_SFT (4)
+#define RG_AUDPREAMPRINPUTSEL_MASK (0x3)
+
+#define RG_AUDADCRPWRUP 12
+
+#define RG_AUDADCRINPUTSEL_SFT (13)
+#define RG_AUDADCRINPUTSEL_MASK (0x3)
+
+/* MT6351_AUDENC_ANA_CON3 */
+#define RG_AUDADCCLKRSTB 6
+
+/* MT6351_AUDENC_ANA_CON9 */
+#define RG_AUDPWDBMICBIAS0 0
+#define RG_AUDMICBIAS0VREF 4
+#define RG_AUDMICBIAS0LOWPEN 7
+
+#define RG_AUDPWDBMICBIAS2 8
+#define RG_AUDMICBIAS2VREF 12
+#define RG_AUDMICBIAS2LOWPEN 15
+
+/* MT6351_AUDENC_ANA_CON10 */
+#define RG_AUDPWDBMICBIAS1 0
+#define RG_AUDMICBIAS1DCSW1NEN 2
+#define RG_AUDMICBIAS1VREF 4
+#define RG_AUDMICBIAS1LOWPEN 7
+
+enum {
+	AUDIO_ANALOG_VOLUME_HSOUTL,
+	AUDIO_ANALOG_VOLUME_HSOUTR,
+	AUDIO_ANALOG_VOLUME_HPOUTL,
+	AUDIO_ANALOG_VOLUME_HPOUTR,
+	AUDIO_ANALOG_VOLUME_LINEOUTL,
+	AUDIO_ANALOG_VOLUME_LINEOUTR,
+	AUDIO_ANALOG_VOLUME_MICAMP1,
+	AUDIO_ANALOG_VOLUME_MICAMP2,
+	AUDIO_ANALOG_VOLUME_TYPE_MAX
+};
+
+/* Supply subseq */
+enum {
+	SUPPLY_SUBSEQ_SETTING,
+	SUPPLY_SUBSEQ_ENABLE,
+	SUPPLY_SUBSEQ_MICBIAS,
+};
+
+#define REG_STRIDE 2
+
+struct mt6351_priv {
+	struct device *dev;
+	struct regmap *regmap;
+
+	unsigned int dl_rate;
+	unsigned int ul_rate;
+
+	int ana_gain[AUDIO_ANALOG_VOLUME_TYPE_MAX];
+
+	int hp_en_counter;
+};
+
+static void set_hp_gain_zero(struct snd_soc_component *cmpnt)
+{
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON2,
+			   0x1f << 7, 0x8 << 7);
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON2,
+			   0x1f << 0, 0x8 << 0);
+}
+
+static unsigned int get_cap_reg_val(struct snd_soc_component *cmpnt,
+				    unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return 0;
+	case 16000:
+		return 1;
+	case 32000:
+		return 2;
+	case 48000:
+		return 3;
+	case 96000:
+		return 4;
+	case 192000:
+		return 5;
+	default:
+		dev_warn(cmpnt->dev, "%s(), error rate %d, return 3",
+			 __func__, rate);
+		return 3;
+	}
+}
+
+static unsigned int get_play_reg_val(struct snd_soc_component *cmpnt,
+				     unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return 0;
+	case 11025:
+		return 1;
+	case 12000:
+		return 2;
+	case 16000:
+		return 3;
+	case 22050:
+		return 4;
+	case 24000:
+		return 5;
+	case 32000:
+		return 6;
+	case 44100:
+		return 7;
+	case 48000:
+	case 96000:
+	case 192000:
+		return 8;
+	default:
+		dev_warn(cmpnt->dev, "%s(), error rate %d, return 8",
+			 __func__, rate);
+		return 8;
+	}
+}
+
+static int mt6351_codec_dai_hw_params(struct snd_pcm_substream *substream,
+				      struct snd_pcm_hw_params *params,
+				      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *cmpnt = dai->component;
+	struct mt6351_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int rate = params_rate(params);
+
+	dev_dbg(priv->dev, "%s(), substream->stream %d, rate %d\n",
+		__func__, substream->stream, rate);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		priv->dl_rate = rate;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		priv->ul_rate = rate;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mt6351_codec_dai_ops = {
+	.hw_params = mt6351_codec_dai_hw_params,
+};
+
+#define MT6351_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\
+			SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
+			SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\
+			SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\
+			SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE)
+
+static struct snd_soc_dai_driver mt6351_dai_driver[] = {
+	{
+		.name = "mt6351-snd-codec-aif1",
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000 |
+				 SNDRV_PCM_RATE_96000 |
+				 SNDRV_PCM_RATE_192000,
+			.formats = MT6351_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000 |
+				 SNDRV_PCM_RATE_16000 |
+				 SNDRV_PCM_RATE_32000 |
+				 SNDRV_PCM_RATE_48000 |
+				 SNDRV_PCM_RATE_96000 |
+				 SNDRV_PCM_RATE_192000,
+			.formats = MT6351_FORMATS,
+		},
+		.ops = &mt6351_codec_dai_ops,
+	},
+};
+
+enum {
+	HP_GAIN_SET_ZERO,
+	HP_GAIN_RESTORE,
+};
+
+static void hp_gain_ramp_set(struct snd_soc_component *cmpnt, int hp_gain_ctl)
+{
+	struct mt6351_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+	int idx, old_idx, offset, reg_idx;
+
+	if (hp_gain_ctl == HP_GAIN_SET_ZERO) {
+		idx = 8;	/* 0dB */
+		old_idx = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL];
+	} else {
+		idx = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL];
+		old_idx = 8;	/* 0dB */
+	}
+	dev_dbg(priv->dev, "%s(), idx %d, old_idx %d\n",
+		__func__, idx, old_idx);
+
+	if (idx > old_idx)
+		offset = idx - old_idx;
+	else
+		offset = old_idx - idx;
+
+	reg_idx = old_idx;
+
+	while (offset > 0) {
+		reg_idx = idx > old_idx ? reg_idx + 1 : reg_idx - 1;
+
+		/* check valid range, and set value */
+		if ((reg_idx >= 0 && reg_idx <= 0x12) || reg_idx == 0x1f) {
+			regmap_update_bits(cmpnt->regmap,
+					   MT6351_ZCD_CON2,
+					   0xf9f,
+					   (reg_idx << 7) | reg_idx);
+			usleep_range(100, 120);
+		}
+		offset--;
+	}
+}
+
+static void hp_zcd_enable(struct snd_soc_component *cmpnt)
+{
+	/* Enable ZCD, for minimize pop noise */
+	/* when adjust gain during HP buffer on */
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON0, 0x7 << 8, 0x1 << 8);
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON0, 0x1 << 7, 0x0 << 7);
+
+	/* timeout, 1=5ms, 0=30ms */
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON0, 0x1 << 6, 0x1 << 6);
+
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON0, 0x3 << 4, 0x0 << 4);
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON0, 0x7 << 1, 0x5 << 1);
+	regmap_update_bits(cmpnt->regmap, MT6351_ZCD_CON0, 0x1 << 0, 0x1 << 0);
+}
+
+static void hp_zcd_disable(struct snd_soc_component *cmpnt)
+{
+	regmap_write(cmpnt->regmap, MT6351_ZCD_CON0, 0x0000);
+}
+
+static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0);
+static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new mt6351_snd_controls[] = {
+	/* dl pga gain */
+	SOC_DOUBLE_TLV("Headphone Volume",
+		       MT6351_ZCD_CON2, 0, 7, 0x12, 1,
+		       playback_tlv),
+	SOC_DOUBLE_TLV("Lineout Volume",
+		       MT6351_ZCD_CON1, 0, 7, 0x12, 1,
+		       playback_tlv),
+	SOC_SINGLE_TLV("Handset Volume",
+		       MT6351_ZCD_CON3, 0, 0x12, 1,
+		       playback_tlv),
+       /* ul pga gain */
+	SOC_DOUBLE_R_TLV("PGA Volume",
+			 MT6351_AUDENC_ANA_CON0, MT6351_AUDENC_ANA_CON1,
+			 8, 4, 0,
+			 pga_tlv),
+};
+
+/* MUX */
+
+/* LOL MUX */
+static const char *const lo_in_mux_map[] = {
+	"Open", "Mute", "Playback", "Test Mode",
+};
+
+static int lo_in_mux_map_value[] = {
+	0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(lo_in_mux_map_enum,
+				  MT6351_AUDDEC_ANA_CON3,
+				  RG_AUDLOLMUXINPUTSEL_VAUDP32_SFT,
+				  RG_AUDLOLMUXINPUTSEL_VAUDP32_MASK,
+				  lo_in_mux_map,
+				  lo_in_mux_map_value);
+
+static const struct snd_kcontrol_new lo_in_mux_control =
+	SOC_DAPM_ENUM("In Select", lo_in_mux_map_enum);
+
+/*HP MUX */
+static const char *const hp_in_mux_map[] = {
+	"Open", "LoudSPK Playback", "Audio Playback", "Test Mode",
+};
+
+static int hp_in_mux_map_value[] = {
+	0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hpl_in_mux_map_enum,
+				  MT6351_AUDDEC_ANA_CON0,
+				  RG_AUDHPLMUXINPUTSEL_VAUDP32_SFT,
+				  RG_AUDHPLMUXINPUTSEL_VAUDP32_MASK,
+				  hp_in_mux_map,
+				  hp_in_mux_map_value);
+
+static const struct snd_kcontrol_new hpl_in_mux_control =
+	SOC_DAPM_ENUM("HPL Select", hpl_in_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(hpr_in_mux_map_enum,
+				  MT6351_AUDDEC_ANA_CON0,
+				  RG_AUDHPRMUXINPUTSEL_VAUDP32_SFT,
+				  RG_AUDHPRMUXINPUTSEL_VAUDP32_MASK,
+				  hp_in_mux_map,
+				  hp_in_mux_map_value);
+
+static const struct snd_kcontrol_new hpr_in_mux_control =
+	SOC_DAPM_ENUM("HPR Select", hpr_in_mux_map_enum);
+
+/* RCV MUX */
+static const char *const rcv_in_mux_map[] = {
+	"Open", "Mute", "Voice Playback", "Test Mode",
+};
+
+static int rcv_in_mux_map_value[] = {
+	0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rcv_in_mux_map_enum,
+				  MT6351_AUDDEC_ANA_CON0,
+				  RG_AUDHSMUXINPUTSEL_VAUDP32_SFT,
+				  RG_AUDHSMUXINPUTSEL_VAUDP32_MASK,
+				  rcv_in_mux_map,
+				  rcv_in_mux_map_value);
+
+static const struct snd_kcontrol_new rcv_in_mux_control =
+	SOC_DAPM_ENUM("RCV Select", rcv_in_mux_map_enum);
+
+/* DAC In MUX */
+static const char *const dac_in_mux_map[] = {
+	"Normal Path", "Sgen",
+};
+
+static int dac_in_mux_map_value[] = {
+	0x0, 0x1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(dac_in_mux_map_enum,
+				  MT6351_AFE_TOP_CON0,
+				  RG_DL_SINE_ON_SFT,
+				  RG_DL_SINE_ON_MASK,
+				  dac_in_mux_map,
+				  dac_in_mux_map_value);
+
+static const struct snd_kcontrol_new dac_in_mux_control =
+	SOC_DAPM_ENUM("DAC Select", dac_in_mux_map_enum);
+
+/* AIF Out MUX */
+static SOC_VALUE_ENUM_SINGLE_DECL(aif_out_mux_map_enum,
+				  MT6351_AFE_TOP_CON0,
+				  RG_UL_SINE_ON_SFT,
+				  RG_UL_SINE_ON_MASK,
+				  dac_in_mux_map,
+				  dac_in_mux_map_value);
+
+static const struct snd_kcontrol_new aif_out_mux_control =
+	SOC_DAPM_ENUM("AIF Out Select", aif_out_mux_map_enum);
+
+/* ADC L MUX */
+static const char *const adc_left_mux_map[] = {
+	"Idle", "AIN0", "Left Preamplifier", "Idle_1",
+};
+
+static int adc_left_mux_map_value[] = {
+	0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adc_left_mux_map_enum,
+				  MT6351_AUDENC_ANA_CON0,
+				  RG_AUDADCLINPUTSEL_SFT,
+				  RG_AUDADCLINPUTSEL_MASK,
+				  adc_left_mux_map,
+				  adc_left_mux_map_value);
+
+static const struct snd_kcontrol_new adc_left_mux_control =
+	SOC_DAPM_ENUM("ADC L Select", adc_left_mux_map_enum);
+
+/* ADC R MUX */
+static const char *const adc_right_mux_map[] = {
+	"Idle", "AIN0", "Right Preamplifier", "Idle_1",
+};
+
+static int adc_right_mux_map_value[] = {
+	0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adc_right_mux_map_enum,
+				  MT6351_AUDENC_ANA_CON1,
+				  RG_AUDADCRINPUTSEL_SFT,
+				  RG_AUDADCRINPUTSEL_MASK,
+				  adc_right_mux_map,
+				  adc_right_mux_map_value);
+
+static const struct snd_kcontrol_new adc_right_mux_control =
+	SOC_DAPM_ENUM("ADC R Select", adc_right_mux_map_enum);
+
+/* PGA L MUX */
+static const char *const pga_left_mux_map[] = {
+	"None", "AIN0", "AIN1", "AIN2",
+};
+
+static int pga_left_mux_map_value[] = {
+	0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(pga_left_mux_map_enum,
+				  MT6351_AUDENC_ANA_CON0,
+				  RG_AUDPREAMPLINPUTSEL_SFT,
+				  RG_AUDPREAMPLINPUTSEL_MASK,
+				  pga_left_mux_map,
+				  pga_left_mux_map_value);
+
+static const struct snd_kcontrol_new pga_left_mux_control =
+	SOC_DAPM_ENUM("PGA L Select", pga_left_mux_map_enum);
+
+/* PGA R MUX */
+static const char *const pga_right_mux_map[] = {
+	"None", "AIN0", "AIN3", "AIN2",
+};
+
+static int pga_right_mux_map_value[] = {
+	0x0, 0x1, 0x2, 0x3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(pga_right_mux_map_enum,
+				  MT6351_AUDENC_ANA_CON1,
+				  RG_AUDPREAMPRINPUTSEL_SFT,
+				  RG_AUDPREAMPRINPUTSEL_MASK,
+				  pga_right_mux_map,
+				  pga_right_mux_map_value);
+
+static const struct snd_kcontrol_new pga_right_mux_control =
+	SOC_DAPM_ENUM("PGA R Select", pga_right_mux_map_enum);
+
+static int mt_reg_set_clr_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol,
+				int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (w->on_val) {
+			/* SET REG */
+			regmap_update_bits(cmpnt->regmap,
+					   w->reg + REG_STRIDE,
+					   0x1 << w->shift,
+					   0x1 << w->shift);
+		} else {
+			/* CLR REG */
+			regmap_update_bits(cmpnt->regmap,
+					   w->reg + REG_STRIDE * 2,
+					   0x1 << w->shift,
+					   0x1 << w->shift);
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		if (w->off_val) {
+			/* SET REG */
+			regmap_update_bits(cmpnt->regmap,
+					   w->reg + REG_STRIDE,
+					   0x1 << w->shift,
+					   0x1 << w->shift);
+		} else {
+			/* CLR REG */
+			regmap_update_bits(cmpnt->regmap,
+					   w->reg + REG_STRIDE * 2,
+					   0x1 << w->shift,
+					   0x1 << w->shift);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_ncp_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol,
+			int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_NCP_CFG1,
+				   0xffff, 0x1515);
+		/* NCP: ck1 and ck2 clock frequecy adjust configure */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_NCP_CFG0,
+				   0xfffe, 0x8C00);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(250, 270);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_sgen_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol,
+			 int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_SGEN_CFG0,
+				   0xffef, 0x0008);
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_SGEN_CFG1,
+				   0xffff, 0x0101);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_aif_in_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol,
+			   int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6351_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	dev_dbg(priv->dev, "%s(), event 0x%x, rate %d\n",
+		__func__, event, priv->dl_rate);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* sdm audio fifo clock power on */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFUNC_AUD_CON2,
+				   0xffff, 0x0006);
+		/* scrambler clock on enable */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFUNC_AUD_CON0,
+				   0xffff, 0xC3A1);
+		/* sdm power on */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFUNC_AUD_CON2,
+				   0xffff, 0x0003);
+		/* sdm fifo enable */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFUNC_AUD_CON2,
+				   0xffff, 0x000B);
+		/* set attenuation gain */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_DL_SDM_CON1,
+				   0xffff, 0x001E);
+
+		regmap_write(cmpnt->regmap, MT6351_AFE_PMIC_NEWIF_CFG0,
+			     (get_play_reg_val(cmpnt, priv->dl_rate) << 12) |
+			     0x330);
+		regmap_write(cmpnt->regmap, MT6351_AFE_DL_SRC2_CON0_H,
+			     (get_play_reg_val(cmpnt, priv->dl_rate) << 12) |
+			     0x300);
+
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_PMIC_NEWIF_CFG2,
+				   0x8000, 0x8000);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_hp_event(struct snd_soc_dapm_widget *w,
+		       struct snd_kcontrol *kcontrol,
+		       int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6351_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+	int reg;
+
+	dev_dbg(priv->dev, "%s(), event 0x%x, hp_en_counter %d\n",
+		__func__, event, priv->hp_en_counter);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		priv->hp_en_counter++;
+		if (priv->hp_en_counter > 1)
+			break;	/* already enabled, do nothing */
+		else if (priv->hp_en_counter <= 0)
+			dev_err(priv->dev, "%s(), hp_en_counter %d <= 0\n",
+				__func__,
+				priv->hp_en_counter);
+
+		hp_zcd_disable(cmpnt);
+
+		/* from yoyo HQA script */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON6,
+				   0x0700, 0x0700);
+
+		/* save target gain to restore after hardware open complete */
+		regmap_read(cmpnt->regmap, MT6351_ZCD_CON2, &reg);
+		priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] = reg & 0x1f;
+		priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] = (reg >> 7) & 0x1f;
+
+		/* Set HPR/HPL gain as minimum (~ -40dB) */
+		regmap_update_bits(cmpnt->regmap,
+				   MT6351_ZCD_CON2, 0xffff, 0x0F9F);
+		/* Set HS gain as minimum (~ -40dB) */
+		regmap_update_bits(cmpnt->regmap,
+				   MT6351_ZCD_CON3, 0xffff, 0x001F);
+		/* De_OSC of HP */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON2,
+				   0x0001, 0x0001);
+		/* enable output STBENH */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON1,
+				   0xffff, 0x2000);
+		/* De_OSC of voice, enable output STBENH */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON1,
+				   0xffff, 0x2100);
+		/* Enable voice driver */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON0,
+				   0x0010, 0xE090);
+		/* Enable pre-charge buffer  */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON1,
+				   0xffff, 0x2140);
+
+		usleep_range(50, 60);
+
+		/* Apply digital DC compensation value to DAC */
+		set_hp_gain_zero(cmpnt);
+
+		/* Enable HPR/HPL */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON1,
+				   0xffff, 0x2100);
+		/* Disable pre-charge buffer */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON1,
+				   0xffff, 0x2000);
+		/* Disable De_OSC of voice */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON0,
+				   0x0010, 0xF4EF);
+		/* Disable voice buffer */
+
+		/* from yoyo HQ */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON6,
+				   0x0700, 0x0300);
+
+		/* Enable ZCD, for minimize pop noise */
+		/* when adjust gain during HP buffer on */
+		hp_zcd_enable(cmpnt);
+
+		/* apply volume setting */
+		hp_gain_ramp_set(cmpnt, HP_GAIN_RESTORE);
+
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		priv->hp_en_counter--;
+		if (priv->hp_en_counter > 0)
+			break;	/* still being used, don't close */
+		else if (priv->hp_en_counter < 0)
+			dev_err(priv->dev, "%s(), hp_en_counter %d <= 0\n",
+				__func__,
+				priv->hp_en_counter);
+
+		/* Disable AUD_ZCD */
+		hp_zcd_disable(cmpnt);
+
+		/* Set HPR/HPL gain as -1dB, step by step */
+		hp_gain_ramp_set(cmpnt, HP_GAIN_SET_ZERO);
+
+		set_hp_gain_zero(cmpnt);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (priv->hp_en_counter > 0)
+			break;	/* still being used, don't close */
+		else if (priv->hp_en_counter < 0)
+			dev_err(priv->dev, "%s(), hp_en_counter %d <= 0\n",
+				__func__,
+				priv->hp_en_counter);
+
+		/* reset*/
+		regmap_update_bits(cmpnt->regmap,
+				   MT6351_AUDDEC_ANA_CON6,
+				   0x0700,
+				   0x0000);
+		/* De_OSC of HP */
+		regmap_update_bits(cmpnt->regmap,
+				   MT6351_AUDDEC_ANA_CON2,
+				   0x0001,
+				   0x0000);
+
+		/* apply volume setting */
+		hp_gain_ramp_set(cmpnt, HP_GAIN_RESTORE);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_aif_out_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol,
+			    int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6351_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	dev_dbg(priv->dev, "%s(), event 0x%x, rate %d\n",
+		__func__, event, priv->ul_rate);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* dcclk_div=11'b00100000011, dcclk_ref_ck_sel=2'b00 */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_DCCLK_CFG0,
+				   0xffff, 0x2062);
+		/* dcclk_pdn=1'b0 */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_DCCLK_CFG0,
+				   0xffff, 0x2060);
+		/* dcclk_gen_on=1'b1 */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_DCCLK_CFG0,
+				   0xffff, 0x2061);
+
+		/* UL sample rate and mode configure */
+		regmap_update_bits(cmpnt->regmap, MT6351_AFE_UL_SRC_CON0_H,
+				   0x000E,
+				   get_cap_reg_val(cmpnt, priv->ul_rate) << 1);
+
+		/* fixed 260k path for 8/16/32/48 */
+		if (priv->ul_rate <= 48000) {
+			/* anc ul path src on */
+			regmap_update_bits(cmpnt->regmap,
+					   MT6351_AFE_HPANC_CFG0,
+					   0x1 << 1,
+					   0x1 << 1);
+			/* ANC clk pdn release */
+			regmap_update_bits(cmpnt->regmap,
+					   MT6351_AFE_HPANC_CFG0,
+					   0x1 << 0,
+					   0x0 << 0);
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* fixed 260k path for 8/16/32/48 */
+		if (priv->ul_rate <= 48000) {
+			/* anc ul path src on */
+			regmap_update_bits(cmpnt->regmap,
+					   MT6351_AFE_HPANC_CFG0,
+					   0x1 << 1,
+					   0x0 << 1);
+			/* ANC clk pdn release */
+			regmap_update_bits(cmpnt->regmap,
+					   MT6351_AFE_HPANC_CFG0,
+					   0x1 << 0,
+					   0x1 << 0);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_adc_clkgen_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol,
+			       int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Audio ADC clock gen. mode: 00_divided by 2 (Normal) */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON3,
+				   0x3 << 4, 0x0);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* ADC CLK from: 00_13MHz from CLKSQ (Default) */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON3,
+				   0x3 << 2, 0x0);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int mt_pga_left_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol,
+			     int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Audio L PGA precharge on */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON0,
+				   0x3 << RG_AUDPREAMPLDCPRECHARGE,
+				   0x1 << RG_AUDPREAMPLDCPRECHARGE);
+		/* Audio L PGA mode: 1_DCC */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON0,
+				   0x3 << RG_AUDPREAMPLDCCEN,
+				   0x1 << RG_AUDPREAMPLDCCEN);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(100, 120);
+		/* Audio L PGA precharge off */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON0,
+				   0x3 << RG_AUDPREAMPLDCPRECHARGE,
+				   0x0 << RG_AUDPREAMPLDCPRECHARGE);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int mt_pga_right_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol,
+			      int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Audio R PGA precharge on */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON1,
+				   0x3 << RG_AUDPREAMPRDCPRECHARGE,
+				   0x1 << RG_AUDPREAMPRDCPRECHARGE);
+		/* Audio R PGA mode: 1_DCC */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON1,
+				   0x3 << RG_AUDPREAMPRDCCEN,
+				   0x1 << RG_AUDPREAMPRDCCEN);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(100, 120);
+		/* Audio R PGA precharge off */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON1,
+				   0x3 << RG_AUDPREAMPRDCPRECHARGE,
+				   0x0 << RG_AUDPREAMPRDCPRECHARGE);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int mt_mic_bias_0_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol,
+			       int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* MIC Bias 0 LowPower: 0_Normal */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON9,
+				   0x3 << RG_AUDMICBIAS0LOWPEN, 0x0);
+		/* MISBIAS0 = 1P9V */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON9,
+				   0x7 << RG_AUDMICBIAS0VREF,
+				   0x2 << RG_AUDMICBIAS0VREF);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* MISBIAS0 = 1P97 */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON9,
+				   0x7 << RG_AUDMICBIAS0VREF,
+				   0x0 << RG_AUDMICBIAS0VREF);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int mt_mic_bias_1_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol,
+			       int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* MIC Bias 1 LowPower: 0_Normal */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON10,
+				   0x3 << RG_AUDMICBIAS1LOWPEN, 0x0);
+		/* MISBIAS1 = 2P7V */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON10,
+				   0x7 << RG_AUDMICBIAS1VREF,
+				   0x7 << RG_AUDMICBIAS1VREF);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* MISBIAS1 = 1P7V */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON10,
+				   0x7 << RG_AUDMICBIAS1VREF,
+				   0x0 << RG_AUDMICBIAS1VREF);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int mt_mic_bias_2_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol,
+			       int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* MIC Bias 2 LowPower: 0_Normal */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON9,
+				   0x3 << RG_AUDMICBIAS2LOWPEN, 0x0);
+		/* MISBIAS2 = 1P9V */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON9,
+				   0x7 << RG_AUDMICBIAS2VREF,
+				   0x2 << RG_AUDMICBIAS2VREF);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* MISBIAS2 = 1P97 */
+		regmap_update_bits(cmpnt->regmap, MT6351_AUDENC_ANA_CON9,
+				   0x7 << RG_AUDMICBIAS2VREF,
+				   0x0 << RG_AUDMICBIAS2VREF);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+/* DAPM Kcontrols */
+static const struct snd_kcontrol_new mt_lineout_control =
+	SOC_DAPM_SINGLE("Switch", MT6351_AUDDEC_ANA_CON3,
+			RG_AUDLOLPWRUP_VAUDP32_BIT, 1, 0);
+
+/* DAPM Widgets */
+static const struct snd_soc_dapm_widget mt6351_dapm_widgets[] = {
+	/* Digital Clock */
+	SND_SOC_DAPM_SUPPLY("AUDIO_TOP_AFE_CTL", MT6351_AUDIO_TOP_CON0,
+			    AUD_TOP_PDN_AFE_CTL_BIT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AUDIO_TOP_DAC_CTL", MT6351_AUDIO_TOP_CON0,
+			    AUD_TOP_PDN_DAC_CTL_BIT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AUDIO_TOP_ADC_CTL", MT6351_AUDIO_TOP_CON0,
+			    AUD_TOP_PDN_ADC_CTL_BIT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AUDIO_TOP_PWR_CLK", MT6351_AUDIO_TOP_CON0,
+			    AUD_TOP_PWR_CLK_DIS_CTL_BIT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AUDIO_TOP_PDN_RESERVED", MT6351_AUDIO_TOP_CON0,
+			    AUD_TOP_PDN_RESERVED_BIT, 1, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("NCP", MT6351_AFE_NCP_CFG0,
+			    RG_NCP_ON_BIT, 0,
+			    mt_ncp_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_SUPPLY("DL Digital Clock", SND_SOC_NOPM,
+			    0, 0, NULL, 0),
+
+	/* Global Supply*/
+	SND_SOC_DAPM_SUPPLY("AUDGLB", MT6351_AUDDEC_ANA_CON9,
+			    RG_AUDGLB_PWRDN_VA32_BIT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKSQ Audio", MT6351_TOP_CLKSQ,
+			    RG_CLKSQ_EN_AUD_BIT, 0,
+			    mt_reg_set_clr_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("ZCD13M_CK", MT6351_TOP_CKPDN_CON0,
+			    RG_ZCD13M_CK_PDN_BIT, 1,
+			    mt_reg_set_clr_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("AUD_CK", MT6351_TOP_CKPDN_CON0,
+			    RG_AUD_CK_PDN_BIT, 1,
+			    mt_reg_set_clr_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("AUDIF_CK", MT6351_TOP_CKPDN_CON0,
+			    RG_AUDIF_CK_PDN_BIT, 1,
+			    mt_reg_set_clr_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("AUDNCP_CK", MT6351_TOP_CKPDN_CON0,
+			    RG_AUDNCP_CK_PDN_BIT, 1,
+			    mt_reg_set_clr_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_SUPPLY("AFE_ON", MT6351_AFE_UL_DL_CON0, RG_AFE_ON_BIT, 0,
+			    NULL, 0),
+
+	/* AIF Rx*/
+	SND_SOC_DAPM_AIF_IN_E("AIF_RX", "AIF1 Playback", 0,
+			      MT6351_AFE_DL_SRC2_CON0_L,
+			      RG_DL_2_SRC_ON_TMP_CTL_PRE_BIT, 0,
+			      mt_aif_in_event, SND_SOC_DAPM_PRE_PMU),
+
+	/* DL Supply */
+	SND_SOC_DAPM_SUPPLY("DL Power Supply", SND_SOC_NOPM,
+			    0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("NV Regulator", MT6351_AUDDEC_ANA_CON10,
+			    RG_NVREG_EN_VAUDP32_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AUD_CLK", MT6351_AUDDEC_ANA_CON9,
+			    RG_RSTB_DECODER_VA32_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("IBIST", MT6351_AUDDEC_ANA_CON9,
+			    RG_AUDIBIASPWRDN_VAUDP32_BIT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LDO", MT6351_AUDDEC_ANA_CON9,
+			    RG_LCLDO_DEC_EN_VA32_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LDO_REMOTE_SENSE", MT6351_AUDDEC_ANA_CON9,
+			    RG_LCLDO_DEC_REMOTE_SENSE_VA18_BIT, 0, NULL, 0),
+
+	/* DAC */
+	SND_SOC_DAPM_MUX("DAC In Mux", SND_SOC_NOPM, 0, 0, &dac_in_mux_control),
+
+	SND_SOC_DAPM_DAC("DACL", NULL, MT6351_AUDDEC_ANA_CON0,
+			 RG_AUDDACLPWRUP_VAUDP32_BIT, 0),
+	SND_SOC_DAPM_SUPPLY("DACL_BIASGEN", MT6351_AUDDEC_ANA_CON0,
+			    RG_AUD_DAC_PWL_UP_VA32_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("DACR", NULL, MT6351_AUDDEC_ANA_CON0,
+			 RG_AUDDACRPWRUP_VAUDP32_BIT, 0),
+	SND_SOC_DAPM_SUPPLY("DACR_BIASGEN", MT6351_AUDDEC_ANA_CON0,
+			    RG_AUD_DAC_PWR_UP_VA32_BIT, 0, NULL, 0),
+	/* LOL */
+	SND_SOC_DAPM_MUX("LOL Mux", SND_SOC_NOPM, 0, 0, &lo_in_mux_control),
+
+	SND_SOC_DAPM_SUPPLY("LO Stability Enh", MT6351_AUDDEC_ANA_CON3,
+			    RG_LOOUTPUTSTBENH_VAUDP32_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LOL Bias Gen", MT6351_AUDDEC_ANA_CON6,
+			    RG_ABIDEC_RSVD0_VAUDP32_LOL_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUT_DRV("LOL Buffer", MT6351_AUDDEC_ANA_CON3,
+			     RG_AUDLOLPWRUP_VAUDP32_BIT, 0, NULL, 0),
+
+	/* Headphone */
+	SND_SOC_DAPM_MUX("HPL Mux", SND_SOC_NOPM, 0, 0, &hpl_in_mux_control),
+	SND_SOC_DAPM_MUX("HPR Mux", SND_SOC_NOPM, 0, 0, &hpr_in_mux_control),
+
+	SND_SOC_DAPM_OUT_DRV_E("HPL Power", MT6351_AUDDEC_ANA_CON0,
+			       RG_AUDHPLPWRUP_VAUDP32_BIT, 0, NULL, 0,
+			       mt_hp_event,
+			       SND_SOC_DAPM_PRE_PMU |
+			       SND_SOC_DAPM_PRE_PMD |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_OUT_DRV_E("HPR Power", MT6351_AUDDEC_ANA_CON0,
+			       RG_AUDHPRPWRUP_VAUDP32_BIT, 0, NULL, 0,
+			       mt_hp_event,
+			       SND_SOC_DAPM_PRE_PMU |
+			       SND_SOC_DAPM_PRE_PMD |
+			       SND_SOC_DAPM_POST_PMD),
+
+	/* Receiver */
+	SND_SOC_DAPM_MUX("RCV Mux", SND_SOC_NOPM, 0, 0, &rcv_in_mux_control),
+
+	SND_SOC_DAPM_SUPPLY("RCV Stability Enh", MT6351_AUDDEC_ANA_CON1,
+			    RG_HSOUTPUTSTBENH_VAUDP32_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RCV Bias Gen", MT6351_AUDDEC_ANA_CON6,
+			    RG_ABIDEC_RSVD0_VAUDP32_HS_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUT_DRV("RCV Buffer", MT6351_AUDDEC_ANA_CON0,
+			     RG_AUDHSPWRUP_VAUDP32_BIT, 0, NULL, 0),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("Receiver"),
+	SND_SOC_DAPM_OUTPUT("Headphone L"),
+	SND_SOC_DAPM_OUTPUT("Headphone R"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT L"),
+
+	/* SGEN */
+	SND_SOC_DAPM_SUPPLY("SGEN DL Enable", MT6351_AFE_SGEN_CFG0,
+			    SGEN_C_DAC_EN_CTL_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("SGEN MUTE", MT6351_AFE_SGEN_CFG0,
+			    SGEN_C_MUTE_SW_CTL_BIT, 1,
+			    mt_sgen_event, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY("SGEN DL SRC", MT6351_AFE_DL_SRC2_CON0_L,
+			    RG_DL_2_SRC_ON_TMP_CTL_PRE_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_INPUT("SGEN DL"),
+
+	/* Uplinks */
+	SND_SOC_DAPM_AIF_OUT_E("AIF1TX", "AIF1 Capture", 0,
+			       MT6351_AFE_UL_SRC_CON0_L,
+			       UL_SRC_ON_TMP_CTL, 0,
+			       mt_aif_out_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_SUPPLY_S("VUSB33_LDO", SUPPLY_SUBSEQ_ENABLE,
+			      MT6351_LDO_VUSB33_CON0, RG_VUSB33_EN, 0,
+			      NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("VUSB33_LDO_CTRL", SUPPLY_SUBSEQ_SETTING,
+			      MT6351_LDO_VUSB33_CON0, RG_VUSB33_ON_CTRL, 1,
+			      NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("VA18_LDO", SUPPLY_SUBSEQ_ENABLE,
+			      MT6351_LDO_VA18_CON0, RG_VA18_EN, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("VA18_LDO_CTRL", SUPPLY_SUBSEQ_SETTING,
+			      MT6351_LDO_VA18_CON0, RG_VA18_ON_CTRL, 1,
+			      NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("ADC CLKGEN", SUPPLY_SUBSEQ_ENABLE,
+			      MT6351_AUDENC_ANA_CON3, RG_AUDADCCLKRSTB, 0,
+			      mt_adc_clkgen_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+	/* Uplinks MUX */
+	SND_SOC_DAPM_MUX("AIF Out Mux", SND_SOC_NOPM, 0, 0,
+			 &aif_out_mux_control),
+
+	SND_SOC_DAPM_MUX("ADC L Mux", SND_SOC_NOPM, 0, 0,
+			 &adc_left_mux_control),
+	SND_SOC_DAPM_MUX("ADC R Mux", SND_SOC_NOPM, 0, 0,
+			 &adc_right_mux_control),
+
+	SND_SOC_DAPM_ADC("ADC L", NULL,
+			 MT6351_AUDENC_ANA_CON0, RG_AUDADCLPWRUP, 0),
+	SND_SOC_DAPM_ADC("ADC R", NULL,
+			 MT6351_AUDENC_ANA_CON1, RG_AUDADCRPWRUP, 0),
+
+	SND_SOC_DAPM_MUX("PGA L Mux", SND_SOC_NOPM, 0, 0,
+			 &pga_left_mux_control),
+	SND_SOC_DAPM_MUX("PGA R Mux", SND_SOC_NOPM, 0, 0,
+			 &pga_right_mux_control),
+
+	SND_SOC_DAPM_PGA_E("PGA L", MT6351_AUDENC_ANA_CON0, RG_AUDPREAMPLON, 0,
+			   NULL, 0,
+			   mt_pga_left_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_E("PGA R", MT6351_AUDENC_ANA_CON1, RG_AUDPREAMPRON, 0,
+			   NULL, 0,
+			   mt_pga_right_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+	/* main mic mic bias */
+	SND_SOC_DAPM_SUPPLY_S("Mic Bias 0", SUPPLY_SUBSEQ_MICBIAS,
+			      MT6351_AUDENC_ANA_CON9, RG_AUDPWDBMICBIAS0, 0,
+			      mt_mic_bias_0_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	/* ref mic mic bias */
+	SND_SOC_DAPM_SUPPLY_S("Mic Bias 2", SUPPLY_SUBSEQ_MICBIAS,
+			      MT6351_AUDENC_ANA_CON9, RG_AUDPWDBMICBIAS2, 0,
+			      mt_mic_bias_2_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	/* headset mic1/2 mic bias */
+	SND_SOC_DAPM_SUPPLY_S("Mic Bias 1", SUPPLY_SUBSEQ_MICBIAS,
+			      MT6351_AUDENC_ANA_CON10, RG_AUDPWDBMICBIAS1, 0,
+			      mt_mic_bias_1_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("Mic Bias 1 DCC pull high", SUPPLY_SUBSEQ_MICBIAS,
+			      MT6351_AUDENC_ANA_CON10,
+			      RG_AUDMICBIAS1DCSW1NEN, 0,
+			      NULL, 0),
+
+	/* UL input */
+	SND_SOC_DAPM_INPUT("AIN0"),
+	SND_SOC_DAPM_INPUT("AIN1"),
+	SND_SOC_DAPM_INPUT("AIN2"),
+	SND_SOC_DAPM_INPUT("AIN3"),
+};
+
+static const struct snd_soc_dapm_route mt6351_dapm_routes[] = {
+	/* Capture */
+	{"AIF1TX", NULL, "AIF Out Mux"},
+	{"AIF1TX", NULL, "VUSB33_LDO"},
+	{"VUSB33_LDO", NULL, "VUSB33_LDO_CTRL"},
+	{"AIF1TX", NULL, "VA18_LDO"},
+	{"VA18_LDO", NULL, "VA18_LDO_CTRL"},
+
+	{"AIF1TX", NULL, "AUDGLB"},
+	{"AIF1TX", NULL, "CLKSQ Audio"},
+
+	{"AIF1TX", NULL, "AFE_ON"},
+
+	{"AIF1TX", NULL, "AUDIO_TOP_AFE_CTL"},
+	{"AIF1TX", NULL, "AUDIO_TOP_ADC_CTL"},
+	{"AIF1TX", NULL, "AUDIO_TOP_PWR_CLK"},
+	{"AIF1TX", NULL, "AUDIO_TOP_PDN_RESERVED"},
+
+	{"AIF Out Mux", "Normal Path", "ADC L"},
+	{"AIF Out Mux", "Normal Path", "ADC R"},
+
+	{"ADC L", NULL, "ADC L Mux"},
+	{"ADC L", NULL, "AUD_CK"},
+	{"ADC L", NULL, "AUDIF_CK"},
+	{"ADC L", NULL, "ADC CLKGEN"},
+	{"ADC R", NULL, "ADC R Mux"},
+	{"ADC R", NULL, "AUD_CK"},
+	{"ADC R", NULL, "AUDIF_CK"},
+	{"ADC R", NULL, "ADC CLKGEN"},
+
+	{"ADC L Mux", "AIN0", "AIN0"},
+	{"ADC L Mux", "Left Preamplifier", "PGA L"},
+
+	{"ADC R Mux", "AIN0", "AIN0"},
+	{"ADC R Mux", "Right Preamplifier", "PGA R"},
+
+	{"PGA L", NULL, "PGA L Mux"},
+	{"PGA R", NULL, "PGA R Mux"},
+
+	{"PGA L Mux", "AIN0", "AIN0"},
+	{"PGA L Mux", "AIN1", "AIN1"},
+	{"PGA L Mux", "AIN2", "AIN2"},
+
+	{"PGA R Mux", "AIN0", "AIN0"},
+	{"PGA R Mux", "AIN3", "AIN3"},
+	{"PGA R Mux", "AIN2", "AIN2"},
+
+	{"AIN0", NULL, "Mic Bias 0"},
+	{"AIN2", NULL, "Mic Bias 2"},
+
+	{"AIN1", NULL, "Mic Bias 1"},
+	{"AIN1", NULL, "Mic Bias 1 DCC pull high"},
+
+	/* DL Supply */
+	{"DL Power Supply", NULL, "AUDGLB"},
+	{"DL Power Supply", NULL, "CLKSQ Audio"},
+	{"DL Power Supply", NULL, "ZCD13M_CK"},
+	{"DL Power Supply", NULL, "AUD_CK"},
+	{"DL Power Supply", NULL, "AUDIF_CK"},
+	{"DL Power Supply", NULL, "AUDNCP_CK"},
+
+	{"DL Power Supply", NULL, "NV Regulator"},
+	{"DL Power Supply", NULL, "AUD_CLK"},
+	{"DL Power Supply", NULL, "IBIST"},
+	{"DL Power Supply", NULL, "LDO"},
+	{"LDO", NULL, "LDO_REMOTE_SENSE"},
+
+	/* DL Digital Supply */
+	{"DL Digital Clock", NULL, "AUDIO_TOP_AFE_CTL"},
+	{"DL Digital Clock", NULL, "AUDIO_TOP_DAC_CTL"},
+	{"DL Digital Clock", NULL, "AUDIO_TOP_PWR_CLK"},
+	{"DL Digital Clock", NULL, "AUDIO_TOP_PDN_RESERVED"},
+	{"DL Digital Clock", NULL, "NCP"},
+	{"DL Digital Clock", NULL, "AFE_ON"},
+
+	{"AIF_RX", NULL, "DL Digital Clock"},
+
+	/* DL Path */
+	{"DAC In Mux", "Normal Path", "AIF_RX"},
+
+	{"DAC In Mux", "Sgen", "SGEN DL"},
+	{"SGEN DL", NULL, "SGEN DL SRC"},
+	{"SGEN DL", NULL, "SGEN MUTE"},
+	{"SGEN DL", NULL, "SGEN DL Enable"},
+	{"SGEN DL", NULL, "DL Digital Clock"},
+
+	{"DACL", NULL, "DAC In Mux"},
+	{"DACL", NULL, "DL Power Supply"},
+	{"DACL", NULL, "DACL_BIASGEN"},
+
+	{"DACR", NULL, "DAC In Mux"},
+	{"DACR", NULL, "DL Power Supply"},
+	{"DACR", NULL, "DACR_BIASGEN"},
+
+	{"LOL Mux", "Playback", "DACL"},
+
+	{"LOL Buffer", NULL, "LOL Mux"},
+	{"LOL Buffer", NULL, "LO Stability Enh"},
+	{"LOL Buffer", NULL, "LOL Bias Gen"},
+
+	{"LINEOUT L", NULL, "LOL Buffer"},
+
+	/* Headphone Path */
+	{"HPL Mux", "Audio Playback", "DACL"},
+	{"HPR Mux", "Audio Playback", "DACR"},
+
+	{"HPL Mux", "LoudSPK Playback", "DACL"},
+	{"HPR Mux", "LoudSPK Playback", "DACR"},
+
+	{"HPL Power", NULL, "HPL Mux"},
+	{"HPR Power", NULL, "HPR Mux"},
+
+	{"Headphone L", NULL, "HPL Power"},
+	{"Headphone R", NULL, "HPR Power"},
+
+	/* Receiver Path */
+	{"RCV Mux", "Voice Playback", "DACL"},
+
+	{"RCV Buffer", NULL, "RCV Mux"},
+	{"RCV Buffer", NULL, "RCV Stability Enh"},
+	{"RCV Buffer", NULL, "RCV Bias Gen"},
+
+	{"Receiver", NULL, "RCV Buffer"},
+};
+
+static int mt6351_codec_init_reg(struct snd_soc_component *cmpnt)
+{
+	int ret = 0;
+
+	/* Disable CLKSQ 26MHz */
+	regmap_update_bits(cmpnt->regmap, MT6351_TOP_CLKSQ, 0x0001, 0x0);
+	/* disable AUDGLB */
+	regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON9,
+			   0x1000, 0x1000);
+	/* Turn off AUDNCP_CLKDIV engine clock,Turn off AUD 26M */
+	regmap_update_bits(cmpnt->regmap, MT6351_TOP_CKPDN_CON0_SET,
+			   0x3800, 0x3800);
+	/* Disable HeadphoneL/HeadphoneR/voice short circuit protection */
+	regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON0,
+			   0xe000, 0xe000);
+	/* [5] = 1, disable LO buffer left short circuit protection */
+	regmap_update_bits(cmpnt->regmap, MT6351_AUDDEC_ANA_CON3,
+			   0x20, 0x20);
+	/* Reverse the PMIC clock*/
+	regmap_update_bits(cmpnt->regmap, MT6351_AFE_PMIC_NEWIF_CFG2,
+			   0x8000, 0x8000);
+	return ret;
+}
+
+static int mt6351_codec_probe(struct snd_soc_component *cmpnt)
+{
+	struct mt6351_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	snd_soc_component_init_regmap(cmpnt, priv->regmap);
+
+	mt6351_codec_init_reg(cmpnt);
+	return 0;
+}
+
+static const struct snd_soc_component_driver mt6351_soc_component_driver = {
+	.probe = mt6351_codec_probe,
+	.controls = mt6351_snd_controls,
+	.num_controls = ARRAY_SIZE(mt6351_snd_controls),
+	.dapm_widgets = mt6351_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt6351_dapm_widgets),
+	.dapm_routes = mt6351_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(mt6351_dapm_routes),
+};
+
+static int mt6351_codec_driver_probe(struct platform_device *pdev)
+{
+	struct mt6351_priv *priv;
+
+	priv = devm_kzalloc(&pdev->dev,
+			    sizeof(struct mt6351_priv),
+			    GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	dev_set_drvdata(&pdev->dev, priv);
+
+	priv->dev = &pdev->dev;
+
+	priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!priv->regmap)
+		return -ENODEV;
+
+	dev_dbg(priv->dev, "%s(), dev name %s\n",
+		__func__, dev_name(&pdev->dev));
+
+	return devm_snd_soc_register_component(&pdev->dev,
+					       &mt6351_soc_component_driver,
+					       mt6351_dai_driver,
+					       ARRAY_SIZE(mt6351_dai_driver));
+}
+
+static const struct of_device_id mt6351_of_match[] = {
+	{.compatible = "mediatek,mt6351-sound",},
+	{}
+};
+
+static struct platform_driver mt6351_codec_driver = {
+	.driver = {
+		.name = "mt6351-sound",
+		.of_match_table = mt6351_of_match,
+	},
+	.probe = mt6351_codec_driver_probe,
+};
+
+module_platform_driver(mt6351_codec_driver)
+
+/* Module information */
+MODULE_DESCRIPTION("MT6351 ALSA SoC codec driver");
+MODULE_AUTHOR("KaiChieh Chuang <kaichieh.chuang@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/mt6351.h b/sound/soc/codecs/mt6351.h
new file mode 100644
index 0000000..04b2ab6
--- /dev/null
+++ b/sound/soc/codecs/mt6351.h
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt6351.h  --  mt6351 ALSA SoC audio codec driver
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
+ */
+
+#ifndef __MT6351_H__
+#define __MT6351_H__
+
+#define MT6351_AFE_UL_DL_CON0               (0x2000 + 0x0000)
+#define MT6351_AFE_DL_SRC2_CON0_H           (0x2000 + 0x0002)
+#define MT6351_AFE_DL_SRC2_CON0_L           (0x2000 + 0x0004)
+#define MT6351_AFE_DL_SDM_CON0              (0x2000 + 0x0006)
+#define MT6351_AFE_DL_SDM_CON1              (0x2000 + 0x0008)
+#define MT6351_AFE_UL_SRC_CON0_H            (0x2000 + 0x000a)
+#define MT6351_AFE_UL_SRC_CON0_L            (0x2000 + 0x000c)
+#define MT6351_AFE_UL_SRC_CON1_H            (0x2000 + 0x000e)
+#define MT6351_AFE_UL_SRC_CON1_L            (0x2000 + 0x0010)
+#define MT6351_AFE_TOP_CON0                 (0x2000 + 0x0012)
+#define MT6351_AUDIO_TOP_CON0               (0x2000 + 0x0014)
+#define MT6351_AFE_DL_SRC_MON0              (0x2000 + 0x0016)
+#define MT6351_AFE_DL_SDM_TEST0             (0x2000 + 0x0018)
+#define MT6351_AFE_MON_DEBUG0               (0x2000 + 0x001a)
+#define MT6351_AFUNC_AUD_CON0               (0x2000 + 0x001c)
+#define MT6351_AFUNC_AUD_CON1               (0x2000 + 0x001e)
+#define MT6351_AFUNC_AUD_CON2               (0x2000 + 0x0020)
+#define MT6351_AFUNC_AUD_CON3               (0x2000 + 0x0022)
+#define MT6351_AFUNC_AUD_CON4               (0x2000 + 0x0024)
+#define MT6351_AFUNC_AUD_MON0               (0x2000 + 0x0026)
+#define MT6351_AFUNC_AUD_MON1               (0x2000 + 0x0028)
+#define MT6351_AFE_UP8X_FIFO_CFG0           (0x2000 + 0x002c)
+#define MT6351_AFE_UP8X_FIFO_LOG_MON0       (0x2000 + 0x002e)
+#define MT6351_AFE_UP8X_FIFO_LOG_MON1       (0x2000 + 0x0030)
+#define MT6351_AFE_DL_DC_COMP_CFG0          (0x2000 + 0x0032)
+#define MT6351_AFE_DL_DC_COMP_CFG1          (0x2000 + 0x0034)
+#define MT6351_AFE_DL_DC_COMP_CFG2          (0x2000 + 0x0036)
+#define MT6351_AFE_PMIC_NEWIF_CFG0          (0x2000 + 0x0038)
+#define MT6351_AFE_PMIC_NEWIF_CFG1          (0x2000 + 0x003a)
+#define MT6351_AFE_PMIC_NEWIF_CFG2          (0x2000 + 0x003c)
+#define MT6351_AFE_PMIC_NEWIF_CFG3          (0x2000 + 0x003e)
+#define MT6351_AFE_SGEN_CFG0                (0x2000 + 0x0040)
+#define MT6351_AFE_SGEN_CFG1                (0x2000 + 0x0042)
+#define MT6351_AFE_ADDA2_UP8X_FIFO_LOG_MON0 (0x2000 + 0x004c)
+#define MT6351_AFE_ADDA2_UP8X_FIFO_LOG_MON1 (0x2000 + 0x004e)
+#define MT6351_AFE_ADDA2_PMIC_NEWIF_CFG0    (0x2000 + 0x0050)
+#define MT6351_AFE_ADDA2_PMIC_NEWIF_CFG1    (0x2000 + 0x0052)
+#define MT6351_AFE_ADDA2_PMIC_NEWIF_CFG2    (0x2000 + 0x0054)
+#define MT6351_AFE_DCCLK_CFG0               (0x2000 + 0x0090)
+#define MT6351_AFE_DCCLK_CFG1               (0x2000 + 0x0092)
+#define MT6351_AFE_HPANC_CFG0               (0x2000 + 0x0094)
+#define MT6351_AFE_NCP_CFG0                 (0x2000 + 0x0096)
+#define MT6351_AFE_NCP_CFG1                 (0x2000 + 0x0098)
+
+#define MT6351_TOP_CKPDN_CON0      0x023A
+#define MT6351_TOP_CKPDN_CON0_SET  0x023C
+#define MT6351_TOP_CKPDN_CON0_CLR  0x023E
+
+#define MT6351_TOP_CLKSQ           0x029A
+#define MT6351_TOP_CLKSQ_SET       0x029C
+#define MT6351_TOP_CLKSQ_CLR       0x029E
+
+#define MT6351_ZCD_CON0            0x0800
+#define MT6351_ZCD_CON1            0x0802
+#define MT6351_ZCD_CON2            0x0804
+#define MT6351_ZCD_CON3            0x0806
+#define MT6351_ZCD_CON4            0x0808
+#define MT6351_ZCD_CON5            0x080A
+
+#define MT6351_LDO_VA18_CON0       0x0A00
+#define MT6351_LDO_VA18_CON1       0x0A02
+#define MT6351_LDO_VUSB33_CON0     0x0A16
+#define MT6351_LDO_VUSB33_CON1     0x0A18
+
+#define MT6351_AUDDEC_ANA_CON0     0x0CF2
+#define MT6351_AUDDEC_ANA_CON1     0x0CF4
+#define MT6351_AUDDEC_ANA_CON2     0x0CF6
+#define MT6351_AUDDEC_ANA_CON3     0x0CF8
+#define MT6351_AUDDEC_ANA_CON4     0x0CFA
+#define MT6351_AUDDEC_ANA_CON5     0x0CFC
+#define MT6351_AUDDEC_ANA_CON6     0x0CFE
+#define MT6351_AUDDEC_ANA_CON7     0x0D00
+#define MT6351_AUDDEC_ANA_CON8     0x0D02
+#define MT6351_AUDDEC_ANA_CON9     0x0D04
+#define MT6351_AUDDEC_ANA_CON10    0x0D06
+
+#define MT6351_AUDENC_ANA_CON0     0x0D08
+#define MT6351_AUDENC_ANA_CON1     0x0D0A
+#define MT6351_AUDENC_ANA_CON2     0x0D0C
+#define MT6351_AUDENC_ANA_CON3     0x0D0E
+#define MT6351_AUDENC_ANA_CON4     0x0D10
+#define MT6351_AUDENC_ANA_CON5     0x0D12
+#define MT6351_AUDENC_ANA_CON6     0x0D14
+#define MT6351_AUDENC_ANA_CON7     0x0D16
+#define MT6351_AUDENC_ANA_CON8     0x0D18
+#define MT6351_AUDENC_ANA_CON9     0x0D1A
+#define MT6351_AUDENC_ANA_CON10    0x0D1C
+#define MT6351_AUDENC_ANA_CON11    0x0D1E
+#define MT6351_AUDENC_ANA_CON12    0x0D20
+#define MT6351_AUDENC_ANA_CON13    0x0D22
+#define MT6351_AUDENC_ANA_CON14    0x0D24
+#define MT6351_AUDENC_ANA_CON15    0x0D26
+#define MT6351_AUDENC_ANA_CON16    0x0D28
+#endif
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c
new file mode 100644
index 0000000..e3c8cd1
--- /dev/null
+++ b/sound/soc/codecs/nau8540.c
@@ -0,0 +1,887 @@
+/*
+ * NAU85L40 ALSA SoC audio driver
+ *
+ * Copyright 2016 Nuvoton Technology Corp.
+ * Author: John Hsu <KCHSU0@nuvoton.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include "nau8540.h"
+
+
+#define NAU_FREF_MAX 13500000
+#define NAU_FVCO_MAX 100000000
+#define NAU_FVCO_MIN 90000000
+
+/* the maximum frequency of CLK_ADC */
+#define CLK_ADC_MAX 6144000
+
+/* scaling for mclk from sysclk_src output */
+static const struct nau8540_fll_attr mclk_src_scaling[] = {
+	{ 1, 0x0 },
+	{ 2, 0x2 },
+	{ 4, 0x3 },
+	{ 8, 0x4 },
+	{ 16, 0x5 },
+	{ 32, 0x6 },
+	{ 3, 0x7 },
+	{ 6, 0xa },
+	{ 12, 0xb },
+	{ 24, 0xc },
+};
+
+/* ratio for input clk freq */
+static const struct nau8540_fll_attr fll_ratio[] = {
+	{ 512000, 0x01 },
+	{ 256000, 0x02 },
+	{ 128000, 0x04 },
+	{ 64000, 0x08 },
+	{ 32000, 0x10 },
+	{ 8000, 0x20 },
+	{ 4000, 0x40 },
+};
+
+static const struct nau8540_fll_attr fll_pre_scalar[] = {
+	{ 1, 0x0 },
+	{ 2, 0x1 },
+	{ 4, 0x2 },
+	{ 8, 0x3 },
+};
+
+/* over sampling rate */
+static const struct nau8540_osr_attr osr_adc_sel[] = {
+	{ 32, 3 },	/* OSR 32, SRC 1/8 */
+	{ 64, 2 },	/* OSR 64, SRC 1/4 */
+	{ 128, 1 },	/* OSR 128, SRC 1/2 */
+	{ 256, 0 },	/* OSR 256, SRC 1 */
+};
+
+static const struct reg_default nau8540_reg_defaults[] = {
+	{NAU8540_REG_POWER_MANAGEMENT, 0x0000},
+	{NAU8540_REG_CLOCK_CTRL, 0x0000},
+	{NAU8540_REG_CLOCK_SRC, 0x0000},
+	{NAU8540_REG_FLL1, 0x0001},
+	{NAU8540_REG_FLL2, 0x3126},
+	{NAU8540_REG_FLL3, 0x0008},
+	{NAU8540_REG_FLL4, 0x0010},
+	{NAU8540_REG_FLL5, 0xC000},
+	{NAU8540_REG_FLL6, 0x6000},
+	{NAU8540_REG_FLL_VCO_RSV, 0xF13C},
+	{NAU8540_REG_PCM_CTRL0, 0x000B},
+	{NAU8540_REG_PCM_CTRL1, 0x3010},
+	{NAU8540_REG_PCM_CTRL2, 0x0800},
+	{NAU8540_REG_PCM_CTRL3, 0x0000},
+	{NAU8540_REG_PCM_CTRL4, 0x000F},
+	{NAU8540_REG_ALC_CONTROL_1, 0x0000},
+	{NAU8540_REG_ALC_CONTROL_2, 0x700B},
+	{NAU8540_REG_ALC_CONTROL_3, 0x0022},
+	{NAU8540_REG_ALC_CONTROL_4, 0x1010},
+	{NAU8540_REG_ALC_CONTROL_5, 0x1010},
+	{NAU8540_REG_NOTCH_FIL1_CH1, 0x0000},
+	{NAU8540_REG_NOTCH_FIL2_CH1, 0x0000},
+	{NAU8540_REG_NOTCH_FIL1_CH2, 0x0000},
+	{NAU8540_REG_NOTCH_FIL2_CH2, 0x0000},
+	{NAU8540_REG_NOTCH_FIL1_CH3, 0x0000},
+	{NAU8540_REG_NOTCH_FIL2_CH3, 0x0000},
+	{NAU8540_REG_NOTCH_FIL1_CH4, 0x0000},
+	{NAU8540_REG_NOTCH_FIL2_CH4, 0x0000},
+	{NAU8540_REG_HPF_FILTER_CH12, 0x0000},
+	{NAU8540_REG_HPF_FILTER_CH34, 0x0000},
+	{NAU8540_REG_ADC_SAMPLE_RATE, 0x0002},
+	{NAU8540_REG_DIGITAL_GAIN_CH1, 0x0400},
+	{NAU8540_REG_DIGITAL_GAIN_CH2, 0x0400},
+	{NAU8540_REG_DIGITAL_GAIN_CH3, 0x0400},
+	{NAU8540_REG_DIGITAL_GAIN_CH4, 0x0400},
+	{NAU8540_REG_DIGITAL_MUX, 0x00E4},
+	{NAU8540_REG_GPIO_CTRL, 0x0000},
+	{NAU8540_REG_MISC_CTRL, 0x0000},
+	{NAU8540_REG_I2C_CTRL, 0xEFFF},
+	{NAU8540_REG_VMID_CTRL, 0x0000},
+	{NAU8540_REG_MUTE, 0x0000},
+	{NAU8540_REG_ANALOG_ADC1, 0x0011},
+	{NAU8540_REG_ANALOG_ADC2, 0x0020},
+	{NAU8540_REG_ANALOG_PWR, 0x0000},
+	{NAU8540_REG_MIC_BIAS, 0x0004},
+	{NAU8540_REG_REFERENCE, 0x0000},
+	{NAU8540_REG_FEPGA1, 0x0000},
+	{NAU8540_REG_FEPGA2, 0x0000},
+	{NAU8540_REG_FEPGA3, 0x0101},
+	{NAU8540_REG_FEPGA4, 0x0101},
+	{NAU8540_REG_PWR, 0x0000},
+};
+
+static bool nau8540_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8540_REG_POWER_MANAGEMENT ... NAU8540_REG_FLL_VCO_RSV:
+	case NAU8540_REG_PCM_CTRL0 ... NAU8540_REG_PCM_CTRL4:
+	case NAU8540_REG_ALC_CONTROL_1 ... NAU8540_REG_ALC_CONTROL_5:
+	case NAU8540_REG_ALC_GAIN_CH12 ... NAU8540_REG_ADC_SAMPLE_RATE:
+	case NAU8540_REG_DIGITAL_GAIN_CH1 ... NAU8540_REG_DIGITAL_MUX:
+	case NAU8540_REG_P2P_CH1 ... NAU8540_REG_I2C_CTRL:
+	case NAU8540_REG_I2C_DEVICE_ID:
+	case NAU8540_REG_VMID_CTRL ... NAU8540_REG_MUTE:
+	case NAU8540_REG_ANALOG_ADC1 ... NAU8540_REG_PWR:
+		return true;
+	default:
+		return false;
+	}
+
+}
+
+static bool nau8540_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8540_REG_SW_RESET ... NAU8540_REG_FLL_VCO_RSV:
+	case NAU8540_REG_PCM_CTRL0 ... NAU8540_REG_PCM_CTRL4:
+	case NAU8540_REG_ALC_CONTROL_1 ... NAU8540_REG_ALC_CONTROL_5:
+	case NAU8540_REG_NOTCH_FIL1_CH1 ... NAU8540_REG_ADC_SAMPLE_RATE:
+	case NAU8540_REG_DIGITAL_GAIN_CH1 ... NAU8540_REG_DIGITAL_MUX:
+	case NAU8540_REG_GPIO_CTRL ... NAU8540_REG_I2C_CTRL:
+	case NAU8540_REG_RST:
+	case NAU8540_REG_VMID_CTRL ... NAU8540_REG_MUTE:
+	case NAU8540_REG_ANALOG_ADC1 ... NAU8540_REG_PWR:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool nau8540_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8540_REG_SW_RESET:
+	case NAU8540_REG_ALC_GAIN_CH12 ... NAU8540_REG_ALC_STATUS:
+	case NAU8540_REG_P2P_CH1 ... NAU8540_REG_PEAK_CH4:
+	case NAU8540_REG_I2C_DEVICE_ID:
+	case NAU8540_REG_RST:
+		return true;
+	default:
+		return false;
+	}
+}
+
+
+static const DECLARE_TLV_DB_MINMAX(adc_vol_tlv, -12800, 3600);
+static const DECLARE_TLV_DB_MINMAX(fepga_gain_tlv, -100, 3600);
+
+static const struct snd_kcontrol_new nau8540_snd_controls[] = {
+	SOC_SINGLE_TLV("Mic1 Volume", NAU8540_REG_DIGITAL_GAIN_CH1,
+		0, 0x520, 0, adc_vol_tlv),
+	SOC_SINGLE_TLV("Mic2 Volume", NAU8540_REG_DIGITAL_GAIN_CH2,
+		0, 0x520, 0, adc_vol_tlv),
+	SOC_SINGLE_TLV("Mic3 Volume", NAU8540_REG_DIGITAL_GAIN_CH3,
+		0, 0x520, 0, adc_vol_tlv),
+	SOC_SINGLE_TLV("Mic4 Volume", NAU8540_REG_DIGITAL_GAIN_CH4,
+		0, 0x520, 0, adc_vol_tlv),
+
+	SOC_SINGLE_TLV("Frontend PGA1 Volume", NAU8540_REG_FEPGA3,
+		0, 0x25, 0, fepga_gain_tlv),
+	SOC_SINGLE_TLV("Frontend PGA2 Volume", NAU8540_REG_FEPGA3,
+		8, 0x25, 0, fepga_gain_tlv),
+	SOC_SINGLE_TLV("Frontend PGA3 Volume", NAU8540_REG_FEPGA4,
+		0, 0x25, 0, fepga_gain_tlv),
+	SOC_SINGLE_TLV("Frontend PGA4 Volume", NAU8540_REG_FEPGA4,
+		8, 0x25, 0, fepga_gain_tlv),
+};
+
+static const char * const adc_channel[] = {
+	"ADC channel 1", "ADC channel 2", "ADC channel 3", "ADC channel 4"
+};
+static SOC_ENUM_SINGLE_DECL(
+	digital_ch4_enum, NAU8540_REG_DIGITAL_MUX, 6, adc_channel);
+
+static const struct snd_kcontrol_new digital_ch4_mux =
+	SOC_DAPM_ENUM("Digital CH4 Select", digital_ch4_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	digital_ch3_enum, NAU8540_REG_DIGITAL_MUX, 4, adc_channel);
+
+static const struct snd_kcontrol_new digital_ch3_mux =
+	SOC_DAPM_ENUM("Digital CH3 Select", digital_ch3_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	digital_ch2_enum, NAU8540_REG_DIGITAL_MUX, 2, adc_channel);
+
+static const struct snd_kcontrol_new digital_ch2_mux =
+	SOC_DAPM_ENUM("Digital CH2 Select", digital_ch2_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	digital_ch1_enum, NAU8540_REG_DIGITAL_MUX, 0, adc_channel);
+
+static const struct snd_kcontrol_new digital_ch1_mux =
+	SOC_DAPM_ENUM("Digital CH1 Select", digital_ch1_enum);
+
+static int adc_power_control(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *k, int  event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		msleep(300);
+		/* DO12 and DO34 pad output enable */
+		regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1,
+			NAU8540_I2S_DO12_TRI, 0);
+		regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2,
+			NAU8540_I2S_DO34_TRI, 0);
+	} else if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1,
+			NAU8540_I2S_DO12_TRI, NAU8540_I2S_DO12_TRI);
+		regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2,
+			NAU8540_I2S_DO34_TRI, NAU8540_I2S_DO34_TRI);
+	}
+	return 0;
+}
+
+static int aiftx_power_control(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *k, int  event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		regmap_write(nau8540->regmap, NAU8540_REG_RST, 0x0001);
+		regmap_write(nau8540->regmap, NAU8540_REG_RST, 0x0000);
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", NAU8540_REG_MIC_BIAS, 11, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", NAU8540_REG_MIC_BIAS, 10, 0, NULL, 0),
+
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("MIC3"),
+	SND_SOC_DAPM_INPUT("MIC4"),
+
+	SND_SOC_DAPM_PGA("Frontend PGA1", NAU8540_REG_PWR, 12, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Frontend PGA2", NAU8540_REG_PWR, 13, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Frontend PGA3", NAU8540_REG_PWR, 14, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Frontend PGA4", NAU8540_REG_PWR, 15, 0, NULL, 0),
+
+	SND_SOC_DAPM_ADC_E("ADC1", NULL,
+		NAU8540_REG_POWER_MANAGEMENT, 0, 0, adc_power_control,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2", NULL,
+		NAU8540_REG_POWER_MANAGEMENT, 1, 0, adc_power_control,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_ADC_E("ADC3", NULL,
+		NAU8540_REG_POWER_MANAGEMENT, 2, 0, adc_power_control,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_ADC_E("ADC4", NULL,
+		NAU8540_REG_POWER_MANAGEMENT, 3, 0, adc_power_control,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_PGA("ADC CH1", NAU8540_REG_ANALOG_PWR, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC CH2", NAU8540_REG_ANALOG_PWR, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC CH3", NAU8540_REG_ANALOG_PWR, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC CH4", NAU8540_REG_ANALOG_PWR, 3, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("Digital CH4 Mux",
+		SND_SOC_NOPM, 0, 0, &digital_ch4_mux),
+	SND_SOC_DAPM_MUX("Digital CH3 Mux",
+		SND_SOC_NOPM, 0, 0, &digital_ch3_mux),
+	SND_SOC_DAPM_MUX("Digital CH2 Mux",
+		SND_SOC_NOPM, 0, 0, &digital_ch2_mux),
+	SND_SOC_DAPM_MUX("Digital CH1 Mux",
+		SND_SOC_NOPM, 0, 0, &digital_ch1_mux),
+
+	SND_SOC_DAPM_AIF_OUT_E("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0,
+		aiftx_power_control, SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route nau8540_dapm_routes[] = {
+	{"Frontend PGA1", NULL, "MIC1"},
+	{"Frontend PGA2", NULL, "MIC2"},
+	{"Frontend PGA3", NULL, "MIC3"},
+	{"Frontend PGA4", NULL, "MIC4"},
+
+	{"ADC1", NULL, "Frontend PGA1"},
+	{"ADC2", NULL, "Frontend PGA2"},
+	{"ADC3", NULL, "Frontend PGA3"},
+	{"ADC4", NULL, "Frontend PGA4"},
+
+	{"ADC CH1", NULL, "ADC1"},
+	{"ADC CH2", NULL, "ADC2"},
+	{"ADC CH3", NULL, "ADC3"},
+	{"ADC CH4", NULL, "ADC4"},
+
+	{"ADC1", NULL, "MICBIAS1"},
+	{"ADC2", NULL, "MICBIAS1"},
+	{"ADC3", NULL, "MICBIAS2"},
+	{"ADC4", NULL, "MICBIAS2"},
+
+	{"Digital CH1 Mux", "ADC channel 1", "ADC CH1"},
+	{"Digital CH1 Mux", "ADC channel 2", "ADC CH2"},
+	{"Digital CH1 Mux", "ADC channel 3", "ADC CH3"},
+	{"Digital CH1 Mux", "ADC channel 4", "ADC CH4"},
+
+	{"Digital CH2 Mux", "ADC channel 1", "ADC CH1"},
+	{"Digital CH2 Mux", "ADC channel 2", "ADC CH2"},
+	{"Digital CH2 Mux", "ADC channel 3", "ADC CH3"},
+	{"Digital CH2 Mux", "ADC channel 4", "ADC CH4"},
+
+	{"Digital CH3 Mux", "ADC channel 1", "ADC CH1"},
+	{"Digital CH3 Mux", "ADC channel 2", "ADC CH2"},
+	{"Digital CH3 Mux", "ADC channel 3", "ADC CH3"},
+	{"Digital CH3 Mux", "ADC channel 4", "ADC CH4"},
+
+	{"Digital CH4 Mux", "ADC channel 1", "ADC CH1"},
+	{"Digital CH4 Mux", "ADC channel 2", "ADC CH2"},
+	{"Digital CH4 Mux", "ADC channel 3", "ADC CH3"},
+	{"Digital CH4 Mux", "ADC channel 4", "ADC CH4"},
+
+	{"AIFTX", NULL, "Digital CH1 Mux"},
+	{"AIFTX", NULL, "Digital CH2 Mux"},
+	{"AIFTX", NULL, "Digital CH3 Mux"},
+	{"AIFTX", NULL, "Digital CH4 Mux"},
+};
+
+static int nau8540_clock_check(struct nau8540 *nau8540, int rate, int osr)
+{
+	if (osr >= ARRAY_SIZE(osr_adc_sel))
+		return -EINVAL;
+
+	if (rate * osr > CLK_ADC_MAX) {
+		dev_err(nau8540->dev, "exceed the maximum frequency of CLK_ADC\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int nau8540_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0, osr;
+
+	/* CLK_ADC = OSR * FS
+	 * ADC clock frequency is defined as Over Sampling Rate (OSR)
+	 * multiplied by the audio sample rate (Fs). Note that the OSR and Fs
+	 * values must be selected such that the maximum frequency is less
+	 * than 6.144 MHz.
+	 */
+	regmap_read(nau8540->regmap, NAU8540_REG_ADC_SAMPLE_RATE, &osr);
+	osr &= NAU8540_ADC_OSR_MASK;
+	if (nau8540_clock_check(nau8540, params_rate(params), osr))
+		return -EINVAL;
+	regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC,
+		NAU8540_CLK_ADC_SRC_MASK,
+		osr_adc_sel[osr].clk_src << NAU8540_CLK_ADC_SRC_SFT);
+
+	switch (params_width(params)) {
+	case 16:
+		val_len |= NAU8540_I2S_DL_16;
+		break;
+	case 20:
+		val_len |= NAU8540_I2S_DL_20;
+		break;
+	case 24:
+		val_len |= NAU8540_I2S_DL_24;
+		break;
+	case 32:
+		val_len |= NAU8540_I2S_DL_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL0,
+		NAU8540_I2S_DL_MASK, val_len);
+
+	return 0;
+}
+
+static int nau8540_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
+	unsigned int ctrl1_val = 0, ctrl2_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		ctrl2_val |= NAU8540_I2S_MS_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		ctrl1_val |= NAU8540_I2S_BP_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		ctrl1_val |= NAU8540_I2S_DF_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ctrl1_val |= NAU8540_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		ctrl1_val |= NAU8540_I2S_DF_RIGTH;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		ctrl1_val |= NAU8540_I2S_DF_PCM_AB;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		ctrl1_val |= NAU8540_I2S_DF_PCM_AB;
+		ctrl1_val |= NAU8540_I2S_PCMB_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL0,
+		NAU8540_I2S_DL_MASK | NAU8540_I2S_DF_MASK |
+		NAU8540_I2S_BP_INV | NAU8540_I2S_PCMB_EN, ctrl1_val);
+	regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1,
+		NAU8540_I2S_MS_MASK | NAU8540_I2S_DO12_OE, ctrl2_val);
+	regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2,
+		NAU8540_I2S_DO34_OE, 0);
+
+	return 0;
+}
+
+/**
+ * nau8540_set_tdm_slot - configure DAI TX TDM.
+ * @dai: DAI
+ * @tx_mask: bitmask representing active TX slots. Ex.
+ *                 0xf for normal 4 channel TDM.
+ *                 0xf0 for shifted 4 channel TDM
+ * @rx_mask: no used.
+ * @slots: Number of slots in use.
+ * @slot_width: Width in bits for each slot.
+ *
+ * Configures a DAI for TDM operation. Only support 4 slots TDM.
+ */
+static int nau8540_set_tdm_slot(struct snd_soc_dai *dai,
+	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
+	unsigned int ctrl2_val = 0, ctrl4_val = 0;
+
+	if (slots > 4 || ((tx_mask & 0xf0) && (tx_mask & 0xf)))
+		return -EINVAL;
+
+	ctrl4_val |= (NAU8540_TDM_MODE | NAU8540_TDM_OFFSET_EN);
+	if (tx_mask & 0xf0) {
+		ctrl2_val = 4 * slot_width;
+		ctrl4_val |= (tx_mask >> 4);
+	} else {
+		ctrl4_val |= tx_mask;
+	}
+	regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL4,
+		NAU8540_TDM_MODE | NAU8540_TDM_OFFSET_EN |
+		NAU8540_TDM_TX_MASK, ctrl4_val);
+	regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1,
+		NAU8540_I2S_DO12_OE, NAU8540_I2S_DO12_OE);
+	regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2,
+		NAU8540_I2S_DO34_OE | NAU8540_I2S_TSLOT_L_MASK,
+		NAU8540_I2S_DO34_OE | ctrl2_val);
+
+	return 0;
+}
+
+
+static const struct snd_soc_dai_ops nau8540_dai_ops = {
+	.hw_params = nau8540_hw_params,
+	.set_fmt = nau8540_set_fmt,
+	.set_tdm_slot = nau8540_set_tdm_slot,
+};
+
+#define NAU8540_RATES SNDRV_PCM_RATE_8000_48000
+#define NAU8540_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+	 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver nau8540_dai = {
+	.name = "nau8540-hifi",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 4,
+		.rates = NAU8540_RATES,
+		.formats = NAU8540_FORMATS,
+	},
+	.ops = &nau8540_dai_ops,
+};
+
+/**
+ * nau8540_calc_fll_param - Calculate FLL parameters.
+ * @fll_in: external clock provided to codec.
+ * @fs: sampling rate.
+ * @fll_param: Pointer to structure of FLL parameters.
+ *
+ * Calculate FLL parameters to configure codec.
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int nau8540_calc_fll_param(unsigned int fll_in,
+	unsigned int fs, struct nau8540_fll *fll_param)
+{
+	u64 fvco, fvco_max;
+	unsigned int fref, i, fvco_sel;
+
+	/* Ensure the reference clock frequency (FREF) is <= 13.5MHz by dividing
+	 * freq_in by 1, 2, 4, or 8 using FLL pre-scalar.
+	 * FREF = freq_in / NAU8540_FLL_REF_DIV_MASK
+	 */
+	for (i = 0; i < ARRAY_SIZE(fll_pre_scalar); i++) {
+		fref = fll_in / fll_pre_scalar[i].param;
+		if (fref <= NAU_FREF_MAX)
+			break;
+	}
+	if (i == ARRAY_SIZE(fll_pre_scalar))
+		return -EINVAL;
+	fll_param->clk_ref_div = fll_pre_scalar[i].val;
+
+	/* Choose the FLL ratio based on FREF */
+	for (i = 0; i < ARRAY_SIZE(fll_ratio); i++) {
+		if (fref >= fll_ratio[i].param)
+			break;
+	}
+	if (i == ARRAY_SIZE(fll_ratio))
+		return -EINVAL;
+	fll_param->ratio = fll_ratio[i].val;
+
+	/* Calculate the frequency of DCO (FDCO) given freq_out = 256 * Fs.
+	 * FDCO must be within the 90MHz - 124MHz or the FFL cannot be
+	 * guaranteed across the full range of operation.
+	 * FDCO = freq_out * 2 * mclk_src_scaling
+	 */
+	fvco_max = 0;
+	fvco_sel = ARRAY_SIZE(mclk_src_scaling);
+	for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) {
+		fvco = 256 * fs * 2 * mclk_src_scaling[i].param;
+		if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX &&
+			fvco_max < fvco) {
+			fvco_max = fvco;
+			fvco_sel = i;
+		}
+	}
+	if (ARRAY_SIZE(mclk_src_scaling) == fvco_sel)
+		return -EINVAL;
+	fll_param->mclk_src = mclk_src_scaling[fvco_sel].val;
+
+	/* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional
+	 * input based on FDCO, FREF and FLL ratio.
+	 */
+	fvco = div_u64(fvco_max << 16, fref * fll_param->ratio);
+	fll_param->fll_int = (fvco >> 16) & 0x3FF;
+	fll_param->fll_frac = fvco & 0xFFFF;
+	return 0;
+}
+
+static void nau8540_fll_apply(struct regmap *regmap,
+	struct nau8540_fll *fll_param)
+{
+	regmap_update_bits(regmap, NAU8540_REG_CLOCK_SRC,
+		NAU8540_CLK_SRC_MASK | NAU8540_CLK_MCLK_SRC_MASK,
+		NAU8540_CLK_SRC_MCLK | fll_param->mclk_src);
+	regmap_update_bits(regmap, NAU8540_REG_FLL1,
+		NAU8540_FLL_RATIO_MASK | NAU8540_ICTRL_LATCH_MASK,
+		fll_param->ratio | (0x6 << NAU8540_ICTRL_LATCH_SFT));
+	/* FLL 16-bit fractional input */
+	regmap_write(regmap, NAU8540_REG_FLL2, fll_param->fll_frac);
+	/* FLL 10-bit integer input */
+	regmap_update_bits(regmap, NAU8540_REG_FLL3,
+		NAU8540_FLL_INTEGER_MASK, fll_param->fll_int);
+	/* FLL pre-scaler */
+	regmap_update_bits(regmap, NAU8540_REG_FLL4,
+		NAU8540_FLL_REF_DIV_MASK,
+		fll_param->clk_ref_div << NAU8540_FLL_REF_DIV_SFT);
+	regmap_update_bits(regmap, NAU8540_REG_FLL5,
+		NAU8540_FLL_CLK_SW_MASK, NAU8540_FLL_CLK_SW_REF);
+	regmap_update_bits(regmap,
+		NAU8540_REG_FLL6, NAU8540_DCO_EN, 0);
+	if (fll_param->fll_frac) {
+		regmap_update_bits(regmap, NAU8540_REG_FLL5,
+			NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN |
+			NAU8540_FLL_FTR_SW_MASK,
+			NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN |
+			NAU8540_FLL_FTR_SW_FILTER);
+		regmap_update_bits(regmap, NAU8540_REG_FLL6,
+			NAU8540_SDM_EN | NAU8540_CUTOFF500,
+			NAU8540_SDM_EN | NAU8540_CUTOFF500);
+	} else {
+		regmap_update_bits(regmap, NAU8540_REG_FLL5,
+			NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN |
+			NAU8540_FLL_FTR_SW_MASK, NAU8540_FLL_FTR_SW_ACCU);
+		regmap_update_bits(regmap, NAU8540_REG_FLL6,
+			NAU8540_SDM_EN | NAU8540_CUTOFF500, 0);
+	}
+}
+
+/* freq_out must be 256*Fs in order to achieve the best performance */
+static int nau8540_set_pll(struct snd_soc_component *component, int pll_id, int source,
+		unsigned int freq_in, unsigned int freq_out)
+{
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
+	struct nau8540_fll fll_param;
+	int ret, fs;
+
+	switch (pll_id) {
+	case NAU8540_CLK_FLL_MCLK:
+		regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
+			NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK,
+			NAU8540_FLL_CLK_SRC_MCLK | 0);
+		break;
+
+	case NAU8540_CLK_FLL_BLK:
+		regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
+			NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK,
+			NAU8540_FLL_CLK_SRC_BLK |
+			(0xf << NAU8540_GAIN_ERR_SFT));
+		break;
+
+	case NAU8540_CLK_FLL_FS:
+		regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
+			NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK,
+			NAU8540_FLL_CLK_SRC_FS |
+			(0xf << NAU8540_GAIN_ERR_SFT));
+		break;
+
+	default:
+		dev_err(nau8540->dev, "Invalid clock id (%d)\n", pll_id);
+		return -EINVAL;
+	}
+	dev_dbg(nau8540->dev, "Sysclk is %dHz and clock id is %d\n",
+		freq_out, pll_id);
+
+	fs = freq_out / 256;
+	ret = nau8540_calc_fll_param(freq_in, fs, &fll_param);
+	if (ret < 0) {
+		dev_err(nau8540->dev, "Unsupported input clock %d\n", freq_in);
+		return ret;
+	}
+	dev_dbg(nau8540->dev, "mclk_src=%x ratio=%x fll_frac=%x fll_int=%x clk_ref_div=%x\n",
+		fll_param.mclk_src, fll_param.ratio, fll_param.fll_frac,
+		fll_param.fll_int, fll_param.clk_ref_div);
+
+	nau8540_fll_apply(nau8540->regmap, &fll_param);
+	mdelay(2);
+	regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC,
+		NAU8540_CLK_SRC_MASK, NAU8540_CLK_SRC_VCO);
+
+	return 0;
+}
+
+static int nau8540_set_sysclk(struct snd_soc_component *component,
+	int clk_id, int source, unsigned int freq, int dir)
+{
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case NAU8540_CLK_DIS:
+	case NAU8540_CLK_MCLK:
+		regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC,
+			NAU8540_CLK_SRC_MASK, NAU8540_CLK_SRC_MCLK);
+		regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL6,
+			NAU8540_DCO_EN, 0);
+		break;
+
+	case NAU8540_CLK_INTERNAL:
+		regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL6,
+			NAU8540_DCO_EN, NAU8540_DCO_EN);
+		regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC,
+			NAU8540_CLK_SRC_MASK, NAU8540_CLK_SRC_VCO);
+		break;
+
+	default:
+		dev_err(nau8540->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+
+	dev_dbg(nau8540->dev, "Sysclk is %dHz and clock id is %d\n",
+		freq, clk_id);
+
+	return 0;
+}
+
+static void nau8540_reset_chip(struct regmap *regmap)
+{
+	regmap_write(regmap, NAU8540_REG_SW_RESET, 0x00);
+	regmap_write(regmap, NAU8540_REG_SW_RESET, 0x00);
+}
+
+static void nau8540_init_regs(struct nau8540 *nau8540)
+{
+	struct regmap *regmap = nau8540->regmap;
+
+	/* Enable Bias/VMID/VMID Tieoff */
+	regmap_update_bits(regmap, NAU8540_REG_VMID_CTRL,
+		NAU8540_VMID_EN | NAU8540_VMID_SEL_MASK,
+		NAU8540_VMID_EN | (0x2 << NAU8540_VMID_SEL_SFT));
+	regmap_update_bits(regmap, NAU8540_REG_REFERENCE,
+		NAU8540_PRECHARGE_DIS | NAU8540_GLOBAL_BIAS_EN,
+		NAU8540_PRECHARGE_DIS | NAU8540_GLOBAL_BIAS_EN);
+	mdelay(2);
+	regmap_update_bits(regmap, NAU8540_REG_MIC_BIAS,
+		NAU8540_PU_PRE, NAU8540_PU_PRE);
+	regmap_update_bits(regmap, NAU8540_REG_CLOCK_CTRL,
+		NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN,
+		NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN);
+	/* ADC OSR selection, CLK_ADC = Fs * OSR;
+	 * Channel time alignment enable.
+	 */
+	regmap_update_bits(regmap, NAU8540_REG_ADC_SAMPLE_RATE,
+		NAU8540_CH_SYNC | NAU8540_ADC_OSR_MASK,
+		NAU8540_CH_SYNC | NAU8540_ADC_OSR_64);
+	/* PGA input mode selection */
+	regmap_update_bits(regmap, NAU8540_REG_FEPGA1,
+		NAU8540_FEPGA1_MODCH2_SHT | NAU8540_FEPGA1_MODCH1_SHT,
+		NAU8540_FEPGA1_MODCH2_SHT | NAU8540_FEPGA1_MODCH1_SHT);
+	regmap_update_bits(regmap, NAU8540_REG_FEPGA2,
+		NAU8540_FEPGA2_MODCH4_SHT | NAU8540_FEPGA2_MODCH3_SHT,
+		NAU8540_FEPGA2_MODCH4_SHT | NAU8540_FEPGA2_MODCH3_SHT);
+	/* DO12 and DO34 pad output disable */
+	regmap_update_bits(regmap, NAU8540_REG_PCM_CTRL1,
+		NAU8540_I2S_DO12_TRI, NAU8540_I2S_DO12_TRI);
+	regmap_update_bits(regmap, NAU8540_REG_PCM_CTRL2,
+		NAU8540_I2S_DO34_TRI, NAU8540_I2S_DO34_TRI);
+}
+
+static int __maybe_unused nau8540_suspend(struct snd_soc_component *component)
+{
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(nau8540->regmap, true);
+	regcache_mark_dirty(nau8540->regmap);
+
+	return 0;
+}
+
+static int __maybe_unused nau8540_resume(struct snd_soc_component *component)
+{
+	struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(nau8540->regmap, false);
+	regcache_sync(nau8540->regmap);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver nau8540_component_driver = {
+	.set_sysclk		= nau8540_set_sysclk,
+	.set_pll		= nau8540_set_pll,
+	.suspend		= nau8540_suspend,
+	.resume			= nau8540_resume,
+	.controls		= nau8540_snd_controls,
+	.num_controls		= ARRAY_SIZE(nau8540_snd_controls),
+	.dapm_widgets		= nau8540_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(nau8540_dapm_widgets),
+	.dapm_routes		= nau8540_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(nau8540_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config nau8540_regmap_config = {
+	.val_bits = 16,
+	.reg_bits = 16,
+
+	.max_register = NAU8540_REG_MAX,
+	.readable_reg = nau8540_readable_reg,
+	.writeable_reg = nau8540_writeable_reg,
+	.volatile_reg = nau8540_volatile_reg,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = nau8540_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(nau8540_reg_defaults),
+};
+
+static int nau8540_i2c_probe(struct i2c_client *i2c,
+	const struct i2c_device_id *id)
+{
+	struct device *dev = &i2c->dev;
+	struct nau8540 *nau8540 = dev_get_platdata(dev);
+	int ret, value;
+
+	if (!nau8540) {
+		nau8540 = devm_kzalloc(dev, sizeof(*nau8540), GFP_KERNEL);
+		if (!nau8540)
+			return -ENOMEM;
+	}
+	i2c_set_clientdata(i2c, nau8540);
+
+	nau8540->regmap = devm_regmap_init_i2c(i2c, &nau8540_regmap_config);
+	if (IS_ERR(nau8540->regmap))
+		return PTR_ERR(nau8540->regmap);
+	ret = regmap_read(nau8540->regmap, NAU8540_REG_I2C_DEVICE_ID, &value);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read device id from the NAU85L40: %d\n",
+			ret);
+		return ret;
+	}
+
+	nau8540->dev = dev;
+	nau8540_reset_chip(nau8540->regmap);
+	nau8540_init_regs(nau8540);
+
+	return devm_snd_soc_register_component(dev,
+		&nau8540_component_driver, &nau8540_dai, 1);
+}
+
+static const struct i2c_device_id nau8540_i2c_ids[] = {
+	{ "nau8540", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, nau8540_i2c_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id nau8540_of_ids[] = {
+	{ .compatible = "nuvoton,nau8540", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, nau8540_of_ids);
+#endif
+
+static struct i2c_driver nau8540_i2c_driver = {
+	.driver = {
+		.name = "nau8540",
+		.of_match_table = of_match_ptr(nau8540_of_ids),
+	},
+	.probe = nau8540_i2c_probe,
+	.id_table = nau8540_i2c_ids,
+};
+module_i2c_driver(nau8540_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC NAU85L40 driver");
+MODULE_AUTHOR("John Hsu <KCHSU0@nuvoton.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/nau8540.h b/sound/soc/codecs/nau8540.h
new file mode 100644
index 0000000..732b490
--- /dev/null
+++ b/sound/soc/codecs/nau8540.h
@@ -0,0 +1,242 @@
+/*
+ * NAU85L40 ALSA SoC audio driver
+ *
+ * Copyright 2016 Nuvoton Technology Corp.
+ * Author: John Hsu <KCHSU0@nuvoton.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __NAU8540_H__
+#define __NAU8540_H__
+
+#define NAU8540_REG_SW_RESET			0x00
+#define NAU8540_REG_POWER_MANAGEMENT	0x01
+#define NAU8540_REG_CLOCK_CTRL		0x02
+#define NAU8540_REG_CLOCK_SRC			0x03
+#define NAU8540_REG_FLL1			0x04
+#define NAU8540_REG_FLL2			0x05
+#define NAU8540_REG_FLL3			0x06
+#define NAU8540_REG_FLL4			0x07
+#define NAU8540_REG_FLL5			0x08
+#define NAU8540_REG_FLL6			0x09
+#define NAU8540_REG_FLL_VCO_RSV		0x0A
+#define NAU8540_REG_PCM_CTRL0			0x10
+#define NAU8540_REG_PCM_CTRL1			0x11
+#define NAU8540_REG_PCM_CTRL2			0x12
+#define NAU8540_REG_PCM_CTRL3			0x13
+#define NAU8540_REG_PCM_CTRL4			0x14
+#define NAU8540_REG_ALC_CONTROL_1		0x20
+#define NAU8540_REG_ALC_CONTROL_2		0x21
+#define NAU8540_REG_ALC_CONTROL_3		0x22
+#define NAU8540_REG_ALC_CONTROL_4		0x23
+#define NAU8540_REG_ALC_CONTROL_5		0x24
+#define NAU8540_REG_ALC_GAIN_CH12		0x2D
+#define NAU8540_REG_ALC_GAIN_CH34		0x2E
+#define NAU8540_REG_ALC_STATUS		0x2F
+#define NAU8540_REG_NOTCH_FIL1_CH1		0x30
+#define NAU8540_REG_NOTCH_FIL2_CH1		0x31
+#define NAU8540_REG_NOTCH_FIL1_CH2		0x32
+#define NAU8540_REG_NOTCH_FIL2_CH2		0x33
+#define NAU8540_REG_NOTCH_FIL1_CH3		0x34
+#define NAU8540_REG_NOTCH_FIL2_CH3		0x35
+#define NAU8540_REG_NOTCH_FIL1_CH4		0x36
+#define NAU8540_REG_NOTCH_FIL2_CH4		0x37
+#define NAU8540_REG_HPF_FILTER_CH12		0x38
+#define NAU8540_REG_HPF_FILTER_CH34		0x39
+#define NAU8540_REG_ADC_SAMPLE_RATE		0x3A
+#define NAU8540_REG_DIGITAL_GAIN_CH1		0x40
+#define NAU8540_REG_DIGITAL_GAIN_CH2		0x41
+#define NAU8540_REG_DIGITAL_GAIN_CH3		0x42
+#define NAU8540_REG_DIGITAL_GAIN_CH4		0x43
+#define NAU8540_REG_DIGITAL_MUX		0x44
+#define NAU8540_REG_P2P_CH1			0x48
+#define NAU8540_REG_P2P_CH2			0x49
+#define NAU8540_REG_P2P_CH3			0x4A
+#define NAU8540_REG_P2P_CH4			0x4B
+#define NAU8540_REG_PEAK_CH1			0x4C
+#define NAU8540_REG_PEAK_CH2			0x4D
+#define NAU8540_REG_PEAK_CH3			0x4E
+#define NAU8540_REG_PEAK_CH4			0x4F
+#define NAU8540_REG_GPIO_CTRL			0x50
+#define NAU8540_REG_MISC_CTRL			0x51
+#define NAU8540_REG_I2C_CTRL			0x52
+#define NAU8540_REG_I2C_DEVICE_ID		0x58
+#define NAU8540_REG_RST			0x5A
+#define NAU8540_REG_VMID_CTRL			0x60
+#define NAU8540_REG_MUTE			0x61
+#define NAU8540_REG_ANALOG_ADC1		0x64
+#define NAU8540_REG_ANALOG_ADC2		0x65
+#define NAU8540_REG_ANALOG_PWR		0x66
+#define NAU8540_REG_MIC_BIAS			0x67
+#define NAU8540_REG_REFERENCE			0x68
+#define NAU8540_REG_FEPGA1			0x69
+#define NAU8540_REG_FEPGA2			0x6A
+#define NAU8540_REG_FEPGA3			0x6B
+#define NAU8540_REG_FEPGA4			0x6C
+#define NAU8540_REG_PWR			0x6D
+#define NAU8540_REG_MAX			NAU8540_REG_PWR
+
+
+/* POWER_MANAGEMENT (0x01) */
+#define NAU8540_ADC4_EN		(0x1 << 3)
+#define NAU8540_ADC3_EN		(0x1 << 2)
+#define NAU8540_ADC2_EN		(0x1 << 1)
+#define NAU8540_ADC1_EN		0x1
+
+/* CLOCK_CTRL (0x02) */
+#define NAU8540_CLK_ADC_EN		(0x1 << 15)
+#define NAU8540_CLK_I2S_EN		(0x1 << 1)
+
+/* CLOCK_SRC (0x03) */
+#define NAU8540_CLK_SRC_SFT		15
+#define NAU8540_CLK_SRC_MASK		(1 << NAU8540_CLK_SRC_SFT)
+#define NAU8540_CLK_SRC_VCO		(1 << NAU8540_CLK_SRC_SFT)
+#define NAU8540_CLK_SRC_MCLK		(0 << NAU8540_CLK_SRC_SFT)
+#define NAU8540_CLK_ADC_SRC_SFT	6
+#define NAU8540_CLK_ADC_SRC_MASK	(0x3 << NAU8540_CLK_ADC_SRC_SFT)
+#define NAU8540_CLK_MCLK_SRC_MASK	0xf
+
+/* FLL1 (0x04) */
+#define NAU8540_ICTRL_LATCH_SFT	10
+#define NAU8540_ICTRL_LATCH_MASK	(0x7 << NAU8540_ICTRL_LATCH_SFT)
+#define NAU8540_FLL_RATIO_MASK	0x7f
+
+/* FLL3 (0x06) */
+#define NAU8540_GAIN_ERR_SFT		12
+#define NAU8540_GAIN_ERR_MASK		(0xf << NAU8540_GAIN_ERR_SFT)
+#define NAU8540_FLL_CLK_SRC_SFT	10
+#define NAU8540_FLL_CLK_SRC_MASK	(0x3 << NAU8540_FLL_CLK_SRC_SFT)
+#define NAU8540_FLL_CLK_SRC_MCLK	(0 << NAU8540_FLL_CLK_SRC_SFT)
+#define NAU8540_FLL_CLK_SRC_BLK	(0x2 << NAU8540_FLL_CLK_SRC_SFT)
+#define NAU8540_FLL_CLK_SRC_FS		(0x3 << NAU8540_FLL_CLK_SRC_SFT)
+#define NAU8540_FLL_INTEGER_MASK	0x3ff
+
+/* FLL4 (0x07) */
+#define NAU8540_FLL_REF_DIV_SFT	10
+#define NAU8540_FLL_REF_DIV_MASK	(0x3 << NAU8540_FLL_REF_DIV_SFT)
+
+/* FLL5 (0x08) */
+#define NAU8540_FLL_PDB_DAC_EN	(0x1 << 15)
+#define NAU8540_FLL_LOOP_FTR_EN	(0x1 << 14)
+#define NAU8540_FLL_CLK_SW_MASK	(0x1 << 13)
+#define NAU8540_FLL_CLK_SW_N2		(0x1 << 13)
+#define NAU8540_FLL_CLK_SW_REF	(0x0 << 13)
+#define NAU8540_FLL_FTR_SW_MASK	(0x1 << 12)
+#define NAU8540_FLL_FTR_SW_ACCU	(0x1 << 12)
+#define NAU8540_FLL_FTR_SW_FILTER	(0x0 << 12)
+
+/* FLL6 (0x9) */
+#define NAU8540_DCO_EN			(0x1 << 15)
+#define NAU8540_SDM_EN			(0x1 << 14)
+#define NAU8540_CUTOFF500		(0x1 << 13)
+
+/* PCM_CTRL0 (0x10) */
+#define NAU8540_I2S_BP_SFT		7
+#define NAU8540_I2S_BP_INV		(0x1 << NAU8540_I2S_BP_SFT)
+#define NAU8540_I2S_PCMB_SFT		6
+#define NAU8540_I2S_PCMB_EN		(0x1 << NAU8540_I2S_PCMB_SFT)
+#define NAU8540_I2S_DL_SFT		2
+#define NAU8540_I2S_DL_MASK		(0x3 << NAU8540_I2S_DL_SFT)
+#define NAU8540_I2S_DL_16		(0 << NAU8540_I2S_DL_SFT)
+#define NAU8540_I2S_DL_20		(0x1 << NAU8540_I2S_DL_SFT)
+#define NAU8540_I2S_DL_24		(0x2 << NAU8540_I2S_DL_SFT)
+#define NAU8540_I2S_DL_32		(0x3 << NAU8540_I2S_DL_SFT)
+#define NAU8540_I2S_DF_MASK		0x3
+#define NAU8540_I2S_DF_RIGTH		0
+#define NAU8540_I2S_DF_LEFT		0x1
+#define NAU8540_I2S_DF_I2S		0x2
+#define NAU8540_I2S_DF_PCM_AB		0x3
+
+/* PCM_CTRL1 (0x11) */
+#define NAU8540_I2S_DO12_TRI		(0x1 << 15)
+#define NAU8540_I2S_LRC_DIV_SFT	12
+#define NAU8540_I2S_LRC_DIV_MASK	(0x3 << NAU8540_I2S_LRC_DIV_SFT)
+#define NAU8540_I2S_DO12_OE		(0x1 << 4)
+#define NAU8540_I2S_MS_SFT		3
+#define NAU8540_I2S_MS_MASK		(0x1 << NAU8540_I2S_MS_SFT)
+#define NAU8540_I2S_MS_MASTER		(0x1 << NAU8540_I2S_MS_SFT)
+#define NAU8540_I2S_MS_SLAVE		(0x0 << NAU8540_I2S_MS_SFT)
+#define NAU8540_I2S_BLK_DIV_MASK	0x7
+
+/* PCM_CTRL1 (0x12) */
+#define NAU8540_I2S_DO34_TRI		(0x1 << 15)
+#define NAU8540_I2S_DO34_OE		(0x1 << 11)
+#define NAU8540_I2S_TSLOT_L_MASK	0x3ff
+
+/* PCM_CTRL4 (0x14) */
+#define NAU8540_TDM_MODE		(0x1 << 15)
+#define NAU8540_TDM_OFFSET_EN		(0x1 << 14)
+#define NAU8540_TDM_TX_MASK		0xf
+
+/* ADC_SAMPLE_RATE (0x3A) */
+#define NAU8540_CH_SYNC		(0x1 << 14)
+#define NAU8540_ADC_OSR_MASK		0x3
+#define NAU8540_ADC_OSR_256		0x3
+#define NAU8540_ADC_OSR_128		0x2
+#define NAU8540_ADC_OSR_64		0x1
+#define NAU8540_ADC_OSR_32		0x0
+
+/* VMID_CTRL (0x60) */
+#define NAU8540_VMID_EN		(1 << 6)
+#define NAU8540_VMID_SEL_SFT		4
+#define NAU8540_VMID_SEL_MASK		(0x3 << NAU8540_VMID_SEL_SFT)
+
+/* MIC_BIAS (0x67) */
+#define NAU8540_PU_PRE			(0x1 << 8)
+
+/* REFERENCE (0x68) */
+#define NAU8540_PRECHARGE_DIS		(0x1 << 13)
+#define NAU8540_GLOBAL_BIAS_EN	(0x1 << 12)
+
+/* FEPGA1 (0x69) */
+#define NAU8540_FEPGA1_MODCH2_SHT_SFT	7
+#define NAU8540_FEPGA1_MODCH2_SHT	(0x1 << NAU8540_FEPGA1_MODCH2_SHT_SFT)
+#define NAU8540_FEPGA1_MODCH1_SHT_SFT	3
+#define NAU8540_FEPGA1_MODCH1_SHT	(0x1 << NAU8540_FEPGA1_MODCH1_SHT_SFT)
+
+/* FEPGA2 (0x6A) */
+#define NAU8540_FEPGA2_MODCH4_SHT_SFT	7
+#define NAU8540_FEPGA2_MODCH4_SHT	(0x1 << NAU8540_FEPGA2_MODCH4_SHT_SFT)
+#define NAU8540_FEPGA2_MODCH3_SHT_SFT	3
+#define NAU8540_FEPGA2_MODCH3_SHT	(0x1 << NAU8540_FEPGA2_MODCH3_SHT_SFT)
+
+
+/* System Clock Source */
+enum {
+	NAU8540_CLK_DIS,
+	NAU8540_CLK_MCLK,
+	NAU8540_CLK_INTERNAL,
+	NAU8540_CLK_FLL_MCLK,
+	NAU8540_CLK_FLL_BLK,
+	NAU8540_CLK_FLL_FS,
+};
+
+struct nau8540 {
+	struct device *dev;
+	struct regmap *regmap;
+};
+
+struct nau8540_fll {
+	int mclk_src;
+	int ratio;
+	int fll_frac;
+	int fll_int;
+	int clk_ref_div;
+};
+
+struct nau8540_fll_attr {
+	unsigned int param;
+	unsigned int val;
+};
+
+/* over sampling rate */
+struct nau8540_osr_attr {
+	unsigned int osr;
+	unsigned int clk_src;
+};
+
+
+#endif	/* __NAU8540_H__ */
diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c
new file mode 100644
index 0000000..bfd74b8
--- /dev/null
+++ b/sound/soc/codecs/nau8810.c
@@ -0,0 +1,874 @@
+/*
+ * nau8810.c  --  NAU8810 ALSA Soc Audio driver
+ *
+ * Copyright 2016 Nuvoton Technology Corp.
+ *
+ * Author: David Lin <ctlin0@nuvoton.com>
+ *
+ * Based on WM8974.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "nau8810.h"
+
+#define NAU_PLL_FREQ_MAX 100000000
+#define NAU_PLL_FREQ_MIN 90000000
+#define NAU_PLL_REF_MAX 33000000
+#define NAU_PLL_REF_MIN 8000000
+#define NAU_PLL_OPTOP_MIN 6
+
+
+static const int nau8810_mclk_scaler[] = { 10, 15, 20, 30, 40, 60, 80, 120 };
+
+static const struct reg_default nau8810_reg_defaults[] = {
+	{ NAU8810_REG_POWER1, 0x0000 },
+	{ NAU8810_REG_POWER2, 0x0000 },
+	{ NAU8810_REG_POWER3, 0x0000 },
+	{ NAU8810_REG_IFACE, 0x0050 },
+	{ NAU8810_REG_COMP, 0x0000 },
+	{ NAU8810_REG_CLOCK, 0x0140 },
+	{ NAU8810_REG_SMPLR, 0x0000 },
+	{ NAU8810_REG_DAC, 0x0000 },
+	{ NAU8810_REG_DACGAIN, 0x00FF },
+	{ NAU8810_REG_ADC, 0x0100 },
+	{ NAU8810_REG_ADCGAIN, 0x00FF },
+	{ NAU8810_REG_EQ1, 0x012C },
+	{ NAU8810_REG_EQ2, 0x002C },
+	{ NAU8810_REG_EQ3, 0x002C },
+	{ NAU8810_REG_EQ4, 0x002C },
+	{ NAU8810_REG_EQ5, 0x002C },
+	{ NAU8810_REG_DACLIM1, 0x0032 },
+	{ NAU8810_REG_DACLIM2, 0x0000 },
+	{ NAU8810_REG_NOTCH1, 0x0000 },
+	{ NAU8810_REG_NOTCH2, 0x0000 },
+	{ NAU8810_REG_NOTCH3, 0x0000 },
+	{ NAU8810_REG_NOTCH4, 0x0000 },
+	{ NAU8810_REG_ALC1, 0x0038 },
+	{ NAU8810_REG_ALC2, 0x000B },
+	{ NAU8810_REG_ALC3, 0x0032 },
+	{ NAU8810_REG_NOISEGATE, 0x0000 },
+	{ NAU8810_REG_PLLN, 0x0008 },
+	{ NAU8810_REG_PLLK1, 0x000C },
+	{ NAU8810_REG_PLLK2, 0x0093 },
+	{ NAU8810_REG_PLLK3, 0x00E9 },
+	{ NAU8810_REG_ATTEN, 0x0000 },
+	{ NAU8810_REG_INPUT_SIGNAL, 0x0003 },
+	{ NAU8810_REG_PGAGAIN, 0x0010 },
+	{ NAU8810_REG_ADCBOOST, 0x0100 },
+	{ NAU8810_REG_OUTPUT, 0x0002 },
+	{ NAU8810_REG_SPKMIX, 0x0001 },
+	{ NAU8810_REG_SPKGAIN, 0x0039 },
+	{ NAU8810_REG_MONOMIX, 0x0001 },
+	{ NAU8810_REG_POWER4, 0x0000 },
+	{ NAU8810_REG_TSLOTCTL1, 0x0000 },
+	{ NAU8810_REG_TSLOTCTL2, 0x0020 },
+	{ NAU8810_REG_DEVICE_REVID, 0x0000 },
+	{ NAU8810_REG_I2C_DEVICEID, 0x001A },
+	{ NAU8810_REG_ADDITIONID, 0x00CA },
+	{ NAU8810_REG_RESERVE, 0x0124 },
+	{ NAU8810_REG_OUTCTL, 0x0001 },
+	{ NAU8810_REG_ALC1ENHAN1, 0x0010 },
+	{ NAU8810_REG_ALC1ENHAN2, 0x0000 },
+	{ NAU8810_REG_MISCCTL, 0x0000 },
+	{ NAU8810_REG_OUTTIEOFF, 0x0000 },
+	{ NAU8810_REG_AGCP2POUT, 0x0000 },
+	{ NAU8810_REG_AGCPOUT, 0x0000 },
+	{ NAU8810_REG_AMTCTL, 0x0000 },
+	{ NAU8810_REG_OUTTIEOFFMAN, 0x0000 },
+};
+
+static bool nau8810_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8810_REG_RESET ... NAU8810_REG_SMPLR:
+	case NAU8810_REG_DAC ... NAU8810_REG_DACGAIN:
+	case NAU8810_REG_ADC ... NAU8810_REG_ADCGAIN:
+	case NAU8810_REG_EQ1 ... NAU8810_REG_EQ5:
+	case NAU8810_REG_DACLIM1 ... NAU8810_REG_DACLIM2:
+	case NAU8810_REG_NOTCH1 ... NAU8810_REG_NOTCH4:
+	case NAU8810_REG_ALC1 ... NAU8810_REG_ATTEN:
+	case NAU8810_REG_INPUT_SIGNAL ... NAU8810_REG_PGAGAIN:
+	case NAU8810_REG_ADCBOOST:
+	case NAU8810_REG_OUTPUT ... NAU8810_REG_SPKMIX:
+	case NAU8810_REG_SPKGAIN:
+	case NAU8810_REG_MONOMIX:
+	case NAU8810_REG_POWER4 ... NAU8810_REG_TSLOTCTL2:
+	case NAU8810_REG_DEVICE_REVID ... NAU8810_REG_RESERVE:
+	case NAU8810_REG_OUTCTL ... NAU8810_REG_ALC1ENHAN2:
+	case NAU8810_REG_MISCCTL:
+	case NAU8810_REG_OUTTIEOFF ... NAU8810_REG_OUTTIEOFFMAN:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool nau8810_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8810_REG_RESET ... NAU8810_REG_SMPLR:
+	case NAU8810_REG_DAC ... NAU8810_REG_DACGAIN:
+	case NAU8810_REG_ADC ... NAU8810_REG_ADCGAIN:
+	case NAU8810_REG_EQ1 ... NAU8810_REG_EQ5:
+	case NAU8810_REG_DACLIM1 ... NAU8810_REG_DACLIM2:
+	case NAU8810_REG_NOTCH1 ... NAU8810_REG_NOTCH4:
+	case NAU8810_REG_ALC1 ... NAU8810_REG_ATTEN:
+	case NAU8810_REG_INPUT_SIGNAL ... NAU8810_REG_PGAGAIN:
+	case NAU8810_REG_ADCBOOST:
+	case NAU8810_REG_OUTPUT ... NAU8810_REG_SPKMIX:
+	case NAU8810_REG_SPKGAIN:
+	case NAU8810_REG_MONOMIX:
+	case NAU8810_REG_POWER4 ... NAU8810_REG_TSLOTCTL2:
+	case NAU8810_REG_OUTCTL ... NAU8810_REG_ALC1ENHAN2:
+	case NAU8810_REG_MISCCTL:
+	case NAU8810_REG_OUTTIEOFF ... NAU8810_REG_OUTTIEOFFMAN:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool nau8810_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8810_REG_RESET:
+	case NAU8810_REG_DEVICE_REVID ... NAU8810_REG_RESERVE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/* The EQ parameters get function is to get the 5 band equalizer control.
+ * The regmap raw read can't work here because regmap doesn't provide
+ * value format for value width of 9 bits. Therefore, the driver reads data
+ * from cache and makes value format according to the endianness of
+ * bytes type control element.
+ */
+static int nau8810_eq_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
+	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+	int i, reg, reg_val;
+	u16 *val;
+
+	val = (u16 *)ucontrol->value.bytes.data;
+	reg = NAU8810_REG_EQ1;
+	for (i = 0; i < params->max / sizeof(u16); i++) {
+		regmap_read(nau8810->regmap, reg + i, &reg_val);
+		/* conversion of 16-bit integers between native CPU format
+		 * and big endian format
+		 */
+		reg_val = cpu_to_be16(reg_val);
+		memcpy(val + i, &reg_val, sizeof(reg_val));
+	}
+
+	return 0;
+}
+
+/* The EQ parameters put function is to make configuration of 5 band equalizer
+ * control. These configuration includes central frequency, equalizer gain,
+ * cut-off frequency, bandwidth control, and equalizer path.
+ * The regmap raw write can't work here because regmap doesn't provide
+ * register and value format for register with address 7 bits and value 9 bits.
+ * Therefore, the driver makes value format according to the endianness of
+ * bytes type control element and writes data to codec.
+ */
+static int nau8810_eq_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
+	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+	void *data;
+	u16 *val, value;
+	int i, reg, ret;
+
+	data = kmemdup(ucontrol->value.bytes.data,
+		params->max, GFP_KERNEL | GFP_DMA);
+	if (!data)
+		return -ENOMEM;
+
+	val = (u16 *)data;
+	reg = NAU8810_REG_EQ1;
+	for (i = 0; i < params->max / sizeof(u16); i++) {
+		/* conversion of 16-bit integers between native CPU format
+		 * and big endian format
+		 */
+		value = be16_to_cpu(*(val + i));
+		ret = regmap_write(nau8810->regmap, reg + i, value);
+		if (ret) {
+			dev_err(component->dev, "EQ configuration fail, register: %x ret: %d\n",
+				reg + i, ret);
+			kfree(data);
+			return ret;
+		}
+	}
+	kfree(data);
+
+	return 0;
+}
+
+static const char * const nau8810_companding[] = {
+	"Off", "NC", "u-law", "A-law" };
+
+static const struct soc_enum nau8810_companding_adc_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_COMP, NAU8810_ADCCM_SFT,
+		ARRAY_SIZE(nau8810_companding), nau8810_companding);
+
+static const struct soc_enum nau8810_companding_dac_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_COMP, NAU8810_DACCM_SFT,
+		ARRAY_SIZE(nau8810_companding), nau8810_companding);
+
+static const char * const nau8810_deemp[] = {
+	"None", "32kHz", "44.1kHz", "48kHz" };
+
+static const struct soc_enum nau8810_deemp_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_DAC, NAU8810_DEEMP_SFT,
+		ARRAY_SIZE(nau8810_deemp), nau8810_deemp);
+
+static const char * const nau8810_eqmode[] = {"Capture", "Playback" };
+
+static const struct soc_enum nau8810_eqmode_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_EQ1, NAU8810_EQM_SFT,
+		ARRAY_SIZE(nau8810_eqmode), nau8810_eqmode);
+
+static const char * const nau8810_alc[] = {"Normal", "Limiter" };
+
+static const struct soc_enum nau8810_alc_enum =
+	SOC_ENUM_SINGLE(NAU8810_REG_ALC3, NAU8810_ALCM_SFT,
+		ARRAY_SIZE(nau8810_alc), nau8810_alc);
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0);
+
+static const struct snd_kcontrol_new nau8810_snd_controls[] = {
+	SOC_ENUM("ADC Companding", nau8810_companding_adc_enum),
+	SOC_ENUM("DAC Companding", nau8810_companding_dac_enum),
+	SOC_ENUM("DAC De-emphasis", nau8810_deemp_enum),
+
+	SOC_ENUM("EQ Function", nau8810_eqmode_enum),
+	SND_SOC_BYTES_EXT("EQ Parameters", 10,
+		  nau8810_eq_get, nau8810_eq_put),
+
+	SOC_SINGLE("DAC Inversion Switch", NAU8810_REG_DAC,
+		NAU8810_DACPL_SFT, 1, 0),
+	SOC_SINGLE_TLV("Playback Volume", NAU8810_REG_DACGAIN,
+		NAU8810_DACGAIN_SFT, 0xff, 0, digital_tlv),
+
+	SOC_SINGLE("High Pass Filter Switch", NAU8810_REG_ADC,
+		NAU8810_HPFEN_SFT, 1, 0),
+	SOC_SINGLE("High Pass Cut Off", NAU8810_REG_ADC,
+		NAU8810_HPF_SFT, 0x7, 0),
+
+	SOC_SINGLE("ADC Inversion Switch", NAU8810_REG_ADC,
+		NAU8810_ADCPL_SFT, 1, 0),
+	SOC_SINGLE_TLV("Capture Volume", NAU8810_REG_ADCGAIN,
+		NAU8810_ADCGAIN_SFT, 0xff, 0, digital_tlv),
+
+	SOC_SINGLE_TLV("EQ1 Volume", NAU8810_REG_EQ1,
+		NAU8810_EQ1GC_SFT, 0x18, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ2 Volume", NAU8810_REG_EQ2,
+		NAU8810_EQ2GC_SFT, 0x18, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ3 Volume", NAU8810_REG_EQ3,
+		NAU8810_EQ3GC_SFT, 0x18, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ4 Volume", NAU8810_REG_EQ4,
+		NAU8810_EQ4GC_SFT, 0x18, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ5 Volume", NAU8810_REG_EQ5,
+		NAU8810_EQ5GC_SFT, 0x18, 1, eq_tlv),
+
+	SOC_SINGLE("DAC Limiter Switch", NAU8810_REG_DACLIM1,
+		NAU8810_DACLIMEN_SFT, 1, 0),
+	SOC_SINGLE("DAC Limiter Decay", NAU8810_REG_DACLIM1,
+		NAU8810_DACLIMDCY_SFT, 0xf, 0),
+	SOC_SINGLE("DAC Limiter Attack", NAU8810_REG_DACLIM1,
+		NAU8810_DACLIMATK_SFT, 0xf, 0),
+	SOC_SINGLE("DAC Limiter Threshold", NAU8810_REG_DACLIM2,
+		NAU8810_DACLIMTHL_SFT, 0x7, 0),
+	SOC_SINGLE("DAC Limiter Boost", NAU8810_REG_DACLIM2,
+		NAU8810_DACLIMBST_SFT, 0xf, 0),
+
+	SOC_ENUM("ALC Mode", nau8810_alc_enum),
+	SOC_SINGLE("ALC Enable Switch", NAU8810_REG_ALC1,
+		NAU8810_ALCEN_SFT, 1, 0),
+	SOC_SINGLE("ALC Max Volume", NAU8810_REG_ALC1,
+		NAU8810_ALCMXGAIN_SFT, 0x7, 0),
+	SOC_SINGLE("ALC Min Volume", NAU8810_REG_ALC1,
+		NAU8810_ALCMINGAIN_SFT, 0x7, 0),
+	SOC_SINGLE("ALC ZC Switch", NAU8810_REG_ALC2,
+		NAU8810_ALCZC_SFT, 1, 0),
+	SOC_SINGLE("ALC Hold", NAU8810_REG_ALC2,
+		NAU8810_ALCHT_SFT, 0xf, 0),
+	SOC_SINGLE("ALC Target", NAU8810_REG_ALC2,
+		NAU8810_ALCSL_SFT, 0xf, 0),
+	SOC_SINGLE("ALC Decay", NAU8810_REG_ALC3,
+		NAU8810_ALCDCY_SFT, 0xf, 0),
+	SOC_SINGLE("ALC Attack", NAU8810_REG_ALC3,
+		NAU8810_ALCATK_SFT, 0xf, 0),
+	SOC_SINGLE("ALC Noise Gate Switch", NAU8810_REG_NOISEGATE,
+		NAU8810_ALCNEN_SFT, 1, 0),
+	SOC_SINGLE("ALC Noise Gate Threshold", NAU8810_REG_NOISEGATE,
+		NAU8810_ALCNTH_SFT, 0x7, 0),
+
+	SOC_SINGLE("PGA ZC Switch", NAU8810_REG_PGAGAIN,
+		NAU8810_PGAZC_SFT, 1, 0),
+	SOC_SINGLE_TLV("PGA Volume", NAU8810_REG_PGAGAIN,
+		NAU8810_PGAGAIN_SFT, 0x3f, 0, inpga_tlv),
+
+	SOC_SINGLE("Speaker ZC Switch", NAU8810_REG_SPKGAIN,
+		NAU8810_SPKZC_SFT, 1, 0),
+	SOC_SINGLE("Speaker Mute Switch", NAU8810_REG_SPKGAIN,
+		NAU8810_SPKMT_SFT, 1, 0),
+	SOC_SINGLE_TLV("Speaker Volume", NAU8810_REG_SPKGAIN,
+		NAU8810_SPKGAIN_SFT, 0x3f, 0, spk_tlv),
+
+	SOC_SINGLE("Capture Boost(+20dB)", NAU8810_REG_ADCBOOST,
+		NAU8810_PGABST_SFT, 1, 0),
+	SOC_SINGLE("Mono Mute Switch", NAU8810_REG_MONOMIX,
+		NAU8810_MOUTMXMT_SFT, 1, 0),
+
+	SOC_SINGLE("DAC Oversampling Rate(128x) Switch", NAU8810_REG_DAC,
+		NAU8810_DACOS_SFT, 1, 0),
+	SOC_SINGLE("ADC Oversampling Rate(128x) Switch", NAU8810_REG_ADC,
+		NAU8810_ADCOS_SFT, 1, 0),
+};
+
+/* Speaker Output Mixer */
+static const struct snd_kcontrol_new nau8810_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", NAU8810_REG_SPKMIX,
+		NAU8810_BYPSPK_SFT, 1, 0),
+	SOC_DAPM_SINGLE("PCM Playback Switch", NAU8810_REG_SPKMIX,
+		NAU8810_DACSPK_SFT, 1, 0),
+};
+
+/* Mono Output Mixer */
+static const struct snd_kcontrol_new nau8810_mono_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", NAU8810_REG_MONOMIX,
+		NAU8810_BYPMOUT_SFT, 1, 0),
+	SOC_DAPM_SINGLE("PCM Playback Switch", NAU8810_REG_MONOMIX,
+		NAU8810_DACMOUT_SFT, 1, 0),
+};
+
+/* PGA Mute */
+static const struct snd_kcontrol_new nau8810_pgaboost_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PGA Mute Switch", NAU8810_REG_PGAGAIN,
+		NAU8810_PGAMT_SFT, 1, 1),
+	SOC_DAPM_SINGLE("PMIC PGA Switch", NAU8810_REG_ADCBOOST,
+		NAU8810_PMICBSTGAIN_SFT, 0x7, 0),
+};
+
+/* Input PGA */
+static const struct snd_kcontrol_new nau8810_inpga[] = {
+	SOC_DAPM_SINGLE("MicN Switch", NAU8810_REG_INPUT_SIGNAL,
+		NAU8810_NMICPGA_SFT, 1, 0),
+	SOC_DAPM_SINGLE("MicP Switch", NAU8810_REG_INPUT_SIGNAL,
+		NAU8810_PMICPGA_SFT, 1, 0),
+};
+
+/* Loopback Switch */
+static const struct snd_kcontrol_new nau8810_loopback =
+	SOC_DAPM_SINGLE("Switch", NAU8810_REG_COMP,
+		NAU8810_ADDAP_SFT, 1, 0);
+
+static int check_mclk_select_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
+	unsigned int value;
+
+	regmap_read(nau8810->regmap, NAU8810_REG_CLOCK, &value);
+	return (value & NAU8810_CLKM_MASK);
+}
+
+static const struct snd_soc_dapm_widget nau8810_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Speaker Mixer", NAU8810_REG_POWER3,
+		NAU8810_SPKMX_EN_SFT, 0, &nau8810_speaker_mixer_controls[0],
+		ARRAY_SIZE(nau8810_speaker_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono Mixer", NAU8810_REG_POWER3,
+		NAU8810_MOUTMX_EN_SFT, 0, &nau8810_mono_mixer_controls[0],
+		ARRAY_SIZE(nau8810_mono_mixer_controls)),
+	SND_SOC_DAPM_DAC("DAC", "HiFi Playback", NAU8810_REG_POWER3,
+		NAU8810_DAC_EN_SFT, 0),
+	SND_SOC_DAPM_ADC("ADC", "HiFi Capture", NAU8810_REG_POWER2,
+		NAU8810_ADC_EN_SFT, 0),
+	SND_SOC_DAPM_PGA("SpkN Out", NAU8810_REG_POWER3,
+		NAU8810_NSPK_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SpkP Out", NAU8810_REG_POWER3,
+		NAU8810_PSPK_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono Out", NAU8810_REG_POWER3,
+		NAU8810_MOUT_EN_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("Input PGA", NAU8810_REG_POWER2,
+		NAU8810_PGA_EN_SFT, 0, nau8810_inpga,
+		ARRAY_SIZE(nau8810_inpga)),
+	SND_SOC_DAPM_MIXER("Input Boost Stage", NAU8810_REG_POWER2,
+		NAU8810_BST_EN_SFT, 0, nau8810_pgaboost_mixer_controls,
+		ARRAY_SIZE(nau8810_pgaboost_mixer_controls)),
+
+	SND_SOC_DAPM_SUPPLY("Mic Bias", NAU8810_REG_POWER1,
+		NAU8810_MICBIAS_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL", NAU8810_REG_POWER1,
+		NAU8810_PLL_EN_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH("Digital Loopback", SND_SOC_NOPM, 0, 0,
+		&nau8810_loopback),
+
+	SND_SOC_DAPM_INPUT("MICN"),
+	SND_SOC_DAPM_INPUT("MICP"),
+	SND_SOC_DAPM_OUTPUT("MONOOUT"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+};
+
+static const struct snd_soc_dapm_route nau8810_dapm_routes[] = {
+	{"DAC", NULL, "PLL", check_mclk_select_pll},
+
+	/* Mono output mixer */
+	{"Mono Mixer", "PCM Playback Switch", "DAC"},
+	{"Mono Mixer", "Line Bypass Switch", "Input Boost Stage"},
+
+	/* Speaker output mixer */
+	{"Speaker Mixer", "PCM Playback Switch", "DAC"},
+	{"Speaker Mixer", "Line Bypass Switch", "Input Boost Stage"},
+
+	/* Outputs */
+	{"Mono Out", NULL, "Mono Mixer"},
+	{"MONOOUT", NULL, "Mono Out"},
+	{"SpkN Out", NULL, "Speaker Mixer"},
+	{"SpkP Out", NULL, "Speaker Mixer"},
+	{"SPKOUTN", NULL, "SpkN Out"},
+	{"SPKOUTP", NULL, "SpkP Out"},
+
+	/* Input Boost Stage */
+	{"ADC", NULL, "Input Boost Stage"},
+	{"ADC", NULL, "PLL", check_mclk_select_pll},
+	{"Input Boost Stage", "PGA Mute Switch", "Input PGA"},
+	{"Input Boost Stage", "PMIC PGA Switch", "MICP"},
+
+	/* Input PGA */
+	{"Input PGA", NULL, "Mic Bias"},
+	{"Input PGA", "MicN Switch", "MICN"},
+	{"Input PGA", "MicP Switch", "MICP"},
+
+	/* Digital Looptack */
+	{"Digital Loopback", "Switch", "ADC"},
+	{"DAC", NULL, "Digital Loopback"},
+};
+
+static int nau8810_set_sysclk(struct snd_soc_dai *dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
+
+	nau8810->clk_id = clk_id;
+	nau8810->sysclk = freq;
+	dev_dbg(nau8810->dev, "master sysclk %dHz, source %s\n",
+		freq, clk_id == NAU8810_SCLK_PLL ? "PLL" : "MCLK");
+
+	return 0;
+}
+
+static int nau88l0_calc_pll(unsigned int pll_in,
+	unsigned int fs, struct nau8810_pll *pll_param)
+{
+	u64 f2, f2_max, pll_ratio;
+	int i, scal_sel;
+
+	if (pll_in > NAU_PLL_REF_MAX || pll_in < NAU_PLL_REF_MIN)
+		return -EINVAL;
+
+	f2_max = 0;
+	scal_sel = ARRAY_SIZE(nau8810_mclk_scaler);
+	for (i = 0; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) {
+		f2 = 256 * fs * 4 * nau8810_mclk_scaler[i] / 10;
+		if (f2 > NAU_PLL_FREQ_MIN && f2 < NAU_PLL_FREQ_MAX &&
+			f2_max < f2) {
+			f2_max = f2;
+			scal_sel = i;
+		}
+	}
+	if (ARRAY_SIZE(nau8810_mclk_scaler) == scal_sel)
+		return -EINVAL;
+	pll_param->mclk_scaler = scal_sel;
+	f2 = f2_max;
+
+	/* Calculate the PLL 4-bit integer input and the PLL 24-bit fractional
+	 * input; round up the 24+4bit.
+	 */
+	pll_ratio = div_u64(f2 << 28, pll_in);
+	pll_param->pre_factor = 0;
+	if (((pll_ratio >> 28) & 0xF) < NAU_PLL_OPTOP_MIN) {
+		pll_ratio <<= 1;
+		pll_param->pre_factor = 1;
+	}
+	pll_param->pll_int = (pll_ratio >> 28) & 0xF;
+	pll_param->pll_frac = ((pll_ratio & 0xFFFFFFF) >> 4);
+
+	return 0;
+}
+
+static int nau8810_set_pll(struct snd_soc_dai *codec_dai, int pll_id,
+	int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
+	struct regmap *map = nau8810->regmap;
+	struct nau8810_pll *pll_param = &nau8810->pll;
+	int ret, fs;
+
+	fs = freq_out / 256;
+	ret = nau88l0_calc_pll(freq_in, fs, pll_param);
+	if (ret < 0) {
+		dev_err(nau8810->dev, "Unsupported input clock %d\n", freq_in);
+		return ret;
+	}
+	dev_info(nau8810->dev, "pll_int=%x pll_frac=%x mclk_scaler=%x pre_factor=%x\n",
+		pll_param->pll_int, pll_param->pll_frac, pll_param->mclk_scaler,
+		pll_param->pre_factor);
+
+	regmap_update_bits(map, NAU8810_REG_PLLN,
+		NAU8810_PLLMCLK_DIV2 | NAU8810_PLLN_MASK,
+		(pll_param->pre_factor ? NAU8810_PLLMCLK_DIV2 : 0) |
+		pll_param->pll_int);
+	regmap_write(map, NAU8810_REG_PLLK1,
+		(pll_param->pll_frac >> NAU8810_PLLK1_SFT) &
+		NAU8810_PLLK1_MASK);
+	regmap_write(map, NAU8810_REG_PLLK2,
+		(pll_param->pll_frac >> NAU8810_PLLK2_SFT) &
+		NAU8810_PLLK2_MASK);
+	regmap_write(map, NAU8810_REG_PLLK3,
+		pll_param->pll_frac & NAU8810_PLLK3_MASK);
+	regmap_update_bits(map, NAU8810_REG_CLOCK, NAU8810_MCLKSEL_MASK,
+		pll_param->mclk_scaler << NAU8810_MCLKSEL_SFT);
+	regmap_update_bits(map, NAU8810_REG_CLOCK,
+		NAU8810_CLKM_MASK, NAU8810_CLKM_PLL);
+
+	return 0;
+}
+
+static int nau8810_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
+	u16 ctrl1_val = 0, ctrl2_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		ctrl2_val |= NAU8810_CLKIO_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		ctrl1_val |= NAU8810_AIFMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ctrl1_val |= NAU8810_AIFMT_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		ctrl1_val |= NAU8810_AIFMT_PCM_A;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		ctrl1_val |= NAU8810_BCLKP_IB | NAU8810_FSP_IF;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		ctrl1_val |= NAU8810_BCLKP_IB;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		ctrl1_val |= NAU8810_FSP_IF;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_IFACE,
+		NAU8810_AIFMT_MASK | NAU8810_FSP_IF |
+		NAU8810_BCLKP_IB, ctrl1_val);
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK,
+		NAU8810_CLKIO_MASK, ctrl2_val);
+
+	return 0;
+}
+
+static int nau8810_mclk_clkdiv(struct nau8810 *nau8810, int rate)
+{
+	int i, sclk, imclk = rate * 256, div = 0;
+
+	if (!nau8810->sysclk) {
+		dev_err(nau8810->dev, "Make mclk div configuration fail because of invalid system clock\n");
+		return -EINVAL;
+	}
+
+	/* Configure the master clock prescaler div to make system
+	 * clock to approximate the internal master clock (IMCLK);
+	 * and large or equal to IMCLK.
+	 */
+	for (i = 1; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) {
+		sclk = (nau8810->sysclk * 10) /
+			nau8810_mclk_scaler[i];
+		if (sclk < imclk)
+			break;
+		div = i;
+	}
+	dev_dbg(nau8810->dev,
+		"master clock prescaler %x for fs %d\n", div, rate);
+
+	/* master clock from MCLK and disable PLL */
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK,
+		NAU8810_MCLKSEL_MASK, (div << NAU8810_MCLKSEL_SFT));
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK,
+		NAU8810_CLKM_MASK, NAU8810_CLKM_MCLK);
+
+	return 0;
+}
+
+static int nau8810_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
+	int val_len = 0, val_rate = 0, ret = 0;
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		val_len |= NAU8810_WLEN_20;
+		break;
+	case 24:
+		val_len |= NAU8810_WLEN_24;
+		break;
+	case 32:
+		val_len |= NAU8810_WLEN_32;
+		break;
+	}
+
+	switch (params_rate(params)) {
+	case 8000:
+		val_rate |= NAU8810_SMPLR_8K;
+		break;
+	case 11025:
+		val_rate |= NAU8810_SMPLR_12K;
+		break;
+	case 16000:
+		val_rate |= NAU8810_SMPLR_16K;
+		break;
+	case 22050:
+		val_rate |= NAU8810_SMPLR_24K;
+		break;
+	case 32000:
+		val_rate |= NAU8810_SMPLR_32K;
+		break;
+	case 44100:
+	case 48000:
+		break;
+	}
+
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_IFACE,
+		NAU8810_WLEN_MASK, val_len);
+	regmap_update_bits(nau8810->regmap, NAU8810_REG_SMPLR,
+		NAU8810_SMPLR_MASK, val_rate);
+
+	/* If the master clock is from MCLK, provide the runtime FS for driver
+	 * to get the master clock prescaler configuration.
+	 */
+	if (nau8810->clk_id == NAU8810_SCLK_MCLK) {
+		ret = nau8810_mclk_clkdiv(nau8810, params_rate(params));
+		if (ret < 0)
+			dev_err(nau8810->dev, "MCLK div configuration fail\n");
+	}
+
+	return ret;
+}
+
+static int nau8810_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
+	struct regmap *map = nau8810->regmap;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		regmap_update_bits(map, NAU8810_REG_POWER1,
+			NAU8810_REFIMP_MASK, NAU8810_REFIMP_80K);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		regmap_update_bits(map, NAU8810_REG_POWER1,
+			NAU8810_IOBUF_EN | NAU8810_ABIAS_EN,
+			NAU8810_IOBUF_EN | NAU8810_ABIAS_EN);
+
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			regcache_sync(map);
+			regmap_update_bits(map, NAU8810_REG_POWER1,
+				NAU8810_REFIMP_MASK, NAU8810_REFIMP_3K);
+			mdelay(100);
+		}
+		regmap_update_bits(map, NAU8810_REG_POWER1,
+			NAU8810_REFIMP_MASK, NAU8810_REFIMP_300K);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		regmap_write(map, NAU8810_REG_POWER1, 0);
+		regmap_write(map, NAU8810_REG_POWER2, 0);
+		regmap_write(map, NAU8810_REG_POWER3, 0);
+		break;
+	}
+
+	return 0;
+}
+
+
+#define NAU8810_RATES (SNDRV_PCM_RATE_8000_48000)
+
+#define NAU8810_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops nau8810_ops = {
+	.hw_params = nau8810_pcm_hw_params,
+	.set_fmt = nau8810_set_dai_fmt,
+	.set_sysclk = nau8810_set_sysclk,
+	.set_pll = nau8810_set_pll,
+};
+
+static struct snd_soc_dai_driver nau8810_dai = {
+	.name = "nau8810-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,   /* Only 1 channel of data */
+		.rates = NAU8810_RATES,
+		.formats = NAU8810_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,   /* Only 1 channel of data */
+		.rates = NAU8810_RATES,
+		.formats = NAU8810_FORMATS,
+	},
+	.ops = &nau8810_ops,
+	.symmetric_rates = 1,
+};
+
+static const struct regmap_config nau8810_regmap_config = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = NAU8810_REG_MAX,
+	.readable_reg = nau8810_readable_reg,
+	.writeable_reg = nau8810_writeable_reg,
+	.volatile_reg = nau8810_volatile_reg,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = nau8810_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(nau8810_reg_defaults),
+};
+
+static const struct snd_soc_component_driver nau8810_component_driver = {
+	.set_bias_level		= nau8810_set_bias_level,
+	.controls		= nau8810_snd_controls,
+	.num_controls		= ARRAY_SIZE(nau8810_snd_controls),
+	.dapm_widgets		= nau8810_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(nau8810_dapm_widgets),
+	.dapm_routes		= nau8810_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(nau8810_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int nau8810_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct device *dev = &i2c->dev;
+	struct nau8810 *nau8810 = dev_get_platdata(dev);
+
+	if (!nau8810) {
+		nau8810 = devm_kzalloc(dev, sizeof(*nau8810), GFP_KERNEL);
+		if (!nau8810)
+			return -ENOMEM;
+	}
+	i2c_set_clientdata(i2c, nau8810);
+
+	nau8810->regmap = devm_regmap_init_i2c(i2c, &nau8810_regmap_config);
+	if (IS_ERR(nau8810->regmap))
+		return PTR_ERR(nau8810->regmap);
+	nau8810->dev = dev;
+
+	regmap_write(nau8810->regmap, NAU8810_REG_RESET, 0x00);
+
+	return devm_snd_soc_register_component(dev,
+		&nau8810_component_driver, &nau8810_dai, 1);
+}
+
+static const struct i2c_device_id nau8810_i2c_id[] = {
+	{ "nau8810", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, nau8810_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id nau8810_of_match[] = {
+	{ .compatible = "nuvoton,nau8810", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, nau8810_of_match);
+#endif
+
+static struct i2c_driver nau8810_i2c_driver = {
+	.driver = {
+		.name = "nau8810",
+		.of_match_table = of_match_ptr(nau8810_of_match),
+	},
+	.probe =    nau8810_i2c_probe,
+	.id_table = nau8810_i2c_id,
+};
+
+module_i2c_driver(nau8810_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC NAU8810 driver");
+MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/nau8810.h b/sound/soc/codecs/nau8810.h
new file mode 100644
index 0000000..df88265
--- /dev/null
+++ b/sound/soc/codecs/nau8810.h
@@ -0,0 +1,281 @@
+/*
+ * NAU8810 ALSA SoC audio driver
+ *
+ * Copyright 2016 Nuvoton Technology Corp.
+ * Author: David Lin <ctlin0@nuvoton.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __NAU8810_H__
+#define __NAU8810_H__
+
+#define NAU8810_REG_RESET		0x00
+#define NAU8810_REG_POWER1		0x01
+#define NAU8810_REG_POWER2		0x02
+#define NAU8810_REG_POWER3		0x03
+#define NAU8810_REG_IFACE		0x04
+#define NAU8810_REG_COMP		0x05
+#define NAU8810_REG_CLOCK		0x06
+#define NAU8810_REG_SMPLR		0x07
+#define NAU8810_REG_DAC		0x0A
+#define NAU8810_REG_DACGAIN		0x0B
+#define NAU8810_REG_ADC		0x0E
+#define NAU8810_REG_ADCGAIN		0x0F
+#define NAU8810_REG_EQ1		0x12
+#define NAU8810_REG_EQ2		0x13
+#define NAU8810_REG_EQ3		0x14
+#define NAU8810_REG_EQ4		0x15
+#define NAU8810_REG_EQ5		0x16
+#define NAU8810_REG_DACLIM1		0x18
+#define NAU8810_REG_DACLIM2		0x19
+#define NAU8810_REG_NOTCH1		0x1B
+#define NAU8810_REG_NOTCH2		0x1C
+#define NAU8810_REG_NOTCH3		0x1D
+#define NAU8810_REG_NOTCH4		0x1E
+#define NAU8810_REG_ALC1		0x20
+#define NAU8810_REG_ALC2		0x21
+#define NAU8810_REG_ALC3		0x22
+#define NAU8810_REG_NOISEGATE		0x23
+#define NAU8810_REG_PLLN		0x24
+#define NAU8810_REG_PLLK1		0x25
+#define NAU8810_REG_PLLK2		0x26
+#define NAU8810_REG_PLLK3		0x27
+#define NAU8810_REG_ATTEN		0x28
+#define NAU8810_REG_INPUT_SIGNAL	0x2C
+#define NAU8810_REG_PGAGAIN		0x2D
+#define NAU8810_REG_ADCBOOST		0x2F
+#define NAU8810_REG_OUTPUT		0x31
+#define NAU8810_REG_SPKMIX		0x32
+#define NAU8810_REG_SPKGAIN		0x36
+#define NAU8810_REG_MONOMIX		0x38
+#define NAU8810_REG_POWER4		0x3A
+#define NAU8810_REG_TSLOTCTL1		0x3B
+#define NAU8810_REG_TSLOTCTL2		0x3C
+#define NAU8810_REG_DEVICE_REVID	0x3E
+#define NAU8810_REG_I2C_DEVICEID	0x3F
+#define NAU8810_REG_ADDITIONID	0x40
+#define NAU8810_REG_RESERVE		0x41
+#define NAU8810_REG_OUTCTL		0x45
+#define NAU8810_REG_ALC1ENHAN1	0x46
+#define NAU8810_REG_ALC1ENHAN2	0x47
+#define NAU8810_REG_MISCCTL		0x49
+#define NAU8810_REG_OUTTIEOFF		0x4B
+#define NAU8810_REG_AGCP2POUT	0x4C
+#define NAU8810_REG_AGCPOUT		0x4D
+#define NAU8810_REG_AMTCTL		0x4E
+#define NAU8810_REG_OUTTIEOFFMAN	0x4F
+#define NAU8810_REG_MAX		NAU8810_REG_OUTTIEOFFMAN
+
+
+/* NAU8810_REG_POWER1 (0x1) */
+#define NAU8810_DCBUF_EN		(0x1 << 8)
+#define NAU8810_PLL_EN_SFT		5
+#define NAU8810_MICBIAS_EN_SFT	4
+#define NAU8810_ABIAS_EN		(0x1 << 3)
+#define NAU8810_IOBUF_EN		(0x1 << 2)
+#define NAU8810_REFIMP_MASK		0x3
+#define NAU8810_REFIMP_DIS		0x0
+#define NAU8810_REFIMP_80K		0x1
+#define NAU8810_REFIMP_300K		0x2
+#define NAU8810_REFIMP_3K		0x3
+
+/* NAU8810_REG_POWER2 (0x2) */
+#define NAU8810_BST_EN_SFT		4
+#define NAU8810_PGA_EN_SFT		2
+#define NAU8810_ADC_EN_SFT		0
+
+/* NAU8810_REG_POWER3 (0x3) */
+#define NAU8810_DAC_EN_SFT		0
+#define NAU8810_SPKMX_EN_SFT		2
+#define NAU8810_MOUTMX_EN_SFT	3
+#define NAU8810_PSPK_EN_SFT		5
+#define NAU8810_NSPK_EN_SFT		6
+#define NAU8810_MOUT_EN_SFT		7
+
+/* NAU8810_REG_IFACE (0x4) */
+#define NAU8810_AIFMT_SFT		3
+#define NAU8810_AIFMT_MASK		(0x3 << NAU8810_AIFMT_SFT)
+#define NAU8810_AIFMT_RIGHT		(0x0 << NAU8810_AIFMT_SFT)
+#define NAU8810_AIFMT_LEFT		(0x1 << NAU8810_AIFMT_SFT)
+#define NAU8810_AIFMT_I2S		(0x2 << NAU8810_AIFMT_SFT)
+#define NAU8810_AIFMT_PCM_A		(0x3 << NAU8810_AIFMT_SFT)
+#define NAU8810_WLEN_SFT		5
+#define NAU8810_WLEN_MASK		(0x3 << NAU8810_WLEN_SFT)
+#define NAU8810_WLEN_16		(0x0 << NAU8810_WLEN_SFT)
+#define NAU8810_WLEN_20		(0x1 << NAU8810_WLEN_SFT)
+#define NAU8810_WLEN_24		(0x2 << NAU8810_WLEN_SFT)
+#define NAU8810_WLEN_32		(0x3 << NAU8810_WLEN_SFT)
+#define NAU8810_FSP_IF			(0x1 << 7)
+#define NAU8810_BCLKP_IB		(0x1 << 8)
+
+/* NAU8810_REG_COMP (0x5) */
+#define NAU8810_ADDAP_SFT		0
+#define NAU8810_ADCCM_SFT		1
+#define NAU8810_DACCM_SFT		3
+
+/* NAU8810_REG_CLOCK (0x6) */
+#define NAU8810_CLKIO_MASK		0x1
+#define NAU8810_CLKIO_SLAVE		0x0
+#define NAU8810_CLKIO_MASTER		0x1
+#define NAU8810_BCLKSEL_SFT		2
+#define NAU8810_BCLKSEL_MASK		(0x7 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_1		(0x0 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_2		(0x1 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_4		(0x2 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_8		(0x3 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_16		(0x4 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_BCLKDIV_32		(0x5 << NAU8810_BCLKSEL_SFT)
+#define NAU8810_MCLKSEL_SFT		5
+#define NAU8810_MCLKSEL_MASK		(0x7 << NAU8810_MCLKSEL_SFT)
+#define NAU8810_CLKM_SFT		8
+#define NAU8810_CLKM_MASK		(0x1 << NAU8810_CLKM_SFT)
+#define NAU8810_CLKM_MCLK		(0x0 << NAU8810_CLKM_SFT)
+#define NAU8810_CLKM_PLL		(0x1 << NAU8810_CLKM_SFT)
+
+/* NAU8810_REG_SMPLR (0x7) */
+#define NAU8810_SMPLR_SFT		1
+#define NAU8810_SMPLR_MASK		(0x7 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_48K		(0x0 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_32K		(0x1 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_24K		(0x2 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_16K		(0x3 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_12K		(0x4 << NAU8810_SMPLR_SFT)
+#define NAU8810_SMPLR_8K		(0x5 << NAU8810_SMPLR_SFT)
+
+/* NAU8810_REG_DAC (0xA) */
+#define NAU8810_DACPL_SFT		0
+#define NAU8810_DACOS_SFT		3
+#define NAU8810_DEEMP_SFT		4
+
+/* NAU8810_REG_DACGAIN (0xB) */
+#define NAU8810_DACGAIN_SFT		0
+
+/* NAU8810_REG_ADC (0xE) */
+#define NAU8810_ADCPL_SFT		0
+#define NAU8810_ADCOS_SFT		3
+#define NAU8810_HPF_SFT		4
+#define NAU8810_HPFEN_SFT		8
+
+/* NAU8810_REG_ADCGAIN (0xF) */
+#define NAU8810_ADCGAIN_SFT		0
+
+/* NAU8810_REG_EQ1 (0x12) */
+#define NAU8810_EQ1GC_SFT		0
+#define NAU8810_EQ1CF_SFT		5
+#define NAU8810_EQM_SFT		8
+
+/* NAU8810_REG_EQ2 (0x13) */
+#define NAU8810_EQ2GC_SFT		0
+#define NAU8810_EQ2CF_SFT		5
+#define NAU8810_EQ2BW_SFT		8
+
+/* NAU8810_REG_EQ3 (0x14) */
+#define NAU8810_EQ3GC_SFT		0
+#define NAU8810_EQ3CF_SFT		5
+#define NAU8810_EQ3BW_SFT		8
+
+/* NAU8810_REG_EQ4 (0x15) */
+#define NAU8810_EQ4GC_SFT		0
+#define NAU8810_EQ4CF_SFT		5
+#define NAU8810_EQ4BW_SFT		8
+
+/* NAU8810_REG_EQ5 (0x16) */
+#define NAU8810_EQ5GC_SFT		0
+#define NAU8810_EQ5CF_SFT		5
+
+/* NAU8810_REG_DACLIM1 (0x18) */
+#define NAU8810_DACLIMATK_SFT		0
+#define NAU8810_DACLIMDCY_SFT		4
+#define NAU8810_DACLIMEN_SFT		8
+
+/* NAU8810_REG_DACLIM2 (0x19) */
+#define NAU8810_DACLIMBST_SFT		0
+#define NAU8810_DACLIMTHL_SFT		4
+
+/* NAU8810_REG_ALC1 (0x20) */
+#define NAU8810_ALCMINGAIN_SFT	0
+#define NAU8810_ALCMXGAIN_SFT		3
+#define NAU8810_ALCEN_SFT		8
+
+/* NAU8810_REG_ALC2 (0x21) */
+#define NAU8810_ALCSL_SFT		0
+#define NAU8810_ALCHT_SFT		4
+#define NAU8810_ALCZC_SFT		8
+
+/* NAU8810_REG_ALC3 (0x22) */
+#define NAU8810_ALCATK_SFT		0
+#define NAU8810_ALCDCY_SFT		4
+#define NAU8810_ALCM_SFT		8
+
+/* NAU8810_REG_NOISEGATE (0x23) */
+#define NAU8810_ALCNTH_SFT		0
+#define NAU8810_ALCNEN_SFT		3
+
+/* NAU8810_REG_PLLN (0x24) */
+#define NAU8810_PLLN_MASK		0xF
+#define NAU8810_PLLMCLK_DIV2		(0x1 << 4)
+
+/* NAU8810_REG_PLLK1 (0x25) */
+#define NAU8810_PLLK1_SFT		18
+#define NAU8810_PLLK1_MASK		0x3F
+
+/* NAU8810_REG_PLLK2 (0x26) */
+#define NAU8810_PLLK2_SFT		9
+#define NAU8810_PLLK2_MASK		0x1FF
+
+/* NAU8810_REG_PLLK3 (0x27) */
+#define NAU8810_PLLK3_MASK		0x1FF
+
+/* NAU8810_REG_INPUT_SIGNAL (0x2C) */
+#define NAU8810_PMICPGA_SFT		0
+#define NAU8810_NMICPGA_SFT		1
+
+/* NAU8810_REG_PGAGAIN (0x2D) */
+#define NAU8810_PGAGAIN_SFT		0
+#define NAU8810_PGAMT_SFT		6
+#define NAU8810_PGAZC_SFT		7
+
+/* NAU8810_REG_ADCBOOST (0x2F) */
+#define NAU8810_PMICBSTGAIN_SFT	4
+#define NAU8810_PGABST_SFT		8
+
+/* NAU8810_REG_SPKMIX (0x32) */
+#define NAU8810_DACSPK_SFT		0
+#define NAU8810_BYPSPK_SFT		1
+
+/* NAU8810_REG_SPKGAIN (0x36) */
+#define NAU8810_SPKGAIN_SFT		0
+#define NAU8810_SPKMT_SFT		6
+#define NAU8810_SPKZC_SFT		7
+
+/* NAU8810_REG_MONOMIX (0x38) */
+#define NAU8810_DACMOUT_SFT		0
+#define NAU8810_BYPMOUT_SFT		1
+#define NAU8810_MOUTMXMT_SFT		6
+
+
+/* System Clock Source */
+enum {
+	NAU8810_SCLK_MCLK,
+	NAU8810_SCLK_PLL,
+};
+
+struct nau8810_pll {
+	int pre_factor;
+	int mclk_scaler;
+	int pll_frac;
+	int pll_int;
+};
+
+struct nau8810 {
+	struct device *dev;
+	struct regmap *regmap;
+	struct nau8810_pll pll;
+	int sysclk;
+	int clk_id;
+};
+
+#endif
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
new file mode 100644
index 0000000..468d514
--- /dev/null
+++ b/sound/soc/codecs/nau8824.c
@@ -0,0 +1,1929 @@
+/*
+ * NAU88L24 ALSA SoC audio driver
+ *
+ * Copyright 2016 Nuvoton Technology Corp.
+ * Author: John Hsu <KCHSU0@nuvoton.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/acpi.h>
+#include <linux/math64.h>
+#include <linux/semaphore.h>
+
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include "nau8824.h"
+
+
+static int nau8824_config_sysclk(struct nau8824 *nau8824,
+	int clk_id, unsigned int freq);
+static bool nau8824_is_jack_inserted(struct nau8824 *nau8824);
+
+/* the ADC threshold of headset */
+#define DMIC_CLK 3072000
+
+/* the ADC threshold of headset */
+#define HEADSET_SARADC_THD 0x80
+
+/* the parameter threshold of FLL */
+#define NAU_FREF_MAX 13500000
+#define NAU_FVCO_MAX 100000000
+#define NAU_FVCO_MIN 90000000
+
+/* scaling for mclk from sysclk_src output */
+static const struct nau8824_fll_attr mclk_src_scaling[] = {
+	{ 1, 0x0 },
+	{ 2, 0x2 },
+	{ 4, 0x3 },
+	{ 8, 0x4 },
+	{ 16, 0x5 },
+	{ 32, 0x6 },
+	{ 3, 0x7 },
+	{ 6, 0xa },
+	{ 12, 0xb },
+	{ 24, 0xc },
+};
+
+/* ratio for input clk freq */
+static const struct nau8824_fll_attr fll_ratio[] = {
+	{ 512000, 0x01 },
+	{ 256000, 0x02 },
+	{ 128000, 0x04 },
+	{ 64000, 0x08 },
+	{ 32000, 0x10 },
+	{ 8000, 0x20 },
+	{ 4000, 0x40 },
+};
+
+static const struct nau8824_fll_attr fll_pre_scalar[] = {
+	{ 1, 0x0 },
+	{ 2, 0x1 },
+	{ 4, 0x2 },
+	{ 8, 0x3 },
+};
+
+/* the maximum frequency of CLK_ADC and CLK_DAC */
+#define CLK_DA_AD_MAX 6144000
+
+/* over sampling rate */
+static const struct nau8824_osr_attr osr_dac_sel[] = {
+	{ 64, 2 },	/* OSR 64, SRC 1/4 */
+	{ 256, 0 },	/* OSR 256, SRC 1 */
+	{ 128, 1 },	/* OSR 128, SRC 1/2 */
+	{ 0, 0 },
+	{ 32, 3 },	/* OSR 32, SRC 1/8 */
+};
+
+static const struct nau8824_osr_attr osr_adc_sel[] = {
+	{ 32, 3 },	/* OSR 32, SRC 1/8 */
+	{ 64, 2 },	/* OSR 64, SRC 1/4 */
+	{ 128, 1 },	/* OSR 128, SRC 1/2 */
+	{ 256, 0 },	/* OSR 256, SRC 1 */
+};
+
+static const struct reg_default nau8824_reg_defaults[] = {
+	{ NAU8824_REG_ENA_CTRL, 0x0000 },
+	{ NAU8824_REG_CLK_GATING_ENA, 0x0000 },
+	{ NAU8824_REG_CLK_DIVIDER, 0x0000 },
+	{ NAU8824_REG_FLL1, 0x0000 },
+	{ NAU8824_REG_FLL2, 0x3126 },
+	{ NAU8824_REG_FLL3, 0x0008 },
+	{ NAU8824_REG_FLL4, 0x0010 },
+	{ NAU8824_REG_FLL5, 0xC000 },
+	{ NAU8824_REG_FLL6, 0x6000 },
+	{ NAU8824_REG_FLL_VCO_RSV, 0xF13C },
+	{ NAU8824_REG_JACK_DET_CTRL, 0x0000 },
+	{ NAU8824_REG_INTERRUPT_SETTING_1, 0x0000 },
+	{ NAU8824_REG_IRQ, 0x0000 },
+	{ NAU8824_REG_CLEAR_INT_REG, 0x0000 },
+	{ NAU8824_REG_INTERRUPT_SETTING, 0x1000 },
+	{ NAU8824_REG_SAR_ADC, 0x0015 },
+	{ NAU8824_REG_VDET_COEFFICIENT, 0x0110 },
+	{ NAU8824_REG_VDET_THRESHOLD_1, 0x0000 },
+	{ NAU8824_REG_VDET_THRESHOLD_2, 0x0000 },
+	{ NAU8824_REG_VDET_THRESHOLD_3, 0x0000 },
+	{ NAU8824_REG_VDET_THRESHOLD_4, 0x0000 },
+	{ NAU8824_REG_GPIO_SEL, 0x0000 },
+	{ NAU8824_REG_PORT0_I2S_PCM_CTRL_1, 0x000B },
+	{ NAU8824_REG_PORT0_I2S_PCM_CTRL_2, 0x0010 },
+	{ NAU8824_REG_PORT0_LEFT_TIME_SLOT, 0x0000 },
+	{ NAU8824_REG_PORT0_RIGHT_TIME_SLOT, 0x0000 },
+	{ NAU8824_REG_TDM_CTRL, 0x0000 },
+	{ NAU8824_REG_ADC_HPF_FILTER, 0x0000 },
+	{ NAU8824_REG_ADC_FILTER_CTRL, 0x0002 },
+	{ NAU8824_REG_DAC_FILTER_CTRL_1, 0x0000 },
+	{ NAU8824_REG_DAC_FILTER_CTRL_2, 0x0000 },
+	{ NAU8824_REG_NOTCH_FILTER_1, 0x0000 },
+	{ NAU8824_REG_NOTCH_FILTER_2, 0x0000 },
+	{ NAU8824_REG_EQ1_LOW, 0x112C },
+	{ NAU8824_REG_EQ2_EQ3, 0x2C2C },
+	{ NAU8824_REG_EQ4_EQ5, 0x2C2C },
+	{ NAU8824_REG_ADC_CH0_DGAIN_CTRL, 0x0100 },
+	{ NAU8824_REG_ADC_CH1_DGAIN_CTRL, 0x0100 },
+	{ NAU8824_REG_ADC_CH2_DGAIN_CTRL, 0x0100 },
+	{ NAU8824_REG_ADC_CH3_DGAIN_CTRL, 0x0100 },
+	{ NAU8824_REG_DAC_MUTE_CTRL, 0x0000 },
+	{ NAU8824_REG_DAC_CH0_DGAIN_CTRL, 0x0100 },
+	{ NAU8824_REG_DAC_CH1_DGAIN_CTRL, 0x0100 },
+	{ NAU8824_REG_ADC_TO_DAC_ST, 0x0000 },
+	{ NAU8824_REG_DRC_KNEE_IP12_ADC_CH01, 0x1486 },
+	{ NAU8824_REG_DRC_KNEE_IP34_ADC_CH01, 0x0F12 },
+	{ NAU8824_REG_DRC_SLOPE_ADC_CH01, 0x25FF },
+	{ NAU8824_REG_DRC_ATKDCY_ADC_CH01, 0x3457 },
+	{ NAU8824_REG_DRC_KNEE_IP12_ADC_CH23, 0x1486 },
+	{ NAU8824_REG_DRC_KNEE_IP34_ADC_CH23, 0x0F12 },
+	{ NAU8824_REG_DRC_SLOPE_ADC_CH23, 0x25FF },
+	{ NAU8824_REG_DRC_ATKDCY_ADC_CH23, 0x3457 },
+	{ NAU8824_REG_DRC_GAINL_ADC0, 0x0200 },
+	{ NAU8824_REG_DRC_GAINL_ADC1, 0x0200 },
+	{ NAU8824_REG_DRC_GAINL_ADC2, 0x0200 },
+	{ NAU8824_REG_DRC_GAINL_ADC3, 0x0200 },
+	{ NAU8824_REG_DRC_KNEE_IP12_DAC, 0x1486 },
+	{ NAU8824_REG_DRC_KNEE_IP34_DAC, 0x0F12 },
+	{ NAU8824_REG_DRC_SLOPE_DAC, 0x25F9 },
+	{ NAU8824_REG_DRC_ATKDCY_DAC, 0x3457 },
+	{ NAU8824_REG_DRC_GAIN_DAC_CH0, 0x0200 },
+	{ NAU8824_REG_DRC_GAIN_DAC_CH1, 0x0200 },
+	{ NAU8824_REG_MODE, 0x0000 },
+	{ NAU8824_REG_MODE1, 0x0000 },
+	{ NAU8824_REG_MODE2, 0x0000 },
+	{ NAU8824_REG_CLASSG, 0x0000 },
+	{ NAU8824_REG_OTP_EFUSE, 0x0000 },
+	{ NAU8824_REG_OTPDOUT_1, 0x0000 },
+	{ NAU8824_REG_OTPDOUT_2, 0x0000 },
+	{ NAU8824_REG_MISC_CTRL, 0x0000 },
+	{ NAU8824_REG_I2C_TIMEOUT, 0xEFFF },
+	{ NAU8824_REG_TEST_MODE, 0x0000 },
+	{ NAU8824_REG_I2C_DEVICE_ID, 0x1AF1 },
+	{ NAU8824_REG_SAR_ADC_DATA_OUT, 0x00FF },
+	{ NAU8824_REG_BIAS_ADJ, 0x0000 },
+	{ NAU8824_REG_PGA_GAIN, 0x0000 },
+	{ NAU8824_REG_TRIM_SETTINGS, 0x0000 },
+	{ NAU8824_REG_ANALOG_CONTROL_1, 0x0000 },
+	{ NAU8824_REG_ANALOG_CONTROL_2, 0x0000 },
+	{ NAU8824_REG_ENABLE_LO, 0x0000 },
+	{ NAU8824_REG_GAIN_LO, 0x0000 },
+	{ NAU8824_REG_CLASSD_GAIN_1, 0x0000 },
+	{ NAU8824_REG_CLASSD_GAIN_2, 0x0000 },
+	{ NAU8824_REG_ANALOG_ADC_1, 0x0011 },
+	{ NAU8824_REG_ANALOG_ADC_2, 0x0020 },
+	{ NAU8824_REG_RDAC, 0x0008 },
+	{ NAU8824_REG_MIC_BIAS, 0x0006 },
+	{ NAU8824_REG_HS_VOLUME_CONTROL, 0x0000 },
+	{ NAU8824_REG_BOOST, 0x0000 },
+	{ NAU8824_REG_FEPGA, 0x0000 },
+	{ NAU8824_REG_FEPGA_II, 0x0000 },
+	{ NAU8824_REG_FEPGA_SE, 0x0000 },
+	{ NAU8824_REG_FEPGA_ATTENUATION, 0x0000 },
+	{ NAU8824_REG_ATT_PORT0, 0x0000 },
+	{ NAU8824_REG_ATT_PORT1, 0x0000 },
+	{ NAU8824_REG_POWER_UP_CONTROL, 0x0000 },
+	{ NAU8824_REG_CHARGE_PUMP_CONTROL, 0x0300 },
+	{ NAU8824_REG_CHARGE_PUMP_INPUT, 0x0013 },
+};
+
+static int nau8824_sema_acquire(struct nau8824 *nau8824, long timeout)
+{
+	int ret;
+
+	if (timeout) {
+		ret = down_timeout(&nau8824->jd_sem, timeout);
+		if (ret < 0)
+			dev_warn(nau8824->dev, "Acquire semaphore timeout\n");
+	} else {
+		ret = down_interruptible(&nau8824->jd_sem);
+		if (ret < 0)
+			dev_warn(nau8824->dev, "Acquire semaphore fail\n");
+	}
+
+	return ret;
+}
+
+static inline void nau8824_sema_release(struct nau8824 *nau8824)
+{
+	up(&nau8824->jd_sem);
+}
+
+static bool nau8824_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8824_REG_ENA_CTRL ... NAU8824_REG_FLL_VCO_RSV:
+	case NAU8824_REG_JACK_DET_CTRL:
+	case NAU8824_REG_INTERRUPT_SETTING_1:
+	case NAU8824_REG_IRQ:
+	case NAU8824_REG_CLEAR_INT_REG ... NAU8824_REG_VDET_THRESHOLD_4:
+	case NAU8824_REG_GPIO_SEL:
+	case NAU8824_REG_PORT0_I2S_PCM_CTRL_1 ... NAU8824_REG_TDM_CTRL:
+	case NAU8824_REG_ADC_HPF_FILTER ... NAU8824_REG_EQ4_EQ5:
+	case NAU8824_REG_ADC_CH0_DGAIN_CTRL ... NAU8824_REG_ADC_TO_DAC_ST:
+	case NAU8824_REG_DRC_KNEE_IP12_ADC_CH01 ... NAU8824_REG_DRC_GAINL_ADC3:
+	case NAU8824_REG_DRC_KNEE_IP12_DAC ... NAU8824_REG_DRC_GAIN_DAC_CH1:
+	case NAU8824_REG_CLASSG ... NAU8824_REG_OTP_EFUSE:
+	case NAU8824_REG_OTPDOUT_1 ... NAU8824_REG_OTPDOUT_2:
+	case NAU8824_REG_I2C_TIMEOUT:
+	case NAU8824_REG_I2C_DEVICE_ID ... NAU8824_REG_SAR_ADC_DATA_OUT:
+	case NAU8824_REG_BIAS_ADJ ... NAU8824_REG_CLASSD_GAIN_2:
+	case NAU8824_REG_ANALOG_ADC_1 ... NAU8824_REG_ATT_PORT1:
+	case NAU8824_REG_POWER_UP_CONTROL ... NAU8824_REG_CHARGE_PUMP_INPUT:
+		return true;
+	default:
+		return false;
+	}
+
+}
+
+static bool nau8824_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8824_REG_RESET ... NAU8824_REG_FLL_VCO_RSV:
+	case NAU8824_REG_JACK_DET_CTRL:
+	case NAU8824_REG_INTERRUPT_SETTING_1:
+	case NAU8824_REG_CLEAR_INT_REG ... NAU8824_REG_VDET_THRESHOLD_4:
+	case NAU8824_REG_GPIO_SEL:
+	case NAU8824_REG_PORT0_I2S_PCM_CTRL_1 ... NAU8824_REG_TDM_CTRL:
+	case NAU8824_REG_ADC_HPF_FILTER ... NAU8824_REG_EQ4_EQ5:
+	case NAU8824_REG_ADC_CH0_DGAIN_CTRL ... NAU8824_REG_ADC_TO_DAC_ST:
+	case NAU8824_REG_DRC_KNEE_IP12_ADC_CH01:
+	case NAU8824_REG_DRC_KNEE_IP34_ADC_CH01:
+	case NAU8824_REG_DRC_SLOPE_ADC_CH01:
+	case NAU8824_REG_DRC_ATKDCY_ADC_CH01:
+	case NAU8824_REG_DRC_KNEE_IP12_ADC_CH23:
+	case NAU8824_REG_DRC_KNEE_IP34_ADC_CH23:
+	case NAU8824_REG_DRC_SLOPE_ADC_CH23:
+	case NAU8824_REG_DRC_ATKDCY_ADC_CH23:
+	case NAU8824_REG_DRC_KNEE_IP12_DAC ... NAU8824_REG_DRC_ATKDCY_DAC:
+	case NAU8824_REG_CLASSG ... NAU8824_REG_OTP_EFUSE:
+	case NAU8824_REG_I2C_TIMEOUT:
+	case NAU8824_REG_BIAS_ADJ ... NAU8824_REG_CLASSD_GAIN_2:
+	case NAU8824_REG_ANALOG_ADC_1 ... NAU8824_REG_ATT_PORT1:
+	case NAU8824_REG_POWER_UP_CONTROL ... NAU8824_REG_CHARGE_PUMP_CONTROL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool nau8824_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8824_REG_RESET:
+	case NAU8824_REG_IRQ ... NAU8824_REG_CLEAR_INT_REG:
+	case NAU8824_REG_DRC_GAINL_ADC0 ... NAU8824_REG_DRC_GAINL_ADC3:
+	case NAU8824_REG_DRC_GAIN_DAC_CH0 ... NAU8824_REG_DRC_GAIN_DAC_CH1:
+	case NAU8824_REG_OTPDOUT_1 ... NAU8824_REG_OTPDOUT_2:
+	case NAU8824_REG_I2C_DEVICE_ID ... NAU8824_REG_SAR_ADC_DATA_OUT:
+	case NAU8824_REG_CHARGE_PUMP_INPUT:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const char * const nau8824_companding[] = {
+	"Off", "NC", "u-law", "A-law" };
+
+static const struct soc_enum nau8824_companding_adc_enum =
+	SOC_ENUM_SINGLE(NAU8824_REG_PORT0_I2S_PCM_CTRL_1, 12,
+		ARRAY_SIZE(nau8824_companding), nau8824_companding);
+
+static const struct soc_enum nau8824_companding_dac_enum =
+	SOC_ENUM_SINGLE(NAU8824_REG_PORT0_I2S_PCM_CTRL_1, 14,
+		ARRAY_SIZE(nau8824_companding), nau8824_companding);
+
+static const char * const nau8824_adc_decimation[] = {
+	"32", "64", "128", "256" };
+
+static const struct soc_enum nau8824_adc_decimation_enum =
+	SOC_ENUM_SINGLE(NAU8824_REG_ADC_FILTER_CTRL, 0,
+		ARRAY_SIZE(nau8824_adc_decimation), nau8824_adc_decimation);
+
+static const char * const nau8824_dac_oversampl[] = {
+	"64", "256", "128", "", "32" };
+
+static const struct soc_enum nau8824_dac_oversampl_enum =
+	SOC_ENUM_SINGLE(NAU8824_REG_DAC_FILTER_CTRL_1, 0,
+		ARRAY_SIZE(nau8824_dac_oversampl), nau8824_dac_oversampl);
+
+static const char * const nau8824_input_channel[] = {
+	"Input CH0", "Input CH1", "Input CH2", "Input CH3" };
+
+static const struct soc_enum nau8824_adc_ch0_enum =
+	SOC_ENUM_SINGLE(NAU8824_REG_ADC_CH0_DGAIN_CTRL, 9,
+		ARRAY_SIZE(nau8824_input_channel), nau8824_input_channel);
+
+static const struct soc_enum nau8824_adc_ch1_enum =
+	SOC_ENUM_SINGLE(NAU8824_REG_ADC_CH1_DGAIN_CTRL, 9,
+		ARRAY_SIZE(nau8824_input_channel), nau8824_input_channel);
+
+static const struct soc_enum nau8824_adc_ch2_enum =
+	SOC_ENUM_SINGLE(NAU8824_REG_ADC_CH2_DGAIN_CTRL, 9,
+		ARRAY_SIZE(nau8824_input_channel), nau8824_input_channel);
+
+static const struct soc_enum nau8824_adc_ch3_enum =
+	SOC_ENUM_SINGLE(NAU8824_REG_ADC_CH3_DGAIN_CTRL, 9,
+		ARRAY_SIZE(nau8824_input_channel), nau8824_input_channel);
+
+static const char * const nau8824_tdm_slot[] = {
+	"Slot 0", "Slot 1", "Slot 2", "Slot 3" };
+
+static const struct soc_enum nau8824_dac_left_sel_enum =
+	SOC_ENUM_SINGLE(NAU8824_REG_TDM_CTRL, 6,
+		ARRAY_SIZE(nau8824_tdm_slot), nau8824_tdm_slot);
+
+static const struct soc_enum nau8824_dac_right_sel_enum =
+	SOC_ENUM_SINGLE(NAU8824_REG_TDM_CTRL, 4,
+		ARRAY_SIZE(nau8824_tdm_slot), nau8824_tdm_slot);
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(spk_vol_tlv, 0, 2400);
+static const DECLARE_TLV_DB_MINMAX(hp_vol_tlv, -3000, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 200, 0);
+static const DECLARE_TLV_DB_SCALE(dmic_vol_tlv, -12800, 50, 0);
+
+static const struct snd_kcontrol_new nau8824_snd_controls[] = {
+	SOC_ENUM("ADC Companding", nau8824_companding_adc_enum),
+	SOC_ENUM("DAC Companding", nau8824_companding_dac_enum),
+
+	SOC_ENUM("ADC Decimation Rate", nau8824_adc_decimation_enum),
+	SOC_ENUM("DAC Oversampling Rate", nau8824_dac_oversampl_enum),
+
+	SOC_SINGLE_TLV("Speaker Right DACR Volume",
+		NAU8824_REG_CLASSD_GAIN_1, 8, 0x1f, 0, spk_vol_tlv),
+	SOC_SINGLE_TLV("Speaker Left DACL Volume",
+		NAU8824_REG_CLASSD_GAIN_2, 0, 0x1f, 0, spk_vol_tlv),
+	SOC_SINGLE_TLV("Speaker Left DACR Volume",
+		NAU8824_REG_CLASSD_GAIN_1, 0, 0x1f, 0, spk_vol_tlv),
+	SOC_SINGLE_TLV("Speaker Right DACL Volume",
+		NAU8824_REG_CLASSD_GAIN_2, 8, 0x1f, 0, spk_vol_tlv),
+
+	SOC_SINGLE_TLV("Headphone Right DACR Volume",
+		NAU8824_REG_ATT_PORT0, 8, 0x1f, 0, hp_vol_tlv),
+	SOC_SINGLE_TLV("Headphone Left DACL Volume",
+		NAU8824_REG_ATT_PORT0, 0, 0x1f, 0, hp_vol_tlv),
+	SOC_SINGLE_TLV("Headphone Right DACL Volume",
+		NAU8824_REG_ATT_PORT1, 8, 0x1f, 0, hp_vol_tlv),
+	SOC_SINGLE_TLV("Headphone Left DACR Volume",
+		NAU8824_REG_ATT_PORT1, 0, 0x1f, 0, hp_vol_tlv),
+
+	SOC_SINGLE_TLV("MIC1 Volume", NAU8824_REG_FEPGA_II,
+		NAU8824_FEPGA_GAINL_SFT, 0x12, 0, mic_vol_tlv),
+	SOC_SINGLE_TLV("MIC2 Volume", NAU8824_REG_FEPGA_II,
+		NAU8824_FEPGA_GAINR_SFT, 0x12, 0, mic_vol_tlv),
+
+	SOC_SINGLE_TLV("DMIC1 Volume", NAU8824_REG_ADC_CH0_DGAIN_CTRL,
+		0, 0x164, 0, dmic_vol_tlv),
+	SOC_SINGLE_TLV("DMIC2 Volume", NAU8824_REG_ADC_CH1_DGAIN_CTRL,
+		0, 0x164, 0, dmic_vol_tlv),
+	SOC_SINGLE_TLV("DMIC3 Volume", NAU8824_REG_ADC_CH2_DGAIN_CTRL,
+		0, 0x164, 0, dmic_vol_tlv),
+	SOC_SINGLE_TLV("DMIC4 Volume", NAU8824_REG_ADC_CH3_DGAIN_CTRL,
+		0, 0x164, 0, dmic_vol_tlv),
+
+	SOC_ENUM("ADC CH0 Select", nau8824_adc_ch0_enum),
+	SOC_ENUM("ADC CH1 Select", nau8824_adc_ch1_enum),
+	SOC_ENUM("ADC CH2 Select", nau8824_adc_ch2_enum),
+	SOC_ENUM("ADC CH3 Select", nau8824_adc_ch3_enum),
+
+	SOC_SINGLE("ADC CH0 TX Switch", NAU8824_REG_TDM_CTRL, 0, 1, 0),
+	SOC_SINGLE("ADC CH1 TX Switch", NAU8824_REG_TDM_CTRL, 1, 1, 0),
+	SOC_SINGLE("ADC CH2 TX Switch", NAU8824_REG_TDM_CTRL, 2, 1, 0),
+	SOC_SINGLE("ADC CH3 TX Switch", NAU8824_REG_TDM_CTRL, 3, 1, 0),
+
+	SOC_ENUM("DACL Channel Source", nau8824_dac_left_sel_enum),
+	SOC_ENUM("DACR Channel Source", nau8824_dac_right_sel_enum),
+
+	SOC_SINGLE("DACL LR Mix", NAU8824_REG_DAC_MUTE_CTRL, 0, 1, 0),
+	SOC_SINGLE("DACR LR Mix", NAU8824_REG_DAC_MUTE_CTRL, 1, 1, 0),
+
+	SOC_SINGLE("THD for key media",
+		NAU8824_REG_VDET_THRESHOLD_1, 8, 0xff, 0),
+	SOC_SINGLE("THD for key voice command",
+		NAU8824_REG_VDET_THRESHOLD_1, 0, 0xff, 0),
+	SOC_SINGLE("THD for key volume up",
+		NAU8824_REG_VDET_THRESHOLD_2, 8, 0xff, 0),
+	SOC_SINGLE("THD for key volume down",
+		NAU8824_REG_VDET_THRESHOLD_2, 0, 0xff, 0),
+};
+
+static int nau8824_output_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Disables the TESTDAC to let DAC signal pass through. */
+		regmap_update_bits(nau8824->regmap, NAU8824_REG_ENABLE_LO,
+			NAU8824_TEST_DAC_EN, 0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_update_bits(nau8824->regmap, NAU8824_REG_ENABLE_LO,
+			NAU8824_TEST_DAC_EN, NAU8824_TEST_DAC_EN);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int nau8824_spk_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_update_bits(nau8824->regmap,
+			NAU8824_REG_ANALOG_CONTROL_2,
+			NAU8824_CLASSD_CLAMP_DIS, NAU8824_CLASSD_CLAMP_DIS);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_update_bits(nau8824->regmap,
+			NAU8824_REG_ANALOG_CONTROL_2,
+			NAU8824_CLASSD_CLAMP_DIS, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int nau8824_pump_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Prevent startup click by letting charge pump to ramp up */
+		msleep(10);
+		regmap_update_bits(nau8824->regmap,
+			NAU8824_REG_CHARGE_PUMP_CONTROL,
+			NAU8824_JAMNODCLOW, NAU8824_JAMNODCLOW);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_update_bits(nau8824->regmap,
+			NAU8824_REG_CHARGE_PUMP_CONTROL,
+			NAU8824_JAMNODCLOW, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int system_clock_control(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *k, int  event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = nau8824->regmap;
+	unsigned int value;
+	bool clk_fll, error;
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		dev_dbg(nau8824->dev, "system clock control : POWER OFF\n");
+		/* Set clock source to disable or internal clock before the
+		 * playback or capture end. Codec needs clock for Jack
+		 * detection and button press if jack inserted; otherwise,
+		 * the clock should be closed.
+		 */
+		if (nau8824_is_jack_inserted(nau8824)) {
+			nau8824_config_sysclk(nau8824,
+				NAU8824_CLK_INTERNAL, 0);
+		} else {
+			nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0);
+		}
+	} else {
+		dev_dbg(nau8824->dev, "system clock control : POWER ON\n");
+		/* Check the clock source setting is proper or not
+		 * no matter the source is from FLL or MCLK.
+		 */
+		regmap_read(regmap, NAU8824_REG_FLL1, &value);
+		clk_fll = value & NAU8824_FLL_RATIO_MASK;
+		/* It's error to use internal clock when playback */
+		regmap_read(regmap, NAU8824_REG_FLL6, &value);
+		error = value & NAU8824_DCO_EN;
+		if (!error) {
+			/* Check error depending on source is FLL or MCLK. */
+			regmap_read(regmap, NAU8824_REG_CLK_DIVIDER, &value);
+			if (clk_fll)
+				error = !(value & NAU8824_CLK_SRC_VCO);
+			else
+				error = value & NAU8824_CLK_SRC_VCO;
+		}
+		/* Recover the clock source setting if error. */
+		if (error) {
+			if (clk_fll) {
+				regmap_update_bits(regmap,
+					NAU8824_REG_FLL6, NAU8824_DCO_EN, 0);
+				regmap_update_bits(regmap,
+					NAU8824_REG_CLK_DIVIDER,
+					NAU8824_CLK_SRC_MASK,
+					NAU8824_CLK_SRC_VCO);
+			} else {
+				nau8824_config_sysclk(nau8824,
+					NAU8824_CLK_MCLK, 0);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int dmic_clock_control(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *k, int  event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+	int src;
+
+	/* The DMIC clock is gotten from system clock (256fs) divided by
+	 * DMIC_SRC (1, 2, 4, 8, 16, 32). The clock has to be equal or
+	 * less than 3.072 MHz.
+	 */
+	for (src = 0; src < 5; src++) {
+		if ((0x1 << (8 - src)) * nau8824->fs <= DMIC_CLK)
+			break;
+	}
+	dev_dbg(nau8824->dev, "dmic src %d for mclk %d\n", src, nau8824->fs * 256);
+	regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
+		NAU8824_CLK_DMIC_SRC_MASK, (src << NAU8824_CLK_DMIC_SRC_SFT));
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new nau8824_adc_ch0_dmic =
+	SOC_DAPM_SINGLE("Switch", NAU8824_REG_ENA_CTRL,
+		NAU8824_ADC_CH0_DMIC_SFT, 1, 0);
+
+static const struct snd_kcontrol_new nau8824_adc_ch1_dmic =
+	SOC_DAPM_SINGLE("Switch", NAU8824_REG_ENA_CTRL,
+		NAU8824_ADC_CH1_DMIC_SFT, 1, 0);
+
+static const struct snd_kcontrol_new nau8824_adc_ch2_dmic =
+	SOC_DAPM_SINGLE("Switch", NAU8824_REG_ENA_CTRL,
+		NAU8824_ADC_CH2_DMIC_SFT, 1, 0);
+
+static const struct snd_kcontrol_new nau8824_adc_ch3_dmic =
+	SOC_DAPM_SINGLE("Switch", NAU8824_REG_ENA_CTRL,
+		NAU8824_ADC_CH3_DMIC_SFT, 1, 0);
+
+static const struct snd_kcontrol_new nau8824_adc_left_mixer[] = {
+	SOC_DAPM_SINGLE("MIC Switch", NAU8824_REG_FEPGA,
+		NAU8824_FEPGA_MODEL_MIC1_SFT, 1, 0),
+	SOC_DAPM_SINGLE("HSMIC Switch", NAU8824_REG_FEPGA,
+		NAU8824_FEPGA_MODEL_HSMIC_SFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new nau8824_adc_right_mixer[] = {
+	SOC_DAPM_SINGLE("MIC Switch", NAU8824_REG_FEPGA,
+		NAU8824_FEPGA_MODER_MIC2_SFT, 1, 0),
+	SOC_DAPM_SINGLE("HSMIC Switch", NAU8824_REG_FEPGA,
+		NAU8824_FEPGA_MODER_HSMIC_SFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new nau8824_hp_left_mixer[] = {
+	SOC_DAPM_SINGLE("DAC Right Switch", NAU8824_REG_ENABLE_LO,
+		NAU8824_DACR_HPL_EN_SFT, 1, 0),
+	SOC_DAPM_SINGLE("DAC Left Switch", NAU8824_REG_ENABLE_LO,
+		NAU8824_DACL_HPL_EN_SFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new nau8824_hp_right_mixer[] = {
+	SOC_DAPM_SINGLE("DAC Left Switch", NAU8824_REG_ENABLE_LO,
+		NAU8824_DACL_HPR_EN_SFT, 1, 0),
+	SOC_DAPM_SINGLE("DAC Right Switch", NAU8824_REG_ENABLE_LO,
+		NAU8824_DACR_HPR_EN_SFT, 1, 0),
+};
+
+static const char * const nau8824_dac_src[] = { "DACL", "DACR" };
+
+static SOC_ENUM_SINGLE_DECL(
+	nau8824_dacl_enum, NAU8824_REG_DAC_CH0_DGAIN_CTRL,
+	NAU8824_DAC_CH0_SEL_SFT, nau8824_dac_src);
+
+static SOC_ENUM_SINGLE_DECL(
+	nau8824_dacr_enum, NAU8824_REG_DAC_CH1_DGAIN_CTRL,
+	NAU8824_DAC_CH1_SEL_SFT, nau8824_dac_src);
+
+static const struct snd_kcontrol_new nau8824_dacl_mux =
+	SOC_DAPM_ENUM("DACL Source", nau8824_dacl_enum);
+
+static const struct snd_kcontrol_new nau8824_dacr_mux =
+	SOC_DAPM_ENUM("DACR Source", nau8824_dacr_enum);
+
+
+static const struct snd_soc_dapm_widget nau8824_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("System Clock", SND_SOC_NOPM, 0, 0,
+		system_clock_control, SND_SOC_DAPM_POST_PMD |
+		SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_INPUT("HSMIC1"),
+	SND_SOC_DAPM_INPUT("HSMIC2"),
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("DMIC1"),
+	SND_SOC_DAPM_INPUT("DMIC2"),
+	SND_SOC_DAPM_INPUT("DMIC3"),
+	SND_SOC_DAPM_INPUT("DMIC4"),
+
+	SND_SOC_DAPM_SUPPLY("SAR", NAU8824_REG_SAR_ADC,
+		NAU8824_SAR_ADC_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS", NAU8824_REG_MIC_BIAS,
+		NAU8824_MICBIAS_POWERUP_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC12 Power", NAU8824_REG_BIAS_ADJ,
+		NAU8824_DMIC1_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC34 Power", NAU8824_REG_BIAS_ADJ,
+		NAU8824_DMIC2_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC Clock", SND_SOC_NOPM, 0, 0,
+		dmic_clock_control, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_SWITCH("DMIC1 Enable", SND_SOC_NOPM,
+		0, 0, &nau8824_adc_ch0_dmic),
+	SND_SOC_DAPM_SWITCH("DMIC2 Enable", SND_SOC_NOPM,
+		0, 0, &nau8824_adc_ch1_dmic),
+	SND_SOC_DAPM_SWITCH("DMIC3 Enable", SND_SOC_NOPM,
+		0, 0, &nau8824_adc_ch2_dmic),
+	SND_SOC_DAPM_SWITCH("DMIC4 Enable", SND_SOC_NOPM,
+		0, 0, &nau8824_adc_ch3_dmic),
+
+	SND_SOC_DAPM_MIXER("Left ADC", NAU8824_REG_POWER_UP_CONTROL,
+		12, 0, nau8824_adc_left_mixer,
+		ARRAY_SIZE(nau8824_adc_left_mixer)),
+	SND_SOC_DAPM_MIXER("Right ADC", NAU8824_REG_POWER_UP_CONTROL,
+		13, 0, nau8824_adc_right_mixer,
+		ARRAY_SIZE(nau8824_adc_right_mixer)),
+
+	SND_SOC_DAPM_ADC("ADCL", NULL, NAU8824_REG_ANALOG_ADC_2,
+		NAU8824_ADCL_EN_SFT, 0),
+	SND_SOC_DAPM_ADC("ADCR", NULL, NAU8824_REG_ANALOG_ADC_2,
+		NAU8824_ADCR_EN_SFT, 0),
+
+	SND_SOC_DAPM_AIF_OUT("AIFTX", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIFRX", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_DAC("DACL", NULL, NAU8824_REG_RDAC,
+		NAU8824_DACL_EN_SFT, 0),
+	SND_SOC_DAPM_SUPPLY("DACL Clock", NAU8824_REG_RDAC,
+		NAU8824_DACL_CLK_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("DACR", NULL, NAU8824_REG_RDAC,
+		NAU8824_DACR_EN_SFT, 0),
+	SND_SOC_DAPM_SUPPLY("DACR Clock", NAU8824_REG_RDAC,
+		NAU8824_DACR_CLK_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &nau8824_dacl_mux),
+	SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &nau8824_dacr_mux),
+
+	SND_SOC_DAPM_PGA_S("Output DACL", 0, NAU8824_REG_CHARGE_PUMP_CONTROL,
+		8, 1, nau8824_output_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_S("Output DACR", 0, NAU8824_REG_CHARGE_PUMP_CONTROL,
+		9, 1, nau8824_output_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_S("ClassD", 0, NAU8824_REG_CLASSD_GAIN_1,
+		NAU8824_CLASSD_EN_SFT, 0, nau8824_spk_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER("Left Headphone", NAU8824_REG_CLASSG,
+		NAU8824_CLASSG_LDAC_EN_SFT, 0, nau8824_hp_left_mixer,
+		ARRAY_SIZE(nau8824_hp_left_mixer)),
+	SND_SOC_DAPM_MIXER("Right Headphone", NAU8824_REG_CLASSG,
+		NAU8824_CLASSG_RDAC_EN_SFT, 0, nau8824_hp_right_mixer,
+		ARRAY_SIZE(nau8824_hp_right_mixer)),
+	SND_SOC_DAPM_PGA_S("Charge Pump", 1, NAU8824_REG_CHARGE_PUMP_CONTROL,
+		NAU8824_CHARGE_PUMP_EN_SFT, 0, nau8824_pump_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA("Output Driver L",
+		NAU8824_REG_POWER_UP_CONTROL, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Output Driver R",
+		NAU8824_REG_POWER_UP_CONTROL, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Main Driver L",
+		NAU8824_REG_POWER_UP_CONTROL, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Main Driver R",
+		NAU8824_REG_POWER_UP_CONTROL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HP Boost Driver", NAU8824_REG_BOOST,
+		NAU8824_HP_BOOST_DIS_SFT, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Class G", NAU8824_REG_CLASSG,
+		NAU8824_CLASSG_EN_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("SPKOUTL"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTR"),
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_route nau8824_dapm_routes[] = {
+	{"DMIC1 Enable", "Switch", "DMIC1"},
+	{"DMIC2 Enable", "Switch", "DMIC2"},
+	{"DMIC3 Enable", "Switch", "DMIC3"},
+	{"DMIC4 Enable", "Switch", "DMIC4"},
+
+	{"DMIC1", NULL, "DMIC12 Power"},
+	{"DMIC2", NULL, "DMIC12 Power"},
+	{"DMIC3", NULL, "DMIC34 Power"},
+	{"DMIC4", NULL, "DMIC34 Power"},
+	{"DMIC12 Power", NULL, "DMIC Clock"},
+	{"DMIC34 Power", NULL, "DMIC Clock"},
+
+	{"Left ADC", "MIC Switch", "MIC1"},
+	{"Left ADC", "HSMIC Switch", "HSMIC1"},
+	{"Right ADC", "MIC Switch", "MIC2"},
+	{"Right ADC", "HSMIC Switch", "HSMIC2"},
+
+	{"ADCL", NULL, "Left ADC"},
+	{"ADCR", NULL, "Right ADC"},
+
+	{"AIFTX", NULL, "MICBIAS"},
+	{"AIFTX", NULL, "ADCL"},
+	{"AIFTX", NULL, "ADCR"},
+	{"AIFTX", NULL, "DMIC1 Enable"},
+	{"AIFTX", NULL, "DMIC2 Enable"},
+	{"AIFTX", NULL, "DMIC3 Enable"},
+	{"AIFTX", NULL, "DMIC4 Enable"},
+
+	{"AIFTX", NULL, "System Clock"},
+	{"AIFRX", NULL, "System Clock"},
+
+	{"DACL", NULL, "AIFRX"},
+	{"DACL", NULL, "DACL Clock"},
+	{"DACR", NULL, "AIFRX"},
+	{"DACR", NULL, "DACR Clock"},
+
+	{"DACL Mux", "DACL", "DACL"},
+	{"DACL Mux", "DACR", "DACR"},
+	{"DACR Mux", "DACL", "DACL"},
+	{"DACR Mux", "DACR", "DACR"},
+
+	{"Output DACL", NULL, "DACL Mux"},
+	{"Output DACR", NULL, "DACR Mux"},
+
+	{"ClassD", NULL, "Output DACL"},
+	{"ClassD", NULL, "Output DACR"},
+
+	{"Left Headphone", "DAC Left Switch", "Output DACL"},
+	{"Left Headphone", "DAC Right Switch", "Output DACR"},
+	{"Right Headphone", "DAC Left Switch", "Output DACL"},
+	{"Right Headphone", "DAC Right Switch", "Output DACR"},
+
+	{"Charge Pump", NULL, "Left Headphone"},
+	{"Charge Pump", NULL, "Right Headphone"},
+	{"Output Driver L", NULL, "Charge Pump"},
+	{"Output Driver R", NULL, "Charge Pump"},
+	{"Main Driver L", NULL, "Output Driver L"},
+	{"Main Driver R", NULL, "Output Driver R"},
+	{"Class G", NULL, "Main Driver L"},
+	{"Class G", NULL, "Main Driver R"},
+	{"HP Boost Driver", NULL, "Class G"},
+
+	{"SPKOUTL", NULL, "ClassD"},
+	{"SPKOUTR", NULL, "ClassD"},
+	{"HPOL", NULL, "HP Boost Driver"},
+	{"HPOR", NULL, "HP Boost Driver"},
+};
+
+static bool nau8824_is_jack_inserted(struct nau8824 *nau8824)
+{
+	struct snd_soc_jack *jack = nau8824->jack;
+	bool insert = FALSE;
+
+	if (nau8824->irq && jack)
+		insert = jack->status & SND_JACK_HEADPHONE;
+
+	return insert;
+}
+
+static void nau8824_int_status_clear_all(struct regmap *regmap)
+{
+	int active_irq, clear_irq, i;
+
+	/* Reset the intrruption status from rightmost bit if the corres-
+	 * ponding irq event occurs.
+	 */
+	regmap_read(regmap, NAU8824_REG_IRQ, &active_irq);
+	for (i = 0; i < NAU8824_REG_DATA_LEN; i++) {
+		clear_irq = (0x1 << i);
+		if (active_irq & clear_irq)
+			regmap_write(regmap,
+				NAU8824_REG_CLEAR_INT_REG, clear_irq);
+	}
+}
+
+static void nau8824_eject_jack(struct nau8824 *nau8824)
+{
+	struct snd_soc_dapm_context *dapm = nau8824->dapm;
+	struct regmap *regmap = nau8824->regmap;
+
+	/* Clear all interruption status */
+	nau8824_int_status_clear_all(regmap);
+
+	snd_soc_dapm_disable_pin(dapm, "SAR");
+	snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+	snd_soc_dapm_sync(dapm);
+
+	/* Enable the insertion interruption, disable the ejection
+	 * interruption, and then bypass de-bounce circuit.
+	 */
+	regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING,
+		NAU8824_IRQ_KEY_RELEASE_DIS | NAU8824_IRQ_KEY_SHORT_PRESS_DIS |
+		NAU8824_IRQ_EJECT_DIS | NAU8824_IRQ_INSERT_DIS,
+		NAU8824_IRQ_KEY_RELEASE_DIS | NAU8824_IRQ_KEY_SHORT_PRESS_DIS |
+		NAU8824_IRQ_EJECT_DIS);
+	regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING_1,
+		NAU8824_IRQ_INSERT_EN | NAU8824_IRQ_EJECT_EN,
+		NAU8824_IRQ_INSERT_EN);
+	regmap_update_bits(regmap, NAU8824_REG_ENA_CTRL,
+		NAU8824_JD_SLEEP_MODE, NAU8824_JD_SLEEP_MODE);
+
+	/* Close clock for jack type detection at manual mode */
+	if (dapm->bias_level < SND_SOC_BIAS_PREPARE)
+		nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0);
+}
+
+static void nau8824_jdet_work(struct work_struct *work)
+{
+	struct nau8824 *nau8824 = container_of(
+		work, struct nau8824, jdet_work);
+	struct snd_soc_dapm_context *dapm = nau8824->dapm;
+	struct regmap *regmap = nau8824->regmap;
+	int adc_value, event = 0, event_mask = 0;
+
+	snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+	snd_soc_dapm_force_enable_pin(dapm, "SAR");
+	snd_soc_dapm_sync(dapm);
+
+	msleep(100);
+
+	regmap_read(regmap, NAU8824_REG_SAR_ADC_DATA_OUT, &adc_value);
+	adc_value = adc_value & NAU8824_SAR_ADC_DATA_MASK;
+	dev_dbg(nau8824->dev, "SAR ADC data 0x%02x\n", adc_value);
+	if (adc_value < HEADSET_SARADC_THD) {
+		event |= SND_JACK_HEADPHONE;
+
+		snd_soc_dapm_disable_pin(dapm, "SAR");
+		snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+		snd_soc_dapm_sync(dapm);
+	} else {
+		event |= SND_JACK_HEADSET;
+	}
+	event_mask |= SND_JACK_HEADSET;
+	snd_soc_jack_report(nau8824->jack, event, event_mask);
+
+	/* Enable short key press and release interruption. */
+	regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING,
+		NAU8824_IRQ_KEY_RELEASE_DIS |
+		NAU8824_IRQ_KEY_SHORT_PRESS_DIS, 0);
+
+	nau8824_sema_release(nau8824);
+}
+
+static void nau8824_setup_auto_irq(struct nau8824 *nau8824)
+{
+	struct regmap *regmap = nau8824->regmap;
+
+	/* Enable jack ejection interruption. */
+	regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING_1,
+		NAU8824_IRQ_INSERT_EN | NAU8824_IRQ_EJECT_EN,
+		NAU8824_IRQ_EJECT_EN);
+	regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING,
+		NAU8824_IRQ_EJECT_DIS, 0);
+	/* Enable internal VCO needed for interruptions */
+	if (nau8824->dapm->bias_level < SND_SOC_BIAS_PREPARE)
+		nau8824_config_sysclk(nau8824, NAU8824_CLK_INTERNAL, 0);
+	regmap_update_bits(regmap, NAU8824_REG_ENA_CTRL,
+		NAU8824_JD_SLEEP_MODE, 0);
+}
+
+static int nau8824_button_decode(int value)
+{
+	int buttons = 0;
+
+	/* The chip supports up to 8 buttons, but ALSA defines
+	 * only 6 buttons.
+	 */
+	if (value & BIT(0))
+		buttons |= SND_JACK_BTN_0;
+	if (value & BIT(1))
+		buttons |= SND_JACK_BTN_1;
+	if (value & BIT(2))
+		buttons |= SND_JACK_BTN_2;
+	if (value & BIT(3))
+		buttons |= SND_JACK_BTN_3;
+	if (value & BIT(4))
+		buttons |= SND_JACK_BTN_4;
+	if (value & BIT(5))
+		buttons |= SND_JACK_BTN_5;
+
+	return buttons;
+}
+
+#define NAU8824_BUTTONS (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
+		SND_JACK_BTN_2 | SND_JACK_BTN_3)
+
+static irqreturn_t nau8824_interrupt(int irq, void *data)
+{
+	struct nau8824 *nau8824 = (struct nau8824 *)data;
+	struct regmap *regmap = nau8824->regmap;
+	int active_irq, clear_irq = 0, event = 0, event_mask = 0;
+
+	if (regmap_read(regmap, NAU8824_REG_IRQ, &active_irq)) {
+		dev_err(nau8824->dev, "failed to read irq status\n");
+		return IRQ_NONE;
+	}
+	dev_dbg(nau8824->dev, "IRQ %x\n", active_irq);
+
+	if (active_irq & NAU8824_JACK_EJECTION_DETECTED) {
+		nau8824_eject_jack(nau8824);
+		event_mask |= SND_JACK_HEADSET;
+		clear_irq = NAU8824_JACK_EJECTION_DETECTED;
+		/* release semaphore held after resume,
+		 * and cancel jack detection
+		 */
+		nau8824_sema_release(nau8824);
+		cancel_work_sync(&nau8824->jdet_work);
+	} else if (active_irq & NAU8824_KEY_SHORT_PRESS_IRQ) {
+		int key_status, button_pressed;
+
+		regmap_read(regmap, NAU8824_REG_CLEAR_INT_REG,
+			&key_status);
+
+		/* lower 8 bits of the register are for pressed keys */
+		button_pressed = nau8824_button_decode(key_status);
+
+		event |= button_pressed;
+		dev_dbg(nau8824->dev, "button %x pressed\n", event);
+		event_mask |= NAU8824_BUTTONS;
+		clear_irq = NAU8824_KEY_SHORT_PRESS_IRQ;
+	} else if (active_irq & NAU8824_KEY_RELEASE_IRQ) {
+		event_mask = NAU8824_BUTTONS;
+		clear_irq = NAU8824_KEY_RELEASE_IRQ;
+	} else if (active_irq & NAU8824_JACK_INSERTION_DETECTED) {
+		/* Turn off insertion interruption at manual mode */
+		regmap_update_bits(regmap,
+			NAU8824_REG_INTERRUPT_SETTING,
+			NAU8824_IRQ_INSERT_DIS,
+			NAU8824_IRQ_INSERT_DIS);
+		regmap_update_bits(regmap,
+			NAU8824_REG_INTERRUPT_SETTING_1,
+			NAU8824_IRQ_INSERT_EN, 0);
+		/* detect microphone and jack type */
+		cancel_work_sync(&nau8824->jdet_work);
+		schedule_work(&nau8824->jdet_work);
+
+		/* Enable interruption for jack type detection at audo
+		 * mode which can detect microphone and jack type.
+		 */
+		nau8824_setup_auto_irq(nau8824);
+	}
+
+	if (!clear_irq)
+		clear_irq = active_irq;
+	/* clears the rightmost interruption */
+	regmap_write(regmap, NAU8824_REG_CLEAR_INT_REG, clear_irq);
+
+	if (event_mask)
+		snd_soc_jack_report(nau8824->jack, event, event_mask);
+
+	return IRQ_HANDLED;
+}
+
+static int nau8824_clock_check(struct nau8824 *nau8824,
+	int stream, int rate, int osr)
+{
+	int osrate;
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (osr >= ARRAY_SIZE(osr_dac_sel))
+			return -EINVAL;
+		osrate = osr_dac_sel[osr].osr;
+	} else {
+		if (osr >= ARRAY_SIZE(osr_adc_sel))
+			return -EINVAL;
+		osrate = osr_adc_sel[osr].osr;
+	}
+
+	if (!osrate || rate * osr > CLK_DA_AD_MAX) {
+		dev_err(nau8824->dev, "exceed the maximum frequency of CLK_ADC or CLK_DAC\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int nau8824_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0, osr, ctrl_val, bclk_fs, bclk_div;
+
+	nau8824_sema_acquire(nau8824, HZ);
+
+	/* CLK_DAC or CLK_ADC = OSR * FS
+	 * DAC or ADC clock frequency is defined as Over Sampling Rate (OSR)
+	 * multiplied by the audio sample rate (Fs). Note that the OSR and Fs
+	 * values must be selected such that the maximum frequency is less
+	 * than 6.144 MHz.
+	 */
+	nau8824->fs = params_rate(params);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		regmap_read(nau8824->regmap,
+			NAU8824_REG_DAC_FILTER_CTRL_1, &osr);
+		osr &= NAU8824_DAC_OVERSAMPLE_MASK;
+		if (nau8824_clock_check(nau8824, substream->stream,
+			nau8824->fs, osr))
+			return -EINVAL;
+		regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
+			NAU8824_CLK_DAC_SRC_MASK,
+			osr_dac_sel[osr].clk_src << NAU8824_CLK_DAC_SRC_SFT);
+	} else {
+		regmap_read(nau8824->regmap,
+			NAU8824_REG_ADC_FILTER_CTRL, &osr);
+		osr &= NAU8824_ADC_SYNC_DOWN_MASK;
+		if (nau8824_clock_check(nau8824, substream->stream,
+			nau8824->fs, osr))
+			return -EINVAL;
+		regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
+			NAU8824_CLK_ADC_SRC_MASK,
+			osr_adc_sel[osr].clk_src << NAU8824_CLK_ADC_SRC_SFT);
+	}
+
+	/* make BCLK and LRC divde configuration if the codec as master. */
+	regmap_read(nau8824->regmap,
+		NAU8824_REG_PORT0_I2S_PCM_CTRL_2, &ctrl_val);
+	if (ctrl_val & NAU8824_I2S_MS_MASTER) {
+		/* get the bclk and fs ratio */
+		bclk_fs = snd_soc_params_to_bclk(params) / nau8824->fs;
+		if (bclk_fs <= 32)
+			bclk_div = 0x3;
+		else if (bclk_fs <= 64)
+			bclk_div = 0x2;
+		else if (bclk_fs <= 128)
+			bclk_div = 0x1;
+		else if (bclk_fs <= 256)
+			bclk_div = 0;
+		else
+			return -EINVAL;
+		regmap_update_bits(nau8824->regmap,
+			NAU8824_REG_PORT0_I2S_PCM_CTRL_2,
+			NAU8824_I2S_LRC_DIV_MASK | NAU8824_I2S_BLK_DIV_MASK,
+			(bclk_div << NAU8824_I2S_LRC_DIV_SFT) | bclk_div);
+	}
+
+	switch (params_width(params)) {
+	case 16:
+		val_len |= NAU8824_I2S_DL_16;
+		break;
+	case 20:
+		val_len |= NAU8824_I2S_DL_20;
+		break;
+	case 24:
+		val_len |= NAU8824_I2S_DL_24;
+		break;
+	case 32:
+		val_len |= NAU8824_I2S_DL_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_I2S_PCM_CTRL_1,
+		NAU8824_I2S_DL_MASK, val_len);
+
+	nau8824_sema_release(nau8824);
+
+	return 0;
+}
+
+static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+	unsigned int ctrl1_val = 0, ctrl2_val = 0;
+
+	nau8824_sema_acquire(nau8824, HZ);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		ctrl2_val |= NAU8824_I2S_MS_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		ctrl1_val |= NAU8824_I2S_BP_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		ctrl1_val |= NAU8824_I2S_DF_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ctrl1_val |= NAU8824_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		ctrl1_val |= NAU8824_I2S_DF_RIGTH;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		ctrl1_val |= NAU8824_I2S_DF_PCM_AB;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		ctrl1_val |= NAU8824_I2S_DF_PCM_AB;
+		ctrl1_val |= NAU8824_I2S_PCMB_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_I2S_PCM_CTRL_1,
+		NAU8824_I2S_DF_MASK | NAU8824_I2S_BP_MASK |
+		NAU8824_I2S_PCMB_EN, ctrl1_val);
+	regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_I2S_PCM_CTRL_2,
+		NAU8824_I2S_MS_MASK, ctrl2_val);
+
+	nau8824_sema_release(nau8824);
+
+	return 0;
+}
+
+/**
+ * nau8824_set_tdm_slot - configure DAI TDM.
+ * @dai: DAI
+ * @tx_mask: Bitmask representing active TX slots. Ex.
+ *                 0xf for normal 4 channel TDM.
+ *                 0xf0 for shifted 4 channel TDM
+ * @rx_mask: Bitmask [0:1] representing active DACR RX slots.
+ *                 Bitmask [2:3] representing active DACL RX slots.
+ *                 00=CH0,01=CH1,10=CH2,11=CH3. Ex.
+ *                 0xf for DACL/R selecting TDM CH3.
+ *                 0xf0 for DACL/R selecting shifted TDM CH3.
+ * @slots: Number of slots in use.
+ * @slot_width: Width in bits for each slot.
+ *
+ * Configures a DAI for TDM operation. Only support 4 slots TDM.
+ */
+static int nau8824_set_tdm_slot(struct snd_soc_dai *dai,
+	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+	unsigned int tslot_l = 0, ctrl_val = 0;
+
+	if (slots > 4 || ((tx_mask & 0xf0) && (tx_mask & 0xf)) ||
+		((rx_mask & 0xf0) && (rx_mask & 0xf)) ||
+		((rx_mask & 0xf0) && (tx_mask & 0xf)) ||
+		((rx_mask & 0xf) && (tx_mask & 0xf0)))
+		return -EINVAL;
+
+	ctrl_val |= (NAU8824_TDM_MODE | NAU8824_TDM_OFFSET_EN);
+	if (tx_mask & 0xf0) {
+		tslot_l = 4 * slot_width;
+		ctrl_val |= (tx_mask >> 4);
+	} else {
+		ctrl_val |= tx_mask;
+	}
+	if (rx_mask & 0xf0)
+		ctrl_val |= ((rx_mask >> 4) << NAU8824_TDM_DACR_RX_SFT);
+	else
+		ctrl_val |= (rx_mask << NAU8824_TDM_DACR_RX_SFT);
+
+	regmap_update_bits(nau8824->regmap, NAU8824_REG_TDM_CTRL,
+		NAU8824_TDM_MODE | NAU8824_TDM_OFFSET_EN |
+		NAU8824_TDM_DACL_RX_MASK | NAU8824_TDM_DACR_RX_MASK |
+		NAU8824_TDM_TX_MASK, ctrl_val);
+	regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_LEFT_TIME_SLOT,
+		NAU8824_TSLOT_L_MASK, tslot_l);
+
+	return 0;
+}
+
+/**
+ * nau8824_calc_fll_param - Calculate FLL parameters.
+ * @fll_in: external clock provided to codec.
+ * @fs: sampling rate.
+ * @fll_param: Pointer to structure of FLL parameters.
+ *
+ * Calculate FLL parameters to configure codec.
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int nau8824_calc_fll_param(unsigned int fll_in,
+	unsigned int fs, struct nau8824_fll *fll_param)
+{
+	u64 fvco, fvco_max;
+	unsigned int fref, i, fvco_sel;
+
+	/* Ensure the reference clock frequency (FREF) is <= 13.5MHz by dividing
+	 * freq_in by 1, 2, 4, or 8 using FLL pre-scalar.
+	 * FREF = freq_in / NAU8824_FLL_REF_DIV_MASK
+	 */
+	for (i = 0; i < ARRAY_SIZE(fll_pre_scalar); i++) {
+		fref = fll_in / fll_pre_scalar[i].param;
+		if (fref <= NAU_FREF_MAX)
+			break;
+	}
+	if (i == ARRAY_SIZE(fll_pre_scalar))
+		return -EINVAL;
+	fll_param->clk_ref_div = fll_pre_scalar[i].val;
+
+	/* Choose the FLL ratio based on FREF */
+	for (i = 0; i < ARRAY_SIZE(fll_ratio); i++) {
+		if (fref >= fll_ratio[i].param)
+			break;
+	}
+	if (i == ARRAY_SIZE(fll_ratio))
+		return -EINVAL;
+	fll_param->ratio = fll_ratio[i].val;
+
+	/* Calculate the frequency of DCO (FDCO) given freq_out = 256 * Fs.
+	 * FDCO must be within the 90MHz - 124MHz or the FFL cannot be
+	 * guaranteed across the full range of operation.
+	 * FDCO = freq_out * 2 * mclk_src_scaling
+	 */
+	fvco_max = 0;
+	fvco_sel = ARRAY_SIZE(mclk_src_scaling);
+	for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) {
+		fvco = 256ULL * fs * 2 * mclk_src_scaling[i].param;
+		if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX &&
+			fvco_max < fvco) {
+			fvco_max = fvco;
+			fvco_sel = i;
+		}
+	}
+	if (ARRAY_SIZE(mclk_src_scaling) == fvco_sel)
+		return -EINVAL;
+	fll_param->mclk_src = mclk_src_scaling[fvco_sel].val;
+
+	/* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional
+	 * input based on FDCO, FREF and FLL ratio.
+	 */
+	fvco = div_u64(fvco_max << 16, fref * fll_param->ratio);
+	fll_param->fll_int = (fvco >> 16) & 0x3FF;
+	fll_param->fll_frac = fvco & 0xFFFF;
+	return 0;
+}
+
+static void nau8824_fll_apply(struct regmap *regmap,
+	struct nau8824_fll *fll_param)
+{
+	regmap_update_bits(regmap, NAU8824_REG_CLK_DIVIDER,
+		NAU8824_CLK_SRC_MASK | NAU8824_CLK_MCLK_SRC_MASK,
+		NAU8824_CLK_SRC_MCLK | fll_param->mclk_src);
+	regmap_update_bits(regmap, NAU8824_REG_FLL1,
+		NAU8824_FLL_RATIO_MASK, fll_param->ratio);
+	/* FLL 16-bit fractional input */
+	regmap_write(regmap, NAU8824_REG_FLL2, fll_param->fll_frac);
+	/* FLL 10-bit integer input */
+	regmap_update_bits(regmap, NAU8824_REG_FLL3,
+		NAU8824_FLL_INTEGER_MASK, fll_param->fll_int);
+	/* FLL pre-scaler */
+	regmap_update_bits(regmap, NAU8824_REG_FLL4,
+		NAU8824_FLL_REF_DIV_MASK,
+		fll_param->clk_ref_div << NAU8824_FLL_REF_DIV_SFT);
+	/* select divided VCO input */
+	regmap_update_bits(regmap, NAU8824_REG_FLL5,
+		NAU8824_FLL_CLK_SW_MASK, NAU8824_FLL_CLK_SW_REF);
+	/* Disable free-running mode */
+	regmap_update_bits(regmap,
+		NAU8824_REG_FLL6, NAU8824_DCO_EN, 0);
+	if (fll_param->fll_frac) {
+		regmap_update_bits(regmap, NAU8824_REG_FLL5,
+			NAU8824_FLL_PDB_DAC_EN | NAU8824_FLL_LOOP_FTR_EN |
+			NAU8824_FLL_FTR_SW_MASK,
+			NAU8824_FLL_PDB_DAC_EN | NAU8824_FLL_LOOP_FTR_EN |
+			NAU8824_FLL_FTR_SW_FILTER);
+		regmap_update_bits(regmap, NAU8824_REG_FLL6,
+			NAU8824_SDM_EN, NAU8824_SDM_EN);
+	} else {
+		regmap_update_bits(regmap, NAU8824_REG_FLL5,
+			NAU8824_FLL_PDB_DAC_EN | NAU8824_FLL_LOOP_FTR_EN |
+			NAU8824_FLL_FTR_SW_MASK, NAU8824_FLL_FTR_SW_ACCU);
+		regmap_update_bits(regmap,
+			NAU8824_REG_FLL6, NAU8824_SDM_EN, 0);
+	}
+}
+
+/* freq_out must be 256*Fs in order to achieve the best performance */
+static int nau8824_set_pll(struct snd_soc_component *component, int pll_id, int source,
+		unsigned int freq_in, unsigned int freq_out)
+{
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+	struct nau8824_fll fll_param;
+	int ret, fs;
+
+	fs = freq_out / 256;
+	ret = nau8824_calc_fll_param(freq_in, fs, &fll_param);
+	if (ret < 0) {
+		dev_err(nau8824->dev, "Unsupported input clock %d\n", freq_in);
+		return ret;
+	}
+	dev_dbg(nau8824->dev, "mclk_src=%x ratio=%x fll_frac=%x fll_int=%x clk_ref_div=%x\n",
+		fll_param.mclk_src, fll_param.ratio, fll_param.fll_frac,
+		fll_param.fll_int, fll_param.clk_ref_div);
+
+	nau8824_fll_apply(nau8824->regmap, &fll_param);
+	mdelay(2);
+	regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
+		NAU8824_CLK_SRC_MASK, NAU8824_CLK_SRC_VCO);
+
+	return 0;
+}
+
+static int nau8824_config_sysclk(struct nau8824 *nau8824,
+	int clk_id, unsigned int freq)
+{
+	struct regmap *regmap = nau8824->regmap;
+
+	switch (clk_id) {
+	case NAU8824_CLK_DIS:
+		regmap_update_bits(regmap, NAU8824_REG_CLK_DIVIDER,
+			NAU8824_CLK_SRC_MASK, NAU8824_CLK_SRC_MCLK);
+		regmap_update_bits(regmap, NAU8824_REG_FLL6,
+			NAU8824_DCO_EN, 0);
+		break;
+
+	case NAU8824_CLK_MCLK:
+		nau8824_sema_acquire(nau8824, HZ);
+		regmap_update_bits(regmap, NAU8824_REG_CLK_DIVIDER,
+			NAU8824_CLK_SRC_MASK, NAU8824_CLK_SRC_MCLK);
+		regmap_update_bits(regmap, NAU8824_REG_FLL6,
+			NAU8824_DCO_EN, 0);
+		nau8824_sema_release(nau8824);
+		break;
+
+	case NAU8824_CLK_INTERNAL:
+		regmap_update_bits(regmap, NAU8824_REG_FLL6,
+			NAU8824_DCO_EN, NAU8824_DCO_EN);
+		regmap_update_bits(regmap, NAU8824_REG_CLK_DIVIDER,
+			NAU8824_CLK_SRC_MASK, NAU8824_CLK_SRC_VCO);
+		break;
+
+	case NAU8824_CLK_FLL_MCLK:
+		nau8824_sema_acquire(nau8824, HZ);
+		regmap_update_bits(regmap, NAU8824_REG_FLL3,
+			NAU8824_FLL_CLK_SRC_MASK, NAU8824_FLL_CLK_SRC_MCLK);
+		nau8824_sema_release(nau8824);
+		break;
+
+	case NAU8824_CLK_FLL_BLK:
+		nau8824_sema_acquire(nau8824, HZ);
+		regmap_update_bits(regmap, NAU8824_REG_FLL3,
+			NAU8824_FLL_CLK_SRC_MASK, NAU8824_FLL_CLK_SRC_BLK);
+		nau8824_sema_release(nau8824);
+		break;
+
+	case NAU8824_CLK_FLL_FS:
+		nau8824_sema_acquire(nau8824, HZ);
+		regmap_update_bits(regmap, NAU8824_REG_FLL3,
+			NAU8824_FLL_CLK_SRC_MASK, NAU8824_FLL_CLK_SRC_FS);
+		nau8824_sema_release(nau8824);
+		break;
+
+	default:
+		dev_err(nau8824->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+
+	dev_dbg(nau8824->dev, "Sysclk is %dHz and clock id is %d\n", freq,
+		clk_id);
+
+	return 0;
+}
+
+static int nau8824_set_sysclk(struct snd_soc_component *component,
+	int clk_id, int source, unsigned int freq, int dir)
+{
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+
+	return nau8824_config_sysclk(nau8824, clk_id, freq);
+}
+
+static void nau8824_resume_setup(struct nau8824 *nau8824)
+{
+	nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0);
+	if (nau8824->irq) {
+		/* Clear all interruption status */
+		nau8824_int_status_clear_all(nau8824->regmap);
+		/* Enable jack detection at sleep mode, insertion detection,
+		 * and ejection detection.
+		 */
+		regmap_update_bits(nau8824->regmap, NAU8824_REG_ENA_CTRL,
+			NAU8824_JD_SLEEP_MODE, NAU8824_JD_SLEEP_MODE);
+		regmap_update_bits(nau8824->regmap,
+			NAU8824_REG_INTERRUPT_SETTING_1,
+			NAU8824_IRQ_EJECT_EN | NAU8824_IRQ_INSERT_EN,
+			NAU8824_IRQ_EJECT_EN | NAU8824_IRQ_INSERT_EN);
+		regmap_update_bits(nau8824->regmap,
+			NAU8824_REG_INTERRUPT_SETTING,
+			NAU8824_IRQ_EJECT_DIS | NAU8824_IRQ_INSERT_DIS, 0);
+	}
+}
+
+static int nau8824_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/* Setup codec configuration after resume */
+			nau8824_resume_setup(nau8824);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		regmap_update_bits(nau8824->regmap,
+			NAU8824_REG_INTERRUPT_SETTING, 0x3ff, 0x3ff);
+		regmap_update_bits(nau8824->regmap,
+			NAU8824_REG_INTERRUPT_SETTING_1,
+			NAU8824_IRQ_EJECT_EN | NAU8824_IRQ_INSERT_EN, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static int nau8824_component_probe(struct snd_soc_component *component)
+{
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	nau8824->dapm = dapm;
+
+	return 0;
+}
+
+static int __maybe_unused nau8824_suspend(struct snd_soc_component *component)
+{
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+
+	if (nau8824->irq) {
+		disable_irq(nau8824->irq);
+		snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+	}
+	regcache_cache_only(nau8824->regmap, true);
+	regcache_mark_dirty(nau8824->regmap);
+
+	return 0;
+}
+
+static int __maybe_unused nau8824_resume(struct snd_soc_component *component)
+{
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(nau8824->regmap, false);
+	regcache_sync(nau8824->regmap);
+	if (nau8824->irq) {
+		/* Hold semaphore to postpone playback happening
+		 * until jack detection done.
+		 */
+		nau8824_sema_acquire(nau8824, 0);
+		enable_irq(nau8824->irq);
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver nau8824_component_driver = {
+	.probe			= nau8824_component_probe,
+	.set_sysclk		= nau8824_set_sysclk,
+	.set_pll		= nau8824_set_pll,
+	.set_bias_level		= nau8824_set_bias_level,
+	.suspend		= nau8824_suspend,
+	.resume			= nau8824_resume,
+	.controls		= nau8824_snd_controls,
+	.num_controls		= ARRAY_SIZE(nau8824_snd_controls),
+	.dapm_widgets		= nau8824_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(nau8824_dapm_widgets),
+	.dapm_routes		= nau8824_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(nau8824_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct snd_soc_dai_ops nau8824_dai_ops = {
+	.hw_params = nau8824_hw_params,
+	.set_fmt = nau8824_set_fmt,
+	.set_tdm_slot = nau8824_set_tdm_slot,
+};
+
+#define NAU8824_RATES SNDRV_PCM_RATE_8000_192000
+#define NAU8824_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+	 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver nau8824_dai = {
+	.name = NAU8824_CODEC_DAI,
+	.playback = {
+		.stream_name	 = "Playback",
+		.channels_min	 = 1,
+		.channels_max	 = 2,
+		.rates		 = NAU8824_RATES,
+		.formats	 = NAU8824_FORMATS,
+	},
+	.capture = {
+		.stream_name	 = "Capture",
+		.channels_min	 = 1,
+		.channels_max	 = 2,
+		.rates		 = NAU8824_RATES,
+		.formats	 = NAU8824_FORMATS,
+	},
+	.ops = &nau8824_dai_ops,
+};
+
+static const struct regmap_config nau8824_regmap_config = {
+	.val_bits = NAU8824_REG_ADDR_LEN,
+	.reg_bits = NAU8824_REG_DATA_LEN,
+
+	.max_register = NAU8824_REG_MAX,
+	.readable_reg = nau8824_readable_reg,
+	.writeable_reg = nau8824_writeable_reg,
+	.volatile_reg = nau8824_volatile_reg,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = nau8824_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(nau8824_reg_defaults),
+};
+
+/**
+ * nau8824_enable_jack_detect - Specify a jack for event reporting
+ *
+ * @component:  component to register the jack with
+ * @jack: jack to use to report headset and button events on
+ *
+ * After this function has been called the headset insert/remove and button
+ * events will be routed to the given jack.  Jack can be null to stop
+ * reporting.
+ */
+int nau8824_enable_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *jack)
+{
+	struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	nau8824->jack = jack;
+	/* Initiate jack detection work queue */
+	INIT_WORK(&nau8824->jdet_work, nau8824_jdet_work);
+	ret = devm_request_threaded_irq(nau8824->dev, nau8824->irq, NULL,
+		nau8824_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+		"nau8824", nau8824);
+	if (ret) {
+		dev_err(nau8824->dev, "Cannot request irq %d (%d)\n",
+			nau8824->irq, ret);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(nau8824_enable_jack_detect);
+
+static void nau8824_reset_chip(struct regmap *regmap)
+{
+	regmap_write(regmap, NAU8824_REG_RESET, 0x00);
+	regmap_write(regmap, NAU8824_REG_RESET, 0x00);
+}
+
+static void nau8824_setup_buttons(struct nau8824 *nau8824)
+{
+	struct regmap *regmap = nau8824->regmap;
+
+	regmap_update_bits(regmap, NAU8824_REG_SAR_ADC,
+		NAU8824_SAR_TRACKING_GAIN_MASK,
+		nau8824->sar_voltage << NAU8824_SAR_TRACKING_GAIN_SFT);
+	regmap_update_bits(regmap, NAU8824_REG_SAR_ADC,
+		NAU8824_SAR_COMPARE_TIME_MASK,
+		nau8824->sar_compare_time << NAU8824_SAR_COMPARE_TIME_SFT);
+	regmap_update_bits(regmap, NAU8824_REG_SAR_ADC,
+		NAU8824_SAR_SAMPLING_TIME_MASK,
+		nau8824->sar_sampling_time << NAU8824_SAR_SAMPLING_TIME_SFT);
+
+	regmap_update_bits(regmap, NAU8824_REG_VDET_COEFFICIENT,
+		NAU8824_LEVELS_NR_MASK,
+		(nau8824->sar_threshold_num - 1) << NAU8824_LEVELS_NR_SFT);
+	regmap_update_bits(regmap, NAU8824_REG_VDET_COEFFICIENT,
+		NAU8824_HYSTERESIS_MASK,
+		nau8824->sar_hysteresis << NAU8824_HYSTERESIS_SFT);
+	regmap_update_bits(regmap, NAU8824_REG_VDET_COEFFICIENT,
+		NAU8824_SHORTKEY_DEBOUNCE_MASK,
+		nau8824->key_debounce << NAU8824_SHORTKEY_DEBOUNCE_SFT);
+
+	regmap_write(regmap, NAU8824_REG_VDET_THRESHOLD_1,
+		(nau8824->sar_threshold[0] << 8) | nau8824->sar_threshold[1]);
+	regmap_write(regmap, NAU8824_REG_VDET_THRESHOLD_2,
+		(nau8824->sar_threshold[2] << 8) | nau8824->sar_threshold[3]);
+	regmap_write(regmap, NAU8824_REG_VDET_THRESHOLD_3,
+		(nau8824->sar_threshold[4] << 8) | nau8824->sar_threshold[5]);
+	regmap_write(regmap, NAU8824_REG_VDET_THRESHOLD_4,
+		(nau8824->sar_threshold[6] << 8) | nau8824->sar_threshold[7]);
+}
+
+static void nau8824_init_regs(struct nau8824 *nau8824)
+{
+	struct regmap *regmap = nau8824->regmap;
+
+	/* Enable Bias/VMID/VMID Tieoff */
+	regmap_update_bits(regmap, NAU8824_REG_BIAS_ADJ,
+		NAU8824_VMID | NAU8824_VMID_SEL_MASK, NAU8824_VMID |
+		(nau8824->vref_impedance << NAU8824_VMID_SEL_SFT));
+	regmap_update_bits(regmap, NAU8824_REG_BOOST,
+		NAU8824_GLOBAL_BIAS_EN, NAU8824_GLOBAL_BIAS_EN);
+	mdelay(2);
+	regmap_update_bits(regmap, NAU8824_REG_MIC_BIAS,
+		NAU8824_MICBIAS_VOLTAGE_MASK, nau8824->micbias_voltage);
+	/* Disable Boost Driver, Automatic Short circuit protection enable */
+	regmap_update_bits(regmap, NAU8824_REG_BOOST,
+		NAU8824_PRECHARGE_DIS | NAU8824_HP_BOOST_DIS |
+		NAU8824_HP_BOOST_G_DIS | NAU8824_SHORT_SHUTDOWN_EN,
+		NAU8824_PRECHARGE_DIS | NAU8824_HP_BOOST_DIS |
+		NAU8824_HP_BOOST_G_DIS | NAU8824_SHORT_SHUTDOWN_EN);
+	/* Scaling for ADC and DAC clock */
+	regmap_update_bits(regmap, NAU8824_REG_CLK_DIVIDER,
+		NAU8824_CLK_ADC_SRC_MASK | NAU8824_CLK_DAC_SRC_MASK,
+		(0x1 << NAU8824_CLK_ADC_SRC_SFT) |
+		(0x1 << NAU8824_CLK_DAC_SRC_SFT));
+	regmap_update_bits(regmap, NAU8824_REG_DAC_MUTE_CTRL,
+		NAU8824_DAC_ZC_EN, NAU8824_DAC_ZC_EN);
+	regmap_update_bits(regmap, NAU8824_REG_ENA_CTRL,
+		NAU8824_DAC_CH1_EN | NAU8824_DAC_CH0_EN |
+		NAU8824_ADC_CH0_EN | NAU8824_ADC_CH1_EN |
+		NAU8824_ADC_CH2_EN | NAU8824_ADC_CH3_EN,
+		NAU8824_DAC_CH1_EN | NAU8824_DAC_CH0_EN |
+		NAU8824_ADC_CH0_EN | NAU8824_ADC_CH1_EN |
+		NAU8824_ADC_CH2_EN | NAU8824_ADC_CH3_EN);
+	regmap_update_bits(regmap, NAU8824_REG_CLK_GATING_ENA,
+		NAU8824_CLK_ADC_CH23_EN | NAU8824_CLK_ADC_CH01_EN |
+		NAU8824_CLK_DAC_CH1_EN | NAU8824_CLK_DAC_CH0_EN |
+		NAU8824_CLK_I2S_EN | NAU8824_CLK_GAIN_EN |
+		NAU8824_CLK_SAR_EN | NAU8824_CLK_DMIC_CH23_EN,
+		NAU8824_CLK_ADC_CH23_EN | NAU8824_CLK_ADC_CH01_EN |
+		NAU8824_CLK_DAC_CH1_EN | NAU8824_CLK_DAC_CH0_EN |
+		NAU8824_CLK_I2S_EN | NAU8824_CLK_GAIN_EN |
+		NAU8824_CLK_SAR_EN | NAU8824_CLK_DMIC_CH23_EN);
+	/* Class G timer 64ms */
+	regmap_update_bits(regmap, NAU8824_REG_CLASSG,
+		NAU8824_CLASSG_TIMER_MASK,
+		0x20 << NAU8824_CLASSG_TIMER_SFT);
+	regmap_update_bits(regmap, NAU8824_REG_TRIM_SETTINGS,
+		NAU8824_DRV_CURR_INC, NAU8824_DRV_CURR_INC);
+	/* Disable DACR/L power */
+	regmap_update_bits(regmap, NAU8824_REG_CHARGE_PUMP_CONTROL,
+		NAU8824_SPKR_PULL_DOWN | NAU8824_SPKL_PULL_DOWN |
+		NAU8824_POWER_DOWN_DACR | NAU8824_POWER_DOWN_DACL,
+		NAU8824_SPKR_PULL_DOWN | NAU8824_SPKL_PULL_DOWN |
+		NAU8824_POWER_DOWN_DACR | NAU8824_POWER_DOWN_DACL);
+	/* Enable TESTDAC. This sets the analog DAC inputs to a '0' input
+	 * signal to avoid any glitches due to power up transients in both
+	 * the analog and digital DAC circuit.
+	 */
+	regmap_update_bits(regmap, NAU8824_REG_ENABLE_LO,
+		NAU8824_TEST_DAC_EN, NAU8824_TEST_DAC_EN);
+	/* Config L/R channel */
+	regmap_update_bits(regmap, NAU8824_REG_DAC_CH0_DGAIN_CTRL,
+		NAU8824_DAC_CH0_SEL_MASK, NAU8824_DAC_CH0_SEL_I2S0);
+	regmap_update_bits(regmap, NAU8824_REG_DAC_CH1_DGAIN_CTRL,
+		NAU8824_DAC_CH1_SEL_MASK, NAU8824_DAC_CH1_SEL_I2S1);
+	regmap_update_bits(regmap, NAU8824_REG_ENABLE_LO,
+		NAU8824_DACR_HPR_EN | NAU8824_DACL_HPL_EN,
+		NAU8824_DACR_HPR_EN | NAU8824_DACL_HPL_EN);
+	/* Default oversampling/decimations settings are unusable
+	 * (audible hiss). Set it to something better.
+	 */
+	regmap_update_bits(regmap, NAU8824_REG_ADC_FILTER_CTRL,
+		NAU8824_ADC_SYNC_DOWN_MASK, NAU8824_ADC_SYNC_DOWN_64);
+	regmap_update_bits(regmap, NAU8824_REG_DAC_FILTER_CTRL_1,
+		NAU8824_DAC_CICCLP_OFF | NAU8824_DAC_OVERSAMPLE_MASK,
+		NAU8824_DAC_CICCLP_OFF | NAU8824_DAC_OVERSAMPLE_64);
+	/* DAC clock delay 2ns, VREF */
+	regmap_update_bits(regmap, NAU8824_REG_RDAC,
+		NAU8824_RDAC_CLK_DELAY_MASK | NAU8824_RDAC_VREF_MASK,
+		(0x2 << NAU8824_RDAC_CLK_DELAY_SFT) |
+		(0x3 << NAU8824_RDAC_VREF_SFT));
+	/* PGA input mode selection */
+	regmap_update_bits(regmap, NAU8824_REG_FEPGA,
+		NAU8824_FEPGA_MODEL_SHORT_EN | NAU8824_FEPGA_MODER_SHORT_EN,
+		NAU8824_FEPGA_MODEL_SHORT_EN | NAU8824_FEPGA_MODER_SHORT_EN);
+	/* Digital microphone control */
+	regmap_update_bits(regmap, NAU8824_REG_ANALOG_CONTROL_1,
+		NAU8824_DMIC_CLK_DRV_STRG | NAU8824_DMIC_CLK_SLEW_FAST,
+		NAU8824_DMIC_CLK_DRV_STRG | NAU8824_DMIC_CLK_SLEW_FAST);
+	regmap_update_bits(regmap, NAU8824_REG_JACK_DET_CTRL,
+		NAU8824_JACK_LOGIC,
+		/* jkdet_polarity - 1  is for active-low */
+		nau8824->jkdet_polarity ? 0 : NAU8824_JACK_LOGIC);
+	regmap_update_bits(regmap,
+		NAU8824_REG_JACK_DET_CTRL, NAU8824_JACK_EJECT_DT_MASK,
+		(nau8824->jack_eject_debounce << NAU8824_JACK_EJECT_DT_SFT));
+	if (nau8824->sar_threshold_num)
+		nau8824_setup_buttons(nau8824);
+}
+
+static int nau8824_setup_irq(struct nau8824 *nau8824)
+{
+	/* Disable interruption before codec initiation done */
+	regmap_update_bits(nau8824->regmap, NAU8824_REG_ENA_CTRL,
+		NAU8824_JD_SLEEP_MODE, NAU8824_JD_SLEEP_MODE);
+	regmap_update_bits(nau8824->regmap,
+		NAU8824_REG_INTERRUPT_SETTING, 0x3ff, 0x3ff);
+	regmap_update_bits(nau8824->regmap, NAU8824_REG_INTERRUPT_SETTING_1,
+		NAU8824_IRQ_EJECT_EN | NAU8824_IRQ_INSERT_EN, 0);
+
+	return 0;
+}
+
+static void nau8824_print_device_properties(struct nau8824 *nau8824)
+{
+	struct device *dev = nau8824->dev;
+	int i;
+
+	dev_dbg(dev, "jkdet-polarity:       %d\n", nau8824->jkdet_polarity);
+	dev_dbg(dev, "micbias-voltage:      %d\n", nau8824->micbias_voltage);
+	dev_dbg(dev, "vref-impedance:       %d\n", nau8824->vref_impedance);
+
+	dev_dbg(dev, "sar-threshold-num:    %d\n", nau8824->sar_threshold_num);
+	for (i = 0; i < nau8824->sar_threshold_num; i++)
+		dev_dbg(dev, "sar-threshold[%d]=%x\n", i,
+				nau8824->sar_threshold[i]);
+
+	dev_dbg(dev, "sar-hysteresis:       %d\n", nau8824->sar_hysteresis);
+	dev_dbg(dev, "sar-voltage:          %d\n", nau8824->sar_voltage);
+	dev_dbg(dev, "sar-compare-time:     %d\n", nau8824->sar_compare_time);
+	dev_dbg(dev, "sar-sampling-time:    %d\n", nau8824->sar_sampling_time);
+	dev_dbg(dev, "short-key-debounce:   %d\n", nau8824->key_debounce);
+	dev_dbg(dev, "jack-eject-debounce:  %d\n",
+			nau8824->jack_eject_debounce);
+}
+
+static int nau8824_read_device_properties(struct device *dev,
+	struct nau8824 *nau8824) {
+	int ret;
+
+	ret = device_property_read_u32(dev, "nuvoton,jkdet-polarity",
+		&nau8824->jkdet_polarity);
+	if (ret)
+		nau8824->jkdet_polarity = 1;
+	ret = device_property_read_u32(dev, "nuvoton,micbias-voltage",
+		&nau8824->micbias_voltage);
+	if (ret)
+		nau8824->micbias_voltage = 6;
+	ret = device_property_read_u32(dev, "nuvoton,vref-impedance",
+		&nau8824->vref_impedance);
+	if (ret)
+		nau8824->vref_impedance = 2;
+	ret = device_property_read_u32(dev, "nuvoton,sar-threshold-num",
+		&nau8824->sar_threshold_num);
+	if (ret)
+		nau8824->sar_threshold_num = 4;
+	ret = device_property_read_u32_array(dev, "nuvoton,sar-threshold",
+		nau8824->sar_threshold, nau8824->sar_threshold_num);
+	if (ret) {
+		nau8824->sar_threshold[0] = 0x0a;
+		nau8824->sar_threshold[1] = 0x14;
+		nau8824->sar_threshold[2] = 0x26;
+		nau8824->sar_threshold[3] = 0x73;
+	}
+	ret = device_property_read_u32(dev, "nuvoton,sar-hysteresis",
+		&nau8824->sar_hysteresis);
+	if (ret)
+		nau8824->sar_hysteresis = 0;
+	ret = device_property_read_u32(dev, "nuvoton,sar-voltage",
+		&nau8824->sar_voltage);
+	if (ret)
+		nau8824->sar_voltage = 6;
+	ret = device_property_read_u32(dev, "nuvoton,sar-compare-time",
+		&nau8824->sar_compare_time);
+	if (ret)
+		nau8824->sar_compare_time = 1;
+	ret = device_property_read_u32(dev, "nuvoton,sar-sampling-time",
+		&nau8824->sar_sampling_time);
+	if (ret)
+		nau8824->sar_sampling_time = 1;
+	ret = device_property_read_u32(dev, "nuvoton,short-key-debounce",
+		&nau8824->key_debounce);
+	if (ret)
+		nau8824->key_debounce = 0;
+	ret = device_property_read_u32(dev, "nuvoton,jack-eject-debounce",
+		&nau8824->jack_eject_debounce);
+	if (ret)
+		nau8824->jack_eject_debounce = 1;
+
+	return 0;
+}
+
+static int nau8824_i2c_probe(struct i2c_client *i2c,
+	const struct i2c_device_id *id)
+{
+	struct device *dev = &i2c->dev;
+	struct nau8824 *nau8824 = dev_get_platdata(dev);
+	int ret, value;
+
+	if (!nau8824) {
+		nau8824 = devm_kzalloc(dev, sizeof(*nau8824), GFP_KERNEL);
+		if (!nau8824)
+			return -ENOMEM;
+		ret = nau8824_read_device_properties(dev, nau8824);
+		if (ret)
+			return ret;
+	}
+	i2c_set_clientdata(i2c, nau8824);
+
+	nau8824->regmap = devm_regmap_init_i2c(i2c, &nau8824_regmap_config);
+	if (IS_ERR(nau8824->regmap))
+		return PTR_ERR(nau8824->regmap);
+	nau8824->dev = dev;
+	nau8824->irq = i2c->irq;
+	sema_init(&nau8824->jd_sem, 1);
+
+	nau8824_print_device_properties(nau8824);
+
+	ret = regmap_read(nau8824->regmap, NAU8824_REG_I2C_DEVICE_ID, &value);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read device id from the NAU8824: %d\n",
+			ret);
+		return ret;
+	}
+	nau8824_reset_chip(nau8824->regmap);
+	nau8824_init_regs(nau8824);
+
+	if (i2c->irq)
+		nau8824_setup_irq(nau8824);
+
+	return devm_snd_soc_register_component(dev,
+		&nau8824_component_driver, &nau8824_dai, 1);
+}
+
+static const struct i2c_device_id nau8824_i2c_ids[] = {
+	{ "nau8824", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, nau8824_i2c_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id nau8824_of_ids[] = {
+	{ .compatible = "nuvoton,nau8824", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, nau8824_of_ids);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id nau8824_acpi_match[] = {
+	{ "10508824", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, nau8824_acpi_match);
+#endif
+
+static struct i2c_driver nau8824_i2c_driver = {
+	.driver = {
+		.name = "nau8824",
+		.of_match_table = of_match_ptr(nau8824_of_ids),
+		.acpi_match_table = ACPI_PTR(nau8824_acpi_match),
+	},
+	.probe = nau8824_i2c_probe,
+	.id_table = nau8824_i2c_ids,
+};
+module_i2c_driver(nau8824_i2c_driver);
+
+
+MODULE_DESCRIPTION("ASoC NAU88L24 driver");
+MODULE_AUTHOR("John Hsu <KCHSU0@nuvoton.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/nau8824.h b/sound/soc/codecs/nau8824.h
new file mode 100644
index 0000000..6184a2b
--- /dev/null
+++ b/sound/soc/codecs/nau8824.h
@@ -0,0 +1,478 @@
+/*
+ * NAU88L24 ALSA SoC audio driver
+ *
+ * Copyright 2016 Nuvoton Technology Corp.
+ * Author: John Hsu <KCHSU0@nuvoton.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __NAU8824_H__
+#define __NAU8824_H__
+
+#define NAU8824_REG_RESET			0x00
+#define NAU8824_REG_ENA_CTRL			0x01
+#define NAU8824_REG_CLK_GATING_ENA		0x02
+#define NAU8824_REG_CLK_DIVIDER		0x03
+#define NAU8824_REG_FLL1			0x04
+#define NAU8824_REG_FLL2			0x05
+#define NAU8824_REG_FLL3			0x06
+#define NAU8824_REG_FLL4			0x07
+#define NAU8824_REG_FLL5			0x08
+#define NAU8824_REG_FLL6			0x09
+#define NAU8824_REG_FLL_VCO_RSV		0x0A
+#define NAU8824_REG_JACK_DET_CTRL		0x0D
+#define NAU8824_REG_INTERRUPT_SETTING_1	0x0F
+#define NAU8824_REG_IRQ			0x10
+#define NAU8824_REG_CLEAR_INT_REG		0x11
+#define NAU8824_REG_INTERRUPT_SETTING	0x12
+#define NAU8824_REG_SAR_ADC			0x13
+#define NAU8824_REG_VDET_COEFFICIENT		0x14
+#define NAU8824_REG_VDET_THRESHOLD_1	0x15
+#define NAU8824_REG_VDET_THRESHOLD_2	0x16
+#define NAU8824_REG_VDET_THRESHOLD_3	0x17
+#define NAU8824_REG_VDET_THRESHOLD_4	0x18
+#define NAU8824_REG_GPIO_SEL			0x1A
+#define NAU8824_REG_PORT0_I2S_PCM_CTRL_1	0x1C
+#define NAU8824_REG_PORT0_I2S_PCM_CTRL_2	0x1D
+#define NAU8824_REG_PORT0_LEFT_TIME_SLOT	0x1E
+#define NAU8824_REG_PORT0_RIGHT_TIME_SLOT	0x1F
+#define NAU8824_REG_TDM_CTRL			0x20
+#define NAU8824_REG_ADC_HPF_FILTER		0x23
+#define NAU8824_REG_ADC_FILTER_CTRL		0x24
+#define NAU8824_REG_DAC_FILTER_CTRL_1	0x25
+#define NAU8824_REG_DAC_FILTER_CTRL_2	0x26
+#define NAU8824_REG_NOTCH_FILTER_1		0x27
+#define NAU8824_REG_NOTCH_FILTER_2		0x28
+#define NAU8824_REG_EQ1_LOW			0x29
+#define NAU8824_REG_EQ2_EQ3			0x2A
+#define NAU8824_REG_EQ4_EQ5			0x2B
+#define NAU8824_REG_ADC_CH0_DGAIN_CTRL	0x2D
+#define NAU8824_REG_ADC_CH1_DGAIN_CTRL	0x2E
+#define NAU8824_REG_ADC_CH2_DGAIN_CTRL	0x2F
+#define NAU8824_REG_ADC_CH3_DGAIN_CTRL	0x30
+#define NAU8824_REG_DAC_MUTE_CTRL		0x31
+#define NAU8824_REG_DAC_CH0_DGAIN_CTRL	0x32
+#define NAU8824_REG_DAC_CH1_DGAIN_CTRL	0x33
+#define NAU8824_REG_ADC_TO_DAC_ST		0x34
+#define NAU8824_REG_DRC_KNEE_IP12_ADC_CH01	0x38
+#define NAU8824_REG_DRC_KNEE_IP34_ADC_CH01	0x39
+#define NAU8824_REG_DRC_SLOPE_ADC_CH01	0x3A
+#define NAU8824_REG_DRC_ATKDCY_ADC_CH01	0x3B
+#define NAU8824_REG_DRC_KNEE_IP12_ADC_CH23	0x3C
+#define NAU8824_REG_DRC_KNEE_IP34_ADC_CH23	0x3D
+#define NAU8824_REG_DRC_SLOPE_ADC_CH23	0x3E
+#define NAU8824_REG_DRC_ATKDCY_ADC_CH23	0x3F
+#define NAU8824_REG_DRC_GAINL_ADC0		0x40
+#define NAU8824_REG_DRC_GAINL_ADC1		0x41
+#define NAU8824_REG_DRC_GAINL_ADC2		0x42
+#define NAU8824_REG_DRC_GAINL_ADC3		0x43
+#define NAU8824_REG_DRC_KNEE_IP12_DAC	0x45
+#define NAU8824_REG_DRC_KNEE_IP34_DAC	0x46
+#define NAU8824_REG_DRC_SLOPE_DAC		0x47
+#define NAU8824_REG_DRC_ATKDCY_DAC		0x48
+#define NAU8824_REG_DRC_GAIN_DAC_CH0	0x49
+#define NAU8824_REG_DRC_GAIN_DAC_CH1	0x4A
+#define NAU8824_REG_MODE			0x4C
+#define NAU8824_REG_MODE1			0x4D
+#define NAU8824_REG_MODE2			0x4E
+#define NAU8824_REG_CLASSG			0x50
+#define NAU8824_REG_OTP_EFUSE			0x51
+#define NAU8824_REG_OTPDOUT_1		0x53
+#define NAU8824_REG_OTPDOUT_2		0x54
+#define NAU8824_REG_MISC_CTRL			0x55
+#define NAU8824_REG_I2C_TIMEOUT		0x56
+#define NAU8824_REG_TEST_MODE		0x57
+#define NAU8824_REG_I2C_DEVICE_ID		0x58
+#define NAU8824_REG_SAR_ADC_DATA_OUT	0x59
+#define NAU8824_REG_BIAS_ADJ			0x66
+#define NAU8824_REG_PGA_GAIN			0x67
+#define NAU8824_REG_TRIM_SETTINGS		0x68
+#define NAU8824_REG_ANALOG_CONTROL_1	0x69
+#define NAU8824_REG_ANALOG_CONTROL_2	0x6A
+#define NAU8824_REG_ENABLE_LO			0x6B
+#define NAU8824_REG_GAIN_LO			0x6C
+#define NAU8824_REG_CLASSD_GAIN_1		0x6D
+#define NAU8824_REG_CLASSD_GAIN_2		0x6E
+#define NAU8824_REG_ANALOG_ADC_1		0x71
+#define NAU8824_REG_ANALOG_ADC_2		0x72
+#define NAU8824_REG_RDAC			0x73
+#define NAU8824_REG_MIC_BIAS			0x74
+#define NAU8824_REG_HS_VOLUME_CONTROL	0x75
+#define NAU8824_REG_BOOST			0x76
+#define NAU8824_REG_FEPGA			0x77
+#define NAU8824_REG_FEPGA_II			0x78
+#define NAU8824_REG_FEPGA_SE			0x79
+#define NAU8824_REG_FEPGA_ATTENUATION	0x7A
+#define NAU8824_REG_ATT_PORT0		0x7B
+#define NAU8824_REG_ATT_PORT1		0x7C
+#define NAU8824_REG_POWER_UP_CONTROL	0x7F
+#define NAU8824_REG_CHARGE_PUMP_CONTROL	0x80
+#define NAU8824_REG_CHARGE_PUMP_INPUT	0x81
+#define NAU8824_REG_MAX			NAU8824_REG_CHARGE_PUMP_INPUT
+/* 16-bit control register address, and 16-bits control register data */
+#define NAU8824_REG_ADDR_LEN		16
+#define NAU8824_REG_DATA_LEN		16
+
+
+/* ENA_CTRL (0x1) */
+#define NAU8824_DMIC_LCH_EDGE_CH23	(0x1 << 12)
+#define NAU8824_DMIC_LCH_EDGE_CH01	(0x1 << 11)
+#define NAU8824_JD_SLEEP_MODE		(0x1 << 10)
+#define NAU8824_ADC_CH3_DMIC_SFT	9
+#define NAU8824_ADC_CH3_DMIC_EN	(0x1 << NAU8824_ADC_CH3_DMIC_SFT)
+#define NAU8824_ADC_CH2_DMIC_SFT	8
+#define NAU8824_ADC_CH2_DMIC_EN	(0x1 << NAU8824_ADC_CH2_DMIC_SFT)
+#define NAU8824_ADC_CH1_DMIC_SFT	7
+#define NAU8824_ADC_CH1_DMIC_EN	(0x1 << NAU8824_ADC_CH1_DMIC_SFT)
+#define NAU8824_ADC_CH0_DMIC_SFT	6
+#define NAU8824_ADC_CH0_DMIC_EN	(0x1 << NAU8824_ADC_CH0_DMIC_SFT)
+#define NAU8824_DAC_CH1_EN		(0x1 << 5)
+#define NAU8824_DAC_CH0_EN		(0x1 << 4)
+#define NAU8824_ADC_CH3_EN		(0x1 << 3)
+#define NAU8824_ADC_CH2_EN		(0x1 << 2)
+#define NAU8824_ADC_CH1_EN		(0x1 << 1)
+#define NAU8824_ADC_CH0_EN		0x1
+
+/* CLK_GATING_ENA (0x02) */
+#define NAU8824_CLK_ADC_CH23_EN	(0x1 << 15)
+#define NAU8824_CLK_ADC_CH01_EN	(0x1 << 14)
+#define NAU8824_CLK_DAC_CH1_EN	(0x1 << 13)
+#define NAU8824_CLK_DAC_CH0_EN	(0x1 << 12)
+#define NAU8824_CLK_I2S_EN		(0x1 << 7)
+#define NAU8824_CLK_GAIN_EN		(0x1 << 5)
+#define NAU8824_CLK_SAR_EN		(0x1 << 3)
+#define NAU8824_CLK_DMIC_CH23_EN	(0x1 << 1)
+
+/* CLK_DIVIDER (0x3) */
+#define NAU8824_CLK_SRC_SFT		15
+#define NAU8824_CLK_SRC_MASK		(1 << NAU8824_CLK_SRC_SFT)
+#define NAU8824_CLK_SRC_VCO		(1 << NAU8824_CLK_SRC_SFT)
+#define NAU8824_CLK_SRC_MCLK		(0 << NAU8824_CLK_SRC_SFT)
+#define NAU8824_CLK_MCLK_SRC_MASK	(0xf << 0)
+#define NAU8824_CLK_DMIC_SRC_SFT	10
+#define NAU8824_CLK_DMIC_SRC_MASK	(0x7 << NAU8824_CLK_DMIC_SRC_SFT)
+#define NAU8824_CLK_ADC_SRC_SFT	6
+#define NAU8824_CLK_ADC_SRC_MASK	(0x3 << NAU8824_CLK_ADC_SRC_SFT)
+#define NAU8824_CLK_DAC_SRC_SFT	4
+#define NAU8824_CLK_DAC_SRC_MASK	(0x3 << NAU8824_CLK_DAC_SRC_SFT)
+
+/* FLL1 (0x04) */
+#define NAU8824_FLL_RATIO_MASK	(0x7f << 0)
+
+/* FLL3 (0x06) */
+#define NAU8824_FLL_INTEGER_MASK	(0x3ff << 0)
+#define NAU8824_FLL_CLK_SRC_SFT	10
+#define NAU8824_FLL_CLK_SRC_MASK	(0x3 << NAU8824_FLL_CLK_SRC_SFT)
+#define NAU8824_FLL_CLK_SRC_MCLK	(0 << NAU8824_FLL_CLK_SRC_SFT)
+#define NAU8824_FLL_CLK_SRC_BLK	(0x2 << NAU8824_FLL_CLK_SRC_SFT)
+#define NAU8824_FLL_CLK_SRC_FS		(0x3 << NAU8824_FLL_CLK_SRC_SFT)
+
+/* FLL4 (0x07) */
+#define NAU8824_FLL_REF_DIV_SFT	10
+#define NAU8824_FLL_REF_DIV_MASK	(0x3 << NAU8824_FLL_REF_DIV_SFT)
+
+/* FLL5 (0x08) */
+#define NAU8824_FLL_PDB_DAC_EN	(0x1 << 15)
+#define NAU8824_FLL_LOOP_FTR_EN	(0x1 << 14)
+#define NAU8824_FLL_CLK_SW_MASK	(0x1 << 13)
+#define NAU8824_FLL_CLK_SW_N2		(0x1 << 13)
+#define NAU8824_FLL_CLK_SW_REF	(0x0 << 13)
+#define NAU8824_FLL_FTR_SW_MASK	(0x1 << 12)
+#define NAU8824_FLL_FTR_SW_ACCU	(0x1 << 12)
+#define NAU8824_FLL_FTR_SW_FILTER	(0x0 << 12)
+
+/* FLL6 (0x9) */
+#define NAU8824_DCO_EN			(0x1 << 15)
+#define NAU8824_SDM_EN			(0x1 << 14)
+
+/* IRQ (0x10) */
+#define NAU8824_SHORT_CIRCUIT_IRQ		(0x1 << 7)
+#define NAU8824_IMPEDANCE_MEAS_IRQ		(0x1 << 6)
+#define NAU8824_KEY_RELEASE_IRQ		(0x1 << 5)
+#define NAU8824_KEY_LONG_PRESS_IRQ		(0x1 << 4)
+#define NAU8824_KEY_SHORT_PRESS_IRQ		(0x1 << 3)
+#define NAU8824_JACK_EJECTION_DETECTED	(0x1 << 1)
+#define NAU8824_JACK_INSERTION_DETECTED	0x1
+
+/* JACK_DET_CTRL (0x0D) */
+#define NAU8824_JACK_EJECT_DT_SFT	2
+#define NAU8824_JACK_EJECT_DT_MASK (0x3 << NAU8824_JACK_EJECT_DT_SFT)
+#define NAU8824_JACK_LOGIC		0x1
+
+
+/* INTERRUPT_SETTING_1 (0x0F) */
+#define NAU8824_IRQ_EJECT_EN		(0x1 << 9)
+#define NAU8824_IRQ_INSERT_EN		(0x1 << 8)
+
+/* INTERRUPT_SETTING (0x12) */
+#define NAU8824_IRQ_KEY_RELEASE_DIS		(0x1 << 5)
+#define NAU8824_IRQ_KEY_SHORT_PRESS_DIS	(0x1 << 3)
+#define NAU8824_IRQ_EJECT_DIS			(0x1 << 1)
+#define NAU8824_IRQ_INSERT_DIS		0x1
+
+/* SAR_ADC (0x13) */
+#define NAU8824_SAR_ADC_EN_SFT		12
+#define NAU8824_SAR_TRACKING_GAIN_SFT	8
+#define NAU8824_SAR_TRACKING_GAIN_MASK	(0x7 << NAU8824_SAR_TRACKING_GAIN_SFT)
+#define NAU8824_SAR_COMPARE_TIME_SFT	2
+#define NAU8824_SAR_COMPARE_TIME_MASK	(3 << 2)
+#define NAU8824_SAR_SAMPLING_TIME_SFT	0
+#define NAU8824_SAR_SAMPLING_TIME_MASK	(3 << 0)
+
+/* VDET_COEFFICIENT (0x14) */
+#define NAU8824_SHORTKEY_DEBOUNCE_SFT	12
+#define NAU8824_SHORTKEY_DEBOUNCE_MASK	(0x3 << NAU8824_SHORTKEY_DEBOUNCE_SFT)
+#define NAU8824_LEVELS_NR_SFT			8
+#define NAU8824_LEVELS_NR_MASK		(0x7 << 8)
+#define NAU8824_HYSTERESIS_SFT		0
+#define NAU8824_HYSTERESIS_MASK		0xf
+
+/* PORT0_I2S_PCM_CTRL_1 (0x1C) */
+#define NAU8824_I2S_BP_SFT		7
+#define NAU8824_I2S_BP_MASK		(1 << NAU8824_I2S_BP_SFT)
+#define NAU8824_I2S_BP_INV		(1 << NAU8824_I2S_BP_SFT)
+#define NAU8824_I2S_PCMB_SFT		6
+#define NAU8824_I2S_PCMB_EN		(1 << NAU8824_I2S_PCMB_SFT)
+#define NAU8824_I2S_DL_SFT		2
+#define NAU8824_I2S_DL_MASK		(0x3 << NAU8824_I2S_DL_SFT)
+#define NAU8824_I2S_DL_16		(0 << NAU8824_I2S_DL_SFT)
+#define NAU8824_I2S_DL_20		(1 << NAU8824_I2S_DL_SFT)
+#define NAU8824_I2S_DL_24		(2 << NAU8824_I2S_DL_SFT)
+#define NAU8824_I2S_DL_32		(3 << NAU8824_I2S_DL_SFT)
+#define NAU8824_I2S_DF_MASK		0x3
+#define NAU8824_I2S_DF_RIGTH		0
+#define NAU8824_I2S_DF_LEFT		1
+#define NAU8824_I2S_DF_I2S		2
+#define NAU8824_I2S_DF_PCM_AB		3
+
+
+/* PORT0_I2S_PCM_CTRL_2 (0x1D) */
+#define NAU8824_I2S_LRC_DIV_SFT	12
+#define NAU8824_I2S_LRC_DIV_MASK	(0x3 << NAU8824_I2S_LRC_DIV_SFT)
+#define NAU8824_I2S_MS_SFT		3
+#define NAU8824_I2S_MS_MASK		(1 << NAU8824_I2S_MS_SFT)
+#define NAU8824_I2S_MS_MASTER		(1 << NAU8824_I2S_MS_SFT)
+#define NAU8824_I2S_MS_SLAVE		(0 << NAU8824_I2S_MS_SFT)
+#define NAU8824_I2S_BLK_DIV_MASK	0x7
+
+/* PORT0_LEFT_TIME_SLOT (0x1E) */
+#define NAU8824_TSLOT_L_MASK	0x3ff
+
+/* TDM_CTRL (0x20) */
+#define NAU8824_TDM_MODE		(0x1 << 15)
+#define NAU8824_TDM_OFFSET_EN		(0x1 << 14)
+#define NAU8824_TDM_DACL_RX_SFT	6
+#define NAU8824_TDM_DACL_RX_MASK	(0x3 << NAU8824_TDM_DACL_RX_SFT)
+#define NAU8824_TDM_DACR_RX_SFT	4
+#define NAU8824_TDM_DACR_RX_MASK	(0x3 << NAU8824_TDM_DACR_RX_SFT)
+#define NAU8824_TDM_TX_MASK		0xf
+
+/* ADC_FILTER_CTRL (0x24) */
+#define NAU8824_ADC_SYNC_DOWN_MASK	0x3
+#define NAU8824_ADC_SYNC_DOWN_32	0
+#define NAU8824_ADC_SYNC_DOWN_64	1
+#define NAU8824_ADC_SYNC_DOWN_128	2
+#define NAU8824_ADC_SYNC_DOWN_256	3
+
+/* DAC_FILTER_CTRL_1 (0x25) */
+#define NAU8824_DAC_CICCLP_OFF	(0x1 << 7)
+#define NAU8824_DAC_OVERSAMPLE_MASK	0x7
+#define NAU8824_DAC_OVERSAMPLE_64	0
+#define NAU8824_DAC_OVERSAMPLE_256	1
+#define NAU8824_DAC_OVERSAMPLE_128	2
+#define NAU8824_DAC_OVERSAMPLE_32	4
+
+/* DAC_MUTE_CTRL (0x31) */
+#define NAU8824_DAC_CH01_MIX		0x3
+#define NAU8824_DAC_ZC_EN		(0x1 << 11)
+
+/* DAC_CH0_DGAIN_CTRL (0x32) */
+#define NAU8824_DAC_CH0_SEL_SFT	9
+#define NAU8824_DAC_CH0_SEL_MASK	(0x1 << NAU8824_DAC_CH0_SEL_SFT)
+#define NAU8824_DAC_CH0_SEL_I2S0	(0x0 << NAU8824_DAC_CH0_SEL_SFT)
+#define NAU8824_DAC_CH0_SEL_I2S1	(0x1 << NAU8824_DAC_CH0_SEL_SFT)
+#define NAU8824_DAC_CH0_VOL_MASK	0x1ff
+
+/* DAC_CH1_DGAIN_CTRL (0x33) */
+#define NAU8824_DAC_CH1_SEL_SFT	9
+#define NAU8824_DAC_CH1_SEL_MASK	(0x1 << NAU8824_DAC_CH1_SEL_SFT)
+#define NAU8824_DAC_CH1_SEL_I2S0	(0x0 << NAU8824_DAC_CH1_SEL_SFT)
+#define NAU8824_DAC_CH1_SEL_I2S1	(0x1 << NAU8824_DAC_CH1_SEL_SFT)
+#define NAU8824_DAC_CH1_VOL_MASK	0x1ff
+
+/* CLASSG (0x50) */
+#define NAU8824_CLASSG_TIMER_SFT	8
+#define NAU8824_CLASSG_TIMER_MASK	(0x3f << NAU8824_CLASSG_TIMER_SFT)
+#define NAU8824_CLASSG_LDAC_EN_SFT	2
+#define NAU8824_CLASSG_RDAC_EN_SFT	1
+#define NAU8824_CLASSG_EN_SFT		0
+
+/* SAR_ADC_DATA_OUT (0x59) */
+#define NAU8824_SAR_ADC_DATA_MASK	0xff
+
+/* BIAS_ADJ (0x66) */
+#define NAU8824_VMID			(1 << 6)
+#define NAU8824_VMID_SEL_SFT		4
+#define NAU8824_VMID_SEL_MASK		(3 << NAU8824_VMID_SEL_SFT)
+#define NAU8824_DMIC2_EN_SFT		3
+#define NAU8824_DMIC1_EN_SFT		2
+
+/* TRIM_SETTINGS (0x68) */
+#define NAU8824_DRV_CURR_INC		(1 << 15)
+
+/* ANALOG_CONTROL_1 (0x69) */
+#define NAU8824_DMIC_CLK_DRV_STRG	(1 << 3)
+#define NAU8824_DMIC_CLK_SLEW_FAST	(0x7)
+
+/* ANALOG_CONTROL_2 (0x6A) */
+#define NAU8824_CLASSD_CLAMP_DIS_SFT	3
+#define NAU8824_CLASSD_CLAMP_DIS	(0x1 << NAU8824_CLASSD_CLAMP_DIS_SFT)
+
+/* ENABLE_LO (0x6B) */
+#define NAU8824_TEST_DAC_SFT		14
+#define NAU8824_TEST_DAC_EN		(0x3 << NAU8824_TEST_DAC_SFT)
+#define NAU8824_DACL_HPR_EN_SFT	3
+#define NAU8824_DACL_HPR_EN		(0x1 << NAU8824_DACL_HPR_EN_SFT)
+#define NAU8824_DACR_HPR_EN_SFT	2
+#define NAU8824_DACR_HPR_EN		(0x1 << NAU8824_DACR_HPR_EN_SFT)
+#define NAU8824_DACR_HPL_EN_SFT	1
+#define NAU8824_DACR_HPL_EN		(0x1 << NAU8824_DACR_HPL_EN_SFT)
+#define NAU8824_DACL_HPL_EN_SFT	0
+#define NAU8824_DACL_HPL_EN		0x1
+
+/* CLASSD_GAIN_1 (0x6D) */
+#define NAU8824_CLASSD_GAIN_1R_SFT	8
+#define NAU8824_CLASSD_GAIN_1R_MASK	(0x1f << NAU8824_CLASSD_GAIN_1R_SFT)
+#define NAU8824_CLASSD_EN_SFT		7
+#define NAU8824_CLASSD_EN		(0x1 << NAU8824_CLASSD_EN_SFT)
+#define NAU8824_CLASSD_GAIN_1L_MASK	0x1f
+
+/* CLASSD_GAIN_2 (0x6E) */
+#define NAU8824_CLASSD_GAIN_2R_SFT	8
+#define NAU8824_CLASSD_GAIN_2R_MASK	(0x1f << NAU8824_CLASSD_GAIN_1R_SFT)
+#define NAU8824_CLASSD_EN_SFT		7
+#define NAU8824_CLASSD_EN		(0x1 << NAU8824_CLASSD_EN_SFT)
+#define NAU8824_CLASSD_GAIN_2L_MASK	0x1f
+
+/* ANALOG_ADC_2 (0x72) */
+#define NAU8824_ADCR_EN_SFT		7
+#define NAU8824_ADCL_EN_SFT		6
+
+/* RDAC (0x73) */
+#define NAU8824_DACR_EN_SFT		13
+#define NAU8824_DACL_EN_SFT		12
+#define NAU8824_DACR_CLK_SFT		9
+#define NAU8824_DACL_CLK_SFT		8
+#define NAU8824_RDAC_CLK_DELAY_SFT	4
+#define NAU8824_RDAC_CLK_DELAY_MASK	(0x7 << NAU8824_RDAC_CLK_DELAY_SFT)
+#define NAU8824_RDAC_VREF_SFT		2
+#define NAU8824_RDAC_VREF_MASK	(0x3 << NAU8824_RDAC_VREF_SFT)
+
+/* MIC_BIAS (0x74) */
+#define NAU8824_MICBIAS_JKSLV		(1 << 14)
+#define NAU8824_MICBIAS_JKR2		(1 << 12)
+#define NAU8824_MICBIAS_POWERUP_SFT	8
+#define NAU8824_MICBIAS_VOLTAGE_SFT	0
+#define NAU8824_MICBIAS_VOLTAGE_MASK	0x7
+
+/* BOOST (0x76) */
+#define NAU8824_PRECHARGE_DIS			(0x1 << 13)
+#define NAU8824_GLOBAL_BIAS_EN		(0x1 << 12)
+#define NAU8824_HP_BOOST_DIS_SFT		9
+#define NAU8824_HP_BOOST_DIS		(0x1 << NAU8824_HP_BOOST_DIS_SFT)
+#define NAU8824_HP_BOOST_G_DIS_SFT		8
+#define NAU8824_HP_BOOST_G_DIS		(0x1 << NAU8824_HP_BOOST_G_DIS_SFT)
+#define NAU8824_SHORT_SHUTDOWN_DIG_EN	(1 << 7)
+#define NAU8824_SHORT_SHUTDOWN_EN		(1 << 6)
+
+/* FEPGA (0x77) */
+#define NAU8824_FEPGA_MODER_SHORT_SFT	7
+#define NAU8824_FEPGA_MODER_SHORT_EN	(0x1 << NAU8824_FEPGA_MODER_SHORT_SFT)
+#define NAU8824_FEPGA_MODER_MIC2_SFT		5
+#define NAU8824_FEPGA_MODER_MIC2_EN	(0x1 << NAU8824_FEPGA_MODER_MIC2_SFT)
+#define NAU8824_FEPGA_MODER_HSMIC_SFT	4
+#define NAU8824_FEPGA_MODER_HSMIC_EN	(0x1 << NAU8824_FEPGA_MODER_HSMIC_SFT)
+#define NAU8824_FEPGA_MODEL_SHORT_SFT	3
+#define NAU8824_FEPGA_MODEL_SHORT_EN	(0x1 << NAU8824_FEPGA_MODEL_SHORT_SFT)
+#define NAU8824_FEPGA_MODEL_MIC1_SFT		1
+#define NAU8824_FEPGA_MODEL_MIC1_EN	(0x1 << NAU8824_FEPGA_MODEL_MIC1_SFT)
+#define NAU8824_FEPGA_MODEL_HSMIC_SFT	0
+#define NAU8824_FEPGA_MODEL_HSMIC_EN	(0x1 << NAU8824_FEPGA_MODEL_HSMIC_SFT)
+
+/* FEPGA_II (0x78) */
+#define NAU8824_FEPGA_GAINR_SFT	5
+#define NAU8824_FEPGA_GAINR_MASK	(0x1f << NAU8824_FEPGA_GAINR_SFT)
+#define NAU8824_FEPGA_GAINL_SFT	0
+#define NAU8824_FEPGA_GAINL_MASK	0x1f
+
+/* CHARGE_PUMP_CONTROL (0x80) */
+#define NAU8824_JAMNODCLOW		(0x1 << 15)
+#define NAU8824_SPKR_PULL_DOWN	(0x1 << 13)
+#define NAU8824_SPKL_PULL_DOWN	(0x1 << 12)
+#define NAU8824_POWER_DOWN_DACR	(0x1 << 9)
+#define NAU8824_POWER_DOWN_DACL	(0x1 << 8)
+#define NAU8824_CHARGE_PUMP_EN_SFT	5
+#define NAU8824_CHARGE_PUMP_EN	(0x1 << NAU8824_CHARGE_PUMP_EN_SFT)
+
+
+#define NAU8824_CODEC_DAI "nau8824-hifi"
+
+/* System Clock Source */
+enum {
+	NAU8824_CLK_DIS,
+	NAU8824_CLK_MCLK,
+	NAU8824_CLK_INTERNAL,
+	NAU8824_CLK_FLL_MCLK,
+	NAU8824_CLK_FLL_BLK,
+	NAU8824_CLK_FLL_FS,
+};
+
+struct nau8824 {
+	struct device *dev;
+	struct regmap *regmap;
+	struct snd_soc_dapm_context *dapm;
+	struct snd_soc_jack *jack;
+	struct work_struct jdet_work;
+	struct semaphore jd_sem;
+	int fs;
+	int irq;
+	int micbias_voltage;
+	int vref_impedance;
+	int jkdet_polarity;
+	int sar_threshold_num;
+	int sar_threshold[8];
+	int sar_hysteresis;
+	int sar_voltage;
+	int sar_compare_time;
+	int sar_sampling_time;
+	int key_debounce;
+	int jack_eject_debounce;
+};
+
+struct nau8824_fll {
+	int mclk_src;
+	int ratio;
+	int fll_frac;
+	int fll_int;
+	int clk_ref_div;
+};
+
+struct nau8824_fll_attr {
+	unsigned int param;
+	unsigned int val;
+};
+
+struct nau8824_osr_attr {
+	unsigned int osr;
+	unsigned int clk_src;
+};
+
+
+int nau8824_enable_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *jack);
+
+#endif				/* _NAU8824_H */
+
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
new file mode 100644
index 0000000..b9fed99
--- /dev/null
+++ b/sound/soc/codecs/nau8825.c
@@ -0,0 +1,2667 @@
+/*
+ * Nuvoton NAU8825 audio codec driver
+ *
+ * Copyright 2015 Google Chromium project.
+ *  Author: Anatol Pomozov <anatol@chromium.org>
+ * Copyright 2015 Nuvoton Technology Corp.
+ *  Co-author: Meng-Huang Kuo <mhkuo@nuvoton.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/acpi.h>
+#include <linux/math64.h>
+#include <linux/semaphore.h>
+
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+
+#include "nau8825.h"
+
+
+#define NUVOTON_CODEC_DAI "nau8825-hifi"
+
+#define NAU_FREF_MAX 13500000
+#define NAU_FVCO_MAX 124000000
+#define NAU_FVCO_MIN 90000000
+
+/* cross talk suppression detection */
+#define LOG10_MAGIC 646456993
+#define GAIN_AUGMENT 22500
+#define SIDETONE_BASE 207000
+
+/* the maximum frequency of CLK_ADC and CLK_DAC */
+#define CLK_DA_AD_MAX 6144000
+
+static int nau8825_configure_sysclk(struct nau8825 *nau8825,
+		int clk_id, unsigned int freq);
+
+struct nau8825_fll {
+	int mclk_src;
+	int ratio;
+	int fll_frac;
+	int fll_int;
+	int clk_ref_div;
+};
+
+struct nau8825_fll_attr {
+	unsigned int param;
+	unsigned int val;
+};
+
+/* scaling for mclk from sysclk_src output */
+static const struct nau8825_fll_attr mclk_src_scaling[] = {
+	{ 1, 0x0 },
+	{ 2, 0x2 },
+	{ 4, 0x3 },
+	{ 8, 0x4 },
+	{ 16, 0x5 },
+	{ 32, 0x6 },
+	{ 3, 0x7 },
+	{ 6, 0xa },
+	{ 12, 0xb },
+	{ 24, 0xc },
+	{ 48, 0xd },
+	{ 96, 0xe },
+	{ 5, 0xf },
+};
+
+/* ratio for input clk freq */
+static const struct nau8825_fll_attr fll_ratio[] = {
+	{ 512000, 0x01 },
+	{ 256000, 0x02 },
+	{ 128000, 0x04 },
+	{ 64000, 0x08 },
+	{ 32000, 0x10 },
+	{ 8000, 0x20 },
+	{ 4000, 0x40 },
+};
+
+static const struct nau8825_fll_attr fll_pre_scalar[] = {
+	{ 1, 0x0 },
+	{ 2, 0x1 },
+	{ 4, 0x2 },
+	{ 8, 0x3 },
+};
+
+/* over sampling rate */
+struct nau8825_osr_attr {
+	unsigned int osr;
+	unsigned int clk_src;
+};
+
+static const struct nau8825_osr_attr osr_dac_sel[] = {
+	{ 64, 2 },	/* OSR 64, SRC 1/4 */
+	{ 256, 0 },	/* OSR 256, SRC 1 */
+	{ 128, 1 },	/* OSR 128, SRC 1/2 */
+	{ 0, 0 },
+	{ 32, 3 },	/* OSR 32, SRC 1/8 */
+};
+
+static const struct nau8825_osr_attr osr_adc_sel[] = {
+	{ 32, 3 },	/* OSR 32, SRC 1/8 */
+	{ 64, 2 },	/* OSR 64, SRC 1/4 */
+	{ 128, 1 },	/* OSR 128, SRC 1/2 */
+	{ 256, 0 },	/* OSR 256, SRC 1 */
+};
+
+static const struct reg_default nau8825_reg_defaults[] = {
+	{ NAU8825_REG_ENA_CTRL, 0x00ff },
+	{ NAU8825_REG_IIC_ADDR_SET, 0x0 },
+	{ NAU8825_REG_CLK_DIVIDER, 0x0050 },
+	{ NAU8825_REG_FLL1, 0x0 },
+	{ NAU8825_REG_FLL2, 0x3126 },
+	{ NAU8825_REG_FLL3, 0x0008 },
+	{ NAU8825_REG_FLL4, 0x0010 },
+	{ NAU8825_REG_FLL5, 0x0 },
+	{ NAU8825_REG_FLL6, 0x6000 },
+	{ NAU8825_REG_FLL_VCO_RSV, 0xf13c },
+	{ NAU8825_REG_HSD_CTRL, 0x000c },
+	{ NAU8825_REG_JACK_DET_CTRL, 0x0 },
+	{ NAU8825_REG_INTERRUPT_MASK, 0x0 },
+	{ NAU8825_REG_INTERRUPT_DIS_CTRL, 0xffff },
+	{ NAU8825_REG_SAR_CTRL, 0x0015 },
+	{ NAU8825_REG_KEYDET_CTRL, 0x0110 },
+	{ NAU8825_REG_VDET_THRESHOLD_1, 0x0 },
+	{ NAU8825_REG_VDET_THRESHOLD_2, 0x0 },
+	{ NAU8825_REG_VDET_THRESHOLD_3, 0x0 },
+	{ NAU8825_REG_VDET_THRESHOLD_4, 0x0 },
+	{ NAU8825_REG_GPIO34_CTRL, 0x0 },
+	{ NAU8825_REG_GPIO12_CTRL, 0x0 },
+	{ NAU8825_REG_TDM_CTRL, 0x0 },
+	{ NAU8825_REG_I2S_PCM_CTRL1, 0x000b },
+	{ NAU8825_REG_I2S_PCM_CTRL2, 0x8010 },
+	{ NAU8825_REG_LEFT_TIME_SLOT, 0x0 },
+	{ NAU8825_REG_RIGHT_TIME_SLOT, 0x0 },
+	{ NAU8825_REG_BIQ_CTRL, 0x0 },
+	{ NAU8825_REG_BIQ_COF1, 0x0 },
+	{ NAU8825_REG_BIQ_COF2, 0x0 },
+	{ NAU8825_REG_BIQ_COF3, 0x0 },
+	{ NAU8825_REG_BIQ_COF4, 0x0 },
+	{ NAU8825_REG_BIQ_COF5, 0x0 },
+	{ NAU8825_REG_BIQ_COF6, 0x0 },
+	{ NAU8825_REG_BIQ_COF7, 0x0 },
+	{ NAU8825_REG_BIQ_COF8, 0x0 },
+	{ NAU8825_REG_BIQ_COF9, 0x0 },
+	{ NAU8825_REG_BIQ_COF10, 0x0 },
+	{ NAU8825_REG_ADC_RATE, 0x0010 },
+	{ NAU8825_REG_DAC_CTRL1, 0x0001 },
+	{ NAU8825_REG_DAC_CTRL2, 0x0 },
+	{ NAU8825_REG_DAC_DGAIN_CTRL, 0x0 },
+	{ NAU8825_REG_ADC_DGAIN_CTRL, 0x00cf },
+	{ NAU8825_REG_MUTE_CTRL, 0x0 },
+	{ NAU8825_REG_HSVOL_CTRL, 0x0 },
+	{ NAU8825_REG_DACL_CTRL, 0x02cf },
+	{ NAU8825_REG_DACR_CTRL, 0x00cf },
+	{ NAU8825_REG_ADC_DRC_KNEE_IP12, 0x1486 },
+	{ NAU8825_REG_ADC_DRC_KNEE_IP34, 0x0f12 },
+	{ NAU8825_REG_ADC_DRC_SLOPES, 0x25ff },
+	{ NAU8825_REG_ADC_DRC_ATKDCY, 0x3457 },
+	{ NAU8825_REG_DAC_DRC_KNEE_IP12, 0x1486 },
+	{ NAU8825_REG_DAC_DRC_KNEE_IP34, 0x0f12 },
+	{ NAU8825_REG_DAC_DRC_SLOPES, 0x25f9 },
+	{ NAU8825_REG_DAC_DRC_ATKDCY, 0x3457 },
+	{ NAU8825_REG_IMM_MODE_CTRL, 0x0 },
+	{ NAU8825_REG_CLASSG_CTRL, 0x0 },
+	{ NAU8825_REG_OPT_EFUSE_CTRL, 0x0 },
+	{ NAU8825_REG_MISC_CTRL, 0x0 },
+	{ NAU8825_REG_BIAS_ADJ, 0x0 },
+	{ NAU8825_REG_TRIM_SETTINGS, 0x0 },
+	{ NAU8825_REG_ANALOG_CONTROL_1, 0x0 },
+	{ NAU8825_REG_ANALOG_CONTROL_2, 0x0 },
+	{ NAU8825_REG_ANALOG_ADC_1, 0x0011 },
+	{ NAU8825_REG_ANALOG_ADC_2, 0x0020 },
+	{ NAU8825_REG_RDAC, 0x0008 },
+	{ NAU8825_REG_MIC_BIAS, 0x0006 },
+	{ NAU8825_REG_BOOST, 0x0 },
+	{ NAU8825_REG_FEPGA, 0x0 },
+	{ NAU8825_REG_POWER_UP_CONTROL, 0x0 },
+	{ NAU8825_REG_CHARGE_PUMP, 0x0 },
+};
+
+/* register backup table when cross talk detection */
+static struct reg_default nau8825_xtalk_baktab[] = {
+	{ NAU8825_REG_ADC_DGAIN_CTRL, 0x00cf },
+	{ NAU8825_REG_HSVOL_CTRL, 0 },
+	{ NAU8825_REG_DACL_CTRL, 0x00cf },
+	{ NAU8825_REG_DACR_CTRL, 0x02cf },
+};
+
+static const unsigned short logtable[256] = {
+	0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
+	0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
+	0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
+	0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
+	0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
+	0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
+	0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
+	0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
+	0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
+	0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
+	0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
+	0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
+	0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
+	0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
+	0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
+	0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
+	0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
+	0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
+	0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
+	0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
+	0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
+	0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
+	0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
+	0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
+	0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
+	0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
+	0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
+	0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
+	0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
+	0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
+	0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
+	0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
+};
+
+/**
+ * nau8825_sema_acquire - acquire the semaphore of nau88l25
+ * @nau8825:  component to register the codec private data with
+ * @timeout: how long in jiffies to wait before failure or zero to wait
+ * until release
+ *
+ * Attempts to acquire the semaphore with number of jiffies. If no more
+ * tasks are allowed to acquire the semaphore, calling this function will
+ * put the task to sleep. If the semaphore is not released within the
+ * specified number of jiffies, this function returns.
+ * If the semaphore is not released within the specified number of jiffies,
+ * this function returns -ETIME. If the sleep is interrupted by a signal,
+ * this function will return -EINTR. It returns 0 if the semaphore was
+ * acquired successfully.
+ *
+ * Acquires the semaphore without jiffies. Try to acquire the semaphore
+ * atomically. Returns 0 if the semaphore has been acquired successfully
+ * or 1 if it it cannot be acquired.
+ */
+static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout)
+{
+	int ret;
+
+	if (timeout) {
+		ret = down_timeout(&nau8825->xtalk_sem, timeout);
+		if (ret < 0)
+			dev_warn(nau8825->dev, "Acquire semaphore timeout\n");
+	} else {
+		ret = down_trylock(&nau8825->xtalk_sem);
+		if (ret)
+			dev_warn(nau8825->dev, "Acquire semaphore fail\n");
+	}
+
+	return ret;
+}
+
+/**
+ * nau8825_sema_release - release the semaphore of nau88l25
+ * @nau8825:  component to register the codec private data with
+ *
+ * Release the semaphore which may be called from any context and
+ * even by tasks which have never called down().
+ */
+static inline void nau8825_sema_release(struct nau8825 *nau8825)
+{
+	up(&nau8825->xtalk_sem);
+}
+
+/**
+ * nau8825_sema_reset - reset the semaphore for nau88l25
+ * @nau8825:  component to register the codec private data with
+ *
+ * Reset the counter of the semaphore. Call this function to restart
+ * a new round task management.
+ */
+static inline void nau8825_sema_reset(struct nau8825 *nau8825)
+{
+	nau8825->xtalk_sem.count = 1;
+}
+
+/**
+ * Ramp up the headphone volume change gradually to target level.
+ *
+ * @nau8825:  component to register the codec private data with
+ * @vol_from: the volume to start up
+ * @vol_to: the target volume
+ * @step: the volume span to move on
+ *
+ * The headphone volume is from 0dB to minimum -54dB and -1dB per step.
+ * If the volume changes sharp, there is a pop noise heard in headphone. We
+ * provide the function to ramp up the volume up or down by delaying 10ms
+ * per step.
+ */
+static void nau8825_hpvol_ramp(struct nau8825 *nau8825,
+	unsigned int vol_from, unsigned int vol_to, unsigned int step)
+{
+	unsigned int value, volume, ramp_up, from, to;
+
+	if (vol_from == vol_to || step == 0) {
+		return;
+	} else if (vol_from < vol_to) {
+		ramp_up = true;
+		from = vol_from;
+		to = vol_to;
+	} else {
+		ramp_up = false;
+		from = vol_to;
+		to = vol_from;
+	}
+	/* only handle volume from 0dB to minimum -54dB */
+	if (to > NAU8825_HP_VOL_MIN)
+		to = NAU8825_HP_VOL_MIN;
+
+	for (volume = from; volume < to; volume += step) {
+		if (ramp_up)
+			value = volume;
+		else
+			value = to - volume + from;
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_HSVOL_CTRL,
+			NAU8825_HPL_VOL_MASK | NAU8825_HPR_VOL_MASK,
+			(value << NAU8825_HPL_VOL_SFT) | value);
+		usleep_range(10000, 10500);
+	}
+	if (ramp_up)
+		value = to;
+	else
+		value = from;
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_HSVOL_CTRL,
+		NAU8825_HPL_VOL_MASK | NAU8825_HPR_VOL_MASK,
+		(value << NAU8825_HPL_VOL_SFT) | value);
+}
+
+/**
+ * Computes log10 of a value; the result is round off to 3 decimal. This func-
+ * tion takes reference to dvb-math. The source code locates as the following.
+ * Linux/drivers/media/dvb-core/dvb_math.c
+ *
+ * return log10(value) * 1000
+ */
+static u32 nau8825_intlog10_dec3(u32 value)
+{
+	u32 msb, logentry, significand, interpolation, log10val;
+	u64 log2val;
+
+	/* first detect the msb (count begins at 0) */
+	msb = fls(value) - 1;
+	/**
+	 *      now we use a logtable after the following method:
+	 *
+	 *      log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
+	 *      where x = msb and therefore 1 <= y < 2
+	 *      first y is determined by shifting the value left
+	 *      so that msb is bit 31
+	 *              0x00231f56 -> 0x8C7D5800
+	 *      the result is y * 2^31 -> "significand"
+	 *      then the highest 9 bits are used for a table lookup
+	 *      the highest bit is discarded because it's always set
+	 *      the highest nine bits in our example are 100011000
+	 *      so we would use the entry 0x18
+	 */
+	significand = value << (31 - msb);
+	logentry = (significand >> 23) & 0xff;
+	/**
+	 *      last step we do is interpolation because of the
+	 *      limitations of the log table the error is that part of
+	 *      the significand which isn't used for lookup then we
+	 *      compute the ratio between the error and the next table entry
+	 *      and interpolate it between the log table entry used and the
+	 *      next one the biggest error possible is 0x7fffff
+	 *      (in our example it's 0x7D5800)
+	 *      needed value for next table entry is 0x800000
+	 *      so the interpolation is
+	 *      (error / 0x800000) * (logtable_next - logtable_current)
+	 *      in the implementation the division is moved to the end for
+	 *      better accuracy there is also an overflow correction if
+	 *      logtable_next is 256
+	 */
+	interpolation = ((significand & 0x7fffff) *
+		((logtable[(logentry + 1) & 0xff] -
+		logtable[logentry]) & 0xffff)) >> 15;
+
+	log2val = ((msb << 24) + (logtable[logentry] << 8) + interpolation);
+	/**
+	 *      log10(x) = log2(x) * log10(2)
+	 */
+	log10val = (log2val * LOG10_MAGIC) >> 31;
+	/**
+	 *      the result is round off to 3 decimal
+	 */
+	return log10val / ((1 << 24) / 1000);
+}
+
+/**
+ * computes cross talk suppression sidetone gain.
+ *
+ * @sig_org: orignal signal level
+ * @sig_cros: cross talk signal level
+ *
+ * The orignal and cross talk signal vlues need to be characterized.
+ * Once these values have been characterized, this sidetone value
+ * can be converted to decibel with the equation below.
+ * sidetone = 20 * log (original signal level / crosstalk signal level)
+ *
+ * return cross talk sidetone gain
+ */
+static u32 nau8825_xtalk_sidetone(u32 sig_org, u32 sig_cros)
+{
+	u32 gain, sidetone;
+
+	if (unlikely(sig_org == 0) || unlikely(sig_cros == 0)) {
+		WARN_ON(1);
+		return 0;
+	}
+
+	sig_org = nau8825_intlog10_dec3(sig_org);
+	sig_cros = nau8825_intlog10_dec3(sig_cros);
+	if (sig_org >= sig_cros)
+		gain = (sig_org - sig_cros) * 20 + GAIN_AUGMENT;
+	else
+		gain = (sig_cros - sig_org) * 20 + GAIN_AUGMENT;
+	sidetone = SIDETONE_BASE - gain * 2;
+	sidetone /= 1000;
+
+	return sidetone;
+}
+
+static int nau8825_xtalk_baktab_index_by_reg(unsigned int reg)
+{
+	int index;
+
+	for (index = 0; index < ARRAY_SIZE(nau8825_xtalk_baktab); index++)
+		if (nau8825_xtalk_baktab[index].reg == reg)
+			return index;
+	return -EINVAL;
+}
+
+static void nau8825_xtalk_backup(struct nau8825 *nau8825)
+{
+	int i;
+
+	if (nau8825->xtalk_baktab_initialized)
+		return;
+
+	/* Backup some register values to backup table */
+	for (i = 0; i < ARRAY_SIZE(nau8825_xtalk_baktab); i++)
+		regmap_read(nau8825->regmap, nau8825_xtalk_baktab[i].reg,
+				&nau8825_xtalk_baktab[i].def);
+
+	nau8825->xtalk_baktab_initialized = true;
+}
+
+static void nau8825_xtalk_restore(struct nau8825 *nau8825, bool cause_cancel)
+{
+	int i, volume;
+
+	if (!nau8825->xtalk_baktab_initialized)
+		return;
+
+	/* Restore register values from backup table; When the driver restores
+	 * the headphone volume in XTALK_DONE state, it needs recover to
+	 * original level gradually with 3dB per step for less pop noise.
+	 * Otherwise, the restore should do ASAP.
+	 */
+	for (i = 0; i < ARRAY_SIZE(nau8825_xtalk_baktab); i++) {
+		if (!cause_cancel && nau8825_xtalk_baktab[i].reg ==
+			NAU8825_REG_HSVOL_CTRL) {
+			/* Ramping up the volume change to reduce pop noise */
+			volume = nau8825_xtalk_baktab[i].def &
+				NAU8825_HPR_VOL_MASK;
+			nau8825_hpvol_ramp(nau8825, 0, volume, 3);
+			continue;
+		}
+		regmap_write(nau8825->regmap, nau8825_xtalk_baktab[i].reg,
+				nau8825_xtalk_baktab[i].def);
+	}
+
+	nau8825->xtalk_baktab_initialized = false;
+}
+
+static void nau8825_xtalk_prepare_dac(struct nau8825 *nau8825)
+{
+	/* Enable power of DAC path */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_ENA_CTRL,
+		NAU8825_ENABLE_DACR | NAU8825_ENABLE_DACL |
+		NAU8825_ENABLE_ADC | NAU8825_ENABLE_ADC_CLK |
+		NAU8825_ENABLE_DAC_CLK, NAU8825_ENABLE_DACR |
+		NAU8825_ENABLE_DACL | NAU8825_ENABLE_ADC |
+		NAU8825_ENABLE_ADC_CLK | NAU8825_ENABLE_DAC_CLK);
+	/* Prevent startup click by letting charge pump to ramp up and
+	 * change bump enable
+	 */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+		NAU8825_JAMNODCLOW | NAU8825_CHANRGE_PUMP_EN,
+		NAU8825_JAMNODCLOW | NAU8825_CHANRGE_PUMP_EN);
+	/* Enable clock sync of DAC and DAC clock */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_RDAC,
+		NAU8825_RDAC_EN | NAU8825_RDAC_CLK_EN |
+		NAU8825_RDAC_FS_BCLK_ENB,
+		NAU8825_RDAC_EN | NAU8825_RDAC_CLK_EN);
+	/* Power up output driver with 2 stage */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_POWER_UP_CONTROL,
+		NAU8825_POWERUP_INTEGR_R | NAU8825_POWERUP_INTEGR_L |
+		NAU8825_POWERUP_DRV_IN_R | NAU8825_POWERUP_DRV_IN_L,
+		NAU8825_POWERUP_INTEGR_R | NAU8825_POWERUP_INTEGR_L |
+		NAU8825_POWERUP_DRV_IN_R | NAU8825_POWERUP_DRV_IN_L);
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_POWER_UP_CONTROL,
+		NAU8825_POWERUP_HP_DRV_R | NAU8825_POWERUP_HP_DRV_L,
+		NAU8825_POWERUP_HP_DRV_R | NAU8825_POWERUP_HP_DRV_L);
+	/* HP outputs not shouted to ground  */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_HSD_CTRL,
+		NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L, 0);
+	/* Enable HP boost driver */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_BOOST,
+		NAU8825_HP_BOOST_DIS, NAU8825_HP_BOOST_DIS);
+	/* Enable class G compare path to supply 1.8V or 0.9V. */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_CLASSG_CTRL,
+		NAU8825_CLASSG_LDAC_EN | NAU8825_CLASSG_RDAC_EN,
+		NAU8825_CLASSG_LDAC_EN | NAU8825_CLASSG_RDAC_EN);
+}
+
+static void nau8825_xtalk_prepare_adc(struct nau8825 *nau8825)
+{
+	/* Power up left ADC and raise 5dB than Vmid for Vref  */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_ANALOG_ADC_2,
+		NAU8825_POWERUP_ADCL | NAU8825_ADC_VREFSEL_MASK,
+		NAU8825_POWERUP_ADCL | NAU8825_ADC_VREFSEL_VMID_PLUS_0_5DB);
+}
+
+static void nau8825_xtalk_clock(struct nau8825 *nau8825)
+{
+	/* Recover FLL default value */
+	regmap_write(nau8825->regmap, NAU8825_REG_FLL1, 0x0);
+	regmap_write(nau8825->regmap, NAU8825_REG_FLL2, 0x3126);
+	regmap_write(nau8825->regmap, NAU8825_REG_FLL3, 0x0008);
+	regmap_write(nau8825->regmap, NAU8825_REG_FLL4, 0x0010);
+	regmap_write(nau8825->regmap, NAU8825_REG_FLL5, 0x0);
+	regmap_write(nau8825->regmap, NAU8825_REG_FLL6, 0x6000);
+	/* Enable internal VCO clock for detection signal generated */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
+		NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_VCO);
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6, NAU8825_DCO_EN,
+		NAU8825_DCO_EN);
+	/* Given specific clock frequency of internal clock to
+	 * generate signal.
+	 */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
+		NAU8825_CLK_MCLK_SRC_MASK, 0xf);
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL1,
+		NAU8825_FLL_RATIO_MASK, 0x10);
+}
+
+static void nau8825_xtalk_prepare(struct nau8825 *nau8825)
+{
+	int volume, index;
+
+	/* Backup those registers changed by cross talk detection */
+	nau8825_xtalk_backup(nau8825);
+	/* Config IIS as master to output signal by codec */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
+		NAU8825_I2S_MS_MASK | NAU8825_I2S_LRC_DIV_MASK |
+		NAU8825_I2S_BLK_DIV_MASK, NAU8825_I2S_MS_MASTER |
+		(0x2 << NAU8825_I2S_LRC_DIV_SFT) | 0x1);
+	/* Ramp up headphone volume to 0dB to get better performance and
+	 * avoid pop noise in headphone.
+	 */
+	index = nau8825_xtalk_baktab_index_by_reg(NAU8825_REG_HSVOL_CTRL);
+	if (index != -EINVAL) {
+		volume = nau8825_xtalk_baktab[index].def &
+				NAU8825_HPR_VOL_MASK;
+		nau8825_hpvol_ramp(nau8825, volume, 0, 3);
+	}
+	nau8825_xtalk_clock(nau8825);
+	nau8825_xtalk_prepare_dac(nau8825);
+	nau8825_xtalk_prepare_adc(nau8825);
+	/* Config channel path and digital gain */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_DACL_CTRL,
+		NAU8825_DACL_CH_SEL_MASK | NAU8825_DACL_CH_VOL_MASK,
+		NAU8825_DACL_CH_SEL_L | 0xab);
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_DACR_CTRL,
+		NAU8825_DACR_CH_SEL_MASK | NAU8825_DACR_CH_VOL_MASK,
+		NAU8825_DACR_CH_SEL_R | 0xab);
+	/* Config cross talk parameters and generate the 23Hz sine wave with
+	 * 1/16 full scale of signal level for impedance measurement.
+	 */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_IMM_MODE_CTRL,
+		NAU8825_IMM_THD_MASK | NAU8825_IMM_GEN_VOL_MASK |
+		NAU8825_IMM_CYC_MASK | NAU8825_IMM_DAC_SRC_MASK,
+		(0x9 << NAU8825_IMM_THD_SFT) | NAU8825_IMM_GEN_VOL_1_16th |
+		NAU8825_IMM_CYC_8192 | NAU8825_IMM_DAC_SRC_SIN);
+	/* RMS intrruption enable */
+	regmap_update_bits(nau8825->regmap,
+		NAU8825_REG_INTERRUPT_MASK, NAU8825_IRQ_RMS_EN, 0);
+	/* Power up left and right DAC */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+		NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, 0);
+}
+
+static void nau8825_xtalk_clean_dac(struct nau8825 *nau8825)
+{
+	/* Disable HP boost driver */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_BOOST,
+		NAU8825_HP_BOOST_DIS, 0);
+	/* HP outputs shouted to ground  */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_HSD_CTRL,
+		NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L,
+		NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L);
+	/* Power down left and right DAC */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+		NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
+		NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
+	/* Enable the TESTDAC and  disable L/R HP impedance */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+		NAU8825_BIAS_HPR_IMP | NAU8825_BIAS_HPL_IMP |
+		NAU8825_BIAS_TESTDAC_EN, NAU8825_BIAS_TESTDAC_EN);
+	/* Power down output driver with 2 stage */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_POWER_UP_CONTROL,
+		NAU8825_POWERUP_HP_DRV_R | NAU8825_POWERUP_HP_DRV_L, 0);
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_POWER_UP_CONTROL,
+		NAU8825_POWERUP_INTEGR_R | NAU8825_POWERUP_INTEGR_L |
+		NAU8825_POWERUP_DRV_IN_R | NAU8825_POWERUP_DRV_IN_L, 0);
+	/* Disable clock sync of DAC and DAC clock */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_RDAC,
+		NAU8825_RDAC_EN | NAU8825_RDAC_CLK_EN, 0);
+	/* Disable charge pump ramp up function and change bump */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+		NAU8825_JAMNODCLOW | NAU8825_CHANRGE_PUMP_EN, 0);
+	/* Disable power of DAC path */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_ENA_CTRL,
+		NAU8825_ENABLE_DACR | NAU8825_ENABLE_DACL |
+		NAU8825_ENABLE_ADC_CLK | NAU8825_ENABLE_DAC_CLK, 0);
+	if (!nau8825->irq)
+		regmap_update_bits(nau8825->regmap,
+			NAU8825_REG_ENA_CTRL, NAU8825_ENABLE_ADC, 0);
+}
+
+static void nau8825_xtalk_clean_adc(struct nau8825 *nau8825)
+{
+	/* Power down left ADC and restore voltage to Vmid */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_ANALOG_ADC_2,
+		NAU8825_POWERUP_ADCL | NAU8825_ADC_VREFSEL_MASK, 0);
+}
+
+static void nau8825_xtalk_clean(struct nau8825 *nau8825, bool cause_cancel)
+{
+	/* Enable internal VCO needed for interruptions */
+	nau8825_configure_sysclk(nau8825, NAU8825_CLK_INTERNAL, 0);
+	nau8825_xtalk_clean_dac(nau8825);
+	nau8825_xtalk_clean_adc(nau8825);
+	/* Clear cross talk parameters and disable */
+	regmap_write(nau8825->regmap, NAU8825_REG_IMM_MODE_CTRL, 0);
+	/* RMS intrruption disable */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_INTERRUPT_MASK,
+		NAU8825_IRQ_RMS_EN, NAU8825_IRQ_RMS_EN);
+	/* Recover default value for IIS */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
+		NAU8825_I2S_MS_MASK | NAU8825_I2S_LRC_DIV_MASK |
+		NAU8825_I2S_BLK_DIV_MASK, NAU8825_I2S_MS_SLAVE);
+	/* Restore value of specific register for cross talk */
+	nau8825_xtalk_restore(nau8825, cause_cancel);
+}
+
+static void nau8825_xtalk_imm_start(struct nau8825 *nau8825, int vol)
+{
+	/* Apply ADC volume for better cross talk performance */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_ADC_DGAIN_CTRL,
+				NAU8825_ADC_DIG_VOL_MASK, vol);
+	/* Disables JKTIP(HPL) DAC channel for right to left measurement.
+	 * Do it before sending signal in order to erase pop noise.
+	 */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+		NAU8825_BIAS_TESTDACR_EN | NAU8825_BIAS_TESTDACL_EN,
+		NAU8825_BIAS_TESTDACL_EN);
+	switch (nau8825->xtalk_state) {
+	case NAU8825_XTALK_HPR_R2L:
+		/* Enable right headphone impedance */
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+			NAU8825_BIAS_HPR_IMP | NAU8825_BIAS_HPL_IMP,
+			NAU8825_BIAS_HPR_IMP);
+		break;
+	case NAU8825_XTALK_HPL_R2L:
+		/* Enable left headphone impedance */
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+			NAU8825_BIAS_HPR_IMP | NAU8825_BIAS_HPL_IMP,
+			NAU8825_BIAS_HPL_IMP);
+		break;
+	default:
+		break;
+	}
+	msleep(100);
+	/* Impedance measurement mode enable */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_IMM_MODE_CTRL,
+				NAU8825_IMM_EN, NAU8825_IMM_EN);
+}
+
+static void nau8825_xtalk_imm_stop(struct nau8825 *nau8825)
+{
+	/* Impedance measurement mode disable */
+	regmap_update_bits(nau8825->regmap,
+		NAU8825_REG_IMM_MODE_CTRL, NAU8825_IMM_EN, 0);
+}
+
+/* The cross talk measurement function can reduce cross talk across the
+ * JKTIP(HPL) and JKR1(HPR) outputs which measures the cross talk signal
+ * level to determine what cross talk reduction gain is. This system works by
+ * sending a 23Hz -24dBV sine wave into the headset output DAC and through
+ * the PGA. The output of the PGA is then connected to an internal current
+ * sense which measures the attenuated 23Hz signal and passing the output to
+ * an ADC which converts the measurement to a binary code. With two separated
+ * measurement, one for JKR1(HPR) and the other JKTIP(HPL), measurement data
+ * can be separated read in IMM_RMS_L for HSR and HSL after each measurement.
+ * Thus, the measurement function has four states to complete whole sequence.
+ * 1. Prepare state : Prepare the resource for detection and transfer to HPR
+ *     IMM stat to make JKR1(HPR) impedance measure.
+ * 2. HPR IMM state : Read out orignal signal level of JKR1(HPR) and transfer
+ *     to HPL IMM state to make JKTIP(HPL) impedance measure.
+ * 3. HPL IMM state : Read out cross talk signal level of JKTIP(HPL) and
+ *     transfer to IMM state to determine suppression sidetone gain.
+ * 4. IMM state : Computes cross talk suppression sidetone gain with orignal
+ *     and cross talk signal level. Apply this gain and then restore codec
+ *     configuration. Then transfer to Done state for ending.
+ */
+static void nau8825_xtalk_measure(struct nau8825 *nau8825)
+{
+	u32 sidetone;
+
+	switch (nau8825->xtalk_state) {
+	case NAU8825_XTALK_PREPARE:
+		/* In prepare state, set up clock, intrruption, DAC path, ADC
+		 * path and cross talk detection parameters for preparation.
+		 */
+		nau8825_xtalk_prepare(nau8825);
+		msleep(280);
+		/* Trigger right headphone impedance detection */
+		nau8825->xtalk_state = NAU8825_XTALK_HPR_R2L;
+		nau8825_xtalk_imm_start(nau8825, 0x00d2);
+		break;
+	case NAU8825_XTALK_HPR_R2L:
+		/* In right headphone IMM state, read out right headphone
+		 * impedance measure result, and then start up left side.
+		 */
+		regmap_read(nau8825->regmap, NAU8825_REG_IMM_RMS_L,
+			&nau8825->imp_rms[NAU8825_XTALK_HPR_R2L]);
+		dev_dbg(nau8825->dev, "HPR_R2L imm: %x\n",
+			nau8825->imp_rms[NAU8825_XTALK_HPR_R2L]);
+		/* Disable then re-enable IMM mode to update */
+		nau8825_xtalk_imm_stop(nau8825);
+		/* Trigger left headphone impedance detection */
+		nau8825->xtalk_state = NAU8825_XTALK_HPL_R2L;
+		nau8825_xtalk_imm_start(nau8825, 0x00ff);
+		break;
+	case NAU8825_XTALK_HPL_R2L:
+		/* In left headphone IMM state, read out left headphone
+		 * impedance measure result, and delay some time to wait
+		 * detection sine wave output finish. Then, we can calculate
+		 * the cross talk suppresstion side tone according to the L/R
+		 * headphone imedance.
+		 */
+		regmap_read(nau8825->regmap, NAU8825_REG_IMM_RMS_L,
+			&nau8825->imp_rms[NAU8825_XTALK_HPL_R2L]);
+		dev_dbg(nau8825->dev, "HPL_R2L imm: %x\n",
+			nau8825->imp_rms[NAU8825_XTALK_HPL_R2L]);
+		nau8825_xtalk_imm_stop(nau8825);
+		msleep(150);
+		nau8825->xtalk_state = NAU8825_XTALK_IMM;
+		break;
+	case NAU8825_XTALK_IMM:
+		/* In impedance measure state, the orignal and cross talk
+		 * signal level vlues are ready. The side tone gain is deter-
+		 * mined with these signal level. After all, restore codec
+		 * configuration.
+		 */
+		sidetone = nau8825_xtalk_sidetone(
+			nau8825->imp_rms[NAU8825_XTALK_HPR_R2L],
+			nau8825->imp_rms[NAU8825_XTALK_HPL_R2L]);
+		dev_dbg(nau8825->dev, "cross talk sidetone: %x\n", sidetone);
+		regmap_write(nau8825->regmap, NAU8825_REG_DAC_DGAIN_CTRL,
+					(sidetone << 8) | sidetone);
+		nau8825_xtalk_clean(nau8825, false);
+		nau8825->xtalk_state = NAU8825_XTALK_DONE;
+		break;
+	default:
+		break;
+	}
+}
+
+static void nau8825_xtalk_work(struct work_struct *work)
+{
+	struct nau8825 *nau8825 = container_of(
+		work, struct nau8825, xtalk_work);
+
+	nau8825_xtalk_measure(nau8825);
+	/* To determine the cross talk side tone gain when reach
+	 * the impedance measure state.
+	 */
+	if (nau8825->xtalk_state == NAU8825_XTALK_IMM)
+		nau8825_xtalk_measure(nau8825);
+
+	/* Delay jack report until cross talk detection process
+	 * completed. It can avoid application to do playback
+	 * preparation before cross talk detection is still working.
+	 * Meanwhile, the protection of the cross talk detection
+	 * is released.
+	 */
+	if (nau8825->xtalk_state == NAU8825_XTALK_DONE) {
+		snd_soc_jack_report(nau8825->jack, nau8825->xtalk_event,
+				nau8825->xtalk_event_mask);
+		nau8825_sema_release(nau8825);
+		nau8825->xtalk_protect = false;
+	}
+}
+
+static void nau8825_xtalk_cancel(struct nau8825 *nau8825)
+{
+	/* If the crosstalk is eanbled and the process is on going,
+	 * the driver forces to cancel the crosstalk task and
+	 * restores the configuration to original status.
+	 */
+	if (nau8825->xtalk_enable && nau8825->xtalk_state !=
+		NAU8825_XTALK_DONE) {
+		cancel_work_sync(&nau8825->xtalk_work);
+		nau8825_xtalk_clean(nau8825, true);
+	}
+	/* Reset parameters for cross talk suppression function */
+	nau8825_sema_reset(nau8825);
+	nau8825->xtalk_state = NAU8825_XTALK_DONE;
+	nau8825->xtalk_protect = false;
+}
+
+static bool nau8825_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8825_REG_ENA_CTRL ... NAU8825_REG_FLL_VCO_RSV:
+	case NAU8825_REG_HSD_CTRL ... NAU8825_REG_JACK_DET_CTRL:
+	case NAU8825_REG_INTERRUPT_MASK ... NAU8825_REG_KEYDET_CTRL:
+	case NAU8825_REG_VDET_THRESHOLD_1 ... NAU8825_REG_DACR_CTRL:
+	case NAU8825_REG_ADC_DRC_KNEE_IP12 ... NAU8825_REG_ADC_DRC_ATKDCY:
+	case NAU8825_REG_DAC_DRC_KNEE_IP12 ... NAU8825_REG_DAC_DRC_ATKDCY:
+	case NAU8825_REG_IMM_MODE_CTRL ... NAU8825_REG_IMM_RMS_R:
+	case NAU8825_REG_CLASSG_CTRL ... NAU8825_REG_OPT_EFUSE_CTRL:
+	case NAU8825_REG_MISC_CTRL:
+	case NAU8825_REG_I2C_DEVICE_ID ... NAU8825_REG_SARDOUT_RAM_STATUS:
+	case NAU8825_REG_BIAS_ADJ:
+	case NAU8825_REG_TRIM_SETTINGS ... NAU8825_REG_ANALOG_CONTROL_2:
+	case NAU8825_REG_ANALOG_ADC_1 ... NAU8825_REG_MIC_BIAS:
+	case NAU8825_REG_BOOST ... NAU8825_REG_FEPGA:
+	case NAU8825_REG_POWER_UP_CONTROL ... NAU8825_REG_GENERAL_STATUS:
+		return true;
+	default:
+		return false;
+	}
+
+}
+
+static bool nau8825_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8825_REG_RESET ... NAU8825_REG_FLL_VCO_RSV:
+	case NAU8825_REG_HSD_CTRL ... NAU8825_REG_JACK_DET_CTRL:
+	case NAU8825_REG_INTERRUPT_MASK:
+	case NAU8825_REG_INT_CLR_KEY_STATUS ... NAU8825_REG_KEYDET_CTRL:
+	case NAU8825_REG_VDET_THRESHOLD_1 ... NAU8825_REG_DACR_CTRL:
+	case NAU8825_REG_ADC_DRC_KNEE_IP12 ... NAU8825_REG_ADC_DRC_ATKDCY:
+	case NAU8825_REG_DAC_DRC_KNEE_IP12 ... NAU8825_REG_DAC_DRC_ATKDCY:
+	case NAU8825_REG_IMM_MODE_CTRL:
+	case NAU8825_REG_CLASSG_CTRL ... NAU8825_REG_OPT_EFUSE_CTRL:
+	case NAU8825_REG_MISC_CTRL:
+	case NAU8825_REG_BIAS_ADJ:
+	case NAU8825_REG_TRIM_SETTINGS ... NAU8825_REG_ANALOG_CONTROL_2:
+	case NAU8825_REG_ANALOG_ADC_1 ... NAU8825_REG_MIC_BIAS:
+	case NAU8825_REG_BOOST ... NAU8825_REG_FEPGA:
+	case NAU8825_REG_POWER_UP_CONTROL ... NAU8825_REG_CHARGE_PUMP:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool nau8825_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case NAU8825_REG_RESET:
+	case NAU8825_REG_IRQ_STATUS:
+	case NAU8825_REG_INT_CLR_KEY_STATUS:
+	case NAU8825_REG_IMM_RMS_L:
+	case NAU8825_REG_IMM_RMS_R:
+	case NAU8825_REG_I2C_DEVICE_ID:
+	case NAU8825_REG_SARDOUT_RAM_STATUS:
+	case NAU8825_REG_CHARGE_PUMP_INPUT_READ:
+	case NAU8825_REG_GENERAL_STATUS:
+	case NAU8825_REG_BIQ_CTRL ... NAU8825_REG_BIQ_COF10:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int nau8825_adc_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		msleep(125);
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_ENA_CTRL,
+			NAU8825_ENABLE_ADC, NAU8825_ENABLE_ADC);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (!nau8825->irq)
+			regmap_update_bits(nau8825->regmap,
+				NAU8825_REG_ENA_CTRL, NAU8825_ENABLE_ADC, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int nau8825_pump_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Prevent startup click by letting charge pump to ramp up */
+		msleep(10);
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+			NAU8825_JAMNODCLOW, NAU8825_JAMNODCLOW);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+			NAU8825_JAMNODCLOW, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int nau8825_output_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Disables the TESTDAC to let DAC signal pass through. */
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+			NAU8825_BIAS_TESTDAC_EN, 0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+			NAU8825_BIAS_TESTDAC_EN, NAU8825_BIAS_TESTDAC_EN);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int nau8825_biq_coeff_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+
+	if (!component->regmap)
+		return -EINVAL;
+
+	regmap_raw_read(component->regmap, NAU8825_REG_BIQ_COF1,
+		ucontrol->value.bytes.data, params->max);
+	return 0;
+}
+
+static int nau8825_biq_coeff_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+	void *data;
+
+	if (!component->regmap)
+		return -EINVAL;
+
+	data = kmemdup(ucontrol->value.bytes.data,
+		params->max, GFP_KERNEL | GFP_DMA);
+	if (!data)
+		return -ENOMEM;
+
+	regmap_update_bits(component->regmap, NAU8825_REG_BIQ_CTRL,
+		NAU8825_BIQ_WRT_EN, 0);
+	regmap_raw_write(component->regmap, NAU8825_REG_BIQ_COF1,
+		data, params->max);
+	regmap_update_bits(component->regmap, NAU8825_REG_BIQ_CTRL,
+		NAU8825_BIQ_WRT_EN, NAU8825_BIQ_WRT_EN);
+
+	kfree(data);
+	return 0;
+}
+
+static const char * const nau8825_biq_path[] = {
+	"ADC", "DAC"
+};
+
+static const struct soc_enum nau8825_biq_path_enum =
+	SOC_ENUM_SINGLE(NAU8825_REG_BIQ_CTRL, NAU8825_BIQ_PATH_SFT,
+		ARRAY_SIZE(nau8825_biq_path), nau8825_biq_path);
+
+static const char * const nau8825_adc_decimation[] = {
+	"32", "64", "128", "256"
+};
+
+static const struct soc_enum nau8825_adc_decimation_enum =
+	SOC_ENUM_SINGLE(NAU8825_REG_ADC_RATE, NAU8825_ADC_SYNC_DOWN_SFT,
+		ARRAY_SIZE(nau8825_adc_decimation), nau8825_adc_decimation);
+
+static const char * const nau8825_dac_oversampl[] = {
+	"64", "256", "128", "", "32"
+};
+
+static const struct soc_enum nau8825_dac_oversampl_enum =
+	SOC_ENUM_SINGLE(NAU8825_REG_DAC_CTRL1, NAU8825_DAC_OVERSAMPLE_SFT,
+		ARRAY_SIZE(nau8825_dac_oversampl), nau8825_dac_oversampl);
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(adc_vol_tlv, -10300, 2400);
+static const DECLARE_TLV_DB_MINMAX_MUTE(sidetone_vol_tlv, -4200, 0);
+static const DECLARE_TLV_DB_MINMAX(dac_vol_tlv, -5400, 0);
+static const DECLARE_TLV_DB_MINMAX(fepga_gain_tlv, -100, 3600);
+static const DECLARE_TLV_DB_MINMAX_MUTE(crosstalk_vol_tlv, -9600, 2400);
+
+static const struct snd_kcontrol_new nau8825_controls[] = {
+	SOC_SINGLE_TLV("Mic Volume", NAU8825_REG_ADC_DGAIN_CTRL,
+		0, 0xff, 0, adc_vol_tlv),
+	SOC_DOUBLE_TLV("Headphone Bypass Volume", NAU8825_REG_ADC_DGAIN_CTRL,
+		12, 8, 0x0f, 0, sidetone_vol_tlv),
+	SOC_DOUBLE_TLV("Headphone Volume", NAU8825_REG_HSVOL_CTRL,
+		6, 0, 0x3f, 1, dac_vol_tlv),
+	SOC_SINGLE_TLV("Frontend PGA Volume", NAU8825_REG_POWER_UP_CONTROL,
+		8, 37, 0, fepga_gain_tlv),
+	SOC_DOUBLE_TLV("Headphone Crosstalk Volume", NAU8825_REG_DAC_DGAIN_CTRL,
+		0, 8, 0xff, 0, crosstalk_vol_tlv),
+
+	SOC_ENUM("ADC Decimation Rate", nau8825_adc_decimation_enum),
+	SOC_ENUM("DAC Oversampling Rate", nau8825_dac_oversampl_enum),
+	/* programmable biquad filter */
+	SOC_ENUM("BIQ Path Select", nau8825_biq_path_enum),
+	SND_SOC_BYTES_EXT("BIQ Coefficients", 20,
+		  nau8825_biq_coeff_get, nau8825_biq_coeff_put),
+};
+
+/* DAC Mux 0x33[9] and 0x34[9] */
+static const char * const nau8825_dac_src[] = {
+	"DACL", "DACR",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	nau8825_dacl_enum, NAU8825_REG_DACL_CTRL,
+	NAU8825_DACL_CH_SEL_SFT, nau8825_dac_src);
+
+static SOC_ENUM_SINGLE_DECL(
+	nau8825_dacr_enum, NAU8825_REG_DACR_CTRL,
+	NAU8825_DACR_CH_SEL_SFT, nau8825_dac_src);
+
+static const struct snd_kcontrol_new nau8825_dacl_mux =
+	SOC_DAPM_ENUM("DACL Source", nau8825_dacl_enum);
+
+static const struct snd_kcontrol_new nau8825_dacr_mux =
+	SOC_DAPM_ENUM("DACR Source", nau8825_dacr_enum);
+
+
+static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_OUT("AIFTX", "Capture", 0, NAU8825_REG_I2S_PCM_CTRL2,
+		15, 1),
+
+	SND_SOC_DAPM_INPUT("MIC"),
+	SND_SOC_DAPM_MICBIAS("MICBIAS", NAU8825_REG_MIC_BIAS, 8, 0),
+
+	SND_SOC_DAPM_PGA("Frontend PGA", NAU8825_REG_POWER_UP_CONTROL, 14, 0,
+		NULL, 0),
+
+	SND_SOC_DAPM_ADC_E("ADC", NULL, SND_SOC_NOPM, 0, 0,
+		nau8825_adc_event, SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("ADC Clock", NAU8825_REG_ENA_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Power", NAU8825_REG_ANALOG_ADC_2, 6, 0, NULL,
+		0),
+
+	/* ADC for button press detection. A dapm supply widget is used to
+	 * prevent dapm_power_widgets keeping the codec at SND_SOC_BIAS_ON
+	 * during suspend.
+	 */
+	SND_SOC_DAPM_SUPPLY("SAR", NAU8825_REG_SAR_CTRL,
+		NAU8825_SAR_ADC_EN_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA_S("ADACL", 2, NAU8825_REG_RDAC, 12, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("ADACR", 2, NAU8825_REG_RDAC, 13, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("ADACL Clock", 3, NAU8825_REG_RDAC, 8, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("ADACR Clock", 3, NAU8825_REG_RDAC, 9, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("DDACR", NULL, NAU8825_REG_ENA_CTRL,
+		NAU8825_ENABLE_DACR_SFT, 0),
+	SND_SOC_DAPM_DAC("DDACL", NULL, NAU8825_REG_ENA_CTRL,
+		NAU8825_ENABLE_DACL_SFT, 0),
+	SND_SOC_DAPM_SUPPLY("DDAC Clock", NAU8825_REG_ENA_CTRL, 6, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &nau8825_dacl_mux),
+	SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &nau8825_dacr_mux),
+
+	SND_SOC_DAPM_PGA_S("HP amp L", 0,
+		NAU8825_REG_CLASSG_CTRL, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("HP amp R", 0,
+		NAU8825_REG_CLASSG_CTRL, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA_S("Charge Pump", 1, NAU8825_REG_CHARGE_PUMP, 5, 0,
+		nau8825_pump_event, SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_PGA_S("Output Driver R Stage 1", 4,
+		NAU8825_REG_POWER_UP_CONTROL, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("Output Driver L Stage 1", 4,
+		NAU8825_REG_POWER_UP_CONTROL, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("Output Driver R Stage 2", 5,
+		NAU8825_REG_POWER_UP_CONTROL, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("Output Driver L Stage 2", 5,
+		NAU8825_REG_POWER_UP_CONTROL, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("Output Driver R Stage 3", 6,
+		NAU8825_REG_POWER_UP_CONTROL, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("Output Driver L Stage 3", 6,
+		NAU8825_REG_POWER_UP_CONTROL, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA_S("Output DACL", 7,
+		NAU8825_REG_CHARGE_PUMP, 8, 1, nau8825_output_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_S("Output DACR", 7,
+		NAU8825_REG_CHARGE_PUMP, 9, 1, nau8825_output_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* HPOL/R are ungrounded by disabling 16 Ohm pull-downs on playback */
+	SND_SOC_DAPM_PGA_S("HPOL Pulldown", 8,
+		NAU8825_REG_HSD_CTRL, 0, 1, NULL, 0),
+	SND_SOC_DAPM_PGA_S("HPOR Pulldown", 8,
+		NAU8825_REG_HSD_CTRL, 1, 1, NULL, 0),
+
+	/* High current HPOL/R boost driver */
+	SND_SOC_DAPM_PGA_S("HP Boost Driver", 9,
+		NAU8825_REG_BOOST, 9, 1, NULL, 0),
+
+	/* Class G operation control*/
+	SND_SOC_DAPM_PGA_S("Class G", 10,
+		NAU8825_REG_CLASSG_CTRL, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_route nau8825_dapm_routes[] = {
+	{"Frontend PGA", NULL, "MIC"},
+	{"ADC", NULL, "Frontend PGA"},
+	{"ADC", NULL, "ADC Clock"},
+	{"ADC", NULL, "ADC Power"},
+	{"AIFTX", NULL, "ADC"},
+
+	{"DDACL", NULL, "Playback"},
+	{"DDACR", NULL, "Playback"},
+	{"DDACL", NULL, "DDAC Clock"},
+	{"DDACR", NULL, "DDAC Clock"},
+	{"DACL Mux", "DACL", "DDACL"},
+	{"DACL Mux", "DACR", "DDACR"},
+	{"DACR Mux", "DACL", "DDACL"},
+	{"DACR Mux", "DACR", "DDACR"},
+	{"HP amp L", NULL, "DACL Mux"},
+	{"HP amp R", NULL, "DACR Mux"},
+	{"Charge Pump", NULL, "HP amp L"},
+	{"Charge Pump", NULL, "HP amp R"},
+	{"ADACL", NULL, "Charge Pump"},
+	{"ADACR", NULL, "Charge Pump"},
+	{"ADACL Clock", NULL, "ADACL"},
+	{"ADACR Clock", NULL, "ADACR"},
+	{"Output Driver L Stage 1", NULL, "ADACL Clock"},
+	{"Output Driver R Stage 1", NULL, "ADACR Clock"},
+	{"Output Driver L Stage 2", NULL, "Output Driver L Stage 1"},
+	{"Output Driver R Stage 2", NULL, "Output Driver R Stage 1"},
+	{"Output Driver L Stage 3", NULL, "Output Driver L Stage 2"},
+	{"Output Driver R Stage 3", NULL, "Output Driver R Stage 2"},
+	{"Output DACL", NULL, "Output Driver L Stage 3"},
+	{"Output DACR", NULL, "Output Driver R Stage 3"},
+	{"HPOL Pulldown", NULL, "Output DACL"},
+	{"HPOR Pulldown", NULL, "Output DACR"},
+	{"HP Boost Driver", NULL, "HPOL Pulldown"},
+	{"HP Boost Driver", NULL, "HPOR Pulldown"},
+	{"Class G", NULL, "HP Boost Driver"},
+	{"HPOL", NULL, "Class G"},
+	{"HPOR", NULL, "Class G"},
+};
+
+static int nau8825_clock_check(struct nau8825 *nau8825,
+	int stream, int rate, int osr)
+{
+	int osrate;
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (osr >= ARRAY_SIZE(osr_dac_sel))
+			return -EINVAL;
+		osrate = osr_dac_sel[osr].osr;
+	} else {
+		if (osr >= ARRAY_SIZE(osr_adc_sel))
+			return -EINVAL;
+		osrate = osr_adc_sel[osr].osr;
+	}
+
+	if (!osrate || rate * osr > CLK_DA_AD_MAX) {
+		dev_err(nau8825->dev, "exceed the maximum frequency of CLK_ADC or CLK_DAC\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int nau8825_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0, osr, ctrl_val, bclk_fs, bclk_div;
+
+	nau8825_sema_acquire(nau8825, 3 * HZ);
+
+	/* CLK_DAC or CLK_ADC = OSR * FS
+	 * DAC or ADC clock frequency is defined as Over Sampling Rate (OSR)
+	 * multiplied by the audio sample rate (Fs). Note that the OSR and Fs
+	 * values must be selected such that the maximum frequency is less
+	 * than 6.144 MHz.
+	 */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		regmap_read(nau8825->regmap, NAU8825_REG_DAC_CTRL1, &osr);
+		osr &= NAU8825_DAC_OVERSAMPLE_MASK;
+		if (nau8825_clock_check(nau8825, substream->stream,
+			params_rate(params), osr)) {
+			nau8825_sema_release(nau8825);
+			return -EINVAL;
+		}
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
+			NAU8825_CLK_DAC_SRC_MASK,
+			osr_dac_sel[osr].clk_src << NAU8825_CLK_DAC_SRC_SFT);
+	} else {
+		regmap_read(nau8825->regmap, NAU8825_REG_ADC_RATE, &osr);
+		osr &= NAU8825_ADC_SYNC_DOWN_MASK;
+		if (nau8825_clock_check(nau8825, substream->stream,
+			params_rate(params), osr)) {
+			nau8825_sema_release(nau8825);
+			return -EINVAL;
+		}
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
+			NAU8825_CLK_ADC_SRC_MASK,
+			osr_adc_sel[osr].clk_src << NAU8825_CLK_ADC_SRC_SFT);
+	}
+
+	/* make BCLK and LRC divde configuration if the codec as master. */
+	regmap_read(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, &ctrl_val);
+	if (ctrl_val & NAU8825_I2S_MS_MASTER) {
+		/* get the bclk and fs ratio */
+		bclk_fs = snd_soc_params_to_bclk(params) / params_rate(params);
+		if (bclk_fs <= 32)
+			bclk_div = 2;
+		else if (bclk_fs <= 64)
+			bclk_div = 1;
+		else if (bclk_fs <= 128)
+			bclk_div = 0;
+		else {
+			nau8825_sema_release(nau8825);
+			return -EINVAL;
+		}
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
+			NAU8825_I2S_LRC_DIV_MASK | NAU8825_I2S_BLK_DIV_MASK,
+			((bclk_div + 1) << NAU8825_I2S_LRC_DIV_SFT) | bclk_div);
+	}
+
+	switch (params_width(params)) {
+	case 16:
+		val_len |= NAU8825_I2S_DL_16;
+		break;
+	case 20:
+		val_len |= NAU8825_I2S_DL_20;
+		break;
+	case 24:
+		val_len |= NAU8825_I2S_DL_24;
+		break;
+	case 32:
+		val_len |= NAU8825_I2S_DL_32;
+		break;
+	default:
+		nau8825_sema_release(nau8825);
+		return -EINVAL;
+	}
+
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1,
+		NAU8825_I2S_DL_MASK, val_len);
+
+	/* Release the semaphore. */
+	nau8825_sema_release(nau8825);
+
+	return 0;
+}
+
+static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+	unsigned int ctrl1_val = 0, ctrl2_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		ctrl2_val |= NAU8825_I2S_MS_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		ctrl1_val |= NAU8825_I2S_BP_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		ctrl1_val |= NAU8825_I2S_DF_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ctrl1_val |= NAU8825_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		ctrl1_val |= NAU8825_I2S_DF_RIGTH;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		ctrl1_val |= NAU8825_I2S_DF_PCM_AB;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		ctrl1_val |= NAU8825_I2S_DF_PCM_AB;
+		ctrl1_val |= NAU8825_I2S_PCMB_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	nau8825_sema_acquire(nau8825, 3 * HZ);
+
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1,
+		NAU8825_I2S_DL_MASK | NAU8825_I2S_DF_MASK |
+		NAU8825_I2S_BP_MASK | NAU8825_I2S_PCMB_MASK,
+		ctrl1_val);
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
+		NAU8825_I2S_MS_MASK, ctrl2_val);
+
+	/* Release the semaphore. */
+	nau8825_sema_release(nau8825);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops nau8825_dai_ops = {
+	.hw_params	= nau8825_hw_params,
+	.set_fmt	= nau8825_set_dai_fmt,
+};
+
+#define NAU8825_RATES	SNDRV_PCM_RATE_8000_192000
+#define NAU8825_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+			 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver nau8825_dai = {
+	.name = "nau8825-hifi",
+	.playback = {
+		.stream_name	 = "Playback",
+		.channels_min	 = 1,
+		.channels_max	 = 2,
+		.rates		 = NAU8825_RATES,
+		.formats	 = NAU8825_FORMATS,
+	},
+	.capture = {
+		.stream_name	 = "Capture",
+		.channels_min	 = 1,
+		.channels_max	 = 1,
+		.rates		 = NAU8825_RATES,
+		.formats	 = NAU8825_FORMATS,
+	},
+	.ops = &nau8825_dai_ops,
+};
+
+/**
+ * nau8825_enable_jack_detect - Specify a jack for event reporting
+ *
+ * @component:  component to register the jack with
+ * @jack: jack to use to report headset and button events on
+ *
+ * After this function has been called the headset insert/remove and button
+ * events will be routed to the given jack.  Jack can be null to stop
+ * reporting.
+ */
+int nau8825_enable_jack_detect(struct snd_soc_component *component,
+				struct snd_soc_jack *jack)
+{
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = nau8825->regmap;
+
+	nau8825->jack = jack;
+
+	/* Ground HP Outputs[1:0], needed for headset auto detection
+	 * Enable Automatic Mic/Gnd switching reading on insert interrupt[6]
+	 */
+	regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL,
+		NAU8825_HSD_AUTO_MODE | NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L,
+		NAU8825_HSD_AUTO_MODE | NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nau8825_enable_jack_detect);
+
+
+static bool nau8825_is_jack_inserted(struct regmap *regmap)
+{
+	bool active_high, is_high;
+	int status, jkdet;
+
+	regmap_read(regmap, NAU8825_REG_JACK_DET_CTRL, &jkdet);
+	active_high = jkdet & NAU8825_JACK_POLARITY;
+	regmap_read(regmap, NAU8825_REG_I2C_DEVICE_ID, &status);
+	is_high = status & NAU8825_GPIO2JD1;
+	/* return jack connection status according to jack insertion logic
+	 * active high or active low.
+	 */
+	return active_high == is_high;
+}
+
+static void nau8825_restart_jack_detection(struct regmap *regmap)
+{
+	/* this will restart the entire jack detection process including MIC/GND
+	 * switching and create interrupts. We have to go from 0 to 1 and back
+	 * to 0 to restart.
+	 */
+	regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL,
+		NAU8825_JACK_DET_RESTART, NAU8825_JACK_DET_RESTART);
+	regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL,
+		NAU8825_JACK_DET_RESTART, 0);
+}
+
+static void nau8825_int_status_clear_all(struct regmap *regmap)
+{
+	int active_irq, clear_irq, i;
+
+	/* Reset the intrruption status from rightmost bit if the corres-
+	 * ponding irq event occurs.
+	 */
+	regmap_read(regmap, NAU8825_REG_IRQ_STATUS, &active_irq);
+	for (i = 0; i < NAU8825_REG_DATA_LEN; i++) {
+		clear_irq = (0x1 << i);
+		if (active_irq & clear_irq)
+			regmap_write(regmap,
+				NAU8825_REG_INT_CLR_KEY_STATUS, clear_irq);
+	}
+}
+
+static void nau8825_eject_jack(struct nau8825 *nau8825)
+{
+	struct snd_soc_dapm_context *dapm = nau8825->dapm;
+	struct regmap *regmap = nau8825->regmap;
+
+	/* Force to cancel the cross talk detection process */
+	nau8825_xtalk_cancel(nau8825);
+
+	snd_soc_dapm_disable_pin(dapm, "SAR");
+	snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+	/* Detach 2kOhm Resistors from MICBIAS to MICGND1/2 */
+	regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+		NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, 0);
+	/* ground HPL/HPR, MICGRND1/2 */
+	regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, 0xf, 0xf);
+
+	snd_soc_dapm_sync(dapm);
+
+	/* Clear all interruption status */
+	nau8825_int_status_clear_all(regmap);
+
+	/* Enable the insertion interruption, disable the ejection inter-
+	 * ruption, and then bypass de-bounce circuit.
+	 */
+	regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_DIS_CTRL,
+		NAU8825_IRQ_EJECT_DIS | NAU8825_IRQ_INSERT_DIS,
+		NAU8825_IRQ_EJECT_DIS);
+	regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK,
+		NAU8825_IRQ_OUTPUT_EN | NAU8825_IRQ_EJECT_EN |
+		NAU8825_IRQ_HEADSET_COMPLETE_EN | NAU8825_IRQ_INSERT_EN,
+		NAU8825_IRQ_OUTPUT_EN | NAU8825_IRQ_EJECT_EN |
+		NAU8825_IRQ_HEADSET_COMPLETE_EN);
+	regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL,
+		NAU8825_JACK_DET_DB_BYPASS, NAU8825_JACK_DET_DB_BYPASS);
+
+	/* Disable ADC needed for interruptions at audo mode */
+	regmap_update_bits(regmap, NAU8825_REG_ENA_CTRL,
+		NAU8825_ENABLE_ADC, 0);
+
+	/* Close clock for jack type detection at manual mode */
+	nau8825_configure_sysclk(nau8825, NAU8825_CLK_DIS, 0);
+}
+
+/* Enable audo mode interruptions with internal clock. */
+static void nau8825_setup_auto_irq(struct nau8825 *nau8825)
+{
+	struct regmap *regmap = nau8825->regmap;
+
+	/* Enable headset jack type detection complete interruption and
+	 * jack ejection interruption.
+	 */
+	regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK,
+		NAU8825_IRQ_HEADSET_COMPLETE_EN | NAU8825_IRQ_EJECT_EN, 0);
+
+	/* Enable internal VCO needed for interruptions */
+	nau8825_configure_sysclk(nau8825, NAU8825_CLK_INTERNAL, 0);
+
+	/* Enable ADC needed for interruptions */
+	regmap_update_bits(regmap, NAU8825_REG_ENA_CTRL,
+		NAU8825_ENABLE_ADC, NAU8825_ENABLE_ADC);
+
+	/* Chip needs one FSCLK cycle in order to generate interruptions,
+	 * as we cannot guarantee one will be provided by the system. Turning
+	 * master mode on then off enables us to generate that FSCLK cycle
+	 * with a minimum of contention on the clock bus.
+	 */
+	regmap_update_bits(regmap, NAU8825_REG_I2S_PCM_CTRL2,
+		NAU8825_I2S_MS_MASK, NAU8825_I2S_MS_MASTER);
+	regmap_update_bits(regmap, NAU8825_REG_I2S_PCM_CTRL2,
+		NAU8825_I2S_MS_MASK, NAU8825_I2S_MS_SLAVE);
+
+	/* Not bypass de-bounce circuit */
+	regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL,
+		NAU8825_JACK_DET_DB_BYPASS, 0);
+
+	/* Unmask all interruptions */
+	regmap_write(regmap, NAU8825_REG_INTERRUPT_DIS_CTRL, 0);
+
+	/* Restart the jack detection process at auto mode */
+	nau8825_restart_jack_detection(regmap);
+}
+
+static int nau8825_button_decode(int value)
+{
+	int buttons = 0;
+
+	/* The chip supports up to 8 buttons, but ALSA defines only 6 buttons */
+	if (value & BIT(0))
+		buttons |= SND_JACK_BTN_0;
+	if (value & BIT(1))
+		buttons |= SND_JACK_BTN_1;
+	if (value & BIT(2))
+		buttons |= SND_JACK_BTN_2;
+	if (value & BIT(3))
+		buttons |= SND_JACK_BTN_3;
+	if (value & BIT(4))
+		buttons |= SND_JACK_BTN_4;
+	if (value & BIT(5))
+		buttons |= SND_JACK_BTN_5;
+
+	return buttons;
+}
+
+static int nau8825_jack_insert(struct nau8825 *nau8825)
+{
+	struct regmap *regmap = nau8825->regmap;
+	struct snd_soc_dapm_context *dapm = nau8825->dapm;
+	int jack_status_reg, mic_detected;
+	int type = 0;
+
+	regmap_read(regmap, NAU8825_REG_GENERAL_STATUS, &jack_status_reg);
+	mic_detected = (jack_status_reg >> 10) & 3;
+	/* The JKSLV and JKR2 all detected in high impedance headset */
+	if (mic_detected == 0x3)
+		nau8825->high_imped = true;
+	else
+		nau8825->high_imped = false;
+
+	switch (mic_detected) {
+	case 0:
+		/* no mic */
+		type = SND_JACK_HEADPHONE;
+		break;
+	case 1:
+		dev_dbg(nau8825->dev, "OMTP (micgnd1) mic connected\n");
+		type = SND_JACK_HEADSET;
+
+		/* Unground MICGND1 */
+		regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, 3 << 2,
+			1 << 2);
+		/* Attach 2kOhm Resistor from MICBIAS to MICGND1 */
+		regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+			NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+			NAU8825_MICBIAS_JKR2);
+		/* Attach SARADC to MICGND1 */
+		regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+			NAU8825_SAR_INPUT_MASK,
+			NAU8825_SAR_INPUT_JKR2);
+
+		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+		snd_soc_dapm_force_enable_pin(dapm, "SAR");
+		snd_soc_dapm_sync(dapm);
+		break;
+	case 2:
+		dev_dbg(nau8825->dev, "CTIA (micgnd2) mic connected\n");
+		type = SND_JACK_HEADSET;
+
+		/* Unground MICGND2 */
+		regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, 3 << 2,
+			2 << 2);
+		/* Attach 2kOhm Resistor from MICBIAS to MICGND2 */
+		regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+			NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2,
+			NAU8825_MICBIAS_JKSLV);
+		/* Attach SARADC to MICGND2 */
+		regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+			NAU8825_SAR_INPUT_MASK,
+			NAU8825_SAR_INPUT_JKSLV);
+
+		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+		snd_soc_dapm_force_enable_pin(dapm, "SAR");
+		snd_soc_dapm_sync(dapm);
+		break;
+	case 3:
+		/* detect error case */
+		dev_err(nau8825->dev, "detection error; disable mic function\n");
+		type = SND_JACK_HEADPHONE;
+		break;
+	}
+
+	/* Leaving HPOL/R grounded after jack insert by default. They will be
+	 * ungrounded as part of the widget power up sequence at the beginning
+	 * of playback to reduce pop.
+	 */
+	return type;
+}
+
+#define NAU8825_BUTTONS (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
+		SND_JACK_BTN_2 | SND_JACK_BTN_3)
+
+static irqreturn_t nau8825_interrupt(int irq, void *data)
+{
+	struct nau8825 *nau8825 = (struct nau8825 *)data;
+	struct regmap *regmap = nau8825->regmap;
+	int active_irq, clear_irq = 0, event = 0, event_mask = 0;
+
+	if (regmap_read(regmap, NAU8825_REG_IRQ_STATUS, &active_irq)) {
+		dev_err(nau8825->dev, "failed to read irq status\n");
+		return IRQ_NONE;
+	}
+
+	if ((active_irq & NAU8825_JACK_EJECTION_IRQ_MASK) ==
+		NAU8825_JACK_EJECTION_DETECTED) {
+
+		nau8825_eject_jack(nau8825);
+		event_mask |= SND_JACK_HEADSET;
+		clear_irq = NAU8825_JACK_EJECTION_IRQ_MASK;
+	} else if (active_irq & NAU8825_KEY_SHORT_PRESS_IRQ) {
+		int key_status;
+
+		regmap_read(regmap, NAU8825_REG_INT_CLR_KEY_STATUS,
+			&key_status);
+
+		/* upper 8 bits of the register are for short pressed keys,
+		 * lower 8 bits - for long pressed buttons
+		 */
+		nau8825->button_pressed = nau8825_button_decode(
+			key_status >> 8);
+
+		event |= nau8825->button_pressed;
+		event_mask |= NAU8825_BUTTONS;
+		clear_irq = NAU8825_KEY_SHORT_PRESS_IRQ;
+	} else if (active_irq & NAU8825_KEY_RELEASE_IRQ) {
+		event_mask = NAU8825_BUTTONS;
+		clear_irq = NAU8825_KEY_RELEASE_IRQ;
+	} else if (active_irq & NAU8825_HEADSET_COMPLETION_IRQ) {
+		if (nau8825_is_jack_inserted(regmap)) {
+			event |= nau8825_jack_insert(nau8825);
+			if (nau8825->xtalk_enable && !nau8825->high_imped) {
+				/* Apply the cross talk suppression in the
+				 * headset without high impedance.
+				 */
+				if (!nau8825->xtalk_protect) {
+					/* Raise protection for cross talk de-
+					 * tection if no protection before.
+					 * The driver has to cancel the pro-
+					 * cess and restore changes if process
+					 * is ongoing when ejection.
+					 */
+					int ret;
+					nau8825->xtalk_protect = true;
+					ret = nau8825_sema_acquire(nau8825, 0);
+					if (ret)
+						nau8825->xtalk_protect = false;
+				}
+				/* Startup cross talk detection process */
+				if (nau8825->xtalk_protect) {
+					nau8825->xtalk_state =
+						NAU8825_XTALK_PREPARE;
+					schedule_work(&nau8825->xtalk_work);
+				}
+			} else {
+				/* The cross talk suppression shouldn't apply
+				 * in the headset with high impedance. Thus,
+				 * relieve the protection raised before.
+				 */
+				if (nau8825->xtalk_protect) {
+					nau8825_sema_release(nau8825);
+					nau8825->xtalk_protect = false;
+				}
+			}
+		} else {
+			dev_warn(nau8825->dev, "Headset completion IRQ fired but no headset connected\n");
+			nau8825_eject_jack(nau8825);
+		}
+
+		event_mask |= SND_JACK_HEADSET;
+		clear_irq = NAU8825_HEADSET_COMPLETION_IRQ;
+		/* Record the interruption report event for driver to report
+		 * the event later. The jack report will delay until cross
+		 * talk detection process is done.
+		 */
+		if (nau8825->xtalk_state == NAU8825_XTALK_PREPARE) {
+			nau8825->xtalk_event = event;
+			nau8825->xtalk_event_mask = event_mask;
+		}
+	} else if (active_irq & NAU8825_IMPEDANCE_MEAS_IRQ) {
+		/* crosstalk detection enable and process on going */
+		if (nau8825->xtalk_enable && nau8825->xtalk_protect)
+			schedule_work(&nau8825->xtalk_work);
+		clear_irq = NAU8825_IMPEDANCE_MEAS_IRQ;
+	} else if ((active_irq & NAU8825_JACK_INSERTION_IRQ_MASK) ==
+		NAU8825_JACK_INSERTION_DETECTED) {
+		/* One more step to check GPIO status directly. Thus, the
+		 * driver can confirm the real insertion interruption because
+		 * the intrruption at manual mode has bypassed debounce
+		 * circuit which can get rid of unstable status.
+		 */
+		if (nau8825_is_jack_inserted(regmap)) {
+			/* Turn off insertion interruption at manual mode */
+			regmap_update_bits(regmap,
+				NAU8825_REG_INTERRUPT_DIS_CTRL,
+				NAU8825_IRQ_INSERT_DIS,
+				NAU8825_IRQ_INSERT_DIS);
+			regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK,
+				NAU8825_IRQ_INSERT_EN, NAU8825_IRQ_INSERT_EN);
+			/* Enable interruption for jack type detection at audo
+			 * mode which can detect microphone and jack type.
+			 */
+			nau8825_setup_auto_irq(nau8825);
+		}
+	}
+
+	if (!clear_irq)
+		clear_irq = active_irq;
+	/* clears the rightmost interruption */
+	regmap_write(regmap, NAU8825_REG_INT_CLR_KEY_STATUS, clear_irq);
+
+	/* Delay jack report until cross talk detection is done. It can avoid
+	 * application to do playback preparation when cross talk detection
+	 * process is still working. Otherwise, the resource like clock and
+	 * power will be issued by them at the same time and conflict happens.
+	 */
+	if (event_mask && nau8825->xtalk_state == NAU8825_XTALK_DONE)
+		snd_soc_jack_report(nau8825->jack, event, event_mask);
+
+	return IRQ_HANDLED;
+}
+
+static void nau8825_setup_buttons(struct nau8825 *nau8825)
+{
+	struct regmap *regmap = nau8825->regmap;
+
+	regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+		NAU8825_SAR_TRACKING_GAIN_MASK,
+		nau8825->sar_voltage << NAU8825_SAR_TRACKING_GAIN_SFT);
+	regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+		NAU8825_SAR_COMPARE_TIME_MASK,
+		nau8825->sar_compare_time << NAU8825_SAR_COMPARE_TIME_SFT);
+	regmap_update_bits(regmap, NAU8825_REG_SAR_CTRL,
+		NAU8825_SAR_SAMPLING_TIME_MASK,
+		nau8825->sar_sampling_time << NAU8825_SAR_SAMPLING_TIME_SFT);
+
+	regmap_update_bits(regmap, NAU8825_REG_KEYDET_CTRL,
+		NAU8825_KEYDET_LEVELS_NR_MASK,
+		(nau8825->sar_threshold_num - 1) << NAU8825_KEYDET_LEVELS_NR_SFT);
+	regmap_update_bits(regmap, NAU8825_REG_KEYDET_CTRL,
+		NAU8825_KEYDET_HYSTERESIS_MASK,
+		nau8825->sar_hysteresis << NAU8825_KEYDET_HYSTERESIS_SFT);
+	regmap_update_bits(regmap, NAU8825_REG_KEYDET_CTRL,
+		NAU8825_KEYDET_SHORTKEY_DEBOUNCE_MASK,
+		nau8825->key_debounce << NAU8825_KEYDET_SHORTKEY_DEBOUNCE_SFT);
+
+	regmap_write(regmap, NAU8825_REG_VDET_THRESHOLD_1,
+		(nau8825->sar_threshold[0] << 8) | nau8825->sar_threshold[1]);
+	regmap_write(regmap, NAU8825_REG_VDET_THRESHOLD_2,
+		(nau8825->sar_threshold[2] << 8) | nau8825->sar_threshold[3]);
+	regmap_write(regmap, NAU8825_REG_VDET_THRESHOLD_3,
+		(nau8825->sar_threshold[4] << 8) | nau8825->sar_threshold[5]);
+	regmap_write(regmap, NAU8825_REG_VDET_THRESHOLD_4,
+		(nau8825->sar_threshold[6] << 8) | nau8825->sar_threshold[7]);
+
+	/* Enable short press and release interruptions */
+	regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK,
+		NAU8825_IRQ_KEY_SHORT_PRESS_EN | NAU8825_IRQ_KEY_RELEASE_EN,
+		0);
+}
+
+static void nau8825_init_regs(struct nau8825 *nau8825)
+{
+	struct regmap *regmap = nau8825->regmap;
+
+	/* Latch IIC LSB value */
+	regmap_write(regmap, NAU8825_REG_IIC_ADDR_SET, 0x0001);
+	/* Enable Bias/Vmid */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+		NAU8825_BIAS_VMID, NAU8825_BIAS_VMID);
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_BOOST,
+		NAU8825_GLOBAL_BIAS_EN, NAU8825_GLOBAL_BIAS_EN);
+
+	/* VMID Tieoff */
+	regmap_update_bits(regmap, NAU8825_REG_BIAS_ADJ,
+		NAU8825_BIAS_VMID_SEL_MASK,
+		nau8825->vref_impedance << NAU8825_BIAS_VMID_SEL_SFT);
+	/* Disable Boost Driver, Automatic Short circuit protection enable */
+	regmap_update_bits(regmap, NAU8825_REG_BOOST,
+		NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_DIS |
+		NAU8825_HP_BOOST_G_DIS | NAU8825_SHORT_SHUTDOWN_EN,
+		NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_DIS |
+		NAU8825_HP_BOOST_G_DIS | NAU8825_SHORT_SHUTDOWN_EN);
+
+	regmap_update_bits(regmap, NAU8825_REG_GPIO12_CTRL,
+		NAU8825_JKDET_OUTPUT_EN,
+		nau8825->jkdet_enable ? 0 : NAU8825_JKDET_OUTPUT_EN);
+	regmap_update_bits(regmap, NAU8825_REG_GPIO12_CTRL,
+		NAU8825_JKDET_PULL_EN,
+		nau8825->jkdet_pull_enable ? 0 : NAU8825_JKDET_PULL_EN);
+	regmap_update_bits(regmap, NAU8825_REG_GPIO12_CTRL,
+		NAU8825_JKDET_PULL_UP,
+		nau8825->jkdet_pull_up ? NAU8825_JKDET_PULL_UP : 0);
+	regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL,
+		NAU8825_JACK_POLARITY,
+		/* jkdet_polarity - 1  is for active-low */
+		nau8825->jkdet_polarity ? 0 : NAU8825_JACK_POLARITY);
+
+	regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL,
+		NAU8825_JACK_INSERT_DEBOUNCE_MASK,
+		nau8825->jack_insert_debounce << NAU8825_JACK_INSERT_DEBOUNCE_SFT);
+	regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL,
+		NAU8825_JACK_EJECT_DEBOUNCE_MASK,
+		nau8825->jack_eject_debounce << NAU8825_JACK_EJECT_DEBOUNCE_SFT);
+
+	/* Mask unneeded IRQs: 1 - disable, 0 - enable */
+	regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK, 0x7ff, 0x7ff);
+
+	regmap_update_bits(regmap, NAU8825_REG_MIC_BIAS,
+		NAU8825_MICBIAS_VOLTAGE_MASK, nau8825->micbias_voltage);
+
+	if (nau8825->sar_threshold_num)
+		nau8825_setup_buttons(nau8825);
+
+	/* Default oversampling/decimations settings are unusable
+	 * (audible hiss). Set it to something better.
+	 */
+	regmap_update_bits(regmap, NAU8825_REG_ADC_RATE,
+		NAU8825_ADC_SYNC_DOWN_MASK | NAU8825_ADC_SINC4_EN,
+		NAU8825_ADC_SYNC_DOWN_64);
+	regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1,
+		NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_64);
+	/* Disable DACR/L power */
+	regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP,
+		NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
+		NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
+	/* Enable TESTDAC. This sets the analog DAC inputs to a '0' input
+	 * signal to avoid any glitches due to power up transients in both
+	 * the analog and digital DAC circuit.
+	 */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+		NAU8825_BIAS_TESTDAC_EN, NAU8825_BIAS_TESTDAC_EN);
+	/* CICCLP off */
+	regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1,
+		NAU8825_DAC_CLIP_OFF, NAU8825_DAC_CLIP_OFF);
+
+	/* Class AB bias current to 2x, DAC Capacitor enable MSB/LSB */
+	regmap_update_bits(regmap, NAU8825_REG_ANALOG_CONTROL_2,
+		NAU8825_HP_NON_CLASSG_CURRENT_2xADJ |
+		NAU8825_DAC_CAPACITOR_MSB | NAU8825_DAC_CAPACITOR_LSB,
+		NAU8825_HP_NON_CLASSG_CURRENT_2xADJ |
+		NAU8825_DAC_CAPACITOR_MSB | NAU8825_DAC_CAPACITOR_LSB);
+	/* Class G timer 64ms */
+	regmap_update_bits(regmap, NAU8825_REG_CLASSG_CTRL,
+		NAU8825_CLASSG_TIMER_MASK,
+		0x20 << NAU8825_CLASSG_TIMER_SFT);
+	/* DAC clock delay 2ns, VREF */
+	regmap_update_bits(regmap, NAU8825_REG_RDAC,
+		NAU8825_RDAC_CLK_DELAY_MASK | NAU8825_RDAC_VREF_MASK,
+		(0x2 << NAU8825_RDAC_CLK_DELAY_SFT) |
+		(0x3 << NAU8825_RDAC_VREF_SFT));
+	/* Config L/R channel */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_DACL_CTRL,
+		NAU8825_DACL_CH_SEL_MASK, NAU8825_DACL_CH_SEL_L);
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_DACR_CTRL,
+		NAU8825_DACL_CH_SEL_MASK, NAU8825_DACL_CH_SEL_R);
+	/* Disable short Frame Sync detection logic */
+	regmap_update_bits(regmap, NAU8825_REG_LEFT_TIME_SLOT,
+		NAU8825_DIS_FS_SHORT_DET, NAU8825_DIS_FS_SHORT_DET);
+}
+
+static const struct regmap_config nau8825_regmap_config = {
+	.val_bits = NAU8825_REG_DATA_LEN,
+	.reg_bits = NAU8825_REG_ADDR_LEN,
+
+	.max_register = NAU8825_REG_MAX,
+	.readable_reg = nau8825_readable_reg,
+	.writeable_reg = nau8825_writeable_reg,
+	.volatile_reg = nau8825_volatile_reg,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = nau8825_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(nau8825_reg_defaults),
+};
+
+static int nau8825_component_probe(struct snd_soc_component *component)
+{
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	nau8825->dapm = dapm;
+
+	return 0;
+}
+
+static void nau8825_component_remove(struct snd_soc_component *component)
+{
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+
+	/* Cancel and reset cross tak suppresstion detection funciton */
+	nau8825_xtalk_cancel(nau8825);
+}
+
+/**
+ * nau8825_calc_fll_param - Calculate FLL parameters.
+ * @fll_in: external clock provided to codec.
+ * @fs: sampling rate.
+ * @fll_param: Pointer to structure of FLL parameters.
+ *
+ * Calculate FLL parameters to configure codec.
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs,
+		struct nau8825_fll *fll_param)
+{
+	u64 fvco, fvco_max;
+	unsigned int fref, i, fvco_sel;
+
+	/* Ensure the reference clock frequency (FREF) is <= 13.5MHz by dividing
+	 * freq_in by 1, 2, 4, or 8 using FLL pre-scalar.
+	 * FREF = freq_in / NAU8825_FLL_REF_DIV_MASK
+	 */
+	for (i = 0; i < ARRAY_SIZE(fll_pre_scalar); i++) {
+		fref = fll_in / fll_pre_scalar[i].param;
+		if (fref <= NAU_FREF_MAX)
+			break;
+	}
+	if (i == ARRAY_SIZE(fll_pre_scalar))
+		return -EINVAL;
+	fll_param->clk_ref_div = fll_pre_scalar[i].val;
+
+	/* Choose the FLL ratio based on FREF */
+	for (i = 0; i < ARRAY_SIZE(fll_ratio); i++) {
+		if (fref >= fll_ratio[i].param)
+			break;
+	}
+	if (i == ARRAY_SIZE(fll_ratio))
+		return -EINVAL;
+	fll_param->ratio = fll_ratio[i].val;
+
+	/* Calculate the frequency of DCO (FDCO) given freq_out = 256 * Fs.
+	 * FDCO must be within the 90MHz - 124MHz or the FFL cannot be
+	 * guaranteed across the full range of operation.
+	 * FDCO = freq_out * 2 * mclk_src_scaling
+	 */
+	fvco_max = 0;
+	fvco_sel = ARRAY_SIZE(mclk_src_scaling);
+	for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) {
+		fvco = 256ULL * fs * 2 * mclk_src_scaling[i].param;
+		if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX &&
+			fvco_max < fvco) {
+			fvco_max = fvco;
+			fvco_sel = i;
+		}
+	}
+	if (ARRAY_SIZE(mclk_src_scaling) == fvco_sel)
+		return -EINVAL;
+	fll_param->mclk_src = mclk_src_scaling[fvco_sel].val;
+
+	/* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional
+	 * input based on FDCO, FREF and FLL ratio.
+	 */
+	fvco = div_u64(fvco_max << 16, fref * fll_param->ratio);
+	fll_param->fll_int = (fvco >> 16) & 0x3FF;
+	fll_param->fll_frac = fvco & 0xFFFF;
+	return 0;
+}
+
+static void nau8825_fll_apply(struct nau8825 *nau8825,
+		struct nau8825_fll *fll_param)
+{
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
+		NAU8825_CLK_SRC_MASK | NAU8825_CLK_MCLK_SRC_MASK,
+		NAU8825_CLK_SRC_MCLK | fll_param->mclk_src);
+	/* Make DSP operate at high speed for better performance. */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL1,
+		NAU8825_FLL_RATIO_MASK | NAU8825_ICTRL_LATCH_MASK,
+		fll_param->ratio | (0x6 << NAU8825_ICTRL_LATCH_SFT));
+	/* FLL 16-bit fractional input */
+	regmap_write(nau8825->regmap, NAU8825_REG_FLL2, fll_param->fll_frac);
+	/* FLL 10-bit integer input */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL3,
+			NAU8825_FLL_INTEGER_MASK, fll_param->fll_int);
+	/* FLL pre-scaler */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL4,
+			NAU8825_FLL_REF_DIV_MASK,
+			fll_param->clk_ref_div << NAU8825_FLL_REF_DIV_SFT);
+	/* select divided VCO input */
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5,
+		NAU8825_FLL_CLK_SW_MASK, NAU8825_FLL_CLK_SW_REF);
+	/* Disable free-running mode */
+	regmap_update_bits(nau8825->regmap,
+		NAU8825_REG_FLL6, NAU8825_DCO_EN, 0);
+	if (fll_param->fll_frac) {
+		/* set FLL loop filter enable and cutoff frequency at 500Khz */
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5,
+			NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN |
+			NAU8825_FLL_FTR_SW_MASK,
+			NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN |
+			NAU8825_FLL_FTR_SW_FILTER);
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6,
+			NAU8825_SDM_EN | NAU8825_CUTOFF500,
+			NAU8825_SDM_EN | NAU8825_CUTOFF500);
+	} else {
+		/* disable FLL loop filter and cutoff frequency */
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5,
+			NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN |
+			NAU8825_FLL_FTR_SW_MASK, NAU8825_FLL_FTR_SW_ACCU);
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6,
+			NAU8825_SDM_EN | NAU8825_CUTOFF500, 0);
+	}
+}
+
+/* freq_out must be 256*Fs in order to achieve the best performance */
+static int nau8825_set_pll(struct snd_soc_component *component, int pll_id, int source,
+		unsigned int freq_in, unsigned int freq_out)
+{
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+	struct nau8825_fll fll_param;
+	int ret, fs;
+
+	fs = freq_out / 256;
+	ret = nau8825_calc_fll_param(freq_in, fs, &fll_param);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupported input clock %d\n", freq_in);
+		return ret;
+	}
+	dev_dbg(component->dev, "mclk_src=%x ratio=%x fll_frac=%x fll_int=%x clk_ref_div=%x\n",
+		fll_param.mclk_src, fll_param.ratio, fll_param.fll_frac,
+		fll_param.fll_int, fll_param.clk_ref_div);
+
+	nau8825_fll_apply(nau8825, &fll_param);
+	mdelay(2);
+	regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
+			NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_VCO);
+	return 0;
+}
+
+static int nau8825_mclk_prepare(struct nau8825 *nau8825, unsigned int freq)
+{
+	int ret = 0;
+
+	nau8825->mclk = devm_clk_get(nau8825->dev, "mclk");
+	if (IS_ERR(nau8825->mclk)) {
+		dev_info(nau8825->dev, "No 'mclk' clock found, assume MCLK is managed externally");
+		return 0;
+	}
+
+	if (!nau8825->mclk_freq) {
+		ret = clk_prepare_enable(nau8825->mclk);
+		if (ret) {
+			dev_err(nau8825->dev, "Unable to prepare codec mclk\n");
+			return ret;
+		}
+	}
+
+	if (nau8825->mclk_freq != freq) {
+		freq = clk_round_rate(nau8825->mclk, freq);
+		ret = clk_set_rate(nau8825->mclk, freq);
+		if (ret) {
+			dev_err(nau8825->dev, "Unable to set mclk rate\n");
+			return ret;
+		}
+		nau8825->mclk_freq = freq;
+	}
+
+	return 0;
+}
+
+static void nau8825_configure_mclk_as_sysclk(struct regmap *regmap)
+{
+	regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
+		NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_MCLK);
+	regmap_update_bits(regmap, NAU8825_REG_FLL6,
+		NAU8825_DCO_EN, 0);
+	/* Make DSP operate as default setting for power saving. */
+	regmap_update_bits(regmap, NAU8825_REG_FLL1,
+		NAU8825_ICTRL_LATCH_MASK, 0);
+}
+
+static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
+	unsigned int freq)
+{
+	struct regmap *regmap = nau8825->regmap;
+	int ret;
+
+	switch (clk_id) {
+	case NAU8825_CLK_DIS:
+		/* Clock provided externally and disable internal VCO clock */
+		nau8825_configure_mclk_as_sysclk(regmap);
+		if (nau8825->mclk_freq) {
+			clk_disable_unprepare(nau8825->mclk);
+			nau8825->mclk_freq = 0;
+		}
+
+		break;
+	case NAU8825_CLK_MCLK:
+		/* Acquire the semaphore to synchronize the playback and
+		 * interrupt handler. In order to avoid the playback inter-
+		 * fered by cross talk process, the driver make the playback
+		 * preparation halted until cross talk process finish.
+		 */
+		nau8825_sema_acquire(nau8825, 3 * HZ);
+		nau8825_configure_mclk_as_sysclk(regmap);
+		/* MCLK not changed by clock tree */
+		regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
+			NAU8825_CLK_MCLK_SRC_MASK, 0);
+		/* Release the semaphore. */
+		nau8825_sema_release(nau8825);
+
+		ret = nau8825_mclk_prepare(nau8825, freq);
+		if (ret)
+			return ret;
+
+		break;
+	case NAU8825_CLK_INTERNAL:
+		if (nau8825_is_jack_inserted(nau8825->regmap)) {
+			regmap_update_bits(regmap, NAU8825_REG_FLL6,
+				NAU8825_DCO_EN, NAU8825_DCO_EN);
+			regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
+				NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_VCO);
+			/* Decrease the VCO frequency and make DSP operate
+			 * as default setting for power saving.
+			 */
+			regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
+				NAU8825_CLK_MCLK_SRC_MASK, 0xf);
+			regmap_update_bits(regmap, NAU8825_REG_FLL1,
+				NAU8825_ICTRL_LATCH_MASK |
+				NAU8825_FLL_RATIO_MASK, 0x10);
+			regmap_update_bits(regmap, NAU8825_REG_FLL6,
+				NAU8825_SDM_EN, NAU8825_SDM_EN);
+		} else {
+			/* The clock turns off intentionally for power saving
+			 * when no headset connected.
+			 */
+			nau8825_configure_mclk_as_sysclk(regmap);
+			dev_warn(nau8825->dev, "Disable clock for power saving when no headset connected\n");
+		}
+		if (nau8825->mclk_freq) {
+			clk_disable_unprepare(nau8825->mclk);
+			nau8825->mclk_freq = 0;
+		}
+
+		break;
+	case NAU8825_CLK_FLL_MCLK:
+		/* Acquire the semaphore to synchronize the playback and
+		 * interrupt handler. In order to avoid the playback inter-
+		 * fered by cross talk process, the driver make the playback
+		 * preparation halted until cross talk process finish.
+		 */
+		nau8825_sema_acquire(nau8825, 3 * HZ);
+		/* Higher FLL reference input frequency can only set lower
+		 * gain error, such as 0000 for input reference from MCLK
+		 * 12.288Mhz.
+		 */
+		regmap_update_bits(regmap, NAU8825_REG_FLL3,
+			NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
+			NAU8825_FLL_CLK_SRC_MCLK | 0);
+		/* Release the semaphore. */
+		nau8825_sema_release(nau8825);
+
+		ret = nau8825_mclk_prepare(nau8825, freq);
+		if (ret)
+			return ret;
+
+		break;
+	case NAU8825_CLK_FLL_BLK:
+		/* Acquire the semaphore to synchronize the playback and
+		 * interrupt handler. In order to avoid the playback inter-
+		 * fered by cross talk process, the driver make the playback
+		 * preparation halted until cross talk process finish.
+		 */
+		nau8825_sema_acquire(nau8825, 3 * HZ);
+		/* If FLL reference input is from low frequency source,
+		 * higher error gain can apply such as 0xf which has
+		 * the most sensitive gain error correction threshold,
+		 * Therefore, FLL has the most accurate DCO to
+		 * target frequency.
+		 */
+		regmap_update_bits(regmap, NAU8825_REG_FLL3,
+			NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
+			NAU8825_FLL_CLK_SRC_BLK |
+			(0xf << NAU8825_GAIN_ERR_SFT));
+		/* Release the semaphore. */
+		nau8825_sema_release(nau8825);
+
+		if (nau8825->mclk_freq) {
+			clk_disable_unprepare(nau8825->mclk);
+			nau8825->mclk_freq = 0;
+		}
+
+		break;
+	case NAU8825_CLK_FLL_FS:
+		/* Acquire the semaphore to synchronize the playback and
+		 * interrupt handler. In order to avoid the playback inter-
+		 * fered by cross talk process, the driver make the playback
+		 * preparation halted until cross talk process finish.
+		 */
+		nau8825_sema_acquire(nau8825, 3 * HZ);
+		/* If FLL reference input is from low frequency source,
+		 * higher error gain can apply such as 0xf which has
+		 * the most sensitive gain error correction threshold,
+		 * Therefore, FLL has the most accurate DCO to
+		 * target frequency.
+		 */
+		regmap_update_bits(regmap, NAU8825_REG_FLL3,
+			NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
+			NAU8825_FLL_CLK_SRC_FS |
+			(0xf << NAU8825_GAIN_ERR_SFT));
+		/* Release the semaphore. */
+		nau8825_sema_release(nau8825);
+
+		if (nau8825->mclk_freq) {
+			clk_disable_unprepare(nau8825->mclk);
+			nau8825->mclk_freq = 0;
+		}
+
+		break;
+	default:
+		dev_err(nau8825->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+
+	dev_dbg(nau8825->dev, "Sysclk is %dHz and clock id is %d\n", freq,
+		clk_id);
+	return 0;
+}
+
+static int nau8825_set_sysclk(struct snd_soc_component *component, int clk_id,
+	int source, unsigned int freq, int dir)
+{
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+
+	return nau8825_configure_sysclk(nau8825, clk_id, freq);
+}
+
+static int nau8825_resume_setup(struct nau8825 *nau8825)
+{
+	struct regmap *regmap = nau8825->regmap;
+
+	/* Close clock when jack type detection at manual mode */
+	nau8825_configure_sysclk(nau8825, NAU8825_CLK_DIS, 0);
+
+	/* Clear all interruption status */
+	nau8825_int_status_clear_all(regmap);
+
+	/* Enable both insertion and ejection interruptions, and then
+	 * bypass de-bounce circuit.
+	 */
+	regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK,
+		NAU8825_IRQ_OUTPUT_EN | NAU8825_IRQ_HEADSET_COMPLETE_EN |
+		NAU8825_IRQ_EJECT_EN | NAU8825_IRQ_INSERT_EN,
+		NAU8825_IRQ_OUTPUT_EN | NAU8825_IRQ_HEADSET_COMPLETE_EN);
+	regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL,
+		NAU8825_JACK_DET_DB_BYPASS, NAU8825_JACK_DET_DB_BYPASS);
+	regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_DIS_CTRL,
+		NAU8825_IRQ_INSERT_DIS | NAU8825_IRQ_EJECT_DIS, 0);
+
+	return 0;
+}
+
+static int nau8825_set_bias_level(struct snd_soc_component *component,
+				   enum snd_soc_bias_level level)
+{
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			if (nau8825->mclk_freq) {
+				ret = clk_prepare_enable(nau8825->mclk);
+				if (ret) {
+					dev_err(nau8825->dev, "Unable to prepare component mclk\n");
+					return ret;
+				}
+			}
+			/* Setup codec configuration after resume */
+			nau8825_resume_setup(nau8825);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* Reset the configuration of jack type for detection */
+		/* Detach 2kOhm Resistors from MICBIAS to MICGND1/2 */
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_MIC_BIAS,
+			NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, 0);
+		/* ground HPL/HPR, MICGRND1/2 */
+		regmap_update_bits(nau8825->regmap,
+			NAU8825_REG_HSD_CTRL, 0xf, 0xf);
+		/* Cancel and reset cross talk detection funciton */
+		nau8825_xtalk_cancel(nau8825);
+		/* Turn off all interruptions before system shutdown. Keep the
+		 * interruption quiet before resume setup completes.
+		 */
+		regmap_write(nau8825->regmap,
+			NAU8825_REG_INTERRUPT_DIS_CTRL, 0xffff);
+		/* Disable ADC needed for interruptions at audo mode */
+		regmap_update_bits(nau8825->regmap, NAU8825_REG_ENA_CTRL,
+			NAU8825_ENABLE_ADC, 0);
+		if (nau8825->mclk_freq)
+			clk_disable_unprepare(nau8825->mclk);
+		break;
+	}
+	return 0;
+}
+
+static int __maybe_unused nau8825_suspend(struct snd_soc_component *component)
+{
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+
+	disable_irq(nau8825->irq);
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+	/* Power down codec power; don't suppoet button wakeup */
+	snd_soc_dapm_disable_pin(nau8825->dapm, "SAR");
+	snd_soc_dapm_disable_pin(nau8825->dapm, "MICBIAS");
+	snd_soc_dapm_sync(nau8825->dapm);
+	regcache_cache_only(nau8825->regmap, true);
+	regcache_mark_dirty(nau8825->regmap);
+
+	return 0;
+}
+
+static int __maybe_unused nau8825_resume(struct snd_soc_component *component)
+{
+	struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	regcache_cache_only(nau8825->regmap, false);
+	regcache_sync(nau8825->regmap);
+	nau8825->xtalk_protect = true;
+	ret = nau8825_sema_acquire(nau8825, 0);
+	if (ret)
+		nau8825->xtalk_protect = false;
+	enable_irq(nau8825->irq);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver nau8825_component_driver = {
+	.probe			= nau8825_component_probe,
+	.remove			= nau8825_component_remove,
+	.set_sysclk		= nau8825_set_sysclk,
+	.set_pll		= nau8825_set_pll,
+	.set_bias_level		= nau8825_set_bias_level,
+	.suspend		= nau8825_suspend,
+	.resume			= nau8825_resume,
+	.controls		= nau8825_controls,
+	.num_controls		= ARRAY_SIZE(nau8825_controls),
+	.dapm_widgets		= nau8825_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(nau8825_dapm_widgets),
+	.dapm_routes		= nau8825_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(nau8825_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static void nau8825_reset_chip(struct regmap *regmap)
+{
+	regmap_write(regmap, NAU8825_REG_RESET, 0x00);
+	regmap_write(regmap, NAU8825_REG_RESET, 0x00);
+}
+
+static void nau8825_print_device_properties(struct nau8825 *nau8825)
+{
+	int i;
+	struct device *dev = nau8825->dev;
+
+	dev_dbg(dev, "jkdet-enable:         %d\n", nau8825->jkdet_enable);
+	dev_dbg(dev, "jkdet-pull-enable:    %d\n", nau8825->jkdet_pull_enable);
+	dev_dbg(dev, "jkdet-pull-up:        %d\n", nau8825->jkdet_pull_up);
+	dev_dbg(dev, "jkdet-polarity:       %d\n", nau8825->jkdet_polarity);
+	dev_dbg(dev, "micbias-voltage:      %d\n", nau8825->micbias_voltage);
+	dev_dbg(dev, "vref-impedance:       %d\n", nau8825->vref_impedance);
+
+	dev_dbg(dev, "sar-threshold-num:    %d\n", nau8825->sar_threshold_num);
+	for (i = 0; i < nau8825->sar_threshold_num; i++)
+		dev_dbg(dev, "sar-threshold[%d]=%d\n", i,
+				nau8825->sar_threshold[i]);
+
+	dev_dbg(dev, "sar-hysteresis:       %d\n", nau8825->sar_hysteresis);
+	dev_dbg(dev, "sar-voltage:          %d\n", nau8825->sar_voltage);
+	dev_dbg(dev, "sar-compare-time:     %d\n", nau8825->sar_compare_time);
+	dev_dbg(dev, "sar-sampling-time:    %d\n", nau8825->sar_sampling_time);
+	dev_dbg(dev, "short-key-debounce:   %d\n", nau8825->key_debounce);
+	dev_dbg(dev, "jack-insert-debounce: %d\n",
+			nau8825->jack_insert_debounce);
+	dev_dbg(dev, "jack-eject-debounce:  %d\n",
+			nau8825->jack_eject_debounce);
+	dev_dbg(dev, "crosstalk-enable:     %d\n",
+			nau8825->xtalk_enable);
+}
+
+static int nau8825_read_device_properties(struct device *dev,
+	struct nau8825 *nau8825) {
+	int ret;
+
+	nau8825->jkdet_enable = device_property_read_bool(dev,
+		"nuvoton,jkdet-enable");
+	nau8825->jkdet_pull_enable = device_property_read_bool(dev,
+		"nuvoton,jkdet-pull-enable");
+	nau8825->jkdet_pull_up = device_property_read_bool(dev,
+		"nuvoton,jkdet-pull-up");
+	ret = device_property_read_u32(dev, "nuvoton,jkdet-polarity",
+		&nau8825->jkdet_polarity);
+	if (ret)
+		nau8825->jkdet_polarity = 1;
+	ret = device_property_read_u32(dev, "nuvoton,micbias-voltage",
+		&nau8825->micbias_voltage);
+	if (ret)
+		nau8825->micbias_voltage = 6;
+	ret = device_property_read_u32(dev, "nuvoton,vref-impedance",
+		&nau8825->vref_impedance);
+	if (ret)
+		nau8825->vref_impedance = 2;
+	ret = device_property_read_u32(dev, "nuvoton,sar-threshold-num",
+		&nau8825->sar_threshold_num);
+	if (ret)
+		nau8825->sar_threshold_num = 4;
+	ret = device_property_read_u32_array(dev, "nuvoton,sar-threshold",
+		nau8825->sar_threshold, nau8825->sar_threshold_num);
+	if (ret) {
+		nau8825->sar_threshold[0] = 0x08;
+		nau8825->sar_threshold[1] = 0x12;
+		nau8825->sar_threshold[2] = 0x26;
+		nau8825->sar_threshold[3] = 0x73;
+	}
+	ret = device_property_read_u32(dev, "nuvoton,sar-hysteresis",
+		&nau8825->sar_hysteresis);
+	if (ret)
+		nau8825->sar_hysteresis = 0;
+	ret = device_property_read_u32(dev, "nuvoton,sar-voltage",
+		&nau8825->sar_voltage);
+	if (ret)
+		nau8825->sar_voltage = 6;
+	ret = device_property_read_u32(dev, "nuvoton,sar-compare-time",
+		&nau8825->sar_compare_time);
+	if (ret)
+		nau8825->sar_compare_time = 1;
+	ret = device_property_read_u32(dev, "nuvoton,sar-sampling-time",
+		&nau8825->sar_sampling_time);
+	if (ret)
+		nau8825->sar_sampling_time = 1;
+	ret = device_property_read_u32(dev, "nuvoton,short-key-debounce",
+		&nau8825->key_debounce);
+	if (ret)
+		nau8825->key_debounce = 3;
+	ret = device_property_read_u32(dev, "nuvoton,jack-insert-debounce",
+		&nau8825->jack_insert_debounce);
+	if (ret)
+		nau8825->jack_insert_debounce = 7;
+	ret = device_property_read_u32(dev, "nuvoton,jack-eject-debounce",
+		&nau8825->jack_eject_debounce);
+	if (ret)
+		nau8825->jack_eject_debounce = 0;
+	nau8825->xtalk_enable = device_property_read_bool(dev,
+		"nuvoton,crosstalk-enable");
+
+	nau8825->mclk = devm_clk_get(dev, "mclk");
+	if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) {
+		return -EPROBE_DEFER;
+	} else if (PTR_ERR(nau8825->mclk) == -ENOENT) {
+		/* The MCLK is managed externally or not used at all */
+		nau8825->mclk = NULL;
+		dev_info(dev, "No 'mclk' clock found, assume MCLK is managed externally");
+	} else if (IS_ERR(nau8825->mclk)) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int nau8825_setup_irq(struct nau8825 *nau8825)
+{
+	int ret;
+
+	ret = devm_request_threaded_irq(nau8825->dev, nau8825->irq, NULL,
+		nau8825_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+		"nau8825", nau8825);
+
+	if (ret) {
+		dev_err(nau8825->dev, "Cannot request irq %d (%d)\n",
+			nau8825->irq, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int nau8825_i2c_probe(struct i2c_client *i2c,
+	const struct i2c_device_id *id)
+{
+	struct device *dev = &i2c->dev;
+	struct nau8825 *nau8825 = dev_get_platdata(&i2c->dev);
+	int ret, value;
+
+	if (!nau8825) {
+		nau8825 = devm_kzalloc(dev, sizeof(*nau8825), GFP_KERNEL);
+		if (!nau8825)
+			return -ENOMEM;
+		ret = nau8825_read_device_properties(dev, nau8825);
+		if (ret)
+			return ret;
+	}
+
+	i2c_set_clientdata(i2c, nau8825);
+
+	nau8825->regmap = devm_regmap_init_i2c(i2c, &nau8825_regmap_config);
+	if (IS_ERR(nau8825->regmap))
+		return PTR_ERR(nau8825->regmap);
+	nau8825->dev = dev;
+	nau8825->irq = i2c->irq;
+	/* Initiate parameters, semaphore and work queue which are needed in
+	 * cross talk suppression measurment function.
+	 */
+	nau8825->xtalk_state = NAU8825_XTALK_DONE;
+	nau8825->xtalk_protect = false;
+	nau8825->xtalk_baktab_initialized = false;
+	sema_init(&nau8825->xtalk_sem, 1);
+	INIT_WORK(&nau8825->xtalk_work, nau8825_xtalk_work);
+
+	nau8825_print_device_properties(nau8825);
+
+	nau8825_reset_chip(nau8825->regmap);
+	ret = regmap_read(nau8825->regmap, NAU8825_REG_I2C_DEVICE_ID, &value);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read device id from the NAU8825: %d\n",
+			ret);
+		return ret;
+	}
+	if ((value & NAU8825_SOFTWARE_ID_MASK) !=
+			NAU8825_SOFTWARE_ID_NAU8825) {
+		dev_err(dev, "Not a NAU8825 chip\n");
+		return -ENODEV;
+	}
+
+	nau8825_init_regs(nau8825);
+
+	if (i2c->irq)
+		nau8825_setup_irq(nau8825);
+
+	return devm_snd_soc_register_component(&i2c->dev,
+		&nau8825_component_driver,
+		&nau8825_dai, 1);
+}
+
+static int nau8825_i2c_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id nau8825_i2c_ids[] = {
+	{ "nau8825", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, nau8825_i2c_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id nau8825_of_ids[] = {
+	{ .compatible = "nuvoton,nau8825", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, nau8825_of_ids);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id nau8825_acpi_match[] = {
+	{ "10508825", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, nau8825_acpi_match);
+#endif
+
+static struct i2c_driver nau8825_driver = {
+	.driver = {
+		.name = "nau8825",
+		.of_match_table = of_match_ptr(nau8825_of_ids),
+		.acpi_match_table = ACPI_PTR(nau8825_acpi_match),
+	},
+	.probe = nau8825_i2c_probe,
+	.remove = nau8825_i2c_remove,
+	.id_table = nau8825_i2c_ids,
+};
+module_i2c_driver(nau8825_driver);
+
+MODULE_DESCRIPTION("ASoC nau8825 driver");
+MODULE_AUTHOR("Anatol Pomozov <anatol@chromium.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h
new file mode 100644
index 0000000..f6074c6
--- /dev/null
+++ b/sound/soc/codecs/nau8825.h
@@ -0,0 +1,487 @@
+/*
+ * NAU8825 ALSA SoC audio driver
+ *
+ * Copyright 2015 Google Inc.
+ * Author: Anatol Pomozov <anatol.pomozov@chrominium.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __NAU8825_H__
+#define __NAU8825_H__
+
+#define NAU8825_REG_RESET		0x00
+#define NAU8825_REG_ENA_CTRL		0x01
+#define NAU8825_REG_IIC_ADDR_SET		0x02
+#define NAU8825_REG_CLK_DIVIDER		0x03
+#define NAU8825_REG_FLL1		0x04
+#define NAU8825_REG_FLL2		0x05
+#define NAU8825_REG_FLL3		0x06
+#define NAU8825_REG_FLL4		0x07
+#define NAU8825_REG_FLL5		0x08
+#define NAU8825_REG_FLL6		0x09
+#define NAU8825_REG_FLL_VCO_RSV		0x0a
+#define NAU8825_REG_HSD_CTRL		0x0c
+#define NAU8825_REG_JACK_DET_CTRL		0x0d
+#define NAU8825_REG_INTERRUPT_MASK		0x0f
+#define NAU8825_REG_IRQ_STATUS		0x10
+#define NAU8825_REG_INT_CLR_KEY_STATUS		0x11
+#define NAU8825_REG_INTERRUPT_DIS_CTRL		0x12
+#define NAU8825_REG_SAR_CTRL		0x13
+#define NAU8825_REG_KEYDET_CTRL		0x14
+#define NAU8825_REG_VDET_THRESHOLD_1		0x15
+#define NAU8825_REG_VDET_THRESHOLD_2		0x16
+#define NAU8825_REG_VDET_THRESHOLD_3		0x17
+#define NAU8825_REG_VDET_THRESHOLD_4		0x18
+#define NAU8825_REG_GPIO34_CTRL		0x19
+#define NAU8825_REG_GPIO12_CTRL		0x1a
+#define NAU8825_REG_TDM_CTRL		0x1b
+#define NAU8825_REG_I2S_PCM_CTRL1		0x1c
+#define NAU8825_REG_I2S_PCM_CTRL2		0x1d
+#define NAU8825_REG_LEFT_TIME_SLOT		0x1e
+#define NAU8825_REG_RIGHT_TIME_SLOT		0x1f
+#define NAU8825_REG_BIQ_CTRL		0x20
+#define NAU8825_REG_BIQ_COF1		0x21
+#define NAU8825_REG_BIQ_COF2		0x22
+#define NAU8825_REG_BIQ_COF3		0x23
+#define NAU8825_REG_BIQ_COF4		0x24
+#define NAU8825_REG_BIQ_COF5		0x25
+#define NAU8825_REG_BIQ_COF6		0x26
+#define NAU8825_REG_BIQ_COF7		0x27
+#define NAU8825_REG_BIQ_COF8		0x28
+#define NAU8825_REG_BIQ_COF9		0x29
+#define NAU8825_REG_BIQ_COF10		0x2a
+#define NAU8825_REG_ADC_RATE		0x2b
+#define NAU8825_REG_DAC_CTRL1		0x2c
+#define NAU8825_REG_DAC_CTRL2		0x2d
+#define NAU8825_REG_DAC_DGAIN_CTRL		0x2f
+#define NAU8825_REG_ADC_DGAIN_CTRL		0x30
+#define NAU8825_REG_MUTE_CTRL		0x31
+#define NAU8825_REG_HSVOL_CTRL		0x32
+#define NAU8825_REG_DACL_CTRL		0x33
+#define NAU8825_REG_DACR_CTRL		0x34
+#define NAU8825_REG_ADC_DRC_KNEE_IP12		0x38
+#define NAU8825_REG_ADC_DRC_KNEE_IP34		0x39
+#define NAU8825_REG_ADC_DRC_SLOPES		0x3a
+#define NAU8825_REG_ADC_DRC_ATKDCY		0x3b
+#define NAU8825_REG_DAC_DRC_KNEE_IP12		0x45
+#define NAU8825_REG_DAC_DRC_KNEE_IP34		0x46
+#define NAU8825_REG_DAC_DRC_SLOPES		0x47
+#define NAU8825_REG_DAC_DRC_ATKDCY		0x48
+#define NAU8825_REG_IMM_MODE_CTRL		0x4c
+#define NAU8825_REG_IMM_RMS_L		0x4d
+#define NAU8825_REG_IMM_RMS_R		0x4e
+#define NAU8825_REG_CLASSG_CTRL		0x50
+#define NAU8825_REG_OPT_EFUSE_CTRL		0x51
+#define NAU8825_REG_MISC_CTRL		0x55
+#define NAU8825_REG_I2C_DEVICE_ID		0x58
+#define NAU8825_REG_SARDOUT_RAM_STATUS		0x59
+#define NAU8825_REG_BIAS_ADJ		0x66
+#define NAU8825_REG_TRIM_SETTINGS		0x68
+#define NAU8825_REG_ANALOG_CONTROL_1		0x69
+#define NAU8825_REG_ANALOG_CONTROL_2		0x6a
+#define NAU8825_REG_ANALOG_ADC_1		0x71
+#define NAU8825_REG_ANALOG_ADC_2		0x72
+#define NAU8825_REG_RDAC		0x73
+#define NAU8825_REG_MIC_BIAS		0x74
+#define NAU8825_REG_BOOST		0x76
+#define NAU8825_REG_FEPGA		0x77
+#define NAU8825_REG_POWER_UP_CONTROL		0x7f
+#define NAU8825_REG_CHARGE_PUMP		0x80
+#define NAU8825_REG_CHARGE_PUMP_INPUT_READ		0x81
+#define NAU8825_REG_GENERAL_STATUS		0x82
+#define NAU8825_REG_MAX		NAU8825_REG_GENERAL_STATUS
+/* 16-bit control register address, and 16-bits control register data */
+#define NAU8825_REG_ADDR_LEN		16
+#define NAU8825_REG_DATA_LEN		16
+
+/* ENA_CTRL (0x1) */
+#define NAU8825_ENABLE_DACR_SFT	10
+#define NAU8825_ENABLE_DACR	(1 << NAU8825_ENABLE_DACR_SFT)
+#define NAU8825_ENABLE_DACL_SFT	9
+#define NAU8825_ENABLE_DACL		(1 << NAU8825_ENABLE_DACL_SFT)
+#define NAU8825_ENABLE_ADC_SFT	8
+#define NAU8825_ENABLE_ADC		(1 << NAU8825_ENABLE_ADC_SFT)
+#define NAU8825_ENABLE_ADC_CLK_SFT	7
+#define NAU8825_ENABLE_ADC_CLK	(1 << NAU8825_ENABLE_ADC_CLK_SFT)
+#define NAU8825_ENABLE_DAC_CLK_SFT	6
+#define NAU8825_ENABLE_DAC_CLK	(1 << NAU8825_ENABLE_DAC_CLK_SFT)
+#define NAU8825_ENABLE_SAR_SFT	1
+
+/* CLK_DIVIDER (0x3) */
+#define NAU8825_CLK_SRC_SFT			15
+#define NAU8825_CLK_SRC_MASK			(1 << NAU8825_CLK_SRC_SFT)
+#define NAU8825_CLK_SRC_VCO			(1 << NAU8825_CLK_SRC_SFT)
+#define NAU8825_CLK_SRC_MCLK			(0 << NAU8825_CLK_SRC_SFT)
+#define NAU8825_CLK_ADC_SRC_SFT		6
+#define NAU8825_CLK_ADC_SRC_MASK		(0x3 << NAU8825_CLK_ADC_SRC_SFT)
+#define NAU8825_CLK_DAC_SRC_SFT		4
+#define NAU8825_CLK_DAC_SRC_MASK		(0x3 << NAU8825_CLK_DAC_SRC_SFT)
+#define NAU8825_CLK_MCLK_SRC_MASK		(0xf << 0)
+
+/* FLL1 (0x04) */
+#define NAU8825_ICTRL_LATCH_SFT	10
+#define NAU8825_ICTRL_LATCH_MASK	(0x7 << NAU8825_ICTRL_LATCH_SFT)
+#define NAU8825_FLL_RATIO_MASK			(0x7f << 0)
+
+/* FLL3 (0x06) */
+#define NAU8825_GAIN_ERR_SFT			12
+#define NAU8825_GAIN_ERR_MASK			(0xf << NAU8825_GAIN_ERR_SFT)
+#define NAU8825_FLL_INTEGER_MASK		(0x3ff << 0)
+#define NAU8825_FLL_CLK_SRC_SFT		10
+#define NAU8825_FLL_CLK_SRC_MASK		(0x3 << NAU8825_FLL_CLK_SRC_SFT)
+#define NAU8825_FLL_CLK_SRC_MCLK		(0 << NAU8825_FLL_CLK_SRC_SFT)
+#define NAU8825_FLL_CLK_SRC_BLK		(0x2 << NAU8825_FLL_CLK_SRC_SFT)
+#define NAU8825_FLL_CLK_SRC_FS			(0x3 << NAU8825_FLL_CLK_SRC_SFT)
+
+/* FLL4 (0x07) */
+#define NAU8825_FLL_REF_DIV_SFT	10
+#define NAU8825_FLL_REF_DIV_MASK	(0x3 << NAU8825_FLL_REF_DIV_SFT)
+
+/* FLL5 (0x08) */
+#define NAU8825_FLL_PDB_DAC_EN		(0x1 << 15)
+#define NAU8825_FLL_LOOP_FTR_EN		(0x1 << 14)
+#define NAU8825_FLL_CLK_SW_MASK		(0x1 << 13)
+#define NAU8825_FLL_CLK_SW_N2			(0x1 << 13)
+#define NAU8825_FLL_CLK_SW_REF		(0x0 << 13)
+#define NAU8825_FLL_FTR_SW_MASK		(0x1 << 12)
+#define NAU8825_FLL_FTR_SW_ACCU		(0x1 << 12)
+#define NAU8825_FLL_FTR_SW_FILTER		(0x0 << 12)
+
+/* FLL6 (0x9) */
+#define NAU8825_DCO_EN				(0x1 << 15)
+#define NAU8825_SDM_EN				(0x1 << 14)
+#define NAU8825_CUTOFF500			(0x1 << 13)
+
+/* HSD_CTRL (0xc) */
+#define NAU8825_HSD_AUTO_MODE	(1 << 6)
+/* 0 - open, 1 - short to GND */
+#define NAU8825_SPKR_DWN1R	(1 << 1)
+#define NAU8825_SPKR_DWN1L	(1 << 0)
+
+/* JACK_DET_CTRL (0xd) */
+#define NAU8825_JACK_DET_RESTART	(1 << 9)
+#define NAU8825_JACK_DET_DB_BYPASS	(1 << 8)
+#define NAU8825_JACK_INSERT_DEBOUNCE_SFT	5
+#define NAU8825_JACK_INSERT_DEBOUNCE_MASK	(0x7 << NAU8825_JACK_INSERT_DEBOUNCE_SFT)
+#define NAU8825_JACK_EJECT_DEBOUNCE_SFT		2
+#define NAU8825_JACK_EJECT_DEBOUNCE_MASK	(0x7 << NAU8825_JACK_EJECT_DEBOUNCE_SFT)
+#define NAU8825_JACK_POLARITY	(1 << 1) /* 0 - active low, 1 - active high */
+
+/* INTERRUPT_MASK (0xf) */
+#define NAU8825_IRQ_OUTPUT_EN (1 << 11)
+#define NAU8825_IRQ_HEADSET_COMPLETE_EN (1 << 10)
+#define NAU8825_IRQ_RMS_EN (1 << 8)
+#define NAU8825_IRQ_KEY_RELEASE_EN (1 << 7)
+#define NAU8825_IRQ_KEY_SHORT_PRESS_EN (1 << 5)
+#define NAU8825_IRQ_EJECT_EN (1 << 2)
+#define NAU8825_IRQ_INSERT_EN (1 << 0)
+
+/* IRQ_STATUS (0x10) */
+#define NAU8825_HEADSET_COMPLETION_IRQ	(1 << 10)
+#define NAU8825_SHORT_CIRCUIT_IRQ	(1 << 9)
+#define NAU8825_IMPEDANCE_MEAS_IRQ	(1 << 8)
+#define NAU8825_KEY_IRQ_MASK	(0x7 << 5)
+#define NAU8825_KEY_RELEASE_IRQ	(1 << 7)
+#define NAU8825_KEY_LONG_PRESS_IRQ	(1 << 6)
+#define NAU8825_KEY_SHORT_PRESS_IRQ	(1 << 5)
+#define NAU8825_MIC_DETECTION_IRQ	(1 << 4)
+#define NAU8825_JACK_EJECTION_IRQ_MASK	(3 << 2)
+#define NAU8825_JACK_EJECTION_DETECTED	(1 << 2)
+#define NAU8825_JACK_INSERTION_IRQ_MASK	(3 << 0)
+#define NAU8825_JACK_INSERTION_DETECTED	(1 << 0)
+
+/* INTERRUPT_DIS_CTRL (0x12) */
+#define NAU8825_IRQ_HEADSET_COMPLETE_DIS (1 << 10)
+#define NAU8825_IRQ_KEY_RELEASE_DIS (1 << 7)
+#define NAU8825_IRQ_KEY_SHORT_PRESS_DIS (1 << 5)
+#define NAU8825_IRQ_EJECT_DIS (1 << 2)
+#define NAU8825_IRQ_INSERT_DIS (1 << 0)
+
+/* SAR_CTRL (0x13) */
+#define NAU8825_SAR_ADC_EN_SFT	12
+#define NAU8825_SAR_ADC_EN	(1 << NAU8825_SAR_ADC_EN_SFT)
+#define NAU8825_SAR_INPUT_MASK	(1 << 11)
+#define NAU8825_SAR_INPUT_JKSLV	(1 << 11)
+#define NAU8825_SAR_INPUT_JKR2	(0 << 11)
+#define NAU8825_SAR_TRACKING_GAIN_SFT	8
+#define NAU8825_SAR_TRACKING_GAIN_MASK	(0x7 << NAU8825_SAR_TRACKING_GAIN_SFT)
+#define NAU8825_SAR_COMPARE_TIME_SFT	2
+#define NAU8825_SAR_COMPARE_TIME_MASK	(3 << 2)
+#define NAU8825_SAR_SAMPLING_TIME_SFT	0
+#define NAU8825_SAR_SAMPLING_TIME_MASK	(3 << 0)
+
+/* KEYDET_CTRL (0x14) */
+#define NAU8825_KEYDET_SHORTKEY_DEBOUNCE_SFT	12
+#define NAU8825_KEYDET_SHORTKEY_DEBOUNCE_MASK	(0x3 << NAU8825_KEYDET_SHORTKEY_DEBOUNCE_SFT)
+#define NAU8825_KEYDET_LEVELS_NR_SFT	8
+#define NAU8825_KEYDET_LEVELS_NR_MASK	(0x7 << 8)
+#define NAU8825_KEYDET_HYSTERESIS_SFT	0
+#define NAU8825_KEYDET_HYSTERESIS_MASK	0xf
+
+/* GPIO12_CTRL (0x1a) */
+#define NAU8825_JKDET_PULL_UP	(1 << 11) /* 0 - pull down, 1 - pull up */
+#define NAU8825_JKDET_PULL_EN	(1 << 9) /* 0 - enable pull, 1 - disable */
+#define NAU8825_JKDET_OUTPUT_EN	(1 << 8) /* 0 - enable input, 1 - enable output */
+
+/* I2S_PCM_CTRL1 (0x1c) */
+#define NAU8825_I2S_BP_SFT	7
+#define NAU8825_I2S_BP_MASK	(1 << NAU8825_I2S_BP_SFT)
+#define NAU8825_I2S_BP_INV	(1 << NAU8825_I2S_BP_SFT)
+#define NAU8825_I2S_PCMB_SFT	6
+#define NAU8825_I2S_PCMB_MASK	(1 << NAU8825_I2S_PCMB_SFT)
+#define NAU8825_I2S_PCMB_EN	(1 << NAU8825_I2S_PCMB_SFT)
+#define NAU8825_I2S_DL_SFT	2
+#define NAU8825_I2S_DL_MASK	(0x3 << NAU8825_I2S_DL_SFT)
+#define NAU8825_I2S_DL_16	(0 << NAU8825_I2S_DL_SFT)
+#define NAU8825_I2S_DL_20	(1 << NAU8825_I2S_DL_SFT)
+#define NAU8825_I2S_DL_24	(2 << NAU8825_I2S_DL_SFT)
+#define NAU8825_I2S_DL_32	(3 << NAU8825_I2S_DL_SFT)
+#define NAU8825_I2S_DF_SFT	0
+#define NAU8825_I2S_DF_MASK	(0x3 << NAU8825_I2S_DF_SFT)
+#define NAU8825_I2S_DF_RIGTH	(0 << NAU8825_I2S_DF_SFT)
+#define NAU8825_I2S_DF_LEFT	(1 << NAU8825_I2S_DF_SFT)
+#define NAU8825_I2S_DF_I2S	(2 << NAU8825_I2S_DF_SFT)
+#define NAU8825_I2S_DF_PCM_AB	(3 << NAU8825_I2S_DF_SFT)
+
+/* I2S_PCM_CTRL2 (0x1d) */
+#define NAU8825_I2S_TRISTATE	(1 << 15) /* 0 - normal mode, 1 - Hi-Z output */
+#define NAU8825_I2S_LRC_DIV_SFT	12
+#define NAU8825_I2S_LRC_DIV_MASK	(0x3 << NAU8825_I2S_LRC_DIV_SFT)
+#define NAU8825_I2S_MS_SFT	3
+#define NAU8825_I2S_MS_MASK	(1 << NAU8825_I2S_MS_SFT)
+#define NAU8825_I2S_MS_MASTER	(1 << NAU8825_I2S_MS_SFT)
+#define NAU8825_I2S_MS_SLAVE	(0 << NAU8825_I2S_MS_SFT)
+#define NAU8825_I2S_BLK_DIV_MASK	0x7
+
+/* LEFT_TIME_SLOT (0x1e) */
+#define NAU8825_FS_ERR_CMP_SEL_SFT	14
+#define NAU8825_FS_ERR_CMP_SEL_MASK	(0x3 << NAU8825_FS_ERR_CMP_SEL_SFT)
+#define NAU8825_DIS_FS_SHORT_DET	(1 << 13)
+
+/* BIQ_CTRL (0x20) */
+#define NAU8825_BIQ_WRT_SFT   4
+#define NAU8825_BIQ_WRT_EN     (1 << NAU8825_BIQ_WRT_SFT)
+#define NAU8825_BIQ_PATH_SFT   0
+#define NAU8825_BIQ_PATH_MASK  (1 << NAU8825_BIQ_PATH_SFT)
+#define NAU8825_BIQ_PATH_ADC   (0 << NAU8825_BIQ_PATH_SFT)
+#define NAU8825_BIQ_PATH_DAC   (1 << NAU8825_BIQ_PATH_SFT)
+
+/* ADC_RATE (0x2b) */
+#define NAU8825_ADC_SINC4_SFT		4
+#define NAU8825_ADC_SINC4_EN		(1 << NAU8825_ADC_SINC4_SFT)
+#define NAU8825_ADC_SYNC_DOWN_SFT	0
+#define NAU8825_ADC_SYNC_DOWN_MASK	0x3
+#define NAU8825_ADC_SYNC_DOWN_32	0
+#define NAU8825_ADC_SYNC_DOWN_64	1
+#define NAU8825_ADC_SYNC_DOWN_128	2
+#define NAU8825_ADC_SYNC_DOWN_256	3
+
+/* DAC_CTRL1 (0x2c) */
+#define NAU8825_DAC_CLIP_OFF	(1 << 7)
+#define NAU8825_DAC_OVERSAMPLE_SFT	0
+#define NAU8825_DAC_OVERSAMPLE_MASK	0x7
+#define NAU8825_DAC_OVERSAMPLE_64	0
+#define NAU8825_DAC_OVERSAMPLE_256	1
+#define NAU8825_DAC_OVERSAMPLE_128	2
+#define NAU8825_DAC_OVERSAMPLE_32	4
+
+/* ADC_DGAIN_CTRL (0x30) */
+#define NAU8825_ADC_DIG_VOL_MASK	0xff
+
+/* MUTE_CTRL (0x31) */
+#define NAU8825_DAC_ZERO_CROSSING_EN	(1 << 9)
+#define NAU8825_DAC_SOFT_MUTE	(1 << 9)
+
+/* HSVOL_CTRL (0x32) */
+#define NAU8825_HP_MUTE	(1 << 15)
+#define NAU8825_HP_MUTE_AUTO	(1 << 14)
+#define NAU8825_HPL_MUTE	(1 << 13)
+#define NAU8825_HPR_MUTE	(1 << 12)
+#define NAU8825_HPL_VOL_SFT	6
+#define NAU8825_HPL_VOL_MASK	(0x3f << NAU8825_HPL_VOL_SFT)
+#define NAU8825_HPR_VOL_SFT	0
+#define NAU8825_HPR_VOL_MASK	(0x3f << NAU8825_HPR_VOL_SFT)
+#define NAU8825_HP_VOL_MIN	0x36
+
+/* DACL_CTRL (0x33) */
+#define NAU8825_DACL_CH_SEL_SFT	9
+#define NAU8825_DACL_CH_SEL_MASK (0x1 << NAU8825_DACL_CH_SEL_SFT)
+#define NAU8825_DACL_CH_SEL_L    (0x0 << NAU8825_DACL_CH_SEL_SFT)
+#define NAU8825_DACL_CH_SEL_R    (0x1 << NAU8825_DACL_CH_SEL_SFT)
+#define NAU8825_DACL_CH_VOL_MASK	0xff
+
+/* DACR_CTRL (0x34) */
+#define NAU8825_DACR_CH_SEL_SFT	9
+#define NAU8825_DACR_CH_SEL_MASK (0x1 << NAU8825_DACR_CH_SEL_SFT)
+#define NAU8825_DACR_CH_SEL_L    (0x0 << NAU8825_DACR_CH_SEL_SFT)
+#define NAU8825_DACR_CH_SEL_R    (0x1 << NAU8825_DACR_CH_SEL_SFT)
+#define NAU8825_DACR_CH_VOL_MASK	0xff
+
+/* IMM_MODE_CTRL (0x4C) */
+#define NAU8825_IMM_THD_SFT		8
+#define NAU8825_IMM_THD_MASK		(0x3f << NAU8825_IMM_THD_SFT)
+#define NAU8825_IMM_GEN_VOL_SFT	6
+#define NAU8825_IMM_GEN_VOL_MASK	(0x3 << NAU8825_IMM_GEN_VOL_SFT)
+#define NAU8825_IMM_GEN_VOL_1_2nd	(0x0 << NAU8825_IMM_GEN_VOL_SFT)
+#define NAU8825_IMM_GEN_VOL_1_4th	(0x1 << NAU8825_IMM_GEN_VOL_SFT)
+#define NAU8825_IMM_GEN_VOL_1_8th	(0x2 << NAU8825_IMM_GEN_VOL_SFT)
+#define NAU8825_IMM_GEN_VOL_1_16th	(0x3 << NAU8825_IMM_GEN_VOL_SFT)
+
+#define NAU8825_IMM_CYC_SFT		4
+#define NAU8825_IMM_CYC_MASK		(0x3 << NAU8825_IMM_CYC_SFT)
+#define NAU8825_IMM_CYC_1024		(0x0 << NAU8825_IMM_CYC_SFT)
+#define NAU8825_IMM_CYC_2048		(0x1 << NAU8825_IMM_CYC_SFT)
+#define NAU8825_IMM_CYC_4096		(0x2 << NAU8825_IMM_CYC_SFT)
+#define NAU8825_IMM_CYC_8192		(0x3 << NAU8825_IMM_CYC_SFT)
+#define NAU8825_IMM_EN			(1 << 3)
+#define NAU8825_IMM_DAC_SRC_MASK	0x7
+#define NAU8825_IMM_DAC_SRC_BIQ	0x0
+#define NAU8825_IMM_DAC_SRC_DRC	0x1
+#define NAU8825_IMM_DAC_SRC_MIX	0x2
+#define NAU8825_IMM_DAC_SRC_SIN	0x3
+
+/* CLASSG_CTRL (0x50) */
+#define NAU8825_CLASSG_TIMER_SFT	8
+#define NAU8825_CLASSG_TIMER_MASK	(0x3f << NAU8825_CLASSG_TIMER_SFT)
+#define NAU8825_CLASSG_TIMER_1ms	(0x1 << NAU8825_CLASSG_TIMER_SFT)
+#define NAU8825_CLASSG_TIMER_2ms	(0x2 << NAU8825_CLASSG_TIMER_SFT)
+#define NAU8825_CLASSG_TIMER_8ms	(0x4 << NAU8825_CLASSG_TIMER_SFT)
+#define NAU8825_CLASSG_TIMER_16ms	(0x8 << NAU8825_CLASSG_TIMER_SFT)
+#define NAU8825_CLASSG_TIMER_32ms	(0x10 << NAU8825_CLASSG_TIMER_SFT)
+#define NAU8825_CLASSG_TIMER_64ms	(0x20 << NAU8825_CLASSG_TIMER_SFT)
+#define NAU8825_CLASSG_LDAC_EN		(0x1 << 2)
+#define NAU8825_CLASSG_RDAC_EN		(0x1 << 1)
+#define NAU8825_CLASSG_EN		(1 << 0)
+
+/* I2C_DEVICE_ID (0x58) */
+#define NAU8825_GPIO2JD1	(1 << 7)
+#define NAU8825_SOFTWARE_ID_MASK	0x3
+#define NAU8825_SOFTWARE_ID_NAU8825	0x0
+
+/* BIAS_ADJ (0x66) */
+#define NAU8825_BIAS_HPR_IMP		(1 << 15)
+#define NAU8825_BIAS_HPL_IMP		(1 << 14)
+#define NAU8825_BIAS_TESTDAC_SFT	8
+#define NAU8825_BIAS_TESTDAC_EN	(0x3 << NAU8825_BIAS_TESTDAC_SFT)
+#define NAU8825_BIAS_TESTDACR_EN	(0x2 << NAU8825_BIAS_TESTDAC_SFT)
+#define NAU8825_BIAS_TESTDACL_EN	(0x1 << NAU8825_BIAS_TESTDAC_SFT)
+#define NAU8825_BIAS_VMID	(1 << 6)
+#define NAU8825_BIAS_VMID_SEL_SFT	4
+#define NAU8825_BIAS_VMID_SEL_MASK	(3 << NAU8825_BIAS_VMID_SEL_SFT)
+
+/* ANALOG_CONTROL_2 (0x6a) */
+#define NAU8825_HP_NON_CLASSG_CURRENT_2xADJ (1 << 12)
+#define NAU8825_DAC_CAPACITOR_MSB (1 << 1)
+#define NAU8825_DAC_CAPACITOR_LSB (1 << 0)
+
+/* ANALOG_ADC_2 (0x72) */
+#define NAU8825_ADC_VREFSEL_MASK	(0x3 << 8)
+#define NAU8825_ADC_VREFSEL_ANALOG	(0 << 8)
+#define NAU8825_ADC_VREFSEL_VMID	(1 << 8)
+#define NAU8825_ADC_VREFSEL_VMID_PLUS_0_5DB	(2 << 8)
+#define NAU8825_ADC_VREFSEL_VMID_PLUS_1DB	(3 << 8)
+#define NAU8825_POWERUP_ADCL	(1 << 6)
+
+/* RDAC (0x73) */
+#define NAU8825_RDAC_FS_BCLK_ENB	(1 << 15)
+#define NAU8825_RDAC_EN_SFT		12
+#define NAU8825_RDAC_EN		(0x3 << NAU8825_RDAC_EN_SFT)
+#define NAU8825_RDAC_CLK_EN_SFT	8
+#define NAU8825_RDAC_CLK_EN		(0x3 << NAU8825_RDAC_CLK_EN_SFT)
+#define NAU8825_RDAC_CLK_DELAY_SFT	4
+#define NAU8825_RDAC_CLK_DELAY_MASK	(0x7 << NAU8825_RDAC_CLK_DELAY_SFT)
+#define NAU8825_RDAC_VREF_SFT	2
+#define NAU8825_RDAC_VREF_MASK	(0x3 << NAU8825_RDAC_VREF_SFT)
+
+/* MIC_BIAS (0x74) */
+#define NAU8825_MICBIAS_JKSLV	(1 << 14)
+#define NAU8825_MICBIAS_JKR2	(1 << 12)
+#define NAU8825_MICBIAS_POWERUP_SFT	8
+#define NAU8825_MICBIAS_VOLTAGE_SFT	0
+#define NAU8825_MICBIAS_VOLTAGE_MASK	0x7
+
+/* BOOST (0x76) */
+#define NAU8825_PRECHARGE_DIS	(1 << 13)
+#define NAU8825_GLOBAL_BIAS_EN	(1 << 12)
+#define NAU8825_HP_BOOST_DIS		(1 << 9)
+#define NAU8825_HP_BOOST_G_DIS	(1 << 8)
+#define NAU8825_SHORT_SHUTDOWN_EN	(1 << 6)
+
+/* POWER_UP_CONTROL (0x7f) */
+#define NAU8825_POWERUP_INTEGR_R	(1 << 5)
+#define NAU8825_POWERUP_INTEGR_L	(1 << 4)
+#define NAU8825_POWERUP_DRV_IN_R	(1 << 3)
+#define NAU8825_POWERUP_DRV_IN_L	(1 << 2)
+#define NAU8825_POWERUP_HP_DRV_R	(1 << 1)
+#define NAU8825_POWERUP_HP_DRV_L	(1 << 0)
+
+/* CHARGE_PUMP (0x80) */
+#define NAU8825_JAMNODCLOW	(1 << 10)
+#define NAU8825_POWER_DOWN_DACR	(1 << 9)
+#define NAU8825_POWER_DOWN_DACL	(1 << 8)
+#define NAU8825_CHANRGE_PUMP_EN	(1 << 5)
+
+
+/* System Clock Source */
+enum {
+	NAU8825_CLK_DIS = 0,
+	NAU8825_CLK_MCLK,
+	NAU8825_CLK_INTERNAL,
+	NAU8825_CLK_FLL_MCLK,
+	NAU8825_CLK_FLL_BLK,
+	NAU8825_CLK_FLL_FS,
+};
+
+/* Cross talk detection state */
+enum {
+	NAU8825_XTALK_PREPARE = 0,
+	NAU8825_XTALK_HPR_R2L,
+	NAU8825_XTALK_HPL_R2L,
+	NAU8825_XTALK_IMM,
+	NAU8825_XTALK_DONE,
+};
+
+struct nau8825 {
+	struct device *dev;
+	struct regmap *regmap;
+	struct snd_soc_dapm_context *dapm;
+	struct snd_soc_jack *jack;
+	struct clk *mclk;
+	struct work_struct xtalk_work;
+	struct semaphore xtalk_sem;
+	int irq;
+	int mclk_freq; /* 0 - mclk is disabled */
+	int button_pressed;
+	int micbias_voltage;
+	int vref_impedance;
+	bool jkdet_enable;
+	bool jkdet_pull_enable;
+	bool jkdet_pull_up;
+	int jkdet_polarity;
+	int sar_threshold_num;
+	int sar_threshold[8];
+	int sar_hysteresis;
+	int sar_voltage;
+	int sar_compare_time;
+	int sar_sampling_time;
+	int key_debounce;
+	int jack_insert_debounce;
+	int jack_eject_debounce;
+	int high_imped;
+	int xtalk_state;
+	int xtalk_event;
+	int xtalk_event_mask;
+	bool xtalk_protect;
+	int imp_rms[NAU8825_XTALK_IMM];
+	int xtalk_enable;
+	bool xtalk_baktab_initialized; /* True if initialized. */
+};
+
+int nau8825_enable_jack_detect(struct snd_soc_component *component,
+				struct snd_soc_jack *jack);
+
+
+#endif  /* __NAU8825_H__ */
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
new file mode 100644
index 0000000..84777d3
--- /dev/null
+++ b/sound/soc/codecs/pcm1681.c
@@ -0,0 +1,347 @@
+/*
+ * PCM1681 ASoC codec driver
+ *
+ * Copyright (c) StreamUnlimited GmbH 2013
+ *	Marek Belisko <marek.belisko@streamunlimited.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#define PCM1681_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  |		\
+			     SNDRV_PCM_FMTBIT_S24_LE)
+
+#define PCM1681_PCM_RATES   (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
+			     SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100  | \
+			     SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200  | \
+			     SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+
+#define PCM1681_SOFT_MUTE_ALL		0xff
+#define PCM1681_DEEMPH_RATE_MASK	0x18
+#define PCM1681_DEEMPH_MASK		0x01
+
+#define PCM1681_ATT_CONTROL(X)	(X <= 6 ? X : X + 9) /* Attenuation level */
+#define PCM1681_SOFT_MUTE	0x07	/* Soft mute control register */
+#define PCM1681_DAC_CONTROL	0x08	/* DAC operation control */
+#define PCM1681_FMT_CONTROL	0x09	/* Audio interface data format */
+#define PCM1681_DEEMPH_CONTROL	0x0a	/* De-emphasis control */
+#define PCM1681_ZERO_DETECT_STATUS	0x0e	/* Zero detect status reg */
+
+static const struct reg_default pcm1681_reg_defaults[] = {
+	{ 0x01,	0xff },
+	{ 0x02,	0xff },
+	{ 0x03,	0xff },
+	{ 0x04,	0xff },
+	{ 0x05,	0xff },
+	{ 0x06,	0xff },
+	{ 0x07,	0x00 },
+	{ 0x08,	0x00 },
+	{ 0x09,	0x06 },
+	{ 0x0A,	0x00 },
+	{ 0x0B,	0xff },
+	{ 0x0C,	0x0f },
+	{ 0x0D,	0x00 },
+	{ 0x10,	0xff },
+	{ 0x11,	0xff },
+	{ 0x12,	0x00 },
+	{ 0x13,	0x00 },
+};
+
+static bool pcm1681_accessible_reg(struct device *dev, unsigned int reg)
+{
+	return !((reg == 0x00) || (reg == 0x0f));
+}
+
+static bool pcm1681_writeable_reg(struct device *dev, unsigned int reg)
+{
+	return pcm1681_accessible_reg(dev, reg) &&
+		(reg != PCM1681_ZERO_DETECT_STATUS);
+}
+
+struct pcm1681_private {
+	struct regmap *regmap;
+	unsigned int format;
+	/* Current deemphasis status */
+	unsigned int deemph;
+	/* Current rate for deemphasis control */
+	unsigned int rate;
+};
+
+static const int pcm1681_deemph[] = { 44100, 48000, 32000 };
+
+static int pcm1681_set_deemph(struct snd_soc_component *component)
+{
+	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
+	int i = 0, val = -1, enable = 0;
+
+	if (priv->deemph) {
+		for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++) {
+			if (pcm1681_deemph[i] == priv->rate) {
+				val = i;
+				break;
+			}
+		}
+	}
+
+	if (val != -1) {
+		regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL,
+				   PCM1681_DEEMPH_RATE_MASK, val << 3);
+		enable = 1;
+	} else {
+		enable = 0;
+	}
+
+	/* enable/disable deemphasis functionality */
+	return regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL,
+					PCM1681_DEEMPH_MASK, enable);
+}
+
+static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = priv->deemph;
+
+	return 0;
+}
+
+static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
+
+	priv->deemph = ucontrol->value.integer.value[0];
+
+	return pcm1681_set_deemph(component);
+}
+
+static int pcm1681_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int format)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
+
+	/* The PCM1681 can only be slave to all clocks */
+	if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+		dev_err(component->dev, "Invalid clocking mode\n");
+		return -EINVAL;
+	}
+
+	priv->format = format;
+
+	return 0;
+}
+
+static int pcm1681_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
+	int val;
+
+	if (mute)
+		val = PCM1681_SOFT_MUTE_ALL;
+	else
+		val = 0;
+
+	return regmap_write(priv->regmap, PCM1681_SOFT_MUTE, val);
+}
+
+static int pcm1681_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
+	int val = 0, ret;
+
+	priv->rate = params_rate(params);
+
+	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (params_width(params)) {
+		case 24:
+			val = 0;
+			break;
+		case 16:
+			val = 3;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		val = 0x04;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val = 0x05;
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(priv->regmap, PCM1681_FMT_CONTROL, 0x0f, val);
+	if (ret < 0)
+		return ret;
+
+	return pcm1681_set_deemph(component);
+}
+
+static const struct snd_soc_dai_ops pcm1681_dai_ops = {
+	.set_fmt	= pcm1681_set_dai_fmt,
+	.hw_params	= pcm1681_hw_params,
+	.digital_mute	= pcm1681_digital_mute,
+};
+
+static const struct snd_soc_dapm_widget pcm1681_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("VOUT1"),
+SND_SOC_DAPM_OUTPUT("VOUT2"),
+SND_SOC_DAPM_OUTPUT("VOUT3"),
+SND_SOC_DAPM_OUTPUT("VOUT4"),
+SND_SOC_DAPM_OUTPUT("VOUT5"),
+SND_SOC_DAPM_OUTPUT("VOUT6"),
+SND_SOC_DAPM_OUTPUT("VOUT7"),
+SND_SOC_DAPM_OUTPUT("VOUT8"),
+};
+
+static const struct snd_soc_dapm_route pcm1681_dapm_routes[] = {
+	{ "VOUT1", NULL, "Playback" },
+	{ "VOUT2", NULL, "Playback" },
+	{ "VOUT3", NULL, "Playback" },
+	{ "VOUT4", NULL, "Playback" },
+	{ "VOUT5", NULL, "Playback" },
+	{ "VOUT6", NULL, "Playback" },
+	{ "VOUT7", NULL, "Playback" },
+	{ "VOUT8", NULL, "Playback" },
+};
+
+static const DECLARE_TLV_DB_SCALE(pcm1681_dac_tlv, -6350, 50, 1);
+
+static const struct snd_kcontrol_new pcm1681_controls[] = {
+	SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume",
+			PCM1681_ATT_CONTROL(1), PCM1681_ATT_CONTROL(2), 0,
+			0x7f, 0, pcm1681_dac_tlv),
+	SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume",
+			PCM1681_ATT_CONTROL(3), PCM1681_ATT_CONTROL(4), 0,
+			0x7f, 0, pcm1681_dac_tlv),
+	SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume",
+			PCM1681_ATT_CONTROL(5), PCM1681_ATT_CONTROL(6), 0,
+			0x7f, 0, pcm1681_dac_tlv),
+	SOC_DOUBLE_R_TLV("Channel 7/8 Playback Volume",
+			PCM1681_ATT_CONTROL(7), PCM1681_ATT_CONTROL(8), 0,
+			0x7f, 0, pcm1681_dac_tlv),
+	SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
+			    pcm1681_get_deemph, pcm1681_put_deemph),
+};
+
+static struct snd_soc_dai_driver pcm1681_dai = {
+	.name = "pcm1681-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = PCM1681_PCM_RATES,
+		.formats = PCM1681_PCM_FORMATS,
+	},
+	.ops = &pcm1681_dai_ops,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id pcm1681_dt_ids[] = {
+	{ .compatible = "ti,pcm1681", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm1681_dt_ids);
+#endif
+
+static const struct regmap_config pcm1681_regmap = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= 0x13,
+	.reg_defaults		= pcm1681_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(pcm1681_reg_defaults),
+	.writeable_reg		= pcm1681_writeable_reg,
+	.readable_reg		= pcm1681_accessible_reg,
+};
+
+static const struct snd_soc_component_driver soc_component_dev_pcm1681 = {
+	.controls		= pcm1681_controls,
+	.num_controls		= ARRAY_SIZE(pcm1681_controls),
+	.dapm_widgets		= pcm1681_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm1681_dapm_widgets),
+	.dapm_routes		= pcm1681_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm1681_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct i2c_device_id pcm1681_i2c_id[] = {
+	{"pcm1681", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, pcm1681_i2c_id);
+
+static int pcm1681_i2c_probe(struct i2c_client *client,
+			      const struct i2c_device_id *id)
+{
+	int ret;
+	struct pcm1681_private *priv;
+
+	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->regmap = devm_regmap_init_i2c(client, &pcm1681_regmap);
+	if (IS_ERR(priv->regmap)) {
+		ret = PTR_ERR(priv->regmap);
+		dev_err(&client->dev, "Failed to create regmap: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(client, priv);
+
+	return devm_snd_soc_register_component(&client->dev,
+		&soc_component_dev_pcm1681,
+		&pcm1681_dai, 1);
+}
+
+static struct i2c_driver pcm1681_i2c_driver = {
+	.driver = {
+		.name	= "pcm1681",
+		.of_match_table = of_match_ptr(pcm1681_dt_ids),
+	},
+	.id_table	= pcm1681_i2c_id,
+	.probe		= pcm1681_i2c_probe,
+};
+
+module_i2c_driver(pcm1681_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments PCM1681 ALSA SoC Codec Driver");
+MODULE_AUTHOR("Marek Belisko <marek.belisko@streamunlimited.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm1789-i2c.c b/sound/soc/codecs/pcm1789-i2c.c
new file mode 100644
index 0000000..327ec58
--- /dev/null
+++ b/sound/soc/codecs/pcm1789-i2c.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+// Audio driver for PCM1789 I2C
+// Copyright (C) 2018 Bootlin
+// Mylène Josserand <mylene.josserand@bootlin.com>
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#include "pcm1789.h"
+
+static int pcm1789_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	int ret;
+
+	regmap = devm_regmap_init_i2c(client, &pcm1789_regmap_config);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		dev_err(&client->dev, "Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	return pcm1789_common_init(&client->dev, regmap);
+}
+
+static int pcm1789_i2c_remove(struct i2c_client *client)
+{
+	return pcm1789_common_exit(&client->dev);
+}
+
+static const struct of_device_id pcm1789_of_match[] = {
+	{ .compatible = "ti,pcm1789", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm1789_of_match);
+
+static const struct i2c_device_id pcm1789_i2c_ids[] = {
+	{ "pcm1789", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pcm1789_i2c_ids);
+
+static struct i2c_driver pcm1789_i2c_driver = {
+	.driver = {
+		.name	= "pcm1789",
+		.of_match_table = of_match_ptr(pcm1789_of_match),
+	},
+	.id_table	= pcm1789_i2c_ids,
+	.probe		= pcm1789_i2c_probe,
+	.remove	= pcm1789_i2c_remove,
+};
+
+module_i2c_driver(pcm1789_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC PCM1789 I2C driver");
+MODULE_AUTHOR("Mylène Josserand <mylene.josserand@bootlin.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm1789.c b/sound/soc/codecs/pcm1789.c
new file mode 100644
index 0000000..8df6447
--- /dev/null
+++ b/sound/soc/codecs/pcm1789.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0
+// Audio driver for PCM1789
+// Copyright (C) 2018 Bootlin
+// Mylène Josserand <mylene.josserand@bootlin.com>
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "pcm1789.h"
+
+#define PCM1789_MUTE_CONTROL	0x10
+#define PCM1789_FMT_CONTROL	0x11
+#define PCM1789_SOFT_MUTE	0x14
+#define PCM1789_DAC_VOL_LEFT	0x18
+#define PCM1789_DAC_VOL_RIGHT	0x19
+
+#define PCM1789_FMT_MASK	0x07
+#define PCM1789_MUTE_MASK	0x03
+#define PCM1789_MUTE_SRET	0x06
+
+struct pcm1789_private {
+	struct regmap *regmap;
+	unsigned int format;
+	unsigned int rate;
+	struct gpio_desc *reset;
+	struct work_struct work;
+	struct device *dev;
+};
+
+static const struct reg_default pcm1789_reg_defaults[] = {
+	{ PCM1789_FMT_CONTROL, 0x00 },
+	{ PCM1789_SOFT_MUTE, 0x00 },
+	{ PCM1789_DAC_VOL_LEFT, 0xff },
+	{ PCM1789_DAC_VOL_RIGHT, 0xff },
+};
+
+static bool pcm1789_accessible_reg(struct device *dev, unsigned int reg)
+{
+	return reg >= PCM1789_MUTE_CONTROL && reg <= PCM1789_DAC_VOL_RIGHT;
+}
+
+static bool pcm1789_writeable_reg(struct device *dev, unsigned int reg)
+{
+	return pcm1789_accessible_reg(dev, reg);
+}
+
+static int pcm1789_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			       unsigned int format)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct pcm1789_private *priv = snd_soc_component_get_drvdata(component);
+
+	priv->format = format;
+
+	return 0;
+}
+
+static int pcm1789_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct pcm1789_private *priv = snd_soc_component_get_drvdata(component);
+
+	return regmap_update_bits(priv->regmap, PCM1789_SOFT_MUTE,
+				  PCM1789_MUTE_MASK,
+				  mute ? 0 : PCM1789_MUTE_MASK);
+}
+
+static int pcm1789_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *codec_dai)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct pcm1789_private *priv = snd_soc_component_get_drvdata(component);
+	int val = 0, ret;
+
+	priv->rate = params_rate(params);
+
+	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (params_width(params)) {
+		case 24:
+			val = 2;
+			break;
+		case 16:
+			val = 3;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		switch (params_width(params)) {
+		case 16:
+		case 24:
+		case 32:
+			val = 0;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (params_width(params)) {
+		case 16:
+		case 24:
+		case 32:
+			val = 1;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(priv->regmap, PCM1789_FMT_CONTROL,
+				 PCM1789_FMT_MASK, val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static void pcm1789_work_queue(struct work_struct *work)
+{
+	struct pcm1789_private *priv = container_of(work,
+						    struct pcm1789_private,
+						    work);
+
+	/* Perform a software reset to remove codec from desynchronized state */
+	if (regmap_update_bits(priv->regmap, PCM1789_MUTE_CONTROL,
+			       0x3 << PCM1789_MUTE_SRET, 0) < 0)
+		dev_err(priv->dev, "Error while setting SRET");
+}
+
+static int pcm1789_trigger(struct snd_pcm_substream *substream, int cmd,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm1789_private *priv = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		schedule_work(&priv->work);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct snd_soc_dai_ops pcm1789_dai_ops = {
+	.set_fmt	= pcm1789_set_dai_fmt,
+	.hw_params	= pcm1789_hw_params,
+	.digital_mute	= pcm1789_digital_mute,
+	.trigger	= pcm1789_trigger,
+};
+
+static const DECLARE_TLV_DB_SCALE(pcm1789_dac_tlv, -12000, 50, 1);
+
+static const struct snd_kcontrol_new pcm1789_controls[] = {
+	SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1789_DAC_VOL_LEFT,
+			       PCM1789_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0,
+			       pcm1789_dac_tlv),
+};
+
+static const struct snd_soc_dapm_widget pcm1789_dapm_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("IOUTL+"),
+	SND_SOC_DAPM_OUTPUT("IOUTL-"),
+	SND_SOC_DAPM_OUTPUT("IOUTR+"),
+	SND_SOC_DAPM_OUTPUT("IOUTR-"),
+};
+
+static const struct snd_soc_dapm_route pcm1789_dapm_routes[] = {
+	{ "IOUTL+", NULL, "Playback" },
+	{ "IOUTL-", NULL, "Playback" },
+	{ "IOUTR+", NULL, "Playback" },
+	{ "IOUTR-", NULL, "Playback" },
+};
+
+static struct snd_soc_dai_driver pcm1789_dai = {
+	.name = "pcm1789-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_CONTINUOUS,
+		.rate_min = 10000,
+		.rate_max = 200000,
+		.formats = PCM1789_FORMATS,
+	},
+	.ops = &pcm1789_dai_ops,
+};
+
+const struct regmap_config pcm1789_regmap_config = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= PCM1789_DAC_VOL_RIGHT,
+	.reg_defaults		= pcm1789_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(pcm1789_reg_defaults),
+	.writeable_reg		= pcm1789_writeable_reg,
+	.readable_reg		= pcm1789_accessible_reg,
+};
+EXPORT_SYMBOL_GPL(pcm1789_regmap_config);
+
+static const struct snd_soc_component_driver soc_component_dev_pcm1789 = {
+	.controls		= pcm1789_controls,
+	.num_controls		= ARRAY_SIZE(pcm1789_controls),
+	.dapm_widgets		= pcm1789_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm1789_dapm_widgets),
+	.dapm_routes		= pcm1789_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm1789_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+int pcm1789_common_init(struct device *dev, struct regmap *regmap)
+{
+	struct pcm1789_private *pcm1789;
+
+	pcm1789 = devm_kzalloc(dev, sizeof(struct pcm1789_private),
+			       GFP_KERNEL);
+	if (!pcm1789)
+		return -ENOMEM;
+
+	pcm1789->regmap = regmap;
+	pcm1789->dev = dev;
+	dev_set_drvdata(dev, pcm1789);
+
+	pcm1789->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(pcm1789->reset))
+		return PTR_ERR(pcm1789->reset);
+
+	gpiod_set_value_cansleep(pcm1789->reset, 0);
+	msleep(300);
+
+	INIT_WORK(&pcm1789->work, pcm1789_work_queue);
+
+	return devm_snd_soc_register_component(dev, &soc_component_dev_pcm1789,
+					       &pcm1789_dai, 1);
+}
+EXPORT_SYMBOL_GPL(pcm1789_common_init);
+
+int pcm1789_common_exit(struct device *dev)
+{
+	struct pcm1789_private *priv = dev_get_drvdata(dev);
+
+	flush_work(&priv->work);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pcm1789_common_exit);
+
+MODULE_DESCRIPTION("ASoC PCM1789 driver");
+MODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm1789.h b/sound/soc/codecs/pcm1789.h
new file mode 100644
index 0000000..c446d78
--- /dev/null
+++ b/sound/soc/codecs/pcm1789.h
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
+// Definitions for PCM1789 audio driver
+// Copyright (C) 2018 Bootlin
+// Mylène Josserand <mylene.josserand@bootlin.com>
+
+#ifndef __PCM1789_H__
+#define __PCM1789_H__
+
+#define PCM1789_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+			 SNDRV_PCM_FMTBIT_S16_LE)
+
+extern const struct regmap_config pcm1789_regmap_config;
+
+int pcm1789_common_init(struct device *dev, struct regmap *regmap);
+int pcm1789_common_exit(struct device *dev);
+
+#endif
diff --git a/sound/soc/codecs/pcm179x-i2c.c b/sound/soc/codecs/pcm179x-i2c.c
new file mode 100644
index 0000000..0374796
--- /dev/null
+++ b/sound/soc/codecs/pcm179x-i2c.c
@@ -0,0 +1,67 @@
+/*
+ * PCM179X ASoC I2C driver
+ *
+ * Copyright (c) Teenage Engineering AB 2016
+ *
+ *     Jacob Siverskog <jacob@teenage.engineering>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include "pcm179x.h"
+
+static int pcm179x_i2c_probe(struct i2c_client *client,
+			      const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	int ret;
+
+	regmap = devm_regmap_init_i2c(client, &pcm179x_regmap_config);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		dev_err(&client->dev, "Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	return pcm179x_common_init(&client->dev, regmap);
+}
+
+static const struct of_device_id pcm179x_of_match[] = {
+	{ .compatible = "ti,pcm1792a", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm179x_of_match);
+
+static const struct i2c_device_id pcm179x_i2c_ids[] = {
+	{ "pcm179x", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pcm179x_i2c_ids);
+
+static struct i2c_driver pcm179x_i2c_driver = {
+	.driver = {
+		.name	= "pcm179x",
+		.of_match_table = of_match_ptr(pcm179x_of_match),
+	},
+	.id_table	= pcm179x_i2c_ids,
+	.probe		= pcm179x_i2c_probe,
+};
+
+module_i2c_driver(pcm179x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC PCM179X I2C driver");
+MODULE_AUTHOR("Jacob Siverskog <jacob@teenage.engineering>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm179x-spi.c b/sound/soc/codecs/pcm179x-spi.c
new file mode 100644
index 0000000..89ad715
--- /dev/null
+++ b/sound/soc/codecs/pcm179x-spi.c
@@ -0,0 +1,66 @@
+/*
+ * PCM179X ASoC SPI driver
+ *
+ * Copyright (c) Amarula Solutions B.V. 2013
+ *
+ *     Michael Trimarchi <michael@amarulasolutions.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include "pcm179x.h"
+
+static int pcm179x_spi_probe(struct spi_device *spi)
+{
+	struct regmap *regmap;
+	int ret;
+
+	regmap = devm_regmap_init_spi(spi, &pcm179x_regmap_config);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		dev_err(&spi->dev, "Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	return pcm179x_common_init(&spi->dev, regmap);
+}
+
+static const struct of_device_id pcm179x_of_match[] = {
+	{ .compatible = "ti,pcm1792a", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm179x_of_match);
+
+static const struct spi_device_id pcm179x_spi_ids[] = {
+	{ "pcm179x", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, pcm179x_spi_ids);
+
+static struct spi_driver pcm179x_spi_driver = {
+	.driver = {
+		.name = "pcm179x",
+		.of_match_table = of_match_ptr(pcm179x_of_match),
+	},
+	.id_table = pcm179x_spi_ids,
+	.probe = pcm179x_spi_probe,
+};
+
+module_spi_driver(pcm179x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC PCM179X SPI driver");
+MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c
new file mode 100644
index 0000000..4b311c0
--- /dev/null
+++ b/sound/soc/codecs/pcm179x.c
@@ -0,0 +1,240 @@
+/*
+ * PCM179X ASoC codec driver
+ *
+ * Copyright (c) Amarula Solutions B.V. 2013
+ *
+ *     Michael Trimarchi <michael@amarulasolutions.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/of.h>
+
+#include "pcm179x.h"
+
+#define PCM179X_DAC_VOL_LEFT	0x10
+#define PCM179X_DAC_VOL_RIGHT	0x11
+#define PCM179X_FMT_CONTROL	0x12
+#define PCM179X_MODE_CONTROL	0x13
+#define PCM179X_SOFT_MUTE	PCM179X_FMT_CONTROL
+
+#define PCM179X_FMT_MASK	0x70
+#define PCM179X_FMT_SHIFT	4
+#define PCM179X_MUTE_MASK	0x01
+#define PCM179X_MUTE_SHIFT	0
+#define PCM179X_ATLD_ENABLE	(1 << 7)
+
+static const struct reg_default pcm179x_reg_defaults[] = {
+	{ 0x10, 0xff },
+	{ 0x11, 0xff },
+	{ 0x12, 0x50 },
+	{ 0x13, 0x00 },
+	{ 0x14, 0x00 },
+	{ 0x15, 0x01 },
+	{ 0x16, 0x00 },
+	{ 0x17, 0x00 },
+};
+
+static bool pcm179x_accessible_reg(struct device *dev, unsigned int reg)
+{
+	return reg >= 0x10 && reg <= 0x17;
+}
+
+static bool pcm179x_writeable_reg(struct device *dev, unsigned int reg)
+{
+	bool accessible;
+
+	accessible = pcm179x_accessible_reg(dev, reg);
+
+	return accessible && reg != 0x16 && reg != 0x17;
+}
+
+struct pcm179x_private {
+	struct regmap *regmap;
+	unsigned int format;
+	unsigned int rate;
+};
+
+static int pcm179x_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int format)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct pcm179x_private *priv = snd_soc_component_get_drvdata(component);
+
+	priv->format = format;
+
+	return 0;
+}
+
+static int pcm179x_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm179x_private *priv = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = regmap_update_bits(priv->regmap, PCM179X_SOFT_MUTE,
+				 PCM179X_MUTE_MASK, !!mute);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int pcm179x_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm179x_private *priv = snd_soc_component_get_drvdata(component);
+	int val = 0, ret;
+
+	priv->rate = params_rate(params);
+
+	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (params_width(params)) {
+		case 24:
+		case 32:
+			val = 2;
+			break;
+		case 16:
+			val = 0;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		switch (params_width(params)) {
+		case 24:
+		case 32:
+			val = 5;
+			break;
+		case 16:
+			val = 4;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	val = val << PCM179X_FMT_SHIFT | PCM179X_ATLD_ENABLE;
+
+	ret = regmap_update_bits(priv->regmap, PCM179X_FMT_CONTROL,
+				 PCM179X_FMT_MASK | PCM179X_ATLD_ENABLE, val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops pcm179x_dai_ops = {
+	.set_fmt	= pcm179x_set_dai_fmt,
+	.hw_params	= pcm179x_hw_params,
+	.digital_mute	= pcm179x_digital_mute,
+};
+
+static const DECLARE_TLV_DB_SCALE(pcm179x_dac_tlv, -12000, 50, 1);
+
+static const struct snd_kcontrol_new pcm179x_controls[] = {
+	SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM179X_DAC_VOL_LEFT,
+			 PCM179X_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0,
+			 pcm179x_dac_tlv),
+	SOC_SINGLE("DAC Invert Output Switch", PCM179X_MODE_CONTROL, 7, 1, 0),
+	SOC_SINGLE("DAC Rolloff Filter Switch", PCM179X_MODE_CONTROL, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget pcm179x_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("IOUTL+"),
+SND_SOC_DAPM_OUTPUT("IOUTL-"),
+SND_SOC_DAPM_OUTPUT("IOUTR+"),
+SND_SOC_DAPM_OUTPUT("IOUTR-"),
+};
+
+static const struct snd_soc_dapm_route pcm179x_dapm_routes[] = {
+	{ "IOUTL+", NULL, "Playback" },
+	{ "IOUTL-", NULL, "Playback" },
+	{ "IOUTR+", NULL, "Playback" },
+	{ "IOUTR-", NULL, "Playback" },
+};
+
+static struct snd_soc_dai_driver pcm179x_dai = {
+	.name = "pcm179x-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_CONTINUOUS,
+		.rate_min = 10000,
+		.rate_max = 200000,
+		.formats = PCM1792A_FORMATS, },
+	.ops = &pcm179x_dai_ops,
+};
+
+const struct regmap_config pcm179x_regmap_config = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= 23,
+	.reg_defaults		= pcm179x_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(pcm179x_reg_defaults),
+	.writeable_reg		= pcm179x_writeable_reg,
+	.readable_reg		= pcm179x_accessible_reg,
+};
+EXPORT_SYMBOL_GPL(pcm179x_regmap_config);
+
+static const struct snd_soc_component_driver soc_component_dev_pcm179x = {
+	.controls		= pcm179x_controls,
+	.num_controls		= ARRAY_SIZE(pcm179x_controls),
+	.dapm_widgets		= pcm179x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm179x_dapm_widgets),
+	.dapm_routes		= pcm179x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm179x_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+int pcm179x_common_init(struct device *dev, struct regmap *regmap)
+{
+	struct pcm179x_private *pcm179x;
+
+	pcm179x = devm_kzalloc(dev, sizeof(struct pcm179x_private),
+				GFP_KERNEL);
+	if (!pcm179x)
+		return -ENOMEM;
+
+	pcm179x->regmap = regmap;
+	dev_set_drvdata(dev, pcm179x);
+
+	return devm_snd_soc_register_component(dev,
+			&soc_component_dev_pcm179x, &pcm179x_dai, 1);
+}
+EXPORT_SYMBOL_GPL(pcm179x_common_init);
+
+MODULE_DESCRIPTION("ASoC PCM179X driver");
+MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm179x.h b/sound/soc/codecs/pcm179x.h
new file mode 100644
index 0000000..cf8681c
--- /dev/null
+++ b/sound/soc/codecs/pcm179x.h
@@ -0,0 +1,27 @@
+/*
+ * definitions for PCM179X
+ *
+ * Copyright 2013 Amarula Solutions
+ *
+  * 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 __PCM179X_H__
+#define __PCM179X_H__
+
+#define PCM1792A_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+			  SNDRV_PCM_FMTBIT_S16_LE)
+
+extern const struct regmap_config pcm179x_regmap_config;
+
+int pcm179x_common_init(struct device *dev, struct regmap *regmap);
+
+#endif
diff --git a/sound/soc/codecs/pcm186x-i2c.c b/sound/soc/codecs/pcm186x-i2c.c
new file mode 100644
index 0000000..0214dc6
--- /dev/null
+++ b/sound/soc/codecs/pcm186x-i2c.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments PCM186x Universal Audio ADC - I2C
+ *
+ * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
+ *	Andreas Dannenberg <dannenberg@ti.com>
+ *	Andrew F. Davis <afd@ti.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#include "pcm186x.h"
+
+static const struct of_device_id pcm186x_of_match[] = {
+	{ .compatible = "ti,pcm1862", .data = (void *)PCM1862 },
+	{ .compatible = "ti,pcm1863", .data = (void *)PCM1863 },
+	{ .compatible = "ti,pcm1864", .data = (void *)PCM1864 },
+	{ .compatible = "ti,pcm1865", .data = (void *)PCM1865 },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm186x_of_match);
+
+static int pcm186x_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	const enum pcm186x_type type = (enum pcm186x_type)id->driver_data;
+	int irq = i2c->irq;
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_i2c(i2c, &pcm186x_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return pcm186x_probe(&i2c->dev, type, irq, regmap);
+}
+
+static const struct i2c_device_id pcm186x_i2c_id[] = {
+	{ "pcm1862", PCM1862 },
+	{ "pcm1863", PCM1863 },
+	{ "pcm1864", PCM1864 },
+	{ "pcm1865", PCM1865 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pcm186x_i2c_id);
+
+static struct i2c_driver pcm186x_i2c_driver = {
+	.probe		= pcm186x_i2c_probe,
+	.id_table	= pcm186x_i2c_id,
+	.driver		= {
+		.name	= "pcm186x",
+		.of_match_table = pcm186x_of_match,
+	},
+};
+module_i2c_driver(pcm186x_i2c_driver);
+
+MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
+MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_DESCRIPTION("PCM186x Universal Audio ADC I2C Interface Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm186x-spi.c b/sound/soc/codecs/pcm186x-spi.c
new file mode 100644
index 0000000..b56e198
--- /dev/null
+++ b/sound/soc/codecs/pcm186x-spi.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments PCM186x Universal Audio ADC - SPI
+ *
+ * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
+ *	Andreas Dannenberg <dannenberg@ti.com>
+ *	Andrew F. Davis <afd@ti.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "pcm186x.h"
+
+static const struct of_device_id pcm186x_of_match[] = {
+	{ .compatible = "ti,pcm1862", .data = (void *)PCM1862 },
+	{ .compatible = "ti,pcm1863", .data = (void *)PCM1863 },
+	{ .compatible = "ti,pcm1864", .data = (void *)PCM1864 },
+	{ .compatible = "ti,pcm1865", .data = (void *)PCM1865 },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm186x_of_match);
+
+static int pcm186x_spi_probe(struct spi_device *spi)
+{
+	const enum pcm186x_type type =
+			 (enum pcm186x_type)spi_get_device_id(spi)->driver_data;
+	int irq = spi->irq;
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_spi(spi, &pcm186x_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return pcm186x_probe(&spi->dev, type, irq, regmap);
+}
+
+static const struct spi_device_id pcm186x_spi_id[] = {
+	{ "pcm1862", PCM1862 },
+	{ "pcm1863", PCM1863 },
+	{ "pcm1864", PCM1864 },
+	{ "pcm1865", PCM1865 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, pcm186x_spi_id);
+
+static struct spi_driver pcm186x_spi_driver = {
+	.probe		= pcm186x_spi_probe,
+	.id_table	= pcm186x_spi_id,
+	.driver		= {
+		.name	= "pcm186x",
+		.of_match_table = pcm186x_of_match,
+	},
+};
+module_spi_driver(pcm186x_spi_driver);
+
+MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
+MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_DESCRIPTION("PCM186x Universal Audio ADC SPI Interface Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c
new file mode 100644
index 0000000..690c26e
--- /dev/null
+++ b/sound/soc/codecs/pcm186x.c
@@ -0,0 +1,712 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments PCM186x Universal Audio ADC
+ *
+ * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
+ *	Andreas Dannenberg <dannenberg@ti.com>
+ *	Andrew F. Davis <afd@ti.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "pcm186x.h"
+
+static const char * const pcm186x_supply_names[] = {
+	"avdd",		/* Analog power supply. Connect to 3.3-V supply. */
+	"dvdd",		/* Digital power supply. Connect to 3.3-V supply. */
+	"iovdd",	/* I/O power supply. Connect to 3.3-V or 1.8-V. */
+};
+#define PCM186x_NUM_SUPPLIES ARRAY_SIZE(pcm186x_supply_names)
+
+struct pcm186x_priv {
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[PCM186x_NUM_SUPPLIES];
+	unsigned int sysclk;
+	unsigned int tdm_offset;
+	bool is_tdm_mode;
+	bool is_master_mode;
+};
+
+static const DECLARE_TLV_DB_SCALE(pcm186x_pga_tlv, -1200, 4000, 50);
+
+static const struct snd_kcontrol_new pcm1863_snd_controls[] = {
+	SOC_DOUBLE_R_S_TLV("ADC Capture Volume", PCM186X_PGA_VAL_CH1_L,
+			   PCM186X_PGA_VAL_CH1_R, 0, -24, 80, 7, 0,
+			   pcm186x_pga_tlv),
+};
+
+static const struct snd_kcontrol_new pcm1865_snd_controls[] = {
+	SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", PCM186X_PGA_VAL_CH1_L,
+			   PCM186X_PGA_VAL_CH1_R, 0, -24, 80, 7, 0,
+			   pcm186x_pga_tlv),
+	SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", PCM186X_PGA_VAL_CH2_L,
+			   PCM186X_PGA_VAL_CH2_R, 0, -24, 80, 7, 0,
+			   pcm186x_pga_tlv),
+};
+
+static const unsigned int pcm186x_adc_input_channel_sel_value[] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+	0x10, 0x20, 0x30
+};
+
+static const char * const pcm186x_adcl_input_channel_sel_text[] = {
+	"No Select",
+	"VINL1[SE]",					/* Default for ADC1L */
+	"VINL2[SE]",					/* Default for ADC2L */
+	"VINL2[SE] + VINL1[SE]",
+	"VINL3[SE]",
+	"VINL3[SE] + VINL1[SE]",
+	"VINL3[SE] + VINL2[SE]",
+	"VINL3[SE] + VINL2[SE] + VINL1[SE]",
+	"VINL4[SE]",
+	"VINL4[SE] + VINL1[SE]",
+	"VINL4[SE] + VINL2[SE]",
+	"VINL4[SE] + VINL2[SE] + VINL1[SE]",
+	"VINL4[SE] + VINL3[SE]",
+	"VINL4[SE] + VINL3[SE] + VINL1[SE]",
+	"VINL4[SE] + VINL3[SE] + VINL2[SE]",
+	"VINL4[SE] + VINL3[SE] + VINL2[SE] + VINL1[SE]",
+	"{VIN1P, VIN1M}[DIFF]",
+	"{VIN4P, VIN4M}[DIFF]",
+	"{VIN1P, VIN1M}[DIFF] + {VIN4P, VIN4M}[DIFF]"
+};
+
+static const char * const pcm186x_adcr_input_channel_sel_text[] = {
+	"No Select",
+	"VINR1[SE]",					/* Default for ADC1R */
+	"VINR2[SE]",					/* Default for ADC2R */
+	"VINR2[SE] + VINR1[SE]",
+	"VINR3[SE]",
+	"VINR3[SE] + VINR1[SE]",
+	"VINR3[SE] + VINR2[SE]",
+	"VINR3[SE] + VINR2[SE] + VINR1[SE]",
+	"VINR4[SE]",
+	"VINR4[SE] + VINR1[SE]",
+	"VINR4[SE] + VINR2[SE]",
+	"VINR4[SE] + VINR2[SE] + VINR1[SE]",
+	"VINR4[SE] + VINR3[SE]",
+	"VINR4[SE] + VINR3[SE] + VINR1[SE]",
+	"VINR4[SE] + VINR3[SE] + VINR2[SE]",
+	"VINR4[SE] + VINR3[SE] + VINR2[SE] + VINR1[SE]",
+	"{VIN2P, VIN2M}[DIFF]",
+	"{VIN3P, VIN3M}[DIFF]",
+	"{VIN2P, VIN2M}[DIFF] + {VIN3P, VIN3M}[DIFF]"
+};
+
+static const struct soc_enum pcm186x_adc_input_channel_sel[] = {
+	SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0,
+			      PCM186X_ADC_INPUT_SEL_MASK,
+			      ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
+			      pcm186x_adcl_input_channel_sel_text,
+			      pcm186x_adc_input_channel_sel_value),
+	SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0,
+			      PCM186X_ADC_INPUT_SEL_MASK,
+			      ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
+			      pcm186x_adcr_input_channel_sel_text,
+			      pcm186x_adc_input_channel_sel_value),
+	SOC_VALUE_ENUM_SINGLE(PCM186X_ADC2_INPUT_SEL_L, 0,
+			      PCM186X_ADC_INPUT_SEL_MASK,
+			      ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
+			      pcm186x_adcl_input_channel_sel_text,
+			      pcm186x_adc_input_channel_sel_value),
+	SOC_VALUE_ENUM_SINGLE(PCM186X_ADC2_INPUT_SEL_R, 0,
+			      PCM186X_ADC_INPUT_SEL_MASK,
+			      ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
+			      pcm186x_adcr_input_channel_sel_text,
+			      pcm186x_adc_input_channel_sel_value),
+};
+
+static const struct snd_kcontrol_new pcm186x_adc_mux_controls[] = {
+	SOC_DAPM_ENUM("ADC1 Left Input", pcm186x_adc_input_channel_sel[0]),
+	SOC_DAPM_ENUM("ADC1 Right Input", pcm186x_adc_input_channel_sel[1]),
+	SOC_DAPM_ENUM("ADC2 Left Input", pcm186x_adc_input_channel_sel[2]),
+	SOC_DAPM_ENUM("ADC2 Right Input", pcm186x_adc_input_channel_sel[3]),
+};
+
+static const struct snd_soc_dapm_widget pcm1863_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("VINL1"),
+	SND_SOC_DAPM_INPUT("VINR1"),
+	SND_SOC_DAPM_INPUT("VINL2"),
+	SND_SOC_DAPM_INPUT("VINR2"),
+	SND_SOC_DAPM_INPUT("VINL3"),
+	SND_SOC_DAPM_INPUT("VINR3"),
+	SND_SOC_DAPM_INPUT("VINL4"),
+	SND_SOC_DAPM_INPUT("VINR4"),
+
+	SND_SOC_DAPM_MUX("ADC Left Capture Source", SND_SOC_NOPM, 0, 0,
+			 &pcm186x_adc_mux_controls[0]),
+	SND_SOC_DAPM_MUX("ADC Right Capture Source", SND_SOC_NOPM, 0, 0,
+			 &pcm186x_adc_mux_controls[1]),
+
+	/*
+	 * Put the codec into SLEEP mode when not in use, allowing the
+	 * Energysense mechanism to operate.
+	 */
+	SND_SOC_DAPM_ADC("ADC", "HiFi Capture", PCM186X_POWER_CTRL, 1,  0),
+};
+
+static const struct snd_soc_dapm_widget pcm1865_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("VINL1"),
+	SND_SOC_DAPM_INPUT("VINR1"),
+	SND_SOC_DAPM_INPUT("VINL2"),
+	SND_SOC_DAPM_INPUT("VINR2"),
+	SND_SOC_DAPM_INPUT("VINL3"),
+	SND_SOC_DAPM_INPUT("VINR3"),
+	SND_SOC_DAPM_INPUT("VINL4"),
+	SND_SOC_DAPM_INPUT("VINR4"),
+
+	SND_SOC_DAPM_MUX("ADC1 Left Capture Source", SND_SOC_NOPM, 0, 0,
+			 &pcm186x_adc_mux_controls[0]),
+	SND_SOC_DAPM_MUX("ADC1 Right Capture Source", SND_SOC_NOPM, 0, 0,
+			 &pcm186x_adc_mux_controls[1]),
+	SND_SOC_DAPM_MUX("ADC2 Left Capture Source", SND_SOC_NOPM, 0, 0,
+			 &pcm186x_adc_mux_controls[2]),
+	SND_SOC_DAPM_MUX("ADC2 Right Capture Source", SND_SOC_NOPM, 0, 0,
+			 &pcm186x_adc_mux_controls[3]),
+
+	/*
+	 * Put the codec into SLEEP mode when not in use, allowing the
+	 * Energysense mechanism to operate.
+	 */
+	SND_SOC_DAPM_ADC("ADC1", "HiFi Capture 1", PCM186X_POWER_CTRL, 1,  0),
+	SND_SOC_DAPM_ADC("ADC2", "HiFi Capture 2", PCM186X_POWER_CTRL, 1,  0),
+};
+
+static const struct snd_soc_dapm_route pcm1863_dapm_routes[] = {
+	{ "ADC Left Capture Source", NULL, "VINL1" },
+	{ "ADC Left Capture Source", NULL, "VINR1" },
+	{ "ADC Left Capture Source", NULL, "VINL2" },
+	{ "ADC Left Capture Source", NULL, "VINR2" },
+	{ "ADC Left Capture Source", NULL, "VINL3" },
+	{ "ADC Left Capture Source", NULL, "VINR3" },
+	{ "ADC Left Capture Source", NULL, "VINL4" },
+	{ "ADC Left Capture Source", NULL, "VINR4" },
+
+	{ "ADC", NULL, "ADC Left Capture Source" },
+
+	{ "ADC Right Capture Source", NULL, "VINL1" },
+	{ "ADC Right Capture Source", NULL, "VINR1" },
+	{ "ADC Right Capture Source", NULL, "VINL2" },
+	{ "ADC Right Capture Source", NULL, "VINR2" },
+	{ "ADC Right Capture Source", NULL, "VINL3" },
+	{ "ADC Right Capture Source", NULL, "VINR3" },
+	{ "ADC Right Capture Source", NULL, "VINL4" },
+	{ "ADC Right Capture Source", NULL, "VINR4" },
+
+	{ "ADC", NULL, "ADC Right Capture Source" },
+};
+
+static const struct snd_soc_dapm_route pcm1865_dapm_routes[] = {
+	{ "ADC1 Left Capture Source", NULL, "VINL1" },
+	{ "ADC1 Left Capture Source", NULL, "VINR1" },
+	{ "ADC1 Left Capture Source", NULL, "VINL2" },
+	{ "ADC1 Left Capture Source", NULL, "VINR2" },
+	{ "ADC1 Left Capture Source", NULL, "VINL3" },
+	{ "ADC1 Left Capture Source", NULL, "VINR3" },
+	{ "ADC1 Left Capture Source", NULL, "VINL4" },
+	{ "ADC1 Left Capture Source", NULL, "VINR4" },
+
+	{ "ADC1", NULL, "ADC1 Left Capture Source" },
+
+	{ "ADC1 Right Capture Source", NULL, "VINL1" },
+	{ "ADC1 Right Capture Source", NULL, "VINR1" },
+	{ "ADC1 Right Capture Source", NULL, "VINL2" },
+	{ "ADC1 Right Capture Source", NULL, "VINR2" },
+	{ "ADC1 Right Capture Source", NULL, "VINL3" },
+	{ "ADC1 Right Capture Source", NULL, "VINR3" },
+	{ "ADC1 Right Capture Source", NULL, "VINL4" },
+	{ "ADC1 Right Capture Source", NULL, "VINR4" },
+
+	{ "ADC1", NULL, "ADC1 Right Capture Source" },
+
+	{ "ADC2 Left Capture Source", NULL, "VINL1" },
+	{ "ADC2 Left Capture Source", NULL, "VINR1" },
+	{ "ADC2 Left Capture Source", NULL, "VINL2" },
+	{ "ADC2 Left Capture Source", NULL, "VINR2" },
+	{ "ADC2 Left Capture Source", NULL, "VINL3" },
+	{ "ADC2 Left Capture Source", NULL, "VINR3" },
+	{ "ADC2 Left Capture Source", NULL, "VINL4" },
+	{ "ADC2 Left Capture Source", NULL, "VINR4" },
+
+	{ "ADC2", NULL, "ADC2 Left Capture Source" },
+
+	{ "ADC2 Right Capture Source", NULL, "VINL1" },
+	{ "ADC2 Right Capture Source", NULL, "VINR1" },
+	{ "ADC2 Right Capture Source", NULL, "VINL2" },
+	{ "ADC2 Right Capture Source", NULL, "VINR2" },
+	{ "ADC2 Right Capture Source", NULL, "VINL3" },
+	{ "ADC2 Right Capture Source", NULL, "VINR3" },
+	{ "ADC2 Right Capture Source", NULL, "VINL4" },
+	{ "ADC2 Right Capture Source", NULL, "VINR4" },
+
+	{ "ADC2", NULL, "ADC2 Right Capture Source" },
+};
+
+static int pcm186x_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
+	unsigned int rate = params_rate(params);
+	snd_pcm_format_t format = params_format(params);
+	unsigned int width = params_width(params);
+	unsigned int channels = params_channels(params);
+	unsigned int div_lrck;
+	unsigned int div_bck;
+	u8 tdm_tx_sel = 0;
+	u8 pcm_cfg = 0;
+
+	dev_dbg(component->dev, "%s() rate=%u format=0x%x width=%u channels=%u\n",
+		__func__, rate, format, width, channels);
+
+	switch (width) {
+	case 16:
+		pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_16 <<
+			  PCM186X_PCM_CFG_RX_WLEN_SHIFT |
+			  PCM186X_PCM_CFG_TX_WLEN_16 <<
+			  PCM186X_PCM_CFG_TX_WLEN_SHIFT;
+		break;
+	case 20:
+		pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_20 <<
+			  PCM186X_PCM_CFG_RX_WLEN_SHIFT |
+			  PCM186X_PCM_CFG_TX_WLEN_20 <<
+			  PCM186X_PCM_CFG_TX_WLEN_SHIFT;
+		break;
+	case 24:
+		pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_24 <<
+			  PCM186X_PCM_CFG_RX_WLEN_SHIFT |
+			  PCM186X_PCM_CFG_TX_WLEN_24 <<
+			  PCM186X_PCM_CFG_TX_WLEN_SHIFT;
+		break;
+	case 32:
+		pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_32 <<
+			  PCM186X_PCM_CFG_RX_WLEN_SHIFT |
+			  PCM186X_PCM_CFG_TX_WLEN_32 <<
+			  PCM186X_PCM_CFG_TX_WLEN_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
+			    PCM186X_PCM_CFG_RX_WLEN_MASK |
+			    PCM186X_PCM_CFG_TX_WLEN_MASK,
+			    pcm_cfg);
+
+	div_lrck = width * channels;
+
+	if (priv->is_tdm_mode) {
+		/* Select TDM transmission data */
+		switch (channels) {
+		case 2:
+			tdm_tx_sel = PCM186X_TDM_TX_SEL_2CH;
+			break;
+		case 4:
+			tdm_tx_sel = PCM186X_TDM_TX_SEL_4CH;
+			break;
+		case 6:
+			tdm_tx_sel = PCM186X_TDM_TX_SEL_6CH;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		snd_soc_component_update_bits(component, PCM186X_TDM_TX_SEL,
+				    PCM186X_TDM_TX_SEL_MASK, tdm_tx_sel);
+
+		/* In DSP/TDM mode, the LRCLK divider must be 256 */
+		div_lrck = 256;
+
+		/* Configure 1/256 duty cycle for LRCK */
+		snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
+				    PCM186X_PCM_CFG_TDM_LRCK_MODE,
+				    PCM186X_PCM_CFG_TDM_LRCK_MODE);
+	}
+
+	/* Only configure clock dividers in master mode. */
+	if (priv->is_master_mode) {
+		div_bck = priv->sysclk / (div_lrck * rate);
+
+		dev_dbg(component->dev,
+			"%s() master_clk=%u div_bck=%u div_lrck=%u\n",
+			__func__, priv->sysclk, div_bck, div_lrck);
+
+		snd_soc_component_write(component, PCM186X_BCK_DIV, div_bck - 1);
+		snd_soc_component_write(component, PCM186X_LRK_DIV, div_lrck - 1);
+	}
+
+	return 0;
+}
+
+static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
+	u8 clk_ctrl = 0;
+	u8 pcm_cfg = 0;
+
+	dev_dbg(component->dev, "%s() format=0x%x\n", __func__, format);
+
+	/* set master/slave audio interface */
+	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		if (!priv->sysclk) {
+			dev_err(component->dev, "operating in master mode requires sysclock to be configured\n");
+			return -EINVAL;
+		}
+		clk_ctrl |= PCM186X_CLK_CTRL_MST_MODE;
+		priv->is_master_mode = true;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		priv->is_master_mode = false;
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI master/slave interface\n");
+		return -EINVAL;
+	}
+
+	/* set interface polarity */
+	switch (format & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		dev_err(component->dev, "Inverted DAI clocks not supported\n");
+		return -EINVAL;
+	}
+
+	/* set interface format */
+	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		pcm_cfg = PCM186X_PCM_CFG_FMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		pcm_cfg = PCM186X_PCM_CFG_FMT_LEFTJ;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		priv->tdm_offset += 1;
+		/* Fall through... DSP_A uses the same basic config as DSP_B
+		 * except we need to shift the TDM output by one BCK cycle
+		 */
+	case SND_SOC_DAIFMT_DSP_B:
+		priv->is_tdm_mode = true;
+		pcm_cfg = PCM186X_PCM_CFG_FMT_TDM;
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, PCM186X_CLK_CTRL,
+			    PCM186X_CLK_CTRL_MST_MODE, clk_ctrl);
+
+	snd_soc_component_write(component, PCM186X_TDM_TX_OFFSET, priv->tdm_offset);
+
+	snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
+			    PCM186X_PCM_CFG_FMT_MASK, pcm_cfg);
+
+	return 0;
+}
+
+static int pcm186x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+				unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
+	unsigned int first_slot, last_slot, tdm_offset;
+
+	dev_dbg(component->dev,
+		"%s() tx_mask=0x%x rx_mask=0x%x slots=%d slot_width=%d\n",
+		__func__, tx_mask, rx_mask, slots, slot_width);
+
+	if (!tx_mask) {
+		dev_err(component->dev, "tdm tx mask must not be 0\n");
+		return -EINVAL;
+	}
+
+	first_slot = __ffs(tx_mask);
+	last_slot = __fls(tx_mask);
+
+	if (last_slot - first_slot != hweight32(tx_mask) - 1) {
+		dev_err(component->dev, "tdm tx mask must be contiguous\n");
+		return -EINVAL;
+	}
+
+	tdm_offset = first_slot * slot_width;
+
+	if (tdm_offset > 255) {
+		dev_err(component->dev, "tdm tx slot selection out of bounds\n");
+		return -EINVAL;
+	}
+
+	priv->tdm_offset = tdm_offset;
+
+	return 0;
+}
+
+static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+				  unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "%s() clk_id=%d freq=%u dir=%d\n",
+		__func__, clk_id, freq, dir);
+
+	priv->sysclk = freq;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops pcm186x_dai_ops = {
+	.set_sysclk = pcm186x_set_dai_sysclk,
+	.set_tdm_slot = pcm186x_set_tdm_slot,
+	.set_fmt = pcm186x_set_fmt,
+	.hw_params = pcm186x_hw_params,
+};
+
+static struct snd_soc_dai_driver pcm1863_dai = {
+	.name = "pcm1863-aif",
+	.capture = {
+		 .stream_name = "Capture",
+		 .channels_min = 1,
+		 .channels_max = 2,
+		 .rates = PCM186X_RATES,
+		 .formats = PCM186X_FORMATS,
+	 },
+	.ops = &pcm186x_dai_ops,
+};
+
+static struct snd_soc_dai_driver pcm1865_dai = {
+	.name = "pcm1865-aif",
+	.capture = {
+		 .stream_name = "Capture",
+		 .channels_min = 1,
+		 .channels_max = 4,
+		 .rates = PCM186X_RATES,
+		 .formats = PCM186X_FORMATS,
+	 },
+	.ops = &pcm186x_dai_ops,
+};
+
+static int pcm186x_power_on(struct snd_soc_component *component)
+{
+	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
+				    priv->supplies);
+	if (ret)
+		return ret;
+
+	regcache_cache_only(priv->regmap, false);
+	ret = regcache_sync(priv->regmap);
+	if (ret) {
+		dev_err(component->dev, "Failed to restore cache\n");
+		regcache_cache_only(priv->regmap, true);
+		regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
+				       priv->supplies);
+		return ret;
+	}
+
+	snd_soc_component_update_bits(component, PCM186X_POWER_CTRL,
+			    PCM186X_PWR_CTRL_PWRDN, 0);
+
+	return 0;
+}
+
+static int pcm186x_power_off(struct snd_soc_component *component)
+{
+	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	snd_soc_component_update_bits(component, PCM186X_POWER_CTRL,
+			    PCM186X_PWR_CTRL_PWRDN, PCM186X_PWR_CTRL_PWRDN);
+
+	regcache_cache_only(priv->regmap, true);
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
+				     priv->supplies);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int pcm186x_set_bias_level(struct snd_soc_component *component,
+				  enum snd_soc_bias_level level)
+{
+	dev_dbg(component->dev, "## %s: %d -> %d\n", __func__,
+		snd_soc_component_get_bias_level(component), level);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			pcm186x_power_on(component);
+		break;
+	case SND_SOC_BIAS_OFF:
+		pcm186x_power_off(component);
+		break;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_component_driver soc_codec_dev_pcm1863 = {
+	.set_bias_level		= pcm186x_set_bias_level,
+	.controls		= pcm1863_snd_controls,
+	.num_controls		= ARRAY_SIZE(pcm1863_snd_controls),
+	.dapm_widgets		= pcm1863_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm1863_dapm_widgets),
+	.dapm_routes		= pcm1863_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm1863_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static struct snd_soc_component_driver soc_codec_dev_pcm1865 = {
+	.set_bias_level		= pcm186x_set_bias_level,
+	.controls		= pcm1865_snd_controls,
+	.num_controls		= ARRAY_SIZE(pcm1865_snd_controls),
+	.dapm_widgets		= pcm1865_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm1865_dapm_widgets),
+	.dapm_routes		= pcm1865_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm1865_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static bool pcm186x_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case PCM186X_PAGE:
+	case PCM186X_DEVICE_STATUS:
+	case PCM186X_FSAMPLE_STATUS:
+	case PCM186X_DIV_STATUS:
+	case PCM186X_CLK_STATUS:
+	case PCM186X_SUPPLY_STATUS:
+	case PCM186X_MMAP_STAT_CTRL:
+	case PCM186X_MMAP_ADDRESS:
+		return true;
+	}
+
+	return false;
+}
+
+static const struct regmap_range_cfg pcm186x_range = {
+	.name = "Pages",
+	.range_max = PCM186X_MAX_REGISTER,
+	.selector_reg = PCM186X_PAGE,
+	.selector_mask = 0xff,
+	.window_len = PCM186X_PAGE_LEN,
+};
+
+const struct regmap_config pcm186x_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.volatile_reg = pcm186x_volatile,
+
+	.ranges = &pcm186x_range,
+	.num_ranges = 1,
+
+	.max_register = PCM186X_MAX_REGISTER,
+
+	.cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(pcm186x_regmap);
+
+int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq,
+		  struct regmap *regmap)
+{
+	struct pcm186x_priv *priv;
+	int i, ret;
+
+	priv = devm_kzalloc(dev, sizeof(struct pcm186x_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, priv);
+	priv->regmap = regmap;
+
+	for (i = 0; i < ARRAY_SIZE(priv->supplies); i++)
+		priv->supplies[i].supply = pcm186x_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
+				      priv->supplies);
+	if (ret) {
+		dev_err(dev, "failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
+				    priv->supplies);
+	if (ret) {
+		dev_err(dev, "failed enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	/* Reset device registers for a consistent power-on like state */
+	ret = regmap_write(regmap, PCM186X_PAGE, PCM186X_RESET);
+	if (ret) {
+		dev_err(dev, "failed to write device: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
+				     priv->supplies);
+	if (ret) {
+		dev_err(dev, "failed disable supplies: %d\n", ret);
+		return ret;
+	}
+
+	switch (type) {
+	case PCM1865:
+	case PCM1864:
+		ret = devm_snd_soc_register_component(dev, &soc_codec_dev_pcm1865,
+					     &pcm1865_dai, 1);
+		break;
+	case PCM1863:
+	case PCM1862:
+	default:
+		ret = devm_snd_soc_register_component(dev, &soc_codec_dev_pcm1863,
+					     &pcm1863_dai, 1);
+	}
+	if (ret) {
+		dev_err(dev, "failed to register CODEC: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pcm186x_probe);
+
+MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
+MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_DESCRIPTION("PCM186x Universal Audio ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm186x.h b/sound/soc/codecs/pcm186x.h
new file mode 100644
index 0000000..bb3f0c4
--- /dev/null
+++ b/sound/soc/codecs/pcm186x.h
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments PCM186x Universal Audio ADC
+ *
+ * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
+ *	Andreas Dannenberg <dannenberg@ti.com>
+ *	Andrew F. Davis <afd@ti.com>
+ */
+
+#ifndef _PCM186X_H_
+#define _PCM186X_H_
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+enum pcm186x_type {
+	PCM1862,
+	PCM1863,
+	PCM1864,
+	PCM1865,
+};
+
+#define PCM186X_RATES	SNDRV_PCM_RATE_8000_192000
+#define PCM186X_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
+			 SNDRV_PCM_FMTBIT_S20_3LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE | \
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+#define PCM186X_PAGE_LEN		0x0100
+#define PCM186X_PAGE_BASE(n)		(PCM186X_PAGE_LEN * n)
+
+/* The page selection register address is the same on all pages */
+#define PCM186X_PAGE			0
+
+/* Register Definitions - Page 0 */
+#define PCM186X_PGA_VAL_CH1_L		(PCM186X_PAGE_BASE(0) +   1)
+#define PCM186X_PGA_VAL_CH1_R		(PCM186X_PAGE_BASE(0) +   2)
+#define PCM186X_PGA_VAL_CH2_L		(PCM186X_PAGE_BASE(0) +   3)
+#define PCM186X_PGA_VAL_CH2_R		(PCM186X_PAGE_BASE(0) +   4)
+#define PCM186X_PGA_CTRL		(PCM186X_PAGE_BASE(0) +   5)
+#define PCM186X_ADC1_INPUT_SEL_L	(PCM186X_PAGE_BASE(0) +   6)
+#define PCM186X_ADC1_INPUT_SEL_R	(PCM186X_PAGE_BASE(0) +   7)
+#define PCM186X_ADC2_INPUT_SEL_L	(PCM186X_PAGE_BASE(0) +   8)
+#define PCM186X_ADC2_INPUT_SEL_R	(PCM186X_PAGE_BASE(0) +   9)
+#define PCM186X_AUXADC_INPUT_SEL	(PCM186X_PAGE_BASE(0) +  10)
+#define PCM186X_PCM_CFG			(PCM186X_PAGE_BASE(0) +  11)
+#define PCM186X_TDM_TX_SEL		(PCM186X_PAGE_BASE(0) +  12)
+#define PCM186X_TDM_TX_OFFSET		(PCM186X_PAGE_BASE(0) +  13)
+#define PCM186X_TDM_RX_OFFSET		(PCM186X_PAGE_BASE(0) +  14)
+#define PCM186X_DPGA_VAL_CH1_L		(PCM186X_PAGE_BASE(0) +  15)
+#define PCM186X_GPIO1_0_CTRL		(PCM186X_PAGE_BASE(0) +  16)
+#define PCM186X_GPIO3_2_CTRL		(PCM186X_PAGE_BASE(0) +  17)
+#define PCM186X_GPIO1_0_DIR_CTRL	(PCM186X_PAGE_BASE(0) +  18)
+#define PCM186X_GPIO3_2_DIR_CTRL	(PCM186X_PAGE_BASE(0) +  19)
+#define PCM186X_GPIO_IN_OUT		(PCM186X_PAGE_BASE(0) +  20)
+#define PCM186X_GPIO_PULL_CTRL		(PCM186X_PAGE_BASE(0) +  21)
+#define PCM186X_DPGA_VAL_CH1_R		(PCM186X_PAGE_BASE(0) +  22)
+#define PCM186X_DPGA_VAL_CH2_L		(PCM186X_PAGE_BASE(0) +  23)
+#define PCM186X_DPGA_VAL_CH2_R		(PCM186X_PAGE_BASE(0) +  24)
+#define PCM186X_DPGA_GAIN_CTRL		(PCM186X_PAGE_BASE(0) +  25)
+#define PCM186X_DPGA_MIC_CTRL		(PCM186X_PAGE_BASE(0) +  26)
+#define PCM186X_DIN_RESAMP_CTRL		(PCM186X_PAGE_BASE(0) +  27)
+#define PCM186X_CLK_CTRL		(PCM186X_PAGE_BASE(0) +  32)
+#define PCM186X_DSP1_CLK_DIV		(PCM186X_PAGE_BASE(0) +  33)
+#define PCM186X_DSP2_CLK_DIV		(PCM186X_PAGE_BASE(0) +  34)
+#define PCM186X_ADC_CLK_DIV		(PCM186X_PAGE_BASE(0) +  35)
+#define PCM186X_PLL_SCK_DIV		(PCM186X_PAGE_BASE(0) +  37)
+#define PCM186X_BCK_DIV			(PCM186X_PAGE_BASE(0) +  38)
+#define PCM186X_LRK_DIV			(PCM186X_PAGE_BASE(0) +  39)
+#define PCM186X_PLL_CTRL		(PCM186X_PAGE_BASE(0) +  40)
+#define PCM186X_PLL_P_DIV		(PCM186X_PAGE_BASE(0) +  41)
+#define PCM186X_PLL_R_DIV		(PCM186X_PAGE_BASE(0) +  42)
+#define PCM186X_PLL_J_DIV		(PCM186X_PAGE_BASE(0) +  43)
+#define PCM186X_PLL_D_DIV_LSB		(PCM186X_PAGE_BASE(0) +  44)
+#define PCM186X_PLL_D_DIV_MSB		(PCM186X_PAGE_BASE(0) +  45)
+#define PCM186X_SIGDET_MODE		(PCM186X_PAGE_BASE(0) +  48)
+#define PCM186X_SIGDET_MASK		(PCM186X_PAGE_BASE(0) +  49)
+#define PCM186X_SIGDET_STAT		(PCM186X_PAGE_BASE(0) +  50)
+#define PCM186X_SIGDET_LOSS_TIME	(PCM186X_PAGE_BASE(0) +  52)
+#define PCM186X_SIGDET_SCAN_TIME	(PCM186X_PAGE_BASE(0) +  53)
+#define PCM186X_SIGDET_INT_INTVL	(PCM186X_PAGE_BASE(0) +  54)
+#define PCM186X_SIGDET_DC_REF_CH1_L	(PCM186X_PAGE_BASE(0) +  64)
+#define PCM186X_SIGDET_DC_DIFF_CH1_L	(PCM186X_PAGE_BASE(0) +  65)
+#define PCM186X_SIGDET_DC_LEV_CH1_L	(PCM186X_PAGE_BASE(0) +  66)
+#define PCM186X_SIGDET_DC_REF_CH1_R	(PCM186X_PAGE_BASE(0) +  67)
+#define PCM186X_SIGDET_DC_DIFF_CH1_R	(PCM186X_PAGE_BASE(0) +  68)
+#define PCM186X_SIGDET_DC_LEV_CH1_R	(PCM186X_PAGE_BASE(0) +  69)
+#define PCM186X_SIGDET_DC_REF_CH2_L	(PCM186X_PAGE_BASE(0) +  70)
+#define PCM186X_SIGDET_DC_DIFF_CH2_L	(PCM186X_PAGE_BASE(0) +  71)
+#define PCM186X_SIGDET_DC_LEV_CH2_L	(PCM186X_PAGE_BASE(0) +  72)
+#define PCM186X_SIGDET_DC_REF_CH2_R	(PCM186X_PAGE_BASE(0) +  73)
+#define PCM186X_SIGDET_DC_DIFF_CH2_R	(PCM186X_PAGE_BASE(0) +  74)
+#define PCM186X_SIGDET_DC_LEV_CH2_R	(PCM186X_PAGE_BASE(0) +  75)
+#define PCM186X_SIGDET_DC_REF_CH3_L	(PCM186X_PAGE_BASE(0) +  76)
+#define PCM186X_SIGDET_DC_DIFF_CH3_L	(PCM186X_PAGE_BASE(0) +  77)
+#define PCM186X_SIGDET_DC_LEV_CH3_L	(PCM186X_PAGE_BASE(0) +  78)
+#define PCM186X_SIGDET_DC_REF_CH3_R	(PCM186X_PAGE_BASE(0) +  79)
+#define PCM186X_SIGDET_DC_DIFF_CH3_R	(PCM186X_PAGE_BASE(0) +  80)
+#define PCM186X_SIGDET_DC_LEV_CH3_R	(PCM186X_PAGE_BASE(0) +  81)
+#define PCM186X_SIGDET_DC_REF_CH4_L	(PCM186X_PAGE_BASE(0) +  82)
+#define PCM186X_SIGDET_DC_DIFF_CH4_L	(PCM186X_PAGE_BASE(0) +  83)
+#define PCM186X_SIGDET_DC_LEV_CH4_L	(PCM186X_PAGE_BASE(0) +  84)
+#define PCM186X_SIGDET_DC_REF_CH4_R	(PCM186X_PAGE_BASE(0) +  85)
+#define PCM186X_SIGDET_DC_DIFF_CH4_R	(PCM186X_PAGE_BASE(0) +  86)
+#define PCM186X_SIGDET_DC_LEV_CH4_R	(PCM186X_PAGE_BASE(0) +  87)
+#define PCM186X_AUXADC_DATA_CTRL	(PCM186X_PAGE_BASE(0) +  88)
+#define PCM186X_AUXADC_DATA_LSB		(PCM186X_PAGE_BASE(0) +  89)
+#define PCM186X_AUXADC_DATA_MSB		(PCM186X_PAGE_BASE(0) +  90)
+#define PCM186X_INT_ENABLE		(PCM186X_PAGE_BASE(0) +  96)
+#define PCM186X_INT_FLAG		(PCM186X_PAGE_BASE(0) +  97)
+#define PCM186X_INT_POL_WIDTH		(PCM186X_PAGE_BASE(0) +  98)
+#define PCM186X_POWER_CTRL		(PCM186X_PAGE_BASE(0) + 112)
+#define PCM186X_FILTER_MUTE_CTRL	(PCM186X_PAGE_BASE(0) + 113)
+#define PCM186X_DEVICE_STATUS		(PCM186X_PAGE_BASE(0) + 114)
+#define PCM186X_FSAMPLE_STATUS		(PCM186X_PAGE_BASE(0) + 115)
+#define PCM186X_DIV_STATUS		(PCM186X_PAGE_BASE(0) + 116)
+#define PCM186X_CLK_STATUS		(PCM186X_PAGE_BASE(0) + 117)
+#define PCM186X_SUPPLY_STATUS		(PCM186X_PAGE_BASE(0) + 120)
+
+/* Register Definitions - Page 1 */
+#define PCM186X_MMAP_STAT_CTRL		(PCM186X_PAGE_BASE(1) +   1)
+#define PCM186X_MMAP_ADDRESS		(PCM186X_PAGE_BASE(1) +   2)
+#define PCM186X_MEM_WDATA0		(PCM186X_PAGE_BASE(1) +   4)
+#define PCM186X_MEM_WDATA1		(PCM186X_PAGE_BASE(1) +   5)
+#define PCM186X_MEM_WDATA2		(PCM186X_PAGE_BASE(1) +   6)
+#define PCM186X_MEM_WDATA3		(PCM186X_PAGE_BASE(1) +   7)
+#define PCM186X_MEM_RDATA0		(PCM186X_PAGE_BASE(1) +   8)
+#define PCM186X_MEM_RDATA1		(PCM186X_PAGE_BASE(1) +   9)
+#define PCM186X_MEM_RDATA2		(PCM186X_PAGE_BASE(1) +  10)
+#define PCM186X_MEM_RDATA3		(PCM186X_PAGE_BASE(1) +  11)
+
+/* Register Definitions - Page 3 */
+#define PCM186X_OSC_PWR_DOWN_CTRL	(PCM186X_PAGE_BASE(3) +  18)
+#define PCM186X_MIC_BIAS_CTRL		(PCM186X_PAGE_BASE(3) +  21)
+
+/* Register Definitions - Page 253 */
+#define PCM186X_CURR_TRIM_CTRL		(PCM186X_PAGE_BASE(253) +  20)
+
+#define PCM186X_MAX_REGISTER		PCM186X_CURR_TRIM_CTRL
+
+/* PCM186X_PAGE */
+#define PCM186X_RESET			0xfe
+
+/* PCM186X_ADCX_INPUT_SEL_X */
+#define PCM186X_ADC_INPUT_SEL_POL	BIT(7)
+#define PCM186X_ADC_INPUT_SEL_MASK	GENMASK(5, 0)
+
+/* PCM186X_PCM_CFG */
+#define PCM186X_PCM_CFG_RX_WLEN_MASK	GENMASK(7, 6)
+#define PCM186X_PCM_CFG_RX_WLEN_SHIFT	6
+#define PCM186X_PCM_CFG_RX_WLEN_32	0x00
+#define PCM186X_PCM_CFG_RX_WLEN_24	0x01
+#define PCM186X_PCM_CFG_RX_WLEN_20	0x02
+#define PCM186X_PCM_CFG_RX_WLEN_16	0x03
+#define PCM186X_PCM_CFG_TDM_LRCK_MODE	BIT(4)
+#define PCM186X_PCM_CFG_TX_WLEN_MASK	GENMASK(3, 2)
+#define PCM186X_PCM_CFG_TX_WLEN_SHIFT	2
+#define PCM186X_PCM_CFG_TX_WLEN_32	0x00
+#define PCM186X_PCM_CFG_TX_WLEN_24	0x01
+#define PCM186X_PCM_CFG_TX_WLEN_20	0x02
+#define PCM186X_PCM_CFG_TX_WLEN_16	0x03
+#define PCM186X_PCM_CFG_FMT_MASK	GENMASK(1, 0)
+#define PCM186X_PCM_CFG_FMT_SHIFT	0
+#define PCM186X_PCM_CFG_FMT_I2S		0x00
+#define PCM186X_PCM_CFG_FMT_LEFTJ	0x01
+#define PCM186X_PCM_CFG_FMT_RIGHTJ	0x02
+#define PCM186X_PCM_CFG_FMT_TDM		0x03
+
+/* PCM186X_TDM_TX_SEL */
+#define PCM186X_TDM_TX_SEL_2CH		0x00
+#define PCM186X_TDM_TX_SEL_4CH		0x01
+#define PCM186X_TDM_TX_SEL_6CH		0x02
+#define PCM186X_TDM_TX_SEL_MASK		0x03
+
+/* PCM186X_CLK_CTRL */
+#define PCM186X_CLK_CTRL_SCK_XI_SEL1	BIT(7)
+#define PCM186X_CLK_CTRL_SCK_XI_SEL0	BIT(6)
+#define PCM186X_CLK_CTRL_SCK_SRC_PLL	BIT(5)
+#define PCM186X_CLK_CTRL_MST_MODE	BIT(4)
+#define PCM186X_CLK_CTRL_ADC_SRC_PLL	BIT(3)
+#define PCM186X_CLK_CTRL_DSP2_SRC_PLL	BIT(2)
+#define PCM186X_CLK_CTRL_DSP1_SRC_PLL	BIT(1)
+#define PCM186X_CLK_CTRL_CLKDET_EN	BIT(0)
+
+/* PCM186X_PLL_CTRL */
+#define PCM186X_PLL_CTRL_LOCK		BIT(4)
+#define PCM186X_PLL_CTRL_REF_SEL	BIT(1)
+#define PCM186X_PLL_CTRL_EN		BIT(0)
+
+/* PCM186X_POWER_CTRL */
+#define PCM186X_PWR_CTRL_PWRDN		BIT(2)
+#define PCM186X_PWR_CTRL_SLEEP		BIT(1)
+#define PCM186X_PWR_CTRL_STBY		BIT(0)
+
+/* PCM186X_CLK_STATUS */
+#define PCM186X_CLK_STATUS_LRCKHLT	BIT(6)
+#define PCM186X_CLK_STATUS_BCKHLT	BIT(5)
+#define PCM186X_CLK_STATUS_SCKHLT	BIT(4)
+#define PCM186X_CLK_STATUS_LRCKERR	BIT(2)
+#define PCM186X_CLK_STATUS_BCKERR	BIT(1)
+#define PCM186X_CLK_STATUS_SCKERR	BIT(0)
+
+/* PCM186X_SUPPLY_STATUS */
+#define PCM186X_SUPPLY_STATUS_DVDD	BIT(2)
+#define PCM186X_SUPPLY_STATUS_AVDD	BIT(1)
+#define PCM186X_SUPPLY_STATUS_LDO	BIT(0)
+
+/* PCM186X_MMAP_STAT_CTRL */
+#define PCM186X_MMAP_STAT_DONE		BIT(4)
+#define PCM186X_MMAP_STAT_BUSY		BIT(2)
+#define PCM186X_MMAP_STAT_R_REQ		BIT(1)
+#define PCM186X_MMAP_STAT_W_REQ		BIT(0)
+
+extern const struct regmap_config pcm186x_regmap;
+
+int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq,
+		  struct regmap *regmap);
+
+#endif /* _PCM186X_H_ */
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
new file mode 100644
index 0000000..c6ce9bd
--- /dev/null
+++ b/sound/soc/codecs/pcm3008.c
@@ -0,0 +1,168 @@
+/*
+ * ALSA Soc PCM3008 codec support
+ *
+ * Author:	Hugo Villeneuve
+ * Copyright (C) 2008 Lyrtech inc
+ *
+ * Based on AC97 Soc codec, original copyright follow:
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ *
+ *  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.
+ *
+ * Generic PCM3008 support.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "pcm3008.h"
+
+static int pcm3008_dac_ev(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol,
+			  int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct pcm3008_setup_data *setup = component->dev->platform_data;
+
+	gpio_set_value_cansleep(setup->pdda_pin,
+				SND_SOC_DAPM_EVENT_ON(event));
+
+	return 0;
+}
+
+static int pcm3008_adc_ev(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol,
+			  int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct pcm3008_setup_data *setup = component->dev->platform_data;
+
+	gpio_set_value_cansleep(setup->pdad_pin,
+				SND_SOC_DAPM_EVENT_ON(event));
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget pcm3008_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("VINL"),
+SND_SOC_DAPM_INPUT("VINR"),
+
+SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, pcm3008_dac_ev,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_ADC_E("ADC", NULL, SND_SOC_NOPM, 0, 0, pcm3008_adc_ev,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_OUTPUT("VOUTL"),
+SND_SOC_DAPM_OUTPUT("VOUTR"),
+};
+
+static const struct snd_soc_dapm_route pcm3008_dapm_routes[] = {
+	{ "PCM3008 Capture", NULL, "ADC" },
+	{ "ADC", NULL, "VINL" },
+	{ "ADC", NULL, "VINR" },
+
+	{ "DAC", NULL, "PCM3008 Playback" },
+	{ "VOUTL", NULL, "DAC" },
+	{ "VOUTR", NULL, "DAC" },
+};
+
+#define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |	\
+		       SNDRV_PCM_RATE_48000)
+
+static struct snd_soc_dai_driver pcm3008_dai = {
+	.name = "pcm3008-hifi",
+	.playback = {
+		.stream_name = "PCM3008 Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = PCM3008_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "PCM3008 Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = PCM3008_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_pcm3008 = {
+	.dapm_widgets		= pcm3008_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm3008_dapm_widgets),
+	.dapm_routes		= pcm3008_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm3008_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int pcm3008_codec_probe(struct platform_device *pdev)
+{
+	struct pcm3008_setup_data *setup = pdev->dev.platform_data;
+	int ret;
+
+	if (!setup)
+		return -EINVAL;
+
+	/* DEM1  DEM0  DE-EMPHASIS_MODE
+	 * Low   Low   De-emphasis 44.1 kHz ON
+	 * Low   High  De-emphasis OFF
+	 * High  Low   De-emphasis 48 kHz ON
+	 * High  High  De-emphasis 32 kHz ON
+	 */
+
+	/* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */
+	ret = devm_gpio_request_one(&pdev->dev, setup->dem0_pin,
+				    GPIOF_OUT_INIT_HIGH, "codec_dem0");
+	if (ret != 0)
+		return ret;
+
+	/* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */
+	ret = devm_gpio_request_one(&pdev->dev, setup->dem1_pin,
+				    GPIOF_OUT_INIT_LOW, "codec_dem1");
+	if (ret != 0)
+		return ret;
+
+	/* Configure PDAD GPIO. */
+	ret = devm_gpio_request_one(&pdev->dev, setup->pdad_pin,
+				    GPIOF_OUT_INIT_LOW, "codec_pdad");
+	if (ret != 0)
+		return ret;
+
+	/* Configure PDDA GPIO. */
+	ret = devm_gpio_request_one(&pdev->dev, setup->pdda_pin,
+				    GPIOF_OUT_INIT_LOW, "codec_pdda");
+	if (ret != 0)
+		return ret;
+
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_pcm3008, &pcm3008_dai, 1);
+}
+
+MODULE_ALIAS("platform:pcm3008-codec");
+
+static struct platform_driver pcm3008_codec_driver = {
+	.probe		= pcm3008_codec_probe,
+	.driver		= {
+		.name	= "pcm3008-codec",
+	},
+};
+
+module_platform_driver(pcm3008_codec_driver);
+
+MODULE_DESCRIPTION("Soc PCM3008 driver");
+MODULE_AUTHOR("Hugo Villeneuve");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm3008.h b/sound/soc/codecs/pcm3008.h
new file mode 100644
index 0000000..7e5489a
--- /dev/null
+++ b/sound/soc/codecs/pcm3008.h
@@ -0,0 +1,22 @@
+/*
+ * PCM3008 ALSA SoC Layer
+ *
+ * Author:	Hugo Villeneuve
+ * Copyright (C) 2008 Lyrtech inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_SOC_PCM3008_H
+#define __LINUX_SND_SOC_PCM3008_H
+
+struct pcm3008_setup_data {
+	unsigned dem0_pin;
+	unsigned dem1_pin;
+	unsigned pdad_pin;
+	unsigned pdda_pin;
+};
+
+#endif
diff --git a/sound/soc/codecs/pcm3168a-i2c.c b/sound/soc/codecs/pcm3168a-i2c.c
new file mode 100644
index 0000000..6feb090
--- /dev/null
+++ b/sound/soc/codecs/pcm3168a-i2c.c
@@ -0,0 +1,66 @@
+/*
+ * PCM3168A codec i2c driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <sound/soc.h>
+
+#include "pcm3168a.h"
+
+static int pcm3168a_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_i2c(i2c, &pcm3168a_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return pcm3168a_probe(&i2c->dev, regmap);
+}
+
+static int pcm3168a_i2c_remove(struct i2c_client *i2c)
+{
+	pcm3168a_remove(&i2c->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id pcm3168a_i2c_id[] = {
+	{ "pcm3168a", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pcm3168a_i2c_id);
+
+static const struct of_device_id pcm3168a_of_match[] = {
+	{ .compatible = "ti,pcm3168a", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm3168a_of_match);
+
+static struct i2c_driver pcm3168a_i2c_driver = {
+	.probe		= pcm3168a_i2c_probe,
+	.remove		= pcm3168a_i2c_remove,
+	.id_table	= pcm3168a_i2c_id,
+	.driver		= {
+		.name	= "pcm3168a",
+		.of_match_table = pcm3168a_of_match,
+		.pm		= &pcm3168a_pm_ops,
+	},
+};
+module_i2c_driver(pcm3168a_i2c_driver);
+
+MODULE_DESCRIPTION("PCM3168A I2C codec driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3168a-spi.c b/sound/soc/codecs/pcm3168a-spi.c
new file mode 100644
index 0000000..03945a2
--- /dev/null
+++ b/sound/soc/codecs/pcm3168a-spi.c
@@ -0,0 +1,65 @@
+/*
+ * PCM3168A codec spi driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include <sound/soc.h>
+
+#include "pcm3168a.h"
+
+static int pcm3168a_spi_probe(struct spi_device *spi)
+{
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_spi(spi, &pcm3168a_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return pcm3168a_probe(&spi->dev, regmap);
+}
+
+static int pcm3168a_spi_remove(struct spi_device *spi)
+{
+	pcm3168a_remove(&spi->dev);
+
+	return 0;
+}
+
+static const struct spi_device_id pcm3168a_spi_id[] = {
+	{ "pcm3168a", },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, pcm3168a_spi_id);
+
+static const struct of_device_id pcm3168a_of_match[] = {
+	{ .compatible = "ti,pcm3168a", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm3168a_of_match);
+
+static struct spi_driver pcm3168a_spi_driver = {
+	.probe		= pcm3168a_spi_probe,
+	.remove		= pcm3168a_spi_remove,
+	.id_table	= pcm3168a_spi_id,
+	.driver = {
+		.name	= "pcm3168a",
+		.of_match_table = pcm3168a_of_match,
+		.pm		= &pcm3168a_pm_ops,
+	},
+};
+module_spi_driver(pcm3168a_spi_driver);
+
+MODULE_DESCRIPTION("PCM3168A SPI codec driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
new file mode 100644
index 0000000..3356c91
--- /dev/null
+++ b/sound/soc/codecs/pcm3168a.c
@@ -0,0 +1,770 @@
+/*
+ * PCM3168A codec driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "pcm3168a.h"
+
+#define PCM3168A_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			 SNDRV_PCM_FMTBIT_S24_3LE | \
+			 SNDRV_PCM_FMTBIT_S24_LE | \
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+#define PCM3168A_FMT_I2S		0x0
+#define PCM3168A_FMT_LEFT_J		0x1
+#define PCM3168A_FMT_RIGHT_J		0x2
+#define PCM3168A_FMT_RIGHT_J_16		0x3
+#define PCM3168A_FMT_DSP_A		0x4
+#define PCM3168A_FMT_DSP_B		0x5
+#define PCM3168A_FMT_DSP_MASK		0x4
+
+#define PCM3168A_NUM_SUPPLIES 6
+static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = {
+	"VDD1",
+	"VDD2",
+	"VCCAD1",
+	"VCCAD2",
+	"VCCDA1",
+	"VCCDA2"
+};
+
+struct pcm3168a_priv {
+	struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES];
+	struct regmap *regmap;
+	struct clk *scki;
+	bool adc_master_mode;
+	bool dac_master_mode;
+	unsigned long sysclk;
+	unsigned int adc_fmt;
+	unsigned int dac_fmt;
+};
+
+static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d1_roll_off, PCM3168A_DAC_OP_FLT,
+		PCM3168A_DAC_FLT_SHIFT, pcm3168a_roll_off);
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d2_roll_off, PCM3168A_DAC_OP_FLT,
+		PCM3168A_DAC_FLT_SHIFT + 1, pcm3168a_roll_off);
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d3_roll_off, PCM3168A_DAC_OP_FLT,
+		PCM3168A_DAC_FLT_SHIFT + 2, pcm3168a_roll_off);
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d4_roll_off, PCM3168A_DAC_OP_FLT,
+		PCM3168A_DAC_FLT_SHIFT + 3, pcm3168a_roll_off);
+
+static const char *const pcm3168a_volume_type[] = {
+		"Individual", "Master + Individual" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_volume_type, PCM3168A_DAC_ATT_DEMP_ZF,
+		PCM3168A_DAC_ATMDDA_SHIFT, pcm3168a_volume_type);
+
+static const char *const pcm3168a_att_speed_mult[] = { "2048", "4096" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_att_mult, PCM3168A_DAC_ATT_DEMP_ZF,
+		PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_att_speed_mult);
+
+static const char *const pcm3168a_demp[] = {
+		"Disabled", "48khz", "44.1khz", "32khz" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_demp, PCM3168A_DAC_ATT_DEMP_ZF,
+		PCM3168A_DAC_DEMP_SHIFT, pcm3168a_demp);
+
+static const char *const pcm3168a_zf_func[] = {
+		"DAC 1/2/3/4 AND", "DAC 1/2/3/4 OR", "DAC 1/2/3 AND",
+		"DAC 1/2/3 OR", "DAC 4 AND", "DAC 4 OR" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_func, PCM3168A_DAC_ATT_DEMP_ZF,
+		PCM3168A_DAC_AZRO_SHIFT, pcm3168a_zf_func);
+
+static const char *const pcm3168a_pol[] = { "Active High", "Active Low" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_pol, PCM3168A_DAC_ATT_DEMP_ZF,
+		PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_pol);
+
+static const char *const pcm3168a_con[] = { "Differential", "Single-Ended" };
+
+static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc1_con, PCM3168A_ADC_SEAD,
+				0, 1, pcm3168a_con);
+static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc2_con, PCM3168A_ADC_SEAD,
+				2, 3, pcm3168a_con);
+static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc3_con, PCM3168A_ADC_SEAD,
+				4, 5, pcm3168a_con);
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_volume_type, PCM3168A_ADC_ATT_OVF,
+		PCM3168A_ADC_ATMDAD_SHIFT, pcm3168a_volume_type);
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_att_mult, PCM3168A_ADC_ATT_OVF,
+		PCM3168A_ADC_ATSPAD_SHIFT, pcm3168a_att_speed_mult);
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_ov_pol, PCM3168A_ADC_ATT_OVF,
+		PCM3168A_ADC_OVFP_SHIFT, pcm3168a_pol);
+
+/* -100db to 0db, register values 0-54 cause mute */
+static const DECLARE_TLV_DB_SCALE(pcm3168a_dac_tlv, -10050, 50, 1);
+
+/* -100db to 20db, register values 0-14 cause mute */
+static const DECLARE_TLV_DB_SCALE(pcm3168a_adc_tlv, -10050, 50, 1);
+
+static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
+	SOC_SINGLE("DAC Power-Save Switch", PCM3168A_DAC_PWR_MST_FMT,
+			PCM3168A_DAC_PSMDA_SHIFT, 1, 1),
+	SOC_ENUM("DAC1 Digital Filter roll-off", pcm3168a_d1_roll_off),
+	SOC_ENUM("DAC2 Digital Filter roll-off", pcm3168a_d2_roll_off),
+	SOC_ENUM("DAC3 Digital Filter roll-off", pcm3168a_d3_roll_off),
+	SOC_ENUM("DAC4 Digital Filter roll-off", pcm3168a_d4_roll_off),
+	SOC_DOUBLE("DAC1 Invert Switch", PCM3168A_DAC_INV, 0, 1, 1, 0),
+	SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0),
+	SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0),
+	SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0),
+	SOC_DOUBLE_STS("DAC1 Zero Flag", PCM3168A_DAC_ZERO, 0, 1, 1, 0),
+	SOC_DOUBLE_STS("DAC2 Zero Flag", PCM3168A_DAC_ZERO, 2, 3, 1, 0),
+	SOC_DOUBLE_STS("DAC3 Zero Flag", PCM3168A_DAC_ZERO, 4, 5, 1, 0),
+	SOC_DOUBLE_STS("DAC4 Zero Flag", PCM3168A_DAC_ZERO, 6, 7, 1, 0),
+	SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type),
+	SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult),
+	SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp),
+	SOC_ENUM("DAC Zero Flag Function", pcm3168a_dac_zf_func),
+	SOC_ENUM("DAC Zero Flag Polarity", pcm3168a_dac_zf_pol),
+	SOC_SINGLE_RANGE_TLV("Master Playback Volume",
+			PCM3168A_DAC_VOL_MASTER, 0, 54, 255, 0,
+			pcm3168a_dac_tlv),
+	SOC_DOUBLE_R_RANGE_TLV("DAC1 Playback Volume",
+			PCM3168A_DAC_VOL_CHAN_START,
+			PCM3168A_DAC_VOL_CHAN_START + 1,
+			0, 54, 255, 0, pcm3168a_dac_tlv),
+	SOC_DOUBLE_R_RANGE_TLV("DAC2 Playback Volume",
+			PCM3168A_DAC_VOL_CHAN_START + 2,
+			PCM3168A_DAC_VOL_CHAN_START + 3,
+			0, 54, 255, 0, pcm3168a_dac_tlv),
+	SOC_DOUBLE_R_RANGE_TLV("DAC3 Playback Volume",
+			PCM3168A_DAC_VOL_CHAN_START + 4,
+			PCM3168A_DAC_VOL_CHAN_START + 5,
+			0, 54, 255, 0, pcm3168a_dac_tlv),
+	SOC_DOUBLE_R_RANGE_TLV("DAC4 Playback Volume",
+			PCM3168A_DAC_VOL_CHAN_START + 6,
+			PCM3168A_DAC_VOL_CHAN_START + 7,
+			0, 54, 255, 0, pcm3168a_dac_tlv),
+	SOC_SINGLE("ADC1 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
+			PCM3168A_ADC_BYP_SHIFT, 1, 1),
+	SOC_SINGLE("ADC2 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
+			PCM3168A_ADC_BYP_SHIFT + 1, 1, 1),
+	SOC_SINGLE("ADC3 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
+			PCM3168A_ADC_BYP_SHIFT + 2, 1, 1),
+	SOC_ENUM("ADC1 Connection Type", pcm3168a_adc1_con),
+	SOC_ENUM("ADC2 Connection Type", pcm3168a_adc2_con),
+	SOC_ENUM("ADC3 Connection Type", pcm3168a_adc3_con),
+	SOC_DOUBLE("ADC1 Invert Switch", PCM3168A_ADC_INV, 0, 1, 1, 0),
+	SOC_DOUBLE("ADC2 Invert Switch", PCM3168A_ADC_INV, 2, 3, 1, 0),
+	SOC_DOUBLE("ADC3 Invert Switch", PCM3168A_ADC_INV, 4, 5, 1, 0),
+	SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0),
+	SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0),
+	SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0),
+	SOC_DOUBLE_STS("ADC1 Overflow Flag", PCM3168A_ADC_OV, 0, 1, 1, 0),
+	SOC_DOUBLE_STS("ADC2 Overflow Flag", PCM3168A_ADC_OV, 2, 3, 1, 0),
+	SOC_DOUBLE_STS("ADC3 Overflow Flag", PCM3168A_ADC_OV, 4, 5, 1, 0),
+	SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type),
+	SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult),
+	SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol),
+	SOC_SINGLE_RANGE_TLV("Master Capture Volume",
+			PCM3168A_ADC_VOL_MASTER, 0, 14, 255, 0,
+			pcm3168a_adc_tlv),
+	SOC_DOUBLE_R_RANGE_TLV("ADC1 Capture Volume",
+			PCM3168A_ADC_VOL_CHAN_START,
+			PCM3168A_ADC_VOL_CHAN_START + 1,
+			0, 14, 255, 0, pcm3168a_adc_tlv),
+	SOC_DOUBLE_R_RANGE_TLV("ADC2 Capture Volume",
+			PCM3168A_ADC_VOL_CHAN_START + 2,
+			PCM3168A_ADC_VOL_CHAN_START + 3,
+			0, 14, 255, 0, pcm3168a_adc_tlv),
+	SOC_DOUBLE_R_RANGE_TLV("ADC3 Capture Volume",
+			PCM3168A_ADC_VOL_CHAN_START + 4,
+			PCM3168A_ADC_VOL_CHAN_START + 5,
+			0, 14, 255, 0, pcm3168a_adc_tlv)
+};
+
+static const struct snd_soc_dapm_widget pcm3168a_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC1", "Playback", PCM3168A_DAC_OP_FLT,
+			PCM3168A_DAC_OPEDA_SHIFT, 1),
+	SND_SOC_DAPM_DAC("DAC2", "Playback", PCM3168A_DAC_OP_FLT,
+			PCM3168A_DAC_OPEDA_SHIFT + 1, 1),
+	SND_SOC_DAPM_DAC("DAC3", "Playback", PCM3168A_DAC_OP_FLT,
+			PCM3168A_DAC_OPEDA_SHIFT + 2, 1),
+	SND_SOC_DAPM_DAC("DAC4", "Playback", PCM3168A_DAC_OP_FLT,
+			PCM3168A_DAC_OPEDA_SHIFT + 3, 1),
+
+	SND_SOC_DAPM_OUTPUT("AOUT1L"),
+	SND_SOC_DAPM_OUTPUT("AOUT1R"),
+	SND_SOC_DAPM_OUTPUT("AOUT2L"),
+	SND_SOC_DAPM_OUTPUT("AOUT2R"),
+	SND_SOC_DAPM_OUTPUT("AOUT3L"),
+	SND_SOC_DAPM_OUTPUT("AOUT3R"),
+	SND_SOC_DAPM_OUTPUT("AOUT4L"),
+	SND_SOC_DAPM_OUTPUT("AOUT4R"),
+
+	SND_SOC_DAPM_ADC("ADC1", "Capture", PCM3168A_ADC_PWR_HPFB,
+			PCM3168A_ADC_PSVAD_SHIFT, 1),
+	SND_SOC_DAPM_ADC("ADC2", "Capture", PCM3168A_ADC_PWR_HPFB,
+			PCM3168A_ADC_PSVAD_SHIFT + 1, 1),
+	SND_SOC_DAPM_ADC("ADC3", "Capture", PCM3168A_ADC_PWR_HPFB,
+			PCM3168A_ADC_PSVAD_SHIFT + 2, 1),
+
+	SND_SOC_DAPM_INPUT("AIN1L"),
+	SND_SOC_DAPM_INPUT("AIN1R"),
+	SND_SOC_DAPM_INPUT("AIN2L"),
+	SND_SOC_DAPM_INPUT("AIN2R"),
+	SND_SOC_DAPM_INPUT("AIN3L"),
+	SND_SOC_DAPM_INPUT("AIN3R")
+};
+
+static const struct snd_soc_dapm_route pcm3168a_dapm_routes[] = {
+	/* Playback */
+	{ "AOUT1L", NULL, "DAC1" },
+	{ "AOUT1R", NULL, "DAC1" },
+
+	{ "AOUT2L", NULL, "DAC2" },
+	{ "AOUT2R", NULL, "DAC2" },
+
+	{ "AOUT3L", NULL, "DAC3" },
+	{ "AOUT3R", NULL, "DAC3" },
+
+	{ "AOUT4L", NULL, "DAC4" },
+	{ "AOUT4R", NULL, "DAC4" },
+
+	/* Capture */
+	{ "ADC1", NULL, "AIN1L" },
+	{ "ADC1", NULL, "AIN1R" },
+
+	{ "ADC2", NULL, "AIN2L" },
+	{ "ADC2", NULL, "AIN2R" },
+
+	{ "ADC3", NULL, "AIN3L" },
+	{ "ADC3", NULL, "AIN3R" }
+};
+
+static unsigned int pcm3168a_scki_ratios[] = {
+	768,
+	512,
+	384,
+	256,
+	192,
+	128
+};
+
+#define PCM3168A_NUM_SCKI_RATIOS_DAC	ARRAY_SIZE(pcm3168a_scki_ratios)
+#define PCM3168A_NUM_SCKI_RATIOS_ADC	(ARRAY_SIZE(pcm3168a_scki_ratios) - 2)
+
+#define PCM1368A_MAX_SYSCLK		36864000
+
+static int pcm3168a_reset(struct pcm3168a_priv *pcm3168a)
+{
+	int ret;
+
+	ret = regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE, 0);
+	if (ret)
+		return ret;
+
+	/* Internal reset is de-asserted after 3846 SCKI cycles */
+	msleep(DIV_ROUND_UP(3846 * 1000, pcm3168a->sysclk));
+
+	return regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE,
+			PCM3168A_MRST_MASK | PCM3168A_SRST_MASK);
+}
+
+static int pcm3168a_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
+
+	regmap_write(pcm3168a->regmap, PCM3168A_DAC_MUTE, mute ? 0xff : 0);
+
+	return 0;
+}
+
+static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(dai->component);
+	int ret;
+
+	if (freq > PCM1368A_MAX_SYSCLK)
+		return -EINVAL;
+
+	ret = clk_set_rate(pcm3168a->scki, freq);
+	if (ret)
+		return ret;
+
+	pcm3168a->sysclk = freq;
+
+	return 0;
+}
+
+static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
+			       unsigned int format, bool dac)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
+	u32 fmt, reg, mask, shift;
+	bool master_mode;
+
+	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_LEFT_J:
+		fmt = PCM3168A_FMT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		fmt = PCM3168A_FMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		fmt = PCM3168A_FMT_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		fmt = PCM3168A_FMT_DSP_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		fmt = PCM3168A_FMT_DSP_B;
+		break;
+	default:
+		dev_err(component->dev, "unsupported dai format\n");
+		return -EINVAL;
+	}
+
+	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		master_mode = false;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		master_mode = true;
+		break;
+	default:
+		dev_err(component->dev, "unsupported master/slave mode\n");
+		return -EINVAL;
+	}
+
+	switch (format & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (dac) {
+		reg = PCM3168A_DAC_PWR_MST_FMT;
+		mask = PCM3168A_DAC_FMT_MASK;
+		shift = PCM3168A_DAC_FMT_SHIFT;
+		pcm3168a->dac_master_mode = master_mode;
+		pcm3168a->dac_fmt = fmt;
+	} else {
+		reg = PCM3168A_ADC_MST_FMT;
+		mask = PCM3168A_ADC_FMTAD_MASK;
+		shift = PCM3168A_ADC_FMTAD_SHIFT;
+		pcm3168a->adc_master_mode = master_mode;
+		pcm3168a->adc_fmt = fmt;
+	}
+
+	regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
+
+	return 0;
+}
+
+static int pcm3168a_set_dai_fmt_dac(struct snd_soc_dai *dai,
+			       unsigned int format)
+{
+	return pcm3168a_set_dai_fmt(dai, format, true);
+}
+
+static int pcm3168a_set_dai_fmt_adc(struct snd_soc_dai *dai,
+			       unsigned int format)
+{
+	return pcm3168a_set_dai_fmt(dai, format, false);
+}
+
+static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
+	bool tx, master_mode;
+	u32 val, mask, shift, reg;
+	unsigned int rate, fmt, ratio, max_ratio;
+	int i, min_frame_size;
+
+	rate = params_rate(params);
+
+	ratio = pcm3168a->sysclk / rate;
+
+	tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	if (tx) {
+		max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC;
+		reg = PCM3168A_DAC_PWR_MST_FMT;
+		mask = PCM3168A_DAC_MSDA_MASK;
+		shift = PCM3168A_DAC_MSDA_SHIFT;
+		master_mode = pcm3168a->dac_master_mode;
+		fmt = pcm3168a->dac_fmt;
+	} else {
+		max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC;
+		reg = PCM3168A_ADC_MST_FMT;
+		mask = PCM3168A_ADC_MSAD_MASK;
+		shift = PCM3168A_ADC_MSAD_SHIFT;
+		master_mode = pcm3168a->adc_master_mode;
+		fmt = pcm3168a->adc_fmt;
+	}
+
+	for (i = 0; i < max_ratio; i++) {
+		if (pcm3168a_scki_ratios[i] == ratio)
+			break;
+	}
+
+	if (i == max_ratio) {
+		dev_err(component->dev, "unsupported sysclk ratio\n");
+		return -EINVAL;
+	}
+
+	min_frame_size = params_width(params) * 2;
+	switch (min_frame_size) {
+	case 32:
+		if (master_mode || (fmt != PCM3168A_FMT_RIGHT_J)) {
+			dev_err(component->dev, "32-bit frames are supported only for slave mode using right justified\n");
+			return -EINVAL;
+		}
+		fmt = PCM3168A_FMT_RIGHT_J_16;
+		break;
+	case 48:
+		if (master_mode || (fmt & PCM3168A_FMT_DSP_MASK)) {
+			dev_err(component->dev, "48-bit frames not supported in master mode, or slave mode using DSP\n");
+			return -EINVAL;
+		}
+		break;
+	case 64:
+		break;
+	default:
+		dev_err(component->dev, "unsupported frame size: %d\n", min_frame_size);
+		return -EINVAL;
+	}
+
+	if (master_mode)
+		val = ((i + 1) << shift);
+	else
+		val = 0;
+
+	regmap_update_bits(pcm3168a->regmap, reg, mask, val);
+
+	if (tx) {
+		mask = PCM3168A_DAC_FMT_MASK;
+		shift = PCM3168A_DAC_FMT_SHIFT;
+	} else {
+		mask = PCM3168A_ADC_FMTAD_MASK;
+		shift = PCM3168A_ADC_FMTAD_SHIFT;
+	}
+
+	regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = {
+	.set_fmt	= pcm3168a_set_dai_fmt_dac,
+	.set_sysclk	= pcm3168a_set_dai_sysclk,
+	.hw_params	= pcm3168a_hw_params,
+	.digital_mute	= pcm3168a_digital_mute
+};
+
+static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = {
+	.set_fmt	= pcm3168a_set_dai_fmt_adc,
+	.set_sysclk	= pcm3168a_set_dai_sysclk,
+	.hw_params	= pcm3168a_hw_params
+};
+
+static struct snd_soc_dai_driver pcm3168a_dais[] = {
+	{
+		.name = "pcm3168a-dac",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = PCM3168A_FORMATS
+		},
+		.ops = &pcm3168a_dac_dai_ops
+	},
+	{
+		.name = "pcm3168a-adc",
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = SNDRV_PCM_RATE_8000_96000,
+			.formats = PCM3168A_FORMATS
+		},
+		.ops = &pcm3168a_adc_dai_ops
+	},
+};
+
+static const struct reg_default pcm3168a_reg_default[] = {
+	{ PCM3168A_RST_SMODE, PCM3168A_MRST_MASK | PCM3168A_SRST_MASK },
+	{ PCM3168A_DAC_PWR_MST_FMT, 0x00 },
+	{ PCM3168A_DAC_OP_FLT, 0x00 },
+	{ PCM3168A_DAC_INV, 0x00 },
+	{ PCM3168A_DAC_MUTE, 0x00 },
+	{ PCM3168A_DAC_ZERO, 0x00 },
+	{ PCM3168A_DAC_ATT_DEMP_ZF, 0x00 },
+	{ PCM3168A_DAC_VOL_MASTER, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START + 1, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START + 2, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START + 3, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START + 4, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START + 5, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START + 6, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START + 7, 0xff },
+	{ PCM3168A_ADC_SMODE, 0x00 },
+	{ PCM3168A_ADC_MST_FMT, 0x00 },
+	{ PCM3168A_ADC_PWR_HPFB, 0x00 },
+	{ PCM3168A_ADC_SEAD, 0x00 },
+	{ PCM3168A_ADC_INV, 0x00 },
+	{ PCM3168A_ADC_MUTE, 0x00 },
+	{ PCM3168A_ADC_OV, 0x00 },
+	{ PCM3168A_ADC_ATT_OVF, 0x00 },
+	{ PCM3168A_ADC_VOL_MASTER, 0xd3 },
+	{ PCM3168A_ADC_VOL_CHAN_START, 0xd3 },
+	{ PCM3168A_ADC_VOL_CHAN_START + 1, 0xd3 },
+	{ PCM3168A_ADC_VOL_CHAN_START + 2, 0xd3 },
+	{ PCM3168A_ADC_VOL_CHAN_START + 3, 0xd3 },
+	{ PCM3168A_ADC_VOL_CHAN_START + 4, 0xd3 },
+	{ PCM3168A_ADC_VOL_CHAN_START + 5, 0xd3 }
+};
+
+static bool pcm3168a_readable_register(struct device *dev, unsigned int reg)
+{
+	if (reg >= PCM3168A_RST_SMODE)
+		return true;
+	else
+		return false;
+}
+
+static bool pcm3168a_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case PCM3168A_DAC_ZERO:
+	case PCM3168A_ADC_OV:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool pcm3168a_writeable_register(struct device *dev, unsigned int reg)
+{
+	if (reg < PCM3168A_RST_SMODE)
+		return false;
+
+	switch (reg) {
+	case PCM3168A_DAC_ZERO:
+	case PCM3168A_ADC_OV:
+		return false;
+	default:
+		return true;
+	}
+}
+
+const struct regmap_config pcm3168a_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = PCM3168A_ADC_VOL_CHAN_START + 5,
+	.reg_defaults = pcm3168a_reg_default,
+	.num_reg_defaults = ARRAY_SIZE(pcm3168a_reg_default),
+	.readable_reg = pcm3168a_readable_register,
+	.volatile_reg = pcm3168a_volatile_register,
+	.writeable_reg = pcm3168a_writeable_register,
+	.cache_type = REGCACHE_FLAT
+};
+EXPORT_SYMBOL_GPL(pcm3168a_regmap);
+
+static const struct snd_soc_component_driver pcm3168a_driver = {
+	.controls		= pcm3168a_snd_controls,
+	.num_controls		= ARRAY_SIZE(pcm3168a_snd_controls),
+	.dapm_widgets		= pcm3168a_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm3168a_dapm_widgets),
+	.dapm_routes		= pcm3168a_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm3168a_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+int pcm3168a_probe(struct device *dev, struct regmap *regmap)
+{
+	struct pcm3168a_priv *pcm3168a;
+	int ret, i;
+
+	pcm3168a = devm_kzalloc(dev, sizeof(*pcm3168a), GFP_KERNEL);
+	if (pcm3168a == NULL)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, pcm3168a);
+
+	pcm3168a->scki = devm_clk_get(dev, "scki");
+	if (IS_ERR(pcm3168a->scki)) {
+		ret = PTR_ERR(pcm3168a->scki);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "failed to acquire clock 'scki': %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(pcm3168a->scki);
+	if (ret) {
+		dev_err(dev, "Failed to enable mclk: %d\n", ret);
+		return ret;
+	}
+
+	pcm3168a->sysclk = clk_get_rate(pcm3168a->scki);
+
+	for (i = 0; i < ARRAY_SIZE(pcm3168a->supplies); i++)
+		pcm3168a->supplies[i].supply = pcm3168a_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev,
+			ARRAY_SIZE(pcm3168a->supplies), pcm3168a->supplies);
+	if (ret) {
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "failed to request supplies: %d\n", ret);
+		goto err_clk;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies),
+				    pcm3168a->supplies);
+	if (ret) {
+		dev_err(dev, "failed to enable supplies: %d\n", ret);
+		goto err_clk;
+	}
+
+	pcm3168a->regmap = regmap;
+	if (IS_ERR(pcm3168a->regmap)) {
+		ret = PTR_ERR(pcm3168a->regmap);
+		dev_err(dev, "failed to allocate regmap: %d\n", ret);
+		goto err_regulator;
+	}
+
+	ret = pcm3168a_reset(pcm3168a);
+	if (ret) {
+		dev_err(dev, "Failed to reset device: %d\n", ret);
+		goto err_regulator;
+	}
+
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	pm_runtime_idle(dev);
+
+	ret = devm_snd_soc_register_component(dev, &pcm3168a_driver, pcm3168a_dais,
+			ARRAY_SIZE(pcm3168a_dais));
+	if (ret) {
+		dev_err(dev, "failed to register component: %d\n", ret);
+		goto err_regulator;
+	}
+
+	return 0;
+
+err_regulator:
+	regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+			pcm3168a->supplies);
+err_clk:
+	clk_disable_unprepare(pcm3168a->scki);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pcm3168a_probe);
+
+void pcm3168a_remove(struct device *dev)
+{
+	struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
+
+	pm_runtime_disable(dev);
+	regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+				pcm3168a->supplies);
+	clk_disable_unprepare(pcm3168a->scki);
+}
+EXPORT_SYMBOL_GPL(pcm3168a_remove);
+
+#ifdef CONFIG_PM
+static int pcm3168a_rt_resume(struct device *dev)
+{
+	struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(pcm3168a->scki);
+	if (ret) {
+		dev_err(dev, "Failed to enable mclk: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies),
+				    pcm3168a->supplies);
+	if (ret) {
+		dev_err(dev, "Failed to enable supplies: %d\n", ret);
+		goto err_clk;
+	}
+
+	ret = pcm3168a_reset(pcm3168a);
+	if (ret) {
+		dev_err(dev, "Failed to reset device: %d\n", ret);
+		goto err_regulator;
+	}
+
+	regcache_cache_only(pcm3168a->regmap, false);
+
+	regcache_mark_dirty(pcm3168a->regmap);
+
+	ret = regcache_sync(pcm3168a->regmap);
+	if (ret) {
+		dev_err(dev, "Failed to sync regmap: %d\n", ret);
+		goto err_regulator;
+	}
+
+	return 0;
+
+err_regulator:
+	regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+			       pcm3168a->supplies);
+err_clk:
+	clk_disable_unprepare(pcm3168a->scki);
+
+	return ret;
+}
+
+static int pcm3168a_rt_suspend(struct device *dev)
+{
+	struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
+
+	regcache_cache_only(pcm3168a->regmap, true);
+
+	regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+			       pcm3168a->supplies);
+
+	clk_disable_unprepare(pcm3168a->scki);
+
+	return 0;
+}
+#endif
+
+const struct dev_pm_ops pcm3168a_pm_ops = {
+	SET_RUNTIME_PM_OPS(pcm3168a_rt_suspend, pcm3168a_rt_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(pcm3168a_pm_ops);
+
+MODULE_DESCRIPTION("PCM3168A codec driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3168a.h b/sound/soc/codecs/pcm3168a.h
new file mode 100644
index 0000000..56c8332
--- /dev/null
+++ b/sound/soc/codecs/pcm3168a.h
@@ -0,0 +1,100 @@
+/*
+ * PCM3168A codec driver header
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#ifndef __PCM3168A_H__
+#define __PCM3168A_H__
+
+extern const struct dev_pm_ops pcm3168a_pm_ops;
+extern const struct regmap_config pcm3168a_regmap;
+
+extern int pcm3168a_probe(struct device *dev, struct regmap *regmap);
+extern void pcm3168a_remove(struct device *dev);
+
+#define PCM3168A_RST_SMODE			0x40
+#define PCM3168A_MRST_MASK			0x80
+#define PCM3168A_SRST_MASK			0x40
+#define PCM3168A_DAC_SRDA_SHIFT			0
+#define PCM3168A_DAC_SRDA_MASK			0x3
+
+#define PCM3168A_DAC_PWR_MST_FMT		0x41
+#define PCM3168A_DAC_PSMDA_SHIFT		7
+#define PCM3168A_DAC_PSMDA_MASK			0x80
+#define PCM3168A_DAC_MSDA_SHIFT			4
+#define PCM3168A_DAC_MSDA_MASK			0x70
+#define PCM3168A_DAC_FMT_SHIFT			0
+#define PCM3168A_DAC_FMT_MASK			0xf
+
+#define PCM3168A_DAC_OP_FLT			0x42
+#define PCM3168A_DAC_OPEDA_SHIFT		4
+#define PCM3168A_DAC_OPEDA_MASK			0xf0
+#define PCM3168A_DAC_FLT_SHIFT			0
+#define PCM3168A_DAC_FLT_MASK			0xf
+
+#define PCM3168A_DAC_INV			0x43
+
+#define PCM3168A_DAC_MUTE			0x44
+
+#define PCM3168A_DAC_ZERO			0x45
+
+#define PCM3168A_DAC_ATT_DEMP_ZF		0x46
+#define PCM3168A_DAC_ATMDDA_MASK		0x80
+#define PCM3168A_DAC_ATMDDA_SHIFT		7
+#define PCM3168A_DAC_ATSPDA_MASK		0x40
+#define PCM3168A_DAC_ATSPDA_SHIFT		6
+#define PCM3168A_DAC_DEMP_SHIFT			4
+#define PCM3168A_DAC_DEMP_MASK			0x30
+#define PCM3168A_DAC_AZRO_SHIFT			1
+#define PCM3168A_DAC_AZRO_MASK			0xe
+#define PCM3168A_DAC_ZREV_MASK			0x1
+#define PCM3168A_DAC_ZREV_SHIFT			0
+
+#define PCM3168A_DAC_VOL_MASTER			0x47
+
+#define PCM3168A_DAC_VOL_CHAN_START		0x48
+
+#define PCM3168A_ADC_SMODE			0x50
+#define PCM3168A_ADC_SRAD_SHIFT			0
+#define PCM3168A_ADC_SRAD_MASK			0x3
+
+#define PCM3168A_ADC_MST_FMT			0x51
+#define PCM3168A_ADC_MSAD_SHIFT			4
+#define PCM3168A_ADC_MSAD_MASK			0x70
+#define PCM3168A_ADC_FMTAD_SHIFT		0
+#define PCM3168A_ADC_FMTAD_MASK			0x7
+
+#define PCM3168A_ADC_PWR_HPFB			0x52
+#define PCM3168A_ADC_PSVAD_SHIFT		4
+#define PCM3168A_ADC_PSVAD_MASK			0x70
+#define PCM3168A_ADC_BYP_SHIFT			0
+#define PCM3168A_ADC_BYP_MASK			0x7
+
+#define PCM3168A_ADC_SEAD			0x53
+
+#define PCM3168A_ADC_INV			0x54
+
+#define PCM3168A_ADC_MUTE			0x55
+
+#define PCM3168A_ADC_OV				0x56
+
+#define PCM3168A_ADC_ATT_OVF			0x57
+#define PCM3168A_ADC_ATMDAD_MASK		0x80
+#define PCM3168A_ADC_ATMDAD_SHIFT		7
+#define PCM3168A_ADC_ATSPAD_MASK		0x40
+#define PCM3168A_ADC_ATSPAD_SHIFT		6
+#define PCM3168A_ADC_OVFP_MASK			0x1
+#define PCM3168A_ADC_OVFP_SHIFT			0
+
+#define PCM3168A_ADC_VOL_MASTER			0x58
+
+#define PCM3168A_ADC_VOL_CHAN_START		0x59
+
+#endif
diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c
new file mode 100644
index 0000000..39ac285
--- /dev/null
+++ b/sound/soc/codecs/pcm5102a.c
@@ -0,0 +1,66 @@
+/*
+ * Driver for the PCM5102A codec
+ *
+ * Author:	Florian Meier <florian.meier@koalo.de>
+ *		Copyright 2013
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/soc.h>
+
+static struct snd_soc_dai_driver pcm5102a_dai = {
+	.name = "pcm5102a-hifi",
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			   SNDRV_PCM_FMTBIT_S24_LE |
+			   SNDRV_PCM_FMTBIT_S32_LE
+	},
+};
+
+static struct snd_soc_component_driver soc_component_dev_pcm5102a = {
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int pcm5102a_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_pcm5102a,
+			&pcm5102a_dai, 1);
+}
+
+static const struct of_device_id pcm5102a_of_match[] = {
+	{ .compatible = "ti,pcm5102a", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm5102a_of_match);
+
+static struct platform_driver pcm5102a_codec_driver = {
+	.probe		= pcm5102a_probe,
+	.driver		= {
+		.name	= "pcm5102a-codec",
+		.of_match_table = pcm5102a_of_match,
+	},
+};
+
+module_platform_driver(pcm5102a_codec_driver);
+
+MODULE_DESCRIPTION("ASoC PCM5102A codec driver");
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c
new file mode 100644
index 0000000..0fe5ced
--- /dev/null
+++ b/sound/soc/codecs/pcm512x-i2c.c
@@ -0,0 +1,94 @@
+/*
+ * Driver for the PCM512x CODECs
+ *
+ * Author:	Mark Brown <broonie@kernel.org>
+ *		Copyright 2014 Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+
+#include "pcm512x.h"
+
+static int pcm512x_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	struct regmap_config config = pcm512x_regmap;
+
+	/* msb needs to be set to enable auto-increment of addresses */
+	config.read_flag_mask = 0x80;
+	config.write_flag_mask = 0x80;
+
+	regmap = devm_regmap_init_i2c(i2c, &config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return pcm512x_probe(&i2c->dev, regmap);
+}
+
+static int pcm512x_i2c_remove(struct i2c_client *i2c)
+{
+	pcm512x_remove(&i2c->dev);
+	return 0;
+}
+
+static const struct i2c_device_id pcm512x_i2c_id[] = {
+	{ "pcm5121", },
+	{ "pcm5122", },
+	{ "pcm5141", },
+	{ "pcm5142", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id pcm512x_of_match[] = {
+	{ .compatible = "ti,pcm5121", },
+	{ .compatible = "ti,pcm5122", },
+	{ .compatible = "ti,pcm5141", },
+	{ .compatible = "ti,pcm5142", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm512x_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id pcm512x_acpi_match[] = {
+	{ "104C5121", 0 },
+	{ "104C5122", 0 },
+	{ "104C5141", 0 },
+	{ "104C5142", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, pcm512x_acpi_match);
+#endif
+
+static struct i2c_driver pcm512x_i2c_driver = {
+	.probe 		= pcm512x_i2c_probe,
+	.remove 	= pcm512x_i2c_remove,
+	.id_table	= pcm512x_i2c_id,
+	.driver		= {
+		.name	= "pcm512x",
+		.of_match_table = of_match_ptr(pcm512x_of_match),
+		.acpi_match_table = ACPI_PTR(pcm512x_acpi_match),
+		.pm     = &pcm512x_pm_ops,
+	},
+};
+
+module_i2c_driver(pcm512x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC PCM512x codec driver - I2C");
+MODULE_AUTHOR("Mark Brown <broonie@kernel.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c
new file mode 100644
index 0000000..7cdd2dc
--- /dev/null
+++ b/sound/soc/codecs/pcm512x-spi.c
@@ -0,0 +1,76 @@
+/*
+ * Driver for the PCM512x CODECs
+ *
+ * Author:	Mark Brown <broonie@kernel.org>
+ *		Copyright 2014 Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "pcm512x.h"
+
+static int pcm512x_spi_probe(struct spi_device *spi)
+{
+	struct regmap *regmap;
+	int ret;
+
+	regmap = devm_regmap_init_spi(spi, &pcm512x_regmap);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		return ret;
+	}
+
+	return pcm512x_probe(&spi->dev, regmap);
+}
+
+static int pcm512x_spi_remove(struct spi_device *spi)
+{
+	pcm512x_remove(&spi->dev);
+	return 0;
+}
+
+static const struct spi_device_id pcm512x_spi_id[] = {
+	{ "pcm5121", },
+	{ "pcm5122", },
+	{ "pcm5141", },
+	{ "pcm5142", },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, pcm512x_spi_id);
+
+static const struct of_device_id pcm512x_of_match[] = {
+	{ .compatible = "ti,pcm5121", },
+	{ .compatible = "ti,pcm5122", },
+	{ .compatible = "ti,pcm5141", },
+	{ .compatible = "ti,pcm5142", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm512x_of_match);
+
+static struct spi_driver pcm512x_spi_driver = {
+	.probe		= pcm512x_spi_probe,
+	.remove		= pcm512x_spi_remove,
+	.id_table	= pcm512x_spi_id,
+	.driver = {
+		.name	= "pcm512x",
+		.of_match_table = pcm512x_of_match,
+		.pm     = &pcm512x_pm_ops,
+	},
+};
+
+module_spi_driver(pcm512x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC PCM512x codec driver - SPI");
+MODULE_AUTHOR("Mark Brown <broonie@kernel.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
new file mode 100644
index 0000000..f0f2d4f
--- /dev/null
+++ b/sound/soc/codecs/pcm512x.c
@@ -0,0 +1,1604 @@
+/*
+ * Driver for the PCM512x CODECs
+ *
+ * Author:	Mark Brown <broonie@kernel.org>
+ *		Copyright 2014 Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gcd.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#include "pcm512x.h"
+
+#define PCM512x_NUM_SUPPLIES 3
+static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = {
+	"AVDD",
+	"DVDD",
+	"CPVDD",
+};
+
+struct pcm512x_priv {
+	struct regmap *regmap;
+	struct clk *sclk;
+	struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES];
+	struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES];
+	int fmt;
+	int pll_in;
+	int pll_out;
+	int pll_r;
+	int pll_j;
+	int pll_d;
+	int pll_p;
+	unsigned long real_pll;
+	unsigned long overclock_pll;
+	unsigned long overclock_dac;
+	unsigned long overclock_dsp;
+};
+
+/*
+ * We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define PCM512x_REGULATOR_EVENT(n) \
+static int pcm512x_regulator_event_##n(struct notifier_block *nb, \
+				      unsigned long event, void *data)    \
+{ \
+	struct pcm512x_priv *pcm512x = container_of(nb, struct pcm512x_priv, \
+						    supply_nb[n]); \
+	if (event & REGULATOR_EVENT_DISABLE) { \
+		regcache_mark_dirty(pcm512x->regmap);	\
+		regcache_cache_only(pcm512x->regmap, true);	\
+	} \
+	return 0; \
+}
+
+PCM512x_REGULATOR_EVENT(0)
+PCM512x_REGULATOR_EVENT(1)
+PCM512x_REGULATOR_EVENT(2)
+
+static const struct reg_default pcm512x_reg_defaults[] = {
+	{ PCM512x_RESET,             0x00 },
+	{ PCM512x_POWER,             0x00 },
+	{ PCM512x_MUTE,              0x00 },
+	{ PCM512x_DSP,               0x00 },
+	{ PCM512x_PLL_REF,           0x00 },
+	{ PCM512x_DAC_REF,           0x00 },
+	{ PCM512x_DAC_ROUTING,       0x11 },
+	{ PCM512x_DSP_PROGRAM,       0x01 },
+	{ PCM512x_CLKDET,            0x00 },
+	{ PCM512x_AUTO_MUTE,         0x00 },
+	{ PCM512x_ERROR_DETECT,      0x00 },
+	{ PCM512x_DIGITAL_VOLUME_1,  0x00 },
+	{ PCM512x_DIGITAL_VOLUME_2,  0x30 },
+	{ PCM512x_DIGITAL_VOLUME_3,  0x30 },
+	{ PCM512x_DIGITAL_MUTE_1,    0x22 },
+	{ PCM512x_DIGITAL_MUTE_2,    0x00 },
+	{ PCM512x_DIGITAL_MUTE_3,    0x07 },
+	{ PCM512x_OUTPUT_AMPLITUDE,  0x00 },
+	{ PCM512x_ANALOG_GAIN_CTRL,  0x00 },
+	{ PCM512x_UNDERVOLTAGE_PROT, 0x00 },
+	{ PCM512x_ANALOG_MUTE_CTRL,  0x00 },
+	{ PCM512x_ANALOG_GAIN_BOOST, 0x00 },
+	{ PCM512x_VCOM_CTRL_1,       0x00 },
+	{ PCM512x_VCOM_CTRL_2,       0x01 },
+	{ PCM512x_BCLK_LRCLK_CFG,    0x00 },
+	{ PCM512x_MASTER_MODE,       0x7c },
+	{ PCM512x_GPIO_DACIN,        0x00 },
+	{ PCM512x_GPIO_PLLIN,        0x00 },
+	{ PCM512x_SYNCHRONIZE,       0x10 },
+	{ PCM512x_PLL_COEFF_0,       0x00 },
+	{ PCM512x_PLL_COEFF_1,       0x00 },
+	{ PCM512x_PLL_COEFF_2,       0x00 },
+	{ PCM512x_PLL_COEFF_3,       0x00 },
+	{ PCM512x_PLL_COEFF_4,       0x00 },
+	{ PCM512x_DSP_CLKDIV,        0x00 },
+	{ PCM512x_DAC_CLKDIV,        0x00 },
+	{ PCM512x_NCP_CLKDIV,        0x00 },
+	{ PCM512x_OSR_CLKDIV,        0x00 },
+	{ PCM512x_MASTER_CLKDIV_1,   0x00 },
+	{ PCM512x_MASTER_CLKDIV_2,   0x00 },
+	{ PCM512x_FS_SPEED_MODE,     0x00 },
+	{ PCM512x_IDAC_1,            0x01 },
+	{ PCM512x_IDAC_2,            0x00 },
+};
+
+static bool pcm512x_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case PCM512x_RESET:
+	case PCM512x_POWER:
+	case PCM512x_MUTE:
+	case PCM512x_PLL_EN:
+	case PCM512x_SPI_MISO_FUNCTION:
+	case PCM512x_DSP:
+	case PCM512x_GPIO_EN:
+	case PCM512x_BCLK_LRCLK_CFG:
+	case PCM512x_DSP_GPIO_INPUT:
+	case PCM512x_MASTER_MODE:
+	case PCM512x_PLL_REF:
+	case PCM512x_DAC_REF:
+	case PCM512x_GPIO_DACIN:
+	case PCM512x_GPIO_PLLIN:
+	case PCM512x_SYNCHRONIZE:
+	case PCM512x_PLL_COEFF_0:
+	case PCM512x_PLL_COEFF_1:
+	case PCM512x_PLL_COEFF_2:
+	case PCM512x_PLL_COEFF_3:
+	case PCM512x_PLL_COEFF_4:
+	case PCM512x_DSP_CLKDIV:
+	case PCM512x_DAC_CLKDIV:
+	case PCM512x_NCP_CLKDIV:
+	case PCM512x_OSR_CLKDIV:
+	case PCM512x_MASTER_CLKDIV_1:
+	case PCM512x_MASTER_CLKDIV_2:
+	case PCM512x_FS_SPEED_MODE:
+	case PCM512x_IDAC_1:
+	case PCM512x_IDAC_2:
+	case PCM512x_ERROR_DETECT:
+	case PCM512x_I2S_1:
+	case PCM512x_I2S_2:
+	case PCM512x_DAC_ROUTING:
+	case PCM512x_DSP_PROGRAM:
+	case PCM512x_CLKDET:
+	case PCM512x_AUTO_MUTE:
+	case PCM512x_DIGITAL_VOLUME_1:
+	case PCM512x_DIGITAL_VOLUME_2:
+	case PCM512x_DIGITAL_VOLUME_3:
+	case PCM512x_DIGITAL_MUTE_1:
+	case PCM512x_DIGITAL_MUTE_2:
+	case PCM512x_DIGITAL_MUTE_3:
+	case PCM512x_GPIO_OUTPUT_1:
+	case PCM512x_GPIO_OUTPUT_2:
+	case PCM512x_GPIO_OUTPUT_3:
+	case PCM512x_GPIO_OUTPUT_4:
+	case PCM512x_GPIO_OUTPUT_5:
+	case PCM512x_GPIO_OUTPUT_6:
+	case PCM512x_GPIO_CONTROL_1:
+	case PCM512x_GPIO_CONTROL_2:
+	case PCM512x_OVERFLOW:
+	case PCM512x_RATE_DET_1:
+	case PCM512x_RATE_DET_2:
+	case PCM512x_RATE_DET_3:
+	case PCM512x_RATE_DET_4:
+	case PCM512x_CLOCK_STATUS:
+	case PCM512x_ANALOG_MUTE_DET:
+	case PCM512x_GPIN:
+	case PCM512x_DIGITAL_MUTE_DET:
+	case PCM512x_OUTPUT_AMPLITUDE:
+	case PCM512x_ANALOG_GAIN_CTRL:
+	case PCM512x_UNDERVOLTAGE_PROT:
+	case PCM512x_ANALOG_MUTE_CTRL:
+	case PCM512x_ANALOG_GAIN_BOOST:
+	case PCM512x_VCOM_CTRL_1:
+	case PCM512x_VCOM_CTRL_2:
+	case PCM512x_CRAM_CTRL:
+	case PCM512x_FLEX_A:
+	case PCM512x_FLEX_B:
+		return true;
+	default:
+		/* There are 256 raw register addresses */
+		return reg < 0xff;
+	}
+}
+
+static bool pcm512x_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case PCM512x_PLL_EN:
+	case PCM512x_OVERFLOW:
+	case PCM512x_RATE_DET_1:
+	case PCM512x_RATE_DET_2:
+	case PCM512x_RATE_DET_3:
+	case PCM512x_RATE_DET_4:
+	case PCM512x_CLOCK_STATUS:
+	case PCM512x_ANALOG_MUTE_DET:
+	case PCM512x_GPIN:
+	case PCM512x_DIGITAL_MUTE_DET:
+	case PCM512x_CRAM_CTRL:
+		return true;
+	default:
+		/* There are 256 raw register addresses */
+		return reg < 0xff;
+	}
+}
+
+static int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = pcm512x->overclock_pll;
+	return 0;
+}
+
+static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+
+	switch (snd_soc_component_get_bias_level(component)) {
+	case SND_SOC_BIAS_OFF:
+	case SND_SOC_BIAS_STANDBY:
+		break;
+	default:
+		return -EBUSY;
+	}
+
+	pcm512x->overclock_pll = ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = pcm512x->overclock_dsp;
+	return 0;
+}
+
+static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+
+	switch (snd_soc_component_get_bias_level(component)) {
+	case SND_SOC_BIAS_OFF:
+	case SND_SOC_BIAS_STANDBY:
+		break;
+	default:
+		return -EBUSY;
+	}
+
+	pcm512x->overclock_dsp = ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = pcm512x->overclock_dac;
+	return 0;
+}
+
+static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+
+	switch (snd_soc_component_get_bias_level(component)) {
+	case SND_SOC_BIAS_OFF:
+	case SND_SOC_BIAS_STANDBY:
+		break;
+	default:
+		return -EBUSY;
+	}
+
+	pcm512x->overclock_dac = ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
+
+static const char * const pcm512x_dsp_program_texts[] = {
+	"FIR interpolation with de-emphasis",
+	"Low latency IIR with de-emphasis",
+	"High attenuation with de-emphasis",
+	"Fixed process flow",
+	"Ringing-less low latency FIR",
+};
+
+static const unsigned int pcm512x_dsp_program_values[] = {
+	1,
+	2,
+	3,
+	5,
+	7,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program,
+				  PCM512x_DSP_PROGRAM, 0, 0x1f,
+				  pcm512x_dsp_program_texts,
+				  pcm512x_dsp_program_values);
+
+static const char * const pcm512x_clk_missing_text[] = {
+	"1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s"
+};
+
+static const struct soc_enum pcm512x_clk_missing =
+	SOC_ENUM_SINGLE(PCM512x_CLKDET, 0,  8, pcm512x_clk_missing_text);
+
+static const char * const pcm512x_autom_text[] = {
+	"21ms", "106ms", "213ms", "533ms", "1.07s", "2.13s", "5.33s", "10.66s"
+};
+
+static const struct soc_enum pcm512x_autom_l =
+	SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATML_SHIFT, 8,
+			pcm512x_autom_text);
+
+static const struct soc_enum pcm512x_autom_r =
+	SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 8,
+			pcm512x_autom_text);
+
+static const char * const pcm512x_ramp_rate_text[] = {
+	"1 sample/update", "2 samples/update", "4 samples/update",
+	"Immediate"
+};
+
+static const struct soc_enum pcm512x_vndf =
+	SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDF_SHIFT, 4,
+			pcm512x_ramp_rate_text);
+
+static const struct soc_enum pcm512x_vnuf =
+	SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUF_SHIFT, 4,
+			pcm512x_ramp_rate_text);
+
+static const struct soc_enum pcm512x_vedf =
+	SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDF_SHIFT, 4,
+			pcm512x_ramp_rate_text);
+
+static const char * const pcm512x_ramp_step_text[] = {
+	"4dB/step", "2dB/step", "1dB/step", "0.5dB/step"
+};
+
+static const struct soc_enum pcm512x_vnds =
+	SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDS_SHIFT, 4,
+			pcm512x_ramp_step_text);
+
+static const struct soc_enum pcm512x_vnus =
+	SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUS_SHIFT, 4,
+			pcm512x_ramp_step_text);
+
+static const struct soc_enum pcm512x_veds =
+	SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4,
+			pcm512x_ramp_step_text);
+
+static const struct snd_kcontrol_new pcm512x_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2,
+		 PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+SOC_DOUBLE_TLV("Analogue Playback Volume", PCM512x_ANALOG_GAIN_CTRL,
+	       PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
+SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
+	       PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
+SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
+	   PCM512x_RQMR_SHIFT, 1, 1),
+
+SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
+SOC_ENUM("DSP Program", pcm512x_dsp_program),
+
+SOC_ENUM("Clock Missing Period", pcm512x_clk_missing),
+SOC_ENUM("Auto Mute Time Left", pcm512x_autom_l),
+SOC_ENUM("Auto Mute Time Right", pcm512x_autom_r),
+SOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3,
+	   PCM512x_ACTL_SHIFT, 1, 0),
+SOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT,
+	   PCM512x_AMRE_SHIFT, 1, 0),
+
+SOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf),
+SOC_ENUM("Volume Ramp Down Step", pcm512x_vnds),
+SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf),
+SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus),
+SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf),
+SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds),
+
+SOC_SINGLE_EXT("Max Overclock PLL", SND_SOC_NOPM, 0, 20, 0,
+	       pcm512x_overclock_pll_get, pcm512x_overclock_pll_put),
+SOC_SINGLE_EXT("Max Overclock DSP", SND_SOC_NOPM, 0, 40, 0,
+	       pcm512x_overclock_dsp_get, pcm512x_overclock_dsp_put),
+SOC_SINGLE_EXT("Max Overclock DAC", SND_SOC_NOPM, 0, 40, 0,
+	       pcm512x_overclock_dac_get, pcm512x_overclock_dac_put),
+};
+
+static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_OUTPUT("OUTL"),
+SND_SOC_DAPM_OUTPUT("OUTR"),
+};
+
+static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = {
+	{ "DACL", NULL, "Playback" },
+	{ "DACR", NULL, "Playback" },
+
+	{ "OUTL", NULL, "DACL" },
+	{ "OUTR", NULL, "DACR" },
+};
+
+static unsigned long pcm512x_pll_max(struct pcm512x_priv *pcm512x)
+{
+	return 25000000 + 25000000 * pcm512x->overclock_pll / 100;
+}
+
+static unsigned long pcm512x_dsp_max(struct pcm512x_priv *pcm512x)
+{
+	return 50000000 + 50000000 * pcm512x->overclock_dsp / 100;
+}
+
+static unsigned long pcm512x_dac_max(struct pcm512x_priv *pcm512x,
+				     unsigned long rate)
+{
+	return rate + rate * pcm512x->overclock_dac / 100;
+}
+
+static unsigned long pcm512x_sck_max(struct pcm512x_priv *pcm512x)
+{
+	if (!pcm512x->pll_out)
+		return 25000000;
+	return pcm512x_pll_max(pcm512x);
+}
+
+static unsigned long pcm512x_ncp_target(struct pcm512x_priv *pcm512x,
+					unsigned long dac_rate)
+{
+	/*
+	 * If the DAC is not actually overclocked, use the good old
+	 * NCP target rate...
+	 */
+	if (dac_rate <= 6144000)
+		return 1536000;
+	/*
+	 * ...but if the DAC is in fact overclocked, bump the NCP target
+	 * rate to get the recommended dividers even when overclocking.
+	 */
+	return pcm512x_dac_max(pcm512x, 1536000);
+}
+
+static const u32 pcm512x_dai_rates[] = {
+	8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
+	88200, 96000, 176400, 192000, 384000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_slave = {
+	.count = ARRAY_SIZE(pcm512x_dai_rates),
+	.list  = pcm512x_dai_rates,
+};
+
+static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
+				struct snd_pcm_hw_rule *rule)
+{
+	struct pcm512x_priv *pcm512x = rule->private;
+	struct snd_interval ranges[2];
+	int frame_size;
+
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0)
+		return frame_size;
+
+	switch (frame_size) {
+	case 32:
+		/* No hole when the frame size is 32. */
+		return 0;
+	case 48:
+	case 64:
+		/* There is only one hole in the range of supported
+		 * rates, but it moves with the frame size.
+		 */
+		memset(ranges, 0, sizeof(ranges));
+		ranges[0].min = 8000;
+		ranges[0].max = pcm512x_sck_max(pcm512x) / frame_size / 2;
+		ranges[1].min = DIV_ROUND_UP(16000000, frame_size);
+		ranges[1].max = 384000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_interval_ranges(hw_param_interval(params, rule->var),
+				   ARRAY_SIZE(ranges), ranges, 0);
+}
+
+static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
+				      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+	struct device *dev = dai->dev;
+	struct snd_pcm_hw_constraint_ratnums *constraints_no_pll;
+	struct snd_ratnum *rats_no_pll;
+
+	if (IS_ERR(pcm512x->sclk)) {
+		dev_err(dev, "Need SCLK for master mode: %ld\n",
+			PTR_ERR(pcm512x->sclk));
+		return PTR_ERR(pcm512x->sclk);
+	}
+
+	if (pcm512x->pll_out)
+		return snd_pcm_hw_rule_add(substream->runtime, 0,
+					   SNDRV_PCM_HW_PARAM_RATE,
+					   pcm512x_hw_rule_rate,
+					   pcm512x,
+					   SNDRV_PCM_HW_PARAM_FRAME_BITS,
+					   SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+
+	constraints_no_pll = devm_kzalloc(dev, sizeof(*constraints_no_pll),
+					  GFP_KERNEL);
+	if (!constraints_no_pll)
+		return -ENOMEM;
+	constraints_no_pll->nrats = 1;
+	rats_no_pll = devm_kzalloc(dev, sizeof(*rats_no_pll), GFP_KERNEL);
+	if (!rats_no_pll)
+		return -ENOMEM;
+	constraints_no_pll->rats = rats_no_pll;
+	rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
+	rats_no_pll->den_min = 1;
+	rats_no_pll->den_max = 128;
+	rats_no_pll->den_step = 1;
+
+	return snd_pcm_hw_constraint_ratnums(substream->runtime, 0,
+					     SNDRV_PCM_HW_PARAM_RATE,
+					     constraints_no_pll);
+}
+
+static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream,
+				     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+	struct device *dev = dai->dev;
+	struct regmap *regmap = pcm512x->regmap;
+
+	if (IS_ERR(pcm512x->sclk)) {
+		dev_info(dev, "No SCLK, using BCLK: %ld\n",
+			 PTR_ERR(pcm512x->sclk));
+
+		/* Disable reporting of missing SCLK as an error */
+		regmap_update_bits(regmap, PCM512x_ERROR_DETECT,
+				   PCM512x_IDCH, PCM512x_IDCH);
+
+		/* Switch PLL input to BCLK */
+		regmap_update_bits(regmap, PCM512x_PLL_REF,
+				   PCM512x_SREF, PCM512x_SREF_BCK);
+	}
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE,
+					  &constraints_slave);
+}
+
+static int pcm512x_dai_startup(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+
+	switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+	case SND_SOC_DAIFMT_CBM_CFS:
+		return pcm512x_dai_startup_master(substream, dai);
+
+	case SND_SOC_DAIFMT_CBS_CFS:
+		return pcm512x_dai_startup_slave(substream, dai);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int pcm512x_set_bias_level(struct snd_soc_component *component,
+				  enum snd_soc_bias_level level)
+{
+	struct pcm512x_priv *pcm512x = dev_get_drvdata(component->dev);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+					 PCM512x_RQST, 0);
+		if (ret != 0) {
+			dev_err(component->dev, "Failed to remove standby: %d\n",
+				ret);
+			return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+					 PCM512x_RQST, PCM512x_RQST);
+		if (ret != 0) {
+			dev_err(component->dev, "Failed to request standby: %d\n",
+				ret);
+			return ret;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
+				      unsigned long bclk_rate)
+{
+	struct device *dev = dai->dev;
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+	unsigned long sck_rate;
+	int pow2;
+
+	/* 64 MHz <= pll_rate <= 100 MHz, VREF mode */
+	/* 16 MHz <= sck_rate <=  25 MHz, VREF mode */
+
+	/* select sck_rate as a multiple of bclk_rate but still with
+	 * as many factors of 2 as possible, as that makes it easier
+	 * to find a fast DAC rate
+	 */
+	pow2 = 1 << fls((pcm512x_pll_max(pcm512x) - 16000000) / bclk_rate);
+	for (; pow2; pow2 >>= 1) {
+		sck_rate = rounddown(pcm512x_pll_max(pcm512x),
+				     bclk_rate * pow2);
+		if (sck_rate >= 16000000)
+			break;
+	}
+	if (!pow2) {
+		dev_err(dev, "Impossible to generate a suitable SCK\n");
+		return 0;
+	}
+
+	dev_dbg(dev, "sck_rate %lu\n", sck_rate);
+	return sck_rate;
+}
+
+/* pll_rate = pllin_rate * R * J.D / P
+ * 1 <= R <= 16
+ * 1 <= J <= 63
+ * 0 <= D <= 9999
+ * 1 <= P <= 15
+ * 64 MHz <= pll_rate <= 100 MHz
+ * if D == 0
+ *     1 MHz <= pllin_rate / P <= 20 MHz
+ * else if D > 0
+ *     6.667 MHz <= pllin_rate / P <= 20 MHz
+ *     4 <= J <= 11
+ *     R = 1
+ */
+static int pcm512x_find_pll_coeff(struct snd_soc_dai *dai,
+				  unsigned long pllin_rate,
+				  unsigned long pll_rate)
+{
+	struct device *dev = dai->dev;
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+	unsigned long common;
+	int R, J, D, P;
+	unsigned long K; /* 10000 * J.D */
+	unsigned long num;
+	unsigned long den;
+
+	common = gcd(pll_rate, pllin_rate);
+	dev_dbg(dev, "pll %lu pllin %lu common %lu\n",
+		pll_rate, pllin_rate, common);
+	num = pll_rate / common;
+	den = pllin_rate / common;
+
+	/* pllin_rate / P (or here, den) cannot be greater than 20 MHz */
+	if (pllin_rate / den > 20000000 && num < 8) {
+		num *= DIV_ROUND_UP(pllin_rate / den, 20000000);
+		den *= DIV_ROUND_UP(pllin_rate / den, 20000000);
+	}
+	dev_dbg(dev, "num / den = %lu / %lu\n", num, den);
+
+	P = den;
+	if (den <= 15 && num <= 16 * 63
+	    && 1000000 <= pllin_rate / P && pllin_rate / P <= 20000000) {
+		/* Try the case with D = 0 */
+		D = 0;
+		/* factor 'num' into J and R, such that R <= 16 and J <= 63 */
+		for (R = 16; R; R--) {
+			if (num % R)
+				continue;
+			J = num / R;
+			if (J == 0 || J > 63)
+				continue;
+
+			dev_dbg(dev, "R * J / P = %d * %d / %d\n", R, J, P);
+			pcm512x->real_pll = pll_rate;
+			goto done;
+		}
+		/* no luck */
+	}
+
+	R = 1;
+
+	if (num > 0xffffffffUL / 10000)
+		goto fallback;
+
+	/* Try to find an exact pll_rate using the D > 0 case */
+	common = gcd(10000 * num, den);
+	num = 10000 * num / common;
+	den /= common;
+	dev_dbg(dev, "num %lu den %lu common %lu\n", num, den, common);
+
+	for (P = den; P <= 15; P++) {
+		if (pllin_rate / P < 6667000 || 200000000 < pllin_rate / P)
+			continue;
+		if (num * P % den)
+			continue;
+		K = num * P / den;
+		/* J == 12 is ok if D == 0 */
+		if (K < 40000 || K > 120000)
+			continue;
+
+		J = K / 10000;
+		D = K % 10000;
+		dev_dbg(dev, "J.D / P = %d.%04d / %d\n", J, D, P);
+		pcm512x->real_pll = pll_rate;
+		goto done;
+	}
+
+	/* Fall back to an approximate pll_rate */
+
+fallback:
+	/* find smallest possible P */
+	P = DIV_ROUND_UP(pllin_rate, 20000000);
+	if (!P)
+		P = 1;
+	else if (P > 15) {
+		dev_err(dev, "Need a slower clock as pll-input\n");
+		return -EINVAL;
+	}
+	if (pllin_rate / P < 6667000) {
+		dev_err(dev, "Need a faster clock as pll-input\n");
+		return -EINVAL;
+	}
+	K = DIV_ROUND_CLOSEST_ULL(10000ULL * pll_rate * P, pllin_rate);
+	if (K < 40000)
+		K = 40000;
+	/* J == 12 is ok if D == 0 */
+	if (K > 120000)
+		K = 120000;
+	J = K / 10000;
+	D = K % 10000;
+	dev_dbg(dev, "J.D / P ~ %d.%04d / %d\n", J, D, P);
+	pcm512x->real_pll = DIV_ROUND_DOWN_ULL((u64)K * pllin_rate, 10000 * P);
+
+done:
+	pcm512x->pll_r = R;
+	pcm512x->pll_j = J;
+	pcm512x->pll_d = D;
+	pcm512x->pll_p = P;
+	return 0;
+}
+
+static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai,
+					    unsigned long osr_rate,
+					    unsigned long pllin_rate)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+	unsigned long dac_rate;
+
+	if (!pcm512x->pll_out)
+		return 0; /* no PLL to bypass, force SCK as DAC input */
+
+	if (pllin_rate % osr_rate)
+		return 0; /* futile, quit early */
+
+	/* run DAC no faster than 6144000 Hz */
+	for (dac_rate = rounddown(pcm512x_dac_max(pcm512x, 6144000), osr_rate);
+	     dac_rate;
+	     dac_rate -= osr_rate) {
+
+		if (pllin_rate / dac_rate > 128)
+			return 0; /* DAC divider would be too big */
+
+		if (!(pllin_rate % dac_rate))
+			return dac_rate;
+
+		dac_rate -= osr_rate;
+	}
+
+	return 0;
+}
+
+static int pcm512x_set_dividers(struct snd_soc_dai *dai,
+				struct snd_pcm_hw_params *params)
+{
+	struct device *dev = dai->dev;
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+	unsigned long pllin_rate = 0;
+	unsigned long pll_rate;
+	unsigned long sck_rate;
+	unsigned long mck_rate;
+	unsigned long bclk_rate;
+	unsigned long sample_rate;
+	unsigned long osr_rate;
+	unsigned long dacsrc_rate;
+	int bclk_div;
+	int lrclk_div;
+	int dsp_div;
+	int dac_div;
+	unsigned long dac_rate;
+	int ncp_div;
+	int osr_div;
+	int ret;
+	int idac;
+	int fssp;
+	int gpio;
+
+	lrclk_div = snd_soc_params_to_frame_size(params);
+	if (lrclk_div == 0) {
+		dev_err(dev, "No LRCLK?\n");
+		return -EINVAL;
+	}
+
+	if (!pcm512x->pll_out) {
+		sck_rate = clk_get_rate(pcm512x->sclk);
+		bclk_div = params->rate_den * 64 / lrclk_div;
+		bclk_rate = DIV_ROUND_CLOSEST(sck_rate, bclk_div);
+
+		mck_rate = sck_rate;
+	} else {
+		ret = snd_soc_params_to_bclk(params);
+		if (ret < 0) {
+			dev_err(dev, "Failed to find suitable BCLK: %d\n", ret);
+			return ret;
+		}
+		if (ret == 0) {
+			dev_err(dev, "No BCLK?\n");
+			return -EINVAL;
+		}
+		bclk_rate = ret;
+
+		pllin_rate = clk_get_rate(pcm512x->sclk);
+
+		sck_rate = pcm512x_find_sck(dai, bclk_rate);
+		if (!sck_rate)
+			return -EINVAL;
+		pll_rate = 4 * sck_rate;
+
+		ret = pcm512x_find_pll_coeff(dai, pllin_rate, pll_rate);
+		if (ret != 0)
+			return ret;
+
+		ret = regmap_write(pcm512x->regmap,
+				   PCM512x_PLL_COEFF_0, pcm512x->pll_p - 1);
+		if (ret != 0) {
+			dev_err(dev, "Failed to write PLL P: %d\n", ret);
+			return ret;
+		}
+
+		ret = regmap_write(pcm512x->regmap,
+				   PCM512x_PLL_COEFF_1, pcm512x->pll_j);
+		if (ret != 0) {
+			dev_err(dev, "Failed to write PLL J: %d\n", ret);
+			return ret;
+		}
+
+		ret = regmap_write(pcm512x->regmap,
+				   PCM512x_PLL_COEFF_2, pcm512x->pll_d >> 8);
+		if (ret != 0) {
+			dev_err(dev, "Failed to write PLL D msb: %d\n", ret);
+			return ret;
+		}
+
+		ret = regmap_write(pcm512x->regmap,
+				   PCM512x_PLL_COEFF_3, pcm512x->pll_d & 0xff);
+		if (ret != 0) {
+			dev_err(dev, "Failed to write PLL D lsb: %d\n", ret);
+			return ret;
+		}
+
+		ret = regmap_write(pcm512x->regmap,
+				   PCM512x_PLL_COEFF_4, pcm512x->pll_r - 1);
+		if (ret != 0) {
+			dev_err(dev, "Failed to write PLL R: %d\n", ret);
+			return ret;
+		}
+
+		mck_rate = pcm512x->real_pll;
+
+		bclk_div = DIV_ROUND_CLOSEST(sck_rate, bclk_rate);
+	}
+
+	if (bclk_div > 128) {
+		dev_err(dev, "Failed to find BCLK divider\n");
+		return -EINVAL;
+	}
+
+	/* the actual rate */
+	sample_rate = sck_rate / bclk_div / lrclk_div;
+	osr_rate = 16 * sample_rate;
+
+	/* run DSP no faster than 50 MHz */
+	dsp_div = mck_rate > pcm512x_dsp_max(pcm512x) ? 2 : 1;
+
+	dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate);
+	if (dac_rate) {
+		/* the desired clock rate is "compatible" with the pll input
+		 * clock, so use that clock as dac input instead of the pll
+		 * output clock since the pll will introduce jitter and thus
+		 * noise.
+		 */
+		dev_dbg(dev, "using pll input as dac input\n");
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF,
+					 PCM512x_SDAC, PCM512x_SDAC_GPIO);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to set gpio as dacref: %d\n", ret);
+			return ret;
+		}
+
+		gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1;
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_DACIN,
+					 PCM512x_GREF, gpio);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to set gpio %d as dacin: %d\n",
+				pcm512x->pll_in, ret);
+			return ret;
+		}
+
+		dacsrc_rate = pllin_rate;
+	} else {
+		/* run DAC no faster than 6144000 Hz */
+		unsigned long dac_mul = pcm512x_dac_max(pcm512x, 6144000)
+			/ osr_rate;
+		unsigned long sck_mul = sck_rate / osr_rate;
+
+		for (; dac_mul; dac_mul--) {
+			if (!(sck_mul % dac_mul))
+				break;
+		}
+		if (!dac_mul) {
+			dev_err(dev, "Failed to find DAC rate\n");
+			return -EINVAL;
+		}
+
+		dac_rate = dac_mul * osr_rate;
+		dev_dbg(dev, "dac_rate %lu sample_rate %lu\n",
+			dac_rate, sample_rate);
+
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF,
+					 PCM512x_SDAC, PCM512x_SDAC_SCK);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to set sck as dacref: %d\n", ret);
+			return ret;
+		}
+
+		dacsrc_rate = sck_rate;
+	}
+
+	osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate);
+	if (osr_div > 128) {
+		dev_err(dev, "Failed to find OSR divider\n");
+		return -EINVAL;
+	}
+
+	dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate);
+	if (dac_div > 128) {
+		dev_err(dev, "Failed to find DAC divider\n");
+		return -EINVAL;
+	}
+	dac_rate = dacsrc_rate / dac_div;
+
+	ncp_div = DIV_ROUND_CLOSEST(dac_rate,
+				    pcm512x_ncp_target(pcm512x, dac_rate));
+	if (ncp_div > 128 || dac_rate / ncp_div > 2048000) {
+		/* run NCP no faster than 2048000 Hz, but why? */
+		ncp_div = DIV_ROUND_UP(dac_rate, 2048000);
+		if (ncp_div > 128) {
+			dev_err(dev, "Failed to find NCP divider\n");
+			return -EINVAL;
+		}
+	}
+
+	idac = mck_rate / (dsp_div * sample_rate);
+
+	ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write DSP divider: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_write(pcm512x->regmap, PCM512x_DAC_CLKDIV, dac_div - 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write DAC divider: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_write(pcm512x->regmap, PCM512x_NCP_CLKDIV, ncp_div - 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write NCP divider: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_write(pcm512x->regmap, PCM512x_OSR_CLKDIV, osr_div - 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write OSR divider: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_write(pcm512x->regmap,
+			   PCM512x_MASTER_CLKDIV_1, bclk_div - 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write BCLK divider: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_write(pcm512x->regmap,
+			   PCM512x_MASTER_CLKDIV_2, lrclk_div - 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write LRCLK divider: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_write(pcm512x->regmap, PCM512x_IDAC_1, idac >> 8);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write IDAC msb divider: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_write(pcm512x->regmap, PCM512x_IDAC_2, idac & 0xff);
+	if (ret != 0) {
+		dev_err(dev, "Failed to write IDAC lsb divider: %d\n", ret);
+		return ret;
+	}
+
+	if (sample_rate <= pcm512x_dac_max(pcm512x, 48000))
+		fssp = PCM512x_FSSP_48KHZ;
+	else if (sample_rate <= pcm512x_dac_max(pcm512x, 96000))
+		fssp = PCM512x_FSSP_96KHZ;
+	else if (sample_rate <= pcm512x_dac_max(pcm512x, 192000))
+		fssp = PCM512x_FSSP_192KHZ;
+	else
+		fssp = PCM512x_FSSP_384KHZ;
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_FS_SPEED_MODE,
+				 PCM512x_FSSP, fssp);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set fs speed: %d\n", ret);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "DSP divider %d\n", dsp_div);
+	dev_dbg(component->dev, "DAC divider %d\n", dac_div);
+	dev_dbg(component->dev, "NCP divider %d\n", ncp_div);
+	dev_dbg(component->dev, "OSR divider %d\n", osr_div);
+	dev_dbg(component->dev, "BCK divider %d\n", bclk_div);
+	dev_dbg(component->dev, "LRCK divider %d\n", lrclk_div);
+	dev_dbg(component->dev, "IDAC %d\n", idac);
+	dev_dbg(component->dev, "1<<FSSP %d\n", 1 << fssp);
+
+	return 0;
+}
+
+static int pcm512x_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+	int alen;
+	int gpio;
+	int clock_output;
+	int master_mode;
+	int ret;
+
+	dev_dbg(component->dev, "hw_params %u Hz, %u channels\n",
+		params_rate(params),
+		params_channels(params));
+
+	switch (params_width(params)) {
+	case 16:
+		alen = PCM512x_ALEN_16;
+		break;
+	case 20:
+		alen = PCM512x_ALEN_20;
+		break;
+	case 24:
+		alen = PCM512x_ALEN_24;
+		break;
+	case 32:
+		alen = PCM512x_ALEN_32;
+		break;
+	default:
+		dev_err(component->dev, "Bad frame size: %d\n",
+			params_width(params));
+		return -EINVAL;
+	}
+
+	switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		ret = regmap_update_bits(pcm512x->regmap,
+					 PCM512x_BCLK_LRCLK_CFG,
+					 PCM512x_BCKP
+					 | PCM512x_BCKO | PCM512x_LRKO,
+					 0);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to enable slave mode: %d\n", ret);
+			return ret;
+		}
+
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
+					 PCM512x_DCAS, 0);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to enable clock divider autoset: %d\n",
+				ret);
+			return ret;
+		}
+		return 0;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		clock_output = PCM512x_BCKO | PCM512x_LRKO;
+		master_mode = PCM512x_RLRK | PCM512x_RBCK;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		clock_output = PCM512x_BCKO;
+		master_mode = PCM512x_RBCK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
+				 PCM512x_ALEN, alen);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set frame size: %d\n", ret);
+		return ret;
+	}
+
+	if (pcm512x->pll_out) {
+		ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_A, 0x11);
+		if (ret != 0) {
+			dev_err(component->dev, "Failed to set FLEX_A: %d\n", ret);
+			return ret;
+		}
+
+		ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_B, 0xff);
+		if (ret != 0) {
+			dev_err(component->dev, "Failed to set FLEX_B: %d\n", ret);
+			return ret;
+		}
+
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
+					 PCM512x_IDFS | PCM512x_IDBK
+					 | PCM512x_IDSK | PCM512x_IDCH
+					 | PCM512x_IDCM | PCM512x_DCAS
+					 | PCM512x_IPLK,
+					 PCM512x_IDFS | PCM512x_IDBK
+					 | PCM512x_IDSK | PCM512x_IDCH
+					 | PCM512x_DCAS);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to ignore auto-clock failures: %d\n",
+				ret);
+			return ret;
+		}
+	} else {
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
+					 PCM512x_IDFS | PCM512x_IDBK
+					 | PCM512x_IDSK | PCM512x_IDCH
+					 | PCM512x_IDCM | PCM512x_DCAS
+					 | PCM512x_IPLK,
+					 PCM512x_IDFS | PCM512x_IDBK
+					 | PCM512x_IDSK | PCM512x_IDCH
+					 | PCM512x_DCAS | PCM512x_IPLK);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to ignore auto-clock failures: %d\n",
+				ret);
+			return ret;
+		}
+
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN,
+					 PCM512x_PLLE, 0);
+		if (ret != 0) {
+			dev_err(component->dev, "Failed to disable pll: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = pcm512x_set_dividers(dai, params);
+	if (ret != 0)
+		return ret;
+
+	if (pcm512x->pll_out) {
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_REF,
+					 PCM512x_SREF, PCM512x_SREF_GPIO);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to set gpio as pllref: %d\n", ret);
+			return ret;
+		}
+
+		gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1;
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_PLLIN,
+					 PCM512x_GREF, gpio);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to set gpio %d as pllin: %d\n",
+				pcm512x->pll_in, ret);
+			return ret;
+		}
+
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN,
+					 PCM512x_PLLE, PCM512x_PLLE);
+		if (ret != 0) {
+			dev_err(component->dev, "Failed to enable pll: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG,
+				 PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
+				 clock_output);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to enable clock output: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE,
+				 PCM512x_RLRK | PCM512x_RBCK,
+				 master_mode);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to enable master mode: %d\n", ret);
+		return ret;
+	}
+
+	if (pcm512x->pll_out) {
+		gpio = PCM512x_G1OE << (pcm512x->pll_out - 1);
+		ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN,
+					 gpio, gpio);
+		if (ret != 0) {
+			dev_err(component->dev, "Failed to enable gpio %d: %d\n",
+				pcm512x->pll_out, ret);
+			return ret;
+		}
+
+		gpio = PCM512x_GPIO_OUTPUT_1 + pcm512x->pll_out - 1;
+		ret = regmap_update_bits(pcm512x->regmap, gpio,
+					 PCM512x_GxSL, PCM512x_GxSL_PLLCK);
+		if (ret != 0) {
+			dev_err(component->dev, "Failed to output pll on %d: %d\n",
+				ret, pcm512x->pll_out);
+			return ret;
+		}
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE,
+				 PCM512x_RQSY, PCM512x_RQSY_HALT);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to halt clocks: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE,
+				 PCM512x_RQSY, PCM512x_RQSY_RESUME);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to resume clocks: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+
+	pcm512x->fmt = fmt;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops pcm512x_dai_ops = {
+	.startup = pcm512x_dai_startup,
+	.hw_params = pcm512x_hw_params,
+	.set_fmt = pcm512x_set_fmt,
+};
+
+static struct snd_soc_dai_driver pcm512x_dai = {
+	.name = "pcm512x-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_CONTINUOUS,
+		.rate_min = 8000,
+		.rate_max = 384000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			   SNDRV_PCM_FMTBIT_S24_LE |
+			   SNDRV_PCM_FMTBIT_S32_LE
+	},
+	.ops = &pcm512x_dai_ops,
+};
+
+static const struct snd_soc_component_driver pcm512x_component_driver = {
+	.set_bias_level		= pcm512x_set_bias_level,
+	.controls		= pcm512x_controls,
+	.num_controls		= ARRAY_SIZE(pcm512x_controls),
+	.dapm_widgets		= pcm512x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm512x_dapm_widgets),
+	.dapm_routes		= pcm512x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm512x_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_range_cfg pcm512x_range = {
+	.name = "Pages", .range_min = PCM512x_VIRT_BASE,
+	.range_max = PCM512x_MAX_REGISTER,
+	.selector_reg = PCM512x_PAGE,
+	.selector_mask = 0xff,
+	.window_start = 0, .window_len = 0x100,
+};
+
+const struct regmap_config pcm512x_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.readable_reg = pcm512x_readable,
+	.volatile_reg = pcm512x_volatile,
+
+	.ranges = &pcm512x_range,
+	.num_ranges = 1,
+
+	.max_register = PCM512x_MAX_REGISTER,
+	.reg_defaults = pcm512x_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(pcm512x_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(pcm512x_regmap);
+
+int pcm512x_probe(struct device *dev, struct regmap *regmap)
+{
+	struct pcm512x_priv *pcm512x;
+	int i, ret;
+
+	pcm512x = devm_kzalloc(dev, sizeof(struct pcm512x_priv), GFP_KERNEL);
+	if (!pcm512x)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, pcm512x);
+	pcm512x->regmap = regmap;
+
+	for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++)
+		pcm512x->supplies[i].supply = pcm512x_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pcm512x->supplies),
+				      pcm512x->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to get supplies: %d\n", ret);
+		return ret;
+	}
+
+	pcm512x->supply_nb[0].notifier_call = pcm512x_regulator_event_0;
+	pcm512x->supply_nb[1].notifier_call = pcm512x_regulator_event_1;
+	pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2;
+
+	for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) {
+		ret = regulator_register_notifier(pcm512x->supplies[i].consumer,
+						  &pcm512x->supply_nb[i]);
+		if (ret != 0) {
+			dev_err(dev,
+				"Failed to register regulator notifier: %d\n",
+				ret);
+		}
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies),
+				    pcm512x->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	/* Reset the device, verifying I/O in the process for I2C */
+	ret = regmap_write(regmap, PCM512x_RESET,
+			   PCM512x_RSTM | PCM512x_RSTR);
+	if (ret != 0) {
+		dev_err(dev, "Failed to reset device: %d\n", ret);
+		goto err;
+	}
+
+	ret = regmap_write(regmap, PCM512x_RESET, 0);
+	if (ret != 0) {
+		dev_err(dev, "Failed to reset device: %d\n", ret);
+		goto err;
+	}
+
+	pcm512x->sclk = devm_clk_get(dev, NULL);
+	if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+	if (!IS_ERR(pcm512x->sclk)) {
+		ret = clk_prepare_enable(pcm512x->sclk);
+		if (ret != 0) {
+			dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+			return ret;
+		}
+	}
+
+	/* Default to standby mode */
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+				 PCM512x_RQST, PCM512x_RQST);
+	if (ret != 0) {
+		dev_err(dev, "Failed to request standby: %d\n",
+			ret);
+		goto err_clk;
+	}
+
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	pm_runtime_idle(dev);
+
+#ifdef CONFIG_OF
+	if (dev->of_node) {
+		const struct device_node *np = dev->of_node;
+		u32 val;
+
+		if (of_property_read_u32(np, "pll-in", &val) >= 0) {
+			if (val > 6) {
+				dev_err(dev, "Invalid pll-in\n");
+				ret = -EINVAL;
+				goto err_clk;
+			}
+			pcm512x->pll_in = val;
+		}
+
+		if (of_property_read_u32(np, "pll-out", &val) >= 0) {
+			if (val > 6) {
+				dev_err(dev, "Invalid pll-out\n");
+				ret = -EINVAL;
+				goto err_clk;
+			}
+			pcm512x->pll_out = val;
+		}
+
+		if (!pcm512x->pll_in != !pcm512x->pll_out) {
+			dev_err(dev,
+				"Error: both pll-in and pll-out, or none\n");
+			ret = -EINVAL;
+			goto err_clk;
+		}
+		if (pcm512x->pll_in && pcm512x->pll_in == pcm512x->pll_out) {
+			dev_err(dev, "Error: pll-in == pll-out\n");
+			ret = -EINVAL;
+			goto err_clk;
+		}
+	}
+#endif
+
+	ret = devm_snd_soc_register_component(dev, &pcm512x_component_driver,
+				    &pcm512x_dai, 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to register CODEC: %d\n", ret);
+		goto err_pm;
+	}
+
+	return 0;
+
+err_pm:
+	pm_runtime_disable(dev);
+err_clk:
+	if (!IS_ERR(pcm512x->sclk))
+		clk_disable_unprepare(pcm512x->sclk);
+err:
+	regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies),
+				     pcm512x->supplies);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pcm512x_probe);
+
+void pcm512x_remove(struct device *dev)
+{
+	struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
+
+	pm_runtime_disable(dev);
+	if (!IS_ERR(pcm512x->sclk))
+		clk_disable_unprepare(pcm512x->sclk);
+	regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies),
+			       pcm512x->supplies);
+}
+EXPORT_SYMBOL_GPL(pcm512x_remove);
+
+#ifdef CONFIG_PM
+static int pcm512x_suspend(struct device *dev)
+{
+	struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+				 PCM512x_RQPD, PCM512x_RQPD);
+	if (ret != 0) {
+		dev_err(dev, "Failed to request power down: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies),
+				     pcm512x->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to disable supplies: %d\n", ret);
+		return ret;
+	}
+
+	if (!IS_ERR(pcm512x->sclk))
+		clk_disable_unprepare(pcm512x->sclk);
+
+	return 0;
+}
+
+static int pcm512x_resume(struct device *dev)
+{
+	struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
+	int ret;
+
+	if (!IS_ERR(pcm512x->sclk)) {
+		ret = clk_prepare_enable(pcm512x->sclk);
+		if (ret != 0) {
+			dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies),
+				    pcm512x->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	regcache_cache_only(pcm512x->regmap, false);
+	ret = regcache_sync(pcm512x->regmap);
+	if (ret != 0) {
+		dev_err(dev, "Failed to sync cache: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+				 PCM512x_RQPD, 0);
+	if (ret != 0) {
+		dev_err(dev, "Failed to remove power down: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+#endif
+
+const struct dev_pm_ops pcm512x_pm_ops = {
+	SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(pcm512x_pm_ops);
+
+MODULE_DESCRIPTION("ASoC PCM512x codec driver");
+MODULE_AUTHOR("Mark Brown <broonie@kernel.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h
new file mode 100644
index 0000000..d70d9c0
--- /dev/null
+++ b/sound/soc/codecs/pcm512x.h
@@ -0,0 +1,270 @@
+/*
+ * Driver for the PCM512x CODECs
+ *
+ * Author:	Mark Brown <broonie@kernel.org>
+ *		Copyright 2014 Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _SND_SOC_PCM512X
+#define _SND_SOC_PCM512X
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#define PCM512x_VIRT_BASE 0x100
+#define PCM512x_PAGE_LEN  0x100
+#define PCM512x_PAGE_BASE(n)  (PCM512x_VIRT_BASE + (PCM512x_PAGE_LEN * n))
+
+#define PCM512x_PAGE              0
+
+#define PCM512x_RESET             (PCM512x_PAGE_BASE(0) +   1)
+#define PCM512x_POWER             (PCM512x_PAGE_BASE(0) +   2)
+#define PCM512x_MUTE              (PCM512x_PAGE_BASE(0) +   3)
+#define PCM512x_PLL_EN            (PCM512x_PAGE_BASE(0) +   4)
+#define PCM512x_SPI_MISO_FUNCTION (PCM512x_PAGE_BASE(0) +   6)
+#define PCM512x_DSP               (PCM512x_PAGE_BASE(0) +   7)
+#define PCM512x_GPIO_EN           (PCM512x_PAGE_BASE(0) +   8)
+#define PCM512x_BCLK_LRCLK_CFG    (PCM512x_PAGE_BASE(0) +   9)
+#define PCM512x_DSP_GPIO_INPUT    (PCM512x_PAGE_BASE(0) +  10)
+#define PCM512x_MASTER_MODE       (PCM512x_PAGE_BASE(0) +  12)
+#define PCM512x_PLL_REF           (PCM512x_PAGE_BASE(0) +  13)
+#define PCM512x_DAC_REF           (PCM512x_PAGE_BASE(0) +  14)
+#define PCM512x_GPIO_DACIN        (PCM512x_PAGE_BASE(0) +  16)
+#define PCM512x_GPIO_PLLIN        (PCM512x_PAGE_BASE(0) +  18)
+#define PCM512x_SYNCHRONIZE       (PCM512x_PAGE_BASE(0) +  19)
+#define PCM512x_PLL_COEFF_0       (PCM512x_PAGE_BASE(0) +  20)
+#define PCM512x_PLL_COEFF_1       (PCM512x_PAGE_BASE(0) +  21)
+#define PCM512x_PLL_COEFF_2       (PCM512x_PAGE_BASE(0) +  22)
+#define PCM512x_PLL_COEFF_3       (PCM512x_PAGE_BASE(0) +  23)
+#define PCM512x_PLL_COEFF_4       (PCM512x_PAGE_BASE(0) +  24)
+#define PCM512x_DSP_CLKDIV        (PCM512x_PAGE_BASE(0) +  27)
+#define PCM512x_DAC_CLKDIV        (PCM512x_PAGE_BASE(0) +  28)
+#define PCM512x_NCP_CLKDIV        (PCM512x_PAGE_BASE(0) +  29)
+#define PCM512x_OSR_CLKDIV        (PCM512x_PAGE_BASE(0) +  30)
+#define PCM512x_MASTER_CLKDIV_1   (PCM512x_PAGE_BASE(0) +  32)
+#define PCM512x_MASTER_CLKDIV_2   (PCM512x_PAGE_BASE(0) +  33)
+#define PCM512x_FS_SPEED_MODE     (PCM512x_PAGE_BASE(0) +  34)
+#define PCM512x_IDAC_1            (PCM512x_PAGE_BASE(0) +  35)
+#define PCM512x_IDAC_2            (PCM512x_PAGE_BASE(0) +  36)
+#define PCM512x_ERROR_DETECT      (PCM512x_PAGE_BASE(0) +  37)
+#define PCM512x_I2S_1             (PCM512x_PAGE_BASE(0) +  40)
+#define PCM512x_I2S_2             (PCM512x_PAGE_BASE(0) +  41)
+#define PCM512x_DAC_ROUTING       (PCM512x_PAGE_BASE(0) +  42)
+#define PCM512x_DSP_PROGRAM       (PCM512x_PAGE_BASE(0) +  43)
+#define PCM512x_CLKDET            (PCM512x_PAGE_BASE(0) +  44)
+#define PCM512x_AUTO_MUTE         (PCM512x_PAGE_BASE(0) +  59)
+#define PCM512x_DIGITAL_VOLUME_1  (PCM512x_PAGE_BASE(0) +  60)
+#define PCM512x_DIGITAL_VOLUME_2  (PCM512x_PAGE_BASE(0) +  61)
+#define PCM512x_DIGITAL_VOLUME_3  (PCM512x_PAGE_BASE(0) +  62)
+#define PCM512x_DIGITAL_MUTE_1    (PCM512x_PAGE_BASE(0) +  63)
+#define PCM512x_DIGITAL_MUTE_2    (PCM512x_PAGE_BASE(0) +  64)
+#define PCM512x_DIGITAL_MUTE_3    (PCM512x_PAGE_BASE(0) +  65)
+#define PCM512x_GPIO_OUTPUT_1     (PCM512x_PAGE_BASE(0) +  80)
+#define PCM512x_GPIO_OUTPUT_2     (PCM512x_PAGE_BASE(0) +  81)
+#define PCM512x_GPIO_OUTPUT_3     (PCM512x_PAGE_BASE(0) +  82)
+#define PCM512x_GPIO_OUTPUT_4     (PCM512x_PAGE_BASE(0) +  83)
+#define PCM512x_GPIO_OUTPUT_5     (PCM512x_PAGE_BASE(0) +  84)
+#define PCM512x_GPIO_OUTPUT_6     (PCM512x_PAGE_BASE(0) +  85)
+#define PCM512x_GPIO_CONTROL_1    (PCM512x_PAGE_BASE(0) +  86)
+#define PCM512x_GPIO_CONTROL_2    (PCM512x_PAGE_BASE(0) +  87)
+#define PCM512x_OVERFLOW          (PCM512x_PAGE_BASE(0) +  90)
+#define PCM512x_RATE_DET_1        (PCM512x_PAGE_BASE(0) +  91)
+#define PCM512x_RATE_DET_2        (PCM512x_PAGE_BASE(0) +  92)
+#define PCM512x_RATE_DET_3        (PCM512x_PAGE_BASE(0) +  93)
+#define PCM512x_RATE_DET_4        (PCM512x_PAGE_BASE(0) +  94)
+#define PCM512x_CLOCK_STATUS      (PCM512x_PAGE_BASE(0) +  95)
+#define PCM512x_ANALOG_MUTE_DET   (PCM512x_PAGE_BASE(0) + 108)
+#define PCM512x_GPIN              (PCM512x_PAGE_BASE(0) + 119)
+#define PCM512x_DIGITAL_MUTE_DET  (PCM512x_PAGE_BASE(0) + 120)
+
+#define PCM512x_OUTPUT_AMPLITUDE  (PCM512x_PAGE_BASE(1) +   1)
+#define PCM512x_ANALOG_GAIN_CTRL  (PCM512x_PAGE_BASE(1) +   2)
+#define PCM512x_UNDERVOLTAGE_PROT (PCM512x_PAGE_BASE(1) +   5)
+#define PCM512x_ANALOG_MUTE_CTRL  (PCM512x_PAGE_BASE(1) +   6)
+#define PCM512x_ANALOG_GAIN_BOOST (PCM512x_PAGE_BASE(1) +   7)
+#define PCM512x_VCOM_CTRL_1       (PCM512x_PAGE_BASE(1) +   8)
+#define PCM512x_VCOM_CTRL_2       (PCM512x_PAGE_BASE(1) +   9)
+
+#define PCM512x_CRAM_CTRL         (PCM512x_PAGE_BASE(44) +  1)
+
+#define PCM512x_FLEX_A            (PCM512x_PAGE_BASE(253) + 63)
+#define PCM512x_FLEX_B            (PCM512x_PAGE_BASE(253) + 64)
+
+#define PCM512x_MAX_REGISTER      (PCM512x_PAGE_BASE(253) + 64)
+
+/* Page 0, Register 1 - reset */
+#define PCM512x_RSTR (1 << 0)
+#define PCM512x_RSTM (1 << 4)
+
+/* Page 0, Register 2 - power */
+#define PCM512x_RQPD       (1 << 0)
+#define PCM512x_RQPD_SHIFT 0
+#define PCM512x_RQST       (1 << 4)
+#define PCM512x_RQST_SHIFT 4
+
+/* Page 0, Register 3 - mute */
+#define PCM512x_RQMR_SHIFT 0
+#define PCM512x_RQML_SHIFT 4
+
+/* Page 0, Register 4 - PLL */
+#define PCM512x_PLLE       (1 << 0)
+#define PCM512x_PLLE_SHIFT 0
+#define PCM512x_PLCK       (1 << 4)
+#define PCM512x_PLCK_SHIFT 4
+
+/* Page 0, Register 7 - DSP */
+#define PCM512x_SDSL       (1 << 0)
+#define PCM512x_SDSL_SHIFT 0
+#define PCM512x_DEMP       (1 << 4)
+#define PCM512x_DEMP_SHIFT 4
+
+/* Page 0, Register 8 - GPIO output enable */
+#define PCM512x_G1OE       (1 << 0)
+#define PCM512x_G2OE       (1 << 1)
+#define PCM512x_G3OE       (1 << 2)
+#define PCM512x_G4OE       (1 << 3)
+#define PCM512x_G5OE       (1 << 4)
+#define PCM512x_G6OE       (1 << 5)
+
+/* Page 0, Register 9 - BCK, LRCLK configuration */
+#define PCM512x_LRKO       (1 << 0)
+#define PCM512x_LRKO_SHIFT 0
+#define PCM512x_BCKO       (1 << 4)
+#define PCM512x_BCKO_SHIFT 4
+#define PCM512x_BCKP       (1 << 5)
+#define PCM512x_BCKP_SHIFT 5
+
+/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
+#define PCM512x_RLRK       (1 << 0)
+#define PCM512x_RLRK_SHIFT 0
+#define PCM512x_RBCK       (1 << 1)
+#define PCM512x_RBCK_SHIFT 1
+
+/* Page 0, Register 13 - PLL reference */
+#define PCM512x_SREF        (7 << 4)
+#define PCM512x_SREF_SHIFT  4
+#define PCM512x_SREF_SCK    (0 << 4)
+#define PCM512x_SREF_BCK    (1 << 4)
+#define PCM512x_SREF_GPIO   (3 << 4)
+
+/* Page 0, Register 14 - DAC reference */
+#define PCM512x_SDAC        (7 << 4)
+#define PCM512x_SDAC_SHIFT  4
+#define PCM512x_SDAC_MCK    (0 << 4)
+#define PCM512x_SDAC_PLL    (1 << 4)
+#define PCM512x_SDAC_SCK    (3 << 4)
+#define PCM512x_SDAC_BCK    (4 << 4)
+#define PCM512x_SDAC_GPIO   (5 << 4)
+
+/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
+#define PCM512x_GREF        (7 << 0)
+#define PCM512x_GREF_SHIFT  0
+#define PCM512x_GREF_GPIO1  (0 << 0)
+#define PCM512x_GREF_GPIO2  (1 << 0)
+#define PCM512x_GREF_GPIO3  (2 << 0)
+#define PCM512x_GREF_GPIO4  (3 << 0)
+#define PCM512x_GREF_GPIO5  (4 << 0)
+#define PCM512x_GREF_GPIO6  (5 << 0)
+
+/* Page 0, Register 19 - synchronize */
+#define PCM512x_RQSY        (1 << 0)
+#define PCM512x_RQSY_RESUME (0 << 0)
+#define PCM512x_RQSY_HALT   (1 << 0)
+
+/* Page 0, Register 34 - fs speed mode */
+#define PCM512x_FSSP        (3 << 0)
+#define PCM512x_FSSP_SHIFT  0
+#define PCM512x_FSSP_48KHZ  (0 << 0)
+#define PCM512x_FSSP_96KHZ  (1 << 0)
+#define PCM512x_FSSP_192KHZ (2 << 0)
+#define PCM512x_FSSP_384KHZ (3 << 0)
+
+/* Page 0, Register 37 - Error detection */
+#define PCM512x_IPLK (1 << 0)
+#define PCM512x_DCAS (1 << 1)
+#define PCM512x_IDCM (1 << 2)
+#define PCM512x_IDCH (1 << 3)
+#define PCM512x_IDSK (1 << 4)
+#define PCM512x_IDBK (1 << 5)
+#define PCM512x_IDFS (1 << 6)
+
+/* Page 0, Register 40 - I2S configuration */
+#define PCM512x_ALEN       (3 << 0)
+#define PCM512x_ALEN_SHIFT 0
+#define PCM512x_ALEN_16    (0 << 0)
+#define PCM512x_ALEN_20    (1 << 0)
+#define PCM512x_ALEN_24    (2 << 0)
+#define PCM512x_ALEN_32    (3 << 0)
+#define PCM512x_AFMT       (3 << 4)
+#define PCM512x_AFMT_SHIFT 4
+#define PCM512x_AFMT_I2S   (0 << 4)
+#define PCM512x_AFMT_DSP   (1 << 4)
+#define PCM512x_AFMT_RTJ   (2 << 4)
+#define PCM512x_AFMT_LTJ   (3 << 4)
+
+/* Page 0, Register 42 - DAC routing */
+#define PCM512x_AUPR_SHIFT 0
+#define PCM512x_AUPL_SHIFT 4
+
+/* Page 0, Register 59 - auto mute */
+#define PCM512x_ATMR_SHIFT 0
+#define PCM512x_ATML_SHIFT 4
+
+/* Page 0, Register 63 - ramp rates */
+#define PCM512x_VNDF_SHIFT 6
+#define PCM512x_VNDS_SHIFT 4
+#define PCM512x_VNUF_SHIFT 2
+#define PCM512x_VNUS_SHIFT 0
+
+/* Page 0, Register 64 - emergency ramp rates */
+#define PCM512x_VEDF_SHIFT 6
+#define PCM512x_VEDS_SHIFT 4
+
+/* Page 0, Register 65 - Digital mute enables */
+#define PCM512x_ACTL_SHIFT 2
+#define PCM512x_AMLE_SHIFT 1
+#define PCM512x_AMRE_SHIFT 0
+
+/* Page 0, Register 80-85, GPIO output selection */
+#define PCM512x_GxSL       (31 << 0)
+#define PCM512x_GxSL_SHIFT 0
+#define PCM512x_GxSL_OFF   (0 << 0)
+#define PCM512x_GxSL_DSP   (1 << 0)
+#define PCM512x_GxSL_REG   (2 << 0)
+#define PCM512x_GxSL_AMUTB (3 << 0)
+#define PCM512x_GxSL_AMUTL (4 << 0)
+#define PCM512x_GxSL_AMUTR (5 << 0)
+#define PCM512x_GxSL_CLKI  (6 << 0)
+#define PCM512x_GxSL_SDOUT (7 << 0)
+#define PCM512x_GxSL_ANMUL (8 << 0)
+#define PCM512x_GxSL_ANMUR (9 << 0)
+#define PCM512x_GxSL_PLLLK (10 << 0)
+#define PCM512x_GxSL_CPCLK (11 << 0)
+#define PCM512x_GxSL_UV0_7 (14 << 0)
+#define PCM512x_GxSL_UV0_3 (15 << 0)
+#define PCM512x_GxSL_PLLCK (16 << 0)
+
+/* Page 1, Register 2 - analog volume control */
+#define PCM512x_RAGN_SHIFT 0
+#define PCM512x_LAGN_SHIFT 4
+
+/* Page 1, Register 7 - analog boost control */
+#define PCM512x_AGBR_SHIFT 0
+#define PCM512x_AGBL_SHIFT 4
+
+extern const struct dev_pm_ops pcm512x_pm_ops;
+extern const struct regmap_config pcm512x_regmap;
+
+int pcm512x_probe(struct device *dev, struct regmap *regmap);
+void pcm512x_remove(struct device *dev);
+
+#endif
diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c
new file mode 100644
index 0000000..7ef3b54
--- /dev/null
+++ b/sound/soc/codecs/rl6231.c
@@ -0,0 +1,244 @@
+/*
+ * rl6231.c - RL6231 class device shared support
+ *
+ * Copyright 2014 Realtek Semiconductor Corp.
+ *
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include <linux/gcd.h>
+#include "rl6231.h"
+
+/**
+ * rl6231_get_pre_div - Return the value of pre divider.
+ *
+ * @map: map for setting.
+ * @reg: register.
+ * @sft: shift.
+ *
+ * Return the value of pre divider from given register value.
+ * Return negative error code for unexpected register value.
+ */
+int rl6231_get_pre_div(struct regmap *map, unsigned int reg, int sft)
+{
+	int pd, val;
+
+	regmap_read(map, reg, &val);
+
+	val = (val >> sft) & 0x7;
+
+	switch (val) {
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+		pd = val + 1;
+		break;
+	case 4:
+		pd = 6;
+		break;
+	case 5:
+		pd = 8;
+		break;
+	case 6:
+		pd = 12;
+		break;
+	case 7:
+		pd = 16;
+		break;
+	default:
+		pd = -EINVAL;
+		break;
+	}
+
+	return pd;
+}
+EXPORT_SYMBOL_GPL(rl6231_get_pre_div);
+
+/**
+ * rl6231_calc_dmic_clk - Calculate the frequency divider parameter of dmic.
+ *
+ * @rate: base clock rate.
+ *
+ * Choose divider parameter that gives the highest possible DMIC frequency in
+ * 1MHz - 3MHz range.
+ */
+int rl6231_calc_dmic_clk(int rate)
+{
+	static const int div[] = {2, 3, 4, 6, 8, 12};
+	int i;
+
+	if (rate < 1000000 * div[0]) {
+		pr_warn("Base clock rate %d is too low\n", rate);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(div); i++) {
+		if ((div[i] % 3) == 0)
+			continue;
+		/* find divider that gives DMIC frequency below 3.072MHz */
+		if (3072000 * div[i] >= rate)
+			return i;
+	}
+
+	pr_warn("Base clock rate %d is too high\n", rate);
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(rl6231_calc_dmic_clk);
+
+struct pll_calc_map {
+	unsigned int pll_in;
+	unsigned int pll_out;
+	int k;
+	int n;
+	int m;
+	bool m_bp;
+};
+
+static const struct pll_calc_map pll_preset_table[] = {
+	{19200000,  4096000,  23, 14, 1, false},
+	{19200000,  24576000,  3, 30, 3, false},
+};
+
+static unsigned int find_best_div(unsigned int in,
+	unsigned int max, unsigned int div)
+{
+	unsigned int d;
+
+	if (in <= max)
+		return 1;
+
+	d = in / max;
+	if (in % max)
+		d++;
+
+	while (div % d != 0)
+		d++;
+
+
+	return d;
+}
+
+/**
+ * rl6231_pll_calc - Calcualte PLL M/N/K code.
+ * @freq_in: external clock provided to codec.
+ * @freq_out: target clock which codec works on.
+ * @pll_code: Pointer to structure with M, N, K and bypass flag.
+ *
+ * Calcualte M/N/K code to configure PLL for codec.
+ *
+ * Returns 0 for success or negative error code.
+ */
+int rl6231_pll_calc(const unsigned int freq_in,
+	const unsigned int freq_out, struct rl6231_pll_code *pll_code)
+{
+	int max_n = RL6231_PLL_N_MAX, max_m = RL6231_PLL_M_MAX;
+	int i, k, n_t;
+	int k_t, min_k, max_k, n = 0, m = 0, m_t = 0;
+	unsigned int red, pll_out, in_t, out_t, div, div_t;
+	unsigned int red_t = abs(freq_out - freq_in);
+	unsigned int f_in, f_out, f_max;
+	bool bypass = false;
+
+	if (RL6231_PLL_INP_MAX < freq_in || RL6231_PLL_INP_MIN > freq_in)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(pll_preset_table); i++) {
+		if (freq_in == pll_preset_table[i].pll_in &&
+			freq_out == pll_preset_table[i].pll_out) {
+			k = pll_preset_table[i].k;
+			m = pll_preset_table[i].m;
+			n = pll_preset_table[i].n;
+			bypass = pll_preset_table[i].m_bp;
+			pr_debug("Use preset PLL parameter table\n");
+			goto code_find;
+		}
+	}
+
+	min_k = 80000000 / freq_out - 2;
+	max_k = 150000000 / freq_out - 2;
+	if (max_k > RL6231_PLL_K_MAX)
+		max_k = RL6231_PLL_K_MAX;
+	if (min_k > RL6231_PLL_K_MAX)
+		min_k = max_k = RL6231_PLL_K_MAX;
+	div_t = gcd(freq_in, freq_out);
+	f_max = 0xffffffff / RL6231_PLL_N_MAX;
+	div = find_best_div(freq_in, f_max, div_t);
+	f_in = freq_in / div;
+	f_out = freq_out / div;
+	k = min_k;
+	for (k_t = min_k; k_t <= max_k; k_t++) {
+		for (n_t = 0; n_t <= max_n; n_t++) {
+			in_t = f_in * (n_t + 2);
+			pll_out = f_out * (k_t + 2);
+			if (in_t == pll_out) {
+				bypass = true;
+				n = n_t;
+				k = k_t;
+				goto code_find;
+			}
+			out_t = in_t / (k_t + 2);
+			red = abs(f_out - out_t);
+			if (red < red_t) {
+				bypass = true;
+				n = n_t;
+				m = 0;
+				k = k_t;
+				if (red == 0)
+					goto code_find;
+				red_t = red;
+			}
+			for (m_t = 0; m_t <= max_m; m_t++) {
+				out_t = in_t / ((m_t + 2) * (k_t + 2));
+				red = abs(f_out - out_t);
+				if (red < red_t) {
+					bypass = false;
+					n = n_t;
+					m = m_t;
+					k = k_t;
+					if (red == 0)
+						goto code_find;
+					red_t = red;
+				}
+			}
+		}
+	}
+	pr_debug("Only get approximation about PLL\n");
+
+code_find:
+
+	pll_code->m_bp = bypass;
+	pll_code->m_code = m;
+	pll_code->n_code = n;
+	pll_code->k_code = k;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rl6231_pll_calc);
+
+int rl6231_get_clk_info(int sclk, int rate)
+{
+	int i;
+	static const int pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
+
+	if (sclk <= 0 || rate <= 0)
+		return -EINVAL;
+
+	rate = rate << 8;
+	for (i = 0; i < ARRAY_SIZE(pd); i++)
+		if (sclk == rate * pd[i])
+			return i;
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(rl6231_get_clk_info);
+
+MODULE_DESCRIPTION("RL6231 class device shared support");
+MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rl6231.h b/sound/soc/codecs/rl6231.h
new file mode 100644
index 0000000..4c77b44
--- /dev/null
+++ b/sound/soc/codecs/rl6231.h
@@ -0,0 +1,35 @@
+/*
+ * rl6231.h - RL6231 class device shared support
+ *
+ * Copyright 2014 Realtek Semiconductor Corp.
+ *
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RL6231_H__
+#define __RL6231_H__
+
+#define RL6231_PLL_INP_MAX	40000000
+#define RL6231_PLL_INP_MIN	256000
+#define RL6231_PLL_N_MAX	0x1ff
+#define RL6231_PLL_K_MAX	0x1f
+#define RL6231_PLL_M_MAX	0xf
+
+struct rl6231_pll_code {
+	bool m_bp; /* Indicates bypass m code or not. */
+	int m_code;
+	int n_code;
+	int k_code;
+};
+
+int rl6231_calc_dmic_clk(int rate);
+int rl6231_pll_calc(const unsigned int freq_in,
+	const unsigned int freq_out, struct rl6231_pll_code *pll_code);
+int rl6231_get_clk_info(int sclk, int rate);
+int rl6231_get_pre_div(struct regmap *map, unsigned int reg, int sft);
+
+#endif /* __RL6231_H__ */
diff --git a/sound/soc/codecs/rl6347a.c b/sound/soc/codecs/rl6347a.c
new file mode 100644
index 0000000..8f571cf
--- /dev/null
+++ b/sound/soc/codecs/rl6347a.c
@@ -0,0 +1,111 @@
+/*
+ * rl6347a.c - RL6347A class device shared support
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ *
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include "rl6347a.h"
+
+int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value)
+{
+	struct i2c_client *client = context;
+	struct rl6347a_priv *rl6347a = i2c_get_clientdata(client);
+	u8 data[4];
+	int ret, i;
+
+	/* handle index registers */
+	if (reg <= 0xff) {
+		rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg);
+		for (i = 0; i < rl6347a->index_cache_size; i++) {
+			if (reg == rl6347a->index_cache[i].reg) {
+				rl6347a->index_cache[i].def = value;
+				break;
+			}
+
+		}
+		reg = RL6347A_PROC_COEF;
+	}
+
+	data[0] = (reg >> 24) & 0xff;
+	data[1] = (reg >> 16) & 0xff;
+	/*
+	 * 4 bit VID: reg should be 0
+	 * 12 bit VID: value should be 0
+	 * So we use an OR operator to handle it rather than use if condition.
+	 */
+	data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff);
+	data[3] = value & 0xff;
+
+	ret = i2c_master_send(client, data, 4);
+
+	if (ret == 4)
+		return 0;
+	else
+		dev_err(&client->dev, "I2C error %d\n", ret);
+	if (ret < 0)
+		return ret;
+	else
+		return -EIO;
+}
+EXPORT_SYMBOL_GPL(rl6347a_hw_write);
+
+int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value)
+{
+	struct i2c_client *client = context;
+	struct i2c_msg xfer[2];
+	int ret;
+	__be32 be_reg;
+	unsigned int index, vid, buf = 0x0;
+
+	/* handle index registers */
+	if (reg <= 0xff) {
+		rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg);
+		reg = RL6347A_PROC_COEF;
+	}
+
+	reg = reg | 0x80000;
+	vid = (reg >> 8) & 0xfff;
+
+	if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) {
+		index = (reg >> 8) & 0xf;
+		reg = (reg & ~0xf0f) | index;
+	}
+	be_reg = cpu_to_be32(reg);
+
+	/* Write register */
+	xfer[0].addr = client->addr;
+	xfer[0].flags = 0;
+	xfer[0].len = 4;
+	xfer[0].buf = (u8 *)&be_reg;
+
+	/* Read data */
+	xfer[1].addr = client->addr;
+	xfer[1].flags = I2C_M_RD;
+	xfer[1].len = 4;
+	xfer[1].buf = (u8 *)&buf;
+
+	ret = i2c_transfer(client->adapter, xfer, 2);
+	if (ret < 0)
+		return ret;
+	else if (ret != 2)
+		return -EIO;
+
+	*value = be32_to_cpu(buf);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rl6347a_hw_read);
+
+MODULE_DESCRIPTION("RL6347A class device shared support");
+MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rl6347a.h b/sound/soc/codecs/rl6347a.h
new file mode 100644
index 0000000..e127919
--- /dev/null
+++ b/sound/soc/codecs/rl6347a.h
@@ -0,0 +1,34 @@
+/*
+ * rl6347a.h - RL6347A class device shared support
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ *
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __RL6347A_H__
+#define __RL6347A_H__
+
+#include <sound/hda_verbs.h>
+
+#define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D)
+
+#define RL6347A_VENDOR_REGISTERS	0x20
+
+#define RL6347A_COEF_INDEX\
+	VERB_CMD(AC_VERB_SET_COEF_INDEX, RL6347A_VENDOR_REGISTERS, 0)
+#define RL6347A_PROC_COEF\
+	VERB_CMD(AC_VERB_SET_PROC_COEF, RL6347A_VENDOR_REGISTERS, 0)
+
+struct rl6347a_priv {
+	struct reg_default *index_cache;
+	int index_cache_size;
+};
+
+int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value);
+int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value);
+
+#endif /* __RL6347A_H__ */
diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c
new file mode 100644
index 0000000..c4452ef
--- /dev/null
+++ b/sound/soc/codecs/rt1305.c
@@ -0,0 +1,1184 @@
+/*
+ * rt1305.c  --  RT1305 ALSA SoC amplifier component driver
+ *
+ * Copyright 2018 Realtek Semiconductor Corp.
+ * Author: Shuming Fan <shumingf@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/acpi.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rl6231.h"
+#include "rt1305.h"
+
+
+#define RT1305_PR_RANGE_BASE (0xff + 1)
+#define RT1305_PR_SPACING 0x100
+
+#define RT1305_PR_BASE (RT1305_PR_RANGE_BASE + (0 * RT1305_PR_SPACING))
+
+
+static const struct regmap_range_cfg rt1305_ranges[] = {
+	{
+		.name = "PR",
+		.range_min = RT1305_PR_BASE,
+		.range_max = RT1305_PR_BASE + 0xff,
+		.selector_reg = RT1305_PRIV_INDEX,
+		.selector_mask = 0xff,
+		.selector_shift = 0x0,
+		.window_start = RT1305_PRIV_DATA,
+		.window_len = 0x1,
+	},
+};
+
+
+static const struct reg_sequence init_list[] = {
+
+	{ RT1305_PR_BASE + 0xcf, 0x5548 },
+	{ RT1305_PR_BASE + 0x5d, 0x0442 },
+	{ RT1305_PR_BASE + 0xc1, 0x0320 },
+
+	{ RT1305_POWER_STATUS, 0x0000 },
+
+	{ RT1305_SPK_TEMP_PROTECTION_1, 0xd6de },
+	{ RT1305_SPK_TEMP_PROTECTION_2, 0x0707 },
+	{ RT1305_SPK_TEMP_PROTECTION_3, 0x4090 },
+
+	{ RT1305_DAC_SET_1, 0xdfdf },	/* 4 ohm 2W  */
+	{ RT1305_ADC_SET_3, 0x0219 },
+	{ RT1305_ADC_SET_1, 0x170f },	/* 0.2 ohm RSense*/
+
+};
+#define RT1305_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+struct rt1305_priv {
+	struct snd_soc_component *component;
+	struct regmap *regmap;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck;
+	int bclk;
+	int master;
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+};
+
+static const struct reg_default rt1305_reg[] = {
+
+	{ 0x04, 0x0400 },
+	{ 0x05, 0x0880 },
+	{ 0x06, 0x0000 },
+	{ 0x07, 0x3100 },
+	{ 0x08, 0x8000 },
+	{ 0x09, 0x0000 },
+	{ 0x0a, 0x087e },
+	{ 0x0b, 0x0020 },
+	{ 0x0c, 0x0802 },
+	{ 0x0d, 0x0020 },
+	{ 0x10, 0x1d1d },
+	{ 0x11, 0x1d1d },
+	{ 0x12, 0xffff },
+	{ 0x14, 0x000c },
+	{ 0x16, 0x1717 },
+	{ 0x17, 0x4000 },
+	{ 0x18, 0x0019 },
+	{ 0x20, 0x0000 },
+	{ 0x22, 0x0000 },
+	{ 0x24, 0x0000 },
+	{ 0x26, 0x0000 },
+	{ 0x28, 0x0000 },
+	{ 0x2a, 0x4000 },
+	{ 0x2b, 0x3000 },
+	{ 0x2d, 0x6000 },
+	{ 0x2e, 0x0000 },
+	{ 0x2f, 0x8000 },
+	{ 0x32, 0x0000 },
+	{ 0x39, 0x0001 },
+	{ 0x3a, 0x0000 },
+	{ 0x3b, 0x1020 },
+	{ 0x3c, 0x0000 },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x4c00 },
+	{ 0x3f, 0x3000 },
+	{ 0x40, 0x000c },
+	{ 0x42, 0x0400 },
+	{ 0x46, 0xc22c },
+	{ 0x47, 0x0000 },
+	{ 0x4b, 0x0000 },
+	{ 0x4c, 0x0300 },
+	{ 0x4f, 0xf000 },
+	{ 0x50, 0xc200 },
+	{ 0x51, 0x1f1f },
+	{ 0x52, 0x01f0 },
+	{ 0x53, 0x407f },
+	{ 0x54, 0xffff },
+	{ 0x58, 0x4005 },
+	{ 0x5e, 0x0000 },
+	{ 0x5f, 0x0000 },
+	{ 0x60, 0xee13 },
+	{ 0x62, 0x0000 },
+	{ 0x63, 0x5f5f },
+	{ 0x64, 0x0040 },
+	{ 0x65, 0x4000 },
+	{ 0x66, 0x4004 },
+	{ 0x67, 0x0306 },
+	{ 0x68, 0x8c04 },
+	{ 0x69, 0xe021 },
+	{ 0x6a, 0x0000 },
+	{ 0x6c, 0xaaaa },
+	{ 0x70, 0x0333 },
+	{ 0x71, 0x3330 },
+	{ 0x72, 0x3333 },
+	{ 0x73, 0x3300 },
+	{ 0x74, 0x0000 },
+	{ 0x75, 0x0000 },
+	{ 0x76, 0x0000 },
+	{ 0x7a, 0x0003 },
+	{ 0x7c, 0x10ec },
+	{ 0x7e, 0x6251 },
+	{ 0x80, 0x0800 },
+	{ 0x81, 0x4000 },
+	{ 0x82, 0x0000 },
+	{ 0x90, 0x7a01 },
+	{ 0x91, 0x8431 },
+	{ 0x92, 0x0180 },
+	{ 0x93, 0x0000 },
+	{ 0x94, 0x0000 },
+	{ 0x95, 0x0000 },
+	{ 0x96, 0x0000 },
+	{ 0x97, 0x0000 },
+	{ 0x98, 0x0000 },
+	{ 0x99, 0x0000 },
+	{ 0x9a, 0x0000 },
+	{ 0x9b, 0x0000 },
+	{ 0x9c, 0x0000 },
+	{ 0x9d, 0x0000 },
+	{ 0x9e, 0x0000 },
+	{ 0x9f, 0x0000 },
+	{ 0xa0, 0x0000 },
+	{ 0xb0, 0x8200 },
+	{ 0xb1, 0x00ff },
+	{ 0xb2, 0x0008 },
+	{ 0xc0, 0x0200 },
+	{ 0xc1, 0x0000 },
+	{ 0xc2, 0x0000 },
+	{ 0xc3, 0x0000 },
+	{ 0xc4, 0x0000 },
+	{ 0xc5, 0x0000 },
+	{ 0xc6, 0x0000 },
+	{ 0xc7, 0x0000 },
+	{ 0xc8, 0x0000 },
+	{ 0xc9, 0x0000 },
+	{ 0xca, 0x0200 },
+	{ 0xcb, 0x0000 },
+	{ 0xcc, 0x0000 },
+	{ 0xcd, 0x0000 },
+	{ 0xce, 0x0000 },
+	{ 0xcf, 0x0000 },
+	{ 0xd0, 0x0000 },
+	{ 0xd1, 0x0000 },
+	{ 0xd2, 0x0000 },
+	{ 0xd3, 0x0000 },
+	{ 0xd4, 0x0200 },
+	{ 0xd5, 0x0000 },
+	{ 0xd6, 0x0000 },
+	{ 0xd7, 0x0000 },
+	{ 0xd8, 0x0000 },
+	{ 0xd9, 0x0000 },
+	{ 0xda, 0x0000 },
+	{ 0xdb, 0x0000 },
+	{ 0xdc, 0x0000 },
+	{ 0xdd, 0x0000 },
+	{ 0xde, 0x0200 },
+	{ 0xdf, 0x0000 },
+	{ 0xe0, 0x0000 },
+	{ 0xe1, 0x0000 },
+	{ 0xe2, 0x0000 },
+	{ 0xe3, 0x0000 },
+	{ 0xe4, 0x0000 },
+	{ 0xe5, 0x0000 },
+	{ 0xe6, 0x0000 },
+	{ 0xe7, 0x0000 },
+	{ 0xe8, 0x0200 },
+	{ 0xe9, 0x0000 },
+	{ 0xea, 0x0000 },
+	{ 0xeb, 0x0000 },
+	{ 0xec, 0x0000 },
+	{ 0xed, 0x0000 },
+	{ 0xee, 0x0000 },
+	{ 0xef, 0x0000 },
+	{ 0xf0, 0x0000 },
+	{ 0xf1, 0x0000 },
+	{ 0xf2, 0x0200 },
+	{ 0xf3, 0x0000 },
+	{ 0xf4, 0x0000 },
+	{ 0xf5, 0x0000 },
+	{ 0xf6, 0x0000 },
+	{ 0xf7, 0x0000 },
+	{ 0xf8, 0x0000 },
+	{ 0xf9, 0x0000 },
+	{ 0xfa, 0x0000 },
+	{ 0xfb, 0x0000 },
+};
+
+static int rt1305_reg_init(struct snd_soc_component *component)
+{
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+
+	regmap_multi_reg_write(rt1305->regmap, init_list, RT1305_INIT_REG_LEN);
+	return 0;
+}
+
+static bool rt1305_volatile_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt1305_ranges); i++) {
+		if (reg >= rt1305_ranges[i].range_min &&
+			reg <= rt1305_ranges[i].range_max) {
+			return true;
+		}
+	}
+
+	switch (reg) {
+	case RT1305_RESET:
+	case RT1305_SPDIF_IN_SET_1:
+	case RT1305_SPDIF_IN_SET_2:
+	case RT1305_SPDIF_IN_SET_3:
+	case RT1305_POWER_CTRL_2:
+	case RT1305_CLOCK_DETECT:
+	case RT1305_BIQUAD_SET_1:
+	case RT1305_BIQUAD_SET_2:
+	case RT1305_EQ_SET_2:
+	case RT1305_SPK_TEMP_PROTECTION_0:
+	case RT1305_SPK_TEMP_PROTECTION_2:
+	case RT1305_SPK_DC_DETECT_1:
+	case RT1305_SILENCE_DETECT:
+	case RT1305_VERSION_ID:
+	case RT1305_VENDOR_ID:
+	case RT1305_DEVICE_ID:
+	case RT1305_EFUSE_1:
+	case RT1305_EFUSE_3:
+	case RT1305_DC_CALIB_1:
+	case RT1305_DC_CALIB_3:
+	case RT1305_DAC_OFFSET_1:
+	case RT1305_DAC_OFFSET_2:
+	case RT1305_DAC_OFFSET_3:
+	case RT1305_DAC_OFFSET_4:
+	case RT1305_DAC_OFFSET_5:
+	case RT1305_DAC_OFFSET_6:
+	case RT1305_DAC_OFFSET_7:
+	case RT1305_DAC_OFFSET_8:
+	case RT1305_DAC_OFFSET_9:
+	case RT1305_DAC_OFFSET_10:
+	case RT1305_DAC_OFFSET_11:
+	case RT1305_TRIM_1:
+	case RT1305_TRIM_2:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+static bool rt1305_readable_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt1305_ranges); i++) {
+		if (reg >= rt1305_ranges[i].range_min &&
+			reg <= rt1305_ranges[i].range_max) {
+			return true;
+		}
+	}
+
+	switch (reg) {
+	case RT1305_RESET:
+	case RT1305_CLK_1 ... RT1305_CAL_EFUSE_CLOCK:
+	case RT1305_PLL0_1 ... RT1305_PLL1_2:
+	case RT1305_MIXER_CTRL_1:
+	case RT1305_MIXER_CTRL_2:
+	case RT1305_DAC_SET_1:
+	case RT1305_DAC_SET_2:
+	case RT1305_ADC_SET_1:
+	case RT1305_ADC_SET_2:
+	case RT1305_ADC_SET_3:
+	case RT1305_PATH_SET:
+	case RT1305_SPDIF_IN_SET_1:
+	case RT1305_SPDIF_IN_SET_2:
+	case RT1305_SPDIF_IN_SET_3:
+	case RT1305_SPDIF_OUT_SET_1:
+	case RT1305_SPDIF_OUT_SET_2:
+	case RT1305_SPDIF_OUT_SET_3:
+	case RT1305_I2S_SET_1:
+	case RT1305_I2S_SET_2:
+	case RT1305_PBTL_MONO_MODE_SRC:
+	case RT1305_MANUALLY_I2C_DEVICE:
+	case RT1305_POWER_STATUS:
+	case RT1305_POWER_CTRL_1:
+	case RT1305_POWER_CTRL_2:
+	case RT1305_POWER_CTRL_3:
+	case RT1305_POWER_CTRL_4:
+	case RT1305_POWER_CTRL_5:
+	case RT1305_CLOCK_DETECT:
+	case RT1305_BIQUAD_SET_1:
+	case RT1305_BIQUAD_SET_2:
+	case RT1305_ADJUSTED_HPF_1:
+	case RT1305_ADJUSTED_HPF_2:
+	case RT1305_EQ_SET_1:
+	case RT1305_EQ_SET_2:
+	case RT1305_SPK_TEMP_PROTECTION_0:
+	case RT1305_SPK_TEMP_PROTECTION_1:
+	case RT1305_SPK_TEMP_PROTECTION_2:
+	case RT1305_SPK_TEMP_PROTECTION_3:
+	case RT1305_SPK_DC_DETECT_1:
+	case RT1305_SPK_DC_DETECT_2:
+	case RT1305_LOUDNESS:
+	case RT1305_THERMAL_FOLD_BACK_1:
+	case RT1305_THERMAL_FOLD_BACK_2:
+	case RT1305_SILENCE_DETECT ... RT1305_SPK_EXCURSION_LIMITER_7:
+	case RT1305_VERSION_ID:
+	case RT1305_VENDOR_ID:
+	case RT1305_DEVICE_ID:
+	case RT1305_EFUSE_1:
+	case RT1305_EFUSE_2:
+	case RT1305_EFUSE_3:
+	case RT1305_DC_CALIB_1:
+	case RT1305_DC_CALIB_2:
+	case RT1305_DC_CALIB_3:
+	case RT1305_DAC_OFFSET_1 ... RT1305_DAC_OFFSET_14:
+	case RT1305_TRIM_1:
+	case RT1305_TRIM_2:
+	case RT1305_TUNE_INTERNAL_OSC:
+	case RT1305_BIQUAD1_H0_L_28_16 ... RT1305_BIQUAD3_A2_R_15_0:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9435, 37, 0);
+
+static const char * const rt1305_rx_data_ch_select[] = {
+	"LR",
+	"RL",
+	"Copy L",
+	"Copy R",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1305_rx_data_ch_enum, RT1305_I2S_SET_2, 2,
+	rt1305_rx_data_ch_select);
+
+static void rt1305_reset(struct regmap *regmap)
+{
+	regmap_write(regmap, RT1305_RESET, 0);
+}
+
+static const struct snd_kcontrol_new rt1305_snd_controls[] = {
+	SOC_DOUBLE_TLV("DAC Playback Volume", RT1305_DAC_SET_1,
+			8, 0, 0xff, 0, dac_vol_tlv),
+
+	/* I2S Data Channel Selection */
+	SOC_ENUM("RX Channel Select", rt1305_rx_data_ch_enum),
+};
+
+static int rt1305_is_rc_clk_from_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(source->dapm);
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	snd_soc_component_read(component, RT1305_CLK_1, &val);
+
+	if (rt1305->sysclk_src == RT1305_FS_SYS_PRE_S_PLL1 &&
+		(val & RT1305_SEL_PLL_SRC_2_RCCLK))
+		return 1;
+	else
+		return 0;
+}
+
+static int rt1305_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(source->dapm);
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+
+	if (rt1305->sysclk_src == RT1305_FS_SYS_PRE_S_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int rt1305_classd_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT1305_POWER_CTRL_1,
+			RT1305_POW_PDB_JD_MASK, RT1305_POW_PDB_JD);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT1305_POWER_CTRL_1,
+			RT1305_POW_PDB_JD_MASK, 0);
+		usleep_range(150000, 200000);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new rt1305_sto_dac_l =
+	SOC_DAPM_SINGLE("Switch", RT1305_DAC_SET_2,
+		RT1305_DVOL_MUTE_L_EN_SFT, 1, 1);
+
+static const struct snd_kcontrol_new rt1305_sto_dac_r =
+	SOC_DAPM_SINGLE("Switch", RT1305_DAC_SET_2,
+		RT1305_DVOL_MUTE_R_EN_SFT, 1, 1);
+
+static const struct snd_soc_dapm_widget rt1305_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("PLL0", RT1305_POWER_CTRL_1,
+		RT1305_POW_PLL0_EN_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL1", RT1305_POWER_CTRL_1,
+		RT1305_POW_PLL1_EN_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MBIAS", RT1305_POWER_CTRL_1,
+		RT1305_POW_MBIAS_LV_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BG MBIAS", RT1305_POWER_CTRL_1,
+		RT1305_POW_BG_MBIAS_LV_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LDO2", RT1305_POWER_CTRL_1,
+		RT1305_POW_LDO2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BG2", RT1305_POWER_CTRL_1,
+		RT1305_POW_BG2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LDO2 IB2", RT1305_POWER_CTRL_1,
+		RT1305_POW_LDO2_IB2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VREF", RT1305_POWER_CTRL_1,
+		RT1305_POW_VREF_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VREF1", RT1305_POWER_CTRL_1,
+		RT1305_POW_VREF1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VREF2", RT1305_POWER_CTRL_1,
+		RT1305_POW_VREF2_BIT, 0, NULL, 0),
+
+
+	SND_SOC_DAPM_SUPPLY("DISC VREF", RT1305_POWER_CTRL_2,
+		RT1305_POW_DISC_VREF_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("FASTB VREF", RT1305_POWER_CTRL_2,
+		RT1305_POW_FASTB_VREF_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ULTRA FAST VREF", RT1305_POWER_CTRL_2,
+		RT1305_POW_ULTRA_FAST_VREF_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CHOP DAC", RT1305_POWER_CTRL_2,
+		RT1305_POW_CKXEN_DAC_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CKGEN DAC", RT1305_POWER_CTRL_2,
+		RT1305_POW_EN_CKGEN_DAC_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLAMP", RT1305_POWER_CTRL_2,
+		RT1305_POW_CLAMP_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BUFL", RT1305_POWER_CTRL_2,
+		RT1305_POW_BUFL_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BUFR", RT1305_POWER_CTRL_2,
+		RT1305_POW_BUFR_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CKGEN ADC", RT1305_POWER_CTRL_2,
+		RT1305_POW_EN_CKGEN_ADC_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC3 L", RT1305_POWER_CTRL_2,
+		RT1305_POW_ADC3_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC3 R", RT1305_POWER_CTRL_2,
+		RT1305_POW_ADC3_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("TRIOSC", RT1305_POWER_CTRL_2,
+		RT1305_POW_TRIOSC_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AVDD1", RT1305_POWER_CTRL_2,
+		RT1305_POR_AVDD1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AVDD2", RT1305_POWER_CTRL_2,
+		RT1305_POR_AVDD2_BIT, 0, NULL, 0),
+
+
+	SND_SOC_DAPM_SUPPLY("VSENSE R", RT1305_POWER_CTRL_3,
+		RT1305_POW_VSENSE_RCH_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VSENSE L", RT1305_POWER_CTRL_3,
+		RT1305_POW_VSENSE_LCH_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ISENSE R", RT1305_POWER_CTRL_3,
+		RT1305_POW_ISENSE_RCH_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ISENSE L", RT1305_POWER_CTRL_3,
+		RT1305_POW_ISENSE_LCH_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("POR AVDD1", RT1305_POWER_CTRL_3,
+		RT1305_POW_POR_AVDD1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("POR AVDD2", RT1305_POWER_CTRL_3,
+		RT1305_POW_POR_AVDD2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VCM 6172", RT1305_POWER_CTRL_3,
+		RT1305_EN_VCM_6172_BIT, 0, NULL, 0),
+
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("DAC L Power", RT1305_POWER_CTRL_2,
+		RT1305_POW_DAC1_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC R Power", RT1305_POWER_CTRL_2,
+		RT1305_POW_DAC1_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_SWITCH("DAC L", SND_SOC_NOPM, 0, 0, &rt1305_sto_dac_l),
+	SND_SOC_DAPM_SWITCH("DAC R", SND_SOC_NOPM, 0, 0, &rt1305_sto_dac_r),
+
+	/* Output Lines */
+	SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0,
+		rt1305_classd_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_OUTPUT("SPOL"),
+	SND_SOC_DAPM_OUTPUT("SPOR"),
+};
+
+static const struct snd_soc_dapm_route rt1305_dapm_routes[] = {
+
+	{ "DAC", NULL, "AIF1RX" },
+
+	{ "DAC", NULL, "PLL0", rt1305_is_rc_clk_from_pll },
+	{ "DAC", NULL, "PLL1", rt1305_is_sys_clk_from_pll },
+
+	{ "DAC", NULL, "MBIAS" },
+	{ "DAC", NULL, "BG MBIAS" },
+	{ "DAC", NULL, "LDO2" },
+	{ "DAC", NULL, "BG2" },
+	{ "DAC", NULL, "LDO2 IB2" },
+	{ "DAC", NULL, "VREF" },
+	{ "DAC", NULL, "VREF1" },
+	{ "DAC", NULL, "VREF2" },
+
+	{ "DAC", NULL, "DISC VREF" },
+	{ "DAC", NULL, "FASTB VREF" },
+	{ "DAC", NULL, "ULTRA FAST VREF" },
+	{ "DAC", NULL, "CHOP DAC" },
+	{ "DAC", NULL, "CKGEN DAC" },
+	{ "DAC", NULL, "CLAMP" },
+	{ "DAC", NULL, "CKGEN ADC" },
+	{ "DAC", NULL, "TRIOSC" },
+	{ "DAC", NULL, "AVDD1" },
+	{ "DAC", NULL, "AVDD2" },
+
+	{ "DAC", NULL, "POR AVDD1" },
+	{ "DAC", NULL, "POR AVDD2" },
+	{ "DAC", NULL, "VCM 6172" },
+
+	{ "DAC L", "Switch", "DAC" },
+	{ "DAC R", "Switch", "DAC" },
+
+	{ "DAC R", NULL, "VSENSE R" },
+	{ "DAC L", NULL, "VSENSE L" },
+	{ "DAC R", NULL, "ISENSE R" },
+	{ "DAC L", NULL, "ISENSE L" },
+	{ "DAC L", NULL, "ADC3 L" },
+	{ "DAC R", NULL, "ADC3 R" },
+	{ "DAC L", NULL, "BUFL" },
+	{ "DAC R", NULL, "BUFR" },
+	{ "DAC L", NULL, "DAC L Power" },
+	{ "DAC R", NULL, "DAC R Power" },
+
+	{ "CLASS D", NULL, "DAC L" },
+	{ "CLASS D", NULL, "DAC R" },
+
+	{ "SPOL", NULL, "CLASS D" },
+	{ "SPOR", NULL, "CLASS D" },
+};
+
+static int rt1305_get_clk_info(int sclk, int rate)
+{
+	int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
+
+	if (sclk <= 0 || rate <= 0)
+		return -EINVAL;
+
+	rate = rate << 8;
+	for (i = 0; i < ARRAY_SIZE(pd); i++)
+		if (sclk == rate * pd[i])
+			return i;
+
+	return -EINVAL;
+}
+
+static int rt1305_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0, val_clk, mask_clk;
+	int pre_div, bclk_ms, frame_size;
+
+	rt1305->lrck = params_rate(params);
+	pre_div = rt1305_get_clk_info(rt1305->sysclk, rt1305->lrck);
+	if (pre_div < 0) {
+		dev_warn(component->dev, "Force using PLL ");
+		snd_soc_dai_set_pll(dai, 0, RT1305_PLL1_S_BCLK,
+			rt1305->lrck * 64, rt1305->lrck * 256);
+		snd_soc_dai_set_sysclk(dai, RT1305_FS_SYS_PRE_S_PLL1,
+			rt1305->lrck * 256, SND_SOC_CLOCK_IN);
+		pre_div = 0;
+	}
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n",
+			frame_size);
+		return -EINVAL;
+	}
+
+	bclk_ms = frame_size > 32;
+	rt1305->bclk = rt1305->lrck * (32 << bclk_ms);
+
+	dev_dbg(component->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+				bclk_ms, pre_div, dai->id);
+
+	dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+				rt1305->lrck, pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		val_len |= RT1305_I2S_DL_SEL_16B;
+		break;
+	case 20:
+		val_len |= RT1305_I2S_DL_SEL_20B;
+		break;
+	case 24:
+		val_len |= RT1305_I2S_DL_SEL_24B;
+		break;
+	case 8:
+		val_len |= RT1305_I2S_DL_SEL_8B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT1305_AIF1:
+		mask_clk = RT1305_DIV_FS_SYS_MASK;
+		val_clk = pre_div << RT1305_DIV_FS_SYS_SFT;
+		snd_soc_component_update_bits(component, RT1305_I2S_SET_2,
+			RT1305_I2S_DL_SEL_MASK,
+			val_len);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT1305_CLK_2,
+		mask_clk, val_clk);
+
+	return 0;
+}
+
+static int rt1305_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0, reg1_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		reg_val |= RT1305_SEL_I2S_OUT_MODE_M;
+		rt1305->master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT1305_SEL_I2S_OUT_MODE_S;
+		rt1305->master = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg1_val |= RT1305_I2S_BCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg1_val |= RT1305_I2S_DF_SEL_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg1_val |= RT1305_I2S_DF_SEL_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg1_val |= RT1305_I2S_DF_SEL_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT1305_AIF1:
+		snd_soc_component_update_bits(component, RT1305_I2S_SET_1,
+			RT1305_SEL_I2S_OUT_MODE_MASK, reg_val);
+		snd_soc_component_update_bits(component, RT1305_I2S_SET_2,
+			RT1305_I2S_DF_SEL_MASK | RT1305_I2S_BCLK_MASK,
+			reg1_val);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int rt1305_set_component_sysclk(struct snd_soc_component *component,
+		int clk_id, int source, unsigned int freq, int dir)
+{
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	if (freq == rt1305->sysclk && clk_id == rt1305->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT1305_FS_SYS_PRE_S_MCLK:
+		reg_val |= RT1305_SEL_FS_SYS_PRE_MCLK;
+		snd_soc_component_update_bits(component,
+			RT1305_CLOCK_DETECT, RT1305_SEL_CLK_DET_SRC_MASK,
+			RT1305_SEL_CLK_DET_SRC_MCLK);
+		break;
+	case RT1305_FS_SYS_PRE_S_PLL1:
+		reg_val |= RT1305_SEL_FS_SYS_PRE_PLL;
+		break;
+	case RT1305_FS_SYS_PRE_S_RCCLK:
+		reg_val |= RT1305_SEL_FS_SYS_PRE_RCCLK;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, RT1305_CLK_1,
+		RT1305_SEL_FS_SYS_PRE_MASK, reg_val);
+	rt1305->sysclk = freq;
+	rt1305->sysclk_src = clk_id;
+
+	dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n",
+		freq, clk_id);
+
+	return 0;
+}
+
+static int rt1305_set_component_pll(struct snd_soc_component *component,
+		int pll_id, int source, unsigned int freq_in,
+		unsigned int freq_out)
+{
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt1305->pll_src && freq_in == rt1305->pll_in &&
+	    freq_out == rt1305->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt1305->pll_in = 0;
+		rt1305->pll_out = 0;
+		snd_soc_component_update_bits(component, RT1305_CLK_1,
+			RT1305_SEL_FS_SYS_PRE_MASK | RT1305_SEL_PLL_SRC_1_MASK,
+			RT1305_SEL_FS_SYS_PRE_PLL | RT1305_SEL_PLL_SRC_1_BCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT1305_PLL2_S_MCLK:
+		snd_soc_component_update_bits(component, RT1305_CLK_1,
+			RT1305_SEL_PLL_SRC_2_MASK | RT1305_SEL_PLL_SRC_1_MASK |
+			RT1305_DIV_PLL_SRC_2_MASK,
+			RT1305_SEL_PLL_SRC_2_MCLK | RT1305_SEL_PLL_SRC_1_PLL2);
+		snd_soc_component_update_bits(component,
+			RT1305_CLOCK_DETECT, RT1305_SEL_CLK_DET_SRC_MASK,
+			RT1305_SEL_CLK_DET_SRC_MCLK);
+		break;
+	case RT1305_PLL1_S_BCLK:
+		snd_soc_component_update_bits(component,
+			RT1305_CLK_1, RT1305_SEL_PLL_SRC_1_MASK,
+			RT1305_SEL_PLL_SRC_1_BCLK);
+		break;
+	case RT1305_PLL2_S_RCCLK:
+		snd_soc_component_update_bits(component, RT1305_CLK_1,
+			RT1305_SEL_PLL_SRC_2_MASK | RT1305_SEL_PLL_SRC_1_MASK |
+			RT1305_DIV_PLL_SRC_2_MASK,
+			RT1305_SEL_PLL_SRC_2_RCCLK | RT1305_SEL_PLL_SRC_1_PLL2);
+		freq_in = 98304000;
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL Source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_component_write(component, RT1305_PLL1_1,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT1305_PLL_1_M_SFT |
+		pll_code.m_bp << RT1305_PLL_1_M_BYPASS_SFT |
+		pll_code.n_code);
+	snd_soc_component_write(component, RT1305_PLL1_2,
+		pll_code.k_code);
+
+	rt1305->pll_in = freq_in;
+	rt1305->pll_out = freq_out;
+	rt1305->pll_src = source;
+
+	return 0;
+}
+
+static int rt1305_probe(struct snd_soc_component *component)
+{
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+
+	rt1305->component = component;
+
+	/* initial settings */
+	rt1305_reg_init(component);
+
+	return 0;
+}
+
+static void rt1305_remove(struct snd_soc_component *component)
+{
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+
+	rt1305_reset(rt1305->regmap);
+}
+
+#ifdef CONFIG_PM
+static int rt1305_suspend(struct snd_soc_component *component)
+{
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt1305->regmap, true);
+	regcache_mark_dirty(rt1305->regmap);
+
+	return 0;
+}
+
+static int rt1305_resume(struct snd_soc_component *component)
+{
+	struct rt1305_priv *rt1305 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt1305->regmap, false);
+	regcache_sync(rt1305->regmap);
+
+	return 0;
+}
+#else
+#define rt1305_suspend NULL
+#define rt1305_resume NULL
+#endif
+
+#define RT1305_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT1305_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops rt1305_aif_dai_ops = {
+	.hw_params = rt1305_hw_params,
+	.set_fmt = rt1305_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver rt1305_dai[] = {
+	{
+		.name = "rt1305-aif",
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT1305_STEREO_RATES,
+			.formats = RT1305_FORMATS,
+		},
+		.ops = &rt1305_aif_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt1305 = {
+	.probe = rt1305_probe,
+	.remove = rt1305_remove,
+	.suspend = rt1305_suspend,
+	.resume = rt1305_resume,
+	.controls = rt1305_snd_controls,
+	.num_controls = ARRAY_SIZE(rt1305_snd_controls),
+	.dapm_widgets = rt1305_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rt1305_dapm_widgets),
+	.dapm_routes = rt1305_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(rt1305_dapm_routes),
+	.set_sysclk = rt1305_set_component_sysclk,
+	.set_pll = rt1305_set_component_pll,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt1305_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.max_register = RT1305_MAX_REG + 1 + (ARRAY_SIZE(rt1305_ranges) *
+					       RT1305_PR_SPACING),
+	.volatile_reg = rt1305_volatile_register,
+	.readable_reg = rt1305_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt1305_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt1305_reg),
+	.ranges = rt1305_ranges,
+	.num_ranges = ARRAY_SIZE(rt1305_ranges),
+	.use_single_rw = true,
+};
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rt1305_of_match[] = {
+	{ .compatible = "realtek,rt1305", },
+	{ .compatible = "realtek,rt1306", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt1305_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static struct acpi_device_id rt1305_acpi_match[] = {
+	{"10EC1305", 0,},
+	{"10EC1306", 0,},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, rt1305_acpi_match);
+#endif
+
+static const struct i2c_device_id rt1305_i2c_id[] = {
+	{ "rt1305", 0 },
+	{ "rt1306", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt1305_i2c_id);
+
+static void rt1305_calibrate(struct rt1305_priv *rt1305)
+{
+	unsigned int valmsb, vallsb, offsetl, offsetr;
+	unsigned int rh, rl, rhl, r0ohm;
+	u64 r0l, r0r;
+
+	regcache_cache_bypass(rt1305->regmap, true);
+
+	rt1305_reset(rt1305->regmap);
+	regmap_write(rt1305->regmap, RT1305_ADC_SET_3, 0x0219);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xcf, 0x5548);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xc1, 0x0320);
+	regmap_write(rt1305->regmap, RT1305_CLOCK_DETECT, 0x1000);
+	regmap_write(rt1305->regmap, RT1305_CLK_1, 0x0600);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xffd0);
+	regmap_write(rt1305->regmap, RT1305_EFUSE_1, 0x0080);
+	regmap_write(rt1305->regmap, RT1305_EFUSE_1, 0x0880);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_1, 0x0dfe);
+
+	/* Sin Gen */
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x5d, 0x0442);
+
+	regmap_write(rt1305->regmap, RT1305_CAL_EFUSE_CLOCK, 0xb000);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xc3, 0xd4a0);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xcc, 0x00cc);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xc1, 0x0320);
+	regmap_write(rt1305->regmap, RT1305_POWER_STATUS, 0x0000);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_2, 0xffff);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfc20);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x06, 0x00c0);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfca0);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfce0);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfcf0);
+
+	/* EFUSE read */
+	regmap_write(rt1305->regmap, RT1305_EFUSE_1, 0x0080);
+	regmap_write(rt1305->regmap, RT1305_EFUSE_1, 0x0880);
+	regmap_write(rt1305->regmap, RT1305_EFUSE_1, 0x0880);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfce0);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfca0);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfc20);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x06, 0x0000);
+	regmap_write(rt1305->regmap, RT1305_EFUSE_1, 0x0000);
+
+	regmap_read(rt1305->regmap, RT1305_DAC_OFFSET_5, &valmsb);
+	regmap_read(rt1305->regmap, RT1305_DAC_OFFSET_6, &vallsb);
+	offsetl = valmsb << 16 | vallsb;
+	regmap_read(rt1305->regmap, RT1305_DAC_OFFSET_7, &valmsb);
+	regmap_read(rt1305->regmap, RT1305_DAC_OFFSET_8, &vallsb);
+	offsetr = valmsb << 16 | vallsb;
+	pr_info("DC offsetl=0x%x, offsetr=0x%x\n", offsetl, offsetr);
+
+	/* R0 calibration */
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x5d, 0x9542);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0xfcf0);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_2, 0xffff);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_1, 0x1dfe);
+	regmap_write(rt1305->regmap, RT1305_SILENCE_DETECT, 0x0e13);
+	regmap_write(rt1305->regmap, RT1305_CLK_1, 0x0650);
+
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x50, 0x0064);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x51, 0x0770);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x52, 0xc30c);
+	regmap_write(rt1305->regmap, RT1305_SPK_TEMP_PROTECTION_1, 0x8200);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xd4, 0xfb00);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xd4, 0xff80);
+	msleep(2000);
+	regmap_read(rt1305->regmap, RT1305_PR_BASE + 0x55, &rh);
+	regmap_read(rt1305->regmap, RT1305_PR_BASE + 0x56, &rl);
+	rhl = (rh << 16) | rl;
+	r0ohm = (rhl*10) / 33554432;
+
+	pr_debug("Left_rhl = 0x%x rh=0x%x rl=0x%x\n", rhl, rh, rl);
+	pr_info("Left channel %d.%dohm\n", (r0ohm/10), (r0ohm%10));
+
+	r0l = 562949953421312ULL;
+	if (rhl != 0)
+		do_div(r0l, rhl);
+	pr_debug("Left_r0 = 0x%llx\n", r0l);
+
+	regmap_write(rt1305->regmap, RT1305_SPK_TEMP_PROTECTION_1, 0x9200);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xd4, 0xfb00);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xd4, 0xff80);
+	msleep(2000);
+	regmap_read(rt1305->regmap, RT1305_PR_BASE + 0x55, &rh);
+	regmap_read(rt1305->regmap, RT1305_PR_BASE + 0x56, &rl);
+	rhl = (rh << 16) | rl;
+	r0ohm = (rhl*10) / 33554432;
+
+	pr_debug("Right_rhl = 0x%x rh=0x%x rl=0x%x\n", rhl, rh, rl);
+	pr_info("Right channel %d.%dohm\n", (r0ohm/10), (r0ohm%10));
+
+	r0r = 562949953421312ULL;
+	if (rhl != 0)
+		do_div(r0r, rhl);
+	pr_debug("Right_r0 = 0x%llx\n", r0r);
+
+	regmap_write(rt1305->regmap, RT1305_SPK_TEMP_PROTECTION_1, 0xc2ec);
+
+	if ((r0l > R0_UPPER) && (r0l < R0_LOWER) &&
+		(r0r > R0_UPPER) && (r0r < R0_LOWER)) {
+		regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x4e,
+			(r0l >> 16) & 0xffff);
+		regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x4f,
+			r0l & 0xffff);
+		regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xfe,
+			((r0r >> 16) & 0xffff) | 0xf800);
+		regmap_write(rt1305->regmap, RT1305_PR_BASE + 0xfd,
+			r0r & 0xffff);
+	} else {
+		pr_err("R0 calibration failed\n");
+	}
+
+	/* restore some registers */
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_1, 0x0dfe);
+	usleep_range(200000, 400000);
+	regmap_write(rt1305->regmap, RT1305_PR_BASE + 0x5d, 0x0442);
+	regmap_write(rt1305->regmap, RT1305_CLOCK_DETECT, 0x3000);
+	regmap_write(rt1305->regmap, RT1305_CLK_1, 0x0400);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_1, 0x0000);
+	regmap_write(rt1305->regmap, RT1305_CAL_EFUSE_CLOCK, 0x8000);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_2, 0x1020);
+	regmap_write(rt1305->regmap, RT1305_POWER_CTRL_3, 0x0000);
+
+	regcache_cache_bypass(rt1305->regmap, false);
+}
+
+static int rt1305_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt1305_priv *rt1305;
+	int ret;
+	unsigned int val;
+
+	rt1305 = devm_kzalloc(&i2c->dev, sizeof(struct rt1305_priv),
+				GFP_KERNEL);
+	if (rt1305 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt1305);
+
+	rt1305->regmap = devm_regmap_init_i2c(i2c, &rt1305_regmap);
+	if (IS_ERR(rt1305->regmap)) {
+		ret = PTR_ERR(rt1305->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt1305->regmap, RT1305_DEVICE_ID, &val);
+	if (val != RT1305_DEVICE_ID_NUM) {
+		dev_err(&i2c->dev,
+			"Device with ID register %x is not rt1305\n", val);
+		return -ENODEV;
+	}
+
+	rt1305_reset(rt1305->regmap);
+	rt1305_calibrate(rt1305);
+
+	return devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_rt1305,
+			rt1305_dai, ARRAY_SIZE(rt1305_dai));
+}
+
+static void rt1305_i2c_shutdown(struct i2c_client *client)
+{
+	struct rt1305_priv *rt1305 = i2c_get_clientdata(client);
+
+	rt1305_reset(rt1305->regmap);
+}
+
+
+static struct i2c_driver rt1305_i2c_driver = {
+	.driver = {
+		.name = "rt1305",
+#if defined(CONFIG_OF)
+		.of_match_table = rt1305_of_match,
+#endif
+#if defined(CONFIG_ACPI)
+		.acpi_match_table = ACPI_PTR(rt1305_acpi_match)
+#endif
+	},
+	.probe = rt1305_i2c_probe,
+	.shutdown = rt1305_i2c_shutdown,
+	.id_table = rt1305_i2c_id,
+};
+module_i2c_driver(rt1305_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT1305 amplifier driver");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt1305.h b/sound/soc/codecs/rt1305.h
new file mode 100644
index 0000000..bde86f9
--- /dev/null
+++ b/sound/soc/codecs/rt1305.h
@@ -0,0 +1,276 @@
+/*
+ * RT1305.h  --  RT1305 ALSA SoC amplifier component driver
+ *
+ * Copyright 2018 Realtek Semiconductor Corp.
+ * Author: Shuming Fan <shumingf@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _RT1305_H_
+#define _RT1305_H_
+
+#define RT1305_DEVICE_ID_NUM 0x6251
+
+#define RT1305_RESET				0x00
+#define RT1305_CLK_1				0x04
+#define RT1305_CLK_2				0x05
+#define RT1305_CLK_3				0x06
+#define RT1305_DFLL_REG				0x07
+#define RT1305_CAL_EFUSE_CLOCK	0x08
+#define RT1305_PLL0_1				0x0a
+#define RT1305_PLL0_2				0x0b
+#define RT1305_PLL1_1				0x0c
+#define RT1305_PLL1_2				0x0d
+#define RT1305_MIXER_CTRL_1 0x10
+#define RT1305_MIXER_CTRL_2 0x11
+#define RT1305_DAC_SET_1             0x12
+#define RT1305_DAC_SET_2             0x14
+#define RT1305_ADC_SET_1            0x16
+#define RT1305_ADC_SET_2            0x17
+#define RT1305_ADC_SET_3            0x18
+#define RT1305_PATH_SET             0x20
+#define RT1305_SPDIF_IN_SET_1                 0x22
+#define RT1305_SPDIF_IN_SET_2                 0x24
+#define RT1305_SPDIF_IN_SET_3                 0x26
+#define RT1305_SPDIF_OUT_SET_1                 0x28
+#define RT1305_SPDIF_OUT_SET_2                 0x2a
+#define RT1305_SPDIF_OUT_SET_3                 0x2b
+#define RT1305_I2S_SET_1                       0x2d
+#define RT1305_I2S_SET_2                      0x2e
+#define RT1305_PBTL_MONO_MODE_SRC            0x2f
+#define RT1305_MANUALLY_I2C_DEVICE 0x32
+#define RT1305_POWER_STATUS                  0x39
+#define RT1305_POWER_CTRL_1                  0x3a
+#define RT1305_POWER_CTRL_2                  0x3b
+#define RT1305_POWER_CTRL_3                  0x3c
+#define RT1305_POWER_CTRL_4                  0x3d
+#define RT1305_POWER_CTRL_5                  0x3e
+#define RT1305_CLOCK_DETECT                  0x3f
+#define RT1305_BIQUAD_SET_1                  0x40
+#define RT1305_BIQUAD_SET_2                  0x42
+#define RT1305_ADJUSTED_HPF_1             0x46
+#define RT1305_ADJUSTED_HPF_2               0x47
+#define RT1305_EQ_SET_1                  0x4b
+#define RT1305_EQ_SET_2                  0x4c
+#define RT1305_SPK_TEMP_PROTECTION_0 0x4f
+#define RT1305_SPK_TEMP_PROTECTION_1 0x50
+#define RT1305_SPK_TEMP_PROTECTION_2 0x51
+#define RT1305_SPK_TEMP_PROTECTION_3 0x52
+#define RT1305_SPK_DC_DETECT_1                  0x53
+#define RT1305_SPK_DC_DETECT_2                  0x54
+#define RT1305_LOUDNESS 0x58
+#define RT1305_THERMAL_FOLD_BACK_1 0x5e
+#define RT1305_THERMAL_FOLD_BACK_2 0x5f
+#define RT1305_SILENCE_DETECT                  0x60
+#define RT1305_ALC_DRC_1                  0x62
+#define RT1305_ALC_DRC_2                  0x63
+#define RT1305_ALC_DRC_3                  0x64
+#define RT1305_ALC_DRC_4                  0x65
+#define RT1305_PRIV_INDEX			0x6a
+#define RT1305_PRIV_DATA			0x6c
+#define RT1305_SPK_EXCURSION_LIMITER_7 0x76
+#define RT1305_VERSION_ID			0x7a
+#define RT1305_VENDOR_ID			0x7c
+#define RT1305_DEVICE_ID			0x7e
+#define RT1305_EFUSE_1                  0x80
+#define RT1305_EFUSE_2                  0x81
+#define RT1305_EFUSE_3                  0x82
+#define RT1305_DC_CALIB_1                  0x90
+#define RT1305_DC_CALIB_2                  0x91
+#define RT1305_DC_CALIB_3                  0x92
+#define RT1305_DAC_OFFSET_1            0x93
+#define RT1305_DAC_OFFSET_2            0x94
+#define RT1305_DAC_OFFSET_3            0x95
+#define RT1305_DAC_OFFSET_4            0x96
+#define RT1305_DAC_OFFSET_5            0x97
+#define RT1305_DAC_OFFSET_6            0x98
+#define RT1305_DAC_OFFSET_7            0x99
+#define RT1305_DAC_OFFSET_8            0x9a
+#define RT1305_DAC_OFFSET_9            0x9b
+#define RT1305_DAC_OFFSET_10            0x9c
+#define RT1305_DAC_OFFSET_11            0x9d
+#define RT1305_DAC_OFFSET_12            0x9e
+#define RT1305_DAC_OFFSET_13            0x9f
+#define RT1305_DAC_OFFSET_14            0xa0
+#define RT1305_TRIM_1                  0xb0
+#define RT1305_TRIM_2                  0xb1
+#define RT1305_TUNE_INTERNAL_OSC             0xb2
+#define RT1305_BIQUAD1_H0_L_28_16 0xc0
+#define RT1305_BIQUAD3_A2_R_15_0 0xfb
+#define RT1305_MAX_REG	                 0xff
+
+/* CLOCK-1 (0x04) */
+#define RT1305_SEL_PLL_SRC_2_MASK			(0x1 << 15)
+#define RT1305_SEL_PLL_SRC_2_SFT			15
+#define RT1305_SEL_PLL_SRC_2_MCLK			(0x0 << 15)
+#define RT1305_SEL_PLL_SRC_2_RCCLK			(0x1 << 15)
+#define RT1305_DIV_PLL_SRC_2_MASK			(0x3 << 13)
+#define RT1305_DIV_PLL_SRC_2_SFT			13
+#define RT1305_SEL_PLL_SRC_1_MASK			(0x3 << 10)
+#define RT1305_SEL_PLL_SRC_1_SFT			10
+#define RT1305_SEL_PLL_SRC_1_PLL2			(0x0 << 10)
+#define RT1305_SEL_PLL_SRC_1_BCLK			(0x1 << 10)
+#define RT1305_SEL_PLL_SRC_1_DFLL			(0x2 << 10)
+#define RT1305_SEL_FS_SYS_PRE_MASK			(0x3 << 8)
+#define RT1305_SEL_FS_SYS_PRE_SFT			8
+#define RT1305_SEL_FS_SYS_PRE_MCLK			(0x0 << 8)
+#define RT1305_SEL_FS_SYS_PRE_PLL			(0x1 << 8)
+#define RT1305_SEL_FS_SYS_PRE_RCCLK			(0x2 << 8)
+#define RT1305_DIV_FS_SYS_MASK				(0x7 << 4)
+#define RT1305_DIV_FS_SYS_SFT				4
+
+/* PLL1M/N/K Code-1 (0x0c) */
+#define RT1305_PLL_1_M_SFT		12
+#define RT1305_PLL_1_M_BYPASS_MASK			(0x1 << 11)
+#define RT1305_PLL_1_M_BYPASS_SFT		11
+#define RT1305_PLL_1_M_BYPASS			(0x1 << 11)
+#define RT1305_PLL_1_N_MASK			(0x1ff << 0)
+
+/* DAC Setting (0x14) */
+#define RT1305_DVOL_MUTE_L_EN_SFT		15
+#define RT1305_DVOL_MUTE_R_EN_SFT		14
+
+/* I2S Setting-1 (0x2d) */
+#define RT1305_SEL_I2S_OUT_MODE_MASK		(0x1 << 15)
+#define RT1305_SEL_I2S_OUT_MODE_SFT			15
+#define RT1305_SEL_I2S_OUT_MODE_S			(0x0 << 15)
+#define RT1305_SEL_I2S_OUT_MODE_M			(0x1 << 15)
+
+/* I2S Setting-2 (0x2e) */
+#define RT1305_I2S_DF_SEL_MASK			(0x3 << 12)
+#define RT1305_I2S_DF_SEL_SFT			12
+#define RT1305_I2S_DF_SEL_I2S			(0x0 << 12)
+#define RT1305_I2S_DF_SEL_LEFT			(0x1 << 12)
+#define RT1305_I2S_DF_SEL_PCM_A			(0x2 << 12)
+#define RT1305_I2S_DF_SEL_PCM_B			(0x3 << 12)
+#define RT1305_I2S_DL_SEL_MASK			(0x3 << 10)
+#define RT1305_I2S_DL_SEL_SFT			10
+#define RT1305_I2S_DL_SEL_16B			(0x0 << 10)
+#define RT1305_I2S_DL_SEL_20B			(0x1 << 10)
+#define RT1305_I2S_DL_SEL_24B			(0x2 << 10)
+#define RT1305_I2S_DL_SEL_8B			(0x3 << 10)
+#define RT1305_I2S_BCLK_MASK		(0x1 << 9)
+#define RT1305_I2S_BCLK_SFT			9
+#define RT1305_I2S_BCLK_NORMAL		(0x0 << 9)
+#define RT1305_I2S_BCLK_INV			(0x1 << 9)
+
+/* Power Control-1 (0x3a) */
+#define RT1305_POW_PDB_JD_MASK				(0x1 << 12)
+#define RT1305_POW_PDB_JD				(0x1 << 12)
+#define RT1305_POW_PDB_JD_BIT			12
+#define RT1305_POW_PLL0_EN				(0x1 << 11)
+#define RT1305_POW_PLL0_EN_BIT			11
+#define RT1305_POW_PLL1_EN				(0x1 << 10)
+#define RT1305_POW_PLL1_EN_BIT			10
+#define RT1305_POW_PDB_JD_POLARITY				(0x1 << 9)
+#define RT1305_POW_PDB_JD_POLARITY_BIT			9
+#define RT1305_POW_MBIAS_LV				(0x1 << 8)
+#define RT1305_POW_MBIAS_LV_BIT			8
+#define RT1305_POW_BG_MBIAS_LV				(0x1 << 7)
+#define RT1305_POW_BG_MBIAS_LV_BIT			7
+#define RT1305_POW_LDO2				(0x1 << 6)
+#define RT1305_POW_LDO2_BIT			6
+#define RT1305_POW_BG2				(0x1 << 5)
+#define RT1305_POW_BG2_BIT			5
+#define RT1305_POW_LDO2_IB2				(0x1 << 4)
+#define RT1305_POW_LDO2_IB2_BIT			4
+#define RT1305_POW_VREF				(0x1 << 3)
+#define RT1305_POW_VREF_BIT			3
+#define RT1305_POW_VREF1				(0x1 << 2)
+#define RT1305_POW_VREF1_BIT			2
+#define RT1305_POW_VREF2				(0x1 << 1)
+#define RT1305_POW_VREF2_BIT			1
+
+/* Power Control-2 (0x3b) */
+#define RT1305_POW_DISC_VREF           (1 << 15)
+#define RT1305_POW_DISC_VREF_BIT       15
+#define RT1305_POW_FASTB_VREF          (1 << 14)
+#define RT1305_POW_FASTB_VREF_BIT          14
+#define RT1305_POW_ULTRA_FAST_VREF     (1 << 13)
+#define RT1305_POW_ULTRA_FAST_VREF_BIT     13
+#define RT1305_POW_CKXEN_DAC           (1 << 12)
+#define RT1305_POW_CKXEN_DAC_BIT           12
+#define RT1305_POW_EN_CKGEN_DAC        (1 << 11)
+#define RT1305_POW_EN_CKGEN_DAC_BIT        11
+#define RT1305_POW_DAC1_L          (1 << 10)
+#define RT1305_POW_DAC1_L_BIT          10
+#define RT1305_POW_DAC1_R          (1 << 9)
+#define RT1305_POW_DAC1_R_BIT          9
+#define RT1305_POW_CLAMP           (1 << 8)
+#define RT1305_POW_CLAMP_BIT           8
+#define RT1305_POW_BUFL            (1 << 7)
+#define RT1305_POW_BUFL_BIT            7
+#define RT1305_POW_BUFR              (1 << 6)
+#define RT1305_POW_BUFR_BIT              6
+#define RT1305_POW_EN_CKGEN_ADC       (1 << 5)
+#define RT1305_POW_EN_CKGEN_ADC_BIT       5
+#define RT1305_POW_ADC3_L             (1 << 4)
+#define RT1305_POW_ADC3_L_BIT             4
+#define RT1305_POW_ADC3_R             (1 << 3)
+#define RT1305_POW_ADC3_R_BIT             3
+#define RT1305_POW_TRIOSC               (1 << 2)
+#define RT1305_POW_TRIOSC_BIT               2
+#define RT1305_POR_AVDD1              (1 << 1)
+#define RT1305_POR_AVDD1_BIT              1
+#define RT1305_POR_AVDD2           (1 << 0)
+#define RT1305_POR_AVDD2_BIT           0
+
+/* Power Control-3 (0x3c) */
+#define RT1305_POW_VSENSE_RCH           (1 << 15)
+#define RT1305_POW_VSENSE_RCH_BIT        15
+#define RT1305_POW_VSENSE_LCH           (1 << 14)
+#define RT1305_POW_VSENSE_LCH_BIT           14
+#define RT1305_POW_ISENSE_RCH            (1 << 13)
+#define RT1305_POW_ISENSE_RCH_BIT          13
+#define RT1305_POW_ISENSE_LCH            (1 << 12)
+#define RT1305_POW_ISENSE_LCH_BIT            12
+#define RT1305_POW_POR_AVDD1            (1 << 11)
+#define RT1305_POW_POR_AVDD1_BIT          11
+#define RT1305_POW_POR_AVDD2            (1 << 10)
+#define RT1305_POW_POR_AVDD2_BIT            10
+#define RT1305_EN_K_HV            (1 << 9)
+#define RT1305_EN_K_HV_BIT           9
+#define RT1305_EN_PRE_K_HV            (1 << 8)
+#define RT1305_EN_PRE_K_HV_BIT           8
+#define RT1305_EN_EFUSE_1P8V            (1 << 7)
+#define RT1305_EN_EFUSE_1P8V_BIT           7
+#define RT1305_EN_EFUSE_5V             (1 << 6)
+#define RT1305_EN_EFUSE_5V_BIT           6
+#define RT1305_EN_VCM_6172           (1 << 5)
+#define RT1305_EN_VCM_6172_BIT          5
+#define RT1305_POR_EFUSE           (1 << 4)
+#define RT1305_POR_EFUSE_BIT             4
+
+/* Clock Detect (0x3f) */
+#define RT1305_SEL_CLK_DET_SRC_MASK			(0x1 << 12)
+#define RT1305_SEL_CLK_DET_SRC_SFT			12
+#define RT1305_SEL_CLK_DET_SRC_MCLK			(0x0 << 12)
+#define RT1305_SEL_CLK_DET_SRC_BCLK			(0x1 << 12)
+
+
+/* System Clock Source */
+enum {
+	RT1305_FS_SYS_PRE_S_MCLK,
+	RT1305_FS_SYS_PRE_S_PLL1,
+	RT1305_FS_SYS_PRE_S_RCCLK,	/* 98.304M Hz */
+};
+
+/* PLL Source 1/2 */
+enum {
+	RT1305_PLL1_S_BCLK,
+	RT1305_PLL2_S_MCLK,
+	RT1305_PLL2_S_RCCLK,	/* 98.304M Hz */
+};
+
+enum {
+	RT1305_AIF1,
+	RT1305_AIFS
+};
+
+#define R0_UPPER 0x2E8BA2 //5.5 ohm
+#define R0_LOWER 0x666666 //2.5 ohm
+
+#endif		/* end of _RT1305_H_ */
diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c
new file mode 100644
index 0000000..d88e673
--- /dev/null
+++ b/sound/soc/codecs/rt274.c
@@ -0,0 +1,1227 @@
+/*
+ * rt274.c  --  RT274 ALSA SoC audio codec driver
+ *
+ * Copyright 2017 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+#include <linux/workqueue.h>
+
+#include "rl6347a.h"
+#include "rt274.h"
+
+#define RT274_VENDOR_ID 0x10ec0274
+
+struct rt274_priv {
+	struct reg_default *index_cache;
+	int index_cache_size;
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct i2c_client *i2c;
+	struct snd_soc_jack *jack;
+	struct delayed_work jack_detect_work;
+	int sys_clk;
+	int clk_id;
+	int fs;
+	bool master;
+};
+
+static const struct reg_default rt274_index_def[] = {
+	{ 0x00, 0x1004 },
+	{ 0x01, 0xaaaa },
+	{ 0x02, 0x88aa },
+	{ 0x03, 0x0002 },
+	{ 0x04, 0xaa09 },
+	{ 0x05, 0x0700 },
+	{ 0x06, 0x6110 },
+	{ 0x07, 0x0200 },
+	{ 0x08, 0xa807 },
+	{ 0x09, 0x0021 },
+	{ 0x0a, 0x7770 },
+	{ 0x0b, 0x7770 },
+	{ 0x0c, 0x002b },
+	{ 0x0d, 0x2420 },
+	{ 0x0e, 0x65c0 },
+	{ 0x0f, 0x7770 },
+	{ 0x10, 0x0420 },
+	{ 0x11, 0x7418 },
+	{ 0x12, 0x6bd0 },
+	{ 0x13, 0x645f },
+	{ 0x14, 0x0400 },
+	{ 0x15, 0x8ccc },
+	{ 0x16, 0x4c50 },
+	{ 0x17, 0xff00 },
+	{ 0x18, 0x0003 },
+	{ 0x19, 0x2c11 },
+	{ 0x1a, 0x830b },
+	{ 0x1b, 0x4e4b },
+	{ 0x1c, 0x0000 },
+	{ 0x1d, 0x0000 },
+	{ 0x1e, 0x0000 },
+	{ 0x1f, 0x0000 },
+	{ 0x20, 0x51ff },
+	{ 0x21, 0x8000 },
+	{ 0x22, 0x8f00 },
+	{ 0x23, 0x88f4 },
+	{ 0x24, 0x0000 },
+	{ 0x25, 0x0000 },
+	{ 0x26, 0x0000 },
+	{ 0x27, 0x0000 },
+	{ 0x28, 0x0000 },
+	{ 0x29, 0x3000 },
+	{ 0x2a, 0x0000 },
+	{ 0x2b, 0x0000 },
+	{ 0x2c, 0x0f00 },
+	{ 0x2d, 0x100f },
+	{ 0x2e, 0x2902 },
+	{ 0x2f, 0xe280 },
+	{ 0x30, 0x1000 },
+	{ 0x31, 0x8400 },
+	{ 0x32, 0x5aaa },
+	{ 0x33, 0x8420 },
+	{ 0x34, 0xa20c },
+	{ 0x35, 0x096a },
+	{ 0x36, 0x5757 },
+	{ 0x37, 0xfe05 },
+	{ 0x38, 0x4901 },
+	{ 0x39, 0x110a },
+	{ 0x3a, 0x0010 },
+	{ 0x3b, 0x60d9 },
+	{ 0x3c, 0xf214 },
+	{ 0x3d, 0xc2ba },
+	{ 0x3e, 0xa928 },
+	{ 0x3f, 0x0000 },
+	{ 0x40, 0x9800 },
+	{ 0x41, 0x0000 },
+	{ 0x42, 0x2000 },
+	{ 0x43, 0x3d90 },
+	{ 0x44, 0x4900 },
+	{ 0x45, 0x5289 },
+	{ 0x46, 0x0004 },
+	{ 0x47, 0xa47a },
+	{ 0x48, 0xd049 },
+	{ 0x49, 0x0049 },
+	{ 0x4a, 0xa83b },
+	{ 0x4b, 0x0777 },
+	{ 0x4c, 0x065c },
+	{ 0x4d, 0x7fff },
+	{ 0x4e, 0x7fff },
+	{ 0x4f, 0x0000 },
+	{ 0x50, 0x0000 },
+	{ 0x51, 0x0000 },
+	{ 0x52, 0xbf5f },
+	{ 0x53, 0x3320 },
+	{ 0x54, 0xcc00 },
+	{ 0x55, 0x0000 },
+	{ 0x56, 0x3f00 },
+	{ 0x57, 0x0000 },
+	{ 0x58, 0x0000 },
+	{ 0x59, 0x0000 },
+	{ 0x5a, 0x1300 },
+	{ 0x5b, 0x005f },
+	{ 0x5c, 0x0000 },
+	{ 0x5d, 0x1001 },
+	{ 0x5e, 0x1000 },
+	{ 0x5f, 0x0000 },
+	{ 0x60, 0x5554 },
+	{ 0x61, 0xffc0 },
+	{ 0x62, 0xa000 },
+	{ 0x63, 0xd010 },
+	{ 0x64, 0x0000 },
+	{ 0x65, 0x3fb1 },
+	{ 0x66, 0x1881 },
+	{ 0x67, 0xc810 },
+	{ 0x68, 0x2000 },
+	{ 0x69, 0xfff0 },
+	{ 0x6a, 0x0300 },
+	{ 0x6b, 0x5060 },
+	{ 0x6c, 0x0000 },
+	{ 0x6d, 0x0000 },
+	{ 0x6e, 0x0c25 },
+	{ 0x6f, 0x0c0b },
+	{ 0x70, 0x8000 },
+	{ 0x71, 0x4008 },
+	{ 0x72, 0x0000 },
+	{ 0x73, 0x0800 },
+	{ 0x74, 0xa28f },
+	{ 0x75, 0xa050 },
+	{ 0x76, 0x7fe8 },
+	{ 0x77, 0xdb8c },
+	{ 0x78, 0x0000 },
+	{ 0x79, 0x0000 },
+	{ 0x7a, 0x2a96 },
+	{ 0x7b, 0x800f },
+	{ 0x7c, 0x0200 },
+	{ 0x7d, 0x1600 },
+	{ 0x7e, 0x0000 },
+	{ 0x7f, 0x0000 },
+};
+#define INDEX_CACHE_SIZE ARRAY_SIZE(rt274_index_def)
+
+static const struct reg_default rt274_reg[] = {
+	{ 0x00170500, 0x00000400 },
+	{ 0x00220000, 0x00000031 },
+	{ 0x00239000, 0x00000057 },
+	{ 0x0023a000, 0x00000057 },
+	{ 0x00270500, 0x00000400 },
+	{ 0x00370500, 0x00000400 },
+	{ 0x00870500, 0x00000400 },
+	{ 0x00920000, 0x00000031 },
+	{ 0x00935000, 0x00000097 },
+	{ 0x00936000, 0x00000097 },
+	{ 0x00970500, 0x00000400 },
+	{ 0x00b37000, 0x00000400 },
+	{ 0x00b37200, 0x00000400 },
+	{ 0x00b37300, 0x00000400 },
+	{ 0x00c37000, 0x00000400 },
+	{ 0x00c37100, 0x00000400 },
+	{ 0x01270500, 0x00000400 },
+	{ 0x01370500, 0x00000400 },
+	{ 0x01371f00, 0x411111f0 },
+	{ 0x01937000, 0x00000000 },
+	{ 0x01970500, 0x00000400 },
+	{ 0x02050000, 0x0000001b },
+	{ 0x02139000, 0x00000080 },
+	{ 0x0213a000, 0x00000080 },
+	{ 0x02170100, 0x00000001 },
+	{ 0x02170500, 0x00000400 },
+	{ 0x02170700, 0x00000000 },
+	{ 0x02270100, 0x00000000 },
+	{ 0x02370100, 0x00000000 },
+	{ 0x01970700, 0x00000020 },
+	{ 0x00830000, 0x00000097 },
+	{ 0x00930000, 0x00000097 },
+	{ 0x01270700, 0x00000000 },
+};
+
+static bool rt274_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0 ... 0xff:
+	case RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID):
+	case RT274_GET_HP_SENSE:
+	case RT274_GET_MIC_SENSE:
+	case RT274_PROC_COEF:
+	case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT0, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT1, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN1, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN1, 0):
+	case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN2, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC1, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC2, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE1, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE2, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_INLINE_CMD, 0):
+		return true;
+	default:
+		return false;
+	}
+
+
+}
+
+static bool rt274_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0 ... 0xff:
+	case RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID):
+	case RT274_GET_HP_SENSE:
+	case RT274_GET_MIC_SENSE:
+	case RT274_SET_AUDIO_POWER:
+	case RT274_SET_HPO_POWER:
+	case RT274_SET_DMIC1_POWER:
+	case RT274_LOUT_MUX:
+	case RT274_HPO_MUX:
+	case RT274_ADC0_MUX:
+	case RT274_ADC1_MUX:
+	case RT274_SET_MIC:
+	case RT274_SET_PIN_HPO:
+	case RT274_SET_PIN_LOUT3:
+	case RT274_SET_PIN_DMIC1:
+	case RT274_SET_AMP_GAIN_HPO:
+	case RT274_SET_DMIC2_DEFAULT:
+	case RT274_DAC0L_GAIN:
+	case RT274_DAC0R_GAIN:
+	case RT274_DAC1L_GAIN:
+	case RT274_DAC1R_GAIN:
+	case RT274_ADCL_GAIN:
+	case RT274_ADCR_GAIN:
+	case RT274_MIC_GAIN:
+	case RT274_HPOL_GAIN:
+	case RT274_HPOR_GAIN:
+	case RT274_LOUTL_GAIN:
+	case RT274_LOUTR_GAIN:
+	case RT274_DAC_FORMAT:
+	case RT274_ADC_FORMAT:
+	case RT274_COEF_INDEX:
+	case RT274_PROC_COEF:
+	case RT274_SET_AMP_GAIN_ADC_IN1:
+	case RT274_SET_AMP_GAIN_ADC_IN2:
+	case RT274_SET_POWER(RT274_DAC_OUT0):
+	case RT274_SET_POWER(RT274_DAC_OUT1):
+	case RT274_SET_POWER(RT274_ADC_IN1):
+	case RT274_SET_POWER(RT274_ADC_IN2):
+	case RT274_SET_POWER(RT274_DMIC2):
+	case RT274_SET_POWER(RT274_MIC):
+	case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT0, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_DAC_OUT1, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN1, 0):
+	case VERB_CMD(AC_VERB_GET_STREAM_FORMAT, RT274_ADC_IN2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_ADC_IN2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_DMIC2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE1, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_LINE2, 0):
+	case VERB_CMD(AC_VERB_GET_AMP_GAIN_MUTE, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN1, 0):
+	case VERB_CMD(AC_VERB_GET_CONNECT_SEL, RT274_MIXER_IN2, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC1, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_DMIC2, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE1, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_LINE2, 0):
+	case VERB_CMD(AC_VERB_GET_PIN_WIDGET_CONTROL, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_HP_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_MIC, 0):
+	case VERB_CMD(AC_VERB_GET_UNSOLICITED_RESPONSE, RT274_INLINE_CMD, 0):
+		return true;
+	default:
+		return false;
+	}
+}
+
+#ifdef CONFIG_PM
+static void rt274_index_sync(struct snd_soc_component *component)
+{
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
+	int i;
+
+	for (i = 0; i < INDEX_CACHE_SIZE; i++) {
+		snd_soc_component_write(component, rt274->index_cache[i].reg,
+				  rt274->index_cache[i].def);
+	}
+}
+#endif
+
+static int rt274_jack_detect(struct rt274_priv *rt274, bool *hp, bool *mic)
+{
+	unsigned int buf;
+
+	*hp = false;
+	*mic = false;
+
+	if (!rt274->component)
+		return -EINVAL;
+
+	regmap_read(rt274->regmap, RT274_GET_HP_SENSE, &buf);
+	*hp = buf & 0x80000000;
+	regmap_read(rt274->regmap, RT274_GET_MIC_SENSE, &buf);
+	*mic = buf & 0x80000000;
+
+	pr_debug("*hp = %d *mic = %d\n", *hp, *mic);
+
+	return 0;
+}
+
+static void rt274_jack_detect_work(struct work_struct *work)
+{
+	struct rt274_priv *rt274 =
+		container_of(work, struct rt274_priv, jack_detect_work.work);
+	int status = 0;
+	bool hp = false;
+	bool mic = false;
+
+	if (rt274_jack_detect(rt274, &hp, &mic) < 0)
+		return;
+
+	if (hp == true)
+		status |= SND_JACK_HEADPHONE;
+
+	if (mic == true)
+		status |= SND_JACK_MICROPHONE;
+
+	snd_soc_jack_report(rt274->jack, status,
+		SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+}
+
+static irqreturn_t rt274_irq(int irq, void *data);
+
+static int rt274_mic_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *jack,  void *data)
+{
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
+
+	if (jack == NULL) {
+		/* Disable jack detection */
+		regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
+					RT274_IRQ_EN, RT274_IRQ_DIS);
+
+		return 0;
+	}
+	rt274->jack = jack;
+
+	regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
+				RT274_IRQ_EN, RT274_IRQ_EN);
+
+	/* Send an initial report */
+	rt274_irq(0, rt274);
+
+	return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
+
+static const struct snd_kcontrol_new rt274_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT274_DAC0L_GAIN,
+			 RT274_DAC0R_GAIN, 0, 0x7f, 0, out_vol_tlv),
+	SOC_DOUBLE_R_TLV("DAC1 Playback Volume", RT274_DAC1L_GAIN,
+			 RT274_DAC1R_GAIN, 0, 0x7f, 0, out_vol_tlv),
+	SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT274_ADCL_GAIN,
+			    RT274_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv),
+	SOC_DOUBLE_R("ADC0 Capture Switch", RT274_ADCL_GAIN,
+			    RT274_ADCR_GAIN, RT274_MUTE_SFT, 1, 1),
+	SOC_SINGLE_TLV("AMIC Volume", RT274_MIC_GAIN,
+			    0, 0x3, 0, mic_vol_tlv),
+};
+
+static const struct snd_kcontrol_new hpol_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_HPOL_GAIN,
+			RT274_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpor_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_HPOR_GAIN,
+			RT274_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new loutl_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_LOUTL_GAIN,
+			RT274_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new loutr_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT274_LOUTR_GAIN,
+			RT274_MUTE_SFT, 1, 1);
+
+/* ADC0 source */
+static const char * const rt274_adc_src[] = {
+	"Mic", "Line1", "Line2", "Dmic"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt274_adc0_enum, RT274_ADC0_MUX, RT274_ADC_SEL_SFT,
+	rt274_adc_src);
+
+static const struct snd_kcontrol_new rt274_adc0_mux =
+	SOC_DAPM_ENUM("ADC 0 source", rt274_adc0_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt274_adc1_enum, RT274_ADC1_MUX, RT274_ADC_SEL_SFT,
+	rt274_adc_src);
+
+static const struct snd_kcontrol_new rt274_adc1_mux =
+	SOC_DAPM_ENUM("ADC 1 source", rt274_adc1_enum);
+
+static const char * const rt274_dac_src[] = {
+	"DAC OUT0", "DAC OUT1"
+};
+/* HP-OUT source */
+static SOC_ENUM_SINGLE_DECL(rt274_hpo_enum, RT274_HPO_MUX,
+				0, rt274_dac_src);
+
+static const struct snd_kcontrol_new rt274_hpo_mux =
+SOC_DAPM_ENUM("HPO source", rt274_hpo_enum);
+
+/* Line out source */
+static SOC_ENUM_SINGLE_DECL(rt274_lout_enum, RT274_LOUT_MUX,
+				0, rt274_dac_src);
+
+static const struct snd_kcontrol_new rt274_lout_mux =
+SOC_DAPM_ENUM("LOUT source", rt274_lout_enum);
+
+static const struct snd_soc_dapm_widget rt274_dapm_widgets[] = {
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC1 Pin"),
+	SND_SOC_DAPM_INPUT("DMIC2 Pin"),
+	SND_SOC_DAPM_INPUT("MIC"),
+	SND_SOC_DAPM_INPUT("LINE1"),
+	SND_SOC_DAPM_INPUT("LINE2"),
+
+	/* DMIC */
+	SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC 0", NULL, RT274_SET_STREAMID_ADC1, 4, 0),
+	SND_SOC_DAPM_ADC("ADC 1", NULL, RT274_SET_STREAMID_ADC2, 4, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("ADC 0 Mux", SND_SOC_NOPM, 0, 0,
+		&rt274_adc0_mux),
+	SND_SOC_DAPM_MUX("ADC 1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt274_adc1_mux),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RXL", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF1RXR", "AIF1 Playback", 1, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TXL", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TXR", "AIF1 Capture", 1, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2RXL", "AIF1 Playback", 2, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2RXR", "AIF1 Playback", 3, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2TXL", "AIF1 Capture", 2, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2TXR", "AIF1 Capture", 3, SND_SOC_NOPM, 0, 0),
+
+	/* Output Side */
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC 0", NULL, RT274_SET_STREAMID_DAC0, 4, 0),
+	SND_SOC_DAPM_DAC("DAC 1", NULL, RT274_SET_STREAMID_DAC1, 4, 0),
+
+	/* Output Mux */
+	SND_SOC_DAPM_MUX("HPO Mux", SND_SOC_NOPM, 0, 0, &rt274_hpo_mux),
+	SND_SOC_DAPM_MUX("LOUT Mux", SND_SOC_NOPM, 0, 0, &rt274_lout_mux),
+
+	SND_SOC_DAPM_SUPPLY("HP Power", RT274_SET_PIN_HPO,
+		RT274_SET_PIN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LOUT Power", RT274_SET_PIN_LOUT3,
+		RT274_SET_PIN_SFT, 0, NULL, 0),
+
+	/* Output Mixer */
+	SND_SOC_DAPM_PGA("DAC OUT0", SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+	SND_SOC_DAPM_PGA("DAC OUT1", SND_SOC_NOPM, 0, 0,
+			NULL, 0),
+
+	/* Output Pga */
+	SND_SOC_DAPM_SWITCH("LOUT L", SND_SOC_NOPM, 0, 0,
+		&loutl_enable_control),
+	SND_SOC_DAPM_SWITCH("LOUT R", SND_SOC_NOPM, 0, 0,
+		&loutr_enable_control),
+	SND_SOC_DAPM_SWITCH("HPO L", SND_SOC_NOPM, 0, 0,
+		&hpol_enable_control),
+	SND_SOC_DAPM_SWITCH("HPO R", SND_SOC_NOPM, 0, 0,
+		&hpor_enable_control),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPO Pin"),
+	SND_SOC_DAPM_OUTPUT("SPDIF"),
+	SND_SOC_DAPM_OUTPUT("LINE3"),
+};
+
+static const struct snd_soc_dapm_route rt274_dapm_routes[] = {
+	{"DMIC1", NULL, "DMIC1 Pin"},
+	{"DMIC2", NULL, "DMIC2 Pin"},
+
+	{"ADC 0 Mux", "Mic", "MIC"},
+	{"ADC 0 Mux", "Dmic", "DMIC1"},
+	{"ADC 0 Mux", "Line1", "LINE1"},
+	{"ADC 0 Mux", "Line2", "LINE2"},
+	{"ADC 1 Mux", "Mic", "MIC"},
+	{"ADC 1 Mux", "Dmic", "DMIC2"},
+	{"ADC 1 Mux", "Line1", "LINE1"},
+	{"ADC 1 Mux", "Line2", "LINE2"},
+
+	{"ADC 0", NULL, "ADC 0 Mux"},
+	{"ADC 1", NULL, "ADC 1 Mux"},
+
+	{"AIF1TXL", NULL, "ADC 0"},
+	{"AIF1TXR", NULL, "ADC 0"},
+	{"AIF2TXL", NULL, "ADC 1"},
+	{"AIF2TXR", NULL, "ADC 1"},
+
+	{"DAC 0", NULL, "AIF1RXL"},
+	{"DAC 0", NULL, "AIF1RXR"},
+	{"DAC 1", NULL, "AIF2RXL"},
+	{"DAC 1", NULL, "AIF2RXR"},
+
+	{"DAC OUT0", NULL, "DAC 0"},
+
+	{"DAC OUT1", NULL, "DAC 1"},
+
+	{"LOUT Mux", "DAC OUT0", "DAC OUT0"},
+	{"LOUT Mux", "DAC OUT1", "DAC OUT1"},
+
+	{"LOUT L", "Switch", "LOUT Mux"},
+	{"LOUT R", "Switch", "LOUT Mux"},
+	{"LOUT L", NULL, "LOUT Power"},
+	{"LOUT R", NULL, "LOUT Power"},
+
+	{"LINE3", NULL, "LOUT L"},
+	{"LINE3", NULL, "LOUT R"},
+
+	{"HPO Mux", "DAC OUT0", "DAC OUT0"},
+	{"HPO Mux", "DAC OUT1", "DAC OUT1"},
+
+	{"HPO L", "Switch", "HPO Mux"},
+	{"HPO R", "Switch", "HPO Mux"},
+	{"HPO L", NULL, "HP Power"},
+	{"HPO R", NULL, "HP Power"},
+
+	{"HPO Pin", NULL, "HPO L"},
+	{"HPO Pin", NULL, "HPO R"},
+};
+
+static int rt274_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
+	unsigned int val = 0;
+	int d_len_code = 0, c_len_code = 0;
+
+	switch (params_rate(params)) {
+	/* bit 14 0:48K 1:44.1K */
+	case 44100:
+	case 48000:
+		break;
+	default:
+		dev_err(component->dev, "Unsupported sample rate %d\n",
+					params_rate(params));
+		return -EINVAL;
+	}
+	switch (rt274->sys_clk) {
+	case 12288000:
+	case 24576000:
+		if (params_rate(params) != 48000) {
+			dev_err(component->dev, "Sys_clk is not matched (%d %d)\n",
+					params_rate(params), rt274->sys_clk);
+			return -EINVAL;
+		}
+		break;
+	case 11289600:
+	case 22579200:
+		if (params_rate(params) != 44100) {
+			dev_err(component->dev, "Sys_clk is not matched (%d %d)\n",
+					params_rate(params), rt274->sys_clk);
+			return -EINVAL;
+		}
+		break;
+	}
+
+	if (params_channels(params) <= 16) {
+		/* bit 3:0 Number of Channel */
+		val |= (params_channels(params) - 1);
+	} else {
+		dev_err(component->dev, "Unsupported channels %d\n",
+					params_channels(params));
+		return -EINVAL;
+	}
+
+	switch (params_width(params)) {
+	/* bit 6:4 Bits per Sample */
+	case 16:
+		d_len_code = 0;
+		c_len_code = 0;
+		val |= (0x1 << 4);
+		break;
+	case 32:
+		d_len_code = 2;
+		c_len_code = 3;
+		val |= (0x4 << 4);
+		break;
+	case 20:
+		d_len_code = 1;
+		c_len_code = 1;
+		val |= (0x2 << 4);
+		break;
+	case 24:
+		d_len_code = 2;
+		c_len_code = 2;
+		val |= (0x3 << 4);
+		break;
+	case 8:
+		d_len_code = 3;
+		c_len_code = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (rt274->master)
+		c_len_code = 0x3;
+
+	snd_soc_component_update_bits(component,
+		RT274_I2S_CTRL1, 0xc018, d_len_code << 3 | c_len_code << 14);
+	dev_dbg(component->dev, "format val = 0x%x\n", val);
+
+	snd_soc_component_update_bits(component, RT274_DAC_FORMAT, 0x407f, val);
+	snd_soc_component_update_bits(component, RT274_ADC_FORMAT, 0x407f, val);
+
+	return 0;
+}
+
+static int rt274_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		snd_soc_component_update_bits(component,
+			RT274_I2S_CTRL1, RT274_I2S_MODE_MASK, RT274_I2S_MODE_M);
+		rt274->master = true;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		snd_soc_component_update_bits(component,
+			RT274_I2S_CTRL1, RT274_I2S_MODE_MASK, RT274_I2S_MODE_S);
+		rt274->master = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		snd_soc_component_update_bits(component, RT274_I2S_CTRL1,
+					RT274_I2S_FMT_MASK, RT274_I2S_FMT_I2S);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		snd_soc_component_update_bits(component, RT274_I2S_CTRL1,
+					RT274_I2S_FMT_MASK, RT274_I2S_FMT_LJ);
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		snd_soc_component_update_bits(component, RT274_I2S_CTRL1,
+					RT274_I2S_FMT_MASK, RT274_I2S_FMT_PCMA);
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		snd_soc_component_update_bits(component, RT274_I2S_CTRL1,
+					RT274_I2S_FMT_MASK, RT274_I2S_FMT_PCMB);
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* bit 15 Stream Type 0:PCM 1:Non-PCM */
+	snd_soc_component_update_bits(component, RT274_DAC_FORMAT, 0x8000, 0);
+	snd_soc_component_update_bits(component, RT274_ADC_FORMAT, 0x8000, 0);
+
+	return 0;
+}
+
+static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+			unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
+
+	switch (source) {
+	case RT274_PLL2_S_MCLK:
+		snd_soc_component_update_bits(component, RT274_PLL2_CTRL,
+				RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_MCLK);
+		break;
+	default:
+		dev_warn(component->dev, "invalid pll source, use BCLK\n");
+	case RT274_PLL2_S_BCLK:
+		snd_soc_component_update_bits(component, RT274_PLL2_CTRL,
+				RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_BCLK);
+		break;
+	}
+
+	if (source == RT274_PLL2_S_BCLK) {
+		snd_soc_component_update_bits(component, RT274_MCLK_CTRL,
+				(0x3 << 12), (0x3 << 12));
+		switch (rt274->fs) {
+		case 50:
+			snd_soc_component_write(component, 0x7a, 0xaab6);
+			snd_soc_component_write(component, 0x7b, 0x0301);
+			snd_soc_component_write(component, 0x7c, 0x04fe);
+			break;
+		case 64:
+			snd_soc_component_write(component, 0x7a, 0xaa96);
+			snd_soc_component_write(component, 0x7b, 0x8003);
+			snd_soc_component_write(component, 0x7c, 0x081e);
+			break;
+		case 128:
+			snd_soc_component_write(component, 0x7a, 0xaa96);
+			snd_soc_component_write(component, 0x7b, 0x8003);
+			snd_soc_component_write(component, 0x7c, 0x080e);
+			break;
+		default:
+			dev_warn(component->dev, "invalid freq_in, assume 4.8M\n");
+		case 100:
+			snd_soc_component_write(component, 0x7a, 0xaab6);
+			snd_soc_component_write(component, 0x7b, 0x0301);
+			snd_soc_component_write(component, 0x7c, 0x047e);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int rt274_set_dai_sysclk(struct snd_soc_dai *dai,
+				int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
+	unsigned int clk_src, mclk_en;
+
+	dev_dbg(component->dev, "%s freq=%d\n", __func__, freq);
+
+	switch (clk_id) {
+	case RT274_SCLK_S_MCLK:
+		mclk_en = RT274_MCLK_MODE_EN;
+		clk_src = RT274_CLK_SRC_MCLK;
+		break;
+	case RT274_SCLK_S_PLL1:
+		mclk_en = RT274_MCLK_MODE_DIS;
+		clk_src = RT274_CLK_SRC_MCLK;
+		break;
+	case RT274_SCLK_S_PLL2:
+		mclk_en = RT274_MCLK_MODE_EN;
+		clk_src = RT274_CLK_SRC_PLL2;
+		break;
+	default:
+		mclk_en = RT274_MCLK_MODE_DIS;
+		clk_src = RT274_CLK_SRC_MCLK;
+		dev_warn(component->dev, "invalid sysclk source, use PLL1\n");
+		break;
+	}
+	snd_soc_component_update_bits(component, RT274_MCLK_CTRL,
+			RT274_MCLK_MODE_MASK, mclk_en);
+	snd_soc_component_update_bits(component, RT274_CLK_CTRL,
+			RT274_CLK_SRC_MASK, clk_src);
+
+	switch (freq) {
+	case 19200000:
+		if (clk_id == RT274_SCLK_S_MCLK) {
+			dev_err(component->dev, "Should not use MCLK\n");
+			return -EINVAL;
+		}
+		snd_soc_component_update_bits(component,
+			RT274_I2S_CTRL2, 0x40, 0x40);
+		break;
+	case 24000000:
+		if (clk_id == RT274_SCLK_S_MCLK) {
+			dev_err(component->dev, "Should not use MCLK\n");
+			return -EINVAL;
+		}
+		snd_soc_component_update_bits(component,
+			RT274_I2S_CTRL2, 0x40, 0x0);
+		break;
+	case 12288000:
+	case 11289600:
+		snd_soc_component_update_bits(component,
+			RT274_MCLK_CTRL, 0x1fcf, 0x0008);
+		break;
+	case 24576000:
+	case 22579200:
+		snd_soc_component_update_bits(component,
+			RT274_MCLK_CTRL, 0x1fcf, 0x1543);
+		break;
+	default:
+		dev_err(component->dev, "Unsupported system clock\n");
+		return -EINVAL;
+	}
+
+	rt274->sys_clk = freq;
+	rt274->clk_id = clk_id;
+
+	return 0;
+}
+
+static int rt274_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
+	rt274->fs = ratio;
+	if ((ratio / 50) == 0)
+		snd_soc_component_update_bits(component,
+			RT274_I2S_CTRL1, 0x1000, 0x1000);
+	else
+		snd_soc_component_update_bits(component,
+			RT274_I2S_CTRL1, 0x1000, 0x0);
+
+
+	return 0;
+}
+
+static int rt274_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			unsigned int rx_mask, int slots, int slot_width)
+
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (rx_mask || tx_mask) {
+		snd_soc_component_update_bits(component,
+			RT274_I2S_CTRL1, RT274_TDM_EN, RT274_TDM_EN);
+	} else {
+		snd_soc_component_update_bits(component,
+			RT274_I2S_CTRL1, RT274_TDM_EN, RT274_TDM_DIS);
+		return 0;
+	}
+
+	switch (slots) {
+	case 4:
+		snd_soc_component_update_bits(component,
+			RT274_I2S_CTRL1, RT274_TDM_CH_NUM, RT274_TDM_4CH);
+		break;
+	case 2:
+		snd_soc_component_update_bits(component,
+			RT274_I2S_CTRL1, RT274_TDM_CH_NUM, RT274_TDM_2CH);
+		break;
+	default:
+		dev_err(component->dev,
+			"Support 2 or 4 slots TDM only\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt274_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		if (SND_SOC_BIAS_STANDBY ==
+			snd_soc_component_get_bias_level(component)) {
+			snd_soc_component_write(component,
+				RT274_SET_AUDIO_POWER, AC_PWRST_D0);
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_component_write(component,
+			RT274_SET_AUDIO_POWER, AC_PWRST_D3);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static irqreturn_t rt274_irq(int irq, void *data)
+{
+	struct rt274_priv *rt274 = data;
+	bool hp = false;
+	bool mic = false;
+	int ret, status = 0;
+
+	/* Clear IRQ */
+	regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
+				RT274_IRQ_CLR, RT274_IRQ_CLR);
+
+	ret = rt274_jack_detect(rt274, &hp, &mic);
+
+	if (ret == 0) {
+		if (hp == true)
+			status |= SND_JACK_HEADPHONE;
+
+		if (mic == true)
+			status |= SND_JACK_MICROPHONE;
+
+		snd_soc_jack_report(rt274->jack, status,
+			SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+
+		pm_wakeup_event(&rt274->i2c->dev, 300);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int rt274_probe(struct snd_soc_component *component)
+{
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
+
+	rt274->component = component;
+
+	if (rt274->i2c->irq) {
+		INIT_DELAYED_WORK(&rt274->jack_detect_work,
+					rt274_jack_detect_work);
+		schedule_delayed_work(&rt274->jack_detect_work,
+					msecs_to_jiffies(1250));
+	}
+
+	return 0;
+}
+
+static void rt274_remove(struct snd_soc_component *component)
+{
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
+
+	cancel_delayed_work_sync(&rt274->jack_detect_work);
+}
+
+#ifdef CONFIG_PM
+static int rt274_suspend(struct snd_soc_component *component)
+{
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt274->regmap, true);
+	regcache_mark_dirty(rt274->regmap);
+
+	return 0;
+}
+
+static int rt274_resume(struct snd_soc_component *component)
+{
+	struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt274->regmap, false);
+	rt274_index_sync(component);
+	regcache_sync(rt274->regmap);
+
+	return 0;
+}
+#else
+#define rt274_suspend NULL
+#define rt274_resume NULL
+#endif
+
+#define RT274_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define RT274_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt274_aif_dai_ops = {
+	.hw_params = rt274_hw_params,
+	.set_fmt = rt274_set_dai_fmt,
+	.set_sysclk = rt274_set_dai_sysclk,
+	.set_pll = rt274_set_dai_pll,
+	.set_bclk_ratio = rt274_set_bclk_ratio,
+	.set_tdm_slot = rt274_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver rt274_dai[] = {
+	{
+		.name = "rt274-aif1",
+		.id = RT274_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT274_STEREO_RATES,
+			.formats = RT274_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT274_STEREO_RATES,
+			.formats = RT274_FORMATS,
+		},
+		.ops = &rt274_aif_dai_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt274 = {
+	.probe			= rt274_probe,
+	.remove			= rt274_remove,
+	.suspend		= rt274_suspend,
+	.resume			= rt274_resume,
+	.set_bias_level		= rt274_set_bias_level,
+	.set_jack		= rt274_mic_detect,
+	.controls		= rt274_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt274_snd_controls),
+	.dapm_widgets		= rt274_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt274_dapm_widgets),
+	.dapm_routes		= rt274_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt274_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt274_regmap = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.max_register = 0x05bfffff,
+	.volatile_reg = rt274_volatile_register,
+	.readable_reg = rt274_readable_register,
+	.reg_write = rl6347a_hw_write,
+	.reg_read = rl6347a_hw_read,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt274_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt274_reg),
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt274_of_match[] = {
+	{.compatible = "realtek,rt274"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt274_of_match);
+#endif
+
+static const struct i2c_device_id rt274_i2c_id[] = {
+	{"rt274", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, rt274_i2c_id);
+
+static const struct acpi_device_id rt274_acpi_match[] = {
+	{ "10EC0274", 0 },
+	{ "INT34C2", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, rt274_acpi_match);
+
+static int rt274_i2c_probe(struct i2c_client *i2c,
+			   const struct i2c_device_id *id)
+{
+	struct rt274_priv *rt274;
+
+	int ret;
+	unsigned int val;
+
+	rt274 = devm_kzalloc(&i2c->dev,	sizeof(*rt274),
+				GFP_KERNEL);
+	if (rt274 == NULL)
+		return -ENOMEM;
+
+	rt274->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt274_regmap);
+	if (IS_ERR(rt274->regmap)) {
+		ret = PTR_ERR(rt274->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt274->regmap,
+		RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &val);
+	if (val != RT274_VENDOR_ID) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt274\n", val);
+		return -ENODEV;
+	}
+
+	rt274->index_cache = devm_kmemdup(&i2c->dev, rt274_index_def,
+					  sizeof(rt274_index_def), GFP_KERNEL);
+	if (!rt274->index_cache)
+		return -ENOMEM;
+
+	rt274->index_cache_size = INDEX_CACHE_SIZE;
+	rt274->i2c = i2c;
+	i2c_set_clientdata(i2c, rt274);
+
+	/* reset codec */
+	regmap_write(rt274->regmap, RT274_RESET, 0);
+	regmap_update_bits(rt274->regmap, 0x1a, 0x4000, 0x4000);
+
+	/* Set Pad PDB is floating */
+	regmap_update_bits(rt274->regmap, RT274_PAD_CTRL12, 0x3, 0x0);
+	regmap_write(rt274->regmap, RT274_COEF5b_INDEX, 0x01);
+	regmap_write(rt274->regmap, RT274_COEF5b_COEF, 0x8540);
+	regmap_update_bits(rt274->regmap, 0x6f, 0x0100, 0x0100);
+	/* Combo jack auto detect */
+	regmap_write(rt274->regmap, 0x4a, 0x201b);
+	/* Aux mode off */
+	regmap_update_bits(rt274->regmap, 0x6f, 0x3000, 0x2000);
+	/* HP DC Calibration */
+	regmap_update_bits(rt274->regmap, 0x6f, 0xf, 0x0);
+	/* Set NID=58h.Index 00h [15]= 1b; */
+	regmap_write(rt274->regmap, RT274_COEF58_INDEX, 0x00);
+	regmap_write(rt274->regmap, RT274_COEF58_COEF, 0xb888);
+	msleep(500);
+	regmap_update_bits(rt274->regmap, 0x6f, 0xf, 0xb);
+	regmap_write(rt274->regmap, RT274_COEF58_INDEX, 0x00);
+	regmap_write(rt274->regmap, RT274_COEF58_COEF, 0x3888);
+	/* Set pin widget */
+	regmap_write(rt274->regmap, RT274_SET_PIN_HPO, 0x40);
+	regmap_write(rt274->regmap, RT274_SET_PIN_LOUT3, 0x40);
+	regmap_write(rt274->regmap, RT274_SET_MIC, 0x20);
+	regmap_write(rt274->regmap, RT274_SET_PIN_DMIC1, 0x20);
+
+	regmap_update_bits(rt274->regmap, RT274_I2S_CTRL2, 0xc004, 0x4004);
+	regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
+				RT274_GPI2_SEL_MASK, RT274_GPI2_SEL_DMIC_CLK);
+
+	/* jack detection */
+	regmap_write(rt274->regmap, RT274_UNSOLICITED_HP_OUT, 0x81);
+	regmap_write(rt274->regmap, RT274_UNSOLICITED_MIC, 0x82);
+
+	if (rt274->i2c->irq) {
+		ret = request_threaded_irq(rt274->i2c->irq, NULL, rt274_irq,
+			IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt274", rt274);
+		if (ret != 0) {
+			dev_err(&i2c->dev,
+				"Failed to reguest IRQ: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_rt274,
+				     rt274_dai, ARRAY_SIZE(rt274_dai));
+
+	return ret;
+}
+
+static int rt274_i2c_remove(struct i2c_client *i2c)
+{
+	struct rt274_priv *rt274 = i2c_get_clientdata(i2c);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, rt274);
+
+	return 0;
+}
+
+
+static struct i2c_driver rt274_i2c_driver = {
+	.driver = {
+		   .name = "rt274",
+		   .acpi_match_table = ACPI_PTR(rt274_acpi_match),
+#ifdef CONFIG_OF
+		   .of_match_table = of_match_ptr(rt274_of_match),
+#endif
+		   },
+	.probe = rt274_i2c_probe,
+	.remove = rt274_i2c_remove,
+	.id_table = rt274_i2c_id,
+};
+
+module_i2c_driver(rt274_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT274 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt274.h b/sound/soc/codecs/rt274.h
new file mode 100644
index 0000000..4fd1bcb
--- /dev/null
+++ b/sound/soc/codecs/rt274.h
@@ -0,0 +1,217 @@
+/*
+ * rt274.h  --  RT274 ALSA SoC audio driver
+ *
+ * Copyright 2016 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT274_H__
+#define __RT274_H__
+
+#define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D)
+
+#define RT274_AUDIO_FUNCTION_GROUP			0x01
+#define RT274_DAC_OUT0					0x02
+#define RT274_DAC_OUT1					0x03
+#define RT274_ADC_IN2					0x08
+#define RT274_ADC_IN1					0x09
+#define RT274_DIG_CVT					0x0a
+#define RT274_DMIC1					0x12
+#define RT274_DMIC2					0x13
+#define RT274_MIC					0x19
+#define RT274_LINE1					0x1a
+#define RT274_LINE2					0x1b
+#define RT274_LINE3					0x16
+#define RT274_SPDIF					0x1e
+#define RT274_VENDOR_REGISTERS				0x20
+#define RT274_HP_OUT					0x21
+#define RT274_MIXER_IN1					0x22
+#define RT274_MIXER_IN2					0x23
+#define RT274_INLINE_CMD				0x55
+
+#define RT274_SET_PIN_SFT				6
+#define RT274_SET_PIN_ENABLE				0x40
+#define RT274_SET_PIN_DISABLE				0
+#define RT274_SET_EAPD_HIGH				0x2
+#define RT274_SET_EAPD_LOW				0
+
+#define RT274_MUTE_SFT					7
+
+/* Verb commands */
+#define RT274_RESET\
+	VERB_CMD(AC_VERB_SET_CODEC_RESET, RT274_AUDIO_FUNCTION_GROUP, 0)
+#define RT274_GET_PARAM(NID, PARAM) VERB_CMD(AC_VERB_PARAMETERS, NID, PARAM)
+#define RT274_SET_POWER(NID) VERB_CMD(AC_VERB_SET_POWER_STATE, NID, 0)
+#define RT274_SET_AUDIO_POWER RT274_SET_POWER(RT274_AUDIO_FUNCTION_GROUP)
+#define RT274_SET_HPO_POWER RT274_SET_POWER(RT274_HP_OUT)
+#define RT274_SET_DMIC1_POWER RT274_SET_POWER(RT274_DMIC1)
+#define RT274_LOUT_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_LINE3, 0)
+#define RT274_HPO_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_HP_OUT, 0)
+#define RT274_ADC0_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_MIXER_IN1, 0)
+#define RT274_ADC1_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT274_MIXER_IN2, 0)
+#define RT274_SET_MIC\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_MIC, 0)
+#define RT274_SET_PIN_LOUT3\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_LINE3, 0)
+#define RT274_SET_PIN_HPO\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_HP_OUT, 0)
+#define RT274_SET_PIN_DMIC1\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_DMIC1, 0)
+#define RT274_SET_PIN_SPDIF\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT274_SPDIF, 0)
+#define RT274_SET_PIN_DIG_CVT\
+	VERB_CMD(AC_VERB_SET_DIGI_CONVERT_1, RT274_DIG_CVT, 0)
+#define RT274_SET_AMP_GAIN_HPO\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_HP_OUT, 0)
+#define RT274_SET_AMP_GAIN_ADC_IN1\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0)
+#define RT274_SET_AMP_GAIN_ADC_IN2\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN2, 0)
+#define RT274_GET_HP_SENSE\
+	VERB_CMD(AC_VERB_GET_PIN_SENSE, RT274_HP_OUT, 0)
+#define RT274_GET_MIC_SENSE\
+	VERB_CMD(AC_VERB_GET_PIN_SENSE, RT274_MIC, 0)
+#define RT274_SET_DMIC2_DEFAULT\
+	VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT274_DMIC2, 0)
+#define RT274_SET_SPDIF_DEFAULT\
+	VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT274_SPDIF, 0)
+#define RT274_DAC0L_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0xa000)
+#define RT274_DAC0R_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT0, 0x9000)
+#define RT274_DAC1L_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0xa000)
+#define RT274_DAC1R_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_DAC_OUT1, 0x9000)
+#define RT274_ADCL_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0x6000)
+#define RT274_ADCR_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_ADC_IN1, 0x5000)
+#define RT274_MIC_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_MIC, 0x7000)
+#define RT274_LOUTL_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_LINE3, 0xa000)
+#define RT274_LOUTR_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_LINE3, 0x9000)
+#define RT274_HPOL_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_HP_OUT, 0xa000)
+#define RT274_HPOR_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT274_HP_OUT, 0x9000)
+#define RT274_DAC_FORMAT\
+	VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT274_DAC_OUT0, 0)
+#define RT274_ADC_FORMAT\
+	VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT274_ADC_IN1, 0)
+#define RT274_COEF_INDEX\
+	VERB_CMD(AC_VERB_SET_COEF_INDEX, RT274_VENDOR_REGISTERS, 0)
+#define RT274_PROC_COEF\
+	VERB_CMD(AC_VERB_SET_PROC_COEF, RT274_VENDOR_REGISTERS, 0)
+#define RT274_UNSOLICITED_INLINE_CMD\
+	VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT274_INLINE_CMD, 0)
+#define RT274_UNSOLICITED_HP_OUT\
+	VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT274_HP_OUT, 0)
+#define RT274_UNSOLICITED_MIC\
+	VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT274_MIC, 0)
+#define RT274_COEF58_INDEX\
+	VERB_CMD(AC_VERB_SET_COEF_INDEX, 0x58, 0)
+#define RT274_COEF58_COEF\
+	VERB_CMD(AC_VERB_SET_PROC_COEF, 0x58, 0)
+#define RT274_COEF5b_INDEX\
+	VERB_CMD(AC_VERB_SET_COEF_INDEX, 0x5b, 0)
+#define RT274_COEF5b_COEF\
+	VERB_CMD(AC_VERB_SET_PROC_COEF, 0x5b, 0)
+#define RT274_SET_STREAMID_DAC0\
+	VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_DAC_OUT0, 0)
+#define RT274_SET_STREAMID_DAC1\
+	VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_DAC_OUT1, 0)
+#define RT274_SET_STREAMID_ADC1\
+	VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_ADC_IN1, 0)
+#define RT274_SET_STREAMID_ADC2\
+	VERB_CMD(AC_VERB_SET_CHANNEL_STREAMID, RT274_ADC_IN2, 0)
+
+/* Index registers */
+#define RT274_EAPD_GPIO_IRQ_CTRL	0x10
+#define RT274_PAD_CTRL12		0x35
+#define RT274_I2S_CTRL1			0x63
+#define RT274_I2S_CTRL2			0x64
+#define RT274_MCLK_CTRL			0x71
+#define RT274_CLK_CTRL			0x72
+#define RT274_PLL2_CTRL			0x7b
+
+
+/* EAPD GPIO IRQ control (Index 0x10) */
+#define RT274_IRQ_DIS		(0x0 << 13)
+#define RT274_IRQ_EN		(0x1 << 13)
+#define RT274_IRQ_CLR		(0x1 << 12)
+#define RT274_GPI2_SEL_MASK	(0x3 << 7)
+#define RT274_GPI2_SEL_GPIO2	(0x0 << 7)
+#define RT274_GPI2_SEL_I2S	(0x1 << 7)
+#define RT274_GPI2_SEL_DMIC_CLK	(0x2 << 7)
+#define RT274_GPI2_SEL_CBJ	(0x3 << 7)
+
+/* Front I2S_Interface control 1 (Index 0x63) */
+#define RT274_I2S_MODE_MASK	(0x1 << 11)
+#define RT274_I2S_MODE_S	(0x0 << 11)
+#define RT274_I2S_MODE_M	(0x1 << 11)
+#define RT274_TDM_DIS		(0x0 << 10)
+#define RT274_TDM_EN		(0x1 << 10)
+#define RT274_TDM_CH_NUM	(0x1 << 7)
+#define RT274_TDM_2CH		(0x0 << 7)
+#define RT274_TDM_4CH		(0x1 << 7)
+#define RT274_I2S_FMT_MASK	(0x3 << 8)
+#define RT274_I2S_FMT_I2S	(0x0 << 8)
+#define RT274_I2S_FMT_LJ	(0x1 << 8)
+#define RT274_I2S_FMT_PCMA	(0x2 << 8)
+#define RT274_I2S_FMT_PCMB	(0x3 << 8)
+
+/* MCLK clock domain control (Index 0x71) */
+#define RT274_MCLK_MODE_MASK	(0x1 << 14)
+#define RT274_MCLK_MODE_DIS	(0x0 << 14)
+#define RT274_MCLK_MODE_EN	(0x1 << 14)
+
+/* Clock control (Index 0x72) */
+#define RT274_CLK_SRC_MASK	(0x7 << 3)
+#define RT274_CLK_SRC_MCLK	(0x0 << 3)
+#define RT274_CLK_SRC_PLL2	(0x3 << 3)
+
+/* PLL2 control (Index 0x7b) */
+#define RT274_PLL2_SRC_MASK	(0x1 << 13)
+#define RT274_PLL2_SRC_MCLK	(0x0 << 13)
+#define RT274_PLL2_SRC_BCLK	(0x1 << 13)
+
+/* HP-OUT (0x21) */
+#define RT274_M_HP_MUX_SFT	14
+#define RT274_HP_SEL_MASK	0x1
+#define RT274_HP_SEL_SFT	0
+#define RT274_HP_SEL_F		0
+#define RT274_HP_SEL_S		1
+
+/* ADC (0x22) (0x23) */
+#define RT274_ADC_SEL_MASK	0x7
+#define RT274_ADC_SEL_SFT	0
+#define RT274_ADC_SEL_MIC	0
+#define RT274_ADC_SEL_LINE1	1
+#define RT274_ADC_SEL_LINE2	2
+#define RT274_ADC_SEL_DMIC	3
+
+#define RT274_SCLK_S_MCLK	0
+#define RT274_SCLK_S_PLL1	1
+#define RT274_SCLK_S_PLL2	2
+
+#define RT274_PLL2_S_MCLK	0
+#define RT274_PLL2_S_BCLK	1
+
+enum {
+	RT274_AIF1,
+	RT274_AIFS,
+};
+
+#endif /* __RT274_H__ */
+
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
new file mode 100644
index 0000000..0b0f748
--- /dev/null
+++ b/sound/soc/codecs/rt286.c
@@ -0,0 +1,1277 @@
+/*
+ * rt286.c  --  RT286 ALSA SoC audio codec driver
+ *
+ * Copyright 2013 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+#include <linux/workqueue.h>
+#include <sound/rt286.h>
+
+#include "rl6347a.h"
+#include "rt286.h"
+
+#define RT286_VENDOR_ID 0x10ec0286
+#define RT288_VENDOR_ID 0x10ec0288
+
+struct rt286_priv {
+	struct reg_default *index_cache;
+	int index_cache_size;
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct rt286_platform_data pdata;
+	struct i2c_client *i2c;
+	struct snd_soc_jack *jack;
+	struct delayed_work jack_detect_work;
+	int sys_clk;
+	int clk_id;
+};
+
+static const struct reg_default rt286_index_def[] = {
+	{ 0x01, 0xaaaa },
+	{ 0x02, 0x8aaa },
+	{ 0x03, 0x0002 },
+	{ 0x04, 0xaf01 },
+	{ 0x08, 0x000d },
+	{ 0x09, 0xd810 },
+	{ 0x0a, 0x0120 },
+	{ 0x0b, 0x0000 },
+	{ 0x0d, 0x2800 },
+	{ 0x0f, 0x0000 },
+	{ 0x19, 0x0a17 },
+	{ 0x20, 0x0020 },
+	{ 0x33, 0x0208 },
+	{ 0x49, 0x0004 },
+	{ 0x4f, 0x50e9 },
+	{ 0x50, 0x2000 },
+	{ 0x63, 0x2902 },
+	{ 0x67, 0x1111 },
+	{ 0x68, 0x1016 },
+	{ 0x69, 0x273f },
+};
+#define INDEX_CACHE_SIZE ARRAY_SIZE(rt286_index_def)
+
+static const struct reg_default rt286_reg[] = {
+	{ 0x00170500, 0x00000400 },
+	{ 0x00220000, 0x00000031 },
+	{ 0x00239000, 0x0000007f },
+	{ 0x0023a000, 0x0000007f },
+	{ 0x00270500, 0x00000400 },
+	{ 0x00370500, 0x00000400 },
+	{ 0x00870500, 0x00000400 },
+	{ 0x00920000, 0x00000031 },
+	{ 0x00935000, 0x000000c3 },
+	{ 0x00936000, 0x000000c3 },
+	{ 0x00970500, 0x00000400 },
+	{ 0x00b37000, 0x00000097 },
+	{ 0x00b37200, 0x00000097 },
+	{ 0x00b37300, 0x00000097 },
+	{ 0x00c37000, 0x00000000 },
+	{ 0x00c37100, 0x00000080 },
+	{ 0x01270500, 0x00000400 },
+	{ 0x01370500, 0x00000400 },
+	{ 0x01371f00, 0x411111f0 },
+	{ 0x01439000, 0x00000080 },
+	{ 0x0143a000, 0x00000080 },
+	{ 0x01470700, 0x00000000 },
+	{ 0x01470500, 0x00000400 },
+	{ 0x01470c00, 0x00000000 },
+	{ 0x01470100, 0x00000000 },
+	{ 0x01837000, 0x00000000 },
+	{ 0x01870500, 0x00000400 },
+	{ 0x02050000, 0x00000000 },
+	{ 0x02139000, 0x00000080 },
+	{ 0x0213a000, 0x00000080 },
+	{ 0x02170100, 0x00000000 },
+	{ 0x02170500, 0x00000400 },
+	{ 0x02170700, 0x00000000 },
+	{ 0x02270100, 0x00000000 },
+	{ 0x02370100, 0x00000000 },
+	{ 0x01870700, 0x00000020 },
+	{ 0x00830000, 0x000000c3 },
+	{ 0x00930000, 0x000000c3 },
+	{ 0x01270700, 0x00000000 },
+};
+
+static bool rt286_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0 ... 0xff:
+	case RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID):
+	case RT286_GET_HP_SENSE:
+	case RT286_GET_MIC1_SENSE:
+	case RT286_PROC_COEF:
+		return true;
+	default:
+		return false;
+	}
+
+
+}
+
+static bool rt286_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0 ... 0xff:
+	case RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID):
+	case RT286_GET_HP_SENSE:
+	case RT286_GET_MIC1_SENSE:
+	case RT286_SET_AUDIO_POWER:
+	case RT286_SET_HPO_POWER:
+	case RT286_SET_SPK_POWER:
+	case RT286_SET_DMIC1_POWER:
+	case RT286_SPK_MUX:
+	case RT286_HPO_MUX:
+	case RT286_ADC0_MUX:
+	case RT286_ADC1_MUX:
+	case RT286_SET_MIC1:
+	case RT286_SET_PIN_HPO:
+	case RT286_SET_PIN_SPK:
+	case RT286_SET_PIN_DMIC1:
+	case RT286_SPK_EAPD:
+	case RT286_SET_AMP_GAIN_HPO:
+	case RT286_SET_DMIC2_DEFAULT:
+	case RT286_DACL_GAIN:
+	case RT286_DACR_GAIN:
+	case RT286_ADCL_GAIN:
+	case RT286_ADCR_GAIN:
+	case RT286_MIC_GAIN:
+	case RT286_SPOL_GAIN:
+	case RT286_SPOR_GAIN:
+	case RT286_HPOL_GAIN:
+	case RT286_HPOR_GAIN:
+	case RT286_F_DAC_SWITCH:
+	case RT286_F_RECMIX_SWITCH:
+	case RT286_REC_MIC_SWITCH:
+	case RT286_REC_I2S_SWITCH:
+	case RT286_REC_LINE_SWITCH:
+	case RT286_REC_BEEP_SWITCH:
+	case RT286_DAC_FORMAT:
+	case RT286_ADC_FORMAT:
+	case RT286_COEF_INDEX:
+	case RT286_PROC_COEF:
+	case RT286_SET_AMP_GAIN_ADC_IN1:
+	case RT286_SET_AMP_GAIN_ADC_IN2:
+	case RT286_SET_POWER(RT286_DAC_OUT1):
+	case RT286_SET_POWER(RT286_DAC_OUT2):
+	case RT286_SET_POWER(RT286_ADC_IN1):
+	case RT286_SET_POWER(RT286_ADC_IN2):
+	case RT286_SET_POWER(RT286_DMIC2):
+	case RT286_SET_POWER(RT286_MIC1):
+		return true;
+	default:
+		return false;
+	}
+}
+
+#ifdef CONFIG_PM
+static void rt286_index_sync(struct snd_soc_component *component)
+{
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
+	int i;
+
+	for (i = 0; i < INDEX_CACHE_SIZE; i++) {
+		snd_soc_component_write(component, rt286->index_cache[i].reg,
+				  rt286->index_cache[i].def);
+	}
+}
+#endif
+
+static int rt286_support_power_controls[] = {
+	RT286_DAC_OUT1,
+	RT286_DAC_OUT2,
+	RT286_ADC_IN1,
+	RT286_ADC_IN2,
+	RT286_MIC1,
+	RT286_DMIC1,
+	RT286_DMIC2,
+	RT286_SPK_OUT,
+	RT286_HP_OUT,
+};
+#define RT286_POWER_REG_LEN ARRAY_SIZE(rt286_support_power_controls)
+
+static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
+{
+	struct snd_soc_dapm_context *dapm;
+	unsigned int val, buf;
+
+	*hp = false;
+	*mic = false;
+
+	if (!rt286->component)
+		return -EINVAL;
+
+	dapm = snd_soc_component_get_dapm(rt286->component);
+
+	if (rt286->pdata.cbj_en) {
+		regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
+		*hp = buf & 0x80000000;
+		if (*hp) {
+			/* power on HV,VERF */
+			regmap_update_bits(rt286->regmap,
+				RT286_DC_GAIN, 0x200, 0x200);
+
+			snd_soc_dapm_force_enable_pin(dapm, "HV");
+			snd_soc_dapm_force_enable_pin(dapm, "VREF");
+			/* power LDO1 */
+			snd_soc_dapm_force_enable_pin(dapm, "LDO1");
+			snd_soc_dapm_sync(dapm);
+
+			regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24);
+			msleep(50);
+
+			regmap_update_bits(rt286->regmap,
+				RT286_CBJ_CTRL1, 0xfcc0, 0xd400);
+			msleep(300);
+			regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val);
+
+			if (0x0070 == (val & 0x0070)) {
+				*mic = true;
+			} else {
+				regmap_update_bits(rt286->regmap,
+					RT286_CBJ_CTRL1, 0xfcc0, 0xe400);
+				msleep(300);
+				regmap_read(rt286->regmap,
+					RT286_CBJ_CTRL2, &val);
+				if (0x0070 == (val & 0x0070))
+					*mic = true;
+				else
+					*mic = false;
+			}
+			regmap_update_bits(rt286->regmap,
+				RT286_DC_GAIN, 0x200, 0x0);
+
+		} else {
+			*mic = false;
+			regmap_write(rt286->regmap, RT286_SET_MIC1, 0x20);
+			regmap_update_bits(rt286->regmap,
+				RT286_CBJ_CTRL1, 0x0400, 0x0000);
+		}
+	} else {
+		regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
+		*hp = buf & 0x80000000;
+		regmap_read(rt286->regmap, RT286_GET_MIC1_SENSE, &buf);
+		*mic = buf & 0x80000000;
+	}
+	if (!*mic) {
+		snd_soc_dapm_disable_pin(dapm, "HV");
+		snd_soc_dapm_disable_pin(dapm, "VREF");
+	}
+	if (!*hp)
+		snd_soc_dapm_disable_pin(dapm, "LDO1");
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static void rt286_jack_detect_work(struct work_struct *work)
+{
+	struct rt286_priv *rt286 =
+		container_of(work, struct rt286_priv, jack_detect_work.work);
+	int status = 0;
+	bool hp = false;
+	bool mic = false;
+
+	rt286_jack_detect(rt286, &hp, &mic);
+
+	if (hp == true)
+		status |= SND_JACK_HEADPHONE;
+
+	if (mic == true)
+		status |= SND_JACK_MICROPHONE;
+
+	snd_soc_jack_report(rt286->jack, status,
+		SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+}
+
+int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
+
+	rt286->jack = jack;
+
+	if (jack) {
+		/* enable IRQ */
+		if (rt286->jack->status & SND_JACK_HEADPHONE)
+			snd_soc_dapm_force_enable_pin(dapm, "LDO1");
+		regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x2);
+		/* Send an initial empty report */
+		snd_soc_jack_report(rt286->jack, rt286->jack->status,
+			SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+	} else {
+		/* disable IRQ */
+		regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x0);
+		snd_soc_dapm_disable_pin(dapm, "LDO1");
+	}
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt286_mic_detect);
+
+static int is_mclk_mode(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
+
+	if (rt286->clk_id == RT286_SCLK_S_MCLK)
+		return 1;
+	else
+		return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
+
+static const struct snd_kcontrol_new rt286_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT286_DACL_GAIN,
+			    RT286_DACR_GAIN, 0, 0x7f, 0, out_vol_tlv),
+	SOC_DOUBLE_R("ADC0 Capture Switch", RT286_ADCL_GAIN,
+			    RT286_ADCR_GAIN, 7, 1, 1),
+	SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT286_ADCL_GAIN,
+			    RT286_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv),
+	SOC_SINGLE_TLV("AMIC Volume", RT286_MIC_GAIN,
+			    0, 0x3, 0, mic_vol_tlv),
+	SOC_DOUBLE_R("Speaker Playback Switch", RT286_SPOL_GAIN,
+			    RT286_SPOR_GAIN, RT286_MUTE_SFT, 1, 1),
+};
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt286_front_mix[] = {
+	SOC_DAPM_SINGLE("DAC Switch",  RT286_F_DAC_SWITCH,
+			RT286_MUTE_SFT, 1, 1),
+	SOC_DAPM_SINGLE("RECMIX Switch", RT286_F_RECMIX_SWITCH,
+			RT286_MUTE_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt286_rec_mix[] = {
+	SOC_DAPM_SINGLE("Mic1 Switch", RT286_REC_MIC_SWITCH,
+			RT286_MUTE_SFT, 1, 1),
+	SOC_DAPM_SINGLE("I2S Switch", RT286_REC_I2S_SWITCH,
+			RT286_MUTE_SFT, 1, 1),
+	SOC_DAPM_SINGLE("Line1 Switch", RT286_REC_LINE_SWITCH,
+			RT286_MUTE_SFT, 1, 1),
+	SOC_DAPM_SINGLE("Beep Switch", RT286_REC_BEEP_SWITCH,
+			RT286_MUTE_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new spo_enable_control =
+	SOC_DAPM_SINGLE("Switch", RT286_SET_PIN_SPK,
+			RT286_SET_PIN_SFT, 1, 0);
+
+static const struct snd_kcontrol_new hpol_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT286_HPOL_GAIN,
+			RT286_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpor_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT286_HPOR_GAIN,
+			RT286_MUTE_SFT, 1, 1);
+
+/* ADC0 source */
+static const char * const rt286_adc_src[] = {
+	"Mic", "RECMIX", "Dmic"
+};
+
+static const int rt286_adc_values[] = {
+	0, 4, 5,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(
+	rt286_adc0_enum, RT286_ADC0_MUX, RT286_ADC_SEL_SFT,
+	RT286_ADC_SEL_MASK, rt286_adc_src, rt286_adc_values);
+
+static const struct snd_kcontrol_new rt286_adc0_mux =
+	SOC_DAPM_ENUM("ADC 0 source", rt286_adc0_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(
+	rt286_adc1_enum, RT286_ADC1_MUX, RT286_ADC_SEL_SFT,
+	RT286_ADC_SEL_MASK, rt286_adc_src, rt286_adc_values);
+
+static const struct snd_kcontrol_new rt286_adc1_mux =
+	SOC_DAPM_ENUM("ADC 1 source", rt286_adc1_enum);
+
+static const char * const rt286_dac_src[] = {
+	"Front", "Surround"
+};
+/* HP-OUT source */
+static SOC_ENUM_SINGLE_DECL(rt286_hpo_enum, RT286_HPO_MUX,
+				0, rt286_dac_src);
+
+static const struct snd_kcontrol_new rt286_hpo_mux =
+SOC_DAPM_ENUM("HPO source", rt286_hpo_enum);
+
+/* SPK-OUT source */
+static SOC_ENUM_SINGLE_DECL(rt286_spo_enum, RT286_SPK_MUX,
+				0, rt286_dac_src);
+
+static const struct snd_kcontrol_new rt286_spo_mux =
+SOC_DAPM_ENUM("SPO source", rt286_spo_enum);
+
+static int rt286_spk_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_write(component,
+			RT286_SPK_EAPD, RT286_SET_EAPD_HIGH);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_write(component,
+			RT286_SPK_EAPD, RT286_SET_EAPD_LOW);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_write(component, RT286_SET_PIN_DMIC1, 0x20);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_write(component, RT286_SET_PIN_DMIC1, 0);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT286_POWER_CTRL2, 0x38, 0x08);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT286_POWER_CTRL2, 0x38, 0x30);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt286_mic1_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component,
+			RT286_A_BIAS_CTRL3, 0xc000, 0x8000);
+		snd_soc_component_update_bits(component,
+			RT286_A_BIAS_CTRL2, 0xc000, 0x8000);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component,
+			RT286_A_BIAS_CTRL3, 0xc000, 0x0000);
+		snd_soc_component_update_bits(component,
+			RT286_A_BIAS_CTRL2, 0xc000, 0x0000);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY_S("HV", 1, RT286_POWER_CTRL1,
+		12, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VREF", RT286_POWER_CTRL1,
+		0, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT286_POWER_CTRL2,
+		2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("LDO2", 2, RT286_POWER_CTRL1,
+		13, 1, rt286_ldo2_event, SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("MCLK MODE", RT286_PLL_CTRL1,
+		5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MIC1 Input Buffer", SND_SOC_NOPM,
+		0, 0, rt286_mic1_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC1 Pin"),
+	SND_SOC_DAPM_INPUT("DMIC2 Pin"),
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("LINE1"),
+	SND_SOC_DAPM_INPUT("Beep"),
+
+	/* DMIC */
+	SND_SOC_DAPM_PGA_E("DMIC1", RT286_SET_POWER(RT286_DMIC1), 0, 1,
+		NULL, 0, rt286_set_dmic1_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA("DMIC2", RT286_SET_POWER(RT286_DMIC2), 0, 1,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC Receiver", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIX", SND_SOC_NOPM, 0, 0,
+		rt286_rec_mix, ARRAY_SIZE(rt286_rec_mix)),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC 0", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, 0, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("ADC 0 Mux", RT286_SET_POWER(RT286_ADC_IN1), 0, 1,
+		&rt286_adc0_mux),
+	SND_SOC_DAPM_MUX("ADC 1 Mux", RT286_SET_POWER(RT286_ADC_IN2), 0, 1,
+		&rt286_adc1_mux),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Side */
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC 0", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC 1", NULL, SND_SOC_NOPM, 0, 0),
+
+	/* Output Mux */
+	SND_SOC_DAPM_MUX("SPK Mux", SND_SOC_NOPM, 0, 0, &rt286_spo_mux),
+	SND_SOC_DAPM_MUX("HPO Mux", SND_SOC_NOPM, 0, 0, &rt286_hpo_mux),
+
+	SND_SOC_DAPM_SUPPLY("HP Power", RT286_SET_PIN_HPO,
+		RT286_SET_PIN_SFT, 0, NULL, 0),
+
+	/* Output Mixer */
+	SND_SOC_DAPM_MIXER("Front", RT286_SET_POWER(RT286_DAC_OUT1), 0, 1,
+			rt286_front_mix, ARRAY_SIZE(rt286_front_mix)),
+	SND_SOC_DAPM_PGA("Surround", RT286_SET_POWER(RT286_DAC_OUT2), 0, 1,
+			NULL, 0),
+
+	/* Output Pga */
+	SND_SOC_DAPM_SWITCH_E("SPO", SND_SOC_NOPM, 0, 0,
+		&spo_enable_control, rt286_spk_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SWITCH("HPO L", SND_SOC_NOPM, 0, 0,
+		&hpol_enable_control),
+	SND_SOC_DAPM_SWITCH("HPO R", SND_SOC_NOPM, 0, 0,
+		&hpor_enable_control),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("SPOL"),
+	SND_SOC_DAPM_OUTPUT("SPOR"),
+	SND_SOC_DAPM_OUTPUT("HPO Pin"),
+	SND_SOC_DAPM_OUTPUT("SPDIF"),
+};
+
+static const struct snd_soc_dapm_route rt286_dapm_routes[] = {
+	{"ADC 0", NULL, "MCLK MODE", is_mclk_mode},
+	{"ADC 1", NULL, "MCLK MODE", is_mclk_mode},
+	{"Front", NULL, "MCLK MODE", is_mclk_mode},
+	{"Surround", NULL, "MCLK MODE", is_mclk_mode},
+
+	{"HP Power", NULL, "LDO1"},
+	{"HP Power", NULL, "LDO2"},
+
+	{"MIC1", NULL, "LDO1"},
+	{"MIC1", NULL, "LDO2"},
+	{"MIC1", NULL, "HV"},
+	{"MIC1", NULL, "VREF"},
+	{"MIC1", NULL, "MIC1 Input Buffer"},
+
+	{"SPO", NULL, "LDO1"},
+	{"SPO", NULL, "LDO2"},
+	{"SPO", NULL, "HV"},
+	{"SPO", NULL, "VREF"},
+
+	{"DMIC1", NULL, "DMIC1 Pin"},
+	{"DMIC2", NULL, "DMIC2 Pin"},
+	{"DMIC1", NULL, "DMIC Receiver"},
+	{"DMIC2", NULL, "DMIC Receiver"},
+
+	{"RECMIX", "Beep Switch", "Beep"},
+	{"RECMIX", "Line1 Switch", "LINE1"},
+	{"RECMIX", "Mic1 Switch", "MIC1"},
+
+	{"ADC 0 Mux", "Dmic", "DMIC1"},
+	{"ADC 0 Mux", "RECMIX", "RECMIX"},
+	{"ADC 0 Mux", "Mic", "MIC1"},
+	{"ADC 1 Mux", "Dmic", "DMIC2"},
+	{"ADC 1 Mux", "RECMIX", "RECMIX"},
+	{"ADC 1 Mux", "Mic", "MIC1"},
+
+	{"ADC 0", NULL, "ADC 0 Mux"},
+	{"ADC 1", NULL, "ADC 1 Mux"},
+
+	{"AIF1TX", NULL, "ADC 0"},
+	{"AIF2TX", NULL, "ADC 1"},
+
+	{"DAC 0", NULL, "AIF1RX"},
+	{"DAC 1", NULL, "AIF2RX"},
+
+	{"Front", "DAC Switch", "DAC 0"},
+	{"Front", "RECMIX Switch", "RECMIX"},
+
+	{"Surround", NULL, "DAC 1"},
+
+	{"SPK Mux", "Front", "Front"},
+	{"SPK Mux", "Surround", "Surround"},
+
+	{"HPO Mux", "Front", "Front"},
+	{"HPO Mux", "Surround", "Surround"},
+
+	{"SPO", "Switch", "SPK Mux"},
+	{"HPO L", "Switch", "HPO Mux"},
+	{"HPO R", "Switch", "HPO Mux"},
+	{"HPO L", NULL, "HP Power"},
+	{"HPO R", NULL, "HP Power"},
+
+	{"SPOL", NULL, "SPO"},
+	{"SPOR", NULL, "SPO"},
+	{"HPO Pin", NULL, "HPO L"},
+	{"HPO Pin", NULL, "HPO R"},
+};
+
+static int rt286_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
+	unsigned int val = 0;
+	int d_len_code;
+
+	switch (params_rate(params)) {
+	/* bit 14 0:48K 1:44.1K */
+	case 44100:
+		val |= 0x4000;
+		break;
+	case 48000:
+		break;
+	default:
+		dev_err(component->dev, "Unsupported sample rate %d\n",
+					params_rate(params));
+		return -EINVAL;
+	}
+	switch (rt286->sys_clk) {
+	case 12288000:
+	case 24576000:
+		if (params_rate(params) != 48000) {
+			dev_err(component->dev, "Sys_clk is not matched (%d %d)\n",
+					params_rate(params), rt286->sys_clk);
+			return -EINVAL;
+		}
+		break;
+	case 11289600:
+	case 22579200:
+		if (params_rate(params) != 44100) {
+			dev_err(component->dev, "Sys_clk is not matched (%d %d)\n",
+					params_rate(params), rt286->sys_clk);
+			return -EINVAL;
+		}
+		break;
+	}
+
+	if (params_channels(params) <= 16) {
+		/* bit 3:0 Number of Channel */
+		val |= (params_channels(params) - 1);
+	} else {
+		dev_err(component->dev, "Unsupported channels %d\n",
+					params_channels(params));
+		return -EINVAL;
+	}
+
+	d_len_code = 0;
+	switch (params_width(params)) {
+	/* bit 6:4 Bits per Sample */
+	case 16:
+		d_len_code = 0;
+		val |= (0x1 << 4);
+		break;
+	case 32:
+		d_len_code = 2;
+		val |= (0x4 << 4);
+		break;
+	case 20:
+		d_len_code = 1;
+		val |= (0x2 << 4);
+		break;
+	case 24:
+		d_len_code = 2;
+		val |= (0x3 << 4);
+		break;
+	case 8:
+		d_len_code = 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component,
+		RT286_I2S_CTRL1, 0x0018, d_len_code << 3);
+	dev_dbg(component->dev, "format val = 0x%x\n", val);
+
+	snd_soc_component_update_bits(component, RT286_DAC_FORMAT, 0x407f, val);
+	snd_soc_component_update_bits(component, RT286_ADC_FORMAT, 0x407f, val);
+
+	return 0;
+}
+
+static int rt286_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		snd_soc_component_update_bits(component,
+			RT286_I2S_CTRL1, 0x800, 0x800);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		snd_soc_component_update_bits(component,
+			RT286_I2S_CTRL1, 0x800, 0x0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		snd_soc_component_update_bits(component,
+			RT286_I2S_CTRL1, 0x300, 0x0);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		snd_soc_component_update_bits(component,
+			RT286_I2S_CTRL1, 0x300, 0x1 << 8);
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		snd_soc_component_update_bits(component,
+			RT286_I2S_CTRL1, 0x300, 0x2 << 8);
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		snd_soc_component_update_bits(component,
+			RT286_I2S_CTRL1, 0x300, 0x3 << 8);
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* bit 15 Stream Type 0:PCM 1:Non-PCM */
+	snd_soc_component_update_bits(component, RT286_DAC_FORMAT, 0x8000, 0);
+	snd_soc_component_update_bits(component, RT286_ADC_FORMAT, 0x8000, 0);
+
+	return 0;
+}
+
+static int rt286_set_dai_sysclk(struct snd_soc_dai *dai,
+				int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "%s freq=%d\n", __func__, freq);
+
+	if (RT286_SCLK_S_MCLK == clk_id) {
+		snd_soc_component_update_bits(component,
+			RT286_I2S_CTRL2, 0x0100, 0x0);
+		snd_soc_component_update_bits(component,
+			RT286_PLL_CTRL1, 0x20, 0x20);
+	} else {
+		snd_soc_component_update_bits(component,
+			RT286_I2S_CTRL2, 0x0100, 0x0100);
+		snd_soc_component_update_bits(component,
+			RT286_PLL_CTRL, 0x4, 0x4);
+		snd_soc_component_update_bits(component,
+			RT286_PLL_CTRL1, 0x20, 0x0);
+	}
+
+	switch (freq) {
+	case 19200000:
+		if (RT286_SCLK_S_MCLK == clk_id) {
+			dev_err(component->dev, "Should not use MCLK\n");
+			return -EINVAL;
+		}
+		snd_soc_component_update_bits(component,
+			RT286_I2S_CTRL2, 0x40, 0x40);
+		break;
+	case 24000000:
+		if (RT286_SCLK_S_MCLK == clk_id) {
+			dev_err(component->dev, "Should not use MCLK\n");
+			return -EINVAL;
+		}
+		snd_soc_component_update_bits(component,
+			RT286_I2S_CTRL2, 0x40, 0x0);
+		break;
+	case 12288000:
+	case 11289600:
+		snd_soc_component_update_bits(component,
+			RT286_I2S_CTRL2, 0x8, 0x0);
+		snd_soc_component_update_bits(component,
+			RT286_CLK_DIV, 0xfc1e, 0x0004);
+		break;
+	case 24576000:
+	case 22579200:
+		snd_soc_component_update_bits(component,
+			RT286_I2S_CTRL2, 0x8, 0x8);
+		snd_soc_component_update_bits(component,
+			RT286_CLK_DIV, 0xfc1e, 0x5406);
+		break;
+	default:
+		dev_err(component->dev, "Unsupported system clock\n");
+		return -EINVAL;
+	}
+
+	rt286->sys_clk = freq;
+	rt286->clk_id = clk_id;
+
+	return 0;
+}
+
+static int rt286_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct snd_soc_component *component = dai->component;
+
+	dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
+	if (50 == ratio)
+		snd_soc_component_update_bits(component,
+			RT286_I2S_CTRL1, 0x1000, 0x1000);
+	else
+		snd_soc_component_update_bits(component,
+			RT286_I2S_CTRL1, 0x1000, 0x0);
+
+
+	return 0;
+}
+
+static int rt286_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		if (SND_SOC_BIAS_STANDBY == snd_soc_component_get_bias_level(component)) {
+			snd_soc_component_write(component,
+				RT286_SET_AUDIO_POWER, AC_PWRST_D0);
+			snd_soc_component_update_bits(component,
+				RT286_DC_GAIN, 0x200, 0x200);
+		}
+		break;
+
+	case SND_SOC_BIAS_ON:
+		mdelay(10);
+		snd_soc_component_update_bits(component,
+			RT286_DC_GAIN, 0x200, 0x0);
+
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_component_write(component,
+			RT286_SET_AUDIO_POWER, AC_PWRST_D3);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static irqreturn_t rt286_irq(int irq, void *data)
+{
+	struct rt286_priv *rt286 = data;
+	bool hp = false;
+	bool mic = false;
+	int status = 0;
+
+	rt286_jack_detect(rt286, &hp, &mic);
+
+	/* Clear IRQ */
+	regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x1, 0x1);
+
+	if (hp == true)
+		status |= SND_JACK_HEADPHONE;
+
+	if (mic == true)
+		status |= SND_JACK_MICROPHONE;
+
+	snd_soc_jack_report(rt286->jack, status,
+		SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+
+	pm_wakeup_event(&rt286->i2c->dev, 300);
+
+	return IRQ_HANDLED;
+}
+
+static int rt286_probe(struct snd_soc_component *component)
+{
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
+
+	rt286->component = component;
+
+	if (rt286->i2c->irq) {
+		regmap_update_bits(rt286->regmap,
+					RT286_IRQ_CTRL, 0x2, 0x2);
+
+		INIT_DELAYED_WORK(&rt286->jack_detect_work,
+					rt286_jack_detect_work);
+		schedule_delayed_work(&rt286->jack_detect_work,
+					msecs_to_jiffies(1250));
+	}
+
+	return 0;
+}
+
+static void rt286_remove(struct snd_soc_component *component)
+{
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
+
+	cancel_delayed_work_sync(&rt286->jack_detect_work);
+}
+
+#ifdef CONFIG_PM
+static int rt286_suspend(struct snd_soc_component *component)
+{
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt286->regmap, true);
+	regcache_mark_dirty(rt286->regmap);
+
+	return 0;
+}
+
+static int rt286_resume(struct snd_soc_component *component)
+{
+	struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt286->regmap, false);
+	rt286_index_sync(component);
+	regcache_sync(rt286->regmap);
+
+	return 0;
+}
+#else
+#define rt286_suspend NULL
+#define rt286_resume NULL
+#endif
+
+#define RT286_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define RT286_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt286_aif_dai_ops = {
+	.hw_params = rt286_hw_params,
+	.set_fmt = rt286_set_dai_fmt,
+	.set_sysclk = rt286_set_dai_sysclk,
+	.set_bclk_ratio = rt286_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt286_dai[] = {
+	{
+		.name = "rt286-aif1",
+		.id = RT286_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT286_STEREO_RATES,
+			.formats = RT286_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT286_STEREO_RATES,
+			.formats = RT286_FORMATS,
+		},
+		.ops = &rt286_aif_dai_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "rt286-aif2",
+		.id = RT286_AIF2,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT286_STEREO_RATES,
+			.formats = RT286_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT286_STEREO_RATES,
+			.formats = RT286_FORMATS,
+		},
+		.ops = &rt286_aif_dai_ops,
+		.symmetric_rates = 1,
+	},
+
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt286 = {
+	.probe			= rt286_probe,
+	.remove			= rt286_remove,
+	.suspend		= rt286_suspend,
+	.resume			= rt286_resume,
+	.set_bias_level		= rt286_set_bias_level,
+	.controls		= rt286_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt286_snd_controls),
+	.dapm_widgets		= rt286_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt286_dapm_widgets),
+	.dapm_routes		= rt286_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt286_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt286_regmap = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.max_register = 0x02370100,
+	.volatile_reg = rt286_volatile_register,
+	.readable_reg = rt286_readable_register,
+	.reg_write = rl6347a_hw_write,
+	.reg_read = rl6347a_hw_read,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt286_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt286_reg),
+};
+
+static const struct i2c_device_id rt286_i2c_id[] = {
+	{"rt286", 0},
+	{"rt288", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, rt286_i2c_id);
+
+static const struct acpi_device_id rt286_acpi_match[] = {
+	{ "INT343A", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, rt286_acpi_match);
+
+static const struct dmi_system_id force_combo_jack_table[] = {
+	{
+		.ident = "Intel Wilson Beach",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_NAME, "Wilson Beach SDS")
+		}
+	},
+	{
+		.ident = "Intel Skylake RVP",
+		.matches = {
+			DMI_MATCH(DMI_PRODUCT_NAME, "Skylake Client platform")
+		}
+	},
+	{
+		.ident = "Intel Kabylake RVP",
+		.matches = {
+			DMI_MATCH(DMI_PRODUCT_NAME, "Kabylake Client platform")
+		}
+	},
+	{
+		.ident = "Thinkpad Helix 2nd",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Helix 2nd")
+		}
+	},
+
+	{ }
+};
+
+static const struct dmi_system_id dmi_dell_dino[] = {
+	{
+		.ident = "Dell Dino",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343")
+		}
+	},
+	{ }
+};
+
+static int rt286_i2c_probe(struct i2c_client *i2c,
+			   const struct i2c_device_id *id)
+{
+	struct rt286_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt286_priv *rt286;
+	int i, ret, val;
+
+	rt286 = devm_kzalloc(&i2c->dev,	sizeof(*rt286),
+				GFP_KERNEL);
+	if (NULL == rt286)
+		return -ENOMEM;
+
+	rt286->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt286_regmap);
+	if (IS_ERR(rt286->regmap)) {
+		ret = PTR_ERR(rt286->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = regmap_read(rt286->regmap,
+		RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &val);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "I2C error %d\n", ret);
+		return ret;
+	}
+	if (val != RT286_VENDOR_ID && val != RT288_VENDOR_ID) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt286\n", val);
+		return -ENODEV;
+	}
+
+	rt286->index_cache = devm_kmemdup(&i2c->dev, rt286_index_def,
+					  sizeof(rt286_index_def), GFP_KERNEL);
+	if (!rt286->index_cache)
+		return -ENOMEM;
+
+	rt286->index_cache_size = INDEX_CACHE_SIZE;
+	rt286->i2c = i2c;
+	i2c_set_clientdata(i2c, rt286);
+
+	/* restore codec default */
+	for (i = 0; i < INDEX_CACHE_SIZE; i++)
+		regmap_write(rt286->regmap, rt286->index_cache[i].reg,
+				rt286->index_cache[i].def);
+	for (i = 0; i < ARRAY_SIZE(rt286_reg); i++)
+		regmap_write(rt286->regmap, rt286_reg[i].reg,
+				rt286_reg[i].def);
+
+	if (pdata)
+		rt286->pdata = *pdata;
+
+	if (dmi_check_system(force_combo_jack_table) ||
+		dmi_check_system(dmi_dell_dino))
+		rt286->pdata.cbj_en = true;
+
+	regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3);
+
+	for (i = 0; i < RT286_POWER_REG_LEN; i++)
+		regmap_write(rt286->regmap,
+			RT286_SET_POWER(rt286_support_power_controls[i]),
+			AC_PWRST_D1);
+
+	if (!rt286->pdata.cbj_en) {
+		regmap_write(rt286->regmap, RT286_CBJ_CTRL2, 0x0000);
+		regmap_write(rt286->regmap, RT286_MIC1_DET_CTRL, 0x0816);
+		regmap_update_bits(rt286->regmap,
+					RT286_CBJ_CTRL1, 0xf000, 0xb000);
+	} else {
+		regmap_update_bits(rt286->regmap,
+					RT286_CBJ_CTRL1, 0xf000, 0x5000);
+	}
+
+	mdelay(10);
+
+	if (!rt286->pdata.gpio2_en)
+		regmap_write(rt286->regmap, RT286_SET_DMIC2_DEFAULT, 0x4000);
+	else
+		regmap_write(rt286->regmap, RT286_SET_DMIC2_DEFAULT, 0);
+
+	mdelay(10);
+
+	regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000);
+	/* Power down LDO, VREF */
+	regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0xc, 0x0);
+	regmap_update_bits(rt286->regmap, RT286_POWER_CTRL1, 0x1001, 0x1001);
+
+	/* Set depop parameter */
+	regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a);
+	regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737);
+	regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f);
+
+	if (dmi_check_system(dmi_dell_dino)) {
+		regmap_update_bits(rt286->regmap,
+			RT286_SET_GPIO_MASK, 0x40, 0x40);
+		regmap_update_bits(rt286->regmap,
+			RT286_SET_GPIO_DIRECTION, 0x40, 0x40);
+		regmap_update_bits(rt286->regmap,
+			RT286_SET_GPIO_DATA, 0x40, 0x40);
+		regmap_update_bits(rt286->regmap,
+			RT286_GPIO_CTRL, 0xc, 0x8);
+	}
+
+	if (rt286->i2c->irq) {
+		ret = request_threaded_irq(rt286->i2c->irq, NULL, rt286_irq,
+			IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt286", rt286);
+		if (ret != 0) {
+			dev_err(&i2c->dev,
+				"Failed to reguest IRQ: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_rt286,
+				     rt286_dai, ARRAY_SIZE(rt286_dai));
+
+	return ret;
+}
+
+static int rt286_i2c_remove(struct i2c_client *i2c)
+{
+	struct rt286_priv *rt286 = i2c_get_clientdata(i2c);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, rt286);
+
+	return 0;
+}
+
+
+static struct i2c_driver rt286_i2c_driver = {
+	.driver = {
+		   .name = "rt286",
+		   .acpi_match_table = ACPI_PTR(rt286_acpi_match),
+		   },
+	.probe = rt286_i2c_probe,
+	.remove = rt286_i2c_remove,
+	.id_table = rt286_i2c_id,
+};
+
+module_i2c_driver(rt286_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT286 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt286.h b/sound/soc/codecs/rt286.h
new file mode 100644
index 0000000..c63d0e7
--- /dev/null
+++ b/sound/soc/codecs/rt286.h
@@ -0,0 +1,205 @@
+/*
+ * rt286.h  --  RT286 ALSA SoC audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ * Author: Johnny Hsu <johnnyhsu@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT286_H__
+#define __RT286_H__
+
+#define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D)
+
+#define RT286_AUDIO_FUNCTION_GROUP			0x01
+#define RT286_DAC_OUT1					0x02
+#define RT286_DAC_OUT2					0x03
+#define RT286_ADC_IN1					0x09
+#define RT286_ADC_IN2					0x08
+#define RT286_MIXER_IN					0x0b
+#define RT286_MIXER_OUT1				0x0c
+#define RT286_MIXER_OUT2				0x0d
+#define RT286_DMIC1					0x12
+#define RT286_DMIC2					0x13
+#define RT286_SPK_OUT					0x14
+#define RT286_MIC1					0x18
+#define RT286_LINE1					0x1a
+#define RT286_BEEP					0x1d
+#define RT286_SPDIF					0x1e
+#define RT286_VENDOR_REGISTERS				0x20
+#define RT286_HP_OUT					0x21
+#define RT286_MIXER_IN1					0x22
+#define RT286_MIXER_IN2					0x23
+
+#define RT286_SET_PIN_SFT				6
+#define RT286_SET_PIN_ENABLE				0x40
+#define RT286_SET_PIN_DISABLE				0
+#define RT286_SET_EAPD_HIGH				0x2
+#define RT286_SET_EAPD_LOW				0
+
+#define RT286_MUTE_SFT					7
+
+/* Verb commands */
+#define RT286_GET_PARAM(NID, PARAM) VERB_CMD(AC_VERB_PARAMETERS, NID, PARAM)
+#define RT286_SET_POWER(NID) VERB_CMD(AC_VERB_SET_POWER_STATE, NID, 0)
+#define RT286_SET_AUDIO_POWER RT286_SET_POWER(RT286_AUDIO_FUNCTION_GROUP)
+#define RT286_SET_HPO_POWER RT286_SET_POWER(RT286_HP_OUT)
+#define RT286_SET_SPK_POWER RT286_SET_POWER(RT286_SPK_OUT)
+#define RT286_SET_DMIC1_POWER RT286_SET_POWER(RT286_DMIC1)
+#define RT286_SPK_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_SPK_OUT, 0)
+#define RT286_HPO_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_HP_OUT, 0)
+#define RT286_ADC0_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_MIXER_IN1, 0)
+#define RT286_ADC1_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_MIXER_IN2, 0)
+#define RT286_SET_MIC1\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_MIC1, 0)
+#define RT286_SET_PIN_HPO\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_HP_OUT, 0)
+#define RT286_SET_PIN_SPK\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_SPK_OUT, 0)
+#define RT286_SET_PIN_DMIC1\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_DMIC1, 0)
+#define RT286_SPK_EAPD\
+	VERB_CMD(AC_VERB_SET_EAPD_BTLENABLE, RT286_SPK_OUT, 0)
+#define RT286_SET_AMP_GAIN_HPO\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_HP_OUT, 0)
+#define RT286_SET_AMP_GAIN_ADC_IN1\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN1, 0)
+#define RT286_SET_AMP_GAIN_ADC_IN2\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN2, 0)
+#define RT286_GET_HP_SENSE\
+	VERB_CMD(AC_VERB_GET_PIN_SENSE, RT286_HP_OUT, 0)
+#define RT286_GET_MIC1_SENSE\
+	VERB_CMD(AC_VERB_GET_PIN_SENSE, RT286_MIC1, 0)
+#define RT286_SET_DMIC2_DEFAULT\
+	VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT286_DMIC2, 0)
+#define RT286_DACL_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_DAC_OUT1, 0xa000)
+#define RT286_DACR_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_DAC_OUT1, 0x9000)
+#define RT286_ADCL_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN1, 0x6000)
+#define RT286_ADCR_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN1, 0x5000)
+#define RT286_MIC_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIC1, 0x7000)
+#define RT286_SPOL_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_SPK_OUT, 0xa000)
+#define RT286_SPOR_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_SPK_OUT, 0x9000)
+#define RT286_HPOL_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_HP_OUT, 0xa000)
+#define RT286_HPOR_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_HP_OUT, 0x9000)
+#define RT286_F_DAC_SWITCH\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_OUT1, 0x7000)
+#define RT286_F_RECMIX_SWITCH\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_OUT1, 0x7100)
+#define RT286_REC_MIC_SWITCH\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7000)
+#define RT286_REC_I2S_SWITCH\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7100)
+#define RT286_REC_LINE_SWITCH\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7200)
+#define RT286_REC_BEEP_SWITCH\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7300)
+#define RT286_DAC_FORMAT\
+	VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT286_DAC_OUT1, 0)
+#define RT286_ADC_FORMAT\
+	VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT286_ADC_IN1, 0)
+#define RT286_COEF_INDEX\
+	VERB_CMD(AC_VERB_SET_COEF_INDEX, RT286_VENDOR_REGISTERS, 0)
+#define RT286_PROC_COEF\
+	VERB_CMD(AC_VERB_SET_PROC_COEF, RT286_VENDOR_REGISTERS, 0)
+#define RT286_SET_GPIO_MASK\
+	VERB_CMD(AC_VERB_SET_GPIO_MASK, RT286_AUDIO_FUNCTION_GROUP, 0)
+#define RT286_SET_GPIO_DIRECTION\
+	VERB_CMD(AC_VERB_SET_GPIO_DIRECTION, RT286_AUDIO_FUNCTION_GROUP, 0)
+#define RT286_SET_GPIO_DATA\
+	VERB_CMD(AC_VERB_SET_GPIO_DATA, RT286_AUDIO_FUNCTION_GROUP, 0)
+
+/* Index registers */
+#define RT286_A_BIAS_CTRL1	0x01
+#define RT286_A_BIAS_CTRL2	0x02
+#define RT286_POWER_CTRL1	0x03
+#define RT286_A_BIAS_CTRL3	0x04
+#define RT286_POWER_CTRL2	0x08
+#define RT286_I2S_CTRL1		0x09
+#define RT286_I2S_CTRL2		0x0a
+#define RT286_CLK_DIV		0x0b
+#define RT286_DC_GAIN		0x0d
+#define RT286_POWER_CTRL3	0x0f
+#define RT286_MIC1_DET_CTRL	0x19
+#define RT286_MISC_CTRL1	0x20
+#define RT286_GPIO_CTRL		0x29
+#define RT286_IRQ_CTRL		0x33
+#define RT286_PLL_CTRL1		0x49
+#define RT286_CBJ_CTRL1		0x4f
+#define RT286_CBJ_CTRL2		0x50
+#define RT286_PLL_CTRL		0x63
+#define RT286_DEPOP_CTRL1	0x66
+#define RT286_DEPOP_CTRL2	0x67
+#define RT286_DEPOP_CTRL3	0x68
+#define RT286_DEPOP_CTRL4	0x69
+
+/* SPDIF (0x06) */
+#define RT286_SPDIF_SEL_SFT	0
+#define RT286_SPDIF_SEL_PCM0	0
+#define RT286_SPDIF_SEL_PCM1	1
+#define RT286_SPDIF_SEL_SPOUT	2
+#define RT286_SPDIF_SEL_PP	3
+
+/* RECMIX (0x0b) */
+#define RT286_M_REC_BEEP_SFT	0
+#define RT286_M_REC_LINE1_SFT	1
+#define RT286_M_REC_MIC1_SFT	2
+#define RT286_M_REC_I2S_SFT	3
+
+/* Front (0x0c) */
+#define RT286_M_FRONT_DAC_SFT	0
+#define RT286_M_FRONT_REC_SFT	1
+
+/* SPK-OUT (0x14) */
+#define RT286_M_SPK_MUX_SFT	14
+#define RT286_SPK_SEL_MASK	0x1
+#define RT286_SPK_SEL_SFT	0
+#define RT286_SPK_SEL_F		0
+#define RT286_SPK_SEL_S		1
+
+/* HP-OUT (0x21) */
+#define RT286_M_HP_MUX_SFT	14
+#define RT286_HP_SEL_MASK	0x1
+#define RT286_HP_SEL_SFT	0
+#define RT286_HP_SEL_F		0
+#define RT286_HP_SEL_S		1
+
+/* ADC (0x22) (0x23) */
+#define RT286_ADC_SEL_MASK	0x7
+#define RT286_ADC_SEL_SFT	0
+#define RT286_ADC_SEL_SURR	0
+#define RT286_ADC_SEL_FRONT	1
+#define RT286_ADC_SEL_DMIC	2
+#define RT286_ADC_SEL_BEEP	4
+#define RT286_ADC_SEL_LINE1	5
+#define RT286_ADC_SEL_I2S	6
+#define RT286_ADC_SEL_MIC1	7
+
+#define RT286_SCLK_S_MCLK	0
+#define RT286_SCLK_S_PLL	1
+
+enum {
+	RT286_AIF1,
+	RT286_AIF2,
+	RT286_AIFS,
+};
+
+int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack);
+
+#endif /* __RT286_H__ */
+
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
new file mode 100644
index 0000000..06cdba4
--- /dev/null
+++ b/sound/soc/codecs/rt298.c
@@ -0,0 +1,1322 @@
+/*
+ * rt298.c  --  RT298 ALSA SoC audio codec driver
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+#include <linux/workqueue.h>
+#include <sound/rt298.h>
+
+#include "rl6347a.h"
+#include "rt298.h"
+
+#define RT298_VENDOR_ID 0x10ec0298
+
+struct rt298_priv {
+	struct reg_default *index_cache;
+	int index_cache_size;
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	struct rt298_platform_data pdata;
+	struct i2c_client *i2c;
+	struct snd_soc_jack *jack;
+	struct delayed_work jack_detect_work;
+	int sys_clk;
+	int clk_id;
+	int is_hp_in;
+};
+
+static const struct reg_default rt298_index_def[] = {
+	{ 0x01, 0xa5a8 },
+	{ 0x02, 0x8e95 },
+	{ 0x03, 0x0002 },
+	{ 0x04, 0xaf67 },
+	{ 0x08, 0x200f },
+	{ 0x09, 0xd010 },
+	{ 0x0a, 0x0100 },
+	{ 0x0b, 0x0000 },
+	{ 0x0d, 0x2800 },
+	{ 0x0f, 0x0022 },
+	{ 0x19, 0x0217 },
+	{ 0x20, 0x0020 },
+	{ 0x33, 0x0208 },
+	{ 0x46, 0x0300 },
+	{ 0x49, 0x4004 },
+	{ 0x4f, 0x50c9 },
+	{ 0x50, 0x3000 },
+	{ 0x63, 0x1b02 },
+	{ 0x67, 0x1111 },
+	{ 0x68, 0x1016 },
+	{ 0x69, 0x273f },
+};
+#define INDEX_CACHE_SIZE ARRAY_SIZE(rt298_index_def)
+
+static const struct reg_default rt298_reg[] = {
+	{ 0x00170500, 0x00000400 },
+	{ 0x00220000, 0x00000031 },
+	{ 0x00239000, 0x0000007f },
+	{ 0x0023a000, 0x0000007f },
+	{ 0x00270500, 0x00000400 },
+	{ 0x00370500, 0x00000400 },
+	{ 0x00870500, 0x00000400 },
+	{ 0x00920000, 0x00000031 },
+	{ 0x00935000, 0x000000c3 },
+	{ 0x00936000, 0x000000c3 },
+	{ 0x00970500, 0x00000400 },
+	{ 0x00b37000, 0x00000097 },
+	{ 0x00b37200, 0x00000097 },
+	{ 0x00b37300, 0x00000097 },
+	{ 0x00c37000, 0x00000000 },
+	{ 0x00c37100, 0x00000080 },
+	{ 0x01270500, 0x00000400 },
+	{ 0x01370500, 0x00000400 },
+	{ 0x01371f00, 0x411111f0 },
+	{ 0x01439000, 0x00000080 },
+	{ 0x0143a000, 0x00000080 },
+	{ 0x01470700, 0x00000000 },
+	{ 0x01470500, 0x00000400 },
+	{ 0x01470c00, 0x00000000 },
+	{ 0x01470100, 0x00000000 },
+	{ 0x01837000, 0x00000000 },
+	{ 0x01870500, 0x00000400 },
+	{ 0x02050000, 0x00000000 },
+	{ 0x02139000, 0x00000080 },
+	{ 0x0213a000, 0x00000080 },
+	{ 0x02170100, 0x00000000 },
+	{ 0x02170500, 0x00000400 },
+	{ 0x02170700, 0x00000000 },
+	{ 0x02270100, 0x00000000 },
+	{ 0x02370100, 0x00000000 },
+	{ 0x01870700, 0x00000020 },
+	{ 0x00830000, 0x000000c3 },
+	{ 0x00930000, 0x000000c3 },
+	{ 0x01270700, 0x00000000 },
+};
+
+static bool rt298_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0 ... 0xff:
+	case RT298_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID):
+	case RT298_GET_HP_SENSE:
+	case RT298_GET_MIC1_SENSE:
+	case RT298_PROC_COEF:
+	case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_MIC1, 0):
+	case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_SPK_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_HP_OUT, 0):
+		return true;
+	default:
+		return false;
+	}
+
+
+}
+
+static bool rt298_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0 ... 0xff:
+	case RT298_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID):
+	case RT298_GET_HP_SENSE:
+	case RT298_GET_MIC1_SENSE:
+	case RT298_SET_AUDIO_POWER:
+	case RT298_SET_HPO_POWER:
+	case RT298_SET_SPK_POWER:
+	case RT298_SET_DMIC1_POWER:
+	case RT298_SPK_MUX:
+	case RT298_HPO_MUX:
+	case RT298_ADC0_MUX:
+	case RT298_ADC1_MUX:
+	case RT298_SET_MIC1:
+	case RT298_SET_PIN_HPO:
+	case RT298_SET_PIN_SPK:
+	case RT298_SET_PIN_DMIC1:
+	case RT298_SPK_EAPD:
+	case RT298_SET_AMP_GAIN_HPO:
+	case RT298_SET_DMIC2_DEFAULT:
+	case RT298_DACL_GAIN:
+	case RT298_DACR_GAIN:
+	case RT298_ADCL_GAIN:
+	case RT298_ADCR_GAIN:
+	case RT298_MIC_GAIN:
+	case RT298_SPOL_GAIN:
+	case RT298_SPOR_GAIN:
+	case RT298_HPOL_GAIN:
+	case RT298_HPOR_GAIN:
+	case RT298_F_DAC_SWITCH:
+	case RT298_F_RECMIX_SWITCH:
+	case RT298_REC_MIC_SWITCH:
+	case RT298_REC_I2S_SWITCH:
+	case RT298_REC_LINE_SWITCH:
+	case RT298_REC_BEEP_SWITCH:
+	case RT298_DAC_FORMAT:
+	case RT298_ADC_FORMAT:
+	case RT298_COEF_INDEX:
+	case RT298_PROC_COEF:
+	case RT298_SET_AMP_GAIN_ADC_IN1:
+	case RT298_SET_AMP_GAIN_ADC_IN2:
+	case RT298_SET_POWER(RT298_DAC_OUT1):
+	case RT298_SET_POWER(RT298_DAC_OUT2):
+	case RT298_SET_POWER(RT298_ADC_IN1):
+	case RT298_SET_POWER(RT298_ADC_IN2):
+	case RT298_SET_POWER(RT298_DMIC2):
+	case RT298_SET_POWER(RT298_MIC1):
+	case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_MIC1, 0):
+	case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_SPK_OUT, 0):
+	case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_HP_OUT, 0):
+		return true;
+	default:
+		return false;
+	}
+}
+
+#ifdef CONFIG_PM
+static void rt298_index_sync(struct snd_soc_component *component)
+{
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
+	int i;
+
+	for (i = 0; i < INDEX_CACHE_SIZE; i++) {
+		snd_soc_component_write(component, rt298->index_cache[i].reg,
+				  rt298->index_cache[i].def);
+	}
+}
+#endif
+
+static int rt298_support_power_controls[] = {
+	RT298_DAC_OUT1,
+	RT298_DAC_OUT2,
+	RT298_ADC_IN1,
+	RT298_ADC_IN2,
+	RT298_MIC1,
+	RT298_DMIC1,
+	RT298_DMIC2,
+	RT298_SPK_OUT,
+	RT298_HP_OUT,
+};
+#define RT298_POWER_REG_LEN ARRAY_SIZE(rt298_support_power_controls)
+
+static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic)
+{
+	struct snd_soc_dapm_context *dapm;
+	unsigned int val, buf;
+
+	*hp = false;
+	*mic = false;
+
+	if (!rt298->component)
+		return -EINVAL;
+
+	dapm = snd_soc_component_get_dapm(rt298->component);
+
+	if (rt298->pdata.cbj_en) {
+		regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf);
+		*hp = buf & 0x80000000;
+		if (*hp == rt298->is_hp_in)
+			return -1;
+		rt298->is_hp_in = *hp;
+		if (*hp) {
+			/* power on HV,VERF */
+			regmap_update_bits(rt298->regmap,
+				RT298_DC_GAIN, 0x200, 0x200);
+
+			snd_soc_dapm_force_enable_pin(dapm, "HV");
+			snd_soc_dapm_force_enable_pin(dapm, "VREF");
+			/* power LDO1 */
+			snd_soc_dapm_force_enable_pin(dapm, "LDO1");
+			snd_soc_dapm_sync(dapm);
+
+			regmap_update_bits(rt298->regmap,
+				RT298_POWER_CTRL1, 0x1001, 0);
+			regmap_update_bits(rt298->regmap,
+				RT298_POWER_CTRL2, 0x4, 0x4);
+
+			regmap_write(rt298->regmap, RT298_SET_MIC1, 0x24);
+			msleep(50);
+
+			regmap_update_bits(rt298->regmap,
+				RT298_CBJ_CTRL1, 0xfcc0, 0xd400);
+			msleep(300);
+			regmap_read(rt298->regmap, RT298_CBJ_CTRL2, &val);
+
+			if (0x0070 == (val & 0x0070)) {
+				*mic = true;
+			} else {
+				regmap_update_bits(rt298->regmap,
+					RT298_CBJ_CTRL1, 0xfcc0, 0xe400);
+				msleep(300);
+				regmap_read(rt298->regmap,
+					RT298_CBJ_CTRL2, &val);
+				if (0x0070 == (val & 0x0070))
+					*mic = true;
+				else
+					*mic = false;
+			}
+			regmap_update_bits(rt298->regmap,
+				RT298_DC_GAIN, 0x200, 0x0);
+
+		} else {
+			*mic = false;
+			regmap_write(rt298->regmap, RT298_SET_MIC1, 0x20);
+			regmap_update_bits(rt298->regmap,
+				RT298_CBJ_CTRL1, 0x0400, 0x0000);
+		}
+	} else {
+		regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf);
+		*hp = buf & 0x80000000;
+		regmap_read(rt298->regmap, RT298_GET_MIC1_SENSE, &buf);
+		*mic = buf & 0x80000000;
+	}
+	if (!*mic) {
+		snd_soc_dapm_disable_pin(dapm, "HV");
+		snd_soc_dapm_disable_pin(dapm, "VREF");
+	}
+	if (!*hp)
+		snd_soc_dapm_disable_pin(dapm, "LDO1");
+	snd_soc_dapm_sync(dapm);
+
+	pr_debug("*hp = %d *mic = %d\n", *hp, *mic);
+
+	return 0;
+}
+
+static void rt298_jack_detect_work(struct work_struct *work)
+{
+	struct rt298_priv *rt298 =
+		container_of(work, struct rt298_priv, jack_detect_work.work);
+	int status = 0;
+	bool hp = false;
+	bool mic = false;
+
+	if (rt298_jack_detect(rt298, &hp, &mic) < 0)
+		return;
+
+	if (hp == true)
+		status |= SND_JACK_HEADPHONE;
+
+	if (mic == true)
+		status |= SND_JACK_MICROPHONE;
+
+	snd_soc_jack_report(rt298->jack, status,
+		SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+}
+
+int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
+{
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm;
+	bool hp = false;
+	bool mic = false;
+	int status = 0;
+
+	/* If jack in NULL, disable HS jack */
+	if (!jack) {
+		regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x0);
+		dapm = snd_soc_component_get_dapm(component);
+		snd_soc_dapm_disable_pin(dapm, "LDO1");
+		snd_soc_dapm_sync(dapm);
+		return 0;
+	}
+
+	rt298->jack = jack;
+	regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2);
+
+	rt298_jack_detect(rt298, &hp, &mic);
+	if (hp == true)
+		status |= SND_JACK_HEADPHONE;
+
+	if (mic == true)
+		status |= SND_JACK_MICROPHONE;
+
+	snd_soc_jack_report(rt298->jack, status,
+		SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt298_mic_detect);
+
+static int is_mclk_mode(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
+
+	if (rt298->clk_id == RT298_SCLK_S_MCLK)
+		return 1;
+	else
+		return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
+
+static const struct snd_kcontrol_new rt298_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT298_DACL_GAIN,
+			    RT298_DACR_GAIN, 0, 0x7f, 0, out_vol_tlv),
+	SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT298_ADCL_GAIN,
+			    RT298_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv),
+	SOC_SINGLE_TLV("AMIC Volume", RT298_MIC_GAIN,
+			    0, 0x3, 0, mic_vol_tlv),
+	SOC_DOUBLE_R("Speaker Playback Switch", RT298_SPOL_GAIN,
+			    RT298_SPOR_GAIN, RT298_MUTE_SFT, 1, 1),
+};
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt298_front_mix[] = {
+	SOC_DAPM_SINGLE("DAC Switch",  RT298_F_DAC_SWITCH,
+			RT298_MUTE_SFT, 1, 1),
+	SOC_DAPM_SINGLE("RECMIX Switch", RT298_F_RECMIX_SWITCH,
+			RT298_MUTE_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt298_rec_mix[] = {
+	SOC_DAPM_SINGLE("Mic1 Switch", RT298_REC_MIC_SWITCH,
+			RT298_MUTE_SFT, 1, 1),
+	SOC_DAPM_SINGLE("I2S Switch", RT298_REC_I2S_SWITCH,
+			RT298_MUTE_SFT, 1, 1),
+	SOC_DAPM_SINGLE("Line1 Switch", RT298_REC_LINE_SWITCH,
+			RT298_MUTE_SFT, 1, 1),
+	SOC_DAPM_SINGLE("Beep Switch", RT298_REC_BEEP_SWITCH,
+			RT298_MUTE_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new spo_enable_control =
+	SOC_DAPM_SINGLE("Switch", RT298_SET_PIN_SPK,
+			RT298_SET_PIN_SFT, 1, 0);
+
+static const struct snd_kcontrol_new hpol_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT298_HPOL_GAIN,
+			RT298_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpor_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT298_HPOR_GAIN,
+			RT298_MUTE_SFT, 1, 1);
+
+/* ADC0 source */
+static const char * const rt298_adc_src[] = {
+	"Mic", "RECMIX", "Dmic"
+};
+
+static const int rt298_adc_values[] = {
+	0, 4, 5,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(
+	rt298_adc0_enum, RT298_ADC0_MUX, RT298_ADC_SEL_SFT,
+	RT298_ADC_SEL_MASK, rt298_adc_src, rt298_adc_values);
+
+static const struct snd_kcontrol_new rt298_adc0_mux =
+	SOC_DAPM_ENUM("ADC 0 source", rt298_adc0_enum);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(
+	rt298_adc1_enum, RT298_ADC1_MUX, RT298_ADC_SEL_SFT,
+	RT298_ADC_SEL_MASK, rt298_adc_src, rt298_adc_values);
+
+static const struct snd_kcontrol_new rt298_adc1_mux =
+	SOC_DAPM_ENUM("ADC 1 source", rt298_adc1_enum);
+
+static const char * const rt298_dac_src[] = {
+	"Front", "Surround"
+};
+/* HP-OUT source */
+static SOC_ENUM_SINGLE_DECL(rt298_hpo_enum, RT298_HPO_MUX,
+				0, rt298_dac_src);
+
+static const struct snd_kcontrol_new rt298_hpo_mux =
+SOC_DAPM_ENUM("HPO source", rt298_hpo_enum);
+
+/* SPK-OUT source */
+static SOC_ENUM_SINGLE_DECL(rt298_spo_enum, RT298_SPK_MUX,
+				0, rt298_dac_src);
+
+static const struct snd_kcontrol_new rt298_spo_mux =
+SOC_DAPM_ENUM("SPO source", rt298_spo_enum);
+
+static int rt298_spk_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_write(component,
+			RT298_SPK_EAPD, RT298_SET_EAPD_HIGH);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_write(component,
+			RT298_SPK_EAPD, RT298_SET_EAPD_LOW);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt298_set_dmic1_event(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_write(component, RT298_SET_PIN_DMIC1, 0x20);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_write(component, RT298_SET_PIN_DMIC1, 0);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt298_adc_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	unsigned int nid;
+
+	nid = (w->reg >> 20) & 0xff;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component,
+			VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0),
+			0x7080, 0x7000);
+		 /* If MCLK doesn't exist, reset AD filter */
+		if (!(snd_soc_component_read32(component, RT298_VAD_CTRL) & 0x200)) {
+			pr_info("NO MCLK\n");
+			switch (nid) {
+			case RT298_ADC_IN1:
+				snd_soc_component_update_bits(component,
+					RT298_D_FILTER_CTRL, 0x2, 0x2);
+				mdelay(10);
+				snd_soc_component_update_bits(component,
+					RT298_D_FILTER_CTRL, 0x2, 0x0);
+				break;
+			case RT298_ADC_IN2:
+				snd_soc_component_update_bits(component,
+					RT298_D_FILTER_CTRL, 0x4, 0x4);
+				mdelay(10);
+				snd_soc_component_update_bits(component,
+					RT298_D_FILTER_CTRL, 0x4, 0x0);
+				break;
+			}
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component,
+			VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0),
+			0x7080, 0x7080);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt298_mic1_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component,
+			RT298_A_BIAS_CTRL3, 0xc000, 0x8000);
+		snd_soc_component_update_bits(component,
+			RT298_A_BIAS_CTRL2, 0xc000, 0x8000);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component,
+			RT298_A_BIAS_CTRL3, 0xc000, 0x0000);
+		snd_soc_component_update_bits(component,
+			RT298_A_BIAS_CTRL2, 0xc000, 0x0000);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt298_dapm_widgets[] = {
+
+	SND_SOC_DAPM_SUPPLY_S("HV", 1, RT298_POWER_CTRL1,
+		12, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VREF", RT298_POWER_CTRL1,
+		0, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("BG_MBIAS", 1, RT298_POWER_CTRL2,
+		1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT298_POWER_CTRL2,
+		2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("LDO2", 1, RT298_POWER_CTRL2,
+		3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("VREF1", 1, RT298_POWER_CTRL2,
+		4, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("LV", 2, RT298_POWER_CTRL1,
+		13, 1, NULL, 0),
+
+
+	SND_SOC_DAPM_SUPPLY("MCLK MODE", RT298_PLL_CTRL1,
+		5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MIC1 Input Buffer", SND_SOC_NOPM,
+		0, 0, rt298_mic1_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC1 Pin"),
+	SND_SOC_DAPM_INPUT("DMIC2 Pin"),
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("LINE1"),
+	SND_SOC_DAPM_INPUT("Beep"),
+
+	/* DMIC */
+	SND_SOC_DAPM_PGA_E("DMIC1", RT298_SET_POWER(RT298_DMIC1), 0, 1,
+		NULL, 0, rt298_set_dmic1_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA("DMIC2", RT298_SET_POWER(RT298_DMIC2), 0, 1,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC Receiver", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIX", SND_SOC_NOPM, 0, 0,
+		rt298_rec_mix, ARRAY_SIZE(rt298_rec_mix)),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC 0", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, 0, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX_E("ADC 0 Mux", RT298_SET_POWER(RT298_ADC_IN1), 0, 1,
+		&rt298_adc0_mux, rt298_adc_event, SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("ADC 1 Mux", RT298_SET_POWER(RT298_ADC_IN2), 0, 1,
+		&rt298_adc1_mux, rt298_adc_event, SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMU),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Side */
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC 0", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC 1", NULL, SND_SOC_NOPM, 0, 0),
+
+	/* Output Mux */
+	SND_SOC_DAPM_MUX("SPK Mux", SND_SOC_NOPM, 0, 0, &rt298_spo_mux),
+	SND_SOC_DAPM_MUX("HPO Mux", SND_SOC_NOPM, 0, 0, &rt298_hpo_mux),
+
+	SND_SOC_DAPM_SUPPLY("HP Power", RT298_SET_PIN_HPO,
+		RT298_SET_PIN_SFT, 0, NULL, 0),
+
+	/* Output Mixer */
+	SND_SOC_DAPM_MIXER("Front", RT298_SET_POWER(RT298_DAC_OUT1), 0, 1,
+			rt298_front_mix, ARRAY_SIZE(rt298_front_mix)),
+	SND_SOC_DAPM_PGA("Surround", RT298_SET_POWER(RT298_DAC_OUT2), 0, 1,
+			NULL, 0),
+
+	/* Output Pga */
+	SND_SOC_DAPM_SWITCH_E("SPO", SND_SOC_NOPM, 0, 0,
+		&spo_enable_control, rt298_spk_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SWITCH("HPO L", SND_SOC_NOPM, 0, 0,
+		&hpol_enable_control),
+	SND_SOC_DAPM_SWITCH("HPO R", SND_SOC_NOPM, 0, 0,
+		&hpor_enable_control),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("SPOL"),
+	SND_SOC_DAPM_OUTPUT("SPOR"),
+	SND_SOC_DAPM_OUTPUT("HPO Pin"),
+	SND_SOC_DAPM_OUTPUT("SPDIF"),
+};
+
+static const struct snd_soc_dapm_route rt298_dapm_routes[] = {
+
+	{"ADC 0", NULL, "MCLK MODE", is_mclk_mode},
+	{"ADC 1", NULL, "MCLK MODE", is_mclk_mode},
+	{"Front", NULL, "MCLK MODE", is_mclk_mode},
+	{"Surround", NULL, "MCLK MODE", is_mclk_mode},
+
+	{"HP Power", NULL, "LDO1"},
+	{"HP Power", NULL, "LDO2"},
+	{"HP Power", NULL, "LV"},
+	{"HP Power", NULL, "VREF1"},
+	{"HP Power", NULL, "BG_MBIAS"},
+
+	{"MIC1", NULL, "LDO1"},
+	{"MIC1", NULL, "LDO2"},
+	{"MIC1", NULL, "HV"},
+	{"MIC1", NULL, "LV"},
+	{"MIC1", NULL, "VREF"},
+	{"MIC1", NULL, "VREF1"},
+	{"MIC1", NULL, "BG_MBIAS"},
+	{"MIC1", NULL, "MIC1 Input Buffer"},
+
+	{"SPO", NULL, "LDO1"},
+	{"SPO", NULL, "LDO2"},
+	{"SPO", NULL, "HV"},
+	{"SPO", NULL, "LV"},
+	{"SPO", NULL, "VREF"},
+	{"SPO", NULL, "VREF1"},
+	{"SPO", NULL, "BG_MBIAS"},
+
+	{"DMIC1", NULL, "DMIC1 Pin"},
+	{"DMIC2", NULL, "DMIC2 Pin"},
+	{"DMIC1", NULL, "DMIC Receiver"},
+	{"DMIC2", NULL, "DMIC Receiver"},
+
+	{"RECMIX", "Beep Switch", "Beep"},
+	{"RECMIX", "Line1 Switch", "LINE1"},
+	{"RECMIX", "Mic1 Switch", "MIC1"},
+
+	{"ADC 0 Mux", "Dmic", "DMIC1"},
+	{"ADC 0 Mux", "RECMIX", "RECMIX"},
+	{"ADC 0 Mux", "Mic", "MIC1"},
+	{"ADC 1 Mux", "Dmic", "DMIC2"},
+	{"ADC 1 Mux", "RECMIX", "RECMIX"},
+	{"ADC 1 Mux", "Mic", "MIC1"},
+
+	{"ADC 0", NULL, "ADC 0 Mux"},
+	{"ADC 1", NULL, "ADC 1 Mux"},
+
+	{"AIF1TX", NULL, "ADC 0"},
+	{"AIF2TX", NULL, "ADC 1"},
+
+	{"DAC 0", NULL, "AIF1RX"},
+	{"DAC 1", NULL, "AIF2RX"},
+
+	{"Front", "DAC Switch", "DAC 0"},
+	{"Front", "RECMIX Switch", "RECMIX"},
+
+	{"Surround", NULL, "DAC 1"},
+
+	{"SPK Mux", "Front", "Front"},
+	{"SPK Mux", "Surround", "Surround"},
+
+	{"HPO Mux", "Front", "Front"},
+	{"HPO Mux", "Surround", "Surround"},
+
+	{"SPO", "Switch", "SPK Mux"},
+	{"HPO L", "Switch", "HPO Mux"},
+	{"HPO R", "Switch", "HPO Mux"},
+	{"HPO L", NULL, "HP Power"},
+	{"HPO R", NULL, "HP Power"},
+
+	{"SPOL", NULL, "SPO"},
+	{"SPOR", NULL, "SPO"},
+	{"HPO Pin", NULL, "HPO L"},
+	{"HPO Pin", NULL, "HPO R"},
+};
+
+static int rt298_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
+	unsigned int val = 0;
+	int d_len_code;
+
+	switch (params_rate(params)) {
+	/* bit 14 0:48K 1:44.1K */
+	case 44100:
+	case 48000:
+		break;
+	default:
+		dev_err(component->dev, "Unsupported sample rate %d\n",
+					params_rate(params));
+		return -EINVAL;
+	}
+	switch (rt298->sys_clk) {
+	case 12288000:
+	case 24576000:
+		if (params_rate(params) != 48000) {
+			dev_err(component->dev, "Sys_clk is not matched (%d %d)\n",
+					params_rate(params), rt298->sys_clk);
+			return -EINVAL;
+		}
+		break;
+	case 11289600:
+	case 22579200:
+		if (params_rate(params) != 44100) {
+			dev_err(component->dev, "Sys_clk is not matched (%d %d)\n",
+					params_rate(params), rt298->sys_clk);
+			return -EINVAL;
+		}
+		break;
+	}
+
+	if (params_channels(params) <= 16) {
+		/* bit 3:0 Number of Channel */
+		val |= (params_channels(params) - 1);
+	} else {
+		dev_err(component->dev, "Unsupported channels %d\n",
+					params_channels(params));
+		return -EINVAL;
+	}
+
+	d_len_code = 0;
+	switch (params_width(params)) {
+	/* bit 6:4 Bits per Sample */
+	case 16:
+		d_len_code = 0;
+		val |= (0x1 << 4);
+		break;
+	case 32:
+		d_len_code = 2;
+		val |= (0x4 << 4);
+		break;
+	case 20:
+		d_len_code = 1;
+		val |= (0x2 << 4);
+		break;
+	case 24:
+		d_len_code = 2;
+		val |= (0x3 << 4);
+		break;
+	case 8:
+		d_len_code = 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component,
+		RT298_I2S_CTRL1, 0x0018, d_len_code << 3);
+	dev_dbg(component->dev, "format val = 0x%x\n", val);
+
+	snd_soc_component_update_bits(component, RT298_DAC_FORMAT, 0x407f, val);
+	snd_soc_component_update_bits(component, RT298_ADC_FORMAT, 0x407f, val);
+
+	return 0;
+}
+
+static int rt298_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		snd_soc_component_update_bits(component,
+			RT298_I2S_CTRL1, 0x800, 0x800);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		snd_soc_component_update_bits(component,
+			RT298_I2S_CTRL1, 0x800, 0x0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		snd_soc_component_update_bits(component,
+			RT298_I2S_CTRL1, 0x300, 0x0);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		snd_soc_component_update_bits(component,
+			RT298_I2S_CTRL1, 0x300, 0x1 << 8);
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		snd_soc_component_update_bits(component,
+			RT298_I2S_CTRL1, 0x300, 0x2 << 8);
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		snd_soc_component_update_bits(component,
+			RT298_I2S_CTRL1, 0x300, 0x3 << 8);
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* bit 15 Stream Type 0:PCM 1:Non-PCM */
+	snd_soc_component_update_bits(component, RT298_DAC_FORMAT, 0x8000, 0);
+	snd_soc_component_update_bits(component, RT298_ADC_FORMAT, 0x8000, 0);
+
+	return 0;
+}
+
+static int rt298_set_dai_sysclk(struct snd_soc_dai *dai,
+				int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "%s freq=%d\n", __func__, freq);
+
+	if (RT298_SCLK_S_MCLK == clk_id) {
+		snd_soc_component_update_bits(component,
+			RT298_I2S_CTRL2, 0x0100, 0x0);
+		snd_soc_component_update_bits(component,
+			RT298_PLL_CTRL1, 0x20, 0x20);
+	} else {
+		snd_soc_component_update_bits(component,
+			RT298_I2S_CTRL2, 0x0100, 0x0100);
+		snd_soc_component_update_bits(component,
+			RT298_PLL_CTRL1, 0x20, 0x0);
+	}
+
+	switch (freq) {
+	case 19200000:
+		if (RT298_SCLK_S_MCLK == clk_id) {
+			dev_err(component->dev, "Should not use MCLK\n");
+			return -EINVAL;
+		}
+		snd_soc_component_update_bits(component,
+			RT298_I2S_CTRL2, 0x40, 0x40);
+		break;
+	case 24000000:
+		if (RT298_SCLK_S_MCLK == clk_id) {
+			dev_err(component->dev, "Should not use MCLK\n");
+			return -EINVAL;
+		}
+		snd_soc_component_update_bits(component,
+			RT298_I2S_CTRL2, 0x40, 0x0);
+		break;
+	case 12288000:
+	case 11289600:
+		snd_soc_component_update_bits(component,
+			RT298_I2S_CTRL2, 0x8, 0x0);
+		snd_soc_component_update_bits(component,
+			RT298_CLK_DIV, 0xfc1e, 0x0004);
+		break;
+	case 24576000:
+	case 22579200:
+		snd_soc_component_update_bits(component,
+			RT298_I2S_CTRL2, 0x8, 0x8);
+		snd_soc_component_update_bits(component,
+			RT298_CLK_DIV, 0xfc1e, 0x5406);
+		break;
+	default:
+		dev_err(component->dev, "Unsupported system clock\n");
+		return -EINVAL;
+	}
+
+	rt298->sys_clk = freq;
+	rt298->clk_id = clk_id;
+
+	return 0;
+}
+
+static int rt298_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct snd_soc_component *component = dai->component;
+
+	dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
+	if (50 == ratio)
+		snd_soc_component_update_bits(component,
+			RT298_I2S_CTRL1, 0x1000, 0x1000);
+	else
+		snd_soc_component_update_bits(component,
+			RT298_I2S_CTRL1, 0x1000, 0x0);
+
+
+	return 0;
+}
+
+static int rt298_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		if (SND_SOC_BIAS_STANDBY ==
+			snd_soc_component_get_bias_level(component)) {
+			snd_soc_component_write(component,
+				RT298_SET_AUDIO_POWER, AC_PWRST_D0);
+			snd_soc_component_update_bits(component, 0x0d, 0x200, 0x200);
+			snd_soc_component_update_bits(component, 0x52, 0x80, 0x0);
+			mdelay(20);
+			snd_soc_component_update_bits(component, 0x0d, 0x200, 0x0);
+			snd_soc_component_update_bits(component, 0x52, 0x80, 0x80);
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_component_write(component,
+			RT298_SET_AUDIO_POWER, AC_PWRST_D3);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static irqreturn_t rt298_irq(int irq, void *data)
+{
+	struct rt298_priv *rt298 = data;
+	bool hp = false;
+	bool mic = false;
+	int ret, status = 0;
+
+	ret = rt298_jack_detect(rt298, &hp, &mic);
+
+	/* Clear IRQ */
+	regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x1, 0x1);
+
+	if (ret == 0) {
+		if (hp == true)
+			status |= SND_JACK_HEADPHONE;
+
+		if (mic == true)
+			status |= SND_JACK_MICROPHONE;
+
+		snd_soc_jack_report(rt298->jack, status,
+			SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+
+		pm_wakeup_event(&rt298->i2c->dev, 300);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int rt298_probe(struct snd_soc_component *component)
+{
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
+
+	rt298->component = component;
+
+	if (rt298->i2c->irq) {
+		regmap_update_bits(rt298->regmap,
+					RT298_IRQ_CTRL, 0x2, 0x2);
+
+		INIT_DELAYED_WORK(&rt298->jack_detect_work,
+					rt298_jack_detect_work);
+		schedule_delayed_work(&rt298->jack_detect_work,
+					msecs_to_jiffies(1250));
+	}
+
+	return 0;
+}
+
+static void rt298_remove(struct snd_soc_component *component)
+{
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
+
+	cancel_delayed_work_sync(&rt298->jack_detect_work);
+}
+
+#ifdef CONFIG_PM
+static int rt298_suspend(struct snd_soc_component *component)
+{
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
+
+	rt298->is_hp_in = -1;
+	regcache_cache_only(rt298->regmap, true);
+	regcache_mark_dirty(rt298->regmap);
+
+	return 0;
+}
+
+static int rt298_resume(struct snd_soc_component *component)
+{
+	struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt298->regmap, false);
+	rt298_index_sync(component);
+	regcache_sync(rt298->regmap);
+
+	return 0;
+}
+#else
+#define rt298_suspend NULL
+#define rt298_resume NULL
+#endif
+
+#define RT298_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define RT298_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt298_aif_dai_ops = {
+	.hw_params = rt298_hw_params,
+	.set_fmt = rt298_set_dai_fmt,
+	.set_sysclk = rt298_set_dai_sysclk,
+	.set_bclk_ratio = rt298_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt298_dai[] = {
+	{
+		.name = "rt298-aif1",
+		.id = RT298_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT298_STEREO_RATES,
+			.formats = RT298_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT298_STEREO_RATES,
+			.formats = RT298_FORMATS,
+		},
+		.ops = &rt298_aif_dai_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "rt298-aif2",
+		.id = RT298_AIF2,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT298_STEREO_RATES,
+			.formats = RT298_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT298_STEREO_RATES,
+			.formats = RT298_FORMATS,
+		},
+		.ops = &rt298_aif_dai_ops,
+		.symmetric_rates = 1,
+	},
+
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt298 = {
+	.probe			= rt298_probe,
+	.remove			= rt298_remove,
+	.suspend		= rt298_suspend,
+	.resume			= rt298_resume,
+	.set_bias_level		= rt298_set_bias_level,
+	.controls		= rt298_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt298_snd_controls),
+	.dapm_widgets		= rt298_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt298_dapm_widgets),
+	.dapm_routes		= rt298_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt298_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt298_regmap = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.max_register = 0x02370100,
+	.volatile_reg = rt298_volatile_register,
+	.readable_reg = rt298_readable_register,
+	.reg_write = rl6347a_hw_write,
+	.reg_read = rl6347a_hw_read,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt298_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt298_reg),
+};
+
+static const struct i2c_device_id rt298_i2c_id[] = {
+	{"rt298", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, rt298_i2c_id);
+
+static const struct acpi_device_id rt298_acpi_match[] = {
+	{ "INT343A", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, rt298_acpi_match);
+
+static const struct dmi_system_id force_combo_jack_table[] = {
+	{
+		.ident = "Intel Broxton P",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Broxton P")
+		}
+	},
+	{
+		.ident = "Intel Gemini Lake",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Geminilake")
+		}
+	},
+	{ }
+};
+
+static int rt298_i2c_probe(struct i2c_client *i2c,
+			   const struct i2c_device_id *id)
+{
+	struct rt298_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt298_priv *rt298;
+	struct device *dev = &i2c->dev;
+	const struct acpi_device_id *acpiid;
+	int i, ret;
+
+	rt298 = devm_kzalloc(&i2c->dev,	sizeof(*rt298),
+				GFP_KERNEL);
+	if (NULL == rt298)
+		return -ENOMEM;
+
+	rt298->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt298_regmap);
+	if (IS_ERR(rt298->regmap)) {
+		ret = PTR_ERR(rt298->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt298->regmap,
+		RT298_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &ret);
+	if (ret != RT298_VENDOR_ID) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt298\n", ret);
+		return -ENODEV;
+	}
+
+	rt298->index_cache = devm_kmemdup(&i2c->dev, rt298_index_def,
+					  sizeof(rt298_index_def), GFP_KERNEL);
+	if (!rt298->index_cache)
+		return -ENOMEM;
+
+	rt298->index_cache_size = INDEX_CACHE_SIZE;
+	rt298->i2c = i2c;
+	i2c_set_clientdata(i2c, rt298);
+
+	/* restore codec default */
+	for (i = 0; i < INDEX_CACHE_SIZE; i++)
+		regmap_write(rt298->regmap, rt298->index_cache[i].reg,
+				rt298->index_cache[i].def);
+	for (i = 0; i < ARRAY_SIZE(rt298_reg); i++)
+		regmap_write(rt298->regmap, rt298_reg[i].reg,
+				rt298_reg[i].def);
+
+	if (pdata)
+		rt298->pdata = *pdata;
+
+	/* enable jack combo mode on supported devices */
+	acpiid = acpi_match_device(dev->driver->acpi_match_table, dev);
+	if (acpiid && acpiid->driver_data) {
+		rt298->pdata = *(struct rt298_platform_data *)
+				acpiid->driver_data;
+	}
+
+	if (dmi_check_system(force_combo_jack_table)) {
+		rt298->pdata.cbj_en = true;
+		rt298->pdata.gpio2_en = false;
+	}
+
+	/* VREF Charging */
+	regmap_update_bits(rt298->regmap, 0x04, 0x80, 0x80);
+	regmap_update_bits(rt298->regmap, 0x1b, 0x860, 0x860);
+	/* Vref2 */
+	regmap_update_bits(rt298->regmap, 0x08, 0x20, 0x20);
+
+	regmap_write(rt298->regmap, RT298_SET_AUDIO_POWER, AC_PWRST_D3);
+
+	for (i = 0; i < RT298_POWER_REG_LEN; i++)
+		regmap_write(rt298->regmap,
+			RT298_SET_POWER(rt298_support_power_controls[i]),
+			AC_PWRST_D1);
+
+	if (!rt298->pdata.cbj_en) {
+		regmap_write(rt298->regmap, RT298_CBJ_CTRL2, 0x0000);
+		regmap_write(rt298->regmap, RT298_MIC1_DET_CTRL, 0x0816);
+		regmap_update_bits(rt298->regmap,
+					RT298_CBJ_CTRL1, 0xf000, 0xb000);
+	} else {
+		regmap_update_bits(rt298->regmap,
+					RT298_CBJ_CTRL1, 0xf000, 0x5000);
+	}
+
+	mdelay(10);
+
+	if (!rt298->pdata.gpio2_en)
+		regmap_write(rt298->regmap, RT298_SET_DMIC2_DEFAULT, 0x40);
+	else
+		regmap_write(rt298->regmap, RT298_SET_DMIC2_DEFAULT, 0);
+
+	mdelay(10);
+
+	regmap_write(rt298->regmap, RT298_MISC_CTRL1, 0x0000);
+	regmap_update_bits(rt298->regmap,
+				RT298_WIND_FILTER_CTRL, 0x0082, 0x0082);
+
+	regmap_write(rt298->regmap, RT298_UNSOLICITED_INLINE_CMD, 0x81);
+	regmap_write(rt298->regmap, RT298_UNSOLICITED_HP_OUT, 0x82);
+	regmap_write(rt298->regmap, RT298_UNSOLICITED_MIC1, 0x84);
+	regmap_update_bits(rt298->regmap, RT298_IRQ_FLAG_CTRL, 0x2, 0x2);
+
+	rt298->is_hp_in = -1;
+
+	if (rt298->i2c->irq) {
+		ret = request_threaded_irq(rt298->i2c->irq, NULL, rt298_irq,
+			IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt298", rt298);
+		if (ret != 0) {
+			dev_err(&i2c->dev,
+				"Failed to reguest IRQ: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_rt298,
+				     rt298_dai, ARRAY_SIZE(rt298_dai));
+
+	return ret;
+}
+
+static int rt298_i2c_remove(struct i2c_client *i2c)
+{
+	struct rt298_priv *rt298 = i2c_get_clientdata(i2c);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, rt298);
+
+	return 0;
+}
+
+
+static struct i2c_driver rt298_i2c_driver = {
+	.driver = {
+		   .name = "rt298",
+		   .acpi_match_table = ACPI_PTR(rt298_acpi_match),
+		   },
+	.probe = rt298_i2c_probe,
+	.remove = rt298_i2c_remove,
+	.id_table = rt298_i2c_id,
+};
+
+module_i2c_driver(rt298_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT298 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt298.h b/sound/soc/codecs/rt298.h
new file mode 100644
index 0000000..b4db935
--- /dev/null
+++ b/sound/soc/codecs/rt298.h
@@ -0,0 +1,216 @@
+/*
+ * rt298.h  --  RT298 ALSA SoC audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ * Author: Johnny Hsu <johnnyhsu@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT298_H__
+#define __RT298_H__
+
+#define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D)
+
+#define RT298_AUDIO_FUNCTION_GROUP			0x01
+#define RT298_DAC_OUT1					0x02
+#define RT298_DAC_OUT2					0x03
+#define RT298_DIG_CVT					0x06
+#define RT298_ADC_IN1					0x09
+#define RT298_ADC_IN2					0x08
+#define RT298_MIXER_IN					0x0b
+#define RT298_MIXER_OUT1				0x0c
+#define RT298_MIXER_OUT2				0x0d
+#define RT298_DMIC1					0x12
+#define RT298_DMIC2					0x13
+#define RT298_SPK_OUT					0x14
+#define RT298_MIC1					0x18
+#define RT298_LINE1					0x1a
+#define RT298_BEEP					0x1d
+#define RT298_SPDIF					0x1e
+#define RT298_VENDOR_REGISTERS				0x20
+#define RT298_HP_OUT					0x21
+#define RT298_MIXER_IN1					0x22
+#define RT298_MIXER_IN2					0x23
+#define RT298_INLINE_CMD				0x55
+
+#define RT298_SET_PIN_SFT				6
+#define RT298_SET_PIN_ENABLE				0x40
+#define RT298_SET_PIN_DISABLE				0
+#define RT298_SET_EAPD_HIGH				0x2
+#define RT298_SET_EAPD_LOW				0
+
+#define RT298_MUTE_SFT					7
+
+/* Verb commands */
+#define RT298_GET_PARAM(NID, PARAM) VERB_CMD(AC_VERB_PARAMETERS, NID, PARAM)
+#define RT298_SET_POWER(NID) VERB_CMD(AC_VERB_SET_POWER_STATE, NID, 0)
+#define RT298_SET_AUDIO_POWER RT298_SET_POWER(RT298_AUDIO_FUNCTION_GROUP)
+#define RT298_SET_HPO_POWER RT298_SET_POWER(RT298_HP_OUT)
+#define RT298_SET_SPK_POWER RT298_SET_POWER(RT298_SPK_OUT)
+#define RT298_SET_DMIC1_POWER RT298_SET_POWER(RT298_DMIC1)
+#define RT298_SPK_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_SPK_OUT, 0)
+#define RT298_HPO_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_HP_OUT, 0)
+#define RT298_ADC0_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_MIXER_IN1, 0)
+#define RT298_ADC1_MUX\
+	VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_MIXER_IN2, 0)
+#define RT298_SET_MIC1\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_MIC1, 0)
+#define RT298_SET_PIN_HPO\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_HP_OUT, 0)
+#define RT298_SET_PIN_SPK\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_SPK_OUT, 0)
+#define RT298_SET_PIN_DMIC1\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_DMIC1, 0)
+#define RT298_SET_PIN_SPDIF\
+	VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_SPDIF, 0)
+#define RT298_SET_PIN_DIG_CVT\
+	VERB_CMD(AC_VERB_SET_DIGI_CONVERT_1, RT298_DIG_CVT, 0)
+#define RT298_SPK_EAPD\
+	VERB_CMD(AC_VERB_SET_EAPD_BTLENABLE, RT298_SPK_OUT, 0)
+#define RT298_SET_AMP_GAIN_HPO\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_HP_OUT, 0)
+#define RT298_SET_AMP_GAIN_ADC_IN1\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN1, 0)
+#define RT298_SET_AMP_GAIN_ADC_IN2\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN2, 0)
+#define RT298_GET_HP_SENSE\
+	VERB_CMD(AC_VERB_GET_PIN_SENSE, RT298_HP_OUT, 0)
+#define RT298_GET_MIC1_SENSE\
+	VERB_CMD(AC_VERB_GET_PIN_SENSE, RT298_MIC1, 0)
+#define RT298_SET_DMIC2_DEFAULT\
+	VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT298_DMIC2, 0)
+#define RT298_SET_SPDIF_DEFAULT\
+	VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT298_SPDIF, 0)
+#define RT298_DACL_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_DAC_OUT1, 0xa000)
+#define RT298_DACR_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_DAC_OUT1, 0x9000)
+#define RT298_ADCL_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN1, 0x6000)
+#define RT298_ADCR_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN1, 0x5000)
+#define RT298_MIC_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIC1, 0x7000)
+#define RT298_SPOL_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_SPK_OUT, 0xa000)
+#define RT298_SPOR_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_SPK_OUT, 0x9000)
+#define RT298_HPOL_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_HP_OUT, 0xa000)
+#define RT298_HPOR_GAIN\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_HP_OUT, 0x9000)
+#define RT298_F_DAC_SWITCH\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_OUT1, 0x7000)
+#define RT298_F_RECMIX_SWITCH\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_OUT1, 0x7100)
+#define RT298_REC_MIC_SWITCH\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7000)
+#define RT298_REC_I2S_SWITCH\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7100)
+#define RT298_REC_LINE_SWITCH\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7200)
+#define RT298_REC_BEEP_SWITCH\
+	VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7300)
+#define RT298_DAC_FORMAT\
+	VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT298_DAC_OUT1, 0)
+#define RT298_ADC_FORMAT\
+	VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT298_ADC_IN1, 0)
+#define RT298_COEF_INDEX\
+	VERB_CMD(AC_VERB_SET_COEF_INDEX, RT298_VENDOR_REGISTERS, 0)
+#define RT298_PROC_COEF\
+	VERB_CMD(AC_VERB_SET_PROC_COEF, RT298_VENDOR_REGISTERS, 0)
+#define RT298_UNSOLICITED_INLINE_CMD\
+	VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT298_INLINE_CMD, 0)
+#define RT298_UNSOLICITED_HP_OUT\
+	VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT298_HP_OUT, 0)
+#define RT298_UNSOLICITED_MIC1\
+	VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT298_MIC1, 0)
+
+/* Index registers */
+#define RT298_A_BIAS_CTRL1	0x01
+#define RT298_A_BIAS_CTRL2	0x02
+#define RT298_POWER_CTRL1	0x03
+#define RT298_A_BIAS_CTRL3	0x04
+#define RT298_D_FILTER_CTRL	0x05
+#define RT298_POWER_CTRL2	0x08
+#define RT298_I2S_CTRL1		0x09
+#define RT298_I2S_CTRL2		0x0a
+#define RT298_CLK_DIV		0x0b
+#define RT298_DC_GAIN		0x0d
+#define RT298_POWER_CTRL3	0x0f
+#define RT298_MIC1_DET_CTRL	0x19
+#define RT298_MISC_CTRL1	0x20
+#define RT298_IRQ_CTRL		0x33
+#define RT298_WIND_FILTER_CTRL	0x46
+#define RT298_PLL_CTRL1		0x49
+#define RT298_VAD_CTRL		0x4e
+#define RT298_CBJ_CTRL1		0x4f
+#define RT298_CBJ_CTRL2		0x50
+#define RT298_PLL_CTRL		0x63
+#define RT298_DEPOP_CTRL1	0x66
+#define RT298_DEPOP_CTRL2	0x67
+#define RT298_DEPOP_CTRL3	0x68
+#define RT298_DEPOP_CTRL4	0x69
+#define RT298_IRQ_FLAG_CTRL	0x7c
+
+/* SPDIF (0x06) */
+#define RT298_SPDIF_SEL_SFT	0
+#define RT298_SPDIF_SEL_PCM0	0
+#define RT298_SPDIF_SEL_PCM1	1
+#define RT298_SPDIF_SEL_SPOUT	2
+#define RT298_SPDIF_SEL_PP	3
+
+/* RECMIX (0x0b) */
+#define RT298_M_REC_BEEP_SFT	0
+#define RT298_M_REC_LINE1_SFT	1
+#define RT298_M_REC_MIC1_SFT	2
+#define RT298_M_REC_I2S_SFT	3
+
+/* Front (0x0c) */
+#define RT298_M_FRONT_DAC_SFT	0
+#define RT298_M_FRONT_REC_SFT	1
+
+/* SPK-OUT (0x14) */
+#define RT298_M_SPK_MUX_SFT	14
+#define RT298_SPK_SEL_MASK	0x1
+#define RT298_SPK_SEL_SFT	0
+#define RT298_SPK_SEL_F		0
+#define RT298_SPK_SEL_S		1
+
+/* HP-OUT (0x21) */
+#define RT298_M_HP_MUX_SFT	14
+#define RT298_HP_SEL_MASK	0x1
+#define RT298_HP_SEL_SFT	0
+#define RT298_HP_SEL_F		0
+#define RT298_HP_SEL_S		1
+
+/* ADC (0x22) (0x23) */
+#define RT298_ADC_SEL_MASK	0x7
+#define RT298_ADC_SEL_SFT	0
+#define RT298_ADC_SEL_SURR	0
+#define RT298_ADC_SEL_FRONT	1
+#define RT298_ADC_SEL_DMIC	2
+#define RT298_ADC_SEL_BEEP	4
+#define RT298_ADC_SEL_LINE1	5
+#define RT298_ADC_SEL_I2S	6
+#define RT298_ADC_SEL_MIC1	7
+
+#define RT298_SCLK_S_MCLK	0
+#define RT298_SCLK_S_PLL	1
+
+enum {
+	RT298_AIF1,
+	RT298_AIF2,
+	RT298_AIFS,
+};
+
+int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack);
+
+#endif /* __RT298_H__ */
+
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
new file mode 100644
index 0000000..6478d10
--- /dev/null
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -0,0 +1,515 @@
+/*
+ * rt5514-spi.c  --  RT5514 SPI driver
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/spi/spi.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_qos.h>
+#include <linux/sysfs.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rt5514-spi.h"
+
+#define DRV_NAME "rt5514-spi"
+
+static struct spi_device *rt5514_spi;
+
+struct rt5514_dsp {
+	struct device *dev;
+	struct delayed_work copy_work;
+	struct mutex dma_lock;
+	struct snd_pcm_substream *substream;
+	unsigned int buf_base, buf_limit, buf_rp;
+	size_t buf_size, get_size, dma_offset;
+};
+
+static const struct snd_pcm_hardware rt5514_spi_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.period_bytes_min	= PAGE_SIZE,
+	.period_bytes_max	= 0x20000 / 8,
+	.periods_min		= 8,
+	.periods_max		= 8,
+	.channels_min		= 1,
+	.channels_max		= 1,
+	.buffer_bytes_max	= 0x20000,
+};
+
+static struct snd_soc_dai_driver rt5514_spi_dai = {
+	.name = "rt5514-dsp-cpu-dai",
+	.id = 0,
+	.capture = {
+		.stream_name = "DSP Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+};
+
+static void rt5514_spi_copy_work(struct work_struct *work)
+{
+	struct rt5514_dsp *rt5514_dsp =
+		container_of(work, struct rt5514_dsp, copy_work.work);
+	struct snd_pcm_runtime *runtime;
+	size_t period_bytes, truncated_bytes = 0;
+	unsigned int cur_wp, remain_data;
+	u8 buf[8];
+
+	mutex_lock(&rt5514_dsp->dma_lock);
+	if (!rt5514_dsp->substream) {
+		dev_err(rt5514_dsp->dev, "No pcm substream\n");
+		goto done;
+	}
+
+	runtime = rt5514_dsp->substream->runtime;
+	period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream);
+
+	if (rt5514_dsp->get_size >= rt5514_dsp->buf_size) {
+		rt5514_spi_burst_read(RT5514_BUFFER_VOICE_WP, (u8 *)&buf,
+			sizeof(buf));
+		cur_wp = buf[0] | buf[1] << 8 | buf[2] << 16 |
+					buf[3] << 24;
+
+		if (cur_wp >= rt5514_dsp->buf_rp)
+			remain_data = (cur_wp - rt5514_dsp->buf_rp);
+		else
+			remain_data =
+				(rt5514_dsp->buf_limit - rt5514_dsp->buf_rp) +
+				(cur_wp - rt5514_dsp->buf_base);
+
+		if (remain_data < period_bytes) {
+			schedule_delayed_work(&rt5514_dsp->copy_work, 5);
+			goto done;
+		}
+	}
+
+	if (rt5514_dsp->buf_rp + period_bytes <= rt5514_dsp->buf_limit) {
+		rt5514_spi_burst_read(rt5514_dsp->buf_rp,
+			runtime->dma_area + rt5514_dsp->dma_offset,
+			period_bytes);
+
+		if (rt5514_dsp->buf_rp + period_bytes == rt5514_dsp->buf_limit)
+			rt5514_dsp->buf_rp = rt5514_dsp->buf_base;
+		else
+			rt5514_dsp->buf_rp += period_bytes;
+	} else {
+		truncated_bytes = rt5514_dsp->buf_limit - rt5514_dsp->buf_rp;
+		rt5514_spi_burst_read(rt5514_dsp->buf_rp,
+			runtime->dma_area + rt5514_dsp->dma_offset,
+			truncated_bytes);
+
+		rt5514_spi_burst_read(rt5514_dsp->buf_base,
+			runtime->dma_area + rt5514_dsp->dma_offset +
+			truncated_bytes, period_bytes - truncated_bytes);
+
+		rt5514_dsp->buf_rp = rt5514_dsp->buf_base + period_bytes -
+			truncated_bytes;
+	}
+
+	rt5514_dsp->get_size += period_bytes;
+	rt5514_dsp->dma_offset += period_bytes;
+	if (rt5514_dsp->dma_offset >= runtime->dma_bytes)
+		rt5514_dsp->dma_offset = 0;
+
+	snd_pcm_period_elapsed(rt5514_dsp->substream);
+
+	schedule_delayed_work(&rt5514_dsp->copy_work, 5);
+
+done:
+	mutex_unlock(&rt5514_dsp->dma_lock);
+}
+
+static void rt5514_schedule_copy(struct rt5514_dsp *rt5514_dsp)
+{
+	size_t period_bytes;
+	u8 buf[8];
+
+	if (!rt5514_dsp->substream)
+		return;
+
+	period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream);
+	rt5514_dsp->get_size = 0;
+
+	/**
+	 * The address area x1800XXXX is the register address, and it cannot
+	 * support spi burst read perfectly. So we use the spi burst read
+	 * individually to make sure the data correctly.
+	 */
+	rt5514_spi_burst_read(RT5514_BUFFER_VOICE_BASE, (u8 *)&buf,
+		sizeof(buf));
+	rt5514_dsp->buf_base = buf[0] | buf[1] << 8 | buf[2] << 16 |
+				buf[3] << 24;
+
+	rt5514_spi_burst_read(RT5514_BUFFER_VOICE_LIMIT, (u8 *)&buf,
+		sizeof(buf));
+	rt5514_dsp->buf_limit = buf[0] | buf[1] << 8 | buf[2] << 16 |
+				buf[3] << 24;
+
+	rt5514_spi_burst_read(RT5514_BUFFER_VOICE_WP, (u8 *)&buf,
+		sizeof(buf));
+	rt5514_dsp->buf_rp = buf[0] | buf[1] << 8 | buf[2] << 16 |
+				buf[3] << 24;
+
+	if (rt5514_dsp->buf_rp % 8)
+		rt5514_dsp->buf_rp = (rt5514_dsp->buf_rp / 8) * 8;
+
+	rt5514_dsp->buf_size = rt5514_dsp->buf_limit - rt5514_dsp->buf_base;
+
+	if (rt5514_dsp->buf_size % period_bytes)
+		rt5514_dsp->buf_size = (rt5514_dsp->buf_size / period_bytes) *
+			period_bytes;
+
+	if (rt5514_dsp->buf_base && rt5514_dsp->buf_limit &&
+		rt5514_dsp->buf_rp && rt5514_dsp->buf_size)
+		schedule_delayed_work(&rt5514_dsp->copy_work, 0);
+}
+
+static irqreturn_t rt5514_spi_irq(int irq, void *data)
+{
+	struct rt5514_dsp *rt5514_dsp = data;
+
+	rt5514_schedule_copy(rt5514_dsp);
+
+	return IRQ_HANDLED;
+}
+
+/* PCM for streaming audio from the DSP buffer */
+static int rt5514_spi_pcm_open(struct snd_pcm_substream *substream)
+{
+	snd_soc_set_runtime_hwparams(substream, &rt5514_spi_pcm_hardware);
+
+	return 0;
+}
+
+static int rt5514_spi_hw_params(struct snd_pcm_substream *substream,
+			       struct snd_pcm_hw_params *hw_params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct rt5514_dsp *rt5514_dsp =
+		snd_soc_component_get_drvdata(component);
+	int ret;
+	u8 buf[8];
+
+	mutex_lock(&rt5514_dsp->dma_lock);
+	ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+			params_buffer_bytes(hw_params));
+	rt5514_dsp->substream = substream;
+	rt5514_dsp->dma_offset = 0;
+
+	/* Read IRQ status and schedule copy accordingly. */
+	rt5514_spi_burst_read(RT5514_IRQ_CTRL, (u8 *)&buf, sizeof(buf));
+	if (buf[0] & RT5514_IRQ_STATUS_BIT)
+		rt5514_schedule_copy(rt5514_dsp);
+
+	mutex_unlock(&rt5514_dsp->dma_lock);
+
+	return ret;
+}
+
+static int rt5514_spi_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct rt5514_dsp *rt5514_dsp =
+		snd_soc_component_get_drvdata(component);
+
+	mutex_lock(&rt5514_dsp->dma_lock);
+	rt5514_dsp->substream = NULL;
+	mutex_unlock(&rt5514_dsp->dma_lock);
+
+	cancel_delayed_work_sync(&rt5514_dsp->copy_work);
+
+	return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static snd_pcm_uframes_t rt5514_spi_pcm_pointer(
+		struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct rt5514_dsp *rt5514_dsp =
+		snd_soc_component_get_drvdata(component);
+
+	return bytes_to_frames(runtime, rt5514_dsp->dma_offset);
+}
+
+static const struct snd_pcm_ops rt5514_spi_pcm_ops = {
+	.open		= rt5514_spi_pcm_open,
+	.hw_params	= rt5514_spi_hw_params,
+	.hw_free	= rt5514_spi_hw_free,
+	.pointer	= rt5514_spi_pcm_pointer,
+	.page		= snd_pcm_lib_get_vmalloc_page,
+};
+
+static int rt5514_spi_pcm_probe(struct snd_soc_component *component)
+{
+	struct rt5514_dsp *rt5514_dsp;
+	int ret;
+
+	rt5514_dsp = devm_kzalloc(component->dev, sizeof(*rt5514_dsp),
+			GFP_KERNEL);
+
+	rt5514_dsp->dev = &rt5514_spi->dev;
+	mutex_init(&rt5514_dsp->dma_lock);
+	INIT_DELAYED_WORK(&rt5514_dsp->copy_work, rt5514_spi_copy_work);
+	snd_soc_component_set_drvdata(component, rt5514_dsp);
+
+	if (rt5514_spi->irq) {
+		ret = devm_request_threaded_irq(&rt5514_spi->dev,
+			rt5514_spi->irq, NULL, rt5514_spi_irq,
+			IRQF_TRIGGER_RISING | IRQF_ONESHOT, "rt5514-spi",
+			rt5514_dsp);
+		if (ret)
+			dev_err(&rt5514_spi->dev,
+				"%s Failed to reguest IRQ: %d\n", __func__,
+				ret);
+		else
+			device_init_wakeup(rt5514_dsp->dev, true);
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver rt5514_spi_component = {
+	.name  = DRV_NAME,
+	.probe = rt5514_spi_pcm_probe,
+	.ops = &rt5514_spi_pcm_ops,
+};
+
+/**
+ * rt5514_spi_burst_read - Read data from SPI by rt5514 address.
+ * @addr: Start address.
+ * @rxbuf: Data Buffer for reading.
+ * @len: Data length, it must be a multiple of 8.
+ *
+ *
+ * Returns true for success.
+ */
+int rt5514_spi_burst_read(unsigned int addr, u8 *rxbuf, size_t len)
+{
+	u8 spi_cmd = RT5514_SPI_CMD_BURST_READ;
+	int status;
+	u8 write_buf[8];
+	unsigned int i, end, offset = 0;
+
+	struct spi_message message;
+	struct spi_transfer x[3];
+
+	while (offset < len) {
+		if (offset + RT5514_SPI_BUF_LEN <= len)
+			end = RT5514_SPI_BUF_LEN;
+		else
+			end = len % RT5514_SPI_BUF_LEN;
+
+		write_buf[0] = spi_cmd;
+		write_buf[1] = ((addr + offset) & 0xff000000) >> 24;
+		write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16;
+		write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8;
+		write_buf[4] = ((addr + offset) & 0x000000ff) >> 0;
+
+		spi_message_init(&message);
+		memset(x, 0, sizeof(x));
+
+		x[0].len = 5;
+		x[0].tx_buf = write_buf;
+		spi_message_add_tail(&x[0], &message);
+
+		x[1].len = 4;
+		x[1].tx_buf = write_buf;
+		spi_message_add_tail(&x[1], &message);
+
+		x[2].len = end;
+		x[2].rx_buf = rxbuf + offset;
+		spi_message_add_tail(&x[2], &message);
+
+		status = spi_sync(rt5514_spi, &message);
+
+		if (status)
+			return false;
+
+		offset += RT5514_SPI_BUF_LEN;
+	}
+
+	for (i = 0; i < len; i += 8) {
+		write_buf[0] = rxbuf[i + 0];
+		write_buf[1] = rxbuf[i + 1];
+		write_buf[2] = rxbuf[i + 2];
+		write_buf[3] = rxbuf[i + 3];
+		write_buf[4] = rxbuf[i + 4];
+		write_buf[5] = rxbuf[i + 5];
+		write_buf[6] = rxbuf[i + 6];
+		write_buf[7] = rxbuf[i + 7];
+
+		rxbuf[i + 0] = write_buf[7];
+		rxbuf[i + 1] = write_buf[6];
+		rxbuf[i + 2] = write_buf[5];
+		rxbuf[i + 3] = write_buf[4];
+		rxbuf[i + 4] = write_buf[3];
+		rxbuf[i + 5] = write_buf[2];
+		rxbuf[i + 6] = write_buf[1];
+		rxbuf[i + 7] = write_buf[0];
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(rt5514_spi_burst_read);
+
+/**
+ * rt5514_spi_burst_write - Write data to SPI by rt5514 address.
+ * @addr: Start address.
+ * @txbuf: Data Buffer for writng.
+ * @len: Data length, it must be a multiple of 8.
+ *
+ *
+ * Returns true for success.
+ */
+int rt5514_spi_burst_write(u32 addr, const u8 *txbuf, size_t len)
+{
+	u8 spi_cmd = RT5514_SPI_CMD_BURST_WRITE;
+	u8 *write_buf;
+	unsigned int i, end, offset = 0;
+
+	write_buf = kmalloc(RT5514_SPI_BUF_LEN + 6, GFP_KERNEL);
+
+	if (write_buf == NULL)
+		return -ENOMEM;
+
+	while (offset < len) {
+		if (offset + RT5514_SPI_BUF_LEN <= len)
+			end = RT5514_SPI_BUF_LEN;
+		else
+			end = len % RT5514_SPI_BUF_LEN;
+
+		write_buf[0] = spi_cmd;
+		write_buf[1] = ((addr + offset) & 0xff000000) >> 24;
+		write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16;
+		write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8;
+		write_buf[4] = ((addr + offset) & 0x000000ff) >> 0;
+
+		for (i = 0; i < end; i += 8) {
+			write_buf[i + 12] = txbuf[offset + i + 0];
+			write_buf[i + 11] = txbuf[offset + i + 1];
+			write_buf[i + 10] = txbuf[offset + i + 2];
+			write_buf[i +  9] = txbuf[offset + i + 3];
+			write_buf[i +  8] = txbuf[offset + i + 4];
+			write_buf[i +  7] = txbuf[offset + i + 5];
+			write_buf[i +  6] = txbuf[offset + i + 6];
+			write_buf[i +  5] = txbuf[offset + i + 7];
+		}
+
+		write_buf[end + 5] = spi_cmd;
+
+		spi_write(rt5514_spi, write_buf, end + 6);
+
+		offset += RT5514_SPI_BUF_LEN;
+	}
+
+	kfree(write_buf);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5514_spi_burst_write);
+
+static int rt5514_spi_probe(struct spi_device *spi)
+{
+	int ret;
+
+	rt5514_spi = spi;
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+					      &rt5514_spi_component,
+					      &rt5514_spi_dai, 1);
+	if (ret < 0) {
+		dev_err(&spi->dev, "Failed to register component.\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __maybe_unused rt5514_suspend(struct device *dev)
+{
+	int irq = to_spi_device(dev)->irq;
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(irq);
+
+	return 0;
+}
+
+static int __maybe_unused rt5514_resume(struct device *dev)
+{
+	struct snd_soc_component *component = snd_soc_lookup_component(dev, DRV_NAME);
+	struct rt5514_dsp *rt5514_dsp =
+		snd_soc_component_get_drvdata(component);
+	int irq = to_spi_device(dev)->irq;
+	u8 buf[8];
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(irq);
+
+	if (rt5514_dsp) {
+		if (rt5514_dsp->substream) {
+			rt5514_spi_burst_read(RT5514_IRQ_CTRL, (u8 *)&buf,
+				sizeof(buf));
+			if (buf[0] & RT5514_IRQ_STATUS_BIT)
+				rt5514_schedule_copy(rt5514_dsp);
+		}
+	}
+
+	return 0;
+}
+
+static const struct dev_pm_ops rt5514_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(rt5514_suspend, rt5514_resume)
+};
+
+static const struct of_device_id rt5514_of_match[] = {
+	{ .compatible = "realtek,rt5514", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5514_of_match);
+
+static struct spi_driver rt5514_spi_driver = {
+	.driver = {
+		.name = "rt5514",
+		.pm = &rt5514_pm_ops,
+		.of_match_table = of_match_ptr(rt5514_of_match),
+	},
+	.probe = rt5514_spi_probe,
+};
+module_spi_driver(rt5514_spi_driver);
+
+MODULE_DESCRIPTION("RT5514 SPI driver");
+MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5514-spi.h b/sound/soc/codecs/rt5514-spi.h
new file mode 100644
index 0000000..c1a3664
--- /dev/null
+++ b/sound/soc/codecs/rt5514-spi.h
@@ -0,0 +1,40 @@
+/*
+ * rt5514-spi.h  --  RT5514 driver
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5514_SPI_H__
+#define __RT5514_SPI_H__
+
+/**
+ * RT5514_SPI_BUF_LEN is the buffer size of SPI master controller.
+*/
+#define RT5514_SPI_BUF_LEN		240
+
+#define RT5514_BUFFER_VOICE_BASE	0x18000200
+#define RT5514_BUFFER_VOICE_LIMIT	0x18000204
+#define RT5514_BUFFER_VOICE_WP		0x1800020c
+#define RT5514_IRQ_CTRL			0x18002094
+
+#define RT5514_IRQ_STATUS_BIT		(0x1 << 5)
+
+/* SPI Command */
+enum {
+	RT5514_SPI_CMD_16_READ = 0,
+	RT5514_SPI_CMD_16_WRITE,
+	RT5514_SPI_CMD_32_READ,
+	RT5514_SPI_CMD_32_WRITE,
+	RT5514_SPI_CMD_BURST_READ,
+	RT5514_SPI_CMD_BURST_WRITE,
+};
+
+int rt5514_spi_burst_read(unsigned int addr, u8 *rxbuf, size_t len);
+int rt5514_spi_burst_write(u32 addr, const u8 *txbuf, size_t len);
+
+#endif /* __RT5514_SPI_H__ */
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
new file mode 100644
index 0000000..32fe76c
--- /dev/null
+++ b/sound/soc/codecs/rt5514.c
@@ -0,0 +1,1341 @@
+/*
+ * rt5514.c  --  RT5514 ALSA SoC audio codec driver
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rl6231.h"
+#include "rt5514.h"
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
+#include "rt5514-spi.h"
+#endif
+
+static const struct reg_sequence rt5514_i2c_patch[] = {
+	{0x1800101c, 0x00000000},
+	{0x18001100, 0x0000031f},
+	{0x18001104, 0x00000007},
+	{0x18001108, 0x00000000},
+	{0x1800110c, 0x00000000},
+	{0x18001110, 0x00000000},
+	{0x18001114, 0x00000001},
+	{0x18001118, 0x00000000},
+	{0x18002f08, 0x00000006},
+	{0x18002f00, 0x00055149},
+	{0x18002f00, 0x0005514b},
+	{0x18002f00, 0x00055149},
+	{0xfafafafa, 0x00000001},
+	{0x18002f10, 0x00000001},
+	{0x18002f10, 0x00000000},
+	{0x18002f10, 0x00000001},
+	{0xfafafafa, 0x00000001},
+	{0x18002000, 0x000010ec},
+	{0xfafafafa, 0x00000000},
+};
+
+static const struct reg_sequence rt5514_patch[] = {
+	{RT5514_DIG_IO_CTRL,		0x00000040},
+	{RT5514_CLK_CTRL1,		0x38020041},
+	{RT5514_SRC_CTRL,		0x44000eee},
+	{RT5514_ANA_CTRL_LDO10,		0x00028604},
+	{RT5514_ANA_CTRL_ADCFED,	0x00000800},
+	{RT5514_ASRC_IN_CTRL1,		0x00000003},
+	{RT5514_DOWNFILTER0_CTRL3,	0x10000342},
+	{RT5514_DOWNFILTER1_CTRL3,	0x10000342},
+};
+
+static const struct reg_default rt5514_reg[] = {
+	{RT5514_RESET,			0x00000000},
+	{RT5514_PWR_ANA1,		0x00808880},
+	{RT5514_PWR_ANA2,		0x00220000},
+	{RT5514_I2S_CTRL1,		0x00000330},
+	{RT5514_I2S_CTRL2,		0x20000000},
+	{RT5514_VAD_CTRL6,		0xc00007d2},
+	{RT5514_EXT_VAD_CTRL,		0x80000080},
+	{RT5514_DIG_IO_CTRL,		0x00000040},
+	{RT5514_PAD_CTRL1,		0x00804000},
+	{RT5514_DMIC_DATA_CTRL,		0x00000005},
+	{RT5514_DIG_SOURCE_CTRL,	0x00000002},
+	{RT5514_SRC_CTRL,		0x44000eee},
+	{RT5514_DOWNFILTER2_CTRL1,	0x0000882f},
+	{RT5514_PLL_SOURCE_CTRL,	0x00000004},
+	{RT5514_CLK_CTRL1,		0x38020041},
+	{RT5514_CLK_CTRL2,		0x00000000},
+	{RT5514_PLL3_CALIB_CTRL1,	0x00400200},
+	{RT5514_PLL3_CALIB_CTRL5,	0x40220012},
+	{RT5514_DELAY_BUF_CTRL1,	0x7fff006a},
+	{RT5514_DELAY_BUF_CTRL3,	0x00000000},
+	{RT5514_ASRC_IN_CTRL1,		0x00000003},
+	{RT5514_DOWNFILTER0_CTRL1,	0x00020c2f},
+	{RT5514_DOWNFILTER0_CTRL2,	0x00020c2f},
+	{RT5514_DOWNFILTER0_CTRL3,	0x10000342},
+	{RT5514_DOWNFILTER1_CTRL1,	0x00020c2f},
+	{RT5514_DOWNFILTER1_CTRL2,	0x00020c2f},
+	{RT5514_DOWNFILTER1_CTRL3,	0x10000342},
+	{RT5514_ANA_CTRL_LDO10,		0x00028604},
+	{RT5514_ANA_CTRL_LDO18_16,	0x02000345},
+	{RT5514_ANA_CTRL_ADC12,		0x0000a2a8},
+	{RT5514_ANA_CTRL_ADC21,		0x00001180},
+	{RT5514_ANA_CTRL_ADC22,		0x0000aaa8},
+	{RT5514_ANA_CTRL_ADC23,		0x00151427},
+	{RT5514_ANA_CTRL_MICBST,	0x00002000},
+	{RT5514_ANA_CTRL_ADCFED,	0x00000800},
+	{RT5514_ANA_CTRL_INBUF,		0x00000143},
+	{RT5514_ANA_CTRL_VREF,		0x00008d50},
+	{RT5514_ANA_CTRL_PLL3,		0x0000000e},
+	{RT5514_ANA_CTRL_PLL1_1,	0x00000000},
+	{RT5514_ANA_CTRL_PLL1_2,	0x00030220},
+	{RT5514_DMIC_LP_CTRL,		0x00000000},
+	{RT5514_MISC_CTRL_DSP,		0x00000000},
+	{RT5514_DSP_CTRL1,		0x00055149},
+	{RT5514_DSP_CTRL3,		0x00000006},
+	{RT5514_DSP_CTRL4,		0x00000001},
+	{RT5514_VENDOR_ID1,		0x00000001},
+	{RT5514_VENDOR_ID2,		0x10ec5514},
+};
+
+static void rt5514_enable_dsp_prepare(struct rt5514_priv *rt5514)
+{
+	/* Reset */
+	regmap_write(rt5514->i2c_regmap, 0x18002000, 0x000010ec);
+	/* LDO_I_limit */
+	regmap_write(rt5514->i2c_regmap, 0x18002200, 0x00028604);
+	/* I2C bypass enable */
+	regmap_write(rt5514->i2c_regmap, 0xfafafafa, 0x00000001);
+	/* mini-core reset */
+	regmap_write(rt5514->i2c_regmap, 0x18002f00, 0x0005514b);
+	regmap_write(rt5514->i2c_regmap, 0x18002f00, 0x00055149);
+	/* I2C bypass disable */
+	regmap_write(rt5514->i2c_regmap, 0xfafafafa, 0x00000000);
+	/* PIN config */
+	regmap_write(rt5514->i2c_regmap, 0x18002070, 0x00000040);
+	/* PLL3(QN)=RCOSC*(10+2) */
+	regmap_write(rt5514->i2c_regmap, 0x18002240, 0x0000000a);
+	/* PLL3 source=RCOSC, fsi=rt_clk */
+	regmap_write(rt5514->i2c_regmap, 0x18002100, 0x0000000b);
+	/* Power on RCOSC, pll3 */
+	regmap_write(rt5514->i2c_regmap, 0x18002004, 0x00808b81);
+	/* DSP clk source = pll3, ENABLE DSP clk */
+	regmap_write(rt5514->i2c_regmap, 0x18002f08, 0x00000005);
+	/* Enable DSP clk auto switch */
+	regmap_write(rt5514->i2c_regmap, 0x18001114, 0x00000001);
+	/* Reduce DSP power */
+	regmap_write(rt5514->i2c_regmap, 0x18001118, 0x00000001);
+}
+
+static bool rt5514_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5514_VENDOR_ID1:
+	case RT5514_VENDOR_ID2:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+static bool rt5514_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5514_RESET:
+	case RT5514_PWR_ANA1:
+	case RT5514_PWR_ANA2:
+	case RT5514_I2S_CTRL1:
+	case RT5514_I2S_CTRL2:
+	case RT5514_VAD_CTRL6:
+	case RT5514_EXT_VAD_CTRL:
+	case RT5514_DIG_IO_CTRL:
+	case RT5514_PAD_CTRL1:
+	case RT5514_DMIC_DATA_CTRL:
+	case RT5514_DIG_SOURCE_CTRL:
+	case RT5514_SRC_CTRL:
+	case RT5514_DOWNFILTER2_CTRL1:
+	case RT5514_PLL_SOURCE_CTRL:
+	case RT5514_CLK_CTRL1:
+	case RT5514_CLK_CTRL2:
+	case RT5514_PLL3_CALIB_CTRL1:
+	case RT5514_PLL3_CALIB_CTRL5:
+	case RT5514_DELAY_BUF_CTRL1:
+	case RT5514_DELAY_BUF_CTRL3:
+	case RT5514_ASRC_IN_CTRL1:
+	case RT5514_DOWNFILTER0_CTRL1:
+	case RT5514_DOWNFILTER0_CTRL2:
+	case RT5514_DOWNFILTER0_CTRL3:
+	case RT5514_DOWNFILTER1_CTRL1:
+	case RT5514_DOWNFILTER1_CTRL2:
+	case RT5514_DOWNFILTER1_CTRL3:
+	case RT5514_ANA_CTRL_LDO10:
+	case RT5514_ANA_CTRL_LDO18_16:
+	case RT5514_ANA_CTRL_ADC12:
+	case RT5514_ANA_CTRL_ADC21:
+	case RT5514_ANA_CTRL_ADC22:
+	case RT5514_ANA_CTRL_ADC23:
+	case RT5514_ANA_CTRL_MICBST:
+	case RT5514_ANA_CTRL_ADCFED:
+	case RT5514_ANA_CTRL_INBUF:
+	case RT5514_ANA_CTRL_VREF:
+	case RT5514_ANA_CTRL_PLL3:
+	case RT5514_ANA_CTRL_PLL1_1:
+	case RT5514_ANA_CTRL_PLL1_2:
+	case RT5514_DMIC_LP_CTRL:
+	case RT5514_MISC_CTRL_DSP:
+	case RT5514_DSP_CTRL1:
+	case RT5514_DSP_CTRL3:
+	case RT5514_DSP_CTRL4:
+	case RT5514_VENDOR_ID1:
+	case RT5514_VENDOR_ID2:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+static bool rt5514_i2c_readable_register(struct device *dev,
+	unsigned int reg)
+{
+	switch (reg) {
+	case RT5514_DSP_MAPPING | RT5514_RESET:
+	case RT5514_DSP_MAPPING | RT5514_PWR_ANA1:
+	case RT5514_DSP_MAPPING | RT5514_PWR_ANA2:
+	case RT5514_DSP_MAPPING | RT5514_I2S_CTRL1:
+	case RT5514_DSP_MAPPING | RT5514_I2S_CTRL2:
+	case RT5514_DSP_MAPPING | RT5514_VAD_CTRL6:
+	case RT5514_DSP_MAPPING | RT5514_EXT_VAD_CTRL:
+	case RT5514_DSP_MAPPING | RT5514_DIG_IO_CTRL:
+	case RT5514_DSP_MAPPING | RT5514_PAD_CTRL1:
+	case RT5514_DSP_MAPPING | RT5514_DMIC_DATA_CTRL:
+	case RT5514_DSP_MAPPING | RT5514_DIG_SOURCE_CTRL:
+	case RT5514_DSP_MAPPING | RT5514_SRC_CTRL:
+	case RT5514_DSP_MAPPING | RT5514_DOWNFILTER2_CTRL1:
+	case RT5514_DSP_MAPPING | RT5514_PLL_SOURCE_CTRL:
+	case RT5514_DSP_MAPPING | RT5514_CLK_CTRL1:
+	case RT5514_DSP_MAPPING | RT5514_CLK_CTRL2:
+	case RT5514_DSP_MAPPING | RT5514_PLL3_CALIB_CTRL1:
+	case RT5514_DSP_MAPPING | RT5514_PLL3_CALIB_CTRL5:
+	case RT5514_DSP_MAPPING | RT5514_DELAY_BUF_CTRL1:
+	case RT5514_DSP_MAPPING | RT5514_DELAY_BUF_CTRL3:
+	case RT5514_DSP_MAPPING | RT5514_ASRC_IN_CTRL1:
+	case RT5514_DSP_MAPPING | RT5514_DOWNFILTER0_CTRL1:
+	case RT5514_DSP_MAPPING | RT5514_DOWNFILTER0_CTRL2:
+	case RT5514_DSP_MAPPING | RT5514_DOWNFILTER0_CTRL3:
+	case RT5514_DSP_MAPPING | RT5514_DOWNFILTER1_CTRL1:
+	case RT5514_DSP_MAPPING | RT5514_DOWNFILTER1_CTRL2:
+	case RT5514_DSP_MAPPING | RT5514_DOWNFILTER1_CTRL3:
+	case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_LDO10:
+	case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_LDO18_16:
+	case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADC12:
+	case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADC21:
+	case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADC22:
+	case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADC23:
+	case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_MICBST:
+	case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADCFED:
+	case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_INBUF:
+	case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_VREF:
+	case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_PLL3:
+	case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_PLL1_1:
+	case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_PLL1_2:
+	case RT5514_DSP_MAPPING | RT5514_DMIC_LP_CTRL:
+	case RT5514_DSP_MAPPING | RT5514_MISC_CTRL_DSP:
+	case RT5514_DSP_MAPPING | RT5514_DSP_CTRL1:
+	case RT5514_DSP_MAPPING | RT5514_DSP_CTRL3:
+	case RT5514_DSP_MAPPING | RT5514_DSP_CTRL4:
+	case RT5514_DSP_MAPPING | RT5514_VENDOR_ID1:
+	case RT5514_DSP_MAPPING | RT5514_VENDOR_ID2:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+/* {-3, 0, +3, +4.5, +7.5, +9.5, +12, +14, +17} dB */
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
+	0, 2, TLV_DB_SCALE_ITEM(-300, 300, 0),
+	3, 3, TLV_DB_SCALE_ITEM(450, 0, 0),
+	4, 4, TLV_DB_SCALE_ITEM(750, 0, 0),
+	5, 5, TLV_DB_SCALE_ITEM(950, 0, 0),
+	6, 6, TLV_DB_SCALE_ITEM(1200, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(1400, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(1700, 0, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
+
+static int rt5514_dsp_voice_wake_up_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = rt5514->dsp_enabled;
+
+	return 0;
+}
+
+static int rt5514_calibration(struct rt5514_priv *rt5514, bool on)
+{
+	if (on) {
+		regmap_write(rt5514->regmap, RT5514_ANA_CTRL_PLL3, 0x0000000a);
+		regmap_update_bits(rt5514->regmap, RT5514_PLL_SOURCE_CTRL, 0xf,
+			0xa);
+		regmap_update_bits(rt5514->regmap, RT5514_PWR_ANA1, 0x301,
+			0x301);
+		regmap_write(rt5514->regmap, RT5514_PLL3_CALIB_CTRL4,
+			0x80000000 | rt5514->pll3_cal_value);
+		regmap_write(rt5514->regmap, RT5514_PLL3_CALIB_CTRL1,
+			0x8bb80800);
+		regmap_update_bits(rt5514->regmap, RT5514_PLL3_CALIB_CTRL5,
+			0xc0000000, 0x80000000);
+		regmap_update_bits(rt5514->regmap, RT5514_PLL3_CALIB_CTRL5,
+			0xc0000000, 0xc0000000);
+	} else {
+		regmap_update_bits(rt5514->regmap, RT5514_PLL3_CALIB_CTRL5,
+			0xc0000000, 0x40000000);
+		regmap_update_bits(rt5514->regmap, RT5514_PWR_ANA1, 0x301, 0);
+		regmap_update_bits(rt5514->regmap, RT5514_PLL_SOURCE_CTRL, 0xf,
+			0x4);
+	}
+
+	return 0;
+}
+
+static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+	const struct firmware *fw = NULL;
+	u8 buf[8];
+
+	if (ucontrol->value.integer.value[0] == rt5514->dsp_enabled)
+		return 0;
+
+	if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+		rt5514->dsp_enabled = ucontrol->value.integer.value[0];
+
+		if (rt5514->dsp_enabled) {
+			if (rt5514->pdata.dsp_calib_clk_name &&
+				!IS_ERR(rt5514->dsp_calib_clk)) {
+				if (clk_set_rate(rt5514->dsp_calib_clk,
+					rt5514->pdata.dsp_calib_clk_rate))
+					dev_err(component->dev,
+						"Can't set rate for mclk");
+
+				if (clk_prepare_enable(rt5514->dsp_calib_clk))
+					dev_err(component->dev,
+						"Can't enable dsp_calib_clk");
+
+				rt5514_calibration(rt5514, true);
+
+				msleep(20);
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
+				rt5514_spi_burst_read(RT5514_PLL3_CALIB_CTRL6 |
+					RT5514_DSP_MAPPING, buf, sizeof(buf));
+#else
+				dev_err(component->dev, "There is no SPI driver for"
+					" loading the firmware\n");
+				memset(buf, 0, sizeof(buf));
+#endif
+				rt5514->pll3_cal_value = buf[0] | buf[1] << 8 |
+					buf[2] << 16 | buf[3] << 24;
+
+				rt5514_calibration(rt5514, false);
+				clk_disable_unprepare(rt5514->dsp_calib_clk);
+			}
+
+			rt5514_enable_dsp_prepare(rt5514);
+
+			request_firmware(&fw, RT5514_FIRMWARE1, component->dev);
+			if (fw) {
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
+				rt5514_spi_burst_write(0x4ff60000, fw->data,
+					((fw->size/8)+1)*8);
+#else
+				dev_err(component->dev, "There is no SPI driver for"
+					" loading the firmware\n");
+#endif
+				release_firmware(fw);
+				fw = NULL;
+			}
+
+			request_firmware(&fw, RT5514_FIRMWARE2, component->dev);
+			if (fw) {
+#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI)
+				rt5514_spi_burst_write(0x4ffc0000, fw->data,
+					((fw->size/8)+1)*8);
+#else
+				dev_err(component->dev, "There is no SPI driver for"
+					" loading the firmware\n");
+#endif
+				release_firmware(fw);
+				fw = NULL;
+			}
+
+			/* DSP run */
+			regmap_write(rt5514->i2c_regmap, 0x18002f00,
+				0x00055148);
+
+			if (rt5514->pdata.dsp_calib_clk_name &&
+				!IS_ERR(rt5514->dsp_calib_clk)) {
+				msleep(20);
+
+				regmap_write(rt5514->i2c_regmap, 0x1800211c,
+					rt5514->pll3_cal_value);
+				regmap_write(rt5514->i2c_regmap, 0x18002124,
+					0x00220012);
+				regmap_write(rt5514->i2c_regmap, 0x18002124,
+					0x80220042);
+				regmap_write(rt5514->i2c_regmap, 0x18002124,
+					0xe0220042);
+			}
+		} else {
+			regmap_multi_reg_write(rt5514->i2c_regmap,
+				rt5514_i2c_patch, ARRAY_SIZE(rt5514_i2c_patch));
+			regcache_mark_dirty(rt5514->regmap);
+			regcache_sync(rt5514->regmap);
+		}
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new rt5514_snd_controls[] = {
+	SOC_DOUBLE_TLV("MIC Boost Volume", RT5514_ANA_CTRL_MICBST,
+		RT5514_SEL_BSTL_SFT, RT5514_SEL_BSTR_SFT, 8, 0, bst_tlv),
+	SOC_DOUBLE_R_TLV("ADC1 Capture Volume", RT5514_DOWNFILTER0_CTRL1,
+		RT5514_DOWNFILTER0_CTRL2, RT5514_AD_GAIN_SFT, 63, 0,
+		adc_vol_tlv),
+	SOC_DOUBLE_R_TLV("ADC2 Capture Volume", RT5514_DOWNFILTER1_CTRL1,
+		RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 63, 0,
+		adc_vol_tlv),
+	SOC_SINGLE_EXT("DSP Voice Wake Up", SND_SOC_NOPM, 0, 1, 0,
+		rt5514_dsp_voice_wake_up_get, rt5514_dsp_voice_wake_up_put),
+};
+
+/* ADC Mixer*/
+static const struct snd_kcontrol_new rt5514_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("DMIC Switch", RT5514_DOWNFILTER0_CTRL1,
+		RT5514_AD_DMIC_MIX_BIT, 1, 1),
+	SOC_DAPM_SINGLE("ADC Switch", RT5514_DOWNFILTER0_CTRL1,
+		RT5514_AD_AD_MIX_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5514_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("DMIC Switch", RT5514_DOWNFILTER0_CTRL2,
+		RT5514_AD_DMIC_MIX_BIT, 1, 1),
+	SOC_DAPM_SINGLE("ADC Switch", RT5514_DOWNFILTER0_CTRL2,
+		RT5514_AD_AD_MIX_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5514_sto2_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("DMIC Switch", RT5514_DOWNFILTER1_CTRL1,
+		RT5514_AD_DMIC_MIX_BIT, 1, 1),
+	SOC_DAPM_SINGLE("ADC Switch", RT5514_DOWNFILTER1_CTRL1,
+		RT5514_AD_AD_MIX_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5514_sto2_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("DMIC Switch", RT5514_DOWNFILTER1_CTRL2,
+		RT5514_AD_DMIC_MIX_BIT, 1, 1),
+	SOC_DAPM_SINGLE("ADC Switch", RT5514_DOWNFILTER1_CTRL2,
+		RT5514_AD_AD_MIX_BIT, 1, 1),
+};
+
+/* DMIC Source */
+static const char * const rt5514_dmic_src[] = {
+	"DMIC1", "DMIC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5514_stereo1_dmic_enum, RT5514_DIG_SOURCE_CTRL,
+	RT5514_AD0_DMIC_INPUT_SEL_SFT, rt5514_dmic_src);
+
+static const struct snd_kcontrol_new rt5514_sto1_dmic_mux =
+	SOC_DAPM_ENUM("Stereo1 DMIC Source", rt5514_stereo1_dmic_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5514_stereo2_dmic_enum, RT5514_DIG_SOURCE_CTRL,
+	RT5514_AD1_DMIC_INPUT_SEL_SFT, rt5514_dmic_src);
+
+static const struct snd_kcontrol_new rt5514_sto2_dmic_mux =
+	SOC_DAPM_ENUM("Stereo2 DMIC Source", rt5514_stereo2_dmic_enum);
+
+/**
+ * rt5514_calc_dmic_clk - Calculate the frequency divider parameter of dmic.
+ *
+ * @rate: base clock rate.
+ *
+ * Choose divider parameter that gives the highest possible DMIC frequency in
+ * 1MHz - 3MHz range.
+ */
+static int rt5514_calc_dmic_clk(struct snd_soc_component *component, int rate)
+{
+	int div[] = {2, 3, 4, 8, 12, 16, 24, 32};
+	int i;
+
+	if (rate < 1000000 * div[0]) {
+		pr_warn("Base clock rate %d is too low\n", rate);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(div); i++) {
+		/* find divider that gives DMIC frequency below 3.072MHz */
+		if (3072000 * div[i] >= rate)
+			return i;
+	}
+
+	dev_warn(component->dev, "Base clock rate %d is too high\n", rate);
+	return -EINVAL;
+}
+
+static int rt5514_set_dmic_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+	int idx;
+
+	idx = rt5514_calc_dmic_clk(component, rt5514->sysclk);
+	if (idx < 0)
+		dev_err(component->dev, "Failed to set DMIC clock\n");
+	else
+		regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL1,
+			RT5514_CLK_DMIC_OUT_SEL_MASK,
+			idx << RT5514_CLK_DMIC_OUT_SEL_SFT);
+
+	if (rt5514->pdata.dmic_init_delay)
+		msleep(rt5514->pdata.dmic_init_delay);
+
+	return idx;
+}
+
+static int rt5514_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+
+	if (rt5514->sysclk_src == RT5514_SCLK_S_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int rt5514_i2s_use_asrc(struct snd_soc_dapm_widget *source,
+	struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+
+	return (rt5514->sysclk > rt5514->lrck * 384);
+}
+
+static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = {
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC1L"),
+	SND_SOC_DAPM_INPUT("DMIC1R"),
+	SND_SOC_DAPM_INPUT("DMIC2L"),
+	SND_SOC_DAPM_INPUT("DMIC2R"),
+
+	SND_SOC_DAPM_INPUT("AMICL"),
+	SND_SOC_DAPM_INPUT("AMICR"),
+
+	SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("DMIC CLK", 1, SND_SOC_NOPM, 0, 0,
+		rt5514_set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+
+	SND_SOC_DAPM_SUPPLY("ADC CLK", RT5514_CLK_CTRL1,
+		RT5514_CLK_AD_ANA1_EN_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("LDO18 IN", RT5514_PWR_ANA1,
+		RT5514_POW_LDO18_IN_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LDO18 ADC", RT5514_PWR_ANA1,
+		RT5514_POW_LDO18_ADC_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LDO21", RT5514_PWR_ANA1, RT5514_POW_LDO21_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BG LDO18 IN", RT5514_PWR_ANA1,
+		RT5514_POW_BG_LDO18_IN_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BG LDO21", RT5514_PWR_ANA1,
+		RT5514_POW_BG_LDO21_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BG MBIAS", RT5514_PWR_ANA2,
+		RT5514_POW_BG_MBIAS_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MBIAS", RT5514_PWR_ANA2, RT5514_POW_MBIAS_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VREF2", RT5514_PWR_ANA2, RT5514_POW_VREF2_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("VREF1", RT5514_PWR_ANA2, RT5514_POW_VREF1_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Power", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+
+	SND_SOC_DAPM_SUPPLY("LDO16L", RT5514_PWR_ANA2, RT5514_POWL_LDO16_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1L", RT5514_PWR_ANA2, RT5514_POW_ADC1_L_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BSTL2", RT5514_PWR_ANA2, RT5514_POW2_BSTL_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BSTL", RT5514_PWR_ANA2, RT5514_POW_BSTL_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADCFEDL", RT5514_PWR_ANA2, RT5514_POW_ADCFEDL_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADCL Power", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("LDO16R", RT5514_PWR_ANA2, RT5514_POWR_LDO16_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1R", RT5514_PWR_ANA2, RT5514_POW_ADC1_R_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BSTR2", RT5514_PWR_ANA2, RT5514_POW2_BSTR_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BSTR", RT5514_PWR_ANA2, RT5514_POW_BSTR_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADCFEDR", RT5514_PWR_ANA2, RT5514_POW_ADCFEDR_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADCR Power", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("PLL1 LDO ENABLE", RT5514_ANA_CTRL_PLL1_2,
+		RT5514_EN_LDO_PLL1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL1 LDO", RT5514_PWR_ANA2,
+		RT5514_POW_PLL1_LDO_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL1", RT5514_PWR_ANA2, RT5514_POW_PLL1_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ASRC AD1", 1, RT5514_CLK_CTRL2,
+		RT5514_CLK_AD0_ASRC_EN_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ASRC AD2", 1, RT5514_CLK_CTRL2,
+		RT5514_CLK_AD1_ASRC_EN_BIT, 0, NULL, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0,
+				&rt5514_sto1_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo2 DMIC Mux", SND_SOC_NOPM, 0, 0,
+				&rt5514_sto2_dmic_mux),
+
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("adc stereo1 filter", RT5514_CLK_CTRL1,
+		RT5514_CLK_AD0_EN_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("adc stereo2 filter", RT5514_CLK_CTRL1,
+		RT5514_CLK_AD1_EN_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5514_sto1_adc_l_mix, ARRAY_SIZE(rt5514_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5514_sto1_adc_r_mix, ARRAY_SIZE(rt5514_sto1_adc_r_mix)),
+	SND_SOC_DAPM_MIXER("Sto2 ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5514_sto2_adc_l_mix, ARRAY_SIZE(rt5514_sto2_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Sto2 ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5514_sto2_adc_r_mix, ARRAY_SIZE(rt5514_sto2_adc_r_mix)),
+
+	SND_SOC_DAPM_ADC("Stereo1 ADC MIXL", NULL, RT5514_DOWNFILTER0_CTRL1,
+		RT5514_AD_AD_MUTE_BIT, 1),
+	SND_SOC_DAPM_ADC("Stereo1 ADC MIXR", NULL, RT5514_DOWNFILTER0_CTRL2,
+		RT5514_AD_AD_MUTE_BIT, 1),
+	SND_SOC_DAPM_ADC("Stereo2 ADC MIXL", NULL, RT5514_DOWNFILTER1_CTRL1,
+		RT5514_AD_AD_MUTE_BIT, 1),
+	SND_SOC_DAPM_ADC("Stereo2 ADC MIXR", NULL, RT5514_DOWNFILTER1_CTRL2,
+		RT5514_AD_AD_MUTE_BIT, 1),
+
+	/* ADC PGA */
+	SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo2 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt5514_dapm_routes[] = {
+	{ "DMIC1", NULL, "DMIC1L" },
+	{ "DMIC1", NULL, "DMIC1R" },
+	{ "DMIC2", NULL, "DMIC2L" },
+	{ "DMIC2", NULL, "DMIC2R" },
+
+	{ "DMIC1L", NULL, "DMIC CLK" },
+	{ "DMIC1R", NULL, "DMIC CLK" },
+	{ "DMIC2L", NULL, "DMIC CLK" },
+	{ "DMIC2R", NULL, "DMIC CLK" },
+
+	{ "Stereo1 DMIC Mux", "DMIC1", "DMIC1" },
+	{ "Stereo1 DMIC Mux", "DMIC2", "DMIC2" },
+
+	{ "Sto1 ADC MIXL", "DMIC Switch", "Stereo1 DMIC Mux" },
+	{ "Sto1 ADC MIXL", "ADC Switch", "AMICL" },
+	{ "Sto1 ADC MIXR", "DMIC Switch", "Stereo1 DMIC Mux" },
+	{ "Sto1 ADC MIXR", "ADC Switch", "AMICR" },
+
+	{ "ADC Power", NULL, "LDO18 IN" },
+	{ "ADC Power", NULL, "LDO18 ADC" },
+	{ "ADC Power", NULL, "LDO21" },
+	{ "ADC Power", NULL, "BG LDO18 IN" },
+	{ "ADC Power", NULL, "BG LDO21" },
+	{ "ADC Power", NULL, "BG MBIAS" },
+	{ "ADC Power", NULL, "MBIAS" },
+	{ "ADC Power", NULL, "VREF2" },
+	{ "ADC Power", NULL, "VREF1" },
+
+	{ "ADCL Power", NULL, "LDO16L" },
+	{ "ADCL Power", NULL, "ADC1L" },
+	{ "ADCL Power", NULL, "BSTL2" },
+	{ "ADCL Power", NULL, "BSTL" },
+	{ "ADCL Power", NULL, "ADCFEDL" },
+
+	{ "ADCR Power", NULL, "LDO16R" },
+	{ "ADCR Power", NULL, "ADC1R" },
+	{ "ADCR Power", NULL, "BSTR2" },
+	{ "ADCR Power", NULL, "BSTR" },
+	{ "ADCR Power", NULL, "ADCFEDR" },
+
+	{ "AMICL", NULL, "ADC CLK" },
+	{ "AMICL", NULL, "ADC Power" },
+	{ "AMICL", NULL, "ADCL Power" },
+	{ "AMICR", NULL, "ADC CLK" },
+	{ "AMICR", NULL, "ADC Power" },
+	{ "AMICR", NULL, "ADCR Power" },
+
+	{ "PLL1 LDO", NULL, "PLL1 LDO ENABLE" },
+	{ "PLL1", NULL, "PLL1 LDO" },
+
+	{ "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" },
+	{ "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" },
+
+	{ "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL" },
+	{ "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR" },
+	{ "Stereo1 ADC MIX", NULL, "adc stereo1 filter" },
+	{ "adc stereo1 filter", NULL, "PLL1", rt5514_is_sys_clk_from_pll },
+	{ "adc stereo1 filter", NULL, "ASRC AD1", rt5514_i2s_use_asrc },
+
+	{ "Stereo2 DMIC Mux", "DMIC1", "DMIC1" },
+	{ "Stereo2 DMIC Mux", "DMIC2", "DMIC2" },
+
+	{ "Sto2 ADC MIXL", "DMIC Switch", "Stereo2 DMIC Mux" },
+	{ "Sto2 ADC MIXL", "ADC Switch", "AMICL" },
+	{ "Sto2 ADC MIXR", "DMIC Switch", "Stereo2 DMIC Mux" },
+	{ "Sto2 ADC MIXR", "ADC Switch", "AMICR" },
+
+	{ "Stereo2 ADC MIXL", NULL, "Sto2 ADC MIXL" },
+	{ "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" },
+
+	{ "Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXL" },
+	{ "Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXR" },
+	{ "Stereo2 ADC MIX", NULL, "adc stereo2 filter" },
+	{ "adc stereo2 filter", NULL, "PLL1", rt5514_is_sys_clk_from_pll },
+	{ "adc stereo2 filter", NULL, "ASRC AD2", rt5514_i2s_use_asrc },
+
+	{ "AIF1TX", NULL, "Stereo1 ADC MIX"},
+	{ "AIF1TX", NULL, "Stereo2 ADC MIX"},
+};
+
+static int rt5514_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+	int pre_div, bclk_ms, frame_size;
+	unsigned int val_len = 0;
+
+	rt5514->lrck = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5514->sysclk, rt5514->lrck);
+	if (pre_div < 0) {
+		dev_err(component->dev, "Unsupported clock setting\n");
+		return -EINVAL;
+	}
+
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
+		return -EINVAL;
+	}
+
+	bclk_ms = frame_size > 32;
+	rt5514->bclk = rt5514->lrck * (32 << bclk_ms);
+
+	dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+		rt5514->bclk, rt5514->lrck);
+	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+				bclk_ms, pre_div, dai->id);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		val_len = RT5514_I2S_DL_20;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		val_len = RT5514_I2S_DL_24;
+		break;
+	case SNDRV_PCM_FORMAT_S8:
+		val_len = RT5514_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1, RT5514_I2S_DL_MASK,
+		val_len);
+	regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL1,
+		RT5514_CLK_AD_ANA1_SEL_MASK,
+		(pre_div + 1) << RT5514_CLK_AD_ANA1_SEL_SFT);
+	regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL2,
+		RT5514_CLK_SYS_DIV_OUT_MASK | RT5514_SEL_ADC_OSR_MASK,
+		pre_div << RT5514_CLK_SYS_DIV_OUT_SFT |
+		pre_div << RT5514_SEL_ADC_OSR_SFT);
+
+	return 0;
+}
+
+static int rt5514_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+
+	case SND_SOC_DAIFMT_NB_IF:
+		reg_val |= RT5514_I2S_LR_INV;
+		break;
+
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5514_I2S_BP_INV;
+		break;
+
+	case SND_SOC_DAIFMT_IB_IF:
+		reg_val |= RT5514_I2S_BP_INV | RT5514_I2S_LR_INV;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5514_I2S_DF_LEFT;
+		break;
+
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5514_I2S_DF_PCM_A;
+		break;
+
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5514_I2S_DF_PCM_B;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1,
+		RT5514_I2S_DF_MASK | RT5514_I2S_BP_MASK | RT5514_I2S_LR_MASK,
+		reg_val);
+
+	return 0;
+}
+
+static int rt5514_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	if (freq == rt5514->sysclk && clk_id == rt5514->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5514_SCLK_S_MCLK:
+		reg_val |= RT5514_CLK_SYS_PRE_SEL_MCLK;
+		break;
+
+	case RT5514_SCLK_S_PLL1:
+		reg_val |= RT5514_CLK_SYS_PRE_SEL_PLL;
+		break;
+
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+
+	regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL2,
+		RT5514_CLK_SYS_PRE_SEL_MASK, reg_val);
+
+	rt5514->sysclk = freq;
+	rt5514->sysclk_src = clk_id;
+
+	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+	return 0;
+}
+
+static int rt5514_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+			unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt5514->pll_in = 0;
+		rt5514->pll_out = 0;
+		regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL2,
+			RT5514_CLK_SYS_PRE_SEL_MASK,
+			RT5514_CLK_SYS_PRE_SEL_MCLK);
+
+		return 0;
+	}
+
+	if (source == rt5514->pll_src && freq_in == rt5514->pll_in &&
+	    freq_out == rt5514->pll_out)
+		return 0;
+
+	switch (source) {
+	case RT5514_PLL1_S_MCLK:
+		regmap_update_bits(rt5514->regmap, RT5514_PLL_SOURCE_CTRL,
+			RT5514_PLL_1_SEL_MASK, RT5514_PLL_1_SEL_MCLK);
+		break;
+
+	case RT5514_PLL1_S_BCLK:
+		regmap_update_bits(rt5514->regmap, RT5514_PLL_SOURCE_CTRL,
+			RT5514_PLL_1_SEL_MASK, RT5514_PLL_1_SEL_SCLK);
+		break;
+
+	default:
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	regmap_write(rt5514->regmap, RT5514_ANA_CTRL_PLL1_1,
+		pll_code.k_code << RT5514_PLL_K_SFT |
+		pll_code.n_code << RT5514_PLL_N_SFT |
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5514_PLL_M_SFT);
+	regmap_update_bits(rt5514->regmap, RT5514_ANA_CTRL_PLL1_2,
+		RT5514_PLL_M_BP, pll_code.m_bp << RT5514_PLL_M_BP_SFT);
+
+	rt5514->pll_in = freq_in;
+	rt5514->pll_out = freq_out;
+	rt5514->pll_src = source;
+
+	return 0;
+}
+
+static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+	unsigned int val = 0, val2 = 0;
+
+	if (rx_mask || tx_mask)
+		val |= RT5514_TDM_MODE;
+
+	switch (tx_mask) {
+	case 0x3:
+		val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH2 |
+			RT5514_TDM_DOCKING_START_SLOT0;
+		break;
+
+	case 0x30:
+		val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH2 |
+			RT5514_TDM_DOCKING_START_SLOT4;
+		break;
+
+	case 0xf:
+		val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH4 |
+			RT5514_TDM_DOCKING_START_SLOT0;
+		break;
+
+	case 0xf0:
+		val2 |= RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH4 |
+			RT5514_TDM_DOCKING_START_SLOT4;
+		break;
+
+	default:
+		break;
+	}
+
+
+
+	switch (slots) {
+	case 4:
+		val |= RT5514_TDMSLOT_SEL_RX_4CH | RT5514_TDMSLOT_SEL_TX_4CH;
+		break;
+
+	case 6:
+		val |= RT5514_TDMSLOT_SEL_RX_6CH | RT5514_TDMSLOT_SEL_TX_6CH;
+		break;
+
+	case 8:
+		val |= RT5514_TDMSLOT_SEL_RX_8CH | RT5514_TDMSLOT_SEL_TX_8CH;
+		break;
+
+	case 2:
+	default:
+		break;
+	}
+
+	switch (slot_width) {
+	case 20:
+		val |= RT5514_CH_LEN_RX_20 | RT5514_CH_LEN_TX_20;
+		break;
+
+	case 24:
+		val |= RT5514_CH_LEN_RX_24 | RT5514_CH_LEN_TX_24;
+		break;
+
+	case 25:
+		val |= RT5514_TDM_MODE2;
+		break;
+
+	case 32:
+		val |= RT5514_CH_LEN_RX_32 | RT5514_CH_LEN_TX_32;
+		break;
+
+	case 16:
+	default:
+		break;
+	}
+
+	regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1, RT5514_TDM_MODE |
+		RT5514_TDMSLOT_SEL_RX_MASK | RT5514_TDMSLOT_SEL_TX_MASK |
+		RT5514_CH_LEN_RX_MASK | RT5514_CH_LEN_TX_MASK |
+		RT5514_TDM_MODE2, val);
+
+	regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL2,
+		RT5514_TDM_DOCKING_MODE | RT5514_TDM_DOCKING_VALID_CH_MASK |
+		RT5514_TDM_DOCKING_START_MASK, val2);
+
+	return 0;
+}
+
+static int rt5514_set_bias_level(struct snd_soc_component *component,
+			enum snd_soc_bias_level level)
+{
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		if (IS_ERR(rt5514->mclk))
+			break;
+
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
+			clk_disable_unprepare(rt5514->mclk);
+		} else {
+			ret = clk_prepare_enable(rt5514->mclk);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/*
+			 * If the DSP is enabled in start of recording, the DSP
+			 * should be disabled, and sync back to normal recording
+			 * settings to make sure recording properly.
+			 */
+			if (rt5514->dsp_enabled) {
+				rt5514->dsp_enabled = 0;
+				regmap_multi_reg_write(rt5514->i2c_regmap,
+					rt5514_i2c_patch,
+					ARRAY_SIZE(rt5514_i2c_patch));
+				regcache_mark_dirty(rt5514->regmap);
+				regcache_sync(rt5514->regmap);
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5514_probe(struct snd_soc_component *component)
+{
+	struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
+	struct platform_device *pdev = container_of(component->dev,
+						   struct platform_device, dev);
+
+	rt5514->mclk = devm_clk_get(component->dev, "mclk");
+	if (PTR_ERR(rt5514->mclk) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	if (rt5514->pdata.dsp_calib_clk_name) {
+		rt5514->dsp_calib_clk = devm_clk_get(&pdev->dev,
+				rt5514->pdata.dsp_calib_clk_name);
+		if (PTR_ERR(rt5514->dsp_calib_clk) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+	}
+
+	rt5514->component = component;
+	rt5514->pll3_cal_value = 0x0078b000;
+
+	return 0;
+}
+
+static int rt5514_i2c_read(void *context, unsigned int reg, unsigned int *val)
+{
+	struct i2c_client *client = context;
+	struct rt5514_priv *rt5514 = i2c_get_clientdata(client);
+
+	regmap_read(rt5514->i2c_regmap, reg | RT5514_DSP_MAPPING, val);
+
+	return 0;
+}
+
+static int rt5514_i2c_write(void *context, unsigned int reg, unsigned int val)
+{
+	struct i2c_client *client = context;
+	struct rt5514_priv *rt5514 = i2c_get_clientdata(client);
+
+	regmap_write(rt5514->i2c_regmap, reg | RT5514_DSP_MAPPING, val);
+
+	return 0;
+}
+
+#define RT5514_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5514_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5514_aif_dai_ops = {
+	.hw_params = rt5514_hw_params,
+	.set_fmt = rt5514_set_dai_fmt,
+	.set_sysclk = rt5514_set_dai_sysclk,
+	.set_pll = rt5514_set_dai_pll,
+	.set_tdm_slot = rt5514_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver rt5514_dai[] = {
+	{
+		.name = "rt5514-aif1",
+		.id = 0,
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = RT5514_STEREO_RATES,
+			.formats = RT5514_FORMATS,
+		},
+		.ops = &rt5514_aif_dai_ops,
+	}
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5514 = {
+	.probe			= rt5514_probe,
+	.set_bias_level		= rt5514_set_bias_level,
+	.controls		= rt5514_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5514_snd_controls),
+	.dapm_widgets		= rt5514_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5514_dapm_widgets),
+	.dapm_routes		= rt5514_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5514_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt5514_i2c_regmap = {
+	.name = "i2c",
+	.reg_bits = 32,
+	.val_bits = 32,
+
+	.readable_reg = rt5514_i2c_readable_register,
+
+	.cache_type = REGCACHE_NONE,
+};
+
+static const struct regmap_config rt5514_regmap = {
+	.reg_bits = 16,
+	.val_bits = 32,
+
+	.max_register = RT5514_VENDOR_ID2,
+	.volatile_reg = rt5514_volatile_register,
+	.readable_reg = rt5514_readable_register,
+	.reg_read = rt5514_i2c_read,
+	.reg_write = rt5514_i2c_write,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5514_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5514_reg),
+	.use_single_rw = true,
+};
+
+static const struct i2c_device_id rt5514_i2c_id[] = {
+	{ "rt5514", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt5514_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rt5514_of_match[] = {
+	{ .compatible = "realtek,rt5514", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5514_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5514_acpi_match[] = {
+	{ "10EC5514", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, rt5514_acpi_match);
+#endif
+
+static int rt5514_parse_dp(struct rt5514_priv *rt5514, struct device *dev)
+{
+	device_property_read_u32(dev, "realtek,dmic-init-delay-ms",
+		&rt5514->pdata.dmic_init_delay);
+	device_property_read_string(dev, "realtek,dsp-calib-clk-name",
+		&rt5514->pdata.dsp_calib_clk_name);
+	device_property_read_u32(dev, "realtek,dsp-calib-clk-rate",
+		&rt5514->pdata.dsp_calib_clk_rate);
+
+	return 0;
+}
+
+static __maybe_unused int rt5514_i2c_resume(struct device *dev)
+{
+	struct rt5514_priv *rt5514 = dev_get_drvdata(dev);
+	unsigned int val;
+
+	/*
+	 * Add a bogus read to avoid rt5514's confusion after s2r in case it
+	 * saw glitches on the i2c lines and thought the other side sent a
+	 * start bit.
+	 */
+	regmap_read(rt5514->regmap, RT5514_VENDOR_ID2, &val);
+
+	return 0;
+}
+
+static int rt5514_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5514_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt5514_priv *rt5514;
+	int ret;
+	unsigned int val = ~0;
+
+	rt5514 = devm_kzalloc(&i2c->dev, sizeof(struct rt5514_priv),
+				GFP_KERNEL);
+	if (rt5514 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt5514);
+
+	if (pdata)
+		rt5514->pdata = *pdata;
+	else
+		rt5514_parse_dp(rt5514, &i2c->dev);
+
+	rt5514->i2c_regmap = devm_regmap_init_i2c(i2c, &rt5514_i2c_regmap);
+	if (IS_ERR(rt5514->i2c_regmap)) {
+		ret = PTR_ERR(rt5514->i2c_regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	rt5514->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt5514_regmap);
+	if (IS_ERR(rt5514->regmap)) {
+		ret = PTR_ERR(rt5514->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	/*
+	 * The rt5514 can get confused if the i2c lines glitch together, as
+	 * can happen at bootup as regulators are turned off and on.  If it's
+	 * in this glitched state the first i2c read will fail, so we'll give
+	 * it one change to retry.
+	 */
+	ret = regmap_read(rt5514->regmap, RT5514_VENDOR_ID2, &val);
+	if (ret || val != RT5514_DEVICE_ID)
+		ret = regmap_read(rt5514->regmap, RT5514_VENDOR_ID2, &val);
+	if (ret || val != RT5514_DEVICE_ID) {
+		dev_err(&i2c->dev,
+			"Device with ID register %x is not rt5514\n", val);
+		return -ENODEV;
+	}
+
+	ret = regmap_multi_reg_write(rt5514->i2c_regmap, rt5514_i2c_patch,
+				    ARRAY_SIZE(rt5514_i2c_patch));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply i2c_regmap patch: %d\n",
+			ret);
+
+	ret = regmap_register_patch(rt5514->regmap, rt5514_patch,
+				    ARRAY_SIZE(rt5514_patch));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	return devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_rt5514,
+			rt5514_dai, ARRAY_SIZE(rt5514_dai));
+}
+
+static const struct dev_pm_ops rt5514_i2_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(NULL, rt5514_i2c_resume)
+};
+
+static struct i2c_driver rt5514_i2c_driver = {
+	.driver = {
+		.name = "rt5514",
+		.acpi_match_table = ACPI_PTR(rt5514_acpi_match),
+		.of_match_table = of_match_ptr(rt5514_of_match),
+		.pm = &rt5514_i2_pm_ops,
+	},
+	.probe = rt5514_i2c_probe,
+	.id_table = rt5514_i2c_id,
+};
+module_i2c_driver(rt5514_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5514 driver");
+MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h
new file mode 100644
index 0000000..d1ef0b3
--- /dev/null
+++ b/sound/soc/codecs/rt5514.h
@@ -0,0 +1,289 @@
+/*
+ * rt5514.h  --  RT5514 ALSA SoC audio driver
+ *
+ * Copyright 2015 Realtek Microelectronics
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5514_H__
+#define __RT5514_H__
+
+#include <linux/clk.h>
+#include <sound/rt5514.h>
+
+#define RT5514_DEVICE_ID			0x10ec5514
+
+#define RT5514_RESET				0x2000
+#define RT5514_PWR_ANA1				0x2004
+#define RT5514_PWR_ANA2				0x2008
+#define RT5514_I2S_CTRL1			0x2010
+#define RT5514_I2S_CTRL2			0x2014
+#define RT5514_VAD_CTRL6			0x2030
+#define RT5514_EXT_VAD_CTRL			0x206c
+#define RT5514_DIG_IO_CTRL			0x2070
+#define RT5514_PAD_CTRL1			0x2080
+#define RT5514_DMIC_DATA_CTRL			0x20a0
+#define RT5514_DIG_SOURCE_CTRL			0x20a4
+#define RT5514_SRC_CTRL				0x20ac
+#define RT5514_DOWNFILTER2_CTRL1		0x20d0
+#define RT5514_PLL_SOURCE_CTRL			0x2100
+#define RT5514_CLK_CTRL1			0x2104
+#define RT5514_CLK_CTRL2			0x2108
+#define RT5514_PLL3_CALIB_CTRL1			0x2110
+#define RT5514_PLL3_CALIB_CTRL4			0x2120
+#define RT5514_PLL3_CALIB_CTRL5			0x2124
+#define RT5514_PLL3_CALIB_CTRL6			0x2128
+#define RT5514_DELAY_BUF_CTRL1			0x2140
+#define RT5514_DELAY_BUF_CTRL3			0x2148
+#define RT5514_ASRC_IN_CTRL1			0x2180
+#define RT5514_DOWNFILTER0_CTRL1		0x2190
+#define RT5514_DOWNFILTER0_CTRL2		0x2194
+#define RT5514_DOWNFILTER0_CTRL3		0x2198
+#define RT5514_DOWNFILTER1_CTRL1		0x21a0
+#define RT5514_DOWNFILTER1_CTRL2		0x21a4
+#define RT5514_DOWNFILTER1_CTRL3		0x21a8
+#define RT5514_ANA_CTRL_LDO10			0x2200
+#define RT5514_ANA_CTRL_LDO18_16		0x2204
+#define RT5514_ANA_CTRL_ADC12			0x2210
+#define RT5514_ANA_CTRL_ADC21			0x2214
+#define RT5514_ANA_CTRL_ADC22			0x2218
+#define RT5514_ANA_CTRL_ADC23			0x221c
+#define RT5514_ANA_CTRL_MICBST			0x2220
+#define RT5514_ANA_CTRL_ADCFED			0x2224
+#define RT5514_ANA_CTRL_INBUF			0x2228
+#define RT5514_ANA_CTRL_VREF			0x222c
+#define RT5514_ANA_CTRL_PLL3			0x2240
+#define RT5514_ANA_CTRL_PLL1_1			0x2260
+#define RT5514_ANA_CTRL_PLL1_2			0x2264
+#define RT5514_DMIC_LP_CTRL			0x2e00
+#define RT5514_MISC_CTRL_DSP			0x2e04
+#define RT5514_DSP_CTRL1			0x2f00
+#define RT5514_DSP_CTRL3			0x2f08
+#define RT5514_DSP_CTRL4			0x2f10
+#define RT5514_VENDOR_ID1			0x2ff0
+#define RT5514_VENDOR_ID2			0x2ff4
+
+#define RT5514_DSP_MAPPING			0x18000000
+
+/* RT5514_PWR_ANA1 (0x2004) */
+#define RT5514_POW_LDO18_IN			(0x1 << 5)
+#define RT5514_POW_LDO18_IN_BIT			5
+#define RT5514_POW_LDO18_ADC			(0x1 << 4)
+#define RT5514_POW_LDO18_ADC_BIT		4
+#define RT5514_POW_LDO21			(0x1 << 3)
+#define RT5514_POW_LDO21_BIT			3
+#define RT5514_POW_BG_LDO18_IN			(0x1 << 2)
+#define RT5514_POW_BG_LDO18_IN_BIT		2
+#define RT5514_POW_BG_LDO21			(0x1 << 1)
+#define RT5514_POW_BG_LDO21_BIT			1
+
+/* RT5514_PWR_ANA2 (0x2008) */
+#define RT5514_POW_PLL1				(0x1 << 18)
+#define RT5514_POW_PLL1_BIT			18
+#define RT5514_POW_PLL1_LDO			(0x1 << 16)
+#define RT5514_POW_PLL1_LDO_BIT			16
+#define RT5514_POW_BG_MBIAS			(0x1 << 15)
+#define RT5514_POW_BG_MBIAS_BIT			15
+#define RT5514_POW_MBIAS			(0x1 << 14)
+#define RT5514_POW_MBIAS_BIT			14
+#define RT5514_POW_VREF2			(0x1 << 13)
+#define RT5514_POW_VREF2_BIT			13
+#define RT5514_POW_VREF1			(0x1 << 12)
+#define RT5514_POW_VREF1_BIT			12
+#define RT5514_POWR_LDO16			(0x1 << 11)
+#define RT5514_POWR_LDO16_BIT			11
+#define RT5514_POWL_LDO16			(0x1 << 10)
+#define RT5514_POWL_LDO16_BIT			10
+#define RT5514_POW_ADC2				(0x1 << 9)
+#define RT5514_POW_ADC2_BIT			9
+#define RT5514_POW_INPUT_BUF			(0x1 << 8)
+#define RT5514_POW_INPUT_BUF_BIT		8
+#define RT5514_POW_ADC1_R			(0x1 << 7)
+#define RT5514_POW_ADC1_R_BIT			7
+#define RT5514_POW_ADC1_L			(0x1 << 6)
+#define RT5514_POW_ADC1_L_BIT			6
+#define RT5514_POW2_BSTR			(0x1 << 5)
+#define RT5514_POW2_BSTR_BIT			5
+#define RT5514_POW2_BSTL			(0x1 << 4)
+#define RT5514_POW2_BSTL_BIT			4
+#define RT5514_POW_BSTR				(0x1 << 3)
+#define RT5514_POW_BSTR_BIT			3
+#define RT5514_POW_BSTL				(0x1 << 2)
+#define RT5514_POW_BSTL_BIT			2
+#define RT5514_POW_ADCFEDR			(0x1 << 1)
+#define RT5514_POW_ADCFEDR_BIT			1
+#define RT5514_POW_ADCFEDL			(0x1 << 0)
+#define RT5514_POW_ADCFEDL_BIT			0
+
+/* RT5514_I2S_CTRL1 (0x2010) */
+#define RT5514_TDM_MODE2			(0x1 << 30)
+#define RT5514_TDM_MODE2_SFT			30
+#define RT5514_TDM_MODE				(0x1 << 28)
+#define RT5514_TDM_MODE_SFT			28
+#define RT5514_I2S_LR_MASK			(0x1 << 26)
+#define RT5514_I2S_LR_SFT			26
+#define RT5514_I2S_LR_NOR			(0x0 << 26)
+#define RT5514_I2S_LR_INV			(0x1 << 26)
+#define RT5514_I2S_BP_MASK			(0x1 << 25)
+#define RT5514_I2S_BP_SFT			25
+#define RT5514_I2S_BP_NOR			(0x0 << 25)
+#define RT5514_I2S_BP_INV			(0x1 << 25)
+#define RT5514_I2S_DF_MASK			(0x7 << 16)
+#define RT5514_I2S_DF_SFT			16
+#define RT5514_I2S_DF_I2S			(0x0 << 16)
+#define RT5514_I2S_DF_LEFT			(0x1 << 16)
+#define RT5514_I2S_DF_PCM_A			(0x2 << 16)
+#define RT5514_I2S_DF_PCM_B			(0x3 << 16)
+#define RT5514_TDMSLOT_SEL_RX_MASK		(0x3 << 10)
+#define RT5514_TDMSLOT_SEL_RX_SFT		10
+#define RT5514_TDMSLOT_SEL_RX_4CH		(0x1 << 10)
+#define RT5514_TDMSLOT_SEL_RX_6CH		(0x2 << 10)
+#define RT5514_TDMSLOT_SEL_RX_8CH		(0x3 << 10)
+#define RT5514_CH_LEN_RX_MASK			(0x3 << 8)
+#define RT5514_CH_LEN_RX_SFT			8
+#define RT5514_CH_LEN_RX_16			(0x0 << 8)
+#define RT5514_CH_LEN_RX_20			(0x1 << 8)
+#define RT5514_CH_LEN_RX_24			(0x2 << 8)
+#define RT5514_CH_LEN_RX_32			(0x3 << 8)
+#define RT5514_TDMSLOT_SEL_TX_MASK		(0x3 << 6)
+#define RT5514_TDMSLOT_SEL_TX_SFT		6
+#define RT5514_TDMSLOT_SEL_TX_4CH		(0x1 << 6)
+#define RT5514_TDMSLOT_SEL_TX_6CH		(0x2 << 6)
+#define RT5514_TDMSLOT_SEL_TX_8CH		(0x3 << 6)
+#define RT5514_CH_LEN_TX_MASK			(0x3 << 4)
+#define RT5514_CH_LEN_TX_SFT			4
+#define RT5514_CH_LEN_TX_16			(0x0 << 4)
+#define RT5514_CH_LEN_TX_20			(0x1 << 4)
+#define RT5514_CH_LEN_TX_24			(0x2 << 4)
+#define RT5514_CH_LEN_TX_32			(0x3 << 4)
+#define RT5514_I2S_DL_MASK			(0x3 << 0)
+#define RT5514_I2S_DL_SFT			0
+#define RT5514_I2S_DL_16			(0x0 << 0)
+#define RT5514_I2S_DL_20			(0x1 << 0)
+#define RT5514_I2S_DL_24			(0x2 << 0)
+#define RT5514_I2S_DL_8				(0x3 << 0)
+
+/* RT5514_I2S_CTRL2 (0x2014) */
+#define RT5514_TDM_DOCKING_MODE			(0x1 << 31)
+#define RT5514_TDM_DOCKING_MODE_SFT		31
+#define RT5514_TDM_DOCKING_VALID_CH_MASK	(0x1 << 29)
+#define RT5514_TDM_DOCKING_VALID_CH_SFT		29
+#define RT5514_TDM_DOCKING_VALID_CH2		(0x0 << 29)
+#define RT5514_TDM_DOCKING_VALID_CH4		(0x1 << 29)
+#define RT5514_TDM_DOCKING_START_MASK		(0x1 << 28)
+#define RT5514_TDM_DOCKING_START_SFT		28
+#define RT5514_TDM_DOCKING_START_SLOT0		(0x0 << 28)
+#define RT5514_TDM_DOCKING_START_SLOT4		(0x1 << 28)
+
+/* RT5514_DIG_SOURCE_CTRL (0x20a4) */
+#define RT5514_AD1_DMIC_INPUT_SEL		(0x1 << 1)
+#define RT5514_AD1_DMIC_INPUT_SEL_SFT		1
+#define RT5514_AD0_DMIC_INPUT_SEL		(0x1 << 0)
+#define RT5514_AD0_DMIC_INPUT_SEL_SFT		0
+
+/* RT5514_PLL_SOURCE_CTRL (0x2100) */
+#define RT5514_PLL_1_SEL_MASK			(0x7 << 12)
+#define RT5514_PLL_1_SEL_SFT			12
+#define RT5514_PLL_1_SEL_SCLK			(0x3 << 12)
+#define RT5514_PLL_1_SEL_MCLK			(0x4 << 12)
+
+/* RT5514_CLK_CTRL1 (0x2104) */
+#define RT5514_CLK_AD_ANA1_EN			(0x1 << 31)
+#define RT5514_CLK_AD_ANA1_EN_BIT		31
+#define RT5514_CLK_AD1_EN			(0x1 << 24)
+#define RT5514_CLK_AD1_EN_BIT			24
+#define RT5514_CLK_AD0_EN			(0x1 << 23)
+#define RT5514_CLK_AD0_EN_BIT			23
+#define RT5514_CLK_DMIC_OUT_SEL_MASK		(0x7 << 8)
+#define RT5514_CLK_DMIC_OUT_SEL_SFT		8
+#define RT5514_CLK_AD_ANA1_SEL_MASK		(0xf << 0)
+#define RT5514_CLK_AD_ANA1_SEL_SFT		0
+
+/* RT5514_CLK_CTRL2 (0x2108) */
+#define RT5514_CLK_AD1_ASRC_EN			(0x1 << 17)
+#define RT5514_CLK_AD1_ASRC_EN_BIT		17
+#define RT5514_CLK_AD0_ASRC_EN			(0x1 << 16)
+#define RT5514_CLK_AD0_ASRC_EN_BIT		16
+#define RT5514_CLK_SYS_DIV_OUT_MASK		(0x7 << 8)
+#define RT5514_CLK_SYS_DIV_OUT_SFT		8
+#define RT5514_SEL_ADC_OSR_MASK			(0x7 << 4)
+#define RT5514_SEL_ADC_OSR_SFT			4
+#define RT5514_CLK_SYS_PRE_SEL_MASK		(0x3 << 0)
+#define RT5514_CLK_SYS_PRE_SEL_SFT		0
+#define RT5514_CLK_SYS_PRE_SEL_MCLK		(0x2 << 0)
+#define RT5514_CLK_SYS_PRE_SEL_PLL		(0x3 << 0)
+
+/*  RT5514_DOWNFILTER_CTRL (0x2190 0x2194 0x21a0 0x21a4) */
+#define RT5514_AD_DMIC_MIX			(0x1 << 11)
+#define RT5514_AD_DMIC_MIX_BIT			11
+#define RT5514_AD_AD_MIX			(0x1 << 10)
+#define RT5514_AD_AD_MIX_BIT			10
+#define RT5514_AD_AD_MUTE			(0x1 << 7)
+#define RT5514_AD_AD_MUTE_BIT			7
+#define RT5514_AD_GAIN_MASK			(0x3f << 1)
+#define RT5514_AD_GAIN_SFT			1
+
+/*  RT5514_ANA_CTRL_MICBST (0x2220) */
+#define RT5514_SEL_BSTL_MASK			(0xf << 4)
+#define RT5514_SEL_BSTL_SFT			4
+#define RT5514_SEL_BSTR_MASK			(0xf << 0)
+#define RT5514_SEL_BSTR_SFT			0
+
+/*  RT5514_ANA_CTRL_PLL1_1 (0x2260) */
+#define RT5514_PLL_K_MAX			0x1f
+#define RT5514_PLL_K_MASK			(RT5514_PLL_K_MAX << 16)
+#define RT5514_PLL_K_SFT			16
+#define RT5514_PLL_N_MAX			0x1ff
+#define RT5514_PLL_N_MASK			(RT5514_PLL_N_MAX << 7)
+#define RT5514_PLL_N_SFT			4
+#define RT5514_PLL_M_MAX			0xf
+#define RT5514_PLL_M_MASK			(RT5514_PLL_M_MAX << 0)
+#define RT5514_PLL_M_SFT			0
+
+/*  RT5514_ANA_CTRL_PLL1_2 (0x2264) */
+#define RT5514_PLL_M_BP				(0x1 << 2)
+#define RT5514_PLL_M_BP_SFT			2
+#define RT5514_PLL_K_BP				(0x1 << 1)
+#define RT5514_PLL_K_BP_SFT			1
+#define RT5514_EN_LDO_PLL1			(0x1 << 0)
+#define RT5514_EN_LDO_PLL1_BIT			0
+
+#define RT5514_PLL_INP_MAX			40000000
+#define RT5514_PLL_INP_MIN			256000
+
+#define RT5514_FIRMWARE1	"rt5514_dsp_fw1.bin"
+#define RT5514_FIRMWARE2	"rt5514_dsp_fw2.bin"
+
+/* System Clock Source */
+enum {
+	RT5514_SCLK_S_MCLK,
+	RT5514_SCLK_S_PLL1,
+};
+
+/* PLL1 Source */
+enum {
+	RT5514_PLL1_S_MCLK,
+	RT5514_PLL1_S_BCLK,
+};
+
+struct rt5514_priv {
+	struct rt5514_platform_data pdata;
+	struct snd_soc_component *component;
+	struct regmap *i2c_regmap, *regmap;
+	struct clk *mclk, *dsp_calib_clk;
+	int sysclk;
+	int sysclk_src;
+	int lrck;
+	int bclk;
+	int pll_src;
+	int pll_in;
+	int pll_out;
+	int dsp_enabled;
+	unsigned int pll3_cal_value;
+};
+
+#endif /* __RT5514_H__ */
diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c
new file mode 100644
index 0000000..3dc795f
--- /dev/null
+++ b/sound/soc/codecs/rt5616.c
@@ -0,0 +1,1422 @@
+/*
+ * rt5616.c  --  RT5616 ALSA SoC audio codec driver
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rl6231.h"
+#include "rt5616.h"
+
+#define RT5616_PR_RANGE_BASE (0xff + 1)
+#define RT5616_PR_SPACING 0x100
+
+#define RT5616_PR_BASE (RT5616_PR_RANGE_BASE + (0 * RT5616_PR_SPACING))
+
+static const struct regmap_range_cfg rt5616_ranges[] = {
+	{
+		.name = "PR",
+		.range_min = RT5616_PR_BASE,
+		.range_max = RT5616_PR_BASE + 0xf8,
+		.selector_reg = RT5616_PRIV_INDEX,
+		.selector_mask = 0xff,
+		.selector_shift = 0x0,
+		.window_start = RT5616_PRIV_DATA,
+		.window_len = 0x1,
+	},
+};
+
+static const struct reg_sequence init_list[] = {
+	{RT5616_PR_BASE + 0x3d,	0x3e00},
+	{RT5616_PR_BASE + 0x25,	0x6110},
+	{RT5616_PR_BASE + 0x20,	0x611f},
+	{RT5616_PR_BASE + 0x21,	0x4040},
+	{RT5616_PR_BASE + 0x23,	0x0004},
+};
+
+#define RT5616_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+static const struct reg_default rt5616_reg[] = {
+	{ 0x00, 0x0021 },
+	{ 0x02, 0xc8c8 },
+	{ 0x03, 0xc8c8 },
+	{ 0x05, 0x0000 },
+	{ 0x0d, 0x0000 },
+	{ 0x0f, 0x0808 },
+	{ 0x19, 0xafaf },
+	{ 0x1c, 0x2f2f },
+	{ 0x1e, 0x0000 },
+	{ 0x27, 0x7860 },
+	{ 0x29, 0x8080 },
+	{ 0x2a, 0x5252 },
+	{ 0x3b, 0x0000 },
+	{ 0x3c, 0x006f },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x006f },
+	{ 0x45, 0x6000 },
+	{ 0x4d, 0x0000 },
+	{ 0x4e, 0x0000 },
+	{ 0x4f, 0x0279 },
+	{ 0x50, 0x0000 },
+	{ 0x51, 0x0000 },
+	{ 0x52, 0x0279 },
+	{ 0x53, 0xf000 },
+	{ 0x61, 0x0000 },
+	{ 0x62, 0x0000 },
+	{ 0x63, 0x00c0 },
+	{ 0x64, 0x0000 },
+	{ 0x65, 0x0000 },
+	{ 0x66, 0x0000 },
+	{ 0x70, 0x8000 },
+	{ 0x73, 0x1104 },
+	{ 0x74, 0x0c00 },
+	{ 0x80, 0x0000 },
+	{ 0x81, 0x0000 },
+	{ 0x82, 0x0000 },
+	{ 0x8b, 0x0600 },
+	{ 0x8e, 0x0004 },
+	{ 0x8f, 0x1100 },
+	{ 0x90, 0x0000 },
+	{ 0x91, 0x0c00 },
+	{ 0x92, 0x0000 },
+	{ 0x93, 0x2000 },
+	{ 0x94, 0x0200 },
+	{ 0x95, 0x0000 },
+	{ 0xb0, 0x2080 },
+	{ 0xb1, 0x0000 },
+	{ 0xb2, 0x0000 },
+	{ 0xb4, 0x2206 },
+	{ 0xb5, 0x1f00 },
+	{ 0xb6, 0x0000 },
+	{ 0xb7, 0x0000 },
+	{ 0xbb, 0x0000 },
+	{ 0xbc, 0x0000 },
+	{ 0xbd, 0x0000 },
+	{ 0xbe, 0x0000 },
+	{ 0xbf, 0x0000 },
+	{ 0xc0, 0x0100 },
+	{ 0xc1, 0x0000 },
+	{ 0xc2, 0x0000 },
+	{ 0xc8, 0x0000 },
+	{ 0xc9, 0x0000 },
+	{ 0xca, 0x0000 },
+	{ 0xcb, 0x0000 },
+	{ 0xcc, 0x0000 },
+	{ 0xcd, 0x0000 },
+	{ 0xce, 0x0000 },
+	{ 0xcf, 0x0013 },
+	{ 0xd0, 0x0680 },
+	{ 0xd1, 0x1c17 },
+	{ 0xd3, 0xb320 },
+	{ 0xd4, 0x0000 },
+	{ 0xd6, 0x0000 },
+	{ 0xd7, 0x0000 },
+	{ 0xd9, 0x0809 },
+	{ 0xda, 0x0000 },
+	{ 0xfa, 0x0010 },
+	{ 0xfb, 0x0000 },
+	{ 0xfc, 0x0000 },
+	{ 0xfe, 0x10ec },
+	{ 0xff, 0x6281 },
+};
+
+struct rt5616_priv {
+	struct snd_soc_component *component;
+	struct delayed_work patch_work;
+	struct regmap *regmap;
+	struct clk *mclk;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5616_AIFS];
+	int bclk[RT5616_AIFS];
+	int master[RT5616_AIFS];
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+};
+
+static bool rt5616_volatile_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5616_ranges); i++) {
+		if (reg >= rt5616_ranges[i].range_min &&
+		    reg <= rt5616_ranges[i].range_max)
+			return true;
+	}
+
+	switch (reg) {
+	case RT5616_RESET:
+	case RT5616_PRIV_DATA:
+	case RT5616_EQ_CTRL1:
+	case RT5616_DRC_AGC_1:
+	case RT5616_IRQ_CTRL2:
+	case RT5616_INT_IRQ_ST:
+	case RT5616_PGM_REG_ARR1:
+	case RT5616_PGM_REG_ARR3:
+	case RT5616_VENDOR_ID:
+	case RT5616_DEVICE_ID:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5616_readable_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5616_ranges); i++) {
+		if (reg >= rt5616_ranges[i].range_min &&
+		    reg <= rt5616_ranges[i].range_max)
+			return true;
+	}
+
+	switch (reg) {
+	case RT5616_RESET:
+	case RT5616_VERSION_ID:
+	case RT5616_VENDOR_ID:
+	case RT5616_DEVICE_ID:
+	case RT5616_HP_VOL:
+	case RT5616_LOUT_CTRL1:
+	case RT5616_LOUT_CTRL2:
+	case RT5616_IN1_IN2:
+	case RT5616_INL1_INR1_VOL:
+	case RT5616_DAC1_DIG_VOL:
+	case RT5616_ADC_DIG_VOL:
+	case RT5616_ADC_BST_VOL:
+	case RT5616_STO1_ADC_MIXER:
+	case RT5616_AD_DA_MIXER:
+	case RT5616_STO_DAC_MIXER:
+	case RT5616_REC_L1_MIXER:
+	case RT5616_REC_L2_MIXER:
+	case RT5616_REC_R1_MIXER:
+	case RT5616_REC_R2_MIXER:
+	case RT5616_HPO_MIXER:
+	case RT5616_OUT_L1_MIXER:
+	case RT5616_OUT_L2_MIXER:
+	case RT5616_OUT_L3_MIXER:
+	case RT5616_OUT_R1_MIXER:
+	case RT5616_OUT_R2_MIXER:
+	case RT5616_OUT_R3_MIXER:
+	case RT5616_LOUT_MIXER:
+	case RT5616_PWR_DIG1:
+	case RT5616_PWR_DIG2:
+	case RT5616_PWR_ANLG1:
+	case RT5616_PWR_ANLG2:
+	case RT5616_PWR_MIXER:
+	case RT5616_PWR_VOL:
+	case RT5616_PRIV_INDEX:
+	case RT5616_PRIV_DATA:
+	case RT5616_I2S1_SDP:
+	case RT5616_ADDA_CLK1:
+	case RT5616_ADDA_CLK2:
+	case RT5616_GLB_CLK:
+	case RT5616_PLL_CTRL1:
+	case RT5616_PLL_CTRL2:
+	case RT5616_HP_OVCD:
+	case RT5616_DEPOP_M1:
+	case RT5616_DEPOP_M2:
+	case RT5616_DEPOP_M3:
+	case RT5616_CHARGE_PUMP:
+	case RT5616_PV_DET_SPK_G:
+	case RT5616_MICBIAS:
+	case RT5616_A_JD_CTL1:
+	case RT5616_A_JD_CTL2:
+	case RT5616_EQ_CTRL1:
+	case RT5616_EQ_CTRL2:
+	case RT5616_WIND_FILTER:
+	case RT5616_DRC_AGC_1:
+	case RT5616_DRC_AGC_2:
+	case RT5616_DRC_AGC_3:
+	case RT5616_SVOL_ZC:
+	case RT5616_JD_CTRL1:
+	case RT5616_JD_CTRL2:
+	case RT5616_IRQ_CTRL1:
+	case RT5616_IRQ_CTRL2:
+	case RT5616_INT_IRQ_ST:
+	case RT5616_GPIO_CTRL1:
+	case RT5616_GPIO_CTRL2:
+	case RT5616_GPIO_CTRL3:
+	case RT5616_PGM_REG_ARR1:
+	case RT5616_PGM_REG_ARR2:
+	case RT5616_PGM_REG_ARR3:
+	case RT5616_PGM_REG_ARR4:
+	case RT5616_PGM_REG_ARR5:
+	case RT5616_SCB_FUNC:
+	case RT5616_SCB_CTRL:
+	case RT5616_BASE_BACK:
+	case RT5616_MP3_PLUS1:
+	case RT5616_MP3_PLUS2:
+	case RT5616_ADJ_HPF_CTRL1:
+	case RT5616_ADJ_HPF_CTRL2:
+	case RT5616_HP_CALIB_AMP_DET:
+	case RT5616_HP_CALIB2:
+	case RT5616_SV_ZCD1:
+	case RT5616_SV_ZCD2:
+	case RT5616_D_MISC:
+	case RT5616_DUMMY2:
+	case RT5616_DUMMY3:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(bst_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
+);
+
+static const struct snd_kcontrol_new rt5616_snd_controls[] = {
+	/* Headphone Output Volume */
+	SOC_DOUBLE("HP Playback Switch", RT5616_HP_VOL,
+		   RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE("HPVOL Playback Switch", RT5616_HP_VOL,
+		   RT5616_VOL_L_SFT, RT5616_VOL_R_SFT, 1, 1),
+	SOC_DOUBLE_TLV("HP Playback Volume", RT5616_HP_VOL,
+		       RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv),
+	/* OUTPUT Control */
+	SOC_DOUBLE("OUT Playback Switch", RT5616_LOUT_CTRL1,
+		   RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE("OUT Channel Switch", RT5616_LOUT_CTRL1,
+		   RT5616_VOL_L_SFT, RT5616_VOL_R_SFT, 1, 1),
+	SOC_DOUBLE_TLV("OUT Playback Volume", RT5616_LOUT_CTRL1,
+		       RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5616_DAC1_DIG_VOL,
+		       RT5616_L_VOL_SFT, RT5616_R_VOL_SFT,
+		       175, 0, dac_vol_tlv),
+	/* IN1/IN2 Control */
+	SOC_SINGLE_TLV("IN1 Boost Volume", RT5616_IN1_IN2,
+		       RT5616_BST_SFT1, 8, 0, bst_tlv),
+	SOC_SINGLE_TLV("IN2 Boost Volume", RT5616_IN1_IN2,
+		       RT5616_BST_SFT2, 8, 0, bst_tlv),
+	/* INL/INR Volume Control */
+	SOC_DOUBLE_TLV("IN Capture Volume", RT5616_INL1_INR1_VOL,
+		       RT5616_INL_VOL_SFT, RT5616_INR_VOL_SFT,
+		       31, 1, in_vol_tlv),
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("ADC Capture Switch", RT5616_ADC_DIG_VOL,
+		   RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("ADC Capture Volume", RT5616_ADC_DIG_VOL,
+		       RT5616_L_VOL_SFT, RT5616_R_VOL_SFT,
+		       127, 0, adc_vol_tlv),
+
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("ADC Boost Volume", RT5616_ADC_BST_VOL,
+		       RT5616_ADC_L_BST_SFT, RT5616_ADC_R_BST_SFT,
+		       3, 0, adc_bst_tlv),
+};
+
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+			       struct snd_soc_dapm_widget *sink)
+{
+	unsigned int val;
+
+	val = snd_soc_component_read32(snd_soc_dapm_to_component(source->dapm), RT5616_GLB_CLK);
+	val &= RT5616_SCLK_SRC_MASK;
+	if (val == RT5616_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5616_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5616_STO1_ADC_MIXER,
+			RT5616_M_STO1_ADC_L1_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5616_STO1_ADC_MIXER,
+			RT5616_M_STO1_ADC_R1_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5616_AD_DA_MIXER,
+			RT5616_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INF1 Switch", RT5616_AD_DA_MIXER,
+			RT5616_M_IF1_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5616_AD_DA_MIXER,
+			RT5616_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INF1 Switch", RT5616_AD_DA_MIXER,
+			RT5616_M_IF1_DAC_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_sto_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_STO_DAC_MIXER,
+			RT5616_M_DAC_L1_MIXL_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_STO_DAC_MIXER,
+			RT5616_M_DAC_R1_MIXL_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_sto_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_STO_DAC_MIXER,
+			RT5616_M_DAC_R1_MIXR_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_STO_DAC_MIXER,
+			RT5616_M_DAC_L1_MIXR_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5616_rec_l_mix[] = {
+	SOC_DAPM_SINGLE("INL1 Switch", RT5616_REC_L2_MIXER,
+			RT5616_M_IN1_L_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5616_REC_L2_MIXER,
+			RT5616_M_BST2_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5616_REC_L2_MIXER,
+			RT5616_M_BST1_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_rec_r_mix[] = {
+	SOC_DAPM_SINGLE("INR1 Switch", RT5616_REC_R2_MIXER,
+			RT5616_M_IN1_R_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5616_REC_R2_MIXER,
+			RT5616_M_BST2_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5616_REC_R2_MIXER,
+			RT5616_M_BST1_RM_R_SFT, 1, 1),
+};
+
+/* Analog Output Mixer */
+
+static const struct snd_kcontrol_new rt5616_out_l_mix[] = {
+	SOC_DAPM_SINGLE("BST1 Switch", RT5616_OUT_L3_MIXER,
+			RT5616_M_BST1_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5616_OUT_L3_MIXER,
+			RT5616_M_BST2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL1 Switch", RT5616_OUT_L3_MIXER,
+			RT5616_M_IN1_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("REC MIXL Switch", RT5616_OUT_L3_MIXER,
+			RT5616_M_RM_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_OUT_L3_MIXER,
+			RT5616_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_out_r_mix[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5616_OUT_R3_MIXER,
+			RT5616_M_BST2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5616_OUT_R3_MIXER,
+			RT5616_M_BST1_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR1 Switch", RT5616_OUT_R3_MIXER,
+			RT5616_M_IN1_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("REC MIXR Switch", RT5616_OUT_R3_MIXER,
+			RT5616_M_RM_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_OUT_R3_MIXER,
+			RT5616_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_hpo_mix[] = {
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5616_HPO_MIXER,
+			RT5616_M_DAC1_HM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("HPVOL Switch", RT5616_HPO_MIXER,
+			RT5616_M_HPVOL_HM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_lout_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_LOUT_MIXER,
+			RT5616_M_DAC_L1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_LOUT_MIXER,
+			RT5616_M_DAC_R1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL L Switch", RT5616_LOUT_MIXER,
+			RT5616_M_OV_L_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL R Switch", RT5616_LOUT_MIXER,
+			RT5616_M_OV_R_LM_SFT, 1, 1),
+};
+
+static int rt5616_adc_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5616_ADC_DIG_VOL,
+				    RT5616_L_MUTE | RT5616_R_MUTE, 0);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, RT5616_ADC_DIG_VOL,
+				    RT5616_L_MUTE | RT5616_R_MUTE,
+				    RT5616_L_MUTE | RT5616_R_MUTE);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5616_charge_pump_event(struct snd_soc_dapm_widget *w,
+				    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* depop parameters */
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M2,
+				    RT5616_DEPOP_MASK, RT5616_DEPOP_MAN);
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
+				    RT5616_HP_CP_MASK | RT5616_HP_SG_MASK |
+				    RT5616_HP_CB_MASK, RT5616_HP_CP_PU |
+				    RT5616_HP_SG_DIS | RT5616_HP_CB_PU);
+		snd_soc_component_write(component, RT5616_PR_BASE +
+			      RT5616_HP_DCC_INT1, 0x9f00);
+		/* headphone amp power on */
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
+				    RT5616_PWR_FV1 | RT5616_PWR_FV2, 0);
+		snd_soc_component_update_bits(component, RT5616_PWR_VOL,
+				    RT5616_PWR_HV_L | RT5616_PWR_HV_R,
+				    RT5616_PWR_HV_L | RT5616_PWR_HV_R);
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
+				    RT5616_PWR_HP_L | RT5616_PWR_HP_R |
+				    RT5616_PWR_HA, RT5616_PWR_HP_L |
+				    RT5616_PWR_HP_R | RT5616_PWR_HA);
+		msleep(50);
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
+				    RT5616_PWR_FV1 | RT5616_PWR_FV2,
+				    RT5616_PWR_FV1 | RT5616_PWR_FV2);
+
+		snd_soc_component_update_bits(component, RT5616_CHARGE_PUMP,
+				    RT5616_PM_HP_MASK, RT5616_PM_HP_HV);
+		snd_soc_component_update_bits(component, RT5616_PR_BASE +
+				    RT5616_CHOP_DAC_ADC, 0x0200, 0x0200);
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
+				    RT5616_HP_CO_MASK | RT5616_HP_SG_MASK,
+				    RT5616_HP_CO_EN | RT5616_HP_SG_EN);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5616_PR_BASE +
+				    RT5616_CHOP_DAC_ADC, 0x0200, 0x0);
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
+				    RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK |
+				    RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS |
+				    RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS);
+		/* headphone amp power down */
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
+				    RT5616_SMT_TRIG_MASK |
+				    RT5616_HP_CD_PD_MASK | RT5616_HP_CO_MASK |
+				    RT5616_HP_CP_MASK | RT5616_HP_SG_MASK |
+				    RT5616_HP_CB_MASK,
+				    RT5616_SMT_TRIG_DIS | RT5616_HP_CD_PD_EN |
+				    RT5616_HP_CO_DIS | RT5616_HP_CP_PD |
+				    RT5616_HP_SG_EN | RT5616_HP_CB_PD);
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
+				    RT5616_PWR_HP_L | RT5616_PWR_HP_R |
+				    RT5616_PWR_HA, 0);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5616_hp_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* headphone unmute sequence */
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M3,
+				    RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK |
+				    RT5616_CP_FQ3_MASK,
+				    RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ1_SFT |
+				    RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT |
+				    RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ3_SFT);
+		snd_soc_component_write(component, RT5616_PR_BASE +
+			      RT5616_MAMP_INT_REG2, 0xfc00);
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
+				    RT5616_SMT_TRIG_MASK, RT5616_SMT_TRIG_EN);
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
+				    RT5616_RSTN_MASK, RT5616_RSTN_EN);
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
+				    RT5616_RSTN_MASK | RT5616_HP_L_SMT_MASK |
+				    RT5616_HP_R_SMT_MASK, RT5616_RSTN_DIS |
+				    RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN);
+		snd_soc_component_update_bits(component, RT5616_HP_VOL,
+				    RT5616_L_MUTE | RT5616_R_MUTE, 0);
+		msleep(100);
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
+				    RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK |
+				    RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS |
+				    RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS);
+		msleep(20);
+		snd_soc_component_update_bits(component, RT5616_HP_CALIB_AMP_DET,
+				    RT5616_HPD_PS_MASK, RT5616_HPD_PS_EN);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		/* headphone mute sequence */
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M3,
+				    RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK |
+				    RT5616_CP_FQ3_MASK,
+				    RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ1_SFT |
+				    RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT |
+				    RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ3_SFT);
+		snd_soc_component_write(component, RT5616_PR_BASE +
+			      RT5616_MAMP_INT_REG2, 0xfc00);
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
+				    RT5616_HP_SG_MASK, RT5616_HP_SG_EN);
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
+				    RT5616_RSTP_MASK, RT5616_RSTP_EN);
+		snd_soc_component_update_bits(component, RT5616_DEPOP_M1,
+				    RT5616_RSTP_MASK | RT5616_HP_L_SMT_MASK |
+				    RT5616_HP_R_SMT_MASK, RT5616_RSTP_DIS |
+				    RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN);
+		snd_soc_component_update_bits(component, RT5616_HP_CALIB_AMP_DET,
+				    RT5616_HPD_PS_MASK, RT5616_HPD_PS_DIS);
+		msleep(90);
+		snd_soc_component_update_bits(component, RT5616_HP_VOL,
+				    RT5616_L_MUTE | RT5616_R_MUTE,
+				    RT5616_L_MUTE | RT5616_R_MUTE);
+		msleep(30);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5616_lout_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
+				    RT5616_PWR_LM, RT5616_PWR_LM);
+		snd_soc_component_update_bits(component, RT5616_LOUT_CTRL1,
+				    RT5616_L_MUTE | RT5616_R_MUTE, 0);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5616_LOUT_CTRL1,
+				    RT5616_L_MUTE | RT5616_R_MUTE,
+				    RT5616_L_MUTE | RT5616_R_MUTE);
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
+				    RT5616_PWR_LM, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5616_bst1_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG2,
+				    RT5616_PWR_BST1_OP2, RT5616_PWR_BST1_OP2);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG2,
+				    RT5616_PWR_BST1_OP2, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5616_bst2_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG2,
+				    RT5616_PWR_BST2_OP2, RT5616_PWR_BST2_OP2);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5616_PWR_ANLG2,
+				    RT5616_PWR_BST2_OP2, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5616_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("PLL1", RT5616_PWR_ANLG2,
+			    RT5616_PWR_PLL_BIT, 0, NULL, 0),
+	/* Input Side */
+	/* micbias */
+	SND_SOC_DAPM_SUPPLY("LDO", RT5616_PWR_ANLG1,
+			    RT5616_PWR_LDO_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("micbias1", RT5616_PWR_ANLG2,
+			    RT5616_PWR_MB1_BIT, 0, NULL, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN2N"),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA_E("BST1", RT5616_PWR_ANLG2,
+			   RT5616_PWR_BST1_BIT, 0, NULL, 0, rt5616_bst1_event,
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_E("BST2", RT5616_PWR_ANLG2,
+			   RT5616_PWR_BST2_BIT, 0, NULL, 0, rt5616_bst2_event,
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	/* Input Volume */
+	SND_SOC_DAPM_PGA("INL1 VOL", RT5616_PWR_VOL,
+			 RT5616_PWR_IN1_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR1 VOL", RT5616_PWR_VOL,
+			 RT5616_PWR_IN1_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INL2 VOL", RT5616_PWR_VOL,
+			 RT5616_PWR_IN2_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR2 VOL", RT5616_PWR_VOL,
+			 RT5616_PWR_IN2_R_BIT, 0, NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIXL", RT5616_PWR_MIXER, RT5616_PWR_RM_L_BIT, 0,
+			   rt5616_rec_l_mix, ARRAY_SIZE(rt5616_rec_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIXR", RT5616_PWR_MIXER, RT5616_PWR_RM_R_BIT, 0,
+			   rt5616_rec_r_mix, ARRAY_SIZE(rt5616_rec_r_mix)),
+	/* ADCs */
+	SND_SOC_DAPM_ADC_E("ADC L", NULL, RT5616_PWR_DIG1,
+			   RT5616_PWR_ADC_L_BIT, 0, rt5616_adc_event,
+			   SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_ADC_E("ADC R", NULL, RT5616_PWR_DIG1,
+			   RT5616_PWR_ADC_R_BIT, 0, rt5616_adc_event,
+			   SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("stereo1 filter", RT5616_PWR_DIG2,
+			    RT5616_PWR_ADC_STO1_F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+			   rt5616_sto1_adc_l_mix,
+			   ARRAY_SIZE(rt5616_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+			   rt5616_sto1_adc_r_mix,
+			   ARRAY_SIZE(rt5616_sto1_adc_r_mix)),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5616_PWR_DIG1,
+			    RT5616_PWR_I2S1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface Select */
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Audio DSP */
+	SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Output Side */
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
+			   rt5616_dac_l_mix, ARRAY_SIZE(rt5616_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
+			   rt5616_dac_r_mix, ARRAY_SIZE(rt5616_dac_r_mix)),
+
+	SND_SOC_DAPM_SUPPLY("Stero1 DAC Power", RT5616_PWR_DIG2,
+			    RT5616_PWR_DAC_STO1_F_BIT, 0, NULL, 0),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+			   rt5616_sto_dac_l_mix,
+			   ARRAY_SIZE(rt5616_sto_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+			   rt5616_sto_dac_r_mix,
+			   ARRAY_SIZE(rt5616_sto_dac_r_mix)),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC L1", NULL, RT5616_PWR_DIG1,
+			 RT5616_PWR_DAC_L1_BIT, 0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, RT5616_PWR_DIG1,
+			 RT5616_PWR_DAC_R1_BIT, 0),
+	/* OUT Mixer */
+	SND_SOC_DAPM_MIXER("OUT MIXL", RT5616_PWR_MIXER, RT5616_PWR_OM_L_BIT,
+			   0, rt5616_out_l_mix, ARRAY_SIZE(rt5616_out_l_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXR", RT5616_PWR_MIXER, RT5616_PWR_OM_R_BIT,
+			   0, rt5616_out_r_mix, ARRAY_SIZE(rt5616_out_r_mix)),
+	/* Output Volume */
+	SND_SOC_DAPM_PGA("OUTVOL L", RT5616_PWR_VOL,
+			 RT5616_PWR_OV_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OUTVOL R", RT5616_PWR_VOL,
+			 RT5616_PWR_OV_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HPOVOL L", RT5616_PWR_VOL,
+			 RT5616_PWR_HV_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HPOVOL R", RT5616_PWR_VOL,
+			 RT5616_PWR_HV_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM,
+			 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DAC 2", SND_SOC_NOPM,
+			 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HPOVOL", SND_SOC_NOPM,
+			 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INL1", RT5616_PWR_VOL,
+			 RT5616_PWR_IN1_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR1", RT5616_PWR_VOL,
+			 RT5616_PWR_IN1_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INL2", RT5616_PWR_VOL,
+			 RT5616_PWR_IN2_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR2", RT5616_PWR_VOL,
+			 RT5616_PWR_IN2_R_BIT, 0, NULL, 0),
+	/* HPO/LOUT/Mono Mixer */
+	SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0,
+			   rt5616_hpo_mix, ARRAY_SIZE(rt5616_hpo_mix)),
+	SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0,
+			   rt5616_lout_mix, ARRAY_SIZE(rt5616_lout_mix)),
+
+	SND_SOC_DAPM_PGA_S("HP amp", 1, SND_SOC_NOPM, 0, 0,
+			   rt5616_hp_event, SND_SOC_DAPM_PRE_PMD |
+			   SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0,
+			   rt5616_lout_event, SND_SOC_DAPM_PRE_PMD |
+			   SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, SND_SOC_NOPM, 0, 0,
+			      rt5616_charge_pump_event, SND_SOC_DAPM_POST_PMU |
+			      SND_SOC_DAPM_PRE_PMD),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+	SND_SOC_DAPM_OUTPUT("LOUTL"),
+	SND_SOC_DAPM_OUTPUT("LOUTR"),
+};
+
+static const struct snd_soc_dapm_route rt5616_dapm_routes[] = {
+	{"IN1P", NULL, "LDO"},
+	{"IN2P", NULL, "LDO"},
+
+	{"IN1P", NULL, "MIC1"},
+	{"IN2P", NULL, "MIC2"},
+	{"IN2N", NULL, "MIC2"},
+
+	{"BST1", NULL, "IN1P"},
+	{"BST2", NULL, "IN2P"},
+	{"BST2", NULL, "IN2N"},
+	{"BST1", NULL, "micbias1"},
+	{"BST2", NULL, "micbias1"},
+
+	{"INL1 VOL", NULL, "IN2P"},
+	{"INR1 VOL", NULL, "IN2N"},
+
+	{"RECMIXL", "INL1 Switch", "INL1 VOL"},
+	{"RECMIXL", "BST2 Switch", "BST2"},
+	{"RECMIXL", "BST1 Switch", "BST1"},
+
+	{"RECMIXR", "INR1 Switch", "INR1 VOL"},
+	{"RECMIXR", "BST2 Switch", "BST2"},
+	{"RECMIXR", "BST1 Switch", "BST1"},
+
+	{"ADC L", NULL, "RECMIXL"},
+	{"ADC R", NULL, "RECMIXR"},
+
+	{"Stereo1 ADC MIXL", "ADC1 Switch", "ADC L"},
+	{"Stereo1 ADC MIXL", NULL, "stereo1 filter"},
+	{"stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll},
+
+	{"Stereo1 ADC MIXR", "ADC1 Switch", "ADC R"},
+	{"Stereo1 ADC MIXR", NULL, "stereo1 filter"},
+	{"stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll},
+
+	{"IF1 ADC1", NULL, "Stereo1 ADC MIXL"},
+	{"IF1 ADC1", NULL, "Stereo1 ADC MIXR"},
+	{"IF1 ADC1", NULL, "I2S1"},
+
+	{"AIF1TX", NULL, "IF1 ADC1"},
+
+	{"IF1 DAC", NULL, "AIF1RX"},
+	{"IF1 DAC", NULL, "I2S1"},
+
+	{"IF1 DAC1 L", NULL, "IF1 DAC"},
+	{"IF1 DAC1 R", NULL, "IF1 DAC"},
+
+	{"DAC MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"},
+	{"DAC MIXL", "INF1 Switch", "IF1 DAC1 L"},
+	{"DAC MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"},
+	{"DAC MIXR", "INF1 Switch", "IF1 DAC1 R"},
+
+	{"Audio DSP", NULL, "DAC MIXL"},
+	{"Audio DSP", NULL, "DAC MIXR"},
+
+	{"Stereo DAC MIXL", "DAC L1 Switch", "Audio DSP"},
+	{"Stereo DAC MIXL", "DAC R1 Switch", "DAC MIXR"},
+	{"Stereo DAC MIXL", NULL, "Stero1 DAC Power"},
+	{"Stereo DAC MIXR", "DAC R1 Switch", "Audio DSP"},
+	{"Stereo DAC MIXR", "DAC L1 Switch", "DAC MIXL"},
+	{"Stereo DAC MIXR", NULL, "Stero1 DAC Power"},
+
+	{"DAC L1", NULL, "Stereo DAC MIXL"},
+	{"DAC L1", NULL, "PLL1", is_sys_clk_from_pll},
+	{"DAC R1", NULL, "Stereo DAC MIXR"},
+	{"DAC R1", NULL, "PLL1", is_sys_clk_from_pll},
+
+	{"OUT MIXL", "BST1 Switch", "BST1"},
+	{"OUT MIXL", "BST2 Switch", "BST2"},
+	{"OUT MIXL", "INL1 Switch", "INL1 VOL"},
+	{"OUT MIXL", "REC MIXL Switch", "RECMIXL"},
+	{"OUT MIXL", "DAC L1 Switch", "DAC L1"},
+
+	{"OUT MIXR", "BST2 Switch", "BST2"},
+	{"OUT MIXR", "BST1 Switch", "BST1"},
+	{"OUT MIXR", "INR1 Switch", "INR1 VOL"},
+	{"OUT MIXR", "REC MIXR Switch", "RECMIXR"},
+	{"OUT MIXR", "DAC R1 Switch", "DAC R1"},
+
+	{"HPOVOL L", NULL, "OUT MIXL"},
+	{"HPOVOL R", NULL, "OUT MIXR"},
+	{"OUTVOL L", NULL, "OUT MIXL"},
+	{"OUTVOL R", NULL, "OUT MIXR"},
+
+	{"DAC 1", NULL, "DAC L1"},
+	{"DAC 1", NULL, "DAC R1"},
+	{"HPOVOL", NULL, "HPOVOL L"},
+	{"HPOVOL", NULL, "HPOVOL R"},
+	{"HPO MIX", "DAC1 Switch", "DAC 1"},
+	{"HPO MIX", "HPVOL Switch", "HPOVOL"},
+
+	{"LOUT MIX", "DAC L1 Switch", "DAC L1"},
+	{"LOUT MIX", "DAC R1 Switch", "DAC R1"},
+	{"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"},
+	{"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"},
+
+	{"HP amp", NULL, "HPO MIX"},
+	{"HP amp", NULL, "Charge Pump"},
+	{"HPOL", NULL, "HP amp"},
+	{"HPOR", NULL, "HP amp"},
+
+	{"LOUT amp", NULL, "LOUT MIX"},
+	{"LOUT amp", NULL, "Charge Pump"},
+	{"LOUTL", NULL, "LOUT amp"},
+	{"LOUTR", NULL, "LOUT amp"},
+
+};
+
+static int rt5616_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0, val_clk, mask_clk;
+	int pre_div, bclk_ms, frame_size;
+
+	rt5616->lrck[dai->id] = params_rate(params);
+
+	pre_div = rl6231_get_clk_info(rt5616->sysclk, rt5616->lrck[dai->id]);
+
+	if (pre_div < 0) {
+		dev_err(component->dev, "Unsupported clock setting\n");
+		return -EINVAL;
+	}
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
+		return -EINVAL;
+	}
+	bclk_ms = frame_size > 32 ? 1 : 0;
+	rt5616->bclk[dai->id] = rt5616->lrck[dai->id] * (32 << bclk_ms);
+
+	dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+		rt5616->bclk[dai->id], rt5616->lrck[dai->id]);
+	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+		bclk_ms, pre_div, dai->id);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		val_len |= RT5616_I2S_DL_20;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		val_len |= RT5616_I2S_DL_24;
+		break;
+	case SNDRV_PCM_FORMAT_S8:
+		val_len |= RT5616_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mask_clk = RT5616_I2S_PD1_MASK;
+	val_clk = pre_div << RT5616_I2S_PD1_SFT;
+	snd_soc_component_update_bits(component, RT5616_I2S1_SDP,
+			    RT5616_I2S_DL_MASK, val_len);
+	snd_soc_component_update_bits(component, RT5616_ADDA_CLK1, mask_clk, val_clk);
+
+	return 0;
+}
+
+static int rt5616_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5616->master[dai->id] = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5616_I2S_MS_S;
+		rt5616->master[dai->id] = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5616_I2S_BP_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5616_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5616_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5616_I2S_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5616_I2S1_SDP,
+			    RT5616_I2S_MS_MASK | RT5616_I2S_BP_MASK |
+			    RT5616_I2S_DF_MASK, reg_val);
+
+	return 0;
+}
+
+static int rt5616_set_dai_sysclk(struct snd_soc_dai *dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	if (freq == rt5616->sysclk && clk_id == rt5616->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5616_SCLK_S_MCLK:
+		reg_val |= RT5616_SCLK_SRC_MCLK;
+		break;
+	case RT5616_SCLK_S_PLL1:
+		reg_val |= RT5616_SCLK_SRC_PLL1;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5616_GLB_CLK,
+			    RT5616_SCLK_SRC_MASK, reg_val);
+	rt5616->sysclk = freq;
+	rt5616->sysclk_src = clk_id;
+
+	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+	return 0;
+}
+
+static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+			      unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5616->pll_src && freq_in == rt5616->pll_in &&
+	    freq_out == rt5616->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt5616->pll_in = 0;
+		rt5616->pll_out = 0;
+		snd_soc_component_update_bits(component, RT5616_GLB_CLK,
+				    RT5616_SCLK_SRC_MASK,
+				    RT5616_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5616_PLL1_S_MCLK:
+		snd_soc_component_update_bits(component, RT5616_GLB_CLK,
+				    RT5616_PLL1_SRC_MASK,
+				    RT5616_PLL1_SRC_MCLK);
+		break;
+	case RT5616_PLL1_S_BCLK1:
+	case RT5616_PLL1_S_BCLK2:
+		snd_soc_component_update_bits(component, RT5616_GLB_CLK,
+				    RT5616_PLL1_SRC_MASK,
+				    RT5616_PLL1_SRC_BCLK1);
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_component_write(component, RT5616_PLL_CTRL1,
+		      pll_code.n_code << RT5616_PLL_N_SFT | pll_code.k_code);
+	snd_soc_component_write(component, RT5616_PLL_CTRL2,
+		      (pll_code.m_bp ? 0 : pll_code.m_code) <<
+		      RT5616_PLL_M_SFT |
+		      pll_code.m_bp << RT5616_PLL_M_BP_SFT);
+
+	rt5616->pll_in = freq_in;
+	rt5616->pll_out = freq_out;
+	rt5616->pll_src = source;
+
+	return 0;
+}
+
+static int rt5616_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/*
+		 * SND_SOC_BIAS_PREPARE is called while preparing for a
+		 * transition to ON or away from ON. If current bias_level
+		 * is SND_SOC_BIAS_ON, then it is preparing for a transition
+		 * away from ON. Disable the clock in that case, otherwise
+		 * enable it.
+		 */
+		if (IS_ERR(rt5616->mclk))
+			break;
+
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
+			clk_disable_unprepare(rt5616->mclk);
+		} else {
+			ret = clk_prepare_enable(rt5616->mclk);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
+					    RT5616_PWR_VREF1 | RT5616_PWR_MB |
+					    RT5616_PWR_BG | RT5616_PWR_VREF2,
+					    RT5616_PWR_VREF1 | RT5616_PWR_MB |
+					    RT5616_PWR_BG | RT5616_PWR_VREF2);
+			mdelay(10);
+			snd_soc_component_update_bits(component, RT5616_PWR_ANLG1,
+					    RT5616_PWR_FV1 | RT5616_PWR_FV2,
+					    RT5616_PWR_FV1 | RT5616_PWR_FV2);
+			snd_soc_component_update_bits(component, RT5616_D_MISC,
+					    RT5616_D_GATE_EN,
+					    RT5616_D_GATE_EN);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, RT5616_D_MISC, RT5616_D_GATE_EN, 0);
+		snd_soc_component_write(component, RT5616_PWR_DIG1, 0x0000);
+		snd_soc_component_write(component, RT5616_PWR_DIG2, 0x0000);
+		snd_soc_component_write(component, RT5616_PWR_VOL, 0x0000);
+		snd_soc_component_write(component, RT5616_PWR_MIXER, 0x0000);
+		snd_soc_component_write(component, RT5616_PWR_ANLG1, 0x0000);
+		snd_soc_component_write(component, RT5616_PWR_ANLG2, 0x0000);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5616_probe(struct snd_soc_component *component)
+{
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
+
+	/* Check if MCLK provided */
+	rt5616->mclk = devm_clk_get(component->dev, "mclk");
+	if (PTR_ERR(rt5616->mclk) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	rt5616->component = component;
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5616_suspend(struct snd_soc_component *component)
+{
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5616->regmap, true);
+	regcache_mark_dirty(rt5616->regmap);
+
+	return 0;
+}
+
+static int rt5616_resume(struct snd_soc_component *component)
+{
+	struct rt5616_priv *rt5616 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5616->regmap, false);
+	regcache_sync(rt5616->regmap);
+	return 0;
+}
+#else
+#define rt5616_suspend NULL
+#define rt5616_resume NULL
+#endif
+
+#define RT5616_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5616_aif_dai_ops = {
+	.hw_params = rt5616_hw_params,
+	.set_fmt = rt5616_set_dai_fmt,
+	.set_sysclk = rt5616_set_dai_sysclk,
+	.set_pll = rt5616_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver rt5616_dai[] = {
+	{
+		.name = "rt5616-aif1",
+		.id = RT5616_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5616_STEREO_RATES,
+			.formats = RT5616_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5616_STEREO_RATES,
+			.formats = RT5616_FORMATS,
+		},
+		.ops = &rt5616_aif_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5616 = {
+	.probe			= rt5616_probe,
+	.suspend		= rt5616_suspend,
+	.resume			= rt5616_resume,
+	.set_bias_level		= rt5616_set_bias_level,
+	.controls		= rt5616_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5616_snd_controls),
+	.dapm_widgets		= rt5616_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5616_dapm_widgets),
+	.dapm_routes		= rt5616_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5616_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt5616_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.use_single_rw = true,
+	.max_register = RT5616_DEVICE_ID + 1 + (ARRAY_SIZE(rt5616_ranges) *
+					       RT5616_PR_SPACING),
+	.volatile_reg = rt5616_volatile_register,
+	.readable_reg = rt5616_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5616_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5616_reg),
+	.ranges = rt5616_ranges,
+	.num_ranges = ARRAY_SIZE(rt5616_ranges),
+};
+
+static const struct i2c_device_id rt5616_i2c_id[] = {
+	{ "rt5616", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt5616_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rt5616_of_match[] = {
+	{ .compatible = "realtek,rt5616", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5616_of_match);
+#endif
+
+static int rt5616_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct rt5616_priv *rt5616;
+	unsigned int val;
+	int ret;
+
+	rt5616 = devm_kzalloc(&i2c->dev, sizeof(struct rt5616_priv),
+			      GFP_KERNEL);
+	if (!rt5616)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt5616);
+
+	rt5616->regmap = devm_regmap_init_i2c(i2c, &rt5616_regmap);
+	if (IS_ERR(rt5616->regmap)) {
+		ret = PTR_ERR(rt5616->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt5616->regmap, RT5616_DEVICE_ID, &val);
+	if (val != 0x6281) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt5616\n",
+			val);
+		return -ENODEV;
+	}
+	regmap_write(rt5616->regmap, RT5616_RESET, 0);
+	regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1,
+			   RT5616_PWR_VREF1 | RT5616_PWR_MB |
+			   RT5616_PWR_BG | RT5616_PWR_VREF2,
+			   RT5616_PWR_VREF1 | RT5616_PWR_MB |
+			   RT5616_PWR_BG | RT5616_PWR_VREF2);
+	mdelay(10);
+	regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1,
+			   RT5616_PWR_FV1 | RT5616_PWR_FV2,
+			   RT5616_PWR_FV1 | RT5616_PWR_FV2);
+
+	ret = regmap_register_patch(rt5616->regmap, init_list,
+				    ARRAY_SIZE(init_list));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1,
+			   RT5616_PWR_LDO_DVO_MASK, RT5616_PWR_LDO_DVO_1_2V);
+
+	return devm_snd_soc_register_component(&i2c->dev,
+				      &soc_component_dev_rt5616,
+				      rt5616_dai, ARRAY_SIZE(rt5616_dai));
+}
+
+static int rt5616_i2c_remove(struct i2c_client *i2c)
+{
+	return 0;
+}
+
+static void rt5616_i2c_shutdown(struct i2c_client *client)
+{
+	struct rt5616_priv *rt5616 = i2c_get_clientdata(client);
+
+	regmap_write(rt5616->regmap, RT5616_HP_VOL, 0xc8c8);
+	regmap_write(rt5616->regmap, RT5616_LOUT_CTRL1, 0xc8c8);
+}
+
+static struct i2c_driver rt5616_i2c_driver = {
+	.driver = {
+		.name = "rt5616",
+		.of_match_table = of_match_ptr(rt5616_of_match),
+	},
+	.probe = rt5616_i2c_probe,
+	.remove = rt5616_i2c_remove,
+	.shutdown = rt5616_i2c_shutdown,
+	.id_table = rt5616_i2c_id,
+};
+module_i2c_driver(rt5616_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5616 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt5616.h b/sound/soc/codecs/rt5616.h
new file mode 100644
index 0000000..f88cddd
--- /dev/null
+++ b/sound/soc/codecs/rt5616.h
@@ -0,0 +1,1819 @@
+/*
+ * rt5616.h  --  RT5616 ALSA SoC audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ * Author: Johnny Hsu <johnnyhsu@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5616_H__
+#define __RT5616_H__
+
+/* Info */
+#define RT5616_RESET				0x00
+#define RT5616_VERSION_ID			0xfd
+#define RT5616_VENDOR_ID			0xfe
+#define RT5616_DEVICE_ID			0xff
+/*  I/O - Output */
+#define RT5616_HP_VOL				0x02
+#define RT5616_LOUT_CTRL1			0x03
+#define RT5616_LOUT_CTRL2			0x05
+/* I/O - Input */
+#define RT5616_IN1_IN2				0x0d
+#define RT5616_INL1_INR1_VOL			0x0f
+/* I/O - ADC/DAC/DMIC */
+#define RT5616_DAC1_DIG_VOL			0x19
+#define RT5616_ADC_DIG_VOL			0x1c
+#define RT5616_ADC_BST_VOL			0x1e
+/* Mixer - D-D */
+#define RT5616_STO1_ADC_MIXER			0x27
+#define RT5616_AD_DA_MIXER			0x29
+#define RT5616_STO_DAC_MIXER			0x2a
+
+/* Mixer - ADC */
+#define RT5616_REC_L1_MIXER			0x3b
+#define RT5616_REC_L2_MIXER			0x3c
+#define RT5616_REC_R1_MIXER			0x3d
+#define RT5616_REC_R2_MIXER			0x3e
+/* Mixer - DAC */
+#define RT5616_HPO_MIXER			0x45
+#define RT5616_OUT_L1_MIXER			0x4d
+#define RT5616_OUT_L2_MIXER			0x4e
+#define RT5616_OUT_L3_MIXER			0x4f
+#define RT5616_OUT_R1_MIXER			0x50
+#define RT5616_OUT_R2_MIXER			0x51
+#define RT5616_OUT_R3_MIXER			0x52
+#define RT5616_LOUT_MIXER			0x53
+/* Power */
+#define RT5616_PWR_DIG1				0x61
+#define RT5616_PWR_DIG2				0x62
+#define RT5616_PWR_ANLG1			0x63
+#define RT5616_PWR_ANLG2			0x64
+#define RT5616_PWR_MIXER			0x65
+#define RT5616_PWR_VOL				0x66
+/* Private Register Control */
+#define RT5616_PRIV_INDEX			0x6a
+#define RT5616_PRIV_DATA			0x6c
+/* Format - ADC/DAC */
+#define RT5616_I2S1_SDP				0x70
+#define RT5616_ADDA_CLK1			0x73
+#define RT5616_ADDA_CLK2			0x74
+
+/* Function - Analog */
+#define RT5616_GLB_CLK				0x80
+#define RT5616_PLL_CTRL1			0x81
+#define RT5616_PLL_CTRL2			0x82
+#define RT5616_HP_OVCD				0x8b
+#define RT5616_DEPOP_M1				0x8e
+#define RT5616_DEPOP_M2				0x8f
+#define RT5616_DEPOP_M3				0x90
+#define RT5616_CHARGE_PUMP			0x91
+#define RT5616_PV_DET_SPK_G			0x92
+#define RT5616_MICBIAS				0x93
+#define RT5616_A_JD_CTL1			0x94
+#define RT5616_A_JD_CTL2			0x95
+/* Function - Digital */
+#define RT5616_EQ_CTRL1				0xb0
+#define RT5616_EQ_CTRL2				0xb1
+#define RT5616_WIND_FILTER			0xb2
+#define RT5616_DRC_AGC_1			0xb4
+#define RT5616_DRC_AGC_2			0xb5
+#define RT5616_DRC_AGC_3			0xb6
+#define RT5616_SVOL_ZC				0xb7
+#define RT5616_JD_CTRL1				0xbb
+#define RT5616_JD_CTRL2				0xbc
+#define RT5616_IRQ_CTRL1			0xbd
+#define RT5616_IRQ_CTRL2			0xbe
+#define RT5616_INT_IRQ_ST			0xbf
+#define RT5616_GPIO_CTRL1			0xc0
+#define RT5616_GPIO_CTRL2			0xc1
+#define RT5616_GPIO_CTRL3			0xc2
+#define RT5616_PGM_REG_ARR1			0xc8
+#define RT5616_PGM_REG_ARR2			0xc9
+#define RT5616_PGM_REG_ARR3			0xca
+#define RT5616_PGM_REG_ARR4			0xcb
+#define RT5616_PGM_REG_ARR5			0xcc
+#define RT5616_SCB_FUNC				0xcd
+#define RT5616_SCB_CTRL				0xce
+#define RT5616_BASE_BACK			0xcf
+#define RT5616_MP3_PLUS1			0xd0
+#define RT5616_MP3_PLUS2			0xd1
+#define RT5616_ADJ_HPF_CTRL1			0xd3
+#define RT5616_ADJ_HPF_CTRL2			0xd4
+#define RT5616_HP_CALIB_AMP_DET			0xd6
+#define RT5616_HP_CALIB2			0xd7
+#define RT5616_SV_ZCD1				0xd9
+#define RT5616_SV_ZCD2				0xda
+#define RT5616_D_MISC				0xfa
+/* Dummy Register */
+#define RT5616_DUMMY2				0xfb
+#define RT5616_DUMMY3				0xfc
+
+
+/* Index of Codec Private Register definition */
+#define RT5616_BIAS_CUR1			0x12
+#define RT5616_BIAS_CUR3			0x14
+#define RT5616_CLSD_INT_REG1			0x1c
+#define RT5616_MAMP_INT_REG2			0x37
+#define RT5616_CHOP_DAC_ADC			0x3d
+#define RT5616_3D_SPK				0x63
+#define RT5616_WND_1				0x6c
+#define RT5616_WND_2				0x6d
+#define RT5616_WND_3				0x6e
+#define RT5616_WND_4				0x6f
+#define RT5616_WND_5				0x70
+#define RT5616_WND_8				0x73
+#define RT5616_DIP_SPK_INF			0x75
+#define RT5616_HP_DCC_INT1			0x77
+#define RT5616_EQ_BW_LOP			0xa0
+#define RT5616_EQ_GN_LOP			0xa1
+#define RT5616_EQ_FC_BP1			0xa2
+#define RT5616_EQ_BW_BP1			0xa3
+#define RT5616_EQ_GN_BP1			0xa4
+#define RT5616_EQ_FC_BP2			0xa5
+#define RT5616_EQ_BW_BP2			0xa6
+#define RT5616_EQ_GN_BP2			0xa7
+#define RT5616_EQ_FC_BP3			0xa8
+#define RT5616_EQ_BW_BP3			0xa9
+#define RT5616_EQ_GN_BP3			0xaa
+#define RT5616_EQ_FC_BP4			0xab
+#define RT5616_EQ_BW_BP4			0xac
+#define RT5616_EQ_GN_BP4			0xad
+#define RT5616_EQ_FC_HIP1			0xae
+#define RT5616_EQ_GN_HIP1			0xaf
+#define RT5616_EQ_FC_HIP2			0xb0
+#define RT5616_EQ_BW_HIP2			0xb1
+#define RT5616_EQ_GN_HIP2			0xb2
+#define RT5616_EQ_PRE_VOL			0xb3
+#define RT5616_EQ_PST_VOL			0xb4
+
+
+/* global definition */
+#define RT5616_L_MUTE				(0x1 << 15)
+#define RT5616_L_MUTE_SFT			15
+#define RT5616_VOL_L_MUTE			(0x1 << 14)
+#define RT5616_VOL_L_SFT			14
+#define RT5616_R_MUTE				(0x1 << 7)
+#define RT5616_R_MUTE_SFT			7
+#define RT5616_VOL_R_MUTE			(0x1 << 6)
+#define RT5616_VOL_R_SFT			6
+#define RT5616_L_VOL_MASK			(0x3f << 8)
+#define RT5616_L_VOL_SFT			8
+#define RT5616_R_VOL_MASK			(0x3f)
+#define RT5616_R_VOL_SFT			0
+
+/* LOUT Control 2(0x05) */
+#define RT5616_EN_DFO				(0x1 << 15)
+
+/* IN1 and IN2 Control (0x0d) */
+/* IN3 and IN4 Control (0x0e) */
+#define RT5616_BST_MASK1			(0xf<<12)
+#define RT5616_BST_SFT1				12
+#define RT5616_BST_MASK2			(0xf<<8)
+#define RT5616_BST_SFT2				8
+#define RT5616_IN_DF1				(0x1 << 7)
+#define RT5616_IN_SFT1				7
+#define RT5616_IN_DF2				(0x1 << 6)
+#define RT5616_IN_SFT2				6
+
+/* INL1 and INR1 Volume Control (0x0f) */
+#define RT5616_INL_VOL_MASK			(0x1f << 8)
+#define RT5616_INL_VOL_SFT			8
+#define RT5616_INR_SEL_MASK			(0x1 << 7)
+#define RT5616_INR_SEL_SFT			7
+#define RT5616_INR_SEL_IN4N			(0x0 << 7)
+#define RT5616_INR_SEL_MONON			(0x1 << 7)
+#define RT5616_INR_VOL_MASK			(0x1f)
+#define RT5616_INR_VOL_SFT			0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5616_DAC_L1_VOL_MASK			(0xff << 8)
+#define RT5616_DAC_L1_VOL_SFT			8
+#define RT5616_DAC_R1_VOL_MASK			(0xff)
+#define RT5616_DAC_R1_VOL_SFT			0
+
+/* DAC2 Digital Volume (0x1a) */
+#define RT5616_DAC_L2_VOL_MASK			(0xff << 8)
+#define RT5616_DAC_L2_VOL_SFT			8
+#define RT5616_DAC_R2_VOL_MASK			(0xff)
+#define RT5616_DAC_R2_VOL_SFT			0
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5616_ADC_L_VOL_MASK			(0x7f << 8)
+#define RT5616_ADC_L_VOL_SFT			8
+#define RT5616_ADC_R_VOL_MASK			(0x7f)
+#define RT5616_ADC_R_VOL_SFT			0
+
+/* Mono ADC Digital Volume Control (0x1d) */
+#define RT5616_M_MONO_ADC_L			(0x1 << 15)
+#define RT5616_M_MONO_ADC_L_SFT			15
+#define RT5616_MONO_ADC_L_VOL_MASK		(0x7f << 8)
+#define RT5616_MONO_ADC_L_VOL_SFT		8
+#define RT5616_M_MONO_ADC_R			(0x1 << 7)
+#define RT5616_M_MONO_ADC_R_SFT			7
+#define RT5616_MONO_ADC_R_VOL_MASK		(0x7f)
+#define RT5616_MONO_ADC_R_VOL_SFT		0
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5616_ADC_L_BST_MASK			(0x3 << 14)
+#define RT5616_ADC_L_BST_SFT			14
+#define RT5616_ADC_R_BST_MASK			(0x3 << 12)
+#define RT5616_ADC_R_BST_SFT			12
+#define RT5616_ADC_COMP_MASK			(0x3 << 10)
+#define RT5616_ADC_COMP_SFT			10
+
+/* Stereo ADC1 Mixer Control (0x27) */
+#define RT5616_M_STO1_ADC_L1			(0x1 << 14)
+#define RT5616_M_STO1_ADC_L1_SFT		14
+#define RT5616_M_STO1_ADC_R1			(0x1 << 6)
+#define RT5616_M_STO1_ADC_R1_SFT		6
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5616_M_ADCMIX_L			(0x1 << 15)
+#define RT5616_M_ADCMIX_L_SFT			15
+#define RT5616_M_IF1_DAC_L			(0x1 << 14)
+#define RT5616_M_IF1_DAC_L_SFT			14
+#define RT5616_M_ADCMIX_R			(0x1 << 7)
+#define RT5616_M_ADCMIX_R_SFT			7
+#define RT5616_M_IF1_DAC_R			(0x1 << 6)
+#define RT5616_M_IF1_DAC_R_SFT			6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5616_M_DAC_L1_MIXL			(0x1 << 14)
+#define RT5616_M_DAC_L1_MIXL_SFT		14
+#define RT5616_DAC_L1_STO_L_VOL_MASK		(0x1 << 13)
+#define RT5616_DAC_L1_STO_L_VOL_SFT		13
+#define RT5616_M_DAC_R1_MIXL			(0x1 << 9)
+#define RT5616_M_DAC_R1_MIXL_SFT		9
+#define RT5616_DAC_R1_STO_L_VOL_MASK		(0x1 << 8)
+#define RT5616_DAC_R1_STO_L_VOL_SFT		8
+#define RT5616_M_DAC_R1_MIXR			(0x1 << 6)
+#define RT5616_M_DAC_R1_MIXR_SFT		6
+#define RT5616_DAC_R1_STO_R_VOL_MASK		(0x1 << 5)
+#define RT5616_DAC_R1_STO_R_VOL_SFT		5
+#define RT5616_M_DAC_L1_MIXR			(0x1 << 1)
+#define RT5616_M_DAC_L1_MIXR_SFT		1
+#define RT5616_DAC_L1_STO_R_VOL_MASK		(0x1)
+#define RT5616_DAC_L1_STO_R_VOL_SFT		0
+
+/* DD Mixer Control (0x2b) */
+#define RT5616_M_STO_DD_L1			(0x1 << 14)
+#define RT5616_M_STO_DD_L1_SFT			14
+#define RT5616_STO_DD_L1_VOL_MASK		(0x1 << 13)
+#define RT5616_DAC_DD_L1_VOL_SFT		13
+#define RT5616_M_STO_DD_L2			(0x1 << 12)
+#define RT5616_M_STO_DD_L2_SFT			12
+#define RT5616_STO_DD_L2_VOL_MASK		(0x1 << 11)
+#define RT5616_STO_DD_L2_VOL_SFT		11
+#define RT5616_M_STO_DD_R2_L			(0x1 << 10)
+#define RT5616_M_STO_DD_R2_L_SFT		10
+#define RT5616_STO_DD_R2_L_VOL_MASK		(0x1 << 9)
+#define RT5616_STO_DD_R2_L_VOL_SFT		9
+#define RT5616_M_STO_DD_R1			(0x1 << 6)
+#define RT5616_M_STO_DD_R1_SFT			6
+#define RT5616_STO_DD_R1_VOL_MASK		(0x1 << 5)
+#define RT5616_STO_DD_R1_VOL_SFT		5
+#define RT5616_M_STO_DD_R2			(0x1 << 4)
+#define RT5616_M_STO_DD_R2_SFT			4
+#define RT5616_STO_DD_R2_VOL_MASK		(0x1 << 3)
+#define RT5616_STO_DD_R2_VOL_SFT		3
+#define RT5616_M_STO_DD_L2_R			(0x1 << 2)
+#define RT5616_M_STO_DD_L2_R_SFT		2
+#define RT5616_STO_DD_L2_R_VOL_MASK		(0x1 << 1)
+#define RT5616_STO_DD_L2_R_VOL_SFT		1
+
+/* Digital Mixer Control (0x2c) */
+#define RT5616_M_STO_L_DAC_L			(0x1 << 15)
+#define RT5616_M_STO_L_DAC_L_SFT		15
+#define RT5616_STO_L_DAC_L_VOL_MASK		(0x1 << 14)
+#define RT5616_STO_L_DAC_L_VOL_SFT		14
+#define RT5616_M_DAC_L2_DAC_L			(0x1 << 13)
+#define RT5616_M_DAC_L2_DAC_L_SFT		13
+#define RT5616_DAC_L2_DAC_L_VOL_MASK		(0x1 << 12)
+#define RT5616_DAC_L2_DAC_L_VOL_SFT		12
+#define RT5616_M_STO_R_DAC_R			(0x1 << 11)
+#define RT5616_M_STO_R_DAC_R_SFT		11
+#define RT5616_STO_R_DAC_R_VOL_MASK		(0x1 << 10)
+#define RT5616_STO_R_DAC_R_VOL_SFT		10
+#define RT5616_M_DAC_R2_DAC_R			(0x1 << 9)
+#define RT5616_M_DAC_R2_DAC_R_SFT		9
+#define RT5616_DAC_R2_DAC_R_VOL_MASK		(0x1 << 8)
+#define RT5616_DAC_R2_DAC_R_VOL_SFT		8
+
+/* DSP Path Control 1 (0x2d) */
+#define RT5616_RXDP_SRC_MASK			(0x1 << 15)
+#define RT5616_RXDP_SRC_SFT			15
+#define RT5616_RXDP_SRC_NOR			(0x0 << 15)
+#define RT5616_RXDP_SRC_DIV3			(0x1 << 15)
+#define RT5616_TXDP_SRC_MASK			(0x1 << 14)
+#define RT5616_TXDP_SRC_SFT			14
+#define RT5616_TXDP_SRC_NOR			(0x0 << 14)
+#define RT5616_TXDP_SRC_DIV3			(0x1 << 14)
+
+/* DSP Path Control 2 (0x2e) */
+#define RT5616_DAC_L2_SEL_MASK			(0x3 << 14)
+#define RT5616_DAC_L2_SEL_SFT			14
+#define RT5616_DAC_L2_SEL_IF2			(0x0 << 14)
+#define RT5616_DAC_L2_SEL_IF3			(0x1 << 14)
+#define RT5616_DAC_L2_SEL_TXDC			(0x2 << 14)
+#define RT5616_DAC_L2_SEL_BASS			(0x3 << 14)
+#define RT5616_DAC_R2_SEL_MASK			(0x3 << 12)
+#define RT5616_DAC_R2_SEL_SFT			12
+#define RT5616_DAC_R2_SEL_IF2			(0x0 << 12)
+#define RT5616_DAC_R2_SEL_IF3			(0x1 << 12)
+#define RT5616_DAC_R2_SEL_TXDC			(0x2 << 12)
+#define RT5616_IF2_ADC_L_SEL_MASK		(0x1 << 11)
+#define RT5616_IF2_ADC_L_SEL_SFT		11
+#define RT5616_IF2_ADC_L_SEL_TXDP		(0x0 << 11)
+#define RT5616_IF2_ADC_L_SEL_PASS		(0x1 << 11)
+#define RT5616_IF2_ADC_R_SEL_MASK		(0x1 << 10)
+#define RT5616_IF2_ADC_R_SEL_SFT		10
+#define RT5616_IF2_ADC_R_SEL_TXDP		(0x0 << 10)
+#define RT5616_IF2_ADC_R_SEL_PASS		(0x1 << 10)
+#define RT5616_RXDC_SEL_MASK			(0x3 << 8)
+#define RT5616_RXDC_SEL_SFT			8
+#define RT5616_RXDC_SEL_NOR			(0x0 << 8)
+#define RT5616_RXDC_SEL_L2R			(0x1 << 8)
+#define RT5616_RXDC_SEL_R2L			(0x2 << 8)
+#define RT5616_RXDC_SEL_SWAP			(0x3 << 8)
+#define RT5616_RXDP_SEL_MASK			(0x3 << 6)
+#define RT5616_RXDP_SEL_SFT			6
+#define RT5616_RXDP_SEL_NOR			(0x0 << 6)
+#define RT5616_RXDP_SEL_L2R			(0x1 << 6)
+#define RT5616_RXDP_SEL_R2L			(0x2 << 6)
+#define RT5616_RXDP_SEL_SWAP			(0x3 << 6)
+#define RT5616_TXDC_SEL_MASK			(0x3 << 4)
+#define RT5616_TXDC_SEL_SFT			4
+#define RT5616_TXDC_SEL_NOR			(0x0 << 4)
+#define RT5616_TXDC_SEL_L2R			(0x1 << 4)
+#define RT5616_TXDC_SEL_R2L			(0x2 << 4)
+#define RT5616_TXDC_SEL_SWAP			(0x3 << 4)
+#define RT5616_TXDP_SEL_MASK			(0x3 << 2)
+#define RT5616_TXDP_SEL_SFT			2
+#define RT5616_TXDP_SEL_NOR			(0x0 << 2)
+#define RT5616_TXDP_SEL_L2R			(0x1 << 2)
+#define RT5616_TXDP_SEL_R2L			(0x2 << 2)
+#define RT5616_TRXDP_SEL_SWAP			(0x3 << 2)
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5616_G_LN_L2_RM_L_MASK		(0x7 << 13)
+#define RT5616_G_IN_L2_RM_L_SFT			13
+#define RT5616_G_LN_L1_RM_L_MASK		(0x7 << 10)
+#define RT5616_G_IN_L1_RM_L_SFT			10
+#define RT5616_G_BST3_RM_L_MASK			(0x7 << 4)
+#define RT5616_G_BST3_RM_L_SFT			4
+#define RT5616_G_BST2_RM_L_MASK			(0x7 << 1)
+#define RT5616_G_BST2_RM_L_SFT			1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5616_G_BST1_RM_L_MASK			(0x7 << 13)
+#define RT5616_G_BST1_RM_L_SFT			13
+#define RT5616_G_OM_L_RM_L_MASK			(0x7 << 10)
+#define RT5616_G_OM_L_RM_L_SFT			10
+#define RT5616_M_IN2_L_RM_L			(0x1 << 6)
+#define RT5616_M_IN2_L_RM_L_SFT			6
+#define RT5616_M_IN1_L_RM_L			(0x1 << 5)
+#define RT5616_M_IN1_L_RM_L_SFT			5
+#define RT5616_M_BST3_RM_L			(0x1 << 3)
+#define RT5616_M_BST3_RM_L_SFT			3
+#define RT5616_M_BST2_RM_L			(0x1 << 2)
+#define RT5616_M_BST2_RM_L_SFT			2
+#define RT5616_M_BST1_RM_L			(0x1 << 1)
+#define RT5616_M_BST1_RM_L_SFT			1
+#define RT5616_M_OM_L_RM_L			(0x1)
+#define RT5616_M_OM_L_RM_L_SFT			0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5616_G_IN2_R_RM_R_MASK		(0x7 << 13)
+#define RT5616_G_IN2_R_RM_R_SFT			13
+#define RT5616_G_IN1_R_RM_R_MASK		(0x7 << 10)
+#define RT5616_G_IN1_R_RM_R_SFT			10
+#define RT5616_G_BST3_RM_R_MASK			(0x7 << 4)
+#define RT5616_G_BST3_RM_R_SFT			4
+#define RT5616_G_BST2_RM_R_MASK			(0x7 << 1)
+#define RT5616_G_BST2_RM_R_SFT			1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5616_G_BST1_RM_R_MASK			(0x7 << 13)
+#define RT5616_G_BST1_RM_R_SFT			13
+#define RT5616_G_OM_R_RM_R_MASK			(0x7 << 10)
+#define RT5616_G_OM_R_RM_R_SFT			10
+#define RT5616_M_IN2_R_RM_R			(0x1 << 6)
+#define RT5616_M_IN2_R_RM_R_SFT			6
+#define RT5616_M_IN1_R_RM_R			(0x1 << 5)
+#define RT5616_M_IN1_R_RM_R_SFT			5
+#define RT5616_M_BST3_RM_R			(0x1 << 3)
+#define RT5616_M_BST3_RM_R_SFT			3
+#define RT5616_M_BST2_RM_R			(0x1 << 2)
+#define RT5616_M_BST2_RM_R_SFT			2
+#define RT5616_M_BST1_RM_R			(0x1 << 1)
+#define RT5616_M_BST1_RM_R_SFT			1
+#define RT5616_M_OM_R_RM_R			(0x1)
+#define RT5616_M_OM_R_RM_R_SFT			0
+
+/* HPMIX Control (0x45) */
+#define RT5616_M_DAC1_HM			(0x1 << 14)
+#define RT5616_M_DAC1_HM_SFT			14
+#define RT5616_M_HPVOL_HM			(0x1 << 13)
+#define RT5616_M_HPVOL_HM_SFT			13
+#define RT5616_G_HPOMIX_MASK			(0x1 << 12)
+#define RT5616_G_HPOMIX_SFT			12
+
+/* SPK Left Mixer Control (0x46) */
+#define RT5616_G_RM_L_SM_L_MASK			(0x3 << 14)
+#define RT5616_G_RM_L_SM_L_SFT			14
+#define RT5616_G_IN_L_SM_L_MASK			(0x3 << 12)
+#define RT5616_G_IN_L_SM_L_SFT			12
+#define RT5616_G_DAC_L1_SM_L_MASK		(0x3 << 10)
+#define RT5616_G_DAC_L1_SM_L_SFT		10
+#define RT5616_G_DAC_L2_SM_L_MASK		(0x3 << 8)
+#define RT5616_G_DAC_L2_SM_L_SFT		8
+#define RT5616_G_OM_L_SM_L_MASK			(0x3 << 6)
+#define RT5616_G_OM_L_SM_L_SFT			6
+#define RT5616_M_RM_L_SM_L			(0x1 << 5)
+#define RT5616_M_RM_L_SM_L_SFT			5
+#define RT5616_M_IN_L_SM_L			(0x1 << 4)
+#define RT5616_M_IN_L_SM_L_SFT			4
+#define RT5616_M_DAC_L1_SM_L			(0x1 << 3)
+#define RT5616_M_DAC_L1_SM_L_SFT		3
+#define RT5616_M_DAC_L2_SM_L			(0x1 << 2)
+#define RT5616_M_DAC_L2_SM_L_SFT		2
+#define RT5616_M_OM_L_SM_L			(0x1 << 1)
+#define RT5616_M_OM_L_SM_L_SFT			1
+
+/* SPK Right Mixer Control (0x47) */
+#define RT5616_G_RM_R_SM_R_MASK			(0x3 << 14)
+#define RT5616_G_RM_R_SM_R_SFT			14
+#define RT5616_G_IN_R_SM_R_MASK			(0x3 << 12)
+#define RT5616_G_IN_R_SM_R_SFT			12
+#define RT5616_G_DAC_R1_SM_R_MASK		(0x3 << 10)
+#define RT5616_G_DAC_R1_SM_R_SFT		10
+#define RT5616_G_DAC_R2_SM_R_MASK		(0x3 << 8)
+#define RT5616_G_DAC_R2_SM_R_SFT		8
+#define RT5616_G_OM_R_SM_R_MASK			(0x3 << 6)
+#define RT5616_G_OM_R_SM_R_SFT			6
+#define RT5616_M_RM_R_SM_R			(0x1 << 5)
+#define RT5616_M_RM_R_SM_R_SFT			5
+#define RT5616_M_IN_R_SM_R			(0x1 << 4)
+#define RT5616_M_IN_R_SM_R_SFT			4
+#define RT5616_M_DAC_R1_SM_R			(0x1 << 3)
+#define RT5616_M_DAC_R1_SM_R_SFT		3
+#define RT5616_M_DAC_R2_SM_R			(0x1 << 2)
+#define RT5616_M_DAC_R2_SM_R_SFT		2
+#define RT5616_M_OM_R_SM_R			(0x1 << 1)
+#define RT5616_M_OM_R_SM_R_SFT			1
+
+/* SPOLMIX Control (0x48) */
+#define RT5616_M_DAC_R1_SPM_L			(0x1 << 15)
+#define RT5616_M_DAC_R1_SPM_L_SFT		15
+#define RT5616_M_DAC_L1_SPM_L			(0x1 << 14)
+#define RT5616_M_DAC_L1_SPM_L_SFT		14
+#define RT5616_M_SV_R_SPM_L			(0x1 << 13)
+#define RT5616_M_SV_R_SPM_L_SFT			13
+#define RT5616_M_SV_L_SPM_L			(0x1 << 12)
+#define RT5616_M_SV_L_SPM_L_SFT			12
+#define RT5616_M_BST1_SPM_L			(0x1 << 11)
+#define RT5616_M_BST1_SPM_L_SFT			11
+
+/* SPORMIX Control (0x49) */
+#define RT5616_M_DAC_R1_SPM_R			(0x1 << 13)
+#define RT5616_M_DAC_R1_SPM_R_SFT		13
+#define RT5616_M_SV_R_SPM_R			(0x1 << 12)
+#define RT5616_M_SV_R_SPM_R_SFT			12
+#define RT5616_M_BST1_SPM_R			(0x1 << 11)
+#define RT5616_M_BST1_SPM_R_SFT			11
+
+/* SPOLMIX / SPORMIX Ratio Control (0x4a) */
+#define RT5616_SPO_CLSD_RATIO_MASK		(0x7)
+#define RT5616_SPO_CLSD_RATIO_SFT		0
+
+/* Mono Output Mixer Control (0x4c) */
+#define RT5616_M_DAC_R2_MM			(0x1 << 15)
+#define RT5616_M_DAC_R2_MM_SFT			15
+#define RT5616_M_DAC_L2_MM			(0x1 << 14)
+#define RT5616_M_DAC_L2_MM_SFT			14
+#define RT5616_M_OV_R_MM			(0x1 << 13)
+#define RT5616_M_OV_R_MM_SFT			13
+#define RT5616_M_OV_L_MM			(0x1 << 12)
+#define RT5616_M_OV_L_MM_SFT			12
+#define RT5616_M_BST1_MM			(0x1 << 11)
+#define RT5616_M_BST1_MM_SFT			11
+#define RT5616_G_MONOMIX_MASK			(0x1 << 10)
+#define RT5616_G_MONOMIX_SFT			10
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5616_G_BST2_OM_L_MASK			(0x7 << 10)
+#define RT5616_G_BST2_OM_L_SFT			10
+#define RT5616_G_BST1_OM_L_MASK			(0x7 << 7)
+#define RT5616_G_BST1_OM_L_SFT			7
+#define RT5616_G_IN1_L_OM_L_MASK		(0x7 << 4)
+#define RT5616_G_IN1_L_OM_L_SFT			4
+#define RT5616_G_RM_L_OM_L_MASK			(0x7 << 1)
+#define RT5616_G_RM_L_OM_L_SFT			1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5616_G_DAC_L1_OM_L_MASK		(0x7 << 7)
+#define RT5616_G_DAC_L1_OM_L_SFT		7
+#define RT5616_G_IN2_L_OM_L_MASK		(0x7 << 4)
+#define RT5616_G_IN2_L_OM_L_SFT			4
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5616_M_IN2_L_OM_L			(0x1 << 9)
+#define RT5616_M_IN2_L_OM_L_SFT			9
+#define RT5616_M_BST2_OM_L			(0x1 << 6)
+#define RT5616_M_BST2_OM_L_SFT			6
+#define RT5616_M_BST1_OM_L			(0x1 << 5)
+#define RT5616_M_BST1_OM_L_SFT			5
+#define RT5616_M_IN1_L_OM_L			(0x1 << 4)
+#define RT5616_M_IN1_L_OM_L_SFT			4
+#define RT5616_M_RM_L_OM_L			(0x1 << 3)
+#define RT5616_M_RM_L_OM_L_SFT			3
+#define RT5616_M_DAC_L1_OM_L			(0x1)
+#define RT5616_M_DAC_L1_OM_L_SFT		0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5616_G_BST2_OM_R_MASK			(0x7 << 10)
+#define RT5616_G_BST2_OM_R_SFT			10
+#define RT5616_G_BST1_OM_R_MASK			(0x7 << 7)
+#define RT5616_G_BST1_OM_R_SFT			7
+#define RT5616_G_IN1_R_OM_R_MASK		(0x7 << 4)
+#define RT5616_G_IN1_R_OM_R_SFT			4
+#define RT5616_G_RM_R_OM_R_MASK			(0x7 << 1)
+#define RT5616_G_RM_R_OM_R_SFT			1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5616_G_DAC_R1_OM_R_MASK		(0x7 << 7)
+#define RT5616_G_DAC_R1_OM_R_SFT		7
+#define RT5616_G_IN2_R_OM_R_MASK		(0x7 << 4)
+#define RT5616_G_IN2_R_OM_R_SFT			4
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5616_M_IN2_R_OM_R			(0x1 << 9)
+#define RT5616_M_IN2_R_OM_R_SFT			9
+#define RT5616_M_BST2_OM_R			(0x1 << 6)
+#define RT5616_M_BST2_OM_R_SFT			6
+#define RT5616_M_BST1_OM_R			(0x1 << 5)
+#define RT5616_M_BST1_OM_R_SFT			5
+#define RT5616_M_IN1_R_OM_R			(0x1 << 4)
+#define RT5616_M_IN1_R_OM_R_SFT			4
+#define RT5616_M_RM_R_OM_R			(0x1 << 3)
+#define RT5616_M_RM_R_OM_R_SFT			3
+#define RT5616_M_DAC_R1_OM_R			(0x1)
+#define RT5616_M_DAC_R1_OM_R_SFT		0
+
+/* LOUT Mixer Control (0x53) */
+#define RT5616_M_DAC_L1_LM			(0x1 << 15)
+#define RT5616_M_DAC_L1_LM_SFT			15
+#define RT5616_M_DAC_R1_LM			(0x1 << 14)
+#define RT5616_M_DAC_R1_LM_SFT			14
+#define RT5616_M_OV_L_LM			(0x1 << 13)
+#define RT5616_M_OV_L_LM_SFT			13
+#define RT5616_M_OV_R_LM			(0x1 << 12)
+#define RT5616_M_OV_R_LM_SFT			12
+#define RT5616_G_LOUTMIX_MASK			(0x1 << 11)
+#define RT5616_G_LOUTMIX_SFT			11
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5616_PWR_I2S1				(0x1 << 15)
+#define RT5616_PWR_I2S1_BIT			15
+#define RT5616_PWR_I2S2				(0x1 << 14)
+#define RT5616_PWR_I2S2_BIT			14
+#define RT5616_PWR_DAC_L1			(0x1 << 12)
+#define RT5616_PWR_DAC_L1_BIT			12
+#define RT5616_PWR_DAC_R1			(0x1 << 11)
+#define RT5616_PWR_DAC_R1_BIT			11
+#define RT5616_PWR_ADC_L			(0x1 << 2)
+#define RT5616_PWR_ADC_L_BIT			2
+#define RT5616_PWR_ADC_R			(0x1 << 1)
+#define RT5616_PWR_ADC_R_BIT			1
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5616_PWR_ADC_STO1_F			(0x1 << 15)
+#define RT5616_PWR_ADC_STO1_F_BIT		15
+#define RT5616_PWR_DAC_STO1_F			(0x1 << 11)
+#define RT5616_PWR_DAC_STO1_F_BIT		11
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5616_PWR_VREF1			(0x1 << 15)
+#define RT5616_PWR_VREF1_BIT			15
+#define RT5616_PWR_FV1				(0x1 << 14)
+#define RT5616_PWR_FV1_BIT			14
+#define RT5616_PWR_MB				(0x1 << 13)
+#define RT5616_PWR_MB_BIT			13
+#define RT5616_PWR_LM				(0x1 << 12)
+#define RT5616_PWR_LM_BIT			12
+#define RT5616_PWR_BG				(0x1 << 11)
+#define RT5616_PWR_BG_BIT			11
+#define RT5616_PWR_HP_L				(0x1 << 7)
+#define RT5616_PWR_HP_L_BIT			7
+#define RT5616_PWR_HP_R				(0x1 << 6)
+#define RT5616_PWR_HP_R_BIT			6
+#define RT5616_PWR_HA				(0x1 << 5)
+#define RT5616_PWR_HA_BIT			5
+#define RT5616_PWR_VREF2			(0x1 << 4)
+#define RT5616_PWR_VREF2_BIT			4
+#define RT5616_PWR_FV2				(0x1 << 3)
+#define RT5616_PWR_FV2_BIT			3
+#define RT5616_PWR_LDO				(0x1 << 2)
+#define RT5616_PWR_LDO_BIT			2
+#define RT5616_PWR_LDO_DVO_MASK			(0x3)
+#define RT5616_PWR_LDO_DVO_1_0V			0
+#define RT5616_PWR_LDO_DVO_1_1V			1
+#define RT5616_PWR_LDO_DVO_1_2V			2
+#define RT5616_PWR_LDO_DVO_1_3V			3
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5616_PWR_BST1				(0x1 << 15)
+#define RT5616_PWR_BST1_BIT			15
+#define RT5616_PWR_BST2				(0x1 << 14)
+#define RT5616_PWR_BST2_BIT			14
+#define RT5616_PWR_MB1				(0x1 << 11)
+#define RT5616_PWR_MB1_BIT			11
+#define RT5616_PWR_PLL				(0x1 << 9)
+#define RT5616_PWR_PLL_BIT			9
+#define RT5616_PWR_BST1_OP2			(0x1 << 5)
+#define RT5616_PWR_BST1_OP2_BIT			5
+#define RT5616_PWR_BST2_OP2			(0x1 << 4)
+#define RT5616_PWR_BST2_OP2_BIT			4
+#define RT5616_PWR_BST3_OP2			(0x1 << 3)
+#define RT5616_PWR_BST3_OP2_BIT			3
+#define RT5616_PWR_JD_M				(0x1 << 2)
+#define RT5616_PWM_JD_M_BIT			2
+#define RT5616_PWR_JD2				(0x1 << 1)
+#define RT5616_PWM_JD2_BIT			1
+#define RT5616_PWR_JD3				(0x1)
+#define RT5616_PWM_JD3_BIT			0
+
+/* Power Management for Mixer (0x65) */
+#define RT5616_PWR_OM_L				(0x1 << 15)
+#define RT5616_PWR_OM_L_BIT			15
+#define RT5616_PWR_OM_R				(0x1 << 14)
+#define RT5616_PWR_OM_R_BIT			14
+#define RT5616_PWR_RM_L				(0x1 << 11)
+#define RT5616_PWR_RM_L_BIT			11
+#define RT5616_PWR_RM_R				(0x1 << 10)
+#define RT5616_PWR_RM_R_BIT			10
+
+/* Power Management for Volume (0x66) */
+#define RT5616_PWR_OV_L				(0x1 << 13)
+#define RT5616_PWR_OV_L_BIT			13
+#define RT5616_PWR_OV_R				(0x1 << 12)
+#define RT5616_PWR_OV_R_BIT			12
+#define RT5616_PWR_HV_L				(0x1 << 11)
+#define RT5616_PWR_HV_L_BIT			11
+#define RT5616_PWR_HV_R				(0x1 << 10)
+#define RT5616_PWR_HV_R_BIT			10
+#define RT5616_PWR_IN1_L			(0x1 << 9)
+#define RT5616_PWR_IN1_L_BIT			9
+#define RT5616_PWR_IN1_R			(0x1 << 8)
+#define RT5616_PWR_IN1_R_BIT			8
+#define RT5616_PWR_IN2_L			(0x1 << 7)
+#define RT5616_PWR_IN2_L_BIT			7
+#define RT5616_PWR_IN2_R			(0x1 << 6)
+#define RT5616_PWR_IN2_R_BIT			6
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71) */
+#define RT5616_I2S_MS_MASK			(0x1 << 15)
+#define RT5616_I2S_MS_SFT			15
+#define RT5616_I2S_MS_M				(0x0 << 15)
+#define RT5616_I2S_MS_S				(0x1 << 15)
+#define RT5616_I2S_O_CP_MASK			(0x3 << 10)
+#define RT5616_I2S_O_CP_SFT			10
+#define RT5616_I2S_O_CP_OFF			(0x0 << 10)
+#define RT5616_I2S_O_CP_U_LAW			(0x1 << 10)
+#define RT5616_I2S_O_CP_A_LAW			(0x2 << 10)
+#define RT5616_I2S_I_CP_MASK			(0x3 << 8)
+#define RT5616_I2S_I_CP_SFT			8
+#define RT5616_I2S_I_CP_OFF			(0x0 << 8)
+#define RT5616_I2S_I_CP_U_LAW			(0x1 << 8)
+#define RT5616_I2S_I_CP_A_LAW			(0x2 << 8)
+#define RT5616_I2S_BP_MASK			(0x1 << 7)
+#define RT5616_I2S_BP_SFT			7
+#define RT5616_I2S_BP_NOR			(0x0 << 7)
+#define RT5616_I2S_BP_INV			(0x1 << 7)
+#define RT5616_I2S_DL_MASK			(0x3 << 2)
+#define RT5616_I2S_DL_SFT			2
+#define RT5616_I2S_DL_16			(0x0 << 2)
+#define RT5616_I2S_DL_20			(0x1 << 2)
+#define RT5616_I2S_DL_24			(0x2 << 2)
+#define RT5616_I2S_DL_8				(0x3 << 2)
+#define RT5616_I2S_DF_MASK			(0x3)
+#define RT5616_I2S_DF_SFT			0
+#define RT5616_I2S_DF_I2S			(0x0)
+#define RT5616_I2S_DF_LEFT			(0x1)
+#define RT5616_I2S_DF_PCM_A			(0x2)
+#define RT5616_I2S_DF_PCM_B			(0x3)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5616_I2S_PD1_MASK			(0x7 << 12)
+#define RT5616_I2S_PD1_SFT			12
+#define RT5616_I2S_PD1_1			(0x0 << 12)
+#define RT5616_I2S_PD1_2			(0x1 << 12)
+#define RT5616_I2S_PD1_3			(0x2 << 12)
+#define RT5616_I2S_PD1_4			(0x3 << 12)
+#define RT5616_I2S_PD1_6			(0x4 << 12)
+#define RT5616_I2S_PD1_8			(0x5 << 12)
+#define RT5616_I2S_PD1_12			(0x6 << 12)
+#define RT5616_I2S_PD1_16			(0x7 << 12)
+#define RT5616_I2S_BCLK_MS2_MASK		(0x1 << 11)
+#define RT5616_DAC_OSR_MASK			(0x3 << 2)
+#define RT5616_DAC_OSR_SFT			2
+#define RT5616_DAC_OSR_128			(0x0 << 2)
+#define RT5616_DAC_OSR_64			(0x1 << 2)
+#define RT5616_DAC_OSR_32			(0x2 << 2)
+#define RT5616_DAC_OSR_128_3			(0x3 << 2)
+#define RT5616_ADC_OSR_MASK			(0x3)
+#define RT5616_ADC_OSR_SFT			0
+#define RT5616_ADC_OSR_128			(0x0)
+#define RT5616_ADC_OSR_64			(0x1)
+#define RT5616_ADC_OSR_32			(0x2)
+#define RT5616_ADC_OSR_128_3			(0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5616_DAHPF_EN				(0x1 << 11)
+#define RT5616_DAHPF_EN_SFT			11
+#define RT5616_ADHPF_EN				(0x1 << 10)
+#define RT5616_ADHPF_EN_SFT			10
+
+/* TDM Control 1 (0x77) */
+#define RT5616_TDM_INTEL_SEL_MASK		(0x1 << 15)
+#define RT5616_TDM_INTEL_SEL_SFT		15
+#define RT5616_TDM_INTEL_SEL_64			(0x0 << 15)
+#define RT5616_TDM_INTEL_SEL_50			(0x1 << 15)
+#define RT5616_TDM_MODE_SEL_MASK		(0x1 << 14)
+#define RT5616_TDM_MODE_SEL_SFT			14
+#define RT5616_TDM_MODE_SEL_NOR			(0x0 << 14)
+#define RT5616_TDM_MODE_SEL_TDM			(0x1 << 14)
+#define RT5616_TDM_CH_NUM_SEL_MASK		(0x3 << 12)
+#define RT5616_TDM_CH_NUM_SEL_SFT		12
+#define RT5616_TDM_CH_NUM_SEL_2			(0x0 << 12)
+#define RT5616_TDM_CH_NUM_SEL_4			(0x1 << 12)
+#define RT5616_TDM_CH_NUM_SEL_6			(0x2 << 12)
+#define RT5616_TDM_CH_NUM_SEL_8			(0x3 << 12)
+#define RT5616_TDM_CH_LEN_SEL_MASK		(0x3 << 10)
+#define RT5616_TDM_CH_LEN_SEL_SFT		10
+#define RT5616_TDM_CH_LEN_SEL_16		(0x0 << 10)
+#define RT5616_TDM_CH_LEN_SEL_20		(0x1 << 10)
+#define RT5616_TDM_CH_LEN_SEL_24		(0x2 << 10)
+#define RT5616_TDM_CH_LEN_SEL_32		(0x3 << 10)
+#define RT5616_TDM_ADC_SEL_MASK			(0x1 << 9)
+#define RT5616_TDM_ADC_SEL_SFT			9
+#define RT5616_TDM_ADC_SEL_NOR			(0x0 << 9)
+#define RT5616_TDM_ADC_SEL_SWAP			(0x1 << 9)
+#define RT5616_TDM_ADC_START_SEL_MASK		(0x1 << 8)
+#define RT5616_TDM_ADC_START_SEL_SFT		8
+#define RT5616_TDM_ADC_START_SEL_SL0		(0x0 << 8)
+#define RT5616_TDM_ADC_START_SEL_SL4		(0x1 << 8)
+#define RT5616_TDM_I2S_CH2_SEL_MASK		(0x3 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_SFT		6
+#define RT5616_TDM_I2S_CH2_SEL_LR		(0x0 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_RL		(0x1 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_LL		(0x2 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_RR		(0x3 << 6)
+#define RT5616_TDM_I2S_CH4_SEL_MASK		(0x3 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_SFT		4
+#define RT5616_TDM_I2S_CH4_SEL_LR		(0x0 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_RL		(0x1 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_LL		(0x2 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_RR		(0x3 << 4)
+#define RT5616_TDM_I2S_CH6_SEL_MASK		(0x3 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_SFT		2
+#define RT5616_TDM_I2S_CH6_SEL_LR		(0x0 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_RL		(0x1 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_LL		(0x2 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_RR		(0x3 << 2)
+#define RT5616_TDM_I2S_CH8_SEL_MASK		(0x3)
+#define RT5616_TDM_I2S_CH8_SEL_SFT		0
+#define RT5616_TDM_I2S_CH8_SEL_LR		(0x0)
+#define RT5616_TDM_I2S_CH8_SEL_RL		(0x1)
+#define RT5616_TDM_I2S_CH8_SEL_LL		(0x2)
+#define RT5616_TDM_I2S_CH8_SEL_RR		(0x3)
+
+/* TDM Control 2 (0x78) */
+#define RT5616_TDM_LRCK_POL_SEL_MASK		(0x1 << 15)
+#define RT5616_TDM_LRCK_POL_SEL_SFT		15
+#define RT5616_TDM_LRCK_POL_SEL_NOR		(0x0 << 15)
+#define RT5616_TDM_LRCK_POL_SEL_INV		(0x1 << 15)
+#define RT5616_TDM_CH_VAL_SEL_MASK		(0x1 << 14)
+#define RT5616_TDM_CH_VAL_SEL_SFT		14
+#define RT5616_TDM_CH_VAL_SEL_CH01		(0x0 << 14)
+#define RT5616_TDM_CH_VAL_SEL_CH0123		(0x1 << 14)
+#define RT5616_TDM_CH_VAL_EN			(0x1 << 13)
+#define RT5616_TDM_CH_VAL_SFT			13
+#define RT5616_TDM_LPBK_EN			(0x1 << 12)
+#define RT5616_TDM_LPBK_SFT			12
+#define RT5616_TDM_LRCK_PULSE_SEL_MASK		(0x1 << 11)
+#define RT5616_TDM_LRCK_PULSE_SEL_SFT		11
+#define RT5616_TDM_LRCK_PULSE_SEL_BCLK		(0x0 << 11)
+#define RT5616_TDM_LRCK_PULSE_SEL_CH		(0x1 << 11)
+#define RT5616_TDM_END_EDGE_SEL_MASK		(0x1 << 10)
+#define RT5616_TDM_END_EDGE_SEL_SFT		10
+#define RT5616_TDM_END_EDGE_SEL_POS		(0x0 << 10)
+#define RT5616_TDM_END_EDGE_SEL_NEG		(0x1 << 10)
+#define RT5616_TDM_END_EDGE_EN			(0x1 << 9)
+#define RT5616_TDM_END_EDGE_EN_SFT		9
+#define RT5616_TDM_TRAN_EDGE_SEL_MASK		(0x1 << 8)
+#define RT5616_TDM_TRAN_EDGE_SEL_SFT		8
+#define RT5616_TDM_TRAN_EDGE_SEL_POS		(0x0 << 8)
+#define RT5616_TDM_TRAN_EDGE_SEL_NEG		(0x1 << 8)
+#define RT5616_M_TDM2_L				(0x1 << 7)
+#define RT5616_M_TDM2_L_SFT			7
+#define RT5616_M_TDM2_R				(0x1 << 6)
+#define RT5616_M_TDM2_R_SFT			6
+#define RT5616_M_TDM4_L				(0x1 << 5)
+#define RT5616_M_TDM4_L_SFT			5
+#define RT5616_M_TDM4_R				(0x1 << 4)
+#define RT5616_M_TDM4_R_SFT			4
+
+/* Global Clock Control (0x80) */
+#define RT5616_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5616_SCLK_SRC_SFT			14
+#define RT5616_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5616_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5616_PLL1_SRC_MASK			(0x3 << 12)
+#define RT5616_PLL1_SRC_SFT			12
+#define RT5616_PLL1_SRC_MCLK			(0x0 << 12)
+#define RT5616_PLL1_SRC_BCLK1			(0x1 << 12)
+#define RT5616_PLL1_SRC_BCLK2			(0x2 << 12)
+#define RT5616_PLL1_PD_MASK			(0x1 << 3)
+#define RT5616_PLL1_PD_SFT			3
+#define RT5616_PLL1_PD_1			(0x0 << 3)
+#define RT5616_PLL1_PD_2			(0x1 << 3)
+
+#define RT5616_PLL_INP_MAX			40000000
+#define RT5616_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5616_PLL_N_MAX			0x1ff
+#define RT5616_PLL_N_MASK			(RT5616_PLL_N_MAX << 7)
+#define RT5616_PLL_N_SFT			7
+#define RT5616_PLL_K_MAX			0x1f
+#define RT5616_PLL_K_MASK			(RT5616_PLL_K_MAX)
+#define RT5616_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5616_PLL_M_MAX			0xf
+#define RT5616_PLL_M_MASK			(RT5616_PLL_M_MAX << 12)
+#define RT5616_PLL_M_SFT			12
+#define RT5616_PLL_M_BP				(0x1 << 11)
+#define RT5616_PLL_M_BP_SFT			11
+
+/* PLL tracking mode 1 (0x83) */
+#define RT5616_STO1_T_MASK			(0x1 << 15)
+#define RT5616_STO1_T_SFT			15
+#define RT5616_STO1_T_SCLK			(0x0 << 15)
+#define RT5616_STO1_T_LRCK1			(0x1 << 15)
+#define RT5616_STO2_T_MASK			(0x1 << 12)
+#define RT5616_STO2_T_SFT			12
+#define RT5616_STO2_T_I2S2			(0x0 << 12)
+#define RT5616_STO2_T_LRCK2			(0x1 << 12)
+#define RT5616_ASRC2_REF_MASK			(0x1 << 11)
+#define RT5616_ASRC2_REF_SFT			11
+#define RT5616_ASRC2_REF_LRCK2			(0x0 << 11)
+#define RT5616_ASRC2_REF_LRCK1			(0x1 << 11)
+#define RT5616_DMIC_1_M_MASK			(0x1 << 9)
+#define RT5616_DMIC_1_M_SFT			9
+#define RT5616_DMIC_1_M_NOR			(0x0 << 9)
+#define RT5616_DMIC_1_M_ASYN			(0x1 << 9)
+
+/* PLL tracking mode 2 (0x84) */
+#define RT5616_STO1_ASRC_EN			(0x1 << 15)
+#define RT5616_STO1_ASRC_EN_SFT			15
+#define RT5616_STO2_ASRC_EN			(0x1 << 14)
+#define RT5616_STO2_ASRC_EN_SFT			14
+#define RT5616_STO1_DAC_M_MASK			(0x1 << 13)
+#define RT5616_STO1_DAC_M_SFT			13
+#define RT5616_STO1_DAC_M_NOR			(0x0 << 13)
+#define RT5616_STO1_DAC_M_ASRC			(0x1 << 13)
+#define RT5616_STO2_DAC_M_MASK			(0x1 << 12)
+#define RT5616_STO2_DAC_M_SFT			12
+#define RT5616_STO2_DAC_M_NOR			(0x0 << 12)
+#define RT5616_STO2_DAC_M_ASRC			(0x1 << 12)
+#define RT5616_ADC_M_MASK			(0x1 << 11)
+#define RT5616_ADC_M_SFT			11
+#define RT5616_ADC_M_NOR			(0x0 << 11)
+#define RT5616_ADC_M_ASRC			(0x1 << 11)
+#define RT5616_I2S1_R_D_MASK			(0x1 << 4)
+#define RT5616_I2S1_R_D_SFT			4
+#define RT5616_I2S1_R_D_DIS			(0x0 << 4)
+#define RT5616_I2S1_R_D_EN			(0x1 << 4)
+#define RT5616_I2S2_R_D_MASK			(0x1 << 3)
+#define RT5616_I2S2_R_D_SFT			3
+#define RT5616_I2S2_R_D_DIS			(0x0 << 3)
+#define RT5616_I2S2_R_D_EN			(0x1 << 3)
+#define RT5616_PRE_SCLK_MASK			(0x3)
+#define RT5616_PRE_SCLK_SFT			0
+#define RT5616_PRE_SCLK_512			(0x0)
+#define RT5616_PRE_SCLK_1024			(0x1)
+#define RT5616_PRE_SCLK_2048			(0x2)
+
+/* PLL tracking mode 3 (0x85) */
+#define RT5616_I2S1_RATE_MASK			(0xf << 12)
+#define RT5616_I2S1_RATE_SFT			12
+#define RT5616_I2S2_RATE_MASK			(0xf << 8)
+#define RT5616_I2S2_RATE_SFT			8
+#define RT5616_G_ASRC_LP_MASK			(0x1 << 3)
+#define RT5616_G_ASRC_LP_SFT			3
+#define RT5616_ASRC_LP_F_M			(0x1 << 2)
+#define RT5616_ASRC_LP_F_SFT			2
+#define RT5616_ASRC_LP_F_NOR			(0x0 << 2)
+#define RT5616_ASRC_LP_F_SB			(0x1 << 2)
+#define RT5616_FTK_PH_DET_MASK			(0x3)
+#define RT5616_FTK_PH_DET_SFT			0
+#define RT5616_FTK_PH_DET_DIV1			(0x0)
+#define RT5616_FTK_PH_DET_DIV2			(0x1)
+#define RT5616_FTK_PH_DET_DIV4			(0x2)
+#define RT5616_FTK_PH_DET_DIV8			(0x3)
+
+/*PLL tracking mode 6 (0x89) */
+#define RT5616_I2S1_PD_MASK			(0x7 << 12)
+#define RT5616_I2S1_PD_SFT			12
+#define RT5616_I2S2_PD_MASK			(0x7 << 8)
+#define RT5616_I2S2_PD_SFT			8
+
+/*PLL tracking mode 7 (0x8a) */
+#define RT5616_FSI1_RATE_MASK			(0xf << 12)
+#define RT5616_FSI1_RATE_SFT			12
+#define RT5616_FSI2_RATE_MASK			(0xf << 8)
+#define RT5616_FSI2_RATE_SFT			8
+
+/* HPOUT Over Current Detection (0x8b) */
+#define RT5616_HP_OVCD_MASK			(0x1 << 10)
+#define RT5616_HP_OVCD_SFT			10
+#define RT5616_HP_OVCD_DIS			(0x0 << 10)
+#define RT5616_HP_OVCD_EN			(0x1 << 10)
+#define RT5616_HP_OC_TH_MASK			(0x3 << 8)
+#define RT5616_HP_OC_TH_SFT			8
+#define RT5616_HP_OC_TH_90			(0x0 << 8)
+#define RT5616_HP_OC_TH_105			(0x1 << 8)
+#define RT5616_HP_OC_TH_120			(0x2 << 8)
+#define RT5616_HP_OC_TH_135			(0x3 << 8)
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5616_SMT_TRIG_MASK			(0x1 << 15)
+#define RT5616_SMT_TRIG_SFT			15
+#define RT5616_SMT_TRIG_DIS			(0x0 << 15)
+#define RT5616_SMT_TRIG_EN			(0x1 << 15)
+#define RT5616_HP_L_SMT_MASK			(0x1 << 9)
+#define RT5616_HP_L_SMT_SFT			9
+#define RT5616_HP_L_SMT_DIS			(0x0 << 9)
+#define RT5616_HP_L_SMT_EN			(0x1 << 9)
+#define RT5616_HP_R_SMT_MASK			(0x1 << 8)
+#define RT5616_HP_R_SMT_SFT			8
+#define RT5616_HP_R_SMT_DIS			(0x0 << 8)
+#define RT5616_HP_R_SMT_EN			(0x1 << 8)
+#define RT5616_HP_CD_PD_MASK			(0x1 << 7)
+#define RT5616_HP_CD_PD_SFT			7
+#define RT5616_HP_CD_PD_DIS			(0x0 << 7)
+#define RT5616_HP_CD_PD_EN			(0x1 << 7)
+#define RT5616_RSTN_MASK			(0x1 << 6)
+#define RT5616_RSTN_SFT				6
+#define RT5616_RSTN_DIS				(0x0 << 6)
+#define RT5616_RSTN_EN				(0x1 << 6)
+#define RT5616_RSTP_MASK			(0x1 << 5)
+#define RT5616_RSTP_SFT				5
+#define RT5616_RSTP_DIS				(0x0 << 5)
+#define RT5616_RSTP_EN				(0x1 << 5)
+#define RT5616_HP_CO_MASK			(0x1 << 4)
+#define RT5616_HP_CO_SFT			4
+#define RT5616_HP_CO_DIS			(0x0 << 4)
+#define RT5616_HP_CO_EN				(0x1 << 4)
+#define RT5616_HP_CP_MASK			(0x1 << 3)
+#define RT5616_HP_CP_SFT			3
+#define RT5616_HP_CP_PD				(0x0 << 3)
+#define RT5616_HP_CP_PU				(0x1 << 3)
+#define RT5616_HP_SG_MASK			(0x1 << 2)
+#define RT5616_HP_SG_SFT			2
+#define RT5616_HP_SG_DIS			(0x0 << 2)
+#define RT5616_HP_SG_EN				(0x1 << 2)
+#define RT5616_HP_DP_MASK			(0x1 << 1)
+#define RT5616_HP_DP_SFT			1
+#define RT5616_HP_DP_PD				(0x0 << 1)
+#define RT5616_HP_DP_PU				(0x1 << 1)
+#define RT5616_HP_CB_MASK			(0x1)
+#define RT5616_HP_CB_SFT			0
+#define RT5616_HP_CB_PD				(0x0)
+#define RT5616_HP_CB_PU				(0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5616_DEPOP_MASK			(0x1 << 13)
+#define RT5616_DEPOP_SFT			13
+#define RT5616_DEPOP_AUTO			(0x0 << 13)
+#define RT5616_DEPOP_MAN			(0x1 << 13)
+#define RT5616_RAMP_MASK			(0x1 << 12)
+#define RT5616_RAMP_SFT				12
+#define RT5616_RAMP_DIS				(0x0 << 12)
+#define RT5616_RAMP_EN				(0x1 << 12)
+#define RT5616_BPS_MASK				(0x1 << 11)
+#define RT5616_BPS_SFT				11
+#define RT5616_BPS_DIS				(0x0 << 11)
+#define RT5616_BPS_EN				(0x1 << 11)
+#define RT5616_FAST_UPDN_MASK			(0x1 << 10)
+#define RT5616_FAST_UPDN_SFT			10
+#define RT5616_FAST_UPDN_DIS			(0x0 << 10)
+#define RT5616_FAST_UPDN_EN			(0x1 << 10)
+#define RT5616_MRES_MASK			(0x3 << 8)
+#define RT5616_MRES_SFT				8
+#define RT5616_MRES_15MO			(0x0 << 8)
+#define RT5616_MRES_25MO			(0x1 << 8)
+#define RT5616_MRES_35MO			(0x2 << 8)
+#define RT5616_MRES_45MO			(0x3 << 8)
+#define RT5616_VLO_MASK				(0x1 << 7)
+#define RT5616_VLO_SFT				7
+#define RT5616_VLO_3V				(0x0 << 7)
+#define RT5616_VLO_32V				(0x1 << 7)
+#define RT5616_DIG_DP_MASK			(0x1 << 6)
+#define RT5616_DIG_DP_SFT			6
+#define RT5616_DIG_DP_DIS			(0x0 << 6)
+#define RT5616_DIG_DP_EN			(0x1 << 6)
+#define RT5616_DP_TH_MASK			(0x3 << 4)
+#define RT5616_DP_TH_SFT			4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5616_CP_SYS_MASK			(0x7 << 12)
+#define RT5616_CP_SYS_SFT			12
+#define RT5616_CP_FQ1_MASK			(0x7 << 8)
+#define RT5616_CP_FQ1_SFT			8
+#define RT5616_CP_FQ2_MASK			(0x7 << 4)
+#define RT5616_CP_FQ2_SFT			4
+#define RT5616_CP_FQ3_MASK			(0x7)
+#define RT5616_CP_FQ3_SFT			0
+#define RT5616_CP_FQ_1_5_KHZ			0
+#define RT5616_CP_FQ_3_KHZ			1
+#define RT5616_CP_FQ_6_KHZ			2
+#define RT5616_CP_FQ_12_KHZ			3
+#define RT5616_CP_FQ_24_KHZ			4
+#define RT5616_CP_FQ_48_KHZ			5
+#define RT5616_CP_FQ_96_KHZ			6
+#define RT5616_CP_FQ_192_KHZ			7
+
+/* HPOUT charge pump (0x91) */
+#define RT5616_OSW_L_MASK			(0x1 << 11)
+#define RT5616_OSW_L_SFT			11
+#define RT5616_OSW_L_DIS			(0x0 << 11)
+#define RT5616_OSW_L_EN				(0x1 << 11)
+#define RT5616_OSW_R_MASK			(0x1 << 10)
+#define RT5616_OSW_R_SFT			10
+#define RT5616_OSW_R_DIS			(0x0 << 10)
+#define RT5616_OSW_R_EN				(0x1 << 10)
+#define RT5616_PM_HP_MASK			(0x3 << 8)
+#define RT5616_PM_HP_SFT			8
+#define RT5616_PM_HP_LV				(0x0 << 8)
+#define RT5616_PM_HP_MV				(0x1 << 8)
+#define RT5616_PM_HP_HV				(0x2 << 8)
+#define RT5616_IB_HP_MASK			(0x3 << 6)
+#define RT5616_IB_HP_SFT			6
+#define RT5616_IB_HP_125IL			(0x0 << 6)
+#define RT5616_IB_HP_25IL			(0x1 << 6)
+#define RT5616_IB_HP_5IL			(0x2 << 6)
+#define RT5616_IB_HP_1IL			(0x3 << 6)
+
+/* Micbias Control (0x93) */
+#define RT5616_MIC1_BS_MASK			(0x1 << 15)
+#define RT5616_MIC1_BS_SFT			15
+#define RT5616_MIC1_BS_9AV			(0x0 << 15)
+#define RT5616_MIC1_BS_75AV			(0x1 << 15)
+#define RT5616_MIC1_CLK_MASK			(0x1 << 13)
+#define RT5616_MIC1_CLK_SFT			13
+#define RT5616_MIC1_CLK_DIS			(0x0 << 13)
+#define RT5616_MIC1_CLK_EN			(0x1 << 13)
+#define RT5616_MIC1_OVCD_MASK			(0x1 << 11)
+#define RT5616_MIC1_OVCD_SFT			11
+#define RT5616_MIC1_OVCD_DIS			(0x0 << 11)
+#define RT5616_MIC1_OVCD_EN			(0x1 << 11)
+#define RT5616_MIC1_OVTH_MASK			(0x3 << 9)
+#define RT5616_MIC1_OVTH_SFT			9
+#define RT5616_MIC1_OVTH_600UA			(0x0 << 9)
+#define RT5616_MIC1_OVTH_1500UA			(0x1 << 9)
+#define RT5616_MIC1_OVTH_2000UA			(0x2 << 9)
+#define RT5616_PWR_MB_MASK			(0x1 << 5)
+#define RT5616_PWR_MB_SFT			5
+#define RT5616_PWR_MB_PD			(0x0 << 5)
+#define RT5616_PWR_MB_PU			(0x1 << 5)
+#define RT5616_PWR_CLK12M_MASK			(0x1 << 4)
+#define RT5616_PWR_CLK12M_SFT			4
+#define RT5616_PWR_CLK12M_PD			(0x0 << 4)
+#define RT5616_PWR_CLK12M_PU			(0x1 << 4)
+
+/* Analog JD Control 1 (0x94) */
+#define RT5616_JD2_CMP_MASK			(0x7 << 12)
+#define RT5616_JD2_CMP_SFT			12
+#define RT5616_JD_PU				(0x1 << 11)
+#define RT5616_JD_PU_SFT			11
+#define RT5616_JD_PD				(0x1 << 10)
+#define RT5616_JD_PD_SFT			10
+#define RT5616_JD_MODE_SEL_MASK			(0x3 << 8)
+#define RT5616_JD_MODE_SEL_SFT			8
+#define RT5616_JD_MODE_SEL_M0			(0x0 << 8)
+#define RT5616_JD_MODE_SEL_M1			(0x1 << 8)
+#define RT5616_JD_MODE_SEL_M2			(0x2 << 8)
+#define RT5616_JD_M_CMP				(0x7 << 4)
+#define RT5616_JD_M_CMP_SFT			4
+#define RT5616_JD_M_PU				(0x1 << 3)
+#define RT5616_JD_M_PU_SFT			3
+#define RT5616_JD_M_PD				(0x1 << 2)
+#define RT5616_JD_M_PD_SFT			2
+#define RT5616_JD_M_MODE_SEL_MASK		(0x3)
+#define RT5616_JD_M_MODE_SEL_SFT		0
+#define RT5616_JD_M_MODE_SEL_M0			(0x0)
+#define RT5616_JD_M_MODE_SEL_M1			(0x1)
+#define RT5616_JD_M_MODE_SEL_M2			(0x2)
+
+/* Analog JD Control 2 (0x95) */
+#define RT5616_JD3_CMP_MASK			(0x7 << 12)
+#define RT5616_JD3_CMP_SFT			12
+
+/* EQ Control 1 (0xb0) */
+#define RT5616_EQ_SRC_MASK			(0x1 << 15)
+#define RT5616_EQ_SRC_SFT			15
+#define RT5616_EQ_SRC_DAC			(0x0 << 15)
+#define RT5616_EQ_SRC_ADC			(0x1 << 15)
+#define RT5616_EQ_UPD				(0x1 << 14)
+#define RT5616_EQ_UPD_BIT			14
+#define RT5616_EQ_CD_MASK			(0x1 << 13)
+#define RT5616_EQ_CD_SFT			13
+#define RT5616_EQ_CD_DIS			(0x0 << 13)
+#define RT5616_EQ_CD_EN				(0x1 << 13)
+#define RT5616_EQ_DITH_MASK			(0x3 << 8)
+#define RT5616_EQ_DITH_SFT			8
+#define RT5616_EQ_DITH_NOR			(0x0 << 8)
+#define RT5616_EQ_DITH_LSB			(0x1 << 8)
+#define RT5616_EQ_DITH_LSB_1			(0x2 << 8)
+#define RT5616_EQ_DITH_LSB_2			(0x3 << 8)
+#define RT5616_EQ_CD_F				(0x1 << 7)
+#define RT5616_EQ_CD_F_BIT			7
+#define RT5616_EQ_STA_HP2			(0x1 << 6)
+#define RT5616_EQ_STA_HP2_BIT			6
+#define RT5616_EQ_STA_HP1			(0x1 << 5)
+#define RT5616_EQ_STA_HP1_BIT			5
+#define RT5616_EQ_STA_BP4			(0x1 << 4)
+#define RT5616_EQ_STA_BP4_BIT			4
+#define RT5616_EQ_STA_BP3			(0x1 << 3)
+#define RT5616_EQ_STA_BP3_BIT			3
+#define RT5616_EQ_STA_BP2			(0x1 << 2)
+#define RT5616_EQ_STA_BP2_BIT			2
+#define RT5616_EQ_STA_BP1			(0x1 << 1)
+#define RT5616_EQ_STA_BP1_BIT			1
+#define RT5616_EQ_STA_LP			(0x1)
+#define RT5616_EQ_STA_LP_BIT			0
+
+/* EQ Control 2 (0xb1) */
+#define RT5616_EQ_HPF1_M_MASK			(0x1 << 8)
+#define RT5616_EQ_HPF1_M_SFT			8
+#define RT5616_EQ_HPF1_M_HI			(0x0 << 8)
+#define RT5616_EQ_HPF1_M_1ST			(0x1 << 8)
+#define RT5616_EQ_LPF1_M_MASK			(0x1 << 7)
+#define RT5616_EQ_LPF1_M_SFT			7
+#define RT5616_EQ_LPF1_M_LO			(0x0 << 7)
+#define RT5616_EQ_LPF1_M_1ST			(0x1 << 7)
+#define RT5616_EQ_HPF2_MASK			(0x1 << 6)
+#define RT5616_EQ_HPF2_SFT			6
+#define RT5616_EQ_HPF2_DIS			(0x0 << 6)
+#define RT5616_EQ_HPF2_EN			(0x1 << 6)
+#define RT5616_EQ_HPF1_MASK			(0x1 << 5)
+#define RT5616_EQ_HPF1_SFT			5
+#define RT5616_EQ_HPF1_DIS			(0x0 << 5)
+#define RT5616_EQ_HPF1_EN			(0x1 << 5)
+#define RT5616_EQ_BPF4_MASK			(0x1 << 4)
+#define RT5616_EQ_BPF4_SFT			4
+#define RT5616_EQ_BPF4_DIS			(0x0 << 4)
+#define RT5616_EQ_BPF4_EN			(0x1 << 4)
+#define RT5616_EQ_BPF3_MASK			(0x1 << 3)
+#define RT5616_EQ_BPF3_SFT			3
+#define RT5616_EQ_BPF3_DIS			(0x0 << 3)
+#define RT5616_EQ_BPF3_EN			(0x1 << 3)
+#define RT5616_EQ_BPF2_MASK			(0x1 << 2)
+#define RT5616_EQ_BPF2_SFT			2
+#define RT5616_EQ_BPF2_DIS			(0x0 << 2)
+#define RT5616_EQ_BPF2_EN			(0x1 << 2)
+#define RT5616_EQ_BPF1_MASK			(0x1 << 1)
+#define RT5616_EQ_BPF1_SFT			1
+#define RT5616_EQ_BPF1_DIS			(0x0 << 1)
+#define RT5616_EQ_BPF1_EN			(0x1 << 1)
+#define RT5616_EQ_LPF_MASK			(0x1)
+#define RT5616_EQ_LPF_SFT			0
+#define RT5616_EQ_LPF_DIS			(0x0)
+#define RT5616_EQ_LPF_EN			(0x1)
+#define RT5616_EQ_CTRL_MASK			(0x7f)
+
+/* Memory Test (0xb2) */
+#define RT5616_MT_MASK				(0x1 << 15)
+#define RT5616_MT_SFT				15
+#define RT5616_MT_DIS				(0x0 << 15)
+#define RT5616_MT_EN				(0x1 << 15)
+
+/* DRC/AGC Control 1 (0xb4) */
+#define RT5616_DRC_AGC_P_MASK			(0x1 << 15)
+#define RT5616_DRC_AGC_P_SFT			15
+#define RT5616_DRC_AGC_P_DAC			(0x0 << 15)
+#define RT5616_DRC_AGC_P_ADC			(0x1 << 15)
+#define RT5616_DRC_AGC_MASK			(0x1 << 14)
+#define RT5616_DRC_AGC_SFT			14
+#define RT5616_DRC_AGC_DIS			(0x0 << 14)
+#define RT5616_DRC_AGC_EN			(0x1 << 14)
+#define RT5616_DRC_AGC_UPD			(0x1 << 13)
+#define RT5616_DRC_AGC_UPD_BIT			13
+#define RT5616_DRC_AGC_AR_MASK			(0x1f << 8)
+#define RT5616_DRC_AGC_AR_SFT			8
+#define RT5616_DRC_AGC_R_MASK			(0x7 << 5)
+#define RT5616_DRC_AGC_R_SFT			5
+#define RT5616_DRC_AGC_R_48K			(0x1 << 5)
+#define RT5616_DRC_AGC_R_96K			(0x2 << 5)
+#define RT5616_DRC_AGC_R_192K			(0x3 << 5)
+#define RT5616_DRC_AGC_R_441K			(0x5 << 5)
+#define RT5616_DRC_AGC_R_882K			(0x6 << 5)
+#define RT5616_DRC_AGC_R_1764K			(0x7 << 5)
+#define RT5616_DRC_AGC_RC_MASK			(0x1f)
+#define RT5616_DRC_AGC_RC_SFT			0
+
+/* DRC/AGC Control 2 (0xb5) */
+#define RT5616_DRC_AGC_POB_MASK			(0x3f << 8)
+#define RT5616_DRC_AGC_POB_SFT			8
+#define RT5616_DRC_AGC_CP_MASK			(0x1 << 7)
+#define RT5616_DRC_AGC_CP_SFT			7
+#define RT5616_DRC_AGC_CP_DIS			(0x0 << 7)
+#define RT5616_DRC_AGC_CP_EN			(0x1 << 7)
+#define RT5616_DRC_AGC_CPR_MASK			(0x3 << 5)
+#define RT5616_DRC_AGC_CPR_SFT			5
+#define RT5616_DRC_AGC_CPR_1_1			(0x0 << 5)
+#define RT5616_DRC_AGC_CPR_1_2			(0x1 << 5)
+#define RT5616_DRC_AGC_CPR_1_3			(0x2 << 5)
+#define RT5616_DRC_AGC_CPR_1_4			(0x3 << 5)
+#define RT5616_DRC_AGC_PRB_MASK			(0x1f)
+#define RT5616_DRC_AGC_PRB_SFT			0
+
+/* DRC/AGC Control 3 (0xb6) */
+#define RT5616_DRC_AGC_NGB_MASK			(0xf << 12)
+#define RT5616_DRC_AGC_NGB_SFT			12
+#define RT5616_DRC_AGC_TAR_MASK			(0x1f << 7)
+#define RT5616_DRC_AGC_TAR_SFT			7
+#define RT5616_DRC_AGC_NG_MASK			(0x1 << 6)
+#define RT5616_DRC_AGC_NG_SFT			6
+#define RT5616_DRC_AGC_NG_DIS			(0x0 << 6)
+#define RT5616_DRC_AGC_NG_EN			(0x1 << 6)
+#define RT5616_DRC_AGC_NGH_MASK			(0x1 << 5)
+#define RT5616_DRC_AGC_NGH_SFT			5
+#define RT5616_DRC_AGC_NGH_DIS			(0x0 << 5)
+#define RT5616_DRC_AGC_NGH_EN			(0x1 << 5)
+#define RT5616_DRC_AGC_NGT_MASK			(0x1f)
+#define RT5616_DRC_AGC_NGT_SFT			0
+
+/* Jack Detect Control 1 (0xbb) */
+#define RT5616_JD_MASK				(0x7 << 13)
+#define RT5616_JD_SFT				13
+#define RT5616_JD_DIS				(0x0 << 13)
+#define RT5616_JD_GPIO1				(0x1 << 13)
+#define RT5616_JD_GPIO2				(0x2 << 13)
+#define RT5616_JD_GPIO3				(0x3 << 13)
+#define RT5616_JD_GPIO4				(0x4 << 13)
+#define RT5616_JD_GPIO5				(0x5 << 13)
+#define RT5616_JD_GPIO6				(0x6 << 13)
+#define RT5616_JD_HP_MASK			(0x1 << 11)
+#define RT5616_JD_HP_SFT			11
+#define RT5616_JD_HP_DIS			(0x0 << 11)
+#define RT5616_JD_HP_EN				(0x1 << 11)
+#define RT5616_JD_HP_TRG_MASK			(0x1 << 10)
+#define RT5616_JD_HP_TRG_SFT			10
+#define RT5616_JD_HP_TRG_LO			(0x0 << 10)
+#define RT5616_JD_HP_TRG_HI			(0x1 << 10)
+#define RT5616_JD_SPL_MASK			(0x1 << 9)
+#define RT5616_JD_SPL_SFT			9
+#define RT5616_JD_SPL_DIS			(0x0 << 9)
+#define RT5616_JD_SPL_EN			(0x1 << 9)
+#define RT5616_JD_SPL_TRG_MASK			(0x1 << 8)
+#define RT5616_JD_SPL_TRG_SFT			8
+#define RT5616_JD_SPL_TRG_LO			(0x0 << 8)
+#define RT5616_JD_SPL_TRG_HI			(0x1 << 8)
+#define RT5616_JD_SPR_MASK			(0x1 << 7)
+#define RT5616_JD_SPR_SFT			7
+#define RT5616_JD_SPR_DIS			(0x0 << 7)
+#define RT5616_JD_SPR_EN			(0x1 << 7)
+#define RT5616_JD_SPR_TRG_MASK			(0x1 << 6)
+#define RT5616_JD_SPR_TRG_SFT			6
+#define RT5616_JD_SPR_TRG_LO			(0x0 << 6)
+#define RT5616_JD_SPR_TRG_HI			(0x1 << 6)
+#define RT5616_JD_LO_MASK			(0x1 << 3)
+#define RT5616_JD_LO_SFT			3
+#define RT5616_JD_LO_DIS			(0x0 << 3)
+#define RT5616_JD_LO_EN				(0x1 << 3)
+#define RT5616_JD_LO_TRG_MASK			(0x1 << 2)
+#define RT5616_JD_LO_TRG_SFT			2
+#define RT5616_JD_LO_TRG_LO			(0x0 << 2)
+#define RT5616_JD_LO_TRG_HI			(0x1 << 2)
+
+/* Jack Detect Control 2 (0xbc) */
+#define RT5616_JD_TRG_SEL_MASK			(0x7 << 9)
+#define RT5616_JD_TRG_SEL_SFT			9
+#define RT5616_JD_TRG_SEL_GPIO			(0x0 << 9)
+#define RT5616_JD_TRG_SEL_JD1_1			(0x1 << 9)
+#define RT5616_JD_TRG_SEL_JD1_2			(0x2 << 9)
+#define RT5616_JD_TRG_SEL_JD2			(0x3 << 9)
+#define RT5616_JD_TRG_SEL_JD3			(0x4 << 9)
+#define RT5616_JD3_IRQ_EN			(0x1 << 8)
+#define RT5616_JD3_IRQ_EN_SFT			8
+#define RT5616_JD3_EN_STKY			(0x1 << 7)
+#define RT5616_JD3_EN_STKY_SFT			7
+#define RT5616_JD3_INV				(0x1 << 6)
+#define RT5616_JD3_INV_SFT			6
+
+/* IRQ Control 1 (0xbd) */
+#define RT5616_IRQ_JD_MASK			(0x1 << 15)
+#define RT5616_IRQ_JD_SFT			15
+#define RT5616_IRQ_JD_BP			(0x0 << 15)
+#define RT5616_IRQ_JD_NOR			(0x1 << 15)
+#define RT5616_JD_STKY_MASK			(0x1 << 13)
+#define RT5616_JD_STKY_SFT			13
+#define RT5616_JD_STKY_DIS			(0x0 << 13)
+#define RT5616_JD_STKY_EN			(0x1 << 13)
+#define RT5616_JD_P_MASK			(0x1 << 11)
+#define RT5616_JD_P_SFT				11
+#define RT5616_JD_P_NOR				(0x0 << 11)
+#define RT5616_JD_P_INV				(0x1 << 11)
+#define RT5616_JD1_1_IRQ_EN			(0x1 << 9)
+#define RT5616_JD1_1_IRQ_EN_SFT			9
+#define RT5616_JD1_1_EN_STKY			(0x1 << 8)
+#define RT5616_JD1_1_EN_STKY_SFT			8
+#define RT5616_JD1_1_INV			(0x1 << 7)
+#define RT5616_JD1_1_INV_SFT			7
+#define RT5616_JD1_2_IRQ_EN			(0x1 << 6)
+#define RT5616_JD1_2_IRQ_EN_SFT			6
+#define RT5616_JD1_2_EN_STKY			(0x1 << 5)
+#define RT5616_JD1_2_EN_STKY_SFT			5
+#define RT5616_JD1_2_INV			(0x1 << 4)
+#define RT5616_JD1_2_INV_SFT			4
+#define RT5616_JD2_IRQ_EN			(0x1 << 3)
+#define RT5616_JD2_IRQ_EN_SFT			3
+#define RT5616_JD2_EN_STKY			(0x1 << 2)
+#define RT5616_JD2_EN_STKY_SFT			2
+#define RT5616_JD2_INV				(0x1 << 1)
+#define RT5616_JD2_INV_SFT			1
+
+/* IRQ Control 2 (0xbe) */
+#define RT5616_IRQ_MB1_OC_MASK			(0x1 << 15)
+#define RT5616_IRQ_MB1_OC_SFT			15
+#define RT5616_IRQ_MB1_OC_BP			(0x0 << 15)
+#define RT5616_IRQ_MB1_OC_NOR			(0x1 << 15)
+#define RT5616_MB1_OC_STKY_MASK			(0x1 << 11)
+#define RT5616_MB1_OC_STKY_SFT			11
+#define RT5616_MB1_OC_STKY_DIS			(0x0 << 11)
+#define RT5616_MB1_OC_STKY_EN			(0x1 << 11)
+#define RT5616_MB1_OC_P_MASK			(0x1 << 7)
+#define RT5616_MB1_OC_P_SFT			7
+#define RT5616_MB1_OC_P_NOR			(0x0 << 7)
+#define RT5616_MB1_OC_P_INV			(0x1 << 7)
+#define RT5616_MB2_OC_P_MASK			(0x1 << 6)
+#define RT5616_MB1_OC_CLR			(0x1 << 3)
+#define RT5616_MB1_OC_CLR_SFT			3
+#define RT5616_STA_GPIO8			(0x1)
+#define RT5616_STA_GPIO8_BIT			0
+
+/* Internal Status and GPIO status (0xbf) */
+#define RT5616_STA_JD3				(0x1 << 15)
+#define RT5616_STA_JD3_BIT			15
+#define RT5616_STA_JD2				(0x1 << 14)
+#define RT5616_STA_JD2_BIT			14
+#define RT5616_STA_JD1_2			(0x1 << 13)
+#define RT5616_STA_JD1_2_BIT			13
+#define RT5616_STA_JD1_1			(0x1 << 12)
+#define RT5616_STA_JD1_1_BIT			12
+#define RT5616_STA_GP7				(0x1 << 11)
+#define RT5616_STA_GP7_BIT			11
+#define RT5616_STA_GP6				(0x1 << 10)
+#define RT5616_STA_GP6_BIT			10
+#define RT5616_STA_GP5				(0x1 << 9)
+#define RT5616_STA_GP5_BIT			9
+#define RT5616_STA_GP1				(0x1 << 8)
+#define RT5616_STA_GP1_BIT			8
+#define RT5616_STA_GP2				(0x1 << 7)
+#define RT5616_STA_GP2_BIT			7
+#define RT5616_STA_GP3				(0x1 << 6)
+#define RT5616_STA_GP3_BIT			6
+#define RT5616_STA_GP4				(0x1 << 5)
+#define RT5616_STA_GP4_BIT			5
+#define RT5616_STA_GP_JD			(0x1 << 4)
+#define RT5616_STA_GP_JD_BIT			4
+
+/* GPIO Control 1 (0xc0) */
+#define RT5616_GP1_PIN_MASK			(0x1 << 15)
+#define RT5616_GP1_PIN_SFT			15
+#define RT5616_GP1_PIN_GPIO1			(0x0 << 15)
+#define RT5616_GP1_PIN_IRQ			(0x1 << 15)
+#define RT5616_GP2_PIN_MASK			(0x1 << 14)
+#define RT5616_GP2_PIN_SFT			14
+#define RT5616_GP2_PIN_GPIO2			(0x0 << 14)
+#define RT5616_GP2_PIN_DMIC1_SCL		(0x1 << 14)
+#define RT5616_GPIO_M_MASK			(0x1 << 9)
+#define RT5616_GPIO_M_SFT			9
+#define RT5616_GPIO_M_FLT			(0x0 << 9)
+#define RT5616_GPIO_M_PH			(0x1 << 9)
+#define RT5616_I2S2_SEL_MASK			(0x1 << 8)
+#define RT5616_I2S2_SEL_SFT			8
+#define RT5616_I2S2_SEL_I2S			(0x0 << 8)
+#define RT5616_I2S2_SEL_GPIO			(0x1 << 8)
+#define RT5616_GP5_PIN_MASK			(0x1 << 7)
+#define RT5616_GP5_PIN_SFT			7
+#define RT5616_GP5_PIN_GPIO5			(0x0 << 7)
+#define RT5616_GP5_PIN_IRQ			(0x1 << 7)
+#define RT5616_GP6_PIN_MASK			(0x1 << 6)
+#define RT5616_GP6_PIN_SFT			6
+#define RT5616_GP6_PIN_GPIO6			(0x0 << 6)
+#define RT5616_GP6_PIN_DMIC_SDA			(0x1 << 6)
+#define RT5616_GP7_PIN_MASK			(0x1 << 5)
+#define RT5616_GP7_PIN_SFT			5
+#define RT5616_GP7_PIN_GPIO7			(0x0 << 5)
+#define RT5616_GP7_PIN_IRQ			(0x1 << 5)
+#define RT5616_GP8_PIN_MASK			(0x1 << 4)
+#define RT5616_GP8_PIN_SFT			4
+#define RT5616_GP8_PIN_GPIO8			(0x0 << 4)
+#define RT5616_GP8_PIN_DMIC_SDA			(0x1 << 4)
+#define RT5616_GPIO_PDM_SEL_MASK		(0x1 << 3)
+#define RT5616_GPIO_PDM_SEL_SFT			3
+#define RT5616_GPIO_PDM_SEL_GPIO		(0x0 << 3)
+#define RT5616_GPIO_PDM_SEL_PDM			(0x1 << 3)
+
+/* GPIO Control 2 (0xc1) */
+#define RT5616_GP5_DR_MASK			(0x1 << 14)
+#define RT5616_GP5_DR_SFT			14
+#define RT5616_GP5_DR_IN			(0x0 << 14)
+#define RT5616_GP5_DR_OUT			(0x1 << 14)
+#define RT5616_GP5_OUT_MASK			(0x1 << 13)
+#define RT5616_GP5_OUT_SFT			13
+#define RT5616_GP5_OUT_LO			(0x0 << 13)
+#define RT5616_GP5_OUT_HI			(0x1 << 13)
+#define RT5616_GP5_P_MASK			(0x1 << 12)
+#define RT5616_GP5_P_SFT			12
+#define RT5616_GP5_P_NOR			(0x0 << 12)
+#define RT5616_GP5_P_INV			(0x1 << 12)
+#define RT5616_GP4_DR_MASK			(0x1 << 11)
+#define RT5616_GP4_DR_SFT			11
+#define RT5616_GP4_DR_IN			(0x0 << 11)
+#define RT5616_GP4_DR_OUT			(0x1 << 11)
+#define RT5616_GP4_OUT_MASK			(0x1 << 10)
+#define RT5616_GP4_OUT_SFT			10
+#define RT5616_GP4_OUT_LO			(0x0 << 10)
+#define RT5616_GP4_OUT_HI			(0x1 << 10)
+#define RT5616_GP4_P_MASK			(0x1 << 9)
+#define RT5616_GP4_P_SFT			9
+#define RT5616_GP4_P_NOR			(0x0 << 9)
+#define RT5616_GP4_P_INV			(0x1 << 9)
+#define RT5616_GP3_DR_MASK			(0x1 << 8)
+#define RT5616_GP3_DR_SFT			8
+#define RT5616_GP3_DR_IN			(0x0 << 8)
+#define RT5616_GP3_DR_OUT			(0x1 << 8)
+#define RT5616_GP3_OUT_MASK			(0x1 << 7)
+#define RT5616_GP3_OUT_SFT			7
+#define RT5616_GP3_OUT_LO			(0x0 << 7)
+#define RT5616_GP3_OUT_HI			(0x1 << 7)
+#define RT5616_GP3_P_MASK			(0x1 << 6)
+#define RT5616_GP3_P_SFT			6
+#define RT5616_GP3_P_NOR			(0x0 << 6)
+#define RT5616_GP3_P_INV			(0x1 << 6)
+#define RT5616_GP2_DR_MASK			(0x1 << 5)
+#define RT5616_GP2_DR_SFT			5
+#define RT5616_GP2_DR_IN			(0x0 << 5)
+#define RT5616_GP2_DR_OUT			(0x1 << 5)
+#define RT5616_GP2_OUT_MASK			(0x1 << 4)
+#define RT5616_GP2_OUT_SFT			4
+#define RT5616_GP2_OUT_LO			(0x0 << 4)
+#define RT5616_GP2_OUT_HI			(0x1 << 4)
+#define RT5616_GP2_P_MASK			(0x1 << 3)
+#define RT5616_GP2_P_SFT			3
+#define RT5616_GP2_P_NOR			(0x0 << 3)
+#define RT5616_GP2_P_INV			(0x1 << 3)
+#define RT5616_GP1_DR_MASK			(0x1 << 2)
+#define RT5616_GP1_DR_SFT			2
+#define RT5616_GP1_DR_IN			(0x0 << 2)
+#define RT5616_GP1_DR_OUT			(0x1 << 2)
+#define RT5616_GP1_OUT_MASK			(0x1 << 1)
+#define RT5616_GP1_OUT_SFT			1
+#define RT5616_GP1_OUT_LO			(0x0 << 1)
+#define RT5616_GP1_OUT_HI			(0x1 << 1)
+#define RT5616_GP1_P_MASK			(0x1)
+#define RT5616_GP1_P_SFT			0
+#define RT5616_GP1_P_NOR			(0x0)
+#define RT5616_GP1_P_INV			(0x1)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5616_GP8_DR_MASK			(0x1 << 8)
+#define RT5616_GP8_DR_SFT			8
+#define RT5616_GP8_DR_IN			(0x0 << 8)
+#define RT5616_GP8_DR_OUT			(0x1 << 8)
+#define RT5616_GP8_OUT_MASK			(0x1 << 7)
+#define RT5616_GP8_OUT_SFT			7
+#define RT5616_GP8_OUT_LO			(0x0 << 7)
+#define RT5616_GP8_OUT_HI			(0x1 << 7)
+#define RT5616_GP8_P_MASK			(0x1 << 6)
+#define RT5616_GP8_P_SFT			6
+#define RT5616_GP8_P_NOR			(0x0 << 6)
+#define RT5616_GP8_P_INV			(0x1 << 6)
+#define RT5616_GP7_DR_MASK			(0x1 << 5)
+#define RT5616_GP7_DR_SFT			5
+#define RT5616_GP7_DR_IN			(0x0 << 5)
+#define RT5616_GP7_DR_OUT			(0x1 << 5)
+#define RT5616_GP7_OUT_MASK			(0x1 << 4)
+#define RT5616_GP7_OUT_SFT			4
+#define RT5616_GP7_OUT_LO			(0x0 << 4)
+#define RT5616_GP7_OUT_HI			(0x1 << 4)
+#define RT5616_GP7_P_MASK			(0x1 << 3)
+#define RT5616_GP7_P_SFT			3
+#define RT5616_GP7_P_NOR			(0x0 << 3)
+#define RT5616_GP7_P_INV			(0x1 << 3)
+#define RT5616_GP6_DR_MASK			(0x1 << 2)
+#define RT5616_GP6_DR_SFT			2
+#define RT5616_GP6_DR_IN			(0x0 << 2)
+#define RT5616_GP6_DR_OUT			(0x1 << 2)
+#define RT5616_GP6_OUT_MASK			(0x1 << 1)
+#define RT5616_GP6_OUT_SFT			1
+#define RT5616_GP6_OUT_LO			(0x0 << 1)
+#define RT5616_GP6_OUT_HI			(0x1 << 1)
+#define RT5616_GP6_P_MASK			(0x1)
+#define RT5616_GP6_P_SFT			0
+#define RT5616_GP6_P_NOR			(0x0)
+#define RT5616_GP6_P_INV			(0x1)
+
+/* Scramble Control (0xce) */
+#define RT5616_SCB_SWAP_MASK			(0x1 << 15)
+#define RT5616_SCB_SWAP_SFT			15
+#define RT5616_SCB_SWAP_DIS			(0x0 << 15)
+#define RT5616_SCB_SWAP_EN			(0x1 << 15)
+#define RT5616_SCB_MASK				(0x1 << 14)
+#define RT5616_SCB_SFT				14
+#define RT5616_SCB_DIS				(0x0 << 14)
+#define RT5616_SCB_EN				(0x1 << 14)
+
+/* Baseback Control (0xcf) */
+#define RT5616_BB_MASK				(0x1 << 15)
+#define RT5616_BB_SFT				15
+#define RT5616_BB_DIS				(0x0 << 15)
+#define RT5616_BB_EN				(0x1 << 15)
+#define RT5616_BB_CT_MASK			(0x7 << 12)
+#define RT5616_BB_CT_SFT			12
+#define RT5616_BB_CT_A				(0x0 << 12)
+#define RT5616_BB_CT_B				(0x1 << 12)
+#define RT5616_BB_CT_C				(0x2 << 12)
+#define RT5616_BB_CT_D				(0x3 << 12)
+#define RT5616_M_BB_L_MASK			(0x1 << 9)
+#define RT5616_M_BB_L_SFT			9
+#define RT5616_M_BB_R_MASK			(0x1 << 8)
+#define RT5616_M_BB_R_SFT			8
+#define RT5616_M_BB_HPF_L_MASK			(0x1 << 7)
+#define RT5616_M_BB_HPF_L_SFT			7
+#define RT5616_M_BB_HPF_R_MASK			(0x1 << 6)
+#define RT5616_M_BB_HPF_R_SFT			6
+#define RT5616_G_BB_BST_MASK			(0x3f)
+#define RT5616_G_BB_BST_SFT			0
+
+/* MP3 Plus Control 1 (0xd0) */
+#define RT5616_M_MP3_L_MASK			(0x1 << 15)
+#define RT5616_M_MP3_L_SFT			15
+#define RT5616_M_MP3_R_MASK			(0x1 << 14)
+#define RT5616_M_MP3_R_SFT			14
+#define RT5616_M_MP3_MASK			(0x1 << 13)
+#define RT5616_M_MP3_SFT			13
+#define RT5616_M_MP3_DIS			(0x0 << 13)
+#define RT5616_M_MP3_EN				(0x1 << 13)
+#define RT5616_EG_MP3_MASK			(0x1f << 8)
+#define RT5616_EG_MP3_SFT			8
+#define RT5616_MP3_HLP_MASK			(0x1 << 7)
+#define RT5616_MP3_HLP_SFT			7
+#define RT5616_MP3_HLP_DIS			(0x0 << 7)
+#define RT5616_MP3_HLP_EN			(0x1 << 7)
+#define RT5616_M_MP3_ORG_L_MASK			(0x1 << 6)
+#define RT5616_M_MP3_ORG_L_SFT			6
+#define RT5616_M_MP3_ORG_R_MASK			(0x1 << 5)
+#define RT5616_M_MP3_ORG_R_SFT			5
+
+/* MP3 Plus Control 2 (0xd1) */
+#define RT5616_MP3_WT_MASK			(0x1 << 13)
+#define RT5616_MP3_WT_SFT			13
+#define RT5616_MP3_WT_1_4			(0x0 << 13)
+#define RT5616_MP3_WT_1_2			(0x1 << 13)
+#define RT5616_OG_MP3_MASK			(0x1f << 8)
+#define RT5616_OG_MP3_SFT			8
+#define RT5616_HG_MP3_MASK			(0x3f)
+#define RT5616_HG_MP3_SFT			0
+
+/* 3D HP Control 1 (0xd2) */
+#define RT5616_3D_CF_MASK			(0x1 << 15)
+#define RT5616_3D_CF_SFT			15
+#define RT5616_3D_CF_DIS			(0x0 << 15)
+#define RT5616_3D_CF_EN				(0x1 << 15)
+#define RT5616_3D_HP_MASK			(0x1 << 14)
+#define RT5616_3D_HP_SFT			14
+#define RT5616_3D_HP_DIS			(0x0 << 14)
+#define RT5616_3D_HP_EN				(0x1 << 14)
+#define RT5616_3D_BT_MASK			(0x1 << 13)
+#define RT5616_3D_BT_SFT			13
+#define RT5616_3D_BT_DIS			(0x0 << 13)
+#define RT5616_3D_BT_EN				(0x1 << 13)
+#define RT5616_3D_1F_MIX_MASK			(0x3 << 11)
+#define RT5616_3D_1F_MIX_SFT			11
+#define RT5616_3D_HP_M_MASK			(0x1 << 10)
+#define RT5616_3D_HP_M_SFT			10
+#define RT5616_3D_HP_M_SUR			(0x0 << 10)
+#define RT5616_3D_HP_M_FRO			(0x1 << 10)
+#define RT5616_M_3D_HRTF_MASK			(0x1 << 9)
+#define RT5616_M_3D_HRTF_SFT			9
+#define RT5616_M_3D_D2H_MASK			(0x1 << 8)
+#define RT5616_M_3D_D2H_SFT			8
+#define RT5616_M_3D_D2R_MASK			(0x1 << 7)
+#define RT5616_M_3D_D2R_SFT			7
+#define RT5616_M_3D_REVB_MASK			(0x1 << 6)
+#define RT5616_M_3D_REVB_SFT			6
+
+/* Adjustable high pass filter control 1 (0xd3) */
+#define RT5616_2ND_HPF_MASK			(0x1 << 15)
+#define RT5616_2ND_HPF_SFT			15
+#define RT5616_2ND_HPF_DIS			(0x0 << 15)
+#define RT5616_2ND_HPF_EN			(0x1 << 15)
+#define RT5616_HPF_CF_L_MASK			(0x7 << 12)
+#define RT5616_HPF_CF_L_SFT			12
+#define RT5616_HPF_CF_R_MASK			(0x7 << 8)
+#define RT5616_HPF_CF_R_SFT			8
+#define RT5616_ZD_T_MASK			(0x3 << 6)
+#define RT5616_ZD_T_SFT				6
+#define RT5616_ZD_F_MASK			(0x3 << 4)
+#define RT5616_ZD_F_SFT				4
+#define RT5616_ZD_F_IM				(0x0 << 4)
+#define RT5616_ZD_F_ZC_IM			(0x1 << 4)
+#define RT5616_ZD_F_ZC_IOD			(0x2 << 4)
+#define RT5616_ZD_F_UN				(0x3 << 4)
+
+/* Adjustable high pass filter control 2 (0xd4) */
+#define RT5616_HPF_CF_L_NUM_MASK		(0x3f << 8)
+#define RT5616_HPF_CF_L_NUM_SFT			8
+#define RT5616_HPF_CF_R_NUM_MASK		(0x3f)
+#define RT5616_HPF_CF_R_NUM_SFT			0
+
+/* HP calibration control and Amp detection (0xd6) */
+#define RT5616_SI_DAC_MASK			(0x1 << 11)
+#define RT5616_SI_DAC_SFT			11
+#define RT5616_SI_DAC_AUTO			(0x0 << 11)
+#define RT5616_SI_DAC_TEST			(0x1 << 11)
+#define RT5616_DC_CAL_M_MASK			(0x1 << 10)
+#define RT5616_DC_CAL_M_SFT			10
+#define RT5616_DC_CAL_M_NOR			(0x0 << 10)
+#define RT5616_DC_CAL_M_CAL			(0x1 << 10)
+#define RT5616_DC_CAL_MASK			(0x1 << 9)
+#define RT5616_DC_CAL_SFT			9
+#define RT5616_DC_CAL_DIS			(0x0 << 9)
+#define RT5616_DC_CAL_EN			(0x1 << 9)
+#define RT5616_HPD_RCV_MASK			(0x7 << 6)
+#define RT5616_HPD_RCV_SFT			6
+#define RT5616_HPD_PS_MASK			(0x1 << 5)
+#define RT5616_HPD_PS_SFT			5
+#define RT5616_HPD_PS_DIS			(0x0 << 5)
+#define RT5616_HPD_PS_EN			(0x1 << 5)
+#define RT5616_CAL_M_MASK			(0x1 << 4)
+#define RT5616_CAL_M_SFT			4
+#define RT5616_CAL_M_DEP			(0x0 << 4)
+#define RT5616_CAL_M_CAL			(0x1 << 4)
+#define RT5616_CAL_MASK				(0x1 << 3)
+#define RT5616_CAL_SFT				3
+#define RT5616_CAL_DIS				(0x0 << 3)
+#define RT5616_CAL_EN				(0x1 << 3)
+#define RT5616_CAL_TEST_MASK			(0x1 << 2)
+#define RT5616_CAL_TEST_SFT			2
+#define RT5616_CAL_TEST_DIS			(0x0 << 2)
+#define RT5616_CAL_TEST_EN			(0x1 << 2)
+#define RT5616_CAL_P_MASK			(0x3)
+#define RT5616_CAL_P_SFT			0
+#define RT5616_CAL_P_NONE			(0x0)
+#define RT5616_CAL_P_CAL			(0x1)
+#define RT5616_CAL_P_DAC_CAL			(0x2)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5616_SV_MASK				(0x1 << 15)
+#define RT5616_SV_SFT				15
+#define RT5616_SV_DIS				(0x0 << 15)
+#define RT5616_SV_EN				(0x1 << 15)
+#define RT5616_OUT_SV_MASK			(0x1 << 13)
+#define RT5616_OUT_SV_SFT			13
+#define RT5616_OUT_SV_DIS			(0x0 << 13)
+#define RT5616_OUT_SV_EN			(0x1 << 13)
+#define RT5616_HP_SV_MASK			(0x1 << 12)
+#define RT5616_HP_SV_SFT			12
+#define RT5616_HP_SV_DIS			(0x0 << 12)
+#define RT5616_HP_SV_EN				(0x1 << 12)
+#define RT5616_ZCD_DIG_MASK			(0x1 << 11)
+#define RT5616_ZCD_DIG_SFT			11
+#define RT5616_ZCD_DIG_DIS			(0x0 << 11)
+#define RT5616_ZCD_DIG_EN			(0x1 << 11)
+#define RT5616_ZCD_MASK				(0x1 << 10)
+#define RT5616_ZCD_SFT				10
+#define RT5616_ZCD_PD				(0x0 << 10)
+#define RT5616_ZCD_PU				(0x1 << 10)
+#define RT5616_M_ZCD_MASK			(0x3f << 4)
+#define RT5616_M_ZCD_SFT			4
+#define RT5616_M_ZCD_OM_L			(0x1 << 7)
+#define RT5616_M_ZCD_OM_R			(0x1 << 6)
+#define RT5616_M_ZCD_RM_L			(0x1 << 5)
+#define RT5616_M_ZCD_RM_R			(0x1 << 4)
+#define RT5616_SV_DLY_MASK			(0xf)
+#define RT5616_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5616_ZCD_HP_MASK			(0x1 << 15)
+#define RT5616_ZCD_HP_SFT			15
+#define RT5616_ZCD_HP_DIS			(0x0 << 15)
+#define RT5616_ZCD_HP_EN			(0x1 << 15)
+
+/* Digital Misc Control (0xfa) */
+#define RT5616_I2S2_MS_SP_MASK			(0x1 << 8)
+#define RT5616_I2S2_MS_SP_SEL			8
+#define RT5616_I2S2_MS_SP_64			(0x0 << 8)
+#define RT5616_I2S2_MS_SP_50			(0x1 << 8)
+#define RT5616_CLK_DET_EN			(0x1 << 3)
+#define RT5616_CLK_DET_EN_SFT			3
+#define RT5616_AMP_DET_EN			(0x1 << 1)
+#define RT5616_AMP_DET_EN_SFT			1
+#define RT5616_D_GATE_EN			(0x1)
+#define RT5616_D_GATE_EN_SFT			0
+
+/* Codec Private Register definition */
+/* 3D Speaker Control (0x63) */
+#define RT5616_3D_SPK_MASK			(0x1 << 15)
+#define RT5616_3D_SPK_SFT			15
+#define RT5616_3D_SPK_DIS			(0x0 << 15)
+#define RT5616_3D_SPK_EN			(0x1 << 15)
+#define RT5616_3D_SPK_M_MASK			(0x3 << 13)
+#define RT5616_3D_SPK_M_SFT			13
+#define RT5616_3D_SPK_CG_MASK			(0x1f << 8)
+#define RT5616_3D_SPK_CG_SFT			8
+#define RT5616_3D_SPK_SG_MASK			(0x1f)
+#define RT5616_3D_SPK_SG_SFT			0
+
+/* Wind Noise Detection Control 1 (0x6c) */
+#define RT5616_WND_MASK				(0x1 << 15)
+#define RT5616_WND_SFT				15
+#define RT5616_WND_DIS				(0x0 << 15)
+#define RT5616_WND_EN				(0x1 << 15)
+
+/* Wind Noise Detection Control 2 (0x6d) */
+#define RT5616_WND_FC_NW_MASK			(0x3f << 10)
+#define RT5616_WND_FC_NW_SFT			10
+#define RT5616_WND_FC_WK_MASK			(0x3f << 4)
+#define RT5616_WND_FC_WK_SFT			4
+
+/* Wind Noise Detection Control 3 (0x6e) */
+#define RT5616_HPF_FC_MASK			(0x3f << 6)
+#define RT5616_HPF_FC_SFT			6
+#define RT5616_WND_FC_ST_MASK			(0x3f)
+#define RT5616_WND_FC_ST_SFT			0
+
+/* Wind Noise Detection Control 4 (0x6f) */
+#define RT5616_WND_TH_LO_MASK			(0x3ff)
+#define RT5616_WND_TH_LO_SFT			0
+
+/* Wind Noise Detection Control 5 (0x70) */
+#define RT5616_WND_TH_HI_MASK			(0x3ff)
+#define RT5616_WND_TH_HI_SFT			0
+
+/* Wind Noise Detection Control 8 (0x73) */
+#define RT5616_WND_WIND_MASK			(0x1 << 13) /* Read-Only */
+#define RT5616_WND_WIND_SFT			13
+#define RT5616_WND_STRONG_MASK			(0x1 << 12) /* Read-Only */
+#define RT5616_WND_STRONG_SFT			12
+enum {
+	RT5616_NO_WIND,
+	RT5616_BREEZE,
+	RT5616_STORM,
+};
+
+/* Dipole Speaker Interface (0x75) */
+#define RT5616_DP_ATT_MASK			(0x3 << 14)
+#define RT5616_DP_ATT_SFT			14
+#define RT5616_DP_SPK_MASK			(0x1 << 10)
+#define RT5616_DP_SPK_SFT			10
+#define RT5616_DP_SPK_DIS			(0x0 << 10)
+#define RT5616_DP_SPK_EN			(0x1 << 10)
+
+/* EQ Pre Volume Control (0xb3) */
+#define RT5616_EQ_PRE_VOL_MASK			(0xffff)
+#define RT5616_EQ_PRE_VOL_SFT			0
+
+/* EQ Post Volume Control (0xb4) */
+#define RT5616_EQ_PST_VOL_MASK			(0xffff)
+#define RT5616_EQ_PST_VOL_SFT			0
+
+/* System Clock Source */
+enum {
+	RT5616_SCLK_S_MCLK,
+	RT5616_SCLK_S_PLL1,
+};
+
+/* PLL1 Source */
+enum {
+	RT5616_PLL1_S_MCLK,
+	RT5616_PLL1_S_BCLK1,
+	RT5616_PLL1_S_BCLK2,
+};
+
+enum {
+	RT5616_AIF1,
+	RT5616_AIFS,
+};
+
+#endif /* __RT5616_H__ */
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
new file mode 100644
index 0000000..865f49a
--- /dev/null
+++ b/sound/soc/codecs/rt5631.c
@@ -0,0 +1,1742 @@
+/*
+ * rt5631.c  --  RT5631 ALSA Soc Audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ *
+ * Author: flove <flove@realtek.com>
+ *
+ * Based on WM8753.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rt5631.h"
+
+struct rt5631_priv {
+	struct regmap *regmap;
+	int codec_version;
+	int master;
+	int sysclk;
+	int rx_rate;
+	int bclk_rate;
+	int dmic_used_flag;
+};
+
+static const struct reg_default rt5631_reg[] = {
+	{ RT5631_SPK_OUT_VOL, 0x8888 },
+	{ RT5631_HP_OUT_VOL, 0x8080 },
+	{ RT5631_MONO_AXO_1_2_VOL, 0xa080 },
+	{ RT5631_AUX_IN_VOL, 0x0808 },
+	{ RT5631_ADC_REC_MIXER, 0xf0f0 },
+	{ RT5631_VDAC_DIG_VOL, 0x0010 },
+	{ RT5631_OUTMIXER_L_CTRL, 0xffc0 },
+	{ RT5631_OUTMIXER_R_CTRL, 0xffc0 },
+	{ RT5631_AXO1MIXER_CTRL, 0x88c0 },
+	{ RT5631_AXO2MIXER_CTRL, 0x88c0 },
+	{ RT5631_DIG_MIC_CTRL, 0x3000 },
+	{ RT5631_MONO_INPUT_VOL, 0x8808 },
+	{ RT5631_SPK_MIXER_CTRL, 0xf8f8 },
+	{ RT5631_SPK_MONO_OUT_CTRL, 0xfc00 },
+	{ RT5631_SPK_MONO_HP_OUT_CTRL, 0x4440 },
+	{ RT5631_SDP_CTRL, 0x8000 },
+	{ RT5631_MONO_SDP_CTRL, 0x8000 },
+	{ RT5631_STEREO_AD_DA_CLK_CTRL, 0x2010 },
+	{ RT5631_GEN_PUR_CTRL_REG, 0x0e00 },
+	{ RT5631_INT_ST_IRQ_CTRL_2, 0x071a },
+	{ RT5631_MISC_CTRL, 0x2040 },
+	{ RT5631_DEPOP_FUN_CTRL_2, 0x8000 },
+	{ RT5631_SOFT_VOL_CTRL, 0x07e0 },
+	{ RT5631_ALC_CTRL_1, 0x0206 },
+	{ RT5631_ALC_CTRL_3, 0x2000 },
+	{ RT5631_PSEUDO_SPATL_CTRL, 0x0553 },
+};
+
+/**
+ * rt5631_write_index - write index register of 2nd layer
+ */
+static void rt5631_write_index(struct snd_soc_component *component,
+		unsigned int reg, unsigned int value)
+{
+	snd_soc_component_write(component, RT5631_INDEX_ADD, reg);
+	snd_soc_component_write(component, RT5631_INDEX_DATA, value);
+}
+
+/**
+ * rt5631_read_index - read index register of 2nd layer
+ */
+static unsigned int rt5631_read_index(struct snd_soc_component *component,
+				unsigned int reg)
+{
+	unsigned int value;
+
+	snd_soc_component_write(component, RT5631_INDEX_ADD, reg);
+	value = snd_soc_component_read32(component, RT5631_INDEX_DATA);
+
+	return value;
+}
+
+static int rt5631_reset(struct snd_soc_component *component)
+{
+	return snd_soc_component_write(component, RT5631_RESET, 0);
+}
+
+static bool rt5631_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5631_RESET:
+	case RT5631_INT_ST_IRQ_CTRL_2:
+	case RT5631_INDEX_ADD:
+	case RT5631_INDEX_DATA:
+	case RT5631_EQ_CTRL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5631_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5631_RESET:
+	case RT5631_SPK_OUT_VOL:
+	case RT5631_HP_OUT_VOL:
+	case RT5631_MONO_AXO_1_2_VOL:
+	case RT5631_AUX_IN_VOL:
+	case RT5631_STEREO_DAC_VOL_1:
+	case RT5631_MIC_CTRL_1:
+	case RT5631_STEREO_DAC_VOL_2:
+	case RT5631_ADC_CTRL_1:
+	case RT5631_ADC_REC_MIXER:
+	case RT5631_ADC_CTRL_2:
+	case RT5631_VDAC_DIG_VOL:
+	case RT5631_OUTMIXER_L_CTRL:
+	case RT5631_OUTMIXER_R_CTRL:
+	case RT5631_AXO1MIXER_CTRL:
+	case RT5631_AXO2MIXER_CTRL:
+	case RT5631_MIC_CTRL_2:
+	case RT5631_DIG_MIC_CTRL:
+	case RT5631_MONO_INPUT_VOL:
+	case RT5631_SPK_MIXER_CTRL:
+	case RT5631_SPK_MONO_OUT_CTRL:
+	case RT5631_SPK_MONO_HP_OUT_CTRL:
+	case RT5631_SDP_CTRL:
+	case RT5631_MONO_SDP_CTRL:
+	case RT5631_STEREO_AD_DA_CLK_CTRL:
+	case RT5631_PWR_MANAG_ADD1:
+	case RT5631_PWR_MANAG_ADD2:
+	case RT5631_PWR_MANAG_ADD3:
+	case RT5631_PWR_MANAG_ADD4:
+	case RT5631_GEN_PUR_CTRL_REG:
+	case RT5631_GLOBAL_CLK_CTRL:
+	case RT5631_PLL_CTRL:
+	case RT5631_INT_ST_IRQ_CTRL_1:
+	case RT5631_INT_ST_IRQ_CTRL_2:
+	case RT5631_GPIO_CTRL:
+	case RT5631_MISC_CTRL:
+	case RT5631_DEPOP_FUN_CTRL_1:
+	case RT5631_DEPOP_FUN_CTRL_2:
+	case RT5631_JACK_DET_CTRL:
+	case RT5631_SOFT_VOL_CTRL:
+	case RT5631_ALC_CTRL_1:
+	case RT5631_ALC_CTRL_2:
+	case RT5631_ALC_CTRL_3:
+	case RT5631_PSEUDO_SPATL_CTRL:
+	case RT5631_INDEX_ADD:
+	case RT5631_INDEX_DATA:
+	case RT5631_EQ_CTRL:
+	case RT5631_VENDOR_ID:
+	case RT5631_VENDOR_ID1:
+	case RT5631_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -95625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52}dB */
+static const DECLARE_TLV_DB_RANGE(mic_bst_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+static int rt5631_dmic_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = rt5631->dmic_used_flag;
+
+	return 0;
+}
+
+static int rt5631_dmic_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
+
+	rt5631->dmic_used_flag = ucontrol->value.integer.value[0];
+	return 0;
+}
+
+/* MIC Input Type */
+static const char *rt5631_input_mode[] = {
+	"Single ended", "Differential"};
+
+static SOC_ENUM_SINGLE_DECL(rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1,
+			    RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode);
+
+static SOC_ENUM_SINGLE_DECL(rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1,
+			    RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode);
+
+/* MONO Input Type */
+static SOC_ENUM_SINGLE_DECL(rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL,
+			    RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode);
+
+/* SPK Ratio Gain Control */
+static const char *rt5631_spk_ratio[] = {"1.00x", "1.09x", "1.27x", "1.44x",
+			"1.56x", "1.68x", "1.99x", "2.34x"};
+
+static SOC_ENUM_SINGLE_DECL(rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG,
+			    RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio);
+
+static const struct snd_kcontrol_new rt5631_snd_controls[] = {
+	/* MIC */
+	SOC_ENUM("MIC1 Mode Control",  rt5631_mic1_mode_enum),
+	SOC_SINGLE_TLV("MIC1 Boost Volume", RT5631_MIC_CTRL_2,
+		RT5631_MIC1_BOOST_SHIFT, 8, 0, mic_bst_tlv),
+	SOC_ENUM("MIC2 Mode Control", rt5631_mic2_mode_enum),
+	SOC_SINGLE_TLV("MIC2 Boost Volume", RT5631_MIC_CTRL_2,
+		RT5631_MIC2_BOOST_SHIFT, 8, 0, mic_bst_tlv),
+	/* MONO IN */
+	SOC_ENUM("MONOIN Mode Control", rt5631_monoin_mode_enum),
+	SOC_DOUBLE_TLV("MONOIN_RX Capture Volume", RT5631_MONO_INPUT_VOL,
+			RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT,
+			RT5631_VOL_MASK, 1, in_vol_tlv),
+	/* AXI */
+	SOC_DOUBLE_TLV("AXI Capture Volume", RT5631_AUX_IN_VOL,
+			RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT,
+			RT5631_VOL_MASK, 1, in_vol_tlv),
+	/* DAC */
+	SOC_DOUBLE_TLV("PCM Playback Volume", RT5631_STEREO_DAC_VOL_2,
+			RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT,
+			RT5631_DAC_VOL_MASK, 1, dac_vol_tlv),
+	SOC_DOUBLE("PCM Playback Switch", RT5631_STEREO_DAC_VOL_1,
+			RT5631_L_MUTE_SHIFT, RT5631_R_MUTE_SHIFT, 1, 1),
+	/* AXO */
+	SOC_SINGLE("AXO1 Playback Switch", RT5631_MONO_AXO_1_2_VOL,
+				RT5631_L_MUTE_SHIFT, 1, 1),
+	SOC_SINGLE("AXO2 Playback Switch", RT5631_MONO_AXO_1_2_VOL,
+				RT5631_R_VOL_SHIFT, 1, 1),
+	/* OUTVOL */
+	SOC_DOUBLE("OUTVOL Channel Switch", RT5631_SPK_OUT_VOL,
+		RT5631_L_EN_SHIFT, RT5631_R_EN_SHIFT, 1, 0),
+
+	/* SPK */
+	SOC_DOUBLE("Speaker Playback Switch", RT5631_SPK_OUT_VOL,
+		RT5631_L_MUTE_SHIFT, RT5631_R_MUTE_SHIFT, 1, 1),
+	SOC_DOUBLE_TLV("Speaker Playback Volume", RT5631_SPK_OUT_VOL,
+		RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT, 39, 1, out_vol_tlv),
+	/* MONO OUT */
+	SOC_SINGLE("MONO Playback Switch", RT5631_MONO_AXO_1_2_VOL,
+				RT5631_MUTE_MONO_SHIFT, 1, 1),
+	/* HP */
+	SOC_DOUBLE("HP Playback Switch", RT5631_HP_OUT_VOL,
+		RT5631_L_MUTE_SHIFT, RT5631_R_MUTE_SHIFT, 1, 1),
+	SOC_DOUBLE_TLV("HP Playback Volume", RT5631_HP_OUT_VOL,
+		RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT,
+		RT5631_VOL_MASK, 1, out_vol_tlv),
+	/* DMIC */
+	SOC_SINGLE_EXT("DMIC Switch", 0, 0, 1, 0,
+		rt5631_dmic_get, rt5631_dmic_put),
+	SOC_DOUBLE("DMIC Capture Switch", RT5631_DIG_MIC_CTRL,
+		RT5631_DMIC_L_CH_MUTE_SHIFT,
+		RT5631_DMIC_R_CH_MUTE_SHIFT, 1, 1),
+
+	/* SPK Ratio Gain Control */
+	SOC_ENUM("SPK Ratio Control", rt5631_spk_ratio_enum),
+};
+
+static int check_sysclk1_source(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	unsigned int reg;
+
+	reg = snd_soc_component_read32(component, RT5631_GLOBAL_CLK_CTRL);
+	return reg & RT5631_SYSCLK_SOUR_SEL_PLL;
+}
+
+static int check_dmic_used(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
+	return rt5631->dmic_used_flag;
+}
+
+static int check_dacl_to_outmixl(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	unsigned int reg;
+
+	reg = snd_soc_component_read32(component, RT5631_OUTMIXER_L_CTRL);
+	return !(reg & RT5631_M_DAC_L_TO_OUTMIXER_L);
+}
+
+static int check_dacr_to_outmixr(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	unsigned int reg;
+
+	reg = snd_soc_component_read32(component, RT5631_OUTMIXER_R_CTRL);
+	return !(reg & RT5631_M_DAC_R_TO_OUTMIXER_R);
+}
+
+static int check_dacl_to_spkmixl(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	unsigned int reg;
+
+	reg = snd_soc_component_read32(component, RT5631_SPK_MIXER_CTRL);
+	return !(reg & RT5631_M_DAC_L_TO_SPKMIXER_L);
+}
+
+static int check_dacr_to_spkmixr(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	unsigned int reg;
+
+	reg = snd_soc_component_read32(component, RT5631_SPK_MIXER_CTRL);
+	return !(reg & RT5631_M_DAC_R_TO_SPKMIXER_R);
+}
+
+static int check_adcl_select(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	unsigned int reg;
+
+	reg = snd_soc_component_read32(component, RT5631_ADC_REC_MIXER);
+	return !(reg & RT5631_M_MIC1_TO_RECMIXER_L);
+}
+
+static int check_adcr_select(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	unsigned int reg;
+
+	reg = snd_soc_component_read32(component, RT5631_ADC_REC_MIXER);
+	return !(reg & RT5631_M_MIC2_TO_RECMIXER_R);
+}
+
+/**
+ * onebit_depop_power_stage - auto depop in power stage.
+ * @enable: power on/off
+ *
+ * When power on/off headphone, the depop sequence is done by hardware.
+ */
+static void onebit_depop_power_stage(struct snd_soc_component *component, int enable)
+{
+	unsigned int soft_vol, hp_zc;
+
+	/* enable one-bit depop function */
+	snd_soc_component_update_bits(component, RT5631_DEPOP_FUN_CTRL_2,
+				RT5631_EN_ONE_BIT_DEPOP, 0);
+
+	/* keep soft volume and zero crossing setting */
+	soft_vol = snd_soc_component_read32(component, RT5631_SOFT_VOL_CTRL);
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, 0);
+	hp_zc = snd_soc_component_read32(component, RT5631_INT_ST_IRQ_CTRL_2);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
+	if (enable) {
+		/* config one-bit depop parameter */
+		rt5631_write_index(component, RT5631_TEST_MODE_CTRL, 0x84c0);
+		rt5631_write_index(component, RT5631_SPK_INTL_CTRL, 0x309f);
+		rt5631_write_index(component, RT5631_CP_INTL_REG2, 0x6530);
+		/* power on capless block */
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_2,
+				RT5631_EN_CAP_FREE_DEPOP);
+	} else {
+		/* power off capless block */
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_2, 0);
+		msleep(100);
+	}
+
+	/* recover soft volume and zero crossing setting */
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, soft_vol);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
+}
+
+/**
+ * onebit_depop_mute_stage - auto depop in mute stage.
+ * @enable: mute/unmute
+ *
+ * When mute/unmute headphone, the depop sequence is done by hardware.
+ */
+static void onebit_depop_mute_stage(struct snd_soc_component *component, int enable)
+{
+	unsigned int soft_vol, hp_zc;
+
+	/* enable one-bit depop function */
+	snd_soc_component_update_bits(component, RT5631_DEPOP_FUN_CTRL_2,
+				RT5631_EN_ONE_BIT_DEPOP, 0);
+
+	/* keep soft volume and zero crossing setting */
+	soft_vol = snd_soc_component_read32(component, RT5631_SOFT_VOL_CTRL);
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, 0);
+	hp_zc = snd_soc_component_read32(component, RT5631_INT_ST_IRQ_CTRL_2);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
+	if (enable) {
+		schedule_timeout_uninterruptible(msecs_to_jiffies(10));
+		/* config one-bit depop parameter */
+		rt5631_write_index(component, RT5631_SPK_INTL_CTRL, 0x307f);
+		snd_soc_component_update_bits(component, RT5631_HP_OUT_VOL,
+				RT5631_L_MUTE | RT5631_R_MUTE, 0);
+		msleep(300);
+	} else {
+		snd_soc_component_update_bits(component, RT5631_HP_OUT_VOL,
+			RT5631_L_MUTE | RT5631_R_MUTE,
+			RT5631_L_MUTE | RT5631_R_MUTE);
+		msleep(100);
+	}
+
+	/* recover soft volume and zero crossing setting */
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, soft_vol);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
+}
+
+/**
+ * onebit_depop_power_stage - step by step depop sequence in power stage.
+ * @enable: power on/off
+ *
+ * When power on/off headphone, the depop sequence is done in step by step.
+ */
+static void depop_seq_power_stage(struct snd_soc_component *component, int enable)
+{
+	unsigned int soft_vol, hp_zc;
+
+	/* depop control by register */
+	snd_soc_component_update_bits(component, RT5631_DEPOP_FUN_CTRL_2,
+		RT5631_EN_ONE_BIT_DEPOP, RT5631_EN_ONE_BIT_DEPOP);
+
+	/* keep soft volume and zero crossing setting */
+	soft_vol = snd_soc_component_read32(component, RT5631_SOFT_VOL_CTRL);
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, 0);
+	hp_zc = snd_soc_component_read32(component, RT5631_INT_ST_IRQ_CTRL_2);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
+	if (enable) {
+		/* config depop sequence parameter */
+		rt5631_write_index(component, RT5631_SPK_INTL_CTRL, 0x303e);
+
+		/* power on headphone and charge pump */
+		snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
+			RT5631_PWR_CHARGE_PUMP | RT5631_PWR_HP_L_AMP |
+			RT5631_PWR_HP_R_AMP,
+			RT5631_PWR_CHARGE_PUMP | RT5631_PWR_HP_L_AMP |
+			RT5631_PWR_HP_R_AMP);
+
+		/* power on soft generator and depop mode2 */
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_1,
+			RT5631_POW_ON_SOFT_GEN | RT5631_EN_DEPOP2_FOR_HP);
+		msleep(100);
+
+		/* stop depop mode */
+		snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
+			RT5631_PWR_HP_DEPOP_DIS, RT5631_PWR_HP_DEPOP_DIS);
+	} else {
+		/* config depop sequence parameter */
+		rt5631_write_index(component, RT5631_SPK_INTL_CTRL, 0x303F);
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_1,
+			RT5631_POW_ON_SOFT_GEN | RT5631_EN_MUTE_UNMUTE_DEPOP |
+			RT5631_PD_HPAMP_L_ST_UP | RT5631_PD_HPAMP_R_ST_UP);
+		msleep(75);
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_1,
+			RT5631_POW_ON_SOFT_GEN | RT5631_PD_HPAMP_L_ST_UP |
+			RT5631_PD_HPAMP_R_ST_UP);
+
+		/* start depop mode */
+		snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
+				RT5631_PWR_HP_DEPOP_DIS, 0);
+
+		/* config depop sequence parameter */
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_1,
+			RT5631_POW_ON_SOFT_GEN | RT5631_EN_DEPOP2_FOR_HP |
+			RT5631_PD_HPAMP_L_ST_UP | RT5631_PD_HPAMP_R_ST_UP);
+		msleep(80);
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_1,
+			RT5631_POW_ON_SOFT_GEN);
+
+		/* power down headphone and charge pump */
+		snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
+			RT5631_PWR_CHARGE_PUMP | RT5631_PWR_HP_L_AMP |
+			RT5631_PWR_HP_R_AMP, 0);
+	}
+
+	/* recover soft volume and zero crossing setting */
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, soft_vol);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
+}
+
+/**
+ * depop_seq_mute_stage - step by step depop sequence in mute stage.
+ * @enable: mute/unmute
+ *
+ * When mute/unmute headphone, the depop sequence is done in step by step.
+ */
+static void depop_seq_mute_stage(struct snd_soc_component *component, int enable)
+{
+	unsigned int soft_vol, hp_zc;
+
+	/* depop control by register */
+	snd_soc_component_update_bits(component, RT5631_DEPOP_FUN_CTRL_2,
+		RT5631_EN_ONE_BIT_DEPOP, RT5631_EN_ONE_BIT_DEPOP);
+
+	/* keep soft volume and zero crossing setting */
+	soft_vol = snd_soc_component_read32(component, RT5631_SOFT_VOL_CTRL);
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, 0);
+	hp_zc = snd_soc_component_read32(component, RT5631_INT_ST_IRQ_CTRL_2);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff);
+	if (enable) {
+		schedule_timeout_uninterruptible(msecs_to_jiffies(10));
+
+		/* config depop sequence parameter */
+		rt5631_write_index(component, RT5631_SPK_INTL_CTRL, 0x302f);
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_1,
+			RT5631_POW_ON_SOFT_GEN | RT5631_EN_MUTE_UNMUTE_DEPOP |
+			RT5631_EN_HP_R_M_UN_MUTE_DEPOP |
+			RT5631_EN_HP_L_M_UN_MUTE_DEPOP);
+
+		snd_soc_component_update_bits(component, RT5631_HP_OUT_VOL,
+				RT5631_L_MUTE | RT5631_R_MUTE, 0);
+		msleep(160);
+	} else {
+		/* config depop sequence parameter */
+		rt5631_write_index(component, RT5631_SPK_INTL_CTRL, 0x302f);
+		snd_soc_component_write(component, RT5631_DEPOP_FUN_CTRL_1,
+			RT5631_POW_ON_SOFT_GEN | RT5631_EN_MUTE_UNMUTE_DEPOP |
+			RT5631_EN_HP_R_M_UN_MUTE_DEPOP |
+			RT5631_EN_HP_L_M_UN_MUTE_DEPOP);
+
+		snd_soc_component_update_bits(component, RT5631_HP_OUT_VOL,
+			RT5631_L_MUTE | RT5631_R_MUTE,
+			RT5631_L_MUTE | RT5631_R_MUTE);
+		msleep(150);
+	}
+
+	/* recover soft volume and zero crossing setting */
+	snd_soc_component_write(component, RT5631_SOFT_VOL_CTRL, soft_vol);
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, hp_zc);
+}
+
+static int hp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMD:
+		if (rt5631->codec_version) {
+			onebit_depop_mute_stage(component, 0);
+			onebit_depop_power_stage(component, 0);
+		} else {
+			depop_seq_mute_stage(component, 0);
+			depop_seq_power_stage(component, 0);
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		if (rt5631->codec_version) {
+			onebit_depop_power_stage(component, 1);
+			onebit_depop_mute_stage(component, 1);
+		} else {
+			depop_seq_power_stage(component, 1);
+			depop_seq_mute_stage(component, 1);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int set_dmic_params(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
+
+	switch (rt5631->rx_rate) {
+	case 44100:
+	case 48000:
+		snd_soc_component_update_bits(component, RT5631_DIG_MIC_CTRL,
+			RT5631_DMIC_CLK_CTRL_MASK,
+			RT5631_DMIC_CLK_CTRL_TO_32FS);
+		break;
+
+	case 32000:
+	case 22050:
+		snd_soc_component_update_bits(component, RT5631_DIG_MIC_CTRL,
+			RT5631_DMIC_CLK_CTRL_MASK,
+			RT5631_DMIC_CLK_CTRL_TO_64FS);
+		break;
+
+	case 16000:
+	case 11025:
+	case 8000:
+		snd_soc_component_update_bits(component, RT5631_DIG_MIC_CTRL,
+			RT5631_DMIC_CLK_CTRL_MASK,
+			RT5631_DMIC_CLK_CTRL_TO_128FS);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new rt5631_recmixl_mixer_controls[] = {
+	SOC_DAPM_SINGLE("OUTMIXL Capture Switch", RT5631_ADC_REC_MIXER,
+			RT5631_M_OUTMIXL_RECMIXL_BIT, 1, 1),
+	SOC_DAPM_SINGLE("MIC1_BST1 Capture Switch", RT5631_ADC_REC_MIXER,
+			RT5631_M_MIC1_RECMIXL_BIT, 1, 1),
+	SOC_DAPM_SINGLE("AXILVOL Capture Switch", RT5631_ADC_REC_MIXER,
+			RT5631_M_AXIL_RECMIXL_BIT, 1, 1),
+	SOC_DAPM_SINGLE("MONOIN_RX Capture Switch", RT5631_ADC_REC_MIXER,
+			RT5631_M_MONO_IN_RECMIXL_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_recmixr_mixer_controls[] = {
+	SOC_DAPM_SINGLE("MONOIN_RX Capture Switch", RT5631_ADC_REC_MIXER,
+			RT5631_M_MONO_IN_RECMIXR_BIT, 1, 1),
+	SOC_DAPM_SINGLE("AXIRVOL Capture Switch", RT5631_ADC_REC_MIXER,
+			RT5631_M_AXIR_RECMIXR_BIT, 1, 1),
+	SOC_DAPM_SINGLE("MIC2_BST2 Capture Switch", RT5631_ADC_REC_MIXER,
+			RT5631_M_MIC2_RECMIXR_BIT, 1, 1),
+	SOC_DAPM_SINGLE("OUTMIXR Capture Switch", RT5631_ADC_REC_MIXER,
+			RT5631_M_OUTMIXR_RECMIXR_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_spkmixl_mixer_controls[] = {
+	SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_SPK_MIXER_CTRL,
+			RT5631_M_RECMIXL_SPKMIXL_BIT, 1, 1),
+	SOC_DAPM_SINGLE("MIC1_P Playback Switch", RT5631_SPK_MIXER_CTRL,
+			RT5631_M_MIC1P_SPKMIXL_BIT, 1, 1),
+	SOC_DAPM_SINGLE("DACL Playback Switch", RT5631_SPK_MIXER_CTRL,
+			RT5631_M_DACL_SPKMIXL_BIT, 1, 1),
+	SOC_DAPM_SINGLE("OUTMIXL Playback Switch", RT5631_SPK_MIXER_CTRL,
+			RT5631_M_OUTMIXL_SPKMIXL_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_spkmixr_mixer_controls[] = {
+	SOC_DAPM_SINGLE("OUTMIXR Playback Switch", RT5631_SPK_MIXER_CTRL,
+			RT5631_M_OUTMIXR_SPKMIXR_BIT, 1, 1),
+	SOC_DAPM_SINGLE("DACR Playback Switch", RT5631_SPK_MIXER_CTRL,
+			RT5631_M_DACR_SPKMIXR_BIT, 1, 1),
+	SOC_DAPM_SINGLE("MIC2_P Playback Switch", RT5631_SPK_MIXER_CTRL,
+			RT5631_M_MIC2P_SPKMIXR_BIT, 1, 1),
+	SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_SPK_MIXER_CTRL,
+			RT5631_M_RECMIXR_SPKMIXR_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_outmixl_mixer_controls[] = {
+	SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_OUTMIXER_L_CTRL,
+				RT5631_M_RECMIXL_OUTMIXL_BIT, 1, 1),
+	SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_OUTMIXER_L_CTRL,
+				RT5631_M_RECMIXR_OUTMIXL_BIT, 1, 1),
+	SOC_DAPM_SINGLE("DACL Playback Switch", RT5631_OUTMIXER_L_CTRL,
+				RT5631_M_DACL_OUTMIXL_BIT, 1, 1),
+	SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_OUTMIXER_L_CTRL,
+				RT5631_M_MIC1_OUTMIXL_BIT, 1, 1),
+	SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_OUTMIXER_L_CTRL,
+				RT5631_M_MIC2_OUTMIXL_BIT, 1, 1),
+	SOC_DAPM_SINGLE("MONOIN_RXP Playback Switch", RT5631_OUTMIXER_L_CTRL,
+				RT5631_M_MONO_INP_OUTMIXL_BIT, 1, 1),
+	SOC_DAPM_SINGLE("AXILVOL Playback Switch", RT5631_OUTMIXER_L_CTRL,
+				RT5631_M_AXIL_OUTMIXL_BIT, 1, 1),
+	SOC_DAPM_SINGLE("AXIRVOL Playback Switch", RT5631_OUTMIXER_L_CTRL,
+				RT5631_M_AXIR_OUTMIXL_BIT, 1, 1),
+	SOC_DAPM_SINGLE("VDAC Playback Switch", RT5631_OUTMIXER_L_CTRL,
+				RT5631_M_VDAC_OUTMIXL_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_outmixr_mixer_controls[] = {
+	SOC_DAPM_SINGLE("VDAC Playback Switch", RT5631_OUTMIXER_R_CTRL,
+				RT5631_M_VDAC_OUTMIXR_BIT, 1, 1),
+	SOC_DAPM_SINGLE("AXIRVOL Playback Switch", RT5631_OUTMIXER_R_CTRL,
+				RT5631_M_AXIR_OUTMIXR_BIT, 1, 1),
+	SOC_DAPM_SINGLE("AXILVOL Playback Switch", RT5631_OUTMIXER_R_CTRL,
+				RT5631_M_AXIL_OUTMIXR_BIT, 1, 1),
+	SOC_DAPM_SINGLE("MONOIN_RXN Playback Switch", RT5631_OUTMIXER_R_CTRL,
+				RT5631_M_MONO_INN_OUTMIXR_BIT, 1, 1),
+	SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_OUTMIXER_R_CTRL,
+				RT5631_M_MIC2_OUTMIXR_BIT, 1, 1),
+	SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_OUTMIXER_R_CTRL,
+				RT5631_M_MIC1_OUTMIXR_BIT, 1, 1),
+	SOC_DAPM_SINGLE("DACR Playback Switch", RT5631_OUTMIXER_R_CTRL,
+				RT5631_M_DACR_OUTMIXR_BIT, 1, 1),
+	SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_OUTMIXER_R_CTRL,
+				RT5631_M_RECMIXR_OUTMIXR_BIT, 1, 1),
+	SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_OUTMIXER_R_CTRL,
+				RT5631_M_RECMIXL_OUTMIXR_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_AXO1MIX_mixer_controls[] = {
+	SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_AXO1MIXER_CTRL,
+				RT5631_M_MIC1_AXO1MIX_BIT , 1, 1),
+	SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_AXO1MIXER_CTRL,
+				RT5631_M_MIC2_AXO1MIX_BIT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_AXO1MIXER_CTRL,
+				RT5631_M_OUTMIXL_AXO1MIX_BIT , 1 , 1),
+	SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_AXO1MIXER_CTRL,
+				RT5631_M_OUTMIXR_AXO1MIX_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_AXO2MIX_mixer_controls[] = {
+	SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_AXO2MIXER_CTRL,
+				RT5631_M_MIC1_AXO2MIX_BIT, 1, 1),
+	SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_AXO2MIXER_CTRL,
+				RT5631_M_MIC2_AXO2MIX_BIT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_AXO2MIXER_CTRL,
+				RT5631_M_OUTMIXL_AXO2MIX_BIT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_AXO2MIXER_CTRL,
+				RT5631_M_OUTMIXR_AXO2MIX_BIT, 1 , 1),
+};
+
+static const struct snd_kcontrol_new rt5631_spolmix_mixer_controls[] = {
+	SOC_DAPM_SINGLE("SPKVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL,
+				RT5631_M_SPKVOLL_SPOLMIX_BIT, 1, 1),
+	SOC_DAPM_SINGLE("SPKVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL,
+				RT5631_M_SPKVOLR_SPOLMIX_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_spormix_mixer_controls[] = {
+	SOC_DAPM_SINGLE("SPKVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL,
+				RT5631_M_SPKVOLL_SPORMIX_BIT, 1, 1),
+	SOC_DAPM_SINGLE("SPKVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL,
+				RT5631_M_SPKVOLR_SPORMIX_BIT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_monomix_mixer_controls[] = {
+	SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL,
+				RT5631_M_OUTVOLL_MONOMIX_BIT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL,
+				RT5631_M_OUTVOLR_MONOMIX_BIT, 1, 1),
+};
+
+/* Left SPK Volume Input */
+static const char *rt5631_spkvoll_sel[] = {"Vmid", "SPKMIXL"};
+
+static SOC_ENUM_SINGLE_DECL(rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL,
+			    RT5631_L_EN_SHIFT, rt5631_spkvoll_sel);
+
+static const struct snd_kcontrol_new rt5631_spkvoll_mux_control =
+	SOC_DAPM_ENUM("Left SPKVOL SRC", rt5631_spkvoll_enum);
+
+/* Left HP Volume Input */
+static const char *rt5631_hpvoll_sel[] = {"Vmid", "OUTMIXL"};
+
+static SOC_ENUM_SINGLE_DECL(rt5631_hpvoll_enum, RT5631_HP_OUT_VOL,
+			    RT5631_L_EN_SHIFT, rt5631_hpvoll_sel);
+
+static const struct snd_kcontrol_new rt5631_hpvoll_mux_control =
+	SOC_DAPM_ENUM("Left HPVOL SRC", rt5631_hpvoll_enum);
+
+/* Left Out Volume Input */
+static const char *rt5631_outvoll_sel[] = {"Vmid", "OUTMIXL"};
+
+static SOC_ENUM_SINGLE_DECL(rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL,
+			    RT5631_L_EN_SHIFT, rt5631_outvoll_sel);
+
+static const struct snd_kcontrol_new rt5631_outvoll_mux_control =
+	SOC_DAPM_ENUM("Left OUTVOL SRC", rt5631_outvoll_enum);
+
+/* Right Out Volume Input */
+static const char *rt5631_outvolr_sel[] = {"Vmid", "OUTMIXR"};
+
+static SOC_ENUM_SINGLE_DECL(rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL,
+			    RT5631_R_EN_SHIFT, rt5631_outvolr_sel);
+
+static const struct snd_kcontrol_new rt5631_outvolr_mux_control =
+	SOC_DAPM_ENUM("Right OUTVOL SRC", rt5631_outvolr_enum);
+
+/* Right HP Volume Input */
+static const char *rt5631_hpvolr_sel[] = {"Vmid", "OUTMIXR"};
+
+static SOC_ENUM_SINGLE_DECL(rt5631_hpvolr_enum, RT5631_HP_OUT_VOL,
+			    RT5631_R_EN_SHIFT, rt5631_hpvolr_sel);
+
+static const struct snd_kcontrol_new rt5631_hpvolr_mux_control =
+	SOC_DAPM_ENUM("Right HPVOL SRC", rt5631_hpvolr_enum);
+
+/* Right SPK Volume Input */
+static const char *rt5631_spkvolr_sel[] = {"Vmid", "SPKMIXR"};
+
+static SOC_ENUM_SINGLE_DECL(rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL,
+			    RT5631_R_EN_SHIFT, rt5631_spkvolr_sel);
+
+static const struct snd_kcontrol_new rt5631_spkvolr_mux_control =
+	SOC_DAPM_ENUM("Right SPKVOL SRC", rt5631_spkvolr_enum);
+
+/* SPO Left Channel Input */
+static const char *rt5631_spol_src_sel[] = {
+	"SPOLMIX", "MONOIN_RX", "VDAC", "DACL"};
+
+static SOC_ENUM_SINGLE_DECL(rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+			    RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel);
+
+static const struct snd_kcontrol_new rt5631_spol_mux_control =
+	SOC_DAPM_ENUM("SPOL SRC", rt5631_spol_src_enum);
+
+/* SPO Right Channel Input */
+static const char *rt5631_spor_src_sel[] = {
+	"SPORMIX", "MONOIN_RX", "VDAC", "DACR"};
+
+static SOC_ENUM_SINGLE_DECL(rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+			    RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel);
+
+static const struct snd_kcontrol_new rt5631_spor_mux_control =
+	SOC_DAPM_ENUM("SPOR SRC", rt5631_spor_src_enum);
+
+/* MONO Input */
+static const char *rt5631_mono_src_sel[] = {"MONOMIX", "MONOIN_RX", "VDAC"};
+
+static SOC_ENUM_SINGLE_DECL(rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+			    RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel);
+
+static const struct snd_kcontrol_new rt5631_mono_mux_control =
+	SOC_DAPM_ENUM("MONO SRC", rt5631_mono_src_enum);
+
+/* Left HPO Input */
+static const char *rt5631_hpl_src_sel[] = {"Left HPVOL", "Left DAC"};
+
+static SOC_ENUM_SINGLE_DECL(rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+			    RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel);
+
+static const struct snd_kcontrol_new rt5631_hpl_mux_control =
+	SOC_DAPM_ENUM("HPL SRC", rt5631_hpl_src_enum);
+
+/* Right HPO Input */
+static const char *rt5631_hpr_src_sel[] = {"Right HPVOL", "Right DAC"};
+
+static SOC_ENUM_SINGLE_DECL(rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+			    RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel);
+
+static const struct snd_kcontrol_new rt5631_hpr_mux_control =
+	SOC_DAPM_ENUM("HPR SRC", rt5631_hpr_src_enum);
+
+static const struct snd_soc_dapm_widget rt5631_dapm_widgets[] = {
+	/* Vmid */
+	SND_SOC_DAPM_VMID("Vmid"),
+	/* PLL1 */
+	SND_SOC_DAPM_SUPPLY("PLL1", RT5631_PWR_MANAG_ADD2,
+			RT5631_PWR_PLL1_BIT, 0, NULL, 0),
+
+	/* Input Side */
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("AXIL"),
+	SND_SOC_DAPM_INPUT("AXIR"),
+	SND_SOC_DAPM_INPUT("MONOIN_RXN"),
+	SND_SOC_DAPM_INPUT("MONOIN_RXP"),
+	SND_SOC_DAPM_INPUT("DMIC"),
+
+	/* MICBIAS */
+	SND_SOC_DAPM_MICBIAS("MIC Bias1", RT5631_PWR_MANAG_ADD2,
+			RT5631_PWR_MICBIAS1_VOL_BIT, 0),
+	SND_SOC_DAPM_MICBIAS("MIC Bias2", RT5631_PWR_MANAG_ADD2,
+			RT5631_PWR_MICBIAS2_VOL_BIT, 0),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("MIC1 Boost", RT5631_PWR_MANAG_ADD2,
+			RT5631_PWR_MIC1_BOOT_GAIN_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MIC2 Boost", RT5631_PWR_MANAG_ADD2,
+			RT5631_PWR_MIC2_BOOT_GAIN_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MONOIN_RXP Boost", RT5631_PWR_MANAG_ADD4,
+			RT5631_PWR_MONO_IN_P_VOL_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MONOIN_RXN Boost", RT5631_PWR_MANAG_ADD4,
+			RT5631_PWR_MONO_IN_N_VOL_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AXIL Boost", RT5631_PWR_MANAG_ADD4,
+			RT5631_PWR_AXIL_IN_VOL_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AXIR Boost", RT5631_PWR_MANAG_ADD4,
+			RT5631_PWR_AXIR_IN_VOL_BIT, 0, NULL, 0),
+
+	/* MONO In */
+	SND_SOC_DAPM_MIXER("MONO_IN", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIXL Mixer", RT5631_PWR_MANAG_ADD2,
+		RT5631_PWR_RECMIXER_L_BIT, 0,
+		&rt5631_recmixl_mixer_controls[0],
+		ARRAY_SIZE(rt5631_recmixl_mixer_controls)),
+	SND_SOC_DAPM_MIXER("RECMIXR Mixer", RT5631_PWR_MANAG_ADD2,
+		RT5631_PWR_RECMIXER_R_BIT, 0,
+		&rt5631_recmixr_mixer_controls[0],
+		ARRAY_SIZE(rt5631_recmixr_mixer_controls)),
+	/* Because of record duplication for L/R channel,
+	 * L/R ADCs need power up at the same time */
+	SND_SOC_DAPM_MIXER("ADC Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* DMIC */
+	SND_SOC_DAPM_SUPPLY("DMIC Supply", RT5631_DIG_MIC_CTRL,
+		RT5631_DMIC_ENA_SHIFT, 0,
+		set_dmic_params, SND_SOC_DAPM_PRE_PMU),
+	/* ADC Data Srouce */
+	SND_SOC_DAPM_SUPPLY("Left ADC Select", RT5631_INT_ST_IRQ_CTRL_2,
+			RT5631_ADC_DATA_SEL_MIC1_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Right ADC Select", RT5631_INT_ST_IRQ_CTRL_2,
+			RT5631_ADC_DATA_SEL_MIC2_SHIFT, 0, NULL, 0),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("Left ADC", "HIFI Capture",
+		RT5631_PWR_MANAG_ADD1, RT5631_PWR_ADC_L_CLK_BIT, 0),
+	SND_SOC_DAPM_ADC("Right ADC", "HIFI Capture",
+		RT5631_PWR_MANAG_ADD1, RT5631_PWR_ADC_R_CLK_BIT, 0),
+
+	/* DAC and ADC supply power */
+	SND_SOC_DAPM_SUPPLY("I2S", RT5631_PWR_MANAG_ADD1,
+			RT5631_PWR_MAIN_I2S_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC REF", RT5631_PWR_MANAG_ADD1,
+			RT5631_PWR_DAC_REF_BIT, 0, NULL, 0),
+
+	/* Output Side */
+	/* DACs */
+	SND_SOC_DAPM_DAC("Left DAC", "HIFI Playback",
+		RT5631_PWR_MANAG_ADD1, RT5631_PWR_DAC_L_CLK_BIT, 0),
+	SND_SOC_DAPM_DAC("Right DAC", "HIFI Playback",
+		RT5631_PWR_MANAG_ADD1, RT5631_PWR_DAC_R_CLK_BIT, 0),
+	SND_SOC_DAPM_DAC("Voice DAC", "Voice DAC Mono Playback",
+				SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_PGA("Voice DAC Boost", SND_SOC_NOPM, 0, 0, NULL, 0),
+	/* DAC supply power */
+	SND_SOC_DAPM_SUPPLY("Left DAC To Mixer", RT5631_PWR_MANAG_ADD1,
+			RT5631_PWR_DAC_L_TO_MIXER_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Right DAC To Mixer", RT5631_PWR_MANAG_ADD1,
+			RT5631_PWR_DAC_R_TO_MIXER_BIT, 0, NULL, 0),
+
+	/* Left SPK Mixer */
+	SND_SOC_DAPM_MIXER("SPKMIXL Mixer", RT5631_PWR_MANAG_ADD2,
+			RT5631_PWR_SPKMIXER_L_BIT, 0,
+			&rt5631_spkmixl_mixer_controls[0],
+			ARRAY_SIZE(rt5631_spkmixl_mixer_controls)),
+	/* Left Out Mixer */
+	SND_SOC_DAPM_MIXER("OUTMIXL Mixer", RT5631_PWR_MANAG_ADD2,
+			RT5631_PWR_OUTMIXER_L_BIT, 0,
+			&rt5631_outmixl_mixer_controls[0],
+			ARRAY_SIZE(rt5631_outmixl_mixer_controls)),
+	/* Right Out Mixer */
+	SND_SOC_DAPM_MIXER("OUTMIXR Mixer", RT5631_PWR_MANAG_ADD2,
+			RT5631_PWR_OUTMIXER_R_BIT, 0,
+			&rt5631_outmixr_mixer_controls[0],
+			ARRAY_SIZE(rt5631_outmixr_mixer_controls)),
+	/* Right SPK Mixer */
+	SND_SOC_DAPM_MIXER("SPKMIXR Mixer", RT5631_PWR_MANAG_ADD2,
+			RT5631_PWR_SPKMIXER_R_BIT, 0,
+			&rt5631_spkmixr_mixer_controls[0],
+			ARRAY_SIZE(rt5631_spkmixr_mixer_controls)),
+
+	/* Volume Mux */
+	SND_SOC_DAPM_MUX("Left SPKVOL Mux", RT5631_PWR_MANAG_ADD4,
+			RT5631_PWR_SPK_L_VOL_BIT, 0,
+			&rt5631_spkvoll_mux_control),
+	SND_SOC_DAPM_MUX("Left HPVOL Mux", RT5631_PWR_MANAG_ADD4,
+			RT5631_PWR_HP_L_OUT_VOL_BIT, 0,
+			&rt5631_hpvoll_mux_control),
+	SND_SOC_DAPM_MUX("Left OUTVOL Mux", RT5631_PWR_MANAG_ADD4,
+			RT5631_PWR_LOUT_VOL_BIT, 0,
+			&rt5631_outvoll_mux_control),
+	SND_SOC_DAPM_MUX("Right OUTVOL Mux", RT5631_PWR_MANAG_ADD4,
+			RT5631_PWR_ROUT_VOL_BIT, 0,
+			&rt5631_outvolr_mux_control),
+	SND_SOC_DAPM_MUX("Right HPVOL Mux", RT5631_PWR_MANAG_ADD4,
+			RT5631_PWR_HP_R_OUT_VOL_BIT, 0,
+			&rt5631_hpvolr_mux_control),
+	SND_SOC_DAPM_MUX("Right SPKVOL Mux", RT5631_PWR_MANAG_ADD4,
+			RT5631_PWR_SPK_R_VOL_BIT, 0,
+			&rt5631_spkvolr_mux_control),
+
+	/* DAC To HP */
+	SND_SOC_DAPM_PGA_S("Left DAC_HP", 0, SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("Right DAC_HP", 0, SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* HP Depop */
+	SND_SOC_DAPM_PGA_S("HP Depop", 1, SND_SOC_NOPM, 0, 0,
+		hp_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+	/* AXO1 Mixer */
+	SND_SOC_DAPM_MIXER("AXO1MIX Mixer", RT5631_PWR_MANAG_ADD3,
+			RT5631_PWR_AXO1MIXER_BIT, 0,
+			&rt5631_AXO1MIX_mixer_controls[0],
+			ARRAY_SIZE(rt5631_AXO1MIX_mixer_controls)),
+	/* SPOL Mixer */
+	SND_SOC_DAPM_MIXER("SPOLMIX Mixer", SND_SOC_NOPM, 0, 0,
+			&rt5631_spolmix_mixer_controls[0],
+			ARRAY_SIZE(rt5631_spolmix_mixer_controls)),
+	/* MONO Mixer */
+	SND_SOC_DAPM_MIXER("MONOMIX Mixer", RT5631_PWR_MANAG_ADD3,
+			RT5631_PWR_MONOMIXER_BIT, 0,
+			&rt5631_monomix_mixer_controls[0],
+			ARRAY_SIZE(rt5631_monomix_mixer_controls)),
+	/* SPOR Mixer */
+	SND_SOC_DAPM_MIXER("SPORMIX Mixer", SND_SOC_NOPM, 0, 0,
+			&rt5631_spormix_mixer_controls[0],
+			ARRAY_SIZE(rt5631_spormix_mixer_controls)),
+	/* AXO2 Mixer */
+	SND_SOC_DAPM_MIXER("AXO2MIX Mixer", RT5631_PWR_MANAG_ADD3,
+			RT5631_PWR_AXO2MIXER_BIT, 0,
+			&rt5631_AXO2MIX_mixer_controls[0],
+			ARRAY_SIZE(rt5631_AXO2MIX_mixer_controls)),
+
+	/* Mux */
+	SND_SOC_DAPM_MUX("SPOL Mux", SND_SOC_NOPM, 0, 0,
+			&rt5631_spol_mux_control),
+	SND_SOC_DAPM_MUX("SPOR Mux", SND_SOC_NOPM, 0, 0,
+			&rt5631_spor_mux_control),
+	SND_SOC_DAPM_MUX("MONO Mux", SND_SOC_NOPM, 0, 0,
+			&rt5631_mono_mux_control),
+	SND_SOC_DAPM_MUX("HPL Mux", SND_SOC_NOPM, 0, 0,
+			&rt5631_hpl_mux_control),
+	SND_SOC_DAPM_MUX("HPR Mux", SND_SOC_NOPM, 0, 0,
+			&rt5631_hpr_mux_control),
+
+	/* AMP supply */
+	SND_SOC_DAPM_SUPPLY("MONO Depop", RT5631_PWR_MANAG_ADD3,
+			RT5631_PWR_MONO_DEPOP_DIS_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Class D", RT5631_PWR_MANAG_ADD1,
+			RT5631_PWR_CLASS_D_BIT, 0, NULL, 0),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("AUXO1"),
+	SND_SOC_DAPM_OUTPUT("AUXO2"),
+	SND_SOC_DAPM_OUTPUT("SPOL"),
+	SND_SOC_DAPM_OUTPUT("SPOR"),
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+	SND_SOC_DAPM_OUTPUT("MONO"),
+};
+
+static const struct snd_soc_dapm_route rt5631_dapm_routes[] = {
+	{"MIC1 Boost", NULL, "MIC1"},
+	{"MIC2 Boost", NULL, "MIC2"},
+	{"MONOIN_RXP Boost", NULL, "MONOIN_RXP"},
+	{"MONOIN_RXN Boost", NULL, "MONOIN_RXN"},
+	{"AXIL Boost", NULL, "AXIL"},
+	{"AXIR Boost", NULL, "AXIR"},
+
+	{"MONO_IN", NULL, "MONOIN_RXP Boost"},
+	{"MONO_IN", NULL, "MONOIN_RXN Boost"},
+
+	{"RECMIXL Mixer", "OUTMIXL Capture Switch", "OUTMIXL Mixer"},
+	{"RECMIXL Mixer", "MIC1_BST1 Capture Switch", "MIC1 Boost"},
+	{"RECMIXL Mixer", "AXILVOL Capture Switch", "AXIL Boost"},
+	{"RECMIXL Mixer", "MONOIN_RX Capture Switch", "MONO_IN"},
+
+	{"RECMIXR Mixer", "OUTMIXR Capture Switch", "OUTMIXR Mixer"},
+	{"RECMIXR Mixer", "MIC2_BST2 Capture Switch", "MIC2 Boost"},
+	{"RECMIXR Mixer", "AXIRVOL Capture Switch", "AXIR Boost"},
+	{"RECMIXR Mixer", "MONOIN_RX Capture Switch", "MONO_IN"},
+
+	{"ADC Mixer", NULL, "RECMIXL Mixer"},
+	{"ADC Mixer", NULL, "RECMIXR Mixer"},
+
+	{"Left ADC", NULL, "ADC Mixer"},
+	{"Left ADC", NULL, "Left ADC Select", check_adcl_select},
+	{"Left ADC", NULL, "PLL1", check_sysclk1_source},
+	{"Left ADC", NULL, "I2S"},
+	{"Left ADC", NULL, "DAC REF"},
+
+	{"Right ADC", NULL, "ADC Mixer"},
+	{"Right ADC", NULL, "Right ADC Select", check_adcr_select},
+	{"Right ADC", NULL, "PLL1", check_sysclk1_source},
+	{"Right ADC", NULL, "I2S"},
+	{"Right ADC", NULL, "DAC REF"},
+
+	{"DMIC", NULL, "DMIC Supply", check_dmic_used},
+	{"Left ADC", NULL, "DMIC"},
+	{"Right ADC", NULL, "DMIC"},
+
+	{"Left DAC", NULL, "PLL1", check_sysclk1_source},
+	{"Left DAC", NULL, "I2S"},
+	{"Left DAC", NULL, "DAC REF"},
+	{"Right DAC", NULL, "PLL1", check_sysclk1_source},
+	{"Right DAC", NULL, "I2S"},
+	{"Right DAC", NULL, "DAC REF"},
+
+	{"Voice DAC Boost", NULL, "Voice DAC"},
+
+	{"SPKMIXL Mixer", NULL, "Left DAC To Mixer", check_dacl_to_spkmixl},
+	{"SPKMIXL Mixer", "RECMIXL Playback Switch", "RECMIXL Mixer"},
+	{"SPKMIXL Mixer", "MIC1_P Playback Switch", "MIC1"},
+	{"SPKMIXL Mixer", "DACL Playback Switch", "Left DAC"},
+	{"SPKMIXL Mixer", "OUTMIXL Playback Switch", "OUTMIXL Mixer"},
+
+	{"SPKMIXR Mixer", NULL, "Right DAC To Mixer", check_dacr_to_spkmixr},
+	{"SPKMIXR Mixer", "OUTMIXR Playback Switch", "OUTMIXR Mixer"},
+	{"SPKMIXR Mixer", "DACR Playback Switch", "Right DAC"},
+	{"SPKMIXR Mixer", "MIC2_P Playback Switch", "MIC2"},
+	{"SPKMIXR Mixer", "RECMIXR Playback Switch", "RECMIXR Mixer"},
+
+	{"OUTMIXL Mixer", NULL, "Left DAC To Mixer", check_dacl_to_outmixl},
+	{"OUTMIXL Mixer", "RECMIXL Playback Switch", "RECMIXL Mixer"},
+	{"OUTMIXL Mixer", "RECMIXR Playback Switch", "RECMIXR Mixer"},
+	{"OUTMIXL Mixer", "DACL Playback Switch", "Left DAC"},
+	{"OUTMIXL Mixer", "MIC1_BST1 Playback Switch", "MIC1 Boost"},
+	{"OUTMIXL Mixer", "MIC2_BST2 Playback Switch", "MIC2 Boost"},
+	{"OUTMIXL Mixer", "MONOIN_RXP Playback Switch", "MONOIN_RXP Boost"},
+	{"OUTMIXL Mixer", "AXILVOL Playback Switch", "AXIL Boost"},
+	{"OUTMIXL Mixer", "AXIRVOL Playback Switch", "AXIR Boost"},
+	{"OUTMIXL Mixer", "VDAC Playback Switch", "Voice DAC Boost"},
+
+	{"OUTMIXR Mixer", NULL, "Right DAC To Mixer", check_dacr_to_outmixr},
+	{"OUTMIXR Mixer", "RECMIXL Playback Switch", "RECMIXL Mixer"},
+	{"OUTMIXR Mixer", "RECMIXR Playback Switch", "RECMIXR Mixer"},
+	{"OUTMIXR Mixer", "DACR Playback Switch", "Right DAC"},
+	{"OUTMIXR Mixer", "MIC1_BST1 Playback Switch", "MIC1 Boost"},
+	{"OUTMIXR Mixer", "MIC2_BST2 Playback Switch", "MIC2 Boost"},
+	{"OUTMIXR Mixer", "MONOIN_RXN Playback Switch", "MONOIN_RXN Boost"},
+	{"OUTMIXR Mixer", "AXILVOL Playback Switch", "AXIL Boost"},
+	{"OUTMIXR Mixer", "AXIRVOL Playback Switch", "AXIR Boost"},
+	{"OUTMIXR Mixer", "VDAC Playback Switch", "Voice DAC Boost"},
+
+	{"Left SPKVOL Mux",  "SPKMIXL", "SPKMIXL Mixer"},
+	{"Left SPKVOL Mux",  "Vmid", "Vmid"},
+	{"Left HPVOL Mux",  "OUTMIXL", "OUTMIXL Mixer"},
+	{"Left HPVOL Mux",  "Vmid", "Vmid"},
+	{"Left OUTVOL Mux",  "OUTMIXL", "OUTMIXL Mixer"},
+	{"Left OUTVOL Mux",  "Vmid", "Vmid"},
+	{"Right OUTVOL Mux",  "OUTMIXR", "OUTMIXR Mixer"},
+	{"Right OUTVOL Mux",  "Vmid", "Vmid"},
+	{"Right HPVOL Mux",  "OUTMIXR", "OUTMIXR Mixer"},
+	{"Right HPVOL Mux",  "Vmid", "Vmid"},
+	{"Right SPKVOL Mux",  "SPKMIXR", "SPKMIXR Mixer"},
+	{"Right SPKVOL Mux",  "Vmid", "Vmid"},
+
+	{"AXO1MIX Mixer", "MIC1_BST1 Playback Switch", "MIC1 Boost"},
+	{"AXO1MIX Mixer", "OUTVOLL Playback Switch", "Left OUTVOL Mux"},
+	{"AXO1MIX Mixer", "OUTVOLR Playback Switch", "Right OUTVOL Mux"},
+	{"AXO1MIX Mixer", "MIC2_BST2 Playback Switch", "MIC2 Boost"},
+
+	{"AXO2MIX Mixer", "MIC1_BST1 Playback Switch", "MIC1 Boost"},
+	{"AXO2MIX Mixer", "OUTVOLL Playback Switch", "Left OUTVOL Mux"},
+	{"AXO2MIX Mixer", "OUTVOLR Playback Switch", "Right OUTVOL Mux"},
+	{"AXO2MIX Mixer", "MIC2_BST2 Playback Switch", "MIC2 Boost"},
+
+	{"SPOLMIX Mixer", "SPKVOLL Playback Switch", "Left SPKVOL Mux"},
+	{"SPOLMIX Mixer", "SPKVOLR Playback Switch", "Right SPKVOL Mux"},
+
+	{"SPORMIX Mixer", "SPKVOLL Playback Switch", "Left SPKVOL Mux"},
+	{"SPORMIX Mixer", "SPKVOLR Playback Switch", "Right SPKVOL Mux"},
+
+	{"MONOMIX Mixer", "OUTVOLL Playback Switch", "Left OUTVOL Mux"},
+	{"MONOMIX Mixer", "OUTVOLR Playback Switch", "Right OUTVOL Mux"},
+
+	{"SPOL Mux", "SPOLMIX", "SPOLMIX Mixer"},
+	{"SPOL Mux", "MONOIN_RX", "MONO_IN"},
+	{"SPOL Mux", "VDAC", "Voice DAC Boost"},
+	{"SPOL Mux", "DACL", "Left DAC"},
+
+	{"SPOR Mux", "SPORMIX", "SPORMIX Mixer"},
+	{"SPOR Mux", "MONOIN_RX", "MONO_IN"},
+	{"SPOR Mux", "VDAC", "Voice DAC Boost"},
+	{"SPOR Mux", "DACR", "Right DAC"},
+
+	{"MONO Mux", "MONOMIX", "MONOMIX Mixer"},
+	{"MONO Mux", "MONOIN_RX", "MONO_IN"},
+	{"MONO Mux", "VDAC", "Voice DAC Boost"},
+
+	{"Right DAC_HP", NULL, "Right DAC"},
+	{"Left DAC_HP", NULL, "Left DAC"},
+
+	{"HPL Mux", "Left HPVOL", "Left HPVOL Mux"},
+	{"HPL Mux", "Left DAC", "Left DAC_HP"},
+	{"HPR Mux", "Right HPVOL", "Right HPVOL Mux"},
+	{"HPR Mux", "Right DAC", "Right DAC_HP"},
+
+	{"HP Depop", NULL, "HPL Mux"},
+	{"HP Depop", NULL, "HPR Mux"},
+
+	{"AUXO1", NULL, "AXO1MIX Mixer"},
+	{"AUXO2", NULL, "AXO2MIX Mixer"},
+
+	{"SPOL", NULL, "Class D"},
+	{"SPOL", NULL, "SPOL Mux"},
+	{"SPOR", NULL, "Class D"},
+	{"SPOR", NULL, "SPOR Mux"},
+
+	{"HPOL", NULL, "HP Depop"},
+	{"HPOR", NULL, "HP Depop"},
+
+	{"MONO", NULL, "MONO Depop"},
+	{"MONO", NULL, "MONO Mux"},
+};
+
+struct coeff_clk_div {
+	u32 mclk;
+	u32 bclk;
+	u32 rate;
+	u16 reg_val;
+};
+
+/* PLL divisors */
+struct pll_div {
+	u32 pll_in;
+	u32 pll_out;
+	u16 reg_val;
+};
+
+static const struct pll_div codec_master_pll_div[] = {
+	{2048000,  8192000,  0x0ea0},
+	{3686400,  8192000,  0x4e27},
+	{12000000,  8192000,  0x456b},
+	{13000000,  8192000,  0x495f},
+	{13100000,  8192000,  0x0320},
+	{2048000,  11289600,  0xf637},
+	{3686400,  11289600,  0x2f22},
+	{12000000,  11289600,  0x3e2f},
+	{13000000,  11289600,  0x4d5b},
+	{13100000,  11289600,  0x363b},
+	{2048000,  16384000,  0x1ea0},
+	{3686400,  16384000,  0x9e27},
+	{12000000,  16384000,  0x452b},
+	{13000000,  16384000,  0x542f},
+	{13100000,  16384000,  0x03a0},
+	{2048000,  16934400,  0xe625},
+	{3686400,  16934400,  0x9126},
+	{12000000,  16934400,  0x4d2c},
+	{13000000,  16934400,  0x742f},
+	{13100000,  16934400,  0x3c27},
+	{2048000,  22579200,  0x2aa0},
+	{3686400,  22579200,  0x2f20},
+	{12000000,  22579200,  0x7e2f},
+	{13000000,  22579200,  0x742f},
+	{13100000,  22579200,  0x3c27},
+	{2048000,  24576000,  0x2ea0},
+	{3686400,  24576000,  0xee27},
+	{12000000,  24576000,  0x2915},
+	{13000000,  24576000,  0x772e},
+	{13100000,  24576000,  0x0d20},
+	{26000000,  24576000,  0x2027},
+	{26000000,  22579200,  0x392f},
+	{24576000,  22579200,  0x0921},
+	{24576000,  24576000,  0x02a0},
+};
+
+static const struct pll_div codec_slave_pll_div[] = {
+	{256000,  2048000,  0x46f0},
+	{256000,  4096000,  0x3ea0},
+	{352800,  5644800,  0x3ea0},
+	{512000,  8192000,  0x3ea0},
+	{1024000,  8192000,  0x46f0},
+	{705600,  11289600,  0x3ea0},
+	{1024000,  16384000,  0x3ea0},
+	{1411200,  22579200,  0x3ea0},
+	{1536000,  24576000,  0x3ea0},
+	{2048000,  16384000,  0x1ea0},
+	{2822400,  22579200,  0x1ea0},
+	{2822400,  45158400,  0x5ec0},
+	{5644800,  45158400,  0x46f0},
+	{3072000,  24576000,  0x1ea0},
+	{3072000,  49152000,  0x5ec0},
+	{6144000,  49152000,  0x46f0},
+	{705600,  11289600,  0x3ea0},
+	{705600,  8467200,  0x3ab0},
+	{24576000,  24576000,  0x02a0},
+	{1411200,  11289600,  0x1690},
+	{2822400,  11289600,  0x0a90},
+	{1536000,  12288000,  0x1690},
+	{3072000,  12288000,  0x0a90},
+};
+
+static struct coeff_clk_div coeff_div[] = {
+	/* sysclk is 256fs */
+	{2048000,  8000 * 32,  8000, 0x1000},
+	{2048000,  8000 * 64,  8000, 0x0000},
+	{2822400,  11025 * 32,  11025,  0x1000},
+	{2822400,  11025 * 64,  11025,  0x0000},
+	{4096000,  16000 * 32,  16000,  0x1000},
+	{4096000,  16000 * 64,  16000,  0x0000},
+	{5644800,  22050 * 32,  22050,  0x1000},
+	{5644800,  22050 * 64,  22050,  0x0000},
+	{8192000,  32000 * 32,  32000,  0x1000},
+	{8192000,  32000 * 64,  32000,  0x0000},
+	{11289600,  44100 * 32,  44100,  0x1000},
+	{11289600,  44100 * 64,  44100,  0x0000},
+	{12288000,  48000 * 32,  48000,  0x1000},
+	{12288000,  48000 * 64,  48000,  0x0000},
+	{22579200,  88200 * 32,  88200,  0x1000},
+	{22579200,  88200 * 64,  88200,  0x0000},
+	{24576000,  96000 * 32,  96000,  0x1000},
+	{24576000,  96000 * 64,  96000,  0x0000},
+	/* sysclk is 512fs */
+	{4096000,  8000 * 32,  8000, 0x3000},
+	{4096000,  8000 * 64,  8000, 0x2000},
+	{5644800,  11025 * 32,  11025, 0x3000},
+	{5644800,  11025 * 64,  11025, 0x2000},
+	{8192000,  16000 * 32,  16000, 0x3000},
+	{8192000,  16000 * 64,  16000, 0x2000},
+	{11289600,  22050 * 32,  22050, 0x3000},
+	{11289600,  22050 * 64,  22050, 0x2000},
+	{16384000,  32000 * 32,  32000, 0x3000},
+	{16384000,  32000 * 64,  32000, 0x2000},
+	{22579200,  44100 * 32,  44100, 0x3000},
+	{22579200,  44100 * 64,  44100, 0x2000},
+	{24576000,  48000 * 32,  48000, 0x3000},
+	{24576000,  48000 * 64,  48000, 0x2000},
+	{45158400,  88200 * 32,  88200, 0x3000},
+	{45158400,  88200 * 64,  88200, 0x2000},
+	{49152000,  96000 * 32,  96000, 0x3000},
+	{49152000,  96000 * 64,  96000, 0x2000},
+	/* sysclk is 24.576Mhz or 22.5792Mhz */
+	{24576000,  8000 * 32,  8000,  0x7080},
+	{24576000,  8000 * 64,  8000,  0x6080},
+	{24576000,  16000 * 32,  16000,  0x5080},
+	{24576000,  16000 * 64,  16000,  0x4080},
+	{24576000,  24000 * 32,  24000,  0x5000},
+	{24576000,  24000 * 64,  24000,  0x4000},
+	{24576000,  32000 * 32,  32000,  0x3080},
+	{24576000,  32000 * 64,  32000,  0x2080},
+	{22579200,  11025 * 32,  11025,  0x7000},
+	{22579200,  11025 * 64,  11025,  0x6000},
+	{22579200,  22050 * 32,  22050,  0x5000},
+	{22579200,  22050 * 64,  22050,  0x4000},
+};
+
+static int get_coeff(int mclk, int rate, int timesofbclk)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].mclk == mclk && coeff_div[i].rate == rate &&
+			(coeff_div[i].bclk / coeff_div[i].rate) == timesofbclk)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static int rt5631_hifi_pcm_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
+	int timesofbclk = 32, coeff;
+	unsigned int iface = 0;
+
+	dev_dbg(component->dev, "enter %s\n", __func__);
+
+	rt5631->bclk_rate = snd_soc_params_to_bclk(params);
+	if (rt5631->bclk_rate < 0) {
+		dev_err(component->dev, "Fail to get BCLK rate\n");
+		return rt5631->bclk_rate;
+	}
+	rt5631->rx_rate = params_rate(params);
+
+	if (rt5631->master)
+		coeff = get_coeff(rt5631->sysclk, rt5631->rx_rate,
+			rt5631->bclk_rate / rt5631->rx_rate);
+	else
+		coeff = get_coeff(rt5631->sysclk, rt5631->rx_rate,
+					timesofbclk);
+	if (coeff < 0) {
+		dev_err(component->dev, "Fail to get coeff\n");
+		return coeff;
+	}
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		iface |= RT5631_SDP_I2S_DL_20;
+		break;
+	case 24:
+		iface |= RT5631_SDP_I2S_DL_24;
+		break;
+	case 8:
+		iface |= RT5631_SDP_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5631_SDP_CTRL,
+		RT5631_SDP_I2S_DL_MASK, iface);
+	snd_soc_component_write(component, RT5631_STEREO_AD_DA_CLK_CTRL,
+					coeff_div[coeff].reg_val);
+
+	return 0;
+}
+
+static int rt5631_hifi_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
+						unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
+	unsigned int iface = 0;
+
+	dev_dbg(component->dev, "enter %s\n", __func__);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5631->master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		iface |= RT5631_SDP_MODE_SEL_SLAVE;
+		rt5631->master = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= RT5631_SDP_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= RT5631_SDP_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface  |= RT5631_SDP_I2S_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= RT5631_SDP_I2S_BCLK_POL_CTRL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, RT5631_SDP_CTRL, iface);
+
+	return 0;
+}
+
+static int rt5631_hifi_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "enter %s, syclk=%d\n", __func__, freq);
+
+	if ((freq >= (256 * 8000)) && (freq <= (512 * 96000))) {
+		rt5631->sysclk = freq;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int rt5631_codec_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+		int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
+	int i, ret = -EINVAL;
+
+	dev_dbg(component->dev, "enter %s\n", __func__);
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		snd_soc_component_update_bits(component, RT5631_GLOBAL_CLK_CTRL,
+			RT5631_SYSCLK_SOUR_SEL_MASK,
+			RT5631_SYSCLK_SOUR_SEL_MCLK);
+
+		return 0;
+	}
+
+	if (rt5631->master) {
+		for (i = 0; i < ARRAY_SIZE(codec_master_pll_div); i++)
+			if (freq_in == codec_master_pll_div[i].pll_in &&
+			freq_out == codec_master_pll_div[i].pll_out) {
+				dev_info(component->dev,
+					"change PLL in master mode\n");
+				snd_soc_component_write(component, RT5631_PLL_CTRL,
+					codec_master_pll_div[i].reg_val);
+				schedule_timeout_uninterruptible(
+					msecs_to_jiffies(20));
+				snd_soc_component_update_bits(component,
+					RT5631_GLOBAL_CLK_CTRL,
+					RT5631_SYSCLK_SOUR_SEL_MASK |
+					RT5631_PLLCLK_SOUR_SEL_MASK,
+					RT5631_SYSCLK_SOUR_SEL_PLL |
+					RT5631_PLLCLK_SOUR_SEL_MCLK);
+				ret = 0;
+				break;
+			}
+	} else {
+		for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i++)
+			if (freq_in == codec_slave_pll_div[i].pll_in &&
+			freq_out == codec_slave_pll_div[i].pll_out) {
+				dev_info(component->dev,
+					"change PLL in slave mode\n");
+				snd_soc_component_write(component, RT5631_PLL_CTRL,
+					codec_slave_pll_div[i].reg_val);
+				schedule_timeout_uninterruptible(
+					msecs_to_jiffies(20));
+				snd_soc_component_update_bits(component,
+					RT5631_GLOBAL_CLK_CTRL,
+					RT5631_SYSCLK_SOUR_SEL_MASK |
+					RT5631_PLLCLK_SOUR_SEL_MASK,
+					RT5631_SYSCLK_SOUR_SEL_PLL |
+					RT5631_PLLCLK_SOUR_SEL_BCLK);
+				ret = 0;
+				break;
+			}
+	}
+
+	return ret;
+}
+
+static int rt5631_set_bias_level(struct snd_soc_component *component,
+			enum snd_soc_bias_level level)
+{
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD2,
+			RT5631_PWR_MICBIAS1_VOL | RT5631_PWR_MICBIAS2_VOL,
+			RT5631_PWR_MICBIAS1_VOL | RT5631_PWR_MICBIAS2_VOL);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
+				RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS,
+				RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS);
+			msleep(80);
+			snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
+				RT5631_PWR_FAST_VREF_CTRL,
+				RT5631_PWR_FAST_VREF_CTRL);
+			regcache_cache_only(rt5631->regmap, false);
+			regcache_sync(rt5631->regmap);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_write(component, RT5631_PWR_MANAG_ADD1, 0x0000);
+		snd_soc_component_write(component, RT5631_PWR_MANAG_ADD2, 0x0000);
+		snd_soc_component_write(component, RT5631_PWR_MANAG_ADD3, 0x0000);
+		snd_soc_component_write(component, RT5631_PWR_MANAG_ADD4, 0x0000);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5631_probe(struct snd_soc_component *component)
+{
+	struct rt5631_priv *rt5631 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	val = rt5631_read_index(component, RT5631_ADDA_MIXER_INTL_REG3);
+	if (val & 0x0002)
+		rt5631->codec_version = 1;
+	else
+		rt5631->codec_version = 0;
+
+	rt5631_reset(component);
+	snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
+		RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS,
+		RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS);
+	msleep(80);
+	snd_soc_component_update_bits(component, RT5631_PWR_MANAG_ADD3,
+		RT5631_PWR_FAST_VREF_CTRL, RT5631_PWR_FAST_VREF_CTRL);
+	/* enable HP zero cross */
+	snd_soc_component_write(component, RT5631_INT_ST_IRQ_CTRL_2, 0x0f18);
+	/* power off ClassD auto Recovery */
+	if (rt5631->codec_version)
+		snd_soc_component_update_bits(component, RT5631_INT_ST_IRQ_CTRL_2,
+					0x2000, 0x2000);
+	else
+		snd_soc_component_update_bits(component, RT5631_INT_ST_IRQ_CTRL_2,
+					0x2000, 0);
+	/* DMIC */
+	if (rt5631->dmic_used_flag) {
+		snd_soc_component_update_bits(component, RT5631_GPIO_CTRL,
+			RT5631_GPIO_PIN_FUN_SEL_MASK |
+			RT5631_GPIO_DMIC_FUN_SEL_MASK,
+			RT5631_GPIO_PIN_FUN_SEL_GPIO_DIMC |
+			RT5631_GPIO_DMIC_FUN_SEL_DIMC);
+		snd_soc_component_update_bits(component, RT5631_DIG_MIC_CTRL,
+			RT5631_DMIC_L_CH_LATCH_MASK |
+			RT5631_DMIC_R_CH_LATCH_MASK,
+			RT5631_DMIC_L_CH_LATCH_FALLING |
+			RT5631_DMIC_R_CH_LATCH_RISING);
+	}
+
+	snd_soc_component_init_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+
+#define RT5631_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define RT5631_FORMAT	(SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | \
+			SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5631_ops = {
+	.hw_params = rt5631_hifi_pcm_params,
+	.set_fmt = rt5631_hifi_codec_set_dai_fmt,
+	.set_sysclk = rt5631_hifi_codec_set_dai_sysclk,
+	.set_pll = rt5631_codec_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver rt5631_dai[] = {
+	{
+		.name = "rt5631-hifi",
+		.id = 1,
+		.playback = {
+			.stream_name = "HIFI Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5631_STEREO_RATES,
+			.formats = RT5631_FORMAT,
+		},
+		.capture = {
+			.stream_name = "HIFI Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5631_STEREO_RATES,
+			.formats = RT5631_FORMAT,
+		},
+		.ops = &rt5631_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5631 = {
+	.probe			= rt5631_probe,
+	.set_bias_level		= rt5631_set_bias_level,
+	.controls		= rt5631_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5631_snd_controls),
+	.dapm_widgets		= rt5631_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5631_dapm_widgets),
+	.dapm_routes		= rt5631_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5631_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct i2c_device_id rt5631_i2c_id[] = {
+	{ "rt5631", 0 },
+	{ "alc5631", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt5631_i2c_dt_ids[] = {
+	{ .compatible = "realtek,rt5631"},
+	{ .compatible = "realtek,alc5631"},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, rt5631_i2c_dt_ids);
+#endif
+
+static const struct regmap_config rt5631_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.readable_reg = rt5631_readable_register,
+	.volatile_reg = rt5631_volatile_register,
+	.max_register = RT5631_VENDOR_ID2,
+	.reg_defaults = rt5631_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5631_reg),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int rt5631_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5631_priv *rt5631;
+	int ret;
+
+	rt5631 = devm_kzalloc(&i2c->dev, sizeof(struct rt5631_priv),
+			      GFP_KERNEL);
+	if (NULL == rt5631)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt5631);
+
+	rt5631->regmap = devm_regmap_init_i2c(i2c, &rt5631_regmap_config);
+	if (IS_ERR(rt5631->regmap))
+		return PTR_ERR(rt5631->regmap);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_rt5631,
+			rt5631_dai, ARRAY_SIZE(rt5631_dai));
+	return ret;
+}
+
+static int rt5631_i2c_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static struct i2c_driver rt5631_i2c_driver = {
+	.driver = {
+		.name = "rt5631",
+		.of_match_table = of_match_ptr(rt5631_i2c_dt_ids),
+	},
+	.probe = rt5631_i2c_probe,
+	.remove   = rt5631_i2c_remove,
+	.id_table = rt5631_i2c_id,
+};
+
+module_i2c_driver(rt5631_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5631 driver");
+MODULE_AUTHOR("flove <flove@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt5631.h b/sound/soc/codecs/rt5631.h
new file mode 100644
index 0000000..8a6b99a
--- /dev/null
+++ b/sound/soc/codecs/rt5631.h
@@ -0,0 +1,702 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __RTCODEC5631_H__
+#define __RTCODEC5631_H__
+
+
+#define RT5631_RESET				0x00
+#define RT5631_SPK_OUT_VOL			0x02
+#define RT5631_HP_OUT_VOL			0x04
+#define RT5631_MONO_AXO_1_2_VOL		0x06
+#define RT5631_AUX_IN_VOL			0x0A
+#define RT5631_STEREO_DAC_VOL_1		0x0C
+#define RT5631_MIC_CTRL_1			0x0E
+#define RT5631_STEREO_DAC_VOL_2		0x10
+#define RT5631_ADC_CTRL_1			0x12
+#define RT5631_ADC_REC_MIXER			0x14
+#define RT5631_ADC_CTRL_2			0x16
+#define RT5631_VDAC_DIG_VOL			0x18
+#define RT5631_OUTMIXER_L_CTRL			0x1A
+#define RT5631_OUTMIXER_R_CTRL			0x1C
+#define RT5631_AXO1MIXER_CTRL			0x1E
+#define RT5631_AXO2MIXER_CTRL			0x20
+#define RT5631_MIC_CTRL_2			0x22
+#define RT5631_DIG_MIC_CTRL			0x24
+#define RT5631_MONO_INPUT_VOL			0x26
+#define RT5631_SPK_MIXER_CTRL			0x28
+#define RT5631_SPK_MONO_OUT_CTRL		0x2A
+#define RT5631_SPK_MONO_HP_OUT_CTRL		0x2C
+#define RT5631_SDP_CTRL				0x34
+#define RT5631_MONO_SDP_CTRL			0x36
+#define RT5631_STEREO_AD_DA_CLK_CTRL		0x38
+#define RT5631_PWR_MANAG_ADD1		0x3A
+#define RT5631_PWR_MANAG_ADD2		0x3B
+#define RT5631_PWR_MANAG_ADD3		0x3C
+#define RT5631_PWR_MANAG_ADD4		0x3E
+#define RT5631_GEN_PUR_CTRL_REG		0x40
+#define RT5631_GLOBAL_CLK_CTRL			0x42
+#define RT5631_PLL_CTRL				0x44
+#define RT5631_INT_ST_IRQ_CTRL_1		0x48
+#define RT5631_INT_ST_IRQ_CTRL_2		0x4A
+#define RT5631_GPIO_CTRL			0x4C
+#define RT5631_MISC_CTRL			0x52
+#define RT5631_DEPOP_FUN_CTRL_1		0x54
+#define RT5631_DEPOP_FUN_CTRL_2		0x56
+#define RT5631_JACK_DET_CTRL			0x5A
+#define RT5631_SOFT_VOL_CTRL			0x5C
+#define RT5631_ALC_CTRL_1			0x64
+#define RT5631_ALC_CTRL_2			0x65
+#define RT5631_ALC_CTRL_3			0x66
+#define RT5631_PSEUDO_SPATL_CTRL		0x68
+#define RT5631_INDEX_ADD			0x6A
+#define RT5631_INDEX_DATA			0x6C
+#define RT5631_EQ_CTRL				0x6E
+#define RT5631_VENDOR_ID			0x7A
+#define RT5631_VENDOR_ID1			0x7C
+#define RT5631_VENDOR_ID2			0x7E
+
+/* Index of Codec Private Register definition */
+#define RT5631_EQ_BW_LOP			0x00
+#define RT5631_EQ_GAIN_LOP			0x01
+#define RT5631_EQ_FC_BP1			0x02
+#define RT5631_EQ_BW_BP1			0x03
+#define RT5631_EQ_GAIN_BP1			0x04
+#define RT5631_EQ_FC_BP2			0x05
+#define RT5631_EQ_BW_BP2			0x06
+#define RT5631_EQ_GAIN_BP2			0x07
+#define RT5631_EQ_FC_BP3			0x08
+#define RT5631_EQ_BW_BP3			0x09
+#define RT5631_EQ_GAIN_BP3			0x0a
+#define RT5631_EQ_BW_HIP			0x0b
+#define RT5631_EQ_GAIN_HIP			0x0c
+#define RT5631_EQ_HPF_A1			0x0d
+#define RT5631_EQ_HPF_A2			0x0e
+#define RT5631_EQ_HPF_GAIN			0x0f
+#define RT5631_EQ_PRE_VOL_CTRL			0x11
+#define RT5631_EQ_POST_VOL_CTRL		0x12
+#define RT5631_TEST_MODE_CTRL			0x39
+#define RT5631_CP_INTL_REG2			0x45
+#define RT5631_ADDA_MIXER_INTL_REG3		0x52
+#define RT5631_SPK_INTL_CTRL			0x56
+
+
+/* global definition */
+#define RT5631_L_MUTE					(0x1 << 15)
+#define RT5631_L_MUTE_SHIFT				15
+#define RT5631_L_EN					(0x1 << 14)
+#define RT5631_L_EN_SHIFT				14
+#define RT5631_R_MUTE					(0x1 << 7)
+#define RT5631_R_MUTE_SHIFT				7
+#define RT5631_R_EN					(0x1 << 6)
+#define RT5631_R_EN_SHIFT				6
+#define RT5631_VOL_MASK				0x1f
+#define RT5631_L_VOL_SHIFT				8
+#define RT5631_R_VOL_SHIFT				0
+
+/* Speaker Output Control(0x02) */
+#define RT5631_SPK_L_VOL_SEL_MASK			(0x1 << 14)
+#define RT5631_SPK_L_VOL_SEL_VMID			(0x0 << 14)
+#define RT5631_SPK_L_VOL_SEL_SPKMIX_L			(0x1 << 14)
+#define RT5631_SPK_R_VOL_SEL_MASK			(0x1 << 6)
+#define RT5631_SPK_R_VOL_SEL_VMID			(0x0 << 6)
+#define RT5631_SPK_R_VOL_SEL_SPKMIX_R			(0x1 << 6)
+
+/* Headphone Output Control(0x04) */
+#define RT5631_HP_L_VOL_SEL_MASK			(0x1 << 14)
+#define RT5631_HP_L_VOL_SEL_VMID			(0x0 << 14)
+#define RT5631_HP_L_VOL_SEL_OUTMIX_L			(0x1 << 14)
+#define RT5631_HP_R_VOL_SEL_MASK			(0x1 << 6)
+#define RT5631_HP_R_VOL_SEL_VMID			(0x0 << 6)
+#define RT5631_HP_R_VOL_SEL_OUTMIX_R			(0x1 << 6)
+
+/* Output Control for AUXOUT/MONO(0x06) */
+#define RT5631_AUXOUT_1_VOL_SEL_MASK			(0x1 << 14)
+#define RT5631_AUXOUT_1_VOL_SEL_VMID			(0x0 << 14)
+#define RT5631_AUXOUT_1_VOL_SEL_OUTMIX_L		(0x1 << 14)
+#define RT5631_MUTE_MONO				(0x1 << 13)
+#define RT5631_MUTE_MONO_SHIFT			13
+#define RT5631_AUXOUT_2_VOL_SEL_MASK			(0x1 << 6)
+#define RT5631_AUXOUT_2_VOL_SEL_VMID			(0x0 << 6)
+#define RT5631_AUXOUT_2_VOL_SEL_OUTMIX_R		(0x1 << 6)
+
+/* Microphone Input Control 1(0x0E) */
+#define RT5631_MIC1_DIFF_INPUT_CTRL			(0x1 << 15)
+#define RT5631_MIC1_DIFF_INPUT_SHIFT			15
+#define RT5631_MIC2_DIFF_INPUT_CTRL			(0x1 << 7)
+#define RT5631_MIC2_DIFF_INPUT_SHIFT			7
+
+/* Stereo DAC Digital Volume2(0x10) */
+#define RT5631_DAC_VOL_MASK				0xff
+
+/* ADC Recording Mixer Control(0x14) */
+#define RT5631_M_OUTMIXER_L_TO_RECMIXER_L		(0x1 << 15)
+#define RT5631_M_OUTMIXL_RECMIXL_BIT			15
+#define RT5631_M_MIC1_TO_RECMIXER_L			(0x1 << 14)
+#define RT5631_M_MIC1_RECMIXL_BIT			14
+#define RT5631_M_AXIL_TO_RECMIXER_L			(0x1 << 13)
+#define RT5631_M_AXIL_RECMIXL_BIT			13
+#define RT5631_M_MONO_IN_TO_RECMIXER_L		(0x1 << 12)
+#define RT5631_M_MONO_IN_RECMIXL_BIT			12
+#define RT5631_M_OUTMIXER_R_TO_RECMIXER_R		(0x1 << 7)
+#define RT5631_M_OUTMIXR_RECMIXR_BIT			7
+#define RT5631_M_MIC2_TO_RECMIXER_R			(0x1 << 6)
+#define RT5631_M_MIC2_RECMIXR_BIT			6
+#define RT5631_M_AXIR_TO_RECMIXER_R			(0x1 << 5)
+#define RT5631_M_AXIR_RECMIXR_BIT			5
+#define RT5631_M_MONO_IN_TO_RECMIXER_R		(0x1 << 4)
+#define RT5631_M_MONO_IN_RECMIXR_BIT			4
+
+/* Left Output Mixer Control(0x1A) */
+#define RT5631_M_RECMIXER_L_TO_OUTMIXER_L		(0x1 << 15)
+#define RT5631_M_RECMIXL_OUTMIXL_BIT			15
+#define RT5631_M_RECMIXER_R_TO_OUTMIXER_L		(0x1 << 14)
+#define RT5631_M_RECMIXR_OUTMIXL_BIT			14
+#define RT5631_M_DAC_L_TO_OUTMIXER_L			(0x1 << 13)
+#define RT5631_M_DACL_OUTMIXL_BIT			13
+#define RT5631_M_MIC1_TO_OUTMIXER_L			(0x1 << 12)
+#define RT5631_M_MIC1_OUTMIXL_BIT			12
+#define RT5631_M_MIC2_TO_OUTMIXER_L			(0x1 << 11)
+#define RT5631_M_MIC2_OUTMIXL_BIT			11
+#define RT5631_M_MONO_IN_P_TO_OUTMIXER_L		(0x1 << 10)
+#define RT5631_M_MONO_INP_OUTMIXL_BIT		10
+#define RT5631_M_AXIL_TO_OUTMIXER_L			(0x1 << 9)
+#define RT5631_M_AXIL_OUTMIXL_BIT			9
+#define RT5631_M_AXIR_TO_OUTMIXER_L			(0x1 << 8)
+#define RT5631_M_AXIR_OUTMIXL_BIT			8
+#define RT5631_M_VDAC_TO_OUTMIXER_L			(0x1 << 7)
+#define RT5631_M_VDAC_OUTMIXL_BIT			7
+
+/* Right Output Mixer Control(0x1C) */
+#define RT5631_M_RECMIXER_L_TO_OUTMIXER_R		(0x1 << 15)
+#define RT5631_M_RECMIXL_OUTMIXR_BIT			15
+#define RT5631_M_RECMIXER_R_TO_OUTMIXER_R		(0x1 << 14)
+#define RT5631_M_RECMIXR_OUTMIXR_BIT			14
+#define RT5631_M_DAC_R_TO_OUTMIXER_R			(0x1 << 13)
+#define RT5631_M_DACR_OUTMIXR_BIT			13
+#define RT5631_M_MIC1_TO_OUTMIXER_R			(0x1 << 12)
+#define RT5631_M_MIC1_OUTMIXR_BIT			12
+#define RT5631_M_MIC2_TO_OUTMIXER_R			(0x1 << 11)
+#define RT5631_M_MIC2_OUTMIXR_BIT			11
+#define RT5631_M_MONO_IN_N_TO_OUTMIXER_R		(0x1 << 10)
+#define RT5631_M_MONO_INN_OUTMIXR_BIT		10
+#define RT5631_M_AXIL_TO_OUTMIXER_R			(0x1 << 9)
+#define RT5631_M_AXIL_OUTMIXR_BIT			9
+#define RT5631_M_AXIR_TO_OUTMIXER_R			(0x1 << 8)
+#define RT5631_M_AXIR_OUTMIXR_BIT			8
+#define RT5631_M_VDAC_TO_OUTMIXER_R			(0x1 << 7)
+#define RT5631_M_VDAC_OUTMIXR_BIT			7
+
+/* Lout Mixer Control(0x1E) */
+#define RT5631_M_MIC1_TO_AXO1MIXER			(0x1 << 15)
+#define RT5631_M_MIC1_AXO1MIX_BIT			15
+#define RT5631_M_MIC2_TO_AXO1MIXER			(0x1 << 11)
+#define RT5631_M_MIC2_AXO1MIX_BIT			11
+#define RT5631_M_OUTMIXER_L_TO_AXO1MIXER		(0x1 << 7)
+#define RT5631_M_OUTMIXL_AXO1MIX_BIT			7
+#define RT5631_M_OUTMIXER_R_TO_AXO1MIXER		(0x1 << 6)
+#define RT5631_M_OUTMIXR_AXO1MIX_BIT			6
+
+/* Rout Mixer Control(0x20) */
+#define RT5631_M_MIC1_TO_AXO2MIXER			(0x1 << 15)
+#define RT5631_M_MIC1_AXO2MIX_BIT			15
+#define RT5631_M_MIC2_TO_AXO2MIXER			(0x1 << 11)
+#define RT5631_M_MIC2_AXO2MIX_BIT			11
+#define RT5631_M_OUTMIXER_L_TO_AXO2MIXER		(0x1 << 7)
+#define RT5631_M_OUTMIXL_AXO2MIX_BIT			7
+#define RT5631_M_OUTMIXER_R_TO_AXO2MIXER		(0x1 << 6)
+#define RT5631_M_OUTMIXR_AXO2MIX_BIT			6
+
+/* Micphone Input Control 2(0x22) */
+#define RT5631_MIC_BIAS_90_PRECNET_AVDD 1
+#define RT5631_MIC_BIAS_75_PRECNET_AVDD 2
+
+#define RT5631_MIC1_BOOST_CTRL_MASK			(0xf << 12)
+#define RT5631_MIC1_BOOST_CTRL_BYPASS		(0x0 << 12)
+#define RT5631_MIC1_BOOST_CTRL_20DB			(0x1 << 12)
+#define RT5631_MIC1_BOOST_CTRL_24DB			(0x2 << 12)
+#define RT5631_MIC1_BOOST_CTRL_30DB			(0x3 << 12)
+#define RT5631_MIC1_BOOST_CTRL_35DB			(0x4 << 12)
+#define RT5631_MIC1_BOOST_CTRL_40DB			(0x5 << 12)
+#define RT5631_MIC1_BOOST_CTRL_34DB			(0x6 << 12)
+#define RT5631_MIC1_BOOST_CTRL_50DB			(0x7 << 12)
+#define RT5631_MIC1_BOOST_CTRL_52DB			(0x8 << 12)
+#define RT5631_MIC1_BOOST_SHIFT			12
+
+#define RT5631_MIC2_BOOST_CTRL_MASK			(0xf << 8)
+#define RT5631_MIC2_BOOST_CTRL_BYPASS		(0x0 << 8)
+#define RT5631_MIC2_BOOST_CTRL_20DB			(0x1 << 8)
+#define RT5631_MIC2_BOOST_CTRL_24DB			(0x2 << 8)
+#define RT5631_MIC2_BOOST_CTRL_30DB			(0x3 << 8)
+#define RT5631_MIC2_BOOST_CTRL_35DB			(0x4 << 8)
+#define RT5631_MIC2_BOOST_CTRL_40DB			(0x5 << 8)
+#define RT5631_MIC2_BOOST_CTRL_34DB			(0x6 << 8)
+#define RT5631_MIC2_BOOST_CTRL_50DB			(0x7 << 8)
+#define RT5631_MIC2_BOOST_CTRL_52DB			(0x8 << 8)
+#define RT5631_MIC2_BOOST_SHIFT			8
+
+#define RT5631_MICBIAS1_VOLT_CTRL_MASK		(0x1 << 7)
+#define RT5631_MICBIAS1_VOLT_CTRL_90P			(0x0 << 7)
+#define RT5631_MICBIAS1_VOLT_CTRL_75P			(0x1 << 7)
+
+#define RT5631_MICBIAS1_S_C_DET_MASK			(0x1 << 6)
+#define RT5631_MICBIAS1_S_C_DET_DIS			(0x0 << 6)
+#define RT5631_MICBIAS1_S_C_DET_ENA			(0x1 << 6)
+
+#define RT5631_MICBIAS1_SHORT_CURR_DET_MASK		(0x3 << 4)
+#define RT5631_MICBIAS1_SHORT_CURR_DET_600UA	(0x0 << 4)
+#define RT5631_MICBIAS1_SHORT_CURR_DET_1500UA	(0x1 << 4)
+#define RT5631_MICBIAS1_SHORT_CURR_DET_2000UA	(0x2 << 4)
+
+#define RT5631_MICBIAS2_VOLT_CTRL_MASK		(0x1 << 3)
+#define RT5631_MICBIAS2_VOLT_CTRL_90P			(0x0 << 3)
+#define RT5631_MICBIAS2_VOLT_CTRL_75P			(0x1 << 3)
+
+#define RT5631_MICBIAS2_S_C_DET_MASK			(0x1 << 2)
+#define RT5631_MICBIAS2_S_C_DET_DIS			(0x0 << 2)
+#define RT5631_MICBIAS2_S_C_DET_ENA			(0x1 << 2)
+
+#define RT5631_MICBIAS2_SHORT_CURR_DET_MASK		(0x3)
+#define RT5631_MICBIAS2_SHORT_CURR_DET_600UA	(0x0)
+#define RT5631_MICBIAS2_SHORT_CURR_DET_1500UA	(0x1)
+#define RT5631_MICBIAS2_SHORT_CURR_DET_2000UA	(0x2)
+
+
+/* Digital Microphone Control(0x24) */
+#define RT5631_DMIC_ENA_MASK				(0x1 << 15)
+#define RT5631_DMIC_ENA_SHIFT				15
+/* DMIC_ENA: DMIC to ADC Digital filter */
+#define RT5631_DMIC_ENA				(0x1 << 15)
+/* DMIC_DIS: ADC mixer to ADC Digital filter */
+#define RT5631_DMIC_DIS					(0x0 << 15)
+#define RT5631_DMIC_L_CH_MUTE				(0x1 << 13)
+#define RT5631_DMIC_L_CH_MUTE_SHIFT			13
+#define RT5631_DMIC_R_CH_MUTE				(0x1 << 12)
+#define RT5631_DMIC_R_CH_MUTE_SHIFT			12
+#define RT5631_DMIC_L_CH_LATCH_MASK			(0x1 << 9)
+#define RT5631_DMIC_L_CH_LATCH_RISING			(0x1 << 9)
+#define RT5631_DMIC_L_CH_LATCH_FALLING		(0x0 << 9)
+#define RT5631_DMIC_R_CH_LATCH_MASK			(0x1 << 8)
+#define RT5631_DMIC_R_CH_LATCH_RISING			(0x1 << 8)
+#define RT5631_DMIC_R_CH_LATCH_FALLING		(0x0 << 8)
+#define RT5631_DMIC_CLK_CTRL_MASK			(0x3 << 4)
+#define RT5631_DMIC_CLK_CTRL_TO_128FS			(0x0 << 4)
+#define RT5631_DMIC_CLK_CTRL_TO_64FS			(0x1 << 4)
+#define RT5631_DMIC_CLK_CTRL_TO_32FS			(0x2 << 4)
+
+/* Microphone Input Volume(0x26) */
+#define RT5631_MONO_DIFF_INPUT_SHIFT			15
+
+/* Speaker Mixer Control(0x28) */
+#define RT5631_M_RECMIXER_L_TO_SPKMIXER_L		(0x1 << 15)
+#define RT5631_M_RECMIXL_SPKMIXL_BIT			15
+#define RT5631_M_MIC1_P_TO_SPKMIXER_L		(0x1 << 14)
+#define RT5631_M_MIC1P_SPKMIXL_BIT			14
+#define RT5631_M_DAC_L_TO_SPKMIXER_L			(0x1 << 13)
+#define RT5631_M_DACL_SPKMIXL_BIT			13
+#define RT5631_M_OUTMIXER_L_TO_SPKMIXER_L		(0x1 << 12)
+#define RT5631_M_OUTMIXL_SPKMIXL_BIT			12
+
+#define RT5631_M_RECMIXER_R_TO_SPKMIXER_R		(0x1 << 7)
+#define RT5631_M_RECMIXR_SPKMIXR_BIT			7
+#define RT5631_M_MIC2_P_TO_SPKMIXER_R		(0x1 << 6)
+#define RT5631_M_MIC2P_SPKMIXR_BIT			6
+#define RT5631_M_DAC_R_TO_SPKMIXER_R			(0x1 << 5)
+#define RT5631_M_DACR_SPKMIXR_BIT			5
+#define RT5631_M_OUTMIXER_R_TO_SPKMIXER_R		(0x1 << 4)
+#define RT5631_M_OUTMIXR_SPKMIXR_BIT			4
+
+/* Speaker/Mono Output Control(0x2A) */
+#define RT5631_M_SPKVOL_L_TO_SPOL_MIXER		(0x1 << 15)
+#define RT5631_M_SPKVOLL_SPOLMIX_BIT			15
+#define RT5631_M_SPKVOL_R_TO_SPOL_MIXER		(0x1 << 14)
+#define RT5631_M_SPKVOLR_SPOLMIX_BIT			14
+#define RT5631_M_SPKVOL_L_TO_SPOR_MIXER		(0x1 << 13)
+#define RT5631_M_SPKVOLL_SPORMIX_BIT			13
+#define RT5631_M_SPKVOL_R_TO_SPOR_MIXER		(0x1 << 12)
+#define RT5631_M_SPKVOLR_SPORMIX_BIT			12
+#define RT5631_M_OUTVOL_L_TO_MONOMIXER		(0x1 << 11)
+#define RT5631_M_OUTVOLL_MONOMIX_BIT			11
+#define RT5631_M_OUTVOL_R_TO_MONOMIXER		(0x1 << 10)
+#define RT5631_M_OUTVOLR_MONOMIX_BIT			10
+
+/* Speaker/Mono/HP Output Control(0x2C) */
+#define RT5631_SPK_L_MUX_SEL_MASK			(0x3 << 14)
+#define RT5631_SPK_L_MUX_SEL_SPKMIXER_L		(0x0 << 14)
+#define RT5631_SPK_L_MUX_SEL_MONO_IN			(0x1 << 14)
+#define RT5631_SPK_L_MUX_SEL_DAC_L			(0x3 << 14)
+#define RT5631_SPK_L_MUX_SEL_SHIFT			14
+
+#define RT5631_SPK_R_MUX_SEL_MASK			(0x3 << 10)
+#define RT5631_SPK_R_MUX_SEL_SPKMIXER_R		(0x0 << 10)
+#define RT5631_SPK_R_MUX_SEL_MONO_IN			(0x1 << 10)
+#define RT5631_SPK_R_MUX_SEL_DAC_R			(0x3 << 10)
+#define RT5631_SPK_R_MUX_SEL_SHIFT			10
+
+#define RT5631_MONO_MUX_SEL_MASK			(0x3 << 6)
+#define RT5631_MONO_MUX_SEL_MONOMIXER		(0x0 << 6)
+#define RT5631_MONO_MUX_SEL_MONO_IN			(0x1 << 6)
+#define RT5631_MONO_MUX_SEL_SHIFT			6
+
+#define RT5631_HP_L_MUX_SEL_MASK			(0x1 << 3)
+#define RT5631_HP_L_MUX_SEL_HPVOL_L			(0x0 << 3)
+#define RT5631_HP_L_MUX_SEL_DAC_L			(0x1 << 3)
+#define RT5631_HP_L_MUX_SEL_SHIFT			3
+
+#define RT5631_HP_R_MUX_SEL_MASK			(0x1 << 2)
+#define RT5631_HP_R_MUX_SEL_HPVOL_R			(0x0 << 2)
+#define RT5631_HP_R_MUX_SEL_DAC_R			(0x1 << 2)
+#define RT5631_HP_R_MUX_SEL_SHIFT			2
+
+/* Stereo I2S Serial Data Port Control(0x34) */
+#define RT5631_SDP_MODE_SEL_MASK			(0x1 << 15)
+#define RT5631_SDP_MODE_SEL_MASTER			(0x0 << 15)
+#define RT5631_SDP_MODE_SEL_SLAVE			(0x1 << 15)
+
+#define RT5631_SDP_ADC_CPS_SEL_MASK			(0x3 << 10)
+#define RT5631_SDP_ADC_CPS_SEL_OFF			(0x0 << 10)
+#define RT5631_SDP_ADC_CPS_SEL_U_LAW			(0x1 << 10)
+#define RT5631_SDP_ADC_CPS_SEL_A_LAW			(0x2 << 10)
+
+#define RT5631_SDP_DAC_CPS_SEL_MASK			(0x3 << 8)
+#define RT5631_SDP_DAC_CPS_SEL_OFF			(0x0 << 8)
+#define RT5631_SDP_DAC_CPS_SEL_U_LAW			(0x1 << 8)
+#define RT5631_SDP_DAC_CPS_SEL_A_LAW			(0x2 << 8)
+/* 0:Normal 1:Invert */
+#define RT5631_SDP_I2S_BCLK_POL_CTRL			(0x1 << 7)
+/* 0:Normal 1:Invert */
+#define RT5631_SDP_DAC_R_INV				(0x1 << 6)
+/* 0:ADC data appear at left phase of LRCK
+ * 1:ADC data appear at right phase of LRCK
+ */
+#define RT5631_SDP_ADC_DATA_L_R_SWAP			(0x1 << 5)
+/* 0:DAC data appear at left phase of LRCK
+ * 1:DAC data appear at right phase of LRCK
+ */
+#define RT5631_SDP_DAC_DATA_L_R_SWAP			(0x1 << 4)
+
+/* Data Length Slection */
+#define RT5631_SDP_I2S_DL_MASK				(0x3 << 2)
+#define RT5631_SDP_I2S_DL_16				(0x0 << 2)
+#define RT5631_SDP_I2S_DL_20				(0x1 << 2)
+#define RT5631_SDP_I2S_DL_24				(0x2 << 2)
+#define RT5631_SDP_I2S_DL_8				(0x3 << 2)
+
+/* PCM Data Format Selection */
+#define RT5631_SDP_I2S_DF_MASK				(0x3)
+#define RT5631_SDP_I2S_DF_I2S				(0x0)
+#define RT5631_SDP_I2S_DF_LEFT				(0x1)
+#define RT5631_SDP_I2S_DF_PCM_A			(0x2)
+#define RT5631_SDP_I2S_DF_PCM_B			(0x3)
+
+/* Stereo AD/DA Clock Control(0x38h) */
+#define RT5631_I2S_PRE_DIV_MASK			(0x7 << 13)
+#define RT5631_I2S_PRE_DIV_1				(0x0 << 13)
+#define RT5631_I2S_PRE_DIV_2				(0x1 << 13)
+#define RT5631_I2S_PRE_DIV_4				(0x2 << 13)
+#define RT5631_I2S_PRE_DIV_8				(0x3 << 13)
+#define RT5631_I2S_PRE_DIV_16				(0x4 << 13)
+#define RT5631_I2S_PRE_DIV_32				(0x5 << 13)
+/* CLOCK RELATIVE OF BCLK AND LCRK */
+#define RT5631_I2S_LRCK_SEL_N_BCLK_MASK		(0x1 << 12)
+#define RT5631_I2S_LRCK_SEL_64_BCLK			(0x0 << 12) /* 64FS */
+#define RT5631_I2S_LRCK_SEL_32_BCLK			(0x1 << 12) /* 32FS */
+
+#define RT5631_DAC_OSR_SEL_MASK			(0x3 << 10)
+#define RT5631_DAC_OSR_SEL_128FS			(0x3 << 10)
+#define RT5631_DAC_OSR_SEL_64FS			(0x3 << 10)
+#define RT5631_DAC_OSR_SEL_32FS			(0x3 << 10)
+#define RT5631_DAC_OSR_SEL_16FS			(0x3 << 10)
+
+#define RT5631_ADC_OSR_SEL_MASK			(0x3 << 8)
+#define RT5631_ADC_OSR_SEL_128FS			(0x3 << 8)
+#define RT5631_ADC_OSR_SEL_64FS			(0x3 << 8)
+#define RT5631_ADC_OSR_SEL_32FS			(0x3 << 8)
+#define RT5631_ADC_OSR_SEL_16FS			(0x3 << 8)
+
+#define RT5631_ADDA_FILTER_CLK_SEL_256FS		(0 << 7) /* 256FS */
+#define RT5631_ADDA_FILTER_CLK_SEL_384FS		(1 << 7) /* 384FS */
+
+/* Power managment addition 1 (0x3A) */
+#define RT5631_PWR_MAIN_I2S_EN			(0x1 << 15)
+#define RT5631_PWR_MAIN_I2S_BIT			15
+#define RT5631_PWR_CLASS_D				(0x1 << 12)
+#define RT5631_PWR_CLASS_D_BIT			12
+#define RT5631_PWR_ADC_L_CLK				(0x1 << 11)
+#define RT5631_PWR_ADC_L_CLK_BIT			11
+#define RT5631_PWR_ADC_R_CLK				(0x1 << 10)
+#define RT5631_PWR_ADC_R_CLK_BIT			10
+#define RT5631_PWR_DAC_L_CLK				(0x1 << 9)
+#define RT5631_PWR_DAC_L_CLK_BIT			9
+#define RT5631_PWR_DAC_R_CLK				(0x1 << 8)
+#define RT5631_PWR_DAC_R_CLK_BIT			8
+#define RT5631_PWR_DAC_REF				(0x1 << 7)
+#define RT5631_PWR_DAC_REF_BIT			7
+#define RT5631_PWR_DAC_L_TO_MIXER			(0x1 << 6)
+#define RT5631_PWR_DAC_L_TO_MIXER_BIT		6
+#define RT5631_PWR_DAC_R_TO_MIXER			(0x1 << 5)
+#define RT5631_PWR_DAC_R_TO_MIXER_BIT		5
+
+/* Power managment addition 2 (0x3B) */
+#define RT5631_PWR_OUTMIXER_L				(0x1 << 15)
+#define RT5631_PWR_OUTMIXER_L_BIT			15
+#define RT5631_PWR_OUTMIXER_R				(0x1 << 14)
+#define RT5631_PWR_OUTMIXER_R_BIT			14
+#define RT5631_PWR_SPKMIXER_L				(0x1 << 13)
+#define RT5631_PWR_SPKMIXER_L_BIT			13
+#define RT5631_PWR_SPKMIXER_R				(0x1 << 12)
+#define RT5631_PWR_SPKMIXER_R_BIT			12
+#define RT5631_PWR_RECMIXER_L				(0x1 << 11)
+#define RT5631_PWR_RECMIXER_L_BIT			11
+#define RT5631_PWR_RECMIXER_R				(0x1 << 10)
+#define RT5631_PWR_RECMIXER_R_BIT			10
+#define RT5631_PWR_MIC1_BOOT_GAIN			(0x1 << 5)
+#define RT5631_PWR_MIC1_BOOT_GAIN_BIT		5
+#define RT5631_PWR_MIC2_BOOT_GAIN			(0x1 << 4)
+#define RT5631_PWR_MIC2_BOOT_GAIN_BIT		4
+#define RT5631_PWR_MICBIAS1_VOL			(0x1 << 3)
+#define RT5631_PWR_MICBIAS1_VOL_BIT			3
+#define RT5631_PWR_MICBIAS2_VOL			(0x1 << 2)
+#define RT5631_PWR_MICBIAS2_VOL_BIT			2
+#define RT5631_PWR_PLL1				(0x1 << 1)
+#define RT5631_PWR_PLL1_BIT				1
+#define RT5631_PWR_PLL2				(0x1 << 0)
+#define RT5631_PWR_PLL2_BIT				0
+
+/* Power managment addition 3(0x3C) */
+#define RT5631_PWR_VREF				(0x1 << 15)
+#define RT5631_PWR_VREF_BIT				15
+#define RT5631_PWR_FAST_VREF_CTRL			(0x1 << 14)
+#define RT5631_PWR_FAST_VREF_CTRL_BIT			14
+#define RT5631_PWR_MAIN_BIAS				(0x1 << 13)
+#define RT5631_PWR_MAIN_BIAS_BIT			13
+#define RT5631_PWR_AXO1MIXER				(0x1 << 11)
+#define RT5631_PWR_AXO1MIXER_BIT			11
+#define RT5631_PWR_AXO2MIXER				(0x1 << 10)
+#define RT5631_PWR_AXO2MIXER_BIT			10
+#define RT5631_PWR_MONOMIXER				(0x1 << 9)
+#define RT5631_PWR_MONOMIXER_BIT			9
+#define RT5631_PWR_MONO_DEPOP_DIS			(0x1 << 8)
+#define RT5631_PWR_MONO_DEPOP_DIS_BIT		8
+#define RT5631_PWR_MONO_AMP_EN			(0x1 << 7)
+#define RT5631_PWR_MONO_AMP_EN_BIT			7
+#define RT5631_PWR_CHARGE_PUMP			(0x1 << 4)
+#define RT5631_PWR_CHARGE_PUMP_BIT			4
+#define RT5631_PWR_HP_L_AMP				(0x1 << 3)
+#define RT5631_PWR_HP_L_AMP_BIT			3
+#define RT5631_PWR_HP_R_AMP				(0x1 << 2)
+#define RT5631_PWR_HP_R_AMP_BIT			2
+#define RT5631_PWR_HP_DEPOP_DIS			(0x1 << 1)
+#define RT5631_PWR_HP_DEPOP_DIS_BIT			1
+#define RT5631_PWR_HP_AMP_DRIVING			(0x1 << 0)
+#define RT5631_PWR_HP_AMP_DRIVING_BIT		0
+
+/* Power managment addition 4(0x3E) */
+#define RT5631_PWR_SPK_L_VOL				(0x1 << 15)
+#define RT5631_PWR_SPK_L_VOL_BIT			15
+#define RT5631_PWR_SPK_R_VOL				(0x1 << 14)
+#define RT5631_PWR_SPK_R_VOL_BIT			14
+#define RT5631_PWR_LOUT_VOL				(0x1 << 13)
+#define RT5631_PWR_LOUT_VOL_BIT			13
+#define RT5631_PWR_ROUT_VOL				(0x1 << 12)
+#define RT5631_PWR_ROUT_VOL_BIT			12
+#define RT5631_PWR_HP_L_OUT_VOL			(0x1 << 11)
+#define RT5631_PWR_HP_L_OUT_VOL_BIT			11
+#define RT5631_PWR_HP_R_OUT_VOL			(0x1 << 10)
+#define RT5631_PWR_HP_R_OUT_VOL_BIT			10
+#define RT5631_PWR_AXIL_IN_VOL				(0x1 << 9)
+#define RT5631_PWR_AXIL_IN_VOL_BIT			9
+#define RT5631_PWR_AXIR_IN_VOL			(0x1 << 8)
+#define RT5631_PWR_AXIR_IN_VOL_BIT			8
+#define RT5631_PWR_MONO_IN_P_VOL			(0x1 << 7)
+#define RT5631_PWR_MONO_IN_P_VOL_BIT			7
+#define RT5631_PWR_MONO_IN_N_VOL			(0x1 << 6)
+#define RT5631_PWR_MONO_IN_N_VOL_BIT			6
+
+/* General Purpose Control Register(0x40) */
+#define RT5631_SPK_AMP_AUTO_RATIO_EN			(0x1 << 15)
+
+#define RT5631_SPK_AMP_RATIO_CTRL_MASK		(0x7 << 12)
+#define RT5631_SPK_AMP_RATIO_CTRL_2_34		(0x0 << 12) /* 7.40DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_1_99		(0x1 << 12) /* 5.99DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_1_68		(0x2 << 12) /* 4.50DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_1_56		(0x3 << 12) /* 3.86DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_1_44		(0x4 << 12) /* 3.16DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_1_27		(0x5 << 12) /* 2.10DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_1_09		(0x6 << 12) /* 0.80DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_1_00		(0x7 << 12) /* 0.00DB */
+#define RT5631_SPK_AMP_RATIO_CTRL_SHIFT		12
+
+#define RT5631_STEREO_DAC_HI_PASS_FILT_EN		(0x1 << 11)
+#define RT5631_STEREO_ADC_HI_PASS_FILT_EN		(0x1 << 10)
+/* Select ADC Wind Filter Clock type */
+#define RT5631_ADC_WIND_FILT_MASK			(0x3 << 4)
+#define RT5631_ADC_WIND_FILT_8_16_32K			(0x0 << 4) /*8/16/32k*/
+#define RT5631_ADC_WIND_FILT_11_22_44K		(0x1 << 4) /*11/22/44k*/
+#define RT5631_ADC_WIND_FILT_12_24_48K		(0x2 << 4) /*12/24/48k*/
+#define RT5631_ADC_WIND_FILT_EN			(0x1 << 3)
+/* SelectADC Wind Filter Corner Frequency */
+#define RT5631_ADC_WIND_CNR_FREQ_MASK	(0x7 << 0)
+#define RT5631_ADC_WIND_CNR_FREQ_82_113_122	(0x0 << 0) /* 82/113/122 Hz */
+#define RT5631_ADC_WIND_CNR_FREQ_102_141_153 (0x1 << 0) /* 102/141/153 Hz */
+#define RT5631_ADC_WIND_CNR_FREQ_131_180_156 (0x2 << 0) /* 131/180/156 Hz */
+#define RT5631_ADC_WIND_CNR_FREQ_163_225_245 (0x3 << 0) /* 163/225/245 Hz */
+#define RT5631_ADC_WIND_CNR_FREQ_204_281_306 (0x4 << 0) /* 204/281/306 Hz */
+#define RT5631_ADC_WIND_CNR_FREQ_261_360_392 (0x5 << 0) /* 261/360/392 Hz */
+#define RT5631_ADC_WIND_CNR_FREQ_327_450_490 (0x6 << 0) /* 327/450/490 Hz */
+#define RT5631_ADC_WIND_CNR_FREQ_408_563_612 (0x7 << 0) /* 408/563/612 Hz */
+
+/* Global Clock Control Register(0x42) */
+#define RT5631_SYSCLK_SOUR_SEL_MASK			(0x3 << 14)
+#define RT5631_SYSCLK_SOUR_SEL_MCLK			(0x0 << 14)
+#define RT5631_SYSCLK_SOUR_SEL_PLL			(0x1 << 14)
+#define RT5631_SYSCLK_SOUR_SEL_PLL_TCK		(0x2 << 14)
+
+#define RT5631_PLLCLK_SOUR_SEL_MASK			(0x3 << 12)
+#define RT5631_PLLCLK_SOUR_SEL_MCLK			(0x0 << 12)
+#define RT5631_PLLCLK_SOUR_SEL_BCLK			(0x1 << 12)
+#define RT5631_PLLCLK_SOUR_SEL_VBCLK			(0x2 << 12)
+
+#define RT5631_PLLCLK_PRE_DIV1				(0x0 << 11)
+#define RT5631_PLLCLK_PRE_DIV2				(0x1 << 11)
+
+/* PLL Control(0x44) */
+#define RT5631_PLL_CTRL_M_VAL(m)			((m)&0xf)
+#define RT5631_PLL_CTRL_K_VAL(k)			(((k)&0x7) << 4)
+#define RT5631_PLL_CTRL_N_VAL(n)			(((n)&0xff) << 8)
+
+/* Internal Status and IRQ Control2(0x4A) */
+#define RT5631_ADC_DATA_SEL_MASK			(0x3 << 14)
+#define RT5631_ADC_DATA_SEL_Disable			(0x0 << 14)
+#define RT5631_ADC_DATA_SEL_MIC1			(0x1 << 14)
+#define RT5631_ADC_DATA_SEL_MIC1_SHIFT		14
+#define RT5631_ADC_DATA_SEL_MIC2			(0x2 << 14)
+#define RT5631_ADC_DATA_SEL_MIC2_SHIFT		15
+#define RT5631_ADC_DATA_SEL_STO			(0x3 << 14)
+#define RT5631_ADC_DATA_SEL_SHIFT			14
+
+/* GPIO Pin Configuration(0x4C) */
+#define RT5631_GPIO_PIN_FUN_SEL_MASK			(0x1 << 15)
+#define RT5631_GPIO_PIN_FUN_SEL_IRQ			(0x1 << 15)
+#define RT5631_GPIO_PIN_FUN_SEL_GPIO_DIMC		(0x0 << 15)
+
+#define RT5631_GPIO_DMIC_FUN_SEL_MASK		(0x1 << 3)
+#define RT5631_GPIO_DMIC_FUN_SEL_DIMC		(0x1 << 3)
+#define RT5631_GPIO_DMIC_FUN_SEL_GPIO			(0x0 << 3)
+
+#define RT5631_GPIO_PIN_CON_MASK			(0x1 << 2)
+#define RT5631_GPIO_PIN_SET_INPUT			(0x0 << 2)
+#define RT5631_GPIO_PIN_SET_OUTPUT			(0x1 << 2)
+
+/* De-POP function Control 1(0x54) */
+#define RT5631_POW_ON_SOFT_GEN			(0x1 << 15)
+#define RT5631_EN_MUTE_UNMUTE_DEPOP			(0x1 << 14)
+#define RT5631_EN_DEPOP2_FOR_HP			(0x1 << 7)
+/* Power Down HPAMP_L Starts Up Signal */
+#define RT5631_PD_HPAMP_L_ST_UP			(0x1 << 5)
+/* Power Down HPAMP_R Starts Up Signal */
+#define RT5631_PD_HPAMP_R_ST_UP			(0x1 << 4)
+/* Enable left HP mute/unmute depop */
+#define RT5631_EN_HP_L_M_UN_MUTE_DEPOP		(0x1 << 1)
+/* Enable right HP mute/unmute depop */
+#define RT5631_EN_HP_R_M_UN_MUTE_DEPOP		(0x1 << 0)
+
+/* De-POP Fnction Control(0x56) */
+#define RT5631_EN_ONE_BIT_DEPOP			(0x1 << 15)
+#define RT5631_EN_CAP_FREE_DEPOP			(0x1 << 14)
+
+/* Jack Detect Control Register(0x5A) */
+#define RT5631_JD_USE_MASK				(0x3 << 14)
+#define RT5631_JD_USE_JD2				(0x3 << 14)
+#define RT5631_JD_USE_JD1				(0x2 << 14)
+#define RT5631_JD_USE_GPIO				(0x1 << 14)
+#define RT5631_JD_OFF					(0x0 << 14)
+/* JD trigger enable for HP */
+#define RT5631_JD_HP_EN					(0x1 << 11)
+#define RT5631_JD_HP_TRI_MASK				(0x1 << 10)
+#define RT5631_JD_HP_TRI_HI				(0x1 << 10)
+#define RT5631_JD_HP_TRI_LO				(0x1 << 10)
+/* JD trigger enable for speaker LP/LN */
+#define RT5631_JD_SPK_L_EN				(0x1 << 9)
+#define RT5631_JD_SPK_L_TRI_MASK			(0x1 << 8)
+#define RT5631_JD_SPK_L_TRI_HI				(0x1 << 8)
+#define RT5631_JD_SPK_L_TRI_LO				(0x0 << 8)
+/* JD trigger enable for speaker RP/RN */
+#define RT5631_JD_SPK_R_EN				(0x1 << 7)
+#define RT5631_JD_SPK_R_TRI_MASK			(0x1 << 6)
+#define RT5631_JD_SPK_R_TRI_HI				(0x1 << 6)
+#define RT5631_JD_SPK_R_TRI_LO				(0x0 << 6)
+/* JD trigger enable for monoout */
+#define RT5631_JD_MONO_EN				(0x1 << 5)
+#define RT5631_JD_MONO_TRI_MASK			(0x1 << 4)
+#define RT5631_JD_MONO_TRI_HI				(0x1 << 4)
+#define RT5631_JD_MONO_TRI_LO				(0x0 << 4)
+/* JD trigger enable for Lout */
+#define RT5631_JD_AUX_1_EN				(0x1 << 3)
+#define RT5631_JD_AUX_1_MASK				(0x1 << 2)
+#define RT5631_JD_AUX_1_TRI_HI				(0x1 << 2)
+#define RT5631_JD_AUX_1_TRI_LO				(0x0 << 2)
+/* JD trigger enable for Rout */
+#define RT5631_JD_AUX_2_EN				(0x1 << 1)
+#define RT5631_JD_AUX_2_MASK				(0x1 << 0)
+#define RT5631_JD_AUX_2_TRI_HI				(0x1 << 0)
+#define RT5631_JD_AUX_2_TRI_LO				(0x0 << 0)
+
+/* ALC CONTROL 1(0x64) */
+#define RT5631_ALC_ATTACK_RATE_MASK			(0x1F << 8)
+#define RT5631_ALC_RECOVERY_RATE_MASK		(0x1F << 0)
+
+/* ALC CONTROL 2(0x65) */
+/* select Compensation gain for Noise gate function */
+#define RT5631_ALC_COM_NOISE_GATE_MASK		(0xF << 0)
+
+/* ALC CONTROL 3(0x66) */
+#define RT5631_ALC_FUN_MASK				(0x3 << 14)
+#define RT5631_ALC_FUN_DIS				(0x0 << 14)
+#define RT5631_ALC_ENA_DAC_PATH			(0x1 << 14)
+#define RT5631_ALC_ENA_ADC_PATH			(0x3 << 14)
+#define RT5631_ALC_PARA_UPDATE			(0x1 << 13)
+#define RT5631_ALC_LIMIT_LEVEL_MASK			(0x1F << 8)
+#define RT5631_ALC_NOISE_GATE_FUN_MASK		(0x1 << 7)
+#define RT5631_ALC_NOISE_GATE_FUN_DIS			(0x0 << 7)
+#define RT5631_ALC_NOISE_GATE_FUN_ENA		(0x1 << 7)
+/* ALC noise gate hold data function */
+#define RT5631_ALC_NOISE_GATE_H_D_MASK		(0x1 << 6)
+#define RT5631_ALC_NOISE_GATE_H_D_DIS			(0x0 << 6)
+#define RT5631_ALC_NOISE_GATE_H_D_ENA		(0x1 << 6)
+
+/* Psedueo Stereo & Spatial Effect Block Control(0x68) */
+#define RT5631_SPATIAL_CTRL_EN				(0x1 << 15)
+#define RT5631_ALL_PASS_FILTER_EN			(0x1 << 14)
+#define RT5631_PSEUDO_STEREO_EN			(0x1 << 13)
+#define RT5631_STEREO_EXPENSION_EN			(0x1 << 12)
+/* 3D gain parameter */
+#define RT5631_GAIN_3D_PARA_MASK		(0x3 << 6)
+#define RT5631_GAIN_3D_PARA_1_00		(0x0 << 6) /* 3D gain 1.0 */
+#define RT5631_GAIN_3D_PARA_1_50		(0x1 << 6) /* 3D gain 1.5 */
+#define RT5631_GAIN_3D_PARA_2_00		(0x2 << 6) /* 3D gain 2.0 */
+/* 3D ratio parameter */
+#define RT5631_RATIO_3D_MASK			(0x3 << 4)
+#define RT5631_RATIO_3D_0_0			(0x0 << 4) /* 3D ratio 0.0 */
+#define RT5631_RATIO_3D_0_66			(0x1 << 4) /* 3D ratio 0.66 */
+#define RT5631_RATIO_3D_1_0			(0x2 << 4) /* 3D ratio 1.0 */
+/* select samplerate for all pass filter */
+#define RT5631_APF_FUN_SLE_MASK			(0x3 << 0)
+#define RT5631_APF_FUN_SEL_48K				(0x3 << 0)
+#define RT5631_APF_FUN_SEL_44_1K			(0x2 << 0)
+#define RT5631_APF_FUN_SEL_32K				(0x1 << 0)
+#define RT5631_APF_FUN_DIS				(0x0 << 0)
+
+/* EQ CONTROL 1(0x6E) */
+#define RT5631_HW_EQ_PATH_SEL_MASK			(0x1 << 15)
+#define RT5631_HW_EQ_PATH_SEL_DAC			(0x0 << 15)
+#define RT5631_HW_EQ_PATH_SEL_ADC			(0x1 << 15)
+#define RT5631_HW_EQ_UPDATE_CTRL			(0x1 << 14)
+
+#define RT5631_EN_HW_EQ_HPF2				(0x1 << 5)
+#define RT5631_EN_HW_EQ_HPF1				(0x1 << 4)
+#define RT5631_EN_HW_EQ_BP3				(0x1 << 3)
+#define RT5631_EN_HW_EQ_BP2				(0x1 << 2)
+#define RT5631_EN_HW_EQ_BP1				(0x1 << 1)
+#define RT5631_EN_HW_EQ_LPF				(0x1 << 0)
+
+
+#endif /* __RTCODEC5631_H__ */
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
new file mode 100644
index 0000000..2777014
--- /dev/null
+++ b/sound/soc/codecs/rt5640.c
@@ -0,0 +1,2864 @@
+/*
+ * rt5640.c  --  RT5640/RT5639 ALSA SoC audio codec driver
+ *
+ * Copyright 2011 Realtek Semiconductor Corp.
+ * Author: Johnny Hsu <johnnyhsu@realtek.com>
+ * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rl6231.h"
+#include "rt5640.h"
+
+#define RT5640_DEVICE_ID 0x6231
+
+#define RT5640_PR_RANGE_BASE (0xff + 1)
+#define RT5640_PR_SPACING 0x100
+
+#define RT5640_PR_BASE (RT5640_PR_RANGE_BASE + (0 * RT5640_PR_SPACING))
+
+static const struct regmap_range_cfg rt5640_ranges[] = {
+	{ .name = "PR", .range_min = RT5640_PR_BASE,
+	  .range_max = RT5640_PR_BASE + 0xb4,
+	  .selector_reg = RT5640_PRIV_INDEX,
+	  .selector_mask = 0xff,
+	  .selector_shift = 0x0,
+	  .window_start = RT5640_PRIV_DATA,
+	  .window_len = 0x1, },
+};
+
+static const struct reg_sequence init_list[] = {
+	{RT5640_PR_BASE + 0x3d,	0x3600},
+	{RT5640_PR_BASE + 0x12,	0x0aa8},
+	{RT5640_PR_BASE + 0x14,	0x0aaa},
+	{RT5640_PR_BASE + 0x20,	0x6110},
+	{RT5640_PR_BASE + 0x21,	0xe0e0},
+	{RT5640_PR_BASE + 0x23,	0x1804},
+};
+
+static const struct reg_default rt5640_reg[] = {
+	{ 0x00, 0x000e },
+	{ 0x01, 0xc8c8 },
+	{ 0x02, 0xc8c8 },
+	{ 0x03, 0xc8c8 },
+	{ 0x04, 0x8000 },
+	{ 0x0d, 0x0000 },
+	{ 0x0e, 0x0000 },
+	{ 0x0f, 0x0808 },
+	{ 0x19, 0xafaf },
+	{ 0x1a, 0xafaf },
+	{ 0x1b, 0x0000 },
+	{ 0x1c, 0x2f2f },
+	{ 0x1d, 0x2f2f },
+	{ 0x1e, 0x0000 },
+	{ 0x27, 0x7060 },
+	{ 0x28, 0x7070 },
+	{ 0x29, 0x8080 },
+	{ 0x2a, 0x5454 },
+	{ 0x2b, 0x5454 },
+	{ 0x2c, 0xaa00 },
+	{ 0x2d, 0x0000 },
+	{ 0x2e, 0xa000 },
+	{ 0x2f, 0x0000 },
+	{ 0x3b, 0x0000 },
+	{ 0x3c, 0x007f },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x007f },
+	{ 0x45, 0xe000 },
+	{ 0x46, 0x003e },
+	{ 0x47, 0x003e },
+	{ 0x48, 0xf800 },
+	{ 0x49, 0x3800 },
+	{ 0x4a, 0x0004 },
+	{ 0x4c, 0xfc00 },
+	{ 0x4d, 0x0000 },
+	{ 0x4f, 0x01ff },
+	{ 0x50, 0x0000 },
+	{ 0x51, 0x0000 },
+	{ 0x52, 0x01ff },
+	{ 0x53, 0xf000 },
+	{ 0x61, 0x0000 },
+	{ 0x62, 0x0000 },
+	{ 0x63, 0x00c0 },
+	{ 0x64, 0x0000 },
+	{ 0x65, 0x0000 },
+	{ 0x66, 0x0000 },
+	{ 0x6a, 0x0000 },
+	{ 0x6c, 0x0000 },
+	{ 0x70, 0x8000 },
+	{ 0x71, 0x8000 },
+	{ 0x72, 0x8000 },
+	{ 0x73, 0x1114 },
+	{ 0x74, 0x0c00 },
+	{ 0x75, 0x1d00 },
+	{ 0x80, 0x0000 },
+	{ 0x81, 0x0000 },
+	{ 0x82, 0x0000 },
+	{ 0x83, 0x0000 },
+	{ 0x84, 0x0000 },
+	{ 0x85, 0x0008 },
+	{ 0x89, 0x0000 },
+	{ 0x8a, 0x0000 },
+	{ 0x8b, 0x0600 },
+	{ 0x8c, 0x0228 },
+	{ 0x8d, 0xa000 },
+	{ 0x8e, 0x0004 },
+	{ 0x8f, 0x1100 },
+	{ 0x90, 0x0646 },
+	{ 0x91, 0x0c00 },
+	{ 0x92, 0x0000 },
+	{ 0x93, 0x3000 },
+	{ 0xb0, 0x2080 },
+	{ 0xb1, 0x0000 },
+	{ 0xb4, 0x2206 },
+	{ 0xb5, 0x1f00 },
+	{ 0xb6, 0x0000 },
+	{ 0xb8, 0x034b },
+	{ 0xb9, 0x0066 },
+	{ 0xba, 0x000b },
+	{ 0xbb, 0x0000 },
+	{ 0xbc, 0x0000 },
+	{ 0xbd, 0x0000 },
+	{ 0xbe, 0x0000 },
+	{ 0xbf, 0x0000 },
+	{ 0xc0, 0x0400 },
+	{ 0xc2, 0x0000 },
+	{ 0xc4, 0x0000 },
+	{ 0xc5, 0x0000 },
+	{ 0xc6, 0x2000 },
+	{ 0xc8, 0x0000 },
+	{ 0xc9, 0x0000 },
+	{ 0xca, 0x0000 },
+	{ 0xcb, 0x0000 },
+	{ 0xcc, 0x0000 },
+	{ 0xcf, 0x0013 },
+	{ 0xd0, 0x0680 },
+	{ 0xd1, 0x1c17 },
+	{ 0xd2, 0x8c00 },
+	{ 0xd3, 0xaa20 },
+	{ 0xd6, 0x0400 },
+	{ 0xd9, 0x0809 },
+	{ 0xfe, 0x10ec },
+	{ 0xff, 0x6231 },
+};
+
+static int rt5640_reset(struct snd_soc_component *component)
+{
+	return snd_soc_component_write(component, RT5640_RESET, 0);
+}
+
+static bool rt5640_volatile_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5640_ranges); i++)
+		if ((reg >= rt5640_ranges[i].window_start &&
+		     reg <= rt5640_ranges[i].window_start +
+		     rt5640_ranges[i].window_len) ||
+		    (reg >= rt5640_ranges[i].range_min &&
+		     reg <= rt5640_ranges[i].range_max))
+			return true;
+
+	switch (reg) {
+	case RT5640_RESET:
+	case RT5640_ASRC_5:
+	case RT5640_EQ_CTRL1:
+	case RT5640_DRC_AGC_1:
+	case RT5640_ANC_CTRL1:
+	case RT5640_IRQ_CTRL2:
+	case RT5640_INT_IRQ_ST:
+	case RT5640_DSP_CTRL2:
+	case RT5640_DSP_CTRL3:
+	case RT5640_PRIV_INDEX:
+	case RT5640_PRIV_DATA:
+	case RT5640_PGM_REG_ARR1:
+	case RT5640_PGM_REG_ARR3:
+	case RT5640_VENDOR_ID:
+	case RT5640_VENDOR_ID1:
+	case RT5640_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5640_readable_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5640_ranges); i++)
+		if ((reg >= rt5640_ranges[i].window_start &&
+		     reg <= rt5640_ranges[i].window_start +
+		     rt5640_ranges[i].window_len) ||
+		    (reg >= rt5640_ranges[i].range_min &&
+		     reg <= rt5640_ranges[i].range_max))
+			return true;
+
+	switch (reg) {
+	case RT5640_RESET:
+	case RT5640_SPK_VOL:
+	case RT5640_HP_VOL:
+	case RT5640_OUTPUT:
+	case RT5640_MONO_OUT:
+	case RT5640_IN1_IN2:
+	case RT5640_IN3_IN4:
+	case RT5640_INL_INR_VOL:
+	case RT5640_DAC1_DIG_VOL:
+	case RT5640_DAC2_DIG_VOL:
+	case RT5640_DAC2_CTRL:
+	case RT5640_ADC_DIG_VOL:
+	case RT5640_ADC_DATA:
+	case RT5640_ADC_BST_VOL:
+	case RT5640_STO_ADC_MIXER:
+	case RT5640_MONO_ADC_MIXER:
+	case RT5640_AD_DA_MIXER:
+	case RT5640_STO_DAC_MIXER:
+	case RT5640_MONO_DAC_MIXER:
+	case RT5640_DIG_MIXER:
+	case RT5640_DSP_PATH1:
+	case RT5640_DSP_PATH2:
+	case RT5640_DIG_INF_DATA:
+	case RT5640_REC_L1_MIXER:
+	case RT5640_REC_L2_MIXER:
+	case RT5640_REC_R1_MIXER:
+	case RT5640_REC_R2_MIXER:
+	case RT5640_HPO_MIXER:
+	case RT5640_SPK_L_MIXER:
+	case RT5640_SPK_R_MIXER:
+	case RT5640_SPO_L_MIXER:
+	case RT5640_SPO_R_MIXER:
+	case RT5640_SPO_CLSD_RATIO:
+	case RT5640_MONO_MIXER:
+	case RT5640_OUT_L1_MIXER:
+	case RT5640_OUT_L2_MIXER:
+	case RT5640_OUT_L3_MIXER:
+	case RT5640_OUT_R1_MIXER:
+	case RT5640_OUT_R2_MIXER:
+	case RT5640_OUT_R3_MIXER:
+	case RT5640_LOUT_MIXER:
+	case RT5640_PWR_DIG1:
+	case RT5640_PWR_DIG2:
+	case RT5640_PWR_ANLG1:
+	case RT5640_PWR_ANLG2:
+	case RT5640_PWR_MIXER:
+	case RT5640_PWR_VOL:
+	case RT5640_PRIV_INDEX:
+	case RT5640_PRIV_DATA:
+	case RT5640_I2S1_SDP:
+	case RT5640_I2S2_SDP:
+	case RT5640_ADDA_CLK1:
+	case RT5640_ADDA_CLK2:
+	case RT5640_DMIC:
+	case RT5640_GLB_CLK:
+	case RT5640_PLL_CTRL1:
+	case RT5640_PLL_CTRL2:
+	case RT5640_ASRC_1:
+	case RT5640_ASRC_2:
+	case RT5640_ASRC_3:
+	case RT5640_ASRC_4:
+	case RT5640_ASRC_5:
+	case RT5640_HP_OVCD:
+	case RT5640_CLS_D_OVCD:
+	case RT5640_CLS_D_OUT:
+	case RT5640_DEPOP_M1:
+	case RT5640_DEPOP_M2:
+	case RT5640_DEPOP_M3:
+	case RT5640_CHARGE_PUMP:
+	case RT5640_PV_DET_SPK_G:
+	case RT5640_MICBIAS:
+	case RT5640_EQ_CTRL1:
+	case RT5640_EQ_CTRL2:
+	case RT5640_WIND_FILTER:
+	case RT5640_DRC_AGC_1:
+	case RT5640_DRC_AGC_2:
+	case RT5640_DRC_AGC_3:
+	case RT5640_SVOL_ZC:
+	case RT5640_ANC_CTRL1:
+	case RT5640_ANC_CTRL2:
+	case RT5640_ANC_CTRL3:
+	case RT5640_JD_CTRL:
+	case RT5640_ANC_JD:
+	case RT5640_IRQ_CTRL1:
+	case RT5640_IRQ_CTRL2:
+	case RT5640_INT_IRQ_ST:
+	case RT5640_GPIO_CTRL1:
+	case RT5640_GPIO_CTRL2:
+	case RT5640_GPIO_CTRL3:
+	case RT5640_DSP_CTRL1:
+	case RT5640_DSP_CTRL2:
+	case RT5640_DSP_CTRL3:
+	case RT5640_DSP_CTRL4:
+	case RT5640_PGM_REG_ARR1:
+	case RT5640_PGM_REG_ARR2:
+	case RT5640_PGM_REG_ARR3:
+	case RT5640_PGM_REG_ARR4:
+	case RT5640_PGM_REG_ARR5:
+	case RT5640_SCB_FUNC:
+	case RT5640_SCB_CTRL:
+	case RT5640_BASE_BACK:
+	case RT5640_MP3_PLUS1:
+	case RT5640_MP3_PLUS2:
+	case RT5640_3D_HP:
+	case RT5640_ADJ_HPF:
+	case RT5640_HP_CALIB_AMP_DET:
+	case RT5640_HP_CALIB2:
+	case RT5640_SV_ZCD1:
+	case RT5640_SV_ZCD2:
+	case RT5640_DUMMY1:
+	case RT5640_DUMMY2:
+	case RT5640_DUMMY3:
+	case RT5640_VENDOR_ID:
+	case RT5640_VENDOR_ID1:
+	case RT5640_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+/* Interface data select */
+static const char * const rt5640_data_select[] = {
+	"Normal", "Swap", "left copy to right", "right copy to left"};
+
+static SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA,
+			    RT5640_IF1_DAC_SEL_SFT, rt5640_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA,
+			    RT5640_IF1_ADC_SEL_SFT, rt5640_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA,
+			    RT5640_IF2_DAC_SEL_SFT, rt5640_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA,
+			    RT5640_IF2_ADC_SEL_SFT, rt5640_data_select);
+
+/* Class D speaker gain ratio */
+static const char * const rt5640_clsd_spk_ratio[] = {"1.66x", "1.83x", "1.94x",
+	"2x", "2.11x", "2.22x", "2.33x", "2.44x", "2.55x", "2.66x", "2.77x"};
+
+static SOC_ENUM_SINGLE_DECL(rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT,
+			    RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio);
+
+static const struct snd_kcontrol_new rt5640_snd_controls[] = {
+	/* Speaker Output Volume */
+	SOC_DOUBLE("Speaker Channel Switch", RT5640_SPK_VOL,
+		RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
+	SOC_DOUBLE_TLV("Speaker Playback Volume", RT5640_SPK_VOL,
+		RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
+	/* Headphone Output Volume */
+	SOC_DOUBLE("HP Channel Switch", RT5640_HP_VOL,
+		RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
+	SOC_DOUBLE_TLV("HP Playback Volume", RT5640_HP_VOL,
+		RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
+	/* OUTPUT Control */
+	SOC_DOUBLE("OUT Playback Switch", RT5640_OUTPUT,
+		RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE("OUT Channel Switch", RT5640_OUTPUT,
+		RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
+	SOC_DOUBLE_TLV("OUT Playback Volume", RT5640_OUTPUT,
+		RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE("DAC2 Playback Switch", RT5640_DAC2_CTRL,
+		RT5640_M_DAC_L2_VOL_SFT, RT5640_M_DAC_R2_VOL_SFT, 1, 1),
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5640_DAC1_DIG_VOL,
+			RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
+			175, 0, dac_vol_tlv),
+	/* IN1/IN2/IN3 Control */
+	SOC_SINGLE_TLV("IN1 Boost", RT5640_IN1_IN2,
+		RT5640_BST_SFT1, 8, 0, bst_tlv),
+	SOC_SINGLE_TLV("IN2 Boost", RT5640_IN3_IN4,
+		RT5640_BST_SFT2, 8, 0, bst_tlv),
+	SOC_SINGLE_TLV("IN3 Boost", RT5640_IN1_IN2,
+		RT5640_BST_SFT2, 8, 0, bst_tlv),
+
+	/* INL/INR Volume Control */
+	SOC_DOUBLE_TLV("IN Capture Volume", RT5640_INL_INR_VOL,
+			RT5640_INL_VOL_SFT, RT5640_INR_VOL_SFT,
+			31, 1, in_vol_tlv),
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("ADC Capture Switch", RT5640_ADC_DIG_VOL,
+		RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("ADC Capture Volume", RT5640_ADC_DIG_VOL,
+			RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
+			127, 0, adc_vol_tlv),
+	SOC_DOUBLE("Mono ADC Capture Switch", RT5640_DUMMY1,
+		RT5640_M_MONO_ADC_L_SFT, RT5640_M_MONO_ADC_R_SFT, 1, 1),
+	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5640_ADC_DATA,
+			RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
+			127, 0, adc_vol_tlv),
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("ADC Boost Gain", RT5640_ADC_BST_VOL,
+			RT5640_ADC_L_BST_SFT, RT5640_ADC_R_BST_SFT,
+			3, 0, adc_bst_tlv),
+	/* Class D speaker gain ratio */
+	SOC_ENUM("Class D SPK Ratio Control", rt5640_clsd_spk_ratio_enum),
+
+	SOC_ENUM("ADC IF1 Data Switch", rt5640_if1_adc_enum),
+	SOC_ENUM("DAC IF1 Data Switch", rt5640_if1_dac_enum),
+	SOC_ENUM("ADC IF2 Data Switch", rt5640_if2_adc_enum),
+	SOC_ENUM("DAC IF2 Data Switch", rt5640_if2_dac_enum),
+};
+
+static const struct snd_kcontrol_new rt5640_specific_snd_controls[] = {
+	/* MONO Output Control */
+	SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT, RT5640_L_MUTE_SFT,
+		1, 1),
+
+	SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL,
+		RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 175, 0, dac_vol_tlv),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+	int idx, rate;
+
+	rate = rt5640->sysclk / rl6231_get_pre_div(rt5640->regmap,
+		RT5640_ADDA_CLK1, RT5640_I2S_PD1_SFT);
+	idx = rl6231_calc_dmic_clk(rate);
+	if (idx < 0)
+		dev_err(component->dev, "Failed to set DMIC clock\n");
+	else
+		snd_soc_component_update_bits(component, RT5640_DMIC, RT5640_DMIC_CLK_MASK,
+					idx << RT5640_DMIC_CLK_SFT);
+	return idx;
+}
+
+static int is_using_asrc(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	if (!rt5640->asrc_en)
+		return 0;
+
+	return 1;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5640_sto_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5640_STO_ADC_MIXER,
+			RT5640_M_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5640_STO_ADC_MIXER,
+			RT5640_M_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_sto_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5640_STO_ADC_MIXER,
+			RT5640_M_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5640_STO_ADC_MIXER,
+			RT5640_M_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5640_MONO_ADC_MIXER,
+			RT5640_M_MONO_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5640_MONO_ADC_MIXER,
+			RT5640_M_MONO_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5640_MONO_ADC_MIXER,
+			RT5640_M_MONO_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5640_MONO_ADC_MIXER,
+			RT5640_M_MONO_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5640_AD_DA_MIXER,
+			RT5640_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INF1 Switch", RT5640_AD_DA_MIXER,
+			RT5640_M_IF1_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5640_AD_DA_MIXER,
+			RT5640_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INF1 Switch", RT5640_AD_DA_MIXER,
+			RT5640_M_IF1_DAC_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_sto_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_STO_DAC_MIXER,
+			RT5640_M_DAC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_STO_DAC_MIXER,
+			RT5640_M_DAC_L2_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ANC Switch", RT5640_STO_DAC_MIXER,
+			RT5640_M_ANC_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_sto_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_STO_DAC_MIXER,
+			RT5640_M_DAC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_STO_DAC_MIXER,
+			RT5640_M_DAC_R2_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ANC Switch", RT5640_STO_DAC_MIXER,
+			RT5640_M_ANC_DAC_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5639_sto_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_STO_DAC_MIXER,
+			RT5640_M_DAC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_STO_DAC_MIXER,
+			RT5640_M_DAC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5639_sto_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_STO_DAC_MIXER,
+			RT5640_M_DAC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_STO_DAC_MIXER,
+			RT5640_M_DAC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_MONO_DAC_MIXER,
+			RT5640_M_DAC_L1_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_MONO_DAC_MIXER,
+			RT5640_M_DAC_L2_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_MONO_DAC_MIXER,
+			RT5640_M_DAC_R2_MONO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_MONO_DAC_MIXER,
+			RT5640_M_DAC_R1_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_MONO_DAC_MIXER,
+			RT5640_M_DAC_R2_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_MONO_DAC_MIXER,
+			RT5640_M_DAC_L2_MONO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_dig_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_DIG_MIXER,
+			RT5640_M_STO_L_DAC_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_DIG_MIXER,
+			RT5640_M_DAC_L2_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_dig_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_DIG_MIXER,
+			RT5640_M_STO_R_DAC_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_DIG_MIXER,
+			RT5640_M_DAC_R2_DAC_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5640_rec_l_mix[] = {
+	SOC_DAPM_SINGLE("HPOL Switch", RT5640_REC_L2_MIXER,
+			RT5640_M_HP_L_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5640_REC_L2_MIXER,
+			RT5640_M_IN_L_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5640_REC_L2_MIXER,
+			RT5640_M_BST2_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5640_REC_L2_MIXER,
+			RT5640_M_BST4_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5640_REC_L2_MIXER,
+			RT5640_M_BST1_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUT MIXL Switch", RT5640_REC_L2_MIXER,
+			RT5640_M_OM_L_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_rec_r_mix[] = {
+	SOC_DAPM_SINGLE("HPOR Switch", RT5640_REC_R2_MIXER,
+			RT5640_M_HP_R_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5640_REC_R2_MIXER,
+			RT5640_M_IN_R_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5640_REC_R2_MIXER,
+			RT5640_M_BST2_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5640_REC_R2_MIXER,
+			RT5640_M_BST4_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5640_REC_R2_MIXER,
+			RT5640_M_BST1_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUT MIXR Switch", RT5640_REC_R2_MIXER,
+			RT5640_M_OM_R_RM_R_SFT, 1, 1),
+};
+
+/* Analog Output Mixer */
+static const struct snd_kcontrol_new rt5640_spk_l_mix[] = {
+	SOC_DAPM_SINGLE("REC MIXL Switch", RT5640_SPK_L_MIXER,
+			RT5640_M_RM_L_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5640_SPK_L_MIXER,
+			RT5640_M_IN_L_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_SPK_L_MIXER,
+			RT5640_M_DAC_L1_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_SPK_L_MIXER,
+			RT5640_M_DAC_L2_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUT MIXL Switch", RT5640_SPK_L_MIXER,
+			RT5640_M_OM_L_SM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_spk_r_mix[] = {
+	SOC_DAPM_SINGLE("REC MIXR Switch", RT5640_SPK_R_MIXER,
+			RT5640_M_RM_R_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5640_SPK_R_MIXER,
+			RT5640_M_IN_R_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_SPK_R_MIXER,
+			RT5640_M_DAC_R1_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_SPK_R_MIXER,
+			RT5640_M_DAC_R2_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUT MIXR Switch", RT5640_SPK_R_MIXER,
+			RT5640_M_OM_R_SM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_out_l_mix[] = {
+	SOC_DAPM_SINGLE("SPK MIXL Switch", RT5640_OUT_L3_MIXER,
+			RT5640_M_SM_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_L3_MIXER,
+			RT5640_M_BST1_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5640_OUT_L3_MIXER,
+			RT5640_M_IN_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("REC MIXL Switch", RT5640_OUT_L3_MIXER,
+			RT5640_M_RM_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_OUT_L3_MIXER,
+			RT5640_M_DAC_R2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_OUT_L3_MIXER,
+			RT5640_M_DAC_L2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_OUT_L3_MIXER,
+			RT5640_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_out_r_mix[] = {
+	SOC_DAPM_SINGLE("SPK MIXR Switch", RT5640_OUT_R3_MIXER,
+			RT5640_M_SM_L_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5640_OUT_R3_MIXER,
+			RT5640_M_BST4_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_R3_MIXER,
+			RT5640_M_BST1_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5640_OUT_R3_MIXER,
+			RT5640_M_IN_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("REC MIXR Switch", RT5640_OUT_R3_MIXER,
+			RT5640_M_RM_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_OUT_R3_MIXER,
+			RT5640_M_DAC_L2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_OUT_R3_MIXER,
+			RT5640_M_DAC_R2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_OUT_R3_MIXER,
+			RT5640_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5639_out_l_mix[] = {
+	SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_L3_MIXER,
+			RT5640_M_BST1_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5640_OUT_L3_MIXER,
+			RT5640_M_IN_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("REC MIXL Switch", RT5640_OUT_L3_MIXER,
+			RT5640_M_RM_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_OUT_L3_MIXER,
+			RT5640_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5639_out_r_mix[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5640_OUT_R3_MIXER,
+			RT5640_M_BST4_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_R3_MIXER,
+			RT5640_M_BST1_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5640_OUT_R3_MIXER,
+			RT5640_M_IN_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("REC MIXR Switch", RT5640_OUT_R3_MIXER,
+			RT5640_M_RM_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_OUT_R3_MIXER,
+			RT5640_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_spo_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_SPO_L_MIXER,
+			RT5640_M_DAC_R1_SPM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_SPO_L_MIXER,
+			RT5640_M_DAC_L1_SPM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("SPKVOL R Switch", RT5640_SPO_L_MIXER,
+			RT5640_M_SV_R_SPM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("SPKVOL L Switch", RT5640_SPO_L_MIXER,
+			RT5640_M_SV_L_SPM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5640_SPO_L_MIXER,
+			RT5640_M_BST1_SPM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_spo_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_SPO_R_MIXER,
+			RT5640_M_DAC_R1_SPM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("SPKVOL R Switch", RT5640_SPO_R_MIXER,
+			RT5640_M_SV_R_SPM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5640_SPO_R_MIXER,
+			RT5640_M_BST1_SPM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_hpo_mix[] = {
+	SOC_DAPM_SINGLE("HPO MIX DAC2 Switch", RT5640_HPO_MIXER,
+			RT5640_M_DAC2_HM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("HPO MIX DAC1 Switch", RT5640_HPO_MIXER,
+			RT5640_M_DAC1_HM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("HPO MIX HPVOL Switch", RT5640_HPO_MIXER,
+			RT5640_M_HPVOL_HM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5639_hpo_mix[] = {
+	SOC_DAPM_SINGLE("HPO MIX DAC1 Switch", RT5640_HPO_MIXER,
+			RT5640_M_DAC1_HM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("HPO MIX HPVOL Switch", RT5640_HPO_MIXER,
+			RT5640_M_HPVOL_HM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_lout_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_LOUT_MIXER,
+			RT5640_M_DAC_L1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_LOUT_MIXER,
+			RT5640_M_DAC_R1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL L Switch", RT5640_LOUT_MIXER,
+			RT5640_M_OV_L_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL R Switch", RT5640_LOUT_MIXER,
+			RT5640_M_OV_R_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_mix[] = {
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_MONO_MIXER,
+			RT5640_M_DAC_R2_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_MONO_MIXER,
+			RT5640_M_DAC_L2_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL R Switch", RT5640_MONO_MIXER,
+			RT5640_M_OV_R_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL L Switch", RT5640_MONO_MIXER,
+			RT5640_M_OV_L_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5640_MONO_MIXER,
+			RT5640_M_BST1_MM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new spk_l_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_SPK_VOL,
+		RT5640_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new spk_r_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_SPK_VOL,
+		RT5640_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hp_l_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_HP_VOL,
+		RT5640_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hp_r_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_HP_VOL,
+		RT5640_R_MUTE_SFT, 1, 1);
+
+/* Stereo ADC source */
+static const char * const rt5640_stereo_adc1_src[] = {
+	"DIG MIX", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER,
+			    RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src);
+
+static const struct snd_kcontrol_new rt5640_sto_adc_1_mux =
+	SOC_DAPM_ENUM("Stereo ADC1 Mux", rt5640_stereo_adc1_enum);
+
+static const char * const rt5640_stereo_adc2_src[] = {
+	"DMIC1", "DMIC2", "DIG MIX"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER,
+			    RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src);
+
+static const struct snd_kcontrol_new rt5640_sto_adc_2_mux =
+	SOC_DAPM_ENUM("Stereo ADC2 Mux", rt5640_stereo_adc2_enum);
+
+/* Mono ADC source */
+static const char * const rt5640_mono_adc_l1_src[] = {
+	"Mono DAC MIXL", "ADCL"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER,
+			    RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5640_mono_adc_l1_mux =
+	SOC_DAPM_ENUM("Mono ADC1 left source", rt5640_mono_adc_l1_enum);
+
+static const char * const rt5640_mono_adc_l2_src[] = {
+	"DMIC L1", "DMIC L2", "Mono DAC MIXL"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER,
+			    RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5640_mono_adc_l2_mux =
+	SOC_DAPM_ENUM("Mono ADC2 left source", rt5640_mono_adc_l2_enum);
+
+static const char * const rt5640_mono_adc_r1_src[] = {
+	"Mono DAC MIXR", "ADCR"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER,
+			    RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5640_mono_adc_r1_mux =
+	SOC_DAPM_ENUM("Mono ADC1 right source", rt5640_mono_adc_r1_enum);
+
+static const char * const rt5640_mono_adc_r2_src[] = {
+	"DMIC R1", "DMIC R2", "Mono DAC MIXR"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER,
+			    RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5640_mono_adc_r2_mux =
+	SOC_DAPM_ENUM("Mono ADC2 right source", rt5640_mono_adc_r2_enum);
+
+/* DAC2 channel source */
+static const char * const rt5640_dac_l2_src[] = {
+	"IF2", "Base L/R"
+};
+
+static int rt5640_dac_l2_values[] = {
+	0,
+	3,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_l2_enum,
+				  RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT,
+				  0x3, rt5640_dac_l2_src, rt5640_dac_l2_values);
+
+static const struct snd_kcontrol_new rt5640_dac_l2_mux =
+	SOC_DAPM_ENUM("DAC2 left channel source", rt5640_dac_l2_enum);
+
+static const char * const rt5640_dac_r2_src[] = {
+	"IF2",
+};
+
+static int rt5640_dac_r2_values[] = {
+	0,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_r2_enum,
+				  RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT,
+				  0x3, rt5640_dac_r2_src, rt5640_dac_r2_values);
+
+static const struct snd_kcontrol_new rt5640_dac_r2_mux =
+	SOC_DAPM_ENUM("DAC2 right channel source", rt5640_dac_r2_enum);
+
+/* digital interface and iis interface map */
+static const char * const rt5640_dai_iis_map[] = {
+	"1:1|2:2", "1:2|2:1", "1:1|2:1", "1:2|2:2"
+};
+
+static int rt5640_dai_iis_map_values[] = {
+	0,
+	5,
+	6,
+	7,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dai_iis_map_enum,
+				  RT5640_I2S1_SDP, RT5640_I2S_IF_SFT,
+				  0x7, rt5640_dai_iis_map,
+				  rt5640_dai_iis_map_values);
+
+static const struct snd_kcontrol_new rt5640_dai_mux =
+	SOC_DAPM_ENUM("DAI select", rt5640_dai_iis_map_enum);
+
+/* SDI select */
+static const char * const rt5640_sdi_sel[] = {
+	"IF1", "IF2"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5640_sdi_sel_enum, RT5640_I2S2_SDP,
+			    RT5640_I2S2_SDI_SFT, rt5640_sdi_sel);
+
+static const struct snd_kcontrol_new rt5640_sdi_mux =
+	SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum);
+
+static void hp_amp_power_on(struct snd_soc_component *component)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	/* depop parameters */
+	regmap_update_bits(rt5640->regmap, RT5640_PR_BASE +
+		RT5640_CHPUMP_INT_REG1, 0x0700, 0x0200);
+	regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M2,
+		RT5640_DEPOP_MASK, RT5640_DEPOP_MAN);
+	regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+		RT5640_HP_CP_MASK | RT5640_HP_SG_MASK | RT5640_HP_CB_MASK,
+		RT5640_HP_CP_PU | RT5640_HP_SG_DIS | RT5640_HP_CB_PU);
+	regmap_write(rt5640->regmap, RT5640_PR_BASE + RT5640_HP_DCC_INT1,
+			   0x9f00);
+	/* headphone amp power on */
+	regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+		RT5640_PWR_FV1 | RT5640_PWR_FV2, 0);
+	regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+		RT5640_PWR_HA,
+		RT5640_PWR_HA);
+	usleep_range(10000, 15000);
+	regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+		RT5640_PWR_FV1 | RT5640_PWR_FV2 ,
+		RT5640_PWR_FV1 | RT5640_PWR_FV2);
+}
+
+static void rt5640_pmu_depop(struct snd_soc_component *component)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M2,
+		RT5640_DEPOP_MASK | RT5640_DIG_DP_MASK,
+		RT5640_DEPOP_AUTO | RT5640_DIG_DP_EN);
+	regmap_update_bits(rt5640->regmap, RT5640_CHARGE_PUMP,
+		RT5640_PM_HP_MASK, RT5640_PM_HP_HV);
+
+	regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M3,
+		RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK | RT5640_CP_FQ3_MASK,
+		(RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ1_SFT) |
+		(RT5640_CP_FQ_12_KHZ << RT5640_CP_FQ2_SFT) |
+		(RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ3_SFT));
+
+	regmap_write(rt5640->regmap, RT5640_PR_BASE +
+		RT5640_MAMP_INT_REG2, 0x1c00);
+	regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+		RT5640_HP_CP_MASK | RT5640_HP_SG_MASK,
+		RT5640_HP_CP_PD | RT5640_HP_SG_EN);
+	regmap_update_bits(rt5640->regmap, RT5640_PR_BASE +
+		RT5640_CHPUMP_INT_REG1, 0x0700, 0x0400);
+}
+
+static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		rt5640_pmu_depop(component);
+		rt5640->hp_mute = 0;
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		rt5640->hp_mute = 1;
+		msleep(70);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5640_lout_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		hp_amp_power_on(component);
+		snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
+			RT5640_PWR_LM, RT5640_PWR_LM);
+		snd_soc_component_update_bits(component, RT5640_OUTPUT,
+			RT5640_L_MUTE | RT5640_R_MUTE, 0);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5640_OUTPUT,
+			RT5640_L_MUTE | RT5640_R_MUTE,
+			RT5640_L_MUTE | RT5640_R_MUTE);
+		snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
+			RT5640_PWR_LM, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		hp_amp_power_on(component);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (!rt5640->hp_mute)
+			msleep(80);
+
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY_S("Stereo Filter ASRC", 1, RT5640_ASRC_1,
+			 15, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S2 Filter ASRC", 1, RT5640_ASRC_1,
+			 12, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5640_ASRC_1,
+			 11, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC1 ASRC", 1, RT5640_ASRC_1,
+			 9, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC2 ASRC", 1, RT5640_ASRC_1,
+			 8, 0, NULL, 0),
+
+
+	/* Input Side */
+	/* micbias */
+	SND_SOC_DAPM_SUPPLY("LDO2", RT5640_PWR_ANLG1,
+			RT5640_PWR_LDO2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5640_PWR_ANLG2,
+			RT5640_PWR_MB1_BIT, 0, NULL, 0),
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC1"),
+	SND_SOC_DAPM_INPUT("DMIC2"),
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN1N"),
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN2N"),
+	SND_SOC_DAPM_INPUT("IN3P"),
+	SND_SOC_DAPM_INPUT("IN3N"),
+	SND_SOC_DAPM_PGA("DMIC L1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC R1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC L2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC R2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+		set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5640_DMIC, RT5640_DMIC_1_EN_SFT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5640_DMIC, RT5640_DMIC_2_EN_SFT, 0,
+		NULL, 0),
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1", RT5640_PWR_ANLG2,
+		RT5640_PWR_BST1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST2", RT5640_PWR_ANLG2,
+		RT5640_PWR_BST4_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST3", RT5640_PWR_ANLG2,
+		RT5640_PWR_BST2_BIT, 0, NULL, 0),
+	/* Input Volume */
+	SND_SOC_DAPM_PGA("INL VOL", RT5640_PWR_VOL,
+		RT5640_PWR_IN_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR VOL", RT5640_PWR_VOL,
+		RT5640_PWR_IN_R_BIT, 0, NULL, 0),
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIXL", RT5640_PWR_MIXER, RT5640_PWR_RM_L_BIT, 0,
+			rt5640_rec_l_mix, ARRAY_SIZE(rt5640_rec_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIXR", RT5640_PWR_MIXER, RT5640_PWR_RM_R_BIT, 0,
+			rt5640_rec_r_mix, ARRAY_SIZE(rt5640_rec_r_mix)),
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC L", NULL, RT5640_PWR_DIG1,
+			RT5640_PWR_ADC_L_BIT, 0),
+	SND_SOC_DAPM_ADC("ADC R", NULL, RT5640_PWR_DIG1,
+			RT5640_PWR_ADC_R_BIT, 0),
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("Stereo ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5640_sto_adc_2_mux),
+	SND_SOC_DAPM_MUX("Stereo ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5640_sto_adc_2_mux),
+	SND_SOC_DAPM_MUX("Stereo ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5640_sto_adc_1_mux),
+	SND_SOC_DAPM_MUX("Stereo ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5640_sto_adc_1_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5640_mono_adc_l2_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5640_mono_adc_l1_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5640_mono_adc_r1_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5640_mono_adc_r2_mux),
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("Stereo Filter", RT5640_PWR_DIG2,
+		RT5640_PWR_ADC_SF_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5640_sto_adc_l_mix, ARRAY_SIZE(rt5640_sto_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5640_sto_adc_r_mix, ARRAY_SIZE(rt5640_sto_adc_r_mix)),
+	SND_SOC_DAPM_SUPPLY("Mono Left Filter", RT5640_PWR_DIG2,
+		RT5640_PWR_ADC_MF_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mono ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5640_mono_adc_l_mix, ARRAY_SIZE(rt5640_mono_adc_l_mix)),
+	SND_SOC_DAPM_SUPPLY("Mono Right Filter", RT5640_PWR_DIG2,
+		RT5640_PWR_ADC_MF_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mono ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5640_mono_adc_r_mix, ARRAY_SIZE(rt5640_mono_adc_r_mix)),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5640_PWR_DIG1,
+		RT5640_PWR_I2S1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("I2S2", RT5640_PWR_DIG1,
+		RT5640_PWR_I2S2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	/* Digital Interface Select */
+	SND_SOC_DAPM_MUX("DAI1 RX Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+	SND_SOC_DAPM_MUX("DAI1 TX Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+	SND_SOC_DAPM_MUX("DAI1 IF1 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+	SND_SOC_DAPM_MUX("DAI1 IF2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+	SND_SOC_DAPM_MUX("SDI1 TX Mux", SND_SOC_NOPM, 0, 0, &rt5640_sdi_mux),
+	SND_SOC_DAPM_MUX("DAI2 RX Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+	SND_SOC_DAPM_MUX("DAI2 TX Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+	SND_SOC_DAPM_MUX("DAI2 IF1 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+	SND_SOC_DAPM_MUX("DAI2 IF2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+	SND_SOC_DAPM_MUX("SDI2 TX Mux", SND_SOC_NOPM, 0, 0, &rt5640_sdi_mux),
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Side */
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5640_dac_l_mix, ARRAY_SIZE(rt5640_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5640_dac_r_mix, ARRAY_SIZE(rt5640_dac_r_mix)),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5640_mono_dac_l_mix, ARRAY_SIZE(rt5640_mono_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5640_mono_dac_r_mix, ARRAY_SIZE(rt5640_mono_dac_r_mix)),
+	SND_SOC_DAPM_MIXER("DIG MIXL", SND_SOC_NOPM, 0, 0,
+		rt5640_dig_l_mix, ARRAY_SIZE(rt5640_dig_l_mix)),
+	SND_SOC_DAPM_MIXER("DIG MIXR", SND_SOC_NOPM, 0, 0,
+		rt5640_dig_r_mix, ARRAY_SIZE(rt5640_dig_r_mix)),
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM,
+			0, 0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM,
+			0, 0),
+	SND_SOC_DAPM_SUPPLY("DAC L1 Power", RT5640_PWR_DIG1,
+		RT5640_PWR_DAC_L1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC R1 Power", RT5640_PWR_DIG1,
+		RT5640_PWR_DAC_R1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5640_PWR_DIG1,
+		RT5640_PWR_DAC_L2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5640_PWR_DIG1,
+		RT5640_PWR_DAC_R2_BIT, 0, NULL, 0),
+	/* SPK/OUT Mixer */
+	SND_SOC_DAPM_MIXER("SPK MIXL", RT5640_PWR_MIXER, RT5640_PWR_SM_L_BIT,
+		0, rt5640_spk_l_mix, ARRAY_SIZE(rt5640_spk_l_mix)),
+	SND_SOC_DAPM_MIXER("SPK MIXR", RT5640_PWR_MIXER, RT5640_PWR_SM_R_BIT,
+		0, rt5640_spk_r_mix, ARRAY_SIZE(rt5640_spk_r_mix)),
+	/* Ouput Volume */
+	SND_SOC_DAPM_PGA("SPKVOL L", RT5640_PWR_VOL,
+		RT5640_PWR_SV_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SPKVOL R", RT5640_PWR_VOL,
+		RT5640_PWR_SV_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OUTVOL L", RT5640_PWR_VOL,
+		RT5640_PWR_OV_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OUTVOL R", RT5640_PWR_VOL,
+		RT5640_PWR_OV_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HPOVOL L", RT5640_PWR_VOL,
+		RT5640_PWR_HV_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HPOVOL R", RT5640_PWR_VOL,
+		RT5640_PWR_HV_R_BIT, 0, NULL, 0),
+	/* SPO/HPO/LOUT/Mono Mixer */
+	SND_SOC_DAPM_MIXER("SPOL MIX", SND_SOC_NOPM, 0,
+		0, rt5640_spo_l_mix, ARRAY_SIZE(rt5640_spo_l_mix)),
+	SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0,
+		0, rt5640_spo_r_mix, ARRAY_SIZE(rt5640_spo_r_mix)),
+	SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0,
+		rt5640_lout_mix, ARRAY_SIZE(rt5640_lout_mix)),
+	SND_SOC_DAPM_SUPPLY_S("Improve HP Amp Drv", 1, SND_SOC_NOPM,
+		0, 0, rt5640_hp_power_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0,
+		rt5640_hp_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0,
+		rt5640_lout_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("HP L Amp", RT5640_PWR_ANLG1,
+		RT5640_PWR_HP_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HP R Amp", RT5640_PWR_ANLG1,
+		RT5640_PWR_HP_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Improve SPK Amp Drv", RT5640_PWR_DIG1,
+		RT5640_PWR_CLS_D_BIT, 0, NULL, 0),
+
+	/* Output Switch */
+	SND_SOC_DAPM_SWITCH("Speaker L Playback", SND_SOC_NOPM, 0, 0,
+			&spk_l_enable_control),
+	SND_SOC_DAPM_SWITCH("Speaker R Playback", SND_SOC_NOPM, 0, 0,
+			&spk_r_enable_control),
+	SND_SOC_DAPM_SWITCH("HP L Playback", SND_SOC_NOPM, 0, 0,
+			&hp_l_enable_control),
+	SND_SOC_DAPM_SWITCH("HP R Playback", SND_SOC_NOPM, 0, 0,
+			&hp_r_enable_control),
+	SND_SOC_DAPM_POST("HP Post", rt5640_hp_post_event),
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("SPOLP"),
+	SND_SOC_DAPM_OUTPUT("SPOLN"),
+	SND_SOC_DAPM_OUTPUT("SPORP"),
+	SND_SOC_DAPM_OUTPUT("SPORN"),
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+	SND_SOC_DAPM_OUTPUT("LOUTL"),
+	SND_SOC_DAPM_OUTPUT("LOUTR"),
+};
+
+static const struct snd_soc_dapm_widget rt5640_specific_dapm_widgets[] = {
+	/* Audio DSP */
+	SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+	/* ANC */
+	SND_SOC_DAPM_PGA("ANC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* DAC2 channel Mux */
+	SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dac_l2_mux),
+	SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dac_r2_mux),
+
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5640_sto_dac_l_mix, ARRAY_SIZE(rt5640_sto_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5640_sto_dac_r_mix, ARRAY_SIZE(rt5640_sto_dac_r_mix)),
+
+	SND_SOC_DAPM_DAC("DAC R2", NULL, SND_SOC_NOPM, 0,
+		0),
+	SND_SOC_DAPM_DAC("DAC L2", NULL, SND_SOC_NOPM, 0,
+		0),
+
+	SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT,
+		0, rt5640_out_l_mix, ARRAY_SIZE(rt5640_out_l_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT,
+		0, rt5640_out_r_mix, ARRAY_SIZE(rt5640_out_r_mix)),
+
+	SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0,
+		rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
+	SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0,
+		rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
+
+	SND_SOC_DAPM_MIXER("Mono MIX", RT5640_PWR_ANLG1, RT5640_PWR_MM_BIT, 0,
+		rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)),
+	SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1,
+		RT5640_PWR_MA_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("MONOP"),
+	SND_SOC_DAPM_OUTPUT("MONON"),
+};
+
+static const struct snd_soc_dapm_widget rt5639_specific_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5639_sto_dac_l_mix, ARRAY_SIZE(rt5639_sto_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5639_sto_dac_r_mix, ARRAY_SIZE(rt5639_sto_dac_r_mix)),
+
+	SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT,
+		0, rt5639_out_l_mix, ARRAY_SIZE(rt5639_out_l_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT,
+		0, rt5639_out_r_mix, ARRAY_SIZE(rt5639_out_r_mix)),
+
+	SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0,
+		rt5639_hpo_mix, ARRAY_SIZE(rt5639_hpo_mix)),
+	SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0,
+		rt5639_hpo_mix, ARRAY_SIZE(rt5639_hpo_mix)),
+};
+
+static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
+	{ "I2S1", NULL, "Stereo Filter ASRC", is_using_asrc },
+	{ "I2S2", NULL, "I2S2 ASRC", is_using_asrc },
+	{ "I2S2", NULL, "I2S2 Filter ASRC", is_using_asrc },
+	{ "DMIC1", NULL, "DMIC1 ASRC", is_using_asrc },
+	{ "DMIC2", NULL, "DMIC2 ASRC", is_using_asrc },
+
+	{"IN1P", NULL, "LDO2"},
+	{"IN2P", NULL, "LDO2"},
+	{"IN3P", NULL, "LDO2"},
+
+	{"DMIC L1", NULL, "DMIC1"},
+	{"DMIC R1", NULL, "DMIC1"},
+	{"DMIC L2", NULL, "DMIC2"},
+	{"DMIC R2", NULL, "DMIC2"},
+
+	{"BST1", NULL, "IN1P"},
+	{"BST1", NULL, "IN1N"},
+	{"BST2", NULL, "IN2P"},
+	{"BST2", NULL, "IN2N"},
+	{"BST3", NULL, "IN3P"},
+	{"BST3", NULL, "IN3N"},
+
+	{"INL VOL", NULL, "IN2P"},
+	{"INR VOL", NULL, "IN2N"},
+
+	{"RECMIXL", "HPOL Switch", "HPOL"},
+	{"RECMIXL", "INL Switch", "INL VOL"},
+	{"RECMIXL", "BST3 Switch", "BST3"},
+	{"RECMIXL", "BST2 Switch", "BST2"},
+	{"RECMIXL", "BST1 Switch", "BST1"},
+	{"RECMIXL", "OUT MIXL Switch", "OUT MIXL"},
+
+	{"RECMIXR", "HPOR Switch", "HPOR"},
+	{"RECMIXR", "INR Switch", "INR VOL"},
+	{"RECMIXR", "BST3 Switch", "BST3"},
+	{"RECMIXR", "BST2 Switch", "BST2"},
+	{"RECMIXR", "BST1 Switch", "BST1"},
+	{"RECMIXR", "OUT MIXR Switch", "OUT MIXR"},
+
+	{"ADC L", NULL, "RECMIXL"},
+	{"ADC R", NULL, "RECMIXR"},
+
+	{"DMIC L1", NULL, "DMIC CLK"},
+	{"DMIC L1", NULL, "DMIC1 Power"},
+	{"DMIC R1", NULL, "DMIC CLK"},
+	{"DMIC R1", NULL, "DMIC1 Power"},
+	{"DMIC L2", NULL, "DMIC CLK"},
+	{"DMIC L2", NULL, "DMIC2 Power"},
+	{"DMIC R2", NULL, "DMIC CLK"},
+	{"DMIC R2", NULL, "DMIC2 Power"},
+
+	{"Stereo ADC L2 Mux", "DMIC1", "DMIC L1"},
+	{"Stereo ADC L2 Mux", "DMIC2", "DMIC L2"},
+	{"Stereo ADC L2 Mux", "DIG MIX", "DIG MIXL"},
+	{"Stereo ADC L1 Mux", "ADC", "ADC L"},
+	{"Stereo ADC L1 Mux", "DIG MIX", "DIG MIXL"},
+
+	{"Stereo ADC R1 Mux", "ADC", "ADC R"},
+	{"Stereo ADC R1 Mux", "DIG MIX", "DIG MIXR"},
+	{"Stereo ADC R2 Mux", "DMIC1", "DMIC R1"},
+	{"Stereo ADC R2 Mux", "DMIC2", "DMIC R2"},
+	{"Stereo ADC R2 Mux", "DIG MIX", "DIG MIXR"},
+
+	{"Mono ADC L2 Mux", "DMIC L1", "DMIC L1"},
+	{"Mono ADC L2 Mux", "DMIC L2", "DMIC L2"},
+	{"Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL"},
+	{"Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL"},
+	{"Mono ADC L1 Mux", "ADCL", "ADC L"},
+
+	{"Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR"},
+	{"Mono ADC R1 Mux", "ADCR", "ADC R"},
+	{"Mono ADC R2 Mux", "DMIC R1", "DMIC R1"},
+	{"Mono ADC R2 Mux", "DMIC R2", "DMIC R2"},
+	{"Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR"},
+
+	{"Stereo ADC MIXL", "ADC1 Switch", "Stereo ADC L1 Mux"},
+	{"Stereo ADC MIXL", "ADC2 Switch", "Stereo ADC L2 Mux"},
+	{"Stereo ADC MIXL", NULL, "Stereo Filter"},
+
+	{"Stereo ADC MIXR", "ADC1 Switch", "Stereo ADC R1 Mux"},
+	{"Stereo ADC MIXR", "ADC2 Switch", "Stereo ADC R2 Mux"},
+	{"Stereo ADC MIXR", NULL, "Stereo Filter"},
+
+	{"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"},
+	{"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"},
+	{"Mono ADC MIXL", NULL, "Mono Left Filter"},
+
+	{"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"},
+	{"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"},
+	{"Mono ADC MIXR", NULL, "Mono Right Filter"},
+
+	{"IF2 ADC L", NULL, "Mono ADC MIXL"},
+	{"IF2 ADC R", NULL, "Mono ADC MIXR"},
+	{"IF1 ADC L", NULL, "Stereo ADC MIXL"},
+	{"IF1 ADC R", NULL, "Stereo ADC MIXR"},
+
+	{"IF1 ADC", NULL, "I2S1"},
+	{"IF1 ADC", NULL, "IF1 ADC L"},
+	{"IF1 ADC", NULL, "IF1 ADC R"},
+	{"IF2 ADC", NULL, "I2S2"},
+	{"IF2 ADC", NULL, "IF2 ADC L"},
+	{"IF2 ADC", NULL, "IF2 ADC R"},
+
+	{"DAI1 TX Mux", "1:1|2:2", "IF1 ADC"},
+	{"DAI1 TX Mux", "1:2|2:1", "IF2 ADC"},
+	{"DAI1 IF1 Mux", "1:1|2:1", "IF1 ADC"},
+	{"DAI1 IF2 Mux", "1:1|2:1", "IF2 ADC"},
+	{"SDI1 TX Mux", "IF1", "DAI1 IF1 Mux"},
+	{"SDI1 TX Mux", "IF2", "DAI1 IF2 Mux"},
+
+	{"DAI2 TX Mux", "1:2|2:1", "IF1 ADC"},
+	{"DAI2 TX Mux", "1:1|2:2", "IF2 ADC"},
+	{"DAI2 IF1 Mux", "1:2|2:2", "IF1 ADC"},
+	{"DAI2 IF2 Mux", "1:2|2:2", "IF2 ADC"},
+	{"SDI2 TX Mux", "IF1", "DAI2 IF1 Mux"},
+	{"SDI2 TX Mux", "IF2", "DAI2 IF2 Mux"},
+
+	{"AIF1TX", NULL, "DAI1 TX Mux"},
+	{"AIF1TX", NULL, "SDI1 TX Mux"},
+	{"AIF2TX", NULL, "DAI2 TX Mux"},
+	{"AIF2TX", NULL, "SDI2 TX Mux"},
+
+	{"DAI1 RX Mux", "1:1|2:2", "AIF1RX"},
+	{"DAI1 RX Mux", "1:1|2:1", "AIF1RX"},
+	{"DAI1 RX Mux", "1:2|2:1", "AIF2RX"},
+	{"DAI1 RX Mux", "1:2|2:2", "AIF2RX"},
+
+	{"DAI2 RX Mux", "1:2|2:1", "AIF1RX"},
+	{"DAI2 RX Mux", "1:1|2:1", "AIF1RX"},
+	{"DAI2 RX Mux", "1:1|2:2", "AIF2RX"},
+	{"DAI2 RX Mux", "1:2|2:2", "AIF2RX"},
+
+	{"IF1 DAC", NULL, "I2S1"},
+	{"IF1 DAC", NULL, "DAI1 RX Mux"},
+	{"IF2 DAC", NULL, "I2S2"},
+	{"IF2 DAC", NULL, "DAI2 RX Mux"},
+
+	{"IF1 DAC L", NULL, "IF1 DAC"},
+	{"IF1 DAC R", NULL, "IF1 DAC"},
+	{"IF2 DAC L", NULL, "IF2 DAC"},
+	{"IF2 DAC R", NULL, "IF2 DAC"},
+
+	{"DAC MIXL", "Stereo ADC Switch", "Stereo ADC MIXL"},
+	{"DAC MIXL", "INF1 Switch", "IF1 DAC L"},
+	{"DAC MIXL", NULL, "DAC L1 Power"},
+	{"DAC MIXR", "Stereo ADC Switch", "Stereo ADC MIXR"},
+	{"DAC MIXR", "INF1 Switch", "IF1 DAC R"},
+	{"DAC MIXR", NULL, "DAC R1 Power"},
+
+	{"Stereo DAC MIXL", "DAC L1 Switch", "DAC MIXL"},
+	{"Stereo DAC MIXR", "DAC R1 Switch", "DAC MIXR"},
+
+	{"Mono DAC MIXL", "DAC L1 Switch", "DAC MIXL"},
+	{"Mono DAC MIXR", "DAC R1 Switch", "DAC MIXR"},
+
+	{"DIG MIXL", "DAC L1 Switch", "DAC MIXL"},
+	{"DIG MIXR", "DAC R1 Switch", "DAC MIXR"},
+
+	{"DAC L1", NULL, "Stereo DAC MIXL"},
+	{"DAC L1", NULL, "DAC L1 Power"},
+	{"DAC R1", NULL, "Stereo DAC MIXR"},
+	{"DAC R1", NULL, "DAC R1 Power"},
+
+	{"SPK MIXL", "REC MIXL Switch", "RECMIXL"},
+	{"SPK MIXL", "INL Switch", "INL VOL"},
+	{"SPK MIXL", "DAC L1 Switch", "DAC L1"},
+	{"SPK MIXL", "OUT MIXL Switch", "OUT MIXL"},
+	{"SPK MIXR", "REC MIXR Switch", "RECMIXR"},
+	{"SPK MIXR", "INR Switch", "INR VOL"},
+	{"SPK MIXR", "DAC R1 Switch", "DAC R1"},
+	{"SPK MIXR", "OUT MIXR Switch", "OUT MIXR"},
+
+	{"OUT MIXL", "BST1 Switch", "BST1"},
+	{"OUT MIXL", "INL Switch", "INL VOL"},
+	{"OUT MIXL", "REC MIXL Switch", "RECMIXL"},
+	{"OUT MIXL", "DAC L1 Switch", "DAC L1"},
+
+	{"OUT MIXR", "BST2 Switch", "BST2"},
+	{"OUT MIXR", "BST1 Switch", "BST1"},
+	{"OUT MIXR", "INR Switch", "INR VOL"},
+	{"OUT MIXR", "REC MIXR Switch", "RECMIXR"},
+	{"OUT MIXR", "DAC R1 Switch", "DAC R1"},
+
+	{"SPKVOL L", NULL, "SPK MIXL"},
+	{"SPKVOL R", NULL, "SPK MIXR"},
+	{"HPOVOL L", NULL, "OUT MIXL"},
+	{"HPOVOL R", NULL, "OUT MIXR"},
+	{"OUTVOL L", NULL, "OUT MIXL"},
+	{"OUTVOL R", NULL, "OUT MIXR"},
+
+	{"SPOL MIX", "DAC R1 Switch", "DAC R1"},
+	{"SPOL MIX", "DAC L1 Switch", "DAC L1"},
+	{"SPOL MIX", "SPKVOL R Switch", "SPKVOL R"},
+	{"SPOL MIX", "SPKVOL L Switch", "SPKVOL L"},
+	{"SPOL MIX", "BST1 Switch", "BST1"},
+	{"SPOR MIX", "DAC R1 Switch", "DAC R1"},
+	{"SPOR MIX", "SPKVOL R Switch", "SPKVOL R"},
+	{"SPOR MIX", "BST1 Switch", "BST1"},
+
+	{"HPO MIX L", "HPO MIX DAC1 Switch", "DAC L1"},
+	{"HPO MIX L", "HPO MIX HPVOL Switch", "HPOVOL L"},
+	{"HPO MIX L", NULL, "HP L Amp"},
+	{"HPO MIX R", "HPO MIX DAC1 Switch", "DAC R1"},
+	{"HPO MIX R", "HPO MIX HPVOL Switch", "HPOVOL R"},
+	{"HPO MIX R", NULL, "HP R Amp"},
+
+	{"LOUT MIX", "DAC L1 Switch", "DAC L1"},
+	{"LOUT MIX", "DAC R1 Switch", "DAC R1"},
+	{"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"},
+	{"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"},
+
+	{"HP Amp", NULL, "HPO MIX L"},
+	{"HP Amp", NULL, "HPO MIX R"},
+
+	{"Speaker L Playback", "Switch", "SPOL MIX"},
+	{"Speaker R Playback", "Switch", "SPOR MIX"},
+	{"SPOLP", NULL, "Speaker L Playback"},
+	{"SPOLN", NULL, "Speaker L Playback"},
+	{"SPORP", NULL, "Speaker R Playback"},
+	{"SPORN", NULL, "Speaker R Playback"},
+
+	{"SPOLP", NULL, "Improve SPK Amp Drv"},
+	{"SPOLN", NULL, "Improve SPK Amp Drv"},
+	{"SPORP", NULL, "Improve SPK Amp Drv"},
+	{"SPORN", NULL, "Improve SPK Amp Drv"},
+
+	{"HPOL", NULL, "Improve HP Amp Drv"},
+	{"HPOR", NULL, "Improve HP Amp Drv"},
+
+	{"HP L Playback", "Switch", "HP Amp"},
+	{"HP R Playback", "Switch", "HP Amp"},
+	{"HPOL", NULL, "HP L Playback"},
+	{"HPOR", NULL, "HP R Playback"},
+
+	{"LOUT amp", NULL, "LOUT MIX"},
+	{"LOUTL", NULL, "LOUT amp"},
+	{"LOUTR", NULL, "LOUT amp"},
+};
+
+static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = {
+	{"ANC", NULL, "Stereo ADC MIXL"},
+	{"ANC", NULL, "Stereo ADC MIXR"},
+
+	{"Audio DSP", NULL, "DAC MIXL"},
+	{"Audio DSP", NULL, "DAC MIXR"},
+
+	{"DAC L2 Mux", "IF2", "IF2 DAC L"},
+	{"DAC L2 Mux", "Base L/R", "Audio DSP"},
+	{"DAC L2 Mux", NULL, "DAC L2 Power"},
+	{"DAC R2 Mux", "IF2", "IF2 DAC R"},
+	{"DAC R2 Mux", NULL, "DAC R2 Power"},
+
+	{"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+	{"Stereo DAC MIXL", "ANC Switch", "ANC"},
+	{"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+	{"Stereo DAC MIXR", "ANC Switch", "ANC"},
+
+	{"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+	{"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"},
+
+	{"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+	{"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"},
+
+	{"DIG MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+	{"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+
+	{"DAC L2", NULL, "Mono DAC MIXL"},
+	{"DAC L2", NULL, "DAC L2 Power"},
+	{"DAC R2", NULL, "Mono DAC MIXR"},
+	{"DAC R2", NULL, "DAC R2 Power"},
+
+	{"SPK MIXL", "DAC L2 Switch", "DAC L2"},
+	{"SPK MIXR", "DAC R2 Switch", "DAC R2"},
+
+	{"OUT MIXL", "SPK MIXL Switch", "SPK MIXL"},
+	{"OUT MIXR", "SPK MIXR Switch", "SPK MIXR"},
+
+	{"OUT MIXL", "DAC R2 Switch", "DAC R2"},
+	{"OUT MIXL", "DAC L2 Switch", "DAC L2"},
+
+	{"OUT MIXR", "DAC L2 Switch", "DAC L2"},
+	{"OUT MIXR", "DAC R2 Switch", "DAC R2"},
+
+	{"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"},
+	{"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"},
+
+	{"Mono MIX", "DAC R2 Switch", "DAC R2"},
+	{"Mono MIX", "DAC L2 Switch", "DAC L2"},
+	{"Mono MIX", "OUTVOL R Switch", "OUTVOL R"},
+	{"Mono MIX", "OUTVOL L Switch", "OUTVOL L"},
+	{"Mono MIX", "BST1 Switch", "BST1"},
+
+	{"MONOP", NULL, "Mono MIX"},
+	{"MONON", NULL, "Mono MIX"},
+	{"MONOP", NULL, "Improve MONO Amp Drv"},
+};
+
+static const struct snd_soc_dapm_route rt5639_specific_dapm_routes[] = {
+	{"Stereo DAC MIXL", "DAC L2 Switch", "IF2 DAC L"},
+	{"Stereo DAC MIXR", "DAC R2 Switch", "IF2 DAC R"},
+
+	{"Mono DAC MIXL", "DAC L2 Switch", "IF2 DAC L"},
+	{"Mono DAC MIXL", "DAC R2 Switch", "IF2 DAC R"},
+
+	{"Mono DAC MIXR", "DAC R2 Switch", "IF2 DAC R"},
+	{"Mono DAC MIXR", "DAC L2 Switch", "IF2 DAC L"},
+
+	{"DIG MIXL", "DAC L2 Switch", "IF2 DAC L"},
+	{"DIG MIXR", "DAC R2 Switch", "IF2 DAC R"},
+
+	{"IF2 DAC L", NULL, "DAC L2 Power"},
+	{"IF2 DAC R", NULL, "DAC R2 Power"},
+};
+
+static int get_sdp_info(struct snd_soc_component *component, int dai_id)
+{
+	int ret = 0, val;
+
+	if (component == NULL)
+		return -EINVAL;
+
+	val = snd_soc_component_read32(component, RT5640_I2S1_SDP);
+	val = (val & RT5640_I2S_IF_MASK) >> RT5640_I2S_IF_SFT;
+	switch (dai_id) {
+	case RT5640_AIF1:
+		switch (val) {
+		case RT5640_IF_123:
+		case RT5640_IF_132:
+			ret |= RT5640_U_IF1;
+			break;
+		case RT5640_IF_113:
+			ret |= RT5640_U_IF1;
+			/* fall through */
+		case RT5640_IF_312:
+		case RT5640_IF_213:
+			ret |= RT5640_U_IF2;
+			break;
+		}
+		break;
+
+	case RT5640_AIF2:
+		switch (val) {
+		case RT5640_IF_231:
+		case RT5640_IF_213:
+			ret |= RT5640_U_IF1;
+			break;
+		case RT5640_IF_223:
+			ret |= RT5640_U_IF1;
+			/* fall through */
+		case RT5640_IF_123:
+		case RT5640_IF_321:
+			ret |= RT5640_U_IF2;
+			break;
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int rt5640_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0, val_clk, mask_clk;
+	int dai_sel, pre_div, bclk_ms, frame_size;
+
+	rt5640->lrck[dai->id] = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]);
+	if (pre_div < 0) {
+		dev_err(component->dev, "Unsupported clock setting %d for DAI %d\n",
+			rt5640->lrck[dai->id], dai->id);
+		return -EINVAL;
+	}
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
+		return frame_size;
+	}
+	if (frame_size > 32)
+		bclk_ms = 1;
+	else
+		bclk_ms = 0;
+	rt5640->bclk[dai->id] = rt5640->lrck[dai->id] * (32 << bclk_ms);
+
+	dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+		rt5640->bclk[dai->id], rt5640->lrck[dai->id]);
+	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+				bclk_ms, pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		val_len |= RT5640_I2S_DL_20;
+		break;
+	case 24:
+		val_len |= RT5640_I2S_DL_24;
+		break;
+	case 8:
+		val_len |= RT5640_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dai_sel = get_sdp_info(component, dai->id);
+	if (dai_sel < 0) {
+		dev_err(component->dev, "Failed to get sdp info: %d\n", dai_sel);
+		return -EINVAL;
+	}
+	if (dai_sel & RT5640_U_IF1) {
+		mask_clk = RT5640_I2S_BCLK_MS1_MASK | RT5640_I2S_PD1_MASK;
+		val_clk = bclk_ms << RT5640_I2S_BCLK_MS1_SFT |
+			pre_div << RT5640_I2S_PD1_SFT;
+		snd_soc_component_update_bits(component, RT5640_I2S1_SDP,
+			RT5640_I2S_DL_MASK, val_len);
+		snd_soc_component_update_bits(component, RT5640_ADDA_CLK1, mask_clk, val_clk);
+	}
+	if (dai_sel & RT5640_U_IF2) {
+		mask_clk = RT5640_I2S_BCLK_MS2_MASK | RT5640_I2S_PD2_MASK;
+		val_clk = bclk_ms << RT5640_I2S_BCLK_MS2_SFT |
+			pre_div << RT5640_I2S_PD2_SFT;
+		snd_soc_component_update_bits(component, RT5640_I2S2_SDP,
+			RT5640_I2S_DL_MASK, val_len);
+		snd_soc_component_update_bits(component, RT5640_ADDA_CLK1, mask_clk, val_clk);
+	}
+
+	return 0;
+}
+
+static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+	int dai_sel;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5640->master[dai->id] = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5640_I2S_MS_S;
+		rt5640->master[dai->id] = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5640_I2S_BP_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5640_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5640_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val  |= RT5640_I2S_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dai_sel = get_sdp_info(component, dai->id);
+	if (dai_sel < 0) {
+		dev_err(component->dev, "Failed to get sdp info: %d\n", dai_sel);
+		return -EINVAL;
+	}
+	if (dai_sel & RT5640_U_IF1) {
+		snd_soc_component_update_bits(component, RT5640_I2S1_SDP,
+			RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
+			RT5640_I2S_DF_MASK, reg_val);
+	}
+	if (dai_sel & RT5640_U_IF2) {
+		snd_soc_component_update_bits(component, RT5640_I2S2_SDP,
+			RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
+			RT5640_I2S_DF_MASK, reg_val);
+	}
+
+	return 0;
+}
+
+static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+	unsigned int pll_bit = 0;
+
+	if (freq == rt5640->sysclk && clk_id == rt5640->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5640_SCLK_S_MCLK:
+		reg_val |= RT5640_SCLK_SRC_MCLK;
+		break;
+	case RT5640_SCLK_S_PLL1:
+		reg_val |= RT5640_SCLK_SRC_PLL1;
+		pll_bit |= RT5640_PWR_PLL;
+		break;
+	case RT5640_SCLK_S_RCCLK:
+		reg_val |= RT5640_SCLK_SRC_RCCLK;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, RT5640_PWR_ANLG2,
+		RT5640_PWR_PLL, pll_bit);
+	snd_soc_component_update_bits(component, RT5640_GLB_CLK,
+		RT5640_SCLK_SRC_MASK, reg_val);
+	rt5640->sysclk = freq;
+	rt5640->sysclk_src = clk_id;
+
+	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+	return 0;
+}
+
+static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+			unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5640->pll_src && freq_in == rt5640->pll_in &&
+	    freq_out == rt5640->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt5640->pll_in = 0;
+		rt5640->pll_out = 0;
+		snd_soc_component_update_bits(component, RT5640_GLB_CLK,
+			RT5640_SCLK_SRC_MASK, RT5640_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5640_PLL1_S_MCLK:
+		snd_soc_component_update_bits(component, RT5640_GLB_CLK,
+			RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_MCLK);
+		break;
+	case RT5640_PLL1_S_BCLK1:
+		snd_soc_component_update_bits(component, RT5640_GLB_CLK,
+			RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_BCLK1);
+		break;
+	case RT5640_PLL1_S_BCLK2:
+		snd_soc_component_update_bits(component, RT5640_GLB_CLK,
+			RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_BCLK2);
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_component_write(component, RT5640_PLL_CTRL1,
+		pll_code.n_code << RT5640_PLL_N_SFT | pll_code.k_code);
+	snd_soc_component_write(component, RT5640_PLL_CTRL2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5640_PLL_M_SFT |
+		pll_code.m_bp << RT5640_PLL_M_BP_SFT);
+
+	rt5640->pll_in = freq_in;
+	rt5640->pll_out = freq_out;
+	rt5640->pll_src = source;
+
+	return 0;
+}
+
+static int rt5640_set_bias_level(struct snd_soc_component *component,
+			enum snd_soc_bias_level level)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/*
+		 * SND_SOC_BIAS_PREPARE is called while preparing for a
+		 * transition to ON or away from ON. If current bias_level
+		 * is SND_SOC_BIAS_ON, then it is preparing for a transition
+		 * away from ON. Disable the clock in that case, otherwise
+		 * enable it.
+		 */
+		if (IS_ERR(rt5640->mclk))
+			break;
+
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
+			clk_disable_unprepare(rt5640->mclk);
+		} else {
+			ret = clk_prepare_enable(rt5640->mclk);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (SND_SOC_BIAS_OFF == snd_soc_component_get_bias_level(component)) {
+			snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
+				RT5640_PWR_VREF1 | RT5640_PWR_MB |
+				RT5640_PWR_BG | RT5640_PWR_VREF2,
+				RT5640_PWR_VREF1 | RT5640_PWR_MB |
+				RT5640_PWR_BG | RT5640_PWR_VREF2);
+			usleep_range(10000, 15000);
+			snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
+				RT5640_PWR_FV1 | RT5640_PWR_FV2,
+				RT5640_PWR_FV1 | RT5640_PWR_FV2);
+			snd_soc_component_update_bits(component, RT5640_DUMMY1,
+						0x0301, 0x0301);
+			snd_soc_component_update_bits(component, RT5640_MICBIAS,
+						0x0030, 0x0030);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_write(component, RT5640_DEPOP_M1, 0x0004);
+		snd_soc_component_write(component, RT5640_DEPOP_M2, 0x1100);
+		snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x1, 0);
+		snd_soc_component_write(component, RT5640_PWR_DIG1, 0x0000);
+		snd_soc_component_write(component, RT5640_PWR_DIG2, 0x0000);
+		snd_soc_component_write(component, RT5640_PWR_VOL, 0x0000);
+		snd_soc_component_write(component, RT5640_PWR_MIXER, 0x0000);
+		snd_soc_component_write(component, RT5640_PWR_ANLG1, 0x0000);
+		snd_soc_component_write(component, RT5640_PWR_ANLG2, 0x0000);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int rt5640_dmic_enable(struct snd_soc_component *component,
+		       bool dmic1_data_pin, bool dmic2_data_pin)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+		RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL);
+
+	if (dmic1_data_pin) {
+		regmap_update_bits(rt5640->regmap, RT5640_DMIC,
+			RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3);
+		regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+			RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA);
+	}
+
+	if (dmic2_data_pin) {
+		regmap_update_bits(rt5640->regmap, RT5640_DMIC,
+			RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4);
+		regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+			RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
+
+int rt5640_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+	unsigned int asrc2_mask = 0;
+	unsigned int asrc2_value = 0;
+
+	switch (clk_src) {
+	case RT5640_CLK_SEL_SYS:
+	case RT5640_CLK_SEL_ASRC:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (!filter_mask)
+		return -EINVAL;
+
+	if (filter_mask & RT5640_DA_STEREO_FILTER) {
+		asrc2_mask |= RT5640_STO_DAC_M_MASK;
+		asrc2_value = (asrc2_value & ~RT5640_STO_DAC_M_MASK)
+			| (clk_src << RT5640_STO_DAC_M_SFT);
+	}
+
+	if (filter_mask & RT5640_DA_MONO_L_FILTER) {
+		asrc2_mask |= RT5640_MDA_L_M_MASK;
+		asrc2_value = (asrc2_value & ~RT5640_MDA_L_M_MASK)
+			| (clk_src << RT5640_MDA_L_M_SFT);
+	}
+
+	if (filter_mask & RT5640_DA_MONO_R_FILTER) {
+		asrc2_mask |= RT5640_MDA_R_M_MASK;
+		asrc2_value = (asrc2_value & ~RT5640_MDA_R_M_MASK)
+			| (clk_src << RT5640_MDA_R_M_SFT);
+	}
+
+	if (filter_mask & RT5640_AD_STEREO_FILTER) {
+		asrc2_mask |= RT5640_ADC_M_MASK;
+		asrc2_value = (asrc2_value & ~RT5640_ADC_M_MASK)
+			| (clk_src << RT5640_ADC_M_SFT);
+	}
+
+	if (filter_mask & RT5640_AD_MONO_L_FILTER) {
+		asrc2_mask |= RT5640_MAD_L_M_MASK;
+		asrc2_value = (asrc2_value & ~RT5640_MAD_L_M_MASK)
+			| (clk_src << RT5640_MAD_L_M_SFT);
+	}
+
+	if (filter_mask & RT5640_AD_MONO_R_FILTER)  {
+		asrc2_mask |= RT5640_MAD_R_M_MASK;
+		asrc2_value = (asrc2_value & ~RT5640_MAD_R_M_MASK)
+			| (clk_src << RT5640_MAD_R_M_SFT);
+	}
+
+	snd_soc_component_update_bits(component, RT5640_ASRC_2,
+		asrc2_mask, asrc2_value);
+
+	if (snd_soc_component_read32(component, RT5640_ASRC_2)) {
+		rt5640->asrc_en = true;
+		snd_soc_component_update_bits(component, RT5640_JD_CTRL, 0x3, 0x3);
+	} else {
+		rt5640->asrc_en = false;
+		snd_soc_component_update_bits(component, RT5640_JD_CTRL, 0x3, 0x0);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src);
+
+static void rt5640_enable_micbias1_for_ovcd(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_dapm_mutex_lock(dapm);
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2");
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1");
+	/* OVCD is unreliable when used with RCCLK as sysclk-source */
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "Platform Clock");
+	snd_soc_dapm_sync_unlocked(dapm);
+	snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_dapm_mutex_lock(dapm);
+	snd_soc_dapm_disable_pin_unlocked(dapm, "Platform Clock");
+	snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1");
+	snd_soc_dapm_disable_pin_unlocked(dapm, "LDO2");
+	snd_soc_dapm_sync_unlocked(dapm);
+	snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static void rt5640_enable_micbias1_ovcd_irq(struct snd_soc_component *component)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
+		RT5640_IRQ_MB1_OC_MASK, RT5640_IRQ_MB1_OC_NOR);
+	rt5640->ovcd_irq_enabled = true;
+}
+
+static void rt5640_disable_micbias1_ovcd_irq(struct snd_soc_component *component)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
+		RT5640_IRQ_MB1_OC_MASK, RT5640_IRQ_MB1_OC_BP);
+	rt5640->ovcd_irq_enabled = false;
+}
+
+static void rt5640_clear_micbias1_ovcd(struct snd_soc_component *component)
+{
+	snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
+		RT5640_MB1_OC_STATUS, 0);
+}
+
+static bool rt5640_micbias1_ovcd(struct snd_soc_component *component)
+{
+	int val;
+
+	val = snd_soc_component_read32(component, RT5640_IRQ_CTRL2);
+	dev_dbg(component->dev, "irq ctrl2 %#04x\n", val);
+
+	return (val & RT5640_MB1_OC_STATUS);
+}
+
+static bool rt5640_jack_inserted(struct snd_soc_component *component)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+	int val;
+
+	val = snd_soc_component_read32(component, RT5640_INT_IRQ_ST);
+	dev_dbg(component->dev, "irq status %#04x\n", val);
+
+	if (rt5640->jd_inverted)
+		return !(val & RT5640_JD_STATUS);
+	else
+		return (val & RT5640_JD_STATUS);
+}
+
+/* Jack detect and button-press timings */
+#define JACK_SETTLE_TIME	100 /* milli seconds */
+#define JACK_DETECT_COUNT	5
+#define JACK_DETECT_MAXCOUNT	20  /* Aprox. 2 seconds worth of tries */
+#define JACK_UNPLUG_TIME	80  /* milli seconds */
+#define BP_POLL_TIME		10  /* milli seconds */
+#define BP_POLL_MAXCOUNT	200 /* assume something is wrong after this */
+#define BP_THRESHOLD		3
+
+static void rt5640_start_button_press_work(struct snd_soc_component *component)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	rt5640->poll_count = 0;
+	rt5640->press_count = 0;
+	rt5640->release_count = 0;
+	rt5640->pressed = false;
+	rt5640->press_reported = false;
+	rt5640_clear_micbias1_ovcd(component);
+	schedule_delayed_work(&rt5640->bp_work, msecs_to_jiffies(BP_POLL_TIME));
+}
+
+static void rt5640_button_press_work(struct work_struct *work)
+{
+	struct rt5640_priv *rt5640 =
+		container_of(work, struct rt5640_priv, bp_work.work);
+	struct snd_soc_component *component = rt5640->component;
+
+	/* Check the jack was not removed underneath us */
+	if (!rt5640_jack_inserted(component))
+		return;
+
+	if (rt5640_micbias1_ovcd(component)) {
+		rt5640->release_count = 0;
+		rt5640->press_count++;
+		/* Remember till after JACK_UNPLUG_TIME wait */
+		if (rt5640->press_count >= BP_THRESHOLD)
+			rt5640->pressed = true;
+		rt5640_clear_micbias1_ovcd(component);
+	} else {
+		rt5640->press_count = 0;
+		rt5640->release_count++;
+	}
+
+	/*
+	 * The pins get temporarily shorted on jack unplug, so we poll for
+	 * at least JACK_UNPLUG_TIME milli-seconds before reporting a press.
+	 */
+	rt5640->poll_count++;
+	if (rt5640->poll_count < (JACK_UNPLUG_TIME / BP_POLL_TIME)) {
+		schedule_delayed_work(&rt5640->bp_work,
+				      msecs_to_jiffies(BP_POLL_TIME));
+		return;
+	}
+
+	if (rt5640->pressed && !rt5640->press_reported) {
+		dev_dbg(component->dev, "headset button press\n");
+		snd_soc_jack_report(rt5640->jack, SND_JACK_BTN_0,
+				    SND_JACK_BTN_0);
+		rt5640->press_reported = true;
+	}
+
+	if (rt5640->release_count >= BP_THRESHOLD) {
+		if (rt5640->press_reported) {
+			dev_dbg(component->dev, "headset button release\n");
+			snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0);
+		}
+		/* Re-enable OVCD IRQ to detect next press */
+		rt5640_enable_micbias1_ovcd_irq(component);
+		return; /* Stop polling */
+	}
+
+	schedule_delayed_work(&rt5640->bp_work, msecs_to_jiffies(BP_POLL_TIME));
+}
+
+static int rt5640_detect_headset(struct snd_soc_component *component)
+{
+	int i, headset_count = 0, headphone_count = 0;
+
+	/*
+	 * We get the insertion event before the jack is fully inserted at which
+	 * point the second ring on a TRRS connector may short the 2nd ring and
+	 * sleeve contacts, also the overcurrent detection is not entirely
+	 * reliable. So we try several times with a wait in between until we
+	 * detect the same type JACK_DETECT_COUNT times in a row.
+	 */
+	for (i = 0; i < JACK_DETECT_MAXCOUNT; i++) {
+		/* Clear any previous over-current status flag */
+		rt5640_clear_micbias1_ovcd(component);
+
+		msleep(JACK_SETTLE_TIME);
+
+		/* Check the jack is still connected before checking ovcd */
+		if (!rt5640_jack_inserted(component))
+			return 0;
+
+		if (rt5640_micbias1_ovcd(component)) {
+			/*
+			 * Over current detected, there is a short between the
+			 * 2nd ring contact and the ground, so a TRS connector
+			 * without a mic contact and thus plain headphones.
+			 */
+			dev_dbg(component->dev, "jack mic-gnd shorted\n");
+			headset_count = 0;
+			headphone_count++;
+			if (headphone_count == JACK_DETECT_COUNT)
+				return SND_JACK_HEADPHONE;
+		} else {
+			dev_dbg(component->dev, "jack mic-gnd open\n");
+			headphone_count = 0;
+			headset_count++;
+			if (headset_count == JACK_DETECT_COUNT)
+				return SND_JACK_HEADSET;
+		}
+	}
+
+	dev_err(component->dev, "Error detecting headset vs headphones, bad contact?, assuming headphones\n");
+	return SND_JACK_HEADPHONE;
+}
+
+static void rt5640_jack_work(struct work_struct *work)
+{
+	struct rt5640_priv *rt5640 =
+		container_of(work, struct rt5640_priv, jack_work);
+	struct snd_soc_component *component = rt5640->component;
+	int status;
+
+	if (!rt5640_jack_inserted(component)) {
+		/* Jack removed, or spurious IRQ? */
+		if (rt5640->jack->status & SND_JACK_HEADPHONE) {
+			if (rt5640->jack->status & SND_JACK_MICROPHONE) {
+				cancel_delayed_work_sync(&rt5640->bp_work);
+				rt5640_disable_micbias1_ovcd_irq(component);
+				rt5640_disable_micbias1_for_ovcd(component);
+			}
+			snd_soc_jack_report(rt5640->jack, 0,
+					    SND_JACK_HEADSET | SND_JACK_BTN_0);
+			dev_dbg(component->dev, "jack unplugged\n");
+		}
+	} else if (!(rt5640->jack->status & SND_JACK_HEADPHONE)) {
+		/* Jack inserted */
+		WARN_ON(rt5640->ovcd_irq_enabled);
+		rt5640_enable_micbias1_for_ovcd(component);
+		status = rt5640_detect_headset(component);
+		if (status == SND_JACK_HEADSET) {
+			/* Enable ovcd IRQ for button press detect. */
+			rt5640_enable_micbias1_ovcd_irq(component);
+		} else {
+			/* No more need for overcurrent detect. */
+			rt5640_disable_micbias1_for_ovcd(component);
+		}
+		dev_dbg(component->dev, "detect status %#02x\n", status);
+		snd_soc_jack_report(rt5640->jack, status, SND_JACK_HEADSET);
+	} else if (rt5640->ovcd_irq_enabled && rt5640_micbias1_ovcd(component)) {
+		dev_dbg(component->dev, "OVCD IRQ\n");
+
+		/*
+		 * The ovcd IRQ keeps firing while the button is pressed, so
+		 * we disable it and start polling the button until released.
+		 *
+		 * The disable will make the IRQ pin 0 again and since we get
+		 * IRQs on both edges (so as to detect both jack plugin and
+		 * unplug) this means we will immediately get another IRQ.
+		 * The ovcd_irq_enabled check above makes the 2ND IRQ a NOP.
+		 */
+		rt5640_disable_micbias1_ovcd_irq(component);
+		rt5640_start_button_press_work(component);
+
+		/*
+		 * If the jack-detect IRQ flag goes high (unplug) after our
+		 * above rt5640_jack_inserted() check and before we have
+		 * disabled the OVCD IRQ, the IRQ pin will stay high and as
+		 * we react to edges, we miss the unplug event -> recheck.
+		 */
+		queue_work(system_long_wq, &rt5640->jack_work);
+	}
+}
+
+static irqreturn_t rt5640_irq(int irq, void *data)
+{
+	struct rt5640_priv *rt5640 = data;
+
+	if (rt5640->jack)
+		queue_work(system_long_wq, &rt5640->jack_work);
+
+	return IRQ_HANDLED;
+}
+
+static void rt5640_cancel_work(void *data)
+{
+	struct rt5640_priv *rt5640 = data;
+
+	cancel_work_sync(&rt5640->jack_work);
+	cancel_delayed_work_sync(&rt5640->bp_work);
+}
+
+static void rt5640_enable_jack_detect(struct snd_soc_component *component,
+				      struct snd_soc_jack *jack)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	/* Select JD-source */
+	snd_soc_component_update_bits(component, RT5640_JD_CTRL,
+		RT5640_JD_MASK, rt5640->jd_src);
+
+	/* Selecting GPIO01 as an interrupt */
+	snd_soc_component_update_bits(component, RT5640_GPIO_CTRL1,
+		RT5640_GP1_PIN_MASK, RT5640_GP1_PIN_IRQ);
+
+	/* Set GPIO1 output */
+	snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3,
+		RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT);
+
+	/* Enabling jd2 in general control 1 */
+	snd_soc_component_write(component, RT5640_DUMMY1, 0x3f41);
+
+	/* Enabling jd2 in general control 2 */
+	snd_soc_component_write(component, RT5640_DUMMY2, 0x4001);
+
+	snd_soc_component_write(component, RT5640_PR_BASE + RT5640_BIAS_CUR4,
+		0xa800 | rt5640->ovcd_sf);
+
+	snd_soc_component_update_bits(component, RT5640_MICBIAS,
+		RT5640_MIC1_OVTH_MASK | RT5640_MIC1_OVCD_MASK,
+		rt5640->ovcd_th | RT5640_MIC1_OVCD_EN);
+
+	/*
+	 * The over-current-detect is only reliable in detecting the absence
+	 * of over-current, when the mic-contact in the jack is short-circuited,
+	 * the hardware periodically retries if it can apply the bias-current
+	 * leading to the ovcd status flip-flopping 1-0-1 with it being 0 about
+	 * 10% of the time, as we poll the ovcd status bit we might hit that
+	 * 10%, so we enable sticky mode and when checking OVCD we clear the
+	 * status, msleep() a bit and then check to get a reliable reading.
+	 */
+	snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
+		RT5640_MB1_OC_STKY_MASK, RT5640_MB1_OC_STKY_EN);
+
+	/*
+	 * All IRQs get or-ed together, so we need the jack IRQ to report 0
+	 * when a jack is inserted so that the OVCD IRQ then toggles the IRQ
+	 * pin 0/1 instead of it being stuck to 1. So we invert the JD polarity
+	 * on systems where the hardware does not already do this.
+	 */
+	if (rt5640->jd_inverted)
+		snd_soc_component_write(component, RT5640_IRQ_CTRL1,
+					RT5640_IRQ_JD_NOR);
+	else
+		snd_soc_component_write(component, RT5640_IRQ_CTRL1,
+					RT5640_IRQ_JD_NOR | RT5640_JD_P_INV);
+
+	rt5640->jack = jack;
+	if (rt5640->jack->status & SND_JACK_MICROPHONE) {
+		rt5640_enable_micbias1_for_ovcd(component);
+		rt5640_enable_micbias1_ovcd_irq(component);
+	}
+
+	enable_irq(rt5640->irq);
+	/* sync initial jack state */
+	queue_work(system_long_wq, &rt5640->jack_work);
+}
+
+static void rt5640_disable_jack_detect(struct snd_soc_component *component)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	disable_irq(rt5640->irq);
+	rt5640_cancel_work(rt5640);
+
+	if (rt5640->jack->status & SND_JACK_MICROPHONE) {
+		rt5640_disable_micbias1_ovcd_irq(component);
+		rt5640_disable_micbias1_for_ovcd(component);
+		snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0);
+	}
+
+	rt5640->jack = NULL;
+}
+
+static int rt5640_set_jack(struct snd_soc_component *component,
+			   struct snd_soc_jack *jack, void *data)
+{
+	if (jack)
+		rt5640_enable_jack_detect(component, jack);
+	else
+		rt5640_disable_jack_detect(component);
+
+	return 0;
+}
+
+static int rt5640_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+	u32 dmic1_data_pin = 0;
+	u32 dmic2_data_pin = 0;
+	bool dmic_en = false;
+	u32 val;
+
+	/* Check if MCLK provided */
+	rt5640->mclk = devm_clk_get(component->dev, "mclk");
+	if (PTR_ERR(rt5640->mclk) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	rt5640->component = component;
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+
+	snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x0301, 0x0301);
+	snd_soc_component_update_bits(component, RT5640_MICBIAS, 0x0030, 0x0030);
+	snd_soc_component_update_bits(component, RT5640_DSP_PATH2, 0xfc00, 0x0c00);
+
+	switch (snd_soc_component_read32(component, RT5640_RESET) & RT5640_ID_MASK) {
+	case RT5640_ID_5640:
+	case RT5640_ID_5642:
+		snd_soc_add_component_controls(component,
+			rt5640_specific_snd_controls,
+			ARRAY_SIZE(rt5640_specific_snd_controls));
+		snd_soc_dapm_new_controls(dapm,
+			rt5640_specific_dapm_widgets,
+			ARRAY_SIZE(rt5640_specific_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm,
+			rt5640_specific_dapm_routes,
+			ARRAY_SIZE(rt5640_specific_dapm_routes));
+		break;
+	case RT5640_ID_5639:
+		snd_soc_dapm_new_controls(dapm,
+			rt5639_specific_dapm_widgets,
+			ARRAY_SIZE(rt5639_specific_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm,
+			rt5639_specific_dapm_routes,
+			ARRAY_SIZE(rt5639_specific_dapm_routes));
+		break;
+	default:
+		dev_err(component->dev,
+			"The driver is for RT5639 RT5640 or RT5642 only\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Note on some platforms the platform code may need to add device-props
+	 * rather then relying only on properties set by the firmware.
+	 * Therefor the property parsing MUST be done here, rather then from
+	 * rt5640_i2c_probe(), so that the platform-code can attach extra
+	 * properties before calling snd_soc_register_card().
+	 */
+	if (device_property_read_bool(component->dev, "realtek,in1-differential"))
+		snd_soc_component_update_bits(component, RT5640_IN1_IN2,
+					      RT5640_IN_DF1, RT5640_IN_DF1);
+
+	if (device_property_read_bool(component->dev, "realtek,in2-differential"))
+		snd_soc_component_update_bits(component, RT5640_IN3_IN4,
+					      RT5640_IN_DF2, RT5640_IN_DF2);
+
+	if (device_property_read_bool(component->dev, "realtek,in3-differential"))
+		snd_soc_component_update_bits(component, RT5640_IN1_IN2,
+					      RT5640_IN_DF2, RT5640_IN_DF2);
+
+	if (device_property_read_u32(component->dev, "realtek,dmic1-data-pin",
+				     &val) == 0 && val) {
+		dmic1_data_pin = val - 1;
+		dmic_en = true;
+	}
+
+	if (device_property_read_u32(component->dev, "realtek,dmic2-data-pin",
+				     &val) == 0 && val) {
+		dmic2_data_pin = val - 1;
+		dmic_en = true;
+	}
+
+	if (dmic_en)
+		rt5640_dmic_enable(component, dmic1_data_pin, dmic2_data_pin);
+
+	if (device_property_read_u32(component->dev,
+				     "realtek,jack-detect-source", &val) == 0) {
+		if (val <= RT5640_JD_SRC_GPIO4)
+			rt5640->jd_src = val << RT5640_JD_SFT;
+		else
+			dev_warn(component->dev, "Warning: Invalid jack-detect-source value: %d, leaving jack-detect disabled\n",
+				 val);
+	}
+
+	if (!device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted"))
+		rt5640->jd_inverted = true;
+
+	/*
+	 * Testing on various boards has shown that good defaults for the OVCD
+	 * threshold and scale-factor are 2000µA and 0.75. For an effective
+	 * limit of 1500µA, this seems to be more reliable then 1500µA and 1.0.
+	 */
+	rt5640->ovcd_th = RT5640_MIC1_OVTH_2000UA;
+	rt5640->ovcd_sf = RT5640_MIC_OVCD_SF_0P75;
+
+	if (device_property_read_u32(component->dev,
+			"realtek,over-current-threshold-microamp", &val) == 0) {
+		switch (val) {
+		case 600:
+			rt5640->ovcd_th = RT5640_MIC1_OVTH_600UA;
+			break;
+		case 1500:
+			rt5640->ovcd_th = RT5640_MIC1_OVTH_1500UA;
+			break;
+		case 2000:
+			rt5640->ovcd_th = RT5640_MIC1_OVTH_2000UA;
+			break;
+		default:
+			dev_warn(component->dev, "Warning: Invalid over-current-threshold-microamp value: %d, defaulting to 2000uA\n",
+				 val);
+		}
+	}
+
+	if (device_property_read_u32(component->dev,
+			"realtek,over-current-scale-factor", &val) == 0) {
+		if (val <= RT5640_OVCD_SF_1P5)
+			rt5640->ovcd_sf = val << RT5640_MIC_OVCD_SF_SFT;
+		else
+			dev_warn(component->dev, "Warning: Invalid over-current-scale-factor value: %d, defaulting to 0.75\n",
+				 val);
+	}
+
+	return 0;
+}
+
+static void rt5640_remove(struct snd_soc_component *component)
+{
+	rt5640_reset(component);
+}
+
+#ifdef CONFIG_PM
+static int rt5640_suspend(struct snd_soc_component *component)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+	rt5640_reset(component);
+	regcache_cache_only(rt5640->regmap, true);
+	regcache_mark_dirty(rt5640->regmap);
+	if (gpio_is_valid(rt5640->ldo1_en))
+		gpio_set_value_cansleep(rt5640->ldo1_en, 0);
+
+	return 0;
+}
+
+static int rt5640_resume(struct snd_soc_component *component)
+{
+	struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+
+	if (gpio_is_valid(rt5640->ldo1_en)) {
+		gpio_set_value_cansleep(rt5640->ldo1_en, 1);
+		msleep(400);
+	}
+
+	regcache_cache_only(rt5640->regmap, false);
+	regcache_sync(rt5640->regmap);
+
+	return 0;
+}
+#else
+#define rt5640_suspend NULL
+#define rt5640_resume NULL
+#endif
+
+#define RT5640_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define RT5640_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5640_aif_dai_ops = {
+	.hw_params = rt5640_hw_params,
+	.set_fmt = rt5640_set_dai_fmt,
+	.set_sysclk = rt5640_set_dai_sysclk,
+	.set_pll = rt5640_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver rt5640_dai[] = {
+	{
+		.name = "rt5640-aif1",
+		.id = RT5640_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5640_STEREO_RATES,
+			.formats = RT5640_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5640_STEREO_RATES,
+			.formats = RT5640_FORMATS,
+		},
+		.ops = &rt5640_aif_dai_ops,
+	},
+	{
+		.name = "rt5640-aif2",
+		.id = RT5640_AIF2,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5640_STEREO_RATES,
+			.formats = RT5640_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5640_STEREO_RATES,
+			.formats = RT5640_FORMATS,
+		},
+		.ops = &rt5640_aif_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5640 = {
+	.probe			= rt5640_probe,
+	.remove			= rt5640_remove,
+	.suspend		= rt5640_suspend,
+	.resume			= rt5640_resume,
+	.set_bias_level		= rt5640_set_bias_level,
+	.set_jack		= rt5640_set_jack,
+	.controls		= rt5640_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5640_snd_controls),
+	.dapm_widgets		= rt5640_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5640_dapm_widgets),
+	.dapm_routes		= rt5640_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5640_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+
+};
+
+static const struct regmap_config rt5640_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.use_single_rw = true,
+
+	.max_register = RT5640_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5640_ranges) *
+					       RT5640_PR_SPACING),
+	.volatile_reg = rt5640_volatile_register,
+	.readable_reg = rt5640_readable_register,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5640_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5640_reg),
+	.ranges = rt5640_ranges,
+	.num_ranges = ARRAY_SIZE(rt5640_ranges),
+};
+
+static const struct i2c_device_id rt5640_i2c_id[] = {
+	{ "rt5640", 0 },
+	{ "rt5639", 0 },
+	{ "rt5642", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rt5640_of_match[] = {
+	{ .compatible = "realtek,rt5639", },
+	{ .compatible = "realtek,rt5640", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5640_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5640_acpi_match[] = {
+	{ "INT33CA", 0 },
+	{ "10EC3276", 0 },
+	{ "10EC5640", 0 },
+	{ "10EC5642", 0 },
+	{ "INTCCFFD", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
+#endif
+
+static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)
+{
+	rt5640->ldo1_en = of_get_named_gpio(np, "realtek,ldo1-en-gpios", 0);
+	/*
+	 * LDO1_EN is optional (it may be statically tied on the board).
+	 * -ENOENT means that the property doesn't exist, i.e. there is no
+	 * GPIO, so is not an error. Any other error code means the property
+	 * exists, but could not be parsed.
+	 */
+	if (!gpio_is_valid(rt5640->ldo1_en) &&
+			(rt5640->ldo1_en != -ENOENT))
+		return rt5640->ldo1_en;
+
+	return 0;
+}
+
+static int rt5640_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5640_priv *rt5640;
+	int ret;
+	unsigned int val;
+
+	rt5640 = devm_kzalloc(&i2c->dev,
+				sizeof(struct rt5640_priv),
+				GFP_KERNEL);
+	if (NULL == rt5640)
+		return -ENOMEM;
+	i2c_set_clientdata(i2c, rt5640);
+
+	if (i2c->dev.of_node) {
+		ret = rt5640_parse_dt(rt5640, i2c->dev.of_node);
+		if (ret)
+			return ret;
+	} else
+		rt5640->ldo1_en = -EINVAL;
+
+	rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap);
+	if (IS_ERR(rt5640->regmap)) {
+		ret = PTR_ERR(rt5640->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (gpio_is_valid(rt5640->ldo1_en)) {
+		ret = devm_gpio_request_one(&i2c->dev, rt5640->ldo1_en,
+					    GPIOF_OUT_INIT_HIGH,
+					    "RT5640 LDO1_EN");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request LDO1_EN %d: %d\n",
+				rt5640->ldo1_en, ret);
+			return ret;
+		}
+		msleep(400);
+	}
+
+	regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val);
+	if (val != RT5640_DEVICE_ID) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt5640/39\n", val);
+		return -ENODEV;
+	}
+
+	regmap_write(rt5640->regmap, RT5640_RESET, 0);
+
+	ret = regmap_register_patch(rt5640->regmap, init_list,
+				    ARRAY_SIZE(init_list));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	regmap_update_bits(rt5640->regmap, RT5640_DUMMY1,
+				RT5640_MCLK_DET, RT5640_MCLK_DET);
+
+	rt5640->hp_mute = 1;
+	rt5640->irq = i2c->irq;
+	INIT_DELAYED_WORK(&rt5640->bp_work, rt5640_button_press_work);
+	INIT_WORK(&rt5640->jack_work, rt5640_jack_work);
+
+	/* Make sure work is stopped on probe-error / remove */
+	ret = devm_add_action_or_reset(&i2c->dev, rt5640_cancel_work, rt5640);
+	if (ret)
+		return ret;
+
+	ret = devm_request_irq(&i2c->dev, rt5640->irq, rt5640_irq,
+			       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+			       | IRQF_ONESHOT, "rt5640", rt5640);
+	if (ret == 0) {
+		/* Gets re-enabled by rt5640_set_jack() */
+		disable_irq(rt5640->irq);
+	} else {
+		dev_warn(&i2c->dev, "Failed to reguest IRQ %d: %d\n",
+			 rt5640->irq, ret);
+		rt5640->irq = -ENXIO;
+	}
+
+	return devm_snd_soc_register_component(&i2c->dev,
+				      &soc_component_dev_rt5640,
+				      rt5640_dai, ARRAY_SIZE(rt5640_dai));
+}
+
+static struct i2c_driver rt5640_i2c_driver = {
+	.driver = {
+		.name = "rt5640",
+		.acpi_match_table = ACPI_PTR(rt5640_acpi_match),
+		.of_match_table = of_match_ptr(rt5640_of_match),
+	},
+	.probe = rt5640_i2c_probe,
+	.id_table = rt5640_i2c_id,
+};
+module_i2c_driver(rt5640_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5640/RT5639 driver");
+MODULE_AUTHOR("Johnny Hsu <johnnyhsu@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
new file mode 100644
index 0000000..e29e3e7
--- /dev/null
+++ b/sound/soc/codecs/rt5640.h
@@ -0,0 +1,2163 @@
+/*
+ * rt5640.h  --  RT5640 ALSA SoC audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ * Author: Johnny Hsu <johnnyhsu@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _RT5640_H
+#define _RT5640_H
+
+#include <linux/clk.h>
+#include <linux/workqueue.h>
+#include <dt-bindings/sound/rt5640.h>
+
+/* Info */
+#define RT5640_RESET				0x00
+#define RT5640_VENDOR_ID			0xfd
+#define RT5640_VENDOR_ID1			0xfe
+#define RT5640_VENDOR_ID2			0xff
+/*  I/O - Output */
+#define RT5640_SPK_VOL				0x01
+#define RT5640_HP_VOL				0x02
+#define RT5640_OUTPUT				0x03
+#define RT5640_MONO_OUT				0x04
+/* I/O - Input */
+#define RT5640_IN1_IN2				0x0d
+#define RT5640_IN3_IN4				0x0e
+#define RT5640_INL_INR_VOL			0x0f
+/* I/O - ADC/DAC/DMIC */
+#define RT5640_DAC1_DIG_VOL			0x19
+#define RT5640_DAC2_DIG_VOL			0x1a
+#define RT5640_DAC2_CTRL			0x1b
+#define RT5640_ADC_DIG_VOL			0x1c
+#define RT5640_ADC_DATA				0x1d
+#define RT5640_ADC_BST_VOL			0x1e
+/* Mixer - D-D */
+#define RT5640_STO_ADC_MIXER			0x27
+#define RT5640_MONO_ADC_MIXER			0x28
+#define RT5640_AD_DA_MIXER			0x29
+#define RT5640_STO_DAC_MIXER			0x2a
+#define RT5640_MONO_DAC_MIXER			0x2b
+#define RT5640_DIG_MIXER			0x2c
+#define RT5640_DSP_PATH1			0x2d
+#define RT5640_DSP_PATH2			0x2e
+#define RT5640_DIG_INF_DATA			0x2f
+/* Mixer - ADC */
+#define RT5640_REC_L1_MIXER			0x3b
+#define RT5640_REC_L2_MIXER			0x3c
+#define RT5640_REC_R1_MIXER			0x3d
+#define RT5640_REC_R2_MIXER			0x3e
+/* Mixer - DAC */
+#define RT5640_HPO_MIXER			0x45
+#define RT5640_SPK_L_MIXER			0x46
+#define RT5640_SPK_R_MIXER			0x47
+#define RT5640_SPO_L_MIXER			0x48
+#define RT5640_SPO_R_MIXER			0x49
+#define RT5640_SPO_CLSD_RATIO			0x4a
+#define RT5640_MONO_MIXER			0x4c
+#define RT5640_OUT_L1_MIXER			0x4d
+#define RT5640_OUT_L2_MIXER			0x4e
+#define RT5640_OUT_L3_MIXER			0x4f
+#define RT5640_OUT_R1_MIXER			0x50
+#define RT5640_OUT_R2_MIXER			0x51
+#define RT5640_OUT_R3_MIXER			0x52
+#define RT5640_LOUT_MIXER			0x53
+/* Power */
+#define RT5640_PWR_DIG1				0x61
+#define RT5640_PWR_DIG2				0x62
+#define RT5640_PWR_ANLG1			0x63
+#define RT5640_PWR_ANLG2			0x64
+#define RT5640_PWR_MIXER			0x65
+#define RT5640_PWR_VOL				0x66
+/* Private Register Control */
+#define RT5640_PRIV_INDEX			0x6a
+#define RT5640_PRIV_DATA			0x6c
+/* Format - ADC/DAC */
+#define RT5640_I2S1_SDP				0x70
+#define RT5640_I2S2_SDP				0x71
+#define RT5640_ADDA_CLK1			0x73
+#define RT5640_ADDA_CLK2			0x74
+#define RT5640_DMIC				0x75
+/* Function - Analog */
+#define RT5640_GLB_CLK				0x80
+#define RT5640_PLL_CTRL1			0x81
+#define RT5640_PLL_CTRL2			0x82
+#define RT5640_ASRC_1				0x83
+#define RT5640_ASRC_2				0x84
+#define RT5640_ASRC_3				0x85
+#define RT5640_ASRC_4				0x89
+#define RT5640_ASRC_5				0x8a
+#define RT5640_HP_OVCD				0x8b
+#define RT5640_CLS_D_OVCD			0x8c
+#define RT5640_CLS_D_OUT			0x8d
+#define RT5640_DEPOP_M1				0x8e
+#define RT5640_DEPOP_M2				0x8f
+#define RT5640_DEPOP_M3				0x90
+#define RT5640_CHARGE_PUMP			0x91
+#define RT5640_PV_DET_SPK_G			0x92
+#define RT5640_MICBIAS				0x93
+/* Function - Digital */
+#define RT5640_EQ_CTRL1				0xb0
+#define RT5640_EQ_CTRL2				0xb1
+#define RT5640_WIND_FILTER			0xb2
+#define RT5640_DRC_AGC_1			0xb4
+#define RT5640_DRC_AGC_2			0xb5
+#define RT5640_DRC_AGC_3			0xb6
+#define RT5640_SVOL_ZC				0xb7
+#define RT5640_ANC_CTRL1			0xb8
+#define RT5640_ANC_CTRL2			0xb9
+#define RT5640_ANC_CTRL3			0xba
+#define RT5640_JD_CTRL				0xbb
+#define RT5640_ANC_JD				0xbc
+#define RT5640_IRQ_CTRL1			0xbd
+#define RT5640_IRQ_CTRL2			0xbe
+#define RT5640_INT_IRQ_ST			0xbf
+#define RT5640_GPIO_CTRL1			0xc0
+#define RT5640_GPIO_CTRL2			0xc1
+#define RT5640_GPIO_CTRL3			0xc2
+#define RT5640_DSP_CTRL1			0xc4
+#define RT5640_DSP_CTRL2			0xc5
+#define RT5640_DSP_CTRL3			0xc6
+#define RT5640_DSP_CTRL4			0xc7
+#define RT5640_PGM_REG_ARR1			0xc8
+#define RT5640_PGM_REG_ARR2			0xc9
+#define RT5640_PGM_REG_ARR3			0xca
+#define RT5640_PGM_REG_ARR4			0xcb
+#define RT5640_PGM_REG_ARR5			0xcc
+#define RT5640_SCB_FUNC				0xcd
+#define RT5640_SCB_CTRL				0xce
+#define RT5640_BASE_BACK			0xcf
+#define RT5640_MP3_PLUS1			0xd0
+#define RT5640_MP3_PLUS2			0xd1
+#define RT5640_3D_HP				0xd2
+#define RT5640_ADJ_HPF				0xd3
+#define RT5640_HP_CALIB_AMP_DET			0xd6
+#define RT5640_HP_CALIB2			0xd7
+#define RT5640_SV_ZCD1				0xd9
+#define RT5640_SV_ZCD2				0xda
+/* Dummy Register */
+#define RT5640_DUMMY1				0xfa
+#define RT5640_DUMMY2				0xfb
+#define RT5640_DUMMY3				0xfc
+
+
+/* Index of Codec Private Register definition */
+#define RT5640_BIAS_CUR4			0x15
+#define RT5640_CHPUMP_INT_REG1			0x24
+#define RT5640_MAMP_INT_REG2			0x37
+#define RT5640_3D_SPK				0x63
+#define RT5640_WND_1				0x6c
+#define RT5640_WND_2				0x6d
+#define RT5640_WND_3				0x6e
+#define RT5640_WND_4				0x6f
+#define RT5640_WND_5				0x70
+#define RT5640_WND_8				0x73
+#define RT5640_DIP_SPK_INF			0x75
+#define RT5640_HP_DCC_INT1			0x77
+#define RT5640_EQ_BW_LOP			0xa0
+#define RT5640_EQ_GN_LOP			0xa1
+#define RT5640_EQ_FC_BP1			0xa2
+#define RT5640_EQ_BW_BP1			0xa3
+#define RT5640_EQ_GN_BP1			0xa4
+#define RT5640_EQ_FC_BP2			0xa5
+#define RT5640_EQ_BW_BP2			0xa6
+#define RT5640_EQ_GN_BP2			0xa7
+#define RT5640_EQ_FC_BP3			0xa8
+#define RT5640_EQ_BW_BP3			0xa9
+#define RT5640_EQ_GN_BP3			0xaa
+#define RT5640_EQ_FC_BP4			0xab
+#define RT5640_EQ_BW_BP4			0xac
+#define RT5640_EQ_GN_BP4			0xad
+#define RT5640_EQ_FC_HIP1			0xae
+#define RT5640_EQ_GN_HIP1			0xaf
+#define RT5640_EQ_FC_HIP2			0xb0
+#define RT5640_EQ_BW_HIP2			0xb1
+#define RT5640_EQ_GN_HIP2			0xb2
+#define RT5640_EQ_PRE_VOL			0xb3
+#define RT5640_EQ_PST_VOL			0xb4
+
+/* global definition */
+#define RT5640_L_MUTE				(0x1 << 15)
+#define RT5640_L_MUTE_SFT			15
+#define RT5640_VOL_L_MUTE			(0x1 << 14)
+#define RT5640_VOL_L_SFT			14
+#define RT5640_R_MUTE				(0x1 << 7)
+#define RT5640_R_MUTE_SFT			7
+#define RT5640_VOL_R_MUTE			(0x1 << 6)
+#define RT5640_VOL_R_SFT			6
+#define RT5640_L_VOL_MASK			(0x3f << 8)
+#define RT5640_L_VOL_SFT			8
+#define RT5640_R_VOL_MASK			(0x3f)
+#define RT5640_R_VOL_SFT			0
+
+/* SW Reset & Device ID (0x00) */
+#define RT5640_ID_MASK				(0x3 << 1)
+#define RT5640_ID_5639				(0x0 << 1)
+#define RT5640_ID_5640				(0x2 << 1)
+#define RT5640_ID_5642				(0x3 << 1)
+
+
+/* IN1 and IN2 Control (0x0d) */
+/* IN3 and IN4 Control (0x0e) */
+#define RT5640_BST_SFT1				12
+#define RT5640_BST_SFT2				8
+#define RT5640_IN_DF1				(0x1 << 7)
+#define RT5640_IN_SFT1				7
+#define RT5640_IN_DF2				(0x1 << 6)
+#define RT5640_IN_SFT2				6
+
+/* INL and INR Volume Control (0x0f) */
+#define RT5640_INL_SEL_MASK			(0x1 << 15)
+#define RT5640_INL_SEL_SFT			15
+#define RT5640_INL_SEL_IN4P			(0x0 << 15)
+#define RT5640_INL_SEL_MONOP			(0x1 << 15)
+#define RT5640_INL_VOL_MASK			(0x1f << 8)
+#define RT5640_INL_VOL_SFT			8
+#define RT5640_INR_SEL_MASK			(0x1 << 7)
+#define RT5640_INR_SEL_SFT			7
+#define RT5640_INR_SEL_IN4N			(0x0 << 7)
+#define RT5640_INR_SEL_MONON			(0x1 << 7)
+#define RT5640_INR_VOL_MASK			(0x1f)
+#define RT5640_INR_VOL_SFT			0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5640_DAC_L1_VOL_MASK			(0xff << 8)
+#define RT5640_DAC_L1_VOL_SFT			8
+#define RT5640_DAC_R1_VOL_MASK			(0xff)
+#define RT5640_DAC_R1_VOL_SFT			0
+
+/* DAC2 Digital Volume (0x1a) */
+#define RT5640_DAC_L2_VOL_MASK			(0xff << 8)
+#define RT5640_DAC_L2_VOL_SFT			8
+#define RT5640_DAC_R2_VOL_MASK			(0xff)
+#define RT5640_DAC_R2_VOL_SFT			0
+
+/* DAC2 Control (0x1b) */
+#define RT5640_M_DAC_L2_VOL			(0x1 << 13)
+#define RT5640_M_DAC_L2_VOL_SFT			13
+#define RT5640_M_DAC_R2_VOL			(0x1 << 12)
+#define RT5640_M_DAC_R2_VOL_SFT			12
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5640_ADC_L_VOL_MASK			(0x7f << 8)
+#define RT5640_ADC_L_VOL_SFT			8
+#define RT5640_ADC_R_VOL_MASK			(0x7f)
+#define RT5640_ADC_R_VOL_SFT			0
+
+/* Mono ADC Digital Volume Control (0x1d) */
+#define RT5640_MONO_ADC_L_VOL_MASK		(0x7f << 8)
+#define RT5640_MONO_ADC_L_VOL_SFT		8
+#define RT5640_MONO_ADC_R_VOL_MASK		(0x7f)
+#define RT5640_MONO_ADC_R_VOL_SFT		0
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5640_ADC_L_BST_MASK			(0x3 << 14)
+#define RT5640_ADC_L_BST_SFT			14
+#define RT5640_ADC_R_BST_MASK			(0x3 << 12)
+#define RT5640_ADC_R_BST_SFT			12
+#define RT5640_ADC_COMP_MASK			(0x3 << 10)
+#define RT5640_ADC_COMP_SFT			10
+
+/* Stereo ADC Mixer Control (0x27) */
+#define RT5640_M_ADC_L1				(0x1 << 14)
+#define RT5640_M_ADC_L1_SFT			14
+#define RT5640_M_ADC_L2				(0x1 << 13)
+#define RT5640_M_ADC_L2_SFT			13
+#define RT5640_ADC_1_SRC_MASK			(0x1 << 12)
+#define RT5640_ADC_1_SRC_SFT			12
+#define RT5640_ADC_1_SRC_ADC			(0x1 << 12)
+#define RT5640_ADC_1_SRC_DACMIX			(0x0 << 12)
+#define RT5640_ADC_2_SRC_MASK			(0x3 << 10)
+#define RT5640_ADC_2_SRC_SFT			10
+#define RT5640_ADC_2_SRC_DMIC1			(0x0 << 10)
+#define RT5640_ADC_2_SRC_DMIC2			(0x1 << 10)
+#define RT5640_ADC_2_SRC_DACMIX			(0x2 << 10)
+#define RT5640_M_ADC_R1				(0x1 << 6)
+#define RT5640_M_ADC_R1_SFT			6
+#define RT5640_M_ADC_R2				(0x1 << 5)
+#define RT5640_M_ADC_R2_SFT			5
+
+/* Mono ADC Mixer Control (0x28) */
+#define RT5640_M_MONO_ADC_L1			(0x1 << 14)
+#define RT5640_M_MONO_ADC_L1_SFT		14
+#define RT5640_M_MONO_ADC_L2			(0x1 << 13)
+#define RT5640_M_MONO_ADC_L2_SFT		13
+#define RT5640_MONO_ADC_L1_SRC_MASK		(0x1 << 12)
+#define RT5640_MONO_ADC_L1_SRC_SFT		12
+#define RT5640_MONO_ADC_L1_SRC_DACMIXL		(0x0 << 12)
+#define RT5640_MONO_ADC_L1_SRC_ADCL		(0x1 << 12)
+#define RT5640_MONO_ADC_L2_SRC_MASK		(0x3 << 10)
+#define RT5640_MONO_ADC_L2_SRC_SFT		10
+#define RT5640_MONO_ADC_L2_SRC_DMIC_L1		(0x0 << 10)
+#define RT5640_MONO_ADC_L2_SRC_DMIC_L2		(0x1 << 10)
+#define RT5640_MONO_ADC_L2_SRC_DACMIXL		(0x2 << 10)
+#define RT5640_M_MONO_ADC_R1			(0x1 << 6)
+#define RT5640_M_MONO_ADC_R1_SFT		6
+#define RT5640_M_MONO_ADC_R2			(0x1 << 5)
+#define RT5640_M_MONO_ADC_R2_SFT		5
+#define RT5640_MONO_ADC_R1_SRC_MASK		(0x1 << 4)
+#define RT5640_MONO_ADC_R1_SRC_SFT		4
+#define RT5640_MONO_ADC_R1_SRC_ADCR		(0x1 << 4)
+#define RT5640_MONO_ADC_R1_SRC_DACMIXR		(0x0 << 4)
+#define RT5640_MONO_ADC_R2_SRC_MASK		(0x3 << 2)
+#define RT5640_MONO_ADC_R2_SRC_SFT		2
+#define RT5640_MONO_ADC_R2_SRC_DMIC_R1		(0x0 << 2)
+#define RT5640_MONO_ADC_R2_SRC_DMIC_R2		(0x1 << 2)
+#define RT5640_MONO_ADC_R2_SRC_DACMIXR		(0x2 << 2)
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5640_M_ADCMIX_L			(0x1 << 15)
+#define RT5640_M_ADCMIX_L_SFT			15
+#define RT5640_M_IF1_DAC_L			(0x1 << 14)
+#define RT5640_M_IF1_DAC_L_SFT			14
+#define RT5640_M_ADCMIX_R			(0x1 << 7)
+#define RT5640_M_ADCMIX_R_SFT			7
+#define RT5640_M_IF1_DAC_R			(0x1 << 6)
+#define RT5640_M_IF1_DAC_R_SFT			6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5640_M_DAC_L1				(0x1 << 14)
+#define RT5640_M_DAC_L1_SFT			14
+#define RT5640_DAC_L1_STO_L_VOL_MASK		(0x1 << 13)
+#define RT5640_DAC_L1_STO_L_VOL_SFT		13
+#define RT5640_M_DAC_L2				(0x1 << 12)
+#define RT5640_M_DAC_L2_SFT			12
+#define RT5640_DAC_L2_STO_L_VOL_MASK		(0x1 << 11)
+#define RT5640_DAC_L2_STO_L_VOL_SFT		11
+#define RT5640_M_ANC_DAC_L			(0x1 << 10)
+#define RT5640_M_ANC_DAC_L_SFT			10
+#define RT5640_M_DAC_R1				(0x1 << 6)
+#define RT5640_M_DAC_R1_SFT			6
+#define RT5640_DAC_R1_STO_R_VOL_MASK		(0x1 << 5)
+#define RT5640_DAC_R1_STO_R_VOL_SFT		5
+#define RT5640_M_DAC_R2				(0x1 << 4)
+#define RT5640_M_DAC_R2_SFT			4
+#define RT5640_DAC_R2_STO_R_VOL_MASK		(0x1 << 3)
+#define RT5640_DAC_R2_STO_R_VOL_SFT		3
+#define RT5640_M_ANC_DAC_R			(0x1 << 2)
+#define RT5640_M_ANC_DAC_R_SFT		2
+
+/* Mono DAC Mixer Control (0x2b) */
+#define RT5640_M_DAC_L1_MONO_L			(0x1 << 14)
+#define RT5640_M_DAC_L1_MONO_L_SFT		14
+#define RT5640_DAC_L1_MONO_L_VOL_MASK		(0x1 << 13)
+#define RT5640_DAC_L1_MONO_L_VOL_SFT		13
+#define RT5640_M_DAC_L2_MONO_L			(0x1 << 12)
+#define RT5640_M_DAC_L2_MONO_L_SFT		12
+#define RT5640_DAC_L2_MONO_L_VOL_MASK		(0x1 << 11)
+#define RT5640_DAC_L2_MONO_L_VOL_SFT		11
+#define RT5640_M_DAC_R2_MONO_L			(0x1 << 10)
+#define RT5640_M_DAC_R2_MONO_L_SFT		10
+#define RT5640_DAC_R2_MONO_L_VOL_MASK		(0x1 << 9)
+#define RT5640_DAC_R2_MONO_L_VOL_SFT		9
+#define RT5640_M_DAC_R1_MONO_R			(0x1 << 6)
+#define RT5640_M_DAC_R1_MONO_R_SFT		6
+#define RT5640_DAC_R1_MONO_R_VOL_MASK		(0x1 << 5)
+#define RT5640_DAC_R1_MONO_R_VOL_SFT		5
+#define RT5640_M_DAC_R2_MONO_R			(0x1 << 4)
+#define RT5640_M_DAC_R2_MONO_R_SFT		4
+#define RT5640_DAC_R2_MONO_R_VOL_MASK		(0x1 << 3)
+#define RT5640_DAC_R2_MONO_R_VOL_SFT		3
+#define RT5640_M_DAC_L2_MONO_R			(0x1 << 2)
+#define RT5640_M_DAC_L2_MONO_R_SFT		2
+#define RT5640_DAC_L2_MONO_R_VOL_MASK		(0x1 << 1)
+#define RT5640_DAC_L2_MONO_R_VOL_SFT		1
+
+/* Digital Mixer Control (0x2c) */
+#define RT5640_M_STO_L_DAC_L			(0x1 << 15)
+#define RT5640_M_STO_L_DAC_L_SFT		15
+#define RT5640_STO_L_DAC_L_VOL_MASK		(0x1 << 14)
+#define RT5640_STO_L_DAC_L_VOL_SFT		14
+#define RT5640_M_DAC_L2_DAC_L			(0x1 << 13)
+#define RT5640_M_DAC_L2_DAC_L_SFT		13
+#define RT5640_DAC_L2_DAC_L_VOL_MASK		(0x1 << 12)
+#define RT5640_DAC_L2_DAC_L_VOL_SFT		12
+#define RT5640_M_STO_R_DAC_R			(0x1 << 11)
+#define RT5640_M_STO_R_DAC_R_SFT		11
+#define RT5640_STO_R_DAC_R_VOL_MASK		(0x1 << 10)
+#define RT5640_STO_R_DAC_R_VOL_SFT		10
+#define RT5640_M_DAC_R2_DAC_R			(0x1 << 9)
+#define RT5640_M_DAC_R2_DAC_R_SFT		9
+#define RT5640_DAC_R2_DAC_R_VOL_MASK		(0x1 << 8)
+#define RT5640_DAC_R2_DAC_R_VOL_SFT		8
+
+/* DSP Path Control 1 (0x2d) */
+#define RT5640_RXDP_SRC_MASK			(0x1 << 15)
+#define RT5640_RXDP_SRC_SFT			15
+#define RT5640_RXDP_SRC_NOR			(0x0 << 15)
+#define RT5640_RXDP_SRC_DIV3			(0x1 << 15)
+#define RT5640_TXDP_SRC_MASK			(0x1 << 14)
+#define RT5640_TXDP_SRC_SFT			14
+#define RT5640_TXDP_SRC_NOR			(0x0 << 14)
+#define RT5640_TXDP_SRC_DIV3			(0x1 << 14)
+
+/* DSP Path Control 2 (0x2e) */
+#define RT5640_DAC_L2_SEL_MASK			(0x3 << 14)
+#define RT5640_DAC_L2_SEL_SFT			14
+#define RT5640_DAC_L2_SEL_IF2			(0x0 << 14)
+#define RT5640_DAC_L2_SEL_IF3			(0x1 << 14)
+#define RT5640_DAC_L2_SEL_TXDC			(0x2 << 14)
+#define RT5640_DAC_L2_SEL_BASS			(0x3 << 14)
+#define RT5640_DAC_R2_SEL_MASK			(0x3 << 12)
+#define RT5640_DAC_R2_SEL_SFT			12
+#define RT5640_DAC_R2_SEL_IF2			(0x0 << 12)
+#define RT5640_DAC_R2_SEL_IF3			(0x1 << 12)
+#define RT5640_DAC_R2_SEL_TXDC			(0x2 << 12)
+#define RT5640_IF2_ADC_L_SEL_MASK		(0x1 << 11)
+#define RT5640_IF2_ADC_L_SEL_SFT		11
+#define RT5640_IF2_ADC_L_SEL_TXDP		(0x0 << 11)
+#define RT5640_IF2_ADC_L_SEL_PASS		(0x1 << 11)
+#define RT5640_IF2_ADC_R_SEL_MASK		(0x1 << 10)
+#define RT5640_IF2_ADC_R_SEL_SFT		10
+#define RT5640_IF2_ADC_R_SEL_TXDP		(0x0 << 10)
+#define RT5640_IF2_ADC_R_SEL_PASS		(0x1 << 10)
+#define RT5640_RXDC_SEL_MASK			(0x3 << 8)
+#define RT5640_RXDC_SEL_SFT			8
+#define RT5640_RXDC_SEL_NOR			(0x0 << 8)
+#define RT5640_RXDC_SEL_L2R			(0x1 << 8)
+#define RT5640_RXDC_SEL_R2L			(0x2 << 8)
+#define RT5640_RXDC_SEL_SWAP			(0x3 << 8)
+#define RT5640_RXDP_SEL_MASK			(0x3 << 6)
+#define RT5640_RXDP_SEL_SFT			6
+#define RT5640_RXDP_SEL_NOR			(0x0 << 6)
+#define RT5640_RXDP_SEL_L2R			(0x1 << 6)
+#define RT5640_RXDP_SEL_R2L			(0x2 << 6)
+#define RT5640_RXDP_SEL_SWAP			(0x3 << 6)
+#define RT5640_TXDC_SEL_MASK			(0x3 << 4)
+#define RT5640_TXDC_SEL_SFT			4
+#define RT5640_TXDC_SEL_NOR			(0x0 << 4)
+#define RT5640_TXDC_SEL_L2R			(0x1 << 4)
+#define RT5640_TXDC_SEL_R2L			(0x2 << 4)
+#define RT5640_TXDC_SEL_SWAP			(0x3 << 4)
+#define RT5640_TXDP_SEL_MASK			(0x3 << 2)
+#define RT5640_TXDP_SEL_SFT			2
+#define RT5640_TXDP_SEL_NOR			(0x0 << 2)
+#define RT5640_TXDP_SEL_L2R			(0x1 << 2)
+#define RT5640_TXDP_SEL_R2L			(0x2 << 2)
+#define RT5640_TRXDP_SEL_SWAP			(0x3 << 2)
+
+/* Digital Interface Data Control (0x2f) */
+#define RT5640_IF1_DAC_SEL_MASK			(0x3 << 14)
+#define RT5640_IF1_DAC_SEL_SFT			14
+#define RT5640_IF1_DAC_SEL_NOR			(0x0 << 14)
+#define RT5640_IF1_DAC_SEL_SWAP			(0x1 << 14)
+#define RT5640_IF1_DAC_SEL_L2R			(0x2 << 14)
+#define RT5640_IF1_DAC_SEL_R2L			(0x3 << 14)
+#define RT5640_IF1_ADC_SEL_MASK			(0x3 << 12)
+#define RT5640_IF1_ADC_SEL_SFT			12
+#define RT5640_IF1_ADC_SEL_NOR			(0x0 << 12)
+#define RT5640_IF1_ADC_SEL_SWAP			(0x1 << 12)
+#define RT5640_IF1_ADC_SEL_L2R			(0x2 << 12)
+#define RT5640_IF1_ADC_SEL_R2L			(0x3 << 12)
+#define RT5640_IF2_DAC_SEL_MASK			(0x3 << 10)
+#define RT5640_IF2_DAC_SEL_SFT			10
+#define RT5640_IF2_DAC_SEL_NOR			(0x0 << 10)
+#define RT5640_IF2_DAC_SEL_SWAP			(0x1 << 10)
+#define RT5640_IF2_DAC_SEL_L2R			(0x2 << 10)
+#define RT5640_IF2_DAC_SEL_R2L			(0x3 << 10)
+#define RT5640_IF2_ADC_SEL_MASK			(0x3 << 8)
+#define RT5640_IF2_ADC_SEL_SFT			8
+#define RT5640_IF2_ADC_SEL_NOR			(0x0 << 8)
+#define RT5640_IF2_ADC_SEL_SWAP			(0x1 << 8)
+#define RT5640_IF2_ADC_SEL_L2R			(0x2 << 8)
+#define RT5640_IF2_ADC_SEL_R2L			(0x3 << 8)
+#define RT5640_IF3_DAC_SEL_MASK			(0x3 << 6)
+#define RT5640_IF3_DAC_SEL_SFT			6
+#define RT5640_IF3_DAC_SEL_NOR			(0x0 << 6)
+#define RT5640_IF3_DAC_SEL_SWAP			(0x1 << 6)
+#define RT5640_IF3_DAC_SEL_L2R			(0x2 << 6)
+#define RT5640_IF3_DAC_SEL_R2L			(0x3 << 6)
+#define RT5640_IF3_ADC_SEL_MASK			(0x3 << 4)
+#define RT5640_IF3_ADC_SEL_SFT			4
+#define RT5640_IF3_ADC_SEL_NOR			(0x0 << 4)
+#define RT5640_IF3_ADC_SEL_SWAP			(0x1 << 4)
+#define RT5640_IF3_ADC_SEL_L2R			(0x2 << 4)
+#define RT5640_IF3_ADC_SEL_R2L			(0x3 << 4)
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5640_G_HP_L_RM_L_MASK			(0x7 << 13)
+#define RT5640_G_HP_L_RM_L_SFT			13
+#define RT5640_G_IN_L_RM_L_MASK			(0x7 << 10)
+#define RT5640_G_IN_L_RM_L_SFT			10
+#define RT5640_G_BST4_RM_L_MASK			(0x7 << 7)
+#define RT5640_G_BST4_RM_L_SFT			7
+#define RT5640_G_BST3_RM_L_MASK			(0x7 << 4)
+#define RT5640_G_BST3_RM_L_SFT			4
+#define RT5640_G_BST2_RM_L_MASK			(0x7 << 1)
+#define RT5640_G_BST2_RM_L_SFT			1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5640_G_BST1_RM_L_MASK			(0x7 << 13)
+#define RT5640_G_BST1_RM_L_SFT			13
+#define RT5640_G_OM_L_RM_L_MASK			(0x7 << 10)
+#define RT5640_G_OM_L_RM_L_SFT			10
+#define RT5640_M_HP_L_RM_L			(0x1 << 6)
+#define RT5640_M_HP_L_RM_L_SFT			6
+#define RT5640_M_IN_L_RM_L			(0x1 << 5)
+#define RT5640_M_IN_L_RM_L_SFT			5
+#define RT5640_M_BST4_RM_L			(0x1 << 4)
+#define RT5640_M_BST4_RM_L_SFT			4
+#define RT5640_M_BST3_RM_L			(0x1 << 3)
+#define RT5640_M_BST3_RM_L_SFT			3
+#define RT5640_M_BST2_RM_L			(0x1 << 2)
+#define RT5640_M_BST2_RM_L_SFT			2
+#define RT5640_M_BST1_RM_L			(0x1 << 1)
+#define RT5640_M_BST1_RM_L_SFT			1
+#define RT5640_M_OM_L_RM_L			(0x1)
+#define RT5640_M_OM_L_RM_L_SFT			0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5640_G_HP_R_RM_R_MASK			(0x7 << 13)
+#define RT5640_G_HP_R_RM_R_SFT			13
+#define RT5640_G_IN_R_RM_R_MASK			(0x7 << 10)
+#define RT5640_G_IN_R_RM_R_SFT			10
+#define RT5640_G_BST4_RM_R_MASK			(0x7 << 7)
+#define RT5640_G_BST4_RM_R_SFT			7
+#define RT5640_G_BST3_RM_R_MASK			(0x7 << 4)
+#define RT5640_G_BST3_RM_R_SFT			4
+#define RT5640_G_BST2_RM_R_MASK			(0x7 << 1)
+#define RT5640_G_BST2_RM_R_SFT			1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5640_G_BST1_RM_R_MASK			(0x7 << 13)
+#define RT5640_G_BST1_RM_R_SFT			13
+#define RT5640_G_OM_R_RM_R_MASK			(0x7 << 10)
+#define RT5640_G_OM_R_RM_R_SFT			10
+#define RT5640_M_HP_R_RM_R			(0x1 << 6)
+#define RT5640_M_HP_R_RM_R_SFT			6
+#define RT5640_M_IN_R_RM_R			(0x1 << 5)
+#define RT5640_M_IN_R_RM_R_SFT			5
+#define RT5640_M_BST4_RM_R			(0x1 << 4)
+#define RT5640_M_BST4_RM_R_SFT			4
+#define RT5640_M_BST3_RM_R			(0x1 << 3)
+#define RT5640_M_BST3_RM_R_SFT			3
+#define RT5640_M_BST2_RM_R			(0x1 << 2)
+#define RT5640_M_BST2_RM_R_SFT			2
+#define RT5640_M_BST1_RM_R			(0x1 << 1)
+#define RT5640_M_BST1_RM_R_SFT			1
+#define RT5640_M_OM_R_RM_R			(0x1)
+#define RT5640_M_OM_R_RM_R_SFT			0
+
+/* HPMIX Control (0x45) */
+#define RT5640_M_DAC2_HM			(0x1 << 15)
+#define RT5640_M_DAC2_HM_SFT			15
+#define RT5640_M_DAC1_HM			(0x1 << 14)
+#define RT5640_M_DAC1_HM_SFT			14
+#define RT5640_M_HPVOL_HM			(0x1 << 13)
+#define RT5640_M_HPVOL_HM_SFT			13
+#define RT5640_G_HPOMIX_MASK			(0x1 << 12)
+#define RT5640_G_HPOMIX_SFT			12
+
+/* SPK Left Mixer Control (0x46) */
+#define RT5640_G_RM_L_SM_L_MASK			(0x3 << 14)
+#define RT5640_G_RM_L_SM_L_SFT			14
+#define RT5640_G_IN_L_SM_L_MASK			(0x3 << 12)
+#define RT5640_G_IN_L_SM_L_SFT			12
+#define RT5640_G_DAC_L1_SM_L_MASK		(0x3 << 10)
+#define RT5640_G_DAC_L1_SM_L_SFT		10
+#define RT5640_G_DAC_L2_SM_L_MASK		(0x3 << 8)
+#define RT5640_G_DAC_L2_SM_L_SFT		8
+#define RT5640_G_OM_L_SM_L_MASK			(0x3 << 6)
+#define RT5640_G_OM_L_SM_L_SFT			6
+#define RT5640_M_RM_L_SM_L			(0x1 << 5)
+#define RT5640_M_RM_L_SM_L_SFT			5
+#define RT5640_M_IN_L_SM_L			(0x1 << 4)
+#define RT5640_M_IN_L_SM_L_SFT			4
+#define RT5640_M_DAC_L1_SM_L			(0x1 << 3)
+#define RT5640_M_DAC_L1_SM_L_SFT		3
+#define RT5640_M_DAC_L2_SM_L			(0x1 << 2)
+#define RT5640_M_DAC_L2_SM_L_SFT		2
+#define RT5640_M_OM_L_SM_L			(0x1 << 1)
+#define RT5640_M_OM_L_SM_L_SFT		1
+
+/* SPK Right Mixer Control (0x47) */
+#define RT5640_G_RM_R_SM_R_MASK			(0x3 << 14)
+#define RT5640_G_RM_R_SM_R_SFT			14
+#define RT5640_G_IN_R_SM_R_MASK			(0x3 << 12)
+#define RT5640_G_IN_R_SM_R_SFT			12
+#define RT5640_G_DAC_R1_SM_R_MASK		(0x3 << 10)
+#define RT5640_G_DAC_R1_SM_R_SFT		10
+#define RT5640_G_DAC_R2_SM_R_MASK		(0x3 << 8)
+#define RT5640_G_DAC_R2_SM_R_SFT		8
+#define RT5640_G_OM_R_SM_R_MASK			(0x3 << 6)
+#define RT5640_G_OM_R_SM_R_SFT			6
+#define RT5640_M_RM_R_SM_R			(0x1 << 5)
+#define RT5640_M_RM_R_SM_R_SFT			5
+#define RT5640_M_IN_R_SM_R			(0x1 << 4)
+#define RT5640_M_IN_R_SM_R_SFT			4
+#define RT5640_M_DAC_R1_SM_R			(0x1 << 3)
+#define RT5640_M_DAC_R1_SM_R_SFT		3
+#define RT5640_M_DAC_R2_SM_R			(0x1 << 2)
+#define RT5640_M_DAC_R2_SM_R_SFT		2
+#define RT5640_M_OM_R_SM_R			(0x1 << 1)
+#define RT5640_M_OM_R_SM_R_SFT			1
+
+/* SPOLMIX Control (0x48) */
+#define RT5640_M_DAC_R1_SPM_L			(0x1 << 15)
+#define RT5640_M_DAC_R1_SPM_L_SFT		15
+#define RT5640_M_DAC_L1_SPM_L			(0x1 << 14)
+#define RT5640_M_DAC_L1_SPM_L_SFT		14
+#define RT5640_M_SV_R_SPM_L			(0x1 << 13)
+#define RT5640_M_SV_R_SPM_L_SFT			13
+#define RT5640_M_SV_L_SPM_L			(0x1 << 12)
+#define RT5640_M_SV_L_SPM_L_SFT			12
+#define RT5640_M_BST1_SPM_L			(0x1 << 11)
+#define RT5640_M_BST1_SPM_L_SFT			11
+
+/* SPORMIX Control (0x49) */
+#define RT5640_M_DAC_R1_SPM_R			(0x1 << 13)
+#define RT5640_M_DAC_R1_SPM_R_SFT		13
+#define RT5640_M_SV_R_SPM_R			(0x1 << 12)
+#define RT5640_M_SV_R_SPM_R_SFT			12
+#define RT5640_M_BST1_SPM_R			(0x1 << 11)
+#define RT5640_M_BST1_SPM_R_SFT			11
+
+/* SPOLMIX / SPORMIX Ratio Control (0x4a) */
+#define RT5640_SPO_CLSD_RATIO_MASK		(0x7)
+#define RT5640_SPO_CLSD_RATIO_SFT		0
+
+/* Mono Output Mixer Control (0x4c) */
+#define RT5640_M_DAC_R2_MM			(0x1 << 15)
+#define RT5640_M_DAC_R2_MM_SFT			15
+#define RT5640_M_DAC_L2_MM			(0x1 << 14)
+#define RT5640_M_DAC_L2_MM_SFT			14
+#define RT5640_M_OV_R_MM			(0x1 << 13)
+#define RT5640_M_OV_R_MM_SFT			13
+#define RT5640_M_OV_L_MM			(0x1 << 12)
+#define RT5640_M_OV_L_MM_SFT			12
+#define RT5640_M_BST1_MM			(0x1 << 11)
+#define RT5640_M_BST1_MM_SFT			11
+#define RT5640_G_MONOMIX_MASK			(0x1 << 10)
+#define RT5640_G_MONOMIX_SFT			10
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5640_G_BST3_OM_L_MASK			(0x7 << 13)
+#define RT5640_G_BST3_OM_L_SFT			13
+#define RT5640_G_BST2_OM_L_MASK			(0x7 << 10)
+#define RT5640_G_BST2_OM_L_SFT			10
+#define RT5640_G_BST1_OM_L_MASK			(0x7 << 7)
+#define RT5640_G_BST1_OM_L_SFT			7
+#define RT5640_G_IN_L_OM_L_MASK			(0x7 << 4)
+#define RT5640_G_IN_L_OM_L_SFT			4
+#define RT5640_G_RM_L_OM_L_MASK			(0x7 << 1)
+#define RT5640_G_RM_L_OM_L_SFT			1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5640_G_DAC_R2_OM_L_MASK		(0x7 << 13)
+#define RT5640_G_DAC_R2_OM_L_SFT		13
+#define RT5640_G_DAC_L2_OM_L_MASK		(0x7 << 10)
+#define RT5640_G_DAC_L2_OM_L_SFT		10
+#define RT5640_G_DAC_L1_OM_L_MASK		(0x7 << 7)
+#define RT5640_G_DAC_L1_OM_L_SFT		7
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5640_M_SM_L_OM_L			(0x1 << 8)
+#define RT5640_M_SM_L_OM_L_SFT			8
+#define RT5640_M_BST3_OM_L			(0x1 << 7)
+#define RT5640_M_BST3_OM_L_SFT			7
+#define RT5640_M_BST2_OM_L			(0x1 << 6)
+#define RT5640_M_BST2_OM_L_SFT			6
+#define RT5640_M_BST1_OM_L			(0x1 << 5)
+#define RT5640_M_BST1_OM_L_SFT			5
+#define RT5640_M_IN_L_OM_L			(0x1 << 4)
+#define RT5640_M_IN_L_OM_L_SFT			4
+#define RT5640_M_RM_L_OM_L			(0x1 << 3)
+#define RT5640_M_RM_L_OM_L_SFT			3
+#define RT5640_M_DAC_R2_OM_L			(0x1 << 2)
+#define RT5640_M_DAC_R2_OM_L_SFT		2
+#define RT5640_M_DAC_L2_OM_L			(0x1 << 1)
+#define RT5640_M_DAC_L2_OM_L_SFT		1
+#define RT5640_M_DAC_L1_OM_L			(0x1)
+#define RT5640_M_DAC_L1_OM_L_SFT		0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5640_G_BST4_OM_R_MASK			(0x7 << 13)
+#define RT5640_G_BST4_OM_R_SFT			13
+#define RT5640_G_BST2_OM_R_MASK			(0x7 << 10)
+#define RT5640_G_BST2_OM_R_SFT			10
+#define RT5640_G_BST1_OM_R_MASK			(0x7 << 7)
+#define RT5640_G_BST1_OM_R_SFT			7
+#define RT5640_G_IN_R_OM_R_MASK			(0x7 << 4)
+#define RT5640_G_IN_R_OM_R_SFT			4
+#define RT5640_G_RM_R_OM_R_MASK			(0x7 << 1)
+#define RT5640_G_RM_R_OM_R_SFT			1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5640_G_DAC_L2_OM_R_MASK		(0x7 << 13)
+#define RT5640_G_DAC_L2_OM_R_SFT		13
+#define RT5640_G_DAC_R2_OM_R_MASK		(0x7 << 10)
+#define RT5640_G_DAC_R2_OM_R_SFT		10
+#define RT5640_G_DAC_R1_OM_R_MASK		(0x7 << 7)
+#define RT5640_G_DAC_R1_OM_R_SFT		7
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5640_M_SM_L_OM_R			(0x1 << 8)
+#define RT5640_M_SM_L_OM_R_SFT			8
+#define RT5640_M_BST4_OM_R			(0x1 << 7)
+#define RT5640_M_BST4_OM_R_SFT			7
+#define RT5640_M_BST2_OM_R			(0x1 << 6)
+#define RT5640_M_BST2_OM_R_SFT			6
+#define RT5640_M_BST1_OM_R			(0x1 << 5)
+#define RT5640_M_BST1_OM_R_SFT			5
+#define RT5640_M_IN_R_OM_R			(0x1 << 4)
+#define RT5640_M_IN_R_OM_R_SFT			4
+#define RT5640_M_RM_R_OM_R			(0x1 << 3)
+#define RT5640_M_RM_R_OM_R_SFT			3
+#define RT5640_M_DAC_L2_OM_R			(0x1 << 2)
+#define RT5640_M_DAC_L2_OM_R_SFT		2
+#define RT5640_M_DAC_R2_OM_R			(0x1 << 1)
+#define RT5640_M_DAC_R2_OM_R_SFT		1
+#define RT5640_M_DAC_R1_OM_R			(0x1)
+#define RT5640_M_DAC_R1_OM_R_SFT		0
+
+/* LOUT Mixer Control (0x53) */
+#define RT5640_M_DAC_L1_LM			(0x1 << 15)
+#define RT5640_M_DAC_L1_LM_SFT			15
+#define RT5640_M_DAC_R1_LM			(0x1 << 14)
+#define RT5640_M_DAC_R1_LM_SFT			14
+#define RT5640_M_OV_L_LM			(0x1 << 13)
+#define RT5640_M_OV_L_LM_SFT			13
+#define RT5640_M_OV_R_LM			(0x1 << 12)
+#define RT5640_M_OV_R_LM_SFT			12
+#define RT5640_G_LOUTMIX_MASK			(0x1 << 11)
+#define RT5640_G_LOUTMIX_SFT			11
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5640_PWR_I2S1				(0x1 << 15)
+#define RT5640_PWR_I2S1_BIT			15
+#define RT5640_PWR_I2S2				(0x1 << 14)
+#define RT5640_PWR_I2S2_BIT			14
+#define RT5640_PWR_DAC_L1			(0x1 << 12)
+#define RT5640_PWR_DAC_L1_BIT			12
+#define RT5640_PWR_DAC_R1			(0x1 << 11)
+#define RT5640_PWR_DAC_R1_BIT			11
+#define RT5640_PWR_DAC_L2			(0x1 << 7)
+#define RT5640_PWR_DAC_L2_BIT			7
+#define RT5640_PWR_DAC_R2			(0x1 << 6)
+#define RT5640_PWR_DAC_R2_BIT			6
+#define RT5640_PWR_ADC_L			(0x1 << 2)
+#define RT5640_PWR_ADC_L_BIT			2
+#define RT5640_PWR_ADC_R			(0x1 << 1)
+#define RT5640_PWR_ADC_R_BIT			1
+#define RT5640_PWR_CLS_D			(0x1)
+#define RT5640_PWR_CLS_D_BIT			0
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5640_PWR_ADC_SF			(0x1 << 15)
+#define RT5640_PWR_ADC_SF_BIT			15
+#define RT5640_PWR_ADC_MF_L			(0x1 << 14)
+#define RT5640_PWR_ADC_MF_L_BIT			14
+#define RT5640_PWR_ADC_MF_R			(0x1 << 13)
+#define RT5640_PWR_ADC_MF_R_BIT			13
+#define RT5640_PWR_I2S_DSP			(0x1 << 12)
+#define RT5640_PWR_I2S_DSP_BIT			12
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5640_PWR_VREF1			(0x1 << 15)
+#define RT5640_PWR_VREF1_BIT			15
+#define RT5640_PWR_FV1				(0x1 << 14)
+#define RT5640_PWR_FV1_BIT			14
+#define RT5640_PWR_MB				(0x1 << 13)
+#define RT5640_PWR_MB_BIT			13
+#define RT5640_PWR_LM				(0x1 << 12)
+#define RT5640_PWR_LM_BIT			12
+#define RT5640_PWR_BG				(0x1 << 11)
+#define RT5640_PWR_BG_BIT			11
+#define RT5640_PWR_MM				(0x1 << 10)
+#define RT5640_PWR_MM_BIT			10
+#define RT5640_PWR_MA				(0x1 << 8)
+#define RT5640_PWR_MA_BIT			8
+#define RT5640_PWR_HP_L				(0x1 << 7)
+#define RT5640_PWR_HP_L_BIT			7
+#define RT5640_PWR_HP_R				(0x1 << 6)
+#define RT5640_PWR_HP_R_BIT			6
+#define RT5640_PWR_HA				(0x1 << 5)
+#define RT5640_PWR_HA_BIT			5
+#define RT5640_PWR_VREF2			(0x1 << 4)
+#define RT5640_PWR_VREF2_BIT			4
+#define RT5640_PWR_FV2				(0x1 << 3)
+#define RT5640_PWR_FV2_BIT			3
+#define RT5640_PWR_LDO2				(0x1 << 2)
+#define RT5640_PWR_LDO2_BIT			2
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5640_PWR_BST1				(0x1 << 15)
+#define RT5640_PWR_BST1_BIT			15
+#define RT5640_PWR_BST2				(0x1 << 14)
+#define RT5640_PWR_BST2_BIT			14
+#define RT5640_PWR_BST3				(0x1 << 13)
+#define RT5640_PWR_BST3_BIT			13
+#define RT5640_PWR_BST4				(0x1 << 12)
+#define RT5640_PWR_BST4_BIT			12
+#define RT5640_PWR_MB1				(0x1 << 11)
+#define RT5640_PWR_MB1_BIT			11
+#define RT5640_PWR_PLL				(0x1 << 9)
+#define RT5640_PWR_PLL_BIT			9
+
+/* Power Management for Mixer (0x65) */
+#define RT5640_PWR_OM_L				(0x1 << 15)
+#define RT5640_PWR_OM_L_BIT			15
+#define RT5640_PWR_OM_R				(0x1 << 14)
+#define RT5640_PWR_OM_R_BIT			14
+#define RT5640_PWR_SM_L				(0x1 << 13)
+#define RT5640_PWR_SM_L_BIT			13
+#define RT5640_PWR_SM_R				(0x1 << 12)
+#define RT5640_PWR_SM_R_BIT			12
+#define RT5640_PWR_RM_L				(0x1 << 11)
+#define RT5640_PWR_RM_L_BIT			11
+#define RT5640_PWR_RM_R				(0x1 << 10)
+#define RT5640_PWR_RM_R_BIT			10
+
+/* Power Management for Volume (0x66) */
+#define RT5640_PWR_SV_L				(0x1 << 15)
+#define RT5640_PWR_SV_L_BIT			15
+#define RT5640_PWR_SV_R				(0x1 << 14)
+#define RT5640_PWR_SV_R_BIT			14
+#define RT5640_PWR_OV_L				(0x1 << 13)
+#define RT5640_PWR_OV_L_BIT			13
+#define RT5640_PWR_OV_R				(0x1 << 12)
+#define RT5640_PWR_OV_R_BIT			12
+#define RT5640_PWR_HV_L				(0x1 << 11)
+#define RT5640_PWR_HV_L_BIT			11
+#define RT5640_PWR_HV_R				(0x1 << 10)
+#define RT5640_PWR_HV_R_BIT			10
+#define RT5640_PWR_IN_L				(0x1 << 9)
+#define RT5640_PWR_IN_L_BIT			9
+#define RT5640_PWR_IN_R				(0x1 << 8)
+#define RT5640_PWR_IN_R_BIT			8
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71 0x72) */
+#define RT5640_I2S_MS_MASK			(0x1 << 15)
+#define RT5640_I2S_MS_SFT			15
+#define RT5640_I2S_MS_M				(0x0 << 15)
+#define RT5640_I2S_MS_S				(0x1 << 15)
+#define RT5640_I2S_IF_MASK			(0x7 << 12)
+#define RT5640_I2S_IF_SFT			12
+#define RT5640_I2S_O_CP_MASK			(0x3 << 10)
+#define RT5640_I2S_O_CP_SFT			10
+#define RT5640_I2S_O_CP_OFF			(0x0 << 10)
+#define RT5640_I2S_O_CP_U_LAW			(0x1 << 10)
+#define RT5640_I2S_O_CP_A_LAW			(0x2 << 10)
+#define RT5640_I2S_I_CP_MASK			(0x3 << 8)
+#define RT5640_I2S_I_CP_SFT			8
+#define RT5640_I2S_I_CP_OFF			(0x0 << 8)
+#define RT5640_I2S_I_CP_U_LAW			(0x1 << 8)
+#define RT5640_I2S_I_CP_A_LAW			(0x2 << 8)
+#define RT5640_I2S_BP_MASK			(0x1 << 7)
+#define RT5640_I2S_BP_SFT			7
+#define RT5640_I2S_BP_NOR			(0x0 << 7)
+#define RT5640_I2S_BP_INV			(0x1 << 7)
+#define RT5640_I2S_DL_MASK			(0x3 << 2)
+#define RT5640_I2S_DL_SFT			2
+#define RT5640_I2S_DL_16			(0x0 << 2)
+#define RT5640_I2S_DL_20			(0x1 << 2)
+#define RT5640_I2S_DL_24			(0x2 << 2)
+#define RT5640_I2S_DL_8				(0x3 << 2)
+#define RT5640_I2S_DF_MASK			(0x3)
+#define RT5640_I2S_DF_SFT			0
+#define RT5640_I2S_DF_I2S			(0x0)
+#define RT5640_I2S_DF_LEFT			(0x1)
+#define RT5640_I2S_DF_PCM_A			(0x2)
+#define RT5640_I2S_DF_PCM_B			(0x3)
+
+/* I2S2 Audio Serial Data Port Control (0x71) */
+#define RT5640_I2S2_SDI_MASK			(0x1 << 6)
+#define RT5640_I2S2_SDI_SFT			6
+#define RT5640_I2S2_SDI_I2S1			(0x0 << 6)
+#define RT5640_I2S2_SDI_I2S2			(0x1 << 6)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5640_I2S_BCLK_MS1_MASK		(0x1 << 15)
+#define RT5640_I2S_BCLK_MS1_SFT			15
+#define RT5640_I2S_BCLK_MS1_32			(0x0 << 15)
+#define RT5640_I2S_BCLK_MS1_64			(0x1 << 15)
+#define RT5640_I2S_PD1_MASK			(0x7 << 12)
+#define RT5640_I2S_PD1_SFT			12
+#define RT5640_I2S_PD1_1			(0x0 << 12)
+#define RT5640_I2S_PD1_2			(0x1 << 12)
+#define RT5640_I2S_PD1_3			(0x2 << 12)
+#define RT5640_I2S_PD1_4			(0x3 << 12)
+#define RT5640_I2S_PD1_6			(0x4 << 12)
+#define RT5640_I2S_PD1_8			(0x5 << 12)
+#define RT5640_I2S_PD1_12			(0x6 << 12)
+#define RT5640_I2S_PD1_16			(0x7 << 12)
+#define RT5640_I2S_BCLK_MS2_MASK		(0x1 << 11)
+#define RT5640_I2S_BCLK_MS2_SFT			11
+#define RT5640_I2S_BCLK_MS2_32			(0x0 << 11)
+#define RT5640_I2S_BCLK_MS2_64			(0x1 << 11)
+#define RT5640_I2S_PD2_MASK			(0x7 << 8)
+#define RT5640_I2S_PD2_SFT			8
+#define RT5640_I2S_PD2_1			(0x0 << 8)
+#define RT5640_I2S_PD2_2			(0x1 << 8)
+#define RT5640_I2S_PD2_3			(0x2 << 8)
+#define RT5640_I2S_PD2_4			(0x3 << 8)
+#define RT5640_I2S_PD2_6			(0x4 << 8)
+#define RT5640_I2S_PD2_8			(0x5 << 8)
+#define RT5640_I2S_PD2_12			(0x6 << 8)
+#define RT5640_I2S_PD2_16			(0x7 << 8)
+#define RT5640_I2S_BCLK_MS3_MASK		(0x1 << 7)
+#define RT5640_I2S_BCLK_MS3_SFT			7
+#define RT5640_I2S_BCLK_MS3_32			(0x0 << 7)
+#define RT5640_I2S_BCLK_MS3_64			(0x1 << 7)
+#define RT5640_I2S_PD3_MASK			(0x7 << 4)
+#define RT5640_I2S_PD3_SFT			4
+#define RT5640_I2S_PD3_1			(0x0 << 4)
+#define RT5640_I2S_PD3_2			(0x1 << 4)
+#define RT5640_I2S_PD3_3			(0x2 << 4)
+#define RT5640_I2S_PD3_4			(0x3 << 4)
+#define RT5640_I2S_PD3_6			(0x4 << 4)
+#define RT5640_I2S_PD3_8			(0x5 << 4)
+#define RT5640_I2S_PD3_12			(0x6 << 4)
+#define RT5640_I2S_PD3_16			(0x7 << 4)
+#define RT5640_DAC_OSR_MASK			(0x3 << 2)
+#define RT5640_DAC_OSR_SFT			2
+#define RT5640_DAC_OSR_128			(0x0 << 2)
+#define RT5640_DAC_OSR_64			(0x1 << 2)
+#define RT5640_DAC_OSR_32			(0x2 << 2)
+#define RT5640_DAC_OSR_16			(0x3 << 2)
+#define RT5640_ADC_OSR_MASK			(0x3)
+#define RT5640_ADC_OSR_SFT			0
+#define RT5640_ADC_OSR_128			(0x0)
+#define RT5640_ADC_OSR_64			(0x1)
+#define RT5640_ADC_OSR_32			(0x2)
+#define RT5640_ADC_OSR_16			(0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5640_DAC_L_OSR_MASK			(0x3 << 14)
+#define RT5640_DAC_L_OSR_SFT			14
+#define RT5640_DAC_L_OSR_128			(0x0 << 14)
+#define RT5640_DAC_L_OSR_64			(0x1 << 14)
+#define RT5640_DAC_L_OSR_32			(0x2 << 14)
+#define RT5640_DAC_L_OSR_16			(0x3 << 14)
+#define RT5640_ADC_R_OSR_MASK			(0x3 << 12)
+#define RT5640_ADC_R_OSR_SFT			12
+#define RT5640_ADC_R_OSR_128			(0x0 << 12)
+#define RT5640_ADC_R_OSR_64			(0x1 << 12)
+#define RT5640_ADC_R_OSR_32			(0x2 << 12)
+#define RT5640_ADC_R_OSR_16			(0x3 << 12)
+#define RT5640_DAHPF_EN				(0x1 << 11)
+#define RT5640_DAHPF_EN_SFT			11
+#define RT5640_ADHPF_EN				(0x1 << 10)
+#define RT5640_ADHPF_EN_SFT			10
+
+/* Digital Microphone Control (0x75) */
+#define RT5640_DMIC_1_EN_MASK			(0x1 << 15)
+#define RT5640_DMIC_1_EN_SFT			15
+#define RT5640_DMIC_1_DIS			(0x0 << 15)
+#define RT5640_DMIC_1_EN			(0x1 << 15)
+#define RT5640_DMIC_2_EN_MASK			(0x1 << 14)
+#define RT5640_DMIC_2_EN_SFT			14
+#define RT5640_DMIC_2_DIS			(0x0 << 14)
+#define RT5640_DMIC_2_EN			(0x1 << 14)
+#define RT5640_DMIC_1L_LH_MASK			(0x1 << 13)
+#define RT5640_DMIC_1L_LH_SFT			13
+#define RT5640_DMIC_1L_LH_FALLING		(0x0 << 13)
+#define RT5640_DMIC_1L_LH_RISING		(0x1 << 13)
+#define RT5640_DMIC_1R_LH_MASK			(0x1 << 12)
+#define RT5640_DMIC_1R_LH_SFT			12
+#define RT5640_DMIC_1R_LH_FALLING		(0x0 << 12)
+#define RT5640_DMIC_1R_LH_RISING		(0x1 << 12)
+#define RT5640_DMIC_1_DP_MASK			(0x1 << 11)
+#define RT5640_DMIC_1_DP_SFT			11
+#define RT5640_DMIC_1_DP_GPIO3			(0x0 << 11)
+#define RT5640_DMIC_1_DP_IN1P			(0x1 << 11)
+#define RT5640_DMIC_2_DP_MASK			(0x1 << 10)
+#define RT5640_DMIC_2_DP_SFT			10
+#define RT5640_DMIC_2_DP_GPIO4			(0x0 << 10)
+#define RT5640_DMIC_2_DP_IN1N			(0x1 << 10)
+#define RT5640_DMIC_2L_LH_MASK			(0x1 << 9)
+#define RT5640_DMIC_2L_LH_SFT			9
+#define RT5640_DMIC_2L_LH_FALLING		(0x0 << 9)
+#define RT5640_DMIC_2L_LH_RISING		(0x1 << 9)
+#define RT5640_DMIC_2R_LH_MASK			(0x1 << 8)
+#define RT5640_DMIC_2R_LH_SFT			8
+#define RT5640_DMIC_2R_LH_FALLING		(0x0 << 8)
+#define RT5640_DMIC_2R_LH_RISING		(0x1 << 8)
+#define RT5640_DMIC_CLK_MASK			(0x7 << 5)
+#define RT5640_DMIC_CLK_SFT			5
+
+/* Global Clock Control (0x80) */
+#define RT5640_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5640_SCLK_SRC_SFT			14
+#define RT5640_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5640_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5640_SCLK_SRC_RCCLK			(0x2 << 14)
+#define RT5640_PLL1_SRC_MASK			(0x3 << 12)
+#define RT5640_PLL1_SRC_SFT			12
+#define RT5640_PLL1_SRC_MCLK			(0x0 << 12)
+#define RT5640_PLL1_SRC_BCLK1			(0x1 << 12)
+#define RT5640_PLL1_SRC_BCLK2			(0x2 << 12)
+#define RT5640_PLL1_SRC_BCLK3			(0x3 << 12)
+#define RT5640_PLL1_PD_MASK			(0x1 << 3)
+#define RT5640_PLL1_PD_SFT			3
+#define RT5640_PLL1_PD_1			(0x0 << 3)
+#define RT5640_PLL1_PD_2			(0x1 << 3)
+
+#define RT5640_PLL_INP_MAX			40000000
+#define RT5640_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5640_PLL_N_MAX			0x1ff
+#define RT5640_PLL_N_MASK			(RT5640_PLL_N_MAX << 7)
+#define RT5640_PLL_N_SFT			7
+#define RT5640_PLL_K_MAX			0x1f
+#define RT5640_PLL_K_MASK			(RT5640_PLL_K_MAX)
+#define RT5640_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5640_PLL_M_MAX			0xf
+#define RT5640_PLL_M_MASK			(RT5640_PLL_M_MAX << 12)
+#define RT5640_PLL_M_SFT			12
+#define RT5640_PLL_M_BP				(0x1 << 11)
+#define RT5640_PLL_M_BP_SFT			11
+
+/* ASRC Control 1 (0x83) */
+#define RT5640_STO_T_MASK			(0x1 << 15)
+#define RT5640_STO_T_SFT			15
+#define RT5640_STO_T_SCLK			(0x0 << 15)
+#define RT5640_STO_T_LRCK1			(0x1 << 15)
+#define RT5640_M1_T_MASK			(0x1 << 14)
+#define RT5640_M1_T_SFT				14
+#define RT5640_M1_T_I2S2			(0x0 << 14)
+#define RT5640_M1_T_I2S2_D3			(0x1 << 14)
+#define RT5640_I2S2_F_MASK			(0x1 << 12)
+#define RT5640_I2S2_F_SFT			12
+#define RT5640_I2S2_F_I2S2_D2			(0x0 << 12)
+#define RT5640_I2S2_F_I2S1_TCLK			(0x1 << 12)
+#define RT5640_DMIC_1_M_MASK			(0x1 << 9)
+#define RT5640_DMIC_1_M_SFT			9
+#define RT5640_DMIC_1_M_NOR			(0x0 << 9)
+#define RT5640_DMIC_1_M_ASYN			(0x1 << 9)
+#define RT5640_DMIC_2_M_MASK			(0x1 << 8)
+#define RT5640_DMIC_2_M_SFT			8
+#define RT5640_DMIC_2_M_NOR			(0x0 << 8)
+#define RT5640_DMIC_2_M_ASYN			(0x1 << 8)
+
+/* ASRC clock source selection (0x84) */
+#define RT5640_CLK_SEL_SYS			(0x0)
+#define RT5640_CLK_SEL_ASRC			(0x1)
+
+/* ASRC Control 2 (0x84) */
+#define RT5640_MDA_L_M_MASK			(0x1 << 15)
+#define RT5640_MDA_L_M_SFT			15
+#define RT5640_MDA_L_M_NOR			(0x0 << 15)
+#define RT5640_MDA_L_M_ASYN			(0x1 << 15)
+#define RT5640_MDA_R_M_MASK			(0x1 << 14)
+#define RT5640_MDA_R_M_SFT			14
+#define RT5640_MDA_R_M_NOR			(0x0 << 14)
+#define RT5640_MDA_R_M_ASYN			(0x1 << 14)
+#define RT5640_MAD_L_M_MASK			(0x1 << 13)
+#define RT5640_MAD_L_M_SFT			13
+#define RT5640_MAD_L_M_NOR			(0x0 << 13)
+#define RT5640_MAD_L_M_ASYN			(0x1 << 13)
+#define RT5640_MAD_R_M_MASK			(0x1 << 12)
+#define RT5640_MAD_R_M_SFT			12
+#define RT5640_MAD_R_M_NOR			(0x0 << 12)
+#define RT5640_MAD_R_M_ASYN			(0x1 << 12)
+#define RT5640_ADC_M_MASK			(0x1 << 11)
+#define RT5640_ADC_M_SFT			11
+#define RT5640_ADC_M_NOR			(0x0 << 11)
+#define RT5640_ADC_M_ASYN			(0x1 << 11)
+#define RT5640_STO_DAC_M_MASK			(0x1 << 5)
+#define RT5640_STO_DAC_M_SFT			5
+#define RT5640_STO_DAC_M_NOR			(0x0 << 5)
+#define RT5640_STO_DAC_M_ASYN			(0x1 << 5)
+#define RT5640_I2S1_R_D_MASK			(0x1 << 4)
+#define RT5640_I2S1_R_D_SFT			4
+#define RT5640_I2S1_R_D_DIS			(0x0 << 4)
+#define RT5640_I2S1_R_D_EN			(0x1 << 4)
+#define RT5640_I2S2_R_D_MASK			(0x1 << 3)
+#define RT5640_I2S2_R_D_SFT			3
+#define RT5640_I2S2_R_D_DIS			(0x0 << 3)
+#define RT5640_I2S2_R_D_EN			(0x1 << 3)
+#define RT5640_PRE_SCLK_MASK			(0x3)
+#define RT5640_PRE_SCLK_SFT			0
+#define RT5640_PRE_SCLK_512			(0x0)
+#define RT5640_PRE_SCLK_1024			(0x1)
+#define RT5640_PRE_SCLK_2048			(0x2)
+
+/* ASRC Control 3 (0x85) */
+#define RT5640_I2S1_RATE_MASK			(0xf << 12)
+#define RT5640_I2S1_RATE_SFT			12
+#define RT5640_I2S2_RATE_MASK			(0xf << 8)
+#define RT5640_I2S2_RATE_SFT			8
+
+/* ASRC Control 4 (0x89) */
+#define RT5640_I2S1_PD_MASK			(0x7 << 12)
+#define RT5640_I2S1_PD_SFT			12
+#define RT5640_I2S2_PD_MASK			(0x7 << 8)
+#define RT5640_I2S2_PD_SFT			8
+
+/* HPOUT Over Current Detection (0x8b) */
+#define RT5640_HP_OVCD_MASK			(0x1 << 10)
+#define RT5640_HP_OVCD_SFT			10
+#define RT5640_HP_OVCD_DIS			(0x0 << 10)
+#define RT5640_HP_OVCD_EN			(0x1 << 10)
+#define RT5640_HP_OC_TH_MASK			(0x3 << 8)
+#define RT5640_HP_OC_TH_SFT			8
+#define RT5640_HP_OC_TH_90			(0x0 << 8)
+#define RT5640_HP_OC_TH_105			(0x1 << 8)
+#define RT5640_HP_OC_TH_120			(0x2 << 8)
+#define RT5640_HP_OC_TH_135			(0x3 << 8)
+
+/* Class D Over Current Control (0x8c) */
+#define RT5640_CLSD_OC_MASK			(0x1 << 9)
+#define RT5640_CLSD_OC_SFT			9
+#define RT5640_CLSD_OC_PU			(0x0 << 9)
+#define RT5640_CLSD_OC_PD			(0x1 << 9)
+#define RT5640_AUTO_PD_MASK			(0x1 << 8)
+#define RT5640_AUTO_PD_SFT			8
+#define RT5640_AUTO_PD_DIS			(0x0 << 8)
+#define RT5640_AUTO_PD_EN			(0x1 << 8)
+#define RT5640_CLSD_OC_TH_MASK			(0x3f)
+#define RT5640_CLSD_OC_TH_SFT			0
+
+/* Class D Output Control (0x8d) */
+#define RT5640_CLSD_RATIO_MASK			(0xf << 12)
+#define RT5640_CLSD_RATIO_SFT			12
+#define RT5640_CLSD_OM_MASK			(0x1 << 11)
+#define RT5640_CLSD_OM_SFT			11
+#define RT5640_CLSD_OM_MONO			(0x0 << 11)
+#define RT5640_CLSD_OM_STO			(0x1 << 11)
+#define RT5640_CLSD_SCH_MASK			(0x1 << 10)
+#define RT5640_CLSD_SCH_SFT			10
+#define RT5640_CLSD_SCH_L			(0x0 << 10)
+#define RT5640_CLSD_SCH_S			(0x1 << 10)
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5640_SMT_TRIG_MASK			(0x1 << 15)
+#define RT5640_SMT_TRIG_SFT			15
+#define RT5640_SMT_TRIG_DIS			(0x0 << 15)
+#define RT5640_SMT_TRIG_EN			(0x1 << 15)
+#define RT5640_HP_L_SMT_MASK			(0x1 << 9)
+#define RT5640_HP_L_SMT_SFT			9
+#define RT5640_HP_L_SMT_DIS			(0x0 << 9)
+#define RT5640_HP_L_SMT_EN			(0x1 << 9)
+#define RT5640_HP_R_SMT_MASK			(0x1 << 8)
+#define RT5640_HP_R_SMT_SFT			8
+#define RT5640_HP_R_SMT_DIS			(0x0 << 8)
+#define RT5640_HP_R_SMT_EN			(0x1 << 8)
+#define RT5640_HP_CD_PD_MASK			(0x1 << 7)
+#define RT5640_HP_CD_PD_SFT			7
+#define RT5640_HP_CD_PD_DIS			(0x0 << 7)
+#define RT5640_HP_CD_PD_EN			(0x1 << 7)
+#define RT5640_RSTN_MASK			(0x1 << 6)
+#define RT5640_RSTN_SFT				6
+#define RT5640_RSTN_DIS				(0x0 << 6)
+#define RT5640_RSTN_EN				(0x1 << 6)
+#define RT5640_RSTP_MASK			(0x1 << 5)
+#define RT5640_RSTP_SFT				5
+#define RT5640_RSTP_DIS				(0x0 << 5)
+#define RT5640_RSTP_EN				(0x1 << 5)
+#define RT5640_HP_CO_MASK			(0x1 << 4)
+#define RT5640_HP_CO_SFT			4
+#define RT5640_HP_CO_DIS			(0x0 << 4)
+#define RT5640_HP_CO_EN				(0x1 << 4)
+#define RT5640_HP_CP_MASK			(0x1 << 3)
+#define RT5640_HP_CP_SFT			3
+#define RT5640_HP_CP_PD				(0x0 << 3)
+#define RT5640_HP_CP_PU				(0x1 << 3)
+#define RT5640_HP_SG_MASK			(0x1 << 2)
+#define RT5640_HP_SG_SFT			2
+#define RT5640_HP_SG_DIS			(0x0 << 2)
+#define RT5640_HP_SG_EN				(0x1 << 2)
+#define RT5640_HP_DP_MASK			(0x1 << 1)
+#define RT5640_HP_DP_SFT			1
+#define RT5640_HP_DP_PD				(0x0 << 1)
+#define RT5640_HP_DP_PU				(0x1 << 1)
+#define RT5640_HP_CB_MASK			(0x1)
+#define RT5640_HP_CB_SFT			0
+#define RT5640_HP_CB_PD				(0x0)
+#define RT5640_HP_CB_PU				(0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5640_DEPOP_MASK			(0x1 << 13)
+#define RT5640_DEPOP_SFT			13
+#define RT5640_DEPOP_AUTO			(0x0 << 13)
+#define RT5640_DEPOP_MAN			(0x1 << 13)
+#define RT5640_RAMP_MASK			(0x1 << 12)
+#define RT5640_RAMP_SFT				12
+#define RT5640_RAMP_DIS				(0x0 << 12)
+#define RT5640_RAMP_EN				(0x1 << 12)
+#define RT5640_BPS_MASK				(0x1 << 11)
+#define RT5640_BPS_SFT				11
+#define RT5640_BPS_DIS				(0x0 << 11)
+#define RT5640_BPS_EN				(0x1 << 11)
+#define RT5640_FAST_UPDN_MASK			(0x1 << 10)
+#define RT5640_FAST_UPDN_SFT			10
+#define RT5640_FAST_UPDN_DIS			(0x0 << 10)
+#define RT5640_FAST_UPDN_EN			(0x1 << 10)
+#define RT5640_MRES_MASK			(0x3 << 8)
+#define RT5640_MRES_SFT				8
+#define RT5640_MRES_15MO			(0x0 << 8)
+#define RT5640_MRES_25MO			(0x1 << 8)
+#define RT5640_MRES_35MO			(0x2 << 8)
+#define RT5640_MRES_45MO			(0x3 << 8)
+#define RT5640_VLO_MASK				(0x1 << 7)
+#define RT5640_VLO_SFT				7
+#define RT5640_VLO_3V				(0x0 << 7)
+#define RT5640_VLO_32V				(0x1 << 7)
+#define RT5640_DIG_DP_MASK			(0x1 << 6)
+#define RT5640_DIG_DP_SFT			6
+#define RT5640_DIG_DP_DIS			(0x0 << 6)
+#define RT5640_DIG_DP_EN			(0x1 << 6)
+#define RT5640_DP_TH_MASK			(0x3 << 4)
+#define RT5640_DP_TH_SFT			4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5640_CP_SYS_MASK			(0x7 << 12)
+#define RT5640_CP_SYS_SFT			12
+#define RT5640_CP_FQ1_MASK			(0x7 << 8)
+#define RT5640_CP_FQ1_SFT			8
+#define RT5640_CP_FQ2_MASK			(0x7 << 4)
+#define RT5640_CP_FQ2_SFT			4
+#define RT5640_CP_FQ3_MASK			(0x7)
+#define RT5640_CP_FQ3_SFT			0
+#define RT5640_CP_FQ_1_5_KHZ			0
+#define RT5640_CP_FQ_3_KHZ			1
+#define RT5640_CP_FQ_6_KHZ			2
+#define RT5640_CP_FQ_12_KHZ			3
+#define RT5640_CP_FQ_24_KHZ			4
+#define RT5640_CP_FQ_48_KHZ			5
+#define RT5640_CP_FQ_96_KHZ			6
+#define RT5640_CP_FQ_192_KHZ			7
+
+/* HPOUT charge pump (0x91) */
+#define RT5640_OSW_L_MASK			(0x1 << 11)
+#define RT5640_OSW_L_SFT			11
+#define RT5640_OSW_L_DIS			(0x0 << 11)
+#define RT5640_OSW_L_EN				(0x1 << 11)
+#define RT5640_OSW_R_MASK			(0x1 << 10)
+#define RT5640_OSW_R_SFT			10
+#define RT5640_OSW_R_DIS			(0x0 << 10)
+#define RT5640_OSW_R_EN				(0x1 << 10)
+#define RT5640_PM_HP_MASK			(0x3 << 8)
+#define RT5640_PM_HP_SFT			8
+#define RT5640_PM_HP_LV				(0x0 << 8)
+#define RT5640_PM_HP_MV				(0x1 << 8)
+#define RT5640_PM_HP_HV				(0x2 << 8)
+#define RT5640_IB_HP_MASK			(0x3 << 6)
+#define RT5640_IB_HP_SFT			6
+#define RT5640_IB_HP_125IL			(0x0 << 6)
+#define RT5640_IB_HP_25IL			(0x1 << 6)
+#define RT5640_IB_HP_5IL			(0x2 << 6)
+#define RT5640_IB_HP_1IL			(0x3 << 6)
+
+/* PV detection and SPK gain control (0x92) */
+#define RT5640_PVDD_DET_MASK			(0x1 << 15)
+#define RT5640_PVDD_DET_SFT			15
+#define RT5640_PVDD_DET_DIS			(0x0 << 15)
+#define RT5640_PVDD_DET_EN			(0x1 << 15)
+#define RT5640_SPK_AG_MASK			(0x1 << 14)
+#define RT5640_SPK_AG_SFT			14
+#define RT5640_SPK_AG_DIS			(0x0 << 14)
+#define RT5640_SPK_AG_EN			(0x1 << 14)
+
+/* Micbias Control (0x93) */
+#define RT5640_MIC1_BS_MASK			(0x1 << 15)
+#define RT5640_MIC1_BS_SFT			15
+#define RT5640_MIC1_BS_9AV			(0x0 << 15)
+#define RT5640_MIC1_BS_75AV			(0x1 << 15)
+#define RT5640_MIC2_BS_MASK			(0x1 << 14)
+#define RT5640_MIC2_BS_SFT			14
+#define RT5640_MIC2_BS_9AV			(0x0 << 14)
+#define RT5640_MIC2_BS_75AV			(0x1 << 14)
+#define RT5640_MIC1_CLK_MASK			(0x1 << 13)
+#define RT5640_MIC1_CLK_SFT			13
+#define RT5640_MIC1_CLK_DIS			(0x0 << 13)
+#define RT5640_MIC1_CLK_EN			(0x1 << 13)
+#define RT5640_MIC2_CLK_MASK			(0x1 << 12)
+#define RT5640_MIC2_CLK_SFT			12
+#define RT5640_MIC2_CLK_DIS			(0x0 << 12)
+#define RT5640_MIC2_CLK_EN			(0x1 << 12)
+#define RT5640_MIC1_OVCD_MASK			(0x1 << 11)
+#define RT5640_MIC1_OVCD_SFT			11
+#define RT5640_MIC1_OVCD_DIS			(0x0 << 11)
+#define RT5640_MIC1_OVCD_EN			(0x1 << 11)
+#define RT5640_MIC1_OVTH_MASK			(0x3 << 9)
+#define RT5640_MIC1_OVTH_SFT			9
+#define RT5640_MIC1_OVTH_600UA			(0x0 << 9)
+#define RT5640_MIC1_OVTH_1500UA			(0x1 << 9)
+#define RT5640_MIC1_OVTH_2000UA			(0x2 << 9)
+#define RT5640_MIC2_OVCD_MASK			(0x1 << 8)
+#define RT5640_MIC2_OVCD_SFT			8
+#define RT5640_MIC2_OVCD_DIS			(0x0 << 8)
+#define RT5640_MIC2_OVCD_EN			(0x1 << 8)
+#define RT5640_MIC2_OVTH_MASK			(0x3 << 6)
+#define RT5640_MIC2_OVTH_SFT			6
+#define RT5640_MIC2_OVTH_600UA			(0x0 << 6)
+#define RT5640_MIC2_OVTH_1500UA			(0x1 << 6)
+#define RT5640_MIC2_OVTH_2000UA			(0x2 << 6)
+#define RT5640_PWR_MB_MASK			(0x1 << 5)
+#define RT5640_PWR_MB_SFT			5
+#define RT5640_PWR_MB_PD			(0x0 << 5)
+#define RT5640_PWR_MB_PU			(0x1 << 5)
+#define RT5640_PWR_CLK25M_MASK			(0x1 << 4)
+#define RT5640_PWR_CLK25M_SFT			4
+#define RT5640_PWR_CLK25M_PD			(0x0 << 4)
+#define RT5640_PWR_CLK25M_PU			(0x1 << 4)
+
+/* EQ Control 1 (0xb0) */
+#define RT5640_EQ_SRC_MASK			(0x1 << 15)
+#define RT5640_EQ_SRC_SFT			15
+#define RT5640_EQ_SRC_DAC			(0x0 << 15)
+#define RT5640_EQ_SRC_ADC			(0x1 << 15)
+#define RT5640_EQ_UPD				(0x1 << 14)
+#define RT5640_EQ_UPD_BIT			14
+#define RT5640_EQ_CD_MASK			(0x1 << 13)
+#define RT5640_EQ_CD_SFT			13
+#define RT5640_EQ_CD_DIS			(0x0 << 13)
+#define RT5640_EQ_CD_EN				(0x1 << 13)
+#define RT5640_EQ_DITH_MASK			(0x3 << 8)
+#define RT5640_EQ_DITH_SFT			8
+#define RT5640_EQ_DITH_NOR			(0x0 << 8)
+#define RT5640_EQ_DITH_LSB			(0x1 << 8)
+#define RT5640_EQ_DITH_LSB_1			(0x2 << 8)
+#define RT5640_EQ_DITH_LSB_2			(0x3 << 8)
+
+/* EQ Control 2 (0xb1) */
+#define RT5640_EQ_HPF1_M_MASK			(0x1 << 8)
+#define RT5640_EQ_HPF1_M_SFT			8
+#define RT5640_EQ_HPF1_M_HI			(0x0 << 8)
+#define RT5640_EQ_HPF1_M_1ST			(0x1 << 8)
+#define RT5640_EQ_LPF1_M_MASK			(0x1 << 7)
+#define RT5640_EQ_LPF1_M_SFT			7
+#define RT5640_EQ_LPF1_M_LO			(0x0 << 7)
+#define RT5640_EQ_LPF1_M_1ST			(0x1 << 7)
+#define RT5640_EQ_HPF2_MASK			(0x1 << 6)
+#define RT5640_EQ_HPF2_SFT			6
+#define RT5640_EQ_HPF2_DIS			(0x0 << 6)
+#define RT5640_EQ_HPF2_EN			(0x1 << 6)
+#define RT5640_EQ_HPF1_MASK			(0x1 << 5)
+#define RT5640_EQ_HPF1_SFT			5
+#define RT5640_EQ_HPF1_DIS			(0x0 << 5)
+#define RT5640_EQ_HPF1_EN			(0x1 << 5)
+#define RT5640_EQ_BPF4_MASK			(0x1 << 4)
+#define RT5640_EQ_BPF4_SFT			4
+#define RT5640_EQ_BPF4_DIS			(0x0 << 4)
+#define RT5640_EQ_BPF4_EN			(0x1 << 4)
+#define RT5640_EQ_BPF3_MASK			(0x1 << 3)
+#define RT5640_EQ_BPF3_SFT			3
+#define RT5640_EQ_BPF3_DIS			(0x0 << 3)
+#define RT5640_EQ_BPF3_EN			(0x1 << 3)
+#define RT5640_EQ_BPF2_MASK			(0x1 << 2)
+#define RT5640_EQ_BPF2_SFT			2
+#define RT5640_EQ_BPF2_DIS			(0x0 << 2)
+#define RT5640_EQ_BPF2_EN			(0x1 << 2)
+#define RT5640_EQ_BPF1_MASK			(0x1 << 1)
+#define RT5640_EQ_BPF1_SFT			1
+#define RT5640_EQ_BPF1_DIS			(0x0 << 1)
+#define RT5640_EQ_BPF1_EN			(0x1 << 1)
+#define RT5640_EQ_LPF_MASK			(0x1)
+#define RT5640_EQ_LPF_SFT			0
+#define RT5640_EQ_LPF_DIS			(0x0)
+#define RT5640_EQ_LPF_EN			(0x1)
+
+/* Memory Test (0xb2) */
+#define RT5640_MT_MASK				(0x1 << 15)
+#define RT5640_MT_SFT				15
+#define RT5640_MT_DIS				(0x0 << 15)
+#define RT5640_MT_EN				(0x1 << 15)
+
+/* DRC/AGC Control 1 (0xb4) */
+#define RT5640_DRC_AGC_P_MASK			(0x1 << 15)
+#define RT5640_DRC_AGC_P_SFT			15
+#define RT5640_DRC_AGC_P_DAC			(0x0 << 15)
+#define RT5640_DRC_AGC_P_ADC			(0x1 << 15)
+#define RT5640_DRC_AGC_MASK			(0x1 << 14)
+#define RT5640_DRC_AGC_SFT			14
+#define RT5640_DRC_AGC_DIS			(0x0 << 14)
+#define RT5640_DRC_AGC_EN			(0x1 << 14)
+#define RT5640_DRC_AGC_UPD			(0x1 << 13)
+#define RT5640_DRC_AGC_UPD_BIT			13
+#define RT5640_DRC_AGC_AR_MASK			(0x1f << 8)
+#define RT5640_DRC_AGC_AR_SFT			8
+#define RT5640_DRC_AGC_R_MASK			(0x7 << 5)
+#define RT5640_DRC_AGC_R_SFT			5
+#define RT5640_DRC_AGC_R_48K			(0x1 << 5)
+#define RT5640_DRC_AGC_R_96K			(0x2 << 5)
+#define RT5640_DRC_AGC_R_192K			(0x3 << 5)
+#define RT5640_DRC_AGC_R_441K			(0x5 << 5)
+#define RT5640_DRC_AGC_R_882K			(0x6 << 5)
+#define RT5640_DRC_AGC_R_1764K			(0x7 << 5)
+#define RT5640_DRC_AGC_RC_MASK			(0x1f)
+#define RT5640_DRC_AGC_RC_SFT			0
+
+/* DRC/AGC Control 2 (0xb5) */
+#define RT5640_DRC_AGC_POB_MASK			(0x3f << 8)
+#define RT5640_DRC_AGC_POB_SFT			8
+#define RT5640_DRC_AGC_CP_MASK			(0x1 << 7)
+#define RT5640_DRC_AGC_CP_SFT			7
+#define RT5640_DRC_AGC_CP_DIS			(0x0 << 7)
+#define RT5640_DRC_AGC_CP_EN			(0x1 << 7)
+#define RT5640_DRC_AGC_CPR_MASK			(0x3 << 5)
+#define RT5640_DRC_AGC_CPR_SFT			5
+#define RT5640_DRC_AGC_CPR_1_1			(0x0 << 5)
+#define RT5640_DRC_AGC_CPR_1_2			(0x1 << 5)
+#define RT5640_DRC_AGC_CPR_1_3			(0x2 << 5)
+#define RT5640_DRC_AGC_CPR_1_4			(0x3 << 5)
+#define RT5640_DRC_AGC_PRB_MASK			(0x1f)
+#define RT5640_DRC_AGC_PRB_SFT			0
+
+/* DRC/AGC Control 3 (0xb6) */
+#define RT5640_DRC_AGC_NGB_MASK			(0xf << 12)
+#define RT5640_DRC_AGC_NGB_SFT			12
+#define RT5640_DRC_AGC_TAR_MASK			(0x1f << 7)
+#define RT5640_DRC_AGC_TAR_SFT			7
+#define RT5640_DRC_AGC_NG_MASK			(0x1 << 6)
+#define RT5640_DRC_AGC_NG_SFT			6
+#define RT5640_DRC_AGC_NG_DIS			(0x0 << 6)
+#define RT5640_DRC_AGC_NG_EN			(0x1 << 6)
+#define RT5640_DRC_AGC_NGH_MASK			(0x1 << 5)
+#define RT5640_DRC_AGC_NGH_SFT			5
+#define RT5640_DRC_AGC_NGH_DIS			(0x0 << 5)
+#define RT5640_DRC_AGC_NGH_EN			(0x1 << 5)
+#define RT5640_DRC_AGC_NGT_MASK			(0x1f)
+#define RT5640_DRC_AGC_NGT_SFT			0
+
+/* ANC Control 1 (0xb8) */
+#define RT5640_ANC_M_MASK			(0x1 << 15)
+#define RT5640_ANC_M_SFT			15
+#define RT5640_ANC_M_NOR			(0x0 << 15)
+#define RT5640_ANC_M_REV			(0x1 << 15)
+#define RT5640_ANC_MASK				(0x1 << 14)
+#define RT5640_ANC_SFT				14
+#define RT5640_ANC_DIS				(0x0 << 14)
+#define RT5640_ANC_EN				(0x1 << 14)
+#define RT5640_ANC_MD_MASK			(0x3 << 12)
+#define RT5640_ANC_MD_SFT			12
+#define RT5640_ANC_MD_DIS			(0x0 << 12)
+#define RT5640_ANC_MD_67MS			(0x1 << 12)
+#define RT5640_ANC_MD_267MS			(0x2 << 12)
+#define RT5640_ANC_MD_1067MS			(0x3 << 12)
+#define RT5640_ANC_SN_MASK			(0x1 << 11)
+#define RT5640_ANC_SN_SFT			11
+#define RT5640_ANC_SN_DIS			(0x0 << 11)
+#define RT5640_ANC_SN_EN			(0x1 << 11)
+#define RT5640_ANC_CLK_MASK			(0x1 << 10)
+#define RT5640_ANC_CLK_SFT			10
+#define RT5640_ANC_CLK_ANC			(0x0 << 10)
+#define RT5640_ANC_CLK_REG			(0x1 << 10)
+#define RT5640_ANC_ZCD_MASK			(0x3 << 8)
+#define RT5640_ANC_ZCD_SFT			8
+#define RT5640_ANC_ZCD_DIS			(0x0 << 8)
+#define RT5640_ANC_ZCD_T1			(0x1 << 8)
+#define RT5640_ANC_ZCD_T2			(0x2 << 8)
+#define RT5640_ANC_ZCD_WT			(0x3 << 8)
+#define RT5640_ANC_CS_MASK			(0x1 << 7)
+#define RT5640_ANC_CS_SFT			7
+#define RT5640_ANC_CS_DIS			(0x0 << 7)
+#define RT5640_ANC_CS_EN			(0x1 << 7)
+#define RT5640_ANC_SW_MASK			(0x1 << 6)
+#define RT5640_ANC_SW_SFT			6
+#define RT5640_ANC_SW_NOR			(0x0 << 6)
+#define RT5640_ANC_SW_AUTO			(0x1 << 6)
+#define RT5640_ANC_CO_L_MASK			(0x3f)
+#define RT5640_ANC_CO_L_SFT			0
+
+/* ANC Control 2 (0xb6) */
+#define RT5640_ANC_FG_R_MASK			(0xf << 12)
+#define RT5640_ANC_FG_R_SFT			12
+#define RT5640_ANC_FG_L_MASK			(0xf << 8)
+#define RT5640_ANC_FG_L_SFT			8
+#define RT5640_ANC_CG_R_MASK			(0xf << 4)
+#define RT5640_ANC_CG_R_SFT			4
+#define RT5640_ANC_CG_L_MASK			(0xf)
+#define RT5640_ANC_CG_L_SFT			0
+
+/* ANC Control 3 (0xb6) */
+#define RT5640_ANC_CD_MASK			(0x1 << 6)
+#define RT5640_ANC_CD_SFT			6
+#define RT5640_ANC_CD_BOTH			(0x0 << 6)
+#define RT5640_ANC_CD_IND			(0x1 << 6)
+#define RT5640_ANC_CO_R_MASK			(0x3f)
+#define RT5640_ANC_CO_R_SFT			0
+
+/* Jack Detect Control (0xbb) */
+#define RT5640_JD_MASK				(0x7 << 13)
+#define RT5640_JD_SFT				13
+#define RT5640_JD_DIS				(0x0 << 13)
+#define RT5640_JD_GPIO1				(0x1 << 13)
+#define RT5640_JD_JD1_IN4P			(0x2 << 13)
+#define RT5640_JD_JD2_IN4N			(0x3 << 13)
+#define RT5640_JD_GPIO2				(0x4 << 13)
+#define RT5640_JD_GPIO3				(0x5 << 13)
+#define RT5640_JD_GPIO4				(0x6 << 13)
+#define RT5640_JD_HP_MASK			(0x1 << 11)
+#define RT5640_JD_HP_SFT			11
+#define RT5640_JD_HP_DIS			(0x0 << 11)
+#define RT5640_JD_HP_EN				(0x1 << 11)
+#define RT5640_JD_HP_TRG_MASK			(0x1 << 10)
+#define RT5640_JD_HP_TRG_SFT			10
+#define RT5640_JD_HP_TRG_LO			(0x0 << 10)
+#define RT5640_JD_HP_TRG_HI			(0x1 << 10)
+#define RT5640_JD_SPL_MASK			(0x1 << 9)
+#define RT5640_JD_SPL_SFT			9
+#define RT5640_JD_SPL_DIS			(0x0 << 9)
+#define RT5640_JD_SPL_EN			(0x1 << 9)
+#define RT5640_JD_SPL_TRG_MASK			(0x1 << 8)
+#define RT5640_JD_SPL_TRG_SFT			8
+#define RT5640_JD_SPL_TRG_LO			(0x0 << 8)
+#define RT5640_JD_SPL_TRG_HI			(0x1 << 8)
+#define RT5640_JD_SPR_MASK			(0x1 << 7)
+#define RT5640_JD_SPR_SFT			7
+#define RT5640_JD_SPR_DIS			(0x0 << 7)
+#define RT5640_JD_SPR_EN			(0x1 << 7)
+#define RT5640_JD_SPR_TRG_MASK			(0x1 << 6)
+#define RT5640_JD_SPR_TRG_SFT			6
+#define RT5640_JD_SPR_TRG_LO			(0x0 << 6)
+#define RT5640_JD_SPR_TRG_HI			(0x1 << 6)
+#define RT5640_JD_MO_MASK			(0x1 << 5)
+#define RT5640_JD_MO_SFT			5
+#define RT5640_JD_MO_DIS			(0x0 << 5)
+#define RT5640_JD_MO_EN				(0x1 << 5)
+#define RT5640_JD_MO_TRG_MASK			(0x1 << 4)
+#define RT5640_JD_MO_TRG_SFT			4
+#define RT5640_JD_MO_TRG_LO			(0x0 << 4)
+#define RT5640_JD_MO_TRG_HI			(0x1 << 4)
+#define RT5640_JD_LO_MASK			(0x1 << 3)
+#define RT5640_JD_LO_SFT			3
+#define RT5640_JD_LO_DIS			(0x0 << 3)
+#define RT5640_JD_LO_EN				(0x1 << 3)
+#define RT5640_JD_LO_TRG_MASK			(0x1 << 2)
+#define RT5640_JD_LO_TRG_SFT			2
+#define RT5640_JD_LO_TRG_LO			(0x0 << 2)
+#define RT5640_JD_LO_TRG_HI			(0x1 << 2)
+#define RT5640_JD1_IN4P_MASK			(0x1 << 1)
+#define RT5640_JD1_IN4P_SFT			1
+#define RT5640_JD1_IN4P_DIS			(0x0 << 1)
+#define RT5640_JD1_IN4P_EN			(0x1 << 1)
+#define RT5640_JD2_IN4N_MASK			(0x1)
+#define RT5640_JD2_IN4N_SFT			0
+#define RT5640_JD2_IN4N_DIS			(0x0)
+#define RT5640_JD2_IN4N_EN			(0x1)
+
+/* Jack detect for ANC (0xbc) */
+#define RT5640_ANC_DET_MASK			(0x3 << 4)
+#define RT5640_ANC_DET_SFT			4
+#define RT5640_ANC_DET_DIS			(0x0 << 4)
+#define RT5640_ANC_DET_MB1			(0x1 << 4)
+#define RT5640_ANC_DET_MB2			(0x2 << 4)
+#define RT5640_ANC_DET_JD			(0x3 << 4)
+#define RT5640_AD_TRG_MASK			(0x1 << 3)
+#define RT5640_AD_TRG_SFT			3
+#define RT5640_AD_TRG_LO			(0x0 << 3)
+#define RT5640_AD_TRG_HI			(0x1 << 3)
+#define RT5640_ANCM_DET_MASK			(0x3 << 4)
+#define RT5640_ANCM_DET_SFT			4
+#define RT5640_ANCM_DET_DIS			(0x0 << 4)
+#define RT5640_ANCM_DET_MB1			(0x1 << 4)
+#define RT5640_ANCM_DET_MB2			(0x2 << 4)
+#define RT5640_ANCM_DET_JD			(0x3 << 4)
+#define RT5640_AMD_TRG_MASK			(0x1 << 3)
+#define RT5640_AMD_TRG_SFT			3
+#define RT5640_AMD_TRG_LO			(0x0 << 3)
+#define RT5640_AMD_TRG_HI			(0x1 << 3)
+
+/* IRQ Control 1 (0xbd) */
+#define RT5640_IRQ_JD_MASK			(0x1 << 15)
+#define RT5640_IRQ_JD_SFT			15
+#define RT5640_IRQ_JD_BP			(0x0 << 15)
+#define RT5640_IRQ_JD_NOR			(0x1 << 15)
+#define RT5640_IRQ_OT_MASK			(0x1 << 14)
+#define RT5640_IRQ_OT_SFT			14
+#define RT5640_IRQ_OT_BP			(0x0 << 14)
+#define RT5640_IRQ_OT_NOR			(0x1 << 14)
+#define RT5640_JD_STKY_MASK			(0x1 << 13)
+#define RT5640_JD_STKY_SFT			13
+#define RT5640_JD_STKY_DIS			(0x0 << 13)
+#define RT5640_JD_STKY_EN			(0x1 << 13)
+#define RT5640_OT_STKY_MASK			(0x1 << 12)
+#define RT5640_OT_STKY_SFT			12
+#define RT5640_OT_STKY_DIS			(0x0 << 12)
+#define RT5640_OT_STKY_EN			(0x1 << 12)
+#define RT5640_JD_P_MASK			(0x1 << 11)
+#define RT5640_JD_P_SFT				11
+#define RT5640_JD_P_NOR				(0x0 << 11)
+#define RT5640_JD_P_INV				(0x1 << 11)
+#define RT5640_OT_P_MASK			(0x1 << 10)
+#define RT5640_OT_P_SFT				10
+#define RT5640_OT_P_NOR				(0x0 << 10)
+#define RT5640_OT_P_INV				(0x1 << 10)
+
+/* IRQ Control 2 (0xbe) */
+#define RT5640_IRQ_MB1_OC_MASK			(0x1 << 15)
+#define RT5640_IRQ_MB1_OC_SFT			15
+#define RT5640_IRQ_MB1_OC_BP			(0x0 << 15)
+#define RT5640_IRQ_MB1_OC_NOR			(0x1 << 15)
+#define RT5640_IRQ_MB2_OC_MASK			(0x1 << 14)
+#define RT5640_IRQ_MB2_OC_SFT			14
+#define RT5640_IRQ_MB2_OC_BP			(0x0 << 14)
+#define RT5640_IRQ_MB2_OC_NOR			(0x1 << 14)
+#define RT5640_MB1_OC_STKY_MASK			(0x1 << 11)
+#define RT5640_MB1_OC_STKY_SFT			11
+#define RT5640_MB1_OC_STKY_DIS			(0x0 << 11)
+#define RT5640_MB1_OC_STKY_EN			(0x1 << 11)
+#define RT5640_MB2_OC_STKY_MASK			(0x1 << 10)
+#define RT5640_MB2_OC_STKY_SFT			10
+#define RT5640_MB2_OC_STKY_DIS			(0x0 << 10)
+#define RT5640_MB2_OC_STKY_EN			(0x1 << 10)
+#define RT5640_MB1_OC_P_MASK			(0x1 << 7)
+#define RT5640_MB1_OC_P_SFT			7
+#define RT5640_MB1_OC_P_NOR			(0x0 << 7)
+#define RT5640_MB1_OC_P_INV			(0x1 << 7)
+#define RT5640_MB2_OC_P_MASK			(0x1 << 6)
+#define RT5640_MB2_OC_P_SFT			6
+#define RT5640_MB2_OC_P_NOR			(0x0 << 6)
+#define RT5640_MB2_OC_P_INV			(0x1 << 6)
+#define RT5640_MB1_OC_STATUS			(0x1 << 3)
+#define RT5640_MB1_OC_STATUS_SFT		3
+#define RT5640_MB2_OC_STATUS			(0x1 << 2)
+#define RT5640_MB2_OC_STATUS_SFT		2
+
+/* GPIO and Internal Status (0xbf) */
+#define RT5640_GPIO1_STATUS			(0x1 << 8)
+#define RT5640_GPIO2_STATUS			(0x1 << 7)
+#define RT5640_JD_STATUS			(0x1 << 4)
+#define RT5640_OVT_STATUS			(0x1 << 3)
+#define RT5640_CLS_D_OVCD_STATUS		(0x1 << 0)
+
+/* GPIO Control 1 (0xc0) */
+#define RT5640_GP1_PIN_MASK			(0x1 << 15)
+#define RT5640_GP1_PIN_SFT			15
+#define RT5640_GP1_PIN_GPIO1			(0x0 << 15)
+#define RT5640_GP1_PIN_IRQ			(0x1 << 15)
+#define RT5640_GP2_PIN_MASK			(0x1 << 14)
+#define RT5640_GP2_PIN_SFT			14
+#define RT5640_GP2_PIN_GPIO2			(0x0 << 14)
+#define RT5640_GP2_PIN_DMIC1_SCL		(0x1 << 14)
+#define RT5640_GP3_PIN_MASK			(0x3 << 12)
+#define RT5640_GP3_PIN_SFT			12
+#define RT5640_GP3_PIN_GPIO3			(0x0 << 12)
+#define RT5640_GP3_PIN_DMIC1_SDA		(0x1 << 12)
+#define RT5640_GP3_PIN_IRQ			(0x2 << 12)
+#define RT5640_GP4_PIN_MASK			(0x1 << 11)
+#define RT5640_GP4_PIN_SFT			11
+#define RT5640_GP4_PIN_GPIO4			(0x0 << 11)
+#define RT5640_GP4_PIN_DMIC2_SDA		(0x1 << 11)
+#define RT5640_DP_SIG_MASK			(0x1 << 10)
+#define RT5640_DP_SIG_SFT			10
+#define RT5640_DP_SIG_TEST			(0x0 << 10)
+#define RT5640_DP_SIG_AP			(0x1 << 10)
+#define RT5640_GPIO_M_MASK			(0x1 << 9)
+#define RT5640_GPIO_M_SFT			9
+#define RT5640_GPIO_M_FLT			(0x0 << 9)
+#define RT5640_GPIO_M_PH			(0x1 << 9)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5640_GP4_PF_MASK			(0x1 << 11)
+#define RT5640_GP4_PF_SFT			11
+#define RT5640_GP4_PF_IN			(0x0 << 11)
+#define RT5640_GP4_PF_OUT			(0x1 << 11)
+#define RT5640_GP4_OUT_MASK			(0x1 << 10)
+#define RT5640_GP4_OUT_SFT			10
+#define RT5640_GP4_OUT_LO			(0x0 << 10)
+#define RT5640_GP4_OUT_HI			(0x1 << 10)
+#define RT5640_GP4_P_MASK			(0x1 << 9)
+#define RT5640_GP4_P_SFT			9
+#define RT5640_GP4_P_NOR			(0x0 << 9)
+#define RT5640_GP4_P_INV			(0x1 << 9)
+#define RT5640_GP3_PF_MASK			(0x1 << 8)
+#define RT5640_GP3_PF_SFT			8
+#define RT5640_GP3_PF_IN			(0x0 << 8)
+#define RT5640_GP3_PF_OUT			(0x1 << 8)
+#define RT5640_GP3_OUT_MASK			(0x1 << 7)
+#define RT5640_GP3_OUT_SFT			7
+#define RT5640_GP3_OUT_LO			(0x0 << 7)
+#define RT5640_GP3_OUT_HI			(0x1 << 7)
+#define RT5640_GP3_P_MASK			(0x1 << 6)
+#define RT5640_GP3_P_SFT			6
+#define RT5640_GP3_P_NOR			(0x0 << 6)
+#define RT5640_GP3_P_INV			(0x1 << 6)
+#define RT5640_GP2_PF_MASK			(0x1 << 5)
+#define RT5640_GP2_PF_SFT			5
+#define RT5640_GP2_PF_IN			(0x0 << 5)
+#define RT5640_GP2_PF_OUT			(0x1 << 5)
+#define RT5640_GP2_OUT_MASK			(0x1 << 4)
+#define RT5640_GP2_OUT_SFT			4
+#define RT5640_GP2_OUT_LO			(0x0 << 4)
+#define RT5640_GP2_OUT_HI			(0x1 << 4)
+#define RT5640_GP2_P_MASK			(0x1 << 3)
+#define RT5640_GP2_P_SFT			3
+#define RT5640_GP2_P_NOR			(0x0 << 3)
+#define RT5640_GP2_P_INV			(0x1 << 3)
+#define RT5640_GP1_PF_MASK			(0x1 << 2)
+#define RT5640_GP1_PF_SFT			2
+#define RT5640_GP1_PF_IN			(0x0 << 2)
+#define RT5640_GP1_PF_OUT			(0x1 << 2)
+#define RT5640_GP1_OUT_MASK			(0x1 << 1)
+#define RT5640_GP1_OUT_SFT			1
+#define RT5640_GP1_OUT_LO			(0x0 << 1)
+#define RT5640_GP1_OUT_HI			(0x1 << 1)
+#define RT5640_GP1_P_MASK			(0x1)
+#define RT5640_GP1_P_SFT			0
+#define RT5640_GP1_P_NOR			(0x0)
+#define RT5640_GP1_P_INV			(0x1)
+
+/* FM34-500 Register Control 1 (0xc4) */
+#define RT5640_DSP_ADD_SFT			0
+
+/* FM34-500 Register Control 2 (0xc5) */
+#define RT5640_DSP_DAT_SFT			0
+
+/* FM34-500 Register Control 3 (0xc6) */
+#define RT5640_DSP_BUSY_MASK			(0x1 << 15)
+#define RT5640_DSP_BUSY_BIT			15
+#define RT5640_DSP_DS_MASK			(0x1 << 14)
+#define RT5640_DSP_DS_SFT			14
+#define RT5640_DSP_DS_FM3010			(0x1 << 14)
+#define RT5640_DSP_DS_TEMP			(0x1 << 14)
+#define RT5640_DSP_CLK_MASK			(0x3 << 12)
+#define RT5640_DSP_CLK_SFT			12
+#define RT5640_DSP_CLK_384K			(0x0 << 12)
+#define RT5640_DSP_CLK_192K			(0x1 << 12)
+#define RT5640_DSP_CLK_96K			(0x2 << 12)
+#define RT5640_DSP_CLK_64K			(0x3 << 12)
+#define RT5640_DSP_PD_PIN_MASK			(0x1 << 11)
+#define RT5640_DSP_PD_PIN_SFT			11
+#define RT5640_DSP_PD_PIN_LO			(0x0 << 11)
+#define RT5640_DSP_PD_PIN_HI			(0x1 << 11)
+#define RT5640_DSP_RST_PIN_MASK			(0x1 << 10)
+#define RT5640_DSP_RST_PIN_SFT			10
+#define RT5640_DSP_RST_PIN_LO			(0x0 << 10)
+#define RT5640_DSP_RST_PIN_HI			(0x1 << 10)
+#define RT5640_DSP_R_EN				(0x1 << 9)
+#define RT5640_DSP_R_EN_BIT			9
+#define RT5640_DSP_W_EN				(0x1 << 8)
+#define RT5640_DSP_W_EN_BIT			8
+#define RT5640_DSP_CMD_MASK			(0xff)
+#define RT5640_DSP_CMD_SFT			0
+#define RT5640_DSP_CMD_MW			(0x3B)	/* Memory Write */
+#define RT5640_DSP_CMD_MR			(0x37)	/* Memory Read */
+#define RT5640_DSP_CMD_RR			(0x60)	/* Register Read */
+#define RT5640_DSP_CMD_RW			(0x68)	/* Register Write */
+
+/* Programmable Register Array Control 1 (0xc8) */
+#define RT5640_REG_SEQ_MASK			(0xf << 12)
+#define RT5640_REG_SEQ_SFT			12
+#define RT5640_SEQ1_ST_MASK			(0x1 << 11) /*RO*/
+#define RT5640_SEQ1_ST_SFT			11
+#define RT5640_SEQ1_ST_RUN			(0x0 << 11)
+#define RT5640_SEQ1_ST_FIN			(0x1 << 11)
+#define RT5640_SEQ2_ST_MASK			(0x1 << 10) /*RO*/
+#define RT5640_SEQ2_ST_SFT			10
+#define RT5640_SEQ2_ST_RUN			(0x0 << 10)
+#define RT5640_SEQ2_ST_FIN			(0x1 << 10)
+#define RT5640_REG_LV_MASK			(0x1 << 9)
+#define RT5640_REG_LV_SFT			9
+#define RT5640_REG_LV_MX			(0x0 << 9)
+#define RT5640_REG_LV_PR			(0x1 << 9)
+#define RT5640_SEQ_2_PT_MASK			(0x1 << 8)
+#define RT5640_SEQ_2_PT_BIT			8
+#define RT5640_REG_IDX_MASK			(0xff)
+#define RT5640_REG_IDX_SFT			0
+
+/* Programmable Register Array Control 2 (0xc9) */
+#define RT5640_REG_DAT_MASK			(0xffff)
+#define RT5640_REG_DAT_SFT			0
+
+/* Programmable Register Array Control 3 (0xca) */
+#define RT5640_SEQ_DLY_MASK			(0xff << 8)
+#define RT5640_SEQ_DLY_SFT			8
+#define RT5640_PROG_MASK			(0x1 << 7)
+#define RT5640_PROG_SFT				7
+#define RT5640_PROG_DIS				(0x0 << 7)
+#define RT5640_PROG_EN				(0x1 << 7)
+#define RT5640_SEQ1_PT_RUN			(0x1 << 6)
+#define RT5640_SEQ1_PT_RUN_BIT			6
+#define RT5640_SEQ2_PT_RUN			(0x1 << 5)
+#define RT5640_SEQ2_PT_RUN_BIT			5
+
+/* Programmable Register Array Control 4 (0xcb) */
+#define RT5640_SEQ1_START_MASK			(0xf << 8)
+#define RT5640_SEQ1_START_SFT			8
+#define RT5640_SEQ1_END_MASK			(0xf)
+#define RT5640_SEQ1_END_SFT			0
+
+/* Programmable Register Array Control 5 (0xcc) */
+#define RT5640_SEQ2_START_MASK			(0xf << 8)
+#define RT5640_SEQ2_START_SFT			8
+#define RT5640_SEQ2_END_MASK			(0xf)
+#define RT5640_SEQ2_END_SFT			0
+
+/* Scramble Function (0xcd) */
+#define RT5640_SCB_KEY_MASK			(0xff)
+#define RT5640_SCB_KEY_SFT			0
+
+/* Scramble Control (0xce) */
+#define RT5640_SCB_SWAP_MASK			(0x1 << 15)
+#define RT5640_SCB_SWAP_SFT			15
+#define RT5640_SCB_SWAP_DIS			(0x0 << 15)
+#define RT5640_SCB_SWAP_EN			(0x1 << 15)
+#define RT5640_SCB_MASK				(0x1 << 14)
+#define RT5640_SCB_SFT				14
+#define RT5640_SCB_DIS				(0x0 << 14)
+#define RT5640_SCB_EN				(0x1 << 14)
+
+/* Baseback Control (0xcf) */
+#define RT5640_BB_MASK				(0x1 << 15)
+#define RT5640_BB_SFT				15
+#define RT5640_BB_DIS				(0x0 << 15)
+#define RT5640_BB_EN				(0x1 << 15)
+#define RT5640_BB_CT_MASK			(0x7 << 12)
+#define RT5640_BB_CT_SFT			12
+#define RT5640_BB_CT_A				(0x0 << 12)
+#define RT5640_BB_CT_B				(0x1 << 12)
+#define RT5640_BB_CT_C				(0x2 << 12)
+#define RT5640_BB_CT_D				(0x3 << 12)
+#define RT5640_M_BB_L_MASK			(0x1 << 9)
+#define RT5640_M_BB_L_SFT			9
+#define RT5640_M_BB_R_MASK			(0x1 << 8)
+#define RT5640_M_BB_R_SFT			8
+#define RT5640_M_BB_HPF_L_MASK			(0x1 << 7)
+#define RT5640_M_BB_HPF_L_SFT			7
+#define RT5640_M_BB_HPF_R_MASK			(0x1 << 6)
+#define RT5640_M_BB_HPF_R_SFT			6
+#define RT5640_G_BB_BST_MASK			(0x3f)
+#define RT5640_G_BB_BST_SFT			0
+
+/* MP3 Plus Control 1 (0xd0) */
+#define RT5640_M_MP3_L_MASK			(0x1 << 15)
+#define RT5640_M_MP3_L_SFT			15
+#define RT5640_M_MP3_R_MASK			(0x1 << 14)
+#define RT5640_M_MP3_R_SFT			14
+#define RT5640_M_MP3_MASK			(0x1 << 13)
+#define RT5640_M_MP3_SFT			13
+#define RT5640_M_MP3_DIS			(0x0 << 13)
+#define RT5640_M_MP3_EN				(0x1 << 13)
+#define RT5640_EG_MP3_MASK			(0x1f << 8)
+#define RT5640_EG_MP3_SFT			8
+#define RT5640_MP3_HLP_MASK			(0x1 << 7)
+#define RT5640_MP3_HLP_SFT			7
+#define RT5640_MP3_HLP_DIS			(0x0 << 7)
+#define RT5640_MP3_HLP_EN			(0x1 << 7)
+#define RT5640_M_MP3_ORG_L_MASK			(0x1 << 6)
+#define RT5640_M_MP3_ORG_L_SFT			6
+#define RT5640_M_MP3_ORG_R_MASK			(0x1 << 5)
+#define RT5640_M_MP3_ORG_R_SFT			5
+
+/* MP3 Plus Control 2 (0xd1) */
+#define RT5640_MP3_WT_MASK			(0x1 << 13)
+#define RT5640_MP3_WT_SFT			13
+#define RT5640_MP3_WT_1_4			(0x0 << 13)
+#define RT5640_MP3_WT_1_2			(0x1 << 13)
+#define RT5640_OG_MP3_MASK			(0x1f << 8)
+#define RT5640_OG_MP3_SFT			8
+#define RT5640_HG_MP3_MASK			(0x3f)
+#define RT5640_HG_MP3_SFT			0
+
+/* 3D HP Control 1 (0xd2) */
+#define RT5640_3D_CF_MASK			(0x1 << 15)
+#define RT5640_3D_CF_SFT			15
+#define RT5640_3D_CF_DIS			(0x0 << 15)
+#define RT5640_3D_CF_EN				(0x1 << 15)
+#define RT5640_3D_HP_MASK			(0x1 << 14)
+#define RT5640_3D_HP_SFT			14
+#define RT5640_3D_HP_DIS			(0x0 << 14)
+#define RT5640_3D_HP_EN				(0x1 << 14)
+#define RT5640_3D_BT_MASK			(0x1 << 13)
+#define RT5640_3D_BT_SFT			13
+#define RT5640_3D_BT_DIS			(0x0 << 13)
+#define RT5640_3D_BT_EN				(0x1 << 13)
+#define RT5640_3D_1F_MIX_MASK			(0x3 << 11)
+#define RT5640_3D_1F_MIX_SFT			11
+#define RT5640_3D_HP_M_MASK			(0x1 << 10)
+#define RT5640_3D_HP_M_SFT			10
+#define RT5640_3D_HP_M_SUR			(0x0 << 10)
+#define RT5640_3D_HP_M_FRO			(0x1 << 10)
+#define RT5640_M_3D_HRTF_MASK			(0x1 << 9)
+#define RT5640_M_3D_HRTF_SFT			9
+#define RT5640_M_3D_D2H_MASK			(0x1 << 8)
+#define RT5640_M_3D_D2H_SFT			8
+#define RT5640_M_3D_D2R_MASK			(0x1 << 7)
+#define RT5640_M_3D_D2R_SFT			7
+#define RT5640_M_3D_REVB_MASK			(0x1 << 6)
+#define RT5640_M_3D_REVB_SFT			6
+
+/* Adjustable high pass filter control 1 (0xd3) */
+#define RT5640_2ND_HPF_MASK			(0x1 << 15)
+#define RT5640_2ND_HPF_SFT			15
+#define RT5640_2ND_HPF_DIS			(0x0 << 15)
+#define RT5640_2ND_HPF_EN			(0x1 << 15)
+#define RT5640_HPF_CF_L_MASK			(0x7 << 12)
+#define RT5640_HPF_CF_L_SFT			12
+#define RT5640_1ST_HPF_MASK			(0x1 << 11)
+#define RT5640_1ST_HPF_SFT			11
+#define RT5640_1ST_HPF_DIS			(0x0 << 11)
+#define RT5640_1ST_HPF_EN			(0x1 << 11)
+#define RT5640_HPF_CF_R_MASK			(0x7 << 8)
+#define RT5640_HPF_CF_R_SFT			8
+#define RT5640_ZD_T_MASK			(0x3 << 6)
+#define RT5640_ZD_T_SFT				6
+#define RT5640_ZD_F_MASK			(0x3 << 4)
+#define RT5640_ZD_F_SFT				4
+#define RT5640_ZD_F_IM				(0x0 << 4)
+#define RT5640_ZD_F_ZC_IM			(0x1 << 4)
+#define RT5640_ZD_F_ZC_IOD			(0x2 << 4)
+#define RT5640_ZD_F_UN				(0x3 << 4)
+
+/* HP calibration control and Amp detection (0xd6) */
+#define RT5640_SI_DAC_MASK			(0x1 << 11)
+#define RT5640_SI_DAC_SFT			11
+#define RT5640_SI_DAC_AUTO			(0x0 << 11)
+#define RT5640_SI_DAC_TEST			(0x1 << 11)
+#define RT5640_DC_CAL_M_MASK			(0x1 << 10)
+#define RT5640_DC_CAL_M_SFT			10
+#define RT5640_DC_CAL_M_CAL			(0x0 << 10)
+#define RT5640_DC_CAL_M_NOR			(0x1 << 10)
+#define RT5640_DC_CAL_MASK			(0x1 << 9)
+#define RT5640_DC_CAL_SFT			9
+#define RT5640_DC_CAL_DIS			(0x0 << 9)
+#define RT5640_DC_CAL_EN			(0x1 << 9)
+#define RT5640_HPD_RCV_MASK			(0x7 << 6)
+#define RT5640_HPD_RCV_SFT			6
+#define RT5640_HPD_PS_MASK			(0x1 << 5)
+#define RT5640_HPD_PS_SFT			5
+#define RT5640_HPD_PS_DIS			(0x0 << 5)
+#define RT5640_HPD_PS_EN			(0x1 << 5)
+#define RT5640_CAL_M_MASK			(0x1 << 4)
+#define RT5640_CAL_M_SFT			4
+#define RT5640_CAL_M_DEP			(0x0 << 4)
+#define RT5640_CAL_M_CAL			(0x1 << 4)
+#define RT5640_CAL_MASK				(0x1 << 3)
+#define RT5640_CAL_SFT				3
+#define RT5640_CAL_DIS				(0x0 << 3)
+#define RT5640_CAL_EN				(0x1 << 3)
+#define RT5640_CAL_TEST_MASK			(0x1 << 2)
+#define RT5640_CAL_TEST_SFT			2
+#define RT5640_CAL_TEST_DIS			(0x0 << 2)
+#define RT5640_CAL_TEST_EN			(0x1 << 2)
+#define RT5640_CAL_P_MASK			(0x3)
+#define RT5640_CAL_P_SFT			0
+#define RT5640_CAL_P_NONE			(0x0)
+#define RT5640_CAL_P_CAL			(0x1)
+#define RT5640_CAL_P_DAC_CAL			(0x2)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5640_SV_MASK				(0x1 << 15)
+#define RT5640_SV_SFT				15
+#define RT5640_SV_DIS				(0x0 << 15)
+#define RT5640_SV_EN				(0x1 << 15)
+#define RT5640_SPO_SV_MASK			(0x1 << 14)
+#define RT5640_SPO_SV_SFT			14
+#define RT5640_SPO_SV_DIS			(0x0 << 14)
+#define RT5640_SPO_SV_EN			(0x1 << 14)
+#define RT5640_OUT_SV_MASK			(0x1 << 13)
+#define RT5640_OUT_SV_SFT			13
+#define RT5640_OUT_SV_DIS			(0x0 << 13)
+#define RT5640_OUT_SV_EN			(0x1 << 13)
+#define RT5640_HP_SV_MASK			(0x1 << 12)
+#define RT5640_HP_SV_SFT			12
+#define RT5640_HP_SV_DIS			(0x0 << 12)
+#define RT5640_HP_SV_EN				(0x1 << 12)
+#define RT5640_ZCD_DIG_MASK			(0x1 << 11)
+#define RT5640_ZCD_DIG_SFT			11
+#define RT5640_ZCD_DIG_DIS			(0x0 << 11)
+#define RT5640_ZCD_DIG_EN			(0x1 << 11)
+#define RT5640_ZCD_MASK				(0x1 << 10)
+#define RT5640_ZCD_SFT				10
+#define RT5640_ZCD_PD				(0x0 << 10)
+#define RT5640_ZCD_PU				(0x1 << 10)
+#define RT5640_M_ZCD_MASK			(0x3f << 4)
+#define RT5640_M_ZCD_SFT			4
+#define RT5640_M_ZCD_RM_L			(0x1 << 9)
+#define RT5640_M_ZCD_RM_R			(0x1 << 8)
+#define RT5640_M_ZCD_SM_L			(0x1 << 7)
+#define RT5640_M_ZCD_SM_R			(0x1 << 6)
+#define RT5640_M_ZCD_OM_L			(0x1 << 5)
+#define RT5640_M_ZCD_OM_R			(0x1 << 4)
+#define RT5640_SV_DLY_MASK			(0xf)
+#define RT5640_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5640_ZCD_HP_MASK			(0x1 << 15)
+#define RT5640_ZCD_HP_SFT			15
+#define RT5640_ZCD_HP_DIS			(0x0 << 15)
+#define RT5640_ZCD_HP_EN			(0x1 << 15)
+
+/* General Control 1 (0xfa) */
+#define RT5640_M_MONO_ADC_L			(0x1 << 13)
+#define RT5640_M_MONO_ADC_L_SFT			13
+#define RT5640_M_MONO_ADC_R			(0x1 << 12)
+#define RT5640_M_MONO_ADC_R_SFT			12
+#define RT5640_MCLK_DET				(0x1 << 11)
+
+/* Codec Private Register definition */
+
+/* MIC Over current threshold scale factor (0x15) */
+#define RT5640_MIC_OVCD_SF_MASK			(0x3 << 8)
+#define RT5640_MIC_OVCD_SF_SFT			8
+#define RT5640_MIC_OVCD_SF_0P5			(0x0 << 8)
+#define RT5640_MIC_OVCD_SF_0P75			(0x1 << 8)
+#define RT5640_MIC_OVCD_SF_1P0			(0x2 << 8)
+#define RT5640_MIC_OVCD_SF_1P5			(0x3 << 8)
+
+/* 3D Speaker Control (0x63) */
+#define RT5640_3D_SPK_MASK			(0x1 << 15)
+#define RT5640_3D_SPK_SFT			15
+#define RT5640_3D_SPK_DIS			(0x0 << 15)
+#define RT5640_3D_SPK_EN			(0x1 << 15)
+#define RT5640_3D_SPK_M_MASK			(0x3 << 13)
+#define RT5640_3D_SPK_M_SFT			13
+#define RT5640_3D_SPK_CG_MASK			(0x1f << 8)
+#define RT5640_3D_SPK_CG_SFT			8
+#define RT5640_3D_SPK_SG_MASK			(0x1f)
+#define RT5640_3D_SPK_SG_SFT			0
+
+/* Wind Noise Detection Control 1 (0x6c) */
+#define RT5640_WND_MASK				(0x1 << 15)
+#define RT5640_WND_SFT				15
+#define RT5640_WND_DIS				(0x0 << 15)
+#define RT5640_WND_EN				(0x1 << 15)
+
+/* Wind Noise Detection Control 2 (0x6d) */
+#define RT5640_WND_FC_NW_MASK			(0x3f << 10)
+#define RT5640_WND_FC_NW_SFT			10
+#define RT5640_WND_FC_WK_MASK			(0x3f << 4)
+#define RT5640_WND_FC_WK_SFT			4
+
+/* Wind Noise Detection Control 3 (0x6e) */
+#define RT5640_HPF_FC_MASK			(0x3f << 6)
+#define RT5640_HPF_FC_SFT			6
+#define RT5640_WND_FC_ST_MASK			(0x3f)
+#define RT5640_WND_FC_ST_SFT			0
+
+/* Wind Noise Detection Control 4 (0x6f) */
+#define RT5640_WND_TH_LO_MASK			(0x3ff)
+#define RT5640_WND_TH_LO_SFT			0
+
+/* Wind Noise Detection Control 5 (0x70) */
+#define RT5640_WND_TH_HI_MASK			(0x3ff)
+#define RT5640_WND_TH_HI_SFT			0
+
+/* Wind Noise Detection Control 8 (0x73) */
+#define RT5640_WND_WIND_MASK			(0x1 << 13) /* Read-Only */
+#define RT5640_WND_WIND_SFT			13
+#define RT5640_WND_STRONG_MASK			(0x1 << 12) /* Read-Only */
+#define RT5640_WND_STRONG_SFT			12
+enum {
+	RT5640_NO_WIND,
+	RT5640_BREEZE,
+	RT5640_STORM,
+};
+
+/* Dipole Speaker Interface (0x75) */
+#define RT5640_DP_ATT_MASK			(0x3 << 14)
+#define RT5640_DP_ATT_SFT			14
+#define RT5640_DP_SPK_MASK			(0x1 << 10)
+#define RT5640_DP_SPK_SFT			10
+#define RT5640_DP_SPK_DIS			(0x0 << 10)
+#define RT5640_DP_SPK_EN			(0x1 << 10)
+
+/* EQ Pre Volume Control (0xb3) */
+#define RT5640_EQ_PRE_VOL_MASK			(0xffff)
+#define RT5640_EQ_PRE_VOL_SFT			0
+
+/* EQ Post Volume Control (0xb4) */
+#define RT5640_EQ_PST_VOL_MASK			(0xffff)
+#define RT5640_EQ_PST_VOL_SFT			0
+
+#define RT5640_NO_JACK		BIT(0)
+#define RT5640_HEADSET_DET	BIT(1)
+#define RT5640_HEADPHO_DET	BIT(2)
+
+/* System Clock Source */
+#define RT5640_SCLK_S_MCLK	0
+#define RT5640_SCLK_S_PLL1	1
+#define RT5640_SCLK_S_PLL1_TK	2
+#define RT5640_SCLK_S_RCCLK	3
+
+/* PLL1 Source */
+#define RT5640_PLL1_S_MCLK	0
+#define RT5640_PLL1_S_BCLK1	1
+#define RT5640_PLL1_S_BCLK2	2
+#define RT5640_PLL1_S_BCLK3	3
+
+
+enum {
+	RT5640_AIF1,
+	RT5640_AIF2,
+	RT5640_AIF3,
+	RT5640_AIFS,
+};
+
+enum {
+	RT5640_U_IF1 = 0x1,
+	RT5640_U_IF2 = 0x2,
+	RT5640_U_IF3 = 0x4,
+};
+
+enum {
+	RT5640_IF_123,
+	RT5640_IF_132,
+	RT5640_IF_312,
+	RT5640_IF_321,
+	RT5640_IF_231,
+	RT5640_IF_213,
+	RT5640_IF_113,
+	RT5640_IF_223,
+	RT5640_IF_ALL,
+};
+
+enum {
+	RT5640_DMIC_DIS,
+	RT5640_DMIC1,
+	RT5640_DMIC2,
+};
+
+/* filter mask */
+enum {
+	RT5640_DA_STEREO_FILTER = 0x1,
+	RT5640_DA_MONO_L_FILTER = (0x1 << 1),
+	RT5640_DA_MONO_R_FILTER = (0x1 << 2),
+	RT5640_AD_STEREO_FILTER = (0x1 << 3),
+	RT5640_AD_MONO_L_FILTER = (0x1 << 4),
+	RT5640_AD_MONO_R_FILTER = (0x1 << 5),
+};
+
+struct rt5640_priv {
+	struct snd_soc_component *component;
+	struct regmap *regmap;
+	struct clk *mclk;
+
+	int ldo1_en; /* GPIO for LDO1_EN */
+	int irq;
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5640_AIFS];
+	int bclk[RT5640_AIFS];
+	int master[RT5640_AIFS];
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+	bool hp_mute;
+	bool asrc_en;
+
+	/* Jack and button detect data */
+	bool ovcd_irq_enabled;
+	bool pressed;
+	bool press_reported;
+	int press_count;
+	int release_count;
+	int poll_count;
+	struct delayed_work bp_work;
+	struct work_struct jack_work;
+	struct snd_soc_jack *jack;
+	unsigned int jd_src;
+	bool jd_inverted;
+	unsigned int ovcd_th;
+	unsigned int ovcd_sf;
+};
+
+int rt5640_dmic_enable(struct snd_soc_component *component,
+		       bool dmic1_data_pin, bool dmic2_data_pin);
+int rt5640_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src);
+
+#endif
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
new file mode 100644
index 0000000..1dc70f4
--- /dev/null
+++ b/sound/soc/codecs/rt5645.c
@@ -0,0 +1,4114 @@
+/*
+ * rt5645.c  --  RT5645 ALSA SoC audio codec driver
+ *
+ * Copyright 2013 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/regulator/consumer.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rl6231.h"
+#include "rt5645.h"
+
+#define QUIRK_INV_JD1_1(q)	((q) & 1)
+#define QUIRK_LEVEL_IRQ(q)	(((q) >> 1) & 1)
+#define QUIRK_IN2_DIFF(q)	(((q) >> 2) & 1)
+#define QUIRK_JD_MODE(q)	(((q) >> 4) & 7)
+#define QUIRK_DMIC1_DATA_PIN(q)	(((q) >> 8) & 3)
+#define QUIRK_DMIC2_DATA_PIN(q)	(((q) >> 12) & 3)
+
+static unsigned int quirk = -1;
+module_param(quirk, uint, 0444);
+MODULE_PARM_DESC(quirk, "RT5645 pdata quirk override");
+
+#define RT5645_DEVICE_ID 0x6308
+#define RT5650_DEVICE_ID 0x6419
+
+#define RT5645_PR_RANGE_BASE (0xff + 1)
+#define RT5645_PR_SPACING 0x100
+
+#define RT5645_PR_BASE (RT5645_PR_RANGE_BASE + (0 * RT5645_PR_SPACING))
+
+#define RT5645_HWEQ_NUM 57
+
+#define TIME_TO_POWER_MS 400
+
+static const struct regmap_range_cfg rt5645_ranges[] = {
+	{
+		.name = "PR",
+		.range_min = RT5645_PR_BASE,
+		.range_max = RT5645_PR_BASE + 0xf8,
+		.selector_reg = RT5645_PRIV_INDEX,
+		.selector_mask = 0xff,
+		.selector_shift = 0x0,
+		.window_start = RT5645_PRIV_DATA,
+		.window_len = 0x1,
+	},
+};
+
+static const struct reg_sequence init_list[] = {
+	{RT5645_PR_BASE + 0x3d,	0x3600},
+	{RT5645_PR_BASE + 0x1c,	0xfd70},
+	{RT5645_PR_BASE + 0x20,	0x611f},
+	{RT5645_PR_BASE + 0x21,	0x4040},
+	{RT5645_PR_BASE + 0x23,	0x0004},
+	{RT5645_ASRC_4, 0x0120},
+};
+
+static const struct reg_sequence rt5650_init_list[] = {
+	{0xf6,	0x0100},
+};
+
+static const struct reg_default rt5645_reg[] = {
+	{ 0x00, 0x0000 },
+	{ 0x01, 0xc8c8 },
+	{ 0x02, 0xc8c8 },
+	{ 0x03, 0xc8c8 },
+	{ 0x0a, 0x0002 },
+	{ 0x0b, 0x2827 },
+	{ 0x0c, 0xe000 },
+	{ 0x0d, 0x0000 },
+	{ 0x0e, 0x0000 },
+	{ 0x0f, 0x0808 },
+	{ 0x14, 0x3333 },
+	{ 0x16, 0x4b00 },
+	{ 0x18, 0x018b },
+	{ 0x19, 0xafaf },
+	{ 0x1a, 0xafaf },
+	{ 0x1b, 0x0001 },
+	{ 0x1c, 0x2f2f },
+	{ 0x1d, 0x2f2f },
+	{ 0x1e, 0x0000 },
+	{ 0x20, 0x0000 },
+	{ 0x27, 0x7060 },
+	{ 0x28, 0x7070 },
+	{ 0x29, 0x8080 },
+	{ 0x2a, 0x5656 },
+	{ 0x2b, 0x5454 },
+	{ 0x2c, 0xaaa0 },
+	{ 0x2d, 0x0000 },
+	{ 0x2f, 0x1002 },
+	{ 0x31, 0x5000 },
+	{ 0x32, 0x0000 },
+	{ 0x33, 0x0000 },
+	{ 0x34, 0x0000 },
+	{ 0x35, 0x0000 },
+	{ 0x3b, 0x0000 },
+	{ 0x3c, 0x007f },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x007f },
+	{ 0x3f, 0x0000 },
+	{ 0x40, 0x001f },
+	{ 0x41, 0x0000 },
+	{ 0x42, 0x001f },
+	{ 0x45, 0x6000 },
+	{ 0x46, 0x003e },
+	{ 0x47, 0x003e },
+	{ 0x48, 0xf807 },
+	{ 0x4a, 0x0004 },
+	{ 0x4d, 0x0000 },
+	{ 0x4e, 0x0000 },
+	{ 0x4f, 0x01ff },
+	{ 0x50, 0x0000 },
+	{ 0x51, 0x0000 },
+	{ 0x52, 0x01ff },
+	{ 0x53, 0xf000 },
+	{ 0x56, 0x0111 },
+	{ 0x57, 0x0064 },
+	{ 0x58, 0xef0e },
+	{ 0x59, 0xf0f0 },
+	{ 0x5a, 0xef0e },
+	{ 0x5b, 0xf0f0 },
+	{ 0x5c, 0xef0e },
+	{ 0x5d, 0xf0f0 },
+	{ 0x5e, 0xf000 },
+	{ 0x5f, 0x0000 },
+	{ 0x61, 0x0300 },
+	{ 0x62, 0x0000 },
+	{ 0x63, 0x00c2 },
+	{ 0x64, 0x0000 },
+	{ 0x65, 0x0000 },
+	{ 0x66, 0x0000 },
+	{ 0x6a, 0x0000 },
+	{ 0x6c, 0x0aaa },
+	{ 0x70, 0x8000 },
+	{ 0x71, 0x8000 },
+	{ 0x72, 0x8000 },
+	{ 0x73, 0x7770 },
+	{ 0x74, 0x3e00 },
+	{ 0x75, 0x2409 },
+	{ 0x76, 0x000a },
+	{ 0x77, 0x0c00 },
+	{ 0x78, 0x0000 },
+	{ 0x79, 0x0123 },
+	{ 0x80, 0x0000 },
+	{ 0x81, 0x0000 },
+	{ 0x82, 0x0000 },
+	{ 0x83, 0x0000 },
+	{ 0x84, 0x0000 },
+	{ 0x85, 0x0000 },
+	{ 0x8a, 0x0120 },
+	{ 0x8e, 0x0004 },
+	{ 0x8f, 0x1100 },
+	{ 0x90, 0x0646 },
+	{ 0x91, 0x0c06 },
+	{ 0x93, 0x0000 },
+	{ 0x94, 0x0200 },
+	{ 0x95, 0x0000 },
+	{ 0x9a, 0x2184 },
+	{ 0x9b, 0x010a },
+	{ 0x9c, 0x0aea },
+	{ 0x9d, 0x000c },
+	{ 0x9e, 0x0400 },
+	{ 0xa0, 0xa0a8 },
+	{ 0xa1, 0x0059 },
+	{ 0xa2, 0x0001 },
+	{ 0xae, 0x6000 },
+	{ 0xaf, 0x0000 },
+	{ 0xb0, 0x6000 },
+	{ 0xb1, 0x0000 },
+	{ 0xb2, 0x0000 },
+	{ 0xb3, 0x001f },
+	{ 0xb4, 0x020c },
+	{ 0xb5, 0x1f00 },
+	{ 0xb6, 0x0000 },
+	{ 0xbb, 0x0000 },
+	{ 0xbc, 0x0000 },
+	{ 0xbd, 0x0000 },
+	{ 0xbe, 0x0000 },
+	{ 0xbf, 0x3100 },
+	{ 0xc0, 0x0000 },
+	{ 0xc1, 0x0000 },
+	{ 0xc2, 0x0000 },
+	{ 0xc3, 0x2000 },
+	{ 0xcd, 0x0000 },
+	{ 0xce, 0x0000 },
+	{ 0xcf, 0x1813 },
+	{ 0xd0, 0x0690 },
+	{ 0xd1, 0x1c17 },
+	{ 0xd3, 0xb320 },
+	{ 0xd4, 0x0000 },
+	{ 0xd6, 0x0400 },
+	{ 0xd9, 0x0809 },
+	{ 0xda, 0x0000 },
+	{ 0xdb, 0x0003 },
+	{ 0xdc, 0x0049 },
+	{ 0xdd, 0x001b },
+	{ 0xdf, 0x0008 },
+	{ 0xe0, 0x4000 },
+	{ 0xe6, 0x8000 },
+	{ 0xe7, 0x0200 },
+	{ 0xec, 0xb300 },
+	{ 0xed, 0x0000 },
+	{ 0xf0, 0x001f },
+	{ 0xf1, 0x020c },
+	{ 0xf2, 0x1f00 },
+	{ 0xf3, 0x0000 },
+	{ 0xf4, 0x4000 },
+	{ 0xf8, 0x0000 },
+	{ 0xf9, 0x0000 },
+	{ 0xfa, 0x2060 },
+	{ 0xfb, 0x4040 },
+	{ 0xfc, 0x0000 },
+	{ 0xfd, 0x0002 },
+	{ 0xfe, 0x10ec },
+	{ 0xff, 0x6308 },
+};
+
+static const struct reg_default rt5650_reg[] = {
+	{ 0x00, 0x0000 },
+	{ 0x01, 0xc8c8 },
+	{ 0x02, 0xc8c8 },
+	{ 0x03, 0xc8c8 },
+	{ 0x0a, 0x0002 },
+	{ 0x0b, 0x2827 },
+	{ 0x0c, 0xe000 },
+	{ 0x0d, 0x0000 },
+	{ 0x0e, 0x0000 },
+	{ 0x0f, 0x0808 },
+	{ 0x14, 0x3333 },
+	{ 0x16, 0x4b00 },
+	{ 0x18, 0x018b },
+	{ 0x19, 0xafaf },
+	{ 0x1a, 0xafaf },
+	{ 0x1b, 0x0001 },
+	{ 0x1c, 0x2f2f },
+	{ 0x1d, 0x2f2f },
+	{ 0x1e, 0x0000 },
+	{ 0x20, 0x0000 },
+	{ 0x27, 0x7060 },
+	{ 0x28, 0x7070 },
+	{ 0x29, 0x8080 },
+	{ 0x2a, 0x5656 },
+	{ 0x2b, 0x5454 },
+	{ 0x2c, 0xaaa0 },
+	{ 0x2d, 0x0000 },
+	{ 0x2f, 0x5002 },
+	{ 0x31, 0x5000 },
+	{ 0x32, 0x0000 },
+	{ 0x33, 0x0000 },
+	{ 0x34, 0x0000 },
+	{ 0x35, 0x0000 },
+	{ 0x3b, 0x0000 },
+	{ 0x3c, 0x007f },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x007f },
+	{ 0x3f, 0x0000 },
+	{ 0x40, 0x001f },
+	{ 0x41, 0x0000 },
+	{ 0x42, 0x001f },
+	{ 0x45, 0x6000 },
+	{ 0x46, 0x003e },
+	{ 0x47, 0x003e },
+	{ 0x48, 0xf807 },
+	{ 0x4a, 0x0004 },
+	{ 0x4d, 0x0000 },
+	{ 0x4e, 0x0000 },
+	{ 0x4f, 0x01ff },
+	{ 0x50, 0x0000 },
+	{ 0x51, 0x0000 },
+	{ 0x52, 0x01ff },
+	{ 0x53, 0xf000 },
+	{ 0x56, 0x0111 },
+	{ 0x57, 0x0064 },
+	{ 0x58, 0xef0e },
+	{ 0x59, 0xf0f0 },
+	{ 0x5a, 0xef0e },
+	{ 0x5b, 0xf0f0 },
+	{ 0x5c, 0xef0e },
+	{ 0x5d, 0xf0f0 },
+	{ 0x5e, 0xf000 },
+	{ 0x5f, 0x0000 },
+	{ 0x61, 0x0300 },
+	{ 0x62, 0x0000 },
+	{ 0x63, 0x00c2 },
+	{ 0x64, 0x0000 },
+	{ 0x65, 0x0000 },
+	{ 0x66, 0x0000 },
+	{ 0x6a, 0x0000 },
+	{ 0x6c, 0x0aaa },
+	{ 0x70, 0x8000 },
+	{ 0x71, 0x8000 },
+	{ 0x72, 0x8000 },
+	{ 0x73, 0x7770 },
+	{ 0x74, 0x3e00 },
+	{ 0x75, 0x2409 },
+	{ 0x76, 0x000a },
+	{ 0x77, 0x0c00 },
+	{ 0x78, 0x0000 },
+	{ 0x79, 0x0123 },
+	{ 0x7a, 0x0123 },
+	{ 0x80, 0x0000 },
+	{ 0x81, 0x0000 },
+	{ 0x82, 0x0000 },
+	{ 0x83, 0x0000 },
+	{ 0x84, 0x0000 },
+	{ 0x85, 0x0000 },
+	{ 0x8a, 0x0120 },
+	{ 0x8e, 0x0004 },
+	{ 0x8f, 0x1100 },
+	{ 0x90, 0x0646 },
+	{ 0x91, 0x0c06 },
+	{ 0x93, 0x0000 },
+	{ 0x94, 0x0200 },
+	{ 0x95, 0x0000 },
+	{ 0x9a, 0x2184 },
+	{ 0x9b, 0x010a },
+	{ 0x9c, 0x0aea },
+	{ 0x9d, 0x000c },
+	{ 0x9e, 0x0400 },
+	{ 0xa0, 0xa0a8 },
+	{ 0xa1, 0x0059 },
+	{ 0xa2, 0x0001 },
+	{ 0xae, 0x6000 },
+	{ 0xaf, 0x0000 },
+	{ 0xb0, 0x6000 },
+	{ 0xb1, 0x0000 },
+	{ 0xb2, 0x0000 },
+	{ 0xb3, 0x001f },
+	{ 0xb4, 0x020c },
+	{ 0xb5, 0x1f00 },
+	{ 0xb6, 0x0000 },
+	{ 0xbb, 0x0000 },
+	{ 0xbc, 0x0000 },
+	{ 0xbd, 0x0000 },
+	{ 0xbe, 0x0000 },
+	{ 0xbf, 0x3100 },
+	{ 0xc0, 0x0000 },
+	{ 0xc1, 0x0000 },
+	{ 0xc2, 0x0000 },
+	{ 0xc3, 0x2000 },
+	{ 0xcd, 0x0000 },
+	{ 0xce, 0x0000 },
+	{ 0xcf, 0x1813 },
+	{ 0xd0, 0x0690 },
+	{ 0xd1, 0x1c17 },
+	{ 0xd3, 0xb320 },
+	{ 0xd4, 0x0000 },
+	{ 0xd6, 0x0400 },
+	{ 0xd9, 0x0809 },
+	{ 0xda, 0x0000 },
+	{ 0xdb, 0x0003 },
+	{ 0xdc, 0x0049 },
+	{ 0xdd, 0x001b },
+	{ 0xdf, 0x0008 },
+	{ 0xe0, 0x4000 },
+	{ 0xe6, 0x8000 },
+	{ 0xe7, 0x0200 },
+	{ 0xec, 0xb300 },
+	{ 0xed, 0x0000 },
+	{ 0xf0, 0x001f },
+	{ 0xf1, 0x020c },
+	{ 0xf2, 0x1f00 },
+	{ 0xf3, 0x0000 },
+	{ 0xf4, 0x4000 },
+	{ 0xf8, 0x0000 },
+	{ 0xf9, 0x0000 },
+	{ 0xfa, 0x2060 },
+	{ 0xfb, 0x4040 },
+	{ 0xfc, 0x0000 },
+	{ 0xfd, 0x0002 },
+	{ 0xfe, 0x10ec },
+	{ 0xff, 0x6308 },
+};
+
+struct rt5645_eq_param_s {
+	unsigned short reg;
+	unsigned short val;
+};
+
+static const char *const rt5645_supply_names[] = {
+	"avdd",
+	"cpvdd",
+};
+
+struct rt5645_priv {
+	struct snd_soc_component *component;
+	struct rt5645_platform_data pdata;
+	struct regmap *regmap;
+	struct i2c_client *i2c;
+	struct gpio_desc *gpiod_hp_det;
+	struct snd_soc_jack *hp_jack;
+	struct snd_soc_jack *mic_jack;
+	struct snd_soc_jack *btn_jack;
+	struct delayed_work jack_detect_work, rcclock_work;
+	struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)];
+	struct rt5645_eq_param_s *eq_param;
+	struct timer_list btn_check_timer;
+
+	int codec_type;
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5645_AIFS];
+	int bclk[RT5645_AIFS];
+	int master[RT5645_AIFS];
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+	int jack_type;
+	bool en_button_func;
+	bool hp_on;
+	int v_id;
+};
+
+static int rt5645_reset(struct snd_soc_component *component)
+{
+	return snd_soc_component_write(component, RT5645_RESET, 0);
+}
+
+static bool rt5645_volatile_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5645_ranges); i++) {
+		if (reg >= rt5645_ranges[i].range_min &&
+			reg <= rt5645_ranges[i].range_max) {
+			return true;
+		}
+	}
+
+	switch (reg) {
+	case RT5645_RESET:
+	case RT5645_PRIV_INDEX:
+	case RT5645_PRIV_DATA:
+	case RT5645_IN1_CTRL1:
+	case RT5645_IN1_CTRL2:
+	case RT5645_IN1_CTRL3:
+	case RT5645_A_JD_CTRL1:
+	case RT5645_ADC_EQ_CTRL1:
+	case RT5645_EQ_CTRL1:
+	case RT5645_ALC_CTRL_1:
+	case RT5645_IRQ_CTRL2:
+	case RT5645_IRQ_CTRL3:
+	case RT5645_INT_IRQ_ST:
+	case RT5645_IL_CMD:
+	case RT5650_4BTN_IL_CMD1:
+	case RT5645_VENDOR_ID:
+	case RT5645_VENDOR_ID1:
+	case RT5645_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5645_readable_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5645_ranges); i++) {
+		if (reg >= rt5645_ranges[i].range_min &&
+			reg <= rt5645_ranges[i].range_max) {
+			return true;
+		}
+	}
+
+	switch (reg) {
+	case RT5645_RESET:
+	case RT5645_SPK_VOL:
+	case RT5645_HP_VOL:
+	case RT5645_LOUT1:
+	case RT5645_IN1_CTRL1:
+	case RT5645_IN1_CTRL2:
+	case RT5645_IN1_CTRL3:
+	case RT5645_IN2_CTRL:
+	case RT5645_INL1_INR1_VOL:
+	case RT5645_SPK_FUNC_LIM:
+	case RT5645_ADJ_HPF_CTRL:
+	case RT5645_DAC1_DIG_VOL:
+	case RT5645_DAC2_DIG_VOL:
+	case RT5645_DAC_CTRL:
+	case RT5645_STO1_ADC_DIG_VOL:
+	case RT5645_MONO_ADC_DIG_VOL:
+	case RT5645_ADC_BST_VOL1:
+	case RT5645_ADC_BST_VOL2:
+	case RT5645_STO1_ADC_MIXER:
+	case RT5645_MONO_ADC_MIXER:
+	case RT5645_AD_DA_MIXER:
+	case RT5645_STO_DAC_MIXER:
+	case RT5645_MONO_DAC_MIXER:
+	case RT5645_DIG_MIXER:
+	case RT5650_A_DAC_SOUR:
+	case RT5645_DIG_INF1_DATA:
+	case RT5645_PDM_OUT_CTRL:
+	case RT5645_REC_L1_MIXER:
+	case RT5645_REC_L2_MIXER:
+	case RT5645_REC_R1_MIXER:
+	case RT5645_REC_R2_MIXER:
+	case RT5645_HPMIXL_CTRL:
+	case RT5645_HPOMIXL_CTRL:
+	case RT5645_HPMIXR_CTRL:
+	case RT5645_HPOMIXR_CTRL:
+	case RT5645_HPO_MIXER:
+	case RT5645_SPK_L_MIXER:
+	case RT5645_SPK_R_MIXER:
+	case RT5645_SPO_MIXER:
+	case RT5645_SPO_CLSD_RATIO:
+	case RT5645_OUT_L1_MIXER:
+	case RT5645_OUT_R1_MIXER:
+	case RT5645_OUT_L_GAIN1:
+	case RT5645_OUT_L_GAIN2:
+	case RT5645_OUT_R_GAIN1:
+	case RT5645_OUT_R_GAIN2:
+	case RT5645_LOUT_MIXER:
+	case RT5645_HAPTIC_CTRL1:
+	case RT5645_HAPTIC_CTRL2:
+	case RT5645_HAPTIC_CTRL3:
+	case RT5645_HAPTIC_CTRL4:
+	case RT5645_HAPTIC_CTRL5:
+	case RT5645_HAPTIC_CTRL6:
+	case RT5645_HAPTIC_CTRL7:
+	case RT5645_HAPTIC_CTRL8:
+	case RT5645_HAPTIC_CTRL9:
+	case RT5645_HAPTIC_CTRL10:
+	case RT5645_PWR_DIG1:
+	case RT5645_PWR_DIG2:
+	case RT5645_PWR_ANLG1:
+	case RT5645_PWR_ANLG2:
+	case RT5645_PWR_MIXER:
+	case RT5645_PWR_VOL:
+	case RT5645_PRIV_INDEX:
+	case RT5645_PRIV_DATA:
+	case RT5645_I2S1_SDP:
+	case RT5645_I2S2_SDP:
+	case RT5645_ADDA_CLK1:
+	case RT5645_ADDA_CLK2:
+	case RT5645_DMIC_CTRL1:
+	case RT5645_DMIC_CTRL2:
+	case RT5645_TDM_CTRL_1:
+	case RT5645_TDM_CTRL_2:
+	case RT5645_TDM_CTRL_3:
+	case RT5650_TDM_CTRL_4:
+	case RT5645_GLB_CLK:
+	case RT5645_PLL_CTRL1:
+	case RT5645_PLL_CTRL2:
+	case RT5645_ASRC_1:
+	case RT5645_ASRC_2:
+	case RT5645_ASRC_3:
+	case RT5645_ASRC_4:
+	case RT5645_DEPOP_M1:
+	case RT5645_DEPOP_M2:
+	case RT5645_DEPOP_M3:
+	case RT5645_CHARGE_PUMP:
+	case RT5645_MICBIAS:
+	case RT5645_A_JD_CTRL1:
+	case RT5645_VAD_CTRL4:
+	case RT5645_CLSD_OUT_CTRL:
+	case RT5645_ADC_EQ_CTRL1:
+	case RT5645_ADC_EQ_CTRL2:
+	case RT5645_EQ_CTRL1:
+	case RT5645_EQ_CTRL2:
+	case RT5645_ALC_CTRL_1:
+	case RT5645_ALC_CTRL_2:
+	case RT5645_ALC_CTRL_3:
+	case RT5645_ALC_CTRL_4:
+	case RT5645_ALC_CTRL_5:
+	case RT5645_JD_CTRL:
+	case RT5645_IRQ_CTRL1:
+	case RT5645_IRQ_CTRL2:
+	case RT5645_IRQ_CTRL3:
+	case RT5645_INT_IRQ_ST:
+	case RT5645_GPIO_CTRL1:
+	case RT5645_GPIO_CTRL2:
+	case RT5645_GPIO_CTRL3:
+	case RT5645_BASS_BACK:
+	case RT5645_MP3_PLUS1:
+	case RT5645_MP3_PLUS2:
+	case RT5645_ADJ_HPF1:
+	case RT5645_ADJ_HPF2:
+	case RT5645_HP_CALIB_AMP_DET:
+	case RT5645_SV_ZCD1:
+	case RT5645_SV_ZCD2:
+	case RT5645_IL_CMD:
+	case RT5645_IL_CMD2:
+	case RT5645_IL_CMD3:
+	case RT5650_4BTN_IL_CMD1:
+	case RT5650_4BTN_IL_CMD2:
+	case RT5645_DRC1_HL_CTRL1:
+	case RT5645_DRC2_HL_CTRL1:
+	case RT5645_ADC_MONO_HP_CTRL1:
+	case RT5645_ADC_MONO_HP_CTRL2:
+	case RT5645_DRC2_CTRL1:
+	case RT5645_DRC2_CTRL2:
+	case RT5645_DRC2_CTRL3:
+	case RT5645_DRC2_CTRL4:
+	case RT5645_DRC2_CTRL5:
+	case RT5645_JD_CTRL3:
+	case RT5645_JD_CTRL4:
+	case RT5645_GEN_CTRL1:
+	case RT5645_GEN_CTRL2:
+	case RT5645_GEN_CTRL3:
+	case RT5645_VENDOR_ID:
+	case RT5645_VENDOR_ID1:
+	case RT5645_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+/* {-6, -4.5, -3, -1.5, 0, 0.82, 1.58, 2.28} dB */
+static const DECLARE_TLV_DB_RANGE(spk_clsd_tlv,
+	0, 4, TLV_DB_SCALE_ITEM(-600, 150, 0),
+	5, 5, TLV_DB_SCALE_ITEM(82, 0, 0),
+	6, 6, TLV_DB_SCALE_ITEM(158, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(228, 0, 0)
+);
+
+static int rt5645_hweq_info(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = RT5645_HWEQ_NUM * sizeof(struct rt5645_eq_param_s);
+
+	return 0;
+}
+
+static int rt5645_hweq_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+	struct rt5645_eq_param_s *eq_param =
+		(struct rt5645_eq_param_s *)ucontrol->value.bytes.data;
+	int i;
+
+	for (i = 0; i < RT5645_HWEQ_NUM; i++) {
+		eq_param[i].reg = cpu_to_be16(rt5645->eq_param[i].reg);
+		eq_param[i].val = cpu_to_be16(rt5645->eq_param[i].val);
+	}
+
+	return 0;
+}
+
+static bool rt5645_validate_hweq(unsigned short reg)
+{
+	if ((reg >= 0x1a4 && reg <= 0x1cd) | (reg >= 0x1e5 && reg <= 0x1f8) |
+		(reg == RT5645_EQ_CTRL2))
+		return true;
+
+	return false;
+}
+
+static int rt5645_hweq_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+	struct rt5645_eq_param_s *eq_param =
+		(struct rt5645_eq_param_s *)ucontrol->value.bytes.data;
+	int i;
+
+	for (i = 0; i < RT5645_HWEQ_NUM; i++) {
+		eq_param[i].reg = be16_to_cpu(eq_param[i].reg);
+		eq_param[i].val = be16_to_cpu(eq_param[i].val);
+	}
+
+	/* The final setting of the table should be RT5645_EQ_CTRL2 */
+	for (i = RT5645_HWEQ_NUM - 1; i >= 0; i--) {
+		if (eq_param[i].reg == 0)
+			continue;
+		else if (eq_param[i].reg != RT5645_EQ_CTRL2)
+			return 0;
+		else
+			break;
+	}
+
+	for (i = 0; i < RT5645_HWEQ_NUM; i++) {
+		if (!rt5645_validate_hweq(eq_param[i].reg) &&
+			eq_param[i].reg != 0)
+			return 0;
+		else if (eq_param[i].reg == 0)
+			break;
+	}
+
+	memcpy(rt5645->eq_param, eq_param,
+		RT5645_HWEQ_NUM * sizeof(struct rt5645_eq_param_s));
+
+	return 0;
+}
+
+#define RT5645_HWEQ(xname) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = rt5645_hweq_info, \
+	.get = rt5645_hweq_get, \
+	.put = rt5645_hweq_put \
+}
+
+static int rt5645_spk_put_volsw(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
+		RT5645_PWR_CLK25M_MASK, RT5645_PWR_CLK25M_PU);
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+	mod_delayed_work(system_power_efficient_wq, &rt5645->rcclock_work,
+		msecs_to_jiffies(200));
+
+	return ret;
+}
+
+static const char * const rt5645_dac1_vol_ctrl_mode_text[] = {
+	"immediately", "zero crossing", "soft ramp"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_dac1_vol_ctrl_mode, RT5645_PR_BASE,
+	RT5645_DA1_ZDET_SFT, rt5645_dac1_vol_ctrl_mode_text);
+
+static const struct snd_kcontrol_new rt5645_snd_controls[] = {
+	/* Speaker Output Volume */
+	SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL,
+		RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1),
+	SOC_DOUBLE_EXT_TLV("Speaker Playback Volume", RT5645_SPK_VOL,
+		RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, snd_soc_get_volsw,
+		rt5645_spk_put_volsw, out_vol_tlv),
+
+	/* ClassD modulator Speaker Gain Ratio */
+	SOC_SINGLE_TLV("Speaker ClassD Playback Volume", RT5645_SPO_CLSD_RATIO,
+		RT5645_SPK_G_CLSD_SFT, 7, 0, spk_clsd_tlv),
+
+	/* Headphone Output Volume */
+	SOC_DOUBLE("Headphone Channel Switch", RT5645_HP_VOL,
+		RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1),
+	SOC_DOUBLE_TLV("Headphone Playback Volume", RT5645_HP_VOL,
+		RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+	/* OUTPUT Control */
+	SOC_DOUBLE("OUT Playback Switch", RT5645_LOUT1,
+		RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE("OUT Channel Switch", RT5645_LOUT1,
+		RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1),
+	SOC_DOUBLE_TLV("OUT Playback Volume", RT5645_LOUT1,
+		RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE("DAC2 Playback Switch", RT5645_DAC_CTRL,
+		RT5645_M_DAC_L2_VOL_SFT, RT5645_M_DAC_R2_VOL_SFT, 1, 1),
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5645_DAC1_DIG_VOL,
+		RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 87, 0, dac_vol_tlv),
+	SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5645_DAC2_DIG_VOL,
+		RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 87, 0, dac_vol_tlv),
+
+	/* IN1/IN2 Control */
+	SOC_SINGLE_TLV("IN1 Boost", RT5645_IN1_CTRL1,
+		RT5645_BST_SFT1, 12, 0, bst_tlv),
+	SOC_SINGLE_TLV("IN2 Boost", RT5645_IN2_CTRL,
+		RT5645_BST_SFT2, 8, 0, bst_tlv),
+
+	/* INL/INR Volume Control */
+	SOC_DOUBLE_TLV("IN Capture Volume", RT5645_INL1_INR1_VOL,
+		RT5645_INL_VOL_SFT, RT5645_INR_VOL_SFT, 31, 1, in_vol_tlv),
+
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("ADC Capture Switch", RT5645_STO1_ADC_DIG_VOL,
+		RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("ADC Capture Volume", RT5645_STO1_ADC_DIG_VOL,
+		RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 63, 0, adc_vol_tlv),
+	SOC_DOUBLE("Mono ADC Capture Switch", RT5645_MONO_ADC_DIG_VOL,
+		RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5645_MONO_ADC_DIG_VOL,
+		RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 63, 0, adc_vol_tlv),
+
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("ADC Boost Capture Volume", RT5645_ADC_BST_VOL1,
+		RT5645_STO1_ADC_L_BST_SFT, RT5645_STO1_ADC_R_BST_SFT, 3, 0,
+		adc_bst_tlv),
+	SOC_DOUBLE_TLV("Mono ADC Boost Capture Volume", RT5645_ADC_BST_VOL2,
+		RT5645_MONO_ADC_L_BST_SFT, RT5645_MONO_ADC_R_BST_SFT, 3, 0,
+		adc_bst_tlv),
+
+	/* I2S2 function select */
+	SOC_SINGLE("I2S2 Func Switch", RT5645_GPIO_CTRL1, RT5645_I2S2_SEL_SFT,
+		1, 1),
+	RT5645_HWEQ("Speaker HWEQ"),
+
+	/* Digital Soft Volume Control */
+	SOC_ENUM("DAC1 Digital Volume Control Func", rt5645_dac1_vol_ctrl_mode),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+	int idx, rate;
+
+	rate = rt5645->sysclk / rl6231_get_pre_div(rt5645->regmap,
+		RT5645_ADDA_CLK1, RT5645_I2S_PD1_SFT);
+	idx = rl6231_calc_dmic_clk(rate);
+	if (idx < 0)
+		dev_err(component->dev, "Failed to set DMIC clock\n");
+	else
+		snd_soc_component_update_bits(component, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_CLK_MASK, idx << RT5645_DMIC_CLK_SFT);
+	return idx;
+}
+
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	unsigned int val;
+
+	val = snd_soc_component_read32(component, RT5645_GLB_CLK);
+	val &= RT5645_SCLK_SRC_MASK;
+	if (val == RT5645_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int is_using_asrc(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	unsigned int reg, shift, val;
+
+	switch (source->shift) {
+	case 0:
+		reg = RT5645_ASRC_3;
+		shift = 0;
+		break;
+	case 1:
+		reg = RT5645_ASRC_3;
+		shift = 4;
+		break;
+	case 3:
+		reg = RT5645_ASRC_2;
+		shift = 0;
+		break;
+	case 8:
+		reg = RT5645_ASRC_2;
+		shift = 4;
+		break;
+	case 9:
+		reg = RT5645_ASRC_2;
+		shift = 8;
+		break;
+	case 10:
+		reg = RT5645_ASRC_2;
+		shift = 12;
+		break;
+	default:
+		return 0;
+	}
+
+	val = (snd_soc_component_read32(component, reg) >> shift) & 0xf;
+	switch (val) {
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+		return 1;
+	default:
+		return 0;
+	}
+
+}
+
+static int rt5645_enable_hweq(struct snd_soc_component *component)
+{
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+	int i;
+
+	for (i = 0; i < RT5645_HWEQ_NUM; i++) {
+		if (rt5645_validate_hweq(rt5645->eq_param[i].reg))
+			regmap_write(rt5645->regmap, rt5645->eq_param[i].reg,
+					rt5645->eq_param[i].val);
+		else
+			break;
+	}
+
+	return 0;
+}
+
+/**
+ * rt5645_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @component: SoC audio component device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5645 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5645_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src)
+{
+	unsigned int asrc2_mask = 0;
+	unsigned int asrc2_value = 0;
+	unsigned int asrc3_mask = 0;
+	unsigned int asrc3_value = 0;
+
+	switch (clk_src) {
+	case RT5645_CLK_SEL_SYS:
+	case RT5645_CLK_SEL_I2S1_ASRC:
+	case RT5645_CLK_SEL_I2S2_ASRC:
+	case RT5645_CLK_SEL_SYS2:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (filter_mask & RT5645_DA_STEREO_FILTER) {
+		asrc2_mask |= RT5645_DA_STO_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5645_DA_STO_CLK_SEL_MASK)
+			| (clk_src << RT5645_DA_STO_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5645_DA_MONO_L_FILTER) {
+		asrc2_mask |= RT5645_DA_MONOL_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5645_DA_MONOL_CLK_SEL_MASK)
+			| (clk_src << RT5645_DA_MONOL_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5645_DA_MONO_R_FILTER) {
+		asrc2_mask |= RT5645_DA_MONOR_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5645_DA_MONOR_CLK_SEL_MASK)
+			| (clk_src << RT5645_DA_MONOR_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5645_AD_STEREO_FILTER) {
+		asrc2_mask |= RT5645_AD_STO1_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5645_AD_STO1_CLK_SEL_MASK)
+			| (clk_src << RT5645_AD_STO1_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5645_AD_MONO_L_FILTER) {
+		asrc3_mask |= RT5645_AD_MONOL_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5645_AD_MONOL_CLK_SEL_MASK)
+			| (clk_src << RT5645_AD_MONOL_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5645_AD_MONO_R_FILTER)  {
+		asrc3_mask |= RT5645_AD_MONOR_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5645_AD_MONOR_CLK_SEL_MASK)
+			| (clk_src << RT5645_AD_MONOR_CLK_SEL_SFT);
+	}
+
+	if (asrc2_mask)
+		snd_soc_component_update_bits(component, RT5645_ASRC_2,
+			asrc2_mask, asrc2_value);
+
+	if (asrc3_mask)
+		snd_soc_component_update_bits(component, RT5645_ASRC_3,
+			asrc3_mask, asrc3_value);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5645_sel_asrc_clk_src);
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER,
+			RT5645_M_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5645_STO1_ADC_MIXER,
+			RT5645_M_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER,
+			RT5645_M_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5645_STO1_ADC_MIXER,
+			RT5645_M_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_mono_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5645_MONO_ADC_MIXER,
+			RT5645_M_MONO_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5645_MONO_ADC_MIXER,
+			RT5645_M_MONO_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_mono_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5645_MONO_ADC_MIXER,
+			RT5645_M_MONO_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5645_MONO_ADC_MIXER,
+			RT5645_M_MONO_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5645_AD_DA_MIXER,
+			RT5645_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC1 Switch", RT5645_AD_DA_MIXER,
+			RT5645_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5645_AD_DA_MIXER,
+			RT5645_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC1 Switch", RT5645_AD_DA_MIXER,
+			RT5645_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_sto_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_STO_DAC_MIXER,
+			RT5645_M_DAC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_STO_DAC_MIXER,
+			RT5645_M_DAC_L2_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_STO_DAC_MIXER,
+			RT5645_M_DAC_R1_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_sto_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_STO_DAC_MIXER,
+			RT5645_M_DAC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_STO_DAC_MIXER,
+			RT5645_M_DAC_R2_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_STO_DAC_MIXER,
+			RT5645_M_DAC_L1_STO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_mono_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_MONO_DAC_MIXER,
+			RT5645_M_DAC_L1_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_MONO_DAC_MIXER,
+			RT5645_M_DAC_L2_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_MONO_DAC_MIXER,
+			RT5645_M_DAC_R2_MONO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_mono_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_MONO_DAC_MIXER,
+			RT5645_M_DAC_R1_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_MONO_DAC_MIXER,
+			RT5645_M_DAC_R2_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_MONO_DAC_MIXER,
+			RT5645_M_DAC_L2_MONO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_dig_l_mix[] = {
+	SOC_DAPM_SINGLE("Sto DAC Mix L Switch", RT5645_DIG_MIXER,
+			RT5645_M_STO_L_DAC_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_DIG_MIXER,
+			RT5645_M_DAC_L2_DAC_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_DIG_MIXER,
+			RT5645_M_DAC_R2_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_dig_r_mix[] = {
+	SOC_DAPM_SINGLE("Sto DAC Mix R Switch", RT5645_DIG_MIXER,
+			RT5645_M_STO_R_DAC_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_DIG_MIXER,
+			RT5645_M_DAC_R2_DAC_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_DIG_MIXER,
+			RT5645_M_DAC_L2_DAC_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5645_rec_l_mix[] = {
+	SOC_DAPM_SINGLE("HPOL Switch", RT5645_REC_L2_MIXER,
+			RT5645_M_HP_L_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5645_REC_L2_MIXER,
+			RT5645_M_IN_L_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5645_REC_L2_MIXER,
+			RT5645_M_BST2_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5645_REC_L2_MIXER,
+			RT5645_M_BST1_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUT MIXL Switch", RT5645_REC_L2_MIXER,
+			RT5645_M_OM_L_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_rec_r_mix[] = {
+	SOC_DAPM_SINGLE("HPOR Switch", RT5645_REC_R2_MIXER,
+			RT5645_M_HP_R_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5645_REC_R2_MIXER,
+			RT5645_M_IN_R_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5645_REC_R2_MIXER,
+			RT5645_M_BST2_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5645_REC_R2_MIXER,
+			RT5645_M_BST1_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUT MIXR Switch", RT5645_REC_R2_MIXER,
+			RT5645_M_OM_R_RM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_spk_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_SPK_L_MIXER,
+			RT5645_M_DAC_L1_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_SPK_L_MIXER,
+			RT5645_M_DAC_L2_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5645_SPK_L_MIXER,
+			RT5645_M_IN_L_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5645_SPK_L_MIXER,
+			RT5645_M_BST1_L_SM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_spk_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_SPK_R_MIXER,
+			RT5645_M_DAC_R1_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_SPK_R_MIXER,
+			RT5645_M_DAC_R2_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5645_SPK_R_MIXER,
+			RT5645_M_IN_R_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5645_SPK_R_MIXER,
+			RT5645_M_BST2_R_SM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_out_l_mix[] = {
+	SOC_DAPM_SINGLE("BST1 Switch", RT5645_OUT_L1_MIXER,
+			RT5645_M_BST1_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5645_OUT_L1_MIXER,
+			RT5645_M_IN_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5645_OUT_L1_MIXER,
+			RT5645_M_DAC_L2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_OUT_L1_MIXER,
+			RT5645_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_out_r_mix[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5645_OUT_R1_MIXER,
+			RT5645_M_BST2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5645_OUT_R1_MIXER,
+			RT5645_M_IN_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5645_OUT_R1_MIXER,
+			RT5645_M_DAC_R2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_OUT_R1_MIXER,
+			RT5645_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_spo_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_SPO_MIXER,
+			RT5645_M_DAC_R1_SPM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_SPO_MIXER,
+			RT5645_M_DAC_L1_SPM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("SPKVOL R Switch", RT5645_SPO_MIXER,
+			RT5645_M_SV_R_SPM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("SPKVOL L Switch", RT5645_SPO_MIXER,
+			RT5645_M_SV_L_SPM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_spo_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_SPO_MIXER,
+			RT5645_M_DAC_R1_SPM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("SPKVOL R Switch", RT5645_SPO_MIXER,
+			RT5645_M_SV_R_SPM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_hpo_mix[] = {
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5645_HPO_MIXER,
+			RT5645_M_DAC1_HM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("HPVOL Switch", RT5645_HPO_MIXER,
+			RT5645_M_HPVOL_HM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_hpvoll_mix[] = {
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5645_HPOMIXL_CTRL,
+			RT5645_M_DAC1_HV_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC2 Switch", RT5645_HPOMIXL_CTRL,
+			RT5645_M_DAC2_HV_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5645_HPOMIXL_CTRL,
+			RT5645_M_IN_HV_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5645_HPOMIXL_CTRL,
+			RT5645_M_BST1_HV_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_hpvolr_mix[] = {
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5645_HPOMIXR_CTRL,
+			RT5645_M_DAC1_HV_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC2 Switch", RT5645_HPOMIXR_CTRL,
+			RT5645_M_DAC2_HV_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5645_HPOMIXR_CTRL,
+			RT5645_M_IN_HV_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5645_HPOMIXR_CTRL,
+			RT5645_M_BST2_HV_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5645_lout_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5645_LOUT_MIXER,
+			RT5645_M_DAC_L1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5645_LOUT_MIXER,
+			RT5645_M_DAC_R1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTMIX L Switch", RT5645_LOUT_MIXER,
+			RT5645_M_OV_L_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTMIX R Switch", RT5645_LOUT_MIXER,
+			RT5645_M_OV_R_LM_SFT, 1, 1),
+};
+
+/*DAC1 L/R source*/ /* MX-29 [9:8] [11:10] */
+static const char * const rt5645_dac1_src[] = {
+	"IF1 DAC", "IF2 DAC", "IF3 DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_dac1l_enum, RT5645_AD_DA_MIXER,
+	RT5645_DAC1_L_SEL_SFT, rt5645_dac1_src);
+
+static const struct snd_kcontrol_new rt5645_dac1l_mux =
+	SOC_DAPM_ENUM("DAC1 L source", rt5645_dac1l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_dac1r_enum, RT5645_AD_DA_MIXER,
+	RT5645_DAC1_R_SEL_SFT, rt5645_dac1_src);
+
+static const struct snd_kcontrol_new rt5645_dac1r_mux =
+	SOC_DAPM_ENUM("DAC1 R source", rt5645_dac1r_enum);
+
+/*DAC2 L/R source*/ /* MX-1B [6:4] [2:0] */
+static const char * const rt5645_dac12_src[] = {
+	"IF1 DAC", "IF2 DAC", "IF3 DAC", "Mono ADC", "VAD_ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_dac2l_enum, RT5645_DAC_CTRL,
+	RT5645_DAC2_L_SEL_SFT, rt5645_dac12_src);
+
+static const struct snd_kcontrol_new rt5645_dac_l2_mux =
+	SOC_DAPM_ENUM("DAC2 L source", rt5645_dac2l_enum);
+
+static const char * const rt5645_dacr2_src[] = {
+	"IF1 DAC", "IF2 DAC", "IF3 DAC", "Mono ADC", "Haptic"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_dac2r_enum, RT5645_DAC_CTRL,
+	RT5645_DAC2_R_SEL_SFT, rt5645_dacr2_src);
+
+static const struct snd_kcontrol_new rt5645_dac_r2_mux =
+	SOC_DAPM_ENUM("DAC2 R source", rt5645_dac2r_enum);
+
+
+/* INL/R source */
+static const char * const rt5645_inl_src[] = {
+	"IN2P", "MonoP"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_inl_enum, RT5645_INL1_INR1_VOL,
+	RT5645_INL_SEL_SFT, rt5645_inl_src);
+
+static const struct snd_kcontrol_new rt5645_inl_mux =
+	SOC_DAPM_ENUM("INL source", rt5645_inl_enum);
+
+static const char * const rt5645_inr_src[] = {
+	"IN2N", "MonoN"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_inr_enum, RT5645_INL1_INR1_VOL,
+	RT5645_INR_SEL_SFT, rt5645_inr_src);
+
+static const struct snd_kcontrol_new rt5645_inr_mux =
+	SOC_DAPM_ENUM("INR source", rt5645_inr_enum);
+
+/* Stereo1 ADC source */
+/* MX-27 [12] */
+static const char * const rt5645_stereo_adc1_src[] = {
+	"DAC MIX", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_stereo1_adc1_enum, RT5645_STO1_ADC_MIXER,
+	RT5645_ADC_1_SRC_SFT, rt5645_stereo_adc1_src);
+
+static const struct snd_kcontrol_new rt5645_sto_adc1_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC1 Mux", rt5645_stereo1_adc1_enum);
+
+/* MX-27 [11] */
+static const char * const rt5645_stereo_adc2_src[] = {
+	"DAC MIX", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_stereo1_adc2_enum, RT5645_STO1_ADC_MIXER,
+	RT5645_ADC_2_SRC_SFT, rt5645_stereo_adc2_src);
+
+static const struct snd_kcontrol_new rt5645_sto_adc2_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC2 Mux", rt5645_stereo1_adc2_enum);
+
+/* MX-27 [8] */
+static const char * const rt5645_stereo_dmic_src[] = {
+	"DMIC1", "DMIC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_stereo1_dmic_enum, RT5645_STO1_ADC_MIXER,
+	RT5645_DMIC_SRC_SFT, rt5645_stereo_dmic_src);
+
+static const struct snd_kcontrol_new rt5645_sto1_dmic_mux =
+	SOC_DAPM_ENUM("Stereo1 DMIC source", rt5645_stereo1_dmic_enum);
+
+/* Mono ADC source */
+/* MX-28 [12] */
+static const char * const rt5645_mono_adc_l1_src[] = {
+	"Mono DAC MIXL", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_mono_adc_l1_enum, RT5645_MONO_ADC_MIXER,
+	RT5645_MONO_ADC_L1_SRC_SFT, rt5645_mono_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5645_mono_adc_l1_mux =
+	SOC_DAPM_ENUM("Mono ADC1 left source", rt5645_mono_adc_l1_enum);
+/* MX-28 [11] */
+static const char * const rt5645_mono_adc_l2_src[] = {
+	"Mono DAC MIXL", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_mono_adc_l2_enum, RT5645_MONO_ADC_MIXER,
+	RT5645_MONO_ADC_L2_SRC_SFT, rt5645_mono_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5645_mono_adc_l2_mux =
+	SOC_DAPM_ENUM("Mono ADC2 left source", rt5645_mono_adc_l2_enum);
+
+/* MX-28 [8] */
+static const char * const rt5645_mono_dmic_src[] = {
+	"DMIC1", "DMIC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_mono_dmic_l_enum, RT5645_MONO_ADC_MIXER,
+	RT5645_MONO_DMIC_L_SRC_SFT, rt5645_mono_dmic_src);
+
+static const struct snd_kcontrol_new rt5645_mono_dmic_l_mux =
+	SOC_DAPM_ENUM("Mono DMIC left source", rt5645_mono_dmic_l_enum);
+/* MX-28 [1:0] */
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_mono_dmic_r_enum, RT5645_MONO_ADC_MIXER,
+	RT5645_MONO_DMIC_R_SRC_SFT, rt5645_mono_dmic_src);
+
+static const struct snd_kcontrol_new rt5645_mono_dmic_r_mux =
+	SOC_DAPM_ENUM("Mono DMIC Right source", rt5645_mono_dmic_r_enum);
+/* MX-28 [4] */
+static const char * const rt5645_mono_adc_r1_src[] = {
+	"Mono DAC MIXR", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_mono_adc_r1_enum, RT5645_MONO_ADC_MIXER,
+	RT5645_MONO_ADC_R1_SRC_SFT, rt5645_mono_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5645_mono_adc_r1_mux =
+	SOC_DAPM_ENUM("Mono ADC1 right source", rt5645_mono_adc_r1_enum);
+/* MX-28 [3] */
+static const char * const rt5645_mono_adc_r2_src[] = {
+	"Mono DAC MIXR", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_mono_adc_r2_enum, RT5645_MONO_ADC_MIXER,
+	RT5645_MONO_ADC_R2_SRC_SFT, rt5645_mono_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5645_mono_adc_r2_mux =
+	SOC_DAPM_ENUM("Mono ADC2 right source", rt5645_mono_adc_r2_enum);
+
+/* MX-77 [9:8] */
+static const char * const rt5645_if1_adc_in_src[] = {
+	"IF_ADC1/IF_ADC2/VAD_ADC", "IF_ADC2/IF_ADC1/VAD_ADC",
+	"VAD_ADC/IF_ADC1/IF_ADC2", "VAD_ADC/IF_ADC2/IF_ADC1"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_if1_adc_in_enum, RT5645_TDM_CTRL_1,
+	RT5645_IF1_ADC_IN_SFT, rt5645_if1_adc_in_src);
+
+static const struct snd_kcontrol_new rt5645_if1_adc_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum);
+
+/* MX-78 [4:0] */
+static const char * const rt5650_if1_adc_in_src[] = {
+	"IF_ADC1/IF_ADC2/DAC_REF/Null",
+	"IF_ADC1/IF_ADC2/Null/DAC_REF",
+	"IF_ADC1/DAC_REF/IF_ADC2/Null",
+	"IF_ADC1/DAC_REF/Null/IF_ADC2",
+	"IF_ADC1/Null/DAC_REF/IF_ADC2",
+	"IF_ADC1/Null/IF_ADC2/DAC_REF",
+
+	"IF_ADC2/IF_ADC1/DAC_REF/Null",
+	"IF_ADC2/IF_ADC1/Null/DAC_REF",
+	"IF_ADC2/DAC_REF/IF_ADC1/Null",
+	"IF_ADC2/DAC_REF/Null/IF_ADC1",
+	"IF_ADC2/Null/DAC_REF/IF_ADC1",
+	"IF_ADC2/Null/IF_ADC1/DAC_REF",
+
+	"DAC_REF/IF_ADC1/IF_ADC2/Null",
+	"DAC_REF/IF_ADC1/Null/IF_ADC2",
+	"DAC_REF/IF_ADC2/IF_ADC1/Null",
+	"DAC_REF/IF_ADC2/Null/IF_ADC1",
+	"DAC_REF/Null/IF_ADC1/IF_ADC2",
+	"DAC_REF/Null/IF_ADC2/IF_ADC1",
+
+	"Null/IF_ADC1/IF_ADC2/DAC_REF",
+	"Null/IF_ADC1/DAC_REF/IF_ADC2",
+	"Null/IF_ADC2/IF_ADC1/DAC_REF",
+	"Null/IF_ADC2/DAC_REF/IF_ADC1",
+	"Null/DAC_REF/IF_ADC1/IF_ADC2",
+	"Null/DAC_REF/IF_ADC2/IF_ADC1",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5650_if1_adc_in_enum, RT5645_TDM_CTRL_2,
+	0, rt5650_if1_adc_in_src);
+
+static const struct snd_kcontrol_new rt5650_if1_adc_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC IN source", rt5650_if1_adc_in_enum);
+
+/* MX-78 [15:14][13:12][11:10] */
+static const char * const rt5645_tdm_adc_swap_select[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot0_1_enum,
+	RT5645_TDM_CTRL_2, 14, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_adc1_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC1 IN source", rt5650_tdm_adc_slot0_1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot2_3_enum,
+	RT5645_TDM_CTRL_2, 12, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_adc2_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC2 IN source", rt5650_tdm_adc_slot2_3_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot4_5_enum,
+	RT5645_TDM_CTRL_2, 10, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_adc3_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC3 IN source", rt5650_tdm_adc_slot4_5_enum);
+
+/* MX-77 [7:6][5:4][3:2] */
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot0_1_enum,
+	RT5645_TDM_CTRL_1, 6, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_adc1_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC1 IN source", rt5645_tdm_adc_slot0_1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot2_3_enum,
+	RT5645_TDM_CTRL_1, 4, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_adc2_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC2 IN source", rt5645_tdm_adc_slot2_3_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot4_5_enum,
+	RT5645_TDM_CTRL_1, 2, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_adc3_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC3 IN source", rt5645_tdm_adc_slot4_5_enum);
+
+/* MX-79 [14:12][10:8][6:4][2:0] */
+static const char * const rt5645_tdm_dac_swap_select[] = {
+	"Slot0", "Slot1", "Slot2", "Slot3"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac0_enum,
+	RT5645_TDM_CTRL_3, 12, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac0_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC0 source", rt5645_tdm_dac0_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac1_enum,
+	RT5645_TDM_CTRL_3, 8, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac1_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC1 source", rt5645_tdm_dac1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac2_enum,
+	RT5645_TDM_CTRL_3, 4, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac2_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC2 source", rt5645_tdm_dac2_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac3_enum,
+	RT5645_TDM_CTRL_3, 0, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac3_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC3 source", rt5645_tdm_dac3_enum);
+
+/* MX-7a [14:12][10:8][6:4][2:0] */
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac0_enum,
+	RT5650_TDM_CTRL_4, 12, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac0_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC0 source", rt5650_tdm_dac0_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac1_enum,
+	RT5650_TDM_CTRL_4, 8, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac1_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC1 source", rt5650_tdm_dac1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac2_enum,
+	RT5650_TDM_CTRL_4, 4, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac2_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC2 source", rt5650_tdm_dac2_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac3_enum,
+	RT5650_TDM_CTRL_4, 0, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac3_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC3 source", rt5650_tdm_dac3_enum);
+
+/* MX-2d [3] [2] */
+static const char * const rt5650_a_dac1_src[] = {
+	"DAC1", "Stereo DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5650_a_dac1_l_enum, RT5650_A_DAC_SOUR,
+	RT5650_A_DAC1_L_IN_SFT, rt5650_a_dac1_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac1_l_mux =
+	SOC_DAPM_ENUM("A DAC1 L source", rt5650_a_dac1_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5650_a_dac1_r_enum, RT5650_A_DAC_SOUR,
+	RT5650_A_DAC1_R_IN_SFT, rt5650_a_dac1_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac1_r_mux =
+	SOC_DAPM_ENUM("A DAC1 R source", rt5650_a_dac1_r_enum);
+
+/* MX-2d [1] [0] */
+static const char * const rt5650_a_dac2_src[] = {
+	"Stereo DAC Mixer", "Mono DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5650_a_dac2_l_enum, RT5650_A_DAC_SOUR,
+	RT5650_A_DAC2_L_IN_SFT, rt5650_a_dac2_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac2_l_mux =
+	SOC_DAPM_ENUM("A DAC2 L source", rt5650_a_dac2_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5650_a_dac2_r_enum, RT5650_A_DAC_SOUR,
+	RT5650_A_DAC2_R_IN_SFT, rt5650_a_dac2_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac2_r_mux =
+	SOC_DAPM_ENUM("A DAC2 R source", rt5650_a_dac2_r_enum);
+
+/* MX-2F [13:12] */
+static const char * const rt5645_if2_adc_in_src[] = {
+	"IF_ADC1", "IF_ADC2", "VAD_ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_if2_adc_in_enum, RT5645_DIG_INF1_DATA,
+	RT5645_IF2_ADC_IN_SFT, rt5645_if2_adc_in_src);
+
+static const struct snd_kcontrol_new rt5645_if2_adc_in_mux =
+	SOC_DAPM_ENUM("IF2 ADC IN source", rt5645_if2_adc_in_enum);
+
+/* MX-2F [1:0] */
+static const char * const rt5645_if3_adc_in_src[] = {
+	"IF_ADC1", "IF_ADC2", "VAD_ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_if3_adc_in_enum, RT5645_DIG_INF1_DATA,
+	RT5645_IF3_ADC_IN_SFT, rt5645_if3_adc_in_src);
+
+static const struct snd_kcontrol_new rt5645_if3_adc_in_mux =
+	SOC_DAPM_ENUM("IF3 ADC IN source", rt5645_if3_adc_in_enum);
+
+/* MX-31 [15] [13] [11] [9] */
+static const char * const rt5645_pdm_src[] = {
+	"Mono DAC", "Stereo DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_pdm1_l_enum, RT5645_PDM_OUT_CTRL,
+	RT5645_PDM1_L_SFT, rt5645_pdm_src);
+
+static const struct snd_kcontrol_new rt5645_pdm1_l_mux =
+	SOC_DAPM_ENUM("PDM1 L source", rt5645_pdm1_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_pdm1_r_enum, RT5645_PDM_OUT_CTRL,
+	RT5645_PDM1_R_SFT, rt5645_pdm_src);
+
+static const struct snd_kcontrol_new rt5645_pdm1_r_mux =
+	SOC_DAPM_ENUM("PDM1 R source", rt5645_pdm1_r_enum);
+
+/* MX-9D [9:8] */
+static const char * const rt5645_vad_adc_src[] = {
+	"Sto1 ADC L", "Mono ADC L", "Mono ADC R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5645_vad_adc_enum, RT5645_VAD_CTRL4,
+	RT5645_VAD_SEL_SFT, rt5645_vad_adc_src);
+
+static const struct snd_kcontrol_new rt5645_vad_adc_mux =
+	SOC_DAPM_ENUM("VAD ADC source", rt5645_vad_adc_enum);
+
+static const struct snd_kcontrol_new spk_l_vol_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_SPK_VOL,
+		RT5645_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new spk_r_vol_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_SPK_VOL,
+		RT5645_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hp_l_vol_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_HP_VOL,
+		RT5645_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hp_r_vol_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_HP_VOL,
+		RT5645_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new pdm1_l_vol_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_PDM_OUT_CTRL,
+		RT5645_M_PDM1_L, 1, 1);
+
+static const struct snd_kcontrol_new pdm1_r_vol_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5645_PDM_OUT_CTRL,
+		RT5645_M_PDM1_R, 1, 1);
+
+static void hp_amp_power(struct snd_soc_component *component, int on)
+{
+	static int hp_amp_power_count;
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+
+	if (on) {
+		if (hp_amp_power_count <= 0) {
+			if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+				snd_soc_component_write(component, RT5645_DEPOP_M2, 0x3100);
+				snd_soc_component_write(component, RT5645_CHARGE_PUMP,
+					0x0e06);
+				snd_soc_component_write(component, RT5645_DEPOP_M1, 0x000d);
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					RT5645_HP_DCC_INT1, 0x9f01);
+				msleep(20);
+				snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
+					RT5645_HP_CO_MASK, RT5645_HP_CO_EN);
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					0x3e, 0x7400);
+				snd_soc_component_write(component, RT5645_DEPOP_M3, 0x0737);
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					RT5645_MAMP_INT_REG2, 0xfc00);
+				snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
+				msleep(90);
+				rt5645->hp_on = true;
+			} else {
+				/* depop parameters */
+				snd_soc_component_update_bits(component, RT5645_DEPOP_M2,
+					RT5645_DEPOP_MASK, RT5645_DEPOP_MAN);
+				snd_soc_component_write(component, RT5645_DEPOP_M1, 0x000d);
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					RT5645_HP_DCC_INT1, 0x9f01);
+				mdelay(150);
+				/* headphone amp power on */
+				snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+					RT5645_PWR_FV1 | RT5645_PWR_FV2, 0);
+				snd_soc_component_update_bits(component, RT5645_PWR_VOL,
+					RT5645_PWR_HV_L | RT5645_PWR_HV_R,
+					RT5645_PWR_HV_L | RT5645_PWR_HV_R);
+				snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+					RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+					RT5645_PWR_HA,
+					RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+					RT5645_PWR_HA);
+				mdelay(5);
+				snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+					RT5645_PWR_FV1 | RT5645_PWR_FV2,
+					RT5645_PWR_FV1 | RT5645_PWR_FV2);
+
+				snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
+					RT5645_HP_CO_MASK | RT5645_HP_SG_MASK,
+					RT5645_HP_CO_EN | RT5645_HP_SG_EN);
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					0x14, 0x1aaa);
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					0x24, 0x0430);
+			}
+		}
+		hp_amp_power_count++;
+	} else {
+		hp_amp_power_count--;
+		if (hp_amp_power_count <= 0) {
+			if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					0x3e, 0x7400);
+				snd_soc_component_write(component, RT5645_DEPOP_M3, 0x0737);
+				regmap_write(rt5645->regmap, RT5645_PR_BASE +
+					RT5645_MAMP_INT_REG2, 0xfc00);
+				snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
+				msleep(100);
+				snd_soc_component_write(component, RT5645_DEPOP_M1, 0x0001);
+
+			} else {
+				snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
+					RT5645_HP_SG_MASK |
+					RT5645_HP_L_SMT_MASK |
+					RT5645_HP_R_SMT_MASK,
+					RT5645_HP_SG_DIS |
+					RT5645_HP_L_SMT_DIS |
+					RT5645_HP_R_SMT_DIS);
+				/* headphone amp power down */
+				snd_soc_component_write(component, RT5645_DEPOP_M1, 0x0000);
+				snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+					RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+					RT5645_PWR_HA, 0);
+				snd_soc_component_update_bits(component, RT5645_DEPOP_M2,
+					RT5645_DEPOP_MASK, 0);
+			}
+		}
+	}
+}
+
+static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		hp_amp_power(component, 1);
+		/* headphone unmute sequence */
+		if (rt5645->codec_type == CODEC_TYPE_RT5645) {
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M3,
+				RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
+				RT5645_CP_FQ3_MASK,
+				(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
+				(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
+				(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
+			regmap_write(rt5645->regmap, RT5645_PR_BASE +
+				RT5645_MAMP_INT_REG2, 0xfc00);
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
+				RT5645_SMT_TRIG_MASK, RT5645_SMT_TRIG_EN);
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
+				RT5645_RSTN_MASK, RT5645_RSTN_EN);
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
+				RT5645_RSTN_MASK | RT5645_HP_L_SMT_MASK |
+				RT5645_HP_R_SMT_MASK, RT5645_RSTN_DIS |
+				RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
+			msleep(40);
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
+				RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK |
+				RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS |
+				RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS);
+		}
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		/* headphone mute sequence */
+		if (rt5645->codec_type == CODEC_TYPE_RT5645) {
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M3,
+				RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
+				RT5645_CP_FQ3_MASK,
+				(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
+				(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
+				(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
+			regmap_write(rt5645->regmap, RT5645_PR_BASE +
+				RT5645_MAMP_INT_REG2, 0xfc00);
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
+				RT5645_HP_SG_MASK, RT5645_HP_SG_EN);
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
+				RT5645_RSTP_MASK, RT5645_RSTP_EN);
+			snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
+				RT5645_RSTP_MASK | RT5645_HP_L_SMT_MASK |
+				RT5645_HP_R_SMT_MASK, RT5645_RSTP_DIS |
+				RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
+			msleep(30);
+		}
+		hp_amp_power(component, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		rt5645_enable_hweq(component);
+		snd_soc_component_update_bits(component, RT5645_PWR_DIG1,
+			RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
+			RT5645_PWR_CLS_D_L,
+			RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
+			RT5645_PWR_CLS_D_L);
+		snd_soc_component_update_bits(component, RT5645_GEN_CTRL3,
+			RT5645_DET_CLK_MASK, RT5645_DET_CLK_MODE1);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5645_GEN_CTRL3,
+			RT5645_DET_CLK_MASK, RT5645_DET_CLK_DIS);
+		snd_soc_component_write(component, RT5645_EQ_CTRL2, 0);
+		snd_soc_component_update_bits(component, RT5645_PWR_DIG1,
+			RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
+			RT5645_PWR_CLS_D_L, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5645_lout_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		hp_amp_power(component, 1);
+		snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+			RT5645_PWR_LM, RT5645_PWR_LM);
+		snd_soc_component_update_bits(component, RT5645_LOUT1,
+			RT5645_L_MUTE | RT5645_R_MUTE, 0);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5645_LOUT1,
+			RT5645_L_MUTE | RT5645_R_MUTE,
+			RT5645_L_MUTE | RT5645_R_MUTE);
+		snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+			RT5645_PWR_LM, 0);
+		hp_amp_power(component, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5645_bst2_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5645_PWR_ANLG2,
+			RT5645_PWR_BST2_P, RT5645_PWR_BST2_P);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5645_PWR_ANLG2,
+			RT5645_PWR_BST2_P, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5650_hp_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *k, int  event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (rt5645->hp_on) {
+			msleep(100);
+			rt5645->hp_on = false;
+		}
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5645_set_micbias1_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *k, int  event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component, RT5645_GEN_CTRL2,
+			RT5645_MICBIAS1_POW_CTRL_SEL_MASK,
+			RT5645_MICBIAS1_POW_CTRL_SEL_M);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, RT5645_GEN_CTRL2,
+			RT5645_MICBIAS1_POW_CTRL_SEL_MASK,
+			RT5645_MICBIAS1_POW_CTRL_SEL_A);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5645_set_micbias2_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *k, int  event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component, RT5645_GEN_CTRL2,
+			RT5645_MICBIAS2_POW_CTRL_SEL_MASK,
+			RT5645_MICBIAS2_POW_CTRL_SEL_M);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, RT5645_GEN_CTRL2,
+			RT5645_MICBIAS2_POW_CTRL_SEL_MASK,
+			RT5645_MICBIAS2_POW_CTRL_SEL_A);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("LDO2", RT5645_PWR_MIXER,
+		RT5645_PWR_LDO2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL1", RT5645_PWR_ANLG2,
+		RT5645_PWR_PLL_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("JD Power", RT5645_PWR_ANLG2,
+		RT5645_PWR_JD1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5645_PWR_VOL,
+		RT5645_PWR_MIC_DET_BIT, 0, NULL, 0),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5645_ASRC_1,
+			      11, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5645_ASRC_1,
+			      12, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5645_ASRC_1,
+			      10, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC MONO L ASRC", 1, RT5645_ASRC_1,
+			      9, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5645_ASRC_1,
+			      8, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5645_ASRC_1,
+			      7, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5645_ASRC_1,
+			      5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5645_ASRC_1,
+			      4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5645_ASRC_1,
+			      3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5645_ASRC_1,
+			      1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5645_ASRC_1,
+			      0, 0, NULL, 0),
+
+	/* Input Side */
+	/* micbias */
+	SND_SOC_DAPM_SUPPLY("micbias1", RT5645_PWR_ANLG2,
+			RT5645_PWR_MB1_BIT, 0, rt5645_set_micbias1_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("micbias2", RT5645_PWR_ANLG2,
+			RT5645_PWR_MB2_BIT, 0, rt5645_set_micbias2_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC L1"),
+	SND_SOC_DAPM_INPUT("DMIC R1"),
+	SND_SOC_DAPM_INPUT("DMIC L2"),
+	SND_SOC_DAPM_INPUT("DMIC R2"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN1N"),
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN2N"),
+
+	SND_SOC_DAPM_INPUT("Haptic Generator"),
+
+	SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+		set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5645_DMIC_CTRL1,
+		RT5645_DMIC_1_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5645_DMIC_CTRL1,
+		RT5645_DMIC_2_EN_SFT, 0, NULL, 0),
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1", RT5645_PWR_ANLG2,
+		RT5645_PWR_BST1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_E("BST2", RT5645_PWR_ANLG2,
+		RT5645_PWR_BST2_BIT, 0, NULL, 0, rt5645_bst2_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	/* Input Volume */
+	SND_SOC_DAPM_PGA("INL VOL", RT5645_PWR_VOL,
+		RT5645_PWR_IN_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR VOL", RT5645_PWR_VOL,
+		RT5645_PWR_IN_R_BIT, 0, NULL, 0),
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIXL", RT5645_PWR_MIXER, RT5645_PWR_RM_L_BIT,
+			0, rt5645_rec_l_mix, ARRAY_SIZE(rt5645_rec_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIXR", RT5645_PWR_MIXER, RT5645_PWR_RM_R_BIT,
+			0, rt5645_rec_r_mix, ARRAY_SIZE(rt5645_rec_r_mix)),
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC L power", RT5645_PWR_DIG1,
+		RT5645_PWR_ADC_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC R power", RT5645_PWR_DIG1,
+		RT5645_PWR_ADC_R_BIT, 0, NULL, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_sto1_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_sto_adc2_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_sto_adc2_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_sto_adc1_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_sto_adc1_mux),
+	SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_mono_dmic_l_mux),
+	SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_mono_dmic_r_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_mono_adc_l2_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_mono_adc_l1_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_mono_adc_r1_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_mono_adc_r2_mux),
+	/* ADC Mixer */
+
+	SND_SOC_DAPM_SUPPLY_S("adc stereo1 filter", 1, RT5645_PWR_DIG2,
+		RT5645_PWR_ADC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER_E("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5645_sto1_adc_l_mix, ARRAY_SIZE(rt5645_sto1_adc_l_mix),
+		NULL, 0),
+	SND_SOC_DAPM_MIXER_E("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5645_sto1_adc_r_mix, ARRAY_SIZE(rt5645_sto1_adc_r_mix),
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("adc mono left filter", 1, RT5645_PWR_DIG2,
+		RT5645_PWR_ADC_MF_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER_E("Mono ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5645_mono_adc_l_mix, ARRAY_SIZE(rt5645_mono_adc_l_mix),
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("adc mono right filter", 1, RT5645_PWR_DIG2,
+		RT5645_PWR_ADC_MF_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER_E("Mono ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5645_mono_adc_r_mix, ARRAY_SIZE(rt5645_mono_adc_r_mix),
+		NULL, 0),
+
+	/* ADC PGA */
+	SND_SOC_DAPM_PGA("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("VAD_ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* IF1 2 Mux */
+	SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM,
+		0, 0, &rt5645_if2_adc_in_mux),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5645_PWR_DIG1,
+		RT5645_PWR_I2S1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC0", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("I2S2", RT5645_PWR_DIG1,
+		RT5645_PWR_I2S2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface Select */
+	SND_SOC_DAPM_MUX("VAD ADC Mux", SND_SOC_NOPM,
+		0, 0, &rt5645_vad_adc_mux),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Side */
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
+		rt5645_dac_l_mix, ARRAY_SIZE(rt5645_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+		rt5645_dac_r_mix, ARRAY_SIZE(rt5645_dac_r_mix)),
+
+	/* DAC2 channel Mux */
+	SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac_l2_mux),
+	SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac_r2_mux),
+	SND_SOC_DAPM_PGA("DAC L2 Volume", RT5645_PWR_DIG1,
+		RT5645_PWR_DAC_L2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DAC R2 Volume", RT5645_PWR_DIG1,
+		RT5645_PWR_DAC_R2_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("DAC1 L Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac1l_mux),
+	SND_SOC_DAPM_MUX("DAC1 R Mux", SND_SOC_NOPM, 0, 0, &rt5645_dac1r_mux),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY_S("dac stereo1 filter", 1, RT5645_PWR_DIG2,
+		RT5645_PWR_DAC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("dac mono left filter", 1, RT5645_PWR_DIG2,
+		RT5645_PWR_DAC_MF_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("dac mono right filter", 1, RT5645_PWR_DIG2,
+		RT5645_PWR_DAC_MF_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5645_sto_dac_l_mix, ARRAY_SIZE(rt5645_sto_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5645_sto_dac_r_mix, ARRAY_SIZE(rt5645_sto_dac_r_mix)),
+	SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5645_mono_dac_l_mix, ARRAY_SIZE(rt5645_mono_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5645_mono_dac_r_mix, ARRAY_SIZE(rt5645_mono_dac_r_mix)),
+	SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5645_dig_l_mix, ARRAY_SIZE(rt5645_dig_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5645_dig_r_mix, ARRAY_SIZE(rt5645_dig_r_mix)),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC L1", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_L1_BIT,
+		0),
+	SND_SOC_DAPM_DAC("DAC L2", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_L2_BIT,
+		0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_R1_BIT,
+		0),
+	SND_SOC_DAPM_DAC("DAC R2", NULL, RT5645_PWR_DIG1, RT5645_PWR_DAC_R2_BIT,
+		0),
+	/* OUT Mixer */
+	SND_SOC_DAPM_MIXER("SPK MIXL", RT5645_PWR_MIXER, RT5645_PWR_SM_L_BIT,
+		0, rt5645_spk_l_mix, ARRAY_SIZE(rt5645_spk_l_mix)),
+	SND_SOC_DAPM_MIXER("SPK MIXR", RT5645_PWR_MIXER, RT5645_PWR_SM_R_BIT,
+		0, rt5645_spk_r_mix, ARRAY_SIZE(rt5645_spk_r_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXL", RT5645_PWR_MIXER, RT5645_PWR_OM_L_BIT,
+		0, rt5645_out_l_mix, ARRAY_SIZE(rt5645_out_l_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXR", RT5645_PWR_MIXER, RT5645_PWR_OM_R_BIT,
+		0, rt5645_out_r_mix, ARRAY_SIZE(rt5645_out_r_mix)),
+	/* Ouput Volume */
+	SND_SOC_DAPM_SWITCH("SPKVOL L", RT5645_PWR_VOL, RT5645_PWR_SV_L_BIT, 0,
+		&spk_l_vol_control),
+	SND_SOC_DAPM_SWITCH("SPKVOL R", RT5645_PWR_VOL, RT5645_PWR_SV_R_BIT, 0,
+		&spk_r_vol_control),
+	SND_SOC_DAPM_MIXER("HPOVOL MIXL", RT5645_PWR_VOL, RT5645_PWR_HV_L_BIT,
+		0, rt5645_hpvoll_mix, ARRAY_SIZE(rt5645_hpvoll_mix)),
+	SND_SOC_DAPM_MIXER("HPOVOL MIXR", RT5645_PWR_VOL, RT5645_PWR_HV_R_BIT,
+		0, rt5645_hpvolr_mix, ARRAY_SIZE(rt5645_hpvolr_mix)),
+	SND_SOC_DAPM_SUPPLY("HPOVOL MIXL Power", RT5645_PWR_MIXER,
+		RT5645_PWR_HM_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HPOVOL MIXR Power", RT5645_PWR_MIXER,
+		RT5645_PWR_HM_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DAC 2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HPOVOL", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SWITCH("HPOVOL L", SND_SOC_NOPM, 0, 0, &hp_l_vol_control),
+	SND_SOC_DAPM_SWITCH("HPOVOL R", SND_SOC_NOPM, 0, 0, &hp_r_vol_control),
+
+	/* HPO/LOUT/Mono Mixer */
+	SND_SOC_DAPM_MIXER("SPOL MIX", SND_SOC_NOPM, 0, 0, rt5645_spo_l_mix,
+		ARRAY_SIZE(rt5645_spo_l_mix)),
+	SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0, 0, rt5645_spo_r_mix,
+		ARRAY_SIZE(rt5645_spo_r_mix)),
+	SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0, rt5645_hpo_mix,
+		ARRAY_SIZE(rt5645_hpo_mix)),
+	SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0, rt5645_lout_mix,
+		ARRAY_SIZE(rt5645_lout_mix)),
+
+	SND_SOC_DAPM_PGA_S("HP amp", 1, SND_SOC_NOPM, 0, 0, rt5645_hp_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0, rt5645_lout_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("SPK amp", 2, SND_SOC_NOPM, 0, 0, rt5645_spk_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+	/* PDM */
+	SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5645_PWR_DIG2, RT5645_PWR_PDM1_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_MUX("PDM1 L Mux", SND_SOC_NOPM, 0, 0, &rt5645_pdm1_l_mux),
+	SND_SOC_DAPM_MUX("PDM1 R Mux", SND_SOC_NOPM, 0, 0, &rt5645_pdm1_r_mux),
+
+	SND_SOC_DAPM_SWITCH("PDM1 L", SND_SOC_NOPM, 0, 0, &pdm1_l_vol_control),
+	SND_SOC_DAPM_SWITCH("PDM1 R", SND_SOC_NOPM, 0, 0, &pdm1_r_vol_control),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+	SND_SOC_DAPM_OUTPUT("LOUTL"),
+	SND_SOC_DAPM_OUTPUT("LOUTR"),
+	SND_SOC_DAPM_OUTPUT("PDM1L"),
+	SND_SOC_DAPM_OUTPUT("PDM1R"),
+	SND_SOC_DAPM_OUTPUT("SPOL"),
+	SND_SOC_DAPM_OUTPUT("SPOR"),
+	SND_SOC_DAPM_POST("DAPM_POST", rt5650_hp_event),
+};
+
+static const struct snd_soc_dapm_widget rt5645_specific_dapm_widgets[] = {
+	SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_if1_dac0_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_if1_dac1_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_if1_dac2_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5645_if1_dac3_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("RT5645 IF1 ADC Mux", SND_SOC_NOPM,
+		0, 0, &rt5645_if1_adc_in_mux),
+	SND_SOC_DAPM_MUX("RT5645 IF1 ADC1 Swap Mux", SND_SOC_NOPM,
+		0, 0, &rt5645_if1_adc1_in_mux),
+	SND_SOC_DAPM_MUX("RT5645 IF1 ADC2 Swap Mux", SND_SOC_NOPM,
+		0, 0, &rt5645_if1_adc2_in_mux),
+	SND_SOC_DAPM_MUX("RT5645 IF1 ADC3 Swap Mux", SND_SOC_NOPM,
+		0, 0, &rt5645_if1_adc3_in_mux),
+};
+
+static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = {
+	SND_SOC_DAPM_MUX("A DAC1 L Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_a_dac1_l_mux),
+	SND_SOC_DAPM_MUX("A DAC1 R Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_a_dac1_r_mux),
+	SND_SOC_DAPM_MUX("A DAC2 L Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_a_dac2_l_mux),
+	SND_SOC_DAPM_MUX("A DAC2 R Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_a_dac2_r_mux),
+
+	SND_SOC_DAPM_MUX("RT5650 IF1 ADC1 Swap Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_if1_adc1_in_mux),
+	SND_SOC_DAPM_MUX("RT5650 IF1 ADC2 Swap Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_if1_adc2_in_mux),
+	SND_SOC_DAPM_MUX("RT5650 IF1 ADC3 Swap Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_if1_adc3_in_mux),
+	SND_SOC_DAPM_MUX("RT5650 IF1 ADC Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_if1_adc_in_mux),
+
+	SND_SOC_DAPM_MUX("RT5650 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5650_if1_dac0_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("RT5650 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5650_if1_dac1_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("RT5650 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5650_if1_dac2_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("RT5650 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5650_if1_dac3_tdm_sel_mux),
+};
+
+static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
+	{ "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc },
+	{ "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc },
+	{ "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc },
+	{ "dac mono left filter", NULL, "DAC MONO L ASRC", is_using_asrc },
+	{ "dac mono right filter", NULL, "DAC MONO R ASRC", is_using_asrc },
+	{ "dac stereo1 filter", NULL, "DAC STO ASRC", is_using_asrc },
+
+	{ "I2S1", NULL, "I2S1 ASRC" },
+	{ "I2S2", NULL, "I2S2 ASRC" },
+
+	{ "IN1P", NULL, "LDO2" },
+	{ "IN2P", NULL, "LDO2" },
+
+	{ "DMIC1", NULL, "DMIC L1" },
+	{ "DMIC1", NULL, "DMIC R1" },
+	{ "DMIC2", NULL, "DMIC L2" },
+	{ "DMIC2", NULL, "DMIC R2" },
+
+	{ "BST1", NULL, "IN1P" },
+	{ "BST1", NULL, "IN1N" },
+	{ "BST1", NULL, "JD Power" },
+	{ "BST1", NULL, "Mic Det Power" },
+	{ "BST2", NULL, "IN2P" },
+	{ "BST2", NULL, "IN2N" },
+
+	{ "INL VOL", NULL, "IN2P" },
+	{ "INR VOL", NULL, "IN2N" },
+
+	{ "RECMIXL", "HPOL Switch", "HPOL" },
+	{ "RECMIXL", "INL Switch", "INL VOL" },
+	{ "RECMIXL", "BST2 Switch", "BST2" },
+	{ "RECMIXL", "BST1 Switch", "BST1" },
+	{ "RECMIXL", "OUT MIXL Switch", "OUT MIXL" },
+
+	{ "RECMIXR", "HPOR Switch", "HPOR" },
+	{ "RECMIXR", "INR Switch", "INR VOL" },
+	{ "RECMIXR", "BST2 Switch", "BST2" },
+	{ "RECMIXR", "BST1 Switch", "BST1" },
+	{ "RECMIXR", "OUT MIXR Switch", "OUT MIXR" },
+
+	{ "ADC L", NULL, "RECMIXL" },
+	{ "ADC L", NULL, "ADC L power" },
+	{ "ADC R", NULL, "RECMIXR" },
+	{ "ADC R", NULL, "ADC R power" },
+
+	{"DMIC L1", NULL, "DMIC CLK"},
+	{"DMIC L1", NULL, "DMIC1 Power"},
+	{"DMIC R1", NULL, "DMIC CLK"},
+	{"DMIC R1", NULL, "DMIC1 Power"},
+	{"DMIC L2", NULL, "DMIC CLK"},
+	{"DMIC L2", NULL, "DMIC2 Power"},
+	{"DMIC R2", NULL, "DMIC CLK"},
+	{"DMIC R2", NULL, "DMIC2 Power"},
+
+	{ "Stereo1 DMIC Mux", "DMIC1", "DMIC1" },
+	{ "Stereo1 DMIC Mux", "DMIC2", "DMIC2" },
+	{ "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC" },
+
+	{ "Mono DMIC L Mux", "DMIC1", "DMIC L1" },
+	{ "Mono DMIC L Mux", "DMIC2", "DMIC L2" },
+	{ "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC" },
+
+	{ "Mono DMIC R Mux", "DMIC1", "DMIC R1" },
+	{ "Mono DMIC R Mux", "DMIC2", "DMIC R2" },
+	{ "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC" },
+
+	{ "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" },
+	{ "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" },
+	{ "Stereo1 ADC L1 Mux", "ADC", "ADC L" },
+	{ "Stereo1 ADC L1 Mux", "DAC MIX", "DAC MIXL" },
+
+	{ "Stereo1 ADC R1 Mux", "ADC", "ADC R" },
+	{ "Stereo1 ADC R1 Mux", "DAC MIX", "DAC MIXR" },
+	{ "Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC Mux" },
+	{ "Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR" },
+
+	{ "Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux" },
+	{ "Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL" },
+	{ "Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL" },
+	{ "Mono ADC L1 Mux", "ADC", "ADC L" },
+
+	{ "Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR" },
+	{ "Mono ADC R1 Mux", "ADC", "ADC R" },
+	{ "Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux" },
+	{ "Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR" },
+
+	{ "Sto1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux" },
+	{ "Sto1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux" },
+	{ "Sto1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux" },
+	{ "Sto1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux" },
+
+	{ "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" },
+	{ "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" },
+	{ "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" },
+	{ "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" },
+	{ "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux" },
+	{ "Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux" },
+	{ "Mono ADC MIXL", NULL, "adc mono left filter" },
+	{ "adc mono left filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux" },
+	{ "Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux" },
+	{ "Mono ADC MIXR", NULL, "adc mono right filter" },
+	{ "adc mono right filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "VAD ADC Mux", "Sto1 ADC L", "Stereo1 ADC MIXL" },
+	{ "VAD ADC Mux", "Mono ADC L", "Mono ADC MIXL" },
+	{ "VAD ADC Mux", "Mono ADC R", "Mono ADC MIXR" },
+
+	{ "IF_ADC1", NULL, "Stereo1 ADC MIXL" },
+	{ "IF_ADC1", NULL, "Stereo1 ADC MIXR" },
+	{ "IF_ADC2", NULL, "Mono ADC MIXL" },
+	{ "IF_ADC2", NULL, "Mono ADC MIXR" },
+	{ "VAD_ADC", NULL, "VAD ADC Mux" },
+
+	{ "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" },
+	{ "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" },
+	{ "IF2 ADC Mux", "VAD_ADC", "VAD_ADC" },
+
+	{ "IF1 ADC", NULL, "I2S1" },
+	{ "IF2 ADC", NULL, "I2S2" },
+	{ "IF2 ADC", NULL, "IF2 ADC Mux" },
+
+	{ "AIF2TX", NULL, "IF2 ADC" },
+
+	{ "IF1 DAC0", NULL, "AIF1RX" },
+	{ "IF1 DAC1", NULL, "AIF1RX" },
+	{ "IF1 DAC2", NULL, "AIF1RX" },
+	{ "IF1 DAC3", NULL, "AIF1RX" },
+	{ "IF2 DAC", NULL, "AIF2RX" },
+
+	{ "IF1 DAC0", NULL, "I2S1" },
+	{ "IF1 DAC1", NULL, "I2S1" },
+	{ "IF1 DAC2", NULL, "I2S1" },
+	{ "IF1 DAC3", NULL, "I2S1" },
+	{ "IF2 DAC", NULL, "I2S2" },
+
+	{ "IF2 DAC L", NULL, "IF2 DAC" },
+	{ "IF2 DAC R", NULL, "IF2 DAC" },
+
+	{ "DAC1 L Mux", "IF2 DAC", "IF2 DAC L" },
+	{ "DAC1 R Mux", "IF2 DAC", "IF2 DAC R" },
+
+	{ "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" },
+	{ "DAC1 MIXL", "DAC1 Switch", "DAC1 L Mux" },
+	{ "DAC1 MIXL", NULL, "dac stereo1 filter" },
+	{ "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR" },
+	{ "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" },
+	{ "DAC1 MIXR", NULL, "dac stereo1 filter" },
+
+	{ "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" },
+	{ "DAC L2 Mux", "Mono ADC", "Mono ADC MIXL" },
+	{ "DAC L2 Mux", "VAD_ADC", "VAD_ADC" },
+	{ "DAC L2 Volume", NULL, "DAC L2 Mux" },
+	{ "DAC L2 Volume", NULL, "dac mono left filter" },
+
+	{ "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" },
+	{ "DAC R2 Mux", "Mono ADC", "Mono ADC MIXR" },
+	{ "DAC R2 Mux", "Haptic", "Haptic Generator" },
+	{ "DAC R2 Volume", NULL, "DAC R2 Mux" },
+	{ "DAC R2 Volume", NULL, "dac mono right filter" },
+
+	{ "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" },
+	{ "Stereo DAC MIXL", NULL, "dac stereo1 filter" },
+	{ "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" },
+	{ "Stereo DAC MIXR", NULL, "dac stereo1 filter" },
+
+	{ "Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" },
+	{ "Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Volume" },
+	{ "Mono DAC MIXL", NULL, "dac mono left filter" },
+	{ "Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" },
+	{ "Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" },
+	{ "Mono DAC MIXR", NULL, "dac mono right filter" },
+
+	{ "DAC MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" },
+	{ "DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" },
+	{ "DAC MIXL", "DAC R2 Switch", "DAC R2 Volume" },
+	{ "DAC MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" },
+	{ "DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" },
+	{ "DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" },
+
+	{ "DAC L1", NULL, "PLL1", is_sys_clk_from_pll },
+	{ "DAC R1", NULL, "PLL1", is_sys_clk_from_pll },
+	{ "DAC L2", NULL, "PLL1", is_sys_clk_from_pll },
+	{ "DAC R2", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "SPK MIXL", "BST1 Switch", "BST1" },
+	{ "SPK MIXL", "INL Switch", "INL VOL" },
+	{ "SPK MIXL", "DAC L1 Switch", "DAC L1" },
+	{ "SPK MIXL", "DAC L2 Switch", "DAC L2" },
+	{ "SPK MIXR", "BST2 Switch", "BST2" },
+	{ "SPK MIXR", "INR Switch", "INR VOL" },
+	{ "SPK MIXR", "DAC R1 Switch", "DAC R1" },
+	{ "SPK MIXR", "DAC R2 Switch", "DAC R2" },
+
+	{ "OUT MIXL", "BST1 Switch", "BST1" },
+	{ "OUT MIXL", "INL Switch", "INL VOL" },
+	{ "OUT MIXL", "DAC L2 Switch", "DAC L2" },
+	{ "OUT MIXL", "DAC L1 Switch", "DAC L1" },
+
+	{ "OUT MIXR", "BST2 Switch", "BST2" },
+	{ "OUT MIXR", "INR Switch", "INR VOL" },
+	{ "OUT MIXR", "DAC R2 Switch", "DAC R2" },
+	{ "OUT MIXR", "DAC R1 Switch", "DAC R1" },
+
+	{ "HPOVOL MIXL", "DAC1 Switch", "DAC L1" },
+	{ "HPOVOL MIXL", "DAC2 Switch", "DAC L2" },
+	{ "HPOVOL MIXL", "INL Switch", "INL VOL" },
+	{ "HPOVOL MIXL", "BST1 Switch", "BST1" },
+	{ "HPOVOL MIXL", NULL, "HPOVOL MIXL Power" },
+	{ "HPOVOL MIXR", "DAC1 Switch", "DAC R1" },
+	{ "HPOVOL MIXR", "DAC2 Switch", "DAC R2" },
+	{ "HPOVOL MIXR", "INR Switch", "INR VOL" },
+	{ "HPOVOL MIXR", "BST2 Switch", "BST2" },
+	{ "HPOVOL MIXR", NULL, "HPOVOL MIXR Power" },
+
+	{ "DAC 2", NULL, "DAC L2" },
+	{ "DAC 2", NULL, "DAC R2" },
+	{ "DAC 1", NULL, "DAC L1" },
+	{ "DAC 1", NULL, "DAC R1" },
+	{ "HPOVOL L", "Switch", "HPOVOL MIXL" },
+	{ "HPOVOL R", "Switch", "HPOVOL MIXR" },
+	{ "HPOVOL", NULL, "HPOVOL L" },
+	{ "HPOVOL", NULL, "HPOVOL R" },
+	{ "HPO MIX", "DAC1 Switch", "DAC 1" },
+	{ "HPO MIX", "HPVOL Switch", "HPOVOL" },
+
+	{ "SPKVOL L", "Switch", "SPK MIXL" },
+	{ "SPKVOL R", "Switch", "SPK MIXR" },
+
+	{ "SPOL MIX", "DAC L1 Switch", "DAC L1" },
+	{ "SPOL MIX", "SPKVOL L Switch", "SPKVOL L" },
+	{ "SPOR MIX", "DAC R1 Switch", "DAC R1" },
+	{ "SPOR MIX", "SPKVOL R Switch", "SPKVOL R" },
+
+	{ "LOUT MIX", "DAC L1 Switch", "DAC L1" },
+	{ "LOUT MIX", "DAC R1 Switch", "DAC R1" },
+	{ "LOUT MIX", "OUTMIX L Switch", "OUT MIXL" },
+	{ "LOUT MIX", "OUTMIX R Switch", "OUT MIXR" },
+
+	{ "PDM1 L Mux", "Stereo DAC", "Stereo DAC MIXL" },
+	{ "PDM1 L Mux", "Mono DAC", "Mono DAC MIXL" },
+	{ "PDM1 L Mux", NULL, "PDM1 Power" },
+	{ "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
+	{ "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" },
+	{ "PDM1 R Mux", NULL, "PDM1 Power" },
+
+	{ "HP amp", NULL, "HPO MIX" },
+	{ "HP amp", NULL, "JD Power" },
+	{ "HP amp", NULL, "Mic Det Power" },
+	{ "HP amp", NULL, "LDO2" },
+	{ "HPOL", NULL, "HP amp" },
+	{ "HPOR", NULL, "HP amp" },
+
+	{ "LOUT amp", NULL, "LOUT MIX" },
+	{ "LOUTL", NULL, "LOUT amp" },
+	{ "LOUTR", NULL, "LOUT amp" },
+
+	{ "PDM1 L", "Switch", "PDM1 L Mux" },
+	{ "PDM1 R", "Switch", "PDM1 R Mux" },
+
+	{ "PDM1L", NULL, "PDM1 L" },
+	{ "PDM1R", NULL, "PDM1 R" },
+
+	{ "SPK amp", NULL, "SPOL MIX" },
+	{ "SPK amp", NULL, "SPOR MIX" },
+	{ "SPOL", NULL, "SPK amp" },
+	{ "SPOR", NULL, "SPK amp" },
+};
+
+static const struct snd_soc_dapm_route rt5650_specific_dapm_routes[] = {
+	{ "A DAC1 L Mux", "DAC1",  "DAC1 MIXL"},
+	{ "A DAC1 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"},
+	{ "A DAC1 R Mux", "DAC1",  "DAC1 MIXR"},
+	{ "A DAC1 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"},
+
+	{ "A DAC2 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"},
+	{ "A DAC2 L Mux", "Mono DAC Mixer", "Mono DAC MIXL"},
+	{ "A DAC2 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"},
+	{ "A DAC2 R Mux", "Mono DAC Mixer", "Mono DAC MIXR"},
+
+	{ "DAC L1", NULL, "A DAC1 L Mux" },
+	{ "DAC R1", NULL, "A DAC1 R Mux" },
+	{ "DAC L2", NULL, "A DAC2 L Mux" },
+	{ "DAC R2", NULL, "A DAC2 R Mux" },
+
+	{ "RT5650 IF1 ADC1 Swap Mux", "L/R", "IF_ADC1" },
+	{ "RT5650 IF1 ADC1 Swap Mux", "R/L", "IF_ADC1" },
+	{ "RT5650 IF1 ADC1 Swap Mux", "L/L", "IF_ADC1" },
+	{ "RT5650 IF1 ADC1 Swap Mux", "R/R", "IF_ADC1" },
+
+	{ "RT5650 IF1 ADC2 Swap Mux", "L/R", "IF_ADC2" },
+	{ "RT5650 IF1 ADC2 Swap Mux", "R/L", "IF_ADC2" },
+	{ "RT5650 IF1 ADC2 Swap Mux", "L/L", "IF_ADC2" },
+	{ "RT5650 IF1 ADC2 Swap Mux", "R/R", "IF_ADC2" },
+
+	{ "RT5650 IF1 ADC3 Swap Mux", "L/R", "VAD_ADC" },
+	{ "RT5650 IF1 ADC3 Swap Mux", "R/L", "VAD_ADC" },
+	{ "RT5650 IF1 ADC3 Swap Mux", "L/L", "VAD_ADC" },
+	{ "RT5650 IF1 ADC3 Swap Mux", "R/R", "VAD_ADC" },
+
+	{ "IF1 ADC", NULL, "RT5650 IF1 ADC1 Swap Mux" },
+	{ "IF1 ADC", NULL, "RT5650 IF1 ADC2 Swap Mux" },
+	{ "IF1 ADC", NULL, "RT5650 IF1 ADC3 Swap Mux" },
+
+	{ "RT5650 IF1 ADC Mux", "IF_ADC1/IF_ADC2/DAC_REF/Null", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC1/IF_ADC2/Null/DAC_REF", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC1/DAC_REF/IF_ADC2/Null", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC1/DAC_REF/Null/IF_ADC2", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC1/Null/DAC_REF/IF_ADC2", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC1/Null/IF_ADC2/DAC_REF", "IF1 ADC" },
+
+	{ "RT5650 IF1 ADC Mux", "IF_ADC2/IF_ADC1/DAC_REF/Null", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC2/IF_ADC1/Null/DAC_REF", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC2/DAC_REF/IF_ADC1/Null", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC2/DAC_REF/Null/IF_ADC1", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC2/Null/DAC_REF/IF_ADC1", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "IF_ADC2/Null/IF_ADC1/DAC_REF", "IF1 ADC" },
+
+	{ "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC1/IF_ADC2/Null", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC1/Null/IF_ADC2", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC2/IF_ADC1/Null", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC2/Null/IF_ADC1", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "DAC_REF/Null/IF_ADC1/IF_ADC2", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "DAC_REF/Null/IF_ADC2/IF_ADC1", "IF1 ADC" },
+
+	{ "RT5650 IF1 ADC Mux", "Null/IF_ADC1/IF_ADC2/DAC_REF", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "Null/IF_ADC1/DAC_REF/IF_ADC2", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "Null/IF_ADC2/IF_ADC1/DAC_REF", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "Null/IF_ADC2/DAC_REF/IF_ADC1", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "Null/DAC_REF/IF_ADC1/IF_ADC2", "IF1 ADC" },
+	{ "RT5650 IF1 ADC Mux", "Null/DAC_REF/IF_ADC2/IF_ADC1", "IF1 ADC" },
+	{ "AIF1TX", NULL, "RT5650 IF1 ADC Mux" },
+
+	{ "RT5650 IF1 DAC1 L Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5650 IF1 DAC1 L Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5650 IF1 DAC1 L Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5650 IF1 DAC1 L Mux", "Slot3", "IF1 DAC3" },
+
+	{ "RT5650 IF1 DAC1 R Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5650 IF1 DAC1 R Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5650 IF1 DAC1 R Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5650 IF1 DAC1 R Mux", "Slot3", "IF1 DAC3" },
+
+	{ "RT5650 IF1 DAC2 L Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5650 IF1 DAC2 L Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5650 IF1 DAC2 L Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5650 IF1 DAC2 L Mux", "Slot3", "IF1 DAC3" },
+
+	{ "RT5650 IF1 DAC2 R Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5650 IF1 DAC2 R Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5650 IF1 DAC2 R Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5650 IF1 DAC2 R Mux", "Slot3", "IF1 DAC3" },
+
+	{ "DAC1 L Mux", "IF1 DAC", "RT5650 IF1 DAC1 L Mux" },
+	{ "DAC1 R Mux", "IF1 DAC", "RT5650 IF1 DAC1 R Mux" },
+
+	{ "DAC L2 Mux", "IF1 DAC", "RT5650 IF1 DAC2 L Mux" },
+	{ "DAC R2 Mux", "IF1 DAC", "RT5650 IF1 DAC2 R Mux" },
+};
+
+static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
+	{ "DAC L1", NULL, "Stereo DAC MIXL" },
+	{ "DAC R1", NULL, "Stereo DAC MIXR" },
+	{ "DAC L2", NULL, "Mono DAC MIXL" },
+	{ "DAC R2", NULL, "Mono DAC MIXR" },
+
+	{ "RT5645 IF1 ADC1 Swap Mux", "L/R", "IF_ADC1" },
+	{ "RT5645 IF1 ADC1 Swap Mux", "R/L", "IF_ADC1" },
+	{ "RT5645 IF1 ADC1 Swap Mux", "L/L", "IF_ADC1" },
+	{ "RT5645 IF1 ADC1 Swap Mux", "R/R", "IF_ADC1" },
+
+	{ "RT5645 IF1 ADC2 Swap Mux", "L/R", "IF_ADC2" },
+	{ "RT5645 IF1 ADC2 Swap Mux", "R/L", "IF_ADC2" },
+	{ "RT5645 IF1 ADC2 Swap Mux", "L/L", "IF_ADC2" },
+	{ "RT5645 IF1 ADC2 Swap Mux", "R/R", "IF_ADC2" },
+
+	{ "RT5645 IF1 ADC3 Swap Mux", "L/R", "VAD_ADC" },
+	{ "RT5645 IF1 ADC3 Swap Mux", "R/L", "VAD_ADC" },
+	{ "RT5645 IF1 ADC3 Swap Mux", "L/L", "VAD_ADC" },
+	{ "RT5645 IF1 ADC3 Swap Mux", "R/R", "VAD_ADC" },
+
+	{ "IF1 ADC", NULL, "RT5645 IF1 ADC1 Swap Mux" },
+	{ "IF1 ADC", NULL, "RT5645 IF1 ADC2 Swap Mux" },
+	{ "IF1 ADC", NULL, "RT5645 IF1 ADC3 Swap Mux" },
+
+	{ "RT5645 IF1 ADC Mux", "IF_ADC1/IF_ADC2/VAD_ADC", "IF1 ADC" },
+	{ "RT5645 IF1 ADC Mux", "IF_ADC2/IF_ADC1/VAD_ADC", "IF1 ADC" },
+	{ "RT5645 IF1 ADC Mux", "VAD_ADC/IF_ADC1/IF_ADC2", "IF1 ADC" },
+	{ "RT5645 IF1 ADC Mux", "VAD_ADC/IF_ADC2/IF_ADC1", "IF1 ADC" },
+	{ "AIF1TX", NULL, "RT5645 IF1 ADC Mux" },
+
+	{ "RT5645 IF1 DAC1 L Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5645 IF1 DAC1 L Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5645 IF1 DAC1 L Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5645 IF1 DAC1 L Mux", "Slot3", "IF1 DAC3" },
+
+	{ "RT5645 IF1 DAC1 R Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5645 IF1 DAC1 R Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5645 IF1 DAC1 R Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5645 IF1 DAC1 R Mux", "Slot3", "IF1 DAC3" },
+
+	{ "RT5645 IF1 DAC2 L Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5645 IF1 DAC2 L Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5645 IF1 DAC2 L Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5645 IF1 DAC2 L Mux", "Slot3", "IF1 DAC3" },
+
+	{ "RT5645 IF1 DAC2 R Mux", "Slot0", "IF1 DAC0" },
+	{ "RT5645 IF1 DAC2 R Mux", "Slot1", "IF1 DAC1" },
+	{ "RT5645 IF1 DAC2 R Mux", "Slot2", "IF1 DAC2" },
+	{ "RT5645 IF1 DAC2 R Mux", "Slot3", "IF1 DAC3" },
+
+	{ "DAC1 L Mux", "IF1 DAC", "RT5645 IF1 DAC1 L Mux" },
+	{ "DAC1 R Mux", "IF1 DAC", "RT5645 IF1 DAC1 R Mux" },
+
+	{ "DAC L2 Mux", "IF1 DAC", "RT5645 IF1 DAC2 L Mux" },
+	{ "DAC R2 Mux", "IF1 DAC", "RT5645 IF1 DAC2 R Mux" },
+};
+
+static const struct snd_soc_dapm_route rt5645_old_dapm_routes[] = {
+	{ "SPOL MIX", "DAC R1 Switch", "DAC R1" },
+	{ "SPOL MIX", "SPKVOL R Switch", "SPKVOL R" },
+};
+
+static int rt5645_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0, val_clk, mask_clk, dl_sft;
+	int pre_div, bclk_ms, frame_size;
+
+	rt5645->lrck[dai->id] = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5645->sysclk, rt5645->lrck[dai->id]);
+	if (pre_div < 0) {
+		dev_err(component->dev, "Unsupported clock setting\n");
+		return -EINVAL;
+	}
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
+		return -EINVAL;
+	}
+
+	switch (rt5645->codec_type) {
+	case CODEC_TYPE_RT5650:
+		dl_sft = 4;
+		break;
+	default:
+		dl_sft = 2;
+		break;
+	}
+
+	bclk_ms = frame_size > 32;
+	rt5645->bclk[dai->id] = rt5645->lrck[dai->id] * (32 << bclk_ms);
+
+	dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+		rt5645->bclk[dai->id], rt5645->lrck[dai->id]);
+	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+				bclk_ms, pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		val_len = 0x1;
+		break;
+	case 24:
+		val_len = 0x2;
+		break;
+	case 8:
+		val_len = 0x3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5645_AIF1:
+		mask_clk = RT5645_I2S_PD1_MASK;
+		val_clk = pre_div << RT5645_I2S_PD1_SFT;
+		snd_soc_component_update_bits(component, RT5645_I2S1_SDP,
+			(0x3 << dl_sft), (val_len << dl_sft));
+		snd_soc_component_update_bits(component, RT5645_ADDA_CLK1, mask_clk, val_clk);
+		break;
+	case  RT5645_AIF2:
+		mask_clk = RT5645_I2S_BCLK_MS2_MASK | RT5645_I2S_PD2_MASK;
+		val_clk = bclk_ms << RT5645_I2S_BCLK_MS2_SFT |
+			pre_div << RT5645_I2S_PD2_SFT;
+		snd_soc_component_update_bits(component, RT5645_I2S2_SDP,
+			(0x3 << dl_sft), (val_len << dl_sft));
+		snd_soc_component_update_bits(component, RT5645_ADDA_CLK1, mask_clk, val_clk);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5645_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0, pol_sft;
+
+	switch (rt5645->codec_type) {
+	case CODEC_TYPE_RT5650:
+		pol_sft = 8;
+		break;
+	default:
+		pol_sft = 7;
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5645->master[dai->id] = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5645_I2S_MS_S;
+		rt5645->master[dai->id] = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= (1 << pol_sft);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5645_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5645_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5645_I2S_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+	switch (dai->id) {
+	case RT5645_AIF1:
+		snd_soc_component_update_bits(component, RT5645_I2S1_SDP,
+			RT5645_I2S_MS_MASK | (1 << pol_sft) |
+			RT5645_I2S_DF_MASK, reg_val);
+		break;
+	case RT5645_AIF2:
+		snd_soc_component_update_bits(component, RT5645_I2S2_SDP,
+			RT5645_I2S_MS_MASK | (1 << pol_sft) |
+			RT5645_I2S_DF_MASK, reg_val);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int rt5645_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	if (freq == rt5645->sysclk && clk_id == rt5645->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5645_SCLK_S_MCLK:
+		reg_val |= RT5645_SCLK_SRC_MCLK;
+		break;
+	case RT5645_SCLK_S_PLL1:
+		reg_val |= RT5645_SCLK_SRC_PLL1;
+		break;
+	case RT5645_SCLK_S_RCCLK:
+		reg_val |= RT5645_SCLK_SRC_RCCLK;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, RT5645_GLB_CLK,
+		RT5645_SCLK_SRC_MASK, reg_val);
+	rt5645->sysclk = freq;
+	rt5645->sysclk_src = clk_id;
+
+	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+	return 0;
+}
+
+static int rt5645_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+			unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5645->pll_src && freq_in == rt5645->pll_in &&
+	    freq_out == rt5645->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt5645->pll_in = 0;
+		rt5645->pll_out = 0;
+		snd_soc_component_update_bits(component, RT5645_GLB_CLK,
+			RT5645_SCLK_SRC_MASK, RT5645_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5645_PLL1_S_MCLK:
+		snd_soc_component_update_bits(component, RT5645_GLB_CLK,
+			RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_MCLK);
+		break;
+	case RT5645_PLL1_S_BCLK1:
+	case RT5645_PLL1_S_BCLK2:
+		switch (dai->id) {
+		case RT5645_AIF1:
+			snd_soc_component_update_bits(component, RT5645_GLB_CLK,
+				RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_BCLK1);
+			break;
+		case  RT5645_AIF2:
+			snd_soc_component_update_bits(component, RT5645_GLB_CLK,
+				RT5645_PLL1_SRC_MASK, RT5645_PLL1_SRC_BCLK2);
+			break;
+		default:
+			dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+			return -EINVAL;
+		}
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_component_write(component, RT5645_PLL_CTRL1,
+		pll_code.n_code << RT5645_PLL_N_SFT | pll_code.k_code);
+	snd_soc_component_write(component, RT5645_PLL_CTRL2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5645_PLL_M_SFT |
+		pll_code.m_bp << RT5645_PLL_M_BP_SFT);
+
+	rt5645->pll_in = freq_in;
+	rt5645->pll_out = freq_out;
+	rt5645->pll_src = source;
+
+	return 0;
+}
+
+static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+	unsigned int i_slot_sft, o_slot_sft, i_width_sht, o_width_sht, en_sft;
+	unsigned int mask, val = 0;
+
+	switch (rt5645->codec_type) {
+	case CODEC_TYPE_RT5650:
+		en_sft = 15;
+		i_slot_sft = 10;
+		o_slot_sft = 8;
+		i_width_sht = 6;
+		o_width_sht = 4;
+		mask = 0x8ff0;
+		break;
+	default:
+		en_sft = 14;
+		i_slot_sft = o_slot_sft = 12;
+		i_width_sht = o_width_sht = 10;
+		mask = 0x7c00;
+		break;
+	}
+	if (rx_mask || tx_mask) {
+		val |= (1 << en_sft);
+		if (rt5645->codec_type == CODEC_TYPE_RT5645)
+			snd_soc_component_update_bits(component, RT5645_BASS_BACK,
+				RT5645_G_BB_BST_MASK, RT5645_G_BB_BST_25DB);
+	}
+
+	switch (slots) {
+	case 4:
+		val |= (1 << i_slot_sft) | (1 << o_slot_sft);
+		break;
+	case 6:
+		val |= (2 << i_slot_sft) | (2 << o_slot_sft);
+		break;
+	case 8:
+		val |= (3 << i_slot_sft) | (3 << o_slot_sft);
+		break;
+	case 2:
+	default:
+		break;
+	}
+
+	switch (slot_width) {
+	case 20:
+		val |= (1 << i_width_sht) | (1 << o_width_sht);
+		break;
+	case 24:
+		val |= (2 << i_width_sht) | (2 << o_width_sht);
+		break;
+	case 32:
+		val |= (3 << i_width_sht) | (3 << o_width_sht);
+		break;
+	case 16:
+	default:
+		break;
+	}
+
+	snd_soc_component_update_bits(component, RT5645_TDM_CTRL_1, mask, val);
+
+	return 0;
+}
+
+static int rt5645_set_bias_level(struct snd_soc_component *component,
+			enum snd_soc_bias_level level)
+{
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		if (SND_SOC_BIAS_STANDBY == snd_soc_component_get_bias_level(component)) {
+			snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+				RT5645_PWR_VREF1 | RT5645_PWR_MB |
+				RT5645_PWR_BG | RT5645_PWR_VREF2,
+				RT5645_PWR_VREF1 | RT5645_PWR_MB |
+				RT5645_PWR_BG | RT5645_PWR_VREF2);
+			mdelay(10);
+			snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+				RT5645_PWR_FV1 | RT5645_PWR_FV2,
+				RT5645_PWR_FV1 | RT5645_PWR_FV2);
+			snd_soc_component_update_bits(component, RT5645_GEN_CTRL1,
+				RT5645_DIG_GATE_CTRL, RT5645_DIG_GATE_CTRL);
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+			RT5645_PWR_VREF1 | RT5645_PWR_MB |
+			RT5645_PWR_BG | RT5645_PWR_VREF2,
+			RT5645_PWR_VREF1 | RT5645_PWR_MB |
+			RT5645_PWR_BG | RT5645_PWR_VREF2);
+		mdelay(10);
+		snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+			RT5645_PWR_FV1 | RT5645_PWR_FV2,
+			RT5645_PWR_FV1 | RT5645_PWR_FV2);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
+			msleep(40);
+			if (rt5645->en_button_func)
+				queue_delayed_work(system_power_efficient_wq,
+					&rt5645->jack_detect_work,
+					msecs_to_jiffies(0));
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1100);
+		if (!rt5645->en_button_func)
+			snd_soc_component_update_bits(component, RT5645_GEN_CTRL1,
+					RT5645_DIG_GATE_CTRL, 0);
+		snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+				RT5645_PWR_VREF1 | RT5645_PWR_MB |
+				RT5645_PWR_BG | RT5645_PWR_VREF2 |
+				RT5645_PWR_FV1 | RT5645_PWR_FV2, 0x0);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static void rt5645_enable_push_button_irq(struct snd_soc_component *component,
+	bool enable)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	if (enable) {
+		snd_soc_dapm_force_enable_pin(dapm, "ADC L power");
+		snd_soc_dapm_force_enable_pin(dapm, "ADC R power");
+		snd_soc_dapm_sync(dapm);
+
+		snd_soc_component_update_bits(component, RT5650_4BTN_IL_CMD1, 0x3, 0x3);
+		snd_soc_component_update_bits(component,
+					RT5645_INT_IRQ_ST, 0x8, 0x8);
+		snd_soc_component_update_bits(component,
+					RT5650_4BTN_IL_CMD2, 0x8000, 0x8000);
+		snd_soc_component_read32(component, RT5650_4BTN_IL_CMD1);
+		pr_debug("%s read %x = %x\n", __func__, RT5650_4BTN_IL_CMD1,
+			snd_soc_component_read32(component, RT5650_4BTN_IL_CMD1));
+	} else {
+		snd_soc_component_update_bits(component, RT5650_4BTN_IL_CMD2, 0x8000, 0x0);
+		snd_soc_component_update_bits(component, RT5645_INT_IRQ_ST, 0x8, 0x0);
+
+		snd_soc_dapm_disable_pin(dapm, "ADC L power");
+		snd_soc_dapm_disable_pin(dapm, "ADC R power");
+		snd_soc_dapm_sync(dapm);
+	}
+}
+
+static int rt5645_jack_detect(struct snd_soc_component *component, int jack_insert)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	if (jack_insert) {
+		regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06);
+
+		/* for jack type detect */
+		snd_soc_dapm_force_enable_pin(dapm, "LDO2");
+		snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power");
+		snd_soc_dapm_sync(dapm);
+		if (!dapm->card->instantiated) {
+			/* Power up necessary bits for JD if dapm is
+			   not ready yet */
+			regmap_update_bits(rt5645->regmap, RT5645_PWR_ANLG1,
+				RT5645_PWR_MB | RT5645_PWR_VREF2,
+				RT5645_PWR_MB | RT5645_PWR_VREF2);
+			regmap_update_bits(rt5645->regmap, RT5645_PWR_MIXER,
+				RT5645_PWR_LDO2, RT5645_PWR_LDO2);
+			regmap_update_bits(rt5645->regmap, RT5645_PWR_VOL,
+				RT5645_PWR_MIC_DET, RT5645_PWR_MIC_DET);
+		}
+
+		regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0);
+		regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2,
+			RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD);
+		regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
+			RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
+		msleep(100);
+		regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2,
+			RT5645_CBJ_MN_JD, 0);
+
+		msleep(600);
+		regmap_read(rt5645->regmap, RT5645_IN1_CTRL3, &val);
+		val &= 0x7;
+		dev_dbg(component->dev, "val = %d\n", val);
+
+		if (val == 1 || val == 2) {
+			rt5645->jack_type = SND_JACK_HEADSET;
+			if (rt5645->en_button_func) {
+				rt5645_enable_push_button_irq(component, true);
+			}
+		} else {
+			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+			snd_soc_dapm_sync(dapm);
+			rt5645->jack_type = SND_JACK_HEADPHONE;
+		}
+		if (rt5645->pdata.level_trigger_irq)
+			regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
+				RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
+	} else { /* jack out */
+		rt5645->jack_type = 0;
+
+		regmap_update_bits(rt5645->regmap, RT5645_HP_VOL,
+			RT5645_L_MUTE | RT5645_R_MUTE,
+			RT5645_L_MUTE | RT5645_R_MUTE);
+		regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2,
+			RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD);
+		regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
+			RT5645_CBJ_BST1_EN, 0);
+
+		if (rt5645->en_button_func)
+			rt5645_enable_push_button_irq(component, false);
+
+		if (rt5645->pdata.jd_mode == 0)
+			snd_soc_dapm_disable_pin(dapm, "LDO2");
+		snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+		snd_soc_dapm_sync(dapm);
+		if (rt5645->pdata.level_trigger_irq)
+			regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
+				RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
+	}
+
+	return rt5645->jack_type;
+}
+
+static int rt5645_button_detect(struct snd_soc_component *component)
+{
+	int btn_type, val;
+
+	val = snd_soc_component_read32(component, RT5650_4BTN_IL_CMD1);
+	pr_debug("val=0x%x\n", val);
+	btn_type = val & 0xfff0;
+	snd_soc_component_write(component, RT5650_4BTN_IL_CMD1, val);
+
+	return btn_type;
+}
+
+static irqreturn_t rt5645_irq(int irq, void *data);
+
+int rt5645_set_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack,
+	struct snd_soc_jack *btn_jack)
+{
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+
+	rt5645->hp_jack = hp_jack;
+	rt5645->mic_jack = mic_jack;
+	rt5645->btn_jack = btn_jack;
+	if (rt5645->btn_jack && rt5645->codec_type == CODEC_TYPE_RT5650) {
+		rt5645->en_button_func = true;
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+				RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ);
+		regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL1,
+				RT5645_DIG_GATE_CTRL, RT5645_DIG_GATE_CTRL);
+	}
+	rt5645_irq(0, rt5645);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5645_set_jack_detect);
+
+static void rt5645_jack_detect_work(struct work_struct *work)
+{
+	struct rt5645_priv *rt5645 =
+		container_of(work, struct rt5645_priv, jack_detect_work.work);
+	int val, btn_type, gpio_state = 0, report = 0;
+
+	if (!rt5645->component)
+		return;
+
+	switch (rt5645->pdata.jd_mode) {
+	case 0: /* Not using rt5645 JD */
+		if (rt5645->gpiod_hp_det) {
+			gpio_state = gpiod_get_value(rt5645->gpiod_hp_det);
+			dev_dbg(rt5645->component->dev, "gpio_state = %d\n",
+				gpio_state);
+			report = rt5645_jack_detect(rt5645->component, gpio_state);
+		}
+		snd_soc_jack_report(rt5645->hp_jack,
+				    report, SND_JACK_HEADPHONE);
+		snd_soc_jack_report(rt5645->mic_jack,
+				    report, SND_JACK_MICROPHONE);
+		return;
+	default: /* read rt5645 jd1_1 status */
+		val = snd_soc_component_read32(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000;
+		break;
+
+	}
+
+	if (!val && (rt5645->jack_type == 0)) { /* jack in */
+		report = rt5645_jack_detect(rt5645->component, 1);
+	} else if (!val && rt5645->jack_type != 0) {
+		/* for push button and jack out */
+		btn_type = 0;
+		if (snd_soc_component_read32(rt5645->component, RT5645_INT_IRQ_ST) & 0x4) {
+			/* button pressed */
+			report = SND_JACK_HEADSET;
+			btn_type = rt5645_button_detect(rt5645->component);
+			/* rt5650 can report three kinds of button behavior,
+			   one click, double click and hold. However,
+			   currently we will report button pressed/released
+			   event. So all the three button behaviors are
+			   treated as button pressed. */
+			switch (btn_type) {
+			case 0x8000:
+			case 0x4000:
+			case 0x2000:
+				report |= SND_JACK_BTN_0;
+				break;
+			case 0x1000:
+			case 0x0800:
+			case 0x0400:
+				report |= SND_JACK_BTN_1;
+				break;
+			case 0x0200:
+			case 0x0100:
+			case 0x0080:
+				report |= SND_JACK_BTN_2;
+				break;
+			case 0x0040:
+			case 0x0020:
+			case 0x0010:
+				report |= SND_JACK_BTN_3;
+				break;
+			case 0x0000: /* unpressed */
+				break;
+			default:
+				dev_err(rt5645->component->dev,
+					"Unexpected button code 0x%04x\n",
+					btn_type);
+				break;
+			}
+		}
+		if (btn_type == 0)/* button release */
+			report =  rt5645->jack_type;
+		else {
+			mod_timer(&rt5645->btn_check_timer,
+				msecs_to_jiffies(100));
+		}
+	} else {
+		/* jack out */
+		report = 0;
+		snd_soc_component_update_bits(rt5645->component,
+				    RT5645_INT_IRQ_ST, 0x1, 0x0);
+		rt5645_jack_detect(rt5645->component, 0);
+	}
+
+	snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE);
+	snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE);
+	if (rt5645->en_button_func)
+		snd_soc_jack_report(rt5645->btn_jack,
+			report, SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				SND_JACK_BTN_2 | SND_JACK_BTN_3);
+}
+
+static void rt5645_rcclock_work(struct work_struct *work)
+{
+	struct rt5645_priv *rt5645 =
+		container_of(work, struct rt5645_priv, rcclock_work.work);
+
+	regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
+		RT5645_PWR_CLK25M_MASK, RT5645_PWR_CLK25M_PD);
+}
+
+static irqreturn_t rt5645_irq(int irq, void *data)
+{
+	struct rt5645_priv *rt5645 = data;
+
+	queue_delayed_work(system_power_efficient_wq,
+			   &rt5645->jack_detect_work, msecs_to_jiffies(250));
+
+	return IRQ_HANDLED;
+}
+
+static void rt5645_btn_check_callback(struct timer_list *t)
+{
+	struct rt5645_priv *rt5645 = from_timer(rt5645, t, btn_check_timer);
+
+	queue_delayed_work(system_power_efficient_wq,
+		   &rt5645->jack_detect_work, msecs_to_jiffies(5));
+}
+
+static int rt5645_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+
+	rt5645->component = component;
+
+	switch (rt5645->codec_type) {
+	case CODEC_TYPE_RT5645:
+		snd_soc_dapm_new_controls(dapm,
+			rt5645_specific_dapm_widgets,
+			ARRAY_SIZE(rt5645_specific_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm,
+			rt5645_specific_dapm_routes,
+			ARRAY_SIZE(rt5645_specific_dapm_routes));
+		if (rt5645->v_id < 3) {
+			snd_soc_dapm_add_routes(dapm,
+				rt5645_old_dapm_routes,
+				ARRAY_SIZE(rt5645_old_dapm_routes));
+		}
+		break;
+	case CODEC_TYPE_RT5650:
+		snd_soc_dapm_new_controls(dapm,
+			rt5650_specific_dapm_widgets,
+			ARRAY_SIZE(rt5650_specific_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm,
+			rt5650_specific_dapm_routes,
+			ARRAY_SIZE(rt5650_specific_dapm_routes));
+		break;
+	}
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+
+	/* for JD function */
+	if (rt5645->pdata.jd_mode) {
+		snd_soc_dapm_force_enable_pin(dapm, "JD Power");
+		snd_soc_dapm_force_enable_pin(dapm, "LDO2");
+		snd_soc_dapm_sync(dapm);
+	}
+
+	if (rt5645->pdata.long_name)
+		component->card->long_name = rt5645->pdata.long_name;
+
+	rt5645->eq_param = devm_kcalloc(component->dev,
+		RT5645_HWEQ_NUM, sizeof(struct rt5645_eq_param_s),
+		GFP_KERNEL);
+
+	return 0;
+}
+
+static void rt5645_remove(struct snd_soc_component *component)
+{
+	rt5645_reset(component);
+}
+
+#ifdef CONFIG_PM
+static int rt5645_suspend(struct snd_soc_component *component)
+{
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5645->regmap, true);
+	regcache_mark_dirty(rt5645->regmap);
+
+	return 0;
+}
+
+static int rt5645_resume(struct snd_soc_component *component)
+{
+	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5645->regmap, false);
+	regcache_sync(rt5645->regmap);
+
+	return 0;
+}
+#else
+#define rt5645_suspend NULL
+#define rt5645_resume NULL
+#endif
+
+#define RT5645_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define RT5645_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5645_aif_dai_ops = {
+	.hw_params = rt5645_hw_params,
+	.set_fmt = rt5645_set_dai_fmt,
+	.set_sysclk = rt5645_set_dai_sysclk,
+	.set_tdm_slot = rt5645_set_tdm_slot,
+	.set_pll = rt5645_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver rt5645_dai[] = {
+	{
+		.name = "rt5645-aif1",
+		.id = RT5645_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5645_STEREO_RATES,
+			.formats = RT5645_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = RT5645_STEREO_RATES,
+			.formats = RT5645_FORMATS,
+		},
+		.ops = &rt5645_aif_dai_ops,
+	},
+	{
+		.name = "rt5645-aif2",
+		.id = RT5645_AIF2,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5645_STEREO_RATES,
+			.formats = RT5645_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5645_STEREO_RATES,
+			.formats = RT5645_FORMATS,
+		},
+		.ops = &rt5645_aif_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5645 = {
+	.probe			= rt5645_probe,
+	.remove			= rt5645_remove,
+	.suspend		= rt5645_suspend,
+	.resume			= rt5645_resume,
+	.set_bias_level		= rt5645_set_bias_level,
+	.controls		= rt5645_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5645_snd_controls),
+	.dapm_widgets		= rt5645_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5645_dapm_widgets),
+	.dapm_routes		= rt5645_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5645_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt5645_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.use_single_rw = true,
+	.max_register = RT5645_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5645_ranges) *
+					       RT5645_PR_SPACING),
+	.volatile_reg = rt5645_volatile_register,
+	.readable_reg = rt5645_readable_register,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5645_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5645_reg),
+	.ranges = rt5645_ranges,
+	.num_ranges = ARRAY_SIZE(rt5645_ranges),
+};
+
+static const struct regmap_config rt5650_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.use_single_rw = true,
+	.max_register = RT5645_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5645_ranges) *
+					       RT5645_PR_SPACING),
+	.volatile_reg = rt5645_volatile_register,
+	.readable_reg = rt5645_readable_register,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5650_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5650_reg),
+	.ranges = rt5645_ranges,
+	.num_ranges = ARRAY_SIZE(rt5645_ranges),
+};
+
+static const struct regmap_config temp_regmap = {
+	.name="nocache",
+	.reg_bits = 8,
+	.val_bits = 16,
+	.use_single_rw = true,
+	.max_register = RT5645_VENDOR_ID2 + 1,
+	.cache_type = REGCACHE_NONE,
+};
+
+static const struct i2c_device_id rt5645_i2c_id[] = {
+	{ "rt5645", 0 },
+	{ "rt5650", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt5645_of_match[] = {
+	{ .compatible = "realtek,rt5645", },
+	{ .compatible = "realtek,rt5650", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, rt5645_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5645_acpi_match[] = {
+	{ "10EC5645", 0 },
+	{ "10EC5648", 0 },
+	{ "10EC5650", 0 },
+	{ "10EC5640", 0 },
+	{ "10EC3270", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
+#endif
+
+static const struct rt5645_platform_data intel_braswell_platform_data = {
+	.dmic1_data_pin = RT5645_DMIC1_DISABLE,
+	.dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
+	.jd_mode = 3,
+};
+
+static const struct rt5645_platform_data buddy_platform_data = {
+	.dmic1_data_pin = RT5645_DMIC_DATA_GPIO5,
+	.dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
+	.jd_mode = 3,
+	.level_trigger_irq = true,
+};
+
+static const struct rt5645_platform_data gpd_win_platform_data = {
+	.jd_mode = 3,
+	.inv_jd1_1 = true,
+	.long_name = "gpd-win-pocket-rt5645",
+	/* The GPD pocket has a diff. mic, for the win this does not matter. */
+	.in2_diff = true,
+};
+
+static const struct rt5645_platform_data asus_t100ha_platform_data = {
+	.dmic1_data_pin = RT5645_DMIC_DATA_IN2N,
+	.dmic2_data_pin = RT5645_DMIC2_DISABLE,
+	.jd_mode = 3,
+	.inv_jd1_1 = true,
+};
+
+static const struct rt5645_platform_data lenovo_ideapad_miix_310_pdata = {
+	.jd_mode = 3,
+	.in2_diff = true,
+};
+
+static const struct rt5645_platform_data jd_mode3_platform_data = {
+	.jd_mode = 3,
+};
+
+static const struct dmi_system_id dmi_platform_data[] = {
+	{
+		.ident = "Chrome Buddy",
+		.matches = {
+			DMI_MATCH(DMI_PRODUCT_NAME, "Buddy"),
+		},
+		.driver_data = (void *)&buddy_platform_data,
+	},
+	{
+		.ident = "Intel Strago",
+		.matches = {
+			DMI_MATCH(DMI_PRODUCT_NAME, "Strago"),
+		},
+		.driver_data = (void *)&intel_braswell_platform_data,
+	},
+	{
+		.ident = "Google Chrome",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
+		},
+		.driver_data = (void *)&intel_braswell_platform_data,
+	},
+	{
+		.ident = "Google Setzer",
+		.matches = {
+			DMI_MATCH(DMI_PRODUCT_NAME, "Setzer"),
+		},
+		.driver_data = (void *)&intel_braswell_platform_data,
+	},
+	{
+		.ident = "Microsoft Surface 3",
+		.matches = {
+			DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
+		},
+		.driver_data = (void *)&intel_braswell_platform_data,
+	},
+	{
+		/*
+		 * Match for the GPDwin which unfortunately uses somewhat
+		 * generic dmi strings, which is why we test for 4 strings.
+		 * Comparing against 23 other byt/cht boards, board_vendor
+		 * and board_name are unique to the GPDwin, where as only one
+		 * other board has the same board_serial and 3 others have
+		 * the same default product_name. Also the GPDwin is the
+		 * only device to have both board_ and product_name not set.
+		 */
+		.ident = "GPD Win / Pocket",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+			DMI_MATCH(DMI_BOARD_NAME, "Default string"),
+			DMI_MATCH(DMI_BOARD_SERIAL, "Default string"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
+		},
+		.driver_data = (void *)&gpd_win_platform_data,
+	},
+	{
+		.ident = "ASUS T100HAN",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "T100HAN"),
+		},
+		.driver_data = (void *)&asus_t100ha_platform_data,
+	},
+	{
+		.ident = "MINIX Z83-4",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MINIX"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
+		},
+		.driver_data = (void *)&jd_mode3_platform_data,
+	},
+	{
+		.ident = "Teclast X80 Pro",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "X80 Pro"),
+		},
+		.driver_data = (void *)&jd_mode3_platform_data,
+	},
+	{
+		.ident = "Lenovo Ideapad Miix 310",
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80SG"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "MIIX 310-10ICR"),
+		},
+		.driver_data = (void *)&lenovo_ideapad_miix_310_pdata,
+	},
+	{
+		.ident = "Lenovo Ideapad Miix 320",
+		.matches = {
+		  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80XF"),
+		  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
+		},
+		.driver_data = (void *)&intel_braswell_platform_data,
+	},
+	{ }
+};
+
+static bool rt5645_check_dp(struct device *dev)
+{
+	if (device_property_present(dev, "realtek,in2-differential") ||
+	    device_property_present(dev, "realtek,dmic1-data-pin") ||
+	    device_property_present(dev, "realtek,dmic2-data-pin") ||
+	    device_property_present(dev, "realtek,jd-mode"))
+		return true;
+
+	return false;
+}
+
+static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev)
+{
+	rt5645->pdata.in2_diff = device_property_read_bool(dev,
+		"realtek,in2-differential");
+	device_property_read_u32(dev,
+		"realtek,dmic1-data-pin", &rt5645->pdata.dmic1_data_pin);
+	device_property_read_u32(dev,
+		"realtek,dmic2-data-pin", &rt5645->pdata.dmic2_data_pin);
+	device_property_read_u32(dev,
+		"realtek,jd-mode", &rt5645->pdata.jd_mode);
+
+	return 0;
+}
+
+static int rt5645_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5645_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	const struct dmi_system_id *dmi_data;
+	struct rt5645_priv *rt5645;
+	int ret, i;
+	unsigned int val;
+	struct regmap *regmap;
+
+	rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv),
+				GFP_KERNEL);
+	if (rt5645 == NULL)
+		return -ENOMEM;
+
+	rt5645->i2c = i2c;
+	i2c_set_clientdata(i2c, rt5645);
+
+	dmi_data = dmi_first_match(dmi_platform_data);
+	if (dmi_data) {
+		dev_info(&i2c->dev, "Detected %s platform\n", dmi_data->ident);
+		pdata = dmi_data->driver_data;
+	}
+
+	if (pdata)
+		rt5645->pdata = *pdata;
+	else if (rt5645_check_dp(&i2c->dev))
+		rt5645_parse_dt(rt5645, &i2c->dev);
+	else
+		rt5645->pdata = jd_mode3_platform_data;
+
+	if (quirk != -1) {
+		rt5645->pdata.in2_diff = QUIRK_IN2_DIFF(quirk);
+		rt5645->pdata.level_trigger_irq = QUIRK_LEVEL_IRQ(quirk);
+		rt5645->pdata.inv_jd1_1 = QUIRK_INV_JD1_1(quirk);
+		rt5645->pdata.jd_mode = QUIRK_JD_MODE(quirk);
+		rt5645->pdata.dmic1_data_pin = QUIRK_DMIC1_DATA_PIN(quirk);
+		rt5645->pdata.dmic2_data_pin = QUIRK_DMIC2_DATA_PIN(quirk);
+	}
+
+	rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect",
+						       GPIOD_IN);
+
+	if (IS_ERR(rt5645->gpiod_hp_det)) {
+		dev_info(&i2c->dev, "failed to initialize gpiod\n");
+		ret = PTR_ERR(rt5645->gpiod_hp_det);
+		/*
+		 * Continue if optional gpiod is missing, bail for all other
+		 * errors, including -EPROBE_DEFER
+		 */
+		if (ret != -ENOENT)
+			return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++)
+		rt5645->supplies[i].supply = rt5645_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev,
+				      ARRAY_SIZE(rt5645->supplies),
+				      rt5645->supplies);
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(rt5645->supplies),
+				    rt5645->supplies);
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	regmap = devm_regmap_init_i2c(i2c, &temp_regmap);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	/*
+	 * Read after 400msec, as it is the interval required between
+	 * read and power On.
+	 */
+	msleep(TIME_TO_POWER_MS);
+	regmap_read(regmap, RT5645_VENDOR_ID2, &val);
+
+	switch (val) {
+	case RT5645_DEVICE_ID:
+		rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap);
+		rt5645->codec_type = CODEC_TYPE_RT5645;
+		break;
+	case RT5650_DEVICE_ID:
+		rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5650_regmap);
+		rt5645->codec_type = CODEC_TYPE_RT5650;
+		break;
+	default:
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt5645 or rt5650\n",
+			val);
+		ret = -ENODEV;
+		goto err_enable;
+	}
+
+	if (IS_ERR(rt5645->regmap)) {
+		ret = PTR_ERR(rt5645->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_write(rt5645->regmap, RT5645_RESET, 0);
+
+	regmap_read(regmap, RT5645_VENDOR_ID, &val);
+	rt5645->v_id = val & 0xff;
+
+	regmap_write(rt5645->regmap, RT5645_AD_DA_MIXER, 0x8080);
+
+	ret = regmap_register_patch(rt5645->regmap, init_list,
+				    ARRAY_SIZE(init_list));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+		ret = regmap_register_patch(rt5645->regmap, rt5650_init_list,
+				    ARRAY_SIZE(rt5650_init_list));
+		if (ret != 0)
+			dev_warn(&i2c->dev, "Apply rt5650 patch failed: %d\n",
+					   ret);
+	}
+
+	regmap_update_bits(rt5645->regmap, RT5645_CLSD_OUT_CTRL, 0xc0, 0xc0);
+
+	if (rt5645->pdata.in2_diff)
+		regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL,
+					RT5645_IN_DF2, RT5645_IN_DF2);
+
+	if (rt5645->pdata.dmic1_data_pin || rt5645->pdata.dmic2_data_pin) {
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+			RT5645_GP2_PIN_MASK, RT5645_GP2_PIN_DMIC1_SCL);
+	}
+	switch (rt5645->pdata.dmic1_data_pin) {
+	case RT5645_DMIC_DATA_IN2N:
+		regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_IN2N);
+		break;
+
+	case RT5645_DMIC_DATA_GPIO5:
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+			RT5645_I2S2_DAC_PIN_MASK, RT5645_I2S2_DAC_PIN_GPIO);
+		regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO5);
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+			RT5645_GP5_PIN_MASK, RT5645_GP5_PIN_DMIC1_SDA);
+		break;
+
+	case RT5645_DMIC_DATA_GPIO11:
+		regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO11);
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+			RT5645_GP11_PIN_MASK,
+			RT5645_GP11_PIN_DMIC1_SDA);
+		break;
+
+	default:
+		break;
+	}
+
+	switch (rt5645->pdata.dmic2_data_pin) {
+	case RT5645_DMIC_DATA_IN2P:
+		regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_IN2P);
+		break;
+
+	case RT5645_DMIC_DATA_GPIO6:
+		regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO6);
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+			RT5645_GP6_PIN_MASK, RT5645_GP6_PIN_DMIC2_SDA);
+		break;
+
+	case RT5645_DMIC_DATA_GPIO10:
+		regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO10);
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+			RT5645_GP10_PIN_MASK,
+			RT5645_GP10_PIN_DMIC2_SDA);
+		break;
+
+	case RT5645_DMIC_DATA_GPIO12:
+		regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+			RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO12);
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+			RT5645_GP12_PIN_MASK,
+			RT5645_GP12_PIN_DMIC2_SDA);
+		break;
+
+	default:
+		break;
+	}
+
+	if (rt5645->pdata.jd_mode) {
+		regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
+				   RT5645_IRQ_CLK_GATE_CTRL,
+				   RT5645_IRQ_CLK_GATE_CTRL);
+		regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
+				   RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT);
+		regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
+				   RT5645_IRQ_JD_1_1_EN, RT5645_IRQ_JD_1_1_EN);
+		regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
+				   RT5645_JD_PSV_MODE, RT5645_JD_PSV_MODE);
+		regmap_update_bits(rt5645->regmap, RT5645_HPO_MIXER,
+				   RT5645_IRQ_PSV_MODE, RT5645_IRQ_PSV_MODE);
+		regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
+				   RT5645_MIC2_OVCD_EN, RT5645_MIC2_OVCD_EN);
+		regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+				   RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ);
+		switch (rt5645->pdata.jd_mode) {
+		case 1:
+			regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
+					   RT5645_JD1_MODE_MASK,
+					   RT5645_JD1_MODE_0);
+			break;
+		case 2:
+			regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
+					   RT5645_JD1_MODE_MASK,
+					   RT5645_JD1_MODE_1);
+			break;
+		case 3:
+			regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
+					   RT5645_JD1_MODE_MASK,
+					   RT5645_JD1_MODE_2);
+			break;
+		default:
+			break;
+		}
+		if (rt5645->pdata.inv_jd1_1) {
+			regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
+				RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
+		}
+	}
+
+	regmap_update_bits(rt5645->regmap, RT5645_ADDA_CLK1,
+		RT5645_I2S_PD1_MASK, RT5645_I2S_PD1_2);
+
+	if (rt5645->pdata.level_trigger_irq) {
+		regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
+			RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
+	}
+	timer_setup(&rt5645->btn_check_timer, rt5645_btn_check_callback, 0);
+
+	INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
+	INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work);
+
+	if (rt5645->i2c->irq) {
+		ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq,
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+			| IRQF_ONESHOT, "rt5645", rt5645);
+		if (ret) {
+			dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+			goto err_enable;
+		}
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5645,
+				     rt5645_dai, ARRAY_SIZE(rt5645_dai));
+	if (ret)
+		goto err_irq;
+
+	return 0;
+
+err_irq:
+	if (rt5645->i2c->irq)
+		free_irq(rt5645->i2c->irq, rt5645);
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies);
+	return ret;
+}
+
+static int rt5645_i2c_remove(struct i2c_client *i2c)
+{
+	struct rt5645_priv *rt5645 = i2c_get_clientdata(i2c);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, rt5645);
+
+	cancel_delayed_work_sync(&rt5645->jack_detect_work);
+	cancel_delayed_work_sync(&rt5645->rcclock_work);
+	del_timer_sync(&rt5645->btn_check_timer);
+
+	regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies);
+
+	return 0;
+}
+
+static void rt5645_i2c_shutdown(struct i2c_client *i2c)
+{
+	struct rt5645_priv *rt5645 = i2c_get_clientdata(i2c);
+
+	regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
+		RT5645_RING2_SLEEVE_GND, RT5645_RING2_SLEEVE_GND);
+	regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, RT5645_CBJ_MN_JD,
+		RT5645_CBJ_MN_JD);
+	regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, RT5645_CBJ_BST1_EN,
+		0);
+	msleep(20);
+	regmap_write(rt5645->regmap, RT5645_RESET, 0);
+}
+
+static struct i2c_driver rt5645_i2c_driver = {
+	.driver = {
+		.name = "rt5645",
+		.of_match_table = of_match_ptr(rt5645_of_match),
+		.acpi_match_table = ACPI_PTR(rt5645_acpi_match),
+	},
+	.probe = rt5645_i2c_probe,
+	.remove = rt5645_i2c_remove,
+	.shutdown = rt5645_i2c_shutdown,
+	.id_table = rt5645_i2c_id,
+};
+module_i2c_driver(rt5645_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5645 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
new file mode 100644
index 0000000..cc24557
--- /dev/null
+++ b/sound/soc/codecs/rt5645.h
@@ -0,0 +1,2209 @@
+/*
+ * rt5645.h  --  RT5645 ALSA SoC audio driver
+ *
+ * Copyright 2013 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5645_H__
+#define __RT5645_H__
+
+#include <sound/rt5645.h>
+
+/* Info */
+#define RT5645_RESET				0x00
+#define RT5645_VENDOR_ID			0xfd
+#define RT5645_VENDOR_ID1			0xfe
+#define RT5645_VENDOR_ID2			0xff
+/*  I/O - Output */
+#define RT5645_SPK_VOL				0x01
+#define RT5645_HP_VOL				0x02
+#define RT5645_LOUT1				0x03
+#define RT5645_LOUT_CTRL			0x05
+/* I/O - Input */
+#define RT5645_IN1_CTRL1			0x0a
+#define RT5645_IN1_CTRL2			0x0b
+#define RT5645_IN1_CTRL3			0x0c
+#define RT5645_IN2_CTRL				0x0d
+#define RT5645_INL1_INR1_VOL			0x0f
+#define RT5645_SPK_FUNC_LIM			0x14
+#define RT5645_ADJ_HPF_CTRL			0x16
+/* I/O - ADC/DAC/DMIC */
+#define RT5645_DAC1_DIG_VOL			0x19
+#define RT5645_DAC2_DIG_VOL			0x1a
+#define RT5645_DAC_CTRL				0x1b
+#define RT5645_STO1_ADC_DIG_VOL			0x1c
+#define RT5645_MONO_ADC_DIG_VOL			0x1d
+#define RT5645_ADC_BST_VOL1			0x1e
+#define RT5645_ADC_BST_VOL2			0x20
+/* Mixer - D-D */
+#define RT5645_STO1_ADC_MIXER			0x27
+#define RT5645_MONO_ADC_MIXER			0x28
+#define RT5645_AD_DA_MIXER			0x29
+#define RT5645_STO_DAC_MIXER			0x2a
+#define RT5645_MONO_DAC_MIXER			0x2b
+#define RT5645_DIG_MIXER			0x2c
+#define RT5650_A_DAC_SOUR			0x2d
+#define RT5645_DIG_INF1_DATA			0x2f
+/* Mixer - PDM */
+#define RT5645_PDM_OUT_CTRL			0x31
+/* Mixer - ADC */
+#define RT5645_REC_L1_MIXER			0x3b
+#define RT5645_REC_L2_MIXER			0x3c
+#define RT5645_REC_R1_MIXER			0x3d
+#define RT5645_REC_R2_MIXER			0x3e
+/* Mixer - DAC */
+#define RT5645_HPMIXL_CTRL			0x3f
+#define RT5645_HPOMIXL_CTRL			0x40
+#define RT5645_HPMIXR_CTRL			0x41
+#define RT5645_HPOMIXR_CTRL			0x42
+#define RT5645_HPO_MIXER			0x45
+#define RT5645_SPK_L_MIXER			0x46
+#define RT5645_SPK_R_MIXER			0x47
+#define RT5645_SPO_MIXER			0x48
+#define RT5645_SPO_CLSD_RATIO			0x4a
+#define RT5645_OUT_L_GAIN1			0x4d
+#define RT5645_OUT_L_GAIN2			0x4e
+#define RT5645_OUT_L1_MIXER			0x4f
+#define RT5645_OUT_R_GAIN1			0x50
+#define RT5645_OUT_R_GAIN2			0x51
+#define RT5645_OUT_R1_MIXER			0x52
+#define RT5645_LOUT_MIXER			0x53
+/* Haptic */
+#define RT5645_HAPTIC_CTRL1			0x56
+#define RT5645_HAPTIC_CTRL2			0x57
+#define RT5645_HAPTIC_CTRL3			0x58
+#define RT5645_HAPTIC_CTRL4			0x59
+#define RT5645_HAPTIC_CTRL5			0x5a
+#define RT5645_HAPTIC_CTRL6			0x5b
+#define RT5645_HAPTIC_CTRL7			0x5c
+#define RT5645_HAPTIC_CTRL8			0x5d
+#define RT5645_HAPTIC_CTRL9			0x5e
+#define RT5645_HAPTIC_CTRL10			0x5f
+/* Power */
+#define RT5645_PWR_DIG1				0x61
+#define RT5645_PWR_DIG2				0x62
+#define RT5645_PWR_ANLG1			0x63
+#define RT5645_PWR_ANLG2			0x64
+#define RT5645_PWR_MIXER			0x65
+#define RT5645_PWR_VOL				0x66
+/* Private Register Control */
+#define RT5645_PRIV_INDEX			0x6a
+#define RT5645_PRIV_DATA			0x6c
+/* Format - ADC/DAC */
+#define RT5645_I2S1_SDP				0x70
+#define RT5645_I2S2_SDP				0x71
+#define RT5645_ADDA_CLK1			0x73
+#define RT5645_ADDA_CLK2			0x74
+#define RT5645_DMIC_CTRL1			0x75
+#define RT5645_DMIC_CTRL2			0x76
+/* Format - TDM Control */
+#define RT5645_TDM_CTRL_1			0x77
+#define RT5645_TDM_CTRL_2			0x78
+#define RT5645_TDM_CTRL_3			0x79
+#define RT5650_TDM_CTRL_4			0x7a
+
+/* Function - Analog */
+#define RT5645_GLB_CLK				0x80
+#define RT5645_PLL_CTRL1			0x81
+#define RT5645_PLL_CTRL2			0x82
+#define RT5645_ASRC_1				0x83
+#define RT5645_ASRC_2				0x84
+#define RT5645_ASRC_3				0x85
+#define RT5645_ASRC_4				0x8a
+#define RT5645_DEPOP_M1				0x8e
+#define RT5645_DEPOP_M2				0x8f
+#define RT5645_DEPOP_M3				0x90
+#define RT5645_CHARGE_PUMP			0x91
+#define RT5645_MICBIAS				0x93
+#define RT5645_A_JD_CTRL1			0x94
+#define RT5645_VAD_CTRL4			0x9d
+#define RT5645_CLSD_OUT_CTRL			0xa0
+/* Function - Digital */
+#define RT5645_ADC_EQ_CTRL1			0xae
+#define RT5645_ADC_EQ_CTRL2			0xaf
+#define RT5645_EQ_CTRL1				0xb0
+#define RT5645_EQ_CTRL2				0xb1
+#define RT5645_ALC_CTRL_1			0xb3
+#define RT5645_ALC_CTRL_2			0xb4
+#define RT5645_ALC_CTRL_3			0xb5
+#define RT5645_ALC_CTRL_4			0xb6
+#define RT5645_ALC_CTRL_5			0xb7
+#define RT5645_JD_CTRL				0xbb
+#define RT5645_IRQ_CTRL1			0xbc
+#define RT5645_IRQ_CTRL2			0xbd
+#define RT5645_IRQ_CTRL3			0xbe
+#define RT5645_INT_IRQ_ST			0xbf
+#define RT5645_GPIO_CTRL1			0xc0
+#define RT5645_GPIO_CTRL2			0xc1
+#define RT5645_GPIO_CTRL3			0xc2
+#define RT5645_BASS_BACK			0xcf
+#define RT5645_MP3_PLUS1			0xd0
+#define RT5645_MP3_PLUS2			0xd1
+#define RT5645_ADJ_HPF1				0xd3
+#define RT5645_ADJ_HPF2				0xd4
+#define RT5645_HP_CALIB_AMP_DET			0xd6
+#define RT5645_SV_ZCD1				0xd9
+#define RT5645_SV_ZCD2				0xda
+#define RT5645_IL_CMD				0xdb
+#define RT5645_IL_CMD2				0xdc
+#define RT5645_IL_CMD3				0xdd
+#define RT5650_4BTN_IL_CMD1			0xdf
+#define RT5650_4BTN_IL_CMD2			0xe0
+#define RT5645_DRC1_HL_CTRL1			0xe7
+#define RT5645_DRC2_HL_CTRL1			0xe9
+#define RT5645_MUTI_DRC_CTRL1			0xea
+#define RT5645_ADC_MONO_HP_CTRL1		0xec
+#define RT5645_ADC_MONO_HP_CTRL2		0xed
+#define RT5645_DRC2_CTRL1			0xf0
+#define RT5645_DRC2_CTRL2			0xf1
+#define RT5645_DRC2_CTRL3			0xf2
+#define RT5645_DRC2_CTRL4			0xf3
+#define RT5645_DRC2_CTRL5			0xf4
+#define RT5645_JD_CTRL3				0xf8
+#define RT5645_JD_CTRL4				0xf9
+/* General Control */
+#define RT5645_GEN_CTRL1			0xfa
+#define RT5645_GEN_CTRL2			0xfb
+#define RT5645_GEN_CTRL3			0xfc
+
+
+/* Index of Codec Private Register definition */
+#define RT5645_DIG_VOL				0x00
+#define RT5645_PR_ALC_CTRL_1			0x01
+#define RT5645_PR_ALC_CTRL_2			0x02
+#define RT5645_PR_ALC_CTRL_3			0x03
+#define RT5645_PR_ALC_CTRL_4			0x04
+#define RT5645_PR_ALC_CTRL_5			0x05
+#define RT5645_PR_ALC_CTRL_6			0x06
+#define RT5645_BIAS_CUR1			0x12
+#define RT5645_BIAS_CUR3			0x14
+#define RT5645_CLSD_INT_REG1			0x1c
+#define RT5645_MAMP_INT_REG2			0x37
+#define RT5645_CHOP_DAC_ADC			0x3d
+#define RT5645_MIXER_INT_REG			0x3f
+#define RT5645_3D_SPK				0x63
+#define RT5645_WND_1				0x6c
+#define RT5645_WND_2				0x6d
+#define RT5645_WND_3				0x6e
+#define RT5645_WND_4				0x6f
+#define RT5645_WND_5				0x70
+#define RT5645_WND_8				0x73
+#define RT5645_DIP_SPK_INF			0x75
+#define RT5645_HP_DCC_INT1			0x77
+#define RT5645_EQ_BW_LOP			0xa0
+#define RT5645_EQ_GN_LOP			0xa1
+#define RT5645_EQ_FC_BP1			0xa2
+#define RT5645_EQ_BW_BP1			0xa3
+#define RT5645_EQ_GN_BP1			0xa4
+#define RT5645_EQ_FC_BP2			0xa5
+#define RT5645_EQ_BW_BP2			0xa6
+#define RT5645_EQ_GN_BP2			0xa7
+#define RT5645_EQ_FC_BP3			0xa8
+#define RT5645_EQ_BW_BP3			0xa9
+#define RT5645_EQ_GN_BP3			0xaa
+#define RT5645_EQ_FC_BP4			0xab
+#define RT5645_EQ_BW_BP4			0xac
+#define RT5645_EQ_GN_BP4			0xad
+#define RT5645_EQ_FC_HIP1			0xae
+#define RT5645_EQ_GN_HIP1			0xaf
+#define RT5645_EQ_FC_HIP2			0xb0
+#define RT5645_EQ_BW_HIP2			0xb1
+#define RT5645_EQ_GN_HIP2			0xb2
+#define RT5645_EQ_PRE_VOL			0xb3
+#define RT5645_EQ_PST_VOL			0xb4
+
+
+/* global definition */
+#define RT5645_L_MUTE				(0x1 << 15)
+#define RT5645_L_MUTE_SFT			15
+#define RT5645_VOL_L_MUTE			(0x1 << 14)
+#define RT5645_VOL_L_SFT			14
+#define RT5645_R_MUTE				(0x1 << 7)
+#define RT5645_R_MUTE_SFT			7
+#define RT5645_VOL_R_MUTE			(0x1 << 6)
+#define RT5645_VOL_R_SFT			6
+#define RT5645_L_VOL_MASK			(0x3f << 8)
+#define RT5645_L_VOL_SFT			8
+#define RT5645_R_VOL_MASK			(0x3f)
+#define RT5645_R_VOL_SFT			0
+
+/* IN1 Control 1 (0x0a) */
+#define RT5645_CBJ_BST1_MASK			(0xf << 12)
+#define RT5645_CBJ_BST1_SFT			(12)
+#define RT5645_CBJ_JD_HP_EN			(0x1 << 9)
+#define RT5645_CBJ_JD_MIC_EN			(0x1 << 8)
+#define RT5645_CBJ_JD_MIC_SW_EN			(0x1 << 7)
+#define RT5645_CBJ_MIC_SEL_R			(0x1 << 6)
+#define RT5645_CBJ_MIC_SEL_L			(0x1 << 5)
+#define RT5645_CBJ_MIC_SW			(0x1 << 4)
+#define RT5645_CBJ_BST1_EN			(0x1 << 2)
+
+/* IN1 Control 2 (0x0b) */
+#define RT5645_CBJ_MN_JD			(0x1 << 12)
+#define RT5645_CAPLESS_EN			(0x1 << 11)
+#define RT5645_CBJ_DET_MODE			(0x1 << 7)
+
+/* IN1 Control 3 (0x0c) */
+#define RT5645_CBJ_TIE_G_L			(0x1 << 15)
+#define RT5645_CBJ_TIE_G_R			(0x1 << 14)
+
+/* IN2 Control (0x0d) */
+#define RT5645_BST_MASK1			(0xf<<12)
+#define RT5645_BST_SFT1				12
+#define RT5645_BST_MASK2			(0xf<<8)
+#define RT5645_BST_SFT2				8
+#define RT5645_IN_DF2				(0x1 << 6)
+#define RT5645_IN_SFT2				6
+
+/* INL and INR Volume Control (0x0f) */
+#define RT5645_INL_SEL_MASK			(0x1 << 15)
+#define RT5645_INL_SEL_SFT			15
+#define RT5645_INL_SEL_IN4P			(0x0 << 15)
+#define RT5645_INL_SEL_MONOP			(0x1 << 15)
+#define RT5645_INL_VOL_MASK			(0x1f << 8)
+#define RT5645_INL_VOL_SFT			8
+#define RT5645_INR_SEL_MASK			(0x1 << 7)
+#define RT5645_INR_SEL_SFT			7
+#define RT5645_INR_SEL_IN4N			(0x0 << 7)
+#define RT5645_INR_SEL_MONON			(0x1 << 7)
+#define RT5645_INR_VOL_MASK			(0x1f)
+#define RT5645_INR_VOL_SFT			0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5645_DAC_L1_VOL_MASK			(0xff << 8)
+#define RT5645_DAC_L1_VOL_SFT			8
+#define RT5645_DAC_R1_VOL_MASK			(0xff)
+#define RT5645_DAC_R1_VOL_SFT			0
+
+/* DAC2 Digital Volume (0x1a) */
+#define RT5645_DAC_L2_VOL_MASK			(0xff << 8)
+#define RT5645_DAC_L2_VOL_SFT			8
+#define RT5645_DAC_R2_VOL_MASK			(0xff)
+#define RT5645_DAC_R2_VOL_SFT			0
+
+/* DAC2 Control (0x1b) */
+#define RT5645_M_DAC_L2_VOL			(0x1 << 13)
+#define RT5645_M_DAC_L2_VOL_SFT			13
+#define RT5645_M_DAC_R2_VOL			(0x1 << 12)
+#define RT5645_M_DAC_R2_VOL_SFT			12
+#define RT5645_DAC2_L_SEL_MASK			(0x7 << 4)
+#define RT5645_DAC2_L_SEL_SFT			4
+#define RT5645_DAC2_R_SEL_MASK			(0x7 << 0)
+#define RT5645_DAC2_R_SEL_SFT			0
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5645_ADC_L_VOL_MASK			(0x7f << 8)
+#define RT5645_ADC_L_VOL_SFT			8
+#define RT5645_ADC_R_VOL_MASK			(0x7f)
+#define RT5645_ADC_R_VOL_SFT			0
+
+/* Mono ADC Digital Volume Control (0x1d) */
+#define RT5645_MONO_ADC_L_VOL_MASK		(0x7f << 8)
+#define RT5645_MONO_ADC_L_VOL_SFT		8
+#define RT5645_MONO_ADC_R_VOL_MASK		(0x7f)
+#define RT5645_MONO_ADC_R_VOL_SFT		0
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5645_STO1_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5645_STO1_ADC_L_BST_SFT		14
+#define RT5645_STO1_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5645_STO1_ADC_R_BST_SFT		12
+#define RT5645_STO1_ADC_COMP_MASK		(0x3 << 10)
+#define RT5645_STO1_ADC_COMP_SFT		10
+
+/* ADC Boost Volume Control (0x20) */
+#define RT5645_MONO_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5645_MONO_ADC_L_BST_SFT		14
+#define RT5645_MONO_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5645_MONO_ADC_R_BST_SFT		12
+#define RT5645_MONO_ADC_COMP_MASK		(0x3 << 10)
+#define RT5645_MONO_ADC_COMP_SFT		10
+
+/* Stereo2 ADC Mixer Control (0x26) */
+#define RT5645_STO2_ADC_SRC_MASK		(0x1 << 15)
+#define RT5645_STO2_ADC_SRC_SFT			15
+
+/* Stereo ADC Mixer Control (0x27) */
+#define RT5645_M_ADC_L1				(0x1 << 14)
+#define RT5645_M_ADC_L1_SFT			14
+#define RT5645_M_ADC_L2				(0x1 << 13)
+#define RT5645_M_ADC_L2_SFT			13
+#define RT5645_ADC_1_SRC_MASK			(0x1 << 12)
+#define RT5645_ADC_1_SRC_SFT			12
+#define RT5645_ADC_1_SRC_ADC			(0x1 << 12)
+#define RT5645_ADC_1_SRC_DACMIX			(0x0 << 12)
+#define RT5645_ADC_2_SRC_MASK			(0x1 << 11)
+#define RT5645_ADC_2_SRC_SFT			11
+#define RT5645_DMIC_SRC_MASK			(0x1 << 8)
+#define RT5645_DMIC_SRC_SFT			8
+#define RT5645_M_ADC_R1				(0x1 << 6)
+#define RT5645_M_ADC_R1_SFT			6
+#define RT5645_M_ADC_R2				(0x1 << 5)
+#define RT5645_M_ADC_R2_SFT			5
+#define RT5645_DMIC3_SRC_MASK			(0x1 << 1)
+#define RT5645_DMIC3_SRC_SFT			0
+
+/* Mono ADC Mixer Control (0x28) */
+#define RT5645_M_MONO_ADC_L1			(0x1 << 14)
+#define RT5645_M_MONO_ADC_L1_SFT		14
+#define RT5645_M_MONO_ADC_L2			(0x1 << 13)
+#define RT5645_M_MONO_ADC_L2_SFT		13
+#define RT5645_MONO_ADC_L1_SRC_MASK		(0x1 << 12)
+#define RT5645_MONO_ADC_L1_SRC_SFT		12
+#define RT5645_MONO_ADC_L1_SRC_DACMIXL		(0x0 << 12)
+#define RT5645_MONO_ADC_L1_SRC_ADCL		(0x1 << 12)
+#define RT5645_MONO_ADC_L2_SRC_MASK		(0x1 << 11)
+#define RT5645_MONO_ADC_L2_SRC_SFT		11
+#define RT5645_MONO_DMIC_L_SRC_MASK		(0x1 << 8)
+#define RT5645_MONO_DMIC_L_SRC_SFT		8
+#define RT5645_M_MONO_ADC_R1			(0x1 << 6)
+#define RT5645_M_MONO_ADC_R1_SFT		6
+#define RT5645_M_MONO_ADC_R2			(0x1 << 5)
+#define RT5645_M_MONO_ADC_R2_SFT		5
+#define RT5645_MONO_ADC_R1_SRC_MASK		(0x1 << 4)
+#define RT5645_MONO_ADC_R1_SRC_SFT		4
+#define RT5645_MONO_ADC_R1_SRC_ADCR		(0x1 << 4)
+#define RT5645_MONO_ADC_R1_SRC_DACMIXR		(0x0 << 4)
+#define RT5645_MONO_ADC_R2_SRC_MASK		(0x1 << 3)
+#define RT5645_MONO_ADC_R2_SRC_SFT		3
+#define RT5645_MONO_DMIC_R_SRC_MASK		(0x3)
+#define RT5645_MONO_DMIC_R_SRC_SFT		0
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5645_M_ADCMIX_L			(0x1 << 15)
+#define RT5645_M_ADCMIX_L_SFT			15
+#define RT5645_M_DAC1_L				(0x1 << 14)
+#define RT5645_M_DAC1_L_SFT			14
+#define RT5645_DAC1_R_SEL_MASK			(0x3 << 10)
+#define RT5645_DAC1_R_SEL_SFT			10
+#define RT5645_DAC1_R_SEL_IF1			(0x0 << 10)
+#define RT5645_DAC1_R_SEL_IF2			(0x1 << 10)
+#define RT5645_DAC1_R_SEL_IF3			(0x2 << 10)
+#define RT5645_DAC1_R_SEL_IF4			(0x3 << 10)
+#define RT5645_DAC1_L_SEL_MASK			(0x3 << 8)
+#define RT5645_DAC1_L_SEL_SFT			8
+#define RT5645_DAC1_L_SEL_IF1			(0x0 << 8)
+#define RT5645_DAC1_L_SEL_IF2			(0x1 << 8)
+#define RT5645_DAC1_L_SEL_IF3			(0x2 << 8)
+#define RT5645_DAC1_L_SEL_IF4			(0x3 << 8)
+#define RT5645_M_ADCMIX_R			(0x1 << 7)
+#define RT5645_M_ADCMIX_R_SFT			7
+#define RT5645_M_DAC1_R				(0x1 << 6)
+#define RT5645_M_DAC1_R_SFT			6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5645_M_DAC_L1				(0x1 << 14)
+#define RT5645_M_DAC_L1_SFT			14
+#define RT5645_DAC_L1_STO_L_VOL_MASK		(0x1 << 13)
+#define RT5645_DAC_L1_STO_L_VOL_SFT		13
+#define RT5645_M_DAC_L2				(0x1 << 12)
+#define RT5645_M_DAC_L2_SFT			12
+#define RT5645_DAC_L2_STO_L_VOL_MASK		(0x1 << 11)
+#define RT5645_DAC_L2_STO_L_VOL_SFT		11
+#define RT5645_M_ANC_DAC_L			(0x1 << 10)
+#define RT5645_M_ANC_DAC_L_SFT			10
+#define RT5645_M_DAC_R1_STO_L			(0x1 << 9)
+#define RT5645_M_DAC_R1_STO_L_SFT			9
+#define RT5645_DAC_R1_STO_L_VOL_MASK		(0x1 << 8)
+#define RT5645_DAC_R1_STO_L_VOL_SFT		8
+#define RT5645_M_DAC_R1				(0x1 << 6)
+#define RT5645_M_DAC_R1_SFT			6
+#define RT5645_DAC_R1_STO_R_VOL_MASK		(0x1 << 5)
+#define RT5645_DAC_R1_STO_R_VOL_SFT		5
+#define RT5645_M_DAC_R2				(0x1 << 4)
+#define RT5645_M_DAC_R2_SFT			4
+#define RT5645_DAC_R2_STO_R_VOL_MASK		(0x1 << 3)
+#define RT5645_DAC_R2_STO_R_VOL_SFT		3
+#define RT5645_M_ANC_DAC_R			(0x1 << 2)
+#define RT5645_M_ANC_DAC_R_SFT			2
+#define RT5645_M_DAC_L1_STO_R			(0x1 << 1)
+#define RT5645_M_DAC_L1_STO_R_SFT			1
+#define RT5645_DAC_L1_STO_R_VOL_MASK		(0x1)
+#define RT5645_DAC_L1_STO_R_VOL_SFT		0
+
+/* Mono DAC Mixer Control (0x2b) */
+#define RT5645_M_DAC_L1_MONO_L			(0x1 << 14)
+#define RT5645_M_DAC_L1_MONO_L_SFT		14
+#define RT5645_DAC_L1_MONO_L_VOL_MASK		(0x1 << 13)
+#define RT5645_DAC_L1_MONO_L_VOL_SFT		13
+#define RT5645_M_DAC_L2_MONO_L			(0x1 << 12)
+#define RT5645_M_DAC_L2_MONO_L_SFT		12
+#define RT5645_DAC_L2_MONO_L_VOL_MASK		(0x1 << 11)
+#define RT5645_DAC_L2_MONO_L_VOL_SFT		11
+#define RT5645_M_DAC_R2_MONO_L			(0x1 << 10)
+#define RT5645_M_DAC_R2_MONO_L_SFT		10
+#define RT5645_DAC_R2_MONO_L_VOL_MASK		(0x1 << 9)
+#define RT5645_DAC_R2_MONO_L_VOL_SFT		9
+#define RT5645_M_DAC_R1_MONO_R			(0x1 << 6)
+#define RT5645_M_DAC_R1_MONO_R_SFT		6
+#define RT5645_DAC_R1_MONO_R_VOL_MASK		(0x1 << 5)
+#define RT5645_DAC_R1_MONO_R_VOL_SFT		5
+#define RT5645_M_DAC_R2_MONO_R			(0x1 << 4)
+#define RT5645_M_DAC_R2_MONO_R_SFT		4
+#define RT5645_DAC_R2_MONO_R_VOL_MASK		(0x1 << 3)
+#define RT5645_DAC_R2_MONO_R_VOL_SFT		3
+#define RT5645_M_DAC_L2_MONO_R			(0x1 << 2)
+#define RT5645_M_DAC_L2_MONO_R_SFT		2
+#define RT5645_DAC_L2_MONO_R_VOL_MASK		(0x1 << 1)
+#define RT5645_DAC_L2_MONO_R_VOL_SFT		1
+
+/* Digital Mixer Control (0x2c) */
+#define RT5645_M_STO_L_DAC_L			(0x1 << 15)
+#define RT5645_M_STO_L_DAC_L_SFT		15
+#define RT5645_STO_L_DAC_L_VOL_MASK		(0x1 << 14)
+#define RT5645_STO_L_DAC_L_VOL_SFT		14
+#define RT5645_M_DAC_L2_DAC_L			(0x1 << 13)
+#define RT5645_M_DAC_L2_DAC_L_SFT		13
+#define RT5645_DAC_L2_DAC_L_VOL_MASK		(0x1 << 12)
+#define RT5645_DAC_L2_DAC_L_VOL_SFT		12
+#define RT5645_M_STO_R_DAC_R			(0x1 << 11)
+#define RT5645_M_STO_R_DAC_R_SFT		11
+#define RT5645_STO_R_DAC_R_VOL_MASK		(0x1 << 10)
+#define RT5645_STO_R_DAC_R_VOL_SFT		10
+#define RT5645_M_DAC_R2_DAC_R			(0x1 << 9)
+#define RT5645_M_DAC_R2_DAC_R_SFT		9
+#define RT5645_DAC_R2_DAC_R_VOL_MASK		(0x1 << 8)
+#define RT5645_DAC_R2_DAC_R_VOL_SFT		8
+#define RT5645_M_DAC_R2_DAC_L			(0x1 << 7)
+#define RT5645_M_DAC_R2_DAC_L_SFT		7
+#define RT5645_DAC_R2_DAC_L_VOL_MASK		(0x1 << 6)
+#define RT5645_DAC_R2_DAC_L_VOL_SFT		6
+#define RT5645_M_DAC_L2_DAC_R			(0x1 << 5)
+#define RT5645_M_DAC_L2_DAC_R_SFT		5
+#define RT5645_DAC_L2_DAC_R_VOL_MASK		(0x1 << 4)
+#define RT5645_DAC_L2_DAC_R_VOL_SFT		4
+
+/* Analog DAC1/2 Input Source Control (0x2d) */
+#define RT5650_A_DAC1_L_IN_SFT			3
+#define RT5650_A_DAC1_R_IN_SFT			2
+#define RT5650_A_DAC2_L_IN_SFT			1
+#define RT5650_A_DAC2_R_IN_SFT			0
+
+/* Digital Interface Data Control (0x2f) */
+#define RT5645_IF1_ADC2_IN_SEL			(0x1 << 15)
+#define RT5645_IF1_ADC2_IN_SFT			15
+#define RT5645_IF2_ADC_IN_MASK			(0x7 << 12)
+#define RT5645_IF2_ADC_IN_SFT			12
+#define RT5645_IF2_DAC_SEL_MASK			(0x3 << 10)
+#define RT5645_IF2_DAC_SEL_SFT			10
+#define RT5645_IF2_ADC_SEL_MASK			(0x3 << 8)
+#define RT5645_IF2_ADC_SEL_SFT			8
+#define RT5645_IF3_DAC_SEL_MASK			(0x3 << 6)
+#define RT5645_IF3_DAC_SEL_SFT			6
+#define RT5645_IF3_ADC_SEL_MASK			(0x3 << 4)
+#define RT5645_IF3_ADC_SEL_SFT			4
+#define RT5645_IF3_ADC_IN_MASK			(0x7)
+#define RT5645_IF3_ADC_IN_SFT			0
+
+/* PDM Output Control (0x31) */
+#define RT5645_PDM1_L_MASK			(0x1 << 15)
+#define RT5645_PDM1_L_SFT			15
+#define RT5645_M_PDM1_L				(0x1 << 14)
+#define RT5645_M_PDM1_L_SFT			14
+#define RT5645_PDM1_R_MASK			(0x1 << 13)
+#define RT5645_PDM1_R_SFT			13
+#define RT5645_M_PDM1_R				(0x1 << 12)
+#define RT5645_M_PDM1_R_SFT			12
+#define RT5645_PDM2_L_MASK			(0x1 << 11)
+#define RT5645_PDM2_L_SFT			11
+#define RT5645_M_PDM2_L				(0x1 << 10)
+#define RT5645_M_PDM2_L_SFT			10
+#define RT5645_PDM2_R_MASK			(0x1 << 9)
+#define RT5645_PDM2_R_SFT			9
+#define RT5645_M_PDM2_R				(0x1 << 8)
+#define RT5645_M_PDM2_R_SFT			8
+#define RT5645_PDM2_BUSY			(0x1 << 7)
+#define RT5645_PDM1_BUSY			(0x1 << 6)
+#define RT5645_PDM_PATTERN			(0x1 << 5)
+#define RT5645_PDM_GAIN				(0x1 << 4)
+#define RT5645_PDM_DIV_MASK			(0x3)
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5645_G_HP_L_RM_L_MASK			(0x7 << 13)
+#define RT5645_G_HP_L_RM_L_SFT			13
+#define RT5645_G_IN_L_RM_L_MASK			(0x7 << 10)
+#define RT5645_G_IN_L_RM_L_SFT			10
+#define RT5645_G_BST4_RM_L_MASK			(0x7 << 7)
+#define RT5645_G_BST4_RM_L_SFT			7
+#define RT5645_G_BST3_RM_L_MASK			(0x7 << 4)
+#define RT5645_G_BST3_RM_L_SFT			4
+#define RT5645_G_BST2_RM_L_MASK			(0x7 << 1)
+#define RT5645_G_BST2_RM_L_SFT			1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5645_G_BST1_RM_L_MASK			(0x7 << 13)
+#define RT5645_G_BST1_RM_L_SFT			13
+#define RT5645_G_OM_L_RM_L_MASK			(0x7 << 10)
+#define RT5645_G_OM_L_RM_L_SFT			10
+#define RT5645_M_MM_L_RM_L			(0x1 << 6)
+#define RT5645_M_MM_L_RM_L_SFT			6
+#define RT5645_M_IN_L_RM_L			(0x1 << 5)
+#define RT5645_M_IN_L_RM_L_SFT			5
+#define RT5645_M_HP_L_RM_L			(0x1 << 4)
+#define RT5645_M_HP_L_RM_L_SFT			4
+#define RT5645_M_BST3_RM_L			(0x1 << 3)
+#define RT5645_M_BST3_RM_L_SFT			3
+#define RT5645_M_BST2_RM_L			(0x1 << 2)
+#define RT5645_M_BST2_RM_L_SFT			2
+#define RT5645_M_BST1_RM_L			(0x1 << 1)
+#define RT5645_M_BST1_RM_L_SFT			1
+#define RT5645_M_OM_L_RM_L			(0x1)
+#define RT5645_M_OM_L_RM_L_SFT			0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5645_G_HP_R_RM_R_MASK			(0x7 << 13)
+#define RT5645_G_HP_R_RM_R_SFT			13
+#define RT5645_G_IN_R_RM_R_MASK			(0x7 << 10)
+#define RT5645_G_IN_R_RM_R_SFT			10
+#define RT5645_G_BST4_RM_R_MASK			(0x7 << 7)
+#define RT5645_G_BST4_RM_R_SFT			7
+#define RT5645_G_BST3_RM_R_MASK			(0x7 << 4)
+#define RT5645_G_BST3_RM_R_SFT			4
+#define RT5645_G_BST2_RM_R_MASK			(0x7 << 1)
+#define RT5645_G_BST2_RM_R_SFT			1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5645_G_BST1_RM_R_MASK			(0x7 << 13)
+#define RT5645_G_BST1_RM_R_SFT			13
+#define RT5645_G_OM_R_RM_R_MASK			(0x7 << 10)
+#define RT5645_G_OM_R_RM_R_SFT			10
+#define RT5645_M_MM_R_RM_R			(0x1 << 6)
+#define RT5645_M_MM_R_RM_R_SFT			6
+#define RT5645_M_IN_R_RM_R			(0x1 << 5)
+#define RT5645_M_IN_R_RM_R_SFT			5
+#define RT5645_M_HP_R_RM_R			(0x1 << 4)
+#define RT5645_M_HP_R_RM_R_SFT			4
+#define RT5645_M_BST3_RM_R			(0x1 << 3)
+#define RT5645_M_BST3_RM_R_SFT			3
+#define RT5645_M_BST2_RM_R			(0x1 << 2)
+#define RT5645_M_BST2_RM_R_SFT			2
+#define RT5645_M_BST1_RM_R			(0x1 << 1)
+#define RT5645_M_BST1_RM_R_SFT			1
+#define RT5645_M_OM_R_RM_R			(0x1)
+#define RT5645_M_OM_R_RM_R_SFT			0
+
+/* HPOMIX Control (0x40) (0x42) */
+#define RT5645_M_BST1_HV			(0x1 << 4)
+#define RT5645_M_BST1_HV_SFT			4
+#define RT5645_M_BST2_HV			(0x1 << 4)
+#define RT5645_M_BST2_HV_SFT			4
+#define RT5645_M_BST3_HV			(0x1 << 3)
+#define RT5645_M_BST3_HV_SFT			3
+#define RT5645_M_IN_HV				(0x1 << 2)
+#define RT5645_M_IN_HV_SFT			2
+#define RT5645_M_DAC2_HV			(0x1 << 1)
+#define RT5645_M_DAC2_HV_SFT			1
+#define RT5645_M_DAC1_HV			(0x1 << 0)
+#define RT5645_M_DAC1_HV_SFT			0
+
+/* HPMIX Control (0x45) */
+#define RT5645_M_DAC1_HM			(0x1 << 14)
+#define RT5645_M_DAC1_HM_SFT			14
+#define RT5645_M_HPVOL_HM			(0x1 << 13)
+#define RT5645_M_HPVOL_HM_SFT			13
+#define RT5645_IRQ_PSV_MODE			(0x1 << 12)
+
+/* SPK Left Mixer Control (0x46) */
+#define RT5645_G_RM_L_SM_L_MASK			(0x3 << 14)
+#define RT5645_G_RM_L_SM_L_SFT			14
+#define RT5645_G_IN_L_SM_L_MASK			(0x3 << 12)
+#define RT5645_G_IN_L_SM_L_SFT			12
+#define RT5645_G_DAC_L1_SM_L_MASK		(0x3 << 10)
+#define RT5645_G_DAC_L1_SM_L_SFT		10
+#define RT5645_G_DAC_L2_SM_L_MASK		(0x3 << 8)
+#define RT5645_G_DAC_L2_SM_L_SFT		8
+#define RT5645_G_OM_L_SM_L_MASK			(0x3 << 6)
+#define RT5645_G_OM_L_SM_L_SFT			6
+#define RT5645_M_BST1_L_SM_L			(0x1 << 5)
+#define RT5645_M_BST1_L_SM_L_SFT		5
+#define RT5645_M_BST3_L_SM_L			(0x1 << 4)
+#define RT5645_M_BST3_L_SM_L_SFT		4
+#define RT5645_M_IN_L_SM_L			(0x1 << 3)
+#define RT5645_M_IN_L_SM_L_SFT			3
+#define RT5645_M_DAC_L2_SM_L			(0x1 << 2)
+#define RT5645_M_DAC_L2_SM_L_SFT		2
+#define RT5645_M_DAC_L1_SM_L			(0x1 << 1)
+#define RT5645_M_DAC_L1_SM_L_SFT		1
+
+/* SPK Right Mixer Control (0x47) */
+#define RT5645_G_RM_R_SM_R_MASK			(0x3 << 14)
+#define RT5645_G_RM_R_SM_R_SFT			14
+#define RT5645_G_IN_R_SM_R_MASK			(0x3 << 12)
+#define RT5645_G_IN_R_SM_R_SFT			12
+#define RT5645_G_DAC_R1_SM_R_MASK		(0x3 << 10)
+#define RT5645_G_DAC_R1_SM_R_SFT		10
+#define RT5645_G_DAC_R2_SM_R_MASK		(0x3 << 8)
+#define RT5645_G_DAC_R2_SM_R_SFT		8
+#define RT5645_G_OM_R_SM_R_MASK			(0x3 << 6)
+#define RT5645_G_OM_R_SM_R_SFT			6
+#define RT5645_M_BST2_R_SM_R			(0x1 << 5)
+#define RT5645_M_BST2_R_SM_R_SFT		5
+#define RT5645_M_BST3_R_SM_R			(0x1 << 4)
+#define RT5645_M_BST3_R_SM_R_SFT		4
+#define RT5645_M_IN_R_SM_R			(0x1 << 3)
+#define RT5645_M_IN_R_SM_R_SFT			3
+#define RT5645_M_DAC_R2_SM_R			(0x1 << 2)
+#define RT5645_M_DAC_R2_SM_R_SFT		2
+#define RT5645_M_DAC_R1_SM_R			(0x1 << 1)
+#define RT5645_M_DAC_R1_SM_R_SFT		1
+
+/* SPOLMIX Control (0x48) */
+#define RT5645_M_DAC_L1_SPM_L			(0x1 << 15)
+#define RT5645_M_DAC_L1_SPM_L_SFT		15
+#define RT5645_M_DAC_R1_SPM_L			(0x1 << 14)
+#define RT5645_M_DAC_R1_SPM_L_SFT		14
+#define RT5645_M_SV_L_SPM_L			(0x1 << 13)
+#define RT5645_M_SV_L_SPM_L_SFT			13
+#define RT5645_M_SV_R_SPM_L			(0x1 << 12)
+#define RT5645_M_SV_R_SPM_L_SFT			12
+#define RT5645_M_BST3_SPM_L			(0x1 << 11)
+#define RT5645_M_BST3_SPM_L_SFT			11
+#define RT5645_M_DAC_R1_SPM_R			(0x1 << 2)
+#define RT5645_M_DAC_R1_SPM_R_SFT		2
+#define RT5645_M_BST3_SPM_R			(0x1 << 1)
+#define RT5645_M_BST3_SPM_R_SFT			1
+#define RT5645_M_SV_R_SPM_R			(0x1 << 0)
+#define RT5645_M_SV_R_SPM_R_SFT			0
+
+/* SPOMIX Ratio Control (0x4a) */
+#define RT5645_SPK_G_CLSD_MASK			(0x7 << 0)
+#define RT5645_SPK_G_CLSD_SFT			0
+
+/* Mono Output Mixer Control (0x4c) */
+#define RT5645_G_MONOMIX_MASK			(0x1 << 10)
+#define RT5645_G_MONOMIX_SFT			10
+#define RT5645_M_OV_L_MM			(0x1 << 9)
+#define RT5645_M_OV_L_MM_SFT			9
+#define RT5645_M_DAC_L2_MA			(0x1 << 8)
+#define RT5645_M_DAC_L2_MA_SFT			8
+#define RT5645_M_BST2_MM			(0x1 << 4)
+#define RT5645_M_BST2_MM_SFT			4
+#define RT5645_M_DAC_R1_MM			(0x1 << 3)
+#define RT5645_M_DAC_R1_MM_SFT			3
+#define RT5645_M_DAC_R2_MM			(0x1 << 2)
+#define RT5645_M_DAC_R2_MM_SFT			2
+#define RT5645_M_DAC_L2_MM			(0x1 << 1)
+#define RT5645_M_DAC_L2_MM_SFT			1
+#define RT5645_M_BST3_MM			(0x1 << 0)
+#define RT5645_M_BST3_MM_SFT			0
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5645_G_BST3_OM_L_MASK			(0x7 << 13)
+#define RT5645_G_BST3_OM_L_SFT			13
+#define RT5645_G_BST2_OM_L_MASK			(0x7 << 10)
+#define RT5645_G_BST2_OM_L_SFT			10
+#define RT5645_G_BST1_OM_L_MASK			(0x7 << 7)
+#define RT5645_G_BST1_OM_L_SFT			7
+#define RT5645_G_IN_L_OM_L_MASK			(0x7 << 4)
+#define RT5645_G_IN_L_OM_L_SFT			4
+#define RT5645_G_RM_L_OM_L_MASK			(0x7 << 1)
+#define RT5645_G_RM_L_OM_L_SFT			1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5645_G_DAC_R2_OM_L_MASK		(0x7 << 13)
+#define RT5645_G_DAC_R2_OM_L_SFT		13
+#define RT5645_G_DAC_L2_OM_L_MASK		(0x7 << 10)
+#define RT5645_G_DAC_L2_OM_L_SFT		10
+#define RT5645_G_DAC_L1_OM_L_MASK		(0x7 << 7)
+#define RT5645_G_DAC_L1_OM_L_SFT		7
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5645_M_BST3_OM_L			(0x1 << 4)
+#define RT5645_M_BST3_OM_L_SFT			4
+#define RT5645_M_BST1_OM_L			(0x1 << 3)
+#define RT5645_M_BST1_OM_L_SFT			3
+#define RT5645_M_IN_L_OM_L			(0x1 << 2)
+#define RT5645_M_IN_L_OM_L_SFT			2
+#define RT5645_M_DAC_L2_OM_L			(0x1 << 1)
+#define RT5645_M_DAC_L2_OM_L_SFT		1
+#define RT5645_M_DAC_L1_OM_L			(0x1)
+#define RT5645_M_DAC_L1_OM_L_SFT		0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5645_G_BST4_OM_R_MASK			(0x7 << 13)
+#define RT5645_G_BST4_OM_R_SFT			13
+#define RT5645_G_BST2_OM_R_MASK			(0x7 << 10)
+#define RT5645_G_BST2_OM_R_SFT			10
+#define RT5645_G_BST1_OM_R_MASK			(0x7 << 7)
+#define RT5645_G_BST1_OM_R_SFT			7
+#define RT5645_G_IN_R_OM_R_MASK			(0x7 << 4)
+#define RT5645_G_IN_R_OM_R_SFT			4
+#define RT5645_G_RM_R_OM_R_MASK			(0x7 << 1)
+#define RT5645_G_RM_R_OM_R_SFT			1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5645_G_DAC_L2_OM_R_MASK		(0x7 << 13)
+#define RT5645_G_DAC_L2_OM_R_SFT		13
+#define RT5645_G_DAC_R2_OM_R_MASK		(0x7 << 10)
+#define RT5645_G_DAC_R2_OM_R_SFT		10
+#define RT5645_G_DAC_R1_OM_R_MASK		(0x7 << 7)
+#define RT5645_G_DAC_R1_OM_R_SFT		7
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5645_M_BST3_OM_R			(0x1 << 4)
+#define RT5645_M_BST3_OM_R_SFT			4
+#define RT5645_M_BST2_OM_R			(0x1 << 3)
+#define RT5645_M_BST2_OM_R_SFT			3
+#define RT5645_M_IN_R_OM_R			(0x1 << 2)
+#define RT5645_M_IN_R_OM_R_SFT			2
+#define RT5645_M_DAC_R2_OM_R			(0x1 << 1)
+#define RT5645_M_DAC_R2_OM_R_SFT		1
+#define RT5645_M_DAC_R1_OM_R			(0x1)
+#define RT5645_M_DAC_R1_OM_R_SFT		0
+
+/* LOUT Mixer Control (0x53) */
+#define RT5645_M_DAC_L1_LM			(0x1 << 15)
+#define RT5645_M_DAC_L1_LM_SFT			15
+#define RT5645_M_DAC_R1_LM			(0x1 << 14)
+#define RT5645_M_DAC_R1_LM_SFT			14
+#define RT5645_M_OV_L_LM			(0x1 << 13)
+#define RT5645_M_OV_L_LM_SFT			13
+#define RT5645_M_OV_R_LM			(0x1 << 12)
+#define RT5645_M_OV_R_LM_SFT			12
+#define RT5645_G_LOUTMIX_MASK			(0x1 << 11)
+#define RT5645_G_LOUTMIX_SFT			11
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5645_PWR_I2S1				(0x1 << 15)
+#define RT5645_PWR_I2S1_BIT			15
+#define RT5645_PWR_I2S2				(0x1 << 14)
+#define RT5645_PWR_I2S2_BIT			14
+#define RT5645_PWR_I2S3				(0x1 << 13)
+#define RT5645_PWR_I2S3_BIT			13
+#define RT5645_PWR_DAC_L1			(0x1 << 12)
+#define RT5645_PWR_DAC_L1_BIT			12
+#define RT5645_PWR_DAC_R1			(0x1 << 11)
+#define RT5645_PWR_DAC_R1_BIT			11
+#define RT5645_PWR_CLS_D_R			(0x1 << 9)
+#define RT5645_PWR_CLS_D_R_BIT			9
+#define RT5645_PWR_CLS_D_L			(0x1 << 8)
+#define RT5645_PWR_CLS_D_L_BIT			8
+#define RT5645_PWR_DAC_L2			(0x1 << 7)
+#define RT5645_PWR_DAC_L2_BIT			7
+#define RT5645_PWR_DAC_R2			(0x1 << 6)
+#define RT5645_PWR_DAC_R2_BIT			6
+#define RT5645_PWR_ADC_L			(0x1 << 2)
+#define RT5645_PWR_ADC_L_BIT			2
+#define RT5645_PWR_ADC_R			(0x1 << 1)
+#define RT5645_PWR_ADC_R_BIT			1
+#define RT5645_PWR_CLS_D			(0x1)
+#define RT5645_PWR_CLS_D_BIT			0
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5645_PWR_ADC_S1F			(0x1 << 15)
+#define RT5645_PWR_ADC_S1F_BIT			15
+#define RT5645_PWR_ADC_MF_L			(0x1 << 14)
+#define RT5645_PWR_ADC_MF_L_BIT			14
+#define RT5645_PWR_ADC_MF_R			(0x1 << 13)
+#define RT5645_PWR_ADC_MF_R_BIT			13
+#define RT5645_PWR_I2S_DSP			(0x1 << 12)
+#define RT5645_PWR_I2S_DSP_BIT			12
+#define RT5645_PWR_DAC_S1F			(0x1 << 11)
+#define RT5645_PWR_DAC_S1F_BIT			11
+#define RT5645_PWR_DAC_MF_L			(0x1 << 10)
+#define RT5645_PWR_DAC_MF_L_BIT			10
+#define RT5645_PWR_DAC_MF_R			(0x1 << 9)
+#define RT5645_PWR_DAC_MF_R_BIT			9
+#define RT5645_PWR_PDM1				(0x1 << 7)
+#define RT5645_PWR_PDM1_BIT			7
+#define RT5645_PWR_PDM2				(0x1 << 6)
+#define RT5645_PWR_PDM2_BIT			6
+#define RT5645_PWR_IPTV				(0x1 << 1)
+#define RT5645_PWR_IPTV_BIT			1
+#define RT5645_PWR_PAD				(0x1)
+#define RT5645_PWR_PAD_BIT			0
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5645_PWR_VREF1			(0x1 << 15)
+#define RT5645_PWR_VREF1_BIT			15
+#define RT5645_PWR_FV1				(0x1 << 14)
+#define RT5645_PWR_FV1_BIT			14
+#define RT5645_PWR_MB				(0x1 << 13)
+#define RT5645_PWR_MB_BIT			13
+#define RT5645_PWR_LM				(0x1 << 12)
+#define RT5645_PWR_LM_BIT			12
+#define RT5645_PWR_BG				(0x1 << 11)
+#define RT5645_PWR_BG_BIT			11
+#define RT5645_PWR_MA				(0x1 << 10)
+#define RT5645_PWR_MA_BIT			10
+#define RT5645_PWR_HP_L				(0x1 << 7)
+#define RT5645_PWR_HP_L_BIT			7
+#define RT5645_PWR_HP_R				(0x1 << 6)
+#define RT5645_PWR_HP_R_BIT			6
+#define RT5645_PWR_HA				(0x1 << 5)
+#define RT5645_PWR_HA_BIT			5
+#define RT5645_PWR_VREF2			(0x1 << 4)
+#define RT5645_PWR_VREF2_BIT			4
+#define RT5645_PWR_FV2				(0x1 << 3)
+#define RT5645_PWR_FV2_BIT			3
+#define RT5645_LDO_SEL_MASK			(0x3)
+#define RT5645_LDO_SEL_SFT			0
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5645_PWR_BST1				(0x1 << 15)
+#define RT5645_PWR_BST1_BIT			15
+#define RT5645_PWR_BST2				(0x1 << 14)
+#define RT5645_PWR_BST2_BIT			14
+#define RT5645_PWR_BST3				(0x1 << 13)
+#define RT5645_PWR_BST3_BIT			13
+#define RT5645_PWR_BST4				(0x1 << 12)
+#define RT5645_PWR_BST4_BIT			12
+#define RT5645_PWR_MB1				(0x1 << 11)
+#define RT5645_PWR_MB1_BIT			11
+#define RT5645_PWR_MB2				(0x1 << 10)
+#define RT5645_PWR_MB2_BIT			10
+#define RT5645_PWR_PLL				(0x1 << 9)
+#define RT5645_PWR_PLL_BIT			9
+#define RT5645_PWR_BST2_P			(0x1 << 5)
+#define RT5645_PWR_BST2_P_BIT			5
+#define RT5645_PWR_BST3_P			(0x1 << 4)
+#define RT5645_PWR_BST3_P_BIT			4
+#define RT5645_PWR_BST4_P			(0x1 << 3)
+#define RT5645_PWR_BST4_P_BIT			3
+#define RT5645_PWR_JD1				(0x1 << 2)
+#define RT5645_PWR_JD1_BIT			2
+#define RT5645_PWR_JD				(0x1 << 1)
+#define RT5645_PWR_JD_BIT			1
+
+/* Power Management for Mixer (0x65) */
+#define RT5645_PWR_OM_L				(0x1 << 15)
+#define RT5645_PWR_OM_L_BIT			15
+#define RT5645_PWR_OM_R				(0x1 << 14)
+#define RT5645_PWR_OM_R_BIT			14
+#define RT5645_PWR_SM_L				(0x1 << 13)
+#define RT5645_PWR_SM_L_BIT			13
+#define RT5645_PWR_SM_R				(0x1 << 12)
+#define RT5645_PWR_SM_R_BIT			12
+#define RT5645_PWR_RM_L				(0x1 << 11)
+#define RT5645_PWR_RM_L_BIT			11
+#define RT5645_PWR_RM_R				(0x1 << 10)
+#define RT5645_PWR_RM_R_BIT			10
+#define RT5645_PWR_MM				(0x1 << 8)
+#define RT5645_PWR_MM_BIT			8
+#define RT5645_PWR_HM_L				(0x1 << 7)
+#define RT5645_PWR_HM_L_BIT			7
+#define RT5645_PWR_HM_R				(0x1 << 6)
+#define RT5645_PWR_HM_R_BIT			6
+#define RT5645_PWR_LDO2				(0x1 << 1)
+#define RT5645_PWR_LDO2_BIT			1
+
+/* Power Management for Volume (0x66) */
+#define RT5645_PWR_SV_L				(0x1 << 15)
+#define RT5645_PWR_SV_L_BIT			15
+#define RT5645_PWR_SV_R				(0x1 << 14)
+#define RT5645_PWR_SV_R_BIT			14
+#define RT5645_PWR_HV_L				(0x1 << 11)
+#define RT5645_PWR_HV_L_BIT			11
+#define RT5645_PWR_HV_R				(0x1 << 10)
+#define RT5645_PWR_HV_R_BIT			10
+#define RT5645_PWR_IN_L				(0x1 << 9)
+#define RT5645_PWR_IN_L_BIT			9
+#define RT5645_PWR_IN_R				(0x1 << 8)
+#define RT5645_PWR_IN_R_BIT			8
+#define RT5645_PWR_MIC_DET			(0x1 << 5)
+#define RT5645_PWR_MIC_DET_BIT			5
+
+/* I2S1/2 Audio Serial Data Port Control (0x70 0x71) */
+#define RT5645_I2S_MS_MASK			(0x1 << 15)
+#define RT5645_I2S_MS_SFT			15
+#define RT5645_I2S_MS_M				(0x0 << 15)
+#define RT5645_I2S_MS_S				(0x1 << 15)
+#define RT5645_I2S_O_CP_MASK			(0x3 << 10)
+#define RT5645_I2S_O_CP_SFT			10
+#define RT5645_I2S_O_CP_OFF			(0x0 << 10)
+#define RT5645_I2S_O_CP_U_LAW			(0x1 << 10)
+#define RT5645_I2S_O_CP_A_LAW			(0x2 << 10)
+#define RT5645_I2S_I_CP_MASK			(0x3 << 8)
+#define RT5645_I2S_I_CP_SFT			8
+#define RT5645_I2S_I_CP_OFF			(0x0 << 8)
+#define RT5645_I2S_I_CP_U_LAW			(0x1 << 8)
+#define RT5645_I2S_I_CP_A_LAW			(0x2 << 8)
+#define RT5645_I2S_BP_MASK			(0x1 << 7)
+#define RT5645_I2S_BP_SFT			7
+#define RT5645_I2S_BP_NOR			(0x0 << 7)
+#define RT5645_I2S_BP_INV			(0x1 << 7)
+#define RT5645_I2S_DL_MASK			(0x3 << 2)
+#define RT5645_I2S_DL_SFT			2
+#define RT5645_I2S_DL_16			(0x0 << 2)
+#define RT5645_I2S_DL_20			(0x1 << 2)
+#define RT5645_I2S_DL_24			(0x2 << 2)
+#define RT5645_I2S_DL_8				(0x3 << 2)
+#define RT5645_I2S_DF_MASK			(0x3)
+#define RT5645_I2S_DF_SFT			0
+#define RT5645_I2S_DF_I2S			(0x0)
+#define RT5645_I2S_DF_LEFT			(0x1)
+#define RT5645_I2S_DF_PCM_A			(0x2)
+#define RT5645_I2S_DF_PCM_B			(0x3)
+
+/* I2S2 Audio Serial Data Port Control (0x71) */
+#define RT5645_I2S2_SDI_MASK			(0x1 << 6)
+#define RT5645_I2S2_SDI_SFT			6
+#define RT5645_I2S2_SDI_I2S1			(0x0 << 6)
+#define RT5645_I2S2_SDI_I2S2			(0x1 << 6)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5645_I2S_PD1_MASK			(0x7 << 12)
+#define RT5645_I2S_PD1_SFT			12
+#define RT5645_I2S_PD1_1			(0x0 << 12)
+#define RT5645_I2S_PD1_2			(0x1 << 12)
+#define RT5645_I2S_PD1_3			(0x2 << 12)
+#define RT5645_I2S_PD1_4			(0x3 << 12)
+#define RT5645_I2S_PD1_6			(0x4 << 12)
+#define RT5645_I2S_PD1_8			(0x5 << 12)
+#define RT5645_I2S_PD1_12			(0x6 << 12)
+#define RT5645_I2S_PD1_16			(0x7 << 12)
+#define RT5645_I2S_BCLK_MS2_MASK		(0x1 << 11)
+#define RT5645_I2S_BCLK_MS2_SFT			11
+#define RT5645_I2S_BCLK_MS2_32			(0x0 << 11)
+#define RT5645_I2S_BCLK_MS2_64			(0x1 << 11)
+#define RT5645_I2S_PD2_MASK			(0x7 << 8)
+#define RT5645_I2S_PD2_SFT			8
+#define RT5645_I2S_PD2_1			(0x0 << 8)
+#define RT5645_I2S_PD2_2			(0x1 << 8)
+#define RT5645_I2S_PD2_3			(0x2 << 8)
+#define RT5645_I2S_PD2_4			(0x3 << 8)
+#define RT5645_I2S_PD2_6			(0x4 << 8)
+#define RT5645_I2S_PD2_8			(0x5 << 8)
+#define RT5645_I2S_PD2_12			(0x6 << 8)
+#define RT5645_I2S_PD2_16			(0x7 << 8)
+#define RT5645_I2S_BCLK_MS3_MASK		(0x1 << 7)
+#define RT5645_I2S_BCLK_MS3_SFT			7
+#define RT5645_I2S_BCLK_MS3_32			(0x0 << 7)
+#define RT5645_I2S_BCLK_MS3_64			(0x1 << 7)
+#define RT5645_I2S_PD3_MASK			(0x7 << 4)
+#define RT5645_I2S_PD3_SFT			4
+#define RT5645_I2S_PD3_1			(0x0 << 4)
+#define RT5645_I2S_PD3_2			(0x1 << 4)
+#define RT5645_I2S_PD3_3			(0x2 << 4)
+#define RT5645_I2S_PD3_4			(0x3 << 4)
+#define RT5645_I2S_PD3_6			(0x4 << 4)
+#define RT5645_I2S_PD3_8			(0x5 << 4)
+#define RT5645_I2S_PD3_12			(0x6 << 4)
+#define RT5645_I2S_PD3_16			(0x7 << 4)
+#define RT5645_DAC_OSR_MASK			(0x3 << 2)
+#define RT5645_DAC_OSR_SFT			2
+#define RT5645_DAC_OSR_128			(0x0 << 2)
+#define RT5645_DAC_OSR_64			(0x1 << 2)
+#define RT5645_DAC_OSR_32			(0x2 << 2)
+#define RT5645_DAC_OSR_16			(0x3 << 2)
+#define RT5645_ADC_OSR_MASK			(0x3)
+#define RT5645_ADC_OSR_SFT			0
+#define RT5645_ADC_OSR_128			(0x0)
+#define RT5645_ADC_OSR_64			(0x1)
+#define RT5645_ADC_OSR_32			(0x2)
+#define RT5645_ADC_OSR_16			(0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5645_DAC_L_OSR_MASK			(0x3 << 14)
+#define RT5645_DAC_L_OSR_SFT			14
+#define RT5645_DAC_L_OSR_128			(0x0 << 14)
+#define RT5645_DAC_L_OSR_64			(0x1 << 14)
+#define RT5645_DAC_L_OSR_32			(0x2 << 14)
+#define RT5645_DAC_L_OSR_16			(0x3 << 14)
+#define RT5645_ADC_R_OSR_MASK			(0x3 << 12)
+#define RT5645_ADC_R_OSR_SFT			12
+#define RT5645_ADC_R_OSR_128			(0x0 << 12)
+#define RT5645_ADC_R_OSR_64			(0x1 << 12)
+#define RT5645_ADC_R_OSR_32			(0x2 << 12)
+#define RT5645_ADC_R_OSR_16			(0x3 << 12)
+#define RT5645_DAHPF_EN				(0x1 << 11)
+#define RT5645_DAHPF_EN_SFT			11
+#define RT5645_ADHPF_EN				(0x1 << 10)
+#define RT5645_ADHPF_EN_SFT			10
+
+/* Digital Microphone Control (0x75) */
+#define RT5645_DMIC_1_EN_MASK			(0x1 << 15)
+#define RT5645_DMIC_1_EN_SFT			15
+#define RT5645_DMIC_1_DIS			(0x0 << 15)
+#define RT5645_DMIC_1_EN			(0x1 << 15)
+#define RT5645_DMIC_2_EN_MASK			(0x1 << 14)
+#define RT5645_DMIC_2_EN_SFT			14
+#define RT5645_DMIC_2_DIS			(0x0 << 14)
+#define RT5645_DMIC_2_EN			(0x1 << 14)
+#define RT5645_DMIC_1L_LH_MASK			(0x1 << 13)
+#define RT5645_DMIC_1L_LH_SFT			13
+#define RT5645_DMIC_1L_LH_FALLING		(0x0 << 13)
+#define RT5645_DMIC_1L_LH_RISING		(0x1 << 13)
+#define RT5645_DMIC_1R_LH_MASK			(0x1 << 12)
+#define RT5645_DMIC_1R_LH_SFT			12
+#define RT5645_DMIC_1R_LH_FALLING		(0x0 << 12)
+#define RT5645_DMIC_1R_LH_RISING		(0x1 << 12)
+#define RT5645_DMIC_2_DP_MASK			(0x3 << 10)
+#define RT5645_DMIC_2_DP_SFT			10
+#define RT5645_DMIC_2_DP_GPIO6			(0x0 << 10)
+#define RT5645_DMIC_2_DP_GPIO10			(0x1 << 10)
+#define RT5645_DMIC_2_DP_GPIO12			(0x2 << 10)
+#define RT5645_DMIC_2_DP_IN2P			(0x3 << 10)
+#define RT5645_DMIC_2L_LH_MASK			(0x1 << 9)
+#define RT5645_DMIC_2L_LH_SFT			9
+#define RT5645_DMIC_2L_LH_FALLING		(0x0 << 9)
+#define RT5645_DMIC_2L_LH_RISING		(0x1 << 9)
+#define RT5645_DMIC_2R_LH_MASK			(0x1 << 8)
+#define RT5645_DMIC_2R_LH_SFT			8
+#define RT5645_DMIC_2R_LH_FALLING		(0x0 << 8)
+#define RT5645_DMIC_2R_LH_RISING		(0x1 << 8)
+#define RT5645_DMIC_CLK_MASK			(0x7 << 5)
+#define RT5645_DMIC_CLK_SFT			5
+#define RT5645_DMIC_3_EN_MASK			(0x1 << 4)
+#define RT5645_DMIC_3_EN_SFT			4
+#define RT5645_DMIC_3_DIS			(0x0 << 4)
+#define RT5645_DMIC_3_EN			(0x1 << 4)
+#define RT5645_DMIC_1_DP_MASK			(0x3 << 0)
+#define RT5645_DMIC_1_DP_SFT			0
+#define RT5645_DMIC_1_DP_GPIO5			(0x0 << 0)
+#define RT5645_DMIC_1_DP_IN2N			(0x1 << 0)
+#define RT5645_DMIC_1_DP_GPIO11			(0x2 << 0)
+
+/* TDM Control 1 (0x77) */
+#define RT5645_IF1_ADC_IN_MASK			(0x3 << 8)
+#define RT5645_IF1_ADC_IN_SFT			8
+
+/* Global Clock Control (0x80) */
+#define RT5645_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5645_SCLK_SRC_SFT			14
+#define RT5645_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5645_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5645_SCLK_SRC_RCCLK			(0x2 << 14)
+#define RT5645_PLL1_SRC_MASK			(0x7 << 11)
+#define RT5645_PLL1_SRC_SFT			11
+#define RT5645_PLL1_SRC_MCLK			(0x0 << 11)
+#define RT5645_PLL1_SRC_BCLK1			(0x1 << 11)
+#define RT5645_PLL1_SRC_BCLK2			(0x2 << 11)
+#define RT5645_PLL1_SRC_BCLK3			(0x3 << 11)
+#define RT5645_PLL1_SRC_RCCLK			(0x4 << 11)
+#define RT5645_PLL1_PD_MASK			(0x1 << 3)
+#define RT5645_PLL1_PD_SFT			3
+#define RT5645_PLL1_PD_1			(0x0 << 3)
+#define RT5645_PLL1_PD_2			(0x1 << 3)
+
+#define RT5645_PLL_INP_MAX			40000000
+#define RT5645_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5645_PLL_N_MAX			0x1ff
+#define RT5645_PLL_N_MASK			(RT5645_PLL_N_MAX << 7)
+#define RT5645_PLL_N_SFT			7
+#define RT5645_PLL_K_MAX			0x1f
+#define RT5645_PLL_K_MASK			(RT5645_PLL_K_MAX)
+#define RT5645_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5645_PLL_M_MAX			0xf
+#define RT5645_PLL_M_MASK			(RT5645_PLL_M_MAX << 12)
+#define RT5645_PLL_M_SFT			12
+#define RT5645_PLL_M_BP				(0x1 << 11)
+#define RT5645_PLL_M_BP_SFT			11
+
+/* ASRC Control 1 (0x83) */
+#define RT5645_STO_T_MASK			(0x1 << 15)
+#define RT5645_STO_T_SFT			15
+#define RT5645_STO_T_SCLK			(0x0 << 15)
+#define RT5645_STO_T_LRCK1			(0x1 << 15)
+#define RT5645_M1_T_MASK			(0x1 << 14)
+#define RT5645_M1_T_SFT				14
+#define RT5645_M1_T_I2S2			(0x0 << 14)
+#define RT5645_M1_T_I2S2_D3			(0x1 << 14)
+#define RT5645_I2S2_F_MASK			(0x1 << 12)
+#define RT5645_I2S2_F_SFT			12
+#define RT5645_I2S2_F_I2S2_D2			(0x0 << 12)
+#define RT5645_I2S2_F_I2S1_TCLK			(0x1 << 12)
+#define RT5645_DMIC_1_M_MASK			(0x1 << 9)
+#define RT5645_DMIC_1_M_SFT			9
+#define RT5645_DMIC_1_M_NOR			(0x0 << 9)
+#define RT5645_DMIC_1_M_ASYN			(0x1 << 9)
+#define RT5645_DMIC_2_M_MASK			(0x1 << 8)
+#define RT5645_DMIC_2_M_SFT			8
+#define RT5645_DMIC_2_M_NOR			(0x0 << 8)
+#define RT5645_DMIC_2_M_ASYN			(0x1 << 8)
+
+/* ASRC clock source selection (0x84, 0x85) */
+#define RT5645_CLK_SEL_SYS			(0x0)
+#define RT5645_CLK_SEL_I2S1_ASRC		(0x1)
+#define RT5645_CLK_SEL_I2S2_ASRC		(0x2)
+#define RT5645_CLK_SEL_SYS2			(0x5)
+
+/* ASRC Control 2 (0x84) */
+#define RT5645_DA_STO_CLK_SEL_MASK		(0xf << 12)
+#define RT5645_DA_STO_CLK_SEL_SFT		12
+#define RT5645_DA_MONOL_CLK_SEL_MASK		(0xf << 8)
+#define RT5645_DA_MONOL_CLK_SEL_SFT		8
+#define RT5645_DA_MONOR_CLK_SEL_MASK		(0xf << 4)
+#define RT5645_DA_MONOR_CLK_SEL_SFT		4
+#define RT5645_AD_STO1_CLK_SEL_MASK		(0xf << 0)
+#define RT5645_AD_STO1_CLK_SEL_SFT		0
+
+/* ASRC Control 3 (0x85) */
+#define RT5645_AD_MONOL_CLK_SEL_MASK		(0xf << 4)
+#define RT5645_AD_MONOL_CLK_SEL_SFT		4
+#define RT5645_AD_MONOR_CLK_SEL_MASK		(0xf << 0)
+#define RT5645_AD_MONOR_CLK_SEL_SFT		0
+
+/* ASRC Control 4 (0x89) */
+#define RT5645_I2S1_PD_MASK			(0x7 << 12)
+#define RT5645_I2S1_PD_SFT			12
+#define RT5645_I2S2_PD_MASK			(0x7 << 8)
+#define RT5645_I2S2_PD_SFT			8
+
+/* HPOUT Over Current Detection (0x8b) */
+#define RT5645_HP_OVCD_MASK			(0x1 << 10)
+#define RT5645_HP_OVCD_SFT			10
+#define RT5645_HP_OVCD_DIS			(0x0 << 10)
+#define RT5645_HP_OVCD_EN			(0x1 << 10)
+#define RT5645_HP_OC_TH_MASK			(0x3 << 8)
+#define RT5645_HP_OC_TH_SFT			8
+#define RT5645_HP_OC_TH_90			(0x0 << 8)
+#define RT5645_HP_OC_TH_105			(0x1 << 8)
+#define RT5645_HP_OC_TH_120			(0x2 << 8)
+#define RT5645_HP_OC_TH_135			(0x3 << 8)
+
+/* Class D Over Current Control (0x8c) */
+#define RT5645_CLSD_OC_MASK			(0x1 << 9)
+#define RT5645_CLSD_OC_SFT			9
+#define RT5645_CLSD_OC_PU			(0x0 << 9)
+#define RT5645_CLSD_OC_PD			(0x1 << 9)
+#define RT5645_AUTO_PD_MASK			(0x1 << 8)
+#define RT5645_AUTO_PD_SFT			8
+#define RT5645_AUTO_PD_DIS			(0x0 << 8)
+#define RT5645_AUTO_PD_EN			(0x1 << 8)
+#define RT5645_CLSD_OC_TH_MASK			(0x3f)
+#define RT5645_CLSD_OC_TH_SFT			0
+
+/* Class D Output Control (0x8d) */
+#define RT5645_CLSD_RATIO_MASK			(0xf << 12)
+#define RT5645_CLSD_RATIO_SFT			12
+#define RT5645_CLSD_OM_MASK			(0x1 << 11)
+#define RT5645_CLSD_OM_SFT			11
+#define RT5645_CLSD_OM_MONO			(0x0 << 11)
+#define RT5645_CLSD_OM_STO			(0x1 << 11)
+#define RT5645_CLSD_SCH_MASK			(0x1 << 10)
+#define RT5645_CLSD_SCH_SFT			10
+#define RT5645_CLSD_SCH_L			(0x0 << 10)
+#define RT5645_CLSD_SCH_S			(0x1 << 10)
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5645_SMT_TRIG_MASK			(0x1 << 15)
+#define RT5645_SMT_TRIG_SFT			15
+#define RT5645_SMT_TRIG_DIS			(0x0 << 15)
+#define RT5645_SMT_TRIG_EN			(0x1 << 15)
+#define RT5645_HP_L_SMT_MASK			(0x1 << 9)
+#define RT5645_HP_L_SMT_SFT			9
+#define RT5645_HP_L_SMT_DIS			(0x0 << 9)
+#define RT5645_HP_L_SMT_EN			(0x1 << 9)
+#define RT5645_HP_R_SMT_MASK			(0x1 << 8)
+#define RT5645_HP_R_SMT_SFT			8
+#define RT5645_HP_R_SMT_DIS			(0x0 << 8)
+#define RT5645_HP_R_SMT_EN			(0x1 << 8)
+#define RT5645_HP_CD_PD_MASK			(0x1 << 7)
+#define RT5645_HP_CD_PD_SFT			7
+#define RT5645_HP_CD_PD_DIS			(0x0 << 7)
+#define RT5645_HP_CD_PD_EN			(0x1 << 7)
+#define RT5645_RSTN_MASK			(0x1 << 6)
+#define RT5645_RSTN_SFT				6
+#define RT5645_RSTN_DIS				(0x0 << 6)
+#define RT5645_RSTN_EN				(0x1 << 6)
+#define RT5645_RSTP_MASK			(0x1 << 5)
+#define RT5645_RSTP_SFT				5
+#define RT5645_RSTP_DIS				(0x0 << 5)
+#define RT5645_RSTP_EN				(0x1 << 5)
+#define RT5645_HP_CO_MASK			(0x1 << 4)
+#define RT5645_HP_CO_SFT			4
+#define RT5645_HP_CO_DIS			(0x0 << 4)
+#define RT5645_HP_CO_EN				(0x1 << 4)
+#define RT5645_HP_CP_MASK			(0x1 << 3)
+#define RT5645_HP_CP_SFT			3
+#define RT5645_HP_CP_PD				(0x0 << 3)
+#define RT5645_HP_CP_PU				(0x1 << 3)
+#define RT5645_HP_SG_MASK			(0x1 << 2)
+#define RT5645_HP_SG_SFT			2
+#define RT5645_HP_SG_DIS			(0x0 << 2)
+#define RT5645_HP_SG_EN				(0x1 << 2)
+#define RT5645_HP_DP_MASK			(0x1 << 1)
+#define RT5645_HP_DP_SFT			1
+#define RT5645_HP_DP_PD				(0x0 << 1)
+#define RT5645_HP_DP_PU				(0x1 << 1)
+#define RT5645_HP_CB_MASK			(0x1)
+#define RT5645_HP_CB_SFT			0
+#define RT5645_HP_CB_PD				(0x0)
+#define RT5645_HP_CB_PU				(0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5645_DEPOP_MASK			(0x1 << 13)
+#define RT5645_DEPOP_SFT			13
+#define RT5645_DEPOP_AUTO			(0x0 << 13)
+#define RT5645_DEPOP_MAN			(0x1 << 13)
+#define RT5645_RAMP_MASK			(0x1 << 12)
+#define RT5645_RAMP_SFT				12
+#define RT5645_RAMP_DIS				(0x0 << 12)
+#define RT5645_RAMP_EN				(0x1 << 12)
+#define RT5645_BPS_MASK				(0x1 << 11)
+#define RT5645_BPS_SFT				11
+#define RT5645_BPS_DIS				(0x0 << 11)
+#define RT5645_BPS_EN				(0x1 << 11)
+#define RT5645_FAST_UPDN_MASK			(0x1 << 10)
+#define RT5645_FAST_UPDN_SFT			10
+#define RT5645_FAST_UPDN_DIS			(0x0 << 10)
+#define RT5645_FAST_UPDN_EN			(0x1 << 10)
+#define RT5645_MRES_MASK			(0x3 << 8)
+#define RT5645_MRES_SFT				8
+#define RT5645_MRES_15MO			(0x0 << 8)
+#define RT5645_MRES_25MO			(0x1 << 8)
+#define RT5645_MRES_35MO			(0x2 << 8)
+#define RT5645_MRES_45MO			(0x3 << 8)
+#define RT5645_VLO_MASK				(0x1 << 7)
+#define RT5645_VLO_SFT				7
+#define RT5645_VLO_3V				(0x0 << 7)
+#define RT5645_VLO_32V				(0x1 << 7)
+#define RT5645_DIG_DP_MASK			(0x1 << 6)
+#define RT5645_DIG_DP_SFT			6
+#define RT5645_DIG_DP_DIS			(0x0 << 6)
+#define RT5645_DIG_DP_EN			(0x1 << 6)
+#define RT5645_DP_TH_MASK			(0x3 << 4)
+#define RT5645_DP_TH_SFT			4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5645_CP_SYS_MASK			(0x7 << 12)
+#define RT5645_CP_SYS_SFT			12
+#define RT5645_CP_FQ1_MASK			(0x7 << 8)
+#define RT5645_CP_FQ1_SFT			8
+#define RT5645_CP_FQ2_MASK			(0x7 << 4)
+#define RT5645_CP_FQ2_SFT			4
+#define RT5645_CP_FQ3_MASK			(0x7)
+#define RT5645_CP_FQ3_SFT			0
+#define RT5645_CP_FQ_1_5_KHZ			0
+#define RT5645_CP_FQ_3_KHZ			1
+#define RT5645_CP_FQ_6_KHZ			2
+#define RT5645_CP_FQ_12_KHZ			3
+#define RT5645_CP_FQ_24_KHZ			4
+#define RT5645_CP_FQ_48_KHZ			5
+#define RT5645_CP_FQ_96_KHZ			6
+#define RT5645_CP_FQ_192_KHZ			7
+
+/* PV detection and SPK gain control (0x92) */
+#define RT5645_PVDD_DET_MASK			(0x1 << 15)
+#define RT5645_PVDD_DET_SFT			15
+#define RT5645_PVDD_DET_DIS			(0x0 << 15)
+#define RT5645_PVDD_DET_EN			(0x1 << 15)
+#define RT5645_SPK_AG_MASK			(0x1 << 14)
+#define RT5645_SPK_AG_SFT			14
+#define RT5645_SPK_AG_DIS			(0x0 << 14)
+#define RT5645_SPK_AG_EN			(0x1 << 14)
+
+/* Micbias Control (0x93) */
+#define RT5645_MIC1_BS_MASK			(0x1 << 15)
+#define RT5645_MIC1_BS_SFT			15
+#define RT5645_MIC1_BS_9AV			(0x0 << 15)
+#define RT5645_MIC1_BS_75AV			(0x1 << 15)
+#define RT5645_MIC2_BS_MASK			(0x1 << 14)
+#define RT5645_MIC2_BS_SFT			14
+#define RT5645_MIC2_BS_9AV			(0x0 << 14)
+#define RT5645_MIC2_BS_75AV			(0x1 << 14)
+#define RT5645_MIC1_CLK_MASK			(0x1 << 13)
+#define RT5645_MIC1_CLK_SFT			13
+#define RT5645_MIC1_CLK_DIS			(0x0 << 13)
+#define RT5645_MIC1_CLK_EN			(0x1 << 13)
+#define RT5645_MIC2_CLK_MASK			(0x1 << 12)
+#define RT5645_MIC2_CLK_SFT			12
+#define RT5645_MIC2_CLK_DIS			(0x0 << 12)
+#define RT5645_MIC2_CLK_EN			(0x1 << 12)
+#define RT5645_MIC1_OVCD_MASK			(0x1 << 11)
+#define RT5645_MIC1_OVCD_SFT			11
+#define RT5645_MIC1_OVCD_DIS			(0x0 << 11)
+#define RT5645_MIC1_OVCD_EN			(0x1 << 11)
+#define RT5645_MIC1_OVTH_MASK			(0x3 << 9)
+#define RT5645_MIC1_OVTH_SFT			9
+#define RT5645_MIC1_OVTH_600UA			(0x0 << 9)
+#define RT5645_MIC1_OVTH_1500UA			(0x1 << 9)
+#define RT5645_MIC1_OVTH_2000UA			(0x2 << 9)
+#define RT5645_MIC2_OVCD_MASK			(0x1 << 8)
+#define RT5645_MIC2_OVCD_SFT			8
+#define RT5645_MIC2_OVCD_DIS			(0x0 << 8)
+#define RT5645_MIC2_OVCD_EN			(0x1 << 8)
+#define RT5645_MIC2_OVTH_MASK			(0x3 << 6)
+#define RT5645_MIC2_OVTH_SFT			6
+#define RT5645_MIC2_OVTH_600UA			(0x0 << 6)
+#define RT5645_MIC2_OVTH_1500UA			(0x1 << 6)
+#define RT5645_MIC2_OVTH_2000UA			(0x2 << 6)
+#define RT5645_PWR_MB_MASK			(0x1 << 5)
+#define RT5645_PWR_MB_SFT			5
+#define RT5645_PWR_MB_PD			(0x0 << 5)
+#define RT5645_PWR_MB_PU			(0x1 << 5)
+#define RT5645_PWR_CLK25M_MASK			(0x1 << 4)
+#define RT5645_PWR_CLK25M_SFT			4
+#define RT5645_PWR_CLK25M_PD			(0x0 << 4)
+#define RT5645_PWR_CLK25M_PU			(0x1 << 4)
+#define RT5645_IRQ_CLK_MCLK			(0x0 << 3)
+#define RT5645_IRQ_CLK_INT			(0x1 << 3)
+#define RT5645_JD1_MODE_MASK			(0x3 << 0)
+#define RT5645_JD1_MODE_0			(0x0 << 0)
+#define RT5645_JD1_MODE_1			(0x1 << 0)
+#define RT5645_JD1_MODE_2			(0x2 << 0)
+
+/* VAD Control 4 (0x9d) */
+#define RT5645_VAD_SEL_MASK			(0x3 << 8)
+#define RT5645_VAD_SEL_SFT			8
+
+/* EQ Control 1 (0xb0) */
+#define RT5645_EQ_SRC_MASK			(0x1 << 15)
+#define RT5645_EQ_SRC_SFT			15
+#define RT5645_EQ_SRC_DAC			(0x0 << 15)
+#define RT5645_EQ_SRC_ADC			(0x1 << 15)
+#define RT5645_EQ_UPD				(0x1 << 14)
+#define RT5645_EQ_UPD_BIT			14
+#define RT5645_EQ_CD_MASK			(0x1 << 13)
+#define RT5645_EQ_CD_SFT			13
+#define RT5645_EQ_CD_DIS			(0x0 << 13)
+#define RT5645_EQ_CD_EN				(0x1 << 13)
+#define RT5645_EQ_DITH_MASK			(0x3 << 8)
+#define RT5645_EQ_DITH_SFT			8
+#define RT5645_EQ_DITH_NOR			(0x0 << 8)
+#define RT5645_EQ_DITH_LSB			(0x1 << 8)
+#define RT5645_EQ_DITH_LSB_1			(0x2 << 8)
+#define RT5645_EQ_DITH_LSB_2			(0x3 << 8)
+
+/* EQ Control 2 (0xb1) */
+#define RT5645_EQ_HPF1_M_MASK			(0x1 << 8)
+#define RT5645_EQ_HPF1_M_SFT			8
+#define RT5645_EQ_HPF1_M_HI			(0x0 << 8)
+#define RT5645_EQ_HPF1_M_1ST			(0x1 << 8)
+#define RT5645_EQ_LPF1_M_MASK			(0x1 << 7)
+#define RT5645_EQ_LPF1_M_SFT			7
+#define RT5645_EQ_LPF1_M_LO			(0x0 << 7)
+#define RT5645_EQ_LPF1_M_1ST			(0x1 << 7)
+#define RT5645_EQ_HPF2_MASK			(0x1 << 6)
+#define RT5645_EQ_HPF2_SFT			6
+#define RT5645_EQ_HPF2_DIS			(0x0 << 6)
+#define RT5645_EQ_HPF2_EN			(0x1 << 6)
+#define RT5645_EQ_HPF1_MASK			(0x1 << 5)
+#define RT5645_EQ_HPF1_SFT			5
+#define RT5645_EQ_HPF1_DIS			(0x0 << 5)
+#define RT5645_EQ_HPF1_EN			(0x1 << 5)
+#define RT5645_EQ_BPF4_MASK			(0x1 << 4)
+#define RT5645_EQ_BPF4_SFT			4
+#define RT5645_EQ_BPF4_DIS			(0x0 << 4)
+#define RT5645_EQ_BPF4_EN			(0x1 << 4)
+#define RT5645_EQ_BPF3_MASK			(0x1 << 3)
+#define RT5645_EQ_BPF3_SFT			3
+#define RT5645_EQ_BPF3_DIS			(0x0 << 3)
+#define RT5645_EQ_BPF3_EN			(0x1 << 3)
+#define RT5645_EQ_BPF2_MASK			(0x1 << 2)
+#define RT5645_EQ_BPF2_SFT			2
+#define RT5645_EQ_BPF2_DIS			(0x0 << 2)
+#define RT5645_EQ_BPF2_EN			(0x1 << 2)
+#define RT5645_EQ_BPF1_MASK			(0x1 << 1)
+#define RT5645_EQ_BPF1_SFT			1
+#define RT5645_EQ_BPF1_DIS			(0x0 << 1)
+#define RT5645_EQ_BPF1_EN			(0x1 << 1)
+#define RT5645_EQ_LPF_MASK			(0x1)
+#define RT5645_EQ_LPF_SFT			0
+#define RT5645_EQ_LPF_DIS			(0x0)
+#define RT5645_EQ_LPF_EN			(0x1)
+#define RT5645_EQ_CTRL_MASK			(0x7f)
+
+/* Memory Test (0xb2) */
+#define RT5645_MT_MASK				(0x1 << 15)
+#define RT5645_MT_SFT				15
+#define RT5645_MT_DIS				(0x0 << 15)
+#define RT5645_MT_EN				(0x1 << 15)
+
+/* DRC/AGC Control 1 (0xb4) */
+#define RT5645_DRC_AGC_P_MASK			(0x1 << 15)
+#define RT5645_DRC_AGC_P_SFT			15
+#define RT5645_DRC_AGC_P_DAC			(0x0 << 15)
+#define RT5645_DRC_AGC_P_ADC			(0x1 << 15)
+#define RT5645_DRC_AGC_MASK			(0x1 << 14)
+#define RT5645_DRC_AGC_SFT			14
+#define RT5645_DRC_AGC_DIS			(0x0 << 14)
+#define RT5645_DRC_AGC_EN			(0x1 << 14)
+#define RT5645_DRC_AGC_UPD			(0x1 << 13)
+#define RT5645_DRC_AGC_UPD_BIT			13
+#define RT5645_DRC_AGC_AR_MASK			(0x1f << 8)
+#define RT5645_DRC_AGC_AR_SFT			8
+#define RT5645_DRC_AGC_R_MASK			(0x7 << 5)
+#define RT5645_DRC_AGC_R_SFT			5
+#define RT5645_DRC_AGC_R_48K			(0x1 << 5)
+#define RT5645_DRC_AGC_R_96K			(0x2 << 5)
+#define RT5645_DRC_AGC_R_192K			(0x3 << 5)
+#define RT5645_DRC_AGC_R_441K			(0x5 << 5)
+#define RT5645_DRC_AGC_R_882K			(0x6 << 5)
+#define RT5645_DRC_AGC_R_1764K			(0x7 << 5)
+#define RT5645_DRC_AGC_RC_MASK			(0x1f)
+#define RT5645_DRC_AGC_RC_SFT			0
+
+/* DRC/AGC Control 2 (0xb5) */
+#define RT5645_DRC_AGC_POB_MASK			(0x3f << 8)
+#define RT5645_DRC_AGC_POB_SFT			8
+#define RT5645_DRC_AGC_CP_MASK			(0x1 << 7)
+#define RT5645_DRC_AGC_CP_SFT			7
+#define RT5645_DRC_AGC_CP_DIS			(0x0 << 7)
+#define RT5645_DRC_AGC_CP_EN			(0x1 << 7)
+#define RT5645_DRC_AGC_CPR_MASK			(0x3 << 5)
+#define RT5645_DRC_AGC_CPR_SFT			5
+#define RT5645_DRC_AGC_CPR_1_1			(0x0 << 5)
+#define RT5645_DRC_AGC_CPR_1_2			(0x1 << 5)
+#define RT5645_DRC_AGC_CPR_1_3			(0x2 << 5)
+#define RT5645_DRC_AGC_CPR_1_4			(0x3 << 5)
+#define RT5645_DRC_AGC_PRB_MASK			(0x1f)
+#define RT5645_DRC_AGC_PRB_SFT			0
+
+/* DRC/AGC Control 3 (0xb6) */
+#define RT5645_DRC_AGC_NGB_MASK			(0xf << 12)
+#define RT5645_DRC_AGC_NGB_SFT			12
+#define RT5645_DRC_AGC_TAR_MASK			(0x1f << 7)
+#define RT5645_DRC_AGC_TAR_SFT			7
+#define RT5645_DRC_AGC_NG_MASK			(0x1 << 6)
+#define RT5645_DRC_AGC_NG_SFT			6
+#define RT5645_DRC_AGC_NG_DIS			(0x0 << 6)
+#define RT5645_DRC_AGC_NG_EN			(0x1 << 6)
+#define RT5645_DRC_AGC_NGH_MASK			(0x1 << 5)
+#define RT5645_DRC_AGC_NGH_SFT			5
+#define RT5645_DRC_AGC_NGH_DIS			(0x0 << 5)
+#define RT5645_DRC_AGC_NGH_EN			(0x1 << 5)
+#define RT5645_DRC_AGC_NGT_MASK			(0x1f)
+#define RT5645_DRC_AGC_NGT_SFT			0
+
+/* ANC Control 1 (0xb8) */
+#define RT5645_ANC_M_MASK			(0x1 << 15)
+#define RT5645_ANC_M_SFT			15
+#define RT5645_ANC_M_NOR			(0x0 << 15)
+#define RT5645_ANC_M_REV			(0x1 << 15)
+#define RT5645_ANC_MASK				(0x1 << 14)
+#define RT5645_ANC_SFT				14
+#define RT5645_ANC_DIS				(0x0 << 14)
+#define RT5645_ANC_EN				(0x1 << 14)
+#define RT5645_ANC_MD_MASK			(0x3 << 12)
+#define RT5645_ANC_MD_SFT			12
+#define RT5645_ANC_MD_DIS			(0x0 << 12)
+#define RT5645_ANC_MD_67MS			(0x1 << 12)
+#define RT5645_ANC_MD_267MS			(0x2 << 12)
+#define RT5645_ANC_MD_1067MS			(0x3 << 12)
+#define RT5645_ANC_SN_MASK			(0x1 << 11)
+#define RT5645_ANC_SN_SFT			11
+#define RT5645_ANC_SN_DIS			(0x0 << 11)
+#define RT5645_ANC_SN_EN			(0x1 << 11)
+#define RT5645_ANC_CLK_MASK			(0x1 << 10)
+#define RT5645_ANC_CLK_SFT			10
+#define RT5645_ANC_CLK_ANC			(0x0 << 10)
+#define RT5645_ANC_CLK_REG			(0x1 << 10)
+#define RT5645_ANC_ZCD_MASK			(0x3 << 8)
+#define RT5645_ANC_ZCD_SFT			8
+#define RT5645_ANC_ZCD_DIS			(0x0 << 8)
+#define RT5645_ANC_ZCD_T1			(0x1 << 8)
+#define RT5645_ANC_ZCD_T2			(0x2 << 8)
+#define RT5645_ANC_ZCD_WT			(0x3 << 8)
+#define RT5645_ANC_CS_MASK			(0x1 << 7)
+#define RT5645_ANC_CS_SFT			7
+#define RT5645_ANC_CS_DIS			(0x0 << 7)
+#define RT5645_ANC_CS_EN			(0x1 << 7)
+#define RT5645_ANC_SW_MASK			(0x1 << 6)
+#define RT5645_ANC_SW_SFT			6
+#define RT5645_ANC_SW_NOR			(0x0 << 6)
+#define RT5645_ANC_SW_AUTO			(0x1 << 6)
+#define RT5645_ANC_CO_L_MASK			(0x3f)
+#define RT5645_ANC_CO_L_SFT			0
+
+/* ANC Control 2 (0xb6) */
+#define RT5645_ANC_FG_R_MASK			(0xf << 12)
+#define RT5645_ANC_FG_R_SFT			12
+#define RT5645_ANC_FG_L_MASK			(0xf << 8)
+#define RT5645_ANC_FG_L_SFT			8
+#define RT5645_ANC_CG_R_MASK			(0xf << 4)
+#define RT5645_ANC_CG_R_SFT			4
+#define RT5645_ANC_CG_L_MASK			(0xf)
+#define RT5645_ANC_CG_L_SFT			0
+
+/* ANC Control 3 (0xb6) */
+#define RT5645_ANC_CD_MASK			(0x1 << 6)
+#define RT5645_ANC_CD_SFT			6
+#define RT5645_ANC_CD_BOTH			(0x0 << 6)
+#define RT5645_ANC_CD_IND			(0x1 << 6)
+#define RT5645_ANC_CO_R_MASK			(0x3f)
+#define RT5645_ANC_CO_R_SFT			0
+
+/* Jack Detect Control (0xbb) */
+#define RT5645_JD_MASK				(0x7 << 13)
+#define RT5645_JD_SFT				13
+#define RT5645_JD_DIS				(0x0 << 13)
+#define RT5645_JD_GPIO1				(0x1 << 13)
+#define RT5645_JD_JD1_IN4P			(0x2 << 13)
+#define RT5645_JD_JD2_IN4N			(0x3 << 13)
+#define RT5645_JD_GPIO2				(0x4 << 13)
+#define RT5645_JD_GPIO3				(0x5 << 13)
+#define RT5645_JD_GPIO4				(0x6 << 13)
+#define RT5645_JD_HP_MASK			(0x1 << 11)
+#define RT5645_JD_HP_SFT			11
+#define RT5645_JD_HP_DIS			(0x0 << 11)
+#define RT5645_JD_HP_EN				(0x1 << 11)
+#define RT5645_JD_HP_TRG_MASK			(0x1 << 10)
+#define RT5645_JD_HP_TRG_SFT			10
+#define RT5645_JD_HP_TRG_LO			(0x0 << 10)
+#define RT5645_JD_HP_TRG_HI			(0x1 << 10)
+#define RT5645_JD_SPL_MASK			(0x1 << 9)
+#define RT5645_JD_SPL_SFT			9
+#define RT5645_JD_SPL_DIS			(0x0 << 9)
+#define RT5645_JD_SPL_EN			(0x1 << 9)
+#define RT5645_JD_SPL_TRG_MASK			(0x1 << 8)
+#define RT5645_JD_SPL_TRG_SFT			8
+#define RT5645_JD_SPL_TRG_LO			(0x0 << 8)
+#define RT5645_JD_SPL_TRG_HI			(0x1 << 8)
+#define RT5645_JD_SPR_MASK			(0x1 << 7)
+#define RT5645_JD_SPR_SFT			7
+#define RT5645_JD_SPR_DIS			(0x0 << 7)
+#define RT5645_JD_SPR_EN			(0x1 << 7)
+#define RT5645_JD_SPR_TRG_MASK			(0x1 << 6)
+#define RT5645_JD_SPR_TRG_SFT			6
+#define RT5645_JD_SPR_TRG_LO			(0x0 << 6)
+#define RT5645_JD_SPR_TRG_HI			(0x1 << 6)
+#define RT5645_JD_MO_MASK			(0x1 << 5)
+#define RT5645_JD_MO_SFT			5
+#define RT5645_JD_MO_DIS			(0x0 << 5)
+#define RT5645_JD_MO_EN				(0x1 << 5)
+#define RT5645_JD_MO_TRG_MASK			(0x1 << 4)
+#define RT5645_JD_MO_TRG_SFT			4
+#define RT5645_JD_MO_TRG_LO			(0x0 << 4)
+#define RT5645_JD_MO_TRG_HI			(0x1 << 4)
+#define RT5645_JD_LO_MASK			(0x1 << 3)
+#define RT5645_JD_LO_SFT			3
+#define RT5645_JD_LO_DIS			(0x0 << 3)
+#define RT5645_JD_LO_EN				(0x1 << 3)
+#define RT5645_JD_LO_TRG_MASK			(0x1 << 2)
+#define RT5645_JD_LO_TRG_SFT			2
+#define RT5645_JD_LO_TRG_LO			(0x0 << 2)
+#define RT5645_JD_LO_TRG_HI			(0x1 << 2)
+#define RT5645_JD1_IN4P_MASK			(0x1 << 1)
+#define RT5645_JD1_IN4P_SFT			1
+#define RT5645_JD1_IN4P_DIS			(0x0 << 1)
+#define RT5645_JD1_IN4P_EN			(0x1 << 1)
+#define RT5645_JD2_IN4N_MASK			(0x1)
+#define RT5645_JD2_IN4N_SFT			0
+#define RT5645_JD2_IN4N_DIS			(0x0)
+#define RT5645_JD2_IN4N_EN			(0x1)
+
+/* Jack detect for ANC (0xbc) */
+#define RT5645_ANC_DET_MASK			(0x3 << 4)
+#define RT5645_ANC_DET_SFT			4
+#define RT5645_ANC_DET_DIS			(0x0 << 4)
+#define RT5645_ANC_DET_MB1			(0x1 << 4)
+#define RT5645_ANC_DET_MB2			(0x2 << 4)
+#define RT5645_ANC_DET_JD			(0x3 << 4)
+#define RT5645_AD_TRG_MASK			(0x1 << 3)
+#define RT5645_AD_TRG_SFT			3
+#define RT5645_AD_TRG_LO			(0x0 << 3)
+#define RT5645_AD_TRG_HI			(0x1 << 3)
+#define RT5645_ANCM_DET_MASK			(0x3 << 4)
+#define RT5645_ANCM_DET_SFT			4
+#define RT5645_ANCM_DET_DIS			(0x0 << 4)
+#define RT5645_ANCM_DET_MB1			(0x1 << 4)
+#define RT5645_ANCM_DET_MB2			(0x2 << 4)
+#define RT5645_ANCM_DET_JD			(0x3 << 4)
+#define RT5645_AMD_TRG_MASK			(0x1 << 3)
+#define RT5645_AMD_TRG_SFT			3
+#define RT5645_AMD_TRG_LO			(0x0 << 3)
+#define RT5645_AMD_TRG_HI			(0x1 << 3)
+
+/* IRQ Control 1 (0xbd) */
+#define RT5645_IRQ_JD_MASK			(0x1 << 15)
+#define RT5645_IRQ_JD_SFT			15
+#define RT5645_IRQ_JD_BP			(0x0 << 15)
+#define RT5645_IRQ_JD_NOR			(0x1 << 15)
+#define RT5645_IRQ_OT_MASK			(0x1 << 14)
+#define RT5645_IRQ_OT_SFT			14
+#define RT5645_IRQ_OT_BP			(0x0 << 14)
+#define RT5645_IRQ_OT_NOR			(0x1 << 14)
+#define RT5645_JD_STKY_MASK			(0x1 << 13)
+#define RT5645_JD_STKY_SFT			13
+#define RT5645_JD_STKY_DIS			(0x0 << 13)
+#define RT5645_JD_STKY_EN			(0x1 << 13)
+#define RT5645_OT_STKY_MASK			(0x1 << 12)
+#define RT5645_OT_STKY_SFT			12
+#define RT5645_OT_STKY_DIS			(0x0 << 12)
+#define RT5645_OT_STKY_EN			(0x1 << 12)
+#define RT5645_JD_P_MASK			(0x1 << 11)
+#define RT5645_JD_P_SFT				11
+#define RT5645_JD_P_NOR				(0x0 << 11)
+#define RT5645_JD_P_INV				(0x1 << 11)
+#define RT5645_OT_P_MASK			(0x1 << 10)
+#define RT5645_OT_P_SFT				10
+#define RT5645_OT_P_NOR				(0x0 << 10)
+#define RT5645_OT_P_INV				(0x1 << 10)
+#define RT5645_IRQ_JD_1_1_EN			(0x1 << 9)
+#define RT5645_JD_1_1_MASK			(0x1 << 7)
+#define RT5645_JD_1_1_SFT			7
+#define RT5645_JD_1_1_NOR			(0x0 << 7)
+#define RT5645_JD_1_1_INV			(0x1 << 7)
+
+/* IRQ Control 2 (0xbe) */
+#define RT5645_IRQ_MB1_OC_MASK			(0x1 << 15)
+#define RT5645_IRQ_MB1_OC_SFT			15
+#define RT5645_IRQ_MB1_OC_BP			(0x0 << 15)
+#define RT5645_IRQ_MB1_OC_NOR			(0x1 << 15)
+#define RT5645_IRQ_MB2_OC_MASK			(0x1 << 14)
+#define RT5645_IRQ_MB2_OC_SFT			14
+#define RT5645_IRQ_MB2_OC_BP			(0x0 << 14)
+#define RT5645_IRQ_MB2_OC_NOR			(0x1 << 14)
+#define RT5645_MB1_OC_STKY_MASK			(0x1 << 13)
+#define RT5645_MB1_OC_STKY_SFT			13
+#define RT5645_MB1_OC_STKY_DIS			(0x0 << 13)
+#define RT5645_MB1_OC_STKY_EN			(0x1 << 13)
+#define RT5645_MB2_OC_STKY_MASK			(0x1 << 12)
+#define RT5645_MB2_OC_STKY_SFT			12
+#define RT5645_MB2_OC_STKY_DIS			(0x0 << 12)
+#define RT5645_MB2_OC_STKY_EN			(0x1 << 12)
+#define RT5645_MB1_OC_P_MASK			(0x1 << 7)
+#define RT5645_MB1_OC_P_SFT			7
+#define RT5645_MB1_OC_P_NOR			(0x0 << 7)
+#define RT5645_MB1_OC_P_INV			(0x1 << 7)
+#define RT5645_MB2_OC_P_MASK			(0x1 << 6)
+#define RT5645_MB2_OC_P_SFT			6
+#define RT5645_MB2_OC_P_NOR			(0x0 << 6)
+#define RT5645_MB2_OC_P_INV			(0x1 << 6)
+#define RT5645_MB1_OC_CLR			(0x1 << 3)
+#define RT5645_MB1_OC_CLR_SFT			3
+#define RT5645_MB2_OC_CLR			(0x1 << 2)
+#define RT5645_MB2_OC_CLR_SFT			2
+
+/* GPIO Control 1 (0xc0) */
+#define RT5645_GP1_PIN_MASK			(0x1 << 15)
+#define RT5645_GP1_PIN_SFT			15
+#define RT5645_GP1_PIN_GPIO1			(0x0 << 15)
+#define RT5645_GP1_PIN_IRQ			(0x1 << 15)
+#define RT5645_GP2_PIN_MASK			(0x1 << 14)
+#define RT5645_GP2_PIN_SFT			14
+#define RT5645_GP2_PIN_GPIO2			(0x0 << 14)
+#define RT5645_GP2_PIN_DMIC1_SCL		(0x1 << 14)
+#define RT5645_GP3_PIN_MASK			(0x3 << 12)
+#define RT5645_GP3_PIN_SFT			12
+#define RT5645_GP3_PIN_GPIO3			(0x0 << 12)
+#define RT5645_GP3_PIN_DMIC1_SDA		(0x1 << 12)
+#define RT5645_GP3_PIN_IRQ			(0x2 << 12)
+#define RT5645_GP4_PIN_MASK			(0x1 << 11)
+#define RT5645_GP4_PIN_SFT			11
+#define RT5645_GP4_PIN_GPIO4			(0x0 << 11)
+#define RT5645_GP4_PIN_DMIC2_SDA		(0x1 << 11)
+#define RT5645_DP_SIG_MASK			(0x1 << 10)
+#define RT5645_DP_SIG_SFT			10
+#define RT5645_DP_SIG_TEST			(0x0 << 10)
+#define RT5645_DP_SIG_AP			(0x1 << 10)
+#define RT5645_GPIO_M_MASK			(0x1 << 9)
+#define RT5645_GPIO_M_SFT			9
+#define RT5645_GPIO_M_FLT			(0x0 << 9)
+#define RT5645_GPIO_M_PH			(0x1 << 9)
+#define RT5645_I2S2_SEL				(0x1 << 8)
+#define RT5645_I2S2_SEL_SFT			8
+#define RT5645_GP5_PIN_MASK			(0x1 << 7)
+#define RT5645_GP5_PIN_SFT			7
+#define RT5645_GP5_PIN_GPIO5			(0x0 << 7)
+#define RT5645_GP5_PIN_DMIC1_SDA		(0x1 << 7)
+#define RT5645_GP6_PIN_MASK			(0x1 << 6)
+#define RT5645_GP6_PIN_SFT			6
+#define RT5645_GP6_PIN_GPIO6			(0x0 << 6)
+#define RT5645_GP6_PIN_DMIC2_SDA		(0x1 << 6)
+#define RT5645_I2S2_DAC_PIN_MASK		(0x1 << 4)
+#define RT5645_I2S2_DAC_PIN_SFT			4
+#define RT5645_I2S2_DAC_PIN_I2S			(0x0 << 4)
+#define RT5645_I2S2_DAC_PIN_GPIO		(0x1 << 4)
+#define RT5645_GP8_PIN_MASK			(0x1 << 3)
+#define RT5645_GP8_PIN_SFT			3
+#define RT5645_GP8_PIN_GPIO8			(0x0 << 3)
+#define RT5645_GP8_PIN_DMIC2_SDA		(0x1 << 3)
+#define RT5645_GP12_PIN_MASK			(0x1 << 2)
+#define RT5645_GP12_PIN_SFT			2
+#define RT5645_GP12_PIN_GPIO12			(0x0 << 2)
+#define RT5645_GP12_PIN_DMIC2_SDA		(0x1 << 2)
+#define RT5645_GP11_PIN_MASK			(0x1 << 1)
+#define RT5645_GP11_PIN_SFT			1
+#define RT5645_GP11_PIN_GPIO11			(0x0 << 1)
+#define RT5645_GP11_PIN_DMIC1_SDA		(0x1 << 1)
+#define RT5645_GP10_PIN_MASK			(0x1)
+#define RT5645_GP10_PIN_SFT			0
+#define RT5645_GP10_PIN_GPIO10			(0x0)
+#define RT5645_GP10_PIN_DMIC2_SDA		(0x1)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5645_GP4_PF_MASK			(0x1 << 11)
+#define RT5645_GP4_PF_SFT			11
+#define RT5645_GP4_PF_IN			(0x0 << 11)
+#define RT5645_GP4_PF_OUT			(0x1 << 11)
+#define RT5645_GP4_OUT_MASK			(0x1 << 10)
+#define RT5645_GP4_OUT_SFT			10
+#define RT5645_GP4_OUT_LO			(0x0 << 10)
+#define RT5645_GP4_OUT_HI			(0x1 << 10)
+#define RT5645_GP4_P_MASK			(0x1 << 9)
+#define RT5645_GP4_P_SFT			9
+#define RT5645_GP4_P_NOR			(0x0 << 9)
+#define RT5645_GP4_P_INV			(0x1 << 9)
+#define RT5645_GP3_PF_MASK			(0x1 << 8)
+#define RT5645_GP3_PF_SFT			8
+#define RT5645_GP3_PF_IN			(0x0 << 8)
+#define RT5645_GP3_PF_OUT			(0x1 << 8)
+#define RT5645_GP3_OUT_MASK			(0x1 << 7)
+#define RT5645_GP3_OUT_SFT			7
+#define RT5645_GP3_OUT_LO			(0x0 << 7)
+#define RT5645_GP3_OUT_HI			(0x1 << 7)
+#define RT5645_GP3_P_MASK			(0x1 << 6)
+#define RT5645_GP3_P_SFT			6
+#define RT5645_GP3_P_NOR			(0x0 << 6)
+#define RT5645_GP3_P_INV			(0x1 << 6)
+#define RT5645_GP2_PF_MASK			(0x1 << 5)
+#define RT5645_GP2_PF_SFT			5
+#define RT5645_GP2_PF_IN			(0x0 << 5)
+#define RT5645_GP2_PF_OUT			(0x1 << 5)
+#define RT5645_GP2_OUT_MASK			(0x1 << 4)
+#define RT5645_GP2_OUT_SFT			4
+#define RT5645_GP2_OUT_LO			(0x0 << 4)
+#define RT5645_GP2_OUT_HI			(0x1 << 4)
+#define RT5645_GP2_P_MASK			(0x1 << 3)
+#define RT5645_GP2_P_SFT			3
+#define RT5645_GP2_P_NOR			(0x0 << 3)
+#define RT5645_GP2_P_INV			(0x1 << 3)
+#define RT5645_GP1_PF_MASK			(0x1 << 2)
+#define RT5645_GP1_PF_SFT			2
+#define RT5645_GP1_PF_IN			(0x0 << 2)
+#define RT5645_GP1_PF_OUT			(0x1 << 2)
+#define RT5645_GP1_OUT_MASK			(0x1 << 1)
+#define RT5645_GP1_OUT_SFT			1
+#define RT5645_GP1_OUT_LO			(0x0 << 1)
+#define RT5645_GP1_OUT_HI			(0x1 << 1)
+#define RT5645_GP1_P_MASK			(0x1)
+#define RT5645_GP1_P_SFT			0
+#define RT5645_GP1_P_NOR			(0x0)
+#define RT5645_GP1_P_INV			(0x1)
+
+/* Programmable Register Array Control 1 (0xc8) */
+#define RT5645_REG_SEQ_MASK			(0xf << 12)
+#define RT5645_REG_SEQ_SFT			12
+#define RT5645_SEQ1_ST_MASK			(0x1 << 11) /*RO*/
+#define RT5645_SEQ1_ST_SFT			11
+#define RT5645_SEQ1_ST_RUN			(0x0 << 11)
+#define RT5645_SEQ1_ST_FIN			(0x1 << 11)
+#define RT5645_SEQ2_ST_MASK			(0x1 << 10) /*RO*/
+#define RT5645_SEQ2_ST_SFT			10
+#define RT5645_SEQ2_ST_RUN			(0x0 << 10)
+#define RT5645_SEQ2_ST_FIN			(0x1 << 10)
+#define RT5645_REG_LV_MASK			(0x1 << 9)
+#define RT5645_REG_LV_SFT			9
+#define RT5645_REG_LV_MX			(0x0 << 9)
+#define RT5645_REG_LV_PR			(0x1 << 9)
+#define RT5645_SEQ_2_PT_MASK			(0x1 << 8)
+#define RT5645_SEQ_2_PT_BIT			8
+#define RT5645_REG_IDX_MASK			(0xff)
+#define RT5645_REG_IDX_SFT			0
+
+/* Programmable Register Array Control 2 (0xc9) */
+#define RT5645_REG_DAT_MASK			(0xffff)
+#define RT5645_REG_DAT_SFT			0
+
+/* Programmable Register Array Control 3 (0xca) */
+#define RT5645_SEQ_DLY_MASK			(0xff << 8)
+#define RT5645_SEQ_DLY_SFT			8
+#define RT5645_PROG_MASK			(0x1 << 7)
+#define RT5645_PROG_SFT				7
+#define RT5645_PROG_DIS				(0x0 << 7)
+#define RT5645_PROG_EN				(0x1 << 7)
+#define RT5645_SEQ1_PT_RUN			(0x1 << 6)
+#define RT5645_SEQ1_PT_RUN_BIT			6
+#define RT5645_SEQ2_PT_RUN			(0x1 << 5)
+#define RT5645_SEQ2_PT_RUN_BIT			5
+
+/* Programmable Register Array Control 4 (0xcb) */
+#define RT5645_SEQ1_START_MASK			(0xf << 8)
+#define RT5645_SEQ1_START_SFT			8
+#define RT5645_SEQ1_END_MASK			(0xf)
+#define RT5645_SEQ1_END_SFT			0
+
+/* Programmable Register Array Control 5 (0xcc) */
+#define RT5645_SEQ2_START_MASK			(0xf << 8)
+#define RT5645_SEQ2_START_SFT			8
+#define RT5645_SEQ2_END_MASK			(0xf)
+#define RT5645_SEQ2_END_SFT			0
+
+/* Scramble Function (0xcd) */
+#define RT5645_SCB_KEY_MASK			(0xff)
+#define RT5645_SCB_KEY_SFT			0
+
+/* Scramble Control (0xce) */
+#define RT5645_SCB_SWAP_MASK			(0x1 << 15)
+#define RT5645_SCB_SWAP_SFT			15
+#define RT5645_SCB_SWAP_DIS			(0x0 << 15)
+#define RT5645_SCB_SWAP_EN			(0x1 << 15)
+#define RT5645_SCB_MASK				(0x1 << 14)
+#define RT5645_SCB_SFT				14
+#define RT5645_SCB_DIS				(0x0 << 14)
+#define RT5645_SCB_EN				(0x1 << 14)
+
+/* Baseback Control (0xcf) */
+#define RT5645_BB_MASK				(0x1 << 15)
+#define RT5645_BB_SFT				15
+#define RT5645_BB_DIS				(0x0 << 15)
+#define RT5645_BB_EN				(0x1 << 15)
+#define RT5645_BB_CT_MASK			(0x7 << 12)
+#define RT5645_BB_CT_SFT			12
+#define RT5645_BB_CT_A				(0x0 << 12)
+#define RT5645_BB_CT_B				(0x1 << 12)
+#define RT5645_BB_CT_C				(0x2 << 12)
+#define RT5645_BB_CT_D				(0x3 << 12)
+#define RT5645_M_BB_L_MASK			(0x1 << 9)
+#define RT5645_M_BB_L_SFT			9
+#define RT5645_M_BB_R_MASK			(0x1 << 8)
+#define RT5645_M_BB_R_SFT			8
+#define RT5645_M_BB_HPF_L_MASK			(0x1 << 7)
+#define RT5645_M_BB_HPF_L_SFT			7
+#define RT5645_M_BB_HPF_R_MASK			(0x1 << 6)
+#define RT5645_M_BB_HPF_R_SFT			6
+#define RT5645_G_BB_BST_MASK			(0x3f)
+#define RT5645_G_BB_BST_SFT			0
+#define RT5645_G_BB_BST_25DB			0x14
+
+/* MP3 Plus Control 1 (0xd0) */
+#define RT5645_M_MP3_L_MASK			(0x1 << 15)
+#define RT5645_M_MP3_L_SFT			15
+#define RT5645_M_MP3_R_MASK			(0x1 << 14)
+#define RT5645_M_MP3_R_SFT			14
+#define RT5645_M_MP3_MASK			(0x1 << 13)
+#define RT5645_M_MP3_SFT			13
+#define RT5645_M_MP3_DIS			(0x0 << 13)
+#define RT5645_M_MP3_EN				(0x1 << 13)
+#define RT5645_EG_MP3_MASK			(0x1f << 8)
+#define RT5645_EG_MP3_SFT			8
+#define RT5645_MP3_HLP_MASK			(0x1 << 7)
+#define RT5645_MP3_HLP_SFT			7
+#define RT5645_MP3_HLP_DIS			(0x0 << 7)
+#define RT5645_MP3_HLP_EN			(0x1 << 7)
+#define RT5645_M_MP3_ORG_L_MASK			(0x1 << 6)
+#define RT5645_M_MP3_ORG_L_SFT			6
+#define RT5645_M_MP3_ORG_R_MASK			(0x1 << 5)
+#define RT5645_M_MP3_ORG_R_SFT			5
+
+/* MP3 Plus Control 2 (0xd1) */
+#define RT5645_MP3_WT_MASK			(0x1 << 13)
+#define RT5645_MP3_WT_SFT			13
+#define RT5645_MP3_WT_1_4			(0x0 << 13)
+#define RT5645_MP3_WT_1_2			(0x1 << 13)
+#define RT5645_OG_MP3_MASK			(0x1f << 8)
+#define RT5645_OG_MP3_SFT			8
+#define RT5645_HG_MP3_MASK			(0x3f)
+#define RT5645_HG_MP3_SFT			0
+
+/* 3D HP Control 1 (0xd2) */
+#define RT5645_3D_CF_MASK			(0x1 << 15)
+#define RT5645_3D_CF_SFT			15
+#define RT5645_3D_CF_DIS			(0x0 << 15)
+#define RT5645_3D_CF_EN				(0x1 << 15)
+#define RT5645_3D_HP_MASK			(0x1 << 14)
+#define RT5645_3D_HP_SFT			14
+#define RT5645_3D_HP_DIS			(0x0 << 14)
+#define RT5645_3D_HP_EN				(0x1 << 14)
+#define RT5645_3D_BT_MASK			(0x1 << 13)
+#define RT5645_3D_BT_SFT			13
+#define RT5645_3D_BT_DIS			(0x0 << 13)
+#define RT5645_3D_BT_EN				(0x1 << 13)
+#define RT5645_3D_1F_MIX_MASK			(0x3 << 11)
+#define RT5645_3D_1F_MIX_SFT			11
+#define RT5645_3D_HP_M_MASK			(0x1 << 10)
+#define RT5645_3D_HP_M_SFT			10
+#define RT5645_3D_HP_M_SUR			(0x0 << 10)
+#define RT5645_3D_HP_M_FRO			(0x1 << 10)
+#define RT5645_M_3D_HRTF_MASK			(0x1 << 9)
+#define RT5645_M_3D_HRTF_SFT			9
+#define RT5645_M_3D_D2H_MASK			(0x1 << 8)
+#define RT5645_M_3D_D2H_SFT			8
+#define RT5645_M_3D_D2R_MASK			(0x1 << 7)
+#define RT5645_M_3D_D2R_SFT			7
+#define RT5645_M_3D_REVB_MASK			(0x1 << 6)
+#define RT5645_M_3D_REVB_SFT			6
+
+/* Adjustable high pass filter control 1 (0xd3) */
+#define RT5645_2ND_HPF_MASK			(0x1 << 15)
+#define RT5645_2ND_HPF_SFT			15
+#define RT5645_2ND_HPF_DIS			(0x0 << 15)
+#define RT5645_2ND_HPF_EN			(0x1 << 15)
+#define RT5645_HPF_CF_L_MASK			(0x7 << 12)
+#define RT5645_HPF_CF_L_SFT			12
+#define RT5645_1ST_HPF_MASK			(0x1 << 11)
+#define RT5645_1ST_HPF_SFT			11
+#define RT5645_1ST_HPF_DIS			(0x0 << 11)
+#define RT5645_1ST_HPF_EN			(0x1 << 11)
+#define RT5645_HPF_CF_R_MASK			(0x7 << 8)
+#define RT5645_HPF_CF_R_SFT			8
+#define RT5645_ZD_T_MASK			(0x3 << 6)
+#define RT5645_ZD_T_SFT				6
+#define RT5645_ZD_F_MASK			(0x3 << 4)
+#define RT5645_ZD_F_SFT				4
+#define RT5645_ZD_F_IM				(0x0 << 4)
+#define RT5645_ZD_F_ZC_IM			(0x1 << 4)
+#define RT5645_ZD_F_ZC_IOD			(0x2 << 4)
+#define RT5645_ZD_F_UN				(0x3 << 4)
+
+/* HP calibration control and Amp detection (0xd6) */
+#define RT5645_SI_DAC_MASK			(0x1 << 11)
+#define RT5645_SI_DAC_SFT			11
+#define RT5645_SI_DAC_AUTO			(0x0 << 11)
+#define RT5645_SI_DAC_TEST			(0x1 << 11)
+#define RT5645_DC_CAL_M_MASK			(0x1 << 10)
+#define RT5645_DC_CAL_M_SFT			10
+#define RT5645_DC_CAL_M_CAL			(0x0 << 10)
+#define RT5645_DC_CAL_M_NOR			(0x1 << 10)
+#define RT5645_DC_CAL_MASK			(0x1 << 9)
+#define RT5645_DC_CAL_SFT			9
+#define RT5645_DC_CAL_DIS			(0x0 << 9)
+#define RT5645_DC_CAL_EN			(0x1 << 9)
+#define RT5645_HPD_RCV_MASK			(0x7 << 6)
+#define RT5645_HPD_RCV_SFT			6
+#define RT5645_HPD_PS_MASK			(0x1 << 5)
+#define RT5645_HPD_PS_SFT			5
+#define RT5645_HPD_PS_DIS			(0x0 << 5)
+#define RT5645_HPD_PS_EN			(0x1 << 5)
+#define RT5645_CAL_M_MASK			(0x1 << 4)
+#define RT5645_CAL_M_SFT			4
+#define RT5645_CAL_M_DEP			(0x0 << 4)
+#define RT5645_CAL_M_CAL			(0x1 << 4)
+#define RT5645_CAL_MASK				(0x1 << 3)
+#define RT5645_CAL_SFT				3
+#define RT5645_CAL_DIS				(0x0 << 3)
+#define RT5645_CAL_EN				(0x1 << 3)
+#define RT5645_CAL_TEST_MASK			(0x1 << 2)
+#define RT5645_CAL_TEST_SFT			2
+#define RT5645_CAL_TEST_DIS			(0x0 << 2)
+#define RT5645_CAL_TEST_EN			(0x1 << 2)
+#define RT5645_CAL_P_MASK			(0x3)
+#define RT5645_CAL_P_SFT			0
+#define RT5645_CAL_P_NONE			(0x0)
+#define RT5645_CAL_P_CAL			(0x1)
+#define RT5645_CAL_P_DAC_CAL			(0x2)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5645_SV_MASK				(0x1 << 15)
+#define RT5645_SV_SFT				15
+#define RT5645_SV_DIS				(0x0 << 15)
+#define RT5645_SV_EN				(0x1 << 15)
+#define RT5645_SPO_SV_MASK			(0x1 << 14)
+#define RT5645_SPO_SV_SFT			14
+#define RT5645_SPO_SV_DIS			(0x0 << 14)
+#define RT5645_SPO_SV_EN			(0x1 << 14)
+#define RT5645_OUT_SV_MASK			(0x1 << 13)
+#define RT5645_OUT_SV_SFT			13
+#define RT5645_OUT_SV_DIS			(0x0 << 13)
+#define RT5645_OUT_SV_EN			(0x1 << 13)
+#define RT5645_HP_SV_MASK			(0x1 << 12)
+#define RT5645_HP_SV_SFT			12
+#define RT5645_HP_SV_DIS			(0x0 << 12)
+#define RT5645_HP_SV_EN				(0x1 << 12)
+#define RT5645_ZCD_DIG_MASK			(0x1 << 11)
+#define RT5645_ZCD_DIG_SFT			11
+#define RT5645_ZCD_DIG_DIS			(0x0 << 11)
+#define RT5645_ZCD_DIG_EN			(0x1 << 11)
+#define RT5645_ZCD_MASK				(0x1 << 10)
+#define RT5645_ZCD_SFT				10
+#define RT5645_ZCD_PD				(0x0 << 10)
+#define RT5645_ZCD_PU				(0x1 << 10)
+#define RT5645_M_ZCD_MASK			(0x3f << 4)
+#define RT5645_M_ZCD_SFT			4
+#define RT5645_M_ZCD_RM_L			(0x1 << 9)
+#define RT5645_M_ZCD_RM_R			(0x1 << 8)
+#define RT5645_M_ZCD_SM_L			(0x1 << 7)
+#define RT5645_M_ZCD_SM_R			(0x1 << 6)
+#define RT5645_M_ZCD_OM_L			(0x1 << 5)
+#define RT5645_M_ZCD_OM_R			(0x1 << 4)
+#define RT5645_SV_DLY_MASK			(0xf)
+#define RT5645_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5645_ZCD_HP_MASK			(0x1 << 15)
+#define RT5645_ZCD_HP_SFT			15
+#define RT5645_ZCD_HP_DIS			(0x0 << 15)
+#define RT5645_ZCD_HP_EN			(0x1 << 15)
+
+
+/* Codec Private Register definition */
+/* DAC ADC Digital Volume (0x00) */
+#define RT5645_DA1_ZDET_SFT			6
+
+/* 3D Speaker Control (0x63) */
+#define RT5645_3D_SPK_MASK			(0x1 << 15)
+#define RT5645_3D_SPK_SFT			15
+#define RT5645_3D_SPK_DIS			(0x0 << 15)
+#define RT5645_3D_SPK_EN			(0x1 << 15)
+#define RT5645_3D_SPK_M_MASK			(0x3 << 13)
+#define RT5645_3D_SPK_M_SFT			13
+#define RT5645_3D_SPK_CG_MASK			(0x1f << 8)
+#define RT5645_3D_SPK_CG_SFT			8
+#define RT5645_3D_SPK_SG_MASK			(0x1f)
+#define RT5645_3D_SPK_SG_SFT			0
+
+/* Wind Noise Detection Control 1 (0x6c) */
+#define RT5645_WND_MASK				(0x1 << 15)
+#define RT5645_WND_SFT				15
+#define RT5645_WND_DIS				(0x0 << 15)
+#define RT5645_WND_EN				(0x1 << 15)
+
+/* Wind Noise Detection Control 2 (0x6d) */
+#define RT5645_WND_FC_NW_MASK			(0x3f << 10)
+#define RT5645_WND_FC_NW_SFT			10
+#define RT5645_WND_FC_WK_MASK			(0x3f << 4)
+#define RT5645_WND_FC_WK_SFT			4
+
+/* Wind Noise Detection Control 3 (0x6e) */
+#define RT5645_HPF_FC_MASK			(0x3f << 6)
+#define RT5645_HPF_FC_SFT			6
+#define RT5645_WND_FC_ST_MASK			(0x3f)
+#define RT5645_WND_FC_ST_SFT			0
+
+/* Wind Noise Detection Control 4 (0x6f) */
+#define RT5645_WND_TH_LO_MASK			(0x3ff)
+#define RT5645_WND_TH_LO_SFT			0
+
+/* Wind Noise Detection Control 5 (0x70) */
+#define RT5645_WND_TH_HI_MASK			(0x3ff)
+#define RT5645_WND_TH_HI_SFT			0
+
+/* Wind Noise Detection Control 8 (0x73) */
+#define RT5645_WND_WIND_MASK			(0x1 << 13) /* Read-Only */
+#define RT5645_WND_WIND_SFT			13
+#define RT5645_WND_STRONG_MASK			(0x1 << 12) /* Read-Only */
+#define RT5645_WND_STRONG_SFT			12
+enum {
+	RT5645_NO_WIND,
+	RT5645_BREEZE,
+	RT5645_STORM,
+};
+
+/* Dipole Speaker Interface (0x75) */
+#define RT5645_DP_ATT_MASK			(0x3 << 14)
+#define RT5645_DP_ATT_SFT			14
+#define RT5645_DP_SPK_MASK			(0x1 << 10)
+#define RT5645_DP_SPK_SFT			10
+#define RT5645_DP_SPK_DIS			(0x0 << 10)
+#define RT5645_DP_SPK_EN			(0x1 << 10)
+
+/* EQ Pre Volume Control (0xb3) */
+#define RT5645_EQ_PRE_VOL_MASK			(0xffff)
+#define RT5645_EQ_PRE_VOL_SFT			0
+
+/* EQ Post Volume Control (0xb4) */
+#define RT5645_EQ_PST_VOL_MASK			(0xffff)
+#define RT5645_EQ_PST_VOL_SFT			0
+
+/* Jack Detect Control 3 (0xf8) */
+#define RT5645_CMP_MIC_IN_DET_MASK		(0x7 << 12)
+#define RT5645_JD_CBJ_EN			(0x1 << 7)
+#define RT5645_JD_CBJ_POL			(0x1 << 6)
+#define RT5645_JD_TRI_CBJ_SEL_MASK		(0x7 << 3)
+#define RT5645_JD_TRI_CBJ_SEL_SFT		(3)
+#define RT5645_JD_TRI_HPO_SEL_MASK		(0x7)
+#define RT5645_JD_TRI_HPO_SEL_SFT		(0)
+#define RT5645_JD_F_GPIO_JD1			(0x0)
+#define RT5645_JD_F_JD1_1			(0x1)
+#define RT5645_JD_F_JD1_2			(0x2)
+#define RT5645_JD_F_JD2				(0x3)
+#define RT5645_JD_F_JD3				(0x4)
+#define RT5645_JD_F_GPIO_JD2			(0x5)
+#define RT5645_JD_F_MX0B_12			(0x6)
+
+/* Digital Misc Control (0xfa) */
+#define RT5645_RST_DSP				(0x1 << 13)
+#define RT5645_IF1_ADC1_IN1_SEL			(0x1 << 12)
+#define RT5645_IF1_ADC1_IN1_SFT			12
+#define RT5645_IF1_ADC1_IN2_SEL			(0x1 << 11)
+#define RT5645_IF1_ADC1_IN2_SFT			11
+#define RT5645_IF1_ADC2_IN1_SEL			(0x1 << 10)
+#define RT5645_IF1_ADC2_IN1_SFT			10
+#define RT5645_DIG_GATE_CTRL			0x1
+
+/* General Control2 (0xfb) */
+#define RT5645_RXDC_SRC_MASK			(0x1 << 7)
+#define RT5645_RXDC_SRC_STO			(0x0 << 7)
+#define RT5645_RXDC_SRC_MONO			(0x1 << 7)
+#define RT5645_RXDC_SRC_SFT			(7)
+#define RT5645_MICBIAS1_POW_CTRL_SEL_MASK	(0x1 << 5)
+#define RT5645_MICBIAS1_POW_CTRL_SEL_A		(0x0 << 5)
+#define RT5645_MICBIAS1_POW_CTRL_SEL_M		(0x1 << 5)
+#define RT5645_MICBIAS2_POW_CTRL_SEL_MASK	(0x1 << 4)
+#define RT5645_MICBIAS2_POW_CTRL_SEL_A		(0x0 << 4)
+#define RT5645_MICBIAS2_POW_CTRL_SEL_M		(0x1 << 4)
+#define RT5645_RXDP2_SEL_MASK			(0x1 << 3)
+#define RT5645_RXDP2_SEL_IF2			(0x0 << 3)
+#define RT5645_RXDP2_SEL_ADC			(0x1 << 3)
+#define RT5645_RXDP2_SEL_SFT			(3)
+
+/* General Control3 (0xfc) */
+#define RT5645_JD_PSV_MODE			(0x1 << 12)
+#define RT5645_IRQ_CLK_GATE_CTRL		(0x1 << 11)
+#define RT5645_DET_CLK_MASK			(0x3 << 9)
+#define RT5645_DET_CLK_DIS			(0x0 << 9)
+#define RT5645_DET_CLK_MODE1			(0x1 << 9)
+#define RT5645_DET_CLK_MODE2			(0x2 << 9)
+#define RT5645_MICINDET_MANU			(0x1 << 7)
+#define RT5645_RING2_SLEEVE_GND			(0x1 << 5)
+
+/* Vendor ID (0xfd) */
+#define RT5645_VER_C				0x2
+#define RT5645_VER_D				0x3
+
+
+/* Volume Rescale */
+#define RT5645_VOL_RSCL_MAX 0x27
+#define RT5645_VOL_RSCL_RANGE 0x1F
+/* Debug String Length */
+#define RT5645_REG_DISP_LEN 23
+
+
+/* System Clock Source */
+enum {
+	RT5645_SCLK_S_MCLK,
+	RT5645_SCLK_S_PLL1,
+	RT5645_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+	RT5645_PLL1_S_MCLK,
+	RT5645_PLL1_S_BCLK1,
+	RT5645_PLL1_S_BCLK2,
+};
+
+enum {
+	RT5645_AIF1,
+	RT5645_AIF2,
+	RT5645_AIFS,
+};
+
+enum {
+	RT5645_DMIC1_DISABLE,
+	RT5645_DMIC_DATA_IN2P,
+	RT5645_DMIC_DATA_GPIO6,
+	RT5645_DMIC_DATA_GPIO10,
+	RT5645_DMIC_DATA_GPIO12,
+};
+
+enum {
+	RT5645_DMIC2_DISABLE,
+	RT5645_DMIC_DATA_IN2N,
+	RT5645_DMIC_DATA_GPIO5,
+	RT5645_DMIC_DATA_GPIO11,
+};
+
+enum {
+	CODEC_TYPE_RT5645,
+	CODEC_TYPE_RT5650,
+};
+
+/* filter mask */
+enum {
+	RT5645_DA_STEREO_FILTER = 0x1,
+	RT5645_DA_MONO_L_FILTER = (0x1 << 1),
+	RT5645_DA_MONO_R_FILTER = (0x1 << 2),
+	RT5645_AD_STEREO_FILTER = (0x1 << 3),
+	RT5645_AD_MONO_L_FILTER = (0x1 << 4),
+	RT5645_AD_MONO_R_FILTER = (0x1 << 5),
+};
+
+int rt5645_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src);
+
+int rt5645_set_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack,
+	struct snd_soc_jack *btn_jack);
+#endif /* __RT5645_H__ */
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
new file mode 100644
index 0000000..985852f
--- /dev/null
+++ b/sound/soc/codecs/rt5651.c
@@ -0,0 +1,2234 @@
+/*
+ * rt5651.c  --  RT5651 ALSA SoC audio codec driver
+ *
+ * Copyright 2014 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+
+#include "rl6231.h"
+#include "rt5651.h"
+
+#define RT5651_DEVICE_ID_VALUE 0x6281
+
+#define RT5651_PR_RANGE_BASE (0xff + 1)
+#define RT5651_PR_SPACING 0x100
+
+#define RT5651_PR_BASE (RT5651_PR_RANGE_BASE + (0 * RT5651_PR_SPACING))
+
+static const struct regmap_range_cfg rt5651_ranges[] = {
+	{ .name = "PR", .range_min = RT5651_PR_BASE,
+	  .range_max = RT5651_PR_BASE + 0xb4,
+	  .selector_reg = RT5651_PRIV_INDEX,
+	  .selector_mask = 0xff,
+	  .selector_shift = 0x0,
+	  .window_start = RT5651_PRIV_DATA,
+	  .window_len = 0x1, },
+};
+
+static const struct reg_sequence init_list[] = {
+	{RT5651_PR_BASE + 0x3d,	0x3e00},
+};
+
+static const struct reg_default rt5651_reg[] = {
+	{ 0x00, 0x0000 },
+	{ 0x02, 0xc8c8 },
+	{ 0x03, 0xc8c8 },
+	{ 0x05, 0x0000 },
+	{ 0x0d, 0x0000 },
+	{ 0x0e, 0x0000 },
+	{ 0x0f, 0x0808 },
+	{ 0x10, 0x0808 },
+	{ 0x19, 0xafaf },
+	{ 0x1a, 0xafaf },
+	{ 0x1b, 0x0c00 },
+	{ 0x1c, 0x2f2f },
+	{ 0x1d, 0x2f2f },
+	{ 0x1e, 0x0000 },
+	{ 0x27, 0x7860 },
+	{ 0x28, 0x7070 },
+	{ 0x29, 0x8080 },
+	{ 0x2a, 0x5252 },
+	{ 0x2b, 0x5454 },
+	{ 0x2f, 0x0000 },
+	{ 0x30, 0x5000 },
+	{ 0x3b, 0x0000 },
+	{ 0x3c, 0x006f },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x006f },
+	{ 0x45, 0x6000 },
+	{ 0x4d, 0x0000 },
+	{ 0x4e, 0x0000 },
+	{ 0x4f, 0x0279 },
+	{ 0x50, 0x0000 },
+	{ 0x51, 0x0000 },
+	{ 0x52, 0x0279 },
+	{ 0x53, 0xf000 },
+	{ 0x61, 0x0000 },
+	{ 0x62, 0x0000 },
+	{ 0x63, 0x00c0 },
+	{ 0x64, 0x0000 },
+	{ 0x65, 0x0000 },
+	{ 0x66, 0x0000 },
+	{ 0x70, 0x8000 },
+	{ 0x71, 0x8000 },
+	{ 0x73, 0x1104 },
+	{ 0x74, 0x0c00 },
+	{ 0x75, 0x1400 },
+	{ 0x77, 0x0c00 },
+	{ 0x78, 0x4000 },
+	{ 0x79, 0x0123 },
+	{ 0x80, 0x0000 },
+	{ 0x81, 0x0000 },
+	{ 0x82, 0x0000 },
+	{ 0x83, 0x0800 },
+	{ 0x84, 0x0000 },
+	{ 0x85, 0x0008 },
+	{ 0x89, 0x0000 },
+	{ 0x8e, 0x0004 },
+	{ 0x8f, 0x1100 },
+	{ 0x90, 0x0000 },
+	{ 0x93, 0x2000 },
+	{ 0x94, 0x0200 },
+	{ 0xb0, 0x2080 },
+	{ 0xb1, 0x0000 },
+	{ 0xb4, 0x2206 },
+	{ 0xb5, 0x1f00 },
+	{ 0xb6, 0x0000 },
+	{ 0xbb, 0x0000 },
+	{ 0xbc, 0x0000 },
+	{ 0xbd, 0x0000 },
+	{ 0xbe, 0x0000 },
+	{ 0xbf, 0x0000 },
+	{ 0xc0, 0x0400 },
+	{ 0xc1, 0x0000 },
+	{ 0xc2, 0x0000 },
+	{ 0xcf, 0x0013 },
+	{ 0xd0, 0x0680 },
+	{ 0xd1, 0x1c17 },
+	{ 0xd3, 0xb320 },
+	{ 0xd9, 0x0809 },
+	{ 0xfa, 0x0010 },
+	{ 0xfe, 0x10ec },
+	{ 0xff, 0x6281 },
+};
+
+static bool rt5651_volatile_register(struct device *dev,  unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5651_ranges); i++) {
+		if ((reg >= rt5651_ranges[i].window_start &&
+		     reg <= rt5651_ranges[i].window_start +
+		     rt5651_ranges[i].window_len) ||
+		    (reg >= rt5651_ranges[i].range_min &&
+		     reg <= rt5651_ranges[i].range_max)) {
+			return true;
+		}
+	}
+
+	switch (reg) {
+	case RT5651_RESET:
+	case RT5651_PRIV_DATA:
+	case RT5651_EQ_CTRL1:
+	case RT5651_ALC_1:
+	case RT5651_IRQ_CTRL2:
+	case RT5651_INT_IRQ_ST:
+	case RT5651_PGM_REG_ARR1:
+	case RT5651_PGM_REG_ARR3:
+	case RT5651_VENDOR_ID:
+	case RT5651_DEVICE_ID:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5651_readable_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5651_ranges); i++) {
+		if ((reg >= rt5651_ranges[i].window_start &&
+		     reg <= rt5651_ranges[i].window_start +
+		     rt5651_ranges[i].window_len) ||
+		    (reg >= rt5651_ranges[i].range_min &&
+		     reg <= rt5651_ranges[i].range_max)) {
+			return true;
+		}
+	}
+
+	switch (reg) {
+	case RT5651_RESET:
+	case RT5651_VERSION_ID:
+	case RT5651_VENDOR_ID:
+	case RT5651_DEVICE_ID:
+	case RT5651_HP_VOL:
+	case RT5651_LOUT_CTRL1:
+	case RT5651_LOUT_CTRL2:
+	case RT5651_IN1_IN2:
+	case RT5651_IN3:
+	case RT5651_INL1_INR1_VOL:
+	case RT5651_INL2_INR2_VOL:
+	case RT5651_DAC1_DIG_VOL:
+	case RT5651_DAC2_DIG_VOL:
+	case RT5651_DAC2_CTRL:
+	case RT5651_ADC_DIG_VOL:
+	case RT5651_ADC_DATA:
+	case RT5651_ADC_BST_VOL:
+	case RT5651_STO1_ADC_MIXER:
+	case RT5651_STO2_ADC_MIXER:
+	case RT5651_AD_DA_MIXER:
+	case RT5651_STO_DAC_MIXER:
+	case RT5651_DD_MIXER:
+	case RT5651_DIG_INF_DATA:
+	case RT5651_PDM_CTL:
+	case RT5651_REC_L1_MIXER:
+	case RT5651_REC_L2_MIXER:
+	case RT5651_REC_R1_MIXER:
+	case RT5651_REC_R2_MIXER:
+	case RT5651_HPO_MIXER:
+	case RT5651_OUT_L1_MIXER:
+	case RT5651_OUT_L2_MIXER:
+	case RT5651_OUT_L3_MIXER:
+	case RT5651_OUT_R1_MIXER:
+	case RT5651_OUT_R2_MIXER:
+	case RT5651_OUT_R3_MIXER:
+	case RT5651_LOUT_MIXER:
+	case RT5651_PWR_DIG1:
+	case RT5651_PWR_DIG2:
+	case RT5651_PWR_ANLG1:
+	case RT5651_PWR_ANLG2:
+	case RT5651_PWR_MIXER:
+	case RT5651_PWR_VOL:
+	case RT5651_PRIV_INDEX:
+	case RT5651_PRIV_DATA:
+	case RT5651_I2S1_SDP:
+	case RT5651_I2S2_SDP:
+	case RT5651_ADDA_CLK1:
+	case RT5651_ADDA_CLK2:
+	case RT5651_DMIC:
+	case RT5651_TDM_CTL_1:
+	case RT5651_TDM_CTL_2:
+	case RT5651_TDM_CTL_3:
+	case RT5651_GLB_CLK:
+	case RT5651_PLL_CTRL1:
+	case RT5651_PLL_CTRL2:
+	case RT5651_PLL_MODE_1:
+	case RT5651_PLL_MODE_2:
+	case RT5651_PLL_MODE_3:
+	case RT5651_PLL_MODE_4:
+	case RT5651_PLL_MODE_5:
+	case RT5651_PLL_MODE_6:
+	case RT5651_PLL_MODE_7:
+	case RT5651_DEPOP_M1:
+	case RT5651_DEPOP_M2:
+	case RT5651_DEPOP_M3:
+	case RT5651_CHARGE_PUMP:
+	case RT5651_MICBIAS:
+	case RT5651_A_JD_CTL1:
+	case RT5651_EQ_CTRL1:
+	case RT5651_EQ_CTRL2:
+	case RT5651_ALC_1:
+	case RT5651_ALC_2:
+	case RT5651_ALC_3:
+	case RT5651_JD_CTRL1:
+	case RT5651_JD_CTRL2:
+	case RT5651_IRQ_CTRL1:
+	case RT5651_IRQ_CTRL2:
+	case RT5651_INT_IRQ_ST:
+	case RT5651_GPIO_CTRL1:
+	case RT5651_GPIO_CTRL2:
+	case RT5651_GPIO_CTRL3:
+	case RT5651_PGM_REG_ARR1:
+	case RT5651_PGM_REG_ARR2:
+	case RT5651_PGM_REG_ARR3:
+	case RT5651_PGM_REG_ARR4:
+	case RT5651_PGM_REG_ARR5:
+	case RT5651_SCB_FUNC:
+	case RT5651_SCB_CTRL:
+	case RT5651_BASE_BACK:
+	case RT5651_MP3_PLUS1:
+	case RT5651_MP3_PLUS2:
+	case RT5651_ADJ_HPF_CTRL1:
+	case RT5651_ADJ_HPF_CTRL2:
+	case RT5651_HP_CALIB_AMP_DET:
+	case RT5651_HP_CALIB2:
+	case RT5651_SV_ZCD1:
+	case RT5651_SV_ZCD2:
+	case RT5651_D_MISC:
+	case RT5651_DUMMY2:
+	case RT5651_DUMMY3:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+/* Interface data select */
+static const char * const rt5651_data_select[] = {
+	"Normal", "Swap", "left copy to right", "right copy to left"};
+
+static SOC_ENUM_SINGLE_DECL(rt5651_if2_dac_enum, RT5651_DIG_INF_DATA,
+				RT5651_IF2_DAC_SEL_SFT, rt5651_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5651_if2_adc_enum, RT5651_DIG_INF_DATA,
+				RT5651_IF2_ADC_SEL_SFT, rt5651_data_select);
+
+static const struct snd_kcontrol_new rt5651_snd_controls[] = {
+	/* Headphone Output Volume */
+	SOC_DOUBLE_TLV("HP Playback Volume", RT5651_HP_VOL,
+		RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv),
+	/* OUTPUT Control */
+	SOC_DOUBLE_TLV("OUT Playback Volume", RT5651_LOUT_CTRL1,
+		RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE("DAC2 Playback Switch", RT5651_DAC2_CTRL,
+		RT5651_M_DAC_L2_VOL_SFT, RT5651_M_DAC_R2_VOL_SFT, 1, 1),
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5651_DAC1_DIG_VOL,
+			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
+			175, 0, dac_vol_tlv),
+	SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5651_DAC2_DIG_VOL,
+			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
+			175, 0, dac_vol_tlv),
+	/* IN1/IN2/IN3 Control */
+	SOC_SINGLE_TLV("IN1 Boost", RT5651_IN1_IN2,
+		RT5651_BST_SFT1, 8, 0, bst_tlv),
+	SOC_SINGLE_TLV("IN2 Boost", RT5651_IN1_IN2,
+		RT5651_BST_SFT2, 8, 0, bst_tlv),
+	SOC_SINGLE_TLV("IN3 Boost", RT5651_IN3,
+		RT5651_BST_SFT1, 8, 0, bst_tlv),
+	/* INL/INR Volume Control */
+	SOC_DOUBLE_TLV("IN Capture Volume", RT5651_INL1_INR1_VOL,
+			RT5651_INL_VOL_SFT, RT5651_INR_VOL_SFT,
+			31, 1, in_vol_tlv),
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("ADC Capture Switch", RT5651_ADC_DIG_VOL,
+		RT5651_L_MUTE_SFT, RT5651_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("ADC Capture Volume", RT5651_ADC_DIG_VOL,
+			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
+			127, 0, adc_vol_tlv),
+	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5651_ADC_DATA,
+			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
+			127, 0, adc_vol_tlv),
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("ADC Boost Gain", RT5651_ADC_BST_VOL,
+			RT5651_ADC_L_BST_SFT, RT5651_ADC_R_BST_SFT,
+			3, 0, adc_bst_tlv),
+
+	/* ASRC */
+	SOC_SINGLE("IF1 ASRC Switch", RT5651_PLL_MODE_1,
+		RT5651_STO1_T_SFT, 1, 0),
+	SOC_SINGLE("IF2 ASRC Switch", RT5651_PLL_MODE_1,
+		RT5651_STO2_T_SFT, 1, 0),
+	SOC_SINGLE("DMIC ASRC Switch", RT5651_PLL_MODE_1,
+		RT5651_DMIC_1_M_SFT, 1, 0),
+
+	SOC_ENUM("ADC IF2 Data Switch", rt5651_if2_adc_enum),
+	SOC_ENUM("DAC IF2 Data Switch", rt5651_if2_dac_enum),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+	int idx, rate;
+
+	rate = rt5651->sysclk / rl6231_get_pre_div(rt5651->regmap,
+		RT5651_ADDA_CLK1, RT5651_I2S_PD1_SFT);
+	idx = rl6231_calc_dmic_clk(rate);
+	if (idx < 0)
+		dev_err(component->dev, "Failed to set DMIC clock\n");
+	else
+		snd_soc_component_update_bits(component, RT5651_DMIC, RT5651_DMIC_CLK_MASK,
+					idx << RT5651_DMIC_CLK_SFT);
+
+	return idx;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5651_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO1_ADC_MIXER,
+			RT5651_M_STO1_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO1_ADC_MIXER,
+			RT5651_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO1_ADC_MIXER,
+			RT5651_M_STO1_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO1_ADC_MIXER,
+			RT5651_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO2_ADC_MIXER,
+			RT5651_M_STO2_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO2_ADC_MIXER,
+			RT5651_M_STO2_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO2_ADC_MIXER,
+			RT5651_M_STO2_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO2_ADC_MIXER,
+			RT5651_M_STO2_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5651_AD_DA_MIXER,
+			RT5651_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INF1 Switch", RT5651_AD_DA_MIXER,
+			RT5651_M_IF1_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5651_AD_DA_MIXER,
+			RT5651_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INF1 Switch", RT5651_AD_DA_MIXER,
+			RT5651_M_IF1_DAC_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_STO_DAC_MIXER,
+			RT5651_M_DAC_L1_MIXL_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_STO_DAC_MIXER,
+			RT5651_M_DAC_L2_MIXL_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_STO_DAC_MIXER,
+			RT5651_M_DAC_R1_MIXL_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_sto_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_STO_DAC_MIXER,
+			RT5651_M_DAC_R1_MIXR_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_STO_DAC_MIXER,
+			RT5651_M_DAC_R2_MIXR_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_STO_DAC_MIXER,
+			RT5651_M_DAC_L1_MIXR_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_dd_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_DD_MIXER,
+			RT5651_M_STO_DD_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_DD_MIXER,
+			RT5651_M_STO_DD_L2_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_DD_MIXER,
+			RT5651_M_STO_DD_R2_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_dd_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_DD_MIXER,
+			RT5651_M_STO_DD_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_DD_MIXER,
+			RT5651_M_STO_DD_R2_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_DD_MIXER,
+			RT5651_M_STO_DD_L2_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5651_rec_l_mix[] = {
+	SOC_DAPM_SINGLE("INL1 Switch", RT5651_REC_L2_MIXER,
+			RT5651_M_IN1_L_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5651_REC_L2_MIXER,
+			RT5651_M_BST3_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5651_REC_L2_MIXER,
+			RT5651_M_BST2_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5651_REC_L2_MIXER,
+			RT5651_M_BST1_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_rec_r_mix[] = {
+	SOC_DAPM_SINGLE("INR1 Switch", RT5651_REC_R2_MIXER,
+			RT5651_M_IN1_R_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5651_REC_R2_MIXER,
+			RT5651_M_BST3_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5651_REC_R2_MIXER,
+			RT5651_M_BST2_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5651_REC_R2_MIXER,
+			RT5651_M_BST1_RM_R_SFT, 1, 1),
+};
+
+/* Analog Output Mixer */
+
+static const struct snd_kcontrol_new rt5651_out_l_mix[] = {
+	SOC_DAPM_SINGLE("BST1 Switch", RT5651_OUT_L3_MIXER,
+			RT5651_M_BST1_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5651_OUT_L3_MIXER,
+			RT5651_M_BST2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL1 Switch", RT5651_OUT_L3_MIXER,
+			RT5651_M_IN1_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("REC MIXL Switch", RT5651_OUT_L3_MIXER,
+			RT5651_M_RM_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_OUT_L3_MIXER,
+			RT5651_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_out_r_mix[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5651_OUT_R3_MIXER,
+			RT5651_M_BST2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5651_OUT_R3_MIXER,
+			RT5651_M_BST1_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR1 Switch", RT5651_OUT_R3_MIXER,
+			RT5651_M_IN1_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("REC MIXR Switch", RT5651_OUT_R3_MIXER,
+			RT5651_M_RM_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_OUT_R3_MIXER,
+			RT5651_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_hpo_mix[] = {
+	SOC_DAPM_SINGLE("HPO MIX DAC1 Switch", RT5651_HPO_MIXER,
+			RT5651_M_DAC1_HM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("HPO MIX HPVOL Switch", RT5651_HPO_MIXER,
+			RT5651_M_HPVOL_HM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5651_lout_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_LOUT_MIXER,
+			RT5651_M_DAC_L1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5651_LOUT_MIXER,
+			RT5651_M_DAC_R1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL L Switch", RT5651_LOUT_MIXER,
+			RT5651_M_OV_L_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL R Switch", RT5651_LOUT_MIXER,
+			RT5651_M_OV_R_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new outvol_l_control =
+	SOC_DAPM_SINGLE("Switch", RT5651_LOUT_CTRL1,
+			RT5651_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_r_control =
+	SOC_DAPM_SINGLE("Switch", RT5651_LOUT_CTRL1,
+			RT5651_VOL_R_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_l_mute_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_LOUT_CTRL1,
+				    RT5651_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_r_mute_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_LOUT_CTRL1,
+				    RT5651_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpovol_l_control =
+	SOC_DAPM_SINGLE("Switch", RT5651_HP_VOL,
+			RT5651_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpovol_r_control =
+	SOC_DAPM_SINGLE("Switch", RT5651_HP_VOL,
+			RT5651_VOL_R_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_l_mute_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_HP_VOL,
+				    RT5651_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_r_mute_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5651_HP_VOL,
+				    RT5651_R_MUTE_SFT, 1, 1);
+
+/* Stereo ADC source */
+static const char * const rt5651_stereo1_adc1_src[] = {"DD MIX", "ADC"};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5651_stereo1_adc1_enum, RT5651_STO1_ADC_MIXER,
+	RT5651_STO1_ADC_1_SRC_SFT, rt5651_stereo1_adc1_src);
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_l1_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC L1 source", rt5651_stereo1_adc1_enum);
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_r1_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC R1 source", rt5651_stereo1_adc1_enum);
+
+static const char * const rt5651_stereo1_adc2_src[] = {"DMIC", "DD MIX"};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5651_stereo1_adc2_enum, RT5651_STO1_ADC_MIXER,
+	RT5651_STO1_ADC_2_SRC_SFT, rt5651_stereo1_adc2_src);
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_l2_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC L2 source", rt5651_stereo1_adc2_enum);
+
+static const struct snd_kcontrol_new rt5651_sto1_adc_r2_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC R2 source", rt5651_stereo1_adc2_enum);
+
+/* Mono ADC source */
+static const char * const rt5651_sto2_adc_l1_src[] = {"DD MIXL", "ADCL"};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5651_sto2_adc_l1_enum, RT5651_STO1_ADC_MIXER,
+	RT5651_STO2_ADC_L1_SRC_SFT, rt5651_sto2_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_l1_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC1 left source", rt5651_sto2_adc_l1_enum);
+
+static const char * const rt5651_sto2_adc_l2_src[] = {"DMIC L", "DD MIXL"};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5651_sto2_adc_l2_enum, RT5651_STO1_ADC_MIXER,
+	RT5651_STO2_ADC_L2_SRC_SFT, rt5651_sto2_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_l2_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC2 left source", rt5651_sto2_adc_l2_enum);
+
+static const char * const rt5651_sto2_adc_r1_src[] = {"DD MIXR", "ADCR"};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5651_sto2_adc_r1_enum, RT5651_STO1_ADC_MIXER,
+	RT5651_STO2_ADC_R1_SRC_SFT, rt5651_sto2_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_r1_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC1 right source", rt5651_sto2_adc_r1_enum);
+
+static const char * const rt5651_sto2_adc_r2_src[] = {"DMIC R", "DD MIXR"};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5651_sto2_adc_r2_enum, RT5651_STO1_ADC_MIXER,
+	RT5651_STO2_ADC_R2_SRC_SFT, rt5651_sto2_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5651_sto2_adc_r2_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC2 right source", rt5651_sto2_adc_r2_enum);
+
+/* DAC2 channel source */
+
+static const char * const rt5651_dac_src[] = {"IF1", "IF2"};
+
+static SOC_ENUM_SINGLE_DECL(rt5651_dac_l2_enum, RT5651_DAC2_CTRL,
+				RT5651_SEL_DAC_L2_SFT, rt5651_dac_src);
+
+static const struct snd_kcontrol_new rt5651_dac_l2_mux =
+	SOC_DAPM_ENUM("DAC2 left channel source", rt5651_dac_l2_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5651_dac_r2_enum, RT5651_DAC2_CTRL,
+	RT5651_SEL_DAC_R2_SFT, rt5651_dac_src);
+
+static const struct snd_kcontrol_new rt5651_dac_r2_mux =
+	SOC_DAPM_ENUM("DAC2 right channel source", rt5651_dac_r2_enum);
+
+/* IF2_ADC channel source */
+
+static const char * const rt5651_adc_src[] = {"IF1 ADC1", "IF1 ADC2"};
+
+static SOC_ENUM_SINGLE_DECL(rt5651_if2_adc_src_enum, RT5651_DIG_INF_DATA,
+				RT5651_IF2_ADC_SRC_SFT, rt5651_adc_src);
+
+static const struct snd_kcontrol_new rt5651_if2_adc_src_mux =
+	SOC_DAPM_ENUM("IF2 ADC channel source", rt5651_if2_adc_src_enum);
+
+/* PDM select */
+static const char * const rt5651_pdm_sel[] = {"DD MIX", "Stereo DAC MIX"};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5651_pdm_l_sel_enum, RT5651_PDM_CTL,
+	RT5651_PDM_L_SEL_SFT, rt5651_pdm_sel);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5651_pdm_r_sel_enum, RT5651_PDM_CTL,
+	RT5651_PDM_R_SEL_SFT, rt5651_pdm_sel);
+
+static const struct snd_kcontrol_new rt5651_pdm_l_mux =
+	SOC_DAPM_ENUM("PDM L select", rt5651_pdm_l_sel_enum);
+
+static const struct snd_kcontrol_new rt5651_pdm_r_mux =
+	SOC_DAPM_ENUM("PDM R select", rt5651_pdm_r_sel_enum);
+
+static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* depop parameters */
+		regmap_update_bits(rt5651->regmap, RT5651_PR_BASE +
+			RT5651_CHPUMP_INT_REG1, 0x0700, 0x0200);
+		regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M2,
+			RT5651_DEPOP_MASK, RT5651_DEPOP_MAN);
+		regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M1,
+			RT5651_HP_CP_MASK | RT5651_HP_SG_MASK |
+			RT5651_HP_CB_MASK, RT5651_HP_CP_PU |
+			RT5651_HP_SG_DIS | RT5651_HP_CB_PU);
+		regmap_write(rt5651->regmap, RT5651_PR_BASE +
+				RT5651_HP_DCC_INT1, 0x9f00);
+		/* headphone amp power on */
+		regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1,
+			RT5651_PWR_FV1 | RT5651_PWR_FV2, 0);
+		regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1,
+			RT5651_PWR_HA,
+			RT5651_PWR_HA);
+		usleep_range(10000, 15000);
+		regmap_update_bits(rt5651->regmap, RT5651_PWR_ANLG1,
+			RT5651_PWR_FV1 | RT5651_PWR_FV2 ,
+			RT5651_PWR_FV1 | RT5651_PWR_FV2);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5651_hp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* headphone unmute sequence */
+		regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M2,
+			RT5651_DEPOP_MASK | RT5651_DIG_DP_MASK,
+			RT5651_DEPOP_AUTO | RT5651_DIG_DP_EN);
+		regmap_update_bits(rt5651->regmap, RT5651_CHARGE_PUMP,
+			RT5651_PM_HP_MASK, RT5651_PM_HP_HV);
+
+		regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M3,
+			RT5651_CP_FQ1_MASK | RT5651_CP_FQ2_MASK |
+			RT5651_CP_FQ3_MASK,
+			(RT5651_CP_FQ_192_KHZ << RT5651_CP_FQ1_SFT) |
+			(RT5651_CP_FQ_12_KHZ << RT5651_CP_FQ2_SFT) |
+			(RT5651_CP_FQ_192_KHZ << RT5651_CP_FQ3_SFT));
+
+		regmap_write(rt5651->regmap, RT5651_PR_BASE +
+			RT5651_MAMP_INT_REG2, 0x1c00);
+		regmap_update_bits(rt5651->regmap, RT5651_DEPOP_M1,
+			RT5651_HP_CP_MASK | RT5651_HP_SG_MASK,
+			RT5651_HP_CP_PD | RT5651_HP_SG_EN);
+		regmap_update_bits(rt5651->regmap, RT5651_PR_BASE +
+			RT5651_CHPUMP_INT_REG1, 0x0700, 0x0400);
+		rt5651->hp_mute = 0;
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		rt5651->hp_mute = 1;
+		usleep_range(70000, 75000);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (!rt5651->hp_mute)
+			usleep_range(80000, 85000);
+
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5651_bst1_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
+			RT5651_PWR_BST1_OP2, RT5651_PWR_BST1_OP2);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
+			RT5651_PWR_BST1_OP2, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5651_bst2_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
+			RT5651_PWR_BST2_OP2, RT5651_PWR_BST2_OP2);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
+			RT5651_PWR_BST2_OP2, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5651_bst3_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
+			RT5651_PWR_BST3_OP2, RT5651_PWR_BST3_OP2);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
+			RT5651_PWR_BST3_OP2, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = {
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5651_PLL_MODE_2,
+			      15, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5651_PLL_MODE_2,
+			      14, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("STO1 DAC ASRC", 1, RT5651_PLL_MODE_2,
+			      13, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("STO2 DAC ASRC", 1, RT5651_PLL_MODE_2,
+			      12, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC ASRC", 1, RT5651_PLL_MODE_2,
+			      11, 0, NULL, 0),
+
+	/* micbias */
+	SND_SOC_DAPM_SUPPLY("LDO", RT5651_PWR_ANLG1,
+			RT5651_PWR_LDO_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("micbias1", RT5651_PWR_ANLG2,
+			RT5651_PWR_MB1_BIT, 0, NULL, 0),
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("MIC3"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN2N"),
+	SND_SOC_DAPM_INPUT("IN3P"),
+	SND_SOC_DAPM_INPUT("DMIC L1"),
+	SND_SOC_DAPM_INPUT("DMIC R1"),
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", RT5651_DMIC, RT5651_DMIC_1_EN_SFT,
+			    0, set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+	/* Boost */
+	SND_SOC_DAPM_PGA_E("BST1", RT5651_PWR_ANLG2,
+		RT5651_PWR_BST1_BIT, 0, NULL, 0, rt5651_bst1_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_E("BST2", RT5651_PWR_ANLG2,
+		RT5651_PWR_BST2_BIT, 0, NULL, 0, rt5651_bst2_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_E("BST3", RT5651_PWR_ANLG2,
+		RT5651_PWR_BST3_BIT, 0, NULL, 0, rt5651_bst3_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	/* Input Volume */
+	SND_SOC_DAPM_PGA("INL1 VOL", RT5651_PWR_VOL,
+			 RT5651_PWR_IN1_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR1 VOL", RT5651_PWR_VOL,
+			 RT5651_PWR_IN1_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INL2 VOL", RT5651_PWR_VOL,
+			 RT5651_PWR_IN2_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR2 VOL", RT5651_PWR_VOL,
+			 RT5651_PWR_IN2_R_BIT, 0, NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIXL", RT5651_PWR_MIXER, RT5651_PWR_RM_L_BIT, 0,
+			   rt5651_rec_l_mix, ARRAY_SIZE(rt5651_rec_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIXR", RT5651_PWR_MIXER, RT5651_PWR_RM_R_BIT, 0,
+			   rt5651_rec_r_mix, ARRAY_SIZE(rt5651_rec_r_mix)),
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_SUPPLY("ADC L Power", RT5651_PWR_DIG1,
+			    RT5651_PWR_ADC_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC R Power", RT5651_PWR_DIG1,
+			    RT5651_PWR_ADC_R_BIT, 0, NULL, 0),
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5651_sto1_adc_l2_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5651_sto1_adc_r2_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5651_sto1_adc_l1_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5651_sto1_adc_r1_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5651_sto2_adc_l2_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5651_sto2_adc_l1_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5651_sto2_adc_r1_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5651_sto2_adc_r2_mux),
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("Stereo1 Filter", RT5651_PWR_DIG2,
+			    RT5651_PWR_ADC_STO1_F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Stereo2 Filter", RT5651_PWR_DIG2,
+			    RT5651_PWR_ADC_STO2_F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+			   rt5651_sto1_adc_l_mix,
+			   ARRAY_SIZE(rt5651_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+			   rt5651_sto1_adc_r_mix,
+			   ARRAY_SIZE(rt5651_sto1_adc_r_mix)),
+	SND_SOC_DAPM_MIXER("Stereo2 ADC MIXL", SND_SOC_NOPM, 0, 0,
+			   rt5651_sto2_adc_l_mix,
+			   ARRAY_SIZE(rt5651_sto2_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo2 ADC MIXR", SND_SOC_NOPM, 0, 0,
+			   rt5651_sto2_adc_r_mix,
+			   ARRAY_SIZE(rt5651_sto2_adc_r_mix)),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5651_PWR_DIG1,
+			    RT5651_PWR_I2S1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("I2S2", RT5651_PWR_DIG1,
+			    RT5651_PWR_I2S2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("IF2 ADC", SND_SOC_NOPM, 0, 0,
+			 &rt5651_if2_adc_src_mux),
+
+	/* Digital Interface Select */
+
+	SND_SOC_DAPM_MUX("PDM L Mux", RT5651_PDM_CTL,
+			 RT5651_M_PDM_L_SFT, 1, &rt5651_pdm_l_mux),
+	SND_SOC_DAPM_MUX("PDM R Mux", RT5651_PDM_CTL,
+			 RT5651_M_PDM_R_SFT, 1, &rt5651_pdm_r_mux),
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Audio DSP */
+	SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Output Side */
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
+			   rt5651_dac_l_mix, ARRAY_SIZE(rt5651_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
+			   rt5651_dac_r_mix, ARRAY_SIZE(rt5651_dac_r_mix)),
+
+	/* DAC2 channel Mux */
+	SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_dac_l2_mux),
+	SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5651_dac_r2_mux),
+	SND_SOC_DAPM_PGA("DAC L2 Volume", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DAC R2 Volume", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Stero1 DAC Power", RT5651_PWR_DIG2,
+			    RT5651_PWR_DAC_STO1_F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Stero2 DAC Power", RT5651_PWR_DIG2,
+			    RT5651_PWR_DAC_STO2_F_BIT, 0, NULL, 0),
+	/* DAC Mixer */
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+			   rt5651_sto_dac_l_mix,
+			   ARRAY_SIZE(rt5651_sto_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+			   rt5651_sto_dac_r_mix,
+			   ARRAY_SIZE(rt5651_sto_dac_r_mix)),
+	SND_SOC_DAPM_MIXER("DD MIXL", SND_SOC_NOPM, 0, 0,
+			   rt5651_dd_dac_l_mix,
+			   ARRAY_SIZE(rt5651_dd_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DD MIXR", SND_SOC_NOPM, 0, 0,
+			   rt5651_dd_dac_r_mix,
+			   ARRAY_SIZE(rt5651_dd_dac_r_mix)),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_SUPPLY("DAC L1 Power", RT5651_PWR_DIG1,
+			    RT5651_PWR_DAC_L1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC R1 Power", RT5651_PWR_DIG1,
+			    RT5651_PWR_DAC_R1_BIT, 0, NULL, 0),
+	/* OUT Mixer */
+	SND_SOC_DAPM_MIXER("OUT MIXL", RT5651_PWR_MIXER, RT5651_PWR_OM_L_BIT,
+			   0, rt5651_out_l_mix, ARRAY_SIZE(rt5651_out_l_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXR", RT5651_PWR_MIXER, RT5651_PWR_OM_R_BIT,
+			   0, rt5651_out_r_mix, ARRAY_SIZE(rt5651_out_r_mix)),
+	/* Ouput Volume */
+	SND_SOC_DAPM_SWITCH("OUTVOL L", RT5651_PWR_VOL,
+			    RT5651_PWR_OV_L_BIT, 0, &outvol_l_control),
+	SND_SOC_DAPM_SWITCH("OUTVOL R", RT5651_PWR_VOL,
+			    RT5651_PWR_OV_R_BIT, 0, &outvol_r_control),
+	SND_SOC_DAPM_SWITCH("HPOVOL L", RT5651_PWR_VOL,
+			    RT5651_PWR_HV_L_BIT, 0, &hpovol_l_control),
+	SND_SOC_DAPM_SWITCH("HPOVOL R", RT5651_PWR_VOL,
+			    RT5651_PWR_HV_R_BIT, 0, &hpovol_r_control),
+	SND_SOC_DAPM_PGA("INL1", RT5651_PWR_VOL,
+			 RT5651_PWR_IN1_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR1", RT5651_PWR_VOL,
+			 RT5651_PWR_IN1_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INL2", RT5651_PWR_VOL,
+			 RT5651_PWR_IN2_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR2", RT5651_PWR_VOL,
+			 RT5651_PWR_IN2_R_BIT, 0, NULL, 0),
+	/* HPO/LOUT/Mono Mixer */
+	SND_SOC_DAPM_MIXER("HPOL MIX", SND_SOC_NOPM, 0, 0,
+			   rt5651_hpo_mix, ARRAY_SIZE(rt5651_hpo_mix)),
+	SND_SOC_DAPM_MIXER("HPOR MIX", SND_SOC_NOPM, 0, 0,
+			   rt5651_hpo_mix, ARRAY_SIZE(rt5651_hpo_mix)),
+	SND_SOC_DAPM_SUPPLY("HP L Amp", RT5651_PWR_ANLG1,
+			    RT5651_PWR_HP_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HP R Amp", RT5651_PWR_ANLG1,
+			    RT5651_PWR_HP_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("LOUT MIX", RT5651_PWR_ANLG1, RT5651_PWR_LM_BIT, 0,
+			   rt5651_lout_mix, ARRAY_SIZE(rt5651_lout_mix)),
+
+	SND_SOC_DAPM_SUPPLY("Amp Power", RT5651_PWR_ANLG1,
+			    RT5651_PWR_HA_BIT, 0, rt5651_amp_power_event,
+			    SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5651_hp_event,
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SWITCH("HPO L Playback", SND_SOC_NOPM, 0, 0,
+			    &hpo_l_mute_control),
+	SND_SOC_DAPM_SWITCH("HPO R Playback", SND_SOC_NOPM, 0, 0,
+			    &hpo_r_mute_control),
+	SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0,
+			    &lout_l_mute_control),
+	SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0,
+			    &lout_r_mute_control),
+	SND_SOC_DAPM_POST("HP Post", rt5651_hp_post_event),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+	SND_SOC_DAPM_OUTPUT("LOUTL"),
+	SND_SOC_DAPM_OUTPUT("LOUTR"),
+	SND_SOC_DAPM_OUTPUT("PDML"),
+	SND_SOC_DAPM_OUTPUT("PDMR"),
+};
+
+static const struct snd_soc_dapm_route rt5651_dapm_routes[] = {
+	{"Stero1 DAC Power", NULL, "STO1 DAC ASRC"},
+	{"Stero2 DAC Power", NULL, "STO2 DAC ASRC"},
+	{"I2S1", NULL, "I2S1 ASRC"},
+	{"I2S2", NULL, "I2S2 ASRC"},
+
+	{"IN1P", NULL, "LDO"},
+	{"IN2P", NULL, "LDO"},
+	{"IN3P", NULL, "LDO"},
+
+	{"IN1P", NULL, "MIC1"},
+	{"IN2P", NULL, "MIC2"},
+	{"IN2N", NULL, "MIC2"},
+	{"IN3P", NULL, "MIC3"},
+
+	{"BST1", NULL, "IN1P"},
+	{"BST2", NULL, "IN2P"},
+	{"BST2", NULL, "IN2N"},
+	{"BST3", NULL, "IN3P"},
+
+	{"INL1 VOL", NULL, "IN2P"},
+	{"INR1 VOL", NULL, "IN2N"},
+
+	{"RECMIXL", "INL1 Switch", "INL1 VOL"},
+	{"RECMIXL", "BST3 Switch", "BST3"},
+	{"RECMIXL", "BST2 Switch", "BST2"},
+	{"RECMIXL", "BST1 Switch", "BST1"},
+
+	{"RECMIXR", "INR1 Switch", "INR1 VOL"},
+	{"RECMIXR", "BST3 Switch", "BST3"},
+	{"RECMIXR", "BST2 Switch", "BST2"},
+	{"RECMIXR", "BST1 Switch", "BST1"},
+
+	{"ADC L", NULL, "RECMIXL"},
+	{"ADC L", NULL, "ADC L Power"},
+	{"ADC R", NULL, "RECMIXR"},
+	{"ADC R", NULL, "ADC R Power"},
+
+	{"DMIC L1", NULL, "DMIC CLK"},
+	{"DMIC R1", NULL, "DMIC CLK"},
+
+	{"Stereo1 ADC L2 Mux", "DMIC", "DMIC L1"},
+	{"Stereo1 ADC L2 Mux", "DD MIX", "DD MIXL"},
+	{"Stereo1 ADC L1 Mux", "ADC", "ADC L"},
+	{"Stereo1 ADC L1 Mux", "DD MIX", "DD MIXL"},
+
+	{"Stereo1 ADC R1 Mux", "ADC", "ADC R"},
+	{"Stereo1 ADC R1 Mux", "DD MIX", "DD MIXR"},
+	{"Stereo1 ADC R2 Mux", "DMIC", "DMIC R1"},
+	{"Stereo1 ADC R2 Mux", "DD MIX", "DD MIXR"},
+
+	{"Stereo2 ADC L2 Mux", "DMIC L", "DMIC L1"},
+	{"Stereo2 ADC L2 Mux", "DD MIXL", "DD MIXL"},
+	{"Stereo2 ADC L1 Mux", "DD MIXL", "DD MIXL"},
+	{"Stereo2 ADC L1 Mux", "ADCL", "ADC L"},
+
+	{"Stereo2 ADC R1 Mux", "DD MIXR", "DD MIXR"},
+	{"Stereo2 ADC R1 Mux", "ADCR", "ADC R"},
+	{"Stereo2 ADC R2 Mux", "DMIC R", "DMIC R1"},
+	{"Stereo2 ADC R2 Mux", "DD MIXR", "DD MIXR"},
+
+	{"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"},
+	{"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"},
+	{"Stereo1 ADC MIXL", NULL, "Stereo1 Filter"},
+	{"Stereo1 Filter", NULL, "ADC ASRC"},
+
+	{"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"},
+	{"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"},
+	{"Stereo1 ADC MIXR", NULL, "Stereo1 Filter"},
+
+	{"Stereo2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC L1 Mux"},
+	{"Stereo2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC L2 Mux"},
+	{"Stereo2 ADC MIXL", NULL, "Stereo2 Filter"},
+	{"Stereo2 Filter", NULL, "ADC ASRC"},
+
+	{"Stereo2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC R1 Mux"},
+	{"Stereo2 ADC MIXR", "ADC2 Switch", "Stereo2 ADC R2 Mux"},
+	{"Stereo2 ADC MIXR", NULL, "Stereo2 Filter"},
+
+	{"IF1 ADC2", NULL, "Stereo2 ADC MIXL"},
+	{"IF1 ADC2", NULL, "Stereo2 ADC MIXR"},
+	{"IF1 ADC1", NULL, "Stereo1 ADC MIXL"},
+	{"IF1 ADC1", NULL, "Stereo1 ADC MIXR"},
+
+	{"IF1 ADC1", NULL, "I2S1"},
+
+	{"IF2 ADC", "IF1 ADC1", "IF1 ADC1"},
+	{"IF2 ADC", "IF1 ADC2", "IF1 ADC2"},
+	{"IF2 ADC", NULL, "I2S2"},
+
+	{"AIF1TX", NULL, "IF1 ADC1"},
+	{"AIF1TX", NULL, "IF1 ADC2"},
+	{"AIF2TX", NULL, "IF2 ADC"},
+
+	{"IF1 DAC", NULL, "AIF1RX"},
+	{"IF1 DAC", NULL, "I2S1"},
+	{"IF2 DAC", NULL, "AIF2RX"},
+	{"IF2 DAC", NULL, "I2S2"},
+
+	{"IF1 DAC1 L", NULL, "IF1 DAC"},
+	{"IF1 DAC1 R", NULL, "IF1 DAC"},
+	{"IF1 DAC2 L", NULL, "IF1 DAC"},
+	{"IF1 DAC2 R", NULL, "IF1 DAC"},
+	{"IF2 DAC L", NULL, "IF2 DAC"},
+	{"IF2 DAC R", NULL, "IF2 DAC"},
+
+	{"DAC MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"},
+	{"DAC MIXL", "INF1 Switch", "IF1 DAC1 L"},
+	{"DAC MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"},
+	{"DAC MIXR", "INF1 Switch", "IF1 DAC1 R"},
+
+	{"Audio DSP", NULL, "DAC MIXL"},
+	{"Audio DSP", NULL, "DAC MIXR"},
+
+	{"DAC L2 Mux", "IF1", "IF1 DAC2 L"},
+	{"DAC L2 Mux", "IF2", "IF2 DAC L"},
+	{"DAC L2 Volume", NULL, "DAC L2 Mux"},
+
+	{"DAC R2 Mux", "IF1", "IF1 DAC2 R"},
+	{"DAC R2 Mux", "IF2", "IF2 DAC R"},
+	{"DAC R2 Volume", NULL, "DAC R2 Mux"},
+
+	{"Stereo DAC MIXL", "DAC L1 Switch", "Audio DSP"},
+	{"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Volume"},
+	{"Stereo DAC MIXL", "DAC R1 Switch", "DAC MIXR"},
+	{"Stereo DAC MIXL", NULL, "Stero1 DAC Power"},
+	{"Stereo DAC MIXL", NULL, "Stero2 DAC Power"},
+	{"Stereo DAC MIXR", "DAC R1 Switch", "Audio DSP"},
+	{"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Volume"},
+	{"Stereo DAC MIXR", "DAC L1 Switch", "DAC MIXL"},
+	{"Stereo DAC MIXR", NULL, "Stero1 DAC Power"},
+	{"Stereo DAC MIXR", NULL, "Stero2 DAC Power"},
+
+	{"PDM L Mux", "Stereo DAC MIX", "Stereo DAC MIXL"},
+	{"PDM L Mux", "DD MIX", "DAC MIXL"},
+	{"PDM R Mux", "Stereo DAC MIX", "Stereo DAC MIXR"},
+	{"PDM R Mux", "DD MIX", "DAC MIXR"},
+
+	{"DAC L1", NULL, "Stereo DAC MIXL"},
+	{"DAC L1", NULL, "DAC L1 Power"},
+	{"DAC R1", NULL, "Stereo DAC MIXR"},
+	{"DAC R1", NULL, "DAC R1 Power"},
+
+	{"DD MIXL", "DAC L1 Switch", "DAC MIXL"},
+	{"DD MIXL", "DAC L2 Switch", "DAC L2 Volume"},
+	{"DD MIXL", "DAC R2 Switch", "DAC R2 Volume"},
+	{"DD MIXL", NULL, "Stero2 DAC Power"},
+
+	{"DD MIXR", "DAC R1 Switch", "DAC MIXR"},
+	{"DD MIXR", "DAC R2 Switch", "DAC R2 Volume"},
+	{"DD MIXR", "DAC L2 Switch", "DAC L2 Volume"},
+	{"DD MIXR", NULL, "Stero2 DAC Power"},
+
+	{"OUT MIXL", "BST1 Switch", "BST1"},
+	{"OUT MIXL", "BST2 Switch", "BST2"},
+	{"OUT MIXL", "INL1 Switch", "INL1 VOL"},
+	{"OUT MIXL", "REC MIXL Switch", "RECMIXL"},
+	{"OUT MIXL", "DAC L1 Switch", "DAC L1"},
+
+	{"OUT MIXR", "BST2 Switch", "BST2"},
+	{"OUT MIXR", "BST1 Switch", "BST1"},
+	{"OUT MIXR", "INR1 Switch", "INR1 VOL"},
+	{"OUT MIXR", "REC MIXR Switch", "RECMIXR"},
+	{"OUT MIXR", "DAC R1 Switch", "DAC R1"},
+
+	{"HPOVOL L", "Switch", "OUT MIXL"},
+	{"HPOVOL R", "Switch", "OUT MIXR"},
+	{"OUTVOL L", "Switch", "OUT MIXL"},
+	{"OUTVOL R", "Switch", "OUT MIXR"},
+
+	{"HPOL MIX", "HPO MIX DAC1 Switch", "DAC L1"},
+	{"HPOL MIX", "HPO MIX HPVOL Switch", "HPOVOL L"},
+	{"HPOL MIX", NULL, "HP L Amp"},
+	{"HPOR MIX", "HPO MIX DAC1 Switch", "DAC R1"},
+	{"HPOR MIX", "HPO MIX HPVOL Switch", "HPOVOL R"},
+	{"HPOR MIX", NULL, "HP R Amp"},
+
+	{"LOUT MIX", "DAC L1 Switch", "DAC L1"},
+	{"LOUT MIX", "DAC R1 Switch", "DAC R1"},
+	{"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"},
+	{"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"},
+
+	{"HP Amp", NULL, "HPOL MIX"},
+	{"HP Amp", NULL, "HPOR MIX"},
+	{"HP Amp", NULL, "Amp Power"},
+	{"HPO L Playback", "Switch", "HP Amp"},
+	{"HPO R Playback", "Switch", "HP Amp"},
+	{"HPOL", NULL, "HPO L Playback"},
+	{"HPOR", NULL, "HPO R Playback"},
+
+	{"LOUT L Playback", "Switch", "LOUT MIX"},
+	{"LOUT R Playback", "Switch", "LOUT MIX"},
+	{"LOUTL", NULL, "LOUT L Playback"},
+	{"LOUTL", NULL, "Amp Power"},
+	{"LOUTR", NULL, "LOUT R Playback"},
+	{"LOUTR", NULL, "Amp Power"},
+
+	{"PDML", NULL, "PDM L Mux"},
+	{"PDMR", NULL, "PDM R Mux"},
+};
+
+static int rt5651_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0, val_clk, mask_clk;
+	int pre_div, bclk_ms, frame_size;
+
+	rt5651->lrck[dai->id] = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5651->sysclk, rt5651->lrck[dai->id]);
+
+	if (pre_div < 0) {
+		dev_err(component->dev, "Unsupported clock setting\n");
+		return -EINVAL;
+	}
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
+		return -EINVAL;
+	}
+	bclk_ms = frame_size > 32 ? 1 : 0;
+	rt5651->bclk[dai->id] = rt5651->lrck[dai->id] * (32 << bclk_ms);
+
+	dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+		rt5651->bclk[dai->id], rt5651->lrck[dai->id]);
+	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+				bclk_ms, pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		val_len |= RT5651_I2S_DL_20;
+		break;
+	case 24:
+		val_len |= RT5651_I2S_DL_24;
+		break;
+	case 8:
+		val_len |= RT5651_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5651_AIF1:
+		mask_clk = RT5651_I2S_PD1_MASK;
+		val_clk = pre_div << RT5651_I2S_PD1_SFT;
+		snd_soc_component_update_bits(component, RT5651_I2S1_SDP,
+			RT5651_I2S_DL_MASK, val_len);
+		snd_soc_component_update_bits(component, RT5651_ADDA_CLK1, mask_clk, val_clk);
+		break;
+	case RT5651_AIF2:
+		mask_clk = RT5651_I2S_BCLK_MS2_MASK | RT5651_I2S_PD2_MASK;
+		val_clk = pre_div << RT5651_I2S_PD2_SFT;
+		snd_soc_component_update_bits(component, RT5651_I2S2_SDP,
+			RT5651_I2S_DL_MASK, val_len);
+		snd_soc_component_update_bits(component, RT5651_ADDA_CLK1, mask_clk, val_clk);
+		break;
+	default:
+		dev_err(component->dev, "Wrong dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5651_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5651->master[dai->id] = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5651_I2S_MS_S;
+		rt5651->master[dai->id] = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5651_I2S_BP_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5651_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5651_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5651_I2S_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5651_AIF1:
+		snd_soc_component_update_bits(component, RT5651_I2S1_SDP,
+			RT5651_I2S_MS_MASK | RT5651_I2S_BP_MASK |
+			RT5651_I2S_DF_MASK, reg_val);
+		break;
+	case RT5651_AIF2:
+		snd_soc_component_update_bits(component, RT5651_I2S2_SDP,
+			RT5651_I2S_MS_MASK | RT5651_I2S_BP_MASK |
+			RT5651_I2S_DF_MASK, reg_val);
+		break;
+	default:
+		dev_err(component->dev, "Wrong dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int rt5651_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+	unsigned int pll_bit = 0;
+
+	if (freq == rt5651->sysclk && clk_id == rt5651->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5651_SCLK_S_MCLK:
+		reg_val |= RT5651_SCLK_SRC_MCLK;
+		break;
+	case RT5651_SCLK_S_PLL1:
+		reg_val |= RT5651_SCLK_SRC_PLL1;
+		pll_bit |= RT5651_PWR_PLL;
+		break;
+	case RT5651_SCLK_S_RCCLK:
+		reg_val |= RT5651_SCLK_SRC_RCCLK;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
+		RT5651_PWR_PLL, pll_bit);
+	snd_soc_component_update_bits(component, RT5651_GLB_CLK,
+		RT5651_SCLK_SRC_MASK, reg_val);
+	rt5651->sysclk = freq;
+	rt5651->sysclk_src = clk_id;
+
+	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+	return 0;
+}
+
+static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+			unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5651->pll_src && freq_in == rt5651->pll_in &&
+	    freq_out == rt5651->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt5651->pll_in = 0;
+		rt5651->pll_out = 0;
+		snd_soc_component_update_bits(component, RT5651_GLB_CLK,
+			RT5651_SCLK_SRC_MASK, RT5651_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5651_PLL1_S_MCLK:
+		snd_soc_component_update_bits(component, RT5651_GLB_CLK,
+			RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_MCLK);
+		break;
+	case RT5651_PLL1_S_BCLK1:
+		snd_soc_component_update_bits(component, RT5651_GLB_CLK,
+				RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_BCLK1);
+		break;
+	case RT5651_PLL1_S_BCLK2:
+			snd_soc_component_update_bits(component, RT5651_GLB_CLK,
+				RT5651_PLL1_SRC_MASK, RT5651_PLL1_SRC_BCLK2);
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_component_write(component, RT5651_PLL_CTRL1,
+		pll_code.n_code << RT5651_PLL_N_SFT | pll_code.k_code);
+	snd_soc_component_write(component, RT5651_PLL_CTRL2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5651_PLL_M_SFT |
+		pll_code.m_bp << RT5651_PLL_M_BP_SFT);
+
+	rt5651->pll_in = freq_in;
+	rt5651->pll_out = freq_out;
+	rt5651->pll_src = source;
+
+	return 0;
+}
+
+static int rt5651_set_bias_level(struct snd_soc_component *component,
+			enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		if (SND_SOC_BIAS_STANDBY == snd_soc_component_get_bias_level(component)) {
+			if (snd_soc_component_read32(component, RT5651_PLL_MODE_1) & 0x9200)
+				snd_soc_component_update_bits(component, RT5651_D_MISC,
+						    0xc00, 0xc00);
+		}
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (SND_SOC_BIAS_OFF == snd_soc_component_get_bias_level(component)) {
+			snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,
+				RT5651_PWR_VREF1 | RT5651_PWR_MB |
+				RT5651_PWR_BG | RT5651_PWR_VREF2,
+				RT5651_PWR_VREF1 | RT5651_PWR_MB |
+				RT5651_PWR_BG | RT5651_PWR_VREF2);
+			usleep_range(10000, 15000);
+			snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,
+				RT5651_PWR_FV1 | RT5651_PWR_FV2,
+				RT5651_PWR_FV1 | RT5651_PWR_FV2);
+			snd_soc_component_update_bits(component, RT5651_D_MISC, 0x1, 0x1);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_write(component, RT5651_D_MISC, 0x0010);
+		snd_soc_component_write(component, RT5651_PWR_DIG1, 0x0000);
+		snd_soc_component_write(component, RT5651_PWR_DIG2, 0x0000);
+		snd_soc_component_write(component, RT5651_PWR_VOL, 0x0000);
+		snd_soc_component_write(component, RT5651_PWR_MIXER, 0x0000);
+		/* Do not touch the LDO voltage select bits on bias-off */
+		snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,
+			~RT5651_PWR_LDO_DVO_MASK, 0);
+		/* Leave PLL1 and jack-detect power as is, all others off */
+		snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
+				    ~(RT5651_PWR_PLL | RT5651_PWR_JD_M), 0);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static void rt5651_enable_micbias1_for_ovcd(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_dapm_mutex_lock(dapm);
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO");
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "micbias1");
+	/* OVCD is unreliable when used with RCCLK as sysclk-source */
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "Platform Clock");
+	snd_soc_dapm_sync_unlocked(dapm);
+	snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static void rt5651_disable_micbias1_for_ovcd(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_dapm_mutex_lock(dapm);
+	snd_soc_dapm_disable_pin_unlocked(dapm, "Platform Clock");
+	snd_soc_dapm_disable_pin_unlocked(dapm, "micbias1");
+	snd_soc_dapm_disable_pin_unlocked(dapm, "LDO");
+	snd_soc_dapm_sync_unlocked(dapm);
+	snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static void rt5651_enable_micbias1_ovcd_irq(struct snd_soc_component *component)
+{
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
+		RT5651_IRQ_MB1_OC_MASK, RT5651_IRQ_MB1_OC_NOR);
+	rt5651->ovcd_irq_enabled = true;
+}
+
+static void rt5651_disable_micbias1_ovcd_irq(struct snd_soc_component *component)
+{
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
+		RT5651_IRQ_MB1_OC_MASK, RT5651_IRQ_MB1_OC_BP);
+	rt5651->ovcd_irq_enabled = false;
+}
+
+static void rt5651_clear_micbias1_ovcd(struct snd_soc_component *component)
+{
+	snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
+		RT5651_MB1_OC_CLR, 0);
+}
+
+static bool rt5651_micbias1_ovcd(struct snd_soc_component *component)
+{
+	int val;
+
+	val = snd_soc_component_read32(component, RT5651_IRQ_CTRL2);
+	dev_dbg(component->dev, "irq ctrl2 %#04x\n", val);
+
+	return (val & RT5651_MB1_OC_CLR);
+}
+
+static bool rt5651_jack_inserted(struct snd_soc_component *component)
+{
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+	int val;
+
+	val = snd_soc_component_read32(component, RT5651_INT_IRQ_ST);
+	dev_dbg(component->dev, "irq status %#04x\n", val);
+
+	switch (rt5651->jd_src) {
+	case RT5651_JD1_1:
+		val &= 0x1000;
+		break;
+	case RT5651_JD1_2:
+		val &= 0x2000;
+		break;
+	case RT5651_JD2:
+		val &= 0x4000;
+		break;
+	default:
+		break;
+	}
+
+	return val == 0;
+}
+
+/* Jack detect and button-press timings */
+#define JACK_SETTLE_TIME	100 /* milli seconds */
+#define JACK_DETECT_COUNT	5
+#define JACK_DETECT_MAXCOUNT	20  /* Aprox. 2 seconds worth of tries */
+#define JACK_UNPLUG_TIME	80  /* milli seconds */
+#define BP_POLL_TIME		10  /* milli seconds */
+#define BP_POLL_MAXCOUNT	200 /* assume something is wrong after this */
+#define BP_THRESHOLD		3
+
+static void rt5651_start_button_press_work(struct snd_soc_component *component)
+{
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+	rt5651->poll_count = 0;
+	rt5651->press_count = 0;
+	rt5651->release_count = 0;
+	rt5651->pressed = false;
+	rt5651->press_reported = false;
+	rt5651_clear_micbias1_ovcd(component);
+	schedule_delayed_work(&rt5651->bp_work, msecs_to_jiffies(BP_POLL_TIME));
+}
+
+static void rt5651_button_press_work(struct work_struct *work)
+{
+	struct rt5651_priv *rt5651 =
+		container_of(work, struct rt5651_priv, bp_work.work);
+	struct snd_soc_component *component = rt5651->component;
+
+	/* Check the jack was not removed underneath us */
+	if (!rt5651_jack_inserted(component))
+		return;
+
+	if (rt5651_micbias1_ovcd(component)) {
+		rt5651->release_count = 0;
+		rt5651->press_count++;
+		/* Remember till after JACK_UNPLUG_TIME wait */
+		if (rt5651->press_count >= BP_THRESHOLD)
+			rt5651->pressed = true;
+		rt5651_clear_micbias1_ovcd(component);
+	} else {
+		rt5651->press_count = 0;
+		rt5651->release_count++;
+	}
+
+	/*
+	 * The pins get temporarily shorted on jack unplug, so we poll for
+	 * at least JACK_UNPLUG_TIME milli-seconds before reporting a press.
+	 */
+	rt5651->poll_count++;
+	if (rt5651->poll_count < (JACK_UNPLUG_TIME / BP_POLL_TIME)) {
+		schedule_delayed_work(&rt5651->bp_work,
+				      msecs_to_jiffies(BP_POLL_TIME));
+		return;
+	}
+
+	if (rt5651->pressed && !rt5651->press_reported) {
+		dev_dbg(component->dev, "headset button press\n");
+		snd_soc_jack_report(rt5651->hp_jack, SND_JACK_BTN_0,
+				    SND_JACK_BTN_0);
+		rt5651->press_reported = true;
+	}
+
+	if (rt5651->release_count >= BP_THRESHOLD) {
+		if (rt5651->press_reported) {
+			dev_dbg(component->dev, "headset button release\n");
+			snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0);
+		}
+		/* Re-enable OVCD IRQ to detect next press */
+		rt5651_enable_micbias1_ovcd_irq(component);
+		return; /* Stop polling */
+	}
+
+	schedule_delayed_work(&rt5651->bp_work, msecs_to_jiffies(BP_POLL_TIME));
+}
+
+static int rt5651_detect_headset(struct snd_soc_component *component)
+{
+	int i, headset_count = 0, headphone_count = 0;
+
+	/*
+	 * We get the insertion event before the jack is fully inserted at which
+	 * point the second ring on a TRRS connector may short the 2nd ring and
+	 * sleeve contacts, also the overcurrent detection is not entirely
+	 * reliable. So we try several times with a wait in between until we
+	 * detect the same type JACK_DETECT_COUNT times in a row.
+	 */
+	for (i = 0; i < JACK_DETECT_MAXCOUNT; i++) {
+		/* Clear any previous over-current status flag */
+		rt5651_clear_micbias1_ovcd(component);
+
+		msleep(JACK_SETTLE_TIME);
+
+		/* Check the jack is still connected before checking ovcd */
+		if (!rt5651_jack_inserted(component))
+			return 0;
+
+		if (rt5651_micbias1_ovcd(component)) {
+			/*
+			 * Over current detected, there is a short between the
+			 * 2nd ring contact and the ground, so a TRS connector
+			 * without a mic contact and thus plain headphones.
+			 */
+			dev_dbg(component->dev, "mic-gnd shorted\n");
+			headset_count = 0;
+			headphone_count++;
+			if (headphone_count == JACK_DETECT_COUNT)
+				return SND_JACK_HEADPHONE;
+		} else {
+			dev_dbg(component->dev, "mic-gnd open\n");
+			headphone_count = 0;
+			headset_count++;
+			if (headset_count == JACK_DETECT_COUNT)
+				return SND_JACK_HEADSET;
+		}
+	}
+
+	dev_err(component->dev, "Error detecting headset vs headphones, bad contact?, assuming headphones\n");
+	return SND_JACK_HEADPHONE;
+}
+
+static void rt5651_jack_detect_work(struct work_struct *work)
+{
+	struct rt5651_priv *rt5651 =
+		container_of(work, struct rt5651_priv, jack_detect_work);
+	struct snd_soc_component *component = rt5651->component;
+	int report = 0;
+
+	if (!rt5651_jack_inserted(component)) {
+		/* Jack removed, or spurious IRQ? */
+		if (rt5651->hp_jack->status & SND_JACK_HEADPHONE) {
+			if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
+				cancel_delayed_work_sync(&rt5651->bp_work);
+				rt5651_disable_micbias1_ovcd_irq(component);
+				rt5651_disable_micbias1_for_ovcd(component);
+			}
+			snd_soc_jack_report(rt5651->hp_jack, 0,
+					    SND_JACK_HEADSET | SND_JACK_BTN_0);
+			dev_dbg(component->dev, "jack unplugged\n");
+		}
+	} else if (!(rt5651->hp_jack->status & SND_JACK_HEADPHONE)) {
+		/* Jack inserted */
+		WARN_ON(rt5651->ovcd_irq_enabled);
+		rt5651_enable_micbias1_for_ovcd(component);
+		report = rt5651_detect_headset(component);
+		if (report == SND_JACK_HEADSET) {
+			/* Enable ovcd IRQ for button press detect. */
+			rt5651_enable_micbias1_ovcd_irq(component);
+		} else {
+			/* No more need for overcurrent detect. */
+			rt5651_disable_micbias1_for_ovcd(component);
+		}
+		dev_dbg(component->dev, "detect report %#02x\n", report);
+		snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET);
+	} else if (rt5651->ovcd_irq_enabled && rt5651_micbias1_ovcd(component)) {
+		dev_dbg(component->dev, "OVCD IRQ\n");
+
+		/*
+		 * The ovcd IRQ keeps firing while the button is pressed, so
+		 * we disable it and start polling the button until released.
+		 *
+		 * The disable will make the IRQ pin 0 again and since we get
+		 * IRQs on both edges (so as to detect both jack plugin and
+		 * unplug) this means we will immediately get another IRQ.
+		 * The ovcd_irq_enabled check above makes the 2ND IRQ a NOP.
+		 */
+		rt5651_disable_micbias1_ovcd_irq(component);
+		rt5651_start_button_press_work(component);
+
+		/*
+		 * If the jack-detect IRQ flag goes high (unplug) after our
+		 * above rt5651_jack_inserted() check and before we have
+		 * disabled the OVCD IRQ, the IRQ pin will stay high and as
+		 * we react to edges, we miss the unplug event -> recheck.
+		 */
+		queue_work(system_long_wq, &rt5651->jack_detect_work);
+	}
+}
+
+static irqreturn_t rt5651_irq(int irq, void *data)
+{
+	struct rt5651_priv *rt5651 = data;
+
+	queue_work(system_power_efficient_wq, &rt5651->jack_detect_work);
+
+	return IRQ_HANDLED;
+}
+
+static void rt5651_cancel_work(void *data)
+{
+	struct rt5651_priv *rt5651 = data;
+
+	cancel_work_sync(&rt5651->jack_detect_work);
+	cancel_delayed_work_sync(&rt5651->bp_work);
+}
+
+static void rt5651_enable_jack_detect(struct snd_soc_component *component,
+				      struct snd_soc_jack *hp_jack)
+{
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+	/* IRQ output on GPIO1 */
+	snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1,
+		RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ);
+
+	/* Select jack detect source */
+	switch (rt5651->jd_src) {
+	case RT5651_JD1_1:
+		snd_soc_component_update_bits(component, RT5651_JD_CTRL2,
+			RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_1);
+		snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1,
+			RT5651_JD1_1_IRQ_EN, RT5651_JD1_1_IRQ_EN);
+		break;
+	case RT5651_JD1_2:
+		snd_soc_component_update_bits(component, RT5651_JD_CTRL2,
+			RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_2);
+		snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1,
+			RT5651_JD1_2_IRQ_EN, RT5651_JD1_2_IRQ_EN);
+		break;
+	case RT5651_JD2:
+		snd_soc_component_update_bits(component, RT5651_JD_CTRL2,
+			RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD2);
+		snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1,
+			RT5651_JD2_IRQ_EN, RT5651_JD2_IRQ_EN);
+		break;
+	case RT5651_JD_NULL:
+		return;
+	default:
+		dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n");
+		return;
+	}
+
+	/* Enable jack detect power */
+	snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
+		RT5651_PWR_JD_M, RT5651_PWR_JD_M);
+
+	/* Set OVCD threshold current and scale-factor */
+	snd_soc_component_write(component, RT5651_PR_BASE + RT5651_BIAS_CUR4,
+				0xa800 | rt5651->ovcd_sf);
+
+	snd_soc_component_update_bits(component, RT5651_MICBIAS,
+				      RT5651_MIC1_OVCD_MASK |
+				      RT5651_MIC1_OVTH_MASK |
+				      RT5651_PWR_CLK12M_MASK |
+				      RT5651_PWR_MB_MASK,
+				      RT5651_MIC1_OVCD_EN |
+				      rt5651->ovcd_th |
+				      RT5651_PWR_MB_PU |
+				      RT5651_PWR_CLK12M_PU);
+
+	/*
+	 * The over-current-detect is only reliable in detecting the absence
+	 * of over-current, when the mic-contact in the jack is short-circuited,
+	 * the hardware periodically retries if it can apply the bias-current
+	 * leading to the ovcd status flip-flopping 1-0-1 with it being 0 about
+	 * 10% of the time, as we poll the ovcd status bit we might hit that
+	 * 10%, so we enable sticky mode and when checking OVCD we clear the
+	 * status, msleep() a bit and then check to get a reliable reading.
+	 */
+	snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
+		RT5651_MB1_OC_STKY_MASK, RT5651_MB1_OC_STKY_EN);
+
+	rt5651->hp_jack = hp_jack;
+	if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
+		rt5651_enable_micbias1_for_ovcd(component);
+		rt5651_enable_micbias1_ovcd_irq(component);
+	}
+
+	enable_irq(rt5651->irq);
+	/* sync initial jack state */
+	queue_work(system_power_efficient_wq, &rt5651->jack_detect_work);
+}
+
+static void rt5651_disable_jack_detect(struct snd_soc_component *component)
+{
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+	disable_irq(rt5651->irq);
+	rt5651_cancel_work(rt5651);
+
+	if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
+		rt5651_disable_micbias1_ovcd_irq(component);
+		rt5651_disable_micbias1_for_ovcd(component);
+		snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0);
+	}
+
+	rt5651->hp_jack = NULL;
+}
+
+static int rt5651_set_jack(struct snd_soc_component *component,
+			   struct snd_soc_jack *jack, void *data)
+{
+	if (jack)
+		rt5651_enable_jack_detect(component, jack);
+	else
+		rt5651_disable_jack_detect(component);
+
+	return 0;
+}
+
+/*
+ * Note on some platforms the platform code may need to add device-properties,
+ * rather then relying only on properties set by the firmware. Therefor the
+ * property parsing MUST be done from the component driver's probe function,
+ * rather then from the i2c driver's probe function, so that the platform-code
+ * can attach extra properties before calling snd_soc_register_card().
+ */
+static void rt5651_apply_properties(struct snd_soc_component *component)
+{
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+	u32 val;
+
+	if (device_property_read_bool(component->dev, "realtek,in2-differential"))
+		snd_soc_component_update_bits(component, RT5651_IN1_IN2,
+				RT5651_IN_DF2, RT5651_IN_DF2);
+
+	if (device_property_read_bool(component->dev, "realtek,dmic-en"))
+		snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1,
+				RT5651_GP2_PIN_MASK, RT5651_GP2_PIN_DMIC1_SCL);
+
+	if (device_property_read_u32(component->dev,
+				     "realtek,jack-detect-source", &val) == 0)
+		rt5651->jd_src = val;
+
+	/*
+	 * Testing on various boards has shown that good defaults for the OVCD
+	 * threshold and scale-factor are 2000µA and 0.75. For an effective
+	 * limit of 1500µA, this seems to be more reliable then 1500µA and 1.0.
+	 */
+	rt5651->ovcd_th = RT5651_MIC1_OVTH_2000UA;
+	rt5651->ovcd_sf = RT5651_MIC_OVCD_SF_0P75;
+
+	if (device_property_read_u32(component->dev,
+			"realtek,over-current-threshold-microamp", &val) == 0) {
+		switch (val) {
+		case 600:
+			rt5651->ovcd_th = RT5651_MIC1_OVTH_600UA;
+			break;
+		case 1500:
+			rt5651->ovcd_th = RT5651_MIC1_OVTH_1500UA;
+			break;
+		case 2000:
+			rt5651->ovcd_th = RT5651_MIC1_OVTH_2000UA;
+			break;
+		default:
+			dev_warn(component->dev, "Warning: Invalid over-current-threshold-microamp value: %d, defaulting to 2000uA\n",
+				 val);
+		}
+	}
+
+	if (device_property_read_u32(component->dev,
+			"realtek,over-current-scale-factor", &val) == 0) {
+		if (val <= RT5651_OVCD_SF_1P5)
+			rt5651->ovcd_sf = val << RT5651_MIC_OVCD_SF_SFT;
+		else
+			dev_warn(component->dev, "Warning: Invalid over-current-scale-factor value: %d, defaulting to 0.75\n",
+				 val);
+	}
+}
+
+static int rt5651_probe(struct snd_soc_component *component)
+{
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+	rt5651->component = component;
+
+	snd_soc_component_update_bits(component, RT5651_PWR_ANLG1,
+		RT5651_PWR_LDO_DVO_MASK, RT5651_PWR_LDO_DVO_1_2V);
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+
+	rt5651_apply_properties(component);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5651_suspend(struct snd_soc_component *component)
+{
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5651->regmap, true);
+	regcache_mark_dirty(rt5651->regmap);
+	return 0;
+}
+
+static int rt5651_resume(struct snd_soc_component *component)
+{
+	struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5651->regmap, false);
+	snd_soc_component_cache_sync(component);
+
+	return 0;
+}
+#else
+#define rt5651_suspend NULL
+#define rt5651_resume NULL
+#endif
+
+#define RT5651_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define RT5651_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5651_aif_dai_ops = {
+	.hw_params = rt5651_hw_params,
+	.set_fmt = rt5651_set_dai_fmt,
+	.set_sysclk = rt5651_set_dai_sysclk,
+	.set_pll = rt5651_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver rt5651_dai[] = {
+	{
+		.name = "rt5651-aif1",
+		.id = RT5651_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5651_STEREO_RATES,
+			.formats = RT5651_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5651_STEREO_RATES,
+			.formats = RT5651_FORMATS,
+		},
+		.ops = &rt5651_aif_dai_ops,
+	},
+	{
+		.name = "rt5651-aif2",
+		.id = RT5651_AIF2,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5651_STEREO_RATES,
+			.formats = RT5651_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5651_STEREO_RATES,
+			.formats = RT5651_FORMATS,
+		},
+		.ops = &rt5651_aif_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5651 = {
+	.probe			= rt5651_probe,
+	.suspend		= rt5651_suspend,
+	.resume			= rt5651_resume,
+	.set_bias_level		= rt5651_set_bias_level,
+	.set_jack		= rt5651_set_jack,
+	.controls		= rt5651_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5651_snd_controls),
+	.dapm_widgets		= rt5651_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5651_dapm_widgets),
+	.dapm_routes		= rt5651_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5651_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt5651_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = RT5651_DEVICE_ID + 1 + (ARRAY_SIZE(rt5651_ranges) *
+					       RT5651_PR_SPACING),
+	.volatile_reg = rt5651_volatile_register,
+	.readable_reg = rt5651_readable_register,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5651_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5651_reg),
+	.ranges = rt5651_ranges,
+	.num_ranges = ARRAY_SIZE(rt5651_ranges),
+	.use_single_rw = true,
+};
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rt5651_of_match[] = {
+	{ .compatible = "realtek,rt5651", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5651_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5651_acpi_match[] = {
+	{ "10EC5651", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, rt5651_acpi_match);
+#endif
+
+static const struct i2c_device_id rt5651_i2c_id[] = {
+	{ "rt5651", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id);
+
+/*
+ * Note this function MUST not look at device-properties, see the comment
+ * above rt5651_apply_properties().
+ */
+static int rt5651_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5651_priv *rt5651;
+	int ret;
+
+	rt5651 = devm_kzalloc(&i2c->dev, sizeof(*rt5651),
+				GFP_KERNEL);
+	if (NULL == rt5651)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt5651);
+
+	rt5651->regmap = devm_regmap_init_i2c(i2c, &rt5651_regmap);
+	if (IS_ERR(rt5651->regmap)) {
+		ret = PTR_ERR(rt5651->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret);
+	if (ret != RT5651_DEVICE_ID_VALUE) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt5651\n", ret);
+		return -ENODEV;
+	}
+
+	regmap_write(rt5651->regmap, RT5651_RESET, 0);
+
+	ret = regmap_register_patch(rt5651->regmap, init_list,
+				    ARRAY_SIZE(init_list));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	rt5651->irq = i2c->irq;
+	rt5651->hp_mute = 1;
+
+	INIT_DELAYED_WORK(&rt5651->bp_work, rt5651_button_press_work);
+	INIT_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work);
+
+	/* Make sure work is stopped on probe-error / remove */
+	ret = devm_add_action_or_reset(&i2c->dev, rt5651_cancel_work, rt5651);
+	if (ret)
+		return ret;
+
+	ret = devm_request_irq(&i2c->dev, rt5651->irq, rt5651_irq,
+			       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+			       | IRQF_ONESHOT, "rt5651", rt5651);
+	if (ret == 0) {
+		/* Gets re-enabled by rt5651_set_jack() */
+		disable_irq(rt5651->irq);
+	} else {
+		dev_warn(&i2c->dev, "Failed to reguest IRQ %d: %d\n",
+			 rt5651->irq, ret);
+		rt5651->irq = -ENXIO;
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				&soc_component_dev_rt5651,
+				rt5651_dai, ARRAY_SIZE(rt5651_dai));
+
+	return ret;
+}
+
+static struct i2c_driver rt5651_i2c_driver = {
+	.driver = {
+		.name = "rt5651",
+		.acpi_match_table = ACPI_PTR(rt5651_acpi_match),
+		.of_match_table = of_match_ptr(rt5651_of_match),
+	},
+	.probe = rt5651_i2c_probe,
+	.id_table = rt5651_i2c_id,
+};
+module_i2c_driver(rt5651_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5651 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h
new file mode 100644
index 0000000..ac6de6f
--- /dev/null
+++ b/sound/soc/codecs/rt5651.h
@@ -0,0 +1,2103 @@
+/*
+ * rt5651.h  --  RT5651 ALSA SoC audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ * Author: Johnny Hsu <johnnyhsu@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5651_H__
+#define __RT5651_H__
+
+#include <dt-bindings/sound/rt5651.h>
+
+/* Info */
+#define RT5651_RESET				0x00
+#define RT5651_VERSION_ID			0xfd
+#define RT5651_VENDOR_ID			0xfe
+#define RT5651_DEVICE_ID			0xff
+/*  I/O - Output */
+#define RT5651_HP_VOL				0x02
+#define RT5651_LOUT_CTRL1			0x03
+#define RT5651_LOUT_CTRL2			0x05
+/* I/O - Input */
+#define RT5651_IN1_IN2				0x0d
+#define RT5651_IN3				0x0e
+#define RT5651_INL1_INR1_VOL			0x0f
+#define RT5651_INL2_INR2_VOL			0x10
+/* I/O - ADC/DAC/DMIC */
+#define RT5651_DAC1_DIG_VOL			0x19
+#define RT5651_DAC2_DIG_VOL			0x1a
+#define RT5651_DAC2_CTRL			0x1b
+#define RT5651_ADC_DIG_VOL			0x1c
+#define RT5651_ADC_DATA				0x1d
+#define RT5651_ADC_BST_VOL			0x1e
+/* Mixer - D-D */
+#define RT5651_STO1_ADC_MIXER			0x27
+#define RT5651_STO2_ADC_MIXER			0x28
+#define RT5651_AD_DA_MIXER			0x29
+#define RT5651_STO_DAC_MIXER			0x2a
+#define RT5651_DD_MIXER				0x2b
+#define RT5651_DIG_INF_DATA			0x2f
+/* PDM */
+#define RT5651_PDM_CTL				0x30
+#define RT5651_PDM_I2C_CTL1			0x31
+#define RT5651_PDM_I2C_CTL2			0x32
+#define RT5651_PDM_I2C_DATA_W			0x33
+#define RT5651_PDM_I2C_DATA_R			0x34
+/* Mixer - ADC */
+#define RT5651_REC_L1_MIXER			0x3b
+#define RT5651_REC_L2_MIXER			0x3c
+#define RT5651_REC_R1_MIXER			0x3d
+#define RT5651_REC_R2_MIXER			0x3e
+/* Mixer - DAC */
+#define RT5651_HPO_MIXER			0x45
+#define RT5651_OUT_L1_MIXER			0x4d
+#define RT5651_OUT_L2_MIXER			0x4e
+#define RT5651_OUT_L3_MIXER			0x4f
+#define RT5651_OUT_R1_MIXER			0x50
+#define RT5651_OUT_R2_MIXER			0x51
+#define RT5651_OUT_R3_MIXER			0x52
+#define RT5651_LOUT_MIXER			0x53
+/* Power */
+#define RT5651_PWR_DIG1				0x61
+#define RT5651_PWR_DIG2				0x62
+#define RT5651_PWR_ANLG1			0x63
+#define RT5651_PWR_ANLG2			0x64
+#define RT5651_PWR_MIXER			0x65
+#define RT5651_PWR_VOL				0x66
+/* Private Register Control */
+#define RT5651_PRIV_INDEX			0x6a
+#define RT5651_PRIV_DATA			0x6c
+/* Format - ADC/DAC */
+#define RT5651_I2S1_SDP				0x70
+#define RT5651_I2S2_SDP				0x71
+#define RT5651_ADDA_CLK1			0x73
+#define RT5651_ADDA_CLK2			0x74
+#define RT5651_DMIC				0x75
+/* TDM Control */
+#define RT5651_TDM_CTL_1			0x77
+#define RT5651_TDM_CTL_2			0x78
+#define RT5651_TDM_CTL_3			0x79
+/* Function - Analog */
+#define RT5651_GLB_CLK				0x80
+#define RT5651_PLL_CTRL1			0x81
+#define RT5651_PLL_CTRL2			0x82
+#define RT5651_PLL_MODE_1			0x83
+#define RT5651_PLL_MODE_2			0x84
+#define RT5651_PLL_MODE_3			0x85
+#define RT5651_PLL_MODE_4			0x86
+#define RT5651_PLL_MODE_5			0x87
+#define RT5651_PLL_MODE_6			0x89
+#define RT5651_PLL_MODE_7			0x8a
+#define RT5651_DEPOP_M1				0x8e
+#define RT5651_DEPOP_M2				0x8f
+#define RT5651_DEPOP_M3				0x90
+#define RT5651_CHARGE_PUMP			0x91
+#define RT5651_MICBIAS				0x93
+#define RT5651_A_JD_CTL1			0x94
+/* Function - Digital */
+#define RT5651_EQ_CTRL1				0xb0
+#define RT5651_EQ_CTRL2				0xb1
+#define RT5651_ALC_1				0xb4
+#define RT5651_ALC_2				0xb5
+#define RT5651_ALC_3				0xb6
+#define RT5651_JD_CTRL1				0xbb
+#define RT5651_JD_CTRL2				0xbc
+#define RT5651_IRQ_CTRL1			0xbd
+#define RT5651_IRQ_CTRL2			0xbe
+#define RT5651_INT_IRQ_ST			0xbf
+#define RT5651_GPIO_CTRL1			0xc0
+#define RT5651_GPIO_CTRL2			0xc1
+#define RT5651_GPIO_CTRL3			0xc2
+#define RT5651_PGM_REG_ARR1			0xc8
+#define RT5651_PGM_REG_ARR2			0xc9
+#define RT5651_PGM_REG_ARR3			0xca
+#define RT5651_PGM_REG_ARR4			0xcb
+#define RT5651_PGM_REG_ARR5			0xcc
+#define RT5651_SCB_FUNC				0xcd
+#define RT5651_SCB_CTRL				0xce
+#define RT5651_BASE_BACK			0xcf
+#define RT5651_MP3_PLUS1			0xd0
+#define RT5651_MP3_PLUS2			0xd1
+#define RT5651_ADJ_HPF_CTRL1			0xd3
+#define RT5651_ADJ_HPF_CTRL2			0xd4
+#define RT5651_HP_CALIB_AMP_DET			0xd6
+#define RT5651_HP_CALIB2			0xd7
+#define RT5651_SV_ZCD1				0xd9
+#define RT5651_SV_ZCD2				0xda
+#define RT5651_D_MISC				0xfa
+/* Dummy Register */
+#define RT5651_DUMMY2				0xfb
+#define RT5651_DUMMY3				0xfc
+
+
+/* Index of Codec Private Register definition */
+#define RT5651_BIAS_CUR1			0x12
+#define RT5651_BIAS_CUR3			0x14
+#define RT5651_BIAS_CUR4			0x15
+#define RT5651_CLSD_INT_REG1			0x1c
+#define RT5651_CHPUMP_INT_REG1			0x24
+#define RT5651_MAMP_INT_REG2			0x37
+#define RT5651_CHOP_DAC_ADC			0x3d
+#define RT5651_3D_SPK				0x63
+#define RT5651_WND_1				0x6c
+#define RT5651_WND_2				0x6d
+#define RT5651_WND_3				0x6e
+#define RT5651_WND_4				0x6f
+#define RT5651_WND_5				0x70
+#define RT5651_WND_8				0x73
+#define RT5651_DIP_SPK_INF			0x75
+#define RT5651_HP_DCC_INT1			0x77
+#define RT5651_EQ_BW_LOP			0xa0
+#define RT5651_EQ_GN_LOP			0xa1
+#define RT5651_EQ_FC_BP1			0xa2
+#define RT5651_EQ_BW_BP1			0xa3
+#define RT5651_EQ_GN_BP1			0xa4
+#define RT5651_EQ_FC_BP2			0xa5
+#define RT5651_EQ_BW_BP2			0xa6
+#define RT5651_EQ_GN_BP2			0xa7
+#define RT5651_EQ_FC_BP3			0xa8
+#define RT5651_EQ_BW_BP3			0xa9
+#define RT5651_EQ_GN_BP3			0xaa
+#define RT5651_EQ_FC_BP4			0xab
+#define RT5651_EQ_BW_BP4			0xac
+#define RT5651_EQ_GN_BP4			0xad
+#define RT5651_EQ_FC_HIP1			0xae
+#define RT5651_EQ_GN_HIP1			0xaf
+#define RT5651_EQ_FC_HIP2			0xb0
+#define RT5651_EQ_BW_HIP2			0xb1
+#define RT5651_EQ_GN_HIP2			0xb2
+#define RT5651_EQ_PRE_VOL			0xb3
+#define RT5651_EQ_PST_VOL			0xb4
+
+
+/* global definition */
+#define RT5651_L_MUTE				(0x1 << 15)
+#define RT5651_L_MUTE_SFT			15
+#define RT5651_VOL_L_MUTE			(0x1 << 14)
+#define RT5651_VOL_L_SFT			14
+#define RT5651_R_MUTE				(0x1 << 7)
+#define RT5651_R_MUTE_SFT			7
+#define RT5651_VOL_R_MUTE			(0x1 << 6)
+#define RT5651_VOL_R_SFT			6
+#define RT5651_L_VOL_MASK			(0x3f << 8)
+#define RT5651_L_VOL_SFT			8
+#define RT5651_R_VOL_MASK			(0x3f)
+#define RT5651_R_VOL_SFT			0
+
+/* LOUT Control 2(0x05) */
+#define RT5651_EN_DFO				(0x1 << 15)
+
+/* IN1 and IN2 Control (0x0d) */
+/* IN3 and IN4 Control (0x0e) */
+#define RT5651_BST_MASK1			(0xf<<12)
+#define RT5651_BST_SFT1				12
+#define RT5651_BST_MASK2			(0xf<<8)
+#define RT5651_BST_SFT2				8
+#define RT5651_IN_DF1				(0x1 << 7)
+#define RT5651_IN_SFT1				7
+#define RT5651_IN_DF2				(0x1 << 6)
+#define RT5651_IN_SFT2				6
+
+/* INL1 and INR1 Volume Control (0x0f) */
+/* INL2 and INR2 Volume Control (0x10) */
+#define RT5651_INL_SEL_MASK			(0x1 << 15)
+#define RT5651_INL_SEL_SFT			15
+#define RT5651_INL_SEL_IN4P			(0x0 << 15)
+#define RT5651_INL_SEL_MONOP			(0x1 << 15)
+#define RT5651_INL_VOL_MASK			(0x1f << 8)
+#define RT5651_INL_VOL_SFT			8
+#define RT5651_INR_SEL_MASK			(0x1 << 7)
+#define RT5651_INR_SEL_SFT			7
+#define RT5651_INR_SEL_IN4N			(0x0 << 7)
+#define RT5651_INR_SEL_MONON			(0x1 << 7)
+#define RT5651_INR_VOL_MASK			(0x1f)
+#define RT5651_INR_VOL_SFT			0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5651_DAC_L1_VOL_MASK			(0xff << 8)
+#define RT5651_DAC_L1_VOL_SFT			8
+#define RT5651_DAC_R1_VOL_MASK			(0xff)
+#define RT5651_DAC_R1_VOL_SFT			0
+
+/* DAC2 Digital Volume (0x1a) */
+#define RT5651_DAC_L2_VOL_MASK			(0xff << 8)
+#define RT5651_DAC_L2_VOL_SFT			8
+#define RT5651_DAC_R2_VOL_MASK			(0xff)
+#define RT5651_DAC_R2_VOL_SFT			0
+
+/* DAC2 Control (0x1b) */
+#define RT5651_M_DAC_L2_VOL			(0x1 << 13)
+#define RT5651_M_DAC_L2_VOL_SFT			13
+#define RT5651_M_DAC_R2_VOL			(0x1 << 12)
+#define RT5651_M_DAC_R2_VOL_SFT			12
+#define RT5651_SEL_DAC_L2			(0x1 << 11)
+#define RT5651_IF2_DAC_L2			(0x1 << 11)
+#define RT5651_IF1_DAC_L2			(0x0 << 11)
+#define RT5651_SEL_DAC_L2_SFT			11
+#define RT5651_SEL_DAC_R2			(0x1 << 10)
+#define RT5651_IF2_DAC_R2			(0x1 << 11)
+#define RT5651_IF1_DAC_R2			(0x0 << 11)
+#define RT5651_SEL_DAC_R2_SFT			10
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5651_ADC_L_VOL_MASK			(0x7f << 8)
+#define RT5651_ADC_L_VOL_SFT			8
+#define RT5651_ADC_R_VOL_MASK			(0x7f)
+#define RT5651_ADC_R_VOL_SFT			0
+
+/* Mono ADC Digital Volume Control (0x1d) */
+#define RT5651_M_MONO_ADC_L			(0x1 << 15)
+#define RT5651_M_MONO_ADC_L_SFT			15
+#define RT5651_MONO_ADC_L_VOL_MASK		(0x7f << 8)
+#define RT5651_MONO_ADC_L_VOL_SFT		8
+#define RT5651_M_MONO_ADC_R			(0x1 << 7)
+#define RT5651_M_MONO_ADC_R_SFT			7
+#define RT5651_MONO_ADC_R_VOL_MASK		(0x7f)
+#define RT5651_MONO_ADC_R_VOL_SFT		0
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5651_ADC_L_BST_MASK			(0x3 << 14)
+#define RT5651_ADC_L_BST_SFT			14
+#define RT5651_ADC_R_BST_MASK			(0x3 << 12)
+#define RT5651_ADC_R_BST_SFT			12
+#define RT5651_ADC_COMP_MASK			(0x3 << 10)
+#define RT5651_ADC_COMP_SFT			10
+
+/* Stereo ADC1 Mixer Control (0x27) */
+#define RT5651_M_STO1_ADC_L1			(0x1 << 14)
+#define RT5651_M_STO1_ADC_L1_SFT		14
+#define RT5651_M_STO1_ADC_L2			(0x1 << 13)
+#define RT5651_M_STO1_ADC_L2_SFT		13
+#define RT5651_STO1_ADC_1_SRC_MASK		(0x1 << 12)
+#define RT5651_STO1_ADC_1_SRC_SFT		12
+#define RT5651_STO1_ADC_1_SRC_ADC		(0x1 << 12)
+#define RT5651_STO1_ADC_1_SRC_DACMIX		(0x0 << 12)
+#define RT5651_STO1_ADC_2_SRC_MASK		(0x1 << 11)
+#define RT5651_STO1_ADC_2_SRC_SFT		11
+#define RT5651_STO1_ADC_2_SRC_DMIC		(0x0 << 11)
+#define RT5651_STO1_ADC_2_SRC_DACMIXR	(0x1 << 11)
+#define RT5651_M_STO1_ADC_R1			(0x1 << 6)
+#define RT5651_M_STO1_ADC_R1_SFT		6
+#define RT5651_M_STO1_ADC_R2			(0x1 << 5)
+#define RT5651_M_STO1_ADC_R2_SFT		5
+
+/* Stereo ADC2 Mixer Control (0x28) */
+#define RT5651_M_STO2_ADC_L1			(0x1 << 14)
+#define RT5651_M_STO2_ADC_L1_SFT		14
+#define RT5651_M_STO2_ADC_L2			(0x1 << 13)
+#define RT5651_M_STO2_ADC_L2_SFT		13
+#define RT5651_STO2_ADC_L1_SRC_MASK		(0x1 << 12)
+#define RT5651_STO2_ADC_L1_SRC_SFT		12
+#define RT5651_STO2_ADC_L1_SRC_DACMIXL		(0x0 << 12)
+#define RT5651_STO2_ADC_L1_SRC_ADCL		(0x1 << 12)
+#define RT5651_STO2_ADC_L2_SRC_MASK		(0x1 << 11)
+#define RT5651_STO2_ADC_L2_SRC_SFT		11
+#define RT5651_STO2_ADC_L2_SRC_DMIC		(0x0 << 11)
+#define RT5651_STO2_ADC_L2_SRC_DACMIXR		(0x1 << 11)
+#define RT5651_M_STO2_ADC_R1			(0x1 << 6)
+#define RT5651_M_STO2_ADC_R1_SFT		6
+#define RT5651_M_STO2_ADC_R2			(0x1 << 5)
+#define RT5651_M_STO2_ADC_R2_SFT		5
+#define RT5651_STO2_ADC_R1_SRC_MASK		(0x1 << 4)
+#define RT5651_STO2_ADC_R1_SRC_SFT		4
+#define RT5651_STO2_ADC_R1_SRC_ADCR		(0x1 << 4)
+#define RT5651_STO2_ADC_R1_SRC_DACMIXR		(0x0 << 4)
+#define RT5651_STO2_ADC_R2_SRC_MASK		(0x1 << 3)
+#define RT5651_STO2_ADC_R2_SRC_SFT		3
+#define RT5651_STO2_ADC_R2_SRC_DMIC		(0x0 << 3)
+#define RT5651_STO2_ADC_R2_SRC_DACMIXR		(0x1 << 3)
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5651_M_ADCMIX_L			(0x1 << 15)
+#define RT5651_M_ADCMIX_L_SFT			15
+#define RT5651_M_IF1_DAC_L			(0x1 << 14)
+#define RT5651_M_IF1_DAC_L_SFT			14
+#define RT5651_M_ADCMIX_R			(0x1 << 7)
+#define RT5651_M_ADCMIX_R_SFT			7
+#define RT5651_M_IF1_DAC_R			(0x1 << 6)
+#define RT5651_M_IF1_DAC_R_SFT			6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5651_M_DAC_L1_MIXL			(0x1 << 14)
+#define RT5651_M_DAC_L1_MIXL_SFT		14
+#define RT5651_DAC_L1_STO_L_VOL_MASK		(0x1 << 13)
+#define RT5651_DAC_L1_STO_L_VOL_SFT		13
+#define RT5651_M_DAC_L2_MIXL			(0x1 << 12)
+#define RT5651_M_DAC_L2_MIXL_SFT		12
+#define RT5651_DAC_L2_STO_L_VOL_MASK		(0x1 << 11)
+#define RT5651_DAC_L2_STO_L_VOL_SFT		11
+#define RT5651_M_DAC_R1_MIXL			(0x1 << 9)
+#define RT5651_M_DAC_R1_MIXL_SFT		9
+#define RT5651_DAC_R1_STO_L_VOL_MASK		(0x1 << 8)
+#define RT5651_DAC_R1_STO_L_VOL_SFT		8
+#define RT5651_M_DAC_R1_MIXR			(0x1 << 6)
+#define RT5651_M_DAC_R1_MIXR_SFT		6
+#define RT5651_DAC_R1_STO_R_VOL_MASK		(0x1 << 5)
+#define RT5651_DAC_R1_STO_R_VOL_SFT		5
+#define RT5651_M_DAC_R2_MIXR			(0x1 << 4)
+#define RT5651_M_DAC_R2_MIXR_SFT		4
+#define RT5651_DAC_R2_STO_R_VOL_MASK		(0x1 << 3)
+#define RT5651_DAC_R2_STO_R_VOL_SFT		3
+#define RT5651_M_DAC_L1_MIXR			(0x1 << 1)
+#define RT5651_M_DAC_L1_MIXR_SFT		1
+#define RT5651_DAC_L1_STO_R_VOL_MASK		(0x1)
+#define RT5651_DAC_L1_STO_R_VOL_SFT		0
+
+/* DD Mixer Control (0x2b) */
+#define RT5651_M_STO_DD_L1			(0x1 << 14)
+#define RT5651_M_STO_DD_L1_SFT			14
+#define RT5651_STO_DD_L1_VOL_MASK		(0x1 << 13)
+#define RT5651_DAC_DD_L1_VOL_SFT		13
+#define RT5651_M_STO_DD_L2			(0x1 << 12)
+#define RT5651_M_STO_DD_L2_SFT			12
+#define RT5651_STO_DD_L2_VOL_MASK		(0x1 << 11)
+#define RT5651_STO_DD_L2_VOL_SFT		11
+#define RT5651_M_STO_DD_R2_L			(0x1 << 10)
+#define RT5651_M_STO_DD_R2_L_SFT		10
+#define RT5651_STO_DD_R2_L_VOL_MASK		(0x1 << 9)
+#define RT5651_STO_DD_R2_L_VOL_SFT		9
+#define RT5651_M_STO_DD_R1			(0x1 << 6)
+#define RT5651_M_STO_DD_R1_SFT			6
+#define RT5651_STO_DD_R1_VOL_MASK		(0x1 << 5)
+#define RT5651_STO_DD_R1_VOL_SFT		5
+#define RT5651_M_STO_DD_R2			(0x1 << 4)
+#define RT5651_M_STO_DD_R2_SFT			4
+#define RT5651_STO_DD_R2_VOL_MASK		(0x1 << 3)
+#define RT5651_STO_DD_R2_VOL_SFT		3
+#define RT5651_M_STO_DD_L2_R			(0x1 << 2)
+#define RT5651_M_STO_DD_L2_R_SFT		2
+#define RT5651_STO_DD_L2_R_VOL_MASK		(0x1 << 1)
+#define RT5651_STO_DD_L2_R_VOL_SFT		1
+
+/* Digital Mixer Control (0x2c) */
+#define RT5651_M_STO_L_DAC_L			(0x1 << 15)
+#define RT5651_M_STO_L_DAC_L_SFT		15
+#define RT5651_STO_L_DAC_L_VOL_MASK		(0x1 << 14)
+#define RT5651_STO_L_DAC_L_VOL_SFT		14
+#define RT5651_M_DAC_L2_DAC_L			(0x1 << 13)
+#define RT5651_M_DAC_L2_DAC_L_SFT		13
+#define RT5651_DAC_L2_DAC_L_VOL_MASK		(0x1 << 12)
+#define RT5651_DAC_L2_DAC_L_VOL_SFT		12
+#define RT5651_M_STO_R_DAC_R			(0x1 << 11)
+#define RT5651_M_STO_R_DAC_R_SFT		11
+#define RT5651_STO_R_DAC_R_VOL_MASK		(0x1 << 10)
+#define RT5651_STO_R_DAC_R_VOL_SFT		10
+#define RT5651_M_DAC_R2_DAC_R			(0x1 << 9)
+#define RT5651_M_DAC_R2_DAC_R_SFT		9
+#define RT5651_DAC_R2_DAC_R_VOL_MASK		(0x1 << 8)
+#define RT5651_DAC_R2_DAC_R_VOL_SFT		8
+
+/* DSP Path Control 1 (0x2d) */
+#define RT5651_RXDP_SRC_MASK			(0x1 << 15)
+#define RT5651_RXDP_SRC_SFT			15
+#define RT5651_RXDP_SRC_NOR			(0x0 << 15)
+#define RT5651_RXDP_SRC_DIV3			(0x1 << 15)
+#define RT5651_TXDP_SRC_MASK			(0x1 << 14)
+#define RT5651_TXDP_SRC_SFT			14
+#define RT5651_TXDP_SRC_NOR			(0x0 << 14)
+#define RT5651_TXDP_SRC_DIV3			(0x1 << 14)
+
+/* DSP Path Control 2 (0x2e) */
+#define RT5651_DAC_L2_SEL_MASK			(0x3 << 14)
+#define RT5651_DAC_L2_SEL_SFT			14
+#define RT5651_DAC_L2_SEL_IF2			(0x0 << 14)
+#define RT5651_DAC_L2_SEL_IF3			(0x1 << 14)
+#define RT5651_DAC_L2_SEL_TXDC			(0x2 << 14)
+#define RT5651_DAC_L2_SEL_BASS			(0x3 << 14)
+#define RT5651_DAC_R2_SEL_MASK			(0x3 << 12)
+#define RT5651_DAC_R2_SEL_SFT			12
+#define RT5651_DAC_R2_SEL_IF2			(0x0 << 12)
+#define RT5651_DAC_R2_SEL_IF3			(0x1 << 12)
+#define RT5651_DAC_R2_SEL_TXDC			(0x2 << 12)
+#define RT5651_IF2_ADC_L_SEL_MASK		(0x1 << 11)
+#define RT5651_IF2_ADC_L_SEL_SFT		11
+#define RT5651_IF2_ADC_L_SEL_TXDP		(0x0 << 11)
+#define RT5651_IF2_ADC_L_SEL_PASS		(0x1 << 11)
+#define RT5651_IF2_ADC_R_SEL_MASK		(0x1 << 10)
+#define RT5651_IF2_ADC_R_SEL_SFT		10
+#define RT5651_IF2_ADC_R_SEL_TXDP		(0x0 << 10)
+#define RT5651_IF2_ADC_R_SEL_PASS		(0x1 << 10)
+#define RT5651_RXDC_SEL_MASK			(0x3 << 8)
+#define RT5651_RXDC_SEL_SFT			8
+#define RT5651_RXDC_SEL_NOR			(0x0 << 8)
+#define RT5651_RXDC_SEL_L2R			(0x1 << 8)
+#define RT5651_RXDC_SEL_R2L			(0x2 << 8)
+#define RT5651_RXDC_SEL_SWAP			(0x3 << 8)
+#define RT5651_RXDP_SEL_MASK			(0x3 << 6)
+#define RT5651_RXDP_SEL_SFT			6
+#define RT5651_RXDP_SEL_NOR			(0x0 << 6)
+#define RT5651_RXDP_SEL_L2R			(0x1 << 6)
+#define RT5651_RXDP_SEL_R2L			(0x2 << 6)
+#define RT5651_RXDP_SEL_SWAP			(0x3 << 6)
+#define RT5651_TXDC_SEL_MASK			(0x3 << 4)
+#define RT5651_TXDC_SEL_SFT			4
+#define RT5651_TXDC_SEL_NOR			(0x0 << 4)
+#define RT5651_TXDC_SEL_L2R			(0x1 << 4)
+#define RT5651_TXDC_SEL_R2L			(0x2 << 4)
+#define RT5651_TXDC_SEL_SWAP			(0x3 << 4)
+#define RT5651_TXDP_SEL_MASK			(0x3 << 2)
+#define RT5651_TXDP_SEL_SFT			2
+#define RT5651_TXDP_SEL_NOR			(0x0 << 2)
+#define RT5651_TXDP_SEL_L2R			(0x1 << 2)
+#define RT5651_TXDP_SEL_R2L			(0x2 << 2)
+#define RT5651_TRXDP_SEL_SWAP			(0x3 << 2)
+
+/* Digital Interface Data Control (0x2f) */
+#define RT5651_IF2_DAC_SEL_MASK			(0x3 << 10)
+#define RT5651_IF2_DAC_SEL_SFT			10
+#define RT5651_IF2_DAC_SEL_NOR			(0x0 << 10)
+#define RT5651_IF2_DAC_SEL_SWAP			(0x1 << 10)
+#define RT5651_IF2_DAC_SEL_L2R			(0x2 << 10)
+#define RT5651_IF2_DAC_SEL_R2L			(0x3 << 10)
+#define RT5651_IF2_ADC_SEL_MASK			(0x3 << 8)
+#define RT5651_IF2_ADC_SEL_SFT			8
+#define RT5651_IF2_ADC_SEL_NOR			(0x0 << 8)
+#define RT5651_IF2_ADC_SEL_SWAP			(0x1 << 8)
+#define RT5651_IF2_ADC_SEL_L2R			(0x2 << 8)
+#define RT5651_IF2_ADC_SEL_R2L			(0x3 << 8)
+#define RT5651_IF2_ADC_SRC_MASK			(0x1 << 7)
+#define RT5651_IF2_ADC_SRC_SFT			7
+#define RT5651_IF1_ADC1				(0x0 << 7)
+#define RT5651_IF1_ADC2				(0x1 << 7)
+
+/* PDM Output Control (0x30) */
+#define RT5651_PDM_L_SEL_MASK			(0x1 << 15)
+#define RT5651_PDM_L_SEL_SFT			15
+#define RT5651_PDM_L_SEL_DD_L			(0x0 << 15)
+#define RT5651_PDM_L_SEL_STO_L			(0x1 << 15)
+#define RT5651_M_PDM_L				(0x1 << 14)
+#define RT5651_M_PDM_L_SFT			14
+#define RT5651_PDM_R_SEL_MASK			(0x1 << 13)
+#define RT5651_PDM_R_SEL_SFT			13
+#define RT5651_PDM_R_SEL_DD_L			(0x0 << 13)
+#define RT5651_PDM_R_SEL_STO_L			(0x1 << 13)
+#define RT5651_M_PDM_R				(0x1 << 12)
+#define RT5651_M_PDM_R_SFT			12
+#define RT5651_PDM_BUSY				(0x1 << 6)
+#define RT5651_PDM_BUSY_SFT			6
+#define RT5651_PDM_PATTERN_SEL_MASK		(0x1 << 5)
+#define RT5651_PDM_PATTERN_SEL_64		(0x0 << 5)
+#define RT5651_PDM_PATTERN_SEL_128		(0x1 << 5)
+#define RT5651_PDM_VOL_MASK			(0x1 << 4)
+#define RT5651_PDM_VOL_SFT			4
+#define RT5651_PDM_DIV_MASK			(0x3)
+#define RT5651_PDM_DIV_SFT			0
+#define RT5651_PDM_DIV_1			0
+#define RT5651_PDM_DIV_2			1
+#define RT5651_PDM_DIV_3			2
+#define RT5651_PDM_DIV_4			3
+
+/* PDM I2C/Data Control 1 (0x31) */
+#define RT5651_PDM_I2C_ID_MASK			(0xf << 12)
+#define PT5631_PDM_CMD_EXE			(0x1 << 11)
+#define RT5651_PDM_I2C_CMD_MASK			(0x1 << 10)
+#define RT5651_PDM_I2C_CMD_R			(0x0 << 10)
+#define RT5651_PDM_I2C_CMD_W			(0x1 << 10)
+#define RT5651_PDM_I2C_CMD_EXE			(0x1 << 9)
+#define RT5651_PDM_I2C_NORMAL			(0x0 << 8)
+#define RT5651_PDM_I2C_BUSY			(0x1 << 8)
+
+/* PDM I2C/Data Control 2 (0x32) */
+#define RT5651_PDM_I2C_ADDR			(0xff << 8)
+#define RT5651_PDM_I2C_CMD_PATTERN		(0xff)
+
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5651_G_LN_L2_RM_L_MASK		(0x7 << 13)
+#define RT5651_G_IN_L2_RM_L_SFT			13
+#define RT5651_G_LN_L1_RM_L_MASK		(0x7 << 10)
+#define RT5651_G_IN_L1_RM_L_SFT			10
+#define RT5651_G_BST3_RM_L_MASK			(0x7 << 4)
+#define RT5651_G_BST3_RM_L_SFT			4
+#define RT5651_G_BST2_RM_L_MASK			(0x7 << 1)
+#define RT5651_G_BST2_RM_L_SFT			1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5651_G_BST1_RM_L_MASK			(0x7 << 13)
+#define RT5651_G_BST1_RM_L_SFT			13
+#define RT5651_G_OM_L_RM_L_MASK			(0x7 << 10)
+#define RT5651_G_OM_L_RM_L_SFT			10
+#define RT5651_M_IN2_L_RM_L			(0x1 << 6)
+#define RT5651_M_IN2_L_RM_L_SFT			6
+#define RT5651_M_IN1_L_RM_L			(0x1 << 5)
+#define RT5651_M_IN1_L_RM_L_SFT			5
+#define RT5651_M_BST3_RM_L			(0x1 << 3)
+#define RT5651_M_BST3_RM_L_SFT			3
+#define RT5651_M_BST2_RM_L			(0x1 << 2)
+#define RT5651_M_BST2_RM_L_SFT			2
+#define RT5651_M_BST1_RM_L			(0x1 << 1)
+#define RT5651_M_BST1_RM_L_SFT			1
+#define RT5651_M_OM_L_RM_L			(0x1)
+#define RT5651_M_OM_L_RM_L_SFT			0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5651_G_IN2_R_RM_R_MASK		(0x7 << 13)
+#define RT5651_G_IN2_R_RM_R_SFT			13
+#define RT5651_G_IN1_R_RM_R_MASK		(0x7 << 10)
+#define RT5651_G_IN1_R_RM_R_SFT			10
+#define RT5651_G_BST3_RM_R_MASK			(0x7 << 4)
+#define RT5651_G_BST3_RM_R_SFT			4
+#define RT5651_G_BST2_RM_R_MASK			(0x7 << 1)
+#define RT5651_G_BST2_RM_R_SFT			1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5651_G_BST1_RM_R_MASK			(0x7 << 13)
+#define RT5651_G_BST1_RM_R_SFT			13
+#define RT5651_G_OM_R_RM_R_MASK			(0x7 << 10)
+#define RT5651_G_OM_R_RM_R_SFT			10
+#define RT5651_M_IN2_R_RM_R			(0x1 << 6)
+#define RT5651_M_IN2_R_RM_R_SFT			6
+#define RT5651_M_IN1_R_RM_R			(0x1 << 5)
+#define RT5651_M_IN1_R_RM_R_SFT			5
+#define RT5651_M_BST3_RM_R			(0x1 << 3)
+#define RT5651_M_BST3_RM_R_SFT			3
+#define RT5651_M_BST2_RM_R			(0x1 << 2)
+#define RT5651_M_BST2_RM_R_SFT			2
+#define RT5651_M_BST1_RM_R			(0x1 << 1)
+#define RT5651_M_BST1_RM_R_SFT			1
+#define RT5651_M_OM_R_RM_R			(0x1)
+#define RT5651_M_OM_R_RM_R_SFT			0
+
+/* HPMIX Control (0x45) */
+#define RT5651_M_DAC1_HM			(0x1 << 14)
+#define RT5651_M_DAC1_HM_SFT			14
+#define RT5651_M_HPVOL_HM			(0x1 << 13)
+#define RT5651_M_HPVOL_HM_SFT			13
+#define RT5651_G_HPOMIX_MASK			(0x1 << 12)
+#define RT5651_G_HPOMIX_SFT			12
+
+/* SPK Left Mixer Control (0x46) */
+#define RT5651_G_RM_L_SM_L_MASK			(0x3 << 14)
+#define RT5651_G_RM_L_SM_L_SFT			14
+#define RT5651_G_IN_L_SM_L_MASK			(0x3 << 12)
+#define RT5651_G_IN_L_SM_L_SFT			12
+#define RT5651_G_DAC_L1_SM_L_MASK		(0x3 << 10)
+#define RT5651_G_DAC_L1_SM_L_SFT		10
+#define RT5651_G_DAC_L2_SM_L_MASK		(0x3 << 8)
+#define RT5651_G_DAC_L2_SM_L_SFT		8
+#define RT5651_G_OM_L_SM_L_MASK			(0x3 << 6)
+#define RT5651_G_OM_L_SM_L_SFT			6
+#define RT5651_M_RM_L_SM_L			(0x1 << 5)
+#define RT5651_M_RM_L_SM_L_SFT			5
+#define RT5651_M_IN_L_SM_L			(0x1 << 4)
+#define RT5651_M_IN_L_SM_L_SFT			4
+#define RT5651_M_DAC_L1_SM_L			(0x1 << 3)
+#define RT5651_M_DAC_L1_SM_L_SFT		3
+#define RT5651_M_DAC_L2_SM_L			(0x1 << 2)
+#define RT5651_M_DAC_L2_SM_L_SFT		2
+#define RT5651_M_OM_L_SM_L			(0x1 << 1)
+#define RT5651_M_OM_L_SM_L_SFT			1
+
+/* SPK Right Mixer Control (0x47) */
+#define RT5651_G_RM_R_SM_R_MASK			(0x3 << 14)
+#define RT5651_G_RM_R_SM_R_SFT			14
+#define RT5651_G_IN_R_SM_R_MASK			(0x3 << 12)
+#define RT5651_G_IN_R_SM_R_SFT			12
+#define RT5651_G_DAC_R1_SM_R_MASK		(0x3 << 10)
+#define RT5651_G_DAC_R1_SM_R_SFT		10
+#define RT5651_G_DAC_R2_SM_R_MASK		(0x3 << 8)
+#define RT5651_G_DAC_R2_SM_R_SFT		8
+#define RT5651_G_OM_R_SM_R_MASK			(0x3 << 6)
+#define RT5651_G_OM_R_SM_R_SFT			6
+#define RT5651_M_RM_R_SM_R			(0x1 << 5)
+#define RT5651_M_RM_R_SM_R_SFT			5
+#define RT5651_M_IN_R_SM_R			(0x1 << 4)
+#define RT5651_M_IN_R_SM_R_SFT			4
+#define RT5651_M_DAC_R1_SM_R			(0x1 << 3)
+#define RT5651_M_DAC_R1_SM_R_SFT		3
+#define RT5651_M_DAC_R2_SM_R			(0x1 << 2)
+#define RT5651_M_DAC_R2_SM_R_SFT		2
+#define RT5651_M_OM_R_SM_R			(0x1 << 1)
+#define RT5651_M_OM_R_SM_R_SFT			1
+
+/* SPOLMIX Control (0x48) */
+#define RT5651_M_DAC_R1_SPM_L			(0x1 << 15)
+#define RT5651_M_DAC_R1_SPM_L_SFT		15
+#define RT5651_M_DAC_L1_SPM_L			(0x1 << 14)
+#define RT5651_M_DAC_L1_SPM_L_SFT		14
+#define RT5651_M_SV_R_SPM_L			(0x1 << 13)
+#define RT5651_M_SV_R_SPM_L_SFT			13
+#define RT5651_M_SV_L_SPM_L			(0x1 << 12)
+#define RT5651_M_SV_L_SPM_L_SFT			12
+#define RT5651_M_BST1_SPM_L			(0x1 << 11)
+#define RT5651_M_BST1_SPM_L_SFT			11
+
+/* SPORMIX Control (0x49) */
+#define RT5651_M_DAC_R1_SPM_R			(0x1 << 13)
+#define RT5651_M_DAC_R1_SPM_R_SFT		13
+#define RT5651_M_SV_R_SPM_R			(0x1 << 12)
+#define RT5651_M_SV_R_SPM_R_SFT			12
+#define RT5651_M_BST1_SPM_R			(0x1 << 11)
+#define RT5651_M_BST1_SPM_R_SFT			11
+
+/* SPOLMIX / SPORMIX Ratio Control (0x4a) */
+#define RT5651_SPO_CLSD_RATIO_MASK		(0x7)
+#define RT5651_SPO_CLSD_RATIO_SFT		0
+
+/* Mono Output Mixer Control (0x4c) */
+#define RT5651_M_DAC_R2_MM			(0x1 << 15)
+#define RT5651_M_DAC_R2_MM_SFT			15
+#define RT5651_M_DAC_L2_MM			(0x1 << 14)
+#define RT5651_M_DAC_L2_MM_SFT			14
+#define RT5651_M_OV_R_MM			(0x1 << 13)
+#define RT5651_M_OV_R_MM_SFT			13
+#define RT5651_M_OV_L_MM			(0x1 << 12)
+#define RT5651_M_OV_L_MM_SFT			12
+#define RT5651_M_BST1_MM			(0x1 << 11)
+#define RT5651_M_BST1_MM_SFT			11
+#define RT5651_G_MONOMIX_MASK			(0x1 << 10)
+#define RT5651_G_MONOMIX_SFT			10
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5651_G_BST2_OM_L_MASK			(0x7 << 10)
+#define RT5651_G_BST2_OM_L_SFT			10
+#define RT5651_G_BST1_OM_L_MASK			(0x7 << 7)
+#define RT5651_G_BST1_OM_L_SFT			7
+#define RT5651_G_IN1_L_OM_L_MASK		(0x7 << 4)
+#define RT5651_G_IN1_L_OM_L_SFT			4
+#define RT5651_G_RM_L_OM_L_MASK			(0x7 << 1)
+#define RT5651_G_RM_L_OM_L_SFT			1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5651_G_DAC_L1_OM_L_MASK		(0x7 << 7)
+#define RT5651_G_DAC_L1_OM_L_SFT		7
+#define RT5651_G_IN2_L_OM_L_MASK		(0x7 << 4)
+#define RT5651_G_IN2_L_OM_L_SFT			4
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5651_M_IN2_L_OM_L			(0x1 << 9)
+#define RT5651_M_IN2_L_OM_L_SFT			9
+#define RT5651_M_BST2_OM_L			(0x1 << 6)
+#define RT5651_M_BST2_OM_L_SFT			6
+#define RT5651_M_BST1_OM_L			(0x1 << 5)
+#define RT5651_M_BST1_OM_L_SFT			5
+#define RT5651_M_IN1_L_OM_L			(0x1 << 4)
+#define RT5651_M_IN1_L_OM_L_SFT			4
+#define RT5651_M_RM_L_OM_L			(0x1 << 3)
+#define RT5651_M_RM_L_OM_L_SFT			3
+#define RT5651_M_DAC_L1_OM_L			(0x1)
+#define RT5651_M_DAC_L1_OM_L_SFT		0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5651_G_BST2_OM_R_MASK			(0x7 << 10)
+#define RT5651_G_BST2_OM_R_SFT			10
+#define RT5651_G_BST1_OM_R_MASK			(0x7 << 7)
+#define RT5651_G_BST1_OM_R_SFT			7
+#define RT5651_G_IN1_R_OM_R_MASK		(0x7 << 4)
+#define RT5651_G_IN1_R_OM_R_SFT			4
+#define RT5651_G_RM_R_OM_R_MASK			(0x7 << 1)
+#define RT5651_G_RM_R_OM_R_SFT			1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5651_G_DAC_R1_OM_R_MASK		(0x7 << 7)
+#define RT5651_G_DAC_R1_OM_R_SFT		7
+#define RT5651_G_IN2_R_OM_R_MASK		(0x7 << 4)
+#define RT5651_G_IN2_R_OM_R_SFT			4
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5651_M_IN2_R_OM_R			(0x1 << 9)
+#define RT5651_M_IN2_R_OM_R_SFT			9
+#define RT5651_M_BST2_OM_R			(0x1 << 6)
+#define RT5651_M_BST2_OM_R_SFT			6
+#define RT5651_M_BST1_OM_R			(0x1 << 5)
+#define RT5651_M_BST1_OM_R_SFT			5
+#define RT5651_M_IN1_R_OM_R			(0x1 << 4)
+#define RT5651_M_IN1_R_OM_R_SFT			4
+#define RT5651_M_RM_R_OM_R			(0x1 << 3)
+#define RT5651_M_RM_R_OM_R_SFT			3
+#define RT5651_M_DAC_R1_OM_R			(0x1)
+#define RT5651_M_DAC_R1_OM_R_SFT		0
+
+/* LOUT Mixer Control (0x53) */
+#define RT5651_M_DAC_L1_LM			(0x1 << 15)
+#define RT5651_M_DAC_L1_LM_SFT			15
+#define RT5651_M_DAC_R1_LM			(0x1 << 14)
+#define RT5651_M_DAC_R1_LM_SFT			14
+#define RT5651_M_OV_L_LM			(0x1 << 13)
+#define RT5651_M_OV_L_LM_SFT			13
+#define RT5651_M_OV_R_LM			(0x1 << 12)
+#define RT5651_M_OV_R_LM_SFT			12
+#define RT5651_G_LOUTMIX_MASK			(0x1 << 11)
+#define RT5651_G_LOUTMIX_SFT			11
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5651_PWR_I2S1				(0x1 << 15)
+#define RT5651_PWR_I2S1_BIT			15
+#define RT5651_PWR_I2S2				(0x1 << 14)
+#define RT5651_PWR_I2S2_BIT			14
+#define RT5651_PWR_DAC_L1			(0x1 << 12)
+#define RT5651_PWR_DAC_L1_BIT			12
+#define RT5651_PWR_DAC_R1			(0x1 << 11)
+#define RT5651_PWR_DAC_R1_BIT			11
+#define RT5651_PWR_ADC_L			(0x1 << 2)
+#define RT5651_PWR_ADC_L_BIT			2
+#define RT5651_PWR_ADC_R			(0x1 << 1)
+#define RT5651_PWR_ADC_R_BIT			1
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5651_PWR_ADC_STO1_F			(0x1 << 15)
+#define RT5651_PWR_ADC_STO1_F_BIT			15
+#define RT5651_PWR_ADC_STO2_F			(0x1 << 14)
+#define RT5651_PWR_ADC_STO2_F_BIT		14
+#define RT5651_PWR_DAC_STO1_F			(0x1 << 11)
+#define RT5651_PWR_DAC_STO1_F_BIT			11
+#define RT5651_PWR_DAC_STO2_F			(0x1 << 10)
+#define RT5651_PWR_DAC_STO2_F_BIT		10
+#define RT5651_PWR_PDM				(0x1 << 9)
+#define RT5651_PWR_PDM_BIT			9
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5651_PWR_VREF1			(0x1 << 15)
+#define RT5651_PWR_VREF1_BIT			15
+#define RT5651_PWR_FV1				(0x1 << 14)
+#define RT5651_PWR_FV1_BIT			14
+#define RT5651_PWR_MB				(0x1 << 13)
+#define RT5651_PWR_MB_BIT			13
+#define RT5651_PWR_LM				(0x1 << 12)
+#define RT5651_PWR_LM_BIT			12
+#define RT5651_PWR_BG				(0x1 << 11)
+#define RT5651_PWR_BG_BIT			11
+#define RT5651_PWR_HP_L				(0x1 << 7)
+#define RT5651_PWR_HP_L_BIT			7
+#define RT5651_PWR_HP_R				(0x1 << 6)
+#define RT5651_PWR_HP_R_BIT			6
+#define RT5651_PWR_HA				(0x1 << 5)
+#define RT5651_PWR_HA_BIT			5
+#define RT5651_PWR_VREF2			(0x1 << 4)
+#define RT5651_PWR_VREF2_BIT			4
+#define RT5651_PWR_FV2				(0x1 << 3)
+#define RT5651_PWR_FV2_BIT			3
+#define RT5651_PWR_LDO				(0x1 << 2)
+#define RT5651_PWR_LDO_BIT			2
+#define RT5651_PWR_LDO_DVO_MASK			(0x3)
+#define RT5651_PWR_LDO_DVO_1_0V			0
+#define RT5651_PWR_LDO_DVO_1_1V			1
+#define RT5651_PWR_LDO_DVO_1_2V			2
+#define RT5651_PWR_LDO_DVO_1_3V			3
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5651_PWR_BST1				(0x1 << 15)
+#define RT5651_PWR_BST1_BIT			15
+#define RT5651_PWR_BST2				(0x1 << 14)
+#define RT5651_PWR_BST2_BIT			14
+#define RT5651_PWR_BST3				(0x1 << 13)
+#define RT5651_PWR_BST3_BIT			13
+#define RT5651_PWR_MB1				(0x1 << 11)
+#define RT5651_PWR_MB1_BIT			11
+#define RT5651_PWR_PLL				(0x1 << 9)
+#define RT5651_PWR_PLL_BIT			9
+#define RT5651_PWR_BST1_OP2			(0x1 << 5)
+#define RT5651_PWR_BST1_OP2_BIT			5
+#define RT5651_PWR_BST2_OP2			(0x1 << 4)
+#define RT5651_PWR_BST2_OP2_BIT			4
+#define RT5651_PWR_BST3_OP2			(0x1 << 3)
+#define RT5651_PWR_BST3_OP2_BIT			3
+#define RT5651_PWR_JD_M				(0x1 << 2)
+#define RT5651_PWM_JD_M_BIT			2
+#define RT5651_PWR_JD2				(0x1 << 1)
+#define RT5651_PWM_JD2_BIT			1
+#define RT5651_PWR_JD3				(0x1)
+#define RT5651_PWM_JD3_BIT			0
+
+/* Power Management for Mixer (0x65) */
+#define RT5651_PWR_OM_L				(0x1 << 15)
+#define RT5651_PWR_OM_L_BIT			15
+#define RT5651_PWR_OM_R				(0x1 << 14)
+#define RT5651_PWR_OM_R_BIT			14
+#define RT5651_PWR_RM_L				(0x1 << 11)
+#define RT5651_PWR_RM_L_BIT			11
+#define RT5651_PWR_RM_R				(0x1 << 10)
+#define RT5651_PWR_RM_R_BIT			10
+
+/* Power Management for Volume (0x66) */
+#define RT5651_PWR_OV_L				(0x1 << 13)
+#define RT5651_PWR_OV_L_BIT			13
+#define RT5651_PWR_OV_R				(0x1 << 12)
+#define RT5651_PWR_OV_R_BIT			12
+#define RT5651_PWR_HV_L				(0x1 << 11)
+#define RT5651_PWR_HV_L_BIT			11
+#define RT5651_PWR_HV_R				(0x1 << 10)
+#define RT5651_PWR_HV_R_BIT			10
+#define RT5651_PWR_IN1_L			(0x1 << 9)
+#define RT5651_PWR_IN1_L_BIT			9
+#define RT5651_PWR_IN1_R			(0x1 << 8)
+#define RT5651_PWR_IN1_R_BIT			8
+#define RT5651_PWR_IN2_L			(0x1 << 7)
+#define RT5651_PWR_IN2_L_BIT			7
+#define RT5651_PWR_IN2_R			(0x1 << 6)
+#define RT5651_PWR_IN2_R_BIT			6
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71) */
+#define RT5651_I2S_MS_MASK			(0x1 << 15)
+#define RT5651_I2S_MS_SFT			15
+#define RT5651_I2S_MS_M				(0x0 << 15)
+#define RT5651_I2S_MS_S				(0x1 << 15)
+#define RT5651_I2S_O_CP_MASK			(0x3 << 10)
+#define RT5651_I2S_O_CP_SFT			10
+#define RT5651_I2S_O_CP_OFF			(0x0 << 10)
+#define RT5651_I2S_O_CP_U_LAW			(0x1 << 10)
+#define RT5651_I2S_O_CP_A_LAW			(0x2 << 10)
+#define RT5651_I2S_I_CP_MASK			(0x3 << 8)
+#define RT5651_I2S_I_CP_SFT			8
+#define RT5651_I2S_I_CP_OFF			(0x0 << 8)
+#define RT5651_I2S_I_CP_U_LAW			(0x1 << 8)
+#define RT5651_I2S_I_CP_A_LAW			(0x2 << 8)
+#define RT5651_I2S_BP_MASK			(0x1 << 7)
+#define RT5651_I2S_BP_SFT			7
+#define RT5651_I2S_BP_NOR			(0x0 << 7)
+#define RT5651_I2S_BP_INV			(0x1 << 7)
+#define RT5651_I2S_DL_MASK			(0x3 << 2)
+#define RT5651_I2S_DL_SFT			2
+#define RT5651_I2S_DL_16			(0x0 << 2)
+#define RT5651_I2S_DL_20			(0x1 << 2)
+#define RT5651_I2S_DL_24			(0x2 << 2)
+#define RT5651_I2S_DL_8				(0x3 << 2)
+#define RT5651_I2S_DF_MASK			(0x3)
+#define RT5651_I2S_DF_SFT			0
+#define RT5651_I2S_DF_I2S			(0x0)
+#define RT5651_I2S_DF_LEFT			(0x1)
+#define RT5651_I2S_DF_PCM_A			(0x2)
+#define RT5651_I2S_DF_PCM_B			(0x3)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5651_I2S_PD1_MASK			(0x7 << 12)
+#define RT5651_I2S_PD1_SFT			12
+#define RT5651_I2S_PD1_1			(0x0 << 12)
+#define RT5651_I2S_PD1_2			(0x1 << 12)
+#define RT5651_I2S_PD1_3			(0x2 << 12)
+#define RT5651_I2S_PD1_4			(0x3 << 12)
+#define RT5651_I2S_PD1_6			(0x4 << 12)
+#define RT5651_I2S_PD1_8			(0x5 << 12)
+#define RT5651_I2S_PD1_12			(0x6 << 12)
+#define RT5651_I2S_PD1_16			(0x7 << 12)
+#define RT5651_I2S_BCLK_MS2_MASK		(0x1 << 11)
+#define RT5651_I2S_BCLK_MS2_SFT			11
+#define RT5651_I2S_BCLK_MS2_32			(0x0 << 11)
+#define RT5651_I2S_BCLK_MS2_64			(0x1 << 11)
+#define RT5651_I2S_PD2_MASK			(0x7 << 8)
+#define RT5651_I2S_PD2_SFT			8
+#define RT5651_I2S_PD2_1			(0x0 << 8)
+#define RT5651_I2S_PD2_2			(0x1 << 8)
+#define RT5651_I2S_PD2_3			(0x2 << 8)
+#define RT5651_I2S_PD2_4			(0x3 << 8)
+#define RT5651_I2S_PD2_6			(0x4 << 8)
+#define RT5651_I2S_PD2_8			(0x5 << 8)
+#define RT5651_I2S_PD2_12			(0x6 << 8)
+#define RT5651_I2S_PD2_16			(0x7 << 8)
+#define RT5651_DAC_OSR_MASK			(0x3 << 2)
+#define RT5651_DAC_OSR_SFT			2
+#define RT5651_DAC_OSR_128			(0x0 << 2)
+#define RT5651_DAC_OSR_64			(0x1 << 2)
+#define RT5651_DAC_OSR_32			(0x2 << 2)
+#define RT5651_DAC_OSR_128_3			(0x3 << 2)
+#define RT5651_ADC_OSR_MASK			(0x3)
+#define RT5651_ADC_OSR_SFT			0
+#define RT5651_ADC_OSR_128			(0x0)
+#define RT5651_ADC_OSR_64			(0x1)
+#define RT5651_ADC_OSR_32			(0x2)
+#define RT5651_ADC_OSR_128_3			(0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5651_DAHPF_EN				(0x1 << 11)
+#define RT5651_DAHPF_EN_SFT			11
+#define RT5651_ADHPF_EN				(0x1 << 10)
+#define RT5651_ADHPF_EN_SFT			10
+
+/* Digital Microphone Control (0x75) */
+#define RT5651_DMIC_1_EN_MASK			(0x1 << 15)
+#define RT5651_DMIC_1_EN_SFT			15
+#define RT5651_DMIC_1_DIS			(0x0 << 15)
+#define RT5651_DMIC_1_EN			(0x1 << 15)
+#define RT5651_DMIC_1L_LH_MASK			(0x1 << 13)
+#define RT5651_DMIC_1L_LH_SFT			13
+#define RT5651_DMIC_1L_LH_FALLING		(0x0 << 13)
+#define RT5651_DMIC_1L_LH_RISING		(0x1 << 13)
+#define RT5651_DMIC_1R_LH_MASK			(0x1 << 12)
+#define RT5651_DMIC_1R_LH_SFT			12
+#define RT5651_DMIC_1R_LH_FALLING		(0x0 << 12)
+#define RT5651_DMIC_1R_LH_RISING		(0x1 << 12)
+#define RT5651_DMIC_1_DP_MASK			(0x3 << 10)
+#define RT5651_DMIC_1_DP_SFT			10
+#define RT5651_DMIC_1_DP_GPIO6			(0x0 << 10)
+#define RT5651_DMIC_1_DP_IN1P			(0x1 << 10)
+#define RT5651_DMIC_2_DP_GPIO8			(0x2 << 10)
+#define RT5651_DMIC_CLK_MASK			(0x7 << 5)
+#define RT5651_DMIC_CLK_SFT			5
+
+/* TDM Control 1 (0x77) */
+#define RT5651_TDM_INTEL_SEL_MASK		(0x1 << 15)
+#define RT5651_TDM_INTEL_SEL_SFT		15
+#define RT5651_TDM_INTEL_SEL_64			(0x0 << 15)
+#define RT5651_TDM_INTEL_SEL_50			(0x1 << 15)
+#define RT5651_TDM_MODE_SEL_MASK		(0x1 << 14)
+#define RT5651_TDM_MODE_SEL_SFT			14
+#define RT5651_TDM_MODE_SEL_NOR			(0x0 << 14)
+#define RT5651_TDM_MODE_SEL_TDM			(0x1 << 14)
+#define RT5651_TDM_CH_NUM_SEL_MASK		(0x3 << 12)
+#define RT5651_TDM_CH_NUM_SEL_SFT		12
+#define RT5651_TDM_CH_NUM_SEL_2			(0x0 << 12)
+#define RT5651_TDM_CH_NUM_SEL_4			(0x1 << 12)
+#define RT5651_TDM_CH_NUM_SEL_6			(0x2 << 12)
+#define RT5651_TDM_CH_NUM_SEL_8			(0x3 << 12)
+#define RT5651_TDM_CH_LEN_SEL_MASK		(0x3 << 10)
+#define RT5651_TDM_CH_LEN_SEL_SFT		10
+#define RT5651_TDM_CH_LEN_SEL_16		(0x0 << 10)
+#define RT5651_TDM_CH_LEN_SEL_20		(0x1 << 10)
+#define RT5651_TDM_CH_LEN_SEL_24		(0x2 << 10)
+#define RT5651_TDM_CH_LEN_SEL_32		(0x3 << 10)
+#define RT5651_TDM_ADC_SEL_MASK			(0x1 << 9)
+#define RT5651_TDM_ADC_SEL_SFT			9
+#define RT5651_TDM_ADC_SEL_NOR			(0x0 << 9)
+#define RT5651_TDM_ADC_SEL_SWAP			(0x1 << 9)
+#define RT5651_TDM_ADC_START_SEL_MASK		(0x1 << 8)
+#define RT5651_TDM_ADC_START_SEL_SFT		8
+#define RT5651_TDM_ADC_START_SEL_SL0		(0x0 << 8)
+#define RT5651_TDM_ADC_START_SEL_SL4		(0x1 << 8)
+#define RT5651_TDM_I2S_CH2_SEL_MASK		(0x3 << 6)
+#define RT5651_TDM_I2S_CH2_SEL_SFT		6
+#define RT5651_TDM_I2S_CH2_SEL_LR		(0x0 << 6)
+#define RT5651_TDM_I2S_CH2_SEL_RL		(0x1 << 6)
+#define RT5651_TDM_I2S_CH2_SEL_LL		(0x2 << 6)
+#define RT5651_TDM_I2S_CH2_SEL_RR		(0x3 << 6)
+#define RT5651_TDM_I2S_CH4_SEL_MASK		(0x3 << 4)
+#define RT5651_TDM_I2S_CH4_SEL_SFT		4
+#define RT5651_TDM_I2S_CH4_SEL_LR		(0x0 << 4)
+#define RT5651_TDM_I2S_CH4_SEL_RL		(0x1 << 4)
+#define RT5651_TDM_I2S_CH4_SEL_LL		(0x2 << 4)
+#define RT5651_TDM_I2S_CH4_SEL_RR		(0x3 << 4)
+#define RT5651_TDM_I2S_CH6_SEL_MASK		(0x3 << 2)
+#define RT5651_TDM_I2S_CH6_SEL_SFT		2
+#define RT5651_TDM_I2S_CH6_SEL_LR		(0x0 << 2)
+#define RT5651_TDM_I2S_CH6_SEL_RL		(0x1 << 2)
+#define RT5651_TDM_I2S_CH6_SEL_LL		(0x2 << 2)
+#define RT5651_TDM_I2S_CH6_SEL_RR		(0x3 << 2)
+#define RT5651_TDM_I2S_CH8_SEL_MASK		(0x3)
+#define RT5651_TDM_I2S_CH8_SEL_SFT		0
+#define RT5651_TDM_I2S_CH8_SEL_LR		(0x0)
+#define RT5651_TDM_I2S_CH8_SEL_RL		(0x1)
+#define RT5651_TDM_I2S_CH8_SEL_LL		(0x2)
+#define RT5651_TDM_I2S_CH8_SEL_RR		(0x3)
+
+/* TDM Control 2 (0x78) */
+#define RT5651_TDM_LRCK_POL_SEL_MASK		(0x1 << 15)
+#define RT5651_TDM_LRCK_POL_SEL_SFT		15
+#define RT5651_TDM_LRCK_POL_SEL_NOR		(0x0 << 15)
+#define RT5651_TDM_LRCK_POL_SEL_INV		(0x1 << 15)
+#define RT5651_TDM_CH_VAL_SEL_MASK		(0x1 << 14)
+#define RT5651_TDM_CH_VAL_SEL_SFT		14
+#define RT5651_TDM_CH_VAL_SEL_CH01		(0x0 << 14)
+#define RT5651_TDM_CH_VAL_SEL_CH0123		(0x1 << 14)
+#define RT5651_TDM_CH_VAL_EN			(0x1 << 13)
+#define RT5651_TDM_CH_VAL_SFT			13
+#define RT5651_TDM_LPBK_EN			(0x1 << 12)
+#define RT5651_TDM_LPBK_SFT			12
+#define RT5651_TDM_LRCK_PULSE_SEL_MASK		(0x1 << 11)
+#define RT5651_TDM_LRCK_PULSE_SEL_SFT		11
+#define RT5651_TDM_LRCK_PULSE_SEL_BCLK		(0x0 << 11)
+#define RT5651_TDM_LRCK_PULSE_SEL_CH		(0x1 << 11)
+#define RT5651_TDM_END_EDGE_SEL_MASK		(0x1 << 10)
+#define RT5651_TDM_END_EDGE_SEL_SFT		10
+#define RT5651_TDM_END_EDGE_SEL_POS		(0x0 << 10)
+#define RT5651_TDM_END_EDGE_SEL_NEG		(0x1 << 10)
+#define RT5651_TDM_END_EDGE_EN			(0x1 << 9)
+#define RT5651_TDM_END_EDGE_EN_SFT		9
+#define RT5651_TDM_TRAN_EDGE_SEL_MASK		(0x1 << 8)
+#define RT5651_TDM_TRAN_EDGE_SEL_SFT		8
+#define RT5651_TDM_TRAN_EDGE_SEL_POS		(0x0 << 8)
+#define RT5651_TDM_TRAN_EDGE_SEL_NEG		(0x1 << 8)
+#define RT5651_M_TDM2_L				(0x1 << 7)
+#define RT5651_M_TDM2_L_SFT			7
+#define RT5651_M_TDM2_R				(0x1 << 6)
+#define RT5651_M_TDM2_R_SFT			6
+#define RT5651_M_TDM4_L				(0x1 << 5)
+#define RT5651_M_TDM4_L_SFT			5
+#define RT5651_M_TDM4_R				(0x1 << 4)
+#define RT5651_M_TDM4_R_SFT			4
+
+/* TDM Control 3 (0x79) */
+#define RT5651_CH2_L_SEL_MASK			(0x7 << 12)
+#define RT5651_CH2_L_SEL_SFT			12
+#define RT5651_CH2_L_SEL_SL0			(0x0 << 12)
+#define RT5651_CH2_L_SEL_SL1			(0x1 << 12)
+#define RT5651_CH2_L_SEL_SL2			(0x2 << 12)
+#define RT5651_CH2_L_SEL_SL3			(0x3 << 12)
+#define RT5651_CH2_L_SEL_SL4			(0x4 << 12)
+#define RT5651_CH2_L_SEL_SL5			(0x5 << 12)
+#define RT5651_CH2_L_SEL_SL6			(0x6 << 12)
+#define RT5651_CH2_L_SEL_SL7			(0x7 << 12)
+#define RT5651_CH2_R_SEL_MASK			(0x7 << 8)
+#define RT5651_CH2_R_SEL_SFT			8
+#define RT5651_CH2_R_SEL_SL0			(0x0 << 8)
+#define RT5651_CH2_R_SEL_SL1			(0x1 << 8)
+#define RT5651_CH2_R_SEL_SL2			(0x2 << 8)
+#define RT5651_CH2_R_SEL_SL3			(0x3 << 8)
+#define RT5651_CH2_R_SEL_SL4			(0x4 << 8)
+#define RT5651_CH2_R_SEL_SL5			(0x5 << 8)
+#define RT5651_CH2_R_SEL_SL6			(0x6 << 8)
+#define RT5651_CH2_R_SEL_SL7			(0x7 << 8)
+#define RT5651_CH4_L_SEL_MASK			(0x7 << 4)
+#define RT5651_CH4_L_SEL_SFT			4
+#define RT5651_CH4_L_SEL_SL0			(0x0 << 4)
+#define RT5651_CH4_L_SEL_SL1			(0x1 << 4)
+#define RT5651_CH4_L_SEL_SL2			(0x2 << 4)
+#define RT5651_CH4_L_SEL_SL3			(0x3 << 4)
+#define RT5651_CH4_L_SEL_SL4			(0x4 << 4)
+#define RT5651_CH4_L_SEL_SL5			(0x5 << 4)
+#define RT5651_CH4_L_SEL_SL6			(0x6 << 4)
+#define RT5651_CH4_L_SEL_SL7			(0x7 << 4)
+#define RT5651_CH4_R_SEL_MASK			(0x7)
+#define RT5651_CH4_R_SEL_SFT			0
+#define RT5651_CH4_R_SEL_SL0			(0x0)
+#define RT5651_CH4_R_SEL_SL1			(0x1)
+#define RT5651_CH4_R_SEL_SL2			(0x2)
+#define RT5651_CH4_R_SEL_SL3			(0x3)
+#define RT5651_CH4_R_SEL_SL4			(0x4)
+#define RT5651_CH4_R_SEL_SL5			(0x5)
+#define RT5651_CH4_R_SEL_SL6			(0x6)
+#define RT5651_CH4_R_SEL_SL7			(0x7)
+
+/* Global Clock Control (0x80) */
+#define RT5651_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5651_SCLK_SRC_SFT			14
+#define RT5651_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5651_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5651_SCLK_SRC_RCCLK			(0x2 << 14)
+#define RT5651_PLL1_SRC_MASK			(0x3 << 12)
+#define RT5651_PLL1_SRC_SFT			12
+#define RT5651_PLL1_SRC_MCLK			(0x0 << 12)
+#define RT5651_PLL1_SRC_BCLK1			(0x1 << 12)
+#define RT5651_PLL1_SRC_BCLK2			(0x2 << 12)
+#define RT5651_PLL1_PD_MASK			(0x1 << 3)
+#define RT5651_PLL1_PD_SFT			3
+#define RT5651_PLL1_PD_1			(0x0 << 3)
+#define RT5651_PLL1_PD_2			(0x1 << 3)
+
+#define RT5651_PLL_INP_MAX			40000000
+#define RT5651_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5651_PLL_N_MAX			0x1ff
+#define RT5651_PLL_N_MASK			(RT5651_PLL_N_MAX << 7)
+#define RT5651_PLL_N_SFT			7
+#define RT5651_PLL_K_MAX			0x1f
+#define RT5651_PLL_K_MASK			(RT5651_PLL_K_MAX)
+#define RT5651_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5651_PLL_M_MAX			0xf
+#define RT5651_PLL_M_MASK			(RT5651_PLL_M_MAX << 12)
+#define RT5651_PLL_M_SFT			12
+#define RT5651_PLL_M_BP				(0x1 << 11)
+#define RT5651_PLL_M_BP_SFT			11
+
+/* PLL tracking mode 1 (0x83) */
+#define RT5651_STO1_T_MASK			(0x1 << 15)
+#define RT5651_STO1_T_SFT			15
+#define RT5651_STO1_T_SCLK			(0x0 << 15)
+#define RT5651_STO1_T_LRCK1			(0x1 << 15)
+#define RT5651_STO2_T_MASK			(0x1 << 12)
+#define RT5651_STO2_T_SFT			12
+#define RT5651_STO2_T_I2S2			(0x0 << 12)
+#define RT5651_STO2_T_LRCK2			(0x1 << 12)
+#define RT5651_ASRC2_REF_MASK			(0x1 << 11)
+#define RT5651_ASRC2_REF_SFT			11
+#define RT5651_ASRC2_REF_LRCK2			(0x0 << 11)
+#define RT5651_ASRC2_REF_LRCK1			(0x1 << 11)
+#define RT5651_DMIC_1_M_MASK			(0x1 << 9)
+#define RT5651_DMIC_1_M_SFT			9
+#define RT5651_DMIC_1_M_NOR			(0x0 << 9)
+#define RT5651_DMIC_1_M_ASYN			(0x1 << 9)
+
+/* PLL tracking mode 2 (0x84) */
+#define RT5651_STO1_ASRC_EN			(0x1 << 15)
+#define RT5651_STO1_ASRC_EN_SFT			15
+#define RT5651_STO2_ASRC_EN			(0x1 << 14)
+#define RT5651_STO2_ASRC_EN_SFT			14
+#define RT5651_STO1_DAC_M_MASK			(0x1 << 13)
+#define RT5651_STO1_DAC_M_SFT			13
+#define RT5651_STO1_DAC_M_NOR			(0x0 << 13)
+#define RT5651_STO1_DAC_M_ASRC			(0x1 << 13)
+#define RT5651_STO2_DAC_M_MASK			(0x1 << 12)
+#define RT5651_STO2_DAC_M_SFT			12
+#define RT5651_STO2_DAC_M_NOR			(0x0 << 12)
+#define RT5651_STO2_DAC_M_ASRC			(0x1 << 12)
+#define RT5651_ADC_M_MASK			(0x1 << 11)
+#define RT5651_ADC_M_SFT			11
+#define RT5651_ADC_M_NOR			(0x0 << 11)
+#define RT5651_ADC_M_ASRC			(0x1 << 11)
+#define RT5651_I2S1_R_D_MASK			(0x1 << 4)
+#define RT5651_I2S1_R_D_SFT			4
+#define RT5651_I2S1_R_D_DIS			(0x0 << 4)
+#define RT5651_I2S1_R_D_EN			(0x1 << 4)
+#define RT5651_I2S2_R_D_MASK			(0x1 << 3)
+#define RT5651_I2S2_R_D_SFT			3
+#define RT5651_I2S2_R_D_DIS			(0x0 << 3)
+#define RT5651_I2S2_R_D_EN			(0x1 << 3)
+#define RT5651_PRE_SCLK_MASK			(0x3)
+#define RT5651_PRE_SCLK_SFT			0
+#define RT5651_PRE_SCLK_512			(0x0)
+#define RT5651_PRE_SCLK_1024			(0x1)
+#define RT5651_PRE_SCLK_2048			(0x2)
+
+/* PLL tracking mode 3 (0x85) */
+#define RT5651_I2S1_RATE_MASK			(0xf << 12)
+#define RT5651_I2S1_RATE_SFT			12
+#define RT5651_I2S2_RATE_MASK			(0xf << 8)
+#define RT5651_I2S2_RATE_SFT			8
+#define RT5651_G_ASRC_LP_MASK			(0x1 << 3)
+#define RT5651_G_ASRC_LP_SFT			3
+#define RT5651_ASRC_LP_F_M			(0x1 << 2)
+#define RT5651_ASRC_LP_F_SFT			2
+#define RT5651_ASRC_LP_F_NOR			(0x0 << 2)
+#define RT5651_ASRC_LP_F_SB			(0x1 << 2)
+#define RT5651_FTK_PH_DET_MASK			(0x3)
+#define RT5651_FTK_PH_DET_SFT			0
+#define RT5651_FTK_PH_DET_DIV1			(0x0)
+#define RT5651_FTK_PH_DET_DIV2			(0x1)
+#define RT5651_FTK_PH_DET_DIV4			(0x2)
+#define RT5651_FTK_PH_DET_DIV8			(0x3)
+
+/*PLL tracking mode 6 (0x89) */
+#define RT5651_I2S1_PD_MASK			(0x7 << 12)
+#define RT5651_I2S1_PD_SFT			12
+#define RT5651_I2S2_PD_MASK			(0x7 << 8)
+#define RT5651_I2S2_PD_SFT			8
+
+/*PLL tracking mode 7 (0x8a) */
+#define RT5651_FSI1_RATE_MASK			(0xf << 12)
+#define RT5651_FSI1_RATE_SFT			12
+#define RT5651_FSI2_RATE_MASK			(0xf << 8)
+#define RT5651_FSI2_RATE_SFT			8
+
+/* HPOUT Over Current Detection (0x8b) */
+#define RT5651_HP_OVCD_MASK			(0x1 << 10)
+#define RT5651_HP_OVCD_SFT			10
+#define RT5651_HP_OVCD_DIS			(0x0 << 10)
+#define RT5651_HP_OVCD_EN			(0x1 << 10)
+#define RT5651_HP_OC_TH_MASK			(0x3 << 8)
+#define RT5651_HP_OC_TH_SFT			8
+#define RT5651_HP_OC_TH_90			(0x0 << 8)
+#define RT5651_HP_OC_TH_105			(0x1 << 8)
+#define RT5651_HP_OC_TH_120			(0x2 << 8)
+#define RT5651_HP_OC_TH_135			(0x3 << 8)
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5651_SMT_TRIG_MASK			(0x1 << 15)
+#define RT5651_SMT_TRIG_SFT			15
+#define RT5651_SMT_TRIG_DIS			(0x0 << 15)
+#define RT5651_SMT_TRIG_EN			(0x1 << 15)
+#define RT5651_HP_L_SMT_MASK			(0x1 << 9)
+#define RT5651_HP_L_SMT_SFT			9
+#define RT5651_HP_L_SMT_DIS			(0x0 << 9)
+#define RT5651_HP_L_SMT_EN			(0x1 << 9)
+#define RT5651_HP_R_SMT_MASK			(0x1 << 8)
+#define RT5651_HP_R_SMT_SFT			8
+#define RT5651_HP_R_SMT_DIS			(0x0 << 8)
+#define RT5651_HP_R_SMT_EN			(0x1 << 8)
+#define RT5651_HP_CD_PD_MASK			(0x1 << 7)
+#define RT5651_HP_CD_PD_SFT			7
+#define RT5651_HP_CD_PD_DIS			(0x0 << 7)
+#define RT5651_HP_CD_PD_EN			(0x1 << 7)
+#define RT5651_RSTN_MASK			(0x1 << 6)
+#define RT5651_RSTN_SFT				6
+#define RT5651_RSTN_DIS				(0x0 << 6)
+#define RT5651_RSTN_EN				(0x1 << 6)
+#define RT5651_RSTP_MASK			(0x1 << 5)
+#define RT5651_RSTP_SFT				5
+#define RT5651_RSTP_DIS				(0x0 << 5)
+#define RT5651_RSTP_EN				(0x1 << 5)
+#define RT5651_HP_CO_MASK			(0x1 << 4)
+#define RT5651_HP_CO_SFT			4
+#define RT5651_HP_CO_DIS			(0x0 << 4)
+#define RT5651_HP_CO_EN				(0x1 << 4)
+#define RT5651_HP_CP_MASK			(0x1 << 3)
+#define RT5651_HP_CP_SFT			3
+#define RT5651_HP_CP_PD				(0x0 << 3)
+#define RT5651_HP_CP_PU				(0x1 << 3)
+#define RT5651_HP_SG_MASK			(0x1 << 2)
+#define RT5651_HP_SG_SFT			2
+#define RT5651_HP_SG_DIS			(0x0 << 2)
+#define RT5651_HP_SG_EN				(0x1 << 2)
+#define RT5651_HP_DP_MASK			(0x1 << 1)
+#define RT5651_HP_DP_SFT			1
+#define RT5651_HP_DP_PD				(0x0 << 1)
+#define RT5651_HP_DP_PU				(0x1 << 1)
+#define RT5651_HP_CB_MASK			(0x1)
+#define RT5651_HP_CB_SFT			0
+#define RT5651_HP_CB_PD				(0x0)
+#define RT5651_HP_CB_PU				(0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5651_DEPOP_MASK			(0x1 << 13)
+#define RT5651_DEPOP_SFT			13
+#define RT5651_DEPOP_AUTO			(0x0 << 13)
+#define RT5651_DEPOP_MAN			(0x1 << 13)
+#define RT5651_RAMP_MASK			(0x1 << 12)
+#define RT5651_RAMP_SFT				12
+#define RT5651_RAMP_DIS				(0x0 << 12)
+#define RT5651_RAMP_EN				(0x1 << 12)
+#define RT5651_BPS_MASK				(0x1 << 11)
+#define RT5651_BPS_SFT				11
+#define RT5651_BPS_DIS				(0x0 << 11)
+#define RT5651_BPS_EN				(0x1 << 11)
+#define RT5651_FAST_UPDN_MASK			(0x1 << 10)
+#define RT5651_FAST_UPDN_SFT			10
+#define RT5651_FAST_UPDN_DIS			(0x0 << 10)
+#define RT5651_FAST_UPDN_EN			(0x1 << 10)
+#define RT5651_MRES_MASK			(0x3 << 8)
+#define RT5651_MRES_SFT				8
+#define RT5651_MRES_15MO			(0x0 << 8)
+#define RT5651_MRES_25MO			(0x1 << 8)
+#define RT5651_MRES_35MO			(0x2 << 8)
+#define RT5651_MRES_45MO			(0x3 << 8)
+#define RT5651_VLO_MASK				(0x1 << 7)
+#define RT5651_VLO_SFT				7
+#define RT5651_VLO_3V				(0x0 << 7)
+#define RT5651_VLO_32V				(0x1 << 7)
+#define RT5651_DIG_DP_MASK			(0x1 << 6)
+#define RT5651_DIG_DP_SFT			6
+#define RT5651_DIG_DP_DIS			(0x0 << 6)
+#define RT5651_DIG_DP_EN			(0x1 << 6)
+#define RT5651_DP_TH_MASK			(0x3 << 4)
+#define RT5651_DP_TH_SFT			4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5651_CP_SYS_MASK			(0x7 << 12)
+#define RT5651_CP_SYS_SFT			12
+#define RT5651_CP_FQ1_MASK			(0x7 << 8)
+#define RT5651_CP_FQ1_SFT			8
+#define RT5651_CP_FQ2_MASK			(0x7 << 4)
+#define RT5651_CP_FQ2_SFT			4
+#define RT5651_CP_FQ3_MASK			(0x7)
+#define RT5651_CP_FQ3_SFT			0
+#define RT5651_CP_FQ_1_5_KHZ			0
+#define RT5651_CP_FQ_3_KHZ			1
+#define RT5651_CP_FQ_6_KHZ			2
+#define RT5651_CP_FQ_12_KHZ			3
+#define RT5651_CP_FQ_24_KHZ			4
+#define RT5651_CP_FQ_48_KHZ			5
+#define RT5651_CP_FQ_96_KHZ			6
+#define RT5651_CP_FQ_192_KHZ			7
+
+/* HPOUT charge pump (0x91) */
+#define RT5651_OSW_L_MASK			(0x1 << 11)
+#define RT5651_OSW_L_SFT			11
+#define RT5651_OSW_L_DIS			(0x0 << 11)
+#define RT5651_OSW_L_EN				(0x1 << 11)
+#define RT5651_OSW_R_MASK			(0x1 << 10)
+#define RT5651_OSW_R_SFT			10
+#define RT5651_OSW_R_DIS			(0x0 << 10)
+#define RT5651_OSW_R_EN				(0x1 << 10)
+#define RT5651_PM_HP_MASK			(0x3 << 8)
+#define RT5651_PM_HP_SFT			8
+#define RT5651_PM_HP_LV				(0x0 << 8)
+#define RT5651_PM_HP_MV				(0x1 << 8)
+#define RT5651_PM_HP_HV				(0x2 << 8)
+#define RT5651_IB_HP_MASK			(0x3 << 6)
+#define RT5651_IB_HP_SFT			6
+#define RT5651_IB_HP_125IL			(0x0 << 6)
+#define RT5651_IB_HP_25IL			(0x1 << 6)
+#define RT5651_IB_HP_5IL			(0x2 << 6)
+#define RT5651_IB_HP_1IL			(0x3 << 6)
+
+/* Micbias Control (0x93) */
+#define RT5651_MIC1_BS_MASK			(0x1 << 15)
+#define RT5651_MIC1_BS_SFT			15
+#define RT5651_MIC1_BS_9AV			(0x0 << 15)
+#define RT5651_MIC1_BS_75AV			(0x1 << 15)
+#define RT5651_MIC1_CLK_MASK			(0x1 << 13)
+#define RT5651_MIC1_CLK_SFT			13
+#define RT5651_MIC1_CLK_DIS			(0x0 << 13)
+#define RT5651_MIC1_CLK_EN			(0x1 << 13)
+#define RT5651_MIC1_OVCD_MASK			(0x1 << 11)
+#define RT5651_MIC1_OVCD_SFT			11
+#define RT5651_MIC1_OVCD_DIS			(0x0 << 11)
+#define RT5651_MIC1_OVCD_EN			(0x1 << 11)
+#define RT5651_MIC1_OVTH_MASK			(0x3 << 9)
+#define RT5651_MIC1_OVTH_SFT			9
+#define RT5651_MIC1_OVTH_600UA			(0x0 << 9)
+#define RT5651_MIC1_OVTH_1500UA			(0x1 << 9)
+#define RT5651_MIC1_OVTH_2000UA			(0x2 << 9)
+#define RT5651_PWR_MB_MASK			(0x1 << 5)
+#define RT5651_PWR_MB_SFT			5
+#define RT5651_PWR_MB_PD			(0x0 << 5)
+#define RT5651_PWR_MB_PU			(0x1 << 5)
+#define RT5651_PWR_CLK12M_MASK			(0x1 << 4)
+#define RT5651_PWR_CLK12M_SFT			4
+#define RT5651_PWR_CLK12M_PD			(0x0 << 4)
+#define RT5651_PWR_CLK12M_PU			(0x1 << 4)
+
+/* Analog JD Control 1 (0x94) */
+#define RT5651_JD2_CMP_MASK			(0x7 << 12)
+#define RT5651_JD2_CMP_SFT			12
+#define RT5651_JD_PU				(0x1 << 11)
+#define RT5651_JD_PU_SFT			11
+#define RT5651_JD_PD				(0x1 << 10)
+#define RT5651_JD_PD_SFT			10
+#define RT5651_JD_MODE_SEL_MASK			(0x3 << 8)
+#define RT5651_JD_MODE_SEL_SFT			8
+#define RT5651_JD_MODE_SEL_M0			(0x0 << 8)
+#define RT5651_JD_MODE_SEL_M1			(0x1 << 8)
+#define RT5651_JD_MODE_SEL_M2			(0x2 << 8)
+#define RT5651_JD_M_CMP				(0x7 << 4)
+#define RT5651_JD_M_CMP_SFT			4
+#define RT5651_JD_M_PU				(0x1 << 3)
+#define RT5651_JD_M_PU_SFT			3
+#define RT5651_JD_M_PD				(0x1 << 2)
+#define RT5651_JD_M_PD_SFT			2
+#define RT5651_JD_M_MODE_SEL_MASK		(0x3)
+#define RT5651_JD_M_MODE_SEL_SFT		0
+#define RT5651_JD_M_MODE_SEL_M0			(0x0)
+#define RT5651_JD_M_MODE_SEL_M1			(0x1)
+#define RT5651_JD_M_MODE_SEL_M2			(0x2)
+
+/* Analog JD Control 2 (0x95) */
+#define RT5651_JD3_CMP_MASK			(0x7 << 12)
+#define RT5651_JD3_CMP_SFT			12
+
+/* EQ Control 1 (0xb0) */
+#define RT5651_EQ_SRC_MASK			(0x1 << 15)
+#define RT5651_EQ_SRC_SFT			15
+#define RT5651_EQ_SRC_DAC			(0x0 << 15)
+#define RT5651_EQ_SRC_ADC			(0x1 << 15)
+#define RT5651_EQ_UPD				(0x1 << 14)
+#define RT5651_EQ_UPD_BIT			14
+#define RT5651_EQ_CD_MASK			(0x1 << 13)
+#define RT5651_EQ_CD_SFT			13
+#define RT5651_EQ_CD_DIS			(0x0 << 13)
+#define RT5651_EQ_CD_EN				(0x1 << 13)
+#define RT5651_EQ_DITH_MASK			(0x3 << 8)
+#define RT5651_EQ_DITH_SFT			8
+#define RT5651_EQ_DITH_NOR			(0x0 << 8)
+#define RT5651_EQ_DITH_LSB			(0x1 << 8)
+#define RT5651_EQ_DITH_LSB_1			(0x2 << 8)
+#define RT5651_EQ_DITH_LSB_2			(0x3 << 8)
+#define RT5651_EQ_CD_F				(0x1 << 7)
+#define RT5651_EQ_CD_F_BIT			7
+#define RT5651_EQ_STA_HP2			(0x1 << 6)
+#define RT5651_EQ_STA_HP2_BIT			6
+#define RT5651_EQ_STA_HP1			(0x1 << 5)
+#define RT5651_EQ_STA_HP1_BIT			5
+#define RT5651_EQ_STA_BP4			(0x1 << 4)
+#define RT5651_EQ_STA_BP4_BIT			4
+#define RT5651_EQ_STA_BP3			(0x1 << 3)
+#define RT5651_EQ_STA_BP3_BIT			3
+#define RT5651_EQ_STA_BP2			(0x1 << 2)
+#define RT5651_EQ_STA_BP2_BIT			2
+#define RT5651_EQ_STA_BP1			(0x1 << 1)
+#define RT5651_EQ_STA_BP1_BIT			1
+#define RT5651_EQ_STA_LP			(0x1)
+#define RT5651_EQ_STA_LP_BIT			0
+
+/* EQ Control 2 (0xb1) */
+#define RT5651_EQ_HPF1_M_MASK			(0x1 << 8)
+#define RT5651_EQ_HPF1_M_SFT			8
+#define RT5651_EQ_HPF1_M_HI			(0x0 << 8)
+#define RT5651_EQ_HPF1_M_1ST			(0x1 << 8)
+#define RT5651_EQ_LPF1_M_MASK			(0x1 << 7)
+#define RT5651_EQ_LPF1_M_SFT			7
+#define RT5651_EQ_LPF1_M_LO			(0x0 << 7)
+#define RT5651_EQ_LPF1_M_1ST			(0x1 << 7)
+#define RT5651_EQ_HPF2_MASK			(0x1 << 6)
+#define RT5651_EQ_HPF2_SFT			6
+#define RT5651_EQ_HPF2_DIS			(0x0 << 6)
+#define RT5651_EQ_HPF2_EN			(0x1 << 6)
+#define RT5651_EQ_HPF1_MASK			(0x1 << 5)
+#define RT5651_EQ_HPF1_SFT			5
+#define RT5651_EQ_HPF1_DIS			(0x0 << 5)
+#define RT5651_EQ_HPF1_EN			(0x1 << 5)
+#define RT5651_EQ_BPF4_MASK			(0x1 << 4)
+#define RT5651_EQ_BPF4_SFT			4
+#define RT5651_EQ_BPF4_DIS			(0x0 << 4)
+#define RT5651_EQ_BPF4_EN			(0x1 << 4)
+#define RT5651_EQ_BPF3_MASK			(0x1 << 3)
+#define RT5651_EQ_BPF3_SFT			3
+#define RT5651_EQ_BPF3_DIS			(0x0 << 3)
+#define RT5651_EQ_BPF3_EN			(0x1 << 3)
+#define RT5651_EQ_BPF2_MASK			(0x1 << 2)
+#define RT5651_EQ_BPF2_SFT			2
+#define RT5651_EQ_BPF2_DIS			(0x0 << 2)
+#define RT5651_EQ_BPF2_EN			(0x1 << 2)
+#define RT5651_EQ_BPF1_MASK			(0x1 << 1)
+#define RT5651_EQ_BPF1_SFT			1
+#define RT5651_EQ_BPF1_DIS			(0x0 << 1)
+#define RT5651_EQ_BPF1_EN			(0x1 << 1)
+#define RT5651_EQ_LPF_MASK			(0x1)
+#define RT5651_EQ_LPF_SFT			0
+#define RT5651_EQ_LPF_DIS			(0x0)
+#define RT5651_EQ_LPF_EN			(0x1)
+#define RT5651_EQ_CTRL_MASK			(0x7f)
+
+/* Memory Test (0xb2) */
+#define RT5651_MT_MASK				(0x1 << 15)
+#define RT5651_MT_SFT				15
+#define RT5651_MT_DIS				(0x0 << 15)
+#define RT5651_MT_EN				(0x1 << 15)
+
+/* ALC Control 1 (0xb4) */
+#define RT5651_ALC_P_MASK			(0x1 << 15)
+#define RT5651_ALC_P_SFT			15
+#define RT5651_ALC_P_DAC			(0x0 << 15)
+#define RT5651_ALC_P_ADC			(0x1 << 15)
+#define RT5651_ALC_MASK				(0x1 << 14)
+#define RT5651_ALC_SFT				14
+#define RT5651_ALC_DIS				(0x0 << 14)
+#define RT5651_ALC_EN				(0x1 << 14)
+#define RT5651_ALC_UPD				(0x1 << 13)
+#define RT5651_ALC_UPD_BIT			13
+#define RT5651_ALC_AR_MASK			(0x1f << 8)
+#define RT5651_ALC_AR_SFT			8
+#define RT5651_ALC_R_MASK			(0x7 << 5)
+#define RT5651_ALC_R_SFT			5
+#define RT5651_ALC_R_48K			(0x1 << 5)
+#define RT5651_ALC_R_96K			(0x2 << 5)
+#define RT5651_ALC_R_192K			(0x3 << 5)
+#define RT5651_ALC_R_441K			(0x5 << 5)
+#define RT5651_ALC_R_882K			(0x6 << 5)
+#define RT5651_ALC_R_1764K			(0x7 << 5)
+#define RT5651_ALC_RC_MASK			(0x1f)
+#define RT5651_ALC_RC_SFT			0
+
+/* ALC Control 2 (0xb5) */
+#define RT5651_ALC_POB_MASK			(0x3f << 8)
+#define RT5651_ALC_POB_SFT			8
+#define RT5651_ALC_DRC_MASK			(0x1 << 7)
+#define RT5651_ALC_DRC_SFT			7
+#define RT5651_ALC_DRC_DIS			(0x0 << 7)
+#define RT5651_ALC_DRC_EN			(0x1 << 7)
+#define RT5651_ALC_CPR_MASK			(0x3 << 5)
+#define RT5651_ALC_CPR_SFT			5
+#define RT5651_ALC_CPR_1_1			(0x0 << 5)
+#define RT5651_ALC_CPR_1_2			(0x1 << 5)
+#define RT5651_ALC_CPR_1_4			(0x2 << 5)
+#define RT5651_ALC_CPR_1_8			(0x3 << 5)
+#define RT5651_ALC_PRB_MASK			(0x1f)
+#define RT5651_ALC_PRB_SFT			0
+
+/* ALC Control 3 (0xb6) */
+#define RT5651_ALC_NGB_MASK			(0xf << 12)
+#define RT5651_ALC_NGB_SFT			12
+#define RT5651_ALC_TAR_MASK			(0x1f << 7)
+#define RT5651_ALC_TAR_SFT			7
+#define RT5651_ALC_NG_MASK			(0x1 << 6)
+#define RT5651_ALC_NG_SFT			6
+#define RT5651_ALC_NG_DIS			(0x0 << 6)
+#define RT5651_ALC_NG_EN			(0x1 << 6)
+#define RT5651_ALC_NGH_MASK			(0x1 << 5)
+#define RT5651_ALC_NGH_SFT			5
+#define RT5651_ALC_NGH_DIS			(0x0 << 5)
+#define RT5651_ALC_NGH_EN			(0x1 << 5)
+#define RT5651_ALC_NGT_MASK			(0x1f)
+#define RT5651_ALC_NGT_SFT			0
+
+/* Jack Detect Control 1 (0xbb) */
+#define RT5651_JD_MASK				(0x7 << 13)
+#define RT5651_JD_SFT				13
+#define RT5651_JD_DIS				(0x0 << 13)
+#define RT5651_JD_GPIO1				(0x1 << 13)
+#define RT5651_JD_GPIO2				(0x2 << 13)
+#define RT5651_JD_GPIO3				(0x3 << 13)
+#define RT5651_JD_GPIO4				(0x4 << 13)
+#define RT5651_JD_GPIO5				(0x5 << 13)
+#define RT5651_JD_GPIO6				(0x6 << 13)
+#define RT5651_JD_HP_MASK			(0x1 << 11)
+#define RT5651_JD_HP_SFT			11
+#define RT5651_JD_HP_DIS			(0x0 << 11)
+#define RT5651_JD_HP_EN				(0x1 << 11)
+#define RT5651_JD_HP_TRG_MASK			(0x1 << 10)
+#define RT5651_JD_HP_TRG_SFT			10
+#define RT5651_JD_HP_TRG_LO			(0x0 << 10)
+#define RT5651_JD_HP_TRG_HI			(0x1 << 10)
+#define RT5651_JD_SPL_MASK			(0x1 << 9)
+#define RT5651_JD_SPL_SFT			9
+#define RT5651_JD_SPL_DIS			(0x0 << 9)
+#define RT5651_JD_SPL_EN			(0x1 << 9)
+#define RT5651_JD_SPL_TRG_MASK			(0x1 << 8)
+#define RT5651_JD_SPL_TRG_SFT			8
+#define RT5651_JD_SPL_TRG_LO			(0x0 << 8)
+#define RT5651_JD_SPL_TRG_HI			(0x1 << 8)
+#define RT5651_JD_SPR_MASK			(0x1 << 7)
+#define RT5651_JD_SPR_SFT			7
+#define RT5651_JD_SPR_DIS			(0x0 << 7)
+#define RT5651_JD_SPR_EN			(0x1 << 7)
+#define RT5651_JD_SPR_TRG_MASK			(0x1 << 6)
+#define RT5651_JD_SPR_TRG_SFT			6
+#define RT5651_JD_SPR_TRG_LO			(0x0 << 6)
+#define RT5651_JD_SPR_TRG_HI			(0x1 << 6)
+#define RT5651_JD_LO_MASK			(0x1 << 3)
+#define RT5651_JD_LO_SFT			3
+#define RT5651_JD_LO_DIS			(0x0 << 3)
+#define RT5651_JD_LO_EN				(0x1 << 3)
+#define RT5651_JD_LO_TRG_MASK			(0x1 << 2)
+#define RT5651_JD_LO_TRG_SFT			2
+#define RT5651_JD_LO_TRG_LO			(0x0 << 2)
+#define RT5651_JD_LO_TRG_HI			(0x1 << 2)
+
+/* Jack Detect Control 2 (0xbc) */
+#define RT5651_JD_TRG_SEL_MASK			(0x7 << 9)
+#define RT5651_JD_TRG_SEL_SFT			9
+#define RT5651_JD_TRG_SEL_GPIO			(0x0 << 9)
+#define RT5651_JD_TRG_SEL_JD1_1			(0x1 << 9)
+#define RT5651_JD_TRG_SEL_JD1_2			(0x2 << 9)
+#define RT5651_JD_TRG_SEL_JD2			(0x3 << 9)
+#define RT5651_JD_TRG_SEL_JD3			(0x4 << 9)
+#define RT5651_JD3_IRQ_EN			(0x1 << 8)
+#define RT5651_JD3_IRQ_EN_SFT			8
+#define RT5651_JD3_EN_STKY			(0x1 << 7)
+#define RT5651_JD3_EN_STKY_SFT			7
+#define RT5651_JD3_INV				(0x1 << 6)
+#define RT5651_JD3_INV_SFT			6
+
+/* IRQ Control 1 (0xbd) */
+#define RT5651_IRQ_JD_MASK			(0x1 << 15)
+#define RT5651_IRQ_JD_SFT			15
+#define RT5651_IRQ_JD_BP			(0x0 << 15)
+#define RT5651_IRQ_JD_NOR			(0x1 << 15)
+#define RT5651_JD_STKY_MASK			(0x1 << 13)
+#define RT5651_JD_STKY_SFT			13
+#define RT5651_JD_STKY_DIS			(0x0 << 13)
+#define RT5651_JD_STKY_EN			(0x1 << 13)
+#define RT5651_JD_P_MASK			(0x1 << 11)
+#define RT5651_JD_P_SFT				11
+#define RT5651_JD_P_NOR				(0x0 << 11)
+#define RT5651_JD_P_INV				(0x1 << 11)
+#define RT5651_JD1_1_IRQ_EN			(0x1 << 9)
+#define RT5651_JD1_1_IRQ_EN_SFT			9
+#define RT5651_JD1_1_EN_STKY			(0x1 << 8)
+#define RT5651_JD1_1_EN_STKY_SFT			8
+#define RT5651_JD1_1_INV			(0x1 << 7)
+#define RT5651_JD1_1_INV_SFT			7
+#define RT5651_JD1_2_IRQ_EN			(0x1 << 6)
+#define RT5651_JD1_2_IRQ_EN_SFT			6
+#define RT5651_JD1_2_EN_STKY			(0x1 << 5)
+#define RT5651_JD1_2_EN_STKY_SFT			5
+#define RT5651_JD1_2_INV			(0x1 << 4)
+#define RT5651_JD1_2_INV_SFT			4
+#define RT5651_JD2_IRQ_EN			(0x1 << 3)
+#define RT5651_JD2_IRQ_EN_SFT			3
+#define RT5651_JD2_EN_STKY			(0x1 << 2)
+#define RT5651_JD2_EN_STKY_SFT			2
+#define RT5651_JD2_INV				(0x1 << 1)
+#define RT5651_JD2_INV_SFT			1
+
+/* IRQ Control 2 (0xbe) */
+#define RT5651_IRQ_MB1_OC_MASK			(0x1 << 15)
+#define RT5651_IRQ_MB1_OC_SFT			15
+#define RT5651_IRQ_MB1_OC_BP			(0x0 << 15)
+#define RT5651_IRQ_MB1_OC_NOR			(0x1 << 15)
+#define RT5651_MB1_OC_STKY_MASK			(0x1 << 11)
+#define RT5651_MB1_OC_STKY_SFT			11
+#define RT5651_MB1_OC_STKY_DIS			(0x0 << 11)
+#define RT5651_MB1_OC_STKY_EN			(0x1 << 11)
+#define RT5651_MB1_OC_P_MASK			(0x1 << 7)
+#define RT5651_MB1_OC_P_SFT			7
+#define RT5651_MB1_OC_P_NOR			(0x0 << 7)
+#define RT5651_MB1_OC_P_INV			(0x1 << 7)
+#define RT5651_MB2_OC_P_MASK			(0x1 << 6)
+#define RT5651_MB1_OC_CLR			(0x1 << 3)
+#define RT5651_MB1_OC_CLR_SFT			3
+#define RT5651_STA_GPIO8			(0x1)
+#define RT5651_STA_GPIO8_BIT			0
+
+/* Internal Status and GPIO status (0xbf) */
+#define RT5651_STA_JD3				(0x1 << 15)
+#define RT5651_STA_JD3_BIT			15
+#define RT5651_STA_JD2				(0x1 << 14)
+#define RT5651_STA_JD2_BIT			14
+#define RT5651_STA_JD1_2			(0x1 << 13)
+#define RT5651_STA_JD1_2_BIT			13
+#define RT5651_STA_JD1_1			(0x1 << 12)
+#define RT5651_STA_JD1_1_BIT			12
+#define RT5651_STA_GP7				(0x1 << 11)
+#define RT5651_STA_GP7_BIT			11
+#define RT5651_STA_GP6				(0x1 << 10)
+#define RT5651_STA_GP6_BIT			10
+#define RT5651_STA_GP5				(0x1 << 9)
+#define RT5651_STA_GP5_BIT			9
+#define RT5651_STA_GP1				(0x1 << 8)
+#define RT5651_STA_GP1_BIT			8
+#define RT5651_STA_GP2				(0x1 << 7)
+#define RT5651_STA_GP2_BIT			7
+#define RT5651_STA_GP3				(0x1 << 6)
+#define RT5651_STA_GP3_BIT			6
+#define RT5651_STA_GP4				(0x1 << 5)
+#define RT5651_STA_GP4_BIT			5
+#define RT5651_STA_GP_JD			(0x1 << 4)
+#define RT5651_STA_GP_JD_BIT			4
+
+/* GPIO Control 1 (0xc0) */
+#define RT5651_GP1_PIN_MASK			(0x1 << 15)
+#define RT5651_GP1_PIN_SFT			15
+#define RT5651_GP1_PIN_GPIO1			(0x0 << 15)
+#define RT5651_GP1_PIN_IRQ			(0x1 << 15)
+#define RT5651_GP2_PIN_MASK			(0x1 << 14)
+#define RT5651_GP2_PIN_SFT			14
+#define RT5651_GP2_PIN_GPIO2			(0x0 << 14)
+#define RT5651_GP2_PIN_DMIC1_SCL		(0x1 << 14)
+#define RT5651_GPIO_M_MASK			(0x1 << 9)
+#define RT5651_GPIO_M_SFT			9
+#define RT5651_GPIO_M_FLT			(0x0 << 9)
+#define RT5651_GPIO_M_PH			(0x1 << 9)
+#define RT5651_I2S2_SEL_MASK			(0x1 << 8)
+#define RT5651_I2S2_SEL_SFT			8
+#define RT5651_I2S2_SEL_I2S			(0x0 << 8)
+#define RT5651_I2S2_SEL_GPIO			(0x1 << 8)
+#define RT5651_GP5_PIN_MASK			(0x1 << 7)
+#define RT5651_GP5_PIN_SFT			7
+#define RT5651_GP5_PIN_GPIO5			(0x0 << 7)
+#define RT5651_GP5_PIN_IRQ			(0x1 << 7)
+#define RT5651_GP6_PIN_MASK			(0x1 << 6)
+#define RT5651_GP6_PIN_SFT			6
+#define RT5651_GP6_PIN_GPIO6			(0x0 << 6)
+#define RT5651_GP6_PIN_DMIC_SDA			(0x1 << 6)
+#define RT5651_GP7_PIN_MASK			(0x1 << 5)
+#define RT5651_GP7_PIN_SFT			5
+#define RT5651_GP7_PIN_GPIO7			(0x0 << 5)
+#define RT5651_GP7_PIN_IRQ			(0x1 << 5)
+#define RT5651_GP8_PIN_MASK			(0x1 << 4)
+#define RT5651_GP8_PIN_SFT			4
+#define RT5651_GP8_PIN_GPIO8			(0x0 << 4)
+#define RT5651_GP8_PIN_DMIC_SDA			(0x1 << 4)
+#define RT5651_GPIO_PDM_SEL_MASK		(0x1 << 3)
+#define RT5651_GPIO_PDM_SEL_SFT			3
+#define RT5651_GPIO_PDM_SEL_GPIO		(0x0 << 3)
+#define RT5651_GPIO_PDM_SEL_PDM			(0x1 << 3)
+
+/* GPIO Control 2 (0xc1) */
+#define RT5651_GP5_DR_MASK			(0x1 << 14)
+#define RT5651_GP5_DR_SFT			14
+#define RT5651_GP5_DR_IN			(0x0 << 14)
+#define RT5651_GP5_DR_OUT			(0x1 << 14)
+#define RT5651_GP5_OUT_MASK			(0x1 << 13)
+#define RT5651_GP5_OUT_SFT			13
+#define RT5651_GP5_OUT_LO			(0x0 << 13)
+#define RT5651_GP5_OUT_HI			(0x1 << 13)
+#define RT5651_GP5_P_MASK			(0x1 << 12)
+#define RT5651_GP5_P_SFT			12
+#define RT5651_GP5_P_NOR			(0x0 << 12)
+#define RT5651_GP5_P_INV			(0x1 << 12)
+#define RT5651_GP4_DR_MASK			(0x1 << 11)
+#define RT5651_GP4_DR_SFT			11
+#define RT5651_GP4_DR_IN			(0x0 << 11)
+#define RT5651_GP4_DR_OUT			(0x1 << 11)
+#define RT5651_GP4_OUT_MASK			(0x1 << 10)
+#define RT5651_GP4_OUT_SFT			10
+#define RT5651_GP4_OUT_LO			(0x0 << 10)
+#define RT5651_GP4_OUT_HI			(0x1 << 10)
+#define RT5651_GP4_P_MASK			(0x1 << 9)
+#define RT5651_GP4_P_SFT			9
+#define RT5651_GP4_P_NOR			(0x0 << 9)
+#define RT5651_GP4_P_INV			(0x1 << 9)
+#define RT5651_GP3_DR_MASK			(0x1 << 8)
+#define RT5651_GP3_DR_SFT			8
+#define RT5651_GP3_DR_IN			(0x0 << 8)
+#define RT5651_GP3_DR_OUT			(0x1 << 8)
+#define RT5651_GP3_OUT_MASK			(0x1 << 7)
+#define RT5651_GP3_OUT_SFT			7
+#define RT5651_GP3_OUT_LO			(0x0 << 7)
+#define RT5651_GP3_OUT_HI			(0x1 << 7)
+#define RT5651_GP3_P_MASK			(0x1 << 6)
+#define RT5651_GP3_P_SFT			6
+#define RT5651_GP3_P_NOR			(0x0 << 6)
+#define RT5651_GP3_P_INV			(0x1 << 6)
+#define RT5651_GP2_DR_MASK			(0x1 << 5)
+#define RT5651_GP2_DR_SFT			5
+#define RT5651_GP2_DR_IN			(0x0 << 5)
+#define RT5651_GP2_DR_OUT			(0x1 << 5)
+#define RT5651_GP2_OUT_MASK			(0x1 << 4)
+#define RT5651_GP2_OUT_SFT			4
+#define RT5651_GP2_OUT_LO			(0x0 << 4)
+#define RT5651_GP2_OUT_HI			(0x1 << 4)
+#define RT5651_GP2_P_MASK			(0x1 << 3)
+#define RT5651_GP2_P_SFT			3
+#define RT5651_GP2_P_NOR			(0x0 << 3)
+#define RT5651_GP2_P_INV			(0x1 << 3)
+#define RT5651_GP1_DR_MASK			(0x1 << 2)
+#define RT5651_GP1_DR_SFT			2
+#define RT5651_GP1_DR_IN			(0x0 << 2)
+#define RT5651_GP1_DR_OUT			(0x1 << 2)
+#define RT5651_GP1_OUT_MASK			(0x1 << 1)
+#define RT5651_GP1_OUT_SFT			1
+#define RT5651_GP1_OUT_LO			(0x0 << 1)
+#define RT5651_GP1_OUT_HI			(0x1 << 1)
+#define RT5651_GP1_P_MASK			(0x1)
+#define RT5651_GP1_P_SFT			0
+#define RT5651_GP1_P_NOR			(0x0)
+#define RT5651_GP1_P_INV			(0x1)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5651_GP8_DR_MASK			(0x1 << 8)
+#define RT5651_GP8_DR_SFT			8
+#define RT5651_GP8_DR_IN			(0x0 << 8)
+#define RT5651_GP8_DR_OUT			(0x1 << 8)
+#define RT5651_GP8_OUT_MASK			(0x1 << 7)
+#define RT5651_GP8_OUT_SFT			7
+#define RT5651_GP8_OUT_LO			(0x0 << 7)
+#define RT5651_GP8_OUT_HI			(0x1 << 7)
+#define RT5651_GP8_P_MASK			(0x1 << 6)
+#define RT5651_GP8_P_SFT			6
+#define RT5651_GP8_P_NOR			(0x0 << 6)
+#define RT5651_GP8_P_INV			(0x1 << 6)
+#define RT5651_GP7_DR_MASK			(0x1 << 5)
+#define RT5651_GP7_DR_SFT			5
+#define RT5651_GP7_DR_IN			(0x0 << 5)
+#define RT5651_GP7_DR_OUT			(0x1 << 5)
+#define RT5651_GP7_OUT_MASK			(0x1 << 4)
+#define RT5651_GP7_OUT_SFT			4
+#define RT5651_GP7_OUT_LO			(0x0 << 4)
+#define RT5651_GP7_OUT_HI			(0x1 << 4)
+#define RT5651_GP7_P_MASK			(0x1 << 3)
+#define RT5651_GP7_P_SFT			3
+#define RT5651_GP7_P_NOR			(0x0 << 3)
+#define RT5651_GP7_P_INV			(0x1 << 3)
+#define RT5651_GP6_DR_MASK			(0x1 << 2)
+#define RT5651_GP6_DR_SFT			2
+#define RT5651_GP6_DR_IN			(0x0 << 2)
+#define RT5651_GP6_DR_OUT			(0x1 << 2)
+#define RT5651_GP6_OUT_MASK			(0x1 << 1)
+#define RT5651_GP6_OUT_SFT			1
+#define RT5651_GP6_OUT_LO			(0x0 << 1)
+#define RT5651_GP6_OUT_HI			(0x1 << 1)
+#define RT5651_GP6_P_MASK			(0x1)
+#define RT5651_GP6_P_SFT			0
+#define RT5651_GP6_P_NOR			(0x0)
+#define RT5651_GP6_P_INV			(0x1)
+
+/* Scramble Control (0xce) */
+#define RT5651_SCB_SWAP_MASK			(0x1 << 15)
+#define RT5651_SCB_SWAP_SFT			15
+#define RT5651_SCB_SWAP_DIS			(0x0 << 15)
+#define RT5651_SCB_SWAP_EN			(0x1 << 15)
+#define RT5651_SCB_MASK				(0x1 << 14)
+#define RT5651_SCB_SFT				14
+#define RT5651_SCB_DIS				(0x0 << 14)
+#define RT5651_SCB_EN				(0x1 << 14)
+
+/* Baseback Control (0xcf) */
+#define RT5651_BB_MASK				(0x1 << 15)
+#define RT5651_BB_SFT				15
+#define RT5651_BB_DIS				(0x0 << 15)
+#define RT5651_BB_EN				(0x1 << 15)
+#define RT5651_BB_CT_MASK			(0x7 << 12)
+#define RT5651_BB_CT_SFT			12
+#define RT5651_BB_CT_A				(0x0 << 12)
+#define RT5651_BB_CT_B				(0x1 << 12)
+#define RT5651_BB_CT_C				(0x2 << 12)
+#define RT5651_BB_CT_D				(0x3 << 12)
+#define RT5651_M_BB_L_MASK			(0x1 << 9)
+#define RT5651_M_BB_L_SFT			9
+#define RT5651_M_BB_R_MASK			(0x1 << 8)
+#define RT5651_M_BB_R_SFT			8
+#define RT5651_M_BB_HPF_L_MASK			(0x1 << 7)
+#define RT5651_M_BB_HPF_L_SFT			7
+#define RT5651_M_BB_HPF_R_MASK			(0x1 << 6)
+#define RT5651_M_BB_HPF_R_SFT			6
+#define RT5651_G_BB_BST_MASK			(0x3f)
+#define RT5651_G_BB_BST_SFT			0
+
+/* MP3 Plus Control 1 (0xd0) */
+#define RT5651_M_MP3_L_MASK			(0x1 << 15)
+#define RT5651_M_MP3_L_SFT			15
+#define RT5651_M_MP3_R_MASK			(0x1 << 14)
+#define RT5651_M_MP3_R_SFT			14
+#define RT5651_M_MP3_MASK			(0x1 << 13)
+#define RT5651_M_MP3_SFT			13
+#define RT5651_M_MP3_DIS			(0x0 << 13)
+#define RT5651_M_MP3_EN				(0x1 << 13)
+#define RT5651_EG_MP3_MASK			(0x1f << 8)
+#define RT5651_EG_MP3_SFT			8
+#define RT5651_MP3_HLP_MASK			(0x1 << 7)
+#define RT5651_MP3_HLP_SFT			7
+#define RT5651_MP3_HLP_DIS			(0x0 << 7)
+#define RT5651_MP3_HLP_EN			(0x1 << 7)
+#define RT5651_M_MP3_ORG_L_MASK			(0x1 << 6)
+#define RT5651_M_MP3_ORG_L_SFT			6
+#define RT5651_M_MP3_ORG_R_MASK			(0x1 << 5)
+#define RT5651_M_MP3_ORG_R_SFT			5
+
+/* MP3 Plus Control 2 (0xd1) */
+#define RT5651_MP3_WT_MASK			(0x1 << 13)
+#define RT5651_MP3_WT_SFT			13
+#define RT5651_MP3_WT_1_4			(0x0 << 13)
+#define RT5651_MP3_WT_1_2			(0x1 << 13)
+#define RT5651_OG_MP3_MASK			(0x1f << 8)
+#define RT5651_OG_MP3_SFT			8
+#define RT5651_HG_MP3_MASK			(0x3f)
+#define RT5651_HG_MP3_SFT			0
+
+/* 3D HP Control 1 (0xd2) */
+#define RT5651_3D_CF_MASK			(0x1 << 15)
+#define RT5651_3D_CF_SFT			15
+#define RT5651_3D_CF_DIS			(0x0 << 15)
+#define RT5651_3D_CF_EN				(0x1 << 15)
+#define RT5651_3D_HP_MASK			(0x1 << 14)
+#define RT5651_3D_HP_SFT			14
+#define RT5651_3D_HP_DIS			(0x0 << 14)
+#define RT5651_3D_HP_EN				(0x1 << 14)
+#define RT5651_3D_BT_MASK			(0x1 << 13)
+#define RT5651_3D_BT_SFT			13
+#define RT5651_3D_BT_DIS			(0x0 << 13)
+#define RT5651_3D_BT_EN				(0x1 << 13)
+#define RT5651_3D_1F_MIX_MASK			(0x3 << 11)
+#define RT5651_3D_1F_MIX_SFT			11
+#define RT5651_3D_HP_M_MASK			(0x1 << 10)
+#define RT5651_3D_HP_M_SFT			10
+#define RT5651_3D_HP_M_SUR			(0x0 << 10)
+#define RT5651_3D_HP_M_FRO			(0x1 << 10)
+#define RT5651_M_3D_HRTF_MASK			(0x1 << 9)
+#define RT5651_M_3D_HRTF_SFT			9
+#define RT5651_M_3D_D2H_MASK			(0x1 << 8)
+#define RT5651_M_3D_D2H_SFT			8
+#define RT5651_M_3D_D2R_MASK			(0x1 << 7)
+#define RT5651_M_3D_D2R_SFT			7
+#define RT5651_M_3D_REVB_MASK			(0x1 << 6)
+#define RT5651_M_3D_REVB_SFT			6
+
+/* Adjustable high pass filter control 1 (0xd3) */
+#define RT5651_2ND_HPF_MASK			(0x1 << 15)
+#define RT5651_2ND_HPF_SFT			15
+#define RT5651_2ND_HPF_DIS			(0x0 << 15)
+#define RT5651_2ND_HPF_EN			(0x1 << 15)
+#define RT5651_HPF_CF_L_MASK			(0x7 << 12)
+#define RT5651_HPF_CF_L_SFT			12
+#define RT5651_HPF_CF_R_MASK			(0x7 << 8)
+#define RT5651_HPF_CF_R_SFT			8
+#define RT5651_ZD_T_MASK			(0x3 << 6)
+#define RT5651_ZD_T_SFT				6
+#define RT5651_ZD_F_MASK			(0x3 << 4)
+#define RT5651_ZD_F_SFT				4
+#define RT5651_ZD_F_IM				(0x0 << 4)
+#define RT5651_ZD_F_ZC_IM			(0x1 << 4)
+#define RT5651_ZD_F_ZC_IOD			(0x2 << 4)
+#define RT5651_ZD_F_UN				(0x3 << 4)
+
+/* Adjustable high pass filter control 2 (0xd4) */
+#define RT5651_HPF_CF_L_NUM_MASK		(0x3f << 8)
+#define RT5651_HPF_CF_L_NUM_SFT			8
+#define RT5651_HPF_CF_R_NUM_MASK		(0x3f)
+#define RT5651_HPF_CF_R_NUM_SFT			0
+
+/* HP calibration control and Amp detection (0xd6) */
+#define RT5651_SI_DAC_MASK			(0x1 << 11)
+#define RT5651_SI_DAC_SFT			11
+#define RT5651_SI_DAC_AUTO			(0x0 << 11)
+#define RT5651_SI_DAC_TEST			(0x1 << 11)
+#define RT5651_DC_CAL_M_MASK			(0x1 << 10)
+#define RT5651_DC_CAL_M_SFT			10
+#define RT5651_DC_CAL_M_NOR			(0x0 << 10)
+#define RT5651_DC_CAL_M_CAL			(0x1 << 10)
+#define RT5651_DC_CAL_MASK			(0x1 << 9)
+#define RT5651_DC_CAL_SFT			9
+#define RT5651_DC_CAL_DIS			(0x0 << 9)
+#define RT5651_DC_CAL_EN			(0x1 << 9)
+#define RT5651_HPD_RCV_MASK			(0x7 << 6)
+#define RT5651_HPD_RCV_SFT			6
+#define RT5651_HPD_PS_MASK			(0x1 << 5)
+#define RT5651_HPD_PS_SFT			5
+#define RT5651_HPD_PS_DIS			(0x0 << 5)
+#define RT5651_HPD_PS_EN			(0x1 << 5)
+#define RT5651_CAL_M_MASK			(0x1 << 4)
+#define RT5651_CAL_M_SFT			4
+#define RT5651_CAL_M_DEP			(0x0 << 4)
+#define RT5651_CAL_M_CAL			(0x1 << 4)
+#define RT5651_CAL_MASK				(0x1 << 3)
+#define RT5651_CAL_SFT				3
+#define RT5651_CAL_DIS				(0x0 << 3)
+#define RT5651_CAL_EN				(0x1 << 3)
+#define RT5651_CAL_TEST_MASK			(0x1 << 2)
+#define RT5651_CAL_TEST_SFT			2
+#define RT5651_CAL_TEST_DIS			(0x0 << 2)
+#define RT5651_CAL_TEST_EN			(0x1 << 2)
+#define RT5651_CAL_P_MASK			(0x3)
+#define RT5651_CAL_P_SFT			0
+#define RT5651_CAL_P_NONE			(0x0)
+#define RT5651_CAL_P_CAL			(0x1)
+#define RT5651_CAL_P_DAC_CAL			(0x2)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5651_SV_MASK				(0x1 << 15)
+#define RT5651_SV_SFT				15
+#define RT5651_SV_DIS				(0x0 << 15)
+#define RT5651_SV_EN				(0x1 << 15)
+#define RT5651_OUT_SV_MASK			(0x1 << 13)
+#define RT5651_OUT_SV_SFT			13
+#define RT5651_OUT_SV_DIS			(0x0 << 13)
+#define RT5651_OUT_SV_EN			(0x1 << 13)
+#define RT5651_HP_SV_MASK			(0x1 << 12)
+#define RT5651_HP_SV_SFT			12
+#define RT5651_HP_SV_DIS			(0x0 << 12)
+#define RT5651_HP_SV_EN				(0x1 << 12)
+#define RT5651_ZCD_DIG_MASK			(0x1 << 11)
+#define RT5651_ZCD_DIG_SFT			11
+#define RT5651_ZCD_DIG_DIS			(0x0 << 11)
+#define RT5651_ZCD_DIG_EN			(0x1 << 11)
+#define RT5651_ZCD_MASK				(0x1 << 10)
+#define RT5651_ZCD_SFT				10
+#define RT5651_ZCD_PD				(0x0 << 10)
+#define RT5651_ZCD_PU				(0x1 << 10)
+#define RT5651_M_ZCD_MASK			(0x3f << 4)
+#define RT5651_M_ZCD_SFT			4
+#define RT5651_M_ZCD_OM_L			(0x1 << 7)
+#define RT5651_M_ZCD_OM_R			(0x1 << 6)
+#define RT5651_M_ZCD_RM_L			(0x1 << 5)
+#define RT5651_M_ZCD_RM_R			(0x1 << 4)
+#define RT5651_SV_DLY_MASK			(0xf)
+#define RT5651_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5651_ZCD_HP_MASK			(0x1 << 15)
+#define RT5651_ZCD_HP_SFT			15
+#define RT5651_ZCD_HP_DIS			(0x0 << 15)
+#define RT5651_ZCD_HP_EN			(0x1 << 15)
+
+/* Digital Misc Control (0xfa) */
+#define RT5651_I2S2_MS_SP_MASK			(0x1 << 8)
+#define RT5651_I2S2_MS_SP_SEL			8
+#define RT5651_I2S2_MS_SP_64			(0x0 << 8)
+#define RT5651_I2S2_MS_SP_50			(0x1 << 8)
+#define RT5651_CLK_DET_EN			(0x1 << 3)
+#define RT5651_CLK_DET_EN_SFT			3
+#define RT5651_AMP_DET_EN			(0x1 << 1)
+#define RT5651_AMP_DET_EN_SFT			1
+#define RT5651_D_GATE_EN			(0x1)
+#define RT5651_D_GATE_EN_SFT			0
+
+/* Codec Private Register definition */
+
+/* MIC Over current threshold scale factor (0x15) */
+#define RT5651_MIC_OVCD_SF_MASK			(0x3 << 8)
+#define RT5651_MIC_OVCD_SF_SFT			8
+#define RT5651_MIC_OVCD_SF_0P5			(0x0 << 8)
+#define RT5651_MIC_OVCD_SF_0P75			(0x1 << 8)
+#define RT5651_MIC_OVCD_SF_1P0			(0x2 << 8)
+#define RT5651_MIC_OVCD_SF_1P5			(0x3 << 8)
+
+/* 3D Speaker Control (0x63) */
+#define RT5651_3D_SPK_MASK			(0x1 << 15)
+#define RT5651_3D_SPK_SFT			15
+#define RT5651_3D_SPK_DIS			(0x0 << 15)
+#define RT5651_3D_SPK_EN			(0x1 << 15)
+#define RT5651_3D_SPK_M_MASK			(0x3 << 13)
+#define RT5651_3D_SPK_M_SFT			13
+#define RT5651_3D_SPK_CG_MASK			(0x1f << 8)
+#define RT5651_3D_SPK_CG_SFT			8
+#define RT5651_3D_SPK_SG_MASK			(0x1f)
+#define RT5651_3D_SPK_SG_SFT			0
+
+/* Wind Noise Detection Control 1 (0x6c) */
+#define RT5651_WND_MASK				(0x1 << 15)
+#define RT5651_WND_SFT				15
+#define RT5651_WND_DIS				(0x0 << 15)
+#define RT5651_WND_EN				(0x1 << 15)
+
+/* Wind Noise Detection Control 2 (0x6d) */
+#define RT5651_WND_FC_NW_MASK			(0x3f << 10)
+#define RT5651_WND_FC_NW_SFT			10
+#define RT5651_WND_FC_WK_MASK			(0x3f << 4)
+#define RT5651_WND_FC_WK_SFT			4
+
+/* Wind Noise Detection Control 3 (0x6e) */
+#define RT5651_HPF_FC_MASK			(0x3f << 6)
+#define RT5651_HPF_FC_SFT			6
+#define RT5651_WND_FC_ST_MASK			(0x3f)
+#define RT5651_WND_FC_ST_SFT			0
+
+/* Wind Noise Detection Control 4 (0x6f) */
+#define RT5651_WND_TH_LO_MASK			(0x3ff)
+#define RT5651_WND_TH_LO_SFT			0
+
+/* Wind Noise Detection Control 5 (0x70) */
+#define RT5651_WND_TH_HI_MASK			(0x3ff)
+#define RT5651_WND_TH_HI_SFT			0
+
+/* Wind Noise Detection Control 8 (0x73) */
+#define RT5651_WND_WIND_MASK			(0x1 << 13) /* Read-Only */
+#define RT5651_WND_WIND_SFT			13
+#define RT5651_WND_STRONG_MASK			(0x1 << 12) /* Read-Only */
+#define RT5651_WND_STRONG_SFT			12
+enum {
+	RT5651_NO_WIND,
+	RT5651_BREEZE,
+	RT5651_STORM,
+};
+
+/* Dipole Speaker Interface (0x75) */
+#define RT5651_DP_ATT_MASK			(0x3 << 14)
+#define RT5651_DP_ATT_SFT			14
+#define RT5651_DP_SPK_MASK			(0x1 << 10)
+#define RT5651_DP_SPK_SFT			10
+#define RT5651_DP_SPK_DIS			(0x0 << 10)
+#define RT5651_DP_SPK_EN			(0x1 << 10)
+
+/* EQ Pre Volume Control (0xb3) */
+#define RT5651_EQ_PRE_VOL_MASK			(0xffff)
+#define RT5651_EQ_PRE_VOL_SFT			0
+
+/* EQ Post Volume Control (0xb4) */
+#define RT5651_EQ_PST_VOL_MASK			(0xffff)
+#define RT5651_EQ_PST_VOL_SFT			0
+
+/* System Clock Source */
+enum {
+	RT5651_SCLK_S_MCLK,
+	RT5651_SCLK_S_PLL1,
+	RT5651_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+	RT5651_PLL1_S_MCLK,
+	RT5651_PLL1_S_BCLK1,
+	RT5651_PLL1_S_BCLK2,
+};
+
+enum {
+	RT5651_AIF1,
+	RT5651_AIF2,
+	RT5651_AIFS,
+};
+
+struct rt5651_pll_code {
+	bool m_bp; /* Indicates bypass m code or not. */
+	int m_code;
+	int n_code;
+	int k_code;
+};
+
+struct rt5651_priv {
+	struct snd_soc_component *component;
+	struct regmap *regmap;
+	/* Jack and button detect data */
+	struct snd_soc_jack *hp_jack;
+	struct work_struct jack_detect_work;
+	struct delayed_work bp_work;
+	bool ovcd_irq_enabled;
+	bool pressed;
+	bool press_reported;
+	int press_count;
+	int release_count;
+	int poll_count;
+	unsigned int jd_src;
+	unsigned int ovcd_th;
+	unsigned int ovcd_sf;
+
+	int irq;
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5651_AIFS];
+	int bclk[RT5651_AIFS];
+	int master[RT5651_AIFS];
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+	int dmic_en;
+	bool hp_mute;
+};
+
+#endif /* __RT5651_H__ */
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
new file mode 100644
index 0000000..1c1a521
--- /dev/null
+++ b/sound/soc/codecs/rt5659.c
@@ -0,0 +1,4372 @@
+/*
+ * rt5659.c  --  RT5659/RT5658 ALSA SoC audio codec driver
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/rt5659.h>
+
+#include "rl6231.h"
+#include "rt5659.h"
+
+static const struct reg_default rt5659_reg[] = {
+	{ 0x0000, 0x0000 },
+	{ 0x0001, 0x4848 },
+	{ 0x0002, 0x8080 },
+	{ 0x0003, 0xc8c8 },
+	{ 0x0004, 0xc80a },
+	{ 0x0005, 0x0000 },
+	{ 0x0006, 0x0000 },
+	{ 0x0007, 0x0103 },
+	{ 0x0008, 0x0080 },
+	{ 0x0009, 0x0000 },
+	{ 0x000a, 0x0000 },
+	{ 0x000c, 0x0000 },
+	{ 0x000d, 0x0000 },
+	{ 0x000f, 0x0808 },
+	{ 0x0010, 0x3080 },
+	{ 0x0011, 0x4a00 },
+	{ 0x0012, 0x4e00 },
+	{ 0x0015, 0x42c1 },
+	{ 0x0016, 0x0000 },
+	{ 0x0018, 0x000b },
+	{ 0x0019, 0xafaf },
+	{ 0x001a, 0xafaf },
+	{ 0x001b, 0x0011 },
+	{ 0x001c, 0x2f2f },
+	{ 0x001d, 0x2f2f },
+	{ 0x001e, 0x2f2f },
+	{ 0x001f, 0x0000 },
+	{ 0x0020, 0x0000 },
+	{ 0x0021, 0x0000 },
+	{ 0x0022, 0x5757 },
+	{ 0x0023, 0x0039 },
+	{ 0x0026, 0xc060 },
+	{ 0x0027, 0xd8d8 },
+	{ 0x0029, 0x8080 },
+	{ 0x002a, 0xaaaa },
+	{ 0x002b, 0xaaaa },
+	{ 0x002c, 0x00af },
+	{ 0x002d, 0x0000 },
+	{ 0x002f, 0x1002 },
+	{ 0x0031, 0x5000 },
+	{ 0x0032, 0x0000 },
+	{ 0x0033, 0x0000 },
+	{ 0x0034, 0x0000 },
+	{ 0x0035, 0x0000 },
+	{ 0x0036, 0x0000 },
+	{ 0x003a, 0x0000 },
+	{ 0x003b, 0x0000 },
+	{ 0x003c, 0x007f },
+	{ 0x003d, 0x0000 },
+	{ 0x003e, 0x007f },
+	{ 0x0040, 0x0808 },
+	{ 0x0046, 0x001f },
+	{ 0x0047, 0x001f },
+	{ 0x0048, 0x0003 },
+	{ 0x0049, 0xe061 },
+	{ 0x004a, 0x0000 },
+	{ 0x004b, 0x031f },
+	{ 0x004d, 0x0000 },
+	{ 0x004e, 0x001f },
+	{ 0x004f, 0x0000 },
+	{ 0x0050, 0x001f },
+	{ 0x0052, 0xf000 },
+	{ 0x0053, 0x0111 },
+	{ 0x0054, 0x0064 },
+	{ 0x0055, 0x0080 },
+	{ 0x0056, 0xef0e },
+	{ 0x0057, 0xf0f0 },
+	{ 0x0058, 0xef0e },
+	{ 0x0059, 0xf0f0 },
+	{ 0x005a, 0xef0e },
+	{ 0x005b, 0xf0f0 },
+	{ 0x005c, 0xf000 },
+	{ 0x005d, 0x0000 },
+	{ 0x005e, 0x1f2c },
+	{ 0x005f, 0x1f2c },
+	{ 0x0060, 0x2717 },
+	{ 0x0061, 0x0000 },
+	{ 0x0062, 0x0000 },
+	{ 0x0063, 0x003e },
+	{ 0x0064, 0x0000 },
+	{ 0x0065, 0x0000 },
+	{ 0x0066, 0x0000 },
+	{ 0x0067, 0x0000 },
+	{ 0x006a, 0x0000 },
+	{ 0x006b, 0x0000 },
+	{ 0x006c, 0x0000 },
+	{ 0x006e, 0x0000 },
+	{ 0x006f, 0x0000 },
+	{ 0x0070, 0x8000 },
+	{ 0x0071, 0x8000 },
+	{ 0x0072, 0x8000 },
+	{ 0x0073, 0x1110 },
+	{ 0x0074, 0xfe00 },
+	{ 0x0075, 0x2409 },
+	{ 0x0076, 0x000a },
+	{ 0x0077, 0x00f0 },
+	{ 0x0078, 0x0000 },
+	{ 0x0079, 0x0000 },
+	{ 0x007a, 0x0123 },
+	{ 0x007b, 0x8003 },
+	{ 0x0080, 0x0000 },
+	{ 0x0081, 0x0000 },
+	{ 0x0082, 0x0000 },
+	{ 0x0083, 0x0000 },
+	{ 0x0084, 0x0000 },
+	{ 0x0085, 0x0000 },
+	{ 0x0086, 0x0008 },
+	{ 0x0087, 0x0000 },
+	{ 0x0088, 0x0000 },
+	{ 0x0089, 0x0000 },
+	{ 0x008a, 0x0000 },
+	{ 0x008b, 0x0000 },
+	{ 0x008c, 0x0003 },
+	{ 0x008e, 0x0000 },
+	{ 0x008f, 0x1000 },
+	{ 0x0090, 0x0646 },
+	{ 0x0091, 0x0c16 },
+	{ 0x0092, 0x0073 },
+	{ 0x0093, 0x0000 },
+	{ 0x0094, 0x0080 },
+	{ 0x0097, 0x0000 },
+	{ 0x0098, 0x0000 },
+	{ 0x0099, 0x0000 },
+	{ 0x009a, 0x0000 },
+	{ 0x009b, 0x0000 },
+	{ 0x009c, 0x007f },
+	{ 0x009d, 0x0000 },
+	{ 0x009e, 0x007f },
+	{ 0x009f, 0x0000 },
+	{ 0x00a0, 0x0060 },
+	{ 0x00a1, 0x90a1 },
+	{ 0x00ae, 0x2000 },
+	{ 0x00af, 0x0000 },
+	{ 0x00b0, 0x2000 },
+	{ 0x00b1, 0x0000 },
+	{ 0x00b2, 0x0000 },
+	{ 0x00b6, 0x0000 },
+	{ 0x00b7, 0x0000 },
+	{ 0x00b8, 0x0000 },
+	{ 0x00b9, 0x0000 },
+	{ 0x00ba, 0x0000 },
+	{ 0x00bb, 0x0000 },
+	{ 0x00be, 0x0000 },
+	{ 0x00bf, 0x0000 },
+	{ 0x00c0, 0x0000 },
+	{ 0x00c1, 0x0000 },
+	{ 0x00c2, 0x0000 },
+	{ 0x00c3, 0x0000 },
+	{ 0x00c4, 0x0003 },
+	{ 0x00c5, 0x0000 },
+	{ 0x00cb, 0xa02f },
+	{ 0x00cc, 0x0000 },
+	{ 0x00cd, 0x0e02 },
+	{ 0x00d6, 0x0000 },
+	{ 0x00d7, 0x2244 },
+	{ 0x00d9, 0x0809 },
+	{ 0x00da, 0x0000 },
+	{ 0x00db, 0x0008 },
+	{ 0x00dc, 0x00c0 },
+	{ 0x00dd, 0x6724 },
+	{ 0x00de, 0x3131 },
+	{ 0x00df, 0x0008 },
+	{ 0x00e0, 0x4000 },
+	{ 0x00e1, 0x3131 },
+	{ 0x00e4, 0x400c },
+	{ 0x00e5, 0x8031 },
+	{ 0x00ea, 0xb320 },
+	{ 0x00eb, 0x0000 },
+	{ 0x00ec, 0xb300 },
+	{ 0x00ed, 0x0000 },
+	{ 0x00f0, 0x0000 },
+	{ 0x00f1, 0x0202 },
+	{ 0x00f2, 0x0ddd },
+	{ 0x00f3, 0x0ddd },
+	{ 0x00f4, 0x0ddd },
+	{ 0x00f6, 0x0000 },
+	{ 0x00f7, 0x0000 },
+	{ 0x00f8, 0x0000 },
+	{ 0x00f9, 0x0000 },
+	{ 0x00fa, 0x8000 },
+	{ 0x00fb, 0x0000 },
+	{ 0x00fc, 0x0000 },
+	{ 0x00fd, 0x0001 },
+	{ 0x00fe, 0x10ec },
+	{ 0x00ff, 0x6311 },
+	{ 0x0100, 0xaaaa },
+	{ 0x010a, 0xaaaa },
+	{ 0x010b, 0x00a0 },
+	{ 0x010c, 0xaeae },
+	{ 0x010d, 0xaaaa },
+	{ 0x010e, 0xaaa8 },
+	{ 0x010f, 0xa0aa },
+	{ 0x0110, 0xe02a },
+	{ 0x0111, 0xa702 },
+	{ 0x0112, 0xaaaa },
+	{ 0x0113, 0x2800 },
+	{ 0x0116, 0x0000 },
+	{ 0x0117, 0x0f00 },
+	{ 0x011a, 0x0020 },
+	{ 0x011b, 0x0011 },
+	{ 0x011c, 0x0150 },
+	{ 0x011d, 0x0000 },
+	{ 0x011e, 0x0000 },
+	{ 0x011f, 0x0000 },
+	{ 0x0120, 0x0000 },
+	{ 0x0121, 0x009b },
+	{ 0x0122, 0x5014 },
+	{ 0x0123, 0x0421 },
+	{ 0x0124, 0x7cea },
+	{ 0x0125, 0x0420 },
+	{ 0x0126, 0x5550 },
+	{ 0x0132, 0x0000 },
+	{ 0x0133, 0x0000 },
+	{ 0x0137, 0x5055 },
+	{ 0x0138, 0x3700 },
+	{ 0x0139, 0x79a1 },
+	{ 0x013a, 0x2020 },
+	{ 0x013b, 0x2020 },
+	{ 0x013c, 0x2005 },
+	{ 0x013e, 0x1f00 },
+	{ 0x013f, 0x0000 },
+	{ 0x0145, 0x0002 },
+	{ 0x0146, 0x0000 },
+	{ 0x0147, 0x0000 },
+	{ 0x0148, 0x0000 },
+	{ 0x0150, 0x1813 },
+	{ 0x0151, 0x0690 },
+	{ 0x0152, 0x1c17 },
+	{ 0x0153, 0x6883 },
+	{ 0x0154, 0xd3ce },
+	{ 0x0155, 0x352d },
+	{ 0x0156, 0x00eb },
+	{ 0x0157, 0x3717 },
+	{ 0x0158, 0x4c6a },
+	{ 0x0159, 0xe41b },
+	{ 0x015a, 0x2a13 },
+	{ 0x015b, 0xb600 },
+	{ 0x015c, 0xc730 },
+	{ 0x015d, 0x35d4 },
+	{ 0x015e, 0x00bf },
+	{ 0x0160, 0x0ec0 },
+	{ 0x0161, 0x0020 },
+	{ 0x0162, 0x0080 },
+	{ 0x0163, 0x0800 },
+	{ 0x0164, 0x0000 },
+	{ 0x0165, 0x0000 },
+	{ 0x0166, 0x0000 },
+	{ 0x0167, 0x001f },
+	{ 0x0170, 0x4e80 },
+	{ 0x0171, 0x0020 },
+	{ 0x0172, 0x0080 },
+	{ 0x0173, 0x0800 },
+	{ 0x0174, 0x000c },
+	{ 0x0175, 0x0000 },
+	{ 0x0190, 0x3300 },
+	{ 0x0191, 0x2200 },
+	{ 0x0192, 0x0000 },
+	{ 0x01b0, 0x4b38 },
+	{ 0x01b1, 0x0000 },
+	{ 0x01b2, 0x0000 },
+	{ 0x01b3, 0x0000 },
+	{ 0x01c0, 0x0045 },
+	{ 0x01c1, 0x0540 },
+	{ 0x01c2, 0x0000 },
+	{ 0x01c3, 0x0030 },
+	{ 0x01c7, 0x0000 },
+	{ 0x01c8, 0x5757 },
+	{ 0x01c9, 0x5757 },
+	{ 0x01ca, 0x5757 },
+	{ 0x01cb, 0x5757 },
+	{ 0x01cc, 0x5757 },
+	{ 0x01cd, 0x5757 },
+	{ 0x01ce, 0x006f },
+	{ 0x01da, 0x0000 },
+	{ 0x01db, 0x0000 },
+	{ 0x01de, 0x7d00 },
+	{ 0x01df, 0x10c0 },
+	{ 0x01e0, 0x06a1 },
+	{ 0x01e1, 0x0000 },
+	{ 0x01e2, 0x0000 },
+	{ 0x01e3, 0x0000 },
+	{ 0x01e4, 0x0001 },
+	{ 0x01e6, 0x0000 },
+	{ 0x01e7, 0x0000 },
+	{ 0x01e8, 0x0000 },
+	{ 0x01ea, 0x0000 },
+	{ 0x01eb, 0x0000 },
+	{ 0x01ec, 0x0000 },
+	{ 0x01ed, 0x0000 },
+	{ 0x01ee, 0x0000 },
+	{ 0x01ef, 0x0000 },
+	{ 0x01f0, 0x0000 },
+	{ 0x01f1, 0x0000 },
+	{ 0x01f2, 0x0000 },
+	{ 0x01f6, 0x1e04 },
+	{ 0x01f7, 0x01a1 },
+	{ 0x01f8, 0x0000 },
+	{ 0x01f9, 0x0000 },
+	{ 0x01fa, 0x0002 },
+	{ 0x01fb, 0x0000 },
+	{ 0x01fc, 0x0000 },
+	{ 0x01fd, 0x0000 },
+	{ 0x01fe, 0x0000 },
+	{ 0x0200, 0x066c },
+	{ 0x0201, 0x7fff },
+	{ 0x0202, 0x7fff },
+	{ 0x0203, 0x0000 },
+	{ 0x0204, 0x0000 },
+	{ 0x0205, 0x0000 },
+	{ 0x0206, 0x0000 },
+	{ 0x0207, 0x0000 },
+	{ 0x0208, 0x0000 },
+	{ 0x0256, 0x0000 },
+	{ 0x0257, 0x0000 },
+	{ 0x0258, 0x0000 },
+	{ 0x0259, 0x0000 },
+	{ 0x025a, 0x0000 },
+	{ 0x025b, 0x3333 },
+	{ 0x025c, 0x3333 },
+	{ 0x025d, 0x3333 },
+	{ 0x025e, 0x0000 },
+	{ 0x025f, 0x0000 },
+	{ 0x0260, 0x0000 },
+	{ 0x0261, 0x0022 },
+	{ 0x0262, 0x0300 },
+	{ 0x0265, 0x1e80 },
+	{ 0x0266, 0x0131 },
+	{ 0x0267, 0x0003 },
+	{ 0x0268, 0x0000 },
+	{ 0x0269, 0x0000 },
+	{ 0x026a, 0x0000 },
+	{ 0x026b, 0x0000 },
+	{ 0x026c, 0x0000 },
+	{ 0x026d, 0x0000 },
+	{ 0x026e, 0x0000 },
+	{ 0x026f, 0x0000 },
+	{ 0x0270, 0x0000 },
+	{ 0x0271, 0x0000 },
+	{ 0x0272, 0x0000 },
+	{ 0x0273, 0x0000 },
+	{ 0x0280, 0x0000 },
+	{ 0x0281, 0x0000 },
+	{ 0x0282, 0x0418 },
+	{ 0x0283, 0x7fff },
+	{ 0x0284, 0x7000 },
+	{ 0x0290, 0x01d0 },
+	{ 0x0291, 0x0100 },
+	{ 0x02fa, 0x0000 },
+	{ 0x02fb, 0x0000 },
+	{ 0x02fc, 0x0000 },
+	{ 0x0300, 0x001f },
+	{ 0x0301, 0x032c },
+	{ 0x0302, 0x5f21 },
+	{ 0x0303, 0x4000 },
+	{ 0x0304, 0x4000 },
+	{ 0x0305, 0x0600 },
+	{ 0x0306, 0x8000 },
+	{ 0x0307, 0x0700 },
+	{ 0x0308, 0x001f },
+	{ 0x0309, 0x032c },
+	{ 0x030a, 0x5f21 },
+	{ 0x030b, 0x4000 },
+	{ 0x030c, 0x4000 },
+	{ 0x030d, 0x0600 },
+	{ 0x030e, 0x8000 },
+	{ 0x030f, 0x0700 },
+	{ 0x0310, 0x4560 },
+	{ 0x0311, 0xa4a8 },
+	{ 0x0312, 0x7418 },
+	{ 0x0313, 0x0000 },
+	{ 0x0314, 0x0006 },
+	{ 0x0315, 0x00ff },
+	{ 0x0316, 0xc400 },
+	{ 0x0317, 0x4560 },
+	{ 0x0318, 0xa4a8 },
+	{ 0x0319, 0x7418 },
+	{ 0x031a, 0x0000 },
+	{ 0x031b, 0x0006 },
+	{ 0x031c, 0x00ff },
+	{ 0x031d, 0xc400 },
+	{ 0x0320, 0x0f20 },
+	{ 0x0321, 0x8700 },
+	{ 0x0322, 0x7dc2 },
+	{ 0x0323, 0xa178 },
+	{ 0x0324, 0x5383 },
+	{ 0x0325, 0x7dc2 },
+	{ 0x0326, 0xa178 },
+	{ 0x0327, 0x5383 },
+	{ 0x0328, 0x003e },
+	{ 0x0329, 0x02c1 },
+	{ 0x032a, 0xd37d },
+	{ 0x0330, 0x00a6 },
+	{ 0x0331, 0x04c3 },
+	{ 0x0332, 0x27c8 },
+	{ 0x0333, 0xbf50 },
+	{ 0x0334, 0x0045 },
+	{ 0x0335, 0x2007 },
+	{ 0x0336, 0x7418 },
+	{ 0x0337, 0x0501 },
+	{ 0x0338, 0x0000 },
+	{ 0x0339, 0x0010 },
+	{ 0x033a, 0x1010 },
+	{ 0x0340, 0x0800 },
+	{ 0x0341, 0x0800 },
+	{ 0x0342, 0x0800 },
+	{ 0x0343, 0x0800 },
+	{ 0x0344, 0x0000 },
+	{ 0x0345, 0x0000 },
+	{ 0x0346, 0x0000 },
+	{ 0x0347, 0x0000 },
+	{ 0x0348, 0x0000 },
+	{ 0x0349, 0x0000 },
+	{ 0x034a, 0x0000 },
+	{ 0x034b, 0x0000 },
+	{ 0x034c, 0x0000 },
+	{ 0x034d, 0x0000 },
+	{ 0x034e, 0x0000 },
+	{ 0x034f, 0x0000 },
+	{ 0x0350, 0x0000 },
+	{ 0x0351, 0x0000 },
+	{ 0x0352, 0x0000 },
+	{ 0x0353, 0x0000 },
+	{ 0x0354, 0x0000 },
+	{ 0x0355, 0x0000 },
+	{ 0x0356, 0x0000 },
+	{ 0x0357, 0x0000 },
+	{ 0x0358, 0x0000 },
+	{ 0x0359, 0x0000 },
+	{ 0x035a, 0x0000 },
+	{ 0x035b, 0x0000 },
+	{ 0x035c, 0x0000 },
+	{ 0x035d, 0x0000 },
+	{ 0x035e, 0x2000 },
+	{ 0x035f, 0x0000 },
+	{ 0x0360, 0x2000 },
+	{ 0x0361, 0x2000 },
+	{ 0x0362, 0x0000 },
+	{ 0x0363, 0x2000 },
+	{ 0x0364, 0x0200 },
+	{ 0x0365, 0x0000 },
+	{ 0x0366, 0x0000 },
+	{ 0x0367, 0x0000 },
+	{ 0x0368, 0x0000 },
+	{ 0x0369, 0x0000 },
+	{ 0x036a, 0x0000 },
+	{ 0x036b, 0x0000 },
+	{ 0x036c, 0x0000 },
+	{ 0x036d, 0x0000 },
+	{ 0x036e, 0x0200 },
+	{ 0x036f, 0x0000 },
+	{ 0x0370, 0x0000 },
+	{ 0x0371, 0x0000 },
+	{ 0x0372, 0x0000 },
+	{ 0x0373, 0x0000 },
+	{ 0x0374, 0x0000 },
+	{ 0x0375, 0x0000 },
+	{ 0x0376, 0x0000 },
+	{ 0x0377, 0x0000 },
+	{ 0x03d0, 0x0000 },
+	{ 0x03d1, 0x0000 },
+	{ 0x03d2, 0x0000 },
+	{ 0x03d3, 0x0000 },
+	{ 0x03d4, 0x2000 },
+	{ 0x03d5, 0x2000 },
+	{ 0x03d6, 0x0000 },
+	{ 0x03d7, 0x0000 },
+	{ 0x03d8, 0x2000 },
+	{ 0x03d9, 0x2000 },
+	{ 0x03da, 0x2000 },
+	{ 0x03db, 0x2000 },
+	{ 0x03dc, 0x0000 },
+	{ 0x03dd, 0x0000 },
+	{ 0x03de, 0x0000 },
+	{ 0x03df, 0x2000 },
+	{ 0x03e0, 0x0000 },
+	{ 0x03e1, 0x0000 },
+	{ 0x03e2, 0x0000 },
+	{ 0x03e3, 0x0000 },
+	{ 0x03e4, 0x0000 },
+	{ 0x03e5, 0x0000 },
+	{ 0x03e6, 0x0000 },
+	{ 0x03e7, 0x0000 },
+	{ 0x03e8, 0x0000 },
+	{ 0x03e9, 0x0000 },
+	{ 0x03ea, 0x0000 },
+	{ 0x03eb, 0x0000 },
+	{ 0x03ec, 0x0000 },
+	{ 0x03ed, 0x0000 },
+	{ 0x03ee, 0x0000 },
+	{ 0x03ef, 0x0000 },
+	{ 0x03f0, 0x0800 },
+	{ 0x03f1, 0x0800 },
+	{ 0x03f2, 0x0800 },
+	{ 0x03f3, 0x0800 },
+};
+
+static bool rt5659_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5659_RESET:
+	case RT5659_EJD_CTRL_2:
+	case RT5659_SILENCE_CTRL:
+	case RT5659_DAC2_DIG_VOL:
+	case RT5659_HP_IMP_GAIN_2:
+	case RT5659_PDM_OUT_CTRL:
+	case RT5659_PDM_DATA_CTRL_1:
+	case RT5659_PDM_DATA_CTRL_4:
+	case RT5659_HAPTIC_GEN_CTRL_1:
+	case RT5659_HAPTIC_GEN_CTRL_3:
+	case RT5659_HAPTIC_LPF_CTRL_3:
+	case RT5659_CLK_DET:
+	case RT5659_MICBIAS_1:
+	case RT5659_ASRC_11:
+	case RT5659_ADC_EQ_CTRL_1:
+	case RT5659_DAC_EQ_CTRL_1:
+	case RT5659_INT_ST_1:
+	case RT5659_INT_ST_2:
+	case RT5659_GPIO_STA:
+	case RT5659_SINE_GEN_CTRL_1:
+	case RT5659_IL_CMD_1:
+	case RT5659_4BTN_IL_CMD_1:
+	case RT5659_PSV_IL_CMD_1:
+	case RT5659_AJD1_CTRL:
+	case RT5659_AJD2_AJD3_CTRL:
+	case RT5659_JD_CTRL_3:
+	case RT5659_VENDOR_ID:
+	case RT5659_VENDOR_ID_1:
+	case RT5659_DEVICE_ID:
+	case RT5659_MEMORY_TEST:
+	case RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL:
+	case RT5659_VOL_TEST:
+	case RT5659_STO_NG2_CTRL_1:
+	case RT5659_STO_NG2_CTRL_5:
+	case RT5659_STO_NG2_CTRL_6:
+	case RT5659_STO_NG2_CTRL_7:
+	case RT5659_MONO_NG2_CTRL_1:
+	case RT5659_MONO_NG2_CTRL_5:
+	case RT5659_MONO_NG2_CTRL_6:
+	case RT5659_HP_IMP_SENS_CTRL_1:
+	case RT5659_HP_IMP_SENS_CTRL_3:
+	case RT5659_HP_IMP_SENS_CTRL_4:
+	case RT5659_HP_CALIB_CTRL_1:
+	case RT5659_HP_CALIB_CTRL_9:
+	case RT5659_HP_CALIB_STA_1:
+	case RT5659_HP_CALIB_STA_2:
+	case RT5659_HP_CALIB_STA_3:
+	case RT5659_HP_CALIB_STA_4:
+	case RT5659_HP_CALIB_STA_5:
+	case RT5659_HP_CALIB_STA_6:
+	case RT5659_HP_CALIB_STA_7:
+	case RT5659_HP_CALIB_STA_8:
+	case RT5659_HP_CALIB_STA_9:
+	case RT5659_MONO_AMP_CALIB_CTRL_1:
+	case RT5659_MONO_AMP_CALIB_CTRL_3:
+	case RT5659_MONO_AMP_CALIB_STA_1:
+	case RT5659_MONO_AMP_CALIB_STA_2:
+	case RT5659_MONO_AMP_CALIB_STA_3:
+	case RT5659_MONO_AMP_CALIB_STA_4:
+	case RT5659_SPK_PWR_LMT_STA_1:
+	case RT5659_SPK_PWR_LMT_STA_2:
+	case RT5659_SPK_PWR_LMT_STA_3:
+	case RT5659_SPK_PWR_LMT_STA_4:
+	case RT5659_SPK_PWR_LMT_STA_5:
+	case RT5659_SPK_PWR_LMT_STA_6:
+	case RT5659_SPK_DC_CAILB_CTRL_1:
+	case RT5659_SPK_DC_CAILB_STA_1:
+	case RT5659_SPK_DC_CAILB_STA_2:
+	case RT5659_SPK_DC_CAILB_STA_3:
+	case RT5659_SPK_DC_CAILB_STA_4:
+	case RT5659_SPK_DC_CAILB_STA_5:
+	case RT5659_SPK_DC_CAILB_STA_6:
+	case RT5659_SPK_DC_CAILB_STA_7:
+	case RT5659_SPK_DC_CAILB_STA_8:
+	case RT5659_SPK_DC_CAILB_STA_9:
+	case RT5659_SPK_DC_CAILB_STA_10:
+	case RT5659_SPK_VDD_STA_1:
+	case RT5659_SPK_VDD_STA_2:
+	case RT5659_SPK_DC_DET_CTRL_1:
+	case RT5659_PURE_DC_DET_CTRL_1:
+	case RT5659_PURE_DC_DET_CTRL_2:
+	case RT5659_DRC1_PRIV_1:
+	case RT5659_DRC1_PRIV_4:
+	case RT5659_DRC1_PRIV_5:
+	case RT5659_DRC1_PRIV_6:
+	case RT5659_DRC1_PRIV_7:
+	case RT5659_DRC2_PRIV_1:
+	case RT5659_DRC2_PRIV_4:
+	case RT5659_DRC2_PRIV_5:
+	case RT5659_DRC2_PRIV_6:
+	case RT5659_DRC2_PRIV_7:
+	case RT5659_ALC_PGA_STA_1:
+	case RT5659_ALC_PGA_STA_2:
+	case RT5659_ALC_PGA_STA_3:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5659_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5659_RESET:
+	case RT5659_SPO_VOL:
+	case RT5659_HP_VOL:
+	case RT5659_LOUT:
+	case RT5659_MONO_OUT:
+	case RT5659_HPL_GAIN:
+	case RT5659_HPR_GAIN:
+	case RT5659_MONO_GAIN:
+	case RT5659_SPDIF_CTRL_1:
+	case RT5659_SPDIF_CTRL_2:
+	case RT5659_CAL_BST_CTRL:
+	case RT5659_IN1_IN2:
+	case RT5659_IN3_IN4:
+	case RT5659_INL1_INR1_VOL:
+	case RT5659_EJD_CTRL_1:
+	case RT5659_EJD_CTRL_2:
+	case RT5659_EJD_CTRL_3:
+	case RT5659_SILENCE_CTRL:
+	case RT5659_PSV_CTRL:
+	case RT5659_SIDETONE_CTRL:
+	case RT5659_DAC1_DIG_VOL:
+	case RT5659_DAC2_DIG_VOL:
+	case RT5659_DAC_CTRL:
+	case RT5659_STO1_ADC_DIG_VOL:
+	case RT5659_MONO_ADC_DIG_VOL:
+	case RT5659_STO2_ADC_DIG_VOL:
+	case RT5659_STO1_BOOST:
+	case RT5659_MONO_BOOST:
+	case RT5659_STO2_BOOST:
+	case RT5659_HP_IMP_GAIN_1:
+	case RT5659_HP_IMP_GAIN_2:
+	case RT5659_STO1_ADC_MIXER:
+	case RT5659_MONO_ADC_MIXER:
+	case RT5659_AD_DA_MIXER:
+	case RT5659_STO_DAC_MIXER:
+	case RT5659_MONO_DAC_MIXER:
+	case RT5659_DIG_MIXER:
+	case RT5659_A_DAC_MUX:
+	case RT5659_DIG_INF23_DATA:
+	case RT5659_PDM_OUT_CTRL:
+	case RT5659_PDM_DATA_CTRL_1:
+	case RT5659_PDM_DATA_CTRL_2:
+	case RT5659_PDM_DATA_CTRL_3:
+	case RT5659_PDM_DATA_CTRL_4:
+	case RT5659_SPDIF_CTRL:
+	case RT5659_REC1_GAIN:
+	case RT5659_REC1_L1_MIXER:
+	case RT5659_REC1_L2_MIXER:
+	case RT5659_REC1_R1_MIXER:
+	case RT5659_REC1_R2_MIXER:
+	case RT5659_CAL_REC:
+	case RT5659_REC2_L1_MIXER:
+	case RT5659_REC2_L2_MIXER:
+	case RT5659_REC2_R1_MIXER:
+	case RT5659_REC2_R2_MIXER:
+	case RT5659_SPK_L_MIXER:
+	case RT5659_SPK_R_MIXER:
+	case RT5659_SPO_AMP_GAIN:
+	case RT5659_ALC_BACK_GAIN:
+	case RT5659_MONOMIX_GAIN:
+	case RT5659_MONOMIX_IN_GAIN:
+	case RT5659_OUT_L_GAIN:
+	case RT5659_OUT_L_MIXER:
+	case RT5659_OUT_R_GAIN:
+	case RT5659_OUT_R_MIXER:
+	case RT5659_LOUT_MIXER:
+	case RT5659_HAPTIC_GEN_CTRL_1:
+	case RT5659_HAPTIC_GEN_CTRL_2:
+	case RT5659_HAPTIC_GEN_CTRL_3:
+	case RT5659_HAPTIC_GEN_CTRL_4:
+	case RT5659_HAPTIC_GEN_CTRL_5:
+	case RT5659_HAPTIC_GEN_CTRL_6:
+	case RT5659_HAPTIC_GEN_CTRL_7:
+	case RT5659_HAPTIC_GEN_CTRL_8:
+	case RT5659_HAPTIC_GEN_CTRL_9:
+	case RT5659_HAPTIC_GEN_CTRL_10:
+	case RT5659_HAPTIC_GEN_CTRL_11:
+	case RT5659_HAPTIC_LPF_CTRL_1:
+	case RT5659_HAPTIC_LPF_CTRL_2:
+	case RT5659_HAPTIC_LPF_CTRL_3:
+	case RT5659_PWR_DIG_1:
+	case RT5659_PWR_DIG_2:
+	case RT5659_PWR_ANLG_1:
+	case RT5659_PWR_ANLG_2:
+	case RT5659_PWR_ANLG_3:
+	case RT5659_PWR_MIXER:
+	case RT5659_PWR_VOL:
+	case RT5659_PRIV_INDEX:
+	case RT5659_CLK_DET:
+	case RT5659_PRIV_DATA:
+	case RT5659_PRE_DIV_1:
+	case RT5659_PRE_DIV_2:
+	case RT5659_I2S1_SDP:
+	case RT5659_I2S2_SDP:
+	case RT5659_I2S3_SDP:
+	case RT5659_ADDA_CLK_1:
+	case RT5659_ADDA_CLK_2:
+	case RT5659_DMIC_CTRL_1:
+	case RT5659_DMIC_CTRL_2:
+	case RT5659_TDM_CTRL_1:
+	case RT5659_TDM_CTRL_2:
+	case RT5659_TDM_CTRL_3:
+	case RT5659_TDM_CTRL_4:
+	case RT5659_TDM_CTRL_5:
+	case RT5659_GLB_CLK:
+	case RT5659_PLL_CTRL_1:
+	case RT5659_PLL_CTRL_2:
+	case RT5659_ASRC_1:
+	case RT5659_ASRC_2:
+	case RT5659_ASRC_3:
+	case RT5659_ASRC_4:
+	case RT5659_ASRC_5:
+	case RT5659_ASRC_6:
+	case RT5659_ASRC_7:
+	case RT5659_ASRC_8:
+	case RT5659_ASRC_9:
+	case RT5659_ASRC_10:
+	case RT5659_DEPOP_1:
+	case RT5659_DEPOP_2:
+	case RT5659_DEPOP_3:
+	case RT5659_HP_CHARGE_PUMP_1:
+	case RT5659_HP_CHARGE_PUMP_2:
+	case RT5659_MICBIAS_1:
+	case RT5659_MICBIAS_2:
+	case RT5659_ASRC_11:
+	case RT5659_ASRC_12:
+	case RT5659_ASRC_13:
+	case RT5659_REC_M1_M2_GAIN_CTRL:
+	case RT5659_RC_CLK_CTRL:
+	case RT5659_CLASSD_CTRL_1:
+	case RT5659_CLASSD_CTRL_2:
+	case RT5659_ADC_EQ_CTRL_1:
+	case RT5659_ADC_EQ_CTRL_2:
+	case RT5659_DAC_EQ_CTRL_1:
+	case RT5659_DAC_EQ_CTRL_2:
+	case RT5659_DAC_EQ_CTRL_3:
+	case RT5659_IRQ_CTRL_1:
+	case RT5659_IRQ_CTRL_2:
+	case RT5659_IRQ_CTRL_3:
+	case RT5659_IRQ_CTRL_4:
+	case RT5659_IRQ_CTRL_5:
+	case RT5659_IRQ_CTRL_6:
+	case RT5659_INT_ST_1:
+	case RT5659_INT_ST_2:
+	case RT5659_GPIO_CTRL_1:
+	case RT5659_GPIO_CTRL_2:
+	case RT5659_GPIO_CTRL_3:
+	case RT5659_GPIO_CTRL_4:
+	case RT5659_GPIO_CTRL_5:
+	case RT5659_GPIO_STA:
+	case RT5659_SINE_GEN_CTRL_1:
+	case RT5659_SINE_GEN_CTRL_2:
+	case RT5659_SINE_GEN_CTRL_3:
+	case RT5659_HP_AMP_DET_CTRL_1:
+	case RT5659_HP_AMP_DET_CTRL_2:
+	case RT5659_SV_ZCD_1:
+	case RT5659_SV_ZCD_2:
+	case RT5659_IL_CMD_1:
+	case RT5659_IL_CMD_2:
+	case RT5659_IL_CMD_3:
+	case RT5659_IL_CMD_4:
+	case RT5659_4BTN_IL_CMD_1:
+	case RT5659_4BTN_IL_CMD_2:
+	case RT5659_4BTN_IL_CMD_3:
+	case RT5659_PSV_IL_CMD_1:
+	case RT5659_PSV_IL_CMD_2:
+	case RT5659_ADC_STO1_HP_CTRL_1:
+	case RT5659_ADC_STO1_HP_CTRL_2:
+	case RT5659_ADC_MONO_HP_CTRL_1:
+	case RT5659_ADC_MONO_HP_CTRL_2:
+	case RT5659_AJD1_CTRL:
+	case RT5659_AJD2_AJD3_CTRL:
+	case RT5659_JD1_THD:
+	case RT5659_JD2_THD:
+	case RT5659_JD3_THD:
+	case RT5659_JD_CTRL_1:
+	case RT5659_JD_CTRL_2:
+	case RT5659_JD_CTRL_3:
+	case RT5659_JD_CTRL_4:
+	case RT5659_DIG_MISC:
+	case RT5659_DUMMY_2:
+	case RT5659_DUMMY_3:
+	case RT5659_VENDOR_ID:
+	case RT5659_VENDOR_ID_1:
+	case RT5659_DEVICE_ID:
+	case RT5659_DAC_ADC_DIG_VOL:
+	case RT5659_BIAS_CUR_CTRL_1:
+	case RT5659_BIAS_CUR_CTRL_2:
+	case RT5659_BIAS_CUR_CTRL_3:
+	case RT5659_BIAS_CUR_CTRL_4:
+	case RT5659_BIAS_CUR_CTRL_5:
+	case RT5659_BIAS_CUR_CTRL_6:
+	case RT5659_BIAS_CUR_CTRL_7:
+	case RT5659_BIAS_CUR_CTRL_8:
+	case RT5659_BIAS_CUR_CTRL_9:
+	case RT5659_BIAS_CUR_CTRL_10:
+	case RT5659_MEMORY_TEST:
+	case RT5659_VREF_REC_OP_FB_CAP_CTRL:
+	case RT5659_CLASSD_0:
+	case RT5659_CLASSD_1:
+	case RT5659_CLASSD_2:
+	case RT5659_CLASSD_3:
+	case RT5659_CLASSD_4:
+	case RT5659_CLASSD_5:
+	case RT5659_CLASSD_6:
+	case RT5659_CLASSD_7:
+	case RT5659_CLASSD_8:
+	case RT5659_CLASSD_9:
+	case RT5659_CLASSD_10:
+	case RT5659_CHARGE_PUMP_1:
+	case RT5659_CHARGE_PUMP_2:
+	case RT5659_DIG_IN_CTRL_1:
+	case RT5659_DIG_IN_CTRL_2:
+	case RT5659_PAD_DRIVING_CTRL:
+	case RT5659_SOFT_RAMP_DEPOP:
+	case RT5659_PLL:
+	case RT5659_CHOP_DAC:
+	case RT5659_CHOP_ADC:
+	case RT5659_CALIB_ADC_CTRL:
+	case RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL:
+	case RT5659_VOL_TEST:
+	case RT5659_TEST_MODE_CTRL_1:
+	case RT5659_TEST_MODE_CTRL_2:
+	case RT5659_TEST_MODE_CTRL_3:
+	case RT5659_TEST_MODE_CTRL_4:
+	case RT5659_BASSBACK_CTRL:
+	case RT5659_MP3_PLUS_CTRL_1:
+	case RT5659_MP3_PLUS_CTRL_2:
+	case RT5659_MP3_HPF_A1:
+	case RT5659_MP3_HPF_A2:
+	case RT5659_MP3_HPF_H0:
+	case RT5659_MP3_LPF_H0:
+	case RT5659_3D_SPK_CTRL:
+	case RT5659_3D_SPK_COEF_1:
+	case RT5659_3D_SPK_COEF_2:
+	case RT5659_3D_SPK_COEF_3:
+	case RT5659_3D_SPK_COEF_4:
+	case RT5659_3D_SPK_COEF_5:
+	case RT5659_3D_SPK_COEF_6:
+	case RT5659_3D_SPK_COEF_7:
+	case RT5659_STO_NG2_CTRL_1:
+	case RT5659_STO_NG2_CTRL_2:
+	case RT5659_STO_NG2_CTRL_3:
+	case RT5659_STO_NG2_CTRL_4:
+	case RT5659_STO_NG2_CTRL_5:
+	case RT5659_STO_NG2_CTRL_6:
+	case RT5659_STO_NG2_CTRL_7:
+	case RT5659_STO_NG2_CTRL_8:
+	case RT5659_MONO_NG2_CTRL_1:
+	case RT5659_MONO_NG2_CTRL_2:
+	case RT5659_MONO_NG2_CTRL_3:
+	case RT5659_MONO_NG2_CTRL_4:
+	case RT5659_MONO_NG2_CTRL_5:
+	case RT5659_MONO_NG2_CTRL_6:
+	case RT5659_MID_HP_AMP_DET:
+	case RT5659_LOW_HP_AMP_DET:
+	case RT5659_LDO_CTRL:
+	case RT5659_HP_DECROSS_CTRL_1:
+	case RT5659_HP_DECROSS_CTRL_2:
+	case RT5659_HP_DECROSS_CTRL_3:
+	case RT5659_HP_DECROSS_CTRL_4:
+	case RT5659_HP_IMP_SENS_CTRL_1:
+	case RT5659_HP_IMP_SENS_CTRL_2:
+	case RT5659_HP_IMP_SENS_CTRL_3:
+	case RT5659_HP_IMP_SENS_CTRL_4:
+	case RT5659_HP_IMP_SENS_MAP_1:
+	case RT5659_HP_IMP_SENS_MAP_2:
+	case RT5659_HP_IMP_SENS_MAP_3:
+	case RT5659_HP_IMP_SENS_MAP_4:
+	case RT5659_HP_IMP_SENS_MAP_5:
+	case RT5659_HP_IMP_SENS_MAP_6:
+	case RT5659_HP_IMP_SENS_MAP_7:
+	case RT5659_HP_IMP_SENS_MAP_8:
+	case RT5659_HP_LOGIC_CTRL_1:
+	case RT5659_HP_LOGIC_CTRL_2:
+	case RT5659_HP_CALIB_CTRL_1:
+	case RT5659_HP_CALIB_CTRL_2:
+	case RT5659_HP_CALIB_CTRL_3:
+	case RT5659_HP_CALIB_CTRL_4:
+	case RT5659_HP_CALIB_CTRL_5:
+	case RT5659_HP_CALIB_CTRL_6:
+	case RT5659_HP_CALIB_CTRL_7:
+	case RT5659_HP_CALIB_CTRL_9:
+	case RT5659_HP_CALIB_CTRL_10:
+	case RT5659_HP_CALIB_CTRL_11:
+	case RT5659_HP_CALIB_STA_1:
+	case RT5659_HP_CALIB_STA_2:
+	case RT5659_HP_CALIB_STA_3:
+	case RT5659_HP_CALIB_STA_4:
+	case RT5659_HP_CALIB_STA_5:
+	case RT5659_HP_CALIB_STA_6:
+	case RT5659_HP_CALIB_STA_7:
+	case RT5659_HP_CALIB_STA_8:
+	case RT5659_HP_CALIB_STA_9:
+	case RT5659_MONO_AMP_CALIB_CTRL_1:
+	case RT5659_MONO_AMP_CALIB_CTRL_2:
+	case RT5659_MONO_AMP_CALIB_CTRL_3:
+	case RT5659_MONO_AMP_CALIB_CTRL_4:
+	case RT5659_MONO_AMP_CALIB_CTRL_5:
+	case RT5659_MONO_AMP_CALIB_STA_1:
+	case RT5659_MONO_AMP_CALIB_STA_2:
+	case RT5659_MONO_AMP_CALIB_STA_3:
+	case RT5659_MONO_AMP_CALIB_STA_4:
+	case RT5659_SPK_PWR_LMT_CTRL_1:
+	case RT5659_SPK_PWR_LMT_CTRL_2:
+	case RT5659_SPK_PWR_LMT_CTRL_3:
+	case RT5659_SPK_PWR_LMT_STA_1:
+	case RT5659_SPK_PWR_LMT_STA_2:
+	case RT5659_SPK_PWR_LMT_STA_3:
+	case RT5659_SPK_PWR_LMT_STA_4:
+	case RT5659_SPK_PWR_LMT_STA_5:
+	case RT5659_SPK_PWR_LMT_STA_6:
+	case RT5659_FLEX_SPK_BST_CTRL_1:
+	case RT5659_FLEX_SPK_BST_CTRL_2:
+	case RT5659_FLEX_SPK_BST_CTRL_3:
+	case RT5659_FLEX_SPK_BST_CTRL_4:
+	case RT5659_SPK_EX_LMT_CTRL_1:
+	case RT5659_SPK_EX_LMT_CTRL_2:
+	case RT5659_SPK_EX_LMT_CTRL_3:
+	case RT5659_SPK_EX_LMT_CTRL_4:
+	case RT5659_SPK_EX_LMT_CTRL_5:
+	case RT5659_SPK_EX_LMT_CTRL_6:
+	case RT5659_SPK_EX_LMT_CTRL_7:
+	case RT5659_ADJ_HPF_CTRL_1:
+	case RT5659_ADJ_HPF_CTRL_2:
+	case RT5659_SPK_DC_CAILB_CTRL_1:
+	case RT5659_SPK_DC_CAILB_CTRL_2:
+	case RT5659_SPK_DC_CAILB_CTRL_3:
+	case RT5659_SPK_DC_CAILB_CTRL_4:
+	case RT5659_SPK_DC_CAILB_CTRL_5:
+	case RT5659_SPK_DC_CAILB_STA_1:
+	case RT5659_SPK_DC_CAILB_STA_2:
+	case RT5659_SPK_DC_CAILB_STA_3:
+	case RT5659_SPK_DC_CAILB_STA_4:
+	case RT5659_SPK_DC_CAILB_STA_5:
+	case RT5659_SPK_DC_CAILB_STA_6:
+	case RT5659_SPK_DC_CAILB_STA_7:
+	case RT5659_SPK_DC_CAILB_STA_8:
+	case RT5659_SPK_DC_CAILB_STA_9:
+	case RT5659_SPK_DC_CAILB_STA_10:
+	case RT5659_SPK_VDD_STA_1:
+	case RT5659_SPK_VDD_STA_2:
+	case RT5659_SPK_DC_DET_CTRL_1:
+	case RT5659_SPK_DC_DET_CTRL_2:
+	case RT5659_SPK_DC_DET_CTRL_3:
+	case RT5659_PURE_DC_DET_CTRL_1:
+	case RT5659_PURE_DC_DET_CTRL_2:
+	case RT5659_DUMMY_4:
+	case RT5659_DUMMY_5:
+	case RT5659_DUMMY_6:
+	case RT5659_DRC1_CTRL_1:
+	case RT5659_DRC1_CTRL_2:
+	case RT5659_DRC1_CTRL_3:
+	case RT5659_DRC1_CTRL_4:
+	case RT5659_DRC1_CTRL_5:
+	case RT5659_DRC1_CTRL_6:
+	case RT5659_DRC1_HARD_LMT_CTRL_1:
+	case RT5659_DRC1_HARD_LMT_CTRL_2:
+	case RT5659_DRC2_CTRL_1:
+	case RT5659_DRC2_CTRL_2:
+	case RT5659_DRC2_CTRL_3:
+	case RT5659_DRC2_CTRL_4:
+	case RT5659_DRC2_CTRL_5:
+	case RT5659_DRC2_CTRL_6:
+	case RT5659_DRC2_HARD_LMT_CTRL_1:
+	case RT5659_DRC2_HARD_LMT_CTRL_2:
+	case RT5659_DRC1_PRIV_1:
+	case RT5659_DRC1_PRIV_2:
+	case RT5659_DRC1_PRIV_3:
+	case RT5659_DRC1_PRIV_4:
+	case RT5659_DRC1_PRIV_5:
+	case RT5659_DRC1_PRIV_6:
+	case RT5659_DRC1_PRIV_7:
+	case RT5659_DRC2_PRIV_1:
+	case RT5659_DRC2_PRIV_2:
+	case RT5659_DRC2_PRIV_3:
+	case RT5659_DRC2_PRIV_4:
+	case RT5659_DRC2_PRIV_5:
+	case RT5659_DRC2_PRIV_6:
+	case RT5659_DRC2_PRIV_7:
+	case RT5659_MULTI_DRC_CTRL:
+	case RT5659_CROSS_OVER_1:
+	case RT5659_CROSS_OVER_2:
+	case RT5659_CROSS_OVER_3:
+	case RT5659_CROSS_OVER_4:
+	case RT5659_CROSS_OVER_5:
+	case RT5659_CROSS_OVER_6:
+	case RT5659_CROSS_OVER_7:
+	case RT5659_CROSS_OVER_8:
+	case RT5659_CROSS_OVER_9:
+	case RT5659_CROSS_OVER_10:
+	case RT5659_ALC_PGA_CTRL_1:
+	case RT5659_ALC_PGA_CTRL_2:
+	case RT5659_ALC_PGA_CTRL_3:
+	case RT5659_ALC_PGA_CTRL_4:
+	case RT5659_ALC_PGA_CTRL_5:
+	case RT5659_ALC_PGA_CTRL_6:
+	case RT5659_ALC_PGA_CTRL_7:
+	case RT5659_ALC_PGA_CTRL_8:
+	case RT5659_ALC_PGA_STA_1:
+	case RT5659_ALC_PGA_STA_2:
+	case RT5659_ALC_PGA_STA_3:
+	case RT5659_DAC_L_EQ_PRE_VOL:
+	case RT5659_DAC_R_EQ_PRE_VOL:
+	case RT5659_DAC_L_EQ_POST_VOL:
+	case RT5659_DAC_R_EQ_POST_VOL:
+	case RT5659_DAC_L_EQ_LPF1_A1:
+	case RT5659_DAC_L_EQ_LPF1_H0:
+	case RT5659_DAC_R_EQ_LPF1_A1:
+	case RT5659_DAC_R_EQ_LPF1_H0:
+	case RT5659_DAC_L_EQ_BPF2_A1:
+	case RT5659_DAC_L_EQ_BPF2_A2:
+	case RT5659_DAC_L_EQ_BPF2_H0:
+	case RT5659_DAC_R_EQ_BPF2_A1:
+	case RT5659_DAC_R_EQ_BPF2_A2:
+	case RT5659_DAC_R_EQ_BPF2_H0:
+	case RT5659_DAC_L_EQ_BPF3_A1:
+	case RT5659_DAC_L_EQ_BPF3_A2:
+	case RT5659_DAC_L_EQ_BPF3_H0:
+	case RT5659_DAC_R_EQ_BPF3_A1:
+	case RT5659_DAC_R_EQ_BPF3_A2:
+	case RT5659_DAC_R_EQ_BPF3_H0:
+	case RT5659_DAC_L_EQ_BPF4_A1:
+	case RT5659_DAC_L_EQ_BPF4_A2:
+	case RT5659_DAC_L_EQ_BPF4_H0:
+	case RT5659_DAC_R_EQ_BPF4_A1:
+	case RT5659_DAC_R_EQ_BPF4_A2:
+	case RT5659_DAC_R_EQ_BPF4_H0:
+	case RT5659_DAC_L_EQ_HPF1_A1:
+	case RT5659_DAC_L_EQ_HPF1_H0:
+	case RT5659_DAC_R_EQ_HPF1_A1:
+	case RT5659_DAC_R_EQ_HPF1_H0:
+	case RT5659_DAC_L_EQ_HPF2_A1:
+	case RT5659_DAC_L_EQ_HPF2_A2:
+	case RT5659_DAC_L_EQ_HPF2_H0:
+	case RT5659_DAC_R_EQ_HPF2_A1:
+	case RT5659_DAC_R_EQ_HPF2_A2:
+	case RT5659_DAC_R_EQ_HPF2_H0:
+	case RT5659_DAC_L_BI_EQ_BPF1_H0_1:
+	case RT5659_DAC_L_BI_EQ_BPF1_H0_2:
+	case RT5659_DAC_L_BI_EQ_BPF1_B1_1:
+	case RT5659_DAC_L_BI_EQ_BPF1_B1_2:
+	case RT5659_DAC_L_BI_EQ_BPF1_B2_1:
+	case RT5659_DAC_L_BI_EQ_BPF1_B2_2:
+	case RT5659_DAC_L_BI_EQ_BPF1_A1_1:
+	case RT5659_DAC_L_BI_EQ_BPF1_A1_2:
+	case RT5659_DAC_L_BI_EQ_BPF1_A2_1:
+	case RT5659_DAC_L_BI_EQ_BPF1_A2_2:
+	case RT5659_DAC_R_BI_EQ_BPF1_H0_1:
+	case RT5659_DAC_R_BI_EQ_BPF1_H0_2:
+	case RT5659_DAC_R_BI_EQ_BPF1_B1_1:
+	case RT5659_DAC_R_BI_EQ_BPF1_B1_2:
+	case RT5659_DAC_R_BI_EQ_BPF1_B2_1:
+	case RT5659_DAC_R_BI_EQ_BPF1_B2_2:
+	case RT5659_DAC_R_BI_EQ_BPF1_A1_1:
+	case RT5659_DAC_R_BI_EQ_BPF1_A1_2:
+	case RT5659_DAC_R_BI_EQ_BPF1_A2_1:
+	case RT5659_DAC_R_BI_EQ_BPF1_A2_2:
+	case RT5659_ADC_L_EQ_LPF1_A1:
+	case RT5659_ADC_R_EQ_LPF1_A1:
+	case RT5659_ADC_L_EQ_LPF1_H0:
+	case RT5659_ADC_R_EQ_LPF1_H0:
+	case RT5659_ADC_L_EQ_BPF1_A1:
+	case RT5659_ADC_R_EQ_BPF1_A1:
+	case RT5659_ADC_L_EQ_BPF1_A2:
+	case RT5659_ADC_R_EQ_BPF1_A2:
+	case RT5659_ADC_L_EQ_BPF1_H0:
+	case RT5659_ADC_R_EQ_BPF1_H0:
+	case RT5659_ADC_L_EQ_BPF2_A1:
+	case RT5659_ADC_R_EQ_BPF2_A1:
+	case RT5659_ADC_L_EQ_BPF2_A2:
+	case RT5659_ADC_R_EQ_BPF2_A2:
+	case RT5659_ADC_L_EQ_BPF2_H0:
+	case RT5659_ADC_R_EQ_BPF2_H0:
+	case RT5659_ADC_L_EQ_BPF3_A1:
+	case RT5659_ADC_R_EQ_BPF3_A1:
+	case RT5659_ADC_L_EQ_BPF3_A2:
+	case RT5659_ADC_R_EQ_BPF3_A2:
+	case RT5659_ADC_L_EQ_BPF3_H0:
+	case RT5659_ADC_R_EQ_BPF3_H0:
+	case RT5659_ADC_L_EQ_BPF4_A1:
+	case RT5659_ADC_R_EQ_BPF4_A1:
+	case RT5659_ADC_L_EQ_BPF4_A2:
+	case RT5659_ADC_R_EQ_BPF4_A2:
+	case RT5659_ADC_L_EQ_BPF4_H0:
+	case RT5659_ADC_R_EQ_BPF4_H0:
+	case RT5659_ADC_L_EQ_HPF1_A1:
+	case RT5659_ADC_R_EQ_HPF1_A1:
+	case RT5659_ADC_L_EQ_HPF1_H0:
+	case RT5659_ADC_R_EQ_HPF1_H0:
+	case RT5659_ADC_L_EQ_PRE_VOL:
+	case RT5659_ADC_R_EQ_PRE_VOL:
+	case RT5659_ADC_L_EQ_POST_VOL:
+	case RT5659_ADC_R_EQ_POST_VOL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+static const DECLARE_TLV_DB_SCALE(in_bst_tlv, -1200, 75, 0);
+
+/* Interface data select */
+static const char * const rt5659_data_select[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5659_if1_01_adc_enum,
+	RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT01_SFT, rt5659_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5659_if1_23_adc_enum,
+	RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT23_SFT, rt5659_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5659_if1_45_adc_enum,
+	RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT45_SFT, rt5659_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5659_if1_67_adc_enum,
+	RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT67_SFT, rt5659_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5659_if2_dac_enum,
+	RT5659_DIG_INF23_DATA, RT5659_IF2_DAC_SEL_SFT, rt5659_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5659_if2_adc_enum,
+	RT5659_DIG_INF23_DATA, RT5659_IF2_ADC_SEL_SFT, rt5659_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5659_if3_dac_enum,
+	RT5659_DIG_INF23_DATA, RT5659_IF3_DAC_SEL_SFT, rt5659_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5659_if3_adc_enum,
+	RT5659_DIG_INF23_DATA, RT5659_IF3_ADC_SEL_SFT, rt5659_data_select);
+
+static const struct snd_kcontrol_new rt5659_if1_01_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 01 ADC Swap Source", rt5659_if1_01_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if1_23_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 23 ADC1 Swap Source", rt5659_if1_23_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if1_45_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 45 ADC1 Swap Source", rt5659_if1_45_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if1_67_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 67 ADC1 Swap Source", rt5659_if1_67_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if2_dac_swap_mux =
+	SOC_DAPM_ENUM("IF2 DAC Swap Source", rt5659_if2_dac_enum);
+
+static const struct snd_kcontrol_new rt5659_if2_adc_swap_mux =
+	SOC_DAPM_ENUM("IF2 ADC Swap Source", rt5659_if2_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if3_dac_swap_mux =
+	SOC_DAPM_ENUM("IF3 DAC Swap Source", rt5659_if3_dac_enum);
+
+static const struct snd_kcontrol_new rt5659_if3_adc_swap_mux =
+	SOC_DAPM_ENUM("IF3 ADC Swap Source", rt5659_if3_adc_enum);
+
+static const char * const rt5659_asrc_clk_src[] = {
+	"clk_sysy_div_out", "clk_i2s1_track", "clk_i2s2_track",
+	"clk_i2s3_track", "clk_sys2", "clk_sys3"
+};
+
+static unsigned int rt5659_asrc_clk_map_values[] = {
+	0, 1, 2, 3, 5, 6,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(
+	rt5659_da_sto_asrc_enum, RT5659_ASRC_2, RT5659_DA_STO_T_SFT, 0x7,
+	rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(
+	rt5659_da_monol_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_L_T_SFT, 0x7,
+	rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(
+	rt5659_da_monor_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_R_T_SFT, 0x7,
+	rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(
+	rt5659_ad_sto1_asrc_enum, RT5659_ASRC_2, RT5659_AD_STO1_T_SFT, 0x7,
+	rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(
+	rt5659_ad_sto2_asrc_enum, RT5659_ASRC_3, RT5659_AD_STO2_T_SFT, 0x7,
+	rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(
+	rt5659_ad_monol_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_L_T_SFT, 0x7,
+	rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(
+	rt5659_ad_monor_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_R_T_SFT, 0x7,
+	rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static int rt5659_hp_vol_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+	if (snd_soc_component_read32(component, RT5659_STO_NG2_CTRL_1) & RT5659_NG2_EN) {
+		snd_soc_component_update_bits(component, RT5659_STO_NG2_CTRL_1,
+			RT5659_NG2_EN_MASK, RT5659_NG2_DIS);
+		snd_soc_component_update_bits(component, RT5659_STO_NG2_CTRL_1,
+			RT5659_NG2_EN_MASK, RT5659_NG2_EN);
+	}
+
+	return ret;
+}
+
+static void rt5659_enable_push_button_irq(struct snd_soc_component *component,
+	bool enable)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	if (enable) {
+		snd_soc_component_write(component, RT5659_4BTN_IL_CMD_1, 0x000b);
+
+		/* MICBIAS1 and Mic Det Power for button detect*/
+		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+		snd_soc_dapm_force_enable_pin(dapm,
+			"Mic Det Power");
+		snd_soc_dapm_sync(dapm);
+
+		snd_soc_component_update_bits(component, RT5659_PWR_ANLG_2,
+			RT5659_PWR_MB1, RT5659_PWR_MB1);
+		snd_soc_component_update_bits(component, RT5659_PWR_VOL,
+			RT5659_PWR_MIC_DET, RT5659_PWR_MIC_DET);
+
+		snd_soc_component_update_bits(component, RT5659_IRQ_CTRL_2,
+				RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_EN);
+		snd_soc_component_update_bits(component, RT5659_4BTN_IL_CMD_2,
+				RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_EN);
+	} else {
+		snd_soc_component_update_bits(component, RT5659_4BTN_IL_CMD_2,
+				RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_DIS);
+		snd_soc_component_update_bits(component, RT5659_IRQ_CTRL_2,
+				RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_DIS);
+		/* MICBIAS1 and Mic Det Power for button detect*/
+		snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+		snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+		snd_soc_dapm_sync(dapm);
+	}
+}
+
+/**
+ * rt5659_headset_detect - Detect headset.
+ * @component: SoC audio component device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+
+static int rt5659_headset_detect(struct snd_soc_component *component, int jack_insert)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};
+	int reg_63;
+
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
+
+	if (jack_insert) {
+		snd_soc_dapm_force_enable_pin(dapm,
+			"Mic Det Power");
+		snd_soc_dapm_sync(dapm);
+		reg_63 = snd_soc_component_read32(component, RT5659_PWR_ANLG_1);
+
+		snd_soc_component_update_bits(component, RT5659_PWR_ANLG_1,
+			RT5659_PWR_VREF2 | RT5659_PWR_MB,
+			RT5659_PWR_VREF2 | RT5659_PWR_MB);
+		msleep(20);
+		snd_soc_component_update_bits(component, RT5659_PWR_ANLG_1,
+			RT5659_PWR_FV2, RT5659_PWR_FV2);
+
+		snd_soc_component_write(component, RT5659_EJD_CTRL_2, 0x4160);
+		snd_soc_component_update_bits(component, RT5659_EJD_CTRL_1,
+			0x20, 0x0);
+		msleep(20);
+		snd_soc_component_update_bits(component, RT5659_EJD_CTRL_1,
+			0x20, 0x20);
+
+		while (i < 5) {
+			msleep(sleep_time[i]);
+			val = snd_soc_component_read32(component, RT5659_EJD_CTRL_2) & 0x0003;
+			i++;
+			if (val == 0x1 || val == 0x2 || val == 0x3)
+				break;
+		}
+
+		switch (val) {
+		case 1:
+			rt5659->jack_type = SND_JACK_HEADSET;
+			rt5659_enable_push_button_irq(component, true);
+			break;
+		default:
+			snd_soc_component_write(component, RT5659_PWR_ANLG_1, reg_63);
+			rt5659->jack_type = SND_JACK_HEADPHONE;
+			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+			snd_soc_dapm_sync(dapm);
+			break;
+		}
+	} else {
+		snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+		snd_soc_dapm_sync(dapm);
+		if (rt5659->jack_type == SND_JACK_HEADSET)
+			rt5659_enable_push_button_irq(component, false);
+		rt5659->jack_type = 0;
+	}
+
+	dev_dbg(component->dev, "jack_type = %d\n", rt5659->jack_type);
+	return rt5659->jack_type;
+}
+
+static int rt5659_button_detect(struct snd_soc_component *component)
+{
+	int btn_type, val;
+
+	val = snd_soc_component_read32(component, RT5659_4BTN_IL_CMD_1);
+	btn_type = val & 0xfff0;
+	snd_soc_component_write(component, RT5659_4BTN_IL_CMD_1, val);
+
+	return btn_type;
+}
+
+static irqreturn_t rt5659_irq(int irq, void *data)
+{
+	struct rt5659_priv *rt5659 = data;
+
+	queue_delayed_work(system_power_efficient_wq,
+			   &rt5659->jack_detect_work, msecs_to_jiffies(250));
+
+	return IRQ_HANDLED;
+}
+
+int rt5659_set_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *hs_jack)
+{
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
+
+	rt5659->hs_jack = hs_jack;
+
+	rt5659_irq(0, rt5659);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5659_set_jack_detect);
+
+static void rt5659_jack_detect_work(struct work_struct *work)
+{
+	struct rt5659_priv *rt5659 =
+		container_of(work, struct rt5659_priv, jack_detect_work.work);
+	int val, btn_type, report = 0;
+
+	if (!rt5659->component)
+		return;
+
+	val = snd_soc_component_read32(rt5659->component, RT5659_INT_ST_1) & 0x0080;
+	if (!val) {
+		/* jack in */
+		if (rt5659->jack_type == 0) {
+			/* jack was out, report jack type */
+			report = rt5659_headset_detect(rt5659->component, 1);
+		} else {
+			/* jack is already in, report button event */
+			report = SND_JACK_HEADSET;
+			btn_type = rt5659_button_detect(rt5659->component);
+			/**
+			 * rt5659 can report three kinds of button behavior,
+			 * one click, double click and hold. However,
+			 * currently we will report button pressed/released
+			 * event. So all the three button behaviors are
+			 * treated as button pressed.
+			 */
+			switch (btn_type) {
+			case 0x8000:
+			case 0x4000:
+			case 0x2000:
+				report |= SND_JACK_BTN_0;
+				break;
+			case 0x1000:
+			case 0x0800:
+			case 0x0400:
+				report |= SND_JACK_BTN_1;
+				break;
+			case 0x0200:
+			case 0x0100:
+			case 0x0080:
+				report |= SND_JACK_BTN_2;
+				break;
+			case 0x0040:
+			case 0x0020:
+			case 0x0010:
+				report |= SND_JACK_BTN_3;
+				break;
+			case 0x0000: /* unpressed */
+				break;
+			default:
+				btn_type = 0;
+				dev_err(rt5659->component->dev,
+					"Unexpected button code 0x%04x\n",
+					btn_type);
+				break;
+			}
+
+			/* button release or spurious interrput*/
+			if (btn_type == 0)
+				report =  rt5659->jack_type;
+		}
+	} else {
+		/* jack out */
+		report = rt5659_headset_detect(rt5659->component, 0);
+	}
+
+	snd_soc_jack_report(rt5659->hs_jack, report, SND_JACK_HEADSET |
+			    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+			    SND_JACK_BTN_2 | SND_JACK_BTN_3);
+}
+
+static void rt5659_jack_detect_intel_hd_header(struct work_struct *work)
+{
+	struct rt5659_priv *rt5659 =
+		container_of(work, struct rt5659_priv, jack_detect_work.work);
+	unsigned int value;
+	bool hp_flag, mic_flag;
+
+	if (!rt5659->hs_jack)
+		return;
+
+	/* headphone jack */
+	regmap_read(rt5659->regmap, RT5659_GPIO_STA, &value);
+	hp_flag = (!(value & 0x8)) ? true : false;
+
+	if (hp_flag != rt5659->hda_hp_plugged) {
+		rt5659->hda_hp_plugged = hp_flag;
+
+		if (hp_flag) {
+			regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_1,
+				0x10, 0x0);
+			rt5659->jack_type |= SND_JACK_HEADPHONE;
+		} else {
+			regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_1,
+				0x10, 0x10);
+			rt5659->jack_type = rt5659->jack_type &
+				(~SND_JACK_HEADPHONE);
+		}
+
+		snd_soc_jack_report(rt5659->hs_jack, rt5659->jack_type,
+			SND_JACK_HEADPHONE);
+	}
+
+	/* mic jack */
+	regmap_read(rt5659->regmap, RT5659_4BTN_IL_CMD_1, &value);
+	regmap_write(rt5659->regmap, RT5659_4BTN_IL_CMD_1, value);
+	mic_flag = (value & 0x2000) ? true : false;
+
+	if (mic_flag != rt5659->hda_mic_plugged) {
+		rt5659->hda_mic_plugged = mic_flag;
+		if (mic_flag) {
+			regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_2,
+				0x2, 0x2);
+			rt5659->jack_type |= SND_JACK_MICROPHONE;
+		} else {
+			regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_2,
+				0x2, 0x0);
+			rt5659->jack_type = rt5659->jack_type
+				& (~SND_JACK_MICROPHONE);
+		}
+
+		snd_soc_jack_report(rt5659->hs_jack, rt5659->jack_type,
+			SND_JACK_MICROPHONE);
+	}
+}
+
+static const struct snd_kcontrol_new rt5659_snd_controls[] = {
+	/* Speaker Output Volume */
+	SOC_DOUBLE_TLV("Speaker Playback Volume", RT5659_SPO_VOL,
+		RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+	/* Headphone Output Volume */
+	SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", RT5659_HPL_GAIN,
+		RT5659_HPR_GAIN, RT5659_G_HP_SFT, 31, 1, snd_soc_get_volsw,
+		rt5659_hp_vol_put, hp_vol_tlv),
+
+	/* Mono Output Volume */
+	SOC_SINGLE_TLV("Mono Playback Volume", RT5659_MONO_OUT,
+		RT5659_L_VOL_SFT, 39, 1, out_vol_tlv),
+
+	/* Output Volume */
+	SOC_DOUBLE_TLV("OUT Playback Volume", RT5659_LOUT,
+		RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5659_DAC1_DIG_VOL,
+		RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 175, 0, dac_vol_tlv),
+	SOC_DOUBLE("DAC1 Playback Switch", RT5659_AD_DA_MIXER,
+		RT5659_M_DAC1_L_SFT, RT5659_M_DAC1_R_SFT, 1, 1),
+
+	SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5659_DAC2_DIG_VOL,
+		RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 175, 0, dac_vol_tlv),
+	SOC_DOUBLE("DAC2 Playback Switch", RT5659_DAC_CTRL,
+		RT5659_M_DAC2_L_VOL_SFT, RT5659_M_DAC2_R_VOL_SFT, 1, 1),
+
+	/* IN1/IN2/IN3/IN4 Volume */
+	SOC_SINGLE_TLV("IN1 Boost Volume", RT5659_IN1_IN2,
+		RT5659_BST1_SFT, 69, 0, in_bst_tlv),
+	SOC_SINGLE_TLV("IN2 Boost Volume", RT5659_IN1_IN2,
+		RT5659_BST2_SFT, 69, 0, in_bst_tlv),
+	SOC_SINGLE_TLV("IN3 Boost Volume", RT5659_IN3_IN4,
+		RT5659_BST3_SFT, 69, 0, in_bst_tlv),
+	SOC_SINGLE_TLV("IN4 Boost Volume", RT5659_IN3_IN4,
+		RT5659_BST4_SFT, 69, 0, in_bst_tlv),
+
+	/* INL/INR Volume Control */
+	SOC_DOUBLE_TLV("IN Capture Volume", RT5659_INL1_INR1_VOL,
+		RT5659_INL_VOL_SFT, RT5659_INR_VOL_SFT, 31, 1, in_vol_tlv),
+
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("STO1 ADC Capture Switch", RT5659_STO1_ADC_DIG_VOL,
+		RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5659_STO1_ADC_DIG_VOL,
+		RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv),
+	SOC_DOUBLE("Mono ADC Capture Switch", RT5659_MONO_ADC_DIG_VOL,
+		RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5659_MONO_ADC_DIG_VOL,
+		RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv),
+	SOC_DOUBLE("STO2 ADC Capture Switch", RT5659_STO2_ADC_DIG_VOL,
+		RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("STO2 ADC Capture Volume", RT5659_STO2_ADC_DIG_VOL,
+		RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv),
+
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5659_STO1_BOOST,
+		RT5659_STO1_ADC_L_BST_SFT, RT5659_STO1_ADC_R_BST_SFT,
+		3, 0, adc_bst_tlv),
+
+	SOC_DOUBLE_TLV("Mono ADC Boost Gain Volume", RT5659_MONO_BOOST,
+		RT5659_MONO_ADC_L_BST_SFT, RT5659_MONO_ADC_R_BST_SFT,
+		3, 0, adc_bst_tlv),
+
+	SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5659_STO2_BOOST,
+		RT5659_STO2_ADC_L_BST_SFT, RT5659_STO2_ADC_R_BST_SFT,
+		3, 0, adc_bst_tlv),
+
+	SOC_SINGLE("DAC IF1 DAC1 L Data Switch", RT5659_TDM_CTRL_4, 12, 7, 0),
+	SOC_SINGLE("DAC IF1 DAC1 R Data Switch", RT5659_TDM_CTRL_4, 8, 7, 0),
+	SOC_SINGLE("DAC IF1 DAC2 L Data Switch", RT5659_TDM_CTRL_4, 4, 7, 0),
+	SOC_SINGLE("DAC IF1 DAC2 R Data Switch", RT5659_TDM_CTRL_4, 0, 7, 0),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
+	int pd, idx = -EINVAL;
+
+	pd = rl6231_get_pre_div(rt5659->regmap,
+		RT5659_ADDA_CLK_1, RT5659_I2S_PD1_SFT);
+	idx = rl6231_calc_dmic_clk(rt5659->sysclk / pd);
+
+	if (idx < 0)
+		dev_err(component->dev, "Failed to set DMIC clock\n");
+	else {
+		snd_soc_component_update_bits(component, RT5659_DMIC_CTRL_1,
+			RT5659_DMIC_CLK_MASK, idx << RT5659_DMIC_CLK_SFT);
+	}
+	return idx;
+}
+
+static int set_adc1_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5659_CHOP_ADC,
+			RT5659_CKXEN_ADC1_MASK | RT5659_CKGEN_ADC1_MASK,
+			RT5659_CKXEN_ADC1_MASK | RT5659_CKGEN_ADC1_MASK);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5659_CHOP_ADC,
+			RT5659_CKXEN_ADC1_MASK | RT5659_CKGEN_ADC1_MASK, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+
+}
+
+static int set_adc2_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5659_CHOP_ADC,
+			RT5659_CKXEN_ADC2_MASK | RT5659_CKGEN_ADC2_MASK,
+			RT5659_CKXEN_ADC2_MASK | RT5659_CKGEN_ADC2_MASK);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5659_CHOP_ADC,
+			RT5659_CKXEN_ADC2_MASK | RT5659_CKGEN_ADC2_MASK, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+
+}
+
+static int rt5659_charge_pump_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Depop */
+		snd_soc_component_write(component, RT5659_DEPOP_1, 0x0009);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_write(component, RT5659_HP_CHARGE_PUMP_1, 0x0c16);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *w,
+			 struct snd_soc_dapm_widget *sink)
+{
+	unsigned int val;
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	val = snd_soc_component_read32(component, RT5659_GLB_CLK);
+	val &= RT5659_SCLK_SRC_MASK;
+	if (val == RT5659_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int is_using_asrc(struct snd_soc_dapm_widget *w,
+			 struct snd_soc_dapm_widget *sink)
+{
+	unsigned int reg, shift, val;
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (w->shift) {
+	case RT5659_ADC_MONO_R_ASRC_SFT:
+		reg = RT5659_ASRC_3;
+		shift = RT5659_AD_MONO_R_T_SFT;
+		break;
+	case RT5659_ADC_MONO_L_ASRC_SFT:
+		reg = RT5659_ASRC_3;
+		shift = RT5659_AD_MONO_L_T_SFT;
+		break;
+	case RT5659_ADC_STO1_ASRC_SFT:
+		reg = RT5659_ASRC_2;
+		shift = RT5659_AD_STO1_T_SFT;
+		break;
+	case RT5659_DAC_MONO_R_ASRC_SFT:
+		reg = RT5659_ASRC_2;
+		shift = RT5659_DA_MONO_R_T_SFT;
+		break;
+	case RT5659_DAC_MONO_L_ASRC_SFT:
+		reg = RT5659_ASRC_2;
+		shift = RT5659_DA_MONO_L_T_SFT;
+		break;
+	case RT5659_DAC_STO_ASRC_SFT:
+		reg = RT5659_ASRC_2;
+		shift = RT5659_DA_STO_T_SFT;
+		break;
+	default:
+		return 0;
+	}
+
+	val = (snd_soc_component_read32(component, reg) >> shift) & 0xf;
+	switch (val) {
+	case 1:
+	case 2:
+	case 3:
+		/* I2S_Pre_Div1 should be 1 in asrc mode */
+		snd_soc_component_update_bits(component, RT5659_ADDA_CLK_1,
+			RT5659_I2S_PD1_MASK, RT5659_I2S_PD1_2);
+		return 1;
+	default:
+		return 0;
+	}
+
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5659_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5659_STO1_ADC_MIXER,
+			RT5659_M_STO1_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5659_STO1_ADC_MIXER,
+			RT5659_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5659_STO1_ADC_MIXER,
+			RT5659_M_STO1_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5659_STO1_ADC_MIXER,
+			RT5659_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5659_MONO_ADC_MIXER,
+			RT5659_M_MONO_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5659_MONO_ADC_MIXER,
+			RT5659_M_MONO_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5659_MONO_ADC_MIXER,
+			RT5659_M_MONO_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5659_MONO_ADC_MIXER,
+			RT5659_M_MONO_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5659_AD_DA_MIXER,
+			RT5659_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5659_AD_DA_MIXER,
+			RT5659_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5659_AD_DA_MIXER,
+			RT5659_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5659_AD_DA_MIXER,
+			RT5659_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_sto_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_L1_STO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_R1_STO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_L2_STO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_R2_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_sto_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_L1_STO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_R1_STO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_L2_STO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_R2_STO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_L1_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_R1_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_L2_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_R2_MONO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_L1_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_R1_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_L2_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_R2_MONO_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5659_rec1_l_mix[] = {
+	SOC_DAPM_SINGLE("SPKVOLL Switch", RT5659_REC1_L2_MIXER,
+			RT5659_M_SPKVOLL_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5659_REC1_L2_MIXER,
+			RT5659_M_INL_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC1_L2_MIXER,
+			RT5659_M_BST4_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC1_L2_MIXER,
+			RT5659_M_BST3_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC1_L2_MIXER,
+			RT5659_M_BST2_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC1_L2_MIXER,
+			RT5659_M_BST1_RM1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_rec1_r_mix[] = {
+	SOC_DAPM_SINGLE("HPOVOLR Switch", RT5659_REC1_L2_MIXER,
+			RT5659_M_HPOVOLR_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5659_REC1_R2_MIXER,
+			RT5659_M_INR_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC1_R2_MIXER,
+			RT5659_M_BST4_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC1_R2_MIXER,
+			RT5659_M_BST3_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC1_R2_MIXER,
+			RT5659_M_BST2_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC1_R2_MIXER,
+			RT5659_M_BST1_RM1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_rec2_l_mix[] = {
+	SOC_DAPM_SINGLE("SPKVOLL Switch", RT5659_REC2_L2_MIXER,
+			RT5659_M_SPKVOL_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOLL Switch", RT5659_REC2_L2_MIXER,
+			RT5659_M_OUTVOLL_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC2_L2_MIXER,
+			RT5659_M_BST4_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC2_L2_MIXER,
+			RT5659_M_BST3_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC2_L2_MIXER,
+			RT5659_M_BST2_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC2_L2_MIXER,
+			RT5659_M_BST1_RM2_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_rec2_r_mix[] = {
+	SOC_DAPM_SINGLE("MONOVOL Switch", RT5659_REC2_R2_MIXER,
+			RT5659_M_MONOVOL_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOLR Switch", RT5659_REC2_R2_MIXER,
+			RT5659_M_OUTVOLR_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC2_R2_MIXER,
+			RT5659_M_BST4_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC2_R2_MIXER,
+			RT5659_M_BST3_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC2_R2_MIXER,
+			RT5659_M_BST2_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC2_R2_MIXER,
+			RT5659_M_BST1_RM2_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_spk_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_SPK_L_MIXER,
+			RT5659_M_DAC_L2_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5659_SPK_L_MIXER,
+			RT5659_M_BST1_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5659_SPK_L_MIXER,
+			RT5659_M_IN_L_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5659_SPK_L_MIXER,
+			RT5659_M_IN_R_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_SPK_L_MIXER,
+			RT5659_M_BST3_SM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_spk_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_SPK_R_MIXER,
+			RT5659_M_DAC_R2_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5659_SPK_R_MIXER,
+			RT5659_M_BST4_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5659_SPK_R_MIXER,
+			RT5659_M_IN_L_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5659_SPK_R_MIXER,
+			RT5659_M_IN_R_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_SPK_R_MIXER,
+			RT5659_M_BST3_SM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_monovol_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONOMIX_IN_GAIN,
+			RT5659_M_DAC_L2_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONOMIX_IN_GAIN,
+			RT5659_M_DAC_R2_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5659_MONOMIX_IN_GAIN,
+			RT5659_M_BST1_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5659_MONOMIX_IN_GAIN,
+			RT5659_M_BST2_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_MONOMIX_IN_GAIN,
+			RT5659_M_BST3_MM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_out_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_OUT_L_MIXER,
+			RT5659_M_DAC_L2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5659_OUT_L_MIXER,
+			RT5659_M_IN_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5659_OUT_L_MIXER,
+			RT5659_M_BST1_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5659_OUT_L_MIXER,
+			RT5659_M_BST2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_OUT_L_MIXER,
+			RT5659_M_BST3_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_out_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_OUT_R_MIXER,
+			RT5659_M_DAC_R2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5659_OUT_R_MIXER,
+			RT5659_M_IN_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5659_OUT_R_MIXER,
+			RT5659_M_BST2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_OUT_R_MIXER,
+			RT5659_M_BST3_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5659_OUT_R_MIXER,
+			RT5659_M_BST4_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_spo_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_SPO_AMP_GAIN,
+			RT5659_M_DAC_L2_SPKOMIX_SFT, 1, 0),
+	SOC_DAPM_SINGLE("SPKVOL L Switch", RT5659_SPO_AMP_GAIN,
+			RT5659_M_SPKVOLL_SPKOMIX_SFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rt5659_spo_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_SPO_AMP_GAIN,
+			RT5659_M_DAC_R2_SPKOMIX_SFT, 1, 0),
+	SOC_DAPM_SINGLE("SPKVOL R Switch", RT5659_SPO_AMP_GAIN,
+			RT5659_M_SPKVOLR_SPKOMIX_SFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONOMIX_IN_GAIN,
+			RT5659_M_DAC_L2_MA_SFT, 1, 1),
+	SOC_DAPM_SINGLE("MONOVOL Switch", RT5659_MONOMIX_IN_GAIN,
+			RT5659_M_MONOVOL_MA_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_lout_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_LOUT_MIXER,
+			RT5659_M_DAC_L2_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL L Switch", RT5659_LOUT_MIXER,
+			RT5659_M_OV_L_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_lout_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_LOUT_MIXER,
+			RT5659_M_DAC_R2_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL R Switch", RT5659_LOUT_MIXER,
+			RT5659_M_OV_R_LM_SFT, 1, 1),
+};
+
+/*DAC L2, DAC R2*/
+/*MX-1B [6:4], MX-1B [2:0]*/
+static const char * const rt5659_dac2_src[] = {
+	"IF1 DAC2", "IF2 DAC", "IF3 DAC", "Mono ADC MIX"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_dac_l2_enum, RT5659_DAC_CTRL,
+	RT5659_DAC_L2_SEL_SFT, rt5659_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_dac_l2_mux =
+	SOC_DAPM_ENUM("DAC L2 Source", rt5659_dac_l2_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_dac_r2_enum, RT5659_DAC_CTRL,
+	RT5659_DAC_R2_SEL_SFT, rt5659_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_dac_r2_mux =
+	SOC_DAPM_ENUM("DAC R2 Source", rt5659_dac_r2_enum);
+
+
+/* STO1 ADC1 Source */
+/* MX-26 [13] */
+static const char * const rt5659_sto1_adc1_src[] = {
+	"DAC MIX", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_sto1_adc1_enum, RT5659_STO1_ADC_MIXER,
+	RT5659_STO1_ADC1_SRC_SFT, rt5659_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_adc1_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC1 Source", rt5659_sto1_adc1_enum);
+
+/* STO1 ADC Source */
+/* MX-26 [12] */
+static const char * const rt5659_sto1_adc_src[] = {
+	"ADC1", "ADC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_sto1_adc_enum, RT5659_STO1_ADC_MIXER,
+	RT5659_STO1_ADC_SRC_SFT, rt5659_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_adc_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC Source", rt5659_sto1_adc_enum);
+
+/* STO1 ADC2 Source */
+/* MX-26 [11] */
+static const char * const rt5659_sto1_adc2_src[] = {
+	"DAC MIX", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_sto1_adc2_enum, RT5659_STO1_ADC_MIXER,
+	RT5659_STO1_ADC2_SRC_SFT, rt5659_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_adc2_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC2 Source", rt5659_sto1_adc2_enum);
+
+/* STO1 DMIC Source */
+/* MX-26 [8] */
+static const char * const rt5659_sto1_dmic_src[] = {
+	"DMIC1", "DMIC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_sto1_dmic_enum, RT5659_STO1_ADC_MIXER,
+	RT5659_STO1_DMIC_SRC_SFT, rt5659_sto1_dmic_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_dmic_mux =
+	SOC_DAPM_ENUM("Stereo1 DMIC Source", rt5659_sto1_dmic_enum);
+
+
+/* MONO ADC L2 Source */
+/* MX-27 [12] */
+static const char * const rt5659_mono_adc_l2_src[] = {
+	"Mono DAC MIXL", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_adc_l2_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_ADC_L2_SRC_SFT, rt5659_mono_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l2_mux =
+	SOC_DAPM_ENUM("Mono ADC L2 Source", rt5659_mono_adc_l2_enum);
+
+
+/* MONO ADC L1 Source */
+/* MX-27 [11] */
+static const char * const rt5659_mono_adc_l1_src[] = {
+	"Mono DAC MIXL", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_adc_l1_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_ADC_L1_SRC_SFT, rt5659_mono_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l1_mux =
+	SOC_DAPM_ENUM("Mono ADC L1 Source", rt5659_mono_adc_l1_enum);
+
+/* MONO ADC L Source, MONO ADC R Source*/
+/* MX-27 [10:9], MX-27 [2:1] */
+static const char * const rt5659_mono_adc_src[] = {
+	"ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_adc_l_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_ADC_L_SRC_SFT, rt5659_mono_adc_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l_mux =
+	SOC_DAPM_ENUM("Mono ADC L Source", rt5659_mono_adc_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_adcr_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_ADC_R_SRC_SFT, rt5659_mono_adc_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r_mux =
+	SOC_DAPM_ENUM("Mono ADC R Source", rt5659_mono_adcr_enum);
+
+/* MONO DMIC L Source */
+/* MX-27 [8] */
+static const char * const rt5659_mono_dmic_l_src[] = {
+	"DMIC1 L", "DMIC2 L"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_dmic_l_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_DMIC_L_SRC_SFT, rt5659_mono_dmic_l_src);
+
+static const struct snd_kcontrol_new rt5659_mono_dmic_l_mux =
+	SOC_DAPM_ENUM("Mono DMIC L Source", rt5659_mono_dmic_l_enum);
+
+/* MONO ADC R2 Source */
+/* MX-27 [4] */
+static const char * const rt5659_mono_adc_r2_src[] = {
+	"Mono DAC MIXR", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_adc_r2_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_ADC_R2_SRC_SFT, rt5659_mono_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r2_mux =
+	SOC_DAPM_ENUM("Mono ADC R2 Source", rt5659_mono_adc_r2_enum);
+
+/* MONO ADC R1 Source */
+/* MX-27 [3] */
+static const char * const rt5659_mono_adc_r1_src[] = {
+	"Mono DAC MIXR", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_adc_r1_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_ADC_R1_SRC_SFT, rt5659_mono_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r1_mux =
+	SOC_DAPM_ENUM("Mono ADC R1 Source", rt5659_mono_adc_r1_enum);
+
+/* MONO DMIC R Source */
+/* MX-27 [0] */
+static const char * const rt5659_mono_dmic_r_src[] = {
+	"DMIC1 R", "DMIC2 R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_dmic_r_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_DMIC_R_SRC_SFT, rt5659_mono_dmic_r_src);
+
+static const struct snd_kcontrol_new rt5659_mono_dmic_r_mux =
+	SOC_DAPM_ENUM("Mono DMIC R Source", rt5659_mono_dmic_r_enum);
+
+
+/* DAC R1 Source, DAC L1 Source*/
+/* MX-29 [11:10], MX-29 [9:8]*/
+static const char * const rt5659_dac1_src[] = {
+	"IF1 DAC1", "IF2 DAC", "IF3 DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_dac_r1_enum, RT5659_AD_DA_MIXER,
+	RT5659_DAC1_R_SEL_SFT, rt5659_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_dac_r1_mux =
+	SOC_DAPM_ENUM("DAC R1 Source", rt5659_dac_r1_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_dac_l1_enum, RT5659_AD_DA_MIXER,
+	RT5659_DAC1_L_SEL_SFT, rt5659_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_dac_l1_mux =
+	SOC_DAPM_ENUM("DAC L1 Source", rt5659_dac_l1_enum);
+
+/* DAC Digital Mixer L Source, DAC Digital Mixer R Source*/
+/* MX-2C [6], MX-2C [4]*/
+static const char * const rt5659_dig_dac_mix_src[] = {
+	"Stereo DAC Mixer", "Mono DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_dig_dac_mixl_enum, RT5659_DIG_MIXER,
+	RT5659_DAC_MIX_L_SFT, rt5659_dig_dac_mix_src);
+
+static const struct snd_kcontrol_new rt5659_dig_dac_mixl_mux =
+	SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5659_dig_dac_mixl_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_dig_dac_mixr_enum, RT5659_DIG_MIXER,
+	RT5659_DAC_MIX_R_SFT, rt5659_dig_dac_mix_src);
+
+static const struct snd_kcontrol_new rt5659_dig_dac_mixr_mux =
+	SOC_DAPM_ENUM("DAC Digital Mixer R Source", rt5659_dig_dac_mixr_enum);
+
+/* Analog DAC L1 Source, Analog DAC R1 Source*/
+/* MX-2D [3], MX-2D [2]*/
+static const char * const rt5659_alg_dac1_src[] = {
+	"DAC", "Stereo DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_alg_dac_l1_enum, RT5659_A_DAC_MUX,
+	RT5659_A_DACL1_SFT, rt5659_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_l1_mux =
+	SOC_DAPM_ENUM("Analog DACL1 Source", rt5659_alg_dac_l1_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_alg_dac_r1_enum, RT5659_A_DAC_MUX,
+	RT5659_A_DACR1_SFT, rt5659_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_r1_mux =
+	SOC_DAPM_ENUM("Analog DACR1 Source", rt5659_alg_dac_r1_enum);
+
+/* Analog DAC LR Source, Analog DAC R2 Source*/
+/* MX-2D [1], MX-2D [0]*/
+static const char * const rt5659_alg_dac2_src[] = {
+	"Stereo DAC Mixer", "Mono DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_alg_dac_l2_enum, RT5659_A_DAC_MUX,
+	RT5659_A_DACL2_SFT, rt5659_alg_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_l2_mux =
+	SOC_DAPM_ENUM("Analog DAC L2 Source", rt5659_alg_dac_l2_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_alg_dac_r2_enum, RT5659_A_DAC_MUX,
+	RT5659_A_DACR2_SFT, rt5659_alg_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_r2_mux =
+	SOC_DAPM_ENUM("Analog DAC R2 Source", rt5659_alg_dac_r2_enum);
+
+/* Interface2 ADC Data Input*/
+/* MX-2F [13:12] */
+static const char * const rt5659_if2_adc_in_src[] = {
+	"IF_ADC1", "IF_ADC2", "DAC_REF", "IF_ADC3"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_if2_adc_in_enum, RT5659_DIG_INF23_DATA,
+	RT5659_IF2_ADC_IN_SFT, rt5659_if2_adc_in_src);
+
+static const struct snd_kcontrol_new rt5659_if2_adc_in_mux =
+	SOC_DAPM_ENUM("IF2 ADC IN Source", rt5659_if2_adc_in_enum);
+
+/* Interface3 ADC Data Input*/
+/* MX-2F [1:0] */
+static const char * const rt5659_if3_adc_in_src[] = {
+	"IF_ADC1", "IF_ADC2", "DAC_REF", "Stereo2_ADC_L/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_if3_adc_in_enum, RT5659_DIG_INF23_DATA,
+	RT5659_IF3_ADC_IN_SFT, rt5659_if3_adc_in_src);
+
+static const struct snd_kcontrol_new rt5659_if3_adc_in_mux =
+	SOC_DAPM_ENUM("IF3 ADC IN Source", rt5659_if3_adc_in_enum);
+
+/* PDM 1 L/R*/
+/* MX-31 [15] [13] */
+static const char * const rt5659_pdm_src[] = {
+	"Mono DAC", "Stereo DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_pdm_l_enum, RT5659_PDM_OUT_CTRL,
+	RT5659_PDM1_L_SFT, rt5659_pdm_src);
+
+static const struct snd_kcontrol_new rt5659_pdm_l_mux =
+	SOC_DAPM_ENUM("PDM L Source", rt5659_pdm_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_pdm_r_enum, RT5659_PDM_OUT_CTRL,
+	RT5659_PDM1_R_SFT, rt5659_pdm_src);
+
+static const struct snd_kcontrol_new rt5659_pdm_r_mux =
+	SOC_DAPM_ENUM("PDM R Source", rt5659_pdm_r_enum);
+
+/* SPDIF Output source*/
+/* MX-36 [1:0] */
+static const char * const rt5659_spdif_src[] = {
+	"IF1_DAC1", "IF1_DAC2", "IF2_DAC", "IF3_DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_spdif_enum, RT5659_SPDIF_CTRL,
+	RT5659_SPDIF_SEL_SFT, rt5659_spdif_src);
+
+static const struct snd_kcontrol_new rt5659_spdif_mux =
+	SOC_DAPM_ENUM("SPDIF Source", rt5659_spdif_enum);
+
+/* I2S1 TDM ADCDAT Source */
+/* MX-78[4:0] */
+static const char * const rt5659_rx_adc_data_src[] = {
+	"AD1:AD2:DAC:NUL", "AD1:AD2:NUL:DAC", "AD1:DAC:AD2:NUL",
+	"AD1:DAC:NUL:AD2", "AD1:NUL:DAC:AD2", "AD1:NUL:AD2:DAC",
+	"AD2:AD1:DAC:NUL", "AD2:AD1:NUL:DAC", "AD2:DAC:AD1:NUL",
+	"AD2:DAC:NUL:AD1", "AD2:NUL:DAC:AD1", "AD1:NUL:AD1:DAC",
+	"DAC:AD1:AD2:NUL", "DAC:AD1:NUL:AD2", "DAC:AD2:AD1:NUL",
+	"DAC:AD2:NUL:AD1", "DAC:NUL:DAC:AD2", "DAC:NUL:AD2:DAC",
+	"NUL:AD1:AD2:DAC", "NUL:AD1:DAC:AD2", "NUL:AD2:AD1:DAC",
+	"NUL:AD2:DAC:AD1", "NUL:DAC:DAC:AD2", "NUL:DAC:AD2:DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5659_rx_adc_data_enum, RT5659_TDM_CTRL_2,
+	RT5659_ADCDAT_SRC_SFT, rt5659_rx_adc_data_src);
+
+static const struct snd_kcontrol_new rt5659_rx_adc_dac_mux =
+	SOC_DAPM_ENUM("TDM ADCDAT Source", rt5659_rx_adc_data_enum);
+
+/* Out Volume Switch */
+static const struct snd_kcontrol_new spkvol_l_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_SPO_VOL, RT5659_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new spkvol_r_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_SPO_VOL, RT5659_VOL_R_SFT, 1, 1);
+
+static const struct snd_kcontrol_new monovol_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_MONO_OUT, RT5659_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_l_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_r_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_VOL_R_SFT, 1, 1);
+
+/* Out Switch */
+static const struct snd_kcontrol_new spo_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_CLASSD_2, RT5659_M_RF_DIG_SFT, 1, 1);
+
+static const struct snd_kcontrol_new mono_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_MONO_OUT, RT5659_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_l_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_HP_VOL, RT5659_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_r_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_HP_VOL, RT5659_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_l_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_r_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new pdm_l_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_PDM_OUT_CTRL, RT5659_M_PDM1_L_SFT, 1,
+		1);
+
+static const struct snd_kcontrol_new pdm_r_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_PDM_OUT_CTRL, RT5659_M_PDM1_R_SFT, 1,
+		1);
+
+static int rt5659_spk_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component, RT5659_CLASSD_CTRL_1,
+			RT5659_POW_CLSD_DB_MASK, RT5659_POW_CLSD_DB_EN);
+		snd_soc_component_update_bits(component, RT5659_CLASSD_2,
+			RT5659_M_RI_DIG, RT5659_M_RI_DIG);
+		snd_soc_component_write(component, RT5659_CLASSD_1, 0x0803);
+		snd_soc_component_write(component, RT5659_SPK_DC_CAILB_CTRL_3, 0x0000);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_write(component, RT5659_CLASSD_1, 0x0011);
+		snd_soc_component_update_bits(component, RT5659_CLASSD_2,
+			RT5659_M_RI_DIG, 0x0);
+		snd_soc_component_write(component, RT5659_SPK_DC_CAILB_CTRL_3, 0x0003);
+		snd_soc_component_update_bits(component, RT5659_CLASSD_CTRL_1,
+			RT5659_POW_CLSD_DB_MASK, RT5659_POW_CLSD_DB_DIS);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+
+}
+
+static int rt5659_mono_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_write(component, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e00);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_write(component, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e04);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+
+}
+
+static int rt5659_hp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_write(component, RT5659_HP_CHARGE_PUMP_1, 0x0e1e);
+		snd_soc_component_update_bits(component, RT5659_DEPOP_1, 0x0010, 0x0010);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_write(component, RT5659_DEPOP_1, 0x0000);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int set_dmic_power(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/*Add delay to avoid pop noise*/
+		msleep(450);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5659_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("LDO2", RT5659_PWR_ANLG_3, RT5659_PWR_LDO2_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL", RT5659_PWR_ANLG_3, RT5659_PWR_PLL_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5659_PWR_VOL,
+		RT5659_PWR_MIC_DET_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mono Vref", RT5659_PWR_ANLG_1,
+		RT5659_PWR_VREF3_BIT, 0, NULL, 0),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5659_ASRC_1,
+		RT5659_I2S1_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5659_ASRC_1,
+		RT5659_I2S2_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5659_ASRC_1,
+		RT5659_I2S3_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5659_ASRC_1,
+		RT5659_DAC_STO_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC Mono L ASRC", 1, RT5659_ASRC_1,
+		RT5659_DAC_MONO_L_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC Mono R ASRC", 1, RT5659_ASRC_1,
+		RT5659_DAC_MONO_R_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5659_ASRC_1,
+		RT5659_ADC_STO1_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC Mono L ASRC", 1, RT5659_ASRC_1,
+		RT5659_ADC_MONO_L_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC Mono R ASRC", 1, RT5659_ASRC_1,
+		RT5659_ADC_MONO_R_ASRC_SFT, 0, NULL, 0),
+
+	/* Input Side */
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5659_PWR_ANLG_2, RT5659_PWR_MB1_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5659_PWR_ANLG_2, RT5659_PWR_MB2_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS3", RT5659_PWR_ANLG_2, RT5659_PWR_MB3_BIT,
+		0, NULL, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC L1"),
+	SND_SOC_DAPM_INPUT("DMIC R1"),
+	SND_SOC_DAPM_INPUT("DMIC L2"),
+	SND_SOC_DAPM_INPUT("DMIC R2"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN1N"),
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN2N"),
+	SND_SOC_DAPM_INPUT("IN3P"),
+	SND_SOC_DAPM_INPUT("IN3N"),
+	SND_SOC_DAPM_INPUT("IN4P"),
+	SND_SOC_DAPM_INPUT("IN4N"),
+
+	SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+		set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5659_DMIC_CTRL_1,
+		RT5659_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5659_DMIC_CTRL_1,
+		RT5659_DMIC_2_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST1_P_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST2", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST2_P_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST3", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST3_P_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST4", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST4_P_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST1 Power", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST2 Power", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST3 Power", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST3_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST4 Power", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST4_BIT, 0, NULL, 0),
+
+
+	/* Input Volume */
+	SND_SOC_DAPM_PGA("INL VOL", RT5659_PWR_VOL, RT5659_PWR_IN_L_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR VOL", RT5659_PWR_VOL, RT5659_PWR_IN_R_BIT,
+		0, NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIX1L", RT5659_PWR_MIXER, RT5659_PWR_RM1_L_BIT,
+		0, rt5659_rec1_l_mix, ARRAY_SIZE(rt5659_rec1_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIX1R", RT5659_PWR_MIXER, RT5659_PWR_RM1_R_BIT,
+		0, rt5659_rec1_r_mix, ARRAY_SIZE(rt5659_rec1_r_mix)),
+	SND_SOC_DAPM_MIXER("RECMIX2L", RT5659_PWR_MIXER, RT5659_PWR_RM2_L_BIT,
+		0, rt5659_rec2_l_mix, ARRAY_SIZE(rt5659_rec2_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIX2R", RT5659_PWR_MIXER, RT5659_PWR_RM2_R_BIT,
+		0, rt5659_rec2_r_mix, ARRAY_SIZE(rt5659_rec2_r_mix)),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC2 L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC2 R", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5659_PWR_DIG_1,
+		RT5659_PWR_ADC_L1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5659_PWR_DIG_1,
+		RT5659_PWR_ADC_R1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC2 L Power", RT5659_PWR_DIG_1,
+		RT5659_PWR_ADC_L2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC2 R Power", RT5659_PWR_DIG_1,
+		RT5659_PWR_ADC_R2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1 clock", SND_SOC_NOPM, 0, 0, set_adc1_clk,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("ADC2 clock", SND_SOC_NOPM, 0, 0, set_adc2_clk,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("Stereo1 DMIC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo1 DMIC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_adc1_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_adc1_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_adc2_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_adc2_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_adc_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_adc_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_adc_l2_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_adc_r2_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_adc_l1_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_adc_r1_mux),
+	SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_dmic_l_mux),
+	SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_dmic_r_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_adc_l_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_adc_r_mux),
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5659_PWR_DIG_2,
+		RT5659_PWR_ADC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5659_PWR_DIG_2,
+		RT5659_PWR_ADC_S2F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM,
+		0, 0, rt5659_sto1_adc_l_mix,
+		ARRAY_SIZE(rt5659_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM,
+		0, 0, rt5659_sto1_adc_r_mix,
+		ARRAY_SIZE(rt5659_sto1_adc_r_mix)),
+	SND_SOC_DAPM_SUPPLY("ADC Mono Left Filter", RT5659_PWR_DIG_2,
+		RT5659_PWR_ADC_MF_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mono ADC MIXL", RT5659_MONO_ADC_DIG_VOL,
+		RT5659_L_MUTE_SFT, 1, rt5659_mono_adc_l_mix,
+		ARRAY_SIZE(rt5659_mono_adc_l_mix)),
+	SND_SOC_DAPM_SUPPLY("ADC Mono Right Filter", RT5659_PWR_DIG_2,
+		RT5659_PWR_ADC_MF_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mono ADC MIXR", RT5659_MONO_ADC_DIG_VOL,
+		RT5659_R_MUTE_SFT, 1, rt5659_mono_adc_r_mix,
+		ARRAY_SIZE(rt5659_mono_adc_r_mix)),
+
+	/* ADC PGA */
+	SND_SOC_DAPM_PGA("IF_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo2 ADC LR", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Stereo1 ADC Volume L", RT5659_STO1_ADC_DIG_VOL,
+		RT5659_L_MUTE_SFT, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo1 ADC Volume R", RT5659_STO1_ADC_DIG_VOL,
+		RT5659_R_MUTE_SFT, 1, NULL, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5659_PWR_DIG_1, RT5659_PWR_I2S1_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("I2S2", RT5659_PWR_DIG_1, RT5659_PWR_I2S2_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("I2S3", RT5659_PWR_DIG_1, RT5659_PWR_I2S3_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface Select */
+	SND_SOC_DAPM_PGA("TDM AD1:AD2:DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("TDM AD2:DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("TDM Data Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_rx_adc_dac_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_if2_adc_in_mux),
+	SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_if3_adc_in_mux),
+	SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if1_01_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 23 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if1_23_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 45 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if1_45_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 67 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if1_67_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if2_dac_swap_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if2_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF3 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if3_dac_swap_mux),
+	SND_SOC_DAPM_MUX("IF3 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if3_adc_swap_mux),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF3RX", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF3TX", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Side */
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
+		rt5659_dac_l_mix, ARRAY_SIZE(rt5659_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+		rt5659_dac_r_mix, ARRAY_SIZE(rt5659_dac_r_mix)),
+
+	/* DAC channel Mux */
+	SND_SOC_DAPM_MUX("DAC L1 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_l1_mux),
+	SND_SOC_DAPM_MUX("DAC R1 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_r1_mux),
+	SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_l2_mux),
+	SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_r2_mux),
+
+	SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0,
+		&rt5659_alg_dac_l1_mux),
+	SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0,
+		&rt5659_alg_dac_r1_mux),
+	SND_SOC_DAPM_MUX("DAC L2 Source", SND_SOC_NOPM, 0, 0,
+		&rt5659_alg_dac_l2_mux),
+	SND_SOC_DAPM_MUX("DAC R2 Source", SND_SOC_NOPM, 0, 0,
+		&rt5659_alg_dac_r2_mux),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5659_PWR_DIG_2,
+		RT5659_PWR_DAC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Mono Left Filter", RT5659_PWR_DIG_2,
+		RT5659_PWR_DAC_MF_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Mono Right Filter", RT5659_PWR_DIG_2,
+		RT5659_PWR_DAC_MF_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5659_sto_dac_l_mix, ARRAY_SIZE(rt5659_sto_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5659_sto_dac_r_mix, ARRAY_SIZE(rt5659_sto_dac_r_mix)),
+	SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5659_mono_dac_l_mix, ARRAY_SIZE(rt5659_mono_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5659_mono_dac_r_mix, ARRAY_SIZE(rt5659_mono_dac_r_mix)),
+	SND_SOC_DAPM_MUX("DAC MIXL", SND_SOC_NOPM, 0, 0,
+		&rt5659_dig_dac_mixl_mux),
+	SND_SOC_DAPM_MUX("DAC MIXR", SND_SOC_NOPM, 0, 0,
+		&rt5659_dig_dac_mixr_mux),
+
+	/* DACs */
+	SND_SOC_DAPM_SUPPLY_S("DAC L1 Power", 1, RT5659_PWR_DIG_1,
+		RT5659_PWR_DAC_L1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC R1 Power", 1, RT5659_PWR_DIG_1,
+		RT5659_PWR_DAC_R1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5659_PWR_DIG_1,
+		RT5659_PWR_DAC_L2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5659_PWR_DIG_1,
+		RT5659_PWR_DAC_R2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("DAC L2", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC R2", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_PGA("DAC_REF", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* OUT Mixer */
+	SND_SOC_DAPM_MIXER("SPK MIXL", RT5659_PWR_MIXER, RT5659_PWR_SM_L_BIT,
+		0, rt5659_spk_l_mix, ARRAY_SIZE(rt5659_spk_l_mix)),
+	SND_SOC_DAPM_MIXER("SPK MIXR", RT5659_PWR_MIXER, RT5659_PWR_SM_R_BIT,
+		0, rt5659_spk_r_mix, ARRAY_SIZE(rt5659_spk_r_mix)),
+	SND_SOC_DAPM_MIXER("MONOVOL MIX", RT5659_PWR_MIXER, RT5659_PWR_MM_BIT,
+		0, rt5659_monovol_mix, ARRAY_SIZE(rt5659_monovol_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXL", RT5659_PWR_MIXER, RT5659_PWR_OM_L_BIT,
+		0, rt5659_out_l_mix, ARRAY_SIZE(rt5659_out_l_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXR", RT5659_PWR_MIXER, RT5659_PWR_OM_R_BIT,
+		0, rt5659_out_r_mix, ARRAY_SIZE(rt5659_out_r_mix)),
+
+	/* Output Volume */
+	SND_SOC_DAPM_SWITCH("SPKVOL L", RT5659_PWR_VOL, RT5659_PWR_SV_L_BIT, 0,
+		&spkvol_l_switch),
+	SND_SOC_DAPM_SWITCH("SPKVOL R", RT5659_PWR_VOL, RT5659_PWR_SV_R_BIT, 0,
+		&spkvol_r_switch),
+	SND_SOC_DAPM_SWITCH("MONOVOL", RT5659_PWR_VOL, RT5659_PWR_MV_BIT, 0,
+		&monovol_switch),
+	SND_SOC_DAPM_SWITCH("OUTVOL L", RT5659_PWR_VOL, RT5659_PWR_OV_L_BIT, 0,
+		&outvol_l_switch),
+	SND_SOC_DAPM_SWITCH("OUTVOL R", RT5659_PWR_VOL, RT5659_PWR_OV_R_BIT, 0,
+		&outvol_r_switch),
+
+	/* SPO/MONO/HPO/LOUT */
+	SND_SOC_DAPM_MIXER("SPO L MIX", SND_SOC_NOPM, 0, 0, rt5659_spo_l_mix,
+		ARRAY_SIZE(rt5659_spo_l_mix)),
+	SND_SOC_DAPM_MIXER("SPO R MIX", SND_SOC_NOPM, 0, 0, rt5659_spo_r_mix,
+		ARRAY_SIZE(rt5659_spo_r_mix)),
+	SND_SOC_DAPM_MIXER("Mono MIX", SND_SOC_NOPM, 0,	0, rt5659_mono_mix,
+		ARRAY_SIZE(rt5659_mono_mix)),
+	SND_SOC_DAPM_MIXER("LOUT L MIX", SND_SOC_NOPM, 0, 0, rt5659_lout_l_mix,
+		ARRAY_SIZE(rt5659_lout_l_mix)),
+	SND_SOC_DAPM_MIXER("LOUT R MIX", SND_SOC_NOPM, 0, 0, rt5659_lout_r_mix,
+		ARRAY_SIZE(rt5659_lout_r_mix)),
+
+	SND_SOC_DAPM_PGA_S("SPK Amp", 1, RT5659_PWR_DIG_1, RT5659_PWR_CLS_D_BIT,
+		0, rt5659_spk_event, SND_SOC_DAPM_POST_PMD |
+		SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_PGA_S("Mono Amp", 1, RT5659_PWR_ANLG_1, RT5659_PWR_MA_BIT,
+		0, rt5659_mono_event, SND_SOC_DAPM_POST_PMD |
+		SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5659_hp_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("LOUT Amp", 1,  RT5659_PWR_ANLG_1, RT5659_PWR_LM_BIT,
+		0,  NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0,
+		rt5659_charge_pump_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SWITCH("SPO Playback", SND_SOC_NOPM, 0, 0, &spo_switch),
+	SND_SOC_DAPM_SWITCH("Mono Playback", SND_SOC_NOPM, 0, 0,
+		&mono_switch),
+	SND_SOC_DAPM_SWITCH("HPO L Playback", SND_SOC_NOPM, 0, 0,
+		&hpo_l_switch),
+	SND_SOC_DAPM_SWITCH("HPO R Playback", SND_SOC_NOPM, 0, 0,
+		&hpo_r_switch),
+	SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0,
+		&lout_l_switch),
+	SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0,
+		&lout_r_switch),
+	SND_SOC_DAPM_SWITCH("PDM L Playback", SND_SOC_NOPM, 0, 0,
+		&pdm_l_switch),
+	SND_SOC_DAPM_SWITCH("PDM R Playback", SND_SOC_NOPM, 0, 0,
+		&pdm_r_switch),
+
+	/* PDM */
+	SND_SOC_DAPM_SUPPLY("PDM Power", RT5659_PWR_DIG_2,
+		RT5659_PWR_PDM1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("PDM L Mux", RT5659_PDM_OUT_CTRL,
+		RT5659_M_PDM1_L_SFT, 1, &rt5659_pdm_l_mux),
+	SND_SOC_DAPM_MUX("PDM R Mux", RT5659_PDM_OUT_CTRL,
+		RT5659_M_PDM1_R_SFT, 1, &rt5659_pdm_r_mux),
+
+	/* SPDIF */
+	SND_SOC_DAPM_MUX("SPDIF Mux", SND_SOC_NOPM, 0, 0, &rt5659_spdif_mux),
+
+	SND_SOC_DAPM_SUPPLY("SYS CLK DET", RT5659_CLK_DET, 3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET", RT5659_CLK_DET, 0, 0, NULL, 0),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+	SND_SOC_DAPM_OUTPUT("SPOL"),
+	SND_SOC_DAPM_OUTPUT("SPOR"),
+	SND_SOC_DAPM_OUTPUT("LOUTL"),
+	SND_SOC_DAPM_OUTPUT("LOUTR"),
+	SND_SOC_DAPM_OUTPUT("MONOOUT"),
+	SND_SOC_DAPM_OUTPUT("PDML"),
+	SND_SOC_DAPM_OUTPUT("PDMR"),
+	SND_SOC_DAPM_OUTPUT("SPDIF"),
+};
+
+static const struct snd_soc_dapm_route rt5659_dapm_routes[] = {
+	/*PLL*/
+	{ "ADC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll },
+	{ "ADC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll },
+	{ "ADC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll },
+	{ "ADC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll },
+	{ "DAC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll },
+	{ "DAC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll },
+	{ "DAC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll },
+
+	/*ASRC*/
+	{ "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc },
+	{ "ADC Mono Left Filter", NULL, "ADC Mono L ASRC", is_using_asrc },
+	{ "ADC Mono Right Filter", NULL, "ADC Mono R ASRC", is_using_asrc },
+	{ "DAC Mono Left Filter", NULL, "DAC Mono L ASRC", is_using_asrc },
+	{ "DAC Mono Right Filter", NULL, "DAC Mono R ASRC", is_using_asrc },
+	{ "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc },
+
+	{ "SYS CLK DET", NULL, "CLKDET" },
+
+	{ "I2S1", NULL, "I2S1 ASRC" },
+	{ "I2S2", NULL, "I2S2 ASRC" },
+	{ "I2S3", NULL, "I2S3 ASRC" },
+
+	{ "DMIC1", NULL, "DMIC L1" },
+	{ "DMIC1", NULL, "DMIC R1" },
+	{ "DMIC2", NULL, "DMIC L2" },
+	{ "DMIC2", NULL, "DMIC R2" },
+
+	{ "BST1", NULL, "IN1P" },
+	{ "BST1", NULL, "IN1N" },
+	{ "BST1", NULL, "BST1 Power" },
+	{ "BST2", NULL, "IN2P" },
+	{ "BST2", NULL, "IN2N" },
+	{ "BST2", NULL, "BST2 Power" },
+	{ "BST3", NULL, "IN3P" },
+	{ "BST3", NULL, "IN3N" },
+	{ "BST3", NULL, "BST3 Power" },
+	{ "BST4", NULL, "IN4P" },
+	{ "BST4", NULL, "IN4N" },
+	{ "BST4", NULL, "BST4 Power" },
+
+	{ "INL VOL", NULL, "IN2P" },
+	{ "INR VOL", NULL, "IN2N" },
+
+	{ "RECMIX1L", "SPKVOLL Switch", "SPKVOL L" },
+	{ "RECMIX1L", "INL Switch", "INL VOL" },
+	{ "RECMIX1L", "BST4 Switch", "BST4" },
+	{ "RECMIX1L", "BST3 Switch", "BST3" },
+	{ "RECMIX1L", "BST2 Switch", "BST2" },
+	{ "RECMIX1L", "BST1 Switch", "BST1" },
+
+	{ "RECMIX1R", "HPOVOLR Switch", "HPO R Playback" },
+	{ "RECMIX1R", "INR Switch", "INR VOL" },
+	{ "RECMIX1R", "BST4 Switch", "BST4" },
+	{ "RECMIX1R", "BST3 Switch", "BST3" },
+	{ "RECMIX1R", "BST2 Switch", "BST2" },
+	{ "RECMIX1R", "BST1 Switch", "BST1" },
+
+	{ "RECMIX2L", "SPKVOLL Switch", "SPKVOL L" },
+	{ "RECMIX2L", "OUTVOLL Switch", "OUTVOL L" },
+	{ "RECMIX2L", "BST4 Switch", "BST4" },
+	{ "RECMIX2L", "BST3 Switch", "BST3" },
+	{ "RECMIX2L", "BST2 Switch", "BST2" },
+	{ "RECMIX2L", "BST1 Switch", "BST1" },
+
+	{ "RECMIX2R", "MONOVOL Switch", "MONOVOL" },
+	{ "RECMIX2R", "OUTVOLR Switch", "OUTVOL R" },
+	{ "RECMIX2R", "BST4 Switch", "BST4" },
+	{ "RECMIX2R", "BST3 Switch", "BST3" },
+	{ "RECMIX2R", "BST2 Switch", "BST2" },
+	{ "RECMIX2R", "BST1 Switch", "BST1" },
+
+	{ "ADC1 L", NULL, "RECMIX1L" },
+	{ "ADC1 L", NULL, "ADC1 L Power" },
+	{ "ADC1 L", NULL, "ADC1 clock" },
+	{ "ADC1 R", NULL, "RECMIX1R" },
+	{ "ADC1 R", NULL, "ADC1 R Power" },
+	{ "ADC1 R", NULL, "ADC1 clock" },
+
+	{ "ADC2 L", NULL, "RECMIX2L" },
+	{ "ADC2 L", NULL, "ADC2 L Power" },
+	{ "ADC2 L", NULL, "ADC2 clock" },
+	{ "ADC2 R", NULL, "RECMIX2R" },
+	{ "ADC2 R", NULL, "ADC2 R Power" },
+	{ "ADC2 R", NULL, "ADC2 clock" },
+
+	{ "DMIC L1", NULL, "DMIC CLK" },
+	{ "DMIC L1", NULL, "DMIC1 Power" },
+	{ "DMIC R1", NULL, "DMIC CLK" },
+	{ "DMIC R1", NULL, "DMIC1 Power" },
+	{ "DMIC L2", NULL, "DMIC CLK" },
+	{ "DMIC L2", NULL, "DMIC2 Power" },
+	{ "DMIC R2", NULL, "DMIC CLK" },
+	{ "DMIC R2", NULL, "DMIC2 Power" },
+
+	{ "Stereo1 DMIC L Mux", "DMIC1", "DMIC L1" },
+	{ "Stereo1 DMIC L Mux", "DMIC2", "DMIC L2" },
+
+	{ "Stereo1 DMIC R Mux", "DMIC1", "DMIC R1" },
+	{ "Stereo1 DMIC R Mux", "DMIC2", "DMIC R2" },
+
+	{ "Mono DMIC L Mux", "DMIC1 L", "DMIC L1" },
+	{ "Mono DMIC L Mux", "DMIC2 L", "DMIC L2" },
+
+	{ "Mono DMIC R Mux", "DMIC1 R", "DMIC R1" },
+	{ "Mono DMIC R Mux", "DMIC2 R", "DMIC R2" },
+
+	{ "Stereo1 ADC L Mux", "ADC1", "ADC1 L" },
+	{ "Stereo1 ADC L Mux", "ADC2", "ADC2 L" },
+	{ "Stereo1 ADC R Mux", "ADC1", "ADC1 R" },
+	{ "Stereo1 ADC R Mux", "ADC2", "ADC2 R" },
+
+	{ "Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux" },
+	{ "Stereo1 ADC L1 Mux", "DAC MIX", "DAC MIXL" },
+	{ "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC L Mux" },
+	{ "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" },
+
+	{ "Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux" },
+	{ "Stereo1 ADC R1 Mux", "DAC MIX", "DAC MIXR" },
+	{ "Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC R Mux" },
+	{ "Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR" },
+
+	{ "Mono ADC L Mux", "ADC1 L", "ADC1 L" },
+	{ "Mono ADC L Mux", "ADC1 R", "ADC1 R" },
+	{ "Mono ADC L Mux", "ADC2 L", "ADC2 L" },
+	{ "Mono ADC L Mux", "ADC2 R", "ADC2 R" },
+
+	{ "Mono ADC R Mux", "ADC1 L", "ADC1 L" },
+	{ "Mono ADC R Mux", "ADC1 R", "ADC1 R" },
+	{ "Mono ADC R Mux", "ADC2 L", "ADC2 L" },
+	{ "Mono ADC R Mux", "ADC2 R", "ADC2 R" },
+
+	{ "Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux" },
+	{ "Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL" },
+	{ "Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL" },
+	{ "Mono ADC L1 Mux", "ADC",  "Mono ADC L Mux" },
+
+	{ "Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR" },
+	{ "Mono ADC R1 Mux", "ADC", "Mono ADC R Mux" },
+	{ "Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux" },
+	{ "Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR" },
+
+	{ "Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux" },
+	{ "Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux" },
+	{ "Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter" },
+
+	{ "Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux" },
+	{ "Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux" },
+	{ "Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter" },
+
+	{ "Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux" },
+	{ "Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux" },
+	{ "Mono ADC MIXL", NULL, "ADC Mono Left Filter" },
+
+	{ "Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux" },
+	{ "Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux" },
+	{ "Mono ADC MIXR", NULL, "ADC Mono Right Filter" },
+
+	{ "Stereo1 ADC Volume L", NULL, "Stereo1 ADC MIXL" },
+	{ "Stereo1 ADC Volume R", NULL, "Stereo1 ADC MIXR" },
+
+	{ "IF_ADC1", NULL, "Stereo1 ADC Volume L" },
+	{ "IF_ADC1", NULL, "Stereo1 ADC Volume R" },
+	{ "IF_ADC2", NULL, "Mono ADC MIXL" },
+	{ "IF_ADC2", NULL, "Mono ADC MIXR" },
+
+	{ "TDM AD1:AD2:DAC", NULL, "IF_ADC1" },
+	{ "TDM AD1:AD2:DAC", NULL, "IF_ADC2" },
+	{ "TDM AD1:AD2:DAC", NULL, "DAC_REF" },
+	{ "TDM AD2:DAC", NULL, "IF_ADC2" },
+	{ "TDM AD2:DAC", NULL, "DAC_REF" },
+	{ "TDM Data Mux", "AD1:AD2:DAC:NUL", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD1:AD2:NUL:DAC", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD1:DAC:AD2:NUL", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD1:DAC:NUL:AD2", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD1:NUL:DAC:AD2", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD1:NUL:AD2:DAC", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD2:AD1:DAC:NUL", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD2:AD1:NUL:DAC", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD2:DAC:AD1:NUL", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD2:DAC:NUL:AD1", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD2:NUL:DAC:AD1", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD1:NUL:AD1:DAC", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "DAC:AD1:AD2:NUL", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "DAC:AD1:NUL:AD2", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "DAC:AD2:AD1:NUL", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "DAC:AD2:NUL:AD1", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "DAC:NUL:DAC:AD2", "TDM AD2:DAC" },
+	{ "TDM Data Mux", "DAC:NUL:AD2:DAC", "TDM AD2:DAC" },
+	{ "TDM Data Mux", "NUL:AD1:AD2:DAC", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "NUL:AD1:DAC:AD2", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "NUL:AD2:AD1:DAC", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "NUL:AD2:DAC:AD1", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "NUL:DAC:DAC:AD2", "TDM AD2:DAC" },
+	{ "TDM Data Mux", "NUL:DAC:AD2:DAC", "TDM AD2:DAC" },
+	{ "IF1 01 ADC Swap Mux", "L/R", "TDM Data Mux" },
+	{ "IF1 01 ADC Swap Mux", "R/L", "TDM Data Mux" },
+	{ "IF1 01 ADC Swap Mux", "L/L", "TDM Data Mux" },
+	{ "IF1 01 ADC Swap Mux", "R/R", "TDM Data Mux" },
+	{ "IF1 23 ADC Swap Mux", "L/R", "TDM Data Mux" },
+	{ "IF1 23 ADC Swap Mux", "R/L", "TDM Data Mux" },
+	{ "IF1 23 ADC Swap Mux", "L/L", "TDM Data Mux" },
+	{ "IF1 23 ADC Swap Mux", "R/R", "TDM Data Mux" },
+	{ "IF1 45 ADC Swap Mux", "L/R", "TDM Data Mux" },
+	{ "IF1 45 ADC Swap Mux", "R/L", "TDM Data Mux" },
+	{ "IF1 45 ADC Swap Mux", "L/L", "TDM Data Mux" },
+	{ "IF1 45 ADC Swap Mux", "R/R", "TDM Data Mux" },
+	{ "IF1 67 ADC Swap Mux", "L/R", "TDM Data Mux" },
+	{ "IF1 67 ADC Swap Mux", "R/L", "TDM Data Mux" },
+	{ "IF1 67 ADC Swap Mux", "L/L", "TDM Data Mux" },
+	{ "IF1 67 ADC Swap Mux", "R/R", "TDM Data Mux" },
+	{ "IF1 ADC", NULL, "IF1 01 ADC Swap Mux" },
+	{ "IF1 ADC", NULL, "IF1 23 ADC Swap Mux" },
+	{ "IF1 ADC", NULL, "IF1 45 ADC Swap Mux" },
+	{ "IF1 ADC", NULL, "IF1 67 ADC Swap Mux" },
+	{ "IF1 ADC", NULL, "I2S1" },
+
+	{ "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" },
+	{ "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" },
+	{ "IF2 ADC Mux", "IF_ADC3", "IF_ADC3" },
+	{ "IF2 ADC Mux", "DAC_REF", "DAC_REF" },
+	{ "IF2 ADC", NULL, "IF2 ADC Mux"},
+	{ "IF2 ADC", NULL, "I2S2" },
+
+	{ "IF3 ADC Mux", "IF_ADC1", "IF_ADC1" },
+	{ "IF3 ADC Mux", "IF_ADC2", "IF_ADC2" },
+	{ "IF3 ADC Mux", "Stereo2_ADC_L/R", "Stereo2 ADC LR" },
+	{ "IF3 ADC Mux", "DAC_REF", "DAC_REF" },
+	{ "IF3 ADC", NULL, "IF3 ADC Mux"},
+	{ "IF3 ADC", NULL, "I2S3" },
+
+	{ "AIF1TX", NULL, "IF1 ADC" },
+	{ "IF2 ADC Swap Mux", "L/R", "IF2 ADC" },
+	{ "IF2 ADC Swap Mux", "R/L", "IF2 ADC" },
+	{ "IF2 ADC Swap Mux", "L/L", "IF2 ADC" },
+	{ "IF2 ADC Swap Mux", "R/R", "IF2 ADC" },
+	{ "AIF2TX", NULL, "IF2 ADC Swap Mux" },
+	{ "IF3 ADC Swap Mux", "L/R", "IF3 ADC" },
+	{ "IF3 ADC Swap Mux", "R/L", "IF3 ADC" },
+	{ "IF3 ADC Swap Mux", "L/L", "IF3 ADC" },
+	{ "IF3 ADC Swap Mux", "R/R", "IF3 ADC" },
+	{ "AIF3TX", NULL, "IF3 ADC Swap Mux" },
+
+	{ "IF1 DAC1", NULL, "AIF1RX" },
+	{ "IF1 DAC2", NULL, "AIF1RX" },
+	{ "IF2 DAC Swap Mux", "L/R", "AIF2RX" },
+	{ "IF2 DAC Swap Mux", "R/L", "AIF2RX" },
+	{ "IF2 DAC Swap Mux", "L/L", "AIF2RX" },
+	{ "IF2 DAC Swap Mux", "R/R", "AIF2RX" },
+	{ "IF2 DAC", NULL, "IF2 DAC Swap Mux" },
+	{ "IF3 DAC Swap Mux", "L/R", "AIF3RX" },
+	{ "IF3 DAC Swap Mux", "R/L", "AIF3RX" },
+	{ "IF3 DAC Swap Mux", "L/L", "AIF3RX" },
+	{ "IF3 DAC Swap Mux", "R/R", "AIF3RX" },
+	{ "IF3 DAC", NULL, "IF3 DAC Swap Mux" },
+
+	{ "IF1 DAC1", NULL, "I2S1" },
+	{ "IF1 DAC2", NULL, "I2S1" },
+	{ "IF2 DAC", NULL, "I2S2" },
+	{ "IF3 DAC", NULL, "I2S3" },
+
+	{ "IF1 DAC2 L", NULL, "IF1 DAC2" },
+	{ "IF1 DAC2 R", NULL, "IF1 DAC2" },
+	{ "IF1 DAC1 L", NULL, "IF1 DAC1" },
+	{ "IF1 DAC1 R", NULL, "IF1 DAC1" },
+	{ "IF2 DAC L", NULL, "IF2 DAC" },
+	{ "IF2 DAC R", NULL, "IF2 DAC" },
+	{ "IF3 DAC L", NULL, "IF3 DAC" },
+	{ "IF3 DAC R", NULL, "IF3 DAC" },
+
+	{ "DAC L1 Mux", "IF1 DAC1", "IF1 DAC1 L" },
+	{ "DAC L1 Mux", "IF2 DAC", "IF2 DAC L" },
+	{ "DAC L1 Mux", "IF3 DAC", "IF3 DAC L" },
+	{ "DAC L1 Mux", NULL, "DAC Stereo1 Filter" },
+
+	{ "DAC R1 Mux", "IF1 DAC1", "IF1 DAC1 R" },
+	{ "DAC R1 Mux", "IF2 DAC", "IF2 DAC R" },
+	{ "DAC R1 Mux", "IF3 DAC", "IF3 DAC R" },
+	{ "DAC R1 Mux", NULL, "DAC Stereo1 Filter" },
+
+	{ "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC Volume L" },
+	{ "DAC1 MIXL", "DAC1 Switch", "DAC L1 Mux" },
+	{ "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC Volume R" },
+	{ "DAC1 MIXR", "DAC1 Switch", "DAC R1 Mux" },
+
+	{ "DAC_REF", NULL, "DAC1 MIXL" },
+	{ "DAC_REF", NULL, "DAC1 MIXR" },
+
+	{ "DAC L2 Mux", "IF1 DAC2", "IF1 DAC2 L" },
+	{ "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" },
+	{ "DAC L2 Mux", "IF3 DAC", "IF3 DAC L" },
+	{ "DAC L2 Mux", "Mono ADC MIX", "Mono ADC MIXL" },
+	{ "DAC L2 Mux", NULL, "DAC Mono Left Filter" },
+
+	{ "DAC R2 Mux", "IF1 DAC2", "IF1 DAC2 R" },
+	{ "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" },
+	{ "DAC R2 Mux", "IF3 DAC", "IF3 DAC R" },
+	{ "DAC R2 Mux", "Mono ADC MIX", "Mono ADC MIXR" },
+	{ "DAC R2 Mux", NULL, "DAC Mono Right Filter" },
+
+	{ "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux" },
+	{ "Stereo DAC MIXL", "DAC R2 Switch", "DAC R2 Mux" },
+
+	{ "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXR", "DAC L2 Switch", "DAC L2 Mux" },
+	{ "Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux" },
+
+	{ "Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Mono DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux" },
+	{ "Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux" },
+	{ "Mono DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux" },
+	{ "Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux" },
+
+	{ "DAC MIXL", "Stereo DAC Mixer", "Stereo DAC MIXL" },
+	{ "DAC MIXL", "Mono DAC Mixer", "Mono DAC MIXL" },
+	{ "DAC MIXR", "Stereo DAC Mixer", "Stereo DAC MIXR" },
+	{ "DAC MIXR", "Mono DAC Mixer", "Mono DAC MIXR" },
+
+	{ "DAC L1 Source", NULL, "DAC L1 Power" },
+	{ "DAC L1 Source", "DAC", "DAC1 MIXL" },
+	{ "DAC L1 Source", "Stereo DAC Mixer", "Stereo DAC MIXL" },
+	{ "DAC R1 Source", NULL, "DAC R1 Power" },
+	{ "DAC R1 Source", "DAC", "DAC1 MIXR" },
+	{ "DAC R1 Source", "Stereo DAC Mixer", "Stereo DAC MIXR" },
+	{ "DAC L2 Source", "Stereo DAC Mixer", "Stereo DAC MIXL" },
+	{ "DAC L2 Source", "Mono DAC Mixer", "Mono DAC MIXL" },
+	{ "DAC L2 Source", NULL, "DAC L2 Power" },
+	{ "DAC R2 Source", "Stereo DAC Mixer", "Stereo DAC MIXR" },
+	{ "DAC R2 Source", "Mono DAC Mixer", "Mono DAC MIXR" },
+	{ "DAC R2 Source", NULL, "DAC R2 Power" },
+
+	{ "DAC L1", NULL, "DAC L1 Source" },
+	{ "DAC R1", NULL, "DAC R1 Source" },
+	{ "DAC L2", NULL, "DAC L2 Source" },
+	{ "DAC R2", NULL, "DAC R2 Source" },
+
+	{ "SPK MIXL", "DAC L2 Switch", "DAC L2" },
+	{ "SPK MIXL", "BST1 Switch", "BST1" },
+	{ "SPK MIXL", "INL Switch", "INL VOL" },
+	{ "SPK MIXL", "INR Switch", "INR VOL" },
+	{ "SPK MIXL", "BST3 Switch", "BST3" },
+	{ "SPK MIXR", "DAC R2 Switch", "DAC R2" },
+	{ "SPK MIXR", "BST4 Switch", "BST4" },
+	{ "SPK MIXR", "INL Switch", "INL VOL" },
+	{ "SPK MIXR", "INR Switch", "INR VOL" },
+	{ "SPK MIXR", "BST3 Switch", "BST3" },
+
+	{ "MONOVOL MIX", "DAC L2 Switch", "DAC L2" },
+	{ "MONOVOL MIX", "DAC R2 Switch", "DAC R2" },
+	{ "MONOVOL MIX", "BST1 Switch", "BST1" },
+	{ "MONOVOL MIX", "BST2 Switch", "BST2" },
+	{ "MONOVOL MIX", "BST3 Switch", "BST3" },
+
+	{ "OUT MIXL", "DAC L2 Switch", "DAC L2" },
+	{ "OUT MIXL", "INL Switch", "INL VOL" },
+	{ "OUT MIXL", "BST1 Switch", "BST1" },
+	{ "OUT MIXL", "BST2 Switch", "BST2" },
+	{ "OUT MIXL", "BST3 Switch", "BST3" },
+	{ "OUT MIXR", "DAC R2 Switch", "DAC R2" },
+	{ "OUT MIXR", "INR Switch", "INR VOL" },
+	{ "OUT MIXR", "BST2 Switch", "BST2" },
+	{ "OUT MIXR", "BST3 Switch", "BST3" },
+	{ "OUT MIXR", "BST4 Switch", "BST4" },
+
+	{ "SPKVOL L", "Switch", "SPK MIXL" },
+	{ "SPKVOL R", "Switch", "SPK MIXR" },
+	{ "SPO L MIX", "DAC L2 Switch", "DAC L2" },
+	{ "SPO L MIX", "SPKVOL L Switch", "SPKVOL L" },
+	{ "SPO R MIX", "DAC R2 Switch", "DAC R2" },
+	{ "SPO R MIX", "SPKVOL R Switch", "SPKVOL R" },
+	{ "SPK Amp", NULL, "SPO L MIX" },
+	{ "SPK Amp", NULL, "SPO R MIX" },
+	{ "SPK Amp", NULL, "SYS CLK DET" },
+	{ "SPO Playback", "Switch", "SPK Amp" },
+	{ "SPOL", NULL, "SPO Playback" },
+	{ "SPOR", NULL, "SPO Playback" },
+
+	{ "MONOVOL", "Switch", "MONOVOL MIX" },
+	{ "Mono MIX", "DAC L2 Switch", "DAC L2" },
+	{ "Mono MIX", "MONOVOL Switch", "MONOVOL" },
+	{ "Mono Amp", NULL, "Mono MIX" },
+	{ "Mono Amp", NULL, "Mono Vref" },
+	{ "Mono Amp", NULL, "SYS CLK DET" },
+	{ "Mono Playback", "Switch", "Mono Amp" },
+	{ "MONOOUT", NULL, "Mono Playback" },
+
+	{ "HP Amp", NULL, "DAC L1" },
+	{ "HP Amp", NULL, "DAC R1" },
+	{ "HP Amp", NULL, "Charge Pump" },
+	{ "HP Amp", NULL, "SYS CLK DET" },
+	{ "HPO L Playback", "Switch", "HP Amp"},
+	{ "HPO R Playback", "Switch", "HP Amp"},
+	{ "HPOL", NULL, "HPO L Playback" },
+	{ "HPOR", NULL, "HPO R Playback" },
+
+	{ "OUTVOL L", "Switch", "OUT MIXL" },
+	{ "OUTVOL R", "Switch", "OUT MIXR" },
+	{ "LOUT L MIX", "DAC L2 Switch", "DAC L2" },
+	{ "LOUT L MIX", "OUTVOL L Switch", "OUTVOL L" },
+	{ "LOUT R MIX", "DAC R2 Switch", "DAC R2" },
+	{ "LOUT R MIX", "OUTVOL R Switch", "OUTVOL R" },
+	{ "LOUT Amp", NULL, "LOUT L MIX" },
+	{ "LOUT Amp", NULL, "LOUT R MIX" },
+	{ "LOUT Amp", NULL, "Charge Pump" },
+	{ "LOUT Amp", NULL, "SYS CLK DET" },
+	{ "LOUT L Playback", "Switch", "LOUT Amp" },
+	{ "LOUT R Playback", "Switch", "LOUT Amp" },
+	{ "LOUTL", NULL, "LOUT L Playback" },
+	{ "LOUTR", NULL, "LOUT R Playback" },
+
+	{ "PDM L Mux", "Mono DAC", "Mono DAC MIXL" },
+	{ "PDM L Mux", "Stereo DAC", "Stereo DAC MIXL" },
+	{ "PDM L Mux", NULL, "PDM Power" },
+	{ "PDM R Mux", "Mono DAC", "Mono DAC MIXR" },
+	{ "PDM R Mux", "Stereo DAC", "Stereo DAC MIXR" },
+	{ "PDM R Mux", NULL, "PDM Power" },
+	{ "PDM L Playback", "Switch", "PDM L Mux" },
+	{ "PDM R Playback", "Switch", "PDM R Mux" },
+	{ "PDML", NULL, "PDM L Playback" },
+	{ "PDMR", NULL, "PDM R Playback" },
+
+	{ "SPDIF Mux", "IF3_DAC", "IF3 DAC" },
+	{ "SPDIF Mux", "IF2_DAC", "IF2 DAC" },
+	{ "SPDIF Mux", "IF1_DAC2", "IF1 DAC2" },
+	{ "SPDIF Mux", "IF1_DAC1", "IF1 DAC1" },
+	{ "SPDIF", NULL, "SPDIF Mux" },
+};
+
+static int rt5659_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0, val_clk, mask_clk;
+	int pre_div, frame_size;
+
+	rt5659->lrck[dai->id] = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5659->sysclk, rt5659->lrck[dai->id]);
+	if (pre_div < 0) {
+		dev_err(component->dev, "Unsupported clock setting %d for DAI %d\n",
+			rt5659->lrck[dai->id], dai->id);
+		return -EINVAL;
+	}
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+				rt5659->lrck[dai->id], pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		val_len |= RT5659_I2S_DL_20;
+		break;
+	case 24:
+		val_len |= RT5659_I2S_DL_24;
+		break;
+	case 8:
+		val_len |= RT5659_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5659_AIF1:
+		mask_clk = RT5659_I2S_PD1_MASK;
+		val_clk = pre_div << RT5659_I2S_PD1_SFT;
+		snd_soc_component_update_bits(component, RT5659_I2S1_SDP,
+			RT5659_I2S_DL_MASK, val_len);
+		break;
+	case RT5659_AIF2:
+		mask_clk = RT5659_I2S_PD2_MASK;
+		val_clk = pre_div << RT5659_I2S_PD2_SFT;
+		snd_soc_component_update_bits(component, RT5659_I2S2_SDP,
+			RT5659_I2S_DL_MASK, val_len);
+		break;
+	case RT5659_AIF3:
+		mask_clk = RT5659_I2S_PD3_MASK;
+		val_clk = pre_div << RT5659_I2S_PD3_SFT;
+		snd_soc_component_update_bits(component, RT5659_I2S3_SDP,
+			RT5659_I2S_DL_MASK, val_len);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5659_ADDA_CLK_1, mask_clk, val_clk);
+
+	switch (rt5659->lrck[dai->id]) {
+	case 192000:
+		snd_soc_component_update_bits(component, RT5659_ADDA_CLK_1,
+			RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_32);
+		break;
+	case 96000:
+		snd_soc_component_update_bits(component, RT5659_ADDA_CLK_1,
+			RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_64);
+		break;
+	default:
+		snd_soc_component_update_bits(component, RT5659_ADDA_CLK_1,
+			RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_128);
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5659_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5659->master[dai->id] = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5659_I2S_MS_S;
+		rt5659->master[dai->id] = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5659_I2S_BP_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5659_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5659_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5659_I2S_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5659_AIF1:
+		snd_soc_component_update_bits(component, RT5659_I2S1_SDP,
+			RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
+			RT5659_I2S_DF_MASK, reg_val);
+		break;
+	case RT5659_AIF2:
+		snd_soc_component_update_bits(component, RT5659_I2S2_SDP,
+			RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
+			RT5659_I2S_DF_MASK, reg_val);
+		break;
+	case RT5659_AIF3:
+		snd_soc_component_update_bits(component, RT5659_I2S3_SDP,
+			RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
+			RT5659_I2S_DF_MASK, reg_val);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int rt5659_set_component_sysclk(struct snd_soc_component *component, int clk_id,
+				   int source, unsigned int freq, int dir)
+{
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	if (freq == rt5659->sysclk && clk_id == rt5659->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5659_SCLK_S_MCLK:
+		reg_val |= RT5659_SCLK_SRC_MCLK;
+		break;
+	case RT5659_SCLK_S_PLL1:
+		reg_val |= RT5659_SCLK_SRC_PLL1;
+		break;
+	case RT5659_SCLK_S_RCCLK:
+		reg_val |= RT5659_SCLK_SRC_RCCLK;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, RT5659_GLB_CLK,
+		RT5659_SCLK_SRC_MASK, reg_val);
+	rt5659->sysclk = freq;
+	rt5659->sysclk_src = clk_id;
+
+	dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n",
+		freq, clk_id);
+
+	return 0;
+}
+
+static int rt5659_set_component_pll(struct snd_soc_component *component, int pll_id,
+				int source, unsigned int freq_in,
+				unsigned int freq_out)
+{
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5659->pll_src && freq_in == rt5659->pll_in &&
+	    freq_out == rt5659->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt5659->pll_in = 0;
+		rt5659->pll_out = 0;
+		snd_soc_component_update_bits(component, RT5659_GLB_CLK,
+			RT5659_SCLK_SRC_MASK, RT5659_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5659_PLL1_S_MCLK:
+		snd_soc_component_update_bits(component, RT5659_GLB_CLK,
+			RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_MCLK);
+		break;
+	case RT5659_PLL1_S_BCLK1:
+		snd_soc_component_update_bits(component, RT5659_GLB_CLK,
+				RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK1);
+		break;
+	case RT5659_PLL1_S_BCLK2:
+		snd_soc_component_update_bits(component, RT5659_GLB_CLK,
+				RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK2);
+		break;
+	case RT5659_PLL1_S_BCLK3:
+		snd_soc_component_update_bits(component, RT5659_GLB_CLK,
+				RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK3);
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_component_write(component, RT5659_PLL_CTRL_1,
+		pll_code.n_code << RT5659_PLL_N_SFT | pll_code.k_code);
+	snd_soc_component_write(component, RT5659_PLL_CTRL_2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5659_PLL_M_SFT |
+		pll_code.m_bp << RT5659_PLL_M_BP_SFT);
+
+	rt5659->pll_in = freq_in;
+	rt5659->pll_out = freq_out;
+	rt5659->pll_src = source;
+
+	return 0;
+}
+
+static int rt5659_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int val = 0;
+
+	if (rx_mask || tx_mask)
+		val |= (1 << 15);
+
+	switch (slots) {
+	case 4:
+		val |= (1 << 10);
+		val |= (1 << 8);
+		break;
+	case 6:
+		val |= (2 << 10);
+		val |= (2 << 8);
+		break;
+	case 8:
+		val |= (3 << 10);
+		val |= (3 << 8);
+		break;
+	case 2:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (slot_width) {
+	case 20:
+		val |= (1 << 6);
+		val |= (1 << 4);
+		break;
+	case 24:
+		val |= (2 << 6);
+		val |= (2 << 4);
+		break;
+	case 32:
+		val |= (3 << 6);
+		val |= (3 << 4);
+		break;
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5659_TDM_CTRL_1, 0x8ff0, val);
+
+	return 0;
+}
+
+static int rt5659_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
+
+	rt5659->bclk[dai->id] = ratio;
+
+	if (ratio == 64) {
+		switch (dai->id) {
+		case RT5659_AIF2:
+			snd_soc_component_update_bits(component, RT5659_ADDA_CLK_1,
+				RT5659_I2S_BCLK_MS2_MASK,
+				RT5659_I2S_BCLK_MS2_64);
+			break;
+		case RT5659_AIF3:
+			snd_soc_component_update_bits(component, RT5659_ADDA_CLK_1,
+				RT5659_I2S_BCLK_MS3_MASK,
+				RT5659_I2S_BCLK_MS3_64);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int rt5659_set_bias_level(struct snd_soc_component *component,
+			enum snd_soc_bias_level level)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC,
+			RT5659_DIG_GATE_CTRL, RT5659_DIG_GATE_CTRL);
+		regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1,
+			RT5659_PWR_LDO,	RT5659_PWR_LDO);
+		regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+			RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2,
+			RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2);
+		msleep(20);
+		regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+			RT5659_PWR_FV1 | RT5659_PWR_FV2,
+			RT5659_PWR_FV1 | RT5659_PWR_FV2);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (dapm->bias_level == SND_SOC_BIAS_OFF) {
+			ret = clk_prepare_enable(rt5659->mclk);
+			if (ret) {
+				dev_err(component->dev,
+					"failed to enable MCLK: %d\n", ret);
+				return ret;
+			}
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1,
+			RT5659_PWR_LDO, 0);
+		regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+			RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2
+			| RT5659_PWR_FV1 | RT5659_PWR_FV2,
+			RT5659_PWR_MB | RT5659_PWR_VREF2);
+		regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC,
+			RT5659_DIG_GATE_CTRL, 0);
+		clk_disable_unprepare(rt5659->mclk);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5659_probe(struct snd_soc_component *component)
+{
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
+
+	rt5659->component = component;
+
+	return 0;
+}
+
+static void rt5659_remove(struct snd_soc_component *component)
+{
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
+
+	regmap_write(rt5659->regmap, RT5659_RESET, 0);
+}
+
+#ifdef CONFIG_PM
+static int rt5659_suspend(struct snd_soc_component *component)
+{
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5659->regmap, true);
+	regcache_mark_dirty(rt5659->regmap);
+	return 0;
+}
+
+static int rt5659_resume(struct snd_soc_component *component)
+{
+	struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5659->regmap, false);
+	regcache_sync(rt5659->regmap);
+
+	return 0;
+}
+#else
+#define rt5659_suspend NULL
+#define rt5659_resume NULL
+#endif
+
+#define RT5659_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5659_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5659_aif_dai_ops = {
+	.hw_params = rt5659_hw_params,
+	.set_fmt = rt5659_set_dai_fmt,
+	.set_tdm_slot = rt5659_set_tdm_slot,
+	.set_bclk_ratio = rt5659_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt5659_dai[] = {
+	{
+		.name = "rt5659-aif1",
+		.id = RT5659_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5659_STEREO_RATES,
+			.formats = RT5659_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5659_STEREO_RATES,
+			.formats = RT5659_FORMATS,
+		},
+		.ops = &rt5659_aif_dai_ops,
+	},
+	{
+		.name = "rt5659-aif2",
+		.id = RT5659_AIF2,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5659_STEREO_RATES,
+			.formats = RT5659_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5659_STEREO_RATES,
+			.formats = RT5659_FORMATS,
+		},
+		.ops = &rt5659_aif_dai_ops,
+	},
+	{
+		.name = "rt5659-aif3",
+		.id = RT5659_AIF3,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5659_STEREO_RATES,
+			.formats = RT5659_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF3 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5659_STEREO_RATES,
+			.formats = RT5659_FORMATS,
+		},
+		.ops = &rt5659_aif_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5659 = {
+	.probe			= rt5659_probe,
+	.remove			= rt5659_remove,
+	.suspend		= rt5659_suspend,
+	.resume			= rt5659_resume,
+	.set_bias_level		= rt5659_set_bias_level,
+	.controls		= rt5659_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5659_snd_controls),
+	.dapm_widgets		= rt5659_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5659_dapm_widgets),
+	.dapm_routes		= rt5659_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5659_dapm_routes),
+	.set_sysclk		= rt5659_set_component_sysclk,
+	.set_pll		= rt5659_set_component_pll,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+
+static const struct regmap_config rt5659_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+	.max_register = 0x0400,
+	.volatile_reg = rt5659_volatile_register,
+	.readable_reg = rt5659_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5659_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5659_reg),
+};
+
+static const struct i2c_device_id rt5659_i2c_id[] = {
+	{ "rt5658", 0 },
+	{ "rt5659", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt5659_i2c_id);
+
+static int rt5659_parse_dt(struct rt5659_priv *rt5659, struct device *dev)
+{
+	rt5659->pdata.in1_diff = device_property_read_bool(dev,
+					"realtek,in1-differential");
+	rt5659->pdata.in3_diff = device_property_read_bool(dev,
+					"realtek,in3-differential");
+	rt5659->pdata.in4_diff = device_property_read_bool(dev,
+					"realtek,in4-differential");
+
+
+	device_property_read_u32(dev, "realtek,dmic1-data-pin",
+		&rt5659->pdata.dmic1_data_pin);
+	device_property_read_u32(dev, "realtek,dmic2-data-pin",
+		&rt5659->pdata.dmic2_data_pin);
+	device_property_read_u32(dev, "realtek,jd-src",
+		&rt5659->pdata.jd_src);
+
+	return 0;
+}
+
+static void rt5659_calibrate(struct rt5659_priv *rt5659)
+{
+	int value, count;
+
+	/* Calibrate HPO Start */
+	/* Fine tune HP Performance */
+	regmap_write(rt5659->regmap, RT5659_BIAS_CUR_CTRL_8, 0xa502);
+	regmap_write(rt5659->regmap, RT5659_CHOP_DAC, 0x3030);
+
+	regmap_write(rt5659->regmap, RT5659_PRE_DIV_1, 0xef00);
+	regmap_write(rt5659->regmap, RT5659_PRE_DIV_2, 0xeffc);
+	regmap_write(rt5659->regmap, RT5659_MICBIAS_2, 0x0280);
+	regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x0001);
+	regmap_write(rt5659->regmap, RT5659_GLB_CLK, 0x8000);
+
+	regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xaa7e);
+	msleep(60);
+	regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xfe7e);
+	msleep(50);
+	regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0004);
+	regmap_write(rt5659->regmap, RT5659_PWR_DIG_2, 0x0400);
+	msleep(50);
+	regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0080);
+	usleep_range(10000, 10005);
+	regmap_write(rt5659->regmap, RT5659_DEPOP_1, 0x0009);
+	msleep(50);
+	regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0f80);
+	msleep(50);
+	regmap_write(rt5659->regmap, RT5659_HP_CHARGE_PUMP_1, 0x0e16);
+	msleep(50);
+
+	/* Enalbe K ADC Power And Clock */
+	regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0505);
+	msleep(50);
+	regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0184);
+	regmap_write(rt5659->regmap, RT5659_CALIB_ADC_CTRL, 0x3c05);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c1);
+
+	/* K Headphone */
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x5100);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0014);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0xd100);
+	msleep(60);
+
+	/* Manual K ADC Offset */
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x4900);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0016);
+	regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_1,
+		0x8000, 0x8000);
+
+	count = 0;
+	while (true) {
+		regmap_read(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, &value);
+		if (value & 0x8000)
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (count > 30) {
+			dev_err(rt5659->component->dev,
+				"HP Calibration 1 Failure\n");
+			return;
+		}
+
+		count++;
+	}
+
+	/* Manual K Internal Path Offset */
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1);
+	regmap_write(rt5659->regmap, RT5659_HP_VOL, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x4500);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x001f);
+	regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_1,
+		0x8000, 0x8000);
+
+	count = 0;
+	while (true) {
+		regmap_read(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, &value);
+		if (value & 0x8000)
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (count > 85) {
+			dev_err(rt5659->component->dev,
+				"HP Calibration 2 Failure\n");
+			return;
+		}
+
+		count++;
+	}
+
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c0);
+	/* Calibrate HPO End */
+
+	/* Calibrate SPO Start */
+	regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x2021);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_CTRL_1, 0x0260);
+	regmap_write(rt5659->regmap, RT5659_PWR_MIXER, 0x3000);
+	regmap_write(rt5659->regmap, RT5659_PWR_VOL, 0xc000);
+	regmap_write(rt5659->regmap, RT5659_A_DAC_MUX, 0x000c);
+	regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x8000);
+	regmap_write(rt5659->regmap, RT5659_SPO_VOL, 0x0808);
+	regmap_write(rt5659->regmap, RT5659_SPK_L_MIXER, 0x001e);
+	regmap_write(rt5659->regmap, RT5659_SPK_R_MIXER, 0x001e);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_1, 0x0803);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_2, 0x0554);
+	regmap_write(rt5659->regmap, RT5659_SPO_AMP_GAIN, 0x1103);
+
+	/* Enalbe K ADC Power And Clock */
+	regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0909);
+	regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x0001,
+		0x0001);
+
+	/* Start Calibration */
+	regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x0021);
+	regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_1, 0x3e80);
+	regmap_update_bits(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_1,
+		0x8000, 0x8000);
+
+	count = 0;
+	while (true) {
+		regmap_read(rt5659->regmap,
+				RT5659_SPK_DC_CAILB_CTRL_1, &value);
+		if (value & 0x8000)
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (count > 10) {
+			dev_err(rt5659->component->dev,
+				"SPK Calibration Failure\n");
+			return;
+		}
+
+		count++;
+	}
+	/* Calibrate SPO End */
+
+	/* Calibrate MONO Start */
+	regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_MONOMIX_IN_GAIN, 0x021f);
+	regmap_write(rt5659->regmap, RT5659_MONO_OUT, 0x480a);
+	/* MONO NG2 GAIN 5dB */
+	regmap_write(rt5659->regmap, RT5659_MONO_GAIN, 0x0003);
+	regmap_write(rt5659->regmap, RT5659_MONO_NG2_CTRL_5, 0x0009);
+
+	/* Start Calibration */
+	regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x000f);
+	regmap_write(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e00);
+	regmap_update_bits(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1,
+		0x8000, 0x8000);
+
+	count = 0;
+	while (true) {
+		regmap_read(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1,
+			&value);
+		if (value & 0x8000)
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (count > 35) {
+			dev_err(rt5659->component->dev,
+				"Mono Calibration Failure\n");
+			return;
+		}
+
+		count++;
+	}
+
+	regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x0003);
+	/* Calibrate MONO End */
+
+	/* Power Off */
+	regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0808);
+	regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_CALIB_ADC_CTRL, 0x2005);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c0);
+	regmap_write(rt5659->regmap, RT5659_DEPOP_1, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_1, 0x0011);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_2, 0x0150);
+	regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xfe3e);
+	regmap_write(rt5659->regmap, RT5659_MONO_OUT, 0xc80a);
+	regmap_write(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e04);
+	regmap_write(rt5659->regmap, RT5659_PWR_MIXER, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_PWR_VOL, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_PWR_DIG_2, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0x003e);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_CTRL_1, 0x0060);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x2021);
+	regmap_write(rt5659->regmap, RT5659_GLB_CLK, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_MICBIAS_2, 0x0080);
+	regmap_write(rt5659->regmap, RT5659_HP_VOL, 0x8080);
+	regmap_write(rt5659->regmap, RT5659_HP_CHARGE_PUMP_1, 0x0c16);
+}
+
+static void rt5659_intel_hd_header_probe_setup(struct rt5659_priv *rt5659)
+{
+	int value;
+
+	regmap_read(rt5659->regmap, RT5659_GPIO_STA, &value);
+	if (!(value & 0x8)) {
+		rt5659->hda_hp_plugged = true;
+		regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_1,
+			0x10, 0x0);
+	} else {
+		regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_1,
+			0x10, 0x10);
+	}
+
+	regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+		RT5659_PWR_VREF2 | RT5659_PWR_MB,
+		RT5659_PWR_VREF2 | RT5659_PWR_MB);
+	msleep(20);
+	regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+		RT5659_PWR_FV2, RT5659_PWR_FV2);
+
+	regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_3, RT5659_PWR_LDO2,
+		RT5659_PWR_LDO2);
+	regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_2, RT5659_PWR_MB1,
+		RT5659_PWR_MB1);
+	regmap_update_bits(rt5659->regmap, RT5659_PWR_VOL, RT5659_PWR_MIC_DET,
+		RT5659_PWR_MIC_DET);
+	msleep(20);
+
+	regmap_update_bits(rt5659->regmap, RT5659_4BTN_IL_CMD_2,
+		RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_EN);
+	regmap_read(rt5659->regmap, RT5659_4BTN_IL_CMD_1, &value);
+	regmap_write(rt5659->regmap, RT5659_4BTN_IL_CMD_1, value);
+	regmap_read(rt5659->regmap, RT5659_4BTN_IL_CMD_1, &value);
+
+	if (value & 0x2000) {
+		rt5659->hda_mic_plugged = true;
+		regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_2,
+			0x2, 0x2);
+	} else {
+		regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_2,
+			0x2, 0x0);
+	}
+
+	regmap_update_bits(rt5659->regmap, RT5659_IRQ_CTRL_2,
+		RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_EN);
+}
+
+static int rt5659_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5659_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt5659_priv *rt5659;
+	int ret;
+	unsigned int val;
+
+	rt5659 = devm_kzalloc(&i2c->dev, sizeof(struct rt5659_priv),
+		GFP_KERNEL);
+
+	if (rt5659 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt5659);
+
+	if (pdata)
+		rt5659->pdata = *pdata;
+	else
+		rt5659_parse_dt(rt5659, &i2c->dev);
+
+	rt5659->gpiod_ldo1_en = devm_gpiod_get_optional(&i2c->dev, "ldo1-en",
+							GPIOD_OUT_HIGH);
+	if (IS_ERR(rt5659->gpiod_ldo1_en))
+		dev_warn(&i2c->dev, "Request ldo1-en GPIO failed\n");
+
+	rt5659->gpiod_reset = devm_gpiod_get_optional(&i2c->dev, "reset",
+							GPIOD_OUT_HIGH);
+
+	/* Sleep for 300 ms miniumum */
+	msleep(300);
+
+	rt5659->regmap = devm_regmap_init_i2c(i2c, &rt5659_regmap);
+	if (IS_ERR(rt5659->regmap)) {
+		ret = PTR_ERR(rt5659->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt5659->regmap, RT5659_DEVICE_ID, &val);
+	if (val != DEVICE_ID) {
+		dev_err(&i2c->dev,
+			"Device with ID register %x is not rt5659\n", val);
+		return -ENODEV;
+	}
+
+	regmap_write(rt5659->regmap, RT5659_RESET, 0);
+
+	/* Check if MCLK provided */
+	rt5659->mclk = devm_clk_get(&i2c->dev, "mclk");
+	if (IS_ERR(rt5659->mclk)) {
+		if (PTR_ERR(rt5659->mclk) != -ENOENT)
+			return PTR_ERR(rt5659->mclk);
+		/* Otherwise mark the mclk pointer to NULL */
+		rt5659->mclk = NULL;
+	}
+
+	rt5659_calibrate(rt5659);
+
+	/* line in diff mode*/
+	if (rt5659->pdata.in1_diff)
+		regmap_update_bits(rt5659->regmap, RT5659_IN1_IN2,
+			RT5659_IN1_DF_MASK, RT5659_IN1_DF_MASK);
+	if (rt5659->pdata.in3_diff)
+		regmap_update_bits(rt5659->regmap, RT5659_IN3_IN4,
+			RT5659_IN3_DF_MASK, RT5659_IN3_DF_MASK);
+	if (rt5659->pdata.in4_diff)
+		regmap_update_bits(rt5659->regmap, RT5659_IN3_IN4,
+			RT5659_IN4_DF_MASK, RT5659_IN4_DF_MASK);
+
+	/* DMIC pin*/
+	if (rt5659->pdata.dmic1_data_pin != RT5659_DMIC1_NULL ||
+		rt5659->pdata.dmic2_data_pin != RT5659_DMIC2_NULL) {
+		regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+			RT5659_GP2_PIN_MASK, RT5659_GP2_PIN_DMIC1_SCL);
+
+		switch (rt5659->pdata.dmic1_data_pin) {
+		case RT5659_DMIC1_DATA_IN2N:
+			regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_IN2N);
+			break;
+
+		case RT5659_DMIC1_DATA_GPIO5:
+			regmap_update_bits(rt5659->regmap,
+				RT5659_GPIO_CTRL_3,
+				RT5659_I2S2_PIN_MASK,
+				RT5659_I2S2_PIN_GPIO);
+			regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO5);
+			regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+				RT5659_GP5_PIN_MASK, RT5659_GP5_PIN_DMIC1_SDA);
+			break;
+
+		case RT5659_DMIC1_DATA_GPIO9:
+			regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO9);
+			regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+				RT5659_GP9_PIN_MASK, RT5659_GP9_PIN_DMIC1_SDA);
+			break;
+
+		case RT5659_DMIC1_DATA_GPIO11:
+			regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO11);
+			regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+				RT5659_GP11_PIN_MASK,
+				RT5659_GP11_PIN_DMIC1_SDA);
+			break;
+
+		default:
+			dev_dbg(&i2c->dev, "no DMIC1\n");
+			break;
+		}
+
+		switch (rt5659->pdata.dmic2_data_pin) {
+		case RT5659_DMIC2_DATA_IN2P:
+			regmap_update_bits(rt5659->regmap,
+				RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_2_DP_MASK,
+				RT5659_DMIC_2_DP_IN2P);
+			break;
+
+		case RT5659_DMIC2_DATA_GPIO6:
+			regmap_update_bits(rt5659->regmap,
+				RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_2_DP_MASK,
+				RT5659_DMIC_2_DP_GPIO6);
+			regmap_update_bits(rt5659->regmap,
+				RT5659_GPIO_CTRL_1,
+				RT5659_GP6_PIN_MASK,
+				RT5659_GP6_PIN_DMIC2_SDA);
+			break;
+
+		case RT5659_DMIC2_DATA_GPIO10:
+			regmap_update_bits(rt5659->regmap,
+				RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_2_DP_MASK,
+				RT5659_DMIC_2_DP_GPIO10);
+			regmap_update_bits(rt5659->regmap,
+				RT5659_GPIO_CTRL_1,
+				RT5659_GP10_PIN_MASK,
+				RT5659_GP10_PIN_DMIC2_SDA);
+			break;
+
+		case RT5659_DMIC2_DATA_GPIO12:
+			regmap_update_bits(rt5659->regmap,
+				RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_2_DP_MASK,
+				RT5659_DMIC_2_DP_GPIO12);
+			regmap_update_bits(rt5659->regmap,
+				RT5659_GPIO_CTRL_1,
+				RT5659_GP12_PIN_MASK,
+				RT5659_GP12_PIN_DMIC2_SDA);
+			break;
+
+		default:
+			dev_dbg(&i2c->dev, "no DMIC2\n");
+			break;
+
+		}
+	} else {
+		regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+			RT5659_GP2_PIN_MASK | RT5659_GP5_PIN_MASK |
+			RT5659_GP9_PIN_MASK | RT5659_GP11_PIN_MASK |
+			RT5659_GP6_PIN_MASK | RT5659_GP10_PIN_MASK |
+			RT5659_GP12_PIN_MASK,
+			RT5659_GP2_PIN_GPIO2 | RT5659_GP5_PIN_GPIO5 |
+			RT5659_GP9_PIN_GPIO9 | RT5659_GP11_PIN_GPIO11 |
+			RT5659_GP6_PIN_GPIO6 | RT5659_GP10_PIN_GPIO10 |
+			RT5659_GP12_PIN_GPIO12);
+		regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+			RT5659_DMIC_1_DP_MASK | RT5659_DMIC_2_DP_MASK,
+			RT5659_DMIC_1_DP_IN2N | RT5659_DMIC_2_DP_IN2P);
+	}
+
+	switch (rt5659->pdata.jd_src) {
+	case RT5659_JD3:
+		regmap_write(rt5659->regmap, RT5659_EJD_CTRL_1, 0xa880);
+		regmap_write(rt5659->regmap, RT5659_RC_CLK_CTRL, 0x9000);
+		regmap_write(rt5659->regmap, RT5659_GPIO_CTRL_1, 0xc800);
+		regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+				RT5659_PWR_MB, RT5659_PWR_MB);
+		regmap_write(rt5659->regmap, RT5659_PWR_ANLG_2, 0x0001);
+		regmap_write(rt5659->regmap, RT5659_IRQ_CTRL_2, 0x0040);
+		INIT_DELAYED_WORK(&rt5659->jack_detect_work,
+			rt5659_jack_detect_work);
+		break;
+	case RT5659_JD_HDA_HEADER:
+		regmap_write(rt5659->regmap, RT5659_GPIO_CTRL_3, 0x8000);
+		regmap_write(rt5659->regmap, RT5659_RC_CLK_CTRL, 0x0900);
+		regmap_write(rt5659->regmap, RT5659_EJD_CTRL_1,  0x70c0);
+		regmap_write(rt5659->regmap, RT5659_JD_CTRL_1,   0x2000);
+		regmap_write(rt5659->regmap, RT5659_IRQ_CTRL_1,  0x0040);
+		INIT_DELAYED_WORK(&rt5659->jack_detect_work,
+			rt5659_jack_detect_intel_hd_header);
+		rt5659_intel_hd_header_probe_setup(rt5659);
+		break;
+	default:
+		break;
+	}
+
+	if (i2c->irq) {
+		ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+			rt5659_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+			| IRQF_ONESHOT, "rt5659", rt5659);
+		if (ret)
+			dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+
+		/* Enable IRQ output for GPIO1 pin any way */
+		regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+				   RT5659_GP1_PIN_MASK, RT5659_GP1_PIN_IRQ);
+	}
+
+	return devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_rt5659,
+			rt5659_dai, ARRAY_SIZE(rt5659_dai));
+}
+
+static void rt5659_i2c_shutdown(struct i2c_client *client)
+{
+	struct rt5659_priv *rt5659 = i2c_get_clientdata(client);
+
+	regmap_write(rt5659->regmap, RT5659_RESET, 0);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt5659_of_match[] = {
+	{ .compatible = "realtek,rt5658", },
+	{ .compatible = "realtek,rt5659", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, rt5659_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5659_acpi_match[] = {
+	{ "10EC5658", 0, },
+	{ "10EC5659", 0, },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, rt5659_acpi_match);
+#endif
+
+static struct i2c_driver rt5659_i2c_driver = {
+	.driver = {
+		.name = "rt5659",
+		.of_match_table = of_match_ptr(rt5659_of_match),
+		.acpi_match_table = ACPI_PTR(rt5659_acpi_match),
+	},
+	.probe = rt5659_i2c_probe,
+	.shutdown = rt5659_i2c_shutdown,
+	.id_table = rt5659_i2c_id,
+};
+module_i2c_driver(rt5659_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5659 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5659.h b/sound/soc/codecs/rt5659.h
new file mode 100644
index 0000000..8b576d7
--- /dev/null
+++ b/sound/soc/codecs/rt5659.h
@@ -0,0 +1,1824 @@
+/*
+ * rt5659.h  --  RT5659/RT5658 ALSA SoC audio driver
+ *
+ * Copyright 2015 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5659_H__
+#define __RT5659_H__
+
+#include <sound/rt5659.h>
+
+#define DEVICE_ID 0x6311
+
+/* Info */
+#define RT5659_RESET				0x0000
+#define RT5659_VENDOR_ID			0x00fd
+#define RT5659_VENDOR_ID_1			0x00fe
+#define RT5659_DEVICE_ID			0x00ff
+/*  I/O - Output */
+#define RT5659_SPO_VOL				0x0001
+#define RT5659_HP_VOL				0x0002
+#define RT5659_LOUT				0x0003
+#define RT5659_MONO_OUT				0x0004
+#define RT5659_HPL_GAIN				0x0005
+#define RT5659_HPR_GAIN				0x0006
+#define RT5659_MONO_GAIN			0x0007
+#define RT5659_SPDIF_CTRL_1			0x0008
+#define RT5659_SPDIF_CTRL_2			0x0009
+/* I/O - Input */
+#define RT5659_CAL_BST_CTRL			0x000a
+#define RT5659_IN1_IN2				0x000c
+#define RT5659_IN3_IN4				0x000d
+#define RT5659_INL1_INR1_VOL			0x000f
+/* I/O - Speaker */
+#define RT5659_EJD_CTRL_1			0x0010
+#define RT5659_EJD_CTRL_2			0x0011
+#define RT5659_EJD_CTRL_3			0x0012
+#define RT5659_SILENCE_CTRL			0x0015
+#define RT5659_PSV_CTRL				0x0016
+/* I/O - Sidetone */
+#define RT5659_SIDETONE_CTRL			0x0018
+/* I/O - ADC/DAC/DMIC */
+#define RT5659_DAC1_DIG_VOL			0x0019
+#define RT5659_DAC2_DIG_VOL			0x001a
+#define RT5659_DAC_CTRL				0x001b
+#define RT5659_STO1_ADC_DIG_VOL			0x001c
+#define RT5659_MONO_ADC_DIG_VOL			0x001d
+#define RT5659_STO2_ADC_DIG_VOL			0x001e
+#define RT5659_STO1_BOOST			0x001f
+#define RT5659_MONO_BOOST			0x0020
+#define RT5659_STO2_BOOST			0x0021
+#define RT5659_HP_IMP_GAIN_1			0x0022
+#define RT5659_HP_IMP_GAIN_2			0x0023
+/* Mixer - D-D */
+#define RT5659_STO1_ADC_MIXER			0x0026
+#define RT5659_MONO_ADC_MIXER			0x0027
+#define RT5659_AD_DA_MIXER			0x0029
+#define RT5659_STO_DAC_MIXER			0x002a
+#define RT5659_MONO_DAC_MIXER			0x002b
+#define RT5659_DIG_MIXER			0x002c
+#define RT5659_A_DAC_MUX			0x002d
+#define RT5659_DIG_INF23_DATA			0x002f
+/* Mixer - PDM */
+#define RT5659_PDM_OUT_CTRL			0x0031
+#define RT5659_PDM_DATA_CTRL_1			0x0032
+#define RT5659_PDM_DATA_CTRL_2			0x0033
+#define RT5659_PDM_DATA_CTRL_3			0x0034
+#define RT5659_PDM_DATA_CTRL_4			0x0035
+#define RT5659_SPDIF_CTRL			0x0036
+
+/* Mixer - ADC */
+#define RT5659_REC1_GAIN			0x003a
+#define RT5659_REC1_L1_MIXER			0x003b
+#define RT5659_REC1_L2_MIXER			0x003c
+#define RT5659_REC1_R1_MIXER			0x003d
+#define RT5659_REC1_R2_MIXER			0x003e
+#define RT5659_CAL_REC				0x0040
+#define RT5659_REC2_L1_MIXER			0x009b
+#define RT5659_REC2_L2_MIXER			0x009c
+#define RT5659_REC2_R1_MIXER			0x009d
+#define RT5659_REC2_R2_MIXER			0x009e
+#define RT5659_RC_CLK_CTRL			0x009f
+/* Mixer - DAC */
+#define RT5659_SPK_L_MIXER			0x0046
+#define RT5659_SPK_R_MIXER			0x0047
+#define RT5659_SPO_AMP_GAIN			0x0048
+#define RT5659_ALC_BACK_GAIN			0x0049
+#define RT5659_MONOMIX_GAIN			0x004a
+#define RT5659_MONOMIX_IN_GAIN			0x004b
+#define RT5659_OUT_L_GAIN			0x004d
+#define RT5659_OUT_L_MIXER			0x004e
+#define RT5659_OUT_R_GAIN			0x004f
+#define RT5659_OUT_R_MIXER			0x0050
+#define RT5659_LOUT_MIXER			0x0052
+
+#define RT5659_HAPTIC_GEN_CTRL_1		0x0053
+#define RT5659_HAPTIC_GEN_CTRL_2		0x0054
+#define RT5659_HAPTIC_GEN_CTRL_3		0x0055
+#define RT5659_HAPTIC_GEN_CTRL_4		0x0056
+#define RT5659_HAPTIC_GEN_CTRL_5		0x0057
+#define RT5659_HAPTIC_GEN_CTRL_6		0x0058
+#define RT5659_HAPTIC_GEN_CTRL_7		0x0059
+#define RT5659_HAPTIC_GEN_CTRL_8		0x005a
+#define RT5659_HAPTIC_GEN_CTRL_9		0x005b
+#define RT5659_HAPTIC_GEN_CTRL_10		0x005c
+#define RT5659_HAPTIC_GEN_CTRL_11		0x005d
+#define RT5659_HAPTIC_LPF_CTRL_1		0x005e
+#define RT5659_HAPTIC_LPF_CTRL_2		0x005f
+#define RT5659_HAPTIC_LPF_CTRL_3		0x0060
+/* Power */
+#define RT5659_PWR_DIG_1			0x0061
+#define RT5659_PWR_DIG_2			0x0062
+#define RT5659_PWR_ANLG_1			0x0063
+#define RT5659_PWR_ANLG_2			0x0064
+#define RT5659_PWR_ANLG_3			0x0065
+#define RT5659_PWR_MIXER			0x0066
+#define RT5659_PWR_VOL				0x0067
+/* Private Register Control */
+#define RT5659_PRIV_INDEX			0x006a
+#define RT5659_CLK_DET				0x006b
+#define RT5659_PRIV_DATA			0x006c
+/* System Clock Pre Divider Gating Control */
+#define RT5659_PRE_DIV_1			0x006e
+#define RT5659_PRE_DIV_2			0x006f
+/* Format - ADC/DAC */
+#define RT5659_I2S1_SDP				0x0070
+#define RT5659_I2S2_SDP				0x0071
+#define RT5659_I2S3_SDP				0x0072
+#define RT5659_ADDA_CLK_1			0x0073
+#define RT5659_ADDA_CLK_2			0x0074
+#define RT5659_DMIC_CTRL_1			0x0075
+#define RT5659_DMIC_CTRL_2			0x0076
+/* Format - TDM Control */
+#define RT5659_TDM_CTRL_1			0x0077
+#define RT5659_TDM_CTRL_2			0x0078
+#define RT5659_TDM_CTRL_3			0x0079
+#define RT5659_TDM_CTRL_4			0x007a
+#define RT5659_TDM_CTRL_5			0x007b
+
+/* Function - Analog */
+#define RT5659_GLB_CLK				0x0080
+#define RT5659_PLL_CTRL_1			0x0081
+#define RT5659_PLL_CTRL_2			0x0082
+#define RT5659_ASRC_1				0x0083
+#define RT5659_ASRC_2				0x0084
+#define RT5659_ASRC_3				0x0085
+#define RT5659_ASRC_4				0x0086
+#define RT5659_ASRC_5				0x0087
+#define RT5659_ASRC_6				0x0088
+#define RT5659_ASRC_7				0x0089
+#define RT5659_ASRC_8				0x008a
+#define RT5659_ASRC_9				0x008b
+#define RT5659_ASRC_10				0x008c
+#define RT5659_DEPOP_1				0x008e
+#define RT5659_DEPOP_2				0x008f
+#define RT5659_DEPOP_3				0x0090
+#define RT5659_HP_CHARGE_PUMP_1			0x0091
+#define RT5659_HP_CHARGE_PUMP_2			0x0092
+#define RT5659_MICBIAS_1			0x0093
+#define RT5659_MICBIAS_2			0x0094
+#define RT5659_ASRC_11				0x0097
+#define RT5659_ASRC_12				0x0098
+#define RT5659_ASRC_13				0x0099
+#define RT5659_REC_M1_M2_GAIN_CTRL		0x009a
+#define RT5659_CLASSD_CTRL_1			0x00a0
+#define RT5659_CLASSD_CTRL_2			0x00a1
+
+/* Function - Digital */
+#define RT5659_ADC_EQ_CTRL_1			0x00ae
+#define RT5659_ADC_EQ_CTRL_2			0x00af
+#define RT5659_DAC_EQ_CTRL_1			0x00b0
+#define RT5659_DAC_EQ_CTRL_2			0x00b1
+#define RT5659_DAC_EQ_CTRL_3			0x00b2
+
+#define RT5659_IRQ_CTRL_1			0x00b6
+#define RT5659_IRQ_CTRL_2			0x00b7
+#define RT5659_IRQ_CTRL_3			0x00b8
+#define RT5659_IRQ_CTRL_4			0x00ba
+#define RT5659_IRQ_CTRL_5			0x00bb
+#define RT5659_IRQ_CTRL_6			0x00bc
+#define RT5659_INT_ST_1				0x00be
+#define RT5659_INT_ST_2				0x00bf
+#define RT5659_GPIO_CTRL_1			0x00c0
+#define RT5659_GPIO_CTRL_2			0x00c1
+#define RT5659_GPIO_CTRL_3			0x00c2
+#define RT5659_GPIO_CTRL_4			0x00c3
+#define RT5659_GPIO_CTRL_5			0x00c4
+#define RT5659_GPIO_STA				0x00c5
+#define RT5659_SINE_GEN_CTRL_1			0x00cb
+#define RT5659_SINE_GEN_CTRL_2			0x00cc
+#define RT5659_SINE_GEN_CTRL_3			0x00cd
+#define RT5659_HP_AMP_DET_CTRL_1		0x00d6
+#define RT5659_HP_AMP_DET_CTRL_2		0x00d7
+#define RT5659_SV_ZCD_1				0x00d9
+#define RT5659_SV_ZCD_2				0x00da
+#define RT5659_IL_CMD_1				0x00db
+#define RT5659_IL_CMD_2				0x00dc
+#define RT5659_IL_CMD_3				0x00dd
+#define RT5659_IL_CMD_4				0x00de
+#define RT5659_4BTN_IL_CMD_1			0x00df
+#define RT5659_4BTN_IL_CMD_2			0x00e0
+#define RT5659_4BTN_IL_CMD_3			0x00e1
+#define RT5659_PSV_IL_CMD_1			0x00e4
+#define RT5659_PSV_IL_CMD_2			0x00e5
+
+#define RT5659_ADC_STO1_HP_CTRL_1		0x00ea
+#define RT5659_ADC_STO1_HP_CTRL_2		0x00eb
+#define RT5659_ADC_MONO_HP_CTRL_1		0x00ec
+#define RT5659_ADC_MONO_HP_CTRL_2		0x00ed
+#define RT5659_AJD1_CTRL			0x00f0
+#define RT5659_AJD2_AJD3_CTRL			0x00f1
+#define RT5659_JD1_THD				0x00f2
+#define RT5659_JD2_THD				0x00f3
+#define RT5659_JD3_THD				0x00f4
+#define RT5659_JD_CTRL_1			0x00f6
+#define RT5659_JD_CTRL_2			0x00f7
+#define RT5659_JD_CTRL_3			0x00f8
+#define RT5659_JD_CTRL_4			0x00f9
+/* General Control */
+#define RT5659_DIG_MISC				0x00fa
+#define RT5659_DUMMY_2				0x00fb
+#define RT5659_DUMMY_3				0x00fc
+
+#define RT5659_DAC_ADC_DIG_VOL			0x0100
+#define RT5659_BIAS_CUR_CTRL_1			0x010a
+#define RT5659_BIAS_CUR_CTRL_2			0x010b
+#define RT5659_BIAS_CUR_CTRL_3			0x010c
+#define RT5659_BIAS_CUR_CTRL_4			0x010d
+#define RT5659_BIAS_CUR_CTRL_5			0x010e
+#define RT5659_BIAS_CUR_CTRL_6			0x010f
+#define RT5659_BIAS_CUR_CTRL_7			0x0110
+#define RT5659_BIAS_CUR_CTRL_8			0x0111
+#define RT5659_BIAS_CUR_CTRL_9			0x0112
+#define RT5659_BIAS_CUR_CTRL_10			0x0113
+#define RT5659_MEMORY_TEST			0x0116
+#define RT5659_VREF_REC_OP_FB_CAP_CTRL		0x0117
+#define RT5659_CLASSD_0				0x011a
+#define RT5659_CLASSD_1				0x011b
+#define RT5659_CLASSD_2				0x011c
+#define RT5659_CLASSD_3				0x011d
+#define RT5659_CLASSD_4				0x011e
+#define RT5659_CLASSD_5				0x011f
+#define RT5659_CLASSD_6				0x0120
+#define RT5659_CLASSD_7				0x0121
+#define RT5659_CLASSD_8				0x0122
+#define RT5659_CLASSD_9				0x0123
+#define RT5659_CLASSD_10			0x0124
+#define RT5659_CHARGE_PUMP_1			0x0125
+#define RT5659_CHARGE_PUMP_2			0x0126
+#define RT5659_DIG_IN_CTRL_1			0x0132
+#define RT5659_DIG_IN_CTRL_2			0x0133
+#define RT5659_PAD_DRIVING_CTRL			0x0137
+#define RT5659_SOFT_RAMP_DEPOP			0x0138
+#define RT5659_PLL				0x0139
+#define RT5659_CHOP_DAC				0x013a
+#define RT5659_CHOP_ADC				0x013b
+#define RT5659_CALIB_ADC_CTRL			0x013c
+#define RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL	0x013e
+#define RT5659_VOL_TEST				0x013f
+#define RT5659_TEST_MODE_CTRL_1			0x0145
+#define RT5659_TEST_MODE_CTRL_2			0x0146
+#define RT5659_TEST_MODE_CTRL_3			0x0147
+#define RT5659_TEST_MODE_CTRL_4			0x0148
+#define RT5659_BASSBACK_CTRL			0x0150
+#define RT5659_MP3_PLUS_CTRL_1			0x0151
+#define RT5659_MP3_PLUS_CTRL_2			0x0152
+#define RT5659_MP3_HPF_A1			0x0153
+#define RT5659_MP3_HPF_A2			0x0154
+#define RT5659_MP3_HPF_H0			0x0155
+#define RT5659_MP3_LPF_H0			0x0156
+#define RT5659_3D_SPK_CTRL			0x0157
+#define RT5659_3D_SPK_COEF_1			0x0158
+#define RT5659_3D_SPK_COEF_2			0x0159
+#define RT5659_3D_SPK_COEF_3			0x015a
+#define RT5659_3D_SPK_COEF_4			0x015b
+#define RT5659_3D_SPK_COEF_5			0x015c
+#define RT5659_3D_SPK_COEF_6			0x015d
+#define RT5659_3D_SPK_COEF_7			0x015e
+#define RT5659_STO_NG2_CTRL_1			0x0160
+#define RT5659_STO_NG2_CTRL_2			0x0161
+#define RT5659_STO_NG2_CTRL_3			0x0162
+#define RT5659_STO_NG2_CTRL_4			0x0163
+#define RT5659_STO_NG2_CTRL_5			0x0164
+#define RT5659_STO_NG2_CTRL_6			0x0165
+#define RT5659_STO_NG2_CTRL_7			0x0166
+#define RT5659_STO_NG2_CTRL_8			0x0167
+#define RT5659_MONO_NG2_CTRL_1			0x0170
+#define RT5659_MONO_NG2_CTRL_2			0x0171
+#define RT5659_MONO_NG2_CTRL_3			0x0172
+#define RT5659_MONO_NG2_CTRL_4			0x0173
+#define RT5659_MONO_NG2_CTRL_5			0x0174
+#define RT5659_MONO_NG2_CTRL_6			0x0175
+#define RT5659_MID_HP_AMP_DET			0x0190
+#define RT5659_LOW_HP_AMP_DET			0x0191
+#define RT5659_LDO_CTRL				0x0192
+#define RT5659_HP_DECROSS_CTRL_1		0x01b0
+#define RT5659_HP_DECROSS_CTRL_2		0x01b1
+#define RT5659_HP_DECROSS_CTRL_3		0x01b2
+#define RT5659_HP_DECROSS_CTRL_4		0x01b3
+#define RT5659_HP_IMP_SENS_CTRL_1		0x01c0
+#define RT5659_HP_IMP_SENS_CTRL_2		0x01c1
+#define RT5659_HP_IMP_SENS_CTRL_3		0x01c2
+#define RT5659_HP_IMP_SENS_CTRL_4		0x01c3
+#define RT5659_HP_IMP_SENS_MAP_1		0x01c7
+#define RT5659_HP_IMP_SENS_MAP_2		0x01c8
+#define RT5659_HP_IMP_SENS_MAP_3		0x01c9
+#define RT5659_HP_IMP_SENS_MAP_4		0x01ca
+#define RT5659_HP_IMP_SENS_MAP_5		0x01cb
+#define RT5659_HP_IMP_SENS_MAP_6		0x01cc
+#define RT5659_HP_IMP_SENS_MAP_7		0x01cd
+#define RT5659_HP_IMP_SENS_MAP_8		0x01ce
+#define RT5659_HP_LOGIC_CTRL_1			0x01da
+#define RT5659_HP_LOGIC_CTRL_2			0x01db
+#define RT5659_HP_CALIB_CTRL_1			0x01de
+#define RT5659_HP_CALIB_CTRL_2			0x01df
+#define RT5659_HP_CALIB_CTRL_3			0x01e0
+#define RT5659_HP_CALIB_CTRL_4			0x01e1
+#define RT5659_HP_CALIB_CTRL_5			0x01e2
+#define RT5659_HP_CALIB_CTRL_6			0x01e3
+#define RT5659_HP_CALIB_CTRL_7			0x01e4
+#define RT5659_HP_CALIB_CTRL_9			0x01e6
+#define RT5659_HP_CALIB_CTRL_10			0x01e7
+#define RT5659_HP_CALIB_CTRL_11			0x01e8
+#define RT5659_HP_CALIB_STA_1			0x01ea
+#define RT5659_HP_CALIB_STA_2			0x01eb
+#define RT5659_HP_CALIB_STA_3			0x01ec
+#define RT5659_HP_CALIB_STA_4			0x01ed
+#define RT5659_HP_CALIB_STA_5			0x01ee
+#define RT5659_HP_CALIB_STA_6			0x01ef
+#define RT5659_HP_CALIB_STA_7			0x01f0
+#define RT5659_HP_CALIB_STA_8			0x01f1
+#define RT5659_HP_CALIB_STA_9			0x01f2
+#define RT5659_MONO_AMP_CALIB_CTRL_1		0x01f6
+#define RT5659_MONO_AMP_CALIB_CTRL_2		0x01f7
+#define RT5659_MONO_AMP_CALIB_CTRL_3		0x01f8
+#define RT5659_MONO_AMP_CALIB_CTRL_4		0x01f9
+#define RT5659_MONO_AMP_CALIB_CTRL_5		0x01fa
+#define RT5659_MONO_AMP_CALIB_STA_1		0x01fb
+#define RT5659_MONO_AMP_CALIB_STA_2		0x01fc
+#define RT5659_MONO_AMP_CALIB_STA_3		0x01fd
+#define RT5659_MONO_AMP_CALIB_STA_4		0x01fe
+#define RT5659_SPK_PWR_LMT_CTRL_1		0x0200
+#define RT5659_SPK_PWR_LMT_CTRL_2		0x0201
+#define RT5659_SPK_PWR_LMT_CTRL_3		0x0202
+#define RT5659_SPK_PWR_LMT_STA_1		0x0203
+#define RT5659_SPK_PWR_LMT_STA_2		0x0204
+#define RT5659_SPK_PWR_LMT_STA_3		0x0205
+#define RT5659_SPK_PWR_LMT_STA_4		0x0206
+#define RT5659_SPK_PWR_LMT_STA_5		0x0207
+#define RT5659_SPK_PWR_LMT_STA_6		0x0208
+#define RT5659_FLEX_SPK_BST_CTRL_1		0x0256
+#define RT5659_FLEX_SPK_BST_CTRL_2		0x0257
+#define RT5659_FLEX_SPK_BST_CTRL_3		0x0258
+#define RT5659_FLEX_SPK_BST_CTRL_4		0x0259
+#define RT5659_SPK_EX_LMT_CTRL_1		0x025a
+#define RT5659_SPK_EX_LMT_CTRL_2		0x025b
+#define RT5659_SPK_EX_LMT_CTRL_3		0x025c
+#define RT5659_SPK_EX_LMT_CTRL_4		0x025d
+#define RT5659_SPK_EX_LMT_CTRL_5		0x025e
+#define RT5659_SPK_EX_LMT_CTRL_6		0x025f
+#define RT5659_SPK_EX_LMT_CTRL_7		0x0260
+#define RT5659_ADJ_HPF_CTRL_1			0x0261
+#define RT5659_ADJ_HPF_CTRL_2			0x0262
+#define RT5659_SPK_DC_CAILB_CTRL_1		0x0265
+#define RT5659_SPK_DC_CAILB_CTRL_2		0x0266
+#define RT5659_SPK_DC_CAILB_CTRL_3		0x0267
+#define RT5659_SPK_DC_CAILB_CTRL_4		0x0268
+#define RT5659_SPK_DC_CAILB_CTRL_5		0x0269
+#define RT5659_SPK_DC_CAILB_STA_1		0x026a
+#define RT5659_SPK_DC_CAILB_STA_2		0x026b
+#define RT5659_SPK_DC_CAILB_STA_3		0x026c
+#define RT5659_SPK_DC_CAILB_STA_4		0x026d
+#define RT5659_SPK_DC_CAILB_STA_5		0x026e
+#define RT5659_SPK_DC_CAILB_STA_6		0x026f
+#define RT5659_SPK_DC_CAILB_STA_7		0x0270
+#define RT5659_SPK_DC_CAILB_STA_8		0x0271
+#define RT5659_SPK_DC_CAILB_STA_9		0x0272
+#define RT5659_SPK_DC_CAILB_STA_10		0x0273
+#define RT5659_SPK_VDD_STA_1			0x0280
+#define RT5659_SPK_VDD_STA_2			0x0281
+#define RT5659_SPK_DC_DET_CTRL_1		0x0282
+#define RT5659_SPK_DC_DET_CTRL_2		0x0283
+#define RT5659_SPK_DC_DET_CTRL_3		0x0284
+#define RT5659_PURE_DC_DET_CTRL_1		0x0290
+#define RT5659_PURE_DC_DET_CTRL_2		0x0291
+#define RT5659_DUMMY_4				0x02fa
+#define RT5659_DUMMY_5				0x02fb
+#define RT5659_DUMMY_6				0x02fc
+#define RT5659_DRC1_CTRL_1			0x0300
+#define RT5659_DRC1_CTRL_2			0x0301
+#define RT5659_DRC1_CTRL_3			0x0302
+#define RT5659_DRC1_CTRL_4			0x0303
+#define RT5659_DRC1_CTRL_5			0x0304
+#define RT5659_DRC1_CTRL_6			0x0305
+#define RT5659_DRC1_HARD_LMT_CTRL_1		0x0306
+#define RT5659_DRC1_HARD_LMT_CTRL_2		0x0307
+#define RT5659_DRC2_CTRL_1			0x0308
+#define RT5659_DRC2_CTRL_2			0x0309
+#define RT5659_DRC2_CTRL_3			0x030a
+#define RT5659_DRC2_CTRL_4			0x030b
+#define RT5659_DRC2_CTRL_5			0x030c
+#define RT5659_DRC2_CTRL_6			0x030d
+#define RT5659_DRC2_HARD_LMT_CTRL_1		0x030e
+#define RT5659_DRC2_HARD_LMT_CTRL_2		0x030f
+#define RT5659_DRC1_PRIV_1			0x0310
+#define RT5659_DRC1_PRIV_2			0x0311
+#define RT5659_DRC1_PRIV_3			0x0312
+#define RT5659_DRC1_PRIV_4			0x0313
+#define RT5659_DRC1_PRIV_5			0x0314
+#define RT5659_DRC1_PRIV_6			0x0315
+#define RT5659_DRC1_PRIV_7			0x0316
+#define RT5659_DRC2_PRIV_1			0x0317
+#define RT5659_DRC2_PRIV_2			0x0318
+#define RT5659_DRC2_PRIV_3			0x0319
+#define RT5659_DRC2_PRIV_4			0x031a
+#define RT5659_DRC2_PRIV_5			0x031b
+#define RT5659_DRC2_PRIV_6			0x031c
+#define RT5659_DRC2_PRIV_7			0x031d
+#define RT5659_MULTI_DRC_CTRL			0x0320
+#define RT5659_CROSS_OVER_1			0x0321
+#define RT5659_CROSS_OVER_2			0x0322
+#define RT5659_CROSS_OVER_3			0x0323
+#define RT5659_CROSS_OVER_4			0x0324
+#define RT5659_CROSS_OVER_5			0x0325
+#define RT5659_CROSS_OVER_6			0x0326
+#define RT5659_CROSS_OVER_7			0x0327
+#define RT5659_CROSS_OVER_8			0x0328
+#define RT5659_CROSS_OVER_9			0x0329
+#define RT5659_CROSS_OVER_10			0x032a
+#define RT5659_ALC_PGA_CTRL_1			0x0330
+#define RT5659_ALC_PGA_CTRL_2			0x0331
+#define RT5659_ALC_PGA_CTRL_3			0x0332
+#define RT5659_ALC_PGA_CTRL_4			0x0333
+#define RT5659_ALC_PGA_CTRL_5			0x0334
+#define RT5659_ALC_PGA_CTRL_6			0x0335
+#define RT5659_ALC_PGA_CTRL_7			0x0336
+#define RT5659_ALC_PGA_CTRL_8			0x0337
+#define RT5659_ALC_PGA_STA_1			0x0338
+#define RT5659_ALC_PGA_STA_2			0x0339
+#define RT5659_ALC_PGA_STA_3			0x033a
+#define RT5659_DAC_L_EQ_PRE_VOL			0x0340
+#define RT5659_DAC_R_EQ_PRE_VOL			0x0341
+#define RT5659_DAC_L_EQ_POST_VOL		0x0342
+#define RT5659_DAC_R_EQ_POST_VOL		0x0343
+#define RT5659_DAC_L_EQ_LPF1_A1			0x0344
+#define RT5659_DAC_L_EQ_LPF1_H0			0x0345
+#define RT5659_DAC_R_EQ_LPF1_A1			0x0346
+#define RT5659_DAC_R_EQ_LPF1_H0			0x0347
+#define RT5659_DAC_L_EQ_BPF2_A1			0x0348
+#define RT5659_DAC_L_EQ_BPF2_A2			0x0349
+#define RT5659_DAC_L_EQ_BPF2_H0			0x034a
+#define RT5659_DAC_R_EQ_BPF2_A1			0x034b
+#define RT5659_DAC_R_EQ_BPF2_A2			0x034c
+#define RT5659_DAC_R_EQ_BPF2_H0			0x034d
+#define RT5659_DAC_L_EQ_BPF3_A1			0x034e
+#define RT5659_DAC_L_EQ_BPF3_A2			0x034f
+#define RT5659_DAC_L_EQ_BPF3_H0			0x0350
+#define RT5659_DAC_R_EQ_BPF3_A1			0x0351
+#define RT5659_DAC_R_EQ_BPF3_A2			0x0352
+#define RT5659_DAC_R_EQ_BPF3_H0			0x0353
+#define RT5659_DAC_L_EQ_BPF4_A1			0x0354
+#define RT5659_DAC_L_EQ_BPF4_A2			0x0355
+#define RT5659_DAC_L_EQ_BPF4_H0			0x0356
+#define RT5659_DAC_R_EQ_BPF4_A1			0x0357
+#define RT5659_DAC_R_EQ_BPF4_A2			0x0358
+#define RT5659_DAC_R_EQ_BPF4_H0			0x0359
+#define RT5659_DAC_L_EQ_HPF1_A1			0x035a
+#define RT5659_DAC_L_EQ_HPF1_H0			0x035b
+#define RT5659_DAC_R_EQ_HPF1_A1			0x035c
+#define RT5659_DAC_R_EQ_HPF1_H0			0x035d
+#define RT5659_DAC_L_EQ_HPF2_A1			0x035e
+#define RT5659_DAC_L_EQ_HPF2_A2			0x035f
+#define RT5659_DAC_L_EQ_HPF2_H0			0x0360
+#define RT5659_DAC_R_EQ_HPF2_A1			0x0361
+#define RT5659_DAC_R_EQ_HPF2_A2			0x0362
+#define RT5659_DAC_R_EQ_HPF2_H0			0x0363
+#define RT5659_DAC_L_BI_EQ_BPF1_H0_1		0x0364
+#define RT5659_DAC_L_BI_EQ_BPF1_H0_2		0x0365
+#define RT5659_DAC_L_BI_EQ_BPF1_B1_1		0x0366
+#define RT5659_DAC_L_BI_EQ_BPF1_B1_2		0x0367
+#define RT5659_DAC_L_BI_EQ_BPF1_B2_1		0x0368
+#define RT5659_DAC_L_BI_EQ_BPF1_B2_2		0x0369
+#define RT5659_DAC_L_BI_EQ_BPF1_A1_1		0x036a
+#define RT5659_DAC_L_BI_EQ_BPF1_A1_2		0x036b
+#define RT5659_DAC_L_BI_EQ_BPF1_A2_1		0x036c
+#define RT5659_DAC_L_BI_EQ_BPF1_A2_2		0x036d
+#define RT5659_DAC_R_BI_EQ_BPF1_H0_1		0x036e
+#define RT5659_DAC_R_BI_EQ_BPF1_H0_2		0x036f
+#define RT5659_DAC_R_BI_EQ_BPF1_B1_1		0x0370
+#define RT5659_DAC_R_BI_EQ_BPF1_B1_2		0x0371
+#define RT5659_DAC_R_BI_EQ_BPF1_B2_1		0x0372
+#define RT5659_DAC_R_BI_EQ_BPF1_B2_2		0x0373
+#define RT5659_DAC_R_BI_EQ_BPF1_A1_1		0x0374
+#define RT5659_DAC_R_BI_EQ_BPF1_A1_2		0x0375
+#define RT5659_DAC_R_BI_EQ_BPF1_A2_1		0x0376
+#define RT5659_DAC_R_BI_EQ_BPF1_A2_2		0x0377
+#define RT5659_ADC_L_EQ_LPF1_A1			0x03d0
+#define RT5659_ADC_R_EQ_LPF1_A1			0x03d1
+#define RT5659_ADC_L_EQ_LPF1_H0			0x03d2
+#define RT5659_ADC_R_EQ_LPF1_H0			0x03d3
+#define RT5659_ADC_L_EQ_BPF1_A1			0x03d4
+#define RT5659_ADC_R_EQ_BPF1_A1			0x03d5
+#define RT5659_ADC_L_EQ_BPF1_A2			0x03d6
+#define RT5659_ADC_R_EQ_BPF1_A2			0x03d7
+#define RT5659_ADC_L_EQ_BPF1_H0			0x03d8
+#define RT5659_ADC_R_EQ_BPF1_H0			0x03d9
+#define RT5659_ADC_L_EQ_BPF2_A1			0x03da
+#define RT5659_ADC_R_EQ_BPF2_A1			0x03db
+#define RT5659_ADC_L_EQ_BPF2_A2			0x03dc
+#define RT5659_ADC_R_EQ_BPF2_A2			0x03dd
+#define RT5659_ADC_L_EQ_BPF2_H0			0x03de
+#define RT5659_ADC_R_EQ_BPF2_H0			0x03df
+#define RT5659_ADC_L_EQ_BPF3_A1			0x03e0
+#define RT5659_ADC_R_EQ_BPF3_A1			0x03e1
+#define RT5659_ADC_L_EQ_BPF3_A2			0x03e2
+#define RT5659_ADC_R_EQ_BPF3_A2			0x03e3
+#define RT5659_ADC_L_EQ_BPF3_H0			0x03e4
+#define RT5659_ADC_R_EQ_BPF3_H0			0x03e5
+#define RT5659_ADC_L_EQ_BPF4_A1			0x03e6
+#define RT5659_ADC_R_EQ_BPF4_A1			0x03e7
+#define RT5659_ADC_L_EQ_BPF4_A2			0x03e8
+#define RT5659_ADC_R_EQ_BPF4_A2			0x03e9
+#define RT5659_ADC_L_EQ_BPF4_H0			0x03ea
+#define RT5659_ADC_R_EQ_BPF4_H0			0x03eb
+#define RT5659_ADC_L_EQ_HPF1_A1			0x03ec
+#define RT5659_ADC_R_EQ_HPF1_A1			0x03ed
+#define RT5659_ADC_L_EQ_HPF1_H0			0x03ee
+#define RT5659_ADC_R_EQ_HPF1_H0			0x03ef
+#define RT5659_ADC_L_EQ_PRE_VOL			0x03f0
+#define RT5659_ADC_R_EQ_PRE_VOL			0x03f1
+#define RT5659_ADC_L_EQ_POST_VOL		0x03f2
+#define RT5659_ADC_R_EQ_POST_VOL		0x03f3
+
+
+
+/* global definition */
+#define RT5659_L_MUTE				(0x1 << 15)
+#define RT5659_L_MUTE_SFT			15
+#define RT5659_VOL_L_MUTE			(0x1 << 14)
+#define RT5659_VOL_L_SFT			14
+#define RT5659_R_MUTE				(0x1 << 7)
+#define RT5659_R_MUTE_SFT			7
+#define RT5659_VOL_R_MUTE			(0x1 << 6)
+#define RT5659_VOL_R_SFT			6
+#define RT5659_L_VOL_MASK			(0x3f << 8)
+#define RT5659_L_VOL_SFT			8
+#define RT5659_R_VOL_MASK			(0x3f)
+#define RT5659_R_VOL_SFT			0
+
+/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/
+#define RT5659_G_HP				(0x1f << 8)
+#define RT5659_G_HP_SFT				8
+#define RT5659_G_STO_DA_DMIX			(0x1f)
+#define RT5659_G_STO_DA_SFT			0
+
+/* IN1/IN2 Control (0x000c) */
+#define RT5659_IN1_DF_MASK			(0x1 << 15)
+#define RT5659_IN1_DF				15
+#define RT5659_BST1_MASK			(0x7f << 8)
+#define RT5659_BST1_SFT				8
+#define RT5659_BST2_MASK			(0x7f)
+#define RT5659_BST2_SFT				0
+
+/* IN3/IN4 Control (0x000d) */
+#define RT5659_IN3_DF_MASK			(0x1 << 15)
+#define RT5659_IN3_DF				15
+#define RT5659_BST3_MASK			(0x7f << 8)
+#define RT5659_BST3_SFT				8
+#define RT5659_IN4_DF_MASK			(0x1 << 7)
+#define RT5659_IN4_DF				7
+#define RT5659_BST4_MASK			(0x7f)
+#define RT5659_BST4_SFT				0
+
+/* INL and INR Volume Control (0x000f) */
+#define RT5659_INL_VOL_MASK			(0x1f << 8)
+#define RT5659_INL_VOL_SFT			8
+#define RT5659_INR_VOL_MASK			(0x1f)
+#define RT5659_INR_VOL_SFT			0
+
+/* Embeeded Jack and Type Detection Control 1 (0x0010) */
+#define RT5659_EMB_JD_EN			(0x1 << 15)
+#define RT5659_EMB_JD_EN_SFT			15
+#define RT5659_JD_MODE				(0x1 << 13)
+#define RT5659_JD_MODE_SFT			13
+#define RT5659_EXT_JD_EN			(0x1 << 11)
+#define RT5659_EXT_JD_EN_SFT			11
+#define RT5659_EXT_JD_DIG			(0x1 << 9)
+
+/* Embeeded Jack and Type Detection Control 2 (0x0011) */
+#define RT5659_EXT_JD_SRC			(0x7 << 4)
+#define RT5659_EXT_JD_SRC_SFT			4
+#define RT5659_EXT_JD_SRC_GPIO_JD1		(0x0 << 4)
+#define RT5659_EXT_JD_SRC_GPIO_JD2		(0x1 << 4)
+#define RT5659_EXT_JD_SRC_JD1_1			(0x2 << 4)
+#define RT5659_EXT_JD_SRC_JD1_2			(0x3 << 4)
+#define RT5659_EXT_JD_SRC_JD2			(0x4 << 4)
+#define RT5659_EXT_JD_SRC_JD3			(0x5 << 4)
+#define RT5659_EXT_JD_SRC_MANUAL		(0x6 << 4)
+
+/* Slience Detection Control (0x0015) */
+#define RT5659_SIL_DET_MASK			(0x1 << 15)
+#define RT5659_SIL_DET_DIS			(0x0 << 15)
+#define RT5659_SIL_DET_EN			(0x1 << 15)
+
+/* Sidetone Control (0x0018) */
+#define RT5659_ST_SEL_MASK			(0x7 << 9)
+#define RT5659_ST_SEL_SFT			9
+#define RT5659_ST_EN				(0x1 << 6)
+#define RT5659_ST_EN_SFT			6
+
+/* DAC1 Digital Volume (0x0019) */
+#define RT5659_DAC_L1_VOL_MASK			(0xff << 8)
+#define RT5659_DAC_L1_VOL_SFT			8
+#define RT5659_DAC_R1_VOL_MASK			(0xff)
+#define RT5659_DAC_R1_VOL_SFT			0
+
+/* DAC2 Digital Volume (0x001a) */
+#define RT5659_DAC_L2_VOL_MASK			(0xff << 8)
+#define RT5659_DAC_L2_VOL_SFT			8
+#define RT5659_DAC_R2_VOL_MASK			(0xff)
+#define RT5659_DAC_R2_VOL_SFT			0
+
+/* DAC2 Control (0x001b) */
+#define RT5659_M_DAC2_L_VOL			(0x1 << 13)
+#define RT5659_M_DAC2_L_VOL_SFT			13
+#define RT5659_M_DAC2_R_VOL			(0x1 << 12)
+#define RT5659_M_DAC2_R_VOL_SFT			12
+#define RT5659_DAC_L2_SEL_MASK			(0x7 << 4)
+#define RT5659_DAC_L2_SEL_SFT			4
+#define RT5659_DAC_R2_SEL_MASK			(0x7 << 0)
+#define RT5659_DAC_R2_SEL_SFT			0
+
+/* ADC Digital Volume Control (0x001c) */
+#define RT5659_ADC_L_VOL_MASK			(0x7f << 8)
+#define RT5659_ADC_L_VOL_SFT			8
+#define RT5659_ADC_R_VOL_MASK			(0x7f)
+#define RT5659_ADC_R_VOL_SFT			0
+
+/* Mono ADC Digital Volume Control (0x001d) */
+#define RT5659_MONO_ADC_L_VOL_MASK		(0x7f << 8)
+#define RT5659_MONO_ADC_L_VOL_SFT		8
+#define RT5659_MONO_ADC_R_VOL_MASK		(0x7f)
+#define RT5659_MONO_ADC_R_VOL_SFT		0
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5659_STO1_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5659_STO1_ADC_L_BST_SFT		14
+#define RT5659_STO1_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5659_STO1_ADC_R_BST_SFT		12
+
+/* Mono ADC Boost Gain Control (0x0020) */
+#define RT5659_MONO_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5659_MONO_ADC_L_BST_SFT		14
+#define RT5659_MONO_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5659_MONO_ADC_R_BST_SFT		12
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5659_STO2_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5659_STO2_ADC_L_BST_SFT		14
+#define RT5659_STO2_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5659_STO2_ADC_R_BST_SFT		12
+
+/* Stereo ADC Mixer Control (0x0026) */
+#define RT5659_M_STO1_ADC_L1			(0x1 << 15)
+#define RT5659_M_STO1_ADC_L1_SFT		15
+#define RT5659_M_STO1_ADC_L2			(0x1 << 14)
+#define RT5659_M_STO1_ADC_L2_SFT		14
+#define RT5659_STO1_ADC1_SRC_MASK		(0x1 << 13)
+#define RT5659_STO1_ADC1_SRC_SFT		13
+#define RT5659_STO1_ADC1_SRC_ADC		(0x1 << 13)
+#define RT5659_STO1_ADC1_SRC_DACMIX		(0x0 << 13)
+#define RT5659_STO1_ADC_SRC_MASK		(0x1 << 12)
+#define RT5659_STO1_ADC_SRC_SFT			12
+#define RT5659_STO1_ADC_SRC_ADC1		(0x1 << 12)
+#define RT5659_STO1_ADC_SRC_ADC2		(0x0 << 12)
+#define RT5659_STO1_ADC2_SRC_MASK		(0x1 << 11)
+#define RT5659_STO1_ADC2_SRC_SFT		11
+#define RT5659_STO1_DMIC_SRC_MASK		(0x1 << 8)
+#define RT5659_STO1_DMIC_SRC_SFT		8
+#define RT5659_STO1_DMIC_SRC_DMIC2		(0x1 << 8)
+#define RT5659_STO1_DMIC_SRC_DMIC1		(0x0 << 8)
+#define RT5659_M_STO1_ADC_R1			(0x1 << 6)
+#define RT5659_M_STO1_ADC_R1_SFT		6
+#define RT5659_M_STO1_ADC_R2			(0x1 << 5)
+#define RT5659_M_STO1_ADC_R2_SFT		5
+
+/* Mono1 ADC Mixer control (0x0027) */
+#define RT5659_M_MONO_ADC_L1			(0x1 << 15)
+#define RT5659_M_MONO_ADC_L1_SFT		15
+#define RT5659_M_MONO_ADC_L2			(0x1 << 14)
+#define RT5659_M_MONO_ADC_L2_SFT		14
+#define RT5659_MONO_ADC_L2_SRC_MASK		(0x1 << 12)
+#define RT5659_MONO_ADC_L2_SRC_SFT		12
+#define RT5659_MONO_ADC_L1_SRC_MASK		(0x1 << 11)
+#define RT5659_MONO_ADC_L1_SRC_SFT		11
+#define RT5659_MONO_ADC_L_SRC_MASK		(0x3 << 9)
+#define RT5659_MONO_ADC_L_SRC_SFT		9
+#define RT5659_MONO_DMIC_L_SRC_MASK		(0x1 << 8)
+#define RT5659_MONO_DMIC_L_SRC_SFT		8
+#define RT5659_M_MONO_ADC_R1			(0x1 << 7)
+#define RT5659_M_MONO_ADC_R1_SFT		7
+#define RT5659_M_MONO_ADC_R2			(0x1 << 6)
+#define RT5659_M_MONO_ADC_R2_SFT		6
+#define RT5659_STO2_ADC_SRC_MASK		(0x1 << 5)
+#define RT5659_STO2_ADC_SRC_SFT			5
+#define RT5659_MONO_ADC_R2_SRC_MASK		(0x1 << 4)
+#define RT5659_MONO_ADC_R2_SRC_SFT		4
+#define RT5659_MONO_ADC_R1_SRC_MASK		(0x1 << 3)
+#define RT5659_MONO_ADC_R1_SRC_SFT		3
+#define RT5659_MONO_ADC_R_SRC_MASK		(0x3 << 1)
+#define RT5659_MONO_ADC_R_SRC_SFT		1
+#define RT5659_MONO_DMIC_R_SRC_MASK		0x1
+#define RT5659_MONO_DMIC_R_SRC_SFT		0
+
+/* ADC Mixer to DAC Mixer Control (0x0029) */
+#define RT5659_M_ADCMIX_L			(0x1 << 15)
+#define RT5659_M_ADCMIX_L_SFT			15
+#define RT5659_M_DAC1_L				(0x1 << 14)
+#define RT5659_M_DAC1_L_SFT			14
+#define RT5659_DAC1_R_SEL_MASK			(0x3 << 10)
+#define RT5659_DAC1_R_SEL_SFT			10
+#define RT5659_DAC1_R_SEL_IF1			(0x0 << 10)
+#define RT5659_DAC1_R_SEL_IF2			(0x1 << 10)
+#define RT5659_DAC1_R_SEL_IF3			(0x2 << 10)
+#define RT5659_DAC1_L_SEL_MASK			(0x3 << 8)
+#define RT5659_DAC1_L_SEL_SFT			8
+#define RT5659_DAC1_L_SEL_IF1			(0x0 << 8)
+#define RT5659_DAC1_L_SEL_IF2			(0x1 << 8)
+#define RT5659_DAC1_L_SEL_IF3			(0x2 << 8)
+#define RT5659_M_ADCMIX_R			(0x1 << 7)
+#define RT5659_M_ADCMIX_R_SFT			7
+#define RT5659_M_DAC1_R				(0x1 << 6)
+#define RT5659_M_DAC1_R_SFT			6
+
+/* Stereo DAC Mixer Control (0x002a) */
+#define RT5659_M_DAC_L1_STO_L			(0x1 << 15)
+#define RT5659_M_DAC_L1_STO_L_SFT		15
+#define RT5659_G_DAC_L1_STO_L_MASK		(0x1 << 14)
+#define RT5659_G_DAC_L1_STO_L_SFT		14
+#define RT5659_M_DAC_R1_STO_L			(0x1 << 13)
+#define RT5659_M_DAC_R1_STO_L_SFT		13
+#define RT5659_G_DAC_R1_STO_L_MASK		(0x1 << 12)
+#define RT5659_G_DAC_R1_STO_L_SFT		12
+#define RT5659_M_DAC_L2_STO_L			(0x1 << 11)
+#define RT5659_M_DAC_L2_STO_L_SFT		11
+#define RT5659_G_DAC_L2_STO_L_MASK		(0x1 << 10)
+#define RT5659_G_DAC_L2_STO_L_SFT		10
+#define RT5659_M_DAC_R2_STO_L			(0x1 << 9)
+#define RT5659_M_DAC_R2_STO_L_SFT		9
+#define RT5659_G_DAC_R2_STO_L_MASK		(0x1 << 8)
+#define RT5659_G_DAC_R2_STO_L_SFT		8
+#define RT5659_M_DAC_L1_STO_R			(0x1 << 7)
+#define RT5659_M_DAC_L1_STO_R_SFT		7
+#define RT5659_G_DAC_L1_STO_R_MASK		(0x1 << 6)
+#define RT5659_G_DAC_L1_STO_R_SFT		6
+#define RT5659_M_DAC_R1_STO_R			(0x1 << 5)
+#define RT5659_M_DAC_R1_STO_R_SFT		5
+#define RT5659_G_DAC_R1_STO_R_MASK		(0x1 << 4)
+#define RT5659_G_DAC_R1_STO_R_SFT		4
+#define RT5659_M_DAC_L2_STO_R			(0x1 << 3)
+#define RT5659_M_DAC_L2_STO_R_SFT		3
+#define RT5659_G_DAC_L2_STO_R_MASK		(0x1 << 2)
+#define RT5659_G_DAC_L2_STO_R_SFT		2
+#define RT5659_M_DAC_R2_STO_R			(0x1 << 1)
+#define RT5659_M_DAC_R2_STO_R_SFT		1
+#define RT5659_G_DAC_R2_STO_R_MASK		(0x1)
+#define RT5659_G_DAC_R2_STO_R_SFT		0
+
+/* Mono DAC Mixer Control (0x002b) */
+#define RT5659_M_DAC_L1_MONO_L			(0x1 << 15)
+#define RT5659_M_DAC_L1_MONO_L_SFT		15
+#define RT5659_G_DAC_L1_MONO_L_MASK		(0x1 << 14)
+#define RT5659_G_DAC_L1_MONO_L_SFT		14
+#define RT5659_M_DAC_R1_MONO_L			(0x1 << 13)
+#define RT5659_M_DAC_R1_MONO_L_SFT		13
+#define RT5659_G_DAC_R1_MONO_L_MASK		(0x1 << 12)
+#define RT5659_G_DAC_R1_MONO_L_SFT		12
+#define RT5659_M_DAC_L2_MONO_L			(0x1 << 11)
+#define RT5659_M_DAC_L2_MONO_L_SFT		11
+#define RT5659_G_DAC_L2_MONO_L_MASK		(0x1 << 10)
+#define RT5659_G_DAC_L2_MONO_L_SFT		10
+#define RT5659_M_DAC_R2_MONO_L			(0x1 << 9)
+#define RT5659_M_DAC_R2_MONO_L_SFT		9
+#define RT5659_G_DAC_R2_MONO_L_MASK		(0x1 << 8)
+#define RT5659_G_DAC_R2_MONO_L_SFT		8
+#define RT5659_M_DAC_L1_MONO_R			(0x1 << 7)
+#define RT5659_M_DAC_L1_MONO_R_SFT		7
+#define RT5659_G_DAC_L1_MONO_R_MASK		(0x1 << 6)
+#define RT5659_G_DAC_L1_MONO_R_SFT		6
+#define RT5659_M_DAC_R1_MONO_R			(0x1 << 5)
+#define RT5659_M_DAC_R1_MONO_R_SFT		5
+#define RT5659_G_DAC_R1_MONO_R_MASK		(0x1 << 4)
+#define RT5659_G_DAC_R1_MONO_R_SFT		4
+#define RT5659_M_DAC_L2_MONO_R			(0x1 << 3)
+#define RT5659_M_DAC_L2_MONO_R_SFT		3
+#define RT5659_G_DAC_L2_MONO_R_MASK		(0x1 << 2)
+#define RT5659_G_DAC_L2_MONO_R_SFT		2
+#define RT5659_M_DAC_R2_MONO_R			(0x1 << 1)
+#define RT5659_M_DAC_R2_MONO_R_SFT		1
+#define RT5659_G_DAC_R2_MONO_R_MASK		(0x1)
+#define RT5659_G_DAC_R2_MONO_R_SFT		0
+
+/* Digital Mixer Control (0x002c) */
+#define RT5659_M_DAC_MIX_L			(0x1 << 7)
+#define RT5659_M_DAC_MIX_L_SFT			7
+#define RT5659_DAC_MIX_L_MASK			(0x1 << 6)
+#define RT5659_DAC_MIX_L_SFT			6
+#define RT5659_M_DAC_MIX_R			(0x1 << 5)
+#define RT5659_M_DAC_MIX_R_SFT			5
+#define RT5659_DAC_MIX_R_MASK			(0x1 << 4)
+#define RT5659_DAC_MIX_R_SFT			4
+
+/* Analog DAC Input Source Control (0x002d) */
+#define RT5659_A_DACL1_SEL			(0x1 << 3)
+#define RT5659_A_DACL1_SFT			3
+#define RT5659_A_DACR1_SEL			(0x1 << 2)
+#define RT5659_A_DACR1_SFT			2
+#define RT5659_A_DACL2_SEL			(0x1 << 1)
+#define RT5659_A_DACL2_SFT			1
+#define RT5659_A_DACR2_SEL			(0x1 << 0)
+#define RT5659_A_DACR2_SFT			0
+
+/* Digital Interface Data Control (0x002f) */
+#define RT5659_IF2_ADC3_IN_MASK			(0x3 << 14)
+#define RT5659_IF2_ADC3_IN_SFT			14
+#define RT5659_IF2_ADC_IN_MASK			(0x3 << 12)
+#define RT5659_IF2_ADC_IN_SFT			12
+#define RT5659_IF2_DAC_SEL_MASK			(0x3 << 10)
+#define RT5659_IF2_DAC_SEL_SFT			10
+#define RT5659_IF2_ADC_SEL_MASK			(0x3 << 8)
+#define RT5659_IF2_ADC_SEL_SFT			8
+#define RT5659_IF3_DAC_SEL_MASK			(0x3 << 6)
+#define RT5659_IF3_DAC_SEL_SFT			6
+#define RT5659_IF3_ADC_SEL_MASK			(0x3 << 4)
+#define RT5659_IF3_ADC_SEL_SFT			4
+#define RT5659_IF3_ADC_IN_MASK			(0x3 << 0)
+#define RT5659_IF3_ADC_IN_SFT			0
+
+/* PDM Output Control (0x0031) */
+#define RT5659_PDM1_L_MASK			(0x1 << 15)
+#define RT5659_PDM1_L_SFT			15
+#define RT5659_M_PDM1_L				(0x1 << 14)
+#define RT5659_M_PDM1_L_SFT			14
+#define RT5659_PDM1_R_MASK			(0x1 << 13)
+#define RT5659_PDM1_R_SFT			13
+#define RT5659_M_PDM1_R				(0x1 << 12)
+#define RT5659_M_PDM1_R_SFT			12
+#define RT5659_PDM2_BUSY			(0x1 << 7)
+#define RT5659_PDM1_BUSY			(0x1 << 6)
+#define RT5659_PDM_PATTERN			(0x1 << 5)
+#define RT5659_PDM_GAIN				(0x1 << 4)
+#define RT5659_PDM_DIV_MASK			(0x3)
+
+/*S/PDIF Output Control (0x0036) */
+#define RT5659_SPDIF_SEL_MASK			(0x3 << 0)
+#define RT5659_SPDIF_SEL_SFT			0
+
+/* REC Left Mixer Control 2 (0x003c) */
+#define RT5659_M_BST1_RM1_L			(0x1 << 5)
+#define RT5659_M_BST1_RM1_L_SFT			5
+#define RT5659_M_BST2_RM1_L			(0x1 << 4)
+#define RT5659_M_BST2_RM1_L_SFT			4
+#define RT5659_M_BST3_RM1_L			(0x1 << 3)
+#define RT5659_M_BST3_RM1_L_SFT			3
+#define RT5659_M_BST4_RM1_L			(0x1 << 2)
+#define RT5659_M_BST4_RM1_L_SFT			2
+#define RT5659_M_INL_RM1_L			(0x1 << 1)
+#define RT5659_M_INL_RM1_L_SFT			1
+#define RT5659_M_SPKVOLL_RM1_L			(0x1)
+#define RT5659_M_SPKVOLL_RM1_L_SFT		0
+
+/* REC Right Mixer Control 2 (0x003e) */
+#define RT5659_M_BST1_RM1_R			(0x1 << 5)
+#define RT5659_M_BST1_RM1_R_SFT			5
+#define RT5659_M_BST2_RM1_R			(0x1 << 4)
+#define RT5659_M_BST2_RM1_R_SFT			4
+#define RT5659_M_BST3_RM1_R			(0x1 << 3)
+#define RT5659_M_BST3_RM1_R_SFT			3
+#define RT5659_M_BST4_RM1_R			(0x1 << 2)
+#define RT5659_M_BST4_RM1_R_SFT			2
+#define RT5659_M_INR_RM1_R			(0x1 << 1)
+#define RT5659_M_INR_RM1_R_SFT			1
+#define RT5659_M_HPOVOLR_RM1_R			(0x1)
+#define RT5659_M_HPOVOLR_RM1_R_SFT		0
+
+/* SPK Left Mixer Control (0x0046) */
+#define RT5659_M_BST3_SM_L			(0x1 << 4)
+#define RT5659_M_BST3_SM_L_SFT			4
+#define RT5659_M_IN_R_SM_L			(0x1 << 3)
+#define RT5659_M_IN_R_SM_L_SFT			3
+#define RT5659_M_IN_L_SM_L			(0x1 << 2)
+#define RT5659_M_IN_L_SM_L_SFT			2
+#define RT5659_M_BST1_SM_L			(0x1 << 1)
+#define RT5659_M_BST1_SM_L_SFT			1
+#define RT5659_M_DAC_L2_SM_L			(0x1)
+#define RT5659_M_DAC_L2_SM_L_SFT		0
+
+/* SPK Right Mixer Control (0x0047) */
+#define RT5659_M_BST3_SM_R			(0x1 << 4)
+#define RT5659_M_BST3_SM_R_SFT			4
+#define RT5659_M_IN_R_SM_R			(0x1 << 3)
+#define RT5659_M_IN_R_SM_R_SFT			3
+#define RT5659_M_IN_L_SM_R			(0x1 << 2)
+#define RT5659_M_IN_L_SM_R_SFT			2
+#define RT5659_M_BST4_SM_R			(0x1 << 1)
+#define RT5659_M_BST4_SM_R_SFT			1
+#define RT5659_M_DAC_R2_SM_R			(0x1)
+#define RT5659_M_DAC_R2_SM_R_SFT		0
+
+/* SPO Amp Input and Gain Control (0x0048) */
+#define RT5659_M_DAC_L2_SPKOMIX			(0x1 << 13)
+#define RT5659_M_DAC_L2_SPKOMIX_SFT		13
+#define RT5659_M_SPKVOLL_SPKOMIX		(0x1 << 12)
+#define RT5659_M_SPKVOLL_SPKOMIX_SFT		12
+#define RT5659_M_DAC_R2_SPKOMIX			(0x1 << 9)
+#define RT5659_M_DAC_R2_SPKOMIX_SFT		9
+#define RT5659_M_SPKVOLR_SPKOMIX		(0x1 << 8)
+#define RT5659_M_SPKVOLR_SPKOMIX_SFT		8
+
+/* MONOMIX Input and Gain Control (0x004b) */
+#define RT5659_M_MONOVOL_MA			(0x1 << 9)
+#define RT5659_M_MONOVOL_MA_SFT			9
+#define RT5659_M_DAC_L2_MA			(0x1 << 8)
+#define RT5659_M_DAC_L2_MA_SFT			8
+#define RT5659_M_BST3_MM			(0x1 << 4)
+#define RT5659_M_BST3_MM_SFT			4
+#define RT5659_M_BST2_MM			(0x1 << 3)
+#define RT5659_M_BST2_MM_SFT			3
+#define RT5659_M_BST1_MM			(0x1 << 2)
+#define RT5659_M_BST1_MM_SFT			2
+#define RT5659_M_DAC_R2_MM			(0x1 << 1)
+#define RT5659_M_DAC_R2_MM_SFT			1
+#define RT5659_M_DAC_L2_MM			(0x1)
+#define RT5659_M_DAC_L2_MM_SFT			0
+
+/* Output Left Mixer Control 1 (0x004d) */
+#define RT5659_G_BST3_OM_L_MASK			(0x7 << 12)
+#define RT5659_G_BST3_OM_L_SFT			12
+#define RT5659_G_BST2_OM_L_MASK			(0x7 << 9)
+#define RT5659_G_BST2_OM_L_SFT			9
+#define RT5659_G_BST1_OM_L_MASK			(0x7 << 6)
+#define RT5659_G_BST1_OM_L_SFT			6
+#define RT5659_G_IN_L_OM_L_MASK			(0x7 << 3)
+#define RT5659_G_IN_L_OM_L_SFT			3
+#define RT5659_G_DAC_L2_OM_L_MASK		(0x7 << 0)
+#define RT5659_G_DAC_L2_OM_L_SFT		0
+
+/* Output Left Mixer Input Control (0x004e) */
+#define RT5659_M_BST3_OM_L			(0x1 << 4)
+#define RT5659_M_BST3_OM_L_SFT			4
+#define RT5659_M_BST2_OM_L			(0x1 << 3)
+#define RT5659_M_BST2_OM_L_SFT			3
+#define RT5659_M_BST1_OM_L			(0x1 << 2)
+#define RT5659_M_BST1_OM_L_SFT			2
+#define RT5659_M_IN_L_OM_L			(0x1 << 1)
+#define RT5659_M_IN_L_OM_L_SFT			1
+#define RT5659_M_DAC_L2_OM_L			(0x1)
+#define RT5659_M_DAC_L2_OM_L_SFT		0
+
+/* Output Right Mixer Input Control (0x0050) */
+#define RT5659_M_BST4_OM_R			(0x1 << 4)
+#define RT5659_M_BST4_OM_R_SFT			4
+#define RT5659_M_BST3_OM_R			(0x1 << 3)
+#define RT5659_M_BST3_OM_R_SFT			3
+#define RT5659_M_BST2_OM_R			(0x1 << 2)
+#define RT5659_M_BST2_OM_R_SFT			2
+#define RT5659_M_IN_R_OM_R			(0x1 << 1)
+#define RT5659_M_IN_R_OM_R_SFT			1
+#define RT5659_M_DAC_R2_OM_R			(0x1)
+#define RT5659_M_DAC_R2_OM_R_SFT		0
+
+/* LOUT Mixer Control (0x0052) */
+#define RT5659_M_DAC_L2_LM			(0x1 << 15)
+#define RT5659_M_DAC_L2_LM_SFT			15
+#define RT5659_M_DAC_R2_LM			(0x1 << 14)
+#define RT5659_M_DAC_R2_LM_SFT			14
+#define RT5659_M_OV_L_LM			(0x1 << 13)
+#define RT5659_M_OV_L_LM_SFT			13
+#define RT5659_M_OV_R_LM			(0x1 << 12)
+#define RT5659_M_OV_R_LM_SFT			12
+
+/* Power Management for Digital 1 (0x0061) */
+#define RT5659_PWR_I2S1				(0x1 << 15)
+#define RT5659_PWR_I2S1_BIT			15
+#define RT5659_PWR_I2S2				(0x1 << 14)
+#define RT5659_PWR_I2S2_BIT			14
+#define RT5659_PWR_I2S3				(0x1 << 13)
+#define RT5659_PWR_I2S3_BIT			13
+#define RT5659_PWR_SPDIF			(0x1 << 12)
+#define RT5659_PWR_SPDIF_BIT			12
+#define RT5659_PWR_DAC_L1			(0x1 << 11)
+#define RT5659_PWR_DAC_L1_BIT			11
+#define RT5659_PWR_DAC_R1			(0x1 << 10)
+#define RT5659_PWR_DAC_R1_BIT			10
+#define RT5659_PWR_DAC_L2			(0x1 << 9)
+#define RT5659_PWR_DAC_L2_BIT			9
+#define RT5659_PWR_DAC_R2			(0x1 << 8)
+#define RT5659_PWR_DAC_R2_BIT			8
+#define RT5659_PWR_LDO				(0x1 << 7)
+#define RT5659_PWR_LDO_BIT			7
+#define RT5659_PWR_ADC_L1			(0x1 << 4)
+#define RT5659_PWR_ADC_L1_BIT			4
+#define RT5659_PWR_ADC_R1			(0x1 << 3)
+#define RT5659_PWR_ADC_R1_BIT			3
+#define RT5659_PWR_ADC_L2			(0x1 << 2)
+#define RT5659_PWR_ADC_L2_BIT			2
+#define RT5659_PWR_ADC_R2			(0x1 << 1)
+#define RT5659_PWR_ADC_R2_BIT			1
+#define RT5659_PWR_CLS_D			(0x1)
+#define RT5659_PWR_CLS_D_BIT			0
+
+/* Power Management for Digital 2 (0x0062) */
+#define RT5659_PWR_ADC_S1F			(0x1 << 15)
+#define RT5659_PWR_ADC_S1F_BIT			15
+#define RT5659_PWR_ADC_S2F			(0x1 << 14)
+#define RT5659_PWR_ADC_S2F_BIT			14
+#define RT5659_PWR_ADC_MF_L			(0x1 << 13)
+#define RT5659_PWR_ADC_MF_L_BIT			13
+#define RT5659_PWR_ADC_MF_R			(0x1 << 12)
+#define RT5659_PWR_ADC_MF_R_BIT			12
+#define RT5659_PWR_DAC_S1F			(0x1 << 10)
+#define RT5659_PWR_DAC_S1F_BIT			10
+#define RT5659_PWR_DAC_MF_L			(0x1 << 9)
+#define RT5659_PWR_DAC_MF_L_BIT			9
+#define RT5659_PWR_DAC_MF_R			(0x1 << 8)
+#define RT5659_PWR_DAC_MF_R_BIT			8
+#define RT5659_PWR_PDM1				(0x1 << 7)
+#define RT5659_PWR_PDM1_BIT			7
+
+/* Power Management for Analog 1 (0x0063) */
+#define RT5659_PWR_VREF1			(0x1 << 15)
+#define RT5659_PWR_VREF1_BIT			15
+#define RT5659_PWR_FV1				(0x1 << 14)
+#define RT5659_PWR_FV1_BIT			14
+#define RT5659_PWR_VREF2			(0x1 << 13)
+#define RT5659_PWR_VREF2_BIT			13
+#define RT5659_PWR_FV2				(0x1 << 12)
+#define RT5659_PWR_FV2_BIT			12
+#define RT5659_PWR_VREF3			(0x1 << 11)
+#define RT5659_PWR_VREF3_BIT			11
+#define RT5659_PWR_FV3				(0x1 << 10)
+#define RT5659_PWR_FV3_BIT			10
+#define RT5659_PWR_MB				(0x1 << 9)
+#define RT5659_PWR_MB_BIT			9
+#define RT5659_PWR_LM				(0x1 << 8)
+#define RT5659_PWR_LM_BIT			8
+#define RT5659_PWR_BG				(0x1 << 7)
+#define RT5659_PWR_BG_BIT			7
+#define RT5659_PWR_MA				(0x1 << 6)
+#define RT5659_PWR_MA_BIT			6
+#define RT5659_PWR_HA_L				(0x1 << 5)
+#define RT5659_PWR_HA_L_BIT			5
+#define RT5659_PWR_HA_R				(0x1 << 4)
+#define RT5659_PWR_HA_R_BIT			4
+
+/* Power Management for Analog 2 (0x0064) */
+#define RT5659_PWR_BST1				(0x1 << 15)
+#define RT5659_PWR_BST1_BIT			15
+#define RT5659_PWR_BST2				(0x1 << 14)
+#define RT5659_PWR_BST2_BIT			14
+#define RT5659_PWR_BST3				(0x1 << 13)
+#define RT5659_PWR_BST3_BIT			13
+#define RT5659_PWR_BST4				(0x1 << 12)
+#define RT5659_PWR_BST4_BIT			12
+#define RT5659_PWR_MB1				(0x1 << 11)
+#define RT5659_PWR_MB1_BIT			11
+#define RT5659_PWR_MB2				(0x1 << 10)
+#define RT5659_PWR_MB2_BIT			10
+#define RT5659_PWR_MB3				(0x1 << 9)
+#define RT5659_PWR_MB3_BIT			9
+#define RT5659_PWR_BST1_P			(0x1 << 6)
+#define RT5659_PWR_BST1_P_BIT			6
+#define RT5659_PWR_BST2_P			(0x1 << 5)
+#define RT5659_PWR_BST2_P_BIT			5
+#define RT5659_PWR_BST3_P			(0x1 << 4)
+#define RT5659_PWR_BST3_P_BIT			4
+#define RT5659_PWR_BST4_P			(0x1 << 3)
+#define RT5659_PWR_BST4_P_BIT			3
+#define RT5659_PWR_JD1				(0x1 << 2)
+#define RT5659_PWR_JD1_BIT			2
+#define RT5659_PWR_JD2				(0x1 << 1)
+#define RT5659_PWR_JD2_BIT			1
+#define RT5659_PWR_JD3				(0x1)
+#define RT5659_PWR_JD3_BIT			0
+
+/* Power Management for Analog 3 (0x0065) */
+#define RT5659_PWR_BST_L			(0x1 << 8)
+#define RT5659_PWR_BST_L_BIT			8
+#define RT5659_PWR_BST_R			(0x1 << 7)
+#define RT5659_PWR_BST_R_BIT			7
+#define RT5659_PWR_PLL				(0x1 << 6)
+#define RT5659_PWR_PLL_BIT			6
+#define RT5659_PWR_LDO5				(0x1 << 5)
+#define RT5659_PWR_LDO5_BIT			5
+#define RT5659_PWR_LDO4				(0x1 << 4)
+#define RT5659_PWR_LDO4_BIT			4
+#define RT5659_PWR_LDO3				(0x1 << 3)
+#define RT5659_PWR_LDO3_BIT			3
+#define RT5659_PWR_LDO2				(0x1 << 2)
+#define RT5659_PWR_LDO2_BIT			2
+#define RT5659_PWR_SVD				(0x1 << 1)
+#define RT5659_PWR_SVD_BIT			1
+
+/* Power Management for Mixer (0x0066) */
+#define RT5659_PWR_OM_L				(0x1 << 15)
+#define RT5659_PWR_OM_L_BIT			15
+#define RT5659_PWR_OM_R				(0x1 << 14)
+#define RT5659_PWR_OM_R_BIT			14
+#define RT5659_PWR_SM_L				(0x1 << 13)
+#define RT5659_PWR_SM_L_BIT			13
+#define RT5659_PWR_SM_R				(0x1 << 12)
+#define RT5659_PWR_SM_R_BIT			12
+#define RT5659_PWR_RM1_L			(0x1 << 11)
+#define RT5659_PWR_RM1_L_BIT			11
+#define RT5659_PWR_RM1_R			(0x1 << 10)
+#define RT5659_PWR_RM1_R_BIT			10
+#define RT5659_PWR_MM				(0x1 << 8)
+#define RT5659_PWR_MM_BIT			8
+#define RT5659_PWR_RM2_L			(0x1 << 3)
+#define RT5659_PWR_RM2_L_BIT			3
+#define RT5659_PWR_RM2_R			(0x1 << 2)
+#define RT5659_PWR_RM2_R_BIT			2
+
+/* Power Management for Volume (0x0067) */
+#define RT5659_PWR_SV_L				(0x1 << 15)
+#define RT5659_PWR_SV_L_BIT			15
+#define RT5659_PWR_SV_R				(0x1 << 14)
+#define RT5659_PWR_SV_R_BIT			14
+#define RT5659_PWR_OV_L				(0x1 << 13)
+#define RT5659_PWR_OV_L_BIT			13
+#define RT5659_PWR_OV_R				(0x1 << 12)
+#define RT5659_PWR_OV_R_BIT			12
+#define RT5659_PWR_IN_L				(0x1 << 9)
+#define RT5659_PWR_IN_L_BIT			9
+#define RT5659_PWR_IN_R				(0x1 << 8)
+#define RT5659_PWR_IN_R_BIT			8
+#define RT5659_PWR_MV				(0x1 << 7)
+#define RT5659_PWR_MV_BIT			7
+#define RT5659_PWR_MIC_DET			(0x1 << 5)
+#define RT5659_PWR_MIC_DET_BIT			5
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x0070 0x0071 0x0072) */
+#define RT5659_I2S_MS_MASK			(0x1 << 15)
+#define RT5659_I2S_MS_SFT			15
+#define RT5659_I2S_MS_M				(0x0 << 15)
+#define RT5659_I2S_MS_S				(0x1 << 15)
+#define RT5659_I2S_O_CP_MASK			(0x3 << 12)
+#define RT5659_I2S_O_CP_SFT			12
+#define RT5659_I2S_O_CP_OFF			(0x0 << 12)
+#define RT5659_I2S_O_CP_U_LAW			(0x1 << 12)
+#define RT5659_I2S_O_CP_A_LAW			(0x2 << 12)
+#define RT5659_I2S_I_CP_MASK			(0x3 << 10)
+#define RT5659_I2S_I_CP_SFT			10
+#define RT5659_I2S_I_CP_OFF			(0x0 << 10)
+#define RT5659_I2S_I_CP_U_LAW			(0x1 << 10)
+#define RT5659_I2S_I_CP_A_LAW			(0x2 << 10)
+#define RT5659_I2S_BP_MASK			(0x1 << 8)
+#define RT5659_I2S_BP_SFT			8
+#define RT5659_I2S_BP_NOR			(0x0 << 8)
+#define RT5659_I2S_BP_INV			(0x1 << 8)
+#define RT5659_I2S_DL_MASK			(0x3 << 4)
+#define RT5659_I2S_DL_SFT			4
+#define RT5659_I2S_DL_16			(0x0 << 4)
+#define RT5659_I2S_DL_20			(0x1 << 4)
+#define RT5659_I2S_DL_24			(0x2 << 4)
+#define RT5659_I2S_DL_8				(0x3 << 4)
+#define RT5659_I2S_DF_MASK			(0x7)
+#define RT5659_I2S_DF_SFT			0
+#define RT5659_I2S_DF_I2S			(0x0)
+#define RT5659_I2S_DF_LEFT			(0x1)
+#define RT5659_I2S_DF_PCM_A			(0x2)
+#define RT5659_I2S_DF_PCM_B			(0x3)
+#define RT5659_I2S_DF_PCM_A_N			(0x6)
+#define RT5659_I2S_DF_PCM_B_N			(0x7)
+
+/* ADC/DAC Clock Control 1 (0x0073) */
+#define RT5659_I2S_PD1_MASK			(0x7 << 12)
+#define RT5659_I2S_PD1_SFT			12
+#define RT5659_I2S_PD1_1			(0x0 << 12)
+#define RT5659_I2S_PD1_2			(0x1 << 12)
+#define RT5659_I2S_PD1_3			(0x2 << 12)
+#define RT5659_I2S_PD1_4			(0x3 << 12)
+#define RT5659_I2S_PD1_6			(0x4 << 12)
+#define RT5659_I2S_PD1_8			(0x5 << 12)
+#define RT5659_I2S_PD1_12			(0x6 << 12)
+#define RT5659_I2S_PD1_16			(0x7 << 12)
+#define RT5659_I2S_BCLK_MS2_MASK		(0x1 << 11)
+#define RT5659_I2S_BCLK_MS2_SFT			11
+#define RT5659_I2S_BCLK_MS2_32			(0x0 << 11)
+#define RT5659_I2S_BCLK_MS2_64			(0x1 << 11)
+#define RT5659_I2S_PD2_MASK			(0x7 << 8)
+#define RT5659_I2S_PD2_SFT			8
+#define RT5659_I2S_PD2_1			(0x0 << 8)
+#define RT5659_I2S_PD2_2			(0x1 << 8)
+#define RT5659_I2S_PD2_3			(0x2 << 8)
+#define RT5659_I2S_PD2_4			(0x3 << 8)
+#define RT5659_I2S_PD2_6			(0x4 << 8)
+#define RT5659_I2S_PD2_8			(0x5 << 8)
+#define RT5659_I2S_PD2_12			(0x6 << 8)
+#define RT5659_I2S_PD2_16			(0x7 << 8)
+#define RT5659_I2S_BCLK_MS3_MASK		(0x1 << 7)
+#define RT5659_I2S_BCLK_MS3_SFT			7
+#define RT5659_I2S_BCLK_MS3_32			(0x0 << 7)
+#define RT5659_I2S_BCLK_MS3_64			(0x1 << 7)
+#define RT5659_I2S_PD3_MASK			(0x7 << 4)
+#define RT5659_I2S_PD3_SFT			4
+#define RT5659_I2S_PD3_1			(0x0 << 4)
+#define RT5659_I2S_PD3_2			(0x1 << 4)
+#define RT5659_I2S_PD3_3			(0x2 << 4)
+#define RT5659_I2S_PD3_4			(0x3 << 4)
+#define RT5659_I2S_PD3_6			(0x4 << 4)
+#define RT5659_I2S_PD3_8			(0x5 << 4)
+#define RT5659_I2S_PD3_12			(0x6 << 4)
+#define RT5659_I2S_PD3_16			(0x7 << 4)
+#define RT5659_DAC_OSR_MASK			(0x3 << 2)
+#define RT5659_DAC_OSR_SFT			2
+#define RT5659_DAC_OSR_128			(0x0 << 2)
+#define RT5659_DAC_OSR_64			(0x1 << 2)
+#define RT5659_DAC_OSR_32			(0x2 << 2)
+#define RT5659_DAC_OSR_16			(0x3 << 2)
+#define RT5659_ADC_OSR_MASK			(0x3)
+#define RT5659_ADC_OSR_SFT			0
+#define RT5659_ADC_OSR_128			(0x0)
+#define RT5659_ADC_OSR_64			(0x1)
+#define RT5659_ADC_OSR_32			(0x2)
+#define RT5659_ADC_OSR_16			(0x3)
+
+/* Digital Microphone Control (0x0075) */
+#define RT5659_DMIC_1_EN_MASK			(0x1 << 15)
+#define RT5659_DMIC_1_EN_SFT			15
+#define RT5659_DMIC_1_DIS			(0x0 << 15)
+#define RT5659_DMIC_1_EN			(0x1 << 15)
+#define RT5659_DMIC_2_EN_MASK			(0x1 << 14)
+#define RT5659_DMIC_2_EN_SFT			14
+#define RT5659_DMIC_2_DIS			(0x0 << 14)
+#define RT5659_DMIC_2_EN			(0x1 << 14)
+#define RT5659_DMIC_1L_LH_MASK			(0x1 << 13)
+#define RT5659_DMIC_1L_LH_SFT			13
+#define RT5659_DMIC_1L_LH_RISING		(0x0 << 13)
+#define RT5659_DMIC_1L_LH_FALLING		(0x1 << 13)
+#define RT5659_DMIC_1R_LH_MASK			(0x1 << 12)
+#define RT5659_DMIC_1R_LH_SFT			12
+#define RT5659_DMIC_1R_LH_RISING		(0x0 << 12)
+#define RT5659_DMIC_1R_LH_FALLING		(0x1 << 12)
+#define RT5659_DMIC_2_DP_MASK			(0x3 << 10)
+#define RT5659_DMIC_2_DP_SFT			10
+#define RT5659_DMIC_2_DP_GPIO6			(0x0 << 10)
+#define RT5659_DMIC_2_DP_GPIO10			(0x1 << 10)
+#define RT5659_DMIC_2_DP_GPIO12			(0x2 << 10)
+#define RT5659_DMIC_2_DP_IN2P			(0x3 << 10)
+#define RT5659_DMIC_CLK_MASK			(0x7 << 5)
+#define RT5659_DMIC_CLK_SFT			5
+#define RT5659_DMIC_1_DP_MASK			(0x3 << 0)
+#define RT5659_DMIC_1_DP_SFT			0
+#define RT5659_DMIC_1_DP_GPIO5			(0x0 << 0)
+#define RT5659_DMIC_1_DP_GPIO9			(0x1 << 0)
+#define RT5659_DMIC_1_DP_GPIO11			(0x2 << 0)
+#define RT5659_DMIC_1_DP_IN2N			(0x3 << 0)
+
+/* TDM control 1 (0x0078)*/
+#define RT5659_DS_ADC_SLOT01_SFT		14
+#define RT5659_DS_ADC_SLOT23_SFT		12
+#define RT5659_DS_ADC_SLOT45_SFT		10
+#define RT5659_DS_ADC_SLOT67_SFT		8
+#define RT5659_ADCDAT_SRC_MASK			0x1f
+#define RT5659_ADCDAT_SRC_SFT			0
+
+/* Global Clock Control (0x0080) */
+#define RT5659_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5659_SCLK_SRC_SFT			14
+#define RT5659_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5659_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5659_SCLK_SRC_RCCLK			(0x2 << 14)
+#define RT5659_PLL1_SRC_MASK			(0x7 << 11)
+#define RT5659_PLL1_SRC_SFT			11
+#define RT5659_PLL1_SRC_MCLK			(0x0 << 11)
+#define RT5659_PLL1_SRC_BCLK1			(0x1 << 11)
+#define RT5659_PLL1_SRC_BCLK2			(0x2 << 11)
+#define RT5659_PLL1_SRC_BCLK3			(0x3 << 11)
+#define RT5659_PLL1_PD_MASK			(0x1 << 3)
+#define RT5659_PLL1_PD_SFT			3
+#define RT5659_PLL1_PD_1			(0x0 << 3)
+#define RT5659_PLL1_PD_2			(0x1 << 3)
+
+#define RT5659_PLL_INP_MAX			40000000
+#define RT5659_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x0081) */
+#define RT5659_PLL_N_MAX			0x001ff
+#define RT5659_PLL_N_MASK			(RT5659_PLL_N_MAX << 7)
+#define RT5659_PLL_N_SFT			7
+#define RT5659_PLL_K_MAX			0x001f
+#define RT5659_PLL_K_MASK			(RT5659_PLL_K_MAX)
+#define RT5659_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x0082) */
+#define RT5659_PLL_M_MAX			0x00f
+#define RT5659_PLL_M_MASK			(RT5659_PLL_M_MAX << 12)
+#define RT5659_PLL_M_SFT			12
+#define RT5659_PLL_M_BP				(0x1 << 11)
+#define RT5659_PLL_M_BP_SFT			11
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5659_I2S3_ASRC_MASK			(0x1 << 13)
+#define RT5659_I2S3_ASRC_SFT			13
+#define RT5659_I2S2_ASRC_MASK			(0x1 << 12)
+#define RT5659_I2S2_ASRC_SFT			12
+#define RT5659_I2S1_ASRC_MASK			(0x1 << 11)
+#define RT5659_I2S1_ASRC_SFT			11
+#define RT5659_DAC_STO_ASRC_MASK		(0x1 << 10)
+#define RT5659_DAC_STO_ASRC_SFT			10
+#define RT5659_DAC_MONO_L_ASRC_MASK		(0x1 << 9)
+#define RT5659_DAC_MONO_L_ASRC_SFT		9
+#define RT5659_DAC_MONO_R_ASRC_MASK		(0x1 << 8)
+#define RT5659_DAC_MONO_R_ASRC_SFT		8
+#define RT5659_DMIC_STO1_ASRC_MASK		(0x1 << 7)
+#define RT5659_DMIC_STO1_ASRC_SFT		7
+#define RT5659_DMIC_MONO_L_ASRC_MASK		(0x1 << 5)
+#define RT5659_DMIC_MONO_L_ASRC_SFT		5
+#define RT5659_DMIC_MONO_R_ASRC_MASK		(0x1 << 4)
+#define RT5659_DMIC_MONO_R_ASRC_SFT		4
+#define RT5659_ADC_STO1_ASRC_MASK		(0x1 << 3)
+#define RT5659_ADC_STO1_ASRC_SFT		3
+#define RT5659_ADC_MONO_L_ASRC_MASK		(0x1 << 1)
+#define RT5659_ADC_MONO_L_ASRC_SFT		1
+#define RT5659_ADC_MONO_R_ASRC_MASK		(0x1)
+#define RT5659_ADC_MONO_R_ASRC_SFT		0
+
+/* PLL tracking mode 2 (0x0084)*/
+#define RT5659_DA_STO_T_MASK			(0x7 << 12)
+#define RT5659_DA_STO_T_SFT			12
+#define RT5659_DA_MONO_L_T_MASK			(0x7 << 8)
+#define RT5659_DA_MONO_L_T_SFT			8
+#define RT5659_DA_MONO_R_T_MASK			(0x7 << 4)
+#define RT5659_DA_MONO_R_T_SFT			4
+#define RT5659_AD_STO1_T_MASK			(0x7)
+#define RT5659_AD_STO1_T_SFT			0
+
+/* PLL tracking mode 3 (0x0085)*/
+#define RT5659_AD_STO2_T_MASK			(0x7 << 8)
+#define RT5659_AD_STO2_T_SFT			8
+#define RT5659_AD_MONO_L_T_MASK			(0x7 << 4)
+#define RT5659_AD_MONO_L_T_SFT			4
+#define RT5659_AD_MONO_R_T_MASK			(0x7)
+#define RT5659_AD_MONO_R_T_SFT			0
+
+/* ASRC Control 4 (0x0086) */
+#define RT5659_I2S1_RATE_MASK			(0xf << 12)
+#define RT5659_I2S1_RATE_SFT			12
+#define RT5659_I2S2_RATE_MASK			(0xf << 8)
+#define RT5659_I2S2_RATE_SFT			8
+#define RT5659_I2S3_RATE_MASK			(0xf << 4)
+#define RT5659_I2S3_RATE_SFT			4
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5659_SMT_TRIG_MASK			(0x1 << 15)
+#define RT5659_SMT_TRIG_SFT			15
+#define RT5659_SMT_TRIG_DIS			(0x0 << 15)
+#define RT5659_SMT_TRIG_EN			(0x1 << 15)
+#define RT5659_HP_L_SMT_MASK			(0x1 << 9)
+#define RT5659_HP_L_SMT_SFT			9
+#define RT5659_HP_L_SMT_DIS			(0x0 << 9)
+#define RT5659_HP_L_SMT_EN			(0x1 << 9)
+#define RT5659_HP_R_SMT_MASK			(0x1 << 8)
+#define RT5659_HP_R_SMT_SFT			8
+#define RT5659_HP_R_SMT_DIS			(0x0 << 8)
+#define RT5659_HP_R_SMT_EN			(0x1 << 8)
+#define RT5659_HP_CD_PD_MASK			(0x1 << 7)
+#define RT5659_HP_CD_PD_SFT			7
+#define RT5659_HP_CD_PD_DIS			(0x0 << 7)
+#define RT5659_HP_CD_PD_EN			(0x1 << 7)
+#define RT5659_RSTN_MASK			(0x1 << 6)
+#define RT5659_RSTN_SFT				6
+#define RT5659_RSTN_DIS				(0x0 << 6)
+#define RT5659_RSTN_EN				(0x1 << 6)
+#define RT5659_RSTP_MASK			(0x1 << 5)
+#define RT5659_RSTP_SFT				5
+#define RT5659_RSTP_DIS				(0x0 << 5)
+#define RT5659_RSTP_EN				(0x1 << 5)
+#define RT5659_HP_CO_MASK			(0x1 << 4)
+#define RT5659_HP_CO_SFT			4
+#define RT5659_HP_CO_DIS			(0x0 << 4)
+#define RT5659_HP_CO_EN				(0x1 << 4)
+#define RT5659_HP_CP_MASK			(0x1 << 3)
+#define RT5659_HP_CP_SFT			3
+#define RT5659_HP_CP_PD				(0x0 << 3)
+#define RT5659_HP_CP_PU				(0x1 << 3)
+#define RT5659_HP_SG_MASK			(0x1 << 2)
+#define RT5659_HP_SG_SFT			2
+#define RT5659_HP_SG_DIS			(0x0 << 2)
+#define RT5659_HP_SG_EN				(0x1 << 2)
+#define RT5659_HP_DP_MASK			(0x1 << 1)
+#define RT5659_HP_DP_SFT			1
+#define RT5659_HP_DP_PD				(0x0 << 1)
+#define RT5659_HP_DP_PU				(0x1 << 1)
+#define RT5659_HP_CB_MASK			(0x1)
+#define RT5659_HP_CB_SFT			0
+#define RT5659_HP_CB_PD				(0x0)
+#define RT5659_HP_CB_PU				(0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5659_DEPOP_MASK			(0x1 << 13)
+#define RT5659_DEPOP_SFT			13
+#define RT5659_DEPOP_AUTO			(0x0 << 13)
+#define RT5659_DEPOP_MAN			(0x1 << 13)
+#define RT5659_RAMP_MASK			(0x1 << 12)
+#define RT5659_RAMP_SFT				12
+#define RT5659_RAMP_DIS				(0x0 << 12)
+#define RT5659_RAMP_EN				(0x1 << 12)
+#define RT5659_BPS_MASK				(0x1 << 11)
+#define RT5659_BPS_SFT				11
+#define RT5659_BPS_DIS				(0x0 << 11)
+#define RT5659_BPS_EN				(0x1 << 11)
+#define RT5659_FAST_UPDN_MASK			(0x1 << 10)
+#define RT5659_FAST_UPDN_SFT			10
+#define RT5659_FAST_UPDN_DIS			(0x0 << 10)
+#define RT5659_FAST_UPDN_EN			(0x1 << 10)
+#define RT5659_MRES_MASK			(0x3 << 8)
+#define RT5659_MRES_SFT				8
+#define RT5659_MRES_15MO			(0x0 << 8)
+#define RT5659_MRES_25MO			(0x1 << 8)
+#define RT5659_MRES_35MO			(0x2 << 8)
+#define RT5659_MRES_45MO			(0x3 << 8)
+#define RT5659_VLO_MASK				(0x1 << 7)
+#define RT5659_VLO_SFT				7
+#define RT5659_VLO_3V				(0x0 << 7)
+#define RT5659_VLO_32V				(0x1 << 7)
+#define RT5659_DIG_DP_MASK			(0x1 << 6)
+#define RT5659_DIG_DP_SFT			6
+#define RT5659_DIG_DP_DIS			(0x0 << 6)
+#define RT5659_DIG_DP_EN			(0x1 << 6)
+#define RT5659_DP_TH_MASK			(0x3 << 4)
+#define RT5659_DP_TH_SFT			4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5659_CP_SYS_MASK			(0x7 << 12)
+#define RT5659_CP_SYS_SFT			12
+#define RT5659_CP_FQ1_MASK			(0x7 << 8)
+#define RT5659_CP_FQ1_SFT			8
+#define RT5659_CP_FQ2_MASK			(0x7 << 4)
+#define RT5659_CP_FQ2_SFT			4
+#define RT5659_CP_FQ3_MASK			(0x7)
+#define RT5659_CP_FQ3_SFT			0
+#define RT5659_CP_FQ_1_5_KHZ			0
+#define RT5659_CP_FQ_3_KHZ			1
+#define RT5659_CP_FQ_6_KHZ			2
+#define RT5659_CP_FQ_12_KHZ			3
+#define RT5659_CP_FQ_24_KHZ			4
+#define RT5659_CP_FQ_48_KHZ			5
+#define RT5659_CP_FQ_96_KHZ			6
+#define RT5659_CP_FQ_192_KHZ			7
+
+/* HPOUT charge pump 1 (0x0091) */
+#define RT5659_OSW_L_MASK			(0x1 << 11)
+#define RT5659_OSW_L_SFT			11
+#define RT5659_OSW_L_DIS			(0x0 << 11)
+#define RT5659_OSW_L_EN				(0x1 << 11)
+#define RT5659_OSW_R_MASK			(0x1 << 10)
+#define RT5659_OSW_R_SFT			10
+#define RT5659_OSW_R_DIS			(0x0 << 10)
+#define RT5659_OSW_R_EN				(0x1 << 10)
+#define RT5659_PM_HP_MASK			(0x3 << 8)
+#define RT5659_PM_HP_SFT			8
+#define RT5659_PM_HP_LV				(0x0 << 8)
+#define RT5659_PM_HP_MV				(0x1 << 8)
+#define RT5659_PM_HP_HV				(0x2 << 8)
+#define RT5659_IB_HP_MASK			(0x3 << 6)
+#define RT5659_IB_HP_SFT			6
+#define RT5659_IB_HP_125IL			(0x0 << 6)
+#define RT5659_IB_HP_25IL			(0x1 << 6)
+#define RT5659_IB_HP_5IL			(0x2 << 6)
+#define RT5659_IB_HP_1IL			(0x3 << 6)
+
+/* PV detection and SPK gain control (0x92) */
+#define RT5659_PVDD_DET_MASK			(0x1 << 15)
+#define RT5659_PVDD_DET_SFT			15
+#define RT5659_PVDD_DET_DIS			(0x0 << 15)
+#define RT5659_PVDD_DET_EN			(0x1 << 15)
+#define RT5659_SPK_AG_MASK			(0x1 << 14)
+#define RT5659_SPK_AG_SFT			14
+#define RT5659_SPK_AG_DIS			(0x0 << 14)
+#define RT5659_SPK_AG_EN			(0x1 << 14)
+
+/* Micbias Control (0x93) */
+#define RT5659_MIC1_BS_MASK			(0x1 << 15)
+#define RT5659_MIC1_BS_SFT			15
+#define RT5659_MIC1_BS_9AV			(0x0 << 15)
+#define RT5659_MIC1_BS_75AV			(0x1 << 15)
+#define RT5659_MIC2_BS_MASK			(0x1 << 14)
+#define RT5659_MIC2_BS_SFT			14
+#define RT5659_MIC2_BS_9AV			(0x0 << 14)
+#define RT5659_MIC2_BS_75AV			(0x1 << 14)
+#define RT5659_MIC1_CLK_MASK			(0x1 << 13)
+#define RT5659_MIC1_CLK_SFT			13
+#define RT5659_MIC1_CLK_DIS			(0x0 << 13)
+#define RT5659_MIC1_CLK_EN			(0x1 << 13)
+#define RT5659_MIC2_CLK_MASK			(0x1 << 12)
+#define RT5659_MIC2_CLK_SFT			12
+#define RT5659_MIC2_CLK_DIS			(0x0 << 12)
+#define RT5659_MIC2_CLK_EN			(0x1 << 12)
+#define RT5659_MIC1_OVCD_MASK			(0x1 << 11)
+#define RT5659_MIC1_OVCD_SFT			11
+#define RT5659_MIC1_OVCD_DIS			(0x0 << 11)
+#define RT5659_MIC1_OVCD_EN			(0x1 << 11)
+#define RT5659_MIC1_OVTH_MASK			(0x3 << 9)
+#define RT5659_MIC1_OVTH_SFT			9
+#define RT5659_MIC1_OVTH_600UA			(0x0 << 9)
+#define RT5659_MIC1_OVTH_1500UA			(0x1 << 9)
+#define RT5659_MIC1_OVTH_2000UA			(0x2 << 9)
+#define RT5659_MIC2_OVCD_MASK			(0x1 << 8)
+#define RT5659_MIC2_OVCD_SFT			8
+#define RT5659_MIC2_OVCD_DIS			(0x0 << 8)
+#define RT5659_MIC2_OVCD_EN			(0x1 << 8)
+#define RT5659_MIC2_OVTH_MASK			(0x3 << 6)
+#define RT5659_MIC2_OVTH_SFT			6
+#define RT5659_MIC2_OVTH_600UA			(0x0 << 6)
+#define RT5659_MIC2_OVTH_1500UA			(0x1 << 6)
+#define RT5659_MIC2_OVTH_2000UA			(0x2 << 6)
+#define RT5659_PWR_MB_MASK			(0x1 << 5)
+#define RT5659_PWR_MB_SFT			5
+#define RT5659_PWR_MB_PD			(0x0 << 5)
+#define RT5659_PWR_MB_PU			(0x1 << 5)
+#define RT5659_PWR_CLK25M_MASK			(0x1 << 4)
+#define RT5659_PWR_CLK25M_SFT			4
+#define RT5659_PWR_CLK25M_PD			(0x0 << 4)
+#define RT5659_PWR_CLK25M_PU			(0x1 << 4)
+
+/* REC Mixer 2 Left Control 2 (0x009c) */
+#define RT5659_M_BST1_RM2_L			(0x1 << 5)
+#define RT5659_M_BST1_RM2_L_SFT			5
+#define RT5659_M_BST2_RM2_L			(0x1 << 4)
+#define RT5659_M_BST2_RM2_L_SFT			4
+#define RT5659_M_BST3_RM2_L			(0x1 << 3)
+#define RT5659_M_BST3_RM2_L_SFT			3
+#define RT5659_M_BST4_RM2_L			(0x1 << 2)
+#define RT5659_M_BST4_RM2_L_SFT			2
+#define RT5659_M_OUTVOLL_RM2_L			(0x1 << 1)
+#define RT5659_M_OUTVOLL_RM2_L_SFT		1
+#define RT5659_M_SPKVOL_RM2_L			(0x1)
+#define RT5659_M_SPKVOL_RM2_L_SFT		0
+
+/* REC Mixer 2 Right Control 2 (0x009e) */
+#define RT5659_M_BST1_RM2_R			(0x1 << 5)
+#define RT5659_M_BST1_RM2_R_SFT			5
+#define RT5659_M_BST2_RM2_R			(0x1 << 4)
+#define RT5659_M_BST2_RM2_R_SFT			4
+#define RT5659_M_BST3_RM2_R			(0x1 << 3)
+#define RT5659_M_BST3_RM2_R_SFT			3
+#define RT5659_M_BST4_RM2_R			(0x1 << 2)
+#define RT5659_M_BST4_RM2_R_SFT			2
+#define RT5659_M_OUTVOLR_RM2_R			(0x1 << 1)
+#define RT5659_M_OUTVOLR_RM2_R_SFT		1
+#define RT5659_M_MONOVOL_RM2_R			(0x1)
+#define RT5659_M_MONOVOL_RM2_R_SFT		0
+
+/* Class D Output Control (0x00a0) */
+#define RT5659_POW_CLSD_DB_MASK			(0x1 << 9)
+#define RT5659_POW_CLSD_DB_EN			(0x1 << 9)
+#define RT5659_POW_CLSD_DB_DIS			(0x0 << 9)
+
+/* EQ Control 1 (0x00b0) */
+#define RT5659_EQ_SRC_DAC			(0x0 << 15)
+#define RT5659_EQ_SRC_ADC			(0x1 << 15)
+#define RT5659_EQ_UPD				(0x1 << 14)
+#define RT5659_EQ_UPD_BIT			14
+#define RT5659_EQ_CD_MASK			(0x1 << 13)
+#define RT5659_EQ_CD_SFT			13
+#define RT5659_EQ_CD_DIS			(0x0 << 13)
+#define RT5659_EQ_CD_EN				(0x1 << 13)
+#define RT5659_EQ_DITH_MASK			(0x3 << 8)
+#define RT5659_EQ_DITH_SFT			8
+#define RT5659_EQ_DITH_NOR			(0x0 << 8)
+#define RT5659_EQ_DITH_LSB			(0x1 << 8)
+#define RT5659_EQ_DITH_LSB_1			(0x2 << 8)
+#define RT5659_EQ_DITH_LSB_2			(0x3 << 8)
+
+/* IRQ Control 1 (0x00b7) */
+#define RT5659_JD1_1_EN_MASK			(0x1 << 15)
+#define RT5659_JD1_1_EN_SFT			15
+#define RT5659_JD1_1_DIS			(0x0 << 15)
+#define RT5659_JD1_1_EN				(0x1 << 15)
+#define RT5659_JD1_2_EN_MASK			(0x1 << 12)
+#define RT5659_JD1_2_EN_SFT			12
+#define RT5659_JD1_2_DIS			(0x0 << 12)
+#define RT5659_JD1_2_EN				(0x1 << 12)
+#define RT5659_IL_IRQ_MASK			(0x1 << 3)
+#define RT5659_IL_IRQ_DIS			(0x0 << 3)
+#define RT5659_IL_IRQ_EN			(0x1 << 3)
+
+/* IRQ Control 5 (0x00ba) */
+#define RT5659_IRQ_JD_EN			(0x1 << 3)
+#define RT5659_IRQ_JD_EN_SFT			3
+
+/* GPIO Control 1 (0x00c0) */
+#define RT5659_GP1_PIN_MASK			(0x1 << 15)
+#define RT5659_GP1_PIN_SFT			15
+#define RT5659_GP1_PIN_GPIO1			(0x0 << 15)
+#define RT5659_GP1_PIN_IRQ			(0x1 << 15)
+#define RT5659_GP2_PIN_MASK			(0x1 << 14)
+#define RT5659_GP2_PIN_SFT			14
+#define RT5659_GP2_PIN_GPIO2			(0x0 << 14)
+#define RT5659_GP2_PIN_DMIC1_SCL		(0x1 << 14)
+#define RT5659_GP3_PIN_MASK			(0x1 << 13)
+#define RT5659_GP3_PIN_SFT			13
+#define RT5659_GP3_PIN_GPIO3			(0x0 << 13)
+#define RT5659_GP3_PIN_PDM_SCL			(0x1 << 13)
+#define RT5659_GP4_PIN_MASK			(0x1 << 12)
+#define RT5659_GP4_PIN_SFT			12
+#define RT5659_GP4_PIN_GPIO4			(0x0 << 12)
+#define RT5659_GP4_PIN_PDM_SDA			(0x1 << 12)
+#define RT5659_GP5_PIN_MASK			(0x1 << 11)
+#define RT5659_GP5_PIN_SFT			11
+#define RT5659_GP5_PIN_GPIO5			(0x0 << 11)
+#define RT5659_GP5_PIN_DMIC1_SDA		(0x1 << 11)
+#define RT5659_GP6_PIN_MASK			(0x1 << 10)
+#define RT5659_GP6_PIN_SFT			10
+#define RT5659_GP6_PIN_GPIO6			(0x0 << 10)
+#define RT5659_GP6_PIN_DMIC2_SDA		(0x1 << 10)
+#define RT5659_GP7_PIN_MASK			(0x1 << 9)
+#define RT5659_GP7_PIN_SFT			9
+#define RT5659_GP7_PIN_GPIO7			(0x0 << 9)
+#define RT5659_GP7_PIN_PDM_SCL			(0x1 << 9)
+#define RT5659_GP8_PIN_MASK			(0x1 << 8)
+#define RT5659_GP8_PIN_SFT			8
+#define RT5659_GP8_PIN_GPIO8			(0x0 << 8)
+#define RT5659_GP8_PIN_PDM_SDA			(0x1 << 8)
+#define RT5659_GP9_PIN_MASK			(0x1 << 7)
+#define RT5659_GP9_PIN_SFT			7
+#define RT5659_GP9_PIN_GPIO9			(0x0 << 7)
+#define RT5659_GP9_PIN_DMIC1_SDA		(0x1 << 7)
+#define RT5659_GP10_PIN_MASK			(0x1 << 6)
+#define RT5659_GP10_PIN_SFT			6
+#define RT5659_GP10_PIN_GPIO10			(0x0 << 6)
+#define RT5659_GP10_PIN_DMIC2_SDA		(0x1 << 6)
+#define RT5659_GP11_PIN_MASK			(0x1 << 5)
+#define RT5659_GP11_PIN_SFT			5
+#define RT5659_GP11_PIN_GPIO11			(0x0 << 5)
+#define RT5659_GP11_PIN_DMIC1_SDA		(0x1 << 5)
+#define RT5659_GP12_PIN_MASK			(0x1 << 4)
+#define RT5659_GP12_PIN_SFT			4
+#define RT5659_GP12_PIN_GPIO12			(0x0 << 4)
+#define RT5659_GP12_PIN_DMIC2_SDA		(0x1 << 4)
+#define RT5659_GP13_PIN_MASK			(0x3 << 2)
+#define RT5659_GP13_PIN_SFT			2
+#define RT5659_GP13_PIN_GPIO13			(0x0 << 2)
+#define RT5659_GP13_PIN_SPDIF_SDA		(0x1 << 2)
+#define RT5659_GP13_PIN_DMIC2_SCL		(0x2 << 2)
+#define RT5659_GP13_PIN_PDM_SCL			(0x3 << 2)
+#define RT5659_GP15_PIN_MASK			(0x3)
+#define RT5659_GP15_PIN_SFT			0
+#define RT5659_GP15_PIN_GPIO15			(0x0)
+#define RT5659_GP15_PIN_DMIC3_SCL		(0x1)
+#define RT5659_GP15_PIN_PDM_SDA			(0x2)
+
+/* GPIO Control 2 (0x00c1)*/
+#define RT5659_GP1_PF_IN			(0x0 << 2)
+#define RT5659_GP1_PF_OUT			(0x1 << 2)
+#define RT5659_GP1_PF_MASK			(0x1 << 2)
+#define RT5659_GP1_PF_SFT			2
+
+/* GPIO Control 3 (0x00c2) */
+#define RT5659_I2S2_PIN_MASK			(0x1 << 15)
+#define RT5659_I2S2_PIN_SFT			15
+#define RT5659_I2S2_PIN_I2S			(0x0 << 15)
+#define RT5659_I2S2_PIN_GPIO			(0x1 << 15)
+
+/* Soft volume and zero cross control 1 (0x00d9) */
+#define RT5659_SV_MASK				(0x1 << 15)
+#define RT5659_SV_SFT				15
+#define RT5659_SV_DIS				(0x0 << 15)
+#define RT5659_SV_EN				(0x1 << 15)
+#define RT5659_OUT_SV_MASK			(0x1 << 13)
+#define RT5659_OUT_SV_SFT			13
+#define RT5659_OUT_SV_DIS			(0x0 << 13)
+#define RT5659_OUT_SV_EN			(0x1 << 13)
+#define RT5659_HP_SV_MASK			(0x1 << 12)
+#define RT5659_HP_SV_SFT			12
+#define RT5659_HP_SV_DIS			(0x0 << 12)
+#define RT5659_HP_SV_EN				(0x1 << 12)
+#define RT5659_ZCD_DIG_MASK			(0x1 << 11)
+#define RT5659_ZCD_DIG_SFT			11
+#define RT5659_ZCD_DIG_DIS			(0x0 << 11)
+#define RT5659_ZCD_DIG_EN			(0x1 << 11)
+#define RT5659_ZCD_MASK				(0x1 << 10)
+#define RT5659_ZCD_SFT				10
+#define RT5659_ZCD_PD				(0x0 << 10)
+#define RT5659_ZCD_PU				(0x1 << 10)
+#define RT5659_SV_DLY_MASK			(0xf)
+#define RT5659_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0x00da) */
+#define RT5659_ZCD_HP_MASK			(0x1 << 15)
+#define RT5659_ZCD_HP_SFT			15
+#define RT5659_ZCD_HP_DIS			(0x0 << 15)
+#define RT5659_ZCD_HP_EN			(0x1 << 15)
+
+/* 4 Button Inline Command Control 2 (0x00e0) */
+#define RT5659_4BTN_IL_MASK			(0x1 << 15)
+#define RT5659_4BTN_IL_EN			(0x1 << 15)
+#define RT5659_4BTN_IL_DIS			(0x0 << 15)
+
+/* Analog JD Control 1 (0x00f0) */
+#define RT5659_JD1_MODE_MASK			(0x3 << 0)
+#define RT5659_JD1_MODE_0			(0x0 << 0)
+#define RT5659_JD1_MODE_1			(0x1 << 0)
+#define RT5659_JD1_MODE_2			(0x2 << 0)
+
+/* Jack Detect Control 3 (0x00f8) */
+#define RT5659_JD_TRI_HPO_SEL_MASK		(0x7)
+#define RT5659_JD_TRI_HPO_SEL_SFT		(0)
+#define RT5659_JD_HPO_GPIO_JD1			(0x0)
+#define RT5659_JD_HPO_JD1_1			(0x1)
+#define RT5659_JD_HPO_JD1_2			(0x2)
+#define RT5659_JD_HPO_JD2			(0x3)
+#define RT5659_JD_HPO_GPIO_JD2			(0x4)
+#define RT5659_JD_HPO_JD3			(0x5)
+#define RT5659_JD_HPO_JD_D			(0x6)
+
+/* Digital Misc Control (0x00fa) */
+#define RT5659_AM_MASK				(0x1 << 7)
+#define RT5659_AM_EN				(0x1 << 7)
+#define RT5659_AM_DIS				(0x1 << 7)
+#define RT5659_DIG_GATE_CTRL			0x1
+#define RT5659_DIG_GATE_CTRL_SFT		(0)
+
+/* Chopper and Clock control for ADC (0x011c)*/
+#define RT5659_M_RF_DIG_MASK			(0x1 << 12)
+#define RT5659_M_RF_DIG_SFT			12
+#define RT5659_M_RI_DIG				(0x1 << 11)
+
+/* Chopper and Clock control for DAC (0x013a)*/
+#define RT5659_CKXEN_DAC1_MASK			(0x1 << 13)
+#define RT5659_CKXEN_DAC1_SFT			13
+#define RT5659_CKGEN_DAC1_MASK			(0x1 << 12)
+#define RT5659_CKGEN_DAC1_SFT			12
+#define RT5659_CKXEN_DAC2_MASK			(0x1 << 5)
+#define RT5659_CKXEN_DAC2_SFT			5
+#define RT5659_CKGEN_DAC2_MASK			(0x1 << 4)
+#define RT5659_CKGEN_DAC2_SFT			4
+
+/* Chopper and Clock control for ADC (0x013b)*/
+#define RT5659_CKXEN_ADC1_MASK			(0x1 << 13)
+#define RT5659_CKXEN_ADC1_SFT			13
+#define RT5659_CKGEN_ADC1_MASK			(0x1 << 12)
+#define RT5659_CKGEN_ADC1_SFT			12
+#define RT5659_CKXEN_ADC2_MASK			(0x1 << 5)
+#define RT5659_CKXEN_ADC2_SFT			5
+#define RT5659_CKGEN_ADC2_MASK			(0x1 << 4)
+#define RT5659_CKGEN_ADC2_SFT			4
+
+/* Test Mode Control 1 (0x0145) */
+#define RT5659_AD2DA_LB_MASK			(0x1 << 9)
+#define RT5659_AD2DA_LB_SFT			9
+
+/* Stereo Noise Gate Control 1 (0x0160) */
+#define RT5659_NG2_EN_MASK			(0x1 << 15)
+#define RT5659_NG2_EN				(0x1 << 15)
+#define RT5659_NG2_DIS				(0x0 << 15)
+
+/* System Clock Source */
+enum {
+	RT5659_SCLK_S_MCLK,
+	RT5659_SCLK_S_PLL1,
+	RT5659_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+	RT5659_PLL1_S_MCLK,
+	RT5659_PLL1_S_BCLK1,
+	RT5659_PLL1_S_BCLK2,
+	RT5659_PLL1_S_BCLK3,
+	RT5659_PLL1_S_BCLK4,
+};
+
+enum {
+	RT5659_AIF1,
+	RT5659_AIF2,
+	RT5659_AIF3,
+	RT5659_AIF4,
+	RT5659_AIFS,
+};
+
+struct rt5659_pll_code {
+	bool m_bp;
+	int m_code;
+	int n_code;
+	int k_code;
+};
+
+struct rt5659_priv {
+	struct snd_soc_component *component;
+	struct rt5659_platform_data pdata;
+	struct regmap *regmap;
+	struct gpio_desc *gpiod_ldo1_en;
+	struct gpio_desc *gpiod_reset;
+	struct snd_soc_jack *hs_jack;
+	struct delayed_work jack_detect_work;
+	struct clk *mclk;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5659_AIFS];
+	int bclk[RT5659_AIFS];
+	int master[RT5659_AIFS];
+	int v_id;
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+	int jack_type;
+	bool hda_hp_plugged;
+	bool hda_mic_plugged;
+};
+
+int rt5659_set_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *hs_jack);
+
+#endif /* __RT5659_H__ */
diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c
new file mode 100644
index 0000000..20a7551
--- /dev/null
+++ b/sound/soc/codecs/rt5660.c
@@ -0,0 +1,1350 @@
+/*
+ * rt5660.c  --  RT5660 ALSA SoC audio codec driver
+ *
+ * Copyright 2016 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rl6231.h"
+#include "rt5660.h"
+
+#define RT5660_DEVICE_ID 0x6338
+
+#define RT5660_PR_RANGE_BASE (0xff + 1)
+#define RT5660_PR_SPACING 0x100
+
+#define RT5660_PR_BASE (RT5660_PR_RANGE_BASE + (0 * RT5660_PR_SPACING))
+
+static const struct regmap_range_cfg rt5660_ranges[] = {
+	{ .name = "PR", .range_min = RT5660_PR_BASE,
+	  .range_max = RT5660_PR_BASE + 0xf3,
+	  .selector_reg = RT5660_PRIV_INDEX,
+	  .selector_mask = 0xff,
+	  .selector_shift = 0x0,
+	  .window_start = RT5660_PRIV_DATA,
+	  .window_len = 0x1, },
+};
+
+static const struct reg_sequence rt5660_patch[] = {
+	{ RT5660_ALC_PGA_CTRL2,		0x44c3 },
+	{ RT5660_PR_BASE + 0x3d,	0x2600 },
+};
+
+static const struct reg_default rt5660_reg[] = {
+	{ 0x00, 0x0000 },
+	{ 0x01, 0xc800 },
+	{ 0x02, 0xc8c8 },
+	{ 0x0d, 0x1010 },
+	{ 0x0e, 0x1010 },
+	{ 0x19, 0xafaf },
+	{ 0x1c, 0x2f2f },
+	{ 0x1e, 0x0000 },
+	{ 0x27, 0x6060 },
+	{ 0x29, 0x8080 },
+	{ 0x2a, 0x4242 },
+	{ 0x2f, 0x0000 },
+	{ 0x3b, 0x0000 },
+	{ 0x3c, 0x007f },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x007f },
+	{ 0x45, 0xe000 },
+	{ 0x46, 0x003e },
+	{ 0x48, 0xf800 },
+	{ 0x4a, 0x0004 },
+	{ 0x4d, 0x0000 },
+	{ 0x4e, 0x0000 },
+	{ 0x4f, 0x01ff },
+	{ 0x50, 0x0000 },
+	{ 0x51, 0x0000 },
+	{ 0x52, 0x01ff },
+	{ 0x61, 0x0000 },
+	{ 0x62, 0x0000 },
+	{ 0x63, 0x00c0 },
+	{ 0x64, 0x0000 },
+	{ 0x65, 0x0000 },
+	{ 0x66, 0x0000 },
+	{ 0x70, 0x8000 },
+	{ 0x73, 0x7000 },
+	{ 0x74, 0x3c00 },
+	{ 0x75, 0x2800 },
+	{ 0x80, 0x0000 },
+	{ 0x81, 0x0000 },
+	{ 0x82, 0x0000 },
+	{ 0x8c, 0x0228 },
+	{ 0x8d, 0xa000 },
+	{ 0x8e, 0x0000 },
+	{ 0x92, 0x0000 },
+	{ 0x93, 0x3000 },
+	{ 0xa1, 0x0059 },
+	{ 0xa2, 0x0001 },
+	{ 0xa3, 0x5c80 },
+	{ 0xa4, 0x0146 },
+	{ 0xa5, 0x1f1f },
+	{ 0xa6, 0x78c6 },
+	{ 0xa7, 0xe5ec },
+	{ 0xa8, 0xba61 },
+	{ 0xa9, 0x3c78 },
+	{ 0xaa, 0x8ae2 },
+	{ 0xab, 0xe5ec },
+	{ 0xac, 0xc600 },
+	{ 0xad, 0xba61 },
+	{ 0xae, 0x17ed },
+	{ 0xb0, 0x2080 },
+	{ 0xb1, 0x0000 },
+	{ 0xb3, 0x001f },
+	{ 0xb4, 0x020c },
+	{ 0xb5, 0x1f00 },
+	{ 0xb6, 0x0000 },
+	{ 0xb7, 0x4000 },
+	{ 0xbb, 0x0000 },
+	{ 0xbd, 0x0000 },
+	{ 0xbe, 0x0000 },
+	{ 0xbf, 0x0100 },
+	{ 0xc0, 0x0000 },
+	{ 0xc2, 0x0000 },
+	{ 0xd3, 0xa220 },
+	{ 0xd9, 0x0809 },
+	{ 0xda, 0x0000 },
+	{ 0xe0, 0x8000 },
+	{ 0xe1, 0x0200 },
+	{ 0xe2, 0x8000 },
+	{ 0xe3, 0x0200 },
+	{ 0xe4, 0x0f20 },
+	{ 0xe5, 0x001f },
+	{ 0xe6, 0x020c },
+	{ 0xe7, 0x1f00 },
+	{ 0xe8, 0x0000 },
+	{ 0xe9, 0x4000 },
+	{ 0xea, 0x00a6 },
+	{ 0xeb, 0x04c3 },
+	{ 0xec, 0x27c8 },
+	{ 0xed, 0x7418 },
+	{ 0xee, 0xbf50 },
+	{ 0xef, 0x0045 },
+	{ 0xf0, 0x0007 },
+	{ 0xfa, 0x0000 },
+	{ 0xfd, 0x0000 },
+	{ 0xfe, 0x10ec },
+	{ 0xff, 0x6338 },
+};
+
+static bool rt5660_volatile_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5660_ranges); i++)
+		if ((reg >= rt5660_ranges[i].window_start &&
+		     reg <= rt5660_ranges[i].window_start +
+		     rt5660_ranges[i].window_len) ||
+		    (reg >= rt5660_ranges[i].range_min &&
+		     reg <= rt5660_ranges[i].range_max))
+			return true;
+
+	switch (reg) {
+	case RT5660_RESET:
+	case RT5660_PRIV_DATA:
+	case RT5660_EQ_CTRL1:
+	case RT5660_IRQ_CTRL2:
+	case RT5660_INT_IRQ_ST:
+	case RT5660_VENDOR_ID:
+	case RT5660_VENDOR_ID1:
+	case RT5660_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5660_readable_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5660_ranges); i++)
+		if ((reg >= rt5660_ranges[i].window_start &&
+		     reg <= rt5660_ranges[i].window_start +
+		     rt5660_ranges[i].window_len) ||
+		    (reg >= rt5660_ranges[i].range_min &&
+		     reg <= rt5660_ranges[i].range_max))
+			return true;
+
+	switch (reg) {
+	case RT5660_RESET:
+	case RT5660_SPK_VOL:
+	case RT5660_LOUT_VOL:
+	case RT5660_IN1_IN2:
+	case RT5660_IN3_IN4:
+	case RT5660_DAC1_DIG_VOL:
+	case RT5660_STO1_ADC_DIG_VOL:
+	case RT5660_ADC_BST_VOL1:
+	case RT5660_STO1_ADC_MIXER:
+	case RT5660_AD_DA_MIXER:
+	case RT5660_STO_DAC_MIXER:
+	case RT5660_DIG_INF1_DATA:
+	case RT5660_REC_L1_MIXER:
+	case RT5660_REC_L2_MIXER:
+	case RT5660_REC_R1_MIXER:
+	case RT5660_REC_R2_MIXER:
+	case RT5660_LOUT_MIXER:
+	case RT5660_SPK_MIXER:
+	case RT5660_SPO_MIXER:
+	case RT5660_SPO_CLSD_RATIO:
+	case RT5660_OUT_L_GAIN1:
+	case RT5660_OUT_L_GAIN2:
+	case RT5660_OUT_L1_MIXER:
+	case RT5660_OUT_R_GAIN1:
+	case RT5660_OUT_R_GAIN2:
+	case RT5660_OUT_R1_MIXER:
+	case RT5660_PWR_DIG1:
+	case RT5660_PWR_DIG2:
+	case RT5660_PWR_ANLG1:
+	case RT5660_PWR_ANLG2:
+	case RT5660_PWR_MIXER:
+	case RT5660_PWR_VOL:
+	case RT5660_PRIV_INDEX:
+	case RT5660_PRIV_DATA:
+	case RT5660_I2S1_SDP:
+	case RT5660_ADDA_CLK1:
+	case RT5660_ADDA_CLK2:
+	case RT5660_DMIC_CTRL1:
+	case RT5660_GLB_CLK:
+	case RT5660_PLL_CTRL1:
+	case RT5660_PLL_CTRL2:
+	case RT5660_CLSD_AMP_OC_CTRL:
+	case RT5660_CLSD_AMP_CTRL:
+	case RT5660_LOUT_AMP_CTRL:
+	case RT5660_SPK_AMP_SPKVDD:
+	case RT5660_MICBIAS:
+	case RT5660_CLSD_OUT_CTRL1:
+	case RT5660_CLSD_OUT_CTRL2:
+	case RT5660_DIPOLE_MIC_CTRL1:
+	case RT5660_DIPOLE_MIC_CTRL2:
+	case RT5660_DIPOLE_MIC_CTRL3:
+	case RT5660_DIPOLE_MIC_CTRL4:
+	case RT5660_DIPOLE_MIC_CTRL5:
+	case RT5660_DIPOLE_MIC_CTRL6:
+	case RT5660_DIPOLE_MIC_CTRL7:
+	case RT5660_DIPOLE_MIC_CTRL8:
+	case RT5660_DIPOLE_MIC_CTRL9:
+	case RT5660_DIPOLE_MIC_CTRL10:
+	case RT5660_DIPOLE_MIC_CTRL11:
+	case RT5660_DIPOLE_MIC_CTRL12:
+	case RT5660_EQ_CTRL1:
+	case RT5660_EQ_CTRL2:
+	case RT5660_DRC_AGC_CTRL1:
+	case RT5660_DRC_AGC_CTRL2:
+	case RT5660_DRC_AGC_CTRL3:
+	case RT5660_DRC_AGC_CTRL4:
+	case RT5660_DRC_AGC_CTRL5:
+	case RT5660_JD_CTRL:
+	case RT5660_IRQ_CTRL1:
+	case RT5660_IRQ_CTRL2:
+	case RT5660_INT_IRQ_ST:
+	case RT5660_GPIO_CTRL1:
+	case RT5660_GPIO_CTRL2:
+	case RT5660_WIND_FILTER_CTRL1:
+	case RT5660_SV_ZCD1:
+	case RT5660_SV_ZCD2:
+	case RT5660_DRC1_LM_CTRL1:
+	case RT5660_DRC1_LM_CTRL2:
+	case RT5660_DRC2_LM_CTRL1:
+	case RT5660_DRC2_LM_CTRL2:
+	case RT5660_MULTI_DRC_CTRL:
+	case RT5660_DRC2_CTRL1:
+	case RT5660_DRC2_CTRL2:
+	case RT5660_DRC2_CTRL3:
+	case RT5660_DRC2_CTRL4:
+	case RT5660_DRC2_CTRL5:
+	case RT5660_ALC_PGA_CTRL1:
+	case RT5660_ALC_PGA_CTRL2:
+	case RT5660_ALC_PGA_CTRL3:
+	case RT5660_ALC_PGA_CTRL4:
+	case RT5660_ALC_PGA_CTRL5:
+	case RT5660_ALC_PGA_CTRL6:
+	case RT5660_ALC_PGA_CTRL7:
+	case RT5660_GEN_CTRL1:
+	case RT5660_GEN_CTRL2:
+	case RT5660_GEN_CTRL3:
+	case RT5660_VENDOR_ID:
+	case RT5660_VENDOR_ID1:
+	case RT5660_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(rt5660_out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(rt5660_dac_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(rt5660_adc_vol_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(rt5660_adc_bst_tlv, 0, 1200, 0);
+static const DECLARE_TLV_DB_SCALE(rt5660_bst_tlv, -1200, 75, 0);
+
+static const struct snd_kcontrol_new rt5660_snd_controls[] = {
+	/* Speaker Output Volume */
+	SOC_SINGLE("Speaker Playback Switch", RT5660_SPK_VOL, RT5660_L_MUTE_SFT,
+		1, 1),
+	SOC_SINGLE_TLV("Speaker Playback Volume", RT5660_SPK_VOL,
+		RT5660_L_VOL_SFT, 39, 1, rt5660_out_vol_tlv),
+
+	/* OUTPUT Control */
+	SOC_DOUBLE("OUT Playback Switch", RT5660_LOUT_VOL, RT5660_L_MUTE_SFT,
+		RT5660_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("OUT Playback Volume", RT5660_LOUT_VOL, RT5660_L_VOL_SFT,
+		RT5660_R_VOL_SFT, 39, 1, rt5660_out_vol_tlv),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5660_DAC1_DIG_VOL,
+		RT5660_DAC_L1_VOL_SFT, RT5660_DAC_R1_VOL_SFT, 87, 0,
+		rt5660_dac_vol_tlv),
+
+	/* IN1/IN2/IN3 Control */
+	SOC_SINGLE_TLV("IN1 Boost Volume", RT5660_IN1_IN2, RT5660_BST_SFT1, 69,
+		0, rt5660_bst_tlv),
+	SOC_SINGLE_TLV("IN2 Boost Volume", RT5660_IN1_IN2, RT5660_BST_SFT2, 69,
+		0, rt5660_bst_tlv),
+	SOC_SINGLE_TLV("IN3 Boost Volume", RT5660_IN3_IN4, RT5660_BST_SFT3, 69,
+		0, rt5660_bst_tlv),
+
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("ADC Capture Switch", RT5660_STO1_ADC_DIG_VOL,
+		RT5660_L_MUTE_SFT, RT5660_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("ADC Capture Volume", RT5660_STO1_ADC_DIG_VOL,
+		RT5660_ADC_L_VOL_SFT, RT5660_ADC_R_VOL_SFT, 63, 0,
+		rt5660_adc_vol_tlv),
+
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5660_ADC_BST_VOL1,
+		RT5660_STO1_ADC_L_BST_SFT, RT5660_STO1_ADC_R_BST_SFT, 3, 0,
+		rt5660_adc_bst_tlv),
+};
+
+/**
+ * rt5660_set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ */
+static int rt5660_set_dmic_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
+	int idx, rate;
+
+	rate = rt5660->sysclk / rl6231_get_pre_div(rt5660->regmap,
+		RT5660_ADDA_CLK1, RT5660_I2S_PD1_SFT);
+	idx = rl6231_calc_dmic_clk(rate);
+	if (idx < 0)
+		dev_err(component->dev, "Failed to set DMIC clock\n");
+	else
+		snd_soc_component_update_bits(component, RT5660_DMIC_CTRL1,
+			RT5660_DMIC_CLK_MASK, idx << RT5660_DMIC_CLK_SFT);
+
+	return idx;
+}
+
+static int rt5660_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	unsigned int val;
+
+	val = snd_soc_component_read32(component, RT5660_GLB_CLK);
+	val &= RT5660_SCLK_SRC_MASK;
+	if (val == RT5660_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5660_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5660_STO1_ADC_MIXER,
+			RT5660_M_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5660_STO1_ADC_MIXER,
+			RT5660_M_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5660_STO1_ADC_MIXER,
+			RT5660_M_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5660_STO1_ADC_MIXER,
+			RT5660_M_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5660_AD_DA_MIXER,
+			RT5660_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5660_AD_DA_MIXER,
+			RT5660_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5660_AD_DA_MIXER,
+			RT5660_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5660_AD_DA_MIXER,
+			RT5660_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_sto_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5660_STO_DAC_MIXER,
+			RT5660_M_DAC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5660_STO_DAC_MIXER,
+			RT5660_M_DAC_R1_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_sto_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5660_STO_DAC_MIXER,
+			RT5660_M_DAC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5660_STO_DAC_MIXER,
+			RT5660_M_DAC_L1_STO_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5660_rec_l_mix[] = {
+	SOC_DAPM_SINGLE("BST3 Switch", RT5660_REC_L2_MIXER,
+			RT5660_M_BST3_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5660_REC_L2_MIXER,
+			RT5660_M_BST2_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_REC_L2_MIXER,
+			RT5660_M_BST1_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUT MIXL Switch", RT5660_REC_L2_MIXER,
+			RT5660_M_OM_L_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_rec_r_mix[] = {
+	SOC_DAPM_SINGLE("BST3 Switch", RT5660_REC_R2_MIXER,
+			RT5660_M_BST3_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5660_REC_R2_MIXER,
+			RT5660_M_BST2_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_REC_R2_MIXER,
+			RT5660_M_BST1_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUT MIXR Switch", RT5660_REC_R2_MIXER,
+			RT5660_M_OM_R_RM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_spk_mix[] = {
+	SOC_DAPM_SINGLE("BST3 Switch", RT5660_SPK_MIXER,
+			RT5660_M_BST3_SM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_SPK_MIXER,
+			RT5660_M_BST1_SM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACL Switch", RT5660_SPK_MIXER,
+			RT5660_M_DACL_SM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACR Switch", RT5660_SPK_MIXER,
+			RT5660_M_DACR_SM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTMIXL Switch", RT5660_SPK_MIXER,
+			RT5660_M_OM_L_SM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_out_l_mix[] = {
+	SOC_DAPM_SINGLE("BST3 Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_BST3_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_BST2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_BST1_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("RECMIXL Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_RM_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACR Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_DAC_R_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACL Switch", RT5660_OUT_L1_MIXER,
+			RT5660_M_DAC_L_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_out_r_mix[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_BST2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_BST1_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("RECMIXR Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_RM_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACR Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_DAC_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACL Switch", RT5660_OUT_R1_MIXER,
+			RT5660_M_DAC_L_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_spo_mix[] = {
+	SOC_DAPM_SINGLE("DACR Switch", RT5660_SPO_MIXER,
+			RT5660_M_DAC_R_SPM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DACL Switch", RT5660_SPO_MIXER,
+			RT5660_M_DAC_L_SPM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("SPKVOL Switch", RT5660_SPO_MIXER,
+			RT5660_M_SV_SPM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5660_SPO_MIXER,
+			RT5660_M_BST1_SPM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5660_lout_mix[] = {
+	SOC_DAPM_SINGLE("DAC Switch", RT5660_LOUT_MIXER,
+			RT5660_M_DAC1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTMIX Switch", RT5660_LOUT_MIXER,
+			RT5660_M_LOVOL_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new spk_vol_control =
+	SOC_DAPM_SINGLE("Switch", RT5660_SPK_VOL,
+		RT5660_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_l_vol_control =
+	SOC_DAPM_SINGLE("Switch", RT5660_LOUT_VOL,
+		RT5660_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_r_vol_control =
+	SOC_DAPM_SINGLE("Switch", RT5660_LOUT_VOL,
+		RT5660_VOL_R_SFT, 1, 1);
+
+/* Interface data select */
+static const char * const rt5660_data_select[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5660_if1_dac_enum,
+	RT5660_DIG_INF1_DATA, RT5660_IF1_DAC_IN_SFT, rt5660_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5660_if1_adc_enum,
+	RT5660_DIG_INF1_DATA, RT5660_IF1_ADC_IN_SFT, rt5660_data_select);
+
+static const struct snd_kcontrol_new rt5660_if1_dac_swap_mux =
+	SOC_DAPM_ENUM("IF1 DAC Swap Source", rt5660_if1_dac_enum);
+
+static const struct snd_kcontrol_new rt5660_if1_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC Swap Source", rt5660_if1_adc_enum);
+
+static int rt5660_lout_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5660_LOUT_AMP_CTRL,
+			RT5660_LOUT_CO_MASK | RT5660_LOUT_CB_MASK,
+			RT5660_LOUT_CO_EN | RT5660_LOUT_CB_PU);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5660_LOUT_AMP_CTRL,
+			RT5660_LOUT_CO_MASK | RT5660_LOUT_CB_MASK,
+			RT5660_LOUT_CO_DIS | RT5660_LOUT_CB_PD);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5660_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("LDO2", RT5660_PWR_ANLG1,
+		RT5660_PWR_LDO2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL1", RT5660_PWR_ANLG2,
+		RT5660_PWR_PLL_BIT, 0, NULL, 0),
+
+	/* MICBIAS */
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5660_PWR_ANLG2,
+			RT5660_PWR_MB1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5660_PWR_ANLG2,
+			RT5660_PWR_MB2_BIT, 0, NULL, 0),
+
+	/* Input Side */
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC L1"),
+	SND_SOC_DAPM_INPUT("DMIC R1"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN1N"),
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN3P"),
+	SND_SOC_DAPM_INPUT("IN3N"),
+
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+		rt5660_set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC Power", RT5660_DMIC_CTRL1,
+		RT5660_DMIC_1_EN_SFT, 0, NULL, 0),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1", RT5660_PWR_ANLG2, RT5660_PWR_BST1_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("BST2", RT5660_PWR_ANLG2, RT5660_PWR_BST2_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("BST3", RT5660_PWR_ANLG2, RT5660_PWR_BST3_BIT, 0,
+		NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIXL", RT5660_PWR_MIXER, RT5660_PWR_RM_L_BIT,
+			0, rt5660_rec_l_mix, ARRAY_SIZE(rt5660_rec_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIXR", RT5660_PWR_MIXER, RT5660_PWR_RM_R_BIT,
+			0, rt5660_rec_r_mix, ARRAY_SIZE(rt5660_rec_r_mix)),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC L power", RT5660_PWR_DIG1,
+			RT5660_PWR_ADC_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC R power", RT5660_PWR_DIG1,
+			RT5660_PWR_ADC_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC clock", RT5660_PR_BASE + RT5660_CHOP_DAC_ADC,
+			12, 0, NULL, 0),
+
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("adc stereo1 filter", RT5660_PWR_DIG2,
+		RT5660_PWR_ADC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5660_sto1_adc_l_mix, ARRAY_SIZE(rt5660_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5660_sto1_adc_r_mix, ARRAY_SIZE(rt5660_sto1_adc_r_mix)),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC("Stereo1 ADC MIXL", NULL, RT5660_STO1_ADC_DIG_VOL,
+		RT5660_L_MUTE_SFT, 1),
+	SND_SOC_DAPM_ADC("Stereo1 ADC MIXR", NULL, RT5660_STO1_ADC_DIG_VOL,
+		RT5660_R_MUTE_SFT, 1),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5660_PWR_DIG1, RT5660_PWR_I2S1_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("IF1 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5660_if1_dac_swap_mux),
+	SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("IF1 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5660_if1_adc_swap_mux),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Side */
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, rt5660_dac_l_mix,
+		ARRAY_SIZE(rt5660_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, rt5660_dac_r_mix,
+		ARRAY_SIZE(rt5660_dac_r_mix)),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5660_PWR_DIG2,
+		RT5660_PWR_DAC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5660_sto_dac_l_mix, ARRAY_SIZE(rt5660_sto_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5660_sto_dac_r_mix, ARRAY_SIZE(rt5660_sto_dac_r_mix)),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC L1", NULL, RT5660_PWR_DIG1,
+			RT5660_PWR_DAC_L1_BIT, 0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, RT5660_PWR_DIG1,
+			RT5660_PWR_DAC_R1_BIT, 0),
+
+	/* OUT Mixer */
+	SND_SOC_DAPM_MIXER("SPK MIX", RT5660_PWR_MIXER, RT5660_PWR_SM_BIT,
+		0, rt5660_spk_mix, ARRAY_SIZE(rt5660_spk_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXL", RT5660_PWR_MIXER, RT5660_PWR_OM_L_BIT,
+		0, rt5660_out_l_mix, ARRAY_SIZE(rt5660_out_l_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXR", RT5660_PWR_MIXER, RT5660_PWR_OM_R_BIT,
+		0, rt5660_out_r_mix, ARRAY_SIZE(rt5660_out_r_mix)),
+
+	/* Output Volume */
+	SND_SOC_DAPM_SWITCH("SPKVOL", RT5660_PWR_VOL,
+		RT5660_PWR_SV_BIT, 0, &spk_vol_control),
+	SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("LOUTVOL", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_SWITCH("LOUTVOL L", SND_SOC_NOPM,
+		RT5660_PWR_LV_L_BIT, 0, &lout_l_vol_control),
+	SND_SOC_DAPM_SWITCH("LOUTVOL R", SND_SOC_NOPM,
+		RT5660_PWR_LV_R_BIT, 0, &lout_r_vol_control),
+
+	/* HPO/LOUT/Mono Mixer */
+	SND_SOC_DAPM_MIXER("SPO MIX", SND_SOC_NOPM, 0,
+		0, rt5660_spo_mix, ARRAY_SIZE(rt5660_spo_mix)),
+	SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0,
+		rt5660_lout_mix, ARRAY_SIZE(rt5660_lout_mix)),
+	SND_SOC_DAPM_SUPPLY("VREF HP", RT5660_GEN_CTRL1,
+		RT5660_PWR_VREF_HP_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("LOUT amp", 1, RT5660_PWR_ANLG1,
+		RT5660_PWR_HA_BIT, 0, rt5660_lout_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("SPK amp", 1, RT5660_PWR_DIG1,
+		RT5660_PWR_CLS_D_BIT, 0, NULL, 0),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("LOUTL"),
+	SND_SOC_DAPM_OUTPUT("LOUTR"),
+	SND_SOC_DAPM_OUTPUT("SPO"),
+};
+
+static const struct snd_soc_dapm_route rt5660_dapm_routes[] = {
+	{ "MICBIAS1", NULL, "LDO2" },
+	{ "MICBIAS2", NULL, "LDO2" },
+
+	{ "BST1", NULL, "IN1P" },
+	{ "BST1", NULL, "IN1N" },
+	{ "BST2", NULL, "IN2P" },
+	{ "BST3", NULL, "IN3P" },
+	{ "BST3", NULL, "IN3N" },
+
+	{ "RECMIXL", "BST3 Switch", "BST3" },
+	{ "RECMIXL", "BST2 Switch", "BST2" },
+	{ "RECMIXL", "BST1 Switch", "BST1" },
+	{ "RECMIXL", "OUT MIXL Switch", "OUT MIXL" },
+
+	{ "RECMIXR", "BST3 Switch", "BST3" },
+	{ "RECMIXR", "BST2 Switch", "BST2" },
+	{ "RECMIXR", "BST1 Switch", "BST1" },
+	{ "RECMIXR", "OUT MIXR Switch", "OUT MIXR" },
+
+	{ "ADC L", NULL, "RECMIXL" },
+	{ "ADC L", NULL, "ADC L power" },
+	{ "ADC L", NULL, "ADC clock" },
+	{ "ADC R", NULL, "RECMIXR" },
+	{ "ADC R", NULL, "ADC R power" },
+	{ "ADC R", NULL, "ADC clock" },
+
+	{"DMIC L1", NULL, "DMIC CLK"},
+	{"DMIC L1", NULL, "DMIC Power"},
+	{"DMIC R1", NULL, "DMIC CLK"},
+	{"DMIC R1", NULL, "DMIC Power"},
+
+	{ "Sto1 ADC MIXL", "ADC1 Switch", "ADC L" },
+	{ "Sto1 ADC MIXL", "ADC2 Switch", "DMIC L1" },
+	{ "Sto1 ADC MIXR", "ADC1 Switch", "ADC R" },
+	{ "Sto1 ADC MIXR", "ADC2 Switch", "DMIC R1" },
+
+	{ "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" },
+	{ "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" },
+	{ "adc stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll },
+
+	{ "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" },
+	{ "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" },
+	{ "adc stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll },
+
+	{ "IF1 ADC", NULL, "Stereo1 ADC MIXL" },
+	{ "IF1 ADC", NULL, "Stereo1 ADC MIXR" },
+	{ "IF1 ADC", NULL, "I2S1" },
+
+	{ "IF1 ADC Swap Mux", "L/R", "IF1 ADC" },
+	{ "IF1 ADC Swap Mux", "R/L", "IF1 ADC" },
+	{ "IF1 ADC Swap Mux", "L/L", "IF1 ADC" },
+	{ "IF1 ADC Swap Mux", "R/R", "IF1 ADC" },
+	{ "AIF1TX", NULL, "IF1 ADC Swap Mux" },
+
+	{ "IF1 DAC", NULL, "AIF1RX" },
+	{ "IF1 DAC", NULL, "I2S1" },
+
+	{ "IF1 DAC Swap Mux", "L/R", "IF1 DAC" },
+	{ "IF1 DAC Swap Mux", "R/L", "IF1 DAC" },
+	{ "IF1 DAC Swap Mux", "L/L", "IF1 DAC" },
+	{ "IF1 DAC Swap Mux", "R/R", "IF1 DAC" },
+
+	{ "IF1 DAC L", NULL, "IF1 DAC Swap Mux" },
+	{ "IF1 DAC R", NULL, "IF1 DAC Swap Mux" },
+
+	{ "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" },
+	{ "DAC1 MIXL", "DAC1 Switch", "IF1 DAC L" },
+	{ "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR" },
+	{ "DAC1 MIXR", "DAC1 Switch", "IF1 DAC R" },
+
+	{ "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXL", NULL, "dac stereo1 filter" },
+	{ "dac stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll },
+	{ "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXR", NULL, "dac stereo1 filter" },
+	{ "dac stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll },
+
+	{ "DAC L1", NULL, "Stereo DAC MIXL" },
+	{ "DAC R1", NULL, "Stereo DAC MIXR" },
+
+	{ "SPK MIX", "BST3 Switch", "BST3" },
+	{ "SPK MIX", "BST1 Switch", "BST1" },
+	{ "SPK MIX", "DACL Switch", "DAC L1" },
+	{ "SPK MIX", "DACR Switch", "DAC R1" },
+	{ "SPK MIX", "OUTMIXL Switch", "OUT MIXL" },
+
+	{ "OUT MIXL", "BST3 Switch", "BST3" },
+	{ "OUT MIXL", "BST2 Switch", "BST2" },
+	{ "OUT MIXL", "BST1 Switch", "BST1" },
+	{ "OUT MIXL", "RECMIXL Switch", "RECMIXL" },
+	{ "OUT MIXL", "DACR Switch", "DAC R1" },
+	{ "OUT MIXL", "DACL Switch", "DAC L1" },
+
+	{ "OUT MIXR", "BST2 Switch", "BST2" },
+	{ "OUT MIXR", "BST1 Switch", "BST1" },
+	{ "OUT MIXR", "RECMIXR Switch", "RECMIXR" },
+	{ "OUT MIXR", "DACR Switch", "DAC R1" },
+	{ "OUT MIXR", "DACL Switch", "DAC L1" },
+
+	{ "SPO MIX", "DACR Switch", "DAC R1" },
+	{ "SPO MIX", "DACL Switch", "DAC L1" },
+	{ "SPO MIX", "SPKVOL Switch", "SPKVOL" },
+	{ "SPO MIX", "BST1 Switch", "BST1" },
+
+	{ "SPKVOL", "Switch", "SPK MIX" },
+	{ "LOUTVOL L", "Switch", "OUT MIXL" },
+	{ "LOUTVOL R", "Switch", "OUT MIXR" },
+
+	{ "LOUTVOL", NULL, "LOUTVOL L" },
+	{ "LOUTVOL", NULL, "LOUTVOL R" },
+
+	{ "DAC 1", NULL, "DAC L1" },
+	{ "DAC 1", NULL, "DAC R1" },
+
+	{ "LOUT MIX", "DAC Switch", "DAC 1" },
+	{ "LOUT MIX", "OUTMIX Switch", "LOUTVOL" },
+
+	{ "LOUT amp", NULL, "LOUT MIX" },
+	{ "LOUT amp", NULL, "VREF HP" },
+	{ "LOUTL", NULL, "LOUT amp" },
+	{ "LOUTR", NULL, "LOUT amp" },
+
+	{ "SPK amp", NULL, "SPO MIX" },
+	{ "SPO", NULL, "SPK amp" },
+};
+
+static int rt5660_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0, val_clk, mask_clk;
+	int pre_div, bclk_ms, frame_size;
+
+	rt5660->lrck[dai->id] = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5660->sysclk, rt5660->lrck[dai->id]);
+	if (pre_div < 0) {
+		dev_err(component->dev, "Unsupported clock setting %d for DAI %d\n",
+			rt5660->lrck[dai->id], dai->id);
+		return -EINVAL;
+	}
+
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
+		return frame_size;
+	}
+
+	if (frame_size > 32)
+		bclk_ms = 1;
+	else
+		bclk_ms = 0;
+
+	rt5660->bclk[dai->id] = rt5660->lrck[dai->id] * (32 << bclk_ms);
+
+	dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+		rt5660->bclk[dai->id], rt5660->lrck[dai->id]);
+	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+				bclk_ms, pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		val_len |= RT5660_I2S_DL_20;
+		break;
+	case 24:
+		val_len |= RT5660_I2S_DL_24;
+		break;
+	case 8:
+		val_len |= RT5660_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5660_AIF1:
+		mask_clk = RT5660_I2S_BCLK_MS1_MASK | RT5660_I2S_PD1_MASK;
+		val_clk = bclk_ms << RT5660_I2S_BCLK_MS1_SFT |
+			pre_div << RT5660_I2S_PD1_SFT;
+		snd_soc_component_update_bits(component, RT5660_I2S1_SDP, RT5660_I2S_DL_MASK,
+			val_len);
+		snd_soc_component_update_bits(component, RT5660_ADDA_CLK1, mask_clk, val_clk);
+		break;
+
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5660_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5660->master[dai->id] = 1;
+		break;
+
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5660_I2S_MS_S;
+		rt5660->master[dai->id] = 0;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5660_I2S_BP_INV;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5660_I2S_DF_LEFT;
+		break;
+
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5660_I2S_DF_PCM_A;
+		break;
+
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val  |= RT5660_I2S_DF_PCM_B;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5660_AIF1:
+		snd_soc_component_update_bits(component, RT5660_I2S1_SDP,
+			RT5660_I2S_MS_MASK | RT5660_I2S_BP_MASK |
+			RT5660_I2S_DF_MASK, reg_val);
+		break;
+
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5660_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	if (freq == rt5660->sysclk && clk_id == rt5660->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5660_SCLK_S_MCLK:
+		reg_val |= RT5660_SCLK_SRC_MCLK;
+		break;
+
+	case RT5660_SCLK_S_PLL1:
+		reg_val |= RT5660_SCLK_SRC_PLL1;
+		break;
+
+	case RT5660_SCLK_S_RCCLK:
+		reg_val |= RT5660_SCLK_SRC_RCCLK;
+		break;
+
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5660_GLB_CLK, RT5660_SCLK_SRC_MASK,
+		reg_val);
+
+	rt5660->sysclk = freq;
+	rt5660->sysclk_src = clk_id;
+
+	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+	return 0;
+}
+
+static int rt5660_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+			unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5660->pll_src && freq_in == rt5660->pll_in &&
+		freq_out == rt5660->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt5660->pll_in = 0;
+		rt5660->pll_out = 0;
+		snd_soc_component_update_bits(component, RT5660_GLB_CLK,
+			RT5660_SCLK_SRC_MASK, RT5660_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5660_PLL1_S_MCLK:
+		snd_soc_component_update_bits(component, RT5660_GLB_CLK,
+			RT5660_PLL1_SRC_MASK, RT5660_PLL1_SRC_MCLK);
+		break;
+
+	case RT5660_PLL1_S_BCLK:
+		snd_soc_component_update_bits(component, RT5660_GLB_CLK,
+			RT5660_PLL1_SRC_MASK, RT5660_PLL1_SRC_BCLK1);
+		break;
+
+	default:
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_component_write(component, RT5660_PLL_CTRL1,
+		pll_code.n_code << RT5660_PLL_N_SFT | pll_code.k_code);
+	snd_soc_component_write(component, RT5660_PLL_CTRL2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5660_PLL_M_SFT |
+		pll_code.m_bp << RT5660_PLL_M_BP_SFT);
+
+	rt5660->pll_in = freq_in;
+	rt5660->pll_out = freq_out;
+	rt5660->pll_src = source;
+
+	return 0;
+}
+
+static int rt5660_set_bias_level(struct snd_soc_component *component,
+			enum snd_soc_bias_level level)
+{
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		snd_soc_component_update_bits(component, RT5660_GEN_CTRL1,
+			RT5660_DIG_GATE_CTRL, RT5660_DIG_GATE_CTRL);
+
+		if (IS_ERR(rt5660->mclk))
+			break;
+
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON) {
+			clk_disable_unprepare(rt5660->mclk);
+		} else {
+			ret = clk_prepare_enable(rt5660->mclk);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_update_bits(component, RT5660_PWR_ANLG1,
+				RT5660_PWR_VREF1 | RT5660_PWR_MB |
+				RT5660_PWR_BG | RT5660_PWR_VREF2,
+				RT5660_PWR_VREF1 | RT5660_PWR_MB |
+				RT5660_PWR_BG | RT5660_PWR_VREF2);
+			usleep_range(10000, 15000);
+			snd_soc_component_update_bits(component, RT5660_PWR_ANLG1,
+				RT5660_PWR_FV1 | RT5660_PWR_FV2,
+				RT5660_PWR_FV1 | RT5660_PWR_FV2);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, RT5660_GEN_CTRL1,
+			RT5660_DIG_GATE_CTRL, 0);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5660_probe(struct snd_soc_component *component)
+{
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
+
+	rt5660->component = component;
+
+	return 0;
+}
+
+static void rt5660_remove(struct snd_soc_component *component)
+{
+	snd_soc_component_write(component, RT5660_RESET, 0);
+}
+
+#ifdef CONFIG_PM
+static int rt5660_suspend(struct snd_soc_component *component)
+{
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5660->regmap, true);
+	regcache_mark_dirty(rt5660->regmap);
+
+	return 0;
+}
+
+static int rt5660_resume(struct snd_soc_component *component)
+{
+	struct rt5660_priv *rt5660 = snd_soc_component_get_drvdata(component);
+
+	if (rt5660->pdata.poweroff_codec_in_suspend)
+		msleep(350);
+
+	regcache_cache_only(rt5660->regmap, false);
+	regcache_sync(rt5660->regmap);
+
+	return 0;
+}
+#else
+#define rt5660_suspend NULL
+#define rt5660_resume NULL
+#endif
+
+#define RT5660_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5660_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5660_aif_dai_ops = {
+	.hw_params = rt5660_hw_params,
+	.set_fmt = rt5660_set_dai_fmt,
+	.set_sysclk = rt5660_set_dai_sysclk,
+	.set_pll = rt5660_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver rt5660_dai[] = {
+	{
+		.name = "rt5660-aif1",
+		.id = RT5660_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5660_STEREO_RATES,
+			.formats = RT5660_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5660_STEREO_RATES,
+			.formats = RT5660_FORMATS,
+		},
+		.ops = &rt5660_aif_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5660 = {
+	.probe			= rt5660_probe,
+	.remove			= rt5660_remove,
+	.suspend		= rt5660_suspend,
+	.resume			= rt5660_resume,
+	.set_bias_level		= rt5660_set_bias_level,
+	.controls		= rt5660_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5660_snd_controls),
+	.dapm_widgets		= rt5660_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5660_dapm_widgets),
+	.dapm_routes		= rt5660_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5660_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt5660_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.use_single_rw = true,
+
+	.max_register = RT5660_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5660_ranges) *
+					       RT5660_PR_SPACING),
+	.volatile_reg = rt5660_volatile_register,
+	.readable_reg = rt5660_readable_register,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5660_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5660_reg),
+	.ranges = rt5660_ranges,
+	.num_ranges = ARRAY_SIZE(rt5660_ranges),
+};
+
+static const struct i2c_device_id rt5660_i2c_id[] = {
+	{ "rt5660", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt5660_i2c_id);
+
+static const struct of_device_id rt5660_of_match[] = {
+	{ .compatible = "realtek,rt5660", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5660_of_match);
+
+static const struct acpi_device_id rt5660_acpi_match[] = {
+	{ "10EC5660", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, rt5660_acpi_match);
+
+static int rt5660_parse_dt(struct rt5660_priv *rt5660, struct device *dev)
+{
+	rt5660->pdata.in1_diff = device_property_read_bool(dev,
+					"realtek,in1-differential");
+	rt5660->pdata.in3_diff = device_property_read_bool(dev,
+					"realtek,in3-differential");
+	rt5660->pdata.poweroff_codec_in_suspend = device_property_read_bool(dev,
+					"realtek,poweroff-in-suspend");
+	device_property_read_u32(dev, "realtek,dmic1-data-pin",
+		&rt5660->pdata.dmic1_data_pin);
+
+	return 0;
+}
+
+static int rt5660_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5660_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt5660_priv *rt5660;
+	int ret;
+	unsigned int val;
+
+	rt5660 = devm_kzalloc(&i2c->dev, sizeof(struct rt5660_priv),
+		GFP_KERNEL);
+
+	if (rt5660 == NULL)
+		return -ENOMEM;
+
+	/* Check if MCLK provided */
+	rt5660->mclk = devm_clk_get(&i2c->dev, "mclk");
+	if (PTR_ERR(rt5660->mclk) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	i2c_set_clientdata(i2c, rt5660);
+
+	if (pdata)
+		rt5660->pdata = *pdata;
+	else if (i2c->dev.of_node)
+		rt5660_parse_dt(rt5660, &i2c->dev);
+
+	rt5660->regmap = devm_regmap_init_i2c(i2c, &rt5660_regmap);
+	if (IS_ERR(rt5660->regmap)) {
+		ret = PTR_ERR(rt5660->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt5660->regmap, RT5660_VENDOR_ID2, &val);
+	if (val != RT5660_DEVICE_ID) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt5660\n", val);
+		return -ENODEV;
+	}
+
+	regmap_write(rt5660->regmap, RT5660_RESET, 0);
+
+	ret = regmap_register_patch(rt5660->regmap, rt5660_patch,
+				    ARRAY_SIZE(rt5660_patch));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	regmap_update_bits(rt5660->regmap, RT5660_GEN_CTRL1,
+		RT5660_AUTO_DIS_AMP | RT5660_MCLK_DET | RT5660_POW_CLKDET,
+		RT5660_AUTO_DIS_AMP | RT5660_MCLK_DET | RT5660_POW_CLKDET);
+
+	if (rt5660->pdata.dmic1_data_pin) {
+		regmap_update_bits(rt5660->regmap, RT5660_GPIO_CTRL1,
+			RT5660_GP1_PIN_MASK, RT5660_GP1_PIN_DMIC1_SCL);
+
+		if (rt5660->pdata.dmic1_data_pin == RT5660_DMIC1_DATA_GPIO2)
+			regmap_update_bits(rt5660->regmap, RT5660_DMIC_CTRL1,
+				RT5660_SEL_DMIC_DATA_MASK,
+				RT5660_SEL_DMIC_DATA_GPIO2);
+		else if (rt5660->pdata.dmic1_data_pin == RT5660_DMIC1_DATA_IN1P)
+			regmap_update_bits(rt5660->regmap, RT5660_DMIC_CTRL1,
+				RT5660_SEL_DMIC_DATA_MASK,
+				RT5660_SEL_DMIC_DATA_IN1P);
+	}
+
+	return devm_snd_soc_register_component(&i2c->dev,
+				      &soc_component_dev_rt5660,
+				      rt5660_dai, ARRAY_SIZE(rt5660_dai));
+}
+
+static struct i2c_driver rt5660_i2c_driver = {
+	.driver = {
+		.name = "rt5660",
+		.acpi_match_table = ACPI_PTR(rt5660_acpi_match),
+		.of_match_table = of_match_ptr(rt5660_of_match),
+	},
+	.probe = rt5660_i2c_probe,
+	.id_table = rt5660_i2c_id,
+};
+module_i2c_driver(rt5660_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5660 driver");
+MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5660.h b/sound/soc/codecs/rt5660.h
new file mode 100644
index 0000000..c65de0a
--- /dev/null
+++ b/sound/soc/codecs/rt5660.h
@@ -0,0 +1,850 @@
+/*
+ * rt5660.h  --  RT5660 ALSA SoC audio driver
+ *
+ * Copyright 2016 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _RT5660_H
+#define _RT5660_H
+
+#include <linux/clk.h>
+#include <sound/rt5660.h>
+
+/* Info */
+#define RT5660_RESET				0x00
+#define RT5660_VENDOR_ID			0xfd
+#define RT5660_VENDOR_ID1			0xfe
+#define RT5660_VENDOR_ID2			0xff
+/*  I/O - Output */
+#define RT5660_SPK_VOL				0x01
+#define RT5660_LOUT_VOL				0x02
+/* I/O - Input */
+#define RT5660_IN1_IN2				0x0d
+#define RT5660_IN3_IN4				0x0e
+/* I/O - ADC/DAC/DMIC */
+#define RT5660_DAC1_DIG_VOL			0x19
+#define RT5660_STO1_ADC_DIG_VOL			0x1c
+#define RT5660_ADC_BST_VOL1			0x1e
+/* Mixer - D-D */
+#define RT5660_STO1_ADC_MIXER			0x27
+#define RT5660_AD_DA_MIXER			0x29
+#define RT5660_STO_DAC_MIXER			0x2a
+#define RT5660_DIG_INF1_DATA			0x2f
+/* Mixer - ADC */
+#define RT5660_REC_L1_MIXER			0x3b
+#define RT5660_REC_L2_MIXER			0x3c
+#define RT5660_REC_R1_MIXER			0x3d
+#define RT5660_REC_R2_MIXER			0x3e
+/* Mixer - DAC */
+#define RT5660_LOUT_MIXER			0x45
+#define RT5660_SPK_MIXER			0x46
+#define RT5660_SPO_MIXER			0x48
+#define RT5660_SPO_CLSD_RATIO			0x4a
+#define RT5660_OUT_L_GAIN1			0x4d
+#define RT5660_OUT_L_GAIN2			0x4e
+#define RT5660_OUT_L1_MIXER			0x4f
+#define RT5660_OUT_R_GAIN1			0x50
+#define RT5660_OUT_R_GAIN2			0x51
+#define RT5660_OUT_R1_MIXER			0x52
+/* Power */
+#define RT5660_PWR_DIG1				0x61
+#define RT5660_PWR_DIG2				0x62
+#define RT5660_PWR_ANLG1			0x63
+#define RT5660_PWR_ANLG2			0x64
+#define RT5660_PWR_MIXER			0x65
+#define RT5660_PWR_VOL				0x66
+/* Private Register Control */
+#define RT5660_PRIV_INDEX			0x6a
+#define RT5660_PRIV_DATA			0x6c
+/* Format - ADC/DAC */
+#define RT5660_I2S1_SDP				0x70
+#define RT5660_ADDA_CLK1			0x73
+#define RT5660_ADDA_CLK2			0x74
+#define RT5660_DMIC_CTRL1			0x75
+/* Function - Analog */
+#define RT5660_GLB_CLK				0x80
+#define RT5660_PLL_CTRL1			0x81
+#define RT5660_PLL_CTRL2			0x82
+#define RT5660_CLSD_AMP_OC_CTRL			0x8c
+#define RT5660_CLSD_AMP_CTRL			0x8d
+#define RT5660_LOUT_AMP_CTRL			0x8e
+#define RT5660_SPK_AMP_SPKVDD			0x92
+#define RT5660_MICBIAS				0x93
+#define RT5660_CLSD_OUT_CTRL1			0xa1
+#define RT5660_CLSD_OUT_CTRL2			0xa2
+#define RT5660_DIPOLE_MIC_CTRL1			0xa3
+#define RT5660_DIPOLE_MIC_CTRL2			0xa4
+#define RT5660_DIPOLE_MIC_CTRL3			0xa5
+#define RT5660_DIPOLE_MIC_CTRL4			0xa6
+#define RT5660_DIPOLE_MIC_CTRL5			0xa7
+#define RT5660_DIPOLE_MIC_CTRL6			0xa8
+#define RT5660_DIPOLE_MIC_CTRL7			0xa9
+#define RT5660_DIPOLE_MIC_CTRL8			0xaa
+#define RT5660_DIPOLE_MIC_CTRL9			0xab
+#define RT5660_DIPOLE_MIC_CTRL10		0xac
+#define RT5660_DIPOLE_MIC_CTRL11		0xad
+#define RT5660_DIPOLE_MIC_CTRL12		0xae
+/* Function - Digital */
+#define RT5660_EQ_CTRL1				0xb0
+#define RT5660_EQ_CTRL2				0xb1
+#define RT5660_DRC_AGC_CTRL1			0xb3
+#define RT5660_DRC_AGC_CTRL2			0xb4
+#define RT5660_DRC_AGC_CTRL3			0xb5
+#define RT5660_DRC_AGC_CTRL4			0xb6
+#define RT5660_DRC_AGC_CTRL5			0xb7
+#define RT5660_JD_CTRL				0xbb
+#define RT5660_IRQ_CTRL1			0xbd
+#define RT5660_IRQ_CTRL2			0xbe
+#define RT5660_INT_IRQ_ST			0xbf
+#define RT5660_GPIO_CTRL1			0xc0
+#define RT5660_GPIO_CTRL2			0xc2
+#define RT5660_WIND_FILTER_CTRL1		0xd3
+#define RT5660_SV_ZCD1				0xd9
+#define RT5660_SV_ZCD2				0xda
+#define RT5660_DRC1_LM_CTRL1			0xe0
+#define RT5660_DRC1_LM_CTRL2			0xe1
+#define RT5660_DRC2_LM_CTRL1			0xe2
+#define RT5660_DRC2_LM_CTRL2			0xe3
+#define RT5660_MULTI_DRC_CTRL			0xe4
+#define RT5660_DRC2_CTRL1			0xe5
+#define RT5660_DRC2_CTRL2			0xe6
+#define RT5660_DRC2_CTRL3			0xe7
+#define RT5660_DRC2_CTRL4			0xe8
+#define RT5660_DRC2_CTRL5			0xe9
+#define RT5660_ALC_PGA_CTRL1			0xea
+#define RT5660_ALC_PGA_CTRL2			0xeb
+#define RT5660_ALC_PGA_CTRL3			0xec
+#define RT5660_ALC_PGA_CTRL4			0xed
+#define RT5660_ALC_PGA_CTRL5			0xee
+#define RT5660_ALC_PGA_CTRL6			0xef
+#define RT5660_ALC_PGA_CTRL7			0xf0
+
+/* General Control */
+#define RT5660_GEN_CTRL1			0xfa
+#define RT5660_GEN_CTRL2			0xfb
+#define RT5660_GEN_CTRL3			0xfc
+
+/* Index of Codec Private Register definition */
+#define RT5660_CHOP_DAC_ADC			0x3d
+
+/* Global Definition */
+#define RT5660_L_MUTE				(0x1 << 15)
+#define RT5660_L_MUTE_SFT			15
+#define RT5660_VOL_L_MUTE			(0x1 << 14)
+#define RT5660_VOL_L_SFT			14
+#define RT5660_R_MUTE				(0x1 << 7)
+#define RT5660_R_MUTE_SFT			7
+#define RT5660_VOL_R_MUTE			(0x1 << 6)
+#define RT5660_VOL_R_SFT			6
+#define RT5660_L_VOL_MASK			(0x3f << 8)
+#define RT5660_L_VOL_SFT			8
+#define RT5660_R_VOL_MASK			(0x3f)
+#define RT5660_R_VOL_SFT			0
+
+/* IN1 and IN2 Control (0x0d) */
+#define RT5660_IN_DF1				(0x1 << 15)
+#define RT5660_IN_SFT1				15
+#define RT5660_BST_MASK1			(0x7f << 8)
+#define RT5660_BST_SFT1				8
+#define RT5660_IN_DF2				(0x1 << 7)
+#define RT5660_IN_SFT2				7
+#define RT5660_BST_MASK2			(0x7f << 0)
+#define RT5660_BST_SFT2				0
+
+/* IN3 and IN4 Control (0x0e) */
+#define RT5660_IN_DF3				(0x1 << 15)
+#define RT5660_IN_SFT3				15
+#define RT5660_BST_MASK3			(0x7f << 8)
+#define RT5660_BST_SFT3				8
+#define RT5660_IN_DF4				(0x1 << 7)
+#define RT5660_IN_SFT4				7
+#define RT5660_BST_MASK4			(0x7f << 0)
+#define RT5660_BST_SFT4				0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5660_DAC_L1_VOL_MASK			(0x7f << 9)
+#define RT5660_DAC_L1_VOL_SFT			9
+#define RT5660_DAC_R1_VOL_MASK			(0x7f << 1)
+#define RT5660_DAC_R1_VOL_SFT			1
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5660_ADC_L_VOL_MASK			(0x3f << 9)
+#define RT5660_ADC_L_VOL_SFT			9
+#define RT5660_ADC_R_VOL_MASK			(0x3f << 1)
+#define RT5660_ADC_R_VOL_SFT			1
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5660_STO1_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5660_STO1_ADC_L_BST_SFT		14
+#define RT5660_STO1_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5660_STO1_ADC_R_BST_SFT		12
+
+/* Stereo ADC Mixer Control (0x27) */
+#define RT5660_M_ADC_L1				(0x1 << 14)
+#define RT5660_M_ADC_L1_SFT			14
+#define RT5660_M_ADC_L2				(0x1 << 13)
+#define RT5660_M_ADC_L2_SFT			13
+#define RT5660_M_ADC_R1				(0x1 << 6)
+#define RT5660_M_ADC_R1_SFT			6
+#define RT5660_M_ADC_R2				(0x1 << 5)
+#define RT5660_M_ADC_R2_SFT			5
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5660_M_ADCMIX_L			(0x1 << 15)
+#define RT5660_M_ADCMIX_L_SFT			15
+#define RT5660_M_DAC1_L				(0x1 << 14)
+#define RT5660_M_DAC1_L_SFT			14
+#define RT5660_M_ADCMIX_R			(0x1 << 7)
+#define RT5660_M_ADCMIX_R_SFT			7
+#define RT5660_M_DAC1_R				(0x1 << 6)
+#define RT5660_M_DAC1_R_SFT			6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5660_M_DAC_L1				(0x1 << 14)
+#define RT5660_M_DAC_L1_SFT			14
+#define RT5660_DAC_L1_STO_L_VOL_MASK		(0x1 << 13)
+#define RT5660_DAC_L1_STO_L_VOL_SFT		13
+#define RT5660_M_DAC_R1_STO_L			(0x1 << 9)
+#define RT5660_M_DAC_R1_STO_L_SFT		9
+#define RT5660_DAC_R1_STO_L_VOL_MASK		(0x1 << 8)
+#define RT5660_DAC_R1_STO_L_VOL_SFT		8
+#define RT5660_M_DAC_R1				(0x1 << 6)
+#define RT5660_M_DAC_R1_SFT			6
+#define RT5660_DAC_R1_STO_R_VOL_MASK		(0x1 << 5)
+#define RT5660_DAC_R1_STO_R_VOL_SFT		5
+#define RT5660_M_DAC_L1_STO_R			(0x1 << 1)
+#define RT5660_M_DAC_L1_STO_R_SFT		1
+#define RT5660_DAC_L1_STO_R_VOL_MASK		(0x1)
+#define RT5660_DAC_L1_STO_R_VOL_SFT		0
+
+/* Digital Interface Data Control (0x2f) */
+#define RT5660_IF1_DAC_IN_SEL			(0x3 << 14)
+#define RT5660_IF1_DAC_IN_SFT			14
+#define RT5660_IF1_ADC_IN_SEL			(0x3 << 12)
+#define RT5660_IF1_ADC_IN_SFT			12
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5660_G_BST3_RM_L_MASK			(0x7 << 4)
+#define RT5660_G_BST3_RM_L_SFT			4
+#define RT5660_G_BST2_RM_L_MASK			(0x7 << 1)
+#define RT5660_G_BST2_RM_L_SFT			1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5660_G_BST1_RM_L_MASK			(0x7 << 13)
+#define RT5660_G_BST1_RM_L_SFT			13
+#define RT5660_G_OM_L_RM_L_MASK			(0x7 << 10)
+#define RT5660_G_OM_L_RM_L_SFT			10
+#define RT5660_M_BST3_RM_L			(0x1 << 3)
+#define RT5660_M_BST3_RM_L_SFT			3
+#define RT5660_M_BST2_RM_L			(0x1 << 2)
+#define RT5660_M_BST2_RM_L_SFT			2
+#define RT5660_M_BST1_RM_L			(0x1 << 1)
+#define RT5660_M_BST1_RM_L_SFT			1
+#define RT5660_M_OM_L_RM_L			(0x1)
+#define RT5660_M_OM_L_RM_L_SFT			0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5660_G_BST3_RM_R_MASK			(0x7 << 4)
+#define RT5660_G_BST3_RM_R_SFT			4
+#define RT5660_G_BST2_RM_R_MASK			(0x7 << 1)
+#define RT5660_G_BST2_RM_R_SFT			1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5660_G_BST1_RM_R_MASK			(0x7 << 13)
+#define RT5660_G_BST1_RM_R_SFT			13
+#define RT5660_G_OM_R_RM_R_MASK			(0x7 << 10)
+#define RT5660_G_OM_R_RM_R_SFT			10
+#define RT5660_M_BST3_RM_R			(0x1 << 3)
+#define RT5660_M_BST3_RM_R_SFT			3
+#define RT5660_M_BST2_RM_R			(0x1 << 2)
+#define RT5660_M_BST2_RM_R_SFT			2
+#define RT5660_M_BST1_RM_R			(0x1 << 1)
+#define RT5660_M_BST1_RM_R_SFT			1
+#define RT5660_M_OM_R_RM_R			(0x1)
+#define RT5660_M_OM_R_RM_R_SFT			0
+
+/* LOUTMIX Control (0x45) */
+#define RT5660_M_DAC1_LM			(0x1 << 14)
+#define RT5660_M_DAC1_LM_SFT			14
+#define RT5660_M_LOVOL_M			(0x1 << 13)
+#define RT5660_M_LOVOL_LM_SFT			13
+
+/* SPK Mixer Control (0x46) */
+#define RT5660_G_BST3_SM_MASK			(0x3 << 14)
+#define RT5660_G_BST3_SM_SFT			14
+#define RT5660_G_BST1_SM_MASK			(0x3 << 12)
+#define RT5660_G_BST1_SM_SFT			12
+#define RT5660_G_DACl_SM_MASK			(0x3 << 10)
+#define RT5660_G_DACl_SM_SFT			10
+#define RT5660_G_DACR_SM_MASK			(0x3 << 8)
+#define RT5660_G_DACR_SM_SFT			8
+#define RT5660_G_OM_L_SM_MASK			(0x3 << 6)
+#define RT5660_G_OM_L_SM_SFT			6
+#define RT5660_M_DACR_SM			(0x1 << 5)
+#define RT5660_M_DACR_SM_SFT			5
+#define RT5660_M_BST1_SM			(0x1 << 4)
+#define RT5660_M_BST1_SM_SFT			4
+#define RT5660_M_BST3_SM			(0x1 << 3)
+#define RT5660_M_BST3_SM_SFT			3
+#define RT5660_M_DACL_SM			(0x1 << 2)
+#define RT5660_M_DACL_SM_SFT			2
+#define RT5660_M_OM_L_SM			(0x1 << 1)
+#define RT5660_M_OM_L_SM_SFT			1
+
+/* SPOMIX Control (0x48) */
+#define RT5660_M_DAC_R_SPM			(0x1 << 14)
+#define RT5660_M_DAC_R_SPM_SFT			14
+#define RT5660_M_DAC_L_SPM			(0x1 << 13)
+#define RT5660_M_DAC_L_SPM_SFT			13
+#define RT5660_M_SV_SPM				(0x1 << 12)
+#define RT5660_M_SV_SPM_SFT			12
+#define RT5660_M_BST1_SPM			(0x1 << 11)
+#define RT5660_M_BST1_SPM_SFT			11
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5660_G_BST3_OM_L_MASK			(0x7 << 13)
+#define RT5660_G_BST3_OM_L_SFT			13
+#define RT5660_G_BST2_OM_L_MASK			(0x7 << 10)
+#define RT5660_G_BST2_OM_L_SFT			10
+#define RT5660_G_BST1_OM_L_MASK			(0x7 << 7)
+#define RT5660_G_BST1_OM_L_SFT			7
+#define RT5660_G_RM_L_OM_L_MASK			(0x7 << 1)
+#define RT5660_G_RM_L_OM_L_SFT			1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5660_G_DAC_R1_OM_L_MASK		(0x7 << 10)
+#define RT5660_G_DAC_R1_OM_L_SFT		10
+#define RT5660_G_DAC_L1_OM_L_MASK		(0x7 << 7)
+#define RT5660_G_DAC_L1_OM_L_SFT		7
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5660_M_BST3_OM_L			(0x1 << 5)
+#define RT5660_M_BST3_OM_L_SFT			5
+#define RT5660_M_BST2_OM_L			(0x1 << 4)
+#define RT5660_M_BST2_OM_L_SFT			4
+#define RT5660_M_BST1_OM_L			(0x1 << 3)
+#define RT5660_M_BST1_OM_L_SFT			3
+#define RT5660_M_RM_L_OM_L			(0x1 << 2)
+#define RT5660_M_RM_L_OM_L_SFT			2
+#define RT5660_M_DAC_R_OM_L			(0x1 << 1)
+#define RT5660_M_DAC_R_OM_L_SFT			1
+#define RT5660_M_DAC_L_OM_L			(0x1)
+#define RT5660_M_DAC_L_OM_L_SFT			0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5660_G_BST2_OM_R_MASK			(0x7 << 10)
+#define RT5660_G_BST2_OM_R_SFT			10
+#define RT5660_G_BST1_OM_R_MASK			(0x7 << 7)
+#define RT5660_G_BST1_OM_R_SFT			7
+#define RT5660_G_RM_R_OM_R_MASK			(0x7 << 1)
+#define RT5660_G_RM_R_OM_R_SFT			1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5660_G_DAC_L_OM_R_MASK		(0x7 << 10)
+#define RT5660_G_DAC_L_OM_R_SFT			10
+#define RT5660_G_DAC_R_OM_R_MASK		(0x7 << 7)
+#define RT5660_G_DAC_R_OM_R_SFT			7
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5660_M_BST2_OM_R			(0x1 << 4)
+#define RT5660_M_BST2_OM_R_SFT			4
+#define RT5660_M_BST1_OM_R			(0x1 << 3)
+#define RT5660_M_BST1_OM_R_SFT			3
+#define RT5660_M_RM_R_OM_R			(0x1 << 2)
+#define RT5660_M_RM_R_OM_R_SFT			2
+#define RT5660_M_DAC_L_OM_R			(0x1 << 1)
+#define RT5660_M_DAC_L_OM_R_SFT			1
+#define RT5660_M_DAC_R_OM_R			(0x1)
+#define RT5660_M_DAC_R_OM_R_SFT			0
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5660_PWR_I2S1				(0x1 << 15)
+#define RT5660_PWR_I2S1_BIT			15
+#define RT5660_PWR_DAC_L1			(0x1 << 12)
+#define RT5660_PWR_DAC_L1_BIT			12
+#define RT5660_PWR_DAC_R1			(0x1 << 11)
+#define RT5660_PWR_DAC_R1_BIT			11
+#define RT5660_PWR_ADC_L			(0x1 << 2)
+#define RT5660_PWR_ADC_L_BIT			2
+#define RT5660_PWR_ADC_R			(0x1 << 1)
+#define RT5660_PWR_ADC_R_BIT			1
+#define RT5660_PWR_CLS_D			(0x1)
+#define RT5660_PWR_CLS_D_BIT			0
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5660_PWR_ADC_S1F			(0x1 << 15)
+#define RT5660_PWR_ADC_S1F_BIT			15
+#define RT5660_PWR_DAC_S1F			(0x1 << 11)
+#define RT5660_PWR_DAC_S1F_BIT			11
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5660_PWR_VREF1			(0x1 << 15)
+#define RT5660_PWR_VREF1_BIT			15
+#define RT5660_PWR_FV1				(0x1 << 14)
+#define RT5660_PWR_FV1_BIT			14
+#define RT5660_PWR_MB				(0x1 << 13)
+#define RT5660_PWR_MB_BIT			13
+#define RT5660_PWR_BG				(0x1 << 11)
+#define RT5660_PWR_BG_BIT			11
+#define RT5660_PWR_HP_L				(0x1 << 7)
+#define RT5660_PWR_HP_L_BIT			7
+#define RT5660_PWR_HP_R				(0x1 << 6)
+#define RT5660_PWR_HP_R_BIT			6
+#define RT5660_PWR_HA				(0x1 << 5)
+#define RT5660_PWR_HA_BIT			5
+#define RT5660_PWR_VREF2			(0x1 << 4)
+#define RT5660_PWR_VREF2_BIT			4
+#define RT5660_PWR_FV2				(0x1 << 3)
+#define RT5660_PWR_FV2_BIT			3
+#define RT5660_PWR_LDO2				(0x1 << 2)
+#define RT5660_PWR_LDO2_BIT			2
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5660_PWR_BST1				(0x1 << 15)
+#define RT5660_PWR_BST1_BIT			15
+#define RT5660_PWR_BST2				(0x1 << 14)
+#define RT5660_PWR_BST2_BIT			14
+#define RT5660_PWR_BST3				(0x1 << 13)
+#define RT5660_PWR_BST3_BIT			13
+#define RT5660_PWR_MB1				(0x1 << 11)
+#define RT5660_PWR_MB1_BIT			11
+#define RT5660_PWR_MB2				(0x1 << 10)
+#define RT5660_PWR_MB2_BIT			10
+#define RT5660_PWR_PLL				(0x1 << 9)
+#define RT5660_PWR_PLL_BIT			9
+
+/* Power Management for Mixer (0x65) */
+#define RT5660_PWR_OM_L				(0x1 << 15)
+#define RT5660_PWR_OM_L_BIT			15
+#define RT5660_PWR_OM_R				(0x1 << 14)
+#define RT5660_PWR_OM_R_BIT			14
+#define RT5660_PWR_SM				(0x1 << 13)
+#define RT5660_PWR_SM_BIT			13
+#define RT5660_PWR_RM_L				(0x1 << 11)
+#define RT5660_PWR_RM_L_BIT			11
+#define RT5660_PWR_RM_R				(0x1 << 10)
+#define RT5660_PWR_RM_R_BIT			10
+
+/* Power Management for Volume (0x66) */
+#define RT5660_PWR_SV				(0x1 << 15)
+#define RT5660_PWR_SV_BIT			15
+#define RT5660_PWR_LV_L				(0x1 << 11)
+#define RT5660_PWR_LV_L_BIT			11
+#define RT5660_PWR_LV_R				(0x1 << 10)
+#define RT5660_PWR_LV_R_BIT			10
+
+/* I2S1 Audio Serial Data Port Control (0x70) */
+#define RT5660_I2S_MS_MASK			(0x1 << 15)
+#define RT5660_I2S_MS_SFT			15
+#define RT5660_I2S_MS_M				(0x0 << 15)
+#define RT5660_I2S_MS_S				(0x1 << 15)
+#define RT5660_I2S_O_CP_MASK			(0x3 << 10)
+#define RT5660_I2S_O_CP_SFT			10
+#define RT5660_I2S_O_CP_OFF			(0x0 << 10)
+#define RT5660_I2S_O_CP_U_LAW			(0x1 << 10)
+#define RT5660_I2S_O_CP_A_LAW			(0x2 << 10)
+#define RT5660_I2S_I_CP_MASK			(0x3 << 8)
+#define RT5660_I2S_I_CP_SFT			8
+#define RT5660_I2S_I_CP_OFF			(0x0 << 8)
+#define RT5660_I2S_I_CP_U_LAW			(0x1 << 8)
+#define RT5660_I2S_I_CP_A_LAW			(0x2 << 8)
+#define RT5660_I2S_BP_MASK			(0x1 << 7)
+#define RT5660_I2S_BP_SFT			7
+#define RT5660_I2S_BP_NOR			(0x0 << 7)
+#define RT5660_I2S_BP_INV			(0x1 << 7)
+#define RT5660_I2S_DL_MASK			(0x3 << 2)
+#define RT5660_I2S_DL_SFT			2
+#define RT5660_I2S_DL_16			(0x0 << 2)
+#define RT5660_I2S_DL_20			(0x1 << 2)
+#define RT5660_I2S_DL_24			(0x2 << 2)
+#define RT5660_I2S_DL_8				(0x3 << 2)
+#define RT5660_I2S_DF_MASK			(0x3)
+#define RT5660_I2S_DF_SFT			0
+#define RT5660_I2S_DF_I2S			(0x0)
+#define RT5660_I2S_DF_LEFT			(0x1)
+#define RT5660_I2S_DF_PCM_A			(0x2)
+#define RT5660_I2S_DF_PCM_B			(0x3)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5660_I2S_BCLK_MS1_MASK		(0x1 << 15)
+#define RT5660_I2S_BCLK_MS1_SFT			15
+#define RT5660_I2S_BCLK_MS1_32			(0x0 << 15)
+#define RT5660_I2S_BCLK_MS1_64			(0x1 << 15)
+#define RT5660_I2S_PD1_MASK			(0x7 << 12)
+#define RT5660_I2S_PD1_SFT			12
+#define RT5660_I2S_PD1_1			(0x0 << 12)
+#define RT5660_I2S_PD1_2			(0x1 << 12)
+#define RT5660_I2S_PD1_3			(0x2 << 12)
+#define RT5660_I2S_PD1_4			(0x3 << 12)
+#define RT5660_I2S_PD1_6			(0x4 << 12)
+#define RT5660_I2S_PD1_8			(0x5 << 12)
+#define RT5660_I2S_PD1_12			(0x6 << 12)
+#define RT5660_I2S_PD1_16			(0x7 << 12)
+#define RT5660_DAC_OSR_MASK			(0x3 << 2)
+#define RT5660_DAC_OSR_SFT			2
+#define RT5660_DAC_OSR_128			(0x0 << 2)
+#define RT5660_DAC_OSR_64			(0x1 << 2)
+#define RT5660_DAC_OSR_32			(0x2 << 2)
+#define RT5660_DAC_OSR_16			(0x3 << 2)
+#define RT5660_ADC_OSR_MASK			(0x3)
+#define RT5660_ADC_OSR_SFT			0
+#define RT5660_ADC_OSR_128			(0x0)
+#define RT5660_ADC_OSR_64			(0x1)
+#define RT5660_ADC_OSR_32			(0x2)
+#define RT5660_ADC_OSR_16			(0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5660_RESET_ADF			(0x1 << 13)
+#define RT5660_RESET_ADF_SFT			13
+#define RT5660_RESET_DAF			(0x1 << 12)
+#define RT5660_RESET_DAF_SFT			12
+#define RT5660_DAHPF_EN				(0x1 << 11)
+#define RT5660_DAHPF_EN_SFT			11
+#define RT5660_ADHPF_EN				(0x1 << 10)
+#define RT5660_ADHPF_EN_SFT			10
+
+/* Digital Microphone Control (0x75) */
+#define RT5660_DMIC_1_EN_MASK			(0x1 << 15)
+#define RT5660_DMIC_1_EN_SFT			15
+#define RT5660_DMIC_1_DIS			(0x0 << 15)
+#define RT5660_DMIC_1_EN			(0x1 << 15)
+#define RT5660_DMIC_1L_LH_MASK			(0x1 << 13)
+#define RT5660_DMIC_1L_LH_SFT			13
+#define RT5660_DMIC_1L_LH_RISING		(0x0 << 13)
+#define RT5660_DMIC_1L_LH_FALLING		(0x1 << 13)
+#define RT5660_DMIC_1R_LH_MASK			(0x1 << 12)
+#define RT5660_DMIC_1R_LH_SFT			12
+#define RT5660_DMIC_1R_LH_RISING		(0x0 << 12)
+#define RT5660_DMIC_1R_LH_FALLING		(0x1 << 12)
+#define RT5660_SEL_DMIC_DATA_MASK		(0x1 << 11)
+#define RT5660_SEL_DMIC_DATA_SFT		11
+#define RT5660_SEL_DMIC_DATA_GPIO2		(0x0 << 11)
+#define RT5660_SEL_DMIC_DATA_IN1P		(0x1 << 11)
+#define RT5660_DMIC_CLK_MASK			(0x7 << 5)
+#define RT5660_DMIC_CLK_SFT			5
+
+/* Global Clock Control (0x80) */
+#define RT5660_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5660_SCLK_SRC_SFT			14
+#define RT5660_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5660_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5660_SCLK_SRC_RCCLK			(0x2 << 14)
+#define RT5660_PLL1_SRC_MASK			(0x3 << 12)
+#define RT5660_PLL1_SRC_SFT			12
+#define RT5660_PLL1_SRC_MCLK			(0x0 << 12)
+#define RT5660_PLL1_SRC_BCLK1			(0x1 << 12)
+#define RT5660_PLL1_SRC_RCCLK			(0x2 << 12)
+#define RT5660_PLL1_PD_MASK			(0x1 << 3)
+#define RT5660_PLL1_PD_SFT			3
+#define RT5660_PLL1_PD_1			(0x0 << 3)
+#define RT5660_PLL1_PD_2			(0x1 << 3)
+
+#define RT5660_PLL_INP_MAX			40000000
+#define RT5660_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5660_PLL_N_MAX			0x1ff
+#define RT5660_PLL_N_MASK			(RT5660_PLL_N_MAX << 7)
+#define RT5660_PLL_N_SFT			7
+#define RT5660_PLL_K_MAX			0x1f
+#define RT5660_PLL_K_MASK			(RT5660_PLL_K_MAX)
+#define RT5660_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5660_PLL_M_MAX			0xf
+#define RT5660_PLL_M_MASK			(RT5660_PLL_M_MAX << 12)
+#define RT5660_PLL_M_SFT			12
+#define RT5660_PLL_M_BP				(0x1 << 11)
+#define RT5660_PLL_M_BP_SFT			11
+
+/* Class D Over Current Control (0x8c) */
+#define RT5660_CLSD_OC_MASK			(0x1 << 9)
+#define RT5660_CLSD_OC_SFT			9
+#define RT5660_CLSD_OC_PU			(0x0 << 9)
+#define RT5660_CLSD_OC_PD			(0x1 << 9)
+#define RT5660_AUTO_PD_MASK			(0x1 << 8)
+#define RT5660_AUTO_PD_SFT			8
+#define RT5660_AUTO_PD_DIS			(0x0 << 8)
+#define RT5660_AUTO_PD_EN			(0x1 << 8)
+#define RT5660_CLSD_OC_TH_MASK			(0x3f)
+#define RT5660_CLSD_OC_TH_SFT			0
+
+/* Class D Output Control (0x8d) */
+#define RT5660_CLSD_RATIO_MASK			(0xf << 12)
+#define RT5660_CLSD_RATIO_SFT			12
+
+/* Lout Amp Control 1 (0x8e) */
+#define RT5660_LOUT_CO_MASK			(0x1 << 4)
+#define RT5660_LOUT_CO_SFT			4
+#define RT5660_LOUT_CO_DIS			(0x0 << 4)
+#define RT5660_LOUT_CO_EN			(0x1 << 4)
+#define RT5660_LOUT_CB_MASK			(0x1)
+#define RT5660_LOUT_CB_SFT			0
+#define RT5660_LOUT_CB_PD			(0x0)
+#define RT5660_LOUT_CB_PU			(0x1)
+
+/* SPKVDD detection control (0x92) */
+#define RT5660_SPKVDD_DET_MASK			(0x1 << 15)
+#define RT5660_SPKVDD_DET_SFT			15
+#define RT5660_SPKVDD_DET_DIS			(0x0 << 15)
+#define RT5660_SPKVDD_DET_EN			(0x1 << 15)
+#define RT5660_SPK_AG_MASK			(0x1 << 14)
+#define RT5660_SPK_AG_SFT			14
+#define RT5660_SPK_AG_DIS			(0x0 << 14)
+#define RT5660_SPK_AG_EN			(0x1 << 14)
+
+/* Micbias Control (0x93) */
+#define RT5660_MIC1_BS_MASK			(0x1 << 15)
+#define RT5660_MIC1_BS_SFT			15
+#define RT5660_MIC1_BS_9AV			(0x0 << 15)
+#define RT5660_MIC1_BS_75AV			(0x1 << 15)
+#define RT5660_MIC2_BS_MASK			(0x1 << 14)
+#define RT5660_MIC2_BS_SFT			14
+#define RT5660_MIC2_BS_9AV			(0x0 << 14)
+#define RT5660_MIC2_BS_75AV			(0x1 << 14)
+#define RT5660_MIC1_OVCD_MASK			(0x1 << 11)
+#define RT5660_MIC1_OVCD_SFT			11
+#define RT5660_MIC1_OVCD_DIS			(0x0 << 11)
+#define RT5660_MIC1_OVCD_EN			(0x1 << 11)
+#define RT5660_MIC1_OVTH_MASK			(0x3 << 9)
+#define RT5660_MIC1_OVTH_SFT			9
+#define RT5660_MIC1_OVTH_600UA			(0x0 << 9)
+#define RT5660_MIC1_OVTH_1500UA			(0x1 << 9)
+#define RT5660_MIC1_OVTH_2000UA			(0x2 << 9)
+#define RT5660_MIC2_OVCD_MASK			(0x1 << 8)
+#define RT5660_MIC2_OVCD_SFT			8
+#define RT5660_MIC2_OVCD_DIS			(0x0 << 8)
+#define RT5660_MIC2_OVCD_EN			(0x1 << 8)
+#define RT5660_MIC2_OVTH_MASK			(0x3 << 6)
+#define RT5660_MIC2_OVTH_SFT			6
+#define RT5660_MIC2_OVTH_600UA			(0x0 << 6)
+#define RT5660_MIC2_OVTH_1500UA			(0x1 << 6)
+#define RT5660_MIC2_OVTH_2000UA			(0x2 << 6)
+#define RT5660_PWR_CLK25M_MASK			(0x1 << 4)
+#define RT5660_PWR_CLK25M_SFT			4
+#define RT5660_PWR_CLK25M_PD			(0x0 << 4)
+#define RT5660_PWR_CLK25M_PU			(0x1 << 4)
+
+/* EQ Control 1 (0xb0) */
+#define RT5660_EQ_SRC_MASK			(0x1 << 15)
+#define RT5660_EQ_SRC_SFT			15
+#define RT5660_EQ_SRC_DAC			(0x0 << 15)
+#define RT5660_EQ_SRC_ADC			(0x1 << 15)
+#define RT5660_EQ_UPD				(0x1 << 14)
+#define RT5660_EQ_UPD_BIT			14
+
+/* Jack Detect Control (0xbb) */
+#define RT5660_JD_MASK				(0x3 << 14)
+#define RT5660_JD_SFT				14
+#define RT5660_JD_DIS				(0x0 << 14)
+#define RT5660_JD_GPIO1				(0x1 << 14)
+#define RT5660_JD_GPIO2				(0x2 << 14)
+#define RT5660_JD_LOUT_MASK			(0x1 << 11)
+#define RT5660_JD_LOUT_SFT			11
+#define RT5660_JD_LOUT_DIS			(0x0 << 11)
+#define RT5660_JD_LOUT_EN			(0x1 << 11)
+#define RT5660_JD_LOUT_TRG_MASK			(0x1 << 10)
+#define RT5660_JD_LOUT_TRG_SFT			10
+#define RT5660_JD_LOUT_TRG_LO			(0x0 << 10)
+#define RT5660_JD_LOUT_TRG_HI			(0x1 << 10)
+#define RT5660_JD_SPO_MASK			(0x1 << 9)
+#define RT5660_JD_SPO_SFT			9
+#define RT5660_JD_SPO_DIS			(0x0 << 9)
+#define RT5660_JD_SPO_EN			(0x1 << 9)
+#define RT5660_JD_SPO_TRG_MASK			(0x1 << 8)
+#define RT5660_JD_SPO_TRG_SFT			8
+#define RT5660_JD_SPO_TRG_LO			(0x0 << 8)
+#define RT5660_JD_SPO_TRG_HI			(0x1 << 8)
+
+/* IRQ Control 1 (0xbd) */
+#define RT5660_IRQ_JD_MASK			(0x1 << 15)
+#define RT5660_IRQ_JD_SFT			15
+#define RT5660_IRQ_JD_BP			(0x0 << 15)
+#define RT5660_IRQ_JD_NOR			(0x1 << 15)
+#define RT5660_IRQ_OT_MASK			(0x1 << 14)
+#define RT5660_IRQ_OT_SFT			14
+#define RT5660_IRQ_OT_BP			(0x0 << 14)
+#define RT5660_IRQ_OT_NOR			(0x1 << 14)
+#define RT5660_JD_STKY_MASK			(0x1 << 13)
+#define RT5660_JD_STKY_SFT			13
+#define RT5660_JD_STKY_DIS			(0x0 << 13)
+#define RT5660_JD_STKY_EN			(0x1 << 13)
+#define RT5660_OT_STKY_MASK			(0x1 << 12)
+#define RT5660_OT_STKY_SFT			12
+#define RT5660_OT_STKY_DIS			(0x0 << 12)
+#define RT5660_OT_STKY_EN			(0x1 << 12)
+#define RT5660_JD_P_MASK			(0x1 << 11)
+#define RT5660_JD_P_SFT				11
+#define RT5660_JD_P_NOR				(0x0 << 11)
+#define RT5660_JD_P_INV				(0x1 << 11)
+#define RT5660_OT_P_MASK			(0x1 << 10)
+#define RT5660_OT_P_SFT				10
+#define RT5660_OT_P_NOR				(0x0 << 10)
+#define RT5660_OT_P_INV				(0x1 << 10)
+
+/* IRQ Control 2 (0xbe) */
+#define RT5660_IRQ_MB1_OC_MASK			(0x1 << 15)
+#define RT5660_IRQ_MB1_OC_SFT			15
+#define RT5660_IRQ_MB1_OC_BP			(0x0 << 15)
+#define RT5660_IRQ_MB1_OC_NOR			(0x1 << 15)
+#define RT5660_IRQ_MB2_OC_MASK			(0x1 << 14)
+#define RT5660_IRQ_MB2_OC_SFT			14
+#define RT5660_IRQ_MB2_OC_BP			(0x0 << 14)
+#define RT5660_IRQ_MB2_OC_NOR			(0x1 << 14)
+#define RT5660_MB1_OC_STKY_MASK			(0x1 << 11)
+#define RT5660_MB1_OC_STKY_SFT			11
+#define RT5660_MB1_OC_STKY_DIS			(0x0 << 11)
+#define RT5660_MB1_OC_STKY_EN			(0x1 << 11)
+#define RT5660_MB2_OC_STKY_MASK			(0x1 << 10)
+#define RT5660_MB2_OC_STKY_SFT			10
+#define RT5660_MB2_OC_STKY_DIS			(0x0 << 10)
+#define RT5660_MB2_OC_STKY_EN			(0x1 << 10)
+#define RT5660_MB1_OC_P_MASK			(0x1 << 7)
+#define RT5660_MB1_OC_P_SFT			7
+#define RT5660_MB1_OC_P_NOR			(0x0 << 7)
+#define RT5660_MB1_OC_P_INV			(0x1 << 7)
+#define RT5660_MB2_OC_P_MASK			(0x1 << 6)
+#define RT5660_MB2_OC_P_SFT			6
+#define RT5660_MB2_OC_P_NOR			(0x0 << 6)
+#define RT5660_MB2_OC_P_INV			(0x1 << 6)
+#define RT5660_MB1_OC_CLR			(0x1 << 3)
+#define RT5660_MB1_OC_CLR_SFT			3
+#define RT5660_MB2_OC_CLR			(0x1 << 2)
+#define RT5660_MB2_OC_CLR_SFT			2
+
+/* GPIO Control 1 (0xc0) */
+#define RT5660_GP2_PIN_MASK			(0x1 << 14)
+#define RT5660_GP2_PIN_SFT			14
+#define RT5660_GP2_PIN_GPIO2			(0x0 << 14)
+#define RT5660_GP2_PIN_DMIC1_SDA		(0x1 << 14)
+#define RT5660_GP1_PIN_MASK			(0x3 << 12)
+#define RT5660_GP1_PIN_SFT			12
+#define RT5660_GP1_PIN_GPIO1			(0x0 << 12)
+#define RT5660_GP1_PIN_DMIC1_SCL		(0x1 << 12)
+#define RT5660_GP1_PIN_IRQ			(0x2 << 12)
+#define RT5660_GPIO_M_MASK			(0x1 << 9)
+#define RT5660_GPIO_M_SFT			9
+#define RT5660_GPIO_M_FLT			(0x0 << 9)
+#define RT5660_GPIO_M_PH			(0x1 << 9)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5660_GP2_PF_MASK			(0x1 << 5)
+#define RT5660_GP2_PF_SFT			5
+#define RT5660_GP2_PF_IN			(0x0 << 5)
+#define RT5660_GP2_PF_OUT			(0x1 << 5)
+#define RT5660_GP2_OUT_MASK			(0x1 << 4)
+#define RT5660_GP2_OUT_SFT			4
+#define RT5660_GP2_OUT_LO			(0x0 << 4)
+#define RT5660_GP2_OUT_HI			(0x1 << 4)
+#define RT5660_GP2_P_MASK			(0x1 << 3)
+#define RT5660_GP2_P_SFT			3
+#define RT5660_GP2_P_NOR			(0x0 << 3)
+#define RT5660_GP2_P_INV			(0x1 << 3)
+#define RT5660_GP1_PF_MASK			(0x1 << 2)
+#define RT5660_GP1_PF_SFT			2
+#define RT5660_GP1_PF_IN			(0x0 << 2)
+#define RT5660_GP1_PF_OUT			(0x1 << 2)
+#define RT5660_GP1_OUT_MASK			(0x1 << 1)
+#define RT5660_GP1_OUT_SFT			1
+#define RT5660_GP1_OUT_LO			(0x0 << 1)
+#define RT5660_GP1_OUT_HI			(0x1 << 1)
+#define RT5660_GP1_P_MASK			(0x1)
+#define RT5660_GP1_P_SFT			0
+#define RT5660_GP1_P_NOR			(0x0)
+#define RT5660_GP1_P_INV			(0x1)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5660_SV_MASK				(0x1 << 15)
+#define RT5660_SV_SFT				15
+#define RT5660_SV_DIS				(0x0 << 15)
+#define RT5660_SV_EN				(0x1 << 15)
+#define RT5660_SPO_SV_MASK			(0x1 << 14)
+#define RT5660_SPO_SV_SFT			14
+#define RT5660_SPO_SV_DIS			(0x0 << 14)
+#define RT5660_SPO_SV_EN			(0x1 << 14)
+#define RT5660_OUT_SV_MASK			(0x1 << 12)
+#define RT5660_OUT_SV_SFT			12
+#define RT5660_OUT_SV_DIS			(0x0 << 12)
+#define RT5660_OUT_SV_EN			(0x1 << 12)
+#define RT5660_ZCD_DIG_MASK			(0x1 << 11)
+#define RT5660_ZCD_DIG_SFT			11
+#define RT5660_ZCD_DIG_DIS			(0x0 << 11)
+#define RT5660_ZCD_DIG_EN			(0x1 << 11)
+#define RT5660_ZCD_MASK				(0x1 << 10)
+#define RT5660_ZCD_SFT				10
+#define RT5660_ZCD_PD				(0x0 << 10)
+#define RT5660_ZCD_PU				(0x1 << 10)
+#define RT5660_SV_DLY_MASK			(0xf)
+#define RT5660_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5660_ZCD_SPO_MASK			(0x1 << 15)
+#define RT5660_ZCD_SPO_SFT			15
+#define RT5660_ZCD_SPO_DIS			(0x0 << 15)
+#define RT5660_ZCD_SPO_EN			(0x1 << 15)
+#define RT5660_ZCD_OMR_MASK			(0x1 << 8)
+#define RT5660_ZCD_OMR_SFT			8
+#define RT5660_ZCD_OMR_DIS			(0x0 << 8)
+#define RT5660_ZCD_OMR_EN			(0x1 << 8)
+#define RT5660_ZCD_OML_MASK			(0x1 << 7)
+#define RT5660_ZCD_OML_SFT			7
+#define RT5660_ZCD_OML_DIS			(0x0 << 7)
+#define RT5660_ZCD_OML_EN			(0x1 << 7)
+#define RT5660_ZCD_SPM_MASK			(0x1 << 6)
+#define RT5660_ZCD_SPM_SFT			6
+#define RT5660_ZCD_SPM_DIS			(0x0 << 6)
+#define RT5660_ZCD_SPM_EN			(0x1 << 6)
+#define RT5660_ZCD_RMR_MASK			(0x1 << 5)
+#define RT5660_ZCD_RMR_SFT			5
+#define RT5660_ZCD_RMR_DIS			(0x0 << 5)
+#define RT5660_ZCD_RMR_EN			(0x1 << 5)
+#define RT5660_ZCD_RML_MASK			(0x1 << 4)
+#define RT5660_ZCD_RML_SFT			4
+#define RT5660_ZCD_RML_DIS			(0x0 << 4)
+#define RT5660_ZCD_RML_EN			(0x1 << 4)
+
+/* General Control 1 (0xfa) */
+#define RT5660_PWR_VREF_HP			(0x1 << 11)
+#define RT5660_PWR_VREF_HP_SFT			11
+#define RT5660_AUTO_DIS_AMP			(0x1 << 6)
+#define RT5660_MCLK_DET				(0x1 << 5)
+#define RT5660_POW_CLKDET			(0x1 << 1)
+#define RT5660_DIG_GATE_CTRL			(0x1)
+#define RT5660_DIG_GATE_CTRL_SFT		0
+
+/* System Clock Source */
+#define RT5660_SCLK_S_MCLK			0
+#define RT5660_SCLK_S_PLL1			1
+#define RT5660_SCLK_S_RCCLK			2
+
+/* PLL1 Source */
+#define RT5660_PLL1_S_MCLK			0
+#define RT5660_PLL1_S_BCLK			1
+
+enum {
+	RT5660_AIF1,
+	RT5660_AIFS,
+};
+
+struct rt5660_priv {
+	struct snd_soc_component *component;
+	struct rt5660_platform_data pdata;
+	struct regmap *regmap;
+	struct clk *mclk;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5660_AIFS];
+	int bclk[RT5660_AIFS];
+	int master[RT5660_AIFS];
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+};
+
+#endif
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
new file mode 100644
index 0000000..9bd24ad
--- /dev/null
+++ b/sound/soc/codecs/rt5663.c
@@ -0,0 +1,3679 @@
+/*
+ * rt5663.c  --  RT5663 ALSA SoC audio codec driver
+ *
+ * Copyright 2016 Realtek Semiconductor Corp.
+ * Author: Jack Yu <jack.yu@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rt5663.h"
+#include "rl6231.h"
+
+#define RT5663_DEVICE_ID_2 0x6451
+#define RT5663_DEVICE_ID_1 0x6406
+
+enum {
+	CODEC_VER_1,
+	CODEC_VER_0,
+};
+
+struct impedance_mapping_table {
+	unsigned int imp_min;
+	unsigned int imp_max;
+	unsigned int vol;
+	unsigned int dc_offset_l_manual;
+	unsigned int dc_offset_r_manual;
+	unsigned int dc_offset_l_manual_mic;
+	unsigned int dc_offset_r_manual_mic;
+};
+
+struct rt5663_priv {
+	struct snd_soc_component *component;
+	struct rt5663_platform_data pdata;
+	struct regmap *regmap;
+	struct delayed_work jack_detect_work, jd_unplug_work;
+	struct snd_soc_jack *hs_jack;
+	struct timer_list btn_check_timer;
+	struct impedance_mapping_table *imp_table;
+
+	int codec_ver;
+	int sysclk;
+	int sysclk_src;
+	int lrck;
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+	int jack_type;
+};
+
+static const struct reg_sequence rt5663_patch_list[] = {
+	{ 0x002a, 0x8020 },
+	{ 0x0086, 0x0028 },
+	{ 0x0117, 0x0f28 },
+	{ 0x02fb, 0x8089 },
+};
+
+static const struct reg_default rt5663_v2_reg[] = {
+	{ 0x0000, 0x0000 },
+	{ 0x0001, 0xc8c8 },
+	{ 0x0002, 0x8080 },
+	{ 0x0003, 0x8000 },
+	{ 0x0004, 0xc80a },
+	{ 0x0005, 0x0000 },
+	{ 0x0006, 0x0000 },
+	{ 0x0007, 0x0000 },
+	{ 0x000a, 0x0000 },
+	{ 0x000b, 0x0000 },
+	{ 0x000c, 0x0000 },
+	{ 0x000d, 0x0000 },
+	{ 0x000f, 0x0808 },
+	{ 0x0010, 0x4000 },
+	{ 0x0011, 0x0000 },
+	{ 0x0012, 0x1404 },
+	{ 0x0013, 0x1000 },
+	{ 0x0014, 0xa00a },
+	{ 0x0015, 0x0404 },
+	{ 0x0016, 0x0404 },
+	{ 0x0017, 0x0011 },
+	{ 0x0018, 0xafaf },
+	{ 0x0019, 0xafaf },
+	{ 0x001a, 0xafaf },
+	{ 0x001b, 0x0011 },
+	{ 0x001c, 0x2f2f },
+	{ 0x001d, 0x2f2f },
+	{ 0x001e, 0x2f2f },
+	{ 0x001f, 0x0000 },
+	{ 0x0020, 0x0000 },
+	{ 0x0021, 0x0000 },
+	{ 0x0022, 0x5757 },
+	{ 0x0023, 0x0039 },
+	{ 0x0024, 0x000b },
+	{ 0x0026, 0xc0c0 },
+	{ 0x0027, 0xc0c0 },
+	{ 0x0028, 0xc0c0 },
+	{ 0x0029, 0x8080 },
+	{ 0x002a, 0xaaaa },
+	{ 0x002b, 0xaaaa },
+	{ 0x002c, 0xaba8 },
+	{ 0x002d, 0x0000 },
+	{ 0x002e, 0x0000 },
+	{ 0x002f, 0x0000 },
+	{ 0x0030, 0x0000 },
+	{ 0x0031, 0x5000 },
+	{ 0x0032, 0x0000 },
+	{ 0x0033, 0x0000 },
+	{ 0x0034, 0x0000 },
+	{ 0x0035, 0x0000 },
+	{ 0x003a, 0x0000 },
+	{ 0x003b, 0x0000 },
+	{ 0x003c, 0x00ff },
+	{ 0x003d, 0x0000 },
+	{ 0x003e, 0x00ff },
+	{ 0x003f, 0x0000 },
+	{ 0x0040, 0x0000 },
+	{ 0x0041, 0x00ff },
+	{ 0x0042, 0x0000 },
+	{ 0x0043, 0x00ff },
+	{ 0x0044, 0x0c0c },
+	{ 0x0049, 0xc00b },
+	{ 0x004a, 0x0000 },
+	{ 0x004b, 0x031f },
+	{ 0x004d, 0x0000 },
+	{ 0x004e, 0x001f },
+	{ 0x004f, 0x0000 },
+	{ 0x0050, 0x001f },
+	{ 0x0052, 0xf000 },
+	{ 0x0061, 0x0000 },
+	{ 0x0062, 0x0000 },
+	{ 0x0063, 0x003e },
+	{ 0x0064, 0x0000 },
+	{ 0x0065, 0x0000 },
+	{ 0x0066, 0x003f },
+	{ 0x0067, 0x0000 },
+	{ 0x006b, 0x0000 },
+	{ 0x006d, 0xff00 },
+	{ 0x006e, 0x2808 },
+	{ 0x006f, 0x000a },
+	{ 0x0070, 0x8000 },
+	{ 0x0071, 0x8000 },
+	{ 0x0072, 0x8000 },
+	{ 0x0073, 0x7000 },
+	{ 0x0074, 0x7770 },
+	{ 0x0075, 0x0002 },
+	{ 0x0076, 0x0001 },
+	{ 0x0078, 0x00f0 },
+	{ 0x0079, 0x0000 },
+	{ 0x007a, 0x0000 },
+	{ 0x007b, 0x0000 },
+	{ 0x007c, 0x0000 },
+	{ 0x007d, 0x0123 },
+	{ 0x007e, 0x4500 },
+	{ 0x007f, 0x8003 },
+	{ 0x0080, 0x0000 },
+	{ 0x0081, 0x0000 },
+	{ 0x0082, 0x0000 },
+	{ 0x0083, 0x0000 },
+	{ 0x0084, 0x0000 },
+	{ 0x0085, 0x0000 },
+	{ 0x0086, 0x0008 },
+	{ 0x0087, 0x0000 },
+	{ 0x0088, 0x0000 },
+	{ 0x0089, 0x0000 },
+	{ 0x008a, 0x0000 },
+	{ 0x008b, 0x0000 },
+	{ 0x008c, 0x0003 },
+	{ 0x008e, 0x0060 },
+	{ 0x008f, 0x1000 },
+	{ 0x0091, 0x0c26 },
+	{ 0x0092, 0x0073 },
+	{ 0x0093, 0x0000 },
+	{ 0x0094, 0x0080 },
+	{ 0x0098, 0x0000 },
+	{ 0x0099, 0x0000 },
+	{ 0x009a, 0x0007 },
+	{ 0x009f, 0x0000 },
+	{ 0x00a0, 0x0000 },
+	{ 0x00a1, 0x0002 },
+	{ 0x00a2, 0x0001 },
+	{ 0x00a3, 0x0002 },
+	{ 0x00a4, 0x0001 },
+	{ 0x00ae, 0x2040 },
+	{ 0x00af, 0x0000 },
+	{ 0x00b6, 0x0000 },
+	{ 0x00b7, 0x0000 },
+	{ 0x00b8, 0x0000 },
+	{ 0x00b9, 0x0000 },
+	{ 0x00ba, 0x0002 },
+	{ 0x00bb, 0x0000 },
+	{ 0x00be, 0x0000 },
+	{ 0x00c0, 0x0000 },
+	{ 0x00c1, 0x0aaa },
+	{ 0x00c2, 0xaa80 },
+	{ 0x00c3, 0x0003 },
+	{ 0x00c4, 0x0000 },
+	{ 0x00d0, 0x0000 },
+	{ 0x00d1, 0x2244 },
+	{ 0x00d2, 0x0000 },
+	{ 0x00d3, 0x3300 },
+	{ 0x00d4, 0x2200 },
+	{ 0x00d9, 0x0809 },
+	{ 0x00da, 0x0000 },
+	{ 0x00db, 0x0008 },
+	{ 0x00dc, 0x00c0 },
+	{ 0x00dd, 0x6724 },
+	{ 0x00de, 0x3131 },
+	{ 0x00df, 0x0008 },
+	{ 0x00e0, 0x4000 },
+	{ 0x00e1, 0x3131 },
+	{ 0x00e2, 0x600c },
+	{ 0x00ea, 0xb320 },
+	{ 0x00eb, 0x0000 },
+	{ 0x00ec, 0xb300 },
+	{ 0x00ed, 0x0000 },
+	{ 0x00ee, 0xb320 },
+	{ 0x00ef, 0x0000 },
+	{ 0x00f0, 0x0201 },
+	{ 0x00f1, 0x0ddd },
+	{ 0x00f2, 0x0ddd },
+	{ 0x00f6, 0x0000 },
+	{ 0x00f7, 0x0000 },
+	{ 0x00f8, 0x0000 },
+	{ 0x00fa, 0x0000 },
+	{ 0x00fb, 0x0000 },
+	{ 0x00fc, 0x0000 },
+	{ 0x00fd, 0x0000 },
+	{ 0x00fe, 0x10ec },
+	{ 0x00ff, 0x6451 },
+	{ 0x0100, 0xaaaa },
+	{ 0x0101, 0x000a },
+	{ 0x010a, 0xaaaa },
+	{ 0x010b, 0xa0a0 },
+	{ 0x010c, 0xaeae },
+	{ 0x010d, 0xaaaa },
+	{ 0x010e, 0xaaaa },
+	{ 0x010f, 0xaaaa },
+	{ 0x0110, 0xe002 },
+	{ 0x0111, 0xa602 },
+	{ 0x0112, 0xaaaa },
+	{ 0x0113, 0x2000 },
+	{ 0x0117, 0x0f00 },
+	{ 0x0125, 0x0420 },
+	{ 0x0132, 0x0000 },
+	{ 0x0133, 0x0000 },
+	{ 0x0136, 0x5555 },
+	{ 0x0137, 0x5540 },
+	{ 0x0138, 0x3700 },
+	{ 0x0139, 0x79a1 },
+	{ 0x013a, 0x2020 },
+	{ 0x013b, 0x2020 },
+	{ 0x013c, 0x2005 },
+	{ 0x013f, 0x0000 },
+	{ 0x0145, 0x0002 },
+	{ 0x0146, 0x0000 },
+	{ 0x0147, 0x0000 },
+	{ 0x0148, 0x0000 },
+	{ 0x0160, 0x4ec0 },
+	{ 0x0161, 0x0080 },
+	{ 0x0162, 0x0200 },
+	{ 0x0163, 0x0800 },
+	{ 0x0164, 0x0000 },
+	{ 0x0165, 0x0000 },
+	{ 0x0166, 0x0000 },
+	{ 0x0167, 0x000f },
+	{ 0x0168, 0x000f },
+	{ 0x0170, 0x4e80 },
+	{ 0x0171, 0x0080 },
+	{ 0x0172, 0x0200 },
+	{ 0x0173, 0x0800 },
+	{ 0x0174, 0x00ff },
+	{ 0x0175, 0x0000 },
+	{ 0x0190, 0x4131 },
+	{ 0x0191, 0x4131 },
+	{ 0x0192, 0x4131 },
+	{ 0x0193, 0x4131 },
+	{ 0x0194, 0x0000 },
+	{ 0x0195, 0x0000 },
+	{ 0x0196, 0x0000 },
+	{ 0x0197, 0x0000 },
+	{ 0x0198, 0x0000 },
+	{ 0x0199, 0x0000 },
+	{ 0x01a0, 0x1e64 },
+	{ 0x01a1, 0x06a3 },
+	{ 0x01a2, 0x0000 },
+	{ 0x01a3, 0x0000 },
+	{ 0x01a4, 0x0000 },
+	{ 0x01a5, 0x0000 },
+	{ 0x01a6, 0x0000 },
+	{ 0x01a7, 0x0000 },
+	{ 0x01a8, 0x0000 },
+	{ 0x01a9, 0x0000 },
+	{ 0x01aa, 0x0000 },
+	{ 0x01ab, 0x0000 },
+	{ 0x01b5, 0x0000 },
+	{ 0x01b6, 0x01c3 },
+	{ 0x01b7, 0x02a0 },
+	{ 0x01b8, 0x03e9 },
+	{ 0x01b9, 0x1389 },
+	{ 0x01ba, 0xc351 },
+	{ 0x01bb, 0x0009 },
+	{ 0x01bc, 0x0018 },
+	{ 0x01bd, 0x002a },
+	{ 0x01be, 0x004c },
+	{ 0x01bf, 0x0097 },
+	{ 0x01c0, 0x433d },
+	{ 0x01c1, 0x0000 },
+	{ 0x01c2, 0x0000 },
+	{ 0x01c3, 0x0000 },
+	{ 0x01c4, 0x0000 },
+	{ 0x01c5, 0x0000 },
+	{ 0x01c6, 0x0000 },
+	{ 0x01c7, 0x0000 },
+	{ 0x01c8, 0x40af },
+	{ 0x01c9, 0x0702 },
+	{ 0x01ca, 0x0000 },
+	{ 0x01cb, 0x0000 },
+	{ 0x01cc, 0x5757 },
+	{ 0x01cd, 0x5757 },
+	{ 0x01ce, 0x5757 },
+	{ 0x01cf, 0x5757 },
+	{ 0x01d0, 0x5757 },
+	{ 0x01d1, 0x5757 },
+	{ 0x01d2, 0x5757 },
+	{ 0x01d3, 0x5757 },
+	{ 0x01d4, 0x5757 },
+	{ 0x01d5, 0x5757 },
+	{ 0x01d6, 0x003c },
+	{ 0x01da, 0x0000 },
+	{ 0x01db, 0x0000 },
+	{ 0x01dc, 0x0000 },
+	{ 0x01de, 0x7c00 },
+	{ 0x01df, 0x0320 },
+	{ 0x01e0, 0x06a1 },
+	{ 0x01e1, 0x0000 },
+	{ 0x01e2, 0x0000 },
+	{ 0x01e3, 0x0000 },
+	{ 0x01e4, 0x0000 },
+	{ 0x01e5, 0x0000 },
+	{ 0x01e6, 0x0001 },
+	{ 0x01e7, 0x0000 },
+	{ 0x01e8, 0x0000 },
+	{ 0x01ea, 0x0000 },
+	{ 0x01eb, 0x0000 },
+	{ 0x01ec, 0x0000 },
+	{ 0x01ed, 0x0000 },
+	{ 0x01ee, 0x0000 },
+	{ 0x01ef, 0x0000 },
+	{ 0x01f0, 0x0000 },
+	{ 0x01f1, 0x0000 },
+	{ 0x01f2, 0x0000 },
+	{ 0x01f3, 0x0000 },
+	{ 0x01f4, 0x0000 },
+	{ 0x0200, 0x0000 },
+	{ 0x0201, 0x0000 },
+	{ 0x0202, 0x0000 },
+	{ 0x0203, 0x0000 },
+	{ 0x0204, 0x0000 },
+	{ 0x0205, 0x0000 },
+	{ 0x0206, 0x0000 },
+	{ 0x0207, 0x0000 },
+	{ 0x0208, 0x0000 },
+	{ 0x0210, 0x60b1 },
+	{ 0x0211, 0xa000 },
+	{ 0x0212, 0x024c },
+	{ 0x0213, 0xf7ff },
+	{ 0x0214, 0x024c },
+	{ 0x0215, 0x0102 },
+	{ 0x0216, 0x00a3 },
+	{ 0x0217, 0x0048 },
+	{ 0x0218, 0x92c0 },
+	{ 0x0219, 0x0000 },
+	{ 0x021a, 0x00c8 },
+	{ 0x021b, 0x0020 },
+	{ 0x02fa, 0x0000 },
+	{ 0x02fb, 0x0000 },
+	{ 0x02fc, 0x0000 },
+	{ 0x02ff, 0x0110 },
+	{ 0x0300, 0x001f },
+	{ 0x0301, 0x032c },
+	{ 0x0302, 0x5f21 },
+	{ 0x0303, 0x4000 },
+	{ 0x0304, 0x4000 },
+	{ 0x0305, 0x06d5 },
+	{ 0x0306, 0x8000 },
+	{ 0x0307, 0x0700 },
+	{ 0x0310, 0x4560 },
+	{ 0x0311, 0xa4a8 },
+	{ 0x0312, 0x7418 },
+	{ 0x0313, 0x0000 },
+	{ 0x0314, 0x0006 },
+	{ 0x0315, 0xffff },
+	{ 0x0316, 0xc400 },
+	{ 0x0317, 0x0000 },
+	{ 0x0330, 0x00a6 },
+	{ 0x0331, 0x04c3 },
+	{ 0x0332, 0x27c8 },
+	{ 0x0333, 0xbf50 },
+	{ 0x0334, 0x0045 },
+	{ 0x0335, 0x0007 },
+	{ 0x0336, 0x7418 },
+	{ 0x0337, 0x0501 },
+	{ 0x0338, 0x0000 },
+	{ 0x0339, 0x0010 },
+	{ 0x033a, 0x1010 },
+	{ 0x03c0, 0x7e00 },
+	{ 0x03c1, 0x8000 },
+	{ 0x03c2, 0x8000 },
+	{ 0x03c3, 0x8000 },
+	{ 0x03c4, 0x8000 },
+	{ 0x03c5, 0x8000 },
+	{ 0x03c6, 0x8000 },
+	{ 0x03c7, 0x8000 },
+	{ 0x03c8, 0x8000 },
+	{ 0x03c9, 0x8000 },
+	{ 0x03ca, 0x8000 },
+	{ 0x03cb, 0x8000 },
+	{ 0x03cc, 0x8000 },
+	{ 0x03d0, 0x0000 },
+	{ 0x03d1, 0x0000 },
+	{ 0x03d2, 0x0000 },
+	{ 0x03d3, 0x0000 },
+	{ 0x03d4, 0x2000 },
+	{ 0x03d5, 0x2000 },
+	{ 0x03d6, 0x0000 },
+	{ 0x03d7, 0x0000 },
+	{ 0x03d8, 0x2000 },
+	{ 0x03d9, 0x2000 },
+	{ 0x03da, 0x2000 },
+	{ 0x03db, 0x2000 },
+	{ 0x03dc, 0x0000 },
+	{ 0x03dd, 0x0000 },
+	{ 0x03de, 0x0000 },
+	{ 0x03df, 0x2000 },
+	{ 0x03e0, 0x0000 },
+	{ 0x03e1, 0x0000 },
+	{ 0x03e2, 0x0000 },
+	{ 0x03e3, 0x0000 },
+	{ 0x03e4, 0x0000 },
+	{ 0x03e5, 0x0000 },
+	{ 0x03e6, 0x0000 },
+	{ 0x03e7, 0x0000 },
+	{ 0x03e8, 0x0000 },
+	{ 0x03e9, 0x0000 },
+	{ 0x03ea, 0x0000 },
+	{ 0x03eb, 0x0000 },
+	{ 0x03ec, 0x0000 },
+	{ 0x03ed, 0x0000 },
+	{ 0x03ee, 0x0000 },
+	{ 0x03ef, 0x0000 },
+	{ 0x03f0, 0x0800 },
+	{ 0x03f1, 0x0800 },
+	{ 0x03f2, 0x0800 },
+	{ 0x03f3, 0x0800 },
+	{ 0x03fe, 0x0000 },
+	{ 0x03ff, 0x0000 },
+	{ 0x07f0, 0x0000 },
+	{ 0x07fa, 0x0000 },
+};
+
+static const struct reg_default rt5663_reg[] = {
+	{ 0x0000, 0x0000 },
+	{ 0x0002, 0x0008 },
+	{ 0x0005, 0x1000 },
+	{ 0x0006, 0x1000 },
+	{ 0x000a, 0x0000 },
+	{ 0x0010, 0x000f },
+	{ 0x0015, 0x42f1 },
+	{ 0x0016, 0x0000 },
+	{ 0x0018, 0x000b },
+	{ 0x0019, 0xafaf },
+	{ 0x001c, 0x2f2f },
+	{ 0x001f, 0x0000 },
+	{ 0x0022, 0x5757 },
+	{ 0x0023, 0x0039 },
+	{ 0x0026, 0xc0c0 },
+	{ 0x0029, 0x8080 },
+	{ 0x002a, 0x8020 },
+	{ 0x002c, 0x000c },
+	{ 0x002d, 0x0000 },
+	{ 0x0040, 0x0808 },
+	{ 0x0061, 0x0000 },
+	{ 0x0062, 0x0000 },
+	{ 0x0063, 0x003e },
+	{ 0x0064, 0x0000 },
+	{ 0x0065, 0x0000 },
+	{ 0x0066, 0x0000 },
+	{ 0x006b, 0x0000 },
+	{ 0x006e, 0x0000 },
+	{ 0x006f, 0x0000 },
+	{ 0x0070, 0x8020 },
+	{ 0x0073, 0x1000 },
+	{ 0x0074, 0xe400 },
+	{ 0x0075, 0x0002 },
+	{ 0x0076, 0x0001 },
+	{ 0x0077, 0x00f0 },
+	{ 0x0078, 0x0000 },
+	{ 0x0079, 0x0000 },
+	{ 0x007a, 0x0123 },
+	{ 0x007b, 0x8003 },
+	{ 0x0080, 0x0000 },
+	{ 0x0081, 0x0000 },
+	{ 0x0082, 0x0000 },
+	{ 0x0083, 0x0000 },
+	{ 0x0084, 0x0000 },
+	{ 0x0086, 0x0028 },
+	{ 0x0087, 0x0000 },
+	{ 0x008a, 0x0000 },
+	{ 0x008b, 0x0000 },
+	{ 0x008c, 0x0003 },
+	{ 0x008e, 0x0008 },
+	{ 0x008f, 0x1000 },
+	{ 0x0090, 0x0646 },
+	{ 0x0091, 0x0e3e },
+	{ 0x0092, 0x1071 },
+	{ 0x0093, 0x0000 },
+	{ 0x0094, 0x0080 },
+	{ 0x0097, 0x0000 },
+	{ 0x0098, 0x0000 },
+	{ 0x009a, 0x0000 },
+	{ 0x009f, 0x0000 },
+	{ 0x00ae, 0x6000 },
+	{ 0x00af, 0x0000 },
+	{ 0x00b6, 0x0000 },
+	{ 0x00b7, 0x0000 },
+	{ 0x00b8, 0x0000 },
+	{ 0x00ba, 0x0000 },
+	{ 0x00bb, 0x0000 },
+	{ 0x00be, 0x0000 },
+	{ 0x00bf, 0x0000 },
+	{ 0x00c0, 0x0000 },
+	{ 0x00c1, 0x0000 },
+	{ 0x00c5, 0x0000 },
+	{ 0x00cb, 0xa02f },
+	{ 0x00cc, 0x0000 },
+	{ 0x00cd, 0x0e02 },
+	{ 0x00d9, 0x08f9 },
+	{ 0x00db, 0x0008 },
+	{ 0x00dc, 0x00c0 },
+	{ 0x00dd, 0x6729 },
+	{ 0x00de, 0x3131 },
+	{ 0x00df, 0x0008 },
+	{ 0x00e0, 0x4000 },
+	{ 0x00e1, 0x3131 },
+	{ 0x00e2, 0x0043 },
+	{ 0x00e4, 0x400b },
+	{ 0x00e5, 0x8031 },
+	{ 0x00e6, 0x3080 },
+	{ 0x00e7, 0x4100 },
+	{ 0x00e8, 0x1400 },
+	{ 0x00e9, 0xe00a },
+	{ 0x00ea, 0x0404 },
+	{ 0x00eb, 0x0404 },
+	{ 0x00ec, 0xb320 },
+	{ 0x00ed, 0x0000 },
+	{ 0x00f4, 0x0000 },
+	{ 0x00f6, 0x0000 },
+	{ 0x00f8, 0x0000 },
+	{ 0x00fa, 0x8000 },
+	{ 0x00fd, 0x0001 },
+	{ 0x00fe, 0x10ec },
+	{ 0x00ff, 0x6406 },
+	{ 0x0100, 0xa0a0 },
+	{ 0x0108, 0x4444 },
+	{ 0x0109, 0x4444 },
+	{ 0x010a, 0xaaaa },
+	{ 0x010b, 0x00a0 },
+	{ 0x010c, 0x8aaa },
+	{ 0x010d, 0xaaaa },
+	{ 0x010e, 0x2aaa },
+	{ 0x010f, 0x002a },
+	{ 0x0110, 0xa0a4 },
+	{ 0x0111, 0x4602 },
+	{ 0x0112, 0x0101 },
+	{ 0x0113, 0x2000 },
+	{ 0x0114, 0x0000 },
+	{ 0x0116, 0x0000 },
+	{ 0x0117, 0x0f28 },
+	{ 0x0118, 0x0006 },
+	{ 0x0125, 0x2424 },
+	{ 0x0126, 0x5550 },
+	{ 0x0127, 0x0400 },
+	{ 0x0128, 0x7711 },
+	{ 0x0132, 0x0004 },
+	{ 0x0137, 0x5441 },
+	{ 0x0139, 0x79a1 },
+	{ 0x013a, 0x30c0 },
+	{ 0x013b, 0x2000 },
+	{ 0x013c, 0x2005 },
+	{ 0x013d, 0x30c0 },
+	{ 0x013e, 0x0000 },
+	{ 0x0140, 0x3700 },
+	{ 0x0141, 0x1f00 },
+	{ 0x0144, 0x0000 },
+	{ 0x0145, 0x0002 },
+	{ 0x0146, 0x0000 },
+	{ 0x0160, 0x0e80 },
+	{ 0x0161, 0x0080 },
+	{ 0x0162, 0x0200 },
+	{ 0x0163, 0x0800 },
+	{ 0x0164, 0x0000 },
+	{ 0x0165, 0x0000 },
+	{ 0x0166, 0x0000 },
+	{ 0x0167, 0x1417 },
+	{ 0x0168, 0x0017 },
+	{ 0x0169, 0x0017 },
+	{ 0x0180, 0x2000 },
+	{ 0x0181, 0x0000 },
+	{ 0x0182, 0x0000 },
+	{ 0x0183, 0x2000 },
+	{ 0x0184, 0x0000 },
+	{ 0x0185, 0x0000 },
+	{ 0x01b0, 0x4b30 },
+	{ 0x01b1, 0x0000 },
+	{ 0x01b2, 0xd870 },
+	{ 0x01b3, 0x0000 },
+	{ 0x01b4, 0x0030 },
+	{ 0x01b5, 0x5757 },
+	{ 0x01b6, 0x5757 },
+	{ 0x01b7, 0x5757 },
+	{ 0x01b8, 0x5757 },
+	{ 0x01c0, 0x433d },
+	{ 0x01c1, 0x0540 },
+	{ 0x01c2, 0x0000 },
+	{ 0x01c3, 0x0000 },
+	{ 0x01c4, 0x0000 },
+	{ 0x01c5, 0x0009 },
+	{ 0x01c6, 0x0018 },
+	{ 0x01c7, 0x002a },
+	{ 0x01c8, 0x004c },
+	{ 0x01c9, 0x0097 },
+	{ 0x01ca, 0x01c3 },
+	{ 0x01cb, 0x03e9 },
+	{ 0x01cc, 0x1389 },
+	{ 0x01cd, 0xc351 },
+	{ 0x01ce, 0x0000 },
+	{ 0x01cf, 0x0000 },
+	{ 0x01d0, 0x0000 },
+	{ 0x01d1, 0x0000 },
+	{ 0x01d2, 0x0000 },
+	{ 0x01d3, 0x003c },
+	{ 0x01d4, 0x5757 },
+	{ 0x01d5, 0x5757 },
+	{ 0x01d6, 0x5757 },
+	{ 0x01d7, 0x5757 },
+	{ 0x01d8, 0x5757 },
+	{ 0x01d9, 0x5757 },
+	{ 0x01da, 0x0000 },
+	{ 0x01db, 0x0000 },
+	{ 0x01dd, 0x0009 },
+	{ 0x01de, 0x7f00 },
+	{ 0x01df, 0x00c8 },
+	{ 0x01e0, 0x0691 },
+	{ 0x01e1, 0x0000 },
+	{ 0x01e2, 0x0000 },
+	{ 0x01e3, 0x0000 },
+	{ 0x01e4, 0x0000 },
+	{ 0x01e5, 0x0040 },
+	{ 0x01e6, 0x0000 },
+	{ 0x01e7, 0x0000 },
+	{ 0x01e8, 0x0000 },
+	{ 0x01ea, 0x0000 },
+	{ 0x01eb, 0x0000 },
+	{ 0x01ec, 0x0000 },
+	{ 0x01ed, 0x0000 },
+	{ 0x01ee, 0x0000 },
+	{ 0x01ef, 0x0000 },
+	{ 0x01f0, 0x0000 },
+	{ 0x01f1, 0x0000 },
+	{ 0x01f2, 0x0000 },
+	{ 0x0200, 0x0000 },
+	{ 0x0201, 0x2244 },
+	{ 0x0202, 0xaaaa },
+	{ 0x0250, 0x8010 },
+	{ 0x0251, 0x0000 },
+	{ 0x0252, 0x028a },
+	{ 0x02fa, 0x0000 },
+	{ 0x02fb, 0x8089 },
+	{ 0x02fc, 0x0300 },
+	{ 0x0300, 0x0000 },
+	{ 0x03d0, 0x0000 },
+	{ 0x03d1, 0x0000 },
+	{ 0x03d2, 0x0000 },
+	{ 0x03d3, 0x0000 },
+	{ 0x03d4, 0x2000 },
+	{ 0x03d5, 0x2000 },
+	{ 0x03d6, 0x0000 },
+	{ 0x03d7, 0x0000 },
+	{ 0x03d8, 0x2000 },
+	{ 0x03d9, 0x2000 },
+	{ 0x03da, 0x2000 },
+	{ 0x03db, 0x2000 },
+	{ 0x03dc, 0x0000 },
+	{ 0x03dd, 0x0000 },
+	{ 0x03de, 0x0000 },
+	{ 0x03df, 0x2000 },
+	{ 0x03e0, 0x0000 },
+	{ 0x03e1, 0x0000 },
+	{ 0x03e2, 0x0000 },
+	{ 0x03e3, 0x0000 },
+	{ 0x03e4, 0x0000 },
+	{ 0x03e5, 0x0000 },
+	{ 0x03e6, 0x0000 },
+	{ 0x03e7, 0x0000 },
+	{ 0x03e8, 0x0000 },
+	{ 0x03e9, 0x0000 },
+	{ 0x03ea, 0x0000 },
+	{ 0x03eb, 0x0000 },
+	{ 0x03ec, 0x0000 },
+	{ 0x03ed, 0x0000 },
+	{ 0x03ee, 0x0000 },
+	{ 0x03ef, 0x0000 },
+	{ 0x03f0, 0x0800 },
+	{ 0x03f1, 0x0800 },
+	{ 0x03f2, 0x0800 },
+	{ 0x03f3, 0x0800 },
+};
+
+static bool rt5663_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5663_RESET:
+	case RT5663_SIL_DET_CTL:
+	case RT5663_HP_IMP_GAIN_2:
+	case RT5663_AD_DA_MIXER:
+	case RT5663_FRAC_DIV_2:
+	case RT5663_MICBIAS_1:
+	case RT5663_ASRC_11_2:
+	case RT5663_ADC_EQ_1:
+	case RT5663_INT_ST_1:
+	case RT5663_INT_ST_2:
+	case RT5663_GPIO_STA1:
+	case RT5663_SIN_GEN_1:
+	case RT5663_IL_CMD_1:
+	case RT5663_IL_CMD_5:
+	case RT5663_IL_CMD_PWRSAV1:
+	case RT5663_EM_JACK_TYPE_1:
+	case RT5663_EM_JACK_TYPE_2:
+	case RT5663_EM_JACK_TYPE_3:
+	case RT5663_JD_CTRL2:
+	case RT5663_VENDOR_ID:
+	case RT5663_VENDOR_ID_1:
+	case RT5663_VENDOR_ID_2:
+	case RT5663_PLL_INT_REG:
+	case RT5663_SOFT_RAMP:
+	case RT5663_STO_DRE_1:
+	case RT5663_STO_DRE_5:
+	case RT5663_STO_DRE_6:
+	case RT5663_STO_DRE_7:
+	case RT5663_MIC_DECRO_1:
+	case RT5663_MIC_DECRO_4:
+	case RT5663_HP_IMP_SEN_1:
+	case RT5663_HP_IMP_SEN_3:
+	case RT5663_HP_IMP_SEN_4:
+	case RT5663_HP_IMP_SEN_5:
+	case RT5663_HP_CALIB_1_1:
+	case RT5663_HP_CALIB_9:
+	case RT5663_HP_CALIB_ST1:
+	case RT5663_HP_CALIB_ST2:
+	case RT5663_HP_CALIB_ST3:
+	case RT5663_HP_CALIB_ST4:
+	case RT5663_HP_CALIB_ST5:
+	case RT5663_HP_CALIB_ST6:
+	case RT5663_HP_CALIB_ST7:
+	case RT5663_HP_CALIB_ST8:
+	case RT5663_HP_CALIB_ST9:
+	case RT5663_ANA_JD:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5663_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5663_RESET:
+	case RT5663_HP_OUT_EN:
+	case RT5663_HP_LCH_DRE:
+	case RT5663_HP_RCH_DRE:
+	case RT5663_CALIB_BST:
+	case RT5663_RECMIX:
+	case RT5663_SIL_DET_CTL:
+	case RT5663_PWR_SAV_SILDET:
+	case RT5663_SIDETONE_CTL:
+	case RT5663_STO1_DAC_DIG_VOL:
+	case RT5663_STO1_ADC_DIG_VOL:
+	case RT5663_STO1_BOOST:
+	case RT5663_HP_IMP_GAIN_1:
+	case RT5663_HP_IMP_GAIN_2:
+	case RT5663_STO1_ADC_MIXER:
+	case RT5663_AD_DA_MIXER:
+	case RT5663_STO_DAC_MIXER:
+	case RT5663_DIG_SIDE_MIXER:
+	case RT5663_BYPASS_STO_DAC:
+	case RT5663_CALIB_REC_MIX:
+	case RT5663_PWR_DIG_1:
+	case RT5663_PWR_DIG_2:
+	case RT5663_PWR_ANLG_1:
+	case RT5663_PWR_ANLG_2:
+	case RT5663_PWR_ANLG_3:
+	case RT5663_PWR_MIXER:
+	case RT5663_SIG_CLK_DET:
+	case RT5663_PRE_DIV_GATING_1:
+	case RT5663_PRE_DIV_GATING_2:
+	case RT5663_I2S1_SDP:
+	case RT5663_ADDA_CLK_1:
+	case RT5663_ADDA_RST:
+	case RT5663_FRAC_DIV_1:
+	case RT5663_FRAC_DIV_2:
+	case RT5663_TDM_1:
+	case RT5663_TDM_2:
+	case RT5663_TDM_3:
+	case RT5663_TDM_4:
+	case RT5663_TDM_5:
+	case RT5663_GLB_CLK:
+	case RT5663_PLL_1:
+	case RT5663_PLL_2:
+	case RT5663_ASRC_1:
+	case RT5663_ASRC_2:
+	case RT5663_ASRC_4:
+	case RT5663_DUMMY_REG:
+	case RT5663_ASRC_8:
+	case RT5663_ASRC_9:
+	case RT5663_ASRC_11:
+	case RT5663_DEPOP_1:
+	case RT5663_DEPOP_2:
+	case RT5663_DEPOP_3:
+	case RT5663_HP_CHARGE_PUMP_1:
+	case RT5663_HP_CHARGE_PUMP_2:
+	case RT5663_MICBIAS_1:
+	case RT5663_RC_CLK:
+	case RT5663_ASRC_11_2:
+	case RT5663_DUMMY_REG_2:
+	case RT5663_REC_PATH_GAIN:
+	case RT5663_AUTO_1MRC_CLK:
+	case RT5663_ADC_EQ_1:
+	case RT5663_ADC_EQ_2:
+	case RT5663_IRQ_1:
+	case RT5663_IRQ_2:
+	case RT5663_IRQ_3:
+	case RT5663_IRQ_4:
+	case RT5663_IRQ_5:
+	case RT5663_INT_ST_1:
+	case RT5663_INT_ST_2:
+	case RT5663_GPIO_1:
+	case RT5663_GPIO_2:
+	case RT5663_GPIO_STA1:
+	case RT5663_SIN_GEN_1:
+	case RT5663_SIN_GEN_2:
+	case RT5663_SIN_GEN_3:
+	case RT5663_SOF_VOL_ZC1:
+	case RT5663_IL_CMD_1:
+	case RT5663_IL_CMD_2:
+	case RT5663_IL_CMD_3:
+	case RT5663_IL_CMD_4:
+	case RT5663_IL_CMD_5:
+	case RT5663_IL_CMD_6:
+	case RT5663_IL_CMD_7:
+	case RT5663_IL_CMD_8:
+	case RT5663_IL_CMD_PWRSAV1:
+	case RT5663_IL_CMD_PWRSAV2:
+	case RT5663_EM_JACK_TYPE_1:
+	case RT5663_EM_JACK_TYPE_2:
+	case RT5663_EM_JACK_TYPE_3:
+	case RT5663_EM_JACK_TYPE_4:
+	case RT5663_EM_JACK_TYPE_5:
+	case RT5663_EM_JACK_TYPE_6:
+	case RT5663_STO1_HPF_ADJ1:
+	case RT5663_STO1_HPF_ADJ2:
+	case RT5663_FAST_OFF_MICBIAS:
+	case RT5663_JD_CTRL1:
+	case RT5663_JD_CTRL2:
+	case RT5663_DIG_MISC:
+	case RT5663_VENDOR_ID:
+	case RT5663_VENDOR_ID_1:
+	case RT5663_VENDOR_ID_2:
+	case RT5663_DIG_VOL_ZCD:
+	case RT5663_ANA_BIAS_CUR_1:
+	case RT5663_ANA_BIAS_CUR_2:
+	case RT5663_ANA_BIAS_CUR_3:
+	case RT5663_ANA_BIAS_CUR_4:
+	case RT5663_ANA_BIAS_CUR_5:
+	case RT5663_ANA_BIAS_CUR_6:
+	case RT5663_BIAS_CUR_5:
+	case RT5663_BIAS_CUR_6:
+	case RT5663_BIAS_CUR_7:
+	case RT5663_BIAS_CUR_8:
+	case RT5663_DACREF_LDO:
+	case RT5663_DUMMY_REG_3:
+	case RT5663_BIAS_CUR_9:
+	case RT5663_DUMMY_REG_4:
+	case RT5663_VREFADJ_OP:
+	case RT5663_VREF_RECMIX:
+	case RT5663_CHARGE_PUMP_1:
+	case RT5663_CHARGE_PUMP_1_2:
+	case RT5663_CHARGE_PUMP_1_3:
+	case RT5663_CHARGE_PUMP_2:
+	case RT5663_DIG_IN_PIN1:
+	case RT5663_PAD_DRV_CTL:
+	case RT5663_PLL_INT_REG:
+	case RT5663_CHOP_DAC_L:
+	case RT5663_CHOP_ADC:
+	case RT5663_CALIB_ADC:
+	case RT5663_CHOP_DAC_R:
+	case RT5663_DUMMY_CTL_DACLR:
+	case RT5663_DUMMY_REG_5:
+	case RT5663_SOFT_RAMP:
+	case RT5663_TEST_MODE_1:
+	case RT5663_TEST_MODE_2:
+	case RT5663_TEST_MODE_3:
+	case RT5663_STO_DRE_1:
+	case RT5663_STO_DRE_2:
+	case RT5663_STO_DRE_3:
+	case RT5663_STO_DRE_4:
+	case RT5663_STO_DRE_5:
+	case RT5663_STO_DRE_6:
+	case RT5663_STO_DRE_7:
+	case RT5663_STO_DRE_8:
+	case RT5663_STO_DRE_9:
+	case RT5663_STO_DRE_10:
+	case RT5663_MIC_DECRO_1:
+	case RT5663_MIC_DECRO_2:
+	case RT5663_MIC_DECRO_3:
+	case RT5663_MIC_DECRO_4:
+	case RT5663_MIC_DECRO_5:
+	case RT5663_MIC_DECRO_6:
+	case RT5663_HP_DECRO_1:
+	case RT5663_HP_DECRO_2:
+	case RT5663_HP_DECRO_3:
+	case RT5663_HP_DECRO_4:
+	case RT5663_HP_DECOUP:
+	case RT5663_HP_IMP_SEN_MAP8:
+	case RT5663_HP_IMP_SEN_MAP9:
+	case RT5663_HP_IMP_SEN_MAP10:
+	case RT5663_HP_IMP_SEN_MAP11:
+	case RT5663_HP_IMP_SEN_1:
+	case RT5663_HP_IMP_SEN_2:
+	case RT5663_HP_IMP_SEN_3:
+	case RT5663_HP_IMP_SEN_4:
+	case RT5663_HP_IMP_SEN_5:
+	case RT5663_HP_IMP_SEN_6:
+	case RT5663_HP_IMP_SEN_7:
+	case RT5663_HP_IMP_SEN_8:
+	case RT5663_HP_IMP_SEN_9:
+	case RT5663_HP_IMP_SEN_10:
+	case RT5663_HP_IMP_SEN_11:
+	case RT5663_HP_IMP_SEN_12:
+	case RT5663_HP_IMP_SEN_13:
+	case RT5663_HP_IMP_SEN_14:
+	case RT5663_HP_IMP_SEN_15:
+	case RT5663_HP_IMP_SEN_16:
+	case RT5663_HP_IMP_SEN_17:
+	case RT5663_HP_IMP_SEN_18:
+	case RT5663_HP_IMP_SEN_19:
+	case RT5663_HP_IMPSEN_DIG5:
+	case RT5663_HP_IMPSEN_MAP1:
+	case RT5663_HP_IMPSEN_MAP2:
+	case RT5663_HP_IMPSEN_MAP3:
+	case RT5663_HP_IMPSEN_MAP4:
+	case RT5663_HP_IMPSEN_MAP5:
+	case RT5663_HP_IMPSEN_MAP7:
+	case RT5663_HP_LOGIC_1:
+	case RT5663_HP_LOGIC_2:
+	case RT5663_HP_CALIB_1:
+	case RT5663_HP_CALIB_1_1:
+	case RT5663_HP_CALIB_2:
+	case RT5663_HP_CALIB_3:
+	case RT5663_HP_CALIB_4:
+	case RT5663_HP_CALIB_5:
+	case RT5663_HP_CALIB_5_1:
+	case RT5663_HP_CALIB_6:
+	case RT5663_HP_CALIB_7:
+	case RT5663_HP_CALIB_9:
+	case RT5663_HP_CALIB_10:
+	case RT5663_HP_CALIB_11:
+	case RT5663_HP_CALIB_ST1:
+	case RT5663_HP_CALIB_ST2:
+	case RT5663_HP_CALIB_ST3:
+	case RT5663_HP_CALIB_ST4:
+	case RT5663_HP_CALIB_ST5:
+	case RT5663_HP_CALIB_ST6:
+	case RT5663_HP_CALIB_ST7:
+	case RT5663_HP_CALIB_ST8:
+	case RT5663_HP_CALIB_ST9:
+	case RT5663_HP_AMP_DET:
+	case RT5663_DUMMY_REG_6:
+	case RT5663_HP_BIAS:
+	case RT5663_CBJ_1:
+	case RT5663_CBJ_2:
+	case RT5663_CBJ_3:
+	case RT5663_DUMMY_1:
+	case RT5663_DUMMY_2:
+	case RT5663_DUMMY_3:
+	case RT5663_ANA_JD:
+	case RT5663_ADC_LCH_LPF1_A1:
+	case RT5663_ADC_RCH_LPF1_A1:
+	case RT5663_ADC_LCH_LPF1_H0:
+	case RT5663_ADC_RCH_LPF1_H0:
+	case RT5663_ADC_LCH_BPF1_A1:
+	case RT5663_ADC_RCH_BPF1_A1:
+	case RT5663_ADC_LCH_BPF1_A2:
+	case RT5663_ADC_RCH_BPF1_A2:
+	case RT5663_ADC_LCH_BPF1_H0:
+	case RT5663_ADC_RCH_BPF1_H0:
+	case RT5663_ADC_LCH_BPF2_A1:
+	case RT5663_ADC_RCH_BPF2_A1:
+	case RT5663_ADC_LCH_BPF2_A2:
+	case RT5663_ADC_RCH_BPF2_A2:
+	case RT5663_ADC_LCH_BPF2_H0:
+	case RT5663_ADC_RCH_BPF2_H0:
+	case RT5663_ADC_LCH_BPF3_A1:
+	case RT5663_ADC_RCH_BPF3_A1:
+	case RT5663_ADC_LCH_BPF3_A2:
+	case RT5663_ADC_RCH_BPF3_A2:
+	case RT5663_ADC_LCH_BPF3_H0:
+	case RT5663_ADC_RCH_BPF3_H0:
+	case RT5663_ADC_LCH_BPF4_A1:
+	case RT5663_ADC_RCH_BPF4_A1:
+	case RT5663_ADC_LCH_BPF4_A2:
+	case RT5663_ADC_RCH_BPF4_A2:
+	case RT5663_ADC_LCH_BPF4_H0:
+	case RT5663_ADC_RCH_BPF4_H0:
+	case RT5663_ADC_LCH_HPF1_A1:
+	case RT5663_ADC_RCH_HPF1_A1:
+	case RT5663_ADC_LCH_HPF1_H0:
+	case RT5663_ADC_RCH_HPF1_H0:
+	case RT5663_ADC_EQ_PRE_VOL_L:
+	case RT5663_ADC_EQ_PRE_VOL_R:
+	case RT5663_ADC_EQ_POST_VOL_L:
+	case RT5663_ADC_EQ_POST_VOL_R:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5663_v2_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5663_RESET:
+	case RT5663_CBJ_TYPE_2:
+	case RT5663_PDM_OUT_CTL:
+	case RT5663_PDM_I2C_DATA_CTL1:
+	case RT5663_PDM_I2C_DATA_CTL4:
+	case RT5663_ALC_BK_GAIN:
+	case RT5663_PLL_2:
+	case RT5663_MICBIAS_1:
+	case RT5663_ADC_EQ_1:
+	case RT5663_INT_ST_1:
+	case RT5663_GPIO_STA2:
+	case RT5663_IL_CMD_1:
+	case RT5663_IL_CMD_5:
+	case RT5663_A_JD_CTRL:
+	case RT5663_JD_CTRL2:
+	case RT5663_VENDOR_ID:
+	case RT5663_VENDOR_ID_1:
+	case RT5663_VENDOR_ID_2:
+	case RT5663_STO_DRE_1:
+	case RT5663_STO_DRE_5:
+	case RT5663_STO_DRE_6:
+	case RT5663_STO_DRE_7:
+	case RT5663_MONO_DYNA_6:
+	case RT5663_STO1_SIL_DET:
+	case RT5663_MONOL_SIL_DET:
+	case RT5663_MONOR_SIL_DET:
+	case RT5663_STO2_DAC_SIL:
+	case RT5663_MONO_AMP_CAL_ST1:
+	case RT5663_MONO_AMP_CAL_ST2:
+	case RT5663_MONO_AMP_CAL_ST3:
+	case RT5663_MONO_AMP_CAL_ST4:
+	case RT5663_HP_IMP_SEN_2:
+	case RT5663_HP_IMP_SEN_3:
+	case RT5663_HP_IMP_SEN_4:
+	case RT5663_HP_IMP_SEN_10:
+	case RT5663_HP_CALIB_1:
+	case RT5663_HP_CALIB_10:
+	case RT5663_HP_CALIB_ST1:
+	case RT5663_HP_CALIB_ST4:
+	case RT5663_HP_CALIB_ST5:
+	case RT5663_HP_CALIB_ST6:
+	case RT5663_HP_CALIB_ST7:
+	case RT5663_HP_CALIB_ST8:
+	case RT5663_HP_CALIB_ST9:
+	case RT5663_HP_CALIB_ST10:
+	case RT5663_HP_CALIB_ST11:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5663_v2_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5663_LOUT_CTRL:
+	case RT5663_HP_AMP_2:
+	case RT5663_MONO_OUT:
+	case RT5663_MONO_GAIN:
+	case RT5663_AEC_BST:
+	case RT5663_IN1_IN2:
+	case RT5663_IN3_IN4:
+	case RT5663_INL1_INR1:
+	case RT5663_CBJ_TYPE_2:
+	case RT5663_CBJ_TYPE_3:
+	case RT5663_CBJ_TYPE_4:
+	case RT5663_CBJ_TYPE_5:
+	case RT5663_CBJ_TYPE_8:
+	case RT5663_DAC3_DIG_VOL:
+	case RT5663_DAC3_CTRL:
+	case RT5663_MONO_ADC_DIG_VOL:
+	case RT5663_STO2_ADC_DIG_VOL:
+	case RT5663_MONO_ADC_BST_GAIN:
+	case RT5663_STO2_ADC_BST_GAIN:
+	case RT5663_SIDETONE_CTRL:
+	case RT5663_MONO1_ADC_MIXER:
+	case RT5663_STO2_ADC_MIXER:
+	case RT5663_MONO_DAC_MIXER:
+	case RT5663_DAC2_SRC_CTRL:
+	case RT5663_IF_3_4_DATA_CTL:
+	case RT5663_IF_5_DATA_CTL:
+	case RT5663_PDM_OUT_CTL:
+	case RT5663_PDM_I2C_DATA_CTL1:
+	case RT5663_PDM_I2C_DATA_CTL2:
+	case RT5663_PDM_I2C_DATA_CTL3:
+	case RT5663_PDM_I2C_DATA_CTL4:
+	case RT5663_RECMIX1_NEW:
+	case RT5663_RECMIX1L_0:
+	case RT5663_RECMIX1L:
+	case RT5663_RECMIX1R_0:
+	case RT5663_RECMIX1R:
+	case RT5663_RECMIX2_NEW:
+	case RT5663_RECMIX2_L_2:
+	case RT5663_RECMIX2_R:
+	case RT5663_RECMIX2_R_2:
+	case RT5663_CALIB_REC_LR:
+	case RT5663_ALC_BK_GAIN:
+	case RT5663_MONOMIX_GAIN:
+	case RT5663_MONOMIX_IN_GAIN:
+	case RT5663_OUT_MIXL_GAIN:
+	case RT5663_OUT_LMIX_IN_GAIN:
+	case RT5663_OUT_RMIX_IN_GAIN:
+	case RT5663_OUT_RMIX_IN_GAIN1:
+	case RT5663_LOUT_MIXER_CTRL:
+	case RT5663_PWR_VOL:
+	case RT5663_ADCDAC_RST:
+	case RT5663_I2S34_SDP:
+	case RT5663_I2S5_SDP:
+	case RT5663_TDM_6:
+	case RT5663_TDM_7:
+	case RT5663_TDM_8:
+	case RT5663_TDM_9:
+	case RT5663_ASRC_3:
+	case RT5663_ASRC_6:
+	case RT5663_ASRC_7:
+	case RT5663_PLL_TRK_13:
+	case RT5663_I2S_M_CLK_CTL:
+	case RT5663_FDIV_I2S34_M_CLK:
+	case RT5663_FDIV_I2S34_M_CLK2:
+	case RT5663_FDIV_I2S5_M_CLK:
+	case RT5663_FDIV_I2S5_M_CLK2:
+	case RT5663_V2_IRQ_4:
+	case RT5663_GPIO_3:
+	case RT5663_GPIO_4:
+	case RT5663_GPIO_STA2:
+	case RT5663_HP_AMP_DET1:
+	case RT5663_HP_AMP_DET2:
+	case RT5663_HP_AMP_DET3:
+	case RT5663_MID_BD_HP_AMP:
+	case RT5663_LOW_BD_HP_AMP:
+	case RT5663_SOF_VOL_ZC2:
+	case RT5663_ADC_STO2_ADJ1:
+	case RT5663_ADC_STO2_ADJ2:
+	case RT5663_A_JD_CTRL:
+	case RT5663_JD1_TRES_CTRL:
+	case RT5663_JD2_TRES_CTRL:
+	case RT5663_V2_JD_CTRL2:
+	case RT5663_DUM_REG_2:
+	case RT5663_DUM_REG_3:
+	case RT5663_VENDOR_ID:
+	case RT5663_VENDOR_ID_1:
+	case RT5663_VENDOR_ID_2:
+	case RT5663_DACADC_DIG_VOL2:
+	case RT5663_DIG_IN_PIN2:
+	case RT5663_PAD_DRV_CTL1:
+	case RT5663_SOF_RAM_DEPOP:
+	case RT5663_VOL_TEST:
+	case RT5663_TEST_MODE_4:
+	case RT5663_TEST_MODE_5:
+	case RT5663_STO_DRE_9:
+	case RT5663_MONO_DYNA_1:
+	case RT5663_MONO_DYNA_2:
+	case RT5663_MONO_DYNA_3:
+	case RT5663_MONO_DYNA_4:
+	case RT5663_MONO_DYNA_5:
+	case RT5663_MONO_DYNA_6:
+	case RT5663_STO1_SIL_DET:
+	case RT5663_MONOL_SIL_DET:
+	case RT5663_MONOR_SIL_DET:
+	case RT5663_STO2_DAC_SIL:
+	case RT5663_PWR_SAV_CTL1:
+	case RT5663_PWR_SAV_CTL2:
+	case RT5663_PWR_SAV_CTL3:
+	case RT5663_PWR_SAV_CTL4:
+	case RT5663_PWR_SAV_CTL5:
+	case RT5663_PWR_SAV_CTL6:
+	case RT5663_MONO_AMP_CAL1:
+	case RT5663_MONO_AMP_CAL2:
+	case RT5663_MONO_AMP_CAL3:
+	case RT5663_MONO_AMP_CAL4:
+	case RT5663_MONO_AMP_CAL5:
+	case RT5663_MONO_AMP_CAL6:
+	case RT5663_MONO_AMP_CAL7:
+	case RT5663_MONO_AMP_CAL_ST1:
+	case RT5663_MONO_AMP_CAL_ST2:
+	case RT5663_MONO_AMP_CAL_ST3:
+	case RT5663_MONO_AMP_CAL_ST4:
+	case RT5663_MONO_AMP_CAL_ST5:
+	case RT5663_V2_HP_IMP_SEN_13:
+	case RT5663_V2_HP_IMP_SEN_14:
+	case RT5663_V2_HP_IMP_SEN_6:
+	case RT5663_V2_HP_IMP_SEN_7:
+	case RT5663_V2_HP_IMP_SEN_8:
+	case RT5663_V2_HP_IMP_SEN_9:
+	case RT5663_V2_HP_IMP_SEN_10:
+	case RT5663_HP_LOGIC_3:
+	case RT5663_HP_CALIB_ST10:
+	case RT5663_HP_CALIB_ST11:
+	case RT5663_PRO_REG_TBL_4:
+	case RT5663_PRO_REG_TBL_5:
+	case RT5663_PRO_REG_TBL_6:
+	case RT5663_PRO_REG_TBL_7:
+	case RT5663_PRO_REG_TBL_8:
+	case RT5663_PRO_REG_TBL_9:
+	case RT5663_SAR_ADC_INL_1:
+	case RT5663_SAR_ADC_INL_2:
+	case RT5663_SAR_ADC_INL_3:
+	case RT5663_SAR_ADC_INL_4:
+	case RT5663_SAR_ADC_INL_5:
+	case RT5663_SAR_ADC_INL_6:
+	case RT5663_SAR_ADC_INL_7:
+	case RT5663_SAR_ADC_INL_8:
+	case RT5663_SAR_ADC_INL_9:
+	case RT5663_SAR_ADC_INL_10:
+	case RT5663_SAR_ADC_INL_11:
+	case RT5663_SAR_ADC_INL_12:
+	case RT5663_DRC_CTRL_1:
+	case RT5663_DRC1_CTRL_2:
+	case RT5663_DRC1_CTRL_3:
+	case RT5663_DRC1_CTRL_4:
+	case RT5663_DRC1_CTRL_5:
+	case RT5663_DRC1_CTRL_6:
+	case RT5663_DRC1_HD_CTRL_1:
+	case RT5663_DRC1_HD_CTRL_2:
+	case RT5663_DRC1_PRI_REG_1:
+	case RT5663_DRC1_PRI_REG_2:
+	case RT5663_DRC1_PRI_REG_3:
+	case RT5663_DRC1_PRI_REG_4:
+	case RT5663_DRC1_PRI_REG_5:
+	case RT5663_DRC1_PRI_REG_6:
+	case RT5663_DRC1_PRI_REG_7:
+	case RT5663_DRC1_PRI_REG_8:
+	case RT5663_ALC_PGA_CTL_1:
+	case RT5663_ALC_PGA_CTL_2:
+	case RT5663_ALC_PGA_CTL_3:
+	case RT5663_ALC_PGA_CTL_4:
+	case RT5663_ALC_PGA_CTL_5:
+	case RT5663_ALC_PGA_CTL_6:
+	case RT5663_ALC_PGA_CTL_7:
+	case RT5663_ALC_PGA_CTL_8:
+	case RT5663_ALC_PGA_REG_1:
+	case RT5663_ALC_PGA_REG_2:
+	case RT5663_ALC_PGA_REG_3:
+	case RT5663_ADC_EQ_RECOV_1:
+	case RT5663_ADC_EQ_RECOV_2:
+	case RT5663_ADC_EQ_RECOV_3:
+	case RT5663_ADC_EQ_RECOV_4:
+	case RT5663_ADC_EQ_RECOV_5:
+	case RT5663_ADC_EQ_RECOV_6:
+	case RT5663_ADC_EQ_RECOV_7:
+	case RT5663_ADC_EQ_RECOV_8:
+	case RT5663_ADC_EQ_RECOV_9:
+	case RT5663_ADC_EQ_RECOV_10:
+	case RT5663_ADC_EQ_RECOV_11:
+	case RT5663_ADC_EQ_RECOV_12:
+	case RT5663_ADC_EQ_RECOV_13:
+	case RT5663_VID_HIDDEN:
+	case RT5663_VID_CUSTOMER:
+	case RT5663_SCAN_MODE:
+	case RT5663_I2C_BYPA:
+		return true;
+	case RT5663_TDM_1:
+	case RT5663_DEPOP_3:
+	case RT5663_ASRC_11_2:
+	case RT5663_INT_ST_2:
+	case RT5663_GPIO_STA1:
+	case RT5663_SIN_GEN_1:
+	case RT5663_SIN_GEN_2:
+	case RT5663_SIN_GEN_3:
+	case RT5663_IL_CMD_PWRSAV1:
+	case RT5663_IL_CMD_PWRSAV2:
+	case RT5663_EM_JACK_TYPE_1:
+	case RT5663_EM_JACK_TYPE_2:
+	case RT5663_EM_JACK_TYPE_3:
+	case RT5663_EM_JACK_TYPE_4:
+	case RT5663_FAST_OFF_MICBIAS:
+	case RT5663_ANA_BIAS_CUR_1:
+	case RT5663_ANA_BIAS_CUR_2:
+	case RT5663_BIAS_CUR_9:
+	case RT5663_DUMMY_REG_4:
+	case RT5663_VREF_RECMIX:
+	case RT5663_CHARGE_PUMP_1_2:
+	case RT5663_CHARGE_PUMP_1_3:
+	case RT5663_CHARGE_PUMP_2:
+	case RT5663_CHOP_DAC_R:
+	case RT5663_DUMMY_CTL_DACLR:
+	case RT5663_DUMMY_REG_5:
+	case RT5663_SOFT_RAMP:
+	case RT5663_TEST_MODE_1:
+	case RT5663_STO_DRE_10:
+	case RT5663_MIC_DECRO_1:
+	case RT5663_MIC_DECRO_2:
+	case RT5663_MIC_DECRO_3:
+	case RT5663_MIC_DECRO_4:
+	case RT5663_MIC_DECRO_5:
+	case RT5663_MIC_DECRO_6:
+	case RT5663_HP_DECRO_1:
+	case RT5663_HP_DECRO_2:
+	case RT5663_HP_DECRO_3:
+	case RT5663_HP_DECRO_4:
+	case RT5663_HP_DECOUP:
+	case RT5663_HP_IMPSEN_MAP4:
+	case RT5663_HP_IMPSEN_MAP5:
+	case RT5663_HP_IMPSEN_MAP7:
+	case RT5663_HP_CALIB_1:
+	case RT5663_CBJ_1:
+	case RT5663_CBJ_2:
+	case RT5663_CBJ_3:
+		return false;
+	default:
+		return rt5663_readable_register(dev, reg);
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(rt5663_hp_vol_tlv, -2400, 150, 0);
+static const DECLARE_TLV_DB_SCALE(rt5663_v2_hp_vol_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(in_bst_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+/* Interface data select */
+static const char * const rt5663_if1_adc_data_select[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5663_if1_adc_enum, RT5663_TDM_2,
+	RT5663_DATA_SWAP_ADCDAT1_SHIFT, rt5663_if1_adc_data_select);
+
+static void rt5663_enable_push_button_irq(struct snd_soc_component *component,
+	bool enable)
+{
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+
+	if (enable) {
+		snd_soc_component_update_bits(component, RT5663_IL_CMD_6,
+			RT5663_EN_4BTN_INL_MASK, RT5663_EN_4BTN_INL_EN);
+		/* reset in-line command */
+		snd_soc_component_update_bits(component, RT5663_IL_CMD_6,
+			RT5663_RESET_4BTN_INL_MASK,
+			RT5663_RESET_4BTN_INL_RESET);
+		snd_soc_component_update_bits(component, RT5663_IL_CMD_6,
+			RT5663_RESET_4BTN_INL_MASK,
+			RT5663_RESET_4BTN_INL_NOR);
+		switch (rt5663->codec_ver) {
+		case CODEC_VER_1:
+			snd_soc_component_update_bits(component, RT5663_IRQ_3,
+				RT5663_V2_EN_IRQ_INLINE_MASK,
+				RT5663_V2_EN_IRQ_INLINE_NOR);
+			break;
+		case CODEC_VER_0:
+			snd_soc_component_update_bits(component, RT5663_IRQ_2,
+				RT5663_EN_IRQ_INLINE_MASK,
+				RT5663_EN_IRQ_INLINE_NOR);
+			break;
+		default:
+			dev_err(component->dev, "Unknown CODEC Version\n");
+		}
+	} else {
+		switch (rt5663->codec_ver) {
+		case CODEC_VER_1:
+			snd_soc_component_update_bits(component, RT5663_IRQ_3,
+				RT5663_V2_EN_IRQ_INLINE_MASK,
+				RT5663_V2_EN_IRQ_INLINE_BYP);
+			break;
+		case CODEC_VER_0:
+			snd_soc_component_update_bits(component, RT5663_IRQ_2,
+				RT5663_EN_IRQ_INLINE_MASK,
+				RT5663_EN_IRQ_INLINE_BYP);
+			break;
+		default:
+			dev_err(component->dev, "Unknown CODEC Version\n");
+		}
+		snd_soc_component_update_bits(component, RT5663_IL_CMD_6,
+			RT5663_EN_4BTN_INL_MASK, RT5663_EN_4BTN_INL_DIS);
+		/* reset in-line command */
+		snd_soc_component_update_bits(component, RT5663_IL_CMD_6,
+			RT5663_RESET_4BTN_INL_MASK,
+			RT5663_RESET_4BTN_INL_RESET);
+		snd_soc_component_update_bits(component, RT5663_IL_CMD_6,
+			RT5663_RESET_4BTN_INL_MASK,
+			RT5663_RESET_4BTN_INL_NOR);
+	}
+}
+
+/**
+ * rt5663_v2_jack_detect - Detect headset.
+ * @component: SoC audio component device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+
+static int rt5663_v2_jack_detect(struct snd_soc_component *component, int jack_insert)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+	int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};
+
+	dev_dbg(component->dev, "%s jack_insert:%d\n", __func__, jack_insert);
+	if (jack_insert) {
+		snd_soc_component_write(component, RT5663_CBJ_TYPE_2, 0x8040);
+		snd_soc_component_write(component, RT5663_CBJ_TYPE_3, 0x1484);
+
+		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS2");
+		snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power");
+		snd_soc_dapm_force_enable_pin(dapm, "CBJ Power");
+		snd_soc_dapm_sync(dapm);
+		snd_soc_component_update_bits(component, RT5663_RC_CLK,
+			RT5663_DIG_1M_CLK_MASK, RT5663_DIG_1M_CLK_EN);
+		snd_soc_component_update_bits(component, RT5663_RECMIX, 0x8, 0x8);
+
+		while (i < 5) {
+			msleep(sleep_time[i]);
+			val = snd_soc_component_read32(component, RT5663_CBJ_TYPE_2) & 0x0003;
+			if (val == 0x1 || val == 0x2 || val == 0x3)
+				break;
+			dev_dbg(component->dev, "%s: MX-0011 val=%x sleep %d\n",
+				__func__, val, sleep_time[i]);
+			i++;
+		}
+		dev_dbg(component->dev, "%s val = %d\n", __func__, val);
+		switch (val) {
+		case 1:
+		case 2:
+			rt5663->jack_type = SND_JACK_HEADSET;
+			rt5663_enable_push_button_irq(component, true);
+			break;
+		default:
+			snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+			snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
+			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+			snd_soc_dapm_disable_pin(dapm, "CBJ Power");
+			snd_soc_dapm_sync(dapm);
+			rt5663->jack_type = SND_JACK_HEADPHONE;
+			break;
+		}
+	} else {
+		snd_soc_component_update_bits(component, RT5663_RECMIX, 0x8, 0x0);
+
+		if (rt5663->jack_type == SND_JACK_HEADSET) {
+			rt5663_enable_push_button_irq(component, false);
+			snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+			snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
+			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+			snd_soc_dapm_disable_pin(dapm, "CBJ Power");
+			snd_soc_dapm_sync(dapm);
+		}
+		rt5663->jack_type = 0;
+	}
+
+	dev_dbg(component->dev, "jack_type = %d\n", rt5663->jack_type);
+	return rt5663->jack_type;
+}
+
+/**
+ * rt5663_jack_detect - Detect headset.
+ * @component: SoC audio component device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+static int rt5663_jack_detect(struct snd_soc_component *component, int jack_insert)
+{
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+	int val, i = 0;
+
+	dev_dbg(component->dev, "%s jack_insert:%d\n", __func__, jack_insert);
+
+	if (jack_insert) {
+		snd_soc_component_update_bits(component, RT5663_DIG_MISC,
+			RT5663_DIG_GATE_CTRL_MASK, RT5663_DIG_GATE_CTRL_EN);
+		snd_soc_component_update_bits(component, RT5663_HP_CHARGE_PUMP_1,
+			RT5663_SI_HP_MASK | RT5663_OSW_HP_L_MASK |
+			RT5663_OSW_HP_R_MASK, RT5663_SI_HP_EN |
+			RT5663_OSW_HP_L_DIS | RT5663_OSW_HP_R_DIS);
+		snd_soc_component_update_bits(component, RT5663_DUMMY_1,
+			RT5663_EMB_CLK_MASK | RT5663_HPA_CPL_BIAS_MASK |
+			RT5663_HPA_CPR_BIAS_MASK, RT5663_EMB_CLK_EN |
+			RT5663_HPA_CPL_BIAS_1 | RT5663_HPA_CPR_BIAS_1);
+		snd_soc_component_update_bits(component, RT5663_CBJ_1,
+			RT5663_INBUF_CBJ_BST1_MASK | RT5663_CBJ_SENSE_BST1_MASK,
+			RT5663_INBUF_CBJ_BST1_ON | RT5663_CBJ_SENSE_BST1_L);
+		snd_soc_component_update_bits(component, RT5663_IL_CMD_2,
+			RT5663_PWR_MIC_DET_MASK, RT5663_PWR_MIC_DET_ON);
+		/* BST1 power on for JD */
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_2,
+			RT5663_PWR_BST1_MASK, RT5663_PWR_BST1_ON);
+		snd_soc_component_update_bits(component, RT5663_EM_JACK_TYPE_1,
+			RT5663_CBJ_DET_MASK | RT5663_EXT_JD_MASK |
+			RT5663_POL_EXT_JD_MASK, RT5663_CBJ_DET_EN |
+			RT5663_EXT_JD_EN | RT5663_POL_EXT_JD_EN);
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
+			RT5663_PWR_MB_MASK | RT5663_LDO1_DVO_MASK |
+			RT5663_AMP_HP_MASK, RT5663_PWR_MB |
+			RT5663_LDO1_DVO_0_9V | RT5663_AMP_HP_3X);
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
+			RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
+			RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
+			RT5663_PWR_VREF1 | RT5663_PWR_VREF2);
+		msleep(20);
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
+			RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
+			RT5663_PWR_FV1 | RT5663_PWR_FV2);
+		snd_soc_component_update_bits(component, RT5663_AUTO_1MRC_CLK,
+			RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN);
+		snd_soc_component_update_bits(component, RT5663_IRQ_1,
+			RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN);
+		snd_soc_component_update_bits(component, RT5663_EM_JACK_TYPE_1,
+			RT5663_EM_JD_MASK, RT5663_EM_JD_RST);
+		snd_soc_component_update_bits(component, RT5663_EM_JACK_TYPE_1,
+			RT5663_EM_JD_MASK, RT5663_EM_JD_NOR);
+
+		while (true) {
+			regmap_read(rt5663->regmap, RT5663_INT_ST_2, &val);
+			if (!(val & 0x80))
+				usleep_range(10000, 10005);
+			else
+				break;
+
+			if (i > 200)
+				break;
+			i++;
+		}
+
+		val = snd_soc_component_read32(component, RT5663_EM_JACK_TYPE_2) & 0x0003;
+		dev_dbg(component->dev, "%s val = %d\n", __func__, val);
+
+		snd_soc_component_update_bits(component, RT5663_HP_CHARGE_PUMP_1,
+			RT5663_OSW_HP_L_MASK | RT5663_OSW_HP_R_MASK,
+			RT5663_OSW_HP_L_EN | RT5663_OSW_HP_R_EN);
+
+		switch (val) {
+		case 1:
+		case 2:
+			rt5663->jack_type = SND_JACK_HEADSET;
+			rt5663_enable_push_button_irq(component, true);
+
+			if (rt5663->pdata.impedance_sensing_num)
+				break;
+
+			if (rt5663->pdata.dc_offset_l_manual_mic) {
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_2,
+					rt5663->pdata.dc_offset_l_manual_mic >>
+					16);
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_3,
+					rt5663->pdata.dc_offset_l_manual_mic &
+					0xffff);
+			}
+
+			if (rt5663->pdata.dc_offset_r_manual_mic) {
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_5,
+					rt5663->pdata.dc_offset_r_manual_mic >>
+					16);
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_6,
+					rt5663->pdata.dc_offset_r_manual_mic &
+					0xffff);
+			}
+			break;
+		default:
+			rt5663->jack_type = SND_JACK_HEADPHONE;
+			snd_soc_component_update_bits(component,
+				RT5663_PWR_ANLG_1,
+				RT5663_PWR_MB_MASK | RT5663_PWR_VREF1_MASK |
+				RT5663_PWR_VREF2_MASK, 0);
+			if (rt5663->pdata.impedance_sensing_num)
+				break;
+
+			if (rt5663->pdata.dc_offset_l_manual) {
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_2,
+					rt5663->pdata.dc_offset_l_manual >> 16);
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_3,
+					rt5663->pdata.dc_offset_l_manual &
+					0xffff);
+			}
+
+			if (rt5663->pdata.dc_offset_r_manual) {
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_5,
+					rt5663->pdata.dc_offset_r_manual >> 16);
+				regmap_write(rt5663->regmap, RT5663_MIC_DECRO_6,
+					rt5663->pdata.dc_offset_r_manual &
+					0xffff);
+			}
+			break;
+		}
+	} else {
+		if (rt5663->jack_type == SND_JACK_HEADSET)
+			rt5663_enable_push_button_irq(component, false);
+		rt5663->jack_type = 0;
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
+			RT5663_PWR_MB_MASK | RT5663_PWR_VREF1_MASK |
+			RT5663_PWR_VREF2_MASK, 0);
+	}
+
+	dev_dbg(component->dev, "jack_type = %d\n", rt5663->jack_type);
+	return rt5663->jack_type;
+}
+
+static int rt5663_impedance_sensing(struct snd_soc_component *component)
+{
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+	unsigned int value, i, reg84, reg26, reg2fa, reg91, reg10, reg80;
+
+	for (i = 0; i < rt5663->pdata.impedance_sensing_num; i++) {
+		if (rt5663->imp_table[i].vol == 7)
+			break;
+	}
+
+	if (rt5663->jack_type == SND_JACK_HEADSET) {
+		snd_soc_component_write(component, RT5663_MIC_DECRO_2,
+			rt5663->imp_table[i].dc_offset_l_manual_mic >> 16);
+		snd_soc_component_write(component, RT5663_MIC_DECRO_3,
+			rt5663->imp_table[i].dc_offset_l_manual_mic & 0xffff);
+		snd_soc_component_write(component, RT5663_MIC_DECRO_5,
+			rt5663->imp_table[i].dc_offset_r_manual_mic >> 16);
+		snd_soc_component_write(component, RT5663_MIC_DECRO_6,
+			rt5663->imp_table[i].dc_offset_r_manual_mic & 0xffff);
+	} else {
+		snd_soc_component_write(component, RT5663_MIC_DECRO_2,
+			rt5663->imp_table[i].dc_offset_l_manual >> 16);
+		snd_soc_component_write(component, RT5663_MIC_DECRO_3,
+			rt5663->imp_table[i].dc_offset_l_manual & 0xffff);
+		snd_soc_component_write(component, RT5663_MIC_DECRO_5,
+			rt5663->imp_table[i].dc_offset_r_manual >> 16);
+		snd_soc_component_write(component, RT5663_MIC_DECRO_6,
+			rt5663->imp_table[i].dc_offset_r_manual & 0xffff);
+	}
+
+	reg84 = snd_soc_component_read32(component, RT5663_ASRC_2);
+	reg26 = snd_soc_component_read32(component, RT5663_STO1_ADC_MIXER);
+	reg2fa = snd_soc_component_read32(component, RT5663_DUMMY_1);
+	reg91 = snd_soc_component_read32(component, RT5663_HP_CHARGE_PUMP_1);
+	reg10 = snd_soc_component_read32(component, RT5663_RECMIX);
+	reg80 = snd_soc_component_read32(component, RT5663_GLB_CLK);
+
+	snd_soc_component_update_bits(component, RT5663_STO_DRE_1, 0x8000, 0);
+	snd_soc_component_write(component, RT5663_ASRC_2, 0);
+	snd_soc_component_write(component, RT5663_STO1_ADC_MIXER, 0x4040);
+	snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
+		RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
+		RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
+		RT5663_PWR_VREF1 | RT5663_PWR_VREF2);
+	usleep_range(10000, 10005);
+	snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
+		RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
+		RT5663_PWR_FV1 | RT5663_PWR_FV2);
+	snd_soc_component_update_bits(component, RT5663_GLB_CLK, RT5663_SCLK_SRC_MASK,
+		RT5663_SCLK_SRC_RCCLK);
+	snd_soc_component_update_bits(component, RT5663_RC_CLK, RT5663_DIG_25M_CLK_MASK,
+		RT5663_DIG_25M_CLK_EN);
+	snd_soc_component_update_bits(component, RT5663_ADDA_CLK_1, RT5663_I2S_PD1_MASK, 0);
+	snd_soc_component_write(component, RT5663_PRE_DIV_GATING_1, 0xff00);
+	snd_soc_component_write(component, RT5663_PRE_DIV_GATING_2, 0xfffc);
+	snd_soc_component_write(component, RT5663_HP_CHARGE_PUMP_1, 0x1232);
+	snd_soc_component_write(component, RT5663_HP_LOGIC_2, 0x0005);
+	snd_soc_component_write(component, RT5663_DEPOP_2, 0x3003);
+	snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0030, 0x0030);
+	snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0003, 0x0003);
+	snd_soc_component_update_bits(component, RT5663_PWR_DIG_2,
+		RT5663_PWR_ADC_S1F | RT5663_PWR_DAC_S1F,
+		RT5663_PWR_ADC_S1F | RT5663_PWR_DAC_S1F);
+	snd_soc_component_update_bits(component, RT5663_PWR_DIG_1,
+		RT5663_PWR_DAC_L1 | RT5663_PWR_DAC_R1 |
+		RT5663_PWR_LDO_DACREF_MASK | RT5663_PWR_ADC_L1 |
+		RT5663_PWR_ADC_R1,
+		RT5663_PWR_DAC_L1 | RT5663_PWR_DAC_R1 |
+		RT5663_PWR_LDO_DACREF_ON | RT5663_PWR_ADC_L1 |
+		RT5663_PWR_ADC_R1);
+	msleep(40);
+	snd_soc_component_update_bits(component, RT5663_PWR_ANLG_2,
+		RT5663_PWR_RECMIX1 | RT5663_PWR_RECMIX2,
+		RT5663_PWR_RECMIX1 | RT5663_PWR_RECMIX2);
+	msleep(30);
+	snd_soc_component_write(component, RT5663_HP_CHARGE_PUMP_2, 0x1371);
+	snd_soc_component_write(component, RT5663_STO_DAC_MIXER, 0);
+	snd_soc_component_write(component, RT5663_BYPASS_STO_DAC, 0x000c);
+	snd_soc_component_write(component, RT5663_HP_BIAS, 0xafaa);
+	snd_soc_component_write(component, RT5663_CHARGE_PUMP_1, 0x2224);
+	snd_soc_component_write(component, RT5663_HP_OUT_EN, 0x8088);
+	snd_soc_component_write(component, RT5663_CHOP_ADC, 0x3000);
+	snd_soc_component_write(component, RT5663_ADDA_RST, 0xc000);
+	snd_soc_component_write(component, RT5663_STO1_HPF_ADJ1, 0x3320);
+	snd_soc_component_write(component, RT5663_HP_CALIB_2, 0x00c9);
+	snd_soc_component_write(component, RT5663_DUMMY_1, 0x004c);
+	snd_soc_component_write(component, RT5663_ANA_BIAS_CUR_1, 0x7733);
+	snd_soc_component_write(component, RT5663_CHARGE_PUMP_2, 0x7777);
+	snd_soc_component_write(component, RT5663_STO_DRE_9, 0x0007);
+	snd_soc_component_write(component, RT5663_STO_DRE_10, 0x0007);
+	snd_soc_component_write(component, RT5663_DUMMY_2, 0x02a4);
+	snd_soc_component_write(component, RT5663_RECMIX, 0x0005);
+	snd_soc_component_write(component, RT5663_HP_IMP_SEN_1, 0x4334);
+	snd_soc_component_update_bits(component, RT5663_IRQ_3, 0x0004, 0x0004);
+	snd_soc_component_write(component, RT5663_HP_LOGIC_1, 0x2200);
+	snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000, 0x3000);
+	snd_soc_component_write(component, RT5663_HP_LOGIC_1, 0x6200);
+
+	for (i = 0; i < 100; i++) {
+		msleep(20);
+		if (snd_soc_component_read32(component, RT5663_INT_ST_1) & 0x2)
+			break;
+	}
+
+	value = snd_soc_component_read32(component, RT5663_HP_IMP_SEN_4);
+
+	snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000, 0);
+	snd_soc_component_write(component, RT5663_INT_ST_1, 0);
+	snd_soc_component_write(component, RT5663_HP_LOGIC_1, 0);
+	snd_soc_component_update_bits(component, RT5663_RC_CLK, RT5663_DIG_25M_CLK_MASK,
+		RT5663_DIG_25M_CLK_DIS);
+	snd_soc_component_write(component, RT5663_GLB_CLK, reg80);
+	snd_soc_component_write(component, RT5663_RECMIX, reg10);
+	snd_soc_component_write(component, RT5663_DUMMY_2, 0x00a4);
+	snd_soc_component_write(component, RT5663_DUMMY_1, reg2fa);
+	snd_soc_component_write(component, RT5663_HP_CALIB_2, 0x00c8);
+	snd_soc_component_write(component, RT5663_STO1_HPF_ADJ1, 0xb320);
+	snd_soc_component_write(component, RT5663_ADDA_RST, 0xe400);
+	snd_soc_component_write(component, RT5663_CHOP_ADC, 0x2000);
+	snd_soc_component_write(component, RT5663_HP_OUT_EN, 0x0008);
+	snd_soc_component_update_bits(component, RT5663_PWR_ANLG_2,
+		RT5663_PWR_RECMIX1 | RT5663_PWR_RECMIX2, 0);
+	snd_soc_component_update_bits(component, RT5663_PWR_DIG_1,
+		RT5663_PWR_DAC_L1 | RT5663_PWR_DAC_R1 |
+		RT5663_PWR_LDO_DACREF_MASK | RT5663_PWR_ADC_L1 |
+		RT5663_PWR_ADC_R1, 0);
+	snd_soc_component_update_bits(component, RT5663_PWR_DIG_2,
+		RT5663_PWR_ADC_S1F | RT5663_PWR_DAC_S1F, 0);
+	snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0003, 0);
+	snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0030, 0);
+	snd_soc_component_write(component, RT5663_HP_LOGIC_2, 0);
+	snd_soc_component_write(component, RT5663_HP_CHARGE_PUMP_1, reg91);
+	snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
+		RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK, 0);
+	snd_soc_component_write(component, RT5663_STO1_ADC_MIXER, reg26);
+	snd_soc_component_write(component, RT5663_ASRC_2, reg84);
+
+	for (i = 0; i < rt5663->pdata.impedance_sensing_num; i++) {
+		if (value >= rt5663->imp_table[i].imp_min &&
+			value <= rt5663->imp_table[i].imp_max)
+			break;
+	}
+
+	snd_soc_component_update_bits(component, RT5663_STO_DRE_9, RT5663_DRE_GAIN_HP_MASK,
+		rt5663->imp_table[i].vol);
+	snd_soc_component_update_bits(component, RT5663_STO_DRE_10, RT5663_DRE_GAIN_HP_MASK,
+		rt5663->imp_table[i].vol);
+
+	if (rt5663->jack_type == SND_JACK_HEADSET) {
+		snd_soc_component_write(component, RT5663_MIC_DECRO_2,
+			rt5663->imp_table[i].dc_offset_l_manual_mic >> 16);
+		snd_soc_component_write(component, RT5663_MIC_DECRO_3,
+			rt5663->imp_table[i].dc_offset_l_manual_mic & 0xffff);
+		snd_soc_component_write(component, RT5663_MIC_DECRO_5,
+			rt5663->imp_table[i].dc_offset_r_manual_mic >> 16);
+		snd_soc_component_write(component, RT5663_MIC_DECRO_6,
+			rt5663->imp_table[i].dc_offset_r_manual_mic & 0xffff);
+	} else {
+		snd_soc_component_write(component, RT5663_MIC_DECRO_2,
+			rt5663->imp_table[i].dc_offset_l_manual >> 16);
+		snd_soc_component_write(component, RT5663_MIC_DECRO_3,
+			rt5663->imp_table[i].dc_offset_l_manual & 0xffff);
+		snd_soc_component_write(component, RT5663_MIC_DECRO_5,
+			rt5663->imp_table[i].dc_offset_r_manual >> 16);
+		snd_soc_component_write(component, RT5663_MIC_DECRO_6,
+			rt5663->imp_table[i].dc_offset_r_manual & 0xffff);
+	}
+
+	return 0;
+}
+
+static int rt5663_button_detect(struct snd_soc_component *component)
+{
+	int btn_type, val;
+
+	val = snd_soc_component_read32(component, RT5663_IL_CMD_5);
+	dev_dbg(component->dev, "%s: val=0x%x\n", __func__, val);
+	btn_type = val & 0xfff0;
+	snd_soc_component_write(component, RT5663_IL_CMD_5, val);
+
+	return btn_type;
+}
+
+static irqreturn_t rt5663_irq(int irq, void *data)
+{
+	struct rt5663_priv *rt5663 = data;
+
+	dev_dbg(regmap_get_device(rt5663->regmap), "%s IRQ queue work\n",
+		__func__);
+
+	queue_delayed_work(system_wq, &rt5663->jack_detect_work,
+		msecs_to_jiffies(250));
+
+	return IRQ_HANDLED;
+}
+
+static int rt5663_set_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *hs_jack, void *data)
+{
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+
+	rt5663->hs_jack = hs_jack;
+
+	rt5663_irq(0, rt5663);
+
+	return 0;
+}
+
+static bool rt5663_check_jd_status(struct snd_soc_component *component)
+{
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+	int val = snd_soc_component_read32(component, RT5663_INT_ST_1);
+
+	dev_dbg(component->dev, "%s val=%x\n", __func__, val);
+
+	/* JD1 */
+	switch (rt5663->codec_ver) {
+	case CODEC_VER_1:
+		return !(val & 0x2000);
+	case CODEC_VER_0:
+		return !(val & 0x1000);
+	default:
+		dev_err(component->dev, "Unknown CODEC Version\n");
+	}
+
+	return false;
+}
+
+static void rt5663_jack_detect_work(struct work_struct *work)
+{
+	struct rt5663_priv *rt5663 =
+		container_of(work, struct rt5663_priv, jack_detect_work.work);
+	struct snd_soc_component *component = rt5663->component;
+	int btn_type, report = 0;
+
+	if (!component)
+		return;
+
+	if (rt5663_check_jd_status(component)) {
+		/* jack in */
+		if (rt5663->jack_type == 0) {
+			/* jack was out, report jack type */
+			switch (rt5663->codec_ver) {
+			case CODEC_VER_1:
+				report = rt5663_v2_jack_detect(
+						rt5663->component, 1);
+				break;
+			case CODEC_VER_0:
+				report = rt5663_jack_detect(rt5663->component, 1);
+				if (rt5663->pdata.impedance_sensing_num)
+					rt5663_impedance_sensing(rt5663->component);
+				break;
+			default:
+				dev_err(component->dev, "Unknown CODEC Version\n");
+			}
+
+			/* Delay the jack insert report to avoid pop noise */
+			msleep(30);
+		} else {
+			/* jack is already in, report button event */
+			report = SND_JACK_HEADSET;
+			btn_type = rt5663_button_detect(rt5663->component);
+			/**
+			 * rt5663 can report three kinds of button behavior,
+			 * one click, double click and hold. However,
+			 * currently we will report button pressed/released
+			 * event. So all the three button behaviors are
+			 * treated as button pressed.
+			 */
+			switch (btn_type) {
+			case 0x8000:
+			case 0x4000:
+			case 0x2000:
+				report |= SND_JACK_BTN_0;
+				break;
+			case 0x1000:
+			case 0x0800:
+			case 0x0400:
+				report |= SND_JACK_BTN_1;
+				break;
+			case 0x0200:
+			case 0x0100:
+			case 0x0080:
+				report |= SND_JACK_BTN_2;
+				break;
+			case 0x0040:
+			case 0x0020:
+			case 0x0010:
+				report |= SND_JACK_BTN_3;
+				break;
+			case 0x0000: /* unpressed */
+				break;
+			default:
+				btn_type = 0;
+				dev_err(rt5663->component->dev,
+					"Unexpected button code 0x%04x\n",
+					btn_type);
+				break;
+			}
+			/* button release or spurious interrput*/
+			if (btn_type == 0) {
+				report =  rt5663->jack_type;
+				cancel_delayed_work_sync(
+					&rt5663->jd_unplug_work);
+			} else {
+				queue_delayed_work(system_wq,
+					&rt5663->jd_unplug_work,
+					msecs_to_jiffies(500));
+			}
+		}
+	} else {
+		/* jack out */
+		switch (rt5663->codec_ver) {
+		case CODEC_VER_1:
+			report = rt5663_v2_jack_detect(rt5663->component, 0);
+			break;
+		case CODEC_VER_0:
+			report = rt5663_jack_detect(rt5663->component, 0);
+			break;
+		default:
+			dev_err(component->dev, "Unknown CODEC Version\n");
+		}
+	}
+	dev_dbg(component->dev, "%s jack report: 0x%04x\n", __func__, report);
+	snd_soc_jack_report(rt5663->hs_jack, report, SND_JACK_HEADSET |
+			    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+			    SND_JACK_BTN_2 | SND_JACK_BTN_3);
+}
+
+static void rt5663_jd_unplug_work(struct work_struct *work)
+{
+	struct rt5663_priv *rt5663 =
+		container_of(work, struct rt5663_priv, jd_unplug_work.work);
+	struct snd_soc_component *component = rt5663->component;
+
+	if (!component)
+		return;
+
+	if (!rt5663_check_jd_status(component)) {
+		/* jack out */
+		switch (rt5663->codec_ver) {
+		case CODEC_VER_1:
+			rt5663_v2_jack_detect(rt5663->component, 0);
+			break;
+		case CODEC_VER_0:
+			rt5663_jack_detect(rt5663->component, 0);
+			break;
+		default:
+			dev_err(component->dev, "Unknown CODEC Version\n");
+		}
+
+		snd_soc_jack_report(rt5663->hs_jack, 0, SND_JACK_HEADSET |
+				    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				    SND_JACK_BTN_2 | SND_JACK_BTN_3);
+	} else {
+		queue_delayed_work(system_wq, &rt5663->jd_unplug_work,
+			msecs_to_jiffies(500));
+	}
+}
+
+static const struct snd_kcontrol_new rt5663_snd_controls[] = {
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC Playback Volume", RT5663_STO1_DAC_DIG_VOL,
+		RT5663_DAC_L1_VOL_SHIFT + 1, RT5663_DAC_R1_VOL_SHIFT + 1,
+		87, 0, dac_vol_tlv),
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("ADC Capture Switch", RT5663_STO1_ADC_DIG_VOL,
+		RT5663_ADC_L_MUTE_SHIFT, RT5663_ADC_R_MUTE_SHIFT, 1, 1),
+	SOC_DOUBLE_TLV("ADC Capture Volume", RT5663_STO1_ADC_DIG_VOL,
+		RT5663_ADC_L_VOL_SHIFT + 1, RT5663_ADC_R_VOL_SHIFT + 1,
+		63, 0, adc_vol_tlv),
+};
+
+static const struct snd_kcontrol_new rt5663_v2_specific_controls[] = {
+	/* Headphone Output Volume */
+	SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_HP_LCH_DRE,
+		RT5663_HP_RCH_DRE, RT5663_GAIN_HP_SHIFT, 15, 1,
+		rt5663_v2_hp_vol_tlv),
+	/* Mic Boost Volume */
+	SOC_SINGLE_TLV("IN1 Capture Volume", RT5663_AEC_BST,
+		RT5663_GAIN_CBJ_SHIFT, 8, 0, in_bst_tlv),
+};
+
+static const struct snd_kcontrol_new rt5663_specific_controls[] = {
+	/* Mic Boost Volume*/
+	SOC_SINGLE_TLV("IN1 Capture Volume", RT5663_CBJ_2,
+		RT5663_GAIN_BST1_SHIFT, 8, 0, in_bst_tlv),
+	/* Data Swap for Slot0/1 in ADCDAT1 */
+	SOC_ENUM("IF1 ADC Data Swap", rt5663_if1_adc_enum),
+};
+
+static const struct snd_kcontrol_new rt5663_hpvol_controls[] = {
+	/* Headphone Output Volume */
+	SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_STO_DRE_9,
+		RT5663_STO_DRE_10, RT5663_DRE_GAIN_HP_SHIFT, 23, 1,
+		rt5663_hp_vol_tlv),
+};
+
+static int rt5663_is_sys_clk_from_pll(struct snd_soc_dapm_widget *w,
+	struct snd_soc_dapm_widget *sink)
+{
+	unsigned int val;
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	val = snd_soc_component_read32(component, RT5663_GLB_CLK);
+	val &= RT5663_SCLK_SRC_MASK;
+	if (val == RT5663_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int rt5663_is_using_asrc(struct snd_soc_dapm_widget *w,
+	struct snd_soc_dapm_widget *sink)
+{
+	unsigned int reg, shift, val;
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+
+	if (rt5663->codec_ver == CODEC_VER_1) {
+		switch (w->shift) {
+		case RT5663_ADC_STO1_ASRC_SHIFT:
+			reg = RT5663_ASRC_3;
+			shift = RT5663_V2_AD_STO1_TRACK_SHIFT;
+			break;
+		case RT5663_DAC_STO1_ASRC_SHIFT:
+			reg = RT5663_ASRC_2;
+			shift = RT5663_DA_STO1_TRACK_SHIFT;
+			break;
+		default:
+			return 0;
+		}
+	} else {
+		switch (w->shift) {
+		case RT5663_ADC_STO1_ASRC_SHIFT:
+			reg = RT5663_ASRC_2;
+			shift = RT5663_AD_STO1_TRACK_SHIFT;
+			break;
+		case RT5663_DAC_STO1_ASRC_SHIFT:
+			reg = RT5663_ASRC_2;
+			shift = RT5663_DA_STO1_TRACK_SHIFT;
+			break;
+		default:
+			return 0;
+		}
+	}
+
+	val = (snd_soc_component_read32(component, reg) >> shift) & 0x7;
+
+	if (val)
+		return 1;
+
+	return 0;
+}
+
+static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source,
+	struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+	int da_asrc_en, ad_asrc_en;
+
+	da_asrc_en = (snd_soc_component_read32(component, RT5663_ASRC_2) &
+		RT5663_DA_STO1_TRACK_MASK) ? 1 : 0;
+	switch (rt5663->codec_ver) {
+	case CODEC_VER_1:
+		ad_asrc_en = (snd_soc_component_read32(component, RT5663_ASRC_3) &
+			RT5663_V2_AD_STO1_TRACK_MASK) ? 1 : 0;
+		break;
+	case CODEC_VER_0:
+		ad_asrc_en = (snd_soc_component_read32(component, RT5663_ASRC_2) &
+			RT5663_AD_STO1_TRACK_MASK) ? 1 : 0;
+		break;
+	default:
+		dev_err(component->dev, "Unknown CODEC Version\n");
+		return 1;
+	}
+
+	if (da_asrc_en || ad_asrc_en)
+		if (rt5663->sysclk > rt5663->lrck * 384)
+			return 1;
+
+	dev_err(component->dev, "sysclk < 384 x fs, disable i2s asrc\n");
+
+	return 0;
+}
+
+/**
+ * rt5663_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @component: SoC audio component device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5663 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5663_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src)
+{
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+	unsigned int asrc2_mask = 0;
+	unsigned int asrc2_value = 0;
+	unsigned int asrc3_mask = 0;
+	unsigned int asrc3_value = 0;
+
+	switch (clk_src) {
+	case RT5663_CLK_SEL_SYS:
+	case RT5663_CLK_SEL_I2S1_ASRC:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (filter_mask & RT5663_DA_STEREO_FILTER) {
+		asrc2_mask |= RT5663_DA_STO1_TRACK_MASK;
+		asrc2_value |= clk_src << RT5663_DA_STO1_TRACK_SHIFT;
+	}
+
+	if (filter_mask & RT5663_AD_STEREO_FILTER) {
+		switch (rt5663->codec_ver) {
+		case CODEC_VER_1:
+			asrc3_mask |= RT5663_V2_AD_STO1_TRACK_MASK;
+			asrc3_value |= clk_src << RT5663_V2_AD_STO1_TRACK_SHIFT;
+			break;
+		case CODEC_VER_0:
+			asrc2_mask |= RT5663_AD_STO1_TRACK_MASK;
+			asrc2_value |= clk_src << RT5663_AD_STO1_TRACK_SHIFT;
+			break;
+		default:
+			dev_err(component->dev, "Unknown CODEC Version\n");
+		}
+	}
+
+	if (asrc2_mask)
+		snd_soc_component_update_bits(component, RT5663_ASRC_2, asrc2_mask,
+			asrc2_value);
+
+	if (asrc3_mask)
+		snd_soc_component_update_bits(component, RT5663_ASRC_3, asrc3_mask,
+			asrc3_value);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5663_sel_asrc_clk_src);
+
+/* Analog Mixer */
+static const struct snd_kcontrol_new rt5663_recmix1l[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5663_RECMIX1L,
+		RT5663_RECMIX1L_BST2_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 CBJ Switch", RT5663_RECMIX1L,
+		RT5663_RECMIX1L_BST1_CBJ_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5663_recmix1r[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5663_RECMIX1R,
+		RT5663_RECMIX1R_BST2_SHIFT, 1, 1),
+};
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5663_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER,
+			RT5663_M_STO1_ADC_L1_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER,
+			RT5663_M_STO1_ADC_L2_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5663_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER,
+			RT5663_M_STO1_ADC_R1_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER,
+			RT5663_M_STO1_ADC_R2_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5663_adda_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC L Switch", RT5663_AD_DA_MIXER,
+			RT5663_M_ADCMIX_L_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L Switch", RT5663_AD_DA_MIXER,
+			RT5663_M_DAC1_L_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5663_adda_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC R Switch", RT5663_AD_DA_MIXER,
+			RT5663_M_ADCMIX_R_SHIFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R Switch", RT5663_AD_DA_MIXER,
+			RT5663_M_DAC1_R_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5663_sto1_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER,
+			RT5663_M_DAC_L1_STO_L_SHIFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5663_sto1_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER,
+			RT5663_M_DAC_R1_STO_R_SHIFT, 1, 1),
+};
+
+/* Out Switch */
+static const struct snd_kcontrol_new rt5663_hpo_switch =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5663_HP_AMP_2,
+		RT5663_EN_DAC_HPO_SHIFT, 1, 0);
+
+/* Stereo ADC source */
+static const char * const rt5663_sto1_adc_src[] = {
+	"ADC L", "ADC R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5663_sto1_adcl_enum, RT5663_STO1_ADC_MIXER,
+	RT5663_STO1_ADC_L_SRC_SHIFT, rt5663_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5663_sto1_adcl_mux =
+	SOC_DAPM_ENUM("STO1 ADC L Mux", rt5663_sto1_adcl_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5663_sto1_adcr_enum, RT5663_STO1_ADC_MIXER,
+	RT5663_STO1_ADC_R_SRC_SHIFT, rt5663_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5663_sto1_adcr_mux =
+	SOC_DAPM_ENUM("STO1 ADC R Mux", rt5663_sto1_adcr_enum);
+
+/* RT5663: Analog DACL1 input source */
+static const char * const rt5663_alg_dacl_src[] = {
+	"DAC L", "STO DAC MIXL"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5663_alg_dacl_enum, RT5663_BYPASS_STO_DAC,
+	RT5663_DACL1_SRC_SHIFT, rt5663_alg_dacl_src);
+
+static const struct snd_kcontrol_new rt5663_alg_dacl_mux =
+	SOC_DAPM_ENUM("DAC L Mux", rt5663_alg_dacl_enum);
+
+/* RT5663: Analog DACR1 input source */
+static const char * const rt5663_alg_dacr_src[] = {
+	"DAC R", "STO DAC MIXR"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5663_alg_dacr_enum, RT5663_BYPASS_STO_DAC,
+	RT5663_DACR1_SRC_SHIFT, rt5663_alg_dacr_src);
+
+static const struct snd_kcontrol_new rt5663_alg_dacr_mux =
+	SOC_DAPM_ENUM("DAC R Mux", rt5663_alg_dacr_enum);
+
+static int rt5663_hp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (rt5663->codec_ver == CODEC_VER_1) {
+			snd_soc_component_update_bits(component, RT5663_HP_CHARGE_PUMP_1,
+				RT5663_SEL_PM_HP_SHIFT, RT5663_SEL_PM_HP_HIGH);
+			snd_soc_component_update_bits(component, RT5663_HP_LOGIC_2,
+				RT5663_HP_SIG_SRC1_MASK,
+				RT5663_HP_SIG_SRC1_SILENCE);
+		} else {
+			snd_soc_component_update_bits(component,
+				RT5663_DACREF_LDO, 0x3e0e, 0x3a0a);
+			snd_soc_component_write(component, RT5663_DEPOP_2, 0x3003);
+			snd_soc_component_update_bits(component, RT5663_HP_CHARGE_PUMP_1,
+				RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_DIS);
+			snd_soc_component_write(component, RT5663_HP_CHARGE_PUMP_2, 0x1371);
+			snd_soc_component_write(component, RT5663_HP_BIAS, 0xabba);
+			snd_soc_component_write(component, RT5663_CHARGE_PUMP_1, 0x2224);
+			snd_soc_component_write(component, RT5663_ANA_BIAS_CUR_1, 0x7766);
+			snd_soc_component_write(component, RT5663_HP_BIAS, 0xafaa);
+			snd_soc_component_write(component, RT5663_CHARGE_PUMP_2, 0x7777);
+			snd_soc_component_update_bits(component, RT5663_STO_DRE_1, 0x8000,
+				0x8000);
+			snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000,
+				0x3000);
+		}
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		if (rt5663->codec_ver == CODEC_VER_1) {
+			snd_soc_component_update_bits(component, RT5663_HP_LOGIC_2,
+				RT5663_HP_SIG_SRC1_MASK,
+				RT5663_HP_SIG_SRC1_REG);
+		} else {
+			snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000, 0x0);
+			snd_soc_component_update_bits(component, RT5663_HP_CHARGE_PUMP_1,
+				RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN);
+			snd_soc_component_update_bits(component,
+				RT5663_DACREF_LDO, 0x3e0e, 0);
+		}
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5663_charge_pump_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (rt5663->codec_ver == CODEC_VER_0) {
+			snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0030,
+				0x0030);
+			snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0003,
+				0x0003);
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		if (rt5663->codec_ver == CODEC_VER_0) {
+			snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0003, 0);
+			snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x0030, 0);
+		}
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5663_bst2_power(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_2,
+			RT5663_PWR_BST2_MASK | RT5663_PWR_BST2_OP_MASK,
+			RT5663_PWR_BST2 | RT5663_PWR_BST2_OP);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_2,
+			RT5663_PWR_BST2_MASK | RT5663_PWR_BST2_OP_MASK, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5663_pre_div_power(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_write(component, RT5663_PRE_DIV_GATING_1, 0xff00);
+		snd_soc_component_write(component, RT5663_PRE_DIV_GATING_2, 0xfffc);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_write(component, RT5663_PRE_DIV_GATING_1, 0x0000);
+		snd_soc_component_write(component, RT5663_PRE_DIV_GATING_2, 0x0000);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("PLL", RT5663_PWR_ANLG_3, RT5663_PWR_PLL_SHIFT, 0,
+		NULL, 0),
+
+	/* micbias */
+	SND_SOC_DAPM_MICBIAS("MICBIAS1", RT5663_PWR_ANLG_2,
+		RT5663_PWR_MB1_SHIFT, 0),
+	SND_SOC_DAPM_MICBIAS("MICBIAS2", RT5663_PWR_ANLG_2,
+		RT5663_PWR_MB2_SHIFT, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN1N"),
+
+	/* REC Mixer Power */
+	SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5663_PWR_ANLG_2,
+		RT5663_PWR_RECMIX1_SHIFT, 0, NULL, 0),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_SUPPLY("ADC L Power", RT5663_PWR_DIG_1,
+		RT5663_PWR_ADC_L1_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Clock", RT5663_CHOP_ADC,
+		RT5663_CKGEN_ADCC_SHIFT, 0, NULL, 0),
+
+	/* ADC Mixer */
+	SND_SOC_DAPM_MIXER("STO1 ADC MIXL", SND_SOC_NOPM,
+		0, 0, rt5663_sto1_adc_l_mix,
+		ARRAY_SIZE(rt5663_sto1_adc_l_mix)),
+
+	/* ADC Filter Power */
+	SND_SOC_DAPM_SUPPLY("STO1 ADC Filter", RT5663_PWR_DIG_2,
+		RT5663_PWR_ADC_S1F_SHIFT, 0, NULL, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S", RT5663_PWR_DIG_1, RT5663_PWR_I2S1_SHIFT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("IF DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIFTX", "AIF Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("ADDA MIXL", SND_SOC_NOPM, 0, 0, rt5663_adda_l_mix,
+		ARRAY_SIZE(rt5663_adda_l_mix)),
+	SND_SOC_DAPM_MIXER("ADDA MIXR", SND_SOC_NOPM, 0, 0, rt5663_adda_r_mix,
+		ARRAY_SIZE(rt5663_adda_r_mix)),
+	SND_SOC_DAPM_PGA("DAC L1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DAC R1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY("STO1 DAC Filter", RT5663_PWR_DIG_2,
+		RT5663_PWR_DAC_S1F_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("STO1 DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5663_sto1_dac_l_mix, ARRAY_SIZE(rt5663_sto1_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("STO1 DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5663_sto1_dac_r_mix, ARRAY_SIZE(rt5663_sto1_dac_r_mix)),
+
+	/* DACs */
+	SND_SOC_DAPM_SUPPLY("STO1 DAC L Power", RT5663_PWR_DIG_1,
+		RT5663_PWR_DAC_L1_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("STO1 DAC R Power", RT5663_PWR_DIG_1,
+		RT5663_PWR_DAC_R1_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("DAC L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC R", NULL, SND_SOC_NOPM, 0, 0),
+
+	/* Headphone*/
+	SND_SOC_DAPM_SUPPLY("HP Charge Pump", SND_SOC_NOPM, 0, 0,
+		rt5663_charge_pump_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5663_hp_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_widget rt5663_v2_specific_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("LDO2", RT5663_PWR_ANLG_3,
+		RT5663_PWR_LDO2_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5663_PWR_VOL,
+		RT5663_V2_PWR_MIC_DET_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LDO DAC", RT5663_PWR_DIG_1,
+		RT5663_PWR_LDO_DACREF_SHIFT, 0, NULL, 0),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1,
+		RT5663_I2S1_ASRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC ASRC", RT5663_ASRC_1,
+		RT5663_DAC_STO1_ASRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC ASRC", RT5663_ASRC_1,
+		RT5663_ADC_STO1_ASRC_SHIFT, 0, NULL, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN2N"),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CBJ Power", RT5663_PWR_ANLG_3,
+		RT5663_PWR_CBJ_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST2 Power", SND_SOC_NOPM, 0, 0,
+		rt5663_bst2_power, SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMU),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5663_recmix1l,
+		ARRAY_SIZE(rt5663_recmix1l)),
+	SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5663_recmix1r,
+		ARRAY_SIZE(rt5663_recmix1r)),
+	SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5663_PWR_ANLG_2,
+		RT5663_PWR_RECMIX2_SHIFT, 0, NULL, 0),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_SUPPLY("ADC R Power", RT5663_PWR_DIG_1,
+		RT5663_PWR_ADC_R1_SHIFT, 0, NULL, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_PGA("STO1 ADC L1", RT5663_STO1_ADC_MIXER,
+		RT5663_STO1_ADC_L1_SRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("STO1 ADC R1", RT5663_STO1_ADC_MIXER,
+		RT5663_STO1_ADC_R1_SRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("STO1 ADC L2", RT5663_STO1_ADC_MIXER,
+		RT5663_STO1_ADC_L2_SRC_SHIFT, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("STO1 ADC R2", RT5663_STO1_ADC_MIXER,
+		RT5663_STO1_ADC_R2_SRC_SHIFT, 1, NULL, 0),
+
+	SND_SOC_DAPM_MUX("STO1 ADC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5663_sto1_adcl_mux),
+	SND_SOC_DAPM_MUX("STO1 ADC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5663_sto1_adcr_mux),
+
+	/* ADC Mix */
+	SND_SOC_DAPM_MIXER("STO1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5663_sto1_adc_r_mix, ARRAY_SIZE(rt5663_sto1_adc_r_mix)),
+
+	/* Analog DAC Clock */
+	SND_SOC_DAPM_SUPPLY("DAC Clock", RT5663_CHOP_DAC_L,
+		RT5663_CKGEN_DAC1_SHIFT, 0, NULL, 0),
+
+	/* Headphone out */
+	SND_SOC_DAPM_SWITCH("HPO Playback", SND_SOC_NOPM, 0, 0,
+		&rt5663_hpo_switch),
+};
+
+static const struct snd_soc_dapm_widget rt5663_specific_dapm_widgets[] = {
+	/* System Clock Pre Divider Gating */
+	SND_SOC_DAPM_SUPPLY("Pre Div Power", SND_SOC_NOPM, 0, 0,
+		rt5663_pre_div_power, SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD),
+
+	/* LDO */
+	SND_SOC_DAPM_SUPPLY("LDO ADC", RT5663_PWR_DIG_1,
+		RT5663_PWR_LDO_DACREF_SHIFT, 0, NULL, 0),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1,
+		RT5663_I2S1_ASRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC ASRC", RT5663_ASRC_1,
+		RT5663_DAC_STO1_ASRC_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC ASRC", RT5663_ASRC_1,
+		RT5663_ADC_STO1_ASRC_SHIFT, 0, NULL, 0),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* STO ADC */
+	SND_SOC_DAPM_PGA("STO1 ADC L1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("STO1 ADC L2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Analog DAC source */
+	SND_SOC_DAPM_MUX("DAC L Mux", SND_SOC_NOPM, 0, 0, &rt5663_alg_dacl_mux),
+	SND_SOC_DAPM_MUX("DAC R Mux", SND_SOC_NOPM, 0, 0, &rt5663_alg_dacr_mux),
+};
+
+static const struct snd_soc_dapm_route rt5663_dapm_routes[] = {
+	/* PLL */
+	{ "I2S", NULL, "PLL", rt5663_is_sys_clk_from_pll },
+
+	/* ASRC */
+	{ "STO1 ADC Filter", NULL, "ADC ASRC", rt5663_is_using_asrc },
+	{ "STO1 DAC Filter", NULL, "DAC ASRC", rt5663_is_using_asrc },
+	{ "I2S", NULL, "I2S ASRC", rt5663_i2s_use_asrc },
+
+	{ "ADC L", NULL, "ADC L Power" },
+	{ "ADC L", NULL, "ADC Clock" },
+
+	{ "STO1 ADC L2", NULL, "STO1 DAC MIXL" },
+
+	{ "STO1 ADC MIXL", "ADC1 Switch", "STO1 ADC L1" },
+	{ "STO1 ADC MIXL", "ADC2 Switch", "STO1 ADC L2" },
+	{ "STO1 ADC MIXL", NULL, "STO1 ADC Filter" },
+
+	{ "IF1 ADC1", NULL, "STO1 ADC MIXL" },
+	{ "IF ADC", NULL, "IF1 ADC1" },
+	{ "AIFTX", NULL, "IF ADC" },
+	{ "AIFTX", NULL, "I2S" },
+
+	{ "AIFRX", NULL, "I2S" },
+	{ "IF DAC", NULL, "AIFRX" },
+	{ "IF1 DAC1 L", NULL, "IF DAC" },
+	{ "IF1 DAC1 R", NULL, "IF DAC" },
+
+	{ "ADDA MIXL", "ADC L Switch", "STO1 ADC MIXL" },
+	{ "ADDA MIXL", "DAC L Switch", "IF1 DAC1 L" },
+	{ "ADDA MIXL", NULL, "STO1 DAC Filter" },
+	{ "ADDA MIXL", NULL, "STO1 DAC L Power" },
+	{ "ADDA MIXR", "DAC R Switch", "IF1 DAC1 R" },
+	{ "ADDA MIXR", NULL, "STO1 DAC Filter" },
+	{ "ADDA MIXR", NULL, "STO1 DAC R Power" },
+
+	{ "DAC L1", NULL, "ADDA MIXL" },
+	{ "DAC R1", NULL, "ADDA MIXR" },
+
+	{ "STO1 DAC MIXL", "DAC L Switch", "DAC L1" },
+	{ "STO1 DAC MIXL", NULL, "STO1 DAC L Power" },
+	{ "STO1 DAC MIXL", NULL, "STO1 DAC Filter" },
+	{ "STO1 DAC MIXR", "DAC R Switch", "DAC R1" },
+	{ "STO1 DAC MIXR", NULL, "STO1 DAC R Power" },
+	{ "STO1 DAC MIXR", NULL, "STO1 DAC Filter" },
+
+	{ "HP Amp", NULL, "HP Charge Pump" },
+	{ "HP Amp", NULL, "DAC L" },
+	{ "HP Amp", NULL, "DAC R" },
+};
+
+static const struct snd_soc_dapm_route rt5663_v2_specific_dapm_routes[] = {
+	{ "MICBIAS1", NULL, "LDO2" },
+	{ "MICBIAS2", NULL, "LDO2" },
+
+	{ "BST1 CBJ", NULL, "IN1P" },
+	{ "BST1 CBJ", NULL, "IN1N" },
+	{ "BST1 CBJ", NULL, "CBJ Power" },
+
+	{ "BST2", NULL, "IN2P" },
+	{ "BST2", NULL, "IN2N" },
+	{ "BST2", NULL, "BST2 Power" },
+
+	{ "RECMIX1L", "BST2 Switch", "BST2" },
+	{ "RECMIX1L", "BST1 CBJ Switch", "BST1 CBJ" },
+	{ "RECMIX1L", NULL, "RECMIX1L Power" },
+	{ "RECMIX1R", "BST2 Switch", "BST2" },
+	{ "RECMIX1R", NULL, "RECMIX1R Power" },
+
+	{ "ADC L", NULL, "RECMIX1L" },
+	{ "ADC R", NULL, "RECMIX1R" },
+	{ "ADC R", NULL, "ADC R Power" },
+	{ "ADC R", NULL, "ADC Clock" },
+
+	{ "STO1 ADC L Mux", "ADC L", "ADC L" },
+	{ "STO1 ADC L Mux", "ADC R", "ADC R" },
+	{ "STO1 ADC L1", NULL, "STO1 ADC L Mux" },
+
+	{ "STO1 ADC R Mux", "ADC L", "ADC L" },
+	{ "STO1 ADC R Mux", "ADC R", "ADC R" },
+	{ "STO1 ADC R1", NULL, "STO1 ADC R Mux" },
+	{ "STO1 ADC R2", NULL, "STO1 DAC MIXR" },
+
+	{ "STO1 ADC MIXR", "ADC1 Switch", "STO1 ADC R1" },
+	{ "STO1 ADC MIXR", "ADC2 Switch", "STO1 ADC R2" },
+	{ "STO1 ADC MIXR", NULL, "STO1 ADC Filter" },
+
+	{ "IF1 ADC1", NULL, "STO1 ADC MIXR" },
+
+	{ "ADDA MIXR", "ADC R Switch", "STO1 ADC MIXR" },
+
+	{ "DAC L", NULL, "STO1 DAC MIXL" },
+	{ "DAC L", NULL, "LDO DAC" },
+	{ "DAC L", NULL, "DAC Clock" },
+	{ "DAC R", NULL, "STO1 DAC MIXR" },
+	{ "DAC R", NULL, "LDO DAC" },
+	{ "DAC R", NULL, "DAC Clock" },
+
+	{ "HPO Playback", "Switch", "HP Amp" },
+	{ "HPOL", NULL, "HPO Playback" },
+	{ "HPOR", NULL, "HPO Playback" },
+};
+
+static const struct snd_soc_dapm_route rt5663_specific_dapm_routes[] = {
+	{ "I2S", NULL, "Pre Div Power" },
+
+	{ "BST1", NULL, "IN1P" },
+	{ "BST1", NULL, "IN1N" },
+	{ "BST1", NULL, "RECMIX1L Power" },
+
+	{ "ADC L", NULL, "BST1" },
+
+	{ "STO1 ADC L1", NULL, "ADC L" },
+
+	{ "DAC L Mux", "DAC L",  "DAC L1" },
+	{ "DAC L Mux", "STO DAC MIXL", "STO1 DAC MIXL" },
+	{ "DAC R Mux", "DAC R",  "DAC R1"},
+	{ "DAC R Mux", "STO DAC MIXR", "STO1 DAC MIXR" },
+
+	{ "DAC L", NULL, "DAC L Mux" },
+	{ "DAC R", NULL, "DAC R Mux" },
+
+	{ "HPOL", NULL, "HP Amp" },
+	{ "HPOR", NULL, "HP Amp" },
+};
+
+static int rt5663_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0;
+	int pre_div;
+
+	rt5663->lrck = params_rate(params);
+
+	dev_dbg(dai->dev, "bclk is %dHz and sysclk is %dHz\n",
+		rt5663->lrck, rt5663->sysclk);
+
+	pre_div = rl6231_get_clk_info(rt5663->sysclk, rt5663->lrck);
+	if (pre_div < 0) {
+		dev_err(component->dev, "Unsupported clock setting %d for DAI %d\n",
+			rt5663->lrck, dai->id);
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "pre_div is %d for iis %d\n", pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 8:
+		val_len = RT5663_I2S_DL_8;
+		break;
+	case 16:
+		val_len = RT5663_I2S_DL_16;
+		break;
+	case 20:
+		val_len = RT5663_I2S_DL_20;
+		break;
+	case 24:
+		val_len = RT5663_I2S_DL_24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5663_I2S1_SDP,
+		RT5663_I2S_DL_MASK, val_len);
+
+	snd_soc_component_update_bits(component, RT5663_ADDA_CLK_1,
+		RT5663_I2S_PD1_MASK, pre_div << RT5663_I2S_PD1_SHIFT);
+
+	return 0;
+}
+
+static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int reg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5663_I2S_MS_S;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5663_I2S_BP_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5663_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5663_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5663_I2S_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5663_I2S1_SDP, RT5663_I2S_MS_MASK |
+		RT5663_I2S_BP_MASK | RT5663_I2S_DF_MASK, reg_val);
+
+	return 0;
+}
+
+static int rt5663_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+	unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	if (freq == rt5663->sysclk && clk_id == rt5663->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5663_SCLK_S_MCLK:
+		reg_val |= RT5663_SCLK_SRC_MCLK;
+		break;
+	case RT5663_SCLK_S_PLL1:
+		reg_val |= RT5663_SCLK_SRC_PLL1;
+		break;
+	case RT5663_SCLK_S_RCCLK:
+		reg_val |= RT5663_SCLK_SRC_RCCLK;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, RT5663_GLB_CLK, RT5663_SCLK_SRC_MASK,
+		reg_val);
+	rt5663->sysclk = freq;
+	rt5663->sysclk_src = clk_id;
+
+	dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n",
+		freq, clk_id);
+
+	return 0;
+}
+
+static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+			unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+	int mask, shift, val;
+
+	if (source == rt5663->pll_src && freq_in == rt5663->pll_in &&
+	    freq_out == rt5663->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt5663->pll_in = 0;
+		rt5663->pll_out = 0;
+		snd_soc_component_update_bits(component, RT5663_GLB_CLK,
+			RT5663_SCLK_SRC_MASK, RT5663_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (rt5663->codec_ver) {
+	case CODEC_VER_1:
+		mask = RT5663_V2_PLL1_SRC_MASK;
+		shift = RT5663_V2_PLL1_SRC_SHIFT;
+		break;
+	case CODEC_VER_0:
+		mask = RT5663_PLL1_SRC_MASK;
+		shift = RT5663_PLL1_SRC_SHIFT;
+		break;
+	default:
+		dev_err(component->dev, "Unknown CODEC Version\n");
+		return -EINVAL;
+	}
+
+	switch (source) {
+	case RT5663_PLL1_S_MCLK:
+		val = 0x0;
+		break;
+	case RT5663_PLL1_S_BCLK1:
+		val = 0x1;
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, RT5663_GLB_CLK, mask, (val << shift));
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n", pll_code.m_bp,
+		(pll_code.m_bp ? 0 : pll_code.m_code), pll_code.n_code,
+		pll_code.k_code);
+
+	snd_soc_component_write(component, RT5663_PLL_1,
+		pll_code.n_code << RT5663_PLL_N_SHIFT | pll_code.k_code);
+	snd_soc_component_write(component, RT5663_PLL_2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5663_PLL_M_SHIFT |
+		pll_code.m_bp << RT5663_PLL_M_BP_SHIFT);
+
+	rt5663->pll_in = freq_in;
+	rt5663->pll_out = freq_out;
+	rt5663->pll_src = source;
+
+	return 0;
+}
+
+static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+	unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+	unsigned int val = 0, reg;
+
+	if (rx_mask || tx_mask)
+		val |= RT5663_TDM_MODE_TDM;
+
+	switch (slots) {
+	case 4:
+		val |= RT5663_TDM_IN_CH_4;
+		val |= RT5663_TDM_OUT_CH_4;
+		break;
+	case 6:
+		val |= RT5663_TDM_IN_CH_6;
+		val |= RT5663_TDM_OUT_CH_6;
+		break;
+	case 8:
+		val |= RT5663_TDM_IN_CH_8;
+		val |= RT5663_TDM_OUT_CH_8;
+		break;
+	case 2:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (slot_width) {
+	case 20:
+		val |= RT5663_TDM_IN_LEN_20;
+		val |= RT5663_TDM_OUT_LEN_20;
+		break;
+	case 24:
+		val |= RT5663_TDM_IN_LEN_24;
+		val |= RT5663_TDM_OUT_LEN_24;
+		break;
+	case 32:
+		val |= RT5663_TDM_IN_LEN_32;
+		val |= RT5663_TDM_OUT_LEN_32;
+		break;
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (rt5663->codec_ver) {
+	case CODEC_VER_1:
+		reg = RT5663_TDM_2;
+		break;
+	case CODEC_VER_0:
+		reg = RT5663_TDM_1;
+		break;
+	default:
+		dev_err(component->dev, "Unknown CODEC Version\n");
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, reg, RT5663_TDM_MODE_MASK |
+		RT5663_TDM_IN_CH_MASK | RT5663_TDM_OUT_CH_MASK |
+		RT5663_TDM_IN_LEN_MASK | RT5663_TDM_OUT_LEN_MASK, val);
+
+	return 0;
+}
+
+static int rt5663_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+	unsigned int reg;
+
+	dev_dbg(component->dev, "%s ratio = %d\n", __func__, ratio);
+
+	if (rt5663->codec_ver == CODEC_VER_1)
+		reg = RT5663_TDM_9;
+	else
+		reg = RT5663_TDM_5;
+
+	switch (ratio) {
+	case 32:
+		snd_soc_component_update_bits(component, reg,
+			RT5663_TDM_LENGTN_MASK,
+			RT5663_TDM_LENGTN_16);
+		break;
+	case 40:
+		snd_soc_component_update_bits(component, reg,
+			RT5663_TDM_LENGTN_MASK,
+			RT5663_TDM_LENGTN_20);
+		break;
+	case 48:
+		snd_soc_component_update_bits(component, reg,
+			RT5663_TDM_LENGTN_MASK,
+			RT5663_TDM_LENGTN_24);
+		break;
+	case 64:
+		snd_soc_component_update_bits(component, reg,
+			RT5663_TDM_LENGTN_MASK,
+			RT5663_TDM_LENGTN_32);
+		break;
+	default:
+		dev_err(component->dev, "Invalid ratio!\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5663_set_bias_level(struct snd_soc_component *component,
+			enum snd_soc_bias_level level)
+{
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
+			RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
+			RT5663_PWR_FV1 | RT5663_PWR_FV2);
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		if (rt5663->codec_ver == CODEC_VER_1) {
+			snd_soc_component_update_bits(component, RT5663_DIG_MISC,
+				RT5663_DIG_GATE_CTRL_MASK,
+				RT5663_DIG_GATE_CTRL_EN);
+			snd_soc_component_update_bits(component, RT5663_SIG_CLK_DET,
+				RT5663_EN_ANA_CLK_DET_MASK |
+				RT5663_PWR_CLK_DET_MASK,
+				RT5663_EN_ANA_CLK_DET_AUTO |
+				RT5663_PWR_CLK_DET_EN);
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (rt5663->codec_ver == CODEC_VER_1)
+			snd_soc_component_update_bits(component, RT5663_DIG_MISC,
+				RT5663_DIG_GATE_CTRL_MASK,
+				RT5663_DIG_GATE_CTRL_DIS);
+		snd_soc_component_update_bits(component, RT5663_PWR_ANLG_1,
+			RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
+			RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK |
+			RT5663_PWR_MB_MASK, RT5663_PWR_VREF1 |
+			RT5663_PWR_VREF2 | RT5663_PWR_MB);
+		usleep_range(10000, 10005);
+		if (rt5663->codec_ver == CODEC_VER_1) {
+			snd_soc_component_update_bits(component, RT5663_SIG_CLK_DET,
+				RT5663_EN_ANA_CLK_DET_MASK |
+				RT5663_PWR_CLK_DET_MASK,
+				RT5663_EN_ANA_CLK_DET_DIS |
+				RT5663_PWR_CLK_DET_DIS);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		if (rt5663->jack_type != SND_JACK_HEADSET)
+			snd_soc_component_update_bits(component,
+				RT5663_PWR_ANLG_1,
+				RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
+				RT5663_PWR_FV1 | RT5663_PWR_FV2 |
+				RT5663_PWR_MB_MASK, 0);
+		else
+			snd_soc_component_update_bits(component,
+				RT5663_PWR_ANLG_1,
+				RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
+				RT5663_PWR_FV1 | RT5663_PWR_FV2);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5663_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+
+	rt5663->component = component;
+
+	switch (rt5663->codec_ver) {
+	case CODEC_VER_1:
+		snd_soc_dapm_new_controls(dapm,
+			rt5663_v2_specific_dapm_widgets,
+			ARRAY_SIZE(rt5663_v2_specific_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm,
+			rt5663_v2_specific_dapm_routes,
+			ARRAY_SIZE(rt5663_v2_specific_dapm_routes));
+		snd_soc_add_component_controls(component, rt5663_v2_specific_controls,
+			ARRAY_SIZE(rt5663_v2_specific_controls));
+		break;
+	case CODEC_VER_0:
+		snd_soc_dapm_new_controls(dapm,
+			rt5663_specific_dapm_widgets,
+			ARRAY_SIZE(rt5663_specific_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm,
+			rt5663_specific_dapm_routes,
+			ARRAY_SIZE(rt5663_specific_dapm_routes));
+		snd_soc_add_component_controls(component, rt5663_specific_controls,
+			ARRAY_SIZE(rt5663_specific_controls));
+
+		if (!rt5663->imp_table)
+			snd_soc_add_component_controls(component, rt5663_hpvol_controls,
+				ARRAY_SIZE(rt5663_hpvol_controls));
+		break;
+	}
+
+	return 0;
+}
+
+static void rt5663_remove(struct snd_soc_component *component)
+{
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+
+	regmap_write(rt5663->regmap, RT5663_RESET, 0);
+}
+
+#ifdef CONFIG_PM
+static int rt5663_suspend(struct snd_soc_component *component)
+{
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5663->regmap, true);
+	regcache_mark_dirty(rt5663->regmap);
+
+	return 0;
+}
+
+static int rt5663_resume(struct snd_soc_component *component)
+{
+	struct rt5663_priv *rt5663 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5663->regmap, false);
+	regcache_sync(rt5663->regmap);
+
+	rt5663_irq(0, rt5663);
+
+	return 0;
+}
+#else
+#define rt5663_suspend NULL
+#define rt5663_resume NULL
+#endif
+
+#define RT5663_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5663_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5663_aif_dai_ops = {
+	.hw_params = rt5663_hw_params,
+	.set_fmt = rt5663_set_dai_fmt,
+	.set_sysclk = rt5663_set_dai_sysclk,
+	.set_pll = rt5663_set_dai_pll,
+	.set_tdm_slot = rt5663_set_tdm_slot,
+	.set_bclk_ratio = rt5663_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt5663_dai[] = {
+	{
+		.name = "rt5663-aif",
+		.id = RT5663_AIF,
+		.playback = {
+			.stream_name = "AIF Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5663_STEREO_RATES,
+			.formats = RT5663_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5663_STEREO_RATES,
+			.formats = RT5663_FORMATS,
+		},
+		.ops = &rt5663_aif_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5663 = {
+	.probe			= rt5663_probe,
+	.remove			= rt5663_remove,
+	.suspend		= rt5663_suspend,
+	.resume			= rt5663_resume,
+	.set_bias_level		= rt5663_set_bias_level,
+	.controls		= rt5663_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5663_snd_controls),
+	.dapm_widgets		= rt5663_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5663_dapm_widgets),
+	.dapm_routes		= rt5663_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5663_dapm_routes),
+	.set_jack		= rt5663_set_jack_detect,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt5663_v2_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+	.use_single_rw = true,
+	.max_register = 0x07fa,
+	.volatile_reg = rt5663_v2_volatile_register,
+	.readable_reg = rt5663_v2_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5663_v2_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5663_v2_reg),
+};
+
+static const struct regmap_config rt5663_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+	.use_single_rw = true,
+	.max_register = 0x03f3,
+	.volatile_reg = rt5663_volatile_register,
+	.readable_reg = rt5663_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5663_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5663_reg),
+};
+
+static const struct regmap_config temp_regmap = {
+	.name = "nocache",
+	.reg_bits = 16,
+	.val_bits = 16,
+	.use_single_rw = true,
+	.max_register = 0x03f3,
+	.cache_type = REGCACHE_NONE,
+};
+
+static const struct i2c_device_id rt5663_i2c_id[] = {
+	{ "rt5663", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, rt5663_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rt5663_of_match[] = {
+	{ .compatible = "realtek,rt5663", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5663_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5663_acpi_match[] = {
+	{ "10EC5663", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, rt5663_acpi_match);
+#endif
+
+static void rt5663_v2_calibrate(struct rt5663_priv *rt5663)
+{
+	regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0xa402);
+	regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x0100);
+	regmap_write(rt5663->regmap, RT5663_RECMIX, 0x4040);
+	regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x0001);
+	regmap_write(rt5663->regmap, RT5663_RC_CLK, 0x0380);
+	regmap_write(rt5663->regmap, RT5663_GLB_CLK, 0x8000);
+	regmap_write(rt5663->regmap, RT5663_ADDA_CLK_1, 0x1000);
+	regmap_write(rt5663->regmap, RT5663_CHOP_DAC_L, 0x3030);
+	regmap_write(rt5663->regmap, RT5663_CALIB_ADC, 0x3c05);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa23e);
+	msleep(40);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf23e);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_2, 0x0321);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1, 0xfc00);
+	msleep(500);
+}
+
+static void rt5663_calibrate(struct rt5663_priv *rt5663)
+{
+	int value, count;
+
+	regmap_write(rt5663->regmap, RT5663_RESET, 0x0000);
+	msleep(20);
+	regmap_write(rt5663->regmap, RT5663_ANA_BIAS_CUR_4, 0x00a1);
+	regmap_write(rt5663->regmap, RT5663_RC_CLK, 0x0380);
+	regmap_write(rt5663->regmap, RT5663_GLB_CLK, 0x8000);
+	regmap_write(rt5663->regmap, RT5663_ADDA_CLK_1, 0x1000);
+	regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032);
+	regmap_write(rt5663->regmap, RT5663_HP_IMP_SEN_19, 0x000c);
+	regmap_write(rt5663->regmap, RT5663_DUMMY_1, 0x0324);
+	regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x8001);
+	regmap_write(rt5663->regmap, RT5663_VREFADJ_OP, 0x0f28);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa23b);
+	msleep(30);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf23b);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x8000);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x0008);
+	regmap_write(rt5663->regmap, RT5663_PRE_DIV_GATING_1, 0xffff);
+	regmap_write(rt5663->regmap, RT5663_PRE_DIV_GATING_2, 0xffff);
+	regmap_write(rt5663->regmap, RT5663_CBJ_1, 0x8c10);
+	regmap_write(rt5663->regmap, RT5663_IL_CMD_2, 0x00c1);
+	regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_1, 0xb880);
+	regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_2, 0x4110);
+	regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_2, 0x4118);
+
+	count = 0;
+	while (true) {
+		regmap_read(rt5663->regmap, RT5663_INT_ST_2, &value);
+		if (!(value & 0x80))
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (++count > 200)
+			break;
+	}
+
+	regmap_write(rt5663->regmap, RT5663_HP_IMP_SEN_19, 0x0000);
+	regmap_write(rt5663->regmap, RT5663_DEPOP_2, 0x3003);
+	regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x0038);
+	regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x003b);
+	regmap_write(rt5663->regmap, RT5663_PWR_DIG_2, 0x8400);
+	regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x8df8);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x8003);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x018c);
+	regmap_write(rt5663->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32);
+	regmap_write(rt5663->regmap, RT5663_DUMMY_2, 0x8089);
+	regmap_write(rt5663->regmap, RT5663_DACREF_LDO, 0x3b0b);
+	msleep(40);
+	regmap_write(rt5663->regmap, RT5663_STO_DAC_MIXER, 0x0000);
+	regmap_write(rt5663->regmap, RT5663_BYPASS_STO_DAC, 0x000c);
+	regmap_write(rt5663->regmap, RT5663_HP_BIAS, 0xafaa);
+	regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_1, 0x2224);
+	regmap_write(rt5663->regmap, RT5663_HP_OUT_EN, 0x8088);
+	regmap_write(rt5663->regmap, RT5663_STO_DRE_9, 0x0017);
+	regmap_write(rt5663->regmap, RT5663_STO_DRE_10, 0x0017);
+	regmap_write(rt5663->regmap, RT5663_STO1_ADC_MIXER, 0x4040);
+	regmap_write(rt5663->regmap, RT5663_CHOP_ADC, 0x3000);
+	regmap_write(rt5663->regmap, RT5663_RECMIX, 0x0005);
+	regmap_write(rt5663->regmap, RT5663_ADDA_RST, 0xc000);
+	regmap_write(rt5663->regmap, RT5663_STO1_HPF_ADJ1, 0x3320);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_2, 0x00c9);
+	regmap_write(rt5663->regmap, RT5663_DUMMY_1, 0x004c);
+	regmap_write(rt5663->regmap, RT5663_ANA_BIAS_CUR_1, 0x1111);
+	regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0x4402);
+	regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_2, 0x3311);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1, 0x0069);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_3, 0x06ce);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0x6800);
+	regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_2, 0x1100);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_7, 0x0057);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0xe800);
+
+	count = 0;
+	while (true) {
+		regmap_read(rt5663->regmap, RT5663_HP_CALIB_1_1, &value);
+		if (value & 0x8000)
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (count > 200)
+			return;
+		count++;
+	}
+
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0x6200);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_7, 0x0059);
+	regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0xe200);
+
+	count = 0;
+	while (true) {
+		regmap_read(rt5663->regmap, RT5663_HP_CALIB_1_1, &value);
+		if (value & 0x8000)
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (count > 200)
+			return;
+		count++;
+	}
+
+	regmap_write(rt5663->regmap, RT5663_EM_JACK_TYPE_1, 0xb8e0);
+	usleep_range(10000, 10005);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0x003b);
+	usleep_range(10000, 10005);
+	regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x0000);
+	usleep_range(10000, 10005);
+	regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x000b);
+	usleep_range(10000, 10005);
+	regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x0008);
+	usleep_range(10000, 10005);
+	regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x0000);
+	usleep_range(10000, 10005);
+}
+
+static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev)
+{
+	int table_size;
+
+	device_property_read_u32(dev, "realtek,dc_offset_l_manual",
+		&rt5663->pdata.dc_offset_l_manual);
+	device_property_read_u32(dev, "realtek,dc_offset_r_manual",
+		&rt5663->pdata.dc_offset_r_manual);
+	device_property_read_u32(dev, "realtek,dc_offset_l_manual_mic",
+		&rt5663->pdata.dc_offset_l_manual_mic);
+	device_property_read_u32(dev, "realtek,dc_offset_r_manual_mic",
+		&rt5663->pdata.dc_offset_r_manual_mic);
+	device_property_read_u32(dev, "realtek,impedance_sensing_num",
+		&rt5663->pdata.impedance_sensing_num);
+
+	if (rt5663->pdata.impedance_sensing_num) {
+		table_size = sizeof(struct impedance_mapping_table) *
+			rt5663->pdata.impedance_sensing_num;
+		rt5663->imp_table = devm_kzalloc(dev, table_size, GFP_KERNEL);
+		device_property_read_u32_array(dev,
+			"realtek,impedance_sensing_table",
+			(u32 *)rt5663->imp_table, table_size);
+	}
+
+	return 0;
+}
+
+static int rt5663_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt5663_priv *rt5663;
+	int ret;
+	unsigned int val;
+	struct regmap *regmap;
+
+	rt5663 = devm_kzalloc(&i2c->dev, sizeof(struct rt5663_priv),
+		GFP_KERNEL);
+
+	if (rt5663 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt5663);
+
+	if (pdata)
+		rt5663->pdata = *pdata;
+	else
+		rt5663_parse_dp(rt5663, &i2c->dev);
+
+	regmap = devm_regmap_init_i2c(i2c, &temp_regmap);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = regmap_read(regmap, RT5663_VENDOR_ID_2, &val);
+	if (ret || (val != RT5663_DEVICE_ID_2 && val != RT5663_DEVICE_ID_1)) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt5663, retry one time.\n",
+			val);
+		msleep(100);
+		regmap_read(regmap, RT5663_VENDOR_ID_2, &val);
+	}
+
+	switch (val) {
+	case RT5663_DEVICE_ID_2:
+		rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5663_v2_regmap);
+		rt5663->codec_ver = CODEC_VER_1;
+		break;
+	case RT5663_DEVICE_ID_1:
+		rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5663_regmap);
+		rt5663->codec_ver = CODEC_VER_0;
+		break;
+	default:
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt5663\n",
+			val);
+		return -ENODEV;
+	}
+
+	if (IS_ERR(rt5663->regmap)) {
+		ret = PTR_ERR(rt5663->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	/* reset and calibrate */
+	regmap_write(rt5663->regmap, RT5663_RESET, 0);
+	regcache_cache_bypass(rt5663->regmap, true);
+	switch (rt5663->codec_ver) {
+	case CODEC_VER_1:
+		rt5663_v2_calibrate(rt5663);
+		break;
+	case CODEC_VER_0:
+		rt5663_calibrate(rt5663);
+		break;
+	default:
+		dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__);
+	}
+	regcache_cache_bypass(rt5663->regmap, false);
+	regmap_write(rt5663->regmap, RT5663_RESET, 0);
+	dev_dbg(&i2c->dev, "calibrate done\n");
+
+	switch (rt5663->codec_ver) {
+	case CODEC_VER_1:
+		break;
+	case CODEC_VER_0:
+		ret = regmap_register_patch(rt5663->regmap, rt5663_patch_list,
+					    ARRAY_SIZE(rt5663_patch_list));
+		if (ret != 0)
+			dev_warn(&i2c->dev,
+				"Failed to apply regmap patch: %d\n", ret);
+		break;
+	default:
+		dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__);
+	}
+
+	/* GPIO1 as IRQ */
+	regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, RT5663_GP1_PIN_MASK,
+		RT5663_GP1_PIN_IRQ);
+	/* 4btn inline command debounce */
+	regmap_update_bits(rt5663->regmap, RT5663_IL_CMD_5,
+		RT5663_4BTN_CLK_DEB_MASK, RT5663_4BTN_CLK_DEB_65MS);
+
+	switch (rt5663->codec_ver) {
+	case CODEC_VER_1:
+		regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0xa402);
+		/* JD1 */
+		regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK,
+			RT5663_IRQ_POW_SAV_MASK | RT5663_IRQ_POW_SAV_JD1_MASK,
+			RT5663_IRQ_POW_SAV_EN | RT5663_IRQ_POW_SAV_JD1_EN);
+		regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_2,
+			RT5663_PWR_JD1_MASK, RT5663_PWR_JD1);
+		regmap_update_bits(rt5663->regmap, RT5663_IRQ_1,
+			RT5663_EN_CB_JD_MASK, RT5663_EN_CB_JD_EN);
+
+		regmap_update_bits(rt5663->regmap, RT5663_HP_LOGIC_2,
+			RT5663_HP_SIG_SRC1_MASK, RT5663_HP_SIG_SRC1_REG);
+		regmap_update_bits(rt5663->regmap, RT5663_RECMIX,
+			RT5663_VREF_BIAS_MASK | RT5663_CBJ_DET_MASK |
+			RT5663_DET_TYPE_MASK, RT5663_VREF_BIAS_REG |
+			RT5663_CBJ_DET_EN | RT5663_DET_TYPE_QFN);
+		/* Set GPIO4 and GPIO8 as input for combo jack */
+		regmap_update_bits(rt5663->regmap, RT5663_GPIO_2,
+			RT5663_GP4_PIN_CONF_MASK, RT5663_GP4_PIN_CONF_INPUT);
+		regmap_update_bits(rt5663->regmap, RT5663_GPIO_3,
+			RT5663_GP8_PIN_CONF_MASK, RT5663_GP8_PIN_CONF_INPUT);
+		regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_1,
+			RT5663_LDO1_DVO_MASK | RT5663_AMP_HP_MASK,
+			RT5663_LDO1_DVO_0_9V | RT5663_AMP_HP_3X);
+			break;
+	case CODEC_VER_0:
+		regmap_update_bits(rt5663->regmap, RT5663_DIG_MISC,
+			RT5663_DIG_GATE_CTRL_MASK, RT5663_DIG_GATE_CTRL_EN);
+		regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK,
+			RT5663_IRQ_MANUAL_MASK, RT5663_IRQ_MANUAL_EN);
+		regmap_update_bits(rt5663->regmap, RT5663_IRQ_1,
+			RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN);
+		regmap_update_bits(rt5663->regmap, RT5663_GPIO_1,
+			RT5663_GPIO1_TYPE_MASK, RT5663_GPIO1_TYPE_EN);
+		regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032);
+		regmap_update_bits(rt5663->regmap, RT5663_GPIO_2,
+			RT5663_GP1_PIN_CONF_MASK | RT5663_SEL_GPIO1_MASK,
+			RT5663_GP1_PIN_CONF_OUTPUT | RT5663_SEL_GPIO1_EN);
+		regmap_update_bits(rt5663->regmap, RT5663_RECMIX,
+			RT5663_RECMIX1_BST1_MASK, RT5663_RECMIX1_BST1_ON);
+		regmap_update_bits(rt5663->regmap, RT5663_TDM_2,
+			RT5663_DATA_SWAP_ADCDAT1_MASK,
+			RT5663_DATA_SWAP_ADCDAT1_LL);
+			break;
+	default:
+		dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__);
+	}
+
+	INIT_DELAYED_WORK(&rt5663->jack_detect_work, rt5663_jack_detect_work);
+	INIT_DELAYED_WORK(&rt5663->jd_unplug_work, rt5663_jd_unplug_work);
+
+	if (i2c->irq) {
+		ret = request_irq(i2c->irq, rt5663_irq,
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+			| IRQF_ONESHOT, "rt5663", rt5663);
+		if (ret)
+			dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n",
+				__func__, ret);
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_rt5663,
+			rt5663_dai, ARRAY_SIZE(rt5663_dai));
+
+	if (ret) {
+		if (i2c->irq)
+			free_irq(i2c->irq, rt5663);
+	}
+
+	return ret;
+}
+
+static int rt5663_i2c_remove(struct i2c_client *i2c)
+{
+	struct rt5663_priv *rt5663 = i2c_get_clientdata(i2c);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, rt5663);
+
+	return 0;
+}
+
+static void rt5663_i2c_shutdown(struct i2c_client *client)
+{
+	struct rt5663_priv *rt5663 = i2c_get_clientdata(client);
+
+	regmap_write(rt5663->regmap, RT5663_RESET, 0);
+}
+
+static struct i2c_driver rt5663_i2c_driver = {
+	.driver = {
+		.name = "rt5663",
+		.acpi_match_table = ACPI_PTR(rt5663_acpi_match),
+		.of_match_table = of_match_ptr(rt5663_of_match),
+	},
+	.probe = rt5663_i2c_probe,
+	.remove = rt5663_i2c_remove,
+	.shutdown = rt5663_i2c_shutdown,
+	.id_table = rt5663_i2c_id,
+};
+module_i2c_driver(rt5663_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5663 driver");
+MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h
new file mode 100644
index 0000000..794cf3f
--- /dev/null
+++ b/sound/soc/codecs/rt5663.h
@@ -0,0 +1,1131 @@
+/*
+ * rt5663.h  --  RT5663 ALSA SoC audio driver
+ *
+ * Copyright 2016 Realtek Microelectronics
+ * Author: Jack Yu <jack.yu@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5663_H__
+#define __RT5663_H__
+
+#include <sound/rt5663.h>
+
+/* Info */
+#define RT5663_RESET				0x0000
+#define RT5663_VENDOR_ID			0x00fd
+#define RT5663_VENDOR_ID_1			0x00fe
+#define RT5663_VENDOR_ID_2			0x00ff
+
+#define RT5663_LOUT_CTRL			0x0001
+#define RT5663_HP_AMP_2				0x0003
+#define RT5663_MONO_OUT				0x0004
+#define RT5663_MONO_GAIN			0x0007
+
+#define RT5663_AEC_BST				0x000b
+#define RT5663_IN1_IN2				0x000c
+#define RT5663_IN3_IN4				0x000d
+#define RT5663_INL1_INR1			0x000f
+#define RT5663_CBJ_TYPE_2			0x0011
+#define RT5663_CBJ_TYPE_3			0x0012
+#define RT5663_CBJ_TYPE_4			0x0013
+#define RT5663_CBJ_TYPE_5			0x0014
+#define RT5663_CBJ_TYPE_8			0x0017
+
+/* I/O - ADC/DAC/DMIC */
+#define RT5663_DAC3_DIG_VOL			0x001a
+#define RT5663_DAC3_CTRL			0x001b
+#define RT5663_MONO_ADC_DIG_VOL			0x001d
+#define RT5663_STO2_ADC_DIG_VOL			0x001e
+#define RT5663_MONO_ADC_BST_GAIN		0x0020
+#define RT5663_STO2_ADC_BST_GAIN		0x0021
+#define RT5663_SIDETONE_CTRL			0x0024
+/* Mixer - D-D */
+#define RT5663_MONO1_ADC_MIXER			0x0027
+#define RT5663_STO2_ADC_MIXER			0x0028
+#define RT5663_MONO_DAC_MIXER			0x002b
+#define RT5663_DAC2_SRC_CTRL			0x002e
+#define RT5663_IF_3_4_DATA_CTL			0x002f
+#define RT5663_IF_5_DATA_CTL			0x0030
+#define RT5663_PDM_OUT_CTL			0x0031
+#define RT5663_PDM_I2C_DATA_CTL1		0x0032
+#define RT5663_PDM_I2C_DATA_CTL2		0x0033
+#define RT5663_PDM_I2C_DATA_CTL3		0x0034
+#define RT5663_PDM_I2C_DATA_CTL4		0x0035
+
+/*Mixer - Analog*/
+#define RT5663_RECMIX1_NEW			0x003a
+#define RT5663_RECMIX1L_0			0x003b
+#define RT5663_RECMIX1L				0x003c
+#define RT5663_RECMIX1R_0			0x003d
+#define RT5663_RECMIX1R				0x003e
+#define RT5663_RECMIX2_NEW			0x003f
+#define RT5663_RECMIX2_L_2			0x0041
+#define RT5663_RECMIX2_R			0x0042
+#define RT5663_RECMIX2_R_2			0x0043
+#define RT5663_CALIB_REC_LR			0x0044
+#define RT5663_ALC_BK_GAIN			0x0049
+#define RT5663_MONOMIX_GAIN			0x004a
+#define RT5663_MONOMIX_IN_GAIN			0x004b
+#define RT5663_OUT_MIXL_GAIN			0x004d
+#define RT5663_OUT_LMIX_IN_GAIN			0x004e
+#define RT5663_OUT_RMIX_IN_GAIN			0x004f
+#define RT5663_OUT_RMIX_IN_GAIN1		0x0050
+#define RT5663_LOUT_MIXER_CTRL			0x0052
+/* Power */
+#define RT5663_PWR_VOL				0x0067
+
+#define RT5663_ADCDAC_RST			0x006d
+/* Format - ADC/DAC */
+#define RT5663_I2S34_SDP			0x0071
+#define RT5663_I2S5_SDP				0x0072
+
+/* Function - Analog */
+#define RT5663_ASRC_3				0x0085
+#define RT5663_ASRC_6				0x0088
+#define RT5663_ASRC_7				0x0089
+#define RT5663_PLL_TRK_13			0x0099
+#define RT5663_I2S_M_CLK_CTL			0x00a0
+#define RT5663_FDIV_I2S34_M_CLK			0x00a1
+#define RT5663_FDIV_I2S34_M_CLK2		0x00a2
+#define RT5663_FDIV_I2S5_M_CLK			0x00a3
+#define RT5663_FDIV_I2S5_M_CLK2			0x00a4
+
+/* Function - Digital */
+#define RT5663_V2_IRQ_4				0x00b9
+#define RT5663_GPIO_3				0x00c2
+#define RT5663_GPIO_4				0x00c3
+#define RT5663_GPIO_STA2			0x00c4
+#define RT5663_HP_AMP_DET1			0x00d0
+#define RT5663_HP_AMP_DET2			0x00d1
+#define RT5663_HP_AMP_DET3			0x00d2
+#define RT5663_MID_BD_HP_AMP			0x00d3
+#define RT5663_LOW_BD_HP_AMP			0x00d4
+#define RT5663_SOF_VOL_ZC2			0x00da
+#define RT5663_ADC_STO2_ADJ1			0x00ee
+#define RT5663_ADC_STO2_ADJ2			0x00ef
+/* General Control */
+#define RT5663_A_JD_CTRL			0x00f0
+#define RT5663_JD1_TRES_CTRL			0x00f1
+#define RT5663_JD2_TRES_CTRL			0x00f2
+#define RT5663_V2_JD_CTRL2			0x00f7
+#define RT5663_DUM_REG_2			0x00fb
+#define RT5663_DUM_REG_3			0x00fc
+
+
+#define RT5663_DACADC_DIG_VOL2			0x0101
+#define RT5663_DIG_IN_PIN2			0x0133
+#define RT5663_PAD_DRV_CTL1			0x0136
+#define RT5663_SOF_RAM_DEPOP			0x0138
+#define RT5663_VOL_TEST				0x013f
+#define RT5663_MONO_DYNA_1			0x0170
+#define RT5663_MONO_DYNA_2			0x0171
+#define RT5663_MONO_DYNA_3			0x0172
+#define RT5663_MONO_DYNA_4			0x0173
+#define RT5663_MONO_DYNA_5			0x0174
+#define RT5663_MONO_DYNA_6			0x0175
+#define RT5663_STO1_SIL_DET			0x0190
+#define RT5663_MONOL_SIL_DET			0x0191
+#define RT5663_MONOR_SIL_DET			0x0192
+#define RT5663_STO2_DAC_SIL			0x0193
+#define RT5663_PWR_SAV_CTL1			0x0194
+#define RT5663_PWR_SAV_CTL2			0x0195
+#define RT5663_PWR_SAV_CTL3			0x0196
+#define RT5663_PWR_SAV_CTL4			0x0197
+#define RT5663_PWR_SAV_CTL5			0x0198
+#define RT5663_PWR_SAV_CTL6			0x0199
+#define RT5663_MONO_AMP_CAL1			0x01a0
+#define RT5663_MONO_AMP_CAL2			0x01a1
+#define RT5663_MONO_AMP_CAL3			0x01a2
+#define RT5663_MONO_AMP_CAL4			0x01a3
+#define RT5663_MONO_AMP_CAL5			0x01a4
+#define RT5663_MONO_AMP_CAL6			0x01a5
+#define RT5663_MONO_AMP_CAL7			0x01a6
+#define RT5663_MONO_AMP_CAL_ST1			0x01a7
+#define RT5663_MONO_AMP_CAL_ST2			0x01a8
+#define RT5663_MONO_AMP_CAL_ST3			0x01a9
+#define RT5663_MONO_AMP_CAL_ST4			0x01aa
+#define RT5663_MONO_AMP_CAL_ST5			0x01ab
+#define RT5663_V2_HP_IMP_SEN_13			0x01b9
+#define RT5663_V2_HP_IMP_SEN_14			0x01ba
+#define RT5663_V2_HP_IMP_SEN_6			0x01bb
+#define RT5663_V2_HP_IMP_SEN_7			0x01bc
+#define RT5663_V2_HP_IMP_SEN_8			0x01bd
+#define RT5663_V2_HP_IMP_SEN_9			0x01be
+#define RT5663_V2_HP_IMP_SEN_10			0x01bf
+#define RT5663_HP_LOGIC_3			0x01dc
+#define RT5663_HP_CALIB_ST10			0x01f3
+#define RT5663_HP_CALIB_ST11			0x01f4
+#define RT5663_PRO_REG_TBL_4			0x0203
+#define RT5663_PRO_REG_TBL_5			0x0204
+#define RT5663_PRO_REG_TBL_6			0x0205
+#define RT5663_PRO_REG_TBL_7			0x0206
+#define RT5663_PRO_REG_TBL_8			0x0207
+#define RT5663_PRO_REG_TBL_9			0x0208
+#define RT5663_SAR_ADC_INL_1			0x0210
+#define RT5663_SAR_ADC_INL_2			0x0211
+#define RT5663_SAR_ADC_INL_3			0x0212
+#define RT5663_SAR_ADC_INL_4			0x0213
+#define RT5663_SAR_ADC_INL_5			0x0214
+#define RT5663_SAR_ADC_INL_6			0x0215
+#define RT5663_SAR_ADC_INL_7			0x0216
+#define RT5663_SAR_ADC_INL_8			0x0217
+#define RT5663_SAR_ADC_INL_9			0x0218
+#define RT5663_SAR_ADC_INL_10			0x0219
+#define RT5663_SAR_ADC_INL_11			0x021a
+#define RT5663_SAR_ADC_INL_12			0x021b
+#define RT5663_DRC_CTRL_1			0x02ff
+#define RT5663_DRC1_CTRL_2			0x0301
+#define RT5663_DRC1_CTRL_3			0x0302
+#define RT5663_DRC1_CTRL_4			0x0303
+#define RT5663_DRC1_CTRL_5			0x0304
+#define RT5663_DRC1_CTRL_6			0x0305
+#define RT5663_DRC1_HD_CTRL_1			0x0306
+#define RT5663_DRC1_HD_CTRL_2			0x0307
+#define RT5663_DRC1_PRI_REG_1			0x0310
+#define RT5663_DRC1_PRI_REG_2			0x0311
+#define RT5663_DRC1_PRI_REG_3			0x0312
+#define RT5663_DRC1_PRI_REG_4			0x0313
+#define RT5663_DRC1_PRI_REG_5			0x0314
+#define RT5663_DRC1_PRI_REG_6			0x0315
+#define RT5663_DRC1_PRI_REG_7			0x0316
+#define RT5663_DRC1_PRI_REG_8			0x0317
+#define RT5663_ALC_PGA_CTL_1			0x0330
+#define RT5663_ALC_PGA_CTL_2			0x0331
+#define RT5663_ALC_PGA_CTL_3			0x0332
+#define RT5663_ALC_PGA_CTL_4			0x0333
+#define RT5663_ALC_PGA_CTL_5			0x0334
+#define RT5663_ALC_PGA_CTL_6			0x0335
+#define RT5663_ALC_PGA_CTL_7			0x0336
+#define RT5663_ALC_PGA_CTL_8			0x0337
+#define RT5663_ALC_PGA_REG_1			0x0338
+#define RT5663_ALC_PGA_REG_2			0x0339
+#define RT5663_ALC_PGA_REG_3			0x033a
+#define RT5663_ADC_EQ_RECOV_1			0x03c0
+#define RT5663_ADC_EQ_RECOV_2			0x03c1
+#define RT5663_ADC_EQ_RECOV_3			0x03c2
+#define RT5663_ADC_EQ_RECOV_4			0x03c3
+#define RT5663_ADC_EQ_RECOV_5			0x03c4
+#define RT5663_ADC_EQ_RECOV_6			0x03c5
+#define RT5663_ADC_EQ_RECOV_7			0x03c6
+#define RT5663_ADC_EQ_RECOV_8			0x03c7
+#define RT5663_ADC_EQ_RECOV_9			0x03c8
+#define RT5663_ADC_EQ_RECOV_10			0x03c9
+#define RT5663_ADC_EQ_RECOV_11			0x03ca
+#define RT5663_ADC_EQ_RECOV_12			0x03cb
+#define RT5663_ADC_EQ_RECOV_13			0x03cc
+#define RT5663_VID_HIDDEN			0x03fe
+#define RT5663_VID_CUSTOMER			0x03ff
+#define RT5663_SCAN_MODE			0x07f0
+#define RT5663_I2C_BYPA				0x07fa
+
+/* Headphone Amp Control 2 (0x0003) */
+#define RT5663_EN_DAC_HPO_MASK			(0x1 << 14)
+#define RT5663_EN_DAC_HPO_SHIFT			14
+#define RT5663_EN_DAC_HPO_DIS			(0x0 << 14)
+#define RT5663_EN_DAC_HPO_EN			(0x1 << 14)
+
+/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/
+#define RT5663_GAIN_HP				(0x1f << 8)
+#define RT5663_GAIN_HP_SHIFT			8
+
+/* AEC BST Control (0x000b) */
+#define RT5663_GAIN_CBJ_MASK			(0xf << 8)
+#define RT5663_GAIN_CBJ_SHIFT			8
+
+/* IN1 Control / MIC GND REF (0x000c) */
+#define RT5663_IN1_DF_MASK			(0x1 << 15)
+#define RT5663_IN1_DF_SHIFT			15
+
+/* Combo Jack and Type Detection Control 1 (0x0010) */
+#define RT5663_CBJ_DET_MASK			(0x1 << 15)
+#define RT5663_CBJ_DET_SHIFT			15
+#define RT5663_CBJ_DET_DIS			(0x0 << 15)
+#define RT5663_CBJ_DET_EN			(0x1 << 15)
+#define RT5663_DET_TYPE_MASK			(0x1 << 12)
+#define RT5663_DET_TYPE_SHIFT			12
+#define RT5663_DET_TYPE_WLCSP			(0x0 << 12)
+#define RT5663_DET_TYPE_QFN			(0x1 << 12)
+#define RT5663_VREF_BIAS_MASK			(0x1 << 6)
+#define RT5663_VREF_BIAS_SHIFT			6
+#define RT5663_VREF_BIAS_FSM			(0x0 << 6)
+#define RT5663_VREF_BIAS_REG			(0x1 << 6)
+
+/* REC Left Mixer Control 2 (0x003c) */
+#define RT5663_RECMIX1L_BST1_CBJ		(0x1 << 7)
+#define RT5663_RECMIX1L_BST1_CBJ_SHIFT		7
+#define RT5663_RECMIX1L_BST2			(0x1 << 4)
+#define RT5663_RECMIX1L_BST2_SHIFT		4
+
+/* REC Right Mixer Control 2 (0x003e) */
+#define RT5663_RECMIX1R_BST2			(0x1 << 4)
+#define RT5663_RECMIX1R_BST2_SHIFT		4
+
+/* DAC1 Digital Volume (0x0019) */
+#define RT5663_DAC_L1_VOL_MASK			(0xff << 8)
+#define RT5663_DAC_L1_VOL_SHIFT			8
+#define RT5663_DAC_R1_VOL_MASK			(0xff)
+#define RT5663_DAC_R1_VOL_SHIFT			0
+
+/* ADC Digital Volume Control (0x001c) */
+#define RT5663_ADC_L_MUTE_MASK			(0x1 << 15)
+#define RT5663_ADC_L_MUTE_SHIFT			15
+#define RT5663_ADC_L_VOL_MASK			(0x7f << 8)
+#define RT5663_ADC_L_VOL_SHIFT			8
+#define RT5663_ADC_R_MUTE_MASK			(0x1 << 7)
+#define RT5663_ADC_R_MUTE_SHIFT			7
+#define RT5663_ADC_R_VOL_MASK			(0x7f)
+#define RT5663_ADC_R_VOL_SHIFT			0
+
+/* Stereo ADC Mixer Control (0x0026) */
+#define RT5663_M_STO1_ADC_L1			(0x1 << 15)
+#define RT5663_M_STO1_ADC_L1_SHIFT		15
+#define RT5663_M_STO1_ADC_L2			(0x1 << 14)
+#define RT5663_M_STO1_ADC_L2_SHIFT		14
+#define RT5663_STO1_ADC_L1_SRC			(0x1 << 13)
+#define RT5663_STO1_ADC_L1_SRC_SHIFT		13
+#define RT5663_STO1_ADC_L2_SRC			(0x1 << 12)
+#define RT5663_STO1_ADC_L2_SRC_SHIFT		12
+#define RT5663_STO1_ADC_L_SRC			(0x3 << 10)
+#define RT5663_STO1_ADC_L_SRC_SHIFT		10
+#define RT5663_M_STO1_ADC_R1			(0x1 << 7)
+#define RT5663_M_STO1_ADC_R1_SHIFT		7
+#define RT5663_M_STO1_ADC_R2			(0x1 << 6)
+#define RT5663_M_STO1_ADC_R2_SHIFT		6
+#define RT5663_STO1_ADC_R1_SRC			(0x1 << 5)
+#define RT5663_STO1_ADC_R1_SRC_SHIFT		5
+#define RT5663_STO1_ADC_R2_SRC			(0x1 << 4)
+#define RT5663_STO1_ADC_R2_SRC_SHIFT		4
+#define RT5663_STO1_ADC_R_SRC			(0x3 << 2)
+#define RT5663_STO1_ADC_R_SRC_SHIFT		2
+
+/* ADC Mixer to DAC Mixer Control (0x0029) */
+#define RT5663_M_ADCMIX_L			(0x1 << 15)
+#define RT5663_M_ADCMIX_L_SHIFT			15
+#define RT5663_M_DAC1_L				(0x1 << 14)
+#define RT5663_M_DAC1_L_SHIFT			14
+#define RT5663_M_ADCMIX_R			(0x1 << 7)
+#define RT5663_M_ADCMIX_R_SHIFT			7
+#define RT5663_M_DAC1_R				(0x1 << 6)
+#define RT5663_M_DAC1_R_SHIFT			6
+
+/* Stereo DAC Mixer Control (0x002a) */
+#define RT5663_M_DAC_L1_STO_L			(0x1 << 15)
+#define RT5663_M_DAC_L1_STO_L_SHIFT		15
+#define RT5663_M_DAC_R1_STO_L			(0x1 << 13)
+#define RT5663_M_DAC_R1_STO_L_SHIFT		13
+#define RT5663_M_DAC_L1_STO_R			(0x1 << 7)
+#define RT5663_M_DAC_L1_STO_R_SHIFT		7
+#define RT5663_M_DAC_R1_STO_R			(0x1 << 5)
+#define RT5663_M_DAC_R1_STO_R_SHIFT		5
+
+/* Power Management for Digital 1 (0x0061) */
+#define RT5663_PWR_I2S1				(0x1 << 15)
+#define RT5663_PWR_I2S1_SHIFT			15
+#define RT5663_PWR_DAC_L1			(0x1 << 11)
+#define RT5663_PWR_DAC_L1_SHIFT			11
+#define RT5663_PWR_DAC_R1			(0x1 << 10)
+#define RT5663_PWR_DAC_R1_SHIFT			10
+#define RT5663_PWR_LDO_DACREF_MASK		(0x1 << 8)
+#define RT5663_PWR_LDO_DACREF_SHIFT		8
+#define RT5663_PWR_LDO_DACREF_ON		(0x1 << 8)
+#define RT5663_PWR_LDO_DACREF_DOWN		(0x0 << 8)
+#define RT5663_PWR_LDO_SHIFT			8
+#define RT5663_PWR_ADC_L1			(0x1 << 4)
+#define RT5663_PWR_ADC_L1_SHIFT			4
+#define RT5663_PWR_ADC_R1			(0x1 << 3)
+#define RT5663_PWR_ADC_R1_SHIFT			3
+
+/* Power Management for Digital 2 (0x0062) */
+#define RT5663_PWR_ADC_S1F			(0x1 << 15)
+#define RT5663_PWR_ADC_S1F_SHIFT		15
+#define RT5663_PWR_DAC_S1F			(0x1 << 10)
+#define RT5663_PWR_DAC_S1F_SHIFT		10
+
+/* Power Management for Analog 1 (0x0063) */
+#define RT5663_PWR_VREF1			(0x1 << 15)
+#define RT5663_PWR_VREF1_MASK			(0x1 << 15)
+#define RT5663_PWR_VREF1_SHIFT			15
+#define RT5663_PWR_FV1				(0x1 << 14)
+#define RT5663_PWR_FV1_MASK			(0x1 << 14)
+#define RT5663_PWR_FV1_SHIFT			14
+#define RT5663_PWR_VREF2			(0x1 << 13)
+#define RT5663_PWR_VREF2_MASK			(0x1 << 13)
+#define RT5663_PWR_VREF2_SHIFT			13
+#define RT5663_PWR_FV2				(0x1 << 12)
+#define RT5663_PWR_FV2_MASK			(0x1 << 12)
+#define RT5663_PWR_FV2_SHIFT			12
+#define RT5663_PWR_MB				(0x1 << 9)
+#define RT5663_PWR_MB_MASK			(0x1 << 9)
+#define RT5663_PWR_MB_SHIFT			9
+#define RT5663_AMP_HP_MASK			(0x3 << 2)
+#define RT5663_AMP_HP_SHIFT			2
+#define RT5663_AMP_HP_1X			(0x0 << 2)
+#define RT5663_AMP_HP_3X			(0x1 << 2)
+#define RT5663_AMP_HP_5X			(0x3 << 2)
+#define RT5663_LDO1_DVO_MASK			(0x3)
+#define RT5663_LDO1_DVO_SHIFT			0
+#define RT5663_LDO1_DVO_0_9V			(0x0)
+#define RT5663_LDO1_DVO_1_0V			(0x1)
+#define RT5663_LDO1_DVO_1_2V			(0x2)
+#define RT5663_LDO1_DVO_1_4V			(0x3)
+
+/* Power Management for Analog 2 (0x0064) */
+#define RT5663_PWR_BST1				(0x1 << 15)
+#define RT5663_PWR_BST1_MASK			(0x1 << 15)
+#define RT5663_PWR_BST1_SHIFT			15
+#define RT5663_PWR_BST1_OFF			(0x0 << 15)
+#define RT5663_PWR_BST1_ON			(0x1 << 15)
+#define RT5663_PWR_BST2				(0x1 << 14)
+#define RT5663_PWR_BST2_MASK			(0x1 << 14)
+#define RT5663_PWR_BST2_SHIFT			14
+#define RT5663_PWR_MB1				(0x1 << 11)
+#define RT5663_PWR_MB1_SHIFT			11
+#define RT5663_PWR_MB2				(0x1 << 10)
+#define RT5663_PWR_MB2_SHIFT			10
+#define RT5663_PWR_BST2_OP			(0x1 << 6)
+#define RT5663_PWR_BST2_OP_MASK			(0x1 << 6)
+#define RT5663_PWR_BST2_OP_SHIFT		6
+#define RT5663_PWR_JD1				(0x1 << 3)
+#define RT5663_PWR_JD1_MASK			(0x1 << 3)
+#define RT5663_PWR_JD1_SHIFT			3
+#define RT5663_PWR_JD2				(0x1 << 2)
+#define RT5663_PWR_JD2_MASK			(0x1 << 2)
+#define RT5663_PWR_JD2_SHIFT			2
+#define RT5663_PWR_RECMIX1			(0x1 << 1)
+#define RT5663_PWR_RECMIX1_SHIFT		1
+#define RT5663_PWR_RECMIX2			(0x1)
+#define RT5663_PWR_RECMIX2_SHIFT		0
+
+/* Power Management for Analog 3 (0x0065) */
+#define RT5663_PWR_CBJ_MASK			(0x1 << 9)
+#define RT5663_PWR_CBJ_SHIFT			9
+#define RT5663_PWR_CBJ_OFF			(0x0 << 9)
+#define RT5663_PWR_CBJ_ON			(0x1 << 9)
+#define RT5663_PWR_PLL				(0x1 << 6)
+#define RT5663_PWR_PLL_SHIFT			6
+#define RT5663_PWR_LDO2				(0x1 << 2)
+#define RT5663_PWR_LDO2_SHIFT			2
+
+/* Power Management for Volume (0x0067) */
+#define RT5663_V2_PWR_MIC_DET			(0x1 << 5)
+#define RT5663_V2_PWR_MIC_DET_SHIFT		5
+
+/* MCLK and System Clock Detection Control (0x006b) */
+#define RT5663_EN_ANA_CLK_DET_MASK		(0x1 << 15)
+#define RT5663_EN_ANA_CLK_DET_SHIFT		15
+#define RT5663_EN_ANA_CLK_DET_DIS		(0x0 << 15)
+#define RT5663_EN_ANA_CLK_DET_AUTO		(0x1 << 15)
+#define RT5663_PWR_CLK_DET_MASK			(0x1)
+#define RT5663_PWR_CLK_DET_SHIFT		0
+#define RT5663_PWR_CLK_DET_DIS			(0x0)
+#define RT5663_PWR_CLK_DET_EN			(0x1)
+
+/* I2S1 Audio Serial Data Port Control (0x0070) */
+#define RT5663_I2S_MS_MASK			(0x1 << 15)
+#define RT5663_I2S_MS_SHIFT			15
+#define RT5663_I2S_MS_M				(0x0 << 15)
+#define RT5663_I2S_MS_S				(0x1 << 15)
+#define RT5663_I2S_BP_MASK			(0x1 << 8)
+#define RT5663_I2S_BP_SHIFT			8
+#define RT5663_I2S_BP_NOR			(0x0 << 8)
+#define RT5663_I2S_BP_INV			(0x1 << 8)
+#define RT5663_I2S_DL_MASK			(0x3 << 4)
+#define RT5663_I2S_DL_SHIFT			4
+#define RT5663_I2S_DL_16			(0x0 << 4)
+#define RT5663_I2S_DL_20			(0x1 << 4)
+#define RT5663_I2S_DL_24			(0x2 << 4)
+#define RT5663_I2S_DL_8				(0x3 << 4)
+#define RT5663_I2S_DF_MASK			(0x7)
+#define RT5663_I2S_DF_SHIFT			0
+#define RT5663_I2S_DF_I2S			(0x0)
+#define RT5663_I2S_DF_LEFT			(0x1)
+#define RT5663_I2S_DF_PCM_A			(0x2)
+#define RT5663_I2S_DF_PCM_B			(0x3)
+#define RT5663_I2S_DF_PCM_A_N			(0x6)
+#define RT5663_I2S_DF_PCM_B_N			(0x7)
+
+/* ADC/DAC Clock Control 1 (0x0073) */
+#define RT5663_I2S_PD1_MASK			(0x7 << 12)
+#define RT5663_I2S_PD1_SHIFT			12
+#define RT5663_M_I2S_DIV_MASK			(0x7 << 8)
+#define RT5663_M_I2S_DIV_SHIFT			8
+#define RT5663_CLK_SRC_MASK			(0x3 << 4)
+#define RT5663_CLK_SRC_MCLK			(0x0 << 4)
+#define RT5663_CLK_SRC_PLL_OUT			(0x1 << 4)
+#define RT5663_CLK_SRC_DIV			(0x2 << 4)
+#define RT5663_CLK_SRC_RC			(0x3 << 4)
+#define RT5663_DAC_OSR_MASK			(0x3 << 2)
+#define RT5663_DAC_OSR_SHIFT			2
+#define RT5663_DAC_OSR_128			(0x0 << 2)
+#define RT5663_DAC_OSR_64			(0x1 << 2)
+#define RT5663_DAC_OSR_32			(0x2 << 2)
+#define RT5663_ADC_OSR_MASK			(0x3)
+#define RT5663_ADC_OSR_SHIFT			0
+#define RT5663_ADC_OSR_128			(0x0)
+#define RT5663_ADC_OSR_64			(0x1)
+#define RT5663_ADC_OSR_32			(0x2)
+
+/* TDM1 control 1 (0x0078) */
+#define RT5663_TDM_MODE_MASK			(0x1 << 15)
+#define RT5663_TDM_MODE_SHIFT			15
+#define RT5663_TDM_MODE_I2S			(0x0 << 15)
+#define RT5663_TDM_MODE_TDM			(0x1 << 15)
+#define RT5663_TDM_IN_CH_MASK			(0x3 << 10)
+#define RT5663_TDM_IN_CH_SHIFT			10
+#define RT5663_TDM_IN_CH_2			(0x0 << 10)
+#define RT5663_TDM_IN_CH_4			(0x1 << 10)
+#define RT5663_TDM_IN_CH_6			(0x2 << 10)
+#define RT5663_TDM_IN_CH_8			(0x3 << 10)
+#define RT5663_TDM_OUT_CH_MASK			(0x3 << 8)
+#define RT5663_TDM_OUT_CH_SHIFT			8
+#define RT5663_TDM_OUT_CH_2			(0x0 << 8)
+#define RT5663_TDM_OUT_CH_4			(0x1 << 8)
+#define RT5663_TDM_OUT_CH_6			(0x2 << 8)
+#define RT5663_TDM_OUT_CH_8			(0x3 << 8)
+#define RT5663_TDM_IN_LEN_MASK			(0x3 << 6)
+#define RT5663_TDM_IN_LEN_SHIFT			6
+#define RT5663_TDM_IN_LEN_16			(0x0 << 6)
+#define RT5663_TDM_IN_LEN_20			(0x1 << 6)
+#define RT5663_TDM_IN_LEN_24			(0x2 << 6)
+#define RT5663_TDM_IN_LEN_32			(0x3 << 6)
+#define RT5663_TDM_OUT_LEN_MASK			(0x3 << 4)
+#define RT5663_TDM_OUT_LEN_SHIFT		4
+#define RT5663_TDM_OUT_LEN_16			(0x0 << 4)
+#define RT5663_TDM_OUT_LEN_20			(0x1 << 4)
+#define RT5663_TDM_OUT_LEN_24			(0x2 << 4)
+#define RT5663_TDM_OUT_LEN_32			(0x3 << 4)
+
+/* Global Clock Control (0x0080) */
+#define RT5663_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5663_SCLK_SRC_SHIFT			14
+#define RT5663_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5663_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5663_SCLK_SRC_RCCLK			(0x2 << 14)
+#define RT5663_PLL1_SRC_MASK			(0x7 << 11)
+#define RT5663_PLL1_SRC_SHIFT			11
+#define RT5663_PLL1_SRC_MCLK			(0x0 << 11)
+#define RT5663_PLL1_SRC_BCLK1			(0x1 << 11)
+#define RT5663_V2_PLL1_SRC_MASK			(0x7 << 8)
+#define RT5663_V2_PLL1_SRC_SHIFT		8
+#define RT5663_V2_PLL1_SRC_MCLK			(0x0 << 8)
+#define RT5663_V2_PLL1_SRC_BCLK1		(0x1 << 8)
+#define RT5663_PLL1_PD_MASK			(0x1 << 4)
+#define RT5663_PLL1_PD_SHIFT			4
+
+#define RT5663_PLL_INP_MAX			40000000
+#define RT5663_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x0081) */
+#define RT5663_PLL_N_MAX			0x001ff
+#define RT5663_PLL_N_MASK			(RT5663_PLL_N_MAX << 7)
+#define RT5663_PLL_N_SHIFT			7
+#define RT5663_PLL_K_MAX			0x001f
+#define RT5663_PLL_K_MASK			(RT5663_PLL_K_MAX)
+#define RT5663_PLL_K_SHIFT			0
+
+/* PLL M/N/K Code Control 2 (0x0082) */
+#define RT5663_PLL_M_MAX			0x00f
+#define RT5663_PLL_M_MASK			(RT5663_PLL_M_MAX << 12)
+#define RT5663_PLL_M_SHIFT			12
+#define RT5663_PLL_M_BP				(0x1 << 11)
+#define RT5663_PLL_M_BP_SHIFT			11
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5663_V2_I2S1_ASRC_MASK			(0x1 << 13)
+#define RT5663_V2_I2S1_ASRC_SHIFT			13
+#define RT5663_V2_DAC_STO1_ASRC_MASK		(0x1 << 12)
+#define RT5663_V2_DAC_STO1_ASRC_SHIFT		12
+#define RT5663_V2_ADC_STO1_ASRC_MASK		(0x1 << 4)
+#define RT5663_V2_ADC_STO1_ASRC_SHIFT		4
+
+/* PLL tracking mode 2 (0x0084)*/
+#define RT5663_DA_STO1_TRACK_MASK		(0x7 << 12)
+#define RT5663_DA_STO1_TRACK_SHIFT		12
+#define RT5663_DA_STO1_TRACK_SYSCLK		(0x0 << 12)
+#define RT5663_DA_STO1_TRACK_I2S1		(0x1 << 12)
+
+/* PLL tracking mode 3 (0x0085)*/
+#define RT5663_V2_AD_STO1_TRACK_MASK		(0x7 << 12)
+#define RT5663_V2_AD_STO1_TRACK_SHIFT		12
+#define RT5663_V2_AD_STO1_TRACK_SYSCLK		(0x0 << 12)
+#define RT5663_V2_AD_STO1_TRACK_I2S1		(0x1 << 12)
+
+/* HPOUT Charge pump control 1 (0x0091) */
+#define RT5663_OSW_HP_L_MASK			(0x1 << 11)
+#define RT5663_OSW_HP_L_SHIFT			11
+#define RT5663_OSW_HP_L_EN			(0x1 << 11)
+#define RT5663_OSW_HP_L_DIS			(0x0 << 11)
+#define RT5663_OSW_HP_R_MASK			(0x1 << 10)
+#define RT5663_OSW_HP_R_SHIFT			10
+#define RT5663_OSW_HP_R_EN			(0x1 << 10)
+#define RT5663_OSW_HP_R_DIS			(0x0 << 10)
+#define RT5663_SEL_PM_HP_MASK			(0x3 << 8)
+#define RT5663_SEL_PM_HP_SHIFT			8
+#define RT5663_SEL_PM_HP_0_6			(0x0 << 8)
+#define RT5663_SEL_PM_HP_0_9			(0x1 << 8)
+#define RT5663_SEL_PM_HP_1_8			(0x2 << 8)
+#define RT5663_SEL_PM_HP_HIGH			(0x3 << 8)
+#define RT5663_OVCD_HP_MASK			(0x1 << 2)
+#define RT5663_OVCD_HP_SHIFT			2
+#define RT5663_OVCD_HP_EN			(0x1 << 2)
+#define RT5663_OVCD_HP_DIS			(0x0 << 2)
+
+/* RC Clock Control (0x0094) */
+#define RT5663_DIG_25M_CLK_MASK			(0x1 << 9)
+#define RT5663_DIG_25M_CLK_SHIFT		9
+#define RT5663_DIG_25M_CLK_DIS			(0x0 << 9)
+#define RT5663_DIG_25M_CLK_EN			(0x1 << 9)
+#define RT5663_DIG_1M_CLK_MASK			(0x1 << 8)
+#define RT5663_DIG_1M_CLK_SHIFT			8
+#define RT5663_DIG_1M_CLK_DIS			(0x0 << 8)
+#define RT5663_DIG_1M_CLK_EN			(0x1 << 8)
+
+/* Auto Turn On 1M RC CLK (0x009f) */
+#define RT5663_IRQ_POW_SAV_MASK			(0x1 << 15)
+#define RT5663_IRQ_POW_SAV_SHIFT		15
+#define RT5663_IRQ_POW_SAV_DIS			(0x0 << 15)
+#define RT5663_IRQ_POW_SAV_EN			(0x1 << 15)
+#define RT5663_IRQ_POW_SAV_JD1_MASK		(0x1 << 14)
+#define RT5663_IRQ_POW_SAV_JD1_SHIFT		14
+#define RT5663_IRQ_POW_SAV_JD1_DIS		(0x0 << 14)
+#define RT5663_IRQ_POW_SAV_JD1_EN		(0x1 << 14)
+#define RT5663_IRQ_MANUAL_MASK			(0x1 << 8)
+#define RT5663_IRQ_MANUAL_SHIFT			8
+#define RT5663_IRQ_MANUAL_DIS			(0x0 << 8)
+#define RT5663_IRQ_MANUAL_EN			(0x1 << 8)
+
+/* IRQ Control 1 (0x00b6) */
+#define RT5663_EN_CB_JD_MASK			(0x1 << 3)
+#define RT5663_EN_CB_JD_SHIFT			3
+#define RT5663_EN_CB_JD_EN			(0x1 << 3)
+#define RT5663_EN_CB_JD_DIS			(0x0 << 3)
+
+/* IRQ Control 3 (0x00b8) */
+#define RT5663_V2_EN_IRQ_INLINE_MASK		(0x1 << 6)
+#define RT5663_V2_EN_IRQ_INLINE_SHIFT		6
+#define RT5663_V2_EN_IRQ_INLINE_BYP		(0x0 << 6)
+#define RT5663_V2_EN_IRQ_INLINE_NOR		(0x1 << 6)
+
+/* GPIO Control 1 (0x00c0) */
+#define RT5663_GP1_PIN_MASK			(0x1 << 15)
+#define RT5663_GP1_PIN_SHIFT			15
+#define RT5663_GP1_PIN_GPIO1			(0x0 << 15)
+#define RT5663_GP1_PIN_IRQ			(0x1 << 15)
+
+/* GPIO Control 2 (0x00c1) */
+#define RT5663_GP4_PIN_CONF_MASK		(0x1 << 5)
+#define RT5663_GP4_PIN_CONF_SHIFT		5
+#define RT5663_GP4_PIN_CONF_INPUT		(0x0 << 5)
+#define RT5663_GP4_PIN_CONF_OUTPUT		(0x1 << 5)
+
+/* GPIO Control 2 (0x00c2) */
+#define RT5663_GP8_PIN_CONF_MASK		(0x1 << 13)
+#define RT5663_GP8_PIN_CONF_SHIFT		13
+#define RT5663_GP8_PIN_CONF_INPUT		(0x0 << 13)
+#define RT5663_GP8_PIN_CONF_OUTPUT		(0x1 << 13)
+
+/* 4 Buttons Inline Command Function 1 (0x00df) */
+#define RT5663_4BTN_CLK_DEB_MASK		(0x3 << 2)
+#define RT5663_4BTN_CLK_DEB_SHIFT		2
+#define RT5663_4BTN_CLK_DEB_8MS			(0x0 << 2)
+#define RT5663_4BTN_CLK_DEB_16MS		(0x1 << 2)
+#define RT5663_4BTN_CLK_DEB_32MS		(0x2 << 2)
+#define RT5663_4BTN_CLK_DEB_65MS		(0x3 << 2)
+
+/* Inline Command Function 6 (0x00e0) */
+#define RT5663_EN_4BTN_INL_MASK			(0x1 << 15)
+#define RT5663_EN_4BTN_INL_SHIFT		15
+#define RT5663_EN_4BTN_INL_DIS			(0x0 << 15)
+#define RT5663_EN_4BTN_INL_EN			(0x1 << 15)
+#define RT5663_RESET_4BTN_INL_MASK		(0x1 << 14)
+#define RT5663_RESET_4BTN_INL_SHIFT		14
+#define RT5663_RESET_4BTN_INL_RESET		(0x0 << 14)
+#define RT5663_RESET_4BTN_INL_NOR		(0x1 << 14)
+
+/* Digital Misc Control (0x00fa) */
+#define RT5663_DIG_GATE_CTRL_MASK		0x1
+#define RT5663_DIG_GATE_CTRL_SHIFT		(0)
+#define RT5663_DIG_GATE_CTRL_DIS		0x0
+#define RT5663_DIG_GATE_CTRL_EN			0x1
+
+/* Chopper and Clock control for DAC L (0x013a)*/
+#define RT5663_CKXEN_DAC1_MASK			(0x1 << 13)
+#define RT5663_CKXEN_DAC1_SHIFT			13
+#define RT5663_CKGEN_DAC1_MASK			(0x1 << 12)
+#define RT5663_CKGEN_DAC1_SHIFT			12
+
+/* Chopper and Clock control for ADC (0x013b)*/
+#define RT5663_CKXEN_ADCC_MASK			(0x1 << 13)
+#define RT5663_CKXEN_ADCC_SHIFT			13
+#define RT5663_CKGEN_ADCC_MASK			(0x1 << 12)
+#define RT5663_CKGEN_ADCC_SHIFT			12
+
+/* HP Behavior Logic Control 2 (0x01db) */
+#define RT5663_HP_SIG_SRC1_MASK			(0x3)
+#define RT5663_HP_SIG_SRC1_SHIFT		0
+#define RT5663_HP_SIG_SRC1_HP_DC		(0x0)
+#define RT5663_HP_SIG_SRC1_HP_CALIB		(0x1)
+#define RT5663_HP_SIG_SRC1_REG			(0x2)
+#define RT5663_HP_SIG_SRC1_SILENCE		(0x3)
+
+/* RT5663 specific register */
+#define RT5663_HP_OUT_EN			0x0002
+#define RT5663_HP_LCH_DRE			0x0005
+#define RT5663_HP_RCH_DRE			0x0006
+#define RT5663_CALIB_BST			0x000a
+#define RT5663_RECMIX				0x0010
+#define RT5663_SIL_DET_CTL			0x0015
+#define RT5663_PWR_SAV_SILDET			0x0016
+#define RT5663_SIDETONE_CTL			0x0018
+#define RT5663_STO1_DAC_DIG_VOL			0x0019
+#define RT5663_STO1_ADC_DIG_VOL			0x001c
+#define RT5663_STO1_BOOST			0x001f
+#define RT5663_HP_IMP_GAIN_1			0x0022
+#define RT5663_HP_IMP_GAIN_2			0x0023
+#define RT5663_STO1_ADC_MIXER			0x0026
+#define RT5663_AD_DA_MIXER			0x0029
+#define RT5663_STO_DAC_MIXER			0x002a
+#define RT5663_DIG_SIDE_MIXER			0x002c
+#define RT5663_BYPASS_STO_DAC			0x002d
+#define RT5663_CALIB_REC_MIX			0x0040
+#define RT5663_PWR_DIG_1			0x0061
+#define RT5663_PWR_DIG_2			0x0062
+#define RT5663_PWR_ANLG_1			0x0063
+#define RT5663_PWR_ANLG_2			0x0064
+#define RT5663_PWR_ANLG_3			0x0065
+#define RT5663_PWR_MIXER			0x0066
+#define RT5663_SIG_CLK_DET			0x006b
+#define RT5663_PRE_DIV_GATING_1			0x006e
+#define RT5663_PRE_DIV_GATING_2			0x006f
+#define RT5663_I2S1_SDP				0x0070
+#define RT5663_ADDA_CLK_1			0x0073
+#define RT5663_ADDA_RST				0x0074
+#define RT5663_FRAC_DIV_1			0x0075
+#define RT5663_FRAC_DIV_2			0x0076
+#define RT5663_TDM_1				0x0077
+#define RT5663_TDM_2				0x0078
+#define RT5663_TDM_3				0x0079
+#define RT5663_TDM_4				0x007a
+#define RT5663_TDM_5				0x007b
+#define RT5663_TDM_6				0x007c
+#define RT5663_TDM_7				0x007d
+#define RT5663_TDM_8				0x007e
+#define RT5663_TDM_9				0x007f
+#define RT5663_GLB_CLK				0x0080
+#define RT5663_PLL_1				0x0081
+#define RT5663_PLL_2				0x0082
+#define RT5663_ASRC_1				0x0083
+#define RT5663_ASRC_2				0x0084
+#define RT5663_ASRC_4				0x0086
+#define RT5663_DUMMY_REG			0x0087
+#define RT5663_ASRC_8				0x008a
+#define RT5663_ASRC_9				0x008b
+#define RT5663_ASRC_11				0x008c
+#define RT5663_DEPOP_1				0x008e
+#define RT5663_DEPOP_2				0x008f
+#define RT5663_DEPOP_3				0x0090
+#define RT5663_HP_CHARGE_PUMP_1			0x0091
+#define RT5663_HP_CHARGE_PUMP_2			0x0092
+#define RT5663_MICBIAS_1			0x0093
+#define RT5663_RC_CLK				0x0094
+#define RT5663_ASRC_11_2			0x0097
+#define RT5663_DUMMY_REG_2			0x0098
+#define RT5663_REC_PATH_GAIN			0x009a
+#define RT5663_AUTO_1MRC_CLK			0x009f
+#define RT5663_ADC_EQ_1				0x00ae
+#define RT5663_ADC_EQ_2				0x00af
+#define RT5663_IRQ_1				0x00b6
+#define RT5663_IRQ_2				0x00b7
+#define RT5663_IRQ_3				0x00b8
+#define RT5663_IRQ_4				0x00ba
+#define RT5663_IRQ_5				0x00bb
+#define RT5663_INT_ST_1				0x00be
+#define RT5663_INT_ST_2				0x00bf
+#define RT5663_GPIO_1				0x00c0
+#define RT5663_GPIO_2				0x00c1
+#define RT5663_GPIO_STA1			0x00c5
+#define RT5663_SIN_GEN_1			0x00cb
+#define RT5663_SIN_GEN_2			0x00cc
+#define RT5663_SIN_GEN_3			0x00cd
+#define RT5663_SOF_VOL_ZC1			0x00d9
+#define RT5663_IL_CMD_1				0x00db
+#define RT5663_IL_CMD_2				0x00dc
+#define RT5663_IL_CMD_3				0x00dd
+#define RT5663_IL_CMD_4				0x00de
+#define RT5663_IL_CMD_5				0x00df
+#define RT5663_IL_CMD_6				0x00e0
+#define RT5663_IL_CMD_7				0x00e1
+#define RT5663_IL_CMD_8				0x00e2
+#define RT5663_IL_CMD_PWRSAV1			0x00e4
+#define RT5663_IL_CMD_PWRSAV2			0x00e5
+#define RT5663_EM_JACK_TYPE_1			0x00e6
+#define RT5663_EM_JACK_TYPE_2			0x00e7
+#define RT5663_EM_JACK_TYPE_3			0x00e8
+#define RT5663_EM_JACK_TYPE_4			0x00e9
+#define RT5663_EM_JACK_TYPE_5			0x00ea
+#define RT5663_EM_JACK_TYPE_6			0x00eb
+#define RT5663_STO1_HPF_ADJ1			0x00ec
+#define RT5663_STO1_HPF_ADJ2			0x00ed
+#define RT5663_FAST_OFF_MICBIAS			0x00f4
+#define RT5663_JD_CTRL1				0x00f6
+#define RT5663_JD_CTRL2				0x00f8
+#define RT5663_DIG_MISC				0x00fa
+#define RT5663_DIG_VOL_ZCD			0x0100
+#define RT5663_ANA_BIAS_CUR_1			0x0108
+#define RT5663_ANA_BIAS_CUR_2			0x0109
+#define RT5663_ANA_BIAS_CUR_3			0x010a
+#define RT5663_ANA_BIAS_CUR_4			0x010b
+#define RT5663_ANA_BIAS_CUR_5			0x010c
+#define RT5663_ANA_BIAS_CUR_6			0x010d
+#define RT5663_BIAS_CUR_5			0x010e
+#define RT5663_BIAS_CUR_6			0x010f
+#define RT5663_BIAS_CUR_7			0x0110
+#define RT5663_BIAS_CUR_8			0x0111
+#define RT5663_DACREF_LDO			0x0112
+#define RT5663_DUMMY_REG_3			0x0113
+#define RT5663_BIAS_CUR_9			0x0114
+#define RT5663_DUMMY_REG_4			0x0116
+#define RT5663_VREFADJ_OP			0x0117
+#define RT5663_VREF_RECMIX			0x0118
+#define RT5663_CHARGE_PUMP_1			0x0125
+#define RT5663_CHARGE_PUMP_1_2			0x0126
+#define RT5663_CHARGE_PUMP_1_3			0x0127
+#define RT5663_CHARGE_PUMP_2			0x0128
+#define RT5663_DIG_IN_PIN1			0x0132
+#define RT5663_PAD_DRV_CTL			0x0137
+#define RT5663_PLL_INT_REG			0x0139
+#define RT5663_CHOP_DAC_L			0x013a
+#define RT5663_CHOP_ADC				0x013b
+#define RT5663_CALIB_ADC			0x013c
+#define RT5663_CHOP_DAC_R			0x013d
+#define RT5663_DUMMY_CTL_DACLR			0x013e
+#define RT5663_DUMMY_REG_5			0x0140
+#define RT5663_SOFT_RAMP			0x0141
+#define RT5663_TEST_MODE_1			0x0144
+#define RT5663_TEST_MODE_2			0x0145
+#define RT5663_TEST_MODE_3			0x0146
+#define RT5663_TEST_MODE_4			0x0147
+#define RT5663_TEST_MODE_5			0x0148
+#define RT5663_STO_DRE_1			0x0160
+#define RT5663_STO_DRE_2			0x0161
+#define RT5663_STO_DRE_3			0x0162
+#define RT5663_STO_DRE_4			0x0163
+#define RT5663_STO_DRE_5			0x0164
+#define RT5663_STO_DRE_6			0x0165
+#define RT5663_STO_DRE_7			0x0166
+#define RT5663_STO_DRE_8			0x0167
+#define RT5663_STO_DRE_9			0x0168
+#define RT5663_STO_DRE_10			0x0169
+#define RT5663_MIC_DECRO_1			0x0180
+#define RT5663_MIC_DECRO_2			0x0181
+#define RT5663_MIC_DECRO_3			0x0182
+#define RT5663_MIC_DECRO_4			0x0183
+#define RT5663_MIC_DECRO_5			0x0184
+#define RT5663_MIC_DECRO_6			0x0185
+#define RT5663_HP_DECRO_1			0x01b0
+#define RT5663_HP_DECRO_2			0x01b1
+#define RT5663_HP_DECRO_3			0x01b2
+#define RT5663_HP_DECRO_4			0x01b3
+#define RT5663_HP_DECOUP			0x01b4
+#define RT5663_HP_IMP_SEN_MAP8			0x01b5
+#define RT5663_HP_IMP_SEN_MAP9			0x01b6
+#define RT5663_HP_IMP_SEN_MAP10			0x01b7
+#define RT5663_HP_IMP_SEN_MAP11			0x01b8
+#define RT5663_HP_IMP_SEN_1			0x01c0
+#define RT5663_HP_IMP_SEN_2			0x01c1
+#define RT5663_HP_IMP_SEN_3			0x01c2
+#define RT5663_HP_IMP_SEN_4			0x01c3
+#define RT5663_HP_IMP_SEN_5			0x01c4
+#define RT5663_HP_IMP_SEN_6			0x01c5
+#define RT5663_HP_IMP_SEN_7			0x01c6
+#define RT5663_HP_IMP_SEN_8			0x01c7
+#define RT5663_HP_IMP_SEN_9			0x01c8
+#define RT5663_HP_IMP_SEN_10			0x01c9
+#define RT5663_HP_IMP_SEN_11			0x01ca
+#define RT5663_HP_IMP_SEN_12			0x01cb
+#define RT5663_HP_IMP_SEN_13			0x01cc
+#define RT5663_HP_IMP_SEN_14			0x01cd
+#define RT5663_HP_IMP_SEN_15			0x01ce
+#define RT5663_HP_IMP_SEN_16			0x01cf
+#define RT5663_HP_IMP_SEN_17			0x01d0
+#define RT5663_HP_IMP_SEN_18			0x01d1
+#define RT5663_HP_IMP_SEN_19			0x01d2
+#define RT5663_HP_IMPSEN_DIG5			0x01d3
+#define RT5663_HP_IMPSEN_MAP1			0x01d4
+#define RT5663_HP_IMPSEN_MAP2			0x01d5
+#define RT5663_HP_IMPSEN_MAP3			0x01d6
+#define RT5663_HP_IMPSEN_MAP4			0x01d7
+#define RT5663_HP_IMPSEN_MAP5			0x01d8
+#define RT5663_HP_IMPSEN_MAP7			0x01d9
+#define RT5663_HP_LOGIC_1			0x01da
+#define RT5663_HP_LOGIC_2			0x01db
+#define RT5663_HP_CALIB_1			0x01dd
+#define RT5663_HP_CALIB_1_1			0x01de
+#define RT5663_HP_CALIB_2			0x01df
+#define RT5663_HP_CALIB_3			0x01e0
+#define RT5663_HP_CALIB_4			0x01e1
+#define RT5663_HP_CALIB_5			0x01e2
+#define RT5663_HP_CALIB_5_1			0x01e3
+#define RT5663_HP_CALIB_6			0x01e4
+#define RT5663_HP_CALIB_7			0x01e5
+#define RT5663_HP_CALIB_9			0x01e6
+#define RT5663_HP_CALIB_10			0x01e7
+#define RT5663_HP_CALIB_11			0x01e8
+#define RT5663_HP_CALIB_ST1			0x01ea
+#define RT5663_HP_CALIB_ST2			0x01eb
+#define RT5663_HP_CALIB_ST3			0x01ec
+#define RT5663_HP_CALIB_ST4			0x01ed
+#define RT5663_HP_CALIB_ST5			0x01ee
+#define RT5663_HP_CALIB_ST6			0x01ef
+#define RT5663_HP_CALIB_ST7			0x01f0
+#define RT5663_HP_CALIB_ST8			0x01f1
+#define RT5663_HP_CALIB_ST9			0x01f2
+#define RT5663_HP_AMP_DET			0x0200
+#define RT5663_DUMMY_REG_6			0x0201
+#define RT5663_HP_BIAS				0x0202
+#define RT5663_CBJ_1				0x0250
+#define RT5663_CBJ_2				0x0251
+#define RT5663_CBJ_3				0x0252
+#define RT5663_DUMMY_1				0x02fa
+#define RT5663_DUMMY_2				0x02fb
+#define RT5663_DUMMY_3				0x02fc
+#define RT5663_ANA_JD				0x0300
+#define RT5663_ADC_LCH_LPF1_A1			0x03d0
+#define RT5663_ADC_RCH_LPF1_A1			0x03d1
+#define RT5663_ADC_LCH_LPF1_H0			0x03d2
+#define RT5663_ADC_RCH_LPF1_H0			0x03d3
+#define RT5663_ADC_LCH_BPF1_A1			0x03d4
+#define RT5663_ADC_RCH_BPF1_A1			0x03d5
+#define RT5663_ADC_LCH_BPF1_A2			0x03d6
+#define RT5663_ADC_RCH_BPF1_A2			0x03d7
+#define RT5663_ADC_LCH_BPF1_H0			0x03d8
+#define RT5663_ADC_RCH_BPF1_H0			0x03d9
+#define RT5663_ADC_LCH_BPF2_A1			0x03da
+#define RT5663_ADC_RCH_BPF2_A1			0x03db
+#define RT5663_ADC_LCH_BPF2_A2			0x03dc
+#define RT5663_ADC_RCH_BPF2_A2			0x03dd
+#define RT5663_ADC_LCH_BPF2_H0			0x03de
+#define RT5663_ADC_RCH_BPF2_H0			0x03df
+#define RT5663_ADC_LCH_BPF3_A1			0x03e0
+#define RT5663_ADC_RCH_BPF3_A1			0x03e1
+#define RT5663_ADC_LCH_BPF3_A2			0x03e2
+#define RT5663_ADC_RCH_BPF3_A2			0x03e3
+#define RT5663_ADC_LCH_BPF3_H0			0x03e4
+#define RT5663_ADC_RCH_BPF3_H0			0x03e5
+#define RT5663_ADC_LCH_BPF4_A1			0x03e6
+#define RT5663_ADC_RCH_BPF4_A1			0x03e7
+#define RT5663_ADC_LCH_BPF4_A2			0x03e8
+#define RT5663_ADC_RCH_BPF4_A2			0x03e9
+#define RT5663_ADC_LCH_BPF4_H0			0x03ea
+#define RT5663_ADC_RCH_BPF4_H0			0x03eb
+#define RT5663_ADC_LCH_HPF1_A1			0x03ec
+#define RT5663_ADC_RCH_HPF1_A1			0x03ed
+#define RT5663_ADC_LCH_HPF1_H0			0x03ee
+#define RT5663_ADC_RCH_HPF1_H0			0x03ef
+#define RT5663_ADC_EQ_PRE_VOL_L			0x03f0
+#define RT5663_ADC_EQ_PRE_VOL_R			0x03f1
+#define RT5663_ADC_EQ_POST_VOL_L		0x03f2
+#define RT5663_ADC_EQ_POST_VOL_R		0x03f3
+
+/* RECMIX Control (0x0010) */
+#define RT5663_RECMIX1_BST1_MASK		(0x1)
+#define RT5663_RECMIX1_BST1_SHIFT		0
+#define RT5663_RECMIX1_BST1_ON			(0x0)
+#define RT5663_RECMIX1_BST1_OFF			(0x1)
+
+/* Bypass Stereo1 DAC Mixer Control (0x002d) */
+#define RT5663_DACL1_SRC_MASK			(0x1 << 3)
+#define RT5663_DACL1_SRC_SHIFT			3
+#define RT5663_DACR1_SRC_MASK			(0x1 << 2)
+#define RT5663_DACR1_SRC_SHIFT			2
+
+/* TDM control 2 (0x0078) */
+#define RT5663_DATA_SWAP_ADCDAT1_MASK		(0x3 << 14)
+#define RT5663_DATA_SWAP_ADCDAT1_SHIFT		14
+#define RT5663_DATA_SWAP_ADCDAT1_LR		(0x0 << 14)
+#define RT5663_DATA_SWAP_ADCDAT1_RL		(0x1 << 14)
+#define RT5663_DATA_SWAP_ADCDAT1_LL		(0x2 << 14)
+#define RT5663_DATA_SWAP_ADCDAT1_RR		(0x3 << 14)
+
+/* TDM control 5 (0x007b) */
+#define RT5663_TDM_LENGTN_MASK			(0x3)
+#define RT5663_TDM_LENGTN_SHIFT			0
+#define RT5663_TDM_LENGTN_16			(0x0)
+#define RT5663_TDM_LENGTN_20			(0x1)
+#define RT5663_TDM_LENGTN_24			(0x2)
+#define RT5663_TDM_LENGTN_32			(0x3)
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5663_I2S1_ASRC_MASK			(0x1 << 11)
+#define RT5663_I2S1_ASRC_SHIFT			11
+#define RT5663_DAC_STO1_ASRC_MASK		(0x1 << 10)
+#define RT5663_DAC_STO1_ASRC_SHIFT		10
+#define RT5663_ADC_STO1_ASRC_MASK		(0x1 << 3)
+#define RT5663_ADC_STO1_ASRC_SHIFT		3
+
+/* PLL tracking mode 2 (0x0084)*/
+#define RT5663_DA_STO1_TRACK_MASK		(0x7 << 12)
+#define RT5663_DA_STO1_TRACK_SHIFT		12
+#define RT5663_DA_STO1_TRACK_SYSCLK		(0x0 << 12)
+#define RT5663_DA_STO1_TRACK_I2S1		(0x1 << 12)
+#define RT5663_AD_STO1_TRACK_MASK		(0x7)
+#define RT5663_AD_STO1_TRACK_SHIFT		0
+#define RT5663_AD_STO1_TRACK_SYSCLK		(0x0)
+#define RT5663_AD_STO1_TRACK_I2S1		(0x1)
+
+/* HPOUT Charge pump control 1 (0x0091) */
+#define RT5663_SI_HP_MASK			(0x1 << 12)
+#define RT5663_SI_HP_SHIFT			12
+#define RT5663_SI_HP_EN				(0x1 << 12)
+#define RT5663_SI_HP_DIS			(0x0 << 12)
+
+/* GPIO Control 2 (0x00b6) */
+#define RT5663_GP1_PIN_CONF_MASK		(0x1 << 2)
+#define RT5663_GP1_PIN_CONF_SHIFT		2
+#define RT5663_GP1_PIN_CONF_OUTPUT		(0x1 << 2)
+#define RT5663_GP1_PIN_CONF_INPUT		(0x0 << 2)
+
+/* GPIO Control 2 (0x00b7) */
+#define RT5663_EN_IRQ_INLINE_MASK		(0x1 << 3)
+#define RT5663_EN_IRQ_INLINE_SHIFT		3
+#define RT5663_EN_IRQ_INLINE_NOR		(0x1 << 3)
+#define RT5663_EN_IRQ_INLINE_BYP		(0x0 << 3)
+
+/* GPIO Control 1 (0x00c0) */
+#define RT5663_GPIO1_TYPE_MASK			(0x1 << 15)
+#define RT5663_GPIO1_TYPE_SHIFT			15
+#define RT5663_GPIO1_TYPE_EN			(0x1 << 15)
+#define RT5663_GPIO1_TYPE_DIS			(0x0 << 15)
+
+/* IRQ Control 1 (0x00c1) */
+#define RT5663_EN_IRQ_JD1_MASK			(0x1 << 6)
+#define RT5663_EN_IRQ_JD1_SHIFT			6
+#define RT5663_EN_IRQ_JD1_EN			(0x1 << 6)
+#define RT5663_EN_IRQ_JD1_DIS			(0x0 << 6)
+#define RT5663_SEL_GPIO1_MASK			(0x1 << 2)
+#define RT5663_SEL_GPIO1_SHIFT			6
+#define RT5663_SEL_GPIO1_EN			(0x1 << 2)
+#define RT5663_SEL_GPIO1_DIS			(0x0 << 2)
+
+/* Inline Command Function 2 (0x00dc) */
+#define RT5663_PWR_MIC_DET_MASK			(0x1)
+#define RT5663_PWR_MIC_DET_SHIFT		0
+#define RT5663_PWR_MIC_DET_ON			(0x1)
+#define RT5663_PWR_MIC_DET_OFF			(0x0)
+
+/* Embeeded Jack and Type Detection Control 1 (0x00e6)*/
+#define RT5663_CBJ_DET_MASK			(0x1 << 15)
+#define RT5663_CBJ_DET_SHIFT			15
+#define RT5663_CBJ_DET_DIS			(0x0 << 15)
+#define RT5663_CBJ_DET_EN			(0x1 << 15)
+#define RT5663_EXT_JD_MASK			(0x1 << 11)
+#define RT5663_EXT_JD_SHIFT			11
+#define RT5663_EXT_JD_EN			(0x1 << 11)
+#define RT5663_EXT_JD_DIS			(0x0 << 11)
+#define RT5663_POL_EXT_JD_MASK			(0x1 << 10)
+#define RT5663_POL_EXT_JD_SHIFT			10
+#define RT5663_POL_EXT_JD_EN			(0x1 << 10)
+#define RT5663_POL_EXT_JD_DIS			(0x0 << 10)
+#define RT5663_EM_JD_MASK			(0x1 << 7)
+#define RT5663_EM_JD_SHIFT			7
+#define RT5663_EM_JD_NOR			(0x1 << 7)
+#define RT5663_EM_JD_RST			(0x0 << 7)
+
+/* DACREF LDO Control (0x0112)*/
+#define RT5663_PWR_LDO_DACREFL_MASK		(0x1 << 9)
+#define RT5663_PWR_LDO_DACREFL_SHIFT		9
+#define RT5663_PWR_LDO_DACREFR_MASK		(0x1 << 1)
+#define RT5663_PWR_LDO_DACREFR_SHIFT		1
+
+/* Stereo Dynamic Range Enhancement Control 9 (0x0168, 0x0169)*/
+#define RT5663_DRE_GAIN_HP_MASK			(0x1f)
+#define RT5663_DRE_GAIN_HP_SHIFT		0
+
+/* Combo Jack Control (0x0250) */
+#define RT5663_INBUF_CBJ_BST1_MASK		(0x1 << 11)
+#define RT5663_INBUF_CBJ_BST1_SHIFT		11
+#define RT5663_INBUF_CBJ_BST1_ON		(0x1 << 11)
+#define RT5663_INBUF_CBJ_BST1_OFF		(0x0 << 11)
+#define RT5663_CBJ_SENSE_BST1_MASK		(0x1 << 10)
+#define RT5663_CBJ_SENSE_BST1_SHIFT		10
+#define RT5663_CBJ_SENSE_BST1_L			(0x1 << 10)
+#define RT5663_CBJ_SENSE_BST1_R			(0x0 << 10)
+
+/* Combo Jack Control (0x0251) */
+#define RT5663_GAIN_BST1_MASK			(0xf)
+#define RT5663_GAIN_BST1_SHIFT			0
+
+/* Dummy register 1 (0x02fa) */
+#define RT5663_EMB_CLK_MASK			(0x1 << 9)
+#define RT5663_EMB_CLK_SHIFT			9
+#define RT5663_EMB_CLK_EN			(0x1 << 9)
+#define RT5663_EMB_CLK_DIS			(0x0 << 9)
+#define RT5663_HPA_CPL_BIAS_MASK		(0x7 << 6)
+#define RT5663_HPA_CPL_BIAS_SHIFT		6
+#define RT5663_HPA_CPL_BIAS_0_5			(0x0 << 6)
+#define RT5663_HPA_CPL_BIAS_1			(0x1 << 6)
+#define RT5663_HPA_CPL_BIAS_2			(0x2 << 6)
+#define RT5663_HPA_CPL_BIAS_3			(0x3 << 6)
+#define RT5663_HPA_CPL_BIAS_4_1			(0x4 << 6)
+#define RT5663_HPA_CPL_BIAS_4_2			(0x5 << 6)
+#define RT5663_HPA_CPL_BIAS_6			(0x6 << 6)
+#define RT5663_HPA_CPL_BIAS_8			(0x7 << 6)
+#define RT5663_HPA_CPR_BIAS_MASK		(0x7 << 3)
+#define RT5663_HPA_CPR_BIAS_SHIFT		3
+#define RT5663_HPA_CPR_BIAS_0_5			(0x0 << 3)
+#define RT5663_HPA_CPR_BIAS_1			(0x1 << 3)
+#define RT5663_HPA_CPR_BIAS_2			(0x2 << 3)
+#define RT5663_HPA_CPR_BIAS_3			(0x3 << 3)
+#define RT5663_HPA_CPR_BIAS_4_1			(0x4 << 3)
+#define RT5663_HPA_CPR_BIAS_4_2			(0x5 << 3)
+#define RT5663_HPA_CPR_BIAS_6			(0x6 << 3)
+#define RT5663_HPA_CPR_BIAS_8			(0x7 << 3)
+#define RT5663_DUMMY_BIAS_MASK			(0x7)
+#define RT5663_DUMMY_BIAS_SHIFT			0
+#define RT5663_DUMMY_BIAS_0_5			(0x0)
+#define RT5663_DUMMY_BIAS_1			(0x1)
+#define RT5663_DUMMY_BIAS_2			(0x2)
+#define RT5663_DUMMY_BIAS_3			(0x3)
+#define RT5663_DUMMY_BIAS_4_1			(0x4)
+#define RT5663_DUMMY_BIAS_4_2			(0x5)
+#define RT5663_DUMMY_BIAS_6			(0x6)
+#define RT5663_DUMMY_BIAS_8			(0x7)
+
+
+/* System Clock Source */
+enum {
+	RT5663_SCLK_S_MCLK,
+	RT5663_SCLK_S_PLL1,
+	RT5663_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+	RT5663_PLL1_S_MCLK,
+	RT5663_PLL1_S_BCLK1,
+};
+
+enum {
+	RT5663_AIF,
+	RT5663_AIFS,
+};
+
+/* asrc clock source */
+enum {
+	RT5663_CLK_SEL_SYS = 0x0,
+	RT5663_CLK_SEL_I2S1_ASRC = 0x1,
+};
+
+/* filter mask */
+enum {
+	RT5663_DA_STEREO_FILTER = 0x1,
+	RT5663_AD_STEREO_FILTER = 0x2,
+};
+
+int rt5663_sel_asrc_clk_src(struct snd_soc_component *component,
+	unsigned int filter_mask, unsigned int clk_src);
+
+#endif /* __RT5663_H__ */
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
new file mode 100644
index 0000000..6ba99f5
--- /dev/null
+++ b/sound/soc/codecs/rt5665.c
@@ -0,0 +1,4983 @@
+/*
+ * rt5665.c  --  RT5665/RT5658 ALSA SoC audio codec driver
+ *
+ * Copyright 2016 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/rt5665.h>
+
+#include "rl6231.h"
+#include "rt5665.h"
+
+#define RT5665_NUM_SUPPLIES 3
+
+static const char *rt5665_supply_names[RT5665_NUM_SUPPLIES] = {
+	"AVDD",
+	"MICVDD",
+	"VBAT",
+};
+
+struct rt5665_priv {
+	struct snd_soc_component *component;
+	struct rt5665_platform_data pdata;
+	struct regmap *regmap;
+	struct gpio_desc *gpiod_ldo1_en;
+	struct gpio_desc *gpiod_reset;
+	struct snd_soc_jack *hs_jack;
+	struct regulator_bulk_data supplies[RT5665_NUM_SUPPLIES];
+	struct delayed_work jack_detect_work;
+	struct delayed_work calibrate_work;
+	struct delayed_work jd_check_work;
+	struct mutex calibrate_mutex;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5665_AIFS];
+	int bclk[RT5665_AIFS];
+	int master[RT5665_AIFS];
+	int id;
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+	int jack_type;
+	int irq_work_delay_time;
+	unsigned int sar_adc_value;
+	bool calibration_done;
+};
+
+static const struct reg_default rt5665_reg[] = {
+	{0x0000, 0x0000},
+	{0x0001, 0xc8c8},
+	{0x0002, 0x8080},
+	{0x0003, 0x8000},
+	{0x0004, 0xc80a},
+	{0x0005, 0x0000},
+	{0x0006, 0x0000},
+	{0x0007, 0x0000},
+	{0x000a, 0x0000},
+	{0x000b, 0x0000},
+	{0x000c, 0x0000},
+	{0x000d, 0x0000},
+	{0x000f, 0x0808},
+	{0x0010, 0x4040},
+	{0x0011, 0x0000},
+	{0x0012, 0x1404},
+	{0x0013, 0x1000},
+	{0x0014, 0xa00a},
+	{0x0015, 0x0404},
+	{0x0016, 0x0404},
+	{0x0017, 0x0011},
+	{0x0018, 0xafaf},
+	{0x0019, 0xafaf},
+	{0x001a, 0xafaf},
+	{0x001b, 0x0011},
+	{0x001c, 0x2f2f},
+	{0x001d, 0x2f2f},
+	{0x001e, 0x2f2f},
+	{0x001f, 0x0000},
+	{0x0020, 0x0000},
+	{0x0021, 0x0000},
+	{0x0022, 0x5757},
+	{0x0023, 0x0039},
+	{0x0026, 0xc0c0},
+	{0x0027, 0xc0c0},
+	{0x0028, 0xc0c0},
+	{0x0029, 0x8080},
+	{0x002a, 0xaaaa},
+	{0x002b, 0xaaaa},
+	{0x002c, 0xaba8},
+	{0x002d, 0x0000},
+	{0x002e, 0x0000},
+	{0x002f, 0x0000},
+	{0x0030, 0x0000},
+	{0x0031, 0x5000},
+	{0x0032, 0x0000},
+	{0x0033, 0x0000},
+	{0x0034, 0x0000},
+	{0x0035, 0x0000},
+	{0x003a, 0x0000},
+	{0x003b, 0x0000},
+	{0x003c, 0x00ff},
+	{0x003d, 0x0000},
+	{0x003e, 0x00ff},
+	{0x003f, 0x0000},
+	{0x0040, 0x0000},
+	{0x0041, 0x00ff},
+	{0x0042, 0x0000},
+	{0x0043, 0x00ff},
+	{0x0044, 0x0c0c},
+	{0x0049, 0xc00b},
+	{0x004a, 0x0000},
+	{0x004b, 0x031f},
+	{0x004d, 0x0000},
+	{0x004e, 0x001f},
+	{0x004f, 0x0000},
+	{0x0050, 0x001f},
+	{0x0052, 0xf000},
+	{0x0061, 0x0000},
+	{0x0062, 0x0000},
+	{0x0063, 0x003e},
+	{0x0064, 0x0000},
+	{0x0065, 0x0000},
+	{0x0066, 0x003f},
+	{0x0067, 0x0000},
+	{0x006b, 0x0000},
+	{0x006d, 0xff00},
+	{0x006e, 0x2808},
+	{0x006f, 0x000a},
+	{0x0070, 0x8000},
+	{0x0071, 0x8000},
+	{0x0072, 0x8000},
+	{0x0073, 0x7000},
+	{0x0074, 0x7770},
+	{0x0075, 0x0002},
+	{0x0076, 0x0001},
+	{0x0078, 0x00f0},
+	{0x0079, 0x0000},
+	{0x007a, 0x0000},
+	{0x007b, 0x0000},
+	{0x007c, 0x0000},
+	{0x007d, 0x0123},
+	{0x007e, 0x4500},
+	{0x007f, 0x8003},
+	{0x0080, 0x0000},
+	{0x0081, 0x0000},
+	{0x0082, 0x0000},
+	{0x0083, 0x0000},
+	{0x0084, 0x0000},
+	{0x0085, 0x0000},
+	{0x0086, 0x0008},
+	{0x0087, 0x0000},
+	{0x0088, 0x0000},
+	{0x0089, 0x0000},
+	{0x008a, 0x0000},
+	{0x008b, 0x0000},
+	{0x008c, 0x0003},
+	{0x008e, 0x0060},
+	{0x008f, 0x1000},
+	{0x0091, 0x0c26},
+	{0x0092, 0x0073},
+	{0x0093, 0x0000},
+	{0x0094, 0x0080},
+	{0x0098, 0x0000},
+	{0x0099, 0x0000},
+	{0x009a, 0x0007},
+	{0x009f, 0x0000},
+	{0x00a0, 0x0000},
+	{0x00a1, 0x0002},
+	{0x00a2, 0x0001},
+	{0x00a3, 0x0002},
+	{0x00a4, 0x0001},
+	{0x00ae, 0x2040},
+	{0x00af, 0x0000},
+	{0x00b6, 0x0000},
+	{0x00b7, 0x0000},
+	{0x00b8, 0x0000},
+	{0x00b9, 0x0000},
+	{0x00ba, 0x0002},
+	{0x00bb, 0x0000},
+	{0x00be, 0x0000},
+	{0x00c0, 0x0000},
+	{0x00c1, 0x0aaa},
+	{0x00c2, 0xaa80},
+	{0x00c3, 0x0003},
+	{0x00c4, 0x0000},
+	{0x00d0, 0x0000},
+	{0x00d1, 0x2244},
+	{0x00d3, 0x3300},
+	{0x00d4, 0x2200},
+	{0x00d9, 0x0809},
+	{0x00da, 0x0000},
+	{0x00db, 0x0008},
+	{0x00dc, 0x00c0},
+	{0x00dd, 0x6724},
+	{0x00de, 0x3131},
+	{0x00df, 0x0008},
+	{0x00e0, 0x4000},
+	{0x00e1, 0x3131},
+	{0x00e2, 0x600c},
+	{0x00ea, 0xb320},
+	{0x00eb, 0x0000},
+	{0x00ec, 0xb300},
+	{0x00ed, 0x0000},
+	{0x00ee, 0xb320},
+	{0x00ef, 0x0000},
+	{0x00f0, 0x0201},
+	{0x00f1, 0x0ddd},
+	{0x00f2, 0x0ddd},
+	{0x00f6, 0x0000},
+	{0x00f7, 0x0000},
+	{0x00f8, 0x0000},
+	{0x00fa, 0x0000},
+	{0x00fb, 0x0000},
+	{0x00fc, 0x0000},
+	{0x00fd, 0x0000},
+	{0x00fe, 0x10ec},
+	{0x00ff, 0x6451},
+	{0x0100, 0xaaaa},
+	{0x0101, 0x000a},
+	{0x010a, 0xaaaa},
+	{0x010b, 0xa0a0},
+	{0x010c, 0xaeae},
+	{0x010d, 0xaaaa},
+	{0x010e, 0xaaaa},
+	{0x010f, 0xaaaa},
+	{0x0110, 0xe002},
+	{0x0111, 0xa402},
+	{0x0112, 0xaaaa},
+	{0x0113, 0x2000},
+	{0x0117, 0x0f00},
+	{0x0125, 0x0410},
+	{0x0132, 0x0000},
+	{0x0133, 0x0000},
+	{0x0137, 0x5540},
+	{0x0138, 0x3700},
+	{0x0139, 0x79a1},
+	{0x013a, 0x2020},
+	{0x013b, 0x2020},
+	{0x013c, 0x2005},
+	{0x013f, 0x0000},
+	{0x0145, 0x0002},
+	{0x0146, 0x0000},
+	{0x0147, 0x0000},
+	{0x0148, 0x0000},
+	{0x0150, 0x0000},
+	{0x0160, 0x4eff},
+	{0x0161, 0x0080},
+	{0x0162, 0x0200},
+	{0x0163, 0x0800},
+	{0x0164, 0x0000},
+	{0x0165, 0x0000},
+	{0x0166, 0x0000},
+	{0x0167, 0x000f},
+	{0x0170, 0x4e87},
+	{0x0171, 0x0080},
+	{0x0172, 0x0200},
+	{0x0173, 0x0800},
+	{0x0174, 0x00ff},
+	{0x0175, 0x0000},
+	{0x0190, 0x413d},
+	{0x0191, 0x4139},
+	{0x0192, 0x4135},
+	{0x0193, 0x413d},
+	{0x0194, 0x0000},
+	{0x0195, 0x0000},
+	{0x0196, 0x0000},
+	{0x0197, 0x0000},
+	{0x0198, 0x0000},
+	{0x0199, 0x0000},
+	{0x01a0, 0x1e64},
+	{0x01a1, 0x06a3},
+	{0x01a2, 0x0000},
+	{0x01a3, 0x0000},
+	{0x01a4, 0x0000},
+	{0x01a5, 0x0000},
+	{0x01a6, 0x0000},
+	{0x01a7, 0x8000},
+	{0x01a8, 0x0000},
+	{0x01a9, 0x0000},
+	{0x01aa, 0x0000},
+	{0x01ab, 0x0000},
+	{0x01b5, 0x0000},
+	{0x01b6, 0x01c3},
+	{0x01b7, 0x02a0},
+	{0x01b8, 0x03e9},
+	{0x01b9, 0x1389},
+	{0x01ba, 0xc351},
+	{0x01bb, 0x0009},
+	{0x01bc, 0x0018},
+	{0x01bd, 0x002a},
+	{0x01be, 0x004c},
+	{0x01bf, 0x0097},
+	{0x01c0, 0x433d},
+	{0x01c1, 0x0000},
+	{0x01c2, 0x0000},
+	{0x01c3, 0x0000},
+	{0x01c4, 0x0000},
+	{0x01c5, 0x0000},
+	{0x01c6, 0x0000},
+	{0x01c7, 0x0000},
+	{0x01c8, 0x40af},
+	{0x01c9, 0x0702},
+	{0x01ca, 0x0000},
+	{0x01cb, 0x0000},
+	{0x01cc, 0x5757},
+	{0x01cd, 0x5757},
+	{0x01ce, 0x5757},
+	{0x01cf, 0x5757},
+	{0x01d0, 0x5757},
+	{0x01d1, 0x5757},
+	{0x01d2, 0x5757},
+	{0x01d3, 0x5757},
+	{0x01d4, 0x5757},
+	{0x01d5, 0x5757},
+	{0x01d6, 0x003c},
+	{0x01da, 0x0000},
+	{0x01db, 0x0000},
+	{0x01dc, 0x0000},
+	{0x01de, 0x7c00},
+	{0x01df, 0x0320},
+	{0x01e0, 0x06a1},
+	{0x01e1, 0x0000},
+	{0x01e2, 0x0000},
+	{0x01e3, 0x0000},
+	{0x01e4, 0x0000},
+	{0x01e6, 0x0001},
+	{0x01e7, 0x0000},
+	{0x01e8, 0x0000},
+	{0x01ea, 0xbf3f},
+	{0x01eb, 0x0000},
+	{0x01ec, 0x0000},
+	{0x01ed, 0x0000},
+	{0x01ee, 0x0000},
+	{0x01ef, 0x0000},
+	{0x01f0, 0x0000},
+	{0x01f1, 0x0000},
+	{0x01f2, 0x0000},
+	{0x01f3, 0x0000},
+	{0x01f4, 0x0000},
+	{0x0200, 0x0000},
+	{0x0201, 0x0000},
+	{0x0202, 0x0000},
+	{0x0203, 0x0000},
+	{0x0204, 0x0000},
+	{0x0205, 0x0000},
+	{0x0206, 0x0000},
+	{0x0207, 0x0000},
+	{0x0208, 0x0000},
+	{0x0210, 0x60b1},
+	{0x0211, 0xa005},
+	{0x0212, 0x024c},
+	{0x0213, 0xf7ff},
+	{0x0214, 0x024c},
+	{0x0215, 0x0102},
+	{0x0216, 0x00a3},
+	{0x0217, 0x0048},
+	{0x0218, 0xa2c0},
+	{0x0219, 0x0400},
+	{0x021a, 0x00c8},
+	{0x021b, 0x00c0},
+	{0x02ff, 0x0110},
+	{0x0300, 0x001f},
+	{0x0301, 0x032c},
+	{0x0302, 0x5f21},
+	{0x0303, 0x4000},
+	{0x0304, 0x4000},
+	{0x0305, 0x06d5},
+	{0x0306, 0x8000},
+	{0x0307, 0x0700},
+	{0x0310, 0x4560},
+	{0x0311, 0xa4a8},
+	{0x0312, 0x7418},
+	{0x0313, 0x0000},
+	{0x0314, 0x0006},
+	{0x0315, 0xffff},
+	{0x0316, 0xc400},
+	{0x0317, 0x0000},
+	{0x0330, 0x00a6},
+	{0x0331, 0x04c3},
+	{0x0332, 0x27c8},
+	{0x0333, 0xbf50},
+	{0x0334, 0x0045},
+	{0x0335, 0x0007},
+	{0x0336, 0x7418},
+	{0x0337, 0x0501},
+	{0x0338, 0x0000},
+	{0x0339, 0x0010},
+	{0x033a, 0x1010},
+	{0x03c0, 0x7e00},
+	{0x03c1, 0x8000},
+	{0x03c2, 0x8000},
+	{0x03c3, 0x8000},
+	{0x03c4, 0x8000},
+	{0x03c5, 0x8000},
+	{0x03c6, 0x8000},
+	{0x03c7, 0x8000},
+	{0x03c8, 0x8000},
+	{0x03c9, 0x8000},
+	{0x03ca, 0x8000},
+	{0x03cb, 0x8000},
+	{0x03cc, 0x8000},
+	{0x03d0, 0x0000},
+	{0x03d1, 0x0000},
+	{0x03d2, 0x0000},
+	{0x03d3, 0x0000},
+	{0x03d4, 0x2000},
+	{0x03d5, 0x2000},
+	{0x03d6, 0x0000},
+	{0x03d7, 0x0000},
+	{0x03d8, 0x2000},
+	{0x03d9, 0x2000},
+	{0x03da, 0x2000},
+	{0x03db, 0x2000},
+	{0x03dc, 0x0000},
+	{0x03dd, 0x0000},
+	{0x03de, 0x0000},
+	{0x03df, 0x2000},
+	{0x03e0, 0x0000},
+	{0x03e1, 0x0000},
+	{0x03e2, 0x0000},
+	{0x03e3, 0x0000},
+	{0x03e4, 0x0000},
+	{0x03e5, 0x0000},
+	{0x03e6, 0x0000},
+	{0x03e7, 0x0000},
+	{0x03e8, 0x0000},
+	{0x03e9, 0x0000},
+	{0x03ea, 0x0000},
+	{0x03eb, 0x0000},
+	{0x03ec, 0x0000},
+	{0x03ed, 0x0000},
+	{0x03ee, 0x0000},
+	{0x03ef, 0x0000},
+	{0x03f0, 0x0800},
+	{0x03f1, 0x0800},
+	{0x03f2, 0x0800},
+	{0x03f3, 0x0800},
+};
+
+static bool rt5665_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5665_RESET:
+	case RT5665_EJD_CTRL_2:
+	case RT5665_GPIO_STA:
+	case RT5665_INT_ST_1:
+	case RT5665_IL_CMD_1:
+	case RT5665_4BTN_IL_CMD_1:
+	case RT5665_PSV_IL_CMD_1:
+	case RT5665_AJD1_CTRL:
+	case RT5665_JD_CTRL_3:
+	case RT5665_STO_NG2_CTRL_1:
+	case RT5665_SAR_IL_CMD_4:
+	case RT5665_DEVICE_ID:
+	case RT5665_STO1_DAC_SIL_DET ... RT5665_STO2_DAC_SIL_DET:
+	case RT5665_MONO_AMP_CALIB_STA1 ... RT5665_MONO_AMP_CALIB_STA6:
+	case RT5665_HP_IMP_SENS_CTRL_12 ... RT5665_HP_IMP_SENS_CTRL_15:
+	case RT5665_HP_CALIB_STA_1 ... RT5665_HP_CALIB_STA_11:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5665_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5665_RESET:
+	case RT5665_VENDOR_ID:
+	case RT5665_VENDOR_ID_1:
+	case RT5665_DEVICE_ID:
+	case RT5665_LOUT:
+	case RT5665_HP_CTRL_1:
+	case RT5665_HP_CTRL_2:
+	case RT5665_MONO_OUT:
+	case RT5665_HPL_GAIN:
+	case RT5665_HPR_GAIN:
+	case RT5665_MONO_GAIN:
+	case RT5665_CAL_BST_CTRL:
+	case RT5665_CBJ_BST_CTRL:
+	case RT5665_IN1_IN2:
+	case RT5665_IN3_IN4:
+	case RT5665_INL1_INR1_VOL:
+	case RT5665_EJD_CTRL_1:
+	case RT5665_EJD_CTRL_2:
+	case RT5665_EJD_CTRL_3:
+	case RT5665_EJD_CTRL_4:
+	case RT5665_EJD_CTRL_5:
+	case RT5665_EJD_CTRL_6:
+	case RT5665_EJD_CTRL_7:
+	case RT5665_DAC2_CTRL:
+	case RT5665_DAC2_DIG_VOL:
+	case RT5665_DAC1_DIG_VOL:
+	case RT5665_DAC3_DIG_VOL:
+	case RT5665_DAC3_CTRL:
+	case RT5665_STO1_ADC_DIG_VOL:
+	case RT5665_MONO_ADC_DIG_VOL:
+	case RT5665_STO2_ADC_DIG_VOL:
+	case RT5665_STO1_ADC_BOOST:
+	case RT5665_MONO_ADC_BOOST:
+	case RT5665_STO2_ADC_BOOST:
+	case RT5665_HP_IMP_GAIN_1:
+	case RT5665_HP_IMP_GAIN_2:
+	case RT5665_STO1_ADC_MIXER:
+	case RT5665_MONO_ADC_MIXER:
+	case RT5665_STO2_ADC_MIXER:
+	case RT5665_AD_DA_MIXER:
+	case RT5665_STO1_DAC_MIXER:
+	case RT5665_MONO_DAC_MIXER:
+	case RT5665_STO2_DAC_MIXER:
+	case RT5665_A_DAC1_MUX:
+	case RT5665_A_DAC2_MUX:
+	case RT5665_DIG_INF2_DATA:
+	case RT5665_DIG_INF3_DATA:
+	case RT5665_PDM_OUT_CTRL:
+	case RT5665_PDM_DATA_CTRL_1:
+	case RT5665_PDM_DATA_CTRL_2:
+	case RT5665_PDM_DATA_CTRL_3:
+	case RT5665_PDM_DATA_CTRL_4:
+	case RT5665_REC1_GAIN:
+	case RT5665_REC1_L1_MIXER:
+	case RT5665_REC1_L2_MIXER:
+	case RT5665_REC1_R1_MIXER:
+	case RT5665_REC1_R2_MIXER:
+	case RT5665_REC2_GAIN:
+	case RT5665_REC2_L1_MIXER:
+	case RT5665_REC2_L2_MIXER:
+	case RT5665_REC2_R1_MIXER:
+	case RT5665_REC2_R2_MIXER:
+	case RT5665_CAL_REC:
+	case RT5665_ALC_BACK_GAIN:
+	case RT5665_MONOMIX_GAIN:
+	case RT5665_MONOMIX_IN_GAIN:
+	case RT5665_OUT_L_GAIN:
+	case RT5665_OUT_L_MIXER:
+	case RT5665_OUT_R_GAIN:
+	case RT5665_OUT_R_MIXER:
+	case RT5665_LOUT_MIXER:
+	case RT5665_PWR_DIG_1:
+	case RT5665_PWR_DIG_2:
+	case RT5665_PWR_ANLG_1:
+	case RT5665_PWR_ANLG_2:
+	case RT5665_PWR_ANLG_3:
+	case RT5665_PWR_MIXER:
+	case RT5665_PWR_VOL:
+	case RT5665_CLK_DET:
+	case RT5665_HPF_CTRL1:
+	case RT5665_DMIC_CTRL_1:
+	case RT5665_DMIC_CTRL_2:
+	case RT5665_I2S1_SDP:
+	case RT5665_I2S2_SDP:
+	case RT5665_I2S3_SDP:
+	case RT5665_ADDA_CLK_1:
+	case RT5665_ADDA_CLK_2:
+	case RT5665_I2S1_F_DIV_CTRL_1:
+	case RT5665_I2S1_F_DIV_CTRL_2:
+	case RT5665_TDM_CTRL_1:
+	case RT5665_TDM_CTRL_2:
+	case RT5665_TDM_CTRL_3:
+	case RT5665_TDM_CTRL_4:
+	case RT5665_TDM_CTRL_5:
+	case RT5665_TDM_CTRL_6:
+	case RT5665_TDM_CTRL_7:
+	case RT5665_TDM_CTRL_8:
+	case RT5665_GLB_CLK:
+	case RT5665_PLL_CTRL_1:
+	case RT5665_PLL_CTRL_2:
+	case RT5665_ASRC_1:
+	case RT5665_ASRC_2:
+	case RT5665_ASRC_3:
+	case RT5665_ASRC_4:
+	case RT5665_ASRC_5:
+	case RT5665_ASRC_6:
+	case RT5665_ASRC_7:
+	case RT5665_ASRC_8:
+	case RT5665_ASRC_9:
+	case RT5665_ASRC_10:
+	case RT5665_DEPOP_1:
+	case RT5665_DEPOP_2:
+	case RT5665_HP_CHARGE_PUMP_1:
+	case RT5665_HP_CHARGE_PUMP_2:
+	case RT5665_MICBIAS_1:
+	case RT5665_MICBIAS_2:
+	case RT5665_ASRC_12:
+	case RT5665_ASRC_13:
+	case RT5665_ASRC_14:
+	case RT5665_RC_CLK_CTRL:
+	case RT5665_I2S_M_CLK_CTRL_1:
+	case RT5665_I2S2_F_DIV_CTRL_1:
+	case RT5665_I2S2_F_DIV_CTRL_2:
+	case RT5665_I2S3_F_DIV_CTRL_1:
+	case RT5665_I2S3_F_DIV_CTRL_2:
+	case RT5665_EQ_CTRL_1:
+	case RT5665_EQ_CTRL_2:
+	case RT5665_IRQ_CTRL_1:
+	case RT5665_IRQ_CTRL_2:
+	case RT5665_IRQ_CTRL_3:
+	case RT5665_IRQ_CTRL_4:
+	case RT5665_IRQ_CTRL_5:
+	case RT5665_IRQ_CTRL_6:
+	case RT5665_INT_ST_1:
+	case RT5665_GPIO_CTRL_1:
+	case RT5665_GPIO_CTRL_2:
+	case RT5665_GPIO_CTRL_3:
+	case RT5665_GPIO_CTRL_4:
+	case RT5665_GPIO_STA:
+	case RT5665_HP_AMP_DET_CTRL_1:
+	case RT5665_HP_AMP_DET_CTRL_2:
+	case RT5665_MID_HP_AMP_DET:
+	case RT5665_LOW_HP_AMP_DET:
+	case RT5665_SV_ZCD_1:
+	case RT5665_SV_ZCD_2:
+	case RT5665_IL_CMD_1:
+	case RT5665_IL_CMD_2:
+	case RT5665_IL_CMD_3:
+	case RT5665_IL_CMD_4:
+	case RT5665_4BTN_IL_CMD_1:
+	case RT5665_4BTN_IL_CMD_2:
+	case RT5665_4BTN_IL_CMD_3:
+	case RT5665_PSV_IL_CMD_1:
+	case RT5665_ADC_STO1_HP_CTRL_1:
+	case RT5665_ADC_STO1_HP_CTRL_2:
+	case RT5665_ADC_MONO_HP_CTRL_1:
+	case RT5665_ADC_MONO_HP_CTRL_2:
+	case RT5665_ADC_STO2_HP_CTRL_1:
+	case RT5665_ADC_STO2_HP_CTRL_2:
+	case RT5665_AJD1_CTRL:
+	case RT5665_JD1_THD:
+	case RT5665_JD2_THD:
+	case RT5665_JD_CTRL_1:
+	case RT5665_JD_CTRL_2:
+	case RT5665_JD_CTRL_3:
+	case RT5665_DIG_MISC:
+	case RT5665_DUMMY_2:
+	case RT5665_DUMMY_3:
+	case RT5665_DAC_ADC_DIG_VOL1:
+	case RT5665_DAC_ADC_DIG_VOL2:
+	case RT5665_BIAS_CUR_CTRL_1:
+	case RT5665_BIAS_CUR_CTRL_2:
+	case RT5665_BIAS_CUR_CTRL_3:
+	case RT5665_BIAS_CUR_CTRL_4:
+	case RT5665_BIAS_CUR_CTRL_5:
+	case RT5665_BIAS_CUR_CTRL_6:
+	case RT5665_BIAS_CUR_CTRL_7:
+	case RT5665_BIAS_CUR_CTRL_8:
+	case RT5665_BIAS_CUR_CTRL_9:
+	case RT5665_BIAS_CUR_CTRL_10:
+	case RT5665_VREF_REC_OP_FB_CAP_CTRL:
+	case RT5665_CHARGE_PUMP_1:
+	case RT5665_DIG_IN_CTRL_1:
+	case RT5665_DIG_IN_CTRL_2:
+	case RT5665_PAD_DRIVING_CTRL:
+	case RT5665_SOFT_RAMP_DEPOP:
+	case RT5665_PLL:
+	case RT5665_CHOP_DAC:
+	case RT5665_CHOP_ADC:
+	case RT5665_CALIB_ADC_CTRL:
+	case RT5665_VOL_TEST:
+	case RT5665_TEST_MODE_CTRL_1:
+	case RT5665_TEST_MODE_CTRL_2:
+	case RT5665_TEST_MODE_CTRL_3:
+	case RT5665_TEST_MODE_CTRL_4:
+	case RT5665_BASSBACK_CTRL:
+	case RT5665_STO_NG2_CTRL_1:
+	case RT5665_STO_NG2_CTRL_2:
+	case RT5665_STO_NG2_CTRL_3:
+	case RT5665_STO_NG2_CTRL_4:
+	case RT5665_STO_NG2_CTRL_5:
+	case RT5665_STO_NG2_CTRL_6:
+	case RT5665_STO_NG2_CTRL_7:
+	case RT5665_STO_NG2_CTRL_8:
+	case RT5665_MONO_NG2_CTRL_1:
+	case RT5665_MONO_NG2_CTRL_2:
+	case RT5665_MONO_NG2_CTRL_3:
+	case RT5665_MONO_NG2_CTRL_4:
+	case RT5665_MONO_NG2_CTRL_5:
+	case RT5665_MONO_NG2_CTRL_6:
+	case RT5665_STO1_DAC_SIL_DET:
+	case RT5665_MONOL_DAC_SIL_DET:
+	case RT5665_MONOR_DAC_SIL_DET:
+	case RT5665_STO2_DAC_SIL_DET:
+	case RT5665_SIL_PSV_CTRL1:
+	case RT5665_SIL_PSV_CTRL2:
+	case RT5665_SIL_PSV_CTRL3:
+	case RT5665_SIL_PSV_CTRL4:
+	case RT5665_SIL_PSV_CTRL5:
+	case RT5665_SIL_PSV_CTRL6:
+	case RT5665_MONO_AMP_CALIB_CTRL_1:
+	case RT5665_MONO_AMP_CALIB_CTRL_2:
+	case RT5665_MONO_AMP_CALIB_CTRL_3:
+	case RT5665_MONO_AMP_CALIB_CTRL_4:
+	case RT5665_MONO_AMP_CALIB_CTRL_5:
+	case RT5665_MONO_AMP_CALIB_CTRL_6:
+	case RT5665_MONO_AMP_CALIB_CTRL_7:
+	case RT5665_MONO_AMP_CALIB_STA1:
+	case RT5665_MONO_AMP_CALIB_STA2:
+	case RT5665_MONO_AMP_CALIB_STA3:
+	case RT5665_MONO_AMP_CALIB_STA4:
+	case RT5665_MONO_AMP_CALIB_STA6:
+	case RT5665_HP_IMP_SENS_CTRL_01:
+	case RT5665_HP_IMP_SENS_CTRL_02:
+	case RT5665_HP_IMP_SENS_CTRL_03:
+	case RT5665_HP_IMP_SENS_CTRL_04:
+	case RT5665_HP_IMP_SENS_CTRL_05:
+	case RT5665_HP_IMP_SENS_CTRL_06:
+	case RT5665_HP_IMP_SENS_CTRL_07:
+	case RT5665_HP_IMP_SENS_CTRL_08:
+	case RT5665_HP_IMP_SENS_CTRL_09:
+	case RT5665_HP_IMP_SENS_CTRL_10:
+	case RT5665_HP_IMP_SENS_CTRL_11:
+	case RT5665_HP_IMP_SENS_CTRL_12:
+	case RT5665_HP_IMP_SENS_CTRL_13:
+	case RT5665_HP_IMP_SENS_CTRL_14:
+	case RT5665_HP_IMP_SENS_CTRL_15:
+	case RT5665_HP_IMP_SENS_CTRL_16:
+	case RT5665_HP_IMP_SENS_CTRL_17:
+	case RT5665_HP_IMP_SENS_CTRL_18:
+	case RT5665_HP_IMP_SENS_CTRL_19:
+	case RT5665_HP_IMP_SENS_CTRL_20:
+	case RT5665_HP_IMP_SENS_CTRL_21:
+	case RT5665_HP_IMP_SENS_CTRL_22:
+	case RT5665_HP_IMP_SENS_CTRL_23:
+	case RT5665_HP_IMP_SENS_CTRL_24:
+	case RT5665_HP_IMP_SENS_CTRL_25:
+	case RT5665_HP_IMP_SENS_CTRL_26:
+	case RT5665_HP_IMP_SENS_CTRL_27:
+	case RT5665_HP_IMP_SENS_CTRL_28:
+	case RT5665_HP_IMP_SENS_CTRL_29:
+	case RT5665_HP_IMP_SENS_CTRL_30:
+	case RT5665_HP_IMP_SENS_CTRL_31:
+	case RT5665_HP_IMP_SENS_CTRL_32:
+	case RT5665_HP_IMP_SENS_CTRL_33:
+	case RT5665_HP_IMP_SENS_CTRL_34:
+	case RT5665_HP_LOGIC_CTRL_1:
+	case RT5665_HP_LOGIC_CTRL_2:
+	case RT5665_HP_LOGIC_CTRL_3:
+	case RT5665_HP_CALIB_CTRL_1:
+	case RT5665_HP_CALIB_CTRL_2:
+	case RT5665_HP_CALIB_CTRL_3:
+	case RT5665_HP_CALIB_CTRL_4:
+	case RT5665_HP_CALIB_CTRL_5:
+	case RT5665_HP_CALIB_CTRL_6:
+	case RT5665_HP_CALIB_CTRL_7:
+	case RT5665_HP_CALIB_CTRL_9:
+	case RT5665_HP_CALIB_CTRL_10:
+	case RT5665_HP_CALIB_CTRL_11:
+	case RT5665_HP_CALIB_STA_1:
+	case RT5665_HP_CALIB_STA_2:
+	case RT5665_HP_CALIB_STA_3:
+	case RT5665_HP_CALIB_STA_4:
+	case RT5665_HP_CALIB_STA_5:
+	case RT5665_HP_CALIB_STA_6:
+	case RT5665_HP_CALIB_STA_7:
+	case RT5665_HP_CALIB_STA_8:
+	case RT5665_HP_CALIB_STA_9:
+	case RT5665_HP_CALIB_STA_10:
+	case RT5665_HP_CALIB_STA_11:
+	case RT5665_PGM_TAB_CTRL1:
+	case RT5665_PGM_TAB_CTRL2:
+	case RT5665_PGM_TAB_CTRL3:
+	case RT5665_PGM_TAB_CTRL4:
+	case RT5665_PGM_TAB_CTRL5:
+	case RT5665_PGM_TAB_CTRL6:
+	case RT5665_PGM_TAB_CTRL7:
+	case RT5665_PGM_TAB_CTRL8:
+	case RT5665_PGM_TAB_CTRL9:
+	case RT5665_SAR_IL_CMD_1:
+	case RT5665_SAR_IL_CMD_2:
+	case RT5665_SAR_IL_CMD_3:
+	case RT5665_SAR_IL_CMD_4:
+	case RT5665_SAR_IL_CMD_5:
+	case RT5665_SAR_IL_CMD_6:
+	case RT5665_SAR_IL_CMD_7:
+	case RT5665_SAR_IL_CMD_8:
+	case RT5665_SAR_IL_CMD_9:
+	case RT5665_SAR_IL_CMD_10:
+	case RT5665_SAR_IL_CMD_11:
+	case RT5665_SAR_IL_CMD_12:
+	case RT5665_DRC1_CTRL_0:
+	case RT5665_DRC1_CTRL_1:
+	case RT5665_DRC1_CTRL_2:
+	case RT5665_DRC1_CTRL_3:
+	case RT5665_DRC1_CTRL_4:
+	case RT5665_DRC1_CTRL_5:
+	case RT5665_DRC1_CTRL_6:
+	case RT5665_DRC1_HARD_LMT_CTRL_1:
+	case RT5665_DRC1_HARD_LMT_CTRL_2:
+	case RT5665_DRC1_PRIV_1:
+	case RT5665_DRC1_PRIV_2:
+	case RT5665_DRC1_PRIV_3:
+	case RT5665_DRC1_PRIV_4:
+	case RT5665_DRC1_PRIV_5:
+	case RT5665_DRC1_PRIV_6:
+	case RT5665_DRC1_PRIV_7:
+	case RT5665_DRC1_PRIV_8:
+	case RT5665_ALC_PGA_CTRL_1:
+	case RT5665_ALC_PGA_CTRL_2:
+	case RT5665_ALC_PGA_CTRL_3:
+	case RT5665_ALC_PGA_CTRL_4:
+	case RT5665_ALC_PGA_CTRL_5:
+	case RT5665_ALC_PGA_CTRL_6:
+	case RT5665_ALC_PGA_CTRL_7:
+	case RT5665_ALC_PGA_CTRL_8:
+	case RT5665_ALC_PGA_STA_1:
+	case RT5665_ALC_PGA_STA_2:
+	case RT5665_ALC_PGA_STA_3:
+	case RT5665_EQ_AUTO_RCV_CTRL1:
+	case RT5665_EQ_AUTO_RCV_CTRL2:
+	case RT5665_EQ_AUTO_RCV_CTRL3:
+	case RT5665_EQ_AUTO_RCV_CTRL4:
+	case RT5665_EQ_AUTO_RCV_CTRL5:
+	case RT5665_EQ_AUTO_RCV_CTRL6:
+	case RT5665_EQ_AUTO_RCV_CTRL7:
+	case RT5665_EQ_AUTO_RCV_CTRL8:
+	case RT5665_EQ_AUTO_RCV_CTRL9:
+	case RT5665_EQ_AUTO_RCV_CTRL10:
+	case RT5665_EQ_AUTO_RCV_CTRL11:
+	case RT5665_EQ_AUTO_RCV_CTRL12:
+	case RT5665_EQ_AUTO_RCV_CTRL13:
+	case RT5665_ADC_L_EQ_LPF1_A1:
+	case RT5665_R_EQ_LPF1_A1:
+	case RT5665_L_EQ_LPF1_H0:
+	case RT5665_R_EQ_LPF1_H0:
+	case RT5665_L_EQ_BPF1_A1:
+	case RT5665_R_EQ_BPF1_A1:
+	case RT5665_L_EQ_BPF1_A2:
+	case RT5665_R_EQ_BPF1_A2:
+	case RT5665_L_EQ_BPF1_H0:
+	case RT5665_R_EQ_BPF1_H0:
+	case RT5665_L_EQ_BPF2_A1:
+	case RT5665_R_EQ_BPF2_A1:
+	case RT5665_L_EQ_BPF2_A2:
+	case RT5665_R_EQ_BPF2_A2:
+	case RT5665_L_EQ_BPF2_H0:
+	case RT5665_R_EQ_BPF2_H0:
+	case RT5665_L_EQ_BPF3_A1:
+	case RT5665_R_EQ_BPF3_A1:
+	case RT5665_L_EQ_BPF3_A2:
+	case RT5665_R_EQ_BPF3_A2:
+	case RT5665_L_EQ_BPF3_H0:
+	case RT5665_R_EQ_BPF3_H0:
+	case RT5665_L_EQ_BPF4_A1:
+	case RT5665_R_EQ_BPF4_A1:
+	case RT5665_L_EQ_BPF4_A2:
+	case RT5665_R_EQ_BPF4_A2:
+	case RT5665_L_EQ_BPF4_H0:
+	case RT5665_R_EQ_BPF4_H0:
+	case RT5665_L_EQ_HPF1_A1:
+	case RT5665_R_EQ_HPF1_A1:
+	case RT5665_L_EQ_HPF1_H0:
+	case RT5665_R_EQ_HPF1_H0:
+	case RT5665_L_EQ_PRE_VOL:
+	case RT5665_R_EQ_PRE_VOL:
+	case RT5665_L_EQ_POST_VOL:
+	case RT5665_R_EQ_POST_VOL:
+	case RT5665_SCAN_MODE_CTRL:
+	case RT5665_I2C_MODE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(mono_vol_tlv, -1400, 150, 0);
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+static const DECLARE_TLV_DB_SCALE(in_bst_tlv, -1200, 75, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+/* Interface data select */
+static const char * const rt5665_data_select[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5665_if1_1_01_adc_enum,
+	RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT01_SFT, rt5665_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5665_if1_1_23_adc_enum,
+	RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT23_SFT, rt5665_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5665_if1_1_45_adc_enum,
+	RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT45_SFT, rt5665_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5665_if1_1_67_adc_enum,
+	RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT67_SFT, rt5665_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5665_if1_2_01_adc_enum,
+	RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT01_SFT, rt5665_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5665_if1_2_23_adc_enum,
+	RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT23_SFT, rt5665_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5665_if1_2_45_adc_enum,
+	RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT45_SFT, rt5665_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5665_if1_2_67_adc_enum,
+	RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT67_SFT, rt5665_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5665_if2_1_dac_enum,
+	RT5665_DIG_INF2_DATA, RT5665_IF2_1_DAC_SEL_SFT, rt5665_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5665_if2_1_adc_enum,
+	RT5665_DIG_INF2_DATA, RT5665_IF2_1_ADC_SEL_SFT, rt5665_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5665_if2_2_dac_enum,
+	RT5665_DIG_INF2_DATA, RT5665_IF2_2_DAC_SEL_SFT, rt5665_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5665_if2_2_adc_enum,
+	RT5665_DIG_INF2_DATA, RT5665_IF2_2_ADC_SEL_SFT, rt5665_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5665_if3_dac_enum,
+	RT5665_DIG_INF3_DATA, RT5665_IF3_DAC_SEL_SFT, rt5665_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5665_if3_adc_enum,
+	RT5665_DIG_INF3_DATA, RT5665_IF3_ADC_SEL_SFT, rt5665_data_select);
+
+static const struct snd_kcontrol_new rt5665_if1_1_01_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1_1 01 ADC Swap Mux", rt5665_if1_1_01_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if1_1_23_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1_1 23 ADC Swap Mux", rt5665_if1_1_23_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if1_1_45_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1_1 45 ADC Swap Mux", rt5665_if1_1_45_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if1_1_67_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1_1 67 ADC Swap Mux", rt5665_if1_1_67_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if1_2_01_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1_2 01 ADC Swap Mux", rt5665_if1_2_01_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if1_2_23_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1_2 23 ADC1 Swap Mux", rt5665_if1_2_23_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if1_2_45_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1_2 45 ADC1 Swap Mux", rt5665_if1_2_45_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if1_2_67_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1_2 67 ADC1 Swap Mux", rt5665_if1_2_67_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if2_1_dac_swap_mux =
+	SOC_DAPM_ENUM("IF2_1 DAC Swap Source", rt5665_if2_1_dac_enum);
+
+static const struct snd_kcontrol_new rt5665_if2_1_adc_swap_mux =
+	SOC_DAPM_ENUM("IF2_1 ADC Swap Source", rt5665_if2_1_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if2_2_dac_swap_mux =
+	SOC_DAPM_ENUM("IF2_2 DAC Swap Source", rt5665_if2_2_dac_enum);
+
+static const struct snd_kcontrol_new rt5665_if2_2_adc_swap_mux =
+	SOC_DAPM_ENUM("IF2_2 ADC Swap Source", rt5665_if2_2_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if3_dac_swap_mux =
+	SOC_DAPM_ENUM("IF3 DAC Swap Source", rt5665_if3_dac_enum);
+
+static const struct snd_kcontrol_new rt5665_if3_adc_swap_mux =
+	SOC_DAPM_ENUM("IF3 ADC Swap Source", rt5665_if3_adc_enum);
+
+static int rt5665_hp_vol_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+	if (snd_soc_component_read32(component, RT5665_STO_NG2_CTRL_1) & RT5665_NG2_EN) {
+		snd_soc_component_update_bits(component, RT5665_STO_NG2_CTRL_1,
+			RT5665_NG2_EN_MASK, RT5665_NG2_DIS);
+		snd_soc_component_update_bits(component, RT5665_STO_NG2_CTRL_1,
+			RT5665_NG2_EN_MASK, RT5665_NG2_EN);
+	}
+
+	return ret;
+}
+
+static int rt5665_mono_vol_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+	if (snd_soc_component_read32(component, RT5665_MONO_NG2_CTRL_1) & RT5665_NG2_EN) {
+		snd_soc_component_update_bits(component, RT5665_MONO_NG2_CTRL_1,
+			RT5665_NG2_EN_MASK, RT5665_NG2_DIS);
+		snd_soc_component_update_bits(component, RT5665_MONO_NG2_CTRL_1,
+			RT5665_NG2_EN_MASK, RT5665_NG2_EN);
+	}
+
+	return ret;
+}
+
+/**
+ * rt5665_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @component: SoC audio component device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5665 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5665_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src)
+{
+	unsigned int asrc2_mask = 0;
+	unsigned int asrc2_value = 0;
+	unsigned int asrc3_mask = 0;
+	unsigned int asrc3_value = 0;
+
+	switch (clk_src) {
+	case RT5665_CLK_SEL_SYS:
+	case RT5665_CLK_SEL_I2S1_ASRC:
+	case RT5665_CLK_SEL_I2S2_ASRC:
+	case RT5665_CLK_SEL_I2S3_ASRC:
+	case RT5665_CLK_SEL_SYS2:
+	case RT5665_CLK_SEL_SYS3:
+	case RT5665_CLK_SEL_SYS4:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (filter_mask & RT5665_DA_STEREO1_FILTER) {
+		asrc2_mask |= RT5665_DA_STO1_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5665_DA_STO1_CLK_SEL_MASK)
+			| (clk_src << RT5665_DA_STO1_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5665_DA_STEREO2_FILTER) {
+		asrc2_mask |= RT5665_DA_STO2_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5665_DA_STO2_CLK_SEL_MASK)
+			| (clk_src << RT5665_DA_STO2_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5665_DA_MONO_L_FILTER) {
+		asrc2_mask |= RT5665_DA_MONOL_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5665_DA_MONOL_CLK_SEL_MASK)
+			| (clk_src << RT5665_DA_MONOL_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5665_DA_MONO_R_FILTER) {
+		asrc2_mask |= RT5665_DA_MONOR_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5665_DA_MONOR_CLK_SEL_MASK)
+			| (clk_src << RT5665_DA_MONOR_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5665_AD_STEREO1_FILTER) {
+		asrc3_mask |= RT5665_AD_STO1_CLK_SEL_MASK;
+		asrc3_value = (asrc2_value & ~RT5665_AD_STO1_CLK_SEL_MASK)
+			| (clk_src << RT5665_AD_STO1_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5665_AD_STEREO2_FILTER) {
+		asrc3_mask |= RT5665_AD_STO2_CLK_SEL_MASK;
+		asrc3_value = (asrc2_value & ~RT5665_AD_STO2_CLK_SEL_MASK)
+			| (clk_src << RT5665_AD_STO2_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5665_AD_MONO_L_FILTER) {
+		asrc3_mask |= RT5665_AD_MONOL_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5665_AD_MONOL_CLK_SEL_MASK)
+			| (clk_src << RT5665_AD_MONOL_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5665_AD_MONO_R_FILTER)  {
+		asrc3_mask |= RT5665_AD_MONOR_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5665_AD_MONOR_CLK_SEL_MASK)
+			| (clk_src << RT5665_AD_MONOR_CLK_SEL_SFT);
+	}
+
+	if (asrc2_mask)
+		snd_soc_component_update_bits(component, RT5665_ASRC_2,
+			asrc2_mask, asrc2_value);
+
+	if (asrc3_mask)
+		snd_soc_component_update_bits(component, RT5665_ASRC_3,
+			asrc3_mask, asrc3_value);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5665_sel_asrc_clk_src);
+
+static int rt5665_button_detect(struct snd_soc_component *component)
+{
+	int btn_type, val;
+
+	val = snd_soc_component_read32(component, RT5665_4BTN_IL_CMD_1);
+	btn_type = val & 0xfff0;
+	snd_soc_component_write(component, RT5665_4BTN_IL_CMD_1, val);
+
+	return btn_type;
+}
+
+static void rt5665_enable_push_button_irq(struct snd_soc_component *component,
+	bool enable)
+{
+	if (enable) {
+		snd_soc_component_write(component, RT5665_4BTN_IL_CMD_1, 0x0003);
+		snd_soc_component_update_bits(component, RT5665_SAR_IL_CMD_9, 0x1, 0x1);
+		snd_soc_component_write(component, RT5665_IL_CMD_1, 0x0048);
+		snd_soc_component_update_bits(component, RT5665_4BTN_IL_CMD_2,
+				RT5665_4BTN_IL_MASK | RT5665_4BTN_IL_RST_MASK,
+				RT5665_4BTN_IL_EN | RT5665_4BTN_IL_NOR);
+		snd_soc_component_update_bits(component, RT5665_IRQ_CTRL_3,
+				RT5665_IL_IRQ_MASK, RT5665_IL_IRQ_EN);
+	} else {
+		snd_soc_component_update_bits(component, RT5665_IRQ_CTRL_3,
+				RT5665_IL_IRQ_MASK, RT5665_IL_IRQ_DIS);
+		snd_soc_component_update_bits(component, RT5665_4BTN_IL_CMD_2,
+				RT5665_4BTN_IL_MASK, RT5665_4BTN_IL_DIS);
+		snd_soc_component_update_bits(component, RT5665_4BTN_IL_CMD_2,
+				RT5665_4BTN_IL_RST_MASK, RT5665_4BTN_IL_RST);
+	}
+}
+
+/**
+ * rt5665_headset_detect - Detect headset.
+ * @component: SoC audio component device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+static int rt5665_headset_detect(struct snd_soc_component *component, int jack_insert)
+{
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	unsigned int sar_hs_type, val;
+
+	if (jack_insert) {
+		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+		snd_soc_dapm_sync(dapm);
+
+		regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2, 0x100,
+			0x100);
+
+		regmap_read(rt5665->regmap, RT5665_GPIO_STA, &val);
+		if (val & 0x4) {
+			regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1,
+				0x100, 0);
+
+			regmap_read(rt5665->regmap, RT5665_GPIO_STA, &val);
+			while (val & 0x4) {
+				usleep_range(10000, 15000);
+				regmap_read(rt5665->regmap, RT5665_GPIO_STA,
+					&val);
+			}
+		}
+
+		regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1,
+			0x1a0, 0x120);
+		regmap_write(rt5665->regmap, RT5665_EJD_CTRL_3, 0x3424);
+		regmap_write(rt5665->regmap, RT5665_IL_CMD_1, 0x0048);
+		regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1, 0xa291);
+
+		usleep_range(10000, 15000);
+
+		rt5665->sar_adc_value = snd_soc_component_read32(rt5665->component,
+			RT5665_SAR_IL_CMD_4) & 0x7ff;
+
+		sar_hs_type = rt5665->pdata.sar_hs_type ?
+			rt5665->pdata.sar_hs_type : 729;
+
+		if (rt5665->sar_adc_value > sar_hs_type) {
+			rt5665->jack_type = SND_JACK_HEADSET;
+			rt5665_enable_push_button_irq(component, true);
+			} else {
+			rt5665->jack_type = SND_JACK_HEADPHONE;
+			regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1,
+				0x2291);
+			regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2,
+				0x100, 0);
+			snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+			snd_soc_dapm_sync(dapm);
+		}
+	} else {
+		regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1, 0x2291);
+		regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2, 0x100, 0);
+		snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+		snd_soc_dapm_sync(dapm);
+		if (rt5665->jack_type == SND_JACK_HEADSET)
+			rt5665_enable_push_button_irq(component, false);
+		rt5665->jack_type = 0;
+	}
+
+	dev_dbg(component->dev, "jack_type = %d\n", rt5665->jack_type);
+	return rt5665->jack_type;
+}
+
+static irqreturn_t rt5665_irq(int irq, void *data)
+{
+	struct rt5665_priv *rt5665 = data;
+
+	mod_delayed_work(system_power_efficient_wq,
+			   &rt5665->jack_detect_work, msecs_to_jiffies(250));
+
+	return IRQ_HANDLED;
+}
+
+static void rt5665_jd_check_handler(struct work_struct *work)
+{
+	struct rt5665_priv *rt5665 = container_of(work, struct rt5665_priv,
+		jd_check_work.work);
+
+	if (snd_soc_component_read32(rt5665->component, RT5665_AJD1_CTRL) & 0x0010) {
+		/* jack out */
+		rt5665->jack_type = rt5665_headset_detect(rt5665->component, 0);
+
+		snd_soc_jack_report(rt5665->hs_jack, rt5665->jack_type,
+				SND_JACK_HEADSET |
+				SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				SND_JACK_BTN_2 | SND_JACK_BTN_3);
+	} else {
+		schedule_delayed_work(&rt5665->jd_check_work, 500);
+	}
+}
+
+static int rt5665_set_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *hs_jack, void *data)
+{
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
+
+	switch (rt5665->pdata.jd_src) {
+	case RT5665_JD1:
+		regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1,
+			RT5665_GP1_PIN_MASK, RT5665_GP1_PIN_IRQ);
+		regmap_update_bits(rt5665->regmap, RT5665_RC_CLK_CTRL,
+				0xc000, 0xc000);
+		regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_2,
+			RT5665_PWR_JD1, RT5665_PWR_JD1);
+		regmap_update_bits(rt5665->regmap, RT5665_IRQ_CTRL_1, 0x8, 0x8);
+		break;
+
+	case RT5665_JD_NULL:
+		break;
+
+	default:
+		dev_warn(component->dev, "Wrong JD source\n");
+		break;
+	}
+
+	rt5665->hs_jack = hs_jack;
+
+	return 0;
+}
+
+static void rt5665_jack_detect_handler(struct work_struct *work)
+{
+	struct rt5665_priv *rt5665 =
+		container_of(work, struct rt5665_priv, jack_detect_work.work);
+	int val, btn_type;
+
+	while (!rt5665->component) {
+		pr_debug("%s codec = null\n", __func__);
+		usleep_range(10000, 15000);
+	}
+
+	while (!rt5665->component->card->instantiated) {
+		pr_debug("%s\n", __func__);
+		usleep_range(10000, 15000);
+	}
+
+	while (!rt5665->calibration_done) {
+		pr_debug("%s calibration not ready\n", __func__);
+		usleep_range(10000, 15000);
+	}
+
+	mutex_lock(&rt5665->calibrate_mutex);
+
+	val = snd_soc_component_read32(rt5665->component, RT5665_AJD1_CTRL) & 0x0010;
+	if (!val) {
+		/* jack in */
+		if (rt5665->jack_type == 0) {
+			/* jack was out, report jack type */
+			rt5665->jack_type =
+				rt5665_headset_detect(rt5665->component, 1);
+		} else {
+			/* jack is already in, report button event */
+			rt5665->jack_type = SND_JACK_HEADSET;
+			btn_type = rt5665_button_detect(rt5665->component);
+			/**
+			 * rt5665 can report three kinds of button behavior,
+			 * one click, double click and hold. However,
+			 * currently we will report button pressed/released
+			 * event. So all the three button behaviors are
+			 * treated as button pressed.
+			 */
+			switch (btn_type) {
+			case 0x8000:
+			case 0x4000:
+			case 0x2000:
+				rt5665->jack_type |= SND_JACK_BTN_0;
+				break;
+			case 0x1000:
+			case 0x0800:
+			case 0x0400:
+				rt5665->jack_type |= SND_JACK_BTN_1;
+				break;
+			case 0x0200:
+			case 0x0100:
+			case 0x0080:
+				rt5665->jack_type |= SND_JACK_BTN_2;
+				break;
+			case 0x0040:
+			case 0x0020:
+			case 0x0010:
+				rt5665->jack_type |= SND_JACK_BTN_3;
+				break;
+			case 0x0000: /* unpressed */
+				break;
+			default:
+				btn_type = 0;
+				dev_err(rt5665->component->dev,
+					"Unexpected button code 0x%04x\n",
+					btn_type);
+				break;
+			}
+		}
+	} else {
+		/* jack out */
+		rt5665->jack_type = rt5665_headset_detect(rt5665->component, 0);
+	}
+
+	snd_soc_jack_report(rt5665->hs_jack, rt5665->jack_type,
+			SND_JACK_HEADSET |
+			    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+			    SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+	if (rt5665->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+		SND_JACK_BTN_2 | SND_JACK_BTN_3))
+		schedule_delayed_work(&rt5665->jd_check_work, 0);
+	else
+		cancel_delayed_work_sync(&rt5665->jd_check_work);
+
+	mutex_unlock(&rt5665->calibrate_mutex);
+}
+
+static const char * const rt5665_clk_sync[] = {
+	"I2S1_1", "I2S1_2", "I2S2", "I2S3", "IF2 Slave", "IF3 Slave"
+};
+
+static const struct soc_enum rt5665_enum[] = {
+	SOC_ENUM_SINGLE(RT5665_I2S1_SDP, 11, 5, rt5665_clk_sync),
+	SOC_ENUM_SINGLE(RT5665_I2S2_SDP, 11, 5, rt5665_clk_sync),
+	SOC_ENUM_SINGLE(RT5665_I2S3_SDP, 11, 5, rt5665_clk_sync),
+};
+
+static const struct snd_kcontrol_new rt5665_snd_controls[] = {
+	/* Headphone Output Volume */
+	SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", RT5665_HPL_GAIN,
+		RT5665_HPR_GAIN, RT5665_G_HP_SFT, 15, 1, snd_soc_get_volsw,
+		rt5665_hp_vol_put, hp_vol_tlv),
+
+	/* Mono Output Volume */
+	SOC_SINGLE_EXT_TLV("Mono Playback Volume", RT5665_MONO_GAIN,
+		RT5665_L_VOL_SFT, 15, 1, snd_soc_get_volsw,
+		rt5665_mono_vol_put, mono_vol_tlv),
+
+	SOC_SINGLE_TLV("MONOVOL Playback Volume", RT5665_MONO_OUT,
+		RT5665_L_VOL_SFT, 39, 1, out_vol_tlv),
+
+	/* Output Volume */
+	SOC_DOUBLE_TLV("OUT Playback Volume", RT5665_LOUT, RT5665_L_VOL_SFT,
+		RT5665_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5665_DAC1_DIG_VOL,
+		RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 175, 0, dac_vol_tlv),
+	SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5665_DAC2_DIG_VOL,
+		RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 175, 0, dac_vol_tlv),
+	SOC_DOUBLE("DAC2 Playback Switch", RT5665_DAC2_CTRL,
+		RT5665_M_DAC2_L_VOL_SFT, RT5665_M_DAC2_R_VOL_SFT, 1, 1),
+
+	/* IN1/IN2/IN3/IN4 Volume */
+	SOC_SINGLE_TLV("IN1 Boost Volume", RT5665_IN1_IN2,
+		RT5665_BST1_SFT, 69, 0, in_bst_tlv),
+	SOC_SINGLE_TLV("IN2 Boost Volume", RT5665_IN1_IN2,
+		RT5665_BST2_SFT, 69, 0, in_bst_tlv),
+	SOC_SINGLE_TLV("IN3 Boost Volume", RT5665_IN3_IN4,
+		RT5665_BST3_SFT, 69, 0, in_bst_tlv),
+	SOC_SINGLE_TLV("IN4 Boost Volume", RT5665_IN3_IN4,
+		RT5665_BST4_SFT, 69, 0, in_bst_tlv),
+	SOC_SINGLE_TLV("CBJ Boost Volume", RT5665_CBJ_BST_CTRL,
+		RT5665_BST_CBJ_SFT, 8, 0, bst_tlv),
+
+	/* INL/INR Volume Control */
+	SOC_DOUBLE_TLV("IN Capture Volume", RT5665_INL1_INR1_VOL,
+		RT5665_INL_VOL_SFT, RT5665_INR_VOL_SFT, 31, 1, in_vol_tlv),
+
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("STO1 ADC Capture Switch", RT5665_STO1_ADC_DIG_VOL,
+		RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5665_STO1_ADC_DIG_VOL,
+		RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv),
+	SOC_DOUBLE("Mono ADC Capture Switch", RT5665_MONO_ADC_DIG_VOL,
+		RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5665_MONO_ADC_DIG_VOL,
+		RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv),
+	SOC_DOUBLE("STO2 ADC Capture Switch", RT5665_STO2_ADC_DIG_VOL,
+		RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("STO2 ADC Capture Volume", RT5665_STO2_ADC_DIG_VOL,
+		RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv),
+
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5665_STO1_ADC_BOOST,
+		RT5665_STO1_ADC_L_BST_SFT, RT5665_STO1_ADC_R_BST_SFT,
+		3, 0, adc_bst_tlv),
+
+	SOC_DOUBLE_TLV("Mono ADC Boost Gain Volume", RT5665_MONO_ADC_BOOST,
+		RT5665_MONO_ADC_L_BST_SFT, RT5665_MONO_ADC_R_BST_SFT,
+		3, 0, adc_bst_tlv),
+
+	SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5665_STO2_ADC_BOOST,
+		RT5665_STO2_ADC_L_BST_SFT, RT5665_STO2_ADC_R_BST_SFT,
+		3, 0, adc_bst_tlv),
+
+	/* I2S3 CLK Source */
+	SOC_ENUM("I2S1 Master Clk Sel", rt5665_enum[0]),
+	SOC_ENUM("I2S2 Master Clk Sel", rt5665_enum[1]),
+	SOC_ENUM("I2S3 Master Clk Sel", rt5665_enum[2]),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
+	int pd, idx = -EINVAL;
+
+	pd = rl6231_get_pre_div(rt5665->regmap,
+		RT5665_ADDA_CLK_1, RT5665_I2S_PD1_SFT);
+	idx = rl6231_calc_dmic_clk(rt5665->sysclk / pd);
+
+	if (idx < 0)
+		dev_err(component->dev, "Failed to set DMIC clock\n");
+	else {
+		snd_soc_component_update_bits(component, RT5665_DMIC_CTRL_1,
+			RT5665_DMIC_CLK_MASK, idx << RT5665_DMIC_CLK_SFT);
+	}
+	return idx;
+}
+
+static int rt5665_charge_pump_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component, RT5665_HP_CHARGE_PUMP_1,
+			RT5665_PM_HP_MASK | RT5665_OSW_L_MASK,
+			RT5665_PM_HP_HV | RT5665_OSW_L_EN);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, RT5665_HP_CHARGE_PUMP_1,
+			RT5665_PM_HP_MASK | RT5665_OSW_L_MASK,
+			RT5665_PM_HP_LV | RT5665_OSW_L_DIS);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *w,
+			 struct snd_soc_dapm_widget *sink)
+{
+	unsigned int val;
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	val = snd_soc_component_read32(component, RT5665_GLB_CLK);
+	val &= RT5665_SCLK_SRC_MASK;
+	if (val == RT5665_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int is_using_asrc(struct snd_soc_dapm_widget *w,
+			 struct snd_soc_dapm_widget *sink)
+{
+	unsigned int reg, shift, val;
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (w->shift) {
+	case RT5665_ADC_MONO_R_ASRC_SFT:
+		reg = RT5665_ASRC_3;
+		shift = RT5665_AD_MONOR_CLK_SEL_SFT;
+		break;
+	case RT5665_ADC_MONO_L_ASRC_SFT:
+		reg = RT5665_ASRC_3;
+		shift = RT5665_AD_MONOL_CLK_SEL_SFT;
+		break;
+	case RT5665_ADC_STO1_ASRC_SFT:
+		reg = RT5665_ASRC_3;
+		shift = RT5665_AD_STO1_CLK_SEL_SFT;
+		break;
+	case RT5665_ADC_STO2_ASRC_SFT:
+		reg = RT5665_ASRC_3;
+		shift = RT5665_AD_STO2_CLK_SEL_SFT;
+		break;
+	case RT5665_DAC_MONO_R_ASRC_SFT:
+		reg = RT5665_ASRC_2;
+		shift = RT5665_DA_MONOR_CLK_SEL_SFT;
+		break;
+	case RT5665_DAC_MONO_L_ASRC_SFT:
+		reg = RT5665_ASRC_2;
+		shift = RT5665_DA_MONOL_CLK_SEL_SFT;
+		break;
+	case RT5665_DAC_STO1_ASRC_SFT:
+		reg = RT5665_ASRC_2;
+		shift = RT5665_DA_STO1_CLK_SEL_SFT;
+		break;
+	case RT5665_DAC_STO2_ASRC_SFT:
+		reg = RT5665_ASRC_2;
+		shift = RT5665_DA_STO2_CLK_SEL_SFT;
+		break;
+	default:
+		return 0;
+	}
+
+	val = (snd_soc_component_read32(component, reg) >> shift) & 0xf;
+	switch (val) {
+	case RT5665_CLK_SEL_I2S1_ASRC:
+	case RT5665_CLK_SEL_I2S2_ASRC:
+	case RT5665_CLK_SEL_I2S3_ASRC:
+		/* I2S_Pre_Div1 should be 1 in asrc mode */
+		snd_soc_component_update_bits(component, RT5665_ADDA_CLK_1,
+			RT5665_I2S_PD1_MASK, RT5665_I2S_PD1_2);
+		return 1;
+	default:
+		return 0;
+	}
+
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5665_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO1_ADC_MIXER,
+			RT5665_M_STO1_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO1_ADC_MIXER,
+			RT5665_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO1_ADC_MIXER,
+			RT5665_M_STO1_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO1_ADC_MIXER,
+			RT5665_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_sto2_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO2_ADC_MIXER,
+			RT5665_M_STO2_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO2_ADC_MIXER,
+			RT5665_M_STO2_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_sto2_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO2_ADC_MIXER,
+			RT5665_M_STO2_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO2_ADC_MIXER,
+			RT5665_M_STO2_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_mono_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5665_MONO_ADC_MIXER,
+			RT5665_M_MONO_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5665_MONO_ADC_MIXER,
+			RT5665_M_MONO_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_mono_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5665_MONO_ADC_MIXER,
+			RT5665_M_MONO_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5665_MONO_ADC_MIXER,
+			RT5665_M_MONO_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5665_AD_DA_MIXER,
+			RT5665_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5665_AD_DA_MIXER,
+			RT5665_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5665_AD_DA_MIXER,
+			RT5665_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5665_AD_DA_MIXER,
+			RT5665_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_sto1_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO1_DAC_MIXER,
+			RT5665_M_DAC_L1_STO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO1_DAC_MIXER,
+			RT5665_M_DAC_R1_STO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO1_DAC_MIXER,
+			RT5665_M_DAC_L2_STO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO1_DAC_MIXER,
+			RT5665_M_DAC_R2_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_sto1_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO1_DAC_MIXER,
+			RT5665_M_DAC_L1_STO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO1_DAC_MIXER,
+			RT5665_M_DAC_R1_STO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO1_DAC_MIXER,
+			RT5665_M_DAC_L2_STO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO1_DAC_MIXER,
+			RT5665_M_DAC_R2_STO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_sto2_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO2_DAC_MIXER,
+			RT5665_M_DAC_L1_STO2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO2_DAC_MIXER,
+			RT5665_M_DAC_L2_STO2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L3 Switch", RT5665_STO2_DAC_MIXER,
+			RT5665_M_DAC_L3_STO2_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_sto2_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO2_DAC_MIXER,
+			RT5665_M_DAC_R1_STO2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO2_DAC_MIXER,
+			RT5665_M_DAC_R2_STO2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R3 Switch", RT5665_STO2_DAC_MIXER,
+			RT5665_M_DAC_R3_STO2_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_mono_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_MONO_DAC_MIXER,
+			RT5665_M_DAC_L1_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_MONO_DAC_MIXER,
+			RT5665_M_DAC_R1_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONO_DAC_MIXER,
+			RT5665_M_DAC_L2_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_MONO_DAC_MIXER,
+			RT5665_M_DAC_R2_MONO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_mono_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_MONO_DAC_MIXER,
+			RT5665_M_DAC_L1_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_MONO_DAC_MIXER,
+			RT5665_M_DAC_R1_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONO_DAC_MIXER,
+			RT5665_M_DAC_L2_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_MONO_DAC_MIXER,
+			RT5665_M_DAC_R2_MONO_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5665_rec1_l_mix[] = {
+	SOC_DAPM_SINGLE("CBJ Switch", RT5665_REC1_L2_MIXER,
+			RT5665_M_CBJ_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5665_REC1_L2_MIXER,
+			RT5665_M_INL_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5665_REC1_L2_MIXER,
+			RT5665_M_INR_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC1_L2_MIXER,
+			RT5665_M_BST4_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC1_L2_MIXER,
+			RT5665_M_BST3_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC1_L2_MIXER,
+			RT5665_M_BST2_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC1_L2_MIXER,
+			RT5665_M_BST1_RM1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_rec1_r_mix[] = {
+	SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_REC1_R2_MIXER,
+			RT5665_M_AEC_REF_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5665_REC1_R2_MIXER,
+			RT5665_M_INR_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC1_R2_MIXER,
+			RT5665_M_BST4_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC1_R2_MIXER,
+			RT5665_M_BST3_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC1_R2_MIXER,
+			RT5665_M_BST2_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC1_R2_MIXER,
+			RT5665_M_BST1_RM1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_rec2_l_mix[] = {
+	SOC_DAPM_SINGLE("INL Switch", RT5665_REC2_L2_MIXER,
+			RT5665_M_INL_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5665_REC2_L2_MIXER,
+			RT5665_M_INR_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("CBJ Switch", RT5665_REC2_L2_MIXER,
+			RT5665_M_CBJ_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC2_L2_MIXER,
+			RT5665_M_BST4_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC2_L2_MIXER,
+			RT5665_M_BST3_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC2_L2_MIXER,
+			RT5665_M_BST2_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC2_L2_MIXER,
+			RT5665_M_BST1_RM2_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_rec2_r_mix[] = {
+	SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_REC2_R2_MIXER,
+			RT5665_M_MONOVOL_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5665_REC2_R2_MIXER,
+			RT5665_M_INL_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5665_REC2_R2_MIXER,
+			RT5665_M_INR_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC2_R2_MIXER,
+			RT5665_M_BST4_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC2_R2_MIXER,
+			RT5665_M_BST3_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC2_R2_MIXER,
+			RT5665_M_BST2_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC2_R2_MIXER,
+			RT5665_M_BST1_RM2_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_monovol_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONOMIX_IN_GAIN,
+			RT5665_M_DAC_L2_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("RECMIX2L Switch", RT5665_MONOMIX_IN_GAIN,
+			RT5665_M_RECMIC2L_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5665_MONOMIX_IN_GAIN,
+			RT5665_M_BST1_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5665_MONOMIX_IN_GAIN,
+			RT5665_M_BST2_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5665_MONOMIX_IN_GAIN,
+			RT5665_M_BST3_MM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_out_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_OUT_L_MIXER,
+			RT5665_M_DAC_L2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5665_OUT_L_MIXER,
+			RT5665_M_IN_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5665_OUT_L_MIXER,
+			RT5665_M_BST1_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5665_OUT_L_MIXER,
+			RT5665_M_BST2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5665_OUT_L_MIXER,
+			RT5665_M_BST3_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_out_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_OUT_R_MIXER,
+			RT5665_M_DAC_R2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5665_OUT_R_MIXER,
+			RT5665_M_IN_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5665_OUT_R_MIXER,
+			RT5665_M_BST2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5665_OUT_R_MIXER,
+			RT5665_M_BST3_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5665_OUT_R_MIXER,
+			RT5665_M_BST4_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_mono_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONOMIX_IN_GAIN,
+			RT5665_M_DAC_L2_MA_SFT, 1, 1),
+	SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_MONOMIX_IN_GAIN,
+			RT5665_M_MONOVOL_MA_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_lout_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_LOUT_MIXER,
+			RT5665_M_DAC_L2_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL L Switch", RT5665_LOUT_MIXER,
+			RT5665_M_OV_L_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_lout_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_LOUT_MIXER,
+			RT5665_M_DAC_R2_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL R Switch", RT5665_LOUT_MIXER,
+			RT5665_M_OV_R_LM_SFT, 1, 1),
+};
+
+/*DAC L2, DAC R2*/
+/*MX-17 [6:4], MX-17 [2:0]*/
+static const char * const rt5665_dac2_src[] = {
+	"IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC", "Mono ADC MIX"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_dac_l2_enum, RT5665_DAC2_CTRL,
+	RT5665_DAC_L2_SEL_SFT, rt5665_dac2_src);
+
+static const struct snd_kcontrol_new rt5665_dac_l2_mux =
+	SOC_DAPM_ENUM("Digital DAC L2 Source", rt5665_dac_l2_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_dac_r2_enum, RT5665_DAC2_CTRL,
+	RT5665_DAC_R2_SEL_SFT, rt5665_dac2_src);
+
+static const struct snd_kcontrol_new rt5665_dac_r2_mux =
+	SOC_DAPM_ENUM("Digital DAC R2 Source", rt5665_dac_r2_enum);
+
+/*DAC L3, DAC R3*/
+/*MX-1B [6:4], MX-1B [2:0]*/
+static const char * const rt5665_dac3_src[] = {
+	"IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC", "STO2 ADC MIX"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_dac_l3_enum, RT5665_DAC3_CTRL,
+	RT5665_DAC_L3_SEL_SFT, rt5665_dac3_src);
+
+static const struct snd_kcontrol_new rt5665_dac_l3_mux =
+	SOC_DAPM_ENUM("Digital DAC L3 Source", rt5665_dac_l3_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_dac_r3_enum, RT5665_DAC3_CTRL,
+	RT5665_DAC_R3_SEL_SFT, rt5665_dac3_src);
+
+static const struct snd_kcontrol_new rt5665_dac_r3_mux =
+	SOC_DAPM_ENUM("Digital DAC R3 Source", rt5665_dac_r3_enum);
+
+/* STO1 ADC1 Source */
+/* MX-26 [13] [5] */
+static const char * const rt5665_sto1_adc1_src[] = {
+	"DD Mux", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto1_adc1l_enum, RT5665_STO1_ADC_MIXER,
+	RT5665_STO1_ADC1L_SRC_SFT, rt5665_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_adc1l_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5665_sto1_adc1l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto1_adc1r_enum, RT5665_STO1_ADC_MIXER,
+	RT5665_STO1_ADC1R_SRC_SFT, rt5665_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_adc1r_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5665_sto1_adc1r_enum);
+
+/* STO1 ADC Source */
+/* MX-26 [11:10] [3:2] */
+static const char * const rt5665_sto1_adc_src[] = {
+	"ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto1_adcl_enum, RT5665_STO1_ADC_MIXER,
+	RT5665_STO1_ADCL_SRC_SFT, rt5665_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_adcl_mux =
+	SOC_DAPM_ENUM("Stereo1 ADCL Source", rt5665_sto1_adcl_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto1_adcr_enum, RT5665_STO1_ADC_MIXER,
+	RT5665_STO1_ADCR_SRC_SFT, rt5665_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_adcr_mux =
+	SOC_DAPM_ENUM("Stereo1 ADCR Source", rt5665_sto1_adcr_enum);
+
+/* STO1 ADC2 Source */
+/* MX-26 [12] [4] */
+static const char * const rt5665_sto1_adc2_src[] = {
+	"DAC MIX", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto1_adc2l_enum, RT5665_STO1_ADC_MIXER,
+	RT5665_STO1_ADC2L_SRC_SFT, rt5665_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_adc2l_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC2L Source", rt5665_sto1_adc2l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto1_adc2r_enum, RT5665_STO1_ADC_MIXER,
+	RT5665_STO1_ADC2R_SRC_SFT, rt5665_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_adc2r_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC2R Source", rt5665_sto1_adc2r_enum);
+
+/* STO1 DMIC Source */
+/* MX-26 [8] */
+static const char * const rt5665_sto1_dmic_src[] = {
+	"DMIC1", "DMIC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto1_dmic_enum, RT5665_STO1_ADC_MIXER,
+	RT5665_STO1_DMIC_SRC_SFT, rt5665_sto1_dmic_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_dmic_mux =
+	SOC_DAPM_ENUM("Stereo1 DMIC Mux", rt5665_sto1_dmic_enum);
+
+/* MX-26 [9] */
+static const char * const rt5665_sto1_dd_l_src[] = {
+	"STO2 DAC", "MONO DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto1_dd_l_enum, RT5665_STO1_ADC_MIXER,
+	RT5665_STO1_DD_L_SRC_SFT, rt5665_sto1_dd_l_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_dd_l_mux =
+	SOC_DAPM_ENUM("Stereo1 DD L Source", rt5665_sto1_dd_l_enum);
+
+/* MX-26 [1:0] */
+static const char * const rt5665_sto1_dd_r_src[] = {
+	"STO2 DAC", "MONO DAC", "AEC REF"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto1_dd_r_enum, RT5665_STO1_ADC_MIXER,
+	RT5665_STO1_DD_R_SRC_SFT, rt5665_sto1_dd_r_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_dd_r_mux =
+	SOC_DAPM_ENUM("Stereo1 DD R Source", rt5665_sto1_dd_r_enum);
+
+/* MONO ADC L2 Source */
+/* MX-27 [12] */
+static const char * const rt5665_mono_adc_l2_src[] = {
+	"DAC MIXL", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_mono_adc_l2_enum, RT5665_MONO_ADC_MIXER,
+	RT5665_MONO_ADC_L2_SRC_SFT, rt5665_mono_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5665_mono_adc_l2_mux =
+	SOC_DAPM_ENUM("Mono ADC L2 Source", rt5665_mono_adc_l2_enum);
+
+
+/* MONO ADC L1 Source */
+/* MX-27 [13] */
+static const char * const rt5665_mono_adc_l1_src[] = {
+	"DD Mux", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_mono_adc_l1_enum, RT5665_MONO_ADC_MIXER,
+	RT5665_MONO_ADC_L1_SRC_SFT, rt5665_mono_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5665_mono_adc_l1_mux =
+	SOC_DAPM_ENUM("Mono ADC L1 Source", rt5665_mono_adc_l1_enum);
+
+/* MX-27 [9][1]*/
+static const char * const rt5665_mono_dd_src[] = {
+	"STO2 DAC", "MONO DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_mono_dd_l_enum, RT5665_MONO_ADC_MIXER,
+	RT5665_MONO_DD_L_SRC_SFT, rt5665_mono_dd_src);
+
+static const struct snd_kcontrol_new rt5665_mono_dd_l_mux =
+	SOC_DAPM_ENUM("Mono DD L Source", rt5665_mono_dd_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_mono_dd_r_enum, RT5665_MONO_ADC_MIXER,
+	RT5665_MONO_DD_R_SRC_SFT, rt5665_mono_dd_src);
+
+static const struct snd_kcontrol_new rt5665_mono_dd_r_mux =
+	SOC_DAPM_ENUM("Mono DD R Source", rt5665_mono_dd_r_enum);
+
+/* MONO ADC L Source, MONO ADC R Source*/
+/* MX-27 [11:10], MX-27 [3:2] */
+static const char * const rt5665_mono_adc_src[] = {
+	"ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_mono_adc_l_enum, RT5665_MONO_ADC_MIXER,
+	RT5665_MONO_ADC_L_SRC_SFT, rt5665_mono_adc_src);
+
+static const struct snd_kcontrol_new rt5665_mono_adc_l_mux =
+	SOC_DAPM_ENUM("Mono ADC L Source", rt5665_mono_adc_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_mono_adcr_enum, RT5665_MONO_ADC_MIXER,
+	RT5665_MONO_ADC_R_SRC_SFT, rt5665_mono_adc_src);
+
+static const struct snd_kcontrol_new rt5665_mono_adc_r_mux =
+	SOC_DAPM_ENUM("Mono ADC R Source", rt5665_mono_adcr_enum);
+
+/* MONO DMIC L Source */
+/* MX-27 [8] */
+static const char * const rt5665_mono_dmic_l_src[] = {
+	"DMIC1 L", "DMIC2 L"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_mono_dmic_l_enum, RT5665_MONO_ADC_MIXER,
+	RT5665_MONO_DMIC_L_SRC_SFT, rt5665_mono_dmic_l_src);
+
+static const struct snd_kcontrol_new rt5665_mono_dmic_l_mux =
+	SOC_DAPM_ENUM("Mono DMIC L Source", rt5665_mono_dmic_l_enum);
+
+/* MONO ADC R2 Source */
+/* MX-27 [4] */
+static const char * const rt5665_mono_adc_r2_src[] = {
+	"DAC MIXR", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_mono_adc_r2_enum, RT5665_MONO_ADC_MIXER,
+	RT5665_MONO_ADC_R2_SRC_SFT, rt5665_mono_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5665_mono_adc_r2_mux =
+	SOC_DAPM_ENUM("Mono ADC R2 Source", rt5665_mono_adc_r2_enum);
+
+/* MONO ADC R1 Source */
+/* MX-27 [5] */
+static const char * const rt5665_mono_adc_r1_src[] = {
+	"DD Mux", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_mono_adc_r1_enum, RT5665_MONO_ADC_MIXER,
+	RT5665_MONO_ADC_R1_SRC_SFT, rt5665_mono_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5665_mono_adc_r1_mux =
+	SOC_DAPM_ENUM("Mono ADC R1 Source", rt5665_mono_adc_r1_enum);
+
+/* MONO DMIC R Source */
+/* MX-27 [0] */
+static const char * const rt5665_mono_dmic_r_src[] = {
+	"DMIC1 R", "DMIC2 R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_mono_dmic_r_enum, RT5665_MONO_ADC_MIXER,
+	RT5665_MONO_DMIC_R_SRC_SFT, rt5665_mono_dmic_r_src);
+
+static const struct snd_kcontrol_new rt5665_mono_dmic_r_mux =
+	SOC_DAPM_ENUM("Mono DMIC R Source", rt5665_mono_dmic_r_enum);
+
+
+/* STO2 ADC1 Source */
+/* MX-28 [13] [5] */
+static const char * const rt5665_sto2_adc1_src[] = {
+	"DD Mux", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto2_adc1l_enum, RT5665_STO2_ADC_MIXER,
+	RT5665_STO2_ADC1L_SRC_SFT, rt5665_sto2_adc1_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_adc1l_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC1L Source", rt5665_sto2_adc1l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto2_adc1r_enum, RT5665_STO2_ADC_MIXER,
+	RT5665_STO2_ADC1R_SRC_SFT, rt5665_sto2_adc1_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_adc1r_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC1L Source", rt5665_sto2_adc1r_enum);
+
+/* STO2 ADC Source */
+/* MX-28 [11:10] [3:2] */
+static const char * const rt5665_sto2_adc_src[] = {
+	"ADC1 L", "ADC1 R", "ADC2 L"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto2_adcl_enum, RT5665_STO2_ADC_MIXER,
+	RT5665_STO2_ADCL_SRC_SFT, rt5665_sto2_adc_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_adcl_mux =
+	SOC_DAPM_ENUM("Stereo2 ADCL Source", rt5665_sto2_adcl_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto2_adcr_enum, RT5665_STO2_ADC_MIXER,
+	RT5665_STO2_ADCR_SRC_SFT, rt5665_sto2_adc_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_adcr_mux =
+	SOC_DAPM_ENUM("Stereo2 ADCR Source", rt5665_sto2_adcr_enum);
+
+/* STO2 ADC2 Source */
+/* MX-28 [12] [4] */
+static const char * const rt5665_sto2_adc2_src[] = {
+	"DAC MIX", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto2_adc2l_enum, RT5665_STO2_ADC_MIXER,
+	RT5665_STO2_ADC2L_SRC_SFT, rt5665_sto2_adc2_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_adc2l_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC2L Source", rt5665_sto2_adc2l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto2_adc2r_enum, RT5665_STO2_ADC_MIXER,
+	RT5665_STO2_ADC2R_SRC_SFT, rt5665_sto2_adc2_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_adc2r_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC2R Source", rt5665_sto2_adc2r_enum);
+
+/* STO2 DMIC Source */
+/* MX-28 [8] */
+static const char * const rt5665_sto2_dmic_src[] = {
+	"DMIC1", "DMIC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto2_dmic_enum, RT5665_STO2_ADC_MIXER,
+	RT5665_STO2_DMIC_SRC_SFT, rt5665_sto2_dmic_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_dmic_mux =
+	SOC_DAPM_ENUM("Stereo2 DMIC Source", rt5665_sto2_dmic_enum);
+
+/* MX-28 [9] */
+static const char * const rt5665_sto2_dd_l_src[] = {
+	"STO2 DAC", "MONO DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto2_dd_l_enum, RT5665_STO2_ADC_MIXER,
+	RT5665_STO2_DD_L_SRC_SFT, rt5665_sto2_dd_l_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_dd_l_mux =
+	SOC_DAPM_ENUM("Stereo2 DD L Source", rt5665_sto2_dd_l_enum);
+
+/* MX-28 [1] */
+static const char * const rt5665_sto2_dd_r_src[] = {
+	"STO2 DAC", "MONO DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_sto2_dd_r_enum, RT5665_STO2_ADC_MIXER,
+	RT5665_STO2_DD_R_SRC_SFT, rt5665_sto2_dd_r_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_dd_r_mux =
+	SOC_DAPM_ENUM("Stereo2 DD R Source", rt5665_sto2_dd_r_enum);
+
+/* DAC R1 Source, DAC L1 Source*/
+/* MX-29 [11:10], MX-29 [9:8]*/
+static const char * const rt5665_dac1_src[] = {
+	"IF1 DAC1", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_dac_r1_enum, RT5665_AD_DA_MIXER,
+	RT5665_DAC1_R_SEL_SFT, rt5665_dac1_src);
+
+static const struct snd_kcontrol_new rt5665_dac_r1_mux =
+	SOC_DAPM_ENUM("DAC R1 Source", rt5665_dac_r1_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_dac_l1_enum, RT5665_AD_DA_MIXER,
+	RT5665_DAC1_L_SEL_SFT, rt5665_dac1_src);
+
+static const struct snd_kcontrol_new rt5665_dac_l1_mux =
+	SOC_DAPM_ENUM("DAC L1 Source", rt5665_dac_l1_enum);
+
+/* DAC Digital Mixer L Source, DAC Digital Mixer R Source*/
+/* MX-2D [13:12], MX-2D [9:8]*/
+static const char * const rt5665_dig_dac_mix_src[] = {
+	"Stereo1 DAC Mixer", "Stereo2 DAC Mixer", "Mono DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_dig_dac_mixl_enum, RT5665_A_DAC1_MUX,
+	RT5665_DAC_MIX_L_SFT, rt5665_dig_dac_mix_src);
+
+static const struct snd_kcontrol_new rt5665_dig_dac_mixl_mux =
+	SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5665_dig_dac_mixl_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_dig_dac_mixr_enum, RT5665_A_DAC1_MUX,
+	RT5665_DAC_MIX_R_SFT, rt5665_dig_dac_mix_src);
+
+static const struct snd_kcontrol_new rt5665_dig_dac_mixr_mux =
+	SOC_DAPM_ENUM("DAC Digital Mixer R Source", rt5665_dig_dac_mixr_enum);
+
+/* Analog DAC L1 Source, Analog DAC R1 Source*/
+/* MX-2D [5:4], MX-2D [1:0]*/
+static const char * const rt5665_alg_dac1_src[] = {
+	"Stereo1 DAC Mixer", "DAC1", "DMIC1"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_alg_dac_l1_enum, RT5665_A_DAC1_MUX,
+	RT5665_A_DACL1_SFT, rt5665_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5665_alg_dac_l1_mux =
+	SOC_DAPM_ENUM("Analog DAC L1 Source", rt5665_alg_dac_l1_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_alg_dac_r1_enum, RT5665_A_DAC1_MUX,
+	RT5665_A_DACR1_SFT, rt5665_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5665_alg_dac_r1_mux =
+	SOC_DAPM_ENUM("Analog DAC R1 Source", rt5665_alg_dac_r1_enum);
+
+/* Analog DAC LR Source, Analog DAC R2 Source*/
+/* MX-2E [5:4], MX-2E [0]*/
+static const char * const rt5665_alg_dac2_src[] = {
+	"Mono DAC Mixer", "DAC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_alg_dac_l2_enum, RT5665_A_DAC2_MUX,
+	RT5665_A_DACL2_SFT, rt5665_alg_dac2_src);
+
+static const struct snd_kcontrol_new rt5665_alg_dac_l2_mux =
+	SOC_DAPM_ENUM("Analog DAC L2 Source", rt5665_alg_dac_l2_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_alg_dac_r2_enum, RT5665_A_DAC2_MUX,
+	RT5665_A_DACR2_SFT, rt5665_alg_dac2_src);
+
+static const struct snd_kcontrol_new rt5665_alg_dac_r2_mux =
+	SOC_DAPM_ENUM("Analog DAC R2 Source", rt5665_alg_dac_r2_enum);
+
+/* Interface2 ADC Data Input*/
+/* MX-2F [14:12] */
+static const char * const rt5665_if2_1_adc_in_src[] = {
+	"STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1",
+	"IF1 DAC2", "IF2_2 DAC", "IF3 DAC", "DAC1 MIX"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_if2_1_adc_in_enum, RT5665_DIG_INF2_DATA,
+	RT5665_IF2_1_ADC_IN_SFT, rt5665_if2_1_adc_in_src);
+
+static const struct snd_kcontrol_new rt5665_if2_1_adc_in_mux =
+	SOC_DAPM_ENUM("IF2_1 ADC IN Source", rt5665_if2_1_adc_in_enum);
+
+/* MX-2F [6:4] */
+static const char * const rt5665_if2_2_adc_in_src[] = {
+	"STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1",
+	"IF1 DAC2", "IF2_1 DAC", "IF3 DAC", "DAC1 MIX"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_if2_2_adc_in_enum, RT5665_DIG_INF2_DATA,
+	RT5665_IF2_2_ADC_IN_SFT, rt5665_if2_2_adc_in_src);
+
+static const struct snd_kcontrol_new rt5665_if2_2_adc_in_mux =
+	SOC_DAPM_ENUM("IF2_1 ADC IN Source", rt5665_if2_2_adc_in_enum);
+
+/* Interface3 ADC Data Input*/
+/* MX-30 [6:4] */
+static const char * const rt5665_if3_adc_in_src[] = {
+	"STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1",
+	"IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "DAC1 MIX"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_if3_adc_in_enum, RT5665_DIG_INF3_DATA,
+	RT5665_IF3_ADC_IN_SFT, rt5665_if3_adc_in_src);
+
+static const struct snd_kcontrol_new rt5665_if3_adc_in_mux =
+	SOC_DAPM_ENUM("IF3 ADC IN Source", rt5665_if3_adc_in_enum);
+
+/* PDM 1 L/R*/
+/* MX-31 [11:10] [9:8] */
+static const char * const rt5665_pdm_src[] = {
+	"Stereo1 DAC", "Stereo2 DAC", "Mono DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_pdm_l_enum, RT5665_PDM_OUT_CTRL,
+	RT5665_PDM1_L_SFT, rt5665_pdm_src);
+
+static const struct snd_kcontrol_new rt5665_pdm_l_mux =
+	SOC_DAPM_ENUM("PDM L Source", rt5665_pdm_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_pdm_r_enum, RT5665_PDM_OUT_CTRL,
+	RT5665_PDM1_R_SFT, rt5665_pdm_src);
+
+static const struct snd_kcontrol_new rt5665_pdm_r_mux =
+	SOC_DAPM_ENUM("PDM R Source", rt5665_pdm_r_enum);
+
+
+/* I2S1 TDM ADCDAT Source */
+/* MX-7a[10] */
+static const char * const rt5665_if1_1_adc1_data_src[] = {
+	"STO1 ADC", "IF2_1 DAC",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_if1_1_adc1_data_enum, RT5665_TDM_CTRL_3,
+	RT5665_IF1_ADC1_SEL_SFT, rt5665_if1_1_adc1_data_src);
+
+static const struct snd_kcontrol_new rt5665_if1_1_adc1_mux =
+	SOC_DAPM_ENUM("IF1_1 ADC1 Source", rt5665_if1_1_adc1_data_enum);
+
+/* MX-7a[9] */
+static const char * const rt5665_if1_1_adc2_data_src[] = {
+	"STO2 ADC", "IF2_2 DAC",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_if1_1_adc2_data_enum, RT5665_TDM_CTRL_3,
+	RT5665_IF1_ADC2_SEL_SFT, rt5665_if1_1_adc2_data_src);
+
+static const struct snd_kcontrol_new rt5665_if1_1_adc2_mux =
+	SOC_DAPM_ENUM("IF1_1 ADC2 Source", rt5665_if1_1_adc2_data_enum);
+
+/* MX-7a[8] */
+static const char * const rt5665_if1_1_adc3_data_src[] = {
+	"MONO ADC", "IF3 DAC",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_if1_1_adc3_data_enum, RT5665_TDM_CTRL_3,
+	RT5665_IF1_ADC3_SEL_SFT, rt5665_if1_1_adc3_data_src);
+
+static const struct snd_kcontrol_new rt5665_if1_1_adc3_mux =
+	SOC_DAPM_ENUM("IF1_1 ADC3 Source", rt5665_if1_1_adc3_data_enum);
+
+/* MX-7b[10] */
+static const char * const rt5665_if1_2_adc1_data_src[] = {
+	"STO1 ADC", "IF1 DAC",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_if1_2_adc1_data_enum, RT5665_TDM_CTRL_4,
+	RT5665_IF1_ADC1_SEL_SFT, rt5665_if1_2_adc1_data_src);
+
+static const struct snd_kcontrol_new rt5665_if1_2_adc1_mux =
+	SOC_DAPM_ENUM("IF1_2 ADC1 Source", rt5665_if1_2_adc1_data_enum);
+
+/* MX-7b[9] */
+static const char * const rt5665_if1_2_adc2_data_src[] = {
+	"STO2 ADC", "IF2_1 DAC",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_if1_2_adc2_data_enum, RT5665_TDM_CTRL_4,
+	RT5665_IF1_ADC2_SEL_SFT, rt5665_if1_2_adc2_data_src);
+
+static const struct snd_kcontrol_new rt5665_if1_2_adc2_mux =
+	SOC_DAPM_ENUM("IF1_2 ADC2 Source", rt5665_if1_2_adc2_data_enum);
+
+/* MX-7b[8] */
+static const char * const rt5665_if1_2_adc3_data_src[] = {
+	"MONO ADC", "IF2_2 DAC",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_if1_2_adc3_data_enum, RT5665_TDM_CTRL_4,
+	RT5665_IF1_ADC3_SEL_SFT, rt5665_if1_2_adc3_data_src);
+
+static const struct snd_kcontrol_new rt5665_if1_2_adc3_mux =
+	SOC_DAPM_ENUM("IF1_2 ADC3 Source", rt5665_if1_2_adc3_data_enum);
+
+/* MX-7b[7] */
+static const char * const rt5665_if1_2_adc4_data_src[] = {
+	"DAC1", "IF3 DAC",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_if1_2_adc4_data_enum, RT5665_TDM_CTRL_4,
+	RT5665_IF1_ADC4_SEL_SFT, rt5665_if1_2_adc4_data_src);
+
+static const struct snd_kcontrol_new rt5665_if1_2_adc4_mux =
+	SOC_DAPM_ENUM("IF1_2 ADC4 Source", rt5665_if1_2_adc4_data_enum);
+
+/* MX-7a[4:0] MX-7b[4:0] */
+static const char * const rt5665_tdm_adc_data_src[] = {
+	"1234", "1243", "1324",	"1342", "1432", "1423",
+	"2134", "2143", "2314",	"2341", "2431", "2413",
+	"3124", "3142", "3214", "3241", "3412", "3421",
+	"4123", "4132", "4213", "4231", "4312", "4321"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_tdm1_adc_data_enum, RT5665_TDM_CTRL_3,
+	RT5665_TDM_ADC_SEL_SFT, rt5665_tdm_adc_data_src);
+
+static const struct snd_kcontrol_new rt5665_tdm1_adc_mux =
+	SOC_DAPM_ENUM("TDM1 ADC Mux", rt5665_tdm1_adc_data_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5665_tdm2_adc_data_enum, RT5665_TDM_CTRL_4,
+	RT5665_TDM_ADC_SEL_SFT, rt5665_tdm_adc_data_src);
+
+static const struct snd_kcontrol_new rt5665_tdm2_adc_mux =
+	SOC_DAPM_ENUM("TDM2 ADCDAT Source", rt5665_tdm2_adc_data_enum);
+
+/* Out Volume Switch */
+static const struct snd_kcontrol_new monovol_switch =
+	SOC_DAPM_SINGLE("Switch", RT5665_MONO_OUT, RT5665_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_l_switch =
+	SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_r_switch =
+	SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_VOL_R_SFT, 1, 1);
+
+/* Out Switch */
+static const struct snd_kcontrol_new mono_switch =
+	SOC_DAPM_SINGLE("Switch", RT5665_MONO_OUT, RT5665_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_switch =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5665_HP_CTRL_2,
+					RT5665_VOL_L_SFT, 1, 0);
+
+static const struct snd_kcontrol_new lout_l_switch =
+	SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_r_switch =
+	SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new pdm_l_switch =
+	SOC_DAPM_SINGLE("Switch", RT5665_PDM_OUT_CTRL,
+			RT5665_M_PDM1_L_SFT, 1,	1);
+
+static const struct snd_kcontrol_new pdm_r_switch =
+	SOC_DAPM_SINGLE("Switch", RT5665_PDM_OUT_CTRL,
+			RT5665_M_PDM1_R_SFT, 1,	1);
+
+static int rt5665_mono_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component, RT5665_MONO_NG2_CTRL_1,
+			RT5665_NG2_EN_MASK, RT5665_NG2_EN);
+		snd_soc_component_update_bits(component, RT5665_MONO_AMP_CALIB_CTRL_1, 0x40,
+			0x0);
+		snd_soc_component_update_bits(component, RT5665_MONO_OUT, 0x10, 0x10);
+		snd_soc_component_update_bits(component, RT5665_MONO_OUT, 0x20, 0x20);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, RT5665_MONO_OUT, 0x20, 0);
+		snd_soc_component_update_bits(component, RT5665_MONO_OUT, 0x10, 0);
+		snd_soc_component_update_bits(component, RT5665_MONO_AMP_CALIB_CTRL_1, 0x40,
+			0x40);
+		snd_soc_component_update_bits(component, RT5665_MONO_NG2_CTRL_1,
+			RT5665_NG2_EN_MASK, RT5665_NG2_DIS);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+
+}
+
+static int rt5665_hp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component, RT5665_STO_NG2_CTRL_1,
+			RT5665_NG2_EN_MASK, RT5665_NG2_EN);
+		snd_soc_component_write(component, RT5665_HP_LOGIC_CTRL_2, 0x0003);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_write(component, RT5665_HP_LOGIC_CTRL_2, 0x0002);
+		snd_soc_component_update_bits(component, RT5665_STO_NG2_CTRL_1,
+			RT5665_NG2_EN_MASK, RT5665_NG2_DIS);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+
+}
+
+static int rt5665_lout_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5665_DEPOP_1,
+			RT5665_PUMP_EN, RT5665_PUMP_EN);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5665_DEPOP_1,
+			RT5665_PUMP_EN, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+
+}
+
+static int set_dmic_power(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/*Add delay to avoid pop noise*/
+		msleep(150);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5655_set_verf(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		switch (w->shift) {
+		case RT5665_PWR_VREF1_BIT:
+			snd_soc_component_update_bits(component, RT5665_PWR_ANLG_1,
+				RT5665_PWR_FV1, 0);
+			break;
+
+		case RT5665_PWR_VREF2_BIT:
+			snd_soc_component_update_bits(component, RT5665_PWR_ANLG_1,
+				RT5665_PWR_FV2, 0);
+			break;
+
+		case RT5665_PWR_VREF3_BIT:
+			snd_soc_component_update_bits(component, RT5665_PWR_ANLG_1,
+				RT5665_PWR_FV3, 0);
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(15000, 20000);
+		switch (w->shift) {
+		case RT5665_PWR_VREF1_BIT:
+			snd_soc_component_update_bits(component, RT5665_PWR_ANLG_1,
+				RT5665_PWR_FV1, RT5665_PWR_FV1);
+			break;
+
+		case RT5665_PWR_VREF2_BIT:
+			snd_soc_component_update_bits(component, RT5665_PWR_ANLG_1,
+				RT5665_PWR_FV2, RT5665_PWR_FV2);
+			break;
+
+		case RT5665_PWR_VREF3_BIT:
+			snd_soc_component_update_bits(component, RT5665_PWR_ANLG_1,
+				RT5665_PWR_FV3, RT5665_PWR_FV3);
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5665_i2s_pin_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	unsigned int val1, val2, mask1 = 0, mask2 = 0;
+
+	switch (w->shift) {
+	case RT5665_PWR_I2S2_1_BIT:
+		mask1 = RT5665_GP2_PIN_MASK | RT5665_GP3_PIN_MASK |
+			RT5665_GP4_PIN_MASK | RT5665_GP5_PIN_MASK;
+		val1 = RT5665_GP2_PIN_BCLK2 | RT5665_GP3_PIN_LRCK2 |
+			RT5665_GP4_PIN_DACDAT2_1 | RT5665_GP5_PIN_ADCDAT2_1;
+		break;
+	case RT5665_PWR_I2S2_2_BIT:
+		mask1 = RT5665_GP2_PIN_MASK | RT5665_GP3_PIN_MASK |
+			RT5665_GP8_PIN_MASK;
+		val1 = RT5665_GP2_PIN_BCLK2 | RT5665_GP3_PIN_LRCK2 |
+			RT5665_GP8_PIN_DACDAT2_2;
+		mask2 = RT5665_GP9_PIN_MASK;
+		val2 = RT5665_GP9_PIN_ADCDAT2_2;
+		break;
+	case RT5665_PWR_I2S3_BIT:
+		mask1 = RT5665_GP6_PIN_MASK | RT5665_GP7_PIN_MASK |
+			RT5665_GP8_PIN_MASK;
+		val1 = RT5665_GP6_PIN_BCLK3 | RT5665_GP7_PIN_LRCK3 |
+			RT5665_GP8_PIN_DACDAT3;
+		mask2 = RT5665_GP9_PIN_MASK;
+		val2 = RT5665_GP9_PIN_ADCDAT3;
+		break;
+	}
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (mask1)
+			snd_soc_component_update_bits(component, RT5665_GPIO_CTRL_1,
+					    mask1, val1);
+		if (mask2)
+			snd_soc_component_update_bits(component, RT5665_GPIO_CTRL_2,
+					    mask2, val2);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (mask1)
+			snd_soc_component_update_bits(component, RT5665_GPIO_CTRL_1,
+					    mask1, 0);
+		if (mask2)
+			snd_soc_component_update_bits(component, RT5665_GPIO_CTRL_2,
+					    mask2, 0);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5665_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("LDO2", RT5665_PWR_ANLG_3, RT5665_PWR_LDO2_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL", RT5665_PWR_ANLG_3, RT5665_PWR_PLL_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5665_PWR_VOL,
+		RT5665_PWR_MIC_DET_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Vref1", RT5665_PWR_ANLG_1, RT5665_PWR_VREF1_BIT, 0,
+		rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("Vref2", RT5665_PWR_ANLG_1, RT5665_PWR_VREF2_BIT, 0,
+		rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("Vref3", RT5665_PWR_ANLG_1, RT5665_PWR_VREF3_BIT, 0,
+		rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5665_ASRC_1,
+		RT5665_I2S1_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5665_ASRC_1,
+		RT5665_I2S2_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5665_ASRC_1,
+		RT5665_I2S3_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5665_ASRC_1,
+		RT5665_DAC_STO1_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC STO2 ASRC", 1, RT5665_ASRC_1,
+		RT5665_DAC_STO2_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC Mono L ASRC", 1, RT5665_ASRC_1,
+		RT5665_DAC_MONO_L_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC Mono R ASRC", 1, RT5665_ASRC_1,
+		RT5665_DAC_MONO_R_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5665_ASRC_1,
+		RT5665_ADC_STO1_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5665_ASRC_1,
+		RT5665_ADC_STO2_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC Mono L ASRC", 1, RT5665_ASRC_1,
+		RT5665_ADC_MONO_L_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC Mono R ASRC", 1, RT5665_ASRC_1,
+		RT5665_ADC_MONO_R_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5665_ASRC_1,
+		RT5665_DMIC_STO1_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5665_ASRC_1,
+		RT5665_DMIC_STO2_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5665_ASRC_1,
+		RT5665_DMIC_MONO_L_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5665_ASRC_1,
+		RT5665_DMIC_MONO_R_ASRC_SFT, 0, NULL, 0),
+
+	/* Input Side */
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5665_PWR_ANLG_2, RT5665_PWR_MB1_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5665_PWR_ANLG_2, RT5665_PWR_MB2_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS3", RT5665_PWR_ANLG_2, RT5665_PWR_MB3_BIT,
+		0, NULL, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC L1"),
+	SND_SOC_DAPM_INPUT("DMIC R1"),
+	SND_SOC_DAPM_INPUT("DMIC L2"),
+	SND_SOC_DAPM_INPUT("DMIC R2"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN1N"),
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN2N"),
+	SND_SOC_DAPM_INPUT("IN3P"),
+	SND_SOC_DAPM_INPUT("IN3N"),
+	SND_SOC_DAPM_INPUT("IN4P"),
+	SND_SOC_DAPM_INPUT("IN4N"),
+
+	SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+		set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5665_DMIC_CTRL_1,
+		RT5665_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5665_DMIC_CTRL_1,
+		RT5665_DMIC_2_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST2", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST3", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST4", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST1 Power", RT5665_PWR_ANLG_2,
+		RT5665_PWR_BST1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST2 Power", RT5665_PWR_ANLG_2,
+		RT5665_PWR_BST2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST3 Power", RT5665_PWR_ANLG_2,
+		RT5665_PWR_BST3_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST4 Power", RT5665_PWR_ANLG_2,
+		RT5665_PWR_BST4_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST1P Power", RT5665_PWR_ANLG_2,
+		RT5665_PWR_BST1_P_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST2P Power", RT5665_PWR_ANLG_2,
+		RT5665_PWR_BST2_P_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST3P Power", RT5665_PWR_ANLG_2,
+		RT5665_PWR_BST3_P_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST4P Power", RT5665_PWR_ANLG_2,
+		RT5665_PWR_BST4_P_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CBJ Power", RT5665_PWR_ANLG_3,
+		RT5665_PWR_CBJ_BIT, 0, NULL, 0),
+
+
+	/* Input Volume */
+	SND_SOC_DAPM_PGA("INL VOL", RT5665_PWR_VOL, RT5665_PWR_IN_L_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR VOL", RT5665_PWR_VOL, RT5665_PWR_IN_R_BIT,
+		0, NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5665_rec1_l_mix,
+		ARRAY_SIZE(rt5665_rec1_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5665_rec1_r_mix,
+		ARRAY_SIZE(rt5665_rec1_r_mix)),
+	SND_SOC_DAPM_MIXER("RECMIX2L", SND_SOC_NOPM, 0, 0, rt5665_rec2_l_mix,
+		ARRAY_SIZE(rt5665_rec2_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIX2R", SND_SOC_NOPM, 0, 0, rt5665_rec2_r_mix,
+		ARRAY_SIZE(rt5665_rec2_r_mix)),
+	SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5665_PWR_ANLG_2,
+		RT5665_PWR_RM1_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5665_PWR_ANLG_2,
+		RT5665_PWR_RM1_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RECMIX2L Power", RT5665_PWR_MIXER,
+		RT5665_PWR_RM2_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("RECMIX2R Power", RT5665_PWR_MIXER,
+		RT5665_PWR_RM2_R_BIT, 0, NULL, 0),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC2 L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC2 R", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5665_PWR_DIG_1,
+		RT5665_PWR_ADC_L1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5665_PWR_DIG_1,
+		RT5665_PWR_ADC_R1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC2 L Power", RT5665_PWR_DIG_1,
+		RT5665_PWR_ADC_L2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC2 R Power", RT5665_PWR_DIG_1,
+		RT5665_PWR_ADC_R2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1 clock", RT5665_CHOP_ADC,
+		RT5665_CKGEN_ADC1_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC2 clock", RT5665_CHOP_ADC,
+		RT5665_CKGEN_ADC2_SFT, 0, NULL, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("Stereo1 DMIC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto1_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo1 DMIC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto1_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto1_adc1l_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto1_adc1r_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto1_adc2l_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto1_adc2r_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto1_adcl_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto1_adcr_mux),
+	SND_SOC_DAPM_MUX("Stereo1 DD L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto1_dd_l_mux),
+	SND_SOC_DAPM_MUX("Stereo1 DD R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto1_dd_r_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_mono_adc_l2_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_mono_adc_r2_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_mono_adc_l1_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_mono_adc_r1_mux),
+	SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_mono_dmic_l_mux),
+	SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_mono_dmic_r_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_mono_adc_l_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_mono_adc_r_mux),
+	SND_SOC_DAPM_MUX("Mono DD L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_mono_dd_l_mux),
+	SND_SOC_DAPM_MUX("Mono DD R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_mono_dd_r_mux),
+	SND_SOC_DAPM_MUX("Stereo2 DMIC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto2_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo2 DMIC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto2_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto2_adc1l_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto2_adc1r_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto2_adc2l_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto2_adc2r_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto2_adcl_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto2_adcr_mux),
+	SND_SOC_DAPM_MUX("Stereo2 DD L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto2_dd_l_mux),
+	SND_SOC_DAPM_MUX("Stereo2 DD R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_sto2_dd_r_mux),
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5665_PWR_DIG_2,
+		RT5665_PWR_ADC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5665_PWR_DIG_2,
+		RT5665_PWR_ADC_S2F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", RT5665_STO1_ADC_DIG_VOL,
+		RT5665_L_MUTE_SFT, 1, rt5665_sto1_adc_l_mix,
+		ARRAY_SIZE(rt5665_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5665_STO1_ADC_DIG_VOL,
+		RT5665_R_MUTE_SFT, 1, rt5665_sto1_adc_r_mix,
+		ARRAY_SIZE(rt5665_sto1_adc_r_mix)),
+	SND_SOC_DAPM_MIXER("Stereo2 ADC MIXL", RT5665_STO2_ADC_DIG_VOL,
+		RT5665_L_MUTE_SFT, 1, rt5665_sto2_adc_l_mix,
+		ARRAY_SIZE(rt5665_sto2_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo2 ADC MIXR", RT5665_STO2_ADC_DIG_VOL,
+		RT5665_R_MUTE_SFT, 1, rt5665_sto2_adc_r_mix,
+		ARRAY_SIZE(rt5665_sto2_adc_r_mix)),
+	SND_SOC_DAPM_SUPPLY("ADC Mono Left Filter", RT5665_PWR_DIG_2,
+		RT5665_PWR_ADC_MF_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mono ADC MIXL", RT5665_MONO_ADC_DIG_VOL,
+		RT5665_L_MUTE_SFT, 1, rt5665_mono_adc_l_mix,
+		ARRAY_SIZE(rt5665_mono_adc_l_mix)),
+	SND_SOC_DAPM_SUPPLY("ADC Mono Right Filter", RT5665_PWR_DIG_2,
+		RT5665_PWR_ADC_MF_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mono ADC MIXR", RT5665_MONO_ADC_DIG_VOL,
+		RT5665_R_MUTE_SFT, 1, rt5665_mono_adc_r_mix,
+		ARRAY_SIZE(rt5665_mono_adc_r_mix)),
+
+	/* ADC PGA */
+	SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo2 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1_1", RT5665_PWR_DIG_1, RT5665_PWR_I2S1_1_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("I2S1_2", RT5665_PWR_DIG_1, RT5665_PWR_I2S1_2_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("I2S2_1", RT5665_PWR_DIG_1, RT5665_PWR_I2S2_1_BIT,
+		0, rt5665_i2s_pin_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("I2S2_2", RT5665_PWR_DIG_1, RT5665_PWR_I2S2_2_BIT,
+		0, rt5665_i2s_pin_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("I2S3", RT5665_PWR_DIG_1, RT5665_PWR_I2S3_BIT,
+		0, rt5665_i2s_pin_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC3 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC3 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("IF2_1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2_2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2_1 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2_1 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2_2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2_2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2_1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2_2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface Select */
+	SND_SOC_DAPM_MUX("IF1_1_ADC1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_if1_1_adc1_mux),
+	SND_SOC_DAPM_MUX("IF1_1_ADC2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_if1_1_adc2_mux),
+	SND_SOC_DAPM_MUX("IF1_1_ADC3 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_if1_1_adc3_mux),
+	SND_SOC_DAPM_PGA("IF1_1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("IF1_2_ADC1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_if1_2_adc1_mux),
+	SND_SOC_DAPM_MUX("IF1_2_ADC2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_if1_2_adc2_mux),
+	SND_SOC_DAPM_MUX("IF1_2_ADC3 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_if1_2_adc3_mux),
+	SND_SOC_DAPM_MUX("IF1_2_ADC4 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_if1_2_adc4_mux),
+	SND_SOC_DAPM_MUX("TDM1 slot 01 Data Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_tdm1_adc_mux),
+	SND_SOC_DAPM_MUX("TDM1 slot 23 Data Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_tdm1_adc_mux),
+	SND_SOC_DAPM_MUX("TDM1 slot 45 Data Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_tdm1_adc_mux),
+	SND_SOC_DAPM_MUX("TDM1 slot 67 Data Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_tdm1_adc_mux),
+	SND_SOC_DAPM_MUX("TDM2 slot 01 Data Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_tdm2_adc_mux),
+	SND_SOC_DAPM_MUX("TDM2 slot 23 Data Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_tdm2_adc_mux),
+	SND_SOC_DAPM_MUX("TDM2 slot 45 Data Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_tdm2_adc_mux),
+	SND_SOC_DAPM_MUX("TDM2 slot 67 Data Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_tdm2_adc_mux),
+	SND_SOC_DAPM_MUX("IF2_1 ADC Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_if2_1_adc_in_mux),
+	SND_SOC_DAPM_MUX("IF2_2 ADC Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_if2_2_adc_in_mux),
+	SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0,
+		&rt5665_if3_adc_in_mux),
+	SND_SOC_DAPM_MUX("IF1_1 0 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_1_01_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_1 1 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_1_01_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_1 2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_1_23_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_1 3 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_1_23_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_1 4 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_1_45_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_1 5 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_1_45_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_1 6 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_1_67_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_1 7 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_1_67_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_2 0 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_2_01_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_2 1 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_2_01_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_2 2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_2_23_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_2 3 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_2_23_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_2 4 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_2_45_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_2 5 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_2_45_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_2 6 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_2_67_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1_2 7 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if1_2_67_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF2_1 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if2_1_dac_swap_mux),
+	SND_SOC_DAPM_MUX("IF2_1 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if2_1_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF2_2 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if2_2_dac_swap_mux),
+	SND_SOC_DAPM_MUX("IF2_2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if2_2_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF3 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if3_dac_swap_mux),
+	SND_SOC_DAPM_MUX("IF3 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5665_if3_adc_swap_mux),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 0", "AIF1_1 Capture",
+				0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 1", "AIF1_1 Capture",
+				1, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 2", "AIF1_1 Capture",
+				2, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 3", "AIF1_1 Capture",
+				3, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 4", "AIF1_1 Capture",
+				4, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 5", "AIF1_1 Capture",
+				5, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 6", "AIF1_1 Capture",
+				6, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 7", "AIF1_1 Capture",
+				7, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 0", "AIF1_2 Capture",
+				0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 1", "AIF1_2 Capture",
+				1, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 2", "AIF1_2 Capture",
+				2, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 3", "AIF1_2 Capture",
+				3, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 4", "AIF1_2 Capture",
+				4, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 5", "AIF1_2 Capture",
+				5, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 6", "AIF1_2 Capture",
+				6, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 7", "AIF1_2 Capture",
+				7, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2_1TX", "AIF2_1 Capture",
+				0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2_2TX", "AIF2_2 Capture",
+				0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF3TX", "AIF3 Capture",
+				0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback",
+				0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2_1RX", "AIF2_1 Playback",
+				0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2_2RX", "AIF2_2 Playback",
+				0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF3RX", "AIF3 Playback",
+				0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Side */
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
+		rt5665_dac_l_mix, ARRAY_SIZE(rt5665_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+		rt5665_dac_r_mix, ARRAY_SIZE(rt5665_dac_r_mix)),
+
+	/* DAC channel Mux */
+	SND_SOC_DAPM_MUX("DAC L1 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l1_mux),
+	SND_SOC_DAPM_MUX("DAC R1 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r1_mux),
+	SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l2_mux),
+	SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r2_mux),
+	SND_SOC_DAPM_MUX("DAC L3 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l3_mux),
+	SND_SOC_DAPM_MUX("DAC R3 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r3_mux),
+
+	SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0,
+		&rt5665_alg_dac_l1_mux),
+	SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0,
+		&rt5665_alg_dac_r1_mux),
+	SND_SOC_DAPM_MUX("DAC L2 Source", SND_SOC_NOPM, 0, 0,
+		&rt5665_alg_dac_l2_mux),
+	SND_SOC_DAPM_MUX("DAC R2 Source", SND_SOC_NOPM, 0, 0,
+		&rt5665_alg_dac_r2_mux),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5665_PWR_DIG_2,
+		RT5665_PWR_DAC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Stereo2 Filter", RT5665_PWR_DIG_2,
+		RT5665_PWR_DAC_S2F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Mono Left Filter", RT5665_PWR_DIG_2,
+		RT5665_PWR_DAC_MF_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Mono Right Filter", RT5665_PWR_DIG_2,
+		RT5665_PWR_DAC_MF_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo1 DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5665_sto1_dac_l_mix, ARRAY_SIZE(rt5665_sto1_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo1 DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5665_sto1_dac_r_mix, ARRAY_SIZE(rt5665_sto1_dac_r_mix)),
+	SND_SOC_DAPM_MIXER("Stereo2 DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5665_sto2_dac_l_mix, ARRAY_SIZE(rt5665_sto2_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo2 DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5665_sto2_dac_r_mix, ARRAY_SIZE(rt5665_sto2_dac_r_mix)),
+	SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5665_mono_dac_l_mix, ARRAY_SIZE(rt5665_mono_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5665_mono_dac_r_mix, ARRAY_SIZE(rt5665_mono_dac_r_mix)),
+	SND_SOC_DAPM_MUX("DAC MIXL", SND_SOC_NOPM, 0, 0,
+		&rt5665_dig_dac_mixl_mux),
+	SND_SOC_DAPM_MUX("DAC MIXR", SND_SOC_NOPM, 0, 0,
+		&rt5665_dig_dac_mixr_mux),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5665_PWR_DIG_1,
+		RT5665_PWR_DAC_L2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5665_PWR_DIG_1,
+		RT5665_PWR_DAC_R2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("DAC L2", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC R2", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_PGA("DAC1 MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY_S("DAC 1 Clock", 1, RT5665_CHOP_DAC,
+		RT5665_CKGEN_DAC1_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC 2 Clock", 1, RT5665_CHOP_DAC,
+		RT5665_CKGEN_DAC2_SFT, 0, NULL, 0),
+
+	/* OUT Mixer */
+	SND_SOC_DAPM_MIXER("MONOVOL MIX", RT5665_PWR_MIXER, RT5665_PWR_MM_BIT,
+		0, rt5665_monovol_mix, ARRAY_SIZE(rt5665_monovol_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXL", RT5665_PWR_MIXER, RT5665_PWR_OM_L_BIT,
+		0, rt5665_out_l_mix, ARRAY_SIZE(rt5665_out_l_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXR", RT5665_PWR_MIXER, RT5665_PWR_OM_R_BIT,
+		0, rt5665_out_r_mix, ARRAY_SIZE(rt5665_out_r_mix)),
+
+	/* Output Volume */
+	SND_SOC_DAPM_SWITCH("MONOVOL", RT5665_PWR_VOL, RT5665_PWR_MV_BIT, 0,
+		&monovol_switch),
+	SND_SOC_DAPM_SWITCH("OUTVOL L", RT5665_PWR_VOL, RT5665_PWR_OV_L_BIT, 0,
+		&outvol_l_switch),
+	SND_SOC_DAPM_SWITCH("OUTVOL R", RT5665_PWR_VOL, RT5665_PWR_OV_R_BIT, 0,
+		&outvol_r_switch),
+
+	/* MONO/HPO/LOUT */
+	SND_SOC_DAPM_MIXER("Mono MIX", SND_SOC_NOPM, 0,	0, rt5665_mono_mix,
+		ARRAY_SIZE(rt5665_mono_mix)),
+	SND_SOC_DAPM_MIXER("LOUT L MIX", SND_SOC_NOPM, 0, 0, rt5665_lout_l_mix,
+		ARRAY_SIZE(rt5665_lout_l_mix)),
+	SND_SOC_DAPM_MIXER("LOUT R MIX", SND_SOC_NOPM, 0, 0, rt5665_lout_r_mix,
+		ARRAY_SIZE(rt5665_lout_r_mix)),
+	SND_SOC_DAPM_PGA_S("Mono Amp", 1, RT5665_PWR_ANLG_1, RT5665_PWR_MA_BIT,
+		0, rt5665_mono_event, SND_SOC_DAPM_POST_PMD |
+		SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5665_hp_event,
+		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_PGA_S("LOUT Amp", 1, RT5665_PWR_ANLG_1,
+		RT5665_PWR_LM_BIT, 0, rt5665_lout_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
+
+	SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0,
+		rt5665_charge_pump_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SWITCH("Mono Playback", SND_SOC_NOPM, 0, 0,
+		&mono_switch),
+	SND_SOC_DAPM_SWITCH("HPO Playback", SND_SOC_NOPM, 0, 0,
+		&hpo_switch),
+	SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0,
+		&lout_l_switch),
+	SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0,
+		&lout_r_switch),
+	SND_SOC_DAPM_SWITCH("PDM L Playback", SND_SOC_NOPM, 0, 0,
+		&pdm_l_switch),
+	SND_SOC_DAPM_SWITCH("PDM R Playback", SND_SOC_NOPM, 0, 0,
+		&pdm_r_switch),
+
+	/* PDM */
+	SND_SOC_DAPM_SUPPLY("PDM Power", RT5665_PWR_DIG_2,
+		RT5665_PWR_PDM1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("PDM L Mux", SND_SOC_NOPM,
+		0, 1, &rt5665_pdm_l_mux),
+	SND_SOC_DAPM_MUX("PDM R Mux", SND_SOC_NOPM,
+		0, 1, &rt5665_pdm_r_mux),
+
+	/* CLK DET */
+	SND_SOC_DAPM_SUPPLY("CLKDET SYS", RT5665_CLK_DET, RT5665_SYS_CLK_DET,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET HP", RT5665_CLK_DET, RT5665_HP_CLK_DET,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET MONO", RT5665_CLK_DET, RT5665_MONO_CLK_DET,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET LOUT", RT5665_CLK_DET, RT5665_LOUT_CLK_DET,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET", RT5665_CLK_DET, RT5665_POW_CLK_DET,
+		0, NULL, 0),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+	SND_SOC_DAPM_OUTPUT("LOUTL"),
+	SND_SOC_DAPM_OUTPUT("LOUTR"),
+	SND_SOC_DAPM_OUTPUT("MONOOUT"),
+	SND_SOC_DAPM_OUTPUT("PDML"),
+	SND_SOC_DAPM_OUTPUT("PDMR"),
+};
+
+static const struct snd_soc_dapm_route rt5665_dapm_routes[] = {
+	/*PLL*/
+	{"ADC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll},
+	{"ADC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll},
+	{"ADC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll},
+	{"ADC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll},
+	{"DAC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll},
+	{"DAC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll},
+	{"DAC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll},
+	{"DAC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll},
+
+	/*ASRC*/
+	{"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc},
+	{"ADC Stereo2 Filter", NULL, "ADC STO2 ASRC", is_using_asrc},
+	{"ADC Mono Left Filter", NULL, "ADC Mono L ASRC", is_using_asrc},
+	{"ADC Mono Right Filter", NULL, "ADC Mono R ASRC", is_using_asrc},
+	{"DAC Mono Left Filter", NULL, "DAC Mono L ASRC", is_using_asrc},
+	{"DAC Mono Right Filter", NULL, "DAC Mono R ASRC", is_using_asrc},
+	{"DAC Stereo1 Filter", NULL, "DAC STO1 ASRC", is_using_asrc},
+	{"DAC Stereo2 Filter", NULL, "DAC STO2 ASRC", is_using_asrc},
+	{"I2S1 ASRC", NULL, "CLKDET"},
+	{"I2S2 ASRC", NULL, "CLKDET"},
+	{"I2S3 ASRC", NULL, "CLKDET"},
+
+	/*Vref*/
+	{"Mic Det Power", NULL, "Vref2"},
+	{"MICBIAS1", NULL, "Vref1"},
+	{"MICBIAS1", NULL, "Vref2"},
+	{"MICBIAS2", NULL, "Vref1"},
+	{"MICBIAS2", NULL, "Vref2"},
+	{"MICBIAS3", NULL, "Vref1"},
+	{"MICBIAS3", NULL, "Vref2"},
+
+	{"Stereo1 DMIC L Mux", NULL, "DMIC STO1 ASRC"},
+	{"Stereo1 DMIC R Mux", NULL, "DMIC STO1 ASRC"},
+	{"Stereo2 DMIC L Mux", NULL, "DMIC STO2 ASRC"},
+	{"Stereo2 DMIC R Mux", NULL, "DMIC STO2 ASRC"},
+	{"Mono DMIC L Mux", NULL, "DMIC MONO L ASRC"},
+	{"Mono DMIC R Mux", NULL, "DMIC MONO R ASRC"},
+
+	{"I2S1_1", NULL, "I2S1 ASRC"},
+	{"I2S1_2", NULL, "I2S1 ASRC"},
+	{"I2S2_1", NULL, "I2S2 ASRC"},
+	{"I2S2_2", NULL, "I2S2 ASRC"},
+	{"I2S3", NULL, "I2S3 ASRC"},
+
+	{"CLKDET SYS", NULL, "CLKDET"},
+	{"CLKDET HP", NULL, "CLKDET"},
+	{"CLKDET MONO", NULL, "CLKDET"},
+	{"CLKDET LOUT", NULL, "CLKDET"},
+
+	{"IN1P", NULL, "LDO2"},
+	{"IN2P", NULL, "LDO2"},
+	{"IN3P", NULL, "LDO2"},
+	{"IN4P", NULL, "LDO2"},
+
+	{"DMIC1", NULL, "DMIC L1"},
+	{"DMIC1", NULL, "DMIC R1"},
+	{"DMIC2", NULL, "DMIC L2"},
+	{"DMIC2", NULL, "DMIC R2"},
+
+	{"BST1", NULL, "IN1P"},
+	{"BST1", NULL, "IN1N"},
+	{"BST1", NULL, "BST1 Power"},
+	{"BST1", NULL, "BST1P Power"},
+	{"BST2", NULL, "IN2P"},
+	{"BST2", NULL, "IN2N"},
+	{"BST2", NULL, "BST2 Power"},
+	{"BST2", NULL, "BST2P Power"},
+	{"BST3", NULL, "IN3P"},
+	{"BST3", NULL, "IN3N"},
+	{"BST3", NULL, "BST3 Power"},
+	{"BST3", NULL, "BST3P Power"},
+	{"BST4", NULL, "IN4P"},
+	{"BST4", NULL, "IN4N"},
+	{"BST4", NULL, "BST4 Power"},
+	{"BST4", NULL, "BST4P Power"},
+	{"BST1 CBJ", NULL, "IN1P"},
+	{"BST1 CBJ", NULL, "IN1N"},
+	{"BST1 CBJ", NULL, "CBJ Power"},
+	{"CBJ Power", NULL, "Vref2"},
+
+	{"INL VOL", NULL, "IN3P"},
+	{"INR VOL", NULL, "IN3N"},
+
+	{"RECMIX1L", "CBJ Switch", "BST1 CBJ"},
+	{"RECMIX1L", "INL Switch", "INL VOL"},
+	{"RECMIX1L", "INR Switch", "INR VOL"},
+	{"RECMIX1L", "BST4 Switch", "BST4"},
+	{"RECMIX1L", "BST3 Switch", "BST3"},
+	{"RECMIX1L", "BST2 Switch", "BST2"},
+	{"RECMIX1L", "BST1 Switch", "BST1"},
+	{"RECMIX1L", NULL, "RECMIX1L Power"},
+
+	{"RECMIX1R", "MONOVOL Switch", "MONOVOL"},
+	{"RECMIX1R", "INR Switch", "INR VOL"},
+	{"RECMIX1R", "BST4 Switch", "BST4"},
+	{"RECMIX1R", "BST3 Switch", "BST3"},
+	{"RECMIX1R", "BST2 Switch", "BST2"},
+	{"RECMIX1R", "BST1 Switch", "BST1"},
+	{"RECMIX1R", NULL, "RECMIX1R Power"},
+
+	{"RECMIX2L", "CBJ Switch", "BST1 CBJ"},
+	{"RECMIX2L", "INL Switch", "INL VOL"},
+	{"RECMIX2L", "INR Switch", "INR VOL"},
+	{"RECMIX2L", "BST4 Switch", "BST4"},
+	{"RECMIX2L", "BST3 Switch", "BST3"},
+	{"RECMIX2L", "BST2 Switch", "BST2"},
+	{"RECMIX2L", "BST1 Switch", "BST1"},
+	{"RECMIX2L", NULL, "RECMIX2L Power"},
+
+	{"RECMIX2R", "MONOVOL Switch", "MONOVOL"},
+	{"RECMIX2R", "INL Switch", "INL VOL"},
+	{"RECMIX2R", "INR Switch", "INR VOL"},
+	{"RECMIX2R", "BST4 Switch", "BST4"},
+	{"RECMIX2R", "BST3 Switch", "BST3"},
+	{"RECMIX2R", "BST2 Switch", "BST2"},
+	{"RECMIX2R", "BST1 Switch", "BST1"},
+	{"RECMIX2R", NULL, "RECMIX2R Power"},
+
+	{"ADC1 L", NULL, "RECMIX1L"},
+	{"ADC1 L", NULL, "ADC1 L Power"},
+	{"ADC1 L", NULL, "ADC1 clock"},
+	{"ADC1 R", NULL, "RECMIX1R"},
+	{"ADC1 R", NULL, "ADC1 R Power"},
+	{"ADC1 R", NULL, "ADC1 clock"},
+
+	{"ADC2 L", NULL, "RECMIX2L"},
+	{"ADC2 L", NULL, "ADC2 L Power"},
+	{"ADC2 L", NULL, "ADC2 clock"},
+	{"ADC2 R", NULL, "RECMIX2R"},
+	{"ADC2 R", NULL, "ADC2 R Power"},
+	{"ADC2 R", NULL, "ADC2 clock"},
+
+	{"DMIC L1", NULL, "DMIC CLK"},
+	{"DMIC L1", NULL, "DMIC1 Power"},
+	{"DMIC R1", NULL, "DMIC CLK"},
+	{"DMIC R1", NULL, "DMIC1 Power"},
+	{"DMIC L2", NULL, "DMIC CLK"},
+	{"DMIC L2", NULL, "DMIC2 Power"},
+	{"DMIC R2", NULL, "DMIC CLK"},
+	{"DMIC R2", NULL, "DMIC2 Power"},
+
+	{"Stereo1 DMIC L Mux", "DMIC1", "DMIC L1"},
+	{"Stereo1 DMIC L Mux", "DMIC2", "DMIC L2"},
+
+	{"Stereo1 DMIC R Mux", "DMIC1", "DMIC R1"},
+	{"Stereo1 DMIC R Mux", "DMIC2", "DMIC R2"},
+
+	{"Mono DMIC L Mux", "DMIC1 L", "DMIC L1"},
+	{"Mono DMIC L Mux", "DMIC2 L", "DMIC L2"},
+
+	{"Mono DMIC R Mux", "DMIC1 R", "DMIC R1"},
+	{"Mono DMIC R Mux", "DMIC2 R", "DMIC R2"},
+
+	{"Stereo2 DMIC L Mux", "DMIC1", "DMIC L1"},
+	{"Stereo2 DMIC L Mux", "DMIC2", "DMIC L2"},
+
+	{"Stereo2 DMIC R Mux", "DMIC1", "DMIC R1"},
+	{"Stereo2 DMIC R Mux", "DMIC2", "DMIC R2"},
+
+	{"Stereo1 ADC L Mux", "ADC1 L", "ADC1 L"},
+	{"Stereo1 ADC L Mux", "ADC1 R", "ADC1 R"},
+	{"Stereo1 ADC L Mux", "ADC2 L", "ADC2 L"},
+	{"Stereo1 ADC L Mux", "ADC2 R", "ADC2 R"},
+	{"Stereo1 ADC R Mux", "ADC1 L", "ADC1 L"},
+	{"Stereo1 ADC R Mux", "ADC1 R", "ADC1 R"},
+	{"Stereo1 ADC R Mux", "ADC2 L", "ADC2 L"},
+	{"Stereo1 ADC R Mux", "ADC2 R", "ADC2 R"},
+
+	{"Stereo1 DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"},
+	{"Stereo1 DD L Mux", "MONO DAC", "Mono DAC MIXL"},
+
+	{"Stereo1 DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"},
+	{"Stereo1 DD R Mux", "MONO DAC", "Mono DAC MIXR"},
+
+	{"Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux"},
+	{"Stereo1 ADC L1 Mux", "DD Mux", "Stereo1 DD L Mux"},
+	{"Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC L Mux"},
+	{"Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL"},
+
+	{"Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux"},
+	{"Stereo1 ADC R1 Mux", "DD Mux", "Stereo1 DD R Mux"},
+	{"Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC R Mux"},
+	{"Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR"},
+
+	{"Mono ADC L Mux", "ADC1 L", "ADC1 L"},
+	{"Mono ADC L Mux", "ADC1 R", "ADC1 R"},
+	{"Mono ADC L Mux", "ADC2 L", "ADC2 L"},
+	{"Mono ADC L Mux", "ADC2 R", "ADC2 R"},
+
+	{"Mono ADC R Mux", "ADC1 L", "ADC1 L"},
+	{"Mono ADC R Mux", "ADC1 R", "ADC1 R"},
+	{"Mono ADC R Mux", "ADC2 L", "ADC2 L"},
+	{"Mono ADC R Mux", "ADC2 R", "ADC2 R"},
+
+	{"Mono DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"},
+	{"Mono DD L Mux", "MONO DAC", "Mono DAC MIXL"},
+
+	{"Mono DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"},
+	{"Mono DD R Mux", "MONO DAC", "Mono DAC MIXR"},
+
+	{"Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux"},
+	{"Mono ADC L2 Mux", "DAC MIXL", "DAC MIXL"},
+	{"Mono ADC L1 Mux", "DD Mux", "Mono DD L Mux"},
+	{"Mono ADC L1 Mux", "ADC",  "Mono ADC L Mux"},
+
+	{"Mono ADC R1 Mux", "DD Mux", "Mono DD R Mux"},
+	{"Mono ADC R1 Mux", "ADC", "Mono ADC R Mux"},
+	{"Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux"},
+	{"Mono ADC R2 Mux", "DAC MIXR", "DAC MIXR"},
+
+	{"Stereo2 ADC L Mux", "ADC1 L", "ADC1 L"},
+	{"Stereo2 ADC L Mux", "ADC2 L", "ADC2 L"},
+	{"Stereo2 ADC L Mux", "ADC1 R", "ADC1 R"},
+	{"Stereo2 ADC R Mux", "ADC1 L", "ADC1 L"},
+	{"Stereo2 ADC R Mux", "ADC2 L", "ADC2 L"},
+	{"Stereo2 ADC R Mux", "ADC1 R", "ADC1 R"},
+
+	{"Stereo2 DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"},
+	{"Stereo2 DD L Mux", "MONO DAC", "Mono DAC MIXL"},
+
+	{"Stereo2 DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"},
+	{"Stereo2 DD R Mux", "MONO DAC", "Mono DAC MIXR"},
+
+	{"Stereo2 ADC L1 Mux", "ADC", "Stereo2 ADC L Mux"},
+	{"Stereo2 ADC L1 Mux", "DD Mux", "Stereo2 DD L Mux"},
+	{"Stereo2 ADC L2 Mux", "DMIC", "Stereo2 DMIC L Mux"},
+	{"Stereo2 ADC L2 Mux", "DAC MIX", "DAC MIXL"},
+
+	{"Stereo2 ADC R1 Mux", "ADC", "Stereo2 ADC R Mux"},
+	{"Stereo2 ADC R1 Mux", "DD Mux", "Stereo2 DD R Mux"},
+	{"Stereo2 ADC R2 Mux", "DMIC", "Stereo2 DMIC R Mux"},
+	{"Stereo2 ADC R2 Mux", "DAC MIX", "DAC MIXR"},
+
+	{"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"},
+	{"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"},
+	{"Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter"},
+
+	{"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"},
+	{"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"},
+	{"Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter"},
+
+	{"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"},
+	{"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"},
+	{"Mono ADC MIXL", NULL, "ADC Mono Left Filter"},
+
+	{"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"},
+	{"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"},
+	{"Mono ADC MIXR", NULL, "ADC Mono Right Filter"},
+
+	{"Stereo2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC L1 Mux"},
+	{"Stereo2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC L2 Mux"},
+	{"Stereo2 ADC MIXL", NULL, "ADC Stereo2 Filter"},
+
+	{"Stereo2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC R1 Mux"},
+	{"Stereo2 ADC MIXR", "ADC2 Switch", "Stereo2 ADC R2 Mux"},
+	{"Stereo2 ADC MIXR", NULL, "ADC Stereo2 Filter"},
+
+	{"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL"},
+	{"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR"},
+	{"Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXL"},
+	{"Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXR"},
+	{"Mono ADC MIX", NULL, "Mono ADC MIXL"},
+	{"Mono ADC MIX", NULL, "Mono ADC MIXR"},
+
+	{"IF1_1_ADC1 Mux", "STO1 ADC", "Stereo1 ADC MIX"},
+	{"IF1_1_ADC1 Mux", "IF2_1 DAC", "IF2_1 DAC"},
+	{"IF1_1_ADC2 Mux", "STO2 ADC", "Stereo2 ADC MIX"},
+	{"IF1_1_ADC2 Mux", "IF2_2 DAC", "IF2_2 DAC"},
+	{"IF1_1_ADC3 Mux", "MONO ADC", "Mono ADC MIX"},
+	{"IF1_1_ADC3 Mux", "IF3 DAC", "IF3 DAC"},
+	{"IF1_1_ADC4", NULL, "DAC1 MIX"},
+
+	{"IF1_2_ADC1 Mux", "STO1 ADC", "Stereo1 ADC MIX"},
+	{"IF1_2_ADC1 Mux", "IF1 DAC", "IF1 DAC1"},
+	{"IF1_2_ADC2 Mux", "STO2 ADC", "Stereo2 ADC MIX"},
+	{"IF1_2_ADC2 Mux", "IF2_1 DAC", "IF2_1 DAC"},
+	{"IF1_2_ADC3 Mux", "MONO ADC", "Mono ADC MIX"},
+	{"IF1_2_ADC3 Mux", "IF2_2 DAC", "IF2_2 DAC"},
+	{"IF1_2_ADC4 Mux", "DAC1", "DAC1 MIX"},
+	{"IF1_2_ADC4 Mux", "IF3 DAC", "IF3 DAC"},
+
+	{"TDM1 slot 01 Data Mux", "1234", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 01 Data Mux", "1243", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 01 Data Mux", "1324", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 01 Data Mux", "1342", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 01 Data Mux", "1432", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 01 Data Mux", "1423", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 01 Data Mux", "2134", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 01 Data Mux", "2143", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 01 Data Mux", "2314", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 01 Data Mux", "2341", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 01 Data Mux", "2431", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 01 Data Mux", "2413", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 01 Data Mux", "3124", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 01 Data Mux", "3142", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 01 Data Mux", "3214", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 01 Data Mux", "3241", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 01 Data Mux", "3412", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 01 Data Mux", "3421", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 01 Data Mux", "4123", "IF1_1_ADC4"},
+	{"TDM1 slot 01 Data Mux", "4132", "IF1_1_ADC4"},
+	{"TDM1 slot 01 Data Mux", "4213", "IF1_1_ADC4"},
+	{"TDM1 slot 01 Data Mux", "4231", "IF1_1_ADC4"},
+	{"TDM1 slot 01 Data Mux", "4312", "IF1_1_ADC4"},
+	{"TDM1 slot 01 Data Mux", "4321", "IF1_1_ADC4"},
+	{"TDM1 slot 01 Data Mux", NULL, "I2S1_1"},
+
+	{"TDM1 slot 23 Data Mux", "1234", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 23 Data Mux", "1243", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 23 Data Mux", "1324", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 23 Data Mux", "1342", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 23 Data Mux", "1432", "IF1_1_ADC4"},
+	{"TDM1 slot 23 Data Mux", "1423", "IF1_1_ADC4"},
+	{"TDM1 slot 23 Data Mux", "2134", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 23 Data Mux", "2143", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 23 Data Mux", "2314", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 23 Data Mux", "2341", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 23 Data Mux", "2431", "IF1_1_ADC4"},
+	{"TDM1 slot 23 Data Mux", "2413", "IF1_1_ADC4"},
+	{"TDM1 slot 23 Data Mux", "3124", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 23 Data Mux", "3142", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 23 Data Mux", "3214", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 23 Data Mux", "3241", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 23 Data Mux", "3412", "IF1_1_ADC4"},
+	{"TDM1 slot 23 Data Mux", "3421", "IF1_1_ADC4"},
+	{"TDM1 slot 23 Data Mux", "4123", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 23 Data Mux", "4132", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 23 Data Mux", "4213", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 23 Data Mux", "4231", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 23 Data Mux", "4312", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 23 Data Mux", "4321", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 23 Data Mux", NULL, "I2S1_1"},
+
+	{"TDM1 slot 45 Data Mux", "1234", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 45 Data Mux", "1243", "IF1_1_ADC4"},
+	{"TDM1 slot 45 Data Mux", "1324", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 45 Data Mux", "1342", "IF1_1_ADC4"},
+	{"TDM1 slot 45 Data Mux", "1432", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 45 Data Mux", "1423", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 45 Data Mux", "2134", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 45 Data Mux", "2143", "IF1_1_ADC4"},
+	{"TDM1 slot 45 Data Mux", "2314", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 45 Data Mux", "2341", "IF1_1_ADC4"},
+	{"TDM1 slot 45 Data Mux", "2431", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 45 Data Mux", "2413", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 45 Data Mux", "3124", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 45 Data Mux", "3142", "IF1_1_ADC4"},
+	{"TDM1 slot 45 Data Mux", "3214", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 45 Data Mux", "3241", "IF1_1_ADC4"},
+	{"TDM1 slot 45 Data Mux", "3412", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 45 Data Mux", "3421", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 45 Data Mux", "4123", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 45 Data Mux", "4132", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 45 Data Mux", "4213", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 45 Data Mux", "4231", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 45 Data Mux", "4312", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 45 Data Mux", "4321", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 45 Data Mux", NULL, "I2S1_1"},
+
+	{"TDM1 slot 67 Data Mux", "1234", "IF1_1_ADC4"},
+	{"TDM1 slot 67 Data Mux", "1243", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 67 Data Mux", "1324", "IF1_1_ADC4"},
+	{"TDM1 slot 67 Data Mux", "1342", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 67 Data Mux", "1432", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 67 Data Mux", "1423", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 67 Data Mux", "2134", "IF1_1_ADC4"},
+	{"TDM1 slot 67 Data Mux", "2143", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 67 Data Mux", "2314", "IF1_1_ADC4"},
+	{"TDM1 slot 67 Data Mux", "2341", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 67 Data Mux", "2431", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 67 Data Mux", "2413", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 67 Data Mux", "3124", "IF1_1_ADC4"},
+	{"TDM1 slot 67 Data Mux", "3142", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 67 Data Mux", "3214", "IF1_1_ADC4"},
+	{"TDM1 slot 67 Data Mux", "3241", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 67 Data Mux", "3412", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 67 Data Mux", "3421", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 67 Data Mux", "4123", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 67 Data Mux", "4132", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 67 Data Mux", "4213", "IF1_1_ADC3 Mux"},
+	{"TDM1 slot 67 Data Mux", "4231", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 67 Data Mux", "4312", "IF1_1_ADC2 Mux"},
+	{"TDM1 slot 67 Data Mux", "4321", "IF1_1_ADC1 Mux"},
+	{"TDM1 slot 67 Data Mux", NULL, "I2S1_1"},
+
+
+	{"TDM2 slot 01 Data Mux", "1234", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 01 Data Mux", "1243", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 01 Data Mux", "1324", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 01 Data Mux", "1342", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 01 Data Mux", "1432", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 01 Data Mux", "1423", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 01 Data Mux", "2134", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 01 Data Mux", "2143", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 01 Data Mux", "2314", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 01 Data Mux", "2341", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 01 Data Mux", "2431", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 01 Data Mux", "2413", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 01 Data Mux", "3124", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 01 Data Mux", "3142", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 01 Data Mux", "3214", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 01 Data Mux", "3241", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 01 Data Mux", "3412", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 01 Data Mux", "3421", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 01 Data Mux", "4123", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 01 Data Mux", "4132", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 01 Data Mux", "4213", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 01 Data Mux", "4231", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 01 Data Mux", "4312", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 01 Data Mux", "4321", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 01 Data Mux", NULL, "I2S1_2"},
+
+	{"TDM2 slot 23 Data Mux", "1234", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 23 Data Mux", "1243", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 23 Data Mux", "1324", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 23 Data Mux", "1342", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 23 Data Mux", "1432", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 23 Data Mux", "1423", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 23 Data Mux", "2134", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 23 Data Mux", "2143", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 23 Data Mux", "2314", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 23 Data Mux", "2341", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 23 Data Mux", "2431", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 23 Data Mux", "2413", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 23 Data Mux", "3124", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 23 Data Mux", "3142", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 23 Data Mux", "3214", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 23 Data Mux", "3241", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 23 Data Mux", "3412", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 23 Data Mux", "3421", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 23 Data Mux", "4123", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 23 Data Mux", "4132", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 23 Data Mux", "4213", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 23 Data Mux", "4231", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 23 Data Mux", "4312", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 23 Data Mux", "4321", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 23 Data Mux", NULL, "I2S1_2"},
+
+	{"TDM2 slot 45 Data Mux", "1234", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 45 Data Mux", "1243", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 45 Data Mux", "1324", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 45 Data Mux", "1342", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 45 Data Mux", "1432", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 45 Data Mux", "1423", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 45 Data Mux", "2134", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 45 Data Mux", "2143", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 45 Data Mux", "2314", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 45 Data Mux", "2341", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 45 Data Mux", "2431", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 45 Data Mux", "2413", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 45 Data Mux", "3124", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 45 Data Mux", "3142", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 45 Data Mux", "3214", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 45 Data Mux", "3241", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 45 Data Mux", "3412", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 45 Data Mux", "3421", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 45 Data Mux", "4123", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 45 Data Mux", "4132", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 45 Data Mux", "4213", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 45 Data Mux", "4231", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 45 Data Mux", "4312", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 45 Data Mux", "4321", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 45 Data Mux", NULL, "I2S1_2"},
+
+	{"TDM2 slot 67 Data Mux", "1234", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 67 Data Mux", "1243", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 67 Data Mux", "1324", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 67 Data Mux", "1342", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 67 Data Mux", "1432", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 67 Data Mux", "1423", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 67 Data Mux", "2134", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 67 Data Mux", "2143", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 67 Data Mux", "2314", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 67 Data Mux", "2341", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 67 Data Mux", "2431", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 67 Data Mux", "2413", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 67 Data Mux", "3124", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 67 Data Mux", "3142", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 67 Data Mux", "3214", "IF1_2_ADC4 Mux"},
+	{"TDM2 slot 67 Data Mux", "3241", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 67 Data Mux", "3412", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 67 Data Mux", "3421", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 67 Data Mux", "4123", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 67 Data Mux", "4132", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 67 Data Mux", "4213", "IF1_2_ADC3 Mux"},
+	{"TDM2 slot 67 Data Mux", "4231", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 67 Data Mux", "4312", "IF1_2_ADC2 Mux"},
+	{"TDM2 slot 67 Data Mux", "4321", "IF1_2_ADC1 Mux"},
+	{"TDM2 slot 67 Data Mux", NULL, "I2S1_2"},
+
+	{"IF1_1 0 ADC Swap Mux", "L/R", "TDM1 slot 01 Data Mux"},
+	{"IF1_1 0 ADC Swap Mux", "L/L", "TDM1 slot 01 Data Mux"},
+	{"IF1_1 1 ADC Swap Mux", "R/L", "TDM1 slot 01 Data Mux"},
+	{"IF1_1 1 ADC Swap Mux", "R/R", "TDM1 slot 01 Data Mux"},
+	{"IF1_1 2 ADC Swap Mux", "L/R", "TDM1 slot 23 Data Mux"},
+	{"IF1_1 2 ADC Swap Mux", "R/L", "TDM1 slot 23 Data Mux"},
+	{"IF1_1 3 ADC Swap Mux", "L/L", "TDM1 slot 23 Data Mux"},
+	{"IF1_1 3 ADC Swap Mux", "R/R", "TDM1 slot 23 Data Mux"},
+	{"IF1_1 4 ADC Swap Mux", "L/R", "TDM1 slot 45 Data Mux"},
+	{"IF1_1 4 ADC Swap Mux", "R/L", "TDM1 slot 45 Data Mux"},
+	{"IF1_1 5 ADC Swap Mux", "L/L", "TDM1 slot 45 Data Mux"},
+	{"IF1_1 5 ADC Swap Mux", "R/R", "TDM1 slot 45 Data Mux"},
+	{"IF1_1 6 ADC Swap Mux", "L/R", "TDM1 slot 67 Data Mux"},
+	{"IF1_1 6 ADC Swap Mux", "R/L", "TDM1 slot 67 Data Mux"},
+	{"IF1_1 7 ADC Swap Mux", "L/L", "TDM1 slot 67 Data Mux"},
+	{"IF1_1 7 ADC Swap Mux", "R/R", "TDM1 slot 67 Data Mux"},
+	{"IF1_2 0 ADC Swap Mux", "L/R", "TDM2 slot 01 Data Mux"},
+	{"IF1_2 0 ADC Swap Mux", "R/L", "TDM2 slot 01 Data Mux"},
+	{"IF1_2 1 ADC Swap Mux", "L/L", "TDM2 slot 01 Data Mux"},
+	{"IF1_2 1 ADC Swap Mux", "R/R", "TDM2 slot 01 Data Mux"},
+	{"IF1_2 2 ADC Swap Mux", "L/R", "TDM2 slot 23 Data Mux"},
+	{"IF1_2 2 ADC Swap Mux", "R/L", "TDM2 slot 23 Data Mux"},
+	{"IF1_2 3 ADC Swap Mux", "L/L", "TDM2 slot 23 Data Mux"},
+	{"IF1_2 3 ADC Swap Mux", "R/R", "TDM2 slot 23 Data Mux"},
+	{"IF1_2 4 ADC Swap Mux", "L/R", "TDM2 slot 45 Data Mux"},
+	{"IF1_2 4 ADC Swap Mux", "R/L", "TDM2 slot 45 Data Mux"},
+	{"IF1_2 5 ADC Swap Mux", "L/L", "TDM2 slot 45 Data Mux"},
+	{"IF1_2 5 ADC Swap Mux", "R/R", "TDM2 slot 45 Data Mux"},
+	{"IF1_2 6 ADC Swap Mux", "L/R", "TDM2 slot 67 Data Mux"},
+	{"IF1_2 6 ADC Swap Mux", "R/L", "TDM2 slot 67 Data Mux"},
+	{"IF1_2 7 ADC Swap Mux", "L/L", "TDM2 slot 67 Data Mux"},
+	{"IF1_2 7 ADC Swap Mux", "R/R", "TDM2 slot 67 Data Mux"},
+
+	{"IF2_1 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"},
+	{"IF2_1 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"},
+	{"IF2_1 ADC Mux", "MONO ADC", "Mono ADC MIX"},
+	{"IF2_1 ADC Mux", "IF1 DAC1", "IF1 DAC1"},
+	{"IF2_1 ADC Mux", "IF1 DAC2", "IF1 DAC2"},
+	{"IF2_1 ADC Mux", "IF2_2 DAC", "IF2_2 DAC"},
+	{"IF2_1 ADC Mux", "IF3 DAC", "IF3 DAC"},
+	{"IF2_1 ADC Mux", "DAC1 MIX", "DAC1 MIX"},
+	{"IF2_1 ADC", NULL, "IF2_1 ADC Mux"},
+	{"IF2_1 ADC", NULL, "I2S2_1"},
+
+	{"IF2_2 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"},
+	{"IF2_2 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"},
+	{"IF2_2 ADC Mux", "MONO ADC", "Mono ADC MIX"},
+	{"IF2_2 ADC Mux", "IF1 DAC1", "IF1 DAC1"},
+	{"IF2_2 ADC Mux", "IF1 DAC2", "IF1 DAC2"},
+	{"IF2_2 ADC Mux", "IF2_1 DAC", "IF2_1 DAC"},
+	{"IF2_2 ADC Mux", "IF3 DAC", "IF3 DAC"},
+	{"IF2_2 ADC Mux", "DAC1 MIX", "DAC1 MIX"},
+	{"IF2_2 ADC", NULL, "IF2_2 ADC Mux"},
+	{"IF2_2 ADC", NULL, "I2S2_2"},
+
+	{"IF3 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"},
+	{"IF3 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"},
+	{"IF3 ADC Mux", "MONO ADC", "Mono ADC MIX"},
+	{"IF3 ADC Mux", "IF1 DAC1", "IF1 DAC1"},
+	{"IF3 ADC Mux", "IF1 DAC2", "IF1 DAC2"},
+	{"IF3 ADC Mux", "IF2_1 DAC", "IF2_1 DAC"},
+	{"IF3 ADC Mux", "IF2_2 DAC", "IF2_2 DAC"},
+	{"IF3 ADC Mux", "DAC1 MIX", "DAC1 MIX"},
+	{"IF3 ADC", NULL, "IF3 ADC Mux"},
+	{"IF3 ADC", NULL, "I2S3"},
+
+	{"AIF1_1TX slot 0", NULL, "IF1_1 0 ADC Swap Mux"},
+	{"AIF1_1TX slot 1", NULL, "IF1_1 1 ADC Swap Mux"},
+	{"AIF1_1TX slot 2", NULL, "IF1_1 2 ADC Swap Mux"},
+	{"AIF1_1TX slot 3", NULL, "IF1_1 3 ADC Swap Mux"},
+	{"AIF1_1TX slot 4", NULL, "IF1_1 4 ADC Swap Mux"},
+	{"AIF1_1TX slot 5", NULL, "IF1_1 5 ADC Swap Mux"},
+	{"AIF1_1TX slot 6", NULL, "IF1_1 6 ADC Swap Mux"},
+	{"AIF1_1TX slot 7", NULL, "IF1_1 7 ADC Swap Mux"},
+	{"AIF1_2TX slot 0", NULL, "IF1_2 0 ADC Swap Mux"},
+	{"AIF1_2TX slot 1", NULL, "IF1_2 1 ADC Swap Mux"},
+	{"AIF1_2TX slot 2", NULL, "IF1_2 2 ADC Swap Mux"},
+	{"AIF1_2TX slot 3", NULL, "IF1_2 3 ADC Swap Mux"},
+	{"AIF1_2TX slot 4", NULL, "IF1_2 4 ADC Swap Mux"},
+	{"AIF1_2TX slot 5", NULL, "IF1_2 5 ADC Swap Mux"},
+	{"AIF1_2TX slot 6", NULL, "IF1_2 6 ADC Swap Mux"},
+	{"AIF1_2TX slot 7", NULL, "IF1_2 7 ADC Swap Mux"},
+	{"IF2_1 ADC Swap Mux", "L/R", "IF2_1 ADC"},
+	{"IF2_1 ADC Swap Mux", "R/L", "IF2_1 ADC"},
+	{"IF2_1 ADC Swap Mux", "L/L", "IF2_1 ADC"},
+	{"IF2_1 ADC Swap Mux", "R/R", "IF2_1 ADC"},
+	{"AIF2_1TX", NULL, "IF2_1 ADC Swap Mux"},
+	{"IF2_2 ADC Swap Mux", "L/R", "IF2_2 ADC"},
+	{"IF2_2 ADC Swap Mux", "R/L", "IF2_2 ADC"},
+	{"IF2_2 ADC Swap Mux", "L/L", "IF2_2 ADC"},
+	{"IF2_2 ADC Swap Mux", "R/R", "IF2_2 ADC"},
+	{"AIF2_2TX", NULL, "IF2_2 ADC Swap Mux"},
+	{"IF3 ADC Swap Mux", "L/R", "IF3 ADC"},
+	{"IF3 ADC Swap Mux", "R/L", "IF3 ADC"},
+	{"IF3 ADC Swap Mux", "L/L", "IF3 ADC"},
+	{"IF3 ADC Swap Mux", "R/R", "IF3 ADC"},
+	{"AIF3TX", NULL, "IF3 ADC Swap Mux"},
+
+	{"IF1 DAC1", NULL, "AIF1RX"},
+	{"IF1 DAC2", NULL, "AIF1RX"},
+	{"IF1 DAC3", NULL, "AIF1RX"},
+	{"IF2_1 DAC Swap Mux", "L/R", "AIF2_1RX"},
+	{"IF2_1 DAC Swap Mux", "R/L", "AIF2_1RX"},
+	{"IF2_1 DAC Swap Mux", "L/L", "AIF2_1RX"},
+	{"IF2_1 DAC Swap Mux", "R/R", "AIF2_1RX"},
+	{"IF2_2 DAC Swap Mux", "L/R", "AIF2_2RX"},
+	{"IF2_2 DAC Swap Mux", "R/L", "AIF2_2RX"},
+	{"IF2_2 DAC Swap Mux", "L/L", "AIF2_2RX"},
+	{"IF2_2 DAC Swap Mux", "R/R", "AIF2_2RX"},
+	{"IF2_1 DAC", NULL, "IF2_1 DAC Swap Mux"},
+	{"IF2_2 DAC", NULL, "IF2_2 DAC Swap Mux"},
+	{"IF3 DAC Swap Mux", "L/R", "AIF3RX"},
+	{"IF3 DAC Swap Mux", "R/L", "AIF3RX"},
+	{"IF3 DAC Swap Mux", "L/L", "AIF3RX"},
+	{"IF3 DAC Swap Mux", "R/R", "AIF3RX"},
+	{"IF3 DAC", NULL, "IF3 DAC Swap Mux"},
+
+	{"IF1 DAC1", NULL, "I2S1_1"},
+	{"IF1 DAC2", NULL, "I2S1_1"},
+	{"IF1 DAC3", NULL, "I2S1_1"},
+	{"IF2_1 DAC", NULL, "I2S2_1"},
+	{"IF2_2 DAC", NULL, "I2S2_2"},
+	{"IF3 DAC", NULL, "I2S3"},
+
+	{"IF1 DAC1 L", NULL, "IF1 DAC1"},
+	{"IF1 DAC1 R", NULL, "IF1 DAC1"},
+	{"IF1 DAC2 L", NULL, "IF1 DAC2"},
+	{"IF1 DAC2 R", NULL, "IF1 DAC2"},
+	{"IF1 DAC3 L", NULL, "IF1 DAC3"},
+	{"IF1 DAC3 R", NULL, "IF1 DAC3"},
+	{"IF2_1 DAC L", NULL, "IF2_1 DAC"},
+	{"IF2_1 DAC R", NULL, "IF2_1 DAC"},
+	{"IF2_2 DAC L", NULL, "IF2_2 DAC"},
+	{"IF2_2 DAC R", NULL, "IF2_2 DAC"},
+	{"IF3 DAC L", NULL, "IF3 DAC"},
+	{"IF3 DAC R", NULL, "IF3 DAC"},
+
+	{"DAC L1 Mux", "IF1 DAC1", "IF1 DAC1 L"},
+	{"DAC L1 Mux", "IF2_1 DAC", "IF2_1 DAC L"},
+	{"DAC L1 Mux", "IF2_2 DAC", "IF2_2 DAC L"},
+	{"DAC L1 Mux", "IF3 DAC", "IF3 DAC L"},
+	{"DAC L1 Mux", NULL, "DAC Stereo1 Filter"},
+
+	{"DAC R1 Mux", "IF1 DAC1", "IF1 DAC1 R"},
+	{"DAC R1 Mux", "IF2_1 DAC", "IF2_1 DAC R"},
+	{"DAC R1 Mux", "IF2_2 DAC", "IF2_2 DAC R"},
+	{"DAC R1 Mux", "IF3 DAC", "IF3 DAC R"},
+	{"DAC R1 Mux", NULL, "DAC Stereo1 Filter"},
+
+	{"DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"},
+	{"DAC1 MIXL", "DAC1 Switch", "DAC L1 Mux"},
+	{"DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"},
+	{"DAC1 MIXR", "DAC1 Switch", "DAC R1 Mux"},
+
+	{"DAC1 MIX", NULL, "DAC1 MIXL"},
+	{"DAC1 MIX", NULL, "DAC1 MIXR"},
+
+	{"DAC L2 Mux", "IF1 DAC2", "IF1 DAC2 L"},
+	{"DAC L2 Mux", "IF2_1 DAC", "IF2_1 DAC L"},
+	{"DAC L2 Mux", "IF2_2 DAC", "IF2_2 DAC L"},
+	{"DAC L2 Mux", "IF3 DAC", "IF3 DAC L"},
+	{"DAC L2 Mux", "Mono ADC MIX", "Mono ADC MIXL"},
+	{"DAC L2 Mux", NULL, "DAC Mono Left Filter"},
+
+	{"DAC R2 Mux", "IF1 DAC2", "IF1 DAC2 R"},
+	{"DAC R2 Mux", "IF2_1 DAC", "IF2_1 DAC R"},
+	{"DAC R2 Mux", "IF2_2 DAC", "IF2_2 DAC R"},
+	{"DAC R2 Mux", "IF3 DAC", "IF3 DAC R"},
+	{"DAC R2 Mux", "Mono ADC MIX", "Mono ADC MIXR"},
+	{"DAC R2 Mux", NULL, "DAC Mono Right Filter"},
+
+	{"DAC L3 Mux", "IF1 DAC2", "IF1 DAC2 L"},
+	{"DAC L3 Mux", "IF2_1 DAC", "IF2_1 DAC L"},
+	{"DAC L3 Mux", "IF2_2 DAC", "IF2_2 DAC L"},
+	{"DAC L3 Mux", "IF3 DAC", "IF3 DAC L"},
+	{"DAC L3 Mux", "STO2 ADC MIX", "Stereo2 ADC MIXL"},
+	{"DAC L3 Mux", NULL, "DAC Stereo2 Filter"},
+
+	{"DAC R3 Mux", "IF1 DAC2", "IF1 DAC2 R"},
+	{"DAC R3 Mux", "IF2_1 DAC", "IF2_1 DAC R"},
+	{"DAC R3 Mux", "IF2_2 DAC", "IF2_2 DAC R"},
+	{"DAC R3 Mux", "IF3 DAC", "IF3 DAC R"},
+	{"DAC R3 Mux", "STO2 ADC MIX", "Stereo2 ADC MIXR"},
+	{"DAC R3 Mux", NULL, "DAC Stereo2 Filter"},
+
+	{"Stereo1 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"},
+	{"Stereo1 DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"},
+	{"Stereo1 DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+	{"Stereo1 DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"},
+
+	{"Stereo1 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"},
+	{"Stereo1 DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"},
+	{"Stereo1 DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"},
+	{"Stereo1 DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+
+	{"Stereo2 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"},
+	{"Stereo2 DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+	{"Stereo2 DAC MIXL", "DAC L3 Switch", "DAC L3 Mux"},
+
+	{"Stereo2 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"},
+	{"Stereo2 DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+	{"Stereo2 DAC MIXR", "DAC R3 Switch", "DAC R3 Mux"},
+
+	{"Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"},
+	{"Mono DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"},
+	{"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+	{"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"},
+	{"Mono DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"},
+	{"Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"},
+	{"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"},
+	{"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+
+	{"DAC MIXL", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"},
+	{"DAC MIXL", "Stereo2 DAC Mixer", "Stereo2 DAC MIXL"},
+	{"DAC MIXL", "Mono DAC Mixer", "Mono DAC MIXL"},
+	{"DAC MIXR", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"},
+	{"DAC MIXR", "Stereo2 DAC Mixer", "Stereo2 DAC MIXR"},
+	{"DAC MIXR", "Mono DAC Mixer", "Mono DAC MIXR"},
+
+	{"DAC L1 Source", "DAC1", "DAC1 MIXL"},
+	{"DAC L1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"},
+	{"DAC L1 Source", "DMIC1", "DMIC L1"},
+	{"DAC R1 Source", "DAC1", "DAC1 MIXR"},
+	{"DAC R1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"},
+	{"DAC R1 Source", "DMIC1", "DMIC R1"},
+
+	{"DAC L2 Source", "DAC2", "DAC L2 Mux"},
+	{"DAC L2 Source", "Mono DAC Mixer", "Mono DAC MIXL"},
+	{"DAC L2 Source", NULL, "DAC L2 Power"},
+	{"DAC R2 Source", "DAC2", "DAC R2 Mux"},
+	{"DAC R2 Source", "Mono DAC Mixer", "Mono DAC MIXR"},
+	{"DAC R2 Source", NULL, "DAC R2 Power"},
+
+	{"DAC L1", NULL, "DAC L1 Source"},
+	{"DAC R1", NULL, "DAC R1 Source"},
+	{"DAC L2", NULL, "DAC L2 Source"},
+	{"DAC R2", NULL, "DAC R2 Source"},
+
+	{"DAC L1", NULL, "DAC 1 Clock"},
+	{"DAC R1", NULL, "DAC 1 Clock"},
+	{"DAC L2", NULL, "DAC 2 Clock"},
+	{"DAC R2", NULL, "DAC 2 Clock"},
+
+	{"MONOVOL MIX", "DAC L2 Switch", "DAC L2"},
+	{"MONOVOL MIX", "RECMIX2L Switch", "RECMIX2L"},
+	{"MONOVOL MIX", "BST1 Switch", "BST1"},
+	{"MONOVOL MIX", "BST2 Switch", "BST2"},
+	{"MONOVOL MIX", "BST3 Switch", "BST3"},
+
+	{"OUT MIXL", "DAC L2 Switch", "DAC L2"},
+	{"OUT MIXL", "INL Switch", "INL VOL"},
+	{"OUT MIXL", "BST1 Switch", "BST1"},
+	{"OUT MIXL", "BST2 Switch", "BST2"},
+	{"OUT MIXL", "BST3 Switch", "BST3"},
+	{"OUT MIXR", "DAC R2 Switch", "DAC R2"},
+	{"OUT MIXR", "INR Switch", "INR VOL"},
+	{"OUT MIXR", "BST2 Switch", "BST2"},
+	{"OUT MIXR", "BST3 Switch", "BST3"},
+	{"OUT MIXR", "BST4 Switch", "BST4"},
+
+	{"MONOVOL", "Switch", "MONOVOL MIX"},
+	{"Mono MIX", "DAC L2 Switch", "DAC L2"},
+	{"Mono MIX", "MONOVOL Switch", "MONOVOL"},
+	{"Mono Amp", NULL, "Mono MIX"},
+	{"Mono Amp", NULL, "Vref2"},
+	{"Mono Amp", NULL, "Vref3"},
+	{"Mono Amp", NULL, "CLKDET SYS"},
+	{"Mono Amp", NULL, "CLKDET MONO"},
+	{"Mono Playback", "Switch", "Mono Amp"},
+	{"MONOOUT", NULL, "Mono Playback"},
+
+	{"HP Amp", NULL, "DAC L1"},
+	{"HP Amp", NULL, "DAC R1"},
+	{"HP Amp", NULL, "Charge Pump"},
+	{"HP Amp", NULL, "CLKDET SYS"},
+	{"HP Amp", NULL, "CLKDET HP"},
+	{"HP Amp", NULL, "CBJ Power"},
+	{"HP Amp", NULL, "Vref2"},
+	{"HPO Playback", "Switch", "HP Amp"},
+	{"HPOL", NULL, "HPO Playback"},
+	{"HPOR", NULL, "HPO Playback"},
+
+	{"OUTVOL L", "Switch", "OUT MIXL"},
+	{"OUTVOL R", "Switch", "OUT MIXR"},
+	{"LOUT L MIX", "DAC L2 Switch", "DAC L2"},
+	{"LOUT L MIX", "OUTVOL L Switch", "OUTVOL L"},
+	{"LOUT R MIX", "DAC R2 Switch", "DAC R2"},
+	{"LOUT R MIX", "OUTVOL R Switch", "OUTVOL R"},
+	{"LOUT Amp", NULL, "LOUT L MIX"},
+	{"LOUT Amp", NULL, "LOUT R MIX"},
+	{"LOUT Amp", NULL, "Vref1"},
+	{"LOUT Amp", NULL, "Vref2"},
+	{"LOUT Amp", NULL, "CLKDET SYS"},
+	{"LOUT Amp", NULL, "CLKDET LOUT"},
+	{"LOUT L Playback", "Switch", "LOUT Amp"},
+	{"LOUT R Playback", "Switch", "LOUT Amp"},
+	{"LOUTL", NULL, "LOUT L Playback"},
+	{"LOUTR", NULL, "LOUT R Playback"},
+
+	{"PDM L Mux", "Mono DAC", "Mono DAC MIXL"},
+	{"PDM L Mux", "Stereo1 DAC", "Stereo1 DAC MIXL"},
+	{"PDM L Mux", "Stereo2 DAC", "Stereo2 DAC MIXL"},
+	{"PDM L Mux", NULL, "PDM Power"},
+	{"PDM R Mux", "Mono DAC", "Mono DAC MIXR"},
+	{"PDM R Mux", "Stereo1 DAC", "Stereo1 DAC MIXR"},
+	{"PDM R Mux", "Stereo2 DAC", "Stereo2 DAC MIXR"},
+	{"PDM R Mux", NULL, "PDM Power"},
+	{"PDM L Playback", "Switch", "PDM L Mux"},
+	{"PDM R Playback", "Switch", "PDM R Mux"},
+	{"PDML", NULL, "PDM L Playback"},
+	{"PDMR", NULL, "PDM R Playback"},
+};
+
+static int rt5665_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int val = 0;
+
+	if (rx_mask || tx_mask)
+		val |= RT5665_I2S1_MODE_TDM;
+
+	switch (slots) {
+	case 4:
+		val |= RT5665_TDM_IN_CH_4;
+		val |= RT5665_TDM_OUT_CH_4;
+		break;
+	case 6:
+		val |= RT5665_TDM_IN_CH_6;
+		val |= RT5665_TDM_OUT_CH_6;
+		break;
+	case 8:
+		val |= RT5665_TDM_IN_CH_8;
+		val |= RT5665_TDM_OUT_CH_8;
+		break;
+	case 2:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (slot_width) {
+	case 20:
+		val |= RT5665_TDM_IN_LEN_20;
+		val |= RT5665_TDM_OUT_LEN_20;
+		break;
+	case 24:
+		val |= RT5665_TDM_IN_LEN_24;
+		val |= RT5665_TDM_OUT_LEN_24;
+		break;
+	case 32:
+		val |= RT5665_TDM_IN_LEN_32;
+		val |= RT5665_TDM_OUT_LEN_32;
+		break;
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5665_TDM_CTRL_1,
+		RT5665_I2S1_MODE_MASK | RT5665_TDM_IN_CH_MASK |
+		RT5665_TDM_OUT_CH_MASK | RT5665_TDM_IN_LEN_MASK |
+		RT5665_TDM_OUT_LEN_MASK, val);
+
+	return 0;
+}
+
+
+static int rt5665_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0, val_clk, reg_clk, mask_clk, val_bits = 0x0100;
+	int pre_div, frame_size;
+
+	rt5665->lrck[dai->id] = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5665->sysclk, rt5665->lrck[dai->id]);
+	if (pre_div < 0) {
+		dev_warn(component->dev, "Force using PLL");
+		snd_soc_component_set_pll(component, 0, RT5665_PLL1_S_MCLK,
+			rt5665->sysclk,	rt5665->lrck[dai->id] * 512);
+		snd_soc_component_set_sysclk(component, RT5665_SCLK_S_PLL1, 0,
+			rt5665->lrck[dai->id] * 512, 0);
+		pre_div = 1;
+	}
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+				rt5665->lrck[dai->id], pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		val_bits = 0x0100;
+		break;
+	case 20:
+		val_len |= RT5665_I2S_DL_20;
+		val_bits = 0x1300;
+		break;
+	case 24:
+		val_len |= RT5665_I2S_DL_24;
+		val_bits = 0x2500;
+		break;
+	case 8:
+		val_len |= RT5665_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5665_AIF1_1:
+	case RT5665_AIF1_2:
+		if (params_channels(params) > 2)
+			rt5665_set_tdm_slot(dai, 0xf, 0xf,
+				params_channels(params), params_width(params));
+		reg_clk = RT5665_ADDA_CLK_1;
+		mask_clk = RT5665_I2S_PD1_MASK;
+		val_clk = pre_div << RT5665_I2S_PD1_SFT;
+		snd_soc_component_update_bits(component, RT5665_I2S1_SDP,
+			RT5665_I2S_DL_MASK, val_len);
+		break;
+	case RT5665_AIF2_1:
+	case RT5665_AIF2_2:
+		reg_clk = RT5665_ADDA_CLK_2;
+		mask_clk = RT5665_I2S_PD2_MASK;
+		val_clk = pre_div << RT5665_I2S_PD2_SFT;
+		snd_soc_component_update_bits(component, RT5665_I2S2_SDP,
+			RT5665_I2S_DL_MASK, val_len);
+		break;
+	case RT5665_AIF3:
+		reg_clk = RT5665_ADDA_CLK_2;
+		mask_clk = RT5665_I2S_PD3_MASK;
+		val_clk = pre_div << RT5665_I2S_PD3_SFT;
+		snd_soc_component_update_bits(component, RT5665_I2S3_SDP,
+			RT5665_I2S_DL_MASK, val_len);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, reg_clk, mask_clk, val_clk);
+	snd_soc_component_update_bits(component, RT5665_STO1_DAC_SIL_DET, 0x3700, val_bits);
+
+	switch (rt5665->lrck[dai->id]) {
+	case 192000:
+		snd_soc_component_update_bits(component, RT5665_ADDA_CLK_1,
+			RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK,
+			RT5665_DAC_OSR_32 | RT5665_ADC_OSR_32);
+		break;
+	case 96000:
+		snd_soc_component_update_bits(component, RT5665_ADDA_CLK_1,
+			RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK,
+			RT5665_DAC_OSR_64 | RT5665_ADC_OSR_64);
+		break;
+	default:
+		snd_soc_component_update_bits(component, RT5665_ADDA_CLK_1,
+			RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK,
+			RT5665_DAC_OSR_128 | RT5665_ADC_OSR_128);
+		break;
+	}
+
+	if (rt5665->master[RT5665_AIF2_1] || rt5665->master[RT5665_AIF2_2]) {
+		snd_soc_component_update_bits(component, RT5665_I2S_M_CLK_CTRL_1,
+			RT5665_I2S2_M_PD_MASK, pre_div << RT5665_I2S2_M_PD_SFT);
+	}
+	if (rt5665->master[RT5665_AIF3]) {
+		snd_soc_component_update_bits(component, RT5665_I2S_M_CLK_CTRL_1,
+			RT5665_I2S3_M_PD_MASK, pre_div << RT5665_I2S3_M_PD_SFT);
+	}
+
+	return 0;
+}
+
+static int rt5665_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5665->master[dai->id] = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5665_I2S_MS_S;
+		rt5665->master[dai->id] = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5665_I2S_BP_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5665_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5665_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5665_I2S_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5665_AIF1_1:
+	case RT5665_AIF1_2:
+		snd_soc_component_update_bits(component, RT5665_I2S1_SDP,
+			RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK |
+			RT5665_I2S_DF_MASK, reg_val);
+		break;
+	case RT5665_AIF2_1:
+	case RT5665_AIF2_2:
+		snd_soc_component_update_bits(component, RT5665_I2S2_SDP,
+			RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK |
+			RT5665_I2S_DF_MASK, reg_val);
+		break;
+	case RT5665_AIF3:
+		snd_soc_component_update_bits(component, RT5665_I2S3_SDP,
+			RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK |
+			RT5665_I2S_DF_MASK, reg_val);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int rt5665_set_component_sysclk(struct snd_soc_component *component, int clk_id,
+				   int source, unsigned int freq, int dir)
+{
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0, src = 0;
+
+	if (freq == rt5665->sysclk && clk_id == rt5665->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5665_SCLK_S_MCLK:
+		reg_val |= RT5665_SCLK_SRC_MCLK;
+		src = RT5665_CLK_SRC_MCLK;
+		break;
+	case RT5665_SCLK_S_PLL1:
+		reg_val |= RT5665_SCLK_SRC_PLL1;
+		src = RT5665_CLK_SRC_PLL1;
+		break;
+	case RT5665_SCLK_S_RCCLK:
+		reg_val |= RT5665_SCLK_SRC_RCCLK;
+		src = RT5665_CLK_SRC_RCCLK;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, RT5665_GLB_CLK,
+		RT5665_SCLK_SRC_MASK, reg_val);
+
+	if (rt5665->master[RT5665_AIF2_1] || rt5665->master[RT5665_AIF2_2]) {
+		snd_soc_component_update_bits(component, RT5665_I2S_M_CLK_CTRL_1,
+			RT5665_I2S2_SRC_MASK, src << RT5665_I2S2_SRC_SFT);
+	}
+	if (rt5665->master[RT5665_AIF3]) {
+		snd_soc_component_update_bits(component, RT5665_I2S_M_CLK_CTRL_1,
+			RT5665_I2S3_SRC_MASK, src << RT5665_I2S3_SRC_SFT);
+	}
+
+	rt5665->sysclk = freq;
+	rt5665->sysclk_src = clk_id;
+
+	dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+	return 0;
+}
+
+static int rt5665_set_component_pll(struct snd_soc_component *component, int pll_id,
+				int source, unsigned int freq_in,
+				unsigned int freq_out)
+{
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5665->pll_src && freq_in == rt5665->pll_in &&
+	    freq_out == rt5665->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt5665->pll_in = 0;
+		rt5665->pll_out = 0;
+		snd_soc_component_update_bits(component, RT5665_GLB_CLK,
+			RT5665_SCLK_SRC_MASK, RT5665_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5665_PLL1_S_MCLK:
+		snd_soc_component_update_bits(component, RT5665_GLB_CLK,
+			RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_MCLK);
+		break;
+	case RT5665_PLL1_S_BCLK1:
+		snd_soc_component_update_bits(component, RT5665_GLB_CLK,
+				RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK1);
+		break;
+	case RT5665_PLL1_S_BCLK2:
+		snd_soc_component_update_bits(component, RT5665_GLB_CLK,
+				RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK2);
+		break;
+	case RT5665_PLL1_S_BCLK3:
+		snd_soc_component_update_bits(component, RT5665_GLB_CLK,
+				RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK3);
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL Source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_component_write(component, RT5665_PLL_CTRL_1,
+		pll_code.n_code << RT5665_PLL_N_SFT | pll_code.k_code);
+	snd_soc_component_write(component, RT5665_PLL_CTRL_2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5665_PLL_M_SFT |
+		pll_code.m_bp << RT5665_PLL_M_BP_SFT);
+
+	rt5665->pll_in = freq_in;
+	rt5665->pll_out = freq_out;
+	rt5665->pll_src = source;
+
+	return 0;
+}
+
+static int rt5665_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
+
+	rt5665->bclk[dai->id] = ratio;
+
+	if (ratio == 64) {
+		switch (dai->id) {
+		case RT5665_AIF2_1:
+		case RT5665_AIF2_2:
+			snd_soc_component_update_bits(component, RT5665_ADDA_CLK_2,
+				RT5665_I2S_BCLK_MS2_MASK,
+				RT5665_I2S_BCLK_MS2_64);
+			break;
+		case RT5665_AIF3:
+			snd_soc_component_update_bits(component, RT5665_ADDA_CLK_2,
+				RT5665_I2S_BCLK_MS3_MASK,
+				RT5665_I2S_BCLK_MS3_64);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int rt5665_set_bias_level(struct snd_soc_component *component,
+			enum snd_soc_bias_level level)
+{
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		regmap_update_bits(rt5665->regmap, RT5665_DIG_MISC,
+			RT5665_DIG_GATE_CTRL, RT5665_DIG_GATE_CTRL);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		regmap_update_bits(rt5665->regmap, RT5665_PWR_DIG_1,
+			RT5665_PWR_LDO,	RT5665_PWR_LDO);
+		regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1,
+			RT5665_PWR_MB, RT5665_PWR_MB);
+		regmap_update_bits(rt5665->regmap, RT5665_DIG_MISC,
+			RT5665_DIG_GATE_CTRL, 0);
+		break;
+	case SND_SOC_BIAS_OFF:
+		regmap_update_bits(rt5665->regmap, RT5665_PWR_DIG_1,
+			RT5665_PWR_LDO, 0);
+		regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1,
+			RT5665_PWR_MB, 0);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5665_probe(struct snd_soc_component *component)
+{
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
+
+	rt5665->component = component;
+
+	schedule_delayed_work(&rt5665->calibrate_work, msecs_to_jiffies(100));
+
+	return 0;
+}
+
+static void rt5665_remove(struct snd_soc_component *component)
+{
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
+
+	regmap_write(rt5665->regmap, RT5665_RESET, 0);
+}
+
+#ifdef CONFIG_PM
+static int rt5665_suspend(struct snd_soc_component *component)
+{
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5665->regmap, true);
+	regcache_mark_dirty(rt5665->regmap);
+	return 0;
+}
+
+static int rt5665_resume(struct snd_soc_component *component)
+{
+	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5665->regmap, false);
+	regcache_sync(rt5665->regmap);
+
+	return 0;
+}
+#else
+#define rt5665_suspend NULL
+#define rt5665_resume NULL
+#endif
+
+#define RT5665_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5665_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5665_aif_dai_ops = {
+	.hw_params = rt5665_hw_params,
+	.set_fmt = rt5665_set_dai_fmt,
+	.set_tdm_slot = rt5665_set_tdm_slot,
+	.set_bclk_ratio = rt5665_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt5665_dai[] = {
+	{
+		.name = "rt5665-aif1_1",
+		.id = RT5665_AIF1_1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = RT5665_STEREO_RATES,
+			.formats = RT5665_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1_1 Capture",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = RT5665_STEREO_RATES,
+			.formats = RT5665_FORMATS,
+		},
+		.ops = &rt5665_aif_dai_ops,
+	},
+	{
+		.name = "rt5665-aif1_2",
+		.id = RT5665_AIF1_2,
+		.capture = {
+			.stream_name = "AIF1_2 Capture",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = RT5665_STEREO_RATES,
+			.formats = RT5665_FORMATS,
+		},
+		.ops = &rt5665_aif_dai_ops,
+	},
+	{
+		.name = "rt5665-aif2_1",
+		.id = RT5665_AIF2_1,
+		.playback = {
+			.stream_name = "AIF2_1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5665_STEREO_RATES,
+			.formats = RT5665_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF2_1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5665_STEREO_RATES,
+			.formats = RT5665_FORMATS,
+		},
+		.ops = &rt5665_aif_dai_ops,
+	},
+	{
+		.name = "rt5665-aif2_2",
+		.id = RT5665_AIF2_2,
+		.playback = {
+			.stream_name = "AIF2_2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5665_STEREO_RATES,
+			.formats = RT5665_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF2_2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5665_STEREO_RATES,
+			.formats = RT5665_FORMATS,
+		},
+		.ops = &rt5665_aif_dai_ops,
+	},
+	{
+		.name = "rt5665-aif3",
+		.id = RT5665_AIF3,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5665_STEREO_RATES,
+			.formats = RT5665_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF3 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5665_STEREO_RATES,
+			.formats = RT5665_FORMATS,
+		},
+		.ops = &rt5665_aif_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5665 = {
+	.probe			= rt5665_probe,
+	.remove			= rt5665_remove,
+	.suspend		= rt5665_suspend,
+	.resume			= rt5665_resume,
+	.set_bias_level		= rt5665_set_bias_level,
+	.controls		= rt5665_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5665_snd_controls),
+	.dapm_widgets		= rt5665_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5665_dapm_widgets),
+	.dapm_routes		= rt5665_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5665_dapm_routes),
+	.set_sysclk		= rt5665_set_component_sysclk,
+	.set_pll		= rt5665_set_component_pll,
+	.set_jack		= rt5665_set_jack_detect,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+
+static const struct regmap_config rt5665_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+	.max_register = 0x0400,
+	.volatile_reg = rt5665_volatile_register,
+	.readable_reg = rt5665_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5665_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5665_reg),
+	.use_single_rw = true,
+};
+
+static const struct i2c_device_id rt5665_i2c_id[] = {
+	{"rt5665", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, rt5665_i2c_id);
+
+static int rt5665_parse_dt(struct rt5665_priv *rt5665, struct device *dev)
+{
+	rt5665->pdata.in1_diff = of_property_read_bool(dev->of_node,
+					"realtek,in1-differential");
+	rt5665->pdata.in2_diff = of_property_read_bool(dev->of_node,
+					"realtek,in2-differential");
+	rt5665->pdata.in3_diff = of_property_read_bool(dev->of_node,
+					"realtek,in3-differential");
+	rt5665->pdata.in4_diff = of_property_read_bool(dev->of_node,
+					"realtek,in4-differential");
+
+	of_property_read_u32(dev->of_node, "realtek,dmic1-data-pin",
+		&rt5665->pdata.dmic1_data_pin);
+	of_property_read_u32(dev->of_node, "realtek,dmic2-data-pin",
+		&rt5665->pdata.dmic2_data_pin);
+	of_property_read_u32(dev->of_node, "realtek,jd-src",
+		&rt5665->pdata.jd_src);
+
+	rt5665->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
+		"realtek,ldo1-en-gpios", 0);
+
+	return 0;
+}
+
+static void rt5665_calibrate(struct rt5665_priv *rt5665)
+{
+	int value, count;
+
+	mutex_lock(&rt5665->calibrate_mutex);
+
+	regcache_cache_bypass(rt5665->regmap, true);
+
+	regmap_write(rt5665->regmap, RT5665_RESET, 0);
+	regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602);
+	regmap_write(rt5665->regmap, RT5665_HP_CHARGE_PUMP_1, 0x0c26);
+	regmap_write(rt5665->regmap, RT5665_MONOMIX_IN_GAIN, 0x021f);
+	regmap_write(rt5665->regmap, RT5665_MONO_OUT, 0x480a);
+	regmap_write(rt5665->regmap, RT5665_PWR_MIXER, 0x083f);
+	regmap_write(rt5665->regmap, RT5665_PWR_DIG_1, 0x0180);
+	regmap_write(rt5665->regmap, RT5665_EJD_CTRL_1, 0x4040);
+	regmap_write(rt5665->regmap, RT5665_HP_LOGIC_CTRL_2, 0x0000);
+	regmap_write(rt5665->regmap, RT5665_DIG_MISC, 0x0001);
+	regmap_write(rt5665->regmap, RT5665_MICBIAS_2, 0x0380);
+	regmap_write(rt5665->regmap, RT5665_GLB_CLK, 0x8000);
+	regmap_write(rt5665->regmap, RT5665_ADDA_CLK_1, 0x1000);
+	regmap_write(rt5665->regmap, RT5665_CHOP_DAC, 0x3030);
+	regmap_write(rt5665->regmap, RT5665_CALIB_ADC_CTRL, 0x3c05);
+	regmap_write(rt5665->regmap, RT5665_PWR_ANLG_1, 0xaa3e);
+	usleep_range(15000, 20000);
+	regmap_write(rt5665->regmap, RT5665_PWR_ANLG_1, 0xfe7e);
+	regmap_write(rt5665->regmap, RT5665_HP_CALIB_CTRL_2, 0x0321);
+
+	regmap_write(rt5665->regmap, RT5665_HP_CALIB_CTRL_1, 0xfc00);
+	count = 0;
+	while (true) {
+		regmap_read(rt5665->regmap, RT5665_HP_CALIB_STA_1, &value);
+		if (value & 0x8000)
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (count > 60) {
+			pr_err("HP Calibration Failure\n");
+			regmap_write(rt5665->regmap, RT5665_RESET, 0);
+			regcache_cache_bypass(rt5665->regmap, false);
+			goto out_unlock;
+		}
+
+		count++;
+	}
+
+	regmap_write(rt5665->regmap, RT5665_MONO_AMP_CALIB_CTRL_1, 0x9e24);
+	count = 0;
+	while (true) {
+		regmap_read(rt5665->regmap, RT5665_MONO_AMP_CALIB_STA1, &value);
+		if (value & 0x8000)
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (count > 60) {
+			pr_err("MONO Calibration Failure\n");
+			regmap_write(rt5665->regmap, RT5665_RESET, 0);
+			regcache_cache_bypass(rt5665->regmap, false);
+			goto out_unlock;
+		}
+
+		count++;
+	}
+
+	regmap_write(rt5665->regmap, RT5665_RESET, 0);
+	regcache_cache_bypass(rt5665->regmap, false);
+
+	regcache_mark_dirty(rt5665->regmap);
+	regcache_sync(rt5665->regmap);
+
+	regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602);
+	regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120);
+
+out_unlock:
+	rt5665->calibration_done = true;
+	mutex_unlock(&rt5665->calibrate_mutex);
+}
+
+static void rt5665_calibrate_handler(struct work_struct *work)
+{
+	struct rt5665_priv *rt5665 = container_of(work, struct rt5665_priv,
+		calibrate_work.work);
+
+	while (!rt5665->component->card->instantiated) {
+		pr_debug("%s\n", __func__);
+		usleep_range(10000, 15000);
+	}
+
+	rt5665_calibrate(rt5665);
+}
+
+static int rt5665_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5665_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt5665_priv *rt5665;
+	int i, ret;
+	unsigned int val;
+
+	rt5665 = devm_kzalloc(&i2c->dev, sizeof(struct rt5665_priv),
+		GFP_KERNEL);
+
+	if (rt5665 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt5665);
+
+	if (pdata)
+		rt5665->pdata = *pdata;
+	else
+		rt5665_parse_dt(rt5665, &i2c->dev);
+
+	for (i = 0; i < ARRAY_SIZE(rt5665->supplies); i++)
+		rt5665->supplies[i].supply = rt5665_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5665->supplies),
+				      rt5665->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(rt5665->supplies),
+				    rt5665->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	if (gpio_is_valid(rt5665->pdata.ldo1_en)) {
+		if (devm_gpio_request_one(&i2c->dev, rt5665->pdata.ldo1_en,
+					  GPIOF_OUT_INIT_HIGH, "rt5665"))
+			dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+	}
+
+	/* Sleep for 300 ms miniumum */
+	usleep_range(300000, 350000);
+
+	rt5665->regmap = devm_regmap_init_i2c(i2c, &rt5665_regmap);
+	if (IS_ERR(rt5665->regmap)) {
+		ret = PTR_ERR(rt5665->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt5665->regmap, RT5665_DEVICE_ID, &val);
+	if (val != DEVICE_ID) {
+		dev_err(&i2c->dev,
+			"Device with ID register %x is not rt5665\n", val);
+		return -ENODEV;
+	}
+
+	regmap_read(rt5665->regmap, RT5665_RESET, &val);
+	switch (val) {
+	case 0x0:
+		rt5665->id = CODEC_5666;
+		break;
+	case 0x3:
+	default:
+		rt5665->id = CODEC_5665;
+		break;
+	}
+
+	regmap_write(rt5665->regmap, RT5665_RESET, 0);
+
+	/* line in diff mode*/
+	if (rt5665->pdata.in1_diff)
+		regmap_update_bits(rt5665->regmap, RT5665_IN1_IN2,
+			RT5665_IN1_DF_MASK, RT5665_IN1_DF_MASK);
+	if (rt5665->pdata.in2_diff)
+		regmap_update_bits(rt5665->regmap, RT5665_IN1_IN2,
+			RT5665_IN2_DF_MASK, RT5665_IN2_DF_MASK);
+	if (rt5665->pdata.in3_diff)
+		regmap_update_bits(rt5665->regmap, RT5665_IN3_IN4,
+			RT5665_IN3_DF_MASK, RT5665_IN3_DF_MASK);
+	if (rt5665->pdata.in4_diff)
+		regmap_update_bits(rt5665->regmap, RT5665_IN3_IN4,
+			RT5665_IN4_DF_MASK, RT5665_IN4_DF_MASK);
+
+	/* DMIC pin*/
+	if (rt5665->pdata.dmic1_data_pin != RT5665_DMIC1_NULL ||
+		rt5665->pdata.dmic2_data_pin != RT5665_DMIC2_NULL) {
+		regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_2,
+			RT5665_GP9_PIN_MASK, RT5665_GP9_PIN_DMIC1_SCL);
+		regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1,
+				RT5665_GP8_PIN_MASK, RT5665_GP8_PIN_DMIC2_SCL);
+		switch (rt5665->pdata.dmic1_data_pin) {
+		case RT5665_DMIC1_DATA_IN2N:
+			regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1,
+				RT5665_DMIC_1_DP_MASK, RT5665_DMIC_1_DP_IN2N);
+			break;
+
+		case RT5665_DMIC1_DATA_GPIO4:
+			regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1,
+				RT5665_DMIC_1_DP_MASK, RT5665_DMIC_1_DP_GPIO4);
+			regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1,
+				RT5665_GP4_PIN_MASK, RT5665_GP4_PIN_DMIC1_SDA);
+			break;
+
+		default:
+			dev_dbg(&i2c->dev, "no DMIC1\n");
+			break;
+		}
+
+		switch (rt5665->pdata.dmic2_data_pin) {
+		case RT5665_DMIC2_DATA_IN2P:
+			regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1,
+				RT5665_DMIC_2_DP_MASK, RT5665_DMIC_2_DP_IN2P);
+			break;
+
+		case RT5665_DMIC2_DATA_GPIO5:
+			regmap_update_bits(rt5665->regmap,
+				RT5665_DMIC_CTRL_1,
+				RT5665_DMIC_2_DP_MASK,
+				RT5665_DMIC_2_DP_GPIO5);
+			regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1,
+				RT5665_GP5_PIN_MASK, RT5665_GP5_PIN_DMIC2_SDA);
+			break;
+
+		default:
+			dev_dbg(&i2c->dev, "no DMIC2\n");
+			break;
+
+		}
+	}
+
+	regmap_write(rt5665->regmap, RT5665_HP_LOGIC_CTRL_2, 0x0002);
+	regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1,
+		0xf000 | RT5665_VREF_POW_MASK, 0xe000 | RT5665_VREF_POW_REG);
+	/* Work around for pow_pump */
+	regmap_update_bits(rt5665->regmap, RT5665_STO1_DAC_SIL_DET,
+		RT5665_DEB_STO_DAC_MASK, RT5665_DEB_80_MS);
+
+	regmap_update_bits(rt5665->regmap, RT5665_HP_CHARGE_PUMP_1,
+		RT5665_PM_HP_MASK, RT5665_PM_HP_HV);
+
+	/* Set GPIO4,8 as input for combo jack */
+	if (rt5665->id == CODEC_5666) {
+		regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_2,
+			RT5665_GP4_PF_MASK, RT5665_GP4_PF_IN);
+		regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_3,
+			RT5665_GP8_PF_MASK, RT5665_GP8_PF_IN);
+	}
+
+	/* Enhance performance*/
+	regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1,
+		RT5665_HP_DRIVER_MASK | RT5665_LDO1_DVO_MASK,
+		RT5665_HP_DRIVER_5X | RT5665_LDO1_DVO_12);
+
+	INIT_DELAYED_WORK(&rt5665->jack_detect_work,
+				rt5665_jack_detect_handler);
+	INIT_DELAYED_WORK(&rt5665->calibrate_work,
+				rt5665_calibrate_handler);
+	INIT_DELAYED_WORK(&rt5665->jd_check_work,
+				rt5665_jd_check_handler);
+
+	mutex_init(&rt5665->calibrate_mutex);
+
+	if (i2c->irq) {
+		ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+			rt5665_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+			| IRQF_ONESHOT, "rt5665", rt5665);
+		if (ret)
+			dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+
+	}
+
+	return devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_rt5665,
+			rt5665_dai, ARRAY_SIZE(rt5665_dai));
+}
+
+static void rt5665_i2c_shutdown(struct i2c_client *client)
+{
+	struct rt5665_priv *rt5665 = i2c_get_clientdata(client);
+
+	regmap_write(rt5665->regmap, RT5665_RESET, 0);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt5665_of_match[] = {
+	{.compatible = "realtek,rt5665"},
+	{.compatible = "realtek,rt5666"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5665_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5665_acpi_match[] = {
+	{"10EC5665", 0,},
+	{"10EC5666", 0,},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, rt5665_acpi_match);
+#endif
+
+static struct i2c_driver rt5665_i2c_driver = {
+	.driver = {
+		.name = "rt5665",
+		.of_match_table = of_match_ptr(rt5665_of_match),
+		.acpi_match_table = ACPI_PTR(rt5665_acpi_match),
+	},
+	.probe = rt5665_i2c_probe,
+	.shutdown = rt5665_i2c_shutdown,
+	.id_table = rt5665_i2c_id,
+};
+module_i2c_driver(rt5665_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5665 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5665.h b/sound/soc/codecs/rt5665.h
new file mode 100644
index 0000000..b0a98ca
--- /dev/null
+++ b/sound/soc/codecs/rt5665.h
@@ -0,0 +1,2008 @@
+/*
+ * rt5665.h  --  RT5665/RT5658 ALSA SoC audio driver
+ *
+ * Copyright 2016 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5665_H__
+#define __RT5665_H__
+
+#include <sound/rt5665.h>
+
+#define DEVICE_ID 0x6451
+
+/* Info */
+#define RT5665_RESET				0x0000
+#define RT5665_VENDOR_ID			0x00fd
+#define RT5665_VENDOR_ID_1			0x00fe
+#define RT5665_DEVICE_ID			0x00ff
+/*  I/O - Output */
+#define RT5665_LOUT				0x0001
+#define RT5665_HP_CTRL_1			0x0002
+#define RT5665_HP_CTRL_2			0x0003
+#define RT5665_MONO_OUT				0x0004
+#define RT5665_HPL_GAIN				0x0005
+#define RT5665_HPR_GAIN				0x0006
+#define RT5665_MONO_GAIN			0x0007
+
+/* I/O - Input */
+#define RT5665_CAL_BST_CTRL			0x000a
+#define RT5665_CBJ_BST_CTRL			0x000b
+#define RT5665_IN1_IN2				0x000c
+#define RT5665_IN3_IN4				0x000d
+#define RT5665_INL1_INR1_VOL			0x000f
+/* I/O - Speaker */
+#define RT5665_EJD_CTRL_1			0x0010
+#define RT5665_EJD_CTRL_2			0x0011
+#define RT5665_EJD_CTRL_3			0x0012
+#define RT5665_EJD_CTRL_4			0x0013
+#define RT5665_EJD_CTRL_5			0x0014
+#define RT5665_EJD_CTRL_6			0x0015
+#define RT5665_EJD_CTRL_7			0x0016
+/* I/O - ADC/DAC/DMIC */
+#define RT5665_DAC2_CTRL			0x0017
+#define RT5665_DAC2_DIG_VOL			0x0018
+#define RT5665_DAC1_DIG_VOL			0x0019
+#define RT5665_DAC3_DIG_VOL			0x001a
+#define RT5665_DAC3_CTRL			0x001b
+#define RT5665_STO1_ADC_DIG_VOL			0x001c
+#define RT5665_MONO_ADC_DIG_VOL			0x001d
+#define RT5665_STO2_ADC_DIG_VOL			0x001e
+#define RT5665_STO1_ADC_BOOST			0x001f
+#define RT5665_MONO_ADC_BOOST			0x0020
+#define RT5665_STO2_ADC_BOOST			0x0021
+#define RT5665_HP_IMP_GAIN_1			0x0022
+#define RT5665_HP_IMP_GAIN_2			0x0023
+/* Mixer - D-D */
+#define RT5665_STO1_ADC_MIXER			0x0026
+#define RT5665_MONO_ADC_MIXER			0x0027
+#define RT5665_STO2_ADC_MIXER			0x0028
+#define RT5665_AD_DA_MIXER			0x0029
+#define RT5665_STO1_DAC_MIXER			0x002a
+#define RT5665_MONO_DAC_MIXER			0x002b
+#define RT5665_STO2_DAC_MIXER			0x002c
+#define RT5665_A_DAC1_MUX			0x002d
+#define RT5665_A_DAC2_MUX			0x002e
+#define RT5665_DIG_INF2_DATA			0x002f
+#define RT5665_DIG_INF3_DATA			0x0030
+/* Mixer - PDM */
+#define RT5665_PDM_OUT_CTRL			0x0031
+#define RT5665_PDM_DATA_CTRL_1			0x0032
+#define RT5665_PDM_DATA_CTRL_2			0x0033
+#define RT5665_PDM_DATA_CTRL_3			0x0034
+#define RT5665_PDM_DATA_CTRL_4			0x0035
+/* Mixer - ADC */
+#define RT5665_REC1_GAIN			0x003a
+#define RT5665_REC1_L1_MIXER			0x003b
+#define RT5665_REC1_L2_MIXER			0x003c
+#define RT5665_REC1_R1_MIXER			0x003d
+#define RT5665_REC1_R2_MIXER			0x003e
+#define RT5665_REC2_GAIN			0x003f
+#define RT5665_REC2_L1_MIXER			0x0040
+#define RT5665_REC2_L2_MIXER			0x0041
+#define RT5665_REC2_R1_MIXER			0x0042
+#define RT5665_REC2_R2_MIXER			0x0043
+#define RT5665_CAL_REC				0x0044
+/* Mixer - DAC */
+#define RT5665_ALC_BACK_GAIN			0x0049
+#define RT5665_MONOMIX_GAIN			0x004a
+#define RT5665_MONOMIX_IN_GAIN			0x004b
+#define RT5665_OUT_L_GAIN			0x004d
+#define RT5665_OUT_L_MIXER			0x004e
+#define RT5665_OUT_R_GAIN			0x004f
+#define RT5665_OUT_R_MIXER			0x0050
+#define RT5665_LOUT_MIXER			0x0052
+/* Power */
+#define RT5665_PWR_DIG_1			0x0061
+#define RT5665_PWR_DIG_2			0x0062
+#define RT5665_PWR_ANLG_1			0x0063
+#define RT5665_PWR_ANLG_2			0x0064
+#define RT5665_PWR_ANLG_3			0x0065
+#define RT5665_PWR_MIXER			0x0066
+#define RT5665_PWR_VOL				0x0067
+/* Clock Detect */
+#define RT5665_CLK_DET				0x006b
+/* Filter */
+#define RT5665_HPF_CTRL1			0x006d
+/* DMIC */
+#define RT5665_DMIC_CTRL_1			0x006e
+#define RT5665_DMIC_CTRL_2			0x006f
+/* Format - ADC/DAC */
+#define RT5665_I2S1_SDP				0x0070
+#define RT5665_I2S2_SDP				0x0071
+#define RT5665_I2S3_SDP				0x0072
+#define RT5665_ADDA_CLK_1			0x0073
+#define RT5665_ADDA_CLK_2			0x0074
+#define RT5665_I2S1_F_DIV_CTRL_1		0x0075
+#define RT5665_I2S1_F_DIV_CTRL_2		0x0076
+/* Format - TDM Control */
+#define RT5665_TDM_CTRL_1			0x0078
+#define RT5665_TDM_CTRL_2			0x0079
+#define RT5665_TDM_CTRL_3			0x007a
+#define RT5665_TDM_CTRL_4			0x007b
+#define RT5665_TDM_CTRL_5			0x007c
+#define RT5665_TDM_CTRL_6			0x007d
+#define RT5665_TDM_CTRL_7			0x007e
+#define RT5665_TDM_CTRL_8			0x007f
+/* Function - Analog */
+#define RT5665_GLB_CLK				0x0080
+#define RT5665_PLL_CTRL_1			0x0081
+#define RT5665_PLL_CTRL_2			0x0082
+#define RT5665_ASRC_1				0x0083
+#define RT5665_ASRC_2				0x0084
+#define RT5665_ASRC_3				0x0085
+#define RT5665_ASRC_4				0x0086
+#define RT5665_ASRC_5				0x0087
+#define RT5665_ASRC_6				0x0088
+#define RT5665_ASRC_7				0x0089
+#define RT5665_ASRC_8				0x008a
+#define RT5665_ASRC_9				0x008b
+#define RT5665_ASRC_10				0x008c
+#define RT5665_DEPOP_1				0x008e
+#define RT5665_DEPOP_2				0x008f
+#define RT5665_HP_CHARGE_PUMP_1			0x0091
+#define RT5665_HP_CHARGE_PUMP_2			0x0092
+#define RT5665_MICBIAS_1			0x0093
+#define RT5665_MICBIAS_2			0x0094
+#define RT5665_ASRC_12				0x0098
+#define RT5665_ASRC_13				0x0099
+#define RT5665_ASRC_14				0x009a
+#define RT5665_RC_CLK_CTRL			0x009f
+#define RT5665_I2S_M_CLK_CTRL_1			0x00a0
+#define RT5665_I2S2_F_DIV_CTRL_1		0x00a1
+#define RT5665_I2S2_F_DIV_CTRL_2		0x00a2
+#define RT5665_I2S3_F_DIV_CTRL_1		0x00a3
+#define RT5665_I2S3_F_DIV_CTRL_2		0x00a4
+/* Function - Digital */
+#define RT5665_EQ_CTRL_1			0x00ae
+#define RT5665_EQ_CTRL_2			0x00af
+#define RT5665_IRQ_CTRL_1			0x00b6
+#define RT5665_IRQ_CTRL_2			0x00b7
+#define RT5665_IRQ_CTRL_3			0x00b8
+#define RT5665_IRQ_CTRL_4			0x00b9
+#define RT5665_IRQ_CTRL_5			0x00ba
+#define RT5665_IRQ_CTRL_6			0x00bb
+#define RT5665_INT_ST_1				0x00be
+#define RT5665_GPIO_CTRL_1			0x00c0
+#define RT5665_GPIO_CTRL_2			0x00c1
+#define RT5665_GPIO_CTRL_3			0x00c2
+#define RT5665_GPIO_CTRL_4			0x00c3
+#define RT5665_GPIO_STA				0x00c4
+#define RT5665_HP_AMP_DET_CTRL_1		0x00d0
+#define RT5665_HP_AMP_DET_CTRL_2		0x00d1
+#define RT5665_MID_HP_AMP_DET			0x00d3
+#define RT5665_LOW_HP_AMP_DET			0x00d4
+#define RT5665_SV_ZCD_1				0x00d9
+#define RT5665_SV_ZCD_2				0x00da
+#define RT5665_IL_CMD_1				0x00db
+#define RT5665_IL_CMD_2				0x00dc
+#define RT5665_IL_CMD_3				0x00dd
+#define RT5665_IL_CMD_4				0x00de
+#define RT5665_4BTN_IL_CMD_1			0x00df
+#define RT5665_4BTN_IL_CMD_2			0x00e0
+#define RT5665_4BTN_IL_CMD_3			0x00e1
+#define RT5665_PSV_IL_CMD_1			0x00e2
+
+#define RT5665_ADC_STO1_HP_CTRL_1		0x00ea
+#define RT5665_ADC_STO1_HP_CTRL_2		0x00eb
+#define RT5665_ADC_MONO_HP_CTRL_1		0x00ec
+#define RT5665_ADC_MONO_HP_CTRL_2		0x00ed
+#define RT5665_ADC_STO2_HP_CTRL_1		0x00ee
+#define RT5665_ADC_STO2_HP_CTRL_2		0x00ef
+#define RT5665_AJD1_CTRL			0x00f0
+#define RT5665_JD1_THD				0x00f1
+#define RT5665_JD2_THD				0x00f2
+#define RT5665_JD_CTRL_1			0x00f6
+#define RT5665_JD_CTRL_2			0x00f7
+#define RT5665_JD_CTRL_3			0x00f8
+/* General Control */
+#define RT5665_DIG_MISC				0x00fa
+#define RT5665_DUMMY_2				0x00fb
+#define RT5665_DUMMY_3				0x00fc
+
+#define RT5665_DAC_ADC_DIG_VOL1			0x0100
+#define RT5665_DAC_ADC_DIG_VOL2			0x0101
+#define RT5665_BIAS_CUR_CTRL_1			0x010a
+#define RT5665_BIAS_CUR_CTRL_2			0x010b
+#define RT5665_BIAS_CUR_CTRL_3			0x010c
+#define RT5665_BIAS_CUR_CTRL_4			0x010d
+#define RT5665_BIAS_CUR_CTRL_5			0x010e
+#define RT5665_BIAS_CUR_CTRL_6			0x010f
+#define RT5665_BIAS_CUR_CTRL_7			0x0110
+#define RT5665_BIAS_CUR_CTRL_8			0x0111
+#define RT5665_BIAS_CUR_CTRL_9			0x0112
+#define RT5665_BIAS_CUR_CTRL_10			0x0113
+#define RT5665_VREF_REC_OP_FB_CAP_CTRL		0x0117
+#define RT5665_CHARGE_PUMP_1			0x0125
+#define RT5665_DIG_IN_CTRL_1			0x0132
+#define RT5665_DIG_IN_CTRL_2			0x0133
+#define RT5665_PAD_DRIVING_CTRL			0x0137
+#define RT5665_SOFT_RAMP_DEPOP			0x0138
+#define RT5665_PLL				0x0139
+#define RT5665_CHOP_DAC				0x013a
+#define RT5665_CHOP_ADC				0x013b
+#define RT5665_CALIB_ADC_CTRL			0x013c
+#define RT5665_VOL_TEST				0x013f
+#define RT5665_TEST_MODE_CTRL_1			0x0145
+#define RT5665_TEST_MODE_CTRL_2			0x0146
+#define RT5665_TEST_MODE_CTRL_3			0x0147
+#define RT5665_TEST_MODE_CTRL_4			0x0148
+#define RT5665_BASSBACK_CTRL			0x0150
+#define RT5665_STO_NG2_CTRL_1			0x0160
+#define RT5665_STO_NG2_CTRL_2			0x0161
+#define RT5665_STO_NG2_CTRL_3			0x0162
+#define RT5665_STO_NG2_CTRL_4			0x0163
+#define RT5665_STO_NG2_CTRL_5			0x0164
+#define RT5665_STO_NG2_CTRL_6			0x0165
+#define RT5665_STO_NG2_CTRL_7			0x0166
+#define RT5665_STO_NG2_CTRL_8			0x0167
+#define RT5665_MONO_NG2_CTRL_1			0x0170
+#define RT5665_MONO_NG2_CTRL_2			0x0171
+#define RT5665_MONO_NG2_CTRL_3			0x0172
+#define RT5665_MONO_NG2_CTRL_4			0x0173
+#define RT5665_MONO_NG2_CTRL_5			0x0174
+#define RT5665_MONO_NG2_CTRL_6			0x0175
+#define RT5665_STO1_DAC_SIL_DET			0x0190
+#define RT5665_MONOL_DAC_SIL_DET		0x0191
+#define RT5665_MONOR_DAC_SIL_DET		0x0192
+#define RT5665_STO2_DAC_SIL_DET			0x0193
+#define RT5665_SIL_PSV_CTRL1			0x0194
+#define RT5665_SIL_PSV_CTRL2			0x0195
+#define RT5665_SIL_PSV_CTRL3			0x0196
+#define RT5665_SIL_PSV_CTRL4			0x0197
+#define RT5665_SIL_PSV_CTRL5			0x0198
+#define RT5665_SIL_PSV_CTRL6			0x0199
+#define RT5665_MONO_AMP_CALIB_CTRL_1		0x01a0
+#define RT5665_MONO_AMP_CALIB_CTRL_2		0x01a1
+#define RT5665_MONO_AMP_CALIB_CTRL_3		0x01a2
+#define RT5665_MONO_AMP_CALIB_CTRL_4		0x01a3
+#define RT5665_MONO_AMP_CALIB_CTRL_5		0x01a4
+#define RT5665_MONO_AMP_CALIB_CTRL_6		0x01a5
+#define RT5665_MONO_AMP_CALIB_CTRL_7		0x01a6
+#define RT5665_MONO_AMP_CALIB_STA1		0x01a7
+#define RT5665_MONO_AMP_CALIB_STA2		0x01a8
+#define RT5665_MONO_AMP_CALIB_STA3		0x01a9
+#define RT5665_MONO_AMP_CALIB_STA4		0x01aa
+#define RT5665_MONO_AMP_CALIB_STA6		0x01ab
+#define RT5665_HP_IMP_SENS_CTRL_01		0x01b5
+#define RT5665_HP_IMP_SENS_CTRL_02		0x01b6
+#define RT5665_HP_IMP_SENS_CTRL_03		0x01b7
+#define RT5665_HP_IMP_SENS_CTRL_04		0x01b8
+#define RT5665_HP_IMP_SENS_CTRL_05		0x01b9
+#define RT5665_HP_IMP_SENS_CTRL_06		0x01ba
+#define RT5665_HP_IMP_SENS_CTRL_07		0x01bb
+#define RT5665_HP_IMP_SENS_CTRL_08		0x01bc
+#define RT5665_HP_IMP_SENS_CTRL_09		0x01bd
+#define RT5665_HP_IMP_SENS_CTRL_10		0x01be
+#define RT5665_HP_IMP_SENS_CTRL_11		0x01bf
+#define RT5665_HP_IMP_SENS_CTRL_12		0x01c0
+#define RT5665_HP_IMP_SENS_CTRL_13		0x01c1
+#define RT5665_HP_IMP_SENS_CTRL_14		0x01c2
+#define RT5665_HP_IMP_SENS_CTRL_15		0x01c3
+#define RT5665_HP_IMP_SENS_CTRL_16		0x01c4
+#define RT5665_HP_IMP_SENS_CTRL_17		0x01c5
+#define RT5665_HP_IMP_SENS_CTRL_18		0x01c6
+#define RT5665_HP_IMP_SENS_CTRL_19		0x01c7
+#define RT5665_HP_IMP_SENS_CTRL_20		0x01c8
+#define RT5665_HP_IMP_SENS_CTRL_21		0x01c9
+#define RT5665_HP_IMP_SENS_CTRL_22		0x01ca
+#define RT5665_HP_IMP_SENS_CTRL_23		0x01cb
+#define RT5665_HP_IMP_SENS_CTRL_24		0x01cc
+#define RT5665_HP_IMP_SENS_CTRL_25		0x01cd
+#define RT5665_HP_IMP_SENS_CTRL_26		0x01ce
+#define RT5665_HP_IMP_SENS_CTRL_27		0x01cf
+#define RT5665_HP_IMP_SENS_CTRL_28		0x01d0
+#define RT5665_HP_IMP_SENS_CTRL_29		0x01d1
+#define RT5665_HP_IMP_SENS_CTRL_30		0x01d2
+#define RT5665_HP_IMP_SENS_CTRL_31		0x01d3
+#define RT5665_HP_IMP_SENS_CTRL_32		0x01d4
+#define RT5665_HP_IMP_SENS_CTRL_33		0x01d5
+#define RT5665_HP_IMP_SENS_CTRL_34		0x01d6
+#define RT5665_HP_LOGIC_CTRL_1			0x01da
+#define RT5665_HP_LOGIC_CTRL_2			0x01db
+#define RT5665_HP_LOGIC_CTRL_3			0x01dc
+#define RT5665_HP_CALIB_CTRL_1			0x01de
+#define RT5665_HP_CALIB_CTRL_2			0x01df
+#define RT5665_HP_CALIB_CTRL_3			0x01e0
+#define RT5665_HP_CALIB_CTRL_4			0x01e1
+#define RT5665_HP_CALIB_CTRL_5			0x01e2
+#define RT5665_HP_CALIB_CTRL_6			0x01e3
+#define RT5665_HP_CALIB_CTRL_7			0x01e4
+#define RT5665_HP_CALIB_CTRL_9			0x01e6
+#define RT5665_HP_CALIB_CTRL_10			0x01e7
+#define RT5665_HP_CALIB_CTRL_11			0x01e8
+#define RT5665_HP_CALIB_STA_1			0x01ea
+#define RT5665_HP_CALIB_STA_2			0x01eb
+#define RT5665_HP_CALIB_STA_3			0x01ec
+#define RT5665_HP_CALIB_STA_4			0x01ed
+#define RT5665_HP_CALIB_STA_5			0x01ee
+#define RT5665_HP_CALIB_STA_6			0x01ef
+#define RT5665_HP_CALIB_STA_7			0x01f0
+#define RT5665_HP_CALIB_STA_8			0x01f1
+#define RT5665_HP_CALIB_STA_9			0x01f2
+#define RT5665_HP_CALIB_STA_10			0x01f3
+#define RT5665_HP_CALIB_STA_11			0x01f4
+#define RT5665_PGM_TAB_CTRL1			0x0200
+#define RT5665_PGM_TAB_CTRL2			0x0201
+#define RT5665_PGM_TAB_CTRL3			0x0202
+#define RT5665_PGM_TAB_CTRL4			0x0203
+#define RT5665_PGM_TAB_CTRL5			0x0204
+#define RT5665_PGM_TAB_CTRL6			0x0205
+#define RT5665_PGM_TAB_CTRL7			0x0206
+#define RT5665_PGM_TAB_CTRL8			0x0207
+#define RT5665_PGM_TAB_CTRL9			0x0208
+#define RT5665_SAR_IL_CMD_1			0x0210
+#define RT5665_SAR_IL_CMD_2			0x0211
+#define RT5665_SAR_IL_CMD_3			0x0212
+#define RT5665_SAR_IL_CMD_4			0x0213
+#define RT5665_SAR_IL_CMD_5			0x0214
+#define RT5665_SAR_IL_CMD_6			0x0215
+#define RT5665_SAR_IL_CMD_7			0x0216
+#define RT5665_SAR_IL_CMD_8			0x0217
+#define RT5665_SAR_IL_CMD_9			0x0218
+#define RT5665_SAR_IL_CMD_10			0x0219
+#define RT5665_SAR_IL_CMD_11			0x021a
+#define RT5665_SAR_IL_CMD_12			0x021b
+#define RT5665_DRC1_CTRL_0			0x02ff
+#define RT5665_DRC1_CTRL_1			0x0300
+#define RT5665_DRC1_CTRL_2			0x0301
+#define RT5665_DRC1_CTRL_3			0x0302
+#define RT5665_DRC1_CTRL_4			0x0303
+#define RT5665_DRC1_CTRL_5			0x0304
+#define RT5665_DRC1_CTRL_6			0x0305
+#define RT5665_DRC1_HARD_LMT_CTRL_1		0x0306
+#define RT5665_DRC1_HARD_LMT_CTRL_2		0x0307
+#define RT5665_DRC1_PRIV_1			0x0310
+#define RT5665_DRC1_PRIV_2			0x0311
+#define RT5665_DRC1_PRIV_3			0x0312
+#define RT5665_DRC1_PRIV_4			0x0313
+#define RT5665_DRC1_PRIV_5			0x0314
+#define RT5665_DRC1_PRIV_6			0x0315
+#define RT5665_DRC1_PRIV_7			0x0316
+#define RT5665_DRC1_PRIV_8			0x0317
+#define RT5665_ALC_PGA_CTRL_1			0x0330
+#define RT5665_ALC_PGA_CTRL_2			0x0331
+#define RT5665_ALC_PGA_CTRL_3			0x0332
+#define RT5665_ALC_PGA_CTRL_4			0x0333
+#define RT5665_ALC_PGA_CTRL_5			0x0334
+#define RT5665_ALC_PGA_CTRL_6			0x0335
+#define RT5665_ALC_PGA_CTRL_7			0x0336
+#define RT5665_ALC_PGA_CTRL_8			0x0337
+#define RT5665_ALC_PGA_STA_1			0x0338
+#define RT5665_ALC_PGA_STA_2			0x0339
+#define RT5665_ALC_PGA_STA_3			0x033a
+#define RT5665_EQ_AUTO_RCV_CTRL1		0x03c0
+#define RT5665_EQ_AUTO_RCV_CTRL2		0x03c1
+#define RT5665_EQ_AUTO_RCV_CTRL3		0x03c2
+#define RT5665_EQ_AUTO_RCV_CTRL4		0x03c3
+#define RT5665_EQ_AUTO_RCV_CTRL5		0x03c4
+#define RT5665_EQ_AUTO_RCV_CTRL6		0x03c5
+#define RT5665_EQ_AUTO_RCV_CTRL7		0x03c6
+#define RT5665_EQ_AUTO_RCV_CTRL8		0x03c7
+#define RT5665_EQ_AUTO_RCV_CTRL9		0x03c8
+#define RT5665_EQ_AUTO_RCV_CTRL10		0x03c9
+#define RT5665_EQ_AUTO_RCV_CTRL11		0x03ca
+#define RT5665_EQ_AUTO_RCV_CTRL12		0x03cb
+#define RT5665_EQ_AUTO_RCV_CTRL13		0x03cc
+#define RT5665_ADC_L_EQ_LPF1_A1			0x03d0
+#define RT5665_R_EQ_LPF1_A1			0x03d1
+#define RT5665_L_EQ_LPF1_H0			0x03d2
+#define RT5665_R_EQ_LPF1_H0			0x03d3
+#define RT5665_L_EQ_BPF1_A1			0x03d4
+#define RT5665_R_EQ_BPF1_A1			0x03d5
+#define RT5665_L_EQ_BPF1_A2			0x03d6
+#define RT5665_R_EQ_BPF1_A2			0x03d7
+#define RT5665_L_EQ_BPF1_H0			0x03d8
+#define RT5665_R_EQ_BPF1_H0			0x03d9
+#define RT5665_L_EQ_BPF2_A1			0x03da
+#define RT5665_R_EQ_BPF2_A1			0x03db
+#define RT5665_L_EQ_BPF2_A2			0x03dc
+#define RT5665_R_EQ_BPF2_A2			0x03dd
+#define RT5665_L_EQ_BPF2_H0			0x03de
+#define RT5665_R_EQ_BPF2_H0			0x03df
+#define RT5665_L_EQ_BPF3_A1			0x03e0
+#define RT5665_R_EQ_BPF3_A1			0x03e1
+#define RT5665_L_EQ_BPF3_A2			0x03e2
+#define RT5665_R_EQ_BPF3_A2			0x03e3
+#define RT5665_L_EQ_BPF3_H0			0x03e4
+#define RT5665_R_EQ_BPF3_H0			0x03e5
+#define RT5665_L_EQ_BPF4_A1			0x03e6
+#define RT5665_R_EQ_BPF4_A1			0x03e7
+#define RT5665_L_EQ_BPF4_A2			0x03e8
+#define RT5665_R_EQ_BPF4_A2			0x03e9
+#define RT5665_L_EQ_BPF4_H0			0x03ea
+#define RT5665_R_EQ_BPF4_H0			0x03eb
+#define RT5665_L_EQ_HPF1_A1			0x03ec
+#define RT5665_R_EQ_HPF1_A1			0x03ed
+#define RT5665_L_EQ_HPF1_H0			0x03ee
+#define RT5665_R_EQ_HPF1_H0			0x03ef
+#define RT5665_L_EQ_PRE_VOL			0x03f0
+#define RT5665_R_EQ_PRE_VOL			0x03f1
+#define RT5665_L_EQ_POST_VOL			0x03f2
+#define RT5665_R_EQ_POST_VOL			0x03f3
+#define RT5665_SCAN_MODE_CTRL			0x07f0
+#define RT5665_I2C_MODE				0x07fa
+
+
+
+/* global definition */
+#define RT5665_L_MUTE				(0x1 << 15)
+#define RT5665_L_MUTE_SFT			15
+#define RT5665_VOL_L_MUTE			(0x1 << 14)
+#define RT5665_VOL_L_SFT			14
+#define RT5665_R_MUTE				(0x1 << 7)
+#define RT5665_R_MUTE_SFT			7
+#define RT5665_VOL_R_MUTE			(0x1 << 6)
+#define RT5665_VOL_R_SFT			6
+#define RT5665_L_VOL_MASK			(0x3f << 8)
+#define RT5665_L_VOL_SFT			8
+#define RT5665_R_VOL_MASK			(0x3f)
+#define RT5665_R_VOL_SFT			0
+
+/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/
+#define RT5665_G_HP				(0xf << 8)
+#define RT5665_G_HP_SFT				8
+#define RT5665_G_STO_DA_DMIX			(0xf)
+#define RT5665_G_STO_DA_SFT			0
+
+/* CBJ Control (0x000b) */
+#define RT5665_BST_CBJ_MASK			(0xf << 8)
+#define RT5665_BST_CBJ_SFT			8
+
+/* IN1/IN2 Control (0x000c) */
+#define RT5665_IN1_DF_MASK			(0x1 << 15)
+#define RT5665_IN1_DF				15
+#define RT5665_BST1_MASK			(0x7f << 8)
+#define RT5665_BST1_SFT				8
+#define RT5665_IN2_DF_MASK			(0x1 << 7)
+#define RT5665_IN2_DF				7
+#define RT5665_BST2_MASK			(0x7f)
+#define RT5665_BST2_SFT				0
+
+/* IN3/IN4 Control (0x000d) */
+#define RT5665_IN3_DF_MASK			(0x1 << 15)
+#define RT5665_IN3_DF				15
+#define RT5665_BST3_MASK			(0x7f << 8)
+#define RT5665_BST3_SFT				8
+#define RT5665_IN4_DF_MASK			(0x1 << 7)
+#define RT5665_IN4_DF				7
+#define RT5665_BST4_MASK			(0x7f)
+#define RT5665_BST4_SFT				0
+
+/* INL and INR Volume Control (0x000f) */
+#define RT5665_INL_VOL_MASK			(0x1f << 8)
+#define RT5665_INL_VOL_SFT			8
+#define RT5665_INR_VOL_MASK			(0x1f)
+#define RT5665_INR_VOL_SFT			0
+
+/* Embeeded Jack and Type Detection Control 1 (0x0010) */
+#define RT5665_EMB_JD_EN			(0x1 << 15)
+#define RT5665_EMB_JD_EN_SFT			15
+#define RT5665_JD_MODE				(0x1 << 13)
+#define RT5665_JD_MODE_SFT			13
+#define RT5665_POLA_EXT_JD_MASK			(0x1 << 11)
+#define RT5665_POLA_EXT_JD_LOW			(0x1 << 11)
+#define RT5665_POLA_EXT_JD_HIGH			(0x0 << 11)
+#define RT5665_EXT_JD_DIG			(0x1 << 9)
+#define RT5665_POL_FAST_OFF_MASK		(0x1 << 8)
+#define RT5665_POL_FAST_OFF_HIGH		(0x1 << 8)
+#define RT5665_POL_FAST_OFF_LOW			(0x0 << 8)
+#define RT5665_VREF_POW_MASK			(0x1 << 6)
+#define RT5665_VREF_POW_FSM			(0x0 << 6)
+#define RT5665_VREF_POW_REG			(0x1 << 6)
+#define RT5665_MB1_PATH_MASK			(0x1 << 5)
+#define RT5665_CTRL_MB1_REG			(0x1 << 5)
+#define RT5665_CTRL_MB1_FSM			(0x0 << 5)
+#define RT5665_MB2_PATH_MASK			(0x1 << 4)
+#define RT5665_CTRL_MB2_REG			(0x1 << 4)
+#define RT5665_CTRL_MB2_FSM			(0x0 << 4)
+#define RT5665_TRIG_JD_MASK			(0x1 << 3)
+#define RT5665_TRIG_JD_HIGH			(0x1 << 3)
+#define RT5665_TRIG_JD_LOW			(0x0 << 3)
+
+/* Embeeded Jack and Type Detection Control 2 (0x0011) */
+#define RT5665_EXT_JD_SRC			(0x7 << 4)
+#define RT5665_EXT_JD_SRC_SFT			4
+#define RT5665_EXT_JD_SRC_GPIO_JD1		(0x0 << 4)
+#define RT5665_EXT_JD_SRC_GPIO_JD2		(0x1 << 4)
+#define RT5665_EXT_JD_SRC_JD1_1			(0x2 << 4)
+#define RT5665_EXT_JD_SRC_JD1_2			(0x3 << 4)
+#define RT5665_EXT_JD_SRC_JD2			(0x4 << 4)
+#define RT5665_EXT_JD_SRC_JD3			(0x5 << 4)
+#define RT5665_EXT_JD_SRC_MANUAL		(0x6 << 4)
+
+/* Combo Jack and Type Detection Control 4 (0x0013) */
+#define RT5665_SEL_SHT_MID_TON_MASK		(0x3 << 12)
+#define RT5665_SEL_SHT_MID_TON_2		(0x0 << 12)
+#define RT5665_SEL_SHT_MID_TON_3		(0x1 << 12)
+#define RT5665_CBJ_JD_TEST_MASK			(0x1 << 6)
+#define RT5665_CBJ_JD_TEST_NORM			(0x0 << 6)
+#define RT5665_CBJ_JD_TEST_MODE			(0x1 << 6)
+
+/* Slience Detection Control (0x0015) */
+#define RT5665_SIL_DET_MASK			(0x1 << 15)
+#define RT5665_SIL_DET_DIS			(0x0 << 15)
+#define RT5665_SIL_DET_EN			(0x1 << 15)
+
+/* DAC2 Control (0x0017) */
+#define RT5665_M_DAC2_L_VOL			(0x1 << 13)
+#define RT5665_M_DAC2_L_VOL_SFT			13
+#define RT5665_M_DAC2_R_VOL			(0x1 << 12)
+#define RT5665_M_DAC2_R_VOL_SFT			12
+#define RT5665_DAC_L2_SEL_MASK			(0x7 << 4)
+#define RT5665_DAC_L2_SEL_SFT			4
+#define RT5665_DAC_R2_SEL_MASK			(0x7 << 0)
+#define RT5665_DAC_R2_SEL_SFT			0
+
+/* Sidetone Control (0x0018) */
+#define RT5665_ST_SEL_MASK			(0x7 << 9)
+#define RT5665_ST_SEL_SFT			9
+#define RT5665_ST_EN				(0x1 << 6)
+#define RT5665_ST_EN_SFT			6
+
+/* DAC1 Digital Volume (0x0019) */
+#define RT5665_DAC_L1_VOL_MASK			(0xff << 8)
+#define RT5665_DAC_L1_VOL_SFT			8
+#define RT5665_DAC_R1_VOL_MASK			(0xff)
+#define RT5665_DAC_R1_VOL_SFT			0
+
+/* DAC2 Digital Volume (0x001a) */
+#define RT5665_DAC_L2_VOL_MASK			(0xff << 8)
+#define RT5665_DAC_L2_VOL_SFT			8
+#define RT5665_DAC_R2_VOL_MASK			(0xff)
+#define RT5665_DAC_R2_VOL_SFT			0
+
+/* DAC3 Control (0x001b) */
+#define RT5665_M_DAC3_L_VOL			(0x1 << 13)
+#define RT5665_M_DAC3_L_VOL_SFT			13
+#define RT5665_M_DAC3_R_VOL			(0x1 << 12)
+#define RT5665_M_DAC3_R_VOL_SFT			12
+#define RT5665_DAC_L3_SEL_MASK			(0x7 << 4)
+#define RT5665_DAC_L3_SEL_SFT			4
+#define RT5665_DAC_R3_SEL_MASK			(0x7 << 0)
+#define RT5665_DAC_R3_SEL_SFT			0
+
+/* ADC Digital Volume Control (0x001c) */
+#define RT5665_ADC_L_VOL_MASK			(0x7f << 8)
+#define RT5665_ADC_L_VOL_SFT			8
+#define RT5665_ADC_R_VOL_MASK			(0x7f)
+#define RT5665_ADC_R_VOL_SFT			0
+
+/* Mono ADC Digital Volume Control (0x001d) */
+#define RT5665_MONO_ADC_L_VOL_MASK		(0x7f << 8)
+#define RT5665_MONO_ADC_L_VOL_SFT		8
+#define RT5665_MONO_ADC_R_VOL_MASK		(0x7f)
+#define RT5665_MONO_ADC_R_VOL_SFT		0
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5665_STO1_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5665_STO1_ADC_L_BST_SFT		14
+#define RT5665_STO1_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5665_STO1_ADC_R_BST_SFT		12
+
+/* Mono ADC Boost Gain Control (0x0020) */
+#define RT5665_MONO_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5665_MONO_ADC_L_BST_SFT		14
+#define RT5665_MONO_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5665_MONO_ADC_R_BST_SFT		12
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5665_STO2_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5665_STO2_ADC_L_BST_SFT		14
+#define RT5665_STO2_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5665_STO2_ADC_R_BST_SFT		12
+
+/* Stereo1 ADC Mixer Control (0x0026) */
+#define RT5665_M_STO1_ADC_L1			(0x1 << 15)
+#define RT5665_M_STO1_ADC_L1_SFT		15
+#define RT5665_M_STO1_ADC_L2			(0x1 << 14)
+#define RT5665_M_STO1_ADC_L2_SFT		14
+#define RT5665_STO1_ADC1L_SRC_MASK		(0x1 << 13)
+#define RT5665_STO1_ADC1L_SRC_SFT		13
+#define RT5665_STO1_ADC1_SRC_ADC		(0x1 << 13)
+#define RT5665_STO1_ADC1_SRC_DACMIX		(0x0 << 13)
+#define RT5665_STO1_ADC2L_SRC_MASK		(0x1 << 12)
+#define RT5665_STO1_ADC2L_SRC_SFT		12
+#define RT5665_STO1_ADCL_SRC_MASK		(0x3 << 10)
+#define RT5665_STO1_ADCL_SRC_SFT		10
+#define RT5665_STO1_DD_L_SRC_MASK		(0x1 << 9)
+#define RT5665_STO1_DD_L_SRC_SFT		9
+#define RT5665_STO1_DMIC_SRC_MASK		(0x1 << 8)
+#define RT5665_STO1_DMIC_SRC_SFT		8
+#define RT5665_STO1_DMIC_SRC_DMIC2		(0x1 << 8)
+#define RT5665_STO1_DMIC_SRC_DMIC1		(0x0 << 8)
+#define RT5665_M_STO1_ADC_R1			(0x1 << 7)
+#define RT5665_M_STO1_ADC_R1_SFT		7
+#define RT5665_M_STO1_ADC_R2			(0x1 << 6)
+#define RT5665_M_STO1_ADC_R2_SFT		6
+#define RT5665_STO1_ADC1R_SRC_MASK		(0x1 << 5)
+#define RT5665_STO1_ADC1R_SRC_SFT		5
+#define RT5665_STO1_ADC2R_SRC_MASK		(0x1 << 4)
+#define RT5665_STO1_ADC2R_SRC_SFT		4
+#define RT5665_STO1_ADCR_SRC_MASK		(0x3 << 2)
+#define RT5665_STO1_ADCR_SRC_SFT		2
+#define RT5665_STO1_DD_R_SRC_MASK		(0x3)
+#define RT5665_STO1_DD_R_SRC_SFT		0
+
+
+/* Mono1 ADC Mixer control (0x0027) */
+#define RT5665_M_MONO_ADC_L1			(0x1 << 15)
+#define RT5665_M_MONO_ADC_L1_SFT		15
+#define RT5665_M_MONO_ADC_L2			(0x1 << 14)
+#define RT5665_M_MONO_ADC_L2_SFT		14
+#define RT5665_MONO_ADC_L1_SRC_MASK		(0x1 << 13)
+#define RT5665_MONO_ADC_L1_SRC_SFT		13
+#define RT5665_MONO_ADC_L2_SRC_MASK		(0x1 << 12)
+#define RT5665_MONO_ADC_L2_SRC_SFT		12
+#define RT5665_MONO_ADC_L_SRC_MASK		(0x3 << 10)
+#define RT5665_MONO_ADC_L_SRC_SFT		10
+#define RT5665_MONO_DD_L_SRC_MASK		(0x1 << 9)
+#define RT5665_MONO_DD_L_SRC_SFT		9
+#define RT5665_MONO_DMIC_L_SRC_MASK		(0x1 << 8)
+#define RT5665_MONO_DMIC_L_SRC_SFT		8
+#define RT5665_M_MONO_ADC_R1			(0x1 << 7)
+#define RT5665_M_MONO_ADC_R1_SFT		7
+#define RT5665_M_MONO_ADC_R2			(0x1 << 6)
+#define RT5665_M_MONO_ADC_R2_SFT		6
+#define RT5665_MONO_ADC_R1_SRC_MASK		(0x1 << 5)
+#define RT5665_MONO_ADC_R1_SRC_SFT		5
+#define RT5665_MONO_ADC_R2_SRC_MASK		(0x1 << 4)
+#define RT5665_MONO_ADC_R2_SRC_SFT		4
+#define RT5665_MONO_ADC_R_SRC_MASK		(0x3 << 2)
+#define RT5665_MONO_ADC_R_SRC_SFT		2
+#define RT5665_MONO_DD_R_SRC_MASK		(0x1 << 1)
+#define RT5665_MONO_DD_R_SRC_SFT		1
+#define RT5665_MONO_DMIC_R_SRC_MASK		0x1
+#define RT5665_MONO_DMIC_R_SRC_SFT		0
+
+/* Stereo2 ADC Mixer Control (0x0028) */
+#define RT5665_M_STO2_ADC_L1			(0x1 << 15)
+#define RT5665_M_STO2_ADC_L1_UN			(0x0 << 15)
+#define RT5665_M_STO2_ADC_L1_SFT		15
+#define RT5665_M_STO2_ADC_L2			(0x1 << 14)
+#define RT5665_M_STO2_ADC_L2_SFT		14
+#define RT5665_STO2_ADC1L_SRC_MASK		(0x1 << 13)
+#define RT5665_STO2_ADC1L_SRC_SFT		13
+#define RT5665_STO2_ADC1_SRC_ADC		(0x1 << 13)
+#define RT5665_STO2_ADC1_SRC_DACMIX		(0x0 << 13)
+#define RT5665_STO2_ADC2L_SRC_MASK		(0x1 << 12)
+#define RT5665_STO2_ADC2L_SRC_SFT		12
+#define RT5665_STO2_ADCL_SRC_MASK		(0x3 << 10)
+#define RT5665_STO2_ADCL_SRC_SFT		10
+#define RT5665_STO2_DD_L_SRC_MASK		(0x1 << 9)
+#define RT5665_STO2_DD_L_SRC_SFT		9
+#define RT5665_STO2_DMIC_SRC_MASK		(0x1 << 8)
+#define RT5665_STO2_DMIC_SRC_SFT		8
+#define RT5665_STO2_DMIC_SRC_DMIC2		(0x1 << 8)
+#define RT5665_STO2_DMIC_SRC_DMIC1		(0x0 << 8)
+#define RT5665_M_STO2_ADC_R1			(0x1 << 7)
+#define RT5665_M_STO2_ADC_R1_UN			(0x0 << 7)
+#define RT5665_M_STO2_ADC_R1_SFT		7
+#define RT5665_M_STO2_ADC_R2			(0x1 << 6)
+#define RT5665_M_STO2_ADC_R2_SFT		6
+#define RT5665_STO2_ADC1R_SRC_MASK		(0x1 << 5)
+#define RT5665_STO2_ADC1R_SRC_SFT		5
+#define RT5665_STO2_ADC2R_SRC_MASK		(0x1 << 4)
+#define RT5665_STO2_ADC2R_SRC_SFT		4
+#define RT5665_STO2_ADCR_SRC_MASK		(0x3 << 2)
+#define RT5665_STO2_ADCR_SRC_SFT		2
+#define RT5665_STO2_DD_R_SRC_MASK		(0x1 << 1)
+#define RT5665_STO2_DD_R_SRC_SFT		1
+
+/* ADC Mixer to DAC Mixer Control (0x0029) */
+#define RT5665_M_ADCMIX_L			(0x1 << 15)
+#define RT5665_M_ADCMIX_L_SFT			15
+#define RT5665_M_DAC1_L				(0x1 << 14)
+#define RT5665_M_DAC1_L_SFT			14
+#define RT5665_DAC1_R_SEL_MASK			(0x3 << 10)
+#define RT5665_DAC1_R_SEL_SFT			10
+#define RT5665_DAC1_L_SEL_MASK			(0x3 << 8)
+#define RT5665_DAC1_L_SEL_SFT			8
+#define RT5665_M_ADCMIX_R			(0x1 << 7)
+#define RT5665_M_ADCMIX_R_SFT			7
+#define RT5665_M_DAC1_R				(0x1 << 6)
+#define RT5665_M_DAC1_R_SFT			6
+
+/* Stereo1 DAC Mixer Control (0x002a) */
+#define RT5665_M_DAC_L1_STO_L			(0x1 << 15)
+#define RT5665_M_DAC_L1_STO_L_SFT		15
+#define RT5665_G_DAC_L1_STO_L_MASK		(0x1 << 14)
+#define RT5665_G_DAC_L1_STO_L_SFT		14
+#define RT5665_M_DAC_R1_STO_L			(0x1 << 13)
+#define RT5665_M_DAC_R1_STO_L_SFT		13
+#define RT5665_G_DAC_R1_STO_L_MASK		(0x1 << 12)
+#define RT5665_G_DAC_R1_STO_L_SFT		12
+#define RT5665_M_DAC_L2_STO_L			(0x1 << 11)
+#define RT5665_M_DAC_L2_STO_L_SFT		11
+#define RT5665_G_DAC_L2_STO_L_MASK		(0x1 << 10)
+#define RT5665_G_DAC_L2_STO_L_SFT		10
+#define RT5665_M_DAC_R2_STO_L			(0x1 << 9)
+#define RT5665_M_DAC_R2_STO_L_SFT		9
+#define RT5665_G_DAC_R2_STO_L_MASK		(0x1 << 8)
+#define RT5665_G_DAC_R2_STO_L_SFT		8
+#define RT5665_M_DAC_L1_STO_R			(0x1 << 7)
+#define RT5665_M_DAC_L1_STO_R_SFT		7
+#define RT5665_G_DAC_L1_STO_R_MASK		(0x1 << 6)
+#define RT5665_G_DAC_L1_STO_R_SFT		6
+#define RT5665_M_DAC_R1_STO_R			(0x1 << 5)
+#define RT5665_M_DAC_R1_STO_R_SFT		5
+#define RT5665_G_DAC_R1_STO_R_MASK		(0x1 << 4)
+#define RT5665_G_DAC_R1_STO_R_SFT		4
+#define RT5665_M_DAC_L2_STO_R			(0x1 << 3)
+#define RT5665_M_DAC_L2_STO_R_SFT		3
+#define RT5665_G_DAC_L2_STO_R_MASK		(0x1 << 2)
+#define RT5665_G_DAC_L2_STO_R_SFT		2
+#define RT5665_M_DAC_R2_STO_R			(0x1 << 1)
+#define RT5665_M_DAC_R2_STO_R_SFT		1
+#define RT5665_G_DAC_R2_STO_R_MASK		(0x1)
+#define RT5665_G_DAC_R2_STO_R_SFT		0
+
+/* Mono DAC Mixer Control (0x002b) */
+#define RT5665_M_DAC_L1_MONO_L			(0x1 << 15)
+#define RT5665_M_DAC_L1_MONO_L_SFT		15
+#define RT5665_G_DAC_L1_MONO_L_MASK		(0x1 << 14)
+#define RT5665_G_DAC_L1_MONO_L_SFT		14
+#define RT5665_M_DAC_R1_MONO_L			(0x1 << 13)
+#define RT5665_M_DAC_R1_MONO_L_SFT		13
+#define RT5665_G_DAC_R1_MONO_L_MASK		(0x1 << 12)
+#define RT5665_G_DAC_R1_MONO_L_SFT		12
+#define RT5665_M_DAC_L2_MONO_L			(0x1 << 11)
+#define RT5665_M_DAC_L2_MONO_L_SFT		11
+#define RT5665_G_DAC_L2_MONO_L_MASK		(0x1 << 10)
+#define RT5665_G_DAC_L2_MONO_L_SFT		10
+#define RT5665_M_DAC_R2_MONO_L			(0x1 << 9)
+#define RT5665_M_DAC_R2_MONO_L_SFT		9
+#define RT5665_G_DAC_R2_MONO_L_MASK		(0x1 << 8)
+#define RT5665_G_DAC_R2_MONO_L_SFT		8
+#define RT5665_M_DAC_L1_MONO_R			(0x1 << 7)
+#define RT5665_M_DAC_L1_MONO_R_SFT		7
+#define RT5665_G_DAC_L1_MONO_R_MASK		(0x1 << 6)
+#define RT5665_G_DAC_L1_MONO_R_SFT		6
+#define RT5665_M_DAC_R1_MONO_R			(0x1 << 5)
+#define RT5665_M_DAC_R1_MONO_R_SFT		5
+#define RT5665_G_DAC_R1_MONO_R_MASK		(0x1 << 4)
+#define RT5665_G_DAC_R1_MONO_R_SFT		4
+#define RT5665_M_DAC_L2_MONO_R			(0x1 << 3)
+#define RT5665_M_DAC_L2_MONO_R_SFT		3
+#define RT5665_G_DAC_L2_MONO_R_MASK		(0x1 << 2)
+#define RT5665_G_DAC_L2_MONO_R_SFT		2
+#define RT5665_M_DAC_R2_MONO_R			(0x1 << 1)
+#define RT5665_M_DAC_R2_MONO_R_SFT		1
+#define RT5665_G_DAC_R2_MONO_R_MASK		(0x1)
+#define RT5665_G_DAC_R2_MONO_R_SFT		0
+
+/* Stereo2 DAC Mixer Control (0x002c) */
+#define RT5665_M_DAC_L1_STO2_L			(0x1 << 15)
+#define RT5665_M_DAC_L1_STO2_L_SFT		15
+#define RT5665_G_DAC_L1_STO2_L_MASK		(0x1 << 14)
+#define RT5665_G_DAC_L1_STO2_L_SFT		14
+#define RT5665_M_DAC_L2_STO2_L			(0x1 << 13)
+#define RT5665_M_DAC_L2_STO2_L_SFT		13
+#define RT5665_G_DAC_L2_STO2_L_MASK		(0x1 << 12)
+#define RT5665_G_DAC_L2_STO2_L_SFT		12
+#define RT5665_M_DAC_L3_STO2_L			(0x1 << 11)
+#define RT5665_M_DAC_L3_STO2_L_SFT		11
+#define RT5665_G_DAC_L3_STO2_L_MASK		(0x1 << 10)
+#define RT5665_G_DAC_L3_STO2_L_SFT		10
+#define RT5665_M_ST_DAC_L1			(0x1 << 9)
+#define RT5665_M_ST_DAC_L1_SFT			9
+#define RT5665_M_ST_DAC_R1			(0x1 << 8)
+#define RT5665_M_ST_DAC_R1_SFT			8
+#define RT5665_M_DAC_R1_STO2_R			(0x1 << 7)
+#define RT5665_M_DAC_R1_STO2_R_SFT		7
+#define RT5665_G_DAC_R1_STO2_R_MASK		(0x1 << 6)
+#define RT5665_G_DAC_R1_STO2_R_SFT		6
+#define RT5665_M_DAC_R2_STO2_R			(0x1 << 5)
+#define RT5665_M_DAC_R2_STO2_R_SFT		5
+#define RT5665_G_DAC_R2_STO2_R_MASK		(0x1 << 4)
+#define RT5665_G_DAC_R2_STO2_R_SFT		4
+#define RT5665_M_DAC_R3_STO2_R			(0x1 << 3)
+#define RT5665_M_DAC_R3_STO2_R_SFT		3
+#define RT5665_G_DAC_R3_STO2_R_MASK		(0x1 << 2)
+#define RT5665_G_DAC_R3_STO2_R_SFT		2
+
+/* Analog DAC1 Input Source Control (0x002d) */
+#define RT5665_DAC_MIX_L_MASK			(0x3 << 12)
+#define RT5665_DAC_MIX_L_SFT			12
+#define RT5665_DAC_MIX_R_MASK			(0x3 << 8)
+#define RT5665_DAC_MIX_R_SFT			8
+#define RT5665_DAC_L1_SRC_MASK			(0x3 << 4)
+#define RT5665_A_DACL1_SFT			4
+#define RT5665_DAC_R1_SRC_MASK			(0x3)
+#define RT5665_A_DACR1_SFT			0
+
+/* Analog DAC Input Source Control (0x002e) */
+#define RT5665_A_DACL2_SEL			(0x1 << 4)
+#define RT5665_A_DACL2_SFT			4
+#define RT5665_A_DACR2_SEL			(0x1 << 0)
+#define RT5665_A_DACR2_SFT			0
+
+/* Digital Interface Data Control (0x002f) */
+#define RT5665_IF2_1_ADC_IN_MASK		(0x7 << 12)
+#define RT5665_IF2_1_ADC_IN_SFT			12
+#define RT5665_IF2_1_DAC_SEL_MASK		(0x3 << 10)
+#define RT5665_IF2_1_DAC_SEL_SFT		10
+#define RT5665_IF2_1_ADC_SEL_MASK		(0x3 << 8)
+#define RT5665_IF2_1_ADC_SEL_SFT		8
+#define RT5665_IF2_2_ADC_IN_MASK		(0x7 << 4)
+#define RT5665_IF2_2_ADC_IN_SFT			4
+#define RT5665_IF2_2_DAC_SEL_MASK		(0x3 << 2)
+#define RT5665_IF2_2_DAC_SEL_SFT		2
+#define RT5665_IF2_2_ADC_SEL_MASK		(0x3 << 0)
+#define RT5665_IF2_2_ADC_SEL_SFT		0
+
+/* Digital Interface Data Control (0x0030) */
+#define RT5665_IF3_ADC_IN_MASK			(0x7 << 4)
+#define RT5665_IF3_ADC_IN_SFT			4
+#define RT5665_IF3_DAC_SEL_MASK			(0x3 << 2)
+#define RT5665_IF3_DAC_SEL_SFT			2
+#define RT5665_IF3_ADC_SEL_MASK			(0x3 << 0)
+#define RT5665_IF3_ADC_SEL_SFT			0
+
+/* PDM Output Control (0x0031) */
+#define RT5665_M_PDM1_L				(0x1 << 14)
+#define RT5665_M_PDM1_L_SFT			14
+#define RT5665_M_PDM1_R				(0x1 << 12)
+#define RT5665_M_PDM1_R_SFT			12
+#define RT5665_PDM1_L_MASK			(0x3 << 10)
+#define RT5665_PDM1_L_SFT			10
+#define RT5665_PDM1_R_MASK			(0x3 << 8)
+#define RT5665_PDM1_R_SFT			8
+#define RT5665_PDM1_BUSY			(0x1 << 6)
+#define RT5665_PDM_PATTERN			(0x1 << 5)
+#define RT5665_PDM_GAIN				(0x1 << 4)
+#define RT5665_LRCK_PDM_PI2C			(0x1 << 3)
+#define RT5665_PDM_DIV_MASK			(0x3)
+
+/*S/PDIF Output Control (0x0036) */
+#define RT5665_SPDIF_SEL_MASK			(0x3 << 0)
+#define RT5665_SPDIF_SEL_SFT			0
+
+/* REC Left Mixer Control 2 (0x003c) */
+#define RT5665_M_CBJ_RM1_L			(0x1 << 7)
+#define RT5665_M_CBJ_RM1_L_SFT			7
+#define RT5665_M_BST1_RM1_L			(0x1 << 5)
+#define RT5665_M_BST1_RM1_L_SFT			5
+#define RT5665_M_BST2_RM1_L			(0x1 << 4)
+#define RT5665_M_BST2_RM1_L_SFT			4
+#define RT5665_M_BST3_RM1_L			(0x1 << 3)
+#define RT5665_M_BST3_RM1_L_SFT			3
+#define RT5665_M_BST4_RM1_L			(0x1 << 2)
+#define RT5665_M_BST4_RM1_L_SFT			2
+#define RT5665_M_INL_RM1_L			(0x1 << 1)
+#define RT5665_M_INL_RM1_L_SFT			1
+#define RT5665_M_INR_RM1_L			(0x1)
+#define RT5665_M_INR_RM1_L_SFT			0
+
+/* REC Right Mixer Control 2 (0x003e) */
+#define RT5665_M_AEC_REF_RM1_R			(0x1 << 7)
+#define RT5665_M_AEC_REF_RM1_R_SFT		7
+#define RT5665_M_BST1_RM1_R			(0x1 << 5)
+#define RT5665_M_BST1_RM1_R_SFT			5
+#define RT5665_M_BST2_RM1_R			(0x1 << 4)
+#define RT5665_M_BST2_RM1_R_SFT			4
+#define RT5665_M_BST3_RM1_R			(0x1 << 3)
+#define RT5665_M_BST3_RM1_R_SFT			3
+#define RT5665_M_BST4_RM1_R			(0x1 << 2)
+#define RT5665_M_BST4_RM1_R_SFT			2
+#define RT5665_M_INR_RM1_R			(0x1 << 1)
+#define RT5665_M_INR_RM1_R_SFT			1
+#define RT5665_M_MONOVOL_RM1_R			(0x1)
+#define RT5665_M_MONOVOL_RM1_R_SFT		0
+
+/* REC Mixer 2 Left Control 2 (0x0041) */
+#define RT5665_M_CBJ_RM2_L			(0x1 << 7)
+#define RT5665_M_CBJ_RM2_L_SFT			7
+#define RT5665_M_BST1_RM2_L			(0x1 << 5)
+#define RT5665_M_BST1_RM2_L_SFT			5
+#define RT5665_M_BST2_RM2_L			(0x1 << 4)
+#define RT5665_M_BST2_RM2_L_SFT			4
+#define RT5665_M_BST3_RM2_L			(0x1 << 3)
+#define RT5665_M_BST3_RM2_L_SFT			3
+#define RT5665_M_BST4_RM2_L			(0x1 << 2)
+#define RT5665_M_BST4_RM2_L_SFT			2
+#define RT5665_M_INL_RM2_L			(0x1 << 1)
+#define RT5665_M_INL_RM2_L_SFT			1
+#define RT5665_M_INR_RM2_L			(0x1)
+#define RT5665_M_INR_RM2_L_SFT			0
+
+/* REC Mixer 2 Right Control 2 (0x0043) */
+#define RT5665_M_MONOVOL_RM2_R			(0x1 << 7)
+#define RT5665_M_MONOVOL_RM2_R_SFT		7
+#define RT5665_M_BST1_RM2_R			(0x1 << 5)
+#define RT5665_M_BST1_RM2_R_SFT			5
+#define RT5665_M_BST2_RM2_R			(0x1 << 4)
+#define RT5665_M_BST2_RM2_R_SFT			4
+#define RT5665_M_BST3_RM2_R			(0x1 << 3)
+#define RT5665_M_BST3_RM2_R_SFT			3
+#define RT5665_M_BST4_RM2_R			(0x1 << 2)
+#define RT5665_M_BST4_RM2_R_SFT			2
+#define RT5665_M_INL_RM2_R			(0x1 << 1)
+#define RT5665_M_INL_RM2_R_SFT			1
+#define RT5665_M_INR_RM2_R			(0x1)
+#define RT5665_M_INR_RM2_R_SFT			0
+
+/* SPK Left Mixer Control (0x0046) */
+#define RT5665_M_BST3_SM_L			(0x1 << 4)
+#define RT5665_M_BST3_SM_L_SFT			4
+#define RT5665_M_IN_R_SM_L			(0x1 << 3)
+#define RT5665_M_IN_R_SM_L_SFT			3
+#define RT5665_M_IN_L_SM_L			(0x1 << 2)
+#define RT5665_M_IN_L_SM_L_SFT			2
+#define RT5665_M_BST1_SM_L			(0x1 << 1)
+#define RT5665_M_BST1_SM_L_SFT			1
+#define RT5665_M_DAC_L2_SM_L			(0x1)
+#define RT5665_M_DAC_L2_SM_L_SFT		0
+
+/* SPK Right Mixer Control (0x0047) */
+#define RT5665_M_BST3_SM_R			(0x1 << 4)
+#define RT5665_M_BST3_SM_R_SFT			4
+#define RT5665_M_IN_R_SM_R			(0x1 << 3)
+#define RT5665_M_IN_R_SM_R_SFT			3
+#define RT5665_M_IN_L_SM_R			(0x1 << 2)
+#define RT5665_M_IN_L_SM_R_SFT			2
+#define RT5665_M_BST4_SM_R			(0x1 << 1)
+#define RT5665_M_BST4_SM_R_SFT			1
+#define RT5665_M_DAC_R2_SM_R			(0x1)
+#define RT5665_M_DAC_R2_SM_R_SFT		0
+
+/* SPO Amp Input and Gain Control (0x0048) */
+#define RT5665_M_DAC_L2_SPKOMIX			(0x1 << 13)
+#define RT5665_M_DAC_L2_SPKOMIX_SFT		13
+#define RT5665_M_SPKVOLL_SPKOMIX		(0x1 << 12)
+#define RT5665_M_SPKVOLL_SPKOMIX_SFT		12
+#define RT5665_M_DAC_R2_SPKOMIX			(0x1 << 9)
+#define RT5665_M_DAC_R2_SPKOMIX_SFT		9
+#define RT5665_M_SPKVOLR_SPKOMIX		(0x1 << 8)
+#define RT5665_M_SPKVOLR_SPKOMIX_SFT		8
+
+/* MONOMIX Input and Gain Control (0x004b) */
+#define RT5665_G_MONOVOL_MA			(0x1 << 10)
+#define RT5665_G_MONOVOL_MA_SFT			10
+#define RT5665_M_MONOVOL_MA			(0x1 << 9)
+#define RT5665_M_MONOVOL_MA_SFT			9
+#define RT5665_M_DAC_L2_MA			(0x1 << 8)
+#define RT5665_M_DAC_L2_MA_SFT			8
+#define RT5665_M_BST3_MM			(0x1 << 4)
+#define RT5665_M_BST3_MM_SFT			4
+#define RT5665_M_BST2_MM			(0x1 << 3)
+#define RT5665_M_BST2_MM_SFT			3
+#define RT5665_M_BST1_MM			(0x1 << 2)
+#define RT5665_M_BST1_MM_SFT			2
+#define RT5665_M_RECMIC2L_MM			(0x1 << 1)
+#define RT5665_M_RECMIC2L_MM_SFT		1
+#define RT5665_M_DAC_L2_MM			(0x1)
+#define RT5665_M_DAC_L2_MM_SFT			0
+
+/* Output Left Mixer Control 1 (0x004d) */
+#define RT5665_G_BST3_OM_L_MASK			(0x7 << 12)
+#define RT5665_G_BST3_OM_L_SFT			12
+#define RT5665_G_BST2_OM_L_MASK			(0x7 << 9)
+#define RT5665_G_BST2_OM_L_SFT			9
+#define RT5665_G_BST1_OM_L_MASK			(0x7 << 6)
+#define RT5665_G_BST1_OM_L_SFT			6
+#define RT5665_G_IN_L_OM_L_MASK			(0x7 << 3)
+#define RT5665_G_IN_L_OM_L_SFT			3
+#define RT5665_G_DAC_L2_OM_L_MASK		(0x7 << 0)
+#define RT5665_G_DAC_L2_OM_L_SFT		0
+
+/* Output Left Mixer Input Control (0x004e) */
+#define RT5665_M_BST3_OM_L			(0x1 << 4)
+#define RT5665_M_BST3_OM_L_SFT			4
+#define RT5665_M_BST2_OM_L			(0x1 << 3)
+#define RT5665_M_BST2_OM_L_SFT			3
+#define RT5665_M_BST1_OM_L			(0x1 << 2)
+#define RT5665_M_BST1_OM_L_SFT			2
+#define RT5665_M_IN_L_OM_L			(0x1 << 1)
+#define RT5665_M_IN_L_OM_L_SFT			1
+#define RT5665_M_DAC_L2_OM_L			(0x1)
+#define RT5665_M_DAC_L2_OM_L_SFT		0
+
+/* Output Right Mixer Input Control (0x0050) */
+#define RT5665_M_BST4_OM_R			(0x1 << 4)
+#define RT5665_M_BST4_OM_R_SFT			4
+#define RT5665_M_BST3_OM_R			(0x1 << 3)
+#define RT5665_M_BST3_OM_R_SFT			3
+#define RT5665_M_BST2_OM_R			(0x1 << 2)
+#define RT5665_M_BST2_OM_R_SFT			2
+#define RT5665_M_IN_R_OM_R			(0x1 << 1)
+#define RT5665_M_IN_R_OM_R_SFT			1
+#define RT5665_M_DAC_R2_OM_R			(0x1)
+#define RT5665_M_DAC_R2_OM_R_SFT		0
+
+/* LOUT Mixer Control (0x0052) */
+#define RT5665_M_DAC_L2_LM			(0x1 << 15)
+#define RT5665_M_DAC_L2_LM_SFT			15
+#define RT5665_M_DAC_R2_LM			(0x1 << 14)
+#define RT5665_M_DAC_R2_LM_SFT			14
+#define RT5665_M_OV_L_LM			(0x1 << 13)
+#define RT5665_M_OV_L_LM_SFT			13
+#define RT5665_M_OV_R_LM			(0x1 << 12)
+#define RT5665_M_OV_R_LM_SFT			12
+#define RT5665_LOUT_BST_SFT			11
+#define RT5665_LOUT_DF				(0x1 << 11)
+#define RT5665_LOUT_DF_SFT			11
+
+/* Power Management for Digital 1 (0x0061) */
+#define RT5665_PWR_I2S1_1			(0x1 << 15)
+#define RT5665_PWR_I2S1_1_BIT			15
+#define RT5665_PWR_I2S1_2			(0x1 << 14)
+#define RT5665_PWR_I2S1_2_BIT			14
+#define RT5665_PWR_I2S2_1			(0x1 << 13)
+#define RT5665_PWR_I2S2_1_BIT			13
+#define RT5665_PWR_I2S2_2			(0x1 << 12)
+#define RT5665_PWR_I2S2_2_BIT			12
+#define RT5665_PWR_DAC_L1			(0x1 << 11)
+#define RT5665_PWR_DAC_L1_BIT			11
+#define RT5665_PWR_DAC_R1			(0x1 << 10)
+#define RT5665_PWR_DAC_R1_BIT			10
+#define RT5665_PWR_I2S3				(0x1 << 9)
+#define RT5665_PWR_I2S3_BIT			9
+#define RT5665_PWR_LDO				(0x1 << 8)
+#define RT5665_PWR_LDO_BIT			8
+#define RT5665_PWR_DAC_L2			(0x1 << 7)
+#define RT5665_PWR_DAC_L2_BIT			7
+#define RT5665_PWR_DAC_R2			(0x1 << 6)
+#define RT5665_PWR_DAC_R2_BIT			6
+#define RT5665_PWR_ADC_L1			(0x1 << 4)
+#define RT5665_PWR_ADC_L1_BIT			4
+#define RT5665_PWR_ADC_R1			(0x1 << 3)
+#define RT5665_PWR_ADC_R1_BIT			3
+#define RT5665_PWR_ADC_L2			(0x1 << 2)
+#define RT5665_PWR_ADC_L2_BIT			2
+#define RT5665_PWR_ADC_R2			(0x1 << 1)
+#define RT5665_PWR_ADC_R2_BIT			1
+
+/* Power Management for Digital 2 (0x0062) */
+#define RT5665_PWR_ADC_S1F			(0x1 << 15)
+#define RT5665_PWR_ADC_S1F_BIT			15
+#define RT5665_PWR_ADC_S2F			(0x1 << 14)
+#define RT5665_PWR_ADC_S2F_BIT			14
+#define RT5665_PWR_ADC_MF_L			(0x1 << 13)
+#define RT5665_PWR_ADC_MF_L_BIT			13
+#define RT5665_PWR_ADC_MF_R			(0x1 << 12)
+#define RT5665_PWR_ADC_MF_R_BIT			12
+#define RT5665_PWR_DAC_S2F			(0x1 << 11)
+#define RT5665_PWR_DAC_S2F_BIT			11
+#define RT5665_PWR_DAC_S1F			(0x1 << 10)
+#define RT5665_PWR_DAC_S1F_BIT			10
+#define RT5665_PWR_DAC_MF_L			(0x1 << 9)
+#define RT5665_PWR_DAC_MF_L_BIT			9
+#define RT5665_PWR_DAC_MF_R			(0x1 << 8)
+#define RT5665_PWR_DAC_MF_R_BIT			8
+#define RT5665_PWR_PDM1				(0x1 << 7)
+#define RT5665_PWR_PDM1_BIT			7
+
+/* Power Management for Analog 1 (0x0063) */
+#define RT5665_PWR_VREF1			(0x1 << 15)
+#define RT5665_PWR_VREF1_BIT			15
+#define RT5665_PWR_FV1				(0x1 << 14)
+#define RT5665_PWR_FV1_BIT			14
+#define RT5665_PWR_VREF2			(0x1 << 13)
+#define RT5665_PWR_VREF2_BIT			13
+#define RT5665_PWR_FV2				(0x1 << 12)
+#define RT5665_PWR_FV2_BIT			12
+#define RT5665_PWR_VREF3			(0x1 << 11)
+#define RT5665_PWR_VREF3_BIT			11
+#define RT5665_PWR_FV3				(0x1 << 10)
+#define RT5665_PWR_FV3_BIT			10
+#define RT5665_PWR_MB				(0x1 << 9)
+#define RT5665_PWR_MB_BIT			9
+#define RT5665_PWR_LM				(0x1 << 8)
+#define RT5665_PWR_LM_BIT			8
+#define RT5665_PWR_BG				(0x1 << 7)
+#define RT5665_PWR_BG_BIT			7
+#define RT5665_PWR_MA				(0x1 << 6)
+#define RT5665_PWR_MA_BIT			6
+#define RT5665_PWR_HA_L				(0x1 << 5)
+#define RT5665_PWR_HA_L_BIT			5
+#define RT5665_PWR_HA_R				(0x1 << 4)
+#define RT5665_PWR_HA_R_BIT			4
+#define RT5665_HP_DRIVER_MASK			(0x3 << 2)
+#define RT5665_HP_DRIVER_1X			(0x0 << 2)
+#define RT5665_HP_DRIVER_3X			(0x1 << 2)
+#define RT5665_HP_DRIVER_5X			(0x3 << 2)
+#define RT5665_LDO1_DVO_MASK			(0x3)
+#define RT5665_LDO1_DVO_09			(0x0)
+#define RT5665_LDO1_DVO_10			(0x1)
+#define RT5665_LDO1_DVO_12			(0x2)
+#define RT5665_LDO1_DVO_14			(0x3)
+
+/* Power Management for Analog 2 (0x0064) */
+#define RT5665_PWR_BST1				(0x1 << 15)
+#define RT5665_PWR_BST1_BIT			15
+#define RT5665_PWR_BST2				(0x1 << 14)
+#define RT5665_PWR_BST2_BIT			14
+#define RT5665_PWR_BST3				(0x1 << 13)
+#define RT5665_PWR_BST3_BIT			13
+#define RT5665_PWR_BST4				(0x1 << 12)
+#define RT5665_PWR_BST4_BIT			12
+#define RT5665_PWR_MB1				(0x1 << 11)
+#define RT5665_PWR_MB1_PWR_DOWN			(0x0 << 11)
+#define RT5665_PWR_MB1_BIT			11
+#define RT5665_PWR_MB2				(0x1 << 10)
+#define RT5665_PWR_MB2_PWR_DOWN			(0x0 << 10)
+#define RT5665_PWR_MB2_BIT			10
+#define RT5665_PWR_MB3				(0x1 << 9)
+#define RT5665_PWR_MB3_BIT			9
+#define RT5665_PWR_BST1_P			(0x1 << 7)
+#define RT5665_PWR_BST1_P_BIT			7
+#define RT5665_PWR_BST2_P			(0x1 << 6)
+#define RT5665_PWR_BST2_P_BIT			6
+#define RT5665_PWR_BST3_P			(0x1 << 5)
+#define RT5665_PWR_BST3_P_BIT			5
+#define RT5665_PWR_BST4_P			(0x1 << 4)
+#define RT5665_PWR_BST4_P_BIT			4
+#define RT5665_PWR_JD1				(0x1 << 3)
+#define RT5665_PWR_JD1_BIT			3
+#define RT5665_PWR_JD2				(0x1 << 2)
+#define RT5665_PWR_JD2_BIT			2
+#define RT5665_PWR_RM1_L			(0x1 << 1)
+#define RT5665_PWR_RM1_L_BIT			1
+#define RT5665_PWR_RM1_R			(0x1)
+#define RT5665_PWR_RM1_R_BIT			0
+
+/* Power Management for Analog 3 (0x0065) */
+#define RT5665_PWR_CBJ				(0x1 << 9)
+#define RT5665_PWR_CBJ_BIT			9
+#define RT5665_PWR_BST_L			(0x1 << 8)
+#define RT5665_PWR_BST_L_BIT			8
+#define RT5665_PWR_BST_R			(0x1 << 7)
+#define RT5665_PWR_BST_R_BIT			7
+#define RT5665_PWR_PLL				(0x1 << 6)
+#define RT5665_PWR_PLL_BIT			6
+#define RT5665_PWR_LDO2				(0x1 << 2)
+#define RT5665_PWR_LDO2_BIT			2
+#define RT5665_PWR_SVD				(0x1 << 1)
+#define RT5665_PWR_SVD_BIT			1
+
+/* Power Management for Mixer (0x0066) */
+#define RT5665_PWR_RM2_L			(0x1 << 15)
+#define RT5665_PWR_RM2_L_BIT			15
+#define RT5665_PWR_RM2_R			(0x1 << 14)
+#define RT5665_PWR_RM2_R_BIT			14
+#define RT5665_PWR_OM_L				(0x1 << 13)
+#define RT5665_PWR_OM_L_BIT			13
+#define RT5665_PWR_OM_R				(0x1 << 12)
+#define RT5665_PWR_OM_R_BIT			12
+#define RT5665_PWR_MM				(0x1 << 11)
+#define RT5665_PWR_MM_BIT			11
+#define RT5665_PWR_AEC_REF			(0x1 << 6)
+#define RT5665_PWR_AEC_REF_BIT			6
+#define RT5665_PWR_STO1_DAC_L			(0x1 << 5)
+#define RT5665_PWR_STO1_DAC_L_BIT		5
+#define RT5665_PWR_STO1_DAC_R			(0x1 << 4)
+#define RT5665_PWR_STO1_DAC_R_BIT		4
+#define RT5665_PWR_MONO_DAC_L			(0x1 << 3)
+#define RT5665_PWR_MONO_DAC_L_BIT		3
+#define RT5665_PWR_MONO_DAC_R			(0x1 << 2)
+#define RT5665_PWR_MONO_DAC_R_BIT		2
+#define RT5665_PWR_STO2_DAC_L			(0x1 << 1)
+#define RT5665_PWR_STO2_DAC_L_BIT		1
+#define RT5665_PWR_STO2_DAC_R			(0x1)
+#define RT5665_PWR_STO2_DAC_R_BIT		0
+
+/* Power Management for Volume (0x0067) */
+#define RT5665_PWR_OV_L				(0x1 << 13)
+#define RT5665_PWR_OV_L_BIT			13
+#define RT5665_PWR_OV_R				(0x1 << 12)
+#define RT5665_PWR_OV_R_BIT			12
+#define RT5665_PWR_IN_L				(0x1 << 9)
+#define RT5665_PWR_IN_L_BIT			9
+#define RT5665_PWR_IN_R				(0x1 << 8)
+#define RT5665_PWR_IN_R_BIT			8
+#define RT5665_PWR_MV				(0x1 << 7)
+#define RT5665_PWR_MV_BIT			7
+#define RT5665_PWR_MIC_DET			(0x1 << 5)
+#define RT5665_PWR_MIC_DET_BIT			5
+
+/* (0x006b) */
+#define RT5665_SYS_CLK_DET			15
+#define RT5665_HP_CLK_DET			14
+#define RT5665_MONO_CLK_DET			13
+#define RT5665_LOUT_CLK_DET			12
+#define RT5665_POW_CLK_DET			0
+
+/* Digital Microphone Control 1 (0x006e) */
+#define RT5665_DMIC_1_EN_MASK			(0x1 << 15)
+#define RT5665_DMIC_1_EN_SFT			15
+#define RT5665_DMIC_1_DIS			(0x0 << 15)
+#define RT5665_DMIC_1_EN			(0x1 << 15)
+#define RT5665_DMIC_2_EN_MASK			(0x1 << 14)
+#define RT5665_DMIC_2_EN_SFT			14
+#define RT5665_DMIC_2_DIS			(0x0 << 14)
+#define RT5665_DMIC_2_EN			(0x1 << 14)
+#define RT5665_DMIC_2_DP_MASK			(0x1 << 9)
+#define RT5665_DMIC_2_DP_SFT			9
+#define RT5665_DMIC_2_DP_GPIO5			(0x0 << 9)
+#define RT5665_DMIC_2_DP_IN2P			(0x1 << 9)
+#define RT5665_DMIC_CLK_MASK			(0x7 << 5)
+#define RT5665_DMIC_CLK_SFT			5
+#define RT5665_DMIC_1_DP_MASK			(0x1 << 1)
+#define RT5665_DMIC_1_DP_SFT			1
+#define RT5665_DMIC_1_DP_GPIO4			(0x0 << 1)
+#define RT5665_DMIC_1_DP_IN2N			(0x1 << 1)
+
+
+/* Digital Microphone Control 1 (0x006f) */
+#define RT5665_DMIC_2L_LH_MASK			(0x1 << 3)
+#define RT5665_DMIC_2L_LH_SFT			3
+#define RT5665_DMIC_2L_LH_RISING		(0x0 << 3)
+#define RT5665_DMIC_2L_LH_FALLING		(0x1 << 3)
+#define RT5665_DMIC_2R_LH_MASK			(0x1 << 2)
+#define RT5665_DMIC_2R_LH_SFT			2
+#define RT5665_DMIC_2R_LH_RISING		(0x0 << 2)
+#define RT5665_DMIC_2R_LH_FALLING		(0x1 << 2)
+#define RT5665_DMIC_1L_LH_MASK			(0x1 << 1)
+#define RT5665_DMIC_1L_LH_SFT			1
+#define RT5665_DMIC_1L_LH_RISING		(0x0 << 1)
+#define RT5665_DMIC_1L_LH_FALLING		(0x1 << 1)
+#define RT5665_DMIC_1R_LH_MASK			(0x1 << 0)
+#define RT5665_DMIC_1R_LH_SFT			0
+#define RT5665_DMIC_1R_LH_RISING		(0x0)
+#define RT5665_DMIC_1R_LH_FALLING		(0x1)
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x0070 0x0071 0x0072) */
+#define RT5665_I2S_MS_MASK			(0x1 << 15)
+#define RT5665_I2S_MS_SFT			15
+#define RT5665_I2S_MS_M				(0x0 << 15)
+#define RT5665_I2S_MS_S				(0x1 << 15)
+#define RT5665_I2S_PIN_CFG_MASK			(0x1 << 14)
+#define RT5665_I2S_PIN_CFG_SFT			14
+#define RT5665_I2S_CLK_SEL_MASK			(0x1 << 11)
+#define RT5665_I2S_CLK_SEL_SFT			11
+#define RT5665_I2S_BP_MASK			(0x1 << 8)
+#define RT5665_I2S_BP_SFT			8
+#define RT5665_I2S_BP_NOR			(0x0 << 8)
+#define RT5665_I2S_BP_INV			(0x1 << 8)
+#define RT5665_I2S_DL_MASK			(0x3 << 4)
+#define RT5665_I2S_DL_SFT			4
+#define RT5665_I2S_DL_16			(0x0 << 4)
+#define RT5665_I2S_DL_20			(0x1 << 4)
+#define RT5665_I2S_DL_24			(0x2 << 4)
+#define RT5665_I2S_DL_8				(0x3 << 4)
+#define RT5665_I2S_DF_MASK			(0x7)
+#define RT5665_I2S_DF_SFT			0
+#define RT5665_I2S_DF_I2S			(0x0)
+#define RT5665_I2S_DF_LEFT			(0x1)
+#define RT5665_I2S_DF_PCM_A			(0x2)
+#define RT5665_I2S_DF_PCM_B			(0x3)
+#define RT5665_I2S_DF_PCM_A_N			(0x6)
+#define RT5665_I2S_DF_PCM_B_N			(0x7)
+
+/* ADC/DAC Clock Control 1 (0x0073) */
+#define RT5665_I2S_PD1_MASK			(0x7 << 12)
+#define RT5665_I2S_PD1_SFT			12
+#define RT5665_I2S_PD1_1			(0x0 << 12)
+#define RT5665_I2S_PD1_2			(0x1 << 12)
+#define RT5665_I2S_PD1_3			(0x2 << 12)
+#define RT5665_I2S_PD1_4			(0x3 << 12)
+#define RT5665_I2S_PD1_6			(0x4 << 12)
+#define RT5665_I2S_PD1_8			(0x5 << 12)
+#define RT5665_I2S_PD1_12			(0x6 << 12)
+#define RT5665_I2S_PD1_16			(0x7 << 12)
+#define RT5665_I2S_M_PD2_MASK			(0x7 << 8)
+#define RT5665_I2S_M_PD2_SFT			8
+#define RT5665_I2S_M_PD2_1			(0x0 << 8)
+#define RT5665_I2S_M_PD2_2			(0x1 << 8)
+#define RT5665_I2S_M_PD2_3			(0x2 << 8)
+#define RT5665_I2S_M_PD2_4			(0x3 << 8)
+#define RT5665_I2S_M_PD2_6			(0x4 << 8)
+#define RT5665_I2S_M_PD2_8			(0x5 << 8)
+#define RT5665_I2S_M_PD2_12			(0x6 << 8)
+#define RT5665_I2S_M_PD2_16			(0x7 << 8)
+#define RT5665_I2S_CLK_SRC_MASK			(0x3 << 4)
+#define RT5665_I2S_CLK_SRC_SFT			4
+#define RT5665_I2S_CLK_SRC_MCLK			(0x0 << 4)
+#define RT5665_I2S_CLK_SRC_PLL1			(0x1 << 4)
+#define RT5665_I2S_CLK_SRC_RCCLK		(0x2 << 4)
+#define RT5665_DAC_OSR_MASK			(0x3 << 2)
+#define RT5665_DAC_OSR_SFT			2
+#define RT5665_DAC_OSR_128			(0x0 << 2)
+#define RT5665_DAC_OSR_64			(0x1 << 2)
+#define RT5665_DAC_OSR_32			(0x2 << 2)
+#define RT5665_ADC_OSR_MASK			(0x3)
+#define RT5665_ADC_OSR_SFT			0
+#define RT5665_ADC_OSR_128			(0x0)
+#define RT5665_ADC_OSR_64			(0x1)
+#define RT5665_ADC_OSR_32			(0x2)
+
+/* ADC/DAC Clock Control 2 (0x0074) */
+#define RT5665_I2S_BCLK_MS2_MASK		(0x1 << 15)
+#define RT5665_I2S_BCLK_MS2_SFT			15
+#define RT5665_I2S_BCLK_MS2_32			(0x0 << 15)
+#define RT5665_I2S_BCLK_MS2_64			(0x1 << 15)
+#define RT5665_I2S_PD2_MASK			(0x7 << 12)
+#define RT5665_I2S_PD2_SFT			12
+#define RT5665_I2S_PD2_1			(0x0 << 12)
+#define RT5665_I2S_PD2_2			(0x1 << 12)
+#define RT5665_I2S_PD2_3			(0x2 << 12)
+#define RT5665_I2S_PD2_4			(0x3 << 12)
+#define RT5665_I2S_PD2_6			(0x4 << 12)
+#define RT5665_I2S_PD2_8			(0x5 << 12)
+#define RT5665_I2S_PD2_12			(0x6 << 12)
+#define RT5665_I2S_PD2_16			(0x7 << 12)
+#define RT5665_I2S_BCLK_MS3_MASK		(0x1 << 11)
+#define RT5665_I2S_BCLK_MS3_SFT			11
+#define RT5665_I2S_BCLK_MS3_32			(0x0 << 11)
+#define RT5665_I2S_BCLK_MS3_64			(0x1 << 11)
+#define RT5665_I2S_PD3_MASK			(0x7 << 8)
+#define RT5665_I2S_PD3_SFT			8
+#define RT5665_I2S_PD3_1			(0x0 << 8)
+#define RT5665_I2S_PD3_2			(0x1 << 8)
+#define RT5665_I2S_PD3_3			(0x2 << 8)
+#define RT5665_I2S_PD3_4			(0x3 << 8)
+#define RT5665_I2S_PD3_6			(0x4 << 8)
+#define RT5665_I2S_PD3_8			(0x5 << 8)
+#define RT5665_I2S_PD3_12			(0x6 << 8)
+#define RT5665_I2S_PD3_16			(0x7 << 8)
+#define RT5665_I2S_PD4_MASK			(0x7 << 4)
+#define RT5665_I2S_PD4_SFT			4
+#define RT5665_I2S_PD4_1			(0x0 << 4)
+#define RT5665_I2S_PD4_2			(0x1 << 4)
+#define RT5665_I2S_PD4_3			(0x2 << 4)
+#define RT5665_I2S_PD4_4			(0x3 << 4)
+#define RT5665_I2S_PD4_6			(0x4 << 4)
+#define RT5665_I2S_PD4_8			(0x5 << 4)
+#define RT5665_I2S_PD4_12			(0x6 << 4)
+#define RT5665_I2S_PD4_16			(0x7 << 4)
+
+/* TDM control 1 (0x0078) */
+#define RT5665_I2S1_MODE_MASK			(0x1 << 15)
+#define RT5665_I2S1_MODE_I2S			(0x0 << 15)
+#define RT5665_I2S1_MODE_TDM			(0x1 << 15)
+#define RT5665_TDM_IN_CH_MASK			(0x3 << 10)
+#define RT5665_TDM_IN_CH_2			(0x0 << 10)
+#define RT5665_TDM_IN_CH_4			(0x1 << 10)
+#define RT5665_TDM_IN_CH_6			(0x2 << 10)
+#define RT5665_TDM_IN_CH_8			(0x3 << 10)
+#define RT5665_TDM_OUT_CH_MASK			(0x3 << 8)
+#define RT5665_TDM_OUT_CH_2			(0x0 << 8)
+#define RT5665_TDM_OUT_CH_4			(0x1 << 8)
+#define RT5665_TDM_OUT_CH_6			(0x2 << 8)
+#define RT5665_TDM_OUT_CH_8			(0x3 << 8)
+#define RT5665_TDM_IN_LEN_MASK			(0x3 << 6)
+#define RT5665_TDM_IN_LEN_16			(0x0 << 6)
+#define RT5665_TDM_IN_LEN_20			(0x1 << 6)
+#define RT5665_TDM_IN_LEN_24			(0x2 << 6)
+#define RT5665_TDM_IN_LEN_32			(0x3 << 6)
+#define RT5665_TDM_OUT_LEN_MASK			(0x3 << 4)
+#define RT5665_TDM_OUT_LEN_16			(0x0 << 4)
+#define RT5665_TDM_OUT_LEN_20			(0x1 << 4)
+#define RT5665_TDM_OUT_LEN_24			(0x2 << 4)
+#define RT5665_TDM_OUT_LEN_32			(0x3 << 4)
+
+
+/* TDM control 2 (0x0079) */
+#define RT5665_I2S1_1_DS_ADC_SLOT01_SFT		14
+#define RT5665_I2S1_1_DS_ADC_SLOT23_SFT		12
+#define RT5665_I2S1_1_DS_ADC_SLOT45_SFT		10
+#define RT5665_I2S1_1_DS_ADC_SLOT67_SFT		8
+#define RT5665_I2S1_2_DS_ADC_SLOT01_SFT		6
+#define RT5665_I2S1_2_DS_ADC_SLOT23_SFT		4
+#define RT5665_I2S1_2_DS_ADC_SLOT45_SFT		2
+#define RT5665_I2S1_2_DS_ADC_SLOT67_SFT		0
+
+/* TDM control 3/4 (0x007a) (0x007b) */
+#define RT5665_IF1_ADC1_SEL_SFT			10
+#define RT5665_IF1_ADC2_SEL_SFT			9
+#define RT5665_IF1_ADC3_SEL_SFT			8
+#define RT5665_IF1_ADC4_SEL_SFT			7
+#define RT5665_TDM_ADC_SEL_SFT			0
+#define RT5665_TDM_ADC_CTRL_MASK		(0x1f << 0)
+#define RT5665_TDM_ADC_DATA_06			(0x6 << 0)
+
+/* Global Clock Control (0x0080) */
+#define RT5665_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5665_SCLK_SRC_SFT			14
+#define RT5665_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5665_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5665_SCLK_SRC_RCCLK			(0x2 << 14)
+#define RT5665_PLL1_SRC_MASK			(0x7 << 8)
+#define RT5665_PLL1_SRC_SFT			8
+#define RT5665_PLL1_SRC_MCLK			(0x0 << 8)
+#define RT5665_PLL1_SRC_BCLK1			(0x1 << 8)
+#define RT5665_PLL1_SRC_BCLK2			(0x2 << 8)
+#define RT5665_PLL1_SRC_BCLK3			(0x3 << 8)
+#define RT5665_PLL1_PD_MASK			(0x7 << 4)
+#define RT5665_PLL1_PD_SFT			4
+
+
+#define RT5665_PLL_INP_MAX			40000000
+#define RT5665_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x0081) */
+#define RT5665_PLL_N_MAX			0x001ff
+#define RT5665_PLL_N_MASK			(RT5665_PLL_N_MAX << 7)
+#define RT5665_PLL_N_SFT			7
+#define RT5665_PLL_K_MAX			0x001f
+#define RT5665_PLL_K_MASK			(RT5665_PLL_K_MAX)
+#define RT5665_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x0082) */
+#define RT5665_PLL_M_MAX			0x00f
+#define RT5665_PLL_M_MASK			(RT5665_PLL_M_MAX << 12)
+#define RT5665_PLL_M_SFT			12
+#define RT5665_PLL_M_BP				(0x1 << 11)
+#define RT5665_PLL_M_BP_SFT			11
+#define RT5665_PLL_K_BP				(0x1 << 10)
+#define RT5665_PLL_K_BP_SFT			10
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5665_I2S3_ASRC_MASK			(0x1 << 15)
+#define RT5665_I2S3_ASRC_SFT			15
+#define RT5665_I2S2_ASRC_MASK			(0x1 << 14)
+#define RT5665_I2S2_ASRC_SFT			14
+#define RT5665_I2S1_ASRC_MASK			(0x1 << 13)
+#define RT5665_I2S1_ASRC_SFT			13
+#define RT5665_DAC_STO1_ASRC_MASK		(0x1 << 12)
+#define RT5665_DAC_STO1_ASRC_SFT		12
+#define RT5665_DAC_STO2_ASRC_MASK		(0x1 << 11)
+#define RT5665_DAC_STO2_ASRC_SFT		11
+#define RT5665_DAC_MONO_L_ASRC_MASK		(0x1 << 10)
+#define RT5665_DAC_MONO_L_ASRC_SFT		10
+#define RT5665_DAC_MONO_R_ASRC_MASK		(0x1 << 9)
+#define RT5665_DAC_MONO_R_ASRC_SFT		9
+#define RT5665_DMIC_STO1_ASRC_MASK		(0x1 << 8)
+#define RT5665_DMIC_STO1_ASRC_SFT		8
+#define RT5665_DMIC_STO2_ASRC_MASK		(0x1 << 7)
+#define RT5665_DMIC_STO2_ASRC_SFT		7
+#define RT5665_DMIC_MONO_L_ASRC_MASK		(0x1 << 6)
+#define RT5665_DMIC_MONO_L_ASRC_SFT		6
+#define RT5665_DMIC_MONO_R_ASRC_MASK		(0x1 << 5)
+#define RT5665_DMIC_MONO_R_ASRC_SFT		5
+#define RT5665_ADC_STO1_ASRC_MASK		(0x1 << 4)
+#define RT5665_ADC_STO1_ASRC_SFT		4
+#define RT5665_ADC_STO2_ASRC_MASK		(0x1 << 3)
+#define RT5665_ADC_STO2_ASRC_SFT		3
+#define RT5665_ADC_MONO_L_ASRC_MASK		(0x1 << 2)
+#define RT5665_ADC_MONO_L_ASRC_SFT		2
+#define RT5665_ADC_MONO_R_ASRC_MASK		(0x1 << 1)
+#define RT5665_ADC_MONO_R_ASRC_SFT		1
+
+/* PLL tracking mode 2 (0x0084)*/
+#define RT5665_DA_STO1_CLK_SEL_MASK		(0x7 << 12)
+#define RT5665_DA_STO1_CLK_SEL_SFT		12
+#define RT5665_DA_STO2_CLK_SEL_MASK		(0x7 << 8)
+#define RT5665_DA_STO2_CLK_SEL_SFT		8
+#define RT5665_DA_MONOL_CLK_SEL_MASK		(0x7 << 4)
+#define RT5665_DA_MONOL_CLK_SEL_SFT		4
+#define RT5665_DA_MONOR_CLK_SEL_MASK		(0x7)
+#define RT5665_DA_MONOR_CLK_SEL_SFT		0
+
+/* PLL tracking mode 3 (0x0085)*/
+#define RT5665_AD_STO1_CLK_SEL_MASK		(0x7 << 12)
+#define RT5665_AD_STO1_CLK_SEL_SFT		12
+#define RT5665_AD_STO2_CLK_SEL_MASK		(0x7 << 8)
+#define RT5665_AD_STO2_CLK_SEL_SFT		8
+#define RT5665_AD_MONOL_CLK_SEL_MASK		(0x7 << 4)
+#define RT5665_AD_MONOL_CLK_SEL_SFT		4
+#define RT5665_AD_MONOR_CLK_SEL_MASK		(0x7)
+#define RT5665_AD_MONOR_CLK_SEL_SFT		0
+
+/* ASRC Control 4 (0x0086) */
+#define RT5665_I2S1_RATE_MASK			(0xf << 12)
+#define RT5665_I2S1_RATE_SFT			12
+#define RT5665_I2S2_RATE_MASK			(0xf << 8)
+#define RT5665_I2S2_RATE_SFT			8
+#define RT5665_I2S3_RATE_MASK			(0xf << 4)
+#define RT5665_I2S3_RATE_SFT			4
+
+/* Depop Mode Control 1 (0x008e) */
+#define RT5665_PUMP_EN				(0x1 << 3)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5665_DEPOP_MASK			(0x1 << 13)
+#define RT5665_DEPOP_SFT			13
+#define RT5665_DEPOP_AUTO			(0x0 << 13)
+#define RT5665_DEPOP_MAN			(0x1 << 13)
+#define RT5665_RAMP_MASK			(0x1 << 12)
+#define RT5665_RAMP_SFT				12
+#define RT5665_RAMP_DIS				(0x0 << 12)
+#define RT5665_RAMP_EN				(0x1 << 12)
+#define RT5665_BPS_MASK				(0x1 << 11)
+#define RT5665_BPS_SFT				11
+#define RT5665_BPS_DIS				(0x0 << 11)
+#define RT5665_BPS_EN				(0x1 << 11)
+#define RT5665_FAST_UPDN_MASK			(0x1 << 10)
+#define RT5665_FAST_UPDN_SFT			10
+#define RT5665_FAST_UPDN_DIS			(0x0 << 10)
+#define RT5665_FAST_UPDN_EN			(0x1 << 10)
+#define RT5665_MRES_MASK			(0x3 << 8)
+#define RT5665_MRES_SFT				8
+#define RT5665_MRES_15MO			(0x0 << 8)
+#define RT5665_MRES_25MO			(0x1 << 8)
+#define RT5665_MRES_35MO			(0x2 << 8)
+#define RT5665_MRES_45MO			(0x3 << 8)
+#define RT5665_VLO_MASK				(0x1 << 7)
+#define RT5665_VLO_SFT				7
+#define RT5665_VLO_3V				(0x0 << 7)
+#define RT5665_VLO_32V				(0x1 << 7)
+#define RT5665_DIG_DP_MASK			(0x1 << 6)
+#define RT5665_DIG_DP_SFT			6
+#define RT5665_DIG_DP_DIS			(0x0 << 6)
+#define RT5665_DIG_DP_EN			(0x1 << 6)
+#define RT5665_DP_TH_MASK			(0x3 << 4)
+#define RT5665_DP_TH_SFT			4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5665_CP_SYS_MASK			(0x7 << 12)
+#define RT5665_CP_SYS_SFT			12
+#define RT5665_CP_FQ1_MASK			(0x7 << 8)
+#define RT5665_CP_FQ1_SFT			8
+#define RT5665_CP_FQ2_MASK			(0x7 << 4)
+#define RT5665_CP_FQ2_SFT			4
+#define RT5665_CP_FQ3_MASK			(0x7)
+#define RT5665_CP_FQ3_SFT			0
+#define RT5665_CP_FQ_1_5_KHZ			0
+#define RT5665_CP_FQ_3_KHZ			1
+#define RT5665_CP_FQ_6_KHZ			2
+#define RT5665_CP_FQ_12_KHZ			3
+#define RT5665_CP_FQ_24_KHZ			4
+#define RT5665_CP_FQ_48_KHZ			5
+#define RT5665_CP_FQ_96_KHZ			6
+#define RT5665_CP_FQ_192_KHZ			7
+
+/* HPOUT charge pump 1 (0x0091) */
+#define RT5665_OSW_L_MASK			(0x1 << 11)
+#define RT5665_OSW_L_SFT			11
+#define RT5665_OSW_L_DIS			(0x0 << 11)
+#define RT5665_OSW_L_EN				(0x1 << 11)
+#define RT5665_OSW_R_MASK			(0x1 << 10)
+#define RT5665_OSW_R_SFT			10
+#define RT5665_OSW_R_DIS			(0x0 << 10)
+#define RT5665_OSW_R_EN				(0x1 << 10)
+#define RT5665_PM_HP_MASK			(0x3 << 8)
+#define RT5665_PM_HP_SFT			8
+#define RT5665_PM_HP_LV				(0x0 << 8)
+#define RT5665_PM_HP_MV				(0x1 << 8)
+#define RT5665_PM_HP_HV				(0x2 << 8)
+#define RT5665_IB_HP_MASK			(0x3 << 6)
+#define RT5665_IB_HP_SFT			6
+#define RT5665_IB_HP_125IL			(0x0 << 6)
+#define RT5665_IB_HP_25IL			(0x1 << 6)
+#define RT5665_IB_HP_5IL			(0x2 << 6)
+#define RT5665_IB_HP_1IL			(0x3 << 6)
+
+/* PV detection and SPK gain control (0x92) */
+#define RT5665_PVDD_DET_MASK			(0x1 << 15)
+#define RT5665_PVDD_DET_SFT			15
+#define RT5665_PVDD_DET_DIS			(0x0 << 15)
+#define RT5665_PVDD_DET_EN			(0x1 << 15)
+#define RT5665_SPK_AG_MASK			(0x1 << 14)
+#define RT5665_SPK_AG_SFT			14
+#define RT5665_SPK_AG_DIS			(0x0 << 14)
+#define RT5665_SPK_AG_EN			(0x1 << 14)
+
+/* Micbias Control1 (0x93) */
+#define RT5665_MIC1_BS_MASK			(0x1 << 15)
+#define RT5665_MIC1_BS_SFT			15
+#define RT5665_MIC1_BS_9AV			(0x0 << 15)
+#define RT5665_MIC1_BS_75AV			(0x1 << 15)
+#define RT5665_MIC2_BS_MASK			(0x1 << 14)
+#define RT5665_MIC2_BS_SFT			14
+#define RT5665_MIC2_BS_9AV			(0x0 << 14)
+#define RT5665_MIC2_BS_75AV			(0x1 << 14)
+#define RT5665_MIC1_CLK_MASK			(0x1 << 13)
+#define RT5665_MIC1_CLK_SFT			13
+#define RT5665_MIC1_CLK_DIS			(0x0 << 13)
+#define RT5665_MIC1_CLK_EN			(0x1 << 13)
+#define RT5665_MIC2_CLK_MASK			(0x1 << 12)
+#define RT5665_MIC2_CLK_SFT			12
+#define RT5665_MIC2_CLK_DIS			(0x0 << 12)
+#define RT5665_MIC2_CLK_EN			(0x1 << 12)
+#define RT5665_MIC1_OVCD_MASK			(0x1 << 11)
+#define RT5665_MIC1_OVCD_SFT			11
+#define RT5665_MIC1_OVCD_DIS			(0x0 << 11)
+#define RT5665_MIC1_OVCD_EN			(0x1 << 11)
+#define RT5665_MIC1_OVTH_MASK			(0x3 << 9)
+#define RT5665_MIC1_OVTH_SFT			9
+#define RT5665_MIC1_OVTH_600UA			(0x0 << 9)
+#define RT5665_MIC1_OVTH_1500UA			(0x1 << 9)
+#define RT5665_MIC1_OVTH_2000UA			(0x2 << 9)
+#define RT5665_MIC2_OVCD_MASK			(0x1 << 8)
+#define RT5665_MIC2_OVCD_SFT			8
+#define RT5665_MIC2_OVCD_DIS			(0x0 << 8)
+#define RT5665_MIC2_OVCD_EN			(0x1 << 8)
+#define RT5665_MIC2_OVTH_MASK			(0x3 << 6)
+#define RT5665_MIC2_OVTH_SFT			6
+#define RT5665_MIC2_OVTH_600UA			(0x0 << 6)
+#define RT5665_MIC2_OVTH_1500UA			(0x1 << 6)
+#define RT5665_MIC2_OVTH_2000UA			(0x2 << 6)
+#define RT5665_PWR_MB_MASK			(0x1 << 5)
+#define RT5665_PWR_MB_SFT			5
+#define RT5665_PWR_MB_PD			(0x0 << 5)
+#define RT5665_PWR_MB_PU			(0x1 << 5)
+
+/* Micbias Control2 (0x94) */
+#define RT5665_PWR_CLK25M_MASK			(0x1 << 9)
+#define RT5665_PWR_CLK25M_SFT			9
+#define RT5665_PWR_CLK25M_PD			(0x0 << 9)
+#define RT5665_PWR_CLK25M_PU			(0x1 << 9)
+#define RT5665_PWR_CLK1M_MASK			(0x1 << 8)
+#define RT5665_PWR_CLK1M_SFT			8
+#define RT5665_PWR_CLK1M_PD			(0x0 << 8)
+#define RT5665_PWR_CLK1M_PU			(0x1 << 8)
+
+/* I2S Master Mode Clock Control 1 (0x00a0) */
+#define RT5665_CLK_SRC_MCLK			(0x0)
+#define RT5665_CLK_SRC_PLL1			(0x1)
+#define RT5665_CLK_SRC_RCCLK			(0x2)
+#define RT5665_I2S_PD_1				(0x0)
+#define RT5665_I2S_PD_2				(0x1)
+#define RT5665_I2S_PD_3				(0x2)
+#define RT5665_I2S_PD_4				(0x3)
+#define RT5665_I2S_PD_6				(0x4)
+#define RT5665_I2S_PD_8				(0x5)
+#define RT5665_I2S_PD_12			(0x6)
+#define RT5665_I2S_PD_16			(0x7)
+#define RT5665_I2S2_SRC_MASK			(0x3 << 12)
+#define RT5665_I2S2_SRC_SFT			12
+#define RT5665_I2S2_M_PD_MASK			(0x7 << 8)
+#define RT5665_I2S2_M_PD_SFT			8
+#define RT5665_I2S3_SRC_MASK			(0x3 << 4)
+#define RT5665_I2S3_SRC_SFT			4
+#define RT5665_I2S3_M_PD_MASK			(0x7 << 0)
+#define RT5665_I2S3_M_PD_SFT			0
+
+
+/* EQ Control 1 (0x00b0) */
+#define RT5665_EQ_SRC_DAC			(0x0 << 15)
+#define RT5665_EQ_SRC_ADC			(0x1 << 15)
+#define RT5665_EQ_UPD				(0x1 << 14)
+#define RT5665_EQ_UPD_BIT			14
+#define RT5665_EQ_CD_MASK			(0x1 << 13)
+#define RT5665_EQ_CD_SFT			13
+#define RT5665_EQ_CD_DIS			(0x0 << 13)
+#define RT5665_EQ_CD_EN				(0x1 << 13)
+#define RT5665_EQ_DITH_MASK			(0x3 << 8)
+#define RT5665_EQ_DITH_SFT			8
+#define RT5665_EQ_DITH_NOR			(0x0 << 8)
+#define RT5665_EQ_DITH_LSB			(0x1 << 8)
+#define RT5665_EQ_DITH_LSB_1			(0x2 << 8)
+#define RT5665_EQ_DITH_LSB_2			(0x3 << 8)
+
+/* IRQ Control 1 (0x00b7) */
+#define RT5665_JD1_1_EN_MASK			(0x1 << 15)
+#define RT5665_JD1_1_EN_SFT			15
+#define RT5665_JD1_1_DIS			(0x0 << 15)
+#define RT5665_JD1_1_EN				(0x1 << 15)
+#define RT5665_JD1_2_EN_MASK			(0x1 << 12)
+#define RT5665_JD1_2_EN_SFT			12
+#define RT5665_JD1_2_DIS			(0x0 << 12)
+#define RT5665_JD1_2_EN				(0x1 << 12)
+
+/* IRQ Control 2 (0x00b8) */
+#define RT5665_IL_IRQ_MASK			(0x1 << 6)
+#define RT5665_IL_IRQ_DIS			(0x0 << 6)
+#define RT5665_IL_IRQ_EN			(0x1 << 6)
+
+/* IRQ Control 5 (0x00ba) */
+#define RT5665_IRQ_JD_EN			(0x1 << 3)
+#define RT5665_IRQ_JD_EN_SFT			3
+
+/* GPIO Control 1 (0x00c0) */
+#define RT5665_GP1_PIN_MASK			(0x1 << 15)
+#define RT5665_GP1_PIN_SFT			15
+#define RT5665_GP1_PIN_GPIO1			(0x0 << 15)
+#define RT5665_GP1_PIN_IRQ			(0x1 << 15)
+#define RT5665_GP2_PIN_MASK			(0x3 << 13)
+#define RT5665_GP2_PIN_SFT			13
+#define RT5665_GP2_PIN_GPIO2			(0x0 << 13)
+#define RT5665_GP2_PIN_BCLK2			(0x1 << 13)
+#define RT5665_GP2_PIN_PDM_SCL			(0x2 << 13)
+#define RT5665_GP3_PIN_MASK			(0x3 << 11)
+#define RT5665_GP3_PIN_SFT			11
+#define RT5665_GP3_PIN_GPIO3			(0x0 << 11)
+#define RT5665_GP3_PIN_LRCK2			(0x1 << 11)
+#define RT5665_GP3_PIN_PDM_SDA			(0x2 << 11)
+#define RT5665_GP4_PIN_MASK			(0x3 << 9)
+#define RT5665_GP4_PIN_SFT			9
+#define RT5665_GP4_PIN_GPIO4			(0x0 << 9)
+#define RT5665_GP4_PIN_DACDAT2_1		(0x1 << 9)
+#define RT5665_GP4_PIN_DMIC1_SDA		(0x2 << 9)
+#define RT5665_GP5_PIN_MASK			(0x3 << 7)
+#define RT5665_GP5_PIN_SFT			7
+#define RT5665_GP5_PIN_GPIO5			(0x0 << 7)
+#define RT5665_GP5_PIN_ADCDAT2_1		(0x1 << 7)
+#define RT5665_GP5_PIN_DMIC2_SDA		(0x2 << 7)
+#define RT5665_GP6_PIN_MASK			(0x3 << 5)
+#define RT5665_GP6_PIN_SFT			5
+#define RT5665_GP6_PIN_GPIO6			(0x0 << 5)
+#define RT5665_GP6_PIN_BCLK3			(0x1 << 5)
+#define RT5665_GP6_PIN_PDM_SCL			(0x2 << 5)
+#define RT5665_GP7_PIN_MASK			(0x3 << 3)
+#define RT5665_GP7_PIN_SFT			3
+#define RT5665_GP7_PIN_GPIO7			(0x0 << 3)
+#define RT5665_GP7_PIN_LRCK3			(0x1 << 3)
+#define RT5665_GP7_PIN_PDM_SDA			(0x2 << 3)
+#define RT5665_GP8_PIN_MASK			(0x3 << 1)
+#define RT5665_GP8_PIN_SFT			1
+#define RT5665_GP8_PIN_GPIO8			(0x0 << 1)
+#define RT5665_GP8_PIN_DACDAT3			(0x1 << 1)
+#define RT5665_GP8_PIN_DMIC2_SCL		(0x2 << 1)
+#define RT5665_GP8_PIN_DACDAT2_2		(0x3 << 1)
+
+
+/* GPIO Control 2 (0x00c1)*/
+#define RT5665_GP9_PIN_MASK			(0x3 << 14)
+#define RT5665_GP9_PIN_SFT			14
+#define RT5665_GP9_PIN_GPIO9			(0x0 << 14)
+#define RT5665_GP9_PIN_ADCDAT3			(0x1 << 14)
+#define RT5665_GP9_PIN_DMIC1_SCL		(0x2 << 14)
+#define RT5665_GP9_PIN_ADCDAT2_2		(0x3 << 14)
+#define RT5665_GP10_PIN_MASK			(0x3 << 12)
+#define RT5665_GP10_PIN_SFT			12
+#define RT5665_GP10_PIN_GPIO10			(0x0 << 12)
+#define RT5665_GP10_PIN_ADCDAT1_2		(0x1 << 12)
+#define RT5665_GP10_PIN_LPD			(0x2 << 12)
+#define RT5665_GP1_PF_MASK			(0x1 << 11)
+#define RT5665_GP1_PF_IN			(0x0 << 11)
+#define RT5665_GP1_PF_OUT			(0x1 << 11)
+#define RT5665_GP1_OUT_MASK			(0x1 << 10)
+#define RT5665_GP1_OUT_H			(0x0 << 10)
+#define RT5665_GP1_OUT_L			(0x1 << 10)
+#define RT5665_GP2_PF_MASK			(0x1 << 9)
+#define RT5665_GP2_PF_IN			(0x0 << 9)
+#define RT5665_GP2_PF_OUT			(0x1 << 9)
+#define RT5665_GP2_OUT_MASK			(0x1 << 8)
+#define RT5665_GP2_OUT_H			(0x0 << 8)
+#define RT5665_GP2_OUT_L			(0x1 << 8)
+#define RT5665_GP3_PF_MASK			(0x1 << 7)
+#define RT5665_GP3_PF_IN			(0x0 << 7)
+#define RT5665_GP3_PF_OUT			(0x1 << 7)
+#define RT5665_GP3_OUT_MASK			(0x1 << 6)
+#define RT5665_GP3_OUT_H			(0x0 << 6)
+#define RT5665_GP3_OUT_L			(0x1 << 6)
+#define RT5665_GP4_PF_MASK			(0x1 << 5)
+#define RT5665_GP4_PF_IN			(0x0 << 5)
+#define RT5665_GP4_PF_OUT			(0x1 << 5)
+#define RT5665_GP4_OUT_MASK			(0x1 << 4)
+#define RT5665_GP4_OUT_H			(0x0 << 4)
+#define RT5665_GP4_OUT_L			(0x1 << 4)
+#define RT5665_GP5_PF_MASK			(0x1 << 3)
+#define RT5665_GP5_PF_IN			(0x0 << 3)
+#define RT5665_GP5_PF_OUT			(0x1 << 3)
+#define RT5665_GP5_OUT_MASK			(0x1 << 2)
+#define RT5665_GP5_OUT_H			(0x0 << 2)
+#define RT5665_GP5_OUT_L			(0x1 << 2)
+#define RT5665_GP6_PF_MASK			(0x1 << 1)
+#define RT5665_GP6_PF_IN			(0x0 << 1)
+#define RT5665_GP6_PF_OUT			(0x1 << 1)
+#define RT5665_GP6_OUT_MASK			(0x1)
+#define RT5665_GP6_OUT_H			(0x0)
+#define RT5665_GP6_OUT_L			(0x1)
+
+
+/* GPIO Control 3 (0x00c2) */
+#define RT5665_GP7_PF_MASK			(0x1 << 15)
+#define RT5665_GP7_PF_IN			(0x0 << 15)
+#define RT5665_GP7_PF_OUT			(0x1 << 15)
+#define RT5665_GP7_OUT_MASK			(0x1 << 14)
+#define RT5665_GP7_OUT_H			(0x0 << 14)
+#define RT5665_GP7_OUT_L			(0x1 << 14)
+#define RT5665_GP8_PF_MASK			(0x1 << 13)
+#define RT5665_GP8_PF_IN			(0x0 << 13)
+#define RT5665_GP8_PF_OUT			(0x1 << 13)
+#define RT5665_GP8_OUT_MASK			(0x1 << 12)
+#define RT5665_GP8_OUT_H			(0x0 << 12)
+#define RT5665_GP8_OUT_L			(0x1 << 12)
+#define RT5665_GP9_PF_MASK			(0x1 << 11)
+#define RT5665_GP9_PF_IN			(0x0 << 11)
+#define RT5665_GP9_PF_OUT			(0x1 << 11)
+#define RT5665_GP9_OUT_MASK			(0x1 << 10)
+#define RT5665_GP9_OUT_H			(0x0 << 10)
+#define RT5665_GP9_OUT_L			(0x1 << 10)
+#define RT5665_GP10_PF_MASK			(0x1 << 9)
+#define RT5665_GP10_PF_IN			(0x0 << 9)
+#define RT5665_GP10_PF_OUT			(0x1 << 9)
+#define RT5665_GP10_OUT_MASK			(0x1 << 8)
+#define RT5665_GP10_OUT_H			(0x0 << 8)
+#define RT5665_GP10_OUT_L			(0x1 << 8)
+#define RT5665_GP11_PF_MASK			(0x1 << 7)
+#define RT5665_GP11_PF_IN			(0x0 << 7)
+#define RT5665_GP11_PF_OUT			(0x1 << 7)
+#define RT5665_GP11_OUT_MASK			(0x1 << 6)
+#define RT5665_GP11_OUT_H			(0x0 << 6)
+#define RT5665_GP11_OUT_L			(0x1 << 6)
+
+/* Soft volume and zero cross control 1 (0x00d9) */
+#define RT5665_SV_MASK				(0x1 << 15)
+#define RT5665_SV_SFT				15
+#define RT5665_SV_DIS				(0x0 << 15)
+#define RT5665_SV_EN				(0x1 << 15)
+#define RT5665_OUT_SV_MASK			(0x1 << 13)
+#define RT5665_OUT_SV_SFT			13
+#define RT5665_OUT_SV_DIS			(0x0 << 13)
+#define RT5665_OUT_SV_EN			(0x1 << 13)
+#define RT5665_HP_SV_MASK			(0x1 << 12)
+#define RT5665_HP_SV_SFT			12
+#define RT5665_HP_SV_DIS			(0x0 << 12)
+#define RT5665_HP_SV_EN				(0x1 << 12)
+#define RT5665_ZCD_DIG_MASK			(0x1 << 11)
+#define RT5665_ZCD_DIG_SFT			11
+#define RT5665_ZCD_DIG_DIS			(0x0 << 11)
+#define RT5665_ZCD_DIG_EN			(0x1 << 11)
+#define RT5665_ZCD_MASK				(0x1 << 10)
+#define RT5665_ZCD_SFT				10
+#define RT5665_ZCD_PD				(0x0 << 10)
+#define RT5665_ZCD_PU				(0x1 << 10)
+#define RT5665_SV_DLY_MASK			(0xf)
+#define RT5665_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0x00da) */
+#define RT5665_ZCD_HP_MASK			(0x1 << 15)
+#define RT5665_ZCD_HP_SFT			15
+#define RT5665_ZCD_HP_DIS			(0x0 << 15)
+#define RT5665_ZCD_HP_EN			(0x1 << 15)
+
+/* 4 Button Inline Command Control 2 (0x00e0) */
+#define RT5665_4BTN_IL_MASK			(0x1 << 15)
+#define RT5665_4BTN_IL_EN			(0x1 << 15)
+#define RT5665_4BTN_IL_DIS			(0x0 << 15)
+#define RT5665_4BTN_IL_RST_MASK			(0x1 << 14)
+#define RT5665_4BTN_IL_NOR			(0x1 << 14)
+#define RT5665_4BTN_IL_RST			(0x0 << 14)
+
+/* Analog JD Control 1 (0x00f0) */
+#define RT5665_JD1_MODE_MASK			(0x3 << 0)
+#define RT5665_JD1_MODE_0			(0x0 << 0)
+#define RT5665_JD1_MODE_1			(0x1 << 0)
+#define RT5665_JD1_MODE_2			(0x2 << 0)
+
+/* Jack Detect Control 3 (0x00f8) */
+#define RT5665_JD_TRI_HPO_SEL_MASK		(0x7)
+#define RT5665_JD_TRI_HPO_SEL_SFT		(0)
+#define RT5665_JD_HPO_GPIO_JD1			(0x0)
+#define RT5665_JD_HPO_JD1_1			(0x1)
+#define RT5665_JD_HPO_JD1_2			(0x2)
+#define RT5665_JD_HPO_JD2			(0x3)
+#define RT5665_JD_HPO_GPIO_JD2			(0x4)
+#define RT5665_JD_HPO_JD3			(0x5)
+#define RT5665_JD_HPO_JD_D			(0x6)
+
+/* Digital Misc Control (0x00fa) */
+#define RT5665_AM_MASK				(0x1 << 7)
+#define RT5665_AM_EN				(0x1 << 7)
+#define RT5665_AM_DIS				(0x1 << 7)
+#define RT5665_DIG_GATE_CTRL			0x1
+#define RT5665_DIG_GATE_CTRL_SFT		(0)
+
+/* Chopper and Clock control for ADC (0x011c)*/
+#define RT5665_M_RF_DIG_MASK			(0x1 << 12)
+#define RT5665_M_RF_DIG_SFT			12
+#define RT5665_M_RI_DIG				(0x1 << 11)
+
+/* Chopper and Clock control for DAC (0x013a)*/
+#define RT5665_CKXEN_DAC1_MASK			(0x1 << 13)
+#define RT5665_CKXEN_DAC1_SFT			13
+#define RT5665_CKGEN_DAC1_MASK			(0x1 << 12)
+#define RT5665_CKGEN_DAC1_SFT			12
+#define RT5665_CKXEN_DAC2_MASK			(0x1 << 5)
+#define RT5665_CKXEN_DAC2_SFT			5
+#define RT5665_CKGEN_DAC2_MASK			(0x1 << 4)
+#define RT5665_CKGEN_DAC2_SFT			4
+
+/* Chopper and Clock control for ADC (0x013b)*/
+#define RT5665_CKXEN_ADC1_MASK			(0x1 << 13)
+#define RT5665_CKXEN_ADC1_SFT			13
+#define RT5665_CKGEN_ADC1_MASK			(0x1 << 12)
+#define RT5665_CKGEN_ADC1_SFT			12
+#define RT5665_CKXEN_ADC2_MASK			(0x1 << 5)
+#define RT5665_CKXEN_ADC2_SFT			5
+#define RT5665_CKGEN_ADC2_MASK			(0x1 << 4)
+#define RT5665_CKGEN_ADC2_SFT			4
+
+/* Volume test (0x013f)*/
+#define RT5665_SEL_CLK_VOL_MASK			(0x1 << 15)
+#define RT5665_SEL_CLK_VOL_EN			(0x1 << 15)
+#define RT5665_SEL_CLK_VOL_DIS			(0x0 << 15)
+
+/* Test Mode Control 1 (0x0145) */
+#define RT5665_AD2DA_LB_MASK			(0x1 << 9)
+#define RT5665_AD2DA_LB_SFT			9
+
+/* Stereo Noise Gate Control 1 (0x0160) */
+#define RT5665_NG2_EN_MASK			(0x1 << 15)
+#define RT5665_NG2_EN				(0x1 << 15)
+#define RT5665_NG2_DIS				(0x0 << 15)
+
+/* Stereo1 DAC Silence Detection Control (0x0190) */
+#define RT5665_DEB_STO_DAC_MASK			(0x7 << 4)
+#define RT5665_DEB_80_MS			(0x0 << 4)
+
+/* SAR ADC Inline Command Control 1 (0x0210) */
+#define RT5665_SAR_BUTT_DET_MASK		(0x1 << 15)
+#define RT5665_SAR_BUTT_DET_EN			(0x1 << 15)
+#define RT5665_SAR_BUTT_DET_DIS			(0x0 << 15)
+#define RT5665_SAR_BUTDET_MODE_MASK		(0x1 << 14)
+#define RT5665_SAR_BUTDET_POW_SAV		(0x1 << 14)
+#define RT5665_SAR_BUTDET_POW_NORM		(0x0 << 14)
+#define RT5665_SAR_BUTDET_RST_MASK		(0x1 << 13)
+#define RT5665_SAR_BUTDET_RST_NORMAL		(0x1 << 13)
+#define RT5665_SAR_BUTDET_RST			(0x0 << 13)
+#define RT5665_SAR_POW_MASK			(0x1 << 12)
+#define RT5665_SAR_POW_EN			(0x1 << 12)
+#define RT5665_SAR_POW_DIS			(0x0 << 12)
+#define RT5665_SAR_RST_MASK			(0x1 << 11)
+#define RT5665_SAR_RST_NORMAL			(0x1 << 11)
+#define RT5665_SAR_RST				(0x0 << 11)
+#define RT5665_SAR_BYPASS_MASK			(0x1 << 10)
+#define RT5665_SAR_BYPASS_EN			(0x1 << 10)
+#define RT5665_SAR_BYPASS_DIS			(0x0 << 10)
+#define RT5665_SAR_SEL_MB1_MASK			(0x1 << 9)
+#define RT5665_SAR_SEL_MB1_SEL			(0x1 << 9)
+#define RT5665_SAR_SEL_MB1_NOSEL		(0x0 << 9)
+#define RT5665_SAR_SEL_MB2_MASK			(0x1 << 8)
+#define RT5665_SAR_SEL_MB2_SEL			(0x1 << 8)
+#define RT5665_SAR_SEL_MB2_NOSEL		(0x0 << 8)
+#define RT5665_SAR_SEL_MODE_MASK		(0x1 << 7)
+#define RT5665_SAR_SEL_MODE_CMP			(0x1 << 7)
+#define RT5665_SAR_SEL_MODE_ADC			(0x0 << 7)
+#define RT5665_SAR_SEL_MB1_MB2_MASK		(0x1 << 5)
+#define RT5665_SAR_SEL_MB1_MB2_AUTO		(0x1 << 5)
+#define RT5665_SAR_SEL_MB1_MB2_MANU		(0x0 << 5)
+#define RT5665_SAR_SEL_SIGNAL_MASK		(0x1 << 4)
+#define RT5665_SAR_SEL_SIGNAL_AUTO		(0x1 << 4)
+#define RT5665_SAR_SEL_SIGNAL_MANU		(0x0 << 4)
+
+/* System Clock Source */
+enum {
+	RT5665_SCLK_S_MCLK,
+	RT5665_SCLK_S_PLL1,
+	RT5665_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+	RT5665_PLL1_S_MCLK,
+	RT5665_PLL1_S_BCLK1,
+	RT5665_PLL1_S_BCLK2,
+	RT5665_PLL1_S_BCLK3,
+	RT5665_PLL1_S_BCLK4,
+};
+
+enum {
+	RT5665_AIF1_1,
+	RT5665_AIF1_2,
+	RT5665_AIF2_1,
+	RT5665_AIF2_2,
+	RT5665_AIF3,
+	RT5665_AIFS
+};
+
+enum {
+	CODEC_5665,
+	CODEC_5666,
+};
+
+/* filter mask */
+enum {
+	RT5665_DA_STEREO1_FILTER = 0x1,
+	RT5665_DA_STEREO2_FILTER = (0x1 << 1),
+	RT5665_DA_MONO_L_FILTER = (0x1 << 2),
+	RT5665_DA_MONO_R_FILTER = (0x1 << 3),
+	RT5665_AD_STEREO1_FILTER = (0x1 << 4),
+	RT5665_AD_STEREO2_FILTER = (0x1 << 5),
+	RT5665_AD_MONO_L_FILTER = (0x1 << 6),
+	RT5665_AD_MONO_R_FILTER = (0x1 << 7),
+};
+
+enum {
+	RT5665_CLK_SEL_SYS,
+	RT5665_CLK_SEL_I2S1_ASRC,
+	RT5665_CLK_SEL_I2S2_ASRC,
+	RT5665_CLK_SEL_I2S3_ASRC,
+	RT5665_CLK_SEL_SYS2,
+	RT5665_CLK_SEL_SYS3,
+	RT5665_CLK_SEL_SYS4,
+};
+
+int rt5665_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src);
+
+#endif /* __RT5665_H__ */
diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c
new file mode 100644
index 0000000..3c19d03
--- /dev/null
+++ b/sound/soc/codecs/rt5668.c
@@ -0,0 +1,2639 @@
+/*
+ * rt5668.c  --  RT5668B ALSA SoC audio component driver
+ *
+ * Copyright 2018 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/rt5668.h>
+
+#include "rl6231.h"
+#include "rt5668.h"
+
+#define RT5668_NUM_SUPPLIES 3
+
+static const char *rt5668_supply_names[RT5668_NUM_SUPPLIES] = {
+	"AVDD",
+	"MICVDD",
+	"VBAT",
+};
+
+struct rt5668_priv {
+	struct snd_soc_component *component;
+	struct rt5668_platform_data pdata;
+	struct regmap *regmap;
+	struct snd_soc_jack *hs_jack;
+	struct regulator_bulk_data supplies[RT5668_NUM_SUPPLIES];
+	struct delayed_work jack_detect_work;
+	struct delayed_work jd_check_work;
+	struct mutex calibrate_mutex;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5668_AIFS];
+	int bclk[RT5668_AIFS];
+	int master[RT5668_AIFS];
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+	int jack_type;
+};
+
+static const struct reg_default rt5668_reg[] = {
+	{0x0002, 0x8080},
+	{0x0003, 0x8000},
+	{0x0005, 0x0000},
+	{0x0006, 0x0000},
+	{0x0008, 0x800f},
+	{0x000b, 0x0000},
+	{0x0010, 0x4040},
+	{0x0011, 0x0000},
+	{0x0012, 0x1404},
+	{0x0013, 0x1000},
+	{0x0014, 0xa00a},
+	{0x0015, 0x0404},
+	{0x0016, 0x0404},
+	{0x0019, 0xafaf},
+	{0x001c, 0x2f2f},
+	{0x001f, 0x0000},
+	{0x0022, 0x5757},
+	{0x0023, 0x0039},
+	{0x0024, 0x000b},
+	{0x0026, 0xc0c4},
+	{0x0029, 0x8080},
+	{0x002a, 0xa0a0},
+	{0x002b, 0x0300},
+	{0x0030, 0x0000},
+	{0x003c, 0x0080},
+	{0x0044, 0x0c0c},
+	{0x0049, 0x0000},
+	{0x0061, 0x0000},
+	{0x0062, 0x0000},
+	{0x0063, 0x003f},
+	{0x0064, 0x0000},
+	{0x0065, 0x0000},
+	{0x0066, 0x0030},
+	{0x0067, 0x0000},
+	{0x006b, 0x0000},
+	{0x006c, 0x0000},
+	{0x006d, 0x2200},
+	{0x006e, 0x0a10},
+	{0x0070, 0x8000},
+	{0x0071, 0x8000},
+	{0x0073, 0x0000},
+	{0x0074, 0x0000},
+	{0x0075, 0x0002},
+	{0x0076, 0x0001},
+	{0x0079, 0x0000},
+	{0x007a, 0x0000},
+	{0x007b, 0x0000},
+	{0x007c, 0x0100},
+	{0x007e, 0x0000},
+	{0x0080, 0x0000},
+	{0x0081, 0x0000},
+	{0x0082, 0x0000},
+	{0x0083, 0x0000},
+	{0x0084, 0x0000},
+	{0x0085, 0x0000},
+	{0x0086, 0x0005},
+	{0x0087, 0x0000},
+	{0x0088, 0x0000},
+	{0x008c, 0x0003},
+	{0x008d, 0x0000},
+	{0x008e, 0x0060},
+	{0x008f, 0x1000},
+	{0x0091, 0x0c26},
+	{0x0092, 0x0073},
+	{0x0093, 0x0000},
+	{0x0094, 0x0080},
+	{0x0098, 0x0000},
+	{0x009a, 0x0000},
+	{0x009b, 0x0000},
+	{0x009c, 0x0000},
+	{0x009d, 0x0000},
+	{0x009e, 0x100c},
+	{0x009f, 0x0000},
+	{0x00a0, 0x0000},
+	{0x00a3, 0x0002},
+	{0x00a4, 0x0001},
+	{0x00ae, 0x2040},
+	{0x00af, 0x0000},
+	{0x00b6, 0x0000},
+	{0x00b7, 0x0000},
+	{0x00b8, 0x0000},
+	{0x00b9, 0x0002},
+	{0x00be, 0x0000},
+	{0x00c0, 0x0160},
+	{0x00c1, 0x82a0},
+	{0x00c2, 0x0000},
+	{0x00d0, 0x0000},
+	{0x00d1, 0x2244},
+	{0x00d2, 0x3300},
+	{0x00d3, 0x2200},
+	{0x00d4, 0x0000},
+	{0x00d9, 0x0009},
+	{0x00da, 0x0000},
+	{0x00db, 0x0000},
+	{0x00dc, 0x00c0},
+	{0x00dd, 0x2220},
+	{0x00de, 0x3131},
+	{0x00df, 0x3131},
+	{0x00e0, 0x3131},
+	{0x00e2, 0x0000},
+	{0x00e3, 0x4000},
+	{0x00e4, 0x0aa0},
+	{0x00e5, 0x3131},
+	{0x00e6, 0x3131},
+	{0x00e7, 0x3131},
+	{0x00e8, 0x3131},
+	{0x00ea, 0xb320},
+	{0x00eb, 0x0000},
+	{0x00f0, 0x0000},
+	{0x00f1, 0x00d0},
+	{0x00f2, 0x00d0},
+	{0x00f6, 0x0000},
+	{0x00fa, 0x0000},
+	{0x00fb, 0x0000},
+	{0x00fc, 0x0000},
+	{0x00fd, 0x0000},
+	{0x00fe, 0x10ec},
+	{0x00ff, 0x6530},
+	{0x0100, 0xa0a0},
+	{0x010b, 0x0000},
+	{0x010c, 0xae00},
+	{0x010d, 0xaaa0},
+	{0x010e, 0x8aa2},
+	{0x010f, 0x02a2},
+	{0x0110, 0xc000},
+	{0x0111, 0x04a2},
+	{0x0112, 0x2800},
+	{0x0113, 0x0000},
+	{0x0117, 0x0100},
+	{0x0125, 0x0410},
+	{0x0132, 0x6026},
+	{0x0136, 0x5555},
+	{0x0138, 0x3700},
+	{0x013a, 0x2000},
+	{0x013b, 0x2000},
+	{0x013c, 0x2005},
+	{0x013f, 0x0000},
+	{0x0142, 0x0000},
+	{0x0145, 0x0002},
+	{0x0146, 0x0000},
+	{0x0147, 0x0000},
+	{0x0148, 0x0000},
+	{0x0149, 0x0000},
+	{0x0150, 0x79a1},
+	{0x0151, 0x0000},
+	{0x0160, 0x4ec0},
+	{0x0161, 0x0080},
+	{0x0162, 0x0200},
+	{0x0163, 0x0800},
+	{0x0164, 0x0000},
+	{0x0165, 0x0000},
+	{0x0166, 0x0000},
+	{0x0167, 0x000f},
+	{0x0168, 0x000f},
+	{0x0169, 0x0021},
+	{0x0190, 0x413d},
+	{0x0194, 0x0000},
+	{0x0195, 0x0000},
+	{0x0197, 0x0022},
+	{0x0198, 0x0000},
+	{0x0199, 0x0000},
+	{0x01af, 0x0000},
+	{0x01b0, 0x0400},
+	{0x01b1, 0x0000},
+	{0x01b2, 0x0000},
+	{0x01b3, 0x0000},
+	{0x01b4, 0x0000},
+	{0x01b5, 0x0000},
+	{0x01b6, 0x01c3},
+	{0x01b7, 0x02a0},
+	{0x01b8, 0x03e9},
+	{0x01b9, 0x1389},
+	{0x01ba, 0xc351},
+	{0x01bb, 0x0009},
+	{0x01bc, 0x0018},
+	{0x01bd, 0x002a},
+	{0x01be, 0x004c},
+	{0x01bf, 0x0097},
+	{0x01c0, 0x433d},
+	{0x01c1, 0x2800},
+	{0x01c2, 0x0000},
+	{0x01c3, 0x0000},
+	{0x01c4, 0x0000},
+	{0x01c5, 0x0000},
+	{0x01c6, 0x0000},
+	{0x01c7, 0x0000},
+	{0x01c8, 0x40af},
+	{0x01c9, 0x0702},
+	{0x01ca, 0x0000},
+	{0x01cb, 0x0000},
+	{0x01cc, 0x5757},
+	{0x01cd, 0x5757},
+	{0x01ce, 0x5757},
+	{0x01cf, 0x5757},
+	{0x01d0, 0x5757},
+	{0x01d1, 0x5757},
+	{0x01d2, 0x5757},
+	{0x01d3, 0x5757},
+	{0x01d4, 0x5757},
+	{0x01d5, 0x5757},
+	{0x01d6, 0x0000},
+	{0x01d7, 0x0008},
+	{0x01d8, 0x0029},
+	{0x01d9, 0x3333},
+	{0x01da, 0x0000},
+	{0x01db, 0x0004},
+	{0x01dc, 0x0000},
+	{0x01de, 0x7c00},
+	{0x01df, 0x0320},
+	{0x01e0, 0x06a1},
+	{0x01e1, 0x0000},
+	{0x01e2, 0x0000},
+	{0x01e3, 0x0000},
+	{0x01e4, 0x0000},
+	{0x01e6, 0x0001},
+	{0x01e7, 0x0000},
+	{0x01e8, 0x0000},
+	{0x01ea, 0x0000},
+	{0x01eb, 0x0000},
+	{0x01ec, 0x0000},
+	{0x01ed, 0x0000},
+	{0x01ee, 0x0000},
+	{0x01ef, 0x0000},
+	{0x01f0, 0x0000},
+	{0x01f1, 0x0000},
+	{0x01f2, 0x0000},
+	{0x01f3, 0x0000},
+	{0x01f4, 0x0000},
+	{0x0210, 0x6297},
+	{0x0211, 0xa005},
+	{0x0212, 0x824c},
+	{0x0213, 0xf7ff},
+	{0x0214, 0xf24c},
+	{0x0215, 0x0102},
+	{0x0216, 0x00a3},
+	{0x0217, 0x0048},
+	{0x0218, 0xa2c0},
+	{0x0219, 0x0400},
+	{0x021a, 0x00c8},
+	{0x021b, 0x00c0},
+	{0x021c, 0x0000},
+	{0x0250, 0x4500},
+	{0x0251, 0x40b3},
+	{0x0252, 0x0000},
+	{0x0253, 0x0000},
+	{0x0254, 0x0000},
+	{0x0255, 0x0000},
+	{0x0256, 0x0000},
+	{0x0257, 0x0000},
+	{0x0258, 0x0000},
+	{0x0259, 0x0000},
+	{0x025a, 0x0005},
+	{0x0270, 0x0000},
+	{0x02ff, 0x0110},
+	{0x0300, 0x001f},
+	{0x0301, 0x032c},
+	{0x0302, 0x5f21},
+	{0x0303, 0x4000},
+	{0x0304, 0x4000},
+	{0x0305, 0x06d5},
+	{0x0306, 0x8000},
+	{0x0307, 0x0700},
+	{0x0310, 0x4560},
+	{0x0311, 0xa4a8},
+	{0x0312, 0x7418},
+	{0x0313, 0x0000},
+	{0x0314, 0x0006},
+	{0x0315, 0xffff},
+	{0x0316, 0xc400},
+	{0x0317, 0x0000},
+	{0x03c0, 0x7e00},
+	{0x03c1, 0x8000},
+	{0x03c2, 0x8000},
+	{0x03c3, 0x8000},
+	{0x03c4, 0x8000},
+	{0x03c5, 0x8000},
+	{0x03c6, 0x8000},
+	{0x03c7, 0x8000},
+	{0x03c8, 0x8000},
+	{0x03c9, 0x8000},
+	{0x03ca, 0x8000},
+	{0x03cb, 0x8000},
+	{0x03cc, 0x8000},
+	{0x03d0, 0x0000},
+	{0x03d1, 0x0000},
+	{0x03d2, 0x0000},
+	{0x03d3, 0x0000},
+	{0x03d4, 0x2000},
+	{0x03d5, 0x2000},
+	{0x03d6, 0x0000},
+	{0x03d7, 0x0000},
+	{0x03d8, 0x2000},
+	{0x03d9, 0x2000},
+	{0x03da, 0x2000},
+	{0x03db, 0x2000},
+	{0x03dc, 0x0000},
+	{0x03dd, 0x0000},
+	{0x03de, 0x0000},
+	{0x03df, 0x2000},
+	{0x03e0, 0x0000},
+	{0x03e1, 0x0000},
+	{0x03e2, 0x0000},
+	{0x03e3, 0x0000},
+	{0x03e4, 0x0000},
+	{0x03e5, 0x0000},
+	{0x03e6, 0x0000},
+	{0x03e7, 0x0000},
+	{0x03e8, 0x0000},
+	{0x03e9, 0x0000},
+	{0x03ea, 0x0000},
+	{0x03eb, 0x0000},
+	{0x03ec, 0x0000},
+	{0x03ed, 0x0000},
+	{0x03ee, 0x0000},
+	{0x03ef, 0x0000},
+	{0x03f0, 0x0800},
+	{0x03f1, 0x0800},
+	{0x03f2, 0x0800},
+	{0x03f3, 0x0800},
+};
+
+static bool rt5668_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5668_RESET:
+	case RT5668_CBJ_CTRL_2:
+	case RT5668_INT_ST_1:
+	case RT5668_4BTN_IL_CMD_1:
+	case RT5668_AJD1_CTRL:
+	case RT5668_HP_CALIB_CTRL_1:
+	case RT5668_DEVICE_ID:
+	case RT5668_I2C_MODE:
+	case RT5668_HP_CALIB_CTRL_10:
+	case RT5668_EFUSE_CTRL_2:
+	case RT5668_JD_TOP_VC_VTRL:
+	case RT5668_HP_IMP_SENS_CTRL_19:
+	case RT5668_IL_CMD_1:
+	case RT5668_SAR_IL_CMD_2:
+	case RT5668_SAR_IL_CMD_4:
+	case RT5668_SAR_IL_CMD_10:
+	case RT5668_SAR_IL_CMD_11:
+	case RT5668_EFUSE_CTRL_6...RT5668_EFUSE_CTRL_11:
+	case RT5668_HP_CALIB_STA_1...RT5668_HP_CALIB_STA_11:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5668_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5668_RESET:
+	case RT5668_VERSION_ID:
+	case RT5668_VENDOR_ID:
+	case RT5668_DEVICE_ID:
+	case RT5668_HP_CTRL_1:
+	case RT5668_HP_CTRL_2:
+	case RT5668_HPL_GAIN:
+	case RT5668_HPR_GAIN:
+	case RT5668_I2C_CTRL:
+	case RT5668_CBJ_BST_CTRL:
+	case RT5668_CBJ_CTRL_1:
+	case RT5668_CBJ_CTRL_2:
+	case RT5668_CBJ_CTRL_3:
+	case RT5668_CBJ_CTRL_4:
+	case RT5668_CBJ_CTRL_5:
+	case RT5668_CBJ_CTRL_6:
+	case RT5668_CBJ_CTRL_7:
+	case RT5668_DAC1_DIG_VOL:
+	case RT5668_STO1_ADC_DIG_VOL:
+	case RT5668_STO1_ADC_BOOST:
+	case RT5668_HP_IMP_GAIN_1:
+	case RT5668_HP_IMP_GAIN_2:
+	case RT5668_SIDETONE_CTRL:
+	case RT5668_STO1_ADC_MIXER:
+	case RT5668_AD_DA_MIXER:
+	case RT5668_STO1_DAC_MIXER:
+	case RT5668_A_DAC1_MUX:
+	case RT5668_DIG_INF2_DATA:
+	case RT5668_REC_MIXER:
+	case RT5668_CAL_REC:
+	case RT5668_ALC_BACK_GAIN:
+	case RT5668_PWR_DIG_1:
+	case RT5668_PWR_DIG_2:
+	case RT5668_PWR_ANLG_1:
+	case RT5668_PWR_ANLG_2:
+	case RT5668_PWR_ANLG_3:
+	case RT5668_PWR_MIXER:
+	case RT5668_PWR_VOL:
+	case RT5668_CLK_DET:
+	case RT5668_RESET_LPF_CTRL:
+	case RT5668_RESET_HPF_CTRL:
+	case RT5668_DMIC_CTRL_1:
+	case RT5668_I2S1_SDP:
+	case RT5668_I2S2_SDP:
+	case RT5668_ADDA_CLK_1:
+	case RT5668_ADDA_CLK_2:
+	case RT5668_I2S1_F_DIV_CTRL_1:
+	case RT5668_I2S1_F_DIV_CTRL_2:
+	case RT5668_TDM_CTRL:
+	case RT5668_TDM_ADDA_CTRL_1:
+	case RT5668_TDM_ADDA_CTRL_2:
+	case RT5668_DATA_SEL_CTRL_1:
+	case RT5668_TDM_TCON_CTRL:
+	case RT5668_GLB_CLK:
+	case RT5668_PLL_CTRL_1:
+	case RT5668_PLL_CTRL_2:
+	case RT5668_PLL_TRACK_1:
+	case RT5668_PLL_TRACK_2:
+	case RT5668_PLL_TRACK_3:
+	case RT5668_PLL_TRACK_4:
+	case RT5668_PLL_TRACK_5:
+	case RT5668_PLL_TRACK_6:
+	case RT5668_PLL_TRACK_11:
+	case RT5668_SDW_REF_CLK:
+	case RT5668_DEPOP_1:
+	case RT5668_DEPOP_2:
+	case RT5668_HP_CHARGE_PUMP_1:
+	case RT5668_HP_CHARGE_PUMP_2:
+	case RT5668_MICBIAS_1:
+	case RT5668_MICBIAS_2:
+	case RT5668_PLL_TRACK_12:
+	case RT5668_PLL_TRACK_14:
+	case RT5668_PLL2_CTRL_1:
+	case RT5668_PLL2_CTRL_2:
+	case RT5668_PLL2_CTRL_3:
+	case RT5668_PLL2_CTRL_4:
+	case RT5668_RC_CLK_CTRL:
+	case RT5668_I2S_M_CLK_CTRL_1:
+	case RT5668_I2S2_F_DIV_CTRL_1:
+	case RT5668_I2S2_F_DIV_CTRL_2:
+	case RT5668_EQ_CTRL_1:
+	case RT5668_EQ_CTRL_2:
+	case RT5668_IRQ_CTRL_1:
+	case RT5668_IRQ_CTRL_2:
+	case RT5668_IRQ_CTRL_3:
+	case RT5668_IRQ_CTRL_4:
+	case RT5668_INT_ST_1:
+	case RT5668_GPIO_CTRL_1:
+	case RT5668_GPIO_CTRL_2:
+	case RT5668_GPIO_CTRL_3:
+	case RT5668_HP_AMP_DET_CTRL_1:
+	case RT5668_HP_AMP_DET_CTRL_2:
+	case RT5668_MID_HP_AMP_DET:
+	case RT5668_LOW_HP_AMP_DET:
+	case RT5668_DELAY_BUF_CTRL:
+	case RT5668_SV_ZCD_1:
+	case RT5668_SV_ZCD_2:
+	case RT5668_IL_CMD_1:
+	case RT5668_IL_CMD_2:
+	case RT5668_IL_CMD_3:
+	case RT5668_IL_CMD_4:
+	case RT5668_IL_CMD_5:
+	case RT5668_IL_CMD_6:
+	case RT5668_4BTN_IL_CMD_1:
+	case RT5668_4BTN_IL_CMD_2:
+	case RT5668_4BTN_IL_CMD_3:
+	case RT5668_4BTN_IL_CMD_4:
+	case RT5668_4BTN_IL_CMD_5:
+	case RT5668_4BTN_IL_CMD_6:
+	case RT5668_4BTN_IL_CMD_7:
+	case RT5668_ADC_STO1_HP_CTRL_1:
+	case RT5668_ADC_STO1_HP_CTRL_2:
+	case RT5668_AJD1_CTRL:
+	case RT5668_JD1_THD:
+	case RT5668_JD2_THD:
+	case RT5668_JD_CTRL_1:
+	case RT5668_DUMMY_1:
+	case RT5668_DUMMY_2:
+	case RT5668_DUMMY_3:
+	case RT5668_DAC_ADC_DIG_VOL1:
+	case RT5668_BIAS_CUR_CTRL_2:
+	case RT5668_BIAS_CUR_CTRL_3:
+	case RT5668_BIAS_CUR_CTRL_4:
+	case RT5668_BIAS_CUR_CTRL_5:
+	case RT5668_BIAS_CUR_CTRL_6:
+	case RT5668_BIAS_CUR_CTRL_7:
+	case RT5668_BIAS_CUR_CTRL_8:
+	case RT5668_BIAS_CUR_CTRL_9:
+	case RT5668_BIAS_CUR_CTRL_10:
+	case RT5668_VREF_REC_OP_FB_CAP_CTRL:
+	case RT5668_CHARGE_PUMP_1:
+	case RT5668_DIG_IN_CTRL_1:
+	case RT5668_PAD_DRIVING_CTRL:
+	case RT5668_SOFT_RAMP_DEPOP:
+	case RT5668_CHOP_DAC:
+	case RT5668_CHOP_ADC:
+	case RT5668_CALIB_ADC_CTRL:
+	case RT5668_VOL_TEST:
+	case RT5668_SPKVDD_DET_STA:
+	case RT5668_TEST_MODE_CTRL_1:
+	case RT5668_TEST_MODE_CTRL_2:
+	case RT5668_TEST_MODE_CTRL_3:
+	case RT5668_TEST_MODE_CTRL_4:
+	case RT5668_TEST_MODE_CTRL_5:
+	case RT5668_PLL1_INTERNAL:
+	case RT5668_PLL2_INTERNAL:
+	case RT5668_STO_NG2_CTRL_1:
+	case RT5668_STO_NG2_CTRL_2:
+	case RT5668_STO_NG2_CTRL_3:
+	case RT5668_STO_NG2_CTRL_4:
+	case RT5668_STO_NG2_CTRL_5:
+	case RT5668_STO_NG2_CTRL_6:
+	case RT5668_STO_NG2_CTRL_7:
+	case RT5668_STO_NG2_CTRL_8:
+	case RT5668_STO_NG2_CTRL_9:
+	case RT5668_STO_NG2_CTRL_10:
+	case RT5668_STO1_DAC_SIL_DET:
+	case RT5668_SIL_PSV_CTRL1:
+	case RT5668_SIL_PSV_CTRL2:
+	case RT5668_SIL_PSV_CTRL3:
+	case RT5668_SIL_PSV_CTRL4:
+	case RT5668_SIL_PSV_CTRL5:
+	case RT5668_HP_IMP_SENS_CTRL_01:
+	case RT5668_HP_IMP_SENS_CTRL_02:
+	case RT5668_HP_IMP_SENS_CTRL_03:
+	case RT5668_HP_IMP_SENS_CTRL_04:
+	case RT5668_HP_IMP_SENS_CTRL_05:
+	case RT5668_HP_IMP_SENS_CTRL_06:
+	case RT5668_HP_IMP_SENS_CTRL_07:
+	case RT5668_HP_IMP_SENS_CTRL_08:
+	case RT5668_HP_IMP_SENS_CTRL_09:
+	case RT5668_HP_IMP_SENS_CTRL_10:
+	case RT5668_HP_IMP_SENS_CTRL_11:
+	case RT5668_HP_IMP_SENS_CTRL_12:
+	case RT5668_HP_IMP_SENS_CTRL_13:
+	case RT5668_HP_IMP_SENS_CTRL_14:
+	case RT5668_HP_IMP_SENS_CTRL_15:
+	case RT5668_HP_IMP_SENS_CTRL_16:
+	case RT5668_HP_IMP_SENS_CTRL_17:
+	case RT5668_HP_IMP_SENS_CTRL_18:
+	case RT5668_HP_IMP_SENS_CTRL_19:
+	case RT5668_HP_IMP_SENS_CTRL_20:
+	case RT5668_HP_IMP_SENS_CTRL_21:
+	case RT5668_HP_IMP_SENS_CTRL_22:
+	case RT5668_HP_IMP_SENS_CTRL_23:
+	case RT5668_HP_IMP_SENS_CTRL_24:
+	case RT5668_HP_IMP_SENS_CTRL_25:
+	case RT5668_HP_IMP_SENS_CTRL_26:
+	case RT5668_HP_IMP_SENS_CTRL_27:
+	case RT5668_HP_IMP_SENS_CTRL_28:
+	case RT5668_HP_IMP_SENS_CTRL_29:
+	case RT5668_HP_IMP_SENS_CTRL_30:
+	case RT5668_HP_IMP_SENS_CTRL_31:
+	case RT5668_HP_IMP_SENS_CTRL_32:
+	case RT5668_HP_IMP_SENS_CTRL_33:
+	case RT5668_HP_IMP_SENS_CTRL_34:
+	case RT5668_HP_IMP_SENS_CTRL_35:
+	case RT5668_HP_IMP_SENS_CTRL_36:
+	case RT5668_HP_IMP_SENS_CTRL_37:
+	case RT5668_HP_IMP_SENS_CTRL_38:
+	case RT5668_HP_IMP_SENS_CTRL_39:
+	case RT5668_HP_IMP_SENS_CTRL_40:
+	case RT5668_HP_IMP_SENS_CTRL_41:
+	case RT5668_HP_IMP_SENS_CTRL_42:
+	case RT5668_HP_IMP_SENS_CTRL_43:
+	case RT5668_HP_LOGIC_CTRL_1:
+	case RT5668_HP_LOGIC_CTRL_2:
+	case RT5668_HP_LOGIC_CTRL_3:
+	case RT5668_HP_CALIB_CTRL_1:
+	case RT5668_HP_CALIB_CTRL_2:
+	case RT5668_HP_CALIB_CTRL_3:
+	case RT5668_HP_CALIB_CTRL_4:
+	case RT5668_HP_CALIB_CTRL_5:
+	case RT5668_HP_CALIB_CTRL_6:
+	case RT5668_HP_CALIB_CTRL_7:
+	case RT5668_HP_CALIB_CTRL_9:
+	case RT5668_HP_CALIB_CTRL_10:
+	case RT5668_HP_CALIB_CTRL_11:
+	case RT5668_HP_CALIB_STA_1:
+	case RT5668_HP_CALIB_STA_2:
+	case RT5668_HP_CALIB_STA_3:
+	case RT5668_HP_CALIB_STA_4:
+	case RT5668_HP_CALIB_STA_5:
+	case RT5668_HP_CALIB_STA_6:
+	case RT5668_HP_CALIB_STA_7:
+	case RT5668_HP_CALIB_STA_8:
+	case RT5668_HP_CALIB_STA_9:
+	case RT5668_HP_CALIB_STA_10:
+	case RT5668_HP_CALIB_STA_11:
+	case RT5668_SAR_IL_CMD_1:
+	case RT5668_SAR_IL_CMD_2:
+	case RT5668_SAR_IL_CMD_3:
+	case RT5668_SAR_IL_CMD_4:
+	case RT5668_SAR_IL_CMD_5:
+	case RT5668_SAR_IL_CMD_6:
+	case RT5668_SAR_IL_CMD_7:
+	case RT5668_SAR_IL_CMD_8:
+	case RT5668_SAR_IL_CMD_9:
+	case RT5668_SAR_IL_CMD_10:
+	case RT5668_SAR_IL_CMD_11:
+	case RT5668_SAR_IL_CMD_12:
+	case RT5668_SAR_IL_CMD_13:
+	case RT5668_EFUSE_CTRL_1:
+	case RT5668_EFUSE_CTRL_2:
+	case RT5668_EFUSE_CTRL_3:
+	case RT5668_EFUSE_CTRL_4:
+	case RT5668_EFUSE_CTRL_5:
+	case RT5668_EFUSE_CTRL_6:
+	case RT5668_EFUSE_CTRL_7:
+	case RT5668_EFUSE_CTRL_8:
+	case RT5668_EFUSE_CTRL_9:
+	case RT5668_EFUSE_CTRL_10:
+	case RT5668_EFUSE_CTRL_11:
+	case RT5668_JD_TOP_VC_VTRL:
+	case RT5668_DRC1_CTRL_0:
+	case RT5668_DRC1_CTRL_1:
+	case RT5668_DRC1_CTRL_2:
+	case RT5668_DRC1_CTRL_3:
+	case RT5668_DRC1_CTRL_4:
+	case RT5668_DRC1_CTRL_5:
+	case RT5668_DRC1_CTRL_6:
+	case RT5668_DRC1_HARD_LMT_CTRL_1:
+	case RT5668_DRC1_HARD_LMT_CTRL_2:
+	case RT5668_DRC1_PRIV_1:
+	case RT5668_DRC1_PRIV_2:
+	case RT5668_DRC1_PRIV_3:
+	case RT5668_DRC1_PRIV_4:
+	case RT5668_DRC1_PRIV_5:
+	case RT5668_DRC1_PRIV_6:
+	case RT5668_DRC1_PRIV_7:
+	case RT5668_DRC1_PRIV_8:
+	case RT5668_EQ_AUTO_RCV_CTRL1:
+	case RT5668_EQ_AUTO_RCV_CTRL2:
+	case RT5668_EQ_AUTO_RCV_CTRL3:
+	case RT5668_EQ_AUTO_RCV_CTRL4:
+	case RT5668_EQ_AUTO_RCV_CTRL5:
+	case RT5668_EQ_AUTO_RCV_CTRL6:
+	case RT5668_EQ_AUTO_RCV_CTRL7:
+	case RT5668_EQ_AUTO_RCV_CTRL8:
+	case RT5668_EQ_AUTO_RCV_CTRL9:
+	case RT5668_EQ_AUTO_RCV_CTRL10:
+	case RT5668_EQ_AUTO_RCV_CTRL11:
+	case RT5668_EQ_AUTO_RCV_CTRL12:
+	case RT5668_EQ_AUTO_RCV_CTRL13:
+	case RT5668_ADC_L_EQ_LPF1_A1:
+	case RT5668_R_EQ_LPF1_A1:
+	case RT5668_L_EQ_LPF1_H0:
+	case RT5668_R_EQ_LPF1_H0:
+	case RT5668_L_EQ_BPF1_A1:
+	case RT5668_R_EQ_BPF1_A1:
+	case RT5668_L_EQ_BPF1_A2:
+	case RT5668_R_EQ_BPF1_A2:
+	case RT5668_L_EQ_BPF1_H0:
+	case RT5668_R_EQ_BPF1_H0:
+	case RT5668_L_EQ_BPF2_A1:
+	case RT5668_R_EQ_BPF2_A1:
+	case RT5668_L_EQ_BPF2_A2:
+	case RT5668_R_EQ_BPF2_A2:
+	case RT5668_L_EQ_BPF2_H0:
+	case RT5668_R_EQ_BPF2_H0:
+	case RT5668_L_EQ_BPF3_A1:
+	case RT5668_R_EQ_BPF3_A1:
+	case RT5668_L_EQ_BPF3_A2:
+	case RT5668_R_EQ_BPF3_A2:
+	case RT5668_L_EQ_BPF3_H0:
+	case RT5668_R_EQ_BPF3_H0:
+	case RT5668_L_EQ_BPF4_A1:
+	case RT5668_R_EQ_BPF4_A1:
+	case RT5668_L_EQ_BPF4_A2:
+	case RT5668_R_EQ_BPF4_A2:
+	case RT5668_L_EQ_BPF4_H0:
+	case RT5668_R_EQ_BPF4_H0:
+	case RT5668_L_EQ_HPF1_A1:
+	case RT5668_R_EQ_HPF1_A1:
+	case RT5668_L_EQ_HPF1_H0:
+	case RT5668_R_EQ_HPF1_H0:
+	case RT5668_L_EQ_PRE_VOL:
+	case RT5668_R_EQ_PRE_VOL:
+	case RT5668_L_EQ_POST_VOL:
+	case RT5668_R_EQ_POST_VOL:
+	case RT5668_I2C_MODE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+/* Interface data select */
+static const char * const rt5668_data_select[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5668_if2_adc_enum,
+	RT5668_DIG_INF2_DATA, RT5668_IF2_ADC_SEL_SFT, rt5668_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5668_if1_01_adc_enum,
+	RT5668_TDM_ADDA_CTRL_1, RT5668_IF1_ADC1_SEL_SFT, rt5668_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5668_if1_23_adc_enum,
+	RT5668_TDM_ADDA_CTRL_1, RT5668_IF1_ADC2_SEL_SFT, rt5668_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5668_if1_45_adc_enum,
+	RT5668_TDM_ADDA_CTRL_1, RT5668_IF1_ADC3_SEL_SFT, rt5668_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5668_if1_67_adc_enum,
+	RT5668_TDM_ADDA_CTRL_1, RT5668_IF1_ADC4_SEL_SFT, rt5668_data_select);
+
+static const struct snd_kcontrol_new rt5668_if2_adc_swap_mux =
+	SOC_DAPM_ENUM("IF2 ADC Swap Mux", rt5668_if2_adc_enum);
+
+static const struct snd_kcontrol_new rt5668_if1_01_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 01 ADC Swap Mux", rt5668_if1_01_adc_enum);
+
+static const struct snd_kcontrol_new rt5668_if1_23_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 23 ADC Swap Mux", rt5668_if1_23_adc_enum);
+
+static const struct snd_kcontrol_new rt5668_if1_45_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 45 ADC Swap Mux", rt5668_if1_45_adc_enum);
+
+static const struct snd_kcontrol_new rt5668_if1_67_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 67 ADC Swap Mux", rt5668_if1_67_adc_enum);
+
+static void rt5668_reset(struct regmap *regmap)
+{
+	regmap_write(regmap, RT5668_RESET, 0);
+	regmap_write(regmap, RT5668_I2C_MODE, 1);
+}
+/**
+ * rt5668_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @component: SoC audio component device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5668 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the component driver will turn on
+ * ASRC for these filters if ASRC is selected as their clock source.
+ */
+int rt5668_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src)
+{
+
+	switch (clk_src) {
+	case RT5668_CLK_SEL_SYS:
+	case RT5668_CLK_SEL_I2S1_ASRC:
+	case RT5668_CLK_SEL_I2S2_ASRC:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (filter_mask & RT5668_DA_STEREO1_FILTER) {
+		snd_soc_component_update_bits(component, RT5668_PLL_TRACK_2,
+			RT5668_FILTER_CLK_SEL_MASK,
+			clk_src << RT5668_FILTER_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5668_AD_STEREO1_FILTER) {
+		snd_soc_component_update_bits(component, RT5668_PLL_TRACK_3,
+			RT5668_FILTER_CLK_SEL_MASK,
+			clk_src << RT5668_FILTER_CLK_SEL_SFT);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5668_sel_asrc_clk_src);
+
+static int rt5668_button_detect(struct snd_soc_component *component)
+{
+	int btn_type, val;
+
+	val = snd_soc_component_read32(component, RT5668_4BTN_IL_CMD_1);
+	btn_type = val & 0xfff0;
+	snd_soc_component_write(component, RT5668_4BTN_IL_CMD_1, val);
+	pr_debug("%s btn_type=%x\n", __func__, btn_type);
+
+	return btn_type;
+}
+
+static void rt5668_enable_push_button_irq(struct snd_soc_component *component,
+		bool enable)
+{
+	if (enable) {
+		snd_soc_component_update_bits(component, RT5668_SAR_IL_CMD_1,
+			RT5668_SAR_BUTT_DET_MASK, RT5668_SAR_BUTT_DET_EN);
+		snd_soc_component_update_bits(component, RT5668_SAR_IL_CMD_13,
+			RT5668_SAR_SOUR_MASK, RT5668_SAR_SOUR_BTN);
+		snd_soc_component_write(component, RT5668_IL_CMD_1, 0x0040);
+		snd_soc_component_update_bits(component, RT5668_4BTN_IL_CMD_2,
+			RT5668_4BTN_IL_MASK | RT5668_4BTN_IL_RST_MASK,
+			RT5668_4BTN_IL_EN | RT5668_4BTN_IL_NOR);
+		snd_soc_component_update_bits(component, RT5668_IRQ_CTRL_3,
+			RT5668_IL_IRQ_MASK, RT5668_IL_IRQ_EN);
+	} else {
+		snd_soc_component_update_bits(component, RT5668_IRQ_CTRL_3,
+			RT5668_IL_IRQ_MASK, RT5668_IL_IRQ_DIS);
+		snd_soc_component_update_bits(component, RT5668_SAR_IL_CMD_1,
+			RT5668_SAR_BUTT_DET_MASK, RT5668_SAR_BUTT_DET_DIS);
+		snd_soc_component_update_bits(component, RT5668_4BTN_IL_CMD_2,
+			RT5668_4BTN_IL_MASK, RT5668_4BTN_IL_DIS);
+		snd_soc_component_update_bits(component, RT5668_4BTN_IL_CMD_2,
+			RT5668_4BTN_IL_RST_MASK, RT5668_4BTN_IL_RST);
+		snd_soc_component_update_bits(component, RT5668_SAR_IL_CMD_13,
+			RT5668_SAR_SOUR_MASK, RT5668_SAR_SOUR_TYPE);
+	}
+}
+
+/**
+ * rt5668_headset_detect - Detect headset.
+ * @component: SoC audio component device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+static int rt5668_headset_detect(struct snd_soc_component *component,
+		int jack_insert)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm =
+		snd_soc_component_get_dapm(component);
+	unsigned int val, count;
+
+	if (jack_insert) {
+		snd_soc_dapm_force_enable_pin(dapm, "CBJ Power");
+		snd_soc_dapm_sync(dapm);
+		snd_soc_component_update_bits(component, RT5668_CBJ_CTRL_1,
+			RT5668_TRIG_JD_MASK, RT5668_TRIG_JD_HIGH);
+
+		count = 0;
+		val = snd_soc_component_read32(component, RT5668_CBJ_CTRL_2)
+			& RT5668_JACK_TYPE_MASK;
+		while (val == 0 && count < 50) {
+			usleep_range(10000, 15000);
+			val = snd_soc_component_read32(component,
+				RT5668_CBJ_CTRL_2) & RT5668_JACK_TYPE_MASK;
+			count++;
+		}
+
+		switch (val) {
+		case 0x1:
+		case 0x2:
+			rt5668->jack_type = SND_JACK_HEADSET;
+			rt5668_enable_push_button_irq(component, true);
+			break;
+		default:
+			rt5668->jack_type = SND_JACK_HEADPHONE;
+		}
+
+	} else {
+		rt5668_enable_push_button_irq(component, false);
+		snd_soc_component_update_bits(component, RT5668_CBJ_CTRL_1,
+			RT5668_TRIG_JD_MASK, RT5668_TRIG_JD_LOW);
+		snd_soc_dapm_disable_pin(dapm, "CBJ Power");
+		snd_soc_dapm_sync(dapm);
+
+		rt5668->jack_type = 0;
+	}
+
+	dev_dbg(component->dev, "jack_type = %d\n", rt5668->jack_type);
+	return rt5668->jack_type;
+}
+
+static irqreturn_t rt5668_irq(int irq, void *data)
+{
+	struct rt5668_priv *rt5668 = data;
+
+	mod_delayed_work(system_power_efficient_wq,
+			&rt5668->jack_detect_work, msecs_to_jiffies(250));
+
+	return IRQ_HANDLED;
+}
+
+static void rt5668_jd_check_handler(struct work_struct *work)
+{
+	struct rt5668_priv *rt5668 = container_of(work, struct rt5668_priv,
+		jd_check_work.work);
+
+	if (snd_soc_component_read32(rt5668->component, RT5668_AJD1_CTRL)
+		& RT5668_JDH_RS_MASK) {
+		/* jack out */
+		rt5668->jack_type = rt5668_headset_detect(rt5668->component, 0);
+
+		snd_soc_jack_report(rt5668->hs_jack, rt5668->jack_type,
+				SND_JACK_HEADSET |
+				SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				SND_JACK_BTN_2 | SND_JACK_BTN_3);
+	} else {
+		schedule_delayed_work(&rt5668->jd_check_work, 500);
+	}
+}
+
+static int rt5668_set_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *hs_jack, void *data)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+
+	switch (rt5668->pdata.jd_src) {
+	case RT5668_JD1:
+		snd_soc_component_update_bits(component, RT5668_CBJ_CTRL_2,
+			RT5668_EXT_JD_SRC, RT5668_EXT_JD_SRC_MANUAL);
+		snd_soc_component_write(component, RT5668_CBJ_CTRL_1, 0xd002);
+		snd_soc_component_update_bits(component, RT5668_CBJ_CTRL_3,
+			RT5668_CBJ_IN_BUF_EN, RT5668_CBJ_IN_BUF_EN);
+		snd_soc_component_update_bits(component, RT5668_SAR_IL_CMD_1,
+			RT5668_SAR_POW_MASK, RT5668_SAR_POW_EN);
+		regmap_update_bits(rt5668->regmap, RT5668_GPIO_CTRL_1,
+			RT5668_GP1_PIN_MASK, RT5668_GP1_PIN_IRQ);
+		regmap_update_bits(rt5668->regmap, RT5668_RC_CLK_CTRL,
+				RT5668_POW_IRQ | RT5668_POW_JDH |
+				RT5668_POW_ANA, RT5668_POW_IRQ |
+				RT5668_POW_JDH | RT5668_POW_ANA);
+		regmap_update_bits(rt5668->regmap, RT5668_PWR_ANLG_2,
+			RT5668_PWR_JDH | RT5668_PWR_JDL,
+			RT5668_PWR_JDH | RT5668_PWR_JDL);
+		regmap_update_bits(rt5668->regmap, RT5668_IRQ_CTRL_2,
+			RT5668_JD1_EN_MASK | RT5668_JD1_POL_MASK,
+			RT5668_JD1_EN | RT5668_JD1_POL_NOR);
+		mod_delayed_work(system_power_efficient_wq,
+			   &rt5668->jack_detect_work, msecs_to_jiffies(250));
+		break;
+
+	case RT5668_JD_NULL:
+		regmap_update_bits(rt5668->regmap, RT5668_IRQ_CTRL_2,
+			RT5668_JD1_EN_MASK, RT5668_JD1_DIS);
+		regmap_update_bits(rt5668->regmap, RT5668_RC_CLK_CTRL,
+				RT5668_POW_JDH | RT5668_POW_JDL, 0);
+		break;
+
+	default:
+		dev_warn(component->dev, "Wrong JD source\n");
+		break;
+	}
+
+	rt5668->hs_jack = hs_jack;
+
+	return 0;
+}
+
+static void rt5668_jack_detect_handler(struct work_struct *work)
+{
+	struct rt5668_priv *rt5668 =
+		container_of(work, struct rt5668_priv, jack_detect_work.work);
+	int val, btn_type;
+
+	while (!rt5668->component)
+		usleep_range(10000, 15000);
+
+	while (!rt5668->component->card->instantiated)
+		usleep_range(10000, 15000);
+
+	mutex_lock(&rt5668->calibrate_mutex);
+
+	val = snd_soc_component_read32(rt5668->component, RT5668_AJD1_CTRL)
+		& RT5668_JDH_RS_MASK;
+	if (!val) {
+		/* jack in */
+		if (rt5668->jack_type == 0) {
+			/* jack was out, report jack type */
+			rt5668->jack_type =
+				rt5668_headset_detect(rt5668->component, 1);
+		} else {
+			/* jack is already in, report button event */
+			rt5668->jack_type = SND_JACK_HEADSET;
+			btn_type = rt5668_button_detect(rt5668->component);
+			/**
+			 * rt5668 can report three kinds of button behavior,
+			 * one click, double click and hold. However,
+			 * currently we will report button pressed/released
+			 * event. So all the three button behaviors are
+			 * treated as button pressed.
+			 */
+			switch (btn_type) {
+			case 0x8000:
+			case 0x4000:
+			case 0x2000:
+				rt5668->jack_type |= SND_JACK_BTN_0;
+				break;
+			case 0x1000:
+			case 0x0800:
+			case 0x0400:
+				rt5668->jack_type |= SND_JACK_BTN_1;
+				break;
+			case 0x0200:
+			case 0x0100:
+			case 0x0080:
+				rt5668->jack_type |= SND_JACK_BTN_2;
+				break;
+			case 0x0040:
+			case 0x0020:
+			case 0x0010:
+				rt5668->jack_type |= SND_JACK_BTN_3;
+				break;
+			case 0x0000: /* unpressed */
+				break;
+			default:
+				btn_type = 0;
+				dev_err(rt5668->component->dev,
+					"Unexpected button code 0x%04x\n",
+					btn_type);
+				break;
+			}
+		}
+	} else {
+		/* jack out */
+		rt5668->jack_type = rt5668_headset_detect(rt5668->component, 0);
+	}
+
+	snd_soc_jack_report(rt5668->hs_jack, rt5668->jack_type,
+			SND_JACK_HEADSET |
+			    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+			    SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+	if (rt5668->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+		SND_JACK_BTN_2 | SND_JACK_BTN_3))
+		schedule_delayed_work(&rt5668->jd_check_work, 0);
+	else
+		cancel_delayed_work_sync(&rt5668->jd_check_work);
+
+	mutex_unlock(&rt5668->calibrate_mutex);
+}
+
+static const struct snd_kcontrol_new rt5668_snd_controls[] = {
+	/* Headphone Output Volume */
+	SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5668_HPL_GAIN,
+		RT5668_HPR_GAIN, RT5668_G_HP_SFT, 15, 1, hp_vol_tlv),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5668_DAC1_DIG_VOL,
+		RT5668_L_VOL_SFT, RT5668_R_VOL_SFT, 175, 0, dac_vol_tlv),
+
+	/* IN Boost Volume */
+	SOC_SINGLE_TLV("CBJ Boost Volume", RT5668_CBJ_BST_CTRL,
+		RT5668_BST_CBJ_SFT, 8, 0, bst_tlv),
+
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("STO1 ADC Capture Switch", RT5668_STO1_ADC_DIG_VOL,
+		RT5668_L_MUTE_SFT, RT5668_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5668_STO1_ADC_DIG_VOL,
+		RT5668_L_VOL_SFT, RT5668_R_VOL_SFT, 127, 0, adc_vol_tlv),
+
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5668_STO1_ADC_BOOST,
+		RT5668_STO1_ADC_L_BST_SFT, RT5668_STO1_ADC_R_BST_SFT,
+		3, 0, adc_bst_tlv),
+};
+
+
+static int rt5668_div_sel(struct rt5668_priv *rt5668,
+			  int target, const int div[], int size)
+{
+	int i;
+
+	if (rt5668->sysclk < target) {
+		pr_err("sysclk rate %d is too low\n",
+			rt5668->sysclk);
+		return 0;
+	}
+
+	for (i = 0; i < size - 1; i++) {
+		pr_info("div[%d]=%d\n", i, div[i]);
+		if (target * div[i] == rt5668->sysclk)
+			return i;
+		if (target * div[i + 1] > rt5668->sysclk) {
+			pr_err("can't find div for sysclk %d\n",
+				rt5668->sysclk);
+			return i;
+		}
+	}
+
+	if (target * div[i] < rt5668->sysclk)
+		pr_err("sysclk rate %d is too high\n",
+			rt5668->sysclk);
+
+	return size - 1;
+
+}
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+	int idx = -EINVAL;
+	static const int div[] = {2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128};
+
+	idx = rt5668_div_sel(rt5668, 1500000, div, ARRAY_SIZE(div));
+
+	snd_soc_component_update_bits(component, RT5668_DMIC_CTRL_1,
+		RT5668_DMIC_CLK_MASK, idx << RT5668_DMIC_CLK_SFT);
+
+	return 0;
+}
+
+static int set_filter_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+	int ref, val, reg, idx = -EINVAL;
+	static const int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48};
+
+	val = snd_soc_component_read32(component, RT5668_GPIO_CTRL_1) &
+		RT5668_GP4_PIN_MASK;
+	if (w->shift == RT5668_PWR_ADC_S1F_BIT &&
+		val == RT5668_GP4_PIN_ADCDAT2)
+		ref = 256 * rt5668->lrck[RT5668_AIF2];
+	else
+		ref = 256 * rt5668->lrck[RT5668_AIF1];
+
+	idx = rt5668_div_sel(rt5668, ref, div, ARRAY_SIZE(div));
+
+	if (w->shift == RT5668_PWR_ADC_S1F_BIT)
+		reg = RT5668_PLL_TRACK_3;
+	else
+		reg = RT5668_PLL_TRACK_2;
+
+	snd_soc_component_update_bits(component, reg,
+		RT5668_FILTER_CLK_SEL_MASK, idx << RT5668_FILTER_CLK_SEL_SFT);
+
+	return 0;
+}
+
+static int is_sys_clk_from_pll1(struct snd_soc_dapm_widget *w,
+			 struct snd_soc_dapm_widget *sink)
+{
+	unsigned int val;
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+
+	val = snd_soc_component_read32(component, RT5668_GLB_CLK);
+	val &= RT5668_SCLK_SRC_MASK;
+	if (val == RT5668_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int is_using_asrc(struct snd_soc_dapm_widget *w,
+			 struct snd_soc_dapm_widget *sink)
+{
+	unsigned int reg, shift, val;
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+
+	switch (w->shift) {
+	case RT5668_ADC_STO1_ASRC_SFT:
+		reg = RT5668_PLL_TRACK_3;
+		shift = RT5668_FILTER_CLK_SEL_SFT;
+		break;
+	case RT5668_DAC_STO1_ASRC_SFT:
+		reg = RT5668_PLL_TRACK_2;
+		shift = RT5668_FILTER_CLK_SEL_SFT;
+		break;
+	default:
+		return 0;
+	}
+
+	val = (snd_soc_component_read32(component, reg) >> shift) & 0xf;
+	switch (val) {
+	case RT5668_CLK_SEL_I2S1_ASRC:
+	case RT5668_CLK_SEL_I2S2_ASRC:
+		return 1;
+	default:
+		return 0;
+	}
+
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5668_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5668_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5668_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5668_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5668_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5668_STO1_ADC_MIXER,
+			RT5668_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5668_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5668_AD_DA_MIXER,
+			RT5668_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5668_AD_DA_MIXER,
+			RT5668_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5668_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5668_AD_DA_MIXER,
+			RT5668_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5668_AD_DA_MIXER,
+			RT5668_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5668_sto1_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5668_STO1_DAC_MIXER,
+			RT5668_M_DAC_L1_STO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5668_STO1_DAC_MIXER,
+			RT5668_M_DAC_R1_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5668_sto1_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5668_STO1_DAC_MIXER,
+			RT5668_M_DAC_L1_STO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5668_STO1_DAC_MIXER,
+			RT5668_M_DAC_R1_STO_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5668_rec1_l_mix[] = {
+	SOC_DAPM_SINGLE("CBJ Switch", RT5668_REC_MIXER,
+			RT5668_M_CBJ_RM1_L_SFT, 1, 1),
+};
+
+/* STO1 ADC1 Source */
+/* MX-26 [13] [5] */
+static const char * const rt5668_sto1_adc1_src[] = {
+	"DAC MIX", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_sto1_adc1l_enum, RT5668_STO1_ADC_MIXER,
+	RT5668_STO1_ADC1L_SRC_SFT, rt5668_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adc1l_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5668_sto1_adc1l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_sto1_adc1r_enum, RT5668_STO1_ADC_MIXER,
+	RT5668_STO1_ADC1R_SRC_SFT, rt5668_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adc1r_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5668_sto1_adc1r_enum);
+
+/* STO1 ADC Source */
+/* MX-26 [11:10] [3:2] */
+static const char * const rt5668_sto1_adc_src[] = {
+	"ADC1 L", "ADC1 R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_sto1_adcl_enum, RT5668_STO1_ADC_MIXER,
+	RT5668_STO1_ADCL_SRC_SFT, rt5668_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adcl_mux =
+	SOC_DAPM_ENUM("Stereo1 ADCL Source", rt5668_sto1_adcl_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_sto1_adcr_enum, RT5668_STO1_ADC_MIXER,
+	RT5668_STO1_ADCR_SRC_SFT, rt5668_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adcr_mux =
+	SOC_DAPM_ENUM("Stereo1 ADCR Source", rt5668_sto1_adcr_enum);
+
+/* STO1 ADC2 Source */
+/* MX-26 [12] [4] */
+static const char * const rt5668_sto1_adc2_src[] = {
+	"DAC MIX", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_sto1_adc2l_enum, RT5668_STO1_ADC_MIXER,
+	RT5668_STO1_ADC2L_SRC_SFT, rt5668_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adc2l_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC2L Source", rt5668_sto1_adc2l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_sto1_adc2r_enum, RT5668_STO1_ADC_MIXER,
+	RT5668_STO1_ADC2R_SRC_SFT, rt5668_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5668_sto1_adc2r_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC2R Source", rt5668_sto1_adc2r_enum);
+
+/* MX-79 [6:4] I2S1 ADC data location */
+static const unsigned int rt5668_if1_adc_slot_values[] = {
+	0,
+	2,
+	4,
+	6,
+};
+
+static const char * const rt5668_if1_adc_slot_src[] = {
+	"Slot 0", "Slot 2", "Slot 4", "Slot 6"
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5668_if1_adc_slot_enum,
+	RT5668_TDM_CTRL, RT5668_TDM_ADC_LCA_SFT, RT5668_TDM_ADC_LCA_MASK,
+	rt5668_if1_adc_slot_src, rt5668_if1_adc_slot_values);
+
+static const struct snd_kcontrol_new rt5668_if1_adc_slot_mux =
+	SOC_DAPM_ENUM("IF1 ADC Slot location", rt5668_if1_adc_slot_enum);
+
+/* Analog DAC L1 Source, Analog DAC R1 Source*/
+/* MX-2B [4], MX-2B [0]*/
+static const char * const rt5668_alg_dac1_src[] = {
+	"Stereo1 DAC Mixer", "DAC1"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_alg_dac_l1_enum, RT5668_A_DAC1_MUX,
+	RT5668_A_DACL1_SFT, rt5668_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5668_alg_dac_l1_mux =
+	SOC_DAPM_ENUM("Analog DAC L1 Source", rt5668_alg_dac_l1_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5668_alg_dac_r1_enum, RT5668_A_DAC1_MUX,
+	RT5668_A_DACR1_SFT, rt5668_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5668_alg_dac_r1_mux =
+	SOC_DAPM_ENUM("Analog DAC R1 Source", rt5668_alg_dac_r1_enum);
+
+/* Out Switch */
+static const struct snd_kcontrol_new hpol_switch =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5668_HP_CTRL_1,
+					RT5668_L_MUTE_SFT, 1, 1);
+static const struct snd_kcontrol_new hpor_switch =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5668_HP_CTRL_1,
+					RT5668_R_MUTE_SFT, 1, 1);
+
+static int rt5668_hp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_write(component,
+			RT5668_HP_LOGIC_CTRL_2, 0x0012);
+		snd_soc_component_write(component,
+			RT5668_HP_CTRL_2, 0x6000);
+		snd_soc_component_update_bits(component, RT5668_STO_NG2_CTRL_1,
+			RT5668_NG2_EN_MASK, RT5668_NG2_EN);
+		snd_soc_component_update_bits(component,
+			RT5668_DEPOP_1, 0x60, 0x60);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component,
+			RT5668_DEPOP_1, 0x60, 0x0);
+		snd_soc_component_write(component,
+			RT5668_HP_CTRL_2, 0x0000);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+
+}
+
+static int set_dmic_power(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/*Add delay to avoid pop noise*/
+		msleep(150);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5655_set_verf(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		switch (w->shift) {
+		case RT5668_PWR_VREF1_BIT:
+			snd_soc_component_update_bits(component,
+				RT5668_PWR_ANLG_1, RT5668_PWR_FV1, 0);
+			break;
+
+		case RT5668_PWR_VREF2_BIT:
+			snd_soc_component_update_bits(component,
+				RT5668_PWR_ANLG_1, RT5668_PWR_FV2, 0);
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(15000, 20000);
+		switch (w->shift) {
+		case RT5668_PWR_VREF1_BIT:
+			snd_soc_component_update_bits(component,
+				RT5668_PWR_ANLG_1, RT5668_PWR_FV1,
+				RT5668_PWR_FV1);
+			break;
+
+		case RT5668_PWR_VREF2_BIT:
+			snd_soc_component_update_bits(component,
+				RT5668_PWR_ANLG_1, RT5668_PWR_FV2,
+				RT5668_PWR_FV2);
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const unsigned int rt5668_adcdat_pin_values[] = {
+	1,
+	3,
+};
+
+static const char * const rt5668_adcdat_pin_select[] = {
+	"ADCDAT1",
+	"ADCDAT2",
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5668_adcdat_pin_enum,
+	RT5668_GPIO_CTRL_1, RT5668_GP4_PIN_SFT, RT5668_GP4_PIN_MASK,
+	rt5668_adcdat_pin_select, rt5668_adcdat_pin_values);
+
+static const struct snd_kcontrol_new rt5668_adcdat_pin_ctrl =
+	SOC_DAPM_ENUM("ADCDAT", rt5668_adcdat_pin_enum);
+
+static const struct snd_soc_dapm_widget rt5668_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("LDO2", RT5668_PWR_ANLG_3, RT5668_PWR_LDO2_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL1", RT5668_PWR_ANLG_3, RT5668_PWR_PLL_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL2B", RT5668_PWR_ANLG_3, RT5668_PWR_PLL2B_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL2F", RT5668_PWR_ANLG_3, RT5668_PWR_PLL2F_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Vref1", RT5668_PWR_ANLG_1, RT5668_PWR_VREF1_BIT, 0,
+		rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("Vref2", RT5668_PWR_ANLG_1, RT5668_PWR_VREF2_BIT, 0,
+		rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5668_PLL_TRACK_1,
+		RT5668_DAC_STO1_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5668_PLL_TRACK_1,
+		RT5668_ADC_STO1_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AD ASRC", 1, RT5668_PLL_TRACK_1,
+		RT5668_AD_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DA ASRC", 1, RT5668_PLL_TRACK_1,
+		RT5668_DA_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC ASRC", 1, RT5668_PLL_TRACK_1,
+		RT5668_DMIC_ASRC_SFT, 0, NULL, 0),
+
+	/* Input Side */
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5668_PWR_ANLG_2, RT5668_PWR_MB1_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5668_PWR_ANLG_2, RT5668_PWR_MB2_BIT,
+		0, NULL, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC L1"),
+	SND_SOC_DAPM_INPUT("DMIC R1"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+		set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5668_DMIC_CTRL_1,
+		RT5668_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("CBJ Power", RT5668_PWR_ANLG_3,
+		RT5668_PWR_CBJ_BIT, 0, NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5668_rec1_l_mix,
+		ARRAY_SIZE(rt5668_rec1_l_mix)),
+	SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5668_PWR_ANLG_2,
+		RT5668_PWR_RM1_L_BIT, 0, NULL, 0),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5668_PWR_DIG_1,
+		RT5668_PWR_ADC_L1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5668_PWR_DIG_1,
+		RT5668_PWR_ADC_R1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1 clock", RT5668_CHOP_ADC,
+		RT5668_CKGEN_ADC1_SFT, 0, NULL, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adc1l_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adc1r_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adc2l_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adc2r_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adcl_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_sto1_adcr_mux),
+	SND_SOC_DAPM_MUX("IF1_ADC Mux", SND_SOC_NOPM, 0, 0,
+		&rt5668_if1_adc_slot_mux),
+
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5668_PWR_DIG_2,
+		RT5668_PWR_ADC_S1F_BIT, 0, set_filter_clk,
+		SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", RT5668_STO1_ADC_DIG_VOL,
+		RT5668_L_MUTE_SFT, 1, rt5668_sto1_adc_l_mix,
+		ARRAY_SIZE(rt5668_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5668_STO1_ADC_DIG_VOL,
+		RT5668_R_MUTE_SFT, 1, rt5668_sto1_adc_r_mix,
+		ARRAY_SIZE(rt5668_sto1_adc_r_mix)),
+
+	/* ADC PGA */
+	SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5668_PWR_DIG_1, RT5668_PWR_I2S1_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("I2S2", RT5668_PWR_DIG_1, RT5668_PWR_I2S2_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface Select */
+	SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5668_if1_01_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 23 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5668_if1_23_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 45 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5668_if1_45_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 67 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5668_if1_67_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5668_if2_adc_swap_mux),
+
+	SND_SOC_DAPM_MUX("ADCDAT Mux", SND_SOC_NOPM, 0, 0,
+			&rt5668_adcdat_pin_ctrl),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0,
+		RT5668_I2S1_SDP, RT5668_SEL_ADCDAT_SFT, 1),
+	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0,
+		RT5668_I2S2_SDP, RT5668_I2S2_PIN_CFG_SFT, 1),
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Side */
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
+		rt5668_dac_l_mix, ARRAY_SIZE(rt5668_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+		rt5668_dac_r_mix, ARRAY_SIZE(rt5668_dac_r_mix)),
+
+	/* DAC channel Mux */
+	SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0,
+		&rt5668_alg_dac_l1_mux),
+	SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0,
+		&rt5668_alg_dac_r1_mux),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5668_PWR_DIG_2,
+		RT5668_PWR_DAC_S1F_BIT, 0, set_filter_clk,
+		SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MIXER("Stereo1 DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5668_sto1_dac_l_mix, ARRAY_SIZE(rt5668_sto1_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo1 DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5668_sto1_dac_r_mix, ARRAY_SIZE(rt5668_sto1_dac_r_mix)),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC L1", NULL, RT5668_PWR_DIG_1,
+		RT5668_PWR_DAC_L1_BIT, 0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, RT5668_PWR_DIG_1,
+		RT5668_PWR_DAC_R1_BIT, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC 1 Clock", 3, RT5668_CHOP_DAC,
+		RT5668_CKGEN_DAC1_SFT, 0, NULL, 0),
+
+	/* HPO */
+	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5668_hp_event,
+		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
+
+	SND_SOC_DAPM_SUPPLY("HP Amp L", RT5668_PWR_ANLG_1,
+		RT5668_PWR_HA_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HP Amp R", RT5668_PWR_ANLG_1,
+		RT5668_PWR_HA_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, RT5668_DEPOP_1,
+		RT5668_PUMP_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("Capless", 2, RT5668_DEPOP_1,
+		RT5668_CAPLESS_EN_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH("HPOL Playback", SND_SOC_NOPM, 0, 0,
+		&hpol_switch),
+	SND_SOC_DAPM_SWITCH("HPOR Playback", SND_SOC_NOPM, 0, 0,
+		&hpor_switch),
+
+	/* CLK DET */
+	SND_SOC_DAPM_SUPPLY("CLKDET SYS", RT5668_CLK_DET,
+		RT5668_SYS_CLK_DET_SFT,	0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET PLL1", RT5668_CLK_DET,
+		RT5668_PLL1_CLK_DET_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET PLL2", RT5668_CLK_DET,
+		RT5668_PLL2_CLK_DET_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET", RT5668_CLK_DET,
+		RT5668_POW_CLK_DET_SFT, 0, NULL, 0),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+
+};
+
+static const struct snd_soc_dapm_route rt5668_dapm_routes[] = {
+	/*PLL*/
+	{"ADC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll1},
+	{"DAC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll1},
+
+	/*ASRC*/
+	{"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc},
+	{"DAC Stereo1 Filter", NULL, "DAC STO1 ASRC", is_using_asrc},
+	{"ADC STO1 ASRC", NULL, "AD ASRC"},
+	{"DAC STO1 ASRC", NULL, "DA ASRC"},
+
+	/*Vref*/
+	{"MICBIAS1", NULL, "Vref1"},
+	{"MICBIAS1", NULL, "Vref2"},
+	{"MICBIAS2", NULL, "Vref1"},
+	{"MICBIAS2", NULL, "Vref2"},
+
+	{"CLKDET SYS", NULL, "CLKDET"},
+
+	{"IN1P", NULL, "LDO2"},
+
+	{"BST1 CBJ", NULL, "IN1P"},
+	{"BST1 CBJ", NULL, "CBJ Power"},
+	{"CBJ Power", NULL, "Vref2"},
+
+	{"RECMIX1L", "CBJ Switch", "BST1 CBJ"},
+	{"RECMIX1L", NULL, "RECMIX1L Power"},
+
+	{"ADC1 L", NULL, "RECMIX1L"},
+	{"ADC1 L", NULL, "ADC1 L Power"},
+	{"ADC1 L", NULL, "ADC1 clock"},
+
+	{"DMIC L1", NULL, "DMIC CLK"},
+	{"DMIC L1", NULL, "DMIC1 Power"},
+	{"DMIC R1", NULL, "DMIC CLK"},
+	{"DMIC R1", NULL, "DMIC1 Power"},
+	{"DMIC CLK", NULL, "DMIC ASRC"},
+
+	{"Stereo1 ADC L Mux", "ADC1 L", "ADC1 L"},
+	{"Stereo1 ADC L Mux", "ADC1 R", "ADC1 R"},
+	{"Stereo1 ADC R Mux", "ADC1 L", "ADC1 L"},
+	{"Stereo1 ADC R Mux", "ADC1 R", "ADC1 R"},
+
+	{"Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux"},
+	{"Stereo1 ADC L1 Mux", "DAC MIX", "Stereo1 DAC MIXL"},
+	{"Stereo1 ADC L2 Mux", "DMIC", "DMIC L1"},
+	{"Stereo1 ADC L2 Mux", "DAC MIX", "Stereo1 DAC MIXL"},
+
+	{"Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux"},
+	{"Stereo1 ADC R1 Mux", "DAC MIX", "Stereo1 DAC MIXR"},
+	{"Stereo1 ADC R2 Mux", "DMIC", "DMIC R1"},
+	{"Stereo1 ADC R2 Mux", "DAC MIX", "Stereo1 DAC MIXR"},
+
+	{"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"},
+	{"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"},
+	{"Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter"},
+
+	{"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"},
+	{"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"},
+	{"Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter"},
+
+	{"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL"},
+	{"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR"},
+
+	{"IF1 01 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF1 01 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF1 01 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF1 01 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+	{"IF1 23 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF1 23 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF1 23 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF1 23 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+	{"IF1 45 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF1 45 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF1 45 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF1 45 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+	{"IF1 67 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF1 67 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF1 67 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF1 67 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+
+	{"IF1_ADC Mux", "Slot 0", "IF1 01 ADC Swap Mux"},
+	{"IF1_ADC Mux", "Slot 2", "IF1 23 ADC Swap Mux"},
+	{"IF1_ADC Mux", "Slot 4", "IF1 45 ADC Swap Mux"},
+	{"IF1_ADC Mux", "Slot 6", "IF1 67 ADC Swap Mux"},
+	{"IF1_ADC Mux", NULL, "I2S1"},
+	{"ADCDAT Mux", "ADCDAT1", "IF1_ADC Mux"},
+	{"AIF1TX", NULL, "ADCDAT Mux"},
+	{"IF2 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF2 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF2 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF2 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+	{"ADCDAT Mux", "ADCDAT2", "IF2 ADC Swap Mux"},
+	{"AIF2TX", NULL, "ADCDAT Mux"},
+
+	{"IF1 DAC1 L", NULL, "AIF1RX"},
+	{"IF1 DAC1 L", NULL, "I2S1"},
+	{"IF1 DAC1 L", NULL, "DAC Stereo1 Filter"},
+	{"IF1 DAC1 R", NULL, "AIF1RX"},
+	{"IF1 DAC1 R", NULL, "I2S1"},
+	{"IF1 DAC1 R", NULL, "DAC Stereo1 Filter"},
+
+	{"DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"},
+	{"DAC1 MIXL", "DAC1 Switch", "IF1 DAC1 L"},
+	{"DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"},
+	{"DAC1 MIXR", "DAC1 Switch", "IF1 DAC1 R"},
+
+	{"Stereo1 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"},
+	{"Stereo1 DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"},
+
+	{"Stereo1 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"},
+	{"Stereo1 DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"},
+
+	{"DAC L1 Source", "DAC1", "DAC1 MIXL"},
+	{"DAC L1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"},
+	{"DAC R1 Source", "DAC1", "DAC1 MIXR"},
+	{"DAC R1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"},
+
+	{"DAC L1", NULL, "DAC L1 Source"},
+	{"DAC R1", NULL, "DAC R1 Source"},
+
+	{"DAC L1", NULL, "DAC 1 Clock"},
+	{"DAC R1", NULL, "DAC 1 Clock"},
+
+	{"HP Amp", NULL, "DAC L1"},
+	{"HP Amp", NULL, "DAC R1"},
+	{"HP Amp", NULL, "HP Amp L"},
+	{"HP Amp", NULL, "HP Amp R"},
+	{"HP Amp", NULL, "Capless"},
+	{"HP Amp", NULL, "Charge Pump"},
+	{"HP Amp", NULL, "CLKDET SYS"},
+	{"HP Amp", NULL, "CBJ Power"},
+	{"HP Amp", NULL, "Vref2"},
+	{"HPOL Playback", "Switch", "HP Amp"},
+	{"HPOR Playback", "Switch", "HP Amp"},
+	{"HPOL", NULL, "HPOL Playback"},
+	{"HPOR", NULL, "HPOR Playback"},
+};
+
+static int rt5668_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int val = 0;
+
+	switch (slots) {
+	case 4:
+		val |= RT5668_TDM_TX_CH_4;
+		val |= RT5668_TDM_RX_CH_4;
+		break;
+	case 6:
+		val |= RT5668_TDM_TX_CH_6;
+		val |= RT5668_TDM_RX_CH_6;
+		break;
+	case 8:
+		val |= RT5668_TDM_TX_CH_8;
+		val |= RT5668_TDM_RX_CH_8;
+		break;
+	case 2:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5668_TDM_CTRL,
+		RT5668_TDM_TX_CH_MASK | RT5668_TDM_RX_CH_MASK, val);
+
+	switch (slot_width) {
+	case 16:
+		val = RT5668_TDM_CL_16;
+		break;
+	case 20:
+		val = RT5668_TDM_CL_20;
+		break;
+	case 24:
+		val = RT5668_TDM_CL_24;
+		break;
+	case 32:
+		val = RT5668_TDM_CL_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5668_TDM_TCON_CTRL,
+		RT5668_TDM_CL_MASK, val);
+
+	return 0;
+}
+
+
+static int rt5668_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+	unsigned int len_1 = 0, len_2 = 0;
+	int pre_div, frame_size;
+
+	rt5668->lrck[dai->id] = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5668->sysclk, rt5668->lrck[dai->id]);
+
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n",
+			frame_size);
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+				rt5668->lrck[dai->id], pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		len_1 |= RT5668_I2S1_DL_20;
+		len_2 |= RT5668_I2S2_DL_20;
+		break;
+	case 24:
+		len_1 |= RT5668_I2S1_DL_24;
+		len_2 |= RT5668_I2S2_DL_24;
+		break;
+	case 32:
+		len_1 |= RT5668_I2S1_DL_32;
+		len_2 |= RT5668_I2S2_DL_24;
+		break;
+	case 8:
+		len_1 |= RT5668_I2S2_DL_8;
+		len_2 |= RT5668_I2S2_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5668_AIF1:
+		snd_soc_component_update_bits(component, RT5668_I2S1_SDP,
+			RT5668_I2S1_DL_MASK, len_1);
+		if (rt5668->master[RT5668_AIF1]) {
+			snd_soc_component_update_bits(component,
+				RT5668_ADDA_CLK_1, RT5668_I2S_M_DIV_MASK,
+				pre_div << RT5668_I2S_M_DIV_SFT);
+		}
+		if (params_channels(params) == 1) /* mono mode */
+			snd_soc_component_update_bits(component,
+				RT5668_I2S1_SDP, RT5668_I2S1_MONO_MASK,
+				RT5668_I2S1_MONO_EN);
+		else
+			snd_soc_component_update_bits(component,
+				RT5668_I2S1_SDP, RT5668_I2S1_MONO_MASK,
+				RT5668_I2S1_MONO_DIS);
+		break;
+	case RT5668_AIF2:
+		snd_soc_component_update_bits(component, RT5668_I2S2_SDP,
+			RT5668_I2S2_DL_MASK, len_2);
+		if (rt5668->master[RT5668_AIF2]) {
+			snd_soc_component_update_bits(component,
+				RT5668_I2S_M_CLK_CTRL_1, RT5668_I2S2_M_PD_MASK,
+				pre_div << RT5668_I2S2_M_PD_SFT);
+		}
+		if (params_channels(params) == 1) /* mono mode */
+			snd_soc_component_update_bits(component,
+				RT5668_I2S2_SDP, RT5668_I2S2_MONO_MASK,
+				RT5668_I2S2_MONO_EN);
+		else
+			snd_soc_component_update_bits(component,
+				RT5668_I2S2_SDP, RT5668_I2S2_MONO_MASK,
+				RT5668_I2S2_MONO_DIS);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5668_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0, tdm_ctrl = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5668->master[dai->id] = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		rt5668->master[dai->id] = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5668_I2S_BP_INV;
+		tdm_ctrl |= RT5668_TDM_S_BP_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		if (dai->id == RT5668_AIF1)
+			tdm_ctrl |= RT5668_TDM_S_LP_INV | RT5668_TDM_M_BP_INV;
+		else
+			return -EINVAL;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		if (dai->id == RT5668_AIF1)
+			tdm_ctrl |= RT5668_TDM_S_BP_INV | RT5668_TDM_S_LP_INV |
+				    RT5668_TDM_M_BP_INV | RT5668_TDM_M_LP_INV;
+		else
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5668_I2S_DF_LEFT;
+		tdm_ctrl |= RT5668_TDM_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5668_I2S_DF_PCM_A;
+		tdm_ctrl |= RT5668_TDM_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5668_I2S_DF_PCM_B;
+		tdm_ctrl |= RT5668_TDM_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5668_AIF1:
+		snd_soc_component_update_bits(component, RT5668_I2S1_SDP,
+			RT5668_I2S_DF_MASK, reg_val);
+		snd_soc_component_update_bits(component, RT5668_TDM_TCON_CTRL,
+			RT5668_TDM_MS_MASK | RT5668_TDM_S_BP_MASK |
+			RT5668_TDM_DF_MASK | RT5668_TDM_M_BP_MASK |
+			RT5668_TDM_M_LP_MASK | RT5668_TDM_S_LP_MASK,
+			tdm_ctrl | rt5668->master[dai->id]);
+		break;
+	case RT5668_AIF2:
+		if (rt5668->master[dai->id] == 0)
+			reg_val |= RT5668_I2S2_MS_S;
+		snd_soc_component_update_bits(component, RT5668_I2S2_SDP,
+			RT5668_I2S2_MS_MASK | RT5668_I2S_BP_MASK |
+			RT5668_I2S_DF_MASK, reg_val);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int rt5668_set_component_sysclk(struct snd_soc_component *component,
+		int clk_id, int source, unsigned int freq, int dir)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0, src = 0;
+
+	if (freq == rt5668->sysclk && clk_id == rt5668->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5668_SCLK_S_MCLK:
+		reg_val |= RT5668_SCLK_SRC_MCLK;
+		src = RT5668_CLK_SRC_MCLK;
+		break;
+	case RT5668_SCLK_S_PLL1:
+		reg_val |= RT5668_SCLK_SRC_PLL1;
+		src = RT5668_CLK_SRC_PLL1;
+		break;
+	case RT5668_SCLK_S_PLL2:
+		reg_val |= RT5668_SCLK_SRC_PLL2;
+		src = RT5668_CLK_SRC_PLL2;
+		break;
+	case RT5668_SCLK_S_RCCLK:
+		reg_val |= RT5668_SCLK_SRC_RCCLK;
+		src = RT5668_CLK_SRC_RCCLK;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, RT5668_GLB_CLK,
+		RT5668_SCLK_SRC_MASK, reg_val);
+
+	if (rt5668->master[RT5668_AIF2]) {
+		snd_soc_component_update_bits(component,
+			RT5668_I2S_M_CLK_CTRL_1, RT5668_I2S2_SRC_MASK,
+			src << RT5668_I2S2_SRC_SFT);
+	}
+
+	rt5668->sysclk = freq;
+	rt5668->sysclk_src = clk_id;
+
+	dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n",
+		freq, clk_id);
+
+	return 0;
+}
+
+static int rt5668_set_component_pll(struct snd_soc_component *component,
+		int pll_id, int source, unsigned int freq_in,
+		unsigned int freq_out)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5668->pll_src && freq_in == rt5668->pll_in &&
+	    freq_out == rt5668->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt5668->pll_in = 0;
+		rt5668->pll_out = 0;
+		snd_soc_component_update_bits(component, RT5668_GLB_CLK,
+			RT5668_SCLK_SRC_MASK, RT5668_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5668_PLL1_S_MCLK:
+		snd_soc_component_update_bits(component, RT5668_GLB_CLK,
+			RT5668_PLL1_SRC_MASK, RT5668_PLL1_SRC_MCLK);
+		break;
+	case RT5668_PLL1_S_BCLK1:
+		snd_soc_component_update_bits(component, RT5668_GLB_CLK,
+				RT5668_PLL1_SRC_MASK, RT5668_PLL1_SRC_BCLK1);
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL Source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_component_write(component, RT5668_PLL_CTRL_1,
+		pll_code.n_code << RT5668_PLL_N_SFT | pll_code.k_code);
+	snd_soc_component_write(component, RT5668_PLL_CTRL_2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5668_PLL_M_SFT |
+		pll_code.m_bp << RT5668_PLL_M_BP_SFT);
+
+	rt5668->pll_in = freq_in;
+	rt5668->pll_out = freq_out;
+	rt5668->pll_src = source;
+
+	return 0;
+}
+
+static int rt5668_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+
+	rt5668->bclk[dai->id] = ratio;
+
+	switch (ratio) {
+	case 64:
+		snd_soc_component_update_bits(component, RT5668_ADDA_CLK_2,
+			RT5668_I2S2_BCLK_MS2_MASK,
+			RT5668_I2S2_BCLK_MS2_64);
+		break;
+	case 32:
+		snd_soc_component_update_bits(component, RT5668_ADDA_CLK_2,
+			RT5668_I2S2_BCLK_MS2_MASK,
+			RT5668_I2S2_BCLK_MS2_32);
+		break;
+	default:
+		dev_err(dai->dev, "Invalid bclk ratio %d\n", ratio);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5668_set_bias_level(struct snd_soc_component *component,
+			enum snd_soc_bias_level level)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		regmap_update_bits(rt5668->regmap, RT5668_PWR_ANLG_1,
+			RT5668_PWR_MB | RT5668_PWR_BG,
+			RT5668_PWR_MB | RT5668_PWR_BG);
+		regmap_update_bits(rt5668->regmap, RT5668_PWR_DIG_1,
+			RT5668_DIG_GATE_CTRL | RT5668_PWR_LDO,
+			RT5668_DIG_GATE_CTRL | RT5668_PWR_LDO);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		regmap_update_bits(rt5668->regmap, RT5668_PWR_ANLG_1,
+			RT5668_PWR_MB, RT5668_PWR_MB);
+		regmap_update_bits(rt5668->regmap, RT5668_PWR_DIG_1,
+			RT5668_DIG_GATE_CTRL, RT5668_DIG_GATE_CTRL);
+		break;
+	case SND_SOC_BIAS_OFF:
+		regmap_update_bits(rt5668->regmap, RT5668_PWR_DIG_1,
+			RT5668_DIG_GATE_CTRL | RT5668_PWR_LDO, 0);
+		regmap_update_bits(rt5668->regmap, RT5668_PWR_ANLG_1,
+			RT5668_PWR_MB | RT5668_PWR_BG, 0);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5668_probe(struct snd_soc_component *component)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+
+	rt5668->component = component;
+
+	return 0;
+}
+
+static void rt5668_remove(struct snd_soc_component *component)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+
+	rt5668_reset(rt5668->regmap);
+}
+
+#ifdef CONFIG_PM
+static int rt5668_suspend(struct snd_soc_component *component)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5668->regmap, true);
+	regcache_mark_dirty(rt5668->regmap);
+	return 0;
+}
+
+static int rt5668_resume(struct snd_soc_component *component)
+{
+	struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5668->regmap, false);
+	regcache_sync(rt5668->regmap);
+
+	return 0;
+}
+#else
+#define rt5668_suspend NULL
+#define rt5668_resume NULL
+#endif
+
+#define RT5668_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5668_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5668_aif1_dai_ops = {
+	.hw_params = rt5668_hw_params,
+	.set_fmt = rt5668_set_dai_fmt,
+	.set_tdm_slot = rt5668_set_tdm_slot,
+};
+
+static const struct snd_soc_dai_ops rt5668_aif2_dai_ops = {
+	.hw_params = rt5668_hw_params,
+	.set_fmt = rt5668_set_dai_fmt,
+	.set_bclk_ratio = rt5668_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt5668_dai[] = {
+	{
+		.name = "rt5668-aif1",
+		.id = RT5668_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5668_STEREO_RATES,
+			.formats = RT5668_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5668_STEREO_RATES,
+			.formats = RT5668_FORMATS,
+		},
+		.ops = &rt5668_aif1_dai_ops,
+	},
+	{
+		.name = "rt5668-aif2",
+		.id = RT5668_AIF2,
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5668_STEREO_RATES,
+			.formats = RT5668_FORMATS,
+		},
+		.ops = &rt5668_aif2_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5668 = {
+	.probe = rt5668_probe,
+	.remove = rt5668_remove,
+	.suspend = rt5668_suspend,
+	.resume = rt5668_resume,
+	.set_bias_level = rt5668_set_bias_level,
+	.controls = rt5668_snd_controls,
+	.num_controls = ARRAY_SIZE(rt5668_snd_controls),
+	.dapm_widgets = rt5668_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rt5668_dapm_widgets),
+	.dapm_routes = rt5668_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(rt5668_dapm_routes),
+	.set_sysclk = rt5668_set_component_sysclk,
+	.set_pll = rt5668_set_component_pll,
+	.set_jack = rt5668_set_jack_detect,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt5668_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+	.max_register = RT5668_I2C_MODE,
+	.volatile_reg = rt5668_volatile_register,
+	.readable_reg = rt5668_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5668_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5668_reg),
+	.use_single_rw = true,
+};
+
+static const struct i2c_device_id rt5668_i2c_id[] = {
+	{"rt5668b", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, rt5668_i2c_id);
+
+static int rt5668_parse_dt(struct rt5668_priv *rt5668, struct device *dev)
+{
+
+	of_property_read_u32(dev->of_node, "realtek,dmic1-data-pin",
+		&rt5668->pdata.dmic1_data_pin);
+	of_property_read_u32(dev->of_node, "realtek,dmic1-clk-pin",
+		&rt5668->pdata.dmic1_clk_pin);
+	of_property_read_u32(dev->of_node, "realtek,jd-src",
+		&rt5668->pdata.jd_src);
+
+	rt5668->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
+		"realtek,ldo1-en-gpios", 0);
+
+	return 0;
+}
+
+static void rt5668_calibrate(struct rt5668_priv *rt5668)
+{
+	int value, count;
+
+	mutex_lock(&rt5668->calibrate_mutex);
+
+	rt5668_reset(rt5668->regmap);
+	regmap_write(rt5668->regmap, RT5668_PWR_ANLG_1, 0xa2bf);
+	usleep_range(15000, 20000);
+	regmap_write(rt5668->regmap, RT5668_PWR_ANLG_1, 0xf2bf);
+	regmap_write(rt5668->regmap, RT5668_MICBIAS_2, 0x0380);
+	regmap_write(rt5668->regmap, RT5668_PWR_DIG_1, 0x8001);
+	regmap_write(rt5668->regmap, RT5668_TEST_MODE_CTRL_1, 0x0000);
+	regmap_write(rt5668->regmap, RT5668_STO1_DAC_MIXER, 0x2080);
+	regmap_write(rt5668->regmap, RT5668_STO1_ADC_MIXER, 0x4040);
+	regmap_write(rt5668->regmap, RT5668_DEPOP_1, 0x0069);
+	regmap_write(rt5668->regmap, RT5668_CHOP_DAC, 0x3000);
+	regmap_write(rt5668->regmap, RT5668_HP_CTRL_2, 0x6000);
+	regmap_write(rt5668->regmap, RT5668_HP_CHARGE_PUMP_1, 0x0f26);
+	regmap_write(rt5668->regmap, RT5668_CALIB_ADC_CTRL, 0x7f05);
+	regmap_write(rt5668->regmap, RT5668_STO1_ADC_MIXER, 0x686c);
+	regmap_write(rt5668->regmap, RT5668_CAL_REC, 0x0d0d);
+	regmap_write(rt5668->regmap, RT5668_HP_CALIB_CTRL_9, 0x000f);
+	regmap_write(rt5668->regmap, RT5668_PWR_DIG_1, 0x8d01);
+	regmap_write(rt5668->regmap, RT5668_HP_CALIB_CTRL_2, 0x0321);
+	regmap_write(rt5668->regmap, RT5668_HP_LOGIC_CTRL_2, 0x0004);
+	regmap_write(rt5668->regmap, RT5668_HP_CALIB_CTRL_1, 0x7c00);
+	regmap_write(rt5668->regmap, RT5668_HP_CALIB_CTRL_3, 0x06a1);
+	regmap_write(rt5668->regmap, RT5668_A_DAC1_MUX, 0x0311);
+	regmap_write(rt5668->regmap, RT5668_RESET_HPF_CTRL, 0x0000);
+	regmap_write(rt5668->regmap, RT5668_ADC_STO1_HP_CTRL_1, 0x3320);
+
+	regmap_write(rt5668->regmap, RT5668_HP_CALIB_CTRL_1, 0xfc00);
+
+	for (count = 0; count < 60; count++) {
+		regmap_read(rt5668->regmap, RT5668_HP_CALIB_STA_1, &value);
+		if (!(value & 0x8000))
+			break;
+
+		usleep_range(10000, 10005);
+	}
+
+	if (count >= 60)
+		pr_err("HP Calibration Failure\n");
+
+	/* restore settings */
+	regmap_write(rt5668->regmap, RT5668_STO1_ADC_MIXER, 0xc0c4);
+	regmap_write(rt5668->regmap, RT5668_PWR_DIG_1, 0x0000);
+
+	mutex_unlock(&rt5668->calibrate_mutex);
+
+}
+
+static int rt5668_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5668_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt5668_priv *rt5668;
+	int i, ret;
+	unsigned int val;
+
+	rt5668 = devm_kzalloc(&i2c->dev, sizeof(struct rt5668_priv),
+		GFP_KERNEL);
+
+	if (rt5668 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt5668);
+
+	if (pdata)
+		rt5668->pdata = *pdata;
+	else
+		rt5668_parse_dt(rt5668, &i2c->dev);
+
+	rt5668->regmap = devm_regmap_init_i2c(i2c, &rt5668_regmap);
+	if (IS_ERR(rt5668->regmap)) {
+		ret = PTR_ERR(rt5668->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(rt5668->supplies); i++)
+		rt5668->supplies[i].supply = rt5668_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5668->supplies),
+				      rt5668->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(rt5668->supplies),
+				    rt5668->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	if (gpio_is_valid(rt5668->pdata.ldo1_en)) {
+		if (devm_gpio_request_one(&i2c->dev, rt5668->pdata.ldo1_en,
+					  GPIOF_OUT_INIT_HIGH, "rt5668"))
+			dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+	}
+
+	/* Sleep for 300 ms miniumum */
+	usleep_range(300000, 350000);
+
+	regmap_write(rt5668->regmap, RT5668_I2C_MODE, 0x1);
+	usleep_range(10000, 15000);
+
+	regmap_read(rt5668->regmap, RT5668_DEVICE_ID, &val);
+	if (val != DEVICE_ID) {
+		pr_err("Device with ID register %x is not rt5668\n", val);
+		return -ENODEV;
+	}
+
+	rt5668_reset(rt5668->regmap);
+
+	rt5668_calibrate(rt5668);
+
+	regmap_write(rt5668->regmap, RT5668_DEPOP_1, 0x0000);
+
+	/* DMIC pin*/
+	if (rt5668->pdata.dmic1_data_pin != RT5668_DMIC1_NULL) {
+		switch (rt5668->pdata.dmic1_data_pin) {
+		case RT5668_DMIC1_DATA_GPIO2: /* share with LRCK2 */
+			regmap_update_bits(rt5668->regmap, RT5668_DMIC_CTRL_1,
+				RT5668_DMIC_1_DP_MASK, RT5668_DMIC_1_DP_GPIO2);
+			regmap_update_bits(rt5668->regmap, RT5668_GPIO_CTRL_1,
+				RT5668_GP2_PIN_MASK, RT5668_GP2_PIN_DMIC_SDA);
+			break;
+
+		case RT5668_DMIC1_DATA_GPIO5: /* share with DACDAT1 */
+			regmap_update_bits(rt5668->regmap, RT5668_DMIC_CTRL_1,
+				RT5668_DMIC_1_DP_MASK, RT5668_DMIC_1_DP_GPIO5);
+			regmap_update_bits(rt5668->regmap, RT5668_GPIO_CTRL_1,
+				RT5668_GP5_PIN_MASK, RT5668_GP5_PIN_DMIC_SDA);
+			break;
+
+		default:
+			dev_dbg(&i2c->dev, "invalid DMIC_DAT pin\n");
+			break;
+		}
+
+		switch (rt5668->pdata.dmic1_clk_pin) {
+		case RT5668_DMIC1_CLK_GPIO1: /* share with IRQ */
+			regmap_update_bits(rt5668->regmap, RT5668_GPIO_CTRL_1,
+				RT5668_GP1_PIN_MASK, RT5668_GP1_PIN_DMIC_CLK);
+			break;
+
+		case RT5668_DMIC1_CLK_GPIO3: /* share with BCLK2 */
+			regmap_update_bits(rt5668->regmap, RT5668_GPIO_CTRL_1,
+				RT5668_GP3_PIN_MASK, RT5668_GP3_PIN_DMIC_CLK);
+			break;
+
+		default:
+			dev_dbg(&i2c->dev, "invalid DMIC_CLK pin\n");
+			break;
+		}
+	}
+
+	regmap_update_bits(rt5668->regmap, RT5668_PWR_ANLG_1,
+			RT5668_LDO1_DVO_MASK | RT5668_HP_DRIVER_MASK,
+			RT5668_LDO1_DVO_14 | RT5668_HP_DRIVER_5X);
+	regmap_write(rt5668->regmap, RT5668_MICBIAS_2, 0x0380);
+	regmap_update_bits(rt5668->regmap, RT5668_GPIO_CTRL_1,
+			RT5668_GP4_PIN_MASK | RT5668_GP5_PIN_MASK,
+			RT5668_GP4_PIN_ADCDAT1 | RT5668_GP5_PIN_DACDAT1);
+	regmap_write(rt5668->regmap, RT5668_TEST_MODE_CTRL_1, 0x0000);
+
+	INIT_DELAYED_WORK(&rt5668->jack_detect_work,
+				rt5668_jack_detect_handler);
+	INIT_DELAYED_WORK(&rt5668->jd_check_work,
+				rt5668_jd_check_handler);
+
+	mutex_init(&rt5668->calibrate_mutex);
+
+	if (i2c->irq) {
+		ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+			rt5668_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+			| IRQF_ONESHOT, "rt5668", rt5668);
+		if (ret)
+			dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+
+	}
+
+	return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668,
+			rt5668_dai, ARRAY_SIZE(rt5668_dai));
+}
+
+static int rt5668_i2c_remove(struct i2c_client *i2c)
+{
+	snd_soc_unregister_component(&i2c->dev);
+
+	return 0;
+}
+
+static void rt5668_i2c_shutdown(struct i2c_client *client)
+{
+	struct rt5668_priv *rt5668 = i2c_get_clientdata(client);
+
+	rt5668_reset(rt5668->regmap);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt5668_of_match[] = {
+	{.compatible = "realtek,rt5668b"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5668_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5668_acpi_match[] = {
+	{"10EC5668", 0,},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, rt5668_acpi_match);
+#endif
+
+static struct i2c_driver rt5668_i2c_driver = {
+	.driver = {
+		.name = "rt5668b",
+		.of_match_table = of_match_ptr(rt5668_of_match),
+		.acpi_match_table = ACPI_PTR(rt5668_acpi_match),
+	},
+	.probe = rt5668_i2c_probe,
+	.remove = rt5668_i2c_remove,
+	.shutdown = rt5668_i2c_shutdown,
+	.id_table = rt5668_i2c_id,
+};
+module_i2c_driver(rt5668_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5668B driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5668.h b/sound/soc/codecs/rt5668.h
new file mode 100644
index 0000000..3e7bcfd
--- /dev/null
+++ b/sound/soc/codecs/rt5668.h
@@ -0,0 +1,1318 @@
+/*
+ * rt5668.h  --  RT5668/RT5658 ALSA SoC audio driver
+ *
+ * Copyright 2018 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5668_H__
+#define __RT5668_H__
+
+#include <sound/rt5668.h>
+
+#define DEVICE_ID 0x6530
+
+/* Info */
+#define RT5668_RESET				0x0000
+#define RT5668_VERSION_ID			0x00fd
+#define RT5668_VENDOR_ID			0x00fe
+#define RT5668_DEVICE_ID			0x00ff
+/*  I/O - Output */
+#define RT5668_HP_CTRL_1			0x0002
+#define RT5668_HP_CTRL_2			0x0003
+#define RT5668_HPL_GAIN				0x0005
+#define RT5668_HPR_GAIN				0x0006
+
+#define RT5668_I2C_CTRL				0x0008
+
+/* I/O - Input */
+#define RT5668_CBJ_BST_CTRL			0x000b
+#define RT5668_CBJ_CTRL_1			0x0010
+#define RT5668_CBJ_CTRL_2			0x0011
+#define RT5668_CBJ_CTRL_3			0x0012
+#define RT5668_CBJ_CTRL_4			0x0013
+#define RT5668_CBJ_CTRL_5			0x0014
+#define RT5668_CBJ_CTRL_6			0x0015
+#define RT5668_CBJ_CTRL_7			0x0016
+/* I/O - ADC/DAC/DMIC */
+#define RT5668_DAC1_DIG_VOL			0x0019
+#define RT5668_STO1_ADC_DIG_VOL			0x001c
+#define RT5668_STO1_ADC_BOOST			0x001f
+#define RT5668_HP_IMP_GAIN_1			0x0022
+#define RT5668_HP_IMP_GAIN_2			0x0023
+/* Mixer - D-D */
+#define RT5668_SIDETONE_CTRL			0x0024
+#define RT5668_STO1_ADC_MIXER			0x0026
+#define RT5668_AD_DA_MIXER			0x0029
+#define RT5668_STO1_DAC_MIXER			0x002a
+#define RT5668_A_DAC1_MUX			0x002b
+#define RT5668_DIG_INF2_DATA			0x0030
+/* Mixer - ADC */
+#define RT5668_REC_MIXER			0x003c
+#define RT5668_CAL_REC				0x0044
+#define RT5668_ALC_BACK_GAIN			0x0049
+/* Power */
+#define RT5668_PWR_DIG_1			0x0061
+#define RT5668_PWR_DIG_2			0x0062
+#define RT5668_PWR_ANLG_1			0x0063
+#define RT5668_PWR_ANLG_2			0x0064
+#define RT5668_PWR_ANLG_3			0x0065
+#define RT5668_PWR_MIXER			0x0066
+#define RT5668_PWR_VOL				0x0067
+/* Clock Detect */
+#define RT5668_CLK_DET				0x006b
+/* Filter Auto Reset */
+#define RT5668_RESET_LPF_CTRL			0x006c
+#define RT5668_RESET_HPF_CTRL			0x006d
+/* DMIC */
+#define RT5668_DMIC_CTRL_1			0x006e
+/* Format - ADC/DAC */
+#define RT5668_I2S1_SDP				0x0070
+#define RT5668_I2S2_SDP				0x0071
+#define RT5668_ADDA_CLK_1			0x0073
+#define RT5668_ADDA_CLK_2			0x0074
+#define RT5668_I2S1_F_DIV_CTRL_1		0x0075
+#define RT5668_I2S1_F_DIV_CTRL_2		0x0076
+/* Format - TDM Control */
+#define RT5668_TDM_CTRL				0x0079
+#define RT5668_TDM_ADDA_CTRL_1			0x007a
+#define RT5668_TDM_ADDA_CTRL_2			0x007b
+#define RT5668_DATA_SEL_CTRL_1			0x007c
+#define RT5668_TDM_TCON_CTRL			0x007e
+/* Function - Analog */
+#define RT5668_GLB_CLK				0x0080
+#define RT5668_PLL_CTRL_1			0x0081
+#define RT5668_PLL_CTRL_2			0x0082
+#define RT5668_PLL_TRACK_1			0x0083
+#define RT5668_PLL_TRACK_2			0x0084
+#define RT5668_PLL_TRACK_3			0x0085
+#define RT5668_PLL_TRACK_4			0x0086
+#define RT5668_PLL_TRACK_5			0x0087
+#define RT5668_PLL_TRACK_6			0x0088
+#define RT5668_PLL_TRACK_11			0x008c
+#define RT5668_SDW_REF_CLK			0x008d
+#define RT5668_DEPOP_1				0x008e
+#define RT5668_DEPOP_2				0x008f
+#define RT5668_HP_CHARGE_PUMP_1			0x0091
+#define RT5668_HP_CHARGE_PUMP_2			0x0092
+#define RT5668_MICBIAS_1			0x0093
+#define RT5668_MICBIAS_2			0x0094
+#define RT5668_PLL_TRACK_12			0x0098
+#define RT5668_PLL_TRACK_14			0x009a
+#define RT5668_PLL2_CTRL_1			0x009b
+#define RT5668_PLL2_CTRL_2			0x009c
+#define RT5668_PLL2_CTRL_3			0x009d
+#define RT5668_PLL2_CTRL_4			0x009e
+#define RT5668_RC_CLK_CTRL			0x009f
+#define RT5668_I2S_M_CLK_CTRL_1			0x00a0
+#define RT5668_I2S2_F_DIV_CTRL_1		0x00a3
+#define RT5668_I2S2_F_DIV_CTRL_2		0x00a4
+/* Function - Digital */
+#define RT5668_EQ_CTRL_1			0x00ae
+#define RT5668_EQ_CTRL_2			0x00af
+#define RT5668_IRQ_CTRL_1			0x00b6
+#define RT5668_IRQ_CTRL_2			0x00b7
+#define RT5668_IRQ_CTRL_3			0x00b8
+#define RT5668_IRQ_CTRL_4			0x00b9
+#define RT5668_INT_ST_1				0x00be
+#define RT5668_GPIO_CTRL_1			0x00c0
+#define RT5668_GPIO_CTRL_2			0x00c1
+#define RT5668_GPIO_CTRL_3			0x00c2
+#define RT5668_HP_AMP_DET_CTRL_1		0x00d0
+#define RT5668_HP_AMP_DET_CTRL_2		0x00d1
+#define RT5668_MID_HP_AMP_DET			0x00d2
+#define RT5668_LOW_HP_AMP_DET			0x00d3
+#define RT5668_DELAY_BUF_CTRL			0x00d4
+#define RT5668_SV_ZCD_1				0x00d9
+#define RT5668_SV_ZCD_2				0x00da
+#define RT5668_IL_CMD_1				0x00db
+#define RT5668_IL_CMD_2				0x00dc
+#define RT5668_IL_CMD_3				0x00dd
+#define RT5668_IL_CMD_4				0x00de
+#define RT5668_IL_CMD_5				0x00df
+#define RT5668_IL_CMD_6				0x00e0
+#define RT5668_4BTN_IL_CMD_1			0x00e2
+#define RT5668_4BTN_IL_CMD_2			0x00e3
+#define RT5668_4BTN_IL_CMD_3			0x00e4
+#define RT5668_4BTN_IL_CMD_4			0x00e5
+#define RT5668_4BTN_IL_CMD_5			0x00e6
+#define RT5668_4BTN_IL_CMD_6			0x00e7
+#define RT5668_4BTN_IL_CMD_7			0x00e8
+
+#define RT5668_ADC_STO1_HP_CTRL_1		0x00ea
+#define RT5668_ADC_STO1_HP_CTRL_2		0x00eb
+#define RT5668_AJD1_CTRL			0x00f0
+#define RT5668_JD1_THD				0x00f1
+#define RT5668_JD2_THD				0x00f2
+#define RT5668_JD_CTRL_1			0x00f6
+/* General Control */
+#define RT5668_DUMMY_1				0x00fa
+#define RT5668_DUMMY_2				0x00fb
+#define RT5668_DUMMY_3				0x00fc
+
+#define RT5668_DAC_ADC_DIG_VOL1			0x0100
+#define RT5668_BIAS_CUR_CTRL_2			0x010b
+#define RT5668_BIAS_CUR_CTRL_3			0x010c
+#define RT5668_BIAS_CUR_CTRL_4			0x010d
+#define RT5668_BIAS_CUR_CTRL_5			0x010e
+#define RT5668_BIAS_CUR_CTRL_6			0x010f
+#define RT5668_BIAS_CUR_CTRL_7			0x0110
+#define RT5668_BIAS_CUR_CTRL_8			0x0111
+#define RT5668_BIAS_CUR_CTRL_9			0x0112
+#define RT5668_BIAS_CUR_CTRL_10			0x0113
+#define RT5668_VREF_REC_OP_FB_CAP_CTRL		0x0117
+#define RT5668_CHARGE_PUMP_1			0x0125
+#define RT5668_DIG_IN_CTRL_1			0x0132
+#define RT5668_PAD_DRIVING_CTRL			0x0136
+#define RT5668_SOFT_RAMP_DEPOP			0x0138
+#define RT5668_CHOP_DAC				0x013a
+#define RT5668_CHOP_ADC				0x013b
+#define RT5668_CALIB_ADC_CTRL			0x013c
+#define RT5668_VOL_TEST				0x013f
+#define RT5668_SPKVDD_DET_STA			0x0142
+#define RT5668_TEST_MODE_CTRL_1			0x0145
+#define RT5668_TEST_MODE_CTRL_2			0x0146
+#define RT5668_TEST_MODE_CTRL_3			0x0147
+#define RT5668_TEST_MODE_CTRL_4			0x0148
+#define RT5668_TEST_MODE_CTRL_5			0x0149
+#define RT5668_PLL1_INTERNAL			0x0150
+#define RT5668_PLL2_INTERNAL			0x0151
+#define RT5668_STO_NG2_CTRL_1			0x0160
+#define RT5668_STO_NG2_CTRL_2			0x0161
+#define RT5668_STO_NG2_CTRL_3			0x0162
+#define RT5668_STO_NG2_CTRL_4			0x0163
+#define RT5668_STO_NG2_CTRL_5			0x0164
+#define RT5668_STO_NG2_CTRL_6			0x0165
+#define RT5668_STO_NG2_CTRL_7			0x0166
+#define RT5668_STO_NG2_CTRL_8			0x0167
+#define RT5668_STO_NG2_CTRL_9			0x0168
+#define RT5668_STO_NG2_CTRL_10			0x0169
+#define RT5668_STO1_DAC_SIL_DET			0x0190
+#define RT5668_SIL_PSV_CTRL1			0x0194
+#define RT5668_SIL_PSV_CTRL2			0x0195
+#define RT5668_SIL_PSV_CTRL3			0x0197
+#define RT5668_SIL_PSV_CTRL4			0x0198
+#define RT5668_SIL_PSV_CTRL5			0x0199
+#define RT5668_HP_IMP_SENS_CTRL_01		0x01af
+#define RT5668_HP_IMP_SENS_CTRL_02		0x01b0
+#define RT5668_HP_IMP_SENS_CTRL_03		0x01b1
+#define RT5668_HP_IMP_SENS_CTRL_04		0x01b2
+#define RT5668_HP_IMP_SENS_CTRL_05		0x01b3
+#define RT5668_HP_IMP_SENS_CTRL_06		0x01b4
+#define RT5668_HP_IMP_SENS_CTRL_07		0x01b5
+#define RT5668_HP_IMP_SENS_CTRL_08		0x01b6
+#define RT5668_HP_IMP_SENS_CTRL_09		0x01b7
+#define RT5668_HP_IMP_SENS_CTRL_10		0x01b8
+#define RT5668_HP_IMP_SENS_CTRL_11		0x01b9
+#define RT5668_HP_IMP_SENS_CTRL_12		0x01ba
+#define RT5668_HP_IMP_SENS_CTRL_13		0x01bb
+#define RT5668_HP_IMP_SENS_CTRL_14		0x01bc
+#define RT5668_HP_IMP_SENS_CTRL_15		0x01bd
+#define RT5668_HP_IMP_SENS_CTRL_16		0x01be
+#define RT5668_HP_IMP_SENS_CTRL_17		0x01bf
+#define RT5668_HP_IMP_SENS_CTRL_18		0x01c0
+#define RT5668_HP_IMP_SENS_CTRL_19		0x01c1
+#define RT5668_HP_IMP_SENS_CTRL_20		0x01c2
+#define RT5668_HP_IMP_SENS_CTRL_21		0x01c3
+#define RT5668_HP_IMP_SENS_CTRL_22		0x01c4
+#define RT5668_HP_IMP_SENS_CTRL_23		0x01c5
+#define RT5668_HP_IMP_SENS_CTRL_24		0x01c6
+#define RT5668_HP_IMP_SENS_CTRL_25		0x01c7
+#define RT5668_HP_IMP_SENS_CTRL_26		0x01c8
+#define RT5668_HP_IMP_SENS_CTRL_27		0x01c9
+#define RT5668_HP_IMP_SENS_CTRL_28		0x01ca
+#define RT5668_HP_IMP_SENS_CTRL_29		0x01cb
+#define RT5668_HP_IMP_SENS_CTRL_30		0x01cc
+#define RT5668_HP_IMP_SENS_CTRL_31		0x01cd
+#define RT5668_HP_IMP_SENS_CTRL_32		0x01ce
+#define RT5668_HP_IMP_SENS_CTRL_33		0x01cf
+#define RT5668_HP_IMP_SENS_CTRL_34		0x01d0
+#define RT5668_HP_IMP_SENS_CTRL_35		0x01d1
+#define RT5668_HP_IMP_SENS_CTRL_36		0x01d2
+#define RT5668_HP_IMP_SENS_CTRL_37		0x01d3
+#define RT5668_HP_IMP_SENS_CTRL_38		0x01d4
+#define RT5668_HP_IMP_SENS_CTRL_39		0x01d5
+#define RT5668_HP_IMP_SENS_CTRL_40		0x01d6
+#define RT5668_HP_IMP_SENS_CTRL_41		0x01d7
+#define RT5668_HP_IMP_SENS_CTRL_42		0x01d8
+#define RT5668_HP_IMP_SENS_CTRL_43		0x01d9
+#define RT5668_HP_LOGIC_CTRL_1			0x01da
+#define RT5668_HP_LOGIC_CTRL_2			0x01db
+#define RT5668_HP_LOGIC_CTRL_3			0x01dc
+#define RT5668_HP_CALIB_CTRL_1			0x01de
+#define RT5668_HP_CALIB_CTRL_2			0x01df
+#define RT5668_HP_CALIB_CTRL_3			0x01e0
+#define RT5668_HP_CALIB_CTRL_4			0x01e1
+#define RT5668_HP_CALIB_CTRL_5			0x01e2
+#define RT5668_HP_CALIB_CTRL_6			0x01e3
+#define RT5668_HP_CALIB_CTRL_7			0x01e4
+#define RT5668_HP_CALIB_CTRL_9			0x01e6
+#define RT5668_HP_CALIB_CTRL_10			0x01e7
+#define RT5668_HP_CALIB_CTRL_11			0x01e8
+#define RT5668_HP_CALIB_STA_1			0x01ea
+#define RT5668_HP_CALIB_STA_2			0x01eb
+#define RT5668_HP_CALIB_STA_3			0x01ec
+#define RT5668_HP_CALIB_STA_4			0x01ed
+#define RT5668_HP_CALIB_STA_5			0x01ee
+#define RT5668_HP_CALIB_STA_6			0x01ef
+#define RT5668_HP_CALIB_STA_7			0x01f0
+#define RT5668_HP_CALIB_STA_8			0x01f1
+#define RT5668_HP_CALIB_STA_9			0x01f2
+#define RT5668_HP_CALIB_STA_10			0x01f3
+#define RT5668_HP_CALIB_STA_11			0x01f4
+#define RT5668_SAR_IL_CMD_1			0x0210
+#define RT5668_SAR_IL_CMD_2			0x0211
+#define RT5668_SAR_IL_CMD_3			0x0212
+#define RT5668_SAR_IL_CMD_4			0x0213
+#define RT5668_SAR_IL_CMD_5			0x0214
+#define RT5668_SAR_IL_CMD_6			0x0215
+#define RT5668_SAR_IL_CMD_7			0x0216
+#define RT5668_SAR_IL_CMD_8			0x0217
+#define RT5668_SAR_IL_CMD_9			0x0218
+#define RT5668_SAR_IL_CMD_10			0x0219
+#define RT5668_SAR_IL_CMD_11			0x021a
+#define RT5668_SAR_IL_CMD_12			0x021b
+#define RT5668_SAR_IL_CMD_13			0x021c
+#define RT5668_EFUSE_CTRL_1			0x0250
+#define RT5668_EFUSE_CTRL_2			0x0251
+#define RT5668_EFUSE_CTRL_3			0x0252
+#define RT5668_EFUSE_CTRL_4			0x0253
+#define RT5668_EFUSE_CTRL_5			0x0254
+#define RT5668_EFUSE_CTRL_6			0x0255
+#define RT5668_EFUSE_CTRL_7			0x0256
+#define RT5668_EFUSE_CTRL_8			0x0257
+#define RT5668_EFUSE_CTRL_9			0x0258
+#define RT5668_EFUSE_CTRL_10			0x0259
+#define RT5668_EFUSE_CTRL_11			0x025a
+#define RT5668_JD_TOP_VC_VTRL			0x0270
+#define RT5668_DRC1_CTRL_0			0x02ff
+#define RT5668_DRC1_CTRL_1			0x0300
+#define RT5668_DRC1_CTRL_2			0x0301
+#define RT5668_DRC1_CTRL_3			0x0302
+#define RT5668_DRC1_CTRL_4			0x0303
+#define RT5668_DRC1_CTRL_5			0x0304
+#define RT5668_DRC1_CTRL_6			0x0305
+#define RT5668_DRC1_HARD_LMT_CTRL_1		0x0306
+#define RT5668_DRC1_HARD_LMT_CTRL_2		0x0307
+#define RT5668_DRC1_PRIV_1			0x0310
+#define RT5668_DRC1_PRIV_2			0x0311
+#define RT5668_DRC1_PRIV_3			0x0312
+#define RT5668_DRC1_PRIV_4			0x0313
+#define RT5668_DRC1_PRIV_5			0x0314
+#define RT5668_DRC1_PRIV_6			0x0315
+#define RT5668_DRC1_PRIV_7			0x0316
+#define RT5668_DRC1_PRIV_8			0x0317
+#define RT5668_EQ_AUTO_RCV_CTRL1		0x03c0
+#define RT5668_EQ_AUTO_RCV_CTRL2		0x03c1
+#define RT5668_EQ_AUTO_RCV_CTRL3		0x03c2
+#define RT5668_EQ_AUTO_RCV_CTRL4		0x03c3
+#define RT5668_EQ_AUTO_RCV_CTRL5		0x03c4
+#define RT5668_EQ_AUTO_RCV_CTRL6		0x03c5
+#define RT5668_EQ_AUTO_RCV_CTRL7		0x03c6
+#define RT5668_EQ_AUTO_RCV_CTRL8		0x03c7
+#define RT5668_EQ_AUTO_RCV_CTRL9		0x03c8
+#define RT5668_EQ_AUTO_RCV_CTRL10		0x03c9
+#define RT5668_EQ_AUTO_RCV_CTRL11		0x03ca
+#define RT5668_EQ_AUTO_RCV_CTRL12		0x03cb
+#define RT5668_EQ_AUTO_RCV_CTRL13		0x03cc
+#define RT5668_ADC_L_EQ_LPF1_A1			0x03d0
+#define RT5668_R_EQ_LPF1_A1			0x03d1
+#define RT5668_L_EQ_LPF1_H0			0x03d2
+#define RT5668_R_EQ_LPF1_H0			0x03d3
+#define RT5668_L_EQ_BPF1_A1			0x03d4
+#define RT5668_R_EQ_BPF1_A1			0x03d5
+#define RT5668_L_EQ_BPF1_A2			0x03d6
+#define RT5668_R_EQ_BPF1_A2			0x03d7
+#define RT5668_L_EQ_BPF1_H0			0x03d8
+#define RT5668_R_EQ_BPF1_H0			0x03d9
+#define RT5668_L_EQ_BPF2_A1			0x03da
+#define RT5668_R_EQ_BPF2_A1			0x03db
+#define RT5668_L_EQ_BPF2_A2			0x03dc
+#define RT5668_R_EQ_BPF2_A2			0x03dd
+#define RT5668_L_EQ_BPF2_H0			0x03de
+#define RT5668_R_EQ_BPF2_H0			0x03df
+#define RT5668_L_EQ_BPF3_A1			0x03e0
+#define RT5668_R_EQ_BPF3_A1			0x03e1
+#define RT5668_L_EQ_BPF3_A2			0x03e2
+#define RT5668_R_EQ_BPF3_A2			0x03e3
+#define RT5668_L_EQ_BPF3_H0			0x03e4
+#define RT5668_R_EQ_BPF3_H0			0x03e5
+#define RT5668_L_EQ_BPF4_A1			0x03e6
+#define RT5668_R_EQ_BPF4_A1			0x03e7
+#define RT5668_L_EQ_BPF4_A2			0x03e8
+#define RT5668_R_EQ_BPF4_A2			0x03e9
+#define RT5668_L_EQ_BPF4_H0			0x03ea
+#define RT5668_R_EQ_BPF4_H0			0x03eb
+#define RT5668_L_EQ_HPF1_A1			0x03ec
+#define RT5668_R_EQ_HPF1_A1			0x03ed
+#define RT5668_L_EQ_HPF1_H0			0x03ee
+#define RT5668_R_EQ_HPF1_H0			0x03ef
+#define RT5668_L_EQ_PRE_VOL			0x03f0
+#define RT5668_R_EQ_PRE_VOL			0x03f1
+#define RT5668_L_EQ_POST_VOL			0x03f2
+#define RT5668_R_EQ_POST_VOL			0x03f3
+#define RT5668_I2C_MODE				0xffff
+
+
+/* global definition */
+#define RT5668_L_MUTE				(0x1 << 15)
+#define RT5668_L_MUTE_SFT			15
+#define RT5668_VOL_L_MUTE			(0x1 << 14)
+#define RT5668_VOL_L_SFT			14
+#define RT5668_R_MUTE				(0x1 << 7)
+#define RT5668_R_MUTE_SFT			7
+#define RT5668_VOL_R_MUTE			(0x1 << 6)
+#define RT5668_VOL_R_SFT			6
+#define RT5668_L_VOL_MASK			(0x3f << 8)
+#define RT5668_L_VOL_SFT			8
+#define RT5668_R_VOL_MASK			(0x3f)
+#define RT5668_R_VOL_SFT			0
+
+/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/
+#define RT5668_G_HP				(0xf << 8)
+#define RT5668_G_HP_SFT				8
+#define RT5668_G_STO_DA_DMIX			(0xf)
+#define RT5668_G_STO_DA_SFT			0
+
+/* CBJ Control (0x000b) */
+#define RT5668_BST_CBJ_MASK			(0xf << 8)
+#define RT5668_BST_CBJ_SFT			8
+
+/* Embeeded Jack and Type Detection Control 1 (0x0010) */
+#define RT5668_EMB_JD_EN			(0x1 << 15)
+#define RT5668_EMB_JD_EN_SFT			15
+#define RT5668_EMB_JD_RST			(0x1 << 14)
+#define RT5668_JD_MODE				(0x1 << 13)
+#define RT5668_JD_MODE_SFT			13
+#define RT5668_DET_TYPE				(0x1 << 12)
+#define RT5668_DET_TYPE_SFT			12
+#define RT5668_POLA_EXT_JD_MASK			(0x1 << 11)
+#define RT5668_POLA_EXT_JD_LOW			(0x1 << 11)
+#define RT5668_POLA_EXT_JD_HIGH			(0x0 << 11)
+#define RT5668_EXT_JD_DIG			(0x1 << 9)
+#define RT5668_POL_FAST_OFF_MASK		(0x1 << 8)
+#define RT5668_POL_FAST_OFF_HIGH		(0x1 << 8)
+#define RT5668_POL_FAST_OFF_LOW			(0x0 << 8)
+#define RT5668_FAST_OFF_MASK			(0x1 << 7)
+#define RT5668_FAST_OFF_EN			(0x1 << 7)
+#define RT5668_FAST_OFF_DIS			(0x0 << 7)
+#define RT5668_VREF_POW_MASK			(0x1 << 6)
+#define RT5668_VREF_POW_FSM			(0x0 << 6)
+#define RT5668_VREF_POW_REG			(0x1 << 6)
+#define RT5668_MB1_PATH_MASK			(0x1 << 5)
+#define RT5668_CTRL_MB1_REG			(0x1 << 5)
+#define RT5668_CTRL_MB1_FSM			(0x0 << 5)
+#define RT5668_MB2_PATH_MASK			(0x1 << 4)
+#define RT5668_CTRL_MB2_REG			(0x1 << 4)
+#define RT5668_CTRL_MB2_FSM			(0x0 << 4)
+#define RT5668_TRIG_JD_MASK			(0x1 << 3)
+#define RT5668_TRIG_JD_HIGH			(0x1 << 3)
+#define RT5668_TRIG_JD_LOW			(0x0 << 3)
+#define RT5668_MIC_CAP_MASK			(0x1 << 1)
+#define RT5668_MIC_CAP_HS			(0x1 << 1)
+#define RT5668_MIC_CAP_HP			(0x0 << 1)
+#define RT5668_MIC_CAP_SRC_MASK			(0x1)
+#define RT5668_MIC_CAP_SRC_REG			(0x1)
+#define RT5668_MIC_CAP_SRC_ANA			(0x0)
+
+/* Embeeded Jack and Type Detection Control 2 (0x0011) */
+#define RT5668_EXT_JD_SRC			(0x7 << 4)
+#define RT5668_EXT_JD_SRC_SFT			4
+#define RT5668_EXT_JD_SRC_GPIO_JD1		(0x0 << 4)
+#define RT5668_EXT_JD_SRC_GPIO_JD2		(0x1 << 4)
+#define RT5668_EXT_JD_SRC_JDH			(0x2 << 4)
+#define RT5668_EXT_JD_SRC_JDL			(0x3 << 4)
+#define RT5668_EXT_JD_SRC_MANUAL		(0x4 << 4)
+#define RT5668_JACK_TYPE_MASK			(0x3)
+
+/* Combo Jack and Type Detection Control 3 (0x0012) */
+#define RT5668_CBJ_IN_BUF_EN			(0x1 << 7)
+
+/* Combo Jack and Type Detection Control 4 (0x0013) */
+#define RT5668_SEL_SHT_MID_TON_MASK		(0x3 << 12)
+#define RT5668_SEL_SHT_MID_TON_2		(0x0 << 12)
+#define RT5668_SEL_SHT_MID_TON_3		(0x1 << 12)
+#define RT5668_CBJ_JD_TEST_MASK			(0x1 << 6)
+#define RT5668_CBJ_JD_TEST_NORM			(0x0 << 6)
+#define RT5668_CBJ_JD_TEST_MODE			(0x1 << 6)
+
+/* DAC1 Digital Volume (0x0019) */
+#define RT5668_DAC_L1_VOL_MASK			(0xff << 8)
+#define RT5668_DAC_L1_VOL_SFT			8
+#define RT5668_DAC_R1_VOL_MASK			(0xff)
+#define RT5668_DAC_R1_VOL_SFT			0
+
+/* ADC Digital Volume Control (0x001c) */
+#define RT5668_ADC_L_VOL_MASK			(0x7f << 8)
+#define RT5668_ADC_L_VOL_SFT			8
+#define RT5668_ADC_R_VOL_MASK			(0x7f)
+#define RT5668_ADC_R_VOL_SFT			0
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5668_STO1_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5668_STO1_ADC_L_BST_SFT		14
+#define RT5668_STO1_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5668_STO1_ADC_R_BST_SFT		12
+
+/* Sidetone Control (0x0024) */
+#define RT5668_ST_SRC_SEL			(0x1 << 8)
+#define RT5668_ST_SRC_SFT			8
+#define RT5668_ST_EN_MASK			(0x1 << 6)
+#define RT5668_ST_DIS				(0x0 << 6)
+#define RT5668_ST_EN				(0x1 << 6)
+#define RT5668_ST_EN_SFT			6
+
+/* Stereo1 ADC Mixer Control (0x0026) */
+#define RT5668_M_STO1_ADC_L1			(0x1 << 15)
+#define RT5668_M_STO1_ADC_L1_SFT		15
+#define RT5668_M_STO1_ADC_L2			(0x1 << 14)
+#define RT5668_M_STO1_ADC_L2_SFT		14
+#define RT5668_STO1_ADC1L_SRC_MASK		(0x1 << 13)
+#define RT5668_STO1_ADC1L_SRC_SFT		13
+#define RT5668_STO1_ADC1_SRC_ADC		(0x1 << 13)
+#define RT5668_STO1_ADC1_SRC_DACMIX		(0x0 << 13)
+#define RT5668_STO1_ADC2L_SRC_MASK		(0x1 << 12)
+#define RT5668_STO1_ADC2L_SRC_SFT		12
+#define RT5668_STO1_ADCL_SRC_MASK		(0x3 << 10)
+#define RT5668_STO1_ADCL_SRC_SFT		10
+#define RT5668_STO1_DD_L_SRC_MASK		(0x1 << 9)
+#define RT5668_STO1_DD_L_SRC_SFT		9
+#define RT5668_STO1_DMIC_SRC_MASK		(0x1 << 8)
+#define RT5668_STO1_DMIC_SRC_SFT		8
+#define RT5668_STO1_DMIC_SRC_DMIC2		(0x1 << 8)
+#define RT5668_STO1_DMIC_SRC_DMIC1		(0x0 << 8)
+#define RT5668_M_STO1_ADC_R1			(0x1 << 7)
+#define RT5668_M_STO1_ADC_R1_SFT		7
+#define RT5668_M_STO1_ADC_R2			(0x1 << 6)
+#define RT5668_M_STO1_ADC_R2_SFT		6
+#define RT5668_STO1_ADC1R_SRC_MASK		(0x1 << 5)
+#define RT5668_STO1_ADC1R_SRC_SFT		5
+#define RT5668_STO1_ADC2R_SRC_MASK		(0x1 << 4)
+#define RT5668_STO1_ADC2R_SRC_SFT		4
+#define RT5668_STO1_ADCR_SRC_MASK		(0x3 << 2)
+#define RT5668_STO1_ADCR_SRC_SFT		2
+
+/* ADC Mixer to DAC Mixer Control (0x0029) */
+#define RT5668_M_ADCMIX_L			(0x1 << 15)
+#define RT5668_M_ADCMIX_L_SFT			15
+#define RT5668_M_DAC1_L				(0x1 << 14)
+#define RT5668_M_DAC1_L_SFT			14
+#define RT5668_DAC1_R_SEL_MASK			(0x1 << 10)
+#define RT5668_DAC1_R_SEL_SFT			10
+#define RT5668_DAC1_L_SEL_MASK			(0x1 << 8)
+#define RT5668_DAC1_L_SEL_SFT			8
+#define RT5668_M_ADCMIX_R			(0x1 << 7)
+#define RT5668_M_ADCMIX_R_SFT			7
+#define RT5668_M_DAC1_R				(0x1 << 6)
+#define RT5668_M_DAC1_R_SFT			6
+
+/* Stereo1 DAC Mixer Control (0x002a) */
+#define RT5668_M_DAC_L1_STO_L			(0x1 << 15)
+#define RT5668_M_DAC_L1_STO_L_SFT		15
+#define RT5668_G_DAC_L1_STO_L_MASK		(0x1 << 14)
+#define RT5668_G_DAC_L1_STO_L_SFT		14
+#define RT5668_M_DAC_R1_STO_L			(0x1 << 13)
+#define RT5668_M_DAC_R1_STO_L_SFT		13
+#define RT5668_G_DAC_R1_STO_L_MASK		(0x1 << 12)
+#define RT5668_G_DAC_R1_STO_L_SFT		12
+#define RT5668_M_DAC_L1_STO_R			(0x1 << 7)
+#define RT5668_M_DAC_L1_STO_R_SFT		7
+#define RT5668_G_DAC_L1_STO_R_MASK		(0x1 << 6)
+#define RT5668_G_DAC_L1_STO_R_SFT		6
+#define RT5668_M_DAC_R1_STO_R			(0x1 << 5)
+#define RT5668_M_DAC_R1_STO_R_SFT		5
+#define RT5668_G_DAC_R1_STO_R_MASK		(0x1 << 4)
+#define RT5668_G_DAC_R1_STO_R_SFT		4
+
+/* Analog DAC1 Input Source Control (0x002b) */
+#define RT5668_M_ST_STO_L			(0x1 << 9)
+#define RT5668_M_ST_STO_L_SFT			9
+#define RT5668_M_ST_STO_R			(0x1 << 8)
+#define RT5668_M_ST_STO_R_SFT			8
+#define RT5668_DAC_L1_SRC_MASK			(0x3 << 4)
+#define RT5668_A_DACL1_SFT			4
+#define RT5668_DAC_R1_SRC_MASK			(0x3)
+#define RT5668_A_DACR1_SFT			0
+
+/* Digital Interface Data Control (0x0030) */
+#define RT5668_IF2_ADC_SEL_MASK			(0x3 << 0)
+#define RT5668_IF2_ADC_SEL_SFT			0
+
+/* REC Left Mixer Control 2 (0x003c) */
+#define RT5668_G_CBJ_RM1_L			(0x7 << 10)
+#define RT5668_G_CBJ_RM1_L_SFT			10
+#define RT5668_M_CBJ_RM1_L			(0x1 << 7)
+#define RT5668_M_CBJ_RM1_L_SFT			7
+
+/* Power Management for Digital 1 (0x0061) */
+#define RT5668_PWR_I2S1				(0x1 << 15)
+#define RT5668_PWR_I2S1_BIT			15
+#define RT5668_PWR_I2S2				(0x1 << 14)
+#define RT5668_PWR_I2S2_BIT			14
+#define RT5668_PWR_DAC_L1			(0x1 << 11)
+#define RT5668_PWR_DAC_L1_BIT			11
+#define RT5668_PWR_DAC_R1			(0x1 << 10)
+#define RT5668_PWR_DAC_R1_BIT			10
+#define RT5668_PWR_LDO				(0x1 << 8)
+#define RT5668_PWR_LDO_BIT			8
+#define RT5668_PWR_ADC_L1			(0x1 << 4)
+#define RT5668_PWR_ADC_L1_BIT			4
+#define RT5668_PWR_ADC_R1			(0x1 << 3)
+#define RT5668_PWR_ADC_R1_BIT			3
+#define RT5668_DIG_GATE_CTRL			(0x1 << 0)
+#define RT5668_DIG_GATE_CTRL_SFT		0
+
+
+/* Power Management for Digital 2 (0x0062) */
+#define RT5668_PWR_ADC_S1F			(0x1 << 15)
+#define RT5668_PWR_ADC_S1F_BIT			15
+#define RT5668_PWR_DAC_S1F			(0x1 << 10)
+#define RT5668_PWR_DAC_S1F_BIT			10
+
+/* Power Management for Analog 1 (0x0063) */
+#define RT5668_PWR_VREF1			(0x1 << 15)
+#define RT5668_PWR_VREF1_BIT			15
+#define RT5668_PWR_FV1				(0x1 << 14)
+#define RT5668_PWR_FV1_BIT			14
+#define RT5668_PWR_VREF2			(0x1 << 13)
+#define RT5668_PWR_VREF2_BIT			13
+#define RT5668_PWR_FV2				(0x1 << 12)
+#define RT5668_PWR_FV2_BIT			12
+#define RT5668_LDO1_DBG_MASK			(0x3 << 10)
+#define RT5668_PWR_MB				(0x1 << 9)
+#define RT5668_PWR_MB_BIT			9
+#define RT5668_PWR_BG				(0x1 << 7)
+#define RT5668_PWR_BG_BIT			7
+#define RT5668_LDO1_BYPASS_MASK			(0x1 << 6)
+#define RT5668_LDO1_BYPASS			(0x1 << 6)
+#define RT5668_LDO1_NOT_BYPASS			(0x0 << 6)
+#define RT5668_PWR_MA_BIT			6
+#define RT5668_LDO1_DVO_MASK			(0x3 << 4)
+#define RT5668_LDO1_DVO_09			(0x0 << 4)
+#define RT5668_LDO1_DVO_10			(0x1 << 4)
+#define RT5668_LDO1_DVO_12			(0x2 << 4)
+#define RT5668_LDO1_DVO_14			(0x3 << 4)
+#define RT5668_HP_DRIVER_MASK			(0x3 << 2)
+#define RT5668_HP_DRIVER_1X			(0x0 << 2)
+#define RT5668_HP_DRIVER_3X			(0x1 << 2)
+#define RT5668_HP_DRIVER_5X			(0x3 << 2)
+#define RT5668_PWR_HA_L				(0x1 << 1)
+#define RT5668_PWR_HA_L_BIT			1
+#define RT5668_PWR_HA_R				(0x1 << 0)
+#define RT5668_PWR_HA_R_BIT			0
+
+/* Power Management for Analog 2 (0x0064) */
+#define RT5668_PWR_MB1				(0x1 << 11)
+#define RT5668_PWR_MB1_PWR_DOWN			(0x0 << 11)
+#define RT5668_PWR_MB1_BIT			11
+#define RT5668_PWR_MB2				(0x1 << 10)
+#define RT5668_PWR_MB2_PWR_DOWN			(0x0 << 10)
+#define RT5668_PWR_MB2_BIT			10
+#define RT5668_PWR_JDH				(0x1 << 3)
+#define RT5668_PWR_JDH_BIT			3
+#define RT5668_PWR_JDL				(0x1 << 2)
+#define RT5668_PWR_JDL_BIT			2
+#define RT5668_PWR_RM1_L			(0x1 << 1)
+#define RT5668_PWR_RM1_L_BIT			1
+
+/* Power Management for Analog 3 (0x0065) */
+#define RT5668_PWR_CBJ				(0x1 << 9)
+#define RT5668_PWR_CBJ_BIT			9
+#define RT5668_PWR_PLL				(0x1 << 6)
+#define RT5668_PWR_PLL_BIT			6
+#define RT5668_PWR_PLL2B			(0x1 << 5)
+#define RT5668_PWR_PLL2B_BIT			5
+#define RT5668_PWR_PLL2F			(0x1 << 4)
+#define RT5668_PWR_PLL2F_BIT			4
+#define RT5668_PWR_LDO2				(0x1 << 2)
+#define RT5668_PWR_LDO2_BIT			2
+#define RT5668_PWR_DET_SPKVDD			(0x1 << 1)
+#define RT5668_PWR_DET_SPKVDD_BIT		1
+
+/* Power Management for Mixer (0x0066) */
+#define RT5668_PWR_STO1_DAC_L			(0x1 << 5)
+#define RT5668_PWR_STO1_DAC_L_BIT		5
+#define RT5668_PWR_STO1_DAC_R			(0x1 << 4)
+#define RT5668_PWR_STO1_DAC_R_BIT		4
+
+/* MCLK and System Clock Detection Control (0x006b) */
+#define RT5668_SYS_CLK_DET			(0x1 << 15)
+#define RT5668_SYS_CLK_DET_SFT			15
+#define RT5668_PLL1_CLK_DET			(0x1 << 14)
+#define RT5668_PLL1_CLK_DET_SFT			14
+#define RT5668_PLL2_CLK_DET			(0x1 << 13)
+#define RT5668_PLL2_CLK_DET_SFT			13
+#define RT5668_POW_CLK_DET2_SFT			8
+#define RT5668_POW_CLK_DET_SFT			0
+
+/* Digital Microphone Control 1 (0x006e) */
+#define RT5668_DMIC_1_EN_MASK			(0x1 << 15)
+#define RT5668_DMIC_1_EN_SFT			15
+#define RT5668_DMIC_1_DIS			(0x0 << 15)
+#define RT5668_DMIC_1_EN			(0x1 << 15)
+#define RT5668_DMIC_1_DP_MASK			(0x3 << 4)
+#define RT5668_DMIC_1_DP_SFT			4
+#define RT5668_DMIC_1_DP_GPIO2			(0x0 << 4)
+#define RT5668_DMIC_1_DP_GPIO5			(0x1 << 4)
+#define RT5668_DMIC_CLK_MASK			(0xf << 0)
+#define RT5668_DMIC_CLK_SFT			0
+
+/* I2S1 Audio Serial Data Port Control (0x0070) */
+#define RT5668_SEL_ADCDAT_MASK			(0x1 << 15)
+#define RT5668_SEL_ADCDAT_OUT			(0x0 << 15)
+#define RT5668_SEL_ADCDAT_IN			(0x1 << 15)
+#define RT5668_SEL_ADCDAT_SFT			15
+#define RT5668_I2S1_TX_CHL_MASK			(0x7 << 12)
+#define RT5668_I2S1_TX_CHL_SFT			12
+#define RT5668_I2S1_TX_CHL_16			(0x0 << 12)
+#define RT5668_I2S1_TX_CHL_20			(0x1 << 12)
+#define RT5668_I2S1_TX_CHL_24			(0x2 << 12)
+#define RT5668_I2S1_TX_CHL_32			(0x3 << 12)
+#define RT5668_I2S1_TX_CHL_8			(0x4 << 12)
+#define RT5668_I2S1_RX_CHL_MASK			(0x7 << 8)
+#define RT5668_I2S1_RX_CHL_SFT			8
+#define RT5668_I2S1_RX_CHL_16			(0x0 << 8)
+#define RT5668_I2S1_RX_CHL_20			(0x1 << 8)
+#define RT5668_I2S1_RX_CHL_24			(0x2 << 8)
+#define RT5668_I2S1_RX_CHL_32			(0x3 << 8)
+#define RT5668_I2S1_RX_CHL_8			(0x4 << 8)
+#define RT5668_I2S1_MONO_MASK			(0x1 << 7)
+#define RT5668_I2S1_MONO_EN			(0x1 << 7)
+#define RT5668_I2S1_MONO_DIS			(0x0 << 7)
+#define RT5668_I2S2_MONO_MASK			(0x1 << 6)
+#define RT5668_I2S2_MONO_EN			(0x1 << 6)
+#define RT5668_I2S2_MONO_DIS			(0x0 << 6)
+#define RT5668_I2S1_DL_MASK			(0x7 << 4)
+#define RT5668_I2S1_DL_SFT			4
+#define RT5668_I2S1_DL_16			(0x0 << 4)
+#define RT5668_I2S1_DL_20			(0x1 << 4)
+#define RT5668_I2S1_DL_24			(0x2 << 4)
+#define RT5668_I2S1_DL_32			(0x3 << 4)
+#define RT5668_I2S1_DL_8			(0x4 << 4)
+
+/* I2S1/2 Audio Serial Data Port Control (0x0070)(0x0071) */
+#define RT5668_I2S2_MS_MASK			(0x1 << 15)
+#define RT5668_I2S2_MS_SFT			15
+#define RT5668_I2S2_MS_M			(0x0 << 15)
+#define RT5668_I2S2_MS_S			(0x1 << 15)
+#define RT5668_I2S2_PIN_CFG_MASK		(0x1 << 14)
+#define RT5668_I2S2_PIN_CFG_SFT			14
+#define RT5668_I2S2_CLK_SEL_MASK		(0x1 << 11)
+#define RT5668_I2S2_CLK_SEL_SFT			11
+#define RT5668_I2S2_OUT_MASK			(0x1 << 9)
+#define RT5668_I2S2_OUT_SFT			9
+#define RT5668_I2S2_OUT_UM			(0x0 << 9)
+#define RT5668_I2S2_OUT_M			(0x1 << 9)
+#define RT5668_I2S_BP_MASK			(0x1 << 8)
+#define RT5668_I2S_BP_SFT			8
+#define RT5668_I2S_BP_NOR			(0x0 << 8)
+#define RT5668_I2S_BP_INV			(0x1 << 8)
+#define RT5668_I2S2_MONO_EN			(0x1 << 6)
+#define RT5668_I2S2_MONO_DIS			(0x0 << 6)
+#define RT5668_I2S2_DL_MASK			(0x3 << 4)
+#define RT5668_I2S2_DL_SFT			4
+#define RT5668_I2S2_DL_16			(0x0 << 4)
+#define RT5668_I2S2_DL_20			(0x1 << 4)
+#define RT5668_I2S2_DL_24			(0x2 << 4)
+#define RT5668_I2S2_DL_8			(0x3 << 4)
+#define RT5668_I2S_DF_MASK			(0x7)
+#define RT5668_I2S_DF_SFT			0
+#define RT5668_I2S_DF_I2S			(0x0)
+#define RT5668_I2S_DF_LEFT			(0x1)
+#define RT5668_I2S_DF_PCM_A			(0x2)
+#define RT5668_I2S_DF_PCM_B			(0x3)
+#define RT5668_I2S_DF_PCM_A_N			(0x6)
+#define RT5668_I2S_DF_PCM_B_N			(0x7)
+
+/* ADC/DAC Clock Control 1 (0x0073) */
+#define RT5668_ADC_OSR_MASK			(0xf << 12)
+#define RT5668_ADC_OSR_SFT			12
+#define RT5668_ADC_OSR_D_1			(0x0 << 12)
+#define RT5668_ADC_OSR_D_2			(0x1 << 12)
+#define RT5668_ADC_OSR_D_4			(0x2 << 12)
+#define RT5668_ADC_OSR_D_6			(0x3 << 12)
+#define RT5668_ADC_OSR_D_8			(0x4 << 12)
+#define RT5668_ADC_OSR_D_12			(0x5 << 12)
+#define RT5668_ADC_OSR_D_16			(0x6 << 12)
+#define RT5668_ADC_OSR_D_24			(0x7 << 12)
+#define RT5668_ADC_OSR_D_32			(0x8 << 12)
+#define RT5668_ADC_OSR_D_48			(0x9 << 12)
+#define RT5668_I2S_M_DIV_MASK			(0xf << 12)
+#define RT5668_I2S_M_DIV_SFT			8
+#define RT5668_I2S_M_D_1			(0x0 << 8)
+#define RT5668_I2S_M_D_2			(0x1 << 8)
+#define RT5668_I2S_M_D_3			(0x2 << 8)
+#define RT5668_I2S_M_D_4			(0x3 << 8)
+#define RT5668_I2S_M_D_6			(0x4 << 8)
+#define RT5668_I2S_M_D_8			(0x5 << 8)
+#define RT5668_I2S_M_D_12			(0x6 << 8)
+#define RT5668_I2S_M_D_16			(0x7 << 8)
+#define RT5668_I2S_M_D_24			(0x8 << 8)
+#define RT5668_I2S_M_D_32			(0x9 << 8)
+#define RT5668_I2S_M_D_48			(0x10 << 8)
+#define RT5668_I2S_CLK_SRC_MASK			(0x7 << 4)
+#define RT5668_I2S_CLK_SRC_SFT			4
+#define RT5668_I2S_CLK_SRC_MCLK			(0x0 << 4)
+#define RT5668_I2S_CLK_SRC_PLL1			(0x1 << 4)
+#define RT5668_I2S_CLK_SRC_PLL2			(0x2 << 4)
+#define RT5668_I2S_CLK_SRC_SDW			(0x3 << 4)
+#define RT5668_I2S_CLK_SRC_RCCLK		(0x4 << 4) /* 25M */
+#define RT5668_DAC_OSR_MASK			(0xf << 0)
+#define RT5668_DAC_OSR_SFT			0
+#define RT5668_DAC_OSR_D_1			(0x0 << 0)
+#define RT5668_DAC_OSR_D_2			(0x1 << 0)
+#define RT5668_DAC_OSR_D_4			(0x2 << 0)
+#define RT5668_DAC_OSR_D_6			(0x3 << 0)
+#define RT5668_DAC_OSR_D_8			(0x4 << 0)
+#define RT5668_DAC_OSR_D_12			(0x5 << 0)
+#define RT5668_DAC_OSR_D_16			(0x6 << 0)
+#define RT5668_DAC_OSR_D_24			(0x7 << 0)
+#define RT5668_DAC_OSR_D_32			(0x8 << 0)
+#define RT5668_DAC_OSR_D_48			(0x9 << 0)
+
+/* ADC/DAC Clock Control 2 (0x0074) */
+#define RT5668_I2S2_BCLK_MS2_MASK		(0x1 << 11)
+#define RT5668_I2S2_BCLK_MS2_SFT		11
+#define RT5668_I2S2_BCLK_MS2_32			(0x0 << 11)
+#define RT5668_I2S2_BCLK_MS2_64			(0x1 << 11)
+
+
+/* TDM control 1 (0x0079) */
+#define RT5668_TDM_TX_CH_MASK			(0x3 << 12)
+#define RT5668_TDM_TX_CH_2			(0x0 << 12)
+#define RT5668_TDM_TX_CH_4			(0x1 << 12)
+#define RT5668_TDM_TX_CH_6			(0x2 << 12)
+#define RT5668_TDM_TX_CH_8			(0x3 << 12)
+#define RT5668_TDM_RX_CH_MASK			(0x3 << 8)
+#define RT5668_TDM_RX_CH_2			(0x0 << 8)
+#define RT5668_TDM_RX_CH_4			(0x1 << 8)
+#define RT5668_TDM_RX_CH_6			(0x2 << 8)
+#define RT5668_TDM_RX_CH_8			(0x3 << 8)
+#define RT5668_TDM_ADC_LCA_MASK			(0xf << 4)
+#define RT5668_TDM_ADC_LCA_SFT			4
+#define RT5668_TDM_ADC_DL_SFT			0
+
+/* TDM control 3 (0x007a) */
+#define RT5668_IF1_ADC1_SEL_SFT			14
+#define RT5668_IF1_ADC2_SEL_SFT			12
+#define RT5668_IF1_ADC3_SEL_SFT			10
+#define RT5668_IF1_ADC4_SEL_SFT			8
+#define RT5668_TDM_ADC_SEL_SFT			4
+
+/* TDM/I2S control (0x007e) */
+#define RT5668_TDM_S_BP_MASK			(0x1 << 15)
+#define RT5668_TDM_S_BP_SFT			15
+#define RT5668_TDM_S_BP_NOR			(0x0 << 15)
+#define RT5668_TDM_S_BP_INV			(0x1 << 15)
+#define RT5668_TDM_S_LP_MASK			(0x1 << 14)
+#define RT5668_TDM_S_LP_SFT			14
+#define RT5668_TDM_S_LP_NOR			(0x0 << 14)
+#define RT5668_TDM_S_LP_INV			(0x1 << 14)
+#define RT5668_TDM_DF_MASK			(0x7 << 11)
+#define RT5668_TDM_DF_SFT			11
+#define RT5668_TDM_DF_I2S			(0x0 << 11)
+#define RT5668_TDM_DF_LEFT			(0x1 << 11)
+#define RT5668_TDM_DF_PCM_A			(0x2 << 11)
+#define RT5668_TDM_DF_PCM_B			(0x3 << 11)
+#define RT5668_TDM_DF_PCM_A_N			(0x6 << 11)
+#define RT5668_TDM_DF_PCM_B_N			(0x7 << 11)
+#define RT5668_TDM_CL_MASK			(0x3 << 4)
+#define RT5668_TDM_CL_16			(0x0 << 4)
+#define RT5668_TDM_CL_20			(0x1 << 4)
+#define RT5668_TDM_CL_24			(0x2 << 4)
+#define RT5668_TDM_CL_32			(0x3 << 4)
+#define RT5668_TDM_M_BP_MASK			(0x1 << 2)
+#define RT5668_TDM_M_BP_SFT			2
+#define RT5668_TDM_M_BP_NOR			(0x0 << 2)
+#define RT5668_TDM_M_BP_INV			(0x1 << 2)
+#define RT5668_TDM_M_LP_MASK			(0x1 << 1)
+#define RT5668_TDM_M_LP_SFT			1
+#define RT5668_TDM_M_LP_NOR			(0x0 << 1)
+#define RT5668_TDM_M_LP_INV			(0x1 << 1)
+#define RT5668_TDM_MS_MASK			(0x1 << 0)
+#define RT5668_TDM_MS_SFT			0
+#define RT5668_TDM_MS_M				(0x0 << 0)
+#define RT5668_TDM_MS_S				(0x1 << 0)
+
+/* Global Clock Control (0x0080) */
+#define RT5668_SCLK_SRC_MASK			(0x7 << 13)
+#define RT5668_SCLK_SRC_SFT			13
+#define RT5668_SCLK_SRC_MCLK			(0x0 << 13)
+#define RT5668_SCLK_SRC_PLL1			(0x1 << 13)
+#define RT5668_SCLK_SRC_PLL2			(0x2 << 13)
+#define RT5668_SCLK_SRC_SDW			(0x3 << 13)
+#define RT5668_SCLK_SRC_RCCLK			(0x4 << 13)
+#define RT5668_PLL1_SRC_MASK			(0x3 << 10)
+#define RT5668_PLL1_SRC_SFT			10
+#define RT5668_PLL1_SRC_MCLK			(0x0 << 10)
+#define RT5668_PLL1_SRC_BCLK1			(0x1 << 10)
+#define RT5668_PLL1_SRC_SDW			(0x2 << 10)
+#define RT5668_PLL1_SRC_RC			(0x3 << 10)
+#define RT5668_PLL2_SRC_MASK			(0x3 << 8)
+#define RT5668_PLL2_SRC_SFT			8
+#define RT5668_PLL2_SRC_MCLK			(0x0 << 8)
+#define RT5668_PLL2_SRC_BCLK1			(0x1 << 8)
+#define RT5668_PLL2_SRC_SDW			(0x2 << 8)
+#define RT5668_PLL2_SRC_RC			(0x3 << 8)
+
+
+
+#define RT5668_PLL_INP_MAX			40000000
+#define RT5668_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x0081) */
+#define RT5668_PLL_N_MAX			0x001ff
+#define RT5668_PLL_N_MASK			(RT5668_PLL_N_MAX << 7)
+#define RT5668_PLL_N_SFT			7
+#define RT5668_PLL_K_MAX			0x001f
+#define RT5668_PLL_K_MASK			(RT5668_PLL_K_MAX)
+#define RT5668_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x0082) */
+#define RT5668_PLL_M_MAX			0x00f
+#define RT5668_PLL_M_MASK			(RT5668_PLL_M_MAX << 12)
+#define RT5668_PLL_M_SFT			12
+#define RT5668_PLL_M_BP				(0x1 << 11)
+#define RT5668_PLL_M_BP_SFT			11
+#define RT5668_PLL_K_BP				(0x1 << 10)
+#define RT5668_PLL_K_BP_SFT			10
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5668_DA_ASRC_MASK			(0x1 << 13)
+#define RT5668_DA_ASRC_SFT			13
+#define RT5668_DAC_STO1_ASRC_MASK		(0x1 << 12)
+#define RT5668_DAC_STO1_ASRC_SFT		12
+#define RT5668_AD_ASRC_MASK			(0x1 << 8)
+#define RT5668_AD_ASRC_SFT			8
+#define RT5668_AD_ASRC_SEL_MASK			(0x1 << 4)
+#define RT5668_AD_ASRC_SEL_SFT			4
+#define RT5668_DMIC_ASRC_MASK			(0x1 << 3)
+#define RT5668_DMIC_ASRC_SFT			3
+#define RT5668_ADC_STO1_ASRC_MASK		(0x1 << 2)
+#define RT5668_ADC_STO1_ASRC_SFT		2
+#define RT5668_DA_ASRC_SEL_MASK			(0x1 << 0)
+#define RT5668_DA_ASRC_SEL_SFT			0
+
+/* PLL tracking mode 2 3 (0x0084)(0x0085)*/
+#define RT5668_FILTER_CLK_SEL_MASK		(0x7 << 12)
+#define RT5668_FILTER_CLK_SEL_SFT		12
+
+/* ASRC Control 4 (0x0086) */
+#define RT5668_ASRCIN_FTK_N1_MASK		(0x3 << 14)
+#define RT5668_ASRCIN_FTK_N1_SFT		14
+#define RT5668_ASRCIN_FTK_N2_MASK		(0x3 << 12)
+#define RT5668_ASRCIN_FTK_N2_SFT		12
+#define RT5668_ASRCIN_FTK_M1_MASK		(0x7 << 8)
+#define RT5668_ASRCIN_FTK_M1_SFT		8
+#define RT5668_ASRCIN_FTK_M2_MASK		(0x7 << 4)
+#define RT5668_ASRCIN_FTK_M2_SFT		4
+
+/* SoundWire reference clk (0x008d) */
+#define RT5668_PLL2_OUT_MASK			(0x1 << 8)
+#define RT5668_PLL2_OUT_98M			(0x0 << 8)
+#define RT5668_PLL2_OUT_49M			(0x1 << 8)
+#define RT5668_SDW_REF_2_MASK			(0xf << 4)
+#define RT5668_SDW_REF_2_SFT			4
+#define RT5668_SDW_REF_2_48K			(0x0 << 4)
+#define RT5668_SDW_REF_2_96K			(0x1 << 4)
+#define RT5668_SDW_REF_2_192K			(0x2 << 4)
+#define RT5668_SDW_REF_2_32K			(0x3 << 4)
+#define RT5668_SDW_REF_2_24K			(0x4 << 4)
+#define RT5668_SDW_REF_2_16K			(0x5 << 4)
+#define RT5668_SDW_REF_2_12K			(0x6 << 4)
+#define RT5668_SDW_REF_2_8K			(0x7 << 4)
+#define RT5668_SDW_REF_2_44K			(0x8 << 4)
+#define RT5668_SDW_REF_2_88K			(0x9 << 4)
+#define RT5668_SDW_REF_2_176K			(0xa << 4)
+#define RT5668_SDW_REF_2_353K			(0xb << 4)
+#define RT5668_SDW_REF_2_22K			(0xc << 4)
+#define RT5668_SDW_REF_2_384K			(0xd << 4)
+#define RT5668_SDW_REF_2_11K			(0xe << 4)
+#define RT5668_SDW_REF_1_MASK			(0xf << 0)
+#define RT5668_SDW_REF_1_SFT			0
+#define RT5668_SDW_REF_1_48K			(0x0 << 0)
+#define RT5668_SDW_REF_1_96K			(0x1 << 0)
+#define RT5668_SDW_REF_1_192K			(0x2 << 0)
+#define RT5668_SDW_REF_1_32K			(0x3 << 0)
+#define RT5668_SDW_REF_1_24K			(0x4 << 0)
+#define RT5668_SDW_REF_1_16K			(0x5 << 0)
+#define RT5668_SDW_REF_1_12K			(0x6 << 0)
+#define RT5668_SDW_REF_1_8K			(0x7 << 0)
+#define RT5668_SDW_REF_1_44K			(0x8 << 0)
+#define RT5668_SDW_REF_1_88K			(0x9 << 0)
+#define RT5668_SDW_REF_1_176K			(0xa << 0)
+#define RT5668_SDW_REF_1_353K			(0xb << 0)
+#define RT5668_SDW_REF_1_22K			(0xc << 0)
+#define RT5668_SDW_REF_1_384K			(0xd << 0)
+#define RT5668_SDW_REF_1_11K			(0xe << 0)
+
+/* Depop Mode Control 1 (0x008e) */
+#define RT5668_PUMP_EN				(0x1 << 3)
+#define RT5668_PUMP_EN_SFT				3
+#define RT5668_CAPLESS_EN			(0x1 << 0)
+#define RT5668_CAPLESS_EN_SFT			0
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5668_RAMP_MASK			(0x1 << 12)
+#define RT5668_RAMP_SFT				12
+#define RT5668_RAMP_DIS				(0x0 << 12)
+#define RT5668_RAMP_EN				(0x1 << 12)
+#define RT5668_BPS_MASK				(0x1 << 11)
+#define RT5668_BPS_SFT				11
+#define RT5668_BPS_DIS				(0x0 << 11)
+#define RT5668_BPS_EN				(0x1 << 11)
+#define RT5668_FAST_UPDN_MASK			(0x1 << 10)
+#define RT5668_FAST_UPDN_SFT			10
+#define RT5668_FAST_UPDN_DIS			(0x0 << 10)
+#define RT5668_FAST_UPDN_EN			(0x1 << 10)
+#define RT5668_VLO_MASK				(0x1 << 7)
+#define RT5668_VLO_SFT				7
+#define RT5668_VLO_3V				(0x0 << 7)
+#define RT5668_VLO_33V				(0x1 << 7)
+
+/* HPOUT charge pump 1 (0x0091) */
+#define RT5668_OSW_L_MASK			(0x1 << 11)
+#define RT5668_OSW_L_SFT			11
+#define RT5668_OSW_L_DIS			(0x0 << 11)
+#define RT5668_OSW_L_EN				(0x1 << 11)
+#define RT5668_OSW_R_MASK			(0x1 << 10)
+#define RT5668_OSW_R_SFT			10
+#define RT5668_OSW_R_DIS			(0x0 << 10)
+#define RT5668_OSW_R_EN				(0x1 << 10)
+#define RT5668_PM_HP_MASK			(0x3 << 8)
+#define RT5668_PM_HP_SFT			8
+#define RT5668_PM_HP_LV				(0x0 << 8)
+#define RT5668_PM_HP_MV				(0x1 << 8)
+#define RT5668_PM_HP_HV				(0x2 << 8)
+#define RT5668_IB_HP_MASK			(0x3 << 6)
+#define RT5668_IB_HP_SFT			6
+#define RT5668_IB_HP_125IL			(0x0 << 6)
+#define RT5668_IB_HP_25IL			(0x1 << 6)
+#define RT5668_IB_HP_5IL			(0x2 << 6)
+#define RT5668_IB_HP_1IL			(0x3 << 6)
+
+/* Micbias Control1 (0x93) */
+#define RT5668_MIC1_OV_MASK			(0x3 << 14)
+#define RT5668_MIC1_OV_SFT			14
+#define RT5668_MIC1_OV_2V7			(0x0 << 14)
+#define RT5668_MIC1_OV_2V4			(0x1 << 14)
+#define RT5668_MIC1_OV_2V25			(0x3 << 14)
+#define RT5668_MIC1_OV_1V8			(0x4 << 14)
+#define RT5668_MIC1_CLK_MASK			(0x1 << 13)
+#define RT5668_MIC1_CLK_SFT			13
+#define RT5668_MIC1_CLK_DIS			(0x0 << 13)
+#define RT5668_MIC1_CLK_EN			(0x1 << 13)
+#define RT5668_MIC1_OVCD_MASK			(0x1 << 12)
+#define RT5668_MIC1_OVCD_SFT			12
+#define RT5668_MIC1_OVCD_DIS			(0x0 << 12)
+#define RT5668_MIC1_OVCD_EN			(0x1 << 12)
+#define RT5668_MIC1_OVTH_MASK			(0x3 << 10)
+#define RT5668_MIC1_OVTH_SFT			10
+#define RT5668_MIC1_OVTH_768UA			(0x0 << 10)
+#define RT5668_MIC1_OVTH_960UA			(0x1 << 10)
+#define RT5668_MIC1_OVTH_1152UA			(0x2 << 10)
+#define RT5668_MIC1_OVTH_1960UA			(0x3 << 10)
+#define RT5668_MIC2_OV_MASK			(0x3 << 8)
+#define RT5668_MIC2_OV_SFT			8
+#define RT5668_MIC2_OV_2V7			(0x0 << 8)
+#define RT5668_MIC2_OV_2V4			(0x1 << 8)
+#define RT5668_MIC2_OV_2V25			(0x3 << 8)
+#define RT5668_MIC2_OV_1V8			(0x4 << 8)
+#define RT5668_MIC2_CLK_MASK			(0x1 << 7)
+#define RT5668_MIC2_CLK_SFT			7
+#define RT5668_MIC2_CLK_DIS			(0x0 << 7)
+#define RT5668_MIC2_CLK_EN			(0x1 << 7)
+#define RT5668_MIC2_OVTH_MASK			(0x3 << 4)
+#define RT5668_MIC2_OVTH_SFT			4
+#define RT5668_MIC2_OVTH_768UA			(0x0 << 4)
+#define RT5668_MIC2_OVTH_960UA			(0x1 << 4)
+#define RT5668_MIC2_OVTH_1152UA			(0x2 << 4)
+#define RT5668_MIC2_OVTH_1960UA			(0x3 << 4)
+#define RT5668_PWR_MB_MASK			(0x1 << 3)
+#define RT5668_PWR_MB_SFT			3
+#define RT5668_PWR_MB_PD			(0x0 << 3)
+#define RT5668_PWR_MB_PU			(0x1 << 3)
+
+/* Micbias Control2 (0x0094) */
+#define RT5668_PWR_CLK25M_MASK			(0x1 << 9)
+#define RT5668_PWR_CLK25M_SFT			9
+#define RT5668_PWR_CLK25M_PD			(0x0 << 9)
+#define RT5668_PWR_CLK25M_PU			(0x1 << 9)
+#define RT5668_PWR_CLK1M_MASK			(0x1 << 8)
+#define RT5668_PWR_CLK1M_SFT			8
+#define RT5668_PWR_CLK1M_PD			(0x0 << 8)
+#define RT5668_PWR_CLK1M_PU			(0x1 << 8)
+
+/* RC Clock Control (0x009f) */
+#define RT5668_POW_IRQ				(0x1 << 15)
+#define RT5668_POW_JDH				(0x1 << 14)
+#define RT5668_POW_JDL				(0x1 << 13)
+#define RT5668_POW_ANA				(0x1 << 12)
+
+/* I2S Master Mode Clock Control 1 (0x00a0) */
+#define RT5668_CLK_SRC_MCLK			(0x0)
+#define RT5668_CLK_SRC_PLL1			(0x1)
+#define RT5668_CLK_SRC_PLL2			(0x2)
+#define RT5668_CLK_SRC_SDW			(0x3)
+#define RT5668_CLK_SRC_RCCLK			(0x4)
+#define RT5668_I2S_PD_1				(0x0)
+#define RT5668_I2S_PD_2				(0x1)
+#define RT5668_I2S_PD_3				(0x2)
+#define RT5668_I2S_PD_4				(0x3)
+#define RT5668_I2S_PD_6				(0x4)
+#define RT5668_I2S_PD_8				(0x5)
+#define RT5668_I2S_PD_12			(0x6)
+#define RT5668_I2S_PD_16			(0x7)
+#define RT5668_I2S_PD_24			(0x8)
+#define RT5668_I2S_PD_32			(0x9)
+#define RT5668_I2S_PD_48			(0xa)
+#define RT5668_I2S2_SRC_MASK			(0x3 << 4)
+#define RT5668_I2S2_SRC_SFT			4
+#define RT5668_I2S2_M_PD_MASK			(0xf << 0)
+#define RT5668_I2S2_M_PD_SFT			0
+
+/* IRQ Control 1 (0x00b6) */
+#define RT5668_JD1_PULSE_EN_MASK		(0x1 << 10)
+#define RT5668_JD1_PULSE_EN_SFT			10
+#define RT5668_JD1_PULSE_DIS			(0x0 << 10)
+#define RT5668_JD1_PULSE_EN			(0x1 << 10)
+
+/* IRQ Control 2 (0x00b7) */
+#define RT5668_JD1_EN_MASK			(0x1 << 15)
+#define RT5668_JD1_EN_SFT			15
+#define RT5668_JD1_DIS				(0x0 << 15)
+#define RT5668_JD1_EN				(0x1 << 15)
+#define RT5668_JD1_POL_MASK			(0x1 << 13)
+#define RT5668_JD1_POL_NOR			(0x0 << 13)
+#define RT5668_JD1_POL_INV			(0x1 << 13)
+
+/* IRQ Control 3 (0x00b8) */
+#define RT5668_IL_IRQ_MASK			(0x1 << 7)
+#define RT5668_IL_IRQ_DIS			(0x0 << 7)
+#define RT5668_IL_IRQ_EN			(0x1 << 7)
+
+/* GPIO Control 1 (0x00c0) */
+#define RT5668_GP1_PIN_MASK			(0x3 << 14)
+#define RT5668_GP1_PIN_SFT			14
+#define RT5668_GP1_PIN_GPIO1			(0x0 << 14)
+#define RT5668_GP1_PIN_IRQ			(0x1 << 14)
+#define RT5668_GP1_PIN_DMIC_CLK			(0x2 << 14)
+#define RT5668_GP2_PIN_MASK			(0x3 << 12)
+#define RT5668_GP2_PIN_SFT			12
+#define RT5668_GP2_PIN_GPIO2			(0x0 << 12)
+#define RT5668_GP2_PIN_LRCK2			(0x1 << 12)
+#define RT5668_GP2_PIN_DMIC_SDA			(0x2 << 12)
+#define RT5668_GP3_PIN_MASK			(0x3 << 10)
+#define RT5668_GP3_PIN_SFT			10
+#define RT5668_GP3_PIN_GPIO3			(0x0 << 10)
+#define RT5668_GP3_PIN_BCLK2			(0x1 << 10)
+#define RT5668_GP3_PIN_DMIC_CLK			(0x2 << 10)
+#define RT5668_GP4_PIN_MASK			(0x3 << 8)
+#define RT5668_GP4_PIN_SFT			8
+#define RT5668_GP4_PIN_GPIO4			(0x0 << 8)
+#define RT5668_GP4_PIN_ADCDAT1			(0x1 << 8)
+#define RT5668_GP4_PIN_DMIC_CLK			(0x2 << 8)
+#define RT5668_GP4_PIN_ADCDAT2			(0x3 << 8)
+#define RT5668_GP5_PIN_MASK			(0x3 << 6)
+#define RT5668_GP5_PIN_SFT			6
+#define RT5668_GP5_PIN_GPIO5			(0x0 << 6)
+#define RT5668_GP5_PIN_DACDAT1			(0x1 << 6)
+#define RT5668_GP5_PIN_DMIC_SDA			(0x2 << 6)
+#define RT5668_GP6_PIN_MASK			(0x1 << 5)
+#define RT5668_GP6_PIN_SFT			5
+#define RT5668_GP6_PIN_GPIO6			(0x0 << 5)
+#define RT5668_GP6_PIN_LRCK1			(0x1 << 5)
+
+/* GPIO Control 2 (0x00c1)*/
+#define RT5668_GP1_PF_MASK			(0x1 << 15)
+#define RT5668_GP1_PF_IN			(0x0 << 15)
+#define RT5668_GP1_PF_OUT			(0x1 << 15)
+#define RT5668_GP1_OUT_MASK			(0x1 << 14)
+#define RT5668_GP1_OUT_L			(0x0 << 14)
+#define RT5668_GP1_OUT_H			(0x1 << 14)
+#define RT5668_GP2_PF_MASK			(0x1 << 13)
+#define RT5668_GP2_PF_IN			(0x0 << 13)
+#define RT5668_GP2_PF_OUT			(0x1 << 13)
+#define RT5668_GP2_OUT_MASK			(0x1 << 12)
+#define RT5668_GP2_OUT_L			(0x0 << 12)
+#define RT5668_GP2_OUT_H			(0x1 << 12)
+#define RT5668_GP3_PF_MASK			(0x1 << 11)
+#define RT5668_GP3_PF_IN			(0x0 << 11)
+#define RT5668_GP3_PF_OUT			(0x1 << 11)
+#define RT5668_GP3_OUT_MASK			(0x1 << 10)
+#define RT5668_GP3_OUT_L			(0x0 << 10)
+#define RT5668_GP3_OUT_H			(0x1 << 10)
+#define RT5668_GP4_PF_MASK			(0x1 << 9)
+#define RT5668_GP4_PF_IN			(0x0 << 9)
+#define RT5668_GP4_PF_OUT			(0x1 << 9)
+#define RT5668_GP4_OUT_MASK			(0x1 << 8)
+#define RT5668_GP4_OUT_L			(0x0 << 8)
+#define RT5668_GP4_OUT_H			(0x1 << 8)
+#define RT5668_GP5_PF_MASK			(0x1 << 7)
+#define RT5668_GP5_PF_IN			(0x0 << 7)
+#define RT5668_GP5_PF_OUT			(0x1 << 7)
+#define RT5668_GP5_OUT_MASK			(0x1 << 6)
+#define RT5668_GP5_OUT_L			(0x0 << 6)
+#define RT5668_GP5_OUT_H			(0x1 << 6)
+#define RT5668_GP6_PF_MASK			(0x1 << 5)
+#define RT5668_GP6_PF_IN			(0x0 << 5)
+#define RT5668_GP6_PF_OUT			(0x1 << 5)
+#define RT5668_GP6_OUT_MASK			(0x1 << 4)
+#define RT5668_GP6_OUT_L			(0x0 << 4)
+#define RT5668_GP6_OUT_H			(0x1 << 4)
+
+
+/* GPIO Status (0x00c2) */
+#define RT5668_GP6_STA				(0x1 << 6)
+#define RT5668_GP5_STA				(0x1 << 5)
+#define RT5668_GP4_STA				(0x1 << 4)
+#define RT5668_GP3_STA				(0x1 << 3)
+#define RT5668_GP2_STA				(0x1 << 2)
+#define RT5668_GP1_STA				(0x1 << 1)
+
+/* Soft volume and zero cross control 1 (0x00d9) */
+#define RT5668_SV_MASK				(0x1 << 15)
+#define RT5668_SV_SFT				15
+#define RT5668_SV_DIS				(0x0 << 15)
+#define RT5668_SV_EN				(0x1 << 15)
+#define RT5668_ZCD_MASK				(0x1 << 10)
+#define RT5668_ZCD_SFT				10
+#define RT5668_ZCD_PD				(0x0 << 10)
+#define RT5668_ZCD_PU				(0x1 << 10)
+#define RT5668_SV_DLY_MASK			(0xf)
+#define RT5668_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0x00da) */
+#define RT5668_ZCD_BST1_CBJ_MASK		(0x1 << 7)
+#define RT5668_ZCD_BST1_CBJ_SFT			7
+#define RT5668_ZCD_BST1_CBJ_DIS			(0x0 << 7)
+#define RT5668_ZCD_BST1_CBJ_EN			(0x1 << 7)
+#define RT5668_ZCD_RECMIX_MASK			(0x1)
+#define RT5668_ZCD_RECMIX_SFT			0
+#define RT5668_ZCD_RECMIX_DIS			(0x0)
+#define RT5668_ZCD_RECMIX_EN			(0x1)
+
+/* 4 Button Inline Command Control 2 (0x00e3) */
+#define RT5668_4BTN_IL_MASK			(0x1 << 15)
+#define RT5668_4BTN_IL_EN			(0x1 << 15)
+#define RT5668_4BTN_IL_DIS			(0x0 << 15)
+#define RT5668_4BTN_IL_RST_MASK			(0x1 << 14)
+#define RT5668_4BTN_IL_NOR			(0x1 << 14)
+#define RT5668_4BTN_IL_RST			(0x0 << 14)
+
+/* Analog JD Control (0x00f0) */
+#define RT5668_JDH_RS_MASK			(0x1 << 4)
+#define RT5668_JDH_NO_PLUG			(0x1 << 4)
+#define RT5668_JDH_PLUG				(0x0 << 4)
+
+/* Chopper and Clock control for DAC (0x013a)*/
+#define RT5668_CKXEN_DAC1_MASK			(0x1 << 13)
+#define RT5668_CKXEN_DAC1_SFT			13
+#define RT5668_CKGEN_DAC1_MASK			(0x1 << 12)
+#define RT5668_CKGEN_DAC1_SFT			12
+
+/* Chopper and Clock control for ADC (0x013b)*/
+#define RT5668_CKXEN_ADC1_MASK			(0x1 << 13)
+#define RT5668_CKXEN_ADC1_SFT			13
+#define RT5668_CKGEN_ADC1_MASK			(0x1 << 12)
+#define RT5668_CKGEN_ADC1_SFT			12
+
+/* Volume test (0x013f)*/
+#define RT5668_SEL_CLK_VOL_MASK			(0x1 << 15)
+#define RT5668_SEL_CLK_VOL_EN			(0x1 << 15)
+#define RT5668_SEL_CLK_VOL_DIS			(0x0 << 15)
+
+/* Test Mode Control 1 (0x0145) */
+#define RT5668_AD2DA_LB_MASK			(0x1 << 10)
+#define RT5668_AD2DA_LB_SFT			10
+
+/* Stereo Noise Gate Control 1 (0x0160) */
+#define RT5668_NG2_EN_MASK			(0x1 << 15)
+#define RT5668_NG2_EN				(0x1 << 15)
+#define RT5668_NG2_DIS				(0x0 << 15)
+
+/* Stereo1 DAC Silence Detection Control (0x0190) */
+#define RT5668_DEB_STO_DAC_MASK			(0x7 << 4)
+#define RT5668_DEB_80_MS			(0x0 << 4)
+
+/* SAR ADC Inline Command Control 1 (0x0210) */
+#define RT5668_SAR_BUTT_DET_MASK		(0x1 << 15)
+#define RT5668_SAR_BUTT_DET_EN			(0x1 << 15)
+#define RT5668_SAR_BUTT_DET_DIS			(0x0 << 15)
+#define RT5668_SAR_BUTDET_MODE_MASK		(0x1 << 14)
+#define RT5668_SAR_BUTDET_POW_SAV		(0x1 << 14)
+#define RT5668_SAR_BUTDET_POW_NORM		(0x0 << 14)
+#define RT5668_SAR_BUTDET_RST_MASK		(0x1 << 13)
+#define RT5668_SAR_BUTDET_RST_NORMAL		(0x1 << 13)
+#define RT5668_SAR_BUTDET_RST			(0x0 << 13)
+#define RT5668_SAR_POW_MASK			(0x1 << 12)
+#define RT5668_SAR_POW_EN			(0x1 << 12)
+#define RT5668_SAR_POW_DIS			(0x0 << 12)
+#define RT5668_SAR_RST_MASK			(0x1 << 11)
+#define RT5668_SAR_RST_NORMAL			(0x1 << 11)
+#define RT5668_SAR_RST				(0x0 << 11)
+#define RT5668_SAR_BYPASS_MASK			(0x1 << 10)
+#define RT5668_SAR_BYPASS_EN			(0x1 << 10)
+#define RT5668_SAR_BYPASS_DIS			(0x0 << 10)
+#define RT5668_SAR_SEL_MB1_MASK			(0x1 << 9)
+#define RT5668_SAR_SEL_MB1_SEL			(0x1 << 9)
+#define RT5668_SAR_SEL_MB1_NOSEL		(0x0 << 9)
+#define RT5668_SAR_SEL_MB2_MASK			(0x1 << 8)
+#define RT5668_SAR_SEL_MB2_SEL			(0x1 << 8)
+#define RT5668_SAR_SEL_MB2_NOSEL		(0x0 << 8)
+#define RT5668_SAR_SEL_MODE_MASK		(0x1 << 7)
+#define RT5668_SAR_SEL_MODE_CMP			(0x1 << 7)
+#define RT5668_SAR_SEL_MODE_ADC			(0x0 << 7)
+#define RT5668_SAR_SEL_MB1_MB2_MASK		(0x1 << 5)
+#define RT5668_SAR_SEL_MB1_MB2_AUTO		(0x1 << 5)
+#define RT5668_SAR_SEL_MB1_MB2_MANU		(0x0 << 5)
+#define RT5668_SAR_SEL_SIGNAL_MASK		(0x1 << 4)
+#define RT5668_SAR_SEL_SIGNAL_AUTO		(0x1 << 4)
+#define RT5668_SAR_SEL_SIGNAL_MANU		(0x0 << 4)
+
+/* SAR ADC Inline Command Control 13 (0x021c) */
+#define RT5668_SAR_SOUR_MASK			(0x3f)
+#define RT5668_SAR_SOUR_BTN			(0x3f)
+#define RT5668_SAR_SOUR_TYPE			(0x0)
+
+
+/* System Clock Source */
+enum {
+	RT5668_SCLK_S_MCLK,
+	RT5668_SCLK_S_PLL1,
+	RT5668_SCLK_S_PLL2,
+	RT5668_SCLK_S_RCCLK,
+};
+
+/* PLL Source */
+enum {
+	RT5668_PLL1_S_MCLK,
+	RT5668_PLL1_S_BCLK1,
+	RT5668_PLL1_S_RCCLK,
+};
+
+enum {
+	RT5668_AIF1,
+	RT5668_AIF2,
+	RT5668_AIFS
+};
+
+/* filter mask */
+enum {
+	RT5668_DA_STEREO1_FILTER = 0x1,
+	RT5668_AD_STEREO1_FILTER = (0x1 << 1),
+};
+
+enum {
+	RT5668_CLK_SEL_SYS,
+	RT5668_CLK_SEL_I2S1_ASRC,
+	RT5668_CLK_SEL_I2S2_ASRC,
+};
+
+int rt5668_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src);
+
+#endif /* __RT5668_H__ */
diff --git a/sound/soc/codecs/rt5670-dsp.h b/sound/soc/codecs/rt5670-dsp.h
new file mode 100644
index 0000000..a34d0cd
--- /dev/null
+++ b/sound/soc/codecs/rt5670-dsp.h
@@ -0,0 +1,54 @@
+/*
+ * rt5670-dsp.h  --  RT5670 ALSA SoC DSP driver
+ *
+ * Copyright 2014 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5670_DSP_H__
+#define __RT5670_DSP_H__
+
+#define RT5670_DSP_CTRL1		0xe0
+#define RT5670_DSP_CTRL2		0xe1
+#define RT5670_DSP_CTRL3		0xe2
+#define RT5670_DSP_CTRL4		0xe3
+#define RT5670_DSP_CTRL5		0xe4
+
+/* DSP Control 1 (0xe0) */
+#define RT5670_DSP_CMD_MASK		(0xff << 8)
+#define RT5670_DSP_CMD_PE		(0x0d << 8)	/* Patch Entry */
+#define RT5670_DSP_CMD_MW		(0x3b << 8)	/* Memory Write */
+#define RT5670_DSP_CMD_MR		(0x37 << 8)	/* Memory Read */
+#define RT5670_DSP_CMD_RR		(0x60 << 8)	/* Register Read */
+#define RT5670_DSP_CMD_RW		(0x68 << 8)	/* Register Write */
+#define RT5670_DSP_REG_DATHI		(0x26 << 8)	/* High Data Addr */
+#define RT5670_DSP_REG_DATLO		(0x25 << 8)	/* Low Data Addr */
+#define RT5670_DSP_CLK_MASK		(0x3 << 6)
+#define RT5670_DSP_CLK_SFT		6
+#define RT5670_DSP_CLK_768K		(0x0 << 6)
+#define RT5670_DSP_CLK_384K		(0x1 << 6)
+#define RT5670_DSP_CLK_192K		(0x2 << 6)
+#define RT5670_DSP_CLK_96K		(0x3 << 6)
+#define RT5670_DSP_BUSY_MASK		(0x1 << 5)
+#define RT5670_DSP_RW_MASK		(0x1 << 4)
+#define RT5670_DSP_DL_MASK		(0x3 << 2)
+#define RT5670_DSP_DL_0			(0x0 << 2)
+#define RT5670_DSP_DL_1			(0x1 << 2)
+#define RT5670_DSP_DL_2			(0x2 << 2)
+#define RT5670_DSP_DL_3			(0x3 << 2)
+#define RT5670_DSP_I2C_AL_16		(0x1 << 1)
+#define RT5670_DSP_CMD_EN		(0x1)
+
+struct rt5670_dsp_param {
+	u16 cmd_fmt;
+	u16 addr;
+	u16 data;
+	u8 cmd;
+};
+
+#endif /* __RT5670_DSP_H__ */
+
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
new file mode 100644
index 0000000..732ef92
--- /dev/null
+++ b/sound/soc/codecs/rt5670.c
@@ -0,0 +1,3209 @@
+/*
+ * rt5670.c  --  RT5670 ALSA SoC audio codec driver
+ *
+ * Copyright 2014 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/spi/spi.h>
+#include <linux/dmi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/rt5670.h>
+
+#include "rl6231.h"
+#include "rt5670.h"
+#include "rt5670-dsp.h"
+
+#define RT5670_DEV_GPIO     BIT(0)
+#define RT5670_IN2_DIFF     BIT(1)
+#define RT5670_DMIC_EN      BIT(2)
+#define RT5670_DMIC1_IN2P   BIT(3)
+#define RT5670_DMIC1_GPIO6  BIT(4)
+#define RT5670_DMIC1_GPIO7  BIT(5)
+#define RT5670_DMIC2_INR    BIT(6)
+#define RT5670_DMIC2_GPIO8  BIT(7)
+#define RT5670_DMIC3_GPIO5  BIT(8)
+#define RT5670_JD_MODE1     BIT(9)
+#define RT5670_JD_MODE2     BIT(10)
+#define RT5670_JD_MODE3     BIT(11)
+
+static unsigned long rt5670_quirk;
+static unsigned int quirk_override;
+module_param_named(quirk, quirk_override, uint, 0444);
+MODULE_PARM_DESC(quirk, "Board-specific quirk override");
+
+#define RT5670_DEVICE_ID 0x6271
+
+#define RT5670_PR_RANGE_BASE (0xff + 1)
+#define RT5670_PR_SPACING 0x100
+
+#define RT5670_PR_BASE (RT5670_PR_RANGE_BASE + (0 * RT5670_PR_SPACING))
+
+static const struct regmap_range_cfg rt5670_ranges[] = {
+	{ .name = "PR", .range_min = RT5670_PR_BASE,
+	  .range_max = RT5670_PR_BASE + 0xf8,
+	  .selector_reg = RT5670_PRIV_INDEX,
+	  .selector_mask = 0xff,
+	  .selector_shift = 0x0,
+	  .window_start = RT5670_PRIV_DATA,
+	  .window_len = 0x1, },
+};
+
+static const struct reg_sequence init_list[] = {
+	{ RT5670_PR_BASE + 0x14, 0x9a8a },
+	{ RT5670_PR_BASE + 0x38, 0x1fe1 },
+	{ RT5670_PR_BASE + 0x3d, 0x3640 },
+	{ 0x8a, 0x0123 },
+};
+
+static const struct reg_default rt5670_reg[] = {
+	{ 0x00, 0x0000 },
+	{ 0x02, 0x8888 },
+	{ 0x03, 0x8888 },
+	{ 0x0a, 0x0001 },
+	{ 0x0b, 0x0827 },
+	{ 0x0c, 0x0000 },
+	{ 0x0d, 0x0008 },
+	{ 0x0e, 0x0000 },
+	{ 0x0f, 0x0808 },
+	{ 0x19, 0xafaf },
+	{ 0x1a, 0xafaf },
+	{ 0x1b, 0x0011 },
+	{ 0x1c, 0x2f2f },
+	{ 0x1d, 0x2f2f },
+	{ 0x1e, 0x0000 },
+	{ 0x1f, 0x2f2f },
+	{ 0x20, 0x0000 },
+	{ 0x26, 0x7860 },
+	{ 0x27, 0x7860 },
+	{ 0x28, 0x7871 },
+	{ 0x29, 0x8080 },
+	{ 0x2a, 0x5656 },
+	{ 0x2b, 0x5454 },
+	{ 0x2c, 0xaaa0 },
+	{ 0x2d, 0x0000 },
+	{ 0x2e, 0x2f2f },
+	{ 0x2f, 0x1002 },
+	{ 0x30, 0x0000 },
+	{ 0x31, 0x5f00 },
+	{ 0x32, 0x0000 },
+	{ 0x33, 0x0000 },
+	{ 0x34, 0x0000 },
+	{ 0x35, 0x0000 },
+	{ 0x36, 0x0000 },
+	{ 0x37, 0x0000 },
+	{ 0x38, 0x0000 },
+	{ 0x3b, 0x0000 },
+	{ 0x3c, 0x007f },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x007f },
+	{ 0x45, 0xe00f },
+	{ 0x4c, 0x5380 },
+	{ 0x4f, 0x0073 },
+	{ 0x52, 0x00d3 },
+	{ 0x53, 0xf000 },
+	{ 0x61, 0x0000 },
+	{ 0x62, 0x0001 },
+	{ 0x63, 0x00c3 },
+	{ 0x64, 0x0000 },
+	{ 0x65, 0x0001 },
+	{ 0x66, 0x0000 },
+	{ 0x6f, 0x8000 },
+	{ 0x70, 0x8000 },
+	{ 0x71, 0x8000 },
+	{ 0x72, 0x8000 },
+	{ 0x73, 0x7770 },
+	{ 0x74, 0x0e00 },
+	{ 0x75, 0x1505 },
+	{ 0x76, 0x0015 },
+	{ 0x77, 0x0c00 },
+	{ 0x78, 0x4000 },
+	{ 0x79, 0x0123 },
+	{ 0x7f, 0x1100 },
+	{ 0x80, 0x0000 },
+	{ 0x81, 0x0000 },
+	{ 0x82, 0x0000 },
+	{ 0x83, 0x0000 },
+	{ 0x84, 0x0000 },
+	{ 0x85, 0x0000 },
+	{ 0x86, 0x0004 },
+	{ 0x87, 0x0000 },
+	{ 0x88, 0x0000 },
+	{ 0x89, 0x0000 },
+	{ 0x8a, 0x0123 },
+	{ 0x8b, 0x0000 },
+	{ 0x8c, 0x0003 },
+	{ 0x8d, 0x0000 },
+	{ 0x8e, 0x0004 },
+	{ 0x8f, 0x1100 },
+	{ 0x90, 0x0646 },
+	{ 0x91, 0x0c06 },
+	{ 0x93, 0x0000 },
+	{ 0x94, 0x1270 },
+	{ 0x95, 0x1000 },
+	{ 0x97, 0x0000 },
+	{ 0x98, 0x0000 },
+	{ 0x99, 0x0000 },
+	{ 0x9a, 0x2184 },
+	{ 0x9b, 0x010a },
+	{ 0x9c, 0x0aea },
+	{ 0x9d, 0x000c },
+	{ 0x9e, 0x0400 },
+	{ 0xae, 0x7000 },
+	{ 0xaf, 0x0000 },
+	{ 0xb0, 0x7000 },
+	{ 0xb1, 0x0000 },
+	{ 0xb2, 0x0000 },
+	{ 0xb3, 0x001f },
+	{ 0xb4, 0x220c },
+	{ 0xb5, 0x1f00 },
+	{ 0xb6, 0x0000 },
+	{ 0xb7, 0x0000 },
+	{ 0xbb, 0x0000 },
+	{ 0xbc, 0x0000 },
+	{ 0xbd, 0x0000 },
+	{ 0xbe, 0x0000 },
+	{ 0xbf, 0x0000 },
+	{ 0xc0, 0x0000 },
+	{ 0xc1, 0x0000 },
+	{ 0xc2, 0x0000 },
+	{ 0xcd, 0x0000 },
+	{ 0xce, 0x0000 },
+	{ 0xcf, 0x1813 },
+	{ 0xd0, 0x0690 },
+	{ 0xd1, 0x1c17 },
+	{ 0xd3, 0xa220 },
+	{ 0xd4, 0x0000 },
+	{ 0xd6, 0x0400 },
+	{ 0xd9, 0x0809 },
+	{ 0xda, 0x0000 },
+	{ 0xdb, 0x0001 },
+	{ 0xdc, 0x0049 },
+	{ 0xdd, 0x0024 },
+	{ 0xe6, 0x8000 },
+	{ 0xe7, 0x0000 },
+	{ 0xec, 0xa200 },
+	{ 0xed, 0x0000 },
+	{ 0xee, 0xa200 },
+	{ 0xef, 0x0000 },
+	{ 0xf8, 0x0000 },
+	{ 0xf9, 0x0000 },
+	{ 0xfa, 0x8010 },
+	{ 0xfb, 0x0033 },
+	{ 0xfc, 0x0100 },
+};
+
+static bool rt5670_volatile_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5670_ranges); i++) {
+		if ((reg >= rt5670_ranges[i].window_start &&
+		     reg <= rt5670_ranges[i].window_start +
+		     rt5670_ranges[i].window_len) ||
+		    (reg >= rt5670_ranges[i].range_min &&
+		     reg <= rt5670_ranges[i].range_max)) {
+			return true;
+		}
+	}
+
+	switch (reg) {
+	case RT5670_RESET:
+	case RT5670_PDM_DATA_CTRL1:
+	case RT5670_PDM1_DATA_CTRL4:
+	case RT5670_PDM2_DATA_CTRL4:
+	case RT5670_PRIV_DATA:
+	case RT5670_ASRC_5:
+	case RT5670_CJ_CTRL1:
+	case RT5670_CJ_CTRL2:
+	case RT5670_CJ_CTRL3:
+	case RT5670_A_JD_CTRL1:
+	case RT5670_A_JD_CTRL2:
+	case RT5670_VAD_CTRL5:
+	case RT5670_ADC_EQ_CTRL1:
+	case RT5670_EQ_CTRL1:
+	case RT5670_ALC_CTRL_1:
+	case RT5670_IRQ_CTRL2:
+	case RT5670_INT_IRQ_ST:
+	case RT5670_IL_CMD:
+	case RT5670_DSP_CTRL1:
+	case RT5670_DSP_CTRL2:
+	case RT5670_DSP_CTRL3:
+	case RT5670_DSP_CTRL4:
+	case RT5670_DSP_CTRL5:
+	case RT5670_VENDOR_ID:
+	case RT5670_VENDOR_ID1:
+	case RT5670_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5670_readable_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5670_ranges); i++) {
+		if ((reg >= rt5670_ranges[i].window_start &&
+		     reg <= rt5670_ranges[i].window_start +
+		     rt5670_ranges[i].window_len) ||
+		    (reg >= rt5670_ranges[i].range_min &&
+		     reg <= rt5670_ranges[i].range_max)) {
+			return true;
+		}
+	}
+
+	switch (reg) {
+	case RT5670_RESET:
+	case RT5670_HP_VOL:
+	case RT5670_LOUT1:
+	case RT5670_CJ_CTRL1:
+	case RT5670_CJ_CTRL2:
+	case RT5670_CJ_CTRL3:
+	case RT5670_IN2:
+	case RT5670_INL1_INR1_VOL:
+	case RT5670_DAC1_DIG_VOL:
+	case RT5670_DAC2_DIG_VOL:
+	case RT5670_DAC_CTRL:
+	case RT5670_STO1_ADC_DIG_VOL:
+	case RT5670_MONO_ADC_DIG_VOL:
+	case RT5670_STO2_ADC_DIG_VOL:
+	case RT5670_ADC_BST_VOL1:
+	case RT5670_ADC_BST_VOL2:
+	case RT5670_STO2_ADC_MIXER:
+	case RT5670_STO1_ADC_MIXER:
+	case RT5670_MONO_ADC_MIXER:
+	case RT5670_AD_DA_MIXER:
+	case RT5670_STO_DAC_MIXER:
+	case RT5670_DD_MIXER:
+	case RT5670_DIG_MIXER:
+	case RT5670_DSP_PATH1:
+	case RT5670_DSP_PATH2:
+	case RT5670_DIG_INF1_DATA:
+	case RT5670_DIG_INF2_DATA:
+	case RT5670_PDM_OUT_CTRL:
+	case RT5670_PDM_DATA_CTRL1:
+	case RT5670_PDM1_DATA_CTRL2:
+	case RT5670_PDM1_DATA_CTRL3:
+	case RT5670_PDM1_DATA_CTRL4:
+	case RT5670_PDM2_DATA_CTRL2:
+	case RT5670_PDM2_DATA_CTRL3:
+	case RT5670_PDM2_DATA_CTRL4:
+	case RT5670_REC_L1_MIXER:
+	case RT5670_REC_L2_MIXER:
+	case RT5670_REC_R1_MIXER:
+	case RT5670_REC_R2_MIXER:
+	case RT5670_HPO_MIXER:
+	case RT5670_MONO_MIXER:
+	case RT5670_OUT_L1_MIXER:
+	case RT5670_OUT_R1_MIXER:
+	case RT5670_LOUT_MIXER:
+	case RT5670_PWR_DIG1:
+	case RT5670_PWR_DIG2:
+	case RT5670_PWR_ANLG1:
+	case RT5670_PWR_ANLG2:
+	case RT5670_PWR_MIXER:
+	case RT5670_PWR_VOL:
+	case RT5670_PRIV_INDEX:
+	case RT5670_PRIV_DATA:
+	case RT5670_I2S4_SDP:
+	case RT5670_I2S1_SDP:
+	case RT5670_I2S2_SDP:
+	case RT5670_I2S3_SDP:
+	case RT5670_ADDA_CLK1:
+	case RT5670_ADDA_CLK2:
+	case RT5670_DMIC_CTRL1:
+	case RT5670_DMIC_CTRL2:
+	case RT5670_TDM_CTRL_1:
+	case RT5670_TDM_CTRL_2:
+	case RT5670_TDM_CTRL_3:
+	case RT5670_DSP_CLK:
+	case RT5670_GLB_CLK:
+	case RT5670_PLL_CTRL1:
+	case RT5670_PLL_CTRL2:
+	case RT5670_ASRC_1:
+	case RT5670_ASRC_2:
+	case RT5670_ASRC_3:
+	case RT5670_ASRC_4:
+	case RT5670_ASRC_5:
+	case RT5670_ASRC_7:
+	case RT5670_ASRC_8:
+	case RT5670_ASRC_9:
+	case RT5670_ASRC_10:
+	case RT5670_ASRC_11:
+	case RT5670_ASRC_12:
+	case RT5670_ASRC_13:
+	case RT5670_ASRC_14:
+	case RT5670_DEPOP_M1:
+	case RT5670_DEPOP_M2:
+	case RT5670_DEPOP_M3:
+	case RT5670_CHARGE_PUMP:
+	case RT5670_MICBIAS:
+	case RT5670_A_JD_CTRL1:
+	case RT5670_A_JD_CTRL2:
+	case RT5670_VAD_CTRL1:
+	case RT5670_VAD_CTRL2:
+	case RT5670_VAD_CTRL3:
+	case RT5670_VAD_CTRL4:
+	case RT5670_VAD_CTRL5:
+	case RT5670_ADC_EQ_CTRL1:
+	case RT5670_ADC_EQ_CTRL2:
+	case RT5670_EQ_CTRL1:
+	case RT5670_EQ_CTRL2:
+	case RT5670_ALC_DRC_CTRL1:
+	case RT5670_ALC_DRC_CTRL2:
+	case RT5670_ALC_CTRL_1:
+	case RT5670_ALC_CTRL_2:
+	case RT5670_ALC_CTRL_3:
+	case RT5670_JD_CTRL:
+	case RT5670_IRQ_CTRL1:
+	case RT5670_IRQ_CTRL2:
+	case RT5670_INT_IRQ_ST:
+	case RT5670_GPIO_CTRL1:
+	case RT5670_GPIO_CTRL2:
+	case RT5670_GPIO_CTRL3:
+	case RT5670_SCRABBLE_FUN:
+	case RT5670_SCRABBLE_CTRL:
+	case RT5670_BASE_BACK:
+	case RT5670_MP3_PLUS1:
+	case RT5670_MP3_PLUS2:
+	case RT5670_ADJ_HPF1:
+	case RT5670_ADJ_HPF2:
+	case RT5670_HP_CALIB_AMP_DET:
+	case RT5670_SV_ZCD1:
+	case RT5670_SV_ZCD2:
+	case RT5670_IL_CMD:
+	case RT5670_IL_CMD2:
+	case RT5670_IL_CMD3:
+	case RT5670_DRC_HL_CTRL1:
+	case RT5670_DRC_HL_CTRL2:
+	case RT5670_ADC_MONO_HP_CTRL1:
+	case RT5670_ADC_MONO_HP_CTRL2:
+	case RT5670_ADC_STO2_HP_CTRL1:
+	case RT5670_ADC_STO2_HP_CTRL2:
+	case RT5670_JD_CTRL3:
+	case RT5670_JD_CTRL4:
+	case RT5670_DIG_MISC:
+	case RT5670_DSP_CTRL1:
+	case RT5670_DSP_CTRL2:
+	case RT5670_DSP_CTRL3:
+	case RT5670_DSP_CTRL4:
+	case RT5670_DSP_CTRL5:
+	case RT5670_GEN_CTRL2:
+	case RT5670_GEN_CTRL3:
+	case RT5670_VENDOR_ID:
+	case RT5670_VENDOR_ID1:
+	case RT5670_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/**
+ * rt5670_headset_detect - Detect headset.
+ * @component: SoC audio component device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+
+static int rt5670_headset_detect(struct snd_soc_component *component, int jack_insert)
+{
+	int val;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+
+	if (jack_insert) {
+		snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power");
+		snd_soc_dapm_sync(dapm);
+		snd_soc_component_update_bits(component, RT5670_GEN_CTRL3, 0x4, 0x0);
+		snd_soc_component_update_bits(component, RT5670_CJ_CTRL2,
+			RT5670_CBJ_DET_MODE | RT5670_CBJ_MN_JD,
+			RT5670_CBJ_MN_JD);
+		snd_soc_component_write(component, RT5670_GPIO_CTRL2, 0x0004);
+		snd_soc_component_update_bits(component, RT5670_GPIO_CTRL1,
+			RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ);
+		snd_soc_component_update_bits(component, RT5670_CJ_CTRL1,
+			RT5670_CBJ_BST1_EN, RT5670_CBJ_BST1_EN);
+		snd_soc_component_write(component, RT5670_JD_CTRL3, 0x00f0);
+		snd_soc_component_update_bits(component, RT5670_CJ_CTRL2,
+			RT5670_CBJ_MN_JD, RT5670_CBJ_MN_JD);
+		snd_soc_component_update_bits(component, RT5670_CJ_CTRL2,
+			RT5670_CBJ_MN_JD, 0);
+		msleep(300);
+		val = snd_soc_component_read32(component, RT5670_CJ_CTRL3) & 0x7;
+		if (val == 0x1 || val == 0x2) {
+			rt5670->jack_type = SND_JACK_HEADSET;
+			/* for push button */
+			snd_soc_component_update_bits(component, RT5670_INT_IRQ_ST, 0x8, 0x8);
+			snd_soc_component_update_bits(component, RT5670_IL_CMD, 0x40, 0x40);
+			snd_soc_component_read32(component, RT5670_IL_CMD);
+		} else {
+			snd_soc_component_update_bits(component, RT5670_GEN_CTRL3, 0x4, 0x4);
+			rt5670->jack_type = SND_JACK_HEADPHONE;
+			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+			snd_soc_dapm_sync(dapm);
+		}
+	} else {
+		snd_soc_component_update_bits(component, RT5670_INT_IRQ_ST, 0x8, 0x0);
+		snd_soc_component_update_bits(component, RT5670_GEN_CTRL3, 0x4, 0x4);
+		rt5670->jack_type = 0;
+		snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+		snd_soc_dapm_sync(dapm);
+	}
+
+	return rt5670->jack_type;
+}
+
+void rt5670_jack_suspend(struct snd_soc_component *component)
+{
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+
+	rt5670->jack_type_saved = rt5670->jack_type;
+	rt5670_headset_detect(component, 0);
+}
+EXPORT_SYMBOL_GPL(rt5670_jack_suspend);
+
+void rt5670_jack_resume(struct snd_soc_component *component)
+{
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+
+	if (rt5670->jack_type_saved)
+		rt5670_headset_detect(component, 1);
+}
+EXPORT_SYMBOL_GPL(rt5670_jack_resume);
+
+static int rt5670_button_detect(struct snd_soc_component *component)
+{
+	int btn_type, val;
+
+	val = snd_soc_component_read32(component, RT5670_IL_CMD);
+	btn_type = val & 0xff80;
+	snd_soc_component_write(component, RT5670_IL_CMD, val);
+	if (btn_type != 0) {
+		msleep(20);
+		val = snd_soc_component_read32(component, RT5670_IL_CMD);
+		snd_soc_component_write(component, RT5670_IL_CMD, val);
+	}
+
+	return btn_type;
+}
+
+static int rt5670_irq_detection(void *data)
+{
+	struct rt5670_priv *rt5670 = (struct rt5670_priv *)data;
+	struct snd_soc_jack_gpio *gpio = &rt5670->hp_gpio;
+	struct snd_soc_jack *jack = rt5670->jack;
+	int val, btn_type, report = jack->status;
+
+	if (rt5670->pdata.jd_mode == 1) /* 2 port */
+		val = snd_soc_component_read32(rt5670->component, RT5670_A_JD_CTRL1) & 0x0070;
+	else
+		val = snd_soc_component_read32(rt5670->component, RT5670_A_JD_CTRL1) & 0x0020;
+
+	switch (val) {
+	/* jack in */
+	case 0x30: /* 2 port */
+	case 0x0: /* 1 port or 2 port */
+		if (rt5670->jack_type == 0) {
+			report = rt5670_headset_detect(rt5670->component, 1);
+			/* for push button and jack out */
+			gpio->debounce_time = 25;
+			break;
+		}
+		btn_type = 0;
+		if (snd_soc_component_read32(rt5670->component, RT5670_INT_IRQ_ST) & 0x4) {
+			/* button pressed */
+			report = SND_JACK_HEADSET;
+			btn_type = rt5670_button_detect(rt5670->component);
+			switch (btn_type) {
+			case 0x2000: /* up */
+				report |= SND_JACK_BTN_1;
+				break;
+			case 0x0400: /* center */
+				report |= SND_JACK_BTN_0;
+				break;
+			case 0x0080: /* down */
+				report |= SND_JACK_BTN_2;
+				break;
+			default:
+				dev_err(rt5670->component->dev,
+					"Unexpected button code 0x%04x\n",
+					btn_type);
+				break;
+			}
+		}
+		if (btn_type == 0)/* button release */
+			report =  rt5670->jack_type;
+
+		break;
+	/* jack out */
+	case 0x70: /* 2 port */
+	case 0x10: /* 2 port */
+	case 0x20: /* 1 port */
+		report = 0;
+		snd_soc_component_update_bits(rt5670->component, RT5670_INT_IRQ_ST, 0x1, 0x0);
+		rt5670_headset_detect(rt5670->component, 0);
+		gpio->debounce_time = 150; /* for jack in */
+		break;
+	default:
+		break;
+	}
+
+	return report;
+}
+
+int rt5670_set_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *jack)
+{
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	rt5670->jack = jack;
+	rt5670->hp_gpio.gpiod_dev = component->dev;
+	rt5670->hp_gpio.name = "headset";
+	rt5670->hp_gpio.report = SND_JACK_HEADSET |
+		SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2;
+	rt5670->hp_gpio.debounce_time = 150;
+	rt5670->hp_gpio.wake = true;
+	rt5670->hp_gpio.data = (struct rt5670_priv *)rt5670;
+	rt5670->hp_gpio.jack_status_check = rt5670_irq_detection;
+
+	ret = snd_soc_jack_add_gpios(rt5670->jack, 1,
+			&rt5670->hp_gpio);
+	if (ret) {
+		dev_err(component->dev, "Adding jack GPIO failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5670_set_jack_detect);
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+/* Interface data select */
+static const char * const rt5670_data_select[] = {
+	"Normal", "Swap", "left copy to right", "right copy to left"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_if2_dac_enum, RT5670_DIG_INF1_DATA,
+				RT5670_IF2_DAC_SEL_SFT, rt5670_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5670_if2_adc_enum, RT5670_DIG_INF1_DATA,
+				RT5670_IF2_ADC_SEL_SFT, rt5670_data_select);
+
+static const struct snd_kcontrol_new rt5670_snd_controls[] = {
+	/* Headphone Output Volume */
+	SOC_DOUBLE("HP Playback Switch", RT5670_HP_VOL,
+		RT5670_L_MUTE_SFT, RT5670_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("HP Playback Volume", RT5670_HP_VOL,
+		RT5670_L_VOL_SFT, RT5670_R_VOL_SFT,
+		39, 1, out_vol_tlv),
+	/* OUTPUT Control */
+	SOC_DOUBLE("OUT Channel Switch", RT5670_LOUT1,
+		RT5670_VOL_L_SFT, RT5670_VOL_R_SFT, 1, 1),
+	SOC_DOUBLE_TLV("OUT Playback Volume", RT5670_LOUT1,
+		RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, 39, 1, out_vol_tlv),
+	/* DAC Digital Volume */
+	SOC_DOUBLE("DAC2 Playback Switch", RT5670_DAC_CTRL,
+		RT5670_M_DAC_L2_VOL_SFT, RT5670_M_DAC_R2_VOL_SFT, 1, 1),
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5670_DAC1_DIG_VOL,
+			RT5670_L_VOL_SFT, RT5670_R_VOL_SFT,
+			175, 0, dac_vol_tlv),
+	SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5670_DAC2_DIG_VOL,
+			RT5670_L_VOL_SFT, RT5670_R_VOL_SFT,
+			175, 0, dac_vol_tlv),
+	/* IN1/IN2 Control */
+	SOC_SINGLE_TLV("IN1 Boost Volume", RT5670_CJ_CTRL1,
+		RT5670_BST_SFT1, 8, 0, bst_tlv),
+	SOC_SINGLE_TLV("IN2 Boost Volume", RT5670_IN2,
+		RT5670_BST_SFT1, 8, 0, bst_tlv),
+	/* INL/INR Volume Control */
+	SOC_DOUBLE_TLV("IN Capture Volume", RT5670_INL1_INR1_VOL,
+			RT5670_INL_VOL_SFT, RT5670_INR_VOL_SFT,
+			31, 1, in_vol_tlv),
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("ADC Capture Switch", RT5670_STO1_ADC_DIG_VOL,
+		RT5670_L_MUTE_SFT, RT5670_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("ADC Capture Volume", RT5670_STO1_ADC_DIG_VOL,
+			RT5670_L_VOL_SFT, RT5670_R_VOL_SFT,
+			127, 0, adc_vol_tlv),
+
+	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5670_MONO_ADC_DIG_VOL,
+			RT5670_L_VOL_SFT, RT5670_R_VOL_SFT,
+			127, 0, adc_vol_tlv),
+
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5670_ADC_BST_VOL1,
+			RT5670_STO1_ADC_L_BST_SFT, RT5670_STO1_ADC_R_BST_SFT,
+			3, 0, adc_bst_tlv),
+
+	SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5670_ADC_BST_VOL1,
+			RT5670_STO2_ADC_L_BST_SFT, RT5670_STO2_ADC_R_BST_SFT,
+			3, 0, adc_bst_tlv),
+
+	SOC_ENUM("ADC IF2 Data Switch", rt5670_if2_adc_enum),
+	SOC_ENUM("DAC IF2 Data Switch", rt5670_if2_dac_enum),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+	int idx, rate;
+
+	rate = rt5670->sysclk / rl6231_get_pre_div(rt5670->regmap,
+		RT5670_ADDA_CLK1, RT5670_I2S_PD1_SFT);
+	idx = rl6231_calc_dmic_clk(rate);
+	if (idx < 0)
+		dev_err(component->dev, "Failed to set DMIC clock\n");
+	else
+		snd_soc_component_update_bits(component, RT5670_DMIC_CTRL1,
+			RT5670_DMIC_CLK_MASK, idx << RT5670_DMIC_CLK_SFT);
+	return idx;
+}
+
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+
+	if (rt5670->sysclk_src == RT5670_SCLK_S_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int is_using_asrc(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	unsigned int reg, shift, val;
+
+	switch (source->shift) {
+	case 0:
+		reg = RT5670_ASRC_3;
+		shift = 0;
+		break;
+	case 1:
+		reg = RT5670_ASRC_3;
+		shift = 4;
+		break;
+	case 2:
+		reg = RT5670_ASRC_5;
+		shift = 12;
+		break;
+	case 3:
+		reg = RT5670_ASRC_2;
+		shift = 0;
+		break;
+	case 8:
+		reg = RT5670_ASRC_2;
+		shift = 4;
+		break;
+	case 9:
+		reg = RT5670_ASRC_2;
+		shift = 8;
+		break;
+	case 10:
+		reg = RT5670_ASRC_2;
+		shift = 12;
+		break;
+	default:
+		return 0;
+	}
+
+	val = (snd_soc_component_read32(component, reg) >> shift) & 0xf;
+	switch (val) {
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+		return 1;
+	default:
+		return 0;
+	}
+
+}
+
+static int can_use_asrc(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+
+	if (rt5670->sysclk > rt5670->lrck[RT5670_AIF1] * 384)
+		return 1;
+
+	return 0;
+}
+
+
+/**
+ * rt5670_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @component: SoC audio component device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5670 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5670_sel_asrc_clk_src(struct snd_soc_component *component,
+			    unsigned int filter_mask, unsigned int clk_src)
+{
+	unsigned int asrc2_mask = 0, asrc2_value = 0;
+	unsigned int asrc3_mask = 0, asrc3_value = 0;
+
+	if (clk_src > RT5670_CLK_SEL_SYS3)
+		return -EINVAL;
+
+	if (filter_mask & RT5670_DA_STEREO_FILTER) {
+		asrc2_mask |= RT5670_DA_STO_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5670_DA_STO_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_DA_STO_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5670_DA_MONO_L_FILTER) {
+		asrc2_mask |= RT5670_DA_MONOL_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5670_DA_MONOL_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_DA_MONOL_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5670_DA_MONO_R_FILTER) {
+		asrc2_mask |= RT5670_DA_MONOR_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5670_DA_MONOR_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_DA_MONOR_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5670_AD_STEREO_FILTER) {
+		asrc2_mask |= RT5670_AD_STO1_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5670_AD_STO1_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_AD_STO1_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5670_AD_MONO_L_FILTER) {
+		asrc3_mask |= RT5670_AD_MONOL_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5670_AD_MONOL_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_AD_MONOL_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5670_AD_MONO_R_FILTER)  {
+		asrc3_mask |= RT5670_AD_MONOR_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5670_AD_MONOR_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_AD_MONOR_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5670_UP_RATE_FILTER) {
+		asrc3_mask |= RT5670_UP_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5670_UP_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_UP_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5670_DOWN_RATE_FILTER) {
+		asrc3_mask |= RT5670_DOWN_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5670_DOWN_CLK_SEL_MASK)
+				| (clk_src <<  RT5670_DOWN_CLK_SEL_SFT);
+	}
+
+	if (asrc2_mask)
+		snd_soc_component_update_bits(component, RT5670_ASRC_2,
+				    asrc2_mask, asrc2_value);
+
+	if (asrc3_mask)
+		snd_soc_component_update_bits(component, RT5670_ASRC_3,
+				    asrc3_mask, asrc3_value);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5670_sel_asrc_clk_src);
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER,
+			RT5670_M_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5670_STO1_ADC_MIXER,
+			RT5670_M_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER,
+			RT5670_M_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5670_STO1_ADC_MIXER,
+			RT5670_M_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_sto2_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO2_ADC_MIXER,
+			RT5670_M_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5670_STO2_ADC_MIXER,
+			RT5670_M_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_sto2_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO2_ADC_MIXER,
+			RT5670_M_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5670_STO2_ADC_MIXER,
+			RT5670_M_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_mono_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5670_MONO_ADC_MIXER,
+			RT5670_M_MONO_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5670_MONO_ADC_MIXER,
+			RT5670_M_MONO_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_mono_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5670_MONO_ADC_MIXER,
+			RT5670_M_MONO_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5670_MONO_ADC_MIXER,
+			RT5670_M_MONO_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5670_AD_DA_MIXER,
+			RT5670_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5670_AD_DA_MIXER,
+			RT5670_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5670_AD_DA_MIXER,
+			RT5670_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5670_AD_DA_MIXER,
+			RT5670_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_sto_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_STO_DAC_MIXER,
+			RT5670_M_DAC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5670_STO_DAC_MIXER,
+			RT5670_M_DAC_L2_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_STO_DAC_MIXER,
+			RT5670_M_DAC_R1_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_sto_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_STO_DAC_MIXER,
+			RT5670_M_DAC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5670_STO_DAC_MIXER,
+			RT5670_M_DAC_R2_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_STO_DAC_MIXER,
+			RT5670_M_DAC_L1_STO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_mono_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_DD_MIXER,
+			RT5670_M_DAC_L1_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5670_DD_MIXER,
+			RT5670_M_DAC_L2_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5670_DD_MIXER,
+			RT5670_M_DAC_R2_MONO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_mono_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_DD_MIXER,
+			RT5670_M_DAC_R1_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5670_DD_MIXER,
+			RT5670_M_DAC_R2_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5670_DD_MIXER,
+			RT5670_M_DAC_L2_MONO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_dig_l_mix[] = {
+	SOC_DAPM_SINGLE("Sto DAC Mix L Switch", RT5670_DIG_MIXER,
+			RT5670_M_STO_L_DAC_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5670_DIG_MIXER,
+			RT5670_M_DAC_L2_DAC_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5670_DIG_MIXER,
+			RT5670_M_DAC_R2_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_dig_r_mix[] = {
+	SOC_DAPM_SINGLE("Sto DAC Mix R Switch", RT5670_DIG_MIXER,
+			RT5670_M_STO_R_DAC_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5670_DIG_MIXER,
+			RT5670_M_DAC_R2_DAC_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5670_DIG_MIXER,
+			RT5670_M_DAC_L2_DAC_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5670_rec_l_mix[] = {
+	SOC_DAPM_SINGLE("INL Switch", RT5670_REC_L2_MIXER,
+			RT5670_M_IN_L_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5670_REC_L2_MIXER,
+			RT5670_M_BST2_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5670_REC_L2_MIXER,
+			RT5670_M_BST1_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_rec_r_mix[] = {
+	SOC_DAPM_SINGLE("INR Switch", RT5670_REC_R2_MIXER,
+			RT5670_M_IN_R_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5670_REC_R2_MIXER,
+			RT5670_M_BST2_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5670_REC_R2_MIXER,
+			RT5670_M_BST1_RM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_out_l_mix[] = {
+	SOC_DAPM_SINGLE("BST1 Switch", RT5670_OUT_L1_MIXER,
+			RT5670_M_BST1_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5670_OUT_L1_MIXER,
+			RT5670_M_IN_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5670_OUT_L1_MIXER,
+			RT5670_M_DAC_L2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_OUT_L1_MIXER,
+			RT5670_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_out_r_mix[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5670_OUT_R1_MIXER,
+			RT5670_M_BST2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5670_OUT_R1_MIXER,
+			RT5670_M_IN_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5670_OUT_R1_MIXER,
+			RT5670_M_DAC_R2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_OUT_R1_MIXER,
+			RT5670_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_hpo_mix[] = {
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5670_HPO_MIXER,
+			RT5670_M_DAC1_HM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("HPVOL Switch", RT5670_HPO_MIXER,
+			RT5670_M_HPVOL_HM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_hpvoll_mix[] = {
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5670_HPO_MIXER,
+			RT5670_M_DACL1_HML_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5670_HPO_MIXER,
+			RT5670_M_INL1_HML_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_hpvolr_mix[] = {
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5670_HPO_MIXER,
+			RT5670_M_DACR1_HMR_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5670_HPO_MIXER,
+			RT5670_M_INR1_HMR_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_lout_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_LOUT_MIXER,
+			RT5670_M_DAC_L1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_LOUT_MIXER,
+			RT5670_M_DAC_R1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTMIX L Switch", RT5670_LOUT_MIXER,
+			RT5670_M_OV_L_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTMIX R Switch", RT5670_LOUT_MIXER,
+			RT5670_M_OV_R_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_hpl_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_HPO_MIXER,
+			RT5670_M_DACL1_HML_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL1 Switch", RT5670_HPO_MIXER,
+			RT5670_M_INL1_HML_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5670_hpr_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_HPO_MIXER,
+			RT5670_M_DACR1_HMR_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR1 Switch", RT5670_HPO_MIXER,
+			RT5670_M_INR1_HMR_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new lout_l_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5670_LOUT1,
+		RT5670_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_r_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5670_LOUT1,
+		RT5670_R_MUTE_SFT, 1, 1);
+
+/* DAC1 L/R source */ /* MX-29 [9:8] [11:10] */
+static const char * const rt5670_dac1_src[] = {
+	"IF1 DAC", "IF2 DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_dac1l_enum, RT5670_AD_DA_MIXER,
+	RT5670_DAC1_L_SEL_SFT, rt5670_dac1_src);
+
+static const struct snd_kcontrol_new rt5670_dac1l_mux =
+	SOC_DAPM_ENUM("DAC1 L source", rt5670_dac1l_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5670_dac1r_enum, RT5670_AD_DA_MIXER,
+	RT5670_DAC1_R_SEL_SFT, rt5670_dac1_src);
+
+static const struct snd_kcontrol_new rt5670_dac1r_mux =
+	SOC_DAPM_ENUM("DAC1 R source", rt5670_dac1r_enum);
+
+/*DAC2 L/R source*/ /* MX-1B [6:4] [2:0] */
+/* TODO Use SOC_VALUE_ENUM_SINGLE_DECL */
+static const char * const rt5670_dac12_src[] = {
+	"IF1 DAC", "IF2 DAC", "IF3 DAC", "TxDC DAC",
+	"Bass", "VAD_ADC", "IF4 DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_dac2l_enum, RT5670_DAC_CTRL,
+	RT5670_DAC2_L_SEL_SFT, rt5670_dac12_src);
+
+static const struct snd_kcontrol_new rt5670_dac_l2_mux =
+	SOC_DAPM_ENUM("DAC2 L source", rt5670_dac2l_enum);
+
+static const char * const rt5670_dacr2_src[] = {
+	"IF1 DAC", "IF2 DAC", "IF3 DAC", "TxDC DAC", "TxDP ADC", "IF4 DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_dac2r_enum, RT5670_DAC_CTRL,
+	RT5670_DAC2_R_SEL_SFT, rt5670_dacr2_src);
+
+static const struct snd_kcontrol_new rt5670_dac_r2_mux =
+	SOC_DAPM_ENUM("DAC2 R source", rt5670_dac2r_enum);
+
+/*RxDP source*/ /* MX-2D [15:13] */
+static const char * const rt5670_rxdp_src[] = {
+	"IF2 DAC", "IF1 DAC", "STO1 ADC Mixer", "STO2 ADC Mixer",
+	"Mono ADC Mixer L", "Mono ADC Mixer R", "DAC1"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_rxdp_enum, RT5670_DSP_PATH1,
+	RT5670_RXDP_SEL_SFT, rt5670_rxdp_src);
+
+static const struct snd_kcontrol_new rt5670_rxdp_mux =
+	SOC_DAPM_ENUM("DAC2 L source", rt5670_rxdp_enum);
+
+/* MX-2D [1] [0] */
+static const char * const rt5670_dsp_bypass_src[] = {
+	"DSP", "Bypass"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_dsp_ul_enum, RT5670_DSP_PATH1,
+	RT5670_DSP_UL_SFT, rt5670_dsp_bypass_src);
+
+static const struct snd_kcontrol_new rt5670_dsp_ul_mux =
+	SOC_DAPM_ENUM("DSP UL source", rt5670_dsp_ul_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5670_dsp_dl_enum, RT5670_DSP_PATH1,
+	RT5670_DSP_DL_SFT, rt5670_dsp_bypass_src);
+
+static const struct snd_kcontrol_new rt5670_dsp_dl_mux =
+	SOC_DAPM_ENUM("DSP DL source", rt5670_dsp_dl_enum);
+
+/* Stereo2 ADC source */
+/* MX-26 [15] */
+static const char * const rt5670_stereo2_adc_lr_src[] = {
+	"L", "LR"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc_lr_enum, RT5670_STO2_ADC_MIXER,
+	RT5670_STO2_ADC_SRC_SFT, rt5670_stereo2_adc_lr_src);
+
+static const struct snd_kcontrol_new rt5670_sto2_adc_lr_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC LR source", rt5670_stereo2_adc_lr_enum);
+
+/* Stereo1 ADC source */
+/* MX-27 MX-26 [12] */
+static const char * const rt5670_stereo_adc1_src[] = {
+	"DAC MIX", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc1_enum, RT5670_STO1_ADC_MIXER,
+	RT5670_ADC_1_SRC_SFT, rt5670_stereo_adc1_src);
+
+static const struct snd_kcontrol_new rt5670_sto_adc_1_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC 1 Mux", rt5670_stereo1_adc1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc1_enum, RT5670_STO2_ADC_MIXER,
+	RT5670_ADC_1_SRC_SFT, rt5670_stereo_adc1_src);
+
+static const struct snd_kcontrol_new rt5670_sto2_adc_1_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC 1 Mux", rt5670_stereo2_adc1_enum);
+
+
+/* MX-27 MX-26 [11] */
+static const char * const rt5670_stereo_adc2_src[] = {
+	"DAC MIX", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc2_enum, RT5670_STO1_ADC_MIXER,
+	RT5670_ADC_2_SRC_SFT, rt5670_stereo_adc2_src);
+
+static const struct snd_kcontrol_new rt5670_sto_adc_2_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC 2 Mux", rt5670_stereo1_adc2_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc2_enum, RT5670_STO2_ADC_MIXER,
+	RT5670_ADC_2_SRC_SFT, rt5670_stereo_adc2_src);
+
+static const struct snd_kcontrol_new rt5670_sto2_adc_2_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC 2 Mux", rt5670_stereo2_adc2_enum);
+
+
+/* MX-27 MX26 [10] */
+static const char * const rt5670_stereo_adc_src[] = {
+	"ADC1L ADC2R", "ADC3"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc_enum, RT5670_STO1_ADC_MIXER,
+	RT5670_ADC_SRC_SFT, rt5670_stereo_adc_src);
+
+static const struct snd_kcontrol_new rt5670_sto_adc_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC source", rt5670_stereo1_adc_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc_enum, RT5670_STO2_ADC_MIXER,
+	RT5670_ADC_SRC_SFT, rt5670_stereo_adc_src);
+
+static const struct snd_kcontrol_new rt5670_sto2_adc_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC source", rt5670_stereo2_adc_enum);
+
+/* MX-27 MX-26 [9:8] */
+static const char * const rt5670_stereo_dmic_src[] = {
+	"DMIC1", "DMIC2", "DMIC3"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_dmic_enum, RT5670_STO1_ADC_MIXER,
+	RT5670_DMIC_SRC_SFT, rt5670_stereo_dmic_src);
+
+static const struct snd_kcontrol_new rt5670_sto1_dmic_mux =
+	SOC_DAPM_ENUM("Stereo1 DMIC source", rt5670_stereo1_dmic_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_dmic_enum, RT5670_STO2_ADC_MIXER,
+	RT5670_DMIC_SRC_SFT, rt5670_stereo_dmic_src);
+
+static const struct snd_kcontrol_new rt5670_sto2_dmic_mux =
+	SOC_DAPM_ENUM("Stereo2 DMIC source", rt5670_stereo2_dmic_enum);
+
+/* MX-27 [0] */
+static const char * const rt5670_stereo_dmic3_src[] = {
+	"DMIC3", "PDM ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_stereo_dmic3_enum, RT5670_STO1_ADC_MIXER,
+	RT5670_DMIC3_SRC_SFT, rt5670_stereo_dmic3_src);
+
+static const struct snd_kcontrol_new rt5670_sto_dmic3_mux =
+	SOC_DAPM_ENUM("Stereo DMIC3 source", rt5670_stereo_dmic3_enum);
+
+/* Mono ADC source */
+/* MX-28 [12] */
+static const char * const rt5670_mono_adc_l1_src[] = {
+	"Mono DAC MIXL", "ADC1"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_mono_adc_l1_enum, RT5670_MONO_ADC_MIXER,
+	RT5670_MONO_ADC_L1_SRC_SFT, rt5670_mono_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5670_mono_adc_l1_mux =
+	SOC_DAPM_ENUM("Mono ADC1 left source", rt5670_mono_adc_l1_enum);
+/* MX-28 [11] */
+static const char * const rt5670_mono_adc_l2_src[] = {
+	"Mono DAC MIXL", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_mono_adc_l2_enum, RT5670_MONO_ADC_MIXER,
+	RT5670_MONO_ADC_L2_SRC_SFT, rt5670_mono_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5670_mono_adc_l2_mux =
+	SOC_DAPM_ENUM("Mono ADC2 left source", rt5670_mono_adc_l2_enum);
+
+/* MX-28 [9:8] */
+static const char * const rt5670_mono_dmic_src[] = {
+	"DMIC1", "DMIC2", "DMIC3"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_mono_dmic_l_enum, RT5670_MONO_ADC_MIXER,
+	RT5670_MONO_DMIC_L_SRC_SFT, rt5670_mono_dmic_src);
+
+static const struct snd_kcontrol_new rt5670_mono_dmic_l_mux =
+	SOC_DAPM_ENUM("Mono DMIC left source", rt5670_mono_dmic_l_enum);
+/* MX-28 [1:0] */
+static SOC_ENUM_SINGLE_DECL(rt5670_mono_dmic_r_enum, RT5670_MONO_ADC_MIXER,
+	RT5670_MONO_DMIC_R_SRC_SFT, rt5670_mono_dmic_src);
+
+static const struct snd_kcontrol_new rt5670_mono_dmic_r_mux =
+	SOC_DAPM_ENUM("Mono DMIC Right source", rt5670_mono_dmic_r_enum);
+/* MX-28 [4] */
+static const char * const rt5670_mono_adc_r1_src[] = {
+	"Mono DAC MIXR", "ADC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_mono_adc_r1_enum, RT5670_MONO_ADC_MIXER,
+	RT5670_MONO_ADC_R1_SRC_SFT, rt5670_mono_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5670_mono_adc_r1_mux =
+	SOC_DAPM_ENUM("Mono ADC1 right source", rt5670_mono_adc_r1_enum);
+/* MX-28 [3] */
+static const char * const rt5670_mono_adc_r2_src[] = {
+	"Mono DAC MIXR", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_mono_adc_r2_enum, RT5670_MONO_ADC_MIXER,
+	RT5670_MONO_ADC_R2_SRC_SFT, rt5670_mono_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5670_mono_adc_r2_mux =
+	SOC_DAPM_ENUM("Mono ADC2 right source", rt5670_mono_adc_r2_enum);
+
+/* MX-2D [3:2] */
+static const char * const rt5670_txdp_slot_src[] = {
+	"Slot 0-1", "Slot 2-3", "Slot 4-5", "Slot 6-7"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_txdp_slot_enum, RT5670_DSP_PATH1,
+	RT5670_TXDP_SLOT_SEL_SFT, rt5670_txdp_slot_src);
+
+static const struct snd_kcontrol_new rt5670_txdp_slot_mux =
+	SOC_DAPM_ENUM("TxDP Slot source", rt5670_txdp_slot_enum);
+
+/* MX-2F [15] */
+static const char * const rt5670_if1_adc2_in_src[] = {
+	"IF_ADC2", "VAD_ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_if1_adc2_in_enum, RT5670_DIG_INF1_DATA,
+	RT5670_IF1_ADC2_IN_SFT, rt5670_if1_adc2_in_src);
+
+static const struct snd_kcontrol_new rt5670_if1_adc2_in_mux =
+	SOC_DAPM_ENUM("IF1 ADC2 IN source", rt5670_if1_adc2_in_enum);
+
+/* MX-2F [14:12] */
+static const char * const rt5670_if2_adc_in_src[] = {
+	"IF_ADC1", "IF_ADC2", "IF_ADC3", "TxDC_DAC", "TxDP_ADC", "VAD_ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_if2_adc_in_enum, RT5670_DIG_INF1_DATA,
+	RT5670_IF2_ADC_IN_SFT, rt5670_if2_adc_in_src);
+
+static const struct snd_kcontrol_new rt5670_if2_adc_in_mux =
+	SOC_DAPM_ENUM("IF2 ADC IN source", rt5670_if2_adc_in_enum);
+
+/* MX-30 [5:4] */
+static const char * const rt5670_if4_adc_in_src[] = {
+	"IF_ADC1", "IF_ADC2", "IF_ADC3"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_if4_adc_in_enum, RT5670_DIG_INF2_DATA,
+	RT5670_IF4_ADC_IN_SFT, rt5670_if4_adc_in_src);
+
+static const struct snd_kcontrol_new rt5670_if4_adc_in_mux =
+	SOC_DAPM_ENUM("IF4 ADC IN source", rt5670_if4_adc_in_enum);
+
+/* MX-31 [15] [13] [11] [9] */
+static const char * const rt5670_pdm_src[] = {
+	"Mono DAC", "Stereo DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_pdm1_l_enum, RT5670_PDM_OUT_CTRL,
+	RT5670_PDM1_L_SFT, rt5670_pdm_src);
+
+static const struct snd_kcontrol_new rt5670_pdm1_l_mux =
+	SOC_DAPM_ENUM("PDM1 L source", rt5670_pdm1_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5670_pdm1_r_enum, RT5670_PDM_OUT_CTRL,
+	RT5670_PDM1_R_SFT, rt5670_pdm_src);
+
+static const struct snd_kcontrol_new rt5670_pdm1_r_mux =
+	SOC_DAPM_ENUM("PDM1 R source", rt5670_pdm1_r_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5670_pdm2_l_enum, RT5670_PDM_OUT_CTRL,
+	RT5670_PDM2_L_SFT, rt5670_pdm_src);
+
+static const struct snd_kcontrol_new rt5670_pdm2_l_mux =
+	SOC_DAPM_ENUM("PDM2 L source", rt5670_pdm2_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5670_pdm2_r_enum, RT5670_PDM_OUT_CTRL,
+	RT5670_PDM2_R_SFT, rt5670_pdm_src);
+
+static const struct snd_kcontrol_new rt5670_pdm2_r_mux =
+	SOC_DAPM_ENUM("PDM2 R source", rt5670_pdm2_r_enum);
+
+/* MX-FA [12] */
+static const char * const rt5670_if1_adc1_in1_src[] = {
+	"IF_ADC1", "IF1_ADC3"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_if1_adc1_in1_enum, RT5670_DIG_MISC,
+	RT5670_IF1_ADC1_IN1_SFT, rt5670_if1_adc1_in1_src);
+
+static const struct snd_kcontrol_new rt5670_if1_adc1_in1_mux =
+	SOC_DAPM_ENUM("IF1 ADC1 IN1 source", rt5670_if1_adc1_in1_enum);
+
+/* MX-FA [11] */
+static const char * const rt5670_if1_adc1_in2_src[] = {
+	"IF1_ADC1_IN1", "IF1_ADC4"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_if1_adc1_in2_enum, RT5670_DIG_MISC,
+	RT5670_IF1_ADC1_IN2_SFT, rt5670_if1_adc1_in2_src);
+
+static const struct snd_kcontrol_new rt5670_if1_adc1_in2_mux =
+	SOC_DAPM_ENUM("IF1 ADC1 IN2 source", rt5670_if1_adc1_in2_enum);
+
+/* MX-FA [10] */
+static const char * const rt5670_if1_adc2_in1_src[] = {
+	"IF1_ADC2_IN", "IF1_ADC4"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_if1_adc2_in1_enum, RT5670_DIG_MISC,
+	RT5670_IF1_ADC2_IN1_SFT, rt5670_if1_adc2_in1_src);
+
+static const struct snd_kcontrol_new rt5670_if1_adc2_in1_mux =
+	SOC_DAPM_ENUM("IF1 ADC2 IN1 source", rt5670_if1_adc2_in1_enum);
+
+/* MX-9D [9:8] */
+static const char * const rt5670_vad_adc_src[] = {
+	"Sto1 ADC L", "Mono ADC L", "Mono ADC R", "Sto2 ADC L"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5670_vad_adc_enum, RT5670_VAD_CTRL4,
+	RT5670_VAD_SEL_SFT, rt5670_vad_adc_src);
+
+static const struct snd_kcontrol_new rt5670_vad_adc_mux =
+	SOC_DAPM_ENUM("VAD ADC source", rt5670_vad_adc_enum);
+
+static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(rt5670->regmap, RT5670_CHARGE_PUMP,
+			RT5670_PM_HP_MASK, RT5670_PM_HP_HV);
+		regmap_update_bits(rt5670->regmap, RT5670_GEN_CTRL2,
+			0x0400, 0x0400);
+		/* headphone amp power on */
+		regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1,
+			RT5670_PWR_HA |	RT5670_PWR_FV1 |
+			RT5670_PWR_FV2,	RT5670_PWR_HA |
+			RT5670_PWR_FV1 | RT5670_PWR_FV2);
+		/* depop parameters */
+		regmap_write(rt5670->regmap, RT5670_DEPOP_M2, 0x3100);
+		regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x8009);
+		regmap_write(rt5670->regmap, RT5670_PR_BASE +
+			RT5670_HP_DCC_INT1, 0x9f00);
+		mdelay(20);
+		regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x8019);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x0004);
+		msleep(30);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5670_hp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* headphone unmute sequence */
+		regmap_write(rt5670->regmap, RT5670_PR_BASE +
+				RT5670_MAMP_INT_REG2, 0xb400);
+		regmap_write(rt5670->regmap, RT5670_DEPOP_M3, 0x0772);
+		regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x805d);
+		regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x831d);
+		regmap_update_bits(rt5670->regmap, RT5670_GEN_CTRL2,
+				0x0300, 0x0300);
+		regmap_update_bits(rt5670->regmap, RT5670_HP_VOL,
+			RT5670_L_MUTE | RT5670_R_MUTE, 0);
+		msleep(80);
+		regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x8019);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		/* headphone mute sequence */
+		regmap_write(rt5670->regmap, RT5670_PR_BASE +
+				RT5670_MAMP_INT_REG2, 0xb400);
+		regmap_write(rt5670->regmap, RT5670_DEPOP_M3, 0x0772);
+		regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x803d);
+		mdelay(10);
+		regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x831d);
+		mdelay(10);
+		regmap_update_bits(rt5670->regmap, RT5670_HP_VOL,
+				   RT5670_L_MUTE | RT5670_R_MUTE,
+				   RT5670_L_MUTE | RT5670_R_MUTE);
+		msleep(20);
+		regmap_update_bits(rt5670->regmap,
+				   RT5670_GEN_CTRL2, 0x0300, 0x0);
+		regmap_write(rt5670->regmap, RT5670_DEPOP_M1, 0x8019);
+		regmap_write(rt5670->regmap, RT5670_DEPOP_M3, 0x0707);
+		regmap_write(rt5670->regmap, RT5670_PR_BASE +
+				RT5670_MAMP_INT_REG2, 0xfc00);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5670_bst1_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5670_PWR_ANLG2,
+				    RT5670_PWR_BST1_P, RT5670_PWR_BST1_P);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5670_PWR_ANLG2,
+				    RT5670_PWR_BST1_P, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5670_bst2_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, RT5670_PWR_ANLG2,
+				    RT5670_PWR_BST2_P, RT5670_PWR_BST2_P);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, RT5670_PWR_ANLG2,
+				    RT5670_PWR_BST2_P, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("PLL1", RT5670_PWR_ANLG2,
+			    RT5670_PWR_PLL_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("I2S DSP", RT5670_PWR_DIG2,
+			    RT5670_PWR_I2S_DSP_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5670_PWR_VOL,
+			    RT5670_PWR_MIC_DET_BIT, 0, NULL, 0),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5670_ASRC_1,
+			      11, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5670_ASRC_1,
+			      12, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5670_ASRC_1,
+			      10, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC MONO L ASRC", 1, RT5670_ASRC_1,
+			      9, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5670_ASRC_1,
+			      8, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5670_ASRC_1,
+			      7, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5670_ASRC_1,
+			      6, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5670_ASRC_1,
+			      5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5670_ASRC_1,
+			      4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5670_ASRC_1,
+			      3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5670_ASRC_1,
+			      2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5670_ASRC_1,
+			      1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5670_ASRC_1,
+			      0, 0, NULL, 0),
+
+	/* Input Side */
+	/* micbias */
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5670_PWR_ANLG2,
+			     RT5670_PWR_MB1_BIT, 0, NULL, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC L1"),
+	SND_SOC_DAPM_INPUT("DMIC R1"),
+	SND_SOC_DAPM_INPUT("DMIC L2"),
+	SND_SOC_DAPM_INPUT("DMIC R2"),
+	SND_SOC_DAPM_INPUT("DMIC L3"),
+	SND_SOC_DAPM_INPUT("DMIC R3"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN1N"),
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN2N"),
+
+	SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+			    set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5670_DMIC_CTRL1,
+			    RT5670_DMIC_1_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5670_DMIC_CTRL1,
+			    RT5670_DMIC_2_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC3 Power", RT5670_DMIC_CTRL1,
+			    RT5670_DMIC_3_EN_SFT, 0, NULL, 0),
+	/* Boost */
+	SND_SOC_DAPM_PGA_E("BST1", RT5670_PWR_ANLG2, RT5670_PWR_BST1_BIT,
+			   0, NULL, 0, rt5670_bst1_event,
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_E("BST2", RT5670_PWR_ANLG2, RT5670_PWR_BST2_BIT,
+			   0, NULL, 0, rt5670_bst2_event,
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	/* Input Volume */
+	SND_SOC_DAPM_PGA("INL VOL", RT5670_PWR_VOL,
+			 RT5670_PWR_IN_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR VOL", RT5670_PWR_VOL,
+			 RT5670_PWR_IN_R_BIT, 0, NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIXL", RT5670_PWR_MIXER, RT5670_PWR_RM_L_BIT, 0,
+			   rt5670_rec_l_mix, ARRAY_SIZE(rt5670_rec_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIXR", RT5670_PWR_MIXER, RT5670_PWR_RM_R_BIT, 0,
+			   rt5670_rec_r_mix, ARRAY_SIZE(rt5670_rec_r_mix)),
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC 2", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_PGA("ADC 1_2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC 1 power", RT5670_PWR_DIG1,
+			    RT5670_PWR_ADC_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC 2 power", RT5670_PWR_DIG1,
+			    RT5670_PWR_ADC_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC clock", RT5670_PR_BASE +
+			    RT5670_CHOP_DAC_ADC, 12, 0, NULL, 0),
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_sto1_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_sto_adc_2_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_sto_adc_2_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_sto_adc_1_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_sto_adc_1_mux),
+	SND_SOC_DAPM_MUX("Stereo2 DMIC Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_sto2_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_sto2_adc_2_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_sto2_adc_2_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_sto2_adc_1_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_sto2_adc_1_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC LR Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_sto2_adc_lr_mux),
+	SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_mono_dmic_l_mux),
+	SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_mono_dmic_r_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_mono_adc_l2_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_mono_adc_l1_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_mono_adc_r1_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_mono_adc_r2_mux),
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5670_PWR_DIG2,
+			    RT5670_PWR_ADC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5670_PWR_DIG2,
+			    RT5670_PWR_ADC_S2F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", RT5670_STO1_ADC_DIG_VOL,
+			   RT5670_L_MUTE_SFT, 1, rt5670_sto1_adc_l_mix,
+			   ARRAY_SIZE(rt5670_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", RT5670_STO1_ADC_DIG_VOL,
+			   RT5670_R_MUTE_SFT, 1, rt5670_sto1_adc_r_mix,
+			   ARRAY_SIZE(rt5670_sto1_adc_r_mix)),
+	SND_SOC_DAPM_MIXER("Sto2 ADC MIXL", SND_SOC_NOPM, 0, 0,
+			   rt5670_sto2_adc_l_mix,
+			   ARRAY_SIZE(rt5670_sto2_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Sto2 ADC MIXR", SND_SOC_NOPM, 0, 0,
+			   rt5670_sto2_adc_r_mix,
+			   ARRAY_SIZE(rt5670_sto2_adc_r_mix)),
+	SND_SOC_DAPM_SUPPLY("ADC Mono Left Filter", RT5670_PWR_DIG2,
+			    RT5670_PWR_ADC_MF_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mono ADC MIXL", RT5670_MONO_ADC_DIG_VOL,
+			   RT5670_L_MUTE_SFT, 1, rt5670_mono_adc_l_mix,
+			   ARRAY_SIZE(rt5670_mono_adc_l_mix)),
+	SND_SOC_DAPM_SUPPLY("ADC Mono Right Filter", RT5670_PWR_DIG2,
+			    RT5670_PWR_ADC_MF_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mono ADC MIXR", RT5670_MONO_ADC_DIG_VOL,
+			   RT5670_R_MUTE_SFT, 1, rt5670_mono_adc_r_mix,
+			   ARRAY_SIZE(rt5670_mono_adc_r_mix)),
+
+	/* ADC PGA */
+	SND_SOC_DAPM_PGA("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo2 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo2 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo2 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("VAD_ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* DSP */
+	SND_SOC_DAPM_PGA("TxDP_ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("TxDP_ADC_L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("TxDP_ADC_R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("TxDC_DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("TDM Data Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_txdp_slot_mux),
+
+	SND_SOC_DAPM_MUX("DSP UL Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_dsp_ul_mux),
+	SND_SOC_DAPM_MUX("DSP DL Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_dsp_dl_mux),
+
+	SND_SOC_DAPM_MUX("RxDP Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_rxdp_mux),
+
+	/* IF2 Mux */
+	SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_if2_adc_in_mux),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5670_PWR_DIG1,
+			    RT5670_PWR_I2S1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("I2S2", RT5670_PWR_DIG1,
+			    RT5670_PWR_I2S2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface Select */
+	SND_SOC_DAPM_MUX("IF1 ADC1 IN1 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_if1_adc1_in1_mux),
+	SND_SOC_DAPM_MUX("IF1 ADC1 IN2 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_if1_adc1_in2_mux),
+	SND_SOC_DAPM_MUX("IF1 ADC2 IN Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_if1_adc2_in_mux),
+	SND_SOC_DAPM_MUX("IF1 ADC2 IN1 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_if1_adc2_in1_mux),
+	SND_SOC_DAPM_MUX("VAD ADC Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_vad_adc_mux),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0,
+			     RT5670_GPIO_CTRL1, RT5670_I2S2_PIN_SFT, 1),
+
+	/* Audio DSP */
+	SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Output Side */
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
+			   rt5670_dac_l_mix, ARRAY_SIZE(rt5670_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+			   rt5670_dac_r_mix, ARRAY_SIZE(rt5670_dac_r_mix)),
+	SND_SOC_DAPM_PGA("DAC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* DAC2 channel Mux */
+	SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_dac_l2_mux),
+	SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0,
+			 &rt5670_dac_r2_mux),
+	SND_SOC_DAPM_PGA("DAC L2 Volume", RT5670_PWR_DIG1,
+			 RT5670_PWR_DAC_L2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DAC R2 Volume", RT5670_PWR_DIG1,
+			 RT5670_PWR_DAC_R2_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("DAC1 L Mux", SND_SOC_NOPM, 0, 0, &rt5670_dac1l_mux),
+	SND_SOC_DAPM_MUX("DAC1 R Mux", SND_SOC_NOPM, 0, 0, &rt5670_dac1r_mux),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5670_PWR_DIG2,
+			    RT5670_PWR_DAC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Mono Left Filter", RT5670_PWR_DIG2,
+			    RT5670_PWR_DAC_MF_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Mono Right Filter", RT5670_PWR_DIG2,
+			    RT5670_PWR_DAC_MF_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+			   rt5670_sto_dac_l_mix,
+			   ARRAY_SIZE(rt5670_sto_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+			   rt5670_sto_dac_r_mix,
+			   ARRAY_SIZE(rt5670_sto_dac_r_mix)),
+	SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
+			   rt5670_mono_dac_l_mix,
+			   ARRAY_SIZE(rt5670_mono_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
+			   rt5670_mono_dac_r_mix,
+			   ARRAY_SIZE(rt5670_mono_dac_r_mix)),
+	SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
+			   rt5670_dig_l_mix,
+			   ARRAY_SIZE(rt5670_dig_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
+			   rt5670_dig_r_mix,
+			   ARRAY_SIZE(rt5670_dig_r_mix)),
+
+	/* DACs */
+	SND_SOC_DAPM_SUPPLY("DAC L1 Power", RT5670_PWR_DIG1,
+			    RT5670_PWR_DAC_L1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC R1 Power", RT5670_PWR_DIG1,
+			    RT5670_PWR_DAC_R1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC L2", NULL, RT5670_PWR_DIG1,
+			 RT5670_PWR_DAC_L2_BIT, 0),
+
+	SND_SOC_DAPM_DAC("DAC R2", NULL, RT5670_PWR_DIG1,
+			 RT5670_PWR_DAC_R2_BIT, 0),
+	/* OUT Mixer */
+
+	SND_SOC_DAPM_MIXER("OUT MIXL", RT5670_PWR_MIXER, RT5670_PWR_OM_L_BIT,
+			   0, rt5670_out_l_mix, ARRAY_SIZE(rt5670_out_l_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXR", RT5670_PWR_MIXER, RT5670_PWR_OM_R_BIT,
+			   0, rt5670_out_r_mix, ARRAY_SIZE(rt5670_out_r_mix)),
+	/* Ouput Volume */
+	SND_SOC_DAPM_MIXER("HPOVOL MIXL", RT5670_PWR_VOL,
+			   RT5670_PWR_HV_L_BIT, 0,
+			   rt5670_hpvoll_mix, ARRAY_SIZE(rt5670_hpvoll_mix)),
+	SND_SOC_DAPM_MIXER("HPOVOL MIXR", RT5670_PWR_VOL,
+			   RT5670_PWR_HV_R_BIT, 0,
+			   rt5670_hpvolr_mix, ARRAY_SIZE(rt5670_hpvolr_mix)),
+	SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DAC 2", SND_SOC_NOPM,	0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HPOVOL", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* HPO/LOUT/Mono Mixer */
+	SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0,
+			   rt5670_hpo_mix, ARRAY_SIZE(rt5670_hpo_mix)),
+	SND_SOC_DAPM_MIXER("LOUT MIX", RT5670_PWR_ANLG1, RT5670_PWR_LM_BIT,
+			   0, rt5670_lout_mix, ARRAY_SIZE(rt5670_lout_mix)),
+	SND_SOC_DAPM_SUPPLY_S("Improve HP Amp Drv", 1, SND_SOC_NOPM, 0, 0,
+			      rt5670_hp_power_event, SND_SOC_DAPM_POST_PMU |
+			      SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("HP L Amp", RT5670_PWR_ANLG1,
+			    RT5670_PWR_HP_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HP R Amp", RT5670_PWR_ANLG1,
+			    RT5670_PWR_HP_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0,
+			   rt5670_hp_event, SND_SOC_DAPM_PRE_PMD |
+			   SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0,
+			    &lout_l_enable_control),
+	SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0,
+			    &lout_r_enable_control),
+	SND_SOC_DAPM_PGA("LOUT Amp", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* PDM */
+	SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5670_PWR_DIG2,
+		RT5670_PWR_PDM1_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("PDM1 L Mux", RT5670_PDM_OUT_CTRL,
+			 RT5670_M_PDM1_L_SFT, 1, &rt5670_pdm1_l_mux),
+	SND_SOC_DAPM_MUX("PDM1 R Mux", RT5670_PDM_OUT_CTRL,
+			 RT5670_M_PDM1_R_SFT, 1, &rt5670_pdm1_r_mux),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+	SND_SOC_DAPM_OUTPUT("LOUTL"),
+	SND_SOC_DAPM_OUTPUT("LOUTR"),
+};
+
+static const struct snd_soc_dapm_widget rt5670_specific_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2,
+		RT5670_PWR_PDM2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL,
+			 RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux),
+	SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL,
+			 RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux),
+	SND_SOC_DAPM_OUTPUT("PDM1L"),
+	SND_SOC_DAPM_OUTPUT("PDM1R"),
+	SND_SOC_DAPM_OUTPUT("PDM2L"),
+	SND_SOC_DAPM_OUTPUT("PDM2R"),
+};
+
+static const struct snd_soc_dapm_widget rt5672_specific_dapm_widgets[] = {
+	SND_SOC_DAPM_PGA("SPO Amp", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("SPOLP"),
+	SND_SOC_DAPM_OUTPUT("SPOLN"),
+	SND_SOC_DAPM_OUTPUT("SPORP"),
+	SND_SOC_DAPM_OUTPUT("SPORN"),
+};
+
+static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
+	{ "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc },
+	{ "ADC Stereo2 Filter", NULL, "ADC STO2 ASRC", is_using_asrc },
+	{ "ADC Mono Left Filter", NULL, "ADC MONO L ASRC", is_using_asrc },
+	{ "ADC Mono Right Filter", NULL, "ADC MONO R ASRC", is_using_asrc },
+	{ "DAC Mono Left Filter", NULL, "DAC MONO L ASRC", is_using_asrc },
+	{ "DAC Mono Right Filter", NULL, "DAC MONO R ASRC", is_using_asrc },
+	{ "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc },
+	{ "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc },
+	{ "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc },
+	{ "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc },
+	{ "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc },
+
+	{ "I2S1", NULL, "I2S1 ASRC", can_use_asrc},
+	{ "I2S2", NULL, "I2S2 ASRC", can_use_asrc},
+
+	{ "DMIC1", NULL, "DMIC L1" },
+	{ "DMIC1", NULL, "DMIC R1" },
+	{ "DMIC2", NULL, "DMIC L2" },
+	{ "DMIC2", NULL, "DMIC R2" },
+	{ "DMIC3", NULL, "DMIC L3" },
+	{ "DMIC3", NULL, "DMIC R3" },
+
+	{ "BST1", NULL, "IN1P" },
+	{ "BST1", NULL, "IN1N" },
+	{ "BST1", NULL, "Mic Det Power" },
+	{ "BST2", NULL, "IN2P" },
+	{ "BST2", NULL, "IN2N" },
+
+	{ "INL VOL", NULL, "IN2P" },
+	{ "INR VOL", NULL, "IN2N" },
+
+	{ "RECMIXL", "INL Switch", "INL VOL" },
+	{ "RECMIXL", "BST2 Switch", "BST2" },
+	{ "RECMIXL", "BST1 Switch", "BST1" },
+
+	{ "RECMIXR", "INR Switch", "INR VOL" },
+	{ "RECMIXR", "BST2 Switch", "BST2" },
+	{ "RECMIXR", "BST1 Switch", "BST1" },
+
+	{ "ADC 1", NULL, "RECMIXL" },
+	{ "ADC 1", NULL, "ADC 1 power" },
+	{ "ADC 1", NULL, "ADC clock" },
+	{ "ADC 2", NULL, "RECMIXR" },
+	{ "ADC 2", NULL, "ADC 2 power" },
+	{ "ADC 2", NULL, "ADC clock" },
+
+	{ "DMIC L1", NULL, "DMIC CLK" },
+	{ "DMIC L1", NULL, "DMIC1 Power" },
+	{ "DMIC R1", NULL, "DMIC CLK" },
+	{ "DMIC R1", NULL, "DMIC1 Power" },
+	{ "DMIC L2", NULL, "DMIC CLK" },
+	{ "DMIC L2", NULL, "DMIC2 Power" },
+	{ "DMIC R2", NULL, "DMIC CLK" },
+	{ "DMIC R2", NULL, "DMIC2 Power" },
+	{ "DMIC L3", NULL, "DMIC CLK" },
+	{ "DMIC L3", NULL, "DMIC3 Power" },
+	{ "DMIC R3", NULL, "DMIC CLK" },
+	{ "DMIC R3", NULL, "DMIC3 Power" },
+
+	{ "Stereo1 DMIC Mux", "DMIC1", "DMIC1" },
+	{ "Stereo1 DMIC Mux", "DMIC2", "DMIC2" },
+	{ "Stereo1 DMIC Mux", "DMIC3", "DMIC3" },
+
+	{ "Stereo2 DMIC Mux", "DMIC1", "DMIC1" },
+	{ "Stereo2 DMIC Mux", "DMIC2", "DMIC2" },
+	{ "Stereo2 DMIC Mux", "DMIC3", "DMIC3" },
+
+	{ "Mono DMIC L Mux", "DMIC1", "DMIC L1" },
+	{ "Mono DMIC L Mux", "DMIC2", "DMIC L2" },
+	{ "Mono DMIC L Mux", "DMIC3", "DMIC L3" },
+
+	{ "Mono DMIC R Mux", "DMIC1", "DMIC R1" },
+	{ "Mono DMIC R Mux", "DMIC2", "DMIC R2" },
+	{ "Mono DMIC R Mux", "DMIC3", "DMIC R3" },
+
+	{ "ADC 1_2", NULL, "ADC 1" },
+	{ "ADC 1_2", NULL, "ADC 2" },
+
+	{ "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" },
+	{ "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" },
+	{ "Stereo1 ADC L1 Mux", "ADC", "ADC 1_2" },
+	{ "Stereo1 ADC L1 Mux", "DAC MIX", "DAC MIXL" },
+
+	{ "Stereo1 ADC R1 Mux", "ADC", "ADC 1_2" },
+	{ "Stereo1 ADC R1 Mux", "DAC MIX", "DAC MIXR" },
+	{ "Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC Mux" },
+	{ "Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR" },
+
+	{ "Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux" },
+	{ "Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL" },
+	{ "Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL" },
+	{ "Mono ADC L1 Mux", "ADC1",  "ADC 1" },
+
+	{ "Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR" },
+	{ "Mono ADC R1 Mux", "ADC2", "ADC 2" },
+	{ "Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux" },
+	{ "Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR" },
+
+	{ "Sto1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux" },
+	{ "Sto1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux" },
+	{ "Sto1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux" },
+	{ "Sto1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux" },
+
+	{ "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" },
+	{ "Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter" },
+
+	{ "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" },
+	{ "Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter" },
+	{ "ADC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux" },
+	{ "Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux" },
+	{ "Mono ADC MIXL", NULL, "ADC Mono Left Filter" },
+	{ "ADC Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux" },
+	{ "Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux" },
+	{ "Mono ADC MIXR", NULL, "ADC Mono Right Filter" },
+	{ "ADC Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "Stereo2 ADC L2 Mux", "DMIC", "Stereo2 DMIC Mux" },
+	{ "Stereo2 ADC L2 Mux", "DAC MIX", "DAC MIXL" },
+	{ "Stereo2 ADC L1 Mux", "ADC", "ADC 1_2" },
+	{ "Stereo2 ADC L1 Mux", "DAC MIX", "DAC MIXL" },
+
+	{ "Stereo2 ADC R1 Mux", "ADC", "ADC 1_2" },
+	{ "Stereo2 ADC R1 Mux", "DAC MIX", "DAC MIXR" },
+	{ "Stereo2 ADC R2 Mux", "DMIC", "Stereo2 DMIC Mux" },
+	{ "Stereo2 ADC R2 Mux", "DAC MIX", "DAC MIXR" },
+
+	{ "Sto2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC L1 Mux" },
+	{ "Sto2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC L2 Mux" },
+	{ "Sto2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC R1 Mux" },
+	{ "Sto2 ADC MIXR", "ADC2 Switch", "Stereo2 ADC R2 Mux" },
+
+	{ "Sto2 ADC LR MIX", NULL, "Sto2 ADC MIXL" },
+	{ "Sto2 ADC LR MIX", NULL, "Sto2 ADC MIXR" },
+
+	{ "Stereo2 ADC LR Mux", "L", "Sto2 ADC MIXL" },
+	{ "Stereo2 ADC LR Mux", "LR", "Sto2 ADC LR MIX" },
+
+	{ "Stereo2 ADC MIXL", NULL, "Stereo2 ADC LR Mux" },
+	{ "Stereo2 ADC MIXL", NULL, "ADC Stereo2 Filter" },
+
+	{ "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" },
+	{ "Stereo2 ADC MIXR", NULL, "ADC Stereo2 Filter" },
+	{ "ADC Stereo2 Filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "VAD ADC Mux", "Sto1 ADC L", "Stereo1 ADC MIXL" },
+	{ "VAD ADC Mux", "Mono ADC L", "Mono ADC MIXL" },
+	{ "VAD ADC Mux", "Mono ADC R", "Mono ADC MIXR" },
+	{ "VAD ADC Mux", "Sto2 ADC L", "Sto2 ADC MIXL" },
+
+	{ "VAD_ADC", NULL, "VAD ADC Mux" },
+
+	{ "IF_ADC1", NULL, "Stereo1 ADC MIXL" },
+	{ "IF_ADC1", NULL, "Stereo1 ADC MIXR" },
+	{ "IF_ADC2", NULL, "Mono ADC MIXL" },
+	{ "IF_ADC2", NULL, "Mono ADC MIXR" },
+	{ "IF_ADC3", NULL, "Stereo2 ADC MIXL" },
+	{ "IF_ADC3", NULL, "Stereo2 ADC MIXR" },
+
+	{ "IF1 ADC1 IN1 Mux", "IF_ADC1", "IF_ADC1" },
+	{ "IF1 ADC1 IN1 Mux", "IF1_ADC3", "IF1_ADC3" },
+
+	{ "IF1 ADC1 IN2 Mux", "IF1_ADC1_IN1", "IF1 ADC1 IN1 Mux" },
+	{ "IF1 ADC1 IN2 Mux", "IF1_ADC4", "TxDP_ADC" },
+
+	{ "IF1 ADC2 IN Mux", "IF_ADC2", "IF_ADC2" },
+	{ "IF1 ADC2 IN Mux", "VAD_ADC", "VAD_ADC" },
+
+	{ "IF1 ADC2 IN1 Mux", "IF1_ADC2_IN", "IF1 ADC2 IN Mux" },
+	{ "IF1 ADC2 IN1 Mux", "IF1_ADC4", "TxDP_ADC" },
+
+	{ "IF1_ADC1" , NULL, "IF1 ADC1 IN2 Mux" },
+	{ "IF1_ADC2" , NULL, "IF1 ADC2 IN1 Mux" },
+
+	{ "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL" },
+	{ "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR" },
+	{ "Stereo2 ADC MIX", NULL, "Sto2 ADC MIXL" },
+	{ "Stereo2 ADC MIX", NULL, "Sto2 ADC MIXR" },
+	{ "Mono ADC MIX", NULL, "Mono ADC MIXL" },
+	{ "Mono ADC MIX", NULL, "Mono ADC MIXR" },
+
+	{ "RxDP Mux", "IF2 DAC", "IF2 DAC" },
+	{ "RxDP Mux", "IF1 DAC", "IF1 DAC2" },
+	{ "RxDP Mux", "STO1 ADC Mixer", "Stereo1 ADC MIX" },
+	{ "RxDP Mux", "STO2 ADC Mixer", "Stereo2 ADC MIX" },
+	{ "RxDP Mux", "Mono ADC Mixer L", "Mono ADC MIXL" },
+	{ "RxDP Mux", "Mono ADC Mixer R", "Mono ADC MIXR" },
+	{ "RxDP Mux", "DAC1", "DAC MIX" },
+
+	{ "TDM Data Mux", "Slot 0-1", "Stereo1 ADC MIX" },
+	{ "TDM Data Mux", "Slot 2-3", "Mono ADC MIX" },
+	{ "TDM Data Mux", "Slot 4-5", "Stereo2 ADC MIX" },
+	{ "TDM Data Mux", "Slot 6-7", "IF2 DAC" },
+
+	{ "DSP UL Mux", "Bypass", "TDM Data Mux" },
+	{ "DSP UL Mux", NULL, "I2S DSP" },
+	{ "DSP DL Mux", "Bypass", "RxDP Mux" },
+	{ "DSP DL Mux", NULL, "I2S DSP" },
+
+	{ "TxDP_ADC_L", NULL, "DSP UL Mux" },
+	{ "TxDP_ADC_R", NULL, "DSP UL Mux" },
+	{ "TxDC_DAC", NULL, "DSP DL Mux" },
+
+	{ "TxDP_ADC", NULL, "TxDP_ADC_L" },
+	{ "TxDP_ADC", NULL, "TxDP_ADC_R" },
+
+	{ "IF1 ADC", NULL, "I2S1" },
+	{ "IF1 ADC", NULL, "IF1_ADC1" },
+	{ "IF1 ADC", NULL, "IF1_ADC2" },
+	{ "IF1 ADC", NULL, "IF_ADC3" },
+	{ "IF1 ADC", NULL, "TxDP_ADC" },
+
+	{ "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" },
+	{ "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" },
+	{ "IF2 ADC Mux", "IF_ADC3", "IF_ADC3" },
+	{ "IF2 ADC Mux", "TxDC_DAC", "TxDC_DAC" },
+	{ "IF2 ADC Mux", "TxDP_ADC", "TxDP_ADC" },
+	{ "IF2 ADC Mux", "VAD_ADC", "VAD_ADC" },
+
+	{ "IF2 ADC L", NULL, "IF2 ADC Mux" },
+	{ "IF2 ADC R", NULL, "IF2 ADC Mux" },
+
+	{ "IF2 ADC", NULL, "I2S2" },
+	{ "IF2 ADC", NULL, "IF2 ADC L" },
+	{ "IF2 ADC", NULL, "IF2 ADC R" },
+
+	{ "AIF1TX", NULL, "IF1 ADC" },
+	{ "AIF2TX", NULL, "IF2 ADC" },
+
+	{ "IF1 DAC1", NULL, "AIF1RX" },
+	{ "IF1 DAC2", NULL, "AIF1RX" },
+	{ "IF2 DAC", NULL, "AIF2RX" },
+
+	{ "IF1 DAC1", NULL, "I2S1" },
+	{ "IF1 DAC2", NULL, "I2S1" },
+	{ "IF2 DAC", NULL, "I2S2" },
+
+	{ "IF1 DAC2 L", NULL, "IF1 DAC2" },
+	{ "IF1 DAC2 R", NULL, "IF1 DAC2" },
+	{ "IF1 DAC1 L", NULL, "IF1 DAC1" },
+	{ "IF1 DAC1 R", NULL, "IF1 DAC1" },
+	{ "IF2 DAC L", NULL, "IF2 DAC" },
+	{ "IF2 DAC R", NULL, "IF2 DAC" },
+
+	{ "DAC1 L Mux", "IF1 DAC", "IF1 DAC1 L" },
+	{ "DAC1 L Mux", "IF2 DAC", "IF2 DAC L" },
+
+	{ "DAC1 R Mux", "IF1 DAC", "IF1 DAC1 R" },
+	{ "DAC1 R Mux", "IF2 DAC", "IF2 DAC R" },
+
+	{ "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" },
+	{ "DAC1 MIXL", "DAC1 Switch", "DAC1 L Mux" },
+	{ "DAC1 MIXL", NULL, "DAC Stereo1 Filter" },
+	{ "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR" },
+	{ "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" },
+	{ "DAC1 MIXR", NULL, "DAC Stereo1 Filter" },
+
+	{ "DAC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll },
+	{ "DAC Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll },
+	{ "DAC Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "DAC MIX", NULL, "DAC1 MIXL" },
+	{ "DAC MIX", NULL, "DAC1 MIXR" },
+
+	{ "Audio DSP", NULL, "DAC1 MIXL" },
+	{ "Audio DSP", NULL, "DAC1 MIXR" },
+
+	{ "DAC L2 Mux", "IF1 DAC", "IF1 DAC2 L" },
+	{ "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" },
+	{ "DAC L2 Mux", "TxDC DAC", "TxDC_DAC" },
+	{ "DAC L2 Mux", "VAD_ADC", "VAD_ADC" },
+	{ "DAC L2 Volume", NULL, "DAC L2 Mux" },
+	{ "DAC L2 Volume", NULL, "DAC Mono Left Filter" },
+
+	{ "DAC R2 Mux", "IF1 DAC", "IF1 DAC2 R" },
+	{ "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" },
+	{ "DAC R2 Mux", "TxDC DAC", "TxDC_DAC" },
+	{ "DAC R2 Mux", "TxDP ADC", "TxDP_ADC" },
+	{ "DAC R2 Volume", NULL, "DAC R2 Mux" },
+	{ "DAC R2 Volume", NULL, "DAC Mono Right Filter" },
+
+	{ "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" },
+	{ "Stereo DAC MIXL", NULL, "DAC Stereo1 Filter" },
+	{ "Stereo DAC MIXL", NULL, "DAC L1 Power" },
+	{ "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" },
+	{ "Stereo DAC MIXR", NULL, "DAC Stereo1 Filter" },
+	{ "Stereo DAC MIXR", NULL, "DAC R1 Power" },
+
+	{ "Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" },
+	{ "Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Volume" },
+	{ "Mono DAC MIXL", NULL, "DAC Mono Left Filter" },
+	{ "Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" },
+	{ "Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" },
+	{ "Mono DAC MIXR", NULL, "DAC Mono Right Filter" },
+
+	{ "DAC MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" },
+	{ "DAC MIXL", "DAC L2 Switch", "DAC L2 Volume" },
+	{ "DAC MIXL", "DAC R2 Switch", "DAC R2 Volume" },
+	{ "DAC MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" },
+	{ "DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" },
+	{ "DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" },
+
+	{ "DAC L1", NULL, "DAC L1 Power" },
+	{ "DAC L1", NULL, "Stereo DAC MIXL" },
+	{ "DAC R1", NULL, "DAC R1 Power" },
+	{ "DAC R1", NULL, "Stereo DAC MIXR" },
+	{ "DAC L2", NULL, "Mono DAC MIXL" },
+	{ "DAC R2", NULL, "Mono DAC MIXR" },
+
+	{ "OUT MIXL", "BST1 Switch", "BST1" },
+	{ "OUT MIXL", "INL Switch", "INL VOL" },
+	{ "OUT MIXL", "DAC L2 Switch", "DAC L2" },
+	{ "OUT MIXL", "DAC L1 Switch", "DAC L1" },
+
+	{ "OUT MIXR", "BST2 Switch", "BST2" },
+	{ "OUT MIXR", "INR Switch", "INR VOL" },
+	{ "OUT MIXR", "DAC R2 Switch", "DAC R2" },
+	{ "OUT MIXR", "DAC R1 Switch", "DAC R1" },
+
+	{ "HPOVOL MIXL", "DAC1 Switch", "DAC L1" },
+	{ "HPOVOL MIXL", "INL Switch", "INL VOL" },
+	{ "HPOVOL MIXR", "DAC1 Switch", "DAC R1" },
+	{ "HPOVOL MIXR", "INR Switch", "INR VOL" },
+
+	{ "DAC 2", NULL, "DAC L2" },
+	{ "DAC 2", NULL, "DAC R2" },
+	{ "DAC 1", NULL, "DAC L1" },
+	{ "DAC 1", NULL, "DAC R1" },
+	{ "HPOVOL", NULL, "HPOVOL MIXL" },
+	{ "HPOVOL", NULL, "HPOVOL MIXR" },
+	{ "HPO MIX", "DAC1 Switch", "DAC 1" },
+	{ "HPO MIX", "HPVOL Switch", "HPOVOL" },
+
+	{ "LOUT MIX", "DAC L1 Switch", "DAC L1" },
+	{ "LOUT MIX", "DAC R1 Switch", "DAC R1" },
+	{ "LOUT MIX", "OUTMIX L Switch", "OUT MIXL" },
+	{ "LOUT MIX", "OUTMIX R Switch", "OUT MIXR" },
+
+	{ "PDM1 L Mux", "Stereo DAC", "Stereo DAC MIXL" },
+	{ "PDM1 L Mux", "Mono DAC", "Mono DAC MIXL" },
+	{ "PDM1 L Mux", NULL, "PDM1 Power" },
+	{ "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
+	{ "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" },
+	{ "PDM1 R Mux", NULL, "PDM1 Power" },
+
+	{ "HP Amp", NULL, "HPO MIX" },
+	{ "HP Amp", NULL, "Mic Det Power" },
+	{ "HPOL", NULL, "HP Amp" },
+	{ "HPOL", NULL, "HP L Amp" },
+	{ "HPOL", NULL, "Improve HP Amp Drv" },
+	{ "HPOR", NULL, "HP Amp" },
+	{ "HPOR", NULL, "HP R Amp" },
+	{ "HPOR", NULL, "Improve HP Amp Drv" },
+
+	{ "LOUT Amp", NULL, "LOUT MIX" },
+	{ "LOUT L Playback", "Switch", "LOUT Amp" },
+	{ "LOUT R Playback", "Switch", "LOUT Amp" },
+	{ "LOUTL", NULL, "LOUT L Playback" },
+	{ "LOUTR", NULL, "LOUT R Playback" },
+	{ "LOUTL", NULL, "Improve HP Amp Drv" },
+	{ "LOUTR", NULL, "Improve HP Amp Drv" },
+};
+
+static const struct snd_soc_dapm_route rt5670_specific_dapm_routes[] = {
+	{ "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" },
+	{ "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" },
+	{ "PDM2 L Mux", NULL, "PDM2 Power" },
+	{ "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
+	{ "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" },
+	{ "PDM2 R Mux", NULL, "PDM2 Power" },
+	{ "PDM1L", NULL, "PDM1 L Mux" },
+	{ "PDM1R", NULL, "PDM1 R Mux" },
+	{ "PDM2L", NULL, "PDM2 L Mux" },
+	{ "PDM2R", NULL, "PDM2 R Mux" },
+};
+
+static const struct snd_soc_dapm_route rt5672_specific_dapm_routes[] = {
+	{ "SPO Amp", NULL, "PDM1 L Mux" },
+	{ "SPO Amp", NULL, "PDM1 R Mux" },
+	{ "SPOLP", NULL, "SPO Amp" },
+	{ "SPOLN", NULL, "SPO Amp" },
+	{ "SPORP", NULL, "SPO Amp" },
+	{ "SPORN", NULL, "SPO Amp" },
+};
+
+static int rt5670_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0, val_clk, mask_clk;
+	int pre_div, bclk_ms, frame_size;
+
+	rt5670->lrck[dai->id] = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5670->sysclk, rt5670->lrck[dai->id]);
+	if (pre_div < 0) {
+		dev_err(component->dev, "Unsupported clock setting %d for DAI %d\n",
+			rt5670->lrck[dai->id], dai->id);
+		return -EINVAL;
+	}
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
+		return -EINVAL;
+	}
+	bclk_ms = frame_size > 32;
+	rt5670->bclk[dai->id] = rt5670->lrck[dai->id] * (32 << bclk_ms);
+
+	dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+		rt5670->bclk[dai->id], rt5670->lrck[dai->id]);
+	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+				bclk_ms, pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		val_len |= RT5670_I2S_DL_20;
+		break;
+	case 24:
+		val_len |= RT5670_I2S_DL_24;
+		break;
+	case 8:
+		val_len |= RT5670_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5670_AIF1:
+		mask_clk = RT5670_I2S_BCLK_MS1_MASK | RT5670_I2S_PD1_MASK;
+		val_clk = bclk_ms << RT5670_I2S_BCLK_MS1_SFT |
+			pre_div << RT5670_I2S_PD1_SFT;
+		snd_soc_component_update_bits(component, RT5670_I2S1_SDP,
+			RT5670_I2S_DL_MASK, val_len);
+		snd_soc_component_update_bits(component, RT5670_ADDA_CLK1, mask_clk, val_clk);
+		break;
+	case RT5670_AIF2:
+		mask_clk = RT5670_I2S_BCLK_MS2_MASK | RT5670_I2S_PD2_MASK;
+		val_clk = bclk_ms << RT5670_I2S_BCLK_MS2_SFT |
+			pre_div << RT5670_I2S_PD2_SFT;
+		snd_soc_component_update_bits(component, RT5670_I2S2_SDP,
+			RT5670_I2S_DL_MASK, val_len);
+		snd_soc_component_update_bits(component, RT5670_ADDA_CLK1, mask_clk, val_clk);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5670_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5670->master[dai->id] = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5670_I2S_MS_S;
+		rt5670->master[dai->id] = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5670_I2S_BP_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5670_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5670_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5670_I2S_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5670_AIF1:
+		snd_soc_component_update_bits(component, RT5670_I2S1_SDP,
+			RT5670_I2S_MS_MASK | RT5670_I2S_BP_MASK |
+			RT5670_I2S_DF_MASK, reg_val);
+		break;
+	case RT5670_AIF2:
+		snd_soc_component_update_bits(component, RT5670_I2S2_SDP,
+			RT5670_I2S_MS_MASK | RT5670_I2S_BP_MASK |
+			RT5670_I2S_DF_MASK, reg_val);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int rt5670_set_codec_sysclk(struct snd_soc_component *component, int clk_id,
+				   int source, unsigned int freq, int dir)
+{
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	switch (clk_id) {
+	case RT5670_SCLK_S_MCLK:
+		reg_val |= RT5670_SCLK_SRC_MCLK;
+		break;
+	case RT5670_SCLK_S_PLL1:
+		reg_val |= RT5670_SCLK_SRC_PLL1;
+		break;
+	case RT5670_SCLK_S_RCCLK:
+		reg_val |= RT5670_SCLK_SRC_RCCLK;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, RT5670_GLB_CLK,
+		RT5670_SCLK_SRC_MASK, reg_val);
+	rt5670->sysclk = freq;
+	if (clk_id != RT5670_SCLK_S_RCCLK)
+		rt5670->sysclk_src = clk_id;
+
+	dev_dbg(component->dev, "Sysclk : %dHz clock id : %d\n", freq, clk_id);
+
+	return 0;
+}
+
+static int rt5670_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+			unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5670->pll_src && freq_in == rt5670->pll_in &&
+	    freq_out == rt5670->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt5670->pll_in = 0;
+		rt5670->pll_out = 0;
+		snd_soc_component_update_bits(component, RT5670_GLB_CLK,
+			RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5670_PLL1_S_MCLK:
+		snd_soc_component_update_bits(component, RT5670_GLB_CLK,
+			RT5670_PLL1_SRC_MASK, RT5670_PLL1_SRC_MCLK);
+		break;
+	case RT5670_PLL1_S_BCLK1:
+	case RT5670_PLL1_S_BCLK2:
+	case RT5670_PLL1_S_BCLK3:
+	case RT5670_PLL1_S_BCLK4:
+		switch (dai->id) {
+		case RT5670_AIF1:
+			snd_soc_component_update_bits(component, RT5670_GLB_CLK,
+				RT5670_PLL1_SRC_MASK, RT5670_PLL1_SRC_BCLK1);
+			break;
+		case RT5670_AIF2:
+			snd_soc_component_update_bits(component, RT5670_GLB_CLK,
+				RT5670_PLL1_SRC_MASK, RT5670_PLL1_SRC_BCLK2);
+			break;
+		default:
+			dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+			return -EINVAL;
+		}
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_component_write(component, RT5670_PLL_CTRL1,
+		pll_code.n_code << RT5670_PLL_N_SFT | pll_code.k_code);
+	snd_soc_component_write(component, RT5670_PLL_CTRL2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5670_PLL_M_SFT |
+		pll_code.m_bp << RT5670_PLL_M_BP_SFT);
+
+	rt5670->pll_in = freq_in;
+	rt5670->pll_out = freq_out;
+	rt5670->pll_src = source;
+
+	return 0;
+}
+
+static int rt5670_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int val = 0;
+
+	if (rx_mask || tx_mask)
+		val |= (1 << 14);
+
+	switch (slots) {
+	case 4:
+		val |= (1 << 12);
+		break;
+	case 6:
+		val |= (2 << 12);
+		break;
+	case 8:
+		val |= (3 << 12);
+		break;
+	case 2:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (slot_width) {
+	case 20:
+		val |= (1 << 10);
+		break;
+	case 24:
+		val |= (2 << 10);
+		break;
+	case 32:
+		val |= (3 << 10);
+		break;
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5670_TDM_CTRL_1, 0x7c00, val);
+
+	return 0;
+}
+
+static int rt5670_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct snd_soc_component *component = dai->component;
+
+	dev_dbg(component->dev, "%s ratio=%d\n", __func__, ratio);
+	if (dai->id != RT5670_AIF1)
+		return 0;
+
+	if ((ratio % 50) == 0)
+		snd_soc_component_update_bits(component, RT5670_GEN_CTRL3,
+			RT5670_TDM_DATA_MODE_SEL, RT5670_TDM_DATA_MODE_50FS);
+	else
+		snd_soc_component_update_bits(component, RT5670_GEN_CTRL3,
+			RT5670_TDM_DATA_MODE_SEL, RT5670_TDM_DATA_MODE_NOR);
+
+	return 0;
+}
+
+static int rt5670_set_bias_level(struct snd_soc_component *component,
+			enum snd_soc_bias_level level)
+{
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		if (SND_SOC_BIAS_STANDBY == snd_soc_component_get_bias_level(component)) {
+			snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
+				RT5670_PWR_VREF1 | RT5670_PWR_MB |
+				RT5670_PWR_BG | RT5670_PWR_VREF2,
+				RT5670_PWR_VREF1 | RT5670_PWR_MB |
+				RT5670_PWR_BG | RT5670_PWR_VREF2);
+			mdelay(10);
+			snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
+				RT5670_PWR_FV1 | RT5670_PWR_FV2,
+				RT5670_PWR_FV1 | RT5670_PWR_FV2);
+			snd_soc_component_update_bits(component, RT5670_CHARGE_PUMP,
+				RT5670_OSW_L_MASK | RT5670_OSW_R_MASK,
+				RT5670_OSW_L_DIS | RT5670_OSW_R_DIS);
+			snd_soc_component_update_bits(component, RT5670_DIG_MISC, 0x1, 0x1);
+			snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
+				RT5670_LDO_SEL_MASK, 0x5);
+		}
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
+				RT5670_PWR_VREF1 | RT5670_PWR_VREF2 |
+				RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);
+		snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
+				RT5670_LDO_SEL_MASK, 0x3);
+		break;
+	case SND_SOC_BIAS_OFF:
+		if (rt5670->pdata.jd_mode)
+			snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
+				RT5670_PWR_VREF1 | RT5670_PWR_MB |
+				RT5670_PWR_BG | RT5670_PWR_VREF2 |
+				RT5670_PWR_FV1 | RT5670_PWR_FV2,
+				RT5670_PWR_MB | RT5670_PWR_BG);
+		else
+			snd_soc_component_update_bits(component, RT5670_PWR_ANLG1,
+				RT5670_PWR_VREF1 | RT5670_PWR_MB |
+				RT5670_PWR_BG | RT5670_PWR_VREF2 |
+				RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);
+
+		snd_soc_component_update_bits(component, RT5670_DIG_MISC, 0x1, 0x0);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5670_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+
+	switch (snd_soc_component_read32(component, RT5670_RESET) & RT5670_ID_MASK) {
+	case RT5670_ID_5670:
+	case RT5670_ID_5671:
+		snd_soc_dapm_new_controls(dapm,
+			rt5670_specific_dapm_widgets,
+			ARRAY_SIZE(rt5670_specific_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm,
+			rt5670_specific_dapm_routes,
+			ARRAY_SIZE(rt5670_specific_dapm_routes));
+		break;
+	case RT5670_ID_5672:
+		snd_soc_dapm_new_controls(dapm,
+			rt5672_specific_dapm_widgets,
+			ARRAY_SIZE(rt5672_specific_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm,
+			rt5672_specific_dapm_routes,
+			ARRAY_SIZE(rt5672_specific_dapm_routes));
+		break;
+	default:
+		dev_err(component->dev,
+			"The driver is for RT5670 RT5671 or RT5672 only\n");
+		return -ENODEV;
+	}
+	rt5670->component = component;
+
+	return 0;
+}
+
+static void rt5670_remove(struct snd_soc_component *component)
+{
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+
+	regmap_write(rt5670->regmap, RT5670_RESET, 0);
+	snd_soc_jack_free_gpios(rt5670->jack, 1, &rt5670->hp_gpio);
+}
+
+#ifdef CONFIG_PM
+static int rt5670_suspend(struct snd_soc_component *component)
+{
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5670->regmap, true);
+	regcache_mark_dirty(rt5670->regmap);
+	return 0;
+}
+
+static int rt5670_resume(struct snd_soc_component *component)
+{
+	struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5670->regmap, false);
+	regcache_sync(rt5670->regmap);
+
+	return 0;
+}
+#else
+#define rt5670_suspend NULL
+#define rt5670_resume NULL
+#endif
+
+#define RT5670_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define RT5670_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5670_aif_dai_ops = {
+	.hw_params = rt5670_hw_params,
+	.set_fmt = rt5670_set_dai_fmt,
+	.set_tdm_slot = rt5670_set_tdm_slot,
+	.set_pll = rt5670_set_dai_pll,
+	.set_bclk_ratio = rt5670_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt5670_dai[] = {
+	{
+		.name = "rt5670-aif1",
+		.id = RT5670_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5670_STEREO_RATES,
+			.formats = RT5670_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5670_STEREO_RATES,
+			.formats = RT5670_FORMATS,
+		},
+		.ops = &rt5670_aif_dai_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "rt5670-aif2",
+		.id = RT5670_AIF2,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5670_STEREO_RATES,
+			.formats = RT5670_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5670_STEREO_RATES,
+			.formats = RT5670_FORMATS,
+		},
+		.ops = &rt5670_aif_dai_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5670 = {
+	.probe			= rt5670_probe,
+	.remove			= rt5670_remove,
+	.suspend		= rt5670_suspend,
+	.resume			= rt5670_resume,
+	.set_bias_level		= rt5670_set_bias_level,
+	.set_sysclk		= rt5670_set_codec_sysclk,
+	.controls		= rt5670_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5670_snd_controls),
+	.dapm_widgets		= rt5670_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5670_dapm_widgets),
+	.dapm_routes		= rt5670_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5670_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt5670_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.use_single_rw = true,
+	.max_register = RT5670_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5670_ranges) *
+					       RT5670_PR_SPACING),
+	.volatile_reg = rt5670_volatile_register,
+	.readable_reg = rt5670_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5670_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5670_reg),
+	.ranges = rt5670_ranges,
+	.num_ranges = ARRAY_SIZE(rt5670_ranges),
+};
+
+static const struct i2c_device_id rt5670_i2c_id[] = {
+	{ "rt5670", 0 },
+	{ "rt5671", 0 },
+	{ "rt5672", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5670_acpi_match[] = {
+	{ "10EC5670", 0},
+	{ "10EC5672", 0},
+	{ "10EC5640", 0}, /* quirk */
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
+#endif
+
+static int rt5670_quirk_cb(const struct dmi_system_id *id)
+{
+	rt5670_quirk = (unsigned long)id->driver_data;
+	return 1;
+}
+
+static const struct dmi_system_id dmi_platform_intel_quirks[] = {
+	{
+		.callback = rt5670_quirk_cb,
+		.ident = "Intel Braswell",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+			DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"),
+		},
+		.driver_data = (unsigned long *)(RT5670_DMIC_EN |
+						 RT5670_DMIC1_IN2P |
+						 RT5670_DEV_GPIO |
+						 RT5670_JD_MODE1),
+	},
+	{
+		.callback = rt5670_quirk_cb,
+		.ident = "Dell Wyse 3040",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Wyse 3040"),
+		},
+		.driver_data = (unsigned long *)(RT5670_DMIC_EN |
+						 RT5670_DMIC1_IN2P |
+						 RT5670_DEV_GPIO |
+						 RT5670_JD_MODE1),
+	},
+	{
+		.callback = rt5670_quirk_cb,
+		.ident = "Lenovo Thinkpad Tablet 10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 10"),
+		},
+		.driver_data = (unsigned long *)(RT5670_DMIC_EN |
+						 RT5670_DMIC1_IN2P |
+						 RT5670_DEV_GPIO |
+						 RT5670_JD_MODE1),
+	},
+	{
+		.callback = rt5670_quirk_cb,
+		.ident = "Lenovo Thinkpad Tablet 10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Tablet B"),
+		},
+		.driver_data = (unsigned long *)(RT5670_DMIC_EN |
+						 RT5670_DMIC1_IN2P |
+						 RT5670_DEV_GPIO |
+						 RT5670_JD_MODE1),
+	},
+	{
+		.callback = rt5670_quirk_cb,
+		.ident = "Lenovo Thinkpad Tablet 10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Miix 2 10"),
+		},
+		.driver_data = (unsigned long *)(RT5670_DMIC_EN |
+						 RT5670_DMIC1_IN2P |
+						 RT5670_DEV_GPIO |
+						 RT5670_JD_MODE2),
+	},
+	{
+		.callback = rt5670_quirk_cb,
+		.ident = "Dell Venue 8 Pro 5855",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5855"),
+		},
+		.driver_data = (unsigned long *)(RT5670_DMIC_EN |
+						 RT5670_DMIC2_INR |
+						 RT5670_DEV_GPIO |
+						 RT5670_JD_MODE3),
+	},
+	{}
+};
+
+static int rt5670_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5670_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt5670_priv *rt5670;
+	int ret;
+	unsigned int val;
+
+	rt5670 = devm_kzalloc(&i2c->dev,
+				sizeof(struct rt5670_priv),
+				GFP_KERNEL);
+	if (NULL == rt5670)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt5670);
+
+	if (pdata)
+		rt5670->pdata = *pdata;
+
+	dmi_check_system(dmi_platform_intel_quirks);
+	if (quirk_override) {
+		dev_info(&i2c->dev, "Overriding quirk 0x%x => 0x%x\n",
+			 (unsigned int)rt5670_quirk, quirk_override);
+		rt5670_quirk = quirk_override;
+	}
+
+	if (rt5670_quirk & RT5670_DEV_GPIO) {
+		rt5670->pdata.dev_gpio = true;
+		dev_info(&i2c->dev, "quirk dev_gpio\n");
+	}
+	if (rt5670_quirk & RT5670_IN2_DIFF) {
+		rt5670->pdata.in2_diff = true;
+		dev_info(&i2c->dev, "quirk IN2_DIFF\n");
+	}
+	if (rt5670_quirk & RT5670_DMIC_EN) {
+		rt5670->pdata.dmic_en = true;
+		dev_info(&i2c->dev, "quirk DMIC enabled\n");
+	}
+	if (rt5670_quirk & RT5670_DMIC1_IN2P) {
+		rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
+		dev_info(&i2c->dev, "quirk DMIC1 on IN2P pin\n");
+	}
+	if (rt5670_quirk & RT5670_DMIC1_GPIO6) {
+		rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_GPIO6;
+		dev_info(&i2c->dev, "quirk DMIC1 on GPIO6 pin\n");
+	}
+	if (rt5670_quirk & RT5670_DMIC1_GPIO7) {
+		rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_GPIO7;
+		dev_info(&i2c->dev, "quirk DMIC1 on GPIO7 pin\n");
+	}
+	if (rt5670_quirk & RT5670_DMIC2_INR) {
+		rt5670->pdata.dmic2_data_pin = RT5670_DMIC_DATA_IN3N;
+		dev_info(&i2c->dev, "quirk DMIC2 on INR pin\n");
+	}
+	if (rt5670_quirk & RT5670_DMIC2_GPIO8) {
+		rt5670->pdata.dmic2_data_pin = RT5670_DMIC_DATA_GPIO8;
+		dev_info(&i2c->dev, "quirk DMIC2 on GPIO8 pin\n");
+	}
+	if (rt5670_quirk & RT5670_DMIC3_GPIO5) {
+		rt5670->pdata.dmic3_data_pin = RT5670_DMIC_DATA_GPIO5;
+		dev_info(&i2c->dev, "quirk DMIC3 on GPIO5 pin\n");
+	}
+
+	if (rt5670_quirk & RT5670_JD_MODE1) {
+		rt5670->pdata.jd_mode = 1;
+		dev_info(&i2c->dev, "quirk JD mode 1\n");
+	}
+	if (rt5670_quirk & RT5670_JD_MODE2) {
+		rt5670->pdata.jd_mode = 2;
+		dev_info(&i2c->dev, "quirk JD mode 2\n");
+	}
+	if (rt5670_quirk & RT5670_JD_MODE3) {
+		rt5670->pdata.jd_mode = 3;
+		dev_info(&i2c->dev, "quirk JD mode 3\n");
+	}
+
+	rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap);
+	if (IS_ERR(rt5670->regmap)) {
+		ret = PTR_ERR(rt5670->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt5670->regmap, RT5670_VENDOR_ID2, &val);
+	if (val != RT5670_DEVICE_ID) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt5670/72\n", val);
+		return -ENODEV;
+	}
+
+	regmap_write(rt5670->regmap, RT5670_RESET, 0);
+	regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1,
+		RT5670_PWR_HP_L | RT5670_PWR_HP_R |
+		RT5670_PWR_VREF2, RT5670_PWR_VREF2);
+	msleep(100);
+
+	regmap_write(rt5670->regmap, RT5670_RESET, 0);
+
+	regmap_read(rt5670->regmap, RT5670_VENDOR_ID, &val);
+	if (val >= 4)
+		regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0980);
+	else
+		regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0d00);
+
+	ret = regmap_register_patch(rt5670->regmap, init_list,
+				    ARRAY_SIZE(init_list));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC,
+				 RT5670_MCLK_DET, RT5670_MCLK_DET);
+
+	if (rt5670->pdata.in2_diff)
+		regmap_update_bits(rt5670->regmap, RT5670_IN2,
+					RT5670_IN_DF2, RT5670_IN_DF2);
+
+	if (rt5670->pdata.dev_gpio) {
+		/* for push button */
+		regmap_write(rt5670->regmap, RT5670_IL_CMD, 0x0000);
+		regmap_write(rt5670->regmap, RT5670_IL_CMD2, 0x0010);
+		regmap_write(rt5670->regmap, RT5670_IL_CMD3, 0x0014);
+		/* for irq */
+		regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1,
+				   RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ);
+		regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL2,
+				   RT5670_GP1_PF_MASK, RT5670_GP1_PF_OUT);
+	}
+
+	if (rt5670->pdata.jd_mode) {
+		regmap_update_bits(rt5670->regmap, RT5670_GLB_CLK,
+				   RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_RCCLK);
+		rt5670->sysclk = 0;
+		rt5670->sysclk_src = RT5670_SCLK_S_RCCLK;
+		regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1,
+				   RT5670_PWR_MB, RT5670_PWR_MB);
+		regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG2,
+				   RT5670_PWR_JD1, RT5670_PWR_JD1);
+		regmap_update_bits(rt5670->regmap, RT5670_IRQ_CTRL1,
+				   RT5670_JD1_1_EN_MASK, RT5670_JD1_1_EN);
+		regmap_update_bits(rt5670->regmap, RT5670_JD_CTRL3,
+				   RT5670_JD_TRI_CBJ_SEL_MASK |
+				   RT5670_JD_TRI_HPO_SEL_MASK,
+				   RT5670_JD_CBJ_JD1_1 | RT5670_JD_HPO_JD1_1);
+		switch (rt5670->pdata.jd_mode) {
+		case 1:
+			regmap_update_bits(rt5670->regmap, RT5670_A_JD_CTRL1,
+					   RT5670_JD1_MODE_MASK,
+					   RT5670_JD1_MODE_0);
+			break;
+		case 2:
+			regmap_update_bits(rt5670->regmap, RT5670_A_JD_CTRL1,
+					   RT5670_JD1_MODE_MASK,
+					   RT5670_JD1_MODE_1);
+			break;
+		case 3:
+			regmap_update_bits(rt5670->regmap, RT5670_A_JD_CTRL1,
+					   RT5670_JD1_MODE_MASK,
+					   RT5670_JD1_MODE_2);
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (rt5670->pdata.dmic_en) {
+		regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1,
+				   RT5670_GP2_PIN_MASK,
+				   RT5670_GP2_PIN_DMIC1_SCL);
+
+		switch (rt5670->pdata.dmic1_data_pin) {
+		case RT5670_DMIC_DATA_IN2P:
+			regmap_update_bits(rt5670->regmap, RT5670_DMIC_CTRL1,
+					   RT5670_DMIC_1_DP_MASK,
+					   RT5670_DMIC_1_DP_IN2P);
+			break;
+
+		case RT5670_DMIC_DATA_GPIO6:
+			regmap_update_bits(rt5670->regmap, RT5670_DMIC_CTRL1,
+					   RT5670_DMIC_1_DP_MASK,
+					   RT5670_DMIC_1_DP_GPIO6);
+			regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1,
+					   RT5670_GP6_PIN_MASK,
+					   RT5670_GP6_PIN_DMIC1_SDA);
+			break;
+
+		case RT5670_DMIC_DATA_GPIO7:
+			regmap_update_bits(rt5670->regmap, RT5670_DMIC_CTRL1,
+					   RT5670_DMIC_1_DP_MASK,
+					   RT5670_DMIC_1_DP_GPIO7);
+			regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1,
+					   RT5670_GP7_PIN_MASK,
+					   RT5670_GP7_PIN_DMIC1_SDA);
+			break;
+
+		default:
+			break;
+		}
+
+		switch (rt5670->pdata.dmic2_data_pin) {
+		case RT5670_DMIC_DATA_IN3N:
+			regmap_update_bits(rt5670->regmap, RT5670_DMIC_CTRL1,
+					   RT5670_DMIC_2_DP_MASK,
+					   RT5670_DMIC_2_DP_IN3N);
+			break;
+
+		case RT5670_DMIC_DATA_GPIO8:
+			regmap_update_bits(rt5670->regmap, RT5670_DMIC_CTRL1,
+					   RT5670_DMIC_2_DP_MASK,
+					   RT5670_DMIC_2_DP_GPIO8);
+			regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1,
+					   RT5670_GP8_PIN_MASK,
+					   RT5670_GP8_PIN_DMIC2_SDA);
+			break;
+
+		default:
+			break;
+		}
+
+		switch (rt5670->pdata.dmic3_data_pin) {
+		case RT5670_DMIC_DATA_GPIO5:
+			regmap_update_bits(rt5670->regmap, RT5670_DMIC_CTRL2,
+					   RT5670_DMIC_3_DP_MASK,
+					   RT5670_DMIC_3_DP_GPIO5);
+			regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1,
+					   RT5670_GP5_PIN_MASK,
+					   RT5670_GP5_PIN_DMIC3_SDA);
+			break;
+
+		case RT5670_DMIC_DATA_GPIO9:
+		case RT5670_DMIC_DATA_GPIO10:
+			dev_err(&i2c->dev,
+				"Always use GPIO5 as DMIC3 data pin\n");
+			break;
+
+		default:
+			break;
+		}
+
+	}
+
+	pm_runtime_enable(&i2c->dev);
+	pm_request_idle(&i2c->dev);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_rt5670,
+			rt5670_dai, ARRAY_SIZE(rt5670_dai));
+	if (ret < 0)
+		goto err;
+
+	pm_runtime_put(&i2c->dev);
+
+	return 0;
+err:
+	pm_runtime_disable(&i2c->dev);
+
+	return ret;
+}
+
+static int rt5670_i2c_remove(struct i2c_client *i2c)
+{
+	pm_runtime_disable(&i2c->dev);
+
+	return 0;
+}
+
+static struct i2c_driver rt5670_i2c_driver = {
+	.driver = {
+		.name = "rt5670",
+		.acpi_match_table = ACPI_PTR(rt5670_acpi_match),
+	},
+	.probe = rt5670_i2c_probe,
+	.remove   = rt5670_i2c_remove,
+	.id_table = rt5670_i2c_id,
+};
+
+module_i2c_driver(rt5670_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5670 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h
new file mode 100644
index 0000000..97e8eeb
--- /dev/null
+++ b/sound/soc/codecs/rt5670.h
@@ -0,0 +1,2019 @@
+/*
+ * rt5670.h  --  RT5670 ALSA SoC audio driver
+ *
+ * Copyright 2014 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5670_H__
+#define __RT5670_H__
+
+#include <sound/rt5670.h>
+
+/* Info */
+#define RT5670_RESET				0x00
+#define RT5670_VENDOR_ID			0xfd
+#define RT5670_VENDOR_ID1			0xfe
+#define RT5670_VENDOR_ID2			0xff
+/*  I/O - Output */
+#define RT5670_HP_VOL				0x02
+#define RT5670_LOUT1				0x03
+/* I/O - Input */
+#define RT5670_CJ_CTRL1				0x0a
+#define RT5670_CJ_CTRL2				0x0b
+#define RT5670_CJ_CTRL3				0x0c
+#define RT5670_IN2				0x0e
+#define RT5670_INL1_INR1_VOL			0x0f
+/* I/O - ADC/DAC/DMIC */
+#define RT5670_DAC1_DIG_VOL			0x19
+#define RT5670_DAC2_DIG_VOL			0x1a
+#define RT5670_DAC_CTRL				0x1b
+#define RT5670_STO1_ADC_DIG_VOL			0x1c
+#define RT5670_MONO_ADC_DIG_VOL			0x1d
+#define RT5670_ADC_BST_VOL1			0x1e
+#define RT5670_STO2_ADC_DIG_VOL			0x1f
+/* Mixer - D-D */
+#define RT5670_ADC_BST_VOL2			0x20
+#define RT5670_STO2_ADC_MIXER			0x26
+#define RT5670_STO1_ADC_MIXER			0x27
+#define RT5670_MONO_ADC_MIXER			0x28
+#define RT5670_AD_DA_MIXER			0x29
+#define RT5670_STO_DAC_MIXER			0x2a
+#define RT5670_DD_MIXER				0x2b
+#define RT5670_DIG_MIXER			0x2c
+#define RT5670_DSP_PATH1			0x2d
+#define RT5670_DSP_PATH2			0x2e
+#define RT5670_DIG_INF1_DATA			0x2f
+#define RT5670_DIG_INF2_DATA			0x30
+/* Mixer - PDM */
+#define RT5670_PDM_OUT_CTRL			0x31
+#define RT5670_PDM_DATA_CTRL1			0x32
+#define RT5670_PDM1_DATA_CTRL2			0x33
+#define RT5670_PDM1_DATA_CTRL3			0x34
+#define RT5670_PDM1_DATA_CTRL4			0x35
+#define RT5670_PDM2_DATA_CTRL2			0x36
+#define RT5670_PDM2_DATA_CTRL3			0x37
+#define RT5670_PDM2_DATA_CTRL4			0x38
+/* Mixer - ADC */
+#define RT5670_REC_L1_MIXER			0x3b
+#define RT5670_REC_L2_MIXER			0x3c
+#define RT5670_REC_R1_MIXER			0x3d
+#define RT5670_REC_R2_MIXER			0x3e
+/* Mixer - DAC */
+#define RT5670_HPO_MIXER			0x45
+#define RT5670_MONO_MIXER			0x4c
+#define RT5670_OUT_L1_MIXER			0x4f
+#define RT5670_OUT_R1_MIXER			0x52
+#define RT5670_LOUT_MIXER			0x53
+/* Power */
+#define RT5670_PWR_DIG1				0x61
+#define RT5670_PWR_DIG2				0x62
+#define RT5670_PWR_ANLG1			0x63
+#define RT5670_PWR_ANLG2			0x64
+#define RT5670_PWR_MIXER			0x65
+#define RT5670_PWR_VOL				0x66
+/* Private Register Control */
+#define RT5670_PRIV_INDEX			0x6a
+#define RT5670_PRIV_DATA			0x6c
+/* Format - ADC/DAC */
+#define RT5670_I2S4_SDP				0x6f
+#define RT5670_I2S1_SDP				0x70
+#define RT5670_I2S2_SDP				0x71
+#define RT5670_I2S3_SDP				0x72
+#define RT5670_ADDA_CLK1			0x73
+#define RT5670_ADDA_CLK2			0x74
+#define RT5670_DMIC_CTRL1			0x75
+#define RT5670_DMIC_CTRL2			0x76
+/* Format - TDM Control */
+#define RT5670_TDM_CTRL_1			0x77
+#define RT5670_TDM_CTRL_2			0x78
+#define RT5670_TDM_CTRL_3			0x79
+
+/* Function - Analog */
+#define RT5670_DSP_CLK				0x7f
+#define RT5670_GLB_CLK				0x80
+#define RT5670_PLL_CTRL1			0x81
+#define RT5670_PLL_CTRL2			0x82
+#define RT5670_ASRC_1				0x83
+#define RT5670_ASRC_2				0x84
+#define RT5670_ASRC_3				0x85
+#define RT5670_ASRC_4				0x86
+#define RT5670_ASRC_5				0x87
+#define RT5670_ASRC_7				0x89
+#define RT5670_ASRC_8				0x8a
+#define RT5670_ASRC_9				0x8b
+#define RT5670_ASRC_10				0x8c
+#define RT5670_ASRC_11				0x8d
+#define RT5670_DEPOP_M1				0x8e
+#define RT5670_DEPOP_M2				0x8f
+#define RT5670_DEPOP_M3				0x90
+#define RT5670_CHARGE_PUMP			0x91
+#define RT5670_MICBIAS				0x93
+#define RT5670_A_JD_CTRL1			0x94
+#define RT5670_A_JD_CTRL2			0x95
+#define RT5670_ASRC_12				0x97
+#define RT5670_ASRC_13				0x98
+#define RT5670_ASRC_14				0x99
+#define RT5670_VAD_CTRL1			0x9a
+#define RT5670_VAD_CTRL2			0x9b
+#define RT5670_VAD_CTRL3			0x9c
+#define RT5670_VAD_CTRL4			0x9d
+#define RT5670_VAD_CTRL5			0x9e
+/* Function - Digital */
+#define RT5670_ADC_EQ_CTRL1			0xae
+#define RT5670_ADC_EQ_CTRL2			0xaf
+#define RT5670_EQ_CTRL1				0xb0
+#define RT5670_EQ_CTRL2				0xb1
+#define RT5670_ALC_DRC_CTRL1			0xb2
+#define RT5670_ALC_DRC_CTRL2			0xb3
+#define RT5670_ALC_CTRL_1			0xb4
+#define RT5670_ALC_CTRL_2			0xb5
+#define RT5670_ALC_CTRL_3			0xb6
+#define RT5670_ALC_CTRL_4			0xb7
+#define RT5670_JD_CTRL				0xbb
+#define RT5670_IRQ_CTRL1			0xbd
+#define RT5670_IRQ_CTRL2			0xbe
+#define RT5670_INT_IRQ_ST			0xbf
+#define RT5670_GPIO_CTRL1			0xc0
+#define RT5670_GPIO_CTRL2			0xc1
+#define RT5670_GPIO_CTRL3			0xc2
+#define RT5670_SCRABBLE_FUN			0xcd
+#define RT5670_SCRABBLE_CTRL			0xce
+#define RT5670_BASE_BACK			0xcf
+#define RT5670_MP3_PLUS1			0xd0
+#define RT5670_MP3_PLUS2			0xd1
+#define RT5670_ADJ_HPF1				0xd3
+#define RT5670_ADJ_HPF2				0xd4
+#define RT5670_HP_CALIB_AMP_DET			0xd6
+#define RT5670_SV_ZCD1				0xd9
+#define RT5670_SV_ZCD2				0xda
+#define RT5670_IL_CMD				0xdb
+#define RT5670_IL_CMD2				0xdc
+#define RT5670_IL_CMD3				0xdd
+#define RT5670_DRC_HL_CTRL1			0xe6
+#define RT5670_DRC_HL_CTRL2			0xe7
+#define RT5670_ADC_MONO_HP_CTRL1		0xec
+#define RT5670_ADC_MONO_HP_CTRL2		0xed
+#define RT5670_ADC_STO2_HP_CTRL1		0xee
+#define RT5670_ADC_STO2_HP_CTRL2		0xef
+#define RT5670_JD_CTRL3				0xf8
+#define RT5670_JD_CTRL4				0xf9
+/* General Control */
+#define RT5670_DIG_MISC				0xfa
+#define RT5670_GEN_CTRL2			0xfb
+#define RT5670_GEN_CTRL3			0xfc
+
+
+/* Index of Codec Private Register definition */
+#define RT5670_DIG_VOL				0x00
+#define RT5670_PR_ALC_CTRL_1			0x01
+#define RT5670_PR_ALC_CTRL_2			0x02
+#define RT5670_PR_ALC_CTRL_3			0x03
+#define RT5670_PR_ALC_CTRL_4			0x04
+#define RT5670_PR_ALC_CTRL_5			0x05
+#define RT5670_PR_ALC_CTRL_6			0x06
+#define RT5670_BIAS_CUR1			0x12
+#define RT5670_BIAS_CUR3			0x14
+#define RT5670_CLSD_INT_REG1			0x1c
+#define RT5670_MAMP_INT_REG2			0x37
+#define RT5670_CHOP_DAC_ADC			0x3d
+#define RT5670_MIXER_INT_REG			0x3f
+#define RT5670_3D_SPK				0x63
+#define RT5670_WND_1				0x6c
+#define RT5670_WND_2				0x6d
+#define RT5670_WND_3				0x6e
+#define RT5670_WND_4				0x6f
+#define RT5670_WND_5				0x70
+#define RT5670_WND_8				0x73
+#define RT5670_DIP_SPK_INF			0x75
+#define RT5670_HP_DCC_INT1			0x77
+#define RT5670_EQ_BW_LOP			0xa0
+#define RT5670_EQ_GN_LOP			0xa1
+#define RT5670_EQ_FC_BP1			0xa2
+#define RT5670_EQ_BW_BP1			0xa3
+#define RT5670_EQ_GN_BP1			0xa4
+#define RT5670_EQ_FC_BP2			0xa5
+#define RT5670_EQ_BW_BP2			0xa6
+#define RT5670_EQ_GN_BP2			0xa7
+#define RT5670_EQ_FC_BP3			0xa8
+#define RT5670_EQ_BW_BP3			0xa9
+#define RT5670_EQ_GN_BP3			0xaa
+#define RT5670_EQ_FC_BP4			0xab
+#define RT5670_EQ_BW_BP4			0xac
+#define RT5670_EQ_GN_BP4			0xad
+#define RT5670_EQ_FC_HIP1			0xae
+#define RT5670_EQ_GN_HIP1			0xaf
+#define RT5670_EQ_FC_HIP2			0xb0
+#define RT5670_EQ_BW_HIP2			0xb1
+#define RT5670_EQ_GN_HIP2			0xb2
+#define RT5670_EQ_PRE_VOL			0xb3
+#define RT5670_EQ_PST_VOL			0xb4
+
+
+/* global definition */
+#define RT5670_L_MUTE				(0x1 << 15)
+#define RT5670_L_MUTE_SFT			15
+#define RT5670_VOL_L_MUTE			(0x1 << 14)
+#define RT5670_VOL_L_SFT			14
+#define RT5670_R_MUTE				(0x1 << 7)
+#define RT5670_R_MUTE_SFT			7
+#define RT5670_VOL_R_MUTE			(0x1 << 6)
+#define RT5670_VOL_R_SFT			6
+#define RT5670_L_VOL_MASK			(0x3f << 8)
+#define RT5670_L_VOL_SFT			8
+#define RT5670_R_VOL_MASK			(0x3f)
+#define RT5670_R_VOL_SFT			0
+
+/* SW Reset & Device ID (0x00) */
+#define RT5670_ID_MASK				(0x3 << 1)
+#define RT5670_ID_5670				(0x0 << 1)
+#define RT5670_ID_5672				(0x1 << 1)
+#define RT5670_ID_5671				(0x2 << 1)
+
+/* Combo Jack Control 1 (0x0a) */
+#define RT5670_CBJ_BST1_MASK			(0xf << 12)
+#define RT5670_CBJ_BST1_SFT			(12)
+#define RT5670_CBJ_JD_HP_EN			(0x1 << 9)
+#define RT5670_CBJ_JD_MIC_EN			(0x1 << 8)
+#define RT5670_CBJ_BST1_EN			(0x1 << 2)
+
+/* Combo Jack Control 1 (0x0b) */
+#define RT5670_CBJ_MN_JD			(0x1 << 12)
+#define RT5670_CAPLESS_EN			(0x1 << 11)
+#define RT5670_CBJ_DET_MODE			(0x1 << 7)
+
+/* IN2 Control (0x0e) */
+#define RT5670_BST_MASK1			(0xf<<12)
+#define RT5670_BST_SFT1				12
+#define RT5670_BST_MASK2			(0xf<<8)
+#define RT5670_BST_SFT2				8
+#define RT5670_IN_DF1				(0x1 << 7)
+#define RT5670_IN_SFT1				7
+#define RT5670_IN_DF2				(0x1 << 6)
+#define RT5670_IN_SFT2				6
+
+/* INL and INR Volume Control (0x0f) */
+#define RT5670_INL_SEL_MASK			(0x1 << 15)
+#define RT5670_INL_SEL_SFT			15
+#define RT5670_INL_SEL_IN4P			(0x0 << 15)
+#define RT5670_INL_SEL_MONOP			(0x1 << 15)
+#define RT5670_INL_VOL_MASK			(0x1f << 8)
+#define RT5670_INL_VOL_SFT			8
+#define RT5670_INR_SEL_MASK			(0x1 << 7)
+#define RT5670_INR_SEL_SFT			7
+#define RT5670_INR_SEL_IN4N			(0x0 << 7)
+#define RT5670_INR_SEL_MONON			(0x1 << 7)
+#define RT5670_INR_VOL_MASK			(0x1f)
+#define RT5670_INR_VOL_SFT			0
+
+/* Sidetone Control (0x18) */
+#define RT5670_ST_SEL_MASK			(0x7 << 9)
+#define RT5670_ST_SEL_SFT			9
+#define RT5670_M_ST_DACR2			(0x1 << 8)
+#define RT5670_M_ST_DACR2_SFT			8
+#define RT5670_M_ST_DACL2			(0x1 << 7)
+#define RT5670_M_ST_DACL2_SFT			7
+#define RT5670_ST_EN				(0x1 << 6)
+#define RT5670_ST_EN_SFT			6
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5670_DAC_L1_VOL_MASK			(0xff << 8)
+#define RT5670_DAC_L1_VOL_SFT			8
+#define RT5670_DAC_R1_VOL_MASK			(0xff)
+#define RT5670_DAC_R1_VOL_SFT			0
+
+/* DAC2 Digital Volume (0x1a) */
+#define RT5670_DAC_L2_VOL_MASK			(0xff << 8)
+#define RT5670_DAC_L2_VOL_SFT			8
+#define RT5670_DAC_R2_VOL_MASK			(0xff)
+#define RT5670_DAC_R2_VOL_SFT			0
+
+/* DAC2 Control (0x1b) */
+#define RT5670_M_DAC_L2_VOL			(0x1 << 13)
+#define RT5670_M_DAC_L2_VOL_SFT			13
+#define RT5670_M_DAC_R2_VOL			(0x1 << 12)
+#define RT5670_M_DAC_R2_VOL_SFT			12
+#define RT5670_DAC2_L_SEL_MASK			(0x7 << 4)
+#define RT5670_DAC2_L_SEL_SFT			4
+#define RT5670_DAC2_R_SEL_MASK			(0x7 << 0)
+#define RT5670_DAC2_R_SEL_SFT			0
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5670_ADC_L_VOL_MASK			(0x7f << 8)
+#define RT5670_ADC_L_VOL_SFT			8
+#define RT5670_ADC_R_VOL_MASK			(0x7f)
+#define RT5670_ADC_R_VOL_SFT			0
+
+/* Mono ADC Digital Volume Control (0x1d) */
+#define RT5670_MONO_ADC_L_VOL_MASK		(0x7f << 8)
+#define RT5670_MONO_ADC_L_VOL_SFT		8
+#define RT5670_MONO_ADC_R_VOL_MASK		(0x7f)
+#define RT5670_MONO_ADC_R_VOL_SFT		0
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5670_STO1_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5670_STO1_ADC_L_BST_SFT		14
+#define RT5670_STO1_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5670_STO1_ADC_R_BST_SFT		12
+#define RT5670_STO1_ADC_COMP_MASK		(0x3 << 10)
+#define RT5670_STO1_ADC_COMP_SFT		10
+#define RT5670_STO2_ADC_L_BST_MASK		(0x3 << 8)
+#define RT5670_STO2_ADC_L_BST_SFT		8
+#define RT5670_STO2_ADC_R_BST_MASK		(0x3 << 6)
+#define RT5670_STO2_ADC_R_BST_SFT		6
+#define RT5670_STO2_ADC_COMP_MASK		(0x3 << 4)
+#define RT5670_STO2_ADC_COMP_SFT		4
+
+/* Stereo2 ADC Mixer Control (0x26) */
+#define RT5670_STO2_ADC_SRC_MASK		(0x1 << 15)
+#define RT5670_STO2_ADC_SRC_SFT			15
+
+/* Stereo ADC Mixer Control (0x26 0x27) */
+#define RT5670_M_ADC_L1				(0x1 << 14)
+#define RT5670_M_ADC_L1_SFT			14
+#define RT5670_M_ADC_L2				(0x1 << 13)
+#define RT5670_M_ADC_L2_SFT			13
+#define RT5670_ADC_1_SRC_MASK			(0x1 << 12)
+#define RT5670_ADC_1_SRC_SFT			12
+#define RT5670_ADC_1_SRC_ADC			(0x1 << 12)
+#define RT5670_ADC_1_SRC_DACMIX			(0x0 << 12)
+#define RT5670_ADC_2_SRC_MASK			(0x1 << 11)
+#define RT5670_ADC_2_SRC_SFT			11
+#define RT5670_ADC_SRC_MASK			(0x1 << 10)
+#define RT5670_ADC_SRC_SFT			10
+#define RT5670_DMIC_SRC_MASK			(0x3 << 8)
+#define RT5670_DMIC_SRC_SFT			8
+#define RT5670_M_ADC_R1				(0x1 << 6)
+#define RT5670_M_ADC_R1_SFT			6
+#define RT5670_M_ADC_R2				(0x1 << 5)
+#define RT5670_M_ADC_R2_SFT			5
+#define RT5670_DMIC3_SRC_MASK			(0x1 << 1)
+#define RT5670_DMIC3_SRC_SFT			0
+
+/* Mono ADC Mixer Control (0x28) */
+#define RT5670_M_MONO_ADC_L1			(0x1 << 14)
+#define RT5670_M_MONO_ADC_L1_SFT		14
+#define RT5670_M_MONO_ADC_L2			(0x1 << 13)
+#define RT5670_M_MONO_ADC_L2_SFT		13
+#define RT5670_MONO_ADC_L1_SRC_MASK		(0x1 << 12)
+#define RT5670_MONO_ADC_L1_SRC_SFT		12
+#define RT5670_MONO_ADC_L1_SRC_DACMIXL		(0x0 << 12)
+#define RT5670_MONO_ADC_L1_SRC_ADCL		(0x1 << 12)
+#define RT5670_MONO_ADC_L2_SRC_MASK		(0x1 << 11)
+#define RT5670_MONO_ADC_L2_SRC_SFT		11
+#define RT5670_MONO_ADC_L_SRC_MASK		(0x1 << 10)
+#define RT5670_MONO_ADC_L_SRC_SFT		10
+#define RT5670_MONO_DMIC_L_SRC_MASK		(0x3 << 8)
+#define RT5670_MONO_DMIC_L_SRC_SFT		8
+#define RT5670_M_MONO_ADC_R1			(0x1 << 6)
+#define RT5670_M_MONO_ADC_R1_SFT		6
+#define RT5670_M_MONO_ADC_R2			(0x1 << 5)
+#define RT5670_M_MONO_ADC_R2_SFT		5
+#define RT5670_MONO_ADC_R1_SRC_MASK		(0x1 << 4)
+#define RT5670_MONO_ADC_R1_SRC_SFT		4
+#define RT5670_MONO_ADC_R1_SRC_ADCR		(0x1 << 4)
+#define RT5670_MONO_ADC_R1_SRC_DACMIXR		(0x0 << 4)
+#define RT5670_MONO_ADC_R2_SRC_MASK		(0x1 << 3)
+#define RT5670_MONO_ADC_R2_SRC_SFT		3
+#define RT5670_MONO_DMIC_R_SRC_MASK		(0x3)
+#define RT5670_MONO_DMIC_R_SRC_SFT		0
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5670_M_ADCMIX_L			(0x1 << 15)
+#define RT5670_M_ADCMIX_L_SFT			15
+#define RT5670_M_DAC1_L				(0x1 << 14)
+#define RT5670_M_DAC1_L_SFT			14
+#define RT5670_DAC1_R_SEL_MASK			(0x3 << 10)
+#define RT5670_DAC1_R_SEL_SFT			10
+#define RT5670_DAC1_R_SEL_IF1			(0x0 << 10)
+#define RT5670_DAC1_R_SEL_IF2			(0x1 << 10)
+#define RT5670_DAC1_R_SEL_IF3			(0x2 << 10)
+#define RT5670_DAC1_R_SEL_IF4			(0x3 << 10)
+#define RT5670_DAC1_L_SEL_MASK			(0x3 << 8)
+#define RT5670_DAC1_L_SEL_SFT			8
+#define RT5670_DAC1_L_SEL_IF1			(0x0 << 8)
+#define RT5670_DAC1_L_SEL_IF2			(0x1 << 8)
+#define RT5670_DAC1_L_SEL_IF3			(0x2 << 8)
+#define RT5670_DAC1_L_SEL_IF4			(0x3 << 8)
+#define RT5670_M_ADCMIX_R			(0x1 << 7)
+#define RT5670_M_ADCMIX_R_SFT			7
+#define RT5670_M_DAC1_R				(0x1 << 6)
+#define RT5670_M_DAC1_R_SFT			6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5670_M_DAC_L1				(0x1 << 14)
+#define RT5670_M_DAC_L1_SFT			14
+#define RT5670_DAC_L1_STO_L_VOL_MASK		(0x1 << 13)
+#define RT5670_DAC_L1_STO_L_VOL_SFT		13
+#define RT5670_M_DAC_L2				(0x1 << 12)
+#define RT5670_M_DAC_L2_SFT			12
+#define RT5670_DAC_L2_STO_L_VOL_MASK		(0x1 << 11)
+#define RT5670_DAC_L2_STO_L_VOL_SFT		11
+#define RT5670_M_DAC_R1_STO_L			(0x1 << 9)
+#define RT5670_M_DAC_R1_STO_L_SFT		9
+#define RT5670_DAC_R1_STO_L_VOL_MASK		(0x1 << 8)
+#define RT5670_DAC_R1_STO_L_VOL_SFT		8
+#define RT5670_M_DAC_R1				(0x1 << 6)
+#define RT5670_M_DAC_R1_SFT			6
+#define RT5670_DAC_R1_STO_R_VOL_MASK		(0x1 << 5)
+#define RT5670_DAC_R1_STO_R_VOL_SFT		5
+#define RT5670_M_DAC_R2				(0x1 << 4)
+#define RT5670_M_DAC_R2_SFT			4
+#define RT5670_DAC_R2_STO_R_VOL_MASK		(0x1 << 3)
+#define RT5670_DAC_R2_STO_R_VOL_SFT		3
+#define RT5670_M_DAC_L1_STO_R			(0x1 << 1)
+#define RT5670_M_DAC_L1_STO_R_SFT		1
+#define RT5670_DAC_L1_STO_R_VOL_MASK		(0x1)
+#define RT5670_DAC_L1_STO_R_VOL_SFT		0
+
+/* Mono DAC Mixer Control (0x2b) */
+#define RT5670_M_DAC_L1_MONO_L			(0x1 << 14)
+#define RT5670_M_DAC_L1_MONO_L_SFT		14
+#define RT5670_DAC_L1_MONO_L_VOL_MASK		(0x1 << 13)
+#define RT5670_DAC_L1_MONO_L_VOL_SFT		13
+#define RT5670_M_DAC_L2_MONO_L			(0x1 << 12)
+#define RT5670_M_DAC_L2_MONO_L_SFT		12
+#define RT5670_DAC_L2_MONO_L_VOL_MASK		(0x1 << 11)
+#define RT5670_DAC_L2_MONO_L_VOL_SFT		11
+#define RT5670_M_DAC_R2_MONO_L			(0x1 << 10)
+#define RT5670_M_DAC_R2_MONO_L_SFT		10
+#define RT5670_DAC_R2_MONO_L_VOL_MASK		(0x1 << 9)
+#define RT5670_DAC_R2_MONO_L_VOL_SFT		9
+#define RT5670_M_DAC_R1_MONO_R			(0x1 << 6)
+#define RT5670_M_DAC_R1_MONO_R_SFT		6
+#define RT5670_DAC_R1_MONO_R_VOL_MASK		(0x1 << 5)
+#define RT5670_DAC_R1_MONO_R_VOL_SFT		5
+#define RT5670_M_DAC_R2_MONO_R			(0x1 << 4)
+#define RT5670_M_DAC_R2_MONO_R_SFT		4
+#define RT5670_DAC_R2_MONO_R_VOL_MASK		(0x1 << 3)
+#define RT5670_DAC_R2_MONO_R_VOL_SFT		3
+#define RT5670_M_DAC_L2_MONO_R			(0x1 << 2)
+#define RT5670_M_DAC_L2_MONO_R_SFT		2
+#define RT5670_DAC_L2_MONO_R_VOL_MASK		(0x1 << 1)
+#define RT5670_DAC_L2_MONO_R_VOL_SFT		1
+
+/* Digital Mixer Control (0x2c) */
+#define RT5670_M_STO_L_DAC_L			(0x1 << 15)
+#define RT5670_M_STO_L_DAC_L_SFT		15
+#define RT5670_STO_L_DAC_L_VOL_MASK		(0x1 << 14)
+#define RT5670_STO_L_DAC_L_VOL_SFT		14
+#define RT5670_M_DAC_L2_DAC_L			(0x1 << 13)
+#define RT5670_M_DAC_L2_DAC_L_SFT		13
+#define RT5670_DAC_L2_DAC_L_VOL_MASK		(0x1 << 12)
+#define RT5670_DAC_L2_DAC_L_VOL_SFT		12
+#define RT5670_M_STO_R_DAC_R			(0x1 << 11)
+#define RT5670_M_STO_R_DAC_R_SFT		11
+#define RT5670_STO_R_DAC_R_VOL_MASK		(0x1 << 10)
+#define RT5670_STO_R_DAC_R_VOL_SFT		10
+#define RT5670_M_DAC_R2_DAC_R			(0x1 << 9)
+#define RT5670_M_DAC_R2_DAC_R_SFT		9
+#define RT5670_DAC_R2_DAC_R_VOL_MASK		(0x1 << 8)
+#define RT5670_DAC_R2_DAC_R_VOL_SFT		8
+#define RT5670_M_DAC_R2_DAC_L			(0x1 << 7)
+#define RT5670_M_DAC_R2_DAC_L_SFT		7
+#define RT5670_DAC_R2_DAC_L_VOL_MASK		(0x1 << 6)
+#define RT5670_DAC_R2_DAC_L_VOL_SFT		6
+#define RT5670_M_DAC_L2_DAC_R			(0x1 << 5)
+#define RT5670_M_DAC_L2_DAC_R_SFT		5
+#define RT5670_DAC_L2_DAC_R_VOL_MASK		(0x1 << 4)
+#define RT5670_DAC_L2_DAC_R_VOL_SFT		4
+
+/* DSP Path Control 1 (0x2d) */
+#define RT5670_RXDP_SEL_MASK			(0x7 << 13)
+#define RT5670_RXDP_SEL_SFT			13
+#define RT5670_RXDP_SRC_MASK			(0x3 << 11)
+#define RT5670_RXDP_SRC_SFT			11
+#define RT5670_RXDP_SRC_NOR			(0x0 << 11)
+#define RT5670_RXDP_SRC_DIV2			(0x1 << 11)
+#define RT5670_RXDP_SRC_DIV3			(0x2 << 11)
+#define RT5670_TXDP_SRC_MASK			(0x3 << 4)
+#define RT5670_TXDP_SRC_SFT			4
+#define RT5670_TXDP_SRC_NOR			(0x0 << 4)
+#define RT5670_TXDP_SRC_DIV2			(0x1 << 4)
+#define RT5670_TXDP_SRC_DIV3			(0x2 << 4)
+#define RT5670_TXDP_SLOT_SEL_MASK		(0x3 << 2)
+#define RT5670_TXDP_SLOT_SEL_SFT		2
+#define RT5670_DSP_UL_SEL			(0x1 << 1)
+#define RT5670_DSP_UL_SFT			1
+#define RT5670_DSP_DL_SEL			0x1
+#define RT5670_DSP_DL_SFT			0
+
+/* DSP Path Control 2 (0x2e) */
+#define RT5670_TXDP_L_VOL_MASK			(0x7f << 8)
+#define RT5670_TXDP_L_VOL_SFT			8
+#define RT5670_TXDP_R_VOL_MASK			(0x7f)
+#define RT5670_TXDP_R_VOL_SFT			0
+
+/* Digital Interface Data Control (0x2f) */
+#define RT5670_IF1_ADC2_IN_SEL			(0x1 << 15)
+#define RT5670_IF1_ADC2_IN_SFT			15
+#define RT5670_IF2_ADC_IN_MASK			(0x7 << 12)
+#define RT5670_IF2_ADC_IN_SFT			12
+#define RT5670_IF2_DAC_SEL_MASK			(0x3 << 10)
+#define RT5670_IF2_DAC_SEL_SFT			10
+#define RT5670_IF2_ADC_SEL_MASK			(0x3 << 8)
+#define RT5670_IF2_ADC_SEL_SFT			8
+
+/* Digital Interface Data Control (0x30) */
+#define RT5670_IF4_ADC_IN_MASK			(0x3 << 4)
+#define RT5670_IF4_ADC_IN_SFT			4
+
+/* PDM Output Control (0x31) */
+#define RT5670_PDM1_L_MASK			(0x1 << 15)
+#define RT5670_PDM1_L_SFT			15
+#define RT5670_M_PDM1_L				(0x1 << 14)
+#define RT5670_M_PDM1_L_SFT			14
+#define RT5670_PDM1_R_MASK			(0x1 << 13)
+#define RT5670_PDM1_R_SFT			13
+#define RT5670_M_PDM1_R				(0x1 << 12)
+#define RT5670_M_PDM1_R_SFT			12
+#define RT5670_PDM2_L_MASK			(0x1 << 11)
+#define RT5670_PDM2_L_SFT			11
+#define RT5670_M_PDM2_L				(0x1 << 10)
+#define RT5670_M_PDM2_L_SFT			10
+#define RT5670_PDM2_R_MASK			(0x1 << 9)
+#define RT5670_PDM2_R_SFT			9
+#define RT5670_M_PDM2_R				(0x1 << 8)
+#define RT5670_M_PDM2_R_SFT			8
+#define RT5670_PDM2_BUSY			(0x1 << 7)
+#define RT5670_PDM1_BUSY			(0x1 << 6)
+#define RT5670_PDM_PATTERN			(0x1 << 5)
+#define RT5670_PDM_GAIN				(0x1 << 4)
+#define RT5670_PDM_DIV_MASK			(0x3)
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5670_G_HP_L_RM_L_MASK			(0x7 << 13)
+#define RT5670_G_HP_L_RM_L_SFT			13
+#define RT5670_G_IN_L_RM_L_MASK			(0x7 << 10)
+#define RT5670_G_IN_L_RM_L_SFT			10
+#define RT5670_G_BST4_RM_L_MASK			(0x7 << 7)
+#define RT5670_G_BST4_RM_L_SFT			7
+#define RT5670_G_BST3_RM_L_MASK			(0x7 << 4)
+#define RT5670_G_BST3_RM_L_SFT			4
+#define RT5670_G_BST2_RM_L_MASK			(0x7 << 1)
+#define RT5670_G_BST2_RM_L_SFT			1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5670_G_BST1_RM_L_MASK			(0x7 << 13)
+#define RT5670_G_BST1_RM_L_SFT			13
+#define RT5670_M_IN_L_RM_L			(0x1 << 5)
+#define RT5670_M_IN_L_RM_L_SFT			5
+#define RT5670_M_BST2_RM_L			(0x1 << 3)
+#define RT5670_M_BST2_RM_L_SFT			3
+#define RT5670_M_BST1_RM_L			(0x1 << 1)
+#define RT5670_M_BST1_RM_L_SFT			1
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5670_G_HP_R_RM_R_MASK			(0x7 << 13)
+#define RT5670_G_HP_R_RM_R_SFT			13
+#define RT5670_G_IN_R_RM_R_MASK			(0x7 << 10)
+#define RT5670_G_IN_R_RM_R_SFT			10
+#define RT5670_G_BST4_RM_R_MASK			(0x7 << 7)
+#define RT5670_G_BST4_RM_R_SFT			7
+#define RT5670_G_BST3_RM_R_MASK			(0x7 << 4)
+#define RT5670_G_BST3_RM_R_SFT			4
+#define RT5670_G_BST2_RM_R_MASK			(0x7 << 1)
+#define RT5670_G_BST2_RM_R_SFT			1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5670_G_BST1_RM_R_MASK			(0x7 << 13)
+#define RT5670_G_BST1_RM_R_SFT			13
+#define RT5670_M_IN_R_RM_R			(0x1 << 5)
+#define RT5670_M_IN_R_RM_R_SFT			5
+#define RT5670_M_BST2_RM_R			(0x1 << 3)
+#define RT5670_M_BST2_RM_R_SFT			3
+#define RT5670_M_BST1_RM_R			(0x1 << 1)
+#define RT5670_M_BST1_RM_R_SFT			1
+
+/* HPMIX Control (0x45) */
+#define RT5670_M_DAC2_HM			(0x1 << 15)
+#define RT5670_M_DAC2_HM_SFT			15
+#define RT5670_M_HPVOL_HM			(0x1 << 14)
+#define RT5670_M_HPVOL_HM_SFT			14
+#define RT5670_M_DAC1_HM			(0x1 << 13)
+#define RT5670_M_DAC1_HM_SFT			13
+#define RT5670_G_HPOMIX_MASK			(0x1 << 12)
+#define RT5670_G_HPOMIX_SFT			12
+#define RT5670_M_INR1_HMR			(0x1 << 3)
+#define RT5670_M_INR1_HMR_SFT			3
+#define RT5670_M_DACR1_HMR			(0x1 << 2)
+#define RT5670_M_DACR1_HMR_SFT			2
+#define RT5670_M_INL1_HML			(0x1 << 1)
+#define RT5670_M_INL1_HML_SFT			1
+#define RT5670_M_DACL1_HML			(0x1)
+#define RT5670_M_DACL1_HML_SFT			0
+
+/* Mono Output Mixer Control (0x4c) */
+#define RT5670_M_DAC_R2_MA			(0x1 << 15)
+#define RT5670_M_DAC_R2_MA_SFT			15
+#define RT5670_M_DAC_L2_MA			(0x1 << 14)
+#define RT5670_M_DAC_L2_MA_SFT			14
+#define RT5670_M_OV_R_MM			(0x1 << 13)
+#define RT5670_M_OV_R_MM_SFT			13
+#define RT5670_M_OV_L_MM			(0x1 << 12)
+#define RT5670_M_OV_L_MM_SFT			12
+#define RT5670_G_MONOMIX_MASK			(0x1 << 10)
+#define RT5670_G_MONOMIX_SFT			10
+#define RT5670_M_DAC_R2_MM			(0x1 << 9)
+#define RT5670_M_DAC_R2_MM_SFT			9
+#define RT5670_M_DAC_L2_MM			(0x1 << 8)
+#define RT5670_M_DAC_L2_MM_SFT			8
+#define RT5670_M_BST4_MM			(0x1 << 7)
+#define RT5670_M_BST4_MM_SFT			7
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5670_G_BST3_OM_L_MASK			(0x7 << 13)
+#define RT5670_G_BST3_OM_L_SFT			13
+#define RT5670_G_BST2_OM_L_MASK			(0x7 << 10)
+#define RT5670_G_BST2_OM_L_SFT			10
+#define RT5670_G_BST1_OM_L_MASK			(0x7 << 7)
+#define RT5670_G_BST1_OM_L_SFT			7
+#define RT5670_G_IN_L_OM_L_MASK			(0x7 << 4)
+#define RT5670_G_IN_L_OM_L_SFT			4
+#define RT5670_G_RM_L_OM_L_MASK			(0x7 << 1)
+#define RT5670_G_RM_L_OM_L_SFT			1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5670_G_DAC_R2_OM_L_MASK		(0x7 << 13)
+#define RT5670_G_DAC_R2_OM_L_SFT		13
+#define RT5670_G_DAC_L2_OM_L_MASK		(0x7 << 10)
+#define RT5670_G_DAC_L2_OM_L_SFT		10
+#define RT5670_G_DAC_L1_OM_L_MASK		(0x7 << 7)
+#define RT5670_G_DAC_L1_OM_L_SFT		7
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5670_M_BST1_OM_L			(0x1 << 5)
+#define RT5670_M_BST1_OM_L_SFT			5
+#define RT5670_M_IN_L_OM_L			(0x1 << 4)
+#define RT5670_M_IN_L_OM_L_SFT			4
+#define RT5670_M_DAC_L2_OM_L			(0x1 << 1)
+#define RT5670_M_DAC_L2_OM_L_SFT		1
+#define RT5670_M_DAC_L1_OM_L			(0x1)
+#define RT5670_M_DAC_L1_OM_L_SFT		0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5670_G_BST4_OM_R_MASK			(0x7 << 13)
+#define RT5670_G_BST4_OM_R_SFT			13
+#define RT5670_G_BST2_OM_R_MASK			(0x7 << 10)
+#define RT5670_G_BST2_OM_R_SFT			10
+#define RT5670_G_BST1_OM_R_MASK			(0x7 << 7)
+#define RT5670_G_BST1_OM_R_SFT			7
+#define RT5670_G_IN_R_OM_R_MASK			(0x7 << 4)
+#define RT5670_G_IN_R_OM_R_SFT			4
+#define RT5670_G_RM_R_OM_R_MASK			(0x7 << 1)
+#define RT5670_G_RM_R_OM_R_SFT			1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5670_G_DAC_L2_OM_R_MASK		(0x7 << 13)
+#define RT5670_G_DAC_L2_OM_R_SFT		13
+#define RT5670_G_DAC_R2_OM_R_MASK		(0x7 << 10)
+#define RT5670_G_DAC_R2_OM_R_SFT		10
+#define RT5670_G_DAC_R1_OM_R_MASK		(0x7 << 7)
+#define RT5670_G_DAC_R1_OM_R_SFT		7
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5670_M_BST2_OM_R			(0x1 << 6)
+#define RT5670_M_BST2_OM_R_SFT			6
+#define RT5670_M_IN_R_OM_R			(0x1 << 4)
+#define RT5670_M_IN_R_OM_R_SFT			4
+#define RT5670_M_DAC_R2_OM_R			(0x1 << 1)
+#define RT5670_M_DAC_R2_OM_R_SFT		1
+#define RT5670_M_DAC_R1_OM_R			(0x1)
+#define RT5670_M_DAC_R1_OM_R_SFT		0
+
+/* LOUT Mixer Control (0x53) */
+#define RT5670_M_DAC_L1_LM			(0x1 << 15)
+#define RT5670_M_DAC_L1_LM_SFT			15
+#define RT5670_M_DAC_R1_LM			(0x1 << 14)
+#define RT5670_M_DAC_R1_LM_SFT			14
+#define RT5670_M_OV_L_LM			(0x1 << 13)
+#define RT5670_M_OV_L_LM_SFT			13
+#define RT5670_M_OV_R_LM			(0x1 << 12)
+#define RT5670_M_OV_R_LM_SFT			12
+#define RT5670_G_LOUTMIX_MASK			(0x1 << 11)
+#define RT5670_G_LOUTMIX_SFT			11
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5670_PWR_I2S1				(0x1 << 15)
+#define RT5670_PWR_I2S1_BIT			15
+#define RT5670_PWR_I2S2				(0x1 << 14)
+#define RT5670_PWR_I2S2_BIT			14
+#define RT5670_PWR_DAC_L1			(0x1 << 12)
+#define RT5670_PWR_DAC_L1_BIT			12
+#define RT5670_PWR_DAC_R1			(0x1 << 11)
+#define RT5670_PWR_DAC_R1_BIT			11
+#define RT5670_PWR_DAC_L2			(0x1 << 7)
+#define RT5670_PWR_DAC_L2_BIT			7
+#define RT5670_PWR_DAC_R2			(0x1 << 6)
+#define RT5670_PWR_DAC_R2_BIT			6
+#define RT5670_PWR_ADC_L			(0x1 << 2)
+#define RT5670_PWR_ADC_L_BIT			2
+#define RT5670_PWR_ADC_R			(0x1 << 1)
+#define RT5670_PWR_ADC_R_BIT			1
+#define RT5670_PWR_CLS_D			(0x1)
+#define RT5670_PWR_CLS_D_BIT			0
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5670_PWR_ADC_S1F			(0x1 << 15)
+#define RT5670_PWR_ADC_S1F_BIT			15
+#define RT5670_PWR_ADC_MF_L			(0x1 << 14)
+#define RT5670_PWR_ADC_MF_L_BIT			14
+#define RT5670_PWR_ADC_MF_R			(0x1 << 13)
+#define RT5670_PWR_ADC_MF_R_BIT			13
+#define RT5670_PWR_I2S_DSP			(0x1 << 12)
+#define RT5670_PWR_I2S_DSP_BIT			12
+#define RT5670_PWR_DAC_S1F			(0x1 << 11)
+#define RT5670_PWR_DAC_S1F_BIT			11
+#define RT5670_PWR_DAC_MF_L			(0x1 << 10)
+#define RT5670_PWR_DAC_MF_L_BIT			10
+#define RT5670_PWR_DAC_MF_R			(0x1 << 9)
+#define RT5670_PWR_DAC_MF_R_BIT			9
+#define RT5670_PWR_ADC_S2F			(0x1 << 8)
+#define RT5670_PWR_ADC_S2F_BIT			8
+#define RT5670_PWR_PDM1				(0x1 << 7)
+#define RT5670_PWR_PDM1_BIT			7
+#define RT5670_PWR_PDM2				(0x1 << 6)
+#define RT5670_PWR_PDM2_BIT			6
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5670_PWR_VREF1			(0x1 << 15)
+#define RT5670_PWR_VREF1_BIT			15
+#define RT5670_PWR_FV1				(0x1 << 14)
+#define RT5670_PWR_FV1_BIT			14
+#define RT5670_PWR_MB				(0x1 << 13)
+#define RT5670_PWR_MB_BIT			13
+#define RT5670_PWR_LM				(0x1 << 12)
+#define RT5670_PWR_LM_BIT			12
+#define RT5670_PWR_BG				(0x1 << 11)
+#define RT5670_PWR_BG_BIT			11
+#define RT5670_PWR_HP_L				(0x1 << 7)
+#define RT5670_PWR_HP_L_BIT			7
+#define RT5670_PWR_HP_R				(0x1 << 6)
+#define RT5670_PWR_HP_R_BIT			6
+#define RT5670_PWR_HA				(0x1 << 5)
+#define RT5670_PWR_HA_BIT			5
+#define RT5670_PWR_VREF2			(0x1 << 4)
+#define RT5670_PWR_VREF2_BIT			4
+#define RT5670_PWR_FV2				(0x1 << 3)
+#define RT5670_PWR_FV2_BIT			3
+#define RT5670_LDO_SEL_MASK			(0x3)
+#define RT5670_LDO_SEL_SFT			0
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5670_PWR_BST1				(0x1 << 15)
+#define RT5670_PWR_BST1_BIT			15
+#define RT5670_PWR_BST2				(0x1 << 13)
+#define RT5670_PWR_BST2_BIT			13
+#define RT5670_PWR_MB1				(0x1 << 11)
+#define RT5670_PWR_MB1_BIT			11
+#define RT5670_PWR_MB2				(0x1 << 10)
+#define RT5670_PWR_MB2_BIT			10
+#define RT5670_PWR_PLL				(0x1 << 9)
+#define RT5670_PWR_PLL_BIT			9
+#define RT5670_PWR_BST1_P			(0x1 << 6)
+#define RT5670_PWR_BST1_P_BIT			6
+#define RT5670_PWR_BST2_P			(0x1 << 4)
+#define RT5670_PWR_BST2_P_BIT			4
+#define RT5670_PWR_JD1				(0x1 << 2)
+#define RT5670_PWR_JD1_BIT			2
+#define RT5670_PWR_JD				(0x1 << 1)
+#define RT5670_PWR_JD_BIT			1
+
+/* Power Management for Mixer (0x65) */
+#define RT5670_PWR_OM_L				(0x1 << 15)
+#define RT5670_PWR_OM_L_BIT			15
+#define RT5670_PWR_OM_R				(0x1 << 14)
+#define RT5670_PWR_OM_R_BIT			14
+#define RT5670_PWR_RM_L				(0x1 << 11)
+#define RT5670_PWR_RM_L_BIT			11
+#define RT5670_PWR_RM_R				(0x1 << 10)
+#define RT5670_PWR_RM_R_BIT			10
+
+/* Power Management for Volume (0x66) */
+#define RT5670_PWR_HV_L				(0x1 << 11)
+#define RT5670_PWR_HV_L_BIT			11
+#define RT5670_PWR_HV_R				(0x1 << 10)
+#define RT5670_PWR_HV_R_BIT			10
+#define RT5670_PWR_IN_L				(0x1 << 9)
+#define RT5670_PWR_IN_L_BIT			9
+#define RT5670_PWR_IN_R				(0x1 << 8)
+#define RT5670_PWR_IN_R_BIT			8
+#define RT5670_PWR_MIC_DET			(0x1 << 5)
+#define RT5670_PWR_MIC_DET_BIT			5
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71 0x72) */
+#define RT5670_I2S_MS_MASK			(0x1 << 15)
+#define RT5670_I2S_MS_SFT			15
+#define RT5670_I2S_MS_M				(0x0 << 15)
+#define RT5670_I2S_MS_S				(0x1 << 15)
+#define RT5670_I2S_IF_MASK			(0x7 << 12)
+#define RT5670_I2S_IF_SFT			12
+#define RT5670_I2S_O_CP_MASK			(0x3 << 10)
+#define RT5670_I2S_O_CP_SFT			10
+#define RT5670_I2S_O_CP_OFF			(0x0 << 10)
+#define RT5670_I2S_O_CP_U_LAW			(0x1 << 10)
+#define RT5670_I2S_O_CP_A_LAW			(0x2 << 10)
+#define RT5670_I2S_I_CP_MASK			(0x3 << 8)
+#define RT5670_I2S_I_CP_SFT			8
+#define RT5670_I2S_I_CP_OFF			(0x0 << 8)
+#define RT5670_I2S_I_CP_U_LAW			(0x1 << 8)
+#define RT5670_I2S_I_CP_A_LAW			(0x2 << 8)
+#define RT5670_I2S_BP_MASK			(0x1 << 7)
+#define RT5670_I2S_BP_SFT			7
+#define RT5670_I2S_BP_NOR			(0x0 << 7)
+#define RT5670_I2S_BP_INV			(0x1 << 7)
+#define RT5670_I2S_DL_MASK			(0x3 << 2)
+#define RT5670_I2S_DL_SFT			2
+#define RT5670_I2S_DL_16			(0x0 << 2)
+#define RT5670_I2S_DL_20			(0x1 << 2)
+#define RT5670_I2S_DL_24			(0x2 << 2)
+#define RT5670_I2S_DL_8				(0x3 << 2)
+#define RT5670_I2S_DF_MASK			(0x3)
+#define RT5670_I2S_DF_SFT			0
+#define RT5670_I2S_DF_I2S			(0x0)
+#define RT5670_I2S_DF_LEFT			(0x1)
+#define RT5670_I2S_DF_PCM_A			(0x2)
+#define RT5670_I2S_DF_PCM_B			(0x3)
+
+/* I2S2 Audio Serial Data Port Control (0x71) */
+#define RT5670_I2S2_SDI_MASK			(0x1 << 6)
+#define RT5670_I2S2_SDI_SFT			6
+#define RT5670_I2S2_SDI_I2S1			(0x0 << 6)
+#define RT5670_I2S2_SDI_I2S2			(0x1 << 6)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5670_I2S_BCLK_MS1_MASK		(0x1 << 15)
+#define RT5670_I2S_BCLK_MS1_SFT			15
+#define RT5670_I2S_BCLK_MS1_32			(0x0 << 15)
+#define RT5670_I2S_BCLK_MS1_64			(0x1 << 15)
+#define RT5670_I2S_PD1_MASK			(0x7 << 12)
+#define RT5670_I2S_PD1_SFT			12
+#define RT5670_I2S_PD1_1			(0x0 << 12)
+#define RT5670_I2S_PD1_2			(0x1 << 12)
+#define RT5670_I2S_PD1_3			(0x2 << 12)
+#define RT5670_I2S_PD1_4			(0x3 << 12)
+#define RT5670_I2S_PD1_6			(0x4 << 12)
+#define RT5670_I2S_PD1_8			(0x5 << 12)
+#define RT5670_I2S_PD1_12			(0x6 << 12)
+#define RT5670_I2S_PD1_16			(0x7 << 12)
+#define RT5670_I2S_BCLK_MS2_MASK		(0x1 << 11)
+#define RT5670_I2S_BCLK_MS2_SFT			11
+#define RT5670_I2S_BCLK_MS2_32			(0x0 << 11)
+#define RT5670_I2S_BCLK_MS2_64			(0x1 << 11)
+#define RT5670_I2S_PD2_MASK			(0x7 << 8)
+#define RT5670_I2S_PD2_SFT			8
+#define RT5670_I2S_PD2_1			(0x0 << 8)
+#define RT5670_I2S_PD2_2			(0x1 << 8)
+#define RT5670_I2S_PD2_3			(0x2 << 8)
+#define RT5670_I2S_PD2_4			(0x3 << 8)
+#define RT5670_I2S_PD2_6			(0x4 << 8)
+#define RT5670_I2S_PD2_8			(0x5 << 8)
+#define RT5670_I2S_PD2_12			(0x6 << 8)
+#define RT5670_I2S_PD2_16			(0x7 << 8)
+#define RT5670_I2S_BCLK_MS3_MASK		(0x1 << 7)
+#define RT5670_I2S_BCLK_MS3_SFT			7
+#define RT5670_I2S_BCLK_MS3_32			(0x0 << 7)
+#define RT5670_I2S_BCLK_MS3_64			(0x1 << 7)
+#define RT5670_I2S_PD3_MASK			(0x7 << 4)
+#define RT5670_I2S_PD3_SFT			4
+#define RT5670_I2S_PD3_1			(0x0 << 4)
+#define RT5670_I2S_PD3_2			(0x1 << 4)
+#define RT5670_I2S_PD3_3			(0x2 << 4)
+#define RT5670_I2S_PD3_4			(0x3 << 4)
+#define RT5670_I2S_PD3_6			(0x4 << 4)
+#define RT5670_I2S_PD3_8			(0x5 << 4)
+#define RT5670_I2S_PD3_12			(0x6 << 4)
+#define RT5670_I2S_PD3_16			(0x7 << 4)
+#define RT5670_DAC_OSR_MASK			(0x3 << 2)
+#define RT5670_DAC_OSR_SFT			2
+#define RT5670_DAC_OSR_128			(0x0 << 2)
+#define RT5670_DAC_OSR_64			(0x1 << 2)
+#define RT5670_DAC_OSR_32			(0x2 << 2)
+#define RT5670_DAC_OSR_16			(0x3 << 2)
+#define RT5670_ADC_OSR_MASK			(0x3)
+#define RT5670_ADC_OSR_SFT			0
+#define RT5670_ADC_OSR_128			(0x0)
+#define RT5670_ADC_OSR_64			(0x1)
+#define RT5670_ADC_OSR_32			(0x2)
+#define RT5670_ADC_OSR_16			(0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5670_DAC_L_OSR_MASK			(0x3 << 14)
+#define RT5670_DAC_L_OSR_SFT			14
+#define RT5670_DAC_L_OSR_128			(0x0 << 14)
+#define RT5670_DAC_L_OSR_64			(0x1 << 14)
+#define RT5670_DAC_L_OSR_32			(0x2 << 14)
+#define RT5670_DAC_L_OSR_16			(0x3 << 14)
+#define RT5670_ADC_R_OSR_MASK			(0x3 << 12)
+#define RT5670_ADC_R_OSR_SFT			12
+#define RT5670_ADC_R_OSR_128			(0x0 << 12)
+#define RT5670_ADC_R_OSR_64			(0x1 << 12)
+#define RT5670_ADC_R_OSR_32			(0x2 << 12)
+#define RT5670_ADC_R_OSR_16			(0x3 << 12)
+#define RT5670_DAHPF_EN				(0x1 << 11)
+#define RT5670_DAHPF_EN_SFT			11
+#define RT5670_ADHPF_EN				(0x1 << 10)
+#define RT5670_ADHPF_EN_SFT			10
+
+/* Digital Microphone Control (0x75) */
+#define RT5670_DMIC_1_EN_MASK			(0x1 << 15)
+#define RT5670_DMIC_1_EN_SFT			15
+#define RT5670_DMIC_1_DIS			(0x0 << 15)
+#define RT5670_DMIC_1_EN			(0x1 << 15)
+#define RT5670_DMIC_2_EN_MASK			(0x1 << 14)
+#define RT5670_DMIC_2_EN_SFT			14
+#define RT5670_DMIC_2_DIS			(0x0 << 14)
+#define RT5670_DMIC_2_EN			(0x1 << 14)
+#define RT5670_DMIC_1L_LH_MASK			(0x1 << 13)
+#define RT5670_DMIC_1L_LH_SFT			13
+#define RT5670_DMIC_1L_LH_FALLING		(0x0 << 13)
+#define RT5670_DMIC_1L_LH_RISING		(0x1 << 13)
+#define RT5670_DMIC_1R_LH_MASK			(0x1 << 12)
+#define RT5670_DMIC_1R_LH_SFT			12
+#define RT5670_DMIC_1R_LH_FALLING		(0x0 << 12)
+#define RT5670_DMIC_1R_LH_RISING		(0x1 << 12)
+#define RT5670_DMIC_2_DP_MASK			(0x1 << 10)
+#define RT5670_DMIC_2_DP_SFT			10
+#define RT5670_DMIC_2_DP_GPIO8			(0x0 << 10)
+#define RT5670_DMIC_2_DP_IN3N			(0x1 << 10)
+#define RT5670_DMIC_2L_LH_MASK			(0x1 << 9)
+#define RT5670_DMIC_2L_LH_SFT			9
+#define RT5670_DMIC_2L_LH_FALLING		(0x0 << 9)
+#define RT5670_DMIC_2L_LH_RISING		(0x1 << 9)
+#define RT5670_DMIC_2R_LH_MASK			(0x1 << 8)
+#define RT5670_DMIC_2R_LH_SFT			8
+#define RT5670_DMIC_2R_LH_FALLING		(0x0 << 8)
+#define RT5670_DMIC_2R_LH_RISING		(0x1 << 8)
+#define RT5670_DMIC_CLK_MASK			(0x7 << 5)
+#define RT5670_DMIC_CLK_SFT			5
+#define RT5670_DMIC_3_EN_MASK			(0x1 << 4)
+#define RT5670_DMIC_3_EN_SFT			4
+#define RT5670_DMIC_3_DIS			(0x0 << 4)
+#define RT5670_DMIC_3_EN			(0x1 << 4)
+#define RT5670_DMIC_1_DP_MASK			(0x3 << 0)
+#define RT5670_DMIC_1_DP_SFT			0
+#define RT5670_DMIC_1_DP_GPIO6			(0x0 << 0)
+#define RT5670_DMIC_1_DP_IN2P			(0x1 << 0)
+#define RT5670_DMIC_1_DP_GPIO7			(0x2 << 0)
+
+/* Digital Microphone Control2 (0x76) */
+#define RT5670_DMIC_3_DP_MASK			(0x3 << 6)
+#define RT5670_DMIC_3_DP_SFT			6
+#define RT5670_DMIC_3_DP_GPIO9			(0x0 << 6)
+#define RT5670_DMIC_3_DP_GPIO10			(0x1 << 6)
+#define RT5670_DMIC_3_DP_GPIO5			(0x2 << 6)
+
+/* Global Clock Control (0x80) */
+#define RT5670_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5670_SCLK_SRC_SFT			14
+#define RT5670_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5670_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5670_SCLK_SRC_RCCLK			(0x2 << 14) /* 15MHz */
+#define RT5670_PLL1_SRC_MASK			(0x7 << 11)
+#define RT5670_PLL1_SRC_SFT			11
+#define RT5670_PLL1_SRC_MCLK			(0x0 << 11)
+#define RT5670_PLL1_SRC_BCLK1			(0x1 << 11)
+#define RT5670_PLL1_SRC_BCLK2			(0x2 << 11)
+#define RT5670_PLL1_SRC_BCLK3			(0x3 << 11)
+#define RT5670_PLL1_PD_MASK			(0x1 << 3)
+#define RT5670_PLL1_PD_SFT			3
+#define RT5670_PLL1_PD_1			(0x0 << 3)
+#define RT5670_PLL1_PD_2			(0x1 << 3)
+
+#define RT5670_PLL_INP_MAX			40000000
+#define RT5670_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5670_PLL_N_MAX			0x1ff
+#define RT5670_PLL_N_MASK			(RT5670_PLL_N_MAX << 7)
+#define RT5670_PLL_N_SFT			7
+#define RT5670_PLL_K_MAX			0x1f
+#define RT5670_PLL_K_MASK			(RT5670_PLL_K_MAX)
+#define RT5670_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5670_PLL_M_MAX			0xf
+#define RT5670_PLL_M_MASK			(RT5670_PLL_M_MAX << 12)
+#define RT5670_PLL_M_SFT			12
+#define RT5670_PLL_M_BP				(0x1 << 11)
+#define RT5670_PLL_M_BP_SFT			11
+
+/* ASRC Control 1 (0x83) */
+#define RT5670_STO_T_MASK			(0x1 << 15)
+#define RT5670_STO_T_SFT			15
+#define RT5670_STO_T_SCLK			(0x0 << 15)
+#define RT5670_STO_T_LRCK1			(0x1 << 15)
+#define RT5670_M1_T_MASK			(0x1 << 14)
+#define RT5670_M1_T_SFT				14
+#define RT5670_M1_T_I2S2			(0x0 << 14)
+#define RT5670_M1_T_I2S2_D3			(0x1 << 14)
+#define RT5670_I2S2_F_MASK			(0x1 << 12)
+#define RT5670_I2S2_F_SFT			12
+#define RT5670_I2S2_F_I2S2_D2			(0x0 << 12)
+#define RT5670_I2S2_F_I2S1_TCLK			(0x1 << 12)
+#define RT5670_DMIC_1_M_MASK			(0x1 << 9)
+#define RT5670_DMIC_1_M_SFT			9
+#define RT5670_DMIC_1_M_NOR			(0x0 << 9)
+#define RT5670_DMIC_1_M_ASYN			(0x1 << 9)
+#define RT5670_DMIC_2_M_MASK			(0x1 << 8)
+#define RT5670_DMIC_2_M_SFT			8
+#define RT5670_DMIC_2_M_NOR			(0x0 << 8)
+#define RT5670_DMIC_2_M_ASYN			(0x1 << 8)
+
+/* ASRC clock source selection (0x84, 0x85) */
+#define RT5670_CLK_SEL_SYS			(0x0)
+#define RT5670_CLK_SEL_I2S1_ASRC		(0x1)
+#define RT5670_CLK_SEL_I2S2_ASRC		(0x2)
+#define RT5670_CLK_SEL_I2S3_ASRC		(0x3)
+#define RT5670_CLK_SEL_SYS2			(0x5)
+#define RT5670_CLK_SEL_SYS3			(0x6)
+
+/* ASRC Control 2 (0x84) */
+#define RT5670_DA_STO_CLK_SEL_MASK		(0xf << 12)
+#define RT5670_DA_STO_CLK_SEL_SFT		12
+#define RT5670_DA_MONOL_CLK_SEL_MASK		(0xf << 8)
+#define RT5670_DA_MONOL_CLK_SEL_SFT		8
+#define RT5670_DA_MONOR_CLK_SEL_MASK		(0xf << 4)
+#define RT5670_DA_MONOR_CLK_SEL_SFT		4
+#define RT5670_AD_STO1_CLK_SEL_MASK		(0xf << 0)
+#define RT5670_AD_STO1_CLK_SEL_SFT		0
+
+/* ASRC Control 3 (0x85) */
+#define RT5670_UP_CLK_SEL_MASK			(0xf << 12)
+#define RT5670_UP_CLK_SEL_SFT			12
+#define RT5670_DOWN_CLK_SEL_MASK		(0xf << 8)
+#define RT5670_DOWN_CLK_SEL_SFT			8
+#define RT5670_AD_MONOL_CLK_SEL_MASK		(0xf << 4)
+#define RT5670_AD_MONOL_CLK_SEL_SFT		4
+#define RT5670_AD_MONOR_CLK_SEL_MASK		(0xf << 0)
+#define RT5670_AD_MONOR_CLK_SEL_SFT		0
+
+/* ASRC Control 4 (0x89) */
+#define RT5670_I2S1_PD_MASK			(0x7 << 12)
+#define RT5670_I2S1_PD_SFT			12
+#define RT5670_I2S2_PD_MASK			(0x7 << 8)
+#define RT5670_I2S2_PD_SFT			8
+
+/* HPOUT Over Current Detection (0x8b) */
+#define RT5670_HP_OVCD_MASK			(0x1 << 10)
+#define RT5670_HP_OVCD_SFT			10
+#define RT5670_HP_OVCD_DIS			(0x0 << 10)
+#define RT5670_HP_OVCD_EN			(0x1 << 10)
+#define RT5670_HP_OC_TH_MASK			(0x3 << 8)
+#define RT5670_HP_OC_TH_SFT			8
+#define RT5670_HP_OC_TH_90			(0x0 << 8)
+#define RT5670_HP_OC_TH_105			(0x1 << 8)
+#define RT5670_HP_OC_TH_120			(0x2 << 8)
+#define RT5670_HP_OC_TH_135			(0x3 << 8)
+
+/* Class D Over Current Control (0x8c) */
+#define RT5670_CLSD_OC_MASK			(0x1 << 9)
+#define RT5670_CLSD_OC_SFT			9
+#define RT5670_CLSD_OC_PU			(0x0 << 9)
+#define RT5670_CLSD_OC_PD			(0x1 << 9)
+#define RT5670_AUTO_PD_MASK			(0x1 << 8)
+#define RT5670_AUTO_PD_SFT			8
+#define RT5670_AUTO_PD_DIS			(0x0 << 8)
+#define RT5670_AUTO_PD_EN			(0x1 << 8)
+#define RT5670_CLSD_OC_TH_MASK			(0x3f)
+#define RT5670_CLSD_OC_TH_SFT			0
+
+/* Class D Output Control (0x8d) */
+#define RT5670_CLSD_RATIO_MASK			(0xf << 12)
+#define RT5670_CLSD_RATIO_SFT			12
+#define RT5670_CLSD_OM_MASK			(0x1 << 11)
+#define RT5670_CLSD_OM_SFT			11
+#define RT5670_CLSD_OM_MONO			(0x0 << 11)
+#define RT5670_CLSD_OM_STO			(0x1 << 11)
+#define RT5670_CLSD_SCH_MASK			(0x1 << 10)
+#define RT5670_CLSD_SCH_SFT			10
+#define RT5670_CLSD_SCH_L			(0x0 << 10)
+#define RT5670_CLSD_SCH_S			(0x1 << 10)
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5670_SMT_TRIG_MASK			(0x1 << 15)
+#define RT5670_SMT_TRIG_SFT			15
+#define RT5670_SMT_TRIG_DIS			(0x0 << 15)
+#define RT5670_SMT_TRIG_EN			(0x1 << 15)
+#define RT5670_HP_L_SMT_MASK			(0x1 << 9)
+#define RT5670_HP_L_SMT_SFT			9
+#define RT5670_HP_L_SMT_DIS			(0x0 << 9)
+#define RT5670_HP_L_SMT_EN			(0x1 << 9)
+#define RT5670_HP_R_SMT_MASK			(0x1 << 8)
+#define RT5670_HP_R_SMT_SFT			8
+#define RT5670_HP_R_SMT_DIS			(0x0 << 8)
+#define RT5670_HP_R_SMT_EN			(0x1 << 8)
+#define RT5670_HP_CD_PD_MASK			(0x1 << 7)
+#define RT5670_HP_CD_PD_SFT			7
+#define RT5670_HP_CD_PD_DIS			(0x0 << 7)
+#define RT5670_HP_CD_PD_EN			(0x1 << 7)
+#define RT5670_RSTN_MASK			(0x1 << 6)
+#define RT5670_RSTN_SFT				6
+#define RT5670_RSTN_DIS				(0x0 << 6)
+#define RT5670_RSTN_EN				(0x1 << 6)
+#define RT5670_RSTP_MASK			(0x1 << 5)
+#define RT5670_RSTP_SFT				5
+#define RT5670_RSTP_DIS				(0x0 << 5)
+#define RT5670_RSTP_EN				(0x1 << 5)
+#define RT5670_HP_CO_MASK			(0x1 << 4)
+#define RT5670_HP_CO_SFT			4
+#define RT5670_HP_CO_DIS			(0x0 << 4)
+#define RT5670_HP_CO_EN				(0x1 << 4)
+#define RT5670_HP_CP_MASK			(0x1 << 3)
+#define RT5670_HP_CP_SFT			3
+#define RT5670_HP_CP_PD				(0x0 << 3)
+#define RT5670_HP_CP_PU				(0x1 << 3)
+#define RT5670_HP_SG_MASK			(0x1 << 2)
+#define RT5670_HP_SG_SFT			2
+#define RT5670_HP_SG_DIS			(0x0 << 2)
+#define RT5670_HP_SG_EN				(0x1 << 2)
+#define RT5670_HP_DP_MASK			(0x1 << 1)
+#define RT5670_HP_DP_SFT			1
+#define RT5670_HP_DP_PD				(0x0 << 1)
+#define RT5670_HP_DP_PU				(0x1 << 1)
+#define RT5670_HP_CB_MASK			(0x1)
+#define RT5670_HP_CB_SFT			0
+#define RT5670_HP_CB_PD				(0x0)
+#define RT5670_HP_CB_PU				(0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5670_DEPOP_MASK			(0x1 << 13)
+#define RT5670_DEPOP_SFT			13
+#define RT5670_DEPOP_AUTO			(0x0 << 13)
+#define RT5670_DEPOP_MAN			(0x1 << 13)
+#define RT5670_RAMP_MASK			(0x1 << 12)
+#define RT5670_RAMP_SFT				12
+#define RT5670_RAMP_DIS				(0x0 << 12)
+#define RT5670_RAMP_EN				(0x1 << 12)
+#define RT5670_BPS_MASK				(0x1 << 11)
+#define RT5670_BPS_SFT				11
+#define RT5670_BPS_DIS				(0x0 << 11)
+#define RT5670_BPS_EN				(0x1 << 11)
+#define RT5670_FAST_UPDN_MASK			(0x1 << 10)
+#define RT5670_FAST_UPDN_SFT			10
+#define RT5670_FAST_UPDN_DIS			(0x0 << 10)
+#define RT5670_FAST_UPDN_EN			(0x1 << 10)
+#define RT5670_MRES_MASK			(0x3 << 8)
+#define RT5670_MRES_SFT				8
+#define RT5670_MRES_15MO			(0x0 << 8)
+#define RT5670_MRES_25MO			(0x1 << 8)
+#define RT5670_MRES_35MO			(0x2 << 8)
+#define RT5670_MRES_45MO			(0x3 << 8)
+#define RT5670_VLO_MASK				(0x1 << 7)
+#define RT5670_VLO_SFT				7
+#define RT5670_VLO_3V				(0x0 << 7)
+#define RT5670_VLO_32V				(0x1 << 7)
+#define RT5670_DIG_DP_MASK			(0x1 << 6)
+#define RT5670_DIG_DP_SFT			6
+#define RT5670_DIG_DP_DIS			(0x0 << 6)
+#define RT5670_DIG_DP_EN			(0x1 << 6)
+#define RT5670_DP_TH_MASK			(0x3 << 4)
+#define RT5670_DP_TH_SFT			4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5670_CP_SYS_MASK			(0x7 << 12)
+#define RT5670_CP_SYS_SFT			12
+#define RT5670_CP_FQ1_MASK			(0x7 << 8)
+#define RT5670_CP_FQ1_SFT			8
+#define RT5670_CP_FQ2_MASK			(0x7 << 4)
+#define RT5670_CP_FQ2_SFT			4
+#define RT5670_CP_FQ3_MASK			(0x7)
+#define RT5670_CP_FQ3_SFT			0
+#define RT5670_CP_FQ_1_5_KHZ			0
+#define RT5670_CP_FQ_3_KHZ			1
+#define RT5670_CP_FQ_6_KHZ			2
+#define RT5670_CP_FQ_12_KHZ			3
+#define RT5670_CP_FQ_24_KHZ			4
+#define RT5670_CP_FQ_48_KHZ			5
+#define RT5670_CP_FQ_96_KHZ			6
+#define RT5670_CP_FQ_192_KHZ			7
+
+/* HPOUT charge pump (0x91) */
+#define RT5670_OSW_L_MASK			(0x1 << 11)
+#define RT5670_OSW_L_SFT			11
+#define RT5670_OSW_L_DIS			(0x0 << 11)
+#define RT5670_OSW_L_EN				(0x1 << 11)
+#define RT5670_OSW_R_MASK			(0x1 << 10)
+#define RT5670_OSW_R_SFT			10
+#define RT5670_OSW_R_DIS			(0x0 << 10)
+#define RT5670_OSW_R_EN				(0x1 << 10)
+#define RT5670_PM_HP_MASK			(0x3 << 8)
+#define RT5670_PM_HP_SFT			8
+#define RT5670_PM_HP_LV				(0x0 << 8)
+#define RT5670_PM_HP_MV				(0x1 << 8)
+#define RT5670_PM_HP_HV				(0x2 << 8)
+#define RT5670_IB_HP_MASK			(0x3 << 6)
+#define RT5670_IB_HP_SFT			6
+#define RT5670_IB_HP_125IL			(0x0 << 6)
+#define RT5670_IB_HP_25IL			(0x1 << 6)
+#define RT5670_IB_HP_5IL			(0x2 << 6)
+#define RT5670_IB_HP_1IL			(0x3 << 6)
+
+/* PV detection and SPK gain control (0x92) */
+#define RT5670_PVDD_DET_MASK			(0x1 << 15)
+#define RT5670_PVDD_DET_SFT			15
+#define RT5670_PVDD_DET_DIS			(0x0 << 15)
+#define RT5670_PVDD_DET_EN			(0x1 << 15)
+#define RT5670_SPK_AG_MASK			(0x1 << 14)
+#define RT5670_SPK_AG_SFT			14
+#define RT5670_SPK_AG_DIS			(0x0 << 14)
+#define RT5670_SPK_AG_EN			(0x1 << 14)
+
+/* Micbias Control (0x93) */
+#define RT5670_MIC1_BS_MASK			(0x1 << 15)
+#define RT5670_MIC1_BS_SFT			15
+#define RT5670_MIC1_BS_9AV			(0x0 << 15)
+#define RT5670_MIC1_BS_75AV			(0x1 << 15)
+#define RT5670_MIC2_BS_MASK			(0x1 << 14)
+#define RT5670_MIC2_BS_SFT			14
+#define RT5670_MIC2_BS_9AV			(0x0 << 14)
+#define RT5670_MIC2_BS_75AV			(0x1 << 14)
+#define RT5670_MIC1_CLK_MASK			(0x1 << 13)
+#define RT5670_MIC1_CLK_SFT			13
+#define RT5670_MIC1_CLK_DIS			(0x0 << 13)
+#define RT5670_MIC1_CLK_EN			(0x1 << 13)
+#define RT5670_MIC2_CLK_MASK			(0x1 << 12)
+#define RT5670_MIC2_CLK_SFT			12
+#define RT5670_MIC2_CLK_DIS			(0x0 << 12)
+#define RT5670_MIC2_CLK_EN			(0x1 << 12)
+#define RT5670_MIC1_OVCD_MASK			(0x1 << 11)
+#define RT5670_MIC1_OVCD_SFT			11
+#define RT5670_MIC1_OVCD_DIS			(0x0 << 11)
+#define RT5670_MIC1_OVCD_EN			(0x1 << 11)
+#define RT5670_MIC1_OVTH_MASK			(0x3 << 9)
+#define RT5670_MIC1_OVTH_SFT			9
+#define RT5670_MIC1_OVTH_600UA			(0x0 << 9)
+#define RT5670_MIC1_OVTH_1500UA			(0x1 << 9)
+#define RT5670_MIC1_OVTH_2000UA			(0x2 << 9)
+#define RT5670_MIC2_OVCD_MASK			(0x1 << 8)
+#define RT5670_MIC2_OVCD_SFT			8
+#define RT5670_MIC2_OVCD_DIS			(0x0 << 8)
+#define RT5670_MIC2_OVCD_EN			(0x1 << 8)
+#define RT5670_MIC2_OVTH_MASK			(0x3 << 6)
+#define RT5670_MIC2_OVTH_SFT			6
+#define RT5670_MIC2_OVTH_600UA			(0x0 << 6)
+#define RT5670_MIC2_OVTH_1500UA			(0x1 << 6)
+#define RT5670_MIC2_OVTH_2000UA			(0x2 << 6)
+#define RT5670_PWR_MB_MASK			(0x1 << 5)
+#define RT5670_PWR_MB_SFT			5
+#define RT5670_PWR_MB_PD			(0x0 << 5)
+#define RT5670_PWR_MB_PU			(0x1 << 5)
+#define RT5670_PWR_CLK25M_MASK			(0x1 << 4)
+#define RT5670_PWR_CLK25M_SFT			4
+#define RT5670_PWR_CLK25M_PD			(0x0 << 4)
+#define RT5670_PWR_CLK25M_PU			(0x1 << 4)
+
+/* Analog JD Control 1 (0x94) */
+#define RT5670_JD1_MODE_MASK			(0x3 << 0)
+#define RT5670_JD1_MODE_0			(0x0 << 0)
+#define RT5670_JD1_MODE_1			(0x1 << 0)
+#define RT5670_JD1_MODE_2			(0x2 << 0)
+
+/* VAD Control 4 (0x9d) */
+#define RT5670_VAD_SEL_MASK			(0x3 << 8)
+#define RT5670_VAD_SEL_SFT			8
+
+/* EQ Control 1 (0xb0) */
+#define RT5670_EQ_SRC_MASK			(0x1 << 15)
+#define RT5670_EQ_SRC_SFT			15
+#define RT5670_EQ_SRC_DAC			(0x0 << 15)
+#define RT5670_EQ_SRC_ADC			(0x1 << 15)
+#define RT5670_EQ_UPD				(0x1 << 14)
+#define RT5670_EQ_UPD_BIT			14
+#define RT5670_EQ_CD_MASK			(0x1 << 13)
+#define RT5670_EQ_CD_SFT			13
+#define RT5670_EQ_CD_DIS			(0x0 << 13)
+#define RT5670_EQ_CD_EN				(0x1 << 13)
+#define RT5670_EQ_DITH_MASK			(0x3 << 8)
+#define RT5670_EQ_DITH_SFT			8
+#define RT5670_EQ_DITH_NOR			(0x0 << 8)
+#define RT5670_EQ_DITH_LSB			(0x1 << 8)
+#define RT5670_EQ_DITH_LSB_1			(0x2 << 8)
+#define RT5670_EQ_DITH_LSB_2			(0x3 << 8)
+
+/* EQ Control 2 (0xb1) */
+#define RT5670_EQ_HPF1_M_MASK			(0x1 << 8)
+#define RT5670_EQ_HPF1_M_SFT			8
+#define RT5670_EQ_HPF1_M_HI			(0x0 << 8)
+#define RT5670_EQ_HPF1_M_1ST			(0x1 << 8)
+#define RT5670_EQ_LPF1_M_MASK			(0x1 << 7)
+#define RT5670_EQ_LPF1_M_SFT			7
+#define RT5670_EQ_LPF1_M_LO			(0x0 << 7)
+#define RT5670_EQ_LPF1_M_1ST			(0x1 << 7)
+#define RT5670_EQ_HPF2_MASK			(0x1 << 6)
+#define RT5670_EQ_HPF2_SFT			6
+#define RT5670_EQ_HPF2_DIS			(0x0 << 6)
+#define RT5670_EQ_HPF2_EN			(0x1 << 6)
+#define RT5670_EQ_HPF1_MASK			(0x1 << 5)
+#define RT5670_EQ_HPF1_SFT			5
+#define RT5670_EQ_HPF1_DIS			(0x0 << 5)
+#define RT5670_EQ_HPF1_EN			(0x1 << 5)
+#define RT5670_EQ_BPF4_MASK			(0x1 << 4)
+#define RT5670_EQ_BPF4_SFT			4
+#define RT5670_EQ_BPF4_DIS			(0x0 << 4)
+#define RT5670_EQ_BPF4_EN			(0x1 << 4)
+#define RT5670_EQ_BPF3_MASK			(0x1 << 3)
+#define RT5670_EQ_BPF3_SFT			3
+#define RT5670_EQ_BPF3_DIS			(0x0 << 3)
+#define RT5670_EQ_BPF3_EN			(0x1 << 3)
+#define RT5670_EQ_BPF2_MASK			(0x1 << 2)
+#define RT5670_EQ_BPF2_SFT			2
+#define RT5670_EQ_BPF2_DIS			(0x0 << 2)
+#define RT5670_EQ_BPF2_EN			(0x1 << 2)
+#define RT5670_EQ_BPF1_MASK			(0x1 << 1)
+#define RT5670_EQ_BPF1_SFT			1
+#define RT5670_EQ_BPF1_DIS			(0x0 << 1)
+#define RT5670_EQ_BPF1_EN			(0x1 << 1)
+#define RT5670_EQ_LPF_MASK			(0x1)
+#define RT5670_EQ_LPF_SFT			0
+#define RT5670_EQ_LPF_DIS			(0x0)
+#define RT5670_EQ_LPF_EN			(0x1)
+#define RT5670_EQ_CTRL_MASK			(0x7f)
+
+/* Memory Test (0xb2) */
+#define RT5670_MT_MASK				(0x1 << 15)
+#define RT5670_MT_SFT				15
+#define RT5670_MT_DIS				(0x0 << 15)
+#define RT5670_MT_EN				(0x1 << 15)
+
+/* DRC/AGC Control 1 (0xb4) */
+#define RT5670_DRC_AGC_P_MASK			(0x1 << 15)
+#define RT5670_DRC_AGC_P_SFT			15
+#define RT5670_DRC_AGC_P_DAC			(0x0 << 15)
+#define RT5670_DRC_AGC_P_ADC			(0x1 << 15)
+#define RT5670_DRC_AGC_MASK			(0x1 << 14)
+#define RT5670_DRC_AGC_SFT			14
+#define RT5670_DRC_AGC_DIS			(0x0 << 14)
+#define RT5670_DRC_AGC_EN			(0x1 << 14)
+#define RT5670_DRC_AGC_UPD			(0x1 << 13)
+#define RT5670_DRC_AGC_UPD_BIT			13
+#define RT5670_DRC_AGC_AR_MASK			(0x1f << 8)
+#define RT5670_DRC_AGC_AR_SFT			8
+#define RT5670_DRC_AGC_R_MASK			(0x7 << 5)
+#define RT5670_DRC_AGC_R_SFT			5
+#define RT5670_DRC_AGC_R_48K			(0x1 << 5)
+#define RT5670_DRC_AGC_R_96K			(0x2 << 5)
+#define RT5670_DRC_AGC_R_192K			(0x3 << 5)
+#define RT5670_DRC_AGC_R_441K			(0x5 << 5)
+#define RT5670_DRC_AGC_R_882K			(0x6 << 5)
+#define RT5670_DRC_AGC_R_1764K			(0x7 << 5)
+#define RT5670_DRC_AGC_RC_MASK			(0x1f)
+#define RT5670_DRC_AGC_RC_SFT			0
+
+/* DRC/AGC Control 2 (0xb5) */
+#define RT5670_DRC_AGC_POB_MASK			(0x3f << 8)
+#define RT5670_DRC_AGC_POB_SFT			8
+#define RT5670_DRC_AGC_CP_MASK			(0x1 << 7)
+#define RT5670_DRC_AGC_CP_SFT			7
+#define RT5670_DRC_AGC_CP_DIS			(0x0 << 7)
+#define RT5670_DRC_AGC_CP_EN			(0x1 << 7)
+#define RT5670_DRC_AGC_CPR_MASK			(0x3 << 5)
+#define RT5670_DRC_AGC_CPR_SFT			5
+#define RT5670_DRC_AGC_CPR_1_1			(0x0 << 5)
+#define RT5670_DRC_AGC_CPR_1_2			(0x1 << 5)
+#define RT5670_DRC_AGC_CPR_1_3			(0x2 << 5)
+#define RT5670_DRC_AGC_CPR_1_4			(0x3 << 5)
+#define RT5670_DRC_AGC_PRB_MASK			(0x1f)
+#define RT5670_DRC_AGC_PRB_SFT			0
+
+/* DRC/AGC Control 3 (0xb6) */
+#define RT5670_DRC_AGC_NGB_MASK			(0xf << 12)
+#define RT5670_DRC_AGC_NGB_SFT			12
+#define RT5670_DRC_AGC_TAR_MASK			(0x1f << 7)
+#define RT5670_DRC_AGC_TAR_SFT			7
+#define RT5670_DRC_AGC_NG_MASK			(0x1 << 6)
+#define RT5670_DRC_AGC_NG_SFT			6
+#define RT5670_DRC_AGC_NG_DIS			(0x0 << 6)
+#define RT5670_DRC_AGC_NG_EN			(0x1 << 6)
+#define RT5670_DRC_AGC_NGH_MASK			(0x1 << 5)
+#define RT5670_DRC_AGC_NGH_SFT			5
+#define RT5670_DRC_AGC_NGH_DIS			(0x0 << 5)
+#define RT5670_DRC_AGC_NGH_EN			(0x1 << 5)
+#define RT5670_DRC_AGC_NGT_MASK			(0x1f)
+#define RT5670_DRC_AGC_NGT_SFT			0
+
+/* Jack Detect Control (0xbb) */
+#define RT5670_JD_MASK				(0x7 << 13)
+#define RT5670_JD_SFT				13
+#define RT5670_JD_DIS				(0x0 << 13)
+#define RT5670_JD_GPIO1				(0x1 << 13)
+#define RT5670_JD_JD1_IN4P			(0x2 << 13)
+#define RT5670_JD_JD2_IN4N			(0x3 << 13)
+#define RT5670_JD_GPIO2				(0x4 << 13)
+#define RT5670_JD_GPIO3				(0x5 << 13)
+#define RT5670_JD_GPIO4				(0x6 << 13)
+#define RT5670_JD_HP_MASK			(0x1 << 11)
+#define RT5670_JD_HP_SFT			11
+#define RT5670_JD_HP_DIS			(0x0 << 11)
+#define RT5670_JD_HP_EN				(0x1 << 11)
+#define RT5670_JD_HP_TRG_MASK			(0x1 << 10)
+#define RT5670_JD_HP_TRG_SFT			10
+#define RT5670_JD_HP_TRG_LO			(0x0 << 10)
+#define RT5670_JD_HP_TRG_HI			(0x1 << 10)
+#define RT5670_JD_SPL_MASK			(0x1 << 9)
+#define RT5670_JD_SPL_SFT			9
+#define RT5670_JD_SPL_DIS			(0x0 << 9)
+#define RT5670_JD_SPL_EN			(0x1 << 9)
+#define RT5670_JD_SPL_TRG_MASK			(0x1 << 8)
+#define RT5670_JD_SPL_TRG_SFT			8
+#define RT5670_JD_SPL_TRG_LO			(0x0 << 8)
+#define RT5670_JD_SPL_TRG_HI			(0x1 << 8)
+#define RT5670_JD_SPR_MASK			(0x1 << 7)
+#define RT5670_JD_SPR_SFT			7
+#define RT5670_JD_SPR_DIS			(0x0 << 7)
+#define RT5670_JD_SPR_EN			(0x1 << 7)
+#define RT5670_JD_SPR_TRG_MASK			(0x1 << 6)
+#define RT5670_JD_SPR_TRG_SFT			6
+#define RT5670_JD_SPR_TRG_LO			(0x0 << 6)
+#define RT5670_JD_SPR_TRG_HI			(0x1 << 6)
+#define RT5670_JD_MO_MASK			(0x1 << 5)
+#define RT5670_JD_MO_SFT			5
+#define RT5670_JD_MO_DIS			(0x0 << 5)
+#define RT5670_JD_MO_EN				(0x1 << 5)
+#define RT5670_JD_MO_TRG_MASK			(0x1 << 4)
+#define RT5670_JD_MO_TRG_SFT			4
+#define RT5670_JD_MO_TRG_LO			(0x0 << 4)
+#define RT5670_JD_MO_TRG_HI			(0x1 << 4)
+#define RT5670_JD_LO_MASK			(0x1 << 3)
+#define RT5670_JD_LO_SFT			3
+#define RT5670_JD_LO_DIS			(0x0 << 3)
+#define RT5670_JD_LO_EN				(0x1 << 3)
+#define RT5670_JD_LO_TRG_MASK			(0x1 << 2)
+#define RT5670_JD_LO_TRG_SFT			2
+#define RT5670_JD_LO_TRG_LO			(0x0 << 2)
+#define RT5670_JD_LO_TRG_HI			(0x1 << 2)
+#define RT5670_JD1_IN4P_MASK			(0x1 << 1)
+#define RT5670_JD1_IN4P_SFT			1
+#define RT5670_JD1_IN4P_DIS			(0x0 << 1)
+#define RT5670_JD1_IN4P_EN			(0x1 << 1)
+#define RT5670_JD2_IN4N_MASK			(0x1)
+#define RT5670_JD2_IN4N_SFT			0
+#define RT5670_JD2_IN4N_DIS			(0x0)
+#define RT5670_JD2_IN4N_EN			(0x1)
+
+/* IRQ Control 1 (0xbd) */
+#define RT5670_IRQ_JD_MASK			(0x1 << 15)
+#define RT5670_IRQ_JD_SFT			15
+#define RT5670_IRQ_JD_BP			(0x0 << 15)
+#define RT5670_IRQ_JD_NOR			(0x1 << 15)
+#define RT5670_IRQ_OT_MASK			(0x1 << 14)
+#define RT5670_IRQ_OT_SFT			14
+#define RT5670_IRQ_OT_BP			(0x0 << 14)
+#define RT5670_IRQ_OT_NOR			(0x1 << 14)
+#define RT5670_JD_STKY_MASK			(0x1 << 13)
+#define RT5670_JD_STKY_SFT			13
+#define RT5670_JD_STKY_DIS			(0x0 << 13)
+#define RT5670_JD_STKY_EN			(0x1 << 13)
+#define RT5670_OT_STKY_MASK			(0x1 << 12)
+#define RT5670_OT_STKY_SFT			12
+#define RT5670_OT_STKY_DIS			(0x0 << 12)
+#define RT5670_OT_STKY_EN			(0x1 << 12)
+#define RT5670_JD_P_MASK			(0x1 << 11)
+#define RT5670_JD_P_SFT				11
+#define RT5670_JD_P_NOR				(0x0 << 11)
+#define RT5670_JD_P_INV				(0x1 << 11)
+#define RT5670_OT_P_MASK			(0x1 << 10)
+#define RT5670_OT_P_SFT				10
+#define RT5670_OT_P_NOR				(0x0 << 10)
+#define RT5670_OT_P_INV				(0x1 << 10)
+#define RT5670_JD1_1_EN_MASK			(0x1 << 9)
+#define RT5670_JD1_1_EN_SFT			9
+#define RT5670_JD1_1_DIS			(0x0 << 9)
+#define RT5670_JD1_1_EN				(0x1 << 9)
+
+/* IRQ Control 2 (0xbe) */
+#define RT5670_IRQ_MB1_OC_MASK			(0x1 << 15)
+#define RT5670_IRQ_MB1_OC_SFT			15
+#define RT5670_IRQ_MB1_OC_BP			(0x0 << 15)
+#define RT5670_IRQ_MB1_OC_NOR			(0x1 << 15)
+#define RT5670_IRQ_MB2_OC_MASK			(0x1 << 14)
+#define RT5670_IRQ_MB2_OC_SFT			14
+#define RT5670_IRQ_MB2_OC_BP			(0x0 << 14)
+#define RT5670_IRQ_MB2_OC_NOR			(0x1 << 14)
+#define RT5670_MB1_OC_STKY_MASK			(0x1 << 11)
+#define RT5670_MB1_OC_STKY_SFT			11
+#define RT5670_MB1_OC_STKY_DIS			(0x0 << 11)
+#define RT5670_MB1_OC_STKY_EN			(0x1 << 11)
+#define RT5670_MB2_OC_STKY_MASK			(0x1 << 10)
+#define RT5670_MB2_OC_STKY_SFT			10
+#define RT5670_MB2_OC_STKY_DIS			(0x0 << 10)
+#define RT5670_MB2_OC_STKY_EN			(0x1 << 10)
+#define RT5670_MB1_OC_P_MASK			(0x1 << 7)
+#define RT5670_MB1_OC_P_SFT			7
+#define RT5670_MB1_OC_P_NOR			(0x0 << 7)
+#define RT5670_MB1_OC_P_INV			(0x1 << 7)
+#define RT5670_MB2_OC_P_MASK			(0x1 << 6)
+#define RT5670_MB2_OC_P_SFT			6
+#define RT5670_MB2_OC_P_NOR			(0x0 << 6)
+#define RT5670_MB2_OC_P_INV			(0x1 << 6)
+#define RT5670_MB1_OC_CLR			(0x1 << 3)
+#define RT5670_MB1_OC_CLR_SFT			3
+#define RT5670_MB2_OC_CLR			(0x1 << 2)
+#define RT5670_MB2_OC_CLR_SFT			2
+
+/* GPIO Control 1 (0xc0) */
+#define RT5670_GP1_PIN_MASK			(0x1 << 15)
+#define RT5670_GP1_PIN_SFT			15
+#define RT5670_GP1_PIN_GPIO1			(0x0 << 15)
+#define RT5670_GP1_PIN_IRQ			(0x1 << 15)
+#define RT5670_GP2_PIN_MASK			(0x1 << 14)
+#define RT5670_GP2_PIN_SFT			14
+#define RT5670_GP2_PIN_GPIO2			(0x0 << 14)
+#define RT5670_GP2_PIN_DMIC1_SCL		(0x1 << 14)
+#define RT5670_GP3_PIN_MASK			(0x3 << 12)
+#define RT5670_GP3_PIN_SFT			12
+#define RT5670_GP3_PIN_GPIO3			(0x0 << 12)
+#define RT5670_GP3_PIN_DMIC1_SDA		(0x1 << 12)
+#define RT5670_GP3_PIN_IRQ			(0x2 << 12)
+#define RT5670_GP4_PIN_MASK			(0x1 << 11)
+#define RT5670_GP4_PIN_SFT			11
+#define RT5670_GP4_PIN_GPIO4			(0x0 << 11)
+#define RT5670_GP4_PIN_DMIC2_SDA		(0x1 << 11)
+#define RT5670_DP_SIG_MASK			(0x1 << 10)
+#define RT5670_DP_SIG_SFT			10
+#define RT5670_DP_SIG_TEST			(0x0 << 10)
+#define RT5670_DP_SIG_AP			(0x1 << 10)
+#define RT5670_GPIO_M_MASK			(0x1 << 9)
+#define RT5670_GPIO_M_SFT			9
+#define RT5670_GPIO_M_FLT			(0x0 << 9)
+#define RT5670_GPIO_M_PH			(0x1 << 9)
+#define RT5670_I2S2_PIN_MASK			(0x1 << 8)
+#define RT5670_I2S2_PIN_SFT			8
+#define RT5670_I2S2_PIN_I2S			(0x0 << 8)
+#define RT5670_I2S2_PIN_GPIO			(0x1 << 8)
+#define RT5670_GP5_PIN_MASK			(0x1 << 7)
+#define RT5670_GP5_PIN_SFT			7
+#define RT5670_GP5_PIN_GPIO5			(0x0 << 7)
+#define RT5670_GP5_PIN_DMIC3_SDA		(0x1 << 7)
+#define RT5670_GP6_PIN_MASK			(0x1 << 6)
+#define RT5670_GP6_PIN_SFT			6
+#define RT5670_GP6_PIN_GPIO6			(0x0 << 6)
+#define RT5670_GP6_PIN_DMIC1_SDA		(0x1 << 6)
+#define RT5670_GP7_PIN_MASK			(0x3 << 4)
+#define RT5670_GP7_PIN_SFT			4
+#define RT5670_GP7_PIN_GPIO7			(0x0 << 4)
+#define RT5670_GP7_PIN_DMIC1_SDA		(0x1 << 4)
+#define RT5670_GP7_PIN_PDM_SCL2			(0x2 << 4)
+#define RT5670_GP8_PIN_MASK			(0x1 << 3)
+#define RT5670_GP8_PIN_SFT			3
+#define RT5670_GP8_PIN_GPIO8			(0x0 << 3)
+#define RT5670_GP8_PIN_DMIC2_SDA		(0x1 << 3)
+#define RT5670_GP9_PIN_MASK			(0x1 << 2)
+#define RT5670_GP9_PIN_SFT			2
+#define RT5670_GP9_PIN_GPIO9			(0x0 << 2)
+#define RT5670_GP9_PIN_DMIC3_SDA		(0x1 << 2)
+#define RT5670_GP10_PIN_MASK			(0x3)
+#define RT5670_GP10_PIN_SFT			0
+#define RT5670_GP10_PIN_GPIO9			(0x0)
+#define RT5670_GP10_PIN_DMIC3_SDA		(0x1)
+#define RT5670_GP10_PIN_PDM_ADT2		(0x2)
+
+/* GPIO Control 2 (0xc1) */
+#define RT5670_GP4_PF_MASK			(0x1 << 11)
+#define RT5670_GP4_PF_SFT			11
+#define RT5670_GP4_PF_IN			(0x0 << 11)
+#define RT5670_GP4_PF_OUT			(0x1 << 11)
+#define RT5670_GP4_OUT_MASK			(0x1 << 10)
+#define RT5670_GP4_OUT_SFT			10
+#define RT5670_GP4_OUT_LO			(0x0 << 10)
+#define RT5670_GP4_OUT_HI			(0x1 << 10)
+#define RT5670_GP4_P_MASK			(0x1 << 9)
+#define RT5670_GP4_P_SFT			9
+#define RT5670_GP4_P_NOR			(0x0 << 9)
+#define RT5670_GP4_P_INV			(0x1 << 9)
+#define RT5670_GP3_PF_MASK			(0x1 << 8)
+#define RT5670_GP3_PF_SFT			8
+#define RT5670_GP3_PF_IN			(0x0 << 8)
+#define RT5670_GP3_PF_OUT			(0x1 << 8)
+#define RT5670_GP3_OUT_MASK			(0x1 << 7)
+#define RT5670_GP3_OUT_SFT			7
+#define RT5670_GP3_OUT_LO			(0x0 << 7)
+#define RT5670_GP3_OUT_HI			(0x1 << 7)
+#define RT5670_GP3_P_MASK			(0x1 << 6)
+#define RT5670_GP3_P_SFT			6
+#define RT5670_GP3_P_NOR			(0x0 << 6)
+#define RT5670_GP3_P_INV			(0x1 << 6)
+#define RT5670_GP2_PF_MASK			(0x1 << 5)
+#define RT5670_GP2_PF_SFT			5
+#define RT5670_GP2_PF_IN			(0x0 << 5)
+#define RT5670_GP2_PF_OUT			(0x1 << 5)
+#define RT5670_GP2_OUT_MASK			(0x1 << 4)
+#define RT5670_GP2_OUT_SFT			4
+#define RT5670_GP2_OUT_LO			(0x0 << 4)
+#define RT5670_GP2_OUT_HI			(0x1 << 4)
+#define RT5670_GP2_P_MASK			(0x1 << 3)
+#define RT5670_GP2_P_SFT			3
+#define RT5670_GP2_P_NOR			(0x0 << 3)
+#define RT5670_GP2_P_INV			(0x1 << 3)
+#define RT5670_GP1_PF_MASK			(0x1 << 2)
+#define RT5670_GP1_PF_SFT			2
+#define RT5670_GP1_PF_IN			(0x0 << 2)
+#define RT5670_GP1_PF_OUT			(0x1 << 2)
+#define RT5670_GP1_OUT_MASK			(0x1 << 1)
+#define RT5670_GP1_OUT_SFT			1
+#define RT5670_GP1_OUT_LO			(0x0 << 1)
+#define RT5670_GP1_OUT_HI			(0x1 << 1)
+#define RT5670_GP1_P_MASK			(0x1)
+#define RT5670_GP1_P_SFT			0
+#define RT5670_GP1_P_NOR			(0x0)
+#define RT5670_GP1_P_INV			(0x1)
+
+/* Scramble Function (0xcd) */
+#define RT5670_SCB_KEY_MASK			(0xff)
+#define RT5670_SCB_KEY_SFT			0
+
+/* Scramble Control (0xce) */
+#define RT5670_SCB_SWAP_MASK			(0x1 << 15)
+#define RT5670_SCB_SWAP_SFT			15
+#define RT5670_SCB_SWAP_DIS			(0x0 << 15)
+#define RT5670_SCB_SWAP_EN			(0x1 << 15)
+#define RT5670_SCB_MASK				(0x1 << 14)
+#define RT5670_SCB_SFT				14
+#define RT5670_SCB_DIS				(0x0 << 14)
+#define RT5670_SCB_EN				(0x1 << 14)
+
+/* Baseback Control (0xcf) */
+#define RT5670_BB_MASK				(0x1 << 15)
+#define RT5670_BB_SFT				15
+#define RT5670_BB_DIS				(0x0 << 15)
+#define RT5670_BB_EN				(0x1 << 15)
+#define RT5670_BB_CT_MASK			(0x7 << 12)
+#define RT5670_BB_CT_SFT			12
+#define RT5670_BB_CT_A				(0x0 << 12)
+#define RT5670_BB_CT_B				(0x1 << 12)
+#define RT5670_BB_CT_C				(0x2 << 12)
+#define RT5670_BB_CT_D				(0x3 << 12)
+#define RT5670_M_BB_L_MASK			(0x1 << 9)
+#define RT5670_M_BB_L_SFT			9
+#define RT5670_M_BB_R_MASK			(0x1 << 8)
+#define RT5670_M_BB_R_SFT			8
+#define RT5670_M_BB_HPF_L_MASK			(0x1 << 7)
+#define RT5670_M_BB_HPF_L_SFT			7
+#define RT5670_M_BB_HPF_R_MASK			(0x1 << 6)
+#define RT5670_M_BB_HPF_R_SFT			6
+#define RT5670_G_BB_BST_MASK			(0x3f)
+#define RT5670_G_BB_BST_SFT			0
+
+/* MP3 Plus Control 1 (0xd0) */
+#define RT5670_M_MP3_L_MASK			(0x1 << 15)
+#define RT5670_M_MP3_L_SFT			15
+#define RT5670_M_MP3_R_MASK			(0x1 << 14)
+#define RT5670_M_MP3_R_SFT			14
+#define RT5670_M_MP3_MASK			(0x1 << 13)
+#define RT5670_M_MP3_SFT			13
+#define RT5670_M_MP3_DIS			(0x0 << 13)
+#define RT5670_M_MP3_EN				(0x1 << 13)
+#define RT5670_EG_MP3_MASK			(0x1f << 8)
+#define RT5670_EG_MP3_SFT			8
+#define RT5670_MP3_HLP_MASK			(0x1 << 7)
+#define RT5670_MP3_HLP_SFT			7
+#define RT5670_MP3_HLP_DIS			(0x0 << 7)
+#define RT5670_MP3_HLP_EN			(0x1 << 7)
+#define RT5670_M_MP3_ORG_L_MASK			(0x1 << 6)
+#define RT5670_M_MP3_ORG_L_SFT			6
+#define RT5670_M_MP3_ORG_R_MASK			(0x1 << 5)
+#define RT5670_M_MP3_ORG_R_SFT			5
+
+/* MP3 Plus Control 2 (0xd1) */
+#define RT5670_MP3_WT_MASK			(0x1 << 13)
+#define RT5670_MP3_WT_SFT			13
+#define RT5670_MP3_WT_1_4			(0x0 << 13)
+#define RT5670_MP3_WT_1_2			(0x1 << 13)
+#define RT5670_OG_MP3_MASK			(0x1f << 8)
+#define RT5670_OG_MP3_SFT			8
+#define RT5670_HG_MP3_MASK			(0x3f)
+#define RT5670_HG_MP3_SFT			0
+
+/* 3D HP Control 1 (0xd2) */
+#define RT5670_3D_CF_MASK			(0x1 << 15)
+#define RT5670_3D_CF_SFT			15
+#define RT5670_3D_CF_DIS			(0x0 << 15)
+#define RT5670_3D_CF_EN				(0x1 << 15)
+#define RT5670_3D_HP_MASK			(0x1 << 14)
+#define RT5670_3D_HP_SFT			14
+#define RT5670_3D_HP_DIS			(0x0 << 14)
+#define RT5670_3D_HP_EN				(0x1 << 14)
+#define RT5670_3D_BT_MASK			(0x1 << 13)
+#define RT5670_3D_BT_SFT			13
+#define RT5670_3D_BT_DIS			(0x0 << 13)
+#define RT5670_3D_BT_EN				(0x1 << 13)
+#define RT5670_3D_1F_MIX_MASK			(0x3 << 11)
+#define RT5670_3D_1F_MIX_SFT			11
+#define RT5670_3D_HP_M_MASK			(0x1 << 10)
+#define RT5670_3D_HP_M_SFT			10
+#define RT5670_3D_HP_M_SUR			(0x0 << 10)
+#define RT5670_3D_HP_M_FRO			(0x1 << 10)
+#define RT5670_M_3D_HRTF_MASK			(0x1 << 9)
+#define RT5670_M_3D_HRTF_SFT			9
+#define RT5670_M_3D_D2H_MASK			(0x1 << 8)
+#define RT5670_M_3D_D2H_SFT			8
+#define RT5670_M_3D_D2R_MASK			(0x1 << 7)
+#define RT5670_M_3D_D2R_SFT			7
+#define RT5670_M_3D_REVB_MASK			(0x1 << 6)
+#define RT5670_M_3D_REVB_SFT			6
+
+/* Adjustable high pass filter control 1 (0xd3) */
+#define RT5670_2ND_HPF_MASK			(0x1 << 15)
+#define RT5670_2ND_HPF_SFT			15
+#define RT5670_2ND_HPF_DIS			(0x0 << 15)
+#define RT5670_2ND_HPF_EN			(0x1 << 15)
+#define RT5670_HPF_CF_L_MASK			(0x7 << 12)
+#define RT5670_HPF_CF_L_SFT			12
+#define RT5670_1ST_HPF_MASK			(0x1 << 11)
+#define RT5670_1ST_HPF_SFT			11
+#define RT5670_1ST_HPF_DIS			(0x0 << 11)
+#define RT5670_1ST_HPF_EN			(0x1 << 11)
+#define RT5670_HPF_CF_R_MASK			(0x7 << 8)
+#define RT5670_HPF_CF_R_SFT			8
+#define RT5670_ZD_T_MASK			(0x3 << 6)
+#define RT5670_ZD_T_SFT				6
+#define RT5670_ZD_F_MASK			(0x3 << 4)
+#define RT5670_ZD_F_SFT				4
+#define RT5670_ZD_F_IM				(0x0 << 4)
+#define RT5670_ZD_F_ZC_IM			(0x1 << 4)
+#define RT5670_ZD_F_ZC_IOD			(0x2 << 4)
+#define RT5670_ZD_F_UN				(0x3 << 4)
+
+/* HP calibration control and Amp detection (0xd6) */
+#define RT5670_SI_DAC_MASK			(0x1 << 11)
+#define RT5670_SI_DAC_SFT			11
+#define RT5670_SI_DAC_AUTO			(0x0 << 11)
+#define RT5670_SI_DAC_TEST			(0x1 << 11)
+#define RT5670_DC_CAL_M_MASK			(0x1 << 10)
+#define RT5670_DC_CAL_M_SFT			10
+#define RT5670_DC_CAL_M_CAL			(0x0 << 10)
+#define RT5670_DC_CAL_M_NOR			(0x1 << 10)
+#define RT5670_DC_CAL_MASK			(0x1 << 9)
+#define RT5670_DC_CAL_SFT			9
+#define RT5670_DC_CAL_DIS			(0x0 << 9)
+#define RT5670_DC_CAL_EN			(0x1 << 9)
+#define RT5670_HPD_RCV_MASK			(0x7 << 6)
+#define RT5670_HPD_RCV_SFT			6
+#define RT5670_HPD_PS_MASK			(0x1 << 5)
+#define RT5670_HPD_PS_SFT			5
+#define RT5670_HPD_PS_DIS			(0x0 << 5)
+#define RT5670_HPD_PS_EN			(0x1 << 5)
+#define RT5670_CAL_M_MASK			(0x1 << 4)
+#define RT5670_CAL_M_SFT			4
+#define RT5670_CAL_M_DEP			(0x0 << 4)
+#define RT5670_CAL_M_CAL			(0x1 << 4)
+#define RT5670_CAL_MASK				(0x1 << 3)
+#define RT5670_CAL_SFT				3
+#define RT5670_CAL_DIS				(0x0 << 3)
+#define RT5670_CAL_EN				(0x1 << 3)
+#define RT5670_CAL_TEST_MASK			(0x1 << 2)
+#define RT5670_CAL_TEST_SFT			2
+#define RT5670_CAL_TEST_DIS			(0x0 << 2)
+#define RT5670_CAL_TEST_EN			(0x1 << 2)
+#define RT5670_CAL_P_MASK			(0x3)
+#define RT5670_CAL_P_SFT			0
+#define RT5670_CAL_P_NONE			(0x0)
+#define RT5670_CAL_P_CAL			(0x1)
+#define RT5670_CAL_P_DAC_CAL			(0x2)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5670_SV_MASK				(0x1 << 15)
+#define RT5670_SV_SFT				15
+#define RT5670_SV_DIS				(0x0 << 15)
+#define RT5670_SV_EN				(0x1 << 15)
+#define RT5670_SPO_SV_MASK			(0x1 << 14)
+#define RT5670_SPO_SV_SFT			14
+#define RT5670_SPO_SV_DIS			(0x0 << 14)
+#define RT5670_SPO_SV_EN			(0x1 << 14)
+#define RT5670_OUT_SV_MASK			(0x1 << 13)
+#define RT5670_OUT_SV_SFT			13
+#define RT5670_OUT_SV_DIS			(0x0 << 13)
+#define RT5670_OUT_SV_EN			(0x1 << 13)
+#define RT5670_HP_SV_MASK			(0x1 << 12)
+#define RT5670_HP_SV_SFT			12
+#define RT5670_HP_SV_DIS			(0x0 << 12)
+#define RT5670_HP_SV_EN				(0x1 << 12)
+#define RT5670_ZCD_DIG_MASK			(0x1 << 11)
+#define RT5670_ZCD_DIG_SFT			11
+#define RT5670_ZCD_DIG_DIS			(0x0 << 11)
+#define RT5670_ZCD_DIG_EN			(0x1 << 11)
+#define RT5670_ZCD_MASK				(0x1 << 10)
+#define RT5670_ZCD_SFT				10
+#define RT5670_ZCD_PD				(0x0 << 10)
+#define RT5670_ZCD_PU				(0x1 << 10)
+#define RT5670_M_ZCD_MASK			(0x3f << 4)
+#define RT5670_M_ZCD_SFT			4
+#define RT5670_M_ZCD_RM_L			(0x1 << 9)
+#define RT5670_M_ZCD_RM_R			(0x1 << 8)
+#define RT5670_M_ZCD_SM_L			(0x1 << 7)
+#define RT5670_M_ZCD_SM_R			(0x1 << 6)
+#define RT5670_M_ZCD_OM_L			(0x1 << 5)
+#define RT5670_M_ZCD_OM_R			(0x1 << 4)
+#define RT5670_SV_DLY_MASK			(0xf)
+#define RT5670_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5670_ZCD_HP_MASK			(0x1 << 15)
+#define RT5670_ZCD_HP_SFT			15
+#define RT5670_ZCD_HP_DIS			(0x0 << 15)
+#define RT5670_ZCD_HP_EN			(0x1 << 15)
+
+/* General Control 3 (0xfc) */
+#define RT5670_TDM_DATA_MODE_SEL		(0x1 << 11)
+#define RT5670_TDM_DATA_MODE_NOR		(0x0 << 11)
+#define RT5670_TDM_DATA_MODE_50FS		(0x1 << 11)
+
+/* Codec Private Register definition */
+/* 3D Speaker Control (0x63) */
+#define RT5670_3D_SPK_MASK			(0x1 << 15)
+#define RT5670_3D_SPK_SFT			15
+#define RT5670_3D_SPK_DIS			(0x0 << 15)
+#define RT5670_3D_SPK_EN			(0x1 << 15)
+#define RT5670_3D_SPK_M_MASK			(0x3 << 13)
+#define RT5670_3D_SPK_M_SFT			13
+#define RT5670_3D_SPK_CG_MASK			(0x1f << 8)
+#define RT5670_3D_SPK_CG_SFT			8
+#define RT5670_3D_SPK_SG_MASK			(0x1f)
+#define RT5670_3D_SPK_SG_SFT			0
+
+/* Wind Noise Detection Control 1 (0x6c) */
+#define RT5670_WND_MASK				(0x1 << 15)
+#define RT5670_WND_SFT				15
+#define RT5670_WND_DIS				(0x0 << 15)
+#define RT5670_WND_EN				(0x1 << 15)
+
+/* Wind Noise Detection Control 2 (0x6d) */
+#define RT5670_WND_FC_NW_MASK			(0x3f << 10)
+#define RT5670_WND_FC_NW_SFT			10
+#define RT5670_WND_FC_WK_MASK			(0x3f << 4)
+#define RT5670_WND_FC_WK_SFT			4
+
+/* Wind Noise Detection Control 3 (0x6e) */
+#define RT5670_HPF_FC_MASK			(0x3f << 6)
+#define RT5670_HPF_FC_SFT			6
+#define RT5670_WND_FC_ST_MASK			(0x3f)
+#define RT5670_WND_FC_ST_SFT			0
+
+/* Wind Noise Detection Control 4 (0x6f) */
+#define RT5670_WND_TH_LO_MASK			(0x3ff)
+#define RT5670_WND_TH_LO_SFT			0
+
+/* Wind Noise Detection Control 5 (0x70) */
+#define RT5670_WND_TH_HI_MASK			(0x3ff)
+#define RT5670_WND_TH_HI_SFT			0
+
+/* Wind Noise Detection Control 8 (0x73) */
+#define RT5670_WND_WIND_MASK			(0x1 << 13) /* Read-Only */
+#define RT5670_WND_WIND_SFT			13
+#define RT5670_WND_STRONG_MASK			(0x1 << 12) /* Read-Only */
+#define RT5670_WND_STRONG_SFT			12
+enum {
+	RT5670_NO_WIND,
+	RT5670_BREEZE,
+	RT5670_STORM,
+};
+
+/* Dipole Speaker Interface (0x75) */
+#define RT5670_DP_ATT_MASK			(0x3 << 14)
+#define RT5670_DP_ATT_SFT			14
+#define RT5670_DP_SPK_MASK			(0x1 << 10)
+#define RT5670_DP_SPK_SFT			10
+#define RT5670_DP_SPK_DIS			(0x0 << 10)
+#define RT5670_DP_SPK_EN			(0x1 << 10)
+
+/* EQ Pre Volume Control (0xb3) */
+#define RT5670_EQ_PRE_VOL_MASK			(0xffff)
+#define RT5670_EQ_PRE_VOL_SFT			0
+
+/* EQ Post Volume Control (0xb4) */
+#define RT5670_EQ_PST_VOL_MASK			(0xffff)
+#define RT5670_EQ_PST_VOL_SFT			0
+
+/* Jack Detect Control 3 (0xf8) */
+#define RT5670_CMP_MIC_IN_DET_MASK		(0x7 << 12)
+#define RT5670_JD_CBJ_EN			(0x1 << 7)
+#define RT5670_JD_CBJ_POL			(0x1 << 6)
+#define RT5670_JD_TRI_CBJ_SEL_MASK		(0x7 << 3)
+#define RT5670_JD_TRI_CBJ_SEL_SFT		(3)
+#define RT5670_JD_CBJ_GPIO_JD1			(0x0 << 3)
+#define RT5670_JD_CBJ_JD1_1			(0x1 << 3)
+#define RT5670_JD_CBJ_JD1_2			(0x2 << 3)
+#define RT5670_JD_CBJ_JD2			(0x3 << 3)
+#define RT5670_JD_CBJ_JD3			(0x4 << 3)
+#define RT5670_JD_CBJ_GPIO_JD2			(0x5 << 3)
+#define RT5670_JD_CBJ_MX0B_12			(0x6 << 3)
+#define RT5670_JD_TRI_HPO_SEL_MASK		(0x7 << 3)
+#define RT5670_JD_TRI_HPO_SEL_SFT		(0)
+#define RT5670_JD_HPO_GPIO_JD1			(0x0)
+#define RT5670_JD_HPO_JD1_1			(0x1)
+#define RT5670_JD_HPO_JD1_2			(0x2)
+#define RT5670_JD_HPO_JD2			(0x3)
+#define RT5670_JD_HPO_JD3			(0x4)
+#define RT5670_JD_HPO_GPIO_JD2			(0x5)
+#define RT5670_JD_HPO_MX0B_12			(0x6)
+
+/* Digital Misc Control (0xfa) */
+#define RT5670_RST_DSP				(0x1 << 13)
+#define RT5670_IF1_ADC1_IN1_SEL			(0x1 << 12)
+#define RT5670_IF1_ADC1_IN1_SFT			12
+#define RT5670_IF1_ADC1_IN2_SEL			(0x1 << 11)
+#define RT5670_IF1_ADC1_IN2_SFT			11
+#define RT5670_IF1_ADC2_IN1_SEL			(0x1 << 10)
+#define RT5670_IF1_ADC2_IN1_SFT			10
+#define RT5670_MCLK_DET				(0x1 << 3)
+
+/* General Control2 (0xfb) */
+#define RT5670_RXDC_SRC_MASK			(0x1 << 7)
+#define RT5670_RXDC_SRC_STO			(0x0 << 7)
+#define RT5670_RXDC_SRC_MONO			(0x1 << 7)
+#define RT5670_RXDC_SRC_SFT			(7)
+#define RT5670_RXDP2_SEL_MASK			(0x1 << 3)
+#define RT5670_RXDP2_SEL_IF2			(0x0 << 3)
+#define RT5670_RXDP2_SEL_ADC			(0x1 << 3)
+#define RT5670_RXDP2_SEL_SFT			(3)
+
+/* System Clock Source */
+enum {
+	RT5670_SCLK_S_MCLK,
+	RT5670_SCLK_S_PLL1,
+	RT5670_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+	RT5670_PLL1_S_MCLK,
+	RT5670_PLL1_S_BCLK1,
+	RT5670_PLL1_S_BCLK2,
+	RT5670_PLL1_S_BCLK3,
+	RT5670_PLL1_S_BCLK4,
+};
+
+enum {
+	RT5670_AIF1,
+	RT5670_AIF2,
+	RT5670_AIF3,
+	RT5670_AIF4,
+	RT5670_AIFS,
+};
+
+enum {
+	RT5670_DMIC1_DISABLED,
+	RT5670_DMIC_DATA_GPIO6,
+	RT5670_DMIC_DATA_IN2P,
+	RT5670_DMIC_DATA_GPIO7,
+};
+
+enum {
+	RT5670_DMIC2_DISABLED,
+	RT5670_DMIC_DATA_GPIO8,
+	RT5670_DMIC_DATA_IN3N,
+};
+
+enum {
+	RT5670_DMIC3_DISABLED,
+	RT5670_DMIC_DATA_GPIO9,
+	RT5670_DMIC_DATA_GPIO10,
+	RT5670_DMIC_DATA_GPIO5,
+};
+
+/* filter mask */
+enum {
+	RT5670_DA_STEREO_FILTER = 0x1,
+	RT5670_DA_MONO_L_FILTER = (0x1 << 1),
+	RT5670_DA_MONO_R_FILTER = (0x1 << 2),
+	RT5670_AD_STEREO_FILTER = (0x1 << 3),
+	RT5670_AD_MONO_L_FILTER = (0x1 << 4),
+	RT5670_AD_MONO_R_FILTER = (0x1 << 5),
+	RT5670_UP_RATE_FILTER   = (0x1 << 6),
+	RT5670_DOWN_RATE_FILTER = (0x1 << 7),
+};
+
+int rt5670_sel_asrc_clk_src(struct snd_soc_component *component,
+			    unsigned int filter_mask, unsigned int clk_src);
+
+struct rt5670_priv {
+	struct snd_soc_component *component;
+	struct rt5670_platform_data pdata;
+	struct regmap *regmap;
+	struct snd_soc_jack *jack;
+	struct snd_soc_jack_gpio hp_gpio;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5670_AIFS];
+	int bclk[RT5670_AIFS];
+	int master[RT5670_AIFS];
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+	int dsp_sw; /* expected parameter setting */
+	int dsp_rate;
+	int jack_type;
+	int jack_type_saved;
+};
+
+void rt5670_jack_suspend(struct snd_soc_component *component);
+void rt5670_jack_resume(struct snd_soc_component *component);
+int rt5670_set_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *jack);
+#endif /* __RT5670_H__ */
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
new file mode 100644
index 0000000..bd51f36
--- /dev/null
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -0,0 +1,240 @@
+/*
+ * rt5677-spi.c  --  RT5677 ALSA SoC audio codec driver
+ *
+ * Copyright 2013 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/spi/spi.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_qos.h>
+#include <linux/sysfs.h>
+#include <linux/clk.h>
+#include <linux/firmware.h>
+
+#include "rt5677-spi.h"
+
+#define RT5677_SPI_BURST_LEN	240
+#define RT5677_SPI_HEADER	5
+#define RT5677_SPI_FREQ		6000000
+
+/* The AddressPhase and DataPhase of SPI commands are MSB first on the wire.
+ * DataPhase word size of 16-bit commands is 2 bytes.
+ * DataPhase word size of 32-bit commands is 4 bytes.
+ * DataPhase word size of burst commands is 8 bytes.
+ * The DSP CPU is little-endian.
+ */
+#define RT5677_SPI_WRITE_BURST	0x5
+#define RT5677_SPI_READ_BURST	0x4
+#define RT5677_SPI_WRITE_32	0x3
+#define RT5677_SPI_READ_32	0x2
+#define RT5677_SPI_WRITE_16	0x1
+#define RT5677_SPI_READ_16	0x0
+
+static struct spi_device *g_spi;
+static DEFINE_MUTEX(spi_mutex);
+
+/* Select a suitable transfer command for the next transfer to ensure
+ * the transfer address is always naturally aligned while minimizing
+ * the total number of transfers required.
+ *
+ * 3 transfer commands are available:
+ * RT5677_SPI_READ/WRITE_16:	Transfer 2 bytes
+ * RT5677_SPI_READ/WRITE_32:	Transfer 4 bytes
+ * RT5677_SPI_READ/WRITE_BURST:	Transfer any multiples of 8 bytes
+ *
+ * For example, reading 260 bytes at 0x60030002 uses the following commands:
+ * 0x60030002 RT5677_SPI_READ_16	2 bytes
+ * 0x60030004 RT5677_SPI_READ_32	4 bytes
+ * 0x60030008 RT5677_SPI_READ_BURST	240 bytes
+ * 0x600300F8 RT5677_SPI_READ_BURST	8 bytes
+ * 0x60030100 RT5677_SPI_READ_32	4 bytes
+ * 0x60030104 RT5677_SPI_READ_16	2 bytes
+ *
+ * Input:
+ * @read: true for read commands; false for write commands
+ * @align: alignment of the next transfer address
+ * @remain: number of bytes remaining to transfer
+ *
+ * Output:
+ * @len: number of bytes to transfer with the selected command
+ * Returns the selected command
+ */
+static u8 rt5677_spi_select_cmd(bool read, u32 align, u32 remain, u32 *len)
+{
+	u8 cmd;
+
+	if (align == 2 || align == 6 || remain == 2) {
+		cmd = RT5677_SPI_READ_16;
+		*len = 2;
+	} else if (align == 4 || remain <= 6) {
+		cmd = RT5677_SPI_READ_32;
+		*len = 4;
+	} else {
+		cmd = RT5677_SPI_READ_BURST;
+		*len = min_t(u32, remain & ~7, RT5677_SPI_BURST_LEN);
+	}
+	return read ? cmd : cmd + 1;
+}
+
+/* Copy dstlen bytes from src to dst, while reversing byte order for each word.
+ * If srclen < dstlen, zeros are padded.
+ */
+static void rt5677_spi_reverse(u8 *dst, u32 dstlen, const u8 *src, u32 srclen)
+{
+	u32 w, i, si;
+	u32 word_size = min_t(u32, dstlen, 8);
+
+	for (w = 0; w < dstlen; w += word_size) {
+		for (i = 0; i < word_size; i++) {
+			si = w + word_size - i - 1;
+			dst[w + i] = si < srclen ? src[si] : 0;
+		}
+	}
+}
+
+/* Read DSP address space using SPI. addr and len have to be 2-byte aligned. */
+int rt5677_spi_read(u32 addr, void *rxbuf, size_t len)
+{
+	u32 offset;
+	int status = 0;
+	struct spi_transfer t[2];
+	struct spi_message m;
+	/* +4 bytes is for the DummyPhase following the AddressPhase */
+	u8 header[RT5677_SPI_HEADER + 4];
+	u8 body[RT5677_SPI_BURST_LEN];
+	u8 spi_cmd;
+	u8 *cb = rxbuf;
+
+	if (!g_spi)
+		return -ENODEV;
+
+	if ((addr & 1) || (len & 1)) {
+		dev_err(&g_spi->dev, "Bad read align 0x%x(%zu)\n", addr, len);
+		return -EACCES;
+	}
+
+	memset(t, 0, sizeof(t));
+	t[0].tx_buf = header;
+	t[0].len = sizeof(header);
+	t[0].speed_hz = RT5677_SPI_FREQ;
+	t[1].rx_buf = body;
+	t[1].speed_hz = RT5677_SPI_FREQ;
+	spi_message_init_with_transfers(&m, t, ARRAY_SIZE(t));
+
+	for (offset = 0; offset < len; offset += t[1].len) {
+		spi_cmd = rt5677_spi_select_cmd(true, (addr + offset) & 7,
+				len - offset, &t[1].len);
+
+		/* Construct SPI message header */
+		header[0] = spi_cmd;
+		header[1] = ((addr + offset) & 0xff000000) >> 24;
+		header[2] = ((addr + offset) & 0x00ff0000) >> 16;
+		header[3] = ((addr + offset) & 0x0000ff00) >> 8;
+		header[4] = ((addr + offset) & 0x000000ff) >> 0;
+
+		mutex_lock(&spi_mutex);
+		status |= spi_sync(g_spi, &m);
+		mutex_unlock(&spi_mutex);
+
+		/* Copy data back to caller buffer */
+		rt5677_spi_reverse(cb + offset, t[1].len, body, t[1].len);
+	}
+	return status;
+}
+EXPORT_SYMBOL_GPL(rt5677_spi_read);
+
+/* Write DSP address space using SPI. addr has to be 2-byte aligned.
+ * If len is not 2-byte aligned, an extra byte of zero is written at the end
+ * as padding.
+ */
+int rt5677_spi_write(u32 addr, const void *txbuf, size_t len)
+{
+	u32 offset, len_with_pad = len;
+	int status = 0;
+	struct spi_transfer t;
+	struct spi_message m;
+	/* +1 byte is for the DummyPhase following the DataPhase */
+	u8 buf[RT5677_SPI_HEADER + RT5677_SPI_BURST_LEN + 1];
+	u8 *body = buf + RT5677_SPI_HEADER;
+	u8 spi_cmd;
+	const u8 *cb = txbuf;
+
+	if (!g_spi)
+		return -ENODEV;
+
+	if (addr & 1) {
+		dev_err(&g_spi->dev, "Bad write align 0x%x(%zu)\n", addr, len);
+		return -EACCES;
+	}
+
+	if (len & 1)
+		len_with_pad = len + 1;
+
+	memset(&t, 0, sizeof(t));
+	t.tx_buf = buf;
+	t.speed_hz = RT5677_SPI_FREQ;
+	spi_message_init_with_transfers(&m, &t, 1);
+
+	for (offset = 0; offset < len_with_pad;) {
+		spi_cmd = rt5677_spi_select_cmd(false, (addr + offset) & 7,
+				len_with_pad - offset, &t.len);
+
+		/* Construct SPI message header */
+		buf[0] = spi_cmd;
+		buf[1] = ((addr + offset) & 0xff000000) >> 24;
+		buf[2] = ((addr + offset) & 0x00ff0000) >> 16;
+		buf[3] = ((addr + offset) & 0x0000ff00) >> 8;
+		buf[4] = ((addr + offset) & 0x000000ff) >> 0;
+
+		/* Fetch data from caller buffer */
+		rt5677_spi_reverse(body, t.len, cb + offset, len - offset);
+		offset += t.len;
+		t.len += RT5677_SPI_HEADER + 1;
+
+		mutex_lock(&spi_mutex);
+		status |= spi_sync(g_spi, &m);
+		mutex_unlock(&spi_mutex);
+	}
+	return status;
+}
+EXPORT_SYMBOL_GPL(rt5677_spi_write);
+
+int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw)
+{
+	return rt5677_spi_write(addr, fw->data, fw->size);
+}
+EXPORT_SYMBOL_GPL(rt5677_spi_write_firmware);
+
+static int rt5677_spi_probe(struct spi_device *spi)
+{
+	g_spi = spi;
+	return 0;
+}
+
+static struct spi_driver rt5677_spi_driver = {
+	.driver = {
+		.name = "rt5677",
+	},
+	.probe = rt5677_spi_probe,
+};
+module_spi_driver(rt5677_spi_driver);
+
+MODULE_DESCRIPTION("ASoC RT5677 SPI driver");
+MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5677-spi.h b/sound/soc/codecs/rt5677-spi.h
new file mode 100644
index 0000000..662db16
--- /dev/null
+++ b/sound/soc/codecs/rt5677-spi.h
@@ -0,0 +1,19 @@
+/*
+ * rt5677-spi.h  --  RT5677 ALSA SoC audio codec driver
+ *
+ * Copyright 2013 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5677_SPI_H__
+#define __RT5677_SPI_H__
+
+int rt5677_spi_read(u32 addr, void *rxbuf, size_t len);
+int rt5677_spi_write(u32 addr, const void *txbuf, size_t len);
+int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw);
+
+#endif /* __RT5677_SPI_H__ */
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
new file mode 100644
index 0000000..9b7a183
--- /dev/null
+++ b/sound/soc/codecs/rt5677.c
@@ -0,0 +1,5281 @@
+/*
+ * rt5677.c  --  RT5677 ALSA SoC audio codec driver
+ *
+ * Copyright 2013 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/firmware.h>
+#include <linux/of_device.h>
+#include <linux/property.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rl6231.h"
+#include "rt5677.h"
+#include "rt5677-spi.h"
+
+#define RT5677_DEVICE_ID 0x6327
+
+#define RT5677_PR_RANGE_BASE (0xff + 1)
+#define RT5677_PR_SPACING 0x100
+
+#define RT5677_PR_BASE (RT5677_PR_RANGE_BASE + (0 * RT5677_PR_SPACING))
+
+static const struct regmap_range_cfg rt5677_ranges[] = {
+	{
+		.name = "PR",
+		.range_min = RT5677_PR_BASE,
+		.range_max = RT5677_PR_BASE + 0xfd,
+		.selector_reg = RT5677_PRIV_INDEX,
+		.selector_mask = 0xff,
+		.selector_shift = 0x0,
+		.window_start = RT5677_PRIV_DATA,
+		.window_len = 0x1,
+	},
+};
+
+static const struct reg_sequence init_list[] = {
+	{RT5677_ASRC_12,	0x0018},
+	{RT5677_PR_BASE + 0x3d,	0x364d},
+	{RT5677_PR_BASE + 0x17,	0x4fc0},
+	{RT5677_PR_BASE + 0x13,	0x0312},
+	{RT5677_PR_BASE + 0x1e,	0x0000},
+	{RT5677_PR_BASE + 0x12,	0x0eaa},
+	{RT5677_PR_BASE + 0x14,	0x018a},
+	{RT5677_PR_BASE + 0x15,	0x0490},
+	{RT5677_PR_BASE + 0x38,	0x0f71},
+	{RT5677_PR_BASE + 0x39,	0x0f71},
+};
+#define RT5677_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+static const struct reg_default rt5677_reg[] = {
+	{RT5677_RESET			, 0x0000},
+	{RT5677_LOUT1			, 0xa800},
+	{RT5677_IN1			, 0x0000},
+	{RT5677_MICBIAS			, 0x0000},
+	{RT5677_SLIMBUS_PARAM		, 0x0000},
+	{RT5677_SLIMBUS_RX		, 0x0000},
+	{RT5677_SLIMBUS_CTRL		, 0x0000},
+	{RT5677_SIDETONE_CTRL		, 0x000b},
+	{RT5677_ANA_DAC1_2_3_SRC	, 0x0000},
+	{RT5677_IF_DSP_DAC3_4_MIXER	, 0x1111},
+	{RT5677_DAC4_DIG_VOL		, 0xafaf},
+	{RT5677_DAC3_DIG_VOL		, 0xafaf},
+	{RT5677_DAC1_DIG_VOL		, 0xafaf},
+	{RT5677_DAC2_DIG_VOL		, 0xafaf},
+	{RT5677_IF_DSP_DAC2_MIXER	, 0x0011},
+	{RT5677_STO1_ADC_DIG_VOL	, 0x2f2f},
+	{RT5677_MONO_ADC_DIG_VOL	, 0x2f2f},
+	{RT5677_STO1_2_ADC_BST		, 0x0000},
+	{RT5677_STO2_ADC_DIG_VOL	, 0x2f2f},
+	{RT5677_ADC_BST_CTRL2		, 0x0000},
+	{RT5677_STO3_4_ADC_BST		, 0x0000},
+	{RT5677_STO3_ADC_DIG_VOL	, 0x2f2f},
+	{RT5677_STO4_ADC_DIG_VOL	, 0x2f2f},
+	{RT5677_STO4_ADC_MIXER		, 0xd4c0},
+	{RT5677_STO3_ADC_MIXER		, 0xd4c0},
+	{RT5677_STO2_ADC_MIXER		, 0xd4c0},
+	{RT5677_STO1_ADC_MIXER		, 0xd4c0},
+	{RT5677_MONO_ADC_MIXER		, 0xd4d1},
+	{RT5677_ADC_IF_DSP_DAC1_MIXER	, 0x8080},
+	{RT5677_STO1_DAC_MIXER		, 0xaaaa},
+	{RT5677_MONO_DAC_MIXER		, 0xaaaa},
+	{RT5677_DD1_MIXER		, 0xaaaa},
+	{RT5677_DD2_MIXER		, 0xaaaa},
+	{RT5677_IF3_DATA		, 0x0000},
+	{RT5677_IF4_DATA		, 0x0000},
+	{RT5677_PDM_OUT_CTRL		, 0x8888},
+	{RT5677_PDM_DATA_CTRL1		, 0x0000},
+	{RT5677_PDM_DATA_CTRL2		, 0x0000},
+	{RT5677_PDM1_DATA_CTRL2		, 0x0000},
+	{RT5677_PDM1_DATA_CTRL3		, 0x0000},
+	{RT5677_PDM1_DATA_CTRL4		, 0x0000},
+	{RT5677_PDM2_DATA_CTRL2		, 0x0000},
+	{RT5677_PDM2_DATA_CTRL3		, 0x0000},
+	{RT5677_PDM2_DATA_CTRL4		, 0x0000},
+	{RT5677_TDM1_CTRL1		, 0x0300},
+	{RT5677_TDM1_CTRL2		, 0x0000},
+	{RT5677_TDM1_CTRL3		, 0x4000},
+	{RT5677_TDM1_CTRL4		, 0x0123},
+	{RT5677_TDM1_CTRL5		, 0x4567},
+	{RT5677_TDM2_CTRL1		, 0x0300},
+	{RT5677_TDM2_CTRL2		, 0x0000},
+	{RT5677_TDM2_CTRL3		, 0x4000},
+	{RT5677_TDM2_CTRL4		, 0x0123},
+	{RT5677_TDM2_CTRL5		, 0x4567},
+	{RT5677_I2C_MASTER_CTRL1	, 0x0001},
+	{RT5677_I2C_MASTER_CTRL2	, 0x0000},
+	{RT5677_I2C_MASTER_CTRL3	, 0x0000},
+	{RT5677_I2C_MASTER_CTRL4	, 0x0000},
+	{RT5677_I2C_MASTER_CTRL5	, 0x0000},
+	{RT5677_I2C_MASTER_CTRL6	, 0x0000},
+	{RT5677_I2C_MASTER_CTRL7	, 0x0000},
+	{RT5677_I2C_MASTER_CTRL8	, 0x0000},
+	{RT5677_DMIC_CTRL1		, 0x1505},
+	{RT5677_DMIC_CTRL2		, 0x0055},
+	{RT5677_HAP_GENE_CTRL1		, 0x0111},
+	{RT5677_HAP_GENE_CTRL2		, 0x0064},
+	{RT5677_HAP_GENE_CTRL3		, 0xef0e},
+	{RT5677_HAP_GENE_CTRL4		, 0xf0f0},
+	{RT5677_HAP_GENE_CTRL5		, 0xef0e},
+	{RT5677_HAP_GENE_CTRL6		, 0xf0f0},
+	{RT5677_HAP_GENE_CTRL7		, 0xef0e},
+	{RT5677_HAP_GENE_CTRL8		, 0xf0f0},
+	{RT5677_HAP_GENE_CTRL9		, 0xf000},
+	{RT5677_HAP_GENE_CTRL10		, 0x0000},
+	{RT5677_PWR_DIG1		, 0x0000},
+	{RT5677_PWR_DIG2		, 0x0000},
+	{RT5677_PWR_ANLG1		, 0x0055},
+	{RT5677_PWR_ANLG2		, 0x0000},
+	{RT5677_PWR_DSP1		, 0x0001},
+	{RT5677_PWR_DSP_ST		, 0x0000},
+	{RT5677_PWR_DSP2		, 0x0000},
+	{RT5677_ADC_DAC_HPF_CTRL1	, 0x0e00},
+	{RT5677_PRIV_INDEX		, 0x0000},
+	{RT5677_PRIV_DATA		, 0x0000},
+	{RT5677_I2S4_SDP		, 0x8000},
+	{RT5677_I2S1_SDP		, 0x8000},
+	{RT5677_I2S2_SDP		, 0x8000},
+	{RT5677_I2S3_SDP		, 0x8000},
+	{RT5677_CLK_TREE_CTRL1		, 0x1111},
+	{RT5677_CLK_TREE_CTRL2		, 0x1111},
+	{RT5677_CLK_TREE_CTRL3		, 0x0000},
+	{RT5677_PLL1_CTRL1		, 0x0000},
+	{RT5677_PLL1_CTRL2		, 0x0000},
+	{RT5677_PLL2_CTRL1		, 0x0c60},
+	{RT5677_PLL2_CTRL2		, 0x2000},
+	{RT5677_GLB_CLK1		, 0x0000},
+	{RT5677_GLB_CLK2		, 0x0000},
+	{RT5677_ASRC_1			, 0x0000},
+	{RT5677_ASRC_2			, 0x0000},
+	{RT5677_ASRC_3			, 0x0000},
+	{RT5677_ASRC_4			, 0x0000},
+	{RT5677_ASRC_5			, 0x0000},
+	{RT5677_ASRC_6			, 0x0000},
+	{RT5677_ASRC_7			, 0x0000},
+	{RT5677_ASRC_8			, 0x0000},
+	{RT5677_ASRC_9			, 0x0000},
+	{RT5677_ASRC_10			, 0x0000},
+	{RT5677_ASRC_11			, 0x0000},
+	{RT5677_ASRC_12			, 0x0018},
+	{RT5677_ASRC_13			, 0x0000},
+	{RT5677_ASRC_14			, 0x0000},
+	{RT5677_ASRC_15			, 0x0000},
+	{RT5677_ASRC_16			, 0x0000},
+	{RT5677_ASRC_17			, 0x0000},
+	{RT5677_ASRC_18			, 0x0000},
+	{RT5677_ASRC_19			, 0x0000},
+	{RT5677_ASRC_20			, 0x0000},
+	{RT5677_ASRC_21			, 0x000c},
+	{RT5677_ASRC_22			, 0x0000},
+	{RT5677_ASRC_23			, 0x0000},
+	{RT5677_VAD_CTRL1		, 0x2184},
+	{RT5677_VAD_CTRL2		, 0x010a},
+	{RT5677_VAD_CTRL3		, 0x0aea},
+	{RT5677_VAD_CTRL4		, 0x000c},
+	{RT5677_VAD_CTRL5		, 0x0000},
+	{RT5677_DSP_INB_CTRL1		, 0x0000},
+	{RT5677_DSP_INB_CTRL2		, 0x0000},
+	{RT5677_DSP_IN_OUTB_CTRL	, 0x0000},
+	{RT5677_DSP_OUTB0_1_DIG_VOL	, 0x2f2f},
+	{RT5677_DSP_OUTB2_3_DIG_VOL	, 0x2f2f},
+	{RT5677_DSP_OUTB4_5_DIG_VOL	, 0x2f2f},
+	{RT5677_DSP_OUTB6_7_DIG_VOL	, 0x2f2f},
+	{RT5677_ADC_EQ_CTRL1		, 0x6000},
+	{RT5677_ADC_EQ_CTRL2		, 0x0000},
+	{RT5677_EQ_CTRL1		, 0xc000},
+	{RT5677_EQ_CTRL2		, 0x0000},
+	{RT5677_EQ_CTRL3		, 0x0000},
+	{RT5677_SOFT_VOL_ZERO_CROSS1	, 0x0009},
+	{RT5677_JD_CTRL1		, 0x0000},
+	{RT5677_JD_CTRL2		, 0x0000},
+	{RT5677_JD_CTRL3		, 0x0000},
+	{RT5677_IRQ_CTRL1		, 0x0000},
+	{RT5677_IRQ_CTRL2		, 0x0000},
+	{RT5677_GPIO_ST			, 0x0000},
+	{RT5677_GPIO_CTRL1		, 0x0000},
+	{RT5677_GPIO_CTRL2		, 0x0000},
+	{RT5677_GPIO_CTRL3		, 0x0000},
+	{RT5677_STO1_ADC_HI_FILTER1	, 0xb320},
+	{RT5677_STO1_ADC_HI_FILTER2	, 0x0000},
+	{RT5677_MONO_ADC_HI_FILTER1	, 0xb300},
+	{RT5677_MONO_ADC_HI_FILTER2	, 0x0000},
+	{RT5677_STO2_ADC_HI_FILTER1	, 0xb300},
+	{RT5677_STO2_ADC_HI_FILTER2	, 0x0000},
+	{RT5677_STO3_ADC_HI_FILTER1	, 0xb300},
+	{RT5677_STO3_ADC_HI_FILTER2	, 0x0000},
+	{RT5677_STO4_ADC_HI_FILTER1	, 0xb300},
+	{RT5677_STO4_ADC_HI_FILTER2	, 0x0000},
+	{RT5677_MB_DRC_CTRL1		, 0x0f20},
+	{RT5677_DRC1_CTRL1		, 0x001f},
+	{RT5677_DRC1_CTRL2		, 0x020c},
+	{RT5677_DRC1_CTRL3		, 0x1f00},
+	{RT5677_DRC1_CTRL4		, 0x0000},
+	{RT5677_DRC1_CTRL5		, 0x0000},
+	{RT5677_DRC1_CTRL6		, 0x0029},
+	{RT5677_DRC2_CTRL1		, 0x001f},
+	{RT5677_DRC2_CTRL2		, 0x020c},
+	{RT5677_DRC2_CTRL3		, 0x1f00},
+	{RT5677_DRC2_CTRL4		, 0x0000},
+	{RT5677_DRC2_CTRL5		, 0x0000},
+	{RT5677_DRC2_CTRL6		, 0x0029},
+	{RT5677_DRC1_HL_CTRL1		, 0x8000},
+	{RT5677_DRC1_HL_CTRL2		, 0x0200},
+	{RT5677_DRC2_HL_CTRL1		, 0x8000},
+	{RT5677_DRC2_HL_CTRL2		, 0x0200},
+	{RT5677_DSP_INB1_SRC_CTRL1	, 0x5800},
+	{RT5677_DSP_INB1_SRC_CTRL2	, 0x0000},
+	{RT5677_DSP_INB1_SRC_CTRL3	, 0x0000},
+	{RT5677_DSP_INB1_SRC_CTRL4	, 0x0800},
+	{RT5677_DSP_INB2_SRC_CTRL1	, 0x5800},
+	{RT5677_DSP_INB2_SRC_CTRL2	, 0x0000},
+	{RT5677_DSP_INB2_SRC_CTRL3	, 0x0000},
+	{RT5677_DSP_INB2_SRC_CTRL4	, 0x0800},
+	{RT5677_DSP_INB3_SRC_CTRL1	, 0x5800},
+	{RT5677_DSP_INB3_SRC_CTRL2	, 0x0000},
+	{RT5677_DSP_INB3_SRC_CTRL3	, 0x0000},
+	{RT5677_DSP_INB3_SRC_CTRL4	, 0x0800},
+	{RT5677_DSP_OUTB1_SRC_CTRL1	, 0x5800},
+	{RT5677_DSP_OUTB1_SRC_CTRL2	, 0x0000},
+	{RT5677_DSP_OUTB1_SRC_CTRL3	, 0x0000},
+	{RT5677_DSP_OUTB1_SRC_CTRL4	, 0x0800},
+	{RT5677_DSP_OUTB2_SRC_CTRL1	, 0x5800},
+	{RT5677_DSP_OUTB2_SRC_CTRL2	, 0x0000},
+	{RT5677_DSP_OUTB2_SRC_CTRL3	, 0x0000},
+	{RT5677_DSP_OUTB2_SRC_CTRL4	, 0x0800},
+	{RT5677_DSP_OUTB_0123_MIXER_CTRL, 0xfefe},
+	{RT5677_DSP_OUTB_45_MIXER_CTRL	, 0xfefe},
+	{RT5677_DSP_OUTB_67_MIXER_CTRL	, 0xfefe},
+	{RT5677_DIG_MISC		, 0x0000},
+	{RT5677_GEN_CTRL1		, 0x0000},
+	{RT5677_GEN_CTRL2		, 0x0000},
+	{RT5677_VENDOR_ID		, 0x0000},
+	{RT5677_VENDOR_ID1		, 0x10ec},
+	{RT5677_VENDOR_ID2		, 0x6327},
+};
+
+static bool rt5677_volatile_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5677_ranges); i++) {
+		if (reg >= rt5677_ranges[i].range_min &&
+			reg <= rt5677_ranges[i].range_max) {
+			return true;
+		}
+	}
+
+	switch (reg) {
+	case RT5677_RESET:
+	case RT5677_SLIMBUS_PARAM:
+	case RT5677_PDM_DATA_CTRL1:
+	case RT5677_PDM_DATA_CTRL2:
+	case RT5677_PDM1_DATA_CTRL4:
+	case RT5677_PDM2_DATA_CTRL4:
+	case RT5677_I2C_MASTER_CTRL1:
+	case RT5677_I2C_MASTER_CTRL7:
+	case RT5677_I2C_MASTER_CTRL8:
+	case RT5677_HAP_GENE_CTRL2:
+	case RT5677_PWR_DSP_ST:
+	case RT5677_PRIV_DATA:
+	case RT5677_ASRC_22:
+	case RT5677_ASRC_23:
+	case RT5677_VAD_CTRL5:
+	case RT5677_ADC_EQ_CTRL1:
+	case RT5677_EQ_CTRL1:
+	case RT5677_IRQ_CTRL1:
+	case RT5677_IRQ_CTRL2:
+	case RT5677_GPIO_ST:
+	case RT5677_DSP_INB1_SRC_CTRL4:
+	case RT5677_DSP_INB2_SRC_CTRL4:
+	case RT5677_DSP_INB3_SRC_CTRL4:
+	case RT5677_DSP_OUTB1_SRC_CTRL4:
+	case RT5677_DSP_OUTB2_SRC_CTRL4:
+	case RT5677_VENDOR_ID:
+	case RT5677_VENDOR_ID1:
+	case RT5677_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5677_readable_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5677_ranges); i++) {
+		if (reg >= rt5677_ranges[i].range_min &&
+			reg <= rt5677_ranges[i].range_max) {
+			return true;
+		}
+	}
+
+	switch (reg) {
+	case RT5677_RESET:
+	case RT5677_LOUT1:
+	case RT5677_IN1:
+	case RT5677_MICBIAS:
+	case RT5677_SLIMBUS_PARAM:
+	case RT5677_SLIMBUS_RX:
+	case RT5677_SLIMBUS_CTRL:
+	case RT5677_SIDETONE_CTRL:
+	case RT5677_ANA_DAC1_2_3_SRC:
+	case RT5677_IF_DSP_DAC3_4_MIXER:
+	case RT5677_DAC4_DIG_VOL:
+	case RT5677_DAC3_DIG_VOL:
+	case RT5677_DAC1_DIG_VOL:
+	case RT5677_DAC2_DIG_VOL:
+	case RT5677_IF_DSP_DAC2_MIXER:
+	case RT5677_STO1_ADC_DIG_VOL:
+	case RT5677_MONO_ADC_DIG_VOL:
+	case RT5677_STO1_2_ADC_BST:
+	case RT5677_STO2_ADC_DIG_VOL:
+	case RT5677_ADC_BST_CTRL2:
+	case RT5677_STO3_4_ADC_BST:
+	case RT5677_STO3_ADC_DIG_VOL:
+	case RT5677_STO4_ADC_DIG_VOL:
+	case RT5677_STO4_ADC_MIXER:
+	case RT5677_STO3_ADC_MIXER:
+	case RT5677_STO2_ADC_MIXER:
+	case RT5677_STO1_ADC_MIXER:
+	case RT5677_MONO_ADC_MIXER:
+	case RT5677_ADC_IF_DSP_DAC1_MIXER:
+	case RT5677_STO1_DAC_MIXER:
+	case RT5677_MONO_DAC_MIXER:
+	case RT5677_DD1_MIXER:
+	case RT5677_DD2_MIXER:
+	case RT5677_IF3_DATA:
+	case RT5677_IF4_DATA:
+	case RT5677_PDM_OUT_CTRL:
+	case RT5677_PDM_DATA_CTRL1:
+	case RT5677_PDM_DATA_CTRL2:
+	case RT5677_PDM1_DATA_CTRL2:
+	case RT5677_PDM1_DATA_CTRL3:
+	case RT5677_PDM1_DATA_CTRL4:
+	case RT5677_PDM2_DATA_CTRL2:
+	case RT5677_PDM2_DATA_CTRL3:
+	case RT5677_PDM2_DATA_CTRL4:
+	case RT5677_TDM1_CTRL1:
+	case RT5677_TDM1_CTRL2:
+	case RT5677_TDM1_CTRL3:
+	case RT5677_TDM1_CTRL4:
+	case RT5677_TDM1_CTRL5:
+	case RT5677_TDM2_CTRL1:
+	case RT5677_TDM2_CTRL2:
+	case RT5677_TDM2_CTRL3:
+	case RT5677_TDM2_CTRL4:
+	case RT5677_TDM2_CTRL5:
+	case RT5677_I2C_MASTER_CTRL1:
+	case RT5677_I2C_MASTER_CTRL2:
+	case RT5677_I2C_MASTER_CTRL3:
+	case RT5677_I2C_MASTER_CTRL4:
+	case RT5677_I2C_MASTER_CTRL5:
+	case RT5677_I2C_MASTER_CTRL6:
+	case RT5677_I2C_MASTER_CTRL7:
+	case RT5677_I2C_MASTER_CTRL8:
+	case RT5677_DMIC_CTRL1:
+	case RT5677_DMIC_CTRL2:
+	case RT5677_HAP_GENE_CTRL1:
+	case RT5677_HAP_GENE_CTRL2:
+	case RT5677_HAP_GENE_CTRL3:
+	case RT5677_HAP_GENE_CTRL4:
+	case RT5677_HAP_GENE_CTRL5:
+	case RT5677_HAP_GENE_CTRL6:
+	case RT5677_HAP_GENE_CTRL7:
+	case RT5677_HAP_GENE_CTRL8:
+	case RT5677_HAP_GENE_CTRL9:
+	case RT5677_HAP_GENE_CTRL10:
+	case RT5677_PWR_DIG1:
+	case RT5677_PWR_DIG2:
+	case RT5677_PWR_ANLG1:
+	case RT5677_PWR_ANLG2:
+	case RT5677_PWR_DSP1:
+	case RT5677_PWR_DSP_ST:
+	case RT5677_PWR_DSP2:
+	case RT5677_ADC_DAC_HPF_CTRL1:
+	case RT5677_PRIV_INDEX:
+	case RT5677_PRIV_DATA:
+	case RT5677_I2S4_SDP:
+	case RT5677_I2S1_SDP:
+	case RT5677_I2S2_SDP:
+	case RT5677_I2S3_SDP:
+	case RT5677_CLK_TREE_CTRL1:
+	case RT5677_CLK_TREE_CTRL2:
+	case RT5677_CLK_TREE_CTRL3:
+	case RT5677_PLL1_CTRL1:
+	case RT5677_PLL1_CTRL2:
+	case RT5677_PLL2_CTRL1:
+	case RT5677_PLL2_CTRL2:
+	case RT5677_GLB_CLK1:
+	case RT5677_GLB_CLK2:
+	case RT5677_ASRC_1:
+	case RT5677_ASRC_2:
+	case RT5677_ASRC_3:
+	case RT5677_ASRC_4:
+	case RT5677_ASRC_5:
+	case RT5677_ASRC_6:
+	case RT5677_ASRC_7:
+	case RT5677_ASRC_8:
+	case RT5677_ASRC_9:
+	case RT5677_ASRC_10:
+	case RT5677_ASRC_11:
+	case RT5677_ASRC_12:
+	case RT5677_ASRC_13:
+	case RT5677_ASRC_14:
+	case RT5677_ASRC_15:
+	case RT5677_ASRC_16:
+	case RT5677_ASRC_17:
+	case RT5677_ASRC_18:
+	case RT5677_ASRC_19:
+	case RT5677_ASRC_20:
+	case RT5677_ASRC_21:
+	case RT5677_ASRC_22:
+	case RT5677_ASRC_23:
+	case RT5677_VAD_CTRL1:
+	case RT5677_VAD_CTRL2:
+	case RT5677_VAD_CTRL3:
+	case RT5677_VAD_CTRL4:
+	case RT5677_VAD_CTRL5:
+	case RT5677_DSP_INB_CTRL1:
+	case RT5677_DSP_INB_CTRL2:
+	case RT5677_DSP_IN_OUTB_CTRL:
+	case RT5677_DSP_OUTB0_1_DIG_VOL:
+	case RT5677_DSP_OUTB2_3_DIG_VOL:
+	case RT5677_DSP_OUTB4_5_DIG_VOL:
+	case RT5677_DSP_OUTB6_7_DIG_VOL:
+	case RT5677_ADC_EQ_CTRL1:
+	case RT5677_ADC_EQ_CTRL2:
+	case RT5677_EQ_CTRL1:
+	case RT5677_EQ_CTRL2:
+	case RT5677_EQ_CTRL3:
+	case RT5677_SOFT_VOL_ZERO_CROSS1:
+	case RT5677_JD_CTRL1:
+	case RT5677_JD_CTRL2:
+	case RT5677_JD_CTRL3:
+	case RT5677_IRQ_CTRL1:
+	case RT5677_IRQ_CTRL2:
+	case RT5677_GPIO_ST:
+	case RT5677_GPIO_CTRL1:
+	case RT5677_GPIO_CTRL2:
+	case RT5677_GPIO_CTRL3:
+	case RT5677_STO1_ADC_HI_FILTER1:
+	case RT5677_STO1_ADC_HI_FILTER2:
+	case RT5677_MONO_ADC_HI_FILTER1:
+	case RT5677_MONO_ADC_HI_FILTER2:
+	case RT5677_STO2_ADC_HI_FILTER1:
+	case RT5677_STO2_ADC_HI_FILTER2:
+	case RT5677_STO3_ADC_HI_FILTER1:
+	case RT5677_STO3_ADC_HI_FILTER2:
+	case RT5677_STO4_ADC_HI_FILTER1:
+	case RT5677_STO4_ADC_HI_FILTER2:
+	case RT5677_MB_DRC_CTRL1:
+	case RT5677_DRC1_CTRL1:
+	case RT5677_DRC1_CTRL2:
+	case RT5677_DRC1_CTRL3:
+	case RT5677_DRC1_CTRL4:
+	case RT5677_DRC1_CTRL5:
+	case RT5677_DRC1_CTRL6:
+	case RT5677_DRC2_CTRL1:
+	case RT5677_DRC2_CTRL2:
+	case RT5677_DRC2_CTRL3:
+	case RT5677_DRC2_CTRL4:
+	case RT5677_DRC2_CTRL5:
+	case RT5677_DRC2_CTRL6:
+	case RT5677_DRC1_HL_CTRL1:
+	case RT5677_DRC1_HL_CTRL2:
+	case RT5677_DRC2_HL_CTRL1:
+	case RT5677_DRC2_HL_CTRL2:
+	case RT5677_DSP_INB1_SRC_CTRL1:
+	case RT5677_DSP_INB1_SRC_CTRL2:
+	case RT5677_DSP_INB1_SRC_CTRL3:
+	case RT5677_DSP_INB1_SRC_CTRL4:
+	case RT5677_DSP_INB2_SRC_CTRL1:
+	case RT5677_DSP_INB2_SRC_CTRL2:
+	case RT5677_DSP_INB2_SRC_CTRL3:
+	case RT5677_DSP_INB2_SRC_CTRL4:
+	case RT5677_DSP_INB3_SRC_CTRL1:
+	case RT5677_DSP_INB3_SRC_CTRL2:
+	case RT5677_DSP_INB3_SRC_CTRL3:
+	case RT5677_DSP_INB3_SRC_CTRL4:
+	case RT5677_DSP_OUTB1_SRC_CTRL1:
+	case RT5677_DSP_OUTB1_SRC_CTRL2:
+	case RT5677_DSP_OUTB1_SRC_CTRL3:
+	case RT5677_DSP_OUTB1_SRC_CTRL4:
+	case RT5677_DSP_OUTB2_SRC_CTRL1:
+	case RT5677_DSP_OUTB2_SRC_CTRL2:
+	case RT5677_DSP_OUTB2_SRC_CTRL3:
+	case RT5677_DSP_OUTB2_SRC_CTRL4:
+	case RT5677_DSP_OUTB_0123_MIXER_CTRL:
+	case RT5677_DSP_OUTB_45_MIXER_CTRL:
+	case RT5677_DSP_OUTB_67_MIXER_CTRL:
+	case RT5677_DIG_MISC:
+	case RT5677_GEN_CTRL1:
+	case RT5677_GEN_CTRL2:
+	case RT5677_VENDOR_ID:
+	case RT5677_VENDOR_ID1:
+	case RT5677_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/**
+ * rt5677_dsp_mode_i2c_write_addr - Write value to address on DSP mode.
+ * @rt5677: Private Data.
+ * @addr: Address index.
+ * @value: Address data.
+ *
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677,
+		unsigned int addr, unsigned int value, unsigned int opcode)
+{
+	struct snd_soc_component *component = rt5677->component;
+	int ret;
+
+	mutex_lock(&rt5677->dsp_cmd_lock);
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB,
+		addr >> 16);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set addr msb value: %d\n", ret);
+		goto err;
+	}
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB,
+		addr & 0xffff);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set addr lsb value: %d\n", ret);
+		goto err;
+	}
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB,
+		value >> 16);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set data msb value: %d\n", ret);
+		goto err;
+	}
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB,
+		value & 0xffff);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set data lsb value: %d\n", ret);
+		goto err;
+	}
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE,
+		opcode);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set op code value: %d\n", ret);
+		goto err;
+	}
+
+err:
+	mutex_unlock(&rt5677->dsp_cmd_lock);
+
+	return ret;
+}
+
+/**
+ * rt5677_dsp_mode_i2c_read_addr - Read value from address on DSP mode.
+ * rt5677: Private Data.
+ * @addr: Address index.
+ * @value: Address data.
+ *
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5677_dsp_mode_i2c_read_addr(
+	struct rt5677_priv *rt5677, unsigned int addr, unsigned int *value)
+{
+	struct snd_soc_component *component = rt5677->component;
+	int ret;
+	unsigned int msb, lsb;
+
+	mutex_lock(&rt5677->dsp_cmd_lock);
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB,
+		addr >> 16);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set addr msb value: %d\n", ret);
+		goto err;
+	}
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB,
+		addr & 0xffff);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set addr lsb value: %d\n", ret);
+		goto err;
+	}
+
+	ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE,
+		0x0002);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set op code value: %d\n", ret);
+		goto err;
+	}
+
+	regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, &msb);
+	regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, &lsb);
+	*value = (msb << 16) | lsb;
+
+err:
+	mutex_unlock(&rt5677->dsp_cmd_lock);
+
+	return ret;
+}
+
+/**
+ * rt5677_dsp_mode_i2c_write - Write register on DSP mode.
+ * rt5677: Private Data.
+ * @reg: Register index.
+ * @value: Register data.
+ *
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5677_dsp_mode_i2c_write(struct rt5677_priv *rt5677,
+		unsigned int reg, unsigned int value)
+{
+	return rt5677_dsp_mode_i2c_write_addr(rt5677, 0x18020000 + reg * 2,
+		value, 0x0001);
+}
+
+/**
+ * rt5677_dsp_mode_i2c_read - Read register on DSP mode.
+ * @codec: SoC audio codec device.
+ * @reg: Register index.
+ * @value: Register data.
+ *
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5677_dsp_mode_i2c_read(
+	struct rt5677_priv *rt5677, unsigned int reg, unsigned int *value)
+{
+	int ret = rt5677_dsp_mode_i2c_read_addr(rt5677, 0x18020000 + reg * 2,
+		value);
+
+	*value &= 0xffff;
+
+	return ret;
+}
+
+static void rt5677_set_dsp_mode(struct snd_soc_component *component, bool on)
+{
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+
+	if (on) {
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x2);
+		rt5677->is_dsp_mode = true;
+	} else {
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x0);
+		rt5677->is_dsp_mode = false;
+	}
+}
+
+static int rt5677_set_dsp_vad(struct snd_soc_component *component, bool on)
+{
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+	static bool activity;
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_SND_SOC_RT5677_SPI))
+		return -ENXIO;
+
+	if (on && !activity) {
+		activity = true;
+
+		regcache_cache_only(rt5677->regmap, false);
+		regcache_cache_bypass(rt5677->regmap, true);
+
+		regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x1);
+		regmap_update_bits(rt5677->regmap,
+			RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0f00);
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
+			RT5677_LDO1_SEL_MASK, 0x0);
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
+			RT5677_PWR_LDO1, RT5677_PWR_LDO1);
+		switch (rt5677->type) {
+		case RT5677:
+			regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
+				RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC);
+			regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2,
+				RT5677_PLL2_PR_SRC_MASK |
+				RT5677_DSP_CLK_SRC_MASK,
+				RT5677_PLL2_PR_SRC_MCLK2 |
+				RT5677_DSP_CLK_SRC_BYPASS);
+			break;
+		case RT5676:
+			regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2,
+				RT5677_DSP_CLK_SRC_MASK,
+				RT5677_DSP_CLK_SRC_BYPASS);
+			break;
+		default:
+			break;
+		}
+		regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff);
+		regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd);
+		rt5677_set_dsp_mode(component, true);
+
+		ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1,
+			component->dev);
+		if (ret == 0) {
+			rt5677_spi_write_firmware(0x50000000, rt5677->fw1);
+			release_firmware(rt5677->fw1);
+		}
+
+		ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2,
+			component->dev);
+		if (ret == 0) {
+			rt5677_spi_write_firmware(0x60000000, rt5677->fw2);
+			release_firmware(rt5677->fw2);
+		}
+
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x0);
+
+		regcache_cache_bypass(rt5677->regmap, false);
+		regcache_cache_only(rt5677->regmap, true);
+	} else if (!on && activity) {
+		activity = false;
+
+		regcache_cache_only(rt5677->regmap, false);
+		regcache_cache_bypass(rt5677->regmap, true);
+
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x1);
+		rt5677_set_dsp_mode(component, false);
+		regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x0001);
+
+		regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
+
+		regcache_cache_bypass(rt5677->regmap, false);
+		regcache_mark_dirty(rt5677->regmap);
+		regcache_sync(rt5677->regmap);
+	}
+
+	return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+static int rt5677_dsp_vad_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = rt5677->dsp_vad_en;
+
+	return 0;
+}
+
+static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+
+	rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0];
+
+	if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+		rt5677_set_dsp_vad(component, rt5677->dsp_vad_en);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new rt5677_snd_controls[] = {
+	/* OUTPUT Control */
+	SOC_SINGLE("OUT1 Playback Switch", RT5677_LOUT1,
+		RT5677_LOUT1_L_MUTE_SFT, 1, 1),
+	SOC_SINGLE("OUT2 Playback Switch", RT5677_LOUT1,
+		RT5677_LOUT2_L_MUTE_SFT, 1, 1),
+	SOC_SINGLE("OUT3 Playback Switch", RT5677_LOUT1,
+		RT5677_LOUT3_L_MUTE_SFT, 1, 1),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5677_DAC1_DIG_VOL,
+		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
+	SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5677_DAC2_DIG_VOL,
+		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
+	SOC_DOUBLE_TLV("DAC3 Playback Volume", RT5677_DAC3_DIG_VOL,
+		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
+	SOC_DOUBLE_TLV("DAC4 Playback Volume", RT5677_DAC4_DIG_VOL,
+		RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
+
+	/* IN1/IN2 Control */
+	SOC_SINGLE_TLV("IN1 Boost", RT5677_IN1, RT5677_BST_SFT1, 8, 0, bst_tlv),
+	SOC_SINGLE_TLV("IN2 Boost", RT5677_IN1, RT5677_BST_SFT2, 8, 0, bst_tlv),
+
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("ADC1 Capture Switch", RT5677_STO1_ADC_DIG_VOL,
+		RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE("ADC2 Capture Switch", RT5677_STO2_ADC_DIG_VOL,
+		RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE("ADC3 Capture Switch", RT5677_STO3_ADC_DIG_VOL,
+		RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE("ADC4 Capture Switch", RT5677_STO4_ADC_DIG_VOL,
+		RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE("Mono ADC Capture Switch", RT5677_MONO_ADC_DIG_VOL,
+		RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1),
+
+	SOC_DOUBLE_TLV("ADC1 Capture Volume", RT5677_STO1_ADC_DIG_VOL,
+		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
+		adc_vol_tlv),
+	SOC_DOUBLE_TLV("ADC2 Capture Volume", RT5677_STO2_ADC_DIG_VOL,
+		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
+		adc_vol_tlv),
+	SOC_DOUBLE_TLV("ADC3 Capture Volume", RT5677_STO3_ADC_DIG_VOL,
+		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
+		adc_vol_tlv),
+	SOC_DOUBLE_TLV("ADC4 Capture Volume", RT5677_STO4_ADC_DIG_VOL,
+		RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
+		adc_vol_tlv),
+	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5677_MONO_ADC_DIG_VOL,
+		RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 63, 0,
+		adc_vol_tlv),
+
+	/* Sidetone Control */
+	SOC_SINGLE_TLV("Sidetone Volume", RT5677_SIDETONE_CTRL,
+		RT5677_ST_VOL_SFT, 31, 0, st_vol_tlv),
+
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("STO1 ADC Boost Volume", RT5677_STO1_2_ADC_BST,
+		RT5677_STO1_ADC_L_BST_SFT, RT5677_STO1_ADC_R_BST_SFT, 3, 0,
+		adc_bst_tlv),
+	SOC_DOUBLE_TLV("STO2 ADC Boost Volume", RT5677_STO1_2_ADC_BST,
+		RT5677_STO2_ADC_L_BST_SFT, RT5677_STO2_ADC_R_BST_SFT, 3, 0,
+		adc_bst_tlv),
+	SOC_DOUBLE_TLV("STO3 ADC Boost Volume", RT5677_STO3_4_ADC_BST,
+		RT5677_STO3_ADC_L_BST_SFT, RT5677_STO3_ADC_R_BST_SFT, 3, 0,
+		adc_bst_tlv),
+	SOC_DOUBLE_TLV("STO4 ADC Boost Volume", RT5677_STO3_4_ADC_BST,
+		RT5677_STO4_ADC_L_BST_SFT, RT5677_STO4_ADC_R_BST_SFT, 3, 0,
+		adc_bst_tlv),
+	SOC_DOUBLE_TLV("Mono ADC Boost Volume", RT5677_ADC_BST_CTRL2,
+		RT5677_MONO_ADC_L_BST_SFT, RT5677_MONO_ADC_R_BST_SFT, 3, 0,
+		adc_bst_tlv),
+
+	SOC_SINGLE_EXT("DSP VAD Switch", SND_SOC_NOPM, 0, 1, 0,
+		rt5677_dsp_vad_get, rt5677_dsp_vad_put),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+	int idx, rate;
+
+	rate = rt5677->sysclk / rl6231_get_pre_div(rt5677->regmap,
+		RT5677_CLK_TREE_CTRL1, RT5677_I2S_PD1_SFT);
+	idx = rl6231_calc_dmic_clk(rate);
+	if (idx < 0)
+		dev_err(component->dev, "Failed to set DMIC clock\n");
+	else
+		regmap_update_bits(rt5677->regmap, RT5677_DMIC_CTRL1,
+			RT5677_DMIC_CLK_MASK, idx << RT5677_DMIC_CLK_SFT);
+	return idx;
+}
+
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	regmap_read(rt5677->regmap, RT5677_GLB_CLK1, &val);
+	val &= RT5677_SCLK_SRC_MASK;
+	if (val == RT5677_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int is_using_asrc(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+	unsigned int reg, shift, val;
+
+	if (source->reg == RT5677_ASRC_1) {
+		switch (source->shift) {
+		case 12:
+			reg = RT5677_ASRC_4;
+			shift = 0;
+			break;
+		case 13:
+			reg = RT5677_ASRC_4;
+			shift = 4;
+			break;
+		case 14:
+			reg = RT5677_ASRC_4;
+			shift = 8;
+			break;
+		case 15:
+			reg = RT5677_ASRC_4;
+			shift = 12;
+			break;
+		default:
+			return 0;
+		}
+	} else {
+		switch (source->shift) {
+		case 0:
+			reg = RT5677_ASRC_6;
+			shift = 8;
+			break;
+		case 1:
+			reg = RT5677_ASRC_6;
+			shift = 12;
+			break;
+		case 2:
+			reg = RT5677_ASRC_5;
+			shift = 0;
+			break;
+		case 3:
+			reg = RT5677_ASRC_5;
+			shift = 4;
+			break;
+		case 4:
+			reg = RT5677_ASRC_5;
+			shift = 8;
+			break;
+		case 5:
+			reg = RT5677_ASRC_5;
+			shift = 12;
+			break;
+		case 12:
+			reg = RT5677_ASRC_3;
+			shift = 0;
+			break;
+		case 13:
+			reg = RT5677_ASRC_3;
+			shift = 4;
+			break;
+		case 14:
+			reg = RT5677_ASRC_3;
+			shift = 12;
+			break;
+		default:
+			return 0;
+		}
+	}
+
+	regmap_read(rt5677->regmap, reg, &val);
+	val = (val >> shift) & 0xf;
+
+	switch (val) {
+	case 1 ... 6:
+		return 1;
+	default:
+		return 0;
+	}
+
+}
+
+static int can_use_asrc(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+
+	if (rt5677->sysclk > rt5677->lrck[RT5677_AIF1] * 384)
+		return 1;
+
+	return 0;
+}
+
+/**
+ * rt5677_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @component: SoC audio component device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5677 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5677_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src)
+{
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+	unsigned int asrc3_mask = 0, asrc3_value = 0;
+	unsigned int asrc4_mask = 0, asrc4_value = 0;
+	unsigned int asrc5_mask = 0, asrc5_value = 0;
+	unsigned int asrc6_mask = 0, asrc6_value = 0;
+	unsigned int asrc7_mask = 0, asrc7_value = 0;
+	unsigned int asrc8_mask = 0, asrc8_value = 0;
+
+	switch (clk_src) {
+	case RT5677_CLK_SEL_SYS:
+	case RT5677_CLK_SEL_I2S1_ASRC:
+	case RT5677_CLK_SEL_I2S2_ASRC:
+	case RT5677_CLK_SEL_I2S3_ASRC:
+	case RT5677_CLK_SEL_I2S4_ASRC:
+	case RT5677_CLK_SEL_I2S5_ASRC:
+	case RT5677_CLK_SEL_I2S6_ASRC:
+	case RT5677_CLK_SEL_SYS2:
+	case RT5677_CLK_SEL_SYS3:
+	case RT5677_CLK_SEL_SYS4:
+	case RT5677_CLK_SEL_SYS5:
+	case RT5677_CLK_SEL_SYS6:
+	case RT5677_CLK_SEL_SYS7:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* ASRC 3 */
+	if (filter_mask & RT5677_DA_STEREO_FILTER) {
+		asrc3_mask |= RT5677_DA_STO_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5677_DA_STO_CLK_SEL_MASK)
+			| (clk_src << RT5677_DA_STO_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_DA_MONO2_L_FILTER) {
+		asrc3_mask |= RT5677_DA_MONO2L_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5677_DA_MONO2L_CLK_SEL_MASK)
+			| (clk_src << RT5677_DA_MONO2L_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_DA_MONO2_R_FILTER) {
+		asrc3_mask |= RT5677_DA_MONO2R_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5677_DA_MONO2R_CLK_SEL_MASK)
+			| (clk_src << RT5677_DA_MONO2R_CLK_SEL_SFT);
+	}
+
+	if (asrc3_mask)
+		regmap_update_bits(rt5677->regmap, RT5677_ASRC_3, asrc3_mask,
+			asrc3_value);
+
+	/* ASRC 4 */
+	if (filter_mask & RT5677_DA_MONO3_L_FILTER) {
+		asrc4_mask |= RT5677_DA_MONO3L_CLK_SEL_MASK;
+		asrc4_value = (asrc4_value & ~RT5677_DA_MONO3L_CLK_SEL_MASK)
+			| (clk_src << RT5677_DA_MONO3L_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_DA_MONO3_R_FILTER) {
+		asrc4_mask |= RT5677_DA_MONO3R_CLK_SEL_MASK;
+		asrc4_value = (asrc4_value & ~RT5677_DA_MONO3R_CLK_SEL_MASK)
+			| (clk_src << RT5677_DA_MONO3R_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_DA_MONO4_L_FILTER) {
+		asrc4_mask |= RT5677_DA_MONO4L_CLK_SEL_MASK;
+		asrc4_value = (asrc4_value & ~RT5677_DA_MONO4L_CLK_SEL_MASK)
+			| (clk_src << RT5677_DA_MONO4L_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_DA_MONO4_R_FILTER) {
+		asrc4_mask |= RT5677_DA_MONO4R_CLK_SEL_MASK;
+		asrc4_value = (asrc4_value & ~RT5677_DA_MONO4R_CLK_SEL_MASK)
+			| (clk_src << RT5677_DA_MONO4R_CLK_SEL_SFT);
+	}
+
+	if (asrc4_mask)
+		regmap_update_bits(rt5677->regmap, RT5677_ASRC_4, asrc4_mask,
+			asrc4_value);
+
+	/* ASRC 5 */
+	if (filter_mask & RT5677_AD_STEREO1_FILTER) {
+		asrc5_mask |= RT5677_AD_STO1_CLK_SEL_MASK;
+		asrc5_value = (asrc5_value & ~RT5677_AD_STO1_CLK_SEL_MASK)
+			| (clk_src << RT5677_AD_STO1_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_AD_STEREO2_FILTER) {
+		asrc5_mask |= RT5677_AD_STO2_CLK_SEL_MASK;
+		asrc5_value = (asrc5_value & ~RT5677_AD_STO2_CLK_SEL_MASK)
+			| (clk_src << RT5677_AD_STO2_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_AD_STEREO3_FILTER) {
+		asrc5_mask |= RT5677_AD_STO3_CLK_SEL_MASK;
+		asrc5_value = (asrc5_value & ~RT5677_AD_STO3_CLK_SEL_MASK)
+			| (clk_src << RT5677_AD_STO3_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_AD_STEREO4_FILTER) {
+		asrc5_mask |= RT5677_AD_STO4_CLK_SEL_MASK;
+		asrc5_value = (asrc5_value & ~RT5677_AD_STO4_CLK_SEL_MASK)
+			| (clk_src << RT5677_AD_STO4_CLK_SEL_SFT);
+	}
+
+	if (asrc5_mask)
+		regmap_update_bits(rt5677->regmap, RT5677_ASRC_5, asrc5_mask,
+			asrc5_value);
+
+	/* ASRC 6 */
+	if (filter_mask & RT5677_AD_MONO_L_FILTER) {
+		asrc6_mask |= RT5677_AD_MONOL_CLK_SEL_MASK;
+		asrc6_value = (asrc6_value & ~RT5677_AD_MONOL_CLK_SEL_MASK)
+			| (clk_src << RT5677_AD_MONOL_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_AD_MONO_R_FILTER) {
+		asrc6_mask |= RT5677_AD_MONOR_CLK_SEL_MASK;
+		asrc6_value = (asrc6_value & ~RT5677_AD_MONOR_CLK_SEL_MASK)
+			| (clk_src << RT5677_AD_MONOR_CLK_SEL_SFT);
+	}
+
+	if (asrc6_mask)
+		regmap_update_bits(rt5677->regmap, RT5677_ASRC_6, asrc6_mask,
+			asrc6_value);
+
+	/* ASRC 7 */
+	if (filter_mask & RT5677_DSP_OB_0_3_FILTER) {
+		asrc7_mask |= RT5677_DSP_OB_0_3_CLK_SEL_MASK;
+		asrc7_value = (asrc7_value & ~RT5677_DSP_OB_0_3_CLK_SEL_MASK)
+			| (clk_src << RT5677_DSP_OB_0_3_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_DSP_OB_4_7_FILTER) {
+		asrc7_mask |= RT5677_DSP_OB_4_7_CLK_SEL_MASK;
+		asrc7_value = (asrc7_value & ~RT5677_DSP_OB_4_7_CLK_SEL_MASK)
+			| (clk_src << RT5677_DSP_OB_4_7_CLK_SEL_SFT);
+	}
+
+	if (asrc7_mask)
+		regmap_update_bits(rt5677->regmap, RT5677_ASRC_7, asrc7_mask,
+			asrc7_value);
+
+	/* ASRC 8 */
+	if (filter_mask & RT5677_I2S1_SOURCE) {
+		asrc8_mask |= RT5677_I2S1_CLK_SEL_MASK;
+		asrc8_value = (asrc8_value & ~RT5677_I2S1_CLK_SEL_MASK)
+			| ((clk_src - 1) << RT5677_I2S1_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_I2S2_SOURCE) {
+		asrc8_mask |= RT5677_I2S2_CLK_SEL_MASK;
+		asrc8_value = (asrc8_value & ~RT5677_I2S2_CLK_SEL_MASK)
+			| ((clk_src - 1) << RT5677_I2S2_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_I2S3_SOURCE) {
+		asrc8_mask |= RT5677_I2S3_CLK_SEL_MASK;
+		asrc8_value = (asrc8_value & ~RT5677_I2S3_CLK_SEL_MASK)
+			| ((clk_src - 1) << RT5677_I2S3_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5677_I2S4_SOURCE) {
+		asrc8_mask |= RT5677_I2S4_CLK_SEL_MASK;
+		asrc8_value = (asrc8_value & ~RT5677_I2S4_CLK_SEL_MASK)
+			| ((clk_src - 1) << RT5677_I2S4_CLK_SEL_SFT);
+	}
+
+	if (asrc8_mask)
+		regmap_update_bits(rt5677->regmap, RT5677_ASRC_8, asrc8_mask,
+			asrc8_value);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5677_sel_asrc_clk_src);
+
+static int rt5677_dmic_use_asrc(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+	unsigned int asrc_setting;
+
+	switch (source->shift) {
+	case 11:
+		regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+		asrc_setting = (asrc_setting & RT5677_AD_STO1_CLK_SEL_MASK) >>
+				RT5677_AD_STO1_CLK_SEL_SFT;
+		break;
+
+	case 10:
+		regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+		asrc_setting = (asrc_setting & RT5677_AD_STO2_CLK_SEL_MASK) >>
+				RT5677_AD_STO2_CLK_SEL_SFT;
+		break;
+
+	case 9:
+		regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+		asrc_setting = (asrc_setting & RT5677_AD_STO3_CLK_SEL_MASK) >>
+				RT5677_AD_STO3_CLK_SEL_SFT;
+		break;
+
+	case 8:
+		regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+		asrc_setting = (asrc_setting & RT5677_AD_STO4_CLK_SEL_MASK) >>
+			RT5677_AD_STO4_CLK_SEL_SFT;
+		break;
+
+	case 7:
+		regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting);
+		asrc_setting = (asrc_setting & RT5677_AD_MONOL_CLK_SEL_MASK) >>
+			RT5677_AD_MONOL_CLK_SEL_SFT;
+		break;
+
+	case 6:
+		regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting);
+		asrc_setting = (asrc_setting & RT5677_AD_MONOR_CLK_SEL_MASK) >>
+			RT5677_AD_MONOR_CLK_SEL_SFT;
+		break;
+
+	default:
+		return 0;
+	}
+
+	if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+	    asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+		return 1;
+
+	return 0;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER,
+			RT5677_M_STO1_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO1_ADC_MIXER,
+			RT5677_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER,
+			RT5677_M_STO1_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO1_ADC_MIXER,
+			RT5677_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_sto2_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO2_ADC_MIXER,
+			RT5677_M_STO2_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO2_ADC_MIXER,
+			RT5677_M_STO2_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_sto2_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO2_ADC_MIXER,
+			RT5677_M_STO2_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO2_ADC_MIXER,
+			RT5677_M_STO2_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_sto3_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO3_ADC_MIXER,
+			RT5677_M_STO3_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO3_ADC_MIXER,
+			RT5677_M_STO3_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_sto3_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO3_ADC_MIXER,
+			RT5677_M_STO3_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO3_ADC_MIXER,
+			RT5677_M_STO3_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_sto4_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO4_ADC_MIXER,
+			RT5677_M_STO4_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO4_ADC_MIXER,
+			RT5677_M_STO4_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_sto4_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO4_ADC_MIXER,
+			RT5677_M_STO4_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_STO4_ADC_MIXER,
+			RT5677_M_STO4_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_mono_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_MONO_ADC_MIXER,
+			RT5677_M_MONO_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_MONO_ADC_MIXER,
+			RT5677_M_MONO_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_mono_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5677_MONO_ADC_MIXER,
+			RT5677_M_MONO_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5677_MONO_ADC_MIXER,
+			RT5677_M_MONO_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5677_ADC_IF_DSP_DAC1_MIXER,
+			RT5677_M_ADDA_MIXER1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5677_ADC_IF_DSP_DAC1_MIXER,
+			RT5677_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5677_ADC_IF_DSP_DAC1_MIXER,
+			RT5677_M_ADDA_MIXER1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5677_ADC_IF_DSP_DAC1_MIXER,
+			RT5677_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_sto1_dac_l_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ST L Switch", RT5677_STO1_DAC_MIXER,
+			RT5677_M_ST_DAC1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER,
+			RT5677_M_DAC1_L_STO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC2 L Switch", RT5677_STO1_DAC_MIXER,
+			RT5677_M_DAC2_L_STO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER,
+			RT5677_M_DAC1_R_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_sto1_dac_r_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ST R Switch", RT5677_STO1_DAC_MIXER,
+			RT5677_M_ST_DAC1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER,
+			RT5677_M_DAC1_R_STO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC2 R Switch", RT5677_STO1_DAC_MIXER,
+			RT5677_M_DAC2_R_STO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER,
+			RT5677_M_DAC1_L_STO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_mono_dac_l_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ST L Switch", RT5677_MONO_DAC_MIXER,
+			RT5677_M_ST_DAC2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC1 L Switch", RT5677_MONO_DAC_MIXER,
+			RT5677_M_DAC1_L_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER,
+			RT5677_M_DAC2_L_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER,
+			RT5677_M_DAC2_R_MONO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_mono_dac_r_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("ST R Switch", RT5677_MONO_DAC_MIXER,
+			RT5677_M_ST_DAC2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC1 R Switch", RT5677_MONO_DAC_MIXER,
+			RT5677_M_DAC1_R_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER,
+			RT5677_M_DAC2_R_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER,
+			RT5677_M_DAC2_L_MONO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_dd1_l_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix L Switch", RT5677_DD1_MIXER,
+			RT5677_M_STO_L_DD1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix L Switch", RT5677_DD1_MIXER,
+			RT5677_M_MONO_L_DD1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC3 L Switch", RT5677_DD1_MIXER,
+			RT5677_M_DAC3_L_DD1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC3 R Switch", RT5677_DD1_MIXER,
+			RT5677_M_DAC3_R_DD1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_dd1_r_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix R Switch", RT5677_DD1_MIXER,
+			RT5677_M_STO_R_DD1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix R Switch", RT5677_DD1_MIXER,
+			RT5677_M_MONO_R_DD1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC3 R Switch", RT5677_DD1_MIXER,
+			RT5677_M_DAC3_R_DD1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC3 L Switch", RT5677_DD1_MIXER,
+			RT5677_M_DAC3_L_DD1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_dd2_l_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix L Switch", RT5677_DD2_MIXER,
+			RT5677_M_STO_L_DD2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix L Switch", RT5677_DD2_MIXER,
+			RT5677_M_MONO_L_DD2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC4 L Switch", RT5677_DD2_MIXER,
+			RT5677_M_DAC4_L_DD2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC4 R Switch", RT5677_DD2_MIXER,
+			RT5677_M_DAC4_R_DD2_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_dd2_r_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix R Switch", RT5677_DD2_MIXER,
+			RT5677_M_STO_R_DD2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix R Switch", RT5677_DD2_MIXER,
+			RT5677_M_MONO_R_DD2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC4 R Switch", RT5677_DD2_MIXER,
+			RT5677_M_DAC4_R_DD2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE_AUTODISABLE("DAC4 L Switch", RT5677_DD2_MIXER,
+			RT5677_M_DAC4_L_DD2_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_ob_01_mix[] = {
+	SOC_DAPM_SINGLE("IB01 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL,
+			RT5677_DSP_IB_01_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB23 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL,
+			RT5677_DSP_IB_23_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB45 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL,
+			RT5677_DSP_IB_45_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB6 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL,
+			RT5677_DSP_IB_6_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB7 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL,
+			RT5677_DSP_IB_7_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB8 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL,
+			RT5677_DSP_IB_8_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB9 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL,
+			RT5677_DSP_IB_9_H_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_ob_23_mix[] = {
+	SOC_DAPM_SINGLE("IB01 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL,
+			RT5677_DSP_IB_01_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB23 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL,
+			RT5677_DSP_IB_23_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB45 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL,
+			RT5677_DSP_IB_45_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB6 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL,
+			RT5677_DSP_IB_6_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB7 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL,
+			RT5677_DSP_IB_7_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB8 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL,
+			RT5677_DSP_IB_8_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB9 Switch", RT5677_DSP_OUTB_0123_MIXER_CTRL,
+			RT5677_DSP_IB_9_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_ob_4_mix[] = {
+	SOC_DAPM_SINGLE("IB01 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL,
+			RT5677_DSP_IB_01_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB23 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL,
+			RT5677_DSP_IB_23_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB45 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL,
+			RT5677_DSP_IB_45_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB6 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL,
+			RT5677_DSP_IB_6_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB7 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL,
+			RT5677_DSP_IB_7_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB8 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL,
+			RT5677_DSP_IB_8_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB9 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL,
+			RT5677_DSP_IB_9_H_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_ob_5_mix[] = {
+	SOC_DAPM_SINGLE("IB01 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL,
+			RT5677_DSP_IB_01_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB23 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL,
+			RT5677_DSP_IB_23_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB45 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL,
+			RT5677_DSP_IB_45_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB6 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL,
+			RT5677_DSP_IB_6_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB7 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL,
+			RT5677_DSP_IB_7_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB8 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL,
+			RT5677_DSP_IB_8_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB9 Switch", RT5677_DSP_OUTB_45_MIXER_CTRL,
+			RT5677_DSP_IB_9_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_ob_6_mix[] = {
+	SOC_DAPM_SINGLE("IB01 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL,
+			RT5677_DSP_IB_01_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB23 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL,
+			RT5677_DSP_IB_23_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB45 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL,
+			RT5677_DSP_IB_45_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB6 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL,
+			RT5677_DSP_IB_6_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB7 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL,
+			RT5677_DSP_IB_7_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB8 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL,
+			RT5677_DSP_IB_8_H_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB9 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL,
+			RT5677_DSP_IB_9_H_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5677_ob_7_mix[] = {
+	SOC_DAPM_SINGLE("IB01 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL,
+			RT5677_DSP_IB_01_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB23 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL,
+			RT5677_DSP_IB_23_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB45 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL,
+			RT5677_DSP_IB_45_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB6 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL,
+			RT5677_DSP_IB_6_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB7 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL,
+			RT5677_DSP_IB_7_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB8 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL,
+			RT5677_DSP_IB_8_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("IB9 Switch", RT5677_DSP_OUTB_67_MIXER_CTRL,
+			RT5677_DSP_IB_9_L_SFT, 1, 1),
+};
+
+
+/* Mux */
+/* DAC1 L/R Source */ /* MX-29 [10:8] */
+static const char * const rt5677_dac1_src[] = {
+	"IF1 DAC 01", "IF2 DAC 01", "IF3 DAC LR", "IF4 DAC LR", "SLB DAC 01",
+	"OB 01"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_dac1_enum, RT5677_ADC_IF_DSP_DAC1_MIXER,
+	RT5677_DAC1_L_SEL_SFT, rt5677_dac1_src);
+
+static const struct snd_kcontrol_new rt5677_dac1_mux =
+	SOC_DAPM_ENUM("DAC1 Source", rt5677_dac1_enum);
+
+/* ADDA1 L/R Source */ /* MX-29 [1:0] */
+static const char * const rt5677_adda1_src[] = {
+	"STO1 ADC MIX", "STO2 ADC MIX", "OB 67",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_adda1_enum, RT5677_ADC_IF_DSP_DAC1_MIXER,
+	RT5677_ADDA1_SEL_SFT, rt5677_adda1_src);
+
+static const struct snd_kcontrol_new rt5677_adda1_mux =
+	SOC_DAPM_ENUM("ADDA1 Source", rt5677_adda1_enum);
+
+
+/*DAC2 L/R Source*/ /* MX-1B [6:4] [2:0] */
+static const char * const rt5677_dac2l_src[] = {
+	"IF1 DAC 2", "IF2 DAC 2", "IF3 DAC L", "IF4 DAC L", "SLB DAC 2",
+	"OB 2",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_dac2l_enum, RT5677_IF_DSP_DAC2_MIXER,
+	RT5677_SEL_DAC2_L_SRC_SFT, rt5677_dac2l_src);
+
+static const struct snd_kcontrol_new rt5677_dac2_l_mux =
+	SOC_DAPM_ENUM("DAC2 L Source", rt5677_dac2l_enum);
+
+static const char * const rt5677_dac2r_src[] = {
+	"IF1 DAC 3", "IF2 DAC 3", "IF3 DAC R", "IF4 DAC R", "SLB DAC 3",
+	"OB 3", "Haptic Generator", "VAD ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_dac2r_enum, RT5677_IF_DSP_DAC2_MIXER,
+	RT5677_SEL_DAC2_R_SRC_SFT, rt5677_dac2r_src);
+
+static const struct snd_kcontrol_new rt5677_dac2_r_mux =
+	SOC_DAPM_ENUM("DAC2 R Source", rt5677_dac2r_enum);
+
+/*DAC3 L/R Source*/ /* MX-16 [6:4] [2:0] */
+static const char * const rt5677_dac3l_src[] = {
+	"IF1 DAC 4", "IF2 DAC 4", "IF3 DAC L", "IF4 DAC L",
+	"SLB DAC 4", "OB 4"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_dac3l_enum, RT5677_IF_DSP_DAC3_4_MIXER,
+	RT5677_SEL_DAC3_L_SRC_SFT, rt5677_dac3l_src);
+
+static const struct snd_kcontrol_new rt5677_dac3_l_mux =
+	SOC_DAPM_ENUM("DAC3 L Source", rt5677_dac3l_enum);
+
+static const char * const rt5677_dac3r_src[] = {
+	"IF1 DAC 5", "IF2 DAC 5", "IF3 DAC R", "IF4 DAC R",
+	"SLB DAC 5", "OB 5"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_dac3r_enum, RT5677_IF_DSP_DAC3_4_MIXER,
+	RT5677_SEL_DAC3_R_SRC_SFT, rt5677_dac3r_src);
+
+static const struct snd_kcontrol_new rt5677_dac3_r_mux =
+	SOC_DAPM_ENUM("DAC3 R Source", rt5677_dac3r_enum);
+
+/*DAC4 L/R Source*/ /* MX-16 [14:12] [10:8] */
+static const char * const rt5677_dac4l_src[] = {
+	"IF1 DAC 6", "IF2 DAC 6", "IF3 DAC L", "IF4 DAC L",
+	"SLB DAC 6", "OB 6"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_dac4l_enum, RT5677_IF_DSP_DAC3_4_MIXER,
+	RT5677_SEL_DAC4_L_SRC_SFT, rt5677_dac4l_src);
+
+static const struct snd_kcontrol_new rt5677_dac4_l_mux =
+	SOC_DAPM_ENUM("DAC4 L Source", rt5677_dac4l_enum);
+
+static const char * const rt5677_dac4r_src[] = {
+	"IF1 DAC 7", "IF2 DAC 7", "IF3 DAC R", "IF4 DAC R",
+	"SLB DAC 7", "OB 7"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_dac4r_enum, RT5677_IF_DSP_DAC3_4_MIXER,
+	RT5677_SEL_DAC4_R_SRC_SFT, rt5677_dac4r_src);
+
+static const struct snd_kcontrol_new rt5677_dac4_r_mux =
+	SOC_DAPM_ENUM("DAC4 R Source", rt5677_dac4r_enum);
+
+/* In/OutBound Source Pass SRC */ /* MX-A5 [3] [4] [0] [1] [2] */
+static const char * const rt5677_iob_bypass_src[] = {
+	"Bypass", "Pass SRC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_ob01_bypass_src_enum, RT5677_DSP_IN_OUTB_CTRL,
+	RT5677_SEL_SRC_OB01_SFT, rt5677_iob_bypass_src);
+
+static const struct snd_kcontrol_new rt5677_ob01_bypass_src_mux =
+	SOC_DAPM_ENUM("OB01 Bypass Source", rt5677_ob01_bypass_src_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_ob23_bypass_src_enum, RT5677_DSP_IN_OUTB_CTRL,
+	RT5677_SEL_SRC_OB23_SFT, rt5677_iob_bypass_src);
+
+static const struct snd_kcontrol_new rt5677_ob23_bypass_src_mux =
+	SOC_DAPM_ENUM("OB23 Bypass Source", rt5677_ob23_bypass_src_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_ib01_bypass_src_enum, RT5677_DSP_IN_OUTB_CTRL,
+	RT5677_SEL_SRC_IB01_SFT, rt5677_iob_bypass_src);
+
+static const struct snd_kcontrol_new rt5677_ib01_bypass_src_mux =
+	SOC_DAPM_ENUM("IB01 Bypass Source", rt5677_ib01_bypass_src_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_ib23_bypass_src_enum, RT5677_DSP_IN_OUTB_CTRL,
+	RT5677_SEL_SRC_IB23_SFT, rt5677_iob_bypass_src);
+
+static const struct snd_kcontrol_new rt5677_ib23_bypass_src_mux =
+	SOC_DAPM_ENUM("IB23 Bypass Source", rt5677_ib23_bypass_src_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_ib45_bypass_src_enum, RT5677_DSP_IN_OUTB_CTRL,
+	RT5677_SEL_SRC_IB45_SFT, rt5677_iob_bypass_src);
+
+static const struct snd_kcontrol_new rt5677_ib45_bypass_src_mux =
+	SOC_DAPM_ENUM("IB45 Bypass Source", rt5677_ib45_bypass_src_enum);
+
+/* Stereo ADC Source 2 */ /* MX-27 MX26 MX25 [11:10] */
+static const char * const rt5677_stereo_adc2_src[] = {
+	"DD MIX1", "DMIC", "Stereo DAC MIX"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_stereo1_adc2_enum, RT5677_STO1_ADC_MIXER,
+	RT5677_SEL_STO1_ADC2_SFT, rt5677_stereo_adc2_src);
+
+static const struct snd_kcontrol_new rt5677_sto1_adc2_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC2 Source", rt5677_stereo1_adc2_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_stereo2_adc2_enum, RT5677_STO2_ADC_MIXER,
+	RT5677_SEL_STO2_ADC2_SFT, rt5677_stereo_adc2_src);
+
+static const struct snd_kcontrol_new rt5677_sto2_adc2_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC2 Source", rt5677_stereo2_adc2_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_stereo3_adc2_enum, RT5677_STO3_ADC_MIXER,
+	RT5677_SEL_STO3_ADC2_SFT, rt5677_stereo_adc2_src);
+
+static const struct snd_kcontrol_new rt5677_sto3_adc2_mux =
+	SOC_DAPM_ENUM("Stereo3 ADC2 Source", rt5677_stereo3_adc2_enum);
+
+/* DMIC Source */ /* MX-28 [9:8][1:0] MX-27 MX-26 MX-25 MX-24 [9:8] */
+static const char * const rt5677_dmic_src[] = {
+	"DMIC1", "DMIC2", "DMIC3", "DMIC4"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_mono_dmic_l_enum, RT5677_MONO_ADC_MIXER,
+	RT5677_SEL_MONO_DMIC_L_SFT, rt5677_dmic_src);
+
+static const struct snd_kcontrol_new rt5677_mono_dmic_l_mux =
+	SOC_DAPM_ENUM("Mono DMIC L Source", rt5677_mono_dmic_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_mono_dmic_r_enum, RT5677_MONO_ADC_MIXER,
+	RT5677_SEL_MONO_DMIC_R_SFT, rt5677_dmic_src);
+
+static const struct snd_kcontrol_new rt5677_mono_dmic_r_mux =
+	SOC_DAPM_ENUM("Mono DMIC R Source", rt5677_mono_dmic_r_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_stereo1_dmic_enum, RT5677_STO1_ADC_MIXER,
+	RT5677_SEL_STO1_DMIC_SFT, rt5677_dmic_src);
+
+static const struct snd_kcontrol_new rt5677_sto1_dmic_mux =
+	SOC_DAPM_ENUM("Stereo1 DMIC Source", rt5677_stereo1_dmic_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_stereo2_dmic_enum, RT5677_STO2_ADC_MIXER,
+	RT5677_SEL_STO2_DMIC_SFT, rt5677_dmic_src);
+
+static const struct snd_kcontrol_new rt5677_sto2_dmic_mux =
+	SOC_DAPM_ENUM("Stereo2 DMIC Source", rt5677_stereo2_dmic_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_stereo3_dmic_enum, RT5677_STO3_ADC_MIXER,
+	RT5677_SEL_STO3_DMIC_SFT, rt5677_dmic_src);
+
+static const struct snd_kcontrol_new rt5677_sto3_dmic_mux =
+	SOC_DAPM_ENUM("Stereo3 DMIC Source", rt5677_stereo3_dmic_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_stereo4_dmic_enum, RT5677_STO4_ADC_MIXER,
+	RT5677_SEL_STO4_DMIC_SFT, rt5677_dmic_src);
+
+static const struct snd_kcontrol_new rt5677_sto4_dmic_mux =
+	SOC_DAPM_ENUM("Stereo4 DMIC Source", rt5677_stereo4_dmic_enum);
+
+/* Stereo2 ADC Source */ /* MX-26 [0] */
+static const char * const rt5677_stereo2_adc_lr_src[] = {
+	"L", "LR"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_stereo2_adc_lr_enum, RT5677_STO2_ADC_MIXER,
+	RT5677_SEL_STO2_LR_MIX_SFT, rt5677_stereo2_adc_lr_src);
+
+static const struct snd_kcontrol_new rt5677_sto2_adc_lr_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC LR Source", rt5677_stereo2_adc_lr_enum);
+
+/* Stereo1 ADC Source 1 */ /* MX-27 MX26 MX25 [13:12] */
+static const char * const rt5677_stereo_adc1_src[] = {
+	"DD MIX1", "ADC1/2", "Stereo DAC MIX"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_stereo1_adc1_enum, RT5677_STO1_ADC_MIXER,
+	RT5677_SEL_STO1_ADC1_SFT, rt5677_stereo_adc1_src);
+
+static const struct snd_kcontrol_new rt5677_sto1_adc1_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC1 Source", rt5677_stereo1_adc1_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_stereo2_adc1_enum, RT5677_STO2_ADC_MIXER,
+	RT5677_SEL_STO2_ADC1_SFT, rt5677_stereo_adc1_src);
+
+static const struct snd_kcontrol_new rt5677_sto2_adc1_mux =
+	SOC_DAPM_ENUM("Stereo2 ADC1 Source", rt5677_stereo2_adc1_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_stereo3_adc1_enum, RT5677_STO3_ADC_MIXER,
+	RT5677_SEL_STO3_ADC1_SFT, rt5677_stereo_adc1_src);
+
+static const struct snd_kcontrol_new rt5677_sto3_adc1_mux =
+	SOC_DAPM_ENUM("Stereo3 ADC1 Source", rt5677_stereo3_adc1_enum);
+
+/* Mono ADC Left Source 2 */ /* MX-28 [11:10] */
+static const char * const rt5677_mono_adc2_l_src[] = {
+	"DD MIX1L", "DMIC", "MONO DAC MIXL"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_mono_adc2_l_enum, RT5677_MONO_ADC_MIXER,
+	RT5677_SEL_MONO_ADC_L2_SFT, rt5677_mono_adc2_l_src);
+
+static const struct snd_kcontrol_new rt5677_mono_adc2_l_mux =
+	SOC_DAPM_ENUM("Mono ADC2 L Source", rt5677_mono_adc2_l_enum);
+
+/* Mono ADC Left Source 1 */ /* MX-28 [13:12] */
+static const char * const rt5677_mono_adc1_l_src[] = {
+	"DD MIX1L", "ADC1", "MONO DAC MIXL"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_mono_adc1_l_enum, RT5677_MONO_ADC_MIXER,
+	RT5677_SEL_MONO_ADC_L1_SFT, rt5677_mono_adc1_l_src);
+
+static const struct snd_kcontrol_new rt5677_mono_adc1_l_mux =
+	SOC_DAPM_ENUM("Mono ADC1 L Source", rt5677_mono_adc1_l_enum);
+
+/* Mono ADC Right Source 2 */ /* MX-28 [3:2] */
+static const char * const rt5677_mono_adc2_r_src[] = {
+	"DD MIX1R", "DMIC", "MONO DAC MIXR"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_mono_adc2_r_enum, RT5677_MONO_ADC_MIXER,
+	RT5677_SEL_MONO_ADC_R2_SFT, rt5677_mono_adc2_r_src);
+
+static const struct snd_kcontrol_new rt5677_mono_adc2_r_mux =
+	SOC_DAPM_ENUM("Mono ADC2 R Source", rt5677_mono_adc2_r_enum);
+
+/* Mono ADC Right Source 1 */ /* MX-28 [5:4] */
+static const char * const rt5677_mono_adc1_r_src[] = {
+	"DD MIX1R", "ADC2", "MONO DAC MIXR"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_mono_adc1_r_enum, RT5677_MONO_ADC_MIXER,
+	RT5677_SEL_MONO_ADC_R1_SFT, rt5677_mono_adc1_r_src);
+
+static const struct snd_kcontrol_new rt5677_mono_adc1_r_mux =
+	SOC_DAPM_ENUM("Mono ADC1 R Source", rt5677_mono_adc1_r_enum);
+
+/* Stereo4 ADC Source 2 */ /* MX-24 [11:10] */
+static const char * const rt5677_stereo4_adc2_src[] = {
+	"DD MIX1", "DMIC", "DD MIX2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_stereo4_adc2_enum, RT5677_STO4_ADC_MIXER,
+	RT5677_SEL_STO4_ADC2_SFT, rt5677_stereo4_adc2_src);
+
+static const struct snd_kcontrol_new rt5677_sto4_adc2_mux =
+	SOC_DAPM_ENUM("Stereo4 ADC2 Source", rt5677_stereo4_adc2_enum);
+
+
+/* Stereo4 ADC Source 1 */ /* MX-24 [13:12] */
+static const char * const rt5677_stereo4_adc1_src[] = {
+	"DD MIX1", "ADC1/2", "DD MIX2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_stereo4_adc1_enum, RT5677_STO4_ADC_MIXER,
+	RT5677_SEL_STO4_ADC1_SFT, rt5677_stereo4_adc1_src);
+
+static const struct snd_kcontrol_new rt5677_sto4_adc1_mux =
+	SOC_DAPM_ENUM("Stereo4 ADC1 Source", rt5677_stereo4_adc1_enum);
+
+/* InBound0/1 Source */ /* MX-A3 [14:12] */
+static const char * const rt5677_inbound01_src[] = {
+	"IF1 DAC 01", "IF2 DAC 01", "SLB DAC 01", "STO1 ADC MIX",
+	"VAD ADC/DAC1 FS"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_inbound01_enum, RT5677_DSP_INB_CTRL1,
+	RT5677_IB01_SRC_SFT, rt5677_inbound01_src);
+
+static const struct snd_kcontrol_new rt5677_ib01_src_mux =
+	SOC_DAPM_ENUM("InBound0/1 Source", rt5677_inbound01_enum);
+
+/* InBound2/3 Source */ /* MX-A3 [10:8] */
+static const char * const rt5677_inbound23_src[] = {
+	"IF1 DAC 23", "IF2 DAC 23", "SLB DAC 23", "STO2 ADC MIX",
+	"DAC1 FS", "IF4 DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_inbound23_enum, RT5677_DSP_INB_CTRL1,
+	RT5677_IB23_SRC_SFT, rt5677_inbound23_src);
+
+static const struct snd_kcontrol_new rt5677_ib23_src_mux =
+	SOC_DAPM_ENUM("InBound2/3 Source", rt5677_inbound23_enum);
+
+/* InBound4/5 Source */ /* MX-A3 [6:4] */
+static const char * const rt5677_inbound45_src[] = {
+	"IF1 DAC 45", "IF2 DAC 45", "SLB DAC 45", "STO3 ADC MIX",
+	"IF3 DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_inbound45_enum, RT5677_DSP_INB_CTRL1,
+	RT5677_IB45_SRC_SFT, rt5677_inbound45_src);
+
+static const struct snd_kcontrol_new rt5677_ib45_src_mux =
+	SOC_DAPM_ENUM("InBound4/5 Source", rt5677_inbound45_enum);
+
+/* InBound6 Source */ /* MX-A3 [2:0] */
+static const char * const rt5677_inbound6_src[] = {
+	"IF1 DAC 6", "IF2 DAC 6", "SLB DAC 6", "STO4 ADC MIX L",
+	"IF4 DAC L", "STO1 ADC MIX L", "STO2 ADC MIX L", "STO3 ADC MIX L"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_inbound6_enum, RT5677_DSP_INB_CTRL1,
+	RT5677_IB6_SRC_SFT, rt5677_inbound6_src);
+
+static const struct snd_kcontrol_new rt5677_ib6_src_mux =
+	SOC_DAPM_ENUM("InBound6 Source", rt5677_inbound6_enum);
+
+/* InBound7 Source */ /* MX-A4 [14:12] */
+static const char * const rt5677_inbound7_src[] = {
+	"IF1 DAC 7", "IF2 DAC 7", "SLB DAC 7", "STO4 ADC MIX R",
+	"IF4 DAC R", "STO1 ADC MIX R", "STO2 ADC MIX R", "STO3 ADC MIX R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_inbound7_enum, RT5677_DSP_INB_CTRL2,
+	RT5677_IB7_SRC_SFT, rt5677_inbound7_src);
+
+static const struct snd_kcontrol_new rt5677_ib7_src_mux =
+	SOC_DAPM_ENUM("InBound7 Source", rt5677_inbound7_enum);
+
+/* InBound8 Source */ /* MX-A4 [10:8] */
+static const char * const rt5677_inbound8_src[] = {
+	"STO1 ADC MIX L", "STO2 ADC MIX L", "STO3 ADC MIX L", "STO4 ADC MIX L",
+	"MONO ADC MIX L", "DACL1 FS"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_inbound8_enum, RT5677_DSP_INB_CTRL2,
+	RT5677_IB8_SRC_SFT, rt5677_inbound8_src);
+
+static const struct snd_kcontrol_new rt5677_ib8_src_mux =
+	SOC_DAPM_ENUM("InBound8 Source", rt5677_inbound8_enum);
+
+/* InBound9 Source */ /* MX-A4 [6:4] */
+static const char * const rt5677_inbound9_src[] = {
+	"STO1 ADC MIX R", "STO2 ADC MIX R", "STO3 ADC MIX R", "STO4 ADC MIX R",
+	"MONO ADC MIX R", "DACR1 FS", "DAC1 FS"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_inbound9_enum, RT5677_DSP_INB_CTRL2,
+	RT5677_IB9_SRC_SFT, rt5677_inbound9_src);
+
+static const struct snd_kcontrol_new rt5677_ib9_src_mux =
+	SOC_DAPM_ENUM("InBound9 Source", rt5677_inbound9_enum);
+
+/* VAD Source */ /* MX-9F [6:4] */
+static const char * const rt5677_vad_src[] = {
+	"STO1 ADC MIX L", "MONO ADC MIX L", "MONO ADC MIX R", "STO2 ADC MIX L",
+	"STO3 ADC MIX L"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_vad_enum, RT5677_VAD_CTRL4,
+	RT5677_VAD_SRC_SFT, rt5677_vad_src);
+
+static const struct snd_kcontrol_new rt5677_vad_src_mux =
+	SOC_DAPM_ENUM("VAD Source", rt5677_vad_enum);
+
+/* Sidetone Source */ /* MX-13 [11:9] */
+static const char * const rt5677_sidetone_src[] = {
+	"DMIC1 L", "DMIC2 L", "DMIC3 L", "DMIC4 L", "ADC1", "ADC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_sidetone_enum, RT5677_SIDETONE_CTRL,
+	RT5677_ST_SEL_SFT, rt5677_sidetone_src);
+
+static const struct snd_kcontrol_new rt5677_sidetone_mux =
+	SOC_DAPM_ENUM("Sidetone Source", rt5677_sidetone_enum);
+
+/* DAC1/2 Source */ /* MX-15 [1:0] */
+static const char * const rt5677_dac12_src[] = {
+	"STO1 DAC MIX", "MONO DAC MIX", "DD MIX1", "DD MIX2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_dac12_enum, RT5677_ANA_DAC1_2_3_SRC,
+	RT5677_ANA_DAC1_2_SRC_SEL_SFT, rt5677_dac12_src);
+
+static const struct snd_kcontrol_new rt5677_dac12_mux =
+	SOC_DAPM_ENUM("Analog DAC1/2 Source", rt5677_dac12_enum);
+
+/* DAC3 Source */ /* MX-15 [5:4] */
+static const char * const rt5677_dac3_src[] = {
+	"MONO DAC MIXL", "MONO DAC MIXR", "DD MIX1L", "DD MIX2L"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_dac3_enum, RT5677_ANA_DAC1_2_3_SRC,
+	RT5677_ANA_DAC3_SRC_SEL_SFT, rt5677_dac3_src);
+
+static const struct snd_kcontrol_new rt5677_dac3_mux =
+	SOC_DAPM_ENUM("Analog DAC3 Source", rt5677_dac3_enum);
+
+/* PDM channel Source */ /* MX-31 [13:12][9:8][5:4][1:0] */
+static const char * const rt5677_pdm_src[] = {
+	"STO1 DAC MIX", "MONO DAC MIX", "DD MIX1", "DD MIX2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_pdm1_l_enum, RT5677_PDM_OUT_CTRL,
+	RT5677_SEL_PDM1_L_SFT, rt5677_pdm_src);
+
+static const struct snd_kcontrol_new rt5677_pdm1_l_mux =
+	SOC_DAPM_ENUM("PDM1 Source", rt5677_pdm1_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_pdm2_l_enum, RT5677_PDM_OUT_CTRL,
+	RT5677_SEL_PDM2_L_SFT, rt5677_pdm_src);
+
+static const struct snd_kcontrol_new rt5677_pdm2_l_mux =
+	SOC_DAPM_ENUM("PDM2 Source", rt5677_pdm2_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_pdm1_r_enum, RT5677_PDM_OUT_CTRL,
+	RT5677_SEL_PDM1_R_SFT, rt5677_pdm_src);
+
+static const struct snd_kcontrol_new rt5677_pdm1_r_mux =
+	SOC_DAPM_ENUM("PDM1 Source", rt5677_pdm1_r_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_pdm2_r_enum, RT5677_PDM_OUT_CTRL,
+	RT5677_SEL_PDM2_R_SFT, rt5677_pdm_src);
+
+static const struct snd_kcontrol_new rt5677_pdm2_r_mux =
+	SOC_DAPM_ENUM("PDM2 Source", rt5677_pdm2_r_enum);
+
+/* TDM IF1/2 SLB ADC1 Data Selection */ /* MX-3C MX-41 [5:4] MX-08 [1:0] */
+static const char * const rt5677_if12_adc1_src[] = {
+	"STO1 ADC MIX", "OB01", "VAD ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_adc1_enum, RT5677_TDM1_CTRL2,
+	RT5677_IF1_ADC1_SFT, rt5677_if12_adc1_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc1_mux =
+	SOC_DAPM_ENUM("IF1 ADC1 Source", rt5677_if1_adc1_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_adc1_enum, RT5677_TDM2_CTRL2,
+	RT5677_IF2_ADC1_SFT, rt5677_if12_adc1_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc1_mux =
+	SOC_DAPM_ENUM("IF2 ADC1 Source", rt5677_if2_adc1_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_slb_adc1_enum, RT5677_SLIMBUS_RX,
+	RT5677_SLB_ADC1_SFT, rt5677_if12_adc1_src);
+
+static const struct snd_kcontrol_new rt5677_slb_adc1_mux =
+	SOC_DAPM_ENUM("SLB ADC1 Source", rt5677_slb_adc1_enum);
+
+/* TDM IF1/2 SLB ADC2 Data Selection */ /* MX-3C MX-41 [7:6] MX-08 [3:2] */
+static const char * const rt5677_if12_adc2_src[] = {
+	"STO2 ADC MIX", "OB23"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_adc2_enum, RT5677_TDM1_CTRL2,
+	RT5677_IF1_ADC2_SFT, rt5677_if12_adc2_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc2_mux =
+	SOC_DAPM_ENUM("IF1 ADC2 Source", rt5677_if1_adc2_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_adc2_enum, RT5677_TDM2_CTRL2,
+	RT5677_IF2_ADC2_SFT, rt5677_if12_adc2_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc2_mux =
+	SOC_DAPM_ENUM("IF2 ADC2 Source", rt5677_if2_adc2_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_slb_adc2_enum, RT5677_SLIMBUS_RX,
+	RT5677_SLB_ADC2_SFT, rt5677_if12_adc2_src);
+
+static const struct snd_kcontrol_new rt5677_slb_adc2_mux =
+	SOC_DAPM_ENUM("SLB ADC2 Source", rt5677_slb_adc2_enum);
+
+/* TDM IF1/2 SLB ADC3 Data Selection */ /* MX-3C MX-41 [9:8] MX-08 [5:4] */
+static const char * const rt5677_if12_adc3_src[] = {
+	"STO3 ADC MIX", "MONO ADC MIX", "OB45"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_adc3_enum, RT5677_TDM1_CTRL2,
+	RT5677_IF1_ADC3_SFT, rt5677_if12_adc3_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc3_mux =
+	SOC_DAPM_ENUM("IF1 ADC3 Source", rt5677_if1_adc3_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_adc3_enum, RT5677_TDM2_CTRL2,
+	RT5677_IF2_ADC3_SFT, rt5677_if12_adc3_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc3_mux =
+	SOC_DAPM_ENUM("IF2 ADC3 Source", rt5677_if2_adc3_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_slb_adc3_enum, RT5677_SLIMBUS_RX,
+	RT5677_SLB_ADC3_SFT, rt5677_if12_adc3_src);
+
+static const struct snd_kcontrol_new rt5677_slb_adc3_mux =
+	SOC_DAPM_ENUM("SLB ADC3 Source", rt5677_slb_adc3_enum);
+
+/* TDM IF1/2 SLB ADC4 Data Selection */ /* MX-3C MX-41 [11:10] MX-08 [7:6] */
+static const char * const rt5677_if12_adc4_src[] = {
+	"STO4 ADC MIX", "OB67", "OB01"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_adc4_enum, RT5677_TDM1_CTRL2,
+	RT5677_IF1_ADC4_SFT, rt5677_if12_adc4_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc4_mux =
+	SOC_DAPM_ENUM("IF1 ADC4 Source", rt5677_if1_adc4_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_adc4_enum, RT5677_TDM2_CTRL2,
+	RT5677_IF2_ADC4_SFT, rt5677_if12_adc4_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc4_mux =
+	SOC_DAPM_ENUM("IF2 ADC4 Source", rt5677_if2_adc4_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_slb_adc4_enum, RT5677_SLIMBUS_RX,
+	RT5677_SLB_ADC4_SFT, rt5677_if12_adc4_src);
+
+static const struct snd_kcontrol_new rt5677_slb_adc4_mux =
+	SOC_DAPM_ENUM("SLB ADC4 Source", rt5677_slb_adc4_enum);
+
+/* Interface3/4 ADC Data Input */ /* MX-2F [3:0] MX-30 [7:4] */
+static const char * const rt5677_if34_adc_src[] = {
+	"STO1 ADC MIX", "STO2 ADC MIX", "STO3 ADC MIX", "STO4 ADC MIX",
+	"MONO ADC MIX", "OB01", "OB23", "VAD ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if3_adc_enum, RT5677_IF3_DATA,
+	RT5677_IF3_ADC_IN_SFT, rt5677_if34_adc_src);
+
+static const struct snd_kcontrol_new rt5677_if3_adc_mux =
+	SOC_DAPM_ENUM("IF3 ADC Source", rt5677_if3_adc_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if4_adc_enum, RT5677_IF4_DATA,
+	RT5677_IF4_ADC_IN_SFT, rt5677_if34_adc_src);
+
+static const struct snd_kcontrol_new rt5677_if4_adc_mux =
+	SOC_DAPM_ENUM("IF4 ADC Source", rt5677_if4_adc_enum);
+
+/* TDM IF1/2 ADC Data Selection */ /* MX-3B MX-40 [7:6][5:4][3:2][1:0] */
+static const char * const rt5677_if12_adc_swap_src[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_adc1_swap_enum, RT5677_TDM1_CTRL1,
+	RT5677_IF1_ADC1_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc1_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC1 Swap Source", rt5677_if1_adc1_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_adc2_swap_enum, RT5677_TDM1_CTRL1,
+	RT5677_IF1_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc2_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC2 Swap Source", rt5677_if1_adc2_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_adc3_swap_enum, RT5677_TDM1_CTRL1,
+	RT5677_IF1_ADC3_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc3_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC3 Swap Source", rt5677_if1_adc3_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_adc4_swap_enum, RT5677_TDM1_CTRL1,
+	RT5677_IF1_ADC4_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc4_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC4 Swap Source", rt5677_if1_adc4_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_adc1_swap_enum, RT5677_TDM2_CTRL1,
+	RT5677_IF1_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc1_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC2 Swap Source", rt5677_if2_adc1_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_adc2_swap_enum, RT5677_TDM2_CTRL1,
+	RT5677_IF2_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc2_swap_mux =
+	SOC_DAPM_ENUM("IF2 ADC2 Swap Source", rt5677_if2_adc2_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_adc3_swap_enum, RT5677_TDM2_CTRL1,
+	RT5677_IF2_ADC3_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc3_swap_mux =
+	SOC_DAPM_ENUM("IF2 ADC3 Swap Source", rt5677_if2_adc3_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_adc4_swap_enum, RT5677_TDM2_CTRL1,
+	RT5677_IF2_ADC4_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc4_swap_mux =
+	SOC_DAPM_ENUM("IF2 ADC4 Swap Source", rt5677_if2_adc4_swap_enum);
+
+/* TDM IF1 ADC Data Selection */ /* MX-3C [2:0] */
+static const char * const rt5677_if1_adc_tdm_swap_src[] = {
+	"1/2/3/4", "2/1/3/4", "2/3/1/4", "4/1/2/3", "1/3/2/4", "1/4/2/3",
+	"3/1/2/4", "3/4/1/2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_adc_tdm_swap_enum, RT5677_TDM1_CTRL2,
+	RT5677_IF1_ADC_CTRL_SFT, rt5677_if1_adc_tdm_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc_tdm_swap_mux =
+	SOC_DAPM_ENUM("IF1 ADC TDM Swap Source", rt5677_if1_adc_tdm_swap_enum);
+
+/* TDM IF2 ADC Data Selection */ /* MX-41[2:0] */
+static const char * const rt5677_if2_adc_tdm_swap_src[] = {
+	"1/2/3/4", "2/1/3/4", "3/1/2/4", "4/1/2/3", "1/3/2/4", "1/4/2/3",
+	"2/3/1/4", "3/4/1/2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_adc_tdm_swap_enum, RT5677_TDM2_CTRL2,
+	RT5677_IF2_ADC_CTRL_SFT, rt5677_if2_adc_tdm_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc_tdm_swap_mux =
+	SOC_DAPM_ENUM("IF2 ADC TDM Swap Source", rt5677_if2_adc_tdm_swap_enum);
+
+/* TDM IF1/2 DAC Data Selection */ /* MX-3E[14:12][10:8][6:4][2:0]
+					MX-3F[14:12][10:8][6:4][2:0]
+					MX-43[14:12][10:8][6:4][2:0]
+					MX-44[14:12][10:8][6:4][2:0] */
+static const char * const rt5677_if12_dac_tdm_sel_src[] = {
+	"Slot0", "Slot1", "Slot2", "Slot3", "Slot4", "Slot5", "Slot6", "Slot7"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac0_tdm_sel_enum, RT5677_TDM1_CTRL4,
+	RT5677_IF1_DAC0_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac0_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC0 TDM Source", rt5677_if1_dac0_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac1_tdm_sel_enum, RT5677_TDM1_CTRL4,
+	RT5677_IF1_DAC1_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac1_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC1 TDM Source", rt5677_if1_dac1_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac2_tdm_sel_enum, RT5677_TDM1_CTRL4,
+	RT5677_IF1_DAC2_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac2_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC2 TDM Source", rt5677_if1_dac2_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac3_tdm_sel_enum, RT5677_TDM1_CTRL4,
+	RT5677_IF1_DAC3_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac3_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC3 TDM Source", rt5677_if1_dac3_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac4_tdm_sel_enum, RT5677_TDM1_CTRL5,
+	RT5677_IF1_DAC4_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac4_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC4 TDM Source", rt5677_if1_dac4_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac5_tdm_sel_enum, RT5677_TDM1_CTRL5,
+	RT5677_IF1_DAC5_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac5_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC5 TDM Source", rt5677_if1_dac5_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac6_tdm_sel_enum, RT5677_TDM1_CTRL5,
+	RT5677_IF1_DAC6_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac6_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC6 TDM Source", rt5677_if1_dac6_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if1_dac7_tdm_sel_enum, RT5677_TDM1_CTRL5,
+	RT5677_IF1_DAC7_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac7_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF1 DAC7 TDM Source", rt5677_if1_dac7_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac0_tdm_sel_enum, RT5677_TDM2_CTRL4,
+	RT5677_IF2_DAC0_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac0_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC0 TDM Source", rt5677_if2_dac0_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac1_tdm_sel_enum, RT5677_TDM2_CTRL4,
+	RT5677_IF2_DAC1_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac1_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC1 TDM Source", rt5677_if2_dac1_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac2_tdm_sel_enum, RT5677_TDM2_CTRL4,
+	RT5677_IF2_DAC2_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac2_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC2 TDM Source", rt5677_if2_dac2_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac3_tdm_sel_enum, RT5677_TDM2_CTRL4,
+	RT5677_IF2_DAC3_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac3_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC3 TDM Source", rt5677_if2_dac3_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac4_tdm_sel_enum, RT5677_TDM2_CTRL5,
+	RT5677_IF2_DAC4_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac4_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC4 TDM Source", rt5677_if2_dac4_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac5_tdm_sel_enum, RT5677_TDM2_CTRL5,
+	RT5677_IF2_DAC5_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac5_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC5 TDM Source", rt5677_if2_dac5_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac6_tdm_sel_enum, RT5677_TDM2_CTRL5,
+	RT5677_IF2_DAC6_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac6_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC6 TDM Source", rt5677_if2_dac6_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5677_if2_dac7_tdm_sel_enum, RT5677_TDM2_CTRL5,
+	RT5677_IF2_DAC7_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac7_tdm_sel_mux =
+	SOC_DAPM_ENUM("IF2 DAC7 TDM Source", rt5677_if2_dac7_tdm_sel_enum);
+
+static int rt5677_bst1_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
+			RT5677_PWR_BST1_P, RT5677_PWR_BST1_P);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
+			RT5677_PWR_BST1_P, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5677_bst2_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
+			RT5677_PWR_BST2_P, RT5677_PWR_BST2_P);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
+			RT5677_PWR_BST2_P, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5677_set_pll1_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_update_bits(rt5677->regmap, RT5677_PLL1_CTRL2, 0x2, 0x2);
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(rt5677->regmap, RT5677_PLL1_CTRL2, 0x2, 0x0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5677_set_pll2_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_update_bits(rt5677->regmap, RT5677_PLL2_CTRL2, 0x2, 0x2);
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(rt5677->regmap, RT5677_PLL2_CTRL2, 0x2, 0x0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
+			RT5677_PWR_CLK_MB1 | RT5677_PWR_PP_MB1 |
+			RT5677_PWR_CLK_MB, RT5677_PWR_CLK_MB1 |
+			RT5677_PWR_PP_MB1 | RT5677_PWR_CLK_MB);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
+			RT5677_PWR_CLK_MB1 | RT5677_PWR_PP_MB1 |
+			RT5677_PWR_CLK_MB, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+	unsigned int value;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_read(rt5677->regmap, RT5677_TDM1_CTRL2, &value);
+		if (value & RT5677_IF1_ADC_CTRL_MASK)
+			regmap_update_bits(rt5677->regmap, RT5677_TDM1_CTRL1,
+				RT5677_IF1_ADC_MODE_MASK,
+				RT5677_IF1_ADC_MODE_TDM);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+	unsigned int value;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_read(rt5677->regmap, RT5677_TDM2_CTRL2, &value);
+		if (value & RT5677_IF2_ADC_CTRL_MASK)
+			regmap_update_bits(rt5677->regmap, RT5677_TDM2_CTRL1,
+				RT5677_IF2_ADC_MODE_MASK,
+				RT5677_IF2_ADC_MODE_TDM);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5677_vref_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_ON &&
+			!rt5677->is_vref_slow) {
+			mdelay(20);
+			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
+				RT5677_PWR_FV1 | RT5677_PWR_FV2,
+				RT5677_PWR_FV1 | RT5677_PWR_FV2);
+			rt5677->is_vref_slow = true;
+		}
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5677_filter_power_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		msleep(50);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT,
+		0, rt5677_set_pll1_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("PLL2", RT5677_PWR_ANLG2, RT5677_PWR_PLL2_BIT,
+		0, rt5677_set_pll2_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5677_ASRC_1, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5677_ASRC_1, 1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5677_ASRC_1, 2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S4 ASRC", 1, RT5677_ASRC_1, 3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5677_ASRC_2, 14, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC MONO2 L ASRC", 1, RT5677_ASRC_2, 13, 0, NULL,
+		0),
+	SND_SOC_DAPM_SUPPLY_S("DAC MONO2 R ASRC", 1, RT5677_ASRC_2, 12, 0, NULL,
+		0),
+	SND_SOC_DAPM_SUPPLY_S("DAC MONO3 L ASRC", 1, RT5677_ASRC_1, 15, 0, NULL,
+		0),
+	SND_SOC_DAPM_SUPPLY_S("DAC MONO3 R ASRC", 1, RT5677_ASRC_1, 14, 0, NULL,
+		0),
+	SND_SOC_DAPM_SUPPLY_S("DAC MONO4 L ASRC", 1, RT5677_ASRC_1, 13, 0, NULL,
+		0),
+	SND_SOC_DAPM_SUPPLY_S("DAC MONO4 R ASRC", 1, RT5677_ASRC_1, 12, 0, NULL,
+		0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5677_ASRC_2, 11, 0, NULL,
+		0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5677_ASRC_2, 10, 0, NULL,
+		0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC STO3 ASRC", 1, RT5677_ASRC_2, 9, 0, NULL,
+		0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC STO4 ASRC", 1, RT5677_ASRC_2, 8, 0, NULL,
+		0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5677_ASRC_2, 7, 0, NULL,
+		0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5677_ASRC_2, 6, 0, NULL,
+		0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5677_ASRC_2, 5, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5677_ASRC_2, 4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO3 ASRC", 1, RT5677_ASRC_2, 3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO4 ASRC", 1, RT5677_ASRC_2, 2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5677_ASRC_2, 1, 0, NULL,
+		0),
+	SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5677_ASRC_2, 0, 0, NULL,
+		0),
+
+	/* Input Side */
+	/* micbias */
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5677_PWR_ANLG2, RT5677_PWR_MB1_BIT,
+		0, rt5677_set_micbias1_event, SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMU),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC L1"),
+	SND_SOC_DAPM_INPUT("DMIC R1"),
+	SND_SOC_DAPM_INPUT("DMIC L2"),
+	SND_SOC_DAPM_INPUT("DMIC R2"),
+	SND_SOC_DAPM_INPUT("DMIC L3"),
+	SND_SOC_DAPM_INPUT("DMIC R3"),
+	SND_SOC_DAPM_INPUT("DMIC L4"),
+	SND_SOC_DAPM_INPUT("DMIC R4"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN1N"),
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN2N"),
+
+	SND_SOC_DAPM_INPUT("Haptic Generator"),
+
+	SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DMIC1 power", RT5677_DMIC_CTRL1,
+		RT5677_DMIC_1_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC2 power", RT5677_DMIC_CTRL1,
+		RT5677_DMIC_2_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC3 power", RT5677_DMIC_CTRL1,
+		RT5677_DMIC_3_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC4 power", RT5677_DMIC_CTRL2,
+		RT5677_DMIC_4_EN_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+		set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA_E("BST1", RT5677_PWR_ANLG2,
+		RT5677_PWR_BST1_BIT, 0, NULL, 0, rt5677_bst1_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_E("BST2", RT5677_PWR_ANLG2,
+		RT5677_PWR_BST2_BIT, 0, NULL, 0, rt5677_bst2_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM,
+		0, 0),
+	SND_SOC_DAPM_ADC("ADC 2", NULL, SND_SOC_NOPM,
+		0, 0),
+	SND_SOC_DAPM_PGA("ADC 1_2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC 1 power", RT5677_PWR_DIG1,
+		RT5677_PWR_ADC_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC 2 power", RT5677_PWR_DIG1,
+		RT5677_PWR_ADC_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1 clock", RT5677_PWR_DIG1,
+		RT5677_PWR_ADCFED1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC2 clock", RT5677_PWR_DIG1,
+		RT5677_PWR_ADCFED2_BIT, 0, NULL, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_sto1_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC1 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_sto1_adc1_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC2 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_sto1_adc2_mux),
+	SND_SOC_DAPM_MUX("Stereo2 DMIC Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_sto2_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC1 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_sto2_adc1_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC2 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_sto2_adc2_mux),
+	SND_SOC_DAPM_MUX("Stereo2 ADC LR Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_sto2_adc_lr_mux),
+	SND_SOC_DAPM_MUX("Stereo3 DMIC Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_sto3_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo3 ADC1 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_sto3_adc1_mux),
+	SND_SOC_DAPM_MUX("Stereo3 ADC2 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_sto3_adc2_mux),
+	SND_SOC_DAPM_MUX("Stereo4 DMIC Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_sto4_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo4 ADC1 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_sto4_adc1_mux),
+	SND_SOC_DAPM_MUX("Stereo4 ADC2 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_sto4_adc2_mux),
+	SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_mono_dmic_l_mux),
+	SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_mono_dmic_r_mux),
+	SND_SOC_DAPM_MUX("Mono ADC2 L Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_mono_adc2_l_mux),
+	SND_SOC_DAPM_MUX("Mono ADC1 L Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_mono_adc1_l_mux),
+	SND_SOC_DAPM_MUX("Mono ADC1 R Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_mono_adc1_r_mux),
+	SND_SOC_DAPM_MUX("Mono ADC2 R Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_mono_adc2_r_mux),
+
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("adc stereo1 filter", RT5677_PWR_DIG2,
+		RT5677_PWR_ADC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("adc stereo2 filter", RT5677_PWR_DIG2,
+		RT5677_PWR_ADC_S2F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("adc stereo3 filter", RT5677_PWR_DIG2,
+		RT5677_PWR_ADC_S3F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("adc stereo4 filter", RT5677_PWR_DIG2,
+		RT5677_PWR_ADC_S4F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5677_sto1_adc_l_mix, ARRAY_SIZE(rt5677_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5677_sto1_adc_r_mix, ARRAY_SIZE(rt5677_sto1_adc_r_mix)),
+	SND_SOC_DAPM_MIXER("Sto2 ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5677_sto2_adc_l_mix, ARRAY_SIZE(rt5677_sto2_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Sto2 ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5677_sto2_adc_r_mix, ARRAY_SIZE(rt5677_sto2_adc_r_mix)),
+	SND_SOC_DAPM_MIXER("Sto3 ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5677_sto3_adc_l_mix, ARRAY_SIZE(rt5677_sto3_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Sto3 ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5677_sto3_adc_r_mix, ARRAY_SIZE(rt5677_sto3_adc_r_mix)),
+	SND_SOC_DAPM_MIXER("Sto4 ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5677_sto4_adc_l_mix, ARRAY_SIZE(rt5677_sto4_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Sto4 ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5677_sto4_adc_r_mix, ARRAY_SIZE(rt5677_sto4_adc_r_mix)),
+	SND_SOC_DAPM_SUPPLY("adc mono left filter", RT5677_PWR_DIG2,
+		RT5677_PWR_ADC_MF_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mono ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5677_mono_adc_l_mix, ARRAY_SIZE(rt5677_mono_adc_l_mix)),
+	SND_SOC_DAPM_SUPPLY("adc mono right filter", RT5677_PWR_DIG2,
+		RT5677_PWR_ADC_MF_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mono ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5677_mono_adc_r_mix, ARRAY_SIZE(rt5677_mono_adc_r_mix)),
+
+	/* ADC PGA */
+	SND_SOC_DAPM_PGA("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo2 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo2 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo2 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo3 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo3 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo3 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo4 ADC MIXL", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo4 ADC MIXR", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo4 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* DSP */
+	SND_SOC_DAPM_MUX("IB9 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_ib9_src_mux),
+	SND_SOC_DAPM_MUX("IB8 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_ib8_src_mux),
+	SND_SOC_DAPM_MUX("IB7 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_ib7_src_mux),
+	SND_SOC_DAPM_MUX("IB6 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_ib6_src_mux),
+	SND_SOC_DAPM_MUX("IB45 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_ib45_src_mux),
+	SND_SOC_DAPM_MUX("IB23 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_ib23_src_mux),
+	SND_SOC_DAPM_MUX("IB01 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_ib01_src_mux),
+	SND_SOC_DAPM_MUX("IB45 Bypass Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_ib45_bypass_src_mux),
+	SND_SOC_DAPM_MUX("IB23 Bypass Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_ib23_bypass_src_mux),
+	SND_SOC_DAPM_MUX("IB01 Bypass Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_ib01_bypass_src_mux),
+	SND_SOC_DAPM_MUX("OB23 Bypass Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_ob23_bypass_src_mux),
+	SND_SOC_DAPM_MUX("OB01 Bypass Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_ob01_bypass_src_mux),
+
+	SND_SOC_DAPM_PGA("OB45", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OB67", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("OutBound2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OutBound3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OutBound4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OutBound5", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OutBound6", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OutBound7", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5677_PWR_DIG1,
+		RT5677_PWR_I2S1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC0", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC5", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC6", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC7", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC01", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC23", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC45", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC67", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("I2S2", RT5677_PWR_DIG1,
+		RT5677_PWR_I2S2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC0", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC5", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC6", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC7", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC01", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC23", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC45", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC67", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("I2S3", RT5677_PWR_DIG1,
+		RT5677_PWR_I2S3_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("I2S4", RT5677_PWR_DIG1,
+		RT5677_PWR_I2S4_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF4 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF4 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF4 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF4 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF4 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF4 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("SLB", RT5677_PWR_DIG1,
+		RT5677_PWR_SLB_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB DAC0", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB DAC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB DAC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB DAC5", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB DAC6", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB DAC7", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB DAC01", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB DAC23", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB DAC45", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB DAC67", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SLB ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface Select */
+	SND_SOC_DAPM_MUX("IF1 ADC1 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_adc1_mux),
+	SND_SOC_DAPM_MUX("IF1 ADC2 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_adc2_mux),
+	SND_SOC_DAPM_MUX("IF1 ADC3 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_adc3_mux),
+	SND_SOC_DAPM_MUX("IF1 ADC4 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_adc4_mux),
+	SND_SOC_DAPM_MUX("IF1 ADC1 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_adc1_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 ADC2 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_adc2_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 ADC3 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_adc3_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 ADC4 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_adc4_swap_mux),
+	SND_SOC_DAPM_MUX_E("IF1 ADC TDM Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_adc_tdm_swap_mux, rt5677_if1_adc_tdm_event,
+			SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MUX("IF2 ADC1 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_adc1_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC2 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_adc2_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC3 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_adc3_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC4 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_adc4_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC1 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_adc1_swap_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC2 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_adc2_swap_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC3 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_adc3_swap_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC4 Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_adc4_swap_mux),
+	SND_SOC_DAPM_MUX_E("IF2 ADC TDM Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_adc_tdm_swap_mux, rt5677_if2_adc_tdm_event,
+			SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if3_adc_mux),
+	SND_SOC_DAPM_MUX("IF4 ADC Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if4_adc_mux),
+	SND_SOC_DAPM_MUX("SLB ADC1 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_slb_adc1_mux),
+	SND_SOC_DAPM_MUX("SLB ADC2 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_slb_adc2_mux),
+	SND_SOC_DAPM_MUX("SLB ADC3 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_slb_adc3_mux),
+	SND_SOC_DAPM_MUX("SLB ADC4 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_slb_adc4_mux),
+
+	SND_SOC_DAPM_MUX("IF1 DAC0 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac0_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF1 DAC1 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac1_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF1 DAC2 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac2_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF1 DAC3 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac3_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF1 DAC4 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac4_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF1 DAC5 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac5_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF1 DAC6 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac6_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF1 DAC7 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if1_dac7_tdm_sel_mux),
+
+	SND_SOC_DAPM_MUX("IF2 DAC0 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac0_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC1 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac1_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC2 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac2_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC3 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac3_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC4 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac4_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC5 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac5_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC6 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac6_tdm_sel_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC7 Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_if2_dac7_tdm_sel_mux),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF3RX", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF3TX", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF4RX", "AIF4 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF4TX", "AIF4 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SLBRX", "SLIMBus Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SLBTX", "SLIMBus Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Sidetone Mux */
+	SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_sidetone_mux),
+	SND_SOC_DAPM_SUPPLY("Sidetone Power", RT5677_SIDETONE_CTRL,
+		RT5677_ST_EN_SFT, 0, NULL, 0),
+
+	/* VAD Mux*/
+	SND_SOC_DAPM_MUX("VAD ADC Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_vad_src_mux),
+
+	/* Tensilica DSP */
+	SND_SOC_DAPM_PGA("Tensilica DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("OB01 MIX", SND_SOC_NOPM, 0, 0,
+		rt5677_ob_01_mix, ARRAY_SIZE(rt5677_ob_01_mix)),
+	SND_SOC_DAPM_MIXER("OB23 MIX", SND_SOC_NOPM, 0, 0,
+		rt5677_ob_23_mix, ARRAY_SIZE(rt5677_ob_23_mix)),
+	SND_SOC_DAPM_MIXER("OB4 MIX", SND_SOC_NOPM, 0, 0,
+		rt5677_ob_4_mix, ARRAY_SIZE(rt5677_ob_4_mix)),
+	SND_SOC_DAPM_MIXER("OB5 MIX", SND_SOC_NOPM, 0, 0,
+		rt5677_ob_5_mix, ARRAY_SIZE(rt5677_ob_5_mix)),
+	SND_SOC_DAPM_MIXER("OB6 MIX", SND_SOC_NOPM, 0, 0,
+		rt5677_ob_6_mix, ARRAY_SIZE(rt5677_ob_6_mix)),
+	SND_SOC_DAPM_MIXER("OB7 MIX", SND_SOC_NOPM, 0, 0,
+		rt5677_ob_7_mix, ARRAY_SIZE(rt5677_ob_7_mix)),
+
+	/* Output Side */
+	/* DAC mixer before sound effect */
+	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
+		rt5677_dac_l_mix, ARRAY_SIZE(rt5677_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+		rt5677_dac_r_mix, ARRAY_SIZE(rt5677_dac_r_mix)),
+	SND_SOC_DAPM_PGA("DAC1 FS", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* DAC Mux */
+	SND_SOC_DAPM_MUX("DAC1 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_dac1_mux),
+	SND_SOC_DAPM_MUX("ADDA1 Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_adda1_mux),
+	SND_SOC_DAPM_MUX("DAC12 SRC Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_dac12_mux),
+	SND_SOC_DAPM_MUX("DAC3 SRC Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_dac3_mux),
+
+	/* DAC2 channel Mux */
+	SND_SOC_DAPM_MUX("DAC2 L Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_dac2_l_mux),
+	SND_SOC_DAPM_MUX("DAC2 R Mux", SND_SOC_NOPM, 0, 0,
+				&rt5677_dac2_r_mux),
+
+	/* DAC3 channel Mux */
+	SND_SOC_DAPM_MUX("DAC3 L Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_dac3_l_mux),
+	SND_SOC_DAPM_MUX("DAC3 R Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_dac3_r_mux),
+
+	/* DAC4 channel Mux */
+	SND_SOC_DAPM_MUX("DAC4 L Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_dac4_l_mux),
+	SND_SOC_DAPM_MUX("DAC4 R Mux", SND_SOC_NOPM, 0, 0,
+			&rt5677_dac4_r_mux),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5677_PWR_DIG2,
+		RT5677_PWR_DAC_S1F_BIT, 0, rt5677_filter_power_event,
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("dac mono2 left filter", RT5677_PWR_DIG2,
+		RT5677_PWR_DAC_M2F_L_BIT, 0, rt5677_filter_power_event,
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("dac mono2 right filter", RT5677_PWR_DIG2,
+		RT5677_PWR_DAC_M2F_R_BIT, 0, rt5677_filter_power_event,
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("dac mono3 left filter", RT5677_PWR_DIG2,
+		RT5677_PWR_DAC_M3F_L_BIT, 0, rt5677_filter_power_event,
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("dac mono3 right filter", RT5677_PWR_DIG2,
+		RT5677_PWR_DAC_M3F_R_BIT, 0, rt5677_filter_power_event,
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("dac mono4 left filter", RT5677_PWR_DIG2,
+		RT5677_PWR_DAC_M4F_L_BIT, 0, rt5677_filter_power_event,
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("dac mono4 right filter", RT5677_PWR_DIG2,
+		RT5677_PWR_DAC_M4F_R_BIT, 0, rt5677_filter_power_event,
+		SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5677_sto1_dac_l_mix, ARRAY_SIZE(rt5677_sto1_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5677_sto1_dac_r_mix, ARRAY_SIZE(rt5677_sto1_dac_r_mix)),
+	SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5677_mono_dac_l_mix, ARRAY_SIZE(rt5677_mono_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5677_mono_dac_r_mix, ARRAY_SIZE(rt5677_mono_dac_r_mix)),
+	SND_SOC_DAPM_MIXER("DD1 MIXL", SND_SOC_NOPM, 0, 0,
+		rt5677_dd1_l_mix, ARRAY_SIZE(rt5677_dd1_l_mix)),
+	SND_SOC_DAPM_MIXER("DD1 MIXR", SND_SOC_NOPM, 0, 0,
+		rt5677_dd1_r_mix, ARRAY_SIZE(rt5677_dd1_r_mix)),
+	SND_SOC_DAPM_MIXER("DD2 MIXL", SND_SOC_NOPM, 0, 0,
+		rt5677_dd2_l_mix, ARRAY_SIZE(rt5677_dd2_l_mix)),
+	SND_SOC_DAPM_MIXER("DD2 MIXR", SND_SOC_NOPM, 0, 0,
+		rt5677_dd2_r_mix, ARRAY_SIZE(rt5677_dd2_r_mix)),
+	SND_SOC_DAPM_PGA("Stereo DAC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono DAC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DD1 MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DD2 MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC 1", NULL, RT5677_PWR_DIG1,
+		RT5677_PWR_DAC1_BIT, 0),
+	SND_SOC_DAPM_DAC("DAC 2", NULL, RT5677_PWR_DIG1,
+		RT5677_PWR_DAC2_BIT, 0),
+	SND_SOC_DAPM_DAC("DAC 3", NULL, RT5677_PWR_DIG1,
+		RT5677_PWR_DAC3_BIT, 0),
+
+	/* PDM */
+	SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5677_PWR_DIG2,
+		RT5677_PWR_PDM1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5677_PWR_DIG2,
+		RT5677_PWR_PDM2_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("PDM1 L Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM1_L_SFT,
+		1, &rt5677_pdm1_l_mux),
+	SND_SOC_DAPM_MUX("PDM1 R Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM1_R_SFT,
+		1, &rt5677_pdm1_r_mux),
+	SND_SOC_DAPM_MUX("PDM2 L Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM2_L_SFT,
+		1, &rt5677_pdm2_l_mux),
+	SND_SOC_DAPM_MUX("PDM2 R Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM2_R_SFT,
+		1, &rt5677_pdm2_r_mux),
+
+	SND_SOC_DAPM_PGA_S("LOUT1 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO1_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("LOUT2 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO2_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_PGA_S("LOUT3 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO3_BIT,
+		0, NULL, 0),
+
+	SND_SOC_DAPM_PGA_S("LOUT1 vref", 1, SND_SOC_NOPM, 0, 0,
+		rt5677_vref_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("LOUT2 vref", 1, SND_SOC_NOPM, 0, 0,
+		rt5677_vref_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("LOUT3 vref", 1, SND_SOC_NOPM, 0, 0,
+		rt5677_vref_event, SND_SOC_DAPM_POST_PMU),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("LOUT1"),
+	SND_SOC_DAPM_OUTPUT("LOUT2"),
+	SND_SOC_DAPM_OUTPUT("LOUT3"),
+	SND_SOC_DAPM_OUTPUT("PDM1L"),
+	SND_SOC_DAPM_OUTPUT("PDM1R"),
+	SND_SOC_DAPM_OUTPUT("PDM2L"),
+	SND_SOC_DAPM_OUTPUT("PDM2R"),
+
+	SND_SOC_DAPM_POST("vref", rt5677_vref_event),
+};
+
+static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
+	{ "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", rt5677_dmic_use_asrc },
+	{ "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", rt5677_dmic_use_asrc },
+	{ "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", rt5677_dmic_use_asrc },
+	{ "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", rt5677_dmic_use_asrc },
+	{ "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", rt5677_dmic_use_asrc },
+	{ "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", rt5677_dmic_use_asrc },
+	{ "I2S1", NULL, "I2S1 ASRC", can_use_asrc},
+	{ "I2S2", NULL, "I2S2 ASRC", can_use_asrc},
+	{ "I2S3", NULL, "I2S3 ASRC", can_use_asrc},
+	{ "I2S4", NULL, "I2S4 ASRC", can_use_asrc},
+
+	{ "dac stereo1 filter", NULL, "DAC STO ASRC", is_using_asrc },
+	{ "dac mono2 left filter", NULL, "DAC MONO2 L ASRC", is_using_asrc },
+	{ "dac mono2 right filter", NULL, "DAC MONO2 R ASRC", is_using_asrc },
+	{ "dac mono3 left filter", NULL, "DAC MONO3 L ASRC", is_using_asrc },
+	{ "dac mono3 right filter", NULL, "DAC MONO3 R ASRC", is_using_asrc },
+	{ "dac mono4 left filter", NULL, "DAC MONO4 L ASRC", is_using_asrc },
+	{ "dac mono4 right filter", NULL, "DAC MONO4 R ASRC", is_using_asrc },
+	{ "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc },
+	{ "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc },
+	{ "adc stereo3 filter", NULL, "ADC STO3 ASRC", is_using_asrc },
+	{ "adc stereo4 filter", NULL, "ADC STO4 ASRC", is_using_asrc },
+	{ "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc },
+	{ "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc },
+
+	{ "DMIC1", NULL, "DMIC L1" },
+	{ "DMIC1", NULL, "DMIC R1" },
+	{ "DMIC2", NULL, "DMIC L2" },
+	{ "DMIC2", NULL, "DMIC R2" },
+	{ "DMIC3", NULL, "DMIC L3" },
+	{ "DMIC3", NULL, "DMIC R3" },
+	{ "DMIC4", NULL, "DMIC L4" },
+	{ "DMIC4", NULL, "DMIC R4" },
+
+	{ "DMIC L1", NULL, "DMIC CLK" },
+	{ "DMIC R1", NULL, "DMIC CLK" },
+	{ "DMIC L2", NULL, "DMIC CLK" },
+	{ "DMIC R2", NULL, "DMIC CLK" },
+	{ "DMIC L3", NULL, "DMIC CLK" },
+	{ "DMIC R3", NULL, "DMIC CLK" },
+	{ "DMIC L4", NULL, "DMIC CLK" },
+	{ "DMIC R4", NULL, "DMIC CLK" },
+
+	{ "DMIC L1", NULL, "DMIC1 power" },
+	{ "DMIC R1", NULL, "DMIC1 power" },
+	{ "DMIC L3", NULL, "DMIC3 power" },
+	{ "DMIC R3", NULL, "DMIC3 power" },
+	{ "DMIC L4", NULL, "DMIC4 power" },
+	{ "DMIC R4", NULL, "DMIC4 power" },
+
+	{ "BST1", NULL, "IN1P" },
+	{ "BST1", NULL, "IN1N" },
+	{ "BST2", NULL, "IN2P" },
+	{ "BST2", NULL, "IN2N" },
+
+	{ "IN1P", NULL, "MICBIAS1" },
+	{ "IN1N", NULL, "MICBIAS1" },
+	{ "IN2P", NULL, "MICBIAS1" },
+	{ "IN2N", NULL, "MICBIAS1" },
+
+	{ "ADC 1", NULL, "BST1" },
+	{ "ADC 1", NULL, "ADC 1 power" },
+	{ "ADC 1", NULL, "ADC1 clock" },
+	{ "ADC 2", NULL, "BST2" },
+	{ "ADC 2", NULL, "ADC 2 power" },
+	{ "ADC 2", NULL, "ADC2 clock" },
+
+	{ "Stereo1 DMIC Mux", "DMIC1", "DMIC1" },
+	{ "Stereo1 DMIC Mux", "DMIC2", "DMIC2" },
+	{ "Stereo1 DMIC Mux", "DMIC3", "DMIC3" },
+	{ "Stereo1 DMIC Mux", "DMIC4", "DMIC4" },
+
+	{ "Stereo2 DMIC Mux", "DMIC1", "DMIC1" },
+	{ "Stereo2 DMIC Mux", "DMIC2", "DMIC2" },
+	{ "Stereo2 DMIC Mux", "DMIC3", "DMIC3" },
+	{ "Stereo2 DMIC Mux", "DMIC4", "DMIC4" },
+
+	{ "Stereo3 DMIC Mux", "DMIC1", "DMIC1" },
+	{ "Stereo3 DMIC Mux", "DMIC2", "DMIC2" },
+	{ "Stereo3 DMIC Mux", "DMIC3", "DMIC3" },
+	{ "Stereo3 DMIC Mux", "DMIC4", "DMIC4" },
+
+	{ "Stereo4 DMIC Mux", "DMIC1", "DMIC1" },
+	{ "Stereo4 DMIC Mux", "DMIC2", "DMIC2" },
+	{ "Stereo4 DMIC Mux", "DMIC3", "DMIC3" },
+	{ "Stereo4 DMIC Mux", "DMIC4", "DMIC4" },
+
+	{ "Mono DMIC L Mux", "DMIC1", "DMIC1" },
+	{ "Mono DMIC L Mux", "DMIC2", "DMIC2" },
+	{ "Mono DMIC L Mux", "DMIC3", "DMIC3" },
+	{ "Mono DMIC L Mux", "DMIC4", "DMIC4" },
+
+	{ "Mono DMIC R Mux", "DMIC1", "DMIC1" },
+	{ "Mono DMIC R Mux", "DMIC2", "DMIC2" },
+	{ "Mono DMIC R Mux", "DMIC3", "DMIC3" },
+	{ "Mono DMIC R Mux", "DMIC4", "DMIC4" },
+
+	{ "ADC 1_2", NULL, "ADC 1" },
+	{ "ADC 1_2", NULL, "ADC 2" },
+
+	{ "Stereo1 ADC1 Mux", "DD MIX1", "DD1 MIX" },
+	{ "Stereo1 ADC1 Mux", "ADC1/2", "ADC 1_2" },
+	{ "Stereo1 ADC1 Mux", "Stereo DAC MIX", "Stereo DAC MIX" },
+
+	{ "Stereo1 ADC2 Mux", "DD MIX1", "DD1 MIX" },
+	{ "Stereo1 ADC2 Mux", "DMIC", "Stereo1 DMIC Mux" },
+	{ "Stereo1 ADC2 Mux", "Stereo DAC MIX", "Stereo DAC MIX" },
+
+	{ "Stereo2 ADC1 Mux", "DD MIX1", "DD1 MIX" },
+	{ "Stereo2 ADC1 Mux", "ADC1/2", "ADC 1_2" },
+	{ "Stereo2 ADC1 Mux", "Stereo DAC MIX", "Stereo DAC MIX" },
+
+	{ "Stereo2 ADC2 Mux", "DD MIX1", "DD1 MIX" },
+	{ "Stereo2 ADC2 Mux", "DMIC", "Stereo2 DMIC Mux" },
+	{ "Stereo2 ADC2 Mux", "Stereo DAC MIX", "Stereo DAC MIX" },
+
+	{ "Stereo3 ADC1 Mux", "DD MIX1", "DD1 MIX" },
+	{ "Stereo3 ADC1 Mux", "ADC1/2", "ADC 1_2" },
+	{ "Stereo3 ADC1 Mux", "Stereo DAC MIX", "Stereo DAC MIX" },
+
+	{ "Stereo3 ADC2 Mux", "DD MIX1", "DD1 MIX" },
+	{ "Stereo3 ADC2 Mux", "DMIC", "Stereo3 DMIC Mux" },
+	{ "Stereo3 ADC2 Mux", "Stereo DAC MIX", "Stereo DAC MIX" },
+
+	{ "Stereo4 ADC1 Mux", "DD MIX1", "DD1 MIX" },
+	{ "Stereo4 ADC1 Mux", "ADC1/2", "ADC 1_2" },
+	{ "Stereo4 ADC1 Mux", "DD MIX2", "DD2 MIX" },
+
+	{ "Stereo4 ADC2 Mux", "DD MIX1", "DD1 MIX" },
+	{ "Stereo4 ADC2 Mux", "DMIC", "Stereo3 DMIC Mux" },
+	{ "Stereo4 ADC2 Mux", "DD MIX2", "DD2 MIX" },
+
+	{ "Mono ADC2 L Mux", "DD MIX1L", "DD1 MIXL" },
+	{ "Mono ADC2 L Mux", "DMIC", "Mono DMIC L Mux" },
+	{ "Mono ADC2 L Mux", "MONO DAC MIXL", "Mono DAC MIXL" },
+
+	{ "Mono ADC1 L Mux", "DD MIX1L", "DD1 MIXL" },
+	{ "Mono ADC1 L Mux", "ADC1", "ADC 1" },
+	{ "Mono ADC1 L Mux", "MONO DAC MIXL", "Mono DAC MIXL" },
+
+	{ "Mono ADC1 R Mux", "DD MIX1R", "DD1 MIXR" },
+	{ "Mono ADC1 R Mux", "ADC2", "ADC 2" },
+	{ "Mono ADC1 R Mux", "MONO DAC MIXR", "Mono DAC MIXR" },
+
+	{ "Mono ADC2 R Mux", "DD MIX1R", "DD1 MIXR" },
+	{ "Mono ADC2 R Mux", "DMIC", "Mono DMIC R Mux" },
+	{ "Mono ADC2 R Mux", "MONO DAC MIXR", "Mono DAC MIXR" },
+
+	{ "Sto1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC1 Mux" },
+	{ "Sto1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC2 Mux" },
+	{ "Sto1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC1 Mux" },
+	{ "Sto1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC2 Mux" },
+
+	{ "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" },
+	{ "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" },
+	{ "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" },
+	{ "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" },
+	{ "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL" },
+	{ "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR" },
+
+	{ "Sto2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC1 Mux" },
+	{ "Sto2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC2 Mux" },
+	{ "Sto2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC1 Mux" },
+	{ "Sto2 ADC MIXR", "ADC2 Switch", "Stereo2 ADC2 Mux" },
+
+	{ "Sto2 ADC LR MIX", NULL, "Sto2 ADC MIXL" },
+	{ "Sto2 ADC LR MIX", NULL, "Sto2 ADC MIXR" },
+
+	{ "Stereo2 ADC LR Mux", "L", "Sto2 ADC MIXL" },
+	{ "Stereo2 ADC LR Mux", "LR", "Sto2 ADC LR MIX" },
+
+	{ "Stereo2 ADC MIXL", NULL, "Stereo2 ADC LR Mux" },
+	{ "Stereo2 ADC MIXL", NULL, "adc stereo2 filter" },
+	{ "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" },
+	{ "Stereo2 ADC MIXR", NULL, "adc stereo2 filter" },
+	{ "adc stereo2 filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXL" },
+	{ "Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXR" },
+
+	{ "Sto3 ADC MIXL", "ADC1 Switch", "Stereo3 ADC1 Mux" },
+	{ "Sto3 ADC MIXL", "ADC2 Switch", "Stereo3 ADC2 Mux" },
+	{ "Sto3 ADC MIXR", "ADC1 Switch", "Stereo3 ADC1 Mux" },
+	{ "Sto3 ADC MIXR", "ADC2 Switch", "Stereo3 ADC2 Mux" },
+
+	{ "Stereo3 ADC MIXL", NULL, "Sto3 ADC MIXL" },
+	{ "Stereo3 ADC MIXL", NULL, "adc stereo3 filter" },
+	{ "Stereo3 ADC MIXR", NULL, "Sto3 ADC MIXR" },
+	{ "Stereo3 ADC MIXR", NULL, "adc stereo3 filter" },
+	{ "adc stereo3 filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "Stereo3 ADC MIX", NULL, "Stereo3 ADC MIXL" },
+	{ "Stereo3 ADC MIX", NULL, "Stereo3 ADC MIXR" },
+
+	{ "Sto4 ADC MIXL", "ADC1 Switch", "Stereo4 ADC1 Mux" },
+	{ "Sto4 ADC MIXL", "ADC2 Switch", "Stereo4 ADC2 Mux" },
+	{ "Sto4 ADC MIXR", "ADC1 Switch", "Stereo4 ADC1 Mux" },
+	{ "Sto4 ADC MIXR", "ADC2 Switch", "Stereo4 ADC2 Mux" },
+
+	{ "Stereo4 ADC MIXL", NULL, "Sto4 ADC MIXL" },
+	{ "Stereo4 ADC MIXL", NULL, "adc stereo4 filter" },
+	{ "Stereo4 ADC MIXR", NULL, "Sto4 ADC MIXR" },
+	{ "Stereo4 ADC MIXR", NULL, "adc stereo4 filter" },
+	{ "adc stereo4 filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "Stereo4 ADC MIX", NULL, "Stereo4 ADC MIXL" },
+	{ "Stereo4 ADC MIX", NULL, "Stereo4 ADC MIXR" },
+
+	{ "Mono ADC MIXL", "ADC1 Switch", "Mono ADC1 L Mux" },
+	{ "Mono ADC MIXL", "ADC2 Switch", "Mono ADC2 L Mux" },
+	{ "Mono ADC MIXL", NULL, "adc mono left filter" },
+	{ "adc mono left filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "Mono ADC MIXR", "ADC1 Switch", "Mono ADC1 R Mux" },
+	{ "Mono ADC MIXR", "ADC2 Switch", "Mono ADC2 R Mux" },
+	{ "Mono ADC MIXR", NULL, "adc mono right filter" },
+	{ "adc mono right filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "Mono ADC MIX", NULL, "Mono ADC MIXL" },
+	{ "Mono ADC MIX", NULL, "Mono ADC MIXR" },
+
+	{ "VAD ADC Mux", "STO1 ADC MIX L", "Stereo1 ADC MIXL" },
+	{ "VAD ADC Mux", "MONO ADC MIX L", "Mono ADC MIXL" },
+	{ "VAD ADC Mux", "MONO ADC MIX R", "Mono ADC MIXR" },
+	{ "VAD ADC Mux", "STO2 ADC MIX L", "Stereo2 ADC MIXL" },
+	{ "VAD ADC Mux", "STO3 ADC MIX L", "Stereo3 ADC MIXL" },
+
+	{ "IF1 ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
+	{ "IF1 ADC1 Mux", "OB01", "OB01 Bypass Mux" },
+	{ "IF1 ADC1 Mux", "VAD ADC", "VAD ADC Mux" },
+
+	{ "IF1 ADC2 Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" },
+	{ "IF1 ADC2 Mux", "OB23", "OB23 Bypass Mux" },
+
+	{ "IF1 ADC3 Mux", "STO3 ADC MIX", "Stereo3 ADC MIX" },
+	{ "IF1 ADC3 Mux", "MONO ADC MIX", "Mono ADC MIX" },
+	{ "IF1 ADC3 Mux", "OB45", "OB45" },
+
+	{ "IF1 ADC4 Mux", "STO4 ADC MIX", "Stereo4 ADC MIX" },
+	{ "IF1 ADC4 Mux", "OB67", "OB67" },
+	{ "IF1 ADC4 Mux", "OB01", "OB01 Bypass Mux" },
+
+	{ "IF1 ADC1 Swap Mux", "L/R", "IF1 ADC1 Mux" },
+	{ "IF1 ADC1 Swap Mux", "R/L", "IF1 ADC1 Mux" },
+	{ "IF1 ADC1 Swap Mux", "L/L", "IF1 ADC1 Mux" },
+	{ "IF1 ADC1 Swap Mux", "R/R", "IF1 ADC1 Mux" },
+
+	{ "IF1 ADC2 Swap Mux", "L/R", "IF1 ADC2 Mux" },
+	{ "IF1 ADC2 Swap Mux", "R/L", "IF1 ADC2 Mux" },
+	{ "IF1 ADC2 Swap Mux", "L/L", "IF1 ADC2 Mux" },
+	{ "IF1 ADC2 Swap Mux", "R/R", "IF1 ADC2 Mux" },
+
+	{ "IF1 ADC3 Swap Mux", "L/R", "IF1 ADC3 Mux" },
+	{ "IF1 ADC3 Swap Mux", "R/L", "IF1 ADC3 Mux" },
+	{ "IF1 ADC3 Swap Mux", "L/L", "IF1 ADC3 Mux" },
+	{ "IF1 ADC3 Swap Mux", "R/R", "IF1 ADC3 Mux" },
+
+	{ "IF1 ADC4 Swap Mux", "L/R", "IF1 ADC4 Mux" },
+	{ "IF1 ADC4 Swap Mux", "R/L", "IF1 ADC4 Mux" },
+	{ "IF1 ADC4 Swap Mux", "L/L", "IF1 ADC4 Mux" },
+	{ "IF1 ADC4 Swap Mux", "R/R", "IF1 ADC4 Mux" },
+
+	{ "IF1 ADC", NULL, "IF1 ADC1 Swap Mux" },
+	{ "IF1 ADC", NULL, "IF1 ADC2 Swap Mux" },
+	{ "IF1 ADC", NULL, "IF1 ADC3 Swap Mux" },
+	{ "IF1 ADC", NULL, "IF1 ADC4 Swap Mux" },
+
+	{ "IF1 ADC TDM Swap Mux", "1/2/3/4", "IF1 ADC" },
+	{ "IF1 ADC TDM Swap Mux", "2/1/3/4", "IF1 ADC" },
+	{ "IF1 ADC TDM Swap Mux", "2/3/1/4", "IF1 ADC" },
+	{ "IF1 ADC TDM Swap Mux", "4/1/2/3", "IF1 ADC" },
+	{ "IF1 ADC TDM Swap Mux", "1/3/2/4", "IF1 ADC" },
+	{ "IF1 ADC TDM Swap Mux", "1/4/2/3", "IF1 ADC" },
+	{ "IF1 ADC TDM Swap Mux", "3/1/2/4", "IF1 ADC" },
+	{ "IF1 ADC TDM Swap Mux", "3/4/1/2", "IF1 ADC" },
+
+	{ "AIF1TX", NULL, "I2S1" },
+	{ "AIF1TX", NULL, "IF1 ADC TDM Swap Mux" },
+
+	{ "IF2 ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
+	{ "IF2 ADC1 Mux", "OB01", "OB01 Bypass Mux" },
+	{ "IF2 ADC1 Mux", "VAD ADC", "VAD ADC Mux" },
+
+	{ "IF2 ADC2 Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" },
+	{ "IF2 ADC2 Mux", "OB23", "OB23 Bypass Mux" },
+
+	{ "IF2 ADC3 Mux", "STO3 ADC MIX", "Stereo3 ADC MIX" },
+	{ "IF2 ADC3 Mux", "MONO ADC MIX", "Mono ADC MIX" },
+	{ "IF2 ADC3 Mux", "OB45", "OB45" },
+
+	{ "IF2 ADC4 Mux", "STO4 ADC MIX", "Stereo4 ADC MIX" },
+	{ "IF2 ADC4 Mux", "OB67", "OB67" },
+	{ "IF2 ADC4 Mux", "OB01", "OB01 Bypass Mux" },
+
+	{ "IF2 ADC1 Swap Mux", "L/R", "IF2 ADC1 Mux" },
+	{ "IF2 ADC1 Swap Mux", "R/L", "IF2 ADC1 Mux" },
+	{ "IF2 ADC1 Swap Mux", "L/L", "IF2 ADC1 Mux" },
+	{ "IF2 ADC1 Swap Mux", "R/R", "IF2 ADC1 Mux" },
+
+	{ "IF2 ADC2 Swap Mux", "L/R", "IF2 ADC2 Mux" },
+	{ "IF2 ADC2 Swap Mux", "R/L", "IF2 ADC2 Mux" },
+	{ "IF2 ADC2 Swap Mux", "L/L", "IF2 ADC2 Mux" },
+	{ "IF2 ADC2 Swap Mux", "R/R", "IF2 ADC2 Mux" },
+
+	{ "IF2 ADC3 Swap Mux", "L/R", "IF2 ADC3 Mux" },
+	{ "IF2 ADC3 Swap Mux", "R/L", "IF2 ADC3 Mux" },
+	{ "IF2 ADC3 Swap Mux", "L/L", "IF2 ADC3 Mux" },
+	{ "IF2 ADC3 Swap Mux", "R/R", "IF2 ADC3 Mux" },
+
+	{ "IF2 ADC4 Swap Mux", "L/R", "IF2 ADC4 Mux" },
+	{ "IF2 ADC4 Swap Mux", "R/L", "IF2 ADC4 Mux" },
+	{ "IF2 ADC4 Swap Mux", "L/L", "IF2 ADC4 Mux" },
+	{ "IF2 ADC4 Swap Mux", "R/R", "IF2 ADC4 Mux" },
+
+	{ "IF2 ADC", NULL, "IF2 ADC1 Swap Mux" },
+	{ "IF2 ADC", NULL, "IF2 ADC2 Swap Mux" },
+	{ "IF2 ADC", NULL, "IF2 ADC3 Swap Mux" },
+	{ "IF2 ADC", NULL, "IF2 ADC4 Swap Mux" },
+
+	{ "IF2 ADC TDM Swap Mux", "1/2/3/4", "IF2 ADC" },
+	{ "IF2 ADC TDM Swap Mux", "2/1/3/4", "IF2 ADC" },
+	{ "IF2 ADC TDM Swap Mux", "3/1/2/4", "IF2 ADC" },
+	{ "IF2 ADC TDM Swap Mux", "4/1/2/3", "IF2 ADC" },
+	{ "IF2 ADC TDM Swap Mux", "1/3/2/4", "IF2 ADC" },
+	{ "IF2 ADC TDM Swap Mux", "1/4/2/3", "IF2 ADC" },
+	{ "IF2 ADC TDM Swap Mux", "2/3/1/4", "IF2 ADC" },
+	{ "IF2 ADC TDM Swap Mux", "3/4/1/2", "IF2 ADC" },
+
+	{ "AIF2TX", NULL, "I2S2" },
+	{ "AIF2TX", NULL, "IF2 ADC TDM Swap Mux" },
+
+	{ "IF3 ADC Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
+	{ "IF3 ADC Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" },
+	{ "IF3 ADC Mux", "STO3 ADC MIX", "Stereo3 ADC MIX" },
+	{ "IF3 ADC Mux", "STO4 ADC MIX", "Stereo4 ADC MIX" },
+	{ "IF3 ADC Mux", "MONO ADC MIX", "Mono ADC MIX" },
+	{ "IF3 ADC Mux", "OB01", "OB01 Bypass Mux" },
+	{ "IF3 ADC Mux", "OB23", "OB23 Bypass Mux" },
+	{ "IF3 ADC Mux", "VAD ADC", "VAD ADC Mux" },
+
+	{ "AIF3TX", NULL, "I2S3" },
+	{ "AIF3TX", NULL, "IF3 ADC Mux" },
+
+	{ "IF4 ADC Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
+	{ "IF4 ADC Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" },
+	{ "IF4 ADC Mux", "STO3 ADC MIX", "Stereo3 ADC MIX" },
+	{ "IF4 ADC Mux", "STO4 ADC MIX", "Stereo4 ADC MIX" },
+	{ "IF4 ADC Mux", "MONO ADC MIX", "Mono ADC MIX" },
+	{ "IF4 ADC Mux", "OB01", "OB01 Bypass Mux" },
+	{ "IF4 ADC Mux", "OB23", "OB23 Bypass Mux" },
+	{ "IF4 ADC Mux", "VAD ADC", "VAD ADC Mux" },
+
+	{ "AIF4TX", NULL, "I2S4" },
+	{ "AIF4TX", NULL, "IF4 ADC Mux" },
+
+	{ "SLB ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
+	{ "SLB ADC1 Mux", "OB01", "OB01 Bypass Mux" },
+	{ "SLB ADC1 Mux", "VAD ADC", "VAD ADC Mux" },
+
+	{ "SLB ADC2 Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" },
+	{ "SLB ADC2 Mux", "OB23", "OB23 Bypass Mux" },
+
+	{ "SLB ADC3 Mux", "STO3 ADC MIX", "Stereo3 ADC MIX" },
+	{ "SLB ADC3 Mux", "MONO ADC MIX", "Mono ADC MIX" },
+	{ "SLB ADC3 Mux", "OB45", "OB45" },
+
+	{ "SLB ADC4 Mux", "STO4 ADC MIX", "Stereo4 ADC MIX" },
+	{ "SLB ADC4 Mux", "OB67", "OB67" },
+	{ "SLB ADC4 Mux", "OB01", "OB01 Bypass Mux" },
+
+	{ "SLBTX", NULL, "SLB" },
+	{ "SLBTX", NULL, "SLB ADC1 Mux" },
+	{ "SLBTX", NULL, "SLB ADC2 Mux" },
+	{ "SLBTX", NULL, "SLB ADC3 Mux" },
+	{ "SLBTX", NULL, "SLB ADC4 Mux" },
+
+	{ "IB01 Mux", "IF1 DAC 01", "IF1 DAC01" },
+	{ "IB01 Mux", "IF2 DAC 01", "IF2 DAC01" },
+	{ "IB01 Mux", "SLB DAC 01", "SLB DAC01" },
+	{ "IB01 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
+	{ "IB01 Mux", "VAD ADC/DAC1 FS", "DAC1 FS" },
+
+	{ "IB01 Bypass Mux", "Bypass", "IB01 Mux" },
+	{ "IB01 Bypass Mux", "Pass SRC", "IB01 Mux" },
+
+	{ "IB23 Mux", "IF1 DAC 23", "IF1 DAC23" },
+	{ "IB23 Mux", "IF2 DAC 23", "IF2 DAC23" },
+	{ "IB23 Mux", "SLB DAC 23", "SLB DAC23" },
+	{ "IB23 Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" },
+	{ "IB23 Mux", "DAC1 FS", "DAC1 FS" },
+	{ "IB23 Mux", "IF4 DAC", "IF4 DAC" },
+
+	{ "IB23 Bypass Mux", "Bypass", "IB23 Mux" },
+	{ "IB23 Bypass Mux", "Pass SRC", "IB23 Mux" },
+
+	{ "IB45 Mux", "IF1 DAC 45", "IF1 DAC45" },
+	{ "IB45 Mux", "IF2 DAC 45", "IF2 DAC45" },
+	{ "IB45 Mux", "SLB DAC 45", "SLB DAC45" },
+	{ "IB45 Mux", "STO3 ADC MIX", "Stereo3 ADC MIX" },
+	{ "IB45 Mux", "IF3 DAC", "IF3 DAC" },
+
+	{ "IB45 Bypass Mux", "Bypass", "IB45 Mux" },
+	{ "IB45 Bypass Mux", "Pass SRC", "IB45 Mux" },
+
+	{ "IB6 Mux", "IF1 DAC 6", "IF1 DAC6 Mux" },
+	{ "IB6 Mux", "IF2 DAC 6", "IF2 DAC6 Mux" },
+	{ "IB6 Mux", "SLB DAC 6", "SLB DAC6" },
+	{ "IB6 Mux", "STO4 ADC MIX L", "Stereo4 ADC MIXL" },
+	{ "IB6 Mux", "IF4 DAC L", "IF4 DAC L" },
+	{ "IB6 Mux", "STO1 ADC MIX L", "Stereo1 ADC MIXL" },
+	{ "IB6 Mux", "STO2 ADC MIX L", "Stereo2 ADC MIXL" },
+	{ "IB6 Mux", "STO3 ADC MIX L", "Stereo3 ADC MIXL" },
+
+	{ "IB7 Mux", "IF1 DAC 7", "IF1 DAC7 Mux" },
+	{ "IB7 Mux", "IF2 DAC 7", "IF2 DAC7 Mux" },
+	{ "IB7 Mux", "SLB DAC 7", "SLB DAC7" },
+	{ "IB7 Mux", "STO4 ADC MIX R", "Stereo4 ADC MIXR" },
+	{ "IB7 Mux", "IF4 DAC R", "IF4 DAC R" },
+	{ "IB7 Mux", "STO1 ADC MIX R", "Stereo1 ADC MIXR" },
+	{ "IB7 Mux", "STO2 ADC MIX R", "Stereo2 ADC MIXR" },
+	{ "IB7 Mux", "STO3 ADC MIX R", "Stereo3 ADC MIXR" },
+
+	{ "IB8 Mux", "STO1 ADC MIX L", "Stereo1 ADC MIXL" },
+	{ "IB8 Mux", "STO2 ADC MIX L", "Stereo2 ADC MIXL" },
+	{ "IB8 Mux", "STO3 ADC MIX L", "Stereo3 ADC MIXL" },
+	{ "IB8 Mux", "STO4 ADC MIX L", "Stereo4 ADC MIXL" },
+	{ "IB8 Mux", "MONO ADC MIX L", "Mono ADC MIXL" },
+	{ "IB8 Mux", "DACL1 FS", "DAC1 MIXL" },
+
+	{ "IB9 Mux", "STO1 ADC MIX R", "Stereo1 ADC MIXR" },
+	{ "IB9 Mux", "STO2 ADC MIX R", "Stereo2 ADC MIXR" },
+	{ "IB9 Mux", "STO3 ADC MIX R", "Stereo3 ADC MIXR" },
+	{ "IB9 Mux", "STO4 ADC MIX R", "Stereo4 ADC MIXR" },
+	{ "IB9 Mux", "MONO ADC MIX R", "Mono ADC MIXR" },
+	{ "IB9 Mux", "DACR1 FS", "DAC1 MIXR" },
+	{ "IB9 Mux", "DAC1 FS", "DAC1 FS" },
+
+	{ "OB01 MIX", "IB01 Switch", "IB01 Bypass Mux" },
+	{ "OB01 MIX", "IB23 Switch", "IB23 Bypass Mux" },
+	{ "OB01 MIX", "IB45 Switch", "IB45 Bypass Mux" },
+	{ "OB01 MIX", "IB6 Switch", "IB6 Mux" },
+	{ "OB01 MIX", "IB7 Switch", "IB7 Mux" },
+	{ "OB01 MIX", "IB8 Switch", "IB8 Mux" },
+	{ "OB01 MIX", "IB9 Switch", "IB9 Mux" },
+
+	{ "OB23 MIX", "IB01 Switch", "IB01 Bypass Mux" },
+	{ "OB23 MIX", "IB23 Switch", "IB23 Bypass Mux" },
+	{ "OB23 MIX", "IB45 Switch", "IB45 Bypass Mux" },
+	{ "OB23 MIX", "IB6 Switch", "IB6 Mux" },
+	{ "OB23 MIX", "IB7 Switch", "IB7 Mux" },
+	{ "OB23 MIX", "IB8 Switch", "IB8 Mux" },
+	{ "OB23 MIX", "IB9 Switch", "IB9 Mux" },
+
+	{ "OB4 MIX", "IB01 Switch", "IB01 Bypass Mux" },
+	{ "OB4 MIX", "IB23 Switch", "IB23 Bypass Mux" },
+	{ "OB4 MIX", "IB45 Switch", "IB45 Bypass Mux" },
+	{ "OB4 MIX", "IB6 Switch", "IB6 Mux" },
+	{ "OB4 MIX", "IB7 Switch", "IB7 Mux" },
+	{ "OB4 MIX", "IB8 Switch", "IB8 Mux" },
+	{ "OB4 MIX", "IB9 Switch", "IB9 Mux" },
+
+	{ "OB5 MIX", "IB01 Switch", "IB01 Bypass Mux" },
+	{ "OB5 MIX", "IB23 Switch", "IB23 Bypass Mux" },
+	{ "OB5 MIX", "IB45 Switch", "IB45 Bypass Mux" },
+	{ "OB5 MIX", "IB6 Switch", "IB6 Mux" },
+	{ "OB5 MIX", "IB7 Switch", "IB7 Mux" },
+	{ "OB5 MIX", "IB8 Switch", "IB8 Mux" },
+	{ "OB5 MIX", "IB9 Switch", "IB9 Mux" },
+
+	{ "OB6 MIX", "IB01 Switch", "IB01 Bypass Mux" },
+	{ "OB6 MIX", "IB23 Switch", "IB23 Bypass Mux" },
+	{ "OB6 MIX", "IB45 Switch", "IB45 Bypass Mux" },
+	{ "OB6 MIX", "IB6 Switch", "IB6 Mux" },
+	{ "OB6 MIX", "IB7 Switch", "IB7 Mux" },
+	{ "OB6 MIX", "IB8 Switch", "IB8 Mux" },
+	{ "OB6 MIX", "IB9 Switch", "IB9 Mux" },
+
+	{ "OB7 MIX", "IB01 Switch", "IB01 Bypass Mux" },
+	{ "OB7 MIX", "IB23 Switch", "IB23 Bypass Mux" },
+	{ "OB7 MIX", "IB45 Switch", "IB45 Bypass Mux" },
+	{ "OB7 MIX", "IB6 Switch", "IB6 Mux" },
+	{ "OB7 MIX", "IB7 Switch", "IB7 Mux" },
+	{ "OB7 MIX", "IB8 Switch", "IB8 Mux" },
+	{ "OB7 MIX", "IB9 Switch", "IB9 Mux" },
+
+	{ "OB01 Bypass Mux", "Bypass", "OB01 MIX" },
+	{ "OB01 Bypass Mux", "Pass SRC", "OB01 MIX" },
+	{ "OB23 Bypass Mux", "Bypass", "OB23 MIX" },
+	{ "OB23 Bypass Mux", "Pass SRC", "OB23 MIX" },
+
+	{ "OutBound2", NULL, "OB23 Bypass Mux" },
+	{ "OutBound3", NULL, "OB23 Bypass Mux" },
+	{ "OutBound4", NULL, "OB4 MIX" },
+	{ "OutBound5", NULL, "OB5 MIX" },
+	{ "OutBound6", NULL, "OB6 MIX" },
+	{ "OutBound7", NULL, "OB7 MIX" },
+
+	{ "OB45", NULL, "OutBound4" },
+	{ "OB45", NULL, "OutBound5" },
+	{ "OB67", NULL, "OutBound6" },
+	{ "OB67", NULL, "OutBound7" },
+
+	{ "IF1 DAC0", NULL, "AIF1RX" },
+	{ "IF1 DAC1", NULL, "AIF1RX" },
+	{ "IF1 DAC2", NULL, "AIF1RX" },
+	{ "IF1 DAC3", NULL, "AIF1RX" },
+	{ "IF1 DAC4", NULL, "AIF1RX" },
+	{ "IF1 DAC5", NULL, "AIF1RX" },
+	{ "IF1 DAC6", NULL, "AIF1RX" },
+	{ "IF1 DAC7", NULL, "AIF1RX" },
+	{ "IF1 DAC0", NULL, "I2S1" },
+	{ "IF1 DAC1", NULL, "I2S1" },
+	{ "IF1 DAC2", NULL, "I2S1" },
+	{ "IF1 DAC3", NULL, "I2S1" },
+	{ "IF1 DAC4", NULL, "I2S1" },
+	{ "IF1 DAC5", NULL, "I2S1" },
+	{ "IF1 DAC6", NULL, "I2S1" },
+	{ "IF1 DAC7", NULL, "I2S1" },
+
+	{ "IF1 DAC0 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC0 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC0 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC0 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC0 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC0 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC0 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC0 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC1 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC1 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC1 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC1 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC1 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC1 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC1 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC1 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC2 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC2 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC2 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC2 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC2 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC2 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC2 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC2 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC3 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC3 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC3 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC3 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC3 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC3 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC3 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC3 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC4 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC4 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC4 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC4 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC4 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC4 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC4 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC4 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC5 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC5 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC5 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC5 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC5 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC5 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC5 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC5 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC6 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC6 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC6 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC6 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC6 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC6 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC6 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC6 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC7 Mux", "Slot0", "IF1 DAC0" },
+	{ "IF1 DAC7 Mux", "Slot1", "IF1 DAC1" },
+	{ "IF1 DAC7 Mux", "Slot2", "IF1 DAC2" },
+	{ "IF1 DAC7 Mux", "Slot3", "IF1 DAC3" },
+	{ "IF1 DAC7 Mux", "Slot4", "IF1 DAC4" },
+	{ "IF1 DAC7 Mux", "Slot5", "IF1 DAC5" },
+	{ "IF1 DAC7 Mux", "Slot6", "IF1 DAC6" },
+	{ "IF1 DAC7 Mux", "Slot7", "IF1 DAC7" },
+
+	{ "IF1 DAC01", NULL, "IF1 DAC0 Mux" },
+	{ "IF1 DAC01", NULL, "IF1 DAC1 Mux" },
+	{ "IF1 DAC23", NULL, "IF1 DAC2 Mux" },
+	{ "IF1 DAC23", NULL, "IF1 DAC3 Mux" },
+	{ "IF1 DAC45", NULL, "IF1 DAC4 Mux" },
+	{ "IF1 DAC45", NULL, "IF1 DAC5 Mux" },
+	{ "IF1 DAC67", NULL, "IF1 DAC6 Mux" },
+	{ "IF1 DAC67", NULL, "IF1 DAC7 Mux" },
+
+	{ "IF2 DAC0", NULL, "AIF2RX" },
+	{ "IF2 DAC1", NULL, "AIF2RX" },
+	{ "IF2 DAC2", NULL, "AIF2RX" },
+	{ "IF2 DAC3", NULL, "AIF2RX" },
+	{ "IF2 DAC4", NULL, "AIF2RX" },
+	{ "IF2 DAC5", NULL, "AIF2RX" },
+	{ "IF2 DAC6", NULL, "AIF2RX" },
+	{ "IF2 DAC7", NULL, "AIF2RX" },
+	{ "IF2 DAC0", NULL, "I2S2" },
+	{ "IF2 DAC1", NULL, "I2S2" },
+	{ "IF2 DAC2", NULL, "I2S2" },
+	{ "IF2 DAC3", NULL, "I2S2" },
+	{ "IF2 DAC4", NULL, "I2S2" },
+	{ "IF2 DAC5", NULL, "I2S2" },
+	{ "IF2 DAC6", NULL, "I2S2" },
+	{ "IF2 DAC7", NULL, "I2S2" },
+
+	{ "IF2 DAC0 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC0 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC0 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC0 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC0 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC0 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC0 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC0 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC1 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC1 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC1 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC1 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC1 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC1 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC1 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC1 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC2 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC2 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC2 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC2 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC2 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC2 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC2 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC2 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC3 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC3 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC3 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC3 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC3 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC3 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC3 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC3 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC4 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC4 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC4 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC4 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC4 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC4 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC4 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC4 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC5 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC5 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC5 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC5 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC5 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC5 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC5 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC5 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC6 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC6 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC6 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC6 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC6 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC6 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC6 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC6 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC7 Mux", "Slot0", "IF2 DAC0" },
+	{ "IF2 DAC7 Mux", "Slot1", "IF2 DAC1" },
+	{ "IF2 DAC7 Mux", "Slot2", "IF2 DAC2" },
+	{ "IF2 DAC7 Mux", "Slot3", "IF2 DAC3" },
+	{ "IF2 DAC7 Mux", "Slot4", "IF2 DAC4" },
+	{ "IF2 DAC7 Mux", "Slot5", "IF2 DAC5" },
+	{ "IF2 DAC7 Mux", "Slot6", "IF2 DAC6" },
+	{ "IF2 DAC7 Mux", "Slot7", "IF2 DAC7" },
+
+	{ "IF2 DAC01", NULL, "IF2 DAC0 Mux" },
+	{ "IF2 DAC01", NULL, "IF2 DAC1 Mux" },
+	{ "IF2 DAC23", NULL, "IF2 DAC2 Mux" },
+	{ "IF2 DAC23", NULL, "IF2 DAC3 Mux" },
+	{ "IF2 DAC45", NULL, "IF2 DAC4 Mux" },
+	{ "IF2 DAC45", NULL, "IF2 DAC5 Mux" },
+	{ "IF2 DAC67", NULL, "IF2 DAC6 Mux" },
+	{ "IF2 DAC67", NULL, "IF2 DAC7 Mux" },
+
+	{ "IF3 DAC", NULL, "AIF3RX" },
+	{ "IF3 DAC", NULL, "I2S3" },
+
+	{ "IF4 DAC", NULL, "AIF4RX" },
+	{ "IF4 DAC", NULL, "I2S4" },
+
+	{ "IF3 DAC L", NULL, "IF3 DAC" },
+	{ "IF3 DAC R", NULL, "IF3 DAC" },
+
+	{ "IF4 DAC L", NULL, "IF4 DAC" },
+	{ "IF4 DAC R", NULL, "IF4 DAC" },
+
+	{ "SLB DAC0", NULL, "SLBRX" },
+	{ "SLB DAC1", NULL, "SLBRX" },
+	{ "SLB DAC2", NULL, "SLBRX" },
+	{ "SLB DAC3", NULL, "SLBRX" },
+	{ "SLB DAC4", NULL, "SLBRX" },
+	{ "SLB DAC5", NULL, "SLBRX" },
+	{ "SLB DAC6", NULL, "SLBRX" },
+	{ "SLB DAC7", NULL, "SLBRX" },
+	{ "SLB DAC0", NULL, "SLB" },
+	{ "SLB DAC1", NULL, "SLB" },
+	{ "SLB DAC2", NULL, "SLB" },
+	{ "SLB DAC3", NULL, "SLB" },
+	{ "SLB DAC4", NULL, "SLB" },
+	{ "SLB DAC5", NULL, "SLB" },
+	{ "SLB DAC6", NULL, "SLB" },
+	{ "SLB DAC7", NULL, "SLB" },
+
+	{ "SLB DAC01", NULL, "SLB DAC0" },
+	{ "SLB DAC01", NULL, "SLB DAC1" },
+	{ "SLB DAC23", NULL, "SLB DAC2" },
+	{ "SLB DAC23", NULL, "SLB DAC3" },
+	{ "SLB DAC45", NULL, "SLB DAC4" },
+	{ "SLB DAC45", NULL, "SLB DAC5" },
+	{ "SLB DAC67", NULL, "SLB DAC6" },
+	{ "SLB DAC67", NULL, "SLB DAC7" },
+
+	{ "ADDA1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
+	{ "ADDA1 Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" },
+	{ "ADDA1 Mux", "OB 67", "OB67" },
+
+	{ "DAC1 Mux", "IF1 DAC 01", "IF1 DAC01" },
+	{ "DAC1 Mux", "IF2 DAC 01", "IF2 DAC01" },
+	{ "DAC1 Mux", "IF3 DAC LR", "IF3 DAC" },
+	{ "DAC1 Mux", "IF4 DAC LR", "IF4 DAC" },
+	{ "DAC1 Mux", "SLB DAC 01", "SLB DAC01" },
+	{ "DAC1 Mux", "OB 01", "OB01 Bypass Mux" },
+
+	{ "DAC1 MIXL", "Stereo ADC Switch", "ADDA1 Mux" },
+	{ "DAC1 MIXL", "DAC1 Switch", "DAC1 Mux" },
+	{ "DAC1 MIXR", "Stereo ADC Switch", "ADDA1 Mux" },
+	{ "DAC1 MIXR", "DAC1 Switch", "DAC1 Mux" },
+
+	{ "DAC1 FS", NULL, "DAC1 MIXL" },
+	{ "DAC1 FS", NULL, "DAC1 MIXR" },
+
+	{ "DAC2 L Mux", "IF1 DAC 2", "IF1 DAC2 Mux" },
+	{ "DAC2 L Mux", "IF2 DAC 2", "IF2 DAC2 Mux" },
+	{ "DAC2 L Mux", "IF3 DAC L", "IF3 DAC L" },
+	{ "DAC2 L Mux", "IF4 DAC L", "IF4 DAC L" },
+	{ "DAC2 L Mux", "SLB DAC 2", "SLB DAC2" },
+	{ "DAC2 L Mux", "OB 2", "OutBound2" },
+
+	{ "DAC2 R Mux", "IF1 DAC 3", "IF1 DAC3 Mux" },
+	{ "DAC2 R Mux", "IF2 DAC 3", "IF2 DAC3 Mux" },
+	{ "DAC2 R Mux", "IF3 DAC R", "IF3 DAC R" },
+	{ "DAC2 R Mux", "IF4 DAC R", "IF4 DAC R" },
+	{ "DAC2 R Mux", "SLB DAC 3", "SLB DAC3" },
+	{ "DAC2 R Mux", "OB 3", "OutBound3" },
+	{ "DAC2 R Mux", "Haptic Generator", "Haptic Generator" },
+	{ "DAC2 R Mux", "VAD ADC", "VAD ADC Mux" },
+
+	{ "DAC3 L Mux", "IF1 DAC 4", "IF1 DAC4 Mux" },
+	{ "DAC3 L Mux", "IF2 DAC 4", "IF2 DAC4 Mux" },
+	{ "DAC3 L Mux", "IF3 DAC L", "IF3 DAC L" },
+	{ "DAC3 L Mux", "IF4 DAC L", "IF4 DAC L" },
+	{ "DAC3 L Mux", "SLB DAC 4", "SLB DAC4" },
+	{ "DAC3 L Mux", "OB 4", "OutBound4" },
+
+	{ "DAC3 R Mux", "IF1 DAC 5", "IF1 DAC5 Mux" },
+	{ "DAC3 R Mux", "IF2 DAC 5", "IF2 DAC5 Mux" },
+	{ "DAC3 R Mux", "IF3 DAC R", "IF3 DAC R" },
+	{ "DAC3 R Mux", "IF4 DAC R", "IF4 DAC R" },
+	{ "DAC3 R Mux", "SLB DAC 5", "SLB DAC5" },
+	{ "DAC3 R Mux", "OB 5", "OutBound5" },
+
+	{ "DAC4 L Mux", "IF1 DAC 6", "IF1 DAC6 Mux" },
+	{ "DAC4 L Mux", "IF2 DAC 6", "IF2 DAC6 Mux" },
+	{ "DAC4 L Mux", "IF3 DAC L", "IF3 DAC L" },
+	{ "DAC4 L Mux", "IF4 DAC L", "IF4 DAC L" },
+	{ "DAC4 L Mux", "SLB DAC 6", "SLB DAC6" },
+	{ "DAC4 L Mux", "OB 6", "OutBound6" },
+
+	{ "DAC4 R Mux", "IF1 DAC 7", "IF1 DAC7 Mux" },
+	{ "DAC4 R Mux", "IF2 DAC 7", "IF2 DAC7 Mux" },
+	{ "DAC4 R Mux", "IF3 DAC R", "IF3 DAC R" },
+	{ "DAC4 R Mux", "IF4 DAC R", "IF4 DAC R" },
+	{ "DAC4 R Mux", "SLB DAC 7", "SLB DAC7" },
+	{ "DAC4 R Mux", "OB 7", "OutBound7" },
+
+	{ "Sidetone Mux", "DMIC1 L", "DMIC L1" },
+	{ "Sidetone Mux", "DMIC2 L", "DMIC L2" },
+	{ "Sidetone Mux", "DMIC3 L", "DMIC L3" },
+	{ "Sidetone Mux", "DMIC4 L", "DMIC L4" },
+	{ "Sidetone Mux", "ADC1", "ADC 1" },
+	{ "Sidetone Mux", "ADC2", "ADC 2" },
+	{ "Sidetone Mux", NULL, "Sidetone Power" },
+
+	{ "Stereo DAC MIXL", "ST L Switch", "Sidetone Mux" },
+	{ "Stereo DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXL", "DAC2 L Switch", "DAC2 L Mux" },
+	{ "Stereo DAC MIXL", "DAC1 R Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXL", NULL, "dac stereo1 filter" },
+	{ "Stereo DAC MIXR", "ST R Switch", "Sidetone Mux" },
+	{ "Stereo DAC MIXR", "DAC1 R Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" },
+	{ "Stereo DAC MIXR", "DAC1 L Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXR", NULL, "dac stereo1 filter" },
+	{ "dac stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "Mono DAC MIXL", "ST L Switch", "Sidetone Mux" },
+	{ "Mono DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" },
+	{ "Mono DAC MIXL", "DAC2 L Switch", "DAC2 L Mux" },
+	{ "Mono DAC MIXL", "DAC2 R Switch", "DAC2 R Mux" },
+	{ "Mono DAC MIXL", NULL, "dac mono2 left filter" },
+	{ "dac mono2 left filter", NULL, "PLL1", is_sys_clk_from_pll },
+	{ "Mono DAC MIXR", "ST R Switch", "Sidetone Mux" },
+	{ "Mono DAC MIXR", "DAC1 R Switch", "DAC1 MIXR" },
+	{ "Mono DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" },
+	{ "Mono DAC MIXR", "DAC2 L Switch", "DAC2 L Mux" },
+	{ "Mono DAC MIXR", NULL, "dac mono2 right filter" },
+	{ "dac mono2 right filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "DD1 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" },
+	{ "DD1 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" },
+	{ "DD1 MIXL", "DAC3 L Switch", "DAC3 L Mux" },
+	{ "DD1 MIXL", "DAC3 R Switch", "DAC3 R Mux" },
+	{ "DD1 MIXL", NULL, "dac mono3 left filter" },
+	{ "dac mono3 left filter", NULL, "PLL1", is_sys_clk_from_pll },
+	{ "DD1 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" },
+	{ "DD1 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" },
+	{ "DD1 MIXR", "DAC3 L Switch", "DAC3 L Mux" },
+	{ "DD1 MIXR", "DAC3 R Switch", "DAC3 R Mux" },
+	{ "DD1 MIXR", NULL, "dac mono3 right filter" },
+	{ "dac mono3 right filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "DD2 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" },
+	{ "DD2 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" },
+	{ "DD2 MIXL", "DAC4 L Switch", "DAC4 L Mux" },
+	{ "DD2 MIXL", "DAC4 R Switch", "DAC4 R Mux" },
+	{ "DD2 MIXL", NULL, "dac mono4 left filter" },
+	{ "dac mono4 left filter", NULL, "PLL1", is_sys_clk_from_pll },
+	{ "DD2 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" },
+	{ "DD2 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" },
+	{ "DD2 MIXR", "DAC4 L Switch", "DAC4 L Mux" },
+	{ "DD2 MIXR", "DAC4 R Switch", "DAC4 R Mux" },
+	{ "DD2 MIXR", NULL, "dac mono4 right filter" },
+	{ "dac mono4 right filter", NULL, "PLL1", is_sys_clk_from_pll },
+
+	{ "Stereo DAC MIX", NULL, "Stereo DAC MIXL" },
+	{ "Stereo DAC MIX", NULL, "Stereo DAC MIXR" },
+	{ "Mono DAC MIX", NULL, "Mono DAC MIXL" },
+	{ "Mono DAC MIX", NULL, "Mono DAC MIXR" },
+	{ "DD1 MIX", NULL, "DD1 MIXL" },
+	{ "DD1 MIX", NULL, "DD1 MIXR" },
+	{ "DD2 MIX", NULL, "DD2 MIXL" },
+	{ "DD2 MIX", NULL, "DD2 MIXR" },
+
+	{ "DAC12 SRC Mux", "STO1 DAC MIX", "Stereo DAC MIX" },
+	{ "DAC12 SRC Mux", "MONO DAC MIX", "Mono DAC MIX" },
+	{ "DAC12 SRC Mux", "DD MIX1", "DD1 MIX" },
+	{ "DAC12 SRC Mux", "DD MIX2", "DD2 MIX" },
+
+	{ "DAC3 SRC Mux", "MONO DAC MIXL", "Mono DAC MIXL" },
+	{ "DAC3 SRC Mux", "MONO DAC MIXR", "Mono DAC MIXR" },
+	{ "DAC3 SRC Mux", "DD MIX1L", "DD1 MIXL" },
+	{ "DAC3 SRC Mux", "DD MIX2L", "DD2 MIXL" },
+
+	{ "DAC 1", NULL, "DAC12 SRC Mux" },
+	{ "DAC 2", NULL, "DAC12 SRC Mux" },
+	{ "DAC 3", NULL, "DAC3 SRC Mux" },
+
+	{ "PDM1 L Mux", "STO1 DAC MIX", "Stereo DAC MIXL" },
+	{ "PDM1 L Mux", "MONO DAC MIX", "Mono DAC MIXL" },
+	{ "PDM1 L Mux", "DD MIX1", "DD1 MIXL" },
+	{ "PDM1 L Mux", "DD MIX2", "DD2 MIXL" },
+	{ "PDM1 L Mux", NULL, "PDM1 Power" },
+	{ "PDM1 R Mux", "STO1 DAC MIX", "Stereo DAC MIXR" },
+	{ "PDM1 R Mux", "MONO DAC MIX", "Mono DAC MIXR" },
+	{ "PDM1 R Mux", "DD MIX1", "DD1 MIXR" },
+	{ "PDM1 R Mux", "DD MIX2", "DD2 MIXR" },
+	{ "PDM1 R Mux", NULL, "PDM1 Power" },
+	{ "PDM2 L Mux", "STO1 DAC MIX", "Stereo DAC MIXL" },
+	{ "PDM2 L Mux", "MONO DAC MIX", "Mono DAC MIXL" },
+	{ "PDM2 L Mux", "DD MIX1", "DD1 MIXL" },
+	{ "PDM2 L Mux", "DD MIX2", "DD2 MIXL" },
+	{ "PDM2 L Mux", NULL, "PDM2 Power" },
+	{ "PDM2 R Mux", "STO1 DAC MIX", "Stereo DAC MIXR" },
+	{ "PDM2 R Mux", "MONO DAC MIX", "Mono DAC MIXR" },
+	{ "PDM2 R Mux", "DD MIX1", "DD1 MIXR" },
+	{ "PDM2 R Mux", "DD MIX1", "DD2 MIXR" },
+	{ "PDM2 R Mux", NULL, "PDM2 Power" },
+
+	{ "LOUT1 amp", NULL, "DAC 1" },
+	{ "LOUT2 amp", NULL, "DAC 2" },
+	{ "LOUT3 amp", NULL, "DAC 3" },
+
+	{ "LOUT1 vref", NULL, "LOUT1 amp" },
+	{ "LOUT2 vref", NULL, "LOUT2 amp" },
+	{ "LOUT3 vref", NULL, "LOUT3 amp" },
+
+	{ "LOUT1", NULL, "LOUT1 vref" },
+	{ "LOUT2", NULL, "LOUT2 vref" },
+	{ "LOUT3", NULL, "LOUT3 vref" },
+
+	{ "PDM1L", NULL, "PDM1 L Mux" },
+	{ "PDM1R", NULL, "PDM1 R Mux" },
+	{ "PDM2L", NULL, "PDM2 L Mux" },
+	{ "PDM2R", NULL, "PDM2 R Mux" },
+};
+
+static const struct snd_soc_dapm_route rt5677_dmic2_clk_1[] = {
+	{ "DMIC L2", NULL, "DMIC1 power" },
+	{ "DMIC R2", NULL, "DMIC1 power" },
+};
+
+static const struct snd_soc_dapm_route rt5677_dmic2_clk_2[] = {
+	{ "DMIC L2", NULL, "DMIC2 power" },
+	{ "DMIC R2", NULL, "DMIC2 power" },
+};
+
+static int rt5677_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+	unsigned int val_len = 0, val_clk, mask_clk;
+	int pre_div, bclk_ms, frame_size;
+
+	rt5677->lrck[dai->id] = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5677->sysclk, rt5677->lrck[dai->id]);
+	if (pre_div < 0) {
+		dev_err(component->dev, "Unsupported clock setting: sysclk=%dHz lrck=%dHz\n",
+			rt5677->sysclk, rt5677->lrck[dai->id]);
+		return -EINVAL;
+	}
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n", frame_size);
+		return -EINVAL;
+	}
+	bclk_ms = frame_size > 32;
+	rt5677->bclk[dai->id] = rt5677->lrck[dai->id] * (32 << bclk_ms);
+
+	dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+		rt5677->bclk[dai->id], rt5677->lrck[dai->id]);
+	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+				bclk_ms, pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		val_len |= RT5677_I2S_DL_20;
+		break;
+	case 24:
+		val_len |= RT5677_I2S_DL_24;
+		break;
+	case 8:
+		val_len |= RT5677_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5677_AIF1:
+		mask_clk = RT5677_I2S_PD1_MASK;
+		val_clk = pre_div << RT5677_I2S_PD1_SFT;
+		regmap_update_bits(rt5677->regmap, RT5677_I2S1_SDP,
+			RT5677_I2S_DL_MASK, val_len);
+		regmap_update_bits(rt5677->regmap, RT5677_CLK_TREE_CTRL1,
+			mask_clk, val_clk);
+		break;
+	case RT5677_AIF2:
+		mask_clk = RT5677_I2S_PD2_MASK;
+		val_clk = pre_div << RT5677_I2S_PD2_SFT;
+		regmap_update_bits(rt5677->regmap, RT5677_I2S2_SDP,
+			RT5677_I2S_DL_MASK, val_len);
+		regmap_update_bits(rt5677->regmap, RT5677_CLK_TREE_CTRL1,
+			mask_clk, val_clk);
+		break;
+	case RT5677_AIF3:
+		mask_clk = RT5677_I2S_BCLK_MS3_MASK | RT5677_I2S_PD3_MASK;
+		val_clk = bclk_ms << RT5677_I2S_BCLK_MS3_SFT |
+			pre_div << RT5677_I2S_PD3_SFT;
+		regmap_update_bits(rt5677->regmap, RT5677_I2S3_SDP,
+			RT5677_I2S_DL_MASK, val_len);
+		regmap_update_bits(rt5677->regmap, RT5677_CLK_TREE_CTRL1,
+			mask_clk, val_clk);
+		break;
+	case RT5677_AIF4:
+		mask_clk = RT5677_I2S_BCLK_MS4_MASK | RT5677_I2S_PD4_MASK;
+		val_clk = bclk_ms << RT5677_I2S_BCLK_MS4_SFT |
+			pre_div << RT5677_I2S_PD4_SFT;
+		regmap_update_bits(rt5677->regmap, RT5677_I2S4_SDP,
+			RT5677_I2S_DL_MASK, val_len);
+		regmap_update_bits(rt5677->regmap, RT5677_CLK_TREE_CTRL1,
+			mask_clk, val_clk);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5677_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5677->master[dai->id] = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5677_I2S_MS_S;
+		rt5677->master[dai->id] = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5677_I2S_BP_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5677_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5677_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5677_I2S_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5677_AIF1:
+		regmap_update_bits(rt5677->regmap, RT5677_I2S1_SDP,
+			RT5677_I2S_MS_MASK | RT5677_I2S_BP_MASK |
+			RT5677_I2S_DF_MASK, reg_val);
+		break;
+	case RT5677_AIF2:
+		regmap_update_bits(rt5677->regmap, RT5677_I2S2_SDP,
+			RT5677_I2S_MS_MASK | RT5677_I2S_BP_MASK |
+			RT5677_I2S_DF_MASK, reg_val);
+		break;
+	case RT5677_AIF3:
+		regmap_update_bits(rt5677->regmap, RT5677_I2S3_SDP,
+			RT5677_I2S_MS_MASK | RT5677_I2S_BP_MASK |
+			RT5677_I2S_DF_MASK, reg_val);
+		break;
+	case RT5677_AIF4:
+		regmap_update_bits(rt5677->regmap, RT5677_I2S4_SDP,
+			RT5677_I2S_MS_MASK | RT5677_I2S_BP_MASK |
+			RT5677_I2S_DF_MASK, reg_val);
+		break;
+	default:
+		break;
+	}
+
+
+	return 0;
+}
+
+static int rt5677_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0;
+
+	if (freq == rt5677->sysclk && clk_id == rt5677->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5677_SCLK_S_MCLK:
+		reg_val |= RT5677_SCLK_SRC_MCLK;
+		break;
+	case RT5677_SCLK_S_PLL1:
+		reg_val |= RT5677_SCLK_SRC_PLL1;
+		break;
+	case RT5677_SCLK_S_RCCLK:
+		reg_val |= RT5677_SCLK_SRC_RCCLK;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
+		RT5677_SCLK_SRC_MASK, reg_val);
+	rt5677->sysclk = freq;
+	rt5677->sysclk_src = clk_id;
+
+	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+	return 0;
+}
+
+/**
+ * rt5677_pll_calc - Calcualte PLL M/N/K code.
+ * @freq_in: external clock provided to codec.
+ * @freq_out: target clock which codec works on.
+ * @pll_code: Pointer to structure with M, N, K, bypass K and bypass M flag.
+ *
+ * Calcualte M/N/K code and bypass K/M flag to configure PLL for codec.
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5677_pll_calc(const unsigned int freq_in,
+	const unsigned int freq_out, struct rl6231_pll_code *pll_code)
+{
+	if (RT5677_PLL_INP_MIN > freq_in)
+		return -EINVAL;
+
+	return rl6231_pll_calc(freq_in, freq_out, pll_code);
+}
+
+static int rt5677_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+			unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5677->pll_src && freq_in == rt5677->pll_in &&
+	    freq_out == rt5677->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt5677->pll_in = 0;
+		rt5677->pll_out = 0;
+		regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
+			RT5677_SCLK_SRC_MASK, RT5677_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5677_PLL1_S_MCLK:
+		regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
+			RT5677_PLL1_SRC_MASK, RT5677_PLL1_SRC_MCLK);
+		break;
+	case RT5677_PLL1_S_BCLK1:
+	case RT5677_PLL1_S_BCLK2:
+	case RT5677_PLL1_S_BCLK3:
+	case RT5677_PLL1_S_BCLK4:
+		switch (dai->id) {
+		case RT5677_AIF1:
+			regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
+				RT5677_PLL1_SRC_MASK, RT5677_PLL1_SRC_BCLK1);
+			break;
+		case RT5677_AIF2:
+			regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
+				RT5677_PLL1_SRC_MASK, RT5677_PLL1_SRC_BCLK2);
+			break;
+		case RT5677_AIF3:
+			regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
+				RT5677_PLL1_SRC_MASK, RT5677_PLL1_SRC_BCLK3);
+			break;
+		case RT5677_AIF4:
+			regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
+				RT5677_PLL1_SRC_MASK, RT5677_PLL1_SRC_BCLK4);
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rt5677_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "m_bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	regmap_write(rt5677->regmap, RT5677_PLL1_CTRL1,
+		pll_code.n_code << RT5677_PLL_N_SFT | pll_code.k_code);
+	regmap_write(rt5677->regmap, RT5677_PLL1_CTRL2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5677_PLL_M_SFT |
+		pll_code.m_bp << RT5677_PLL_M_BP_SFT);
+
+	rt5677->pll_in = freq_in;
+	rt5677->pll_out = freq_out;
+	rt5677->pll_src = source;
+
+	return 0;
+}
+
+static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+	unsigned int val = 0, slot_width_25 = 0;
+
+	if (rx_mask || tx_mask)
+		val |= (1 << 12);
+
+	switch (slots) {
+	case 4:
+		val |= (1 << 10);
+		break;
+	case 6:
+		val |= (2 << 10);
+		break;
+	case 8:
+		val |= (3 << 10);
+		break;
+	case 2:
+	default:
+		break;
+	}
+
+	switch (slot_width) {
+	case 20:
+		val |= (1 << 8);
+		break;
+	case 25:
+		slot_width_25 = 0x8080;
+		/* fall through */
+	case 24:
+		val |= (2 << 8);
+		break;
+	case 32:
+		val |= (3 << 8);
+		break;
+	case 16:
+	default:
+		break;
+	}
+
+	switch (dai->id) {
+	case RT5677_AIF1:
+		regmap_update_bits(rt5677->regmap, RT5677_TDM1_CTRL1, 0x1f00,
+			val);
+		regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x8000,
+			slot_width_25);
+		break;
+	case RT5677_AIF2:
+		regmap_update_bits(rt5677->regmap, RT5677_TDM2_CTRL1, 0x1f00,
+			val);
+		regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x80,
+			slot_width_25);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5677_set_bias_level(struct snd_soc_component *component,
+			enum snd_soc_bias_level level)
+{
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) {
+			rt5677_set_dsp_vad(component, false);
+
+			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
+				RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK,
+				0x0055);
+			regmap_update_bits(rt5677->regmap,
+				RT5677_PR_BASE + RT5677_BIAS_CUR4,
+				0x0f00, 0x0f00);
+			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
+				RT5677_PWR_FV1 | RT5677_PWR_FV2 |
+				RT5677_PWR_VREF1 | RT5677_PWR_MB |
+				RT5677_PWR_BG | RT5677_PWR_VREF2,
+				RT5677_PWR_VREF1 | RT5677_PWR_MB |
+				RT5677_PWR_BG | RT5677_PWR_VREF2);
+			rt5677->is_vref_slow = false;
+			regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
+				RT5677_PWR_CORE, RT5677_PWR_CORE);
+			regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC,
+				0x1, 0x1);
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x0);
+		regmap_write(rt5677->regmap, RT5677_PWR_DIG1, 0x0000);
+		regmap_write(rt5677->regmap, RT5677_PWR_DIG2, 0x0000);
+		regmap_write(rt5677->regmap, RT5677_PWR_ANLG1, 0x0022);
+		regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000);
+		regmap_update_bits(rt5677->regmap,
+			RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000);
+
+		if (rt5677->dsp_vad_en)
+			rt5677_set_dsp_vad(component, true);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_GPIOLIB
+static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+
+	switch (offset) {
+	case RT5677_GPIO1 ... RT5677_GPIO5:
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+			0x1 << (offset * 3 + 1), !!value << (offset * 3 + 1));
+		break;
+
+	case RT5677_GPIO6:
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
+			RT5677_GPIO6_OUT_MASK, !!value << RT5677_GPIO6_OUT_SFT);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int rt5677_gpio_direction_out(struct gpio_chip *chip,
+				     unsigned offset, int value)
+{
+	struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+
+	switch (offset) {
+	case RT5677_GPIO1 ... RT5677_GPIO5:
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+			0x3 << (offset * 3 + 1),
+			(0x2 | !!value) << (offset * 3 + 1));
+		break;
+
+	case RT5677_GPIO6:
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
+			RT5677_GPIO6_DIR_MASK | RT5677_GPIO6_OUT_MASK,
+			RT5677_GPIO6_DIR_OUT | !!value << RT5677_GPIO6_OUT_SFT);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+	int value, ret;
+
+	ret = regmap_read(rt5677->regmap, RT5677_GPIO_ST, &value);
+	if (ret < 0)
+		return ret;
+
+	return (value & (0x1 << offset)) >> offset;
+}
+
+static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+	struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+
+	switch (offset) {
+	case RT5677_GPIO1 ... RT5677_GPIO5:
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+			0x1 << (offset * 3 + 2), 0x0);
+		break;
+
+	case RT5677_GPIO6:
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
+			RT5677_GPIO6_DIR_MASK, RT5677_GPIO6_DIR_IN);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/** Configures the gpio as
+ *   0 - floating
+ *   1 - pull down
+ *   2 - pull up
+ */
+static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset,
+		int value)
+{
+	int shift;
+
+	switch (offset) {
+	case RT5677_GPIO1 ... RT5677_GPIO2:
+		shift = 2 * (1 - offset);
+		regmap_update_bits(rt5677->regmap,
+			RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL2,
+			0x3 << shift,
+			(value & 0x3) << shift);
+		break;
+
+	case RT5677_GPIO3 ... RT5677_GPIO6:
+		shift = 2 * (9 - offset);
+		regmap_update_bits(rt5677->regmap,
+			RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL3,
+			0x3 << shift,
+			(value & 0x3) << shift);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+	struct regmap_irq_chip_data *data = rt5677->irq_data;
+	int irq;
+
+	if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) ||
+		(rt5677->pdata.jd1_gpio == 2 &&
+			offset == RT5677_GPIO2) ||
+		(rt5677->pdata.jd1_gpio == 3 &&
+			offset == RT5677_GPIO3)) {
+		irq = RT5677_IRQ_JD1;
+	} else if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) ||
+		(rt5677->pdata.jd2_gpio == 2 &&
+			offset == RT5677_GPIO5) ||
+		(rt5677->pdata.jd2_gpio == 3 &&
+			offset == RT5677_GPIO6)) {
+		irq = RT5677_IRQ_JD2;
+	} else if ((rt5677->pdata.jd3_gpio == 1 &&
+			offset == RT5677_GPIO4) ||
+		(rt5677->pdata.jd3_gpio == 2 &&
+			offset == RT5677_GPIO5) ||
+		(rt5677->pdata.jd3_gpio == 3 &&
+			offset == RT5677_GPIO6)) {
+		irq = RT5677_IRQ_JD3;
+	} else {
+		return -ENXIO;
+	}
+
+	return regmap_irq_get_virq(data, irq);
+}
+
+static const struct gpio_chip rt5677_template_chip = {
+	.label			= "rt5677",
+	.owner			= THIS_MODULE,
+	.direction_output	= rt5677_gpio_direction_out,
+	.set			= rt5677_gpio_set,
+	.direction_input	= rt5677_gpio_direction_in,
+	.get			= rt5677_gpio_get,
+	.to_irq			= rt5677_to_irq,
+	.can_sleep		= 1,
+};
+
+static void rt5677_init_gpio(struct i2c_client *i2c)
+{
+	struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+	int ret;
+
+	rt5677->gpio_chip = rt5677_template_chip;
+	rt5677->gpio_chip.ngpio = RT5677_GPIO_NUM;
+	rt5677->gpio_chip.parent = &i2c->dev;
+	rt5677->gpio_chip.base = -1;
+
+	ret = gpiochip_add_data(&rt5677->gpio_chip, rt5677);
+	if (ret != 0)
+		dev_err(&i2c->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void rt5677_free_gpio(struct i2c_client *i2c)
+{
+	struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+
+	gpiochip_remove(&rt5677->gpio_chip);
+}
+#else
+static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset,
+		int value)
+{
+}
+
+static void rt5677_init_gpio(struct i2c_client *i2c)
+{
+}
+
+static void rt5677_free_gpio(struct i2c_client *i2c)
+{
+}
+#endif
+
+static int rt5677_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+	int i;
+
+	rt5677->component = component;
+
+	if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
+		snd_soc_dapm_add_routes(dapm,
+			rt5677_dmic2_clk_2,
+			ARRAY_SIZE(rt5677_dmic2_clk_2));
+	} else { /*use dmic1 clock by default*/
+		snd_soc_dapm_add_routes(dapm,
+			rt5677_dmic2_clk_1,
+			ARRAY_SIZE(rt5677_dmic2_clk_1));
+	}
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+
+	regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
+	regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00);
+
+	for (i = 0; i < RT5677_GPIO_NUM; i++)
+		rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]);
+
+	if (rt5677->irq_data) {
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, 0x8000,
+			0x8000);
+		regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x0018,
+			0x0008);
+
+		if (rt5677->pdata.jd1_gpio)
+			regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+				RT5677_SEL_GPIO_JD1_MASK,
+				rt5677->pdata.jd1_gpio <<
+				RT5677_SEL_GPIO_JD1_SFT);
+
+		if (rt5677->pdata.jd2_gpio)
+			regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+				RT5677_SEL_GPIO_JD2_MASK,
+				rt5677->pdata.jd2_gpio <<
+				RT5677_SEL_GPIO_JD2_SFT);
+
+		if (rt5677->pdata.jd3_gpio)
+			regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+				RT5677_SEL_GPIO_JD3_MASK,
+				rt5677->pdata.jd3_gpio <<
+				RT5677_SEL_GPIO_JD3_SFT);
+	}
+
+	mutex_init(&rt5677->dsp_cmd_lock);
+	mutex_init(&rt5677->dsp_pri_lock);
+
+	return 0;
+}
+
+static void rt5677_remove(struct snd_soc_component *component)
+{
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+
+	regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
+	gpiod_set_value_cansleep(rt5677->pow_ldo2, 0);
+	gpiod_set_value_cansleep(rt5677->reset_pin, 1);
+}
+
+#ifdef CONFIG_PM
+static int rt5677_suspend(struct snd_soc_component *component)
+{
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+
+	if (!rt5677->dsp_vad_en) {
+		regcache_cache_only(rt5677->regmap, true);
+		regcache_mark_dirty(rt5677->regmap);
+
+		gpiod_set_value_cansleep(rt5677->pow_ldo2, 0);
+		gpiod_set_value_cansleep(rt5677->reset_pin, 1);
+	}
+
+	return 0;
+}
+
+static int rt5677_resume(struct snd_soc_component *component)
+{
+	struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+
+	if (!rt5677->dsp_vad_en) {
+		rt5677->pll_src = 0;
+		rt5677->pll_in = 0;
+		rt5677->pll_out = 0;
+		gpiod_set_value_cansleep(rt5677->pow_ldo2, 1);
+		gpiod_set_value_cansleep(rt5677->reset_pin, 0);
+		if (rt5677->pow_ldo2 || rt5677->reset_pin)
+			msleep(10);
+
+		regcache_cache_only(rt5677->regmap, false);
+		regcache_sync(rt5677->regmap);
+	}
+
+	return 0;
+}
+#else
+#define rt5677_suspend NULL
+#define rt5677_resume NULL
+#endif
+
+static int rt5677_read(void *context, unsigned int reg, unsigned int *val)
+{
+	struct i2c_client *client = context;
+	struct rt5677_priv *rt5677 = i2c_get_clientdata(client);
+
+	if (rt5677->is_dsp_mode) {
+		if (reg > 0xff) {
+			mutex_lock(&rt5677->dsp_pri_lock);
+			rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
+				reg & 0xff);
+			rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val);
+			mutex_unlock(&rt5677->dsp_pri_lock);
+		} else {
+			rt5677_dsp_mode_i2c_read(rt5677, reg, val);
+		}
+	} else {
+		regmap_read(rt5677->regmap_physical, reg, val);
+	}
+
+	return 0;
+}
+
+static int rt5677_write(void *context, unsigned int reg, unsigned int val)
+{
+	struct i2c_client *client = context;
+	struct rt5677_priv *rt5677 = i2c_get_clientdata(client);
+
+	if (rt5677->is_dsp_mode) {
+		if (reg > 0xff) {
+			mutex_lock(&rt5677->dsp_pri_lock);
+			rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
+				reg & 0xff);
+			rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA,
+				val);
+			mutex_unlock(&rt5677->dsp_pri_lock);
+		} else {
+			rt5677_dsp_mode_i2c_write(rt5677, reg, val);
+		}
+	} else {
+		regmap_write(rt5677->regmap_physical, reg, val);
+	}
+
+	return 0;
+}
+
+#define RT5677_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5677_aif_dai_ops = {
+	.hw_params = rt5677_hw_params,
+	.set_fmt = rt5677_set_dai_fmt,
+	.set_sysclk = rt5677_set_dai_sysclk,
+	.set_pll = rt5677_set_dai_pll,
+	.set_tdm_slot = rt5677_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver rt5677_dai[] = {
+	{
+		.name = "rt5677-aif1",
+		.id = RT5677_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5677_STEREO_RATES,
+			.formats = RT5677_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5677_STEREO_RATES,
+			.formats = RT5677_FORMATS,
+		},
+		.ops = &rt5677_aif_dai_ops,
+	},
+	{
+		.name = "rt5677-aif2",
+		.id = RT5677_AIF2,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5677_STEREO_RATES,
+			.formats = RT5677_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5677_STEREO_RATES,
+			.formats = RT5677_FORMATS,
+		},
+		.ops = &rt5677_aif_dai_ops,
+	},
+	{
+		.name = "rt5677-aif3",
+		.id = RT5677_AIF3,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5677_STEREO_RATES,
+			.formats = RT5677_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF3 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5677_STEREO_RATES,
+			.formats = RT5677_FORMATS,
+		},
+		.ops = &rt5677_aif_dai_ops,
+	},
+	{
+		.name = "rt5677-aif4",
+		.id = RT5677_AIF4,
+		.playback = {
+			.stream_name = "AIF4 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5677_STEREO_RATES,
+			.formats = RT5677_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF4 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5677_STEREO_RATES,
+			.formats = RT5677_FORMATS,
+		},
+		.ops = &rt5677_aif_dai_ops,
+	},
+	{
+		.name = "rt5677-slimbus",
+		.id = RT5677_AIF5,
+		.playback = {
+			.stream_name = "SLIMBus Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5677_STEREO_RATES,
+			.formats = RT5677_FORMATS,
+		},
+		.capture = {
+			.stream_name = "SLIMBus Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5677_STEREO_RATES,
+			.formats = RT5677_FORMATS,
+		},
+		.ops = &rt5677_aif_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5677 = {
+	.probe			= rt5677_probe,
+	.remove			= rt5677_remove,
+	.suspend		= rt5677_suspend,
+	.resume			= rt5677_resume,
+	.set_bias_level		= rt5677_set_bias_level,
+	.controls		= rt5677_snd_controls,
+	.num_controls		= ARRAY_SIZE(rt5677_snd_controls),
+	.dapm_widgets		= rt5677_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(rt5677_dapm_widgets),
+	.dapm_routes		= rt5677_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(rt5677_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt5677_regmap_physical = {
+	.name = "physical",
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = RT5677_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5677_ranges) *
+						RT5677_PR_SPACING),
+	.readable_reg = rt5677_readable_register,
+
+	.cache_type = REGCACHE_NONE,
+	.ranges = rt5677_ranges,
+	.num_ranges = ARRAY_SIZE(rt5677_ranges),
+};
+
+static const struct regmap_config rt5677_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = RT5677_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5677_ranges) *
+						RT5677_PR_SPACING),
+
+	.volatile_reg = rt5677_volatile_register,
+	.readable_reg = rt5677_readable_register,
+	.reg_read = rt5677_read,
+	.reg_write = rt5677_write,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5677_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5677_reg),
+	.ranges = rt5677_ranges,
+	.num_ranges = ARRAY_SIZE(rt5677_ranges),
+};
+
+static const struct of_device_id rt5677_of_match[] = {
+	{ .compatible = "realtek,rt5677", .data = (const void *)RT5677 },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, rt5677_of_match);
+
+static const struct acpi_device_id rt5677_acpi_match[] = {
+	{ "RT5677CE", RT5677 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, rt5677_acpi_match);
+
+static void rt5677_read_acpi_properties(struct rt5677_priv *rt5677,
+		struct device *dev)
+{
+	u32 val;
+
+	if (!device_property_read_u32(dev, "DCLK", &val))
+		rt5677->pdata.dmic2_clk_pin = val;
+
+	rt5677->pdata.in1_diff = device_property_read_bool(dev, "IN1");
+	rt5677->pdata.in2_diff = device_property_read_bool(dev, "IN2");
+	rt5677->pdata.lout1_diff = device_property_read_bool(dev, "OUT1");
+	rt5677->pdata.lout2_diff = device_property_read_bool(dev, "OUT2");
+	rt5677->pdata.lout3_diff = device_property_read_bool(dev, "OUT3");
+
+	device_property_read_u32(dev, "JD1", &rt5677->pdata.jd1_gpio);
+	device_property_read_u32(dev, "JD2", &rt5677->pdata.jd2_gpio);
+	device_property_read_u32(dev, "JD3", &rt5677->pdata.jd3_gpio);
+}
+
+static void rt5677_read_device_properties(struct rt5677_priv *rt5677,
+		struct device *dev)
+{
+	rt5677->pdata.in1_diff = device_property_read_bool(dev,
+			"realtek,in1-differential");
+	rt5677->pdata.in2_diff = device_property_read_bool(dev,
+			"realtek,in2-differential");
+	rt5677->pdata.lout1_diff = device_property_read_bool(dev,
+			"realtek,lout1-differential");
+	rt5677->pdata.lout2_diff = device_property_read_bool(dev,
+			"realtek,lout2-differential");
+	rt5677->pdata.lout3_diff = device_property_read_bool(dev,
+			"realtek,lout3-differential");
+
+	device_property_read_u8_array(dev, "realtek,gpio-config",
+			rt5677->pdata.gpio_config, RT5677_GPIO_NUM);
+
+	device_property_read_u32(dev, "realtek,jd1-gpio",
+			&rt5677->pdata.jd1_gpio);
+	device_property_read_u32(dev, "realtek,jd2-gpio",
+			&rt5677->pdata.jd2_gpio);
+	device_property_read_u32(dev, "realtek,jd3-gpio",
+			&rt5677->pdata.jd3_gpio);
+}
+
+static struct regmap_irq rt5677_irqs[] = {
+	[RT5677_IRQ_JD1] = {
+		.reg_offset = 0,
+		.mask = RT5677_EN_IRQ_GPIO_JD1,
+	},
+	[RT5677_IRQ_JD2] = {
+		.reg_offset = 0,
+		.mask = RT5677_EN_IRQ_GPIO_JD2,
+	},
+	[RT5677_IRQ_JD3] = {
+		.reg_offset = 0,
+		.mask = RT5677_EN_IRQ_GPIO_JD3,
+	},
+};
+
+static struct regmap_irq_chip rt5677_irq_chip = {
+	.name = "rt5677",
+	.irqs = rt5677_irqs,
+	.num_irqs = ARRAY_SIZE(rt5677_irqs),
+
+	.num_regs = 1,
+	.status_base = RT5677_IRQ_CTRL1,
+	.mask_base = RT5677_IRQ_CTRL1,
+	.mask_invert = 1,
+};
+
+static int rt5677_init_irq(struct i2c_client *i2c)
+{
+	int ret;
+	struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+
+	if (!rt5677->pdata.jd1_gpio &&
+		!rt5677->pdata.jd2_gpio &&
+		!rt5677->pdata.jd3_gpio)
+		return 0;
+
+	if (!i2c->irq) {
+		dev_err(&i2c->dev, "No interrupt specified\n");
+		return -EINVAL;
+	}
+
+	ret = regmap_add_irq_chip(rt5677->regmap, i2c->irq,
+		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
+		&rt5677_irq_chip, &rt5677->irq_data);
+
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register IRQ chip: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void rt5677_free_irq(struct i2c_client *i2c)
+{
+	struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+
+	if (rt5677->irq_data)
+		regmap_del_irq_chip(i2c->irq, rt5677->irq_data);
+}
+
+static int rt5677_i2c_probe(struct i2c_client *i2c)
+{
+	struct rt5677_priv *rt5677;
+	int ret;
+	unsigned int val;
+
+	rt5677 = devm_kzalloc(&i2c->dev, sizeof(struct rt5677_priv),
+				GFP_KERNEL);
+	if (rt5677 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt5677);
+
+	if (i2c->dev.of_node) {
+		const struct of_device_id *match_id;
+
+		match_id = of_match_device(rt5677_of_match, &i2c->dev);
+		if (match_id)
+			rt5677->type = (enum rt5677_type)match_id->data;
+
+		rt5677_read_device_properties(rt5677, &i2c->dev);
+	} else if (ACPI_HANDLE(&i2c->dev)) {
+		const struct acpi_device_id *acpi_id;
+
+		acpi_id = acpi_match_device(rt5677_acpi_match, &i2c->dev);
+		if (acpi_id)
+			rt5677->type = (enum rt5677_type)acpi_id->driver_data;
+
+		rt5677_read_acpi_properties(rt5677, &i2c->dev);
+	} else {
+		return -EINVAL;
+	}
+
+	/* pow-ldo2 and reset are optional. The codec pins may be statically
+	 * connected on the board without gpios. If the gpio device property
+	 * isn't specified, devm_gpiod_get_optional returns NULL.
+	 */
+	rt5677->pow_ldo2 = devm_gpiod_get_optional(&i2c->dev,
+			"realtek,pow-ldo2", GPIOD_OUT_HIGH);
+	if (IS_ERR(rt5677->pow_ldo2)) {
+		ret = PTR_ERR(rt5677->pow_ldo2);
+		dev_err(&i2c->dev, "Failed to request POW_LDO2: %d\n", ret);
+		return ret;
+	}
+	rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev,
+			"realtek,reset", GPIOD_OUT_LOW);
+	if (IS_ERR(rt5677->reset_pin)) {
+		ret = PTR_ERR(rt5677->reset_pin);
+		dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret);
+		return ret;
+	}
+
+	if (rt5677->pow_ldo2 || rt5677->reset_pin) {
+		/* Wait a while until I2C bus becomes available. The datasheet
+		 * does not specify the exact we should wait but startup
+		 * sequence mentiones at least a few milliseconds.
+		 */
+		msleep(10);
+	}
+
+	rt5677->regmap_physical = devm_regmap_init_i2c(i2c,
+					&rt5677_regmap_physical);
+	if (IS_ERR(rt5677->regmap_physical)) {
+		ret = PTR_ERR(rt5677->regmap_physical);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	rt5677->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt5677_regmap);
+	if (IS_ERR(rt5677->regmap)) {
+		ret = PTR_ERR(rt5677->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt5677->regmap, RT5677_VENDOR_ID2, &val);
+	if (val != RT5677_DEVICE_ID) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt5677\n", val);
+		return -ENODEV;
+	}
+
+	regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
+
+	ret = regmap_register_patch(rt5677->regmap, init_list,
+				    ARRAY_SIZE(init_list));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	if (rt5677->pdata.in1_diff)
+		regmap_update_bits(rt5677->regmap, RT5677_IN1,
+					RT5677_IN_DF1, RT5677_IN_DF1);
+
+	if (rt5677->pdata.in2_diff)
+		regmap_update_bits(rt5677->regmap, RT5677_IN1,
+					RT5677_IN_DF2, RT5677_IN_DF2);
+
+	if (rt5677->pdata.lout1_diff)
+		regmap_update_bits(rt5677->regmap, RT5677_LOUT1,
+					RT5677_LOUT1_L_DF, RT5677_LOUT1_L_DF);
+
+	if (rt5677->pdata.lout2_diff)
+		regmap_update_bits(rt5677->regmap, RT5677_LOUT1,
+					RT5677_LOUT2_L_DF, RT5677_LOUT2_L_DF);
+
+	if (rt5677->pdata.lout3_diff)
+		regmap_update_bits(rt5677->regmap, RT5677_LOUT1,
+					RT5677_LOUT3_L_DF, RT5677_LOUT3_L_DF);
+
+	if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
+		regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL2,
+					RT5677_GPIO5_FUNC_MASK,
+					RT5677_GPIO5_FUNC_DMIC);
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+					RT5677_GPIO5_DIR_MASK,
+					RT5677_GPIO5_DIR_OUT);
+	}
+
+	if (rt5677->pdata.micbias1_vdd_3v3)
+		regmap_update_bits(rt5677->regmap, RT5677_MICBIAS,
+			RT5677_MICBIAS1_CTRL_VDD_MASK,
+			RT5677_MICBIAS1_CTRL_VDD_3_3V);
+
+	rt5677_init_gpio(i2c);
+	rt5677_init_irq(i2c);
+
+	return devm_snd_soc_register_component(&i2c->dev,
+				      &soc_component_dev_rt5677,
+				      rt5677_dai, ARRAY_SIZE(rt5677_dai));
+}
+
+static int rt5677_i2c_remove(struct i2c_client *i2c)
+{
+	rt5677_free_irq(i2c);
+	rt5677_free_gpio(i2c);
+
+	return 0;
+}
+
+static struct i2c_driver rt5677_i2c_driver = {
+	.driver = {
+		.name = "rt5677",
+		.of_match_table = rt5677_of_match,
+		.acpi_match_table = ACPI_PTR(rt5677_acpi_match),
+	},
+	.probe_new = rt5677_i2c_probe,
+	.remove   = rt5677_i2c_remove,
+};
+module_i2c_driver(rt5677_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5677 driver");
+MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h
new file mode 100644
index 0000000..183d92b
--- /dev/null
+++ b/sound/soc/codecs/rt5677.h
@@ -0,0 +1,1822 @@
+/*
+ * rt5677.h  --  RT5677 ALSA SoC audio driver
+ *
+ * Copyright 2013 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5677_H__
+#define __RT5677_H__
+
+#include <linux/gpio/driver.h>
+#include <linux/gpio/consumer.h>
+
+/* Info */
+#define RT5677_RESET				0x00
+#define RT5677_VENDOR_ID			0xfd
+#define RT5677_VENDOR_ID1			0xfe
+#define RT5677_VENDOR_ID2			0xff
+/*  I/O - Output */
+#define RT5677_LOUT1				0x01
+/* I/O - Input */
+#define RT5677_IN1				0x03
+#define RT5677_MICBIAS				0x04
+/* I/O - SLIMBus */
+#define RT5677_SLIMBUS_PARAM			0x07
+#define RT5677_SLIMBUS_RX			0x08
+#define RT5677_SLIMBUS_CTRL			0x09
+/* I/O */
+#define RT5677_SIDETONE_CTRL			0x13
+/* I/O - ADC/DAC */
+#define RT5677_ANA_DAC1_2_3_SRC			0x15
+#define RT5677_IF_DSP_DAC3_4_MIXER		0x16
+#define RT5677_DAC4_DIG_VOL			0x17
+#define RT5677_DAC3_DIG_VOL			0x18
+#define RT5677_DAC1_DIG_VOL			0x19
+#define RT5677_DAC2_DIG_VOL			0x1a
+#define RT5677_IF_DSP_DAC2_MIXER		0x1b
+#define RT5677_STO1_ADC_DIG_VOL			0x1c
+#define RT5677_MONO_ADC_DIG_VOL			0x1d
+#define RT5677_STO1_2_ADC_BST			0x1e
+#define RT5677_STO2_ADC_DIG_VOL			0x1f
+/* Mixer - D-D */
+#define RT5677_ADC_BST_CTRL2			0x20
+#define RT5677_STO3_4_ADC_BST			0x21
+#define RT5677_STO3_ADC_DIG_VOL			0x22
+#define RT5677_STO4_ADC_DIG_VOL			0x23
+#define RT5677_STO4_ADC_MIXER			0x24
+#define RT5677_STO3_ADC_MIXER			0x25
+#define RT5677_STO2_ADC_MIXER			0x26
+#define RT5677_STO1_ADC_MIXER			0x27
+#define RT5677_MONO_ADC_MIXER			0x28
+#define RT5677_ADC_IF_DSP_DAC1_MIXER		0x29
+#define RT5677_STO1_DAC_MIXER			0x2a
+#define RT5677_MONO_DAC_MIXER			0x2b
+#define RT5677_DD1_MIXER			0x2c
+#define RT5677_DD2_MIXER			0x2d
+#define RT5677_IF3_DATA				0x2f
+#define RT5677_IF4_DATA				0x30
+/* Mixer - PDM */
+#define RT5677_PDM_OUT_CTRL			0x31
+#define RT5677_PDM_DATA_CTRL1			0x32
+#define RT5677_PDM_DATA_CTRL2			0x33
+#define RT5677_PDM1_DATA_CTRL2			0x34
+#define RT5677_PDM1_DATA_CTRL3			0x35
+#define RT5677_PDM1_DATA_CTRL4			0x36
+#define RT5677_PDM2_DATA_CTRL2			0x37
+#define RT5677_PDM2_DATA_CTRL3			0x38
+#define RT5677_PDM2_DATA_CTRL4			0x39
+/* TDM */
+#define RT5677_TDM1_CTRL1			0x3b
+#define RT5677_TDM1_CTRL2			0x3c
+#define RT5677_TDM1_CTRL3			0x3d
+#define RT5677_TDM1_CTRL4			0x3e
+#define RT5677_TDM1_CTRL5			0x3f
+#define RT5677_TDM2_CTRL1			0x40
+#define RT5677_TDM2_CTRL2			0x41
+#define RT5677_TDM2_CTRL3			0x42
+#define RT5677_TDM2_CTRL4			0x43
+#define RT5677_TDM2_CTRL5			0x44
+/* I2C_MASTER_CTRL */
+#define RT5677_I2C_MASTER_CTRL1			0x47
+#define RT5677_I2C_MASTER_CTRL2			0x48
+#define RT5677_I2C_MASTER_CTRL3			0x49
+#define RT5677_I2C_MASTER_CTRL4			0x4a
+#define RT5677_I2C_MASTER_CTRL5			0x4b
+#define RT5677_I2C_MASTER_CTRL6			0x4c
+#define RT5677_I2C_MASTER_CTRL7			0x4d
+#define RT5677_I2C_MASTER_CTRL8			0x4e
+/* DMIC */
+#define RT5677_DMIC_CTRL1			0x50
+#define RT5677_DMIC_CTRL2			0x51
+/* Haptic Generator */
+#define RT5677_HAP_GENE_CTRL1			0x56
+#define RT5677_HAP_GENE_CTRL2			0x57
+#define RT5677_HAP_GENE_CTRL3			0x58
+#define RT5677_HAP_GENE_CTRL4			0x59
+#define RT5677_HAP_GENE_CTRL5			0x5a
+#define RT5677_HAP_GENE_CTRL6			0x5b
+#define RT5677_HAP_GENE_CTRL7			0x5c
+#define RT5677_HAP_GENE_CTRL8			0x5d
+#define RT5677_HAP_GENE_CTRL9			0x5e
+#define RT5677_HAP_GENE_CTRL10			0x5f
+/* Power */
+#define RT5677_PWR_DIG1				0x61
+#define RT5677_PWR_DIG2				0x62
+#define RT5677_PWR_ANLG1			0x63
+#define RT5677_PWR_ANLG2			0x64
+#define RT5677_PWR_DSP1				0x65
+#define RT5677_PWR_DSP_ST			0x66
+#define RT5677_PWR_DSP2				0x67
+#define RT5677_ADC_DAC_HPF_CTRL1		0x68
+/* Private Register Control */
+#define RT5677_PRIV_INDEX			0x6a
+#define RT5677_PRIV_DATA			0x6c
+/* Format - ADC/DAC */
+#define RT5677_I2S4_SDP				0x6f
+#define RT5677_I2S1_SDP				0x70
+#define RT5677_I2S2_SDP				0x71
+#define RT5677_I2S3_SDP				0x72
+#define RT5677_CLK_TREE_CTRL1			0x73
+#define RT5677_CLK_TREE_CTRL2			0x74
+#define RT5677_CLK_TREE_CTRL3			0x75
+/* Function - Analog */
+#define RT5677_PLL1_CTRL1			0x7a
+#define RT5677_PLL1_CTRL2			0x7b
+#define RT5677_PLL2_CTRL1			0x7c
+#define RT5677_PLL2_CTRL2			0x7d
+#define RT5677_GLB_CLK1				0x80
+#define RT5677_GLB_CLK2				0x81
+#define RT5677_ASRC_1				0x83
+#define RT5677_ASRC_2				0x84
+#define RT5677_ASRC_3				0x85
+#define RT5677_ASRC_4				0x86
+#define RT5677_ASRC_5				0x87
+#define RT5677_ASRC_6				0x88
+#define RT5677_ASRC_7				0x89
+#define RT5677_ASRC_8				0x8a
+#define RT5677_ASRC_9				0x8b
+#define RT5677_ASRC_10				0x8c
+#define RT5677_ASRC_11				0x8d
+#define RT5677_ASRC_12				0x8e
+#define RT5677_ASRC_13				0x8f
+#define RT5677_ASRC_14				0x90
+#define RT5677_ASRC_15				0x91
+#define RT5677_ASRC_16				0x92
+#define RT5677_ASRC_17				0x93
+#define RT5677_ASRC_18				0x94
+#define RT5677_ASRC_19				0x95
+#define RT5677_ASRC_20				0x97
+#define RT5677_ASRC_21				0x98
+#define RT5677_ASRC_22				0x99
+#define RT5677_ASRC_23				0x9a
+#define RT5677_VAD_CTRL1			0x9c
+#define RT5677_VAD_CTRL2			0x9d
+#define RT5677_VAD_CTRL3			0x9e
+#define RT5677_VAD_CTRL4			0x9f
+#define RT5677_VAD_CTRL5			0xa0
+/* Function - Digital */
+#define RT5677_DSP_INB_CTRL1			0xa3
+#define RT5677_DSP_INB_CTRL2			0xa4
+#define RT5677_DSP_IN_OUTB_CTRL			0xa5
+#define RT5677_DSP_OUTB0_1_DIG_VOL		0xa6
+#define RT5677_DSP_OUTB2_3_DIG_VOL		0xa7
+#define RT5677_DSP_OUTB4_5_DIG_VOL		0xa8
+#define RT5677_DSP_OUTB6_7_DIG_VOL		0xa9
+#define RT5677_ADC_EQ_CTRL1			0xae
+#define RT5677_ADC_EQ_CTRL2			0xaf
+#define RT5677_EQ_CTRL1				0xb0
+#define RT5677_EQ_CTRL2				0xb1
+#define RT5677_EQ_CTRL3				0xb2
+#define RT5677_SOFT_VOL_ZERO_CROSS1		0xb3
+#define RT5677_JD_CTRL1				0xb5
+#define RT5677_JD_CTRL2				0xb6
+#define RT5677_JD_CTRL3				0xb8
+#define RT5677_IRQ_CTRL1			0xbd
+#define RT5677_IRQ_CTRL2			0xbe
+#define RT5677_GPIO_ST				0xbf
+#define RT5677_GPIO_CTRL1			0xc0
+#define RT5677_GPIO_CTRL2			0xc1
+#define RT5677_GPIO_CTRL3			0xc2
+#define RT5677_STO1_ADC_HI_FILTER1		0xc5
+#define RT5677_STO1_ADC_HI_FILTER2		0xc6
+#define RT5677_MONO_ADC_HI_FILTER1		0xc7
+#define RT5677_MONO_ADC_HI_FILTER2		0xc8
+#define RT5677_STO2_ADC_HI_FILTER1		0xc9
+#define RT5677_STO2_ADC_HI_FILTER2		0xca
+#define RT5677_STO3_ADC_HI_FILTER1		0xcb
+#define RT5677_STO3_ADC_HI_FILTER2		0xcc
+#define RT5677_STO4_ADC_HI_FILTER1		0xcd
+#define RT5677_STO4_ADC_HI_FILTER2		0xce
+#define RT5677_MB_DRC_CTRL1			0xd0
+#define RT5677_DRC1_CTRL1			0xd2
+#define RT5677_DRC1_CTRL2			0xd3
+#define RT5677_DRC1_CTRL3			0xd4
+#define RT5677_DRC1_CTRL4			0xd5
+#define RT5677_DRC1_CTRL5			0xd6
+#define RT5677_DRC1_CTRL6			0xd7
+#define RT5677_DRC2_CTRL1			0xd8
+#define RT5677_DRC2_CTRL2			0xd9
+#define RT5677_DRC2_CTRL3			0xda
+#define RT5677_DRC2_CTRL4			0xdb
+#define RT5677_DRC2_CTRL5			0xdc
+#define RT5677_DRC2_CTRL6			0xdd
+#define RT5677_DRC1_HL_CTRL1			0xde
+#define RT5677_DRC1_HL_CTRL2			0xdf
+#define RT5677_DRC2_HL_CTRL1			0xe0
+#define RT5677_DRC2_HL_CTRL2			0xe1
+#define RT5677_DSP_INB1_SRC_CTRL1		0xe3
+#define RT5677_DSP_INB1_SRC_CTRL2		0xe4
+#define RT5677_DSP_INB1_SRC_CTRL3		0xe5
+#define RT5677_DSP_INB1_SRC_CTRL4		0xe6
+#define RT5677_DSP_INB2_SRC_CTRL1		0xe7
+#define RT5677_DSP_INB2_SRC_CTRL2		0xe8
+#define RT5677_DSP_INB2_SRC_CTRL3		0xe9
+#define RT5677_DSP_INB2_SRC_CTRL4		0xea
+#define RT5677_DSP_INB3_SRC_CTRL1		0xeb
+#define RT5677_DSP_INB3_SRC_CTRL2		0xec
+#define RT5677_DSP_INB3_SRC_CTRL3		0xed
+#define RT5677_DSP_INB3_SRC_CTRL4		0xee
+#define RT5677_DSP_OUTB1_SRC_CTRL1		0xef
+#define RT5677_DSP_OUTB1_SRC_CTRL2		0xf0
+#define RT5677_DSP_OUTB1_SRC_CTRL3		0xf1
+#define RT5677_DSP_OUTB1_SRC_CTRL4		0xf2
+#define RT5677_DSP_OUTB2_SRC_CTRL1		0xf3
+#define RT5677_DSP_OUTB2_SRC_CTRL2		0xf4
+#define RT5677_DSP_OUTB2_SRC_CTRL3		0xf5
+#define RT5677_DSP_OUTB2_SRC_CTRL4		0xf6
+
+/* Virtual DSP Mixer Control */
+#define RT5677_DSP_OUTB_0123_MIXER_CTRL		0xf7
+#define RT5677_DSP_OUTB_45_MIXER_CTRL		0xf8
+#define RT5677_DSP_OUTB_67_MIXER_CTRL		0xf9
+
+/* General Control */
+#define RT5677_DIG_MISC				0xfa
+#define RT5677_GEN_CTRL1			0xfb
+#define RT5677_GEN_CTRL2			0xfc
+
+/* DSP Mode I2C Control*/
+#define RT5677_DSP_I2C_OP_CODE			0x00
+#define RT5677_DSP_I2C_ADDR_LSB			0x01
+#define RT5677_DSP_I2C_ADDR_MSB			0x02
+#define RT5677_DSP_I2C_DATA_LSB			0x03
+#define RT5677_DSP_I2C_DATA_MSB			0x04
+
+/* Index of Codec Private Register definition */
+#define RT5677_PR_DRC1_CTRL_1			0x01
+#define RT5677_PR_DRC1_CTRL_2			0x02
+#define RT5677_PR_DRC1_CTRL_3			0x03
+#define RT5677_PR_DRC1_CTRL_4			0x04
+#define RT5677_PR_DRC1_CTRL_5			0x05
+#define RT5677_PR_DRC1_CTRL_6			0x06
+#define RT5677_PR_DRC1_CTRL_7			0x07
+#define RT5677_PR_DRC2_CTRL_1			0x08
+#define RT5677_PR_DRC2_CTRL_2			0x09
+#define RT5677_PR_DRC2_CTRL_3			0x0a
+#define RT5677_PR_DRC2_CTRL_4			0x0b
+#define RT5677_PR_DRC2_CTRL_5			0x0c
+#define RT5677_PR_DRC2_CTRL_6			0x0d
+#define RT5677_PR_DRC2_CTRL_7			0x0e
+#define RT5677_BIAS_CUR1			0x10
+#define RT5677_BIAS_CUR2			0x12
+#define RT5677_BIAS_CUR3			0x13
+#define RT5677_BIAS_CUR4			0x14
+#define RT5677_BIAS_CUR5			0x15
+#define RT5677_VREF_LOUT_CTRL			0x17
+#define RT5677_DIG_VOL_CTRL1			0x1a
+#define RT5677_DIG_VOL_CTRL2			0x1b
+#define RT5677_ANA_ADC_GAIN_CTRL		0x1e
+#define RT5677_VAD_SRAM_TEST1			0x20
+#define RT5677_VAD_SRAM_TEST2			0x21
+#define RT5677_VAD_SRAM_TEST3			0x22
+#define RT5677_VAD_SRAM_TEST4			0x23
+#define RT5677_PAD_DRV_CTRL			0x26
+#define RT5677_DIG_IN_PIN_ST_CTRL1		0x29
+#define RT5677_DIG_IN_PIN_ST_CTRL2		0x2a
+#define RT5677_DIG_IN_PIN_ST_CTRL3		0x2b
+#define RT5677_PLL1_INT				0x38
+#define RT5677_PLL2_INT				0x39
+#define RT5677_TEST_CTRL1			0x3a
+#define RT5677_TEST_CTRL2			0x3b
+#define RT5677_TEST_CTRL3			0x3c
+#define RT5677_CHOP_DAC_ADC			0x3d
+#define RT5677_SOFT_DEPOP_DAC_CLK_CTRL		0x3e
+#define RT5677_CROSS_OVER_FILTER1		0x90
+#define RT5677_CROSS_OVER_FILTER2		0x91
+#define RT5677_CROSS_OVER_FILTER3		0x92
+#define RT5677_CROSS_OVER_FILTER4		0x93
+#define RT5677_CROSS_OVER_FILTER5		0x94
+#define RT5677_CROSS_OVER_FILTER6		0x95
+#define RT5677_CROSS_OVER_FILTER7		0x96
+#define RT5677_CROSS_OVER_FILTER8		0x97
+#define RT5677_CROSS_OVER_FILTER9		0x98
+#define RT5677_CROSS_OVER_FILTER10		0x99
+
+/* global definition */
+#define RT5677_L_MUTE				(0x1 << 15)
+#define RT5677_L_MUTE_SFT			15
+#define RT5677_VOL_L_MUTE			(0x1 << 14)
+#define RT5677_VOL_L_SFT			14
+#define RT5677_R_MUTE				(0x1 << 7)
+#define RT5677_R_MUTE_SFT			7
+#define RT5677_VOL_R_MUTE			(0x1 << 6)
+#define RT5677_VOL_R_SFT			6
+#define RT5677_L_VOL_MASK			(0x7f << 9)
+#define RT5677_L_VOL_SFT			9
+#define RT5677_R_VOL_MASK			(0x7f << 1)
+#define RT5677_R_VOL_SFT			1
+
+/* LOUT1 Control (0x01) */
+#define RT5677_LOUT1_L_MUTE			(0x1 << 15)
+#define RT5677_LOUT1_L_MUTE_SFT			(15)
+#define RT5677_LOUT1_L_DF			(0x1 << 14)
+#define RT5677_LOUT1_L_DF_SFT			(14)
+#define RT5677_LOUT2_L_MUTE			(0x1 << 13)
+#define RT5677_LOUT2_L_MUTE_SFT			(13)
+#define RT5677_LOUT2_L_DF			(0x1 << 12)
+#define RT5677_LOUT2_L_DF_SFT			(12)
+#define RT5677_LOUT3_L_MUTE			(0x1 << 11)
+#define RT5677_LOUT3_L_MUTE_SFT			(11)
+#define RT5677_LOUT3_L_DF			(0x1 << 10)
+#define RT5677_LOUT3_L_DF_SFT			(10)
+#define RT5677_LOUT1_ENH_DRV			(0x1 << 9)
+#define RT5677_LOUT1_ENH_DRV_SFT		(9)
+#define RT5677_LOUT2_ENH_DRV			(0x1 << 8)
+#define RT5677_LOUT2_ENH_DRV_SFT		(8)
+#define RT5677_LOUT3_ENH_DRV			(0x1 << 7)
+#define RT5677_LOUT3_ENH_DRV_SFT		(7)
+
+/* IN1 Control (0x03) */
+#define RT5677_BST_MASK1			(0xf << 12)
+#define RT5677_BST_SFT1				12
+#define RT5677_BST_MASK2			(0xf << 8)
+#define RT5677_BST_SFT2				8
+#define RT5677_IN_DF1				(0x1 << 7)
+#define RT5677_IN_DF1_SFT			7
+#define RT5677_IN_DF2				(0x1 << 6)
+#define RT5677_IN_DF2_SFT			6
+
+/* Micbias Control (0x04) */
+#define RT5677_MICBIAS1_OUTVOLT_MASK		(0x1 << 15)
+#define RT5677_MICBIAS1_OUTVOLT_SFT		(15)
+#define RT5677_MICBIAS1_OUTVOLT_2_7V		(0x0 << 15)
+#define RT5677_MICBIAS1_OUTVOLT_2_25V		(0x1 << 15)
+#define RT5677_MICBIAS1_CTRL_VDD_MASK		(0x1 << 14)
+#define RT5677_MICBIAS1_CTRL_VDD_SFT		(14)
+#define RT5677_MICBIAS1_CTRL_VDD_1_8V		(0x0 << 14)
+#define RT5677_MICBIAS1_CTRL_VDD_3_3V		(0x1 << 14)
+#define RT5677_MICBIAS1_OVCD_MASK		(0x1 << 11)
+#define RT5677_MICBIAS1_OVCD_SHIFT		(11)
+#define RT5677_MICBIAS1_OVCD_DIS		(0x0 << 11)
+#define RT5677_MICBIAS1_OVCD_EN			(0x1 << 11)
+#define RT5677_MICBIAS1_OVTH_MASK		(0x3 << 9)
+#define RT5677_MICBIAS1_OVTH_SFT		9
+#define RT5677_MICBIAS1_OVTH_640UA		(0x0 << 9)
+#define RT5677_MICBIAS1_OVTH_1280UA		(0x1 << 9)
+#define RT5677_MICBIAS1_OVTH_1920UA		(0x2 << 9)
+
+/* SLIMbus Parameter (0x07) */
+
+/* SLIMbus Rx (0x08) */
+#define RT5677_SLB_ADC4_MASK			(0x3 << 6)
+#define RT5677_SLB_ADC4_SFT			6
+#define RT5677_SLB_ADC3_MASK			(0x3 << 4)
+#define RT5677_SLB_ADC3_SFT			4
+#define RT5677_SLB_ADC2_MASK			(0x3 << 2)
+#define RT5677_SLB_ADC2_SFT			2
+#define RT5677_SLB_ADC1_MASK			(0x3 << 0)
+#define RT5677_SLB_ADC1_SFT			0
+
+/* SLIMBus control (0x09) */
+
+/* Sidetone Control (0x13) */
+#define RT5677_ST_HPF_SEL_MASK			(0x7 << 13)
+#define RT5677_ST_HPF_SEL_SFT			13
+#define RT5677_ST_HPF_PATH			(0x1 << 12)
+#define RT5677_ST_HPF_PATH_SFT			12
+#define RT5677_ST_SEL_MASK			(0x7 << 9)
+#define RT5677_ST_SEL_SFT			9
+#define RT5677_ST_EN				(0x1 << 6)
+#define RT5677_ST_EN_SFT			6
+#define RT5677_ST_GAIN				(0x1 << 5)
+#define RT5677_ST_GAIN_SFT			5
+#define RT5677_ST_VOL_MASK			(0x1f << 0)
+#define RT5677_ST_VOL_SFT			0
+
+/* Analog DAC1/2/3 Source Control (0x15) */
+#define RT5677_ANA_DAC3_SRC_SEL_MASK		(0x3 << 4)
+#define RT5677_ANA_DAC3_SRC_SEL_SFT		4
+#define RT5677_ANA_DAC1_2_SRC_SEL_MASK		(0x3 << 0)
+#define RT5677_ANA_DAC1_2_SRC_SEL_SFT		0
+
+/* IF/DSP to DAC3/4 Mixer Control (0x16) */
+#define RT5677_M_DAC4_L_VOL			(0x1 << 15)
+#define RT5677_M_DAC4_L_VOL_SFT			15
+#define RT5677_SEL_DAC4_L_SRC_MASK		(0x7 << 12)
+#define RT5677_SEL_DAC4_L_SRC_SFT		12
+#define RT5677_M_DAC4_R_VOL			(0x1 << 11)
+#define RT5677_M_DAC4_R_VOL_SFT			11
+#define RT5677_SEL_DAC4_R_SRC_MASK		(0x7 << 8)
+#define RT5677_SEL_DAC4_R_SRC_SFT		8
+#define RT5677_M_DAC3_L_VOL			(0x1 << 7)
+#define RT5677_M_DAC3_L_VOL_SFT			7
+#define RT5677_SEL_DAC3_L_SRC_MASK		(0x7 << 4)
+#define RT5677_SEL_DAC3_L_SRC_SFT		4
+#define RT5677_M_DAC3_R_VOL			(0x1 << 3)
+#define RT5677_M_DAC3_R_VOL_SFT			3
+#define RT5677_SEL_DAC3_R_SRC_MASK		(0x7 << 0)
+#define RT5677_SEL_DAC3_R_SRC_SFT		0
+
+/* DAC4 Digital Volume (0x17) */
+#define RT5677_DAC4_L_VOL_MASK			(0xff << 8)
+#define RT5677_DAC4_L_VOL_SFT			8
+#define RT5677_DAC4_R_VOL_MASK			(0xff)
+#define RT5677_DAC4_R_VOL_SFT			0
+
+/* DAC3 Digital Volume (0x18) */
+#define RT5677_DAC3_L_VOL_MASK			(0xff << 8)
+#define RT5677_DAC3_L_VOL_SFT			8
+#define RT5677_DAC3_R_VOL_MASK			(0xff)
+#define RT5677_DAC3_R_VOL_SFT			0
+
+/* DAC3 Digital Volume (0x19) */
+#define RT5677_DAC1_L_VOL_MASK			(0xff << 8)
+#define RT5677_DAC1_L_VOL_SFT			8
+#define RT5677_DAC1_R_VOL_MASK			(0xff)
+#define RT5677_DAC1_R_VOL_SFT			0
+
+/* DAC2 Digital Volume (0x1a) */
+#define RT5677_DAC2_L_VOL_MASK			(0xff << 8)
+#define RT5677_DAC2_L_VOL_SFT			8
+#define RT5677_DAC2_R_VOL_MASK			(0xff)
+#define RT5677_DAC2_R_VOL_SFT			0
+
+/* IF/DSP to DAC2 Mixer Control (0x1b) */
+#define RT5677_M_DAC2_L_VOL			(0x1 << 7)
+#define RT5677_M_DAC2_L_VOL_SFT			7
+#define RT5677_SEL_DAC2_L_SRC_MASK		(0x7 << 4)
+#define RT5677_SEL_DAC2_L_SRC_SFT		4
+#define RT5677_M_DAC2_R_VOL			(0x1 << 3)
+#define RT5677_M_DAC2_R_VOL_SFT			3
+#define RT5677_SEL_DAC2_R_SRC_MASK		(0x7 << 0)
+#define RT5677_SEL_DAC2_R_SRC_SFT		0
+
+/* Stereo1 ADC Digital Volume Control (0x1c) */
+#define RT5677_STO1_ADC_L_VOL_MASK		(0x3f << 9)
+#define RT5677_STO1_ADC_L_VOL_SFT		9
+#define RT5677_STO1_ADC_R_VOL_MASK		(0x3f << 1)
+#define RT5677_STO1_ADC_R_VOL_SFT		1
+
+/* Mono ADC Digital Volume Control (0x1d) */
+#define RT5677_MONO_ADC_L_VOL_MASK		(0x3f << 9)
+#define RT5677_MONO_ADC_L_VOL_SFT		9
+#define RT5677_MONO_ADC_R_VOL_MASK		(0x3f << 1)
+#define RT5677_MONO_ADC_R_VOL_SFT		1
+
+/* Stereo 1/2 ADC Boost Gain Control (0x1e) */
+#define RT5677_STO1_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5677_STO1_ADC_L_BST_SFT		14
+#define RT5677_STO1_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5677_STO1_ADC_R_BST_SFT		12
+#define RT5677_STO1_ADC_COMP_MASK		(0x3 << 10)
+#define RT5677_STO1_ADC_COMP_SFT		10
+#define RT5677_STO2_ADC_L_BST_MASK		(0x3 << 8)
+#define RT5677_STO2_ADC_L_BST_SFT		8
+#define RT5677_STO2_ADC_R_BST_MASK		(0x3 << 6)
+#define RT5677_STO2_ADC_R_BST_SFT		6
+#define RT5677_STO2_ADC_COMP_MASK		(0x3 << 4)
+#define RT5677_STO2_ADC_COMP_SFT		4
+
+/* Stereo2 ADC Digital Volume Control (0x1f) */
+#define RT5677_STO2_ADC_L_VOL_MASK		(0x7f << 8)
+#define RT5677_STO2_ADC_L_VOL_SFT		8
+#define RT5677_STO2_ADC_R_VOL_MASK		(0x7f)
+#define RT5677_STO2_ADC_R_VOL_SFT		0
+
+/* ADC Boost Gain Control 2 (0x20) */
+#define RT5677_MONO_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5677_MONO_ADC_L_BST_SFT		14
+#define RT5677_MONO_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5677_MONO_ADC_R_BST_SFT		12
+#define RT5677_MONO_ADC_COMP_MASK		(0x3 << 10)
+#define RT5677_MONO_ADC_COMP_SFT		10
+
+/* Stereo 3/4 ADC Boost Gain Control (0x21) */
+#define RT5677_STO3_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5677_STO3_ADC_L_BST_SFT		14
+#define RT5677_STO3_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5677_STO3_ADC_R_BST_SFT		12
+#define RT5677_STO3_ADC_COMP_MASK		(0x3 << 10)
+#define RT5677_STO3_ADC_COMP_SFT		10
+#define RT5677_STO4_ADC_L_BST_MASK		(0x3 << 8)
+#define RT5677_STO4_ADC_L_BST_SFT		8
+#define RT5677_STO4_ADC_R_BST_MASK		(0x3 << 6)
+#define RT5677_STO4_ADC_R_BST_SFT		6
+#define RT5677_STO4_ADC_COMP_MASK		(0x3 << 4)
+#define RT5677_STO4_ADC_COMP_SFT		4
+
+/* Stereo3 ADC Digital Volume Control (0x22) */
+#define RT5677_STO3_ADC_L_VOL_MASK		(0x7f << 8)
+#define RT5677_STO3_ADC_L_VOL_SFT		8
+#define RT5677_STO3_ADC_R_VOL_MASK		(0x7f)
+#define RT5677_STO3_ADC_R_VOL_SFT		0
+
+/* Stereo4 ADC Digital Volume Control (0x23) */
+#define RT5677_STO4_ADC_L_VOL_MASK		(0x7f << 8)
+#define RT5677_STO4_ADC_L_VOL_SFT		8
+#define RT5677_STO4_ADC_R_VOL_MASK		(0x7f)
+#define RT5677_STO4_ADC_R_VOL_SFT		0
+
+/* Stereo4 ADC Mixer control (0x24) */
+#define RT5677_M_STO4_ADC_L2			(0x1 << 15)
+#define RT5677_M_STO4_ADC_L2_SFT		15
+#define RT5677_M_STO4_ADC_L1			(0x1 << 14)
+#define RT5677_M_STO4_ADC_L1_SFT		14
+#define RT5677_SEL_STO4_ADC1_MASK		(0x3 << 12)
+#define RT5677_SEL_STO4_ADC1_SFT		12
+#define RT5677_SEL_STO4_ADC2_MASK		(0x3 << 10)
+#define RT5677_SEL_STO4_ADC2_SFT		10
+#define RT5677_SEL_STO4_DMIC_MASK		(0x3 << 8)
+#define RT5677_SEL_STO4_DMIC_SFT		8
+#define RT5677_M_STO4_ADC_R1			(0x1 << 7)
+#define RT5677_M_STO4_ADC_R1_SFT		7
+#define RT5677_M_STO4_ADC_R2			(0x1 << 6)
+#define RT5677_M_STO4_ADC_R2_SFT		6
+
+/* Stereo3 ADC Mixer control (0x25) */
+#define RT5677_M_STO3_ADC_L2			(0x1 << 15)
+#define RT5677_M_STO3_ADC_L2_SFT		15
+#define RT5677_M_STO3_ADC_L1			(0x1 << 14)
+#define RT5677_M_STO3_ADC_L1_SFT		14
+#define RT5677_SEL_STO3_ADC1_MASK		(0x3 << 12)
+#define RT5677_SEL_STO3_ADC1_SFT		12
+#define RT5677_SEL_STO3_ADC2_MASK		(0x3 << 10)
+#define RT5677_SEL_STO3_ADC2_SFT		10
+#define RT5677_SEL_STO3_DMIC_MASK		(0x3 << 8)
+#define RT5677_SEL_STO3_DMIC_SFT		8
+#define RT5677_M_STO3_ADC_R1			(0x1 << 7)
+#define RT5677_M_STO3_ADC_R1_SFT		7
+#define RT5677_M_STO3_ADC_R2			(0x1 << 6)
+#define RT5677_M_STO3_ADC_R2_SFT		6
+
+/* Stereo2 ADC Mixer Control (0x26) */
+#define RT5677_M_STO2_ADC_L2			(0x1 << 15)
+#define RT5677_M_STO2_ADC_L2_SFT		15
+#define RT5677_M_STO2_ADC_L1			(0x1 << 14)
+#define RT5677_M_STO2_ADC_L1_SFT		14
+#define RT5677_SEL_STO2_ADC1_MASK		(0x3 << 12)
+#define RT5677_SEL_STO2_ADC1_SFT		12
+#define RT5677_SEL_STO2_ADC2_MASK		(0x3 << 10)
+#define RT5677_SEL_STO2_ADC2_SFT		10
+#define RT5677_SEL_STO2_DMIC_MASK		(0x3 << 8)
+#define RT5677_SEL_STO2_DMIC_SFT		8
+#define RT5677_M_STO2_ADC_R1			(0x1 << 7)
+#define RT5677_M_STO2_ADC_R1_SFT		7
+#define RT5677_M_STO2_ADC_R2			(0x1 << 6)
+#define RT5677_M_STO2_ADC_R2_SFT		6
+#define RT5677_SEL_STO2_LR_MIX_MASK		(0x1 << 0)
+#define RT5677_SEL_STO2_LR_MIX_SFT		0
+#define RT5677_SEL_STO2_LR_MIX_L		(0x0 << 0)
+#define RT5677_SEL_STO2_LR_MIX_LR		(0x1 << 0)
+
+/* Stereo1 ADC Mixer control (0x27) */
+#define RT5677_M_STO1_ADC_L2			(0x1 << 15)
+#define RT5677_M_STO1_ADC_L2_SFT		15
+#define RT5677_M_STO1_ADC_L1			(0x1 << 14)
+#define RT5677_M_STO1_ADC_L1_SFT		14
+#define RT5677_SEL_STO1_ADC1_MASK		(0x3 << 12)
+#define RT5677_SEL_STO1_ADC1_SFT		12
+#define RT5677_SEL_STO1_ADC2_MASK		(0x3 << 10)
+#define RT5677_SEL_STO1_ADC2_SFT		10
+#define RT5677_SEL_STO1_DMIC_MASK		(0x3 << 8)
+#define RT5677_SEL_STO1_DMIC_SFT		8
+#define RT5677_M_STO1_ADC_R1			(0x1 << 7)
+#define RT5677_M_STO1_ADC_R1_SFT		7
+#define RT5677_M_STO1_ADC_R2			(0x1 << 6)
+#define RT5677_M_STO1_ADC_R2_SFT		6
+
+/* Mono ADC Mixer control (0x28) */
+#define RT5677_M_MONO_ADC_L2			(0x1 << 15)
+#define RT5677_M_MONO_ADC_L2_SFT		15
+#define RT5677_M_MONO_ADC_L1			(0x1 << 14)
+#define RT5677_M_MONO_ADC_L1_SFT		14
+#define RT5677_SEL_MONO_ADC_L1_MASK		(0x3 << 12)
+#define RT5677_SEL_MONO_ADC_L1_SFT		12
+#define RT5677_SEL_MONO_ADC_L2_MASK		(0x3 << 10)
+#define RT5677_SEL_MONO_ADC_L2_SFT		10
+#define RT5677_SEL_MONO_DMIC_L_MASK		(0x3 << 8)
+#define RT5677_SEL_MONO_DMIC_L_SFT		8
+#define RT5677_M_MONO_ADC_R1			(0x1 << 7)
+#define RT5677_M_MONO_ADC_R1_SFT		7
+#define RT5677_M_MONO_ADC_R2			(0x1 << 6)
+#define RT5677_M_MONO_ADC_R2_SFT		6
+#define RT5677_SEL_MONO_ADC_R1_MASK		(0x3 << 4)
+#define RT5677_SEL_MONO_ADC_R1_SFT		4
+#define RT5677_SEL_MONO_ADC_R2_MASK		(0x3 << 2)
+#define RT5677_SEL_MONO_ADC_R2_SFT		2
+#define RT5677_SEL_MONO_DMIC_R_MASK		(0x3 << 0)
+#define RT5677_SEL_MONO_DMIC_R_SFT		0
+
+/* ADC/IF/DSP to DAC1 Mixer control (0x29) */
+#define RT5677_M_ADDA_MIXER1_L			(0x1 << 15)
+#define RT5677_M_ADDA_MIXER1_L_SFT		15
+#define RT5677_M_DAC1_L				(0x1 << 14)
+#define RT5677_M_DAC1_L_SFT			14
+#define RT5677_DAC1_L_SEL_MASK			(0x7 << 8)
+#define RT5677_DAC1_L_SEL_SFT			8
+#define RT5677_M_ADDA_MIXER1_R			(0x1 << 7)
+#define RT5677_M_ADDA_MIXER1_R_SFT		7
+#define RT5677_M_DAC1_R				(0x1 << 6)
+#define RT5677_M_DAC1_R_SFT			6
+#define RT5677_ADDA1_SEL_MASK			(0x3 << 0)
+#define RT5677_ADDA1_SEL_SFT			0
+
+/* Stereo1 DAC Mixer L/R Control (0x2a) */
+#define RT5677_M_ST_DAC1_L			(0x1 << 15)
+#define RT5677_M_ST_DAC1_L_SFT			15
+#define RT5677_M_DAC1_L_STO_L			(0x1 << 13)
+#define RT5677_M_DAC1_L_STO_L_SFT		13
+#define RT5677_DAC1_L_STO_L_VOL_MASK		(0x1 << 12)
+#define RT5677_DAC1_L_STO_L_VOL_SFT		12
+#define RT5677_M_DAC2_L_STO_L			(0x1 << 11)
+#define RT5677_M_DAC2_L_STO_L_SFT		11
+#define RT5677_DAC2_L_STO_L_VOL_MASK		(0x1 << 10)
+#define RT5677_DAC2_L_STO_L_VOL_SFT		10
+#define RT5677_M_DAC1_R_STO_L			(0x1 << 9)
+#define RT5677_M_DAC1_R_STO_L_SFT		9
+#define RT5677_DAC1_R_STO_L_VOL_MASK		(0x1 << 8)
+#define RT5677_DAC1_R_STO_L_VOL_SFT		8
+#define RT5677_M_ST_DAC1_R			(0x1 << 7)
+#define RT5677_M_ST_DAC1_R_SFT			7
+#define RT5677_M_DAC1_R_STO_R			(0x1 << 5)
+#define RT5677_M_DAC1_R_STO_R_SFT		5
+#define RT5677_DAC1_R_STO_R_VOL_MASK		(0x1 << 4)
+#define RT5677_DAC1_R_STO_R_VOL_SFT		4
+#define RT5677_M_DAC2_R_STO_R			(0x1 << 3)
+#define RT5677_M_DAC2_R_STO_R_SFT		3
+#define RT5677_DAC2_R_STO_R_VOL_MASK		(0x1 << 2)
+#define RT5677_DAC2_R_STO_R_VOL_SFT		2
+#define RT5677_M_DAC1_L_STO_R			(0x1 << 1)
+#define RT5677_M_DAC1_L_STO_R_SFT		1
+#define RT5677_DAC1_L_STO_R_VOL_MASK		(0x1 << 0)
+#define RT5677_DAC1_L_STO_R_VOL_SFT		0
+
+/* Mono DAC Mixer L/R Control (0x2b) */
+#define RT5677_M_ST_DAC2_L			(0x1 << 15)
+#define RT5677_M_ST_DAC2_L_SFT			15
+#define RT5677_M_DAC2_L_MONO_L			(0x1 << 13)
+#define RT5677_M_DAC2_L_MONO_L_SFT		13
+#define RT5677_DAC2_L_MONO_L_VOL_MASK		(0x1 << 12)
+#define RT5677_DAC2_L_MONO_L_VOL_SFT		12
+#define RT5677_M_DAC2_R_MONO_L			(0x1 << 11)
+#define RT5677_M_DAC2_R_MONO_L_SFT		11
+#define RT5677_DAC2_R_MONO_L_VOL_MASK		(0x1 << 10)
+#define RT5677_DAC2_R_MONO_L_VOL_SFT		10
+#define RT5677_M_DAC1_L_MONO_L			(0x1 << 9)
+#define RT5677_M_DAC1_L_MONO_L_SFT		9
+#define RT5677_DAC1_L_MONO_L_VOL_MASK		(0x1 << 8)
+#define RT5677_DAC1_L_MONO_L_VOL_SFT		8
+#define RT5677_M_ST_DAC2_R			(0x1 << 7)
+#define RT5677_M_ST_DAC2_R_SFT			7
+#define RT5677_M_DAC2_R_MONO_R			(0x1 << 5)
+#define RT5677_M_DAC2_R_MONO_R_SFT		5
+#define RT5677_DAC2_R_MONO_R_VOL_MASK		(0x1 << 4)
+#define RT5677_DAC2_R_MONO_R_VOL_SFT		4
+#define RT5677_M_DAC1_R_MONO_R			(0x1 << 3)
+#define RT5677_M_DAC1_R_MONO_R_SFT		3
+#define RT5677_DAC1_R_MONO_R_VOL_MASK		(0x1 << 2)
+#define RT5677_DAC1_R_MONO_R_VOL_SFT		2
+#define RT5677_M_DAC2_L_MONO_R			(0x1 << 1)
+#define RT5677_M_DAC2_L_MONO_R_SFT		1
+#define RT5677_DAC2_L_MONO_R_VOL_MASK		(0x1 << 0)
+#define RT5677_DAC2_L_MONO_R_VOL_SFT		0
+
+/* DD Mixer 1 Control (0x2c) */
+#define RT5677_M_STO_L_DD1_L			(0x1 << 15)
+#define RT5677_M_STO_L_DD1_L_SFT		15
+#define RT5677_STO_L_DD1_L_VOL_MASK		(0x1 << 14)
+#define RT5677_STO_L_DD1_L_VOL_SFT		14
+#define RT5677_M_MONO_L_DD1_L			(0x1 << 13)
+#define RT5677_M_MONO_L_DD1_L_SFT		13
+#define RT5677_MONO_L_DD1_L_VOL_MASK		(0x1 << 12)
+#define RT5677_MONO_L_DD1_L_VOL_SFT		12
+#define RT5677_M_DAC3_L_DD1_L			(0x1 << 11)
+#define RT5677_M_DAC3_L_DD1_L_SFT		11
+#define RT5677_DAC3_L_DD1_L_VOL_MASK		(0x1 << 10)
+#define RT5677_DAC3_L_DD1_L_VOL_SFT		10
+#define RT5677_M_DAC3_R_DD1_L			(0x1 << 9)
+#define RT5677_M_DAC3_R_DD1_L_SFT		9
+#define RT5677_DAC3_R_DD1_L_VOL_MASK		(0x1 << 8)
+#define RT5677_DAC3_R_DD1_L_VOL_SFT		8
+#define RT5677_M_STO_R_DD1_R			(0x1 << 7)
+#define RT5677_M_STO_R_DD1_R_SFT		7
+#define RT5677_STO_R_DD1_R_VOL_MASK		(0x1 << 6)
+#define RT5677_STO_R_DD1_R_VOL_SFT		6
+#define RT5677_M_MONO_R_DD1_R			(0x1 << 5)
+#define RT5677_M_MONO_R_DD1_R_SFT		5
+#define RT5677_MONO_R_DD1_R_VOL_MASK		(0x1 << 4)
+#define RT5677_MONO_R_DD1_R_VOL_SFT		4
+#define RT5677_M_DAC3_R_DD1_R			(0x1 << 3)
+#define RT5677_M_DAC3_R_DD1_R_SFT		3
+#define RT5677_DAC3_R_DD1_R_VOL_MASK		(0x1 << 2)
+#define RT5677_DAC3_R_DD1_R_VOL_SFT		2
+#define RT5677_M_DAC3_L_DD1_R			(0x1 << 1)
+#define RT5677_M_DAC3_L_DD1_R_SFT		1
+#define RT5677_DAC3_L_DD1_R_VOL_MASK		(0x1 << 0)
+#define RT5677_DAC3_L_DD1_R_VOL_SFT		0
+
+/* DD Mixer 2 Control (0x2d) */
+#define RT5677_M_STO_L_DD2_L			(0x1 << 15)
+#define RT5677_M_STO_L_DD2_L_SFT		15
+#define RT5677_STO_L_DD2_L_VOL_MASK		(0x1 << 14)
+#define RT5677_STO_L_DD2_L_VOL_SFT		14
+#define RT5677_M_MONO_L_DD2_L			(0x1 << 13)
+#define RT5677_M_MONO_L_DD2_L_SFT		13
+#define RT5677_MONO_L_DD2_L_VOL_MASK		(0x1 << 12)
+#define RT5677_MONO_L_DD2_L_VOL_SFT		12
+#define RT5677_M_DAC4_L_DD2_L			(0x1 << 11)
+#define RT5677_M_DAC4_L_DD2_L_SFT		11
+#define RT5677_DAC4_L_DD2_L_VOL_MASK		(0x1 << 10)
+#define RT5677_DAC4_L_DD2_L_VOL_SFT		10
+#define RT5677_M_DAC4_R_DD2_L			(0x1 << 9)
+#define RT5677_M_DAC4_R_DD2_L_SFT		9
+#define RT5677_DAC4_R_DD2_L_VOL_MASK		(0x1 << 8)
+#define RT5677_DAC4_R_DD2_L_VOL_SFT		8
+#define RT5677_M_STO_R_DD2_R			(0x1 << 7)
+#define RT5677_M_STO_R_DD2_R_SFT		7
+#define RT5677_STO_R_DD2_R_VOL_MASK		(0x1 << 6)
+#define RT5677_STO_R_DD2_R_VOL_SFT		6
+#define RT5677_M_MONO_R_DD2_R			(0x1 << 5)
+#define RT5677_M_MONO_R_DD2_R_SFT		5
+#define RT5677_MONO_R_DD2_R_VOL_MASK		(0x1 << 4)
+#define RT5677_MONO_R_DD2_R_VOL_SFT		4
+#define RT5677_M_DAC4_R_DD2_R			(0x1 << 3)
+#define RT5677_M_DAC4_R_DD2_R_SFT		3
+#define RT5677_DAC4_R_DD2_R_VOL_MASK		(0x1 << 2)
+#define RT5677_DAC4_R_DD2_R_VOL_SFT		2
+#define RT5677_M_DAC4_L_DD2_R			(0x1 << 1)
+#define RT5677_M_DAC4_L_DD2_R_SFT		1
+#define RT5677_DAC4_L_DD2_R_VOL_MASK		(0x1 << 0)
+#define RT5677_DAC4_L_DD2_R_VOL_SFT		0
+
+/* IF3 data control (0x2f) */
+#define RT5677_IF3_DAC_SEL_MASK			(0x3 << 6)
+#define RT5677_IF3_DAC_SEL_SFT			6
+#define RT5677_IF3_ADC_SEL_MASK			(0x3 << 4)
+#define RT5677_IF3_ADC_SEL_SFT			4
+#define RT5677_IF3_ADC_IN_MASK			(0xf << 0)
+#define RT5677_IF3_ADC_IN_SFT			0
+
+/* IF4 data control (0x30) */
+#define RT5677_IF4_ADC_IN_MASK			(0xf << 4)
+#define RT5677_IF4_ADC_IN_SFT			4
+#define RT5677_IF4_DAC_SEL_MASK			(0x3 << 2)
+#define RT5677_IF4_DAC_SEL_SFT			2
+#define RT5677_IF4_ADC_SEL_MASK			(0x3 << 0)
+#define RT5677_IF4_ADC_SEL_SFT			0
+
+/* PDM Output Control (0x31) */
+#define RT5677_M_PDM1_L				(0x1 << 15)
+#define RT5677_M_PDM1_L_SFT			15
+#define RT5677_SEL_PDM1_L_MASK			(0x3 << 12)
+#define RT5677_SEL_PDM1_L_SFT			12
+#define RT5677_M_PDM1_R				(0x1 << 11)
+#define RT5677_M_PDM1_R_SFT			11
+#define RT5677_SEL_PDM1_R_MASK			(0x3 << 8)
+#define RT5677_SEL_PDM1_R_SFT			8
+#define RT5677_M_PDM2_L				(0x1 << 7)
+#define RT5677_M_PDM2_L_SFT			7
+#define RT5677_SEL_PDM2_L_MASK			(0x3 << 4)
+#define RT5677_SEL_PDM2_L_SFT			4
+#define RT5677_M_PDM2_R				(0x1 << 3)
+#define RT5677_M_PDM2_R_SFT			3
+#define RT5677_SEL_PDM2_R_MASK			(0x3 << 0)
+#define RT5677_SEL_PDM2_R_SFT			0
+
+/* PDM I2C / Data Control 1 (0x32) */
+#define RT5677_PDM2_PW_DOWN			(0x1 << 7)
+#define RT5677_PDM1_PW_DOWN			(0x1 << 6)
+#define RT5677_PDM2_BUSY			(0x1 << 5)
+#define RT5677_PDM1_BUSY			(0x1 << 4)
+#define RT5677_PDM_PATTERN			(0x1 << 3)
+#define RT5677_PDM_GAIN				(0x1 << 2)
+#define RT5677_PDM_DIV_MASK			(0x3 << 0)
+
+/* PDM I2C / Data Control 2 (0x33) */
+#define RT5677_PDM1_I2C_ID			(0xf << 12)
+#define RT5677_PDM1_EXE				(0x1 << 11)
+#define RT5677_PDM1_I2C_CMD			(0x1 << 10)
+#define RT5677_PDM1_I2C_EXE			(0x1 << 9)
+#define RT5677_PDM1_I2C_BUSY			(0x1 << 8)
+#define RT5677_PDM2_I2C_ID			(0xf << 4)
+#define RT5677_PDM2_EXE				(0x1 << 3)
+#define RT5677_PDM2_I2C_CMD			(0x1 << 2)
+#define RT5677_PDM2_I2C_EXE			(0x1 << 1)
+#define RT5677_PDM2_I2C_BUSY			(0x1 << 0)
+
+/* TDM1 control 1 (0x3b) */
+#define RT5677_IF1_ADC_MODE_MASK		(0x1 << 12)
+#define RT5677_IF1_ADC_MODE_SFT			12
+#define RT5677_IF1_ADC_MODE_I2S			(0x0 << 12)
+#define RT5677_IF1_ADC_MODE_TDM			(0x1 << 12)
+#define RT5677_IF1_ADC1_SWAP_MASK		(0x3 << 6)
+#define RT5677_IF1_ADC1_SWAP_SFT		6
+#define RT5677_IF1_ADC2_SWAP_MASK		(0x3 << 4)
+#define RT5677_IF1_ADC2_SWAP_SFT		4
+#define RT5677_IF1_ADC3_SWAP_MASK		(0x3 << 2)
+#define RT5677_IF1_ADC3_SWAP_SFT		2
+#define RT5677_IF1_ADC4_SWAP_MASK		(0x3 << 0)
+#define RT5677_IF1_ADC4_SWAP_SFT		0
+
+/* TDM1 control 2 (0x3c) */
+#define RT5677_IF1_ADC4_MASK			(0x3 << 10)
+#define RT5677_IF1_ADC4_SFT			10
+#define RT5677_IF1_ADC3_MASK			(0x3 << 8)
+#define RT5677_IF1_ADC3_SFT			8
+#define RT5677_IF1_ADC2_MASK			(0x3 << 6)
+#define RT5677_IF1_ADC2_SFT			6
+#define RT5677_IF1_ADC1_MASK			(0x3 << 4)
+#define RT5677_IF1_ADC1_SFT			4
+#define RT5677_IF1_ADC_CTRL_MASK		(0x7 << 0)
+#define RT5677_IF1_ADC_CTRL_SFT			0
+
+/* TDM1 control 4 (0x3e) */
+#define RT5677_IF1_DAC0_MASK			(0x7 << 12)
+#define RT5677_IF1_DAC0_SFT			12
+#define RT5677_IF1_DAC1_MASK			(0x7 << 8)
+#define RT5677_IF1_DAC1_SFT			8
+#define RT5677_IF1_DAC2_MASK			(0x7 << 4)
+#define RT5677_IF1_DAC2_SFT			4
+#define RT5677_IF1_DAC3_MASK			(0x7 << 0)
+#define RT5677_IF1_DAC3_SFT			0
+
+/* TDM1 control 5 (0x3f) */
+#define RT5677_IF1_DAC4_MASK			(0x7 << 12)
+#define RT5677_IF1_DAC4_SFT			12
+#define RT5677_IF1_DAC5_MASK			(0x7 << 8)
+#define RT5677_IF1_DAC5_SFT			8
+#define RT5677_IF1_DAC6_MASK			(0x7 << 4)
+#define RT5677_IF1_DAC6_SFT			4
+#define RT5677_IF1_DAC7_MASK			(0x7 << 0)
+#define RT5677_IF1_DAC7_SFT			0
+
+/* TDM2 control 1 (0x40) */
+#define RT5677_IF2_ADC_MODE_MASK		(0x1 << 12)
+#define RT5677_IF2_ADC_MODE_SFT			12
+#define RT5677_IF2_ADC_MODE_I2S			(0x0 << 12)
+#define RT5677_IF2_ADC_MODE_TDM			(0x1 << 12)
+#define RT5677_IF2_ADC1_SWAP_MASK		(0x3 << 6)
+#define RT5677_IF2_ADC1_SWAP_SFT		6
+#define RT5677_IF2_ADC2_SWAP_MASK		(0x3 << 4)
+#define RT5677_IF2_ADC2_SWAP_SFT		4
+#define RT5677_IF2_ADC3_SWAP_MASK		(0x3 << 2)
+#define RT5677_IF2_ADC3_SWAP_SFT		2
+#define RT5677_IF2_ADC4_SWAP_MASK		(0x3 << 0)
+#define RT5677_IF2_ADC4_SWAP_SFT		0
+
+/* TDM2 control 2 (0x41) */
+#define RT5677_IF2_ADC4_MASK			(0x3 << 10)
+#define RT5677_IF2_ADC4_SFT			10
+#define RT5677_IF2_ADC3_MASK			(0x3 << 8)
+#define RT5677_IF2_ADC3_SFT			8
+#define RT5677_IF2_ADC2_MASK			(0x3 << 6)
+#define RT5677_IF2_ADC2_SFT			6
+#define RT5677_IF2_ADC1_MASK			(0x3 << 4)
+#define RT5677_IF2_ADC1_SFT			4
+#define RT5677_IF2_ADC_CTRL_MASK		(0x7 << 0)
+#define RT5677_IF2_ADC_CTRL_SFT			0
+
+/* TDM2 control 4 (0x43) */
+#define RT5677_IF2_DAC0_MASK			(0x7 << 12)
+#define RT5677_IF2_DAC0_SFT			12
+#define RT5677_IF2_DAC1_MASK			(0x7 << 8)
+#define RT5677_IF2_DAC1_SFT			8
+#define RT5677_IF2_DAC2_MASK			(0x7 << 4)
+#define RT5677_IF2_DAC2_SFT			4
+#define RT5677_IF2_DAC3_MASK			(0x7 << 0)
+#define RT5677_IF2_DAC3_SFT			0
+
+/* TDM2 control 5 (0x44) */
+#define RT5677_IF2_DAC4_MASK			(0x7 << 12)
+#define RT5677_IF2_DAC4_SFT			12
+#define RT5677_IF2_DAC5_MASK			(0x7 << 8)
+#define RT5677_IF2_DAC5_SFT			8
+#define RT5677_IF2_DAC6_MASK			(0x7 << 4)
+#define RT5677_IF2_DAC6_SFT			4
+#define RT5677_IF2_DAC7_MASK			(0x7 << 0)
+#define RT5677_IF2_DAC7_SFT			0
+
+/* Digital Microphone Control 1 (0x50) */
+#define RT5677_DMIC_1_EN_MASK			(0x1 << 15)
+#define RT5677_DMIC_1_EN_SFT			15
+#define RT5677_DMIC_1_DIS			(0x0 << 15)
+#define RT5677_DMIC_1_EN			(0x1 << 15)
+#define RT5677_DMIC_2_EN_MASK			(0x1 << 14)
+#define RT5677_DMIC_2_EN_SFT			14
+#define RT5677_DMIC_2_DIS			(0x0 << 14)
+#define RT5677_DMIC_2_EN			(0x1 << 14)
+#define RT5677_DMIC_L_STO1_LH_MASK		(0x1 << 13)
+#define RT5677_DMIC_L_STO1_LH_SFT		13
+#define RT5677_DMIC_L_STO1_LH_FALLING		(0x0 << 13)
+#define RT5677_DMIC_L_STO1_LH_RISING		(0x1 << 13)
+#define RT5677_DMIC_R_STO1_LH_MASK		(0x1 << 12)
+#define RT5677_DMIC_R_STO1_LH_SFT		12
+#define RT5677_DMIC_R_STO1_LH_FALLING		(0x0 << 12)
+#define RT5677_DMIC_R_STO1_LH_RISING		(0x1 << 12)
+#define RT5677_DMIC_L_STO3_LH_MASK		(0x1 << 11)
+#define RT5677_DMIC_L_STO3_LH_SFT		11
+#define RT5677_DMIC_L_STO3_LH_FALLING		(0x0 << 11)
+#define RT5677_DMIC_L_STO3_LH_RISING		(0x1 << 11)
+#define RT5677_DMIC_R_STO3_LH_MASK		(0x1 << 10)
+#define RT5677_DMIC_R_STO3_LH_SFT		10
+#define RT5677_DMIC_R_STO3_LH_FALLING		(0x0 << 10)
+#define RT5677_DMIC_R_STO3_LH_RISING		(0x1 << 10)
+#define RT5677_DMIC_L_STO2_LH_MASK		(0x1 << 9)
+#define RT5677_DMIC_L_STO2_LH_SFT		9
+#define RT5677_DMIC_L_STO2_LH_FALLING		(0x0 << 9)
+#define RT5677_DMIC_L_STO2_LH_RISING		(0x1 << 9)
+#define RT5677_DMIC_R_STO2_LH_MASK		(0x1 << 8)
+#define RT5677_DMIC_R_STO2_LH_SFT		8
+#define RT5677_DMIC_R_STO2_LH_FALLING		(0x0 << 8)
+#define RT5677_DMIC_R_STO2_LH_RISING		(0x1 << 8)
+#define RT5677_DMIC_CLK_MASK			(0x7 << 5)
+#define RT5677_DMIC_CLK_SFT			5
+#define RT5677_DMIC_3_EN_MASK			(0x1 << 4)
+#define RT5677_DMIC_3_EN_SFT			4
+#define RT5677_DMIC_3_DIS			(0x0 << 4)
+#define RT5677_DMIC_3_EN			(0x1 << 4)
+#define RT5677_DMIC_R_MONO_LH_MASK		(0x1 << 2)
+#define RT5677_DMIC_R_MONO_LH_SFT		2
+#define RT5677_DMIC_R_MONO_LH_FALLING		(0x0 << 2)
+#define RT5677_DMIC_R_MONO_LH_RISING		(0x1 << 2)
+#define RT5677_DMIC_L_STO4_LH_MASK		(0x1 << 1)
+#define RT5677_DMIC_L_STO4_LH_SFT		1
+#define RT5677_DMIC_L_STO4_LH_FALLING		(0x0 << 1)
+#define RT5677_DMIC_L_STO4_LH_RISING		(0x1 << 1)
+#define RT5677_DMIC_R_STO4_LH_MASK		(0x1 << 0)
+#define RT5677_DMIC_R_STO4_LH_SFT		0
+#define RT5677_DMIC_R_STO4_LH_FALLING		(0x0 << 0)
+#define RT5677_DMIC_R_STO4_LH_RISING		(0x1 << 0)
+
+/* Digital Microphone Control 2 (0x51) */
+#define RT5677_DMIC_4_EN_MASK			(0x1 << 15)
+#define RT5677_DMIC_4_EN_SFT			15
+#define RT5677_DMIC_4_DIS			(0x0 << 15)
+#define RT5677_DMIC_4_EN			(0x1 << 15)
+#define RT5677_DMIC_4L_LH_MASK			(0x1 << 7)
+#define RT5677_DMIC_4L_LH_SFT			7
+#define RT5677_DMIC_4L_LH_FALLING		(0x0 << 7)
+#define RT5677_DMIC_4L_LH_RISING		(0x1 << 7)
+#define RT5677_DMIC_4R_LH_MASK			(0x1 << 6)
+#define RT5677_DMIC_4R_LH_SFT			6
+#define RT5677_DMIC_4R_LH_FALLING		(0x0 << 6)
+#define RT5677_DMIC_4R_LH_RISING		(0x1 << 6)
+#define RT5677_DMIC_3L_LH_MASK			(0x1 << 5)
+#define RT5677_DMIC_3L_LH_SFT			5
+#define RT5677_DMIC_3L_LH_FALLING		(0x0 << 5)
+#define RT5677_DMIC_3L_LH_RISING		(0x1 << 5)
+#define RT5677_DMIC_3R_LH_MASK			(0x1 << 4)
+#define RT5677_DMIC_3R_LH_SFT			4
+#define RT5677_DMIC_3R_LH_FALLING		(0x0 << 4)
+#define RT5677_DMIC_3R_LH_RISING		(0x1 << 4)
+#define RT5677_DMIC_2L_LH_MASK			(0x1 << 3)
+#define RT5677_DMIC_2L_LH_SFT			3
+#define RT5677_DMIC_2L_LH_FALLING		(0x0 << 3)
+#define RT5677_DMIC_2L_LH_RISING		(0x1 << 3)
+#define RT5677_DMIC_2R_LH_MASK			(0x1 << 2)
+#define RT5677_DMIC_2R_LH_SFT			2
+#define RT5677_DMIC_2R_LH_FALLING		(0x0 << 2)
+#define RT5677_DMIC_2R_LH_RISING		(0x1 << 2)
+#define RT5677_DMIC_1L_LH_MASK			(0x1 << 1)
+#define RT5677_DMIC_1L_LH_SFT			1
+#define RT5677_DMIC_1L_LH_FALLING		(0x0 << 1)
+#define RT5677_DMIC_1L_LH_RISING		(0x1 << 1)
+#define RT5677_DMIC_1R_LH_MASK			(0x1 << 0)
+#define RT5677_DMIC_1R_LH_SFT			0
+#define RT5677_DMIC_1R_LH_FALLING		(0x0 << 0)
+#define RT5677_DMIC_1R_LH_RISING		(0x1 << 0)
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5677_PWR_I2S1				(0x1 << 15)
+#define RT5677_PWR_I2S1_BIT			15
+#define RT5677_PWR_I2S2				(0x1 << 14)
+#define RT5677_PWR_I2S2_BIT			14
+#define RT5677_PWR_I2S3				(0x1 << 13)
+#define RT5677_PWR_I2S3_BIT			13
+#define RT5677_PWR_DAC1				(0x1 << 12)
+#define RT5677_PWR_DAC1_BIT			12
+#define RT5677_PWR_DAC2				(0x1 << 11)
+#define RT5677_PWR_DAC2_BIT			11
+#define RT5677_PWR_I2S4				(0x1 << 10)
+#define RT5677_PWR_I2S4_BIT			10
+#define RT5677_PWR_SLB				(0x1 << 9)
+#define RT5677_PWR_SLB_BIT			9
+#define RT5677_PWR_DAC3				(0x1 << 7)
+#define RT5677_PWR_DAC3_BIT			7
+#define RT5677_PWR_ADCFED2			(0x1 << 4)
+#define RT5677_PWR_ADCFED2_BIT			4
+#define RT5677_PWR_ADCFED1			(0x1 << 3)
+#define RT5677_PWR_ADCFED1_BIT			3
+#define RT5677_PWR_ADC_L			(0x1 << 2)
+#define RT5677_PWR_ADC_L_BIT			2
+#define RT5677_PWR_ADC_R			(0x1 << 1)
+#define RT5677_PWR_ADC_R_BIT			1
+#define RT5677_PWR_I2C_MASTER			(0x1 << 0)
+#define RT5677_PWR_I2C_MASTER_BIT		0
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5677_PWR_ADC_S1F			(0x1 << 15)
+#define RT5677_PWR_ADC_S1F_BIT			15
+#define RT5677_PWR_ADC_MF_L			(0x1 << 14)
+#define RT5677_PWR_ADC_MF_L_BIT			14
+#define RT5677_PWR_ADC_MF_R			(0x1 << 13)
+#define RT5677_PWR_ADC_MF_R_BIT			13
+#define RT5677_PWR_DAC_S1F			(0x1 << 12)
+#define RT5677_PWR_DAC_S1F_BIT			12
+#define RT5677_PWR_DAC_M2F_L			(0x1 << 11)
+#define RT5677_PWR_DAC_M2F_L_BIT		11
+#define RT5677_PWR_DAC_M2F_R			(0x1 << 10)
+#define RT5677_PWR_DAC_M2F_R_BIT		10
+#define RT5677_PWR_DAC_M3F_L			(0x1 << 9)
+#define RT5677_PWR_DAC_M3F_L_BIT		9
+#define RT5677_PWR_DAC_M3F_R			(0x1 << 8)
+#define RT5677_PWR_DAC_M3F_R_BIT		8
+#define RT5677_PWR_DAC_M4F_L			(0x1 << 7)
+#define RT5677_PWR_DAC_M4F_L_BIT		7
+#define RT5677_PWR_DAC_M4F_R			(0x1 << 6)
+#define RT5677_PWR_DAC_M4F_R_BIT		6
+#define RT5677_PWR_ADC_S2F			(0x1 << 5)
+#define RT5677_PWR_ADC_S2F_BIT			5
+#define RT5677_PWR_ADC_S3F			(0x1 << 4)
+#define RT5677_PWR_ADC_S3F_BIT			4
+#define RT5677_PWR_ADC_S4F			(0x1 << 3)
+#define RT5677_PWR_ADC_S4F_BIT			3
+#define RT5677_PWR_PDM1				(0x1 << 2)
+#define RT5677_PWR_PDM1_BIT			2
+#define RT5677_PWR_PDM2				(0x1 << 1)
+#define RT5677_PWR_PDM2_BIT			1
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5677_PWR_VREF1			(0x1 << 15)
+#define RT5677_PWR_VREF1_BIT			15
+#define RT5677_PWR_FV1				(0x1 << 14)
+#define RT5677_PWR_FV1_BIT			14
+#define RT5677_PWR_MB				(0x1 << 13)
+#define RT5677_PWR_MB_BIT			13
+#define RT5677_PWR_LO1				(0x1 << 12)
+#define RT5677_PWR_LO1_BIT			12
+#define RT5677_PWR_BG				(0x1 << 11)
+#define RT5677_PWR_BG_BIT			11
+#define RT5677_PWR_LO2				(0x1 << 10)
+#define RT5677_PWR_LO2_BIT			10
+#define RT5677_PWR_LO3				(0x1 << 9)
+#define RT5677_PWR_LO3_BIT			9
+#define RT5677_PWR_VREF2			(0x1 << 8)
+#define RT5677_PWR_VREF2_BIT			8
+#define RT5677_PWR_FV2				(0x1 << 7)
+#define RT5677_PWR_FV2_BIT			7
+#define RT5677_LDO2_SEL_MASK			(0x7 << 4)
+#define RT5677_LDO2_SEL_SFT			4
+#define RT5677_LDO1_SEL_MASK			(0x7 << 0)
+#define RT5677_LDO1_SEL_SFT			0
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5677_PWR_BST1				(0x1 << 15)
+#define RT5677_PWR_BST1_BIT			15
+#define RT5677_PWR_BST2				(0x1 << 14)
+#define RT5677_PWR_BST2_BIT			14
+#define RT5677_PWR_CLK_MB1			(0x1 << 13)
+#define RT5677_PWR_CLK_MB1_BIT			13
+#define RT5677_PWR_SLIM				(0x1 << 12)
+#define RT5677_PWR_SLIM_BIT			12
+#define RT5677_PWR_MB1				(0x1 << 11)
+#define RT5677_PWR_MB1_BIT			11
+#define RT5677_PWR_PP_MB1			(0x1 << 10)
+#define RT5677_PWR_PP_MB1_BIT			10
+#define RT5677_PWR_PLL1				(0x1 << 9)
+#define RT5677_PWR_PLL1_BIT			9
+#define RT5677_PWR_PLL2				(0x1 << 8)
+#define RT5677_PWR_PLL2_BIT			8
+#define RT5677_PWR_CORE				(0x1 << 7)
+#define RT5677_PWR_CORE_BIT			7
+#define RT5677_PWR_CLK_MB			(0x1 << 6)
+#define RT5677_PWR_CLK_MB_BIT			6
+#define RT5677_PWR_BST1_P			(0x1 << 5)
+#define RT5677_PWR_BST1_P_BIT			5
+#define RT5677_PWR_BST2_P			(0x1 << 4)
+#define RT5677_PWR_BST2_P_BIT			4
+#define RT5677_PWR_IPTV				(0x1 << 3)
+#define RT5677_PWR_IPTV_BIT			3
+#define RT5677_PWR_25M_CLK			(0x1 << 1)
+#define RT5677_PWR_25M_CLK_BIT			1
+#define RT5677_PWR_LDO1				(0x1 << 0)
+#define RT5677_PWR_LDO1_BIT			0
+
+/* Power Management for DSP (0x65) */
+#define RT5677_PWR_SR7				(0x1 << 10)
+#define RT5677_PWR_SR7_BIT			10
+#define RT5677_PWR_SR6				(0x1 << 9)
+#define RT5677_PWR_SR6_BIT			9
+#define RT5677_PWR_SR5				(0x1 << 8)
+#define RT5677_PWR_SR5_BIT			8
+#define RT5677_PWR_SR4				(0x1 << 7)
+#define RT5677_PWR_SR4_BIT			7
+#define RT5677_PWR_SR3				(0x1 << 6)
+#define RT5677_PWR_SR3_BIT			6
+#define RT5677_PWR_SR2				(0x1 << 5)
+#define RT5677_PWR_SR2_BIT			5
+#define RT5677_PWR_SR1				(0x1 << 4)
+#define RT5677_PWR_SR1_BIT			4
+#define RT5677_PWR_SR0				(0x1 << 3)
+#define RT5677_PWR_SR0_BIT			3
+#define RT5677_PWR_MLT				(0x1 << 2)
+#define RT5677_PWR_MLT_BIT			2
+#define RT5677_PWR_DSP				(0x1 << 1)
+#define RT5677_PWR_DSP_BIT			1
+#define RT5677_PWR_DSP_CPU			(0x1 << 0)
+#define RT5677_PWR_DSP_CPU_BIT			0
+
+/* Power Status for DSP (0x66) */
+#define RT5677_PWR_SR7_RDY			(0x1 << 9)
+#define RT5677_PWR_SR7_RDY_BIT			9
+#define RT5677_PWR_SR6_RDY			(0x1 << 8)
+#define RT5677_PWR_SR6_RDY_BIT			8
+#define RT5677_PWR_SR5_RDY			(0x1 << 7)
+#define RT5677_PWR_SR5_RDY_BIT			7
+#define RT5677_PWR_SR4_RDY			(0x1 << 6)
+#define RT5677_PWR_SR4_RDY_BIT			6
+#define RT5677_PWR_SR3_RDY			(0x1 << 5)
+#define RT5677_PWR_SR3_RDY_BIT			5
+#define RT5677_PWR_SR2_RDY			(0x1 << 4)
+#define RT5677_PWR_SR2_RDY_BIT			4
+#define RT5677_PWR_SR1_RDY			(0x1 << 3)
+#define RT5677_PWR_SR1_RDY_BIT			3
+#define RT5677_PWR_SR0_RDY			(0x1 << 2)
+#define RT5677_PWR_SR0_RDY_BIT			2
+#define RT5677_PWR_MLT_RDY			(0x1 << 1)
+#define RT5677_PWR_MLT_RDY_BIT			1
+#define RT5677_PWR_DSP_RDY			(0x1 << 0)
+#define RT5677_PWR_DSP_RDY_BIT			0
+
+/* Power Management for DSP (0x67) */
+#define RT5677_PWR_SLIM_ISO			(0x1 << 11)
+#define RT5677_PWR_SLIM_ISO_BIT			11
+#define RT5677_PWR_CORE_ISO			(0x1 << 10)
+#define RT5677_PWR_CORE_ISO_BIT			10
+#define RT5677_PWR_DSP_ISO			(0x1 << 9)
+#define RT5677_PWR_DSP_ISO_BIT			9
+#define RT5677_PWR_SR7_ISO			(0x1 << 8)
+#define RT5677_PWR_SR7_ISO_BIT			8
+#define RT5677_PWR_SR6_ISO			(0x1 << 7)
+#define RT5677_PWR_SR6_ISO_BIT			7
+#define RT5677_PWR_SR5_ISO			(0x1 << 6)
+#define RT5677_PWR_SR5_ISO_BIT			6
+#define RT5677_PWR_SR4_ISO			(0x1 << 5)
+#define RT5677_PWR_SR4_ISO_BIT			5
+#define RT5677_PWR_SR3_ISO			(0x1 << 4)
+#define RT5677_PWR_SR3_ISO_BIT			4
+#define RT5677_PWR_SR2_ISO			(0x1 << 3)
+#define RT5677_PWR_SR2_ISO_BIT			3
+#define RT5677_PWR_SR1_ISO			(0x1 << 2)
+#define RT5677_PWR_SR1_ISO_BIT			2
+#define RT5677_PWR_SR0_ISO			(0x1 << 1)
+#define RT5677_PWR_SR0_ISO_BIT			1
+#define RT5677_PWR_MLT_ISO			(0x1 << 0)
+#define RT5677_PWR_MLT_ISO_BIT			0
+
+/* I2S1/2/3/4 Audio Serial Data Port Control (0x6f 0x70 0x71 0x72) */
+#define RT5677_I2S_MS_MASK			(0x1 << 15)
+#define RT5677_I2S_MS_SFT			15
+#define RT5677_I2S_MS_M				(0x0 << 15)
+#define RT5677_I2S_MS_S				(0x1 << 15)
+#define RT5677_I2S_O_CP_MASK			(0x3 << 10)
+#define RT5677_I2S_O_CP_SFT			10
+#define RT5677_I2S_O_CP_OFF			(0x0 << 10)
+#define RT5677_I2S_O_CP_U_LAW			(0x1 << 10)
+#define RT5677_I2S_O_CP_A_LAW			(0x2 << 10)
+#define RT5677_I2S_I_CP_MASK			(0x3 << 8)
+#define RT5677_I2S_I_CP_SFT			8
+#define RT5677_I2S_I_CP_OFF			(0x0 << 8)
+#define RT5677_I2S_I_CP_U_LAW			(0x1 << 8)
+#define RT5677_I2S_I_CP_A_LAW			(0x2 << 8)
+#define RT5677_I2S_BP_MASK			(0x1 << 7)
+#define RT5677_I2S_BP_SFT			7
+#define RT5677_I2S_BP_NOR			(0x0 << 7)
+#define RT5677_I2S_BP_INV			(0x1 << 7)
+#define RT5677_I2S_DL_MASK			(0x3 << 2)
+#define RT5677_I2S_DL_SFT			2
+#define RT5677_I2S_DL_16			(0x0 << 2)
+#define RT5677_I2S_DL_20			(0x1 << 2)
+#define RT5677_I2S_DL_24			(0x2 << 2)
+#define RT5677_I2S_DL_8				(0x3 << 2)
+#define RT5677_I2S_DF_MASK			(0x3 << 0)
+#define RT5677_I2S_DF_SFT			0
+#define RT5677_I2S_DF_I2S			(0x0 << 0)
+#define RT5677_I2S_DF_LEFT			(0x1 << 0)
+#define RT5677_I2S_DF_PCM_A			(0x2 << 0)
+#define RT5677_I2S_DF_PCM_B			(0x3 << 0)
+
+/* Clock Tree Control 1 (0x73) */
+#define RT5677_I2S_PD1_MASK			(0x7 << 12)
+#define RT5677_I2S_PD1_SFT			12
+#define RT5677_I2S_PD1_1			(0x0 << 12)
+#define RT5677_I2S_PD1_2			(0x1 << 12)
+#define RT5677_I2S_PD1_3			(0x2 << 12)
+#define RT5677_I2S_PD1_4			(0x3 << 12)
+#define RT5677_I2S_PD1_6			(0x4 << 12)
+#define RT5677_I2S_PD1_8			(0x5 << 12)
+#define RT5677_I2S_PD1_12			(0x6 << 12)
+#define RT5677_I2S_PD1_16			(0x7 << 12)
+#define RT5677_I2S_BCLK_MS2_MASK		(0x1 << 11)
+#define RT5677_I2S_BCLK_MS2_SFT			11
+#define RT5677_I2S_BCLK_MS2_32			(0x0 << 11)
+#define RT5677_I2S_BCLK_MS2_64			(0x1 << 11)
+#define RT5677_I2S_PD2_MASK			(0x7 << 8)
+#define RT5677_I2S_PD2_SFT			8
+#define RT5677_I2S_PD2_1			(0x0 << 8)
+#define RT5677_I2S_PD2_2			(0x1 << 8)
+#define RT5677_I2S_PD2_3			(0x2 << 8)
+#define RT5677_I2S_PD2_4			(0x3 << 8)
+#define RT5677_I2S_PD2_6			(0x4 << 8)
+#define RT5677_I2S_PD2_8			(0x5 << 8)
+#define RT5677_I2S_PD2_12			(0x6 << 8)
+#define RT5677_I2S_PD2_16			(0x7 << 8)
+#define RT5677_I2S_BCLK_MS3_MASK		(0x1 << 7)
+#define RT5677_I2S_BCLK_MS3_SFT			7
+#define RT5677_I2S_BCLK_MS3_32			(0x0 << 7)
+#define RT5677_I2S_BCLK_MS3_64			(0x1 << 7)
+#define RT5677_I2S_PD3_MASK			(0x7 << 4)
+#define RT5677_I2S_PD3_SFT			4
+#define RT5677_I2S_PD3_1			(0x0 << 4)
+#define RT5677_I2S_PD3_2			(0x1 << 4)
+#define RT5677_I2S_PD3_3			(0x2 << 4)
+#define RT5677_I2S_PD3_4			(0x3 << 4)
+#define RT5677_I2S_PD3_6			(0x4 << 4)
+#define RT5677_I2S_PD3_8			(0x5 << 4)
+#define RT5677_I2S_PD3_12			(0x6 << 4)
+#define RT5677_I2S_PD3_16			(0x7 << 4)
+#define RT5677_I2S_BCLK_MS4_MASK		(0x1 << 3)
+#define RT5677_I2S_BCLK_MS4_SFT			3
+#define RT5677_I2S_BCLK_MS4_32			(0x0 << 3)
+#define RT5677_I2S_BCLK_MS4_64			(0x1 << 3)
+#define RT5677_I2S_PD4_MASK			(0x7 << 0)
+#define RT5677_I2S_PD4_SFT			0
+#define RT5677_I2S_PD4_1			(0x0 << 0)
+#define RT5677_I2S_PD4_2			(0x1 << 0)
+#define RT5677_I2S_PD4_3			(0x2 << 0)
+#define RT5677_I2S_PD4_4			(0x3 << 0)
+#define RT5677_I2S_PD4_6			(0x4 << 0)
+#define RT5677_I2S_PD4_8			(0x5 << 0)
+#define RT5677_I2S_PD4_12			(0x6 << 0)
+#define RT5677_I2S_PD4_16			(0x7 << 0)
+
+/* Clock Tree Control 2 (0x74) */
+#define RT5677_I2S_PD5_MASK			(0x7 << 12)
+#define RT5677_I2S_PD5_SFT			12
+#define RT5677_I2S_PD5_1			(0x0 << 12)
+#define RT5677_I2S_PD5_2			(0x1 << 12)
+#define RT5677_I2S_PD5_3			(0x2 << 12)
+#define RT5677_I2S_PD5_4			(0x3 << 12)
+#define RT5677_I2S_PD5_6			(0x4 << 12)
+#define RT5677_I2S_PD5_8			(0x5 << 12)
+#define RT5677_I2S_PD5_12			(0x6 << 12)
+#define RT5677_I2S_PD5_16			(0x7 << 12)
+#define RT5677_I2S_PD6_MASK			(0x7 << 8)
+#define RT5677_I2S_PD6_SFT			8
+#define RT5677_I2S_PD6_1			(0x0 << 8)
+#define RT5677_I2S_PD6_2			(0x1 << 8)
+#define RT5677_I2S_PD6_3			(0x2 << 8)
+#define RT5677_I2S_PD6_4			(0x3 << 8)
+#define RT5677_I2S_PD6_6			(0x4 << 8)
+#define RT5677_I2S_PD6_8			(0x5 << 8)
+#define RT5677_I2S_PD6_12			(0x6 << 8)
+#define RT5677_I2S_PD6_16			(0x7 << 8)
+#define RT5677_I2S_PD7_MASK			(0x7 << 4)
+#define RT5677_I2S_PD7_SFT			4
+#define RT5677_I2S_PD7_1			(0x0 << 4)
+#define RT5677_I2S_PD7_2			(0x1 << 4)
+#define RT5677_I2S_PD7_3			(0x2 << 4)
+#define RT5677_I2S_PD7_4			(0x3 << 4)
+#define RT5677_I2S_PD7_6			(0x4 << 4)
+#define RT5677_I2S_PD7_8			(0x5 << 4)
+#define RT5677_I2S_PD7_12			(0x6 << 4)
+#define RT5677_I2S_PD7_16			(0x7 << 4)
+#define RT5677_I2S_PD8_MASK			(0x7 << 0)
+#define RT5677_I2S_PD8_SFT			0
+#define RT5677_I2S_PD8_1			(0x0 << 0)
+#define RT5677_I2S_PD8_2			(0x1 << 0)
+#define RT5677_I2S_PD8_3			(0x2 << 0)
+#define RT5677_I2S_PD8_4			(0x3 << 0)
+#define RT5677_I2S_PD8_6			(0x4 << 0)
+#define RT5677_I2S_PD8_8			(0x5 << 0)
+#define RT5677_I2S_PD8_12			(0x6 << 0)
+#define RT5677_I2S_PD8_16			(0x7 << 0)
+
+/* Clock Tree Control 3 (0x75) */
+#define RT5677_DSP_ASRC_O_MASK			(0x3 << 6)
+#define RT5677_DSP_ASRC_O_SFT			6
+#define RT5677_DSP_ASRC_O_1_0			(0x0 << 6)
+#define RT5677_DSP_ASRC_O_1_5			(0x1 << 6)
+#define RT5677_DSP_ASRC_O_2_0			(0x2 << 6)
+#define RT5677_DSP_ASRC_O_3_0			(0x3 << 6)
+#define RT5677_DSP_ASRC_I_MASK			(0x3 << 4)
+#define RT5677_DSP_ASRC_I_SFT			4
+#define RT5677_DSP_ASRC_I_1_0			(0x0 << 4)
+#define RT5677_DSP_ASRC_I_1_5			(0x1 << 4)
+#define RT5677_DSP_ASRC_I_2_0			(0x2 << 4)
+#define RT5677_DSP_ASRC_I_3_0			(0x3 << 4)
+#define RT5677_DSP_BUS_PD_MASK			(0x7 << 0)
+#define RT5677_DSP_BUS_PD_SFT			0
+#define RT5677_DSP_BUS_PD_1			(0x0 << 0)
+#define RT5677_DSP_BUS_PD_2			(0x1 << 0)
+#define RT5677_DSP_BUS_PD_3			(0x2 << 0)
+#define RT5677_DSP_BUS_PD_4			(0x3 << 0)
+#define RT5677_DSP_BUS_PD_6			(0x4 << 0)
+#define RT5677_DSP_BUS_PD_8			(0x5 << 0)
+#define RT5677_DSP_BUS_PD_12			(0x6 << 0)
+#define RT5677_DSP_BUS_PD_16			(0x7 << 0)
+
+#define RT5677_PLL_INP_MAX			40000000
+#define RT5677_PLL_INP_MIN			2048000
+/* PLL M/N/K Code Control 1 (0x7a 0x7c) */
+#define RT5677_PLL_N_MAX			0x1ff
+#define RT5677_PLL_N_MASK			(RT5677_PLL_N_MAX << 7)
+#define RT5677_PLL_N_SFT			7
+#define RT5677_PLL_K_BP				(0x1 << 5)
+#define RT5677_PLL_K_BP_SFT			5
+#define RT5677_PLL_K_MAX			0x1f
+#define RT5677_PLL_K_MASK			(RT5677_PLL_K_MAX)
+#define RT5677_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x7b 0x7d) */
+#define RT5677_PLL_M_MAX			0xf
+#define RT5677_PLL_M_MASK			(RT5677_PLL_M_MAX << 12)
+#define RT5677_PLL_M_SFT			12
+#define RT5677_PLL_M_BP				(0x1 << 11)
+#define RT5677_PLL_M_BP_SFT			11
+
+/* Global Clock Control 1 (0x80) */
+#define RT5677_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5677_SCLK_SRC_SFT			14
+#define RT5677_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5677_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5677_SCLK_SRC_RCCLK			(0x2 << 14) /* 25MHz */
+#define RT5677_SCLK_SRC_SLIM			(0x3 << 14)
+#define RT5677_PLL1_SRC_MASK			(0x7 << 11)
+#define RT5677_PLL1_SRC_SFT			11
+#define RT5677_PLL1_SRC_MCLK			(0x0 << 11)
+#define RT5677_PLL1_SRC_BCLK1			(0x1 << 11)
+#define RT5677_PLL1_SRC_BCLK2			(0x2 << 11)
+#define RT5677_PLL1_SRC_BCLK3			(0x3 << 11)
+#define RT5677_PLL1_SRC_BCLK4			(0x4 << 11)
+#define RT5677_PLL1_SRC_RCCLK			(0x5 << 11)
+#define RT5677_PLL1_SRC_SLIM			(0x6 << 11)
+#define RT5677_MCLK_SRC_MASK			(0x1 << 10)
+#define RT5677_MCLK_SRC_SFT			10
+#define RT5677_MCLK1_SRC			(0x0 << 10)
+#define RT5677_MCLK2_SRC			(0x1 << 10)
+#define RT5677_PLL1_PD_MASK			(0x1 << 8)
+#define RT5677_PLL1_PD_SFT			8
+#define RT5677_PLL1_PD_1			(0x0 << 8)
+#define RT5677_PLL1_PD_2			(0x1 << 8)
+#define RT5677_DAC_OSR_MASK			(0x3 << 6)
+#define RT5677_DAC_OSR_SFT			6
+#define RT5677_DAC_OSR_128			(0x0 << 6)
+#define RT5677_DAC_OSR_64			(0x1 << 6)
+#define RT5677_DAC_OSR_32			(0x2 << 6)
+#define RT5677_ADC_OSR_MASK			(0x3 << 4)
+#define RT5677_ADC_OSR_SFT			4
+#define RT5677_ADC_OSR_128			(0x0 << 4)
+#define RT5677_ADC_OSR_64			(0x1 << 4)
+#define RT5677_ADC_OSR_32			(0x2 << 4)
+
+/* Global Clock Control 2 (0x81) */
+#define RT5677_PLL2_PR_SRC_MASK			(0x1 << 15)
+#define RT5677_PLL2_PR_SRC_SFT			15
+#define RT5677_PLL2_PR_SRC_MCLK1		(0x0 << 15)
+#define RT5677_PLL2_PR_SRC_MCLK2		(0x1 << 15)
+#define RT5677_PLL2_SRC_MASK			(0x7 << 12)
+#define RT5677_PLL2_SRC_SFT			12
+#define RT5677_PLL2_SRC_MCLK			(0x0 << 12)
+#define RT5677_PLL2_SRC_BCLK1			(0x1 << 12)
+#define RT5677_PLL2_SRC_BCLK2			(0x2 << 12)
+#define RT5677_PLL2_SRC_BCLK3			(0x3 << 12)
+#define RT5677_PLL2_SRC_BCLK4			(0x4 << 12)
+#define RT5677_PLL2_SRC_RCCLK			(0x5 << 12)
+#define RT5677_PLL2_SRC_SLIM			(0x6 << 12)
+#define RT5677_DSP_ASRC_O_SRC			(0x3 << 10)
+#define RT5677_DSP_ASRC_O_SRC_SFT		10
+#define RT5677_DSP_ASRC_O_MCLK			(0x0 << 10)
+#define RT5677_DSP_ASRC_O_PLL1			(0x1 << 10)
+#define RT5677_DSP_ASRC_O_SLIM			(0x2 << 10)
+#define RT5677_DSP_ASRC_O_RCCLK			(0x3 << 10)
+#define RT5677_DSP_ASRC_I_SRC			(0x3 << 8)
+#define RT5677_DSP_ASRC_I_SRC_SFT		8
+#define RT5677_DSP_ASRC_I_MCLK			(0x0 << 8)
+#define RT5677_DSP_ASRC_I_PLL1			(0x1 << 8)
+#define RT5677_DSP_ASRC_I_SLIM			(0x2 << 8)
+#define RT5677_DSP_ASRC_I_RCCLK			(0x3 << 8)
+#define RT5677_DSP_CLK_SRC_MASK			(0x1 << 7)
+#define RT5677_DSP_CLK_SRC_SFT			7
+#define RT5677_DSP_CLK_SRC_PLL2			(0x0 << 7)
+#define RT5677_DSP_CLK_SRC_BYPASS		(0x1 << 7)
+
+/* ASRC Control 3 (0x85) */
+#define RT5677_DA_STO_CLK_SEL_MASK		(0xf << 12)
+#define RT5677_DA_STO_CLK_SEL_SFT		12
+#define RT5677_DA_MONO2L_CLK_SEL_MASK		(0xf << 4)
+#define RT5677_DA_MONO2L_CLK_SEL_SFT		4
+#define RT5677_DA_MONO2R_CLK_SEL_MASK		(0xf << 0)
+#define RT5677_DA_MONO2R_CLK_SEL_SFT		0
+
+/* ASRC Control 4 (0x86) */
+#define RT5677_DA_MONO3L_CLK_SEL_MASK		(0xf << 12)
+#define RT5677_DA_MONO3L_CLK_SEL_SFT		12
+#define RT5677_DA_MONO3R_CLK_SEL_MASK		(0xf << 8)
+#define RT5677_DA_MONO3R_CLK_SEL_SFT		8
+#define RT5677_DA_MONO4L_CLK_SEL_MASK		(0xf << 4)
+#define RT5677_DA_MONO4L_CLK_SEL_SFT		4
+#define RT5677_DA_MONO4R_CLK_SEL_MASK		(0xf << 0)
+#define RT5677_DA_MONO4R_CLK_SEL_SFT		0
+
+/* ASRC Control 5 (0x87) */
+#define RT5677_AD_STO1_CLK_SEL_MASK		(0xf << 12)
+#define RT5677_AD_STO1_CLK_SEL_SFT		12
+#define RT5677_AD_STO2_CLK_SEL_MASK		(0xf << 8)
+#define RT5677_AD_STO2_CLK_SEL_SFT		8
+#define RT5677_AD_STO3_CLK_SEL_MASK		(0xf << 4)
+#define RT5677_AD_STO3_CLK_SEL_SFT		4
+#define RT5677_AD_STO4_CLK_SEL_MASK		(0xf << 0)
+#define RT5677_AD_STO4_CLK_SEL_SFT		0
+
+/* ASRC Control 6 (0x88) */
+#define RT5677_AD_MONOL_CLK_SEL_MASK		(0xf << 12)
+#define RT5677_AD_MONOL_CLK_SEL_SFT		12
+#define RT5677_AD_MONOR_CLK_SEL_MASK		(0xf << 8)
+#define RT5677_AD_MONOR_CLK_SEL_SFT		8
+
+/* ASRC Control 7 (0x89) */
+#define RT5677_DSP_OB_0_3_CLK_SEL_MASK		(0xf << 12)
+#define RT5677_DSP_OB_0_3_CLK_SEL_SFT		12
+#define RT5677_DSP_OB_4_7_CLK_SEL_MASK		(0xf << 8)
+#define RT5677_DSP_OB_4_7_CLK_SEL_SFT		8
+
+/* ASRC Control 8 (0x8a) */
+#define RT5677_I2S1_CLK_SEL_MASK		(0xf << 12)
+#define RT5677_I2S1_CLK_SEL_SFT			12
+#define RT5677_I2S2_CLK_SEL_MASK		(0xf << 8)
+#define RT5677_I2S2_CLK_SEL_SFT			8
+#define RT5677_I2S3_CLK_SEL_MASK		(0xf << 4)
+#define RT5677_I2S3_CLK_SEL_SFT			4
+#define RT5677_I2S4_CLK_SEL_MASK		(0xf)
+#define RT5677_I2S4_CLK_SEL_SFT			0
+
+/* VAD Function Control 4 (0x9f) */
+#define RT5677_VAD_SRC_MASK			(0x7 << 8)
+#define RT5677_VAD_SRC_SFT			8
+
+/* DSP InBound Control (0xa3) */
+#define RT5677_IB01_SRC_MASK			(0x7 << 12)
+#define RT5677_IB01_SRC_SFT			12
+#define RT5677_IB23_SRC_MASK			(0x7 << 8)
+#define RT5677_IB23_SRC_SFT			8
+#define RT5677_IB45_SRC_MASK			(0x7 << 4)
+#define RT5677_IB45_SRC_SFT			4
+#define RT5677_IB6_SRC_MASK			(0x7 << 0)
+#define RT5677_IB6_SRC_SFT			0
+
+/* DSP InBound Control (0xa4) */
+#define RT5677_IB7_SRC_MASK			(0x7 << 12)
+#define RT5677_IB7_SRC_SFT			12
+#define RT5677_IB8_SRC_MASK			(0x7 << 8)
+#define RT5677_IB8_SRC_SFT			8
+#define RT5677_IB9_SRC_MASK			(0x7 << 4)
+#define RT5677_IB9_SRC_SFT			4
+
+/* DSP In/OutBound Control (0xa5) */
+#define RT5677_SEL_SRC_OB23			(0x1 << 4)
+#define RT5677_SEL_SRC_OB23_SFT			4
+#define RT5677_SEL_SRC_OB01			(0x1 << 3)
+#define RT5677_SEL_SRC_OB01_SFT			3
+#define RT5677_SEL_SRC_IB45			(0x1 << 2)
+#define RT5677_SEL_SRC_IB45_SFT			2
+#define RT5677_SEL_SRC_IB23			(0x1 << 1)
+#define RT5677_SEL_SRC_IB23_SFT			1
+#define RT5677_SEL_SRC_IB01			(0x1 << 0)
+#define RT5677_SEL_SRC_IB01_SFT			0
+
+/* Jack Detect Control 1 (0xb5) */
+#define RT5677_SEL_GPIO_JD1_MASK		(0x3 << 14)
+#define RT5677_SEL_GPIO_JD1_SFT			14
+#define RT5677_SEL_GPIO_JD2_MASK		(0x3 << 12)
+#define RT5677_SEL_GPIO_JD2_SFT			12
+#define RT5677_SEL_GPIO_JD3_MASK		(0x3 << 10)
+#define RT5677_SEL_GPIO_JD3_SFT			10
+
+/* IRQ Control 1 (0xbd) */
+#define RT5677_STA_GPIO_JD1			(0x1 << 15)
+#define RT5677_STA_GPIO_JD1_SFT			15
+#define RT5677_EN_IRQ_GPIO_JD1			(0x1 << 14)
+#define RT5677_EN_IRQ_GPIO_JD1_SFT		14
+#define RT5677_EN_GPIO_JD1_STICKY		(0x1 << 13)
+#define RT5677_EN_GPIO_JD1_STICKY_SFT		13
+#define RT5677_INV_GPIO_JD1			(0x1 << 12)
+#define RT5677_INV_GPIO_JD1_SFT			12
+#define RT5677_STA_GPIO_JD2			(0x1 << 11)
+#define RT5677_STA_GPIO_JD2_SFT			11
+#define RT5677_EN_IRQ_GPIO_JD2			(0x1 << 10)
+#define RT5677_EN_IRQ_GPIO_JD2_SFT		10
+#define RT5677_EN_GPIO_JD2_STICKY		(0x1 << 9)
+#define RT5677_EN_GPIO_JD2_STICKY_SFT		9
+#define RT5677_INV_GPIO_JD2			(0x1 << 8)
+#define RT5677_INV_GPIO_JD2_SFT			8
+#define RT5677_STA_MICBIAS1_OVCD		(0x1 << 7)
+#define RT5677_STA_MICBIAS1_OVCD_SFT		7
+#define RT5677_EN_IRQ_MICBIAS1_OVCD		(0x1 << 6)
+#define RT5677_EN_IRQ_MICBIAS1_OVCD_SFT		6
+#define RT5677_EN_MICBIAS1_OVCD_STICKY		(0x1 << 5)
+#define RT5677_EN_MICBIAS1_OVCD_STICKY_SFT	5
+#define RT5677_INV_MICBIAS1_OVCD		(0x1 << 4)
+#define RT5677_INV_MICBIAS1_OVCD_SFT		4
+#define RT5677_STA_GPIO_JD3			(0x1 << 3)
+#define RT5677_STA_GPIO_JD3_SFT			3
+#define RT5677_EN_IRQ_GPIO_JD3			(0x1 << 2)
+#define RT5677_EN_IRQ_GPIO_JD3_SFT		2
+#define RT5677_EN_GPIO_JD3_STICKY		(0x1 << 1)
+#define RT5677_EN_GPIO_JD3_STICKY_SFT		1
+#define RT5677_INV_GPIO_JD3			(0x1 << 0)
+#define RT5677_INV_GPIO_JD3_SFT			0
+
+/* GPIO status (0xbf) */
+#define RT5677_GPIO6_STATUS_MASK		(0x1 << 5)
+#define RT5677_GPIO6_STATUS_SFT			5
+#define RT5677_GPIO5_STATUS_MASK		(0x1 << 4)
+#define RT5677_GPIO5_STATUS_SFT			4
+#define RT5677_GPIO4_STATUS_MASK		(0x1 << 3)
+#define RT5677_GPIO4_STATUS_SFT			3
+#define RT5677_GPIO3_STATUS_MASK		(0x1 << 2)
+#define RT5677_GPIO3_STATUS_SFT			2
+#define RT5677_GPIO2_STATUS_MASK		(0x1 << 1)
+#define RT5677_GPIO2_STATUS_SFT			1
+#define RT5677_GPIO1_STATUS_MASK		(0x1 << 0)
+#define RT5677_GPIO1_STATUS_SFT			0
+
+/* GPIO Control 1 (0xc0) */
+#define RT5677_GPIO1_PIN_MASK			(0x1 << 15)
+#define RT5677_GPIO1_PIN_SFT			15
+#define RT5677_GPIO1_PIN_GPIO1			(0x0 << 15)
+#define RT5677_GPIO1_PIN_IRQ			(0x1 << 15)
+#define RT5677_IPTV_MODE_MASK			(0x1 << 14)
+#define RT5677_IPTV_MODE_SFT			14
+#define RT5677_IPTV_MODE_GPIO			(0x0 << 14)
+#define RT5677_IPTV_MODE_IPTV			(0x1 << 14)
+#define RT5677_FUNC_MODE_MASK			(0x1 << 13)
+#define RT5677_FUNC_MODE_SFT			13
+#define RT5677_FUNC_MODE_DMIC_GPIO		(0x0 << 13)
+#define RT5677_FUNC_MODE_JTAG			(0x1 << 13)
+
+/* GPIO Control 2 (0xc1) */
+#define RT5677_GPIO5_DIR_MASK			(0x1 << 14)
+#define RT5677_GPIO5_DIR_SFT			14
+#define RT5677_GPIO5_DIR_IN			(0x0 << 14)
+#define RT5677_GPIO5_DIR_OUT			(0x1 << 14)
+#define RT5677_GPIO5_OUT_MASK			(0x1 << 13)
+#define RT5677_GPIO5_OUT_SFT			13
+#define RT5677_GPIO5_OUT_LO			(0x0 << 13)
+#define RT5677_GPIO5_OUT_HI			(0x1 << 13)
+#define RT5677_GPIO5_P_MASK			(0x1 << 12)
+#define RT5677_GPIO5_P_SFT			12
+#define RT5677_GPIO5_P_NOR			(0x0 << 12)
+#define RT5677_GPIO5_P_INV			(0x1 << 12)
+#define RT5677_GPIO4_DIR_MASK			(0x1 << 11)
+#define RT5677_GPIO4_DIR_SFT			11
+#define RT5677_GPIO4_DIR_IN			(0x0 << 11)
+#define RT5677_GPIO4_DIR_OUT			(0x1 << 11)
+#define RT5677_GPIO4_OUT_MASK			(0x1 << 10)
+#define RT5677_GPIO4_OUT_SFT			10
+#define RT5677_GPIO4_OUT_LO			(0x0 << 10)
+#define RT5677_GPIO4_OUT_HI			(0x1 << 10)
+#define RT5677_GPIO4_P_MASK			(0x1 << 9)
+#define RT5677_GPIO4_P_SFT			9
+#define RT5677_GPIO4_P_NOR			(0x0 << 9)
+#define RT5677_GPIO4_P_INV			(0x1 << 9)
+#define RT5677_GPIO3_DIR_MASK			(0x1 << 8)
+#define RT5677_GPIO3_DIR_SFT			8
+#define RT5677_GPIO3_DIR_IN			(0x0 << 8)
+#define RT5677_GPIO3_DIR_OUT			(0x1 << 8)
+#define RT5677_GPIO3_OUT_MASK			(0x1 << 7)
+#define RT5677_GPIO3_OUT_SFT			7
+#define RT5677_GPIO3_OUT_LO			(0x0 << 7)
+#define RT5677_GPIO3_OUT_HI			(0x1 << 7)
+#define RT5677_GPIO3_P_MASK			(0x1 << 6)
+#define RT5677_GPIO3_P_SFT			6
+#define RT5677_GPIO3_P_NOR			(0x0 << 6)
+#define RT5677_GPIO3_P_INV			(0x1 << 6)
+#define RT5677_GPIO2_DIR_MASK			(0x1 << 5)
+#define RT5677_GPIO2_DIR_SFT			5
+#define RT5677_GPIO2_DIR_IN			(0x0 << 5)
+#define RT5677_GPIO2_DIR_OUT			(0x1 << 5)
+#define RT5677_GPIO2_OUT_MASK			(0x1 << 4)
+#define RT5677_GPIO2_OUT_SFT			4
+#define RT5677_GPIO2_OUT_LO			(0x0 << 4)
+#define RT5677_GPIO2_OUT_HI			(0x1 << 4)
+#define RT5677_GPIO2_P_MASK			(0x1 << 3)
+#define RT5677_GPIO2_P_SFT			3
+#define RT5677_GPIO2_P_NOR			(0x0 << 3)
+#define RT5677_GPIO2_P_INV			(0x1 << 3)
+#define RT5677_GPIO1_DIR_MASK			(0x1 << 2)
+#define RT5677_GPIO1_DIR_SFT			2
+#define RT5677_GPIO1_DIR_IN			(0x0 << 2)
+#define RT5677_GPIO1_DIR_OUT			(0x1 << 2)
+#define RT5677_GPIO1_OUT_MASK			(0x1 << 1)
+#define RT5677_GPIO1_OUT_SFT			1
+#define RT5677_GPIO1_OUT_LO			(0x0 << 1)
+#define RT5677_GPIO1_OUT_HI			(0x1 << 1)
+#define RT5677_GPIO1_P_MASK			(0x1 << 0)
+#define RT5677_GPIO1_P_SFT			0
+#define RT5677_GPIO1_P_NOR			(0x0 << 0)
+#define RT5677_GPIO1_P_INV			(0x1 << 0)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5677_GPIO6_DIR_MASK			(0x1 << 2)
+#define RT5677_GPIO6_DIR_SFT			2
+#define RT5677_GPIO6_DIR_IN			(0x0 << 2)
+#define RT5677_GPIO6_DIR_OUT			(0x1 << 2)
+#define RT5677_GPIO6_OUT_MASK			(0x1 << 1)
+#define RT5677_GPIO6_OUT_SFT			1
+#define RT5677_GPIO6_OUT_LO			(0x0 << 1)
+#define RT5677_GPIO6_OUT_HI			(0x1 << 1)
+#define RT5677_GPIO6_P_MASK			(0x1 << 0)
+#define RT5677_GPIO6_P_SFT			0
+#define RT5677_GPIO6_P_NOR			(0x0 << 0)
+#define RT5677_GPIO6_P_INV			(0x1 << 0)
+
+/* Virtual DSP Mixer Control (0xf7 0xf8 0xf9) */
+#define RT5677_DSP_IB_01_H			(0x1 << 15)
+#define RT5677_DSP_IB_01_H_SFT			15
+#define RT5677_DSP_IB_23_H			(0x1 << 14)
+#define RT5677_DSP_IB_23_H_SFT			14
+#define RT5677_DSP_IB_45_H			(0x1 << 13)
+#define RT5677_DSP_IB_45_H_SFT			13
+#define RT5677_DSP_IB_6_H			(0x1 << 12)
+#define RT5677_DSP_IB_6_H_SFT			12
+#define RT5677_DSP_IB_7_H			(0x1 << 11)
+#define RT5677_DSP_IB_7_H_SFT			11
+#define RT5677_DSP_IB_8_H			(0x1 << 10)
+#define RT5677_DSP_IB_8_H_SFT			10
+#define RT5677_DSP_IB_9_H			(0x1 << 9)
+#define RT5677_DSP_IB_9_H_SFT			9
+#define RT5677_DSP_IB_01_L			(0x1 << 7)
+#define RT5677_DSP_IB_01_L_SFT			7
+#define RT5677_DSP_IB_23_L			(0x1 << 6)
+#define RT5677_DSP_IB_23_L_SFT			6
+#define RT5677_DSP_IB_45_L			(0x1 << 5)
+#define RT5677_DSP_IB_45_L_SFT			5
+#define RT5677_DSP_IB_6_L			(0x1 << 4)
+#define RT5677_DSP_IB_6_L_SFT			4
+#define RT5677_DSP_IB_7_L			(0x1 << 3)
+#define RT5677_DSP_IB_7_L_SFT			3
+#define RT5677_DSP_IB_8_L			(0x1 << 2)
+#define RT5677_DSP_IB_8_L_SFT			2
+#define RT5677_DSP_IB_9_L			(0x1 << 1)
+#define RT5677_DSP_IB_9_L_SFT			1
+
+/* General Control2 (0xfc)*/
+#define RT5677_GPIO5_FUNC_MASK			(0x1 << 9)
+#define RT5677_GPIO5_FUNC_GPIO			(0x0 << 9)
+#define RT5677_GPIO5_FUNC_DMIC			(0x1 << 9)
+
+#define RT5677_FIRMWARE1	"rt5677_dsp_fw1.bin"
+#define RT5677_FIRMWARE2	"rt5677_dsp_fw2.bin"
+
+/* System Clock Source */
+enum {
+	RT5677_SCLK_S_MCLK,
+	RT5677_SCLK_S_PLL1,
+	RT5677_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+	RT5677_PLL1_S_MCLK,
+	RT5677_PLL1_S_BCLK1,
+	RT5677_PLL1_S_BCLK2,
+	RT5677_PLL1_S_BCLK3,
+	RT5677_PLL1_S_BCLK4,
+};
+
+enum {
+	RT5677_AIF1,
+	RT5677_AIF2,
+	RT5677_AIF3,
+	RT5677_AIF4,
+	RT5677_AIF5,
+	RT5677_AIFS,
+};
+
+enum {
+	RT5677_GPIO1,
+	RT5677_GPIO2,
+	RT5677_GPIO3,
+	RT5677_GPIO4,
+	RT5677_GPIO5,
+	RT5677_GPIO6,
+	RT5677_GPIO_NUM,
+};
+
+enum {
+	RT5677_IRQ_JD1,
+	RT5677_IRQ_JD2,
+	RT5677_IRQ_JD3,
+};
+
+enum rt5677_type {
+	RT5677,
+	RT5676,
+};
+
+/* ASRC clock source selection */
+enum {
+	RT5677_CLK_SEL_SYS,
+	RT5677_CLK_SEL_I2S1_ASRC,
+	RT5677_CLK_SEL_I2S2_ASRC,
+	RT5677_CLK_SEL_I2S3_ASRC,
+	RT5677_CLK_SEL_I2S4_ASRC,
+	RT5677_CLK_SEL_I2S5_ASRC,
+	RT5677_CLK_SEL_I2S6_ASRC,
+	RT5677_CLK_SEL_SYS2,
+	RT5677_CLK_SEL_SYS3,
+	RT5677_CLK_SEL_SYS4,
+	RT5677_CLK_SEL_SYS5,
+	RT5677_CLK_SEL_SYS6,
+	RT5677_CLK_SEL_SYS7,
+};
+
+/* filter mask */
+enum {
+	RT5677_DA_STEREO_FILTER = 0x1,
+	RT5677_DA_MONO2_L_FILTER = (0x1 << 1),
+	RT5677_DA_MONO2_R_FILTER = (0x1 << 2),
+	RT5677_DA_MONO3_L_FILTER = (0x1 << 3),
+	RT5677_DA_MONO3_R_FILTER = (0x1 << 4),
+	RT5677_DA_MONO4_L_FILTER = (0x1 << 5),
+	RT5677_DA_MONO4_R_FILTER = (0x1 << 6),
+	RT5677_AD_STEREO1_FILTER = (0x1 << 7),
+	RT5677_AD_STEREO2_FILTER = (0x1 << 8),
+	RT5677_AD_STEREO3_FILTER = (0x1 << 9),
+	RT5677_AD_STEREO4_FILTER = (0x1 << 10),
+	RT5677_AD_MONO_L_FILTER = (0x1 << 11),
+	RT5677_AD_MONO_R_FILTER = (0x1 << 12),
+	RT5677_DSP_OB_0_3_FILTER = (0x1 << 13),
+	RT5677_DSP_OB_4_7_FILTER = (0x1 << 14),
+	RT5677_I2S1_SOURCE = (0x1 << 15),
+	RT5677_I2S2_SOURCE = (0x1 << 16),
+	RT5677_I2S3_SOURCE = (0x1 << 17),
+	RT5677_I2S4_SOURCE = (0x1 << 18),
+};
+
+enum rt5677_dmic2_clk {
+	RT5677_DMIC_CLK1 = 0,
+	RT5677_DMIC_CLK2 = 1,
+};
+
+struct rt5677_platform_data {
+	/* IN1/IN2/LOUT1/LOUT2/LOUT3 can optionally be differential */
+	bool in1_diff;
+	bool in2_diff;
+	bool lout1_diff;
+	bool lout2_diff;
+	bool lout3_diff;
+	/* DMIC2 clock source selection */
+	enum rt5677_dmic2_clk dmic2_clk_pin;
+
+	/* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */
+	u8 gpio_config[6];
+
+	/* jd1 can select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively */
+	unsigned int jd1_gpio;
+	/* jd2 and jd3 can select 0 ~ 3 as
+		OFF, GPIO4, GPIO5 and GPIO6 respectively */
+	unsigned int jd2_gpio;
+	unsigned int jd3_gpio;
+
+	/* Set MICBIAS1 VDD 1v8 or 3v3 */
+	bool micbias1_vdd_3v3;
+};
+
+struct rt5677_priv {
+	struct snd_soc_component *component;
+	struct rt5677_platform_data pdata;
+	struct regmap *regmap, *regmap_physical;
+	const struct firmware *fw1, *fw2;
+	struct mutex dsp_cmd_lock, dsp_pri_lock;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5677_AIFS];
+	int bclk[RT5677_AIFS];
+	int master[RT5677_AIFS];
+	int pll_src;
+	int pll_in;
+	int pll_out;
+	struct gpio_desc *pow_ldo2; /* POW_LDO2 pin */
+	struct gpio_desc *reset_pin; /* RESET pin */
+	enum rt5677_type type;
+#ifdef CONFIG_GPIOLIB
+	struct gpio_chip gpio_chip;
+#endif
+	bool dsp_vad_en;
+	struct regmap_irq_chip_data *irq_data;
+	bool is_dsp_mode;
+	bool is_vref_slow;
+};
+
+int rt5677_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src);
+
+#endif /* __RT5677_H__ */
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
new file mode 100644
index 0000000..afe7d5b
--- /dev/null
+++ b/sound/soc/codecs/rt5682.c
@@ -0,0 +1,2681 @@
+/*
+ * rt5682.c  --  RT5682 ALSA SoC audio component driver
+ *
+ * Copyright 2018 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/rt5682.h>
+
+#include "rl6231.h"
+#include "rt5682.h"
+
+#define RT5682_NUM_SUPPLIES 3
+
+static const char *rt5682_supply_names[RT5682_NUM_SUPPLIES] = {
+	"AVDD",
+	"MICVDD",
+	"VBAT",
+};
+
+struct rt5682_priv {
+	struct snd_soc_component *component;
+	struct rt5682_platform_data pdata;
+	struct regmap *regmap;
+	struct snd_soc_jack *hs_jack;
+	struct regulator_bulk_data supplies[RT5682_NUM_SUPPLIES];
+	struct delayed_work jack_detect_work;
+	struct delayed_work jd_check_work;
+	struct mutex calibrate_mutex;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5682_AIFS];
+	int bclk[RT5682_AIFS];
+	int master[RT5682_AIFS];
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+	int jack_type;
+};
+
+static const struct reg_sequence patch_list[] = {
+	{0x01c1, 0x1000},
+};
+
+static const struct reg_default rt5682_reg[] = {
+	{0x0002, 0x8080},
+	{0x0003, 0x8000},
+	{0x0005, 0x0000},
+	{0x0006, 0x0000},
+	{0x0008, 0x800f},
+	{0x000b, 0x0000},
+	{0x0010, 0x4040},
+	{0x0011, 0x0000},
+	{0x0012, 0x1404},
+	{0x0013, 0x1000},
+	{0x0014, 0xa00a},
+	{0x0015, 0x0404},
+	{0x0016, 0x0404},
+	{0x0019, 0xafaf},
+	{0x001c, 0x2f2f},
+	{0x001f, 0x0000},
+	{0x0022, 0x5757},
+	{0x0023, 0x0039},
+	{0x0024, 0x000b},
+	{0x0026, 0xc0c4},
+	{0x0029, 0x8080},
+	{0x002a, 0xa0a0},
+	{0x002b, 0x0300},
+	{0x0030, 0x0000},
+	{0x003c, 0x0080},
+	{0x0044, 0x0c0c},
+	{0x0049, 0x0000},
+	{0x0061, 0x0000},
+	{0x0062, 0x0000},
+	{0x0063, 0x003f},
+	{0x0064, 0x0000},
+	{0x0065, 0x0000},
+	{0x0066, 0x0030},
+	{0x0067, 0x0000},
+	{0x006b, 0x0000},
+	{0x006c, 0x0000},
+	{0x006d, 0x2200},
+	{0x006e, 0x0a10},
+	{0x0070, 0x8000},
+	{0x0071, 0x8000},
+	{0x0073, 0x0000},
+	{0x0074, 0x0000},
+	{0x0075, 0x0002},
+	{0x0076, 0x0001},
+	{0x0079, 0x0000},
+	{0x007a, 0x0000},
+	{0x007b, 0x0000},
+	{0x007c, 0x0100},
+	{0x007e, 0x0000},
+	{0x0080, 0x0000},
+	{0x0081, 0x0000},
+	{0x0082, 0x0000},
+	{0x0083, 0x0000},
+	{0x0084, 0x0000},
+	{0x0085, 0x0000},
+	{0x0086, 0x0005},
+	{0x0087, 0x0000},
+	{0x0088, 0x0000},
+	{0x008c, 0x0003},
+	{0x008d, 0x0000},
+	{0x008e, 0x0060},
+	{0x008f, 0x1000},
+	{0x0091, 0x0c26},
+	{0x0092, 0x0073},
+	{0x0093, 0x0000},
+	{0x0094, 0x0080},
+	{0x0098, 0x0000},
+	{0x009a, 0x0000},
+	{0x009b, 0x0000},
+	{0x009c, 0x0000},
+	{0x009d, 0x0000},
+	{0x009e, 0x100c},
+	{0x009f, 0x0000},
+	{0x00a0, 0x0000},
+	{0x00a3, 0x0002},
+	{0x00a4, 0x0001},
+	{0x00ae, 0x2040},
+	{0x00af, 0x0000},
+	{0x00b6, 0x0000},
+	{0x00b7, 0x0000},
+	{0x00b8, 0x0000},
+	{0x00b9, 0x0002},
+	{0x00be, 0x0000},
+	{0x00c0, 0x0160},
+	{0x00c1, 0x82a0},
+	{0x00c2, 0x0000},
+	{0x00d0, 0x0000},
+	{0x00d1, 0x2244},
+	{0x00d2, 0x3300},
+	{0x00d3, 0x2200},
+	{0x00d4, 0x0000},
+	{0x00d9, 0x0009},
+	{0x00da, 0x0000},
+	{0x00db, 0x0000},
+	{0x00dc, 0x00c0},
+	{0x00dd, 0x2220},
+	{0x00de, 0x3131},
+	{0x00df, 0x3131},
+	{0x00e0, 0x3131},
+	{0x00e2, 0x0000},
+	{0x00e3, 0x4000},
+	{0x00e4, 0x0aa0},
+	{0x00e5, 0x3131},
+	{0x00e6, 0x3131},
+	{0x00e7, 0x3131},
+	{0x00e8, 0x3131},
+	{0x00ea, 0xb320},
+	{0x00eb, 0x0000},
+	{0x00f0, 0x0000},
+	{0x00f1, 0x00d0},
+	{0x00f2, 0x00d0},
+	{0x00f6, 0x0000},
+	{0x00fa, 0x0000},
+	{0x00fb, 0x0000},
+	{0x00fc, 0x0000},
+	{0x00fd, 0x0000},
+	{0x00fe, 0x10ec},
+	{0x00ff, 0x6530},
+	{0x0100, 0xa0a0},
+	{0x010b, 0x0000},
+	{0x010c, 0xae00},
+	{0x010d, 0xaaa0},
+	{0x010e, 0x8aa2},
+	{0x010f, 0x02a2},
+	{0x0110, 0xc000},
+	{0x0111, 0x04a2},
+	{0x0112, 0x2800},
+	{0x0113, 0x0000},
+	{0x0117, 0x0100},
+	{0x0125, 0x0410},
+	{0x0132, 0x6026},
+	{0x0136, 0x5555},
+	{0x0138, 0x3700},
+	{0x013a, 0x2000},
+	{0x013b, 0x2000},
+	{0x013c, 0x2005},
+	{0x013f, 0x0000},
+	{0x0142, 0x0000},
+	{0x0145, 0x0002},
+	{0x0146, 0x0000},
+	{0x0147, 0x0000},
+	{0x0148, 0x0000},
+	{0x0149, 0x0000},
+	{0x0150, 0x79a1},
+	{0x0151, 0x0000},
+	{0x0160, 0x4ec0},
+	{0x0161, 0x0080},
+	{0x0162, 0x0200},
+	{0x0163, 0x0800},
+	{0x0164, 0x0000},
+	{0x0165, 0x0000},
+	{0x0166, 0x0000},
+	{0x0167, 0x000f},
+	{0x0168, 0x000f},
+	{0x0169, 0x0021},
+	{0x0190, 0x413d},
+	{0x0194, 0x0000},
+	{0x0195, 0x0000},
+	{0x0197, 0x0022},
+	{0x0198, 0x0000},
+	{0x0199, 0x0000},
+	{0x01af, 0x0000},
+	{0x01b0, 0x0400},
+	{0x01b1, 0x0000},
+	{0x01b2, 0x0000},
+	{0x01b3, 0x0000},
+	{0x01b4, 0x0000},
+	{0x01b5, 0x0000},
+	{0x01b6, 0x01c3},
+	{0x01b7, 0x02a0},
+	{0x01b8, 0x03e9},
+	{0x01b9, 0x1389},
+	{0x01ba, 0xc351},
+	{0x01bb, 0x0009},
+	{0x01bc, 0x0018},
+	{0x01bd, 0x002a},
+	{0x01be, 0x004c},
+	{0x01bf, 0x0097},
+	{0x01c0, 0x433d},
+	{0x01c2, 0x0000},
+	{0x01c3, 0x0000},
+	{0x01c4, 0x0000},
+	{0x01c5, 0x0000},
+	{0x01c6, 0x0000},
+	{0x01c7, 0x0000},
+	{0x01c8, 0x40af},
+	{0x01c9, 0x0702},
+	{0x01ca, 0x0000},
+	{0x01cb, 0x0000},
+	{0x01cc, 0x5757},
+	{0x01cd, 0x5757},
+	{0x01ce, 0x5757},
+	{0x01cf, 0x5757},
+	{0x01d0, 0x5757},
+	{0x01d1, 0x5757},
+	{0x01d2, 0x5757},
+	{0x01d3, 0x5757},
+	{0x01d4, 0x5757},
+	{0x01d5, 0x5757},
+	{0x01d6, 0x0000},
+	{0x01d7, 0x0008},
+	{0x01d8, 0x0029},
+	{0x01d9, 0x3333},
+	{0x01da, 0x0000},
+	{0x01db, 0x0004},
+	{0x01dc, 0x0000},
+	{0x01de, 0x7c00},
+	{0x01df, 0x0320},
+	{0x01e0, 0x06a1},
+	{0x01e1, 0x0000},
+	{0x01e2, 0x0000},
+	{0x01e3, 0x0000},
+	{0x01e4, 0x0000},
+	{0x01e6, 0x0001},
+	{0x01e7, 0x0000},
+	{0x01e8, 0x0000},
+	{0x01ea, 0x0000},
+	{0x01eb, 0x0000},
+	{0x01ec, 0x0000},
+	{0x01ed, 0x0000},
+	{0x01ee, 0x0000},
+	{0x01ef, 0x0000},
+	{0x01f0, 0x0000},
+	{0x01f1, 0x0000},
+	{0x01f2, 0x0000},
+	{0x01f3, 0x0000},
+	{0x01f4, 0x0000},
+	{0x0210, 0x6297},
+	{0x0211, 0xa005},
+	{0x0212, 0x824c},
+	{0x0213, 0xf7ff},
+	{0x0214, 0xf24c},
+	{0x0215, 0x0102},
+	{0x0216, 0x00a3},
+	{0x0217, 0x0048},
+	{0x0218, 0xa2c0},
+	{0x0219, 0x0400},
+	{0x021a, 0x00c8},
+	{0x021b, 0x00c0},
+	{0x021c, 0x0000},
+	{0x0250, 0x4500},
+	{0x0251, 0x40b3},
+	{0x0252, 0x0000},
+	{0x0253, 0x0000},
+	{0x0254, 0x0000},
+	{0x0255, 0x0000},
+	{0x0256, 0x0000},
+	{0x0257, 0x0000},
+	{0x0258, 0x0000},
+	{0x0259, 0x0000},
+	{0x025a, 0x0005},
+	{0x0270, 0x0000},
+	{0x02ff, 0x0110},
+	{0x0300, 0x001f},
+	{0x0301, 0x032c},
+	{0x0302, 0x5f21},
+	{0x0303, 0x4000},
+	{0x0304, 0x4000},
+	{0x0305, 0x06d5},
+	{0x0306, 0x8000},
+	{0x0307, 0x0700},
+	{0x0310, 0x4560},
+	{0x0311, 0xa4a8},
+	{0x0312, 0x7418},
+	{0x0313, 0x0000},
+	{0x0314, 0x0006},
+	{0x0315, 0xffff},
+	{0x0316, 0xc400},
+	{0x0317, 0x0000},
+	{0x03c0, 0x7e00},
+	{0x03c1, 0x8000},
+	{0x03c2, 0x8000},
+	{0x03c3, 0x8000},
+	{0x03c4, 0x8000},
+	{0x03c5, 0x8000},
+	{0x03c6, 0x8000},
+	{0x03c7, 0x8000},
+	{0x03c8, 0x8000},
+	{0x03c9, 0x8000},
+	{0x03ca, 0x8000},
+	{0x03cb, 0x8000},
+	{0x03cc, 0x8000},
+	{0x03d0, 0x0000},
+	{0x03d1, 0x0000},
+	{0x03d2, 0x0000},
+	{0x03d3, 0x0000},
+	{0x03d4, 0x2000},
+	{0x03d5, 0x2000},
+	{0x03d6, 0x0000},
+	{0x03d7, 0x0000},
+	{0x03d8, 0x2000},
+	{0x03d9, 0x2000},
+	{0x03da, 0x2000},
+	{0x03db, 0x2000},
+	{0x03dc, 0x0000},
+	{0x03dd, 0x0000},
+	{0x03de, 0x0000},
+	{0x03df, 0x2000},
+	{0x03e0, 0x0000},
+	{0x03e1, 0x0000},
+	{0x03e2, 0x0000},
+	{0x03e3, 0x0000},
+	{0x03e4, 0x0000},
+	{0x03e5, 0x0000},
+	{0x03e6, 0x0000},
+	{0x03e7, 0x0000},
+	{0x03e8, 0x0000},
+	{0x03e9, 0x0000},
+	{0x03ea, 0x0000},
+	{0x03eb, 0x0000},
+	{0x03ec, 0x0000},
+	{0x03ed, 0x0000},
+	{0x03ee, 0x0000},
+	{0x03ef, 0x0000},
+	{0x03f0, 0x0800},
+	{0x03f1, 0x0800},
+	{0x03f2, 0x0800},
+	{0x03f3, 0x0800},
+};
+
+static bool rt5682_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5682_RESET:
+	case RT5682_CBJ_CTRL_2:
+	case RT5682_INT_ST_1:
+	case RT5682_4BTN_IL_CMD_1:
+	case RT5682_AJD1_CTRL:
+	case RT5682_HP_CALIB_CTRL_1:
+	case RT5682_DEVICE_ID:
+	case RT5682_I2C_MODE:
+	case RT5682_HP_CALIB_CTRL_10:
+	case RT5682_EFUSE_CTRL_2:
+	case RT5682_JD_TOP_VC_VTRL:
+	case RT5682_HP_IMP_SENS_CTRL_19:
+	case RT5682_IL_CMD_1:
+	case RT5682_SAR_IL_CMD_2:
+	case RT5682_SAR_IL_CMD_4:
+	case RT5682_SAR_IL_CMD_10:
+	case RT5682_SAR_IL_CMD_11:
+	case RT5682_EFUSE_CTRL_6...RT5682_EFUSE_CTRL_11:
+	case RT5682_HP_CALIB_STA_1...RT5682_HP_CALIB_STA_11:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5682_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5682_RESET:
+	case RT5682_VERSION_ID:
+	case RT5682_VENDOR_ID:
+	case RT5682_DEVICE_ID:
+	case RT5682_HP_CTRL_1:
+	case RT5682_HP_CTRL_2:
+	case RT5682_HPL_GAIN:
+	case RT5682_HPR_GAIN:
+	case RT5682_I2C_CTRL:
+	case RT5682_CBJ_BST_CTRL:
+	case RT5682_CBJ_CTRL_1:
+	case RT5682_CBJ_CTRL_2:
+	case RT5682_CBJ_CTRL_3:
+	case RT5682_CBJ_CTRL_4:
+	case RT5682_CBJ_CTRL_5:
+	case RT5682_CBJ_CTRL_6:
+	case RT5682_CBJ_CTRL_7:
+	case RT5682_DAC1_DIG_VOL:
+	case RT5682_STO1_ADC_DIG_VOL:
+	case RT5682_STO1_ADC_BOOST:
+	case RT5682_HP_IMP_GAIN_1:
+	case RT5682_HP_IMP_GAIN_2:
+	case RT5682_SIDETONE_CTRL:
+	case RT5682_STO1_ADC_MIXER:
+	case RT5682_AD_DA_MIXER:
+	case RT5682_STO1_DAC_MIXER:
+	case RT5682_A_DAC1_MUX:
+	case RT5682_DIG_INF2_DATA:
+	case RT5682_REC_MIXER:
+	case RT5682_CAL_REC:
+	case RT5682_ALC_BACK_GAIN:
+	case RT5682_PWR_DIG_1:
+	case RT5682_PWR_DIG_2:
+	case RT5682_PWR_ANLG_1:
+	case RT5682_PWR_ANLG_2:
+	case RT5682_PWR_ANLG_3:
+	case RT5682_PWR_MIXER:
+	case RT5682_PWR_VOL:
+	case RT5682_CLK_DET:
+	case RT5682_RESET_LPF_CTRL:
+	case RT5682_RESET_HPF_CTRL:
+	case RT5682_DMIC_CTRL_1:
+	case RT5682_I2S1_SDP:
+	case RT5682_I2S2_SDP:
+	case RT5682_ADDA_CLK_1:
+	case RT5682_ADDA_CLK_2:
+	case RT5682_I2S1_F_DIV_CTRL_1:
+	case RT5682_I2S1_F_DIV_CTRL_2:
+	case RT5682_TDM_CTRL:
+	case RT5682_TDM_ADDA_CTRL_1:
+	case RT5682_TDM_ADDA_CTRL_2:
+	case RT5682_DATA_SEL_CTRL_1:
+	case RT5682_TDM_TCON_CTRL:
+	case RT5682_GLB_CLK:
+	case RT5682_PLL_CTRL_1:
+	case RT5682_PLL_CTRL_2:
+	case RT5682_PLL_TRACK_1:
+	case RT5682_PLL_TRACK_2:
+	case RT5682_PLL_TRACK_3:
+	case RT5682_PLL_TRACK_4:
+	case RT5682_PLL_TRACK_5:
+	case RT5682_PLL_TRACK_6:
+	case RT5682_PLL_TRACK_11:
+	case RT5682_SDW_REF_CLK:
+	case RT5682_DEPOP_1:
+	case RT5682_DEPOP_2:
+	case RT5682_HP_CHARGE_PUMP_1:
+	case RT5682_HP_CHARGE_PUMP_2:
+	case RT5682_MICBIAS_1:
+	case RT5682_MICBIAS_2:
+	case RT5682_PLL_TRACK_12:
+	case RT5682_PLL_TRACK_14:
+	case RT5682_PLL2_CTRL_1:
+	case RT5682_PLL2_CTRL_2:
+	case RT5682_PLL2_CTRL_3:
+	case RT5682_PLL2_CTRL_4:
+	case RT5682_RC_CLK_CTRL:
+	case RT5682_I2S_M_CLK_CTRL_1:
+	case RT5682_I2S2_F_DIV_CTRL_1:
+	case RT5682_I2S2_F_DIV_CTRL_2:
+	case RT5682_EQ_CTRL_1:
+	case RT5682_EQ_CTRL_2:
+	case RT5682_IRQ_CTRL_1:
+	case RT5682_IRQ_CTRL_2:
+	case RT5682_IRQ_CTRL_3:
+	case RT5682_IRQ_CTRL_4:
+	case RT5682_INT_ST_1:
+	case RT5682_GPIO_CTRL_1:
+	case RT5682_GPIO_CTRL_2:
+	case RT5682_GPIO_CTRL_3:
+	case RT5682_HP_AMP_DET_CTRL_1:
+	case RT5682_HP_AMP_DET_CTRL_2:
+	case RT5682_MID_HP_AMP_DET:
+	case RT5682_LOW_HP_AMP_DET:
+	case RT5682_DELAY_BUF_CTRL:
+	case RT5682_SV_ZCD_1:
+	case RT5682_SV_ZCD_2:
+	case RT5682_IL_CMD_1:
+	case RT5682_IL_CMD_2:
+	case RT5682_IL_CMD_3:
+	case RT5682_IL_CMD_4:
+	case RT5682_IL_CMD_5:
+	case RT5682_IL_CMD_6:
+	case RT5682_4BTN_IL_CMD_1:
+	case RT5682_4BTN_IL_CMD_2:
+	case RT5682_4BTN_IL_CMD_3:
+	case RT5682_4BTN_IL_CMD_4:
+	case RT5682_4BTN_IL_CMD_5:
+	case RT5682_4BTN_IL_CMD_6:
+	case RT5682_4BTN_IL_CMD_7:
+	case RT5682_ADC_STO1_HP_CTRL_1:
+	case RT5682_ADC_STO1_HP_CTRL_2:
+	case RT5682_AJD1_CTRL:
+	case RT5682_JD1_THD:
+	case RT5682_JD2_THD:
+	case RT5682_JD_CTRL_1:
+	case RT5682_DUMMY_1:
+	case RT5682_DUMMY_2:
+	case RT5682_DUMMY_3:
+	case RT5682_DAC_ADC_DIG_VOL1:
+	case RT5682_BIAS_CUR_CTRL_2:
+	case RT5682_BIAS_CUR_CTRL_3:
+	case RT5682_BIAS_CUR_CTRL_4:
+	case RT5682_BIAS_CUR_CTRL_5:
+	case RT5682_BIAS_CUR_CTRL_6:
+	case RT5682_BIAS_CUR_CTRL_7:
+	case RT5682_BIAS_CUR_CTRL_8:
+	case RT5682_BIAS_CUR_CTRL_9:
+	case RT5682_BIAS_CUR_CTRL_10:
+	case RT5682_VREF_REC_OP_FB_CAP_CTRL:
+	case RT5682_CHARGE_PUMP_1:
+	case RT5682_DIG_IN_CTRL_1:
+	case RT5682_PAD_DRIVING_CTRL:
+	case RT5682_SOFT_RAMP_DEPOP:
+	case RT5682_CHOP_DAC:
+	case RT5682_CHOP_ADC:
+	case RT5682_CALIB_ADC_CTRL:
+	case RT5682_VOL_TEST:
+	case RT5682_SPKVDD_DET_STA:
+	case RT5682_TEST_MODE_CTRL_1:
+	case RT5682_TEST_MODE_CTRL_2:
+	case RT5682_TEST_MODE_CTRL_3:
+	case RT5682_TEST_MODE_CTRL_4:
+	case RT5682_TEST_MODE_CTRL_5:
+	case RT5682_PLL1_INTERNAL:
+	case RT5682_PLL2_INTERNAL:
+	case RT5682_STO_NG2_CTRL_1:
+	case RT5682_STO_NG2_CTRL_2:
+	case RT5682_STO_NG2_CTRL_3:
+	case RT5682_STO_NG2_CTRL_4:
+	case RT5682_STO_NG2_CTRL_5:
+	case RT5682_STO_NG2_CTRL_6:
+	case RT5682_STO_NG2_CTRL_7:
+	case RT5682_STO_NG2_CTRL_8:
+	case RT5682_STO_NG2_CTRL_9:
+	case RT5682_STO_NG2_CTRL_10:
+	case RT5682_STO1_DAC_SIL_DET:
+	case RT5682_SIL_PSV_CTRL1:
+	case RT5682_SIL_PSV_CTRL2:
+	case RT5682_SIL_PSV_CTRL3:
+	case RT5682_SIL_PSV_CTRL4:
+	case RT5682_SIL_PSV_CTRL5:
+	case RT5682_HP_IMP_SENS_CTRL_01:
+	case RT5682_HP_IMP_SENS_CTRL_02:
+	case RT5682_HP_IMP_SENS_CTRL_03:
+	case RT5682_HP_IMP_SENS_CTRL_04:
+	case RT5682_HP_IMP_SENS_CTRL_05:
+	case RT5682_HP_IMP_SENS_CTRL_06:
+	case RT5682_HP_IMP_SENS_CTRL_07:
+	case RT5682_HP_IMP_SENS_CTRL_08:
+	case RT5682_HP_IMP_SENS_CTRL_09:
+	case RT5682_HP_IMP_SENS_CTRL_10:
+	case RT5682_HP_IMP_SENS_CTRL_11:
+	case RT5682_HP_IMP_SENS_CTRL_12:
+	case RT5682_HP_IMP_SENS_CTRL_13:
+	case RT5682_HP_IMP_SENS_CTRL_14:
+	case RT5682_HP_IMP_SENS_CTRL_15:
+	case RT5682_HP_IMP_SENS_CTRL_16:
+	case RT5682_HP_IMP_SENS_CTRL_17:
+	case RT5682_HP_IMP_SENS_CTRL_18:
+	case RT5682_HP_IMP_SENS_CTRL_19:
+	case RT5682_HP_IMP_SENS_CTRL_20:
+	case RT5682_HP_IMP_SENS_CTRL_21:
+	case RT5682_HP_IMP_SENS_CTRL_22:
+	case RT5682_HP_IMP_SENS_CTRL_23:
+	case RT5682_HP_IMP_SENS_CTRL_24:
+	case RT5682_HP_IMP_SENS_CTRL_25:
+	case RT5682_HP_IMP_SENS_CTRL_26:
+	case RT5682_HP_IMP_SENS_CTRL_27:
+	case RT5682_HP_IMP_SENS_CTRL_28:
+	case RT5682_HP_IMP_SENS_CTRL_29:
+	case RT5682_HP_IMP_SENS_CTRL_30:
+	case RT5682_HP_IMP_SENS_CTRL_31:
+	case RT5682_HP_IMP_SENS_CTRL_32:
+	case RT5682_HP_IMP_SENS_CTRL_33:
+	case RT5682_HP_IMP_SENS_CTRL_34:
+	case RT5682_HP_IMP_SENS_CTRL_35:
+	case RT5682_HP_IMP_SENS_CTRL_36:
+	case RT5682_HP_IMP_SENS_CTRL_37:
+	case RT5682_HP_IMP_SENS_CTRL_38:
+	case RT5682_HP_IMP_SENS_CTRL_39:
+	case RT5682_HP_IMP_SENS_CTRL_40:
+	case RT5682_HP_IMP_SENS_CTRL_41:
+	case RT5682_HP_IMP_SENS_CTRL_42:
+	case RT5682_HP_IMP_SENS_CTRL_43:
+	case RT5682_HP_LOGIC_CTRL_1:
+	case RT5682_HP_LOGIC_CTRL_2:
+	case RT5682_HP_LOGIC_CTRL_3:
+	case RT5682_HP_CALIB_CTRL_1:
+	case RT5682_HP_CALIB_CTRL_2:
+	case RT5682_HP_CALIB_CTRL_3:
+	case RT5682_HP_CALIB_CTRL_4:
+	case RT5682_HP_CALIB_CTRL_5:
+	case RT5682_HP_CALIB_CTRL_6:
+	case RT5682_HP_CALIB_CTRL_7:
+	case RT5682_HP_CALIB_CTRL_9:
+	case RT5682_HP_CALIB_CTRL_10:
+	case RT5682_HP_CALIB_CTRL_11:
+	case RT5682_HP_CALIB_STA_1:
+	case RT5682_HP_CALIB_STA_2:
+	case RT5682_HP_CALIB_STA_3:
+	case RT5682_HP_CALIB_STA_4:
+	case RT5682_HP_CALIB_STA_5:
+	case RT5682_HP_CALIB_STA_6:
+	case RT5682_HP_CALIB_STA_7:
+	case RT5682_HP_CALIB_STA_8:
+	case RT5682_HP_CALIB_STA_9:
+	case RT5682_HP_CALIB_STA_10:
+	case RT5682_HP_CALIB_STA_11:
+	case RT5682_SAR_IL_CMD_1:
+	case RT5682_SAR_IL_CMD_2:
+	case RT5682_SAR_IL_CMD_3:
+	case RT5682_SAR_IL_CMD_4:
+	case RT5682_SAR_IL_CMD_5:
+	case RT5682_SAR_IL_CMD_6:
+	case RT5682_SAR_IL_CMD_7:
+	case RT5682_SAR_IL_CMD_8:
+	case RT5682_SAR_IL_CMD_9:
+	case RT5682_SAR_IL_CMD_10:
+	case RT5682_SAR_IL_CMD_11:
+	case RT5682_SAR_IL_CMD_12:
+	case RT5682_SAR_IL_CMD_13:
+	case RT5682_EFUSE_CTRL_1:
+	case RT5682_EFUSE_CTRL_2:
+	case RT5682_EFUSE_CTRL_3:
+	case RT5682_EFUSE_CTRL_4:
+	case RT5682_EFUSE_CTRL_5:
+	case RT5682_EFUSE_CTRL_6:
+	case RT5682_EFUSE_CTRL_7:
+	case RT5682_EFUSE_CTRL_8:
+	case RT5682_EFUSE_CTRL_9:
+	case RT5682_EFUSE_CTRL_10:
+	case RT5682_EFUSE_CTRL_11:
+	case RT5682_JD_TOP_VC_VTRL:
+	case RT5682_DRC1_CTRL_0:
+	case RT5682_DRC1_CTRL_1:
+	case RT5682_DRC1_CTRL_2:
+	case RT5682_DRC1_CTRL_3:
+	case RT5682_DRC1_CTRL_4:
+	case RT5682_DRC1_CTRL_5:
+	case RT5682_DRC1_CTRL_6:
+	case RT5682_DRC1_HARD_LMT_CTRL_1:
+	case RT5682_DRC1_HARD_LMT_CTRL_2:
+	case RT5682_DRC1_PRIV_1:
+	case RT5682_DRC1_PRIV_2:
+	case RT5682_DRC1_PRIV_3:
+	case RT5682_DRC1_PRIV_4:
+	case RT5682_DRC1_PRIV_5:
+	case RT5682_DRC1_PRIV_6:
+	case RT5682_DRC1_PRIV_7:
+	case RT5682_DRC1_PRIV_8:
+	case RT5682_EQ_AUTO_RCV_CTRL1:
+	case RT5682_EQ_AUTO_RCV_CTRL2:
+	case RT5682_EQ_AUTO_RCV_CTRL3:
+	case RT5682_EQ_AUTO_RCV_CTRL4:
+	case RT5682_EQ_AUTO_RCV_CTRL5:
+	case RT5682_EQ_AUTO_RCV_CTRL6:
+	case RT5682_EQ_AUTO_RCV_CTRL7:
+	case RT5682_EQ_AUTO_RCV_CTRL8:
+	case RT5682_EQ_AUTO_RCV_CTRL9:
+	case RT5682_EQ_AUTO_RCV_CTRL10:
+	case RT5682_EQ_AUTO_RCV_CTRL11:
+	case RT5682_EQ_AUTO_RCV_CTRL12:
+	case RT5682_EQ_AUTO_RCV_CTRL13:
+	case RT5682_ADC_L_EQ_LPF1_A1:
+	case RT5682_R_EQ_LPF1_A1:
+	case RT5682_L_EQ_LPF1_H0:
+	case RT5682_R_EQ_LPF1_H0:
+	case RT5682_L_EQ_BPF1_A1:
+	case RT5682_R_EQ_BPF1_A1:
+	case RT5682_L_EQ_BPF1_A2:
+	case RT5682_R_EQ_BPF1_A2:
+	case RT5682_L_EQ_BPF1_H0:
+	case RT5682_R_EQ_BPF1_H0:
+	case RT5682_L_EQ_BPF2_A1:
+	case RT5682_R_EQ_BPF2_A1:
+	case RT5682_L_EQ_BPF2_A2:
+	case RT5682_R_EQ_BPF2_A2:
+	case RT5682_L_EQ_BPF2_H0:
+	case RT5682_R_EQ_BPF2_H0:
+	case RT5682_L_EQ_BPF3_A1:
+	case RT5682_R_EQ_BPF3_A1:
+	case RT5682_L_EQ_BPF3_A2:
+	case RT5682_R_EQ_BPF3_A2:
+	case RT5682_L_EQ_BPF3_H0:
+	case RT5682_R_EQ_BPF3_H0:
+	case RT5682_L_EQ_BPF4_A1:
+	case RT5682_R_EQ_BPF4_A1:
+	case RT5682_L_EQ_BPF4_A2:
+	case RT5682_R_EQ_BPF4_A2:
+	case RT5682_L_EQ_BPF4_H0:
+	case RT5682_R_EQ_BPF4_H0:
+	case RT5682_L_EQ_HPF1_A1:
+	case RT5682_R_EQ_HPF1_A1:
+	case RT5682_L_EQ_HPF1_H0:
+	case RT5682_R_EQ_HPF1_H0:
+	case RT5682_L_EQ_PRE_VOL:
+	case RT5682_R_EQ_PRE_VOL:
+	case RT5682_L_EQ_POST_VOL:
+	case RT5682_R_EQ_POST_VOL:
+	case RT5682_I2C_MODE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+	6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+	7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+	8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+/* Interface data select */
+static const char * const rt5682_data_select[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if2_adc_enum,
+	RT5682_DIG_INF2_DATA, RT5682_IF2_ADC_SEL_SFT, rt5682_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if1_01_adc_enum,
+	RT5682_TDM_ADDA_CTRL_1, RT5682_IF1_ADC1_SEL_SFT, rt5682_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if1_23_adc_enum,
+	RT5682_TDM_ADDA_CTRL_1, RT5682_IF1_ADC2_SEL_SFT, rt5682_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if1_45_adc_enum,
+	RT5682_TDM_ADDA_CTRL_1, RT5682_IF1_ADC3_SEL_SFT, rt5682_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if1_67_adc_enum,
+	RT5682_TDM_ADDA_CTRL_1, RT5682_IF1_ADC4_SEL_SFT, rt5682_data_select);
+
+static const struct snd_kcontrol_new rt5682_if2_adc_swap_mux =
+	SOC_DAPM_ENUM("IF2 ADC Swap Mux", rt5682_if2_adc_enum);
+
+static const struct snd_kcontrol_new rt5682_if1_01_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 01 ADC Swap Mux", rt5682_if1_01_adc_enum);
+
+static const struct snd_kcontrol_new rt5682_if1_23_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 23 ADC Swap Mux", rt5682_if1_23_adc_enum);
+
+static const struct snd_kcontrol_new rt5682_if1_45_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 45 ADC Swap Mux", rt5682_if1_45_adc_enum);
+
+static const struct snd_kcontrol_new rt5682_if1_67_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 67 ADC Swap Mux", rt5682_if1_67_adc_enum);
+
+static void rt5682_reset(struct regmap *regmap)
+{
+	regmap_write(regmap, RT5682_RESET, 0);
+	regmap_write(regmap, RT5682_I2C_MODE, 1);
+}
+/**
+ * rt5682_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @component: SoC audio component device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5682 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the component driver will turn on
+ * ASRC for these filters if ASRC is selected as their clock source.
+ */
+int rt5682_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src)
+{
+
+	switch (clk_src) {
+	case RT5682_CLK_SEL_SYS:
+	case RT5682_CLK_SEL_I2S1_ASRC:
+	case RT5682_CLK_SEL_I2S2_ASRC:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (filter_mask & RT5682_DA_STEREO1_FILTER) {
+		snd_soc_component_update_bits(component, RT5682_PLL_TRACK_2,
+			RT5682_FILTER_CLK_SEL_MASK,
+			clk_src << RT5682_FILTER_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5682_AD_STEREO1_FILTER) {
+		snd_soc_component_update_bits(component, RT5682_PLL_TRACK_3,
+			RT5682_FILTER_CLK_SEL_MASK,
+			clk_src << RT5682_FILTER_CLK_SEL_SFT);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5682_sel_asrc_clk_src);
+
+static int rt5682_button_detect(struct snd_soc_component *component)
+{
+	int btn_type, val;
+
+	val = snd_soc_component_read32(component, RT5682_4BTN_IL_CMD_1);
+	btn_type = val & 0xfff0;
+	snd_soc_component_write(component, RT5682_4BTN_IL_CMD_1, val);
+	pr_debug("%s btn_type=%x\n", __func__, btn_type);
+	snd_soc_component_update_bits(component,
+		RT5682_SAR_IL_CMD_2, 0x10, 0x10);
+
+	return btn_type;
+}
+
+static void rt5682_enable_push_button_irq(struct snd_soc_component *component,
+		bool enable)
+{
+	if (enable) {
+		snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+			RT5682_SAR_BUTT_DET_MASK, RT5682_SAR_BUTT_DET_EN);
+		snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_13,
+			RT5682_SAR_SOUR_MASK, RT5682_SAR_SOUR_BTN);
+		snd_soc_component_write(component, RT5682_IL_CMD_1, 0x0040);
+		snd_soc_component_update_bits(component, RT5682_4BTN_IL_CMD_2,
+			RT5682_4BTN_IL_MASK | RT5682_4BTN_IL_RST_MASK,
+			RT5682_4BTN_IL_EN | RT5682_4BTN_IL_NOR);
+		snd_soc_component_update_bits(component, RT5682_IRQ_CTRL_3,
+			RT5682_IL_IRQ_MASK, RT5682_IL_IRQ_EN);
+	} else {
+		snd_soc_component_update_bits(component, RT5682_IRQ_CTRL_3,
+			RT5682_IL_IRQ_MASK, RT5682_IL_IRQ_DIS);
+		snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+			RT5682_SAR_BUTT_DET_MASK, RT5682_SAR_BUTT_DET_DIS);
+		snd_soc_component_update_bits(component, RT5682_4BTN_IL_CMD_2,
+			RT5682_4BTN_IL_MASK, RT5682_4BTN_IL_DIS);
+		snd_soc_component_update_bits(component, RT5682_4BTN_IL_CMD_2,
+			RT5682_4BTN_IL_RST_MASK, RT5682_4BTN_IL_RST);
+		snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_13,
+			RT5682_SAR_SOUR_MASK, RT5682_SAR_SOUR_TYPE);
+	}
+}
+
+/**
+ * rt5682_headset_detect - Detect headset.
+ * @component: SoC audio component device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+static int rt5682_headset_detect(struct snd_soc_component *component,
+		int jack_insert)
+{
+	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm =
+		snd_soc_component_get_dapm(component);
+	unsigned int val, count;
+
+	if (jack_insert) {
+		snd_soc_dapm_force_enable_pin(dapm, "CBJ Power");
+		snd_soc_dapm_sync(dapm);
+		snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+			RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_HIGH);
+
+		count = 0;
+		val = snd_soc_component_read32(component, RT5682_CBJ_CTRL_2)
+			& RT5682_JACK_TYPE_MASK;
+		while (val == 0 && count < 50) {
+			usleep_range(10000, 15000);
+			val = snd_soc_component_read32(component,
+				RT5682_CBJ_CTRL_2) & RT5682_JACK_TYPE_MASK;
+			count++;
+		}
+
+		switch (val) {
+		case 0x1:
+		case 0x2:
+			rt5682->jack_type = SND_JACK_HEADSET;
+			rt5682_enable_push_button_irq(component, true);
+			break;
+		default:
+			rt5682->jack_type = SND_JACK_HEADPHONE;
+		}
+
+	} else {
+		rt5682_enable_push_button_irq(component, false);
+		snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+			RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_LOW);
+		snd_soc_dapm_disable_pin(dapm, "CBJ Power");
+		snd_soc_dapm_sync(dapm);
+
+		rt5682->jack_type = 0;
+	}
+
+	dev_dbg(component->dev, "jack_type = %d\n", rt5682->jack_type);
+	return rt5682->jack_type;
+}
+
+static irqreturn_t rt5682_irq(int irq, void *data)
+{
+	struct rt5682_priv *rt5682 = data;
+
+	mod_delayed_work(system_power_efficient_wq,
+			&rt5682->jack_detect_work, msecs_to_jiffies(250));
+
+	return IRQ_HANDLED;
+}
+
+static void rt5682_jd_check_handler(struct work_struct *work)
+{
+	struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv,
+		jd_check_work.work);
+
+	if (snd_soc_component_read32(rt5682->component, RT5682_AJD1_CTRL)
+		& RT5682_JDH_RS_MASK) {
+		/* jack out */
+		rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
+
+		snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
+				SND_JACK_HEADSET |
+				SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				SND_JACK_BTN_2 | SND_JACK_BTN_3);
+	} else {
+		schedule_delayed_work(&rt5682->jd_check_work, 500);
+	}
+}
+
+static int rt5682_set_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *hs_jack, void *data)
+{
+	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+	switch (rt5682->pdata.jd_src) {
+	case RT5682_JD1:
+		snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_2,
+			RT5682_EXT_JD_SRC, RT5682_EXT_JD_SRC_MANUAL);
+		snd_soc_component_write(component, RT5682_CBJ_CTRL_1, 0xd042);
+		snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_3,
+			RT5682_CBJ_IN_BUF_EN, RT5682_CBJ_IN_BUF_EN);
+		snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+			RT5682_SAR_POW_MASK, RT5682_SAR_POW_EN);
+		regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+			RT5682_GP1_PIN_MASK, RT5682_GP1_PIN_IRQ);
+		regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL,
+				RT5682_POW_IRQ | RT5682_POW_JDH |
+				RT5682_POW_ANA, RT5682_POW_IRQ |
+				RT5682_POW_JDH | RT5682_POW_ANA);
+		regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_2,
+			RT5682_PWR_JDH | RT5682_PWR_JDL,
+			RT5682_PWR_JDH | RT5682_PWR_JDL);
+		regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
+			RT5682_JD1_EN_MASK | RT5682_JD1_POL_MASK,
+			RT5682_JD1_EN | RT5682_JD1_POL_NOR);
+		mod_delayed_work(system_power_efficient_wq,
+			   &rt5682->jack_detect_work, msecs_to_jiffies(250));
+		break;
+
+	case RT5682_JD_NULL:
+		regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
+			RT5682_JD1_EN_MASK, RT5682_JD1_DIS);
+		regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL,
+				RT5682_POW_JDH | RT5682_POW_JDL, 0);
+		break;
+
+	default:
+		dev_warn(component->dev, "Wrong JD source\n");
+		break;
+	}
+
+	rt5682->hs_jack = hs_jack;
+
+	return 0;
+}
+
+static void rt5682_jack_detect_handler(struct work_struct *work)
+{
+	struct rt5682_priv *rt5682 =
+		container_of(work, struct rt5682_priv, jack_detect_work.work);
+	int val, btn_type;
+
+	while (!rt5682->component)
+		usleep_range(10000, 15000);
+
+	while (!rt5682->component->card->instantiated)
+		usleep_range(10000, 15000);
+
+	mutex_lock(&rt5682->calibrate_mutex);
+
+	val = snd_soc_component_read32(rt5682->component, RT5682_AJD1_CTRL)
+		& RT5682_JDH_RS_MASK;
+	if (!val) {
+		/* jack in */
+		if (rt5682->jack_type == 0) {
+			/* jack was out, report jack type */
+			rt5682->jack_type =
+				rt5682_headset_detect(rt5682->component, 1);
+		} else {
+			/* jack is already in, report button event */
+			rt5682->jack_type = SND_JACK_HEADSET;
+			btn_type = rt5682_button_detect(rt5682->component);
+			/**
+			 * rt5682 can report three kinds of button behavior,
+			 * one click, double click and hold. However,
+			 * currently we will report button pressed/released
+			 * event. So all the three button behaviors are
+			 * treated as button pressed.
+			 */
+			switch (btn_type) {
+			case 0x8000:
+			case 0x4000:
+			case 0x2000:
+				rt5682->jack_type |= SND_JACK_BTN_0;
+				break;
+			case 0x1000:
+			case 0x0800:
+			case 0x0400:
+				rt5682->jack_type |= SND_JACK_BTN_1;
+				break;
+			case 0x0200:
+			case 0x0100:
+			case 0x0080:
+				rt5682->jack_type |= SND_JACK_BTN_2;
+				break;
+			case 0x0040:
+			case 0x0020:
+			case 0x0010:
+				rt5682->jack_type |= SND_JACK_BTN_3;
+				break;
+			case 0x0000: /* unpressed */
+				break;
+			default:
+				btn_type = 0;
+				dev_err(rt5682->component->dev,
+					"Unexpected button code 0x%04x\n",
+					btn_type);
+				break;
+			}
+		}
+	} else {
+		/* jack out */
+		rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
+	}
+
+	snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
+			SND_JACK_HEADSET |
+			    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+			    SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+	if (rt5682->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+		SND_JACK_BTN_2 | SND_JACK_BTN_3))
+		schedule_delayed_work(&rt5682->jd_check_work, 0);
+	else
+		cancel_delayed_work_sync(&rt5682->jd_check_work);
+
+	mutex_unlock(&rt5682->calibrate_mutex);
+}
+
+static const struct snd_kcontrol_new rt5682_snd_controls[] = {
+	/* Headphone Output Volume */
+	SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5682_HPL_GAIN,
+		RT5682_HPR_GAIN, RT5682_G_HP_SFT, 15, 1, hp_vol_tlv),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5682_DAC1_DIG_VOL,
+		RT5682_L_VOL_SFT + 1, RT5682_R_VOL_SFT + 1, 86, 0, dac_vol_tlv),
+
+	/* IN Boost Volume */
+	SOC_SINGLE_TLV("CBJ Boost Volume", RT5682_CBJ_BST_CTRL,
+		RT5682_BST_CBJ_SFT, 8, 0, bst_tlv),
+
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("STO1 ADC Capture Switch", RT5682_STO1_ADC_DIG_VOL,
+		RT5682_L_MUTE_SFT, RT5682_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5682_STO1_ADC_DIG_VOL,
+		RT5682_L_VOL_SFT + 1, RT5682_R_VOL_SFT + 1, 63, 0, adc_vol_tlv),
+
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5682_STO1_ADC_BOOST,
+		RT5682_STO1_ADC_L_BST_SFT, RT5682_STO1_ADC_R_BST_SFT,
+		3, 0, adc_bst_tlv),
+};
+
+
+static int rt5682_div_sel(struct rt5682_priv *rt5682,
+			  int target, const int div[], int size)
+{
+	int i;
+
+	if (rt5682->sysclk < target) {
+		pr_err("sysclk rate %d is too low\n",
+			rt5682->sysclk);
+		return 0;
+	}
+
+	for (i = 0; i < size - 1; i++) {
+		pr_info("div[%d]=%d\n", i, div[i]);
+		if (target * div[i] == rt5682->sysclk)
+			return i;
+		if (target * div[i + 1] > rt5682->sysclk) {
+			pr_err("can't find div for sysclk %d\n",
+				rt5682->sysclk);
+			return i;
+		}
+	}
+
+	if (target * div[i] < rt5682->sysclk)
+		pr_err("sysclk rate %d is too high\n",
+			rt5682->sysclk);
+
+	return size - 1;
+
+}
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+	int idx = -EINVAL;
+	static const int div[] = {2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128};
+
+	idx = rt5682_div_sel(rt5682, 1500000, div, ARRAY_SIZE(div));
+
+	snd_soc_component_update_bits(component, RT5682_DMIC_CTRL_1,
+		RT5682_DMIC_CLK_MASK, idx << RT5682_DMIC_CLK_SFT);
+
+	return 0;
+}
+
+static int set_filter_clk(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+	int ref, val, reg, sft, mask, idx = -EINVAL;
+	static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48};
+	static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48};
+
+	val = snd_soc_component_read32(component, RT5682_GPIO_CTRL_1) &
+		RT5682_GP4_PIN_MASK;
+	if (w->shift == RT5682_PWR_ADC_S1F_BIT &&
+		val == RT5682_GP4_PIN_ADCDAT2)
+		ref = 256 * rt5682->lrck[RT5682_AIF2];
+	else
+		ref = 256 * rt5682->lrck[RT5682_AIF1];
+
+	idx = rt5682_div_sel(rt5682, ref, div_f, ARRAY_SIZE(div_f));
+
+	if (w->shift == RT5682_PWR_ADC_S1F_BIT) {
+		reg = RT5682_PLL_TRACK_3;
+		sft = RT5682_ADC_OSR_SFT;
+		mask = RT5682_ADC_OSR_MASK;
+	} else {
+		reg = RT5682_PLL_TRACK_2;
+		sft = RT5682_DAC_OSR_SFT;
+		mask = RT5682_DAC_OSR_MASK;
+	}
+
+	snd_soc_component_update_bits(component, reg,
+		RT5682_FILTER_CLK_DIV_MASK, idx << RT5682_FILTER_CLK_DIV_SFT);
+
+	/* select over sample rate */
+	for (idx = 0; idx < ARRAY_SIZE(div_o); idx++) {
+		if (rt5682->sysclk <= 12288000 * div_o[idx])
+			break;
+	}
+
+	snd_soc_component_update_bits(component, RT5682_ADDA_CLK_1,
+		mask, idx << sft);
+
+	return 0;
+}
+
+static int is_sys_clk_from_pll1(struct snd_soc_dapm_widget *w,
+			 struct snd_soc_dapm_widget *sink)
+{
+	unsigned int val;
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+
+	val = snd_soc_component_read32(component, RT5682_GLB_CLK);
+	val &= RT5682_SCLK_SRC_MASK;
+	if (val == RT5682_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int is_using_asrc(struct snd_soc_dapm_widget *w,
+			 struct snd_soc_dapm_widget *sink)
+{
+	unsigned int reg, shift, val;
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+
+	switch (w->shift) {
+	case RT5682_ADC_STO1_ASRC_SFT:
+		reg = RT5682_PLL_TRACK_3;
+		shift = RT5682_FILTER_CLK_SEL_SFT;
+		break;
+	case RT5682_DAC_STO1_ASRC_SFT:
+		reg = RT5682_PLL_TRACK_2;
+		shift = RT5682_FILTER_CLK_SEL_SFT;
+		break;
+	default:
+		return 0;
+	}
+
+	val = (snd_soc_component_read32(component, reg) >> shift) & 0xf;
+	switch (val) {
+	case RT5682_CLK_SEL_I2S1_ASRC:
+	case RT5682_CLK_SEL_I2S2_ASRC:
+		return 1;
+	default:
+		return 0;
+	}
+
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5682_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5682_STO1_ADC_MIXER,
+			RT5682_M_STO1_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5682_STO1_ADC_MIXER,
+			RT5682_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5682_STO1_ADC_MIXER,
+			RT5682_M_STO1_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5682_STO1_ADC_MIXER,
+			RT5682_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5682_AD_DA_MIXER,
+			RT5682_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5682_AD_DA_MIXER,
+			RT5682_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5682_AD_DA_MIXER,
+			RT5682_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5682_AD_DA_MIXER,
+			RT5682_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_sto1_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5682_STO1_DAC_MIXER,
+			RT5682_M_DAC_L1_STO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5682_STO1_DAC_MIXER,
+			RT5682_M_DAC_R1_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_sto1_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5682_STO1_DAC_MIXER,
+			RT5682_M_DAC_L1_STO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5682_STO1_DAC_MIXER,
+			RT5682_M_DAC_R1_STO_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5682_rec1_l_mix[] = {
+	SOC_DAPM_SINGLE("CBJ Switch", RT5682_REC_MIXER,
+			RT5682_M_CBJ_RM1_L_SFT, 1, 1),
+};
+
+/* STO1 ADC1 Source */
+/* MX-26 [13] [5] */
+static const char * const rt5682_sto1_adc1_src[] = {
+	"DAC MIX", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5682_sto1_adc1l_enum, RT5682_STO1_ADC_MIXER,
+	RT5682_STO1_ADC1L_SRC_SFT, rt5682_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adc1l_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5682_sto1_adc1l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5682_sto1_adc1r_enum, RT5682_STO1_ADC_MIXER,
+	RT5682_STO1_ADC1R_SRC_SFT, rt5682_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adc1r_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5682_sto1_adc1r_enum);
+
+/* STO1 ADC Source */
+/* MX-26 [11:10] [3:2] */
+static const char * const rt5682_sto1_adc_src[] = {
+	"ADC1 L", "ADC1 R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5682_sto1_adcl_enum, RT5682_STO1_ADC_MIXER,
+	RT5682_STO1_ADCL_SRC_SFT, rt5682_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adcl_mux =
+	SOC_DAPM_ENUM("Stereo1 ADCL Source", rt5682_sto1_adcl_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5682_sto1_adcr_enum, RT5682_STO1_ADC_MIXER,
+	RT5682_STO1_ADCR_SRC_SFT, rt5682_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adcr_mux =
+	SOC_DAPM_ENUM("Stereo1 ADCR Source", rt5682_sto1_adcr_enum);
+
+/* STO1 ADC2 Source */
+/* MX-26 [12] [4] */
+static const char * const rt5682_sto1_adc2_src[] = {
+	"DAC MIX", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5682_sto1_adc2l_enum, RT5682_STO1_ADC_MIXER,
+	RT5682_STO1_ADC2L_SRC_SFT, rt5682_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adc2l_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC2L Source", rt5682_sto1_adc2l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5682_sto1_adc2r_enum, RT5682_STO1_ADC_MIXER,
+	RT5682_STO1_ADC2R_SRC_SFT, rt5682_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adc2r_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC2R Source", rt5682_sto1_adc2r_enum);
+
+/* MX-79 [6:4] I2S1 ADC data location */
+static const unsigned int rt5682_if1_adc_slot_values[] = {
+	0,
+	2,
+	4,
+	6,
+};
+
+static const char * const rt5682_if1_adc_slot_src[] = {
+	"Slot 0", "Slot 2", "Slot 4", "Slot 6"
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5682_if1_adc_slot_enum,
+	RT5682_TDM_CTRL, RT5682_TDM_ADC_LCA_SFT, RT5682_TDM_ADC_LCA_MASK,
+	rt5682_if1_adc_slot_src, rt5682_if1_adc_slot_values);
+
+static const struct snd_kcontrol_new rt5682_if1_adc_slot_mux =
+	SOC_DAPM_ENUM("IF1 ADC Slot location", rt5682_if1_adc_slot_enum);
+
+/* Analog DAC L1 Source, Analog DAC R1 Source*/
+/* MX-2B [4], MX-2B [0]*/
+static const char * const rt5682_alg_dac1_src[] = {
+	"Stereo1 DAC Mixer", "DAC1"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5682_alg_dac_l1_enum, RT5682_A_DAC1_MUX,
+	RT5682_A_DACL1_SFT, rt5682_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5682_alg_dac_l1_mux =
+	SOC_DAPM_ENUM("Analog DAC L1 Source", rt5682_alg_dac_l1_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5682_alg_dac_r1_enum, RT5682_A_DAC1_MUX,
+	RT5682_A_DACR1_SFT, rt5682_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5682_alg_dac_r1_mux =
+	SOC_DAPM_ENUM("Analog DAC R1 Source", rt5682_alg_dac_r1_enum);
+
+/* Out Switch */
+static const struct snd_kcontrol_new hpol_switch =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1,
+					RT5682_L_MUTE_SFT, 1, 1);
+static const struct snd_kcontrol_new hpor_switch =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1,
+					RT5682_R_MUTE_SFT, 1, 1);
+
+static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_write(component,
+			RT5682_HP_LOGIC_CTRL_2, 0x0012);
+		snd_soc_component_write(component,
+			RT5682_HP_CTRL_2, 0x6000);
+		snd_soc_component_update_bits(component, RT5682_STO_NG2_CTRL_1,
+			RT5682_NG2_EN_MASK, RT5682_NG2_EN);
+		snd_soc_component_update_bits(component,
+			RT5682_DEPOP_1, 0x60, 0x60);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component,
+			RT5682_DEPOP_1, 0x60, 0x0);
+		snd_soc_component_write(component,
+			RT5682_HP_CTRL_2, 0x0000);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+
+}
+
+static int set_dmic_power(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/*Add delay to avoid pop noise*/
+		msleep(150);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5655_set_verf(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		switch (w->shift) {
+		case RT5682_PWR_VREF1_BIT:
+			snd_soc_component_update_bits(component,
+				RT5682_PWR_ANLG_1, RT5682_PWR_FV1, 0);
+			break;
+
+		case RT5682_PWR_VREF2_BIT:
+			snd_soc_component_update_bits(component,
+				RT5682_PWR_ANLG_1, RT5682_PWR_FV2, 0);
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(15000, 20000);
+		switch (w->shift) {
+		case RT5682_PWR_VREF1_BIT:
+			snd_soc_component_update_bits(component,
+				RT5682_PWR_ANLG_1, RT5682_PWR_FV1,
+				RT5682_PWR_FV1);
+			break;
+
+		case RT5682_PWR_VREF2_BIT:
+			snd_soc_component_update_bits(component,
+				RT5682_PWR_ANLG_1, RT5682_PWR_FV2,
+				RT5682_PWR_FV2);
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const unsigned int rt5682_adcdat_pin_values[] = {
+	1,
+	3,
+};
+
+static const char * const rt5682_adcdat_pin_select[] = {
+	"ADCDAT1",
+	"ADCDAT2",
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5682_adcdat_pin_enum,
+	RT5682_GPIO_CTRL_1, RT5682_GP4_PIN_SFT, RT5682_GP4_PIN_MASK,
+	rt5682_adcdat_pin_select, rt5682_adcdat_pin_values);
+
+static const struct snd_kcontrol_new rt5682_adcdat_pin_ctrl =
+	SOC_DAPM_ENUM("ADCDAT", rt5682_adcdat_pin_enum);
+
+static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("LDO2", RT5682_PWR_ANLG_3, RT5682_PWR_LDO2_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL1", RT5682_PWR_ANLG_3, RT5682_PWR_PLL_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL2B", RT5682_PWR_ANLG_3, RT5682_PWR_PLL2B_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL2F", RT5682_PWR_ANLG_3, RT5682_PWR_PLL2F_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Vref1", RT5682_PWR_ANLG_1, RT5682_PWR_VREF1_BIT, 0,
+		rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("Vref2", RT5682_PWR_ANLG_1, RT5682_PWR_VREF2_BIT, 0,
+		rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5682_PLL_TRACK_1,
+		RT5682_DAC_STO1_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5682_PLL_TRACK_1,
+		RT5682_ADC_STO1_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AD ASRC", 1, RT5682_PLL_TRACK_1,
+		RT5682_AD_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DA ASRC", 1, RT5682_PLL_TRACK_1,
+		RT5682_DA_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC ASRC", 1, RT5682_PLL_TRACK_1,
+		RT5682_DMIC_ASRC_SFT, 0, NULL, 0),
+
+	/* Input Side */
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5682_PWR_ANLG_2, RT5682_PWR_MB1_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5682_PWR_ANLG_2, RT5682_PWR_MB2_BIT,
+		0, NULL, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC L1"),
+	SND_SOC_DAPM_INPUT("DMIC R1"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+		set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5682_DMIC_CTRL_1,
+		RT5682_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("CBJ Power", RT5682_PWR_ANLG_3,
+		RT5682_PWR_CBJ_BIT, 0, NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5682_rec1_l_mix,
+		ARRAY_SIZE(rt5682_rec1_l_mix)),
+	SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5682_PWR_ANLG_2,
+		RT5682_PWR_RM1_L_BIT, 0, NULL, 0),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5682_PWR_DIG_1,
+		RT5682_PWR_ADC_L1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5682_PWR_DIG_1,
+		RT5682_PWR_ADC_R1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1 clock", RT5682_CHOP_ADC,
+		RT5682_CKGEN_ADC1_SFT, 0, NULL, 0),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5682_sto1_adc1l_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5682_sto1_adc1r_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5682_sto1_adc2l_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5682_sto1_adc2r_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5682_sto1_adcl_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5682_sto1_adcr_mux),
+	SND_SOC_DAPM_MUX("IF1_ADC Mux", SND_SOC_NOPM, 0, 0,
+		&rt5682_if1_adc_slot_mux),
+
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5682_PWR_DIG_2,
+		RT5682_PWR_ADC_S1F_BIT, 0, set_filter_clk,
+		SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", RT5682_STO1_ADC_DIG_VOL,
+		RT5682_L_MUTE_SFT, 1, rt5682_sto1_adc_l_mix,
+		ARRAY_SIZE(rt5682_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5682_STO1_ADC_DIG_VOL,
+		RT5682_R_MUTE_SFT, 1, rt5682_sto1_adc_r_mix,
+		ARRAY_SIZE(rt5682_sto1_adc_r_mix)),
+	SND_SOC_DAPM_SUPPLY("BTN Detection Mode", RT5682_SAR_IL_CMD_1,
+		14, 1, NULL, 0),
+
+	/* ADC PGA */
+	SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5682_PWR_DIG_1, RT5682_PWR_I2S1_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("I2S2", RT5682_PWR_DIG_1, RT5682_PWR_I2S2_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface Select */
+	SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5682_if1_01_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 23 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5682_if1_23_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 45 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5682_if1_45_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 67 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5682_if1_67_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5682_if2_adc_swap_mux),
+
+	SND_SOC_DAPM_MUX("ADCDAT Mux", SND_SOC_NOPM, 0, 0,
+			&rt5682_adcdat_pin_ctrl),
+
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0,
+		RT5682_I2S1_SDP, RT5682_SEL_ADCDAT_SFT, 1),
+	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0,
+		RT5682_I2S2_SDP, RT5682_I2S2_PIN_CFG_SFT, 1),
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Side */
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
+		rt5682_dac_l_mix, ARRAY_SIZE(rt5682_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+		rt5682_dac_r_mix, ARRAY_SIZE(rt5682_dac_r_mix)),
+
+	/* DAC channel Mux */
+	SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0,
+		&rt5682_alg_dac_l1_mux),
+	SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0,
+		&rt5682_alg_dac_r1_mux),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5682_PWR_DIG_2,
+		RT5682_PWR_DAC_S1F_BIT, 0, set_filter_clk,
+		SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MIXER("Stereo1 DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5682_sto1_dac_l_mix, ARRAY_SIZE(rt5682_sto1_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo1 DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5682_sto1_dac_r_mix, ARRAY_SIZE(rt5682_sto1_dac_r_mix)),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC L1", NULL, RT5682_PWR_DIG_1,
+		RT5682_PWR_DAC_L1_BIT, 0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, RT5682_PWR_DIG_1,
+		RT5682_PWR_DAC_R1_BIT, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC 1 Clock", 3, RT5682_CHOP_DAC,
+		RT5682_CKGEN_DAC1_SFT, 0, NULL, 0),
+
+	/* HPO */
+	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5682_hp_event,
+		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
+
+	SND_SOC_DAPM_SUPPLY("HP Amp L", RT5682_PWR_ANLG_1,
+		RT5682_PWR_HA_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HP Amp R", RT5682_PWR_ANLG_1,
+		RT5682_PWR_HA_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, RT5682_DEPOP_1,
+		RT5682_PUMP_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("Capless", 2, RT5682_DEPOP_1,
+		RT5682_CAPLESS_EN_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH("HPOL Playback", SND_SOC_NOPM, 0, 0,
+		&hpol_switch),
+	SND_SOC_DAPM_SWITCH("HPOR Playback", SND_SOC_NOPM, 0, 0,
+		&hpor_switch),
+
+	/* CLK DET */
+	SND_SOC_DAPM_SUPPLY("CLKDET SYS", RT5682_CLK_DET,
+		RT5682_SYS_CLK_DET_SFT,	0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET PLL1", RT5682_CLK_DET,
+		RT5682_PLL1_CLK_DET_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET PLL2", RT5682_CLK_DET,
+		RT5682_PLL2_CLK_DET_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET", RT5682_CLK_DET,
+		RT5682_POW_CLK_DET_SFT, 0, NULL, 0),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+
+};
+
+static const struct snd_soc_dapm_route rt5682_dapm_routes[] = {
+	/*PLL*/
+	{"ADC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll1},
+	{"DAC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll1},
+
+	/*ASRC*/
+	{"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc},
+	{"DAC Stereo1 Filter", NULL, "DAC STO1 ASRC", is_using_asrc},
+	{"ADC STO1 ASRC", NULL, "AD ASRC"},
+	{"ADC STO1 ASRC", NULL, "CLKDET"},
+	{"DAC STO1 ASRC", NULL, "DA ASRC"},
+	{"DAC STO1 ASRC", NULL, "CLKDET"},
+
+	/*Vref*/
+	{"MICBIAS1", NULL, "Vref1"},
+	{"MICBIAS1", NULL, "Vref2"},
+	{"MICBIAS2", NULL, "Vref1"},
+	{"MICBIAS2", NULL, "Vref2"},
+
+	{"CLKDET SYS", NULL, "CLKDET"},
+
+	{"IN1P", NULL, "LDO2"},
+
+	{"BST1 CBJ", NULL, "IN1P"},
+	{"BST1 CBJ", NULL, "CBJ Power"},
+	{"CBJ Power", NULL, "Vref2"},
+
+	{"RECMIX1L", "CBJ Switch", "BST1 CBJ"},
+	{"RECMIX1L", NULL, "RECMIX1L Power"},
+
+	{"ADC1 L", NULL, "RECMIX1L"},
+	{"ADC1 L", NULL, "ADC1 L Power"},
+	{"ADC1 L", NULL, "ADC1 clock"},
+
+	{"DMIC L1", NULL, "DMIC CLK"},
+	{"DMIC L1", NULL, "DMIC1 Power"},
+	{"DMIC R1", NULL, "DMIC CLK"},
+	{"DMIC R1", NULL, "DMIC1 Power"},
+	{"DMIC CLK", NULL, "DMIC ASRC"},
+
+	{"Stereo1 ADC L Mux", "ADC1 L", "ADC1 L"},
+	{"Stereo1 ADC L Mux", "ADC1 R", "ADC1 R"},
+	{"Stereo1 ADC R Mux", "ADC1 L", "ADC1 L"},
+	{"Stereo1 ADC R Mux", "ADC1 R", "ADC1 R"},
+
+	{"Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux"},
+	{"Stereo1 ADC L1 Mux", "DAC MIX", "Stereo1 DAC MIXL"},
+	{"Stereo1 ADC L2 Mux", "DMIC", "DMIC L1"},
+	{"Stereo1 ADC L2 Mux", "DAC MIX", "Stereo1 DAC MIXL"},
+
+	{"Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux"},
+	{"Stereo1 ADC R1 Mux", "DAC MIX", "Stereo1 DAC MIXR"},
+	{"Stereo1 ADC R2 Mux", "DMIC", "DMIC R1"},
+	{"Stereo1 ADC R2 Mux", "DAC MIX", "Stereo1 DAC MIXR"},
+
+	{"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"},
+	{"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"},
+	{"Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter"},
+
+	{"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"},
+	{"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"},
+	{"Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter"},
+
+	{"ADC Stereo1 Filter", NULL, "BTN Detection Mode"},
+
+	{"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL"},
+	{"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR"},
+
+	{"IF1 01 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF1 01 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF1 01 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF1 01 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+	{"IF1 23 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF1 23 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF1 23 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF1 23 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+	{"IF1 45 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF1 45 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF1 45 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF1 45 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+	{"IF1 67 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF1 67 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF1 67 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF1 67 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+
+	{"IF1_ADC Mux", "Slot 0", "IF1 01 ADC Swap Mux"},
+	{"IF1_ADC Mux", "Slot 2", "IF1 23 ADC Swap Mux"},
+	{"IF1_ADC Mux", "Slot 4", "IF1 45 ADC Swap Mux"},
+	{"IF1_ADC Mux", "Slot 6", "IF1 67 ADC Swap Mux"},
+	{"IF1_ADC Mux", NULL, "I2S1"},
+	{"ADCDAT Mux", "ADCDAT1", "IF1_ADC Mux"},
+	{"AIF1TX", NULL, "ADCDAT Mux"},
+	{"IF2 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+	{"IF2 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+	{"IF2 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+	{"IF2 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+	{"ADCDAT Mux", "ADCDAT2", "IF2 ADC Swap Mux"},
+	{"AIF2TX", NULL, "ADCDAT Mux"},
+
+	{"IF1 DAC1 L", NULL, "AIF1RX"},
+	{"IF1 DAC1 L", NULL, "I2S1"},
+	{"IF1 DAC1 L", NULL, "DAC Stereo1 Filter"},
+	{"IF1 DAC1 R", NULL, "AIF1RX"},
+	{"IF1 DAC1 R", NULL, "I2S1"},
+	{"IF1 DAC1 R", NULL, "DAC Stereo1 Filter"},
+
+	{"DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"},
+	{"DAC1 MIXL", "DAC1 Switch", "IF1 DAC1 L"},
+	{"DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"},
+	{"DAC1 MIXR", "DAC1 Switch", "IF1 DAC1 R"},
+
+	{"Stereo1 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"},
+	{"Stereo1 DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"},
+
+	{"Stereo1 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"},
+	{"Stereo1 DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"},
+
+	{"DAC L1 Source", "DAC1", "DAC1 MIXL"},
+	{"DAC L1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"},
+	{"DAC R1 Source", "DAC1", "DAC1 MIXR"},
+	{"DAC R1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"},
+
+	{"DAC L1", NULL, "DAC L1 Source"},
+	{"DAC R1", NULL, "DAC R1 Source"},
+
+	{"DAC L1", NULL, "DAC 1 Clock"},
+	{"DAC R1", NULL, "DAC 1 Clock"},
+
+	{"HP Amp", NULL, "DAC L1"},
+	{"HP Amp", NULL, "DAC R1"},
+	{"HP Amp", NULL, "HP Amp L"},
+	{"HP Amp", NULL, "HP Amp R"},
+	{"HP Amp", NULL, "Capless"},
+	{"HP Amp", NULL, "Charge Pump"},
+	{"HP Amp", NULL, "CLKDET SYS"},
+	{"HP Amp", NULL, "CBJ Power"},
+	{"HP Amp", NULL, "Vref2"},
+	{"HPOL Playback", "Switch", "HP Amp"},
+	{"HPOR Playback", "Switch", "HP Amp"},
+	{"HPOL", NULL, "HPOL Playback"},
+	{"HPOR", NULL, "HPOR Playback"},
+};
+
+static int rt5682_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int cl, val = 0;
+
+	if (tx_mask || rx_mask)
+		snd_soc_component_update_bits(component, RT5682_TDM_ADDA_CTRL_2,
+			RT5682_TDM_EN, RT5682_TDM_EN);
+	else
+		snd_soc_component_update_bits(component, RT5682_TDM_ADDA_CTRL_2,
+			RT5682_TDM_EN, 0);
+
+	switch (slots) {
+	case 4:
+		val |= RT5682_TDM_TX_CH_4;
+		val |= RT5682_TDM_RX_CH_4;
+		break;
+	case 6:
+		val |= RT5682_TDM_TX_CH_6;
+		val |= RT5682_TDM_RX_CH_6;
+		break;
+	case 8:
+		val |= RT5682_TDM_TX_CH_8;
+		val |= RT5682_TDM_RX_CH_8;
+		break;
+	case 2:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5682_TDM_CTRL,
+		RT5682_TDM_TX_CH_MASK | RT5682_TDM_RX_CH_MASK, val);
+
+	switch (slot_width) {
+	case 8:
+		if (tx_mask || rx_mask)
+			return -EINVAL;
+		cl = RT5682_I2S1_TX_CHL_8 | RT5682_I2S1_RX_CHL_8;
+		break;
+	case 16:
+		val = RT5682_TDM_CL_16;
+		cl = RT5682_I2S1_TX_CHL_16 | RT5682_I2S1_RX_CHL_16;
+		break;
+	case 20:
+		val = RT5682_TDM_CL_20;
+		cl = RT5682_I2S1_TX_CHL_20 | RT5682_I2S1_RX_CHL_20;
+		break;
+	case 24:
+		val = RT5682_TDM_CL_24;
+		cl = RT5682_I2S1_TX_CHL_24 | RT5682_I2S1_RX_CHL_24;
+		break;
+	case 32:
+		val = RT5682_TDM_CL_32;
+		cl = RT5682_I2S1_TX_CHL_32 | RT5682_I2S1_RX_CHL_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, RT5682_TDM_TCON_CTRL,
+		RT5682_TDM_CL_MASK, val);
+	snd_soc_component_update_bits(component, RT5682_I2S1_SDP,
+		RT5682_I2S1_TX_CHL_MASK | RT5682_I2S1_RX_CHL_MASK, cl);
+
+	return 0;
+}
+
+
+static int rt5682_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+	unsigned int len_1 = 0, len_2 = 0;
+	int pre_div, frame_size;
+
+	rt5682->lrck[dai->id] = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5682->sysclk, rt5682->lrck[dai->id]);
+
+	frame_size = snd_soc_params_to_frame_size(params);
+	if (frame_size < 0) {
+		dev_err(component->dev, "Unsupported frame size: %d\n",
+			frame_size);
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+				rt5682->lrck[dai->id], pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		len_1 |= RT5682_I2S1_DL_20;
+		len_2 |= RT5682_I2S2_DL_20;
+		break;
+	case 24:
+		len_1 |= RT5682_I2S1_DL_24;
+		len_2 |= RT5682_I2S2_DL_24;
+		break;
+	case 32:
+		len_1 |= RT5682_I2S1_DL_32;
+		len_2 |= RT5682_I2S2_DL_24;
+		break;
+	case 8:
+		len_1 |= RT5682_I2S2_DL_8;
+		len_2 |= RT5682_I2S2_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5682_AIF1:
+		snd_soc_component_update_bits(component, RT5682_I2S1_SDP,
+			RT5682_I2S1_DL_MASK, len_1);
+		if (rt5682->master[RT5682_AIF1]) {
+			snd_soc_component_update_bits(component,
+				RT5682_ADDA_CLK_1, RT5682_I2S_M_DIV_MASK,
+				pre_div << RT5682_I2S_M_DIV_SFT);
+		}
+		if (params_channels(params) == 1) /* mono mode */
+			snd_soc_component_update_bits(component,
+				RT5682_I2S1_SDP, RT5682_I2S1_MONO_MASK,
+				RT5682_I2S1_MONO_EN);
+		else
+			snd_soc_component_update_bits(component,
+				RT5682_I2S1_SDP, RT5682_I2S1_MONO_MASK,
+				RT5682_I2S1_MONO_DIS);
+		break;
+	case RT5682_AIF2:
+		snd_soc_component_update_bits(component, RT5682_I2S2_SDP,
+			RT5682_I2S2_DL_MASK, len_2);
+		if (rt5682->master[RT5682_AIF2]) {
+			snd_soc_component_update_bits(component,
+				RT5682_I2S_M_CLK_CTRL_1, RT5682_I2S2_M_PD_MASK,
+				pre_div << RT5682_I2S2_M_PD_SFT);
+		}
+		if (params_channels(params) == 1) /* mono mode */
+			snd_soc_component_update_bits(component,
+				RT5682_I2S2_SDP, RT5682_I2S2_MONO_MASK,
+				RT5682_I2S2_MONO_EN);
+		else
+			snd_soc_component_update_bits(component,
+				RT5682_I2S2_SDP, RT5682_I2S2_MONO_MASK,
+				RT5682_I2S2_MONO_DIS);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5682_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0, tdm_ctrl = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5682->master[dai->id] = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		rt5682->master[dai->id] = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg_val |= RT5682_I2S_BP_INV;
+		tdm_ctrl |= RT5682_TDM_S_BP_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		if (dai->id == RT5682_AIF1)
+			tdm_ctrl |= RT5682_TDM_S_LP_INV | RT5682_TDM_M_BP_INV;
+		else
+			return -EINVAL;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		if (dai->id == RT5682_AIF1)
+			tdm_ctrl |= RT5682_TDM_S_BP_INV | RT5682_TDM_S_LP_INV |
+				    RT5682_TDM_M_BP_INV | RT5682_TDM_M_LP_INV;
+		else
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg_val |= RT5682_I2S_DF_LEFT;
+		tdm_ctrl |= RT5682_TDM_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5682_I2S_DF_PCM_A;
+		tdm_ctrl |= RT5682_TDM_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5682_I2S_DF_PCM_B;
+		tdm_ctrl |= RT5682_TDM_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5682_AIF1:
+		snd_soc_component_update_bits(component, RT5682_I2S1_SDP,
+			RT5682_I2S_DF_MASK, reg_val);
+		snd_soc_component_update_bits(component, RT5682_TDM_TCON_CTRL,
+			RT5682_TDM_MS_MASK | RT5682_TDM_S_BP_MASK |
+			RT5682_TDM_DF_MASK | RT5682_TDM_M_BP_MASK |
+			RT5682_TDM_M_LP_MASK | RT5682_TDM_S_LP_MASK,
+			tdm_ctrl | rt5682->master[dai->id]);
+		break;
+	case RT5682_AIF2:
+		if (rt5682->master[dai->id] == 0)
+			reg_val |= RT5682_I2S2_MS_S;
+		snd_soc_component_update_bits(component, RT5682_I2S2_SDP,
+			RT5682_I2S2_MS_MASK | RT5682_I2S_BP_MASK |
+			RT5682_I2S_DF_MASK, reg_val);
+		break;
+	default:
+		dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int rt5682_set_component_sysclk(struct snd_soc_component *component,
+		int clk_id, int source, unsigned int freq, int dir)
+{
+	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+	unsigned int reg_val = 0, src = 0;
+
+	if (freq == rt5682->sysclk && clk_id == rt5682->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5682_SCLK_S_MCLK:
+		reg_val |= RT5682_SCLK_SRC_MCLK;
+		src = RT5682_CLK_SRC_MCLK;
+		break;
+	case RT5682_SCLK_S_PLL1:
+		reg_val |= RT5682_SCLK_SRC_PLL1;
+		src = RT5682_CLK_SRC_PLL1;
+		break;
+	case RT5682_SCLK_S_PLL2:
+		reg_val |= RT5682_SCLK_SRC_PLL2;
+		src = RT5682_CLK_SRC_PLL2;
+		break;
+	case RT5682_SCLK_S_RCCLK:
+		reg_val |= RT5682_SCLK_SRC_RCCLK;
+		src = RT5682_CLK_SRC_RCCLK;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, RT5682_GLB_CLK,
+		RT5682_SCLK_SRC_MASK, reg_val);
+
+	if (rt5682->master[RT5682_AIF2]) {
+		snd_soc_component_update_bits(component,
+			RT5682_I2S_M_CLK_CTRL_1, RT5682_I2S2_SRC_MASK,
+			src << RT5682_I2S2_SRC_SFT);
+	}
+
+	rt5682->sysclk = freq;
+	rt5682->sysclk_src = clk_id;
+
+	dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n",
+		freq, clk_id);
+
+	return 0;
+}
+
+static int rt5682_set_component_pll(struct snd_soc_component *component,
+		int pll_id, int source, unsigned int freq_in,
+		unsigned int freq_out)
+{
+	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5682->pll_src && freq_in == rt5682->pll_in &&
+	    freq_out == rt5682->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(component->dev, "PLL disabled\n");
+
+		rt5682->pll_in = 0;
+		rt5682->pll_out = 0;
+		snd_soc_component_update_bits(component, RT5682_GLB_CLK,
+			RT5682_SCLK_SRC_MASK, RT5682_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5682_PLL1_S_MCLK:
+		snd_soc_component_update_bits(component, RT5682_GLB_CLK,
+			RT5682_PLL1_SRC_MASK, RT5682_PLL1_SRC_MCLK);
+		break;
+	case RT5682_PLL1_S_BCLK1:
+		snd_soc_component_update_bits(component, RT5682_GLB_CLK,
+				RT5682_PLL1_SRC_MASK, RT5682_PLL1_SRC_BCLK1);
+		break;
+	default:
+		dev_err(component->dev, "Unknown PLL Source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+	if (ret < 0) {
+		dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+		pll_code.n_code, pll_code.k_code);
+
+	snd_soc_component_write(component, RT5682_PLL_CTRL_1,
+		pll_code.n_code << RT5682_PLL_N_SFT | pll_code.k_code);
+	snd_soc_component_write(component, RT5682_PLL_CTRL_2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5682_PLL_M_SFT |
+		pll_code.m_bp << RT5682_PLL_M_BP_SFT | RT5682_PLL_RST);
+
+	rt5682->pll_in = freq_in;
+	rt5682->pll_out = freq_out;
+	rt5682->pll_src = source;
+
+	return 0;
+}
+
+static int rt5682_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct snd_soc_component *component = dai->component;
+	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+	rt5682->bclk[dai->id] = ratio;
+
+	switch (ratio) {
+	case 64:
+		snd_soc_component_update_bits(component, RT5682_ADDA_CLK_2,
+			RT5682_I2S2_BCLK_MS2_MASK,
+			RT5682_I2S2_BCLK_MS2_64);
+		break;
+	case 32:
+		snd_soc_component_update_bits(component, RT5682_ADDA_CLK_2,
+			RT5682_I2S2_BCLK_MS2_MASK,
+			RT5682_I2S2_BCLK_MS2_32);
+		break;
+	default:
+		dev_err(dai->dev, "Invalid bclk ratio %d\n", ratio);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt5682_set_bias_level(struct snd_soc_component *component,
+			enum snd_soc_bias_level level)
+{
+	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
+			RT5682_PWR_MB | RT5682_PWR_BG,
+			RT5682_PWR_MB | RT5682_PWR_BG);
+		regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1,
+			RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO,
+			RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
+			RT5682_PWR_MB, RT5682_PWR_MB);
+		regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1,
+			RT5682_DIG_GATE_CTRL, RT5682_DIG_GATE_CTRL);
+		break;
+	case SND_SOC_BIAS_OFF:
+		regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1,
+			RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO, 0);
+		regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
+			RT5682_PWR_MB | RT5682_PWR_BG, 0);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5682_probe(struct snd_soc_component *component)
+{
+	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+	rt5682->component = component;
+
+	return 0;
+}
+
+static void rt5682_remove(struct snd_soc_component *component)
+{
+	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+	rt5682_reset(rt5682->regmap);
+}
+
+#ifdef CONFIG_PM
+static int rt5682_suspend(struct snd_soc_component *component)
+{
+	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5682->regmap, true);
+	regcache_mark_dirty(rt5682->regmap);
+	return 0;
+}
+
+static int rt5682_resume(struct snd_soc_component *component)
+{
+	struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(rt5682->regmap, false);
+	regcache_sync(rt5682->regmap);
+
+	return 0;
+}
+#else
+#define rt5682_suspend NULL
+#define rt5682_resume NULL
+#endif
+
+#define RT5682_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5682_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5682_aif1_dai_ops = {
+	.hw_params = rt5682_hw_params,
+	.set_fmt = rt5682_set_dai_fmt,
+	.set_tdm_slot = rt5682_set_tdm_slot,
+};
+
+static const struct snd_soc_dai_ops rt5682_aif2_dai_ops = {
+	.hw_params = rt5682_hw_params,
+	.set_fmt = rt5682_set_dai_fmt,
+	.set_bclk_ratio = rt5682_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt5682_dai[] = {
+	{
+		.name = "rt5682-aif1",
+		.id = RT5682_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5682_STEREO_RATES,
+			.formats = RT5682_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5682_STEREO_RATES,
+			.formats = RT5682_FORMATS,
+		},
+		.ops = &rt5682_aif1_dai_ops,
+	},
+	{
+		.name = "rt5682-aif2",
+		.id = RT5682_AIF2,
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5682_STEREO_RATES,
+			.formats = RT5682_FORMATS,
+		},
+		.ops = &rt5682_aif2_dai_ops,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5682 = {
+	.probe = rt5682_probe,
+	.remove = rt5682_remove,
+	.suspend = rt5682_suspend,
+	.resume = rt5682_resume,
+	.set_bias_level = rt5682_set_bias_level,
+	.controls = rt5682_snd_controls,
+	.num_controls = ARRAY_SIZE(rt5682_snd_controls),
+	.dapm_widgets = rt5682_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rt5682_dapm_widgets),
+	.dapm_routes = rt5682_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(rt5682_dapm_routes),
+	.set_sysclk = rt5682_set_component_sysclk,
+	.set_pll = rt5682_set_component_pll,
+	.set_jack = rt5682_set_jack_detect,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config rt5682_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+	.max_register = RT5682_I2C_MODE,
+	.volatile_reg = rt5682_volatile_register,
+	.readable_reg = rt5682_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5682_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5682_reg),
+	.use_single_rw = true,
+};
+
+static const struct i2c_device_id rt5682_i2c_id[] = {
+	{"rt5682", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, rt5682_i2c_id);
+
+static int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev)
+{
+
+	device_property_read_u32(dev, "realtek,dmic1-data-pin",
+		&rt5682->pdata.dmic1_data_pin);
+	device_property_read_u32(dev, "realtek,dmic1-clk-pin",
+		&rt5682->pdata.dmic1_clk_pin);
+	device_property_read_u32(dev, "realtek,jd-src",
+		&rt5682->pdata.jd_src);
+
+	rt5682->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
+		"realtek,ldo1-en-gpios", 0);
+
+	return 0;
+}
+
+static void rt5682_calibrate(struct rt5682_priv *rt5682)
+{
+	int value, count;
+
+	mutex_lock(&rt5682->calibrate_mutex);
+
+	rt5682_reset(rt5682->regmap);
+	regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2bf);
+	usleep_range(15000, 20000);
+	regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2bf);
+	regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
+	regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8001);
+	regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
+	regmap_write(rt5682->regmap, RT5682_STO1_DAC_MIXER, 0x2080);
+	regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x4040);
+	regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0069);
+	regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x3000);
+	regmap_write(rt5682->regmap, RT5682_HP_CTRL_2, 0x6000);
+	regmap_write(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1, 0x0f26);
+	regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7f05);
+	regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x686c);
+	regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0d0d);
+	regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_9, 0x000f);
+	regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8d01);
+	regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_2, 0x0321);
+	regmap_write(rt5682->regmap, RT5682_HP_LOGIC_CTRL_2, 0x0004);
+	regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00);
+	regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_3, 0x06a1);
+	regmap_write(rt5682->regmap, RT5682_A_DAC1_MUX, 0x0311);
+	regmap_write(rt5682->regmap, RT5682_RESET_HPF_CTRL, 0x0000);
+	regmap_write(rt5682->regmap, RT5682_ADC_STO1_HP_CTRL_1, 0x3320);
+
+	regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0xfc00);
+
+	for (count = 0; count < 60; count++) {
+		regmap_read(rt5682->regmap, RT5682_HP_CALIB_STA_1, &value);
+		if (!(value & 0x8000))
+			break;
+
+		usleep_range(10000, 10005);
+	}
+
+	if (count >= 60)
+		pr_err("HP Calibration Failure\n");
+
+	/* restore settings */
+	regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4);
+	regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000);
+
+	mutex_unlock(&rt5682->calibrate_mutex);
+
+}
+
+static int rt5682_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5682_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt5682_priv *rt5682;
+	int i, ret;
+	unsigned int val;
+
+	rt5682 = devm_kzalloc(&i2c->dev, sizeof(struct rt5682_priv),
+		GFP_KERNEL);
+
+	if (rt5682 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt5682);
+
+	if (pdata)
+		rt5682->pdata = *pdata;
+	else
+		rt5682_parse_dt(rt5682, &i2c->dev);
+
+	rt5682->regmap = devm_regmap_init_i2c(i2c, &rt5682_regmap);
+	if (IS_ERR(rt5682->regmap)) {
+		ret = PTR_ERR(rt5682->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(rt5682->supplies); i++)
+		rt5682->supplies[i].supply = rt5682_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5682->supplies),
+				      rt5682->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(rt5682->supplies),
+				    rt5682->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	if (gpio_is_valid(rt5682->pdata.ldo1_en)) {
+		if (devm_gpio_request_one(&i2c->dev, rt5682->pdata.ldo1_en,
+					  GPIOF_OUT_INIT_HIGH, "rt5682"))
+			dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+	}
+
+	/* Sleep for 300 ms miniumum */
+	usleep_range(300000, 350000);
+
+	regmap_write(rt5682->regmap, RT5682_I2C_MODE, 0x1);
+	usleep_range(10000, 15000);
+
+	regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
+	if (val != DEVICE_ID) {
+		pr_err("Device with ID register %x is not rt5682\n", val);
+		return -ENODEV;
+	}
+
+	rt5682_reset(rt5682->regmap);
+
+	rt5682_calibrate(rt5682);
+
+	ret = regmap_register_patch(rt5682->regmap, patch_list,
+				    ARRAY_SIZE(patch_list));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0000);
+
+	/* DMIC pin*/
+	if (rt5682->pdata.dmic1_data_pin != RT5682_DMIC1_NULL) {
+		switch (rt5682->pdata.dmic1_data_pin) {
+		case RT5682_DMIC1_DATA_GPIO2: /* share with LRCK2 */
+			regmap_update_bits(rt5682->regmap, RT5682_DMIC_CTRL_1,
+				RT5682_DMIC_1_DP_MASK, RT5682_DMIC_1_DP_GPIO2);
+			regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+				RT5682_GP2_PIN_MASK, RT5682_GP2_PIN_DMIC_SDA);
+			break;
+
+		case RT5682_DMIC1_DATA_GPIO5: /* share with DACDAT1 */
+			regmap_update_bits(rt5682->regmap, RT5682_DMIC_CTRL_1,
+				RT5682_DMIC_1_DP_MASK, RT5682_DMIC_1_DP_GPIO5);
+			regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+				RT5682_GP5_PIN_MASK, RT5682_GP5_PIN_DMIC_SDA);
+			break;
+
+		default:
+			dev_warn(&i2c->dev, "invalid DMIC_DAT pin\n");
+			break;
+		}
+
+		switch (rt5682->pdata.dmic1_clk_pin) {
+		case RT5682_DMIC1_CLK_GPIO1: /* share with IRQ */
+			regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+				RT5682_GP1_PIN_MASK, RT5682_GP1_PIN_DMIC_CLK);
+			break;
+
+		case RT5682_DMIC1_CLK_GPIO3: /* share with BCLK2 */
+			regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+				RT5682_GP3_PIN_MASK, RT5682_GP3_PIN_DMIC_CLK);
+			break;
+
+		default:
+			dev_warn(&i2c->dev, "invalid DMIC_CLK pin\n");
+			break;
+		}
+	}
+
+	regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
+			RT5682_LDO1_DVO_MASK | RT5682_HP_DRIVER_MASK,
+			RT5682_LDO1_DVO_12 | RT5682_HP_DRIVER_5X);
+	regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
+	regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+			RT5682_GP4_PIN_MASK | RT5682_GP5_PIN_MASK,
+			RT5682_GP4_PIN_ADCDAT1 | RT5682_GP5_PIN_DACDAT1);
+	regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
+
+	INIT_DELAYED_WORK(&rt5682->jack_detect_work,
+				rt5682_jack_detect_handler);
+	INIT_DELAYED_WORK(&rt5682->jd_check_work,
+				rt5682_jd_check_handler);
+
+	mutex_init(&rt5682->calibrate_mutex);
+
+	if (i2c->irq) {
+		ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+			rt5682_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+			| IRQF_ONESHOT, "rt5682", rt5682);
+		if (ret)
+			dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+
+	}
+
+	return devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_rt5682,
+			rt5682_dai, ARRAY_SIZE(rt5682_dai));
+}
+
+static void rt5682_i2c_shutdown(struct i2c_client *client)
+{
+	struct rt5682_priv *rt5682 = i2c_get_clientdata(client);
+
+	rt5682_reset(rt5682->regmap);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt5682_of_match[] = {
+	{.compatible = "realtek,rt5682i"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5682_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5682_acpi_match[] = {
+	{"10EC5682", 0,},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, rt5682_acpi_match);
+#endif
+
+static struct i2c_driver rt5682_i2c_driver = {
+	.driver = {
+		.name = "rt5682",
+		.of_match_table = of_match_ptr(rt5682_of_match),
+		.acpi_match_table = ACPI_PTR(rt5682_acpi_match),
+	},
+	.probe = rt5682_i2c_probe,
+	.shutdown = rt5682_i2c_shutdown,
+	.id_table = rt5682_i2c_id,
+};
+module_i2c_driver(rt5682_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5682 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
new file mode 100644
index 0000000..8068140
--- /dev/null
+++ b/sound/soc/codecs/rt5682.h
@@ -0,0 +1,1324 @@
+/*
+ * rt5682.h  --  RT5682/RT5658 ALSA SoC audio driver
+ *
+ * Copyright 2018 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5682_H__
+#define __RT5682_H__
+
+#include <sound/rt5682.h>
+
+#define DEVICE_ID 0x6530
+
+/* Info */
+#define RT5682_RESET				0x0000
+#define RT5682_VERSION_ID			0x00fd
+#define RT5682_VENDOR_ID			0x00fe
+#define RT5682_DEVICE_ID			0x00ff
+/*  I/O - Output */
+#define RT5682_HP_CTRL_1			0x0002
+#define RT5682_HP_CTRL_2			0x0003
+#define RT5682_HPL_GAIN				0x0005
+#define RT5682_HPR_GAIN				0x0006
+
+#define RT5682_I2C_CTRL				0x0008
+
+/* I/O - Input */
+#define RT5682_CBJ_BST_CTRL			0x000b
+#define RT5682_CBJ_CTRL_1			0x0010
+#define RT5682_CBJ_CTRL_2			0x0011
+#define RT5682_CBJ_CTRL_3			0x0012
+#define RT5682_CBJ_CTRL_4			0x0013
+#define RT5682_CBJ_CTRL_5			0x0014
+#define RT5682_CBJ_CTRL_6			0x0015
+#define RT5682_CBJ_CTRL_7			0x0016
+/* I/O - ADC/DAC/DMIC */
+#define RT5682_DAC1_DIG_VOL			0x0019
+#define RT5682_STO1_ADC_DIG_VOL			0x001c
+#define RT5682_STO1_ADC_BOOST			0x001f
+#define RT5682_HP_IMP_GAIN_1			0x0022
+#define RT5682_HP_IMP_GAIN_2			0x0023
+/* Mixer - D-D */
+#define RT5682_SIDETONE_CTRL			0x0024
+#define RT5682_STO1_ADC_MIXER			0x0026
+#define RT5682_AD_DA_MIXER			0x0029
+#define RT5682_STO1_DAC_MIXER			0x002a
+#define RT5682_A_DAC1_MUX			0x002b
+#define RT5682_DIG_INF2_DATA			0x0030
+/* Mixer - ADC */
+#define RT5682_REC_MIXER			0x003c
+#define RT5682_CAL_REC				0x0044
+#define RT5682_ALC_BACK_GAIN			0x0049
+/* Power */
+#define RT5682_PWR_DIG_1			0x0061
+#define RT5682_PWR_DIG_2			0x0062
+#define RT5682_PWR_ANLG_1			0x0063
+#define RT5682_PWR_ANLG_2			0x0064
+#define RT5682_PWR_ANLG_3			0x0065
+#define RT5682_PWR_MIXER			0x0066
+#define RT5682_PWR_VOL				0x0067
+/* Clock Detect */
+#define RT5682_CLK_DET				0x006b
+/* Filter Auto Reset */
+#define RT5682_RESET_LPF_CTRL			0x006c
+#define RT5682_RESET_HPF_CTRL			0x006d
+/* DMIC */
+#define RT5682_DMIC_CTRL_1			0x006e
+/* Format - ADC/DAC */
+#define RT5682_I2S1_SDP				0x0070
+#define RT5682_I2S2_SDP				0x0071
+#define RT5682_ADDA_CLK_1			0x0073
+#define RT5682_ADDA_CLK_2			0x0074
+#define RT5682_I2S1_F_DIV_CTRL_1		0x0075
+#define RT5682_I2S1_F_DIV_CTRL_2		0x0076
+/* Format - TDM Control */
+#define RT5682_TDM_CTRL				0x0079
+#define RT5682_TDM_ADDA_CTRL_1			0x007a
+#define RT5682_TDM_ADDA_CTRL_2			0x007b
+#define RT5682_DATA_SEL_CTRL_1			0x007c
+#define RT5682_TDM_TCON_CTRL			0x007e
+/* Function - Analog */
+#define RT5682_GLB_CLK				0x0080
+#define RT5682_PLL_CTRL_1			0x0081
+#define RT5682_PLL_CTRL_2			0x0082
+#define RT5682_PLL_TRACK_1			0x0083
+#define RT5682_PLL_TRACK_2			0x0084
+#define RT5682_PLL_TRACK_3			0x0085
+#define RT5682_PLL_TRACK_4			0x0086
+#define RT5682_PLL_TRACK_5			0x0087
+#define RT5682_PLL_TRACK_6			0x0088
+#define RT5682_PLL_TRACK_11			0x008c
+#define RT5682_SDW_REF_CLK			0x008d
+#define RT5682_DEPOP_1				0x008e
+#define RT5682_DEPOP_2				0x008f
+#define RT5682_HP_CHARGE_PUMP_1			0x0091
+#define RT5682_HP_CHARGE_PUMP_2			0x0092
+#define RT5682_MICBIAS_1			0x0093
+#define RT5682_MICBIAS_2			0x0094
+#define RT5682_PLL_TRACK_12			0x0098
+#define RT5682_PLL_TRACK_14			0x009a
+#define RT5682_PLL2_CTRL_1			0x009b
+#define RT5682_PLL2_CTRL_2			0x009c
+#define RT5682_PLL2_CTRL_3			0x009d
+#define RT5682_PLL2_CTRL_4			0x009e
+#define RT5682_RC_CLK_CTRL			0x009f
+#define RT5682_I2S_M_CLK_CTRL_1			0x00a0
+#define RT5682_I2S2_F_DIV_CTRL_1		0x00a3
+#define RT5682_I2S2_F_DIV_CTRL_2		0x00a4
+/* Function - Digital */
+#define RT5682_EQ_CTRL_1			0x00ae
+#define RT5682_EQ_CTRL_2			0x00af
+#define RT5682_IRQ_CTRL_1			0x00b6
+#define RT5682_IRQ_CTRL_2			0x00b7
+#define RT5682_IRQ_CTRL_3			0x00b8
+#define RT5682_IRQ_CTRL_4			0x00b9
+#define RT5682_INT_ST_1				0x00be
+#define RT5682_GPIO_CTRL_1			0x00c0
+#define RT5682_GPIO_CTRL_2			0x00c1
+#define RT5682_GPIO_CTRL_3			0x00c2
+#define RT5682_HP_AMP_DET_CTRL_1		0x00d0
+#define RT5682_HP_AMP_DET_CTRL_2		0x00d1
+#define RT5682_MID_HP_AMP_DET			0x00d2
+#define RT5682_LOW_HP_AMP_DET			0x00d3
+#define RT5682_DELAY_BUF_CTRL			0x00d4
+#define RT5682_SV_ZCD_1				0x00d9
+#define RT5682_SV_ZCD_2				0x00da
+#define RT5682_IL_CMD_1				0x00db
+#define RT5682_IL_CMD_2				0x00dc
+#define RT5682_IL_CMD_3				0x00dd
+#define RT5682_IL_CMD_4				0x00de
+#define RT5682_IL_CMD_5				0x00df
+#define RT5682_IL_CMD_6				0x00e0
+#define RT5682_4BTN_IL_CMD_1			0x00e2
+#define RT5682_4BTN_IL_CMD_2			0x00e3
+#define RT5682_4BTN_IL_CMD_3			0x00e4
+#define RT5682_4BTN_IL_CMD_4			0x00e5
+#define RT5682_4BTN_IL_CMD_5			0x00e6
+#define RT5682_4BTN_IL_CMD_6			0x00e7
+#define RT5682_4BTN_IL_CMD_7			0x00e8
+
+#define RT5682_ADC_STO1_HP_CTRL_1		0x00ea
+#define RT5682_ADC_STO1_HP_CTRL_2		0x00eb
+#define RT5682_AJD1_CTRL			0x00f0
+#define RT5682_JD1_THD				0x00f1
+#define RT5682_JD2_THD				0x00f2
+#define RT5682_JD_CTRL_1			0x00f6
+/* General Control */
+#define RT5682_DUMMY_1				0x00fa
+#define RT5682_DUMMY_2				0x00fb
+#define RT5682_DUMMY_3				0x00fc
+
+#define RT5682_DAC_ADC_DIG_VOL1			0x0100
+#define RT5682_BIAS_CUR_CTRL_2			0x010b
+#define RT5682_BIAS_CUR_CTRL_3			0x010c
+#define RT5682_BIAS_CUR_CTRL_4			0x010d
+#define RT5682_BIAS_CUR_CTRL_5			0x010e
+#define RT5682_BIAS_CUR_CTRL_6			0x010f
+#define RT5682_BIAS_CUR_CTRL_7			0x0110
+#define RT5682_BIAS_CUR_CTRL_8			0x0111
+#define RT5682_BIAS_CUR_CTRL_9			0x0112
+#define RT5682_BIAS_CUR_CTRL_10			0x0113
+#define RT5682_VREF_REC_OP_FB_CAP_CTRL		0x0117
+#define RT5682_CHARGE_PUMP_1			0x0125
+#define RT5682_DIG_IN_CTRL_1			0x0132
+#define RT5682_PAD_DRIVING_CTRL			0x0136
+#define RT5682_SOFT_RAMP_DEPOP			0x0138
+#define RT5682_CHOP_DAC				0x013a
+#define RT5682_CHOP_ADC				0x013b
+#define RT5682_CALIB_ADC_CTRL			0x013c
+#define RT5682_VOL_TEST				0x013f
+#define RT5682_SPKVDD_DET_STA			0x0142
+#define RT5682_TEST_MODE_CTRL_1			0x0145
+#define RT5682_TEST_MODE_CTRL_2			0x0146
+#define RT5682_TEST_MODE_CTRL_3			0x0147
+#define RT5682_TEST_MODE_CTRL_4			0x0148
+#define RT5682_TEST_MODE_CTRL_5			0x0149
+#define RT5682_PLL1_INTERNAL			0x0150
+#define RT5682_PLL2_INTERNAL			0x0151
+#define RT5682_STO_NG2_CTRL_1			0x0160
+#define RT5682_STO_NG2_CTRL_2			0x0161
+#define RT5682_STO_NG2_CTRL_3			0x0162
+#define RT5682_STO_NG2_CTRL_4			0x0163
+#define RT5682_STO_NG2_CTRL_5			0x0164
+#define RT5682_STO_NG2_CTRL_6			0x0165
+#define RT5682_STO_NG2_CTRL_7			0x0166
+#define RT5682_STO_NG2_CTRL_8			0x0167
+#define RT5682_STO_NG2_CTRL_9			0x0168
+#define RT5682_STO_NG2_CTRL_10			0x0169
+#define RT5682_STO1_DAC_SIL_DET			0x0190
+#define RT5682_SIL_PSV_CTRL1			0x0194
+#define RT5682_SIL_PSV_CTRL2			0x0195
+#define RT5682_SIL_PSV_CTRL3			0x0197
+#define RT5682_SIL_PSV_CTRL4			0x0198
+#define RT5682_SIL_PSV_CTRL5			0x0199
+#define RT5682_HP_IMP_SENS_CTRL_01		0x01af
+#define RT5682_HP_IMP_SENS_CTRL_02		0x01b0
+#define RT5682_HP_IMP_SENS_CTRL_03		0x01b1
+#define RT5682_HP_IMP_SENS_CTRL_04		0x01b2
+#define RT5682_HP_IMP_SENS_CTRL_05		0x01b3
+#define RT5682_HP_IMP_SENS_CTRL_06		0x01b4
+#define RT5682_HP_IMP_SENS_CTRL_07		0x01b5
+#define RT5682_HP_IMP_SENS_CTRL_08		0x01b6
+#define RT5682_HP_IMP_SENS_CTRL_09		0x01b7
+#define RT5682_HP_IMP_SENS_CTRL_10		0x01b8
+#define RT5682_HP_IMP_SENS_CTRL_11		0x01b9
+#define RT5682_HP_IMP_SENS_CTRL_12		0x01ba
+#define RT5682_HP_IMP_SENS_CTRL_13		0x01bb
+#define RT5682_HP_IMP_SENS_CTRL_14		0x01bc
+#define RT5682_HP_IMP_SENS_CTRL_15		0x01bd
+#define RT5682_HP_IMP_SENS_CTRL_16		0x01be
+#define RT5682_HP_IMP_SENS_CTRL_17		0x01bf
+#define RT5682_HP_IMP_SENS_CTRL_18		0x01c0
+#define RT5682_HP_IMP_SENS_CTRL_19		0x01c1
+#define RT5682_HP_IMP_SENS_CTRL_20		0x01c2
+#define RT5682_HP_IMP_SENS_CTRL_21		0x01c3
+#define RT5682_HP_IMP_SENS_CTRL_22		0x01c4
+#define RT5682_HP_IMP_SENS_CTRL_23		0x01c5
+#define RT5682_HP_IMP_SENS_CTRL_24		0x01c6
+#define RT5682_HP_IMP_SENS_CTRL_25		0x01c7
+#define RT5682_HP_IMP_SENS_CTRL_26		0x01c8
+#define RT5682_HP_IMP_SENS_CTRL_27		0x01c9
+#define RT5682_HP_IMP_SENS_CTRL_28		0x01ca
+#define RT5682_HP_IMP_SENS_CTRL_29		0x01cb
+#define RT5682_HP_IMP_SENS_CTRL_30		0x01cc
+#define RT5682_HP_IMP_SENS_CTRL_31		0x01cd
+#define RT5682_HP_IMP_SENS_CTRL_32		0x01ce
+#define RT5682_HP_IMP_SENS_CTRL_33		0x01cf
+#define RT5682_HP_IMP_SENS_CTRL_34		0x01d0
+#define RT5682_HP_IMP_SENS_CTRL_35		0x01d1
+#define RT5682_HP_IMP_SENS_CTRL_36		0x01d2
+#define RT5682_HP_IMP_SENS_CTRL_37		0x01d3
+#define RT5682_HP_IMP_SENS_CTRL_38		0x01d4
+#define RT5682_HP_IMP_SENS_CTRL_39		0x01d5
+#define RT5682_HP_IMP_SENS_CTRL_40		0x01d6
+#define RT5682_HP_IMP_SENS_CTRL_41		0x01d7
+#define RT5682_HP_IMP_SENS_CTRL_42		0x01d8
+#define RT5682_HP_IMP_SENS_CTRL_43		0x01d9
+#define RT5682_HP_LOGIC_CTRL_1			0x01da
+#define RT5682_HP_LOGIC_CTRL_2			0x01db
+#define RT5682_HP_LOGIC_CTRL_3			0x01dc
+#define RT5682_HP_CALIB_CTRL_1			0x01de
+#define RT5682_HP_CALIB_CTRL_2			0x01df
+#define RT5682_HP_CALIB_CTRL_3			0x01e0
+#define RT5682_HP_CALIB_CTRL_4			0x01e1
+#define RT5682_HP_CALIB_CTRL_5			0x01e2
+#define RT5682_HP_CALIB_CTRL_6			0x01e3
+#define RT5682_HP_CALIB_CTRL_7			0x01e4
+#define RT5682_HP_CALIB_CTRL_9			0x01e6
+#define RT5682_HP_CALIB_CTRL_10			0x01e7
+#define RT5682_HP_CALIB_CTRL_11			0x01e8
+#define RT5682_HP_CALIB_STA_1			0x01ea
+#define RT5682_HP_CALIB_STA_2			0x01eb
+#define RT5682_HP_CALIB_STA_3			0x01ec
+#define RT5682_HP_CALIB_STA_4			0x01ed
+#define RT5682_HP_CALIB_STA_5			0x01ee
+#define RT5682_HP_CALIB_STA_6			0x01ef
+#define RT5682_HP_CALIB_STA_7			0x01f0
+#define RT5682_HP_CALIB_STA_8			0x01f1
+#define RT5682_HP_CALIB_STA_9			0x01f2
+#define RT5682_HP_CALIB_STA_10			0x01f3
+#define RT5682_HP_CALIB_STA_11			0x01f4
+#define RT5682_SAR_IL_CMD_1			0x0210
+#define RT5682_SAR_IL_CMD_2			0x0211
+#define RT5682_SAR_IL_CMD_3			0x0212
+#define RT5682_SAR_IL_CMD_4			0x0213
+#define RT5682_SAR_IL_CMD_5			0x0214
+#define RT5682_SAR_IL_CMD_6			0x0215
+#define RT5682_SAR_IL_CMD_7			0x0216
+#define RT5682_SAR_IL_CMD_8			0x0217
+#define RT5682_SAR_IL_CMD_9			0x0218
+#define RT5682_SAR_IL_CMD_10			0x0219
+#define RT5682_SAR_IL_CMD_11			0x021a
+#define RT5682_SAR_IL_CMD_12			0x021b
+#define RT5682_SAR_IL_CMD_13			0x021c
+#define RT5682_EFUSE_CTRL_1			0x0250
+#define RT5682_EFUSE_CTRL_2			0x0251
+#define RT5682_EFUSE_CTRL_3			0x0252
+#define RT5682_EFUSE_CTRL_4			0x0253
+#define RT5682_EFUSE_CTRL_5			0x0254
+#define RT5682_EFUSE_CTRL_6			0x0255
+#define RT5682_EFUSE_CTRL_7			0x0256
+#define RT5682_EFUSE_CTRL_8			0x0257
+#define RT5682_EFUSE_CTRL_9			0x0258
+#define RT5682_EFUSE_CTRL_10			0x0259
+#define RT5682_EFUSE_CTRL_11			0x025a
+#define RT5682_JD_TOP_VC_VTRL			0x0270
+#define RT5682_DRC1_CTRL_0			0x02ff
+#define RT5682_DRC1_CTRL_1			0x0300
+#define RT5682_DRC1_CTRL_2			0x0301
+#define RT5682_DRC1_CTRL_3			0x0302
+#define RT5682_DRC1_CTRL_4			0x0303
+#define RT5682_DRC1_CTRL_5			0x0304
+#define RT5682_DRC1_CTRL_6			0x0305
+#define RT5682_DRC1_HARD_LMT_CTRL_1		0x0306
+#define RT5682_DRC1_HARD_LMT_CTRL_2		0x0307
+#define RT5682_DRC1_PRIV_1			0x0310
+#define RT5682_DRC1_PRIV_2			0x0311
+#define RT5682_DRC1_PRIV_3			0x0312
+#define RT5682_DRC1_PRIV_4			0x0313
+#define RT5682_DRC1_PRIV_5			0x0314
+#define RT5682_DRC1_PRIV_6			0x0315
+#define RT5682_DRC1_PRIV_7			0x0316
+#define RT5682_DRC1_PRIV_8			0x0317
+#define RT5682_EQ_AUTO_RCV_CTRL1		0x03c0
+#define RT5682_EQ_AUTO_RCV_CTRL2		0x03c1
+#define RT5682_EQ_AUTO_RCV_CTRL3		0x03c2
+#define RT5682_EQ_AUTO_RCV_CTRL4		0x03c3
+#define RT5682_EQ_AUTO_RCV_CTRL5		0x03c4
+#define RT5682_EQ_AUTO_RCV_CTRL6		0x03c5
+#define RT5682_EQ_AUTO_RCV_CTRL7		0x03c6
+#define RT5682_EQ_AUTO_RCV_CTRL8		0x03c7
+#define RT5682_EQ_AUTO_RCV_CTRL9		0x03c8
+#define RT5682_EQ_AUTO_RCV_CTRL10		0x03c9
+#define RT5682_EQ_AUTO_RCV_CTRL11		0x03ca
+#define RT5682_EQ_AUTO_RCV_CTRL12		0x03cb
+#define RT5682_EQ_AUTO_RCV_CTRL13		0x03cc
+#define RT5682_ADC_L_EQ_LPF1_A1			0x03d0
+#define RT5682_R_EQ_LPF1_A1			0x03d1
+#define RT5682_L_EQ_LPF1_H0			0x03d2
+#define RT5682_R_EQ_LPF1_H0			0x03d3
+#define RT5682_L_EQ_BPF1_A1			0x03d4
+#define RT5682_R_EQ_BPF1_A1			0x03d5
+#define RT5682_L_EQ_BPF1_A2			0x03d6
+#define RT5682_R_EQ_BPF1_A2			0x03d7
+#define RT5682_L_EQ_BPF1_H0			0x03d8
+#define RT5682_R_EQ_BPF1_H0			0x03d9
+#define RT5682_L_EQ_BPF2_A1			0x03da
+#define RT5682_R_EQ_BPF2_A1			0x03db
+#define RT5682_L_EQ_BPF2_A2			0x03dc
+#define RT5682_R_EQ_BPF2_A2			0x03dd
+#define RT5682_L_EQ_BPF2_H0			0x03de
+#define RT5682_R_EQ_BPF2_H0			0x03df
+#define RT5682_L_EQ_BPF3_A1			0x03e0
+#define RT5682_R_EQ_BPF3_A1			0x03e1
+#define RT5682_L_EQ_BPF3_A2			0x03e2
+#define RT5682_R_EQ_BPF3_A2			0x03e3
+#define RT5682_L_EQ_BPF3_H0			0x03e4
+#define RT5682_R_EQ_BPF3_H0			0x03e5
+#define RT5682_L_EQ_BPF4_A1			0x03e6
+#define RT5682_R_EQ_BPF4_A1			0x03e7
+#define RT5682_L_EQ_BPF4_A2			0x03e8
+#define RT5682_R_EQ_BPF4_A2			0x03e9
+#define RT5682_L_EQ_BPF4_H0			0x03ea
+#define RT5682_R_EQ_BPF4_H0			0x03eb
+#define RT5682_L_EQ_HPF1_A1			0x03ec
+#define RT5682_R_EQ_HPF1_A1			0x03ed
+#define RT5682_L_EQ_HPF1_H0			0x03ee
+#define RT5682_R_EQ_HPF1_H0			0x03ef
+#define RT5682_L_EQ_PRE_VOL			0x03f0
+#define RT5682_R_EQ_PRE_VOL			0x03f1
+#define RT5682_L_EQ_POST_VOL			0x03f2
+#define RT5682_R_EQ_POST_VOL			0x03f3
+#define RT5682_I2C_MODE				0xffff
+
+
+/* global definition */
+#define RT5682_L_MUTE				(0x1 << 15)
+#define RT5682_L_MUTE_SFT			15
+#define RT5682_VOL_L_MUTE			(0x1 << 14)
+#define RT5682_VOL_L_SFT			14
+#define RT5682_R_MUTE				(0x1 << 7)
+#define RT5682_R_MUTE_SFT			7
+#define RT5682_VOL_R_MUTE			(0x1 << 6)
+#define RT5682_VOL_R_SFT			6
+#define RT5682_L_VOL_MASK			(0x3f << 8)
+#define RT5682_L_VOL_SFT			8
+#define RT5682_R_VOL_MASK			(0x3f)
+#define RT5682_R_VOL_SFT			0
+
+/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/
+#define RT5682_G_HP				(0xf << 8)
+#define RT5682_G_HP_SFT				8
+#define RT5682_G_STO_DA_DMIX			(0xf)
+#define RT5682_G_STO_DA_SFT			0
+
+/* CBJ Control (0x000b) */
+#define RT5682_BST_CBJ_MASK			(0xf << 8)
+#define RT5682_BST_CBJ_SFT			8
+
+/* Embeeded Jack and Type Detection Control 1 (0x0010) */
+#define RT5682_EMB_JD_EN			(0x1 << 15)
+#define RT5682_EMB_JD_EN_SFT			15
+#define RT5682_EMB_JD_RST			(0x1 << 14)
+#define RT5682_JD_MODE				(0x1 << 13)
+#define RT5682_JD_MODE_SFT			13
+#define RT5682_DET_TYPE				(0x1 << 12)
+#define RT5682_DET_TYPE_SFT			12
+#define RT5682_POLA_EXT_JD_MASK			(0x1 << 11)
+#define RT5682_POLA_EXT_JD_LOW			(0x1 << 11)
+#define RT5682_POLA_EXT_JD_HIGH			(0x0 << 11)
+#define RT5682_EXT_JD_DIG			(0x1 << 9)
+#define RT5682_POL_FAST_OFF_MASK		(0x1 << 8)
+#define RT5682_POL_FAST_OFF_HIGH		(0x1 << 8)
+#define RT5682_POL_FAST_OFF_LOW			(0x0 << 8)
+#define RT5682_FAST_OFF_MASK			(0x1 << 7)
+#define RT5682_FAST_OFF_EN			(0x1 << 7)
+#define RT5682_FAST_OFF_DIS			(0x0 << 7)
+#define RT5682_VREF_POW_MASK			(0x1 << 6)
+#define RT5682_VREF_POW_FSM			(0x0 << 6)
+#define RT5682_VREF_POW_REG			(0x1 << 6)
+#define RT5682_MB1_PATH_MASK			(0x1 << 5)
+#define RT5682_CTRL_MB1_REG			(0x1 << 5)
+#define RT5682_CTRL_MB1_FSM			(0x0 << 5)
+#define RT5682_MB2_PATH_MASK			(0x1 << 4)
+#define RT5682_CTRL_MB2_REG			(0x1 << 4)
+#define RT5682_CTRL_MB2_FSM			(0x0 << 4)
+#define RT5682_TRIG_JD_MASK			(0x1 << 3)
+#define RT5682_TRIG_JD_HIGH			(0x1 << 3)
+#define RT5682_TRIG_JD_LOW			(0x0 << 3)
+#define RT5682_MIC_CAP_MASK			(0x1 << 1)
+#define RT5682_MIC_CAP_HS			(0x1 << 1)
+#define RT5682_MIC_CAP_HP			(0x0 << 1)
+#define RT5682_MIC_CAP_SRC_MASK			(0x1)
+#define RT5682_MIC_CAP_SRC_REG			(0x1)
+#define RT5682_MIC_CAP_SRC_ANA			(0x0)
+
+/* Embeeded Jack and Type Detection Control 2 (0x0011) */
+#define RT5682_EXT_JD_SRC			(0x7 << 4)
+#define RT5682_EXT_JD_SRC_SFT			4
+#define RT5682_EXT_JD_SRC_GPIO_JD1		(0x0 << 4)
+#define RT5682_EXT_JD_SRC_GPIO_JD2		(0x1 << 4)
+#define RT5682_EXT_JD_SRC_JDH			(0x2 << 4)
+#define RT5682_EXT_JD_SRC_JDL			(0x3 << 4)
+#define RT5682_EXT_JD_SRC_MANUAL		(0x4 << 4)
+#define RT5682_JACK_TYPE_MASK			(0x3)
+
+/* Combo Jack and Type Detection Control 3 (0x0012) */
+#define RT5682_CBJ_IN_BUF_EN			(0x1 << 7)
+
+/* Combo Jack and Type Detection Control 4 (0x0013) */
+#define RT5682_SEL_SHT_MID_TON_MASK		(0x3 << 12)
+#define RT5682_SEL_SHT_MID_TON_2		(0x0 << 12)
+#define RT5682_SEL_SHT_MID_TON_3		(0x1 << 12)
+#define RT5682_CBJ_JD_TEST_MASK			(0x1 << 6)
+#define RT5682_CBJ_JD_TEST_NORM			(0x0 << 6)
+#define RT5682_CBJ_JD_TEST_MODE			(0x1 << 6)
+
+/* DAC1 Digital Volume (0x0019) */
+#define RT5682_DAC_L1_VOL_MASK			(0xff << 8)
+#define RT5682_DAC_L1_VOL_SFT			8
+#define RT5682_DAC_R1_VOL_MASK			(0xff)
+#define RT5682_DAC_R1_VOL_SFT			0
+
+/* ADC Digital Volume Control (0x001c) */
+#define RT5682_ADC_L_VOL_MASK			(0x7f << 8)
+#define RT5682_ADC_L_VOL_SFT			8
+#define RT5682_ADC_R_VOL_MASK			(0x7f)
+#define RT5682_ADC_R_VOL_SFT			0
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5682_STO1_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5682_STO1_ADC_L_BST_SFT		14
+#define RT5682_STO1_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5682_STO1_ADC_R_BST_SFT		12
+
+/* Sidetone Control (0x0024) */
+#define RT5682_ST_SRC_SEL			(0x1 << 8)
+#define RT5682_ST_SRC_SFT			8
+#define RT5682_ST_EN_MASK			(0x1 << 6)
+#define RT5682_ST_DIS				(0x0 << 6)
+#define RT5682_ST_EN				(0x1 << 6)
+#define RT5682_ST_EN_SFT			6
+
+/* Stereo1 ADC Mixer Control (0x0026) */
+#define RT5682_M_STO1_ADC_L1			(0x1 << 15)
+#define RT5682_M_STO1_ADC_L1_SFT		15
+#define RT5682_M_STO1_ADC_L2			(0x1 << 14)
+#define RT5682_M_STO1_ADC_L2_SFT		14
+#define RT5682_STO1_ADC1L_SRC_MASK		(0x1 << 13)
+#define RT5682_STO1_ADC1L_SRC_SFT		13
+#define RT5682_STO1_ADC1_SRC_ADC		(0x1 << 13)
+#define RT5682_STO1_ADC1_SRC_DACMIX		(0x0 << 13)
+#define RT5682_STO1_ADC2L_SRC_MASK		(0x1 << 12)
+#define RT5682_STO1_ADC2L_SRC_SFT		12
+#define RT5682_STO1_ADCL_SRC_MASK		(0x3 << 10)
+#define RT5682_STO1_ADCL_SRC_SFT		10
+#define RT5682_STO1_DD_L_SRC_MASK		(0x1 << 9)
+#define RT5682_STO1_DD_L_SRC_SFT		9
+#define RT5682_STO1_DMIC_SRC_MASK		(0x1 << 8)
+#define RT5682_STO1_DMIC_SRC_SFT		8
+#define RT5682_STO1_DMIC_SRC_DMIC2		(0x1 << 8)
+#define RT5682_STO1_DMIC_SRC_DMIC1		(0x0 << 8)
+#define RT5682_M_STO1_ADC_R1			(0x1 << 7)
+#define RT5682_M_STO1_ADC_R1_SFT		7
+#define RT5682_M_STO1_ADC_R2			(0x1 << 6)
+#define RT5682_M_STO1_ADC_R2_SFT		6
+#define RT5682_STO1_ADC1R_SRC_MASK		(0x1 << 5)
+#define RT5682_STO1_ADC1R_SRC_SFT		5
+#define RT5682_STO1_ADC2R_SRC_MASK		(0x1 << 4)
+#define RT5682_STO1_ADC2R_SRC_SFT		4
+#define RT5682_STO1_ADCR_SRC_MASK		(0x3 << 2)
+#define RT5682_STO1_ADCR_SRC_SFT		2
+
+/* ADC Mixer to DAC Mixer Control (0x0029) */
+#define RT5682_M_ADCMIX_L			(0x1 << 15)
+#define RT5682_M_ADCMIX_L_SFT			15
+#define RT5682_M_DAC1_L				(0x1 << 14)
+#define RT5682_M_DAC1_L_SFT			14
+#define RT5682_DAC1_R_SEL_MASK			(0x1 << 10)
+#define RT5682_DAC1_R_SEL_SFT			10
+#define RT5682_DAC1_L_SEL_MASK			(0x1 << 8)
+#define RT5682_DAC1_L_SEL_SFT			8
+#define RT5682_M_ADCMIX_R			(0x1 << 7)
+#define RT5682_M_ADCMIX_R_SFT			7
+#define RT5682_M_DAC1_R				(0x1 << 6)
+#define RT5682_M_DAC1_R_SFT			6
+
+/* Stereo1 DAC Mixer Control (0x002a) */
+#define RT5682_M_DAC_L1_STO_L			(0x1 << 15)
+#define RT5682_M_DAC_L1_STO_L_SFT		15
+#define RT5682_G_DAC_L1_STO_L_MASK		(0x1 << 14)
+#define RT5682_G_DAC_L1_STO_L_SFT		14
+#define RT5682_M_DAC_R1_STO_L			(0x1 << 13)
+#define RT5682_M_DAC_R1_STO_L_SFT		13
+#define RT5682_G_DAC_R1_STO_L_MASK		(0x1 << 12)
+#define RT5682_G_DAC_R1_STO_L_SFT		12
+#define RT5682_M_DAC_L1_STO_R			(0x1 << 7)
+#define RT5682_M_DAC_L1_STO_R_SFT		7
+#define RT5682_G_DAC_L1_STO_R_MASK		(0x1 << 6)
+#define RT5682_G_DAC_L1_STO_R_SFT		6
+#define RT5682_M_DAC_R1_STO_R			(0x1 << 5)
+#define RT5682_M_DAC_R1_STO_R_SFT		5
+#define RT5682_G_DAC_R1_STO_R_MASK		(0x1 << 4)
+#define RT5682_G_DAC_R1_STO_R_SFT		4
+
+/* Analog DAC1 Input Source Control (0x002b) */
+#define RT5682_M_ST_STO_L			(0x1 << 9)
+#define RT5682_M_ST_STO_L_SFT			9
+#define RT5682_M_ST_STO_R			(0x1 << 8)
+#define RT5682_M_ST_STO_R_SFT			8
+#define RT5682_DAC_L1_SRC_MASK			(0x3 << 4)
+#define RT5682_A_DACL1_SFT			4
+#define RT5682_DAC_R1_SRC_MASK			(0x3)
+#define RT5682_A_DACR1_SFT			0
+
+/* Digital Interface Data Control (0x0030) */
+#define RT5682_IF2_ADC_SEL_MASK			(0x3 << 0)
+#define RT5682_IF2_ADC_SEL_SFT			0
+
+/* REC Left Mixer Control 2 (0x003c) */
+#define RT5682_G_CBJ_RM1_L			(0x7 << 10)
+#define RT5682_G_CBJ_RM1_L_SFT			10
+#define RT5682_M_CBJ_RM1_L			(0x1 << 7)
+#define RT5682_M_CBJ_RM1_L_SFT			7
+
+/* Power Management for Digital 1 (0x0061) */
+#define RT5682_PWR_I2S1				(0x1 << 15)
+#define RT5682_PWR_I2S1_BIT			15
+#define RT5682_PWR_I2S2				(0x1 << 14)
+#define RT5682_PWR_I2S2_BIT			14
+#define RT5682_PWR_DAC_L1			(0x1 << 11)
+#define RT5682_PWR_DAC_L1_BIT			11
+#define RT5682_PWR_DAC_R1			(0x1 << 10)
+#define RT5682_PWR_DAC_R1_BIT			10
+#define RT5682_PWR_LDO				(0x1 << 8)
+#define RT5682_PWR_LDO_BIT			8
+#define RT5682_PWR_ADC_L1			(0x1 << 4)
+#define RT5682_PWR_ADC_L1_BIT			4
+#define RT5682_PWR_ADC_R1			(0x1 << 3)
+#define RT5682_PWR_ADC_R1_BIT			3
+#define RT5682_DIG_GATE_CTRL			(0x1 << 0)
+#define RT5682_DIG_GATE_CTRL_SFT		0
+
+
+/* Power Management for Digital 2 (0x0062) */
+#define RT5682_PWR_ADC_S1F			(0x1 << 15)
+#define RT5682_PWR_ADC_S1F_BIT			15
+#define RT5682_PWR_DAC_S1F			(0x1 << 10)
+#define RT5682_PWR_DAC_S1F_BIT			10
+
+/* Power Management for Analog 1 (0x0063) */
+#define RT5682_PWR_VREF1			(0x1 << 15)
+#define RT5682_PWR_VREF1_BIT			15
+#define RT5682_PWR_FV1				(0x1 << 14)
+#define RT5682_PWR_FV1_BIT			14
+#define RT5682_PWR_VREF2			(0x1 << 13)
+#define RT5682_PWR_VREF2_BIT			13
+#define RT5682_PWR_FV2				(0x1 << 12)
+#define RT5682_PWR_FV2_BIT			12
+#define RT5682_LDO1_DBG_MASK			(0x3 << 10)
+#define RT5682_PWR_MB				(0x1 << 9)
+#define RT5682_PWR_MB_BIT			9
+#define RT5682_PWR_BG				(0x1 << 7)
+#define RT5682_PWR_BG_BIT			7
+#define RT5682_LDO1_BYPASS_MASK			(0x1 << 6)
+#define RT5682_LDO1_BYPASS			(0x1 << 6)
+#define RT5682_LDO1_NOT_BYPASS			(0x0 << 6)
+#define RT5682_PWR_MA_BIT			6
+#define RT5682_LDO1_DVO_MASK			(0x3 << 4)
+#define RT5682_LDO1_DVO_09			(0x0 << 4)
+#define RT5682_LDO1_DVO_10			(0x1 << 4)
+#define RT5682_LDO1_DVO_12			(0x2 << 4)
+#define RT5682_LDO1_DVO_14			(0x3 << 4)
+#define RT5682_HP_DRIVER_MASK			(0x3 << 2)
+#define RT5682_HP_DRIVER_1X			(0x0 << 2)
+#define RT5682_HP_DRIVER_3X			(0x1 << 2)
+#define RT5682_HP_DRIVER_5X			(0x3 << 2)
+#define RT5682_PWR_HA_L				(0x1 << 1)
+#define RT5682_PWR_HA_L_BIT			1
+#define RT5682_PWR_HA_R				(0x1 << 0)
+#define RT5682_PWR_HA_R_BIT			0
+
+/* Power Management for Analog 2 (0x0064) */
+#define RT5682_PWR_MB1				(0x1 << 11)
+#define RT5682_PWR_MB1_PWR_DOWN			(0x0 << 11)
+#define RT5682_PWR_MB1_BIT			11
+#define RT5682_PWR_MB2				(0x1 << 10)
+#define RT5682_PWR_MB2_PWR_DOWN			(0x0 << 10)
+#define RT5682_PWR_MB2_BIT			10
+#define RT5682_PWR_JDH				(0x1 << 3)
+#define RT5682_PWR_JDH_BIT			3
+#define RT5682_PWR_JDL				(0x1 << 2)
+#define RT5682_PWR_JDL_BIT			2
+#define RT5682_PWR_RM1_L			(0x1 << 1)
+#define RT5682_PWR_RM1_L_BIT			1
+
+/* Power Management for Analog 3 (0x0065) */
+#define RT5682_PWR_CBJ				(0x1 << 9)
+#define RT5682_PWR_CBJ_BIT			9
+#define RT5682_PWR_PLL				(0x1 << 6)
+#define RT5682_PWR_PLL_BIT			6
+#define RT5682_PWR_PLL2B			(0x1 << 5)
+#define RT5682_PWR_PLL2B_BIT			5
+#define RT5682_PWR_PLL2F			(0x1 << 4)
+#define RT5682_PWR_PLL2F_BIT			4
+#define RT5682_PWR_LDO2				(0x1 << 2)
+#define RT5682_PWR_LDO2_BIT			2
+#define RT5682_PWR_DET_SPKVDD			(0x1 << 1)
+#define RT5682_PWR_DET_SPKVDD_BIT		1
+
+/* Power Management for Mixer (0x0066) */
+#define RT5682_PWR_STO1_DAC_L			(0x1 << 5)
+#define RT5682_PWR_STO1_DAC_L_BIT		5
+#define RT5682_PWR_STO1_DAC_R			(0x1 << 4)
+#define RT5682_PWR_STO1_DAC_R_BIT		4
+
+/* MCLK and System Clock Detection Control (0x006b) */
+#define RT5682_SYS_CLK_DET			(0x1 << 15)
+#define RT5682_SYS_CLK_DET_SFT			15
+#define RT5682_PLL1_CLK_DET			(0x1 << 14)
+#define RT5682_PLL1_CLK_DET_SFT			14
+#define RT5682_PLL2_CLK_DET			(0x1 << 13)
+#define RT5682_PLL2_CLK_DET_SFT			13
+#define RT5682_POW_CLK_DET2_SFT			8
+#define RT5682_POW_CLK_DET_SFT			0
+
+/* Digital Microphone Control 1 (0x006e) */
+#define RT5682_DMIC_1_EN_MASK			(0x1 << 15)
+#define RT5682_DMIC_1_EN_SFT			15
+#define RT5682_DMIC_1_DIS			(0x0 << 15)
+#define RT5682_DMIC_1_EN			(0x1 << 15)
+#define RT5682_DMIC_1_DP_MASK			(0x3 << 4)
+#define RT5682_DMIC_1_DP_SFT			4
+#define RT5682_DMIC_1_DP_GPIO2			(0x0 << 4)
+#define RT5682_DMIC_1_DP_GPIO5			(0x1 << 4)
+#define RT5682_DMIC_CLK_MASK			(0xf << 0)
+#define RT5682_DMIC_CLK_SFT			0
+
+/* I2S1 Audio Serial Data Port Control (0x0070) */
+#define RT5682_SEL_ADCDAT_MASK			(0x1 << 15)
+#define RT5682_SEL_ADCDAT_OUT			(0x0 << 15)
+#define RT5682_SEL_ADCDAT_IN			(0x1 << 15)
+#define RT5682_SEL_ADCDAT_SFT			15
+#define RT5682_I2S1_TX_CHL_MASK			(0x7 << 12)
+#define RT5682_I2S1_TX_CHL_SFT			12
+#define RT5682_I2S1_TX_CHL_16			(0x0 << 12)
+#define RT5682_I2S1_TX_CHL_20			(0x1 << 12)
+#define RT5682_I2S1_TX_CHL_24			(0x2 << 12)
+#define RT5682_I2S1_TX_CHL_32			(0x3 << 12)
+#define RT5682_I2S1_TX_CHL_8			(0x4 << 12)
+#define RT5682_I2S1_RX_CHL_MASK			(0x7 << 8)
+#define RT5682_I2S1_RX_CHL_SFT			8
+#define RT5682_I2S1_RX_CHL_16			(0x0 << 8)
+#define RT5682_I2S1_RX_CHL_20			(0x1 << 8)
+#define RT5682_I2S1_RX_CHL_24			(0x2 << 8)
+#define RT5682_I2S1_RX_CHL_32			(0x3 << 8)
+#define RT5682_I2S1_RX_CHL_8			(0x4 << 8)
+#define RT5682_I2S1_MONO_MASK			(0x1 << 7)
+#define RT5682_I2S1_MONO_EN			(0x1 << 7)
+#define RT5682_I2S1_MONO_DIS			(0x0 << 7)
+#define RT5682_I2S2_MONO_MASK			(0x1 << 6)
+#define RT5682_I2S2_MONO_EN			(0x1 << 6)
+#define RT5682_I2S2_MONO_DIS			(0x0 << 6)
+#define RT5682_I2S1_DL_MASK			(0x7 << 4)
+#define RT5682_I2S1_DL_SFT			4
+#define RT5682_I2S1_DL_16			(0x0 << 4)
+#define RT5682_I2S1_DL_20			(0x1 << 4)
+#define RT5682_I2S1_DL_24			(0x2 << 4)
+#define RT5682_I2S1_DL_32			(0x3 << 4)
+#define RT5682_I2S1_DL_8			(0x4 << 4)
+
+/* I2S1/2 Audio Serial Data Port Control (0x0070)(0x0071) */
+#define RT5682_I2S2_MS_MASK			(0x1 << 15)
+#define RT5682_I2S2_MS_SFT			15
+#define RT5682_I2S2_MS_M			(0x0 << 15)
+#define RT5682_I2S2_MS_S			(0x1 << 15)
+#define RT5682_I2S2_PIN_CFG_MASK		(0x1 << 14)
+#define RT5682_I2S2_PIN_CFG_SFT			14
+#define RT5682_I2S2_CLK_SEL_MASK		(0x1 << 11)
+#define RT5682_I2S2_CLK_SEL_SFT			11
+#define RT5682_I2S2_OUT_MASK			(0x1 << 9)
+#define RT5682_I2S2_OUT_SFT			9
+#define RT5682_I2S2_OUT_UM			(0x0 << 9)
+#define RT5682_I2S2_OUT_M			(0x1 << 9)
+#define RT5682_I2S_BP_MASK			(0x1 << 8)
+#define RT5682_I2S_BP_SFT			8
+#define RT5682_I2S_BP_NOR			(0x0 << 8)
+#define RT5682_I2S_BP_INV			(0x1 << 8)
+#define RT5682_I2S2_MONO_EN			(0x1 << 6)
+#define RT5682_I2S2_MONO_DIS			(0x0 << 6)
+#define RT5682_I2S2_DL_MASK			(0x3 << 4)
+#define RT5682_I2S2_DL_SFT			4
+#define RT5682_I2S2_DL_16			(0x0 << 4)
+#define RT5682_I2S2_DL_20			(0x1 << 4)
+#define RT5682_I2S2_DL_24			(0x2 << 4)
+#define RT5682_I2S2_DL_8			(0x3 << 4)
+#define RT5682_I2S_DF_MASK			(0x7)
+#define RT5682_I2S_DF_SFT			0
+#define RT5682_I2S_DF_I2S			(0x0)
+#define RT5682_I2S_DF_LEFT			(0x1)
+#define RT5682_I2S_DF_PCM_A			(0x2)
+#define RT5682_I2S_DF_PCM_B			(0x3)
+#define RT5682_I2S_DF_PCM_A_N			(0x6)
+#define RT5682_I2S_DF_PCM_B_N			(0x7)
+
+/* ADC/DAC Clock Control 1 (0x0073) */
+#define RT5682_ADC_OSR_MASK			(0xf << 12)
+#define RT5682_ADC_OSR_SFT			12
+#define RT5682_ADC_OSR_D_1			(0x0 << 12)
+#define RT5682_ADC_OSR_D_2			(0x1 << 12)
+#define RT5682_ADC_OSR_D_4			(0x2 << 12)
+#define RT5682_ADC_OSR_D_6			(0x3 << 12)
+#define RT5682_ADC_OSR_D_8			(0x4 << 12)
+#define RT5682_ADC_OSR_D_12			(0x5 << 12)
+#define RT5682_ADC_OSR_D_16			(0x6 << 12)
+#define RT5682_ADC_OSR_D_24			(0x7 << 12)
+#define RT5682_ADC_OSR_D_32			(0x8 << 12)
+#define RT5682_ADC_OSR_D_48			(0x9 << 12)
+#define RT5682_I2S_M_DIV_MASK			(0xf << 12)
+#define RT5682_I2S_M_DIV_SFT			8
+#define RT5682_I2S_M_D_1			(0x0 << 8)
+#define RT5682_I2S_M_D_2			(0x1 << 8)
+#define RT5682_I2S_M_D_3			(0x2 << 8)
+#define RT5682_I2S_M_D_4			(0x3 << 8)
+#define RT5682_I2S_M_D_6			(0x4 << 8)
+#define RT5682_I2S_M_D_8			(0x5 << 8)
+#define RT5682_I2S_M_D_12			(0x6 << 8)
+#define RT5682_I2S_M_D_16			(0x7 << 8)
+#define RT5682_I2S_M_D_24			(0x8 << 8)
+#define RT5682_I2S_M_D_32			(0x9 << 8)
+#define RT5682_I2S_M_D_48			(0x10 << 8)
+#define RT5682_I2S_CLK_SRC_MASK			(0x7 << 4)
+#define RT5682_I2S_CLK_SRC_SFT			4
+#define RT5682_I2S_CLK_SRC_MCLK			(0x0 << 4)
+#define RT5682_I2S_CLK_SRC_PLL1			(0x1 << 4)
+#define RT5682_I2S_CLK_SRC_PLL2			(0x2 << 4)
+#define RT5682_I2S_CLK_SRC_SDW			(0x3 << 4)
+#define RT5682_I2S_CLK_SRC_RCCLK		(0x4 << 4) /* 25M */
+#define RT5682_DAC_OSR_MASK			(0xf << 0)
+#define RT5682_DAC_OSR_SFT			0
+#define RT5682_DAC_OSR_D_1			(0x0 << 0)
+#define RT5682_DAC_OSR_D_2			(0x1 << 0)
+#define RT5682_DAC_OSR_D_4			(0x2 << 0)
+#define RT5682_DAC_OSR_D_6			(0x3 << 0)
+#define RT5682_DAC_OSR_D_8			(0x4 << 0)
+#define RT5682_DAC_OSR_D_12			(0x5 << 0)
+#define RT5682_DAC_OSR_D_16			(0x6 << 0)
+#define RT5682_DAC_OSR_D_24			(0x7 << 0)
+#define RT5682_DAC_OSR_D_32			(0x8 << 0)
+#define RT5682_DAC_OSR_D_48			(0x9 << 0)
+
+/* ADC/DAC Clock Control 2 (0x0074) */
+#define RT5682_I2S2_BCLK_MS2_MASK		(0x1 << 11)
+#define RT5682_I2S2_BCLK_MS2_SFT		11
+#define RT5682_I2S2_BCLK_MS2_32			(0x0 << 11)
+#define RT5682_I2S2_BCLK_MS2_64			(0x1 << 11)
+
+
+/* TDM control 1 (0x0079) */
+#define RT5682_TDM_TX_CH_MASK			(0x3 << 12)
+#define RT5682_TDM_TX_CH_2			(0x0 << 12)
+#define RT5682_TDM_TX_CH_4			(0x1 << 12)
+#define RT5682_TDM_TX_CH_6			(0x2 << 12)
+#define RT5682_TDM_TX_CH_8			(0x3 << 12)
+#define RT5682_TDM_RX_CH_MASK			(0x3 << 8)
+#define RT5682_TDM_RX_CH_2			(0x0 << 8)
+#define RT5682_TDM_RX_CH_4			(0x1 << 8)
+#define RT5682_TDM_RX_CH_6			(0x2 << 8)
+#define RT5682_TDM_RX_CH_8			(0x3 << 8)
+#define RT5682_TDM_ADC_LCA_MASK			(0xf << 4)
+#define RT5682_TDM_ADC_LCA_SFT			4
+#define RT5682_TDM_ADC_DL_SFT			0
+
+/* TDM control 2 (0x007a) */
+#define RT5682_IF1_ADC1_SEL_SFT			14
+#define RT5682_IF1_ADC2_SEL_SFT			12
+#define RT5682_IF1_ADC3_SEL_SFT			10
+#define RT5682_IF1_ADC4_SEL_SFT			8
+#define RT5682_TDM_ADC_SEL_SFT			4
+
+/* TDM control 3 (0x007b) */
+#define RT5682_TDM_EN				(0x1 << 7)
+
+/* TDM/I2S control (0x007e) */
+#define RT5682_TDM_S_BP_MASK			(0x1 << 15)
+#define RT5682_TDM_S_BP_SFT			15
+#define RT5682_TDM_S_BP_NOR			(0x0 << 15)
+#define RT5682_TDM_S_BP_INV			(0x1 << 15)
+#define RT5682_TDM_S_LP_MASK			(0x1 << 14)
+#define RT5682_TDM_S_LP_SFT			14
+#define RT5682_TDM_S_LP_NOR			(0x0 << 14)
+#define RT5682_TDM_S_LP_INV			(0x1 << 14)
+#define RT5682_TDM_DF_MASK			(0x7 << 11)
+#define RT5682_TDM_DF_SFT			11
+#define RT5682_TDM_DF_I2S			(0x0 << 11)
+#define RT5682_TDM_DF_LEFT			(0x1 << 11)
+#define RT5682_TDM_DF_PCM_A			(0x2 << 11)
+#define RT5682_TDM_DF_PCM_B			(0x3 << 11)
+#define RT5682_TDM_DF_PCM_A_N			(0x6 << 11)
+#define RT5682_TDM_DF_PCM_B_N			(0x7 << 11)
+#define RT5682_TDM_CL_MASK			(0x3 << 4)
+#define RT5682_TDM_CL_16			(0x0 << 4)
+#define RT5682_TDM_CL_20			(0x1 << 4)
+#define RT5682_TDM_CL_24			(0x2 << 4)
+#define RT5682_TDM_CL_32			(0x3 << 4)
+#define RT5682_TDM_M_BP_MASK			(0x1 << 2)
+#define RT5682_TDM_M_BP_SFT			2
+#define RT5682_TDM_M_BP_NOR			(0x0 << 2)
+#define RT5682_TDM_M_BP_INV			(0x1 << 2)
+#define RT5682_TDM_M_LP_MASK			(0x1 << 1)
+#define RT5682_TDM_M_LP_SFT			1
+#define RT5682_TDM_M_LP_NOR			(0x0 << 1)
+#define RT5682_TDM_M_LP_INV			(0x1 << 1)
+#define RT5682_TDM_MS_MASK			(0x1 << 0)
+#define RT5682_TDM_MS_SFT			0
+#define RT5682_TDM_MS_M				(0x0 << 0)
+#define RT5682_TDM_MS_S				(0x1 << 0)
+
+/* Global Clock Control (0x0080) */
+#define RT5682_SCLK_SRC_MASK			(0x7 << 13)
+#define RT5682_SCLK_SRC_SFT			13
+#define RT5682_SCLK_SRC_MCLK			(0x0 << 13)
+#define RT5682_SCLK_SRC_PLL1			(0x1 << 13)
+#define RT5682_SCLK_SRC_PLL2			(0x2 << 13)
+#define RT5682_SCLK_SRC_SDW			(0x3 << 13)
+#define RT5682_SCLK_SRC_RCCLK			(0x4 << 13)
+#define RT5682_PLL1_SRC_MASK			(0x3 << 10)
+#define RT5682_PLL1_SRC_SFT			10
+#define RT5682_PLL1_SRC_MCLK			(0x0 << 10)
+#define RT5682_PLL1_SRC_BCLK1			(0x1 << 10)
+#define RT5682_PLL1_SRC_SDW			(0x2 << 10)
+#define RT5682_PLL1_SRC_RC			(0x3 << 10)
+#define RT5682_PLL2_SRC_MASK			(0x3 << 8)
+#define RT5682_PLL2_SRC_SFT			8
+#define RT5682_PLL2_SRC_MCLK			(0x0 << 8)
+#define RT5682_PLL2_SRC_BCLK1			(0x1 << 8)
+#define RT5682_PLL2_SRC_SDW			(0x2 << 8)
+#define RT5682_PLL2_SRC_RC			(0x3 << 8)
+
+
+
+#define RT5682_PLL_INP_MAX			40000000
+#define RT5682_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x0081) */
+#define RT5682_PLL_N_MAX			0x001ff
+#define RT5682_PLL_N_MASK			(RT5682_PLL_N_MAX << 7)
+#define RT5682_PLL_N_SFT			7
+#define RT5682_PLL_K_MAX			0x001f
+#define RT5682_PLL_K_MASK			(RT5682_PLL_K_MAX)
+#define RT5682_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x0082) */
+#define RT5682_PLL_M_MAX			0x00f
+#define RT5682_PLL_M_MASK			(RT5682_PLL_M_MAX << 12)
+#define RT5682_PLL_M_SFT			12
+#define RT5682_PLL_M_BP				(0x1 << 11)
+#define RT5682_PLL_M_BP_SFT			11
+#define RT5682_PLL_K_BP				(0x1 << 10)
+#define RT5682_PLL_K_BP_SFT			10
+#define RT5682_PLL_RST				(0x1 << 1)
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5682_DA_ASRC_MASK			(0x1 << 13)
+#define RT5682_DA_ASRC_SFT			13
+#define RT5682_DAC_STO1_ASRC_MASK		(0x1 << 12)
+#define RT5682_DAC_STO1_ASRC_SFT		12
+#define RT5682_AD_ASRC_MASK			(0x1 << 8)
+#define RT5682_AD_ASRC_SFT			8
+#define RT5682_AD_ASRC_SEL_MASK			(0x1 << 4)
+#define RT5682_AD_ASRC_SEL_SFT			4
+#define RT5682_DMIC_ASRC_MASK			(0x1 << 3)
+#define RT5682_DMIC_ASRC_SFT			3
+#define RT5682_ADC_STO1_ASRC_MASK		(0x1 << 2)
+#define RT5682_ADC_STO1_ASRC_SFT		2
+#define RT5682_DA_ASRC_SEL_MASK			(0x1 << 0)
+#define RT5682_DA_ASRC_SEL_SFT			0
+
+/* PLL tracking mode 2 3 (0x0084)(0x0085)*/
+#define RT5682_FILTER_CLK_SEL_MASK		(0x7 << 12)
+#define RT5682_FILTER_CLK_SEL_SFT		12
+#define RT5682_FILTER_CLK_DIV_MASK		(0xf << 8)
+#define RT5682_FILTER_CLK_DIV_SFT		8
+
+/* ASRC Control 4 (0x0086) */
+#define RT5682_ASRCIN_FTK_N1_MASK		(0x3 << 14)
+#define RT5682_ASRCIN_FTK_N1_SFT		14
+#define RT5682_ASRCIN_FTK_N2_MASK		(0x3 << 12)
+#define RT5682_ASRCIN_FTK_N2_SFT		12
+#define RT5682_ASRCIN_FTK_M1_MASK		(0x7 << 8)
+#define RT5682_ASRCIN_FTK_M1_SFT		8
+#define RT5682_ASRCIN_FTK_M2_MASK		(0x7 << 4)
+#define RT5682_ASRCIN_FTK_M2_SFT		4
+
+/* SoundWire reference clk (0x008d) */
+#define RT5682_PLL2_OUT_MASK			(0x1 << 8)
+#define RT5682_PLL2_OUT_98M			(0x0 << 8)
+#define RT5682_PLL2_OUT_49M			(0x1 << 8)
+#define RT5682_SDW_REF_2_MASK			(0xf << 4)
+#define RT5682_SDW_REF_2_SFT			4
+#define RT5682_SDW_REF_2_48K			(0x0 << 4)
+#define RT5682_SDW_REF_2_96K			(0x1 << 4)
+#define RT5682_SDW_REF_2_192K			(0x2 << 4)
+#define RT5682_SDW_REF_2_32K			(0x3 << 4)
+#define RT5682_SDW_REF_2_24K			(0x4 << 4)
+#define RT5682_SDW_REF_2_16K			(0x5 << 4)
+#define RT5682_SDW_REF_2_12K			(0x6 << 4)
+#define RT5682_SDW_REF_2_8K			(0x7 << 4)
+#define RT5682_SDW_REF_2_44K			(0x8 << 4)
+#define RT5682_SDW_REF_2_88K			(0x9 << 4)
+#define RT5682_SDW_REF_2_176K			(0xa << 4)
+#define RT5682_SDW_REF_2_353K			(0xb << 4)
+#define RT5682_SDW_REF_2_22K			(0xc << 4)
+#define RT5682_SDW_REF_2_384K			(0xd << 4)
+#define RT5682_SDW_REF_2_11K			(0xe << 4)
+#define RT5682_SDW_REF_1_MASK			(0xf << 0)
+#define RT5682_SDW_REF_1_SFT			0
+#define RT5682_SDW_REF_1_48K			(0x0 << 0)
+#define RT5682_SDW_REF_1_96K			(0x1 << 0)
+#define RT5682_SDW_REF_1_192K			(0x2 << 0)
+#define RT5682_SDW_REF_1_32K			(0x3 << 0)
+#define RT5682_SDW_REF_1_24K			(0x4 << 0)
+#define RT5682_SDW_REF_1_16K			(0x5 << 0)
+#define RT5682_SDW_REF_1_12K			(0x6 << 0)
+#define RT5682_SDW_REF_1_8K			(0x7 << 0)
+#define RT5682_SDW_REF_1_44K			(0x8 << 0)
+#define RT5682_SDW_REF_1_88K			(0x9 << 0)
+#define RT5682_SDW_REF_1_176K			(0xa << 0)
+#define RT5682_SDW_REF_1_353K			(0xb << 0)
+#define RT5682_SDW_REF_1_22K			(0xc << 0)
+#define RT5682_SDW_REF_1_384K			(0xd << 0)
+#define RT5682_SDW_REF_1_11K			(0xe << 0)
+
+/* Depop Mode Control 1 (0x008e) */
+#define RT5682_PUMP_EN				(0x1 << 3)
+#define RT5682_PUMP_EN_SFT				3
+#define RT5682_CAPLESS_EN			(0x1 << 0)
+#define RT5682_CAPLESS_EN_SFT			0
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5682_RAMP_MASK			(0x1 << 12)
+#define RT5682_RAMP_SFT				12
+#define RT5682_RAMP_DIS				(0x0 << 12)
+#define RT5682_RAMP_EN				(0x1 << 12)
+#define RT5682_BPS_MASK				(0x1 << 11)
+#define RT5682_BPS_SFT				11
+#define RT5682_BPS_DIS				(0x0 << 11)
+#define RT5682_BPS_EN				(0x1 << 11)
+#define RT5682_FAST_UPDN_MASK			(0x1 << 10)
+#define RT5682_FAST_UPDN_SFT			10
+#define RT5682_FAST_UPDN_DIS			(0x0 << 10)
+#define RT5682_FAST_UPDN_EN			(0x1 << 10)
+#define RT5682_VLO_MASK				(0x1 << 7)
+#define RT5682_VLO_SFT				7
+#define RT5682_VLO_3V				(0x0 << 7)
+#define RT5682_VLO_33V				(0x1 << 7)
+
+/* HPOUT charge pump 1 (0x0091) */
+#define RT5682_OSW_L_MASK			(0x1 << 11)
+#define RT5682_OSW_L_SFT			11
+#define RT5682_OSW_L_DIS			(0x0 << 11)
+#define RT5682_OSW_L_EN				(0x1 << 11)
+#define RT5682_OSW_R_MASK			(0x1 << 10)
+#define RT5682_OSW_R_SFT			10
+#define RT5682_OSW_R_DIS			(0x0 << 10)
+#define RT5682_OSW_R_EN				(0x1 << 10)
+#define RT5682_PM_HP_MASK			(0x3 << 8)
+#define RT5682_PM_HP_SFT			8
+#define RT5682_PM_HP_LV				(0x0 << 8)
+#define RT5682_PM_HP_MV				(0x1 << 8)
+#define RT5682_PM_HP_HV				(0x2 << 8)
+#define RT5682_IB_HP_MASK			(0x3 << 6)
+#define RT5682_IB_HP_SFT			6
+#define RT5682_IB_HP_125IL			(0x0 << 6)
+#define RT5682_IB_HP_25IL			(0x1 << 6)
+#define RT5682_IB_HP_5IL			(0x2 << 6)
+#define RT5682_IB_HP_1IL			(0x3 << 6)
+
+/* Micbias Control1 (0x93) */
+#define RT5682_MIC1_OV_MASK			(0x3 << 14)
+#define RT5682_MIC1_OV_SFT			14
+#define RT5682_MIC1_OV_2V7			(0x0 << 14)
+#define RT5682_MIC1_OV_2V4			(0x1 << 14)
+#define RT5682_MIC1_OV_2V25			(0x3 << 14)
+#define RT5682_MIC1_OV_1V8			(0x4 << 14)
+#define RT5682_MIC1_CLK_MASK			(0x1 << 13)
+#define RT5682_MIC1_CLK_SFT			13
+#define RT5682_MIC1_CLK_DIS			(0x0 << 13)
+#define RT5682_MIC1_CLK_EN			(0x1 << 13)
+#define RT5682_MIC1_OVCD_MASK			(0x1 << 12)
+#define RT5682_MIC1_OVCD_SFT			12
+#define RT5682_MIC1_OVCD_DIS			(0x0 << 12)
+#define RT5682_MIC1_OVCD_EN			(0x1 << 12)
+#define RT5682_MIC1_OVTH_MASK			(0x3 << 10)
+#define RT5682_MIC1_OVTH_SFT			10
+#define RT5682_MIC1_OVTH_768UA			(0x0 << 10)
+#define RT5682_MIC1_OVTH_960UA			(0x1 << 10)
+#define RT5682_MIC1_OVTH_1152UA			(0x2 << 10)
+#define RT5682_MIC1_OVTH_1960UA			(0x3 << 10)
+#define RT5682_MIC2_OV_MASK			(0x3 << 8)
+#define RT5682_MIC2_OV_SFT			8
+#define RT5682_MIC2_OV_2V7			(0x0 << 8)
+#define RT5682_MIC2_OV_2V4			(0x1 << 8)
+#define RT5682_MIC2_OV_2V25			(0x3 << 8)
+#define RT5682_MIC2_OV_1V8			(0x4 << 8)
+#define RT5682_MIC2_CLK_MASK			(0x1 << 7)
+#define RT5682_MIC2_CLK_SFT			7
+#define RT5682_MIC2_CLK_DIS			(0x0 << 7)
+#define RT5682_MIC2_CLK_EN			(0x1 << 7)
+#define RT5682_MIC2_OVTH_MASK			(0x3 << 4)
+#define RT5682_MIC2_OVTH_SFT			4
+#define RT5682_MIC2_OVTH_768UA			(0x0 << 4)
+#define RT5682_MIC2_OVTH_960UA			(0x1 << 4)
+#define RT5682_MIC2_OVTH_1152UA			(0x2 << 4)
+#define RT5682_MIC2_OVTH_1960UA			(0x3 << 4)
+#define RT5682_PWR_MB_MASK			(0x1 << 3)
+#define RT5682_PWR_MB_SFT			3
+#define RT5682_PWR_MB_PD			(0x0 << 3)
+#define RT5682_PWR_MB_PU			(0x1 << 3)
+
+/* Micbias Control2 (0x0094) */
+#define RT5682_PWR_CLK25M_MASK			(0x1 << 9)
+#define RT5682_PWR_CLK25M_SFT			9
+#define RT5682_PWR_CLK25M_PD			(0x0 << 9)
+#define RT5682_PWR_CLK25M_PU			(0x1 << 9)
+#define RT5682_PWR_CLK1M_MASK			(0x1 << 8)
+#define RT5682_PWR_CLK1M_SFT			8
+#define RT5682_PWR_CLK1M_PD			(0x0 << 8)
+#define RT5682_PWR_CLK1M_PU			(0x1 << 8)
+
+/* RC Clock Control (0x009f) */
+#define RT5682_POW_IRQ				(0x1 << 15)
+#define RT5682_POW_JDH				(0x1 << 14)
+#define RT5682_POW_JDL				(0x1 << 13)
+#define RT5682_POW_ANA				(0x1 << 12)
+
+/* I2S Master Mode Clock Control 1 (0x00a0) */
+#define RT5682_CLK_SRC_MCLK			(0x0)
+#define RT5682_CLK_SRC_PLL1			(0x1)
+#define RT5682_CLK_SRC_PLL2			(0x2)
+#define RT5682_CLK_SRC_SDW			(0x3)
+#define RT5682_CLK_SRC_RCCLK			(0x4)
+#define RT5682_I2S_PD_1				(0x0)
+#define RT5682_I2S_PD_2				(0x1)
+#define RT5682_I2S_PD_3				(0x2)
+#define RT5682_I2S_PD_4				(0x3)
+#define RT5682_I2S_PD_6				(0x4)
+#define RT5682_I2S_PD_8				(0x5)
+#define RT5682_I2S_PD_12			(0x6)
+#define RT5682_I2S_PD_16			(0x7)
+#define RT5682_I2S_PD_24			(0x8)
+#define RT5682_I2S_PD_32			(0x9)
+#define RT5682_I2S_PD_48			(0xa)
+#define RT5682_I2S2_SRC_MASK			(0x3 << 4)
+#define RT5682_I2S2_SRC_SFT			4
+#define RT5682_I2S2_M_PD_MASK			(0xf << 0)
+#define RT5682_I2S2_M_PD_SFT			0
+
+/* IRQ Control 1 (0x00b6) */
+#define RT5682_JD1_PULSE_EN_MASK		(0x1 << 10)
+#define RT5682_JD1_PULSE_EN_SFT			10
+#define RT5682_JD1_PULSE_DIS			(0x0 << 10)
+#define RT5682_JD1_PULSE_EN			(0x1 << 10)
+
+/* IRQ Control 2 (0x00b7) */
+#define RT5682_JD1_EN_MASK			(0x1 << 15)
+#define RT5682_JD1_EN_SFT			15
+#define RT5682_JD1_DIS				(0x0 << 15)
+#define RT5682_JD1_EN				(0x1 << 15)
+#define RT5682_JD1_POL_MASK			(0x1 << 13)
+#define RT5682_JD1_POL_NOR			(0x0 << 13)
+#define RT5682_JD1_POL_INV			(0x1 << 13)
+
+/* IRQ Control 3 (0x00b8) */
+#define RT5682_IL_IRQ_MASK			(0x1 << 7)
+#define RT5682_IL_IRQ_DIS			(0x0 << 7)
+#define RT5682_IL_IRQ_EN			(0x1 << 7)
+
+/* GPIO Control 1 (0x00c0) */
+#define RT5682_GP1_PIN_MASK			(0x3 << 14)
+#define RT5682_GP1_PIN_SFT			14
+#define RT5682_GP1_PIN_GPIO1			(0x0 << 14)
+#define RT5682_GP1_PIN_IRQ			(0x1 << 14)
+#define RT5682_GP1_PIN_DMIC_CLK			(0x2 << 14)
+#define RT5682_GP2_PIN_MASK			(0x3 << 12)
+#define RT5682_GP2_PIN_SFT			12
+#define RT5682_GP2_PIN_GPIO2			(0x0 << 12)
+#define RT5682_GP2_PIN_LRCK2			(0x1 << 12)
+#define RT5682_GP2_PIN_DMIC_SDA			(0x2 << 12)
+#define RT5682_GP3_PIN_MASK			(0x3 << 10)
+#define RT5682_GP3_PIN_SFT			10
+#define RT5682_GP3_PIN_GPIO3			(0x0 << 10)
+#define RT5682_GP3_PIN_BCLK2			(0x1 << 10)
+#define RT5682_GP3_PIN_DMIC_CLK			(0x2 << 10)
+#define RT5682_GP4_PIN_MASK			(0x3 << 8)
+#define RT5682_GP4_PIN_SFT			8
+#define RT5682_GP4_PIN_GPIO4			(0x0 << 8)
+#define RT5682_GP4_PIN_ADCDAT1			(0x1 << 8)
+#define RT5682_GP4_PIN_DMIC_CLK			(0x2 << 8)
+#define RT5682_GP4_PIN_ADCDAT2			(0x3 << 8)
+#define RT5682_GP5_PIN_MASK			(0x3 << 6)
+#define RT5682_GP5_PIN_SFT			6
+#define RT5682_GP5_PIN_GPIO5			(0x0 << 6)
+#define RT5682_GP5_PIN_DACDAT1			(0x1 << 6)
+#define RT5682_GP5_PIN_DMIC_SDA			(0x2 << 6)
+#define RT5682_GP6_PIN_MASK			(0x1 << 5)
+#define RT5682_GP6_PIN_SFT			5
+#define RT5682_GP6_PIN_GPIO6			(0x0 << 5)
+#define RT5682_GP6_PIN_LRCK1			(0x1 << 5)
+
+/* GPIO Control 2 (0x00c1)*/
+#define RT5682_GP1_PF_MASK			(0x1 << 15)
+#define RT5682_GP1_PF_IN			(0x0 << 15)
+#define RT5682_GP1_PF_OUT			(0x1 << 15)
+#define RT5682_GP1_OUT_MASK			(0x1 << 14)
+#define RT5682_GP1_OUT_L			(0x0 << 14)
+#define RT5682_GP1_OUT_H			(0x1 << 14)
+#define RT5682_GP2_PF_MASK			(0x1 << 13)
+#define RT5682_GP2_PF_IN			(0x0 << 13)
+#define RT5682_GP2_PF_OUT			(0x1 << 13)
+#define RT5682_GP2_OUT_MASK			(0x1 << 12)
+#define RT5682_GP2_OUT_L			(0x0 << 12)
+#define RT5682_GP2_OUT_H			(0x1 << 12)
+#define RT5682_GP3_PF_MASK			(0x1 << 11)
+#define RT5682_GP3_PF_IN			(0x0 << 11)
+#define RT5682_GP3_PF_OUT			(0x1 << 11)
+#define RT5682_GP3_OUT_MASK			(0x1 << 10)
+#define RT5682_GP3_OUT_L			(0x0 << 10)
+#define RT5682_GP3_OUT_H			(0x1 << 10)
+#define RT5682_GP4_PF_MASK			(0x1 << 9)
+#define RT5682_GP4_PF_IN			(0x0 << 9)
+#define RT5682_GP4_PF_OUT			(0x1 << 9)
+#define RT5682_GP4_OUT_MASK			(0x1 << 8)
+#define RT5682_GP4_OUT_L			(0x0 << 8)
+#define RT5682_GP4_OUT_H			(0x1 << 8)
+#define RT5682_GP5_PF_MASK			(0x1 << 7)
+#define RT5682_GP5_PF_IN			(0x0 << 7)
+#define RT5682_GP5_PF_OUT			(0x1 << 7)
+#define RT5682_GP5_OUT_MASK			(0x1 << 6)
+#define RT5682_GP5_OUT_L			(0x0 << 6)
+#define RT5682_GP5_OUT_H			(0x1 << 6)
+#define RT5682_GP6_PF_MASK			(0x1 << 5)
+#define RT5682_GP6_PF_IN			(0x0 << 5)
+#define RT5682_GP6_PF_OUT			(0x1 << 5)
+#define RT5682_GP6_OUT_MASK			(0x1 << 4)
+#define RT5682_GP6_OUT_L			(0x0 << 4)
+#define RT5682_GP6_OUT_H			(0x1 << 4)
+
+
+/* GPIO Status (0x00c2) */
+#define RT5682_GP6_STA				(0x1 << 6)
+#define RT5682_GP5_STA				(0x1 << 5)
+#define RT5682_GP4_STA				(0x1 << 4)
+#define RT5682_GP3_STA				(0x1 << 3)
+#define RT5682_GP2_STA				(0x1 << 2)
+#define RT5682_GP1_STA				(0x1 << 1)
+
+/* Soft volume and zero cross control 1 (0x00d9) */
+#define RT5682_SV_MASK				(0x1 << 15)
+#define RT5682_SV_SFT				15
+#define RT5682_SV_DIS				(0x0 << 15)
+#define RT5682_SV_EN				(0x1 << 15)
+#define RT5682_ZCD_MASK				(0x1 << 10)
+#define RT5682_ZCD_SFT				10
+#define RT5682_ZCD_PD				(0x0 << 10)
+#define RT5682_ZCD_PU				(0x1 << 10)
+#define RT5682_SV_DLY_MASK			(0xf)
+#define RT5682_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0x00da) */
+#define RT5682_ZCD_BST1_CBJ_MASK		(0x1 << 7)
+#define RT5682_ZCD_BST1_CBJ_SFT			7
+#define RT5682_ZCD_BST1_CBJ_DIS			(0x0 << 7)
+#define RT5682_ZCD_BST1_CBJ_EN			(0x1 << 7)
+#define RT5682_ZCD_RECMIX_MASK			(0x1)
+#define RT5682_ZCD_RECMIX_SFT			0
+#define RT5682_ZCD_RECMIX_DIS			(0x0)
+#define RT5682_ZCD_RECMIX_EN			(0x1)
+
+/* 4 Button Inline Command Control 2 (0x00e3) */
+#define RT5682_4BTN_IL_MASK			(0x1 << 15)
+#define RT5682_4BTN_IL_EN			(0x1 << 15)
+#define RT5682_4BTN_IL_DIS			(0x0 << 15)
+#define RT5682_4BTN_IL_RST_MASK			(0x1 << 14)
+#define RT5682_4BTN_IL_NOR			(0x1 << 14)
+#define RT5682_4BTN_IL_RST			(0x0 << 14)
+
+/* Analog JD Control (0x00f0) */
+#define RT5682_JDH_RS_MASK			(0x1 << 4)
+#define RT5682_JDH_NO_PLUG			(0x1 << 4)
+#define RT5682_JDH_PLUG				(0x0 << 4)
+
+/* Chopper and Clock control for DAC (0x013a)*/
+#define RT5682_CKXEN_DAC1_MASK			(0x1 << 13)
+#define RT5682_CKXEN_DAC1_SFT			13
+#define RT5682_CKGEN_DAC1_MASK			(0x1 << 12)
+#define RT5682_CKGEN_DAC1_SFT			12
+
+/* Chopper and Clock control for ADC (0x013b)*/
+#define RT5682_CKXEN_ADC1_MASK			(0x1 << 13)
+#define RT5682_CKXEN_ADC1_SFT			13
+#define RT5682_CKGEN_ADC1_MASK			(0x1 << 12)
+#define RT5682_CKGEN_ADC1_SFT			12
+
+/* Volume test (0x013f)*/
+#define RT5682_SEL_CLK_VOL_MASK			(0x1 << 15)
+#define RT5682_SEL_CLK_VOL_EN			(0x1 << 15)
+#define RT5682_SEL_CLK_VOL_DIS			(0x0 << 15)
+
+/* Test Mode Control 1 (0x0145) */
+#define RT5682_AD2DA_LB_MASK			(0x1 << 10)
+#define RT5682_AD2DA_LB_SFT			10
+
+/* Stereo Noise Gate Control 1 (0x0160) */
+#define RT5682_NG2_EN_MASK			(0x1 << 15)
+#define RT5682_NG2_EN				(0x1 << 15)
+#define RT5682_NG2_DIS				(0x0 << 15)
+
+/* Stereo1 DAC Silence Detection Control (0x0190) */
+#define RT5682_DEB_STO_DAC_MASK			(0x7 << 4)
+#define RT5682_DEB_80_MS			(0x0 << 4)
+
+/* SAR ADC Inline Command Control 1 (0x0210) */
+#define RT5682_SAR_BUTT_DET_MASK		(0x1 << 15)
+#define RT5682_SAR_BUTT_DET_EN			(0x1 << 15)
+#define RT5682_SAR_BUTT_DET_DIS			(0x0 << 15)
+#define RT5682_SAR_BUTDET_MODE_MASK		(0x1 << 14)
+#define RT5682_SAR_BUTDET_POW_SAV		(0x1 << 14)
+#define RT5682_SAR_BUTDET_POW_NORM		(0x0 << 14)
+#define RT5682_SAR_BUTDET_RST_MASK		(0x1 << 13)
+#define RT5682_SAR_BUTDET_RST_NORMAL		(0x1 << 13)
+#define RT5682_SAR_BUTDET_RST			(0x0 << 13)
+#define RT5682_SAR_POW_MASK			(0x1 << 12)
+#define RT5682_SAR_POW_EN			(0x1 << 12)
+#define RT5682_SAR_POW_DIS			(0x0 << 12)
+#define RT5682_SAR_RST_MASK			(0x1 << 11)
+#define RT5682_SAR_RST_NORMAL			(0x1 << 11)
+#define RT5682_SAR_RST				(0x0 << 11)
+#define RT5682_SAR_BYPASS_MASK			(0x1 << 10)
+#define RT5682_SAR_BYPASS_EN			(0x1 << 10)
+#define RT5682_SAR_BYPASS_DIS			(0x0 << 10)
+#define RT5682_SAR_SEL_MB1_MASK			(0x1 << 9)
+#define RT5682_SAR_SEL_MB1_SEL			(0x1 << 9)
+#define RT5682_SAR_SEL_MB1_NOSEL		(0x0 << 9)
+#define RT5682_SAR_SEL_MB2_MASK			(0x1 << 8)
+#define RT5682_SAR_SEL_MB2_SEL			(0x1 << 8)
+#define RT5682_SAR_SEL_MB2_NOSEL		(0x0 << 8)
+#define RT5682_SAR_SEL_MODE_MASK		(0x1 << 7)
+#define RT5682_SAR_SEL_MODE_CMP			(0x1 << 7)
+#define RT5682_SAR_SEL_MODE_ADC			(0x0 << 7)
+#define RT5682_SAR_SEL_MB1_MB2_MASK		(0x1 << 5)
+#define RT5682_SAR_SEL_MB1_MB2_AUTO		(0x1 << 5)
+#define RT5682_SAR_SEL_MB1_MB2_MANU		(0x0 << 5)
+#define RT5682_SAR_SEL_SIGNAL_MASK		(0x1 << 4)
+#define RT5682_SAR_SEL_SIGNAL_AUTO		(0x1 << 4)
+#define RT5682_SAR_SEL_SIGNAL_MANU		(0x0 << 4)
+
+/* SAR ADC Inline Command Control 13 (0x021c) */
+#define RT5682_SAR_SOUR_MASK			(0x3f)
+#define RT5682_SAR_SOUR_BTN			(0x3f)
+#define RT5682_SAR_SOUR_TYPE			(0x0)
+
+
+/* System Clock Source */
+enum {
+	RT5682_SCLK_S_MCLK,
+	RT5682_SCLK_S_PLL1,
+	RT5682_SCLK_S_PLL2,
+	RT5682_SCLK_S_RCCLK,
+};
+
+/* PLL Source */
+enum {
+	RT5682_PLL1_S_MCLK,
+	RT5682_PLL1_S_BCLK1,
+	RT5682_PLL1_S_RCCLK,
+};
+
+enum {
+	RT5682_AIF1,
+	RT5682_AIF2,
+	RT5682_AIFS
+};
+
+/* filter mask */
+enum {
+	RT5682_DA_STEREO1_FILTER = 0x1,
+	RT5682_AD_STEREO1_FILTER = (0x1 << 1),
+};
+
+enum {
+	RT5682_CLK_SEL_SYS,
+	RT5682_CLK_SEL_I2S1_ASRC,
+	RT5682_CLK_SEL_I2S2_ASRC,
+};
+
+int rt5682_sel_asrc_clk_src(struct snd_soc_component *component,
+		unsigned int filter_mask, unsigned int clk_src);
+
+#endif /* __RT5682_H__ */
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
new file mode 100644
index 0000000..60764f6
--- /dev/null
+++ b/sound/soc/codecs/sgtl5000.c
@@ -0,0 +1,1603 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// sgtl5000.c  --  SGTL5000 ALSA SoC Audio driver
+//
+// Copyright 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/log2.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/tlv.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "sgtl5000.h"
+
+#define SGTL5000_DAP_REG_OFFSET	0x0100
+#define SGTL5000_MAX_REG_OFFSET	0x013A
+
+/* default value of sgtl5000 registers */
+static const struct reg_default sgtl5000_reg_defaults[] = {
+	{ SGTL5000_CHIP_DIG_POWER,		0x0000 },
+	{ SGTL5000_CHIP_I2S_CTRL,		0x0010 },
+	{ SGTL5000_CHIP_SSS_CTRL,		0x0010 },
+	{ SGTL5000_CHIP_ADCDAC_CTRL,		0x020c },
+	{ SGTL5000_CHIP_DAC_VOL,		0x3c3c },
+	{ SGTL5000_CHIP_PAD_STRENGTH,		0x015f },
+	{ SGTL5000_CHIP_ANA_ADC_CTRL,		0x0000 },
+	{ SGTL5000_CHIP_ANA_HP_CTRL,		0x1818 },
+	{ SGTL5000_CHIP_ANA_CTRL,		0x0111 },
+	{ SGTL5000_CHIP_REF_CTRL,		0x0000 },
+	{ SGTL5000_CHIP_MIC_CTRL,		0x0000 },
+	{ SGTL5000_CHIP_LINE_OUT_CTRL,		0x0000 },
+	{ SGTL5000_CHIP_LINE_OUT_VOL,		0x0404 },
+	{ SGTL5000_CHIP_PLL_CTRL,		0x5000 },
+	{ SGTL5000_CHIP_CLK_TOP_CTRL,		0x0000 },
+	{ SGTL5000_CHIP_ANA_STATUS,		0x0000 },
+	{ SGTL5000_CHIP_SHORT_CTRL,		0x0000 },
+	{ SGTL5000_CHIP_ANA_TEST2,		0x0000 },
+	{ SGTL5000_DAP_CTRL,			0x0000 },
+	{ SGTL5000_DAP_PEQ,			0x0000 },
+	{ SGTL5000_DAP_BASS_ENHANCE,		0x0040 },
+	{ SGTL5000_DAP_BASS_ENHANCE_CTRL,	0x051f },
+	{ SGTL5000_DAP_AUDIO_EQ,		0x0000 },
+	{ SGTL5000_DAP_SURROUND,		0x0040 },
+	{ SGTL5000_DAP_EQ_BASS_BAND0,		0x002f },
+	{ SGTL5000_DAP_EQ_BASS_BAND1,		0x002f },
+	{ SGTL5000_DAP_EQ_BASS_BAND2,		0x002f },
+	{ SGTL5000_DAP_EQ_BASS_BAND3,		0x002f },
+	{ SGTL5000_DAP_EQ_BASS_BAND4,		0x002f },
+	{ SGTL5000_DAP_MAIN_CHAN,		0x8000 },
+	{ SGTL5000_DAP_MIX_CHAN,		0x0000 },
+	{ SGTL5000_DAP_AVC_CTRL,		0x0510 },
+	{ SGTL5000_DAP_AVC_THRESHOLD,		0x1473 },
+	{ SGTL5000_DAP_AVC_ATTACK,		0x0028 },
+	{ SGTL5000_DAP_AVC_DECAY,		0x0050 },
+};
+
+/* AVC: Threshold dB -> register: pre-calculated values */
+static const u16 avc_thr_db2reg[97] = {
+	0x5168, 0x488E, 0x40AA, 0x39A1, 0x335D, 0x2DC7, 0x28CC, 0x245D, 0x2068,
+	0x1CE2, 0x19BE, 0x16F1, 0x1472, 0x1239, 0x103E, 0x0E7A, 0x0CE6, 0x0B7F,
+	0x0A3F, 0x0922, 0x0824, 0x0741, 0x0677, 0x05C3, 0x0522, 0x0493, 0x0414,
+	0x03A2, 0x033D, 0x02E3, 0x0293, 0x024B, 0x020B, 0x01D2, 0x019F, 0x0172,
+	0x014A, 0x0126, 0x0106, 0x00E9, 0x00D0, 0x00B9, 0x00A5, 0x0093, 0x0083,
+	0x0075, 0x0068, 0x005D, 0x0052, 0x0049, 0x0041, 0x003A, 0x0034, 0x002E,
+	0x0029, 0x0025, 0x0021, 0x001D, 0x001A, 0x0017, 0x0014, 0x0012, 0x0010,
+	0x000E, 0x000D, 0x000B, 0x000A, 0x0009, 0x0008, 0x0007, 0x0006, 0x0005,
+	0x0005, 0x0004, 0x0004, 0x0003, 0x0003, 0x0002, 0x0002, 0x0002, 0x0002,
+	0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
+
+/* regulator supplies for sgtl5000, VDDD is an optional external supply */
+enum sgtl5000_regulator_supplies {
+	VDDA,
+	VDDIO,
+	VDDD,
+	SGTL5000_SUPPLY_NUM
+};
+
+/* vddd is optional supply */
+static const char *supply_names[SGTL5000_SUPPLY_NUM] = {
+	"VDDA",
+	"VDDIO",
+	"VDDD"
+};
+
+#define LDO_VOLTAGE		1200000
+#define LINREG_VDDD	((1600 - LDO_VOLTAGE / 1000) / 50)
+
+enum sgtl5000_micbias_resistor {
+	SGTL5000_MICBIAS_OFF = 0,
+	SGTL5000_MICBIAS_2K = 2,
+	SGTL5000_MICBIAS_4K = 4,
+	SGTL5000_MICBIAS_8K = 8,
+};
+
+enum  {
+	I2S_LRCLK_STRENGTH_DISABLE,
+	I2S_LRCLK_STRENGTH_LOW,
+	I2S_LRCLK_STRENGTH_MEDIUM,
+	I2S_LRCLK_STRENGTH_HIGH,
+};
+
+/* sgtl5000 private structure in codec */
+struct sgtl5000_priv {
+	int sysclk;	/* sysclk rate */
+	int master;	/* i2s master or not */
+	int fmt;	/* i2s data format */
+	struct regulator_bulk_data supplies[SGTL5000_SUPPLY_NUM];
+	int num_supplies;
+	struct regmap *regmap;
+	struct clk *mclk;
+	int revision;
+	u8 micbias_resistor;
+	u8 micbias_voltage;
+	u8 lrclk_strength;
+};
+
+/*
+ * mic_bias power on/off share the same register bits with
+ * output impedance of mic bias, when power on mic bias, we
+ * need reclaim it to impedance value.
+ * 0x0 = Powered off
+ * 0x1 = 2Kohm
+ * 0x2 = 4Kohm
+ * 0x3 = 8Kohm
+ */
+static int mic_bias_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* change mic bias resistor */
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_MIC_CTRL,
+			SGTL5000_BIAS_R_MASK,
+			sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_MIC_CTRL,
+				SGTL5000_BIAS_R_MASK, 0);
+		break;
+	}
+	return 0;
+}
+
+/*
+ * As manual described, ADC/DAC only works when VAG powerup,
+ * So enabled VAG before ADC/DAC up.
+ * In power down case, we need wait 400ms when vag fully ramped down.
+ */
+static int power_vag_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	const u32 mask = SGTL5000_DAC_POWERUP | SGTL5000_ADC_POWERUP;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
+			SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
+		msleep(400);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		/*
+		 * Don't clear VAG_POWERUP, when both DAC and ADC are
+		 * operational to prevent inadvertently starving the
+		 * other one of them.
+		 */
+		if ((snd_soc_component_read32(component, SGTL5000_CHIP_ANA_POWER) &
+				mask) != mask) {
+			snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
+				SGTL5000_VAG_POWERUP, 0);
+			msleep(400);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/* input sources for ADC */
+static const char *adc_mux_text[] = {
+	"MIC_IN", "LINE_IN"
+};
+
+static SOC_ENUM_SINGLE_DECL(adc_enum,
+			    SGTL5000_CHIP_ANA_CTRL, 2,
+			    adc_mux_text);
+
+static const struct snd_kcontrol_new adc_mux =
+SOC_DAPM_ENUM("Capture Mux", adc_enum);
+
+/* input sources for headphone */
+static const char *hp_mux_text[] = {
+	"DAC", "LINE_IN"
+};
+
+static SOC_ENUM_SINGLE_DECL(hp_enum,
+			    SGTL5000_CHIP_ANA_CTRL, 6,
+			    hp_mux_text);
+
+static const struct snd_kcontrol_new hp_mux =
+SOC_DAPM_ENUM("Headphone Mux", hp_enum);
+
+/* input sources for DAC */
+static const char *dac_mux_text[] = {
+	"ADC", "I2S", "Rsvrd", "DAP"
+};
+
+static SOC_ENUM_SINGLE_DECL(dac_enum,
+			    SGTL5000_CHIP_SSS_CTRL, SGTL5000_DAC_SEL_SHIFT,
+			    dac_mux_text);
+
+static const struct snd_kcontrol_new dac_mux =
+SOC_DAPM_ENUM("Digital Input Mux", dac_enum);
+
+/* input sources for DAP */
+static const char *dap_mux_text[] = {
+	"ADC", "I2S"
+};
+
+static SOC_ENUM_SINGLE_DECL(dap_enum,
+			    SGTL5000_CHIP_SSS_CTRL, SGTL5000_DAP_SEL_SHIFT,
+			    dap_mux_text);
+
+static const struct snd_kcontrol_new dap_mux =
+SOC_DAPM_ENUM("DAP Mux", dap_enum);
+
+/* input sources for DAP mix */
+static const char *dapmix_mux_text[] = {
+	"ADC", "I2S"
+};
+
+static SOC_ENUM_SINGLE_DECL(dapmix_enum,
+			    SGTL5000_CHIP_SSS_CTRL, SGTL5000_DAP_MIX_SEL_SHIFT,
+			    dapmix_mux_text);
+
+static const struct snd_kcontrol_new dapmix_mux =
+SOC_DAPM_ENUM("DAP MIX Mux", dapmix_enum);
+
+
+static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("LINE_IN"),
+	SND_SOC_DAPM_INPUT("MIC_IN"),
+
+	SND_SOC_DAPM_OUTPUT("HP_OUT"),
+	SND_SOC_DAPM_OUTPUT("LINE_OUT"),
+
+	SND_SOC_DAPM_SUPPLY("Mic Bias", SGTL5000_CHIP_MIC_CTRL, 8, 0,
+			    mic_bias_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_PGA("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, &adc_mux),
+	SND_SOC_DAPM_MUX("Headphone Mux", SND_SOC_NOPM, 0, 0, &hp_mux),
+	SND_SOC_DAPM_MUX("Digital Input Mux", SND_SOC_NOPM, 0, 0, &dac_mux),
+	SND_SOC_DAPM_MUX("DAP Mux", SGTL5000_DAP_CTRL, 0, 0, &dap_mux),
+	SND_SOC_DAPM_MUX("DAP MIX Mux", SGTL5000_DAP_CTRL, 4, 0, &dapmix_mux),
+	SND_SOC_DAPM_MIXER("DAP", SGTL5000_CHIP_DIG_POWER, 4, 0, NULL, 0),
+
+
+	/* aif for i2s input */
+	SND_SOC_DAPM_AIF_IN("AIFIN", "Playback",
+				0, SGTL5000_CHIP_DIG_POWER,
+				0, 0),
+
+	/* aif for i2s output */
+	SND_SOC_DAPM_AIF_OUT("AIFOUT", "Capture",
+				0, SGTL5000_CHIP_DIG_POWER,
+				1, 0),
+
+	SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0),
+	SND_SOC_DAPM_DAC("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0),
+
+	SND_SOC_DAPM_PRE("VAG_POWER_PRE", power_vag_event),
+	SND_SOC_DAPM_POST("VAG_POWER_POST", power_vag_event),
+};
+
+/* routes for sgtl5000 */
+static const struct snd_soc_dapm_route sgtl5000_dapm_routes[] = {
+	{"Capture Mux", "LINE_IN", "LINE_IN"},	/* line_in --> adc_mux */
+	{"Capture Mux", "MIC_IN", "MIC_IN"},	/* mic_in --> adc_mux */
+
+	{"ADC", NULL, "Capture Mux"},		/* adc_mux --> adc */
+	{"AIFOUT", NULL, "ADC"},		/* adc --> i2s_out */
+
+	{"DAP Mux", "ADC", "ADC"},		/* adc --> DAP mux */
+	{"DAP Mux", NULL, "AIFIN"},		/* i2s --> DAP mux */
+	{"DAP", NULL, "DAP Mux"},		/* DAP mux --> dap */
+
+	{"DAP MIX Mux", "ADC", "ADC"},		/* adc --> DAP MIX mux */
+	{"DAP MIX Mux", NULL, "AIFIN"},		/* i2s --> DAP MIX mux */
+	{"DAP", NULL, "DAP MIX Mux"},		/* DAP MIX mux --> dap */
+
+	{"Digital Input Mux", "ADC", "ADC"},	/* adc --> audio mux */
+	{"Digital Input Mux", NULL, "AIFIN"},	/* i2s --> audio mux */
+	{"Digital Input Mux", NULL, "DAP"},	/* dap --> audio mux */
+	{"DAC", NULL, "Digital Input Mux"},	/* audio mux --> dac */
+
+	{"Headphone Mux", "DAC", "DAC"},	/* dac --> hp_mux */
+	{"LO", NULL, "DAC"},			/* dac --> line_out */
+
+	{"Headphone Mux", "LINE_IN", "LINE_IN"},/* line_in --> hp_mux */
+	{"HP", NULL, "Headphone Mux"},		/* hp_mux --> hp */
+
+	{"LINE_OUT", NULL, "LO"},
+	{"HP_OUT", NULL, "HP"},
+};
+
+/* custom function to fetch info of PCM playback volume */
+static int dac_info_volsw(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xfc - 0x3c;
+	return 0;
+}
+
+/*
+ * custom function to get of PCM playback volume
+ *
+ * dac volume register
+ * 15-------------8-7--------------0
+ * | R channel vol | L channel vol |
+ *  -------------------------------
+ *
+ * PCM volume with 0.5017 dB steps from 0 to -90 dB
+ *
+ * register values map to dB
+ * 0x3B and less = Reserved
+ * 0x3C = 0 dB
+ * 0x3D = -0.5 dB
+ * 0xF0 = -90 dB
+ * 0xFC and greater = Muted
+ *
+ * register value map to userspace value
+ *
+ * register value	0x3c(0dB)	  0xf0(-90dB)0xfc
+ *			------------------------------
+ * userspace value	0xc0			     0
+ */
+static int dac_get_volsw(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int reg;
+	int l;
+	int r;
+
+	reg = snd_soc_component_read32(component, SGTL5000_CHIP_DAC_VOL);
+
+	/* get left channel volume */
+	l = (reg & SGTL5000_DAC_VOL_LEFT_MASK) >> SGTL5000_DAC_VOL_LEFT_SHIFT;
+
+	/* get right channel volume */
+	r = (reg & SGTL5000_DAC_VOL_RIGHT_MASK) >> SGTL5000_DAC_VOL_RIGHT_SHIFT;
+
+	/* make sure value fall in (0x3c,0xfc) */
+	l = clamp(l, 0x3c, 0xfc);
+	r = clamp(r, 0x3c, 0xfc);
+
+	/* invert it and map to userspace value */
+	l = 0xfc - l;
+	r = 0xfc - r;
+
+	ucontrol->value.integer.value[0] = l;
+	ucontrol->value.integer.value[1] = r;
+
+	return 0;
+}
+
+/*
+ * custom function to put of PCM playback volume
+ *
+ * dac volume register
+ * 15-------------8-7--------------0
+ * | R channel vol | L channel vol |
+ *  -------------------------------
+ *
+ * PCM volume with 0.5017 dB steps from 0 to -90 dB
+ *
+ * register values map to dB
+ * 0x3B and less = Reserved
+ * 0x3C = 0 dB
+ * 0x3D = -0.5 dB
+ * 0xF0 = -90 dB
+ * 0xFC and greater = Muted
+ *
+ * userspace value map to register value
+ *
+ * userspace value	0xc0			     0
+ *			------------------------------
+ * register value	0x3c(0dB)	0xf0(-90dB)0xfc
+ */
+static int dac_put_volsw(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int reg;
+	int l;
+	int r;
+
+	l = ucontrol->value.integer.value[0];
+	r = ucontrol->value.integer.value[1];
+
+	/* make sure userspace volume fall in (0, 0xfc-0x3c) */
+	l = clamp(l, 0, 0xfc - 0x3c);
+	r = clamp(r, 0, 0xfc - 0x3c);
+
+	/* invert it, get the value can be set to register */
+	l = 0xfc - l;
+	r = 0xfc - r;
+
+	/* shift to get the register value */
+	reg = l << SGTL5000_DAC_VOL_LEFT_SHIFT |
+		r << SGTL5000_DAC_VOL_RIGHT_SHIFT;
+
+	snd_soc_component_write(component, SGTL5000_CHIP_DAC_VOL, reg);
+
+	return 0;
+}
+
+/*
+ * custom function to get AVC threshold
+ *
+ * The threshold dB is calculated by rearranging the calculation from the
+ * avc_put_threshold function: register_value = 10^(dB/20) * 0.636 * 2^15 ==>
+ * dB = ( fls(register_value) - 14.347 ) * 6.02
+ *
+ * As this calculation is expensive and the threshold dB values may not exceed
+ * 0 to 96 we use pre-calculated values.
+ */
+static int avc_get_threshold(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int db, i;
+	u16 reg = snd_soc_component_read32(component, SGTL5000_DAP_AVC_THRESHOLD);
+
+	/* register value 0 => -96dB */
+	if (!reg) {
+		ucontrol->value.integer.value[0] = 96;
+		ucontrol->value.integer.value[1] = 96;
+		return 0;
+	}
+
+	/* get dB from register value (rounded down) */
+	for (i = 0; avc_thr_db2reg[i] > reg; i++)
+		;
+	db = i;
+
+	ucontrol->value.integer.value[0] = db;
+	ucontrol->value.integer.value[1] = db;
+
+	return 0;
+}
+
+/*
+ * custom function to put AVC threshold
+ *
+ * The register value is calculated by following formula:
+ *                                    register_value = 10^(dB/20) * 0.636 * 2^15
+ * As this calculation is expensive and the threshold dB values may not exceed
+ * 0 to 96 we use pre-calculated values.
+ */
+static int avc_put_threshold(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int db;
+	u16 reg;
+
+	db = (int)ucontrol->value.integer.value[0];
+	if (db < 0 || db > 96)
+		return -EINVAL;
+	reg = avc_thr_db2reg[db];
+	snd_soc_component_write(component, SGTL5000_DAP_AVC_THRESHOLD, reg);
+
+	return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(capture_6db_attenuate, -600, 600, 0);
+
+/* tlv for mic gain, 0db 20db 30db 40db */
+static const DECLARE_TLV_DB_RANGE(mic_gain_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+	1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0)
+);
+
+/* tlv for DAP channels, 0% - 100% - 200% */
+static const DECLARE_TLV_DB_SCALE(dap_volume, 0, 1, 0);
+
+/* tlv for bass bands, -11.75db to 12.0db, step .25db */
+static const DECLARE_TLV_DB_SCALE(bass_band, -1175, 25, 0);
+
+/* tlv for hp volume, -51.5db to 12.0db, step .5db */
+static const DECLARE_TLV_DB_SCALE(headphone_volume, -5150, 50, 0);
+
+/* tlv for lineout volume, 31 steps of .5db each */
+static const DECLARE_TLV_DB_SCALE(lineout_volume, -1550, 50, 0);
+
+/* tlv for dap avc max gain, 0db, 6db, 12db */
+static const DECLARE_TLV_DB_SCALE(avc_max_gain, 0, 600, 0);
+
+/* tlv for dap avc threshold, */
+static const DECLARE_TLV_DB_MINMAX(avc_threshold, 0, 9600);
+
+static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
+	/* SOC_DOUBLE_S8_TLV with invert */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "PCM Playback Volume",
+		.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = dac_info_volsw,
+		.get = dac_get_volsw,
+		.put = dac_put_volsw,
+	},
+
+	SOC_DOUBLE("Capture Volume", SGTL5000_CHIP_ANA_ADC_CTRL, 0, 4, 0xf, 0),
+	SOC_SINGLE_TLV("Capture Attenuate Switch (-6dB)",
+			SGTL5000_CHIP_ANA_ADC_CTRL,
+			8, 1, 0, capture_6db_attenuate),
+	SOC_SINGLE("Capture ZC Switch", SGTL5000_CHIP_ANA_CTRL, 1, 1, 0),
+
+	SOC_DOUBLE_TLV("Headphone Playback Volume",
+			SGTL5000_CHIP_ANA_HP_CTRL,
+			0, 8,
+			0x7f, 1,
+			headphone_volume),
+	SOC_SINGLE("Headphone Playback Switch", SGTL5000_CHIP_ANA_CTRL,
+			4, 1, 1),
+	SOC_SINGLE("Headphone Playback ZC Switch", SGTL5000_CHIP_ANA_CTRL,
+			5, 1, 0),
+
+	SOC_SINGLE_TLV("Mic Volume", SGTL5000_CHIP_MIC_CTRL,
+			0, 3, 0, mic_gain_tlv),
+
+	SOC_DOUBLE_TLV("Lineout Playback Volume",
+			SGTL5000_CHIP_LINE_OUT_VOL,
+			SGTL5000_LINE_OUT_VOL_LEFT_SHIFT,
+			SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT,
+			0x1f, 1,
+			lineout_volume),
+	SOC_SINGLE("Lineout Playback Switch", SGTL5000_CHIP_ANA_CTRL, 8, 1, 1),
+
+	SOC_SINGLE_TLV("DAP Main channel", SGTL5000_DAP_MAIN_CHAN,
+	0, 0xffff, 0, dap_volume),
+
+	SOC_SINGLE_TLV("DAP Mix channel", SGTL5000_DAP_MIX_CHAN,
+	0, 0xffff, 0, dap_volume),
+	/* Automatic Volume Control (DAP AVC) */
+	SOC_SINGLE("AVC Switch", SGTL5000_DAP_AVC_CTRL, 0, 1, 0),
+	SOC_SINGLE("AVC Hard Limiter Switch", SGTL5000_DAP_AVC_CTRL, 5, 1, 0),
+	SOC_SINGLE_TLV("AVC Max Gain Volume", SGTL5000_DAP_AVC_CTRL, 12, 2, 0,
+			avc_max_gain),
+	SOC_SINGLE("AVC Integrator Response", SGTL5000_DAP_AVC_CTRL, 8, 3, 0),
+	SOC_SINGLE_EXT_TLV("AVC Threshold Volume", SGTL5000_DAP_AVC_THRESHOLD,
+			0, 96, 0, avc_get_threshold, avc_put_threshold,
+			avc_threshold),
+
+	SOC_SINGLE_TLV("BASS 0", SGTL5000_DAP_EQ_BASS_BAND0,
+	0, 0x5F, 0, bass_band),
+
+	SOC_SINGLE_TLV("BASS 1", SGTL5000_DAP_EQ_BASS_BAND1,
+	0, 0x5F, 0, bass_band),
+
+	SOC_SINGLE_TLV("BASS 2", SGTL5000_DAP_EQ_BASS_BAND2,
+	0, 0x5F, 0, bass_band),
+
+	SOC_SINGLE_TLV("BASS 3", SGTL5000_DAP_EQ_BASS_BAND3,
+	0, 0x5F, 0, bass_band),
+
+	SOC_SINGLE_TLV("BASS 4", SGTL5000_DAP_EQ_BASS_BAND4,
+	0, 0x5F, 0, bass_band),
+};
+
+/* mute the codec used by alsa core */
+static int sgtl5000_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 i2s_pwr = SGTL5000_I2S_IN_POWERUP;
+
+	/*
+	 * During 'digital mute' do not mute DAC
+	 * because LINE_IN would be muted aswell. We want to mute
+	 * only I2S block - this can be done by powering it off
+	 */
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_DIG_POWER,
+			i2s_pwr, mute ? 0 : i2s_pwr);
+
+	return 0;
+}
+
+/* set codec format */
+static int sgtl5000_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
+	u16 i2sctl = 0;
+
+	sgtl5000->master = 0;
+	/*
+	 * i2s clock and frame master setting.
+	 * ONLY support:
+	 *  - clock and frame slave,
+	 *  - clock and frame master
+	 */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		i2sctl |= SGTL5000_I2S_MASTER;
+		sgtl5000->master = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* setting i2s data format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		i2sctl |= SGTL5000_I2S_MODE_PCM << SGTL5000_I2S_MODE_SHIFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		i2sctl |= SGTL5000_I2S_MODE_PCM << SGTL5000_I2S_MODE_SHIFT;
+		i2sctl |= SGTL5000_I2S_LRALIGN;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		i2sctl |= SGTL5000_I2S_MODE_I2S_LJ << SGTL5000_I2S_MODE_SHIFT;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		i2sctl |= SGTL5000_I2S_MODE_RJ << SGTL5000_I2S_MODE_SHIFT;
+		i2sctl |= SGTL5000_I2S_LRPOL;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		i2sctl |= SGTL5000_I2S_MODE_I2S_LJ << SGTL5000_I2S_MODE_SHIFT;
+		i2sctl |= SGTL5000_I2S_LRALIGN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	sgtl5000->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+	/* Clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		i2sctl |= SGTL5000_I2S_SCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, SGTL5000_CHIP_I2S_CTRL, i2sctl);
+
+	return 0;
+}
+
+/* set codec sysclk */
+static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				   int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case SGTL5000_SYSCLK:
+		sgtl5000->sysclk = freq;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * set clock according to i2s frame clock,
+ * sgtl5000 provides 2 clock sources:
+ * 1. sys_mclk: sample freq can only be configured to
+ *	1/256, 1/384, 1/512 of sys_mclk.
+ * 2. pll: can derive any audio clocks.
+ *
+ * clock setting rules:
+ * 1. in slave mode, only sys_mclk can be used
+ * 2. as constraint by sys_mclk, sample freq should be set to 32 kHz, 44.1 kHz
+ * and above.
+ * 3. usage of sys_mclk is preferred over pll to save power.
+ */
+static int sgtl5000_set_clock(struct snd_soc_component *component, int frame_rate)
+{
+	struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
+	int clk_ctl = 0;
+	int sys_fs;	/* sample freq */
+
+	/*
+	 * sample freq should be divided by frame clock,
+	 * if frame clock is lower than 44.1 kHz, sample freq should be set to
+	 * 32 kHz or 44.1 kHz.
+	 */
+	switch (frame_rate) {
+	case 8000:
+	case 16000:
+		sys_fs = 32000;
+		break;
+	case 11025:
+	case 22050:
+		sys_fs = 44100;
+		break;
+	default:
+		sys_fs = frame_rate;
+		break;
+	}
+
+	/* set divided factor of frame clock */
+	switch (sys_fs / frame_rate) {
+	case 4:
+		clk_ctl |= SGTL5000_RATE_MODE_DIV_4 << SGTL5000_RATE_MODE_SHIFT;
+		break;
+	case 2:
+		clk_ctl |= SGTL5000_RATE_MODE_DIV_2 << SGTL5000_RATE_MODE_SHIFT;
+		break;
+	case 1:
+		clk_ctl |= SGTL5000_RATE_MODE_DIV_1 << SGTL5000_RATE_MODE_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set the sys_fs according to frame rate */
+	switch (sys_fs) {
+	case 32000:
+		clk_ctl |= SGTL5000_SYS_FS_32k << SGTL5000_SYS_FS_SHIFT;
+		break;
+	case 44100:
+		clk_ctl |= SGTL5000_SYS_FS_44_1k << SGTL5000_SYS_FS_SHIFT;
+		break;
+	case 48000:
+		clk_ctl |= SGTL5000_SYS_FS_48k << SGTL5000_SYS_FS_SHIFT;
+		break;
+	case 96000:
+		clk_ctl |= SGTL5000_SYS_FS_96k << SGTL5000_SYS_FS_SHIFT;
+		break;
+	default:
+		dev_err(component->dev, "frame rate %d not supported\n",
+			frame_rate);
+		return -EINVAL;
+	}
+
+	/*
+	 * calculate the divider of mclk/sample_freq,
+	 * factor of freq = 96 kHz can only be 256, since mclk is in the range
+	 * of 8 MHz - 27 MHz
+	 */
+	switch (sgtl5000->sysclk / frame_rate) {
+	case 256:
+		clk_ctl |= SGTL5000_MCLK_FREQ_256FS <<
+			SGTL5000_MCLK_FREQ_SHIFT;
+		break;
+	case 384:
+		clk_ctl |= SGTL5000_MCLK_FREQ_384FS <<
+			SGTL5000_MCLK_FREQ_SHIFT;
+		break;
+	case 512:
+		clk_ctl |= SGTL5000_MCLK_FREQ_512FS <<
+			SGTL5000_MCLK_FREQ_SHIFT;
+		break;
+	default:
+		/* if mclk does not satisfy the divider, use pll */
+		if (sgtl5000->master) {
+			clk_ctl |= SGTL5000_MCLK_FREQ_PLL <<
+				SGTL5000_MCLK_FREQ_SHIFT;
+		} else {
+			dev_err(component->dev,
+				"PLL not supported in slave mode\n");
+			dev_err(component->dev, "%d ratio is not supported. "
+				"SYS_MCLK needs to be 256, 384 or 512 * fs\n",
+				sgtl5000->sysclk / frame_rate);
+			return -EINVAL;
+		}
+	}
+
+	/* if using pll, please check manual 6.4.2 for detail */
+	if ((clk_ctl & SGTL5000_MCLK_FREQ_MASK) == SGTL5000_MCLK_FREQ_PLL) {
+		u64 out, t;
+		int div2;
+		int pll_ctl;
+		unsigned int in, int_div, frac_div;
+
+		if (sgtl5000->sysclk > 17000000) {
+			div2 = 1;
+			in = sgtl5000->sysclk / 2;
+		} else {
+			div2 = 0;
+			in = sgtl5000->sysclk;
+		}
+		if (sys_fs == 44100)
+			out = 180633600;
+		else
+			out = 196608000;
+		t = do_div(out, in);
+		int_div = out;
+		t *= 2048;
+		do_div(t, in);
+		frac_div = t;
+		pll_ctl = int_div << SGTL5000_PLL_INT_DIV_SHIFT |
+		    frac_div << SGTL5000_PLL_FRAC_DIV_SHIFT;
+
+		snd_soc_component_write(component, SGTL5000_CHIP_PLL_CTRL, pll_ctl);
+		if (div2)
+			snd_soc_component_update_bits(component,
+				SGTL5000_CHIP_CLK_TOP_CTRL,
+				SGTL5000_INPUT_FREQ_DIV2,
+				SGTL5000_INPUT_FREQ_DIV2);
+		else
+			snd_soc_component_update_bits(component,
+				SGTL5000_CHIP_CLK_TOP_CTRL,
+				SGTL5000_INPUT_FREQ_DIV2,
+				0);
+
+		/* power up pll */
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
+			SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP,
+			SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP);
+
+		/* if using pll, clk_ctrl must be set after pll power up */
+		snd_soc_component_write(component, SGTL5000_CHIP_CLK_CTRL, clk_ctl);
+	} else {
+		/* otherwise, clk_ctrl must be set before pll power down */
+		snd_soc_component_write(component, SGTL5000_CHIP_CLK_CTRL, clk_ctl);
+
+		/* power down pll */
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
+			SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP,
+			0);
+	}
+
+	return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ * input: params_rate, params_fmt
+ */
+static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
+	int channels = params_channels(params);
+	int i2s_ctl = 0;
+	int stereo;
+	int ret;
+
+	/* sysclk should already set */
+	if (!sgtl5000->sysclk) {
+		dev_err(component->dev, "%s: set sysclk first!\n", __func__);
+		return -EFAULT;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		stereo = SGTL5000_DAC_STEREO;
+	else
+		stereo = SGTL5000_ADC_STEREO;
+
+	/* set mono to save power */
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER, stereo,
+			channels == 1 ? 0 : stereo);
+
+	/* set codec clock base on lrclk */
+	ret = sgtl5000_set_clock(component, params_rate(params));
+	if (ret)
+		return ret;
+
+	/* set i2s data format */
+	switch (params_width(params)) {
+	case 16:
+		if (sgtl5000->fmt == SND_SOC_DAIFMT_RIGHT_J)
+			return -EINVAL;
+		i2s_ctl |= SGTL5000_I2S_DLEN_16 << SGTL5000_I2S_DLEN_SHIFT;
+		i2s_ctl |= SGTL5000_I2S_SCLKFREQ_32FS <<
+		    SGTL5000_I2S_SCLKFREQ_SHIFT;
+		break;
+	case 20:
+		i2s_ctl |= SGTL5000_I2S_DLEN_20 << SGTL5000_I2S_DLEN_SHIFT;
+		i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS <<
+		    SGTL5000_I2S_SCLKFREQ_SHIFT;
+		break;
+	case 24:
+		i2s_ctl |= SGTL5000_I2S_DLEN_24 << SGTL5000_I2S_DLEN_SHIFT;
+		i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS <<
+		    SGTL5000_I2S_SCLKFREQ_SHIFT;
+		break;
+	case 32:
+		if (sgtl5000->fmt == SND_SOC_DAIFMT_RIGHT_J)
+			return -EINVAL;
+		i2s_ctl |= SGTL5000_I2S_DLEN_32 << SGTL5000_I2S_DLEN_SHIFT;
+		i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS <<
+		    SGTL5000_I2S_SCLKFREQ_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_I2S_CTRL,
+			    SGTL5000_I2S_DLEN_MASK | SGTL5000_I2S_SCLKFREQ_MASK,
+			    i2s_ctl);
+
+	return 0;
+}
+
+/*
+ * set dac bias
+ * common state changes:
+ * startup:
+ * off --> standby --> prepare --> on
+ * standby --> prepare --> on
+ *
+ * stop:
+ * on --> prepare --> standby
+ */
+static int sgtl5000_set_bias_level(struct snd_soc_component *component,
+				   enum snd_soc_bias_level level)
+{
+	struct sgtl5000_priv *sgtl = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+	case SND_SOC_BIAS_STANDBY:
+		regcache_cache_only(sgtl->regmap, false);
+		ret = regcache_sync(sgtl->regmap);
+		if (ret) {
+			regcache_cache_only(sgtl->regmap, true);
+			return ret;
+		}
+
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
+				    SGTL5000_REFTOP_POWERUP,
+				    SGTL5000_REFTOP_POWERUP);
+		break;
+	case SND_SOC_BIAS_OFF:
+		regcache_cache_only(sgtl->regmap, true);
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
+				    SGTL5000_REFTOP_POWERUP, 0);
+		break;
+	}
+
+	return 0;
+}
+
+#define SGTL5000_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE |\
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops sgtl5000_ops = {
+	.hw_params = sgtl5000_pcm_hw_params,
+	.digital_mute = sgtl5000_digital_mute,
+	.set_fmt = sgtl5000_set_dai_fmt,
+	.set_sysclk = sgtl5000_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver sgtl5000_dai = {
+	.name = "sgtl5000",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		/*
+		 * only support 8~48K + 96K,
+		 * TODO modify hw_param to support more
+		 */
+		.rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_96000,
+		.formats = SGTL5000_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_96000,
+		.formats = SGTL5000_FORMATS,
+	},
+	.ops = &sgtl5000_ops,
+	.symmetric_rates = 1,
+};
+
+static bool sgtl5000_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case SGTL5000_CHIP_ID:
+	case SGTL5000_CHIP_ADCDAC_CTRL:
+	case SGTL5000_CHIP_ANA_STATUS:
+		return true;
+	}
+
+	return false;
+}
+
+static bool sgtl5000_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case SGTL5000_CHIP_ID:
+	case SGTL5000_CHIP_DIG_POWER:
+	case SGTL5000_CHIP_CLK_CTRL:
+	case SGTL5000_CHIP_I2S_CTRL:
+	case SGTL5000_CHIP_SSS_CTRL:
+	case SGTL5000_CHIP_ADCDAC_CTRL:
+	case SGTL5000_CHIP_DAC_VOL:
+	case SGTL5000_CHIP_PAD_STRENGTH:
+	case SGTL5000_CHIP_ANA_ADC_CTRL:
+	case SGTL5000_CHIP_ANA_HP_CTRL:
+	case SGTL5000_CHIP_ANA_CTRL:
+	case SGTL5000_CHIP_LINREG_CTRL:
+	case SGTL5000_CHIP_REF_CTRL:
+	case SGTL5000_CHIP_MIC_CTRL:
+	case SGTL5000_CHIP_LINE_OUT_CTRL:
+	case SGTL5000_CHIP_LINE_OUT_VOL:
+	case SGTL5000_CHIP_ANA_POWER:
+	case SGTL5000_CHIP_PLL_CTRL:
+	case SGTL5000_CHIP_CLK_TOP_CTRL:
+	case SGTL5000_CHIP_ANA_STATUS:
+	case SGTL5000_CHIP_SHORT_CTRL:
+	case SGTL5000_CHIP_ANA_TEST2:
+	case SGTL5000_DAP_CTRL:
+	case SGTL5000_DAP_PEQ:
+	case SGTL5000_DAP_BASS_ENHANCE:
+	case SGTL5000_DAP_BASS_ENHANCE_CTRL:
+	case SGTL5000_DAP_AUDIO_EQ:
+	case SGTL5000_DAP_SURROUND:
+	case SGTL5000_DAP_FLT_COEF_ACCESS:
+	case SGTL5000_DAP_COEF_WR_B0_MSB:
+	case SGTL5000_DAP_COEF_WR_B0_LSB:
+	case SGTL5000_DAP_EQ_BASS_BAND0:
+	case SGTL5000_DAP_EQ_BASS_BAND1:
+	case SGTL5000_DAP_EQ_BASS_BAND2:
+	case SGTL5000_DAP_EQ_BASS_BAND3:
+	case SGTL5000_DAP_EQ_BASS_BAND4:
+	case SGTL5000_DAP_MAIN_CHAN:
+	case SGTL5000_DAP_MIX_CHAN:
+	case SGTL5000_DAP_AVC_CTRL:
+	case SGTL5000_DAP_AVC_THRESHOLD:
+	case SGTL5000_DAP_AVC_ATTACK:
+	case SGTL5000_DAP_AVC_DECAY:
+	case SGTL5000_DAP_COEF_WR_B1_MSB:
+	case SGTL5000_DAP_COEF_WR_B1_LSB:
+	case SGTL5000_DAP_COEF_WR_B2_MSB:
+	case SGTL5000_DAP_COEF_WR_B2_LSB:
+	case SGTL5000_DAP_COEF_WR_A1_MSB:
+	case SGTL5000_DAP_COEF_WR_A1_LSB:
+	case SGTL5000_DAP_COEF_WR_A2_MSB:
+	case SGTL5000_DAP_COEF_WR_A2_LSB:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+/*
+ * This precalculated table contains all (vag_val * 100 / lo_calcntrl) results
+ * to select an appropriate lo_vol_* in SGTL5000_CHIP_LINE_OUT_VOL
+ * The calculatation was done for all possible register values which
+ * is the array index and the following formula: 10^((idx−15)/40) * 100
+ */
+static const u8 vol_quot_table[] = {
+	42, 45, 47, 50, 53, 56, 60, 63,
+	67, 71, 75, 79, 84, 89, 94, 100,
+	106, 112, 119, 126, 133, 141, 150, 158,
+	168, 178, 188, 200, 211, 224, 237, 251
+};
+
+/*
+ * sgtl5000 has 3 internal power supplies:
+ * 1. VAG, normally set to vdda/2
+ * 2. charge pump, set to different value
+ *	according to voltage of vdda and vddio
+ * 3. line out VAG, normally set to vddio/2
+ *
+ * and should be set according to:
+ * 1. vddd provided by external or not
+ * 2. vdda and vddio voltage value. > 3.1v or not
+ */
+static int sgtl5000_set_power_regs(struct snd_soc_component *component)
+{
+	int vddd;
+	int vdda;
+	int vddio;
+	u16 ana_pwr;
+	u16 lreg_ctrl;
+	int vag;
+	int lo_vag;
+	int vol_quot;
+	int lo_vol;
+	size_t i;
+	struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
+
+	vdda  = regulator_get_voltage(sgtl5000->supplies[VDDA].consumer);
+	vddio = regulator_get_voltage(sgtl5000->supplies[VDDIO].consumer);
+	vddd  = (sgtl5000->num_supplies > VDDD)
+		? regulator_get_voltage(sgtl5000->supplies[VDDD].consumer)
+		: LDO_VOLTAGE;
+
+	vdda  = vdda / 1000;
+	vddio = vddio / 1000;
+	vddd  = vddd / 1000;
+
+	if (vdda <= 0 || vddio <= 0 || vddd < 0) {
+		dev_err(component->dev, "regulator voltage not set correctly\n");
+
+		return -EINVAL;
+	}
+
+	/* according to datasheet, maximum voltage of supplies */
+	if (vdda > 3600 || vddio > 3600 || vddd > 1980) {
+		dev_err(component->dev,
+			"exceed max voltage vdda %dmV vddio %dmV vddd %dmV\n",
+			vdda, vddio, vddd);
+
+		return -EINVAL;
+	}
+
+	/* reset value */
+	ana_pwr = snd_soc_component_read32(component, SGTL5000_CHIP_ANA_POWER);
+	ana_pwr |= SGTL5000_DAC_STEREO |
+			SGTL5000_ADC_STEREO |
+			SGTL5000_REFTOP_POWERUP;
+	lreg_ctrl = snd_soc_component_read32(component, SGTL5000_CHIP_LINREG_CTRL);
+
+	if (vddio < 3100 && vdda < 3100) {
+		/* enable internal oscillator used for charge pump */
+		snd_soc_component_update_bits(component, SGTL5000_CHIP_CLK_TOP_CTRL,
+					SGTL5000_INT_OSC_EN,
+					SGTL5000_INT_OSC_EN);
+		/* Enable VDDC charge pump */
+		ana_pwr |= SGTL5000_VDDC_CHRGPMP_POWERUP;
+	} else if (vddio >= 3100 && vdda >= 3100) {
+		ana_pwr &= ~SGTL5000_VDDC_CHRGPMP_POWERUP;
+		/* VDDC use VDDIO rail */
+		lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD;
+		lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO <<
+			    SGTL5000_VDDC_MAN_ASSN_SHIFT;
+	}
+
+	snd_soc_component_write(component, SGTL5000_CHIP_LINREG_CTRL, lreg_ctrl);
+
+	snd_soc_component_write(component, SGTL5000_CHIP_ANA_POWER, ana_pwr);
+
+	/*
+	 * set ADC/DAC VAG to vdda / 2,
+	 * should stay in range (0.8v, 1.575v)
+	 */
+	vag = vdda / 2;
+	if (vag <= SGTL5000_ANA_GND_BASE)
+		vag = 0;
+	else if (vag >= SGTL5000_ANA_GND_BASE + SGTL5000_ANA_GND_STP *
+		 (SGTL5000_ANA_GND_MASK >> SGTL5000_ANA_GND_SHIFT))
+		vag = SGTL5000_ANA_GND_MASK >> SGTL5000_ANA_GND_SHIFT;
+	else
+		vag = (vag - SGTL5000_ANA_GND_BASE) / SGTL5000_ANA_GND_STP;
+
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_REF_CTRL,
+			SGTL5000_ANA_GND_MASK, vag << SGTL5000_ANA_GND_SHIFT);
+
+	/* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */
+	lo_vag = vddio / 2;
+	if (lo_vag <= SGTL5000_LINE_OUT_GND_BASE)
+		lo_vag = 0;
+	else if (lo_vag >= SGTL5000_LINE_OUT_GND_BASE +
+		SGTL5000_LINE_OUT_GND_STP * SGTL5000_LINE_OUT_GND_MAX)
+		lo_vag = SGTL5000_LINE_OUT_GND_MAX;
+	else
+		lo_vag = (lo_vag - SGTL5000_LINE_OUT_GND_BASE) /
+		    SGTL5000_LINE_OUT_GND_STP;
+
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_LINE_OUT_CTRL,
+			SGTL5000_LINE_OUT_CURRENT_MASK |
+			SGTL5000_LINE_OUT_GND_MASK,
+			lo_vag << SGTL5000_LINE_OUT_GND_SHIFT |
+			SGTL5000_LINE_OUT_CURRENT_360u <<
+				SGTL5000_LINE_OUT_CURRENT_SHIFT);
+
+	/*
+	 * Set lineout output level in range (0..31)
+	 * the same value is used for right and left channel
+	 *
+	 * Searching for a suitable index solving this formula:
+	 * idx = 40 * log10(vag_val / lo_cagcntrl) + 15
+	 */
+	vol_quot = (vag * 100) / lo_vag;
+	lo_vol = 0;
+	for (i = 0; i < ARRAY_SIZE(vol_quot_table); i++) {
+		if (vol_quot >= vol_quot_table[i])
+			lo_vol = i;
+		else
+			break;
+	}
+
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_LINE_OUT_VOL,
+		SGTL5000_LINE_OUT_VOL_RIGHT_MASK |
+		SGTL5000_LINE_OUT_VOL_LEFT_MASK,
+		lo_vol << SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT |
+		lo_vol << SGTL5000_LINE_OUT_VOL_LEFT_SHIFT);
+
+	return 0;
+}
+
+static int sgtl5000_enable_regulators(struct i2c_client *client)
+{
+	int ret;
+	int i;
+	int external_vddd = 0;
+	struct regulator *vddd;
+	struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client);
+
+	for (i = 0; i < ARRAY_SIZE(sgtl5000->supplies); i++)
+		sgtl5000->supplies[i].supply = supply_names[i];
+
+	vddd = regulator_get_optional(&client->dev, "VDDD");
+	if (IS_ERR(vddd)) {
+		/* See if it's just not registered yet */
+		if (PTR_ERR(vddd) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+	} else {
+		external_vddd = 1;
+		regulator_put(vddd);
+	}
+
+	sgtl5000->num_supplies = ARRAY_SIZE(sgtl5000->supplies)
+				 - 1 + external_vddd;
+	ret = regulator_bulk_get(&client->dev, sgtl5000->num_supplies,
+				 sgtl5000->supplies);
+	if (ret)
+		return ret;
+
+	ret = regulator_bulk_enable(sgtl5000->num_supplies,
+				    sgtl5000->supplies);
+	if (!ret)
+		usleep_range(10, 20);
+	else
+		regulator_bulk_free(sgtl5000->num_supplies,
+				    sgtl5000->supplies);
+
+	return ret;
+}
+
+static int sgtl5000_probe(struct snd_soc_component *component)
+{
+	int ret;
+	u16 reg;
+	struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component);
+
+	/* power up sgtl5000 */
+	ret = sgtl5000_set_power_regs(component);
+	if (ret)
+		goto err;
+
+	/* enable small pop, introduce 400ms delay in turning off */
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_REF_CTRL,
+				SGTL5000_SMALL_POP, 1);
+
+	/* disable short cut detector */
+	snd_soc_component_write(component, SGTL5000_CHIP_SHORT_CTRL, 0);
+
+	snd_soc_component_write(component, SGTL5000_CHIP_DIG_POWER,
+			SGTL5000_ADC_EN | SGTL5000_DAC_EN);
+
+	/* enable dac volume ramp by default */
+	snd_soc_component_write(component, SGTL5000_CHIP_ADCDAC_CTRL,
+			SGTL5000_DAC_VOL_RAMP_EN |
+			SGTL5000_DAC_MUTE_RIGHT |
+			SGTL5000_DAC_MUTE_LEFT);
+
+	reg = ((sgtl5000->lrclk_strength) << SGTL5000_PAD_I2S_LRCLK_SHIFT | 0x5f);
+	snd_soc_component_write(component, SGTL5000_CHIP_PAD_STRENGTH, reg);
+
+	snd_soc_component_write(component, SGTL5000_CHIP_ANA_CTRL,
+			SGTL5000_HP_ZCD_EN |
+			SGTL5000_ADC_ZCD_EN);
+
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_MIC_CTRL,
+			SGTL5000_BIAS_R_MASK,
+			sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
+
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_MIC_CTRL,
+			SGTL5000_BIAS_VOLT_MASK,
+			sgtl5000->micbias_voltage << SGTL5000_BIAS_VOLT_SHIFT);
+	/*
+	 * enable DAP Graphic EQ
+	 * TODO:
+	 * Add control for changing between PEQ/Tone Control/GEQ
+	 */
+	snd_soc_component_write(component, SGTL5000_DAP_AUDIO_EQ, SGTL5000_DAP_SEL_GEQ);
+
+	/* Unmute DAC after start */
+	snd_soc_component_update_bits(component, SGTL5000_CHIP_ADCDAC_CTRL,
+		SGTL5000_DAC_MUTE_LEFT | SGTL5000_DAC_MUTE_RIGHT, 0);
+
+	return 0;
+
+err:
+	return ret;
+}
+
+static const struct snd_soc_component_driver sgtl5000_driver = {
+	.probe			= sgtl5000_probe,
+	.set_bias_level		= sgtl5000_set_bias_level,
+	.controls		= sgtl5000_snd_controls,
+	.num_controls		= ARRAY_SIZE(sgtl5000_snd_controls),
+	.dapm_widgets		= sgtl5000_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sgtl5000_dapm_widgets),
+	.dapm_routes		= sgtl5000_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(sgtl5000_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config sgtl5000_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+	.reg_stride = 2,
+
+	.max_register = SGTL5000_MAX_REG_OFFSET,
+	.volatile_reg = sgtl5000_volatile,
+	.readable_reg = sgtl5000_readable,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = sgtl5000_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(sgtl5000_reg_defaults),
+};
+
+/*
+ * Write all the default values from sgtl5000_reg_defaults[] array into the
+ * sgtl5000 registers, to make sure we always start with the sane registers
+ * values as stated in the datasheet.
+ *
+ * Since sgtl5000 does not have a reset line, nor a reset command in software,
+ * we follow this approach to guarantee we always start from the default values
+ * and avoid problems like, not being able to probe after an audio playback
+ * followed by a system reset or a 'reboot' command in Linux
+ */
+static void sgtl5000_fill_defaults(struct i2c_client *client)
+{
+	struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client);
+	int i, ret, val, index;
+
+	for (i = 0; i < ARRAY_SIZE(sgtl5000_reg_defaults); i++) {
+		val = sgtl5000_reg_defaults[i].def;
+		index = sgtl5000_reg_defaults[i].reg;
+		ret = regmap_write(sgtl5000->regmap, index, val);
+		if (ret)
+			dev_err(&client->dev,
+				"%s: error %d setting reg 0x%02x to 0x%04x\n",
+				__func__, ret, index, val);
+	}
+}
+
+static int sgtl5000_i2c_probe(struct i2c_client *client,
+			      const struct i2c_device_id *id)
+{
+	struct sgtl5000_priv *sgtl5000;
+	int ret, reg, rev;
+	struct device_node *np = client->dev.of_node;
+	u32 value;
+	u16 ana_pwr;
+
+	sgtl5000 = devm_kzalloc(&client->dev, sizeof(*sgtl5000), GFP_KERNEL);
+	if (!sgtl5000)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, sgtl5000);
+
+	ret = sgtl5000_enable_regulators(client);
+	if (ret)
+		return ret;
+
+	sgtl5000->regmap = devm_regmap_init_i2c(client, &sgtl5000_regmap);
+	if (IS_ERR(sgtl5000->regmap)) {
+		ret = PTR_ERR(sgtl5000->regmap);
+		dev_err(&client->dev, "Failed to allocate regmap: %d\n", ret);
+		goto disable_regs;
+	}
+
+	sgtl5000->mclk = devm_clk_get(&client->dev, NULL);
+	if (IS_ERR(sgtl5000->mclk)) {
+		ret = PTR_ERR(sgtl5000->mclk);
+		/* Defer the probe to see if the clk will be provided later */
+		if (ret == -ENOENT)
+			ret = -EPROBE_DEFER;
+
+		if (ret != -EPROBE_DEFER)
+			dev_err(&client->dev, "Failed to get mclock: %d\n",
+				ret);
+		goto disable_regs;
+	}
+
+	ret = clk_prepare_enable(sgtl5000->mclk);
+	if (ret) {
+		dev_err(&client->dev, "Error enabling clock %d\n", ret);
+		goto disable_regs;
+	}
+
+	/* Need 8 clocks before I2C accesses */
+	udelay(1);
+
+	/* read chip information */
+	ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ID, &reg);
+	if (ret) {
+		dev_err(&client->dev, "Error reading chip id %d\n", ret);
+		goto disable_clk;
+	}
+
+	if (((reg & SGTL5000_PARTID_MASK) >> SGTL5000_PARTID_SHIFT) !=
+	    SGTL5000_PARTID_PART_ID) {
+		dev_err(&client->dev,
+			"Device with ID register %x is not a sgtl5000\n", reg);
+		ret = -ENODEV;
+		goto disable_clk;
+	}
+
+	rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
+	dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev);
+	sgtl5000->revision = rev;
+
+	/* reconfigure the clocks in case we're using the PLL */
+	ret = regmap_write(sgtl5000->regmap,
+			   SGTL5000_CHIP_CLK_CTRL,
+			   SGTL5000_CHIP_CLK_CTRL_DEFAULT);
+	if (ret)
+		dev_err(&client->dev,
+			"Error %d initializing CHIP_CLK_CTRL\n", ret);
+
+	/* Follow section 2.2.1.1 of AN3663 */
+	ana_pwr = SGTL5000_ANA_POWER_DEFAULT;
+	if (sgtl5000->num_supplies <= VDDD) {
+		/* internal VDDD at 1.2V */
+		ret = regmap_update_bits(sgtl5000->regmap,
+					 SGTL5000_CHIP_LINREG_CTRL,
+					 SGTL5000_LINREG_VDDD_MASK,
+					 LINREG_VDDD);
+		if (ret)
+			dev_err(&client->dev,
+				"Error %d setting LINREG_VDDD\n", ret);
+
+		ana_pwr |= SGTL5000_LINEREG_D_POWERUP;
+		dev_info(&client->dev,
+			 "Using internal LDO instead of VDDD: check ER1 erratum\n");
+	} else {
+		/* using external LDO for VDDD
+		 * Clear startup powerup and simple powerup
+		 * bits to save power
+		 */
+		ana_pwr &= ~(SGTL5000_STARTUP_POWERUP
+			     | SGTL5000_LINREG_SIMPLE_POWERUP);
+		dev_dbg(&client->dev, "Using external VDDD\n");
+	}
+	ret = regmap_write(sgtl5000->regmap, SGTL5000_CHIP_ANA_POWER, ana_pwr);
+	if (ret)
+		dev_err(&client->dev,
+			"Error %d setting CHIP_ANA_POWER to %04x\n",
+			ret, ana_pwr);
+
+	if (np) {
+		if (!of_property_read_u32(np,
+			"micbias-resistor-k-ohms", &value)) {
+			switch (value) {
+			case SGTL5000_MICBIAS_OFF:
+				sgtl5000->micbias_resistor = 0;
+				break;
+			case SGTL5000_MICBIAS_2K:
+				sgtl5000->micbias_resistor = 1;
+				break;
+			case SGTL5000_MICBIAS_4K:
+				sgtl5000->micbias_resistor = 2;
+				break;
+			case SGTL5000_MICBIAS_8K:
+				sgtl5000->micbias_resistor = 3;
+				break;
+			default:
+				sgtl5000->micbias_resistor = 2;
+				dev_err(&client->dev,
+					"Unsuitable MicBias resistor\n");
+			}
+		} else {
+			/* default is 4Kohms */
+			sgtl5000->micbias_resistor = 2;
+		}
+		if (!of_property_read_u32(np,
+			"micbias-voltage-m-volts", &value)) {
+			/* 1250mV => 0 */
+			/* steps of 250mV */
+			if ((value >= 1250) && (value <= 3000))
+				sgtl5000->micbias_voltage = (value / 250) - 5;
+			else {
+				sgtl5000->micbias_voltage = 0;
+				dev_err(&client->dev,
+					"Unsuitable MicBias voltage\n");
+			}
+		} else {
+			sgtl5000->micbias_voltage = 0;
+		}
+	}
+
+	sgtl5000->lrclk_strength = I2S_LRCLK_STRENGTH_LOW;
+	if (!of_property_read_u32(np, "lrclk-strength", &value)) {
+		if (value > I2S_LRCLK_STRENGTH_HIGH)
+			value = I2S_LRCLK_STRENGTH_LOW;
+		sgtl5000->lrclk_strength = value;
+	}
+
+	/* Ensure sgtl5000 will start with sane register values */
+	sgtl5000_fill_defaults(client);
+
+	ret = devm_snd_soc_register_component(&client->dev,
+			&sgtl5000_driver, &sgtl5000_dai, 1);
+	if (ret)
+		goto disable_clk;
+
+	return 0;
+
+disable_clk:
+	clk_disable_unprepare(sgtl5000->mclk);
+
+disable_regs:
+	regulator_bulk_disable(sgtl5000->num_supplies, sgtl5000->supplies);
+	regulator_bulk_free(sgtl5000->num_supplies, sgtl5000->supplies);
+
+	return ret;
+}
+
+static int sgtl5000_i2c_remove(struct i2c_client *client)
+{
+	struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client);
+
+	clk_disable_unprepare(sgtl5000->mclk);
+	regulator_bulk_disable(sgtl5000->num_supplies, sgtl5000->supplies);
+	regulator_bulk_free(sgtl5000->num_supplies, sgtl5000->supplies);
+
+	return 0;
+}
+
+static const struct i2c_device_id sgtl5000_id[] = {
+	{"sgtl5000", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, sgtl5000_id);
+
+static const struct of_device_id sgtl5000_dt_ids[] = {
+	{ .compatible = "fsl,sgtl5000", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sgtl5000_dt_ids);
+
+static struct i2c_driver sgtl5000_i2c_driver = {
+	.driver = {
+		   .name = "sgtl5000",
+		   .of_match_table = sgtl5000_dt_ids,
+		   },
+	.probe = sgtl5000_i2c_probe,
+	.remove = sgtl5000_i2c_remove,
+	.id_table = sgtl5000_id,
+};
+
+module_i2c_driver(sgtl5000_i2c_driver);
+
+MODULE_DESCRIPTION("Freescale SGTL5000 ALSA SoC Codec Driver");
+MODULE_AUTHOR("Zeng Zhaoming <zengzm.kernel@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h
new file mode 100644
index 0000000..18cae08
--- /dev/null
+++ b/sound/soc/codecs/sgtl5000.h
@@ -0,0 +1,406 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * sgtl5000.h - SGTL5000 audio codec interface
+ *
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ */
+
+#ifndef _SGTL5000_H
+#define _SGTL5000_H
+
+/*
+ * Registers addresses
+ */
+#define SGTL5000_CHIP_ID			0x0000
+#define SGTL5000_CHIP_DIG_POWER			0x0002
+#define SGTL5000_CHIP_CLK_CTRL			0x0004
+#define SGTL5000_CHIP_I2S_CTRL			0x0006
+#define SGTL5000_CHIP_SSS_CTRL			0x000a
+#define SGTL5000_CHIP_ADCDAC_CTRL		0x000e
+#define SGTL5000_CHIP_DAC_VOL			0x0010
+#define SGTL5000_CHIP_PAD_STRENGTH		0x0014
+#define SGTL5000_CHIP_ANA_ADC_CTRL		0x0020
+#define SGTL5000_CHIP_ANA_HP_CTRL		0x0022
+#define SGTL5000_CHIP_ANA_CTRL			0x0024
+#define SGTL5000_CHIP_LINREG_CTRL		0x0026
+#define SGTL5000_CHIP_REF_CTRL			0x0028
+#define SGTL5000_CHIP_MIC_CTRL			0x002a
+#define SGTL5000_CHIP_LINE_OUT_CTRL		0x002c
+#define SGTL5000_CHIP_LINE_OUT_VOL		0x002e
+#define SGTL5000_CHIP_ANA_POWER			0x0030
+#define SGTL5000_CHIP_PLL_CTRL			0x0032
+#define SGTL5000_CHIP_CLK_TOP_CTRL		0x0034
+#define SGTL5000_CHIP_ANA_STATUS		0x0036
+#define SGTL5000_CHIP_SHORT_CTRL		0x003c
+#define SGTL5000_CHIP_ANA_TEST2			0x003a
+#define SGTL5000_DAP_CTRL			0x0100
+#define SGTL5000_DAP_PEQ			0x0102
+#define SGTL5000_DAP_BASS_ENHANCE		0x0104
+#define SGTL5000_DAP_BASS_ENHANCE_CTRL		0x0106
+#define SGTL5000_DAP_AUDIO_EQ			0x0108
+#define SGTL5000_DAP_SURROUND			0x010a
+#define SGTL5000_DAP_FLT_COEF_ACCESS		0x010c
+#define SGTL5000_DAP_COEF_WR_B0_MSB		0x010e
+#define SGTL5000_DAP_COEF_WR_B0_LSB		0x0110
+#define SGTL5000_DAP_EQ_BASS_BAND0		0x0116
+#define SGTL5000_DAP_EQ_BASS_BAND1		0x0118
+#define SGTL5000_DAP_EQ_BASS_BAND2		0x011a
+#define SGTL5000_DAP_EQ_BASS_BAND3		0x011c
+#define SGTL5000_DAP_EQ_BASS_BAND4		0x011e
+#define SGTL5000_DAP_MAIN_CHAN			0x0120
+#define SGTL5000_DAP_MIX_CHAN			0x0122
+#define SGTL5000_DAP_AVC_CTRL			0x0124
+#define SGTL5000_DAP_AVC_THRESHOLD		0x0126
+#define SGTL5000_DAP_AVC_ATTACK			0x0128
+#define SGTL5000_DAP_AVC_DECAY			0x012a
+#define SGTL5000_DAP_COEF_WR_B1_MSB		0x012c
+#define SGTL5000_DAP_COEF_WR_B1_LSB		0x012e
+#define SGTL5000_DAP_COEF_WR_B2_MSB		0x0130
+#define SGTL5000_DAP_COEF_WR_B2_LSB		0x0132
+#define SGTL5000_DAP_COEF_WR_A1_MSB		0x0134
+#define SGTL5000_DAP_COEF_WR_A1_LSB		0x0136
+#define SGTL5000_DAP_COEF_WR_A2_MSB		0x0138
+#define SGTL5000_DAP_COEF_WR_A2_LSB		0x013a
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * SGTL5000_CHIP_ID
+ */
+#define SGTL5000_PARTID_MASK			0xff00
+#define SGTL5000_PARTID_SHIFT			8
+#define SGTL5000_PARTID_WIDTH			8
+#define SGTL5000_PARTID_PART_ID			0xa0
+#define SGTL5000_REVID_MASK			0x00ff
+#define SGTL5000_REVID_SHIFT			0
+#define SGTL5000_REVID_WIDTH			8
+
+/*
+ * SGTL5000_CHIP_DIG_POWER
+ */
+#define SGTL5000_ADC_EN				0x0040
+#define SGTL5000_DAC_EN				0x0020
+#define SGTL5000_DAP_POWERUP			0x0010
+#define SGTL5000_I2S_OUT_POWERUP		0x0002
+#define SGTL5000_I2S_IN_POWERUP			0x0001
+
+/*
+ * SGTL5000_CHIP_CLK_CTRL
+ */
+#define SGTL5000_CHIP_CLK_CTRL_DEFAULT		0x0008
+#define SGTL5000_RATE_MODE_MASK			0x0030
+#define SGTL5000_RATE_MODE_SHIFT		4
+#define SGTL5000_RATE_MODE_WIDTH		2
+#define SGTL5000_RATE_MODE_DIV_1		0
+#define SGTL5000_RATE_MODE_DIV_2		1
+#define SGTL5000_RATE_MODE_DIV_4		2
+#define SGTL5000_RATE_MODE_DIV_6		3
+#define SGTL5000_SYS_FS_MASK			0x000c
+#define SGTL5000_SYS_FS_SHIFT			2
+#define SGTL5000_SYS_FS_WIDTH			2
+#define SGTL5000_SYS_FS_32k			0x0
+#define SGTL5000_SYS_FS_44_1k			0x1
+#define SGTL5000_SYS_FS_48k			0x2
+#define SGTL5000_SYS_FS_96k			0x3
+#define SGTL5000_MCLK_FREQ_MASK			0x0003
+#define SGTL5000_MCLK_FREQ_SHIFT		0
+#define SGTL5000_MCLK_FREQ_WIDTH		2
+#define SGTL5000_MCLK_FREQ_256FS		0x0
+#define SGTL5000_MCLK_FREQ_384FS		0x1
+#define SGTL5000_MCLK_FREQ_512FS		0x2
+#define SGTL5000_MCLK_FREQ_PLL			0x3
+
+/*
+ * SGTL5000_CHIP_I2S_CTRL
+ */
+#define SGTL5000_I2S_SCLKFREQ_MASK		0x0100
+#define SGTL5000_I2S_SCLKFREQ_SHIFT		8
+#define SGTL5000_I2S_SCLKFREQ_WIDTH		1
+#define SGTL5000_I2S_SCLKFREQ_64FS		0x0
+#define SGTL5000_I2S_SCLKFREQ_32FS		0x1	/* Not for RJ mode */
+#define SGTL5000_I2S_MASTER			0x0080
+#define SGTL5000_I2S_SCLK_INV			0x0040
+#define SGTL5000_I2S_DLEN_MASK			0x0030
+#define SGTL5000_I2S_DLEN_SHIFT			4
+#define SGTL5000_I2S_DLEN_WIDTH			2
+#define SGTL5000_I2S_DLEN_32			0x0
+#define SGTL5000_I2S_DLEN_24			0x1
+#define SGTL5000_I2S_DLEN_20			0x2
+#define SGTL5000_I2S_DLEN_16			0x3
+#define SGTL5000_I2S_MODE_MASK			0x000c
+#define SGTL5000_I2S_MODE_SHIFT			2
+#define SGTL5000_I2S_MODE_WIDTH			2
+#define SGTL5000_I2S_MODE_I2S_LJ		0x0
+#define SGTL5000_I2S_MODE_RJ			0x1
+#define SGTL5000_I2S_MODE_PCM			0x2
+#define SGTL5000_I2S_LRALIGN			0x0002
+#define SGTL5000_I2S_LRPOL			0x0001	/* set for which mode */
+
+/*
+ * SGTL5000_CHIP_SSS_CTRL
+ */
+#define SGTL5000_DAP_MIX_LRSWAP			0x4000
+#define SGTL5000_DAP_LRSWAP			0x2000
+#define SGTL5000_DAC_LRSWAP			0x1000
+#define SGTL5000_I2S_OUT_LRSWAP			0x0400
+#define SGTL5000_DAP_MIX_SEL_MASK		0x0300
+#define SGTL5000_DAP_MIX_SEL_SHIFT		8
+#define SGTL5000_DAP_MIX_SEL_WIDTH		2
+#define SGTL5000_DAP_MIX_SEL_ADC		0x0
+#define SGTL5000_DAP_MIX_SEL_I2S_IN		0x1
+#define SGTL5000_DAP_SEL_MASK			0x00c0
+#define SGTL5000_DAP_SEL_SHIFT			6
+#define SGTL5000_DAP_SEL_WIDTH			2
+#define SGTL5000_DAP_SEL_ADC			0x0
+#define SGTL5000_DAP_SEL_I2S_IN			0x1
+#define SGTL5000_DAC_SEL_MASK			0x0030
+#define SGTL5000_DAC_SEL_SHIFT			4
+#define SGTL5000_DAC_SEL_WIDTH			2
+#define SGTL5000_DAC_SEL_ADC			0x0
+#define SGTL5000_DAC_SEL_I2S_IN			0x1
+#define SGTL5000_DAC_SEL_DAP			0x3
+#define SGTL5000_I2S_OUT_SEL_MASK		0x0003
+#define SGTL5000_I2S_OUT_SEL_SHIFT		0
+#define SGTL5000_I2S_OUT_SEL_WIDTH		2
+#define SGTL5000_I2S_OUT_SEL_ADC		0x0
+#define SGTL5000_I2S_OUT_SEL_I2S_IN		0x1
+#define SGTL5000_I2S_OUT_SEL_DAP		0x3
+
+/*
+ * SGTL5000_CHIP_ADCDAC_CTRL
+ */
+#define SGTL5000_VOL_BUSY_DAC_RIGHT		0x2000
+#define SGTL5000_VOL_BUSY_DAC_LEFT		0x1000
+#define SGTL5000_DAC_VOL_RAMP_EN		0x0200
+#define SGTL5000_DAC_VOL_RAMP_EXPO		0x0100
+#define SGTL5000_DAC_MUTE_RIGHT			0x0008
+#define SGTL5000_DAC_MUTE_LEFT			0x0004
+#define SGTL5000_ADC_HPF_FREEZE			0x0002
+#define SGTL5000_ADC_HPF_BYPASS			0x0001
+
+/*
+ * SGTL5000_CHIP_DAC_VOL
+ */
+#define SGTL5000_DAC_VOL_RIGHT_MASK		0xff00
+#define SGTL5000_DAC_VOL_RIGHT_SHIFT		8
+#define SGTL5000_DAC_VOL_RIGHT_WIDTH		8
+#define SGTL5000_DAC_VOL_LEFT_MASK		0x00ff
+#define SGTL5000_DAC_VOL_LEFT_SHIFT		0
+#define SGTL5000_DAC_VOL_LEFT_WIDTH		8
+
+/*
+ * SGTL5000_CHIP_PAD_STRENGTH
+ */
+#define SGTL5000_PAD_I2S_LRCLK_MASK		0x0300
+#define SGTL5000_PAD_I2S_LRCLK_SHIFT		8
+#define SGTL5000_PAD_I2S_LRCLK_WIDTH		2
+#define SGTL5000_PAD_I2S_SCLK_MASK		0x00c0
+#define SGTL5000_PAD_I2S_SCLK_SHIFT		6
+#define SGTL5000_PAD_I2S_SCLK_WIDTH		2
+#define SGTL5000_PAD_I2S_DOUT_MASK		0x0030
+#define SGTL5000_PAD_I2S_DOUT_SHIFT		4
+#define SGTL5000_PAD_I2S_DOUT_WIDTH		2
+#define SGTL5000_PAD_I2C_SDA_MASK		0x000c
+#define SGTL5000_PAD_I2C_SDA_SHIFT		2
+#define SGTL5000_PAD_I2C_SDA_WIDTH		2
+#define SGTL5000_PAD_I2C_SCL_MASK		0x0003
+#define SGTL5000_PAD_I2C_SCL_SHIFT		0
+#define SGTL5000_PAD_I2C_SCL_WIDTH		2
+
+/*
+ * SGTL5000_CHIP_ANA_ADC_CTRL
+ */
+#define SGTL5000_ADC_VOL_M6DB			0x0100
+#define SGTL5000_ADC_VOL_RIGHT_MASK		0x00f0
+#define SGTL5000_ADC_VOL_RIGHT_SHIFT		4
+#define SGTL5000_ADC_VOL_RIGHT_WIDTH		4
+#define SGTL5000_ADC_VOL_LEFT_MASK		0x000f
+#define SGTL5000_ADC_VOL_LEFT_SHIFT		0
+#define SGTL5000_ADC_VOL_LEFT_WIDTH		4
+
+/*
+ * SGTL5000_CHIP_ANA_HP_CTRL
+ */
+#define SGTL5000_HP_VOL_RIGHT_MASK		0x7f00
+#define SGTL5000_HP_VOL_RIGHT_SHIFT		8
+#define SGTL5000_HP_VOL_RIGHT_WIDTH		7
+#define SGTL5000_HP_VOL_LEFT_MASK		0x007f
+#define SGTL5000_HP_VOL_LEFT_SHIFT		0
+#define SGTL5000_HP_VOL_LEFT_WIDTH		7
+
+/*
+ * SGTL5000_CHIP_ANA_CTRL
+ */
+#define SGTL5000_LINE_OUT_MUTE			0x0100
+#define SGTL5000_HP_SEL_MASK			0x0040
+#define SGTL5000_HP_SEL_SHIFT			6
+#define SGTL5000_HP_SEL_WIDTH			1
+#define SGTL5000_HP_SEL_DAC			0x0
+#define SGTL5000_HP_SEL_LINE_IN			0x1
+#define SGTL5000_HP_ZCD_EN			0x0020
+#define SGTL5000_HP_MUTE			0x0010
+#define SGTL5000_ADC_SEL_MASK			0x0004
+#define SGTL5000_ADC_SEL_SHIFT			2
+#define SGTL5000_ADC_SEL_WIDTH			1
+#define SGTL5000_ADC_SEL_MIC			0x0
+#define SGTL5000_ADC_SEL_LINE_IN		0x1
+#define SGTL5000_ADC_ZCD_EN			0x0002
+#define SGTL5000_ADC_MUTE			0x0001
+
+/*
+ * SGTL5000_CHIP_LINREG_CTRL
+ */
+#define SGTL5000_VDDC_MAN_ASSN_MASK		0x0040
+#define SGTL5000_VDDC_MAN_ASSN_SHIFT		6
+#define SGTL5000_VDDC_MAN_ASSN_WIDTH		1
+#define SGTL5000_VDDC_MAN_ASSN_VDDA		0x0
+#define SGTL5000_VDDC_MAN_ASSN_VDDIO		0x1
+#define SGTL5000_VDDC_ASSN_OVRD			0x0020
+#define SGTL5000_LINREG_VDDD_MASK		0x000f
+#define SGTL5000_LINREG_VDDD_SHIFT		0
+#define SGTL5000_LINREG_VDDD_WIDTH		4
+
+/*
+ * SGTL5000_CHIP_REF_CTRL
+ */
+#define SGTL5000_ANA_GND_MASK			0x01f0
+#define SGTL5000_ANA_GND_SHIFT			4
+#define SGTL5000_ANA_GND_WIDTH			5
+#define SGTL5000_ANA_GND_BASE			800	/* mv */
+#define SGTL5000_ANA_GND_STP			25	/*mv */
+#define SGTL5000_BIAS_CTRL_MASK			0x000e
+#define SGTL5000_BIAS_CTRL_SHIFT		1
+#define SGTL5000_BIAS_CTRL_WIDTH		3
+#define SGTL5000_SMALL_POP			1
+
+/*
+ * SGTL5000_CHIP_MIC_CTRL
+ */
+#define SGTL5000_BIAS_R_MASK			0x0300
+#define SGTL5000_BIAS_R_SHIFT			8
+#define SGTL5000_BIAS_R_WIDTH			2
+#define SGTL5000_BIAS_R_off			0x0
+#define SGTL5000_BIAS_R_2K			0x1
+#define SGTL5000_BIAS_R_4k			0x2
+#define SGTL5000_BIAS_R_8k			0x3
+#define SGTL5000_BIAS_VOLT_MASK			0x0070
+#define SGTL5000_BIAS_VOLT_SHIFT		4
+#define SGTL5000_BIAS_VOLT_WIDTH		3
+#define SGTL5000_MIC_GAIN_MASK			0x0003
+#define SGTL5000_MIC_GAIN_SHIFT			0
+#define SGTL5000_MIC_GAIN_WIDTH			2
+
+/*
+ * SGTL5000_CHIP_LINE_OUT_CTRL
+ */
+#define SGTL5000_LINE_OUT_CURRENT_MASK		0x0f00
+#define SGTL5000_LINE_OUT_CURRENT_SHIFT		8
+#define SGTL5000_LINE_OUT_CURRENT_WIDTH		4
+#define SGTL5000_LINE_OUT_CURRENT_180u		0x0
+#define SGTL5000_LINE_OUT_CURRENT_270u		0x1
+#define SGTL5000_LINE_OUT_CURRENT_360u		0x3
+#define SGTL5000_LINE_OUT_CURRENT_450u		0x7
+#define SGTL5000_LINE_OUT_CURRENT_540u		0xf
+#define SGTL5000_LINE_OUT_GND_MASK		0x003f
+#define SGTL5000_LINE_OUT_GND_SHIFT		0
+#define SGTL5000_LINE_OUT_GND_WIDTH		6
+#define SGTL5000_LINE_OUT_GND_BASE		800	/* mv */
+#define SGTL5000_LINE_OUT_GND_STP		25
+#define SGTL5000_LINE_OUT_GND_MAX		0x23
+
+/*
+ * SGTL5000_CHIP_LINE_OUT_VOL
+ */
+#define SGTL5000_LINE_OUT_VOL_RIGHT_MASK	0x1f00
+#define SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT	8
+#define SGTL5000_LINE_OUT_VOL_RIGHT_WIDTH	5
+#define SGTL5000_LINE_OUT_VOL_LEFT_MASK		0x001f
+#define SGTL5000_LINE_OUT_VOL_LEFT_SHIFT	0
+#define SGTL5000_LINE_OUT_VOL_LEFT_WIDTH	5
+
+/*
+ * SGTL5000_CHIP_ANA_POWER
+ */
+#define SGTL5000_ANA_POWER_DEFAULT		0x7060
+#define SGTL5000_DAC_STEREO			0x4000
+#define SGTL5000_LINREG_SIMPLE_POWERUP		0x2000
+#define SGTL5000_STARTUP_POWERUP		0x1000
+#define SGTL5000_VDDC_CHRGPMP_POWERUP		0x0800
+#define SGTL5000_PLL_POWERUP			0x0400
+#define SGTL5000_LINEREG_D_POWERUP		0x0200
+#define SGTL5000_VCOAMP_POWERUP			0x0100
+#define SGTL5000_VAG_POWERUP			0x0080
+#define SGTL5000_ADC_STEREO			0x0040
+#define SGTL5000_REFTOP_POWERUP			0x0020
+#define SGTL5000_HP_POWERUP			0x0010
+#define SGTL5000_DAC_POWERUP			0x0008
+#define SGTL5000_CAPLESS_HP_POWERUP		0x0004
+#define SGTL5000_ADC_POWERUP			0x0002
+#define SGTL5000_LINE_OUT_POWERUP		0x0001
+
+/*
+ * SGTL5000_CHIP_PLL_CTRL
+ */
+#define SGTL5000_PLL_INT_DIV_MASK		0xf800
+#define SGTL5000_PLL_INT_DIV_SHIFT		11
+#define SGTL5000_PLL_INT_DIV_WIDTH		5
+#define SGTL5000_PLL_FRAC_DIV_MASK		0x07ff
+#define SGTL5000_PLL_FRAC_DIV_SHIFT		0
+#define SGTL5000_PLL_FRAC_DIV_WIDTH		11
+
+/*
+ * SGTL5000_CHIP_CLK_TOP_CTRL
+ */
+#define SGTL5000_INT_OSC_EN			0x0800
+#define SGTL5000_INPUT_FREQ_DIV2		0x0008
+
+/*
+ * SGTL5000_CHIP_ANA_STATUS
+ */
+#define SGTL5000_HP_LRSHORT			0x0200
+#define SGTL5000_CAPLESS_SHORT			0x0100
+#define SGTL5000_PLL_LOCKED			0x0010
+
+/*
+ * SGTL5000_CHIP_SHORT_CTRL
+ */
+#define SGTL5000_LVLADJR_MASK			0x7000
+#define SGTL5000_LVLADJR_SHIFT			12
+#define SGTL5000_LVLADJR_WIDTH			3
+#define SGTL5000_LVLADJL_MASK			0x0700
+#define SGTL5000_LVLADJL_SHIFT			8
+#define SGTL5000_LVLADJL_WIDTH			3
+#define SGTL5000_LVLADJC_MASK			0x0070
+#define SGTL5000_LVLADJC_SHIFT			4
+#define SGTL5000_LVLADJC_WIDTH			3
+#define SGTL5000_LR_SHORT_MOD_MASK		0x000c
+#define SGTL5000_LR_SHORT_MOD_SHIFT		2
+#define SGTL5000_LR_SHORT_MOD_WIDTH		2
+#define SGTL5000_CM_SHORT_MOD_MASK		0x0003
+#define SGTL5000_CM_SHORT_MOD_SHIFT		0
+#define SGTL5000_CM_SHORT_MOD_WIDTH		2
+
+/*
+ *SGTL5000_CHIP_ANA_TEST2
+ */
+#define SGTL5000_MONO_DAC			0x1000
+
+/*
+ * SGTL5000_DAP_CTRL
+ */
+#define SGTL5000_DAP_MIX_EN			0x0010
+#define SGTL5000_DAP_EN				0x0001
+
+#define SGTL5000_SYSCLK				0x00
+#define SGTL5000_LRCLK				0x01
+
+/*
+ * SGTL5000_DAP_AUDIO_EQ
+ */
+#define SGTL5000_DAP_SEL_PEQ			1
+#define SGTL5000_DAP_SEL_TONE_CTRL		2
+#define SGTL5000_DAP_SEL_GEQ			3
+
+#endif
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
new file mode 100644
index 0000000..b779c28
--- /dev/null
+++ b/sound/soc/codecs/si476x.c
@@ -0,0 +1,273 @@
+/*
+ * sound/soc/codecs/si476x.c -- Codec driver for SI476X chips
+ *
+ * Copyright (C) 2012 Innovative Converged Devices(ICD)
+ * Copyright (C) 2013 Andrey Smirnov
+ *
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include <linux/i2c.h>
+
+#include <linux/mfd/si476x-core.h>
+
+enum si476x_audio_registers {
+	SI476X_DIGITAL_IO_OUTPUT_FORMAT		= 0x0203,
+	SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE	= 0x0202,
+};
+
+enum si476x_digital_io_output_format {
+	SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT	= 11,
+	SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT	= 8,
+};
+
+#define SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK	((0x7 << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | \
+						  (0x7 << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT))
+#define SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK	(0x7e)
+
+enum si476x_daudio_formats {
+	SI476X_DAUDIO_MODE_I2S		= (0x0 << 1),
+	SI476X_DAUDIO_MODE_DSP_A	= (0x6 << 1),
+	SI476X_DAUDIO_MODE_DSP_B	= (0x7 << 1),
+	SI476X_DAUDIO_MODE_LEFT_J	= (0x8 << 1),
+	SI476X_DAUDIO_MODE_RIGHT_J	= (0x9 << 1),
+
+	SI476X_DAUDIO_MODE_IB		= (1 << 5),
+	SI476X_DAUDIO_MODE_IF		= (1 << 6),
+};
+
+enum si476x_pcm_format {
+	SI476X_PCM_FORMAT_S8		= 2,
+	SI476X_PCM_FORMAT_S16_LE	= 4,
+	SI476X_PCM_FORMAT_S20_3LE	= 5,
+	SI476X_PCM_FORMAT_S24_LE	= 6,
+};
+
+static const struct snd_soc_dapm_widget si476x_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+};
+
+static const struct snd_soc_dapm_route si476x_dapm_routes[] = {
+	{ "Capture", NULL, "LOUT" },
+	{ "Capture", NULL, "ROUT" },
+};
+
+static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				    unsigned int fmt)
+{
+	struct si476x_core *core = i2c_mfd_cell_to_core(codec_dai->dev);
+	int err;
+	u16 format = 0;
+
+	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+		return -EINVAL;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		format |= SI476X_DAUDIO_MODE_DSP_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		format |= SI476X_DAUDIO_MODE_DSP_B;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		format |= SI476X_DAUDIO_MODE_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		format |= SI476X_DAUDIO_MODE_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		format |= SI476X_DAUDIO_MODE_LEFT_J;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			format |= SI476X_DAUDIO_MODE_IB;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			format |= SI476X_DAUDIO_MODE_IB |
+				SI476X_DAUDIO_MODE_IF;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			format |= SI476X_DAUDIO_MODE_IB;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			format |= SI476X_DAUDIO_MODE_IF;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	si476x_core_lock(core);
+
+	err = snd_soc_component_update_bits(codec_dai->component, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
+				  SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK,
+				  format);
+
+	si476x_core_unlock(core);
+
+	if (err < 0) {
+		dev_err(codec_dai->component->dev, "Failed to set output format\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct si476x_core *core = i2c_mfd_cell_to_core(dai->dev);
+	int rate, width, err;
+
+	rate = params_rate(params);
+	if (rate < 32000 || rate > 48000) {
+		dev_err(dai->component->dev, "Rate: %d is not supported\n", rate);
+		return -EINVAL;
+	}
+
+	switch (params_width(params)) {
+	case 8:
+		width = SI476X_PCM_FORMAT_S8;
+		break;
+	case 16:
+		width = SI476X_PCM_FORMAT_S16_LE;
+		break;
+	case 20:
+		width = SI476X_PCM_FORMAT_S20_3LE;
+		break;
+	case 24:
+		width = SI476X_PCM_FORMAT_S24_LE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	si476x_core_lock(core);
+
+	err = snd_soc_component_write(dai->component, SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE,
+			    rate);
+	if (err < 0) {
+		dev_err(dai->component->dev, "Failed to set sample rate\n");
+		goto out;
+	}
+
+	err = snd_soc_component_update_bits(dai->component, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
+				  SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK,
+				  (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) |
+				  (width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT));
+	if (err < 0) {
+		dev_err(dai->component->dev, "Failed to set output width\n");
+		goto out;
+	}
+
+out:
+	si476x_core_unlock(core);
+
+	return err;
+}
+
+static const struct snd_soc_dai_ops si476x_dai_ops = {
+	.hw_params	= si476x_codec_hw_params,
+	.set_fmt	= si476x_codec_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver si476x_dai = {
+	.name		= "si476x-codec",
+	.capture	= {
+		.stream_name	= "Capture",
+		.channels_min	= 2,
+		.channels_max	= 2,
+
+		.rates = SNDRV_PCM_RATE_32000 |
+		SNDRV_PCM_RATE_44100 |
+		SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S8 |
+		SNDRV_PCM_FMTBIT_S16_LE |
+		SNDRV_PCM_FMTBIT_S20_3LE |
+		SNDRV_PCM_FMTBIT_S24_LE
+	},
+	.ops		= &si476x_dai_ops,
+};
+
+static int si476x_probe(struct snd_soc_component *component)
+{
+	snd_soc_component_init_regmap(component,
+				dev_get_regmap(component->dev->parent, NULL));
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_si476x = {
+	.probe			= si476x_probe,
+	.dapm_widgets		= si476x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(si476x_dapm_widgets),
+	.dapm_routes		= si476x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(si476x_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int si476x_platform_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_si476x,
+				      &si476x_dai, 1);
+}
+
+MODULE_ALIAS("platform:si476x-codec");
+
+static struct platform_driver si476x_platform_driver = {
+	.driver		= {
+		.name	= "si476x-codec",
+	},
+	.probe		= si476x_platform_probe,
+};
+module_platform_driver(si476x_platform_driver);
+
+MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
+MODULE_DESCRIPTION("ASoC Si4761/64 codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sigmadsp-i2c.c b/sound/soc/codecs/sigmadsp-i2c.c
new file mode 100644
index 0000000..d374c18
--- /dev/null
+++ b/sound/soc/codecs/sigmadsp-i2c.c
@@ -0,0 +1,97 @@
+/*
+ * Load Analog Devices SigmaStudio firmware files
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/export.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#include "sigmadsp.h"
+
+static int sigmadsp_write_i2c(void *control_data,
+	unsigned int addr, const uint8_t data[], size_t len)
+{
+	uint8_t *buf;
+	int ret;
+
+	buf = kzalloc(2 + len, GFP_KERNEL | GFP_DMA);
+	if (!buf)
+		return -ENOMEM;
+
+	put_unaligned_be16(addr, buf);
+	memcpy(buf + 2, data, len);
+
+	ret = i2c_master_send(control_data, buf, len + 2);
+
+	kfree(buf);
+
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int sigmadsp_read_i2c(void *control_data,
+	unsigned int addr, uint8_t data[], size_t len)
+{
+	struct i2c_client *client = control_data;
+	struct i2c_msg msgs[2];
+	uint8_t buf[2];
+	int ret;
+
+	put_unaligned_be16(addr, buf);
+
+	msgs[0].addr = client->addr;
+	msgs[0].len = sizeof(buf);
+	msgs[0].buf = buf;
+	msgs[0].flags = 0;
+
+	msgs[1].addr = client->addr;
+	msgs[1].len = len;
+	msgs[1].buf = data;
+	msgs[1].flags = I2C_M_RD;
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0)
+		return ret;
+	else if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+	return 0;
+}
+
+/**
+ * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance
+ * @client: The parent I2C device
+ * @ops: The sigmadsp_ops to use for this instance
+ * @firmware_name: Name of the firmware file to load
+ *
+ * Allocates a SigmaDSP instance and loads the specified firmware file.
+ *
+ * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
+ */
+struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client,
+	const struct sigmadsp_ops *ops,	const char *firmware_name)
+{
+	struct sigmadsp *sigmadsp;
+
+	sigmadsp = devm_sigmadsp_init(&client->dev, ops, firmware_name);
+	if (IS_ERR(sigmadsp))
+		return sigmadsp;
+
+	sigmadsp->control_data = client;
+	sigmadsp->write = sigmadsp_write_i2c;
+	sigmadsp->read = sigmadsp_read_i2c;
+
+	return sigmadsp;
+}
+EXPORT_SYMBOL_GPL(devm_sigmadsp_init_i2c);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("SigmaDSP I2C firmware loader");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sigmadsp-regmap.c b/sound/soc/codecs/sigmadsp-regmap.c
new file mode 100644
index 0000000..912861b
--- /dev/null
+++ b/sound/soc/codecs/sigmadsp-regmap.c
@@ -0,0 +1,60 @@
+/*
+ * Load Analog Devices SigmaStudio firmware files
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/regmap.h>
+#include <linux/export.h>
+#include <linux/module.h>
+
+#include "sigmadsp.h"
+
+static int sigmadsp_write_regmap(void *control_data,
+	unsigned int addr, const uint8_t data[], size_t len)
+{
+	return regmap_raw_write(control_data, addr,
+		data, len);
+}
+
+static int sigmadsp_read_regmap(void *control_data,
+	unsigned int addr, uint8_t data[], size_t len)
+{
+	return regmap_raw_read(control_data, addr,
+		data, len);
+}
+
+/**
+ * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance
+ * @dev: The parent device
+ * @regmap: Regmap instance to use
+ * @ops: The sigmadsp_ops to use for this instance
+ * @firmware_name: Name of the firmware file to load
+ *
+ * Allocates a SigmaDSP instance and loads the specified firmware file.
+ *
+ * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
+ */
+struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev,
+	struct regmap *regmap, const struct sigmadsp_ops *ops,
+	const char *firmware_name)
+{
+	struct sigmadsp *sigmadsp;
+
+	sigmadsp = devm_sigmadsp_init(dev, ops, firmware_name);
+	if (IS_ERR(sigmadsp))
+		return sigmadsp;
+
+	sigmadsp->control_data = regmap;
+	sigmadsp->write = sigmadsp_write_regmap;
+	sigmadsp->read = sigmadsp_read_regmap;
+
+	return sigmadsp;
+}
+EXPORT_SYMBOL_GPL(devm_sigmadsp_init_regmap);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("SigmaDSP regmap firmware loader");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c
new file mode 100644
index 0000000..6df1586
--- /dev/null
+++ b/sound/soc/codecs/sigmadsp.c
@@ -0,0 +1,813 @@
+/*
+ * Load Analog Devices SigmaStudio firmware files
+ *
+ * Copyright 2009-2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/crc32.h>
+#include <linux/firmware.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <sound/control.h>
+#include <sound/soc.h>
+
+#include "sigmadsp.h"
+
+#define SIGMA_MAGIC "ADISIGM"
+
+#define SIGMA_FW_CHUNK_TYPE_DATA 0
+#define SIGMA_FW_CHUNK_TYPE_CONTROL 1
+#define SIGMA_FW_CHUNK_TYPE_SAMPLERATES 2
+
+struct sigmadsp_control {
+	struct list_head head;
+	uint32_t samplerates;
+	unsigned int addr;
+	unsigned int num_bytes;
+	const char *name;
+	struct snd_kcontrol *kcontrol;
+	bool cached;
+	uint8_t cache[];
+};
+
+struct sigmadsp_data {
+	struct list_head head;
+	uint32_t samplerates;
+	unsigned int addr;
+	unsigned int length;
+	uint8_t data[];
+};
+
+struct sigma_fw_chunk {
+	__le32 length;
+	__le32 tag;
+	__le32 samplerates;
+} __packed;
+
+struct sigma_fw_chunk_data {
+	struct sigma_fw_chunk chunk;
+	__le16 addr;
+	uint8_t data[];
+} __packed;
+
+struct sigma_fw_chunk_control {
+	struct sigma_fw_chunk chunk;
+	__le16 type;
+	__le16 addr;
+	__le16 num_bytes;
+	const char name[];
+} __packed;
+
+struct sigma_fw_chunk_samplerate {
+	struct sigma_fw_chunk chunk;
+	__le32 samplerates[];
+} __packed;
+
+struct sigma_firmware_header {
+	unsigned char magic[7];
+	u8 version;
+	__le32 crc;
+} __packed;
+
+enum {
+	SIGMA_ACTION_WRITEXBYTES = 0,
+	SIGMA_ACTION_WRITESINGLE,
+	SIGMA_ACTION_WRITESAFELOAD,
+	SIGMA_ACTION_END,
+};
+
+struct sigma_action {
+	u8 instr;
+	u8 len_hi;
+	__le16 len;
+	__be16 addr;
+	unsigned char payload[];
+} __packed;
+
+static int sigmadsp_write(struct sigmadsp *sigmadsp, unsigned int addr,
+	const uint8_t data[], size_t len)
+{
+	return sigmadsp->write(sigmadsp->control_data, addr, data, len);
+}
+
+static int sigmadsp_read(struct sigmadsp *sigmadsp, unsigned int addr,
+	uint8_t data[], size_t len)
+{
+	return sigmadsp->read(sigmadsp->control_data, addr, data, len);
+}
+
+static int sigmadsp_ctrl_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *info)
+{
+	struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
+
+	info->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	info->count = ctrl->num_bytes;
+
+	return 0;
+}
+
+static int sigmadsp_ctrl_write(struct sigmadsp *sigmadsp,
+	struct sigmadsp_control *ctrl, void *data)
+{
+	/* safeload loads up to 20 bytes in a atomic operation */
+	if (ctrl->num_bytes <= 20 && sigmadsp->ops && sigmadsp->ops->safeload)
+		return sigmadsp->ops->safeload(sigmadsp, ctrl->addr, data,
+			ctrl->num_bytes);
+	else
+		return sigmadsp_write(sigmadsp, ctrl->addr, data,
+			ctrl->num_bytes);
+}
+
+static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
+	struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol);
+	uint8_t *data;
+	int ret = 0;
+
+	mutex_lock(&sigmadsp->lock);
+
+	data = ucontrol->value.bytes.data;
+
+	if (!(kcontrol->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE))
+		ret = sigmadsp_ctrl_write(sigmadsp, ctrl, data);
+
+	if (ret == 0) {
+		memcpy(ctrl->cache, data, ctrl->num_bytes);
+		ctrl->cached = true;
+	}
+
+	mutex_unlock(&sigmadsp->lock);
+
+	return ret;
+}
+
+static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
+	struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol);
+	int ret = 0;
+
+	mutex_lock(&sigmadsp->lock);
+
+	if (!ctrl->cached) {
+		ret = sigmadsp_read(sigmadsp, ctrl->addr, ctrl->cache,
+			ctrl->num_bytes);
+	}
+
+	if (ret == 0) {
+		ctrl->cached = true;
+		memcpy(ucontrol->value.bytes.data, ctrl->cache,
+			ctrl->num_bytes);
+	}
+
+	mutex_unlock(&sigmadsp->lock);
+
+	return ret;
+}
+
+static void sigmadsp_control_free(struct snd_kcontrol *kcontrol)
+{
+	struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
+
+	ctrl->kcontrol = NULL;
+}
+
+static bool sigma_fw_validate_control_name(const char *name, unsigned int len)
+{
+	unsigned int i;
+
+	for (i = 0; i < len; i++) {
+		/* Normal ASCII characters are valid */
+		if (name[i] < ' ' || name[i] > '~')
+			return false;
+	}
+
+	return true;
+}
+
+static int sigma_fw_load_control(struct sigmadsp *sigmadsp,
+	const struct sigma_fw_chunk *chunk, unsigned int length)
+{
+	const struct sigma_fw_chunk_control *ctrl_chunk;
+	struct sigmadsp_control *ctrl;
+	unsigned int num_bytes;
+	size_t name_len;
+	char *name;
+	int ret;
+
+	if (length <= sizeof(*ctrl_chunk))
+		return -EINVAL;
+
+	ctrl_chunk = (const struct sigma_fw_chunk_control *)chunk;
+
+	name_len = length - sizeof(*ctrl_chunk);
+	if (name_len >= SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+		name_len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1;
+
+	/* Make sure there are no non-displayable characaters in the string */
+	if (!sigma_fw_validate_control_name(ctrl_chunk->name, name_len))
+		return -EINVAL;
+
+	num_bytes = le16_to_cpu(ctrl_chunk->num_bytes);
+	ctrl = kzalloc(sizeof(*ctrl) + num_bytes, GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+
+	name = kzalloc(name_len + 1, GFP_KERNEL);
+	if (!name) {
+		ret = -ENOMEM;
+		goto err_free_ctrl;
+	}
+	memcpy(name, ctrl_chunk->name, name_len);
+	name[name_len] = '\0';
+	ctrl->name = name;
+
+	ctrl->addr = le16_to_cpu(ctrl_chunk->addr);
+	ctrl->num_bytes = num_bytes;
+	ctrl->samplerates = le32_to_cpu(chunk->samplerates);
+
+	list_add_tail(&ctrl->head, &sigmadsp->ctrl_list);
+
+	return 0;
+
+err_free_ctrl:
+	kfree(ctrl);
+
+	return ret;
+}
+
+static int sigma_fw_load_data(struct sigmadsp *sigmadsp,
+	const struct sigma_fw_chunk *chunk, unsigned int length)
+{
+	const struct sigma_fw_chunk_data *data_chunk;
+	struct sigmadsp_data *data;
+
+	if (length <= sizeof(*data_chunk))
+		return -EINVAL;
+
+	data_chunk = (struct sigma_fw_chunk_data *)chunk;
+
+	length -= sizeof(*data_chunk);
+
+	data = kzalloc(sizeof(*data) + length, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->addr = le16_to_cpu(data_chunk->addr);
+	data->length = length;
+	data->samplerates = le32_to_cpu(chunk->samplerates);
+	memcpy(data->data, data_chunk->data, length);
+	list_add_tail(&data->head, &sigmadsp->data_list);
+
+	return 0;
+}
+
+static int sigma_fw_load_samplerates(struct sigmadsp *sigmadsp,
+	const struct sigma_fw_chunk *chunk, unsigned int length)
+{
+	const struct sigma_fw_chunk_samplerate *rate_chunk;
+	unsigned int num_rates;
+	unsigned int *rates;
+	unsigned int i;
+
+	rate_chunk = (const struct sigma_fw_chunk_samplerate *)chunk;
+
+	num_rates = (length - sizeof(*rate_chunk)) / sizeof(__le32);
+
+	if (num_rates > 32 || num_rates == 0)
+		return -EINVAL;
+
+	/* We only allow one samplerates block per file */
+	if (sigmadsp->rate_constraints.count)
+		return -EINVAL;
+
+	rates = kcalloc(num_rates, sizeof(*rates), GFP_KERNEL);
+	if (!rates)
+		return -ENOMEM;
+
+	for (i = 0; i < num_rates; i++)
+		rates[i] = le32_to_cpu(rate_chunk->samplerates[i]);
+
+	sigmadsp->rate_constraints.count = num_rates;
+	sigmadsp->rate_constraints.list = rates;
+
+	return 0;
+}
+
+static int sigmadsp_fw_load_v2(struct sigmadsp *sigmadsp,
+	const struct firmware *fw)
+{
+	struct sigma_fw_chunk *chunk;
+	unsigned int length, pos;
+	int ret;
+
+	/*
+	 * Make sure that there is at least one chunk to avoid integer
+	 * underflows later on. Empty firmware is still valid though.
+	 */
+	if (fw->size < sizeof(*chunk) + sizeof(struct sigma_firmware_header))
+		return 0;
+
+	pos = sizeof(struct sigma_firmware_header);
+
+	while (pos < fw->size - sizeof(*chunk)) {
+		chunk = (struct sigma_fw_chunk *)(fw->data + pos);
+
+		length = le32_to_cpu(chunk->length);
+
+		if (length > fw->size - pos || length < sizeof(*chunk))
+			return -EINVAL;
+
+		switch (le32_to_cpu(chunk->tag)) {
+		case SIGMA_FW_CHUNK_TYPE_DATA:
+			ret = sigma_fw_load_data(sigmadsp, chunk, length);
+			break;
+		case SIGMA_FW_CHUNK_TYPE_CONTROL:
+			ret = sigma_fw_load_control(sigmadsp, chunk, length);
+			break;
+		case SIGMA_FW_CHUNK_TYPE_SAMPLERATES:
+			ret = sigma_fw_load_samplerates(sigmadsp, chunk, length);
+			break;
+		default:
+			dev_warn(sigmadsp->dev, "Unknown chunk type: %d\n",
+				chunk->tag);
+			ret = 0;
+			break;
+		}
+
+		if (ret)
+			return ret;
+
+		/*
+		 * This can not overflow since if length is larger than the
+		 * maximum firmware size (0x4000000) we'll error out earilier.
+		 */
+		pos += ALIGN(length, sizeof(__le32));
+	}
+
+	return 0;
+}
+
+static inline u32 sigma_action_len(struct sigma_action *sa)
+{
+	return (sa->len_hi << 16) | le16_to_cpu(sa->len);
+}
+
+static size_t sigma_action_size(struct sigma_action *sa)
+{
+	size_t payload = 0;
+
+	switch (sa->instr) {
+	case SIGMA_ACTION_WRITEXBYTES:
+	case SIGMA_ACTION_WRITESINGLE:
+	case SIGMA_ACTION_WRITESAFELOAD:
+		payload = sigma_action_len(sa);
+		break;
+	default:
+		break;
+	}
+
+	payload = ALIGN(payload, 2);
+
+	return payload + sizeof(struct sigma_action);
+}
+
+/*
+ * Returns a negative error value in case of an error, 0 if processing of
+ * the firmware should be stopped after this action, 1 otherwise.
+ */
+static int process_sigma_action(struct sigmadsp *sigmadsp,
+	struct sigma_action *sa)
+{
+	size_t len = sigma_action_len(sa);
+	struct sigmadsp_data *data;
+
+	pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
+		sa->instr, sa->addr, len);
+
+	switch (sa->instr) {
+	case SIGMA_ACTION_WRITEXBYTES:
+	case SIGMA_ACTION_WRITESINGLE:
+	case SIGMA_ACTION_WRITESAFELOAD:
+		if (len < 3)
+			return -EINVAL;
+
+		data = kzalloc(sizeof(*data) + len - 2, GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+
+		data->addr = be16_to_cpu(sa->addr);
+		data->length = len - 2;
+		memcpy(data->data, sa->payload, data->length);
+		list_add_tail(&data->head, &sigmadsp->data_list);
+		break;
+	case SIGMA_ACTION_END:
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	return 1;
+}
+
+static int sigmadsp_fw_load_v1(struct sigmadsp *sigmadsp,
+	const struct firmware *fw)
+{
+	struct sigma_action *sa;
+	size_t size, pos;
+	int ret;
+
+	pos = sizeof(struct sigma_firmware_header);
+
+	while (pos + sizeof(*sa) <= fw->size) {
+		sa = (struct sigma_action *)(fw->data + pos);
+
+		size = sigma_action_size(sa);
+		pos += size;
+		if (pos > fw->size || size == 0)
+			break;
+
+		ret = process_sigma_action(sigmadsp, sa);
+
+		pr_debug("%s: action returned %i\n", __func__, ret);
+
+		if (ret <= 0)
+			return ret;
+	}
+
+	if (pos != fw->size)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void sigmadsp_firmware_release(struct sigmadsp *sigmadsp)
+{
+	struct sigmadsp_control *ctrl, *_ctrl;
+	struct sigmadsp_data *data, *_data;
+
+	list_for_each_entry_safe(ctrl, _ctrl, &sigmadsp->ctrl_list, head) {
+		kfree(ctrl->name);
+		kfree(ctrl);
+	}
+
+	list_for_each_entry_safe(data, _data, &sigmadsp->data_list, head)
+		kfree(data);
+
+	INIT_LIST_HEAD(&sigmadsp->ctrl_list);
+	INIT_LIST_HEAD(&sigmadsp->data_list);
+}
+
+static void devm_sigmadsp_release(struct device *dev, void *res)
+{
+	sigmadsp_firmware_release((struct sigmadsp *)res);
+}
+
+static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
+{
+	const struct sigma_firmware_header *ssfw_head;
+	const struct firmware *fw;
+	int ret;
+	u32 crc;
+
+	/* first load the blob */
+	ret = request_firmware(&fw, name, sigmadsp->dev);
+	if (ret) {
+		pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
+		goto done;
+	}
+
+	/* then verify the header */
+	ret = -EINVAL;
+
+	/*
+	 * Reject too small or unreasonable large files. The upper limit has been
+	 * chosen a bit arbitrarily, but it should be enough for all practical
+	 * purposes and having the limit makes it easier to avoid integer
+	 * overflows later in the loading process.
+	 */
+	if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) {
+		dev_err(sigmadsp->dev, "Failed to load firmware: Invalid size\n");
+		goto done;
+	}
+
+	ssfw_head = (void *)fw->data;
+	if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) {
+		dev_err(sigmadsp->dev, "Failed to load firmware: Invalid magic\n");
+		goto done;
+	}
+
+	crc = crc32(0, fw->data + sizeof(*ssfw_head),
+			fw->size - sizeof(*ssfw_head));
+	pr_debug("%s: crc=%x\n", __func__, crc);
+	if (crc != le32_to_cpu(ssfw_head->crc)) {
+		dev_err(sigmadsp->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n",
+			le32_to_cpu(ssfw_head->crc), crc);
+		goto done;
+	}
+
+	switch (ssfw_head->version) {
+	case 1:
+		ret = sigmadsp_fw_load_v1(sigmadsp, fw);
+		break;
+	case 2:
+		ret = sigmadsp_fw_load_v2(sigmadsp, fw);
+		break;
+	default:
+		dev_err(sigmadsp->dev,
+			"Failed to load firmware: Invalid version %d. Supported firmware versions: 1, 2\n",
+			ssfw_head->version);
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret)
+		sigmadsp_firmware_release(sigmadsp);
+
+done:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int sigmadsp_init(struct sigmadsp *sigmadsp, struct device *dev,
+	const struct sigmadsp_ops *ops, const char *firmware_name)
+{
+	sigmadsp->ops = ops;
+	sigmadsp->dev = dev;
+
+	INIT_LIST_HEAD(&sigmadsp->ctrl_list);
+	INIT_LIST_HEAD(&sigmadsp->data_list);
+	mutex_init(&sigmadsp->lock);
+
+	return sigmadsp_firmware_load(sigmadsp, firmware_name);
+}
+
+/**
+ * devm_sigmadsp_init() - Initialize SigmaDSP instance
+ * @dev: The parent device
+ * @ops: The sigmadsp_ops to use for this instance
+ * @firmware_name: Name of the firmware file to load
+ *
+ * Allocates a SigmaDSP instance and loads the specified firmware file.
+ *
+ * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
+ */
+struct sigmadsp *devm_sigmadsp_init(struct device *dev,
+	const struct sigmadsp_ops *ops, const char *firmware_name)
+{
+	struct sigmadsp *sigmadsp;
+	int ret;
+
+	sigmadsp = devres_alloc(devm_sigmadsp_release, sizeof(*sigmadsp),
+		GFP_KERNEL);
+	if (!sigmadsp)
+		return ERR_PTR(-ENOMEM);
+
+	ret = sigmadsp_init(sigmadsp, dev, ops, firmware_name);
+	if (ret) {
+		devres_free(sigmadsp);
+		return ERR_PTR(ret);
+	}
+
+	devres_add(dev, sigmadsp);
+
+	return sigmadsp;
+}
+EXPORT_SYMBOL_GPL(devm_sigmadsp_init);
+
+static int sigmadsp_rate_to_index(struct sigmadsp *sigmadsp, unsigned int rate)
+{
+	unsigned int i;
+
+	for (i = 0; i < sigmadsp->rate_constraints.count; i++) {
+		if (sigmadsp->rate_constraints.list[i] == rate)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static unsigned int sigmadsp_get_samplerate_mask(struct sigmadsp *sigmadsp,
+	unsigned int samplerate)
+{
+	int samplerate_index;
+
+	if (samplerate == 0)
+		return 0;
+
+	if (sigmadsp->rate_constraints.count) {
+		samplerate_index = sigmadsp_rate_to_index(sigmadsp, samplerate);
+		if (samplerate_index < 0)
+			return 0;
+
+		return BIT(samplerate_index);
+	} else {
+		return ~0;
+	}
+}
+
+static bool sigmadsp_samplerate_valid(unsigned int supported,
+	unsigned int requested)
+{
+	/* All samplerates are supported */
+	if (!supported)
+		return true;
+
+	return supported & requested;
+}
+
+static int sigmadsp_alloc_control(struct sigmadsp *sigmadsp,
+	struct sigmadsp_control *ctrl, unsigned int samplerate_mask)
+{
+	struct snd_kcontrol_new template;
+	struct snd_kcontrol *kcontrol;
+
+	memset(&template, 0, sizeof(template));
+	template.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	template.name = ctrl->name;
+	template.info = sigmadsp_ctrl_info;
+	template.get = sigmadsp_ctrl_get;
+	template.put = sigmadsp_ctrl_put;
+	template.private_value = (unsigned long)ctrl;
+	template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	if (!sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask))
+		template.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+
+	kcontrol = snd_ctl_new1(&template, sigmadsp);
+	if (!kcontrol)
+		return -ENOMEM;
+
+	kcontrol->private_free = sigmadsp_control_free;
+	ctrl->kcontrol = kcontrol;
+
+	return snd_ctl_add(sigmadsp->component->card->snd_card, kcontrol);
+}
+
+static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp,
+	struct sigmadsp_control *ctrl, unsigned int samplerate_mask)
+{
+	struct snd_card *card = sigmadsp->component->card->snd_card;
+	struct snd_kcontrol_volatile *vd;
+	struct snd_ctl_elem_id id;
+	bool active;
+	bool changed = false;
+
+	active = sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask);
+
+	down_write(&card->controls_rwsem);
+	if (!ctrl->kcontrol) {
+		up_write(&card->controls_rwsem);
+		return;
+	}
+
+	id = ctrl->kcontrol->id;
+	vd = &ctrl->kcontrol->vd[0];
+	if (active == (bool)(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) {
+		vd->access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+		changed = true;
+	}
+	up_write(&card->controls_rwsem);
+
+	if (active && changed) {
+		mutex_lock(&sigmadsp->lock);
+		if (ctrl->cached)
+			sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache);
+		mutex_unlock(&sigmadsp->lock);
+	}
+
+	if (changed)
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &id);
+}
+
+/**
+ * sigmadsp_attach() - Attach a sigmadsp instance to a ASoC component
+ * @sigmadsp: The sigmadsp instance to attach
+ * @component: The component to attach to
+ *
+ * Typically called in the components probe callback.
+ *
+ * Note, once this function has been called the firmware must not be released
+ * until after the ALSA snd_card that the component belongs to has been
+ * disconnected, even if sigmadsp_attach() returns an error.
+ */
+int sigmadsp_attach(struct sigmadsp *sigmadsp,
+	struct snd_soc_component *component)
+{
+	struct sigmadsp_control *ctrl;
+	unsigned int samplerate_mask;
+	int ret;
+
+	sigmadsp->component = component;
+
+	samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp,
+		sigmadsp->current_samplerate);
+
+	list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) {
+		ret = sigmadsp_alloc_control(sigmadsp, ctrl, samplerate_mask);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sigmadsp_attach);
+
+/**
+ * sigmadsp_setup() - Setup the DSP for the specified samplerate
+ * @sigmadsp: The sigmadsp instance to configure
+ * @samplerate: The samplerate the DSP should be configured for
+ *
+ * Loads the appropriate firmware program and parameter memory (if not already
+ * loaded) and enables the controls for the specified samplerate. Any control
+ * parameter changes that have been made previously will be restored.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int samplerate)
+{
+	struct sigmadsp_control *ctrl;
+	unsigned int samplerate_mask;
+	struct sigmadsp_data *data;
+	int ret;
+
+	if (sigmadsp->current_samplerate == samplerate)
+		return 0;
+
+	samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp, samplerate);
+	if (samplerate_mask == 0)
+		return -EINVAL;
+
+	list_for_each_entry(data, &sigmadsp->data_list, head) {
+		if (!sigmadsp_samplerate_valid(data->samplerates,
+		    samplerate_mask))
+			continue;
+		ret = sigmadsp_write(sigmadsp, data->addr, data->data,
+			data->length);
+		if (ret)
+			goto err;
+	}
+
+	list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head)
+		sigmadsp_activate_ctrl(sigmadsp, ctrl, samplerate_mask);
+
+	sigmadsp->current_samplerate = samplerate;
+
+	return 0;
+err:
+	sigmadsp_reset(sigmadsp);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sigmadsp_setup);
+
+/**
+ * sigmadsp_reset() - Notify the sigmadsp instance that the DSP has been reset
+ * @sigmadsp: The sigmadsp instance to reset
+ *
+ * Should be called whenever the DSP has been reset and parameter and program
+ * memory need to be re-loaded.
+ */
+void sigmadsp_reset(struct sigmadsp *sigmadsp)
+{
+	struct sigmadsp_control *ctrl;
+
+	list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head)
+		sigmadsp_activate_ctrl(sigmadsp, ctrl, false);
+
+	sigmadsp->current_samplerate = 0;
+}
+EXPORT_SYMBOL_GPL(sigmadsp_reset);
+
+/**
+ * sigmadsp_restrict_params() - Applies DSP firmware specific constraints
+ * @sigmadsp: The sigmadsp instance
+ * @substream: The substream to restrict
+ *
+ * Applies samplerate constraints that may be required by the firmware Should
+ * typically be called from the CODEC/component drivers startup callback.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int sigmadsp_restrict_params(struct sigmadsp *sigmadsp,
+	struct snd_pcm_substream *substream)
+{
+	if (sigmadsp->rate_constraints.count == 0)
+		return 0;
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+		SNDRV_PCM_HW_PARAM_RATE, &sigmadsp->rate_constraints);
+}
+EXPORT_SYMBOL_GPL(sigmadsp_restrict_params);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h
new file mode 100644
index 0000000..614475c
--- /dev/null
+++ b/sound/soc/codecs/sigmadsp.h
@@ -0,0 +1,66 @@
+/*
+ * Load firmware files from Analog Devices SigmaStudio
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __SIGMA_FIRMWARE_H__
+#define __SIGMA_FIRMWARE_H__
+
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/list.h>
+
+#include <sound/pcm.h>
+
+struct sigmadsp;
+struct snd_soc_component;
+struct snd_pcm_substream;
+
+struct sigmadsp_ops {
+	int (*safeload)(struct sigmadsp *sigmadsp, unsigned int addr,
+			const uint8_t *data, size_t len);
+};
+
+struct sigmadsp {
+	const struct sigmadsp_ops *ops;
+
+	struct list_head ctrl_list;
+	struct list_head data_list;
+
+	struct snd_pcm_hw_constraint_list rate_constraints;
+
+	unsigned int current_samplerate;
+	struct snd_soc_component *component;
+	struct device *dev;
+
+	struct mutex lock;
+
+	void *control_data;
+	int (*write)(void *, unsigned int, const uint8_t *, size_t);
+	int (*read)(void *, unsigned int, uint8_t *, size_t);
+};
+
+struct sigmadsp *devm_sigmadsp_init(struct device *dev,
+	const struct sigmadsp_ops *ops, const char *firmware_name);
+void sigmadsp_reset(struct sigmadsp *sigmadsp);
+
+int sigmadsp_restrict_params(struct sigmadsp *sigmadsp,
+	struct snd_pcm_substream *substream);
+
+struct i2c_client;
+
+struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev,
+	struct regmap *regmap, const struct sigmadsp_ops *ops,
+	const char *firmware_name);
+struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client,
+	const struct sigmadsp_ops *ops,	const char *firmware_name);
+
+int sigmadsp_attach(struct sigmadsp *sigmadsp,
+	struct snd_soc_component *component);
+int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int rate);
+void sigmadsp_reset(struct sigmadsp *sigmadsp);
+
+#endif
diff --git a/sound/soc/codecs/simple-amplifier.c b/sound/soc/codecs/simple-amplifier.c
new file mode 100644
index 0000000..85524ac
--- /dev/null
+++ b/sound/soc/codecs/simple-amplifier.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "simple-amplifier"
+
+struct simple_amp {
+	struct gpio_desc *gpiod_enable;
+};
+
+static int drv_event(struct snd_soc_dapm_widget *w,
+		     struct snd_kcontrol *control, int event)
+{
+	struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+	struct simple_amp *priv = snd_soc_component_get_drvdata(c);
+	int val;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		val = 1;
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		val = 0;
+		break;
+	default:
+		WARN(1, "Unexpected event");
+		return -EINVAL;
+	}
+
+	gpiod_set_value_cansleep(priv->gpiod_enable, val);
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget simple_amp_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("INL"),
+	SND_SOC_DAPM_INPUT("INR"),
+	SND_SOC_DAPM_OUT_DRV_E("DRV", SND_SOC_NOPM, 0, 0, NULL, 0, drv_event,
+			       (SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)),
+	SND_SOC_DAPM_OUTPUT("OUTL"),
+	SND_SOC_DAPM_OUTPUT("OUTR"),
+};
+
+static const struct snd_soc_dapm_route simple_amp_dapm_routes[] = {
+	{ "DRV", NULL, "INL" },
+	{ "DRV", NULL, "INR" },
+	{ "OUTL", NULL, "DRV" },
+	{ "OUTR", NULL, "DRV" },
+};
+
+static const struct snd_soc_component_driver simple_amp_component_driver = {
+	.dapm_widgets		= simple_amp_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(simple_amp_dapm_widgets),
+	.dapm_routes		= simple_amp_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(simple_amp_dapm_routes),
+};
+
+static int simple_amp_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct simple_amp *priv;
+	int err;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, priv);
+
+	priv->gpiod_enable = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+	if (IS_ERR(priv->gpiod_enable)) {
+		err = PTR_ERR(priv->gpiod_enable);
+		if (err != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get 'enable' gpio: %d", err);
+		return err;
+	}
+
+	return devm_snd_soc_register_component(dev,
+					       &simple_amp_component_driver,
+					       NULL, 0);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id simple_amp_ids[] = {
+	{ .compatible = "dioo,dio2125", },
+	{ .compatible = "simple-audio-amplifier", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, simple_amp_ids);
+#endif
+
+static struct platform_driver simple_amp_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = of_match_ptr(simple_amp_ids),
+	},
+	.probe = simple_amp_probe,
+};
+
+module_platform_driver(simple_amp_driver);
+
+MODULE_DESCRIPTION("ASoC Simple Audio Amplifier driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
new file mode 100644
index 0000000..e424499
--- /dev/null
+++ b/sound/soc/codecs/sirf-audio-codec.c
@@ -0,0 +1,581 @@
+/*
+ * SiRF audio codec driver
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "sirf-audio-codec.h"
+
+struct sirf_audio_codec {
+	struct clk *clk;
+	struct regmap *regmap;
+	u32 reg_ctrl0, reg_ctrl1;
+};
+
+static const char * const input_mode_mux[] = {"Single-ended",
+	"Differential"};
+
+static const struct soc_enum input_mode_mux_enum =
+	SOC_ENUM_SINGLE(AUDIO_IC_CODEC_CTRL1, 4, 2, input_mode_mux);
+
+static const struct snd_kcontrol_new sirf_audio_codec_input_mode_control =
+	SOC_DAPM_ENUM("Route", input_mode_mux_enum);
+
+static const DECLARE_TLV_DB_SCALE(playback_vol_tlv, -12400, 100, 0);
+static const DECLARE_TLV_DB_SCALE(capture_vol_tlv_prima2, 500, 100, 0);
+static const DECLARE_TLV_DB_RANGE(capture_vol_tlv_atlas6,
+	0, 7, TLV_DB_SCALE_ITEM(-100, 100, 0),
+	0x22, 0x3F, TLV_DB_SCALE_ITEM(700, 100, 0),
+);
+
+static struct snd_kcontrol_new volume_controls_atlas6[] = {
+	SOC_DOUBLE_TLV("Playback Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
+			0x7F, 0, playback_vol_tlv),
+	SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 16, 10,
+			0x3F, 0, capture_vol_tlv_atlas6),
+};
+
+static struct snd_kcontrol_new volume_controls_prima2[] = {
+	SOC_DOUBLE_TLV("Speaker Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
+			0x7F, 0, playback_vol_tlv),
+	SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 15, 10,
+			0x1F, 0, capture_vol_tlv_prima2),
+};
+
+static struct snd_kcontrol_new left_input_path_controls[] = {
+	SOC_DAPM_SINGLE("Line Left Switch", AUDIO_IC_CODEC_CTRL1, 6, 1, 0),
+	SOC_DAPM_SINGLE("Mic Left Switch", AUDIO_IC_CODEC_CTRL1, 3, 1, 0),
+};
+
+static struct snd_kcontrol_new right_input_path_controls[] = {
+	SOC_DAPM_SINGLE("Line Right Switch", AUDIO_IC_CODEC_CTRL1, 5, 1, 0),
+	SOC_DAPM_SINGLE("Mic Right Switch", AUDIO_IC_CODEC_CTRL1, 2, 1, 0),
+};
+
+static struct snd_kcontrol_new left_dac_to_hp_left_amp_switch_control =
+	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 9, 1, 0);
+
+static struct snd_kcontrol_new left_dac_to_hp_right_amp_switch_control =
+	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 8, 1, 0);
+
+static struct snd_kcontrol_new right_dac_to_hp_left_amp_switch_control =
+	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 7, 1, 0);
+
+static struct snd_kcontrol_new right_dac_to_hp_right_amp_switch_control =
+	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 6, 1, 0);
+
+static struct snd_kcontrol_new left_dac_to_speaker_lineout_switch_control =
+	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 11, 1, 0);
+
+static struct snd_kcontrol_new right_dac_to_speaker_lineout_switch_control =
+	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 10, 1, 0);
+
+/* After enable adc, Delay 200ms to avoid pop noise */
+static int adc_enable_delay_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		msleep(200);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static void enable_and_reset_codec(struct regmap *regmap,
+		u32 codec_enable_bits, u32 codec_reset_bits)
+{
+	regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
+			codec_enable_bits | codec_reset_bits,
+			codec_enable_bits);
+	msleep(20);
+	regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
+			codec_reset_bits, codec_reset_bits);
+}
+
+static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+#define ATLAS6_CODEC_ENABLE_BITS (1 << 29)
+#define ATLAS6_CODEC_RESET_BITS (1 << 28)
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		enable_and_reset_codec(sirf_audio_codec->regmap,
+			ATLAS6_CODEC_ENABLE_BITS, ATLAS6_CODEC_RESET_BITS);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_update_bits(sirf_audio_codec->regmap,
+			AUDIO_IC_CODEC_CTRL1, ATLAS6_CODEC_ENABLE_BITS, 0);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+#define PRIMA2_CODEC_ENABLE_BITS (1 << 27)
+#define PRIMA2_CODEC_RESET_BITS (1 << 26)
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		enable_and_reset_codec(sirf_audio_codec->regmap,
+			PRIMA2_CODEC_ENABLE_BITS, PRIMA2_CODEC_RESET_BITS);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		regmap_update_bits(sirf_audio_codec->regmap,
+			AUDIO_IC_CODEC_CTRL1, PRIMA2_CODEC_ENABLE_BITS, 0);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget atlas6_output_driver_dapm_widgets[] = {
+	SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
+			25, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
+			26, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
+			27, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget prima2_output_driver_dapm_widgets[] = {
+	SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
+			23, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
+			24, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
+			25, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget atlas6_codec_clock_dapm_widget =
+	SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
+			atlas6_codec_enable_and_reset_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
+
+static const struct snd_soc_dapm_widget prima2_codec_clock_dapm_widget =
+	SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
+			prima2_codec_enable_and_reset_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
+
+static const struct snd_soc_dapm_widget sirf_audio_codec_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC left", NULL, AUDIO_IC_CODEC_CTRL0, 1, 0),
+	SND_SOC_DAPM_DAC("DAC right", NULL, AUDIO_IC_CODEC_CTRL0, 0, 0),
+	SND_SOC_DAPM_SWITCH("Left dac to hp left amp", SND_SOC_NOPM, 0, 0,
+			&left_dac_to_hp_left_amp_switch_control),
+	SND_SOC_DAPM_SWITCH("Left dac to hp right amp", SND_SOC_NOPM, 0, 0,
+			&left_dac_to_hp_right_amp_switch_control),
+	SND_SOC_DAPM_SWITCH("Right dac to hp left amp", SND_SOC_NOPM, 0, 0,
+			&right_dac_to_hp_left_amp_switch_control),
+	SND_SOC_DAPM_SWITCH("Right dac to hp right amp", SND_SOC_NOPM, 0, 0,
+			&right_dac_to_hp_right_amp_switch_control),
+	SND_SOC_DAPM_OUT_DRV("HP amp left driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
+			NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("HP amp right driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_SWITCH("Left dac to speaker lineout", SND_SOC_NOPM, 0, 0,
+			&left_dac_to_speaker_lineout_switch_control),
+	SND_SOC_DAPM_SWITCH("Right dac to speaker lineout", SND_SOC_NOPM, 0, 0,
+			&right_dac_to_speaker_lineout_switch_control),
+	SND_SOC_DAPM_OUT_DRV("Speaker amp driver", AUDIO_IC_CODEC_CTRL0, 4, 0,
+			NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPOUTL"),
+	SND_SOC_DAPM_OUTPUT("HPOUTR"),
+	SND_SOC_DAPM_OUTPUT("SPKOUT"),
+
+	SND_SOC_DAPM_ADC_E("ADC left", NULL, AUDIO_IC_CODEC_CTRL1, 8, 0,
+			adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_ADC_E("ADC right", NULL, AUDIO_IC_CODEC_CTRL1, 7, 0,
+			adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MIXER("Left PGA mixer", AUDIO_IC_CODEC_CTRL1, 1, 0,
+		&left_input_path_controls[0],
+		ARRAY_SIZE(left_input_path_controls)),
+	SND_SOC_DAPM_MIXER("Right PGA mixer", AUDIO_IC_CODEC_CTRL1, 0, 0,
+		&right_input_path_controls[0],
+		ARRAY_SIZE(right_input_path_controls)),
+
+	SND_SOC_DAPM_MUX("Mic input mode mux", SND_SOC_NOPM, 0, 0,
+			&sirf_audio_codec_input_mode_control),
+	SND_SOC_DAPM_MICBIAS("Mic Bias", AUDIO_IC_CODEC_PWR, 3, 0),
+	SND_SOC_DAPM_INPUT("MICIN1"),
+	SND_SOC_DAPM_INPUT("MICIN2"),
+	SND_SOC_DAPM_INPUT("LINEIN1"),
+	SND_SOC_DAPM_INPUT("LINEIN2"),
+
+	SND_SOC_DAPM_SUPPLY("HSL Phase Opposite", AUDIO_IC_CODEC_CTRL0,
+			30, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route sirf_audio_codec_map[] = {
+	{"SPKOUT", NULL, "Speaker Driver"},
+	{"Speaker Driver", NULL, "Speaker amp driver"},
+	{"Speaker amp driver", NULL, "Left dac to speaker lineout"},
+	{"Speaker amp driver", NULL, "Right dac to speaker lineout"},
+	{"Left dac to speaker lineout", "Switch", "DAC left"},
+	{"Right dac to speaker lineout", "Switch", "DAC right"},
+	{"HPOUTL", NULL, "HP Left Driver"},
+	{"HPOUTR", NULL, "HP Right Driver"},
+	{"HP Left Driver", NULL, "HP amp left driver"},
+	{"HP Right Driver", NULL, "HP amp right driver"},
+	{"HP amp left driver", NULL, "Right dac to hp left amp"},
+	{"HP amp right driver", NULL , "Right dac to hp right amp"},
+	{"HP amp left driver", NULL, "Left dac to hp left amp"},
+	{"HP amp right driver", NULL , "Right dac to hp right amp"},
+	{"Right dac to hp left amp", "Switch", "DAC left"},
+	{"Right dac to hp right amp", "Switch", "DAC right"},
+	{"Left dac to hp left amp", "Switch", "DAC left"},
+	{"Left dac to hp right amp", "Switch", "DAC right"},
+	{"DAC left", NULL, "codecclk"},
+	{"DAC right", NULL, "codecclk"},
+	{"DAC left", NULL, "Playback"},
+	{"DAC right", NULL, "Playback"},
+	{"DAC left", NULL, "HSL Phase Opposite"},
+	{"DAC right", NULL, "HSL Phase Opposite"},
+
+	{"Capture", NULL, "ADC left"},
+	{"Capture", NULL, "ADC right"},
+	{"ADC left", NULL, "codecclk"},
+	{"ADC right", NULL, "codecclk"},
+	{"ADC left", NULL, "Left PGA mixer"},
+	{"ADC right", NULL, "Right PGA mixer"},
+	{"Left PGA mixer", "Line Left Switch", "LINEIN2"},
+	{"Right PGA mixer", "Line Right Switch", "LINEIN1"},
+	{"Left PGA mixer", "Mic Left Switch", "MICIN2"},
+	{"Right PGA mixer", "Mic Right Switch", "Mic input mode mux"},
+	{"Mic input mode mux", "Single-ended", "MICIN1"},
+	{"Mic input mode mux", "Differential", "MICIN1"},
+};
+
+static void sirf_audio_codec_tx_enable(struct sirf_audio_codec *sirf_audio_codec)
+{
+	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
+		AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
+	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
+		AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET);
+	regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0);
+	regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
+	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
+		AUDIO_FIFO_START, AUDIO_FIFO_START);
+	regmap_update_bits(sirf_audio_codec->regmap,
+		AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, IC_TX_ENABLE);
+}
+
+static void sirf_audio_codec_tx_disable(struct sirf_audio_codec *sirf_audio_codec)
+{
+	regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
+	regmap_update_bits(sirf_audio_codec->regmap,
+		AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, ~IC_TX_ENABLE);
+}
+
+static void sirf_audio_codec_rx_enable(struct sirf_audio_codec *sirf_audio_codec,
+	int channels)
+{
+	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
+		AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
+	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
+		AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET);
+	regmap_write(sirf_audio_codec->regmap,
+		AUDIO_PORT_IC_RXFIFO_INT_MSK, 0);
+	regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0);
+	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
+		AUDIO_FIFO_START, AUDIO_FIFO_START);
+	if (channels == 1)
+		regmap_update_bits(sirf_audio_codec->regmap,
+			AUDIO_PORT_IC_CODEC_RX_CTRL,
+			IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO);
+	else
+		regmap_update_bits(sirf_audio_codec->regmap,
+			AUDIO_PORT_IC_CODEC_RX_CTRL,
+			IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO);
+}
+
+static void sirf_audio_codec_rx_disable(struct sirf_audio_codec *sirf_audio_codec)
+{
+	regmap_update_bits(sirf_audio_codec->regmap,
+			AUDIO_PORT_IC_CODEC_RX_CTRL,
+			IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO);
+}
+
+static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
+		int cmd,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
+	int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+
+	/*
+	 * This is a workaround, When stop playback,
+	 * need disable HP amp, avoid the current noise.
+	 */
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (playback) {
+			snd_soc_component_update_bits(component, AUDIO_IC_CODEC_CTRL0,
+				IC_HSLEN | IC_HSREN, 0);
+			sirf_audio_codec_tx_disable(sirf_audio_codec);
+		} else
+			sirf_audio_codec_rx_disable(sirf_audio_codec);
+		break;
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (playback) {
+			sirf_audio_codec_tx_enable(sirf_audio_codec);
+			snd_soc_component_update_bits(component, AUDIO_IC_CODEC_CTRL0,
+				IC_HSLEN | IC_HSREN, IC_HSLEN | IC_HSREN);
+		} else
+			sirf_audio_codec_rx_enable(sirf_audio_codec,
+				substream->runtime->channels);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops sirf_audio_codec_dai_ops = {
+	.trigger = sirf_audio_codec_trigger,
+};
+
+static struct snd_soc_dai_driver sirf_audio_codec_dai = {
+	.name = "sirf-audio-codec",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &sirf_audio_codec_dai_ops,
+};
+
+static int sirf_audio_codec_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	pm_runtime_enable(component->dev);
+
+	if (of_device_is_compatible(component->dev->of_node, "sirf,prima2-audio-codec")) {
+		snd_soc_dapm_new_controls(dapm,
+			prima2_output_driver_dapm_widgets,
+			ARRAY_SIZE(prima2_output_driver_dapm_widgets));
+		snd_soc_dapm_new_controls(dapm,
+			&prima2_codec_clock_dapm_widget, 1);
+		return snd_soc_add_component_controls(component,
+			volume_controls_prima2,
+			ARRAY_SIZE(volume_controls_prima2));
+	}
+	if (of_device_is_compatible(component->dev->of_node, "sirf,atlas6-audio-codec")) {
+		snd_soc_dapm_new_controls(dapm,
+			atlas6_output_driver_dapm_widgets,
+			ARRAY_SIZE(atlas6_output_driver_dapm_widgets));
+		snd_soc_dapm_new_controls(dapm,
+			&atlas6_codec_clock_dapm_widget, 1);
+		return snd_soc_add_component_controls(component,
+			volume_controls_atlas6,
+			ARRAY_SIZE(volume_controls_atlas6));
+	}
+
+	return -EINVAL;
+}
+
+static void sirf_audio_codec_remove(struct snd_soc_component *component)
+{
+	pm_runtime_disable(component->dev);
+}
+
+static const struct snd_soc_component_driver soc_codec_device_sirf_audio_codec = {
+	.probe			= sirf_audio_codec_probe,
+	.remove			= sirf_audio_codec_remove,
+	.dapm_widgets		= sirf_audio_codec_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sirf_audio_codec_dapm_widgets),
+	.dapm_routes		= sirf_audio_codec_map,
+	.num_dapm_routes	= ARRAY_SIZE(sirf_audio_codec_map),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct of_device_id sirf_audio_codec_of_match[] = {
+	{ .compatible = "sirf,prima2-audio-codec" },
+	{ .compatible = "sirf,atlas6-audio-codec" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, sirf_audio_codec_of_match);
+
+static const struct regmap_config sirf_audio_codec_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK,
+	.cache_type = REGCACHE_NONE,
+};
+
+static int sirf_audio_codec_driver_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct sirf_audio_codec *sirf_audio_codec;
+	void __iomem *base;
+	struct resource *mem_res;
+	const struct of_device_id *match;
+
+	match = of_match_node(sirf_audio_codec_of_match, pdev->dev.of_node);
+
+	sirf_audio_codec = devm_kzalloc(&pdev->dev,
+		sizeof(struct sirf_audio_codec), GFP_KERNEL);
+	if (!sirf_audio_codec)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, sirf_audio_codec);
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, mem_res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	sirf_audio_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+					    &sirf_audio_codec_regmap_config);
+	if (IS_ERR(sirf_audio_codec->regmap))
+		return PTR_ERR(sirf_audio_codec->regmap);
+
+	sirf_audio_codec->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(sirf_audio_codec->clk)) {
+		dev_err(&pdev->dev, "Get clock failed.\n");
+		return PTR_ERR(sirf_audio_codec->clk);
+	}
+
+	ret = clk_prepare_enable(sirf_audio_codec->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Enable clock failed.\n");
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&(pdev->dev),
+			&soc_codec_device_sirf_audio_codec,
+			&sirf_audio_codec_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "Register Audio Codec dai failed.\n");
+		goto err_clk_put;
+	}
+
+	/*
+	 * Always open charge pump, if not, when the charge pump closed the
+	 * adc will not stable
+	 */
+	regmap_update_bits(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
+		IC_CPFREQ, IC_CPFREQ);
+
+	if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas6-audio-codec"))
+		regmap_update_bits(sirf_audio_codec->regmap,
+				AUDIO_IC_CODEC_CTRL0, IC_CPEN, IC_CPEN);
+	return 0;
+
+err_clk_put:
+	clk_disable_unprepare(sirf_audio_codec->clk);
+	return ret;
+}
+
+static int sirf_audio_codec_driver_remove(struct platform_device *pdev)
+{
+	struct sirf_audio_codec *sirf_audio_codec = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(sirf_audio_codec->clk);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int sirf_audio_codec_suspend(struct device *dev)
+{
+	struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
+
+	regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
+		&sirf_audio_codec->reg_ctrl0);
+	regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
+		&sirf_audio_codec->reg_ctrl1);
+	clk_disable_unprepare(sirf_audio_codec->clk);
+
+	return 0;
+}
+
+static int sirf_audio_codec_resume(struct device *dev)
+{
+	struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(sirf_audio_codec->clk);
+	if (ret)
+		return ret;
+
+	regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
+		sirf_audio_codec->reg_ctrl0);
+	regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
+		sirf_audio_codec->reg_ctrl1);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops sirf_audio_codec_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(sirf_audio_codec_suspend, sirf_audio_codec_resume)
+};
+
+static struct platform_driver sirf_audio_codec_driver = {
+	.driver = {
+		.name = "sirf-audio-codec",
+		.of_match_table = sirf_audio_codec_of_match,
+		.pm = &sirf_audio_codec_pm_ops,
+	},
+	.probe = sirf_audio_codec_driver_probe,
+	.remove = sirf_audio_codec_driver_remove,
+};
+
+module_platform_driver(sirf_audio_codec_driver);
+
+MODULE_DESCRIPTION("SiRF audio codec driver");
+MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/sirf-audio-codec.h b/sound/soc/codecs/sirf-audio-codec.h
new file mode 100644
index 0000000..ba1adc0
--- /dev/null
+++ b/sound/soc/codecs/sirf-audio-codec.h
@@ -0,0 +1,125 @@
+/*
+ * SiRF inner codec controllers define
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef _SIRF_AUDIO_CODEC_H
+#define _SIRF_AUDIO_CODEC_H
+
+
+#define AUDIO_IC_CODEC_PWR			(0x00E0)
+#define AUDIO_IC_CODEC_CTRL0			(0x00E4)
+#define AUDIO_IC_CODEC_CTRL1			(0x00E8)
+#define AUDIO_IC_CODEC_CTRL2			(0x00EC)
+#define AUDIO_IC_CODEC_CTRL3			(0x00F0)
+
+#define MICBIASEN		(1 << 3)
+
+#define IC_RDACEN		(1 << 0)
+#define IC_LDACEN		(1 << 1)
+#define IC_HSREN		(1 << 2)
+#define IC_HSLEN		(1 << 3)
+#define IC_SPEN			(1 << 4)
+#define IC_CPEN			(1 << 5)
+
+#define IC_HPRSELR		(1 << 6)
+#define IC_HPLSELR		(1 << 7)
+#define IC_HPRSELL		(1 << 8)
+#define IC_HPLSELL		(1 << 9)
+#define IC_SPSELR		(1 << 10)
+#define IC_SPSELL		(1 << 11)
+
+#define IC_MONOR		(1 << 12)
+#define IC_MONOL		(1 << 13)
+
+#define IC_RXOSRSEL		(1 << 28)
+#define IC_CPFREQ		(1 << 29)
+#define IC_HSINVEN		(1 << 30)
+
+#define IC_MICINREN		(1 << 0)
+#define IC_MICINLEN		(1 << 1)
+#define IC_MICIN1SEL		(1 << 2)
+#define IC_MICIN2SEL		(1 << 3)
+#define IC_MICDIFSEL		(1 << 4)
+#define	IC_LINEIN1SEL		(1 << 5)
+#define	IC_LINEIN2SEL		(1 << 6)
+#define	IC_RADCEN		(1 << 7)
+#define	IC_LADCEN		(1 << 8)
+#define	IC_ALM			(1 << 9)
+
+#define IC_DIGMICEN             (1 << 22)
+#define IC_DIGMICFREQ           (1 << 23)
+#define IC_ADC14B_12            (1 << 24)
+#define IC_FIRDAC_HSL_EN        (1 << 25)
+#define IC_FIRDAC_HSR_EN        (1 << 26)
+#define IC_FIRDAC_LOUT_EN       (1 << 27)
+#define IC_POR                  (1 << 28)
+#define IC_CODEC_CLK_EN         (1 << 29)
+#define IC_HP_3DB_BOOST         (1 << 30)
+
+#define IC_ADC_LEFT_GAIN_SHIFT	16
+#define IC_ADC_RIGHT_GAIN_SHIFT 10
+#define IC_ADC_GAIN_MASK	0x3F
+#define IC_MIC_MAX_GAIN		0x39
+
+#define IC_RXPGAR_MASK		0x3F
+#define IC_RXPGAR_SHIFT		14
+#define IC_RXPGAL_MASK		0x3F
+#define IC_RXPGAL_SHIFT		21
+#define IC_RXPGAR		0x7B
+#define IC_RXPGAL		0x7B
+
+#define AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK     0x3F
+#define AUDIO_PORT_TX_FIFO_SC_OFFSET    0
+#define AUDIO_PORT_TX_FIFO_LC_OFFSET    10
+#define AUDIO_PORT_TX_FIFO_HC_OFFSET    20
+
+#define TX_FIFO_SC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+				<< AUDIO_PORT_TX_FIFO_SC_OFFSET)
+#define TX_FIFO_LC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+				<< AUDIO_PORT_TX_FIFO_LC_OFFSET)
+#define TX_FIFO_HC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+				<< AUDIO_PORT_TX_FIFO_HC_OFFSET)
+
+#define AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK     0x0F
+#define AUDIO_PORT_RX_FIFO_SC_OFFSET    0
+#define AUDIO_PORT_RX_FIFO_LC_OFFSET    10
+#define AUDIO_PORT_RX_FIFO_HC_OFFSET    20
+
+#define RX_FIFO_SC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+				<< AUDIO_PORT_RX_FIFO_SC_OFFSET)
+#define RX_FIFO_LC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+				<< AUDIO_PORT_RX_FIFO_LC_OFFSET)
+#define RX_FIFO_HC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+				<< AUDIO_PORT_RX_FIFO_HC_OFFSET)
+#define AUDIO_PORT_IC_CODEC_TX_CTRL		(0x00F4)
+#define AUDIO_PORT_IC_CODEC_RX_CTRL		(0x00F8)
+
+#define AUDIO_PORT_IC_TXFIFO_OP			(0x00FC)
+#define AUDIO_PORT_IC_TXFIFO_LEV_CHK		(0x0100)
+#define AUDIO_PORT_IC_TXFIFO_STS		(0x0104)
+#define AUDIO_PORT_IC_TXFIFO_INT		(0x0108)
+#define AUDIO_PORT_IC_TXFIFO_INT_MSK		(0x010C)
+
+#define AUDIO_PORT_IC_RXFIFO_OP			(0x0110)
+#define AUDIO_PORT_IC_RXFIFO_LEV_CHK		(0x0114)
+#define AUDIO_PORT_IC_RXFIFO_STS		(0x0118)
+#define AUDIO_PORT_IC_RXFIFO_INT		(0x011C)
+#define AUDIO_PORT_IC_RXFIFO_INT_MSK		(0x0120)
+
+#define AUDIO_FIFO_START		(1 << 0)
+#define AUDIO_FIFO_RESET		(1 << 1)
+
+#define AUDIO_FIFO_FULL			(1 << 0)
+#define AUDIO_FIFO_EMPTY		(1 << 1)
+#define AUDIO_FIFO_OFLOW		(1 << 2)
+#define AUDIO_FIFO_UFLOW		(1 << 3)
+
+#define IC_TX_ENABLE		(0x03)
+#define IC_RX_ENABLE_MONO	(0x01)
+#define IC_RX_ENABLE_STEREO	(0x03)
+
+#endif /*__SIRF_AUDIO_CODEC_H*/
diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c
new file mode 100644
index 0000000..ac69d49
--- /dev/null
+++ b/sound/soc/codecs/spdif_receiver.c
@@ -0,0 +1,90 @@
+/*
+ * ALSA SoC SPDIF DIR (Digital Interface Reciever) driver
+ *
+ * Based on ALSA SoC SPDIF DIT driver
+ *
+ *  This driver is used by controllers which can operate in DIR (SPDI/F) where
+ *  no codec is needed.  This file provides stub codec that can be used
+ *  in these configurations. SPEAr SPDIF IN Audio controller uses this driver.
+ *
+ * Author:      Vipin Kumar,  <vipin.kumar@st.com>
+ * Copyright:   (C) 2012  ST Microelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <linux/of.h>
+
+static const struct snd_soc_dapm_widget dir_widgets[] = {
+	SND_SOC_DAPM_INPUT("spdif-in"),
+};
+
+static const struct snd_soc_dapm_route dir_routes[] = {
+	{ "Capture", NULL, "spdif-in" },
+};
+
+#define STUB_RATES	SNDRV_PCM_RATE_8000_192000
+#define STUB_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE  | \
+			SNDRV_PCM_FMTBIT_S32_LE | \
+			SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
+
+static struct snd_soc_component_driver soc_codec_spdif_dir = {
+	.dapm_widgets		= dir_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(dir_widgets),
+	.dapm_routes		= dir_routes,
+	.num_dapm_routes	= ARRAY_SIZE(dir_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static struct snd_soc_dai_driver dir_stub_dai = {
+	.name		= "dir-hifi",
+	.capture	= {
+		.stream_name	= "Capture",
+		.channels_min	= 1,
+		.channels_max	= 384,
+		.rates		= STUB_RATES,
+		.formats	= STUB_FORMATS,
+	},
+};
+
+static int spdif_dir_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_codec_spdif_dir,
+			&dir_stub_dai, 1);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id spdif_dir_dt_ids[] = {
+	{ .compatible = "linux,spdif-dir", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, spdif_dir_dt_ids);
+#endif
+
+static struct platform_driver spdif_dir_driver = {
+	.probe		= spdif_dir_probe,
+	.driver		= {
+		.name	= "spdif-dir",
+		.of_match_table = of_match_ptr(spdif_dir_dt_ids),
+	},
+};
+
+module_platform_driver(spdif_dir_driver);
+
+MODULE_DESCRIPTION("ASoC SPDIF DIR driver");
+MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c
new file mode 100644
index 0000000..b4f7fc4
--- /dev/null
+++ b/sound/soc/codecs/spdif_transmitter.c
@@ -0,0 +1,91 @@
+/*
+ * ALSA SoC SPDIF DIT driver
+ *
+ *  This driver is used by controllers which can operate in DIT (SPDI/F) where
+ *  no codec is needed.  This file provides stub codec that can be used
+ *  in these configurations. TI DaVinci Audio controller uses this driver.
+ *
+ * Author:      Steve Chen,  <schen@mvista.com>
+ * Copyright:   (C) 2009 MontaVista Software, Inc., <source@mvista.com>
+ * Copyright:   (C) 2009  Texas Instruments, India
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <linux/of.h>
+
+#define DRV_NAME "spdif-dit"
+
+#define STUB_RATES	SNDRV_PCM_RATE_8000_192000
+#define STUB_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE  | \
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dapm_widget dit_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("spdif-out"),
+};
+
+static const struct snd_soc_dapm_route dit_routes[] = {
+	{ "spdif-out", NULL, "Playback" },
+};
+
+static struct snd_soc_component_driver soc_codec_spdif_dit = {
+	.dapm_widgets		= dit_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(dit_widgets),
+	.dapm_routes		= dit_routes,
+	.num_dapm_routes	= ARRAY_SIZE(dit_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static struct snd_soc_dai_driver dit_stub_dai = {
+	.name		= "dit-hifi",
+	.playback 	= {
+		.stream_name	= "Playback",
+		.channels_min	= 1,
+		.channels_max	= 384,
+		.rates		= STUB_RATES,
+		.formats	= STUB_FORMATS,
+	},
+};
+
+static int spdif_dit_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_codec_spdif_dit,
+			&dit_stub_dai, 1);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id spdif_dit_dt_ids[] = {
+	{ .compatible = "linux,spdif-dit", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, spdif_dit_dt_ids);
+#endif
+
+static struct platform_driver spdif_dit_driver = {
+	.probe		= spdif_dit_probe,
+	.driver		= {
+		.name	= DRV_NAME,
+		.of_match_table = of_match_ptr(spdif_dit_dt_ids),
+	},
+};
+
+module_platform_driver(spdif_dit_driver);
+
+MODULE_AUTHOR("Steve Chen <schen@mvista.com>");
+MODULE_DESCRIPTION("SPDIF dummy codec driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/codecs/ssm2305.c b/sound/soc/codecs/ssm2305.c
new file mode 100644
index 0000000..2968959
--- /dev/null
+++ b/sound/soc/codecs/ssm2305.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Analog Devices SSM2305 Amplifier Driver
+//
+// Copyright (C) 2018 Pengutronix, Marco Felsch <kernel@pengutronix.de>
+//
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "ssm2305"
+
+struct ssm2305 {
+	/* shutdown gpio  */
+	struct gpio_desc *gpiod_shutdown;
+};
+
+static int ssm2305_power_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kctrl, int event)
+{
+	struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+	struct ssm2305 *data = snd_soc_component_get_drvdata(c);
+
+	gpiod_set_value_cansleep(data->gpiod_shutdown,
+				 SND_SOC_DAPM_EVENT_ON(event));
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget ssm2305_dapm_widgets[] = {
+	/* Stereo input/output */
+	SND_SOC_DAPM_INPUT("L_IN"),
+	SND_SOC_DAPM_INPUT("R_IN"),
+	SND_SOC_DAPM_OUTPUT("L_OUT"),
+	SND_SOC_DAPM_OUTPUT("R_OUT"),
+
+	SND_SOC_DAPM_SUPPLY("Power", SND_SOC_NOPM, 0, 0, ssm2305_power_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route ssm2305_dapm_routes[] = {
+	{ "L_OUT", NULL, "L_IN" },
+	{ "R_OUT", NULL, "R_IN" },
+	{ "L_IN", NULL, "Power" },
+	{ "R_IN", NULL, "Power" },
+};
+
+static const struct snd_soc_component_driver ssm2305_component_driver = {
+	.dapm_widgets		= ssm2305_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ssm2305_dapm_widgets),
+	.dapm_routes		= ssm2305_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ssm2305_dapm_routes),
+};
+
+static int ssm2305_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ssm2305 *priv;
+	int err;
+
+	/* Allocate the private data */
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, priv);
+
+	/* Get shutdown gpio */
+	priv->gpiod_shutdown = devm_gpiod_get(dev, "shutdown",
+					      GPIOD_OUT_LOW);
+	if (IS_ERR(priv->gpiod_shutdown)) {
+		err = PTR_ERR(priv->gpiod_shutdown);
+		if (err != -EPROBE_DEFER)
+			dev_err(dev, "Failed to get 'shutdown' gpio: %d\n",
+				err);
+		return err;
+	}
+
+	return devm_snd_soc_register_component(dev, &ssm2305_component_driver,
+					       NULL, 0);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id ssm2305_of_match[] = {
+	{ .compatible = "adi,ssm2305", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ssm2305_of_match);
+#endif
+
+static struct platform_driver ssm2305_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = of_match_ptr(ssm2305_of_match),
+	},
+	.probe = ssm2305_probe,
+};
+
+module_platform_driver(ssm2305_driver);
+
+MODULE_DESCRIPTION("ASoC SSM2305 amplifier driver");
+MODULE_AUTHOR("Marco Felsch <m.felsch@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
new file mode 100644
index 0000000..4a1d42a
--- /dev/null
+++ b/sound/soc/codecs/ssm2518.c
@@ -0,0 +1,825 @@
+/*
+ * SSM2518 amplifier audio driver
+ *
+ * Copyright 2013 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_data/ssm2518.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "ssm2518.h"
+
+#define SSM2518_REG_POWER1		0x00
+#define SSM2518_REG_CLOCK		0x01
+#define SSM2518_REG_SAI_CTRL1		0x02
+#define SSM2518_REG_SAI_CTRL2		0x03
+#define SSM2518_REG_CHAN_MAP		0x04
+#define SSM2518_REG_LEFT_VOL		0x05
+#define SSM2518_REG_RIGHT_VOL		0x06
+#define SSM2518_REG_MUTE_CTRL		0x07
+#define SSM2518_REG_FAULT_CTRL		0x08
+#define SSM2518_REG_POWER2		0x09
+#define SSM2518_REG_DRC_1		0x0a
+#define SSM2518_REG_DRC_2		0x0b
+#define SSM2518_REG_DRC_3		0x0c
+#define SSM2518_REG_DRC_4		0x0d
+#define SSM2518_REG_DRC_5		0x0e
+#define SSM2518_REG_DRC_6		0x0f
+#define SSM2518_REG_DRC_7		0x10
+#define SSM2518_REG_DRC_8		0x11
+#define SSM2518_REG_DRC_9		0x12
+
+#define SSM2518_POWER1_RESET			BIT(7)
+#define SSM2518_POWER1_NO_BCLK			BIT(5)
+#define SSM2518_POWER1_MCS_MASK			(0xf << 1)
+#define SSM2518_POWER1_MCS_64FS			(0x0 << 1)
+#define SSM2518_POWER1_MCS_128FS		(0x1 << 1)
+#define SSM2518_POWER1_MCS_256FS		(0x2 << 1)
+#define SSM2518_POWER1_MCS_384FS		(0x3 << 1)
+#define SSM2518_POWER1_MCS_512FS		(0x4 << 1)
+#define SSM2518_POWER1_MCS_768FS		(0x5 << 1)
+#define SSM2518_POWER1_MCS_100FS		(0x6 << 1)
+#define SSM2518_POWER1_MCS_200FS		(0x7 << 1)
+#define SSM2518_POWER1_MCS_400FS		(0x8 << 1)
+#define SSM2518_POWER1_SPWDN			BIT(0)
+
+#define SSM2518_CLOCK_ASR			BIT(0)
+
+#define SSM2518_SAI_CTRL1_FMT_MASK		(0x3 << 5)
+#define SSM2518_SAI_CTRL1_FMT_I2S		(0x0 << 5)
+#define SSM2518_SAI_CTRL1_FMT_LJ		(0x1 << 5)
+#define SSM2518_SAI_CTRL1_FMT_RJ_24BIT		(0x2 << 5)
+#define SSM2518_SAI_CTRL1_FMT_RJ_16BIT		(0x3 << 5)
+
+#define SSM2518_SAI_CTRL1_SAI_MASK		(0x7 << 2)
+#define SSM2518_SAI_CTRL1_SAI_I2S		(0x0 << 2)
+#define SSM2518_SAI_CTRL1_SAI_TDM_2		(0x1 << 2)
+#define SSM2518_SAI_CTRL1_SAI_TDM_4		(0x2 << 2)
+#define SSM2518_SAI_CTRL1_SAI_TDM_8		(0x3 << 2)
+#define SSM2518_SAI_CTRL1_SAI_TDM_16		(0x4 << 2)
+#define SSM2518_SAI_CTRL1_SAI_MONO		(0x5 << 2)
+
+#define SSM2518_SAI_CTRL1_FS_MASK		(0x3)
+#define SSM2518_SAI_CTRL1_FS_8000_12000		(0x0)
+#define SSM2518_SAI_CTRL1_FS_16000_24000	(0x1)
+#define SSM2518_SAI_CTRL1_FS_32000_48000	(0x2)
+#define SSM2518_SAI_CTRL1_FS_64000_96000	(0x3)
+
+#define SSM2518_SAI_CTRL2_BCLK_INTERAL		BIT(7)
+#define SSM2518_SAI_CTRL2_LRCLK_PULSE		BIT(6)
+#define SSM2518_SAI_CTRL2_LRCLK_INVERT		BIT(5)
+#define SSM2518_SAI_CTRL2_MSB			BIT(4)
+#define SSM2518_SAI_CTRL2_SLOT_WIDTH_MASK	(0x3 << 2)
+#define SSM2518_SAI_CTRL2_SLOT_WIDTH_32		(0x0 << 2)
+#define SSM2518_SAI_CTRL2_SLOT_WIDTH_24		(0x1 << 2)
+#define SSM2518_SAI_CTRL2_SLOT_WIDTH_16		(0x2 << 2)
+#define SSM2518_SAI_CTRL2_BCLK_INVERT		BIT(1)
+
+#define SSM2518_CHAN_MAP_RIGHT_SLOT_OFFSET	4
+#define SSM2518_CHAN_MAP_RIGHT_SLOT_MASK	0xf0
+#define SSM2518_CHAN_MAP_LEFT_SLOT_OFFSET	0
+#define SSM2518_CHAN_MAP_LEFT_SLOT_MASK		0x0f
+
+#define SSM2518_MUTE_CTRL_ANA_GAIN		BIT(5)
+#define SSM2518_MUTE_CTRL_MUTE_MASTER		BIT(0)
+
+#define SSM2518_POWER2_APWDN			BIT(0)
+
+#define SSM2518_DAC_MUTE			BIT(6)
+#define SSM2518_DAC_FS_MASK			0x07
+#define SSM2518_DAC_FS_8000			0x00
+#define SSM2518_DAC_FS_16000			0x01
+#define SSM2518_DAC_FS_32000			0x02
+#define SSM2518_DAC_FS_64000			0x03
+#define SSM2518_DAC_FS_128000			0x04
+
+struct ssm2518 {
+	struct regmap *regmap;
+	bool right_j;
+
+	unsigned int sysclk;
+	const struct snd_pcm_hw_constraint_list *constraints;
+
+	int enable_gpio;
+};
+
+static const struct reg_default ssm2518_reg_defaults[] = {
+	{ 0x00, 0x05 },
+	{ 0x01, 0x00 },
+	{ 0x02, 0x02 },
+	{ 0x03, 0x00 },
+	{ 0x04, 0x10 },
+	{ 0x05, 0x40 },
+	{ 0x06, 0x40 },
+	{ 0x07, 0x81 },
+	{ 0x08, 0x0c },
+	{ 0x09, 0x99 },
+	{ 0x0a, 0x7c },
+	{ 0x0b, 0x5b },
+	{ 0x0c, 0x57 },
+	{ 0x0d, 0x89 },
+	{ 0x0e, 0x8c },
+	{ 0x0f, 0x77 },
+	{ 0x10, 0x26 },
+	{ 0x11, 0x1c },
+	{ 0x12, 0x97 },
+};
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(ssm2518_vol_tlv, -7125, 2400);
+static const DECLARE_TLV_DB_SCALE(ssm2518_compressor_tlv, -3400, 200, 0);
+static const DECLARE_TLV_DB_SCALE(ssm2518_expander_tlv, -8100, 300, 0);
+static const DECLARE_TLV_DB_SCALE(ssm2518_noise_gate_tlv, -9600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(ssm2518_post_drc_tlv, -2400, 300, 0);
+
+static const DECLARE_TLV_DB_RANGE(ssm2518_limiter_tlv,
+	0, 7, TLV_DB_SCALE_ITEM(-2200, 200, 0),
+	7, 15, TLV_DB_SCALE_ITEM(-800, 100, 0),
+);
+
+static const char * const ssm2518_drc_peak_detector_attack_time_text[] = {
+	"0 ms", "0.1 ms", "0.19 ms", "0.37 ms", "0.75 ms", "1.5 ms", "3 ms",
+	"6 ms", "12 ms", "24 ms", "48 ms", "96 ms", "192 ms", "384 ms",
+	"768 ms", "1536 ms",
+};
+
+static const char * const ssm2518_drc_peak_detector_release_time_text[] = {
+	"0 ms", "1.5 ms", "3 ms", "6 ms", "12 ms", "24 ms", "48 ms", "96 ms",
+	"192 ms", "384 ms", "768 ms", "1536 ms", "3072 ms", "6144 ms",
+	"12288 ms", "24576 ms"
+};
+
+static const char * const ssm2518_drc_hold_time_text[] = {
+	"0 ms", "0.67 ms", "1.33 ms", "2.67 ms", "5.33 ms", "10.66 ms",
+	"21.32 ms", "42.64 ms", "85.28 ms", "170.56 ms", "341.12 ms",
+	"682.24 ms", "1364 ms",
+};
+
+static SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum,
+	SSM2518_REG_DRC_2, 4, ssm2518_drc_peak_detector_attack_time_text);
+static SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum,
+	SSM2518_REG_DRC_2, 0, ssm2518_drc_peak_detector_release_time_text);
+static SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum,
+	SSM2518_REG_DRC_6, 4, ssm2518_drc_peak_detector_attack_time_text);
+static SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum,
+	SSM2518_REG_DRC_6, 0, ssm2518_drc_peak_detector_release_time_text);
+static SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum,
+	SSM2518_REG_DRC_7, 4, ssm2518_drc_hold_time_text);
+static SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum,
+	SSM2518_REG_DRC_7, 0, ssm2518_drc_hold_time_text);
+static SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum,
+	SSM2518_REG_DRC_9, 0, ssm2518_drc_peak_detector_release_time_text);
+
+static const struct snd_kcontrol_new ssm2518_snd_controls[] = {
+	SOC_SINGLE("Playback De-emphasis Switch", SSM2518_REG_MUTE_CTRL,
+			4, 1, 0),
+	SOC_DOUBLE_R_TLV("Master Playback Volume", SSM2518_REG_LEFT_VOL,
+			SSM2518_REG_RIGHT_VOL, 0, 0xff, 1, ssm2518_vol_tlv),
+	SOC_DOUBLE("Master Playback Switch", SSM2518_REG_MUTE_CTRL, 2, 1, 1, 1),
+
+	SOC_SINGLE("Amp Low Power Mode Switch", SSM2518_REG_POWER2, 4, 1, 0),
+	SOC_SINGLE("DAC Low Power Mode Switch", SSM2518_REG_POWER2, 3, 1, 0),
+
+	SOC_SINGLE("DRC Limiter Switch", SSM2518_REG_DRC_1, 5, 1, 0),
+	SOC_SINGLE("DRC Compressor Switch", SSM2518_REG_DRC_1, 4, 1, 0),
+	SOC_SINGLE("DRC Expander Switch", SSM2518_REG_DRC_1, 3, 1, 0),
+	SOC_SINGLE("DRC Noise Gate Switch", SSM2518_REG_DRC_1, 2, 1, 0),
+	SOC_DOUBLE("DRC Switch", SSM2518_REG_DRC_1, 0, 1, 1, 0),
+
+	SOC_SINGLE_TLV("DRC Limiter Threshold Volume",
+			SSM2518_REG_DRC_3, 4, 15, 1, ssm2518_limiter_tlv),
+	SOC_SINGLE_TLV("DRC Compressor Lower Threshold Volume",
+			SSM2518_REG_DRC_3, 0, 15, 1, ssm2518_compressor_tlv),
+	SOC_SINGLE_TLV("DRC Expander Upper Threshold Volume", SSM2518_REG_DRC_4,
+			4, 15, 1, ssm2518_expander_tlv),
+	SOC_SINGLE_TLV("DRC Noise Gate Threshold Volume",
+			SSM2518_REG_DRC_4, 0, 15, 1, ssm2518_noise_gate_tlv),
+	SOC_SINGLE_TLV("DRC Upper Output Threshold Volume",
+			SSM2518_REG_DRC_5, 4, 15, 1, ssm2518_limiter_tlv),
+	SOC_SINGLE_TLV("DRC Lower Output Threshold Volume",
+			SSM2518_REG_DRC_5, 0, 15, 1, ssm2518_noise_gate_tlv),
+	SOC_SINGLE_TLV("DRC Post Volume", SSM2518_REG_DRC_8,
+			2, 15, 1, ssm2518_post_drc_tlv),
+
+	SOC_ENUM("DRC Peak Detector Attack Time",
+		ssm2518_drc_peak_detector_attack_time_enum),
+	SOC_ENUM("DRC Peak Detector Release Time",
+		ssm2518_drc_peak_detector_release_time_enum),
+	SOC_ENUM("DRC Attack Time", ssm2518_drc_attack_time_enum),
+	SOC_ENUM("DRC Decay Time", ssm2518_drc_decay_time_enum),
+	SOC_ENUM("DRC Hold Time", ssm2518_drc_hold_time_enum),
+	SOC_ENUM("DRC Noise Gate Hold Time",
+		ssm2518_drc_noise_gate_hold_time_enum),
+	SOC_ENUM("DRC RMS Averaging Time", ssm2518_drc_rms_averaging_time_enum),
+};
+
+static const struct snd_soc_dapm_widget ssm2518_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DACL", "HiFi Playback", SSM2518_REG_POWER2, 1, 1),
+	SND_SOC_DAPM_DAC("DACR", "HiFi Playback", SSM2518_REG_POWER2, 2, 1),
+
+	SND_SOC_DAPM_OUTPUT("OUTL"),
+	SND_SOC_DAPM_OUTPUT("OUTR"),
+};
+
+static const struct snd_soc_dapm_route ssm2518_routes[] = {
+	{ "OUTL", NULL, "DACL" },
+	{ "OUTR", NULL, "DACR" },
+};
+
+struct ssm2518_mcs_lut {
+	unsigned int rate;
+	const unsigned int *sysclks;
+};
+
+static const unsigned int ssm2518_sysclks_2048000[] = {
+	2048000, 4096000, 8192000, 12288000, 16384000, 24576000,
+	3200000, 6400000, 12800000, 0
+};
+
+static const unsigned int ssm2518_sysclks_2822000[] = {
+	2822000, 5644800, 11289600, 16934400, 22579200, 33868800,
+	4410000, 8820000, 17640000, 0
+};
+
+static const unsigned int ssm2518_sysclks_3072000[] = {
+	3072000, 6144000, 12288000, 16384000, 24576000, 38864000,
+	4800000, 9600000, 19200000, 0
+};
+
+static const struct ssm2518_mcs_lut ssm2518_mcs_lut[] = {
+	{ 8000,  ssm2518_sysclks_2048000, },
+	{ 11025, ssm2518_sysclks_2822000, },
+	{ 12000, ssm2518_sysclks_3072000, },
+	{ 16000, ssm2518_sysclks_2048000, },
+	{ 24000, ssm2518_sysclks_3072000, },
+	{ 22050, ssm2518_sysclks_2822000, },
+	{ 32000, ssm2518_sysclks_2048000, },
+	{ 44100, ssm2518_sysclks_2822000, },
+	{ 48000, ssm2518_sysclks_3072000, },
+	{ 96000, ssm2518_sysclks_3072000, },
+};
+
+static const unsigned int ssm2518_rates_2048000[] = {
+	8000, 16000, 32000,
+};
+
+static const struct snd_pcm_hw_constraint_list ssm2518_constraints_2048000 = {
+	.list = ssm2518_rates_2048000,
+	.count = ARRAY_SIZE(ssm2518_rates_2048000),
+};
+
+static const unsigned int ssm2518_rates_2822000[] = {
+	11025, 22050, 44100,
+};
+
+static const struct snd_pcm_hw_constraint_list ssm2518_constraints_2822000 = {
+	.list = ssm2518_rates_2822000,
+	.count = ARRAY_SIZE(ssm2518_rates_2822000),
+};
+
+static const unsigned int ssm2518_rates_3072000[] = {
+	12000, 24000, 48000, 96000,
+};
+
+static const struct snd_pcm_hw_constraint_list ssm2518_constraints_3072000 = {
+	.list = ssm2518_rates_3072000,
+	.count = ARRAY_SIZE(ssm2518_rates_3072000),
+};
+
+static const unsigned int ssm2518_rates_12288000[] = {
+	8000, 12000, 16000, 24000, 32000, 48000, 96000,
+};
+
+static const struct snd_pcm_hw_constraint_list ssm2518_constraints_12288000 = {
+	.list = ssm2518_rates_12288000,
+	.count = ARRAY_SIZE(ssm2518_rates_12288000),
+};
+
+static int ssm2518_lookup_mcs(struct ssm2518 *ssm2518,
+	unsigned int rate)
+{
+	const unsigned int *sysclks = NULL;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ssm2518_mcs_lut); i++) {
+		if (ssm2518_mcs_lut[i].rate == rate) {
+			sysclks = ssm2518_mcs_lut[i].sysclks;
+			break;
+		}
+	}
+
+	if (!sysclks)
+		return -EINVAL;
+
+	for (i = 0; sysclks[i]; i++) {
+		if (sysclks[i] == ssm2518->sysclk)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static int ssm2518_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(component);
+	unsigned int rate = params_rate(params);
+	unsigned int ctrl1, ctrl1_mask;
+	int mcs;
+	int ret;
+
+	mcs = ssm2518_lookup_mcs(ssm2518, rate);
+	if (mcs < 0)
+		return mcs;
+
+	ctrl1_mask = SSM2518_SAI_CTRL1_FS_MASK;
+
+	if (rate >= 8000 && rate <= 12000)
+		ctrl1 = SSM2518_SAI_CTRL1_FS_8000_12000;
+	else if (rate >= 16000 && rate <= 24000)
+		ctrl1 = SSM2518_SAI_CTRL1_FS_16000_24000;
+	else if (rate >= 32000 && rate <= 48000)
+		ctrl1 = SSM2518_SAI_CTRL1_FS_32000_48000;
+	else if (rate >= 64000 && rate <= 96000)
+		ctrl1 = SSM2518_SAI_CTRL1_FS_64000_96000;
+	else
+		return -EINVAL;
+
+	if (ssm2518->right_j) {
+		switch (params_width(params)) {
+		case 16:
+			ctrl1 |= SSM2518_SAI_CTRL1_FMT_RJ_16BIT;
+			break;
+		case 24:
+			ctrl1 |= SSM2518_SAI_CTRL1_FMT_RJ_24BIT;
+			break;
+		default:
+			return -EINVAL;
+		}
+		ctrl1_mask |= SSM2518_SAI_CTRL1_FMT_MASK;
+	}
+
+	/* Disable auto samplerate detection */
+	ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_CLOCK,
+				SSM2518_CLOCK_ASR, SSM2518_CLOCK_ASR);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_SAI_CTRL1,
+				ctrl1_mask, ctrl1);
+	if (ret < 0)
+		return ret;
+
+	return regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER1,
+				SSM2518_POWER1_MCS_MASK, mcs << 1);
+}
+
+static int ssm2518_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(dai->component);
+	unsigned int val;
+
+	if (mute)
+		val = SSM2518_MUTE_CTRL_MUTE_MASTER;
+	else
+		val = 0;
+
+	return regmap_update_bits(ssm2518->regmap, SSM2518_REG_MUTE_CTRL,
+			SSM2518_MUTE_CTRL_MUTE_MASTER, val);
+}
+
+static int ssm2518_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(dai->component);
+	unsigned int ctrl1 = 0, ctrl2 = 0;
+	bool invert_fclk;
+	int ret;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		invert_fclk = false;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		ctrl2 |= SSM2518_SAI_CTRL2_BCLK_INVERT;
+		invert_fclk = false;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		invert_fclk = true;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		ctrl2 |= SSM2518_SAI_CTRL2_BCLK_INVERT;
+		invert_fclk = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ssm2518->right_j = false;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		ctrl1 |= SSM2518_SAI_CTRL1_FMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ctrl1 |= SSM2518_SAI_CTRL1_FMT_LJ;
+		invert_fclk = !invert_fclk;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		ctrl1 |= SSM2518_SAI_CTRL1_FMT_RJ_24BIT;
+		ssm2518->right_j = true;
+		invert_fclk = !invert_fclk;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		ctrl2 |= SSM2518_SAI_CTRL2_LRCLK_PULSE;
+		ctrl1 |= SSM2518_SAI_CTRL1_FMT_I2S;
+		invert_fclk = false;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		ctrl2 |= SSM2518_SAI_CTRL2_LRCLK_PULSE;
+		ctrl1 |= SSM2518_SAI_CTRL1_FMT_LJ;
+		invert_fclk = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (invert_fclk)
+		ctrl2 |= SSM2518_SAI_CTRL2_LRCLK_INVERT;
+
+	ret = regmap_write(ssm2518->regmap, SSM2518_REG_SAI_CTRL1, ctrl1);
+	if (ret)
+		return ret;
+
+	return regmap_write(ssm2518->regmap, SSM2518_REG_SAI_CTRL2, ctrl2);
+}
+
+static int ssm2518_set_power(struct ssm2518 *ssm2518, bool enable)
+{
+	int ret = 0;
+
+	if (!enable) {
+		ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER1,
+			SSM2518_POWER1_SPWDN, SSM2518_POWER1_SPWDN);
+		regcache_mark_dirty(ssm2518->regmap);
+	}
+
+	if (gpio_is_valid(ssm2518->enable_gpio))
+		gpio_set_value(ssm2518->enable_gpio, enable);
+
+	regcache_cache_only(ssm2518->regmap, !enable);
+
+	if (enable) {
+		ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER1,
+			SSM2518_POWER1_SPWDN | SSM2518_POWER1_RESET, 0x00);
+		regcache_sync(ssm2518->regmap);
+	}
+
+	return ret;
+}
+
+static int ssm2518_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			ret = ssm2518_set_power(ssm2518, true);
+		break;
+	case SND_SOC_BIAS_OFF:
+		ret = ssm2518_set_power(ssm2518, false);
+		break;
+	}
+
+	return ret;
+}
+
+static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+	unsigned int rx_mask, int slots, int width)
+{
+	struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(dai->component);
+	unsigned int ctrl1, ctrl2;
+	int left_slot, right_slot;
+	int ret;
+
+	if (slots == 0)
+		return regmap_update_bits(ssm2518->regmap,
+			SSM2518_REG_SAI_CTRL1, SSM2518_SAI_CTRL1_SAI_MASK,
+			SSM2518_SAI_CTRL1_SAI_I2S);
+
+	if (tx_mask == 0 || rx_mask != 0)
+		return -EINVAL;
+
+	if (slots == 1) {
+		if (tx_mask != 1)
+			return -EINVAL;
+		left_slot = 0;
+		right_slot = 0;
+	} else {
+		/* We assume the left channel < right channel */
+		left_slot = __ffs(tx_mask);
+		tx_mask &= ~(1 << left_slot);
+		if (tx_mask == 0) {
+			right_slot = left_slot;
+		} else {
+			right_slot = __ffs(tx_mask);
+			tx_mask &= ~(1 << right_slot);
+		}
+	}
+
+	if (tx_mask != 0 || left_slot >= slots || right_slot >= slots)
+		return -EINVAL;
+
+	switch (width) {
+	case 16:
+		ctrl2 = SSM2518_SAI_CTRL2_SLOT_WIDTH_16;
+		break;
+	case 24:
+		ctrl2 = SSM2518_SAI_CTRL2_SLOT_WIDTH_24;
+		break;
+	case 32:
+		ctrl2 = SSM2518_SAI_CTRL2_SLOT_WIDTH_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (slots) {
+	case 1:
+		ctrl1 = SSM2518_SAI_CTRL1_SAI_MONO;
+		break;
+	case 2:
+		ctrl1 = SSM2518_SAI_CTRL1_SAI_TDM_2;
+		break;
+	case 4:
+		ctrl1 = SSM2518_SAI_CTRL1_SAI_TDM_4;
+		break;
+	case 8:
+		ctrl1 = SSM2518_SAI_CTRL1_SAI_TDM_8;
+		break;
+	case 16:
+		ctrl1 = SSM2518_SAI_CTRL1_SAI_TDM_16;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_write(ssm2518->regmap, SSM2518_REG_CHAN_MAP,
+		(left_slot << SSM2518_CHAN_MAP_LEFT_SLOT_OFFSET) |
+		(right_slot << SSM2518_CHAN_MAP_RIGHT_SLOT_OFFSET));
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_SAI_CTRL1,
+		SSM2518_SAI_CTRL1_SAI_MASK, ctrl1);
+	if (ret)
+		return ret;
+
+	return regmap_update_bits(ssm2518->regmap, SSM2518_REG_SAI_CTRL2,
+		SSM2518_SAI_CTRL2_SLOT_WIDTH_MASK, ctrl2);
+}
+
+static int ssm2518_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(dai->component);
+
+	if (ssm2518->constraints)
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE, ssm2518->constraints);
+
+	return 0;
+}
+
+#define SSM2518_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32)
+
+static const struct snd_soc_dai_ops ssm2518_dai_ops = {
+	.startup = ssm2518_startup,
+	.hw_params	= ssm2518_hw_params,
+	.digital_mute	= ssm2518_mute,
+	.set_fmt	= ssm2518_set_dai_fmt,
+	.set_tdm_slot	= ssm2518_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver ssm2518_dai = {
+	.name = "ssm2518-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = SSM2518_FORMATS,
+	},
+	.ops = &ssm2518_dai_ops,
+};
+
+static int ssm2518_set_sysclk(struct snd_soc_component *component, int clk_id,
+	int source, unsigned int freq, int dir)
+{
+	struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	if (clk_id != SSM2518_SYSCLK)
+		return -EINVAL;
+
+	switch (source) {
+	case SSM2518_SYSCLK_SRC_MCLK:
+		val = 0;
+		break;
+	case SSM2518_SYSCLK_SRC_BCLK:
+		/* In this case the bitclock is used as the system clock, and
+		 * the bitclock signal needs to be connected to the MCLK pin and
+		 * the BCLK pin is left unconnected */
+		val = SSM2518_POWER1_NO_BCLK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (freq) {
+	case 0:
+		ssm2518->constraints = NULL;
+		break;
+	case 2048000:
+	case 4096000:
+	case 8192000:
+	case 3200000:
+	case 6400000:
+	case 12800000:
+		ssm2518->constraints = &ssm2518_constraints_2048000;
+		break;
+	case 2822000:
+	case 5644800:
+	case 11289600:
+	case 16934400:
+	case 22579200:
+	case 33868800:
+	case 4410000:
+	case 8820000:
+	case 17640000:
+		ssm2518->constraints = &ssm2518_constraints_2822000;
+		break;
+	case 3072000:
+	case 6144000:
+	case 38864000:
+	case 4800000:
+	case 9600000:
+	case 19200000:
+		ssm2518->constraints = &ssm2518_constraints_3072000;
+		break;
+	case 12288000:
+	case 16384000:
+	case 24576000:
+		ssm2518->constraints = &ssm2518_constraints_12288000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ssm2518->sysclk = freq;
+
+	return regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER1,
+			SSM2518_POWER1_NO_BCLK, val);
+}
+
+static const struct snd_soc_component_driver ssm2518_component_driver = {
+	.set_bias_level		= ssm2518_set_bias_level,
+	.set_sysclk		= ssm2518_set_sysclk,
+	.controls		= ssm2518_snd_controls,
+	.num_controls		= ARRAY_SIZE(ssm2518_snd_controls),
+	.dapm_widgets		= ssm2518_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ssm2518_dapm_widgets),
+	.dapm_routes		= ssm2518_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ssm2518_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config ssm2518_regmap_config = {
+	.val_bits = 8,
+	.reg_bits = 8,
+
+	.max_register = SSM2518_REG_DRC_9,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = ssm2518_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ssm2518_reg_defaults),
+};
+
+static int ssm2518_i2c_probe(struct i2c_client *i2c,
+	const struct i2c_device_id *id)
+{
+	struct ssm2518_platform_data *pdata = i2c->dev.platform_data;
+	struct ssm2518 *ssm2518;
+	int ret;
+
+	ssm2518 = devm_kzalloc(&i2c->dev, sizeof(*ssm2518), GFP_KERNEL);
+	if (ssm2518 == NULL)
+		return -ENOMEM;
+
+	if (pdata) {
+		ssm2518->enable_gpio = pdata->enable_gpio;
+	} else if (i2c->dev.of_node) {
+		ssm2518->enable_gpio = of_get_gpio(i2c->dev.of_node, 0);
+		if (ssm2518->enable_gpio < 0 && ssm2518->enable_gpio != -ENOENT)
+			return ssm2518->enable_gpio;
+	} else {
+		ssm2518->enable_gpio = -1;
+	}
+
+	if (gpio_is_valid(ssm2518->enable_gpio)) {
+		ret = devm_gpio_request_one(&i2c->dev, ssm2518->enable_gpio,
+				GPIOF_OUT_INIT_HIGH, "SSM2518 nSD");
+		if (ret)
+			return ret;
+	}
+
+	i2c_set_clientdata(i2c, ssm2518);
+
+	ssm2518->regmap = devm_regmap_init_i2c(i2c, &ssm2518_regmap_config);
+	if (IS_ERR(ssm2518->regmap))
+		return PTR_ERR(ssm2518->regmap);
+
+	/*
+	 * The reset bit is obviously volatile, but we need to be able to cache
+	 * the other bits in the register, so we can't just mark the whole
+	 * register as volatile. Since this is the only place where we'll ever
+	 * touch the reset bit just bypass the cache for this operation.
+	 */
+	regcache_cache_bypass(ssm2518->regmap, true);
+	ret = regmap_write(ssm2518->regmap, SSM2518_REG_POWER1,
+			SSM2518_POWER1_RESET);
+	regcache_cache_bypass(ssm2518->regmap, false);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER2,
+				SSM2518_POWER2_APWDN, 0x00);
+	if (ret)
+		return ret;
+
+	ret = ssm2518_set_power(ssm2518, false);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_component(&i2c->dev,
+			&ssm2518_component_driver,
+			&ssm2518_dai, 1);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id ssm2518_dt_ids[] = {
+	{ .compatible = "adi,ssm2518", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ssm2518_dt_ids);
+#endif
+
+static const struct i2c_device_id ssm2518_i2c_ids[] = {
+	{ "ssm2518", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ssm2518_i2c_ids);
+
+static struct i2c_driver ssm2518_driver = {
+	.driver = {
+		.name = "ssm2518",
+		.of_match_table = of_match_ptr(ssm2518_dt_ids),
+	},
+	.probe = ssm2518_i2c_probe,
+	.id_table = ssm2518_i2c_ids,
+};
+module_i2c_driver(ssm2518_driver);
+
+MODULE_DESCRIPTION("ASoC SSM2518 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2518.h b/sound/soc/codecs/ssm2518.h
new file mode 100644
index 0000000..62511d8
--- /dev/null
+++ b/sound/soc/codecs/ssm2518.h
@@ -0,0 +1,20 @@
+/*
+ * SSM2518 amplifier audio driver
+ *
+ * Copyright 2013 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __SND_SOC_CODECS_SSM2518_H__
+#define __SND_SOC_CODECS_SSM2518_H__
+
+#define SSM2518_SYSCLK 0
+
+enum ssm2518_sysclk_src {
+	SSM2518_SYSCLK_SRC_MCLK = 0,
+	SSM2518_SYSCLK_SRC_BCLK = 1,
+};
+
+#endif
diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c
new file mode 100644
index 0000000..f1c2b1a
--- /dev/null
+++ b/sound/soc/codecs/ssm2602-i2c.c
@@ -0,0 +1,58 @@
+/*
+ * SSM2602/SSM2603/SSM2604 I2C audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "ssm2602.h"
+
+/*
+ * ssm2602 2 wire address is determined by GPIO5
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+static int ssm2602_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	return ssm2602_probe(&client->dev, id->driver_data,
+		devm_regmap_init_i2c(client, &ssm2602_regmap_config));
+}
+
+static const struct i2c_device_id ssm2602_i2c_id[] = {
+	{ "ssm2602", SSM2602 },
+	{ "ssm2603", SSM2602 },
+	{ "ssm2604", SSM2604 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
+
+static const struct of_device_id ssm2602_of_match[] = {
+	{ .compatible = "adi,ssm2602", },
+	{ .compatible = "adi,ssm2603", },
+	{ .compatible = "adi,ssm2604", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ssm2602_of_match);
+
+static struct i2c_driver ssm2602_i2c_driver = {
+	.driver = {
+		.name = "ssm2602",
+		.of_match_table = ssm2602_of_match,
+	},
+	.probe = ssm2602_i2c_probe,
+	.id_table = ssm2602_i2c_id,
+};
+module_i2c_driver(ssm2602_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 I2C driver");
+MODULE_AUTHOR("Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2602-spi.c b/sound/soc/codecs/ssm2602-spi.c
new file mode 100644
index 0000000..8848628
--- /dev/null
+++ b/sound/soc/codecs/ssm2602-spi.c
@@ -0,0 +1,40 @@
+/*
+ * SSM2602 SPI audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "ssm2602.h"
+
+static int ssm2602_spi_probe(struct spi_device *spi)
+{
+	return ssm2602_probe(&spi->dev, SSM2602,
+		devm_regmap_init_spi(spi, &ssm2602_regmap_config));
+}
+
+static const struct of_device_id ssm2602_of_match[] = {
+	{ .compatible = "adi,ssm2602", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ssm2602_of_match);
+
+static struct spi_driver ssm2602_spi_driver = {
+	.driver = {
+		.name	= "ssm2602",
+		.of_match_table = ssm2602_of_match,
+	},
+	.probe		= ssm2602_spi_probe,
+};
+module_spi_driver(ssm2602_spi_driver);
+
+MODULE_DESCRIPTION("ASoC SSM2602 SPI driver");
+MODULE_AUTHOR("Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
new file mode 100644
index 0000000..501a4e7
--- /dev/null
+++ b/sound/soc/codecs/ssm2602.c
@@ -0,0 +1,659 @@
+/*
+ * File:         sound/soc/codecs/ssm2602.c
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ * Description:  Driver for ssm2602 sound chip
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "ssm2602.h"
+
+/* codec private data */
+struct ssm2602_priv {
+	unsigned int sysclk;
+	const struct snd_pcm_hw_constraint_list *sysclk_constraints;
+
+	struct regmap *regmap;
+
+	enum ssm2602_type type;
+	unsigned int clk_out_pwr;
+};
+
+/*
+ * ssm2602 register cache
+ * We can't read the ssm2602 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ * There is no point in caching the reset register
+ */
+static const struct reg_default ssm2602_reg[SSM2602_CACHEREGNUM] = {
+	{ .reg = 0x00, .def = 0x0097 },
+	{ .reg = 0x01, .def = 0x0097 },
+	{ .reg = 0x02, .def = 0x0079 },
+	{ .reg = 0x03, .def = 0x0079 },
+	{ .reg = 0x04, .def = 0x000a },
+	{ .reg = 0x05, .def = 0x0008 },
+	{ .reg = 0x06, .def = 0x009f },
+	{ .reg = 0x07, .def = 0x000a },
+	{ .reg = 0x08, .def = 0x0000 },
+	{ .reg = 0x09, .def = 0x0000 }
+};
+
+
+/*Appending several "None"s just for OSS mixer use*/
+static const char *ssm2602_input_select[] = {
+	"Line", "Mic",
+};
+
+static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum ssm2602_enum[] = {
+	SOC_ENUM_SINGLE(SSM2602_APANA, 2, ARRAY_SIZE(ssm2602_input_select),
+			ssm2602_input_select),
+	SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, ARRAY_SIZE(ssm2602_deemph),
+			ssm2602_deemph),
+};
+
+static const DECLARE_TLV_DB_RANGE(ssm260x_outmix_tlv,
+	0, 47, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+	48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0)
+);
+
+static const DECLARE_TLV_DB_SCALE(ssm260x_inpga_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(ssm260x_sidetone_tlv, -1500, 300, 0);
+
+static const struct snd_kcontrol_new ssm260x_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 45, 0,
+	ssm260x_inpga_tlv),
+SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
+
+SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1),
+SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0),
+
+SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
+};
+
+static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
+	0, 127, 0, ssm260x_outmix_tlv),
+SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
+	7, 1, 0),
+SOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1,
+	ssm260x_sidetone_tlv),
+
+SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
+SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0),
+SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
+};
+
+/* Output Mixer */
+static const struct snd_kcontrol_new ssm260x_output_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
+SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0),
+SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
+};
+
+/* Input mux */
+static const struct snd_kcontrol_new ssm2602_input_mux_controls =
+SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]);
+
+static const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
+SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("Digital Core Power", SSM2602_ACTIVE, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
+	ssm260x_output_mixer_controls,
+	ARRAY_SIZE(ssm260x_output_mixer_controls)),
+
+SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls),
+SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1),
+
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
+SND_SOC_DAPM_INPUT("MICIN"),
+};
+
+static const struct snd_soc_dapm_widget ssm2604_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
+	ssm260x_output_mixer_controls,
+	ARRAY_SIZE(ssm260x_output_mixer_controls) - 1), /* Last element is the mic */
+};
+
+static const struct snd_soc_dapm_route ssm260x_routes[] = {
+	{"DAC", NULL, "Digital Core Power"},
+	{"ADC", NULL, "Digital Core Power"},
+
+	{"Output Mixer", "Line Bypass Switch", "Line Input"},
+	{"Output Mixer", "HiFi Playback Switch", "DAC"},
+
+	{"ROUT", NULL, "Output Mixer"},
+	{"LOUT", NULL, "Output Mixer"},
+
+	{"Line Input", NULL, "LLINEIN"},
+	{"Line Input", NULL, "RLINEIN"},
+};
+
+static const struct snd_soc_dapm_route ssm2602_routes[] = {
+	{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
+
+	{"RHPOUT", NULL, "Output Mixer"},
+	{"LHPOUT", NULL, "Output Mixer"},
+
+	{"Input Mux", "Line", "Line Input"},
+	{"Input Mux", "Mic", "Mic Bias"},
+	{"ADC", NULL, "Input Mux"},
+
+	{"Mic Bias", NULL, "MICIN"},
+};
+
+static const struct snd_soc_dapm_route ssm2604_routes[] = {
+	{"ADC", NULL, "Line Input"},
+};
+
+static const unsigned int ssm2602_rates_12288000[] = {
+	8000, 16000, 32000, 48000, 96000,
+};
+
+static const struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = {
+	.list = ssm2602_rates_12288000,
+	.count = ARRAY_SIZE(ssm2602_rates_12288000),
+};
+
+static const unsigned int ssm2602_rates_11289600[] = {
+	8000, 11025, 22050, 44100, 88200,
+};
+
+static const struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = {
+	.list = ssm2602_rates_11289600,
+	.count = ARRAY_SIZE(ssm2602_rates_11289600),
+};
+
+struct ssm2602_coeff {
+	u32 mclk;
+	u32 rate;
+	u8 srate;
+};
+
+#define SSM2602_COEFF_SRATE(sr, bosr, usb) (((sr) << 2) | ((bosr) << 1) | (usb))
+
+/* codec mclk clock coefficients */
+static const struct ssm2602_coeff ssm2602_coeff_table[] = {
+	/* 48k */
+	{12288000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x0)},
+	{18432000, 48000, SSM2602_COEFF_SRATE(0x0, 0x1, 0x0)},
+	{12000000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x1)},
+
+	/* 32k */
+	{12288000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x0)},
+	{18432000, 32000, SSM2602_COEFF_SRATE(0x6, 0x1, 0x0)},
+	{12000000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x1)},
+
+	/* 16k */
+	{12288000, 16000, SSM2602_COEFF_SRATE(0x5, 0x0, 0x0)},
+	{18432000, 16000, SSM2602_COEFF_SRATE(0x5, 0x1, 0x0)},
+	{12000000, 16000, SSM2602_COEFF_SRATE(0xa, 0x0, 0x1)},
+
+	/* 8k */
+	{12288000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x0)},
+	{18432000, 8000, SSM2602_COEFF_SRATE(0x3, 0x1, 0x0)},
+	{11289600, 8000, SSM2602_COEFF_SRATE(0xb, 0x0, 0x0)},
+	{16934400, 8000, SSM2602_COEFF_SRATE(0xb, 0x1, 0x0)},
+	{12000000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x1)},
+
+	/* 96k */
+	{12288000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x0)},
+	{18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)},
+	{12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)},
+
+	/* 11.025k */
+	{11289600, 11025, SSM2602_COEFF_SRATE(0xc, 0x0, 0x0)},
+	{16934400, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x0)},
+	{12000000, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x1)},
+
+	/* 22.05k */
+	{11289600, 22050, SSM2602_COEFF_SRATE(0xd, 0x0, 0x0)},
+	{16934400, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x0)},
+	{12000000, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x1)},
+
+	/* 44.1k */
+	{11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)},
+	{16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)},
+	{12000000, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x1)},
+
+	/* 88.2k */
+	{11289600, 88200, SSM2602_COEFF_SRATE(0xf, 0x0, 0x0)},
+	{16934400, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x0)},
+	{12000000, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x1)},
+};
+
+static inline int ssm2602_get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ssm2602_coeff_table); i++) {
+		if (ssm2602_coeff_table[i].rate == rate &&
+			ssm2602_coeff_table[i].mclk == mclk)
+			return ssm2602_coeff_table[i].srate;
+	}
+	return -EINVAL;
+}
+
+static int ssm2602_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
+	int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
+	unsigned int iface;
+
+	if (srate < 0)
+		return srate;
+
+	regmap_write(ssm2602->regmap, SSM2602_SRATE, srate);
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		iface = 0x0;
+		break;
+	case 20:
+		iface = 0x4;
+		break;
+	case 24:
+		iface = 0x8;
+		break;
+	case 32:
+		iface = 0xc;
+		break;
+	default:
+		return -EINVAL;
+	}
+	regmap_update_bits(ssm2602->regmap, SSM2602_IFACE,
+		IFACE_AUDIO_DATA_LEN, iface);
+	return 0;
+}
+
+static int ssm2602_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
+
+	if (ssm2602->sysclk_constraints) {
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+				   SNDRV_PCM_HW_PARAM_RATE,
+				   ssm2602->sysclk_constraints);
+	}
+
+	return 0;
+}
+
+static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(dai->component);
+
+	if (mute)
+		regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,
+				    APDIGI_ENABLE_DAC_MUTE,
+				    APDIGI_ENABLE_DAC_MUTE);
+	else
+		regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,
+				    APDIGI_ENABLE_DAC_MUTE, 0);
+	return 0;
+}
+
+static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
+
+	if (dir == SND_SOC_CLOCK_IN) {
+		if (clk_id != SSM2602_SYSCLK)
+			return -EINVAL;
+
+		switch (freq) {
+		case 12288000:
+		case 18432000:
+			ssm2602->sysclk_constraints = &ssm2602_constraints_12288000;
+			break;
+		case 11289600:
+		case 16934400:
+			ssm2602->sysclk_constraints = &ssm2602_constraints_11289600;
+			break;
+		case 12000000:
+			ssm2602->sysclk_constraints = NULL;
+			break;
+		default:
+			return -EINVAL;
+		}
+		ssm2602->sysclk = freq;
+	} else {
+		unsigned int mask;
+
+		switch (clk_id) {
+		case SSM2602_CLK_CLKOUT:
+			mask = PWR_CLK_OUT_PDN;
+			break;
+		case SSM2602_CLK_XTO:
+			mask = PWR_OSC_PDN;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		if (freq == 0)
+			ssm2602->clk_out_pwr |= mask;
+		else
+			ssm2602->clk_out_pwr &= ~mask;
+
+		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
+			PWR_CLK_OUT_PDN | PWR_OSC_PDN, ssm2602->clk_out_pwr);
+	}
+
+	return 0;
+}
+
+static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(codec_dai->component);
+	unsigned int iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface |= 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0013;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0003;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface */
+	regmap_write(ssm2602->regmap, SSM2602_IFACE, iface);
+	return 0;
+}
+
+static int ssm2602_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* vref/mid on, osc and clkout on if enabled */
+		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
+			PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
+			ssm2602->clk_out_pwr);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* everything off except vref/vmid, */
+		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
+			PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
+			PWR_CLK_OUT_PDN | PWR_OSC_PDN);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* everything off */
+		regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
+			PWR_POWER_OFF, PWR_POWER_OFF);
+		break;
+
+	}
+	return 0;
+}
+
+#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
+		SNDRV_PCM_RATE_96000)
+
+#define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops ssm2602_dai_ops = {
+	.startup	= ssm2602_startup,
+	.hw_params	= ssm2602_hw_params,
+	.digital_mute	= ssm2602_mute,
+	.set_sysclk	= ssm2602_set_dai_sysclk,
+	.set_fmt	= ssm2602_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver ssm2602_dai = {
+	.name = "ssm2602-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SSM2602_RATES,
+		.formats = SSM2602_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SSM2602_RATES,
+		.formats = SSM2602_FORMATS,},
+	.ops = &ssm2602_dai_ops,
+	.symmetric_rates = 1,
+	.symmetric_samplebits = 1,
+};
+
+static int ssm2602_resume(struct snd_soc_component *component)
+{
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
+
+	regcache_sync(ssm2602->regmap);
+
+	return 0;
+}
+
+static int ssm2602_component_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V,
+			    LOUT1V_LRHP_BOTH, LOUT1V_LRHP_BOTH);
+	regmap_update_bits(ssm2602->regmap, SSM2602_ROUT1V,
+			    ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH);
+
+	ret = snd_soc_add_component_controls(component, ssm2602_snd_controls,
+			ARRAY_SIZE(ssm2602_snd_controls));
+	if (ret)
+		return ret;
+
+	ret = snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets,
+			ARRAY_SIZE(ssm2602_dapm_widgets));
+	if (ret)
+		return ret;
+
+	return snd_soc_dapm_add_routes(dapm, ssm2602_routes,
+			ARRAY_SIZE(ssm2602_routes));
+}
+
+static int ssm2604_component_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int ret;
+
+	ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,
+			ARRAY_SIZE(ssm2604_dapm_widgets));
+	if (ret)
+		return ret;
+
+	return snd_soc_dapm_add_routes(dapm, ssm2604_routes,
+			ARRAY_SIZE(ssm2604_routes));
+}
+
+static int ssm260x_component_probe(struct snd_soc_component *component)
+{
+	struct ssm2602_priv *ssm2602 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = regmap_write(ssm2602->regmap, SSM2602_RESET, 0);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
+		return ret;
+	}
+
+	/* set the update bits */
+	regmap_update_bits(ssm2602->regmap, SSM2602_LINVOL,
+			    LINVOL_LRIN_BOTH, LINVOL_LRIN_BOTH);
+	regmap_update_bits(ssm2602->regmap, SSM2602_RINVOL,
+			    RINVOL_RLIN_BOTH, RINVOL_RLIN_BOTH);
+	/*select Line in as default input*/
+	regmap_write(ssm2602->regmap, SSM2602_APANA, APANA_SELECT_DAC |
+			APANA_ENABLE_MIC_BOOST);
+
+	switch (ssm2602->type) {
+	case SSM2602:
+		ret = ssm2602_component_probe(component);
+		break;
+	case SSM2604:
+		ret = ssm2604_component_probe(component);
+		break;
+	}
+
+	return ret;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_ssm2602 = {
+	.probe			= ssm260x_component_probe,
+	.resume			= ssm2602_resume,
+	.set_bias_level		= ssm2602_set_bias_level,
+	.controls		= ssm260x_snd_controls,
+	.num_controls		= ARRAY_SIZE(ssm260x_snd_controls),
+	.dapm_widgets		= ssm260x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ssm260x_dapm_widgets),
+	.dapm_routes		= ssm260x_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ssm260x_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static bool ssm2602_register_volatile(struct device *dev, unsigned int reg)
+{
+	return reg == SSM2602_RESET;
+}
+
+const struct regmap_config ssm2602_regmap_config = {
+	.val_bits = 9,
+	.reg_bits = 7,
+
+	.max_register = SSM2602_RESET,
+	.volatile_reg = ssm2602_register_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = ssm2602_reg,
+	.num_reg_defaults = ARRAY_SIZE(ssm2602_reg),
+};
+EXPORT_SYMBOL_GPL(ssm2602_regmap_config);
+
+int ssm2602_probe(struct device *dev, enum ssm2602_type type,
+	struct regmap *regmap)
+{
+	struct ssm2602_priv *ssm2602;
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	ssm2602 = devm_kzalloc(dev, sizeof(*ssm2602), GFP_KERNEL);
+	if (ssm2602 == NULL)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, ssm2602);
+	ssm2602->type = type;
+	ssm2602->regmap = regmap;
+
+	return devm_snd_soc_register_component(dev, &soc_component_dev_ssm2602,
+		&ssm2602_dai, 1);
+}
+EXPORT_SYMBOL_GPL(ssm2602_probe);
+
+MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver");
+MODULE_AUTHOR("Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h
new file mode 100644
index 0000000..7475388
--- /dev/null
+++ b/sound/soc/codecs/ssm2602.h
@@ -0,0 +1,139 @@
+/*
+ * File:         sound/soc/codecs/ssm2602.h
+ * Author:       Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created:      Tue June 06 2008
+ *
+ * Modified:
+ *               Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _SSM2602_H
+#define _SSM2602_H
+
+#include <linux/regmap.h>
+
+struct device;
+
+enum ssm2602_type {
+	SSM2602,
+	SSM2604,
+};
+
+extern const struct regmap_config ssm2602_regmap_config;
+
+int ssm2602_probe(struct device *dev, enum ssm2602_type type,
+	struct regmap *regmap);
+
+/* SSM2602 Codec Register definitions */
+
+#define SSM2602_LINVOL   0x00
+#define SSM2602_RINVOL   0x01
+#define SSM2602_LOUT1V   0x02
+#define SSM2602_ROUT1V   0x03
+#define SSM2602_APANA    0x04
+#define SSM2602_APDIGI   0x05
+#define SSM2602_PWR      0x06
+#define SSM2602_IFACE    0x07
+#define SSM2602_SRATE    0x08
+#define SSM2602_ACTIVE   0x09
+#define SSM2602_RESET	 0x0f
+
+/*SSM2602 Codec Register Field definitions
+ *(Mask value to extract the corresponding Register field)
+ */
+
+/*Left ADC Volume Control (SSM2602_REG_LEFT_ADC_VOL)*/
+#define     LINVOL_LIN_VOL                0x01F   /* Left Channel PGA Volume control                      */
+#define     LINVOL_LIN_ENABLE_MUTE        0x080   /* Left Channel Input Mute                              */
+#define     LINVOL_LRIN_BOTH              0x100   /* Left Channel Line Input Volume update                */
+
+/*Right ADC Volume Control (SSM2602_REG_RIGHT_ADC_VOL)*/
+#define     RINVOL_RIN_VOL                0x01F   /* Right Channel PGA Volume control                     */
+#define     RINVOL_RIN_ENABLE_MUTE        0x080   /* Right Channel Input Mute                             */
+#define     RINVOL_RLIN_BOTH              0x100   /* Right Channel Line Input Volume update               */
+
+/*Left DAC Volume Control (SSM2602_REG_LEFT_DAC_VOL)*/
+#define     LOUT1V_LHP_VOL                0x07F   /* Left Channel Headphone volume control                */
+#define     LOUT1V_ENABLE_LZC             0x080   /* Left Channel Zero cross detect enable                */
+#define     LOUT1V_LRHP_BOTH              0x100   /* Left Channel Headphone volume update                 */
+
+/*Right DAC Volume Control (SSM2602_REG_RIGHT_DAC_VOL)*/
+#define     ROUT1V_RHP_VOL                0x07F   /* Right Channel Headphone volume control               */
+#define     ROUT1V_ENABLE_RZC             0x080   /* Right Channel Zero cross detect enable               */
+#define     ROUT1V_RLHP_BOTH              0x100   /* Right Channel Headphone volume update                */
+
+/*Analogue Audio Path Control (SSM2602_REG_ANALOGUE_PATH)*/
+#define     APANA_ENABLE_MIC_BOOST       0x001   /* Primary Microphone Amplifier gain booster control    */
+#define     APANA_ENABLE_MIC_MUTE        0x002   /* Microphone Mute Control                              */
+#define     APANA_ADC_IN_SELECT          0x004   /* Microphone/Line IN select to ADC (1=MIC, 0=Line In)  */
+#define     APANA_ENABLE_BYPASS          0x008   /* Line input bypass to line output                     */
+#define     APANA_SELECT_DAC             0x010   /* Select DAC (1=Select DAC, 0=Don't Select DAC)        */
+#define     APANA_ENABLE_SIDETONE        0x020   /* Enable/Disable Side Tone                             */
+#define     APANA_SIDETONE_ATTN          0x0C0   /* Side Tone Attenuation                                */
+#define     APANA_ENABLE_MIC_BOOST2      0x100   /* Secondary Microphone Amplifier gain booster control  */
+
+/*Digital Audio Path Control (SSM2602_REG_DIGITAL_PATH)*/
+#define     APDIGI_ENABLE_ADC_HPF         0x001   /* Enable/Disable ADC Highpass Filter                   */
+#define     APDIGI_DE_EMPHASIS            0x006   /* De-Emphasis Control                                  */
+#define     APDIGI_ENABLE_DAC_MUTE        0x008   /* DAC Mute Control                                     */
+#define     APDIGI_STORE_OFFSET           0x010   /* Store/Clear DC offset when HPF is disabled           */
+
+/*Power Down Control (SSM2602_REG_POWER)
+ *(1=Enable PowerDown, 0=Disable PowerDown)
+ */
+#define     PWR_LINE_IN_PDN            0x001   /* Line Input Power Down                                */
+#define     PWR_MIC_PDN                0x002   /* Microphone Input & Bias Power Down                   */
+#define     PWR_ADC_PDN                0x004   /* ADC Power Down                                       */
+#define     PWR_DAC_PDN                0x008   /* DAC Power Down                                       */
+#define     PWR_OUT_PDN                0x010   /* Outputs Power Down                                   */
+#define     PWR_OSC_PDN                0x020   /* Oscillator Power Down                                */
+#define     PWR_CLK_OUT_PDN            0x040   /* CLKOUT Power Down                                    */
+#define     PWR_POWER_OFF              0x080   /* POWEROFF Mode                                        */
+
+/*Digital Audio Interface Format (SSM2602_REG_DIGITAL_IFACE)*/
+#define     IFACE_IFACE_FORMAT           0x003   /* Digital Audio input format control                   */
+#define     IFACE_AUDIO_DATA_LEN         0x00C   /* Audio Data word length control                       */
+#define     IFACE_DAC_LR_POLARITY        0x010   /* Polarity Control for clocks in RJ,LJ and I2S modes   */
+#define     IFACE_DAC_LR_SWAP            0x020   /* Swap DAC data control                                */
+#define     IFACE_ENABLE_MASTER          0x040   /* Enable/Disable Master Mode                           */
+#define     IFACE_BCLK_INVERT            0x080   /* Bit Clock Inversion control                          */
+
+/*Sampling Control (SSM2602_REG_SAMPLING_CTRL)*/
+#define     SRATE_ENABLE_USB_MODE        0x001   /* Enable/Disable USB Mode                              */
+#define     SRATE_BOS_RATE               0x002   /* Base Over-Sampling rate                              */
+#define     SRATE_SAMPLE_RATE            0x03C   /* Clock setting condition (Sampling rate control)      */
+#define     SRATE_CORECLK_DIV2           0x040   /* Core Clock divider select                            */
+#define     SRATE_CLKOUT_DIV2            0x080   /* Clock Out divider select                             */
+
+/*Active Control (SSM2602_REG_ACTIVE_CTRL)*/
+#define     ACTIVE_ACTIVATE_CODEC         0x001   /* Activate Codec Digital Audio Interface               */
+
+/*********************************************************************/
+
+#define SSM2602_CACHEREGNUM 	10
+
+enum ssm2602_clk {
+	SSM2602_SYSCLK,
+	SSM2602_CLK_CLKOUT,
+	SSM2602_CLK_XTO
+};
+
+#endif
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
new file mode 100644
index 0000000..90119ea
--- /dev/null
+++ b/sound/soc/codecs/ssm4567.c
@@ -0,0 +1,512 @@
+/*
+ * SSM4567 amplifier audio driver
+ *
+ * Copyright 2014 Google Chromium project.
+ *  Author: Anatol Pomozov <anatol@chromium.org>
+ *
+ * Based on code copyright/by:
+ *   Copyright 2013 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#define SSM4567_REG_POWER_CTRL		0x00
+#define SSM4567_REG_AMP_SNS_CTRL		0x01
+#define SSM4567_REG_DAC_CTRL		0x02
+#define SSM4567_REG_DAC_VOLUME		0x03
+#define SSM4567_REG_SAI_CTRL_1		0x04
+#define SSM4567_REG_SAI_CTRL_2		0x05
+#define SSM4567_REG_SAI_PLACEMENT_1		0x06
+#define SSM4567_REG_SAI_PLACEMENT_2		0x07
+#define SSM4567_REG_SAI_PLACEMENT_3		0x08
+#define SSM4567_REG_SAI_PLACEMENT_4		0x09
+#define SSM4567_REG_SAI_PLACEMENT_5		0x0a
+#define SSM4567_REG_SAI_PLACEMENT_6		0x0b
+#define SSM4567_REG_BATTERY_V_OUT		0x0c
+#define SSM4567_REG_LIMITER_CTRL_1		0x0d
+#define SSM4567_REG_LIMITER_CTRL_2		0x0e
+#define SSM4567_REG_LIMITER_CTRL_3		0x0f
+#define SSM4567_REG_STATUS_1		0x10
+#define SSM4567_REG_STATUS_2		0x11
+#define SSM4567_REG_FAULT_CTRL		0x12
+#define SSM4567_REG_PDM_CTRL		0x13
+#define SSM4567_REG_MCLK_RATIO		0x14
+#define SSM4567_REG_BOOST_CTRL_1		0x15
+#define SSM4567_REG_BOOST_CTRL_2		0x16
+#define SSM4567_REG_SOFT_RESET		0xff
+
+/* POWER_CTRL */
+#define SSM4567_POWER_APWDN_EN		BIT(7)
+#define SSM4567_POWER_BSNS_PWDN		BIT(6)
+#define SSM4567_POWER_VSNS_PWDN		BIT(5)
+#define SSM4567_POWER_ISNS_PWDN		BIT(4)
+#define SSM4567_POWER_BOOST_PWDN		BIT(3)
+#define SSM4567_POWER_AMP_PWDN		BIT(2)
+#define SSM4567_POWER_VBAT_ONLY		BIT(1)
+#define SSM4567_POWER_SPWDN			BIT(0)
+
+/* DAC_CTRL */
+#define SSM4567_DAC_HV			BIT(7)
+#define SSM4567_DAC_MUTE		BIT(6)
+#define SSM4567_DAC_HPF			BIT(5)
+#define SSM4567_DAC_LPM			BIT(4)
+#define SSM4567_DAC_FS_MASK	0x7
+#define SSM4567_DAC_FS_8000_12000	0x0
+#define SSM4567_DAC_FS_16000_24000	0x1
+#define SSM4567_DAC_FS_32000_48000	0x2
+#define SSM4567_DAC_FS_64000_96000	0x3
+#define SSM4567_DAC_FS_128000_192000	0x4
+
+/* SAI_CTRL_1 */
+#define SSM4567_SAI_CTRL_1_BCLK			BIT(6)
+#define SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK	(0x3 << 4)
+#define SSM4567_SAI_CTRL_1_TDM_BLCKS_32		(0x0 << 4)
+#define SSM4567_SAI_CTRL_1_TDM_BLCKS_48		(0x1 << 4)
+#define SSM4567_SAI_CTRL_1_TDM_BLCKS_64		(0x2 << 4)
+#define SSM4567_SAI_CTRL_1_FSYNC		BIT(3)
+#define SSM4567_SAI_CTRL_1_LJ			BIT(2)
+#define SSM4567_SAI_CTRL_1_TDM			BIT(1)
+#define SSM4567_SAI_CTRL_1_PDM			BIT(0)
+
+/* SAI_CTRL_2 */
+#define SSM4567_SAI_CTRL_2_AUTO_SLOT		BIT(3)
+#define SSM4567_SAI_CTRL_2_TDM_SLOT_MASK	0x7
+#define SSM4567_SAI_CTRL_2_TDM_SLOT(x)		(x)
+
+struct ssm4567 {
+	struct regmap *regmap;
+};
+
+static const struct reg_default ssm4567_reg_defaults[] = {
+	{ SSM4567_REG_POWER_CTRL,	0x81 },
+	{ SSM4567_REG_AMP_SNS_CTRL, 0x09 },
+	{ SSM4567_REG_DAC_CTRL, 0x32 },
+	{ SSM4567_REG_DAC_VOLUME, 0x40 },
+	{ SSM4567_REG_SAI_CTRL_1, 0x00 },
+	{ SSM4567_REG_SAI_CTRL_2, 0x08 },
+	{ SSM4567_REG_SAI_PLACEMENT_1, 0x01 },
+	{ SSM4567_REG_SAI_PLACEMENT_2, 0x20 },
+	{ SSM4567_REG_SAI_PLACEMENT_3, 0x32 },
+	{ SSM4567_REG_SAI_PLACEMENT_4, 0x07 },
+	{ SSM4567_REG_SAI_PLACEMENT_5, 0x07 },
+	{ SSM4567_REG_SAI_PLACEMENT_6, 0x07 },
+	{ SSM4567_REG_BATTERY_V_OUT, 0x00 },
+	{ SSM4567_REG_LIMITER_CTRL_1, 0xa4 },
+	{ SSM4567_REG_LIMITER_CTRL_2, 0x73 },
+	{ SSM4567_REG_LIMITER_CTRL_3, 0x00 },
+	{ SSM4567_REG_STATUS_1, 0x00 },
+	{ SSM4567_REG_STATUS_2, 0x00 },
+	{ SSM4567_REG_FAULT_CTRL, 0x30 },
+	{ SSM4567_REG_PDM_CTRL, 0x40 },
+	{ SSM4567_REG_MCLK_RATIO, 0x11 },
+	{ SSM4567_REG_BOOST_CTRL_1, 0x03 },
+	{ SSM4567_REG_BOOST_CTRL_2, 0x00 },
+	{ SSM4567_REG_SOFT_RESET, 0x00 },
+};
+
+
+static bool ssm4567_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case SSM4567_REG_POWER_CTRL ... SSM4567_REG_BOOST_CTRL_2:
+		return true;
+	default:
+		return false;
+	}
+
+}
+
+static bool ssm4567_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case SSM4567_REG_POWER_CTRL ... SSM4567_REG_SAI_PLACEMENT_6:
+	case SSM4567_REG_LIMITER_CTRL_1 ... SSM4567_REG_LIMITER_CTRL_3:
+	case SSM4567_REG_FAULT_CTRL ... SSM4567_REG_BOOST_CTRL_2:
+	/* The datasheet states that soft reset register is read-only,
+	 * but logically it is write-only. */
+	case SSM4567_REG_SOFT_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool ssm4567_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case SSM4567_REG_BATTERY_V_OUT:
+	case SSM4567_REG_STATUS_1 ... SSM4567_REG_STATUS_2:
+	case SSM4567_REG_SOFT_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(ssm4567_vol_tlv, -7125, 2400);
+
+static const struct snd_kcontrol_new ssm4567_snd_controls[] = {
+	SOC_SINGLE_TLV("Master Playback Volume", SSM4567_REG_DAC_VOLUME, 0,
+		0xff, 1, ssm4567_vol_tlv),
+	SOC_SINGLE("DAC Low Power Mode Switch", SSM4567_REG_DAC_CTRL, 4, 1, 0),
+	SOC_SINGLE("DAC High Pass Filter Switch", SSM4567_REG_DAC_CTRL,
+		5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ssm4567_amplifier_boost_control =
+	SOC_DAPM_SINGLE("Switch", SSM4567_REG_POWER_CTRL, 1, 1, 1);
+
+static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM4567_REG_POWER_CTRL, 2, 1),
+	SND_SOC_DAPM_SWITCH("Amplifier Boost", SSM4567_REG_POWER_CTRL, 3, 1,
+		&ssm4567_amplifier_boost_control),
+
+	SND_SOC_DAPM_SIGGEN("Sense"),
+
+	SND_SOC_DAPM_PGA("Current Sense", SSM4567_REG_POWER_CTRL, 4, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Voltage Sense", SSM4567_REG_POWER_CTRL, 5, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("VBAT Sense", SSM4567_REG_POWER_CTRL, 6, 1, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("OUT"),
+};
+
+static const struct snd_soc_dapm_route ssm4567_routes[] = {
+	{ "OUT", NULL, "Amplifier Boost" },
+	{ "Amplifier Boost", "Switch", "DAC" },
+	{ "OUT", NULL, "DAC" },
+
+	{ "Current Sense", NULL, "Sense" },
+	{ "Voltage Sense", NULL, "Sense" },
+	{ "VBAT Sense", NULL, "Sense" },
+	{ "Capture Sense", NULL, "Current Sense" },
+	{ "Capture Sense", NULL, "Voltage Sense" },
+	{ "Capture Sense", NULL, "VBAT Sense" },
+};
+
+static int ssm4567_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct ssm4567 *ssm4567 = snd_soc_component_get_drvdata(component);
+	unsigned int rate = params_rate(params);
+	unsigned int dacfs;
+
+	if (rate >= 8000 && rate <= 12000)
+		dacfs = SSM4567_DAC_FS_8000_12000;
+	else if (rate >= 16000 && rate <= 24000)
+		dacfs = SSM4567_DAC_FS_16000_24000;
+	else if (rate >= 32000 && rate <= 48000)
+		dacfs = SSM4567_DAC_FS_32000_48000;
+	else if (rate >= 64000 && rate <= 96000)
+		dacfs = SSM4567_DAC_FS_64000_96000;
+	else if (rate >= 128000 && rate <= 192000)
+		dacfs = SSM4567_DAC_FS_128000_192000;
+	else
+		return -EINVAL;
+
+	return regmap_update_bits(ssm4567->regmap, SSM4567_REG_DAC_CTRL,
+				SSM4567_DAC_FS_MASK, dacfs);
+}
+
+static int ssm4567_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct ssm4567 *ssm4567 = snd_soc_component_get_drvdata(dai->component);
+	unsigned int val;
+
+	val = mute ? SSM4567_DAC_MUTE : 0;
+	return regmap_update_bits(ssm4567->regmap, SSM4567_REG_DAC_CTRL,
+			SSM4567_DAC_MUTE, val);
+}
+
+static int ssm4567_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+	unsigned int rx_mask, int slots, int width)
+{
+	struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai);
+	unsigned int blcks;
+	int slot;
+	int ret;
+
+	if (tx_mask == 0)
+		return -EINVAL;
+
+	if (rx_mask && rx_mask != tx_mask)
+		return -EINVAL;
+
+	slot = __ffs(tx_mask);
+	if (tx_mask != BIT(slot))
+		return -EINVAL;
+
+	switch (width) {
+	case 32:
+		blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_32;
+		break;
+	case 48:
+		blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_48;
+		break;
+	case 64:
+		blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_64;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_2,
+		SSM4567_SAI_CTRL_2_AUTO_SLOT | SSM4567_SAI_CTRL_2_TDM_SLOT_MASK,
+		SSM4567_SAI_CTRL_2_TDM_SLOT(slot));
+	if (ret)
+		return ret;
+
+	return regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1,
+		SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK, blcks);
+}
+
+static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai);
+	unsigned int ctrl1 = 0;
+	bool invert_fclk;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		invert_fclk = false;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		ctrl1 |= SSM4567_SAI_CTRL_1_BCLK;
+		invert_fclk = false;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC;
+		invert_fclk = true;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		ctrl1 |= SSM4567_SAI_CTRL_1_BCLK;
+		invert_fclk = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ctrl1 |= SSM4567_SAI_CTRL_1_LJ;
+		invert_fclk = !invert_fclk;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		ctrl1 |= SSM4567_SAI_CTRL_1_TDM;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		ctrl1 |= SSM4567_SAI_CTRL_1_TDM | SSM4567_SAI_CTRL_1_LJ;
+		break;
+	case SND_SOC_DAIFMT_PDM:
+		ctrl1 |= SSM4567_SAI_CTRL_1_PDM;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (invert_fclk)
+		ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC;
+
+	return regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1,
+			SSM4567_SAI_CTRL_1_BCLK |
+			SSM4567_SAI_CTRL_1_FSYNC |
+			SSM4567_SAI_CTRL_1_LJ |
+			SSM4567_SAI_CTRL_1_TDM |
+			SSM4567_SAI_CTRL_1_PDM,
+			ctrl1);
+}
+
+static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable)
+{
+	int ret = 0;
+
+	if (!enable) {
+		ret = regmap_update_bits(ssm4567->regmap,
+			SSM4567_REG_POWER_CTRL,
+			SSM4567_POWER_SPWDN, SSM4567_POWER_SPWDN);
+		regcache_mark_dirty(ssm4567->regmap);
+	}
+
+	regcache_cache_only(ssm4567->regmap, !enable);
+
+	if (enable) {
+		ret = regmap_write(ssm4567->regmap, SSM4567_REG_SOFT_RESET,
+			0x00);
+		if (ret)
+			return ret;
+
+		ret = regmap_update_bits(ssm4567->regmap,
+			SSM4567_REG_POWER_CTRL,
+			SSM4567_POWER_SPWDN, 0x00);
+		regcache_sync(ssm4567->regmap);
+	}
+
+	return ret;
+}
+
+static int ssm4567_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	struct ssm4567 *ssm4567 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			ret = ssm4567_set_power(ssm4567, true);
+		break;
+	case SND_SOC_BIAS_OFF:
+		ret = ssm4567_set_power(ssm4567, false);
+		break;
+	}
+
+	return ret;
+}
+
+static const struct snd_soc_dai_ops ssm4567_dai_ops = {
+	.hw_params	= ssm4567_hw_params,
+	.digital_mute	= ssm4567_mute,
+	.set_fmt	= ssm4567_set_dai_fmt,
+	.set_tdm_slot	= ssm4567_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver ssm4567_dai = {
+	.name = "ssm4567-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+			SNDRV_PCM_FMTBIT_S32,
+	},
+	.capture = {
+		.stream_name = "Capture Sense",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+			SNDRV_PCM_FMTBIT_S32,
+	},
+	.ops = &ssm4567_dai_ops,
+};
+
+static const struct snd_soc_component_driver ssm4567_component_driver = {
+	.set_bias_level		= ssm4567_set_bias_level,
+	.controls		= ssm4567_snd_controls,
+	.num_controls		= ARRAY_SIZE(ssm4567_snd_controls),
+	.dapm_widgets		= ssm4567_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ssm4567_dapm_widgets),
+	.dapm_routes		= ssm4567_routes,
+	.num_dapm_routes	= ARRAY_SIZE(ssm4567_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config ssm4567_regmap_config = {
+	.val_bits = 8,
+	.reg_bits = 8,
+
+	.max_register = SSM4567_REG_SOFT_RESET,
+	.readable_reg = ssm4567_readable_reg,
+	.writeable_reg = ssm4567_writeable_reg,
+	.volatile_reg = ssm4567_volatile_reg,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = ssm4567_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ssm4567_reg_defaults),
+};
+
+static int ssm4567_i2c_probe(struct i2c_client *i2c,
+	const struct i2c_device_id *id)
+{
+	struct ssm4567 *ssm4567;
+	int ret;
+
+	ssm4567 = devm_kzalloc(&i2c->dev, sizeof(*ssm4567), GFP_KERNEL);
+	if (ssm4567 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, ssm4567);
+
+	ssm4567->regmap = devm_regmap_init_i2c(i2c, &ssm4567_regmap_config);
+	if (IS_ERR(ssm4567->regmap))
+		return PTR_ERR(ssm4567->regmap);
+
+	ret = regmap_write(ssm4567->regmap, SSM4567_REG_SOFT_RESET, 0x00);
+	if (ret)
+		return ret;
+
+	ret = ssm4567_set_power(ssm4567, false);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_component(&i2c->dev, &ssm4567_component_driver,
+			&ssm4567_dai, 1);
+}
+
+static const struct i2c_device_id ssm4567_i2c_ids[] = {
+	{ "ssm4567", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ssm4567_i2c_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id ssm4567_of_match[] = {
+	{ .compatible = "adi,ssm4567", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ssm4567_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+
+static const struct acpi_device_id ssm4567_acpi_match[] = {
+	{ "INT343B", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, ssm4567_acpi_match);
+
+#endif
+
+static struct i2c_driver ssm4567_driver = {
+	.driver = {
+		.name = "ssm4567",
+		.of_match_table = of_match_ptr(ssm4567_of_match),
+		.acpi_match_table = ACPI_PTR(ssm4567_acpi_match),
+	},
+	.probe = ssm4567_i2c_probe,
+	.id_table = ssm4567_i2c_ids,
+};
+module_i2c_driver(ssm4567_driver);
+
+MODULE_DESCRIPTION("ASoC SSM4567 driver");
+MODULE_AUTHOR("Anatol Pomozov <anatol@chromium.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
new file mode 100644
index 0000000..ce508b4
--- /dev/null
+++ b/sound/soc/codecs/sta32x.c
@@ -0,0 +1,1156 @@
+/*
+ * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system
+ *
+ * Copyright: 2011 Raumfeld GmbH
+ * Author: Johannes Stezenbach <js@sig21.net>
+ *
+ * based on code from:
+ *	Wolfson Microelectronics PLC.
+ *	  Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *	Freescale Semiconductor, Inc.
+ *	  Timur Tabi <timur@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <sound/sta32x.h>
+#include "sta32x.h"
+
+#define STA32X_RATES (SNDRV_PCM_RATE_32000 | \
+		      SNDRV_PCM_RATE_44100 | \
+		      SNDRV_PCM_RATE_48000 | \
+		      SNDRV_PCM_RATE_88200 | \
+		      SNDRV_PCM_RATE_96000 | \
+		      SNDRV_PCM_RATE_176400 | \
+		      SNDRV_PCM_RATE_192000)
+
+#define STA32X_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
+	 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+	 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+	 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
+	 SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE  | \
+	 SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_S32_BE)
+
+/* Power-up register defaults */
+static const struct reg_default sta32x_regs[] = {
+	{  0x0, 0x63 },
+	{  0x1, 0x80 },
+	{  0x2, 0xc2 },
+	{  0x3, 0x40 },
+	{  0x4, 0xc2 },
+	{  0x5, 0x5c },
+	{  0x6, 0x10 },
+	{  0x7, 0xff },
+	{  0x8, 0x60 },
+	{  0x9, 0x60 },
+	{  0xa, 0x60 },
+	{  0xb, 0x80 },
+	{  0xc, 0x00 },
+	{  0xd, 0x00 },
+	{  0xe, 0x00 },
+	{  0xf, 0x40 },
+	{ 0x10, 0x80 },
+	{ 0x11, 0x77 },
+	{ 0x12, 0x6a },
+	{ 0x13, 0x69 },
+	{ 0x14, 0x6a },
+	{ 0x15, 0x69 },
+	{ 0x16, 0x00 },
+	{ 0x17, 0x00 },
+	{ 0x18, 0x00 },
+	{ 0x19, 0x00 },
+	{ 0x1a, 0x00 },
+	{ 0x1b, 0x00 },
+	{ 0x1c, 0x00 },
+	{ 0x1d, 0x00 },
+	{ 0x1e, 0x00 },
+	{ 0x1f, 0x00 },
+	{ 0x20, 0x00 },
+	{ 0x21, 0x00 },
+	{ 0x22, 0x00 },
+	{ 0x23, 0x00 },
+	{ 0x24, 0x00 },
+	{ 0x25, 0x00 },
+	{ 0x26, 0x00 },
+	{ 0x27, 0x2d },
+	{ 0x28, 0xc0 },
+	{ 0x2b, 0x00 },
+	{ 0x2c, 0x0c },
+};
+
+static const struct regmap_range sta32x_write_regs_range[] = {
+	regmap_reg_range(STA32X_CONFA,  STA32X_FDRC2),
+};
+
+static const struct regmap_range sta32x_read_regs_range[] = {
+	regmap_reg_range(STA32X_CONFA,  STA32X_FDRC2),
+};
+
+static const struct regmap_range sta32x_volatile_regs_range[] = {
+	regmap_reg_range(STA32X_CFADDR2, STA32X_CFUD),
+};
+
+static const struct regmap_access_table sta32x_write_regs = {
+	.yes_ranges =	sta32x_write_regs_range,
+	.n_yes_ranges =	ARRAY_SIZE(sta32x_write_regs_range),
+};
+
+static const struct regmap_access_table sta32x_read_regs = {
+	.yes_ranges =	sta32x_read_regs_range,
+	.n_yes_ranges =	ARRAY_SIZE(sta32x_read_regs_range),
+};
+
+static const struct regmap_access_table sta32x_volatile_regs = {
+	.yes_ranges =	sta32x_volatile_regs_range,
+	.n_yes_ranges =	ARRAY_SIZE(sta32x_volatile_regs_range),
+};
+
+/* regulator power supply names */
+static const char *sta32x_supply_names[] = {
+	"Vdda",	/* analog supply, 3.3VV */
+	"Vdd3",	/* digital supply, 3.3V */
+	"Vcc"	/* power amp spply, 10V - 36V */
+};
+
+/* codec private data */
+struct sta32x_priv {
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)];
+	struct snd_soc_component *component;
+	struct sta32x_platform_data *pdata;
+
+	unsigned int mclk;
+	unsigned int format;
+
+	u32 coef_shadow[STA32X_COEF_COUNT];
+	struct delayed_work watchdog_work;
+	int shutdown;
+	struct gpio_desc *gpiod_nreset;
+	struct mutex coeff_lock;
+};
+
+static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1);
+static const DECLARE_TLV_DB_SCALE(tone_tlv, -120, 200, 0);
+
+static const char *sta32x_drc_ac[] = {
+	"Anti-Clipping", "Dynamic Range Compression" };
+static const char *sta32x_auto_eq_mode[] = {
+	"User", "Preset", "Loudness" };
+static const char *sta32x_auto_gc_mode[] = {
+	"User", "AC no clipping", "AC limited clipping (10%)",
+	"DRC nighttime listening mode" };
+static const char *sta32x_auto_xo_mode[] = {
+	"User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz", "200Hz",
+	"220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz", "340Hz", "360Hz" };
+static const char *sta32x_preset_eq_mode[] = {
+	"Flat", "Rock", "Soft Rock", "Jazz", "Classical", "Dance", "Pop", "Soft",
+	"Hard", "Party", "Vocal", "Hip-Hop", "Dialog", "Bass-boost #1",
+	"Bass-boost #2", "Bass-boost #3", "Loudness 1", "Loudness 2",
+	"Loudness 3", "Loudness 4", "Loudness 5", "Loudness 6", "Loudness 7",
+	"Loudness 8", "Loudness 9", "Loudness 10", "Loudness 11", "Loudness 12",
+	"Loudness 13", "Loudness 14", "Loudness 15", "Loudness 16" };
+static const char *sta32x_limiter_select[] = {
+	"Limiter Disabled", "Limiter #1", "Limiter #2" };
+static const char *sta32x_limiter_attack_rate[] = {
+	"3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024",
+	"0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752",
+	"0.0645", "0.0564", "0.0501", "0.0451" };
+static const char *sta32x_limiter_release_rate[] = {
+	"0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299",
+	"0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137",
+	"0.0134", "0.0117", "0.0110", "0.0104" };
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_attack_tlv,
+	0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
+	8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),
+);
+
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_release_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0),
+	3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0),
+	8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0),
+);
+
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_attack_tlv,
+	0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0),
+	8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0),
+	14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0),
+);
+
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_release_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+	1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0),
+	3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0),
+	5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0),
+	13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
+);
+
+static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum,
+			    STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
+			    sta32x_drc_ac);
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_eq_enum,
+			    STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT,
+			    sta32x_auto_eq_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_gc_enum,
+			    STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT,
+			    sta32x_auto_gc_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_xo_enum,
+			    STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT,
+			    sta32x_auto_xo_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_preset_eq_enum,
+			    STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT,
+			    sta32x_preset_eq_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch1_enum,
+			    STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT,
+			    sta32x_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch2_enum,
+			    STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT,
+			    sta32x_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch3_enum,
+			    STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT,
+			    sta32x_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_attack_rate_enum,
+			    STA32X_L1AR, STA32X_LxA_SHIFT,
+			    sta32x_limiter_attack_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_attack_rate_enum,
+			    STA32X_L2AR, STA32X_LxA_SHIFT,
+			    sta32x_limiter_attack_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_release_rate_enum,
+			    STA32X_L1AR, STA32X_LxR_SHIFT,
+			    sta32x_limiter_release_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_release_rate_enum,
+			    STA32X_L2AR, STA32X_LxR_SHIFT,
+			    sta32x_limiter_release_rate);
+
+/* byte array controls for setting biquad, mixer, scaling coefficients;
+ * for biquads all five coefficients need to be set in one go,
+ * mixer and pre/postscale coefs can be set individually;
+ * each coef is 24bit, the bytes are ordered in the same way
+ * as given in the STA32x data sheet (big endian; b1, b2, a1, a2, b0)
+ */
+
+static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_info *uinfo)
+{
+	int numcoef = kcontrol->private_value >> 16;
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = 3 * numcoef;
+	return 0;
+}
+
+static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
+	int numcoef = kcontrol->private_value >> 16;
+	int index = kcontrol->private_value & 0xffff;
+	unsigned int cfud, val;
+	int i, ret = 0;
+
+	mutex_lock(&sta32x->coeff_lock);
+
+	/* preserve reserved bits in STA32X_CFUD */
+	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
+	cfud &= 0xf0;
+	/*
+	 * chip documentation does not say if the bits are self clearing,
+	 * so do it explicitly
+	 */
+	regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
+
+	regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
+	if (numcoef == 1) {
+		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04);
+	} else if (numcoef == 5) {
+		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08);
+	} else {
+		ret = -EINVAL;
+		goto exit_unlock;
+	}
+
+	for (i = 0; i < 3 * numcoef; i++) {
+		regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val);
+		ucontrol->value.bytes.data[i] = val;
+	}
+
+exit_unlock:
+	mutex_unlock(&sta32x->coeff_lock);
+
+	return ret;
+}
+
+static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
+	int numcoef = kcontrol->private_value >> 16;
+	int index = kcontrol->private_value & 0xffff;
+	unsigned int cfud;
+	int i;
+
+	/* preserve reserved bits in STA32X_CFUD */
+	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
+	cfud &= 0xf0;
+	/*
+	 * chip documentation does not say if the bits are self clearing,
+	 * so do it explicitly
+	 */
+	regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
+
+	regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
+	for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++)
+		sta32x->coef_shadow[index + i] =
+			  (ucontrol->value.bytes.data[3 * i] << 16)
+			| (ucontrol->value.bytes.data[3 * i + 1] << 8)
+			| (ucontrol->value.bytes.data[3 * i + 2]);
+	for (i = 0; i < 3 * numcoef; i++)
+		regmap_write(sta32x->regmap, STA32X_B1CF1 + i,
+			     ucontrol->value.bytes.data[i]);
+	if (numcoef == 1)
+		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
+	else if (numcoef == 5)
+		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x02);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int sta32x_sync_coef_shadow(struct snd_soc_component *component)
+{
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
+	unsigned int cfud;
+	int i;
+
+	/* preserve reserved bits in STA32X_CFUD */
+	regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
+	cfud &= 0xf0;
+
+	for (i = 0; i < STA32X_COEF_COUNT; i++) {
+		regmap_write(sta32x->regmap, STA32X_CFADDR2, i);
+		regmap_write(sta32x->regmap, STA32X_B1CF1,
+			     (sta32x->coef_shadow[i] >> 16) & 0xff);
+		regmap_write(sta32x->regmap, STA32X_B1CF2,
+			     (sta32x->coef_shadow[i] >> 8) & 0xff);
+		regmap_write(sta32x->regmap, STA32X_B1CF3,
+			     (sta32x->coef_shadow[i]) & 0xff);
+		/*
+		 * chip documentation does not say if the bits are
+		 * self-clearing, so do it explicitly
+		 */
+		regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
+		regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
+	}
+	return 0;
+}
+
+static int sta32x_cache_sync(struct snd_soc_component *component)
+{
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
+	unsigned int mute;
+	int rc;
+
+	/* mute during register sync */
+	regmap_read(sta32x->regmap, STA32X_MMUTE, &mute);
+	regmap_write(sta32x->regmap, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
+	sta32x_sync_coef_shadow(component);
+	rc = regcache_sync(sta32x->regmap);
+	regmap_write(sta32x->regmap, STA32X_MMUTE, mute);
+	return rc;
+}
+
+/* work around ESD issue where sta32x resets and loses all configuration */
+static void sta32x_watchdog(struct work_struct *work)
+{
+	struct sta32x_priv *sta32x = container_of(work, struct sta32x_priv,
+						  watchdog_work.work);
+	struct snd_soc_component *component = sta32x->component;
+	unsigned int confa, confa_cached;
+
+	/* check if sta32x has reset itself */
+	confa_cached = snd_soc_component_read32(component, STA32X_CONFA);
+	regcache_cache_bypass(sta32x->regmap, true);
+	confa = snd_soc_component_read32(component, STA32X_CONFA);
+	regcache_cache_bypass(sta32x->regmap, false);
+	if (confa != confa_cached) {
+		regcache_mark_dirty(sta32x->regmap);
+		sta32x_cache_sync(component);
+	}
+
+	if (!sta32x->shutdown)
+		queue_delayed_work(system_power_efficient_wq,
+				   &sta32x->watchdog_work,
+				   round_jiffies_relative(HZ));
+}
+
+static void sta32x_watchdog_start(struct sta32x_priv *sta32x)
+{
+	if (sta32x->pdata->needs_esd_watchdog) {
+		sta32x->shutdown = 0;
+		queue_delayed_work(system_power_efficient_wq,
+				   &sta32x->watchdog_work,
+				   round_jiffies_relative(HZ));
+	}
+}
+
+static void sta32x_watchdog_stop(struct sta32x_priv *sta32x)
+{
+	if (sta32x->pdata->needs_esd_watchdog) {
+		sta32x->shutdown = 1;
+		cancel_delayed_work_sync(&sta32x->watchdog_work);
+	}
+}
+
+#define SINGLE_COEF(xname, index) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = sta32x_coefficient_info, \
+	.get = sta32x_coefficient_get,\
+	.put = sta32x_coefficient_put, \
+	.private_value = index | (1 << 16) }
+
+#define BIQUAD_COEFS(xname, index) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = sta32x_coefficient_info, \
+	.get = sta32x_coefficient_get,\
+	.put = sta32x_coefficient_put, \
+	.private_value = index | (5 << 16) }
+
+static const struct snd_kcontrol_new sta32x_snd_controls[] = {
+SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv),
+SOC_SINGLE("Master Switch", STA32X_MMUTE, 0, 1, 1),
+SOC_SINGLE("Ch1 Switch", STA32X_MMUTE, 1, 1, 1),
+SOC_SINGLE("Ch2 Switch", STA32X_MMUTE, 2, 1, 1),
+SOC_SINGLE("Ch3 Switch", STA32X_MMUTE, 3, 1, 1),
+SOC_SINGLE_TLV("Ch1 Volume", STA32X_C1VOL, 0, 0xff, 1, chvol_tlv),
+SOC_SINGLE_TLV("Ch2 Volume", STA32X_C2VOL, 0, 0xff, 1, chvol_tlv),
+SOC_SINGLE_TLV("Ch3 Volume", STA32X_C3VOL, 0, 0xff, 1, chvol_tlv),
+SOC_SINGLE("De-emphasis Filter Switch", STA32X_CONFD, STA32X_CONFD_DEMP_SHIFT, 1, 0),
+SOC_ENUM("Compressor/Limiter Switch", sta32x_drc_ac_enum),
+SOC_SINGLE("Miami Mode Switch", STA32X_CONFD, STA32X_CONFD_MME_SHIFT, 1, 0),
+SOC_SINGLE("Zero Cross Switch", STA32X_CONFE, STA32X_CONFE_ZCE_SHIFT, 1, 0),
+SOC_SINGLE("Soft Ramp Switch", STA32X_CONFE, STA32X_CONFE_SVE_SHIFT, 1, 0),
+SOC_SINGLE("Auto-Mute Switch", STA32X_CONFF, STA32X_CONFF_IDE_SHIFT, 1, 0),
+SOC_ENUM("Automode EQ", sta32x_auto_eq_enum),
+SOC_ENUM("Automode GC", sta32x_auto_gc_enum),
+SOC_ENUM("Automode XO", sta32x_auto_xo_enum),
+SOC_ENUM("Preset EQ", sta32x_preset_eq_enum),
+SOC_SINGLE("Ch1 Tone Control Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 Tone Control Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0),
+SOC_SINGLE("Ch1 EQ Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 EQ Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch1 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch3 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0),
+SOC_ENUM("Ch1 Limiter Select", sta32x_limiter_ch1_enum),
+SOC_ENUM("Ch2 Limiter Select", sta32x_limiter_ch2_enum),
+SOC_ENUM("Ch3 Limiter Select", sta32x_limiter_ch3_enum),
+SOC_SINGLE_TLV("Bass Tone Control", STA32X_TONE, STA32X_TONE_BTC_SHIFT, 15, 0, tone_tlv),
+SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0, tone_tlv),
+SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum),
+SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum),
+SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
+SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter2_release_rate_enum),
+
+/* depending on mode, the attack/release thresholds have
+ * two different enum definitions; provide both
+ */
+SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT,
+	       16, 0, sta32x_limiter_ac_attack_tlv),
+SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT,
+	       16, 0, sta32x_limiter_ac_attack_tlv),
+SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT,
+	       16, 0, sta32x_limiter_ac_release_tlv),
+SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT,
+	       16, 0, sta32x_limiter_ac_release_tlv),
+SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT,
+	       16, 0, sta32x_limiter_drc_attack_tlv),
+SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT,
+	       16, 0, sta32x_limiter_drc_attack_tlv),
+SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT,
+	       16, 0, sta32x_limiter_drc_release_tlv),
+SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT,
+	       16, 0, sta32x_limiter_drc_release_tlv),
+
+BIQUAD_COEFS("Ch1 - Biquad 1", 0),
+BIQUAD_COEFS("Ch1 - Biquad 2", 5),
+BIQUAD_COEFS("Ch1 - Biquad 3", 10),
+BIQUAD_COEFS("Ch1 - Biquad 4", 15),
+BIQUAD_COEFS("Ch2 - Biquad 1", 20),
+BIQUAD_COEFS("Ch2 - Biquad 2", 25),
+BIQUAD_COEFS("Ch2 - Biquad 3", 30),
+BIQUAD_COEFS("Ch2 - Biquad 4", 35),
+BIQUAD_COEFS("High-pass", 40),
+BIQUAD_COEFS("Low-pass", 45),
+SINGLE_COEF("Ch1 - Prescale", 50),
+SINGLE_COEF("Ch2 - Prescale", 51),
+SINGLE_COEF("Ch1 - Postscale", 52),
+SINGLE_COEF("Ch2 - Postscale", 53),
+SINGLE_COEF("Ch3 - Postscale", 54),
+SINGLE_COEF("Thermal warning - Postscale", 55),
+SINGLE_COEF("Ch1 - Mix 1", 56),
+SINGLE_COEF("Ch1 - Mix 2", 57),
+SINGLE_COEF("Ch2 - Mix 1", 58),
+SINGLE_COEF("Ch2 - Mix 2", 59),
+SINGLE_COEF("Ch3 - Mix 1", 60),
+SINGLE_COEF("Ch3 - Mix 2", 61),
+};
+
+static const struct snd_soc_dapm_widget sta32x_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_OUTPUT("LEFT"),
+SND_SOC_DAPM_OUTPUT("RIGHT"),
+SND_SOC_DAPM_OUTPUT("SUB"),
+};
+
+static const struct snd_soc_dapm_route sta32x_dapm_routes[] = {
+	{ "LEFT", NULL, "DAC" },
+	{ "RIGHT", NULL, "DAC" },
+	{ "SUB", NULL, "DAC" },
+};
+
+/* MCLK interpolation ratio per fs */
+static struct {
+	int fs;
+	int ir;
+} interpolation_ratios[] = {
+	{ 32000, 0 },
+	{ 44100, 0 },
+	{ 48000, 0 },
+	{ 88200, 1 },
+	{ 96000, 1 },
+	{ 176400, 2 },
+	{ 192000, 2 },
+};
+
+/* MCLK to fs clock ratios */
+static int mcs_ratio_table[3][7] = {
+	{ 768, 512, 384, 256, 128, 576, 0 },
+	{ 384, 256, 192, 128,  64,   0 },
+	{ 384, 256, 192, 128,  64,   0 },
+};
+
+/**
+ * sta32x_set_dai_sysclk - configure MCLK
+ * @codec_dai: the codec DAI
+ * @clk_id: the clock ID (ignored)
+ * @freq: the MCLK input frequency
+ * @dir: the clock direction (ignored)
+ *
+ * The value of MCLK is used to determine which sample rates are supported
+ * by the STA32X, based on the mclk_ratios table.
+ *
+ * This function must be called by the machine driver's 'startup' function,
+ * otherwise the list of supported sample rates will not be available in
+ * time for ALSA.
+ *
+ * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause
+ * theoretically possible sample rates to be enabled. Call it again with a
+ * proper value set one the external clock is set (most probably you would do
+ * that from a machine's driver 'hw_param' hook.
+ */
+static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "mclk=%u\n", freq);
+	sta32x->mclk = freq;
+
+	return 0;
+}
+
+/**
+ * sta32x_set_dai_fmt - configure the codec for the selected audio format
+ * @codec_dai: the codec DAI
+ * @fmt: a SND_SOC_DAIFMT_x value indicating the data format
+ *
+ * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the
+ * codec accordingly.
+ */
+static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
+	u8 confb = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		sta32x->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		confb |= STA32X_CONFB_C2IM;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		confb |= STA32X_CONFB_C1IM;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(sta32x->regmap, STA32X_CONFB,
+				  STA32X_CONFB_C1IM | STA32X_CONFB_C2IM, confb);
+}
+
+/**
+ * sta32x_hw_params - program the STA32X with the given hardware parameters.
+ * @substream: the audio stream
+ * @params: the hardware parameters to set
+ * @dai: the SOC DAI (ignored)
+ *
+ * This function programs the hardware with the values provided.
+ * Specifically, the sample rate and the data format.
+ */
+static int sta32x_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
+	int i, mcs = -EINVAL, ir = -EINVAL;
+	unsigned int confa, confb;
+	unsigned int rate, ratio;
+	int ret;
+
+	if (!sta32x->mclk) {
+		dev_err(component->dev,
+			"sta32x->mclk is unset. Unable to determine ratio\n");
+		return -EIO;
+	}
+
+	rate = params_rate(params);
+	ratio = sta32x->mclk / rate;
+	dev_dbg(component->dev, "rate: %u, ratio: %u\n", rate, ratio);
+
+	for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
+		if (interpolation_ratios[i].fs == rate) {
+			ir = interpolation_ratios[i].ir;
+			break;
+		}
+	}
+
+	if (ir < 0) {
+		dev_err(component->dev, "Unsupported samplerate: %u\n", rate);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 6; i++) {
+		if (mcs_ratio_table[ir][i] == ratio) {
+			mcs = i;
+			break;
+		}
+	}
+
+	if (mcs < 0) {
+		dev_err(component->dev, "Unresolvable ratio: %u\n", ratio);
+		return -EINVAL;
+	}
+
+	confa = (ir << STA32X_CONFA_IR_SHIFT) |
+		(mcs << STA32X_CONFA_MCS_SHIFT);
+	confb = 0;
+
+	switch (params_width(params)) {
+	case 24:
+		dev_dbg(component->dev, "24bit\n");
+		/* fall through */
+	case 32:
+		dev_dbg(component->dev, "24bit or 32bit\n");
+		switch (sta32x->format) {
+		case SND_SOC_DAIFMT_I2S:
+			confb |= 0x0;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			confb |= 0x1;
+			break;
+		case SND_SOC_DAIFMT_RIGHT_J:
+			confb |= 0x2;
+			break;
+		}
+
+		break;
+	case 20:
+		dev_dbg(component->dev, "20bit\n");
+		switch (sta32x->format) {
+		case SND_SOC_DAIFMT_I2S:
+			confb |= 0x4;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			confb |= 0x5;
+			break;
+		case SND_SOC_DAIFMT_RIGHT_J:
+			confb |= 0x6;
+			break;
+		}
+
+		break;
+	case 18:
+		dev_dbg(component->dev, "18bit\n");
+		switch (sta32x->format) {
+		case SND_SOC_DAIFMT_I2S:
+			confb |= 0x8;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			confb |= 0x9;
+			break;
+		case SND_SOC_DAIFMT_RIGHT_J:
+			confb |= 0xa;
+			break;
+		}
+
+		break;
+	case 16:
+		dev_dbg(component->dev, "16bit\n");
+		switch (sta32x->format) {
+		case SND_SOC_DAIFMT_I2S:
+			confb |= 0x0;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			confb |= 0xd;
+			break;
+		case SND_SOC_DAIFMT_RIGHT_J:
+			confb |= 0xe;
+			break;
+		}
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(sta32x->regmap, STA32X_CONFA,
+				 STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK,
+				 confa);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_update_bits(sta32x->regmap, STA32X_CONFB,
+				 STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB,
+				 confb);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int sta32x_startup_sequence(struct sta32x_priv *sta32x)
+{
+	if (sta32x->gpiod_nreset) {
+		gpiod_set_value(sta32x->gpiod_nreset, 0);
+		mdelay(1);
+		gpiod_set_value(sta32x->gpiod_nreset, 1);
+		mdelay(1);
+	}
+
+	return 0;
+}
+
+/**
+ * sta32x_set_bias_level - DAPM callback
+ * @component: the component device
+ * @level: DAPM power level
+ *
+ * This is called by ALSA to put the component into low power mode
+ * or to wake it up.  If the component is powered off completely
+ * all registers must be restored after power on.
+ */
+static int sta32x_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	int ret;
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "level = %d\n", level);
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* Full power on */
+		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+				    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
+				    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
+						    sta32x->supplies);
+			if (ret != 0) {
+				dev_err(component->dev,
+					"Failed to enable supplies: %d\n", ret);
+				return ret;
+			}
+
+			sta32x_startup_sequence(sta32x);
+			sta32x_cache_sync(component);
+			sta32x_watchdog_start(sta32x);
+		}
+
+		/* Power down */
+		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+				   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
+				   0);
+
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* The chip runs through the power down sequence for us. */
+		regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+				   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, 0);
+		msleep(300);
+		sta32x_watchdog_stop(sta32x);
+
+		gpiod_set_value(sta32x->gpiod_nreset, 0);
+
+		regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
+				       sta32x->supplies);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops sta32x_dai_ops = {
+	.hw_params	= sta32x_hw_params,
+	.set_sysclk	= sta32x_set_dai_sysclk,
+	.set_fmt	= sta32x_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver sta32x_dai = {
+	.name = "sta32x-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = STA32X_RATES,
+		.formats = STA32X_FORMATS,
+	},
+	.ops = &sta32x_dai_ops,
+};
+
+static int sta32x_probe(struct snd_soc_component *component)
+{
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
+	struct sta32x_platform_data *pdata = sta32x->pdata;
+	int i, ret = 0, thermal = 0;
+
+	sta32x->component = component;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
+				    sta32x->supplies);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = sta32x_startup_sequence(sta32x);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to startup device\n");
+		return ret;
+	}
+
+	/* CONFA */
+	if (!pdata->thermal_warning_recovery)
+		thermal |= STA32X_CONFA_TWAB;
+	if (!pdata->thermal_warning_adjustment)
+		thermal |= STA32X_CONFA_TWRB;
+	if (!pdata->fault_detect_recovery)
+		thermal |= STA32X_CONFA_FDRB;
+	regmap_update_bits(sta32x->regmap, STA32X_CONFA,
+			   STA32X_CONFA_TWAB | STA32X_CONFA_TWRB |
+			   STA32X_CONFA_FDRB,
+			   thermal);
+
+	/* CONFC */
+	regmap_update_bits(sta32x->regmap, STA32X_CONFC,
+			   STA32X_CONFC_CSZ_MASK,
+			   pdata->drop_compensation_ns
+				<< STA32X_CONFC_CSZ_SHIFT);
+
+	/* CONFE */
+	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+			   STA32X_CONFE_MPCV,
+			   pdata->max_power_use_mpcc ?
+				STA32X_CONFE_MPCV : 0);
+	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+			   STA32X_CONFE_MPC,
+			   pdata->max_power_correction ?
+				STA32X_CONFE_MPC : 0);
+	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+			   STA32X_CONFE_AME,
+			   pdata->am_reduction_mode ?
+				STA32X_CONFE_AME : 0);
+	regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+			   STA32X_CONFE_PWMS,
+			   pdata->odd_pwm_speed_mode ?
+				STA32X_CONFE_PWMS : 0);
+
+	/*  CONFF */
+	regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+			   STA32X_CONFF_IDE,
+			   pdata->invalid_input_detect_mute ?
+				STA32X_CONFF_IDE : 0);
+
+	/* select output configuration  */
+	regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+			   STA32X_CONFF_OCFG_MASK,
+			   pdata->output_conf
+				<< STA32X_CONFF_OCFG_SHIFT);
+
+	/* channel to output mapping */
+	regmap_update_bits(sta32x->regmap, STA32X_C1CFG,
+			   STA32X_CxCFG_OM_MASK,
+			   pdata->ch1_output_mapping
+				<< STA32X_CxCFG_OM_SHIFT);
+	regmap_update_bits(sta32x->regmap, STA32X_C2CFG,
+			   STA32X_CxCFG_OM_MASK,
+			   pdata->ch2_output_mapping
+				<< STA32X_CxCFG_OM_SHIFT);
+	regmap_update_bits(sta32x->regmap, STA32X_C3CFG,
+			   STA32X_CxCFG_OM_MASK,
+			   pdata->ch3_output_mapping
+				<< STA32X_CxCFG_OM_SHIFT);
+
+	/* initialize coefficient shadow RAM with reset values */
+	for (i = 4; i <= 49; i += 5)
+		sta32x->coef_shadow[i] = 0x400000;
+	for (i = 50; i <= 54; i++)
+		sta32x->coef_shadow[i] = 0x7fffff;
+	sta32x->coef_shadow[55] = 0x5a9df7;
+	sta32x->coef_shadow[56] = 0x7fffff;
+	sta32x->coef_shadow[59] = 0x7fffff;
+	sta32x->coef_shadow[60] = 0x400000;
+	sta32x->coef_shadow[61] = 0x400000;
+
+	if (sta32x->pdata->needs_esd_watchdog)
+		INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+	/* Bias level configuration will have done an extra enable */
+	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
+
+	return 0;
+}
+
+static void sta32x_remove(struct snd_soc_component *component)
+{
+	struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
+
+	sta32x_watchdog_stop(sta32x);
+	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
+}
+
+static const struct snd_soc_component_driver sta32x_component = {
+	.probe			= sta32x_probe,
+	.remove			= sta32x_remove,
+	.set_bias_level		= sta32x_set_bias_level,
+	.controls		= sta32x_snd_controls,
+	.num_controls		= ARRAY_SIZE(sta32x_snd_controls),
+	.dapm_widgets		= sta32x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sta32x_dapm_widgets),
+	.dapm_routes		= sta32x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(sta32x_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config sta32x_regmap = {
+	.reg_bits =		8,
+	.val_bits =		8,
+	.max_register =		STA32X_FDRC2,
+	.reg_defaults =		sta32x_regs,
+	.num_reg_defaults =	ARRAY_SIZE(sta32x_regs),
+	.cache_type =		REGCACHE_RBTREE,
+	.wr_table =		&sta32x_write_regs,
+	.rd_table =		&sta32x_read_regs,
+	.volatile_table =	&sta32x_volatile_regs,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id st32x_dt_ids[] = {
+	{ .compatible = "st,sta32x", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, st32x_dt_ids);
+
+static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
+{
+	struct device_node *np = dev->of_node;
+	struct sta32x_platform_data *pdata;
+	u16 tmp;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	of_property_read_u8(np, "st,output-conf",
+			    &pdata->output_conf);
+	of_property_read_u8(np, "st,ch1-output-mapping",
+			    &pdata->ch1_output_mapping);
+	of_property_read_u8(np, "st,ch2-output-mapping",
+			    &pdata->ch2_output_mapping);
+	of_property_read_u8(np, "st,ch3-output-mapping",
+			    &pdata->ch3_output_mapping);
+
+	if (of_get_property(np, "st,thermal-warning-recovery", NULL))
+		pdata->thermal_warning_recovery = 1;
+	if (of_get_property(np, "st,thermal-warning-adjustment", NULL))
+		pdata->thermal_warning_adjustment = 1;
+	if (of_get_property(np, "st,needs_esd_watchdog", NULL))
+		pdata->needs_esd_watchdog = 1;
+
+	tmp = 140;
+	of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
+	pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
+
+	/* CONFE */
+	if (of_get_property(np, "st,max-power-use-mpcc", NULL))
+		pdata->max_power_use_mpcc = 1;
+
+	if (of_get_property(np, "st,max-power-correction", NULL))
+		pdata->max_power_correction = 1;
+
+	if (of_get_property(np, "st,am-reduction-mode", NULL))
+		pdata->am_reduction_mode = 1;
+
+	if (of_get_property(np, "st,odd-pwm-speed-mode", NULL))
+		pdata->odd_pwm_speed_mode = 1;
+
+	/* CONFF */
+	if (of_get_property(np, "st,invalid-input-detect-mute", NULL))
+		pdata->invalid_input_detect_mute = 1;
+
+	sta32x->pdata = pdata;
+
+	return 0;
+}
+#endif
+
+static int sta32x_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct device *dev = &i2c->dev;
+	struct sta32x_priv *sta32x;
+	int ret, i;
+
+	sta32x = devm_kzalloc(&i2c->dev, sizeof(struct sta32x_priv),
+			      GFP_KERNEL);
+	if (!sta32x)
+		return -ENOMEM;
+
+	mutex_init(&sta32x->coeff_lock);
+	sta32x->pdata = dev_get_platdata(dev);
+
+#ifdef CONFIG_OF
+	if (dev->of_node) {
+		ret = sta32x_probe_dt(dev, sta32x);
+		if (ret < 0)
+			return ret;
+	}
+#endif
+
+	/* GPIOs */
+	sta32x->gpiod_nreset = devm_gpiod_get_optional(dev, "reset",
+						       GPIOD_OUT_LOW);
+	if (IS_ERR(sta32x->gpiod_nreset))
+		return PTR_ERR(sta32x->gpiod_nreset);
+
+	/* regulators */
+	for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
+		sta32x->supplies[i].supply = sta32x_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(sta32x->supplies),
+				      sta32x->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	sta32x->regmap = devm_regmap_init_i2c(i2c, &sta32x_regmap);
+	if (IS_ERR(sta32x->regmap)) {
+		ret = PTR_ERR(sta32x->regmap);
+		dev_err(dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, sta32x);
+
+	ret = devm_snd_soc_register_component(dev, &sta32x_component,
+					      &sta32x_dai, 1);
+	if (ret < 0)
+		dev_err(dev, "Failed to register component (%d)\n", ret);
+
+	return ret;
+}
+
+static const struct i2c_device_id sta32x_i2c_id[] = {
+	{ "sta326", 0 },
+	{ "sta328", 0 },
+	{ "sta329", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id);
+
+static struct i2c_driver sta32x_i2c_driver = {
+	.driver = {
+		.name = "sta32x",
+		.of_match_table = of_match_ptr(st32x_dt_ids),
+	},
+	.probe =    sta32x_i2c_probe,
+	.id_table = sta32x_i2c_id,
+};
+
+module_i2c_driver(sta32x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC STA32X driver");
+MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sta32x.h b/sound/soc/codecs/sta32x.h
new file mode 100644
index 0000000..d3191c9
--- /dev/null
+++ b/sound/soc/codecs/sta32x.h
@@ -0,0 +1,211 @@
+/*
+ * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system
+ *
+ * Copyright: 2011 Raumfeld GmbH
+ * Author: Johannes Stezenbach <js@sig21.net>
+ *
+ * based on code from:
+ *	Wolfson Microelectronics PLC.
+ *	Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef _ASOC_STA_32X_H
+#define _ASOC_STA_32X_H
+
+/* STA326 register addresses */
+
+#define STA32X_REGISTER_COUNT	0x2d
+#define STA32X_COEF_COUNT 62
+
+#define STA32X_CONFA	0x00
+#define STA32X_CONFB    0x01
+#define STA32X_CONFC    0x02
+#define STA32X_CONFD    0x03
+#define STA32X_CONFE    0x04
+#define STA32X_CONFF    0x05
+#define STA32X_MMUTE    0x06
+#define STA32X_MVOL     0x07
+#define STA32X_C1VOL    0x08
+#define STA32X_C2VOL    0x09
+#define STA32X_C3VOL    0x0a
+#define STA32X_AUTO1    0x0b
+#define STA32X_AUTO2    0x0c
+#define STA32X_AUTO3    0x0d
+#define STA32X_C1CFG    0x0e
+#define STA32X_C2CFG    0x0f
+#define STA32X_C3CFG    0x10
+#define STA32X_TONE     0x11
+#define STA32X_L1AR     0x12
+#define STA32X_L1ATRT   0x13
+#define STA32X_L2AR     0x14
+#define STA32X_L2ATRT   0x15
+#define STA32X_CFADDR2  0x16
+#define STA32X_B1CF1    0x17
+#define STA32X_B1CF2    0x18
+#define STA32X_B1CF3    0x19
+#define STA32X_B2CF1    0x1a
+#define STA32X_B2CF2    0x1b
+#define STA32X_B2CF3    0x1c
+#define STA32X_A1CF1    0x1d
+#define STA32X_A1CF2    0x1e
+#define STA32X_A1CF3    0x1f
+#define STA32X_A2CF1    0x20
+#define STA32X_A2CF2    0x21
+#define STA32X_A2CF3    0x22
+#define STA32X_B0CF1    0x23
+#define STA32X_B0CF2    0x24
+#define STA32X_B0CF3    0x25
+#define STA32X_CFUD     0x26
+#define STA32X_MPCC1    0x27
+#define STA32X_MPCC2    0x28
+/* Reserved 0x29 */
+/* Reserved 0x2a */
+#define STA32X_Reserved 0x2a
+#define STA32X_FDRC1    0x2b
+#define STA32X_FDRC2    0x2c
+/* Reserved 0x2d */
+
+
+/* STA326 register field definitions */
+
+/* 0x00 CONFA */
+#define STA32X_CONFA_MCS_MASK	0x03
+#define STA32X_CONFA_MCS_SHIFT	0
+#define STA32X_CONFA_IR_MASK	0x18
+#define STA32X_CONFA_IR_SHIFT	3
+#define STA32X_CONFA_TWRB	0x20
+#define STA32X_CONFA_TWAB	0x40
+#define STA32X_CONFA_FDRB	0x80
+
+/* 0x01 CONFB */
+#define STA32X_CONFB_SAI_MASK	0x0f
+#define STA32X_CONFB_SAI_SHIFT	0
+#define STA32X_CONFB_SAIFB	0x10
+#define STA32X_CONFB_DSCKE	0x20
+#define STA32X_CONFB_C1IM	0x40
+#define STA32X_CONFB_C2IM	0x80
+
+/* 0x02 CONFC */
+#define STA32X_CONFC_OM_MASK	0x03
+#define STA32X_CONFC_OM_SHIFT	0
+#define STA32X_CONFC_CSZ_MASK	0x7c
+#define STA32X_CONFC_CSZ_SHIFT	2
+
+/* 0x03 CONFD */
+#define STA32X_CONFD_HPB	0x01
+#define STA32X_CONFD_HPB_SHIFT	0
+#define STA32X_CONFD_DEMP	0x02
+#define STA32X_CONFD_DEMP_SHIFT	1
+#define STA32X_CONFD_DSPB	0x04
+#define STA32X_CONFD_DSPB_SHIFT	2
+#define STA32X_CONFD_PSL	0x08
+#define STA32X_CONFD_PSL_SHIFT	3
+#define STA32X_CONFD_BQL	0x10
+#define STA32X_CONFD_BQL_SHIFT	4
+#define STA32X_CONFD_DRC	0x20
+#define STA32X_CONFD_DRC_SHIFT	5
+#define STA32X_CONFD_ZDE	0x40
+#define STA32X_CONFD_ZDE_SHIFT	6
+#define STA32X_CONFD_MME	0x80
+#define STA32X_CONFD_MME_SHIFT	7
+
+/* 0x04 CONFE */
+#define STA32X_CONFE_MPCV	0x01
+#define STA32X_CONFE_MPCV_SHIFT	0
+#define STA32X_CONFE_MPC	0x02
+#define STA32X_CONFE_MPC_SHIFT	1
+#define STA32X_CONFE_AME	0x08
+#define STA32X_CONFE_AME_SHIFT	3
+#define STA32X_CONFE_PWMS	0x10
+#define STA32X_CONFE_PWMS_SHIFT	4
+#define STA32X_CONFE_ZCE	0x40
+#define STA32X_CONFE_ZCE_SHIFT	6
+#define STA32X_CONFE_SVE	0x80
+#define STA32X_CONFE_SVE_SHIFT	7
+
+/* 0x05 CONFF */
+#define STA32X_CONFF_OCFG_MASK	0x03
+#define STA32X_CONFF_OCFG_SHIFT	0
+#define STA32X_CONFF_IDE	0x04
+#define STA32X_CONFF_IDE_SHIFT	2
+#define STA32X_CONFF_BCLE	0x08
+#define STA32X_CONFF_ECLE	0x20
+#define STA32X_CONFF_PWDN	0x40
+#define STA32X_CONFF_EAPD	0x80
+
+/* 0x06 MMUTE */
+#define STA32X_MMUTE_MMUTE	0x01
+
+/* 0x0b AUTO1 */
+#define STA32X_AUTO1_AMEQ_MASK	0x03
+#define STA32X_AUTO1_AMEQ_SHIFT	0
+#define STA32X_AUTO1_AMV_MASK	0xc0
+#define STA32X_AUTO1_AMV_SHIFT	2
+#define STA32X_AUTO1_AMGC_MASK	0x30
+#define STA32X_AUTO1_AMGC_SHIFT	4
+#define STA32X_AUTO1_AMPS	0x80
+
+/* 0x0c AUTO2 */
+#define STA32X_AUTO2_AMAME	0x01
+#define STA32X_AUTO2_AMAM_MASK	0x0e
+#define STA32X_AUTO2_AMAM_SHIFT	1
+#define STA32X_AUTO2_XO_MASK	0xf0
+#define STA32X_AUTO2_XO_SHIFT	4
+
+/* 0x0d AUTO3 */
+#define STA32X_AUTO3_PEQ_MASK	0x1f
+#define STA32X_AUTO3_PEQ_SHIFT	0
+
+/* 0x0e 0x0f 0x10 CxCFG */
+#define STA32X_CxCFG_TCB	0x01	/* only C1 and C2 */
+#define STA32X_CxCFG_TCB_SHIFT	0
+#define STA32X_CxCFG_EQBP	0x02	/* only C1 and C2 */
+#define STA32X_CxCFG_EQBP_SHIFT	1
+#define STA32X_CxCFG_VBP	0x03
+#define STA32X_CxCFG_VBP_SHIFT	2
+#define STA32X_CxCFG_BO		0x04
+#define STA32X_CxCFG_LS_MASK	0x30
+#define STA32X_CxCFG_LS_SHIFT	4
+#define STA32X_CxCFG_OM_MASK	0xc0
+#define STA32X_CxCFG_OM_SHIFT	6
+
+/* 0x11 TONE */
+#define STA32X_TONE_BTC_SHIFT	0
+#define STA32X_TONE_TTC_SHIFT	4
+
+/* 0x12 0x13 0x14 0x15 limiter attack/release */
+#define STA32X_LxA_SHIFT	0
+#define STA32X_LxR_SHIFT	4
+
+/* 0x26 CFUD */
+#define STA32X_CFUD_W1		0x01
+#define STA32X_CFUD_WA		0x02
+#define STA32X_CFUD_R1		0x04
+#define STA32X_CFUD_RA		0x08
+
+
+/* biquad filter coefficient table offsets */
+#define STA32X_C1_BQ_BASE	0
+#define STA32X_C2_BQ_BASE	20
+#define STA32X_CH_BQ_NUM	4
+#define STA32X_BQ_NUM_COEF	5
+#define STA32X_XO_HP_BQ_BASE	40
+#define STA32X_XO_LP_BQ_BASE	45
+#define STA32X_C1_PRESCALE	50
+#define STA32X_C2_PRESCALE	51
+#define STA32X_C1_POSTSCALE	52
+#define STA32X_C2_POSTSCALE	53
+#define STA32X_C3_POSTSCALE	54
+#define STA32X_TW_POSTSCALE	55
+#define STA32X_C1_MIX1		56
+#define STA32X_C1_MIX2		57
+#define STA32X_C2_MIX1		58
+#define STA32X_C2_MIX2		59
+#define STA32X_C3_MIX1		60
+#define STA32X_C3_MIX2		61
+
+#endif /* _ASOC_STA_32X_H */
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
new file mode 100644
index 0000000..0b87031
--- /dev/null
+++ b/sound/soc/codecs/sta350.c
@@ -0,0 +1,1279 @@
+/*
+ * Codec driver for ST STA350 2.1-channel high-efficiency digital audio system
+ *
+ * Copyright: 2014 Raumfeld GmbH
+ * Author: Sven Brandau <info@brandau.biz>
+ *
+ * based on code from:
+ *	Raumfeld GmbH
+ *	  Johannes Stezenbach <js@sig21.net>
+ *	Wolfson Microelectronics PLC.
+ *	  Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *	Freescale Semiconductor, Inc.
+ *	  Timur Tabi <timur@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <sound/sta350.h>
+#include "sta350.h"
+
+#define STA350_RATES (SNDRV_PCM_RATE_32000 | \
+		      SNDRV_PCM_RATE_44100 | \
+		      SNDRV_PCM_RATE_48000 | \
+		      SNDRV_PCM_RATE_88200 | \
+		      SNDRV_PCM_RATE_96000 | \
+		      SNDRV_PCM_RATE_176400 | \
+		      SNDRV_PCM_RATE_192000)
+
+#define STA350_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
+	 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+	 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+	 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
+	 SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE  | \
+	 SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_S32_BE)
+
+/* Power-up register defaults */
+static const struct reg_default sta350_regs[] = {
+	{  0x0, 0x63 },
+	{  0x1, 0x80 },
+	{  0x2, 0xdf },
+	{  0x3, 0x40 },
+	{  0x4, 0xc2 },
+	{  0x5, 0x5c },
+	{  0x6, 0x00 },
+	{  0x7, 0xff },
+	{  0x8, 0x60 },
+	{  0x9, 0x60 },
+	{  0xa, 0x60 },
+	{  0xb, 0x00 },
+	{  0xc, 0x00 },
+	{  0xd, 0x00 },
+	{  0xe, 0x00 },
+	{  0xf, 0x40 },
+	{ 0x10, 0x80 },
+	{ 0x11, 0x77 },
+	{ 0x12, 0x6a },
+	{ 0x13, 0x69 },
+	{ 0x14, 0x6a },
+	{ 0x15, 0x69 },
+	{ 0x16, 0x00 },
+	{ 0x17, 0x00 },
+	{ 0x18, 0x00 },
+	{ 0x19, 0x00 },
+	{ 0x1a, 0x00 },
+	{ 0x1b, 0x00 },
+	{ 0x1c, 0x00 },
+	{ 0x1d, 0x00 },
+	{ 0x1e, 0x00 },
+	{ 0x1f, 0x00 },
+	{ 0x20, 0x00 },
+	{ 0x21, 0x00 },
+	{ 0x22, 0x00 },
+	{ 0x23, 0x00 },
+	{ 0x24, 0x00 },
+	{ 0x25, 0x00 },
+	{ 0x26, 0x00 },
+	{ 0x27, 0x2a },
+	{ 0x28, 0xc0 },
+	{ 0x29, 0xf3 },
+	{ 0x2a, 0x33 },
+	{ 0x2b, 0x00 },
+	{ 0x2c, 0x0c },
+	{ 0x31, 0x00 },
+	{ 0x36, 0x00 },
+	{ 0x37, 0x00 },
+	{ 0x38, 0x00 },
+	{ 0x39, 0x01 },
+	{ 0x3a, 0xee },
+	{ 0x3b, 0xff },
+	{ 0x3c, 0x7e },
+	{ 0x3d, 0xc0 },
+	{ 0x3e, 0x26 },
+	{ 0x3f, 0x00 },
+	{ 0x48, 0x00 },
+	{ 0x49, 0x00 },
+	{ 0x4a, 0x00 },
+	{ 0x4b, 0x04 },
+	{ 0x4c, 0x00 },
+};
+
+static const struct regmap_range sta350_write_regs_range[] = {
+	regmap_reg_range(STA350_CONFA,  STA350_AUTO2),
+	regmap_reg_range(STA350_C1CFG,  STA350_FDRC2),
+	regmap_reg_range(STA350_EQCFG,  STA350_EVOLRES),
+	regmap_reg_range(STA350_NSHAPE, STA350_MISC2),
+};
+
+static const struct regmap_range sta350_read_regs_range[] = {
+	regmap_reg_range(STA350_CONFA,  STA350_AUTO2),
+	regmap_reg_range(STA350_C1CFG,  STA350_STATUS),
+	regmap_reg_range(STA350_EQCFG,  STA350_EVOLRES),
+	regmap_reg_range(STA350_NSHAPE, STA350_MISC2),
+};
+
+static const struct regmap_range sta350_volatile_regs_range[] = {
+	regmap_reg_range(STA350_CFADDR2, STA350_CFUD),
+	regmap_reg_range(STA350_STATUS,  STA350_STATUS),
+};
+
+static const struct regmap_access_table sta350_write_regs = {
+	.yes_ranges =	sta350_write_regs_range,
+	.n_yes_ranges =	ARRAY_SIZE(sta350_write_regs_range),
+};
+
+static const struct regmap_access_table sta350_read_regs = {
+	.yes_ranges =	sta350_read_regs_range,
+	.n_yes_ranges =	ARRAY_SIZE(sta350_read_regs_range),
+};
+
+static const struct regmap_access_table sta350_volatile_regs = {
+	.yes_ranges =	sta350_volatile_regs_range,
+	.n_yes_ranges =	ARRAY_SIZE(sta350_volatile_regs_range),
+};
+
+/* regulator power supply names */
+static const char * const sta350_supply_names[] = {
+	"vdd-dig",	/* digital supply, 3.3V */
+	"vdd-pll",	/* pll supply, 3.3V */
+	"vcc"		/* power amp supply, 5V - 26V */
+};
+
+/* codec private data */
+struct sta350_priv {
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[ARRAY_SIZE(sta350_supply_names)];
+	struct sta350_platform_data *pdata;
+
+	unsigned int mclk;
+	unsigned int format;
+
+	u32 coef_shadow[STA350_COEF_COUNT];
+	int shutdown;
+
+	struct gpio_desc *gpiod_nreset;
+	struct gpio_desc *gpiod_power_down;
+
+	struct mutex coeff_lock;
+};
+
+static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1);
+static const DECLARE_TLV_DB_SCALE(tone_tlv, -1200, 200, 0);
+
+static const char * const sta350_drc_ac[] = {
+	"Anti-Clipping", "Dynamic Range Compression"
+};
+static const char * const sta350_auto_gc_mode[] = {
+	"User", "AC no clipping", "AC limited clipping (10%)",
+	"DRC nighttime listening mode"
+};
+static const char * const sta350_auto_xo_mode[] = {
+	"User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz",
+	"200Hz", "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz",
+	"340Hz", "360Hz"
+};
+static const char * const sta350_binary_output[] = {
+	"FFX 3-state output - normal operation", "Binary output"
+};
+static const char * const sta350_limiter_select[] = {
+	"Limiter Disabled", "Limiter #1", "Limiter #2"
+};
+static const char * const sta350_limiter_attack_rate[] = {
+	"3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024",
+	"0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752",
+	"0.0645", "0.0564", "0.0501", "0.0451"
+};
+static const char * const sta350_limiter_release_rate[] = {
+	"0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299",
+	"0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137",
+	"0.0134", "0.0117", "0.0110", "0.0104"
+};
+static const char * const sta350_noise_shaper_type[] = {
+	"Third order", "Fourth order"
+};
+
+static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_attack_tlv,
+	0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
+	8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),
+);
+
+static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_release_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0),
+	3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0),
+	8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0),
+);
+
+static DECLARE_TLV_DB_RANGE(sta350_limiter_drc_attack_tlv,
+	0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0),
+	8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0),
+	14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0),
+);
+
+static DECLARE_TLV_DB_RANGE(sta350_limiter_drc_release_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+	1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0),
+	3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0),
+	5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0),
+	13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
+);
+
+static SOC_ENUM_SINGLE_DECL(sta350_drc_ac_enum,
+			    STA350_CONFD, STA350_CONFD_DRC_SHIFT,
+			    sta350_drc_ac);
+static SOC_ENUM_SINGLE_DECL(sta350_noise_shaper_enum,
+			    STA350_CONFE, STA350_CONFE_NSBW_SHIFT,
+			    sta350_noise_shaper_type);
+static SOC_ENUM_SINGLE_DECL(sta350_auto_gc_enum,
+			    STA350_AUTO1, STA350_AUTO1_AMGC_SHIFT,
+			    sta350_auto_gc_mode);
+static SOC_ENUM_SINGLE_DECL(sta350_auto_xo_enum,
+			    STA350_AUTO2, STA350_AUTO2_XO_SHIFT,
+			    sta350_auto_xo_mode);
+static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch1_enum,
+			    STA350_C1CFG, STA350_CxCFG_BO_SHIFT,
+			    sta350_binary_output);
+static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch2_enum,
+			    STA350_C2CFG, STA350_CxCFG_BO_SHIFT,
+			    sta350_binary_output);
+static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch3_enum,
+			    STA350_C3CFG, STA350_CxCFG_BO_SHIFT,
+			    sta350_binary_output);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch1_enum,
+			    STA350_C1CFG, STA350_CxCFG_LS_SHIFT,
+			    sta350_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch2_enum,
+			    STA350_C2CFG, STA350_CxCFG_LS_SHIFT,
+			    sta350_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch3_enum,
+			    STA350_C3CFG, STA350_CxCFG_LS_SHIFT,
+			    sta350_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter1_attack_rate_enum,
+			    STA350_L1AR, STA350_LxA_SHIFT,
+			    sta350_limiter_attack_rate);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter2_attack_rate_enum,
+			    STA350_L2AR, STA350_LxA_SHIFT,
+			    sta350_limiter_attack_rate);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter1_release_rate_enum,
+			    STA350_L1AR, STA350_LxR_SHIFT,
+			    sta350_limiter_release_rate);
+static SOC_ENUM_SINGLE_DECL(sta350_limiter2_release_rate_enum,
+			    STA350_L2AR, STA350_LxR_SHIFT,
+			    sta350_limiter_release_rate);
+
+/*
+ * byte array controls for setting biquad, mixer, scaling coefficients;
+ * for biquads all five coefficients need to be set in one go,
+ * mixer and pre/postscale coefs can be set individually;
+ * each coef is 24bit, the bytes are ordered in the same way
+ * as given in the STA350 data sheet (big endian; b1, b2, a1, a2, b0)
+ */
+
+static int sta350_coefficient_info(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_info *uinfo)
+{
+	int numcoef = kcontrol->private_value >> 16;
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = 3 * numcoef;
+	return 0;
+}
+
+static int sta350_coefficient_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
+	int numcoef = kcontrol->private_value >> 16;
+	int index = kcontrol->private_value & 0xffff;
+	unsigned int cfud, val;
+	int i, ret = 0;
+
+	mutex_lock(&sta350->coeff_lock);
+
+	/* preserve reserved bits in STA350_CFUD */
+	regmap_read(sta350->regmap, STA350_CFUD, &cfud);
+	cfud &= 0xf0;
+	/*
+	 * chip documentation does not say if the bits are self clearing,
+	 * so do it explicitly
+	 */
+	regmap_write(sta350->regmap, STA350_CFUD, cfud);
+
+	regmap_write(sta350->regmap, STA350_CFADDR2, index);
+	if (numcoef == 1) {
+		regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x04);
+	} else if (numcoef == 5) {
+		regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x08);
+	} else {
+		ret = -EINVAL;
+		goto exit_unlock;
+	}
+
+	for (i = 0; i < 3 * numcoef; i++) {
+		regmap_read(sta350->regmap, STA350_B1CF1 + i, &val);
+		ucontrol->value.bytes.data[i] = val;
+	}
+
+exit_unlock:
+	mutex_unlock(&sta350->coeff_lock);
+
+	return ret;
+}
+
+static int sta350_coefficient_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
+	int numcoef = kcontrol->private_value >> 16;
+	int index = kcontrol->private_value & 0xffff;
+	unsigned int cfud;
+	int i;
+
+	/* preserve reserved bits in STA350_CFUD */
+	regmap_read(sta350->regmap, STA350_CFUD, &cfud);
+	cfud &= 0xf0;
+	/*
+	 * chip documentation does not say if the bits are self clearing,
+	 * so do it explicitly
+	 */
+	regmap_write(sta350->regmap, STA350_CFUD, cfud);
+
+	regmap_write(sta350->regmap, STA350_CFADDR2, index);
+	for (i = 0; i < numcoef && (index + i < STA350_COEF_COUNT); i++)
+		sta350->coef_shadow[index + i] =
+			  (ucontrol->value.bytes.data[3 * i] << 16)
+			| (ucontrol->value.bytes.data[3 * i + 1] << 8)
+			| (ucontrol->value.bytes.data[3 * i + 2]);
+	for (i = 0; i < 3 * numcoef; i++)
+		regmap_write(sta350->regmap, STA350_B1CF1 + i,
+			     ucontrol->value.bytes.data[i]);
+	if (numcoef == 1)
+		regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x01);
+	else if (numcoef == 5)
+		regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x02);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int sta350_sync_coef_shadow(struct snd_soc_component *component)
+{
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
+	unsigned int cfud;
+	int i;
+
+	/* preserve reserved bits in STA350_CFUD */
+	regmap_read(sta350->regmap, STA350_CFUD, &cfud);
+	cfud &= 0xf0;
+
+	for (i = 0; i < STA350_COEF_COUNT; i++) {
+		regmap_write(sta350->regmap, STA350_CFADDR2, i);
+		regmap_write(sta350->regmap, STA350_B1CF1,
+			     (sta350->coef_shadow[i] >> 16) & 0xff);
+		regmap_write(sta350->regmap, STA350_B1CF2,
+			     (sta350->coef_shadow[i] >> 8) & 0xff);
+		regmap_write(sta350->regmap, STA350_B1CF3,
+			     (sta350->coef_shadow[i]) & 0xff);
+		/*
+		 * chip documentation does not say if the bits are
+		 * self-clearing, so do it explicitly
+		 */
+		regmap_write(sta350->regmap, STA350_CFUD, cfud);
+		regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x01);
+	}
+	return 0;
+}
+
+static int sta350_cache_sync(struct snd_soc_component *component)
+{
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
+	unsigned int mute;
+	int rc;
+
+	/* mute during register sync */
+	regmap_read(sta350->regmap, STA350_CFUD, &mute);
+	regmap_write(sta350->regmap, STA350_MMUTE, mute | STA350_MMUTE_MMUTE);
+	sta350_sync_coef_shadow(component);
+	rc = regcache_sync(sta350->regmap);
+	regmap_write(sta350->regmap, STA350_MMUTE, mute);
+	return rc;
+}
+
+#define SINGLE_COEF(xname, index) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = sta350_coefficient_info, \
+	.get = sta350_coefficient_get,\
+	.put = sta350_coefficient_put, \
+	.private_value = index | (1 << 16) }
+
+#define BIQUAD_COEFS(xname, index) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = sta350_coefficient_info, \
+	.get = sta350_coefficient_get,\
+	.put = sta350_coefficient_put, \
+	.private_value = index | (5 << 16) }
+
+static const struct snd_kcontrol_new sta350_snd_controls[] = {
+SOC_SINGLE_TLV("Master Volume", STA350_MVOL, 0, 0xff, 1, mvol_tlv),
+/* VOL */
+SOC_SINGLE_TLV("Ch1 Volume", STA350_C1VOL, 0, 0xff, 1, chvol_tlv),
+SOC_SINGLE_TLV("Ch2 Volume", STA350_C2VOL, 0, 0xff, 1, chvol_tlv),
+SOC_SINGLE_TLV("Ch3 Volume", STA350_C3VOL, 0, 0xff, 1, chvol_tlv),
+/* CONFD */
+SOC_SINGLE("High Pass Filter Bypass Switch",
+	   STA350_CONFD, STA350_CONFD_HPB_SHIFT, 1, 1),
+SOC_SINGLE("De-emphasis Filter Switch",
+	   STA350_CONFD, STA350_CONFD_DEMP_SHIFT, 1, 0),
+SOC_SINGLE("DSP Bypass Switch",
+	   STA350_CONFD, STA350_CONFD_DSPB_SHIFT, 1, 0),
+SOC_SINGLE("Post-scale Link Switch",
+	   STA350_CONFD, STA350_CONFD_PSL_SHIFT, 1, 0),
+SOC_SINGLE("Biquad Coefficient Link Switch",
+	   STA350_CONFD, STA350_CONFD_BQL_SHIFT, 1, 0),
+SOC_ENUM("Compressor/Limiter Switch", sta350_drc_ac_enum),
+SOC_ENUM("Noise Shaper Bandwidth", sta350_noise_shaper_enum),
+SOC_SINGLE("Zero-detect Mute Enable Switch",
+	   STA350_CONFD, STA350_CONFD_ZDE_SHIFT, 1, 0),
+SOC_SINGLE("Submix Mode Switch",
+	   STA350_CONFD, STA350_CONFD_SME_SHIFT, 1, 0),
+/* CONFE */
+SOC_SINGLE("Zero Cross Switch", STA350_CONFE, STA350_CONFE_ZCE_SHIFT, 1, 0),
+SOC_SINGLE("Soft Ramp Switch", STA350_CONFE, STA350_CONFE_SVE_SHIFT, 1, 0),
+/* MUTE */
+SOC_SINGLE("Master Switch", STA350_MMUTE, STA350_MMUTE_MMUTE_SHIFT, 1, 1),
+SOC_SINGLE("Ch1 Switch", STA350_MMUTE, STA350_MMUTE_C1M_SHIFT, 1, 1),
+SOC_SINGLE("Ch2 Switch", STA350_MMUTE, STA350_MMUTE_C2M_SHIFT, 1, 1),
+SOC_SINGLE("Ch3 Switch", STA350_MMUTE, STA350_MMUTE_C3M_SHIFT, 1, 1),
+/* AUTOx */
+SOC_ENUM("Automode GC", sta350_auto_gc_enum),
+SOC_ENUM("Automode XO", sta350_auto_xo_enum),
+/* CxCFG */
+SOC_SINGLE("Ch1 Tone Control Bypass Switch",
+	   STA350_C1CFG, STA350_CxCFG_TCB_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 Tone Control Bypass Switch",
+	   STA350_C2CFG, STA350_CxCFG_TCB_SHIFT, 1, 0),
+SOC_SINGLE("Ch1 EQ Bypass Switch",
+	   STA350_C1CFG, STA350_CxCFG_EQBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 EQ Bypass Switch",
+	   STA350_C2CFG, STA350_CxCFG_EQBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch1 Master Volume Bypass Switch",
+	   STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch2 Master Volume Bypass Switch",
+	   STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0),
+SOC_SINGLE("Ch3 Master Volume Bypass Switch",
+	   STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0),
+SOC_ENUM("Ch1 Binary Output Select", sta350_binary_output_ch1_enum),
+SOC_ENUM("Ch2 Binary Output Select", sta350_binary_output_ch2_enum),
+SOC_ENUM("Ch3 Binary Output Select", sta350_binary_output_ch3_enum),
+SOC_ENUM("Ch1 Limiter Select", sta350_limiter_ch1_enum),
+SOC_ENUM("Ch2 Limiter Select", sta350_limiter_ch2_enum),
+SOC_ENUM("Ch3 Limiter Select", sta350_limiter_ch3_enum),
+/* TONE */
+SOC_SINGLE_RANGE_TLV("Bass Tone Control Volume",
+		     STA350_TONE, STA350_TONE_BTC_SHIFT, 1, 13, 0, tone_tlv),
+SOC_SINGLE_RANGE_TLV("Treble Tone Control Volume",
+		     STA350_TONE, STA350_TONE_TTC_SHIFT, 1, 13, 0, tone_tlv),
+SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta350_limiter1_attack_rate_enum),
+SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta350_limiter2_attack_rate_enum),
+SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta350_limiter1_release_rate_enum),
+SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta350_limiter2_release_rate_enum),
+
+/*
+ * depending on mode, the attack/release thresholds have
+ * two different enum definitions; provide both
+ */
+SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)",
+	       STA350_L1ATRT, STA350_LxA_SHIFT,
+	       16, 0, sta350_limiter_ac_attack_tlv),
+SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)",
+	       STA350_L2ATRT, STA350_LxA_SHIFT,
+	       16, 0, sta350_limiter_ac_attack_tlv),
+SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)",
+	       STA350_L1ATRT, STA350_LxR_SHIFT,
+	       16, 0, sta350_limiter_ac_release_tlv),
+SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)",
+	       STA350_L2ATRT, STA350_LxR_SHIFT,
+	       16, 0, sta350_limiter_ac_release_tlv),
+SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)",
+	       STA350_L1ATRT, STA350_LxA_SHIFT,
+	       16, 0, sta350_limiter_drc_attack_tlv),
+SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)",
+	       STA350_L2ATRT, STA350_LxA_SHIFT,
+	       16, 0, sta350_limiter_drc_attack_tlv),
+SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)",
+	       STA350_L1ATRT, STA350_LxR_SHIFT,
+	       16, 0, sta350_limiter_drc_release_tlv),
+SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)",
+	       STA350_L2ATRT, STA350_LxR_SHIFT,
+	       16, 0, sta350_limiter_drc_release_tlv),
+
+BIQUAD_COEFS("Ch1 - Biquad 1", 0),
+BIQUAD_COEFS("Ch1 - Biquad 2", 5),
+BIQUAD_COEFS("Ch1 - Biquad 3", 10),
+BIQUAD_COEFS("Ch1 - Biquad 4", 15),
+BIQUAD_COEFS("Ch2 - Biquad 1", 20),
+BIQUAD_COEFS("Ch2 - Biquad 2", 25),
+BIQUAD_COEFS("Ch2 - Biquad 3", 30),
+BIQUAD_COEFS("Ch2 - Biquad 4", 35),
+BIQUAD_COEFS("High-pass", 40),
+BIQUAD_COEFS("Low-pass", 45),
+SINGLE_COEF("Ch1 - Prescale", 50),
+SINGLE_COEF("Ch2 - Prescale", 51),
+SINGLE_COEF("Ch1 - Postscale", 52),
+SINGLE_COEF("Ch2 - Postscale", 53),
+SINGLE_COEF("Ch3 - Postscale", 54),
+SINGLE_COEF("Thermal warning - Postscale", 55),
+SINGLE_COEF("Ch1 - Mix 1", 56),
+SINGLE_COEF("Ch1 - Mix 2", 57),
+SINGLE_COEF("Ch2 - Mix 1", 58),
+SINGLE_COEF("Ch2 - Mix 2", 59),
+SINGLE_COEF("Ch3 - Mix 1", 60),
+SINGLE_COEF("Ch3 - Mix 2", 61),
+};
+
+static const struct snd_soc_dapm_widget sta350_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_OUTPUT("LEFT"),
+SND_SOC_DAPM_OUTPUT("RIGHT"),
+SND_SOC_DAPM_OUTPUT("SUB"),
+};
+
+static const struct snd_soc_dapm_route sta350_dapm_routes[] = {
+	{ "LEFT", NULL, "DAC" },
+	{ "RIGHT", NULL, "DAC" },
+	{ "SUB", NULL, "DAC" },
+	{ "DAC", NULL, "Playback" },
+};
+
+/* MCLK interpolation ratio per fs */
+static struct {
+	int fs;
+	int ir;
+} interpolation_ratios[] = {
+	{ 32000, 0 },
+	{ 44100, 0 },
+	{ 48000, 0 },
+	{ 88200, 1 },
+	{ 96000, 1 },
+	{ 176400, 2 },
+	{ 192000, 2 },
+};
+
+/* MCLK to fs clock ratios */
+static int mcs_ratio_table[3][6] = {
+	{ 768, 512, 384, 256, 128, 576 },
+	{ 384, 256, 192, 128,  64,   0 },
+	{ 192, 128,  96,  64,  32,   0 },
+};
+
+/**
+ * sta350_set_dai_sysclk - configure MCLK
+ * @codec_dai: the codec DAI
+ * @clk_id: the clock ID (ignored)
+ * @freq: the MCLK input frequency
+ * @dir: the clock direction (ignored)
+ *
+ * The value of MCLK is used to determine which sample rates are supported
+ * by the STA350, based on the mcs_ratio_table.
+ *
+ * This function must be called by the machine driver's 'startup' function,
+ * otherwise the list of supported sample rates will not be available in
+ * time for ALSA.
+ */
+static int sta350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "mclk=%u\n", freq);
+	sta350->mclk = freq;
+
+	return 0;
+}
+
+/**
+ * sta350_set_dai_fmt - configure the codec for the selected audio format
+ * @codec_dai: the codec DAI
+ * @fmt: a SND_SOC_DAIFMT_x value indicating the data format
+ *
+ * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the
+ * codec accordingly.
+ */
+static int sta350_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
+	unsigned int confb = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		sta350->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		confb |= STA350_CONFB_C2IM;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		confb |= STA350_CONFB_C1IM;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(sta350->regmap, STA350_CONFB,
+				  STA350_CONFB_C1IM | STA350_CONFB_C2IM, confb);
+}
+
+/**
+ * sta350_hw_params - program the STA350 with the given hardware parameters.
+ * @substream: the audio stream
+ * @params: the hardware parameters to set
+ * @dai: the SOC DAI (ignored)
+ *
+ * This function programs the hardware with the values provided.
+ * Specifically, the sample rate and the data format.
+ */
+static int sta350_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
+	int i, mcs = -EINVAL, ir = -EINVAL;
+	unsigned int confa, confb;
+	unsigned int rate, ratio;
+	int ret;
+
+	if (!sta350->mclk) {
+		dev_err(component->dev,
+			"sta350->mclk is unset. Unable to determine ratio\n");
+		return -EIO;
+	}
+
+	rate = params_rate(params);
+	ratio = sta350->mclk / rate;
+	dev_dbg(component->dev, "rate: %u, ratio: %u\n", rate, ratio);
+
+	for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
+		if (interpolation_ratios[i].fs == rate) {
+			ir = interpolation_ratios[i].ir;
+			break;
+		}
+	}
+
+	if (ir < 0) {
+		dev_err(component->dev, "Unsupported samplerate: %u\n", rate);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 6; i++) {
+		if (mcs_ratio_table[ir][i] == ratio) {
+			mcs = i;
+			break;
+		}
+	}
+
+	if (mcs < 0) {
+		dev_err(component->dev, "Unresolvable ratio: %u\n", ratio);
+		return -EINVAL;
+	}
+
+	confa = (ir << STA350_CONFA_IR_SHIFT) |
+		(mcs << STA350_CONFA_MCS_SHIFT);
+	confb = 0;
+
+	switch (params_width(params)) {
+	case 24:
+		dev_dbg(component->dev, "24bit\n");
+		/* fall through */
+	case 32:
+		dev_dbg(component->dev, "24bit or 32bit\n");
+		switch (sta350->format) {
+		case SND_SOC_DAIFMT_I2S:
+			confb |= 0x0;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			confb |= 0x1;
+			break;
+		case SND_SOC_DAIFMT_RIGHT_J:
+			confb |= 0x2;
+			break;
+		}
+
+		break;
+	case 20:
+		dev_dbg(component->dev, "20bit\n");
+		switch (sta350->format) {
+		case SND_SOC_DAIFMT_I2S:
+			confb |= 0x4;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			confb |= 0x5;
+			break;
+		case SND_SOC_DAIFMT_RIGHT_J:
+			confb |= 0x6;
+			break;
+		}
+
+		break;
+	case 18:
+		dev_dbg(component->dev, "18bit\n");
+		switch (sta350->format) {
+		case SND_SOC_DAIFMT_I2S:
+			confb |= 0x8;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			confb |= 0x9;
+			break;
+		case SND_SOC_DAIFMT_RIGHT_J:
+			confb |= 0xa;
+			break;
+		}
+
+		break;
+	case 16:
+		dev_dbg(component->dev, "16bit\n");
+		switch (sta350->format) {
+		case SND_SOC_DAIFMT_I2S:
+			confb |= 0x0;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			confb |= 0xd;
+			break;
+		case SND_SOC_DAIFMT_RIGHT_J:
+			confb |= 0xe;
+			break;
+		}
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(sta350->regmap, STA350_CONFA,
+				 STA350_CONFA_MCS_MASK | STA350_CONFA_IR_MASK,
+				 confa);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_update_bits(sta350->regmap, STA350_CONFB,
+				 STA350_CONFB_SAI_MASK | STA350_CONFB_SAIFB,
+				 confb);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int sta350_startup_sequence(struct sta350_priv *sta350)
+{
+	if (sta350->gpiod_power_down)
+		gpiod_set_value(sta350->gpiod_power_down, 1);
+
+	if (sta350->gpiod_nreset) {
+		gpiod_set_value(sta350->gpiod_nreset, 0);
+		mdelay(1);
+		gpiod_set_value(sta350->gpiod_nreset, 1);
+		mdelay(1);
+	}
+
+	return 0;
+}
+
+/**
+ * sta350_set_bias_level - DAPM callback
+ * @component: the component device
+ * @level: DAPM power level
+ *
+ * This is called by ALSA to put the component into low power mode
+ * or to wake it up.  If the component is powered off completely
+ * all registers must be restored after power on.
+ */
+static int sta350_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	dev_dbg(component->dev, "level = %d\n", level);
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* Full power on */
+		regmap_update_bits(sta350->regmap, STA350_CONFF,
+				   STA350_CONFF_PWDN | STA350_CONFF_EAPD,
+				   STA350_CONFF_PWDN | STA350_CONFF_EAPD);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(
+				ARRAY_SIZE(sta350->supplies),
+				sta350->supplies);
+			if (ret < 0) {
+				dev_err(component->dev,
+					"Failed to enable supplies: %d\n",
+					ret);
+				return ret;
+			}
+			sta350_startup_sequence(sta350);
+			sta350_cache_sync(component);
+		}
+
+		/* Power down */
+		regmap_update_bits(sta350->regmap, STA350_CONFF,
+				   STA350_CONFF_PWDN | STA350_CONFF_EAPD,
+				   0);
+
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* The chip runs through the power down sequence for us */
+		regmap_update_bits(sta350->regmap, STA350_CONFF,
+				   STA350_CONFF_PWDN | STA350_CONFF_EAPD, 0);
+
+		/* power down: low */
+		if (sta350->gpiod_power_down)
+			gpiod_set_value(sta350->gpiod_power_down, 0);
+
+		if (sta350->gpiod_nreset)
+			gpiod_set_value(sta350->gpiod_nreset, 0);
+
+		regulator_bulk_disable(ARRAY_SIZE(sta350->supplies),
+				       sta350->supplies);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops sta350_dai_ops = {
+	.hw_params	= sta350_hw_params,
+	.set_sysclk	= sta350_set_dai_sysclk,
+	.set_fmt	= sta350_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver sta350_dai = {
+	.name = "sta350-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = STA350_RATES,
+		.formats = STA350_FORMATS,
+	},
+	.ops = &sta350_dai_ops,
+};
+
+static int sta350_probe(struct snd_soc_component *component)
+{
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
+	struct sta350_platform_data *pdata = sta350->pdata;
+	int i, ret = 0, thermal = 0;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(sta350->supplies),
+				    sta350->supplies);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = sta350_startup_sequence(sta350);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to startup device\n");
+		return ret;
+	}
+
+	/* CONFA */
+	if (!pdata->thermal_warning_recovery)
+		thermal |= STA350_CONFA_TWAB;
+	if (!pdata->thermal_warning_adjustment)
+		thermal |= STA350_CONFA_TWRB;
+	if (!pdata->fault_detect_recovery)
+		thermal |= STA350_CONFA_FDRB;
+	regmap_update_bits(sta350->regmap, STA350_CONFA,
+			   STA350_CONFA_TWAB | STA350_CONFA_TWRB |
+			   STA350_CONFA_FDRB,
+			   thermal);
+
+	/* CONFC */
+	regmap_update_bits(sta350->regmap, STA350_CONFC,
+			   STA350_CONFC_OM_MASK,
+			   pdata->ffx_power_output_mode
+				<< STA350_CONFC_OM_SHIFT);
+	regmap_update_bits(sta350->regmap, STA350_CONFC,
+			   STA350_CONFC_CSZ_MASK,
+			   pdata->drop_compensation_ns
+				<< STA350_CONFC_CSZ_SHIFT);
+	regmap_update_bits(sta350->regmap,
+			   STA350_CONFC,
+			   STA350_CONFC_OCRB,
+			   pdata->oc_warning_adjustment ?
+				STA350_CONFC_OCRB : 0);
+
+	/* CONFE */
+	regmap_update_bits(sta350->regmap, STA350_CONFE,
+			   STA350_CONFE_MPCV,
+			   pdata->max_power_use_mpcc ?
+				STA350_CONFE_MPCV : 0);
+	regmap_update_bits(sta350->regmap, STA350_CONFE,
+			   STA350_CONFE_MPC,
+			   pdata->max_power_correction ?
+				STA350_CONFE_MPC : 0);
+	regmap_update_bits(sta350->regmap, STA350_CONFE,
+			   STA350_CONFE_AME,
+			   pdata->am_reduction_mode ?
+				STA350_CONFE_AME : 0);
+	regmap_update_bits(sta350->regmap, STA350_CONFE,
+			   STA350_CONFE_PWMS,
+			   pdata->odd_pwm_speed_mode ?
+				STA350_CONFE_PWMS : 0);
+	regmap_update_bits(sta350->regmap, STA350_CONFE,
+			   STA350_CONFE_DCCV,
+			   pdata->distortion_compensation ?
+				STA350_CONFE_DCCV : 0);
+	/*  CONFF */
+	regmap_update_bits(sta350->regmap, STA350_CONFF,
+			   STA350_CONFF_IDE,
+			   pdata->invalid_input_detect_mute ?
+				STA350_CONFF_IDE : 0);
+	regmap_update_bits(sta350->regmap, STA350_CONFF,
+			   STA350_CONFF_OCFG_MASK,
+			   pdata->output_conf
+				<< STA350_CONFF_OCFG_SHIFT);
+
+	/* channel to output mapping */
+	regmap_update_bits(sta350->regmap, STA350_C1CFG,
+			   STA350_CxCFG_OM_MASK,
+			   pdata->ch1_output_mapping
+				<< STA350_CxCFG_OM_SHIFT);
+	regmap_update_bits(sta350->regmap, STA350_C2CFG,
+			   STA350_CxCFG_OM_MASK,
+			   pdata->ch2_output_mapping
+				<< STA350_CxCFG_OM_SHIFT);
+	regmap_update_bits(sta350->regmap, STA350_C3CFG,
+			   STA350_CxCFG_OM_MASK,
+			   pdata->ch3_output_mapping
+				<< STA350_CxCFG_OM_SHIFT);
+
+	/* miscellaneous registers */
+	regmap_update_bits(sta350->regmap, STA350_MISC1,
+			   STA350_MISC1_CPWMEN,
+			   pdata->activate_mute_output ?
+				STA350_MISC1_CPWMEN : 0);
+	regmap_update_bits(sta350->regmap, STA350_MISC1,
+			   STA350_MISC1_BRIDGOFF,
+			   pdata->bridge_immediate_off ?
+				STA350_MISC1_BRIDGOFF : 0);
+	regmap_update_bits(sta350->regmap, STA350_MISC1,
+			   STA350_MISC1_NSHHPEN,
+			   pdata->noise_shape_dc_cut ?
+				STA350_MISC1_NSHHPEN : 0);
+	regmap_update_bits(sta350->regmap, STA350_MISC1,
+			   STA350_MISC1_RPDNEN,
+			   pdata->powerdown_master_vol ?
+				STA350_MISC1_RPDNEN: 0);
+
+	regmap_update_bits(sta350->regmap, STA350_MISC2,
+			   STA350_MISC2_PNDLSL_MASK,
+			   pdata->powerdown_delay_divider
+				<< STA350_MISC2_PNDLSL_SHIFT);
+
+	/* initialize coefficient shadow RAM with reset values */
+	for (i = 4; i <= 49; i += 5)
+		sta350->coef_shadow[i] = 0x400000;
+	for (i = 50; i <= 54; i++)
+		sta350->coef_shadow[i] = 0x7fffff;
+	sta350->coef_shadow[55] = 0x5a9df7;
+	sta350->coef_shadow[56] = 0x7fffff;
+	sta350->coef_shadow[59] = 0x7fffff;
+	sta350->coef_shadow[60] = 0x400000;
+	sta350->coef_shadow[61] = 0x400000;
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+	/* Bias level configuration will have done an extra enable */
+	regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies);
+
+	return 0;
+}
+
+static void sta350_remove(struct snd_soc_component *component)
+{
+	struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
+
+	regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies);
+}
+
+static const struct snd_soc_component_driver sta350_component = {
+	.probe			= sta350_probe,
+	.remove			= sta350_remove,
+	.set_bias_level		= sta350_set_bias_level,
+	.controls		= sta350_snd_controls,
+	.num_controls		= ARRAY_SIZE(sta350_snd_controls),
+	.dapm_widgets		= sta350_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sta350_dapm_widgets),
+	.dapm_routes		= sta350_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(sta350_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config sta350_regmap = {
+	.reg_bits =		8,
+	.val_bits =		8,
+	.max_register =		STA350_MISC2,
+	.reg_defaults =		sta350_regs,
+	.num_reg_defaults =	ARRAY_SIZE(sta350_regs),
+	.cache_type =		REGCACHE_RBTREE,
+	.wr_table =		&sta350_write_regs,
+	.rd_table =		&sta350_read_regs,
+	.volatile_table =	&sta350_volatile_regs,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id st350_dt_ids[] = {
+	{ .compatible = "st,sta350", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, st350_dt_ids);
+
+static const char * const sta350_ffx_modes[] = {
+	[STA350_FFX_PM_DROP_COMP]		= "drop-compensation",
+	[STA350_FFX_PM_TAPERED_COMP]		= "tapered-compensation",
+	[STA350_FFX_PM_FULL_POWER]		= "full-power-mode",
+	[STA350_FFX_PM_VARIABLE_DROP_COMP]	= "variable-drop-compensation",
+};
+
+static int sta350_probe_dt(struct device *dev, struct sta350_priv *sta350)
+{
+	struct device_node *np = dev->of_node;
+	struct sta350_platform_data *pdata;
+	const char *ffx_power_mode;
+	u16 tmp;
+	u8 tmp8;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	of_property_read_u8(np, "st,output-conf",
+			    &pdata->output_conf);
+	of_property_read_u8(np, "st,ch1-output-mapping",
+			    &pdata->ch1_output_mapping);
+	of_property_read_u8(np, "st,ch2-output-mapping",
+			    &pdata->ch2_output_mapping);
+	of_property_read_u8(np, "st,ch3-output-mapping",
+			    &pdata->ch3_output_mapping);
+
+	if (of_get_property(np, "st,thermal-warning-recovery", NULL))
+		pdata->thermal_warning_recovery = 1;
+	if (of_get_property(np, "st,thermal-warning-adjustment", NULL))
+		pdata->thermal_warning_adjustment = 1;
+	if (of_get_property(np, "st,fault-detect-recovery", NULL))
+		pdata->fault_detect_recovery = 1;
+
+	pdata->ffx_power_output_mode = STA350_FFX_PM_VARIABLE_DROP_COMP;
+	if (!of_property_read_string(np, "st,ffx-power-output-mode",
+				     &ffx_power_mode)) {
+		int i, mode = -EINVAL;
+
+		for (i = 0; i < ARRAY_SIZE(sta350_ffx_modes); i++)
+			if (!strcasecmp(ffx_power_mode, sta350_ffx_modes[i]))
+				mode = i;
+
+		if (mode < 0)
+			dev_warn(dev, "Unsupported ffx output mode: %s\n",
+				 ffx_power_mode);
+		else
+			pdata->ffx_power_output_mode = mode;
+	}
+
+	tmp = 140;
+	of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
+	pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
+
+	if (of_get_property(np, "st,overcurrent-warning-adjustment", NULL))
+		pdata->oc_warning_adjustment = 1;
+
+	/* CONFE */
+	if (of_get_property(np, "st,max-power-use-mpcc", NULL))
+		pdata->max_power_use_mpcc = 1;
+
+	if (of_get_property(np, "st,max-power-correction", NULL))
+		pdata->max_power_correction = 1;
+
+	if (of_get_property(np, "st,am-reduction-mode", NULL))
+		pdata->am_reduction_mode = 1;
+
+	if (of_get_property(np, "st,odd-pwm-speed-mode", NULL))
+		pdata->odd_pwm_speed_mode = 1;
+
+	if (of_get_property(np, "st,distortion-compensation", NULL))
+		pdata->distortion_compensation = 1;
+
+	/* CONFF */
+	if (of_get_property(np, "st,invalid-input-detect-mute", NULL))
+		pdata->invalid_input_detect_mute = 1;
+
+	/* MISC */
+	if (of_get_property(np, "st,activate-mute-output", NULL))
+		pdata->activate_mute_output = 1;
+
+	if (of_get_property(np, "st,bridge-immediate-off", NULL))
+		pdata->bridge_immediate_off = 1;
+
+	if (of_get_property(np, "st,noise-shape-dc-cut", NULL))
+		pdata->noise_shape_dc_cut = 1;
+
+	if (of_get_property(np, "st,powerdown-master-volume", NULL))
+		pdata->powerdown_master_vol = 1;
+
+	if (!of_property_read_u8(np, "st,powerdown-delay-divider", &tmp8)) {
+		if (is_power_of_2(tmp8) && tmp8 >= 1 && tmp8 <= 128)
+			pdata->powerdown_delay_divider = ilog2(tmp8);
+		else
+			dev_warn(dev, "Unsupported powerdown delay divider %d\n",
+				 tmp8);
+	}
+
+	sta350->pdata = pdata;
+
+	return 0;
+}
+#endif
+
+static int sta350_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct device *dev = &i2c->dev;
+	struct sta350_priv *sta350;
+	int ret, i;
+
+	sta350 = devm_kzalloc(dev, sizeof(struct sta350_priv), GFP_KERNEL);
+	if (!sta350)
+		return -ENOMEM;
+
+	mutex_init(&sta350->coeff_lock);
+	sta350->pdata = dev_get_platdata(dev);
+
+#ifdef CONFIG_OF
+	if (dev->of_node) {
+		ret = sta350_probe_dt(dev, sta350);
+		if (ret < 0)
+			return ret;
+	}
+#endif
+
+	/* GPIOs */
+	sta350->gpiod_nreset = devm_gpiod_get_optional(dev, "reset",
+						       GPIOD_OUT_LOW);
+	if (IS_ERR(sta350->gpiod_nreset))
+		return PTR_ERR(sta350->gpiod_nreset);
+
+	sta350->gpiod_power_down = devm_gpiod_get_optional(dev, "power-down",
+							   GPIOD_OUT_LOW);
+	if (IS_ERR(sta350->gpiod_power_down))
+		return PTR_ERR(sta350->gpiod_power_down);
+
+	/* regulators */
+	for (i = 0; i < ARRAY_SIZE(sta350->supplies); i++)
+		sta350->supplies[i].supply = sta350_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sta350->supplies),
+				      sta350->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	sta350->regmap = devm_regmap_init_i2c(i2c, &sta350_regmap);
+	if (IS_ERR(sta350->regmap)) {
+		ret = PTR_ERR(sta350->regmap);
+		dev_err(dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, sta350);
+
+	ret = devm_snd_soc_register_component(dev, &sta350_component, &sta350_dai, 1);
+	if (ret < 0)
+		dev_err(dev, "Failed to register component (%d)\n", ret);
+
+	return ret;
+}
+
+static int sta350_i2c_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id sta350_i2c_id[] = {
+	{ "sta350", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, sta350_i2c_id);
+
+static struct i2c_driver sta350_i2c_driver = {
+	.driver = {
+		.name = "sta350",
+		.of_match_table = of_match_ptr(st350_dt_ids),
+	},
+	.probe =    sta350_i2c_probe,
+	.remove =   sta350_i2c_remove,
+	.id_table = sta350_i2c_id,
+};
+
+module_i2c_driver(sta350_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC STA350 driver");
+MODULE_AUTHOR("Sven Brandau <info@brandau.biz>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sta350.h b/sound/soc/codecs/sta350.h
new file mode 100644
index 0000000..fb72852
--- /dev/null
+++ b/sound/soc/codecs/sta350.h
@@ -0,0 +1,238 @@
+/*
+ * Codec driver for ST STA350 2.1-channel high-efficiency digital audio system
+ *
+ * Copyright: 2011 Raumfeld GmbH
+ * Author: Sven Brandau <info@brandau.biz>
+ *
+ * based on code from:
+ *      Raumfeld GmbH
+ *        Johannes Stezenbach <js@sig21.net>
+ *	Wolfson Microelectronics PLC.
+ *	  Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef _ASOC_STA_350_H
+#define _ASOC_STA_350_H
+
+/* STA50 register addresses */
+
+#define STA350_REGISTER_COUNT	0x4D
+#define STA350_COEF_COUNT 62
+
+#define STA350_CONFA	0x00
+#define STA350_CONFB    0x01
+#define STA350_CONFC    0x02
+#define STA350_CONFD    0x03
+#define STA350_CONFE    0x04
+#define STA350_CONFF    0x05
+#define STA350_MMUTE    0x06
+#define STA350_MVOL     0x07
+#define STA350_C1VOL    0x08
+#define STA350_C2VOL    0x09
+#define STA350_C3VOL    0x0a
+#define STA350_AUTO1    0x0b
+#define STA350_AUTO2    0x0c
+#define STA350_AUTO3    0x0d
+#define STA350_C1CFG    0x0e
+#define STA350_C2CFG    0x0f
+#define STA350_C3CFG    0x10
+#define STA350_TONE     0x11
+#define STA350_L1AR     0x12
+#define STA350_L1ATRT   0x13
+#define STA350_L2AR     0x14
+#define STA350_L2ATRT   0x15
+#define STA350_CFADDR2  0x16
+#define STA350_B1CF1    0x17
+#define STA350_B1CF2    0x18
+#define STA350_B1CF3    0x19
+#define STA350_B2CF1    0x1a
+#define STA350_B2CF2    0x1b
+#define STA350_B2CF3    0x1c
+#define STA350_A1CF1    0x1d
+#define STA350_A1CF2    0x1e
+#define STA350_A1CF3    0x1f
+#define STA350_A2CF1    0x20
+#define STA350_A2CF2    0x21
+#define STA350_A2CF3    0x22
+#define STA350_B0CF1    0x23
+#define STA350_B0CF2    0x24
+#define STA350_B0CF3    0x25
+#define STA350_CFUD     0x26
+#define STA350_MPCC1    0x27
+#define STA350_MPCC2    0x28
+#define STA350_DCC1     0x29
+#define STA350_DCC2     0x2a
+#define STA350_FDRC1    0x2b
+#define STA350_FDRC2    0x2c
+#define STA350_STATUS   0x2d
+/* reserved: 0x2d - 0x30 */
+#define STA350_EQCFG    0x31
+#define STA350_EATH1    0x32
+#define STA350_ERTH1    0x33
+#define STA350_EATH2    0x34
+#define STA350_ERTH2    0x35
+#define STA350_CONFX    0x36
+#define STA350_SVCA     0x37
+#define STA350_SVCB     0x38
+#define STA350_RMS0A    0x39
+#define STA350_RMS0B    0x3a
+#define STA350_RMS0C    0x3b
+#define STA350_RMS1A    0x3c
+#define STA350_RMS1B    0x3d
+#define STA350_RMS1C    0x3e
+#define STA350_EVOLRES  0x3f
+/* reserved: 0x40 - 0x47 */
+#define STA350_NSHAPE   0x48
+#define STA350_CTXB4B1  0x49
+#define STA350_CTXB7B5  0x4a
+#define STA350_MISC1    0x4b
+#define STA350_MISC2    0x4c
+
+/* 0x00 CONFA */
+#define STA350_CONFA_MCS_MASK	0x03
+#define STA350_CONFA_MCS_SHIFT	0
+#define STA350_CONFA_IR_MASK	0x18
+#define STA350_CONFA_IR_SHIFT	3
+#define STA350_CONFA_TWRB	BIT(5)
+#define STA350_CONFA_TWAB	BIT(6)
+#define STA350_CONFA_FDRB	BIT(7)
+
+/* 0x01 CONFB */
+#define STA350_CONFB_SAI_MASK	0x0f
+#define STA350_CONFB_SAI_SHIFT	0
+#define STA350_CONFB_SAIFB	BIT(4)
+#define STA350_CONFB_DSCKE	BIT(5)
+#define STA350_CONFB_C1IM	BIT(6)
+#define STA350_CONFB_C2IM	BIT(7)
+
+/* 0x02 CONFC */
+#define STA350_CONFC_OM_MASK	0x03
+#define STA350_CONFC_OM_SHIFT	0
+#define STA350_CONFC_CSZ_MASK	0x3c
+#define STA350_CONFC_CSZ_SHIFT	2
+#define STA350_CONFC_OCRB	BIT(7)
+
+/* 0x03 CONFD */
+#define STA350_CONFD_HPB_SHIFT	0
+#define STA350_CONFD_DEMP_SHIFT	1
+#define STA350_CONFD_DSPB_SHIFT	2
+#define STA350_CONFD_PSL_SHIFT	3
+#define STA350_CONFD_BQL_SHIFT	4
+#define STA350_CONFD_DRC_SHIFT	5
+#define STA350_CONFD_ZDE_SHIFT	6
+#define STA350_CONFD_SME_SHIFT	7
+
+/* 0x04 CONFE */
+#define STA350_CONFE_MPCV	BIT(0)
+#define STA350_CONFE_MPCV_SHIFT	0
+#define STA350_CONFE_MPC	BIT(1)
+#define STA350_CONFE_MPC_SHIFT	1
+#define STA350_CONFE_NSBW	BIT(2)
+#define STA350_CONFE_NSBW_SHIFT	2
+#define STA350_CONFE_AME	BIT(3)
+#define STA350_CONFE_AME_SHIFT	3
+#define STA350_CONFE_PWMS	BIT(4)
+#define STA350_CONFE_PWMS_SHIFT	4
+#define STA350_CONFE_DCCV	BIT(5)
+#define STA350_CONFE_DCCV_SHIFT	5
+#define STA350_CONFE_ZCE	BIT(6)
+#define STA350_CONFE_ZCE_SHIFT	6
+#define STA350_CONFE_SVE	BIT(7)
+#define STA350_CONFE_SVE_SHIFT	7
+
+/* 0x05 CONFF */
+#define STA350_CONFF_OCFG_MASK	0x03
+#define STA350_CONFF_OCFG_SHIFT	0
+#define STA350_CONFF_IDE	BIT(2)
+#define STA350_CONFF_BCLE	BIT(3)
+#define STA350_CONFF_LDTE	BIT(4)
+#define STA350_CONFF_ECLE	BIT(5)
+#define STA350_CONFF_PWDN	BIT(6)
+#define STA350_CONFF_EAPD	BIT(7)
+
+/* 0x06 MMUTE */
+#define STA350_MMUTE_MMUTE		0x01
+#define STA350_MMUTE_MMUTE_SHIFT	0
+#define STA350_MMUTE_C1M		0x02
+#define STA350_MMUTE_C1M_SHIFT		1
+#define STA350_MMUTE_C2M		0x04
+#define STA350_MMUTE_C2M_SHIFT		2
+#define STA350_MMUTE_C3M		0x08
+#define STA350_MMUTE_C3M_SHIFT		3
+#define STA350_MMUTE_LOC_MASK		0xC0
+#define STA350_MMUTE_LOC_SHIFT		6
+
+/* 0x0b AUTO1 */
+#define STA350_AUTO1_AMGC_MASK	0x30
+#define STA350_AUTO1_AMGC_SHIFT	4
+
+/* 0x0c AUTO2 */
+#define STA350_AUTO2_AMAME	0x01
+#define STA350_AUTO2_AMAM_MASK	0x0e
+#define STA350_AUTO2_AMAM_SHIFT	1
+#define STA350_AUTO2_XO_MASK	0xf0
+#define STA350_AUTO2_XO_SHIFT	4
+
+/* 0x0d AUTO3 */
+#define STA350_AUTO3_PEQ_MASK	0x1f
+#define STA350_AUTO3_PEQ_SHIFT	0
+
+/* 0x0e 0x0f 0x10 CxCFG */
+#define STA350_CxCFG_TCB_SHIFT	0
+#define STA350_CxCFG_EQBP_SHIFT	1
+#define STA350_CxCFG_VBP_SHIFT	2
+#define STA350_CxCFG_BO_SHIFT	3
+#define STA350_CxCFG_LS_SHIFT	4
+#define STA350_CxCFG_OM_MASK	0xc0
+#define STA350_CxCFG_OM_SHIFT	6
+
+/* 0x11 TONE */
+#define STA350_TONE_BTC_SHIFT	0
+#define STA350_TONE_TTC_SHIFT	4
+
+/* 0x12 0x13 0x14 0x15 limiter attack/release */
+#define STA350_LxA_SHIFT	0
+#define STA350_LxR_SHIFT	4
+
+/* 0x26 CFUD */
+#define STA350_CFUD_W1		0x01
+#define STA350_CFUD_WA		0x02
+#define STA350_CFUD_R1		0x04
+#define STA350_CFUD_RA		0x08
+
+
+/* biquad filter coefficient table offsets */
+#define STA350_C1_BQ_BASE	0
+#define STA350_C2_BQ_BASE	20
+#define STA350_CH_BQ_NUM	4
+#define STA350_BQ_NUM_COEF	5
+#define STA350_XO_HP_BQ_BASE	40
+#define STA350_XO_LP_BQ_BASE	45
+#define STA350_C1_PRESCALE	50
+#define STA350_C2_PRESCALE	51
+#define STA350_C1_POSTSCALE	52
+#define STA350_C2_POSTSCALE	53
+#define STA350_C3_POSTSCALE	54
+#define STA350_TW_POSTSCALE	55
+#define STA350_C1_MIX1		56
+#define STA350_C1_MIX2		57
+#define STA350_C2_MIX1		58
+#define STA350_C2_MIX2		59
+#define STA350_C3_MIX1		60
+#define STA350_C3_MIX2		61
+
+/* miscellaneous register 1 */
+#define STA350_MISC1_CPWMEN	BIT(2)
+#define STA350_MISC1_BRIDGOFF	BIT(5)
+#define STA350_MISC1_NSHHPEN	BIT(6)
+#define STA350_MISC1_RPDNEN	BIT(7)
+
+/* miscellaneous register 2 */
+#define STA350_MISC2_PNDLSL_MASK	0x1c
+#define STA350_MISC2_PNDLSL_SHIFT	2
+
+#endif /* _ASOC_STA_350_H */
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
new file mode 100644
index 0000000..2881a0f
--- /dev/null
+++ b/sound/soc/codecs/sta529.c
@@ -0,0 +1,391 @@
+/*
+ * ASoC codec driver for spear platform
+ *
+ * sound/soc/codecs/sta529.c -- spear ALSA Soc codec driver
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Rajeev Kumar <rajeevkumar.linux@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+/* STA529 Register offsets */
+#define	 STA529_FFXCFG0		0x00
+#define	 STA529_FFXCFG1		0x01
+#define	 STA529_MVOL		0x02
+#define	 STA529_LVOL		0x03
+#define	 STA529_RVOL		0x04
+#define	 STA529_TTF0		0x05
+#define	 STA529_TTF1		0x06
+#define	 STA529_TTP0		0x07
+#define	 STA529_TTP1		0x08
+#define	 STA529_S2PCFG0		0x0A
+#define	 STA529_S2PCFG1		0x0B
+#define	 STA529_P2SCFG0		0x0C
+#define	 STA529_P2SCFG1		0x0D
+#define	 STA529_PLLCFG0		0x14
+#define	 STA529_PLLCFG1		0x15
+#define	 STA529_PLLCFG2		0x16
+#define	 STA529_PLLCFG3		0x17
+#define	 STA529_PLLPFE		0x18
+#define	 STA529_PLLST		0x19
+#define	 STA529_ADCCFG		0x1E /*mic_select*/
+#define	 STA529_CKOCFG		0x1F
+#define	 STA529_MISC		0x20
+#define	 STA529_PADST0		0x21
+#define	 STA529_PADST1		0x22
+#define	 STA529_FFXST		0x23
+#define	 STA529_PWMIN1		0x2D
+#define	 STA529_PWMIN2		0x2E
+#define	 STA529_POWST		0x32
+
+#define STA529_MAX_REGISTER	0x32
+
+#define STA529_RATES		(SNDRV_PCM_RATE_8000 | \
+				SNDRV_PCM_RATE_11025 | \
+				SNDRV_PCM_RATE_16000 | \
+				SNDRV_PCM_RATE_22050 | \
+				SNDRV_PCM_RATE_32000 | \
+				SNDRV_PCM_RATE_44100 | \
+				SNDRV_PCM_RATE_48000)
+
+#define STA529_FORMAT		(SNDRV_PCM_FMTBIT_S16_LE | \
+				SNDRV_PCM_FMTBIT_S24_LE | \
+				SNDRV_PCM_FMTBIT_S32_LE)
+#define	S2PC_VALUE		0x98
+#define CLOCK_OUT		0x60
+#define DATA_FORMAT_MSK		0x0E
+#define LEFT_J_DATA_FORMAT	0x00
+#define I2S_DATA_FORMAT		0x02
+#define RIGHT_J_DATA_FORMAT	0x04
+#define CODEC_MUTE_VAL		0x80
+
+#define POWER_CNTLMSAK		0x40
+#define POWER_STDBY		0x40
+#define FFX_MASK		0x80
+#define FFX_OFF			0x80
+#define POWER_UP		0x00
+#define FFX_CLK_ENB		0x01
+#define FFX_CLK_DIS		0x00
+#define FFX_CLK_MSK		0x01
+#define PLAY_FREQ_RANGE_MSK	0x70
+#define CAP_FREQ_RANGE_MSK	0x0C
+#define PDATA_LEN_MSK		0xC0
+#define BCLK_TO_FS_MSK		0x30
+#define AUDIO_MUTE_MSK		0x80
+
+static const struct reg_default sta529_reg_defaults[] = {
+	{ 0,  0x35 },     /* R0   - FFX Configuration reg 0 */
+	{ 1,  0xc8 },     /* R1   - FFX Configuration reg 1 */
+	{ 2,  0x50 },     /* R2   - Master Volume */
+	{ 3,  0x00 },     /* R3   - Left Volume */
+	{ 4,  0x00 },     /* R4  -  Right Volume */
+	{ 10, 0xb2 },     /* R10  - S2P Config Reg 0 */
+	{ 11, 0x41 },     /* R11  - S2P Config Reg 1 */
+	{ 12, 0x92 },     /* R12  - P2S Config Reg 0 */
+	{ 13, 0x41 },     /* R13  - P2S Config Reg 1 */
+	{ 30, 0xd2 },     /* R30  - ADC Config Reg */
+	{ 31, 0x40 },     /* R31  - clock Out Reg */
+	{ 32, 0x21 },     /* R32  - Misc Register */
+};
+
+struct sta529 {
+	struct regmap *regmap;
+};
+
+static bool sta529_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+
+	case STA529_FFXCFG0:
+	case STA529_FFXCFG1:
+	case STA529_MVOL:
+	case STA529_LVOL:
+	case STA529_RVOL:
+	case STA529_S2PCFG0:
+	case STA529_S2PCFG1:
+	case STA529_P2SCFG0:
+	case STA529_P2SCFG1:
+	case STA529_ADCCFG:
+	case STA529_CKOCFG:
+	case STA529_MISC:
+		return true;
+	default:
+		return false;
+	}
+}
+
+
+static const char *pwm_mode_text[] = { "Binary", "Headphone", "Ternary",
+	"Phase-shift"};
+
+static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -9150, 50, 0);
+static const DECLARE_TLV_DB_SCALE(master_vol_tlv, -12750, 50, 0);
+static SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text);
+
+static const struct snd_kcontrol_new sta529_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("Digital Playback Volume", STA529_LVOL, STA529_RVOL, 0,
+			127, 0, out_gain_tlv),
+	SOC_SINGLE_TLV("Master Playback Volume", STA529_MVOL, 0, 127, 1,
+			master_vol_tlv),
+	SOC_ENUM("PWM Select", pwm_src),
+};
+
+static int sta529_set_bias_level(struct snd_soc_component *component, enum
+		snd_soc_bias_level level)
+{
+	struct sta529 *sta529 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		snd_soc_component_update_bits(component, STA529_FFXCFG0, POWER_CNTLMSAK,
+				POWER_UP);
+		snd_soc_component_update_bits(component, STA529_MISC,	FFX_CLK_MSK,
+				FFX_CLK_ENB);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			regcache_sync(sta529->regmap);
+		snd_soc_component_update_bits(component, STA529_FFXCFG0,
+					POWER_CNTLMSAK, POWER_STDBY);
+		/* Making FFX output to zero */
+		snd_soc_component_update_bits(component, STA529_FFXCFG0, FFX_MASK,
+				FFX_OFF);
+		snd_soc_component_update_bits(component, STA529_MISC, FFX_CLK_MSK,
+				FFX_CLK_DIS);
+		break;
+	case SND_SOC_BIAS_OFF:
+		break;
+	}
+
+	return 0;
+
+}
+
+static int sta529_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	int pdata, play_freq_val, record_freq_val;
+	int bclk_to_fs_ratio;
+
+	switch (params_width(params)) {
+	case 16:
+		pdata = 1;
+		bclk_to_fs_ratio = 0;
+		break;
+	case 24:
+		pdata = 2;
+		bclk_to_fs_ratio = 1;
+		break;
+	case 32:
+		pdata = 3;
+		bclk_to_fs_ratio = 2;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported format\n");
+		return -EINVAL;
+	}
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 11025:
+		play_freq_val = 0;
+		record_freq_val = 2;
+		break;
+	case 16000:
+	case 22050:
+		play_freq_val = 1;
+		record_freq_val = 0;
+		break;
+
+	case 32000:
+	case 44100:
+	case 48000:
+		play_freq_val = 2;
+		record_freq_val = 0;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported rate\n");
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		snd_soc_component_update_bits(component, STA529_S2PCFG1, PDATA_LEN_MSK,
+				pdata << 6);
+		snd_soc_component_update_bits(component, STA529_S2PCFG1, BCLK_TO_FS_MSK,
+				bclk_to_fs_ratio << 4);
+		snd_soc_component_update_bits(component, STA529_MISC, PLAY_FREQ_RANGE_MSK,
+				play_freq_val << 4);
+	} else {
+		snd_soc_component_update_bits(component, STA529_P2SCFG1, PDATA_LEN_MSK,
+				pdata << 6);
+		snd_soc_component_update_bits(component, STA529_P2SCFG1, BCLK_TO_FS_MSK,
+				bclk_to_fs_ratio << 4);
+		snd_soc_component_update_bits(component, STA529_MISC, CAP_FREQ_RANGE_MSK,
+				record_freq_val << 2);
+	}
+
+	return 0;
+}
+
+static int sta529_mute(struct snd_soc_dai *dai, int mute)
+{
+	u8 val = 0;
+
+	if (mute)
+		val |= CODEC_MUTE_VAL;
+
+	snd_soc_component_update_bits(dai->component, STA529_FFXCFG0, AUDIO_MUTE_MSK, val);
+
+	return 0;
+}
+
+static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u8 mode = 0;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_LEFT_J:
+		mode = LEFT_J_DATA_FORMAT;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		mode = I2S_DATA_FORMAT;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		mode = RIGHT_J_DATA_FORMAT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, STA529_S2PCFG0, DATA_FORMAT_MSK, mode);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops sta529_dai_ops = {
+	.hw_params	=	sta529_hw_params,
+	.set_fmt	=	sta529_set_dai_fmt,
+	.digital_mute	=	sta529_mute,
+};
+
+static struct snd_soc_dai_driver sta529_dai = {
+	.name = "sta529-audio",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = STA529_RATES,
+		.formats = STA529_FORMAT,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = STA529_RATES,
+		.formats = STA529_FORMAT,
+	},
+	.ops	= &sta529_dai_ops,
+};
+
+static const struct snd_soc_component_driver sta529_component_driver = {
+	.set_bias_level		= sta529_set_bias_level,
+	.controls		= sta529_snd_controls,
+	.num_controls		= ARRAY_SIZE(sta529_snd_controls),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config sta529_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = STA529_MAX_REGISTER,
+	.readable_reg = sta529_readable,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = sta529_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(sta529_reg_defaults),
+};
+
+static int sta529_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct sta529 *sta529;
+	int ret;
+
+	sta529 = devm_kzalloc(&i2c->dev, sizeof(struct sta529), GFP_KERNEL);
+	if (!sta529)
+		return -ENOMEM;
+
+	sta529->regmap = devm_regmap_init_i2c(i2c, &sta529_regmap);
+	if (IS_ERR(sta529->regmap)) {
+		ret = PTR_ERR(sta529->regmap);
+		dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, sta529);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&sta529_component_driver, &sta529_dai, 1);
+	if (ret != 0)
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+
+	return ret;
+}
+
+static const struct i2c_device_id sta529_i2c_id[] = {
+	{ "sta529", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, sta529_i2c_id);
+
+static const struct of_device_id sta529_of_match[] = {
+	{ .compatible = "st,sta529", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sta529_of_match);
+
+static struct i2c_driver sta529_i2c_driver = {
+	.driver = {
+		.name = "sta529",
+		.of_match_table = sta529_of_match,
+	},
+	.probe		= sta529_i2c_probe,
+	.id_table	= sta529_i2c_id,
+};
+
+module_i2c_driver(sta529_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC STA529 codec driver");
+MODULE_AUTHOR("Rajeev Kumar <rajeevkumar.linux@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
new file mode 100644
index 0000000..f62101a
--- /dev/null
+++ b/sound/soc/codecs/stac9766.c
@@ -0,0 +1,342 @@
+/*
+ * stac9766.c  --  ALSA SoC STAC9766 codec support
+ *
+ * Copyright 2009 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@gmail.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Features:-
+ *
+ *   o Support for AC97 Codec, S/PDIF
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#define STAC9766_VENDOR_ID 0x83847666
+#define STAC9766_VENDOR_ID_MASK 0xffffffff
+
+#define AC97_STAC_DA_CONTROL 0x6A
+#define AC97_STAC_ANALOG_SPECIAL 0x6E
+#define AC97_STAC_STEREO_MIC 0x78
+
+static const struct reg_default stac9766_reg_defaults[] = {
+	{ 0x02, 0x8000 },
+	{ 0x04, 0x8000 },
+	{ 0x06, 0x8000 },
+	{ 0x0a, 0x0000 },
+	{ 0x0c, 0x8008 },
+	{ 0x0e, 0x8008 },
+	{ 0x10, 0x8808 },
+	{ 0x12, 0x8808 },
+	{ 0x14, 0x8808 },
+	{ 0x16, 0x8808 },
+	{ 0x18, 0x8808 },
+	{ 0x1a, 0x0000 },
+	{ 0x1c, 0x8000 },
+	{ 0x20, 0x0000 },
+	{ 0x22, 0x0000 },
+	{ 0x28, 0x0a05 },
+	{ 0x2c, 0xbb80 },
+	{ 0x32, 0xbb80 },
+	{ 0x3a, 0x2000 },
+	{ 0x3e, 0x0100 },
+	{ 0x4c, 0x0300 },
+	{ 0x4e, 0xffff },
+	{ 0x50, 0x0000 },
+	{ 0x52, 0x0000 },
+	{ 0x54, 0x0000 },
+	{ 0x6a, 0x0000 },
+	{ 0x6e, 0x1000 },
+	{ 0x72, 0x0000 },
+	{ 0x78, 0x0000 },
+};
+
+static const struct regmap_config stac9766_regmap_config = {
+	.reg_bits = 16,
+	.reg_stride = 2,
+	.val_bits = 16,
+	.max_register = 0x78,
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = regmap_ac97_default_volatile,
+
+	.reg_defaults = stac9766_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(stac9766_reg_defaults),
+};
+
+static const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX",
+			"Line", "Stereo Mix", "Mono Mix", "Phone"};
+static const char *stac9766_mono_mux[] = {"Mix", "Mic"};
+static const char *stac9766_mic_mux[] = {"Mic1", "Mic2"};
+static const char *stac9766_SPDIF_mux[] = {"PCM", "ADC Record"};
+static const char *stac9766_popbypass_mux[] = {"Normal", "Bypass Mixer"};
+static const char *stac9766_record_all_mux[] = {"All analog",
+	"Analog plus DAC"};
+static const char *stac9766_boost1[] = {"0dB", "10dB"};
+static const char *stac9766_boost2[] = {"0dB", "20dB"};
+static const char *stac9766_stereo_mic[] = {"Off", "On"};
+
+static SOC_ENUM_DOUBLE_DECL(stac9766_record_enum,
+			    AC97_REC_SEL, 8, 0, stac9766_record_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_mono_enum,
+			    AC97_GENERAL_PURPOSE, 9, stac9766_mono_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_mic_enum,
+			    AC97_GENERAL_PURPOSE, 8, stac9766_mic_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_SPDIF_enum,
+			    AC97_STAC_DA_CONTROL, 1, stac9766_SPDIF_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_popbypass_enum,
+			    AC97_GENERAL_PURPOSE, 15, stac9766_popbypass_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_record_all_enum,
+			    AC97_STAC_ANALOG_SPECIAL, 12,
+			    stac9766_record_all_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_boost1_enum,
+			    AC97_MIC, 6, stac9766_boost1); /* 0/10dB */
+static SOC_ENUM_SINGLE_DECL(stac9766_boost2_enum,
+			    AC97_STAC_ANALOG_SPECIAL, 2, stac9766_boost2); /* 0/20dB */
+static SOC_ENUM_SINGLE_DECL(stac9766_stereo_mic_enum,
+			    AC97_STAC_STEREO_MIC, 2, stac9766_stereo_mic);
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(master_tlv, -4650, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(record_tlv,     0, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(beep_tlv,   -4500, 300, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(mix_tlv,    -3450, 150, 0);
+
+static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = {
+	SOC_DOUBLE_TLV("Speaker Volume", AC97_MASTER, 8, 0, 31, 1, master_tlv),
+	SOC_SINGLE("Speaker Switch", AC97_MASTER, 15, 1, 1),
+	SOC_DOUBLE_TLV("Headphone Volume", AC97_HEADPHONE, 8, 0, 31, 1,
+		       master_tlv),
+	SOC_SINGLE("Headphone Switch", AC97_HEADPHONE, 15, 1, 1),
+	SOC_SINGLE_TLV("Mono Out Volume", AC97_MASTER_MONO, 0, 31, 1,
+		       master_tlv),
+	SOC_SINGLE("Mono Out Switch", AC97_MASTER_MONO, 15, 1, 1),
+
+	SOC_DOUBLE_TLV("Record Volume", AC97_REC_GAIN, 8, 0, 15, 0, record_tlv),
+	SOC_SINGLE("Record Switch", AC97_REC_GAIN, 15, 1, 1),
+
+
+	SOC_SINGLE_TLV("Beep Volume", AC97_PC_BEEP, 1, 15, 1, beep_tlv),
+	SOC_SINGLE("Beep Switch", AC97_PC_BEEP, 15, 1, 1),
+	SOC_SINGLE("Beep Frequency", AC97_PC_BEEP, 5, 127, 1),
+	SOC_SINGLE_TLV("Phone Volume", AC97_PHONE, 0, 31, 1, mix_tlv),
+	SOC_SINGLE("Phone Switch", AC97_PHONE, 15, 1, 1),
+
+	SOC_ENUM("Mic Boost1", stac9766_boost1_enum),
+	SOC_ENUM("Mic Boost2", stac9766_boost2_enum),
+	SOC_SINGLE_TLV("Mic Volume", AC97_MIC, 0, 31, 1, mix_tlv),
+	SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1),
+	SOC_ENUM("Stereo Mic", stac9766_stereo_mic_enum),
+
+	SOC_DOUBLE_TLV("Line Volume", AC97_LINE, 8, 0, 31, 1, mix_tlv),
+	SOC_SINGLE("Line Switch", AC97_LINE, 15, 1, 1),
+	SOC_DOUBLE_TLV("CD Volume", AC97_CD, 8, 0, 31, 1, mix_tlv),
+	SOC_SINGLE("CD Switch", AC97_CD, 15, 1, 1),
+	SOC_DOUBLE_TLV("AUX Volume", AC97_AUX, 8, 0, 31, 1, mix_tlv),
+	SOC_SINGLE("AUX Switch", AC97_AUX, 15, 1, 1),
+	SOC_DOUBLE_TLV("Video Volume", AC97_VIDEO, 8, 0, 31, 1, mix_tlv),
+	SOC_SINGLE("Video Switch", AC97_VIDEO, 15, 1, 1),
+
+	SOC_DOUBLE_TLV("DAC Volume", AC97_PCM, 8, 0, 31, 1, mix_tlv),
+	SOC_SINGLE("DAC Switch", AC97_PCM, 15, 1, 1),
+	SOC_SINGLE("Loopback Test Switch", AC97_GENERAL_PURPOSE, 7, 1, 0),
+	SOC_SINGLE("3D Volume", AC97_3D_CONTROL, 3, 2, 1),
+	SOC_SINGLE("3D Switch", AC97_GENERAL_PURPOSE, 13, 1, 0),
+
+	SOC_ENUM("SPDIF Mux", stac9766_SPDIF_enum),
+	SOC_ENUM("Mic1/2 Mux", stac9766_mic_enum),
+	SOC_ENUM("Record All Mux", stac9766_record_all_enum),
+	SOC_ENUM("Record Mux", stac9766_record_enum),
+	SOC_ENUM("Mono Mux", stac9766_mono_enum),
+	SOC_ENUM("Pop Bypass Mux", stac9766_popbypass_enum),
+};
+
+static int ac97_analog_prepare(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned short reg;
+
+	/* enable variable rate audio, disable SPDIF output */
+	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x5, 0x1);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		reg = AC97_PCM_FRONT_DAC_RATE;
+	else
+		reg = AC97_PCM_LR_ADC_RATE;
+
+	return snd_soc_component_write(component, reg, runtime->rate);
+}
+
+static int ac97_digital_prepare(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned short reg;
+
+	snd_soc_component_write(component, AC97_SPDIF, 0x2002);
+
+	/* Enable VRA and SPDIF out */
+	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x5, 0x5);
+
+	reg = AC97_PCM_FRONT_DAC_RATE;
+
+	return snd_soc_component_write(component, reg, runtime->rate);
+}
+
+static int stac9766_set_bias_level(struct snd_soc_component *component,
+				   enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON: /* full On */
+	case SND_SOC_BIAS_PREPARE: /* partial On */
+	case SND_SOC_BIAS_STANDBY: /* Off, with power */
+		snd_soc_component_write(component, AC97_POWERDOWN, 0x0000);
+		break;
+	case SND_SOC_BIAS_OFF: /* Off, without power */
+		/* disable everything including AC link */
+		snd_soc_component_write(component, AC97_POWERDOWN, 0xffff);
+		break;
+	}
+	return 0;
+}
+
+static int stac9766_component_resume(struct snd_soc_component *component)
+{
+	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
+
+	return snd_ac97_reset(ac97, true, STAC9766_VENDOR_ID,
+		STAC9766_VENDOR_ID_MASK);
+}
+
+static const struct snd_soc_dai_ops stac9766_dai_ops_analog = {
+	.prepare = ac97_analog_prepare,
+};
+
+static const struct snd_soc_dai_ops stac9766_dai_ops_digital = {
+	.prepare = ac97_digital_prepare,
+};
+
+static struct snd_soc_dai_driver stac9766_dai[] = {
+{
+	.name = "stac9766-hifi-analog",
+
+	/* stream cababilities */
+	.playback = {
+		.stream_name = "stac9766 analog",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SND_SOC_STD_AC97_FMTS,
+	},
+	.capture = {
+		.stream_name = "stac9766 analog",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SND_SOC_STD_AC97_FMTS,
+	},
+	/* alsa ops */
+	.ops = &stac9766_dai_ops_analog,
+},
+{
+	.name = "stac9766-hifi-IEC958",
+
+	/* stream cababilities */
+	.playback = {
+		.stream_name = "stac9766 IEC958",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_32000 | \
+			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE,
+	},
+	/* alsa ops */
+	.ops = &stac9766_dai_ops_digital,
+}
+};
+
+static int stac9766_component_probe(struct snd_soc_component *component)
+{
+	struct snd_ac97 *ac97;
+	struct regmap *regmap;
+	int ret;
+
+	ac97 = snd_soc_new_ac97_component(component, STAC9766_VENDOR_ID,
+			STAC9766_VENDOR_ID_MASK);
+	if (IS_ERR(ac97))
+		return PTR_ERR(ac97);
+
+	regmap = regmap_init_ac97(ac97, &stac9766_regmap_config);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		goto err_free_ac97;
+	}
+
+	snd_soc_component_init_regmap(component, regmap);
+	snd_soc_component_set_drvdata(component, ac97);
+
+	return 0;
+err_free_ac97:
+	snd_soc_free_ac97_component(ac97);
+	return ret;
+}
+
+static void stac9766_component_remove(struct snd_soc_component *component)
+{
+	struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_exit_regmap(component);
+	snd_soc_free_ac97_component(ac97);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_stac9766 = {
+	.controls		= stac9766_snd_ac97_controls,
+	.num_controls		= ARRAY_SIZE(stac9766_snd_ac97_controls),
+	.set_bias_level		= stac9766_set_bias_level,
+	.probe			= stac9766_component_probe,
+	.remove			= stac9766_component_remove,
+	.resume			= stac9766_component_resume,
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+
+};
+
+static int stac9766_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_stac9766, stac9766_dai, ARRAY_SIZE(stac9766_dai));
+}
+
+static struct platform_driver stac9766_codec_driver = {
+	.driver = {
+			.name = "stac9766-codec",
+	},
+
+	.probe = stac9766_probe,
+};
+
+module_platform_driver(stac9766_codec_driver);
+
+MODULE_DESCRIPTION("ASoC stac9766 driver");
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c
new file mode 100644
index 0000000..7316c80
--- /dev/null
+++ b/sound/soc/codecs/sti-sas.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
+ *          for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/mfd/syscon.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+/* DAC definitions */
+
+/* stih407 DAC registers */
+/* sysconf 5041: Audio-Gue-Control */
+#define STIH407_AUDIO_GLUE_CTRL 0x000000A4
+/* sysconf 5042: Audio-DAC-Control */
+#define STIH407_AUDIO_DAC_CTRL 0x000000A8
+
+/* DAC definitions */
+#define STIH407_DAC_SOFTMUTE		0x0
+#define STIH407_DAC_STANDBY_ANA		0x1
+#define STIH407_DAC_STANDBY		0x2
+
+#define STIH407_DAC_SOFTMUTE_MASK	BIT(STIH407_DAC_SOFTMUTE)
+#define STIH407_DAC_STANDBY_ANA_MASK    BIT(STIH407_DAC_STANDBY_ANA)
+#define STIH407_DAC_STANDBY_MASK        BIT(STIH407_DAC_STANDBY)
+
+/* SPDIF definitions */
+#define SPDIF_BIPHASE_ENABLE		0x6
+#define SPDIF_BIPHASE_IDLE		0x7
+
+#define SPDIF_BIPHASE_ENABLE_MASK	BIT(SPDIF_BIPHASE_ENABLE)
+#define SPDIF_BIPHASE_IDLE_MASK		BIT(SPDIF_BIPHASE_IDLE)
+
+enum {
+	STI_SAS_DAI_SPDIF_OUT,
+	STI_SAS_DAI_ANALOG_OUT,
+};
+
+static const struct reg_default stih407_sas_reg_defaults[] = {
+	{ STIH407_AUDIO_DAC_CTRL, 0x000000000 },
+	{ STIH407_AUDIO_GLUE_CTRL, 0x00000040 },
+};
+
+struct sti_dac_audio {
+	struct regmap *regmap;
+	struct regmap *virt_regmap;
+	struct regmap_field  **field;
+	struct reset_control *rst;
+	int mclk;
+};
+
+struct sti_spdif_audio {
+	struct regmap *regmap;
+	struct regmap_field  **field;
+	int mclk;
+};
+
+/* device data structure */
+struct sti_sas_dev_data {
+	const struct regmap_config *regmap;
+	const struct snd_soc_dai_ops *dac_ops;  /* DAC function callbacks */
+	const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */
+	const int num_dapm_widgets; /* dapms declaration */
+	const struct snd_soc_dapm_route *dapm_routes; /* route declaration */
+	const int num_dapm_routes; /* route declaration */
+};
+
+/* driver data structure */
+struct sti_sas_data {
+	struct device *dev;
+	const struct sti_sas_dev_data *dev_data;
+	struct sti_dac_audio dac;
+	struct sti_spdif_audio spdif;
+};
+
+/* Read a register from the sysconf reg bank */
+static int sti_sas_read_reg(void *context, unsigned int reg,
+			    unsigned int *value)
+{
+	struct sti_sas_data *drvdata = context;
+	int status;
+	u32 val;
+
+	status = regmap_read(drvdata->dac.regmap, reg, &val);
+	*value = (unsigned int)val;
+
+	return status;
+}
+
+/* Read a register from the sysconf reg bank */
+static int sti_sas_write_reg(void *context, unsigned int reg,
+			     unsigned int value)
+{
+	struct sti_sas_data *drvdata = context;
+	int status;
+
+	status = regmap_write(drvdata->dac.regmap, reg, value);
+
+	return status;
+}
+
+static int  sti_sas_init_sas_registers(struct snd_soc_component *component,
+				       struct sti_sas_data *data)
+{
+	int ret;
+	/*
+	 * DAC and SPDIF are activated by default
+	 * put them in IDLE to save power
+	 */
+
+	/* Initialise bi-phase formatter to disabled */
+	ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
+				  SPDIF_BIPHASE_ENABLE_MASK, 0);
+
+	if (!ret)
+		/* Initialise bi-phase formatter idle value to 0 */
+		ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
+					  SPDIF_BIPHASE_IDLE_MASK, 0);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to update SPDIF registers\n");
+		return ret;
+	}
+
+	/* Init DAC configuration */
+	/* init configuration */
+	ret =  snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
+				   STIH407_DAC_STANDBY_MASK,
+				   STIH407_DAC_STANDBY_MASK);
+
+	if (!ret)
+		ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
+					  STIH407_DAC_STANDBY_ANA_MASK,
+					  STIH407_DAC_STANDBY_ANA_MASK);
+	if (!ret)
+		ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
+					  STIH407_DAC_SOFTMUTE_MASK,
+					  STIH407_DAC_SOFTMUTE_MASK);
+
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to update DAC registers\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+/*
+ * DAC
+ */
+static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	/* Sanity check only */
+	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+		dev_err(dai->component->dev,
+			"%s: ERROR: Unsupporter master mask 0x%x\n",
+			__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = {
+	SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL,
+			     STIH407_DAC_STANDBY_ANA, 1, NULL, 0),
+	SND_SOC_DAPM_DAC("DAC standby",  "dac_p", STIH407_AUDIO_DAC_CTRL,
+			 STIH407_DAC_STANDBY, 1),
+	SND_SOC_DAPM_OUTPUT("DAC Output"),
+};
+
+static const struct snd_soc_dapm_route stih407_sas_route[] = {
+	{"DAC Output", NULL, "DAC standby ana"},
+	{"DAC standby ana", NULL, "DAC standby"},
+};
+
+
+static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute) {
+		return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
+					    STIH407_DAC_SOFTMUTE_MASK,
+					    STIH407_DAC_SOFTMUTE_MASK);
+	} else {
+		return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
+					    STIH407_DAC_SOFTMUTE_MASK,
+					    0);
+	}
+}
+
+/*
+ * SPDIF
+ */
+static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
+				 unsigned int fmt)
+{
+	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+		dev_err(dai->component->dev,
+			"%s: ERROR: Unsupporter master mask 0x%x\n",
+			__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * sti_sas_spdif_trigger:
+ * Trigger function is used to ensure that BiPhase Formater is disabled
+ * before CPU dai is stopped.
+ * This is mandatory to avoid that BPF is stalled
+ */
+static int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
+					    SPDIF_BIPHASE_ENABLE_MASK,
+					    SPDIF_BIPHASE_ENABLE_MASK);
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
+					    SPDIF_BIPHASE_ENABLE_MASK,
+					    0);
+	default:
+		return -EINVAL;
+	}
+}
+
+static bool sti_sas_volatile_register(struct device *dev, unsigned int reg)
+{
+	if (reg == STIH407_AUDIO_GLUE_CTRL)
+		return true;
+
+	return false;
+}
+
+/*
+ * CODEC DAIS
+ */
+
+/*
+ * sti_sas_set_sysclk:
+ * get MCLK input frequency to check that MCLK-FS ratio is coherent
+ */
+static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+			      unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
+
+	if (dir == SND_SOC_CLOCK_OUT)
+		return 0;
+
+	if (clk_id != 0)
+		return -EINVAL;
+
+	switch (dai->id) {
+	case STI_SAS_DAI_SPDIF_OUT:
+		drvdata->spdif.mclk = freq;
+		break;
+
+	case STI_SAS_DAI_ANALOG_OUT:
+		drvdata->dac.mclk = freq;
+		break;
+	}
+
+	return 0;
+}
+
+static int sti_sas_prepare(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	switch (dai->id) {
+	case STI_SAS_DAI_SPDIF_OUT:
+		if ((drvdata->spdif.mclk / runtime->rate) != 128) {
+			dev_err(component->dev, "unexpected mclk-fs ratio\n");
+			return -EINVAL;
+		}
+		break;
+	case STI_SAS_DAI_ANALOG_OUT:
+		if ((drvdata->dac.mclk / runtime->rate) != 256) {
+			dev_err(component->dev, "unexpected mclk-fs ratio\n");
+			return -EINVAL;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops stih407_dac_ops = {
+	.set_fmt = sti_sas_dac_set_fmt,
+	.mute_stream = stih407_sas_dac_mute,
+	.prepare = sti_sas_prepare,
+	.set_sysclk = sti_sas_set_sysclk,
+};
+
+static const struct regmap_config stih407_sas_regmap = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.fast_io = true,
+	.max_register = STIH407_AUDIO_DAC_CTRL,
+	.reg_defaults = stih407_sas_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults),
+	.volatile_reg = sti_sas_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_read = sti_sas_read_reg,
+	.reg_write = sti_sas_write_reg,
+};
+
+static const struct sti_sas_dev_data stih407_data = {
+	.regmap = &stih407_sas_regmap,
+	.dac_ops = &stih407_dac_ops,
+	.dapm_widgets = stih407_sas_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets),
+	.dapm_routes =	stih407_sas_route,
+	.num_dapm_routes = ARRAY_SIZE(stih407_sas_route),
+};
+
+static struct snd_soc_dai_driver sti_sas_dai[] = {
+	{
+		.name = "sas-dai-spdif-out",
+		.id = STI_SAS_DAI_SPDIF_OUT,
+		.playback = {
+			.stream_name = "spdif_p",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 |
+				 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+				 SNDRV_PCM_RATE_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = (struct snd_soc_dai_ops[]) {
+			{
+				.set_fmt = sti_sas_spdif_set_fmt,
+				.trigger = sti_sas_spdif_trigger,
+				.set_sysclk = sti_sas_set_sysclk,
+				.prepare = sti_sas_prepare,
+			}
+		},
+	},
+	{
+		.name = "sas-dai-dac",
+		.id = STI_SAS_DAI_ANALOG_OUT,
+		.playback = {
+			.stream_name = "dac_p",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+	},
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int sti_sas_resume(struct snd_soc_component *component)
+{
+	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
+
+	return sti_sas_init_sas_registers(component, drvdata);
+}
+#else
+#define sti_sas_resume NULL
+#endif
+
+static int sti_sas_component_probe(struct snd_soc_component *component)
+{
+	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
+	int ret;
+
+	ret = sti_sas_init_sas_registers(component, drvdata);
+
+	return ret;
+}
+
+static struct snd_soc_component_driver sti_sas_driver = {
+	.probe			= sti_sas_component_probe,
+	.resume			= sti_sas_resume,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct of_device_id sti_sas_dev_match[] = {
+	{
+		.compatible = "st,stih407-sas-codec",
+		.data = &stih407_data,
+	},
+	{},
+};
+
+static int sti_sas_driver_probe(struct platform_device *pdev)
+{
+	struct device_node *pnode = pdev->dev.of_node;
+	struct sti_sas_data *drvdata;
+	const struct of_device_id *of_id;
+
+	/* Allocate device structure */
+	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data),
+			       GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	/* Populate data structure depending on compatibility */
+	of_id = of_match_node(sti_sas_dev_match, pnode);
+	if (!of_id->data) {
+		dev_err(&pdev->dev, "data associated to device is missing\n");
+		return -EINVAL;
+	}
+
+	drvdata->dev_data = (struct sti_sas_dev_data *)of_id->data;
+
+	/* Initialise device structure */
+	drvdata->dev = &pdev->dev;
+
+	/* Request the DAC & SPDIF registers memory region */
+	drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata,
+						    drvdata->dev_data->regmap);
+	if (IS_ERR(drvdata->dac.virt_regmap)) {
+		dev_err(&pdev->dev, "audio registers not enabled\n");
+		return PTR_ERR(drvdata->dac.virt_regmap);
+	}
+
+	/* Request the syscon region */
+	drvdata->dac.regmap =
+		syscon_regmap_lookup_by_phandle(pnode, "st,syscfg");
+	if (IS_ERR(drvdata->dac.regmap)) {
+		dev_err(&pdev->dev, "syscon registers not available\n");
+		return PTR_ERR(drvdata->dac.regmap);
+	}
+	drvdata->spdif.regmap = drvdata->dac.regmap;
+
+	sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;
+
+	/* Set dapms*/
+	sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
+	sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
+
+	sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes;
+	sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
+
+	/* Store context */
+	dev_set_drvdata(&pdev->dev, drvdata);
+
+	return devm_snd_soc_register_component(&pdev->dev, &sti_sas_driver,
+					sti_sas_dai,
+					ARRAY_SIZE(sti_sas_dai));
+}
+
+static struct platform_driver sti_sas_platform_driver = {
+	.driver = {
+		.name = "sti-sas-codec",
+		.of_match_table = sti_sas_dev_match,
+	},
+	.probe = sti_sas_driver_probe,
+};
+
+module_platform_driver(sti_sas_platform_driver);
+
+MODULE_DESCRIPTION("audio codec for STMicroelectronics sti platforms");
+MODULE_AUTHOR("Arnaud.pouliquen@st.com");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
new file mode 100644
index 0000000..355ecaf
--- /dev/null
+++ b/sound/soc/codecs/tas2552.c
@@ -0,0 +1,780 @@
+/*
+ * tas2552.c - ALSA SoC Texas Instruments TAS2552 Mono Audio Amplifier
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated -  http://www.ti.com
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/tas2552-plat.h>
+#include <dt-bindings/sound/tas2552.h>
+
+#include "tas2552.h"
+
+static const struct reg_default tas2552_reg_defs[] = {
+	{TAS2552_CFG_1, 0x22},
+	{TAS2552_CFG_3, 0x80},
+	{TAS2552_DOUT, 0x00},
+	{TAS2552_OUTPUT_DATA, 0xc0},
+	{TAS2552_PDM_CFG, 0x01},
+	{TAS2552_PGA_GAIN, 0x00},
+	{TAS2552_BOOST_APT_CTRL, 0x0f},
+	{TAS2552_RESERVED_0D, 0xbe},
+	{TAS2552_LIMIT_RATE_HYS, 0x08},
+	{TAS2552_CFG_2, 0xef},
+	{TAS2552_SER_CTRL_1, 0x00},
+	{TAS2552_SER_CTRL_2, 0x00},
+	{TAS2552_PLL_CTRL_1, 0x10},
+	{TAS2552_PLL_CTRL_2, 0x00},
+	{TAS2552_PLL_CTRL_3, 0x00},
+	{TAS2552_BTIP, 0x8f},
+	{TAS2552_BTS_CTRL, 0x80},
+	{TAS2552_LIMIT_RELEASE, 0x04},
+	{TAS2552_LIMIT_INT_COUNT, 0x00},
+	{TAS2552_EDGE_RATE_CTRL, 0x40},
+	{TAS2552_VBAT_DATA, 0x00},
+};
+
+#define TAS2552_NUM_SUPPLIES	3
+static const char *tas2552_supply_names[TAS2552_NUM_SUPPLIES] = {
+	"vbat",		/* vbat voltage */
+	"iovdd",	/* I/O Voltage */
+	"avdd",		/* Analog DAC Voltage */
+};
+
+struct tas2552_data {
+	struct snd_soc_component *component;
+	struct regmap *regmap;
+	struct i2c_client *tas2552_client;
+	struct regulator_bulk_data supplies[TAS2552_NUM_SUPPLIES];
+	struct gpio_desc *enable_gpio;
+	unsigned char regs[TAS2552_VBAT_DATA];
+	unsigned int pll_clkin;
+	int pll_clk_id;
+	unsigned int pdm_clk;
+	int pdm_clk_id;
+
+	unsigned int dai_fmt;
+	unsigned int tdm_delay;
+};
+
+static int tas2552_post_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_write(component, TAS2552_RESERVED_0D, 0xc0);
+		snd_soc_component_update_bits(component, TAS2552_LIMIT_RATE_HYS, (1 << 5),
+				    (1 << 5));
+		snd_soc_component_update_bits(component, TAS2552_CFG_2, 1, 0);
+		snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_SWS, 0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_SWS,
+				    TAS2552_SWS);
+		snd_soc_component_update_bits(component, TAS2552_CFG_2, 1, 1);
+		snd_soc_component_update_bits(component, TAS2552_LIMIT_RATE_HYS, (1 << 5), 0);
+		snd_soc_component_write(component, TAS2552_RESERVED_0D, 0xbe);
+		break;
+	}
+	return 0;
+}
+
+/* Input mux controls */
+static const char * const tas2552_input_texts[] = {
+	"Digital", "Analog" };
+static SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum, TAS2552_CFG_3, 7,
+			    tas2552_input_texts);
+
+static const struct snd_kcontrol_new tas2552_input_mux_control =
+	SOC_DAPM_ENUM("Route", tas2552_input_mux_enum);
+
+static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] =
+{
+	SND_SOC_DAPM_INPUT("IN"),
+
+	/* MUX Controls */
+	SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM, 0, 0,
+			 &tas2552_input_mux_control),
+
+	SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0),
+	SND_SOC_DAPM_POST("Post Event", tas2552_post_event),
+
+	SND_SOC_DAPM_OUTPUT("OUT")
+};
+
+static const struct snd_soc_dapm_route tas2552_audio_map[] = {
+	{"DAC", NULL, "DAC IN"},
+	{"Input selection", "Digital", "DAC"},
+	{"Input selection", "Analog", "IN"},
+	{"ClassD", NULL, "Input selection"},
+	{"OUT", NULL, "ClassD"},
+	{"ClassD", NULL, "PLL"},
+};
+
+#ifdef CONFIG_PM
+static void tas2552_sw_shutdown(struct tas2552_data *tas2552, int sw_shutdown)
+{
+	u8 cfg1_reg = 0;
+
+	if (!tas2552->component)
+		return;
+
+	if (sw_shutdown)
+		cfg1_reg = TAS2552_SWS;
+
+	snd_soc_component_update_bits(tas2552->component, TAS2552_CFG_1, TAS2552_SWS,
+			    cfg1_reg);
+}
+#endif
+
+static int tas2552_setup_pll(struct snd_soc_component *component,
+			     struct snd_pcm_hw_params *params)
+{
+	struct tas2552_data *tas2552 = dev_get_drvdata(component->dev);
+	bool bypass_pll = false;
+	unsigned int pll_clk = params_rate(params) * 512;
+	unsigned int pll_clkin = tas2552->pll_clkin;
+	u8 pll_enable;
+
+	if (!pll_clkin) {
+		if (tas2552->pll_clk_id != TAS2552_PLL_CLKIN_BCLK)
+			return -EINVAL;
+
+		pll_clkin = snd_soc_params_to_bclk(params);
+		pll_clkin += tas2552->tdm_delay;
+	}
+
+	pll_enable = snd_soc_component_read32(component, TAS2552_CFG_2) & TAS2552_PLL_ENABLE;
+	snd_soc_component_update_bits(component, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
+
+	if (pll_clkin == pll_clk)
+		bypass_pll = true;
+
+	if (bypass_pll) {
+		/* By pass the PLL configuration */
+		snd_soc_component_update_bits(component, TAS2552_PLL_CTRL_2,
+				    TAS2552_PLL_BYPASS, TAS2552_PLL_BYPASS);
+	} else {
+		/* Fill in the PLL control registers for J & D
+		 * pll_clk = (.5 * pll_clkin * J.D) / 2^p
+		 * Need to fill in J and D here based on incoming freq
+		 */
+		unsigned int d, q, t;
+		u8 j;
+		u8 pll_sel = (tas2552->pll_clk_id << 3) & TAS2552_PLL_SRC_MASK;
+		u8 p = snd_soc_component_read32(component, TAS2552_PLL_CTRL_1);
+
+		p = (p >> 7);
+
+recalc:
+		t = (pll_clk * 2) << p;
+		j = t / pll_clkin;
+		d = t % pll_clkin;
+		t = pll_clkin / 10000;
+		q = d / (t + 1);
+		d = q + ((9999 - pll_clkin % 10000) * (d / t - q)) / 10000;
+
+		if (d && (pll_clkin < 512000 || pll_clkin > 9200000)) {
+			if (tas2552->pll_clk_id == TAS2552_PLL_CLKIN_BCLK) {
+				pll_clkin = 1800000;
+				pll_sel = (TAS2552_PLL_CLKIN_1_8_FIXED << 3) &
+							TAS2552_PLL_SRC_MASK;
+			} else {
+				pll_clkin = snd_soc_params_to_bclk(params);
+				pll_clkin += tas2552->tdm_delay;
+				pll_sel = (TAS2552_PLL_CLKIN_BCLK << 3) &
+							TAS2552_PLL_SRC_MASK;
+			}
+			goto recalc;
+		}
+
+		snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_PLL_SRC_MASK,
+				    pll_sel);
+
+		snd_soc_component_update_bits(component, TAS2552_PLL_CTRL_1,
+				    TAS2552_PLL_J_MASK, j);
+		/* Will clear the PLL_BYPASS bit */
+		snd_soc_component_write(component, TAS2552_PLL_CTRL_2,
+			      TAS2552_PLL_D_UPPER(d));
+		snd_soc_component_write(component, TAS2552_PLL_CTRL_3,
+			      TAS2552_PLL_D_LOWER(d));
+	}
+
+	/* Restore PLL status */
+	snd_soc_component_update_bits(component, TAS2552_CFG_2, TAS2552_PLL_ENABLE,
+			    pll_enable);
+
+	return 0;
+}
+
+static int tas2552_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas2552_data *tas2552 = dev_get_drvdata(component->dev);
+	int cpf;
+	u8 ser_ctrl1_reg, wclk_rate;
+
+	switch (params_width(params)) {
+	case 16:
+		ser_ctrl1_reg = TAS2552_WORDLENGTH_16BIT;
+		cpf = 32 + tas2552->tdm_delay;
+		break;
+	case 20:
+		ser_ctrl1_reg = TAS2552_WORDLENGTH_20BIT;
+		cpf = 64 + tas2552->tdm_delay;
+		break;
+	case 24:
+		ser_ctrl1_reg = TAS2552_WORDLENGTH_24BIT;
+		cpf = 64 + tas2552->tdm_delay;
+		break;
+	case 32:
+		ser_ctrl1_reg = TAS2552_WORDLENGTH_32BIT;
+		cpf = 64 + tas2552->tdm_delay;
+		break;
+	default:
+		dev_err(component->dev, "Not supported sample size: %d\n",
+			params_width(params));
+		return -EINVAL;
+	}
+
+	if (cpf <= 32)
+		ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_32;
+	else if (cpf <= 64)
+		ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_64;
+	else if (cpf <= 128)
+		ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_128;
+	else
+		ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_256;
+
+	snd_soc_component_update_bits(component, TAS2552_SER_CTRL_1,
+			    TAS2552_WORDLENGTH_MASK | TAS2552_CLKSPERFRAME_MASK,
+			    ser_ctrl1_reg);
+
+	switch (params_rate(params)) {
+	case 8000:
+		wclk_rate = TAS2552_WCLK_FREQ_8KHZ;
+		break;
+	case 11025:
+	case 12000:
+		wclk_rate = TAS2552_WCLK_FREQ_11_12KHZ;
+		break;
+	case 16000:
+		wclk_rate = TAS2552_WCLK_FREQ_16KHZ;
+		break;
+	case 22050:
+	case 24000:
+		wclk_rate = TAS2552_WCLK_FREQ_22_24KHZ;
+		break;
+	case 32000:
+		wclk_rate = TAS2552_WCLK_FREQ_32KHZ;
+		break;
+	case 44100:
+	case 48000:
+		wclk_rate = TAS2552_WCLK_FREQ_44_48KHZ;
+		break;
+	case 88200:
+	case 96000:
+		wclk_rate = TAS2552_WCLK_FREQ_88_96KHZ;
+		break;
+	case 176400:
+	case 192000:
+		wclk_rate = TAS2552_WCLK_FREQ_176_192KHZ;
+		break;
+	default:
+		dev_err(component->dev, "Not supported sample rate: %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, TAS2552_CFG_3, TAS2552_WCLK_FREQ_MASK,
+			    wclk_rate);
+
+	return tas2552_setup_pll(component, params);
+}
+
+#define TAS2552_DAI_FMT_MASK	(TAS2552_BCLKDIR | \
+				 TAS2552_WCLKDIR | \
+				 TAS2552_DATAFORMAT_MASK)
+static int tas2552_prepare(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
+	int delay = 0;
+
+	/* TDM slot selection only valid in DSP_A/_B mode */
+	if (tas2552->dai_fmt == SND_SOC_DAIFMT_DSP_A)
+		delay += (tas2552->tdm_delay + 1);
+	else if (tas2552->dai_fmt == SND_SOC_DAIFMT_DSP_B)
+		delay += tas2552->tdm_delay;
+
+	/* Configure data delay */
+	snd_soc_component_write(component, TAS2552_SER_CTRL_2, delay);
+
+	return 0;
+}
+
+static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas2552_data *tas2552 = dev_get_drvdata(component->dev);
+	u8 serial_format;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		serial_format = 0x00;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		serial_format = TAS2552_WCLKDIR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		serial_format = TAS2552_BCLKDIR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		serial_format = (TAS2552_BCLKDIR | TAS2552_WCLKDIR);
+		break;
+	default:
+		dev_vdbg(component->dev, "DAI Format master is not found\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
+		       SND_SOC_DAIFMT_INV_MASK)) {
+	case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
+		break;
+	case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF):
+	case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF):
+		serial_format |= TAS2552_DATAFORMAT_DSP;
+		break;
+	case (SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_NB_NF):
+		serial_format |= TAS2552_DATAFORMAT_RIGHT_J;
+		break;
+	case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF):
+		serial_format |= TAS2552_DATAFORMAT_LEFT_J;
+		break;
+	default:
+		dev_vdbg(component->dev, "DAI Format is not found\n");
+		return -EINVAL;
+	}
+	tas2552->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+	snd_soc_component_update_bits(component, TAS2552_SER_CTRL_1, TAS2552_DAI_FMT_MASK,
+			    serial_format);
+	return 0;
+}
+
+static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+				  unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas2552_data *tas2552 = dev_get_drvdata(component->dev);
+	u8 reg, mask, val;
+
+	switch (clk_id) {
+	case TAS2552_PLL_CLKIN_MCLK:
+	case TAS2552_PLL_CLKIN_IVCLKIN:
+		if (freq < 512000 || freq > 24576000) {
+			/* out of range PLL_CLKIN, fall back to use BCLK */
+			dev_warn(component->dev, "Out of range PLL_CLKIN: %u\n",
+				 freq);
+			clk_id = TAS2552_PLL_CLKIN_BCLK;
+			freq = 0;
+		}
+		/* fall through */
+	case TAS2552_PLL_CLKIN_BCLK:
+	case TAS2552_PLL_CLKIN_1_8_FIXED:
+		mask = TAS2552_PLL_SRC_MASK;
+		val = (clk_id << 3) & mask; /* bit 4:5 in the register */
+		reg = TAS2552_CFG_1;
+		tas2552->pll_clk_id = clk_id;
+		tas2552->pll_clkin = freq;
+		break;
+	case TAS2552_PDM_CLK_PLL:
+	case TAS2552_PDM_CLK_IVCLKIN:
+	case TAS2552_PDM_CLK_BCLK:
+	case TAS2552_PDM_CLK_MCLK:
+		mask = TAS2552_PDM_CLK_SEL_MASK;
+		val = (clk_id >> 1) & mask; /* bit 0:1 in the register */
+		reg = TAS2552_PDM_CFG;
+		tas2552->pdm_clk_id = clk_id;
+		tas2552->pdm_clk = freq;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clk id: %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, reg, mask, val);
+
+	return 0;
+}
+
+static int tas2552_set_dai_tdm_slot(struct snd_soc_dai *dai,
+				    unsigned int tx_mask, unsigned int rx_mask,
+				    int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
+	unsigned int lsb;
+
+	if (unlikely(!tx_mask)) {
+		dev_err(component->dev, "tx masks need to be non 0\n");
+		return -EINVAL;
+	}
+
+	/* TDM based on DSP mode requires slots to be adjacent */
+	lsb = __ffs(tx_mask);
+	if ((lsb + 1) != __fls(tx_mask)) {
+		dev_err(component->dev, "Invalid mask, slots must be adjacent\n");
+		return -EINVAL;
+	}
+
+	tas2552->tdm_delay = lsb * slot_width;
+
+	/* DOUT in high-impedance on inactive bit clocks */
+	snd_soc_component_update_bits(component, TAS2552_DOUT,
+			    TAS2552_SDOUT_TRISTATE, TAS2552_SDOUT_TRISTATE);
+
+	return 0;
+}
+
+static int tas2552_mute(struct snd_soc_dai *dai, int mute)
+{
+	u8 cfg1_reg = 0;
+	struct snd_soc_component *component = dai->component;
+
+	if (mute)
+		cfg1_reg |= TAS2552_MUTE;
+
+	snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_MUTE, cfg1_reg);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int tas2552_runtime_suspend(struct device *dev)
+{
+	struct tas2552_data *tas2552 = dev_get_drvdata(dev);
+
+	tas2552_sw_shutdown(tas2552, 1);
+
+	regcache_cache_only(tas2552->regmap, true);
+	regcache_mark_dirty(tas2552->regmap);
+
+	gpiod_set_value(tas2552->enable_gpio, 0);
+
+	return 0;
+}
+
+static int tas2552_runtime_resume(struct device *dev)
+{
+	struct tas2552_data *tas2552 = dev_get_drvdata(dev);
+
+	gpiod_set_value(tas2552->enable_gpio, 1);
+
+	tas2552_sw_shutdown(tas2552, 0);
+
+	regcache_cache_only(tas2552->regmap, false);
+	regcache_sync(tas2552->regmap);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops tas2552_pm = {
+	SET_RUNTIME_PM_OPS(tas2552_runtime_suspend, tas2552_runtime_resume,
+			   NULL)
+};
+
+static const struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
+	.hw_params	= tas2552_hw_params,
+	.prepare	= tas2552_prepare,
+	.set_sysclk	= tas2552_set_dai_sysclk,
+	.set_fmt	= tas2552_set_dai_fmt,
+	.set_tdm_slot	= tas2552_set_dai_tdm_slot,
+	.digital_mute = tas2552_mute,
+};
+
+/* Formats supported by TAS2552 driver. */
+#define TAS2552_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+/* TAS2552 dai structure. */
+static struct snd_soc_dai_driver tas2552_dai[] = {
+	{
+		.name = "tas2552-amplifier",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = TAS2552_FORMATS,
+		},
+		.ops = &tas2552_speaker_dai_ops,
+	},
+};
+
+/*
+ * DAC digital volumes. From -7 to 24 dB in 1 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(dac_tlv, -700, 100, 0);
+
+static const char * const tas2552_din_source_select[] = {
+	"Muted",
+	"Left",
+	"Right",
+	"Left + Right average",
+};
+static SOC_ENUM_SINGLE_DECL(tas2552_din_source_enum,
+			    TAS2552_CFG_3, 3,
+			    tas2552_din_source_select);
+
+static const struct snd_kcontrol_new tas2552_snd_controls[] = {
+	SOC_SINGLE_TLV("Speaker Driver Playback Volume",
+			 TAS2552_PGA_GAIN, 0, 0x1f, 0, dac_tlv),
+	SOC_ENUM("DIN source", tas2552_din_source_enum),
+};
+
+static int tas2552_component_probe(struct snd_soc_component *component)
+{
+	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	tas2552->component = component;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(tas2552->supplies),
+				    tas2552->supplies);
+
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to enable supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	gpiod_set_value(tas2552->enable_gpio, 1);
+
+	ret = pm_runtime_get_sync(component->dev);
+	if (ret < 0) {
+		dev_err(component->dev, "Enabling device failed: %d\n",
+			ret);
+		goto probe_fail;
+	}
+
+	snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_MUTE, TAS2552_MUTE);
+	snd_soc_component_write(component, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL |
+					    TAS2552_DIN_SRC_SEL_AVG_L_R);
+	snd_soc_component_write(component, TAS2552_OUTPUT_DATA,
+		      TAS2552_PDM_DATA_SEL_V_I |
+		      TAS2552_R_DATA_OUT(TAS2552_DATA_OUT_V_DATA));
+	snd_soc_component_write(component, TAS2552_BOOST_APT_CTRL, TAS2552_APT_DELAY_200 |
+						     TAS2552_APT_THRESH_20_17);
+
+	snd_soc_component_write(component, TAS2552_CFG_2, TAS2552_BOOST_EN | TAS2552_APT_EN |
+					    TAS2552_LIM_EN);
+
+	return 0;
+
+probe_fail:
+	gpiod_set_value(tas2552->enable_gpio, 0);
+
+	regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies),
+					tas2552->supplies);
+	return ret;
+}
+
+static void tas2552_component_remove(struct snd_soc_component *component)
+{
+	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
+
+	pm_runtime_put(component->dev);
+
+	gpiod_set_value(tas2552->enable_gpio, 0);
+};
+
+#ifdef CONFIG_PM
+static int tas2552_suspend(struct snd_soc_component *component)
+{
+	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies),
+					tas2552->supplies);
+
+	if (ret != 0)
+		dev_err(component->dev, "Failed to disable supplies: %d\n",
+			ret);
+	return ret;
+}
+
+static int tas2552_resume(struct snd_soc_component *component)
+{
+	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(tas2552->supplies),
+				    tas2552->supplies);
+
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to enable supplies: %d\n",
+			ret);
+	}
+
+	return ret;
+}
+#else
+#define tas2552_suspend NULL
+#define tas2552_resume NULL
+#endif
+
+static const struct snd_soc_component_driver soc_component_dev_tas2552 = {
+	.probe			= tas2552_component_probe,
+	.remove			= tas2552_component_remove,
+	.suspend		= tas2552_suspend,
+	.resume			= tas2552_resume,
+	.controls		= tas2552_snd_controls,
+	.num_controls		= ARRAY_SIZE(tas2552_snd_controls),
+	.dapm_widgets		= tas2552_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tas2552_dapm_widgets),
+	.dapm_routes		= tas2552_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(tas2552_audio_map),
+	.idle_bias_on		= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config tas2552_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = TAS2552_MAX_REG,
+	.reg_defaults = tas2552_reg_defs,
+	.num_reg_defaults = ARRAY_SIZE(tas2552_reg_defs),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int tas2552_probe(struct i2c_client *client,
+			   const struct i2c_device_id *id)
+{
+	struct device *dev;
+	struct tas2552_data *data;
+	int ret;
+	int i;
+
+	dev = &client->dev;
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	data->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+						    GPIOD_OUT_LOW);
+	if (IS_ERR(data->enable_gpio))
+		return PTR_ERR(data->enable_gpio);
+
+	data->tas2552_client = client;
+	data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config);
+	if (IS_ERR(data->regmap)) {
+		ret = PTR_ERR(data->regmap);
+		dev_err(&client->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
+		data->supplies[i].supply = tas2552_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
+				      data->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	pm_runtime_set_active(&client->dev);
+	pm_runtime_set_autosuspend_delay(&client->dev, 1000);
+	pm_runtime_use_autosuspend(&client->dev);
+	pm_runtime_enable(&client->dev);
+	pm_runtime_mark_last_busy(&client->dev);
+	pm_runtime_put_sync_autosuspend(&client->dev);
+
+	dev_set_drvdata(&client->dev, data);
+
+	ret = devm_snd_soc_register_component(&client->dev,
+				      &soc_component_dev_tas2552,
+				      tas2552_dai, ARRAY_SIZE(tas2552_dai));
+	if (ret < 0)
+		dev_err(&client->dev, "Failed to register component: %d\n", ret);
+
+	return ret;
+}
+
+static int tas2552_i2c_remove(struct i2c_client *client)
+{
+	pm_runtime_disable(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id tas2552_id[] = {
+	{ "tas2552", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas2552_id);
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id tas2552_of_match[] = {
+	{ .compatible = "ti,tas2552", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tas2552_of_match);
+#endif
+
+static struct i2c_driver tas2552_i2c_driver = {
+	.driver = {
+		.name = "tas2552",
+		.of_match_table = of_match_ptr(tas2552_of_match),
+		.pm = &tas2552_pm,
+	},
+	.probe = tas2552_probe,
+	.remove = tas2552_i2c_remove,
+	.id_table = tas2552_id,
+};
+
+module_i2c_driver(tas2552_i2c_driver);
+
+MODULE_AUTHOR("Dan Muprhy <dmurphy@ti.com>");
+MODULE_DESCRIPTION("TAS2552 Audio amplifier driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas2552.h b/sound/soc/codecs/tas2552.h
new file mode 100644
index 0000000..e34752b
--- /dev/null
+++ b/sound/soc/codecs/tas2552.h
@@ -0,0 +1,146 @@
+/*
+ * tas2552.h - ALSA SoC Texas Instruments TAS2552 Mono Audio Amplifier
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated -  http://www.ti.com
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __TAS2552_H__
+#define __TAS2552_H__
+
+/* Register Address Map */
+#define TAS2552_DEVICE_STATUS		0x00
+#define TAS2552_CFG_1			0x01
+#define TAS2552_CFG_2			0x02
+#define TAS2552_CFG_3			0x03
+#define TAS2552_DOUT			0x04
+#define TAS2552_SER_CTRL_1		0x05
+#define TAS2552_SER_CTRL_2		0x06
+#define TAS2552_OUTPUT_DATA		0x07
+#define TAS2552_PLL_CTRL_1		0x08
+#define TAS2552_PLL_CTRL_2		0x09
+#define TAS2552_PLL_CTRL_3		0x0a
+#define TAS2552_BTIP			0x0b
+#define TAS2552_BTS_CTRL		0x0c
+#define TAS2552_RESERVED_0D		0x0d
+#define TAS2552_LIMIT_RATE_HYS		0x0e
+#define TAS2552_LIMIT_RELEASE		0x0f
+#define TAS2552_LIMIT_INT_COUNT		0x10
+#define TAS2552_PDM_CFG			0x11
+#define TAS2552_PGA_GAIN		0x12
+#define TAS2552_EDGE_RATE_CTRL		0x13
+#define TAS2552_BOOST_APT_CTRL		0x14
+#define TAS2552_VER_NUM			0x16
+#define TAS2552_VBAT_DATA		0x19
+#define TAS2552_MAX_REG			TAS2552_VBAT_DATA
+
+/* CFG1 Register Masks */
+#define TAS2552_DEV_RESET		(1 << 0)
+#define TAS2552_SWS			(1 << 1)
+#define TAS2552_MUTE			(1 << 2)
+#define TAS2552_PLL_SRC_MCLK		(0x0 << 4)
+#define TAS2552_PLL_SRC_BCLK		(0x1 << 4)
+#define TAS2552_PLL_SRC_IVCLKIN		(0x2 << 4)
+#define TAS2552_PLL_SRC_1_8_FIXED 	(0x3 << 4)
+#define TAS2552_PLL_SRC_MASK	 	TAS2552_PLL_SRC_1_8_FIXED
+
+/* CFG2 Register Masks */
+#define TAS2552_CLASSD_EN		(1 << 7)
+#define TAS2552_BOOST_EN		(1 << 6)
+#define TAS2552_APT_EN			(1 << 5)
+#define TAS2552_PLL_ENABLE		(1 << 3)
+#define TAS2552_LIM_EN			(1 << 2)
+#define TAS2552_IVSENSE_EN		(1 << 1)
+
+/* CFG3 Register Masks */
+#define TAS2552_WCLK_FREQ_8KHZ		(0x0 << 0)
+#define TAS2552_WCLK_FREQ_11_12KHZ	(0x1 << 0)
+#define TAS2552_WCLK_FREQ_16KHZ		(0x2 << 0)
+#define TAS2552_WCLK_FREQ_22_24KHZ	(0x3 << 0)
+#define TAS2552_WCLK_FREQ_32KHZ		(0x4 << 0)
+#define TAS2552_WCLK_FREQ_44_48KHZ	(0x5 << 0)
+#define TAS2552_WCLK_FREQ_88_96KHZ	(0x6 << 0)
+#define TAS2552_WCLK_FREQ_176_192KHZ	(0x7 << 0)
+#define TAS2552_WCLK_FREQ_MASK		TAS2552_WCLK_FREQ_176_192KHZ
+#define TAS2552_DIN_SRC_SEL_MUTED	(0x0 << 3)
+#define TAS2552_DIN_SRC_SEL_LEFT	(0x1 << 3)
+#define TAS2552_DIN_SRC_SEL_RIGHT	(0x2 << 3)
+#define TAS2552_DIN_SRC_SEL_AVG_L_R	(0x3 << 3)
+#define TAS2552_PDM_IN_SEL		(1 << 5)
+#define TAS2552_I2S_OUT_SEL		(1 << 6)
+#define TAS2552_ANALOG_IN_SEL		(1 << 7)
+
+/* DOUT Register Masks */
+#define TAS2552_SDOUT_TRISTATE		(1 << 2)
+
+/* Serial Interface Control Register Masks */
+#define TAS2552_WORDLENGTH_16BIT	(0x0 << 0)
+#define TAS2552_WORDLENGTH_20BIT	(0x1 << 0)
+#define TAS2552_WORDLENGTH_24BIT	(0x2 << 0)
+#define TAS2552_WORDLENGTH_32BIT	(0x3 << 0)
+#define TAS2552_WORDLENGTH_MASK		TAS2552_WORDLENGTH_32BIT
+#define TAS2552_DATAFORMAT_I2S		(0x0 << 2)
+#define TAS2552_DATAFORMAT_DSP		(0x1 << 2)
+#define TAS2552_DATAFORMAT_RIGHT_J	(0x2 << 2)
+#define TAS2552_DATAFORMAT_LEFT_J	(0x3 << 2)
+#define TAS2552_DATAFORMAT_MASK		TAS2552_DATAFORMAT_LEFT_J
+#define TAS2552_CLKSPERFRAME_32		(0x0 << 4)
+#define TAS2552_CLKSPERFRAME_64		(0x1 << 4)
+#define TAS2552_CLKSPERFRAME_128	(0x2 << 4)
+#define TAS2552_CLKSPERFRAME_256	(0x3 << 4)
+#define TAS2552_CLKSPERFRAME_MASK	TAS2552_CLKSPERFRAME_256
+#define TAS2552_BCLKDIR			(1 << 6)
+#define TAS2552_WCLKDIR			(1 << 7)
+
+/* OUTPUT_DATA register */
+#define TAS2552_DATA_OUT_I_DATA		(0x0)
+#define TAS2552_DATA_OUT_V_DATA		(0x1)
+#define TAS2552_DATA_OUT_VBAT_DATA	(0x2)
+#define TAS2552_DATA_OUT_VBOOST_DATA	(0x3)
+#define TAS2552_DATA_OUT_PGA_GAIN	(0x4)
+#define TAS2552_DATA_OUT_IV_DATA	(0x5)
+#define TAS2552_DATA_OUT_VBAT_VBOOST_GAIN	(0x6)
+#define TAS2552_DATA_OUT_DISABLED	(0x7)
+#define TAS2552_L_DATA_OUT(x)		((x) << 0)
+#define TAS2552_R_DATA_OUT(x)		((x) << 3)
+#define TAS2552_PDM_DATA_SEL_I		(0x0 << 6)
+#define TAS2552_PDM_DATA_SEL_V		(0x1 << 6)
+#define TAS2552_PDM_DATA_SEL_I_V	(0x2 << 6)
+#define TAS2552_PDM_DATA_SEL_V_I	(0x3 << 6)
+#define TAS2552_PDM_DATA_SEL_MASK	TAS2552_PDM_DATA_SEL_V_I
+
+/* PDM CFG Register */
+#define TAS2552_PDM_CLK_SEL_PLL		(0x0 << 0)
+#define TAS2552_PDM_CLK_SEL_IVCLKIN	(0x1 << 0)
+#define TAS2552_PDM_CLK_SEL_BCLK	(0x2 << 0)
+#define TAS2552_PDM_CLK_SEL_MCLK	(0x3 << 0)
+#define TAS2552_PDM_CLK_SEL_MASK	TAS2552_PDM_CLK_SEL_MCLK
+#define TAS2552_PDM_DATA_ES	 	(1 << 2)
+
+/* Boost Auto-pass through register */
+#define TAS2552_APT_DELAY_50		(0x0 << 0)
+#define TAS2552_APT_DELAY_75		(0x1 << 0)
+#define TAS2552_APT_DELAY_125		(0x2 << 0)
+#define TAS2552_APT_DELAY_200		(0x3 << 0)
+#define TAS2552_APT_THRESH_05_02	(0x0 << 2)
+#define TAS2552_APT_THRESH_10_07	(0x1 << 2)
+#define TAS2552_APT_THRESH_14_11	(0x2 << 2)
+#define TAS2552_APT_THRESH_20_17	(0x3 << 2)
+
+/* PLL Control Register */
+#define TAS2552_PLL_J_MASK		0x7f
+#define TAS2552_PLL_D_UPPER(x)		(((x) >> 8) & 0x3f)
+#define TAS2552_PLL_D_LOWER(x)		((x) & 0xff)
+#define TAS2552_PLL_BYPASS		(1 << 7)
+
+#endif
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
new file mode 100644
index 0000000..5efc4b7
--- /dev/null
+++ b/sound/soc/codecs/tas5086.c
@@ -0,0 +1,1014 @@
+/*
+ * TAS5086 ASoC codec driver
+ *
+ * Copyright (c) 2013 Daniel Mack <zonque@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * TODO:
+ *  - implement DAPM and input muxing
+ *  - implement modulation limit
+ *  - implement non-default PWM start
+ *
+ * Note that this chip has a very unusual register layout, specifically
+ * because the registers are of unequal size, and multi-byte registers
+ * require bulk writes to take effect. Regmap does not support that kind
+ * of devices.
+ *
+ * Currently, the driver does not touch any of the registers >= 0x20, so
+ * it doesn't matter because the entire map can be accessed as 8-bit
+ * array. In case more features will be added in the future
+ * that require access to higher registers, the entire regmap H/W I/O
+ * routines have to be open-coded.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/tas5086.h>
+
+#define TAS5086_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  |		\
+			     SNDRV_PCM_FMTBIT_S20_3LE |		\
+			     SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define TAS5086_PCM_RATES   (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100  | \
+			     SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200  | \
+			     SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
+			     SNDRV_PCM_RATE_192000)
+
+/*
+ * TAS5086 registers
+ */
+#define TAS5086_CLOCK_CONTROL		0x00	/* Clock control register  */
+#define TAS5086_CLOCK_RATE(val)		(val << 5)
+#define TAS5086_CLOCK_RATE_MASK		(0x7 << 5)
+#define TAS5086_CLOCK_RATIO(val)	(val << 2)
+#define TAS5086_CLOCK_RATIO_MASK	(0x7 << 2)
+#define TAS5086_CLOCK_SCLK_RATIO_48	(1 << 1)
+#define TAS5086_CLOCK_VALID		(1 << 0)
+
+#define TAS5086_DEEMPH_MASK		0x03
+#define TAS5086_SOFT_MUTE_ALL		0x3f
+
+#define TAS5086_DEV_ID			0x01	/* Device ID register */
+#define TAS5086_ERROR_STATUS		0x02	/* Error status register */
+#define TAS5086_SYS_CONTROL_1		0x03	/* System control register 1 */
+#define TAS5086_SERIAL_DATA_IF		0x04	/* Serial data interface register  */
+#define TAS5086_SYS_CONTROL_2		0x05	/* System control register 2 */
+#define TAS5086_SOFT_MUTE		0x06	/* Soft mute register */
+#define TAS5086_MASTER_VOL		0x07	/* Master volume  */
+#define TAS5086_CHANNEL_VOL(X)		(0x08 + (X))	/* Channel 1-6 volume */
+#define TAS5086_VOLUME_CONTROL		0x09	/* Volume control register */
+#define TAS5086_MOD_LIMIT		0x10	/* Modulation limit register */
+#define TAS5086_PWM_START		0x18	/* PWM start register */
+#define TAS5086_SURROUND		0x19	/* Surround register */
+#define TAS5086_SPLIT_CAP_CHARGE	0x1a	/* Split cap charge period register */
+#define TAS5086_OSC_TRIM		0x1b	/* Oscillator trim register */
+#define TAS5086_BKNDERR 		0x1c
+#define TAS5086_INPUT_MUX		0x20
+#define TAS5086_PWM_OUTPUT_MUX		0x25
+
+#define TAS5086_MAX_REGISTER		TAS5086_PWM_OUTPUT_MUX
+
+#define TAS5086_PWM_START_MIDZ_FOR_START_1	(1 << 7)
+#define TAS5086_PWM_START_MIDZ_FOR_START_2	(1 << 6)
+#define TAS5086_PWM_START_CHANNEL_MASK		(0x3f)
+
+/*
+ * Default TAS5086 power-up configuration
+ */
+static const struct reg_default tas5086_reg_defaults[] = {
+	{ 0x00,	0x6c },
+	{ 0x01,	0x03 },
+	{ 0x02,	0x00 },
+	{ 0x03,	0xa0 },
+	{ 0x04,	0x05 },
+	{ 0x05,	0x60 },
+	{ 0x06,	0x00 },
+	{ 0x07,	0xff },
+	{ 0x08,	0x30 },
+	{ 0x09,	0x30 },
+	{ 0x0a,	0x30 },
+	{ 0x0b,	0x30 },
+	{ 0x0c,	0x30 },
+	{ 0x0d,	0x30 },
+	{ 0x0e,	0xb1 },
+	{ 0x0f,	0x00 },
+	{ 0x10,	0x02 },
+	{ 0x11,	0x00 },
+	{ 0x12,	0x00 },
+	{ 0x13,	0x00 },
+	{ 0x14,	0x00 },
+	{ 0x15,	0x00 },
+	{ 0x16,	0x00 },
+	{ 0x17,	0x00 },
+	{ 0x18,	0x3f },
+	{ 0x19,	0x00 },
+	{ 0x1a,	0x18 },
+	{ 0x1b,	0x82 },
+	{ 0x1c,	0x05 },
+};
+
+static int tas5086_register_size(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5086_CLOCK_CONTROL ... TAS5086_BKNDERR:
+		return 1;
+	case TAS5086_INPUT_MUX:
+	case TAS5086_PWM_OUTPUT_MUX:
+		return 4;
+	}
+
+	dev_err(dev, "Unsupported register address: %d\n", reg);
+	return 0;
+}
+
+static bool tas5086_accessible_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0x0f:
+	case 0x11 ... 0x17:
+	case 0x1d ... 0x1f:
+		return false;
+	default:
+		return true;
+	}
+}
+
+static bool tas5086_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5086_DEV_ID:
+	case TAS5086_ERROR_STATUS:
+		return true;
+	}
+
+	return false;
+}
+
+static bool tas5086_writeable_reg(struct device *dev, unsigned int reg)
+{
+	return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID);
+}
+
+static int tas5086_reg_write(void *context, unsigned int reg,
+			      unsigned int value)
+{
+	struct i2c_client *client = context;
+	unsigned int i, size;
+	uint8_t buf[5];
+	int ret;
+
+	size = tas5086_register_size(&client->dev, reg);
+	if (size == 0)
+		return -EINVAL;
+
+	buf[0] = reg;
+
+	for (i = size; i >= 1; --i) {
+		buf[i] = value;
+		value >>= 8;
+	}
+
+	ret = i2c_master_send(client, buf, size + 1);
+	if (ret == size + 1)
+		return 0;
+	else if (ret < 0)
+		return ret;
+	else
+		return -EIO;
+}
+
+static int tas5086_reg_read(void *context, unsigned int reg,
+			     unsigned int *value)
+{
+	struct i2c_client *client = context;
+	uint8_t send_buf, recv_buf[4];
+	struct i2c_msg msgs[2];
+	unsigned int size;
+	unsigned int i;
+	int ret;
+
+	size = tas5086_register_size(&client->dev, reg);
+	if (size == 0)
+		return -EINVAL;
+
+	send_buf = reg;
+
+	msgs[0].addr = client->addr;
+	msgs[0].len = sizeof(send_buf);
+	msgs[0].buf = &send_buf;
+	msgs[0].flags = 0;
+
+	msgs[1].addr = client->addr;
+	msgs[1].len = size;
+	msgs[1].buf = recv_buf;
+	msgs[1].flags = I2C_M_RD;
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0)
+		return ret;
+	else if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	*value = 0;
+
+	for (i = 0; i < size; i++) {
+		*value <<= 8;
+		*value |= recv_buf[i];
+	}
+
+	return 0;
+}
+
+static const char * const supply_names[] = {
+	"dvdd", "avdd"
+};
+
+struct tas5086_private {
+	struct regmap	*regmap;
+	unsigned int	mclk, sclk;
+	unsigned int	format;
+	bool		deemph;
+	unsigned int	charge_period;
+	unsigned int	pwm_start_mid_z;
+	/* Current sample rate for de-emphasis control */
+	int		rate;
+	/* GPIO driving Reset pin, if any */
+	int		gpio_nreset;
+	struct		regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+};
+
+static int tas5086_deemph[] = { 0, 32000, 44100, 48000 };
+
+static int tas5086_set_deemph(struct snd_soc_component *component)
+{
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
+	int i, val = 0;
+
+	if (priv->deemph) {
+		for (i = 0; i < ARRAY_SIZE(tas5086_deemph); i++) {
+			if (tas5086_deemph[i] == priv->rate) {
+				val = i;
+				break;
+			}
+		}
+	}
+
+	return regmap_update_bits(priv->regmap, TAS5086_SYS_CONTROL_1,
+				  TAS5086_DEEMPH_MASK, val);
+}
+
+static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = priv->deemph;
+
+	return 0;
+}
+
+static int tas5086_put_deemph(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
+
+	priv->deemph = ucontrol->value.integer.value[0];
+
+	return tas5086_set_deemph(component);
+}
+
+
+static int tas5086_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case TAS5086_CLK_IDX_MCLK:
+		priv->mclk = freq;
+		break;
+	case TAS5086_CLK_IDX_SCLK:
+		priv->sclk = freq;
+		break;
+	}
+
+	return 0;
+}
+
+static int tas5086_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			       unsigned int format)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
+
+	/* The TAS5086 can only be slave to all clocks */
+	if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+		dev_err(component->dev, "Invalid clocking mode\n");
+		return -EINVAL;
+	}
+
+	/* we need to refer to the data format from hw_params() */
+	priv->format = format;
+
+	return 0;
+}
+
+static const int tas5086_sample_rates[] = {
+	32000, 38000, 44100, 48000, 88200, 96000, 176400, 192000
+};
+
+static const int tas5086_ratios[] = {
+	64, 128, 192, 256, 384, 512
+};
+
+static int index_in_array(const int *array, int len, int needle)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		if (array[i] == needle)
+			return i;
+
+	return -ENOENT;
+}
+
+static int tas5086_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
+	int val;
+	int ret;
+
+	priv->rate = params_rate(params);
+
+	/* Look up the sample rate and refer to the offset in the list */
+	val = index_in_array(tas5086_sample_rates,
+			     ARRAY_SIZE(tas5086_sample_rates), priv->rate);
+
+	if (val < 0) {
+		dev_err(component->dev, "Invalid sample rate\n");
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+				 TAS5086_CLOCK_RATE_MASK,
+				 TAS5086_CLOCK_RATE(val));
+	if (ret < 0)
+		return ret;
+
+	/* MCLK / Fs ratio */
+	val = index_in_array(tas5086_ratios, ARRAY_SIZE(tas5086_ratios),
+			     priv->mclk / priv->rate);
+	if (val < 0) {
+		dev_err(component->dev, "Invalid MCLK / Fs ratio\n");
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+				 TAS5086_CLOCK_RATIO_MASK,
+				 TAS5086_CLOCK_RATIO(val));
+	if (ret < 0)
+		return ret;
+
+
+	ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+				 TAS5086_CLOCK_SCLK_RATIO_48,
+				 (priv->sclk == 48 * priv->rate) ? 
+					TAS5086_CLOCK_SCLK_RATIO_48 : 0);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * The chip has a very unituitive register mapping and muxes information
+	 * about data format and sample depth into the same register, but not on
+	 * a logical bit-boundary. Hence, we have to refer to the format passed
+	 * in the set_dai_fmt() callback and set up everything from here.
+	 *
+	 * First, determine the 'base' value, using the format ...
+	 */
+	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val = 0x00;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		val = 0x03;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val = 0x06;
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	/* ... then add the offset for the sample bit depth. */
+	switch (params_width(params)) {
+        case 16:
+		val += 0;
+                break;
+	case 20:
+		val += 1;
+		break;
+	case 24:
+		val += 2;
+		break;
+	default:
+		dev_err(component->dev, "Invalid bit width\n");
+		return -EINVAL;
+	}
+
+	ret = regmap_write(priv->regmap, TAS5086_SERIAL_DATA_IF, val);
+	if (ret < 0)
+		return ret;
+
+	/* clock is considered valid now */
+	ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+				 TAS5086_CLOCK_VALID, TAS5086_CLOCK_VALID);
+	if (ret < 0)
+		return ret;
+
+	return tas5086_set_deemph(component);
+}
+
+static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
+	unsigned int val = 0;
+
+	if (mute)
+		val = TAS5086_SOFT_MUTE_ALL;
+
+	return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val);
+}
+
+static void tas5086_reset(struct tas5086_private *priv)
+{
+	if (gpio_is_valid(priv->gpio_nreset)) {
+		/* Reset codec - minimum assertion time is 400ns */
+		gpio_direction_output(priv->gpio_nreset, 0);
+		udelay(1);
+		gpio_set_value(priv->gpio_nreset, 1);
+
+		/* Codec needs ~15ms to wake up */
+		msleep(15);
+	}
+}
+
+/* charge period values in microseconds */
+static const int tas5086_charge_period[] = {
+	  13000,  16900,   23400,   31200,   41600,   54600,   72800,   96200,
+	 130000, 156000,  234000,  312000,  416000,  546000,  728000,  962000,
+	1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000,
+};
+
+static int tas5086_init(struct device *dev, struct tas5086_private *priv)
+{
+	int ret, i;
+
+	/*
+	 * If any of the channels is configured to start in Mid-Z mode,
+	 * configure 'part 1' of the PWM starts to use Mid-Z, and tell
+	 * all configured mid-z channels to start start under 'part 1'.
+	 */
+	if (priv->pwm_start_mid_z)
+		regmap_write(priv->regmap, TAS5086_PWM_START,
+			     TAS5086_PWM_START_MIDZ_FOR_START_1 |
+				priv->pwm_start_mid_z);
+
+	/* lookup and set split-capacitor charge period */
+	if (priv->charge_period == 0) {
+		regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
+	} else {
+		i = index_in_array(tas5086_charge_period,
+				   ARRAY_SIZE(tas5086_charge_period),
+				   priv->charge_period);
+		if (i >= 0)
+			regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE,
+				     i + 0x08);
+		else
+			dev_warn(dev,
+				 "Invalid split-cap charge period of %d ns.\n",
+				 priv->charge_period);
+	}
+
+	/* enable factory trim */
+	ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00);
+	if (ret < 0)
+		return ret;
+
+	/* start all channels */
+	ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20);
+	if (ret < 0)
+		return ret;
+
+	/* mute all channels for now */
+	ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE,
+			   TAS5086_SOFT_MUTE_ALL);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+/* TAS5086 controls */
+static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1);
+
+static const struct snd_kcontrol_new tas5086_controls[] = {
+	SOC_SINGLE_TLV("Master Playback Volume", TAS5086_MASTER_VOL,
+		       0, 0xff, 1, tas5086_dac_tlv),
+	SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume",
+			 TAS5086_CHANNEL_VOL(0), TAS5086_CHANNEL_VOL(1),
+			 0, 0xff, 1, tas5086_dac_tlv),
+	SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume",
+			 TAS5086_CHANNEL_VOL(2), TAS5086_CHANNEL_VOL(3),
+			 0, 0xff, 1, tas5086_dac_tlv),
+	SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume",
+			 TAS5086_CHANNEL_VOL(4), TAS5086_CHANNEL_VOL(5),
+			 0, 0xff, 1, tas5086_dac_tlv),
+	SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
+			    tas5086_get_deemph, tas5086_put_deemph),
+};
+
+/* Input mux controls */
+static const char *tas5086_dapm_sdin_texts[] =
+{
+	"SDIN1-L", "SDIN1-R", "SDIN2-L", "SDIN2-R",
+	"SDIN3-L", "SDIN3-R", "Ground (0)", "nc"
+};
+
+static const struct soc_enum tas5086_dapm_input_mux_enum[] = {
+	SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 20, 8, tas5086_dapm_sdin_texts),
+	SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 16, 8, tas5086_dapm_sdin_texts),
+	SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 12, 8, tas5086_dapm_sdin_texts),
+	SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 8,  8, tas5086_dapm_sdin_texts),
+	SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 4,  8, tas5086_dapm_sdin_texts),
+	SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 0,  8, tas5086_dapm_sdin_texts),
+};
+
+static const struct snd_kcontrol_new tas5086_dapm_input_mux_controls[] = {
+	SOC_DAPM_ENUM("Channel 1 input", tas5086_dapm_input_mux_enum[0]),
+	SOC_DAPM_ENUM("Channel 2 input", tas5086_dapm_input_mux_enum[1]),
+	SOC_DAPM_ENUM("Channel 3 input", tas5086_dapm_input_mux_enum[2]),
+	SOC_DAPM_ENUM("Channel 4 input", tas5086_dapm_input_mux_enum[3]),
+	SOC_DAPM_ENUM("Channel 5 input", tas5086_dapm_input_mux_enum[4]),
+	SOC_DAPM_ENUM("Channel 6 input", tas5086_dapm_input_mux_enum[5]),
+};
+
+/* Output mux controls */
+static const char *tas5086_dapm_channel_texts[] =
+	{ "Channel 1 Mux", "Channel 2 Mux", "Channel 3 Mux",
+	  "Channel 4 Mux", "Channel 5 Mux", "Channel 6 Mux" };
+
+static const struct soc_enum tas5086_dapm_output_mux_enum[] = {
+	SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 20, 6, tas5086_dapm_channel_texts),
+	SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 16, 6, tas5086_dapm_channel_texts),
+	SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 12, 6, tas5086_dapm_channel_texts),
+	SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 8,  6, tas5086_dapm_channel_texts),
+	SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 4,  6, tas5086_dapm_channel_texts),
+	SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 0,  6, tas5086_dapm_channel_texts),
+};
+
+static const struct snd_kcontrol_new tas5086_dapm_output_mux_controls[] = {
+	SOC_DAPM_ENUM("PWM1 Output", tas5086_dapm_output_mux_enum[0]),
+	SOC_DAPM_ENUM("PWM2 Output", tas5086_dapm_output_mux_enum[1]),
+	SOC_DAPM_ENUM("PWM3 Output", tas5086_dapm_output_mux_enum[2]),
+	SOC_DAPM_ENUM("PWM4 Output", tas5086_dapm_output_mux_enum[3]),
+	SOC_DAPM_ENUM("PWM5 Output", tas5086_dapm_output_mux_enum[4]),
+	SOC_DAPM_ENUM("PWM6 Output", tas5086_dapm_output_mux_enum[5]),
+};
+
+static const struct snd_soc_dapm_widget tas5086_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("SDIN1-L"),
+	SND_SOC_DAPM_INPUT("SDIN1-R"),
+	SND_SOC_DAPM_INPUT("SDIN2-L"),
+	SND_SOC_DAPM_INPUT("SDIN2-R"),
+	SND_SOC_DAPM_INPUT("SDIN3-L"),
+	SND_SOC_DAPM_INPUT("SDIN3-R"),
+	SND_SOC_DAPM_INPUT("SDIN4-L"),
+	SND_SOC_DAPM_INPUT("SDIN4-R"),
+
+	SND_SOC_DAPM_OUTPUT("PWM1"),
+	SND_SOC_DAPM_OUTPUT("PWM2"),
+	SND_SOC_DAPM_OUTPUT("PWM3"),
+	SND_SOC_DAPM_OUTPUT("PWM4"),
+	SND_SOC_DAPM_OUTPUT("PWM5"),
+	SND_SOC_DAPM_OUTPUT("PWM6"),
+
+	SND_SOC_DAPM_MUX("Channel 1 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_input_mux_controls[0]),
+	SND_SOC_DAPM_MUX("Channel 2 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_input_mux_controls[1]),
+	SND_SOC_DAPM_MUX("Channel 3 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_input_mux_controls[2]),
+	SND_SOC_DAPM_MUX("Channel 4 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_input_mux_controls[3]),
+	SND_SOC_DAPM_MUX("Channel 5 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_input_mux_controls[4]),
+	SND_SOC_DAPM_MUX("Channel 6 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_input_mux_controls[5]),
+
+	SND_SOC_DAPM_MUX("PWM1 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_output_mux_controls[0]),
+	SND_SOC_DAPM_MUX("PWM2 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_output_mux_controls[1]),
+	SND_SOC_DAPM_MUX("PWM3 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_output_mux_controls[2]),
+	SND_SOC_DAPM_MUX("PWM4 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_output_mux_controls[3]),
+	SND_SOC_DAPM_MUX("PWM5 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_output_mux_controls[4]),
+	SND_SOC_DAPM_MUX("PWM6 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_output_mux_controls[5]),
+};
+
+static const struct snd_soc_dapm_route tas5086_dapm_routes[] = {
+	/* SDIN inputs -> channel muxes */
+	{ "Channel 1 Mux", "SDIN1-L", "SDIN1-L" },
+	{ "Channel 1 Mux", "SDIN1-R", "SDIN1-R" },
+	{ "Channel 1 Mux", "SDIN2-L", "SDIN2-L" },
+	{ "Channel 1 Mux", "SDIN2-R", "SDIN2-R" },
+	{ "Channel 1 Mux", "SDIN3-L", "SDIN3-L" },
+	{ "Channel 1 Mux", "SDIN3-R", "SDIN3-R" },
+
+	{ "Channel 2 Mux", "SDIN1-L", "SDIN1-L" },
+	{ "Channel 2 Mux", "SDIN1-R", "SDIN1-R" },
+	{ "Channel 2 Mux", "SDIN2-L", "SDIN2-L" },
+	{ "Channel 2 Mux", "SDIN2-R", "SDIN2-R" },
+	{ "Channel 2 Mux", "SDIN3-L", "SDIN3-L" },
+	{ "Channel 2 Mux", "SDIN3-R", "SDIN3-R" },
+
+	{ "Channel 2 Mux", "SDIN1-L", "SDIN1-L" },
+	{ "Channel 2 Mux", "SDIN1-R", "SDIN1-R" },
+	{ "Channel 2 Mux", "SDIN2-L", "SDIN2-L" },
+	{ "Channel 2 Mux", "SDIN2-R", "SDIN2-R" },
+	{ "Channel 2 Mux", "SDIN3-L", "SDIN3-L" },
+	{ "Channel 2 Mux", "SDIN3-R", "SDIN3-R" },
+
+	{ "Channel 3 Mux", "SDIN1-L", "SDIN1-L" },
+	{ "Channel 3 Mux", "SDIN1-R", "SDIN1-R" },
+	{ "Channel 3 Mux", "SDIN2-L", "SDIN2-L" },
+	{ "Channel 3 Mux", "SDIN2-R", "SDIN2-R" },
+	{ "Channel 3 Mux", "SDIN3-L", "SDIN3-L" },
+	{ "Channel 3 Mux", "SDIN3-R", "SDIN3-R" },
+
+	{ "Channel 4 Mux", "SDIN1-L", "SDIN1-L" },
+	{ "Channel 4 Mux", "SDIN1-R", "SDIN1-R" },
+	{ "Channel 4 Mux", "SDIN2-L", "SDIN2-L" },
+	{ "Channel 4 Mux", "SDIN2-R", "SDIN2-R" },
+	{ "Channel 4 Mux", "SDIN3-L", "SDIN3-L" },
+	{ "Channel 4 Mux", "SDIN3-R", "SDIN3-R" },
+
+	{ "Channel 5 Mux", "SDIN1-L", "SDIN1-L" },
+	{ "Channel 5 Mux", "SDIN1-R", "SDIN1-R" },
+	{ "Channel 5 Mux", "SDIN2-L", "SDIN2-L" },
+	{ "Channel 5 Mux", "SDIN2-R", "SDIN2-R" },
+	{ "Channel 5 Mux", "SDIN3-L", "SDIN3-L" },
+	{ "Channel 5 Mux", "SDIN3-R", "SDIN3-R" },
+
+	{ "Channel 6 Mux", "SDIN1-L", "SDIN1-L" },
+	{ "Channel 6 Mux", "SDIN1-R", "SDIN1-R" },
+	{ "Channel 6 Mux", "SDIN2-L", "SDIN2-L" },
+	{ "Channel 6 Mux", "SDIN2-R", "SDIN2-R" },
+	{ "Channel 6 Mux", "SDIN3-L", "SDIN3-L" },
+	{ "Channel 6 Mux", "SDIN3-R", "SDIN3-R" },
+
+	/* Channel muxes -> PWM muxes */
+	{ "PWM1 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+	{ "PWM2 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+	{ "PWM3 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+	{ "PWM4 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+	{ "PWM5 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+	{ "PWM6 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+
+	{ "PWM1 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+	{ "PWM2 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+	{ "PWM3 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+	{ "PWM4 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+	{ "PWM5 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+	{ "PWM6 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+
+	{ "PWM1 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+	{ "PWM2 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+	{ "PWM3 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+	{ "PWM4 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+	{ "PWM5 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+	{ "PWM6 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+
+	{ "PWM1 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+	{ "PWM2 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+	{ "PWM3 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+	{ "PWM4 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+	{ "PWM5 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+	{ "PWM6 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+
+	{ "PWM1 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+	{ "PWM2 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+	{ "PWM3 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+	{ "PWM4 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+	{ "PWM5 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+	{ "PWM6 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+
+	{ "PWM1 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+	{ "PWM2 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+	{ "PWM3 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+	{ "PWM4 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+	{ "PWM5 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+	{ "PWM6 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+
+	/* The PWM muxes are directly connected to the PWM outputs */
+	{ "PWM1", NULL, "PWM1 Mux" },
+	{ "PWM2", NULL, "PWM2 Mux" },
+	{ "PWM3", NULL, "PWM3 Mux" },
+	{ "PWM4", NULL, "PWM4 Mux" },
+	{ "PWM5", NULL, "PWM5 Mux" },
+	{ "PWM6", NULL, "PWM6 Mux" },
+
+};
+
+static const struct snd_soc_dai_ops tas5086_dai_ops = {
+	.hw_params	= tas5086_hw_params,
+	.set_sysclk	= tas5086_set_dai_sysclk,
+	.set_fmt	= tas5086_set_dai_fmt,
+	.mute_stream	= tas5086_mute_stream,
+};
+
+static struct snd_soc_dai_driver tas5086_dai = {
+	.name = "tas5086-hifi",
+	.playback = {
+		.stream_name	= "Playback",
+		.channels_min	= 2,
+		.channels_max	= 6,
+		.rates		= TAS5086_PCM_RATES,
+		.formats	= TAS5086_PCM_FORMATS,
+	},
+	.ops = &tas5086_dai_ops,
+};
+
+#ifdef CONFIG_PM
+static int tas5086_soc_suspend(struct snd_soc_component *component)
+{
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	/* Shut down all channels */
+	ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x60);
+	if (ret < 0)
+		return ret;
+
+	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
+
+	return 0;
+}
+
+static int tas5086_soc_resume(struct snd_soc_component *component)
+{
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
+	if (ret < 0)
+		return ret;
+
+	tas5086_reset(priv);
+	regcache_mark_dirty(priv->regmap);
+
+	ret = tas5086_init(component->dev, priv);
+	if (ret < 0)
+		return ret;
+
+	ret = regcache_sync(priv->regmap);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+#else
+#define tas5086_soc_suspend	NULL
+#define tas5086_soc_resume	NULL
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_OF
+static const struct of_device_id tas5086_dt_ids[] = {
+	{ .compatible = "ti,tas5086", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tas5086_dt_ids);
+#endif
+
+static int tas5086_probe(struct snd_soc_component *component)
+{
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
+	int i, ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to enable regulators: %d\n", ret);
+		return ret;
+	}
+
+	priv->pwm_start_mid_z = 0;
+	priv->charge_period = 1300000; /* hardware default is 1300 ms */
+
+	if (of_match_device(of_match_ptr(tas5086_dt_ids), component->dev)) {
+		struct device_node *of_node = component->dev->of_node;
+
+		of_property_read_u32(of_node, "ti,charge-period",
+				     &priv->charge_period);
+
+		for (i = 0; i < 6; i++) {
+			char name[25];
+
+			snprintf(name, sizeof(name),
+				 "ti,mid-z-channel-%d", i + 1);
+
+			if (of_get_property(of_node, name, NULL) != NULL)
+				priv->pwm_start_mid_z |= 1 << i;
+		}
+	}
+
+	tas5086_reset(priv);
+	ret = tas5086_init(component->dev, priv);
+	if (ret < 0)
+		goto exit_disable_regulators;
+
+	/* set master volume to 0 dB */
+	ret = regmap_write(priv->regmap, TAS5086_MASTER_VOL, 0x30);
+	if (ret < 0)
+		goto exit_disable_regulators;
+
+	return 0;
+
+exit_disable_regulators:
+	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
+
+	return ret;
+}
+
+static void tas5086_remove(struct snd_soc_component *component)
+{
+	struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
+
+	if (gpio_is_valid(priv->gpio_nreset))
+		/* Set codec to the reset state */
+		gpio_set_value(priv->gpio_nreset, 0);
+
+	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
+};
+
+static const struct snd_soc_component_driver soc_component_dev_tas5086 = {
+	.probe			= tas5086_probe,
+	.remove			= tas5086_remove,
+	.suspend		= tas5086_soc_suspend,
+	.resume			= tas5086_soc_resume,
+	.controls		= tas5086_controls,
+	.num_controls		= ARRAY_SIZE(tas5086_controls),
+	.dapm_widgets		= tas5086_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tas5086_dapm_widgets),
+	.dapm_routes		= tas5086_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tas5086_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct i2c_device_id tas5086_i2c_id[] = {
+	{ "tas5086", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas5086_i2c_id);
+
+static const struct regmap_config tas5086_regmap = {
+	.reg_bits		= 8,
+	.val_bits		= 32,
+	.max_register		= TAS5086_MAX_REGISTER,
+	.reg_defaults		= tas5086_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(tas5086_reg_defaults),
+	.cache_type		= REGCACHE_RBTREE,
+	.volatile_reg		= tas5086_volatile_reg,
+	.writeable_reg		= tas5086_writeable_reg,
+	.readable_reg		= tas5086_accessible_reg,
+	.reg_read		= tas5086_reg_read,
+	.reg_write		= tas5086_reg_write,
+};
+
+static int tas5086_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct tas5086_private *priv;
+	struct device *dev = &i2c->dev;
+	int gpio_nreset = -EINVAL;
+	int i, ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+		priv->supplies[i].supply = supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
+				      priv->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to get regulators: %d\n", ret);
+		return ret;
+	}
+
+	priv->regmap = devm_regmap_init(dev, NULL, i2c, &tas5086_regmap);
+	if (IS_ERR(priv->regmap)) {
+		ret = PTR_ERR(priv->regmap);
+		dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, priv);
+
+	if (of_match_device(of_match_ptr(tas5086_dt_ids), dev)) {
+		struct device_node *of_node = dev->of_node;
+		gpio_nreset = of_get_named_gpio(of_node, "reset-gpio", 0);
+	}
+
+	if (gpio_is_valid(gpio_nreset))
+		if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset"))
+			gpio_nreset = -EINVAL;
+
+	priv->gpio_nreset = gpio_nreset;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable regulators: %d\n", ret);
+		return ret;
+	}
+
+	tas5086_reset(priv);
+
+	/* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */
+	ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i);
+	if (ret == 0 && i != 0x3) {
+		dev_err(dev,
+			"Failed to identify TAS5086 codec (got %02x)\n", i);
+		ret = -ENODEV;
+	}
+
+	/*
+	 * The chip has been identified, so we can turn off the power
+	 * again until the dai link is set up.
+	 */
+	regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
+
+	if (ret == 0)
+		ret = devm_snd_soc_register_component(&i2c->dev,
+					     &soc_component_dev_tas5086,
+					     &tas5086_dai, 1);
+
+	return ret;
+}
+
+static int tas5086_i2c_remove(struct i2c_client *i2c)
+{
+	return 0;
+}
+
+static struct i2c_driver tas5086_i2c_driver = {
+	.driver = {
+		.name	= "tas5086",
+		.of_match_table = of_match_ptr(tas5086_dt_ids),
+	},
+	.id_table	= tas5086_i2c_id,
+	.probe		= tas5086_i2c_probe,
+	.remove		= tas5086_i2c_remove,
+};
+
+module_i2c_driver(tas5086_i2c_driver);
+
+MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>");
+MODULE_DESCRIPTION("Texas Instruments TAS5086 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c
new file mode 100644
index 0000000..ca2dfe1
--- /dev/null
+++ b/sound/soc/codecs/tas571x.c
@@ -0,0 +1,918 @@
+/*
+ * TAS571x amplifier audio driver
+ *
+ * Copyright (C) 2015 Google, Inc.
+ * Copyright (c) 2013 Daniel Mack <zonque@gmail.com>
+ *
+ * TAS5721 support:
+ * Copyright (C) 2016 Petr Kulhavy, Barix AG <petr@barix.com>
+ *
+ * TAS5707 support:
+ * Copyright (C) 2018 Jerome Brunet, Baylibre SAS <jbrunet@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/stddef.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <asm/unaligned.h>
+
+#include "tas571x.h"
+
+#define TAS571X_MAX_SUPPLIES		6
+
+struct tas571x_chip {
+	const char			*const *supply_names;
+	int				num_supply_names;
+	const struct snd_kcontrol_new	*controls;
+	int				num_controls;
+	const struct regmap_config	*regmap_config;
+	int				vol_reg_size;
+};
+
+struct tas571x_private {
+	const struct tas571x_chip	*chip;
+	struct regmap			*regmap;
+	struct regulator_bulk_data	supplies[TAS571X_MAX_SUPPLIES];
+	struct clk			*mclk;
+	unsigned int			format;
+	struct gpio_desc		*reset_gpio;
+	struct gpio_desc		*pdn_gpio;
+	struct snd_soc_component_driver	component_driver;
+};
+
+static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg)
+{
+	switch (reg) {
+	case TAS571X_MVOL_REG:
+	case TAS571X_CH1_VOL_REG:
+	case TAS571X_CH2_VOL_REG:
+		return priv->chip->vol_reg_size;
+	case TAS571X_INPUT_MUX_REG:
+	case TAS571X_CH4_SRC_SELECT_REG:
+	case TAS571X_PWM_MUX_REG:
+	case TAS5717_CH1_RIGHT_CH_MIX_REG:
+	case TAS5717_CH1_LEFT_CH_MIX_REG:
+	case TAS5717_CH2_LEFT_CH_MIX_REG:
+	case TAS5717_CH2_RIGHT_CH_MIX_REG:
+		return 4;
+	default:
+		return 1;
+	}
+}
+
+static int tas571x_reg_write(void *context, unsigned int reg,
+			     unsigned int value)
+{
+	struct i2c_client *client = context;
+	struct tas571x_private *priv = i2c_get_clientdata(client);
+	unsigned int i, size;
+	uint8_t buf[5];
+	int ret;
+
+	size = tas571x_register_size(priv, reg);
+	buf[0] = reg;
+
+	for (i = size; i >= 1; --i) {
+		buf[i] = value;
+		value >>= 8;
+	}
+
+	ret = i2c_master_send(client, buf, size + 1);
+	if (ret == size + 1)
+		return 0;
+	else if (ret < 0)
+		return ret;
+	else
+		return -EIO;
+}
+
+static int tas571x_reg_read(void *context, unsigned int reg,
+			    unsigned int *value)
+{
+	struct i2c_client *client = context;
+	struct tas571x_private *priv = i2c_get_clientdata(client);
+	uint8_t send_buf, recv_buf[4];
+	struct i2c_msg msgs[2];
+	unsigned int size;
+	unsigned int i;
+	int ret;
+
+	size = tas571x_register_size(priv, reg);
+	send_buf = reg;
+
+	msgs[0].addr = client->addr;
+	msgs[0].len = sizeof(send_buf);
+	msgs[0].buf = &send_buf;
+	msgs[0].flags = 0;
+
+	msgs[1].addr = client->addr;
+	msgs[1].len = size;
+	msgs[1].buf = recv_buf;
+	msgs[1].flags = I2C_M_RD;
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0)
+		return ret;
+	else if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	*value = 0;
+
+	for (i = 0; i < size; i++) {
+		*value <<= 8;
+		*value |= recv_buf[i];
+	}
+
+	return 0;
+}
+
+/*
+ * register write for 8- and 20-byte registers
+ */
+static int tas571x_reg_write_multiword(struct i2c_client *client,
+		unsigned int reg, const long values[], size_t len)
+{
+	size_t i;
+	uint8_t *buf, *p;
+	int ret;
+	size_t send_size = 1 + len * sizeof(uint32_t);
+
+	buf = kzalloc(send_size, GFP_KERNEL | GFP_DMA);
+	if (!buf)
+		return -ENOMEM;
+	buf[0] = reg;
+
+	for (i = 0, p = buf + 1; i < len; i++, p += sizeof(uint32_t))
+		put_unaligned_be32(values[i], p);
+
+	ret = i2c_master_send(client, buf, send_size);
+
+	kfree(buf);
+
+	if (ret == send_size)
+		return 0;
+	else if (ret < 0)
+		return ret;
+	else
+		return -EIO;
+}
+
+/*
+ * register read for 8- and 20-byte registers
+ */
+static int tas571x_reg_read_multiword(struct i2c_client *client,
+		unsigned int reg, long values[], size_t len)
+{
+	unsigned int i;
+	uint8_t send_buf;
+	uint8_t *recv_buf, *p;
+	struct i2c_msg msgs[2];
+	unsigned int recv_size = len * sizeof(uint32_t);
+	int ret;
+
+	recv_buf = kzalloc(recv_size, GFP_KERNEL | GFP_DMA);
+	if (!recv_buf)
+		return -ENOMEM;
+
+	send_buf = reg;
+
+	msgs[0].addr = client->addr;
+	msgs[0].len = sizeof(send_buf);
+	msgs[0].buf = &send_buf;
+	msgs[0].flags = 0;
+
+	msgs[1].addr = client->addr;
+	msgs[1].len = recv_size;
+	msgs[1].buf = recv_buf;
+	msgs[1].flags = I2C_M_RD;
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0)
+		goto err_ret;
+	else if (ret != ARRAY_SIZE(msgs)) {
+		ret = -EIO;
+		goto err_ret;
+	}
+
+	for (i = 0, p = recv_buf; i < len; i++, p += sizeof(uint32_t))
+		values[i] = get_unaligned_be32(p);
+
+err_ret:
+	kfree(recv_buf);
+	return ret;
+}
+
+/*
+ * Integer array controls for setting biquad, mixer, DRC coefficients.
+ * According to the datasheet each coefficient is effectively 26bits,
+ * i.e. stored as 32bits, where bits [31:26] are ignored.
+ * TI's TAS57xx Graphical Development Environment tool however produces
+ * coefficients with more than 26 bits. For this reason we allow values
+ * in the full 32-bits reange.
+ * The coefficients are ordered as given in the TAS571x data sheet:
+ * b0, b1, b2, a1, a2
+ */
+
+static int tas571x_coefficient_info(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_info *uinfo)
+{
+	int numcoef = kcontrol->private_value >> 16;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = numcoef;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xffffffff;
+	return 0;
+}
+
+static int tas571x_coefficient_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
+	int numcoef = kcontrol->private_value >> 16;
+	int index = kcontrol->private_value & 0xffff;
+
+	return tas571x_reg_read_multiword(i2c, index,
+		ucontrol->value.integer.value, numcoef);
+}
+
+static int tas571x_coefficient_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
+	int numcoef = kcontrol->private_value >> 16;
+	int index = kcontrol->private_value & 0xffff;
+
+	return tas571x_reg_write_multiword(i2c, index,
+		ucontrol->value.integer.value, numcoef);
+}
+
+static int tas571x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
+{
+	struct tas571x_private *priv = snd_soc_component_get_drvdata(dai->component);
+
+	priv->format = format;
+
+	return 0;
+}
+
+static int tas571x_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct tas571x_private *priv = snd_soc_component_get_drvdata(dai->component);
+	u32 val;
+
+	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val = 0x00;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		val = 0x03;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val = 0x06;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (params_width(params) >= 24)
+		val += 2;
+	else if (params_width(params) >= 20)
+		val += 1;
+
+	return regmap_update_bits(priv->regmap, TAS571X_SDI_REG,
+				  TAS571X_SDI_FMT_MASK, val);
+}
+
+static int tas571x_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 sysctl2;
+	int ret;
+
+	sysctl2 = mute ? TAS571X_SYS_CTRL_2_SDN_MASK : 0;
+
+	ret = snd_soc_component_update_bits(component,
+			    TAS571X_SYS_CTRL_2_REG,
+		     TAS571X_SYS_CTRL_2_SDN_MASK,
+		     sysctl2);
+	usleep_range(1000, 2000);
+
+	return ret;
+}
+
+static int tas571x_set_bias_level(struct snd_soc_component *component,
+				  enum snd_soc_bias_level level)
+{
+	struct tas571x_private *priv = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			if (!IS_ERR(priv->mclk)) {
+				ret = clk_prepare_enable(priv->mclk);
+				if (ret) {
+					dev_err(component->dev,
+						"Failed to enable master clock: %d\n",
+						ret);
+					return ret;
+				}
+			}
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		if (!IS_ERR(priv->mclk))
+			clk_disable_unprepare(priv->mclk);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tas571x_dai_ops = {
+	.set_fmt	= tas571x_set_dai_fmt,
+	.hw_params	= tas571x_hw_params,
+	.digital_mute	= tas571x_mute,
+};
+
+
+#define BIQUAD_COEFS(xname, reg) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = tas571x_coefficient_info, \
+	.get = tas571x_coefficient_get,\
+	.put = tas571x_coefficient_put, \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.private_value = reg | (5 << 16) }
+
+static const char *const tas5711_supply_names[] = {
+	"AVDD",
+	"DVDD",
+	"PVDD_A",
+	"PVDD_B",
+	"PVDD_C",
+	"PVDD_D",
+};
+
+static const DECLARE_TLV_DB_SCALE(tas5711_volume_tlv, -10350, 50, 1);
+
+static const struct snd_kcontrol_new tas5711_controls[] = {
+	SOC_SINGLE_TLV("Master Volume",
+		       TAS571X_MVOL_REG,
+		       0, 0xff, 1, tas5711_volume_tlv),
+	SOC_DOUBLE_R_TLV("Speaker Volume",
+			 TAS571X_CH1_VOL_REG,
+			 TAS571X_CH2_VOL_REG,
+			 0, 0xff, 1, tas5711_volume_tlv),
+	SOC_DOUBLE("Speaker Switch",
+		   TAS571X_SOFT_MUTE_REG,
+		   TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
+		   1, 1),
+};
+
+static const struct regmap_range tas571x_readonly_regs_range[] = {
+	regmap_reg_range(TAS571X_CLK_CTRL_REG,  TAS571X_DEV_ID_REG),
+};
+
+static const struct regmap_range tas571x_volatile_regs_range[] = {
+	regmap_reg_range(TAS571X_CLK_CTRL_REG,  TAS571X_ERR_STATUS_REG),
+	regmap_reg_range(TAS571X_OSC_TRIM_REG,  TAS571X_OSC_TRIM_REG),
+};
+
+static const struct regmap_access_table tas571x_write_regs = {
+	.no_ranges =	tas571x_readonly_regs_range,
+	.n_no_ranges =	ARRAY_SIZE(tas571x_readonly_regs_range),
+};
+
+static const struct regmap_access_table tas571x_volatile_regs = {
+	.yes_ranges =	tas571x_volatile_regs_range,
+	.n_yes_ranges =	ARRAY_SIZE(tas571x_volatile_regs_range),
+
+};
+
+static const struct reg_default tas5711_reg_defaults[] = {
+	{ 0x04, 0x05 },
+	{ 0x05, 0x40 },
+	{ 0x06, 0x00 },
+	{ 0x07, 0xff },
+	{ 0x08, 0x30 },
+	{ 0x09, 0x30 },
+	{ 0x1b, 0x82 },
+};
+
+static const struct regmap_config tas5711_regmap_config = {
+	.reg_bits			= 8,
+	.val_bits			= 32,
+	.max_register			= 0xff,
+	.reg_read			= tas571x_reg_read,
+	.reg_write			= tas571x_reg_write,
+	.reg_defaults			= tas5711_reg_defaults,
+	.num_reg_defaults		= ARRAY_SIZE(tas5711_reg_defaults),
+	.cache_type			= REGCACHE_RBTREE,
+	.wr_table			= &tas571x_write_regs,
+	.volatile_table			= &tas571x_volatile_regs,
+};
+
+static const struct tas571x_chip tas5711_chip = {
+	.supply_names			= tas5711_supply_names,
+	.num_supply_names		= ARRAY_SIZE(tas5711_supply_names),
+	.controls			= tas5711_controls,
+	.num_controls			= ARRAY_SIZE(tas5711_controls),
+	.regmap_config			= &tas5711_regmap_config,
+	.vol_reg_size			= 1,
+};
+
+static const struct regmap_range tas5707_volatile_regs_range[] = {
+	regmap_reg_range(TAS571X_CLK_CTRL_REG,  TAS571X_ERR_STATUS_REG),
+	regmap_reg_range(TAS571X_OSC_TRIM_REG,  TAS571X_OSC_TRIM_REG),
+	regmap_reg_range(TAS5707_CH1_BQ0_REG, TAS5707_CH2_BQ6_REG),
+};
+
+static const struct regmap_access_table tas5707_volatile_regs = {
+	.yes_ranges =	tas5707_volatile_regs_range,
+	.n_yes_ranges =	ARRAY_SIZE(tas5707_volatile_regs_range),
+
+};
+
+static const DECLARE_TLV_DB_SCALE(tas5707_volume_tlv, -7900, 50, 1);
+
+static const char * const tas5707_volume_slew_step_txt[] = {
+	"256", "512", "1024", "2048",
+};
+
+static const unsigned int tas5707_volume_slew_step_values[] = {
+	3, 0, 1, 2,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(tas5707_volume_slew_step_enum,
+				  TAS571X_VOL_CFG_REG, 0, 0x3,
+				  tas5707_volume_slew_step_txt,
+				  tas5707_volume_slew_step_values);
+
+static const struct snd_kcontrol_new tas5707_controls[] = {
+	SOC_SINGLE_TLV("Master Volume",
+		       TAS571X_MVOL_REG,
+		       0, 0xff, 1, tas5707_volume_tlv),
+	SOC_DOUBLE_R_TLV("Speaker Volume",
+			 TAS571X_CH1_VOL_REG,
+			 TAS571X_CH2_VOL_REG,
+			 0, 0xff, 1, tas5707_volume_tlv),
+	SOC_DOUBLE("Speaker Switch",
+		   TAS571X_SOFT_MUTE_REG,
+		   TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
+		   1, 1),
+
+	SOC_ENUM("Slew Rate Steps", tas5707_volume_slew_step_enum),
+
+	BIQUAD_COEFS("CH1 - Biquad 0", TAS5707_CH1_BQ0_REG),
+	BIQUAD_COEFS("CH1 - Biquad 1", TAS5707_CH1_BQ1_REG),
+	BIQUAD_COEFS("CH1 - Biquad 2", TAS5707_CH1_BQ2_REG),
+	BIQUAD_COEFS("CH1 - Biquad 3", TAS5707_CH1_BQ3_REG),
+	BIQUAD_COEFS("CH1 - Biquad 4", TAS5707_CH1_BQ4_REG),
+	BIQUAD_COEFS("CH1 - Biquad 5", TAS5707_CH1_BQ5_REG),
+	BIQUAD_COEFS("CH1 - Biquad 6", TAS5707_CH1_BQ6_REG),
+
+	BIQUAD_COEFS("CH2 - Biquad 0", TAS5707_CH2_BQ0_REG),
+	BIQUAD_COEFS("CH2 - Biquad 1", TAS5707_CH2_BQ1_REG),
+	BIQUAD_COEFS("CH2 - Biquad 2", TAS5707_CH2_BQ2_REG),
+	BIQUAD_COEFS("CH2 - Biquad 3", TAS5707_CH2_BQ3_REG),
+	BIQUAD_COEFS("CH2 - Biquad 4", TAS5707_CH2_BQ4_REG),
+	BIQUAD_COEFS("CH2 - Biquad 5", TAS5707_CH2_BQ5_REG),
+	BIQUAD_COEFS("CH2 - Biquad 6", TAS5707_CH2_BQ6_REG),
+};
+
+static const struct reg_default tas5707_reg_defaults[] = {
+	{TAS571X_CLK_CTRL_REG,		0x6c},
+	{TAS571X_DEV_ID_REG,		0x70},
+	{TAS571X_ERR_STATUS_REG,	0x00},
+	{TAS571X_SYS_CTRL_1_REG,	0xa0},
+	{TAS571X_SDI_REG,		0x05},
+	{TAS571X_SYS_CTRL_2_REG,	0x40},
+	{TAS571X_SOFT_MUTE_REG,		0x00},
+	{TAS571X_MVOL_REG,		0xff},
+	{TAS571X_CH1_VOL_REG,		0x30},
+	{TAS571X_CH2_VOL_REG,		0x30},
+	{TAS571X_VOL_CFG_REG,		0x91},
+	{TAS571X_MODULATION_LIMIT_REG,	0x02},
+	{TAS571X_IC_DELAY_CH1_REG,	0xac},
+	{TAS571X_IC_DELAY_CH2_REG,	0x54},
+	{TAS571X_IC_DELAY_CH3_REG,	0xac},
+	{TAS571X_IC_DELAY_CH4_REG,	0x54},
+	{TAS571X_START_STOP_PERIOD_REG,	0x0f},
+	{TAS571X_OSC_TRIM_REG,		0x82},
+	{TAS571X_BKND_ERR_REG,		0x02},
+	{TAS571X_INPUT_MUX_REG,		0x17772},
+	{TAS571X_PWM_MUX_REG,		0x1021345},
+};
+
+static const struct regmap_config tas5707_regmap_config = {
+	.reg_bits			= 8,
+	.val_bits			= 32,
+	.max_register			= 0xff,
+	.reg_read			= tas571x_reg_read,
+	.reg_write			= tas571x_reg_write,
+	.reg_defaults			= tas5707_reg_defaults,
+	.num_reg_defaults		= ARRAY_SIZE(tas5707_reg_defaults),
+	.cache_type			= REGCACHE_RBTREE,
+	.wr_table			= &tas571x_write_regs,
+	.volatile_table			= &tas5707_volatile_regs,
+};
+
+static const struct tas571x_chip tas5707_chip = {
+	.supply_names			= tas5711_supply_names,
+	.num_supply_names		= ARRAY_SIZE(tas5711_supply_names),
+	.controls			= tas5707_controls,
+	.num_controls			= ARRAY_SIZE(tas5707_controls),
+	.regmap_config			= &tas5707_regmap_config,
+	.vol_reg_size			= 1,
+};
+
+static const char *const tas5717_supply_names[] = {
+	"AVDD",
+	"DVDD",
+	"HPVDD",
+	"PVDD_AB",
+	"PVDD_CD",
+};
+
+static const DECLARE_TLV_DB_SCALE(tas5717_volume_tlv, -10375, 25, 0);
+
+static const struct snd_kcontrol_new tas5717_controls[] = {
+	/* MVOL LSB is ignored - see comments in tas571x_i2c_probe() */
+	SOC_SINGLE_TLV("Master Volume",
+		       TAS571X_MVOL_REG, 1, 0x1ff, 1,
+		       tas5717_volume_tlv),
+	SOC_DOUBLE_R_TLV("Speaker Volume",
+			 TAS571X_CH1_VOL_REG, TAS571X_CH2_VOL_REG,
+			 1, 0x1ff, 1, tas5717_volume_tlv),
+	SOC_DOUBLE("Speaker Switch",
+		   TAS571X_SOFT_MUTE_REG,
+		   TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
+		   1, 1),
+
+	SOC_DOUBLE_R_RANGE("CH1 Mixer Volume",
+			   TAS5717_CH1_LEFT_CH_MIX_REG,
+			   TAS5717_CH1_RIGHT_CH_MIX_REG,
+			   16, 0, 0x80, 0),
+
+	SOC_DOUBLE_R_RANGE("CH2 Mixer Volume",
+			   TAS5717_CH2_LEFT_CH_MIX_REG,
+			   TAS5717_CH2_RIGHT_CH_MIX_REG,
+			   16, 0, 0x80, 0),
+
+	/*
+	 * The biquads are named according to the register names.
+	 * Please note that TI's TAS57xx Graphical Development Environment
+	 * tool names them different.
+	 */
+	BIQUAD_COEFS("CH1 - Biquad 0", TAS5717_CH1_BQ0_REG),
+	BIQUAD_COEFS("CH1 - Biquad 1", TAS5717_CH1_BQ1_REG),
+	BIQUAD_COEFS("CH1 - Biquad 2", TAS5717_CH1_BQ2_REG),
+	BIQUAD_COEFS("CH1 - Biquad 3", TAS5717_CH1_BQ3_REG),
+	BIQUAD_COEFS("CH1 - Biquad 4", TAS5717_CH1_BQ4_REG),
+	BIQUAD_COEFS("CH1 - Biquad 5", TAS5717_CH1_BQ5_REG),
+	BIQUAD_COEFS("CH1 - Biquad 6", TAS5717_CH1_BQ6_REG),
+	BIQUAD_COEFS("CH1 - Biquad 7", TAS5717_CH1_BQ7_REG),
+	BIQUAD_COEFS("CH1 - Biquad 8", TAS5717_CH1_BQ8_REG),
+	BIQUAD_COEFS("CH1 - Biquad 9", TAS5717_CH1_BQ9_REG),
+	BIQUAD_COEFS("CH1 - Biquad 10", TAS5717_CH1_BQ10_REG),
+	BIQUAD_COEFS("CH1 - Biquad 11", TAS5717_CH1_BQ11_REG),
+
+	BIQUAD_COEFS("CH2 - Biquad 0", TAS5717_CH2_BQ0_REG),
+	BIQUAD_COEFS("CH2 - Biquad 1", TAS5717_CH2_BQ1_REG),
+	BIQUAD_COEFS("CH2 - Biquad 2", TAS5717_CH2_BQ2_REG),
+	BIQUAD_COEFS("CH2 - Biquad 3", TAS5717_CH2_BQ3_REG),
+	BIQUAD_COEFS("CH2 - Biquad 4", TAS5717_CH2_BQ4_REG),
+	BIQUAD_COEFS("CH2 - Biquad 5", TAS5717_CH2_BQ5_REG),
+	BIQUAD_COEFS("CH2 - Biquad 6", TAS5717_CH2_BQ6_REG),
+	BIQUAD_COEFS("CH2 - Biquad 7", TAS5717_CH2_BQ7_REG),
+	BIQUAD_COEFS("CH2 - Biquad 8", TAS5717_CH2_BQ8_REG),
+	BIQUAD_COEFS("CH2 - Biquad 9", TAS5717_CH2_BQ9_REG),
+	BIQUAD_COEFS("CH2 - Biquad 10", TAS5717_CH2_BQ10_REG),
+	BIQUAD_COEFS("CH2 - Biquad 11", TAS5717_CH2_BQ11_REG),
+
+	BIQUAD_COEFS("CH3 - Biquad 0", TAS5717_CH3_BQ0_REG),
+	BIQUAD_COEFS("CH3 - Biquad 1", TAS5717_CH3_BQ1_REG),
+
+	BIQUAD_COEFS("CH4 - Biquad 0", TAS5717_CH4_BQ0_REG),
+	BIQUAD_COEFS("CH4 - Biquad 1", TAS5717_CH4_BQ1_REG),
+};
+
+static const struct reg_default tas5717_reg_defaults[] = {
+	{ 0x04, 0x05 },
+	{ 0x05, 0x40 },
+	{ 0x06, 0x00 },
+	{ 0x07, 0x03ff },
+	{ 0x08, 0x00c0 },
+	{ 0x09, 0x00c0 },
+	{ 0x1b, 0x82 },
+	{ TAS5717_CH1_RIGHT_CH_MIX_REG, 0x0 },
+	{ TAS5717_CH1_LEFT_CH_MIX_REG, 0x800000},
+	{ TAS5717_CH2_LEFT_CH_MIX_REG, 0x0 },
+	{ TAS5717_CH2_RIGHT_CH_MIX_REG, 0x800000},
+};
+
+static const struct regmap_config tas5717_regmap_config = {
+	.reg_bits			= 8,
+	.val_bits			= 32,
+	.max_register			= 0xff,
+	.reg_read			= tas571x_reg_read,
+	.reg_write			= tas571x_reg_write,
+	.reg_defaults			= tas5717_reg_defaults,
+	.num_reg_defaults		= ARRAY_SIZE(tas5717_reg_defaults),
+	.cache_type			= REGCACHE_RBTREE,
+	.wr_table			= &tas571x_write_regs,
+	.volatile_table			= &tas571x_volatile_regs,
+};
+
+/* This entry is reused for tas5719 as the software interface is identical. */
+static const struct tas571x_chip tas5717_chip = {
+	.supply_names			= tas5717_supply_names,
+	.num_supply_names		= ARRAY_SIZE(tas5717_supply_names),
+	.controls			= tas5717_controls,
+	.num_controls			= ARRAY_SIZE(tas5717_controls),
+	.regmap_config			= &tas5717_regmap_config,
+	.vol_reg_size			= 2,
+};
+
+static const char *const tas5721_supply_names[] = {
+	"AVDD",
+	"DVDD",
+	"DRVDD",
+	"PVDD",
+};
+
+static const struct snd_kcontrol_new tas5721_controls[] = {
+	SOC_SINGLE_TLV("Master Volume",
+		       TAS571X_MVOL_REG,
+		       0, 0xff, 1, tas5711_volume_tlv),
+	SOC_DOUBLE_R_TLV("Speaker Volume",
+			 TAS571X_CH1_VOL_REG,
+			 TAS571X_CH2_VOL_REG,
+			 0, 0xff, 1, tas5711_volume_tlv),
+	SOC_DOUBLE("Speaker Switch",
+		   TAS571X_SOFT_MUTE_REG,
+		   TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
+		   1, 1),
+};
+
+static const struct reg_default tas5721_reg_defaults[] = {
+	{TAS571X_CLK_CTRL_REG,		0x6c},
+	{TAS571X_DEV_ID_REG,		0x00},
+	{TAS571X_ERR_STATUS_REG,	0x00},
+	{TAS571X_SYS_CTRL_1_REG,	0xa0},
+	{TAS571X_SDI_REG,		0x05},
+	{TAS571X_SYS_CTRL_2_REG,	0x40},
+	{TAS571X_SOFT_MUTE_REG,		0x00},
+	{TAS571X_MVOL_REG,		0xff},
+	{TAS571X_CH1_VOL_REG,		0x30},
+	{TAS571X_CH2_VOL_REG,		0x30},
+	{TAS571X_CH3_VOL_REG,		0x30},
+	{TAS571X_VOL_CFG_REG,		0x91},
+	{TAS571X_MODULATION_LIMIT_REG,	0x02},
+	{TAS571X_IC_DELAY_CH1_REG,	0xac},
+	{TAS571X_IC_DELAY_CH2_REG,	0x54},
+	{TAS571X_IC_DELAY_CH3_REG,	0xac},
+	{TAS571X_IC_DELAY_CH4_REG,	0x54},
+	{TAS571X_PWM_CH_SDN_GROUP_REG,	0x30},
+	{TAS571X_START_STOP_PERIOD_REG,	0x0f},
+	{TAS571X_OSC_TRIM_REG,		0x82},
+	{TAS571X_BKND_ERR_REG,		0x02},
+	{TAS571X_INPUT_MUX_REG,		0x17772},
+	{TAS571X_CH4_SRC_SELECT_REG,	0x4303},
+	{TAS571X_PWM_MUX_REG,		0x1021345},
+};
+
+static const struct regmap_config tas5721_regmap_config = {
+	.reg_bits			= 8,
+	.val_bits			= 32,
+	.max_register			= 0xff,
+	.reg_read			= tas571x_reg_read,
+	.reg_write			= tas571x_reg_write,
+	.reg_defaults			= tas5721_reg_defaults,
+	.num_reg_defaults		= ARRAY_SIZE(tas5721_reg_defaults),
+	.cache_type			= REGCACHE_RBTREE,
+	.wr_table			= &tas571x_write_regs,
+	.volatile_table			= &tas571x_volatile_regs,
+};
+
+
+static const struct tas571x_chip tas5721_chip = {
+	.supply_names			= tas5721_supply_names,
+	.num_supply_names		= ARRAY_SIZE(tas5721_supply_names),
+	.controls			= tas5711_controls,
+	.num_controls			= ARRAY_SIZE(tas5711_controls),
+	.regmap_config			= &tas5721_regmap_config,
+	.vol_reg_size			= 1,
+};
+
+static const struct snd_soc_dapm_widget tas571x_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_OUTPUT("OUT_A"),
+	SND_SOC_DAPM_OUTPUT("OUT_B"),
+	SND_SOC_DAPM_OUTPUT("OUT_C"),
+	SND_SOC_DAPM_OUTPUT("OUT_D"),
+};
+
+static const struct snd_soc_dapm_route tas571x_dapm_routes[] = {
+	{ "DACL",  NULL, "Playback" },
+	{ "DACR",  NULL, "Playback" },
+
+	{ "OUT_A", NULL, "DACL" },
+	{ "OUT_B", NULL, "DACL" },
+	{ "OUT_C", NULL, "DACR" },
+	{ "OUT_D", NULL, "DACR" },
+};
+
+static const struct snd_soc_component_driver tas571x_component = {
+	.set_bias_level		= tas571x_set_bias_level,
+	.dapm_widgets		= tas571x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tas571x_dapm_widgets),
+	.dapm_routes		= tas571x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tas571x_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static struct snd_soc_dai_driver tas571x_dai = {
+	.name = "tas571x-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S32_LE |
+			   SNDRV_PCM_FMTBIT_S24_LE |
+			   SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &tas571x_dai_ops,
+};
+
+static const struct of_device_id tas571x_of_match[];
+
+static int tas571x_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct tas571x_private *priv;
+	struct device *dev = &client->dev;
+	const struct of_device_id *of_id;
+	int i, ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	i2c_set_clientdata(client, priv);
+
+	of_id = of_match_device(tas571x_of_match, dev);
+	if (of_id)
+		priv->chip = of_id->data;
+	else
+		priv->chip = (void *) id->driver_data;
+
+	priv->mclk = devm_clk_get(dev, "mclk");
+	if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) {
+		dev_err(dev, "Failed to request mclk: %ld\n",
+			PTR_ERR(priv->mclk));
+		return PTR_ERR(priv->mclk);
+	}
+
+	if (WARN_ON(priv->chip->num_supply_names > TAS571X_MAX_SUPPLIES))
+		return -EINVAL;
+	for (i = 0; i < priv->chip->num_supply_names; i++)
+		priv->supplies[i].supply = priv->chip->supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, priv->chip->num_supply_names,
+				      priv->supplies);
+	if (ret) {
+		dev_err(dev, "Failed to get supplies: %d\n", ret);
+		return ret;
+	}
+	ret = regulator_bulk_enable(priv->chip->num_supply_names,
+				    priv->supplies);
+	if (ret) {
+		dev_err(dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	priv->regmap = devm_regmap_init(dev, NULL, client,
+					priv->chip->regmap_config);
+	if (IS_ERR(priv->regmap))
+		return PTR_ERR(priv->regmap);
+
+	priv->pdn_gpio = devm_gpiod_get_optional(dev, "pdn", GPIOD_OUT_LOW);
+	if (IS_ERR(priv->pdn_gpio)) {
+		dev_err(dev, "error requesting pdn_gpio: %ld\n",
+			PTR_ERR(priv->pdn_gpio));
+		return PTR_ERR(priv->pdn_gpio);
+	}
+
+	priv->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						   GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->reset_gpio)) {
+		dev_err(dev, "error requesting reset_gpio: %ld\n",
+			PTR_ERR(priv->reset_gpio));
+		return PTR_ERR(priv->reset_gpio);
+	} else if (priv->reset_gpio) {
+		/* pulse the active low reset line for ~100us */
+		usleep_range(100, 200);
+		gpiod_set_value(priv->reset_gpio, 0);
+		usleep_range(13500, 20000);
+	}
+
+	ret = regmap_write(priv->regmap, TAS571X_OSC_TRIM_REG, 0);
+	if (ret)
+		return ret;
+
+	usleep_range(50000, 60000);
+
+	memcpy(&priv->component_driver, &tas571x_component, sizeof(priv->component_driver));
+	priv->component_driver.controls = priv->chip->controls;
+	priv->component_driver.num_controls = priv->chip->num_controls;
+
+	if (priv->chip->vol_reg_size == 2) {
+		/*
+		 * The master volume defaults to 0x3ff (mute), but we ignore
+		 * (zero) the LSB because the hardware step size is 0.125 dB
+		 * and TLV_DB_SCALE_ITEM has a resolution of 0.01 dB.
+		 */
+		ret = regmap_update_bits(priv->regmap, TAS571X_MVOL_REG, 1, 0);
+		if (ret)
+			return ret;
+	}
+
+	return devm_snd_soc_register_component(&client->dev,
+				      &priv->component_driver,
+				      &tas571x_dai, 1);
+}
+
+static int tas571x_i2c_remove(struct i2c_client *client)
+{
+	struct tas571x_private *priv = i2c_get_clientdata(client);
+
+	regulator_bulk_disable(priv->chip->num_supply_names, priv->supplies);
+
+	return 0;
+}
+
+static const struct of_device_id tas571x_of_match[] = {
+	{ .compatible = "ti,tas5707", .data = &tas5707_chip, },
+	{ .compatible = "ti,tas5711", .data = &tas5711_chip, },
+	{ .compatible = "ti,tas5717", .data = &tas5717_chip, },
+	{ .compatible = "ti,tas5719", .data = &tas5717_chip, },
+	{ .compatible = "ti,tas5721", .data = &tas5721_chip, },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tas571x_of_match);
+
+static const struct i2c_device_id tas571x_i2c_id[] = {
+	{ "tas5707", (kernel_ulong_t) &tas5707_chip },
+	{ "tas5711", (kernel_ulong_t) &tas5711_chip },
+	{ "tas5717", (kernel_ulong_t) &tas5717_chip },
+	{ "tas5719", (kernel_ulong_t) &tas5717_chip },
+	{ "tas5721", (kernel_ulong_t) &tas5721_chip },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas571x_i2c_id);
+
+static struct i2c_driver tas571x_i2c_driver = {
+	.driver = {
+		.name = "tas571x",
+		.of_match_table = of_match_ptr(tas571x_of_match),
+	},
+	.probe = tas571x_i2c_probe,
+	.remove = tas571x_i2c_remove,
+	.id_table = tas571x_i2c_id,
+};
+module_i2c_driver(tas571x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC TAS571x driver");
+MODULE_AUTHOR("Kevin Cernekee <cernekee@chromium.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas571x.h b/sound/soc/codecs/tas571x.h
new file mode 100644
index 0000000..bd23e89
--- /dev/null
+++ b/sound/soc/codecs/tas571x.h
@@ -0,0 +1,111 @@
+/*
+ * TAS571x amplifier audio driver
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _TAS571X_H
+#define _TAS571X_H
+
+/* device registers */
+#define TAS571X_CLK_CTRL_REG		0x00
+#define TAS571X_DEV_ID_REG		0x01
+#define TAS571X_ERR_STATUS_REG		0x02
+#define TAS571X_SYS_CTRL_1_REG		0x03
+#define TAS571X_SDI_REG			0x04
+#define TAS571X_SDI_FMT_MASK		0x0f
+
+#define TAS571X_SYS_CTRL_2_REG		0x05
+#define TAS571X_SYS_CTRL_2_SDN_MASK	0x40
+
+#define TAS571X_SOFT_MUTE_REG		0x06
+#define TAS571X_SOFT_MUTE_CH1_SHIFT	0
+#define TAS571X_SOFT_MUTE_CH2_SHIFT	1
+#define TAS571X_SOFT_MUTE_CH3_SHIFT	2
+
+#define TAS571X_MVOL_REG		0x07
+#define TAS571X_CH1_VOL_REG		0x08
+#define TAS571X_CH2_VOL_REG		0x09
+#define TAS571X_CH3_VOL_REG		0x0a
+#define TAS571X_VOL_CFG_REG		0x0e
+#define TAS571X_MODULATION_LIMIT_REG	0x10
+#define TAS571X_IC_DELAY_CH1_REG	0x11
+#define TAS571X_IC_DELAY_CH2_REG	0x12
+#define TAS571X_IC_DELAY_CH3_REG	0x13
+#define TAS571X_IC_DELAY_CH4_REG	0x14
+
+#define TAS571X_PWM_CH_SDN_GROUP_REG	0x19	/* N/A on TAS5717, TAS5719 */
+#define TAS571X_PWM_CH1_SDN_MASK	(1<<0)
+#define TAS571X_PWM_CH2_SDN_SHIFT	(1<<1)
+#define TAS571X_PWM_CH3_SDN_SHIFT	(1<<2)
+#define TAS571X_PWM_CH4_SDN_SHIFT	(1<<3)
+
+#define TAS571X_START_STOP_PERIOD_REG	0x1a
+#define TAS571X_OSC_TRIM_REG		0x1b
+#define TAS571X_BKND_ERR_REG		0x1c
+#define TAS571X_INPUT_MUX_REG		0x20
+#define TAS571X_CH4_SRC_SELECT_REG	0x21
+#define TAS571X_PWM_MUX_REG		0x25
+
+/* 20-byte biquad registers */
+#define TAS5707_CH1_BQ0_REG		0x29
+#define TAS5707_CH1_BQ1_REG		0x2a
+#define TAS5707_CH1_BQ2_REG		0x2b
+#define TAS5707_CH1_BQ3_REG		0x2c
+#define TAS5707_CH1_BQ4_REG		0x2d
+#define TAS5707_CH1_BQ5_REG		0x2e
+#define TAS5707_CH1_BQ6_REG		0x2f
+
+#define TAS5707_CH2_BQ0_REG		0x30
+#define TAS5707_CH2_BQ1_REG		0x31
+#define TAS5707_CH2_BQ2_REG		0x32
+#define TAS5707_CH2_BQ3_REG		0x33
+#define TAS5707_CH2_BQ4_REG		0x34
+#define TAS5707_CH2_BQ5_REG		0x35
+#define TAS5707_CH2_BQ6_REG		0x36
+
+#define TAS5717_CH1_BQ0_REG		0x26
+#define TAS5717_CH1_BQ1_REG		0x27
+#define TAS5717_CH1_BQ2_REG		0x28
+#define TAS5717_CH1_BQ3_REG		0x29
+#define TAS5717_CH1_BQ4_REG		0x2a
+#define TAS5717_CH1_BQ5_REG		0x2b
+#define TAS5717_CH1_BQ6_REG		0x2c
+#define TAS5717_CH1_BQ7_REG		0x2d
+#define TAS5717_CH1_BQ8_REG		0x2e
+#define TAS5717_CH1_BQ9_REG		0x2f
+
+#define TAS5717_CH2_BQ0_REG		0x30
+#define TAS5717_CH2_BQ1_REG		0x31
+#define TAS5717_CH2_BQ2_REG		0x32
+#define TAS5717_CH2_BQ3_REG		0x33
+#define TAS5717_CH2_BQ4_REG		0x34
+#define TAS5717_CH2_BQ5_REG		0x35
+#define TAS5717_CH2_BQ6_REG		0x36
+#define TAS5717_CH2_BQ7_REG		0x37
+#define TAS5717_CH2_BQ8_REG		0x38
+#define TAS5717_CH2_BQ9_REG		0x39
+
+#define TAS5717_CH1_BQ10_REG		0x58
+#define TAS5717_CH1_BQ11_REG		0x59
+
+#define TAS5717_CH4_BQ0_REG		0x5a
+#define TAS5717_CH4_BQ1_REG		0x5b
+
+#define TAS5717_CH2_BQ10_REG		0x5c
+#define TAS5717_CH2_BQ11_REG		0x5d
+
+#define TAS5717_CH3_BQ0_REG		0x5e
+#define TAS5717_CH3_BQ1_REG		0x5f
+
+#define TAS5717_CH1_RIGHT_CH_MIX_REG	0x72
+#define TAS5717_CH1_LEFT_CH_MIX_REG	0x73
+#define TAS5717_CH2_LEFT_CH_MIX_REG	0x76
+#define TAS5717_CH2_RIGHT_CH_MIX_REG	0x77
+
+#endif /* _TAS571X_H */
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c
new file mode 100644
index 0000000..ae3d032
--- /dev/null
+++ b/sound/soc/codecs/tas5720.c
@@ -0,0 +1,656 @@
+/*
+ * tas5720.c - ALSA SoC Texas Instruments TAS5720 Mono Audio Amplifier
+ *
+ * Copyright (C)2015-2016 Texas Instruments Incorporated -  http://www.ti.com
+ *
+ * Author: Andreas Dannenberg <dannenberg@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "tas5720.h"
+
+/* Define how often to check (and clear) the fault status register (in ms) */
+#define TAS5720_FAULT_CHECK_INTERVAL		200
+
+enum tas572x_type {
+	TAS5720,
+	TAS5722,
+};
+
+static const char * const tas5720_supply_names[] = {
+	"dvdd",		/* Digital power supply. Connect to 3.3-V supply. */
+	"pvdd",		/* Class-D amp and analog power supply (connected). */
+};
+
+#define TAS5720_NUM_SUPPLIES	ARRAY_SIZE(tas5720_supply_names)
+
+struct tas5720_data {
+	struct snd_soc_component *component;
+	struct regmap *regmap;
+	struct i2c_client *tas5720_client;
+	enum tas572x_type devtype;
+	struct regulator_bulk_data supplies[TAS5720_NUM_SUPPLIES];
+	struct delayed_work fault_check_work;
+	unsigned int last_fault;
+};
+
+static int tas5720_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int rate = params_rate(params);
+	bool ssz_ds;
+	int ret;
+
+	switch (rate) {
+	case 44100:
+	case 48000:
+		ssz_ds = false;
+		break;
+	case 88200:
+	case 96000:
+		ssz_ds = true;
+		break;
+	default:
+		dev_err(component->dev, "unsupported sample rate: %u\n", rate);
+		return -EINVAL;
+	}
+
+	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL1_REG,
+				  TAS5720_SSZ_DS, ssz_ds);
+	if (ret < 0) {
+		dev_err(component->dev, "error setting sample rate: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tas5720_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 serial_format;
+	int ret;
+
+	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+		dev_vdbg(component->dev, "DAI Format master is not found\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
+		       SND_SOC_DAIFMT_INV_MASK)) {
+	case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
+		/* 1st data bit occur one BCLK cycle after the frame sync */
+		serial_format = TAS5720_SAIF_I2S;
+		break;
+	case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF):
+		/*
+		 * Note that although the TAS5720 does not have a dedicated DSP
+		 * mode it doesn't care about the LRCLK duty cycle during TDM
+		 * operation. Therefore we can use the device's I2S mode with
+		 * its delaying of the 1st data bit to receive DSP_A formatted
+		 * data. See device datasheet for additional details.
+		 */
+		serial_format = TAS5720_SAIF_I2S;
+		break;
+	case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF):
+		/*
+		 * Similar to DSP_A, we can use the fact that the TAS5720 does
+		 * not care about the LRCLK duty cycle during TDM to receive
+		 * DSP_B formatted data in LEFTJ mode (no delaying of the 1st
+		 * data bit).
+		 */
+		serial_format = TAS5720_SAIF_LEFTJ;
+		break;
+	case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF):
+		/* No delay after the frame sync */
+		serial_format = TAS5720_SAIF_LEFTJ;
+		break;
+	default:
+		dev_vdbg(component->dev, "DAI Format is not found\n");
+		return -EINVAL;
+	}
+
+	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL1_REG,
+				  TAS5720_SAIF_FORMAT_MASK,
+				  serial_format);
+	if (ret < 0) {
+		dev_err(component->dev, "error setting SAIF format: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai,
+				    unsigned int tx_mask, unsigned int rx_mask,
+				    int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int first_slot;
+	int ret;
+
+	if (!tx_mask) {
+		dev_err(component->dev, "tx masks must not be 0\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Determine the first slot that is being requested. We will only
+	 * use the first slot that is found since the TAS5720 is a mono
+	 * amplifier.
+	 */
+	first_slot = __ffs(tx_mask);
+
+	if (first_slot > 7) {
+		dev_err(component->dev, "slot selection out of bounds (%u)\n",
+			first_slot);
+		return -EINVAL;
+	}
+
+	/* Enable manual TDM slot selection (instead of I2C ID based) */
+	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL1_REG,
+				  TAS5720_TDM_CFG_SRC, TAS5720_TDM_CFG_SRC);
+	if (ret < 0)
+		goto error_snd_soc_component_update_bits;
+
+	/* Configure the TDM slot to process audio from */
+	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG,
+				  TAS5720_TDM_SLOT_SEL_MASK, first_slot);
+	if (ret < 0)
+		goto error_snd_soc_component_update_bits;
+
+	return 0;
+
+error_snd_soc_component_update_bits:
+	dev_err(component->dev, "error configuring TDM mode: %d\n", ret);
+	return ret;
+}
+
+static int tas5720_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	int ret;
+
+	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG,
+				  TAS5720_MUTE, mute ? TAS5720_MUTE : 0);
+	if (ret < 0) {
+		dev_err(component->dev, "error (un-)muting device: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void tas5720_fault_check_work(struct work_struct *work)
+{
+	struct tas5720_data *tas5720 = container_of(work, struct tas5720_data,
+			fault_check_work.work);
+	struct device *dev = tas5720->component->dev;
+	unsigned int curr_fault;
+	int ret;
+
+	ret = regmap_read(tas5720->regmap, TAS5720_FAULT_REG, &curr_fault);
+	if (ret < 0) {
+		dev_err(dev, "failed to read FAULT register: %d\n", ret);
+		goto out;
+	}
+
+	/* Check/handle all errors except SAIF clock errors */
+	curr_fault &= TAS5720_OCE | TAS5720_DCE | TAS5720_OTE;
+
+	/*
+	 * Only flag errors once for a given occurrence. This is needed as
+	 * the TAS5720 will take time clearing the fault condition internally
+	 * during which we don't want to bombard the system with the same
+	 * error message over and over.
+	 */
+	if ((curr_fault & TAS5720_OCE) && !(tas5720->last_fault & TAS5720_OCE))
+		dev_crit(dev, "experienced an over current hardware fault\n");
+
+	if ((curr_fault & TAS5720_DCE) && !(tas5720->last_fault & TAS5720_DCE))
+		dev_crit(dev, "experienced a DC detection fault\n");
+
+	if ((curr_fault & TAS5720_OTE) && !(tas5720->last_fault & TAS5720_OTE))
+		dev_crit(dev, "experienced an over temperature fault\n");
+
+	/* Store current fault value so we can detect any changes next time */
+	tas5720->last_fault = curr_fault;
+
+	if (!curr_fault)
+		goto out;
+
+	/*
+	 * Periodically toggle SDZ (shutdown bit) H->L->H to clear any latching
+	 * faults as long as a fault condition persists. Always going through
+	 * the full sequence no matter the first return value to minimizes
+	 * chances for the device to end up in shutdown mode.
+	 */
+	ret = regmap_write_bits(tas5720->regmap, TAS5720_POWER_CTRL_REG,
+				TAS5720_SDZ, 0);
+	if (ret < 0)
+		dev_err(dev, "failed to write POWER_CTRL register: %d\n", ret);
+
+	ret = regmap_write_bits(tas5720->regmap, TAS5720_POWER_CTRL_REG,
+				TAS5720_SDZ, TAS5720_SDZ);
+	if (ret < 0)
+		dev_err(dev, "failed to write POWER_CTRL register: %d\n", ret);
+
+out:
+	/* Schedule the next fault check at the specified interval */
+	schedule_delayed_work(&tas5720->fault_check_work,
+			      msecs_to_jiffies(TAS5720_FAULT_CHECK_INTERVAL));
+}
+
+static int tas5720_codec_probe(struct snd_soc_component *component)
+{
+	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
+	unsigned int device_id, expected_device_id;
+	int ret;
+
+	tas5720->component = component;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(tas5720->supplies),
+				    tas5720->supplies);
+	if (ret != 0) {
+		dev_err(component->dev, "failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * Take a liberal approach to checking the device ID to allow the
+	 * driver to be used even if the device ID does not match, however
+	 * issue a warning if there is a mismatch.
+	 */
+	ret = regmap_read(tas5720->regmap, TAS5720_DEVICE_ID_REG, &device_id);
+	if (ret < 0) {
+		dev_err(component->dev, "failed to read device ID register: %d\n",
+			ret);
+		goto probe_fail;
+	}
+
+	switch (tas5720->devtype) {
+	case TAS5720:
+		expected_device_id = TAS5720_DEVICE_ID;
+		break;
+	case TAS5722:
+		expected_device_id = TAS5722_DEVICE_ID;
+		break;
+	default:
+		dev_err(component->dev, "unexpected private driver data\n");
+		return -EINVAL;
+	}
+
+	if (device_id != expected_device_id)
+		dev_warn(component->dev, "wrong device ID. expected: %u read: %u\n",
+			 expected_device_id, device_id);
+
+	/* Set device to mute */
+	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG,
+				  TAS5720_MUTE, TAS5720_MUTE);
+	if (ret < 0)
+		goto error_snd_soc_component_update_bits;
+
+	/*
+	 * Enter shutdown mode - our default when not playing audio - to
+	 * minimize current consumption. On the TAS5720 there is no real down
+	 * side doing so as all device registers are preserved and the wakeup
+	 * of the codec is rather quick which we do using a dapm widget.
+	 */
+	ret = snd_soc_component_update_bits(component, TAS5720_POWER_CTRL_REG,
+				  TAS5720_SDZ, 0);
+	if (ret < 0)
+		goto error_snd_soc_component_update_bits;
+
+	INIT_DELAYED_WORK(&tas5720->fault_check_work, tas5720_fault_check_work);
+
+	return 0;
+
+error_snd_soc_component_update_bits:
+	dev_err(component->dev, "error configuring device registers: %d\n", ret);
+
+probe_fail:
+	regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies),
+			       tas5720->supplies);
+	return ret;
+}
+
+static void tas5720_codec_remove(struct snd_soc_component *component)
+{
+	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	cancel_delayed_work_sync(&tas5720->fault_check_work);
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies),
+				     tas5720->supplies);
+	if (ret < 0)
+		dev_err(component->dev, "failed to disable supplies: %d\n", ret);
+};
+
+static int tas5720_dac_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	if (event & SND_SOC_DAPM_POST_PMU) {
+		/* Take TAS5720 out of shutdown mode */
+		ret = snd_soc_component_update_bits(component, TAS5720_POWER_CTRL_REG,
+					  TAS5720_SDZ, TAS5720_SDZ);
+		if (ret < 0) {
+			dev_err(component->dev, "error waking component: %d\n", ret);
+			return ret;
+		}
+
+		/*
+		 * Observe codec shutdown-to-active time. The datasheet only
+		 * lists a nominal value however just use-it as-is without
+		 * additional padding to minimize the delay introduced in
+		 * starting to play audio (actually there is other setup done
+		 * by the ASoC framework that will provide additional delays,
+		 * so we should always be safe).
+		 */
+		msleep(25);
+
+		/* Turn on TAS5720 periodic fault checking/handling */
+		tas5720->last_fault = 0;
+		schedule_delayed_work(&tas5720->fault_check_work,
+				msecs_to_jiffies(TAS5720_FAULT_CHECK_INTERVAL));
+	} else if (event & SND_SOC_DAPM_PRE_PMD) {
+		/* Disable TAS5720 periodic fault checking/handling */
+		cancel_delayed_work_sync(&tas5720->fault_check_work);
+
+		/* Place TAS5720 in shutdown mode to minimize current draw */
+		ret = snd_soc_component_update_bits(component, TAS5720_POWER_CTRL_REG,
+					  TAS5720_SDZ, 0);
+		if (ret < 0) {
+			dev_err(component->dev, "error shutting down component: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int tas5720_suspend(struct snd_soc_component *component)
+{
+	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	regcache_cache_only(tas5720->regmap, true);
+	regcache_mark_dirty(tas5720->regmap);
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies),
+				     tas5720->supplies);
+	if (ret < 0)
+		dev_err(component->dev, "failed to disable supplies: %d\n", ret);
+
+	return ret;
+}
+
+static int tas5720_resume(struct snd_soc_component *component)
+{
+	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(tas5720->supplies),
+				    tas5720->supplies);
+	if (ret < 0) {
+		dev_err(component->dev, "failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	regcache_cache_only(tas5720->regmap, false);
+
+	ret = regcache_sync(tas5720->regmap);
+	if (ret < 0) {
+		dev_err(component->dev, "failed to sync regcache: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+#else
+#define tas5720_suspend NULL
+#define tas5720_resume NULL
+#endif
+
+static bool tas5720_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5720_DEVICE_ID_REG:
+	case TAS5720_FAULT_REG:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config tas5720_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = TAS5720_MAX_REG,
+	.cache_type = REGCACHE_RBTREE,
+	.volatile_reg = tas5720_is_volatile_reg,
+};
+
+static const struct regmap_config tas5722_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = TAS5722_MAX_REG,
+	.cache_type = REGCACHE_RBTREE,
+	.volatile_reg = tas5720_is_volatile_reg,
+};
+
+/*
+ * DAC analog gain. There are four discrete values to select from, ranging
+ * from 19.2 dB to 26.3dB.
+ */
+static const DECLARE_TLV_DB_RANGE(dac_analog_tlv,
+	0x0, 0x0, TLV_DB_SCALE_ITEM(1920, 0, 0),
+	0x1, 0x1, TLV_DB_SCALE_ITEM(2070, 0, 0),
+	0x2, 0x2, TLV_DB_SCALE_ITEM(2350, 0, 0),
+	0x3, 0x3, TLV_DB_SCALE_ITEM(2630, 0, 0),
+);
+
+/*
+ * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that
+ * setting the gain below -100 dB (register value <0x7) is effectively a MUTE
+ * as per device datasheet.
+ */
+static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0);
+
+static const struct snd_kcontrol_new tas5720_snd_controls[] = {
+	SOC_SINGLE_TLV("Speaker Driver Playback Volume",
+		       TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, dac_tlv),
+	SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG,
+		       TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
+};
+
+static const struct snd_soc_dapm_widget tas5720_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas5720_dac_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_OUTPUT("OUT")
+};
+
+static const struct snd_soc_dapm_route tas5720_audio_map[] = {
+	{ "DAC", NULL, "DAC IN" },
+	{ "OUT", NULL, "DAC" },
+};
+
+static const struct snd_soc_component_driver soc_component_dev_tas5720 = {
+	.probe			= tas5720_codec_probe,
+	.remove			= tas5720_codec_remove,
+	.suspend		= tas5720_suspend,
+	.resume			= tas5720_resume,
+	.controls		= tas5720_snd_controls,
+	.num_controls		= ARRAY_SIZE(tas5720_snd_controls),
+	.dapm_widgets		= tas5720_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tas5720_dapm_widgets),
+	.dapm_routes		= tas5720_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(tas5720_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+/* PCM rates supported by the TAS5720 driver */
+#define TAS5720_RATES	(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+			 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+/* Formats supported by TAS5720 driver */
+#define TAS5720_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\
+			 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops tas5720_speaker_dai_ops = {
+	.hw_params	= tas5720_hw_params,
+	.set_fmt	= tas5720_set_dai_fmt,
+	.set_tdm_slot	= tas5720_set_dai_tdm_slot,
+	.digital_mute	= tas5720_mute,
+};
+
+/*
+ * TAS5720 DAI structure
+ *
+ * Note that were are advertising .playback.channels_max = 2 despite this being
+ * a mono amplifier. The reason for that is that some serial ports such as TI's
+ * McASP module have a minimum number of channels (2) that they can output.
+ * Advertising more channels than we have will allow us to interface with such
+ * a serial port without really any negative side effects as the TAS5720 will
+ * simply ignore any extra channel(s) asides from the one channel that is
+ * configured to be played back.
+ */
+static struct snd_soc_dai_driver tas5720_dai[] = {
+	{
+		.name = "tas5720-amplifier",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = TAS5720_RATES,
+			.formats = TAS5720_FORMATS,
+		},
+		.ops = &tas5720_speaker_dai_ops,
+	},
+};
+
+static int tas5720_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct tas5720_data *data;
+	const struct regmap_config *regmap_config;
+	int ret;
+	int i;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->tas5720_client = client;
+	data->devtype = id->driver_data;
+
+	switch (id->driver_data) {
+	case TAS5720:
+		regmap_config = &tas5720_regmap_config;
+		break;
+	case TAS5722:
+		regmap_config = &tas5722_regmap_config;
+		break;
+	default:
+		dev_err(dev, "unexpected private driver data\n");
+		return -EINVAL;
+	}
+	data->regmap = devm_regmap_init_i2c(client, regmap_config);
+	if (IS_ERR(data->regmap)) {
+		ret = PTR_ERR(data->regmap);
+		dev_err(dev, "failed to allocate register map: %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
+		data->supplies[i].supply = tas5720_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
+				      data->supplies);
+	if (ret != 0) {
+		dev_err(dev, "failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	dev_set_drvdata(dev, data);
+
+	ret = devm_snd_soc_register_component(&client->dev,
+				     &soc_component_dev_tas5720,
+				     tas5720_dai, ARRAY_SIZE(tas5720_dai));
+	if (ret < 0) {
+		dev_err(dev, "failed to register component: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct i2c_device_id tas5720_id[] = {
+	{ "tas5720", TAS5720 },
+	{ "tas5722", TAS5722 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas5720_id);
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id tas5720_of_match[] = {
+	{ .compatible = "ti,tas5720", },
+	{ .compatible = "ti,tas5722", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, tas5720_of_match);
+#endif
+
+static struct i2c_driver tas5720_i2c_driver = {
+	.driver = {
+		.name = "tas5720",
+		.of_match_table = of_match_ptr(tas5720_of_match),
+	},
+	.probe = tas5720_probe,
+	.id_table = tas5720_id,
+};
+
+module_i2c_driver(tas5720_i2c_driver);
+
+MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
+MODULE_DESCRIPTION("TAS5720 Audio amplifier driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas5720.h b/sound/soc/codecs/tas5720.h
new file mode 100644
index 0000000..1dda309
--- /dev/null
+++ b/sound/soc/codecs/tas5720.h
@@ -0,0 +1,121 @@
+/*
+ * tas5720.h - ALSA SoC Texas Instruments TAS5720 Mono Audio Amplifier
+ *
+ * Copyright (C)2015-2016 Texas Instruments Incorporated -  http://www.ti.com
+ *
+ * Author: Andreas Dannenberg <dannenberg@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __TAS5720_H__
+#define __TAS5720_H__
+
+/* Register Address Map */
+#define TAS5720_DEVICE_ID_REG		0x00
+#define TAS5720_POWER_CTRL_REG		0x01
+#define TAS5720_DIGITAL_CTRL1_REG	0x02
+#define TAS5720_DIGITAL_CTRL2_REG	0x03
+#define TAS5720_VOLUME_CTRL_REG		0x04
+#define TAS5720_ANALOG_CTRL_REG		0x06
+#define TAS5720_FAULT_REG		0x08
+#define TAS5720_DIGITAL_CLIP2_REG	0x10
+#define TAS5720_DIGITAL_CLIP1_REG	0x11
+#define TAS5720_MAX_REG			TAS5720_DIGITAL_CLIP1_REG
+
+/* Additional TAS5722-specific Registers */
+#define TAS5722_DIGITAL_CTRL2_REG	0x13
+#define TAS5722_ANALOG_CTRL2_REG	0x14
+#define TAS5722_MAX_REG			TAS5722_ANALOG_CTRL2_REG
+
+/* TAS5720_DEVICE_ID_REG */
+#define TAS5720_DEVICE_ID		0x01
+#define TAS5722_DEVICE_ID		0x12
+
+/* TAS5720_POWER_CTRL_REG */
+#define TAS5720_DIG_CLIP_MASK		GENMASK(7, 2)
+#define TAS5720_SLEEP			BIT(1)
+#define TAS5720_SDZ			BIT(0)
+
+/* TAS5720_DIGITAL_CTRL1_REG */
+#define TAS5720_HPF_BYPASS		BIT(7)
+#define TAS5720_TDM_CFG_SRC		BIT(6)
+#define TAS5720_SSZ_DS			BIT(3)
+#define TAS5720_SAIF_RIGHTJ_24BIT	(0x0)
+#define TAS5720_SAIF_RIGHTJ_20BIT	(0x1)
+#define TAS5720_SAIF_RIGHTJ_18BIT	(0x2)
+#define TAS5720_SAIF_RIGHTJ_16BIT	(0x3)
+#define TAS5720_SAIF_I2S		(0x4)
+#define TAS5720_SAIF_LEFTJ		(0x5)
+#define TAS5720_SAIF_FORMAT_MASK	GENMASK(2, 0)
+
+/* TAS5720_DIGITAL_CTRL2_REG */
+#define TAS5722_VOL_RAMP_RATE		BIT(6)
+#define TAS5720_MUTE			BIT(4)
+#define TAS5720_TDM_SLOT_SEL_MASK	GENMASK(2, 0)
+
+/* TAS5720_ANALOG_CTRL_REG */
+#define TAS5720_PWM_RATE_6_3_FSYNC	(0x0 << 4)
+#define TAS5720_PWM_RATE_8_4_FSYNC	(0x1 << 4)
+#define TAS5720_PWM_RATE_10_5_FSYNC	(0x2 << 4)
+#define TAS5720_PWM_RATE_12_6_FSYNC	(0x3 << 4)
+#define TAS5720_PWM_RATE_14_7_FSYNC	(0x4 << 4)
+#define TAS5720_PWM_RATE_16_8_FSYNC	(0x5 << 4)
+#define TAS5720_PWM_RATE_20_10_FSYNC	(0x6 << 4)
+#define TAS5720_PWM_RATE_24_12_FSYNC	(0x7 << 4)
+#define TAS5720_PWM_RATE_MASK		GENMASK(6, 4)
+#define TAS5720_ANALOG_GAIN_19_2DBV	(0x0 << 2)
+#define TAS5720_ANALOG_GAIN_20_7DBV	(0x1 << 2)
+#define TAS5720_ANALOG_GAIN_23_5DBV	(0x2 << 2)
+#define TAS5720_ANALOG_GAIN_26_3DBV	(0x3 << 2)
+#define TAS5720_ANALOG_GAIN_MASK	GENMASK(3, 2)
+#define TAS5720_ANALOG_GAIN_SHIFT	(0x2)
+
+/* TAS5720_FAULT_REG */
+#define TAS5720_OC_THRESH_100PCT	(0x0 << 4)
+#define TAS5720_OC_THRESH_75PCT		(0x1 << 4)
+#define TAS5720_OC_THRESH_50PCT		(0x2 << 4)
+#define TAS5720_OC_THRESH_25PCT		(0x3 << 4)
+#define TAS5720_OC_THRESH_MASK		GENMASK(5, 4)
+#define TAS5720_CLKE			BIT(3)
+#define TAS5720_OCE			BIT(2)
+#define TAS5720_DCE			BIT(1)
+#define TAS5720_OTE			BIT(0)
+#define TAS5720_FAULT_MASK		GENMASK(3, 0)
+
+/* TAS5720_DIGITAL_CLIP1_REG */
+#define TAS5720_CLIP1_MASK		GENMASK(7, 2)
+#define TAS5720_CLIP1_SHIFT		(0x2)
+
+/* TAS5722_DIGITAL_CTRL2_REG */
+#define TAS5722_HPF_3_7HZ		(0x0 << 5)
+#define TAS5722_HPF_7_4HZ		(0x1 << 5)
+#define TAS5722_HPF_14_9HZ		(0x2 << 5)
+#define TAS5722_HPF_29_7HZ		(0x3 << 5)
+#define TAS5722_HPF_59_4HZ		(0x4 << 5)
+#define TAS5722_HPF_118_4HZ		(0x5 << 5)
+#define TAS5722_HPF_235_0HZ		(0x6 << 5)
+#define TAS5722_HPF_463_2HZ		(0x7 << 5)
+#define TAS5722_HPF_MASK		GENMASK(7, 5)
+#define TAS5722_AUTO_SLEEP_OFF		(0x0 << 3)
+#define TAS5722_AUTO_SLEEP_1024LR	(0x1 << 3)
+#define TAS5722_AUTO_SLEEP_65536LR	(0x2 << 3)
+#define TAS5722_AUTO_SLEEP_262144LR	(0x3 << 3)
+#define TAS5722_AUTO_SLEEP_MASK		GENMASK(4, 3)
+#define TAS5722_TDM_SLOT_16B		BIT(2)
+#define TAS5722_MCLK_PIN_CFG		BIT(1)
+#define TAS5722_VOL_CONTROL_LSB		BIT(0)
+
+/* TAS5722_ANALOG_CTRL2_REG */
+#define TAS5722_FAULTZ_PU		BIT(3)
+#define TAS5722_VREG_LVL		BIT(2)
+#define TAS5722_PWR_TUNE		BIT(0)
+
+#endif /* __TAS5720_H__ */
diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c
new file mode 100644
index 0000000..0d61455
--- /dev/null
+++ b/sound/soc/codecs/tas6424.c
@@ -0,0 +1,776 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ALSA SoC Texas Instruments TAS6424 Quad-Channel Audio Amplifier
+ *
+ * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
+ *	Author: Andreas Dannenberg <dannenberg@ti.com>
+ *	Andrew F. Davis <afd@ti.com>
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "tas6424.h"
+
+/* Define how often to check (and clear) the fault status register (in ms) */
+#define TAS6424_FAULT_CHECK_INTERVAL 200
+
+static const char * const tas6424_supply_names[] = {
+	"dvdd", /* Digital power supply. Connect to 3.3-V supply. */
+	"vbat", /* Supply used for higher voltage analog circuits. */
+	"pvdd", /* Class-D amp output FETs supply. */
+};
+#define TAS6424_NUM_SUPPLIES ARRAY_SIZE(tas6424_supply_names)
+
+struct tas6424_data {
+	struct device *dev;
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[TAS6424_NUM_SUPPLIES];
+	struct delayed_work fault_check_work;
+	unsigned int last_fault1;
+	unsigned int last_fault2;
+	unsigned int last_warn;
+	struct gpio_desc *standby_gpio;
+	struct gpio_desc *mute_gpio;
+};
+
+/*
+ * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that
+ * setting the gain below -100 dB (register value <0x7) is effectively a MUTE
+ * as per device datasheet.
+ */
+static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0);
+
+static const struct snd_kcontrol_new tas6424_snd_controls[] = {
+	SOC_SINGLE_TLV("Speaker Driver CH1 Playback Volume",
+		       TAS6424_CH1_VOL_CTRL, 0, 0xff, 0, dac_tlv),
+	SOC_SINGLE_TLV("Speaker Driver CH2 Playback Volume",
+		       TAS6424_CH2_VOL_CTRL, 0, 0xff, 0, dac_tlv),
+	SOC_SINGLE_TLV("Speaker Driver CH3 Playback Volume",
+		       TAS6424_CH3_VOL_CTRL, 0, 0xff, 0, dac_tlv),
+	SOC_SINGLE_TLV("Speaker Driver CH4 Playback Volume",
+		       TAS6424_CH4_VOL_CTRL, 0, 0xff, 0, dac_tlv),
+	SOC_SINGLE_STROBE("Auto Diagnostics Switch", TAS6424_DC_DIAG_CTRL1,
+			  TAS6424_LDGBYPASS_SHIFT, 1),
+};
+
+static int tas6424_dac_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct tas6424_data *tas6424 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "%s() event=0x%0x\n", __func__, event);
+
+	if (event & SND_SOC_DAPM_POST_PMU) {
+		/* Observe codec shutdown-to-active time */
+		msleep(12);
+
+		/* Turn on TAS6424 periodic fault checking/handling */
+		tas6424->last_fault1 = 0;
+		tas6424->last_fault2 = 0;
+		tas6424->last_warn = 0;
+		schedule_delayed_work(&tas6424->fault_check_work,
+				      msecs_to_jiffies(TAS6424_FAULT_CHECK_INTERVAL));
+	} else if (event & SND_SOC_DAPM_PRE_PMD) {
+		/* Disable TAS6424 periodic fault checking/handling */
+		cancel_delayed_work_sync(&tas6424->fault_check_work);
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget tas6424_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas6424_dac_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_OUTPUT("OUT")
+};
+
+static const struct snd_soc_dapm_route tas6424_audio_map[] = {
+	{ "DAC", NULL, "DAC IN" },
+	{ "OUT", NULL, "DAC" },
+};
+
+static int tas6424_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int rate = params_rate(params);
+	unsigned int width = params_width(params);
+	u8 sap_ctrl = 0;
+
+	dev_dbg(component->dev, "%s() rate=%u width=%u\n", __func__, rate, width);
+
+	switch (rate) {
+	case 44100:
+		sap_ctrl |= TAS6424_SAP_RATE_44100;
+		break;
+	case 48000:
+		sap_ctrl |= TAS6424_SAP_RATE_48000;
+		break;
+	case 96000:
+		sap_ctrl |= TAS6424_SAP_RATE_96000;
+		break;
+	default:
+		dev_err(component->dev, "unsupported sample rate: %u\n", rate);
+		return -EINVAL;
+	}
+
+	switch (width) {
+	case 16:
+		sap_ctrl |= TAS6424_SAP_TDM_SLOT_SZ_16;
+		break;
+	case 24:
+		break;
+	default:
+		dev_err(component->dev, "unsupported sample width: %u\n", width);
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, TAS6424_SAP_CTRL,
+			    TAS6424_SAP_RATE_MASK |
+			    TAS6424_SAP_TDM_SLOT_SZ_16,
+			    sap_ctrl);
+
+	return 0;
+}
+
+static int tas6424_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 serial_format = 0;
+
+	dev_dbg(component->dev, "%s() fmt=0x%0x\n", __func__, fmt);
+
+	/* clock masters */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI master/slave interface\n");
+		return -EINVAL;
+	}
+
+	/* signal polarity */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI clock signal polarity\n");
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		serial_format |= TAS6424_SAP_I2S;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		serial_format |= TAS6424_SAP_DSP;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		/*
+		 * We can use the fact that the TAS6424 does not care about the
+		 * LRCLK duty cycle during TDM to receive DSP_B formatted data
+		 * in LEFTJ mode (no delaying of the 1st data bit).
+		 */
+		serial_format |= TAS6424_SAP_LEFTJ;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		serial_format |= TAS6424_SAP_LEFTJ;
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI interface format\n");
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, TAS6424_SAP_CTRL,
+			    TAS6424_SAP_FMT_MASK, serial_format);
+
+	return 0;
+}
+
+static int tas6424_set_dai_tdm_slot(struct snd_soc_dai *dai,
+				    unsigned int tx_mask, unsigned int rx_mask,
+				    int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int first_slot, last_slot;
+	bool sap_tdm_slot_last;
+
+	dev_dbg(component->dev, "%s() tx_mask=%d rx_mask=%d\n", __func__,
+		tx_mask, rx_mask);
+
+	if (!tx_mask || !rx_mask)
+		return 0; /* nothing needed to disable TDM mode */
+
+	/*
+	 * Determine the first slot and last slot that is being requested so
+	 * we'll be able to more easily enforce certain constraints as the
+	 * TAS6424's TDM interface is not fully configurable.
+	 */
+	first_slot = __ffs(tx_mask);
+	last_slot = __fls(rx_mask);
+
+	if (last_slot - first_slot != 4) {
+		dev_err(component->dev, "tdm mask must cover 4 contiguous slots\n");
+		return -EINVAL;
+	}
+
+	switch (first_slot) {
+	case 0:
+		sap_tdm_slot_last = false;
+		break;
+	case 4:
+		sap_tdm_slot_last = true;
+		break;
+	default:
+		dev_err(component->dev, "tdm mask must start at slot 0 or 4\n");
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, TAS6424_SAP_CTRL, TAS6424_SAP_TDM_SLOT_LAST,
+			    sap_tdm_slot_last ? TAS6424_SAP_TDM_SLOT_LAST : 0);
+
+	return 0;
+}
+
+static int tas6424_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas6424_data *tas6424 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+
+	dev_dbg(component->dev, "%s() mute=%d\n", __func__, mute);
+
+	if (tas6424->mute_gpio) {
+		gpiod_set_value_cansleep(tas6424->mute_gpio, mute);
+		return 0;
+	}
+
+	if (mute)
+		val = TAS6424_ALL_STATE_MUTE;
+	else
+		val = TAS6424_ALL_STATE_PLAY;
+
+	snd_soc_component_write(component, TAS6424_CH_STATE_CTRL, val);
+
+	return 0;
+}
+
+static int tas6424_power_off(struct snd_soc_component *component)
+{
+	struct tas6424_data *tas6424 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	snd_soc_component_write(component, TAS6424_CH_STATE_CTRL, TAS6424_ALL_STATE_HIZ);
+
+	regcache_cache_only(tas6424->regmap, true);
+	regcache_mark_dirty(tas6424->regmap);
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies),
+				     tas6424->supplies);
+	if (ret < 0) {
+		dev_err(component->dev, "failed to disable supplies: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tas6424_power_on(struct snd_soc_component *component)
+{
+	struct tas6424_data *tas6424 = snd_soc_component_get_drvdata(component);
+	int ret;
+	u8 chan_states;
+	int no_auto_diags = 0;
+	unsigned int reg_val;
+
+	if (!regmap_read(tas6424->regmap, TAS6424_DC_DIAG_CTRL1, &reg_val))
+		no_auto_diags = reg_val & TAS6424_LDGBYPASS_MASK;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(tas6424->supplies),
+				    tas6424->supplies);
+	if (ret < 0) {
+		dev_err(component->dev, "failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	regcache_cache_only(tas6424->regmap, false);
+
+	ret = regcache_sync(tas6424->regmap);
+	if (ret < 0) {
+		dev_err(component->dev, "failed to sync regcache: %d\n", ret);
+		return ret;
+	}
+
+	if (tas6424->mute_gpio) {
+		gpiod_set_value_cansleep(tas6424->mute_gpio, 0);
+		/*
+		 * channels are muted via the mute pin.  Don't also mute
+		 * them via the registers so that subsequent register
+		 * access is not necessary to un-mute the channels
+		 */
+		chan_states = TAS6424_ALL_STATE_PLAY;
+	} else {
+		chan_states = TAS6424_ALL_STATE_MUTE;
+	}
+	snd_soc_component_write(component, TAS6424_CH_STATE_CTRL, chan_states);
+
+	/* any time we come out of HIZ, the output channels automatically run DC
+	 * load diagnostics if autodiagnotics are enabled. wait here until this
+	 * completes.
+	 */
+	if (!no_auto_diags)
+		msleep(230);
+
+	return 0;
+}
+
+static int tas6424_set_bias_level(struct snd_soc_component *component,
+				  enum snd_soc_bias_level level)
+{
+	dev_dbg(component->dev, "%s() level=%d\n", __func__, level);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			tas6424_power_on(component);
+		break;
+	case SND_SOC_BIAS_OFF:
+		tas6424_power_off(component);
+		break;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_component_driver soc_codec_dev_tas6424 = {
+	.set_bias_level		= tas6424_set_bias_level,
+	.controls		= tas6424_snd_controls,
+	.num_controls		= ARRAY_SIZE(tas6424_snd_controls),
+	.dapm_widgets		= tas6424_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tas6424_dapm_widgets),
+	.dapm_routes		= tas6424_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(tas6424_audio_map),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
+	.hw_params	= tas6424_hw_params,
+	.set_fmt	= tas6424_set_dai_fmt,
+	.set_tdm_slot	= tas6424_set_dai_tdm_slot,
+	.digital_mute	= tas6424_mute,
+};
+
+static struct snd_soc_dai_driver tas6424_dai[] = {
+	{
+		.name = "tas6424-amplifier",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = TAS6424_RATES,
+			.formats = TAS6424_FORMATS,
+		},
+		.ops = &tas6424_speaker_dai_ops,
+	},
+};
+
+static void tas6424_fault_check_work(struct work_struct *work)
+{
+	struct tas6424_data *tas6424 = container_of(work, struct tas6424_data,
+						    fault_check_work.work);
+	struct device *dev = tas6424->dev;
+	unsigned int reg;
+	int ret;
+
+	ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT1, &reg);
+	if (ret < 0) {
+		dev_err(dev, "failed to read FAULT1 register: %d\n", ret);
+		goto out;
+	}
+
+	/*
+	 * Ignore any clock faults as there is no clean way to check for them.
+	 * We would need to start checking for those faults *after* the SAIF
+	 * stream has been setup, and stop checking *before* the stream is
+	 * stopped to avoid any false-positives. However there are no
+	 * appropriate hooks to monitor these events.
+	 */
+	reg &= TAS6424_FAULT_PVDD_OV |
+	       TAS6424_FAULT_VBAT_OV |
+	       TAS6424_FAULT_PVDD_UV |
+	       TAS6424_FAULT_VBAT_UV;
+
+	if (!reg) {
+		tas6424->last_fault1 = reg;
+		goto check_global_fault2_reg;
+	}
+
+	/*
+	 * Only flag errors once for a given occurrence. This is needed as
+	 * the TAS6424 will take time clearing the fault condition internally
+	 * during which we don't want to bombard the system with the same
+	 * error message over and over.
+	 */
+	if ((reg & TAS6424_FAULT_PVDD_OV) && !(tas6424->last_fault1 & TAS6424_FAULT_PVDD_OV))
+		dev_crit(dev, "experienced a PVDD overvoltage fault\n");
+
+	if ((reg & TAS6424_FAULT_VBAT_OV) && !(tas6424->last_fault1 & TAS6424_FAULT_VBAT_OV))
+		dev_crit(dev, "experienced a VBAT overvoltage fault\n");
+
+	if ((reg & TAS6424_FAULT_PVDD_UV) && !(tas6424->last_fault1 & TAS6424_FAULT_PVDD_UV))
+		dev_crit(dev, "experienced a PVDD undervoltage fault\n");
+
+	if ((reg & TAS6424_FAULT_VBAT_UV) && !(tas6424->last_fault1 & TAS6424_FAULT_VBAT_UV))
+		dev_crit(dev, "experienced a VBAT undervoltage fault\n");
+
+	/* Store current fault1 value so we can detect any changes next time */
+	tas6424->last_fault1 = reg;
+
+check_global_fault2_reg:
+	ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT2, &reg);
+	if (ret < 0) {
+		dev_err(dev, "failed to read FAULT2 register: %d\n", ret);
+		goto out;
+	}
+
+	reg &= TAS6424_FAULT_OTSD |
+	       TAS6424_FAULT_OTSD_CH1 |
+	       TAS6424_FAULT_OTSD_CH2 |
+	       TAS6424_FAULT_OTSD_CH3 |
+	       TAS6424_FAULT_OTSD_CH4;
+
+	if (!reg) {
+		tas6424->last_fault2 = reg;
+		goto check_warn_reg;
+	}
+
+	if ((reg & TAS6424_FAULT_OTSD) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD))
+		dev_crit(dev, "experienced a global overtemp shutdown\n");
+
+	if ((reg & TAS6424_FAULT_OTSD_CH1) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH1))
+		dev_crit(dev, "experienced an overtemp shutdown on CH1\n");
+
+	if ((reg & TAS6424_FAULT_OTSD_CH2) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH2))
+		dev_crit(dev, "experienced an overtemp shutdown on CH2\n");
+
+	if ((reg & TAS6424_FAULT_OTSD_CH3) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH3))
+		dev_crit(dev, "experienced an overtemp shutdown on CH3\n");
+
+	if ((reg & TAS6424_FAULT_OTSD_CH4) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH4))
+		dev_crit(dev, "experienced an overtemp shutdown on CH4\n");
+
+	/* Store current fault2 value so we can detect any changes next time */
+	tas6424->last_fault2 = reg;
+
+check_warn_reg:
+	ret = regmap_read(tas6424->regmap, TAS6424_WARN, &reg);
+	if (ret < 0) {
+		dev_err(dev, "failed to read WARN register: %d\n", ret);
+		goto out;
+	}
+
+	reg &= TAS6424_WARN_VDD_UV |
+	       TAS6424_WARN_VDD_POR |
+	       TAS6424_WARN_VDD_OTW |
+	       TAS6424_WARN_VDD_OTW_CH1 |
+	       TAS6424_WARN_VDD_OTW_CH2 |
+	       TAS6424_WARN_VDD_OTW_CH3 |
+	       TAS6424_WARN_VDD_OTW_CH4;
+
+	if (!reg) {
+		tas6424->last_warn = reg;
+		goto out;
+	}
+
+	if ((reg & TAS6424_WARN_VDD_UV) && !(tas6424->last_warn & TAS6424_WARN_VDD_UV))
+		dev_warn(dev, "experienced a VDD under voltage condition\n");
+
+	if ((reg & TAS6424_WARN_VDD_POR) && !(tas6424->last_warn & TAS6424_WARN_VDD_POR))
+		dev_warn(dev, "experienced a VDD POR condition\n");
+
+	if ((reg & TAS6424_WARN_VDD_OTW) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW))
+		dev_warn(dev, "experienced a global overtemp warning\n");
+
+	if ((reg & TAS6424_WARN_VDD_OTW_CH1) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH1))
+		dev_warn(dev, "experienced an overtemp warning on CH1\n");
+
+	if ((reg & TAS6424_WARN_VDD_OTW_CH2) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH2))
+		dev_warn(dev, "experienced an overtemp warning on CH2\n");
+
+	if ((reg & TAS6424_WARN_VDD_OTW_CH3) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH3))
+		dev_warn(dev, "experienced an overtemp warning on CH3\n");
+
+	if ((reg & TAS6424_WARN_VDD_OTW_CH4) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH4))
+		dev_warn(dev, "experienced an overtemp warning on CH4\n");
+
+	/* Store current warn value so we can detect any changes next time */
+	tas6424->last_warn = reg;
+
+	/* Clear any faults by toggling the CLEAR_FAULT control bit */
+	ret = regmap_write_bits(tas6424->regmap, TAS6424_MISC_CTRL3,
+				TAS6424_CLEAR_FAULT, TAS6424_CLEAR_FAULT);
+	if (ret < 0)
+		dev_err(dev, "failed to write MISC_CTRL3 register: %d\n", ret);
+
+	ret = regmap_write_bits(tas6424->regmap, TAS6424_MISC_CTRL3,
+				TAS6424_CLEAR_FAULT, 0);
+	if (ret < 0)
+		dev_err(dev, "failed to write MISC_CTRL3 register: %d\n", ret);
+
+out:
+	/* Schedule the next fault check at the specified interval */
+	schedule_delayed_work(&tas6424->fault_check_work,
+			      msecs_to_jiffies(TAS6424_FAULT_CHECK_INTERVAL));
+}
+
+static const struct reg_default tas6424_reg_defaults[] = {
+	{ TAS6424_MODE_CTRL,		0x00 },
+	{ TAS6424_MISC_CTRL1,		0x32 },
+	{ TAS6424_MISC_CTRL2,		0x62 },
+	{ TAS6424_SAP_CTRL,		0x04 },
+	{ TAS6424_CH_STATE_CTRL,	0x55 },
+	{ TAS6424_CH1_VOL_CTRL,		0xcf },
+	{ TAS6424_CH2_VOL_CTRL,		0xcf },
+	{ TAS6424_CH3_VOL_CTRL,		0xcf },
+	{ TAS6424_CH4_VOL_CTRL,		0xcf },
+	{ TAS6424_DC_DIAG_CTRL1,	0x00 },
+	{ TAS6424_DC_DIAG_CTRL2,	0x11 },
+	{ TAS6424_DC_DIAG_CTRL3,	0x11 },
+	{ TAS6424_PIN_CTRL,		0xff },
+	{ TAS6424_AC_DIAG_CTRL1,	0x00 },
+	{ TAS6424_MISC_CTRL3,		0x00 },
+	{ TAS6424_CLIP_CTRL,		0x01 },
+	{ TAS6424_CLIP_WINDOW,		0x14 },
+	{ TAS6424_CLIP_WARN,		0x00 },
+	{ TAS6424_CBC_STAT,		0x00 },
+	{ TAS6424_MISC_CTRL4,		0x40 },
+};
+
+static bool tas6424_is_writable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS6424_MODE_CTRL:
+	case TAS6424_MISC_CTRL1:
+	case TAS6424_MISC_CTRL2:
+	case TAS6424_SAP_CTRL:
+	case TAS6424_CH_STATE_CTRL:
+	case TAS6424_CH1_VOL_CTRL:
+	case TAS6424_CH2_VOL_CTRL:
+	case TAS6424_CH3_VOL_CTRL:
+	case TAS6424_CH4_VOL_CTRL:
+	case TAS6424_DC_DIAG_CTRL1:
+	case TAS6424_DC_DIAG_CTRL2:
+	case TAS6424_DC_DIAG_CTRL3:
+	case TAS6424_PIN_CTRL:
+	case TAS6424_AC_DIAG_CTRL1:
+	case TAS6424_MISC_CTRL3:
+	case TAS6424_CLIP_CTRL:
+	case TAS6424_CLIP_WINDOW:
+	case TAS6424_CLIP_WARN:
+	case TAS6424_CBC_STAT:
+	case TAS6424_MISC_CTRL4:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool tas6424_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS6424_DC_LOAD_DIAG_REP12:
+	case TAS6424_DC_LOAD_DIAG_REP34:
+	case TAS6424_DC_LOAD_DIAG_REPLO:
+	case TAS6424_CHANNEL_STATE:
+	case TAS6424_CHANNEL_FAULT:
+	case TAS6424_GLOB_FAULT1:
+	case TAS6424_GLOB_FAULT2:
+	case TAS6424_WARN:
+	case TAS6424_AC_LOAD_DIAG_REP1:
+	case TAS6424_AC_LOAD_DIAG_REP2:
+	case TAS6424_AC_LOAD_DIAG_REP3:
+	case TAS6424_AC_LOAD_DIAG_REP4:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config tas6424_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.writeable_reg = tas6424_is_writable_reg,
+	.volatile_reg = tas6424_is_volatile_reg,
+
+	.max_register = TAS6424_MAX,
+	.reg_defaults = tas6424_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tas6424_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id tas6424_of_ids[] = {
+	{ .compatible = "ti,tas6424", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, tas6424_of_ids);
+#endif
+
+static int tas6424_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct tas6424_data *tas6424;
+	int ret;
+	int i;
+
+	tas6424 = devm_kzalloc(dev, sizeof(*tas6424), GFP_KERNEL);
+	if (!tas6424)
+		return -ENOMEM;
+	dev_set_drvdata(dev, tas6424);
+
+	tas6424->dev = dev;
+
+	tas6424->regmap = devm_regmap_init_i2c(client, &tas6424_regmap_config);
+	if (IS_ERR(tas6424->regmap)) {
+		ret = PTR_ERR(tas6424->regmap);
+		dev_err(dev, "unable to allocate register map: %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * Get control of the standby pin and set it LOW to take the codec
+	 * out of the stand-by mode.
+	 * Note: The actual pin polarity is taken care of in the GPIO lib
+	 * according the polarity specified in the DTS.
+	 */
+	tas6424->standby_gpio = devm_gpiod_get_optional(dev, "standby",
+						      GPIOD_OUT_LOW);
+	if (IS_ERR(tas6424->standby_gpio)) {
+		if (PTR_ERR(tas6424->standby_gpio) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+		dev_info(dev, "failed to get standby GPIO: %ld\n",
+			PTR_ERR(tas6424->standby_gpio));
+		tas6424->standby_gpio = NULL;
+	}
+
+	/*
+	 * Get control of the mute pin and set it HIGH in order to start with
+	 * all the output muted.
+	 * Note: The actual pin polarity is taken care of in the GPIO lib
+	 * according the polarity specified in the DTS.
+	 */
+	tas6424->mute_gpio = devm_gpiod_get_optional(dev, "mute",
+						      GPIOD_OUT_HIGH);
+	if (IS_ERR(tas6424->mute_gpio)) {
+		if (PTR_ERR(tas6424->mute_gpio) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+		dev_info(dev, "failed to get nmute GPIO: %ld\n",
+			PTR_ERR(tas6424->mute_gpio));
+		tas6424->mute_gpio = NULL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(tas6424->supplies); i++)
+		tas6424->supplies[i].supply = tas6424_supply_names[i];
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(tas6424->supplies),
+				      tas6424->supplies);
+	if (ret) {
+		dev_err(dev, "unable to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(tas6424->supplies),
+				    tas6424->supplies);
+	if (ret) {
+		dev_err(dev, "unable to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	/* Reset device to establish well-defined startup state */
+	ret = regmap_update_bits(tas6424->regmap, TAS6424_MODE_CTRL,
+				 TAS6424_RESET, TAS6424_RESET);
+	if (ret) {
+		dev_err(dev, "unable to reset device: %d\n", ret);
+		return ret;
+	}
+
+	INIT_DELAYED_WORK(&tas6424->fault_check_work, tas6424_fault_check_work);
+
+	ret = devm_snd_soc_register_component(dev, &soc_codec_dev_tas6424,
+				     tas6424_dai, ARRAY_SIZE(tas6424_dai));
+	if (ret < 0) {
+		dev_err(dev, "unable to register codec: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tas6424_i2c_remove(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct tas6424_data *tas6424 = dev_get_drvdata(dev);
+	int ret;
+
+	cancel_delayed_work_sync(&tas6424->fault_check_work);
+
+	/* put the codec in stand-by */
+	if (tas6424->standby_gpio)
+		gpiod_set_value_cansleep(tas6424->standby_gpio, 1);
+
+	ret = regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies),
+				     tas6424->supplies);
+	if (ret < 0) {
+		dev_err(dev, "unable to disable supplies: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct i2c_device_id tas6424_i2c_ids[] = {
+	{ "tas6424", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas6424_i2c_ids);
+
+static struct i2c_driver tas6424_i2c_driver = {
+	.driver = {
+		.name = "tas6424",
+		.of_match_table = of_match_ptr(tas6424_of_ids),
+	},
+	.probe = tas6424_i2c_probe,
+	.remove = tas6424_i2c_remove,
+	.id_table = tas6424_i2c_ids,
+};
+module_i2c_driver(tas6424_i2c_driver);
+
+MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
+MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_DESCRIPTION("TAS6424 Audio amplifier driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/tas6424.h b/sound/soc/codecs/tas6424.h
new file mode 100644
index 0000000..b5958c4
--- /dev/null
+++ b/sound/soc/codecs/tas6424.h
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ALSA SoC Texas Instruments TAS6424 Quad-Channel Audio Amplifier
+ *
+ * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
+ *	Author: Andreas Dannenberg <dannenberg@ti.com>
+ *	Andrew F. Davis <afd@ti.com>
+ */
+
+#ifndef __TAS6424_H__
+#define __TAS6424_H__
+
+#define TAS6424_RATES (SNDRV_PCM_RATE_44100 | \
+		       SNDRV_PCM_RATE_48000 | \
+		       SNDRV_PCM_RATE_96000)
+
+#define TAS6424_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			 SNDRV_PCM_FMTBIT_S24_LE)
+
+/* Register Address Map */
+#define TAS6424_MODE_CTRL		0x00
+#define TAS6424_MISC_CTRL1		0x01
+#define TAS6424_MISC_CTRL2		0x02
+#define TAS6424_SAP_CTRL		0x03
+#define TAS6424_CH_STATE_CTRL		0x04
+#define TAS6424_CH1_VOL_CTRL		0x05
+#define TAS6424_CH2_VOL_CTRL		0x06
+#define TAS6424_CH3_VOL_CTRL		0x07
+#define TAS6424_CH4_VOL_CTRL		0x08
+#define TAS6424_DC_DIAG_CTRL1		0x09
+#define TAS6424_DC_DIAG_CTRL2		0x0a
+#define TAS6424_DC_DIAG_CTRL3		0x0b
+#define TAS6424_DC_LOAD_DIAG_REP12	0x0c
+#define TAS6424_DC_LOAD_DIAG_REP34	0x0d
+#define TAS6424_DC_LOAD_DIAG_REPLO	0x0e
+#define TAS6424_CHANNEL_STATE		0x0f
+#define TAS6424_CHANNEL_FAULT		0x10
+#define TAS6424_GLOB_FAULT1		0x11
+#define TAS6424_GLOB_FAULT2		0x12
+#define TAS6424_WARN			0x13
+#define TAS6424_PIN_CTRL		0x14
+#define TAS6424_AC_DIAG_CTRL1		0x15
+#define TAS6424_AC_DIAG_CTRL2		0x16
+#define TAS6424_AC_LOAD_DIAG_REP1	0x17
+#define TAS6424_AC_LOAD_DIAG_REP2	0x18
+#define TAS6424_AC_LOAD_DIAG_REP3	0x19
+#define TAS6424_AC_LOAD_DIAG_REP4	0x1a
+#define TAS6424_MISC_CTRL3		0x21
+#define TAS6424_CLIP_CTRL		0x22
+#define TAS6424_CLIP_WINDOW		0x23
+#define TAS6424_CLIP_WARN		0x24
+#define TAS6424_CBC_STAT		0x25
+#define TAS6424_MISC_CTRL4		0x26
+#define TAS6424_MAX			TAS6424_MISC_CTRL4
+
+/* TAS6424_MODE_CTRL_REG */
+#define TAS6424_RESET			BIT(7)
+
+/* TAS6424_SAP_CTRL_REG */
+#define TAS6424_SAP_RATE_MASK		GENMASK(7, 6)
+#define TAS6424_SAP_RATE_44100		(0x00 << 6)
+#define TAS6424_SAP_RATE_48000		(0x01 << 6)
+#define TAS6424_SAP_RATE_96000		(0x02 << 6)
+#define TAS6424_SAP_TDM_SLOT_LAST	BIT(5)
+#define TAS6424_SAP_TDM_SLOT_SZ_16	BIT(4)
+#define TAS6424_SAP_TDM_SLOT_SWAP	BIT(3)
+#define TAS6424_SAP_FMT_MASK		GENMASK(2, 0)
+#define TAS6424_SAP_RIGHTJ_24		(0x00 << 0)
+#define TAS6424_SAP_RIGHTJ_20		(0x01 << 0)
+#define TAS6424_SAP_RIGHTJ_18		(0x02 << 0)
+#define TAS6424_SAP_RIGHTJ_16		(0x03 << 0)
+#define TAS6424_SAP_I2S			(0x04 << 0)
+#define TAS6424_SAP_LEFTJ		(0x05 << 0)
+#define TAS6424_SAP_DSP			(0x06 << 0)
+
+/* TAS6424_CH_STATE_CTRL_REG */
+#define TAS6424_CH1_STATE_MASK		GENMASK(7, 6)
+#define TAS6424_CH1_STATE_PLAY		(0x00 << 6)
+#define TAS6424_CH1_STATE_HIZ		(0x01 << 6)
+#define TAS6424_CH1_STATE_MUTE		(0x02 << 6)
+#define TAS6424_CH1_STATE_DIAG		(0x03 << 6)
+#define TAS6424_CH2_STATE_MASK		GENMASK(5, 4)
+#define TAS6424_CH2_STATE_PLAY		(0x00 << 4)
+#define TAS6424_CH2_STATE_HIZ		(0x01 << 4)
+#define TAS6424_CH2_STATE_MUTE		(0x02 << 4)
+#define TAS6424_CH2_STATE_DIAG		(0x03 << 4)
+#define TAS6424_CH3_STATE_MASK		GENMASK(3, 2)
+#define TAS6424_CH3_STATE_PLAY		(0x00 << 2)
+#define TAS6424_CH3_STATE_HIZ		(0x01 << 2)
+#define TAS6424_CH3_STATE_MUTE		(0x02 << 2)
+#define TAS6424_CH3_STATE_DIAG		(0x03 << 2)
+#define TAS6424_CH4_STATE_MASK		GENMASK(1, 0)
+#define TAS6424_CH4_STATE_PLAY		(0x00 << 0)
+#define TAS6424_CH4_STATE_HIZ		(0x01 << 0)
+#define TAS6424_CH4_STATE_MUTE		(0x02 << 0)
+#define TAS6424_CH4_STATE_DIAG		(0x03 << 0)
+#define TAS6424_ALL_STATE_PLAY		(TAS6424_CH1_STATE_PLAY | \
+					 TAS6424_CH2_STATE_PLAY | \
+					 TAS6424_CH3_STATE_PLAY | \
+					 TAS6424_CH4_STATE_PLAY)
+#define TAS6424_ALL_STATE_HIZ		(TAS6424_CH1_STATE_HIZ | \
+					 TAS6424_CH2_STATE_HIZ | \
+					 TAS6424_CH3_STATE_HIZ | \
+					 TAS6424_CH4_STATE_HIZ)
+#define TAS6424_ALL_STATE_MUTE		(TAS6424_CH1_STATE_MUTE | \
+					 TAS6424_CH2_STATE_MUTE | \
+					 TAS6424_CH3_STATE_MUTE | \
+					 TAS6424_CH4_STATE_MUTE)
+#define TAS6424_ALL_STATE_DIAG		(TAS6424_CH1_STATE_DIAG | \
+					 TAS6424_CH2_STATE_DIAG | \
+					 TAS6424_CH3_STATE_DIAG | \
+					 TAS6424_CH4_STATE_DIAG)
+
+/* TAS6424_DC_DIAG_CTRL1 */
+#define TAS6424_LDGBYPASS_SHIFT		0
+#define TAS6424_LDGBYPASS_MASK		BIT(TAS6424_LDGBYPASS_SHIFT)
+
+/* TAS6424_GLOB_FAULT1_REG */
+#define TAS6424_FAULT_CLOCK		BIT(4)
+#define TAS6424_FAULT_PVDD_OV		BIT(3)
+#define TAS6424_FAULT_VBAT_OV		BIT(2)
+#define TAS6424_FAULT_PVDD_UV		BIT(1)
+#define TAS6424_FAULT_VBAT_UV		BIT(0)
+
+/* TAS6424_GLOB_FAULT2_REG */
+#define TAS6424_FAULT_OTSD		BIT(4)
+#define TAS6424_FAULT_OTSD_CH1		BIT(3)
+#define TAS6424_FAULT_OTSD_CH2		BIT(2)
+#define TAS6424_FAULT_OTSD_CH3		BIT(1)
+#define TAS6424_FAULT_OTSD_CH4		BIT(0)
+
+/* TAS6424_WARN_REG */
+#define TAS6424_WARN_VDD_UV		BIT(6)
+#define TAS6424_WARN_VDD_POR		BIT(5)
+#define TAS6424_WARN_VDD_OTW		BIT(4)
+#define TAS6424_WARN_VDD_OTW_CH1	BIT(3)
+#define TAS6424_WARN_VDD_OTW_CH2	BIT(2)
+#define TAS6424_WARN_VDD_OTW_CH3	BIT(1)
+#define TAS6424_WARN_VDD_OTW_CH4	BIT(0)
+
+/* TAS6424_MISC_CTRL3_REG */
+#define TAS6424_CLEAR_FAULT		BIT(7)
+#define TAS6424_PBTL_CH_SEL		BIT(6)
+#define TAS6424_MASK_CBC_WARN		BIT(5)
+#define TAS6424_MASK_VDD_UV		BIT(4)
+#define TAS6424_OTSD_AUTO_RECOVERY	BIT(3)
+
+#endif /* __TAS6424_H__ */
diff --git a/sound/soc/codecs/tda7419.c b/sound/soc/codecs/tda7419.c
new file mode 100644
index 0000000..7f3b79c
--- /dev/null
+++ b/sound/soc/codecs/tda7419.c
@@ -0,0 +1,654 @@
+/*
+ * TDA7419 audio processor driver
+ *
+ * Copyright 2018 Konsulko Group
+ *
+ * Author: Matt Porter <mporter@konsulko.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#define TDA7419_MAIN_SRC_REG		0x00
+#define TDA7419_LOUDNESS_REG		0x01
+#define TDA7419_MUTE_CLK_REG		0x02
+#define TDA7419_VOLUME_REG		0x03
+#define TDA7419_TREBLE_REG		0x04
+#define TDA7419_MIDDLE_REG		0x05
+#define TDA7419_BASS_REG		0x06
+#define TDA7419_SECOND_SRC_REG		0x07
+#define TDA7419_SUB_MID_BASS_REG	0x08
+#define TDA7419_MIXING_GAIN_REG		0x09
+#define TDA7419_ATTENUATOR_LF_REG	0x0a
+#define TDA7419_ATTENUATOR_RF_REG	0x0b
+#define TDA7419_ATTENUATOR_LR_REG	0x0c
+#define TDA7419_ATTENUATOR_RR_REG	0x0d
+#define TDA7419_MIXING_LEVEL_REG	0x0e
+#define TDA7419_ATTENUATOR_SUB_REG	0x0f
+#define TDA7419_SA_CLK_AC_REG		0x10
+#define TDA7419_TESTING_REG		0x11
+
+#define TDA7419_MAIN_SRC_SEL		0
+#define TDA7419_MAIN_SRC_GAIN		3
+#define TDA7419_MAIN_SRC_AUTOZERO	7
+
+#define TDA7419_LOUDNESS_ATTEN		0
+#define TDA7419_LOUDNESS_CENTER_FREQ	4
+#define TDA7419_LOUDNESS_BOOST		6
+#define TDA7419_LOUDNESS_SOFT_STEP	7
+
+#define TDA7419_VOLUME_SOFT_STEP	7
+
+#define TDA7419_SOFT_MUTE		0
+#define TDA7419_MUTE_INFLUENCE		1
+#define TDA7419_SOFT_MUTE_TIME		2
+#define TDA7419_SOFT_STEP_TIME		4
+#define TDA7419_CLK_FAST_MODE		7
+
+#define TDA7419_TREBLE_CENTER_FREQ	5
+#define TDA7419_REF_OUT_SELECT		7
+
+#define TDA7419_MIDDLE_Q_FACTOR		5
+#define TDA7419_MIDDLE_SOFT_STEP	7
+
+#define TDA7419_BASS_Q_FACTOR		5
+#define TDA7419_BASS_SOFT_STEP		7
+
+#define TDA7419_SECOND_SRC_SEL		0
+#define TDA7419_SECOND_SRC_GAIN		3
+#define TDA7419_REAR_SPKR_SRC		7
+
+#define TDA7419_SUB_CUT_OFF_FREQ	0
+#define TDA7419_MIDDLE_CENTER_FREQ	2
+#define TDA7419_BASS_CENTER_FREQ	4
+#define TDA7419_BASS_DC_MODE		6
+#define TDA7419_SMOOTHING_FILTER	7
+
+#define TDA7419_MIX_LF			0
+#define TDA7419_MIX_RF			1
+#define TDA7419_MIX_ENABLE		2
+#define TDA7419_SUB_ENABLE		3
+#define TDA7419_HPF_GAIN		4
+
+#define TDA7419_SA_Q_FACTOR		0
+#define TDA7419_RESET_MODE		1
+#define TDA7419_SA_SOURCE		2
+#define TDA7419_SA_RUN			3
+#define TDA7419_RESET			4
+#define TDA7419_CLK_SOURCE		5
+#define TDA7419_COUPLING_MODE		6
+
+struct tda7419_data {
+	struct regmap *regmap;
+};
+
+static bool tda7419_readable_reg(struct device *dev, unsigned int reg)
+{
+	return false;
+}
+
+static const struct reg_default tda7419_regmap_defaults[] = {
+	{ TDA7419_MAIN_SRC_REG,	0xfe },
+	{ TDA7419_LOUDNESS_REG, 0xfe },
+	{ TDA7419_MUTE_CLK_REG, 0xfe },
+	{ TDA7419_VOLUME_REG, 0xfe },
+	{ TDA7419_TREBLE_REG, 0xfe },
+	{ TDA7419_MIDDLE_REG, 0xfe },
+	{ TDA7419_BASS_REG, 0xfe },
+	{ TDA7419_SECOND_SRC_REG, 0xfe },
+	{ TDA7419_SUB_MID_BASS_REG, 0xfe },
+	{ TDA7419_MIXING_GAIN_REG, 0xfe },
+	{ TDA7419_ATTENUATOR_LF_REG, 0xfe },
+	{ TDA7419_ATTENUATOR_RF_REG, 0xfe },
+	{ TDA7419_ATTENUATOR_LR_REG, 0xfe },
+	{ TDA7419_ATTENUATOR_RR_REG, 0xfe },
+	{ TDA7419_MIXING_LEVEL_REG, 0xfe },
+	{ TDA7419_ATTENUATOR_SUB_REG, 0xfe },
+	{ TDA7419_SA_CLK_AC_REG, 0xfe },
+	{ TDA7419_TESTING_REG, 0xfe },
+};
+
+static const struct regmap_config tda7419_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = TDA7419_TESTING_REG,
+	.cache_type = REGCACHE_RBTREE,
+	.readable_reg = tda7419_readable_reg,
+	.reg_defaults = tda7419_regmap_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tda7419_regmap_defaults),
+};
+
+struct tda7419_vol_control {
+	int min, max;
+	unsigned int reg, rreg, mask, thresh;
+	unsigned int invert:1;
+};
+
+static inline bool tda7419_vol_is_stereo(struct tda7419_vol_control *tvc)
+{
+	if (tvc->reg == tvc->rreg)
+		return false;
+
+	return true;
+}
+
+static int tda7419_vol_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	struct tda7419_vol_control *tvc =
+		(struct tda7419_vol_control *)kcontrol->private_value;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = tda7419_vol_is_stereo(tvc) ? 2 : 1;
+	uinfo->value.integer.min = tvc->min;
+	uinfo->value.integer.max = tvc->max;
+
+	return 0;
+}
+
+static inline int tda7419_vol_get_value(int val, unsigned int mask,
+					int min, int thresh,
+					unsigned int invert)
+{
+	val &= mask;
+	if (val < thresh) {
+		if (invert)
+			val = 0 - val;
+	} else if (val > thresh) {
+		if (invert)
+			val = val - thresh;
+		else
+			val = thresh - val;
+	}
+
+	if (val < min)
+		val = min;
+
+	return val;
+}
+
+static int tda7419_vol_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct tda7419_vol_control *tvc =
+		(struct tda7419_vol_control *)kcontrol->private_value;
+	unsigned int reg = tvc->reg;
+	unsigned int rreg = tvc->rreg;
+	unsigned int mask = tvc->mask;
+	int min = tvc->min;
+	int thresh = tvc->thresh;
+	unsigned int invert = tvc->invert;
+	int val;
+	int ret;
+
+	ret = snd_soc_component_read(component, reg, &val);
+	if (ret < 0)
+		return ret;
+	ucontrol->value.integer.value[0] =
+		tda7419_vol_get_value(val, mask, min, thresh, invert);
+
+	if (tda7419_vol_is_stereo(tvc)) {
+		ret = snd_soc_component_read(component, rreg, &val);
+		if (ret < 0)
+			return ret;
+		ucontrol->value.integer.value[1] =
+			tda7419_vol_get_value(val, mask, min, thresh, invert);
+	}
+
+	return 0;
+}
+
+static inline int tda7419_vol_put_value(int val, int thresh,
+					unsigned int invert)
+{
+	if (val < 0) {
+		if (invert)
+			val = abs(val);
+		else
+			val = thresh - val;
+	} else if ((val > 0) && invert) {
+		val += thresh;
+	}
+
+	return val;
+}
+
+static int tda7419_vol_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_kcontrol_chip(kcontrol);
+	struct tda7419_vol_control *tvc =
+		(struct tda7419_vol_control *)kcontrol->private_value;
+	unsigned int reg = tvc->reg;
+	unsigned int rreg = tvc->rreg;
+	unsigned int mask = tvc->mask;
+	int thresh = tvc->thresh;
+	unsigned int invert = tvc->invert;
+	int val;
+	int ret;
+
+	val = tda7419_vol_put_value(ucontrol->value.integer.value[0],
+				    thresh, invert);
+	ret = snd_soc_component_update_bits(component, reg,
+					    mask, val);
+	if (ret < 0)
+		return ret;
+
+	if (tda7419_vol_is_stereo(tvc)) {
+		val = tda7419_vol_put_value(ucontrol->value.integer.value[1],
+					    thresh, invert);
+		ret = snd_soc_component_update_bits(component, rreg,
+						    mask, val);
+	}
+
+	return ret;
+}
+
+#define TDA7419_SINGLE_VALUE(xreg, xmask, xmin, xmax, xthresh, xinvert) \
+	((unsigned long)&(struct tda7419_vol_control) \
+	{.reg = xreg, .rreg = xreg, .mask = xmask, .min = xmin, \
+	 .max = xmax, .thresh = xthresh, .invert = xinvert})
+
+#define TDA7419_DOUBLE_R_VALUE(xregl, xregr, xmask, xmin, xmax, xthresh, \
+			       xinvert) \
+	((unsigned long)&(struct tda7419_vol_control) \
+	{.reg = xregl, .rreg = xregr, .mask = xmask, .min = xmin, \
+	 .max = xmax, .thresh = xthresh, .invert = xinvert})
+
+#define TDA7419_SINGLE_TLV(xname, xreg, xmask, xmin, xmax, xthresh, \
+			   xinvert, xtlv_array) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+	.name = xname, \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+		SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.tlv.p = (xtlv_array), \
+	.info = tda7419_vol_info, \
+	.get = tda7419_vol_get, \
+	.put = tda7419_vol_put, \
+	.private_value = TDA7419_SINGLE_VALUE(xreg, xmask, xmin, \
+					      xmax, xthresh, xinvert), \
+}
+
+#define TDA7419_DOUBLE_R_TLV(xname, xregl, xregr, xmask, xmin, xmax, \
+			     xthresh, xinvert, xtlv_array) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+	.name = xname, \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+		SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.tlv.p = (xtlv_array), \
+	.info = tda7419_vol_info, \
+	.get = tda7419_vol_get, \
+	.put = tda7419_vol_put, \
+	.private_value = TDA7419_DOUBLE_R_VALUE(xregl, xregr, xmask, \
+						xmin, xmax, xthresh, \
+						xinvert), \
+}
+
+static const char * const enum_src_sel[] = {
+	"QD", "SE1", "SE2", "SE3", "SE", "Mute", "Mute", "Mute"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_main_src_sel,
+	TDA7419_MAIN_SRC_REG, TDA7419_MAIN_SRC_SEL, enum_src_sel);
+static const struct snd_kcontrol_new soc_mux_main_src_sel =
+	SOC_DAPM_ENUM("Main Source Select", soc_enum_main_src_sel);
+static DECLARE_TLV_DB_SCALE(tlv_src_gain, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(tlv_loudness_atten, -1500, 100, 0);
+static const char * const enum_loudness_center_freq[] = {
+	"Flat", "400 Hz", "800 Hz", "2400 Hz"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_loudness_center_freq,
+	TDA7419_LOUDNESS_REG, TDA7419_LOUDNESS_CENTER_FREQ,
+	enum_loudness_center_freq);
+static const char * const enum_mute_influence[] = {
+	"Pin and IIC", "IIC"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_mute_influence,
+	TDA7419_MUTE_CLK_REG, TDA7419_MUTE_INFLUENCE, enum_mute_influence);
+static const char * const enum_soft_mute_time[] = {
+	"0.48 ms", "0.96 ms", "123 ms", "123 ms"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_soft_mute_time,
+	TDA7419_MUTE_CLK_REG, TDA7419_SOFT_MUTE_TIME, enum_soft_mute_time);
+static const char * const enum_soft_step_time[] = {
+	"0.160 ms", "0.321 ms", "0.642 ms", "1.28 ms",
+	"2.56 ms", "5.12 ms", "10.24 ms", "20.48 ms"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_soft_step_time,
+	TDA7419_MUTE_CLK_REG, TDA7419_SOFT_STEP_TIME, enum_soft_step_time);
+static DECLARE_TLV_DB_SCALE(tlv_volume, -8000, 100, 1);
+static const char * const enum_treble_center_freq[] = {
+	"10.0 kHz", "12.5 kHz", "15.0 kHz", "17.5 kHz"};
+static DECLARE_TLV_DB_SCALE(tlv_filter, -1500, 100, 0);
+static SOC_ENUM_SINGLE_DECL(soc_enum_treble_center_freq,
+	TDA7419_TREBLE_REG, TDA7419_TREBLE_CENTER_FREQ,
+	enum_treble_center_freq);
+static const char * const enum_ref_out_select[] = {
+	"External Vref (4 V)", "Internal Vref (3.3 V)"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_ref_out_select,
+	TDA7419_TREBLE_REG, TDA7419_REF_OUT_SELECT, enum_ref_out_select);
+static const char * const enum_middle_q_factor[] = {
+	"0.5", "0.75", "1.0", "1.25"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_middle_q_factor,
+	TDA7419_MIDDLE_REG, TDA7419_MIDDLE_Q_FACTOR, enum_middle_q_factor);
+static const char * const enum_bass_q_factor[] = {
+	"1.0", "1.25", "1.5", "2.0"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_bass_q_factor,
+	TDA7419_BASS_REG, TDA7419_BASS_Q_FACTOR, enum_bass_q_factor);
+static SOC_ENUM_SINGLE_DECL(soc_enum_second_src_sel,
+	TDA7419_SECOND_SRC_REG, TDA7419_SECOND_SRC_SEL, enum_src_sel);
+static const struct snd_kcontrol_new soc_mux_second_src_sel =
+	SOC_DAPM_ENUM("Second Source Select", soc_enum_second_src_sel);
+static const char * const enum_rear_spkr_src[] = {
+	"Main", "Second"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_rear_spkr_src,
+	TDA7419_SECOND_SRC_REG, TDA7419_REAR_SPKR_SRC, enum_rear_spkr_src);
+static const struct snd_kcontrol_new soc_mux_rear_spkr_src =
+	SOC_DAPM_ENUM("Rear Speaker Source", soc_enum_rear_spkr_src);
+static const char * const enum_sub_cut_off_freq[] = {
+	"Flat", "80 Hz", "120 Hz", "160 Hz"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_sub_cut_off_freq,
+	TDA7419_SUB_MID_BASS_REG, TDA7419_SUB_CUT_OFF_FREQ,
+	enum_sub_cut_off_freq);
+static const char * const enum_middle_center_freq[] = {
+	"500 Hz", "1000 Hz", "1500 Hz", "2500 Hz"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_middle_center_freq,
+	TDA7419_SUB_MID_BASS_REG, TDA7419_MIDDLE_CENTER_FREQ,
+	enum_middle_center_freq);
+static const char * const enum_bass_center_freq[] = {
+	"60 Hz", "80 Hz", "100 Hz", "200 Hz"};
+static SOC_ENUM_SINGLE_DECL(soc_enum_bass_center_freq,
+	TDA7419_SUB_MID_BASS_REG, TDA7419_BASS_CENTER_FREQ,
+	enum_bass_center_freq);
+static const char * const enum_sa_q_factor[] = {
+	"3.5", "1.75" };
+static SOC_ENUM_SINGLE_DECL(soc_enum_sa_q_factor,
+	TDA7419_SA_CLK_AC_REG, TDA7419_SA_Q_FACTOR, enum_sa_q_factor);
+static const char * const enum_reset_mode[] = {
+	"IIC", "Auto" };
+static SOC_ENUM_SINGLE_DECL(soc_enum_reset_mode,
+	TDA7419_SA_CLK_AC_REG, TDA7419_RESET_MODE, enum_reset_mode);
+static const char * const enum_sa_src[] = {
+	"Bass", "In Gain" };
+static SOC_ENUM_SINGLE_DECL(soc_enum_sa_src,
+	TDA7419_SA_CLK_AC_REG, TDA7419_SA_SOURCE, enum_sa_src);
+static const char * const enum_clk_src[] = {
+	"Internal", "External" };
+static SOC_ENUM_SINGLE_DECL(soc_enum_clk_src,
+	TDA7419_SA_CLK_AC_REG, TDA7419_CLK_SOURCE, enum_clk_src);
+static const char * const enum_coupling_mode[] = {
+	"DC Coupling (without HPF)", "AC Coupling after In Gain",
+	"DC Coupling (with HPF)", "AC Coupling after Bass" };
+static SOC_ENUM_SINGLE_DECL(soc_enum_coupling_mode,
+	TDA7419_SA_CLK_AC_REG, TDA7419_COUPLING_MODE, enum_coupling_mode);
+
+/* ASoC Controls */
+static struct snd_kcontrol_new tda7419_controls[] = {
+SOC_SINGLE_TLV("Main Source Capture Volume", TDA7419_MAIN_SRC_REG,
+	       TDA7419_MAIN_SRC_GAIN, 15, 0, tlv_src_gain),
+SOC_SINGLE("Main Source AutoZero Switch", TDA7419_MAIN_SRC_REG,
+	   TDA7419_MAIN_SRC_AUTOZERO, 1, 1),
+SOC_SINGLE_TLV("Loudness Playback Volume", TDA7419_LOUDNESS_REG,
+	       TDA7419_LOUDNESS_ATTEN, 15, 1, tlv_loudness_atten),
+SOC_ENUM("Loudness Center Frequency", soc_enum_loudness_center_freq),
+SOC_SINGLE("Loudness High Boost Switch", TDA7419_LOUDNESS_REG,
+	   TDA7419_LOUDNESS_BOOST, 1, 1),
+SOC_SINGLE("Loudness Soft Step Switch", TDA7419_LOUDNESS_REG,
+	   TDA7419_LOUDNESS_SOFT_STEP, 1, 1),
+SOC_SINGLE("Soft Mute Switch", TDA7419_MUTE_CLK_REG, TDA7419_SOFT_MUTE, 1, 1),
+SOC_ENUM("Mute Influence", soc_enum_mute_influence),
+SOC_ENUM("Soft Mute Time", soc_enum_soft_mute_time),
+SOC_ENUM("Soft Step Time", soc_enum_soft_step_time),
+SOC_SINGLE("Clock Fast Mode Switch", TDA7419_MUTE_CLK_REG,
+	   TDA7419_CLK_FAST_MODE, 1, 1),
+TDA7419_SINGLE_TLV("Master Playback Volume", TDA7419_VOLUME_REG,
+		   0x7f, -80, 15, 0x10, 0, tlv_volume),
+SOC_SINGLE("Volume Soft Step Switch", TDA7419_VOLUME_REG,
+	   TDA7419_VOLUME_SOFT_STEP, 1, 1),
+TDA7419_SINGLE_TLV("Treble Playback Volume", TDA7419_TREBLE_REG,
+		   0x1f, -15, 15, 0x10, 1, tlv_filter),
+SOC_ENUM("Treble Center Frequency", soc_enum_treble_center_freq),
+SOC_ENUM("Reference Output Select", soc_enum_ref_out_select),
+TDA7419_SINGLE_TLV("Middle Playback Volume", TDA7419_MIDDLE_REG,
+		   0x1f, -15, 15, 0x10, 1, tlv_filter),
+SOC_ENUM("Middle Q Factor", soc_enum_middle_q_factor),
+SOC_SINGLE("Middle Soft Step Switch", TDA7419_MIDDLE_REG,
+	   TDA7419_MIDDLE_SOFT_STEP, 1, 1),
+TDA7419_SINGLE_TLV("Bass Playback Volume", TDA7419_BASS_REG,
+		   0x1f, -15, 15, 0x10, 1, tlv_filter),
+SOC_ENUM("Bass Q Factor", soc_enum_bass_q_factor),
+SOC_SINGLE("Bass Soft Step Switch", TDA7419_BASS_REG,
+	   TDA7419_BASS_SOFT_STEP, 1, 1),
+SOC_SINGLE_TLV("Second Source Capture Volume", TDA7419_SECOND_SRC_REG,
+	       TDA7419_SECOND_SRC_GAIN, 15, 0, tlv_src_gain),
+SOC_ENUM("Subwoofer Cut-off Frequency", soc_enum_sub_cut_off_freq),
+SOC_ENUM("Middle Center Frequency", soc_enum_middle_center_freq),
+SOC_ENUM("Bass Center Frequency", soc_enum_bass_center_freq),
+SOC_SINGLE("Bass DC Mode Switch", TDA7419_SUB_MID_BASS_REG,
+	   TDA7419_BASS_DC_MODE, 1, 1),
+SOC_SINGLE("Smoothing Filter Switch", TDA7419_SUB_MID_BASS_REG,
+	   TDA7419_SMOOTHING_FILTER, 1, 1),
+TDA7419_DOUBLE_R_TLV("Front Speaker Playback Volume", TDA7419_ATTENUATOR_LF_REG,
+		     TDA7419_ATTENUATOR_RF_REG, 0x7f, -80, 15, 0x10, 0,
+		     tlv_volume),
+SOC_SINGLE("Left Front Soft Step Switch", TDA7419_ATTENUATOR_LF_REG,
+	   TDA7419_VOLUME_SOFT_STEP, 1, 1),
+SOC_SINGLE("Right Front Soft Step Switch", TDA7419_ATTENUATOR_RF_REG,
+	   TDA7419_VOLUME_SOFT_STEP, 1, 1),
+TDA7419_DOUBLE_R_TLV("Rear Speaker Playback Volume", TDA7419_ATTENUATOR_LR_REG,
+		     TDA7419_ATTENUATOR_RR_REG, 0x7f, -80, 15, 0x10, 0,
+		     tlv_volume),
+SOC_SINGLE("Left Rear Soft Step Switch", TDA7419_ATTENUATOR_LR_REG,
+	   TDA7419_VOLUME_SOFT_STEP, 1, 1),
+SOC_SINGLE("Right Rear Soft Step Switch", TDA7419_ATTENUATOR_RR_REG,
+	   TDA7419_VOLUME_SOFT_STEP, 1, 1),
+TDA7419_SINGLE_TLV("Mixing Capture Volume", TDA7419_MIXING_LEVEL_REG,
+		   0x7f, -80, 15, 0x10, 0, tlv_volume),
+SOC_SINGLE("Mixing Level Soft Step Switch", TDA7419_MIXING_LEVEL_REG,
+	   TDA7419_VOLUME_SOFT_STEP, 1, 1),
+TDA7419_SINGLE_TLV("Subwoofer Playback Volume", TDA7419_ATTENUATOR_SUB_REG,
+		   0x7f, -80, 15, 0x10, 0, tlv_volume),
+SOC_SINGLE("Subwoofer Soft Step Switch", TDA7419_ATTENUATOR_SUB_REG,
+	   TDA7419_VOLUME_SOFT_STEP, 1, 1),
+SOC_ENUM("Spectrum Analyzer Q Factor", soc_enum_sa_q_factor),
+SOC_ENUM("Spectrum Analyzer Reset Mode", soc_enum_reset_mode),
+SOC_ENUM("Spectrum Analyzer Source", soc_enum_sa_src),
+SOC_SINGLE("Spectrum Analyzer Run Switch", TDA7419_SA_CLK_AC_REG,
+	   TDA7419_SA_RUN, 1, 1),
+SOC_SINGLE("Spectrum Analyzer Reset Switch", TDA7419_SA_CLK_AC_REG,
+	   TDA7419_RESET, 1, 1),
+SOC_ENUM("Clock Source", soc_enum_clk_src),
+SOC_ENUM("Coupling Mode", soc_enum_coupling_mode),
+};
+
+static const struct snd_kcontrol_new soc_mixer_lf_output_controls[] = {
+	SOC_DAPM_SINGLE("Mix to LF Speaker Switch",
+			TDA7419_MIXING_GAIN_REG,
+			TDA7419_MIX_LF, 1, 1),
+};
+
+static const struct snd_kcontrol_new soc_mixer_rf_output_controls[] = {
+	SOC_DAPM_SINGLE("Mix to RF Speaker Switch",
+			TDA7419_MIXING_GAIN_REG,
+			TDA7419_MIX_RF, 1, 1),
+};
+
+static const struct snd_kcontrol_new soc_mix_enable_switch_controls[] = {
+	SOC_DAPM_SINGLE("Switch", TDA7419_MIXING_GAIN_REG,
+			TDA7419_MIX_ENABLE, 1, 1),
+};
+
+static const struct snd_kcontrol_new soc_sub_enable_switch_controls[] = {
+	SOC_DAPM_SINGLE("Switch", TDA7419_MIXING_GAIN_REG,
+			TDA7419_MIX_ENABLE, 1, 1),
+};
+
+static const struct snd_soc_dapm_widget tda7419_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("SE3L"),
+	SND_SOC_DAPM_INPUT("SE3R"),
+	SND_SOC_DAPM_INPUT("SE2L"),
+	SND_SOC_DAPM_INPUT("SE2R"),
+	SND_SOC_DAPM_INPUT("SE1L"),
+	SND_SOC_DAPM_INPUT("SE1R"),
+	SND_SOC_DAPM_INPUT("DIFFL"),
+	SND_SOC_DAPM_INPUT("DIFFR"),
+	SND_SOC_DAPM_INPUT("MIX"),
+
+	SND_SOC_DAPM_MUX("Main Source Select", SND_SOC_NOPM,
+			 0, 0, &soc_mux_main_src_sel),
+	SND_SOC_DAPM_MUX("Second Source Select", SND_SOC_NOPM,
+			 0, 0, &soc_mux_second_src_sel),
+	SND_SOC_DAPM_MUX("Rear Speaker Source", SND_SOC_NOPM,
+			 0, 0, &soc_mux_rear_spkr_src),
+
+	SND_SOC_DAPM_SWITCH("Mix Enable", SND_SOC_NOPM,
+			0, 0, &soc_mix_enable_switch_controls[0]),
+	SND_SOC_DAPM_MIXER_NAMED_CTL("LF Output Mixer", SND_SOC_NOPM,
+			0, 0, &soc_mixer_lf_output_controls[0],
+			ARRAY_SIZE(soc_mixer_lf_output_controls)),
+	SND_SOC_DAPM_MIXER_NAMED_CTL("RF Output Mixer", SND_SOC_NOPM,
+			0, 0, &soc_mixer_rf_output_controls[0],
+			ARRAY_SIZE(soc_mixer_rf_output_controls)),
+
+	SND_SOC_DAPM_SWITCH("Subwoofer Enable",
+			SND_SOC_NOPM, 0, 0,
+			&soc_sub_enable_switch_controls[0]),
+
+	SND_SOC_DAPM_OUTPUT("OUTLF"),
+	SND_SOC_DAPM_OUTPUT("OUTRF"),
+	SND_SOC_DAPM_OUTPUT("OUTLR"),
+	SND_SOC_DAPM_OUTPUT("OUTRR"),
+	SND_SOC_DAPM_OUTPUT("OUTSW"),
+};
+
+static const struct snd_soc_dapm_route tda7419_dapm_routes[] = {
+	{"Main Source Select", "SE3", "SE3L"},
+	{"Main Source Select", "SE3", "SE3R"},
+	{"Main Source Select", "SE2", "SE2L"},
+	{"Main Source Select", "SE2", "SE2R"},
+	{"Main Source Select", "SE1", "SE1L"},
+	{"Main Source Select", "SE1", "SE1R"},
+	{"Main Source Select", "SE", "DIFFL"},
+	{"Main Source Select", "SE", "DIFFR"},
+	{"Main Source Select", "QD", "DIFFL"},
+	{"Main Source Select", "QD", "DIFFR"},
+
+	{"Second Source Select", "SE3", "SE3L"},
+	{"Second Source Select", "SE3", "SE3R"},
+	{"Second Source Select", "SE2", "SE2L"},
+	{"Second Source Select", "SE2", "SE2R"},
+	{"Second Source Select", "SE1", "SE1L"},
+	{"Second Source Select", "SE1", "SE1R"},
+	{"Second Source Select", "SE", "DIFFL"},
+	{"Second Source Select", "SE", "DIFFR"},
+	{"Second Source Select", "QD", "DIFFL"},
+	{"Second Source Select", "QD", "DIFFR"},
+
+	{"Rear Speaker Source", "Main", "Main Source Select"},
+	{"Rear Speaker Source", "Second", "Second Source Select"},
+
+	{"Subwoofer Enable", "Switch", "Main Source Select"},
+
+	{"Mix Enable", "Switch", "MIX"},
+
+	{"LF Output Mixer", NULL, "Main Source Select"},
+	{"LF Output Mixer", "Mix to LF Speaker Switch", "Mix Enable"},
+	{"RF Output Mixer", NULL, "Main Source Select"},
+	{"RF Output Mixer", "Mix to RF Speaker Switch", "Mix Enable"},
+
+	{"OUTLF", NULL, "LF Output Mixer"},
+	{"OUTRF", NULL, "RF Output Mixer"},
+	{"OUTLR", NULL, "Rear Speaker Source"},
+	{"OUTRR", NULL, "Rear Speaker Source"},
+	{"OUTSW", NULL, "Subwoofer Enable"},
+};
+
+static const struct snd_soc_component_driver tda7419_component_driver = {
+	.name			= "tda7419",
+	.controls		= tda7419_controls,
+	.num_controls		= ARRAY_SIZE(tda7419_controls),
+	.dapm_widgets		= tda7419_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tda7419_dapm_widgets),
+	.dapm_routes		= tda7419_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tda7419_dapm_routes),
+};
+
+static int tda7419_probe(struct i2c_client *i2c,
+			 const struct i2c_device_id *id)
+{
+	struct tda7419_data *tda7419;
+	int i, ret;
+
+	tda7419 = devm_kzalloc(&i2c->dev,
+			       sizeof(struct tda7419_data),
+			       GFP_KERNEL);
+	if (tda7419 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, tda7419);
+
+	tda7419->regmap = devm_regmap_init_i2c(i2c, &tda7419_regmap_config);
+	if (IS_ERR(tda7419->regmap)) {
+		ret = PTR_ERR(tda7419->regmap);
+		dev_err(&i2c->dev, "error initializing regmap: %d\n",
+				ret);
+		return ret;
+	}
+
+	/*
+	 * Reset registers to power-on defaults. The part does not provide a
+	 * soft-reset function and the registers are not readable. This ensures
+	 * that the cache matches register contents even if the registers have
+	 * been previously initialized and not power cycled before probe.
+	 */
+	for (i = 0; i < ARRAY_SIZE(tda7419_regmap_defaults); i++)
+		regmap_write(tda7419->regmap,
+			     tda7419_regmap_defaults[i].reg,
+			     tda7419_regmap_defaults[i].def);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+		&tda7419_component_driver, NULL, 0);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "error registering component: %d\n",
+				ret);
+	}
+
+	return ret;
+}
+
+static const struct i2c_device_id tda7419_i2c_id[] = {
+	{ "tda7419", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tda7419_i2c_id);
+
+static const struct of_device_id tda7419_of_match[] = {
+	{ .compatible = "st,tda7419" },
+	{ },
+};
+
+static struct i2c_driver tda7419_driver = {
+	.driver = {
+		.name   = "tda7419",
+		.of_match_table = tda7419_of_match,
+	},
+	.probe          = tda7419_probe,
+	.id_table       = tda7419_i2c_id,
+};
+
+module_i2c_driver(tda7419_driver);
+
+MODULE_AUTHOR("Matt Porter <mporter@konsulko.com>");
+MODULE_DESCRIPTION("TDA7419 audio processor driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
new file mode 100644
index 0000000..abc114a
--- /dev/null
+++ b/sound/soc/codecs/tfa9879.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// tfa9879.c  --  driver for NXP Semiconductors TFA9879
+//
+// Copyright (C) 2014 Axentia Technologies AB
+// Author: Peter Rosin <peda@axentia.se>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/pcm_params.h>
+
+#include "tfa9879.h"
+
+struct tfa9879_priv {
+	struct regmap *regmap;
+	int lsb_justified;
+};
+
+static int tfa9879_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tfa9879_priv *tfa9879 = snd_soc_component_get_drvdata(component);
+	int fs;
+	int i2s_set = 0;
+
+	switch (params_rate(params)) {
+	case 8000:
+		fs = TFA9879_I2S_FS_8000;
+		break;
+	case 11025:
+		fs = TFA9879_I2S_FS_11025;
+		break;
+	case 12000:
+		fs = TFA9879_I2S_FS_12000;
+		break;
+	case 16000:
+		fs = TFA9879_I2S_FS_16000;
+		break;
+	case 22050:
+		fs = TFA9879_I2S_FS_22050;
+		break;
+	case 24000:
+		fs = TFA9879_I2S_FS_24000;
+		break;
+	case 32000:
+		fs = TFA9879_I2S_FS_32000;
+		break;
+	case 44100:
+		fs = TFA9879_I2S_FS_44100;
+		break;
+	case 48000:
+		fs = TFA9879_I2S_FS_48000;
+		break;
+	case 64000:
+		fs = TFA9879_I2S_FS_64000;
+		break;
+	case 88200:
+		fs = TFA9879_I2S_FS_88200;
+		break;
+	case 96000:
+		fs = TFA9879_I2S_FS_96000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params_width(params)) {
+	case 16:
+		i2s_set = TFA9879_I2S_SET_LSB_J_16;
+		break;
+	case 24:
+		i2s_set = TFA9879_I2S_SET_LSB_J_24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (tfa9879->lsb_justified)
+		snd_soc_component_update_bits(component,
+					      TFA9879_SERIAL_INTERFACE_1,
+					      TFA9879_I2S_SET_MASK,
+					      i2s_set << TFA9879_I2S_SET_SHIFT);
+
+	snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
+				      TFA9879_I2S_FS_MASK,
+				      fs << TFA9879_I2S_FS_SHIFT);
+	return 0;
+}
+
+static int tfa9879_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+
+	snd_soc_component_update_bits(component, TFA9879_MISC_CONTROL,
+				      TFA9879_S_MUTE_MASK,
+				      !!mute << TFA9879_S_MUTE_SHIFT);
+
+	return 0;
+}
+
+static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tfa9879_priv *tfa9879 = snd_soc_component_get_drvdata(component);
+	int i2s_set;
+	int sck_pol;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		sck_pol = TFA9879_SCK_POL_NORMAL;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		sck_pol = TFA9879_SCK_POL_INVERSE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		tfa9879->lsb_justified = 0;
+		i2s_set = TFA9879_I2S_SET_I2S_24;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		tfa9879->lsb_justified = 0;
+		i2s_set = TFA9879_I2S_SET_MSB_J_24;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		tfa9879->lsb_justified = 1;
+		i2s_set = TFA9879_I2S_SET_LSB_J_24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
+				      TFA9879_SCK_POL_MASK,
+				      sck_pol << TFA9879_SCK_POL_SHIFT);
+	snd_soc_component_update_bits(component, TFA9879_SERIAL_INTERFACE_1,
+				      TFA9879_I2S_SET_MASK,
+				      i2s_set << TFA9879_I2S_SET_SHIFT);
+	return 0;
+}
+
+static const struct reg_default tfa9879_regs[] = {
+	{ TFA9879_DEVICE_CONTROL,	0x0000 }, /* 0x00 */
+	{ TFA9879_SERIAL_INTERFACE_1,	0x0a18 }, /* 0x01 */
+	{ TFA9879_PCM_IOM2_FORMAT_1,	0x0007 }, /* 0x02 */
+	{ TFA9879_SERIAL_INTERFACE_2,	0x0a18 }, /* 0x03 */
+	{ TFA9879_PCM_IOM2_FORMAT_2,	0x0007 }, /* 0x04 */
+	{ TFA9879_EQUALIZER_A1,		0x59dd }, /* 0x05 */
+	{ TFA9879_EQUALIZER_A2,		0xc63e }, /* 0x06 */
+	{ TFA9879_EQUALIZER_B1,		0x651a }, /* 0x07 */
+	{ TFA9879_EQUALIZER_B2,		0xe53e }, /* 0x08 */
+	{ TFA9879_EQUALIZER_C1,		0x4616 }, /* 0x09 */
+	{ TFA9879_EQUALIZER_C2,		0xd33e }, /* 0x0a */
+	{ TFA9879_EQUALIZER_D1,		0x4df3 }, /* 0x0b */
+	{ TFA9879_EQUALIZER_D2,		0xea3e }, /* 0x0c */
+	{ TFA9879_EQUALIZER_E1,		0x5ee0 }, /* 0x0d */
+	{ TFA9879_EQUALIZER_E2,		0xf93e }, /* 0x0e */
+	{ TFA9879_BYPASS_CONTROL,	0x0093 }, /* 0x0f */
+	{ TFA9879_DYNAMIC_RANGE_COMPR,	0x92ba }, /* 0x10 */
+	{ TFA9879_BASS_TREBLE,		0x12a5 }, /* 0x11 */
+	{ TFA9879_HIGH_PASS_FILTER,	0x0004 }, /* 0x12 */
+	{ TFA9879_VOLUME_CONTROL,	0x10bd }, /* 0x13 */
+	{ TFA9879_MISC_CONTROL,		0x0000 }, /* 0x14 */
+};
+
+static bool tfa9879_volatile_reg(struct device *dev, unsigned int reg)
+{
+	return reg == TFA9879_MISC_STATUS;
+}
+
+static const DECLARE_TLV_DB_SCALE(volume_tlv, -7050, 50, 1);
+static const DECLARE_TLV_DB_SCALE(tb_gain_tlv, -1800, 200, 0);
+static const char * const tb_freq_text[] = {
+	"Low", "Mid", "High"
+};
+static const struct soc_enum treble_freq_enum =
+	SOC_ENUM_SINGLE(TFA9879_BASS_TREBLE, TFA9879_F_TRBLE_SHIFT,
+			ARRAY_SIZE(tb_freq_text), tb_freq_text);
+static const struct soc_enum bass_freq_enum =
+	SOC_ENUM_SINGLE(TFA9879_BASS_TREBLE, TFA9879_F_BASS_SHIFT,
+			ARRAY_SIZE(tb_freq_text), tb_freq_text);
+
+static const struct snd_kcontrol_new tfa9879_controls[] = {
+	SOC_SINGLE_TLV("PCM Playback Volume", TFA9879_VOLUME_CONTROL,
+		       TFA9879_VOL_SHIFT, 0xbd, 1, volume_tlv),
+	SOC_SINGLE_TLV("Treble Volume", TFA9879_BASS_TREBLE,
+		       TFA9879_G_TRBLE_SHIFT, 18, 0, tb_gain_tlv),
+	SOC_SINGLE_TLV("Bass Volume", TFA9879_BASS_TREBLE,
+		       TFA9879_G_BASS_SHIFT, 18, 0, tb_gain_tlv),
+	SOC_ENUM("Treble Corner Freq", treble_freq_enum),
+	SOC_ENUM("Bass Corner Freq", bass_freq_enum),
+};
+
+static const struct snd_soc_dapm_widget tfa9879_dapm_widgets[] = {
+SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_DAC("DAC", NULL, TFA9879_DEVICE_CONTROL, TFA9879_OPMODE_SHIFT, 0),
+SND_SOC_DAPM_OUTPUT("LINEOUT"),
+SND_SOC_DAPM_SUPPLY("POWER", TFA9879_DEVICE_CONTROL, TFA9879_POWERUP_SHIFT, 0,
+		    NULL, 0),
+};
+
+static const struct snd_soc_dapm_route tfa9879_dapm_routes[] = {
+	{ "DAC", NULL, "AIFINL" },
+	{ "DAC", NULL, "AIFINR" },
+
+	{ "LINEOUT", NULL, "DAC" },
+
+	{ "DAC", NULL, "POWER" },
+};
+
+static const struct snd_soc_component_driver tfa9879_component = {
+	.controls		= tfa9879_controls,
+	.num_controls		= ARRAY_SIZE(tfa9879_controls),
+	.dapm_widgets		= tfa9879_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tfa9879_dapm_widgets),
+	.dapm_routes		= tfa9879_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tfa9879_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config tfa9879_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.volatile_reg = tfa9879_volatile_reg,
+	.max_register = TFA9879_MISC_STATUS,
+	.reg_defaults = tfa9879_regs,
+	.num_reg_defaults = ARRAY_SIZE(tfa9879_regs),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const struct snd_soc_dai_ops tfa9879_dai_ops = {
+	.hw_params = tfa9879_hw_params,
+	.digital_mute = tfa9879_digital_mute,
+	.set_fmt = tfa9879_set_fmt,
+};
+
+#define TFA9879_RATES SNDRV_PCM_RATE_8000_96000
+
+#define TFA9879_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			 SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver tfa9879_dai = {
+	.name = "tfa9879-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = TFA9879_RATES,
+		.formats = TFA9879_FORMATS, },
+	.ops = &tfa9879_dai_ops,
+};
+
+static int tfa9879_i2c_probe(struct i2c_client *i2c)
+{
+	struct tfa9879_priv *tfa9879;
+	int i;
+
+	tfa9879 = devm_kzalloc(&i2c->dev, sizeof(*tfa9879), GFP_KERNEL);
+	if (!tfa9879)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, tfa9879);
+
+	tfa9879->regmap = devm_regmap_init_i2c(i2c, &tfa9879_regmap);
+	if (IS_ERR(tfa9879->regmap))
+		return PTR_ERR(tfa9879->regmap);
+
+	/* Ensure the device is in reset state */
+	for (i = 0; i < ARRAY_SIZE(tfa9879_regs); i++)
+		regmap_write(tfa9879->regmap,
+			     tfa9879_regs[i].reg, tfa9879_regs[i].def);
+
+	return devm_snd_soc_register_component(&i2c->dev, &tfa9879_component,
+					       &tfa9879_dai, 1);
+}
+
+static const struct i2c_device_id tfa9879_i2c_id[] = {
+	{ "tfa9879", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tfa9879_i2c_id);
+
+static const struct of_device_id tfa9879_of_match[] = {
+	{ .compatible = "nxp,tfa9879", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tfa9879_of_match);
+
+static struct i2c_driver tfa9879_i2c_driver = {
+	.driver = {
+		.name = "tfa9879",
+		.of_match_table = tfa9879_of_match,
+	},
+	.probe_new = tfa9879_i2c_probe,
+	.id_table = tfa9879_i2c_id,
+};
+
+module_i2c_driver(tfa9879_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC NXP Semiconductors TFA9879 driver");
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tfa9879.h b/sound/soc/codecs/tfa9879.h
new file mode 100644
index 0000000..66c88d0
--- /dev/null
+++ b/sound/soc/codecs/tfa9879.h
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * tfa9879.h  --  driver for NXP Semiconductors TFA9879
+ *
+ * Copyright (C) 2014 Axentia Technologies AB
+ * Author: Peter Rosin <peda@axentia.se>
+ */
+
+#ifndef _TFA9879_H
+#define _TFA9879_H
+
+#define TFA9879_DEVICE_CONTROL		0x00
+#define TFA9879_SERIAL_INTERFACE_1	0x01
+#define TFA9879_PCM_IOM2_FORMAT_1	0x02
+#define TFA9879_SERIAL_INTERFACE_2	0x03
+#define TFA9879_PCM_IOM2_FORMAT_2	0x04
+#define TFA9879_EQUALIZER_A1		0x05
+#define TFA9879_EQUALIZER_A2		0x06
+#define TFA9879_EQUALIZER_B1		0x07
+#define TFA9879_EQUALIZER_B2		0x08
+#define TFA9879_EQUALIZER_C1		0x09
+#define TFA9879_EQUALIZER_C2		0x0a
+#define TFA9879_EQUALIZER_D1		0x0b
+#define TFA9879_EQUALIZER_D2		0x0c
+#define TFA9879_EQUALIZER_E1		0x0d
+#define TFA9879_EQUALIZER_E2		0x0e
+#define TFA9879_BYPASS_CONTROL		0x0f
+#define TFA9879_DYNAMIC_RANGE_COMPR	0x10
+#define TFA9879_BASS_TREBLE		0x11
+#define TFA9879_HIGH_PASS_FILTER	0x12
+#define TFA9879_VOLUME_CONTROL		0x13
+#define TFA9879_MISC_CONTROL		0x14
+#define TFA9879_MISC_STATUS		0x15
+
+/* TFA9879_DEVICE_CONTROL */
+#define TFA9879_INPUT_SEL_MASK		0x0010
+#define TFA9879_INPUT_SEL_SHIFT		4
+#define TFA9879_OPMODE_MASK		0x0008
+#define TFA9879_OPMODE_SHIFT		3
+#define TFA9879_RESET_MASK		0x0002
+#define TFA9879_RESET_SHIFT		1
+#define TFA9879_POWERUP_MASK		0x0001
+#define TFA9879_POWERUP_SHIFT		0
+
+/* TFA9879_SERIAL_INTERFACE */
+#define TFA9879_MONO_SEL_MASK		0x0c00
+#define TFA9879_MONO_SEL_SHIFT		10
+#define TFA9879_MONO_SEL_LEFT		0
+#define TFA9879_MONO_SEL_RIGHT		1
+#define TFA9879_MONO_SEL_BOTH		2
+#define TFA9879_I2S_FS_MASK		0x03c0
+#define TFA9879_I2S_FS_SHIFT		6
+#define TFA9879_I2S_FS_8000		0
+#define TFA9879_I2S_FS_11025		1
+#define TFA9879_I2S_FS_12000		2
+#define TFA9879_I2S_FS_16000		3
+#define TFA9879_I2S_FS_22050		4
+#define TFA9879_I2S_FS_24000		5
+#define TFA9879_I2S_FS_32000		6
+#define TFA9879_I2S_FS_44100		7
+#define TFA9879_I2S_FS_48000		8
+#define TFA9879_I2S_FS_64000		9
+#define TFA9879_I2S_FS_88200		10
+#define TFA9879_I2S_FS_96000		11
+#define TFA9879_I2S_SET_MASK		0x0038
+#define TFA9879_I2S_SET_SHIFT		3
+#define TFA9879_I2S_SET_MSB_J_24	2
+#define TFA9879_I2S_SET_I2S_24		3
+#define TFA9879_I2S_SET_LSB_J_16	4
+#define TFA9879_I2S_SET_LSB_J_18	5
+#define TFA9879_I2S_SET_LSB_J_20	6
+#define TFA9879_I2S_SET_LSB_J_24	7
+#define TFA9879_SCK_POL_MASK		0x0004
+#define TFA9879_SCK_POL_SHIFT		2
+#define TFA9879_SCK_POL_NORMAL		0
+#define TFA9879_SCK_POL_INVERSE		1
+#define TFA9879_I_MODE_MASK		0x0003
+#define TFA9879_I_MODE_SHIFT		0
+#define TFA9879_I_MODE_I2S		0
+#define TFA9879_I_MODE_PCM_IOM2_SHORT	1
+#define TFA9879_I_MODE_PCM_IOM2_LONG	2
+
+/* TFA9879_PCM_IOM2_FORMAT */
+#define TFA9879_PCM_FS_MASK		0x0800
+#define TFA9879_PCM_FS_SHIFT		11
+#define TFA9879_A_LAW_MASK		0x0400
+#define TFA9879_A_LAW_SHIFT		10
+#define TFA9879_PCM_COMP_MASK		0x0200
+#define TFA9879_PCM_COMP_SHIFT		9
+#define TFA9879_PCM_DL_MASK		0x0100
+#define TFA9879_PCM_DL_SHIFT		8
+#define TFA9879_D1_SLOT_MASK		0x00f0
+#define TFA9879_D1_SLOT_SHIFT		4
+#define TFA9879_D2_SLOT_MASK		0x000f
+#define TFA9879_D2_SLOT_SHIFT		0
+
+/* TFA9879_EQUALIZER_X1 */
+#define TFA9879_T1_MASK			0x8000
+#define TFA9879_T1_SHIFT		15
+#define TFA9879_K1M_MASK		0x7ff0
+#define TFA9879_K1M_SHIFT		4
+#define TFA9879_K1E_MASK		0x000f
+#define TFA9879_K1E_SHIFT		0
+
+/* TFA9879_EQUALIZER_X2 */
+#define TFA9879_T2_MASK			0x8000
+#define TFA9879_T2_SHIFT		15
+#define TFA9879_K2M_MASK		0x7800
+#define TFA9879_K2M_SHIFT		11
+#define TFA9879_K2E_MASK		0x0700
+#define TFA9879_K2E_SHIFT		8
+#define TFA9879_K0_MASK			0x00fe
+#define TFA9879_K0_SHIFT		1
+#define TFA9879_S_MASK			0x0001
+#define TFA9879_S_SHIFT			0
+
+/* TFA9879_BYPASS_CONTROL */
+#define TFA9879_L_OCP_MASK		0x00c0
+#define TFA9879_L_OCP_SHIFT		6
+#define TFA9879_L_OTP_MASK		0x0030
+#define TFA9879_L_OTP_SHIFT		4
+#define TFA9879_CLIPCTRL_MASK		0x0008
+#define TFA9879_CLIPCTRL_SHIFT		3
+#define TFA9879_HPF_BP_MASK		0x0004
+#define TFA9879_HPF_BP_SHIFT		2
+#define TFA9879_DRC_BP_MASK		0x0002
+#define TFA9879_DRC_BP_SHIFT		1
+#define TFA9879_EQ_BP_MASK		0x0001
+#define TFA9879_EQ_BP_SHIFT		0
+
+/* TFA9879_DYNAMIC_RANGE_COMPR */
+#define TFA9879_AT_LVL_MASK		0xf000
+#define TFA9879_AT_LVL_SHIFT		12
+#define TFA9879_AT_RATE_MASK		0x0f00
+#define TFA9879_AT_RATE_SHIFT		8
+#define TFA9879_RL_LVL_MASK		0x00f0
+#define TFA9879_RL_LVL_SHIFT		4
+#define TFA9879_RL_RATE_MASK		0x000f
+#define TFA9879_RL_RATE_SHIFT		0
+
+/* TFA9879_BASS_TREBLE */
+#define TFA9879_G_TRBLE_MASK		0x3e00
+#define TFA9879_G_TRBLE_SHIFT		9
+#define TFA9879_F_TRBLE_MASK		0x0180
+#define TFA9879_F_TRBLE_SHIFT		7
+#define TFA9879_G_BASS_MASK		0x007c
+#define TFA9879_G_BASS_SHIFT		2
+#define TFA9879_F_BASS_MASK		0x0003
+#define TFA9879_F_BASS_SHIFT		0
+
+/* TFA9879_HIGH_PASS_FILTER */
+#define TFA9879_HP_CTRL_MASK		0x00ff
+#define TFA9879_HP_CTRL_SHIFT		0
+
+/* TFA9879_VOLUME_CONTROL */
+#define TFA9879_ZR_CRSS_MASK		0x1000
+#define TFA9879_ZR_CRSS_SHIFT		12
+#define TFA9879_VOL_MASK		0x00ff
+#define TFA9879_VOL_SHIFT		0
+
+/* TFA9879_MISC_CONTROL */
+#define TFA9879_DE_PHAS_MASK		0x0c00
+#define TFA9879_DE_PHAS_SHIFT		10
+#define TFA9879_H_MUTE_MASK		0x0200
+#define TFA9879_H_MUTE_SHIFT		9
+#define TFA9879_S_MUTE_MASK		0x0100
+#define TFA9879_S_MUTE_SHIFT		8
+#define TFA9879_P_LIM_MASK		0x00ff
+#define TFA9879_P_LIM_SHIFT		0
+
+/* TFA9879_MISC_STATUS */
+#define TFA9879_PS_MASK			0x4000
+#define TFA9879_PS_SHIFT		14
+#define TFA9879_PORA_MASK		0x2000
+#define TFA9879_PORA_SHIFT		13
+#define TFA9879_AMP_MASK		0x0600
+#define TFA9879_AMP_SHIFT		9
+#define TFA9879_IBP_2_MASK		0x0100
+#define TFA9879_IBP_2_SHIFT		8
+#define TFA9879_OFP_2_MASK		0x0080
+#define TFA9879_OFP_2_SHIFT		7
+#define TFA9879_UFP_2_MASK		0x0040
+#define TFA9879_UFP_2_SHIFT		6
+#define TFA9879_IBP_1_MASK		0x0020
+#define TFA9879_IBP_1_SHIFT		5
+#define TFA9879_OFP_1_MASK		0x0010
+#define TFA9879_OFP_1_SHIFT		4
+#define TFA9879_UFP_1_MASK		0x0008
+#define TFA9879_UFP_1_SHIFT		3
+#define TFA9879_OCPOKA_MASK		0x0004
+#define TFA9879_OCPOKA_SHIFT		2
+#define TFA9879_OCPOKB_MASK		0x0002
+#define TFA9879_OCPOKB_SHIFT		1
+#define TFA9879_OTPOK_MASK		0x0001
+#define TFA9879_OTPOK_SHIFT		0
+
+#endif
diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c
new file mode 100644
index 0000000..1d7c117
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic23-i2c.c
@@ -0,0 +1,60 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver I2C interface
+ *
+ * Author:      Arun KS, <arunks@mistralsolutions.com>
+ * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd.,
+ *
+ * Based on sound/soc/codecs/wm8731.c by Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "tlv320aic23.h"
+
+static int tlv320aic23_i2c_probe(struct i2c_client *i2c,
+				 const struct i2c_device_id *i2c_id)
+{
+	struct regmap *regmap;
+
+	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EINVAL;
+
+	regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap);
+	return tlv320aic23_probe(&i2c->dev, regmap);
+}
+
+static const struct i2c_device_id tlv320aic23_id[] = {
+	{"tlv320aic23", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
+
+static const struct of_device_id tlv320aic23_of_match[] = {
+	{ .compatible = "ti,tlv320aic23", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tlv320aic23_of_match);
+
+static struct i2c_driver tlv320aic23_i2c_driver = {
+	.driver = {
+		   .name = "tlv320aic23-codec",
+		   .of_match_table = of_match_ptr(tlv320aic23_of_match),
+		   },
+	.probe = tlv320aic23_i2c_probe,
+	.id_table = tlv320aic23_id,
+};
+
+module_i2c_driver(tlv320aic23_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver I2C");
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic23-spi.c b/sound/soc/codecs/tlv320aic23-spi.c
new file mode 100644
index 0000000..d8c9ec1
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic23-spi.c
@@ -0,0 +1,48 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver SPI interface
+ *
+ * Author:      Arun KS, <arunks@mistralsolutions.com>
+ * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd.,
+ *
+ * Based on sound/soc/codecs/wm8731.c by Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include "tlv320aic23.h"
+
+static int aic23_spi_probe(struct spi_device *spi)
+{
+	int ret;
+	struct regmap *regmap;
+
+	dev_dbg(&spi->dev, "probing tlv320aic23 spi device\n");
+
+	spi->mode = SPI_MODE_0;
+	ret = spi_setup(spi);
+	if (ret < 0)
+		return ret;
+
+	regmap = devm_regmap_init_spi(spi, &tlv320aic23_regmap);
+	return tlv320aic23_probe(&spi->dev, regmap);
+}
+
+static struct spi_driver aic23_spi = {
+	.driver = {
+		.name = "tlv320aic23",
+	},
+	.probe = aic23_spi_probe,
+};
+
+module_spi_driver(aic23_spi);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver SPI");
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
new file mode 100644
index 0000000..47480cb
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -0,0 +1,620 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver
+ *
+ * Author:      Arun KS, <arunks@mistralsolutions.com>
+ * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd.,
+ *
+ * Based on sound/soc/codecs/wm8731.c by Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Notes:
+ *  The AIC23 is a driver for a low power stereo audio
+ *  codec tlv320aic23
+ *
+ *  The machine layer should disable unsupported inputs/outputs by
+ *  snd_soc_dapm_disable_pin(codec, "LHPOUT"), etc.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+
+#include "tlv320aic23.h"
+
+/*
+ * AIC23 register cache
+ */
+static const struct reg_default tlv320aic23_reg[] = {
+	{  0, 0x0097 },
+	{  1, 0x0097 },
+	{  2, 0x00F9 },
+	{  3, 0x00F9 },
+	{  4, 0x001A },
+	{  5, 0x0004 },
+	{  6, 0x0007 },
+	{  7, 0x0001 },
+	{  8, 0x0020 },
+	{  9, 0x0000 },
+};
+
+const struct regmap_config tlv320aic23_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = TLV320AIC23_RESET,
+	.reg_defaults = tlv320aic23_reg,
+	.num_reg_defaults = ARRAY_SIZE(tlv320aic23_reg),
+	.cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL(tlv320aic23_regmap);
+
+static const char *rec_src_text[] = { "Line", "Mic" };
+static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static SOC_ENUM_SINGLE_DECL(rec_src_enum,
+			    TLV320AIC23_ANLG, 2, rec_src_text);
+
+static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls =
+SOC_DAPM_ENUM("Input Select", rec_src_enum);
+
+static SOC_ENUM_SINGLE_DECL(tlv320aic23_rec_src,
+			    TLV320AIC23_ANLG, 2, rec_src_text);
+static SOC_ENUM_SINGLE_DECL(tlv320aic23_deemph,
+			    TLV320AIC23_DIGT, 1, deemph_text);
+
+static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0);
+static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0);
+
+static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	u16 val, reg;
+
+	val = (ucontrol->value.integer.value[0] & 0x07);
+
+	/* linear conversion to userspace
+	* 000	=	-6db
+	* 001	=	-9db
+	* 010	=	-12db
+	* 011	=	-18db (Min)
+	* 100	=	0db (Max)
+	*/
+	val = (val >= 4) ? 4  : (3 - val);
+
+	reg = snd_soc_component_read32(component, TLV320AIC23_ANLG) & (~0x1C0);
+	snd_soc_component_write(component, TLV320AIC23_ANLG, reg | (val << 6));
+
+	return 0;
+}
+
+static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	u16 val;
+
+	val = snd_soc_component_read32(component, TLV320AIC23_ANLG) & (0x1C0);
+	val = val >> 6;
+	val = (val >= 4) ? 4  : (3 -  val);
+	ucontrol->value.integer.value[0] = val;
+	return 0;
+
+}
+
+static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("Digital Playback Volume", TLV320AIC23_LCHNVOL,
+			 TLV320AIC23_RCHNVOL, 0, 127, 0, out_gain_tlv),
+	SOC_SINGLE("Digital Playback Switch", TLV320AIC23_DIGT, 3, 1, 1),
+	SOC_DOUBLE_R("Line Input Switch", TLV320AIC23_LINVOL,
+		     TLV320AIC23_RINVOL, 7, 1, 0),
+	SOC_DOUBLE_R_TLV("Line Input Volume", TLV320AIC23_LINVOL,
+			 TLV320AIC23_RINVOL, 0, 31, 0, input_gain_tlv),
+	SOC_SINGLE("Mic Input Switch", TLV320AIC23_ANLG, 1, 1, 1),
+	SOC_SINGLE("Mic Booster Switch", TLV320AIC23_ANLG, 0, 1, 0),
+	SOC_SINGLE_EXT_TLV("Sidetone Volume", TLV320AIC23_ANLG, 6, 4, 0,
+			   snd_soc_tlv320aic23_get_volsw,
+			   snd_soc_tlv320aic23_put_volsw, sidetone_vol_tlv),
+	SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph),
+};
+
+/* PGA Mixer controls for Line and Mic switch */
+static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0),
+	SOC_DAPM_SINGLE("Mic Sidetone Switch", TLV320AIC23_ANLG, 5, 1, 0),
+	SOC_DAPM_SINGLE("Playback Switch", TLV320AIC23_ANLG, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", "Playback", TLV320AIC23_PWR, 3, 1),
+	SND_SOC_DAPM_ADC("ADC", "Capture", TLV320AIC23_PWR, 2, 1),
+	SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0,
+			 &tlv320aic23_rec_src_mux_controls),
+	SND_SOC_DAPM_MIXER("Output Mixer", TLV320AIC23_PWR, 4, 1,
+			   &tlv320aic23_output_mixer_controls[0],
+			   ARRAY_SIZE(tlv320aic23_output_mixer_controls)),
+	SND_SOC_DAPM_PGA("Line Input", TLV320AIC23_PWR, 0, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Mic Input", TLV320AIC23_PWR, 1, 1, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("LHPOUT"),
+	SND_SOC_DAPM_OUTPUT("RHPOUT"),
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+	SND_SOC_DAPM_OUTPUT("ROUT"),
+
+	SND_SOC_DAPM_INPUT("LLINEIN"),
+	SND_SOC_DAPM_INPUT("RLINEIN"),
+
+	SND_SOC_DAPM_INPUT("MICIN"),
+};
+
+static const struct snd_soc_dapm_route tlv320aic23_intercon[] = {
+	/* Output Mixer */
+	{"Output Mixer", "Line Bypass Switch", "Line Input"},
+	{"Output Mixer", "Playback Switch", "DAC"},
+	{"Output Mixer", "Mic Sidetone Switch", "Mic Input"},
+
+	/* Outputs */
+	{"RHPOUT", NULL, "Output Mixer"},
+	{"LHPOUT", NULL, "Output Mixer"},
+	{"LOUT", NULL, "Output Mixer"},
+	{"ROUT", NULL, "Output Mixer"},
+
+	/* Inputs */
+	{"Line Input", NULL, "LLINEIN"},
+	{"Line Input", NULL, "RLINEIN"},
+	{"Mic Input", NULL, "MICIN"},
+
+	/* input mux */
+	{"Capture Source", "Line", "Line Input"},
+	{"Capture Source", "Mic", "Mic Input"},
+	{"ADC", NULL, "Capture Source"},
+
+};
+
+/* AIC23 driver data */
+struct aic23 {
+	struct regmap *regmap;
+	int mclk;
+	int requested_adc;
+	int requested_dac;
+};
+
+/*
+ * Common Crystals used
+ * 11.2896 Mhz /128 = *88.2k  /192 = 58.8k
+ * 12.0000 Mhz /125 = *96k    /136 = 88.235K
+ * 12.2880 Mhz /128 = *96k    /192 = 64k
+ * 16.9344 Mhz /128 = 132.3k /192 = *88.2k
+ * 18.4320 Mhz /128 = 144k   /192 = *96k
+ */
+
+/*
+ * Normal BOSR 0-256/2 = 128, 1-384/2 = 192
+ * USB BOSR 0-250/2 = 125, 1-272/2 = 136
+ */
+static const int bosr_usb_divisor_table[] = {
+	128, 125, 192, 136
+};
+#define LOWER_GROUP ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<6) | (1<<7))
+#define UPPER_GROUP ((1<<8) | (1<<9) | (1<<10) | (1<<11)        | (1<<15))
+static const unsigned short sr_valid_mask[] = {
+	LOWER_GROUP|UPPER_GROUP,	/* Normal, bosr - 0*/
+	LOWER_GROUP,			/* Usb, bosr - 0*/
+	LOWER_GROUP|UPPER_GROUP,	/* Normal, bosr - 1*/
+	UPPER_GROUP,			/* Usb, bosr - 1*/
+};
+/*
+ * Every divisor is a factor of 11*12
+ */
+#define SR_MULT (11*12)
+#define A(x) (SR_MULT/x)
+static const unsigned char sr_adc_mult_table[] = {
+	A(2), A(2), A(12), A(12),  0, 0, A(3), A(1),
+	A(2), A(2), A(11), A(11),  0, 0, 0, A(1)
+};
+static const unsigned char sr_dac_mult_table[] = {
+	A(2), A(12), A(2), A(12),  0, 0, A(3), A(1),
+	A(2), A(11), A(2), A(11),  0, 0, 0, A(1)
+};
+
+static unsigned get_score(int adc, int adc_l, int adc_h, int need_adc,
+		int dac, int dac_l, int dac_h, int need_dac)
+{
+	if ((adc >= adc_l) && (adc <= adc_h) &&
+			(dac >= dac_l) && (dac <= dac_h)) {
+		int diff_adc = need_adc - adc;
+		int diff_dac = need_dac - dac;
+		return abs(diff_adc) + abs(diff_dac);
+	}
+	return UINT_MAX;
+}
+
+static int find_rate(int mclk, u32 need_adc, u32 need_dac)
+{
+	int i, j;
+	int best_i = -1;
+	int best_j = -1;
+	int best_div = 0;
+	unsigned best_score = UINT_MAX;
+	int adc_l, adc_h, dac_l, dac_h;
+
+	need_adc *= SR_MULT;
+	need_dac *= SR_MULT;
+	/*
+	 * rates given are +/- 1/32
+	 */
+	adc_l = need_adc - (need_adc >> 5);
+	adc_h = need_adc + (need_adc >> 5);
+	dac_l = need_dac - (need_dac >> 5);
+	dac_h = need_dac + (need_dac >> 5);
+	for (i = 0; i < ARRAY_SIZE(bosr_usb_divisor_table); i++) {
+		int base = mclk / bosr_usb_divisor_table[i];
+		int mask = sr_valid_mask[i];
+		for (j = 0; j < ARRAY_SIZE(sr_adc_mult_table);
+				j++, mask >>= 1) {
+			int adc;
+			int dac;
+			int score;
+			if ((mask & 1) == 0)
+				continue;
+			adc = base * sr_adc_mult_table[j];
+			dac = base * sr_dac_mult_table[j];
+			score = get_score(adc, adc_l, adc_h, need_adc,
+					dac, dac_l, dac_h, need_dac);
+			if (best_score > score) {
+				best_score = score;
+				best_i = i;
+				best_j = j;
+				best_div = 0;
+			}
+			score = get_score((adc >> 1), adc_l, adc_h, need_adc,
+					(dac >> 1), dac_l, dac_h, need_dac);
+			/* prefer to have a /2 */
+			if ((score != UINT_MAX) && (best_score >= score)) {
+				best_score = score;
+				best_i = i;
+				best_j = j;
+				best_div = 1;
+			}
+		}
+	}
+	return (best_j << 2) | best_i | (best_div << TLV320AIC23_CLKIN_SHIFT);
+}
+
+#ifdef DEBUG
+static void get_current_sample_rates(struct snd_soc_component *component, int mclk,
+		u32 *sample_rate_adc, u32 *sample_rate_dac)
+{
+	int src = snd_soc_component_read32(component, TLV320AIC23_SRATE);
+	int sr = (src >> 2) & 0x0f;
+	int val = (mclk / bosr_usb_divisor_table[src & 3]);
+	int adc = (val * sr_adc_mult_table[sr]) / SR_MULT;
+	int dac = (val * sr_dac_mult_table[sr]) / SR_MULT;
+	if (src & TLV320AIC23_CLKIN_HALF) {
+		adc >>= 1;
+		dac >>= 1;
+	}
+	*sample_rate_adc = adc;
+	*sample_rate_dac = dac;
+}
+#endif
+
+static int set_sample_rate_control(struct snd_soc_component *component, int mclk,
+		u32 sample_rate_adc, u32 sample_rate_dac)
+{
+	/* Search for the right sample rate */
+	int data = find_rate(mclk, sample_rate_adc, sample_rate_dac);
+	if (data < 0) {
+		printk(KERN_ERR "%s:Invalid rate %u,%u requested\n",
+				__func__, sample_rate_adc, sample_rate_dac);
+		return -EINVAL;
+	}
+	snd_soc_component_write(component, TLV320AIC23_SRATE, data);
+#ifdef DEBUG
+	{
+		u32 adc, dac;
+		get_current_sample_rates(component, mclk, &adc, &dac);
+		printk(KERN_DEBUG "actual samplerate = %u,%u reg=%x\n",
+			adc, dac, data);
+	}
+#endif
+	return 0;
+}
+
+static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 iface_reg;
+	int ret;
+	struct aic23 *aic23 = snd_soc_component_get_drvdata(component);
+	u32 sample_rate_adc = aic23->requested_adc;
+	u32 sample_rate_dac = aic23->requested_dac;
+	u32 sample_rate = params_rate(params);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		aic23->requested_dac = sample_rate_dac = sample_rate;
+		if (!sample_rate_adc)
+			sample_rate_adc = sample_rate;
+	} else {
+		aic23->requested_adc = sample_rate_adc = sample_rate;
+		if (!sample_rate_dac)
+			sample_rate_dac = sample_rate;
+	}
+	ret = set_sample_rate_control(component, aic23->mclk, sample_rate_adc,
+			sample_rate_dac);
+	if (ret < 0)
+		return ret;
+
+	iface_reg = snd_soc_component_read32(component, TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		iface_reg |= (0x01 << 2);
+		break;
+	case 24:
+		iface_reg |= (0x02 << 2);
+		break;
+	case 32:
+		iface_reg |= (0x03 << 2);
+		break;
+	}
+	snd_soc_component_write(component, TLV320AIC23_DIGT_FMT, iface_reg);
+
+	return 0;
+}
+
+static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+
+	/* set active */
+	snd_soc_component_write(component, TLV320AIC23_ACTIVE, 0x0001);
+
+	return 0;
+}
+
+static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct aic23 *aic23 = snd_soc_component_get_drvdata(component);
+
+	/* deactivate */
+	if (!snd_soc_component_is_active(component)) {
+		udelay(50);
+		snd_soc_component_write(component, TLV320AIC23_ACTIVE, 0x0);
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		aic23->requested_dac = 0;
+	else
+		aic23->requested_adc = 0;
+}
+
+static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 reg;
+
+	reg = snd_soc_component_read32(component, TLV320AIC23_DIGT);
+	if (mute)
+		reg |= TLV320AIC23_DACM_MUTE;
+
+	else
+		reg &= ~TLV320AIC23_DACM_MUTE;
+
+	snd_soc_component_write(component, TLV320AIC23_DIGT, reg);
+
+	return 0;
+}
+
+static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				   unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface_reg;
+
+	iface_reg = snd_soc_component_read32(component, TLV320AIC23_DIGT_FMT) & (~0x03);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface_reg |= TLV320AIC23_MS_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		iface_reg &= ~TLV320AIC23_MS_MASTER;
+		break;
+	default:
+		return -EINVAL;
+
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface_reg |= TLV320AIC23_FOR_I2S;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface_reg |= TLV320AIC23_LRP_ON;
+		/* fall through */
+	case SND_SOC_DAIFMT_DSP_B:
+		iface_reg |= TLV320AIC23_FOR_DSP;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface_reg |= TLV320AIC23_FOR_LJUST;
+		break;
+	default:
+		return -EINVAL;
+
+	}
+
+	snd_soc_component_write(component, TLV320AIC23_DIGT_FMT, iface_reg);
+
+	return 0;
+}
+
+static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				      int clk_id, unsigned int freq, int dir)
+{
+	struct aic23 *aic23 = snd_soc_dai_get_drvdata(codec_dai);
+	aic23->mclk = freq;
+	return 0;
+}
+
+static int tlv320aic23_set_bias_level(struct snd_soc_component *component,
+				      enum snd_soc_bias_level level)
+{
+	u16 reg = snd_soc_component_read32(component, TLV320AIC23_PWR) & 0x17f;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* vref/mid, osc on, dac unmute */
+		reg &= ~(TLV320AIC23_DEVICE_PWR_OFF | TLV320AIC23_OSC_OFF | \
+			TLV320AIC23_DAC_OFF);
+		snd_soc_component_write(component, TLV320AIC23_PWR, reg);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* everything off except vref/vmid, */
+		snd_soc_component_write(component, TLV320AIC23_PWR,
+			      reg | TLV320AIC23_CLK_OFF);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* everything off, dac mute, inactive */
+		snd_soc_component_write(component, TLV320AIC23_ACTIVE, 0x0);
+		snd_soc_component_write(component, TLV320AIC23_PWR, 0x1ff);
+		break;
+	}
+	return 0;
+}
+
+#define AIC23_RATES	SNDRV_PCM_RATE_8000_96000
+#define AIC23_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops tlv320aic23_dai_ops = {
+	.prepare	= tlv320aic23_pcm_prepare,
+	.hw_params	= tlv320aic23_hw_params,
+	.shutdown	= tlv320aic23_shutdown,
+	.digital_mute	= tlv320aic23_mute,
+	.set_fmt	= tlv320aic23_set_dai_fmt,
+	.set_sysclk	= tlv320aic23_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver tlv320aic23_dai = {
+	.name = "tlv320aic23-hifi",
+	.playback = {
+		     .stream_name = "Playback",
+		     .channels_min = 2,
+		     .channels_max = 2,
+		     .rates = AIC23_RATES,
+		     .formats = AIC23_FORMATS,},
+	.capture = {
+		    .stream_name = "Capture",
+		    .channels_min = 2,
+		    .channels_max = 2,
+		    .rates = AIC23_RATES,
+		    .formats = AIC23_FORMATS,},
+	.ops = &tlv320aic23_dai_ops,
+};
+
+static int tlv320aic23_resume(struct snd_soc_component *component)
+{
+	struct aic23 *aic23 = snd_soc_component_get_drvdata(component);
+	regcache_mark_dirty(aic23->regmap);
+	regcache_sync(aic23->regmap);
+
+	return 0;
+}
+
+static int tlv320aic23_component_probe(struct snd_soc_component *component)
+{
+	/* Reset codec */
+	snd_soc_component_write(component, TLV320AIC23_RESET, 0);
+
+	snd_soc_component_write(component, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K);
+
+	/* Unmute input */
+	snd_soc_component_update_bits(component, TLV320AIC23_LINVOL,
+			    TLV320AIC23_LIM_MUTED, TLV320AIC23_LRS_ENABLED);
+
+	snd_soc_component_update_bits(component, TLV320AIC23_RINVOL,
+			    TLV320AIC23_LIM_MUTED, TLV320AIC23_LRS_ENABLED);
+
+	snd_soc_component_update_bits(component, TLV320AIC23_ANLG,
+			    TLV320AIC23_BYPASS_ON | TLV320AIC23_MICM_MUTED,
+			    0);
+
+	/* Default output volume */
+	snd_soc_component_write(component, TLV320AIC23_LCHNVOL,
+		      TLV320AIC23_DEFAULT_OUT_VOL & TLV320AIC23_OUT_VOL_MASK);
+	snd_soc_component_write(component, TLV320AIC23_RCHNVOL,
+		      TLV320AIC23_DEFAULT_OUT_VOL & TLV320AIC23_OUT_VOL_MASK);
+
+	snd_soc_component_write(component, TLV320AIC23_ACTIVE, 0x1);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_tlv320aic23 = {
+	.probe			= tlv320aic23_component_probe,
+	.resume			= tlv320aic23_resume,
+	.set_bias_level		= tlv320aic23_set_bias_level,
+	.controls		= tlv320aic23_snd_controls,
+	.num_controls		= ARRAY_SIZE(tlv320aic23_snd_controls),
+	.dapm_widgets		= tlv320aic23_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tlv320aic23_dapm_widgets),
+	.dapm_routes		= tlv320aic23_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(tlv320aic23_intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+int tlv320aic23_probe(struct device *dev, struct regmap *regmap)
+{
+	struct aic23 *aic23;
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	aic23 = devm_kzalloc(dev, sizeof(struct aic23), GFP_KERNEL);
+	if (aic23 == NULL)
+		return -ENOMEM;
+
+	aic23->regmap = regmap;
+
+	dev_set_drvdata(dev, aic23);
+
+	return devm_snd_soc_register_component(dev,
+				      &soc_component_dev_tlv320aic23,
+				      &tlv320aic23_dai, 1);
+}
+EXPORT_SYMBOL(tlv320aic23_probe);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h
new file mode 100644
index 0000000..3a7235a
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic23.h
@@ -0,0 +1,125 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver
+ *
+ * Author:      Arun KS, <arunks@mistralsolutions.com>
+ * Copyright:   (C) 2008 Mistral Solutions Pvt Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _TLV320AIC23_H
+#define _TLV320AIC23_H
+
+struct device;
+struct regmap_config;
+
+extern const struct regmap_config tlv320aic23_regmap;
+int tlv320aic23_probe(struct device *dev, struct regmap *regmap);
+
+/* Codec TLV320AIC23 */
+#define TLV320AIC23_LINVOL		0x00
+#define TLV320AIC23_RINVOL		0x01
+#define TLV320AIC23_LCHNVOL		0x02
+#define TLV320AIC23_RCHNVOL		0x03
+#define TLV320AIC23_ANLG		0x04
+#define TLV320AIC23_DIGT		0x05
+#define TLV320AIC23_PWR			0x06
+#define TLV320AIC23_DIGT_FMT		0x07
+#define TLV320AIC23_SRATE		0x08
+#define TLV320AIC23_ACTIVE		0x09
+#define TLV320AIC23_RESET		0x0F
+
+/* Left (right) line input volume control register */
+#define TLV320AIC23_LRS_ENABLED		0x0100
+#define TLV320AIC23_LIM_MUTED		0x0080
+#define TLV320AIC23_LIV_DEFAULT		0x0017
+#define TLV320AIC23_LIV_MAX		0x001f
+#define TLV320AIC23_LIV_MIN		0x0000
+
+/* Left (right) channel headphone volume control register */
+#define TLV320AIC23_LZC_ON		0x0080
+#define TLV320AIC23_LHV_DEFAULT		0x0079
+#define TLV320AIC23_LHV_MAX		0x007f
+#define TLV320AIC23_LHV_MIN		0x0000
+
+/* Analog audio path control register */
+#define TLV320AIC23_STA_REG(x)		((x)<<6)
+#define TLV320AIC23_STE_ENABLED		0x0020
+#define TLV320AIC23_DAC_SELECTED	0x0010
+#define TLV320AIC23_BYPASS_ON		0x0008
+#define TLV320AIC23_INSEL_MIC		0x0004
+#define TLV320AIC23_MICM_MUTED		0x0002
+#define TLV320AIC23_MICB_20DB		0x0001
+
+/* Digital audio path control register */
+#define TLV320AIC23_DACM_MUTE		0x0008
+#define TLV320AIC23_DEEMP_32K		0x0002
+#define TLV320AIC23_DEEMP_44K		0x0004
+#define TLV320AIC23_DEEMP_48K		0x0006
+#define TLV320AIC23_ADCHP_ON		0x0001
+
+/* Power control down register */
+#define TLV320AIC23_DEVICE_PWR_OFF  	0x0080
+#define TLV320AIC23_CLK_OFF		0x0040
+#define TLV320AIC23_OSC_OFF		0x0020
+#define TLV320AIC23_OUT_OFF		0x0010
+#define TLV320AIC23_DAC_OFF		0x0008
+#define TLV320AIC23_ADC_OFF		0x0004
+#define TLV320AIC23_MIC_OFF		0x0002
+#define TLV320AIC23_LINE_OFF		0x0001
+
+/* Digital audio interface register */
+#define TLV320AIC23_MS_MASTER		0x0040
+#define TLV320AIC23_LRSWAP_ON		0x0020
+#define TLV320AIC23_LRP_ON		0x0010
+#define TLV320AIC23_IWL_16		0x0000
+#define TLV320AIC23_IWL_20		0x0004
+#define TLV320AIC23_IWL_24		0x0008
+#define TLV320AIC23_IWL_32		0x000C
+#define TLV320AIC23_FOR_I2S		0x0002
+#define TLV320AIC23_FOR_DSP		0x0003
+#define TLV320AIC23_FOR_LJUST		0x0001
+
+/* Sample rate control register */
+#define TLV320AIC23_CLKOUT_HALF		0x0080
+#define TLV320AIC23_CLKIN_HALF		0x0040
+#define TLV320AIC23_BOSR_384fs		0x0002	/* BOSR_272fs in USB mode */
+#define TLV320AIC23_USB_CLK_ON		0x0001
+#define TLV320AIC23_SR_MASK             0xf
+#define TLV320AIC23_CLKOUT_SHIFT        7
+#define TLV320AIC23_CLKIN_SHIFT         6
+#define TLV320AIC23_SR_SHIFT            2
+#define TLV320AIC23_BOSR_SHIFT          1
+
+/* Digital interface register */
+#define TLV320AIC23_ACT_ON		0x0001
+
+/*
+ * AUDIO related MACROS
+ */
+
+#define TLV320AIC23_DEFAULT_OUT_VOL	0x70
+#define TLV320AIC23_DEFAULT_IN_VOLUME	0x10
+
+#define TLV320AIC23_OUT_VOL_MIN		TLV320AIC23_LHV_MIN
+#define TLV320AIC23_OUT_VOL_MAX		TLV320AIC23_LHV_MAX
+#define TLV320AIC23_OUT_VO_RANGE	(TLV320AIC23_OUT_VOL_MAX - \
+					TLV320AIC23_OUT_VOL_MIN)
+#define TLV320AIC23_OUT_VOL_MASK	TLV320AIC23_OUT_VOL_MAX
+
+#define TLV320AIC23_IN_VOL_MIN		TLV320AIC23_LIV_MIN
+#define TLV320AIC23_IN_VOL_MAX		TLV320AIC23_LIV_MAX
+#define TLV320AIC23_IN_VOL_RANGE	(TLV320AIC23_IN_VOL_MAX - \
+					TLV320AIC23_IN_VOL_MIN)
+#define TLV320AIC23_IN_VOL_MASK		TLV320AIC23_IN_VOL_MAX
+
+#define TLV320AIC23_SIDETONE_MASK	0x1c0
+#define TLV320AIC23_SIDETONE_0		0x100
+#define TLV320AIC23_SIDETONE_6		0x000
+#define TLV320AIC23_SIDETONE_9		0x040
+#define TLV320AIC23_SIDETONE_12		0x080
+#define TLV320AIC23_SIDETONE_18		0x0c0
+
+#endif /* _TLV320AIC23_H */
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
new file mode 100644
index 0000000..b91b8d5
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -0,0 +1,378 @@
+/*
+ * Texas Instruments TLV320AIC26 low power audio CODEC
+ * ALSA SoC CODEC driver
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include "tlv320aic26.h"
+
+MODULE_DESCRIPTION("ASoC TLV320AIC26 codec driver");
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_LICENSE("GPL");
+
+/* AIC26 driver private data */
+struct aic26 {
+	struct spi_device *spi;
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+	int master;
+	int datfm;
+	int mclk;
+
+	/* Keyclick parameters */
+	int keyclick_amplitude;
+	int keyclick_freq;
+	int keyclick_len;
+};
+
+static const struct snd_soc_dapm_widget tlv320aic26_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("MICIN"),
+SND_SOC_DAPM_INPUT("AUX"),
+
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+static const struct snd_soc_dapm_route tlv320aic26_dapm_routes[] = {
+	{ "Capture", NULL, "MICIN" },
+	{ "Capture", NULL, "AUX" },
+
+	{ "HPL", NULL, "Playback" },
+	{ "HPR", NULL, "Playback" },
+};
+
+/* ---------------------------------------------------------------------
+ * Digital Audio Interface Operations
+ */
+static int aic26_hw_params(struct snd_pcm_substream *substream,
+			   struct snd_pcm_hw_params *params,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct aic26 *aic26 = snd_soc_component_get_drvdata(component);
+	int fsref, divisor, wlen, pval, jval, dval, qval;
+	u16 reg;
+
+	dev_dbg(&aic26->spi->dev, "aic26_hw_params(substream=%p, params=%p)\n",
+		substream, params);
+	dev_dbg(&aic26->spi->dev, "rate=%i width=%d\n", params_rate(params),
+		params_width(params));
+
+	switch (params_rate(params)) {
+	case 8000:  fsref = 48000; divisor = AIC26_DIV_6; break;
+	case 11025: fsref = 44100; divisor = AIC26_DIV_4; break;
+	case 12000: fsref = 48000; divisor = AIC26_DIV_4; break;
+	case 16000: fsref = 48000; divisor = AIC26_DIV_3; break;
+	case 22050: fsref = 44100; divisor = AIC26_DIV_2; break;
+	case 24000: fsref = 48000; divisor = AIC26_DIV_2; break;
+	case 32000: fsref = 48000; divisor = AIC26_DIV_1_5; break;
+	case 44100: fsref = 44100; divisor = AIC26_DIV_1; break;
+	case 48000: fsref = 48000; divisor = AIC26_DIV_1; break;
+	default:
+		dev_dbg(&aic26->spi->dev, "bad rate\n"); return -EINVAL;
+	}
+
+	/* select data word length */
+	switch (params_width(params)) {
+	case 8:  wlen = AIC26_WLEN_16; break;
+	case 16: wlen = AIC26_WLEN_16; break;
+	case 24: wlen = AIC26_WLEN_24; break;
+	case 32: wlen = AIC26_WLEN_32; break;
+	default:
+		dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL;
+	}
+
+	/**
+	 * Configure PLL
+	 * fsref = (mclk * PLLM) / 2048
+	 * where PLLM = J.DDDD (DDDD register ranges from 0 to 9999, decimal)
+	 */
+	pval = 1;
+	/* compute J portion of multiplier */
+	jval = fsref / (aic26->mclk / 2048);
+	/* compute fractional DDDD component of multiplier */
+	dval = fsref - (jval * (aic26->mclk / 2048));
+	dval = (10000 * dval) / (aic26->mclk / 2048);
+	dev_dbg(&aic26->spi->dev, "Setting PLLM to %d.%04d\n", jval, dval);
+	qval = 0;
+	reg = 0x8000 | qval << 11 | pval << 8 | jval << 2;
+	snd_soc_component_write(component, AIC26_REG_PLL_PROG1, reg);
+	reg = dval << 2;
+	snd_soc_component_write(component, AIC26_REG_PLL_PROG2, reg);
+
+	/* Audio Control 3 (master mode, fsref rate) */
+	if (aic26->master)
+		reg = 0x0800;
+	if (fsref == 48000)
+		reg = 0x2000;
+	snd_soc_component_update_bits(component, AIC26_REG_AUDIO_CTRL3, 0xf800, reg);
+
+	/* Audio Control 1 (FSref divisor) */
+	reg = wlen | aic26->datfm | (divisor << 3) | divisor;
+	snd_soc_component_update_bits(component, AIC26_REG_AUDIO_CTRL1, 0xfff, reg);
+
+	return 0;
+}
+
+/**
+ * aic26_mute - Mute control to reduce noise when changing audio format
+ */
+static int aic26_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	struct aic26 *aic26 = snd_soc_component_get_drvdata(component);
+	u16 reg;
+
+	dev_dbg(&aic26->spi->dev, "aic26_mute(dai=%p, mute=%i)\n",
+		dai, mute);
+
+	if (mute)
+		reg = 0x8080;
+	else
+		reg = 0;
+	snd_soc_component_update_bits(component, AIC26_REG_DAC_GAIN, 0x8000, reg);
+
+	return 0;
+}
+
+static int aic26_set_sysclk(struct snd_soc_dai *codec_dai,
+			    int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct aic26 *aic26 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(&aic26->spi->dev, "aic26_set_sysclk(dai=%p, clk_id==%i,"
+		" freq=%i, dir=%i)\n",
+		codec_dai, clk_id, freq, dir);
+
+	/* MCLK needs to fall between 2MHz and 50 MHz */
+	if ((freq < 2000000) || (freq > 50000000))
+		return -EINVAL;
+
+	aic26->mclk = freq;
+	return 0;
+}
+
+static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct aic26 *aic26 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(&aic26->spi->dev, "aic26_set_fmt(dai=%p, fmt==%i)\n",
+		codec_dai, fmt);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM: aic26->master = 1; break;
+	case SND_SOC_DAIFMT_CBS_CFS: aic26->master = 0; break;
+	default:
+		dev_dbg(&aic26->spi->dev, "bad master\n"); return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:     aic26->datfm = AIC26_DATFM_I2S; break;
+	case SND_SOC_DAIFMT_DSP_A:   aic26->datfm = AIC26_DATFM_DSP; break;
+	case SND_SOC_DAIFMT_RIGHT_J: aic26->datfm = AIC26_DATFM_RIGHTJ; break;
+	case SND_SOC_DAIFMT_LEFT_J:  aic26->datfm = AIC26_DATFM_LEFTJ; break;
+	default:
+		dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * Digital Audio Interface Definition
+ */
+#define AIC26_RATES	(SNDRV_PCM_RATE_8000  | SNDRV_PCM_RATE_11025 |\
+			 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+			 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+			 SNDRV_PCM_RATE_48000)
+#define AIC26_FORMATS	(SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_BE |\
+			 SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
+
+static const struct snd_soc_dai_ops aic26_dai_ops = {
+	.hw_params	= aic26_hw_params,
+	.digital_mute	= aic26_mute,
+	.set_sysclk	= aic26_set_sysclk,
+	.set_fmt	= aic26_set_fmt,
+};
+
+static struct snd_soc_dai_driver aic26_dai = {
+	.name = "tlv320aic26-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = AIC26_RATES,
+		.formats = AIC26_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = AIC26_RATES,
+		.formats = AIC26_FORMATS,
+	},
+	.ops = &aic26_dai_ops,
+};
+
+/* ---------------------------------------------------------------------
+ * ALSA controls
+ */
+static const char *aic26_capture_src_text[] = {"Mic", "Aux"};
+static SOC_ENUM_SINGLE_DECL(aic26_capture_src_enum,
+			    AIC26_REG_AUDIO_CTRL1, 12,
+			    aic26_capture_src_text);
+
+static const struct snd_kcontrol_new aic26_snd_controls[] = {
+	/* Output */
+	SOC_DOUBLE("PCM Playback Volume", AIC26_REG_DAC_GAIN, 8, 0, 0x7f, 1),
+	SOC_DOUBLE("PCM Playback Switch", AIC26_REG_DAC_GAIN, 15, 7, 1, 1),
+	SOC_SINGLE("PCM Capture Volume", AIC26_REG_ADC_GAIN, 8, 0x7f, 0),
+	SOC_SINGLE("PCM Capture Mute", AIC26_REG_ADC_GAIN, 15, 1, 1),
+	SOC_SINGLE("Keyclick activate", AIC26_REG_AUDIO_CTRL2, 15, 0x1, 0),
+	SOC_SINGLE("Keyclick amplitude", AIC26_REG_AUDIO_CTRL2, 12, 0x7, 0),
+	SOC_SINGLE("Keyclick frequency", AIC26_REG_AUDIO_CTRL2, 8, 0x7, 0),
+	SOC_SINGLE("Keyclick period", AIC26_REG_AUDIO_CTRL2, 4, 0xf, 0),
+	SOC_ENUM("Capture Source", aic26_capture_src_enum),
+};
+
+/* ---------------------------------------------------------------------
+ * SPI device portion of driver: sysfs files for debugging
+ */
+
+static ssize_t aic26_keyclick_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct aic26 *aic26 = dev_get_drvdata(dev);
+	int val, amp, freq, len;
+
+	val = snd_soc_component_read32(aic26->component, AIC26_REG_AUDIO_CTRL2);
+	amp = (val >> 12) & 0x7;
+	freq = (125 << ((val >> 8) & 0x7)) >> 1;
+	len = 2 * (1 + ((val >> 4) & 0xf));
+
+	return sprintf(buf, "amp=%x freq=%iHz len=%iclks\n", amp, freq, len);
+}
+
+/* Any write to the keyclick attribute will trigger the keyclick event */
+static ssize_t aic26_keyclick_set(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct aic26 *aic26 = dev_get_drvdata(dev);
+
+	snd_soc_component_update_bits(aic26->component, AIC26_REG_AUDIO_CTRL2,
+			    0x8000, 0x800);
+
+	return count;
+}
+
+static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
+
+/* ---------------------------------------------------------------------
+ * SoC CODEC portion of driver: probe and release routines
+ */
+static int aic26_probe(struct snd_soc_component *component)
+{
+	struct aic26 *aic26 = dev_get_drvdata(component->dev);
+	int ret, reg;
+
+	aic26->component = component;
+
+	/* Reset the codec to power on defaults */
+	snd_soc_component_write(component, AIC26_REG_RESET, 0xBB00);
+
+	/* Power up CODEC */
+	snd_soc_component_write(component, AIC26_REG_POWER_CTRL, 0);
+
+	/* Audio Control 3 (master mode, fsref rate) */
+	reg = snd_soc_component_read32(component, AIC26_REG_AUDIO_CTRL3);
+	reg &= ~0xf800;
+	reg |= 0x0800; /* set master mode */
+	snd_soc_component_write(component, AIC26_REG_AUDIO_CTRL3, reg);
+
+	/* Register the sysfs files for debugging */
+	/* Create SysFS files */
+	ret = device_create_file(component->dev, &dev_attr_keyclick);
+	if (ret)
+		dev_info(component->dev, "error creating sysfs files\n");
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver aic26_soc_component_dev = {
+	.probe			= aic26_probe,
+	.controls		= aic26_snd_controls,
+	.num_controls		= ARRAY_SIZE(aic26_snd_controls),
+	.dapm_widgets		= tlv320aic26_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tlv320aic26_dapm_widgets),
+	.dapm_routes		= tlv320aic26_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tlv320aic26_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config aic26_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+};
+
+/* ---------------------------------------------------------------------
+ * SPI device portion of driver: probe and release routines and SPI
+ * 				 driver registration.
+ */
+static int aic26_spi_probe(struct spi_device *spi)
+{
+	struct aic26 *aic26;
+	int ret;
+
+	dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
+
+	/* Allocate driver data */
+	aic26 = devm_kzalloc(&spi->dev, sizeof *aic26, GFP_KERNEL);
+	if (!aic26)
+		return -ENOMEM;
+
+	aic26->regmap = devm_regmap_init_spi(spi, &aic26_regmap);
+	if (IS_ERR(aic26->regmap))
+		return PTR_ERR(aic26->regmap);
+
+	/* Initialize the driver data */
+	aic26->spi = spi;
+	dev_set_drvdata(&spi->dev, aic26);
+	aic26->master = 1;
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&aic26_soc_component_dev, &aic26_dai, 1);
+	return ret;
+}
+
+static struct spi_driver aic26_spi = {
+	.driver = {
+		.name = "tlv320aic26-codec",
+	},
+	.probe = aic26_spi_probe,
+};
+
+module_spi_driver(aic26_spi);
diff --git a/sound/soc/codecs/tlv320aic26.h b/sound/soc/codecs/tlv320aic26.h
new file mode 100644
index 0000000..1f2879b
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic26.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Texas Instruments TLV320AIC26 low power audio CODEC
+ * register definitions
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ */
+
+#ifndef _TLV320AIC16_H_
+#define _TLV320AIC16_H_
+
+/* AIC26 Registers */
+#define AIC26_PAGE_ADDR(page, offset)	((page << 11) | offset << 5)
+
+/* Page 0: Auxiliary data registers */
+#define AIC26_REG_BAT1			AIC26_PAGE_ADDR(0, 0x05)
+#define AIC26_REG_BAT2			AIC26_PAGE_ADDR(0, 0x06)
+#define AIC26_REG_AUX			AIC26_PAGE_ADDR(0, 0x07)
+#define AIC26_REG_TEMP1			AIC26_PAGE_ADDR(0, 0x09)
+#define AIC26_REG_TEMP2			AIC26_PAGE_ADDR(0, 0x0A)
+
+/* Page 1: Auxiliary control registers */
+#define AIC26_REG_AUX_ADC		AIC26_PAGE_ADDR(1, 0x00)
+#define AIC26_REG_STATUS		AIC26_PAGE_ADDR(1, 0x01)
+#define AIC26_REG_REFERENCE		AIC26_PAGE_ADDR(1, 0x03)
+#define AIC26_REG_RESET			AIC26_PAGE_ADDR(1, 0x04)
+
+/* Page 2: Audio control registers */
+#define AIC26_REG_AUDIO_CTRL1		AIC26_PAGE_ADDR(2, 0x00)
+#define AIC26_REG_ADC_GAIN		AIC26_PAGE_ADDR(2, 0x01)
+#define AIC26_REG_DAC_GAIN		AIC26_PAGE_ADDR(2, 0x02)
+#define AIC26_REG_SIDETONE		AIC26_PAGE_ADDR(2, 0x03)
+#define AIC26_REG_AUDIO_CTRL2		AIC26_PAGE_ADDR(2, 0x04)
+#define AIC26_REG_POWER_CTRL		AIC26_PAGE_ADDR(2, 0x05)
+#define AIC26_REG_AUDIO_CTRL3		AIC26_PAGE_ADDR(2, 0x06)
+
+#define AIC26_REG_FILTER_COEFF_L_N0	AIC26_PAGE_ADDR(2, 0x07)
+#define AIC26_REG_FILTER_COEFF_L_N1	AIC26_PAGE_ADDR(2, 0x08)
+#define AIC26_REG_FILTER_COEFF_L_N2	AIC26_PAGE_ADDR(2, 0x09)
+#define AIC26_REG_FILTER_COEFF_L_N3	AIC26_PAGE_ADDR(2, 0x0A)
+#define AIC26_REG_FILTER_COEFF_L_N4	AIC26_PAGE_ADDR(2, 0x0B)
+#define AIC26_REG_FILTER_COEFF_L_N5	AIC26_PAGE_ADDR(2, 0x0C)
+#define AIC26_REG_FILTER_COEFF_L_D1	AIC26_PAGE_ADDR(2, 0x0D)
+#define AIC26_REG_FILTER_COEFF_L_D2	AIC26_PAGE_ADDR(2, 0x0E)
+#define AIC26_REG_FILTER_COEFF_L_D4	AIC26_PAGE_ADDR(2, 0x0F)
+#define AIC26_REG_FILTER_COEFF_L_D5	AIC26_PAGE_ADDR(2, 0x10)
+#define AIC26_REG_FILTER_COEFF_R_N0	AIC26_PAGE_ADDR(2, 0x11)
+#define AIC26_REG_FILTER_COEFF_R_N1	AIC26_PAGE_ADDR(2, 0x12)
+#define AIC26_REG_FILTER_COEFF_R_N2	AIC26_PAGE_ADDR(2, 0x13)
+#define AIC26_REG_FILTER_COEFF_R_N3	AIC26_PAGE_ADDR(2, 0x14)
+#define AIC26_REG_FILTER_COEFF_R_N4	AIC26_PAGE_ADDR(2, 0x15)
+#define AIC26_REG_FILTER_COEFF_R_N5	AIC26_PAGE_ADDR(2, 0x16)
+#define AIC26_REG_FILTER_COEFF_R_D1	AIC26_PAGE_ADDR(2, 0x17)
+#define AIC26_REG_FILTER_COEFF_R_D2	AIC26_PAGE_ADDR(2, 0x18)
+#define AIC26_REG_FILTER_COEFF_R_D4	AIC26_PAGE_ADDR(2, 0x19)
+#define AIC26_REG_FILTER_COEFF_R_D5	AIC26_PAGE_ADDR(2, 0x1A)
+
+#define AIC26_REG_PLL_PROG1		AIC26_PAGE_ADDR(2, 0x1B)
+#define AIC26_REG_PLL_PROG2		AIC26_PAGE_ADDR(2, 0x1C)
+#define AIC26_REG_AUDIO_CTRL4		AIC26_PAGE_ADDR(2, 0x1D)
+#define AIC26_REG_AUDIO_CTRL5		AIC26_PAGE_ADDR(2, 0x1E)
+
+/* fsref dividers; used in register 'Audio Control 1' */
+enum aic26_divisors {
+	AIC26_DIV_1	= 0,
+	AIC26_DIV_1_5	= 1,
+	AIC26_DIV_2	= 2,
+	AIC26_DIV_3	= 3,
+	AIC26_DIV_4	= 4,
+	AIC26_DIV_5	= 5,
+	AIC26_DIV_5_5	= 6,
+	AIC26_DIV_6	= 7,
+};
+
+/* Digital data format */
+enum aic26_datfm {
+	AIC26_DATFM_I2S		= 0 << 8,
+	AIC26_DATFM_DSP		= 1 << 8,
+	AIC26_DATFM_RIGHTJ	= 2 << 8, /* right justified */
+	AIC26_DATFM_LEFTJ	= 3 << 8, /* left justified */
+};
+
+/* Sample word length in bits; used in register 'Audio Control 1' */
+enum aic26_wlen {
+	AIC26_WLEN_16	= 0 << 10,
+	AIC26_WLEN_20	= 1 << 10,
+	AIC26_WLEN_24	= 2 << 10,
+	AIC26_WLEN_32	= 3 << 10,
+};
+
+#endif /* _TLV320AIC16_H_ */
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
new file mode 100644
index 0000000..bf92d36
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -0,0 +1,1497 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ALSA SoC TLV320AIC31xx CODEC Driver
+ *
+ * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/
+ *	Jyri Sarha <jsarha@ti.com>
+ *
+ * Based on ground work by: Ajit Kulkarni <x0175765@ti.com>
+ *
+ * The TLV320AIC31xx series of audio codecs are low-power, highly integrated
+ * high performance codecs which provides a stereo DAC, a mono ADC,
+ * and mono/stereo Class-D speaker driver.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/acpi.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <dt-bindings/sound/tlv320aic31xx-micbias.h>
+
+#include "tlv320aic31xx.h"
+
+static const struct reg_default aic31xx_reg_defaults[] = {
+	{ AIC31XX_CLKMUX, 0x00 },
+	{ AIC31XX_PLLPR, 0x11 },
+	{ AIC31XX_PLLJ, 0x04 },
+	{ AIC31XX_PLLDMSB, 0x00 },
+	{ AIC31XX_PLLDLSB, 0x00 },
+	{ AIC31XX_NDAC, 0x01 },
+	{ AIC31XX_MDAC, 0x01 },
+	{ AIC31XX_DOSRMSB, 0x00 },
+	{ AIC31XX_DOSRLSB, 0x80 },
+	{ AIC31XX_NADC, 0x01 },
+	{ AIC31XX_MADC, 0x01 },
+	{ AIC31XX_AOSR, 0x80 },
+	{ AIC31XX_IFACE1, 0x00 },
+	{ AIC31XX_DATA_OFFSET, 0x00 },
+	{ AIC31XX_IFACE2, 0x00 },
+	{ AIC31XX_BCLKN, 0x01 },
+	{ AIC31XX_DACSETUP, 0x14 },
+	{ AIC31XX_DACMUTE, 0x0c },
+	{ AIC31XX_LDACVOL, 0x00 },
+	{ AIC31XX_RDACVOL, 0x00 },
+	{ AIC31XX_ADCSETUP, 0x00 },
+	{ AIC31XX_ADCFGA, 0x80 },
+	{ AIC31XX_ADCVOL, 0x00 },
+	{ AIC31XX_HPDRIVER, 0x04 },
+	{ AIC31XX_SPKAMP, 0x06 },
+	{ AIC31XX_DACMIXERROUTE, 0x00 },
+	{ AIC31XX_LANALOGHPL, 0x7f },
+	{ AIC31XX_RANALOGHPR, 0x7f },
+	{ AIC31XX_LANALOGSPL, 0x7f },
+	{ AIC31XX_RANALOGSPR, 0x7f },
+	{ AIC31XX_HPLGAIN, 0x02 },
+	{ AIC31XX_HPRGAIN, 0x02 },
+	{ AIC31XX_SPLGAIN, 0x00 },
+	{ AIC31XX_SPRGAIN, 0x00 },
+	{ AIC31XX_MICBIAS, 0x00 },
+	{ AIC31XX_MICPGA, 0x80 },
+	{ AIC31XX_MICPGAPI, 0x00 },
+	{ AIC31XX_MICPGAMI, 0x00 },
+};
+
+static bool aic31xx_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AIC31XX_PAGECTL: /* regmap implementation requires this */
+	case AIC31XX_RESET: /* always clears after write */
+	case AIC31XX_OT_FLAG:
+	case AIC31XX_ADCFLAG:
+	case AIC31XX_DACFLAG1:
+	case AIC31XX_DACFLAG2:
+	case AIC31XX_OFFLAG: /* Sticky interrupt flags */
+	case AIC31XX_INTRDACFLAG: /* Sticky interrupt flags */
+	case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
+	case AIC31XX_INTRDACFLAG2:
+	case AIC31XX_INTRADCFLAG2:
+		return true;
+	}
+	return false;
+}
+
+static bool aic31xx_writeable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AIC31XX_OT_FLAG:
+	case AIC31XX_ADCFLAG:
+	case AIC31XX_DACFLAG1:
+	case AIC31XX_DACFLAG2:
+	case AIC31XX_OFFLAG: /* Sticky interrupt flags */
+	case AIC31XX_INTRDACFLAG: /* Sticky interrupt flags */
+	case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
+	case AIC31XX_INTRDACFLAG2:
+	case AIC31XX_INTRADCFLAG2:
+		return false;
+	}
+	return true;
+}
+
+static const struct regmap_range_cfg aic31xx_ranges[] = {
+	{
+		.range_min = 0,
+		.range_max = 12 * 128,
+		.selector_reg = AIC31XX_PAGECTL,
+		.selector_mask = 0xff,
+		.selector_shift = 0,
+		.window_start = 0,
+		.window_len = 128,
+	},
+};
+
+static const struct regmap_config aic31xx_i2c_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.writeable_reg = aic31xx_writeable,
+	.volatile_reg = aic31xx_volatile,
+	.reg_defaults = aic31xx_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(aic31xx_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+	.ranges = aic31xx_ranges,
+	.num_ranges = ARRAY_SIZE(aic31xx_ranges),
+	.max_register = 12 * 128,
+};
+
+static const char * const aic31xx_supply_names[] = {
+	"HPVDD",
+	"SPRVDD",
+	"SPLVDD",
+	"AVDD",
+	"IOVDD",
+	"DVDD",
+};
+
+#define AIC31XX_NUM_SUPPLIES ARRAY_SIZE(aic31xx_supply_names)
+
+struct aic31xx_disable_nb {
+	struct notifier_block nb;
+	struct aic31xx_priv *aic31xx;
+};
+
+struct aic31xx_priv {
+	struct snd_soc_component *component;
+	u8 i2c_regs_status;
+	struct device *dev;
+	struct regmap *regmap;
+	enum aic31xx_type codec_type;
+	struct gpio_desc *gpio_reset;
+	int micbias_vg;
+	struct aic31xx_pdata pdata;
+	struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
+	struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
+	unsigned int sysclk;
+	u8 p_div;
+	int rate_div_line;
+	bool master_dapm_route_applied;
+};
+
+struct aic31xx_rate_divs {
+	u32 mclk_p;
+	u32 rate;
+	u8 pll_j;
+	u16 pll_d;
+	u16 dosr;
+	u8 ndac;
+	u8 mdac;
+	u8 aosr;
+	u8 nadc;
+	u8 madc;
+};
+
+/* ADC dividers can be disabled by configuring them to 0 */
+static const struct aic31xx_rate_divs aic31xx_divs[] = {
+	/* mclk/p    rate  pll: j     d        dosr ndac mdac  aors nadc madc */
+	/* 8k rate */
+	{12000000,   8000,	8, 1920,	128,  48,  2,	128,  48,  2},
+	{12000000,   8000,	8, 1920,	128,  32,  3,	128,  32,  3},
+	{12500000,   8000,	7, 8643,	128,  48,  2,	128,  48,  2},
+	/* 11.025k rate */
+	{12000000,  11025,	7, 5264,	128,  32,  2,	128,  32,  2},
+	{12000000,  11025,	8, 4672,	128,  24,  3,	128,  24,  3},
+	{12500000,  11025,	7, 2253,	128,  32,  2,	128,  32,  2},
+	/* 16k rate */
+	{12000000,  16000,	8, 1920,	128,  24,  2,	128,  24,  2},
+	{12000000,  16000,	8, 1920,	128,  16,  3,	128,  16,  3},
+	{12500000,  16000,	7, 8643,	128,  24,  2,	128,  24,  2},
+	/* 22.05k rate */
+	{12000000,  22050,	7, 5264,	128,  16,  2,	128,  16,  2},
+	{12000000,  22050,	8, 4672,	128,  12,  3,	128,  12,  3},
+	{12500000,  22050,	7, 2253,	128,  16,  2,	128,  16,  2},
+	/* 32k rate */
+	{12000000,  32000,	8, 1920,	128,  12,  2,	128,  12,  2},
+	{12000000,  32000,	8, 1920,	128,   8,  3,	128,   8,  3},
+	{12500000,  32000,	7, 8643,	128,  12,  2,	128,  12,  2},
+	/* 44.1k rate */
+	{12000000,  44100,	7, 5264,	128,   8,  2,	128,   8,  2},
+	{12000000,  44100,	8, 4672,	128,   6,  3,	128,   6,  3},
+	{12500000,  44100,	7, 2253,	128,   8,  2,	128,   8,  2},
+	/* 48k rate */
+	{12000000,  48000,	8, 1920,	128,   8,  2,	128,   8,  2},
+	{12000000,  48000,	7, 6800,	 96,   5,  4,	 96,   5,  4},
+	{12500000,  48000,	7, 8643,	128,   8,  2,	128,   8,  2},
+	/* 88.2k rate */
+	{12000000,  88200,	7, 5264,	 64,   8,  2,	 64,   8,  2},
+	{12000000,  88200,	8, 4672,	 64,   6,  3,	 64,   6,  3},
+	{12500000,  88200,	7, 2253,	 64,   8,  2,	 64,   8,  2},
+	/* 96k rate */
+	{12000000,  96000,	8, 1920,	 64,   8,  2,	 64,   8,  2},
+	{12000000,  96000,	7, 6800,	 48,   5,  4,	 48,   5,  4},
+	{12500000,  96000,	7, 8643,	 64,   8,  2,	 64,   8,  2},
+	/* 176.4k rate */
+	{12000000, 176400,	7, 5264,	 32,   8,  2,	 32,   8,  2},
+	{12000000, 176400,	8, 4672,	 32,   6,  3,	 32,   6,  3},
+	{12500000, 176400,	7, 2253,	 32,   8,  2,	 32,   8,  2},
+	/* 192k rate */
+	{12000000, 192000,	8, 1920,	 32,   8,  2,	 32,   8,  2},
+	{12000000, 192000,	7, 6800,	 24,   5,  4,	 24,   5,  4},
+	{12500000, 192000,	7, 8643,	 32,   8,  2,	 32,   8,  2},
+};
+
+static const char * const ldac_in_text[] = {
+	"Off", "Left Data", "Right Data", "Mono"
+};
+
+static const char * const rdac_in_text[] = {
+	"Off", "Right Data", "Left Data", "Mono"
+};
+
+static SOC_ENUM_SINGLE_DECL(ldac_in_enum, AIC31XX_DACSETUP, 4, ldac_in_text);
+
+static SOC_ENUM_SINGLE_DECL(rdac_in_enum, AIC31XX_DACSETUP, 2, rdac_in_text);
+
+static const char * const mic_select_text[] = {
+	"Off", "FFR 10 Ohm", "FFR 20 Ohm", "FFR 40 Ohm"
+};
+
+static SOC_ENUM_SINGLE_DECL(mic1lp_p_enum, AIC31XX_MICPGAPI, 6,
+	mic_select_text);
+static SOC_ENUM_SINGLE_DECL(mic1rp_p_enum, AIC31XX_MICPGAPI, 4,
+	mic_select_text);
+static SOC_ENUM_SINGLE_DECL(mic1lm_p_enum, AIC31XX_MICPGAPI, 2,
+	mic_select_text);
+
+static SOC_ENUM_SINGLE_DECL(cm_m_enum, AIC31XX_MICPGAMI, 6, mic_select_text);
+static SOC_ENUM_SINGLE_DECL(mic1lm_m_enum, AIC31XX_MICPGAMI, 4,
+	mic_select_text);
+
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(adc_fgain_tlv, 0, 10, 0);
+static const DECLARE_TLV_DB_SCALE(adc_cgain_tlv, -2000, 50, 0);
+static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, 0, 50, 0);
+static const DECLARE_TLV_DB_SCALE(hp_drv_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(class_D_drv_tlv, 600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(sp_vol_tlv, -6350, 50, 0);
+
+/*
+ * controls to be exported to the user space
+ */
+static const struct snd_kcontrol_new common31xx_snd_controls[] = {
+	SOC_DOUBLE_R_S_TLV("DAC Playback Volume", AIC31XX_LDACVOL,
+			   AIC31XX_RDACVOL, 0, -127, 48, 7, 0, dac_vol_tlv),
+
+	SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN,
+		     AIC31XX_HPRGAIN, 2, 1, 0),
+	SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN,
+			 AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv),
+
+	SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL,
+			 AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv),
+};
+
+static const struct snd_kcontrol_new aic31xx_snd_controls[] = {
+	SOC_SINGLE_TLV("ADC Fine Capture Volume", AIC31XX_ADCFGA, 4, 4, 1,
+		       adc_fgain_tlv),
+
+	SOC_SINGLE("ADC Capture Switch", AIC31XX_ADCFGA, 7, 1, 1),
+	SOC_DOUBLE_R_S_TLV("ADC Capture Volume", AIC31XX_ADCVOL, AIC31XX_ADCVOL,
+			   0, -24, 40, 6, 0, adc_cgain_tlv),
+
+	SOC_SINGLE_TLV("Mic PGA Capture Volume", AIC31XX_MICPGA, 0,
+		       119, 0, mic_pga_tlv),
+};
+
+static const struct snd_kcontrol_new aic311x_snd_controls[] = {
+	SOC_DOUBLE_R("Speaker Driver Playback Switch", AIC31XX_SPLGAIN,
+		     AIC31XX_SPRGAIN, 2, 1, 0),
+	SOC_DOUBLE_R_TLV("Speaker Driver Playback Volume", AIC31XX_SPLGAIN,
+			 AIC31XX_SPRGAIN, 3, 3, 0, class_D_drv_tlv),
+
+	SOC_DOUBLE_R_TLV("Speaker Analog Playback Volume", AIC31XX_LANALOGSPL,
+			 AIC31XX_RANALOGSPR, 0, 0x7F, 1, sp_vol_tlv),
+};
+
+static const struct snd_kcontrol_new aic310x_snd_controls[] = {
+	SOC_SINGLE("Speaker Driver Playback Switch", AIC31XX_SPLGAIN,
+		   2, 1, 0),
+	SOC_SINGLE_TLV("Speaker Driver Playback Volume", AIC31XX_SPLGAIN,
+		       3, 3, 0, class_D_drv_tlv),
+
+	SOC_SINGLE_TLV("Speaker Analog Playback Volume", AIC31XX_LANALOGSPL,
+		       0, 0x7F, 1, sp_vol_tlv),
+};
+
+static const struct snd_kcontrol_new ldac_in_control =
+	SOC_DAPM_ENUM("DAC Left Input", ldac_in_enum);
+
+static const struct snd_kcontrol_new rdac_in_control =
+	SOC_DAPM_ENUM("DAC Right Input", rdac_in_enum);
+
+static int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
+			     unsigned int mask, unsigned int wbits, int sleep,
+			     int count)
+{
+	unsigned int bits;
+	int counter = count;
+	int ret = regmap_read(aic31xx->regmap, reg, &bits);
+
+	while ((bits & mask) != wbits && counter && !ret) {
+		usleep_range(sleep, sleep * 2);
+		ret = regmap_read(aic31xx->regmap, reg, &bits);
+		counter--;
+	}
+	if ((bits & mask) != wbits) {
+		dev_err(aic31xx->dev,
+			"%s: Failed! 0x%x was 0x%x expected 0x%x (%d, 0x%x, %d us)\n",
+			__func__, reg, bits, wbits, ret, mask,
+			(count - counter) * sleep);
+		ret = -1;
+	}
+	return ret;
+}
+
+#define WIDGET_BIT(reg, shift) (((shift) << 8) | (reg))
+
+static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
+				    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
+	unsigned int reg = AIC31XX_DACFLAG1;
+	unsigned int mask;
+
+	switch (WIDGET_BIT(w->reg, w->shift)) {
+	case WIDGET_BIT(AIC31XX_DACSETUP, 7):
+		mask = AIC31XX_LDACPWRSTATUS_MASK;
+		break;
+	case WIDGET_BIT(AIC31XX_DACSETUP, 6):
+		mask = AIC31XX_RDACPWRSTATUS_MASK;
+		break;
+	case WIDGET_BIT(AIC31XX_HPDRIVER, 7):
+		mask = AIC31XX_HPLDRVPWRSTATUS_MASK;
+		break;
+	case WIDGET_BIT(AIC31XX_HPDRIVER, 6):
+		mask = AIC31XX_HPRDRVPWRSTATUS_MASK;
+		break;
+	case WIDGET_BIT(AIC31XX_SPKAMP, 7):
+		mask = AIC31XX_SPLDRVPWRSTATUS_MASK;
+		break;
+	case WIDGET_BIT(AIC31XX_SPKAMP, 6):
+		mask = AIC31XX_SPRDRVPWRSTATUS_MASK;
+		break;
+	case WIDGET_BIT(AIC31XX_ADCSETUP, 7):
+		mask = AIC31XX_ADCPWRSTATUS_MASK;
+		reg = AIC31XX_ADCFLAG;
+		break;
+	default:
+		dev_err(component->dev, "Unknown widget '%s' calling %s\n",
+			w->name, __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		return aic31xx_wait_bits(aic31xx, reg, mask, mask, 5000, 100);
+	case SND_SOC_DAPM_POST_PMD:
+		return aic31xx_wait_bits(aic31xx, reg, mask, 0, 5000, 100);
+	default:
+		dev_dbg(component->dev,
+			"Unhandled dapm widget event %d from %s\n",
+			event, w->name);
+	}
+	return 0;
+}
+
+static const struct snd_kcontrol_new aic31xx_left_output_switches[] = {
+	SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0),
+	SOC_DAPM_SINGLE("From MIC1LP", AIC31XX_DACMIXERROUTE, 5, 1, 0),
+	SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new aic31xx_right_output_switches[] = {
+	SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0),
+	SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac31xx_left_output_switches[] = {
+	SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0),
+	SOC_DAPM_SINGLE("From AIN1", AIC31XX_DACMIXERROUTE, 5, 1, 0),
+	SOC_DAPM_SINGLE("From AIN2", AIC31XX_DACMIXERROUTE, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac31xx_right_output_switches[] = {
+	SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0),
+	SOC_DAPM_SINGLE("From AIN2", AIC31XX_DACMIXERROUTE, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new p_term_mic1lp =
+	SOC_DAPM_ENUM("MIC1LP P-Terminal", mic1lp_p_enum);
+
+static const struct snd_kcontrol_new p_term_mic1rp =
+	SOC_DAPM_ENUM("MIC1RP P-Terminal", mic1rp_p_enum);
+
+static const struct snd_kcontrol_new p_term_mic1lm =
+	SOC_DAPM_ENUM("MIC1LM P-Terminal", mic1lm_p_enum);
+
+static const struct snd_kcontrol_new m_term_mic1lm =
+	SOC_DAPM_ENUM("MIC1LM M-Terminal", mic1lm_m_enum);
+
+static const struct snd_kcontrol_new aic31xx_dapm_hpl_switch =
+	SOC_DAPM_SINGLE("Switch", AIC31XX_LANALOGHPL, 7, 1, 0);
+
+static const struct snd_kcontrol_new aic31xx_dapm_hpr_switch =
+	SOC_DAPM_SINGLE("Switch", AIC31XX_RANALOGHPR, 7, 1, 0);
+
+static const struct snd_kcontrol_new aic31xx_dapm_spl_switch =
+	SOC_DAPM_SINGLE("Switch", AIC31XX_LANALOGSPL, 7, 1, 0);
+
+static const struct snd_kcontrol_new aic31xx_dapm_spr_switch =
+	SOC_DAPM_SINGLE("Switch", AIC31XX_RANALOGSPR, 7, 1, 0);
+
+static int mic_bias_event(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* change mic bias voltage to user defined */
+		snd_soc_component_update_bits(component, AIC31XX_MICBIAS,
+				    AIC31XX_MICBIAS_MASK,
+				    aic31xx->micbias_vg <<
+				    AIC31XX_MICBIAS_SHIFT);
+		dev_dbg(component->dev, "%s: turned on\n", __func__);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* turn mic bias off */
+		snd_soc_component_update_bits(component, AIC31XX_MICBIAS,
+				    AIC31XX_MICBIAS_MASK, 0);
+		dev_dbg(component->dev, "%s: turned off\n", __func__);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget common31xx_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("AIF IN", "Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MUX("DAC Left Input",
+			 SND_SOC_NOPM, 0, 0, &ldac_in_control),
+	SND_SOC_DAPM_MUX("DAC Right Input",
+			 SND_SOC_NOPM, 0, 0, &rdac_in_control),
+	/* DACs */
+	SND_SOC_DAPM_DAC_E("DAC Left", "Left Playback",
+			   AIC31XX_DACSETUP, 7, 0, aic31xx_dapm_power_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_DAC_E("DAC Right", "Right Playback",
+			   AIC31XX_DACSETUP, 6, 0, aic31xx_dapm_power_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* HP */
+	SND_SOC_DAPM_SWITCH("HP Left", SND_SOC_NOPM, 0, 0,
+			    &aic31xx_dapm_hpl_switch),
+	SND_SOC_DAPM_SWITCH("HP Right", SND_SOC_NOPM, 0, 0,
+			    &aic31xx_dapm_hpr_switch),
+
+	/* Output drivers */
+	SND_SOC_DAPM_OUT_DRV_E("HPL Driver", AIC31XX_HPDRIVER, 7, 0,
+			       NULL, 0, aic31xx_dapm_power_event,
+			       SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_OUT_DRV_E("HPR Driver", AIC31XX_HPDRIVER, 6, 0,
+			       NULL, 0, aic31xx_dapm_power_event,
+			       SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+
+	/* Mic Bias */
+	SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, mic_bias_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	/* Keep BCLK/WCLK enabled even if DAC/ADC is powered down */
+	SND_SOC_DAPM_SUPPLY("Activate I2S clocks", AIC31XX_IFACE2, 2, 0,
+			    NULL, 0),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+static const struct snd_soc_dapm_widget dac31xx_dapm_widgets[] = {
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("AIN1"),
+	SND_SOC_DAPM_INPUT("AIN2"),
+
+	/* Output Mixers */
+	SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0,
+			   dac31xx_left_output_switches,
+			   ARRAY_SIZE(dac31xx_left_output_switches)),
+	SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
+			   dac31xx_right_output_switches,
+			   ARRAY_SIZE(dac31xx_right_output_switches)),
+};
+
+static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("MIC1LP"),
+	SND_SOC_DAPM_INPUT("MIC1RP"),
+	SND_SOC_DAPM_INPUT("MIC1LM"),
+
+	/* Input Selection to MIC_PGA */
+	SND_SOC_DAPM_MUX("MIC1LP P-Terminal", SND_SOC_NOPM, 0, 0,
+			 &p_term_mic1lp),
+	SND_SOC_DAPM_MUX("MIC1RP P-Terminal", SND_SOC_NOPM, 0, 0,
+			 &p_term_mic1rp),
+	SND_SOC_DAPM_MUX("MIC1LM P-Terminal", SND_SOC_NOPM, 0, 0,
+			 &p_term_mic1lm),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0,
+			   aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("MIC1LM M-Terminal", SND_SOC_NOPM, 0, 0,
+			 &m_term_mic1lm),
+
+	/* Enabling & Disabling MIC Gain Ctl */
+	SND_SOC_DAPM_PGA("MIC_GAIN_CTL", AIC31XX_MICPGA,
+			 7, 1, NULL, 0),
+
+	/* Output Mixers */
+	SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0,
+			   aic31xx_left_output_switches,
+			   ARRAY_SIZE(aic31xx_left_output_switches)),
+	SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
+			   aic31xx_right_output_switches,
+			   ARRAY_SIZE(aic31xx_right_output_switches)),
+
+	SND_SOC_DAPM_AIF_OUT("AIF OUT", "Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_widget aic311x_dapm_widgets[] = {
+	/* AIC3111 and AIC3110 have stereo class-D amplifier */
+	SND_SOC_DAPM_OUT_DRV_E("SPL ClassD", AIC31XX_SPKAMP, 7, 0, NULL, 0,
+			       aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_OUT_DRV_E("SPR ClassD", AIC31XX_SPKAMP, 6, 0, NULL, 0,
+			       aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SWITCH("Speaker Left", SND_SOC_NOPM, 0, 0,
+			    &aic31xx_dapm_spl_switch),
+	SND_SOC_DAPM_SWITCH("Speaker Right", SND_SOC_NOPM, 0, 0,
+			    &aic31xx_dapm_spr_switch),
+	SND_SOC_DAPM_OUTPUT("SPL"),
+	SND_SOC_DAPM_OUTPUT("SPR"),
+};
+
+/* AIC3100 and AIC3120 have only mono class-D amplifier */
+static const struct snd_soc_dapm_widget aic310x_dapm_widgets[] = {
+	SND_SOC_DAPM_OUT_DRV_E("SPK ClassD", AIC31XX_SPKAMP, 7, 0, NULL, 0,
+			       aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SWITCH("Speaker", SND_SOC_NOPM, 0, 0,
+			    &aic31xx_dapm_spl_switch),
+	SND_SOC_DAPM_OUTPUT("SPK"),
+};
+
+static const struct snd_soc_dapm_route
+common31xx_audio_map[] = {
+	/* DAC Input Routing */
+	{"DAC Left Input", "Left Data", "AIF IN"},
+	{"DAC Left Input", "Right Data", "AIF IN"},
+	{"DAC Left Input", "Mono", "AIF IN"},
+	{"DAC Right Input", "Left Data", "AIF IN"},
+	{"DAC Right Input", "Right Data", "AIF IN"},
+	{"DAC Right Input", "Mono", "AIF IN"},
+	{"DAC Left", NULL, "DAC Left Input"},
+	{"DAC Right", NULL, "DAC Right Input"},
+
+	/* HPL path */
+	{"HP Left", "Switch", "Output Left"},
+	{"HPL Driver", NULL, "HP Left"},
+	{"HPL", NULL, "HPL Driver"},
+
+	/* HPR path */
+	{"HP Right", "Switch", "Output Right"},
+	{"HPR Driver", NULL, "HP Right"},
+	{"HPR", NULL, "HPR Driver"},
+};
+
+static const struct snd_soc_dapm_route
+dac31xx_audio_map[] = {
+	/* Left Output */
+	{"Output Left", "From Left DAC", "DAC Left"},
+	{"Output Left", "From AIN1", "AIN1"},
+	{"Output Left", "From AIN2", "AIN2"},
+
+	/* Right Output */
+	{"Output Right", "From Right DAC", "DAC Right"},
+	{"Output Right", "From AIN2", "AIN2"},
+};
+
+static const struct snd_soc_dapm_route
+aic31xx_audio_map[] = {
+	/* Mic input */
+	{"MIC1LP P-Terminal", "FFR 10 Ohm", "MIC1LP"},
+	{"MIC1LP P-Terminal", "FFR 20 Ohm", "MIC1LP"},
+	{"MIC1LP P-Terminal", "FFR 40 Ohm", "MIC1LP"},
+	{"MIC1RP P-Terminal", "FFR 10 Ohm", "MIC1RP"},
+	{"MIC1RP P-Terminal", "FFR 20 Ohm", "MIC1RP"},
+	{"MIC1RP P-Terminal", "FFR 40 Ohm", "MIC1RP"},
+	{"MIC1LM P-Terminal", "FFR 10 Ohm", "MIC1LM"},
+	{"MIC1LM P-Terminal", "FFR 20 Ohm", "MIC1LM"},
+	{"MIC1LM P-Terminal", "FFR 40 Ohm", "MIC1LM"},
+
+	{"MIC1LM M-Terminal", "FFR 10 Ohm", "MIC1LM"},
+	{"MIC1LM M-Terminal", "FFR 20 Ohm", "MIC1LM"},
+	{"MIC1LM M-Terminal", "FFR 40 Ohm", "MIC1LM"},
+
+	{"MIC_GAIN_CTL", NULL, "MIC1LP P-Terminal"},
+	{"MIC_GAIN_CTL", NULL, "MIC1RP P-Terminal"},
+	{"MIC_GAIN_CTL", NULL, "MIC1LM P-Terminal"},
+	{"MIC_GAIN_CTL", NULL, "MIC1LM M-Terminal"},
+
+	{"ADC", NULL, "MIC_GAIN_CTL"},
+
+	{"AIF OUT", NULL, "ADC"},
+
+	/* Left Output */
+	{"Output Left", "From Left DAC", "DAC Left"},
+	{"Output Left", "From MIC1LP", "MIC1LP"},
+	{"Output Left", "From MIC1RP", "MIC1RP"},
+
+	/* Right Output */
+	{"Output Right", "From Right DAC", "DAC Right"},
+	{"Output Right", "From MIC1RP", "MIC1RP"},
+};
+
+static const struct snd_soc_dapm_route
+aic311x_audio_map[] = {
+	/* SP L path */
+	{"Speaker Left", "Switch", "Output Left"},
+	{"SPL ClassD", NULL, "Speaker Left"},
+	{"SPL", NULL, "SPL ClassD"},
+
+	/* SP R path */
+	{"Speaker Right", "Switch", "Output Right"},
+	{"SPR ClassD", NULL, "Speaker Right"},
+	{"SPR", NULL, "SPR ClassD"},
+};
+
+static const struct snd_soc_dapm_route
+aic310x_audio_map[] = {
+	/* SP L path */
+	{"Speaker", "Switch", "Output Left"},
+	{"SPK ClassD", NULL, "Speaker"},
+	{"SPK", NULL, "SPK ClassD"},
+};
+
+/*
+ * Always connected DAPM routes for codec clock master modes.
+ * If the codec is the master on the I2S bus, we need to power up components
+ * to have valid DAC_CLK.
+ *
+ * In order to have the I2S clocks on the bus either the DACs/ADC need to be
+ * enabled, or the P0/R29/D2 (Keep bclk/wclk in power down) need to be set.
+ *
+ * Otherwise the codec will not generate clocks on the bus.
+ */
+static const struct snd_soc_dapm_route
+common31xx_cm_audio_map[] = {
+	{"HPL", NULL, "AIF IN"},
+	{"HPR", NULL, "AIF IN"},
+
+	{"AIF IN", NULL, "Activate I2S clocks"},
+};
+
+static const struct snd_soc_dapm_route
+aic31xx_cm_audio_map[] = {
+	{"AIF OUT", NULL, "MIC1LP"},
+	{"AIF OUT", NULL, "MIC1RP"},
+	{"AIF OUT", NULL, "MIC1LM"},
+
+	{"AIF OUT", NULL, "Activate I2S clocks"},
+};
+
+static int aic31xx_add_controls(struct snd_soc_component *component)
+{
+	int ret = 0;
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
+
+	if (!(aic31xx->codec_type & DAC31XX_BIT))
+		ret = snd_soc_add_component_controls(
+			component, aic31xx_snd_controls,
+			ARRAY_SIZE(aic31xx_snd_controls));
+	if (ret)
+		return ret;
+
+	if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT)
+		ret = snd_soc_add_component_controls(
+			component, aic311x_snd_controls,
+			ARRAY_SIZE(aic311x_snd_controls));
+	else
+		ret = snd_soc_add_component_controls(
+			component, aic310x_snd_controls,
+			ARRAY_SIZE(aic310x_snd_controls));
+
+	return ret;
+}
+
+static int aic31xx_add_widgets(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	if (aic31xx->codec_type & DAC31XX_BIT) {
+		ret = snd_soc_dapm_new_controls(
+			dapm, dac31xx_dapm_widgets,
+			ARRAY_SIZE(dac31xx_dapm_widgets));
+		if (ret)
+			return ret;
+
+		ret = snd_soc_dapm_add_routes(dapm, dac31xx_audio_map,
+					      ARRAY_SIZE(dac31xx_audio_map));
+		if (ret)
+			return ret;
+	} else {
+		ret = snd_soc_dapm_new_controls(
+			dapm, aic31xx_dapm_widgets,
+			ARRAY_SIZE(aic31xx_dapm_widgets));
+		if (ret)
+			return ret;
+
+		ret = snd_soc_dapm_add_routes(dapm, aic31xx_audio_map,
+					      ARRAY_SIZE(aic31xx_audio_map));
+		if (ret)
+			return ret;
+	}
+
+	if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT) {
+		ret = snd_soc_dapm_new_controls(
+			dapm, aic311x_dapm_widgets,
+			ARRAY_SIZE(aic311x_dapm_widgets));
+		if (ret)
+			return ret;
+
+		ret = snd_soc_dapm_add_routes(dapm, aic311x_audio_map,
+					      ARRAY_SIZE(aic311x_audio_map));
+		if (ret)
+			return ret;
+	} else {
+		ret = snd_soc_dapm_new_controls(
+			dapm, aic310x_dapm_widgets,
+			ARRAY_SIZE(aic310x_dapm_widgets));
+		if (ret)
+			return ret;
+
+		ret = snd_soc_dapm_add_routes(dapm, aic310x_audio_map,
+					      ARRAY_SIZE(aic310x_audio_map));
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int aic31xx_setup_pll(struct snd_soc_component *component,
+			     struct snd_pcm_hw_params *params)
+{
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
+	int bclk_score = snd_soc_params_to_frame_size(params);
+	int mclk_p;
+	int bclk_n = 0;
+	int match = -1;
+	int i;
+
+	if (!aic31xx->sysclk || !aic31xx->p_div) {
+		dev_err(component->dev, "Master clock not supplied\n");
+		return -EINVAL;
+	}
+	mclk_p = aic31xx->sysclk / aic31xx->p_div;
+
+	/* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */
+	snd_soc_component_update_bits(component, AIC31XX_CLKMUX,
+			    AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL);
+	snd_soc_component_update_bits(component, AIC31XX_IFACE2,
+			    AIC31XX_BDIVCLK_MASK, AIC31XX_DAC2BCLK);
+
+	for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) {
+		if (aic31xx_divs[i].rate == params_rate(params) &&
+		    aic31xx_divs[i].mclk_p == mclk_p) {
+			int s =	(aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) %
+				snd_soc_params_to_frame_size(params);
+			int bn = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) /
+				snd_soc_params_to_frame_size(params);
+			if (s < bclk_score && bn > 0) {
+				match = i;
+				bclk_n = bn;
+				bclk_score = s;
+			}
+		}
+	}
+
+	if (match == -1) {
+		dev_err(component->dev,
+			"%s: Sample rate (%u) and format not supported\n",
+			__func__, params_rate(params));
+		/* See bellow for details how fix this. */
+		return -EINVAL;
+	}
+	if (bclk_score != 0) {
+		dev_warn(component->dev, "Can not produce exact bitclock");
+		/* This is fine if using dsp format, but if using i2s
+		   there may be trouble. To fix the issue edit the
+		   aic31xx_divs table for your mclk and sample
+		   rate. Details can be found from:
+		   http://www.ti.com/lit/ds/symlink/tlv320aic3100.pdf
+		   Section: 5.6 CLOCK Generation and PLL
+		*/
+	}
+	i = match;
+
+	/* PLL configuration */
+	snd_soc_component_update_bits(component, AIC31XX_PLLPR, AIC31XX_PLL_MASK,
+			    (aic31xx->p_div << 4) | 0x01);
+	snd_soc_component_write(component, AIC31XX_PLLJ, aic31xx_divs[i].pll_j);
+
+	snd_soc_component_write(component, AIC31XX_PLLDMSB,
+		      aic31xx_divs[i].pll_d >> 8);
+	snd_soc_component_write(component, AIC31XX_PLLDLSB,
+		      aic31xx_divs[i].pll_d & 0xff);
+
+	/* DAC dividers configuration */
+	snd_soc_component_update_bits(component, AIC31XX_NDAC, AIC31XX_PLL_MASK,
+			    aic31xx_divs[i].ndac);
+	snd_soc_component_update_bits(component, AIC31XX_MDAC, AIC31XX_PLL_MASK,
+			    aic31xx_divs[i].mdac);
+
+	snd_soc_component_write(component, AIC31XX_DOSRMSB, aic31xx_divs[i].dosr >> 8);
+	snd_soc_component_write(component, AIC31XX_DOSRLSB, aic31xx_divs[i].dosr & 0xff);
+
+	/* ADC dividers configuration. Write reset value 1 if not used. */
+	snd_soc_component_update_bits(component, AIC31XX_NADC, AIC31XX_PLL_MASK,
+			    aic31xx_divs[i].nadc ? aic31xx_divs[i].nadc : 1);
+	snd_soc_component_update_bits(component, AIC31XX_MADC, AIC31XX_PLL_MASK,
+			    aic31xx_divs[i].madc ? aic31xx_divs[i].madc : 1);
+
+	snd_soc_component_write(component, AIC31XX_AOSR, aic31xx_divs[i].aosr);
+
+	/* Bit clock divider configuration. */
+	snd_soc_component_update_bits(component, AIC31XX_BCLKN,
+			    AIC31XX_PLL_MASK, bclk_n);
+
+	aic31xx->rate_div_line = i;
+
+	dev_dbg(component->dev,
+		"pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n",
+		aic31xx_divs[i].pll_j,
+		aic31xx_divs[i].pll_d,
+		aic31xx->p_div,
+		aic31xx_divs[i].dosr,
+		aic31xx_divs[i].ndac,
+		aic31xx_divs[i].mdac,
+		aic31xx_divs[i].aosr,
+		aic31xx_divs[i].nadc,
+		aic31xx_divs[i].madc,
+		bclk_n
+	);
+
+	return 0;
+}
+
+static int aic31xx_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 data = 0;
+
+	dev_dbg(component->dev, "## %s: width %d rate %d\n",
+		__func__, params_width(params),
+		params_rate(params));
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		data = (AIC31XX_WORD_LEN_20BITS <<
+			AIC31XX_IFACE1_DATALEN_SHIFT);
+		break;
+	case 24:
+		data = (AIC31XX_WORD_LEN_24BITS <<
+			AIC31XX_IFACE1_DATALEN_SHIFT);
+		break;
+	case 32:
+		data = (AIC31XX_WORD_LEN_32BITS <<
+			AIC31XX_IFACE1_DATALEN_SHIFT);
+		break;
+	default:
+		dev_err(component->dev, "%s: Unsupported width %d\n",
+			__func__, params_width(params));
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, AIC31XX_IFACE1,
+			    AIC31XX_IFACE1_DATALEN_MASK,
+			    data);
+
+	return aic31xx_setup_pll(component, params);
+}
+
+static int aic31xx_dac_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_component *component = codec_dai->component;
+
+	if (mute) {
+		snd_soc_component_update_bits(component, AIC31XX_DACMUTE,
+				    AIC31XX_DACMUTE_MASK,
+				    AIC31XX_DACMUTE_MASK);
+	} else {
+		snd_soc_component_update_bits(component, AIC31XX_DACMUTE,
+				    AIC31XX_DACMUTE_MASK, 0x0);
+	}
+
+	return 0;
+}
+
+static int aic31xx_clock_master_routes(struct snd_soc_component *component,
+				       unsigned int fmt)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	fmt &= SND_SOC_DAIFMT_MASTER_MASK;
+	if (fmt == SND_SOC_DAIFMT_CBS_CFS &&
+	    aic31xx->master_dapm_route_applied) {
+		/*
+		 * Remove the DAPM route(s) for codec clock master modes,
+		 * if applied
+		 */
+		ret = snd_soc_dapm_del_routes(dapm, common31xx_cm_audio_map,
+					ARRAY_SIZE(common31xx_cm_audio_map));
+		if (!ret && !(aic31xx->codec_type & DAC31XX_BIT))
+			ret = snd_soc_dapm_del_routes(dapm,
+					aic31xx_cm_audio_map,
+					ARRAY_SIZE(aic31xx_cm_audio_map));
+
+		if (ret)
+			return ret;
+
+		aic31xx->master_dapm_route_applied = false;
+	} else if (fmt != SND_SOC_DAIFMT_CBS_CFS &&
+		   !aic31xx->master_dapm_route_applied) {
+		/*
+		 * Add the needed DAPM route(s) for codec clock master modes,
+		 * if it is not done already
+		 */
+		ret = snd_soc_dapm_add_routes(dapm, common31xx_cm_audio_map,
+					ARRAY_SIZE(common31xx_cm_audio_map));
+		if (!ret && !(aic31xx->codec_type & DAC31XX_BIT))
+			ret = snd_soc_dapm_add_routes(dapm,
+					aic31xx_cm_audio_map,
+					ARRAY_SIZE(aic31xx_cm_audio_map));
+
+		if (ret)
+			return ret;
+
+		aic31xx->master_dapm_route_applied = true;
+	}
+
+	return 0;
+}
+
+static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			       unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u8 iface_reg1 = 0;
+	u8 iface_reg2 = 0;
+	u8 dsp_a_val = 0;
+
+	dev_dbg(component->dev, "## %s: fmt = 0x%x\n", __func__, fmt);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		iface_reg1 |= AIC31XX_WCLK_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		iface_reg1 |= AIC31XX_BCLK_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI master/slave interface\n");
+		return -EINVAL;
+	}
+
+	/* signal polarity */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface_reg2 |= AIC31XX_BCLKINV_MASK;
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI clock signal polarity\n");
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		dsp_a_val = 0x1; /* fall through */
+	case SND_SOC_DAIFMT_DSP_B:
+		/*
+		 * NOTE: This CODEC samples on the falling edge of BCLK in
+		 * DSP mode, this is inverted compared to what most DAIs
+		 * expect, so we invert for this mode
+		 */
+		iface_reg2 ^= AIC31XX_BCLKINV_MASK;
+		iface_reg1 |= (AIC31XX_DSP_MODE <<
+			       AIC31XX_IFACE1_DATATYPE_SHIFT);
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		iface_reg1 |= (AIC31XX_RIGHT_JUSTIFIED_MODE <<
+			       AIC31XX_IFACE1_DATATYPE_SHIFT);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface_reg1 |= (AIC31XX_LEFT_JUSTIFIED_MODE <<
+			       AIC31XX_IFACE1_DATATYPE_SHIFT);
+		break;
+	default:
+		dev_err(component->dev, "Invalid DAI interface format\n");
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, AIC31XX_IFACE1,
+			    AIC31XX_IFACE1_DATATYPE_MASK |
+			    AIC31XX_IFACE1_MASTER_MASK,
+			    iface_reg1);
+	snd_soc_component_update_bits(component, AIC31XX_DATA_OFFSET,
+			    AIC31XX_DATA_OFFSET_MASK,
+			    dsp_a_val);
+	snd_soc_component_update_bits(component, AIC31XX_IFACE2,
+			    AIC31XX_BCLKINV_MASK,
+			    iface_reg2);
+
+	return aic31xx_clock_master_routes(component, fmt);
+}
+
+static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
+	int i;
+
+	dev_dbg(component->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n",
+		__func__, clk_id, freq, dir);
+
+	for (i = 1; i < 8; i++)
+		if (freq / i <= 20000000)
+			break;
+	if (freq/i > 20000000) {
+		dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n",
+			__func__, freq);
+			return -EINVAL;
+	}
+	aic31xx->p_div = i;
+
+	for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++)
+		if (aic31xx_divs[i].mclk_p == freq / aic31xx->p_div)
+			break;
+	if (i == ARRAY_SIZE(aic31xx_divs)) {
+		dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n",
+			__func__, freq);
+		return -EINVAL;
+	}
+
+	/* set clock on MCLK, BCLK, or GPIO1 as PLL input */
+	snd_soc_component_update_bits(component, AIC31XX_CLKMUX, AIC31XX_PLL_CLKIN_MASK,
+			    clk_id << AIC31XX_PLL_CLKIN_SHIFT);
+
+	aic31xx->sysclk = freq;
+
+	return 0;
+}
+
+static int aic31xx_regulator_event(struct notifier_block *nb,
+				   unsigned long event, void *data)
+{
+	struct aic31xx_disable_nb *disable_nb =
+		container_of(nb, struct aic31xx_disable_nb, nb);
+	struct aic31xx_priv *aic31xx = disable_nb->aic31xx;
+
+	if (event & REGULATOR_EVENT_DISABLE) {
+		/*
+		 * Put codec to reset and as at least one of the
+		 * supplies was disabled.
+		 */
+		if (aic31xx->gpio_reset)
+			gpiod_set_value(aic31xx->gpio_reset, 1);
+
+		regcache_mark_dirty(aic31xx->regmap);
+		dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__);
+	}
+
+	return 0;
+}
+
+static int aic31xx_reset(struct aic31xx_priv *aic31xx)
+{
+	int ret = 0;
+
+	if (aic31xx->gpio_reset) {
+		gpiod_set_value(aic31xx->gpio_reset, 1);
+		ndelay(10); /* At least 10ns */
+		gpiod_set_value(aic31xx->gpio_reset, 0);
+	} else {
+		ret = regmap_write(aic31xx->regmap, AIC31XX_RESET, 1);
+	}
+	mdelay(1); /* At least 1ms */
+
+	return ret;
+}
+
+static void aic31xx_clk_on(struct snd_soc_component *component)
+{
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
+	u8 mask = AIC31XX_PM_MASK;
+	u8 on = AIC31XX_PM_MASK;
+
+	dev_dbg(component->dev, "codec clock -> on (rate %d)\n",
+		aic31xx_divs[aic31xx->rate_div_line].rate);
+	snd_soc_component_update_bits(component, AIC31XX_PLLPR, mask, on);
+	mdelay(10);
+	snd_soc_component_update_bits(component, AIC31XX_NDAC, mask, on);
+	snd_soc_component_update_bits(component, AIC31XX_MDAC, mask, on);
+	if (aic31xx_divs[aic31xx->rate_div_line].nadc)
+		snd_soc_component_update_bits(component, AIC31XX_NADC, mask, on);
+	if (aic31xx_divs[aic31xx->rate_div_line].madc)
+		snd_soc_component_update_bits(component, AIC31XX_MADC, mask, on);
+	snd_soc_component_update_bits(component, AIC31XX_BCLKN, mask, on);
+}
+
+static void aic31xx_clk_off(struct snd_soc_component *component)
+{
+	u8 mask = AIC31XX_PM_MASK;
+	u8 off = 0;
+
+	dev_dbg(component->dev, "codec clock -> off\n");
+	snd_soc_component_update_bits(component, AIC31XX_BCLKN, mask, off);
+	snd_soc_component_update_bits(component, AIC31XX_MADC, mask, off);
+	snd_soc_component_update_bits(component, AIC31XX_NADC, mask, off);
+	snd_soc_component_update_bits(component, AIC31XX_MDAC, mask, off);
+	snd_soc_component_update_bits(component, AIC31XX_NDAC, mask, off);
+	snd_soc_component_update_bits(component, AIC31XX_PLLPR, mask, off);
+}
+
+static int aic31xx_power_on(struct snd_soc_component *component)
+{
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(aic31xx->supplies),
+				    aic31xx->supplies);
+	if (ret)
+		return ret;
+
+	regcache_cache_only(aic31xx->regmap, false);
+
+	/* Reset device registers for a consistent power-on like state */
+	ret = aic31xx_reset(aic31xx);
+	if (ret < 0)
+		dev_err(aic31xx->dev, "Could not reset device: %d\n", ret);
+
+	ret = regcache_sync(aic31xx->regmap);
+	if (ret) {
+		dev_err(component->dev,
+			"Failed to restore cache: %d\n", ret);
+		regcache_cache_only(aic31xx->regmap, true);
+		regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
+				       aic31xx->supplies);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void aic31xx_power_off(struct snd_soc_component *component)
+{
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(aic31xx->regmap, true);
+	regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
+			       aic31xx->supplies);
+}
+
+static int aic31xx_set_bias_level(struct snd_soc_component *component,
+				  enum snd_soc_bias_level level)
+{
+	dev_dbg(component->dev, "## %s: %d -> %d\n", __func__,
+		snd_soc_component_get_bias_level(component), level);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY)
+			aic31xx_clk_on(component);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		switch (snd_soc_component_get_bias_level(component)) {
+		case SND_SOC_BIAS_OFF:
+			aic31xx_power_on(component);
+			break;
+		case SND_SOC_BIAS_PREPARE:
+			aic31xx_clk_off(component);
+			break;
+		default:
+			BUG();
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY)
+			aic31xx_power_off(component);
+		break;
+	}
+
+	return 0;
+}
+
+static int aic31xx_codec_probe(struct snd_soc_component *component)
+{
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
+	int i, ret;
+
+	dev_dbg(aic31xx->dev, "## %s\n", __func__);
+
+	aic31xx->component = component;
+
+	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) {
+		aic31xx->disable_nb[i].nb.notifier_call =
+			aic31xx_regulator_event;
+		aic31xx->disable_nb[i].aic31xx = aic31xx;
+		ret = regulator_register_notifier(aic31xx->supplies[i].consumer,
+						  &aic31xx->disable_nb[i].nb);
+		if (ret) {
+			dev_err(component->dev,
+				"Failed to request regulator notifier: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	regcache_cache_only(aic31xx->regmap, true);
+	regcache_mark_dirty(aic31xx->regmap);
+
+	ret = aic31xx_add_controls(component);
+	if (ret)
+		return ret;
+
+	ret = aic31xx_add_widgets(component);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void aic31xx_codec_remove(struct snd_soc_component *component)
+{
+	struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
+		regulator_unregister_notifier(aic31xx->supplies[i].consumer,
+					      &aic31xx->disable_nb[i].nb);
+}
+
+static const struct snd_soc_component_driver soc_codec_driver_aic31xx = {
+	.probe			= aic31xx_codec_probe,
+	.remove			= aic31xx_codec_remove,
+	.set_bias_level		= aic31xx_set_bias_level,
+	.controls		= common31xx_snd_controls,
+	.num_controls		= ARRAY_SIZE(common31xx_snd_controls),
+	.dapm_widgets		= common31xx_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(common31xx_dapm_widgets),
+	.dapm_routes		= common31xx_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(common31xx_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct snd_soc_dai_ops aic31xx_dai_ops = {
+	.hw_params	= aic31xx_hw_params,
+	.set_sysclk	= aic31xx_set_dai_sysclk,
+	.set_fmt	= aic31xx_set_dai_fmt,
+	.digital_mute	= aic31xx_dac_mute,
+};
+
+static struct snd_soc_dai_driver dac31xx_dai_driver[] = {
+	{
+		.name = "tlv320dac31xx-hifi",
+		.playback = {
+			.stream_name	 = "Playback",
+			.channels_min	 = 2,
+			.channels_max	 = 2,
+			.rates		 = AIC31XX_RATES,
+			.formats	 = AIC31XX_FORMATS,
+		},
+		.ops = &aic31xx_dai_ops,
+		.symmetric_rates = 1,
+	}
+};
+
+static struct snd_soc_dai_driver aic31xx_dai_driver[] = {
+	{
+		.name = "tlv320aic31xx-hifi",
+		.playback = {
+			.stream_name	 = "Playback",
+			.channels_min	 = 2,
+			.channels_max	 = 2,
+			.rates		 = AIC31XX_RATES,
+			.formats	 = AIC31XX_FORMATS,
+		},
+		.capture = {
+			.stream_name	 = "Capture",
+			.channels_min	 = 2,
+			.channels_max	 = 2,
+			.rates		 = AIC31XX_RATES,
+			.formats	 = AIC31XX_FORMATS,
+		},
+		.ops = &aic31xx_dai_ops,
+		.symmetric_rates = 1,
+	}
+};
+
+#if defined(CONFIG_OF)
+static const struct of_device_id tlv320aic31xx_of_match[] = {
+	{ .compatible = "ti,tlv320aic310x" },
+	{ .compatible = "ti,tlv320aic311x" },
+	{ .compatible = "ti,tlv320aic3100" },
+	{ .compatible = "ti,tlv320aic3110" },
+	{ .compatible = "ti,tlv320aic3120" },
+	{ .compatible = "ti,tlv320aic3111" },
+	{ .compatible = "ti,tlv320dac3100" },
+	{ .compatible = "ti,tlv320dac3101" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match);
+#endif /* CONFIG_OF */
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id aic31xx_acpi_match[] = {
+	{ "10TI3100", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match);
+#endif
+
+static int aic31xx_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct aic31xx_priv *aic31xx;
+	unsigned int micbias_value = MICBIAS_2_0V;
+	int i, ret;
+
+	dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__,
+		id->name, (int)id->driver_data);
+
+	aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL);
+	if (!aic31xx)
+		return -ENOMEM;
+
+	aic31xx->regmap = devm_regmap_init_i2c(i2c, &aic31xx_i2c_regmap);
+	if (IS_ERR(aic31xx->regmap)) {
+		ret = PTR_ERR(aic31xx->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+	aic31xx->dev = &i2c->dev;
+
+	aic31xx->codec_type = id->driver_data;
+
+	dev_set_drvdata(aic31xx->dev, aic31xx);
+
+	fwnode_property_read_u32(aic31xx->dev->fwnode, "ai31xx-micbias-vg",
+				 &micbias_value);
+	switch (micbias_value) {
+	case MICBIAS_2_0V:
+	case MICBIAS_2_5V:
+	case MICBIAS_AVDDV:
+		aic31xx->micbias_vg = micbias_value;
+		break;
+	default:
+		dev_err(aic31xx->dev, "Bad ai31xx-micbias-vg value %d\n",
+			micbias_value);
+		aic31xx->micbias_vg = MICBIAS_2_0V;
+	}
+
+	if (dev_get_platdata(aic31xx->dev)) {
+		memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev), sizeof(aic31xx->pdata));
+		aic31xx->codec_type = aic31xx->pdata.codec_type;
+		aic31xx->micbias_vg = aic31xx->pdata.micbias_vg;
+	}
+
+	aic31xx->gpio_reset = devm_gpiod_get_optional(aic31xx->dev, "reset",
+						      GPIOD_OUT_LOW);
+	if (IS_ERR(aic31xx->gpio_reset)) {
+		dev_err(aic31xx->dev, "not able to acquire gpio\n");
+		return PTR_ERR(aic31xx->gpio_reset);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
+		aic31xx->supplies[i].supply = aic31xx_supply_names[i];
+
+	ret = devm_regulator_bulk_get(aic31xx->dev,
+				      ARRAY_SIZE(aic31xx->supplies),
+				      aic31xx->supplies);
+	if (ret) {
+		dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	if (aic31xx->codec_type & DAC31XX_BIT)
+		return devm_snd_soc_register_component(&i2c->dev,
+				&soc_codec_driver_aic31xx,
+				dac31xx_dai_driver,
+				ARRAY_SIZE(dac31xx_dai_driver));
+	else
+		return devm_snd_soc_register_component(&i2c->dev,
+				&soc_codec_driver_aic31xx,
+				aic31xx_dai_driver,
+				ARRAY_SIZE(aic31xx_dai_driver));
+}
+
+static const struct i2c_device_id aic31xx_i2c_id[] = {
+	{ "tlv320aic310x", AIC3100 },
+	{ "tlv320aic311x", AIC3110 },
+	{ "tlv320aic3100", AIC3100 },
+	{ "tlv320aic3110", AIC3110 },
+	{ "tlv320aic3120", AIC3120 },
+	{ "tlv320aic3111", AIC3111 },
+	{ "tlv320dac3100", DAC3100 },
+	{ "tlv320dac3101", DAC3101 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id);
+
+static struct i2c_driver aic31xx_i2c_driver = {
+	.driver = {
+		.name	= "tlv320aic31xx-codec",
+		.of_match_table = of_match_ptr(tlv320aic31xx_of_match),
+		.acpi_match_table = ACPI_PTR(aic31xx_acpi_match),
+	},
+	.probe		= aic31xx_i2c_probe,
+	.id_table	= aic31xx_i2c_id,
+};
+module_i2c_driver(aic31xx_i2c_driver);
+
+MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>");
+MODULE_DESCRIPTION("ASoC TLV320AIC31xx CODEC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
new file mode 100644
index 0000000..0b58758
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ALSA SoC TLV320AIC31xx CODEC Driver Definitions
+ *
+ * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+#ifndef _TLV320AIC31XX_H
+#define _TLV320AIC31XX_H
+
+#define AIC31XX_RATES	SNDRV_PCM_RATE_8000_192000
+
+#define AIC31XX_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
+			 SNDRV_PCM_FMTBIT_S20_3LE | \
+			 SNDRV_PCM_FMTBIT_S24_3LE | \
+			 SNDRV_PCM_FMTBIT_S24_LE | \
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+#define AIC31XX_STEREO_CLASS_D_BIT	BIT(1)
+#define AIC31XX_MINIDSP_BIT		BIT(2)
+#define DAC31XX_BIT			BIT(3)
+
+enum aic31xx_type {
+	AIC3100	= 0,
+	AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
+	AIC3120 = AIC31XX_MINIDSP_BIT,
+	AIC3111 = AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT,
+	DAC3100 = DAC31XX_BIT,
+	DAC3101 = DAC31XX_BIT | AIC31XX_STEREO_CLASS_D_BIT,
+};
+
+struct aic31xx_pdata {
+	enum aic31xx_type codec_type;
+	unsigned int gpio_reset;
+	int micbias_vg;
+};
+
+#define AIC31XX_REG(page, reg)	((page * 128) + reg)
+
+#define AIC31XX_PAGECTL		AIC31XX_REG(0, 0) /* Page Control Register */
+
+/* Page 0 Registers */
+#define AIC31XX_RESET		AIC31XX_REG(0, 1) /* Software reset register */
+#define AIC31XX_OT_FLAG		AIC31XX_REG(0, 3) /* OT FLAG register */
+#define AIC31XX_CLKMUX		AIC31XX_REG(0, 4) /* Clock clock Gen muxing, Multiplexers*/
+#define AIC31XX_PLLPR		AIC31XX_REG(0, 5) /* PLL P and R-VAL register */
+#define AIC31XX_PLLJ		AIC31XX_REG(0, 6) /* PLL J-VAL register */
+#define AIC31XX_PLLDMSB		AIC31XX_REG(0, 7) /* PLL D-VAL MSB register */
+#define AIC31XX_PLLDLSB		AIC31XX_REG(0, 8) /* PLL D-VAL LSB register */
+#define AIC31XX_NDAC		AIC31XX_REG(0, 11) /* DAC NDAC_VAL register*/
+#define AIC31XX_MDAC		AIC31XX_REG(0, 12) /* DAC MDAC_VAL register */
+#define AIC31XX_DOSRMSB		AIC31XX_REG(0, 13) /* DAC OSR setting register 1, MSB value */
+#define AIC31XX_DOSRLSB		AIC31XX_REG(0, 14) /* DAC OSR setting register 2, LSB value */
+#define AIC31XX_MINI_DSP_INPOL	AIC31XX_REG(0, 16)
+#define AIC31XX_NADC		AIC31XX_REG(0, 18) /* Clock setting register 8, PLL */
+#define AIC31XX_MADC		AIC31XX_REG(0, 19) /* Clock setting register 9, PLL */
+#define AIC31XX_AOSR		AIC31XX_REG(0, 20) /* ADC Oversampling (AOSR) Register */
+#define AIC31XX_CLKOUTMUX	AIC31XX_REG(0, 25) /* Clock setting register 9, Multiplexers */
+#define AIC31XX_CLKOUTMVAL	AIC31XX_REG(0, 26) /* Clock setting register 10, CLOCKOUT M divider value */
+#define AIC31XX_IFACE1		AIC31XX_REG(0, 27) /* Audio Interface Setting Register 1 */
+#define AIC31XX_DATA_OFFSET	AIC31XX_REG(0, 28) /* Audio Data Slot Offset Programming */
+#define AIC31XX_IFACE2		AIC31XX_REG(0, 29) /* Audio Interface Setting Register 2 */
+#define AIC31XX_BCLKN		AIC31XX_REG(0, 30) /* Clock setting register 11, BCLK N Divider */
+#define AIC31XX_IFACESEC1	AIC31XX_REG(0, 31) /* Audio Interface Setting Register 3, Secondary Audio Interface */
+#define AIC31XX_IFACESEC2	AIC31XX_REG(0, 32) /* Audio Interface Setting Register 4 */
+#define AIC31XX_IFACESEC3	AIC31XX_REG(0, 33) /* Audio Interface Setting Register 5 */
+#define AIC31XX_I2C		AIC31XX_REG(0, 34) /* I2C Bus Condition */
+#define AIC31XX_ADCFLAG		AIC31XX_REG(0, 36) /* ADC FLAG */
+#define AIC31XX_DACFLAG1	AIC31XX_REG(0, 37) /* DAC Flag Registers */
+#define AIC31XX_DACFLAG2	AIC31XX_REG(0, 38)
+#define AIC31XX_OFFLAG		AIC31XX_REG(0, 39) /* Sticky Interrupt flag (overflow) */
+#define AIC31XX_INTRDACFLAG	AIC31XX_REG(0, 44) /* Sticy DAC Interrupt flags */
+#define AIC31XX_INTRADCFLAG	AIC31XX_REG(0, 45) /* Sticy ADC Interrupt flags */
+#define AIC31XX_INTRDACFLAG2	AIC31XX_REG(0, 46) /* DAC Interrupt flags 2 */
+#define AIC31XX_INTRADCFLAG2	AIC31XX_REG(0, 47) /* ADC Interrupt flags 2 */
+#define AIC31XX_INT1CTRL	AIC31XX_REG(0, 48) /* INT1 interrupt control */
+#define AIC31XX_INT2CTRL	AIC31XX_REG(0, 49) /* INT2 interrupt control */
+#define AIC31XX_GPIO1		AIC31XX_REG(0, 51) /* GPIO1 control */
+#define AIC31XX_DACPRB		AIC31XX_REG(0, 60)
+#define AIC31XX_ADCPRB		AIC31XX_REG(0, 61) /* ADC Instruction Set Register */
+#define AIC31XX_DACSETUP	AIC31XX_REG(0, 63) /* DAC channel setup register */
+#define AIC31XX_DACMUTE		AIC31XX_REG(0, 64) /* DAC Mute and volume control register */
+#define AIC31XX_LDACVOL		AIC31XX_REG(0, 65) /* Left DAC channel digital volume control */
+#define AIC31XX_RDACVOL		AIC31XX_REG(0, 66) /* Right DAC channel digital volume control */
+#define AIC31XX_HSDETECT	AIC31XX_REG(0, 67) /* Headset detection */
+#define AIC31XX_ADCSETUP	AIC31XX_REG(0, 81) /* ADC Digital Mic */
+#define AIC31XX_ADCFGA		AIC31XX_REG(0, 82) /* ADC Digital Volume Control Fine Adjust */
+#define AIC31XX_ADCVOL		AIC31XX_REG(0, 83) /* ADC Digital Volume Control Coarse Adjust */
+
+/* Page 1 Registers */
+#define AIC31XX_HPDRIVER	AIC31XX_REG(1, 31) /* Headphone drivers */
+#define AIC31XX_SPKAMP		AIC31XX_REG(1, 32) /* Class-D Speakear Amplifier */
+#define AIC31XX_HPPOP		AIC31XX_REG(1, 33) /* HP Output Drivers POP Removal Settings */
+#define AIC31XX_SPPGARAMP	AIC31XX_REG(1, 34) /* Output Driver PGA Ramp-Down Period Control */
+#define AIC31XX_DACMIXERROUTE	AIC31XX_REG(1, 35) /* DAC_L and DAC_R Output Mixer Routing */
+#define AIC31XX_LANALOGHPL	AIC31XX_REG(1, 36) /* Left Analog Vol to HPL */
+#define AIC31XX_RANALOGHPR	AIC31XX_REG(1, 37) /* Right Analog Vol to HPR */
+#define AIC31XX_LANALOGSPL	AIC31XX_REG(1, 38) /* Left Analog Vol to SPL */
+#define AIC31XX_RANALOGSPR	AIC31XX_REG(1, 39) /* Right Analog Vol to SPR */
+#define AIC31XX_HPLGAIN		AIC31XX_REG(1, 40) /* HPL Driver */
+#define AIC31XX_HPRGAIN		AIC31XX_REG(1, 41) /* HPR Driver */
+#define AIC31XX_SPLGAIN		AIC31XX_REG(1, 42) /* SPL Driver */
+#define AIC31XX_SPRGAIN		AIC31XX_REG(1, 43) /* SPR Driver */
+#define AIC31XX_HPCONTROL	AIC31XX_REG(1, 44) /* HP Driver Control */
+#define AIC31XX_MICBIAS		AIC31XX_REG(1, 46) /* MIC Bias Control */
+#define AIC31XX_MICPGA		AIC31XX_REG(1, 47) /* MIC PGA*/
+#define AIC31XX_MICPGAPI	AIC31XX_REG(1, 48) /* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */
+#define AIC31XX_MICPGAMI	AIC31XX_REG(1, 49) /* ADC Input Selection for M-Terminal */
+#define AIC31XX_MICPGACM	AIC31XX_REG(1, 50) /* Input CM Settings */
+
+/* Bits, masks, and shifts */
+
+/* AIC31XX_CLKMUX */
+#define AIC31XX_PLL_CLKIN_MASK		GENMASK(3, 2)
+#define AIC31XX_PLL_CLKIN_SHIFT		(2)
+#define AIC31XX_PLL_CLKIN_MCLK		0x00
+#define AIC31XX_PLL_CLKIN_BCKL		0x01
+#define AIC31XX_PLL_CLKIN_GPIO1		0x02
+#define AIC31XX_PLL_CLKIN_DIN		0x03
+#define AIC31XX_CODEC_CLKIN_MASK	GENMASK(1, 0)
+#define AIC31XX_CODEC_CLKIN_SHIFT	(0)
+#define AIC31XX_CODEC_CLKIN_MCLK	0x00
+#define AIC31XX_CODEC_CLKIN_BCLK	0x01
+#define AIC31XX_CODEC_CLKIN_GPIO1	0x02
+#define AIC31XX_CODEC_CLKIN_PLL		0x03
+
+/* AIC31XX_PLLPR */
+/* AIC31XX_NDAC */
+/* AIC31XX_MDAC */
+/* AIC31XX_NADC */
+/* AIC31XX_MADC */
+/* AIC31XX_BCLKN */
+#define AIC31XX_PLL_MASK		GENMASK(6, 0)
+#define AIC31XX_PM_MASK			BIT(7)
+
+/* AIC31XX_IFACE1 */
+#define AIC31XX_IFACE1_DATATYPE_MASK	GENMASK(7, 6)
+#define AIC31XX_IFACE1_DATATYPE_SHIFT	(6)
+#define AIC31XX_I2S_MODE		0x00
+#define AIC31XX_DSP_MODE		0x01
+#define AIC31XX_RIGHT_JUSTIFIED_MODE	0x02
+#define AIC31XX_LEFT_JUSTIFIED_MODE	0x03
+#define AIC31XX_IFACE1_DATALEN_MASK	GENMASK(5, 4)
+#define AIC31XX_IFACE1_DATALEN_SHIFT	(4)
+#define AIC31XX_WORD_LEN_16BITS		0x00
+#define AIC31XX_WORD_LEN_20BITS		0x01
+#define AIC31XX_WORD_LEN_24BITS		0x02
+#define AIC31XX_WORD_LEN_32BITS		0x03
+#define AIC31XX_IFACE1_MASTER_MASK	GENMASK(3, 2)
+#define AIC31XX_BCLK_MASTER		BIT(2)
+#define AIC31XX_WCLK_MASTER		BIT(3)
+
+/* AIC31XX_DATA_OFFSET */
+#define AIC31XX_DATA_OFFSET_MASK	GENMASK(7, 0)
+
+/* AIC31XX_IFACE2 */
+#define AIC31XX_BCLKINV_MASK		BIT(3)
+#define AIC31XX_BDIVCLK_MASK		GENMASK(1, 0)
+#define AIC31XX_DAC2BCLK		0x00
+#define AIC31XX_DACMOD2BCLK		0x01
+#define AIC31XX_ADC2BCLK		0x02
+#define AIC31XX_ADCMOD2BCLK		0x03
+#define AIC31XX_KEEP_I2SCLK		BIT(2)
+
+/* AIC31XX_ADCFLAG */
+#define AIC31XX_ADCPWRSTATUS_MASK	BIT(6)
+
+/* AIC31XX_DACFLAG1 */
+#define AIC31XX_LDACPWRSTATUS_MASK	BIT(7)
+#define AIC31XX_HPLDRVPWRSTATUS_MASK	BIT(5)
+#define AIC31XX_SPLDRVPWRSTATUS_MASK	BIT(4)
+#define AIC31XX_RDACPWRSTATUS_MASK	BIT(3)
+#define AIC31XX_HPRDRVPWRSTATUS_MASK	BIT(1)
+#define AIC31XX_SPRDRVPWRSTATUS_MASK	BIT(0)
+
+/* AIC31XX_INTRDACFLAG */
+#define AIC31XX_HPLSCDETECT		BIT(7)
+#define AIC31XX_HPRSCDETECT		BIT(6)
+#define AIC31XX_BUTTONPRESS		BIT(5)
+#define AIC31XX_HSPLUG			BIT(4)
+#define AIC31XX_LDRCTHRES		BIT(3)
+#define AIC31XX_RDRCTHRES		BIT(2)
+#define AIC31XX_DACSINT			BIT(1)
+#define AIC31XX_DACAINT			BIT(0)
+
+/* AIC31XX_INT1CTRL */
+#define AIC31XX_HSPLUGDET		BIT(7)
+#define AIC31XX_BUTTONPRESSDET		BIT(6)
+#define AIC31XX_DRCTHRES		BIT(5)
+#define AIC31XX_AGCNOISE		BIT(4)
+#define AIC31XX_SC			BIT(3)
+#define AIC31XX_ENGINE			BIT(2)
+
+/* AIC31XX_DACSETUP */
+#define AIC31XX_SOFTSTEP_MASK		GENMASK(1, 0)
+
+/* AIC31XX_DACMUTE */
+#define AIC31XX_DACMUTE_MASK		GENMASK(3, 2)
+
+/* AIC31XX_MICBIAS */
+#define AIC31XX_MICBIAS_MASK		GENMASK(1, 0)
+#define AIC31XX_MICBIAS_SHIFT		0
+
+#endif	/* _TLV320AIC31XX_H */
diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c
new file mode 100644
index 0000000..385fa2e
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic32x4-i2c.c
@@ -0,0 +1,76 @@
+/*
+ * linux/sound/soc/codecs/tlv320aic32x4-i2c.c
+ *
+ * Copyright 2011 NW Digital Radio
+ *
+ * Author: Jeremy McDermond <nh6z@nh6z.net>
+ *
+ * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
+ *
+ * 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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "tlv320aic32x4.h"
+
+static int aic32x4_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	struct regmap_config config;
+
+	config = aic32x4_regmap_config;
+	config.reg_bits = 8;
+	config.val_bits = 8;
+
+	regmap = devm_regmap_init_i2c(i2c, &config);
+	return aic32x4_probe(&i2c->dev, regmap);
+}
+
+static int aic32x4_i2c_remove(struct i2c_client *i2c)
+{
+	return aic32x4_remove(&i2c->dev);
+}
+
+static const struct i2c_device_id aic32x4_i2c_id[] = {
+	{ "tlv320aic32x4", 0 },
+	{ "tlv320aic32x6", 1 },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id);
+
+static const struct of_device_id aic32x4_of_id[] = {
+	{ .compatible = "ti,tlv320aic32x4", },
+	{ .compatible = "ti,tlv320aic32x6", },
+	{ /* senitel */ }
+};
+MODULE_DEVICE_TABLE(of, aic32x4_of_id);
+
+static struct i2c_driver aic32x4_i2c_driver = {
+	.driver = {
+		.name = "tlv320aic32x4",
+		.of_match_table = aic32x4_of_id,
+	},
+	.probe =    aic32x4_i2c_probe,
+	.remove =   aic32x4_i2c_remove,
+	.id_table = aic32x4_i2c_id,
+};
+
+module_i2c_driver(aic32x4_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC32x4 codec driver I2C");
+MODULE_AUTHOR("Jeremy McDermond <nh6z@nh6z.net>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c
new file mode 100644
index 0000000..07d78ae
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic32x4-spi.c
@@ -0,0 +1,78 @@
+/*
+ * linux/sound/soc/codecs/tlv320aic32x4-spi.c
+ *
+ * Copyright 2011 NW Digital Radio
+ *
+ * Author: Jeremy McDermond <nh6z@nh6z.net>
+ *
+ * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
+ *
+ * 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.
+ */
+
+#include <linux/spi/spi.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "tlv320aic32x4.h"
+
+static int aic32x4_spi_probe(struct spi_device *spi)
+{
+	struct regmap *regmap;
+	struct regmap_config config;
+
+	config = aic32x4_regmap_config;
+	config.reg_bits = 7;
+	config.pad_bits = 1;
+	config.val_bits = 8;
+	config.read_flag_mask = 0x01;
+
+	regmap = devm_regmap_init_spi(spi, &config);
+	return aic32x4_probe(&spi->dev, regmap);
+}
+
+static int aic32x4_spi_remove(struct spi_device *spi)
+{
+	return aic32x4_remove(&spi->dev);
+}
+
+static const struct spi_device_id aic32x4_spi_id[] = {
+	{ "tlv320aic32x4", 0 },
+	{ "tlv320aic32x6", 1 },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, aic32x4_spi_id);
+
+static const struct of_device_id aic32x4_of_id[] = {
+	{ .compatible = "ti,tlv320aic32x4", },
+	{ .compatible = "ti,tlv320aic32x6", },
+	{ /* senitel */ }
+};
+MODULE_DEVICE_TABLE(of, aic32x4_of_id);
+
+static struct spi_driver aic32x4_spi_driver = {
+	.driver = {
+		.name = "tlv320aic32x4",
+		.owner = THIS_MODULE,
+		.of_match_table = aic32x4_of_id,
+	},
+	.probe =    aic32x4_spi_probe,
+	.remove =   aic32x4_spi_remove,
+	.id_table = aic32x4_spi_id,
+};
+
+module_spi_driver(aic32x4_spi_driver);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC32x4 codec driver SPI");
+MODULE_AUTHOR("Jeremy McDermond <nh6z@nh6z.net>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
new file mode 100644
index 0000000..e2b5a11
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -0,0 +1,1209 @@
+/*
+ * linux/sound/soc/codecs/tlv320aic32x4.c
+ *
+ * Copyright 2011 Vista Silicon S.L.
+ *
+ * Author: Javier Martin <javier.martin@vista-silicon.com>
+ *
+ * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/tlv320aic32x4.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "tlv320aic32x4.h"
+
+struct aic32x4_rate_divs {
+	u32 mclk;
+	u32 rate;
+	u8 p_val;
+	u8 pll_j;
+	u16 pll_d;
+	u16 dosr;
+	u8 ndac;
+	u8 mdac;
+	u8 aosr;
+	u8 nadc;
+	u8 madc;
+	u8 blck_N;
+};
+
+struct aic32x4_priv {
+	struct regmap *regmap;
+	u32 sysclk;
+	u32 power_cfg;
+	u32 micpga_routing;
+	bool swapdacs;
+	int rstn_gpio;
+	struct clk *mclk;
+
+	struct regulator *supply_ldo;
+	struct regulator *supply_iov;
+	struct regulator *supply_dv;
+	struct regulator *supply_av;
+
+	struct aic32x4_setup_data *setup;
+	struct device *dev;
+};
+
+static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	u8 val;
+
+	val = snd_soc_component_read32(component, AIC32X4_DINCTL);
+
+	ucontrol->value.integer.value[0] = (val & 0x01);
+
+	return 0;
+};
+
+static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	u8 val;
+	u8 gpio_check;
+
+	val = snd_soc_component_read32(component, AIC32X4_DOUTCTL);
+	gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
+	if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
+		printk(KERN_ERR "%s: MFP2 is not configure as a GPIO output\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (ucontrol->value.integer.value[0] == (val & AIC32X4_MFP2_GPIO_OUT_HIGH))
+		return 0;
+
+	if (ucontrol->value.integer.value[0])
+		val |= ucontrol->value.integer.value[0];
+	else
+		val &= ~AIC32X4_MFP2_GPIO_OUT_HIGH;
+
+	snd_soc_component_write(component, AIC32X4_DOUTCTL, val);
+
+	return 0;
+};
+
+static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	u8 val;
+
+	val = snd_soc_component_read32(component, AIC32X4_SCLKCTL);
+
+	ucontrol->value.integer.value[0] = (val & 0x01);
+
+	return 0;
+};
+
+static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	u8 val;
+	u8 gpio_check;
+
+	val = snd_soc_component_read32(component, AIC32X4_MISOCTL);
+	gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
+	if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
+		printk(KERN_ERR "%s: MFP4 is not configure as a GPIO output\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (ucontrol->value.integer.value[0] == (val & AIC32X4_MFP5_GPIO_OUT_HIGH))
+		return 0;
+
+	if (ucontrol->value.integer.value[0])
+		val |= ucontrol->value.integer.value[0];
+	else
+		val &= ~AIC32X4_MFP5_GPIO_OUT_HIGH;
+
+	snd_soc_component_write(component, AIC32X4_MISOCTL, val);
+
+	return 0;
+};
+
+static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	u8 val;
+
+	val = snd_soc_component_read32(component, AIC32X4_GPIOCTL);
+	ucontrol->value.integer.value[0] = ((val & 0x2) >> 1);
+
+	return 0;
+};
+
+static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	u8 val;
+	u8 gpio_check;
+
+	val = snd_soc_component_read32(component, AIC32X4_GPIOCTL);
+	gpio_check = (val & AIC32X4_MFP5_GPIO_OUTPUT);
+	if (gpio_check != AIC32X4_MFP5_GPIO_OUTPUT) {
+		printk(KERN_ERR "%s: MFP5 is not configure as a GPIO output\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (ucontrol->value.integer.value[0] == (val & 0x1))
+		return 0;
+
+	if (ucontrol->value.integer.value[0])
+		val |= ucontrol->value.integer.value[0];
+	else
+		val &= 0xfe;
+
+	snd_soc_component_write(component, AIC32X4_GPIOCTL, val);
+
+	return 0;
+};
+
+static const struct snd_kcontrol_new aic32x4_mfp1[] = {
+	SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL),
+};
+
+static const struct snd_kcontrol_new aic32x4_mfp2[] = {
+	SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio),
+};
+
+static const struct snd_kcontrol_new aic32x4_mfp3[] = {
+	SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL),
+};
+
+static const struct snd_kcontrol_new aic32x4_mfp4[] = {
+	SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio),
+};
+
+static const struct snd_kcontrol_new aic32x4_mfp5[] = {
+	SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio,
+		aic32x4_set_mfp5_gpio),
+};
+
+/* 0dB min, 0.5dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0);
+/* -63.5dB min, 0.5dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_pcm, -6350, 50, 0);
+/* -6dB min, 1dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_driver_gain, -600, 100, 0);
+/* -12dB min, 0.5dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0);
+
+static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
+	SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
+			AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
+	SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
+			AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0,
+			tlv_driver_gain),
+	SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN,
+			AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0,
+			tlv_driver_gain),
+	SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN,
+			AIC32X4_HPRGAIN, 6, 0x01, 1),
+	SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
+			AIC32X4_LORGAIN, 6, 0x01, 1),
+	SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL,
+			AIC32X4_RMICPGAVOL, 7, 0x01, 1),
+
+	SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0),
+	SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0),
+
+	SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL,
+			AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol),
+	SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL,
+			AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
+
+	SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
+
+	SOC_SINGLE("AGC Left Switch", AIC32X4_LAGC1, 7, 1, 0),
+	SOC_SINGLE("AGC Right Switch", AIC32X4_RAGC1, 7, 1, 0),
+	SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1,
+			4, 0x07, 0),
+	SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1,
+			0, 0x03, 0),
+	SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2,
+			6, 0x03, 0),
+	SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2,
+			1, 0x1F, 0),
+	SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3,
+			0, 0x7F, 0),
+	SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4,
+			3, 0x1F, 0),
+	SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5,
+			3, 0x1F, 0),
+	SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6,
+			0, 0x1F, 0),
+	SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7,
+			0, 0x0F, 0),
+};
+
+static const struct aic32x4_rate_divs aic32x4_divs[] = {
+	/* 8k rate */
+	{12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24},
+	{24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24},
+	{25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24},
+	/* 11.025k rate */
+	{12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16},
+	{24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16},
+	/* 16k rate */
+	{12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12},
+	{24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12},
+	{25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12},
+	/* 22.05k rate */
+	{12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8},
+	{24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8},
+	{25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8},
+	/* 32k rate */
+	{12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
+	{24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6},
+	/* 44.1k rate */
+	{12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
+	{24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4},
+	{25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4},
+	/* 48k rate */
+	{12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
+	{24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4},
+	{25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4},
+
+	/* 96k rate */
+	{25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1},
+};
+
+static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
+	SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0),
+	SOC_DAPM_SINGLE("IN1_L Switch", AIC32X4_HPLROUTE, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new hpr_output_mixer_controls[] = {
+	SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_HPRROUTE, 3, 1, 0),
+	SOC_DAPM_SINGLE("IN1_R Switch", AIC32X4_HPRROUTE, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new lol_output_mixer_controls[] = {
+	SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_LOLROUTE, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new lor_output_mixer_controls[] = {
+	SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_LORROUTE, 3, 1, 0),
+};
+
+static const char * const resistor_text[] = {
+	"Off", "10 kOhm", "20 kOhm", "40 kOhm",
+};
+
+/* Left mixer pins */
+static SOC_ENUM_SINGLE_DECL(in1l_lpga_p_enum, AIC32X4_LMICPGAPIN, 6, resistor_text);
+static SOC_ENUM_SINGLE_DECL(in2l_lpga_p_enum, AIC32X4_LMICPGAPIN, 4, resistor_text);
+static SOC_ENUM_SINGLE_DECL(in3l_lpga_p_enum, AIC32X4_LMICPGAPIN, 2, resistor_text);
+static SOC_ENUM_SINGLE_DECL(in1r_lpga_p_enum, AIC32X4_LMICPGAPIN, 0, resistor_text);
+
+static SOC_ENUM_SINGLE_DECL(cml_lpga_n_enum, AIC32X4_LMICPGANIN, 6, resistor_text);
+static SOC_ENUM_SINGLE_DECL(in2r_lpga_n_enum, AIC32X4_LMICPGANIN, 4, resistor_text);
+static SOC_ENUM_SINGLE_DECL(in3r_lpga_n_enum, AIC32X4_LMICPGANIN, 2, resistor_text);
+
+static const struct snd_kcontrol_new in1l_to_lmixer_controls[] = {
+	SOC_DAPM_ENUM("IN1_L L+ Switch", in1l_lpga_p_enum),
+};
+static const struct snd_kcontrol_new in2l_to_lmixer_controls[] = {
+	SOC_DAPM_ENUM("IN2_L L+ Switch", in2l_lpga_p_enum),
+};
+static const struct snd_kcontrol_new in3l_to_lmixer_controls[] = {
+	SOC_DAPM_ENUM("IN3_L L+ Switch", in3l_lpga_p_enum),
+};
+static const struct snd_kcontrol_new in1r_to_lmixer_controls[] = {
+	SOC_DAPM_ENUM("IN1_R L+ Switch", in1r_lpga_p_enum),
+};
+static const struct snd_kcontrol_new cml_to_lmixer_controls[] = {
+	SOC_DAPM_ENUM("CM_L L- Switch", cml_lpga_n_enum),
+};
+static const struct snd_kcontrol_new in2r_to_lmixer_controls[] = {
+	SOC_DAPM_ENUM("IN2_R L- Switch", in2r_lpga_n_enum),
+};
+static const struct snd_kcontrol_new in3r_to_lmixer_controls[] = {
+	SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum),
+};
+
+/*  Right mixer pins */
+static SOC_ENUM_SINGLE_DECL(in1r_rpga_p_enum, AIC32X4_RMICPGAPIN, 6, resistor_text);
+static SOC_ENUM_SINGLE_DECL(in2r_rpga_p_enum, AIC32X4_RMICPGAPIN, 4, resistor_text);
+static SOC_ENUM_SINGLE_DECL(in3r_rpga_p_enum, AIC32X4_RMICPGAPIN, 2, resistor_text);
+static SOC_ENUM_SINGLE_DECL(in2l_rpga_p_enum, AIC32X4_RMICPGAPIN, 0, resistor_text);
+static SOC_ENUM_SINGLE_DECL(cmr_rpga_n_enum, AIC32X4_RMICPGANIN, 6, resistor_text);
+static SOC_ENUM_SINGLE_DECL(in1l_rpga_n_enum, AIC32X4_RMICPGANIN, 4, resistor_text);
+static SOC_ENUM_SINGLE_DECL(in3l_rpga_n_enum, AIC32X4_RMICPGANIN, 2, resistor_text);
+
+static const struct snd_kcontrol_new in1r_to_rmixer_controls[] = {
+	SOC_DAPM_ENUM("IN1_R R+ Switch", in1r_rpga_p_enum),
+};
+static const struct snd_kcontrol_new in2r_to_rmixer_controls[] = {
+	SOC_DAPM_ENUM("IN2_R R+ Switch", in2r_rpga_p_enum),
+};
+static const struct snd_kcontrol_new in3r_to_rmixer_controls[] = {
+	SOC_DAPM_ENUM("IN3_R R+ Switch", in3r_rpga_p_enum),
+};
+static const struct snd_kcontrol_new in2l_to_rmixer_controls[] = {
+	SOC_DAPM_ENUM("IN2_L R+ Switch", in2l_rpga_p_enum),
+};
+static const struct snd_kcontrol_new cmr_to_rmixer_controls[] = {
+	SOC_DAPM_ENUM("CM_R R- Switch", cmr_rpga_n_enum),
+};
+static const struct snd_kcontrol_new in1l_to_rmixer_controls[] = {
+	SOC_DAPM_ENUM("IN1_L R- Switch", in1l_rpga_n_enum),
+};
+static const struct snd_kcontrol_new in3l_to_rmixer_controls[] = {
+	SOC_DAPM_ENUM("IN3_L R- Switch", in3l_rpga_n_enum),
+};
+
+static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", AIC32X4_DACSETUP, 7, 0),
+	SND_SOC_DAPM_MIXER("HPL Output Mixer", SND_SOC_NOPM, 0, 0,
+			   &hpl_output_mixer_controls[0],
+			   ARRAY_SIZE(hpl_output_mixer_controls)),
+	SND_SOC_DAPM_PGA("HPL Power", AIC32X4_OUTPWRCTL, 5, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("LOL Output Mixer", SND_SOC_NOPM, 0, 0,
+			   &lol_output_mixer_controls[0],
+			   ARRAY_SIZE(lol_output_mixer_controls)),
+	SND_SOC_DAPM_PGA("LOL Power", AIC32X4_OUTPWRCTL, 3, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", AIC32X4_DACSETUP, 6, 0),
+	SND_SOC_DAPM_MIXER("HPR Output Mixer", SND_SOC_NOPM, 0, 0,
+			   &hpr_output_mixer_controls[0],
+			   ARRAY_SIZE(hpr_output_mixer_controls)),
+	SND_SOC_DAPM_PGA("HPR Power", AIC32X4_OUTPWRCTL, 4, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("LOR Output Mixer", SND_SOC_NOPM, 0, 0,
+			   &lor_output_mixer_controls[0],
+			   ARRAY_SIZE(lor_output_mixer_controls)),
+	SND_SOC_DAPM_PGA("LOR Power", AIC32X4_OUTPWRCTL, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0),
+	SND_SOC_DAPM_MUX("IN1_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
+			in1r_to_rmixer_controls),
+	SND_SOC_DAPM_MUX("IN2_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
+			in2r_to_rmixer_controls),
+	SND_SOC_DAPM_MUX("IN3_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
+			in3r_to_rmixer_controls),
+	SND_SOC_DAPM_MUX("IN2_L to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
+			in2l_to_rmixer_controls),
+	SND_SOC_DAPM_MUX("CM_R to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
+			cmr_to_rmixer_controls),
+	SND_SOC_DAPM_MUX("IN1_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
+			in1l_to_rmixer_controls),
+	SND_SOC_DAPM_MUX("IN3_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
+			in3l_to_rmixer_controls),
+
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0),
+	SND_SOC_DAPM_MUX("IN1_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
+			in1l_to_lmixer_controls),
+	SND_SOC_DAPM_MUX("IN2_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
+			in2l_to_lmixer_controls),
+	SND_SOC_DAPM_MUX("IN3_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
+			in3l_to_lmixer_controls),
+	SND_SOC_DAPM_MUX("IN1_R to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
+			in1r_to_lmixer_controls),
+	SND_SOC_DAPM_MUX("CM_L to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
+			cml_to_lmixer_controls),
+	SND_SOC_DAPM_MUX("IN2_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
+			in2r_to_lmixer_controls),
+	SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
+			in3r_to_lmixer_controls),
+
+	SND_SOC_DAPM_MICBIAS("Mic Bias", AIC32X4_MICBIAS, 6, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("LOL"),
+	SND_SOC_DAPM_OUTPUT("LOR"),
+	SND_SOC_DAPM_INPUT("IN1_L"),
+	SND_SOC_DAPM_INPUT("IN1_R"),
+	SND_SOC_DAPM_INPUT("IN2_L"),
+	SND_SOC_DAPM_INPUT("IN2_R"),
+	SND_SOC_DAPM_INPUT("IN3_L"),
+	SND_SOC_DAPM_INPUT("IN3_R"),
+};
+
+static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
+	/* Left Output */
+	{"HPL Output Mixer", "L_DAC Switch", "Left DAC"},
+	{"HPL Output Mixer", "IN1_L Switch", "IN1_L"},
+
+	{"HPL Power", NULL, "HPL Output Mixer"},
+	{"HPL", NULL, "HPL Power"},
+
+	{"LOL Output Mixer", "L_DAC Switch", "Left DAC"},
+
+	{"LOL Power", NULL, "LOL Output Mixer"},
+	{"LOL", NULL, "LOL Power"},
+
+	/* Right Output */
+	{"HPR Output Mixer", "R_DAC Switch", "Right DAC"},
+	{"HPR Output Mixer", "IN1_R Switch", "IN1_R"},
+
+	{"HPR Power", NULL, "HPR Output Mixer"},
+	{"HPR", NULL, "HPR Power"},
+
+	{"LOR Output Mixer", "R_DAC Switch", "Right DAC"},
+
+	{"LOR Power", NULL, "LOR Output Mixer"},
+	{"LOR", NULL, "LOR Power"},
+
+	/* Right Input */
+	{"Right ADC", NULL, "IN1_R to Right Mixer Positive Resistor"},
+	{"IN1_R to Right Mixer Positive Resistor", "10 kOhm", "IN1_R"},
+	{"IN1_R to Right Mixer Positive Resistor", "20 kOhm", "IN1_R"},
+	{"IN1_R to Right Mixer Positive Resistor", "40 kOhm", "IN1_R"},
+
+	{"Right ADC", NULL, "IN2_R to Right Mixer Positive Resistor"},
+	{"IN2_R to Right Mixer Positive Resistor", "10 kOhm", "IN2_R"},
+	{"IN2_R to Right Mixer Positive Resistor", "20 kOhm", "IN2_R"},
+	{"IN2_R to Right Mixer Positive Resistor", "40 kOhm", "IN2_R"},
+
+	{"Right ADC", NULL, "IN3_R to Right Mixer Positive Resistor"},
+	{"IN3_R to Right Mixer Positive Resistor", "10 kOhm", "IN3_R"},
+	{"IN3_R to Right Mixer Positive Resistor", "20 kOhm", "IN3_R"},
+	{"IN3_R to Right Mixer Positive Resistor", "40 kOhm", "IN3_R"},
+
+	{"Right ADC", NULL, "IN2_L to Right Mixer Positive Resistor"},
+	{"IN2_L to Right Mixer Positive Resistor", "10 kOhm", "IN2_L"},
+	{"IN2_L to Right Mixer Positive Resistor", "20 kOhm", "IN2_L"},
+	{"IN2_L to Right Mixer Positive Resistor", "40 kOhm", "IN2_L"},
+
+	{"Right ADC", NULL, "CM_R to Right Mixer Negative Resistor"},
+	{"CM_R to Right Mixer Negative Resistor", "10 kOhm", "CM_R"},
+	{"CM_R to Right Mixer Negative Resistor", "20 kOhm", "CM_R"},
+	{"CM_R to Right Mixer Negative Resistor", "40 kOhm", "CM_R"},
+
+	{"Right ADC", NULL, "IN1_L to Right Mixer Negative Resistor"},
+	{"IN1_L to Right Mixer Negative Resistor", "10 kOhm", "IN1_L"},
+	{"IN1_L to Right Mixer Negative Resistor", "20 kOhm", "IN1_L"},
+	{"IN1_L to Right Mixer Negative Resistor", "40 kOhm", "IN1_L"},
+
+	{"Right ADC", NULL, "IN3_L to Right Mixer Negative Resistor"},
+	{"IN3_L to Right Mixer Negative Resistor", "10 kOhm", "IN3_L"},
+	{"IN3_L to Right Mixer Negative Resistor", "20 kOhm", "IN3_L"},
+	{"IN3_L to Right Mixer Negative Resistor", "40 kOhm", "IN3_L"},
+
+	/* Left Input */
+	{"Left ADC", NULL, "IN1_L to Left Mixer Positive Resistor"},
+	{"IN1_L to Left Mixer Positive Resistor", "10 kOhm", "IN1_L"},
+	{"IN1_L to Left Mixer Positive Resistor", "20 kOhm", "IN1_L"},
+	{"IN1_L to Left Mixer Positive Resistor", "40 kOhm", "IN1_L"},
+
+	{"Left ADC", NULL, "IN2_L to Left Mixer Positive Resistor"},
+	{"IN2_L to Left Mixer Positive Resistor", "10 kOhm", "IN2_L"},
+	{"IN2_L to Left Mixer Positive Resistor", "20 kOhm", "IN2_L"},
+	{"IN2_L to Left Mixer Positive Resistor", "40 kOhm", "IN2_L"},
+
+	{"Left ADC", NULL, "IN3_L to Left Mixer Positive Resistor"},
+	{"IN3_L to Left Mixer Positive Resistor", "10 kOhm", "IN3_L"},
+	{"IN3_L to Left Mixer Positive Resistor", "20 kOhm", "IN3_L"},
+	{"IN3_L to Left Mixer Positive Resistor", "40 kOhm", "IN3_L"},
+
+	{"Left ADC", NULL, "IN1_R to Left Mixer Positive Resistor"},
+	{"IN1_R to Left Mixer Positive Resistor", "10 kOhm", "IN1_R"},
+	{"IN1_R to Left Mixer Positive Resistor", "20 kOhm", "IN1_R"},
+	{"IN1_R to Left Mixer Positive Resistor", "40 kOhm", "IN1_R"},
+
+	{"Left ADC", NULL, "CM_L to Left Mixer Negative Resistor"},
+	{"CM_L to Left Mixer Negative Resistor", "10 kOhm", "CM_L"},
+	{"CM_L to Left Mixer Negative Resistor", "20 kOhm", "CM_L"},
+	{"CM_L to Left Mixer Negative Resistor", "40 kOhm", "CM_L"},
+
+	{"Left ADC", NULL, "IN2_R to Left Mixer Negative Resistor"},
+	{"IN2_R to Left Mixer Negative Resistor", "10 kOhm", "IN2_R"},
+	{"IN2_R to Left Mixer Negative Resistor", "20 kOhm", "IN2_R"},
+	{"IN2_R to Left Mixer Negative Resistor", "40 kOhm", "IN2_R"},
+
+	{"Left ADC", NULL, "IN3_R to Left Mixer Negative Resistor"},
+	{"IN3_R to Left Mixer Negative Resistor", "10 kOhm", "IN3_R"},
+	{"IN3_R to Left Mixer Negative Resistor", "20 kOhm", "IN3_R"},
+	{"IN3_R to Left Mixer Negative Resistor", "40 kOhm", "IN3_R"},
+};
+
+static const struct regmap_range_cfg aic32x4_regmap_pages[] = {
+	{
+		.selector_reg = 0,
+		.selector_mask  = 0xff,
+		.window_start = 0,
+		.window_len = 128,
+		.range_min = 0,
+		.range_max = AIC32X4_RMICPGAVOL,
+	},
+};
+
+const struct regmap_config aic32x4_regmap_config = {
+	.max_register = AIC32X4_RMICPGAVOL,
+	.ranges = aic32x4_regmap_pages,
+	.num_ranges = ARRAY_SIZE(aic32x4_regmap_pages),
+};
+EXPORT_SYMBOL(aic32x4_regmap_config);
+
+static inline int aic32x4_get_divs(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(aic32x4_divs); i++) {
+		if ((aic32x4_divs[i].rate == rate)
+		    && (aic32x4_divs[i].mclk == mclk)) {
+			return i;
+		}
+	}
+	printk(KERN_ERR "aic32x4: master clock and sample rate is not supported\n");
+	return -EINVAL;
+}
+
+static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
+
+	switch (freq) {
+	case 12000000:
+	case 24000000:
+	case 25000000:
+		aic32x4->sysclk = freq;
+		return 0;
+	}
+	printk(KERN_ERR "aic32x4: invalid frequency to set DAI system clock\n");
+	return -EINVAL;
+}
+
+static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u8 iface_reg_1 = 0;
+	u8 iface_reg_2 = 0;
+	u8 iface_reg_3 = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface_reg_1 |= AIC32X4_BCLKMASTER | AIC32X4_WCLKMASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		printk(KERN_ERR "aic32x4: invalid DAI master/slave interface\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface_reg_1 |= (AIC32X4_DSP_MODE <<
+				AIC32X4_IFACE1_DATATYPE_SHIFT);
+		iface_reg_3 |= AIC32X4_BCLKINV_MASK; /* invert bit clock */
+		iface_reg_2 = 0x01; /* add offset 1 */
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface_reg_1 |= (AIC32X4_DSP_MODE <<
+				AIC32X4_IFACE1_DATATYPE_SHIFT);
+		iface_reg_3 |= AIC32X4_BCLKINV_MASK; /* invert bit clock */
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		iface_reg_1 |= (AIC32X4_RIGHT_JUSTIFIED_MODE <<
+				AIC32X4_IFACE1_DATATYPE_SHIFT);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface_reg_1 |= (AIC32X4_LEFT_JUSTIFIED_MODE <<
+				AIC32X4_IFACE1_DATATYPE_SHIFT);
+		break;
+	default:
+		printk(KERN_ERR "aic32x4: invalid DAI interface format\n");
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, AIC32X4_IFACE1,
+			    AIC32X4_IFACE1_DATATYPE_MASK |
+			    AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
+	snd_soc_component_update_bits(component, AIC32X4_IFACE2,
+			    AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
+	snd_soc_component_update_bits(component, AIC32X4_IFACE3,
+			    AIC32X4_BCLKINV_MASK, iface_reg_3);
+
+	return 0;
+}
+
+static int aic32x4_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
+	u8 iface1_reg = 0;
+	u8 dacsetup_reg = 0;
+	int i;
+
+	i = aic32x4_get_divs(aic32x4->sysclk, params_rate(params));
+	if (i < 0) {
+		printk(KERN_ERR "aic32x4: sampling rate not supported\n");
+		return i;
+	}
+
+	/* MCLK as PLL_CLKIN */
+	snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_PLL_CLKIN_MASK,
+			    AIC32X4_PLL_CLKIN_MCLK << AIC32X4_PLL_CLKIN_SHIFT);
+	/* PLL as CODEC_CLKIN */
+	snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_CODEC_CLKIN_MASK,
+			    AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT);
+	/* DAC_MOD_CLK as BDIV_CLKIN */
+	snd_soc_component_update_bits(component, AIC32X4_IFACE3, AIC32X4_BDIVCLK_MASK,
+			    AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
+
+	/* We will fix R value to 1 and will make P & J=K.D as variable */
+	snd_soc_component_update_bits(component, AIC32X4_PLLPR, AIC32X4_PLL_R_MASK, 0x01);
+
+	/* PLL P value */
+	snd_soc_component_update_bits(component, AIC32X4_PLLPR, AIC32X4_PLL_P_MASK,
+			    aic32x4_divs[i].p_val << AIC32X4_PLL_P_SHIFT);
+
+	/* PLL J value */
+	snd_soc_component_write(component, AIC32X4_PLLJ, aic32x4_divs[i].pll_j);
+
+	/* PLL D value */
+	snd_soc_component_write(component, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8));
+	snd_soc_component_write(component, AIC32X4_PLLDLSB, (aic32x4_divs[i].pll_d & 0xff));
+
+	/* NDAC divider value */
+	snd_soc_component_update_bits(component, AIC32X4_NDAC,
+			    AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac);
+
+	/* MDAC divider value */
+	snd_soc_component_update_bits(component, AIC32X4_MDAC,
+			    AIC32X4_MDAC_MASK, aic32x4_divs[i].mdac);
+
+	/* DOSR MSB & LSB values */
+	snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
+	snd_soc_component_write(component, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff));
+
+	/* NADC divider value */
+	snd_soc_component_update_bits(component, AIC32X4_NADC,
+			    AIC32X4_NADC_MASK, aic32x4_divs[i].nadc);
+
+	/* MADC divider value */
+	snd_soc_component_update_bits(component, AIC32X4_MADC,
+			    AIC32X4_MADC_MASK, aic32x4_divs[i].madc);
+
+	/* AOSR value */
+	snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr);
+
+	/* BCLK N divider */
+	snd_soc_component_update_bits(component, AIC32X4_BCLKN,
+			    AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
+
+	switch (params_width(params)) {
+	case 16:
+		iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
+			       AIC32X4_IFACE1_DATALEN_SHIFT);
+		break;
+	case 20:
+		iface1_reg |= (AIC32X4_WORD_LEN_20BITS <<
+			       AIC32X4_IFACE1_DATALEN_SHIFT);
+		break;
+	case 24:
+		iface1_reg |= (AIC32X4_WORD_LEN_24BITS <<
+			       AIC32X4_IFACE1_DATALEN_SHIFT);
+		break;
+	case 32:
+		iface1_reg |= (AIC32X4_WORD_LEN_32BITS <<
+			       AIC32X4_IFACE1_DATALEN_SHIFT);
+		break;
+	}
+	snd_soc_component_update_bits(component, AIC32X4_IFACE1,
+			    AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
+
+	if (params_channels(params) == 1) {
+		dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
+	} else {
+		if (aic32x4->swapdacs)
+			dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN;
+		else
+			dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
+	}
+	snd_soc_component_update_bits(component, AIC32X4_DACSETUP,
+			    AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
+
+	return 0;
+}
+
+static int aic32x4_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+
+	snd_soc_component_update_bits(component, AIC32X4_DACMUTE,
+			    AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
+
+	return 0;
+}
+
+static int aic32x4_set_bias_level(struct snd_soc_component *component,
+				  enum snd_soc_bias_level level)
+{
+	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* Switch on master clock */
+		ret = clk_prepare_enable(aic32x4->mclk);
+		if (ret) {
+			dev_err(component->dev, "Failed to enable master clock\n");
+			return ret;
+		}
+
+		/* Switch on PLL */
+		snd_soc_component_update_bits(component, AIC32X4_PLLPR,
+				    AIC32X4_PLLEN, AIC32X4_PLLEN);
+
+		/* Switch on NDAC Divider */
+		snd_soc_component_update_bits(component, AIC32X4_NDAC,
+				    AIC32X4_NDACEN, AIC32X4_NDACEN);
+
+		/* Switch on MDAC Divider */
+		snd_soc_component_update_bits(component, AIC32X4_MDAC,
+				    AIC32X4_MDACEN, AIC32X4_MDACEN);
+
+		/* Switch on NADC Divider */
+		snd_soc_component_update_bits(component, AIC32X4_NADC,
+				    AIC32X4_NADCEN, AIC32X4_NADCEN);
+
+		/* Switch on MADC Divider */
+		snd_soc_component_update_bits(component, AIC32X4_MADC,
+				    AIC32X4_MADCEN, AIC32X4_MADCEN);
+
+		/* Switch on BCLK_N Divider */
+		snd_soc_component_update_bits(component, AIC32X4_BCLKN,
+				    AIC32X4_BCLKEN, AIC32X4_BCLKEN);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* Switch off BCLK_N Divider */
+		snd_soc_component_update_bits(component, AIC32X4_BCLKN,
+				    AIC32X4_BCLKEN, 0);
+
+		/* Switch off MADC Divider */
+		snd_soc_component_update_bits(component, AIC32X4_MADC,
+				    AIC32X4_MADCEN, 0);
+
+		/* Switch off NADC Divider */
+		snd_soc_component_update_bits(component, AIC32X4_NADC,
+				    AIC32X4_NADCEN, 0);
+
+		/* Switch off MDAC Divider */
+		snd_soc_component_update_bits(component, AIC32X4_MDAC,
+				    AIC32X4_MDACEN, 0);
+
+		/* Switch off NDAC Divider */
+		snd_soc_component_update_bits(component, AIC32X4_NDAC,
+				    AIC32X4_NDACEN, 0);
+
+		/* Switch off PLL */
+		snd_soc_component_update_bits(component, AIC32X4_PLLPR,
+				    AIC32X4_PLLEN, 0);
+
+		/* Switch off master clock */
+		clk_disable_unprepare(aic32x4->mclk);
+		break;
+	case SND_SOC_BIAS_OFF:
+		break;
+	}
+	return 0;
+}
+
+#define AIC32X4_RATES	SNDRV_PCM_RATE_8000_96000
+#define AIC32X4_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+			 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops aic32x4_ops = {
+	.hw_params = aic32x4_hw_params,
+	.digital_mute = aic32x4_mute,
+	.set_fmt = aic32x4_set_dai_fmt,
+	.set_sysclk = aic32x4_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver aic32x4_dai = {
+	.name = "tlv320aic32x4-hifi",
+	.playback = {
+		     .stream_name = "Playback",
+		     .channels_min = 1,
+		     .channels_max = 2,
+		     .rates = AIC32X4_RATES,
+		     .formats = AIC32X4_FORMATS,},
+	.capture = {
+		    .stream_name = "Capture",
+		    .channels_min = 1,
+		    .channels_max = 2,
+		    .rates = AIC32X4_RATES,
+		    .formats = AIC32X4_FORMATS,},
+	.ops = &aic32x4_ops,
+	.symmetric_rates = 1,
+};
+
+static void aic32x4_setup_gpios(struct snd_soc_component *component)
+{
+	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
+
+	/* setup GPIO functions */
+	/* MFP1 */
+	if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) {
+		snd_soc_component_write(component, AIC32X4_DINCTL,
+		      aic32x4->setup->gpio_func[0]);
+		snd_soc_add_component_controls(component, aic32x4_mfp1,
+			ARRAY_SIZE(aic32x4_mfp1));
+	}
+
+	/* MFP2 */
+	if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) {
+		snd_soc_component_write(component, AIC32X4_DOUTCTL,
+		      aic32x4->setup->gpio_func[1]);
+		snd_soc_add_component_controls(component, aic32x4_mfp2,
+			ARRAY_SIZE(aic32x4_mfp2));
+	}
+
+	/* MFP3 */
+	if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) {
+		snd_soc_component_write(component, AIC32X4_SCLKCTL,
+		      aic32x4->setup->gpio_func[2]);
+		snd_soc_add_component_controls(component, aic32x4_mfp3,
+			ARRAY_SIZE(aic32x4_mfp3));
+	}
+
+	/* MFP4 */
+	if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) {
+		snd_soc_component_write(component, AIC32X4_MISOCTL,
+		      aic32x4->setup->gpio_func[3]);
+		snd_soc_add_component_controls(component, aic32x4_mfp4,
+			ARRAY_SIZE(aic32x4_mfp4));
+	}
+
+	/* MFP5 */
+	if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) {
+		snd_soc_component_write(component, AIC32X4_GPIOCTL,
+		      aic32x4->setup->gpio_func[4]);
+		snd_soc_add_component_controls(component, aic32x4_mfp5,
+			ARRAY_SIZE(aic32x4_mfp5));
+	}
+}
+
+static int aic32x4_component_probe(struct snd_soc_component *component)
+{
+	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
+	u32 tmp_reg;
+
+	if (gpio_is_valid(aic32x4->rstn_gpio)) {
+		ndelay(10);
+		gpio_set_value(aic32x4->rstn_gpio, 1);
+	}
+
+	snd_soc_component_write(component, AIC32X4_RESET, 0x01);
+
+	if (aic32x4->setup)
+		aic32x4_setup_gpios(component);
+
+	/* Power platform configuration */
+	if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
+		snd_soc_component_write(component, AIC32X4_MICBIAS, AIC32X4_MICBIAS_LDOIN |
+						      AIC32X4_MICBIAS_2075V);
+	}
+	if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
+		snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
+
+	tmp_reg = (aic32x4->power_cfg & AIC32X4_PWR_AIC32X4_LDO_ENABLE) ?
+			AIC32X4_LDOCTLEN : 0;
+	snd_soc_component_write(component, AIC32X4_LDOCTL, tmp_reg);
+
+	tmp_reg = snd_soc_component_read32(component, AIC32X4_CMMODE);
+	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36)
+		tmp_reg |= AIC32X4_LDOIN_18_36;
+	if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED)
+		tmp_reg |= AIC32X4_LDOIN2HP;
+	snd_soc_component_write(component, AIC32X4_CMMODE, tmp_reg);
+
+	/* Mic PGA routing */
+	if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K)
+		snd_soc_component_write(component, AIC32X4_LMICPGANIN,
+				AIC32X4_LMICPGANIN_IN2R_10K);
+	else
+		snd_soc_component_write(component, AIC32X4_LMICPGANIN,
+				AIC32X4_LMICPGANIN_CM1L_10K);
+	if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K)
+		snd_soc_component_write(component, AIC32X4_RMICPGANIN,
+				AIC32X4_RMICPGANIN_IN1L_10K);
+	else
+		snd_soc_component_write(component, AIC32X4_RMICPGANIN,
+				AIC32X4_RMICPGANIN_CM1R_10K);
+
+	/*
+	 * Workaround: for an unknown reason, the ADC needs to be powered up
+	 * and down for the first capture to work properly. It seems related to
+	 * a HW BUG or some kind of behavior not documented in the datasheet.
+	 */
+	tmp_reg = snd_soc_component_read32(component, AIC32X4_ADCSETUP);
+	snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg |
+				AIC32X4_LADC_EN | AIC32X4_RADC_EN);
+	snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_aic32x4 = {
+	.probe			= aic32x4_component_probe,
+	.set_bias_level		= aic32x4_set_bias_level,
+	.controls		= aic32x4_snd_controls,
+	.num_controls		= ARRAY_SIZE(aic32x4_snd_controls),
+	.dapm_widgets		= aic32x4_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(aic32x4_dapm_widgets),
+	.dapm_routes		= aic32x4_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(aic32x4_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
+		struct device_node *np)
+{
+	struct aic32x4_setup_data *aic32x4_setup;
+
+	aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup),
+							GFP_KERNEL);
+	if (!aic32x4_setup)
+		return -ENOMEM;
+
+	aic32x4->swapdacs = false;
+	aic32x4->micpga_routing = 0;
+	aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
+
+	if (of_property_read_u32_array(np, "aic32x4-gpio-func",
+				aic32x4_setup->gpio_func, 5) >= 0)
+		aic32x4->setup = aic32x4_setup;
+	return 0;
+}
+
+static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4)
+{
+	regulator_disable(aic32x4->supply_iov);
+
+	if (!IS_ERR(aic32x4->supply_ldo))
+		regulator_disable(aic32x4->supply_ldo);
+
+	if (!IS_ERR(aic32x4->supply_dv))
+		regulator_disable(aic32x4->supply_dv);
+
+	if (!IS_ERR(aic32x4->supply_av))
+		regulator_disable(aic32x4->supply_av);
+}
+
+static int aic32x4_setup_regulators(struct device *dev,
+		struct aic32x4_priv *aic32x4)
+{
+	int ret = 0;
+
+	aic32x4->supply_ldo = devm_regulator_get_optional(dev, "ldoin");
+	aic32x4->supply_iov = devm_regulator_get(dev, "iov");
+	aic32x4->supply_dv = devm_regulator_get_optional(dev, "dv");
+	aic32x4->supply_av = devm_regulator_get_optional(dev, "av");
+
+	/* Check if the regulator requirements are fulfilled */
+
+	if (IS_ERR(aic32x4->supply_iov)) {
+		dev_err(dev, "Missing supply 'iov'\n");
+		return PTR_ERR(aic32x4->supply_iov);
+	}
+
+	if (IS_ERR(aic32x4->supply_ldo)) {
+		if (PTR_ERR(aic32x4->supply_ldo) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+
+		if (IS_ERR(aic32x4->supply_dv)) {
+			dev_err(dev, "Missing supply 'dv' or 'ldoin'\n");
+			return PTR_ERR(aic32x4->supply_dv);
+		}
+		if (IS_ERR(aic32x4->supply_av)) {
+			dev_err(dev, "Missing supply 'av' or 'ldoin'\n");
+			return PTR_ERR(aic32x4->supply_av);
+		}
+	} else {
+		if (IS_ERR(aic32x4->supply_dv) &&
+				PTR_ERR(aic32x4->supply_dv) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+		if (IS_ERR(aic32x4->supply_av) &&
+				PTR_ERR(aic32x4->supply_av) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+	}
+
+	ret = regulator_enable(aic32x4->supply_iov);
+	if (ret) {
+		dev_err(dev, "Failed to enable regulator iov\n");
+		return ret;
+	}
+
+	if (!IS_ERR(aic32x4->supply_ldo)) {
+		ret = regulator_enable(aic32x4->supply_ldo);
+		if (ret) {
+			dev_err(dev, "Failed to enable regulator ldo\n");
+			goto error_ldo;
+		}
+	}
+
+	if (!IS_ERR(aic32x4->supply_dv)) {
+		ret = regulator_enable(aic32x4->supply_dv);
+		if (ret) {
+			dev_err(dev, "Failed to enable regulator dv\n");
+			goto error_dv;
+		}
+	}
+
+	if (!IS_ERR(aic32x4->supply_av)) {
+		ret = regulator_enable(aic32x4->supply_av);
+		if (ret) {
+			dev_err(dev, "Failed to enable regulator av\n");
+			goto error_av;
+		}
+	}
+
+	if (!IS_ERR(aic32x4->supply_ldo) && IS_ERR(aic32x4->supply_av))
+		aic32x4->power_cfg |= AIC32X4_PWR_AIC32X4_LDO_ENABLE;
+
+	return 0;
+
+error_av:
+	if (!IS_ERR(aic32x4->supply_dv))
+		regulator_disable(aic32x4->supply_dv);
+
+error_dv:
+	if (!IS_ERR(aic32x4->supply_ldo))
+		regulator_disable(aic32x4->supply_ldo);
+
+error_ldo:
+	regulator_disable(aic32x4->supply_iov);
+	return ret;
+}
+
+int aic32x4_probe(struct device *dev, struct regmap *regmap)
+{
+	struct aic32x4_priv *aic32x4;
+	struct aic32x4_pdata *pdata = dev->platform_data;
+	struct device_node *np = dev->of_node;
+	int ret;
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv),
+			       GFP_KERNEL);
+	if (aic32x4 == NULL)
+		return -ENOMEM;
+
+	aic32x4->dev = dev;
+	dev_set_drvdata(dev, aic32x4);
+
+	if (pdata) {
+		aic32x4->power_cfg = pdata->power_cfg;
+		aic32x4->swapdacs = pdata->swapdacs;
+		aic32x4->micpga_routing = pdata->micpga_routing;
+		aic32x4->rstn_gpio = pdata->rstn_gpio;
+	} else if (np) {
+		ret = aic32x4_parse_dt(aic32x4, np);
+		if (ret) {
+			dev_err(dev, "Failed to parse DT node\n");
+			return ret;
+		}
+	} else {
+		aic32x4->power_cfg = 0;
+		aic32x4->swapdacs = false;
+		aic32x4->micpga_routing = 0;
+		aic32x4->rstn_gpio = -1;
+	}
+
+	aic32x4->mclk = devm_clk_get(dev, "mclk");
+	if (IS_ERR(aic32x4->mclk)) {
+		dev_err(dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n");
+		return PTR_ERR(aic32x4->mclk);
+	}
+
+	if (gpio_is_valid(aic32x4->rstn_gpio)) {
+		ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio,
+				GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
+		if (ret != 0)
+			return ret;
+	}
+
+	ret = aic32x4_setup_regulators(dev, aic32x4);
+	if (ret) {
+		dev_err(dev, "Failed to setup regulators\n");
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(dev,
+			&soc_component_dev_aic32x4, &aic32x4_dai, 1);
+	if (ret) {
+		dev_err(dev, "Failed to register component\n");
+		aic32x4_disable_regulators(aic32x4);
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(aic32x4_probe);
+
+int aic32x4_remove(struct device *dev)
+{
+	struct aic32x4_priv *aic32x4 = dev_get_drvdata(dev);
+
+	aic32x4_disable_regulators(aic32x4);
+
+	return 0;
+}
+EXPORT_SYMBOL(aic32x4_remove);
+
+MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h
new file mode 100644
index 0000000..e9df49e
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic32x4.h
@@ -0,0 +1,207 @@
+/*
+ * tlv320aic32x4.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#ifndef _TLV320AIC32X4_H
+#define _TLV320AIC32X4_H
+
+struct device;
+struct regmap_config;
+
+extern const struct regmap_config aic32x4_regmap_config;
+int aic32x4_probe(struct device *dev, struct regmap *regmap);
+int aic32x4_remove(struct device *dev);
+
+/* tlv320aic32x4 register space (in decimal to match datasheet) */
+
+#define AIC32X4_REG(page, reg)	((page * 128) + reg)
+
+#define	AIC32X4_PSEL		AIC32X4_REG(0, 0)
+
+#define	AIC32X4_RESET		AIC32X4_REG(0, 1)
+#define	AIC32X4_CLKMUX		AIC32X4_REG(0, 4)
+#define	AIC32X4_PLLPR		AIC32X4_REG(0, 5)
+#define	AIC32X4_PLLJ		AIC32X4_REG(0, 6)
+#define	AIC32X4_PLLDMSB		AIC32X4_REG(0, 7)
+#define	AIC32X4_PLLDLSB		AIC32X4_REG(0, 8)
+#define	AIC32X4_NDAC		AIC32X4_REG(0, 11)
+#define	AIC32X4_MDAC		AIC32X4_REG(0, 12)
+#define AIC32X4_DOSRMSB		AIC32X4_REG(0, 13)
+#define AIC32X4_DOSRLSB		AIC32X4_REG(0, 14)
+#define	AIC32X4_NADC		AIC32X4_REG(0, 18)
+#define	AIC32X4_MADC		AIC32X4_REG(0, 19)
+#define AIC32X4_AOSR		AIC32X4_REG(0, 20)
+#define AIC32X4_CLKMUX2		AIC32X4_REG(0, 25)
+#define AIC32X4_CLKOUTM		AIC32X4_REG(0, 26)
+#define AIC32X4_IFACE1		AIC32X4_REG(0, 27)
+#define AIC32X4_IFACE2		AIC32X4_REG(0, 28)
+#define AIC32X4_IFACE3		AIC32X4_REG(0, 29)
+#define AIC32X4_BCLKN		AIC32X4_REG(0, 30)
+#define AIC32X4_IFACE4		AIC32X4_REG(0, 31)
+#define AIC32X4_IFACE5		AIC32X4_REG(0, 32)
+#define AIC32X4_IFACE6		AIC32X4_REG(0, 33)
+#define AIC32X4_GPIOCTL		AIC32X4_REG(0, 52)
+#define AIC32X4_DOUTCTL		AIC32X4_REG(0, 53)
+#define AIC32X4_DINCTL		AIC32X4_REG(0, 54)
+#define AIC32X4_MISOCTL		AIC32X4_REG(0, 55)
+#define AIC32X4_SCLKCTL		AIC32X4_REG(0, 56)
+#define AIC32X4_DACSPB		AIC32X4_REG(0, 60)
+#define AIC32X4_ADCSPB		AIC32X4_REG(0, 61)
+#define AIC32X4_DACSETUP	AIC32X4_REG(0, 63)
+#define AIC32X4_DACMUTE		AIC32X4_REG(0, 64)
+#define AIC32X4_LDACVOL		AIC32X4_REG(0, 65)
+#define AIC32X4_RDACVOL		AIC32X4_REG(0, 66)
+#define AIC32X4_ADCSETUP	AIC32X4_REG(0, 81)
+#define	AIC32X4_ADCFGA		AIC32X4_REG(0, 82)
+#define AIC32X4_LADCVOL		AIC32X4_REG(0, 83)
+#define AIC32X4_RADCVOL		AIC32X4_REG(0, 84)
+#define AIC32X4_LAGC1		AIC32X4_REG(0, 86)
+#define AIC32X4_LAGC2		AIC32X4_REG(0, 87)
+#define AIC32X4_LAGC3		AIC32X4_REG(0, 88)
+#define AIC32X4_LAGC4		AIC32X4_REG(0, 89)
+#define AIC32X4_LAGC5		AIC32X4_REG(0, 90)
+#define AIC32X4_LAGC6		AIC32X4_REG(0, 91)
+#define AIC32X4_LAGC7		AIC32X4_REG(0, 92)
+#define AIC32X4_RAGC1		AIC32X4_REG(0, 94)
+#define AIC32X4_RAGC2		AIC32X4_REG(0, 95)
+#define AIC32X4_RAGC3		AIC32X4_REG(0, 96)
+#define AIC32X4_RAGC4		AIC32X4_REG(0, 97)
+#define AIC32X4_RAGC5		AIC32X4_REG(0, 98)
+#define AIC32X4_RAGC6		AIC32X4_REG(0, 99)
+#define AIC32X4_RAGC7		AIC32X4_REG(0, 100)
+
+#define AIC32X4_PWRCFG		AIC32X4_REG(1, 1)
+#define AIC32X4_LDOCTL		AIC32X4_REG(1, 2)
+#define AIC32X4_OUTPWRCTL	AIC32X4_REG(1, 9)
+#define AIC32X4_CMMODE		AIC32X4_REG(1, 10)
+#define AIC32X4_HPLROUTE	AIC32X4_REG(1, 12)
+#define AIC32X4_HPRROUTE	AIC32X4_REG(1, 13)
+#define AIC32X4_LOLROUTE	AIC32X4_REG(1, 14)
+#define AIC32X4_LORROUTE	AIC32X4_REG(1, 15)
+#define	AIC32X4_HPLGAIN		AIC32X4_REG(1, 16)
+#define	AIC32X4_HPRGAIN		AIC32X4_REG(1, 17)
+#define	AIC32X4_LOLGAIN		AIC32X4_REG(1, 18)
+#define	AIC32X4_LORGAIN		AIC32X4_REG(1, 19)
+#define AIC32X4_HEADSTART	AIC32X4_REG(1, 20)
+#define AIC32X4_MICBIAS		AIC32X4_REG(1, 51)
+#define AIC32X4_LMICPGAPIN	AIC32X4_REG(1, 52)
+#define AIC32X4_LMICPGANIN	AIC32X4_REG(1, 54)
+#define AIC32X4_RMICPGAPIN	AIC32X4_REG(1, 55)
+#define AIC32X4_RMICPGANIN	AIC32X4_REG(1, 57)
+#define AIC32X4_FLOATINGINPUT	AIC32X4_REG(1, 58)
+#define AIC32X4_LMICPGAVOL	AIC32X4_REG(1, 59)
+#define AIC32X4_RMICPGAVOL	AIC32X4_REG(1, 60)
+
+/* Bits, masks, and shifts */
+
+/* AIC32X4_CLKMUX */
+#define AIC32X4_PLL_CLKIN_MASK		GENMASK(3, 2)
+#define AIC32X4_PLL_CLKIN_SHIFT		(2)
+#define AIC32X4_PLL_CLKIN_MCLK		(0x00)
+#define AIC32X4_PLL_CLKIN_BCKL		(0x01)
+#define AIC32X4_PLL_CLKIN_GPIO1		(0x02)
+#define AIC32X4_PLL_CLKIN_DIN		(0x03)
+#define AIC32X4_CODEC_CLKIN_MASK	GENMASK(1, 0)
+#define AIC32X4_CODEC_CLKIN_SHIFT	(0)
+#define AIC32X4_CODEC_CLKIN_MCLK	(0x00)
+#define AIC32X4_CODEC_CLKIN_BCLK	(0x01)
+#define AIC32X4_CODEC_CLKIN_GPIO1	(0x02)
+#define AIC32X4_CODEC_CLKIN_PLL		(0x03)
+
+/* AIC32X4_PLLPR */
+#define AIC32X4_PLLEN			BIT(7)
+#define AIC32X4_PLL_P_MASK		GENMASK(6, 4)
+#define AIC32X4_PLL_P_SHIFT		(4)
+#define AIC32X4_PLL_R_MASK		GENMASK(3, 0)
+
+/* AIC32X4_NDAC */
+#define AIC32X4_NDACEN			BIT(7)
+#define AIC32X4_NDAC_MASK		GENMASK(6, 0)
+
+/* AIC32X4_MDAC */
+#define AIC32X4_MDACEN			BIT(7)
+#define AIC32X4_MDAC_MASK		GENMASK(6, 0)
+
+/* AIC32X4_NADC */
+#define AIC32X4_NADCEN			BIT(7)
+#define AIC32X4_NADC_MASK		GENMASK(6, 0)
+
+/* AIC32X4_MADC */
+#define AIC32X4_MADCEN			BIT(7)
+#define AIC32X4_MADC_MASK		GENMASK(6, 0)
+
+/* AIC32X4_BCLKN */
+#define AIC32X4_BCLKEN			BIT(7)
+#define AIC32X4_BCLK_MASK		GENMASK(6, 0)
+
+/* AIC32X4_IFACE1 */
+#define AIC32X4_IFACE1_DATATYPE_MASK	GENMASK(7, 6)
+#define AIC32X4_IFACE1_DATATYPE_SHIFT	(6)
+#define AIC32X4_I2S_MODE		(0x00)
+#define AIC32X4_DSP_MODE		(0x01)
+#define AIC32X4_RIGHT_JUSTIFIED_MODE	(0x02)
+#define AIC32X4_LEFT_JUSTIFIED_MODE	(0x03)
+#define AIC32X4_IFACE1_DATALEN_MASK	GENMASK(5, 4)
+#define AIC32X4_IFACE1_DATALEN_SHIFT	(4)
+#define AIC32X4_WORD_LEN_16BITS		(0x00)
+#define AIC32X4_WORD_LEN_20BITS		(0x01)
+#define AIC32X4_WORD_LEN_24BITS		(0x02)
+#define AIC32X4_WORD_LEN_32BITS		(0x03)
+#define AIC32X4_IFACE1_MASTER_MASK	GENMASK(3, 2)
+#define AIC32X4_BCLKMASTER		BIT(2)
+#define AIC32X4_WCLKMASTER		BIT(3)
+
+/* AIC32X4_IFACE2 */
+#define AIC32X4_DATA_OFFSET_MASK	GENMASK(7, 0)
+
+/* AIC32X4_IFACE3 */
+#define AIC32X4_BCLKINV_MASK		BIT(3)
+#define AIC32X4_BDIVCLK_MASK		GENMASK(1, 0)
+#define AIC32X4_BDIVCLK_SHIFT		(0)
+#define AIC32X4_DAC2BCLK		(0x00)
+#define AIC32X4_DACMOD2BCLK		(0x01)
+#define AIC32X4_ADC2BCLK		(0x02)
+#define AIC32X4_ADCMOD2BCLK		(0x03)
+
+/* AIC32X4_DACSETUP */
+#define AIC32X4_DAC_CHAN_MASK		GENMASK(5, 2)
+#define AIC32X4_LDAC2RCHN		BIT(5)
+#define AIC32X4_LDAC2LCHN		BIT(4)
+#define AIC32X4_RDAC2LCHN		BIT(3)
+#define AIC32X4_RDAC2RCHN		BIT(2)
+
+/* AIC32X4_DACMUTE */
+#define AIC32X4_MUTEON			0x0C
+
+/* AIC32X4_ADCSETUP */
+#define AIC32X4_LADC_EN			BIT(7)
+#define AIC32X4_RADC_EN			BIT(6)
+
+/* AIC32X4_PWRCFG */
+#define AIC32X4_AVDDWEAKDISABLE		BIT(3)
+
+/* AIC32X4_LDOCTL */
+#define AIC32X4_LDOCTLEN		BIT(0)
+
+/* AIC32X4_CMMODE */
+#define AIC32X4_LDOIN_18_36		BIT(0)
+#define AIC32X4_LDOIN2HP		BIT(1)
+
+/* AIC32X4_MICBIAS */
+#define AIC32X4_MICBIAS_LDOIN		BIT(3)
+#define AIC32X4_MICBIAS_2075V		0x60
+
+/* AIC32X4_LMICPGANIN */
+#define AIC32X4_LMICPGANIN_IN2R_10K	0x10
+#define AIC32X4_LMICPGANIN_CM1L_10K	0x40
+
+/* AIC32X4_RMICPGANIN */
+#define AIC32X4_RMICPGANIN_IN1L_10K	0x10
+#define AIC32X4_RMICPGANIN_CM1R_10K	0x40
+
+#endif				/* _TLV320AIC32X4_H */
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
new file mode 100644
index 0000000..6a271e6
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -0,0 +1,1934 @@
+/*
+ * ALSA SoC TLV320AIC3X codec driver
+ *
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
+ * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * Based on sound/soc/codecs/wm8753.c by Liam Girdwood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Notes:
+ *  The AIC3X is a driver for a low power stereo audio
+ *  codecs aic31, aic32, aic33, aic3007.
+ *
+ *  It supports full aic33 codec functionality.
+ *  The compatibility with aic32, aic31 and aic3007 is as follows:
+ *    aic32/aic3007    |        aic31
+ *  ---------------------------------------
+ *   MONO_LOUT -> N/A  |  MONO_LOUT -> N/A
+ *                     |  IN1L -> LINE1L
+ *                     |  IN1R -> LINE1R
+ *                     |  IN2L -> LINE2L
+ *                     |  IN2R -> LINE2R
+ *                     |  MIC3L/R -> N/A
+ *   truncated internal functionality in
+ *   accordance with documentation
+ *  ---------------------------------------
+ *
+ *  Hence the machine layer should disable unsupported inputs/outputs by
+ *  snd_soc_dapm_disable_pin(codec, "MONO_LOUT"), etc.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/tlv320aic3x.h>
+
+#include "tlv320aic3x.h"
+
+#define AIC3X_NUM_SUPPLIES	4
+static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
+	"IOVDD",	/* I/O Voltage */
+	"DVDD",		/* Digital Core Voltage */
+	"AVDD",		/* Analog DAC Voltage */
+	"DRVDD",	/* ADC Analog and Output Driver Voltage */
+};
+
+static LIST_HEAD(reset_list);
+
+struct aic3x_priv;
+
+struct aic3x_disable_nb {
+	struct notifier_block nb;
+	struct aic3x_priv *aic3x;
+};
+
+/* codec private data */
+struct aic3x_priv {
+	struct snd_soc_component *component;
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
+	struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES];
+	struct aic3x_setup_data *setup;
+	unsigned int sysclk;
+	unsigned int dai_fmt;
+	unsigned int tdm_delay;
+	unsigned int slot_width;
+	struct list_head list;
+	int master;
+	int gpio_reset;
+	int power;
+#define AIC3X_MODEL_3X 0
+#define AIC3X_MODEL_33 1
+#define AIC3X_MODEL_3007 2
+#define AIC3X_MODEL_3104 3
+	u16 model;
+
+	/* Selects the micbias voltage */
+	enum aic3x_micbias_voltage micbias_vg;
+	/* Output Common-Mode Voltage */
+	u8 ocmv;
+};
+
+static const struct reg_default aic3x_reg[] = {
+	{   0, 0x00 }, {   1, 0x00 }, {   2, 0x00 }, {   3, 0x10 },
+	{   4, 0x04 }, {   5, 0x00 }, {   6, 0x00 }, {   7, 0x00 },
+	{   8, 0x00 }, {   9, 0x00 }, {  10, 0x00 }, {  11, 0x01 },
+	{  12, 0x00 }, {  13, 0x00 }, {  14, 0x00 }, {  15, 0x80 },
+	{  16, 0x80 }, {  17, 0xff }, {  18, 0xff }, {  19, 0x78 },
+	{  20, 0x78 }, {  21, 0x78 }, {  22, 0x78 }, {  23, 0x78 },
+	{  24, 0x78 }, {  25, 0x00 }, {  26, 0x00 }, {  27, 0xfe },
+	{  28, 0x00 }, {  29, 0x00 }, {  30, 0xfe }, {  31, 0x00 },
+	{  32, 0x18 }, {  33, 0x18 }, {  34, 0x00 }, {  35, 0x00 },
+	{  36, 0x00 }, {  37, 0x00 }, {  38, 0x00 }, {  39, 0x00 },
+	{  40, 0x00 }, {  41, 0x00 }, {  42, 0x00 }, {  43, 0x80 },
+	{  44, 0x80 }, {  45, 0x00 }, {  46, 0x00 }, {  47, 0x00 },
+	{  48, 0x00 }, {  49, 0x00 }, {  50, 0x00 }, {  51, 0x04 },
+	{  52, 0x00 }, {  53, 0x00 }, {  54, 0x00 }, {  55, 0x00 },
+	{  56, 0x00 }, {  57, 0x00 }, {  58, 0x04 }, {  59, 0x00 },
+	{  60, 0x00 }, {  61, 0x00 }, {  62, 0x00 }, {  63, 0x00 },
+	{  64, 0x00 }, {  65, 0x04 }, {  66, 0x00 }, {  67, 0x00 },
+	{  68, 0x00 }, {  69, 0x00 }, {  70, 0x00 }, {  71, 0x00 },
+	{  72, 0x04 }, {  73, 0x00 }, {  74, 0x00 }, {  75, 0x00 },
+	{  76, 0x00 }, {  77, 0x00 }, {  78, 0x00 }, {  79, 0x00 },
+	{  80, 0x00 }, {  81, 0x00 }, {  82, 0x00 }, {  83, 0x00 },
+	{  84, 0x00 }, {  85, 0x00 }, {  86, 0x00 }, {  87, 0x00 },
+	{  88, 0x00 }, {  89, 0x00 }, {  90, 0x00 }, {  91, 0x00 },
+	{  92, 0x00 }, {  93, 0x00 }, {  94, 0x00 }, {  95, 0x00 },
+	{  96, 0x00 }, {  97, 0x00 }, {  98, 0x00 }, {  99, 0x00 },
+	{ 100, 0x00 }, { 101, 0x00 }, { 102, 0x02 }, { 103, 0x00 },
+	{ 104, 0x00 }, { 105, 0x00 }, { 106, 0x00 }, { 107, 0x00 },
+	{ 108, 0x00 }, { 109, 0x00 },
+};
+
+static bool aic3x_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AIC3X_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config aic3x_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = DAC_ICC_ADJ,
+	.reg_defaults = aic3x_reg,
+	.num_reg_defaults = ARRAY_SIZE(aic3x_reg),
+
+	.volatile_reg = aic3x_volatile_reg,
+
+	.cache_type = REGCACHE_RBTREE,
+};
+
+#define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
+	SOC_SINGLE_EXT(xname, reg, shift, mask, invert, \
+		snd_soc_dapm_get_volsw, snd_soc_dapm_put_volsw_aic3x)
+
+/*
+ * All input lines are connected when !0xf and disconnected with 0xf bit field,
+ * so we have to use specific dapm_put call for input mixer
+ */
+static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned int reg = mc->reg;
+	unsigned int shift = mc->shift;
+	int max = mc->max;
+	unsigned int mask = (1 << fls(max)) - 1;
+	unsigned int invert = mc->invert;
+	unsigned short val;
+	struct snd_soc_dapm_update update = {};
+	int connect, change;
+
+	val = (ucontrol->value.integer.value[0] & mask);
+
+	mask = 0xf;
+	if (val)
+		val = mask;
+
+	connect = !!val;
+
+	if (invert)
+		val = mask - val;
+
+	mask <<= shift;
+	val <<= shift;
+
+	change = snd_soc_component_test_bits(component, reg, mask, val);
+	if (change) {
+		update.kcontrol = kcontrol;
+		update.reg = reg;
+		update.mask = mask;
+		update.val = val;
+
+		snd_soc_dapm_mixer_update_power(dapm, kcontrol, connect,
+			&update);
+	}
+
+	return change;
+}
+
+/*
+ * mic bias power on/off share the same register bits with
+ * output voltage of mic bias. when power on mic bias, we
+ * need reclaim it to voltage value.
+ * 0x0 = Powered off
+ * 0x1 = MICBIAS output is powered to 2.0V,
+ * 0x2 = MICBIAS output is powered to 2.5V
+ * 0x3 = MICBIAS output is connected to AVDD
+ */
+static int mic_bias_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* change mic bias voltage to user defined */
+		snd_soc_component_update_bits(component, MICBIAS_CTRL,
+				MICBIAS_LEVEL_MASK,
+				aic3x->micbias_vg << MICBIAS_LEVEL_SHIFT);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, MICBIAS_CTRL,
+				MICBIAS_LEVEL_MASK, 0);
+		break;
+	}
+	return 0;
+}
+
+static const char * const aic3x_left_dac_mux[] = {
+	"DAC_L1", "DAC_L3", "DAC_L2" };
+static SOC_ENUM_SINGLE_DECL(aic3x_left_dac_enum, DAC_LINE_MUX, 6,
+			    aic3x_left_dac_mux);
+
+static const char * const aic3x_right_dac_mux[] = {
+	"DAC_R1", "DAC_R3", "DAC_R2" };
+static SOC_ENUM_SINGLE_DECL(aic3x_right_dac_enum, DAC_LINE_MUX, 4,
+			    aic3x_right_dac_mux);
+
+static const char * const aic3x_left_hpcom_mux[] = {
+	"differential of HPLOUT", "constant VCM", "single-ended" };
+static SOC_ENUM_SINGLE_DECL(aic3x_left_hpcom_enum, HPLCOM_CFG, 4,
+			    aic3x_left_hpcom_mux);
+
+static const char * const aic3x_right_hpcom_mux[] = {
+	"differential of HPROUT", "constant VCM", "single-ended",
+	"differential of HPLCOM", "external feedback" };
+static SOC_ENUM_SINGLE_DECL(aic3x_right_hpcom_enum, HPRCOM_CFG, 3,
+			    aic3x_right_hpcom_mux);
+
+static const char * const aic3x_linein_mode_mux[] = {
+	"single-ended", "differential" };
+static SOC_ENUM_SINGLE_DECL(aic3x_line1l_2_l_enum, LINE1L_2_LADC_CTRL, 7,
+			    aic3x_linein_mode_mux);
+static SOC_ENUM_SINGLE_DECL(aic3x_line1l_2_r_enum, LINE1L_2_RADC_CTRL, 7,
+			    aic3x_linein_mode_mux);
+static SOC_ENUM_SINGLE_DECL(aic3x_line1r_2_l_enum, LINE1R_2_LADC_CTRL, 7,
+			    aic3x_linein_mode_mux);
+static SOC_ENUM_SINGLE_DECL(aic3x_line1r_2_r_enum, LINE1R_2_RADC_CTRL, 7,
+			    aic3x_linein_mode_mux);
+static SOC_ENUM_SINGLE_DECL(aic3x_line2l_2_ldac_enum, LINE2L_2_LADC_CTRL, 7,
+			    aic3x_linein_mode_mux);
+static SOC_ENUM_SINGLE_DECL(aic3x_line2r_2_rdac_enum, LINE2R_2_RADC_CTRL, 7,
+			    aic3x_linein_mode_mux);
+
+static const char * const aic3x_adc_hpf[] = {
+	"Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" };
+static SOC_ENUM_DOUBLE_DECL(aic3x_adc_hpf_enum, AIC3X_CODEC_DFILT_CTRL, 6, 4,
+			    aic3x_adc_hpf);
+
+static const char * const aic3x_agc_level[] = {
+	"-5.5dB", "-8dB", "-10dB", "-12dB",
+	"-14dB", "-17dB", "-20dB", "-24dB" };
+static SOC_ENUM_SINGLE_DECL(aic3x_lagc_level_enum, LAGC_CTRL_A, 4,
+			    aic3x_agc_level);
+static SOC_ENUM_SINGLE_DECL(aic3x_ragc_level_enum, RAGC_CTRL_A, 4,
+			    aic3x_agc_level);
+
+static const char * const aic3x_agc_attack[] = {
+	"8ms", "11ms", "16ms", "20ms" };
+static SOC_ENUM_SINGLE_DECL(aic3x_lagc_attack_enum, LAGC_CTRL_A, 2,
+			    aic3x_agc_attack);
+static SOC_ENUM_SINGLE_DECL(aic3x_ragc_attack_enum, RAGC_CTRL_A, 2,
+			    aic3x_agc_attack);
+
+static const char * const aic3x_agc_decay[] = {
+	"100ms", "200ms", "400ms", "500ms" };
+static SOC_ENUM_SINGLE_DECL(aic3x_lagc_decay_enum, LAGC_CTRL_A, 0,
+			    aic3x_agc_decay);
+static SOC_ENUM_SINGLE_DECL(aic3x_ragc_decay_enum, RAGC_CTRL_A, 0,
+			    aic3x_agc_decay);
+
+static const char * const aic3x_poweron_time[] = {
+	"0us", "10us", "100us", "1ms", "10ms", "50ms",
+	"100ms", "200ms", "400ms", "800ms", "2s", "4s" };
+static SOC_ENUM_SINGLE_DECL(aic3x_poweron_time_enum, HPOUT_POP_REDUCTION, 4,
+			    aic3x_poweron_time);
+
+static const char * const aic3x_rampup_step[] = { "0ms", "1ms", "2ms", "4ms" };
+static SOC_ENUM_SINGLE_DECL(aic3x_rampup_step_enum, HPOUT_POP_REDUCTION, 2,
+			    aic3x_rampup_step);
+
+/*
+ * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(dac_tlv, -6350, 50, 0);
+/* ADC PGA gain volumes. From 0 to 59.5 dB in 0.5 dB steps */
+static DECLARE_TLV_DB_SCALE(adc_tlv, 0, 50, 0);
+/*
+ * Output stage volumes. From -78.3 to 0 dB. Muted below -78.3 dB.
+ * Step size is approximately 0.5 dB over most of the scale but increasing
+ * near the very low levels.
+ * Define dB scale so that it is mostly correct for range about -55 to 0 dB
+ * but having increasing dB difference below that (and where it doesn't count
+ * so much). This setting shows -50 dB (actual is -50.3 dB) for register
+ * value 100 and -58.5 dB (actual is -78.3 dB) for register value 117.
+ */
+static DECLARE_TLV_DB_SCALE(output_stage_tlv, -5900, 50, 1);
+
+static const struct snd_kcontrol_new aic3x_snd_controls[] = {
+	/* Output */
+	SOC_DOUBLE_R_TLV("PCM Playback Volume",
+			 LDAC_VOL, RDAC_VOL, 0, 0x7f, 1, dac_tlv),
+
+	/*
+	 * Output controls that map to output mixer switches. Note these are
+	 * only for swapped L-to-R and R-to-L routes. See below stereo controls
+	 * for direct L-to-L and R-to-R routes.
+	 */
+	SOC_SINGLE_TLV("Left Line Mixer PGAR Bypass Volume",
+		       PGAR_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+	SOC_SINGLE_TLV("Left Line Mixer DACR1 Playback Volume",
+		       DACR1_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Right Line Mixer PGAL Bypass Volume",
+		       PGAL_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+	SOC_SINGLE_TLV("Right Line Mixer DACL1 Playback Volume",
+		       DACL1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Left HP Mixer PGAR Bypass Volume",
+		       PGAR_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+	SOC_SINGLE_TLV("Left HP Mixer DACR1 Playback Volume",
+		       DACR1_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Right HP Mixer PGAL Bypass Volume",
+		       PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+	SOC_SINGLE_TLV("Right HP Mixer DACL1 Playback Volume",
+		       DACL1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Left HPCOM Mixer PGAR Bypass Volume",
+		       PGAR_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+	SOC_SINGLE_TLV("Left HPCOM Mixer DACR1 Playback Volume",
+		       DACR1_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Right HPCOM Mixer PGAL Bypass Volume",
+		       PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+	SOC_SINGLE_TLV("Right HPCOM Mixer DACL1 Playback Volume",
+		       DACL1_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+	/* Stereo output controls for direct L-to-L and R-to-R routes */
+	SOC_DOUBLE_R_TLV("Line PGA Bypass Volume",
+			 PGAL_2_LLOPM_VOL, PGAR_2_RLOPM_VOL,
+			 0, 118, 1, output_stage_tlv),
+	SOC_DOUBLE_R_TLV("Line DAC Playback Volume",
+			 DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
+			 0, 118, 1, output_stage_tlv),
+
+	SOC_DOUBLE_R_TLV("HP PGA Bypass Volume",
+			 PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
+			 0, 118, 1, output_stage_tlv),
+	SOC_DOUBLE_R_TLV("HP DAC Playback Volume",
+			 DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL,
+			 0, 118, 1, output_stage_tlv),
+
+	SOC_DOUBLE_R_TLV("HPCOM PGA Bypass Volume",
+			 PGAL_2_HPLCOM_VOL, PGAR_2_HPRCOM_VOL,
+			 0, 118, 1, output_stage_tlv),
+	SOC_DOUBLE_R_TLV("HPCOM DAC Playback Volume",
+			 DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL,
+			 0, 118, 1, output_stage_tlv),
+
+	/* Output pin mute controls */
+	SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3,
+		     0x01, 0),
+	SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
+		     0x01, 0),
+	SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
+		     0x01, 0),
+
+	/*
+	 * Note: enable Automatic input Gain Controller with care. It can
+	 * adjust PGA to max value when ADC is on and will never go back.
+	*/
+	SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0),
+	SOC_ENUM("Left AGC Target level", aic3x_lagc_level_enum),
+	SOC_ENUM("Right AGC Target level", aic3x_ragc_level_enum),
+	SOC_ENUM("Left AGC Attack time", aic3x_lagc_attack_enum),
+	SOC_ENUM("Right AGC Attack time", aic3x_ragc_attack_enum),
+	SOC_ENUM("Left AGC Decay time", aic3x_lagc_decay_enum),
+	SOC_ENUM("Right AGC Decay time", aic3x_ragc_decay_enum),
+
+	/* De-emphasis */
+	SOC_DOUBLE("De-emphasis Switch", AIC3X_CODEC_DFILT_CTRL, 2, 0, 0x01, 0),
+
+	/* Input */
+	SOC_DOUBLE_R_TLV("PGA Capture Volume", LADC_VOL, RADC_VOL,
+			 0, 119, 0, adc_tlv),
+	SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1),
+
+	SOC_ENUM("ADC HPF Cut-off", aic3x_adc_hpf_enum),
+
+	/* Pop reduction */
+	SOC_ENUM("Output Driver Power-On time", aic3x_poweron_time_enum),
+	SOC_ENUM("Output Driver Ramp-up step", aic3x_rampup_step_enum),
+};
+
+/* For other than tlv320aic3104 */
+static const struct snd_kcontrol_new aic3x_extra_snd_controls[] = {
+	/*
+	 * Output controls that map to output mixer switches. Note these are
+	 * only for swapped L-to-R and R-to-L routes. See below stereo controls
+	 * for direct L-to-L and R-to-R routes.
+	 */
+	SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume",
+		       LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume",
+		       LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume",
+		       LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume",
+		       LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume",
+		       LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume",
+		       LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+	/* Stereo output controls for direct L-to-L and R-to-R routes */
+	SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume",
+			 LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL,
+			 0, 118, 1, output_stage_tlv),
+
+	SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
+			 LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
+			 0, 118, 1, output_stage_tlv),
+
+	SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume",
+			 LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
+			 0, 118, 1, output_stage_tlv),
+};
+
+static const struct snd_kcontrol_new aic3x_mono_controls[] = {
+	SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
+			 LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
+			 0, 118, 1, output_stage_tlv),
+	SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume",
+			 PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
+			 0, 118, 1, output_stage_tlv),
+	SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
+			 DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
+			 0, 118, 1, output_stage_tlv),
+
+	SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
+};
+
+/*
+ * Class-D amplifier gain. From 0 to 18 dB in 6 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl =
+	SOC_DOUBLE_TLV("Class-D Playback Volume", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
+
+/* Left DAC Mux */
+static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_left_dac_enum);
+
+/* Right DAC Mux */
+static const struct snd_kcontrol_new aic3x_right_dac_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_right_dac_enum);
+
+/* Left HPCOM Mux */
+static const struct snd_kcontrol_new aic3x_left_hpcom_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_left_hpcom_enum);
+
+/* Right HPCOM Mux */
+static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_right_hpcom_enum);
+
+/* Left Line Mixer */
+static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
+	/* Not on tlv320aic3104 */
+	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
+};
+
+/* Right Line Mixer */
+static const struct snd_kcontrol_new aic3x_right_line_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
+	/* Not on tlv320aic3104 */
+	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new aic3x_mono_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
+};
+
+/* Left HP Mixer */
+static const struct snd_kcontrol_new aic3x_left_hp_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLOUT_VOL, 7, 1, 0),
+	/* Not on tlv320aic3104 */
+	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0),
+};
+
+/* Right HP Mixer */
+static const struct snd_kcontrol_new aic3x_right_hp_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPROUT_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
+	/* Not on tlv320aic3104 */
+	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
+};
+
+/* Left HPCOM Mixer */
+static const struct snd_kcontrol_new aic3x_left_hpcom_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLCOM_VOL, 7, 1, 0),
+	/* Not on tlv320aic3104 */
+	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0),
+};
+
+/* Right HPCOM Mixer */
+static const struct snd_kcontrol_new aic3x_right_hpcom_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPRCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
+	/* Not on tlv320aic3104 */
+	SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0),
+	SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
+};
+
+/* Left PGA Mixer */
+static const struct snd_kcontrol_new aic3x_left_pga_mixer_controls[] = {
+	SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Line2L Switch", LINE2L_2_LADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1),
+};
+
+/* Right PGA Mixer */
+static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = {
+	SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Line2R Switch", LINE2R_2_RADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
+};
+
+/* Left PGA Mixer for tlv320aic3104 */
+static const struct snd_kcontrol_new aic3104_left_pga_mixer_controls[] = {
+	SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Mic2L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Mic2R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1),
+};
+
+/* Right PGA Mixer for tlv320aic3104 */
+static const struct snd_kcontrol_new aic3104_right_pga_mixer_controls[] = {
+	SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Mic2L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1),
+	SOC_DAPM_SINGLE_AIC3X("Mic2R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
+};
+
+/* Left Line1 Mux */
+static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_line1l_2_l_enum);
+static const struct snd_kcontrol_new aic3x_right_line1l_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_line1l_2_r_enum);
+
+/* Right Line1 Mux */
+static const struct snd_kcontrol_new aic3x_right_line1r_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_line1r_2_r_enum);
+static const struct snd_kcontrol_new aic3x_left_line1r_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_line1r_2_l_enum);
+
+/* Left Line2 Mux */
+static const struct snd_kcontrol_new aic3x_left_line2_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_line2l_2_ldac_enum);
+
+/* Right Line2 Mux */
+static const struct snd_kcontrol_new aic3x_right_line2_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_line2r_2_rdac_enum);
+
+static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
+	/* Left DAC to Left Outputs */
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0),
+	SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0,
+			 &aic3x_left_dac_mux_controls),
+	SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0,
+			 &aic3x_left_hpcom_mux_controls),
+	SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left HP Out", HPLOUT_CTRL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left HP Com", HPLCOM_CTRL, 0, 0, NULL, 0),
+
+	/* Right DAC to Right Outputs */
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0),
+	SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0,
+			 &aic3x_right_dac_mux_controls),
+	SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0,
+			 &aic3x_right_hpcom_mux_controls),
+	SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right HP Out", HPROUT_CTRL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right HP Com", HPRCOM_CTRL, 0, 0, NULL, 0),
+
+	/* Inputs to Left ADC */
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0),
+	SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0,
+			 &aic3x_left_line1l_mux_controls),
+	SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0,
+			 &aic3x_left_line1r_mux_controls),
+
+	/* Inputs to Right ADC */
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture",
+			 LINE1R_2_RADC_CTRL, 2, 0),
+	SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0,
+			 &aic3x_right_line1l_mux_controls),
+	SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0,
+			 &aic3x_right_line1r_mux_controls),
+
+	/* Mic Bias */
+	SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0,
+			 mic_bias_event,
+			 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_OUTPUT("LLOUT"),
+	SND_SOC_DAPM_OUTPUT("RLOUT"),
+	SND_SOC_DAPM_OUTPUT("HPLOUT"),
+	SND_SOC_DAPM_OUTPUT("HPROUT"),
+	SND_SOC_DAPM_OUTPUT("HPLCOM"),
+	SND_SOC_DAPM_OUTPUT("HPRCOM"),
+
+	SND_SOC_DAPM_INPUT("LINE1L"),
+	SND_SOC_DAPM_INPUT("LINE1R"),
+
+	/*
+	 * Virtual output pin to detection block inside codec. This can be
+	 * used to keep codec bias on if gpio or detection features are needed.
+	 * Force pin on or construct a path with an input jack and mic bias
+	 * widgets.
+	 */
+	SND_SOC_DAPM_OUTPUT("Detection"),
+};
+
+/* For other than tlv320aic3104 */
+static const struct snd_soc_dapm_widget aic3x_extra_dapm_widgets[] = {
+	/* Inputs to Left ADC */
+	SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_left_pga_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_left_pga_mixer_controls)),
+	SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0,
+			 &aic3x_left_line2_mux_controls),
+
+	/* Inputs to Right ADC */
+	SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_right_pga_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_right_pga_mixer_controls)),
+	SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0,
+			 &aic3x_right_line2_mux_controls),
+
+	/*
+	 * Not a real mic bias widget but similar function. This is for dynamic
+	 * control of GPIO1 digital mic modulator clock output function when
+	 * using digital mic.
+	 */
+	SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "GPIO1 dmic modclk",
+			 AIC3X_GPIO1_REG, 4, 0xf,
+			 AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK,
+			 AIC3X_GPIO1_FUNC_DISABLED),
+
+	/*
+	 * Also similar function like mic bias. Selects digital mic with
+	 * configurable oversampling rate instead of ADC converter.
+	 */
+	SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 128",
+			 AIC3X_ASD_INTF_CTRLA, 0, 3, 1, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 64",
+			 AIC3X_ASD_INTF_CTRLA, 0, 3, 2, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32",
+			 AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0),
+
+	/* Output mixers */
+	SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_left_line_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_left_line_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_right_line_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_right_line_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_left_hp_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_left_hp_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_right_hp_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_right_hp_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Left HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_left_hpcom_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_left_hpcom_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Right HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_right_hpcom_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_right_hpcom_mixer_controls)),
+
+	SND_SOC_DAPM_INPUT("MIC3L"),
+	SND_SOC_DAPM_INPUT("MIC3R"),
+	SND_SOC_DAPM_INPUT("LINE2L"),
+	SND_SOC_DAPM_INPUT("LINE2R"),
+};
+
+/* For tlv320aic3104 */
+static const struct snd_soc_dapm_widget aic3104_extra_dapm_widgets[] = {
+	/* Inputs to Left ADC */
+	SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3104_left_pga_mixer_controls[0],
+			   ARRAY_SIZE(aic3104_left_pga_mixer_controls)),
+
+	/* Inputs to Right ADC */
+	SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3104_right_pga_mixer_controls[0],
+			   ARRAY_SIZE(aic3104_right_pga_mixer_controls)),
+
+	/* Output mixers */
+	SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_left_line_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_left_line_mixer_controls) - 2),
+	SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_right_line_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_right_line_mixer_controls) - 2),
+	SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_left_hp_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_left_hp_mixer_controls) - 2),
+	SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_right_hp_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_right_hp_mixer_controls) - 2),
+	SND_SOC_DAPM_MIXER("Left HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_left_hpcom_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_left_hpcom_mixer_controls) - 2),
+	SND_SOC_DAPM_MIXER("Right HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_right_hpcom_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_right_hpcom_mixer_controls) - 2),
+
+	SND_SOC_DAPM_INPUT("MIC2L"),
+	SND_SOC_DAPM_INPUT("MIC2R"),
+};
+
+static const struct snd_soc_dapm_widget aic3x_dapm_mono_widgets[] = {
+	/* Mono Output */
+	SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
+			   &aic3x_mono_mixer_controls[0],
+			   ARRAY_SIZE(aic3x_mono_mixer_controls)),
+
+	SND_SOC_DAPM_OUTPUT("MONO_LOUT"),
+};
+
+static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = {
+	/* Class-D outputs */
+	SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Class-D Out", CLASSD_CTRL, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("SPOP"),
+	SND_SOC_DAPM_OUTPUT("SPOM"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	/* Left Input */
+	{"Left Line1L Mux", "single-ended", "LINE1L"},
+	{"Left Line1L Mux", "differential", "LINE1L"},
+	{"Left Line1R Mux", "single-ended", "LINE1R"},
+	{"Left Line1R Mux", "differential", "LINE1R"},
+
+	{"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"},
+	{"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"},
+
+	{"Left ADC", NULL, "Left PGA Mixer"},
+
+	/* Right Input */
+	{"Right Line1R Mux", "single-ended", "LINE1R"},
+	{"Right Line1R Mux", "differential", "LINE1R"},
+	{"Right Line1L Mux", "single-ended", "LINE1L"},
+	{"Right Line1L Mux", "differential", "LINE1L"},
+
+	{"Right PGA Mixer", "Line1L Switch", "Right Line1L Mux"},
+	{"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"},
+
+	{"Right ADC", NULL, "Right PGA Mixer"},
+
+	/* Left DAC Output */
+	{"Left DAC Mux", "DAC_L1", "Left DAC"},
+	{"Left DAC Mux", "DAC_L2", "Left DAC"},
+	{"Left DAC Mux", "DAC_L3", "Left DAC"},
+
+	/* Right DAC Output */
+	{"Right DAC Mux", "DAC_R1", "Right DAC"},
+	{"Right DAC Mux", "DAC_R2", "Right DAC"},
+	{"Right DAC Mux", "DAC_R3", "Right DAC"},
+
+	/* Left Line Output */
+	{"Left Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+	{"Left Line Mixer", "DACL1 Switch", "Left DAC Mux"},
+	{"Left Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+	{"Left Line Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+	{"Left Line Out", NULL, "Left Line Mixer"},
+	{"Left Line Out", NULL, "Left DAC Mux"},
+	{"LLOUT", NULL, "Left Line Out"},
+
+	/* Right Line Output */
+	{"Right Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+	{"Right Line Mixer", "DACL1 Switch", "Left DAC Mux"},
+	{"Right Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+	{"Right Line Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+	{"Right Line Out", NULL, "Right Line Mixer"},
+	{"Right Line Out", NULL, "Right DAC Mux"},
+	{"RLOUT", NULL, "Right Line Out"},
+
+	/* Left HP Output */
+	{"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+	{"Left HP Mixer", "DACL1 Switch", "Left DAC Mux"},
+	{"Left HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+	{"Left HP Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+	{"Left HP Out", NULL, "Left HP Mixer"},
+	{"Left HP Out", NULL, "Left DAC Mux"},
+	{"HPLOUT", NULL, "Left HP Out"},
+
+	/* Right HP Output */
+	{"Right HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+	{"Right HP Mixer", "DACL1 Switch", "Left DAC Mux"},
+	{"Right HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+	{"Right HP Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+	{"Right HP Out", NULL, "Right HP Mixer"},
+	{"Right HP Out", NULL, "Right DAC Mux"},
+	{"HPROUT", NULL, "Right HP Out"},
+
+	/* Left HPCOM Output */
+	{"Left HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+	{"Left HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
+	{"Left HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+	{"Left HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+	{"Left HPCOM Mux", "differential of HPLOUT", "Left HP Mixer"},
+	{"Left HPCOM Mux", "constant VCM", "Left HPCOM Mixer"},
+	{"Left HPCOM Mux", "single-ended", "Left HPCOM Mixer"},
+	{"Left HP Com", NULL, "Left HPCOM Mux"},
+	{"HPLCOM", NULL, "Left HP Com"},
+
+	/* Right HPCOM Output */
+	{"Right HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+	{"Right HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
+	{"Right HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+	{"Right HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+	{"Right HPCOM Mux", "differential of HPROUT", "Right HP Mixer"},
+	{"Right HPCOM Mux", "constant VCM", "Right HPCOM Mixer"},
+	{"Right HPCOM Mux", "single-ended", "Right HPCOM Mixer"},
+	{"Right HPCOM Mux", "differential of HPLCOM", "Left HPCOM Mixer"},
+	{"Right HPCOM Mux", "external feedback", "Right HPCOM Mixer"},
+	{"Right HP Com", NULL, "Right HPCOM Mux"},
+	{"HPRCOM", NULL, "Right HP Com"},
+};
+
+/* For other than tlv320aic3104 */
+static const struct snd_soc_dapm_route intercon_extra[] = {
+	/* Left Input */
+	{"Left Line2L Mux", "single-ended", "LINE2L"},
+	{"Left Line2L Mux", "differential", "LINE2L"},
+
+	{"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"},
+	{"Left PGA Mixer", "Mic3L Switch", "MIC3L"},
+	{"Left PGA Mixer", "Mic3R Switch", "MIC3R"},
+
+	{"Left ADC", NULL, "GPIO1 dmic modclk"},
+
+	/* Right Input */
+	{"Right Line2R Mux", "single-ended", "LINE2R"},
+	{"Right Line2R Mux", "differential", "LINE2R"},
+
+	{"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"},
+	{"Right PGA Mixer", "Mic3L Switch", "MIC3L"},
+	{"Right PGA Mixer", "Mic3R Switch", "MIC3R"},
+
+	{"Right ADC", NULL, "GPIO1 dmic modclk"},
+
+	/*
+	 * Logical path between digital mic enable and GPIO1 modulator clock
+	 * output function
+	 */
+	{"GPIO1 dmic modclk", NULL, "DMic Rate 128"},
+	{"GPIO1 dmic modclk", NULL, "DMic Rate 64"},
+	{"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
+
+	/* Left Line Output */
+	{"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+	{"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+	/* Right Line Output */
+	{"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+	{"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+	/* Left HP Output */
+	{"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+	{"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+	/* Right HP Output */
+	{"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+	{"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+	/* Left HPCOM Output */
+	{"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+	{"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+	/* Right HPCOM Output */
+	{"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+	{"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+};
+
+/* For tlv320aic3104 */
+static const struct snd_soc_dapm_route intercon_extra_3104[] = {
+	/* Left Input */
+	{"Left PGA Mixer", "Mic2L Switch", "MIC2L"},
+	{"Left PGA Mixer", "Mic2R Switch", "MIC2R"},
+
+	/* Right Input */
+	{"Right PGA Mixer", "Mic2L Switch", "MIC2L"},
+	{"Right PGA Mixer", "Mic2R Switch", "MIC2R"},
+};
+
+static const struct snd_soc_dapm_route intercon_mono[] = {
+	/* Mono Output */
+	{"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+	{"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+	{"Mono Mixer", "DACL1 Switch", "Left DAC Mux"},
+	{"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+	{"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+	{"Mono Mixer", "DACR1 Switch", "Right DAC Mux"},
+	{"Mono Out", NULL, "Mono Mixer"},
+	{"MONO_LOUT", NULL, "Mono Out"},
+};
+
+static const struct snd_soc_dapm_route intercon_3007[] = {
+	/* Class-D outputs */
+	{"Left Class-D Out", NULL, "Left Line Out"},
+	{"Right Class-D Out", NULL, "Left Line Out"},
+	{"SPOP", NULL, "Left Class-D Out"},
+	{"SPOM", NULL, "Right Class-D Out"},
+};
+
+static int aic3x_add_widgets(struct snd_soc_component *component)
+{
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	switch (aic3x->model) {
+	case AIC3X_MODEL_3X:
+	case AIC3X_MODEL_33:
+		snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets,
+					  ARRAY_SIZE(aic3x_extra_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm, intercon_extra,
+					ARRAY_SIZE(intercon_extra));
+		snd_soc_dapm_new_controls(dapm, aic3x_dapm_mono_widgets,
+			ARRAY_SIZE(aic3x_dapm_mono_widgets));
+		snd_soc_dapm_add_routes(dapm, intercon_mono,
+					ARRAY_SIZE(intercon_mono));
+		break;
+	case AIC3X_MODEL_3007:
+		snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets,
+					  ARRAY_SIZE(aic3x_extra_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm, intercon_extra,
+					ARRAY_SIZE(intercon_extra));
+		snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets,
+			ARRAY_SIZE(aic3007_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm, intercon_3007,
+					ARRAY_SIZE(intercon_3007));
+		break;
+	case AIC3X_MODEL_3104:
+		snd_soc_dapm_new_controls(dapm, aic3104_extra_dapm_widgets,
+				ARRAY_SIZE(aic3104_extra_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm, intercon_extra_3104,
+				ARRAY_SIZE(intercon_extra_3104));
+		break;
+	}
+
+	return 0;
+}
+
+static int aic3x_hw_params(struct snd_pcm_substream *substream,
+			   struct snd_pcm_hw_params *params,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
+	int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
+	u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
+	u16 d, pll_d = 1;
+	int clk;
+	int width = aic3x->slot_width;
+
+	if (!width)
+		width = params_width(params);
+
+	/* select data word length */
+	data = snd_soc_component_read32(component, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
+	switch (width) {
+	case 16:
+		break;
+	case 20:
+		data |= (0x01 << 4);
+		break;
+	case 24:
+		data |= (0x02 << 4);
+		break;
+	case 32:
+		data |= (0x03 << 4);
+		break;
+	}
+	snd_soc_component_write(component, AIC3X_ASD_INTF_CTRLB, data);
+
+	/* Fsref can be 44100 or 48000 */
+	fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
+
+	/* Try to find a value for Q which allows us to bypass the PLL and
+	 * generate CODEC_CLK directly. */
+	for (pll_q = 2; pll_q < 18; pll_q++)
+		if (aic3x->sysclk / (128 * pll_q) == fsref) {
+			bypass_pll = 1;
+			break;
+		}
+
+	if (bypass_pll) {
+		pll_q &= 0xf;
+		snd_soc_component_write(component, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
+		snd_soc_component_write(component, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
+		/* disable PLL if it is bypassed */
+		snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG, PLL_ENABLE, 0);
+
+	} else {
+		snd_soc_component_write(component, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
+		/* enable PLL when it is used */
+		snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG,
+				    PLL_ENABLE, PLL_ENABLE);
+	}
+
+	/* Route Left DAC to left channel input and
+	 * right DAC to right channel input */
+	data = (LDAC2LCH | RDAC2RCH);
+	data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
+	if (params_rate(params) >= 64000)
+		data |= DUAL_RATE_MODE;
+	snd_soc_component_write(component, AIC3X_CODEC_DATAPATH_REG, data);
+
+	/* codec sample rate select */
+	data = (fsref * 20) / params_rate(params);
+	if (params_rate(params) < 64000)
+		data /= 2;
+	data /= 5;
+	data -= 2;
+	data |= (data << 4);
+	snd_soc_component_write(component, AIC3X_SAMPLE_RATE_SEL_REG, data);
+
+	if (bypass_pll)
+		return 0;
+
+	/* Use PLL, compute appropriate setup for j, d, r and p, the closest
+	 * one wins the game. Try with d==0 first, next with d!=0.
+	 * Constraints for j are according to the datasheet.
+	 * The sysclk is divided by 1000 to prevent integer overflows.
+	 */
+
+	codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000);
+
+	for (r = 1; r <= 16; r++)
+		for (p = 1; p <= 8; p++) {
+			for (j = 4; j <= 55; j++) {
+				/* This is actually 1000*((j+(d/10000))*r)/p
+				 * The term had to be converted to get
+				 * rid of the division by 10000; d = 0 here
+				 */
+				int tmp_clk = (1000 * j * r) / p;
+
+				/* Check whether this values get closer than
+				 * the best ones we had before
+				 */
+				if (abs(codec_clk - tmp_clk) <
+					abs(codec_clk - last_clk)) {
+					pll_j = j; pll_d = 0;
+					pll_r = r; pll_p = p;
+					last_clk = tmp_clk;
+				}
+
+				/* Early exit for exact matches */
+				if (tmp_clk == codec_clk)
+					goto found;
+			}
+		}
+
+	/* try with d != 0 */
+	for (p = 1; p <= 8; p++) {
+		j = codec_clk * p / 1000;
+
+		if (j < 4 || j > 11)
+			continue;
+
+		/* do not use codec_clk here since we'd loose precision */
+		d = ((2048 * p * fsref) - j * aic3x->sysclk)
+			* 100 / (aic3x->sysclk/100);
+
+		clk = (10000 * j + d) / (10 * p);
+
+		/* check whether this values get closer than the best
+		 * ones we had before */
+		if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) {
+			pll_j = j; pll_d = d; pll_r = 1; pll_p = p;
+			last_clk = clk;
+		}
+
+		/* Early exit for exact matches */
+		if (clk == codec_clk)
+			goto found;
+	}
+
+	if (last_clk == 0) {
+		printk(KERN_ERR "%s(): unable to setup PLL\n", __func__);
+		return -EINVAL;
+	}
+
+found:
+	snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG, PLLP_MASK, pll_p);
+	snd_soc_component_write(component, AIC3X_OVRF_STATUS_AND_PLLR_REG,
+		      pll_r << PLLR_SHIFT);
+	snd_soc_component_write(component, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
+	snd_soc_component_write(component, AIC3X_PLL_PROGC_REG,
+		      (pll_d >> 6) << PLLD_MSB_SHIFT);
+	snd_soc_component_write(component, AIC3X_PLL_PROGD_REG,
+		      (pll_d & 0x3F) << PLLD_LSB_SHIFT);
+
+	return 0;
+}
+
+static int aic3x_prepare(struct snd_pcm_substream *substream,
+			 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
+	int delay = 0;
+	int width = aic3x->slot_width;
+
+	if (!width)
+		width = substream->runtime->sample_bits;
+
+	/* TDM slot selection only valid in DSP_A/_B mode */
+	if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_A)
+		delay += (aic3x->tdm_delay*width + 1);
+	else if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_B)
+		delay += aic3x->tdm_delay*width;
+
+	/* Configure data delay */
+	snd_soc_component_write(component, AIC3X_ASD_INTF_CTRLC, delay);
+
+	return 0;
+}
+
+static int aic3x_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 ldac_reg = snd_soc_component_read32(component, LDAC_VOL) & ~MUTE_ON;
+	u8 rdac_reg = snd_soc_component_read32(component, RDAC_VOL) & ~MUTE_ON;
+
+	if (mute) {
+		snd_soc_component_write(component, LDAC_VOL, ldac_reg | MUTE_ON);
+		snd_soc_component_write(component, RDAC_VOL, rdac_reg | MUTE_ON);
+	} else {
+		snd_soc_component_write(component, LDAC_VOL, ldac_reg);
+		snd_soc_component_write(component, RDAC_VOL, rdac_reg);
+	}
+
+	return 0;
+}
+
+static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
+
+	/* set clock on MCLK or GPIO2 or BCLK */
+	snd_soc_component_update_bits(component, AIC3X_CLKGEN_CTRL_REG, PLLCLK_IN_MASK,
+				clk_id << PLLCLK_IN_SHIFT);
+	snd_soc_component_update_bits(component, AIC3X_CLKGEN_CTRL_REG, CLKDIV_IN_MASK,
+				clk_id << CLKDIV_IN_SHIFT);
+
+	aic3x->sysclk = freq;
+	return 0;
+}
+
+static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			     unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
+	u8 iface_areg, iface_breg;
+
+	iface_areg = snd_soc_component_read32(component, AIC3X_ASD_INTF_CTRLA) & 0x3f;
+	iface_breg = snd_soc_component_read32(component, AIC3X_ASD_INTF_CTRLB) & 0x3f;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aic3x->master = 1;
+		iface_areg |= BIT_CLK_MASTER | WORD_CLK_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		aic3x->master = 0;
+		iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * match both interface format and signal polarities since they
+	 * are fixed
+	 */
+	switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
+		       SND_SOC_DAIFMT_INV_MASK)) {
+	case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
+		break;
+	case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF):
+	case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF):
+		iface_breg |= (0x01 << 6);
+		break;
+	case (SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_NB_NF):
+		iface_breg |= (0x02 << 6);
+		break;
+	case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF):
+		iface_breg |= (0x03 << 6);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	aic3x->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+	/* set iface */
+	snd_soc_component_write(component, AIC3X_ASD_INTF_CTRLA, iface_areg);
+	snd_soc_component_write(component, AIC3X_ASD_INTF_CTRLB, iface_breg);
+
+	return 0;
+}
+
+static int aic3x_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
+				  unsigned int tx_mask, unsigned int rx_mask,
+				  int slots, int slot_width)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
+	unsigned int lsb;
+
+	if (tx_mask != rx_mask) {
+		dev_err(component->dev, "tx and rx masks must be symmetric\n");
+		return -EINVAL;
+	}
+
+	if (unlikely(!tx_mask)) {
+		dev_err(component->dev, "tx and rx masks need to be non 0\n");
+		return -EINVAL;
+	}
+
+	/* TDM based on DSP mode requires slots to be adjacent */
+	lsb = __ffs(tx_mask);
+	if ((lsb + 1) != __fls(tx_mask)) {
+		dev_err(component->dev, "Invalid mask, slots must be adjacent\n");
+		return -EINVAL;
+	}
+
+	switch (slot_width) {
+	case 16:
+	case 20:
+	case 24:
+	case 32:
+		break;
+	default:
+		dev_err(component->dev, "Unsupported slot width %d\n", slot_width);
+		return -EINVAL;
+	}
+
+
+	aic3x->tdm_delay = lsb;
+	aic3x->slot_width = slot_width;
+
+	/* DOUT in high-impedance on inactive bit clocks */
+	snd_soc_component_update_bits(component, AIC3X_ASD_INTF_CTRLA,
+			    DOUT_TRISTATE, DOUT_TRISTATE);
+
+	return 0;
+}
+
+static int aic3x_regulator_event(struct notifier_block *nb,
+				 unsigned long event, void *data)
+{
+	struct aic3x_disable_nb *disable_nb =
+		container_of(nb, struct aic3x_disable_nb, nb);
+	struct aic3x_priv *aic3x = disable_nb->aic3x;
+
+	if (event & REGULATOR_EVENT_DISABLE) {
+		/*
+		 * Put codec to reset and require cache sync as at least one
+		 * of the supplies was disabled
+		 */
+		if (gpio_is_valid(aic3x->gpio_reset))
+			gpio_set_value(aic3x->gpio_reset, 0);
+		regcache_mark_dirty(aic3x->regmap);
+	}
+
+	return 0;
+}
+
+static int aic3x_set_power(struct snd_soc_component *component, int power)
+{
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
+	unsigned int pll_c, pll_d;
+	int ret;
+
+	if (power) {
+		ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
+					    aic3x->supplies);
+		if (ret)
+			goto out;
+		aic3x->power = 1;
+
+		if (gpio_is_valid(aic3x->gpio_reset)) {
+			udelay(1);
+			gpio_set_value(aic3x->gpio_reset, 1);
+		}
+
+		/* Sync reg_cache with the hardware */
+		regcache_cache_only(aic3x->regmap, false);
+		regcache_sync(aic3x->regmap);
+
+		/* Rewrite paired PLL D registers in case cached sync skipped
+		 * writing one of them and thus caused other one also not
+		 * being written
+		 */
+		pll_c = snd_soc_component_read32(component, AIC3X_PLL_PROGC_REG);
+		pll_d = snd_soc_component_read32(component, AIC3X_PLL_PROGD_REG);
+		if (pll_c == aic3x_reg[AIC3X_PLL_PROGC_REG].def ||
+			pll_d == aic3x_reg[AIC3X_PLL_PROGD_REG].def) {
+			snd_soc_component_write(component, AIC3X_PLL_PROGC_REG, pll_c);
+			snd_soc_component_write(component, AIC3X_PLL_PROGD_REG, pll_d);
+		}
+
+		/*
+		 * Delay is needed to reduce pop-noise after syncing back the
+		 * registers
+		 */
+		mdelay(50);
+	} else {
+		/*
+		 * Do soft reset to this codec instance in order to clear
+		 * possible VDD leakage currents in case the supply regulators
+		 * remain on
+		 */
+		snd_soc_component_write(component, AIC3X_RESET, SOFT_RESET);
+		regcache_mark_dirty(aic3x->regmap);
+		aic3x->power = 0;
+		/* HW writes are needless when bias is off */
+		regcache_cache_only(aic3x->regmap, true);
+		ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies),
+					     aic3x->supplies);
+	}
+out:
+	return ret;
+}
+
+static int aic3x_set_bias_level(struct snd_soc_component *component,
+				enum snd_soc_bias_level level)
+{
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY &&
+		    aic3x->master) {
+			/* enable pll */
+			snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG,
+					    PLL_ENABLE, PLL_ENABLE);
+		}
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (!aic3x->power)
+			aic3x_set_power(component, 1);
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE &&
+		    aic3x->master) {
+			/* disable pll */
+			snd_soc_component_update_bits(component, AIC3X_PLL_PROGA_REG,
+					    PLL_ENABLE, 0);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		if (aic3x->power)
+			aic3x_set_power(component, 0);
+		break;
+	}
+
+	return 0;
+}
+
+#define AIC3X_RATES	SNDRV_PCM_RATE_8000_96000
+#define AIC3X_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops aic3x_dai_ops = {
+	.hw_params	= aic3x_hw_params,
+	.prepare	= aic3x_prepare,
+	.digital_mute	= aic3x_mute,
+	.set_sysclk	= aic3x_set_dai_sysclk,
+	.set_fmt	= aic3x_set_dai_fmt,
+	.set_tdm_slot	= aic3x_set_dai_tdm_slot,
+};
+
+static struct snd_soc_dai_driver aic3x_dai = {
+	.name = "tlv320aic3x-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = AIC3X_RATES,
+		.formats = AIC3X_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = AIC3X_RATES,
+		.formats = AIC3X_FORMATS,},
+	.ops = &aic3x_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static void aic3x_mono_init(struct snd_soc_component *component)
+{
+	/* DAC to Mono Line Out default volume and route to Output mixer */
+	snd_soc_component_write(component, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+	snd_soc_component_write(component, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+
+	/* unmute all outputs */
+	snd_soc_component_update_bits(component, MONOLOPM_CTRL, UNMUTE, UNMUTE);
+
+	/* PGA to Mono Line Out default volume, disconnect from Output Mixer */
+	snd_soc_component_write(component, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
+
+	/* Line2 to Mono Out default volume, disconnect from Output Mixer */
+	snd_soc_component_write(component, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
+}
+
+/*
+ * initialise the AIC3X driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int aic3x_init(struct snd_soc_component *component)
+{
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_write(component, AIC3X_PAGE_SELECT, PAGE0_SELECT);
+	snd_soc_component_write(component, AIC3X_RESET, SOFT_RESET);
+
+	/* DAC default volume and mute */
+	snd_soc_component_write(component, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
+	snd_soc_component_write(component, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
+
+	/* DAC to HP default volume and route to Output mixer */
+	snd_soc_component_write(component, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
+	snd_soc_component_write(component, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
+	snd_soc_component_write(component, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
+	snd_soc_component_write(component, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
+	/* DAC to Line Out default volume and route to Output mixer */
+	snd_soc_component_write(component, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+	snd_soc_component_write(component, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+
+	/* unmute all outputs */
+	snd_soc_component_update_bits(component, LLOPM_CTRL, UNMUTE, UNMUTE);
+	snd_soc_component_update_bits(component, RLOPM_CTRL, UNMUTE, UNMUTE);
+	snd_soc_component_update_bits(component, HPLOUT_CTRL, UNMUTE, UNMUTE);
+	snd_soc_component_update_bits(component, HPROUT_CTRL, UNMUTE, UNMUTE);
+	snd_soc_component_update_bits(component, HPLCOM_CTRL, UNMUTE, UNMUTE);
+	snd_soc_component_update_bits(component, HPRCOM_CTRL, UNMUTE, UNMUTE);
+
+	/* ADC default volume and unmute */
+	snd_soc_component_write(component, LADC_VOL, DEFAULT_GAIN);
+	snd_soc_component_write(component, RADC_VOL, DEFAULT_GAIN);
+	/* By default route Line1 to ADC PGA mixer */
+	snd_soc_component_write(component, LINE1L_2_LADC_CTRL, 0x0);
+	snd_soc_component_write(component, LINE1R_2_RADC_CTRL, 0x0);
+
+	/* PGA to HP Bypass default volume, disconnect from Output Mixer */
+	snd_soc_component_write(component, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
+	/* PGA to Line Out default volume, disconnect from Output Mixer */
+	snd_soc_component_write(component, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
+	snd_soc_component_write(component, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
+
+	/* On tlv320aic3104, these registers are reserved and must not be written */
+	if (aic3x->model != AIC3X_MODEL_3104) {
+		/* Line2 to HP Bypass default volume, disconnect from Output Mixer */
+		snd_soc_component_write(component, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
+		snd_soc_component_write(component, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
+		snd_soc_component_write(component, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
+		snd_soc_component_write(component, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
+		/* Line2 Line Out default volume, disconnect from Output Mixer */
+		snd_soc_component_write(component, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
+		snd_soc_component_write(component, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
+	}
+
+	switch (aic3x->model) {
+	case AIC3X_MODEL_3X:
+	case AIC3X_MODEL_33:
+		aic3x_mono_init(component);
+		break;
+	case AIC3X_MODEL_3007:
+		snd_soc_component_write(component, CLASSD_CTRL, 0);
+		break;
+	}
+
+	/*  Output common-mode voltage = 1.5 V */
+	snd_soc_component_update_bits(component, HPOUT_SC, HPOUT_SC_OCMV_MASK,
+			    aic3x->ocmv << HPOUT_SC_OCMV_SHIFT);
+
+	return 0;
+}
+
+static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x)
+{
+	struct aic3x_priv *a;
+
+	list_for_each_entry(a, &reset_list, list) {
+		if (gpio_is_valid(aic3x->gpio_reset) &&
+		    aic3x->gpio_reset == a->gpio_reset)
+			return true;
+	}
+
+	return false;
+}
+
+static int aic3x_probe(struct snd_soc_component *component)
+{
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
+	int ret, i;
+
+	INIT_LIST_HEAD(&aic3x->list);
+	aic3x->component = component;
+
+	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
+		aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
+		aic3x->disable_nb[i].aic3x = aic3x;
+		ret = regulator_register_notifier(aic3x->supplies[i].consumer,
+						  &aic3x->disable_nb[i].nb);
+		if (ret) {
+			dev_err(component->dev,
+				"Failed to request regulator notifier: %d\n",
+				 ret);
+			goto err_notif;
+		}
+	}
+
+	regcache_mark_dirty(aic3x->regmap);
+	aic3x_init(component);
+
+	if (aic3x->setup) {
+		if (aic3x->model != AIC3X_MODEL_3104) {
+			/* setup GPIO functions */
+			snd_soc_component_write(component, AIC3X_GPIO1_REG,
+				      (aic3x->setup->gpio_func[0] & 0xf) << 4);
+			snd_soc_component_write(component, AIC3X_GPIO2_REG,
+				      (aic3x->setup->gpio_func[1] & 0xf) << 4);
+		} else {
+			dev_warn(component->dev, "GPIO functionality is not supported on tlv320aic3104\n");
+		}
+	}
+
+	switch (aic3x->model) {
+	case AIC3X_MODEL_3X:
+	case AIC3X_MODEL_33:
+		snd_soc_add_component_controls(component, aic3x_extra_snd_controls,
+				ARRAY_SIZE(aic3x_extra_snd_controls));
+		snd_soc_add_component_controls(component, aic3x_mono_controls,
+				ARRAY_SIZE(aic3x_mono_controls));
+		break;
+	case AIC3X_MODEL_3007:
+		snd_soc_add_component_controls(component, aic3x_extra_snd_controls,
+				ARRAY_SIZE(aic3x_extra_snd_controls));
+		snd_soc_add_component_controls(component,
+				&aic3x_classd_amp_gain_ctrl, 1);
+		break;
+	case AIC3X_MODEL_3104:
+		break;
+	}
+
+	/* set mic bias voltage */
+	switch (aic3x->micbias_vg) {
+	case AIC3X_MICBIAS_2_0V:
+	case AIC3X_MICBIAS_2_5V:
+	case AIC3X_MICBIAS_AVDDV:
+		snd_soc_component_update_bits(component, MICBIAS_CTRL,
+				    MICBIAS_LEVEL_MASK,
+				    (aic3x->micbias_vg) << MICBIAS_LEVEL_SHIFT);
+		break;
+	case AIC3X_MICBIAS_OFF:
+		/*
+		 * noting to do. target won't enter here. This is just to avoid
+		 * compile time warning "warning: enumeration value
+		 * 'AIC3X_MICBIAS_OFF' not handled in switch"
+		 */
+		break;
+	}
+
+	aic3x_add_widgets(component);
+
+	return 0;
+
+err_notif:
+	while (i--)
+		regulator_unregister_notifier(aic3x->supplies[i].consumer,
+					      &aic3x->disable_nb[i].nb);
+	return ret;
+}
+
+static void aic3x_remove(struct snd_soc_component *component)
+{
+	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
+	int i;
+
+	list_del(&aic3x->list);
+	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
+		regulator_unregister_notifier(aic3x->supplies[i].consumer,
+					      &aic3x->disable_nb[i].nb);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_aic3x = {
+	.set_bias_level		= aic3x_set_bias_level,
+	.probe			= aic3x_probe,
+	.remove			= aic3x_remove,
+	.controls		= aic3x_snd_controls,
+	.num_controls		= ARRAY_SIZE(aic3x_snd_controls),
+	.dapm_widgets		= aic3x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(aic3x_dapm_widgets),
+	.dapm_routes		= intercon,
+	.num_dapm_routes	= ARRAY_SIZE(intercon),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static void aic3x_configure_ocmv(struct i2c_client *client)
+{
+	struct device_node *np = client->dev.of_node;
+	struct aic3x_priv *aic3x = i2c_get_clientdata(client);
+	u32 value;
+	int dvdd, avdd;
+
+	if (np && !of_property_read_u32(np, "ai3x-ocmv", &value)) {
+		/* OCMV setting is forced by DT */
+		if (value <= 3) {
+			aic3x->ocmv = value;
+			return;
+		}
+	}
+
+	dvdd = regulator_get_voltage(aic3x->supplies[1].consumer);
+	avdd = regulator_get_voltage(aic3x->supplies[2].consumer);
+
+	if (avdd > 3600000 || dvdd > 1950000) {
+		dev_warn(&client->dev,
+			 "Too high supply voltage(s) AVDD: %d, DVDD: %d\n",
+			 avdd, dvdd);
+	} else if (avdd == 3600000 && dvdd == 1950000) {
+		aic3x->ocmv = HPOUT_SC_OCMV_1_8V;
+	} else if (avdd > 3300000 && dvdd > 1800000) {
+		aic3x->ocmv = HPOUT_SC_OCMV_1_65V;
+	} else if (avdd > 3000000 && dvdd > 1650000) {
+		aic3x->ocmv = HPOUT_SC_OCMV_1_5V;
+	} else if (avdd >= 2700000 && dvdd >= 1525000) {
+		aic3x->ocmv = HPOUT_SC_OCMV_1_35V;
+	} else {
+		dev_warn(&client->dev,
+			 "Invalid supply voltage(s) AVDD: %d, DVDD: %d\n",
+			 avdd, dvdd);
+	}
+}
+
+/*
+ * AIC3X 2 wire address can be up to 4 devices with device addresses
+ * 0x18, 0x19, 0x1A, 0x1B
+ */
+
+static const struct i2c_device_id aic3x_i2c_id[] = {
+	{ "tlv320aic3x", AIC3X_MODEL_3X },
+	{ "tlv320aic33", AIC3X_MODEL_33 },
+	{ "tlv320aic3007", AIC3X_MODEL_3007 },
+	{ "tlv320aic3106", AIC3X_MODEL_3X },
+	{ "tlv320aic3104", AIC3X_MODEL_3104 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
+
+static const struct reg_sequence aic3007_class_d[] = {
+	/* Class-D speaker driver init; datasheet p. 46 */
+	{ AIC3X_PAGE_SELECT, 0x0D },
+	{ 0xD, 0x0D },
+	{ 0x8, 0x5C },
+	{ 0x8, 0x5D },
+	{ 0x8, 0x5C },
+	{ AIC3X_PAGE_SELECT, 0x00 },
+};
+
+/*
+ * If the i2c layer weren't so broken, we could pass this kind of data
+ * around
+ */
+static int aic3x_i2c_probe(struct i2c_client *i2c,
+			   const struct i2c_device_id *id)
+{
+	struct aic3x_pdata *pdata = i2c->dev.platform_data;
+	struct aic3x_priv *aic3x;
+	struct aic3x_setup_data *ai3x_setup;
+	struct device_node *np = i2c->dev.of_node;
+	int ret, i;
+	u32 value;
+
+	aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL);
+	if (!aic3x)
+		return -ENOMEM;
+
+	aic3x->regmap = devm_regmap_init_i2c(i2c, &aic3x_regmap);
+	if (IS_ERR(aic3x->regmap)) {
+		ret = PTR_ERR(aic3x->regmap);
+		return ret;
+	}
+
+	regcache_cache_only(aic3x->regmap, true);
+
+	i2c_set_clientdata(i2c, aic3x);
+	if (pdata) {
+		aic3x->gpio_reset = pdata->gpio_reset;
+		aic3x->setup = pdata->setup;
+		aic3x->micbias_vg = pdata->micbias_vg;
+	} else if (np) {
+		ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup),
+								GFP_KERNEL);
+		if (!ai3x_setup)
+			return -ENOMEM;
+
+		ret = of_get_named_gpio(np, "reset-gpios", 0);
+		if (ret >= 0) {
+			aic3x->gpio_reset = ret;
+		} else {
+			ret = of_get_named_gpio(np, "gpio-reset", 0);
+			if (ret > 0) {
+				dev_warn(&i2c->dev, "Using deprecated property \"gpio-reset\", please update your DT");
+				aic3x->gpio_reset = ret;
+			} else {
+				aic3x->gpio_reset = -1;
+			}
+		}
+
+		if (of_property_read_u32_array(np, "ai3x-gpio-func",
+					ai3x_setup->gpio_func, 2) >= 0) {
+			aic3x->setup = ai3x_setup;
+		}
+
+		if (!of_property_read_u32(np, "ai3x-micbias-vg", &value)) {
+			switch (value) {
+			case 1 :
+				aic3x->micbias_vg = AIC3X_MICBIAS_2_0V;
+				break;
+			case 2 :
+				aic3x->micbias_vg = AIC3X_MICBIAS_2_5V;
+				break;
+			case 3 :
+				aic3x->micbias_vg = AIC3X_MICBIAS_AVDDV;
+				break;
+			default :
+				aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
+				dev_err(&i2c->dev, "Unsuitable MicBias voltage "
+							"found in DT\n");
+			}
+		} else {
+			aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
+		}
+
+	} else {
+		aic3x->gpio_reset = -1;
+	}
+
+	aic3x->model = id->driver_data;
+
+	if (gpio_is_valid(aic3x->gpio_reset) &&
+	    !aic3x_is_shared_reset(aic3x)) {
+		ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
+		if (ret != 0)
+			goto err;
+		gpio_direction_output(aic3x->gpio_reset, 0);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
+		aic3x->supplies[i].supply = aic3x_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(aic3x->supplies),
+				      aic3x->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		goto err_gpio;
+	}
+
+	aic3x_configure_ocmv(i2c);
+
+	if (aic3x->model == AIC3X_MODEL_3007) {
+		ret = regmap_register_patch(aic3x->regmap, aic3007_class_d,
+					    ARRAY_SIZE(aic3007_class_d));
+		if (ret != 0)
+			dev_err(&i2c->dev, "Failed to init class D: %d\n",
+				ret);
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_aic3x, &aic3x_dai, 1);
+
+	if (ret != 0)
+		goto err_gpio;
+
+	list_add(&aic3x->list, &reset_list);
+
+	return 0;
+
+err_gpio:
+	if (gpio_is_valid(aic3x->gpio_reset) &&
+	    !aic3x_is_shared_reset(aic3x))
+		gpio_free(aic3x->gpio_reset);
+err:
+	return ret;
+}
+
+static int aic3x_i2c_remove(struct i2c_client *client)
+{
+	struct aic3x_priv *aic3x = i2c_get_clientdata(client);
+
+	if (gpio_is_valid(aic3x->gpio_reset) &&
+	    !aic3x_is_shared_reset(aic3x)) {
+		gpio_set_value(aic3x->gpio_reset, 0);
+		gpio_free(aic3x->gpio_reset);
+	}
+	return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id tlv320aic3x_of_match[] = {
+	{ .compatible = "ti,tlv320aic3x", },
+	{ .compatible = "ti,tlv320aic33" },
+	{ .compatible = "ti,tlv320aic3007" },
+	{ .compatible = "ti,tlv320aic3106" },
+	{ .compatible = "ti,tlv320aic3104" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match);
+#endif
+
+/* machine i2c codec control layer */
+static struct i2c_driver aic3x_i2c_driver = {
+	.driver = {
+		.name = "tlv320aic3x-codec",
+		.of_match_table = of_match_ptr(tlv320aic3x_of_match),
+	},
+	.probe	= aic3x_i2c_probe,
+	.remove = aic3x_i2c_remove,
+	.id_table = aic3x_i2c_id,
+};
+
+module_i2c_driver(aic3x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver");
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
new file mode 100644
index 0000000..34c3519
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -0,0 +1,291 @@
+/*
+ * ALSA SoC TLV320AIC3X codec driver
+ *
+ * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
+ * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _AIC3X_H
+#define _AIC3X_H
+
+/* AIC3X register space */
+#define AIC3X_CACHEREGNUM		110
+
+/* Page select register */
+#define AIC3X_PAGE_SELECT		0
+/* Software reset register */
+#define AIC3X_RESET			1
+/* Codec Sample rate select register */
+#define AIC3X_SAMPLE_RATE_SEL_REG	2
+/* PLL progrramming register A */
+#define AIC3X_PLL_PROGA_REG		3
+/* PLL progrramming register B */
+#define AIC3X_PLL_PROGB_REG		4
+/* PLL progrramming register C */
+#define AIC3X_PLL_PROGC_REG		5
+/* PLL progrramming register D */
+#define AIC3X_PLL_PROGD_REG		6
+/* Codec datapath setup register */
+#define AIC3X_CODEC_DATAPATH_REG	7
+/* Audio serial data interface control register A */
+#define AIC3X_ASD_INTF_CTRLA		8
+/* Audio serial data interface control register B */
+#define AIC3X_ASD_INTF_CTRLB		9
+/* Audio serial data interface control register C */
+#define AIC3X_ASD_INTF_CTRLC		10
+/* Audio overflow status and PLL R value programming register */
+#define AIC3X_OVRF_STATUS_AND_PLLR_REG	11
+/* Audio codec digital filter control register */
+#define AIC3X_CODEC_DFILT_CTRL		12
+/* Headset/button press detection register */
+#define AIC3X_HEADSET_DETECT_CTRL_A	13
+#define AIC3X_HEADSET_DETECT_CTRL_B	14
+/* ADC PGA Gain control registers */
+#define LADC_VOL			15
+#define RADC_VOL			16
+/* MIC3 control registers */
+#define MIC3LR_2_LADC_CTRL		17
+#define MIC3LR_2_RADC_CTRL		18
+/* Line1 Input control registers */
+#define LINE1L_2_LADC_CTRL		19
+#define LINE1R_2_LADC_CTRL		21
+#define LINE1R_2_RADC_CTRL		22
+#define LINE1L_2_RADC_CTRL		24
+/* Line2 Input control registers */
+#define LINE2L_2_LADC_CTRL		20
+#define LINE2R_2_RADC_CTRL		23
+/* MICBIAS Control Register */
+#define MICBIAS_CTRL			25
+
+/* AGC Control Registers A, B, C */
+#define LAGC_CTRL_A			26
+#define LAGC_CTRL_B			27
+#define LAGC_CTRL_C			28
+#define RAGC_CTRL_A			29
+#define RAGC_CTRL_B			30
+#define RAGC_CTRL_C			31
+
+/* DAC Power and Left High Power Output control registers */
+#define DAC_PWR				37
+#define HPLCOM_CFG			37
+/* Right High Power Output control registers */
+#define HPRCOM_CFG			38
+/* High Power Output Stage Control Register */
+#define HPOUT_SC			40
+/* DAC Output Switching control registers */
+#define DAC_LINE_MUX			41
+/* High Power Output Driver Pop Reduction registers */
+#define HPOUT_POP_REDUCTION		42
+/* DAC Digital control registers */
+#define LDAC_VOL			43
+#define RDAC_VOL			44
+/* Left High Power Output control registers */
+#define LINE2L_2_HPLOUT_VOL		45
+#define PGAL_2_HPLOUT_VOL		46
+#define DACL1_2_HPLOUT_VOL		47
+#define LINE2R_2_HPLOUT_VOL		48
+#define PGAR_2_HPLOUT_VOL		49
+#define DACR1_2_HPLOUT_VOL		50
+#define HPLOUT_CTRL			51
+/* Left High Power COM control registers */
+#define LINE2L_2_HPLCOM_VOL		52
+#define PGAL_2_HPLCOM_VOL		53
+#define DACL1_2_HPLCOM_VOL		54
+#define LINE2R_2_HPLCOM_VOL		55
+#define PGAR_2_HPLCOM_VOL		56
+#define DACR1_2_HPLCOM_VOL		57
+#define HPLCOM_CTRL			58
+/* Right High Power Output control registers */
+#define LINE2L_2_HPROUT_VOL		59
+#define PGAL_2_HPROUT_VOL		60
+#define DACL1_2_HPROUT_VOL		61
+#define LINE2R_2_HPROUT_VOL		62
+#define PGAR_2_HPROUT_VOL		63
+#define DACR1_2_HPROUT_VOL		64
+#define HPROUT_CTRL			65
+/* Right High Power COM control registers */
+#define LINE2L_2_HPRCOM_VOL		66
+#define PGAL_2_HPRCOM_VOL		67
+#define DACL1_2_HPRCOM_VOL		68
+#define LINE2R_2_HPRCOM_VOL		69
+#define PGAR_2_HPRCOM_VOL		70
+#define DACR1_2_HPRCOM_VOL		71
+#define HPRCOM_CTRL			72
+/* Mono Line Output Plus/Minus control registers */
+#define LINE2L_2_MONOLOPM_VOL		73
+#define PGAL_2_MONOLOPM_VOL		74
+#define DACL1_2_MONOLOPM_VOL		75
+#define LINE2R_2_MONOLOPM_VOL		76
+#define PGAR_2_MONOLOPM_VOL		77
+#define DACR1_2_MONOLOPM_VOL		78
+#define MONOLOPM_CTRL			79
+/* Class-D speaker driver on tlv320aic3007 */
+#define CLASSD_CTRL			73
+/* Left Line Output Plus/Minus control registers */
+#define LINE2L_2_LLOPM_VOL		80
+#define PGAL_2_LLOPM_VOL		81
+#define DACL1_2_LLOPM_VOL		82
+#define LINE2R_2_LLOPM_VOL		83
+#define PGAR_2_LLOPM_VOL		84
+#define DACR1_2_LLOPM_VOL		85
+#define LLOPM_CTRL			86
+/* Right Line Output Plus/Minus control registers */
+#define LINE2L_2_RLOPM_VOL		87
+#define PGAL_2_RLOPM_VOL		88
+#define DACL1_2_RLOPM_VOL		89
+#define LINE2R_2_RLOPM_VOL		90
+#define PGAR_2_RLOPM_VOL		91
+#define DACR1_2_RLOPM_VOL		92
+#define RLOPM_CTRL			93
+/* GPIO/IRQ registers */
+#define AIC3X_STICKY_IRQ_FLAGS_REG	96
+#define AIC3X_RT_IRQ_FLAGS_REG		97
+#define AIC3X_GPIO1_REG			98
+#define AIC3X_GPIO2_REG			99
+#define AIC3X_GPIOA_REG			100
+#define AIC3X_GPIOB_REG			101
+/* Clock generation control register */
+#define AIC3X_CLKGEN_CTRL_REG		102
+/* New AGC registers */
+#define LAGCN_ATTACK			103
+#define LAGCN_DECAY			104
+#define RAGCN_ATTACK			105
+#define RAGCN_DECAY			106
+/* New Programmable ADC Digital Path and I2C Bus Condition Register */
+#define NEW_ADC_DIGITALPATH		107
+/* Passive Analog Signal Bypass Selection During Powerdown Register */
+#define PASSIVE_BYPASS			108
+/* DAC Quiescent Current Adjustment Register */
+#define DAC_ICC_ADJ			109
+
+/* Page select register bits */
+#define PAGE0_SELECT		0
+#define PAGE1_SELECT		1
+
+/* Audio serial data interface control register A bits */
+#define BIT_CLK_MASTER          0x80
+#define WORD_CLK_MASTER         0x40
+#define DOUT_TRISTATE		0x20
+
+/* Codec Datapath setup register 7 */
+#define FSREF_44100		(1 << 7)
+#define FSREF_48000		(0 << 7)
+#define DUAL_RATE_MODE		((1 << 5) | (1 << 6))
+#define LDAC2LCH		(0x1 << 3)
+#define RDAC2RCH		(0x1 << 1)
+#define LDAC2RCH		(0x2 << 3)
+#define RDAC2LCH		(0x2 << 1)
+#define LDAC2MONOMIX		(0x3 << 3)
+#define RDAC2MONOMIX		(0x3 << 1)
+
+/* PLL registers bitfields */
+#define PLLP_SHIFT		0
+#define PLLP_MASK		7
+#define PLLQ_SHIFT		3
+#define PLLR_SHIFT		0
+#define PLLJ_SHIFT		2
+#define PLLD_MSB_SHIFT		0
+#define PLLD_LSB_SHIFT		2
+
+/* Clock generation register bits */
+#define CODEC_CLKIN_PLLDIV	0
+#define CODEC_CLKIN_CLKDIV	1
+#define PLL_CLKIN_SHIFT		4
+#define MCLK_SOURCE		0x0
+#define PLL_CLKDIV_SHIFT	0
+#define PLLCLK_IN_MASK		0x30
+#define PLLCLK_IN_SHIFT		4
+#define CLKDIV_IN_MASK		0xc0
+#define CLKDIV_IN_SHIFT		6
+/* clock in source */
+#define CLKIN_MCLK		0
+#define CLKIN_GPIO2		1
+#define CLKIN_BCLK		2
+
+/* Software reset register bits */
+#define SOFT_RESET		0x80
+
+/* PLL progrramming register A bits */
+#define PLL_ENABLE		0x80
+
+/* Route bits */
+#define ROUTE_ON		0x80
+
+/* Mute bits */
+#define UNMUTE			0x08
+#define MUTE_ON			0x80
+
+/* Power bits */
+#define LADC_PWR_ON		0x04
+#define RADC_PWR_ON		0x04
+#define LDAC_PWR_ON		0x80
+#define RDAC_PWR_ON		0x40
+#define HPLOUT_PWR_ON		0x01
+#define HPROUT_PWR_ON		0x01
+#define HPLCOM_PWR_ON		0x01
+#define HPRCOM_PWR_ON		0x01
+#define MONOLOPM_PWR_ON		0x01
+#define LLOPM_PWR_ON		0x01
+#define RLOPM_PWR_ON	0x01
+
+#define INVERT_VOL(val)   (0x7f - val)
+
+/* Default output volume (inverted) */
+#define DEFAULT_VOL     INVERT_VOL(0x50)
+/* Default input volume */
+#define DEFAULT_GAIN    0x20
+
+/* MICBIAS Control Register */
+#define MICBIAS_LEVEL_SHIFT	(6)
+#define MICBIAS_LEVEL_MASK	(3 << 6)
+
+/* HPOUT_SC */
+#define HPOUT_SC_OCMV_MASK	(3 << 6)
+#define HPOUT_SC_OCMV_SHIFT	(6)
+#define HPOUT_SC_OCMV_1_35V	0
+#define HPOUT_SC_OCMV_1_5V	1
+#define HPOUT_SC_OCMV_1_65V	2
+#define HPOUT_SC_OCMV_1_8V	3
+
+/* headset detection / button API */
+
+/* The AIC3x supports detection of stereo headsets (GND + left + right signal)
+ * and cellular headsets (GND + speaker output + microphone input).
+ * It is recommended to enable MIC bias for this function to work properly.
+ * For more information, please refer to the datasheet. */
+enum {
+	AIC3X_HEADSET_DETECT_OFF	= 0,
+	AIC3X_HEADSET_DETECT_STEREO	= 1,
+	AIC3X_HEADSET_DETECT_CELLULAR   = 2,
+	AIC3X_HEADSET_DETECT_BOTH	= 3
+};
+
+enum {
+	AIC3X_HEADSET_DEBOUNCE_16MS	= 0,
+	AIC3X_HEADSET_DEBOUNCE_32MS	= 1,
+	AIC3X_HEADSET_DEBOUNCE_64MS	= 2,
+	AIC3X_HEADSET_DEBOUNCE_128MS	= 3,
+	AIC3X_HEADSET_DEBOUNCE_256MS	= 4,
+	AIC3X_HEADSET_DEBOUNCE_512MS	= 5
+};
+
+enum {
+	AIC3X_BUTTON_DEBOUNCE_0MS	= 0,
+	AIC3X_BUTTON_DEBOUNCE_8MS	= 1,
+	AIC3X_BUTTON_DEBOUNCE_16MS	= 2,
+	AIC3X_BUTTON_DEBOUNCE_32MS	= 3
+};
+
+#define AIC3X_HEADSET_DETECT_ENABLED	0x80
+#define AIC3X_HEADSET_DETECT_SHIFT	5
+#define AIC3X_HEADSET_DETECT_MASK	3
+#define AIC3X_HEADSET_DEBOUNCE_SHIFT	2
+#define AIC3X_HEADSET_DEBOUNCE_MASK	7
+#define AIC3X_BUTTON_DEBOUNCE_SHIFT 	0
+#define AIC3X_BUTTON_DEBOUNCE_MASK	3
+
+#endif /* _AIC3X_H */
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
new file mode 100644
index 0000000..a957eae
--- /dev/null
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -0,0 +1,1592 @@
+/*
+ * ALSA SoC Texas Instruments TLV320DAC33 codec driver
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * Copyright:   (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <sound/tlv320dac33-plat.h>
+#include "tlv320dac33.h"
+
+/*
+ * The internal FIFO is 24576 bytes long
+ * It can be configured to hold 16bit or 24bit samples
+ * In 16bit configuration the FIFO can hold 6144 stereo samples
+ * In 24bit configuration the FIFO can hold 4096 stereo samples
+ */
+#define DAC33_FIFO_SIZE_16BIT	6144
+#define DAC33_FIFO_SIZE_24BIT	4096
+#define DAC33_MODE7_MARGIN	10	/* Safety margin for FIFO in Mode7 */
+
+#define BURST_BASEFREQ_HZ	49152000
+
+#define SAMPLES_TO_US(rate, samples) \
+	(1000000000 / (((rate) * 1000) / (samples)))
+
+#define US_TO_SAMPLES(rate, us) \
+	((rate) / (1000000 / ((us) < 1000000 ? (us) : 1000000)))
+
+#define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \
+	(((samples)*5000) / (((burstrate)*5000) / ((burstrate) - (playrate))))
+
+static void dac33_calculate_times(struct snd_pcm_substream *substream,
+				  struct snd_soc_component *component);
+static int dac33_prepare_chip(struct snd_pcm_substream *substream,
+			      struct snd_soc_component *component);
+
+enum dac33_state {
+	DAC33_IDLE = 0,
+	DAC33_PREFILL,
+	DAC33_PLAYBACK,
+	DAC33_FLUSH,
+};
+
+enum dac33_fifo_modes {
+	DAC33_FIFO_BYPASS = 0,
+	DAC33_FIFO_MODE1,
+	DAC33_FIFO_MODE7,
+	DAC33_FIFO_LAST_MODE,
+};
+
+#define DAC33_NUM_SUPPLIES 3
+static const char *dac33_supply_names[DAC33_NUM_SUPPLIES] = {
+	"AVDD",
+	"DVDD",
+	"IOVDD",
+};
+
+struct tlv320dac33_priv {
+	struct mutex mutex;
+	struct work_struct work;
+	struct snd_soc_component *component;
+	struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
+	struct snd_pcm_substream *substream;
+	int power_gpio;
+	int chip_power;
+	int irq;
+	unsigned int refclk;
+
+	unsigned int alarm_threshold;	/* set to be half of LATENCY_TIME_MS */
+	enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */
+	unsigned int fifo_size;		/* Size of the FIFO in samples */
+	unsigned int nsample;		/* burst read amount from host */
+	int mode1_latency;		/* latency caused by the i2c writes in
+					 * us */
+	u8 burst_bclkdiv;		/* BCLK divider value in burst mode */
+	u8 *reg_cache;
+	unsigned int burst_rate;	/* Interface speed in Burst modes */
+
+	int keep_bclk;			/* Keep the BCLK continuously running
+					 * in FIFO modes */
+	spinlock_t lock;
+	unsigned long long t_stamp1;	/* Time stamp for FIFO modes to */
+	unsigned long long t_stamp2;	/* calculate the FIFO caused delay */
+
+	unsigned int mode1_us_burst;	/* Time to burst read n number of
+					 * samples */
+	unsigned int mode7_us_to_lthr;	/* Time to reach lthr from uthr */
+
+	unsigned int uthr;
+
+	enum dac33_state state;
+	struct i2c_client *i2c;
+};
+
+static const u8 dac33_reg[DAC33_CACHEREGNUM] = {
+0x00, 0x00, 0x00, 0x00, /* 0x00 - 0x03 */
+0x00, 0x00, 0x00, 0x00, /* 0x04 - 0x07 */
+0x00, 0x00, 0x00, 0x00, /* 0x08 - 0x0b */
+0x00, 0x00, 0x00, 0x00, /* 0x0c - 0x0f */
+0x00, 0x00, 0x00, 0x00, /* 0x10 - 0x13 */
+0x00, 0x00, 0x00, 0x00, /* 0x14 - 0x17 */
+0x00, 0x00, 0x00, 0x00, /* 0x18 - 0x1b */
+0x00, 0x00, 0x00, 0x00, /* 0x1c - 0x1f */
+0x00, 0x00, 0x00, 0x00, /* 0x20 - 0x23 */
+0x00, 0x00, 0x00, 0x00, /* 0x24 - 0x27 */
+0x00, 0x00, 0x00, 0x00, /* 0x28 - 0x2b */
+0x00, 0x00, 0x00, 0x80, /* 0x2c - 0x2f */
+0x80, 0x00, 0x00, 0x00, /* 0x30 - 0x33 */
+0x00, 0x00, 0x00, 0x00, /* 0x34 - 0x37 */
+0x00, 0x00,             /* 0x38 - 0x39 */
+/* Registers 0x3a - 0x3f are reserved  */
+            0x00, 0x00, /* 0x3a - 0x3b */
+0x00, 0x00, 0x00, 0x00, /* 0x3c - 0x3f */
+
+0x00, 0x00, 0x00, 0x00, /* 0x40 - 0x43 */
+0x00, 0x80,             /* 0x44 - 0x45 */
+/* Registers 0x46 - 0x47 are reserved  */
+            0x80, 0x80, /* 0x46 - 0x47 */
+
+0x80, 0x00, 0x00,       /* 0x48 - 0x4a */
+/* Registers 0x4b - 0x7c are reserved  */
+                  0x00, /* 0x4b        */
+0x00, 0x00, 0x00, 0x00, /* 0x4c - 0x4f */
+0x00, 0x00, 0x00, 0x00, /* 0x50 - 0x53 */
+0x00, 0x00, 0x00, 0x00, /* 0x54 - 0x57 */
+0x00, 0x00, 0x00, 0x00, /* 0x58 - 0x5b */
+0x00, 0x00, 0x00, 0x00, /* 0x5c - 0x5f */
+0x00, 0x00, 0x00, 0x00, /* 0x60 - 0x63 */
+0x00, 0x00, 0x00, 0x00, /* 0x64 - 0x67 */
+0x00, 0x00, 0x00, 0x00, /* 0x68 - 0x6b */
+0x00, 0x00, 0x00, 0x00, /* 0x6c - 0x6f */
+0x00, 0x00, 0x00, 0x00, /* 0x70 - 0x73 */
+0x00, 0x00, 0x00, 0x00, /* 0x74 - 0x77 */
+0x00, 0x00, 0x00, 0x00, /* 0x78 - 0x7b */
+0x00,                   /* 0x7c        */
+
+      0xda, 0x33, 0x03, /* 0x7d - 0x7f */
+};
+
+/* Register read and write */
+static inline unsigned int dac33_read_reg_cache(struct snd_soc_component *component,
+						unsigned reg)
+{
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	u8 *cache = dac33->reg_cache;
+	if (reg >= DAC33_CACHEREGNUM)
+		return 0;
+
+	return cache[reg];
+}
+
+static inline void dac33_write_reg_cache(struct snd_soc_component *component,
+					 u8 reg, u8 value)
+{
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	u8 *cache = dac33->reg_cache;
+	if (reg >= DAC33_CACHEREGNUM)
+		return;
+
+	cache[reg] = value;
+}
+
+static int dac33_read(struct snd_soc_component *component, unsigned int reg,
+		      u8 *value)
+{
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	int val, ret = 0;
+
+	*value = reg & 0xff;
+
+	/* If powered off, return the cached value */
+	if (dac33->chip_power) {
+		val = i2c_smbus_read_byte_data(dac33->i2c, value[0]);
+		if (val < 0) {
+			dev_err(component->dev, "Read failed (%d)\n", val);
+			value[0] = dac33_read_reg_cache(component, reg);
+			ret = val;
+		} else {
+			value[0] = val;
+			dac33_write_reg_cache(component, reg, val);
+		}
+	} else {
+		value[0] = dac33_read_reg_cache(component, reg);
+	}
+
+	return ret;
+}
+
+static int dac33_write(struct snd_soc_component *component, unsigned int reg,
+		       unsigned int value)
+{
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	u8 data[2];
+	int ret = 0;
+
+	/*
+	 * data is
+	 *   D15..D8 dac33 register offset
+	 *   D7...D0 register data
+	 */
+	data[0] = reg & 0xff;
+	data[1] = value & 0xff;
+
+	dac33_write_reg_cache(component, data[0], data[1]);
+	if (dac33->chip_power) {
+		ret = i2c_master_send(dac33->i2c, data, 2);
+		if (ret != 2)
+			dev_err(component->dev, "Write failed (%d)\n", ret);
+		else
+			ret = 0;
+	}
+
+	return ret;
+}
+
+static int dac33_write_locked(struct snd_soc_component *component, unsigned int reg,
+			      unsigned int value)
+{
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	mutex_lock(&dac33->mutex);
+	ret = dac33_write(component, reg, value);
+	mutex_unlock(&dac33->mutex);
+
+	return ret;
+}
+
+#define DAC33_I2C_ADDR_AUTOINC	0x80
+static int dac33_write16(struct snd_soc_component *component, unsigned int reg,
+		       unsigned int value)
+{
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	u8 data[3];
+	int ret = 0;
+
+	/*
+	 * data is
+	 *   D23..D16 dac33 register offset
+	 *   D15..D8  register data MSB
+	 *   D7...D0  register data LSB
+	 */
+	data[0] = reg & 0xff;
+	data[1] = (value >> 8) & 0xff;
+	data[2] = value & 0xff;
+
+	dac33_write_reg_cache(component, data[0], data[1]);
+	dac33_write_reg_cache(component, data[0] + 1, data[2]);
+
+	if (dac33->chip_power) {
+		/* We need to set autoincrement mode for 16 bit writes */
+		data[0] |= DAC33_I2C_ADDR_AUTOINC;
+		ret = i2c_master_send(dac33->i2c, data, 3);
+		if (ret != 3)
+			dev_err(component->dev, "Write failed (%d)\n", ret);
+		else
+			ret = 0;
+	}
+
+	return ret;
+}
+
+static void dac33_init_chip(struct snd_soc_component *component)
+{
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+
+	if (unlikely(!dac33->chip_power))
+		return;
+
+	/* A : DAC sample rate Fsref/1.5 */
+	dac33_write(component, DAC33_DAC_CTRL_A, DAC33_DACRATE(0));
+	/* B : DAC src=normal, not muted */
+	dac33_write(component, DAC33_DAC_CTRL_B, DAC33_DACSRCR_RIGHT |
+					     DAC33_DACSRCL_LEFT);
+	/* C : (defaults) */
+	dac33_write(component, DAC33_DAC_CTRL_C, 0x00);
+
+	/* 73 : volume soft stepping control,
+	 clock source = internal osc (?) */
+	dac33_write(component, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN);
+
+	/* Restore only selected registers (gains mostly) */
+	dac33_write(component, DAC33_LDAC_DIG_VOL_CTRL,
+		    dac33_read_reg_cache(component, DAC33_LDAC_DIG_VOL_CTRL));
+	dac33_write(component, DAC33_RDAC_DIG_VOL_CTRL,
+		    dac33_read_reg_cache(component, DAC33_RDAC_DIG_VOL_CTRL));
+
+	dac33_write(component, DAC33_LINEL_TO_LLO_VOL,
+		    dac33_read_reg_cache(component, DAC33_LINEL_TO_LLO_VOL));
+	dac33_write(component, DAC33_LINER_TO_RLO_VOL,
+		    dac33_read_reg_cache(component, DAC33_LINER_TO_RLO_VOL));
+
+	dac33_write(component, DAC33_OUT_AMP_CTRL,
+		    dac33_read_reg_cache(component, DAC33_OUT_AMP_CTRL));
+
+	dac33_write(component, DAC33_LDAC_PWR_CTRL,
+		    dac33_read_reg_cache(component, DAC33_LDAC_PWR_CTRL));
+	dac33_write(component, DAC33_RDAC_PWR_CTRL,
+		    dac33_read_reg_cache(component, DAC33_RDAC_PWR_CTRL));
+}
+
+static inline int dac33_read_id(struct snd_soc_component *component)
+{
+	int i, ret = 0;
+	u8 reg;
+
+	for (i = 0; i < 3; i++) {
+		ret = dac33_read(component, DAC33_DEVICE_ID_MSB + i, &reg);
+		if (ret < 0)
+			break;
+	}
+
+	return ret;
+}
+
+static inline void dac33_soft_power(struct snd_soc_component *component, int power)
+{
+	u8 reg;
+
+	reg = dac33_read_reg_cache(component, DAC33_PWR_CTRL);
+	if (power)
+		reg |= DAC33_PDNALLB;
+	else
+		reg &= ~(DAC33_PDNALLB | DAC33_OSCPDNB |
+			 DAC33_DACRPDNB | DAC33_DACLPDNB);
+	dac33_write(component, DAC33_PWR_CTRL, reg);
+}
+
+static inline void dac33_disable_digital(struct snd_soc_component *component)
+{
+	u8 reg;
+
+	/* Stop the DAI clock */
+	reg = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_B);
+	reg &= ~DAC33_BCLKON;
+	dac33_write(component, DAC33_SER_AUDIOIF_CTRL_B, reg);
+
+	/* Power down the Oscillator, and DACs */
+	reg = dac33_read_reg_cache(component, DAC33_PWR_CTRL);
+	reg &= ~(DAC33_OSCPDNB | DAC33_DACRPDNB | DAC33_DACLPDNB);
+	dac33_write(component, DAC33_PWR_CTRL, reg);
+}
+
+static int dac33_hard_power(struct snd_soc_component *component, int power)
+{
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	mutex_lock(&dac33->mutex);
+
+	/* Safety check */
+	if (unlikely(power == dac33->chip_power)) {
+		dev_dbg(component->dev, "Trying to set the same power state: %s\n",
+			power ? "ON" : "OFF");
+		goto exit;
+	}
+
+	if (power) {
+		ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
+					  dac33->supplies);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to enable supplies: %d\n", ret);
+				goto exit;
+		}
+
+		if (dac33->power_gpio >= 0)
+			gpio_set_value(dac33->power_gpio, 1);
+
+		dac33->chip_power = 1;
+	} else {
+		dac33_soft_power(component, 0);
+		if (dac33->power_gpio >= 0)
+			gpio_set_value(dac33->power_gpio, 0);
+
+		ret = regulator_bulk_disable(ARRAY_SIZE(dac33->supplies),
+					     dac33->supplies);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to disable supplies: %d\n", ret);
+			goto exit;
+		}
+
+		dac33->chip_power = 0;
+	}
+
+exit:
+	mutex_unlock(&dac33->mutex);
+	return ret;
+}
+
+static int dac33_playback_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (likely(dac33->substream)) {
+			dac33_calculate_times(dac33->substream, component);
+			dac33_prepare_chip(dac33->substream, component);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		dac33_disable_digital(component);
+		break;
+	}
+	return 0;
+}
+
+static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.enumerated.item[0] = dac33->fifo_mode;
+
+	return 0;
+}
+
+static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	if (dac33->fifo_mode == ucontrol->value.enumerated.item[0])
+		return 0;
+	/* Do not allow changes while stream is running*/
+	if (snd_soc_component_is_active(component))
+		return -EPERM;
+
+	if (ucontrol->value.enumerated.item[0] >= DAC33_FIFO_LAST_MODE)
+		ret = -EINVAL;
+	else
+		dac33->fifo_mode = ucontrol->value.enumerated.item[0];
+
+	return ret;
+}
+
+/* Codec operation modes */
+static const char *dac33_fifo_mode_texts[] = {
+	"Bypass", "Mode 1", "Mode 7"
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(dac33_fifo_mode_enum, dac33_fifo_mode_texts);
+
+/* L/R Line Output Gain */
+static const char *lr_lineout_gain_texts[] = {
+	"Line -12dB DAC 0dB", "Line -6dB DAC 6dB",
+	"Line 0dB DAC 12dB", "Line 6dB DAC 18dB",
+};
+
+static SOC_ENUM_SINGLE_DECL(l_lineout_gain_enum,
+			    DAC33_LDAC_PWR_CTRL, 0,
+			    lr_lineout_gain_texts);
+
+static SOC_ENUM_SINGLE_DECL(r_lineout_gain_enum,
+			    DAC33_RDAC_PWR_CTRL, 0,
+			    lr_lineout_gain_texts);
+
+/*
+ * DACL/R digital volume control:
+ * from 0 dB to -63.5 in 0.5 dB steps
+ * Need to be inverted later on:
+ * 0x00 == 0 dB
+ * 0x7f == -63.5 dB
+ */
+static DECLARE_TLV_DB_SCALE(dac_digivol_tlv, -6350, 50, 0);
+
+static const struct snd_kcontrol_new dac33_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("DAC Digital Playback Volume",
+		DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL,
+		0, 0x7f, 1, dac_digivol_tlv),
+	SOC_DOUBLE_R("DAC Digital Playback Switch",
+		 DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL, 7, 1, 1),
+	SOC_DOUBLE_R("Line to Line Out Volume",
+		 DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1),
+	SOC_ENUM("Left Line Output Gain", l_lineout_gain_enum),
+	SOC_ENUM("Right Line Output Gain", r_lineout_gain_enum),
+};
+
+static const struct snd_kcontrol_new dac33_mode_snd_controls[] = {
+	SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum,
+		 dac33_get_fifo_mode, dac33_set_fifo_mode),
+};
+
+/* Analog bypass */
+static const struct snd_kcontrol_new dac33_dapm_abypassl_control =
+	SOC_DAPM_SINGLE("Switch", DAC33_LINEL_TO_LLO_VOL, 7, 1, 1);
+
+static const struct snd_kcontrol_new dac33_dapm_abypassr_control =
+	SOC_DAPM_SINGLE("Switch", DAC33_LINER_TO_RLO_VOL, 7, 1, 1);
+
+/* LOP L/R invert selection */
+static const char *dac33_lr_lom_texts[] = {"DAC", "LOP"};
+
+static SOC_ENUM_SINGLE_DECL(dac33_left_lom_enum,
+			    DAC33_OUT_AMP_CTRL, 3,
+			    dac33_lr_lom_texts);
+
+static const struct snd_kcontrol_new dac33_dapm_left_lom_control =
+SOC_DAPM_ENUM("Route", dac33_left_lom_enum);
+
+static SOC_ENUM_SINGLE_DECL(dac33_right_lom_enum,
+			    DAC33_OUT_AMP_CTRL, 2,
+			    dac33_lr_lom_texts);
+
+static const struct snd_kcontrol_new dac33_dapm_right_lom_control =
+SOC_DAPM_ENUM("Route", dac33_right_lom_enum);
+
+static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("LEFT_LO"),
+	SND_SOC_DAPM_OUTPUT("RIGHT_LO"),
+
+	SND_SOC_DAPM_INPUT("LINEL"),
+	SND_SOC_DAPM_INPUT("LINER"),
+
+	SND_SOC_DAPM_DAC("DACL", "Left Playback", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DACR", "Right Playback", SND_SOC_NOPM, 0, 0),
+
+	/* Analog bypass */
+	SND_SOC_DAPM_SWITCH("Analog Left Bypass", SND_SOC_NOPM, 0, 0,
+				&dac33_dapm_abypassl_control),
+	SND_SOC_DAPM_SWITCH("Analog Right Bypass", SND_SOC_NOPM, 0, 0,
+				&dac33_dapm_abypassr_control),
+
+	SND_SOC_DAPM_MUX("Left LOM Inverted From", SND_SOC_NOPM, 0, 0,
+		&dac33_dapm_left_lom_control),
+	SND_SOC_DAPM_MUX("Right LOM Inverted From", SND_SOC_NOPM, 0, 0,
+		&dac33_dapm_right_lom_control),
+	/*
+	 * For DAPM path, when only the anlog bypass path is enabled, and the
+	 * LOP inverted from the corresponding DAC side.
+	 * This is needed, so we can attach the DAC power supply in this case.
+	 */
+	SND_SOC_DAPM_PGA("Left Bypass PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Bypass PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Left Amplifier",
+			 DAC33_OUT_AMP_PWR_CTRL, 6, 3, 3, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amplifier",
+			 DAC33_OUT_AMP_PWR_CTRL, 4, 3, 3, 0),
+
+	SND_SOC_DAPM_SUPPLY("Left DAC Power",
+			    DAC33_LDAC_PWR_CTRL, 2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Right DAC Power",
+			    DAC33_RDAC_PWR_CTRL, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Codec Power",
+			    DAC33_PWR_CTRL, 4, 0, NULL, 0),
+
+	SND_SOC_DAPM_PRE("Pre Playback", dac33_playback_event),
+	SND_SOC_DAPM_POST("Post Playback", dac33_playback_event),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* Analog bypass */
+	{"Analog Left Bypass", "Switch", "LINEL"},
+	{"Analog Right Bypass", "Switch", "LINER"},
+
+	{"Output Left Amplifier", NULL, "DACL"},
+	{"Output Right Amplifier", NULL, "DACR"},
+
+	{"Left Bypass PGA", NULL, "Analog Left Bypass"},
+	{"Right Bypass PGA", NULL, "Analog Right Bypass"},
+
+	{"Left LOM Inverted From", "DAC", "Left Bypass PGA"},
+	{"Right LOM Inverted From", "DAC", "Right Bypass PGA"},
+	{"Left LOM Inverted From", "LOP", "Analog Left Bypass"},
+	{"Right LOM Inverted From", "LOP", "Analog Right Bypass"},
+
+	{"Output Left Amplifier", NULL, "Left LOM Inverted From"},
+	{"Output Right Amplifier", NULL, "Right LOM Inverted From"},
+
+	{"DACL", NULL, "Left DAC Power"},
+	{"DACR", NULL, "Right DAC Power"},
+
+	{"Left Bypass PGA", NULL, "Left DAC Power"},
+	{"Right Bypass PGA", NULL, "Right DAC Power"},
+
+	/* output */
+	{"LEFT_LO", NULL, "Output Left Amplifier"},
+	{"RIGHT_LO", NULL, "Output Right Amplifier"},
+
+	{"LEFT_LO", NULL, "Codec Power"},
+	{"RIGHT_LO", NULL, "Codec Power"},
+};
+
+static int dac33_set_bias_level(struct snd_soc_component *component,
+				enum snd_soc_bias_level level)
+{
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/* Coming from OFF, switch on the component */
+			ret = dac33_hard_power(component, 1);
+			if (ret != 0)
+				return ret;
+
+			dac33_init_chip(component);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* Do not power off, when the component is already off */
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			return 0;
+		ret = dac33_hard_power(component, 0);
+		if (ret != 0)
+			return ret;
+		break;
+	}
+
+	return 0;
+}
+
+static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
+{
+	struct snd_soc_component *component = dac33->component;
+	unsigned int delay;
+	unsigned long flags;
+
+	switch (dac33->fifo_mode) {
+	case DAC33_FIFO_MODE1:
+		dac33_write16(component, DAC33_NSAMPLE_MSB,
+			DAC33_THRREG(dac33->nsample));
+
+		/* Take the timestamps */
+		spin_lock_irqsave(&dac33->lock, flags);
+		dac33->t_stamp2 = ktime_to_us(ktime_get());
+		dac33->t_stamp1 = dac33->t_stamp2;
+		spin_unlock_irqrestore(&dac33->lock, flags);
+
+		dac33_write16(component, DAC33_PREFILL_MSB,
+				DAC33_THRREG(dac33->alarm_threshold));
+		/* Enable Alarm Threshold IRQ with a delay */
+		delay = SAMPLES_TO_US(dac33->burst_rate,
+				     dac33->alarm_threshold) + 1000;
+		usleep_range(delay, delay + 500);
+		dac33_write(component, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
+		break;
+	case DAC33_FIFO_MODE7:
+		/* Take the timestamp */
+		spin_lock_irqsave(&dac33->lock, flags);
+		dac33->t_stamp1 = ktime_to_us(ktime_get());
+		/* Move back the timestamp with drain time */
+		dac33->t_stamp1 -= dac33->mode7_us_to_lthr;
+		spin_unlock_irqrestore(&dac33->lock, flags);
+
+		dac33_write16(component, DAC33_PREFILL_MSB,
+				DAC33_THRREG(DAC33_MODE7_MARGIN));
+
+		/* Enable Upper Threshold IRQ */
+		dac33_write(component, DAC33_FIFO_IRQ_MASK, DAC33_MUT);
+		break;
+	default:
+		dev_warn(component->dev, "Unhandled FIFO mode: %d\n",
+							dac33->fifo_mode);
+		break;
+	}
+}
+
+static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
+{
+	struct snd_soc_component *component = dac33->component;
+	unsigned long flags;
+
+	switch (dac33->fifo_mode) {
+	case DAC33_FIFO_MODE1:
+		/* Take the timestamp */
+		spin_lock_irqsave(&dac33->lock, flags);
+		dac33->t_stamp2 = ktime_to_us(ktime_get());
+		spin_unlock_irqrestore(&dac33->lock, flags);
+
+		dac33_write16(component, DAC33_NSAMPLE_MSB,
+				DAC33_THRREG(dac33->nsample));
+		break;
+	case DAC33_FIFO_MODE7:
+		/* At the moment we are not using interrupts in mode7 */
+		break;
+	default:
+		dev_warn(component->dev, "Unhandled FIFO mode: %d\n",
+							dac33->fifo_mode);
+		break;
+	}
+}
+
+static void dac33_work(struct work_struct *work)
+{
+	struct snd_soc_component *component;
+	struct tlv320dac33_priv *dac33;
+	u8 reg;
+
+	dac33 = container_of(work, struct tlv320dac33_priv, work);
+	component = dac33->component;
+
+	mutex_lock(&dac33->mutex);
+	switch (dac33->state) {
+	case DAC33_PREFILL:
+		dac33->state = DAC33_PLAYBACK;
+		dac33_prefill_handler(dac33);
+		break;
+	case DAC33_PLAYBACK:
+		dac33_playback_handler(dac33);
+		break;
+	case DAC33_IDLE:
+		break;
+	case DAC33_FLUSH:
+		dac33->state = DAC33_IDLE;
+		/* Mask all interrupts from dac33 */
+		dac33_write(component, DAC33_FIFO_IRQ_MASK, 0);
+
+		/* flush fifo */
+		reg = dac33_read_reg_cache(component, DAC33_FIFO_CTRL_A);
+		reg |= DAC33_FIFOFLUSH;
+		dac33_write(component, DAC33_FIFO_CTRL_A, reg);
+		break;
+	}
+	mutex_unlock(&dac33->mutex);
+}
+
+static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
+{
+	struct snd_soc_component *component = dev;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	unsigned long flags;
+
+	spin_lock_irqsave(&dac33->lock, flags);
+	dac33->t_stamp1 = ktime_to_us(ktime_get());
+	spin_unlock_irqrestore(&dac33->lock, flags);
+
+	/* Do not schedule the workqueue in Mode7 */
+	if (dac33->fifo_mode != DAC33_FIFO_MODE7)
+		schedule_work(&dac33->work);
+
+	return IRQ_HANDLED;
+}
+
+static void dac33_oscwait(struct snd_soc_component *component)
+{
+	int timeout = 60;
+	u8 reg;
+
+	do {
+		usleep_range(1000, 2000);
+		dac33_read(component, DAC33_INT_OSC_STATUS, &reg);
+	} while (((reg & 0x03) != DAC33_OSCSTATUS_NORMAL) && timeout--);
+	if ((reg & 0x03) != DAC33_OSCSTATUS_NORMAL)
+		dev_err(component->dev,
+			"internal oscillator calibration failed\n");
+}
+
+static int dac33_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+
+	/* Stream started, save the substream pointer */
+	dac33->substream = substream;
+
+	return 0;
+}
+
+static void dac33_shutdown(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+
+	dac33->substream = NULL;
+}
+
+#define CALC_BURST_RATE(bclkdiv, bclk_per_sample) \
+	(BURST_BASEFREQ_HZ / bclkdiv / bclk_per_sample)
+static int dac33_hw_params(struct snd_pcm_substream *substream,
+			   struct snd_pcm_hw_params *params,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+
+	/* Check parameters for validity */
+	switch (params_rate(params)) {
+	case 44100:
+	case 48000:
+		break;
+	default:
+		dev_err(component->dev, "unsupported rate %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	switch (params_width(params)) {
+	case 16:
+		dac33->fifo_size = DAC33_FIFO_SIZE_16BIT;
+		dac33->burst_rate = CALC_BURST_RATE(dac33->burst_bclkdiv, 32);
+		break;
+	case 32:
+		dac33->fifo_size = DAC33_FIFO_SIZE_24BIT;
+		dac33->burst_rate = CALC_BURST_RATE(dac33->burst_bclkdiv, 64);
+		break;
+	default:
+		dev_err(component->dev, "unsupported width %d\n",
+			params_width(params));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+#define CALC_OSCSET(rate, refclk) ( \
+	((((rate * 10000) / refclk) * 4096) + 7000) / 10000)
+#define CALC_RATIOSET(rate, refclk) ( \
+	((((refclk  * 100000) / rate) * 16384) + 50000) / 100000)
+
+/*
+ * tlv320dac33 is strict on the sequence of the register writes, if the register
+ * writes happens in different order, than dac33 might end up in unknown state.
+ * Use the known, working sequence of register writes to initialize the dac33.
+ */
+static int dac33_prepare_chip(struct snd_pcm_substream *substream,
+			      struct snd_soc_component *component)
+{
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
+	u8 aictrl_a, aictrl_b, fifoctrl_a;
+
+	switch (substream->runtime->rate) {
+	case 44100:
+	case 48000:
+		oscset = CALC_OSCSET(substream->runtime->rate, dac33->refclk);
+		ratioset = CALC_RATIOSET(substream->runtime->rate,
+					 dac33->refclk);
+		break;
+	default:
+		dev_err(component->dev, "unsupported rate %d\n",
+			substream->runtime->rate);
+		return -EINVAL;
+	}
+
+
+	aictrl_a = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_A);
+	aictrl_a &= ~(DAC33_NCYCL_MASK | DAC33_WLEN_MASK);
+	/* Read FIFO control A, and clear FIFO flush bit */
+	fifoctrl_a = dac33_read_reg_cache(component, DAC33_FIFO_CTRL_A);
+	fifoctrl_a &= ~DAC33_FIFOFLUSH;
+
+	fifoctrl_a &= ~DAC33_WIDTH;
+	switch (substream->runtime->format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		aictrl_a |= (DAC33_NCYCL_16 | DAC33_WLEN_16);
+		fifoctrl_a |= DAC33_WIDTH;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		aictrl_a |= (DAC33_NCYCL_32 | DAC33_WLEN_24);
+		break;
+	default:
+		dev_err(component->dev, "unsupported format %d\n",
+			substream->runtime->format);
+		return -EINVAL;
+	}
+
+	mutex_lock(&dac33->mutex);
+
+	if (!dac33->chip_power) {
+		/*
+		 * Chip is not powered yet.
+		 * Do the init in the dac33_set_bias_level later.
+		 */
+		mutex_unlock(&dac33->mutex);
+		return 0;
+	}
+
+	dac33_soft_power(component, 0);
+	dac33_soft_power(component, 1);
+
+	reg_tmp = dac33_read_reg_cache(component, DAC33_INT_OSC_CTRL);
+	dac33_write(component, DAC33_INT_OSC_CTRL, reg_tmp);
+
+	/* Write registers 0x08 and 0x09 (MSB, LSB) */
+	dac33_write16(component, DAC33_INT_OSC_FREQ_RAT_A, oscset);
+
+	/* OSC calibration time */
+	dac33_write(component, DAC33_CALIB_TIME, 96);
+
+	/* adjustment treshold & step */
+	dac33_write(component, DAC33_INT_OSC_CTRL_B, DAC33_ADJTHRSHLD(2) |
+						 DAC33_ADJSTEP(1));
+
+	/* div=4 / gain=1 / div */
+	dac33_write(component, DAC33_INT_OSC_CTRL_C, DAC33_REFDIV(4));
+
+	pwr_ctrl = dac33_read_reg_cache(component, DAC33_PWR_CTRL);
+	pwr_ctrl |= DAC33_OSCPDNB | DAC33_DACRPDNB | DAC33_DACLPDNB;
+	dac33_write(component, DAC33_PWR_CTRL, pwr_ctrl);
+
+	dac33_oscwait(component);
+
+	if (dac33->fifo_mode) {
+		/* Generic for all FIFO modes */
+		/* 50-51 : ASRC Control registers */
+		dac33_write(component, DAC33_ASRC_CTRL_A, DAC33_SRCLKDIV(1));
+		dac33_write(component, DAC33_ASRC_CTRL_B, 1); /* ??? */
+
+		/* Write registers 0x34 and 0x35 (MSB, LSB) */
+		dac33_write16(component, DAC33_SRC_REF_CLK_RATIO_A, ratioset);
+
+		/* Set interrupts to high active */
+		dac33_write(component, DAC33_INTP_CTRL_A, DAC33_INTPM_AHIGH);
+	} else {
+		/* FIFO bypass mode */
+		/* 50-51 : ASRC Control registers */
+		dac33_write(component, DAC33_ASRC_CTRL_A, DAC33_SRCBYP);
+		dac33_write(component, DAC33_ASRC_CTRL_B, 0); /* ??? */
+	}
+
+	/* Interrupt behaviour configuration */
+	switch (dac33->fifo_mode) {
+	case DAC33_FIFO_MODE1:
+		dac33_write(component, DAC33_FIFO_IRQ_MODE_B,
+			    DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL));
+		break;
+	case DAC33_FIFO_MODE7:
+		dac33_write(component, DAC33_FIFO_IRQ_MODE_A,
+			DAC33_UTM(DAC33_FIFO_IRQ_MODE_LEVEL));
+		break;
+	default:
+		/* in FIFO bypass mode, the interrupts are not used */
+		break;
+	}
+
+	aictrl_b = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_B);
+
+	switch (dac33->fifo_mode) {
+	case DAC33_FIFO_MODE1:
+		/*
+		 * For mode1:
+		 * Disable the FIFO bypass (Enable the use of FIFO)
+		 * Select nSample mode
+		 * BCLK is only running when data is needed by DAC33
+		 */
+		fifoctrl_a &= ~DAC33_FBYPAS;
+		fifoctrl_a &= ~DAC33_FAUTO;
+		if (dac33->keep_bclk)
+			aictrl_b |= DAC33_BCLKON;
+		else
+			aictrl_b &= ~DAC33_BCLKON;
+		break;
+	case DAC33_FIFO_MODE7:
+		/*
+		 * For mode1:
+		 * Disable the FIFO bypass (Enable the use of FIFO)
+		 * Select Threshold mode
+		 * BCLK is only running when data is needed by DAC33
+		 */
+		fifoctrl_a &= ~DAC33_FBYPAS;
+		fifoctrl_a |= DAC33_FAUTO;
+		if (dac33->keep_bclk)
+			aictrl_b |= DAC33_BCLKON;
+		else
+			aictrl_b &= ~DAC33_BCLKON;
+		break;
+	default:
+		/*
+		 * For FIFO bypass mode:
+		 * Enable the FIFO bypass (Disable the FIFO use)
+		 * Set the BCLK as continuous
+		 */
+		fifoctrl_a |= DAC33_FBYPAS;
+		aictrl_b |= DAC33_BCLKON;
+		break;
+	}
+
+	dac33_write(component, DAC33_FIFO_CTRL_A, fifoctrl_a);
+	dac33_write(component, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a);
+	dac33_write(component, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b);
+
+	/*
+	 * BCLK divide ratio
+	 * 0: 1.5
+	 * 1: 1
+	 * 2: 2
+	 * ...
+	 * 254: 254
+	 * 255: 255
+	 */
+	if (dac33->fifo_mode)
+		dac33_write(component, DAC33_SER_AUDIOIF_CTRL_C,
+							dac33->burst_bclkdiv);
+	else
+		if (substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE)
+			dac33_write(component, DAC33_SER_AUDIOIF_CTRL_C, 32);
+		else
+			dac33_write(component, DAC33_SER_AUDIOIF_CTRL_C, 16);
+
+	switch (dac33->fifo_mode) {
+	case DAC33_FIFO_MODE1:
+		dac33_write16(component, DAC33_ATHR_MSB,
+			      DAC33_THRREG(dac33->alarm_threshold));
+		break;
+	case DAC33_FIFO_MODE7:
+		/*
+		 * Configure the threshold levels, and leave 10 sample space
+		 * at the bottom, and also at the top of the FIFO
+		 */
+		dac33_write16(component, DAC33_UTHR_MSB, DAC33_THRREG(dac33->uthr));
+		dac33_write16(component, DAC33_LTHR_MSB,
+			      DAC33_THRREG(DAC33_MODE7_MARGIN));
+		break;
+	default:
+		break;
+	}
+
+	mutex_unlock(&dac33->mutex);
+
+	return 0;
+}
+
+static void dac33_calculate_times(struct snd_pcm_substream *substream,
+				  struct snd_soc_component *component)
+{
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	unsigned int period_size = substream->runtime->period_size;
+	unsigned int rate = substream->runtime->rate;
+	unsigned int nsample_limit;
+
+	/* In bypass mode we don't need to calculate */
+	if (!dac33->fifo_mode)
+		return;
+
+	switch (dac33->fifo_mode) {
+	case DAC33_FIFO_MODE1:
+		/* Number of samples under i2c latency */
+		dac33->alarm_threshold = US_TO_SAMPLES(rate,
+						dac33->mode1_latency);
+		nsample_limit = dac33->fifo_size - dac33->alarm_threshold;
+
+		if (period_size <= dac33->alarm_threshold)
+			/*
+			 * Configure nSamaple to number of periods,
+			 * which covers the latency requironment.
+			 */
+			dac33->nsample = period_size *
+				((dac33->alarm_threshold / period_size) +
+				(dac33->alarm_threshold % period_size ?
+				1 : 0));
+		else if (period_size > nsample_limit)
+			dac33->nsample = nsample_limit;
+		else
+			dac33->nsample = period_size;
+
+		dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate,
+						      dac33->nsample);
+		dac33->t_stamp1 = 0;
+		dac33->t_stamp2 = 0;
+		break;
+	case DAC33_FIFO_MODE7:
+		dac33->uthr = UTHR_FROM_PERIOD_SIZE(period_size, rate,
+						    dac33->burst_rate) + 9;
+		if (dac33->uthr > (dac33->fifo_size - DAC33_MODE7_MARGIN))
+			dac33->uthr = dac33->fifo_size - DAC33_MODE7_MARGIN;
+		if (dac33->uthr < (DAC33_MODE7_MARGIN + 10))
+			dac33->uthr = (DAC33_MODE7_MARGIN + 10);
+
+		dac33->mode7_us_to_lthr =
+				SAMPLES_TO_US(substream->runtime->rate,
+					dac33->uthr - DAC33_MODE7_MARGIN + 1);
+		dac33->t_stamp1 = 0;
+		break;
+	default:
+		break;
+	}
+
+}
+
+static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (dac33->fifo_mode) {
+			dac33->state = DAC33_PREFILL;
+			schedule_work(&dac33->work);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (dac33->fifo_mode) {
+			dac33->state = DAC33_FLUSH;
+			schedule_work(&dac33->work);
+		}
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static snd_pcm_sframes_t dac33_dai_delay(
+			struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	unsigned long long t0, t1, t_now;
+	unsigned int time_delta, uthr;
+	int samples_out, samples_in, samples;
+	snd_pcm_sframes_t delay = 0;
+	unsigned long flags;
+
+	switch (dac33->fifo_mode) {
+	case DAC33_FIFO_BYPASS:
+		break;
+	case DAC33_FIFO_MODE1:
+		spin_lock_irqsave(&dac33->lock, flags);
+		t0 = dac33->t_stamp1;
+		t1 = dac33->t_stamp2;
+		spin_unlock_irqrestore(&dac33->lock, flags);
+		t_now = ktime_to_us(ktime_get());
+
+		/* We have not started to fill the FIFO yet, delay is 0 */
+		if (!t1)
+			goto out;
+
+		if (t0 > t1) {
+			/*
+			 * Phase 1:
+			 * After Alarm threshold, and before nSample write
+			 */
+			time_delta = t_now - t0;
+			samples_out = time_delta ? US_TO_SAMPLES(
+						substream->runtime->rate,
+						time_delta) : 0;
+
+			if (likely(dac33->alarm_threshold > samples_out))
+				delay = dac33->alarm_threshold - samples_out;
+			else
+				delay = 0;
+		} else if ((t_now - t1) <= dac33->mode1_us_burst) {
+			/*
+			 * Phase 2:
+			 * After nSample write (during burst operation)
+			 */
+			time_delta = t_now - t0;
+			samples_out = time_delta ? US_TO_SAMPLES(
+						substream->runtime->rate,
+						time_delta) : 0;
+
+			time_delta = t_now - t1;
+			samples_in = time_delta ? US_TO_SAMPLES(
+						dac33->burst_rate,
+						time_delta) : 0;
+
+			samples = dac33->alarm_threshold;
+			samples += (samples_in - samples_out);
+
+			if (likely(samples > 0))
+				delay = samples;
+			else
+				delay = 0;
+		} else {
+			/*
+			 * Phase 3:
+			 * After burst operation, before next alarm threshold
+			 */
+			time_delta = t_now - t0;
+			samples_out = time_delta ? US_TO_SAMPLES(
+						substream->runtime->rate,
+						time_delta) : 0;
+
+			samples_in = dac33->nsample;
+			samples = dac33->alarm_threshold;
+			samples += (samples_in - samples_out);
+
+			if (likely(samples > 0))
+				delay = samples > dac33->fifo_size ?
+					dac33->fifo_size : samples;
+			else
+				delay = 0;
+		}
+		break;
+	case DAC33_FIFO_MODE7:
+		spin_lock_irqsave(&dac33->lock, flags);
+		t0 = dac33->t_stamp1;
+		uthr = dac33->uthr;
+		spin_unlock_irqrestore(&dac33->lock, flags);
+		t_now = ktime_to_us(ktime_get());
+
+		/* We have not started to fill the FIFO yet, delay is 0 */
+		if (!t0)
+			goto out;
+
+		if (t_now <= t0) {
+			/*
+			 * Either the timestamps are messed or equal. Report
+			 * maximum delay
+			 */
+			delay = uthr;
+			goto out;
+		}
+
+		time_delta = t_now - t0;
+		if (time_delta <= dac33->mode7_us_to_lthr) {
+			/*
+			* Phase 1:
+			* After burst (draining phase)
+			*/
+			samples_out = US_TO_SAMPLES(
+					substream->runtime->rate,
+					time_delta);
+
+			if (likely(uthr > samples_out))
+				delay = uthr - samples_out;
+			else
+				delay = 0;
+		} else {
+			/*
+			* Phase 2:
+			* During burst operation
+			*/
+			time_delta = time_delta - dac33->mode7_us_to_lthr;
+
+			samples_out = US_TO_SAMPLES(
+					substream->runtime->rate,
+					time_delta);
+			samples_in = US_TO_SAMPLES(
+					dac33->burst_rate,
+					time_delta);
+			delay = DAC33_MODE7_MARGIN + samples_in - samples_out;
+
+			if (unlikely(delay > uthr))
+				delay = uthr;
+		}
+		break;
+	default:
+		dev_warn(component->dev, "Unhandled FIFO mode: %d\n",
+							dac33->fifo_mode);
+		break;
+	}
+out:
+	return delay;
+}
+
+static int dac33_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	u8 ioc_reg, asrcb_reg;
+
+	ioc_reg = dac33_read_reg_cache(component, DAC33_INT_OSC_CTRL);
+	asrcb_reg = dac33_read_reg_cache(component, DAC33_ASRC_CTRL_B);
+	switch (clk_id) {
+	case TLV320DAC33_MCLK:
+		ioc_reg |= DAC33_REFSEL;
+		asrcb_reg |= DAC33_SRCREFSEL;
+		break;
+	case TLV320DAC33_SLEEPCLK:
+		ioc_reg &= ~DAC33_REFSEL;
+		asrcb_reg &= ~DAC33_SRCREFSEL;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock ID (%d)\n", clk_id);
+		break;
+	}
+	dac33->refclk = freq;
+
+	dac33_write_reg_cache(component, DAC33_INT_OSC_CTRL, ioc_reg);
+	dac33_write_reg_cache(component, DAC33_ASRC_CTRL_B, asrcb_reg);
+
+	return 0;
+}
+
+static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			     unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	u8 aictrl_a, aictrl_b;
+
+	aictrl_a = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_A);
+	aictrl_b = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_B);
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* Codec Master */
+		aictrl_a |= (DAC33_MSBCLK | DAC33_MSWCLK);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* Codec Slave */
+		if (dac33->fifo_mode) {
+			dev_err(component->dev, "FIFO mode requires master mode\n");
+			return -EINVAL;
+		} else
+			aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	aictrl_a &= ~DAC33_AFMT_MASK;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		aictrl_a |= DAC33_AFMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		aictrl_a |= DAC33_AFMT_DSP;
+		aictrl_b &= ~DAC33_DATA_DELAY_MASK;
+		aictrl_b |= DAC33_DATA_DELAY(0);
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		aictrl_a |= DAC33_AFMT_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aictrl_a |= DAC33_AFMT_LEFT_J;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported format (%u)\n",
+			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+		return -EINVAL;
+	}
+
+	dac33_write_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a);
+	dac33_write_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b);
+
+	return 0;
+}
+
+static int dac33_soc_probe(struct snd_soc_component *component)
+{
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	dac33->component = component;
+
+	/* Read the tlv320dac33 ID registers */
+	ret = dac33_hard_power(component, 1);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to power up component: %d\n", ret);
+		goto err_power;
+	}
+	ret = dac33_read_id(component);
+	dac33_hard_power(component, 0);
+
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to read chip ID: %d\n", ret);
+		ret = -ENODEV;
+		goto err_power;
+	}
+
+	/* Check if the IRQ number is valid and request it */
+	if (dac33->irq >= 0) {
+		ret = request_irq(dac33->irq, dac33_interrupt_handler,
+				  IRQF_TRIGGER_RISING,
+				  component->name, component);
+		if (ret < 0) {
+			dev_err(component->dev, "Could not request IRQ%d (%d)\n",
+						dac33->irq, ret);
+			dac33->irq = -1;
+		}
+		if (dac33->irq != -1) {
+			INIT_WORK(&dac33->work, dac33_work);
+		}
+	}
+
+	/* Only add the FIFO controls, if we have valid IRQ number */
+	if (dac33->irq >= 0)
+		snd_soc_add_component_controls(component, dac33_mode_snd_controls,
+				     ARRAY_SIZE(dac33_mode_snd_controls));
+
+err_power:
+	return ret;
+}
+
+static void dac33_soc_remove(struct snd_soc_component *component)
+{
+	struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
+
+	if (dac33->irq >= 0) {
+		free_irq(dac33->irq, dac33->component);
+		flush_work(&dac33->work);
+	}
+}
+
+static const struct snd_soc_component_driver soc_component_dev_tlv320dac33 = {
+	.read			= dac33_read_reg_cache,
+	.write			= dac33_write_locked,
+	.set_bias_level		= dac33_set_bias_level,
+	.probe			= dac33_soc_probe,
+	.remove			= dac33_soc_remove,
+	.controls		= dac33_snd_controls,
+	.num_controls		= ARRAY_SIZE(dac33_snd_controls),
+	.dapm_widgets		= dac33_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(dac33_dapm_widgets),
+	.dapm_routes		= audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(audio_map),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+#define DAC33_RATES	(SNDRV_PCM_RATE_44100 | \
+			 SNDRV_PCM_RATE_48000)
+#define DAC33_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops dac33_dai_ops = {
+	.startup	= dac33_startup,
+	.shutdown	= dac33_shutdown,
+	.hw_params	= dac33_hw_params,
+	.trigger	= dac33_pcm_trigger,
+	.delay		= dac33_dai_delay,
+	.set_sysclk	= dac33_set_dai_sysclk,
+	.set_fmt	= dac33_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver dac33_dai = {
+	.name = "tlv320dac33-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = DAC33_RATES,
+		.formats = DAC33_FORMATS,
+		.sig_bits = 24,
+	},
+	.ops = &dac33_dai_ops,
+};
+
+static int dac33_i2c_probe(struct i2c_client *client,
+			   const struct i2c_device_id *id)
+{
+	struct tlv320dac33_platform_data *pdata;
+	struct tlv320dac33_priv *dac33;
+	int ret, i;
+
+	if (client->dev.platform_data == NULL) {
+		dev_err(&client->dev, "Platform data not set\n");
+		return -ENODEV;
+	}
+	pdata = client->dev.platform_data;
+
+	dac33 = devm_kzalloc(&client->dev, sizeof(struct tlv320dac33_priv),
+			     GFP_KERNEL);
+	if (dac33 == NULL)
+		return -ENOMEM;
+
+	dac33->reg_cache = devm_kmemdup(&client->dev,
+					dac33_reg,
+					ARRAY_SIZE(dac33_reg) * sizeof(u8),
+					GFP_KERNEL);
+	if (!dac33->reg_cache)
+		return -ENOMEM;
+
+	dac33->i2c = client;
+	mutex_init(&dac33->mutex);
+	spin_lock_init(&dac33->lock);
+
+	i2c_set_clientdata(client, dac33);
+
+	dac33->power_gpio = pdata->power_gpio;
+	dac33->burst_bclkdiv = pdata->burst_bclkdiv;
+	dac33->keep_bclk = pdata->keep_bclk;
+	dac33->mode1_latency = pdata->mode1_latency;
+	if (!dac33->mode1_latency)
+		dac33->mode1_latency = 10000; /* 10ms */
+	dac33->irq = client->irq;
+	/* Disable FIFO use by default */
+	dac33->fifo_mode = DAC33_FIFO_BYPASS;
+
+	/* Check if the reset GPIO number is valid and request it */
+	if (dac33->power_gpio >= 0) {
+		ret = gpio_request(dac33->power_gpio, "tlv320dac33 reset");
+		if (ret < 0) {
+			dev_err(&client->dev,
+				"Failed to request reset GPIO (%d)\n",
+				dac33->power_gpio);
+			goto err_gpio;
+		}
+		gpio_direction_output(dac33->power_gpio, 0);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++)
+		dac33->supplies[i].supply = dac33_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies),
+				 dac33->supplies);
+
+	if (ret != 0) {
+		dev_err(&client->dev, "Failed to request supplies: %d\n", ret);
+		goto err_get;
+	}
+
+	ret = devm_snd_soc_register_component(&client->dev,
+			&soc_component_dev_tlv320dac33, &dac33_dai, 1);
+	if (ret < 0)
+		goto err_get;
+
+	return ret;
+err_get:
+	if (dac33->power_gpio >= 0)
+		gpio_free(dac33->power_gpio);
+err_gpio:
+	return ret;
+}
+
+static int dac33_i2c_remove(struct i2c_client *client)
+{
+	struct tlv320dac33_priv *dac33 = i2c_get_clientdata(client);
+
+	if (unlikely(dac33->chip_power))
+		dac33_hard_power(dac33->component, 0);
+
+	if (dac33->power_gpio >= 0)
+		gpio_free(dac33->power_gpio);
+
+	return 0;
+}
+
+static const struct i2c_device_id tlv320dac33_i2c_id[] = {
+	{
+		.name = "tlv320dac33",
+		.driver_data = 0,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, tlv320dac33_i2c_id);
+
+static struct i2c_driver tlv320dac33_i2c_driver = {
+	.driver = {
+		.name = "tlv320dac33-codec",
+	},
+	.probe		= dac33_i2c_probe,
+	.remove		= dac33_i2c_remove,
+	.id_table	= tlv320dac33_i2c_id,
+};
+
+module_i2c_driver(tlv320dac33_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320dac33.h b/sound/soc/codecs/tlv320dac33.h
new file mode 100644
index 0000000..ed69670
--- /dev/null
+++ b/sound/soc/codecs/tlv320dac33.h
@@ -0,0 +1,264 @@
+/*
+ * ALSA SoC Texas Instruments TLV320DAC33 codec driver
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * Copyright:   (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TLV320DAC33_H
+#define __TLV320DAC33_H
+
+#define DAC33_PAGE_SELECT		0x00
+#define DAC33_PWR_CTRL			0x01
+#define DAC33_PLL_CTRL_A		0x02
+#define DAC33_PLL_CTRL_B		0x03
+#define DAC33_PLL_CTRL_C		0x04
+#define DAC33_PLL_CTRL_D		0x05
+#define DAC33_PLL_CTRL_E		0x06
+#define DAC33_INT_OSC_CTRL		0x07
+#define DAC33_INT_OSC_FREQ_RAT_A	0x08
+#define DAC33_INT_OSC_FREQ_RAT_B	0x09
+#define DAC33_INT_OSC_DAC_RATIO_SET	0x0A
+#define DAC33_CALIB_TIME		0x0B
+#define DAC33_INT_OSC_CTRL_B		0x0C
+#define DAC33_INT_OSC_CTRL_C		0x0D
+#define DAC33_INT_OSC_STATUS		0x0E
+#define DAC33_INT_OSC_DAC_RATIO_READ	0x0F
+#define DAC33_INT_OSC_FREQ_RAT_READ_A	0x10
+#define DAC33_INT_OSC_FREQ_RAT_READ_B	0x11
+#define DAC33_SER_AUDIOIF_CTRL_A	0x12
+#define DAC33_SER_AUDIOIF_CTRL_B	0x13
+#define DAC33_SER_AUDIOIF_CTRL_C	0x14
+#define DAC33_FIFO_CTRL_A		0x15
+#define DAC33_UTHR_MSB			0x16
+#define DAC33_UTHR_LSB			0x17
+#define DAC33_ATHR_MSB			0x18
+#define DAC33_ATHR_LSB			0x19
+#define DAC33_LTHR_MSB			0x1A
+#define DAC33_LTHR_LSB			0x1B
+#define DAC33_PREFILL_MSB		0x1C
+#define DAC33_PREFILL_LSB		0x1D
+#define DAC33_NSAMPLE_MSB		0x1E
+#define DAC33_NSAMPLE_LSB		0x1F
+#define DAC33_FIFO_WPTR_MSB		0x20
+#define DAC33_FIFO_WPTR_LSB		0x21
+#define DAC33_FIFO_RPTR_MSB		0x22
+#define DAC33_FIFO_RPTR_LSB		0x23
+#define DAC33_FIFO_DEPTH_MSB		0x24
+#define DAC33_FIFO_DEPTH_LSB		0x25
+#define DAC33_SAMPLES_REMAINING_MSB	0x26
+#define DAC33_SAMPLES_REMAINING_LSB	0x27
+#define DAC33_FIFO_IRQ_FLAG		0x28
+#define DAC33_FIFO_IRQ_MASK		0x29
+#define DAC33_FIFO_IRQ_MODE_A		0x2A
+#define DAC33_FIFO_IRQ_MODE_B		0x2B
+#define DAC33_DAC_CTRL_A		0x2C
+#define DAC33_DAC_CTRL_B		0x2D
+#define DAC33_DAC_CTRL_C		0x2E
+#define DAC33_LDAC_DIG_VOL_CTRL		0x2F
+#define DAC33_RDAC_DIG_VOL_CTRL		0x30
+#define DAC33_DAC_STATUS_FLAGS		0x31
+#define DAC33_ASRC_CTRL_A		0x32
+#define DAC33_ASRC_CTRL_B		0x33
+#define DAC33_SRC_REF_CLK_RATIO_A	0x34
+#define DAC33_SRC_REF_CLK_RATIO_B	0x35
+#define DAC33_SRC_EST_REF_CLK_RATIO_A	0x36
+#define DAC33_SRC_EST_REF_CLK_RATIO_B	0x37
+#define DAC33_INTP_CTRL_A		0x38
+#define DAC33_INTP_CTRL_B		0x39
+/* Registers 0x3A - 0x3F Reserved */
+#define DAC33_LDAC_PWR_CTRL		0x40
+#define DAC33_RDAC_PWR_CTRL		0x41
+#define DAC33_OUT_AMP_CM_CTRL		0x42
+#define DAC33_OUT_AMP_PWR_CTRL		0x43
+#define DAC33_OUT_AMP_CTRL		0x44
+#define DAC33_LINEL_TO_LLO_VOL		0x45
+/* Registers 0x45 - 0x47 Reserved */
+#define DAC33_LINER_TO_RLO_VOL		0x48
+#define DAC33_ANA_VOL_SOFT_STEP_CTRL	0x49
+#define DAC33_OSC_TRIM			0x4A
+/* Registers 0x4B - 0x7C Reserved */
+#define DAC33_DEVICE_ID_MSB		0x7D
+#define DAC33_DEVICE_ID_LSB		0x7E
+#define DAC33_DEVICE_REV_ID		0x7F
+
+#define DAC33_CACHEREGNUM               128
+
+/* Bit definitions */
+
+/* DAC33_PWR_CTRL (0x01) */
+#define DAC33_DACRPDNB			(0x01 << 0)
+#define DAC33_DACLPDNB			(0x01 << 1)
+#define DAC33_OSCPDNB			(0x01 << 2)
+#define DAC33_PLLPDNB			(0x01 << 3)
+#define DAC33_PDNALLB			(0x01 << 4)
+#define DAC33_SOFT_RESET		(0x01 << 7)
+
+/* DAC33_INT_OSC_CTRL (0x07) */
+#define DAC33_REFSEL			(0x01 << 1)
+
+/* DAC33_INT_OSC_CTRL_B (0x0C) */
+#define DAC33_ADJSTEP(x)		(x << 0)
+#define DAC33_ADJTHRSHLD(x)		(x << 4)
+
+/* DAC33_INT_OSC_CTRL_C (0x0D) */
+#define DAC33_REFDIV(x)			(x << 4)
+
+/* DAC33_INT_OSC_STATUS (0x0E) */
+#define DAC33_OSCSTATUS_IDLE_CALIB	(0x00)
+#define DAC33_OSCSTATUS_NORMAL		(0x01)
+#define DAC33_OSCSTATUS_ADJUSTMENT	(0x03)
+#define DAC33_OSCSTATUS_NOT_USED	(0x02)
+
+/* DAC33_SER_AUDIOIF_CTRL_A (0x12) */
+#define DAC33_MSWCLK			(0x01 << 0)
+#define DAC33_MSBCLK			(0x01 << 1)
+#define DAC33_AFMT_MASK			(0x03 << 2)
+#define DAC33_AFMT_I2S			(0x00 << 2)
+#define DAC33_AFMT_DSP			(0x01 << 2)
+#define DAC33_AFMT_RIGHT_J		(0x02 << 2)
+#define DAC33_AFMT_LEFT_J		(0x03 << 2)
+#define DAC33_WLEN_MASK			(0x03 << 4)
+#define DAC33_WLEN_16			(0x00 << 4)
+#define DAC33_WLEN_20			(0x01 << 4)
+#define DAC33_WLEN_24			(0x02 << 4)
+#define DAC33_WLEN_32			(0x03 << 4)
+#define DAC33_NCYCL_MASK		(0x03 << 6)
+#define DAC33_NCYCL_16			(0x00 << 6)
+#define DAC33_NCYCL_20			(0x01 << 6)
+#define DAC33_NCYCL_24			(0x02 << 6)
+#define DAC33_NCYCL_32			(0x03 << 6)
+
+/* DAC33_SER_AUDIOIF_CTRL_B (0x13) */
+#define DAC33_DATA_DELAY_MASK		(0x03 << 2)
+#define DAC33_DATA_DELAY(x)		(x << 2)
+#define DAC33_BCLKON			(0x01 << 5)
+
+/* DAC33_FIFO_CTRL_A (0x15) */
+#define DAC33_WIDTH				(0x01 << 0)
+#define DAC33_FBYPAS				(0x01 << 1)
+#define DAC33_FAUTO				(0x01 << 2)
+#define DAC33_FIFOFLUSH			(0x01 << 3)
+
+/*
+ * UTHR, ATHR, LTHR, PREFILL, NSAMPLE (0x16 - 0x1F)
+ * 13-bit values
+*/
+#define DAC33_THRREG(x)			(((x) & 0x1FFF) << 3)
+
+/* DAC33_FIFO_IRQ_MASK (0x29) */
+#define DAC33_MNS			(0x01 << 0)
+#define DAC33_MPS			(0x01 << 1)
+#define DAC33_MAT			(0x01 << 2)
+#define DAC33_MLT			(0x01 << 3)
+#define DAC33_MUT			(0x01 << 4)
+#define DAC33_MUF			(0x01 << 5)
+#define DAC33_MOF			(0x01 << 6)
+
+#define DAC33_FIFO_IRQ_MODE_MASK	(0x03)
+#define DAC33_FIFO_IRQ_MODE_RISING	(0x00)
+#define DAC33_FIFO_IRQ_MODE_FALLING	(0x01)
+#define DAC33_FIFO_IRQ_MODE_LEVEL	(0x02)
+#define DAC33_FIFO_IRQ_MODE_EDGE	(0x03)
+
+/* DAC33_FIFO_IRQ_MODE_A (0x2A) */
+#define DAC33_UTM(x)			(x << 0)
+#define DAC33_UFM(x)			(x << 2)
+#define DAC33_OFM(x)			(x << 4)
+
+/* DAC33_FIFO_IRQ_MODE_B (0x2B) */
+#define DAC33_NSM(x)			(x << 0)
+#define DAC33_PSM(x)			(x << 2)
+#define DAC33_ATM(x)			(x << 4)
+#define DAC33_LTM(x)			(x << 6)
+
+/* DAC33_DAC_CTRL_A (0x2C) */
+#define DAC33_DACRATE(x)		(x << 0)
+#define DAC33_DACDUAL			(0x01 << 4)
+#define DAC33_DACLKSEL_MASK		(0x03 << 5)
+#define DAC33_DACLKSEL_INTSOC		(0x00 << 5)
+#define DAC33_DACLKSEL_PLL		(0x01 << 5)
+#define DAC33_DACLKSEL_MCLK		(0x02 << 5)
+#define DAC33_DACLKSEL_BCLK		(0x03 << 5)
+
+/* DAC33_DAC_CTRL_B (0x2D) */
+#define DAC33_DACSRCR_MASK		(0x03 << 0)
+#define DAC33_DACSRCR_MUTE		(0x00 << 0)
+#define DAC33_DACSRCR_RIGHT		(0x01 << 0)
+#define DAC33_DACSRCR_LEFT		(0x02 << 0)
+#define DAC33_DACSRCR_MONOMIX		(0x03 << 0)
+#define DAC33_DACSRCL_MASK		(0x03 << 2)
+#define DAC33_DACSRCL_MUTE		(0x00 << 2)
+#define DAC33_DACSRCL_LEFT		(0x01 << 2)
+#define DAC33_DACSRCL_RIGHT		(0x02 << 2)
+#define DAC33_DACSRCL_MONOMIX		(0x03 << 2)
+#define DAC33_DVOLSTEP_MASK		(0x03 << 4)
+#define DAC33_DVOLSTEP_SS_PERFS		(0x00 << 4)
+#define DAC33_DVOLSTEP_SS_PER2FS	(0x01 << 4)
+#define DAC33_DVOLSTEP_SS_DISABLED	(0x02 << 4)
+#define DAC33_DVOLCTRL_MASK		(0x03 << 6)
+#define DAC33_DVOLCTRL_LR_INDEPENDENT1	(0x00 << 6)
+#define DAC33_DVOLCTRL_LR_RIGHT_CONTROL	(0x01 << 6)
+#define DAC33_DVOLCTRL_LR_LEFT_CONTROL	(0x02 << 6)
+#define DAC33_DVOLCTRL_LR_INDEPENDENT2	(0x03 << 6)
+
+/* DAC33_DAC_CTRL_C (0x2E) */
+#define DAC33_DEEMENR			(0x01 << 0)
+#define DAC33_EFFENR			(0x01 << 1)
+#define DAC33_DEEMENL			(0x01 << 2)
+#define DAC33_EFFENL			(0x01 << 3)
+#define DAC33_EN3D			(0x01 << 4)
+#define DAC33_RESYNMUTE			(0x01 << 5)
+#define DAC33_RESYNEN			(0x01 << 6)
+
+/* DAC33_ASRC_CTRL_A (0x32) */
+#define DAC33_SRCBYP			(0x01 << 0)
+#define DAC33_SRCLKSEL_MASK		(0x03 << 1)
+#define DAC33_SRCLKSEL_INTSOC		(0x00 << 1)
+#define DAC33_SRCLKSEL_PLL		(0x01 << 1)
+#define DAC33_SRCLKSEL_MCLK		(0x02 << 1)
+#define DAC33_SRCLKSEL_BCLK		(0x03 << 1)
+#define DAC33_SRCLKDIV(x)		(x << 3)
+
+/* DAC33_ASRC_CTRL_B (0x33) */
+#define DAC33_SRCSETUP(x)		(x << 0)
+#define DAC33_SRCREFSEL			(0x01 << 4)
+#define DAC33_SRCREFDIV(x)		(x << 5)
+
+/* DAC33_INTP_CTRL_A (0x38) */
+#define DAC33_INTPSEL			(0x01 << 0)
+#define DAC33_INTPM_MASK		(0x03 << 1)
+#define DAC33_INTPM_ALOW_OPENDRAIN	(0x00 << 1)
+#define DAC33_INTPM_ALOW		(0x01 << 1)
+#define DAC33_INTPM_AHIGH		(0x02 << 1)
+
+/* DAC33_LDAC_PWR_CTRL (0x40) */
+/* DAC33_RDAC_PWR_CTRL (0x41) */
+#define DAC33_DACLRNUM			(0x01 << 2)
+#define DAC33_LROUT_GAIN(x)		(x << 0)
+
+/* DAC33_ANA_VOL_SOFT_STEP_CTRL (0x49) */
+#define DAC33_VOLCLKSEL			(0x01 << 0)
+#define DAC33_VOLCLKEN			(0x01 << 1)
+#define DAC33_VOLBYPASS			(0x01 << 2)
+
+#define TLV320DAC33_MCLK		0
+#define TLV320DAC33_SLEEPCLK		1
+
+#endif /* __TLV320DAC33_H */
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
new file mode 100644
index 0000000..616cd4b
--- /dev/null
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -0,0 +1,342 @@
+/*
+ * ALSA SoC Texas Instruments TPA6130A2 headset stereo amplifier driver
+ *
+ * Copyright (C) Nokia Corporation
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/tpa6130a2-plat.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+
+#include "tpa6130a2.h"
+
+enum tpa_model {
+	TPA6130A2,
+	TPA6140A2,
+};
+
+/* This struct is used to save the context */
+struct tpa6130a2_data {
+	struct device *dev;
+	struct regmap *regmap;
+	struct regulator *supply;
+	int power_gpio;
+	enum tpa_model id;
+};
+
+static int tpa6130a2_power(struct tpa6130a2_data *data, bool enable)
+{
+	int ret = 0, ret2;
+
+	if (enable) {
+		ret = regulator_enable(data->supply);
+		if (ret != 0) {
+			dev_err(data->dev,
+				"Failed to enable supply: %d\n", ret);
+			return ret;
+		}
+		/* Power on */
+		if (data->power_gpio >= 0)
+			gpio_set_value(data->power_gpio, 1);
+
+		/* Sync registers */
+		regcache_cache_only(data->regmap, false);
+		ret = regcache_sync(data->regmap);
+		if (ret != 0) {
+			dev_err(data->dev,
+				"Failed to sync registers: %d\n", ret);
+			regcache_cache_only(data->regmap, true);
+			if (data->power_gpio >= 0)
+				gpio_set_value(data->power_gpio, 0);
+			ret2 = regulator_disable(data->supply);
+			if (ret2 != 0)
+				dev_err(data->dev,
+					"Failed to disable supply: %d\n", ret2);
+			return ret;
+		}
+	} else {
+		/* Powered off device does not retain registers. While device
+		 * is off, any register updates (i.e. volume changes) should
+		 * happen in cache only.
+		 */
+		regcache_mark_dirty(data->regmap);
+		regcache_cache_only(data->regmap, true);
+
+		/* Power off */
+		if (data->power_gpio >= 0)
+			gpio_set_value(data->power_gpio, 0);
+
+		ret = regulator_disable(data->supply);
+		if (ret != 0) {
+			dev_err(data->dev,
+				"Failed to disable supply: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int tpa6130a2_power_event(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kctrl, int event)
+{
+	struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+	struct tpa6130a2_data *data = snd_soc_component_get_drvdata(c);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* Before widget power up: turn chip on, sync registers */
+		return tpa6130a2_power(data, true);
+	} else {
+		/* After widget power down: turn chip off */
+		return tpa6130a2_power(data, false);
+	}
+}
+
+/*
+ * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going
+ * down in gain.
+ */
+static const DECLARE_TLV_DB_RANGE(tpa6130_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(-5950, 600, 0),
+	2, 3, TLV_DB_SCALE_ITEM(-5000, 250, 0),
+	4, 5, TLV_DB_SCALE_ITEM(-4550, 160, 0),
+	6, 7, TLV_DB_SCALE_ITEM(-4140, 190, 0),
+	8, 9, TLV_DB_SCALE_ITEM(-3650, 120, 0),
+	10, 11, TLV_DB_SCALE_ITEM(-3330, 160, 0),
+	12, 13, TLV_DB_SCALE_ITEM(-3040, 180, 0),
+	14, 20, TLV_DB_SCALE_ITEM(-2710, 110, 0),
+	21, 37, TLV_DB_SCALE_ITEM(-1960, 74, 0),
+	38, 63, TLV_DB_SCALE_ITEM(-720, 45, 0)
+);
+
+static const struct snd_kcontrol_new tpa6130a2_controls[] = {
+	SOC_SINGLE_TLV("Headphone Playback Volume",
+		       TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0,
+		       tpa6130_tlv),
+};
+
+static const DECLARE_TLV_DB_RANGE(tpa6140_tlv,
+	0, 8, TLV_DB_SCALE_ITEM(-5900, 400, 0),
+	9, 16, TLV_DB_SCALE_ITEM(-2500, 200, 0),
+	17, 31, TLV_DB_SCALE_ITEM(-1000, 100, 0)
+);
+
+static const struct snd_kcontrol_new tpa6140a2_controls[] = {
+	SOC_SINGLE_TLV("Headphone Playback Volume",
+		       TPA6130A2_REG_VOL_MUTE, 1, 0x1f, 0,
+		       tpa6140_tlv),
+};
+
+static int tpa6130a2_component_probe(struct snd_soc_component *component)
+{
+	struct tpa6130a2_data *data = snd_soc_component_get_drvdata(component);
+
+	if (data->id == TPA6140A2)
+		return snd_soc_add_component_controls(component,
+			tpa6140a2_controls, ARRAY_SIZE(tpa6140a2_controls));
+	else
+		return snd_soc_add_component_controls(component,
+			tpa6130a2_controls, ARRAY_SIZE(tpa6130a2_controls));
+}
+
+static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("LEFTIN"),
+	SND_SOC_DAPM_INPUT("RIGHTIN"),
+	SND_SOC_DAPM_OUTPUT("HPLEFT"),
+	SND_SOC_DAPM_OUTPUT("HPRIGHT"),
+
+	SND_SOC_DAPM_PGA("Left Mute", TPA6130A2_REG_VOL_MUTE,
+			 TPA6130A2_HP_EN_L_SHIFT, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Mute", TPA6130A2_REG_VOL_MUTE,
+			 TPA6130A2_HP_EN_R_SHIFT, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Left PGA", TPA6130A2_REG_CONTROL,
+			 TPA6130A2_HP_EN_L_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right PGA", TPA6130A2_REG_CONTROL,
+			 TPA6130A2_HP_EN_R_SHIFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Power", TPA6130A2_REG_CONTROL,
+			    TPA6130A2_SWS_SHIFT, 1, tpa6130a2_power_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route tpa6130a2_dapm_routes[] = {
+	{ "Left PGA", NULL, "LEFTIN" },
+	{ "Right PGA", NULL, "RIGHTIN" },
+
+	{ "Left Mute", NULL, "Left PGA" },
+	{ "Right Mute", NULL, "Right PGA" },
+
+	{ "HPLEFT", NULL, "Left Mute" },
+	{ "HPRIGHT", NULL, "Right Mute" },
+
+	{ "Left PGA", NULL, "Power" },
+	{ "Right PGA", NULL, "Power" },
+};
+
+static const struct snd_soc_component_driver tpa6130a2_component_driver = {
+	.name = "tpa6130a2",
+	.probe = tpa6130a2_component_probe,
+	.dapm_widgets = tpa6130a2_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tpa6130a2_dapm_widgets),
+	.dapm_routes = tpa6130a2_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(tpa6130a2_dapm_routes),
+};
+
+static const struct reg_default tpa6130a2_reg_defaults[] = {
+	{ TPA6130A2_REG_CONTROL, TPA6130A2_SWS },
+	{ TPA6130A2_REG_VOL_MUTE, TPA6130A2_MUTE_R | TPA6130A2_MUTE_L },
+};
+
+static const struct regmap_config tpa6130a2_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = TPA6130A2_REG_VERSION,
+	.reg_defaults = tpa6130a2_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tpa6130a2_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int tpa6130a2_probe(struct i2c_client *client,
+			   const struct i2c_device_id *id)
+{
+	struct device *dev;
+	struct tpa6130a2_data *data;
+	struct tpa6130a2_platform_data *pdata = client->dev.platform_data;
+	struct device_node *np = client->dev.of_node;
+	const char *regulator;
+	unsigned int version;
+	int ret;
+
+	dev = &client->dev;
+
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->dev = dev;
+
+	data->regmap = devm_regmap_init_i2c(client, &tpa6130a2_regmap_config);
+	if (IS_ERR(data->regmap))
+		return PTR_ERR(data->regmap);
+
+	if (pdata) {
+		data->power_gpio = pdata->power_gpio;
+	} else if (np) {
+		data->power_gpio = of_get_named_gpio(np, "power-gpio", 0);
+	} else {
+		dev_err(dev, "Platform data not set\n");
+		dump_stack();
+		return -ENODEV;
+	}
+
+	i2c_set_clientdata(client, data);
+
+	data->id = id->driver_data;
+
+	if (data->power_gpio >= 0) {
+		ret = devm_gpio_request(dev, data->power_gpio,
+					"tpa6130a2 enable");
+		if (ret < 0) {
+			dev_err(dev, "Failed to request power GPIO (%d)\n",
+				data->power_gpio);
+			return ret;
+		}
+		gpio_direction_output(data->power_gpio, 0);
+	}
+
+	switch (data->id) {
+	default:
+		dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n",
+			 data->id);
+		/* fall through */
+	case TPA6130A2:
+		regulator = "Vdd";
+		break;
+	case TPA6140A2:
+		regulator = "AVdd";
+		break;
+	}
+
+	data->supply = devm_regulator_get(dev, regulator);
+	if (IS_ERR(data->supply)) {
+		ret = PTR_ERR(data->supply);
+		dev_err(dev, "Failed to request supply: %d\n", ret);
+		return ret;
+	}
+
+	ret = tpa6130a2_power(data, true);
+	if (ret != 0)
+		return ret;
+
+
+	/* Read version */
+	regmap_read(data->regmap, TPA6130A2_REG_VERSION, &version);
+	version &= TPA6130A2_VERSION_MASK;
+	if ((version != 1) && (version != 2))
+		dev_warn(dev, "UNTESTED version detected (%d)\n", version);
+
+	/* Disable the chip */
+	ret = tpa6130a2_power(data, false);
+	if (ret != 0)
+		return ret;
+
+	return devm_snd_soc_register_component(&client->dev,
+			&tpa6130a2_component_driver, NULL, 0);
+}
+
+static const struct i2c_device_id tpa6130a2_id[] = {
+	{ "tpa6130a2", TPA6130A2 },
+	{ "tpa6140a2", TPA6140A2 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tpa6130a2_id);
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id tpa6130a2_of_match[] = {
+	{ .compatible = "ti,tpa6130a2", },
+	{ .compatible = "ti,tpa6140a2" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tpa6130a2_of_match);
+#endif
+
+static struct i2c_driver tpa6130a2_i2c_driver = {
+	.driver = {
+		.name = "tpa6130a2",
+		.of_match_table = of_match_ptr(tpa6130a2_of_match),
+	},
+	.probe = tpa6130a2_probe,
+	.id_table = tpa6130a2_id,
+};
+
+module_i2c_driver(tpa6130a2_i2c_driver);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tpa6130a2.h b/sound/soc/codecs/tpa6130a2.h
new file mode 100644
index 0000000..f19cad5
--- /dev/null
+++ b/sound/soc/codecs/tpa6130a2.h
@@ -0,0 +1,60 @@
+/*
+ * ALSA SoC TPA6130A2 amplifier driver
+ *
+ * Copyright (C) Nokia Corporation
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TPA6130A2_H__
+#define __TPA6130A2_H__
+
+/* Register addresses */
+#define TPA6130A2_REG_CONTROL		0x01
+#define TPA6130A2_REG_VOL_MUTE		0x02
+#define TPA6130A2_REG_OUT_IMPEDANCE	0x03
+#define TPA6130A2_REG_VERSION		0x04
+
+/* Register bits */
+/* TPA6130A2_REG_CONTROL (0x01) */
+#define TPA6130A2_SWS_SHIFT		0
+#define TPA6130A2_SWS			(0x01 << TPA6130A2_SWS_SHIFT)
+#define TPA6130A2_TERMAL		(0x01 << 1)
+#define TPA6130A2_MODE(x)		(x << 4)
+#define TPA6130A2_MODE_STEREO		(0x00)
+#define TPA6130A2_MODE_DUAL_MONO	(0x01)
+#define TPA6130A2_MODE_BRIDGE		(0x02)
+#define TPA6130A2_MODE_MASK		(0x03)
+#define TPA6130A2_HP_EN_R_SHIFT		6
+#define TPA6130A2_HP_EN_R		(0x01 << TPA6130A2_HP_EN_R_SHIFT)
+#define TPA6130A2_HP_EN_L_SHIFT		7
+#define TPA6130A2_HP_EN_L		(0x01 << TPA6130A2_HP_EN_L_SHIFT)
+
+/* TPA6130A2_REG_VOL_MUTE (0x02) */
+#define TPA6130A2_VOLUME(x)		((x & 0x3f) << 0)
+#define TPA6130A2_MUTE_R		(0x01 << 6)
+#define TPA6130A2_MUTE_L		(0x01 << 7)
+
+/* TPA6130A2_REG_OUT_IMPEDANCE (0x03) */
+#define TPA6130A2_HIZ_R			(0x01 << 0)
+#define TPA6130A2_HIZ_L			(0x01 << 1)
+
+/* TPA6130A2_REG_VERSION (0x04) */
+#define TPA6130A2_VERSION_MASK		(0x0f)
+
+#endif /* __TPA6130A2_H__ */
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
new file mode 100644
index 0000000..1271e7e
--- /dev/null
+++ b/sound/soc/codecs/ts3a227e.c
@@ -0,0 +1,400 @@
+/*
+ * TS3A227E Autonomous Audio Accessory Detection and Configuration Switch
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/acpi.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+
+#include "ts3a227e.h"
+
+struct ts3a227e {
+	struct device *dev;
+	struct regmap *regmap;
+	struct snd_soc_jack *jack;
+	bool plugged;
+	bool mic_present;
+	unsigned int buttons_held;
+	int irq;
+};
+
+/* Button values to be reported on the jack */
+static const int ts3a227e_buttons[] = {
+	SND_JACK_BTN_0,
+	SND_JACK_BTN_1,
+	SND_JACK_BTN_2,
+	SND_JACK_BTN_3,
+};
+
+#define TS3A227E_NUM_BUTTONS 4
+#define TS3A227E_JACK_MASK (SND_JACK_HEADPHONE | \
+			    SND_JACK_MICROPHONE | \
+			    SND_JACK_BTN_0 | \
+			    SND_JACK_BTN_1 | \
+			    SND_JACK_BTN_2 | \
+			    SND_JACK_BTN_3)
+
+/* TS3A227E registers */
+#define TS3A227E_REG_DEVICE_ID		0x00
+#define TS3A227E_REG_INTERRUPT		0x01
+#define TS3A227E_REG_KP_INTERRUPT	0x02
+#define TS3A227E_REG_INTERRUPT_DISABLE	0x03
+#define TS3A227E_REG_SETTING_1		0x04
+#define TS3A227E_REG_SETTING_2		0x05
+#define TS3A227E_REG_SETTING_3		0x06
+#define TS3A227E_REG_SWITCH_CONTROL_1	0x07
+#define TS3A227E_REG_SWITCH_CONTROL_2	0x08
+#define TS3A227E_REG_SWITCH_STATUS_1	0x09
+#define TS3A227E_REG_SWITCH_STATUS_2	0x0a
+#define TS3A227E_REG_ACCESSORY_STATUS	0x0b
+#define TS3A227E_REG_ADC_OUTPUT		0x0c
+#define TS3A227E_REG_KP_THRESHOLD_1	0x0d
+#define TS3A227E_REG_KP_THRESHOLD_2	0x0e
+#define TS3A227E_REG_KP_THRESHOLD_3	0x0f
+
+/* TS3A227E_REG_INTERRUPT 0x01 */
+#define INS_REM_EVENT 0x01
+#define DETECTION_COMPLETE_EVENT 0x02
+
+/* TS3A227E_REG_KP_INTERRUPT 0x02 */
+#define PRESS_MASK(idx) (0x01 << (2 * (idx)))
+#define RELEASE_MASK(idx) (0x02 << (2 * (idx)))
+
+/* TS3A227E_REG_INTERRUPT_DISABLE 0x03 */
+#define INS_REM_INT_DISABLE 0x01
+#define DETECTION_COMPLETE_INT_DISABLE 0x02
+#define ADC_COMPLETE_INT_DISABLE 0x04
+#define INTB_DISABLE 0x08
+
+/* TS3A227E_REG_SETTING_2 0x05 */
+#define KP_ENABLE 0x04
+
+/* TS3A227E_REG_SETTING_3 0x06 */
+#define MICBIAS_SETTING_SFT (3)
+#define MICBIAS_SETTING_MASK (0x7 << MICBIAS_SETTING_SFT)
+
+/* TS3A227E_REG_ACCESSORY_STATUS  0x0b */
+#define TYPE_3_POLE 0x01
+#define TYPE_4_POLE_OMTP 0x02
+#define TYPE_4_POLE_STANDARD 0x04
+#define JACK_INSERTED 0x08
+#define EITHER_MIC_MASK (TYPE_4_POLE_OMTP | TYPE_4_POLE_STANDARD)
+
+static const struct reg_default ts3a227e_reg_defaults[] = {
+	{ TS3A227E_REG_DEVICE_ID, 0x10 },
+	{ TS3A227E_REG_INTERRUPT, 0x00 },
+	{ TS3A227E_REG_KP_INTERRUPT, 0x00 },
+	{ TS3A227E_REG_INTERRUPT_DISABLE, 0x08 },
+	{ TS3A227E_REG_SETTING_1, 0x23 },
+	{ TS3A227E_REG_SETTING_2, 0x00 },
+	{ TS3A227E_REG_SETTING_3, 0x0e },
+	{ TS3A227E_REG_SWITCH_CONTROL_1, 0x00 },
+	{ TS3A227E_REG_SWITCH_CONTROL_2, 0x00 },
+	{ TS3A227E_REG_SWITCH_STATUS_1, 0x0c },
+	{ TS3A227E_REG_SWITCH_STATUS_2, 0x00 },
+	{ TS3A227E_REG_ACCESSORY_STATUS, 0x00 },
+	{ TS3A227E_REG_ADC_OUTPUT, 0x00 },
+	{ TS3A227E_REG_KP_THRESHOLD_1, 0x20 },
+	{ TS3A227E_REG_KP_THRESHOLD_2, 0x40 },
+	{ TS3A227E_REG_KP_THRESHOLD_3, 0x68 },
+};
+
+static bool ts3a227e_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TS3A227E_REG_DEVICE_ID ... TS3A227E_REG_KP_THRESHOLD_3:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool ts3a227e_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TS3A227E_REG_INTERRUPT_DISABLE ... TS3A227E_REG_SWITCH_CONTROL_2:
+	case TS3A227E_REG_KP_THRESHOLD_1 ... TS3A227E_REG_KP_THRESHOLD_3:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool ts3a227e_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TS3A227E_REG_INTERRUPT ... TS3A227E_REG_INTERRUPT_DISABLE:
+	case TS3A227E_REG_SETTING_2:
+	case TS3A227E_REG_SWITCH_STATUS_1 ... TS3A227E_REG_ADC_OUTPUT:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void ts3a227e_jack_report(struct ts3a227e *ts3a227e)
+{
+	unsigned int i;
+	int report = 0;
+
+	if (!ts3a227e->jack)
+		return;
+
+	if (ts3a227e->plugged)
+		report = SND_JACK_HEADPHONE;
+	if (ts3a227e->mic_present)
+		report |= SND_JACK_MICROPHONE;
+	for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) {
+		if (ts3a227e->buttons_held & (1 << i))
+			report |= ts3a227e_buttons[i];
+	}
+	snd_soc_jack_report(ts3a227e->jack, report, TS3A227E_JACK_MASK);
+}
+
+static void ts3a227e_new_jack_state(struct ts3a227e *ts3a227e, unsigned acc_reg)
+{
+	bool plugged, mic_present;
+
+	plugged = !!(acc_reg & JACK_INSERTED);
+	mic_present = plugged && !!(acc_reg & EITHER_MIC_MASK);
+
+	ts3a227e->plugged = plugged;
+
+	if (mic_present != ts3a227e->mic_present) {
+		ts3a227e->mic_present = mic_present;
+		ts3a227e->buttons_held = 0;
+		if (mic_present) {
+			/* Enable key press detection. */
+			regmap_update_bits(ts3a227e->regmap,
+					   TS3A227E_REG_SETTING_2,
+					   KP_ENABLE, KP_ENABLE);
+		}
+	}
+}
+
+static irqreturn_t ts3a227e_interrupt(int irq, void *data)
+{
+	struct ts3a227e *ts3a227e = (struct ts3a227e *)data;
+	struct regmap *regmap = ts3a227e->regmap;
+	unsigned int int_reg, kp_int_reg, acc_reg, i;
+	struct device *dev = ts3a227e->dev;
+	int ret;
+
+	/* Check for plug/unplug. */
+	ret = regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg);
+	if (ret) {
+		dev_err(dev, "failed to clear interrupt ret=%d\n", ret);
+		return IRQ_NONE;
+	}
+
+	if (int_reg & (DETECTION_COMPLETE_EVENT | INS_REM_EVENT)) {
+		regmap_read(regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg);
+		ts3a227e_new_jack_state(ts3a227e, acc_reg);
+	}
+
+	/* Report any key events. */
+	ret = regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg);
+	if (ret) {
+		dev_err(dev, "failed to clear key interrupt ret=%d\n", ret);
+		return IRQ_NONE;
+	}
+
+	for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) {
+		if (kp_int_reg & PRESS_MASK(i))
+			ts3a227e->buttons_held |= (1 << i);
+		if (kp_int_reg & RELEASE_MASK(i))
+			ts3a227e->buttons_held &= ~(1 << i);
+	}
+
+	ts3a227e_jack_report(ts3a227e);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ts3a227e_enable_jack_detect - Specify a jack for event reporting
+ *
+ * @component:  component to register the jack with
+ * @jack: jack to use to report headset and button events on
+ *
+ * After this function has been called the headset insert/remove and button
+ * events 0-3 will be routed to the given jack.  Jack can be null to stop
+ * reporting.
+ */
+int ts3a227e_enable_jack_detect(struct snd_soc_component *component,
+				struct snd_soc_jack *jack)
+{
+	struct ts3a227e *ts3a227e = snd_soc_component_get_drvdata(component);
+
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+	ts3a227e->jack = jack;
+	ts3a227e_jack_report(ts3a227e);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ts3a227e_enable_jack_detect);
+
+static struct snd_soc_component_driver ts3a227e_soc_driver;
+
+static const struct regmap_config ts3a227e_regmap_config = {
+	.val_bits = 8,
+	.reg_bits = 8,
+
+	.max_register = TS3A227E_REG_KP_THRESHOLD_3,
+	.readable_reg = ts3a227e_readable_reg,
+	.writeable_reg = ts3a227e_writeable_reg,
+	.volatile_reg = ts3a227e_volatile_reg,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = ts3a227e_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults),
+};
+
+static int ts3a227e_parse_device_property(struct ts3a227e *ts3a227e,
+				struct device *dev)
+{
+	u32 micbias;
+	int err;
+
+	err = device_property_read_u32(dev, "ti,micbias", &micbias);
+	if (!err) {
+		regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_3,
+			MICBIAS_SETTING_MASK,
+			(micbias & 0x07) << MICBIAS_SETTING_SFT);
+	}
+
+	return 0;
+}
+
+static int ts3a227e_i2c_probe(struct i2c_client *i2c,
+			      const struct i2c_device_id *id)
+{
+	struct ts3a227e *ts3a227e;
+	struct device *dev = &i2c->dev;
+	int ret;
+	unsigned int acc_reg;
+
+	ts3a227e = devm_kzalloc(&i2c->dev, sizeof(*ts3a227e), GFP_KERNEL);
+	if (ts3a227e == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, ts3a227e);
+	ts3a227e->dev = dev;
+	ts3a227e->irq = i2c->irq;
+
+	ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config);
+	if (IS_ERR(ts3a227e->regmap))
+		return PTR_ERR(ts3a227e->regmap);
+
+	ret = ts3a227e_parse_device_property(ts3a227e, dev);
+	if (ret) {
+		dev_err(dev, "Failed to parse device property: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt,
+					IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+					"TS3A227E", ts3a227e);
+	if (ret) {
+		dev_err(dev, "Cannot request irq %d (%d)\n", i2c->irq, ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev, &ts3a227e_soc_driver,
+					      NULL, 0);
+	if (ret)
+		return ret;
+
+	/* Enable interrupts except for ADC complete. */
+	regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_INTERRUPT_DISABLE,
+			   INTB_DISABLE | ADC_COMPLETE_INT_DISABLE,
+			   ADC_COMPLETE_INT_DISABLE);
+
+	/* Read jack status because chip might not trigger interrupt at boot. */
+	regmap_read(ts3a227e->regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg);
+	ts3a227e_new_jack_state(ts3a227e, acc_reg);
+	ts3a227e_jack_report(ts3a227e);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ts3a227e_suspend(struct device *dev)
+{
+	struct ts3a227e *ts3a227e = dev_get_drvdata(dev);
+
+	dev_dbg(ts3a227e->dev, "suspend disable irq\n");
+	disable_irq(ts3a227e->irq);
+
+	return 0;
+}
+
+static int ts3a227e_resume(struct device *dev)
+{
+	struct ts3a227e *ts3a227e = dev_get_drvdata(dev);
+
+	dev_dbg(ts3a227e->dev, "resume enable irq\n");
+	enable_irq(ts3a227e->irq);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops ts3a227e_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(ts3a227e_suspend, ts3a227e_resume)
+};
+
+static const struct i2c_device_id ts3a227e_i2c_ids[] = {
+	{ "ts3a227e", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ts3a227e_i2c_ids);
+
+static const struct of_device_id ts3a227e_of_match[] = {
+	{ .compatible = "ti,ts3a227e", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ts3a227e_of_match);
+
+#ifdef CONFIG_ACPI
+static struct acpi_device_id ts3a227e_acpi_match[] = {
+	{ "104C227E", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, ts3a227e_acpi_match);
+#endif
+
+static struct i2c_driver ts3a227e_driver = {
+	.driver = {
+		.name = "ts3a227e",
+		.pm = &ts3a227e_pm,
+		.of_match_table = of_match_ptr(ts3a227e_of_match),
+		.acpi_match_table = ACPI_PTR(ts3a227e_acpi_match),
+	},
+	.probe = ts3a227e_i2c_probe,
+	.id_table = ts3a227e_i2c_ids,
+};
+module_i2c_driver(ts3a227e_driver);
+
+MODULE_DESCRIPTION("ASoC ts3a227e driver");
+MODULE_AUTHOR("Dylan Reid <dgreid@chromium.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ts3a227e.h b/sound/soc/codecs/ts3a227e.h
new file mode 100644
index 0000000..e2acf9c
--- /dev/null
+++ b/sound/soc/codecs/ts3a227e.h
@@ -0,0 +1,17 @@
+/*
+ * TS3A227E Autonous Audio Accessory Detection and Configureation Switch
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _TS3A227E_H
+#define _TS3A227E_H
+
+int ts3a227e_enable_jack_detect(struct snd_soc_component *component,
+				struct snd_soc_jack *jack);
+
+#endif
diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c
new file mode 100644
index 0000000..7396a6e
--- /dev/null
+++ b/sound/soc/codecs/tscs42xx.c
@@ -0,0 +1,1516 @@
+// SPDX-License-Identifier: GPL-2.0
+// tscs42xx.c -- TSCS42xx ALSA SoC Audio driver
+// Copyright 2017 Tempo Semiconductor, Inc.
+// Author: Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <sound/tlv.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "tscs42xx.h"
+
+#define COEFF_SIZE 3
+#define BIQUAD_COEFF_COUNT 5
+#define BIQUAD_SIZE (COEFF_SIZE * BIQUAD_COEFF_COUNT)
+
+#define COEFF_RAM_MAX_ADDR 0xcd
+#define COEFF_RAM_COEFF_COUNT (COEFF_RAM_MAX_ADDR + 1)
+#define COEFF_RAM_SIZE (COEFF_SIZE * COEFF_RAM_COEFF_COUNT)
+
+struct tscs42xx {
+
+	int bclk_ratio;
+	int samplerate;
+	struct mutex audio_params_lock;
+
+	u8 coeff_ram[COEFF_RAM_SIZE];
+	bool coeff_ram_synced;
+	struct mutex coeff_ram_lock;
+
+	struct mutex pll_lock;
+
+	struct regmap *regmap;
+
+	struct clk *sysclk;
+	int sysclk_src_id;
+};
+
+struct coeff_ram_ctl {
+	unsigned int addr;
+	struct soc_bytes_ext bytes_ext;
+};
+
+static bool tscs42xx_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case R_DACCRWRL:
+	case R_DACCRWRM:
+	case R_DACCRWRH:
+	case R_DACCRRDL:
+	case R_DACCRRDM:
+	case R_DACCRRDH:
+	case R_DACCRSTAT:
+	case R_DACCRADDR:
+	case R_PLLCTL0:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tscs42xx_precious(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case R_DACCRWRL:
+	case R_DACCRWRM:
+	case R_DACCRWRH:
+	case R_DACCRRDL:
+	case R_DACCRRDM:
+	case R_DACCRRDH:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config tscs42xx_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.volatile_reg = tscs42xx_volatile,
+	.precious_reg = tscs42xx_precious,
+	.max_register = R_DACMBCREL3H,
+
+	.cache_type = REGCACHE_RBTREE,
+	.can_multi_write = true,
+};
+
+#define MAX_PLL_LOCK_20MS_WAITS 1
+static bool plls_locked(struct snd_soc_component *component)
+{
+	int ret;
+	int count = MAX_PLL_LOCK_20MS_WAITS;
+
+	do {
+		ret = snd_soc_component_read32(component, R_PLLCTL0);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to read PLL lock status (%d)\n", ret);
+			return false;
+		} else if (ret > 0) {
+			return true;
+		}
+		msleep(20);
+	} while (count--);
+
+	return false;
+}
+
+static int sample_rate_to_pll_freq_out(int sample_rate)
+{
+	switch (sample_rate) {
+	case 11025:
+	case 22050:
+	case 44100:
+	case 88200:
+		return 112896000;
+	case 8000:
+	case 16000:
+	case 32000:
+	case 48000:
+	case 96000:
+		return 122880000;
+	default:
+		return -EINVAL;
+	}
+}
+
+#define DACCRSTAT_MAX_TRYS 10
+static int write_coeff_ram(struct snd_soc_component *component, u8 *coeff_ram,
+	unsigned int addr, unsigned int coeff_cnt)
+{
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
+	int cnt;
+	int trys;
+	int ret;
+
+	for (cnt = 0; cnt < coeff_cnt; cnt++, addr++) {
+
+		for (trys = 0; trys < DACCRSTAT_MAX_TRYS; trys++) {
+			ret = snd_soc_component_read32(component, R_DACCRSTAT);
+			if (ret < 0) {
+				dev_err(component->dev,
+					"Failed to read stat (%d)\n", ret);
+				return ret;
+			}
+			if (!ret)
+				break;
+		}
+
+		if (trys == DACCRSTAT_MAX_TRYS) {
+			ret = -EIO;
+			dev_err(component->dev,
+				"dac coefficient write error (%d)\n", ret);
+			return ret;
+		}
+
+		ret = regmap_write(tscs42xx->regmap, R_DACCRADDR, addr);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to write dac ram address (%d)\n", ret);
+			return ret;
+		}
+
+		ret = regmap_bulk_write(tscs42xx->regmap, R_DACCRWRL,
+			&coeff_ram[addr * COEFF_SIZE],
+			COEFF_SIZE);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to write dac ram (%d)\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int power_up_audio_plls(struct snd_soc_component *component)
+{
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
+	int freq_out;
+	int ret;
+	unsigned int mask;
+	unsigned int val;
+
+	freq_out = sample_rate_to_pll_freq_out(tscs42xx->samplerate);
+	switch (freq_out) {
+	case 122880000: /* 48k */
+		mask = RM_PLLCTL1C_PDB_PLL1;
+		val = RV_PLLCTL1C_PDB_PLL1_ENABLE;
+		break;
+	case 112896000: /* 44.1k */
+		mask = RM_PLLCTL1C_PDB_PLL2;
+		val = RV_PLLCTL1C_PDB_PLL2_ENABLE;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev,
+				"Unrecognized PLL output freq (%d)\n", ret);
+		return ret;
+	}
+
+	mutex_lock(&tscs42xx->pll_lock);
+
+	ret = snd_soc_component_update_bits(component, R_PLLCTL1C, mask, val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to turn PLL on (%d)\n", ret);
+		goto exit;
+	}
+
+	if (!plls_locked(component)) {
+		dev_err(component->dev, "Failed to lock plls\n");
+		ret = -ENOMSG;
+		goto exit;
+	}
+
+	ret = 0;
+exit:
+	mutex_unlock(&tscs42xx->pll_lock);
+
+	return ret;
+}
+
+static int power_down_audio_plls(struct snd_soc_component *component)
+{
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	mutex_lock(&tscs42xx->pll_lock);
+
+	ret = snd_soc_component_update_bits(component, R_PLLCTL1C,
+			RM_PLLCTL1C_PDB_PLL1,
+			RV_PLLCTL1C_PDB_PLL1_DISABLE);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to turn PLL off (%d)\n", ret);
+		goto exit;
+	}
+	ret = snd_soc_component_update_bits(component, R_PLLCTL1C,
+			RM_PLLCTL1C_PDB_PLL2,
+			RV_PLLCTL1C_PDB_PLL2_DISABLE);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to turn PLL off (%d)\n", ret);
+		goto exit;
+	}
+
+	ret = 0;
+exit:
+	mutex_unlock(&tscs42xx->pll_lock);
+
+	return ret;
+}
+
+static int coeff_ram_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
+	struct coeff_ram_ctl *ctl =
+		(struct coeff_ram_ctl *)kcontrol->private_value;
+	struct soc_bytes_ext *params = &ctl->bytes_ext;
+
+	mutex_lock(&tscs42xx->coeff_ram_lock);
+
+	memcpy(ucontrol->value.bytes.data,
+		&tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE], params->max);
+
+	mutex_unlock(&tscs42xx->coeff_ram_lock);
+
+	return 0;
+}
+
+static int coeff_ram_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
+	struct coeff_ram_ctl *ctl =
+		(struct coeff_ram_ctl *)kcontrol->private_value;
+	struct soc_bytes_ext *params = &ctl->bytes_ext;
+	unsigned int coeff_cnt = params->max / COEFF_SIZE;
+	int ret;
+
+	mutex_lock(&tscs42xx->coeff_ram_lock);
+
+	tscs42xx->coeff_ram_synced = false;
+
+	memcpy(&tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE],
+		ucontrol->value.bytes.data, params->max);
+
+	mutex_lock(&tscs42xx->pll_lock);
+
+	if (plls_locked(component)) {
+		ret = write_coeff_ram(component, tscs42xx->coeff_ram,
+			ctl->addr, coeff_cnt);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to flush coeff ram cache (%d)\n", ret);
+			goto exit;
+		}
+		tscs42xx->coeff_ram_synced = true;
+	}
+
+	ret = 0;
+exit:
+	mutex_unlock(&tscs42xx->pll_lock);
+
+	mutex_unlock(&tscs42xx->coeff_ram_lock);
+
+	return ret;
+}
+
+/* Input L Capture Route */
+static char const * const input_select_text[] = {
+	"Line 1", "Line 2", "Line 3", "D2S"
+};
+
+static const struct soc_enum left_input_select_enum =
+SOC_ENUM_SINGLE(R_INSELL, FB_INSELL, ARRAY_SIZE(input_select_text),
+		input_select_text);
+
+static const struct snd_kcontrol_new left_input_select =
+SOC_DAPM_ENUM("LEFT_INPUT_SELECT_ENUM", left_input_select_enum);
+
+/* Input R Capture Route */
+static const struct soc_enum right_input_select_enum =
+SOC_ENUM_SINGLE(R_INSELR, FB_INSELR, ARRAY_SIZE(input_select_text),
+		input_select_text);
+
+static const struct snd_kcontrol_new right_input_select =
+SOC_DAPM_ENUM("RIGHT_INPUT_SELECT_ENUM", right_input_select_enum);
+
+/* Input Channel Mapping */
+static char const * const ch_map_select_text[] = {
+	"Normal", "Left to Right", "Right to Left", "Swap"
+};
+
+static const struct soc_enum ch_map_select_enum =
+SOC_ENUM_SINGLE(R_AIC2, FB_AIC2_ADCDSEL, ARRAY_SIZE(ch_map_select_text),
+		ch_map_select_text);
+
+static int dapm_vref_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	msleep(20);
+	return 0;
+}
+
+static int dapm_micb_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	msleep(20);
+	return 0;
+}
+
+static int pll_event(struct snd_soc_dapm_widget *w,
+		     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+	int ret;
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		ret = power_up_audio_plls(component);
+	else
+		ret = power_down_audio_plls(component);
+
+	return ret;
+}
+
+static int dac_event(struct snd_soc_dapm_widget *w,
+		     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	mutex_lock(&tscs42xx->coeff_ram_lock);
+
+	if (tscs42xx->coeff_ram_synced == false) {
+		ret = write_coeff_ram(component, tscs42xx->coeff_ram, 0x00,
+			COEFF_RAM_COEFF_COUNT);
+		if (ret < 0)
+			goto exit;
+		tscs42xx->coeff_ram_synced = true;
+	}
+
+	ret = 0;
+exit:
+	mutex_unlock(&tscs42xx->coeff_ram_lock);
+
+	return ret;
+}
+
+static const struct snd_soc_dapm_widget tscs42xx_dapm_widgets[] = {
+	/* Vref */
+	SND_SOC_DAPM_SUPPLY_S("Vref", 1, R_PWRM2, FB_PWRM2_VREF, 0,
+		dapm_vref_event, SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
+
+	/* PLL */
+	SND_SOC_DAPM_SUPPLY("PLL", SND_SOC_NOPM, 0, 0, pll_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* Headphone */
+	SND_SOC_DAPM_DAC_E("DAC L", "HiFi Playback", R_PWRM2, FB_PWRM2_HPL, 0,
+			dac_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_DAC_E("DAC R", "HiFi Playback", R_PWRM2, FB_PWRM2_HPR, 0,
+			dac_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_OUTPUT("Headphone L"),
+	SND_SOC_DAPM_OUTPUT("Headphone R"),
+
+	/* Speaker */
+	SND_SOC_DAPM_DAC_E("ClassD L", "HiFi Playback",
+		R_PWRM2, FB_PWRM2_SPKL, 0,
+		dac_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_DAC_E("ClassD R", "HiFi Playback",
+		R_PWRM2, FB_PWRM2_SPKR, 0,
+		dac_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_OUTPUT("Speaker L"),
+	SND_SOC_DAPM_OUTPUT("Speaker R"),
+
+	/* Capture */
+	SND_SOC_DAPM_PGA("Analog In PGA L", R_PWRM1, FB_PWRM1_PGAL, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Analog In PGA R", R_PWRM1, FB_PWRM1_PGAR, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Analog Boost L", R_PWRM1, FB_PWRM1_BSTL, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Analog Boost R", R_PWRM1, FB_PWRM1_BSTR, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC Mute", R_CNVRTR0, FB_CNVRTR0_HPOR, true, NULL, 0),
+	SND_SOC_DAPM_ADC("ADC L", "HiFi Capture", R_PWRM1, FB_PWRM1_ADCL, 0),
+	SND_SOC_DAPM_ADC("ADC R", "HiFi Capture", R_PWRM1, FB_PWRM1_ADCR, 0),
+
+	/* Capture Input */
+	SND_SOC_DAPM_MUX("Input L Capture Route", R_PWRM2,
+			FB_PWRM2_INSELL, 0, &left_input_select),
+	SND_SOC_DAPM_MUX("Input R Capture Route", R_PWRM2,
+			FB_PWRM2_INSELR, 0, &right_input_select),
+
+	/* Digital Mic */
+	SND_SOC_DAPM_SUPPLY_S("Digital Mic Enable", 2, R_DMICCTL,
+		FB_DMICCTL_DMICEN, 0, NULL,
+		SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
+
+	/* Analog Mic */
+	SND_SOC_DAPM_SUPPLY_S("Mic Bias", 2, R_PWRM1, FB_PWRM1_MICB,
+		0, dapm_micb_event, SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
+
+	/* Line In */
+	SND_SOC_DAPM_INPUT("Line In 1 L"),
+	SND_SOC_DAPM_INPUT("Line In 1 R"),
+	SND_SOC_DAPM_INPUT("Line In 2 L"),
+	SND_SOC_DAPM_INPUT("Line In 2 R"),
+	SND_SOC_DAPM_INPUT("Line In 3 L"),
+	SND_SOC_DAPM_INPUT("Line In 3 R"),
+};
+
+static const struct snd_soc_dapm_route tscs42xx_intercon[] = {
+	{"DAC L", NULL, "PLL"},
+	{"DAC R", NULL, "PLL"},
+	{"DAC L", NULL, "Vref"},
+	{"DAC R", NULL, "Vref"},
+	{"Headphone L", NULL, "DAC L"},
+	{"Headphone R", NULL, "DAC R"},
+
+	{"ClassD L", NULL, "PLL"},
+	{"ClassD R", NULL, "PLL"},
+	{"ClassD L", NULL, "Vref"},
+	{"ClassD R", NULL, "Vref"},
+	{"Speaker L", NULL, "ClassD L"},
+	{"Speaker R", NULL, "ClassD R"},
+
+	{"Input L Capture Route", NULL, "Vref"},
+	{"Input R Capture Route", NULL, "Vref"},
+
+	{"Mic Bias", NULL, "Vref"},
+
+	{"Input L Capture Route", "Line 1", "Line In 1 L"},
+	{"Input R Capture Route", "Line 1", "Line In 1 R"},
+	{"Input L Capture Route", "Line 2", "Line In 2 L"},
+	{"Input R Capture Route", "Line 2", "Line In 2 R"},
+	{"Input L Capture Route", "Line 3", "Line In 3 L"},
+	{"Input R Capture Route", "Line 3", "Line In 3 R"},
+
+	{"Analog In PGA L", NULL, "Input L Capture Route"},
+	{"Analog In PGA R", NULL, "Input R Capture Route"},
+	{"Analog Boost L", NULL, "Analog In PGA L"},
+	{"Analog Boost R", NULL, "Analog In PGA R"},
+	{"ADC Mute", NULL, "Analog Boost L"},
+	{"ADC Mute", NULL, "Analog Boost R"},
+	{"ADC L", NULL, "PLL"},
+	{"ADC R", NULL, "PLL"},
+	{"ADC L", NULL, "ADC Mute"},
+	{"ADC R", NULL, "ADC Mute"},
+};
+
+/************
+ * CONTROLS *
+ ************/
+
+static char const * const eq_band_enable_text[] = {
+	"Prescale only",
+	"Band1",
+	"Band1:2",
+	"Band1:3",
+	"Band1:4",
+	"Band1:5",
+	"Band1:6",
+};
+
+static char const * const level_detection_text[] = {
+	"Average",
+	"Peak",
+};
+
+static char const * const level_detection_window_text[] = {
+	"512 Samples",
+	"64 Samples",
+};
+
+static char const * const compressor_ratio_text[] = {
+	"Reserved", "1.5:1", "2:1", "3:1", "4:1", "5:1", "6:1",
+	"7:1", "8:1", "9:1", "10:1", "11:1", "12:1", "13:1", "14:1",
+	"15:1", "16:1", "17:1", "18:1", "19:1", "20:1",
+};
+
+static DECLARE_TLV_DB_SCALE(hpvol_scale, -8850, 75, 0);
+static DECLARE_TLV_DB_SCALE(spkvol_scale, -7725, 75, 0);
+static DECLARE_TLV_DB_SCALE(dacvol_scale, -9563, 38, 0);
+static DECLARE_TLV_DB_SCALE(adcvol_scale, -7125, 38, 0);
+static DECLARE_TLV_DB_SCALE(invol_scale, -1725, 75, 0);
+static DECLARE_TLV_DB_SCALE(mic_boost_scale, 0, 1000, 0);
+static DECLARE_TLV_DB_MINMAX(mugain_scale, 0, 4650);
+static DECLARE_TLV_DB_MINMAX(compth_scale, -9562, 0);
+
+static const struct soc_enum eq1_band_enable_enum =
+	SOC_ENUM_SINGLE(R_CONFIG1, FB_CONFIG1_EQ1_BE,
+		ARRAY_SIZE(eq_band_enable_text), eq_band_enable_text);
+
+static const struct soc_enum eq2_band_enable_enum =
+	SOC_ENUM_SINGLE(R_CONFIG1, FB_CONFIG1_EQ2_BE,
+		ARRAY_SIZE(eq_band_enable_text), eq_band_enable_text);
+
+static const struct soc_enum cle_level_detection_enum =
+	SOC_ENUM_SINGLE(R_CLECTL, FB_CLECTL_LVL_MODE,
+		ARRAY_SIZE(level_detection_text),
+		level_detection_text);
+
+static const struct soc_enum cle_level_detection_window_enum =
+	SOC_ENUM_SINGLE(R_CLECTL, FB_CLECTL_WINDOWSEL,
+		ARRAY_SIZE(level_detection_window_text),
+		level_detection_window_text);
+
+static const struct soc_enum mbc_level_detection_enums[] = {
+	SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE1,
+		ARRAY_SIZE(level_detection_text),
+			level_detection_text),
+	SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE2,
+		ARRAY_SIZE(level_detection_text),
+			level_detection_text),
+	SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE3,
+		ARRAY_SIZE(level_detection_text),
+			level_detection_text),
+};
+
+static const struct soc_enum mbc_level_detection_window_enums[] = {
+	SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL1,
+		ARRAY_SIZE(level_detection_window_text),
+			level_detection_window_text),
+	SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL2,
+		ARRAY_SIZE(level_detection_window_text),
+			level_detection_window_text),
+	SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL3,
+		ARRAY_SIZE(level_detection_window_text),
+			level_detection_window_text),
+};
+
+static const struct soc_enum compressor_ratio_enum =
+	SOC_ENUM_SINGLE(R_CMPRAT, FB_CMPRAT,
+		ARRAY_SIZE(compressor_ratio_text), compressor_ratio_text);
+
+static const struct soc_enum dac_mbc1_compressor_ratio_enum =
+	SOC_ENUM_SINGLE(R_DACMBCRAT1, FB_DACMBCRAT1_RATIO,
+		ARRAY_SIZE(compressor_ratio_text), compressor_ratio_text);
+
+static const struct soc_enum dac_mbc2_compressor_ratio_enum =
+	SOC_ENUM_SINGLE(R_DACMBCRAT2, FB_DACMBCRAT2_RATIO,
+		ARRAY_SIZE(compressor_ratio_text), compressor_ratio_text);
+
+static const struct soc_enum dac_mbc3_compressor_ratio_enum =
+	SOC_ENUM_SINGLE(R_DACMBCRAT3, FB_DACMBCRAT3_RATIO,
+		ARRAY_SIZE(compressor_ratio_text), compressor_ratio_text);
+
+static int bytes_info_ext(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *ucontrol)
+{
+	struct coeff_ram_ctl *ctl =
+		(struct coeff_ram_ctl *)kcontrol->private_value;
+	struct soc_bytes_ext *params = &ctl->bytes_ext;
+
+	ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	ucontrol->count = params->max;
+
+	return 0;
+}
+
+#define COEFF_RAM_CTL(xname, xcount, xaddr) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = bytes_info_ext, \
+	.get = coeff_ram_get, .put = coeff_ram_put, \
+	.private_value = (unsigned long)&(struct coeff_ram_ctl) { \
+		.addr = xaddr, \
+		.bytes_ext = {.max = xcount, }, \
+	} \
+}
+
+static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
+	/* Volumes */
+	SOC_DOUBLE_R_TLV("Headphone Volume", R_HPVOLL, R_HPVOLR,
+			FB_HPVOLL, 0x7F, 0, hpvol_scale),
+	SOC_DOUBLE_R_TLV("Speaker Volume", R_SPKVOLL, R_SPKVOLR,
+			FB_SPKVOLL, 0x7F, 0, spkvol_scale),
+	SOC_DOUBLE_R_TLV("Master Volume", R_DACVOLL, R_DACVOLR,
+			FB_DACVOLL, 0xFF, 0, dacvol_scale),
+	SOC_DOUBLE_R_TLV("PCM Volume", R_ADCVOLL, R_ADCVOLR,
+			FB_ADCVOLL, 0xFF, 0, adcvol_scale),
+	SOC_DOUBLE_R_TLV("Input Volume", R_INVOLL, R_INVOLR,
+			FB_INVOLL, 0x3F, 0, invol_scale),
+
+	/* INSEL */
+	SOC_DOUBLE_R_TLV("Mic Boost Volume", R_INSELL, R_INSELR,
+			FB_INSELL_MICBSTL, FV_INSELL_MICBSTL_30DB,
+			0, mic_boost_scale),
+
+	/* Input Channel Map */
+	SOC_ENUM("Input Channel Map", ch_map_select_enum),
+
+	/* Mic Bias */
+	SOC_SINGLE("Mic Bias Boost Switch", 0x71, 0x07, 1, 0),
+
+	/* Headphone Auto Switching */
+	SOC_SINGLE("Headphone Auto Switching Switch",
+			R_CTL, FB_CTL_HPSWEN, 1, 0),
+	SOC_SINGLE("Headphone Detect Polarity Toggle Switch",
+			R_CTL, FB_CTL_HPSWPOL, 1, 0),
+
+	/* Coefficient Ram */
+	COEFF_RAM_CTL("Cascade1L BiQuad1", BIQUAD_SIZE, 0x00),
+	COEFF_RAM_CTL("Cascade1L BiQuad2", BIQUAD_SIZE, 0x05),
+	COEFF_RAM_CTL("Cascade1L BiQuad3", BIQUAD_SIZE, 0x0a),
+	COEFF_RAM_CTL("Cascade1L BiQuad4", BIQUAD_SIZE, 0x0f),
+	COEFF_RAM_CTL("Cascade1L BiQuad5", BIQUAD_SIZE, 0x14),
+	COEFF_RAM_CTL("Cascade1L BiQuad6", BIQUAD_SIZE, 0x19),
+
+	COEFF_RAM_CTL("Cascade1R BiQuad1", BIQUAD_SIZE, 0x20),
+	COEFF_RAM_CTL("Cascade1R BiQuad2", BIQUAD_SIZE, 0x25),
+	COEFF_RAM_CTL("Cascade1R BiQuad3", BIQUAD_SIZE, 0x2a),
+	COEFF_RAM_CTL("Cascade1R BiQuad4", BIQUAD_SIZE, 0x2f),
+	COEFF_RAM_CTL("Cascade1R BiQuad5", BIQUAD_SIZE, 0x34),
+	COEFF_RAM_CTL("Cascade1R BiQuad6", BIQUAD_SIZE, 0x39),
+
+	COEFF_RAM_CTL("Cascade1L Prescale", COEFF_SIZE, 0x1f),
+	COEFF_RAM_CTL("Cascade1R Prescale", COEFF_SIZE, 0x3f),
+
+	COEFF_RAM_CTL("Cascade2L BiQuad1", BIQUAD_SIZE, 0x40),
+	COEFF_RAM_CTL("Cascade2L BiQuad2", BIQUAD_SIZE, 0x45),
+	COEFF_RAM_CTL("Cascade2L BiQuad3", BIQUAD_SIZE, 0x4a),
+	COEFF_RAM_CTL("Cascade2L BiQuad4", BIQUAD_SIZE, 0x4f),
+	COEFF_RAM_CTL("Cascade2L BiQuad5", BIQUAD_SIZE, 0x54),
+	COEFF_RAM_CTL("Cascade2L BiQuad6", BIQUAD_SIZE, 0x59),
+
+	COEFF_RAM_CTL("Cascade2R BiQuad1", BIQUAD_SIZE, 0x60),
+	COEFF_RAM_CTL("Cascade2R BiQuad2", BIQUAD_SIZE, 0x65),
+	COEFF_RAM_CTL("Cascade2R BiQuad3", BIQUAD_SIZE, 0x6a),
+	COEFF_RAM_CTL("Cascade2R BiQuad4", BIQUAD_SIZE, 0x6f),
+	COEFF_RAM_CTL("Cascade2R BiQuad5", BIQUAD_SIZE, 0x74),
+	COEFF_RAM_CTL("Cascade2R BiQuad6", BIQUAD_SIZE, 0x79),
+
+	COEFF_RAM_CTL("Cascade2L Prescale", COEFF_SIZE, 0x5f),
+	COEFF_RAM_CTL("Cascade2R Prescale", COEFF_SIZE, 0x7f),
+
+	COEFF_RAM_CTL("Bass Extraction BiQuad1", BIQUAD_SIZE, 0x80),
+	COEFF_RAM_CTL("Bass Extraction BiQuad2", BIQUAD_SIZE, 0x85),
+
+	COEFF_RAM_CTL("Bass Non Linear Function 1", COEFF_SIZE, 0x8a),
+	COEFF_RAM_CTL("Bass Non Linear Function 2", COEFF_SIZE, 0x8b),
+
+	COEFF_RAM_CTL("Bass Limiter BiQuad", BIQUAD_SIZE, 0x8c),
+
+	COEFF_RAM_CTL("Bass Cut Off BiQuad", BIQUAD_SIZE, 0x91),
+
+	COEFF_RAM_CTL("Bass Mix", COEFF_SIZE, 0x96),
+
+	COEFF_RAM_CTL("Treb Extraction BiQuad1", BIQUAD_SIZE, 0x97),
+	COEFF_RAM_CTL("Treb Extraction BiQuad2", BIQUAD_SIZE, 0x9c),
+
+	COEFF_RAM_CTL("Treb Non Linear Function 1", COEFF_SIZE, 0xa1),
+	COEFF_RAM_CTL("Treb Non Linear Function 2", COEFF_SIZE, 0xa2),
+
+	COEFF_RAM_CTL("Treb Limiter BiQuad", BIQUAD_SIZE, 0xa3),
+
+	COEFF_RAM_CTL("Treb Cut Off BiQuad", BIQUAD_SIZE, 0xa8),
+
+	COEFF_RAM_CTL("Treb Mix", COEFF_SIZE, 0xad),
+
+	COEFF_RAM_CTL("3D", COEFF_SIZE, 0xae),
+
+	COEFF_RAM_CTL("3D Mix", COEFF_SIZE, 0xaf),
+
+	COEFF_RAM_CTL("MBC1 BiQuad1", BIQUAD_SIZE, 0xb0),
+	COEFF_RAM_CTL("MBC1 BiQuad2", BIQUAD_SIZE, 0xb5),
+
+	COEFF_RAM_CTL("MBC2 BiQuad1", BIQUAD_SIZE, 0xba),
+	COEFF_RAM_CTL("MBC2 BiQuad2", BIQUAD_SIZE, 0xbf),
+
+	COEFF_RAM_CTL("MBC3 BiQuad1", BIQUAD_SIZE, 0xc4),
+	COEFF_RAM_CTL("MBC3 BiQuad2", BIQUAD_SIZE, 0xc9),
+
+	/* EQ */
+	SOC_SINGLE("EQ1 Switch", R_CONFIG1, FB_CONFIG1_EQ1_EN, 1, 0),
+	SOC_SINGLE("EQ2 Switch", R_CONFIG1, FB_CONFIG1_EQ2_EN, 1, 0),
+	SOC_ENUM("EQ1 Band Enable", eq1_band_enable_enum),
+	SOC_ENUM("EQ2 Band Enable", eq2_band_enable_enum),
+
+	/* CLE */
+	SOC_ENUM("CLE Level Detect",
+		cle_level_detection_enum),
+	SOC_ENUM("CLE Level Detect Win",
+		cle_level_detection_window_enum),
+	SOC_SINGLE("Expander Switch",
+		R_CLECTL, FB_CLECTL_EXP_EN, 1, 0),
+	SOC_SINGLE("Limiter Switch",
+		R_CLECTL, FB_CLECTL_LIMIT_EN, 1, 0),
+	SOC_SINGLE("Comp Switch",
+		R_CLECTL, FB_CLECTL_COMP_EN, 1, 0),
+	SOC_SINGLE_TLV("CLE Make-Up Gain Volume",
+		R_MUGAIN, FB_MUGAIN_CLEMUG, 0x1f, 0, mugain_scale),
+	SOC_SINGLE_TLV("Comp Thresh Volume",
+		R_COMPTH, FB_COMPTH, 0xff, 0, compth_scale),
+	SOC_ENUM("Comp Ratio", compressor_ratio_enum),
+	SND_SOC_BYTES("Comp Atk Time", R_CATKTCL, 2),
+
+	/* Effects */
+	SOC_SINGLE("3D Switch", R_FXCTL, FB_FXCTL_3DEN, 1, 0),
+	SOC_SINGLE("Treble Switch", R_FXCTL, FB_FXCTL_TEEN, 1, 0),
+	SOC_SINGLE("Treble Bypass Switch", R_FXCTL, FB_FXCTL_TNLFBYPASS, 1, 0),
+	SOC_SINGLE("Bass Switch", R_FXCTL, FB_FXCTL_BEEN, 1, 0),
+	SOC_SINGLE("Bass Bypass Switch", R_FXCTL, FB_FXCTL_BNLFBYPASS, 1, 0),
+
+	/* MBC */
+	SOC_SINGLE("MBC Band1 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN1, 1, 0),
+	SOC_SINGLE("MBC Band2 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN2, 1, 0),
+	SOC_SINGLE("MBC Band3 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN3, 1, 0),
+	SOC_ENUM("MBC Band1 Level Detect",
+		mbc_level_detection_enums[0]),
+	SOC_ENUM("MBC Band2 Level Detect",
+		mbc_level_detection_enums[1]),
+	SOC_ENUM("MBC Band3 Level Detect",
+		mbc_level_detection_enums[2]),
+	SOC_ENUM("MBC Band1 Level Detect Win",
+		mbc_level_detection_window_enums[0]),
+	SOC_ENUM("MBC Band2 Level Detect Win",
+		mbc_level_detection_window_enums[1]),
+	SOC_ENUM("MBC Band3 Level Detect Win",
+		mbc_level_detection_window_enums[2]),
+
+	SOC_SINGLE("MBC1 Phase Invert Switch",
+		R_DACMBCMUG1, FB_DACMBCMUG1_PHASE, 1, 0),
+	SOC_SINGLE_TLV("DAC MBC1 Make-Up Gain Volume",
+		R_DACMBCMUG1, FB_DACMBCMUG1_MUGAIN, 0x1f, 0, mugain_scale),
+	SOC_SINGLE_TLV("DAC MBC1 Comp Thresh Volume",
+		R_DACMBCTHR1, FB_DACMBCTHR1_THRESH, 0xff, 0, compth_scale),
+	SOC_ENUM("DAC MBC1 Comp Ratio",
+		dac_mbc1_compressor_ratio_enum),
+	SND_SOC_BYTES("DAC MBC1 Comp Atk Time", R_DACMBCATK1L, 2),
+	SND_SOC_BYTES("DAC MBC1 Comp Rel Time Const",
+		R_DACMBCREL1L, 2),
+
+	SOC_SINGLE("MBC2 Phase Invert Switch",
+		R_DACMBCMUG2, FB_DACMBCMUG2_PHASE, 1, 0),
+	SOC_SINGLE_TLV("DAC MBC2 Make-Up Gain Volume",
+		R_DACMBCMUG2, FB_DACMBCMUG2_MUGAIN, 0x1f, 0, mugain_scale),
+	SOC_SINGLE_TLV("DAC MBC2 Comp Thresh Volume",
+		R_DACMBCTHR2, FB_DACMBCTHR2_THRESH, 0xff, 0, compth_scale),
+	SOC_ENUM("DAC MBC2 Comp Ratio",
+		dac_mbc2_compressor_ratio_enum),
+	SND_SOC_BYTES("DAC MBC2 Comp Atk Time", R_DACMBCATK2L, 2),
+	SND_SOC_BYTES("DAC MBC2 Comp Rel Time Const",
+		R_DACMBCREL2L, 2),
+
+	SOC_SINGLE("MBC3 Phase Invert Switch",
+		R_DACMBCMUG3, FB_DACMBCMUG3_PHASE, 1, 0),
+	SOC_SINGLE_TLV("DAC MBC3 Make-Up Gain Volume",
+		R_DACMBCMUG3, FB_DACMBCMUG3_MUGAIN, 0x1f, 0, mugain_scale),
+	SOC_SINGLE_TLV("DAC MBC3 Comp Thresh Volume",
+		R_DACMBCTHR3, FB_DACMBCTHR3_THRESH, 0xff, 0, compth_scale),
+	SOC_ENUM("DAC MBC3 Comp Ratio",
+		dac_mbc3_compressor_ratio_enum),
+	SND_SOC_BYTES("DAC MBC3 Comp Atk Time", R_DACMBCATK3L, 2),
+	SND_SOC_BYTES("DAC MBC3 Comp Rel Time Const",
+		R_DACMBCREL3L, 2),
+};
+
+static int setup_sample_format(struct snd_soc_component *component,
+		snd_pcm_format_t format)
+{
+	unsigned int width;
+	int ret;
+
+	switch (format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		width = RV_AIC1_WL_16;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		width = RV_AIC1_WL_20;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		width = RV_AIC1_WL_24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		width = RV_AIC1_WL_32;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Unsupported format width (%d)\n", ret);
+		return ret;
+	}
+	ret = snd_soc_component_update_bits(component,
+			R_AIC1, RM_AIC1_WL, width);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to set sample width (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int setup_sample_rate(struct snd_soc_component *component,
+		unsigned int rate)
+{
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
+	unsigned int br, bm;
+	int ret;
+
+	switch (rate) {
+	case 8000:
+		br = RV_DACSR_DBR_32;
+		bm = RV_DACSR_DBM_PT25;
+		break;
+	case 16000:
+		br = RV_DACSR_DBR_32;
+		bm = RV_DACSR_DBM_PT5;
+		break;
+	case 24000:
+		br = RV_DACSR_DBR_48;
+		bm = RV_DACSR_DBM_PT5;
+		break;
+	case 32000:
+		br = RV_DACSR_DBR_32;
+		bm = RV_DACSR_DBM_1;
+		break;
+	case 48000:
+		br = RV_DACSR_DBR_48;
+		bm = RV_DACSR_DBM_1;
+		break;
+	case 96000:
+		br = RV_DACSR_DBR_48;
+		bm = RV_DACSR_DBM_2;
+		break;
+	case 11025:
+		br = RV_DACSR_DBR_44_1;
+		bm = RV_DACSR_DBM_PT25;
+		break;
+	case 22050:
+		br = RV_DACSR_DBR_44_1;
+		bm = RV_DACSR_DBM_PT5;
+		break;
+	case 44100:
+		br = RV_DACSR_DBR_44_1;
+		bm = RV_DACSR_DBM_1;
+		break;
+	case 88200:
+		br = RV_DACSR_DBR_44_1;
+		bm = RV_DACSR_DBM_2;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported sample rate %d\n", rate);
+		return -EINVAL;
+	}
+
+	/* DAC and ADC share bit and frame clock */
+	ret = snd_soc_component_update_bits(component,
+			R_DACSR, RM_DACSR_DBR, br);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to update register (%d)\n", ret);
+		return ret;
+	}
+	ret = snd_soc_component_update_bits(component,
+			R_DACSR, RM_DACSR_DBM, bm);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to update register (%d)\n", ret);
+		return ret;
+	}
+	ret = snd_soc_component_update_bits(component,
+			R_ADCSR, RM_DACSR_DBR, br);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to update register (%d)\n", ret);
+		return ret;
+	}
+	ret = snd_soc_component_update_bits(component,
+			R_ADCSR, RM_DACSR_DBM, bm);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to update register (%d)\n", ret);
+		return ret;
+	}
+
+	mutex_lock(&tscs42xx->audio_params_lock);
+
+	tscs42xx->samplerate = rate;
+
+	mutex_unlock(&tscs42xx->audio_params_lock);
+
+	return 0;
+}
+
+struct reg_setting {
+	unsigned int addr;
+	unsigned int val;
+	unsigned int mask;
+};
+
+#define PLL_REG_SETTINGS_COUNT 13
+struct pll_ctl {
+	int input_freq;
+	struct reg_setting settings[PLL_REG_SETTINGS_COUNT];
+};
+
+#define PLL_CTL(f, rt, rd, r1b_l, r9, ra, rb,		\
+		rc, r12, r1b_h, re, rf, r10, r11)	\
+	{						\
+		.input_freq = f,			\
+		.settings = {				\
+			{R_TIMEBASE,  rt,   0xFF},	\
+			{R_PLLCTLD,   rd,   0xFF},	\
+			{R_PLLCTL1B, r1b_l, 0x0F},	\
+			{R_PLLCTL9,   r9,   0xFF},	\
+			{R_PLLCTLA,   ra,   0xFF},	\
+			{R_PLLCTLB,   rb,   0xFF},	\
+			{R_PLLCTLC,   rc,   0xFF},	\
+			{R_PLLCTL12, r12,   0xFF},	\
+			{R_PLLCTL1B, r1b_h, 0xF0},	\
+			{R_PLLCTLE,   re,   0xFF},	\
+			{R_PLLCTLF,   rf,   0xFF},	\
+			{R_PLLCTL10, r10,   0xFF},	\
+			{R_PLLCTL11, r11,   0xFF},	\
+		},					\
+	}
+
+static const struct pll_ctl pll_ctls[] = {
+	PLL_CTL(1411200, 0x05,
+		0x39, 0x04, 0x07, 0x02, 0xC3, 0x04,
+		0x1B, 0x10, 0x03, 0x03, 0xD0, 0x02),
+	PLL_CTL(1536000, 0x05,
+		0x1A, 0x04, 0x02, 0x03, 0xE0, 0x01,
+		0x1A, 0x10, 0x02, 0x03, 0xB9, 0x01),
+	PLL_CTL(2822400, 0x0A,
+		0x23, 0x04, 0x07, 0x04, 0xC3, 0x04,
+		0x22, 0x10, 0x05, 0x03, 0x58, 0x02),
+	PLL_CTL(3072000, 0x0B,
+		0x22, 0x04, 0x07, 0x03, 0x48, 0x03,
+		0x1A, 0x10, 0x04, 0x03, 0xB9, 0x01),
+	PLL_CTL(5644800, 0x15,
+		0x23, 0x04, 0x0E, 0x04, 0xC3, 0x04,
+		0x1A, 0x10, 0x08, 0x03, 0xE0, 0x01),
+	PLL_CTL(6144000, 0x17,
+		0x1A, 0x04, 0x08, 0x03, 0xE0, 0x01,
+		0x1A, 0x10, 0x08, 0x03, 0xB9, 0x01),
+	PLL_CTL(12000000, 0x2E,
+		0x1B, 0x04, 0x19, 0x03, 0x00, 0x03,
+		0x2A, 0x10, 0x19, 0x05, 0x98, 0x04),
+	PLL_CTL(19200000, 0x4A,
+		0x13, 0x04, 0x14, 0x03, 0x80, 0x01,
+		0x1A, 0x10, 0x19, 0x03, 0xB9, 0x01),
+	PLL_CTL(22000000, 0x55,
+		0x2A, 0x04, 0x37, 0x05, 0x00, 0x06,
+		0x22, 0x10, 0x26, 0x03, 0x49, 0x02),
+	PLL_CTL(22579200, 0x57,
+		0x22, 0x04, 0x31, 0x03, 0x20, 0x03,
+		0x1A, 0x10, 0x1D, 0x03, 0xB3, 0x01),
+	PLL_CTL(24000000, 0x5D,
+		0x13, 0x04, 0x19, 0x03, 0x80, 0x01,
+		0x1B, 0x10, 0x19, 0x05, 0x4C, 0x02),
+	PLL_CTL(24576000, 0x5F,
+		0x13, 0x04, 0x1D, 0x03, 0xB3, 0x01,
+		0x22, 0x10, 0x40, 0x03, 0x72, 0x03),
+	PLL_CTL(27000000, 0x68,
+		0x22, 0x04, 0x4B, 0x03, 0x00, 0x04,
+		0x2A, 0x10, 0x7D, 0x03, 0x20, 0x06),
+	PLL_CTL(36000000, 0x8C,
+		0x1B, 0x04, 0x4B, 0x03, 0x00, 0x03,
+		0x2A, 0x10, 0x7D, 0x03, 0x98, 0x04),
+	PLL_CTL(25000000, 0x61,
+		0x1B, 0x04, 0x37, 0x03, 0x2B, 0x03,
+		0x1A, 0x10, 0x2A, 0x03, 0x39, 0x02),
+	PLL_CTL(26000000, 0x65,
+		0x23, 0x04, 0x41, 0x05, 0x00, 0x06,
+		0x1A, 0x10, 0x26, 0x03, 0xEF, 0x01),
+	PLL_CTL(12288000, 0x2F,
+		0x1A, 0x04, 0x12, 0x03, 0x1C, 0x02,
+		0x22, 0x10, 0x20, 0x03, 0x72, 0x03),
+	PLL_CTL(40000000, 0x9B,
+		0x22, 0x08, 0x7D, 0x03, 0x80, 0x04,
+		0x23, 0x10, 0x7D, 0x05, 0xE4, 0x06),
+	PLL_CTL(512000, 0x01,
+		0x22, 0x04, 0x01, 0x03, 0xD0, 0x02,
+		0x1B, 0x10, 0x01, 0x04, 0x72, 0x03),
+	PLL_CTL(705600, 0x02,
+		0x22, 0x04, 0x02, 0x03, 0x15, 0x04,
+		0x22, 0x10, 0x01, 0x04, 0x80, 0x02),
+	PLL_CTL(1024000, 0x03,
+		0x22, 0x04, 0x02, 0x03, 0xD0, 0x02,
+		0x1B, 0x10, 0x02, 0x04, 0x72, 0x03),
+	PLL_CTL(2048000, 0x07,
+		0x22, 0x04, 0x04, 0x03, 0xD0, 0x02,
+		0x1B, 0x10, 0x04, 0x04, 0x72, 0x03),
+	PLL_CTL(2400000, 0x08,
+		0x22, 0x04, 0x05, 0x03, 0x00, 0x03,
+		0x23, 0x10, 0x05, 0x05, 0x98, 0x04),
+};
+
+static const struct pll_ctl *get_pll_ctl(int input_freq)
+{
+	int i;
+	const struct pll_ctl *pll_ctl = NULL;
+
+	for (i = 0; i < ARRAY_SIZE(pll_ctls); ++i)
+		if (input_freq == pll_ctls[i].input_freq) {
+			pll_ctl = &pll_ctls[i];
+			break;
+		}
+
+	return pll_ctl;
+}
+
+static int set_pll_ctl_from_input_freq(struct snd_soc_component *component,
+		const int input_freq)
+{
+	int ret;
+	int i;
+	const struct pll_ctl *pll_ctl;
+
+	pll_ctl = get_pll_ctl(input_freq);
+	if (!pll_ctl) {
+		ret = -EINVAL;
+		dev_err(component->dev, "No PLL input entry for %d (%d)\n",
+			input_freq, ret);
+		return ret;
+	}
+
+	for (i = 0; i < PLL_REG_SETTINGS_COUNT; ++i) {
+		ret = snd_soc_component_update_bits(component,
+			pll_ctl->settings[i].addr,
+			pll_ctl->settings[i].mask,
+			pll_ctl->settings[i].val);
+		if (ret < 0) {
+			dev_err(component->dev, "Failed to set pll ctl (%d)\n",
+				ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int tscs42xx_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *codec_dai)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	int ret;
+
+	ret = setup_sample_format(component, params_format(params));
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to setup sample format (%d)\n",
+			ret);
+		return ret;
+	}
+
+	ret = setup_sample_rate(component, params_rate(params));
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to setup sample rate (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int dac_mute(struct snd_soc_component *component)
+{
+	int ret;
+
+	ret = snd_soc_component_update_bits(component,
+			R_CNVRTR1, RM_CNVRTR1_DACMU,
+		RV_CNVRTR1_DACMU_ENABLE);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to mute DAC (%d)\n",
+				ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int dac_unmute(struct snd_soc_component *component)
+{
+	int ret;
+
+	ret = snd_soc_component_update_bits(component,
+			R_CNVRTR1, RM_CNVRTR1_DACMU,
+		RV_CNVRTR1_DACMU_DISABLE);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to unmute DAC (%d)\n",
+				ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int adc_mute(struct snd_soc_component *component)
+{
+	int ret;
+
+	ret = snd_soc_component_update_bits(component,
+			R_CNVRTR0, RM_CNVRTR0_ADCMU, RV_CNVRTR0_ADCMU_ENABLE);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to mute ADC (%d)\n",
+				ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int adc_unmute(struct snd_soc_component *component)
+{
+	int ret;
+
+	ret = snd_soc_component_update_bits(component,
+			R_CNVRTR0, RM_CNVRTR0_ADCMU, RV_CNVRTR0_ADCMU_DISABLE);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to unmute ADC (%d)\n",
+				ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tscs42xx_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+	int ret;
+
+	if (mute)
+		if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+			ret = dac_mute(component);
+		else
+			ret = adc_mute(component);
+	else
+		if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+			ret = dac_unmute(component);
+		else
+			ret = adc_unmute(component);
+
+	return ret;
+}
+
+static int tscs42xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	int ret;
+
+	/* Slave mode not supported since it needs always-on frame clock */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		ret = snd_soc_component_update_bits(component,
+				R_AIC1, RM_AIC1_MS, RV_AIC1_MS_MASTER);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to set codec DAI master (%d)\n", ret);
+			return ret;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Unsupported format (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai,
+		unsigned int ratio)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
+	unsigned int value;
+	int ret = 0;
+
+	switch (ratio) {
+	case 32:
+		value = RV_DACSR_DBCM_32;
+		break;
+	case 40:
+		value = RV_DACSR_DBCM_40;
+		break;
+	case 64:
+		value = RV_DACSR_DBCM_64;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported bclk ratio (%d)\n", ret);
+		return -EINVAL;
+	}
+
+	ret = snd_soc_component_update_bits(component,
+			R_DACSR, RM_DACSR_DBCM, value);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to set DAC BCLK ratio (%d)\n", ret);
+		return ret;
+	}
+	ret = snd_soc_component_update_bits(component,
+			R_ADCSR, RM_ADCSR_ABCM, value);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to set ADC BCLK ratio (%d)\n", ret);
+		return ret;
+	}
+
+	mutex_lock(&tscs42xx->audio_params_lock);
+
+	tscs42xx->bclk_ratio = ratio;
+
+	mutex_unlock(&tscs42xx->audio_params_lock);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tscs42xx_dai_ops = {
+	.hw_params	= tscs42xx_hw_params,
+	.mute_stream	= tscs42xx_mute_stream,
+	.set_fmt	= tscs42xx_set_dai_fmt,
+	.set_bclk_ratio = tscs42xx_set_dai_bclk_ratio,
+};
+
+static int part_is_valid(struct tscs42xx *tscs42xx)
+{
+	int val;
+	int ret;
+	unsigned int reg;
+
+	ret = regmap_read(tscs42xx->regmap, R_DEVIDH, &reg);
+	if (ret < 0)
+		return ret;
+
+	val = reg << 8;
+	ret = regmap_read(tscs42xx->regmap, R_DEVIDL, &reg);
+	if (ret < 0)
+		return ret;
+
+	val |= reg;
+
+	switch (val) {
+	case 0x4A74:
+	case 0x4A73:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static int set_sysclk(struct snd_soc_component *component)
+{
+	struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
+	unsigned long freq;
+	int ret;
+
+	switch (tscs42xx->sysclk_src_id) {
+	case TSCS42XX_PLL_SRC_XTAL:
+	case TSCS42XX_PLL_SRC_MCLK1:
+		ret = snd_soc_component_write(component, R_PLLREFSEL,
+				RV_PLLREFSEL_PLL1_REF_SEL_XTAL_MCLK1 |
+				RV_PLLREFSEL_PLL2_REF_SEL_XTAL_MCLK1);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to set pll reference input (%d)\n",
+				ret);
+			return ret;
+		}
+		break;
+	case TSCS42XX_PLL_SRC_MCLK2:
+		ret = snd_soc_component_write(component, R_PLLREFSEL,
+				RV_PLLREFSEL_PLL1_REF_SEL_MCLK2 |
+				RV_PLLREFSEL_PLL2_REF_SEL_MCLK2);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to set PLL reference (%d)\n", ret);
+			return ret;
+		}
+		break;
+	default:
+		dev_err(component->dev, "pll src is unsupported\n");
+		return -EINVAL;
+	}
+
+	freq = clk_get_rate(tscs42xx->sysclk);
+	ret = set_pll_ctl_from_input_freq(component, freq);
+	if (ret < 0) {
+		dev_err(component->dev,
+			"Failed to setup PLL input freq (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tscs42xx_probe(struct snd_soc_component *component)
+{
+	return set_sysclk(component);
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_tscs42xx = {
+	.probe			= tscs42xx_probe,
+	.dapm_widgets		= tscs42xx_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tscs42xx_dapm_widgets),
+	.dapm_routes		= tscs42xx_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(tscs42xx_intercon),
+	.controls		= tscs42xx_snd_controls,
+	.num_controls		= ARRAY_SIZE(tscs42xx_snd_controls),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static inline void init_coeff_ram_cache(struct tscs42xx *tscs42xx)
+{
+	static const u8 norm_addrs[] = {
+		0x00, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1f, 0x20, 0x25, 0x2a,
+		0x2f, 0x34, 0x39, 0x3f, 0x40, 0x45, 0x4a, 0x4f, 0x54, 0x59,
+		0x5f, 0x60, 0x65, 0x6a, 0x6f, 0x74, 0x79, 0x7f, 0x80, 0x85,
+		0x8c, 0x91, 0x96, 0x97, 0x9c, 0xa3, 0xa8, 0xad, 0xaf, 0xb0,
+		0xb5, 0xba, 0xbf, 0xc4, 0xc9,
+	};
+	u8 *coeff_ram = tscs42xx->coeff_ram;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(norm_addrs); i++)
+		coeff_ram[((norm_addrs[i] + 1) * COEFF_SIZE) - 1] = 0x40;
+}
+
+#define TSCS42XX_RATES SNDRV_PCM_RATE_8000_96000
+
+#define TSCS42XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+	| SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver tscs42xx_dai = {
+	.name = "tscs42xx-HiFi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = TSCS42XX_RATES,
+		.formats = TSCS42XX_FORMATS,},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = TSCS42XX_RATES,
+		.formats = TSCS42XX_FORMATS,},
+	.ops = &tscs42xx_dai_ops,
+	.symmetric_rates = 1,
+	.symmetric_channels = 1,
+	.symmetric_samplebits = 1,
+};
+
+static const struct reg_sequence tscs42xx_patch[] = {
+	{ R_AIC2, RV_AIC2_BLRCM_DAC_BCLK_LRCLK_SHARED },
+};
+
+static char const * const src_names[TSCS42XX_PLL_SRC_CNT] = {
+	"xtal", "mclk1", "mclk2"};
+
+static int tscs42xx_i2c_probe(struct i2c_client *i2c,
+		const struct i2c_device_id *id)
+{
+	struct tscs42xx *tscs42xx;
+	int src;
+	int ret;
+
+	tscs42xx = devm_kzalloc(&i2c->dev, sizeof(*tscs42xx), GFP_KERNEL);
+	if (!tscs42xx) {
+		ret = -ENOMEM;
+		dev_err(&i2c->dev,
+			"Failed to allocate memory for data (%d)\n", ret);
+		return ret;
+	}
+	i2c_set_clientdata(i2c, tscs42xx);
+
+	for (src = TSCS42XX_PLL_SRC_XTAL; src < TSCS42XX_PLL_SRC_CNT; src++) {
+		tscs42xx->sysclk = devm_clk_get(&i2c->dev, src_names[src]);
+		if (!IS_ERR(tscs42xx->sysclk)) {
+			break;
+		} else if (PTR_ERR(tscs42xx->sysclk) != -ENOENT) {
+			ret = PTR_ERR(tscs42xx->sysclk);
+			dev_err(&i2c->dev, "Failed to get sysclk (%d)\n", ret);
+			return ret;
+		}
+	}
+	if (src == TSCS42XX_PLL_SRC_CNT) {
+		ret = -EINVAL;
+		dev_err(&i2c->dev, "Failed to get a valid clock name (%d)\n",
+				ret);
+		return ret;
+	}
+	tscs42xx->sysclk_src_id = src;
+
+	tscs42xx->regmap = devm_regmap_init_i2c(i2c, &tscs42xx_regmap);
+	if (IS_ERR(tscs42xx->regmap)) {
+		ret = PTR_ERR(tscs42xx->regmap);
+		dev_err(&i2c->dev, "Failed to allocate regmap (%d)\n", ret);
+		return ret;
+	}
+
+	init_coeff_ram_cache(tscs42xx);
+
+	ret = part_is_valid(tscs42xx);
+	if (ret <= 0) {
+		dev_err(&i2c->dev, "No valid part (%d)\n", ret);
+		ret = -ENODEV;
+		return ret;
+	}
+
+	ret = regmap_write(tscs42xx->regmap, R_RESET, RV_RESET_ENABLE);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to reset device (%d)\n", ret);
+		return ret;
+	}
+
+	ret = regmap_register_patch(tscs42xx->regmap, tscs42xx_patch,
+			ARRAY_SIZE(tscs42xx_patch));
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to apply patch (%d)\n", ret);
+		return ret;
+	}
+
+	mutex_init(&tscs42xx->audio_params_lock);
+	mutex_init(&tscs42xx->coeff_ram_lock);
+	mutex_init(&tscs42xx->pll_lock);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_codec_dev_tscs42xx, &tscs42xx_dai, 1);
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct i2c_device_id tscs42xx_i2c_id[] = {
+	{ "tscs42A1", 0 },
+	{ "tscs42A2", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tscs42xx_i2c_id);
+
+static const struct of_device_id tscs42xx_of_match[] = {
+	{ .compatible = "tempo,tscs42A1", },
+	{ .compatible = "tempo,tscs42A2", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tscs42xx_of_match);
+
+static struct i2c_driver tscs42xx_i2c_driver = {
+	.driver = {
+		.name = "tscs42xx",
+		.of_match_table = tscs42xx_of_match,
+	},
+	.probe =    tscs42xx_i2c_probe,
+	.id_table = tscs42xx_i2c_id,
+};
+
+module_i2c_driver(tscs42xx_i2c_driver);
+
+MODULE_AUTHOR("Tempo Semiconductor <steven.eckhoff.opensource@gmail.com");
+MODULE_DESCRIPTION("ASoC TSCS42xx driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tscs42xx.h b/sound/soc/codecs/tscs42xx.h
new file mode 100644
index 0000000..6b3a210
--- /dev/null
+++ b/sound/soc/codecs/tscs42xx.h
@@ -0,0 +1,2701 @@
+// SPDX-License-Identifier: GPL-2.0
+// tscs42xx.h -- TSCS42xx ALSA SoC Audio driver
+// Copyright 2017 Tempo Semiconductor, Inc.
+// Author: Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
+
+#ifndef __WOOKIE_H__
+#define __WOOKIE_H__
+
+enum {
+	TSCS42XX_PLL_SRC_XTAL,
+	TSCS42XX_PLL_SRC_MCLK1,
+	TSCS42XX_PLL_SRC_MCLK2,
+	TSCS42XX_PLL_SRC_CNT,
+};
+
+#define R_HPVOLL        0x0
+#define R_HPVOLR        0x1
+#define R_SPKVOLL       0x2
+#define R_SPKVOLR       0x3
+#define R_DACVOLL       0x4
+#define R_DACVOLR       0x5
+#define R_ADCVOLL       0x6
+#define R_ADCVOLR       0x7
+#define R_INVOLL        0x8
+#define R_INVOLR        0x9
+#define R_INMODE        0x0B
+#define R_INSELL        0x0C
+#define R_INSELR        0x0D
+#define R_AIC1          0x13
+#define R_AIC2          0x14
+#define R_CNVRTR0       0x16
+#define R_ADCSR         0x17
+#define R_CNVRTR1       0x18
+#define R_DACSR         0x19
+#define R_PWRM1         0x1A
+#define R_PWRM2         0x1B
+#define R_CTL		0x1C
+#define R_CONFIG0       0x1F
+#define R_CONFIG1       0x20
+#define R_DMICCTL       0x24
+#define R_CLECTL        0x25
+#define R_MUGAIN        0x26
+#define R_COMPTH        0x27
+#define R_CMPRAT        0x28
+#define R_CATKTCL       0x29
+#define R_CATKTCH       0x2A
+#define R_CRELTCL       0x2B
+#define R_CRELTCH       0x2C
+#define R_LIMTH         0x2D
+#define R_LIMTGT        0x2E
+#define R_LATKTCL       0x2F
+#define R_LATKTCH       0x30
+#define R_LRELTCL       0x31
+#define R_LRELTCH       0x32
+#define R_EXPTH         0x33
+#define R_EXPRAT        0x34
+#define R_XATKTCL       0x35
+#define R_XATKTCH       0x36
+#define R_XRELTCL       0x37
+#define R_XRELTCH       0x38
+#define R_FXCTL         0x39
+#define R_DACCRWRL      0x3A
+#define R_DACCRWRM      0x3B
+#define R_DACCRWRH      0x3C
+#define R_DACCRRDL      0x3D
+#define R_DACCRRDM      0x3E
+#define R_DACCRRDH      0x3F
+#define R_DACCRADDR     0x40
+#define R_DCOFSEL       0x41
+#define R_PLLCTL9       0x4E
+#define R_PLLCTLA       0x4F
+#define R_PLLCTLB       0x50
+#define R_PLLCTLC       0x51
+#define R_PLLCTLD       0x52
+#define R_PLLCTLE       0x53
+#define R_PLLCTLF       0x54
+#define R_PLLCTL10      0x55
+#define R_PLLCTL11      0x56
+#define R_PLLCTL12      0x57
+#define R_PLLCTL1B      0x60
+#define R_PLLCTL1C      0x61
+#define R_TIMEBASE      0x77
+#define R_DEVIDL        0x7D
+#define R_DEVIDH        0x7E
+#define R_RESET         0x80
+#define R_DACCRSTAT     0x8A
+#define R_PLLCTL0       0x8E
+#define R_PLLREFSEL     0x8F
+#define R_DACMBCEN      0xC7
+#define R_DACMBCCTL     0xC8
+#define R_DACMBCMUG1    0xC9
+#define R_DACMBCTHR1    0xCA
+#define R_DACMBCRAT1    0xCB
+#define R_DACMBCATK1L   0xCC
+#define R_DACMBCATK1H   0xCD
+#define R_DACMBCREL1L   0xCE
+#define R_DACMBCREL1H   0xCF
+#define R_DACMBCMUG2    0xD0
+#define R_DACMBCTHR2    0xD1
+#define R_DACMBCRAT2    0xD2
+#define R_DACMBCATK2L   0xD3
+#define R_DACMBCATK2H   0xD4
+#define R_DACMBCREL2L   0xD5
+#define R_DACMBCREL2H   0xD6
+#define R_DACMBCMUG3    0xD7
+#define R_DACMBCTHR3    0xD8
+#define R_DACMBCRAT3    0xD9
+#define R_DACMBCATK3L   0xDA
+#define R_DACMBCATK3H   0xDB
+#define R_DACMBCREL3L   0xDC
+#define R_DACMBCREL3H   0xDD
+
+/* Helpers */
+#define RM(m, b) ((m)<<(b))
+#define RV(v, b) ((v)<<(b))
+
+/****************************
+ *      R_HPVOLL (0x0)      *
+ ****************************/
+
+/* Field Offsets */
+#define FB_HPVOLL                            0
+
+/* Field Masks */
+#define FM_HPVOLL                            0X7F
+
+/* Field Values */
+#define FV_HPVOLL_P6DB                       0x7F
+#define FV_HPVOLL_N88PT5DB                   0x1
+#define FV_HPVOLL_MUTE                       0x0
+
+/* Register Masks */
+#define RM_HPVOLL                            RM(FM_HPVOLL, FB_HPVOLL)
+
+/* Register Values */
+#define RV_HPVOLL_P6DB                       RV(FV_HPVOLL_P6DB, FB_HPVOLL)
+#define RV_HPVOLL_N88PT5DB                   RV(FV_HPVOLL_N88PT5DB, FB_HPVOLL)
+#define RV_HPVOLL_MUTE                       RV(FV_HPVOLL_MUTE, FB_HPVOLL)
+
+/****************************
+ *      R_HPVOLR (0x1)      *
+ ****************************/
+
+/* Field Offsets */
+#define FB_HPVOLR                            0
+
+/* Field Masks */
+#define FM_HPVOLR                            0X7F
+
+/* Field Values */
+#define FV_HPVOLR_P6DB                       0x7F
+#define FV_HPVOLR_N88PT5DB                   0x1
+#define FV_HPVOLR_MUTE                       0x0
+
+/* Register Masks */
+#define RM_HPVOLR                            RM(FM_HPVOLR, FB_HPVOLR)
+
+/* Register Values */
+#define RV_HPVOLR_P6DB                       RV(FV_HPVOLR_P6DB, FB_HPVOLR)
+#define RV_HPVOLR_N88PT5DB                   RV(FV_HPVOLR_N88PT5DB, FB_HPVOLR)
+#define RV_HPVOLR_MUTE                       RV(FV_HPVOLR_MUTE, FB_HPVOLR)
+
+/*****************************
+ *      R_SPKVOLL (0x2)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_SPKVOLL                           0
+
+/* Field Masks */
+#define FM_SPKVOLL                           0X7F
+
+/* Field Values */
+#define FV_SPKVOLL_P12DB                     0x7F
+#define FV_SPKVOLL_N77PT25DB                 0x8
+#define FV_SPKVOLL_MUTE                      0x0
+
+/* Register Masks */
+#define RM_SPKVOLL                           RM(FM_SPKVOLL, FB_SPKVOLL)
+
+/* Register Values */
+#define RV_SPKVOLL_P12DB                     RV(FV_SPKVOLL_P12DB, FB_SPKVOLL)
+#define RV_SPKVOLL_N77PT25DB \
+	 RV(FV_SPKVOLL_N77PT25DB, FB_SPKVOLL)
+
+#define RV_SPKVOLL_MUTE                      RV(FV_SPKVOLL_MUTE, FB_SPKVOLL)
+
+/*****************************
+ *      R_SPKVOLR (0x3)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_SPKVOLR                           0
+
+/* Field Masks */
+#define FM_SPKVOLR                           0X7F
+
+/* Field Values */
+#define FV_SPKVOLR_P12DB                     0x7F
+#define FV_SPKVOLR_N77PT25DB                 0x8
+#define FV_SPKVOLR_MUTE                      0x0
+
+/* Register Masks */
+#define RM_SPKVOLR                           RM(FM_SPKVOLR, FB_SPKVOLR)
+
+/* Register Values */
+#define RV_SPKVOLR_P12DB                     RV(FV_SPKVOLR_P12DB, FB_SPKVOLR)
+#define RV_SPKVOLR_N77PT25DB \
+	 RV(FV_SPKVOLR_N77PT25DB, FB_SPKVOLR)
+
+#define RV_SPKVOLR_MUTE                      RV(FV_SPKVOLR_MUTE, FB_SPKVOLR)
+
+/*****************************
+ *      R_DACVOLL (0x4)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_DACVOLL                           0
+
+/* Field Masks */
+#define FM_DACVOLL                           0XFF
+
+/* Field Values */
+#define FV_DACVOLL_0DB                       0xFF
+#define FV_DACVOLL_N95PT625DB                0x1
+#define FV_DACVOLL_MUTE                      0x0
+
+/* Register Masks */
+#define RM_DACVOLL                           RM(FM_DACVOLL, FB_DACVOLL)
+
+/* Register Values */
+#define RV_DACVOLL_0DB                       RV(FV_DACVOLL_0DB, FB_DACVOLL)
+#define RV_DACVOLL_N95PT625DB \
+	 RV(FV_DACVOLL_N95PT625DB, FB_DACVOLL)
+
+#define RV_DACVOLL_MUTE                      RV(FV_DACVOLL_MUTE, FB_DACVOLL)
+
+/*****************************
+ *      R_DACVOLR (0x5)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_DACVOLR                           0
+
+/* Field Masks */
+#define FM_DACVOLR                           0XFF
+
+/* Field Values */
+#define FV_DACVOLR_0DB                       0xFF
+#define FV_DACVOLR_N95PT625DB                0x1
+#define FV_DACVOLR_MUTE                      0x0
+
+/* Register Masks */
+#define RM_DACVOLR                           RM(FM_DACVOLR, FB_DACVOLR)
+
+/* Register Values */
+#define RV_DACVOLR_0DB                       RV(FV_DACVOLR_0DB, FB_DACVOLR)
+#define RV_DACVOLR_N95PT625DB \
+	 RV(FV_DACVOLR_N95PT625DB, FB_DACVOLR)
+
+#define RV_DACVOLR_MUTE                      RV(FV_DACVOLR_MUTE, FB_DACVOLR)
+
+/*****************************
+ *      R_ADCVOLL (0x6)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_ADCVOLL                           0
+
+/* Field Masks */
+#define FM_ADCVOLL                           0XFF
+
+/* Field Values */
+#define FV_ADCVOLL_P24DB                     0xFF
+#define FV_ADCVOLL_N71PT25DB                 0x1
+#define FV_ADCVOLL_MUTE                      0x0
+
+/* Register Masks */
+#define RM_ADCVOLL                           RM(FM_ADCVOLL, FB_ADCVOLL)
+
+/* Register Values */
+#define RV_ADCVOLL_P24DB                     RV(FV_ADCVOLL_P24DB, FB_ADCVOLL)
+#define RV_ADCVOLL_N71PT25DB \
+	 RV(FV_ADCVOLL_N71PT25DB, FB_ADCVOLL)
+
+#define RV_ADCVOLL_MUTE                      RV(FV_ADCVOLL_MUTE, FB_ADCVOLL)
+
+/*****************************
+ *      R_ADCVOLR (0x7)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_ADCVOLR                           0
+
+/* Field Masks */
+#define FM_ADCVOLR                           0XFF
+
+/* Field Values */
+#define FV_ADCVOLR_P24DB                     0xFF
+#define FV_ADCVOLR_N71PT25DB                 0x1
+#define FV_ADCVOLR_MUTE                      0x0
+
+/* Register Masks */
+#define RM_ADCVOLR                           RM(FM_ADCVOLR, FB_ADCVOLR)
+
+/* Register Values */
+#define RV_ADCVOLR_P24DB                     RV(FV_ADCVOLR_P24DB, FB_ADCVOLR)
+#define RV_ADCVOLR_N71PT25DB \
+	 RV(FV_ADCVOLR_N71PT25DB, FB_ADCVOLR)
+
+#define RV_ADCVOLR_MUTE                      RV(FV_ADCVOLR_MUTE, FB_ADCVOLR)
+
+/****************************
+ *      R_INVOLL (0x8)      *
+ ****************************/
+
+/* Field Offsets */
+#define FB_INVOLL_INMUTEL                    7
+#define FB_INVOLL_IZCL                       6
+#define FB_INVOLL                            0
+
+/* Field Masks */
+#define FM_INVOLL_INMUTEL                    0X1
+#define FM_INVOLL_IZCL                       0X1
+#define FM_INVOLL                            0X3F
+
+/* Field Values */
+#define FV_INVOLL_INMUTEL_ENABLE             0x1
+#define FV_INVOLL_INMUTEL_DISABLE            0x0
+#define FV_INVOLL_IZCL_ENABLE                0x1
+#define FV_INVOLL_IZCL_DISABLE               0x0
+#define FV_INVOLL_P30DB                      0x3F
+#define FV_INVOLL_N17PT25DB                  0x0
+
+/* Register Masks */
+#define RM_INVOLL_INMUTEL \
+	 RM(FM_INVOLL_INMUTEL, FB_INVOLL_INMUTEL)
+
+#define RM_INVOLL_IZCL                       RM(FM_INVOLL_IZCL, FB_INVOLL_IZCL)
+#define RM_INVOLL                            RM(FM_INVOLL, FB_INVOLL)
+
+/* Register Values */
+#define RV_INVOLL_INMUTEL_ENABLE \
+	 RV(FV_INVOLL_INMUTEL_ENABLE, FB_INVOLL_INMUTEL)
+
+#define RV_INVOLL_INMUTEL_DISABLE \
+	 RV(FV_INVOLL_INMUTEL_DISABLE, FB_INVOLL_INMUTEL)
+
+#define RV_INVOLL_IZCL_ENABLE \
+	 RV(FV_INVOLL_IZCL_ENABLE, FB_INVOLL_IZCL)
+
+#define RV_INVOLL_IZCL_DISABLE \
+	 RV(FV_INVOLL_IZCL_DISABLE, FB_INVOLL_IZCL)
+
+#define RV_INVOLL_P30DB                      RV(FV_INVOLL_P30DB, FB_INVOLL)
+#define RV_INVOLL_N17PT25DB                  RV(FV_INVOLL_N17PT25DB, FB_INVOLL)
+
+/****************************
+ *      R_INVOLR (0x9)      *
+ ****************************/
+
+/* Field Offsets */
+#define FB_INVOLR_INMUTER                    7
+#define FB_INVOLR_IZCR                       6
+#define FB_INVOLR                            0
+
+/* Field Masks */
+#define FM_INVOLR_INMUTER                    0X1
+#define FM_INVOLR_IZCR                       0X1
+#define FM_INVOLR                            0X3F
+
+/* Field Values */
+#define FV_INVOLR_INMUTER_ENABLE             0x1
+#define FV_INVOLR_INMUTER_DISABLE            0x0
+#define FV_INVOLR_IZCR_ENABLE                0x1
+#define FV_INVOLR_IZCR_DISABLE               0x0
+#define FV_INVOLR_P30DB                      0x3F
+#define FV_INVOLR_N17PT25DB                  0x0
+
+/* Register Masks */
+#define RM_INVOLR_INMUTER \
+	 RM(FM_INVOLR_INMUTER, FB_INVOLR_INMUTER)
+
+#define RM_INVOLR_IZCR                       RM(FM_INVOLR_IZCR, FB_INVOLR_IZCR)
+#define RM_INVOLR                            RM(FM_INVOLR, FB_INVOLR)
+
+/* Register Values */
+#define RV_INVOLR_INMUTER_ENABLE \
+	 RV(FV_INVOLR_INMUTER_ENABLE, FB_INVOLR_INMUTER)
+
+#define RV_INVOLR_INMUTER_DISABLE \
+	 RV(FV_INVOLR_INMUTER_DISABLE, FB_INVOLR_INMUTER)
+
+#define RV_INVOLR_IZCR_ENABLE \
+	 RV(FV_INVOLR_IZCR_ENABLE, FB_INVOLR_IZCR)
+
+#define RV_INVOLR_IZCR_DISABLE \
+	 RV(FV_INVOLR_IZCR_DISABLE, FB_INVOLR_IZCR)
+
+#define RV_INVOLR_P30DB                      RV(FV_INVOLR_P30DB, FB_INVOLR)
+#define RV_INVOLR_N17PT25DB                  RV(FV_INVOLR_N17PT25DB, FB_INVOLR)
+
+/*****************************
+ *      R_INMODE (0x0B)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_INMODE_DS                         0
+
+/* Field Masks */
+#define FM_INMODE_DS                         0X1
+
+/* Field Values */
+#define FV_INMODE_DS_LRIN1                   0x0
+#define FV_INMODE_DS_LRIN2                   0x1
+
+/* Register Masks */
+#define RM_INMODE_DS                         RM(FM_INMODE_DS, FB_INMODE_DS)
+
+/* Register Values */
+#define RV_INMODE_DS_LRIN1 \
+	 RV(FV_INMODE_DS_LRIN1, FB_INMODE_DS)
+
+#define RV_INMODE_DS_LRIN2 \
+	 RV(FV_INMODE_DS_LRIN2, FB_INMODE_DS)
+
+
+/*****************************
+ *      R_INSELL (0x0C)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_INSELL                            6
+#define FB_INSELL_MICBSTL                    4
+
+/* Field Masks */
+#define FM_INSELL                            0X3
+#define FM_INSELL_MICBSTL                    0X3
+
+/* Field Values */
+#define FV_INSELL_IN1                        0x0
+#define FV_INSELL_IN2                        0x1
+#define FV_INSELL_IN3                        0x2
+#define FV_INSELL_D2S                        0x3
+#define FV_INSELL_MICBSTL_OFF                0x0
+#define FV_INSELL_MICBSTL_10DB               0x1
+#define FV_INSELL_MICBSTL_20DB               0x2
+#define FV_INSELL_MICBSTL_30DB               0x3
+
+/* Register Masks */
+#define RM_INSELL                            RM(FM_INSELL, FB_INSELL)
+#define RM_INSELL_MICBSTL \
+	 RM(FM_INSELL_MICBSTL, FB_INSELL_MICBSTL)
+
+
+/* Register Values */
+#define RV_INSELL_IN1                        RV(FV_INSELL_IN1, FB_INSELL)
+#define RV_INSELL_IN2                        RV(FV_INSELL_IN2, FB_INSELL)
+#define RV_INSELL_IN3                        RV(FV_INSELL_IN3, FB_INSELL)
+#define RV_INSELL_D2S                        RV(FV_INSELL_D2S, FB_INSELL)
+#define RV_INSELL_MICBSTL_OFF \
+	 RV(FV_INSELL_MICBSTL_OFF, FB_INSELL_MICBSTL)
+
+#define RV_INSELL_MICBSTL_10DB \
+	 RV(FV_INSELL_MICBSTL_10DB, FB_INSELL_MICBSTL)
+
+#define RV_INSELL_MICBSTL_20DB \
+	 RV(FV_INSELL_MICBSTL_20DB, FB_INSELL_MICBSTL)
+
+#define RV_INSELL_MICBSTL_30DB \
+	 RV(FV_INSELL_MICBSTL_30DB, FB_INSELL_MICBSTL)
+
+
+/*****************************
+ *      R_INSELR (0x0D)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_INSELR                            6
+#define FB_INSELR_MICBSTR                    4
+
+/* Field Masks */
+#define FM_INSELR                            0X3
+#define FM_INSELR_MICBSTR                    0X3
+
+/* Field Values */
+#define FV_INSELR_IN1                        0x0
+#define FV_INSELR_IN2                        0x1
+#define FV_INSELR_IN3                        0x2
+#define FV_INSELR_D2S                        0x3
+#define FV_INSELR_MICBSTR_OFF                0x0
+#define FV_INSELR_MICBSTR_10DB               0x1
+#define FV_INSELR_MICBSTR_20DB               0x2
+#define FV_INSELR_MICBSTR_30DB               0x3
+
+/* Register Masks */
+#define RM_INSELR                            RM(FM_INSELR, FB_INSELR)
+#define RM_INSELR_MICBSTR \
+	 RM(FM_INSELR_MICBSTR, FB_INSELR_MICBSTR)
+
+
+/* Register Values */
+#define RV_INSELR_IN1                        RV(FV_INSELR_IN1, FB_INSELR)
+#define RV_INSELR_IN2                        RV(FV_INSELR_IN2, FB_INSELR)
+#define RV_INSELR_IN3                        RV(FV_INSELR_IN3, FB_INSELR)
+#define RV_INSELR_D2S                        RV(FV_INSELR_D2S, FB_INSELR)
+#define RV_INSELR_MICBSTR_OFF \
+	 RV(FV_INSELR_MICBSTR_OFF, FB_INSELR_MICBSTR)
+
+#define RV_INSELR_MICBSTR_10DB \
+	 RV(FV_INSELR_MICBSTR_10DB, FB_INSELR_MICBSTR)
+
+#define RV_INSELR_MICBSTR_20DB \
+	 RV(FV_INSELR_MICBSTR_20DB, FB_INSELR_MICBSTR)
+
+#define RV_INSELR_MICBSTR_30DB \
+	 RV(FV_INSELR_MICBSTR_30DB, FB_INSELR_MICBSTR)
+
+
+/***************************
+ *      R_AIC1 (0x13)      *
+ ***************************/
+
+/* Field Offsets */
+#define FB_AIC1_BCLKINV                      6
+#define FB_AIC1_MS                           5
+#define FB_AIC1_LRP                          4
+#define FB_AIC1_WL                           2
+#define FB_AIC1_FORMAT                       0
+
+/* Field Masks */
+#define FM_AIC1_BCLKINV                      0X1
+#define FM_AIC1_MS                           0X1
+#define FM_AIC1_LRP                          0X1
+#define FM_AIC1_WL                           0X3
+#define FM_AIC1_FORMAT                       0X3
+
+/* Field Values */
+#define FV_AIC1_BCLKINV_ENABLE               0x1
+#define FV_AIC1_BCLKINV_DISABLE              0x0
+#define FV_AIC1_MS_MASTER                    0x1
+#define FV_AIC1_MS_SLAVE                     0x0
+#define FV_AIC1_LRP_INVERT                   0x1
+#define FV_AIC1_LRP_NORMAL                   0x0
+#define FV_AIC1_WL_16                        0x0
+#define FV_AIC1_WL_20                        0x1
+#define FV_AIC1_WL_24                        0x2
+#define FV_AIC1_WL_32                        0x3
+#define FV_AIC1_FORMAT_RIGHT                 0x0
+#define FV_AIC1_FORMAT_LEFT                  0x1
+#define FV_AIC1_FORMAT_I2S                   0x2
+
+/* Register Masks */
+#define RM_AIC1_BCLKINV \
+	 RM(FM_AIC1_BCLKINV, FB_AIC1_BCLKINV)
+
+#define RM_AIC1_MS                           RM(FM_AIC1_MS, FB_AIC1_MS)
+#define RM_AIC1_LRP                          RM(FM_AIC1_LRP, FB_AIC1_LRP)
+#define RM_AIC1_WL                           RM(FM_AIC1_WL, FB_AIC1_WL)
+#define RM_AIC1_FORMAT                       RM(FM_AIC1_FORMAT, FB_AIC1_FORMAT)
+
+/* Register Values */
+#define RV_AIC1_BCLKINV_ENABLE \
+	 RV(FV_AIC1_BCLKINV_ENABLE, FB_AIC1_BCLKINV)
+
+#define RV_AIC1_BCLKINV_DISABLE \
+	 RV(FV_AIC1_BCLKINV_DISABLE, FB_AIC1_BCLKINV)
+
+#define RV_AIC1_MS_MASTER                    RV(FV_AIC1_MS_MASTER, FB_AIC1_MS)
+#define RV_AIC1_MS_SLAVE                     RV(FV_AIC1_MS_SLAVE, FB_AIC1_MS)
+#define RV_AIC1_LRP_INVERT \
+	 RV(FV_AIC1_LRP_INVERT, FB_AIC1_LRP)
+
+#define RV_AIC1_LRP_NORMAL \
+	 RV(FV_AIC1_LRP_NORMAL, FB_AIC1_LRP)
+
+#define RV_AIC1_WL_16                        RV(FV_AIC1_WL_16, FB_AIC1_WL)
+#define RV_AIC1_WL_20                        RV(FV_AIC1_WL_20, FB_AIC1_WL)
+#define RV_AIC1_WL_24                        RV(FV_AIC1_WL_24, FB_AIC1_WL)
+#define RV_AIC1_WL_32                        RV(FV_AIC1_WL_32, FB_AIC1_WL)
+#define RV_AIC1_FORMAT_RIGHT \
+	 RV(FV_AIC1_FORMAT_RIGHT, FB_AIC1_FORMAT)
+
+#define RV_AIC1_FORMAT_LEFT \
+	 RV(FV_AIC1_FORMAT_LEFT, FB_AIC1_FORMAT)
+
+#define RV_AIC1_FORMAT_I2S \
+	 RV(FV_AIC1_FORMAT_I2S, FB_AIC1_FORMAT)
+
+
+/***************************
+ *      R_AIC2 (0x14)      *
+ ***************************/
+
+/* Field Offsets */
+#define FB_AIC2_DACDSEL                      6
+#define FB_AIC2_ADCDSEL                      4
+#define FB_AIC2_TRI                          3
+#define FB_AIC2_BLRCM                        0
+
+/* Field Masks */
+#define FM_AIC2_DACDSEL                      0X3
+#define FM_AIC2_ADCDSEL                      0X3
+#define FM_AIC2_TRI                          0X1
+#define FM_AIC2_BLRCM                        0X7
+
+/* Field Values */
+#define FV_AIC2_BLRCM_DAC_BCLK_LRCLK_SHARED  0x3
+
+/* Register Masks */
+#define RM_AIC2_DACDSEL \
+	 RM(FM_AIC2_DACDSEL, FB_AIC2_DACDSEL)
+
+#define RM_AIC2_ADCDSEL \
+	 RM(FM_AIC2_ADCDSEL, FB_AIC2_ADCDSEL)
+
+#define RM_AIC2_TRI                          RM(FM_AIC2_TRI, FB_AIC2_TRI)
+#define RM_AIC2_BLRCM                        RM(FM_AIC2_BLRCM, FB_AIC2_BLRCM)
+
+/* Register Values */
+#define RV_AIC2_BLRCM_DAC_BCLK_LRCLK_SHARED \
+	 RV(FV_AIC2_BLRCM_DAC_BCLK_LRCLK_SHARED, FB_AIC2_BLRCM)
+
+
+/******************************
+ *      R_CNVRTR0 (0x16)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_CNVRTR0_ADCPOLR                   7
+#define FB_CNVRTR0_ADCPOLL                   6
+#define FB_CNVRTR0_AMONOMIX                  4
+#define FB_CNVRTR0_ADCMU                     3
+#define FB_CNVRTR0_HPOR                      2
+#define FB_CNVRTR0_ADCHPDR                   1
+#define FB_CNVRTR0_ADCHPDL                   0
+
+/* Field Masks */
+#define FM_CNVRTR0_ADCPOLR                   0X1
+#define FM_CNVRTR0_ADCPOLL                   0X1
+#define FM_CNVRTR0_AMONOMIX                  0X3
+#define FM_CNVRTR0_ADCMU                     0X1
+#define FM_CNVRTR0_HPOR                      0X1
+#define FM_CNVRTR0_ADCHPDR                   0X1
+#define FM_CNVRTR0_ADCHPDL                   0X1
+
+/* Field Values */
+#define FV_CNVRTR0_ADCPOLR_INVERT            0x1
+#define FV_CNVRTR0_ADCPOLR_NORMAL            0x0
+#define FV_CNVRTR0_ADCPOLL_INVERT            0x1
+#define FV_CNVRTR0_ADCPOLL_NORMAL            0x0
+#define FV_CNVRTR0_ADCMU_ENABLE              0x1
+#define FV_CNVRTR0_ADCMU_DISABLE             0x0
+#define FV_CNVRTR0_ADCHPDR_ENABLE            0x1
+#define FV_CNVRTR0_ADCHPDR_DISABLE           0x0
+#define FV_CNVRTR0_ADCHPDL_ENABLE            0x1
+#define FV_CNVRTR0_ADCHPDL_DISABLE           0x0
+
+/* Register Masks */
+#define RM_CNVRTR0_ADCPOLR \
+	 RM(FM_CNVRTR0_ADCPOLR, FB_CNVRTR0_ADCPOLR)
+
+#define RM_CNVRTR0_ADCPOLL \
+	 RM(FM_CNVRTR0_ADCPOLL, FB_CNVRTR0_ADCPOLL)
+
+#define RM_CNVRTR0_AMONOMIX \
+	 RM(FM_CNVRTR0_AMONOMIX, FB_CNVRTR0_AMONOMIX)
+
+#define RM_CNVRTR0_ADCMU \
+	 RM(FM_CNVRTR0_ADCMU, FB_CNVRTR0_ADCMU)
+
+#define RM_CNVRTR0_HPOR \
+	 RM(FM_CNVRTR0_HPOR, FB_CNVRTR0_HPOR)
+
+#define RM_CNVRTR0_ADCHPDR \
+	 RM(FM_CNVRTR0_ADCHPDR, FB_CNVRTR0_ADCHPDR)
+
+#define RM_CNVRTR0_ADCHPDL \
+	 RM(FM_CNVRTR0_ADCHPDL, FB_CNVRTR0_ADCHPDL)
+
+
+/* Register Values */
+#define RV_CNVRTR0_ADCPOLR_INVERT \
+	 RV(FV_CNVRTR0_ADCPOLR_INVERT, FB_CNVRTR0_ADCPOLR)
+
+#define RV_CNVRTR0_ADCPOLR_NORMAL \
+	 RV(FV_CNVRTR0_ADCPOLR_NORMAL, FB_CNVRTR0_ADCPOLR)
+
+#define RV_CNVRTR0_ADCPOLL_INVERT \
+	 RV(FV_CNVRTR0_ADCPOLL_INVERT, FB_CNVRTR0_ADCPOLL)
+
+#define RV_CNVRTR0_ADCPOLL_NORMAL \
+	 RV(FV_CNVRTR0_ADCPOLL_NORMAL, FB_CNVRTR0_ADCPOLL)
+
+#define RV_CNVRTR0_ADCMU_ENABLE \
+	 RV(FV_CNVRTR0_ADCMU_ENABLE, FB_CNVRTR0_ADCMU)
+
+#define RV_CNVRTR0_ADCMU_DISABLE \
+	 RV(FV_CNVRTR0_ADCMU_DISABLE, FB_CNVRTR0_ADCMU)
+
+#define RV_CNVRTR0_ADCHPDR_ENABLE \
+	 RV(FV_CNVRTR0_ADCHPDR_ENABLE, FB_CNVRTR0_ADCHPDR)
+
+#define RV_CNVRTR0_ADCHPDR_DISABLE \
+	 RV(FV_CNVRTR0_ADCHPDR_DISABLE, FB_CNVRTR0_ADCHPDR)
+
+#define RV_CNVRTR0_ADCHPDL_ENABLE \
+	 RV(FV_CNVRTR0_ADCHPDL_ENABLE, FB_CNVRTR0_ADCHPDL)
+
+#define RV_CNVRTR0_ADCHPDL_DISABLE \
+	 RV(FV_CNVRTR0_ADCHPDL_DISABLE, FB_CNVRTR0_ADCHPDL)
+
+
+/****************************
+ *      R_ADCSR (0x17)      *
+ ****************************/
+
+/* Field Offsets */
+#define FB_ADCSR_ABCM                        6
+#define FB_ADCSR_ABR                         3
+#define FB_ADCSR_ABM                         0
+
+/* Field Masks */
+#define FM_ADCSR_ABCM                        0X3
+#define FM_ADCSR_ABR                         0X3
+#define FM_ADCSR_ABM                         0X7
+
+/* Field Values */
+#define FV_ADCSR_ABCM_AUTO                   0x0
+#define FV_ADCSR_ABCM_32                     0x1
+#define FV_ADCSR_ABCM_40                     0x2
+#define FV_ADCSR_ABCM_64                     0x3
+#define FV_ADCSR_ABR_32                      0x0
+#define FV_ADCSR_ABR_44_1                    0x1
+#define FV_ADCSR_ABR_48                      0x2
+#define FV_ADCSR_ABM_PT25                    0x0
+#define FV_ADCSR_ABM_PT5                     0x1
+#define FV_ADCSR_ABM_1                       0x2
+#define FV_ADCSR_ABM_2                       0x3
+
+/* Register Masks */
+#define RM_ADCSR_ABCM                        RM(FM_ADCSR_ABCM, FB_ADCSR_ABCM)
+#define RM_ADCSR_ABR                         RM(FM_ADCSR_ABR, FB_ADCSR_ABR)
+#define RM_ADCSR_ABM                         RM(FM_ADCSR_ABM, FB_ADCSR_ABM)
+
+/* Register Values */
+#define RV_ADCSR_ABCM_AUTO \
+	 RV(FV_ADCSR_ABCM_AUTO, FB_ADCSR_ABCM)
+
+#define RV_ADCSR_ABCM_32 \
+	 RV(FV_ADCSR_ABCM_32, FB_ADCSR_ABCM)
+
+#define RV_ADCSR_ABCM_40 \
+	 RV(FV_ADCSR_ABCM_40, FB_ADCSR_ABCM)
+
+#define RV_ADCSR_ABCM_64 \
+	 RV(FV_ADCSR_ABCM_64, FB_ADCSR_ABCM)
+
+#define RV_ADCSR_ABR_32                      RV(FV_ADCSR_ABR_32, FB_ADCSR_ABR)
+#define RV_ADCSR_ABR_44_1 \
+	 RV(FV_ADCSR_ABR_44_1, FB_ADCSR_ABR)
+
+#define RV_ADCSR_ABR_48                      RV(FV_ADCSR_ABR_48, FB_ADCSR_ABR)
+#define RV_ADCSR_ABR_                        RV(FV_ADCSR_ABR_, FB_ADCSR_ABR)
+#define RV_ADCSR_ABM_PT25 \
+	 RV(FV_ADCSR_ABM_PT25, FB_ADCSR_ABM)
+
+#define RV_ADCSR_ABM_PT5                     RV(FV_ADCSR_ABM_PT5, FB_ADCSR_ABM)
+#define RV_ADCSR_ABM_1                       RV(FV_ADCSR_ABM_1, FB_ADCSR_ABM)
+#define RV_ADCSR_ABM_2                       RV(FV_ADCSR_ABM_2, FB_ADCSR_ABM)
+
+/******************************
+ *      R_CNVRTR1 (0x18)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_CNVRTR1_DACPOLR                   7
+#define FB_CNVRTR1_DACPOLL                   6
+#define FB_CNVRTR1_DMONOMIX                  4
+#define FB_CNVRTR1_DACMU                     3
+#define FB_CNVRTR1_DEEMPH                    2
+#define FB_CNVRTR1_DACDITH                   0
+
+/* Field Masks */
+#define FM_CNVRTR1_DACPOLR                   0X1
+#define FM_CNVRTR1_DACPOLL                   0X1
+#define FM_CNVRTR1_DMONOMIX                  0X3
+#define FM_CNVRTR1_DACMU                     0X1
+#define FM_CNVRTR1_DEEMPH                    0X1
+#define FM_CNVRTR1_DACDITH                   0X3
+
+/* Field Values */
+#define FV_CNVRTR1_DACPOLR_INVERT            0x1
+#define FV_CNVRTR1_DACPOLR_NORMAL            0x0
+#define FV_CNVRTR1_DACPOLL_INVERT            0x1
+#define FV_CNVRTR1_DACPOLL_NORMAL            0x0
+#define FV_CNVRTR1_DMONOMIX_ENABLE           0x1
+#define FV_CNVRTR1_DMONOMIX_DISABLE          0x0
+#define FV_CNVRTR1_DACMU_ENABLE              0x1
+#define FV_CNVRTR1_DACMU_DISABLE             0x0
+
+/* Register Masks */
+#define RM_CNVRTR1_DACPOLR \
+	 RM(FM_CNVRTR1_DACPOLR, FB_CNVRTR1_DACPOLR)
+
+#define RM_CNVRTR1_DACPOLL \
+	 RM(FM_CNVRTR1_DACPOLL, FB_CNVRTR1_DACPOLL)
+
+#define RM_CNVRTR1_DMONOMIX \
+	 RM(FM_CNVRTR1_DMONOMIX, FB_CNVRTR1_DMONOMIX)
+
+#define RM_CNVRTR1_DACMU \
+	 RM(FM_CNVRTR1_DACMU, FB_CNVRTR1_DACMU)
+
+#define RM_CNVRTR1_DEEMPH \
+	 RM(FM_CNVRTR1_DEEMPH, FB_CNVRTR1_DEEMPH)
+
+#define RM_CNVRTR1_DACDITH \
+	 RM(FM_CNVRTR1_DACDITH, FB_CNVRTR1_DACDITH)
+
+
+/* Register Values */
+#define RV_CNVRTR1_DACPOLR_INVERT \
+	 RV(FV_CNVRTR1_DACPOLR_INVERT, FB_CNVRTR1_DACPOLR)
+
+#define RV_CNVRTR1_DACPOLR_NORMAL \
+	 RV(FV_CNVRTR1_DACPOLR_NORMAL, FB_CNVRTR1_DACPOLR)
+
+#define RV_CNVRTR1_DACPOLL_INVERT \
+	 RV(FV_CNVRTR1_DACPOLL_INVERT, FB_CNVRTR1_DACPOLL)
+
+#define RV_CNVRTR1_DACPOLL_NORMAL \
+	 RV(FV_CNVRTR1_DACPOLL_NORMAL, FB_CNVRTR1_DACPOLL)
+
+#define RV_CNVRTR1_DMONOMIX_ENABLE \
+	 RV(FV_CNVRTR1_DMONOMIX_ENABLE, FB_CNVRTR1_DMONOMIX)
+
+#define RV_CNVRTR1_DMONOMIX_DISABLE \
+	 RV(FV_CNVRTR1_DMONOMIX_DISABLE, FB_CNVRTR1_DMONOMIX)
+
+#define RV_CNVRTR1_DACMU_ENABLE \
+	 RV(FV_CNVRTR1_DACMU_ENABLE, FB_CNVRTR1_DACMU)
+
+#define RV_CNVRTR1_DACMU_DISABLE \
+	 RV(FV_CNVRTR1_DACMU_DISABLE, FB_CNVRTR1_DACMU)
+
+
+/****************************
+ *      R_DACSR (0x19)      *
+ ****************************/
+
+/* Field Offsets */
+#define FB_DACSR_DBCM                        6
+#define FB_DACSR_DBR                         3
+#define FB_DACSR_DBM                         0
+
+/* Field Masks */
+#define FM_DACSR_DBCM                        0X3
+#define FM_DACSR_DBR                         0X3
+#define FM_DACSR_DBM                         0X7
+
+/* Field Values */
+#define FV_DACSR_DBCM_AUTO                   0x0
+#define FV_DACSR_DBCM_32                     0x1
+#define FV_DACSR_DBCM_40                     0x2
+#define FV_DACSR_DBCM_64                     0x3
+#define FV_DACSR_DBR_32                      0x0
+#define FV_DACSR_DBR_44_1                    0x1
+#define FV_DACSR_DBR_48                      0x2
+#define FV_DACSR_DBM_PT25                    0x0
+#define FV_DACSR_DBM_PT5                     0x1
+#define FV_DACSR_DBM_1                       0x2
+#define FV_DACSR_DBM_2                       0x3
+
+/* Register Masks */
+#define RM_DACSR_DBCM                        RM(FM_DACSR_DBCM, FB_DACSR_DBCM)
+#define RM_DACSR_DBR                         RM(FM_DACSR_DBR, FB_DACSR_DBR)
+#define RM_DACSR_DBM                         RM(FM_DACSR_DBM, FB_DACSR_DBM)
+
+/* Register Values */
+#define RV_DACSR_DBCM_AUTO \
+	 RV(FV_DACSR_DBCM_AUTO, FB_DACSR_DBCM)
+
+#define RV_DACSR_DBCM_32 \
+	 RV(FV_DACSR_DBCM_32, FB_DACSR_DBCM)
+
+#define RV_DACSR_DBCM_40 \
+	 RV(FV_DACSR_DBCM_40, FB_DACSR_DBCM)
+
+#define RV_DACSR_DBCM_64 \
+	 RV(FV_DACSR_DBCM_64, FB_DACSR_DBCM)
+
+#define RV_DACSR_DBR_32                      RV(FV_DACSR_DBR_32, FB_DACSR_DBR)
+#define RV_DACSR_DBR_44_1 \
+	 RV(FV_DACSR_DBR_44_1, FB_DACSR_DBR)
+
+#define RV_DACSR_DBR_48                      RV(FV_DACSR_DBR_48, FB_DACSR_DBR)
+#define RV_DACSR_DBM_PT25 \
+	 RV(FV_DACSR_DBM_PT25, FB_DACSR_DBM)
+
+#define RV_DACSR_DBM_PT5                     RV(FV_DACSR_DBM_PT5, FB_DACSR_DBM)
+#define RV_DACSR_DBM_1                       RV(FV_DACSR_DBM_1, FB_DACSR_DBM)
+#define RV_DACSR_DBM_2                       RV(FV_DACSR_DBM_2, FB_DACSR_DBM)
+
+/****************************
+ *      R_PWRM1 (0x1A)      *
+ ****************************/
+
+/* Field Offsets */
+#define FB_PWRM1_BSTL                        7
+#define FB_PWRM1_BSTR                        6
+#define FB_PWRM1_PGAL                        5
+#define FB_PWRM1_PGAR                        4
+#define FB_PWRM1_ADCL                        3
+#define FB_PWRM1_ADCR                        2
+#define FB_PWRM1_MICB                        1
+#define FB_PWRM1_DIGENB                      0
+
+/* Field Masks */
+#define FM_PWRM1_BSTL                        0X1
+#define FM_PWRM1_BSTR                        0X1
+#define FM_PWRM1_PGAL                        0X1
+#define FM_PWRM1_PGAR                        0X1
+#define FM_PWRM1_ADCL                        0X1
+#define FM_PWRM1_ADCR                        0X1
+#define FM_PWRM1_MICB                        0X1
+#define FM_PWRM1_DIGENB                      0X1
+
+/* Field Values */
+#define FV_PWRM1_BSTL_ENABLE                 0x1
+#define FV_PWRM1_BSTL_DISABLE                0x0
+#define FV_PWRM1_BSTR_ENABLE                 0x1
+#define FV_PWRM1_BSTR_DISABLE                0x0
+#define FV_PWRM1_PGAL_ENABLE                 0x1
+#define FV_PWRM1_PGAL_DISABLE                0x0
+#define FV_PWRM1_PGAR_ENABLE                 0x1
+#define FV_PWRM1_PGAR_DISABLE                0x0
+#define FV_PWRM1_ADCL_ENABLE                 0x1
+#define FV_PWRM1_ADCL_DISABLE                0x0
+#define FV_PWRM1_ADCR_ENABLE                 0x1
+#define FV_PWRM1_ADCR_DISABLE                0x0
+#define FV_PWRM1_MICB_ENABLE                 0x1
+#define FV_PWRM1_MICB_DISABLE                0x0
+#define FV_PWRM1_DIGENB_DISABLE              0x1
+#define FV_PWRM1_DIGENB_ENABLE               0x0
+
+/* Register Masks */
+#define RM_PWRM1_BSTL                        RM(FM_PWRM1_BSTL, FB_PWRM1_BSTL)
+#define RM_PWRM1_BSTR                        RM(FM_PWRM1_BSTR, FB_PWRM1_BSTR)
+#define RM_PWRM1_PGAL                        RM(FM_PWRM1_PGAL, FB_PWRM1_PGAL)
+#define RM_PWRM1_PGAR                        RM(FM_PWRM1_PGAR, FB_PWRM1_PGAR)
+#define RM_PWRM1_ADCL                        RM(FM_PWRM1_ADCL, FB_PWRM1_ADCL)
+#define RM_PWRM1_ADCR                        RM(FM_PWRM1_ADCR, FB_PWRM1_ADCR)
+#define RM_PWRM1_MICB                        RM(FM_PWRM1_MICB, FB_PWRM1_MICB)
+#define RM_PWRM1_DIGENB \
+	 RM(FM_PWRM1_DIGENB, FB_PWRM1_DIGENB)
+
+
+/* Register Values */
+#define RV_PWRM1_BSTL_ENABLE \
+	 RV(FV_PWRM1_BSTL_ENABLE, FB_PWRM1_BSTL)
+
+#define RV_PWRM1_BSTL_DISABLE \
+	 RV(FV_PWRM1_BSTL_DISABLE, FB_PWRM1_BSTL)
+
+#define RV_PWRM1_BSTR_ENABLE \
+	 RV(FV_PWRM1_BSTR_ENABLE, FB_PWRM1_BSTR)
+
+#define RV_PWRM1_BSTR_DISABLE \
+	 RV(FV_PWRM1_BSTR_DISABLE, FB_PWRM1_BSTR)
+
+#define RV_PWRM1_PGAL_ENABLE \
+	 RV(FV_PWRM1_PGAL_ENABLE, FB_PWRM1_PGAL)
+
+#define RV_PWRM1_PGAL_DISABLE \
+	 RV(FV_PWRM1_PGAL_DISABLE, FB_PWRM1_PGAL)
+
+#define RV_PWRM1_PGAR_ENABLE \
+	 RV(FV_PWRM1_PGAR_ENABLE, FB_PWRM1_PGAR)
+
+#define RV_PWRM1_PGAR_DISABLE \
+	 RV(FV_PWRM1_PGAR_DISABLE, FB_PWRM1_PGAR)
+
+#define RV_PWRM1_ADCL_ENABLE \
+	 RV(FV_PWRM1_ADCL_ENABLE, FB_PWRM1_ADCL)
+
+#define RV_PWRM1_ADCL_DISABLE \
+	 RV(FV_PWRM1_ADCL_DISABLE, FB_PWRM1_ADCL)
+
+#define RV_PWRM1_ADCR_ENABLE \
+	 RV(FV_PWRM1_ADCR_ENABLE, FB_PWRM1_ADCR)
+
+#define RV_PWRM1_ADCR_DISABLE \
+	 RV(FV_PWRM1_ADCR_DISABLE, FB_PWRM1_ADCR)
+
+#define RV_PWRM1_MICB_ENABLE \
+	 RV(FV_PWRM1_MICB_ENABLE, FB_PWRM1_MICB)
+
+#define RV_PWRM1_MICB_DISABLE \
+	 RV(FV_PWRM1_MICB_DISABLE, FB_PWRM1_MICB)
+
+#define RV_PWRM1_DIGENB_DISABLE \
+	 RV(FV_PWRM1_DIGENB_DISABLE, FB_PWRM1_DIGENB)
+
+#define RV_PWRM1_DIGENB_ENABLE \
+	 RV(FV_PWRM1_DIGENB_ENABLE, FB_PWRM1_DIGENB)
+
+
+/****************************
+ *      R_PWRM2 (0x1B)      *
+ ****************************/
+
+/* Field Offsets */
+#define FB_PWRM2_D2S                         7
+#define FB_PWRM2_HPL                         6
+#define FB_PWRM2_HPR                         5
+#define FB_PWRM2_SPKL                        4
+#define FB_PWRM2_SPKR                        3
+#define FB_PWRM2_INSELL                      2
+#define FB_PWRM2_INSELR                      1
+#define FB_PWRM2_VREF                        0
+
+/* Field Masks */
+#define FM_PWRM2_D2S                         0X1
+#define FM_PWRM2_HPL                         0X1
+#define FM_PWRM2_HPR                         0X1
+#define FM_PWRM2_SPKL                        0X1
+#define FM_PWRM2_SPKR                        0X1
+#define FM_PWRM2_INSELL                      0X1
+#define FM_PWRM2_INSELR                      0X1
+#define FM_PWRM2_VREF                        0X1
+
+/* Field Values */
+#define FV_PWRM2_D2S_ENABLE                  0x1
+#define FV_PWRM2_D2S_DISABLE                 0x0
+#define FV_PWRM2_HPL_ENABLE                  0x1
+#define FV_PWRM2_HPL_DISABLE                 0x0
+#define FV_PWRM2_HPR_ENABLE                  0x1
+#define FV_PWRM2_HPR_DISABLE                 0x0
+#define FV_PWRM2_SPKL_ENABLE                 0x1
+#define FV_PWRM2_SPKL_DISABLE                0x0
+#define FV_PWRM2_SPKR_ENABLE                 0x1
+#define FV_PWRM2_SPKR_DISABLE                0x0
+#define FV_PWRM2_INSELL_ENABLE               0x1
+#define FV_PWRM2_INSELL_DISABLE              0x0
+#define FV_PWRM2_INSELR_ENABLE               0x1
+#define FV_PWRM2_INSELR_DISABLE              0x0
+#define FV_PWRM2_VREF_ENABLE                 0x1
+#define FV_PWRM2_VREF_DISABLE                0x0
+
+/* Register Masks */
+#define RM_PWRM2_D2S                         RM(FM_PWRM2_D2S, FB_PWRM2_D2S)
+#define RM_PWRM2_HPL                         RM(FM_PWRM2_HPL, FB_PWRM2_HPL)
+#define RM_PWRM2_HPR                         RM(FM_PWRM2_HPR, FB_PWRM2_HPR)
+#define RM_PWRM2_SPKL                        RM(FM_PWRM2_SPKL, FB_PWRM2_SPKL)
+#define RM_PWRM2_SPKR                        RM(FM_PWRM2_SPKR, FB_PWRM2_SPKR)
+#define RM_PWRM2_INSELL \
+	 RM(FM_PWRM2_INSELL, FB_PWRM2_INSELL)
+
+#define RM_PWRM2_INSELR \
+	 RM(FM_PWRM2_INSELR, FB_PWRM2_INSELR)
+
+#define RM_PWRM2_VREF                        RM(FM_PWRM2_VREF, FB_PWRM2_VREF)
+
+/* Register Values */
+#define RV_PWRM2_D2S_ENABLE \
+	 RV(FV_PWRM2_D2S_ENABLE, FB_PWRM2_D2S)
+
+#define RV_PWRM2_D2S_DISABLE \
+	 RV(FV_PWRM2_D2S_DISABLE, FB_PWRM2_D2S)
+
+#define RV_PWRM2_HPL_ENABLE \
+	 RV(FV_PWRM2_HPL_ENABLE, FB_PWRM2_HPL)
+
+#define RV_PWRM2_HPL_DISABLE \
+	 RV(FV_PWRM2_HPL_DISABLE, FB_PWRM2_HPL)
+
+#define RV_PWRM2_HPR_ENABLE \
+	 RV(FV_PWRM2_HPR_ENABLE, FB_PWRM2_HPR)
+
+#define RV_PWRM2_HPR_DISABLE \
+	 RV(FV_PWRM2_HPR_DISABLE, FB_PWRM2_HPR)
+
+#define RV_PWRM2_SPKL_ENABLE \
+	 RV(FV_PWRM2_SPKL_ENABLE, FB_PWRM2_SPKL)
+
+#define RV_PWRM2_SPKL_DISABLE \
+	 RV(FV_PWRM2_SPKL_DISABLE, FB_PWRM2_SPKL)
+
+#define RV_PWRM2_SPKR_ENABLE \
+	 RV(FV_PWRM2_SPKR_ENABLE, FB_PWRM2_SPKR)
+
+#define RV_PWRM2_SPKR_DISABLE \
+	 RV(FV_PWRM2_SPKR_DISABLE, FB_PWRM2_SPKR)
+
+#define RV_PWRM2_INSELL_ENABLE \
+	 RV(FV_PWRM2_INSELL_ENABLE, FB_PWRM2_INSELL)
+
+#define RV_PWRM2_INSELL_DISABLE \
+	 RV(FV_PWRM2_INSELL_DISABLE, FB_PWRM2_INSELL)
+
+#define RV_PWRM2_INSELR_ENABLE \
+	 RV(FV_PWRM2_INSELR_ENABLE, FB_PWRM2_INSELR)
+
+#define RV_PWRM2_INSELR_DISABLE \
+	 RV(FV_PWRM2_INSELR_DISABLE, FB_PWRM2_INSELR)
+
+#define RV_PWRM2_VREF_ENABLE \
+	 RV(FV_PWRM2_VREF_ENABLE, FB_PWRM2_VREF)
+
+#define RV_PWRM2_VREF_DISABLE \
+	 RV(FV_PWRM2_VREF_DISABLE, FB_PWRM2_VREF)
+
+/******************************
+ *      R_CTL (0x1C)          *
+ ******************************/
+
+/* Fiel Offsets */
+#define FB_CTL_HPSWEN                        7
+#define FB_CTL_HPSWPOL                       6
+
+/******************************
+ *      R_CONFIG0 (0x1F)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_CONFIG0_ASDM                      6
+#define FB_CONFIG0_DSDM                      4
+#define FB_CONFIG0_DC_BYPASS                 1
+#define FB_CONFIG0_SD_FORCE_ON               0
+
+/* Field Masks */
+#define FM_CONFIG0_ASDM                      0X3
+#define FM_CONFIG0_DSDM                      0X3
+#define FM_CONFIG0_DC_BYPASS                 0X1
+#define FM_CONFIG0_SD_FORCE_ON               0X1
+
+/* Field Values */
+#define FV_CONFIG0_ASDM_HALF                 0x1
+#define FV_CONFIG0_ASDM_FULL                 0x2
+#define FV_CONFIG0_ASDM_AUTO                 0x3
+#define FV_CONFIG0_DSDM_HALF                 0x1
+#define FV_CONFIG0_DSDM_FULL                 0x2
+#define FV_CONFIG0_DSDM_AUTO                 0x3
+#define FV_CONFIG0_DC_BYPASS_ENABLE          0x1
+#define FV_CONFIG0_DC_BYPASS_DISABLE         0x0
+#define FV_CONFIG0_SD_FORCE_ON_ENABLE        0x1
+#define FV_CONFIG0_SD_FORCE_ON_DISABLE       0x0
+
+/* Register Masks */
+#define RM_CONFIG0_ASDM \
+	 RM(FM_CONFIG0_ASDM, FB_CONFIG0_ASDM)
+
+#define RM_CONFIG0_DSDM \
+	 RM(FM_CONFIG0_DSDM, FB_CONFIG0_DSDM)
+
+#define RM_CONFIG0_DC_BYPASS \
+	 RM(FM_CONFIG0_DC_BYPASS, FB_CONFIG0_DC_BYPASS)
+
+#define RM_CONFIG0_SD_FORCE_ON \
+	 RM(FM_CONFIG0_SD_FORCE_ON, FB_CONFIG0_SD_FORCE_ON)
+
+
+/* Register Values */
+#define RV_CONFIG0_ASDM_HALF \
+	 RV(FV_CONFIG0_ASDM_HALF, FB_CONFIG0_ASDM)
+
+#define RV_CONFIG0_ASDM_FULL \
+	 RV(FV_CONFIG0_ASDM_FULL, FB_CONFIG0_ASDM)
+
+#define RV_CONFIG0_ASDM_AUTO \
+	 RV(FV_CONFIG0_ASDM_AUTO, FB_CONFIG0_ASDM)
+
+#define RV_CONFIG0_DSDM_HALF \
+	 RV(FV_CONFIG0_DSDM_HALF, FB_CONFIG0_DSDM)
+
+#define RV_CONFIG0_DSDM_FULL \
+	 RV(FV_CONFIG0_DSDM_FULL, FB_CONFIG0_DSDM)
+
+#define RV_CONFIG0_DSDM_AUTO \
+	 RV(FV_CONFIG0_DSDM_AUTO, FB_CONFIG0_DSDM)
+
+#define RV_CONFIG0_DC_BYPASS_ENABLE \
+	 RV(FV_CONFIG0_DC_BYPASS_ENABLE, FB_CONFIG0_DC_BYPASS)
+
+#define RV_CONFIG0_DC_BYPASS_DISABLE \
+	 RV(FV_CONFIG0_DC_BYPASS_DISABLE, FB_CONFIG0_DC_BYPASS)
+
+#define RV_CONFIG0_SD_FORCE_ON_ENABLE \
+	 RV(FV_CONFIG0_SD_FORCE_ON_ENABLE, FB_CONFIG0_SD_FORCE_ON)
+
+#define RV_CONFIG0_SD_FORCE_ON_DISABLE \
+	 RV(FV_CONFIG0_SD_FORCE_ON_DISABLE, FB_CONFIG0_SD_FORCE_ON)
+
+
+/******************************
+ *      R_CONFIG1 (0x20)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_CONFIG1_EQ2_EN                    7
+#define FB_CONFIG1_EQ2_BE                    4
+#define FB_CONFIG1_EQ1_EN                    3
+#define FB_CONFIG1_EQ1_BE                    0
+
+/* Field Masks */
+#define FM_CONFIG1_EQ2_EN                    0X1
+#define FM_CONFIG1_EQ2_BE                    0X7
+#define FM_CONFIG1_EQ1_EN                    0X1
+#define FM_CONFIG1_EQ1_BE                    0X7
+
+/* Field Values */
+#define FV_CONFIG1_EQ2_EN_ENABLE             0x1
+#define FV_CONFIG1_EQ2_EN_DISABLE            0x0
+#define FV_CONFIG1_EQ2_BE_PRE                0x0
+#define FV_CONFIG1_EQ2_BE_PRE_EQ_0           0x1
+#define FV_CONFIG1_EQ2_BE_PRE_EQ0_1          0x2
+#define FV_CONFIG1_EQ2_BE_PRE_EQ0_2          0x3
+#define FV_CONFIG1_EQ2_BE_PRE_EQ0_3          0x4
+#define FV_CONFIG1_EQ2_BE_PRE_EQ0_4          0x5
+#define FV_CONFIG1_EQ2_BE_PRE_EQ0_5          0x6
+#define FV_CONFIG1_EQ1_EN_ENABLE             0x1
+#define FV_CONFIG1_EQ1_EN_DISABLE            0x0
+#define FV_CONFIG1_EQ1_BE_PRE                0x0
+#define FV_CONFIG1_EQ1_BE_PRE_EQ_0           0x1
+#define FV_CONFIG1_EQ1_BE_PRE_EQ0_1          0x2
+#define FV_CONFIG1_EQ1_BE_PRE_EQ0_2          0x3
+#define FV_CONFIG1_EQ1_BE_PRE_EQ0_3          0x4
+#define FV_CONFIG1_EQ1_BE_PRE_EQ0_4          0x5
+#define FV_CONFIG1_EQ1_BE_PRE_EQ0_5          0x6
+
+/* Register Masks */
+#define RM_CONFIG1_EQ2_EN \
+	 RM(FM_CONFIG1_EQ2_EN, FB_CONFIG1_EQ2_EN)
+
+#define RM_CONFIG1_EQ2_BE \
+	 RM(FM_CONFIG1_EQ2_BE, FB_CONFIG1_EQ2_BE)
+
+#define RM_CONFIG1_EQ1_EN \
+	 RM(FM_CONFIG1_EQ1_EN, FB_CONFIG1_EQ1_EN)
+
+#define RM_CONFIG1_EQ1_BE \
+	 RM(FM_CONFIG1_EQ1_BE, FB_CONFIG1_EQ1_BE)
+
+
+/* Register Values */
+#define RV_CONFIG1_EQ2_EN_ENABLE \
+	 RV(FV_CONFIG1_EQ2_EN_ENABLE, FB_CONFIG1_EQ2_EN)
+
+#define RV_CONFIG1_EQ2_EN_DISABLE \
+	 RV(FV_CONFIG1_EQ2_EN_DISABLE, FB_CONFIG1_EQ2_EN)
+
+#define RV_CONFIG1_EQ2_BE_PRE \
+	 RV(FV_CONFIG1_EQ2_BE_PRE, FB_CONFIG1_EQ2_BE)
+
+#define RV_CONFIG1_EQ2_BE_PRE_EQ_0 \
+	 RV(FV_CONFIG1_EQ2_BE_PRE_EQ_0, FB_CONFIG1_EQ2_BE)
+
+#define RV_CONFIG1_EQ2_BE_PRE_EQ0_1 \
+	 RV(FV_CONFIG1_EQ2_BE_PRE_EQ0_1, FB_CONFIG1_EQ2_BE)
+
+#define RV_CONFIG1_EQ2_BE_PRE_EQ0_2 \
+	 RV(FV_CONFIG1_EQ2_BE_PRE_EQ0_2, FB_CONFIG1_EQ2_BE)
+
+#define RV_CONFIG1_EQ2_BE_PRE_EQ0_3 \
+	 RV(FV_CONFIG1_EQ2_BE_PRE_EQ0_3, FB_CONFIG1_EQ2_BE)
+
+#define RV_CONFIG1_EQ2_BE_PRE_EQ0_4 \
+	 RV(FV_CONFIG1_EQ2_BE_PRE_EQ0_4, FB_CONFIG1_EQ2_BE)
+
+#define RV_CONFIG1_EQ2_BE_PRE_EQ0_5 \
+	 RV(FV_CONFIG1_EQ2_BE_PRE_EQ0_5, FB_CONFIG1_EQ2_BE)
+
+#define RV_CONFIG1_EQ1_EN_ENABLE \
+	 RV(FV_CONFIG1_EQ1_EN_ENABLE, FB_CONFIG1_EQ1_EN)
+
+#define RV_CONFIG1_EQ1_EN_DISABLE \
+	 RV(FV_CONFIG1_EQ1_EN_DISABLE, FB_CONFIG1_EQ1_EN)
+
+#define RV_CONFIG1_EQ1_BE_PRE \
+	 RV(FV_CONFIG1_EQ1_BE_PRE, FB_CONFIG1_EQ1_BE)
+
+#define RV_CONFIG1_EQ1_BE_PRE_EQ_0 \
+	 RV(FV_CONFIG1_EQ1_BE_PRE_EQ_0, FB_CONFIG1_EQ1_BE)
+
+#define RV_CONFIG1_EQ1_BE_PRE_EQ0_1 \
+	 RV(FV_CONFIG1_EQ1_BE_PRE_EQ0_1, FB_CONFIG1_EQ1_BE)
+
+#define RV_CONFIG1_EQ1_BE_PRE_EQ0_2 \
+	 RV(FV_CONFIG1_EQ1_BE_PRE_EQ0_2, FB_CONFIG1_EQ1_BE)
+
+#define RV_CONFIG1_EQ1_BE_PRE_EQ0_3 \
+	 RV(FV_CONFIG1_EQ1_BE_PRE_EQ0_3, FB_CONFIG1_EQ1_BE)
+
+#define RV_CONFIG1_EQ1_BE_PRE_EQ0_4 \
+	 RV(FV_CONFIG1_EQ1_BE_PRE_EQ0_4, FB_CONFIG1_EQ1_BE)
+
+#define RV_CONFIG1_EQ1_BE_PRE_EQ0_5 \
+	 RV(FV_CONFIG1_EQ1_BE_PRE_EQ0_5, FB_CONFIG1_EQ1_BE)
+
+
+/******************************
+ *      R_DMICCTL (0x24)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_DMICCTL_DMICEN                    7
+#define FB_DMICCTL_DMONO                     4
+#define FB_DMICCTL_DMPHADJ                   2
+#define FB_DMICCTL_DMRATE                    0
+
+/* Field Masks */
+#define FM_DMICCTL_DMICEN                    0X1
+#define FM_DMICCTL_DMONO                     0X1
+#define FM_DMICCTL_DMPHADJ                   0X3
+#define FM_DMICCTL_DMRATE                    0X3
+
+/* Field Values */
+#define FV_DMICCTL_DMICEN_ENABLE             0x1
+#define FV_DMICCTL_DMICEN_DISABLE            0x0
+#define FV_DMICCTL_DMONO_STEREO              0x0
+#define FV_DMICCTL_DMONO_MONO                0x1
+
+/* Register Masks */
+#define RM_DMICCTL_DMICEN \
+	 RM(FM_DMICCTL_DMICEN, FB_DMICCTL_DMICEN)
+
+#define RM_DMICCTL_DMONO \
+	 RM(FM_DMICCTL_DMONO, FB_DMICCTL_DMONO)
+
+#define RM_DMICCTL_DMPHADJ \
+	 RM(FM_DMICCTL_DMPHADJ, FB_DMICCTL_DMPHADJ)
+
+#define RM_DMICCTL_DMRATE \
+	 RM(FM_DMICCTL_DMRATE, FB_DMICCTL_DMRATE)
+
+
+/* Register Values */
+#define RV_DMICCTL_DMICEN_ENABLE \
+	 RV(FV_DMICCTL_DMICEN_ENABLE, FB_DMICCTL_DMICEN)
+
+#define RV_DMICCTL_DMICEN_DISABLE \
+	 RV(FV_DMICCTL_DMICEN_DISABLE, FB_DMICCTL_DMICEN)
+
+#define RV_DMICCTL_DMONO_STEREO \
+	 RV(FV_DMICCTL_DMONO_STEREO, FB_DMICCTL_DMONO)
+
+#define RV_DMICCTL_DMONO_MONO \
+	 RV(FV_DMICCTL_DMONO_MONO, FB_DMICCTL_DMONO)
+
+
+/*****************************
+ *      R_CLECTL (0x25)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_CLECTL_LVL_MODE                   4
+#define FB_CLECTL_WINDOWSEL                  3
+#define FB_CLECTL_EXP_EN                     2
+#define FB_CLECTL_LIMIT_EN                   1
+#define FB_CLECTL_COMP_EN                    0
+
+/* Field Masks */
+#define FM_CLECTL_LVL_MODE                   0X1
+#define FM_CLECTL_WINDOWSEL                  0X1
+#define FM_CLECTL_EXP_EN                     0X1
+#define FM_CLECTL_LIMIT_EN                   0X1
+#define FM_CLECTL_COMP_EN                    0X1
+
+/* Field Values */
+#define FV_CLECTL_LVL_MODE_AVG               0x0
+#define FV_CLECTL_LVL_MODE_PEAK              0x1
+#define FV_CLECTL_WINDOWSEL_512              0x0
+#define FV_CLECTL_WINDOWSEL_64               0x1
+#define FV_CLECTL_EXP_EN_ENABLE              0x1
+#define FV_CLECTL_EXP_EN_DISABLE             0x0
+#define FV_CLECTL_LIMIT_EN_ENABLE            0x1
+#define FV_CLECTL_LIMIT_EN_DISABLE           0x0
+#define FV_CLECTL_COMP_EN_ENABLE             0x1
+#define FV_CLECTL_COMP_EN_DISABLE            0x0
+
+/* Register Masks */
+#define RM_CLECTL_LVL_MODE \
+	 RM(FM_CLECTL_LVL_MODE, FB_CLECTL_LVL_MODE)
+
+#define RM_CLECTL_WINDOWSEL \
+	 RM(FM_CLECTL_WINDOWSEL, FB_CLECTL_WINDOWSEL)
+
+#define RM_CLECTL_EXP_EN \
+	 RM(FM_CLECTL_EXP_EN, FB_CLECTL_EXP_EN)
+
+#define RM_CLECTL_LIMIT_EN \
+	 RM(FM_CLECTL_LIMIT_EN, FB_CLECTL_LIMIT_EN)
+
+#define RM_CLECTL_COMP_EN \
+	 RM(FM_CLECTL_COMP_EN, FB_CLECTL_COMP_EN)
+
+
+/* Register Values */
+#define RV_CLECTL_LVL_MODE_AVG \
+	 RV(FV_CLECTL_LVL_MODE_AVG, FB_CLECTL_LVL_MODE)
+
+#define RV_CLECTL_LVL_MODE_PEAK \
+	 RV(FV_CLECTL_LVL_MODE_PEAK, FB_CLECTL_LVL_MODE)
+
+#define RV_CLECTL_WINDOWSEL_512 \
+	 RV(FV_CLECTL_WINDOWSEL_512, FB_CLECTL_WINDOWSEL)
+
+#define RV_CLECTL_WINDOWSEL_64 \
+	 RV(FV_CLECTL_WINDOWSEL_64, FB_CLECTL_WINDOWSEL)
+
+#define RV_CLECTL_EXP_EN_ENABLE \
+	 RV(FV_CLECTL_EXP_EN_ENABLE, FB_CLECTL_EXP_EN)
+
+#define RV_CLECTL_EXP_EN_DISABLE \
+	 RV(FV_CLECTL_EXP_EN_DISABLE, FB_CLECTL_EXP_EN)
+
+#define RV_CLECTL_LIMIT_EN_ENABLE \
+	 RV(FV_CLECTL_LIMIT_EN_ENABLE, FB_CLECTL_LIMIT_EN)
+
+#define RV_CLECTL_LIMIT_EN_DISABLE \
+	 RV(FV_CLECTL_LIMIT_EN_DISABLE, FB_CLECTL_LIMIT_EN)
+
+#define RV_CLECTL_COMP_EN_ENABLE \
+	 RV(FV_CLECTL_COMP_EN_ENABLE, FB_CLECTL_COMP_EN)
+
+#define RV_CLECTL_COMP_EN_DISABLE \
+	 RV(FV_CLECTL_COMP_EN_DISABLE, FB_CLECTL_COMP_EN)
+
+
+/*****************************
+ *      R_MUGAIN (0x26)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_MUGAIN_CLEMUG                     0
+
+/* Field Masks */
+#define FM_MUGAIN_CLEMUG                     0X1F
+
+/* Field Values */
+#define FV_MUGAIN_CLEMUG_46PT5DB             0x1F
+#define FV_MUGAIN_CLEMUG_0DB                 0x0
+
+/* Register Masks */
+#define RM_MUGAIN_CLEMUG \
+	 RM(FM_MUGAIN_CLEMUG, FB_MUGAIN_CLEMUG)
+
+
+/* Register Values */
+#define RV_MUGAIN_CLEMUG_46PT5DB \
+	 RV(FV_MUGAIN_CLEMUG_46PT5DB, FB_MUGAIN_CLEMUG)
+
+#define RV_MUGAIN_CLEMUG_0DB \
+	 RV(FV_MUGAIN_CLEMUG_0DB, FB_MUGAIN_CLEMUG)
+
+
+/*****************************
+ *      R_COMPTH (0x27)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_COMPTH                            0
+
+/* Field Masks */
+#define FM_COMPTH                            0XFF
+
+/* Field Values */
+#define FV_COMPTH_0DB                        0xFF
+#define FV_COMPTH_N95PT625DB                 0x0
+
+/* Register Masks */
+#define RM_COMPTH                            RM(FM_COMPTH, FB_COMPTH)
+
+/* Register Values */
+#define RV_COMPTH_0DB                        RV(FV_COMPTH_0DB, FB_COMPTH)
+#define RV_COMPTH_N95PT625DB \
+	 RV(FV_COMPTH_N95PT625DB, FB_COMPTH)
+
+
+/*****************************
+ *      R_CMPRAT (0x28)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_CMPRAT                            0
+
+/* Field Masks */
+#define FM_CMPRAT                            0X1F
+
+/* Register Masks */
+#define RM_CMPRAT                            RM(FM_CMPRAT, FB_CMPRAT)
+
+/******************************
+ *      R_CATKTCL (0x29)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_CATKTCL                           0
+
+/* Field Masks */
+#define FM_CATKTCL                           0XFF
+
+/* Register Masks */
+#define RM_CATKTCL                           RM(FM_CATKTCL, FB_CATKTCL)
+
+/******************************
+ *      R_CATKTCH (0x2A)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_CATKTCH                           0
+
+/* Field Masks */
+#define FM_CATKTCH                           0XFF
+
+/* Register Masks */
+#define RM_CATKTCH                           RM(FM_CATKTCH, FB_CATKTCH)
+
+/******************************
+ *      R_CRELTCL (0x2B)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_CRELTCL                           0
+
+/* Field Masks */
+#define FM_CRELTCL                           0XFF
+
+/* Register Masks */
+#define RM_CRELTCL                           RM(FM_CRELTCL, FB_CRELTCL)
+
+/******************************
+ *      R_CRELTCH (0x2C)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_CRELTCH                           0
+
+/* Field Masks */
+#define FM_CRELTCH                           0XFF
+
+/* Register Masks */
+#define RM_CRELTCH                           RM(FM_CRELTCH, FB_CRELTCH)
+
+/****************************
+ *      R_LIMTH (0x2D)      *
+ ****************************/
+
+/* Field Offsets */
+#define FB_LIMTH                             0
+
+/* Field Masks */
+#define FM_LIMTH                             0XFF
+
+/* Field Values */
+#define FV_LIMTH_0DB                         0xFF
+#define FV_LIMTH_N95PT625DB                  0x0
+
+/* Register Masks */
+#define RM_LIMTH                             RM(FM_LIMTH, FB_LIMTH)
+
+/* Register Values */
+#define RV_LIMTH_0DB                         RV(FV_LIMTH_0DB, FB_LIMTH)
+#define RV_LIMTH_N95PT625DB                  RV(FV_LIMTH_N95PT625DB, FB_LIMTH)
+
+/*****************************
+ *      R_LIMTGT (0x2E)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_LIMTGT                            0
+
+/* Field Masks */
+#define FM_LIMTGT                            0XFF
+
+/* Field Values */
+#define FV_LIMTGT_0DB                        0xFF
+#define FV_LIMTGT_N95PT625DB                 0x0
+
+/* Register Masks */
+#define RM_LIMTGT                            RM(FM_LIMTGT, FB_LIMTGT)
+
+/* Register Values */
+#define RV_LIMTGT_0DB                        RV(FV_LIMTGT_0DB, FB_LIMTGT)
+#define RV_LIMTGT_N95PT625DB \
+	 RV(FV_LIMTGT_N95PT625DB, FB_LIMTGT)
+
+
+/******************************
+ *      R_LATKTCL (0x2F)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_LATKTCL                           0
+
+/* Field Masks */
+#define FM_LATKTCL                           0XFF
+
+/* Register Masks */
+#define RM_LATKTCL                           RM(FM_LATKTCL, FB_LATKTCL)
+
+/******************************
+ *      R_LATKTCH (0x30)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_LATKTCH                           0
+
+/* Field Masks */
+#define FM_LATKTCH                           0XFF
+
+/* Register Masks */
+#define RM_LATKTCH                           RM(FM_LATKTCH, FB_LATKTCH)
+
+/******************************
+ *      R_LRELTCL (0x31)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_LRELTCL                           0
+
+/* Field Masks */
+#define FM_LRELTCL                           0XFF
+
+/* Register Masks */
+#define RM_LRELTCL                           RM(FM_LRELTCL, FB_LRELTCL)
+
+/******************************
+ *      R_LRELTCH (0x32)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_LRELTCH                           0
+
+/* Field Masks */
+#define FM_LRELTCH                           0XFF
+
+/* Register Masks */
+#define RM_LRELTCH                           RM(FM_LRELTCH, FB_LRELTCH)
+
+/****************************
+ *      R_EXPTH (0x33)      *
+ ****************************/
+
+/* Field Offsets */
+#define FB_EXPTH                             0
+
+/* Field Masks */
+#define FM_EXPTH                             0XFF
+
+/* Field Values */
+#define FV_EXPTH_0DB                         0xFF
+#define FV_EXPTH_N95PT625DB                  0x0
+
+/* Register Masks */
+#define RM_EXPTH                             RM(FM_EXPTH, FB_EXPTH)
+
+/* Register Values */
+#define RV_EXPTH_0DB                         RV(FV_EXPTH_0DB, FB_EXPTH)
+#define RV_EXPTH_N95PT625DB                  RV(FV_EXPTH_N95PT625DB, FB_EXPTH)
+
+/*****************************
+ *      R_EXPRAT (0x34)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_EXPRAT                            0
+
+/* Field Masks */
+#define FM_EXPRAT                            0X7
+
+/* Register Masks */
+#define RM_EXPRAT                            RM(FM_EXPRAT, FB_EXPRAT)
+
+/******************************
+ *      R_XATKTCL (0x35)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_XATKTCL                           0
+
+/* Field Masks */
+#define FM_XATKTCL                           0XFF
+
+/* Register Masks */
+#define RM_XATKTCL                           RM(FM_XATKTCL, FB_XATKTCL)
+
+/******************************
+ *      R_XATKTCH (0x36)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_XATKTCH                           0
+
+/* Field Masks */
+#define FM_XATKTCH                           0XFF
+
+/* Register Masks */
+#define RM_XATKTCH                           RM(FM_XATKTCH, FB_XATKTCH)
+
+/******************************
+ *      R_XRELTCL (0x37)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_XRELTCL                           0
+
+/* Field Masks */
+#define FM_XRELTCL                           0XFF
+
+/* Register Masks */
+#define RM_XRELTCL                           RM(FM_XRELTCL, FB_XRELTCL)
+
+/******************************
+ *      R_XRELTCH (0x38)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_XRELTCH                           0
+
+/* Field Masks */
+#define FM_XRELTCH                           0XFF
+
+/* Register Masks */
+#define RM_XRELTCH                           RM(FM_XRELTCH, FB_XRELTCH)
+
+/****************************
+ *      R_FXCTL (0x39)      *
+ ****************************/
+
+/* Field Offsets */
+#define FB_FXCTL_3DEN                        4
+#define FB_FXCTL_TEEN                        3
+#define FB_FXCTL_TNLFBYPASS                  2
+#define FB_FXCTL_BEEN                        1
+#define FB_FXCTL_BNLFBYPASS                  0
+
+/* Field Masks */
+#define FM_FXCTL_3DEN                        0X1
+#define FM_FXCTL_TEEN                        0X1
+#define FM_FXCTL_TNLFBYPASS                  0X1
+#define FM_FXCTL_BEEN                        0X1
+#define FM_FXCTL_BNLFBYPASS                  0X1
+
+/* Field Values */
+#define FV_FXCTL_3DEN_ENABLE                 0x1
+#define FV_FXCTL_3DEN_DISABLE                0x0
+#define FV_FXCTL_TEEN_ENABLE                 0x1
+#define FV_FXCTL_TEEN_DISABLE                0x0
+#define FV_FXCTL_TNLFBYPASS_ENABLE           0x1
+#define FV_FXCTL_TNLFBYPASS_DISABLE          0x0
+#define FV_FXCTL_BEEN_ENABLE                 0x1
+#define FV_FXCTL_BEEN_DISABLE                0x0
+#define FV_FXCTL_BNLFBYPASS_ENABLE           0x1
+#define FV_FXCTL_BNLFBYPASS_DISABLE          0x0
+
+/* Register Masks */
+#define RM_FXCTL_3DEN                        RM(FM_FXCTL_3DEN, FB_FXCTL_3DEN)
+#define RM_FXCTL_TEEN                        RM(FM_FXCTL_TEEN, FB_FXCTL_TEEN)
+#define RM_FXCTL_TNLFBYPASS \
+	 RM(FM_FXCTL_TNLFBYPASS, FB_FXCTL_TNLFBYPASS)
+
+#define RM_FXCTL_BEEN                        RM(FM_FXCTL_BEEN, FB_FXCTL_BEEN)
+#define RM_FXCTL_BNLFBYPASS \
+	 RM(FM_FXCTL_BNLFBYPASS, FB_FXCTL_BNLFBYPASS)
+
+
+/* Register Values */
+#define RV_FXCTL_3DEN_ENABLE \
+	 RV(FV_FXCTL_3DEN_ENABLE, FB_FXCTL_3DEN)
+
+#define RV_FXCTL_3DEN_DISABLE \
+	 RV(FV_FXCTL_3DEN_DISABLE, FB_FXCTL_3DEN)
+
+#define RV_FXCTL_TEEN_ENABLE \
+	 RV(FV_FXCTL_TEEN_ENABLE, FB_FXCTL_TEEN)
+
+#define RV_FXCTL_TEEN_DISABLE \
+	 RV(FV_FXCTL_TEEN_DISABLE, FB_FXCTL_TEEN)
+
+#define RV_FXCTL_TNLFBYPASS_ENABLE \
+	 RV(FV_FXCTL_TNLFBYPASS_ENABLE, FB_FXCTL_TNLFBYPASS)
+
+#define RV_FXCTL_TNLFBYPASS_DISABLE \
+	 RV(FV_FXCTL_TNLFBYPASS_DISABLE, FB_FXCTL_TNLFBYPASS)
+
+#define RV_FXCTL_BEEN_ENABLE \
+	 RV(FV_FXCTL_BEEN_ENABLE, FB_FXCTL_BEEN)
+
+#define RV_FXCTL_BEEN_DISABLE \
+	 RV(FV_FXCTL_BEEN_DISABLE, FB_FXCTL_BEEN)
+
+#define RV_FXCTL_BNLFBYPASS_ENABLE \
+	 RV(FV_FXCTL_BNLFBYPASS_ENABLE, FB_FXCTL_BNLFBYPASS)
+
+#define RV_FXCTL_BNLFBYPASS_DISABLE \
+	 RV(FV_FXCTL_BNLFBYPASS_DISABLE, FB_FXCTL_BNLFBYPASS)
+
+
+/*******************************
+ *      R_DACCRWRL (0x3A)      *
+ *******************************/
+
+/* Field Offsets */
+#define FB_DACCRWRL_DACCRWDL                 0
+
+/* Field Masks */
+#define FM_DACCRWRL_DACCRWDL                 0XFF
+
+/* Register Masks */
+#define RM_DACCRWRL_DACCRWDL \
+	 RM(FM_DACCRWRL_DACCRWDL, FB_DACCRWRL_DACCRWDL)
+
+
+/*******************************
+ *      R_DACCRWRM (0x3B)      *
+ *******************************/
+
+/* Field Offsets */
+#define FB_DACCRWRM_DACCRWDM                 0
+
+/* Field Masks */
+#define FM_DACCRWRM_DACCRWDM                 0XFF
+
+/* Register Masks */
+#define RM_DACCRWRM_DACCRWDM \
+	 RM(FM_DACCRWRM_DACCRWDM, FB_DACCRWRM_DACCRWDM)
+
+
+/*******************************
+ *      R_DACCRWRH (0x3C)      *
+ *******************************/
+
+/* Field Offsets */
+#define FB_DACCRWRH_DACCRWDH                 0
+
+/* Field Masks */
+#define FM_DACCRWRH_DACCRWDH                 0XFF
+
+/* Register Masks */
+#define RM_DACCRWRH_DACCRWDH \
+	 RM(FM_DACCRWRH_DACCRWDH, FB_DACCRWRH_DACCRWDH)
+
+
+/*******************************
+ *      R_DACCRRDL (0x3D)      *
+ *******************************/
+
+/* Field Offsets */
+#define FB_DACCRRDL                          0
+
+/* Field Masks */
+#define FM_DACCRRDL                          0XFF
+
+/* Register Masks */
+#define RM_DACCRRDL                          RM(FM_DACCRRDL, FB_DACCRRDL)
+
+/*******************************
+ *      R_DACCRRDM (0x3E)      *
+ *******************************/
+
+/* Field Offsets */
+#define FB_DACCRRDM                          0
+
+/* Field Masks */
+#define FM_DACCRRDM                          0XFF
+
+/* Register Masks */
+#define RM_DACCRRDM                          RM(FM_DACCRRDM, FB_DACCRRDM)
+
+/*******************************
+ *      R_DACCRRDH (0x3F)      *
+ *******************************/
+
+/* Field Offsets */
+#define FB_DACCRRDH                          0
+
+/* Field Masks */
+#define FM_DACCRRDH                          0XFF
+
+/* Register Masks */
+#define RM_DACCRRDH                          RM(FM_DACCRRDH, FB_DACCRRDH)
+
+/********************************
+ *      R_DACCRADDR (0x40)      *
+ ********************************/
+
+/* Field Offsets */
+#define FB_DACCRADDR_DACCRADD                0
+
+/* Field Masks */
+#define FM_DACCRADDR_DACCRADD                0XFF
+
+/* Register Masks */
+#define RM_DACCRADDR_DACCRADD \
+	 RM(FM_DACCRADDR_DACCRADD, FB_DACCRADDR_DACCRADD)
+
+
+/******************************
+ *      R_DCOFSEL (0x41)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_DCOFSEL_DC_COEF_SEL               0
+
+/* Field Masks */
+#define FM_DCOFSEL_DC_COEF_SEL               0X7
+
+/* Field Values */
+#define FV_DCOFSEL_DC_COEF_SEL_2_N8          0x0
+#define FV_DCOFSEL_DC_COEF_SEL_2_N9          0x1
+#define FV_DCOFSEL_DC_COEF_SEL_2_N10         0x2
+#define FV_DCOFSEL_DC_COEF_SEL_2_N11         0x3
+#define FV_DCOFSEL_DC_COEF_SEL_2_N12         0x4
+#define FV_DCOFSEL_DC_COEF_SEL_2_N13         0x5
+#define FV_DCOFSEL_DC_COEF_SEL_2_N14         0x6
+#define FV_DCOFSEL_DC_COEF_SEL_2_N15         0x7
+
+/* Register Masks */
+#define RM_DCOFSEL_DC_COEF_SEL \
+	 RM(FM_DCOFSEL_DC_COEF_SEL, FB_DCOFSEL_DC_COEF_SEL)
+
+
+/* Register Values */
+#define RV_DCOFSEL_DC_COEF_SEL_2_N8 \
+	 RV(FV_DCOFSEL_DC_COEF_SEL_2_N8, FB_DCOFSEL_DC_COEF_SEL)
+
+#define RV_DCOFSEL_DC_COEF_SEL_2_N9 \
+	 RV(FV_DCOFSEL_DC_COEF_SEL_2_N9, FB_DCOFSEL_DC_COEF_SEL)
+
+#define RV_DCOFSEL_DC_COEF_SEL_2_N10 \
+	 RV(FV_DCOFSEL_DC_COEF_SEL_2_N10, FB_DCOFSEL_DC_COEF_SEL)
+
+#define RV_DCOFSEL_DC_COEF_SEL_2_N11 \
+	 RV(FV_DCOFSEL_DC_COEF_SEL_2_N11, FB_DCOFSEL_DC_COEF_SEL)
+
+#define RV_DCOFSEL_DC_COEF_SEL_2_N12 \
+	 RV(FV_DCOFSEL_DC_COEF_SEL_2_N12, FB_DCOFSEL_DC_COEF_SEL)
+
+#define RV_DCOFSEL_DC_COEF_SEL_2_N13 \
+	 RV(FV_DCOFSEL_DC_COEF_SEL_2_N13, FB_DCOFSEL_DC_COEF_SEL)
+
+#define RV_DCOFSEL_DC_COEF_SEL_2_N14 \
+	 RV(FV_DCOFSEL_DC_COEF_SEL_2_N14, FB_DCOFSEL_DC_COEF_SEL)
+
+#define RV_DCOFSEL_DC_COEF_SEL_2_N15 \
+	 RV(FV_DCOFSEL_DC_COEF_SEL_2_N15, FB_DCOFSEL_DC_COEF_SEL)
+
+
+/******************************
+ *      R_PLLCTL9 (0x4E)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_PLLCTL9_REFDIV_PLL1               0
+
+/* Field Masks */
+#define FM_PLLCTL9_REFDIV_PLL1               0XFF
+
+/* Register Masks */
+#define RM_PLLCTL9_REFDIV_PLL1 \
+	 RM(FM_PLLCTL9_REFDIV_PLL1, FB_PLLCTL9_REFDIV_PLL1)
+
+
+/******************************
+ *      R_PLLCTLA (0x4F)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_PLLCTLA_OUTDIV_PLL1               0
+
+/* Field Masks */
+#define FM_PLLCTLA_OUTDIV_PLL1               0XFF
+
+/* Register Masks */
+#define RM_PLLCTLA_OUTDIV_PLL1 \
+	 RM(FM_PLLCTLA_OUTDIV_PLL1, FB_PLLCTLA_OUTDIV_PLL1)
+
+
+/******************************
+ *      R_PLLCTLB (0x50)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_PLLCTLB_FBDIV_PLL1L               0
+
+/* Field Masks */
+#define FM_PLLCTLB_FBDIV_PLL1L               0XFF
+
+/* Register Masks */
+#define RM_PLLCTLB_FBDIV_PLL1L \
+	 RM(FM_PLLCTLB_FBDIV_PLL1L, FB_PLLCTLB_FBDIV_PLL1L)
+
+
+/******************************
+ *      R_PLLCTLC (0x51)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_PLLCTLC_FBDIV_PLL1H               0
+
+/* Field Masks */
+#define FM_PLLCTLC_FBDIV_PLL1H               0X7
+
+/* Register Masks */
+#define RM_PLLCTLC_FBDIV_PLL1H \
+	 RM(FM_PLLCTLC_FBDIV_PLL1H, FB_PLLCTLC_FBDIV_PLL1H)
+
+
+/******************************
+ *      R_PLLCTLD (0x52)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_PLLCTLD_RZ_PLL1                   3
+#define FB_PLLCTLD_CP_PLL1                   0
+
+/* Field Masks */
+#define FM_PLLCTLD_RZ_PLL1                   0X7
+#define FM_PLLCTLD_CP_PLL1                   0X7
+
+/* Register Masks */
+#define RM_PLLCTLD_RZ_PLL1 \
+	 RM(FM_PLLCTLD_RZ_PLL1, FB_PLLCTLD_RZ_PLL1)
+
+#define RM_PLLCTLD_CP_PLL1 \
+	 RM(FM_PLLCTLD_CP_PLL1, FB_PLLCTLD_CP_PLL1)
+
+
+/******************************
+ *      R_PLLCTLE (0x53)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_PLLCTLE_REFDIV_PLL2               0
+
+/* Field Masks */
+#define FM_PLLCTLE_REFDIV_PLL2               0XFF
+
+/* Register Masks */
+#define RM_PLLCTLE_REFDIV_PLL2 \
+	 RM(FM_PLLCTLE_REFDIV_PLL2, FB_PLLCTLE_REFDIV_PLL2)
+
+
+/******************************
+ *      R_PLLCTLF (0x54)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_PLLCTLF_OUTDIV_PLL2               0
+
+/* Field Masks */
+#define FM_PLLCTLF_OUTDIV_PLL2               0XFF
+
+/* Register Masks */
+#define RM_PLLCTLF_OUTDIV_PLL2 \
+	 RM(FM_PLLCTLF_OUTDIV_PLL2, FB_PLLCTLF_OUTDIV_PLL2)
+
+
+/*******************************
+ *      R_PLLCTL10 (0x55)      *
+ *******************************/
+
+/* Field Offsets */
+#define FB_PLLCTL10_FBDIV_PLL2L              0
+
+/* Field Masks */
+#define FM_PLLCTL10_FBDIV_PLL2L              0XFF
+
+/* Register Masks */
+#define RM_PLLCTL10_FBDIV_PLL2L \
+	 RM(FM_PLLCTL10_FBDIV_PLL2L, FB_PLLCTL10_FBDIV_PLL2L)
+
+
+/*******************************
+ *      R_PLLCTL11 (0x56)      *
+ *******************************/
+
+/* Field Offsets */
+#define FB_PLLCTL11_FBDIV_PLL2H              0
+
+/* Field Masks */
+#define FM_PLLCTL11_FBDIV_PLL2H              0X7
+
+/* Register Masks */
+#define RM_PLLCTL11_FBDIV_PLL2H \
+	 RM(FM_PLLCTL11_FBDIV_PLL2H, FB_PLLCTL11_FBDIV_PLL2H)
+
+
+/*******************************
+ *      R_PLLCTL12 (0x57)      *
+ *******************************/
+
+/* Field Offsets */
+#define FB_PLLCTL12_RZ_PLL2                  3
+#define FB_PLLCTL12_CP_PLL2                  0
+
+/* Field Masks */
+#define FM_PLLCTL12_RZ_PLL2                  0X7
+#define FM_PLLCTL12_CP_PLL2                  0X7
+
+/* Register Masks */
+#define RM_PLLCTL12_RZ_PLL2 \
+	 RM(FM_PLLCTL12_RZ_PLL2, FB_PLLCTL12_RZ_PLL2)
+
+#define RM_PLLCTL12_CP_PLL2 \
+	 RM(FM_PLLCTL12_CP_PLL2, FB_PLLCTL12_CP_PLL2)
+
+
+/*******************************
+ *      R_PLLCTL1B (0x60)      *
+ *******************************/
+
+/* Field Offsets */
+#define FB_PLLCTL1B_VCOI_PLL2                4
+#define FB_PLLCTL1B_VCOI_PLL1                2
+
+/* Field Masks */
+#define FM_PLLCTL1B_VCOI_PLL2                0X3
+#define FM_PLLCTL1B_VCOI_PLL1                0X3
+
+/* Register Masks */
+#define RM_PLLCTL1B_VCOI_PLL2 \
+	 RM(FM_PLLCTL1B_VCOI_PLL2, FB_PLLCTL1B_VCOI_PLL2)
+
+#define RM_PLLCTL1B_VCOI_PLL1 \
+	 RM(FM_PLLCTL1B_VCOI_PLL1, FB_PLLCTL1B_VCOI_PLL1)
+
+
+/*******************************
+ *      R_PLLCTL1C (0x61)      *
+ *******************************/
+
+/* Field Offsets */
+#define FB_PLLCTL1C_PDB_PLL2                 2
+#define FB_PLLCTL1C_PDB_PLL1                 1
+
+/* Field Masks */
+#define FM_PLLCTL1C_PDB_PLL2                 0X1
+#define FM_PLLCTL1C_PDB_PLL1                 0X1
+
+/* Field Values */
+#define FV_PLLCTL1C_PDB_PLL2_ENABLE          0x1
+#define FV_PLLCTL1C_PDB_PLL2_DISABLE         0x0
+#define FV_PLLCTL1C_PDB_PLL1_ENABLE          0x1
+#define FV_PLLCTL1C_PDB_PLL1_DISABLE         0x0
+
+/* Register Masks */
+#define RM_PLLCTL1C_PDB_PLL2 \
+	 RM(FM_PLLCTL1C_PDB_PLL2, FB_PLLCTL1C_PDB_PLL2)
+
+#define RM_PLLCTL1C_PDB_PLL1 \
+	 RM(FM_PLLCTL1C_PDB_PLL1, FB_PLLCTL1C_PDB_PLL1)
+
+
+/* Register Values */
+#define RV_PLLCTL1C_PDB_PLL2_ENABLE \
+	 RV(FV_PLLCTL1C_PDB_PLL2_ENABLE, FB_PLLCTL1C_PDB_PLL2)
+
+#define RV_PLLCTL1C_PDB_PLL2_DISABLE \
+	 RV(FV_PLLCTL1C_PDB_PLL2_DISABLE, FB_PLLCTL1C_PDB_PLL2)
+
+#define RV_PLLCTL1C_PDB_PLL1_ENABLE \
+	 RV(FV_PLLCTL1C_PDB_PLL1_ENABLE, FB_PLLCTL1C_PDB_PLL1)
+
+#define RV_PLLCTL1C_PDB_PLL1_DISABLE \
+	 RV(FV_PLLCTL1C_PDB_PLL1_DISABLE, FB_PLLCTL1C_PDB_PLL1)
+
+
+/*******************************
+ *      R_TIMEBASE (0x77)      *
+ *******************************/
+
+/* Field Offsets */
+#define FB_TIMEBASE_DIVIDER                  0
+
+/* Field Masks */
+#define FM_TIMEBASE_DIVIDER                  0XFF
+
+/* Register Masks */
+#define RM_TIMEBASE_DIVIDER \
+	 RM(FM_TIMEBASE_DIVIDER, FB_TIMEBASE_DIVIDER)
+
+
+/*****************************
+ *      R_DEVIDL (0x7D)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_DEVIDL_DIDL                       0
+
+/* Field Masks */
+#define FM_DEVIDL_DIDL                       0XFF
+
+/* Register Masks */
+#define RM_DEVIDL_DIDL                       RM(FM_DEVIDL_DIDL, FB_DEVIDL_DIDL)
+
+/*****************************
+ *      R_DEVIDH (0x7E)      *
+ *****************************/
+
+/* Field Offsets */
+#define FB_DEVIDH_DIDH                       0
+
+/* Field Masks */
+#define FM_DEVIDH_DIDH                       0XFF
+
+/* Register Masks */
+#define RM_DEVIDH_DIDH                       RM(FM_DEVIDH_DIDH, FB_DEVIDH_DIDH)
+
+/****************************
+ *      R_RESET (0x80)      *
+ ****************************/
+
+/* Field Offsets */
+#define FB_RESET                             0
+
+/* Field Masks */
+#define FM_RESET                             0XFF
+
+/* Field Values */
+#define FV_RESET_ENABLE                      0x85
+
+/* Register Masks */
+#define RM_RESET                             RM(FM_RESET, FB_RESET)
+
+/* Register Values */
+#define RV_RESET_ENABLE                      RV(FV_RESET_ENABLE, FB_RESET)
+
+/********************************
+ *      R_DACCRSTAT (0x8A)      *
+ ********************************/
+
+/* Field Offsets */
+#define FB_DACCRSTAT_DACCR_BUSY              7
+
+/* Field Masks */
+#define FM_DACCRSTAT_DACCR_BUSY              0X1
+
+/* Register Masks */
+#define RM_DACCRSTAT_DACCR_BUSY \
+	 RM(FM_DACCRSTAT_DACCR_BUSY, FB_DACCRSTAT_DACCR_BUSY)
+
+
+/******************************
+ *      R_PLLCTL0 (0x8E)      *
+ ******************************/
+
+/* Field Offsets */
+#define FB_PLLCTL0_PLL2_LOCK                 1
+#define FB_PLLCTL0_PLL1_LOCK                 0
+
+/* Field Masks */
+#define FM_PLLCTL0_PLL2_LOCK                 0X1
+#define FM_PLLCTL0_PLL1_LOCK                 0X1
+
+/* Register Masks */
+#define RM_PLLCTL0_PLL2_LOCK \
+	 RM(FM_PLLCTL0_PLL2_LOCK, FB_PLLCTL0_PLL2_LOCK)
+
+#define RM_PLLCTL0_PLL1_LOCK \
+	 RM(FM_PLLCTL0_PLL1_LOCK, FB_PLLCTL0_PLL1_LOCK)
+
+
+/********************************
+ *      R_PLLREFSEL (0x8F)      *
+ ********************************/
+
+/* Field Offsets */
+#define FB_PLLREFSEL_PLL2_REF_SEL            4
+#define FB_PLLREFSEL_PLL1_REF_SEL            0
+
+/* Field Masks */
+#define FM_PLLREFSEL_PLL2_REF_SEL            0X7
+#define FM_PLLREFSEL_PLL1_REF_SEL            0X7
+
+/* Field Values */
+#define FV_PLLREFSEL_PLL2_REF_SEL_XTAL_MCLK1 0x0
+#define FV_PLLREFSEL_PLL2_REF_SEL_MCLK2      0x1
+#define FV_PLLREFSEL_PLL1_REF_SEL_XTAL_MCLK1 0x0
+#define FV_PLLREFSEL_PLL1_REF_SEL_MCLK2      0x1
+
+/* Register Masks */
+#define RM_PLLREFSEL_PLL2_REF_SEL \
+	 RM(FM_PLLREFSEL_PLL2_REF_SEL, FB_PLLREFSEL_PLL2_REF_SEL)
+
+#define RM_PLLREFSEL_PLL1_REF_SEL \
+	 RM(FM_PLLREFSEL_PLL1_REF_SEL, FB_PLLREFSEL_PLL1_REF_SEL)
+
+
+/* Register Values */
+#define RV_PLLREFSEL_PLL2_REF_SEL_XTAL_MCLK1 \
+	 RV(FV_PLLREFSEL_PLL2_REF_SEL_XTAL_MCLK1, FB_PLLREFSEL_PLL2_REF_SEL)
+
+#define RV_PLLREFSEL_PLL2_REF_SEL_MCLK2 \
+	 RV(FV_PLLREFSEL_PLL2_REF_SEL_MCLK2, FB_PLLREFSEL_PLL2_REF_SEL)
+
+#define RV_PLLREFSEL_PLL1_REF_SEL_XTAL_MCLK1 \
+	 RV(FV_PLLREFSEL_PLL1_REF_SEL_XTAL_MCLK1, FB_PLLREFSEL_PLL1_REF_SEL)
+
+#define RV_PLLREFSEL_PLL1_REF_SEL_MCLK2 \
+	 RV(FV_PLLREFSEL_PLL1_REF_SEL_MCLK2, FB_PLLREFSEL_PLL1_REF_SEL)
+
+
+/*******************************
+ *      R_DACMBCEN (0xC7)      *
+ *******************************/
+
+/* Field Offsets */
+#define FB_DACMBCEN_MBCEN3                   2
+#define FB_DACMBCEN_MBCEN2                   1
+#define FB_DACMBCEN_MBCEN1                   0
+
+/* Field Masks */
+#define FM_DACMBCEN_MBCEN3                   0X1
+#define FM_DACMBCEN_MBCEN2                   0X1
+#define FM_DACMBCEN_MBCEN1                   0X1
+
+/* Register Masks */
+#define RM_DACMBCEN_MBCEN3 \
+	 RM(FM_DACMBCEN_MBCEN3, FB_DACMBCEN_MBCEN3)
+
+#define RM_DACMBCEN_MBCEN2 \
+	 RM(FM_DACMBCEN_MBCEN2, FB_DACMBCEN_MBCEN2)
+
+#define RM_DACMBCEN_MBCEN1 \
+	 RM(FM_DACMBCEN_MBCEN1, FB_DACMBCEN_MBCEN1)
+
+
+/********************************
+ *      R_DACMBCCTL (0xC8)      *
+ ********************************/
+
+/* Field Offsets */
+#define FB_DACMBCCTL_LVLMODE3                5
+#define FB_DACMBCCTL_WINSEL3                 4
+#define FB_DACMBCCTL_LVLMODE2                3
+#define FB_DACMBCCTL_WINSEL2                 2
+#define FB_DACMBCCTL_LVLMODE1                1
+#define FB_DACMBCCTL_WINSEL1                 0
+
+/* Field Masks */
+#define FM_DACMBCCTL_LVLMODE3                0X1
+#define FM_DACMBCCTL_WINSEL3                 0X1
+#define FM_DACMBCCTL_LVLMODE2                0X1
+#define FM_DACMBCCTL_WINSEL2                 0X1
+#define FM_DACMBCCTL_LVLMODE1                0X1
+#define FM_DACMBCCTL_WINSEL1                 0X1
+
+/* Register Masks */
+#define RM_DACMBCCTL_LVLMODE3 \
+	 RM(FM_DACMBCCTL_LVLMODE3, FB_DACMBCCTL_LVLMODE3)
+
+#define RM_DACMBCCTL_WINSEL3 \
+	 RM(FM_DACMBCCTL_WINSEL3, FB_DACMBCCTL_WINSEL3)
+
+#define RM_DACMBCCTL_LVLMODE2 \
+	 RM(FM_DACMBCCTL_LVLMODE2, FB_DACMBCCTL_LVLMODE2)
+
+#define RM_DACMBCCTL_WINSEL2 \
+	 RM(FM_DACMBCCTL_WINSEL2, FB_DACMBCCTL_WINSEL2)
+
+#define RM_DACMBCCTL_LVLMODE1 \
+	 RM(FM_DACMBCCTL_LVLMODE1, FB_DACMBCCTL_LVLMODE1)
+
+#define RM_DACMBCCTL_WINSEL1 \
+	 RM(FM_DACMBCCTL_WINSEL1, FB_DACMBCCTL_WINSEL1)
+
+
+/*********************************
+ *      R_DACMBCMUG1 (0xC9)      *
+ *********************************/
+
+/* Field Offsets */
+#define FB_DACMBCMUG1_PHASE                  5
+#define FB_DACMBCMUG1_MUGAIN                 0
+
+/* Field Masks */
+#define FM_DACMBCMUG1_PHASE                  0X1
+#define FM_DACMBCMUG1_MUGAIN                 0X1F
+
+/* Register Masks */
+#define RM_DACMBCMUG1_PHASE \
+	 RM(FM_DACMBCMUG1_PHASE, FB_DACMBCMUG1_PHASE)
+
+#define RM_DACMBCMUG1_MUGAIN \
+	 RM(FM_DACMBCMUG1_MUGAIN, FB_DACMBCMUG1_MUGAIN)
+
+
+/*********************************
+ *      R_DACMBCTHR1 (0xCA)      *
+ *********************************/
+
+/* Field Offsets */
+#define FB_DACMBCTHR1_THRESH                 0
+
+/* Field Masks */
+#define FM_DACMBCTHR1_THRESH                 0XFF
+
+/* Register Masks */
+#define RM_DACMBCTHR1_THRESH \
+	 RM(FM_DACMBCTHR1_THRESH, FB_DACMBCTHR1_THRESH)
+
+
+/*********************************
+ *      R_DACMBCRAT1 (0xCB)      *
+ *********************************/
+
+/* Field Offsets */
+#define FB_DACMBCRAT1_RATIO                  0
+
+/* Field Masks */
+#define FM_DACMBCRAT1_RATIO                  0X1F
+
+/* Register Masks */
+#define RM_DACMBCRAT1_RATIO \
+	 RM(FM_DACMBCRAT1_RATIO, FB_DACMBCRAT1_RATIO)
+
+
+/**********************************
+ *      R_DACMBCATK1L (0xCC)      *
+ **********************************/
+
+/* Field Offsets */
+#define FB_DACMBCATK1L_TCATKL                0
+
+/* Field Masks */
+#define FM_DACMBCATK1L_TCATKL                0XFF
+
+/* Register Masks */
+#define RM_DACMBCATK1L_TCATKL \
+	 RM(FM_DACMBCATK1L_TCATKL, FB_DACMBCATK1L_TCATKL)
+
+
+/**********************************
+ *      R_DACMBCATK1H (0xCD)      *
+ **********************************/
+
+/* Field Offsets */
+#define FB_DACMBCATK1H_TCATKH                0
+
+/* Field Masks */
+#define FM_DACMBCATK1H_TCATKH                0XFF
+
+/* Register Masks */
+#define RM_DACMBCATK1H_TCATKH \
+	 RM(FM_DACMBCATK1H_TCATKH, FB_DACMBCATK1H_TCATKH)
+
+
+/**********************************
+ *      R_DACMBCREL1L (0xCE)      *
+ **********************************/
+
+/* Field Offsets */
+#define FB_DACMBCREL1L_TCRELL                0
+
+/* Field Masks */
+#define FM_DACMBCREL1L_TCRELL                0XFF
+
+/* Register Masks */
+#define RM_DACMBCREL1L_TCRELL \
+	 RM(FM_DACMBCREL1L_TCRELL, FB_DACMBCREL1L_TCRELL)
+
+
+/**********************************
+ *      R_DACMBCREL1H (0xCF)      *
+ **********************************/
+
+/* Field Offsets */
+#define FB_DACMBCREL1H_TCRELH                0
+
+/* Field Masks */
+#define FM_DACMBCREL1H_TCRELH                0XFF
+
+/* Register Masks */
+#define RM_DACMBCREL1H_TCRELH \
+	 RM(FM_DACMBCREL1H_TCRELH, FB_DACMBCREL1H_TCRELH)
+
+
+/*********************************
+ *      R_DACMBCMUG2 (0xD0)      *
+ *********************************/
+
+/* Field Offsets */
+#define FB_DACMBCMUG2_PHASE                  5
+#define FB_DACMBCMUG2_MUGAIN                 0
+
+/* Field Masks */
+#define FM_DACMBCMUG2_PHASE                  0X1
+#define FM_DACMBCMUG2_MUGAIN                 0X1F
+
+/* Register Masks */
+#define RM_DACMBCMUG2_PHASE \
+	 RM(FM_DACMBCMUG2_PHASE, FB_DACMBCMUG2_PHASE)
+
+#define RM_DACMBCMUG2_MUGAIN \
+	 RM(FM_DACMBCMUG2_MUGAIN, FB_DACMBCMUG2_MUGAIN)
+
+
+/*********************************
+ *      R_DACMBCTHR2 (0xD1)      *
+ *********************************/
+
+/* Field Offsets */
+#define FB_DACMBCTHR2_THRESH                 0
+
+/* Field Masks */
+#define FM_DACMBCTHR2_THRESH                 0XFF
+
+/* Register Masks */
+#define RM_DACMBCTHR2_THRESH \
+	 RM(FM_DACMBCTHR2_THRESH, FB_DACMBCTHR2_THRESH)
+
+
+/*********************************
+ *      R_DACMBCRAT2 (0xD2)      *
+ *********************************/
+
+/* Field Offsets */
+#define FB_DACMBCRAT2_RATIO                  0
+
+/* Field Masks */
+#define FM_DACMBCRAT2_RATIO                  0X1F
+
+/* Register Masks */
+#define RM_DACMBCRAT2_RATIO \
+	 RM(FM_DACMBCRAT2_RATIO, FB_DACMBCRAT2_RATIO)
+
+
+/**********************************
+ *      R_DACMBCATK2L (0xD3)      *
+ **********************************/
+
+/* Field Offsets */
+#define FB_DACMBCATK2L_TCATKL                0
+
+/* Field Masks */
+#define FM_DACMBCATK2L_TCATKL                0XFF
+
+/* Register Masks */
+#define RM_DACMBCATK2L_TCATKL \
+	 RM(FM_DACMBCATK2L_TCATKL, FB_DACMBCATK2L_TCATKL)
+
+
+/**********************************
+ *      R_DACMBCATK2H (0xD4)      *
+ **********************************/
+
+/* Field Offsets */
+#define FB_DACMBCATK2H_TCATKH                0
+
+/* Field Masks */
+#define FM_DACMBCATK2H_TCATKH                0XFF
+
+/* Register Masks */
+#define RM_DACMBCATK2H_TCATKH \
+	 RM(FM_DACMBCATK2H_TCATKH, FB_DACMBCATK2H_TCATKH)
+
+
+/**********************************
+ *      R_DACMBCREL2L (0xD5)      *
+ **********************************/
+
+/* Field Offsets */
+#define FB_DACMBCREL2L_TCRELL                0
+
+/* Field Masks */
+#define FM_DACMBCREL2L_TCRELL                0XFF
+
+/* Register Masks */
+#define RM_DACMBCREL2L_TCRELL \
+	 RM(FM_DACMBCREL2L_TCRELL, FB_DACMBCREL2L_TCRELL)
+
+
+/**********************************
+ *      R_DACMBCREL2H (0xD6)      *
+ **********************************/
+
+/* Field Offsets */
+#define FB_DACMBCREL2H_TCRELH                0
+
+/* Field Masks */
+#define FM_DACMBCREL2H_TCRELH                0XFF
+
+/* Register Masks */
+#define RM_DACMBCREL2H_TCRELH \
+	 RM(FM_DACMBCREL2H_TCRELH, FB_DACMBCREL2H_TCRELH)
+
+
+/*********************************
+ *      R_DACMBCMUG3 (0xD7)      *
+ *********************************/
+
+/* Field Offsets */
+#define FB_DACMBCMUG3_PHASE                  5
+#define FB_DACMBCMUG3_MUGAIN                 0
+
+/* Field Masks */
+#define FM_DACMBCMUG3_PHASE                  0X1
+#define FM_DACMBCMUG3_MUGAIN                 0X1F
+
+/* Register Masks */
+#define RM_DACMBCMUG3_PHASE \
+	 RM(FM_DACMBCMUG3_PHASE, FB_DACMBCMUG3_PHASE)
+
+#define RM_DACMBCMUG3_MUGAIN \
+	 RM(FM_DACMBCMUG3_MUGAIN, FB_DACMBCMUG3_MUGAIN)
+
+
+/*********************************
+ *      R_DACMBCTHR3 (0xD8)      *
+ *********************************/
+
+/* Field Offsets */
+#define FB_DACMBCTHR3_THRESH                 0
+
+/* Field Masks */
+#define FM_DACMBCTHR3_THRESH                 0XFF
+
+/* Register Masks */
+#define RM_DACMBCTHR3_THRESH \
+	 RM(FM_DACMBCTHR3_THRESH, FB_DACMBCTHR3_THRESH)
+
+
+/*********************************
+ *      R_DACMBCRAT3 (0xD9)      *
+ *********************************/
+
+/* Field Offsets */
+#define FB_DACMBCRAT3_RATIO                  0
+
+/* Field Masks */
+#define FM_DACMBCRAT3_RATIO                  0X1F
+
+/* Register Masks */
+#define RM_DACMBCRAT3_RATIO \
+	 RM(FM_DACMBCRAT3_RATIO, FB_DACMBCRAT3_RATIO)
+
+
+/**********************************
+ *      R_DACMBCATK3L (0xDA)      *
+ **********************************/
+
+/* Field Offsets */
+#define FB_DACMBCATK3L_TCATKL                0
+
+/* Field Masks */
+#define FM_DACMBCATK3L_TCATKL                0XFF
+
+/* Register Masks */
+#define RM_DACMBCATK3L_TCATKL \
+	 RM(FM_DACMBCATK3L_TCATKL, FB_DACMBCATK3L_TCATKL)
+
+
+/**********************************
+ *      R_DACMBCATK3H (0xDB)      *
+ **********************************/
+
+/* Field Offsets */
+#define FB_DACMBCATK3H_TCATKH                0
+
+/* Field Masks */
+#define FM_DACMBCATK3H_TCATKH                0XFF
+
+/* Register Masks */
+#define RM_DACMBCATK3H_TCATKH \
+	 RM(FM_DACMBCATK3H_TCATKH, FB_DACMBCATK3H_TCATKH)
+
+
+/**********************************
+ *      R_DACMBCREL3L (0xDC)      *
+ **********************************/
+
+/* Field Offsets */
+#define FB_DACMBCREL3L_TCRELL                0
+
+/* Field Masks */
+#define FM_DACMBCREL3L_TCRELL                0XFF
+
+/* Register Masks */
+#define RM_DACMBCREL3L_TCRELL \
+	 RM(FM_DACMBCREL3L_TCRELL, FB_DACMBCREL3L_TCRELL)
+
+
+/**********************************
+ *      R_DACMBCREL3H (0xDD)      *
+ **********************************/
+
+/* Field Offsets */
+#define FB_DACMBCREL3H_TCRELH                0
+
+/* Field Masks */
+#define FM_DACMBCREL3H_TCRELH                0XFF
+
+/* Register Masks */
+#define RM_DACMBCREL3H_TCRELH \
+	 RM(FM_DACMBCREL3H_TCRELH, FB_DACMBCREL3H_TCRELH)
+
+
+#endif /* __WOOKIE_H__ */
diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c
new file mode 100644
index 0000000..ff85a0b
--- /dev/null
+++ b/sound/soc/codecs/tscs454.c
@@ -0,0 +1,3497 @@
+// SPDX-License-Identifier: GPL-2.0
+// tscs454.c -- TSCS454 ALSA SoC Audio driver
+// Copyright 2018 Tempo Semiconductor, Inc.
+// Author: Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+
+#include <sound/tlv.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "tscs454.h"
+
+static const unsigned int PLL_48K_RATE = (48000 * 256);
+static const unsigned int PLL_44_1K_RATE = (44100 * 256);
+
+#define COEFF_SIZE 3
+#define BIQUAD_COEFF_COUNT 5
+#define BIQUAD_SIZE (COEFF_SIZE * BIQUAD_COEFF_COUNT)
+
+#define COEFF_RAM_MAX_ADDR 0xcd
+#define COEFF_RAM_COEFF_COUNT (COEFF_RAM_MAX_ADDR + 1)
+#define COEFF_RAM_SIZE (COEFF_SIZE * COEFF_RAM_COEFF_COUNT)
+
+enum {
+	TSCS454_DAI1_ID,
+	TSCS454_DAI2_ID,
+	TSCS454_DAI3_ID,
+	TSCS454_DAI_COUNT,
+};
+
+struct pll {
+	int id;
+	unsigned int users;
+	struct mutex lock;
+};
+
+static inline void pll_init(struct pll *pll, int id)
+{
+	pll->id = id;
+	mutex_init(&pll->lock);
+}
+
+struct internal_rate {
+	struct pll *pll;
+};
+
+struct aif {
+	unsigned int id;
+	bool master;
+	struct pll *pll;
+};
+
+static inline void aif_init(struct aif *aif, unsigned int id)
+{
+	aif->id = id;
+}
+
+struct coeff_ram {
+	u8 cache[COEFF_RAM_SIZE];
+	bool synced;
+	struct mutex lock;
+};
+
+static inline void init_coeff_ram_cache(u8 *cache)
+{
+	static const u8 norm_addrs[] = { 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x19,
+		0x1f, 0x20, 0x25, 0x2a, 0x2f, 0x34, 0x39, 0x3f, 0x40, 0x45,
+		0x4a, 0x4f, 0x54, 0x59, 0x5f, 0x60, 0x65, 0x6a, 0x6f, 0x74,
+		0x79, 0x7f, 0x80, 0x85, 0x8c, 0x91, 0x96, 0x97, 0x9c, 0xa3,
+		0xa8, 0xad, 0xaf, 0xb0, 0xb5, 0xba, 0xbf, 0xc4, 0xc9};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(norm_addrs); i++)
+		cache[((norm_addrs[i] + 1) * COEFF_SIZE) - 1] = 0x40;
+}
+
+static inline void coeff_ram_init(struct coeff_ram *ram)
+{
+	init_coeff_ram_cache(ram->cache);
+	mutex_init(&ram->lock);
+}
+
+struct aifs_status {
+	u8 streams;
+};
+
+static inline void set_aif_status_active(struct aifs_status *status,
+		int aif_id, bool playback)
+{
+	u8 mask = 0x01 << (aif_id * 2 + !playback);
+
+	status->streams |= mask;
+}
+
+static inline void set_aif_status_inactive(struct aifs_status *status,
+		int aif_id, bool playback)
+{
+	u8 mask = ~(0x01 << (aif_id * 2 + !playback));
+
+	status->streams &= mask;
+}
+
+static bool aifs_active(struct aifs_status *status)
+{
+	return status->streams;
+}
+
+static bool aif_active(struct aifs_status *status, int aif_id)
+{
+	return (0x03 << aif_id * 2) & status->streams;
+}
+
+struct tscs454 {
+	struct regmap *regmap;
+	struct aif aifs[TSCS454_DAI_COUNT];
+
+	struct aifs_status aifs_status;
+	struct mutex aifs_status_lock;
+
+	struct pll pll1;
+	struct pll pll2;
+	struct internal_rate internal_rate;
+
+	struct coeff_ram dac_ram;
+	struct coeff_ram spk_ram;
+	struct coeff_ram sub_ram;
+
+	struct clk *sysclk;
+	int sysclk_src_id;
+	unsigned int bclk_freq;
+};
+
+struct coeff_ram_ctl {
+	unsigned int addr;
+	struct soc_bytes_ext bytes_ext;
+};
+
+static const struct reg_sequence tscs454_patch[] = {
+	/* Assign ASRC out of the box so DAI 1 just works */
+	{ R_AUDIOMUX1, FV_ASRCIMUX_I2S1 | FV_I2S2MUX_I2S2 },
+	{ R_AUDIOMUX2, FV_ASRCOMUX_I2S1 | FV_DACMUX_I2S1 | FV_I2S3MUX_I2S3 },
+	{ R_AUDIOMUX3, FV_CLSSDMUX_I2S1 | FV_SUBMUX_I2S1_LR },
+	{ R_TDMCTL0, FV_TDMMD_256 },
+	{ VIRT_ADDR(0x0A, 0x13), 1 << 3 },
+};
+
+static bool tscs454_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case R_PLLSTAT:
+
+	case R_SPKCRRDL:
+	case R_SPKCRRDM:
+	case R_SPKCRRDH:
+	case R_SPKCRS:
+
+	case R_DACCRRDL:
+	case R_DACCRRDM:
+	case R_DACCRRDH:
+	case R_DACCRS:
+
+	case R_SUBCRRDL:
+	case R_SUBCRRDM:
+	case R_SUBCRRDH:
+	case R_SUBCRS:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool tscs454_writable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case R_SPKCRRDL:
+	case R_SPKCRRDM:
+	case R_SPKCRRDH:
+
+	case R_DACCRRDL:
+	case R_DACCRRDM:
+	case R_DACCRRDH:
+
+	case R_SUBCRRDL:
+	case R_SUBCRRDM:
+	case R_SUBCRRDH:
+		return false;
+	default:
+		return true;
+	};
+}
+
+static bool tscs454_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case R_SPKCRWDL:
+	case R_SPKCRWDM:
+	case R_SPKCRWDH:
+
+	case R_DACCRWDL:
+	case R_DACCRWDM:
+	case R_DACCRWDH:
+
+	case R_SUBCRWDL:
+	case R_SUBCRWDM:
+	case R_SUBCRWDH:
+		return false;
+	default:
+		return true;
+	};
+}
+
+static bool tscs454_precious(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case R_SPKCRWDL:
+	case R_SPKCRWDM:
+	case R_SPKCRWDH:
+	case R_SPKCRRDL:
+	case R_SPKCRRDM:
+	case R_SPKCRRDH:
+
+	case R_DACCRWDL:
+	case R_DACCRWDM:
+	case R_DACCRWDH:
+	case R_DACCRRDL:
+	case R_DACCRRDM:
+	case R_DACCRRDH:
+
+	case R_SUBCRWDL:
+	case R_SUBCRWDM:
+	case R_SUBCRWDH:
+	case R_SUBCRRDL:
+	case R_SUBCRRDM:
+	case R_SUBCRRDH:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_range_cfg tscs454_regmap_range_cfg = {
+	.name = "Pages",
+	.range_min = VIRT_BASE,
+	.range_max = VIRT_ADDR(0xFE, 0x02),
+	.selector_reg = R_PAGESEL,
+	.selector_mask = 0xff,
+	.selector_shift = 0,
+	.window_start = 0,
+	.window_len = 0x100,
+};
+
+static struct regmap_config const tscs454_regmap_cfg = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.writeable_reg = tscs454_writable,
+	.readable_reg = tscs454_readable,
+	.volatile_reg = tscs454_volatile,
+	.precious_reg = tscs454_precious,
+	.ranges = &tscs454_regmap_range_cfg,
+	.num_ranges = 1,
+	.max_register = VIRT_ADDR(0xFE, 0x02),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static inline int tscs454_data_init(struct tscs454 *tscs454,
+		struct i2c_client *i2c)
+{
+	int i;
+	int ret;
+
+	tscs454->regmap = devm_regmap_init_i2c(i2c, &tscs454_regmap_cfg);
+	if (IS_ERR(tscs454->regmap)) {
+		ret = PTR_ERR(tscs454->regmap);
+		return ret;
+	}
+
+	for (i = 0; i < TSCS454_DAI_COUNT; i++)
+		aif_init(&tscs454->aifs[i], i);
+
+	mutex_init(&tscs454->aifs_status_lock);
+	pll_init(&tscs454->pll1, 1);
+	pll_init(&tscs454->pll2, 2);
+
+	coeff_ram_init(&tscs454->dac_ram);
+	coeff_ram_init(&tscs454->spk_ram);
+	coeff_ram_init(&tscs454->sub_ram);
+
+	return 0;
+}
+
+struct reg_setting {
+	unsigned int addr;
+	unsigned int val;
+};
+
+static int coeff_ram_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	struct coeff_ram_ctl *ctl =
+		(struct coeff_ram_ctl *)kcontrol->private_value;
+	struct soc_bytes_ext *params = &ctl->bytes_ext;
+	u8 *coeff_ram;
+	struct mutex *coeff_ram_lock;
+
+	if (strstr(kcontrol->id.name, "DAC")) {
+		coeff_ram = tscs454->dac_ram.cache;
+		coeff_ram_lock = &tscs454->dac_ram.lock;
+	} else if (strstr(kcontrol->id.name, "Speaker")) {
+		coeff_ram = tscs454->spk_ram.cache;
+		coeff_ram_lock = &tscs454->spk_ram.lock;
+	} else if (strstr(kcontrol->id.name, "Sub")) {
+		coeff_ram = tscs454->sub_ram.cache;
+		coeff_ram_lock = &tscs454->sub_ram.lock;
+	} else {
+		return -EINVAL;
+	}
+
+	mutex_lock(coeff_ram_lock);
+
+	memcpy(ucontrol->value.bytes.data,
+		&coeff_ram[ctl->addr * COEFF_SIZE], params->max);
+
+	mutex_unlock(coeff_ram_lock);
+
+	return 0;
+}
+
+#define DACCRSTAT_MAX_TRYS 10
+static int write_coeff_ram(struct snd_soc_component *component, u8 *coeff_ram,
+		unsigned int r_stat, unsigned int r_addr, unsigned int r_wr,
+		unsigned int coeff_addr, unsigned int coeff_cnt)
+{
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+	int cnt;
+	int trys;
+	int ret;
+
+	for (cnt = 0; cnt < coeff_cnt; cnt++, coeff_addr++) {
+
+		for (trys = 0; trys < DACCRSTAT_MAX_TRYS; trys++) {
+			ret = snd_soc_component_read(component, r_stat, &val);
+			if (ret < 0) {
+				dev_err(component->dev,
+					"Failed to read stat (%d)\n", ret);
+				return ret;
+			}
+			if (!val)
+				break;
+		}
+
+		if (trys == DACCRSTAT_MAX_TRYS) {
+			ret = -EIO;
+			dev_err(component->dev,
+				"Coefficient write error (%d)\n", ret);
+			return ret;
+		}
+
+		ret = regmap_write(tscs454->regmap, r_addr, coeff_addr);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to write dac ram address (%d)\n", ret);
+			return ret;
+		}
+
+		ret = regmap_bulk_write(tscs454->regmap, r_wr,
+			&coeff_ram[coeff_addr * COEFF_SIZE],
+			COEFF_SIZE);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to write dac ram (%d)\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int coeff_ram_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	struct coeff_ram_ctl *ctl =
+		(struct coeff_ram_ctl *)kcontrol->private_value;
+	struct soc_bytes_ext *params = &ctl->bytes_ext;
+	unsigned int coeff_cnt = params->max / COEFF_SIZE;
+	u8 *coeff_ram;
+	struct mutex *coeff_ram_lock;
+	bool *coeff_ram_synced;
+	unsigned int r_stat;
+	unsigned int r_addr;
+	unsigned int r_wr;
+	unsigned int val;
+	int ret;
+
+	if (strstr(kcontrol->id.name, "DAC")) {
+		coeff_ram = tscs454->dac_ram.cache;
+		coeff_ram_lock = &tscs454->dac_ram.lock;
+		coeff_ram_synced = &tscs454->dac_ram.synced;
+		r_stat = R_DACCRS;
+		r_addr = R_DACCRADD;
+		r_wr = R_DACCRWDL;
+	} else if (strstr(kcontrol->id.name, "Speaker")) {
+		coeff_ram = tscs454->spk_ram.cache;
+		coeff_ram_lock = &tscs454->spk_ram.lock;
+		coeff_ram_synced = &tscs454->spk_ram.synced;
+		r_stat = R_SPKCRS;
+		r_addr = R_SPKCRADD;
+		r_wr = R_SPKCRWDL;
+	} else if (strstr(kcontrol->id.name, "Sub")) {
+		coeff_ram = tscs454->sub_ram.cache;
+		coeff_ram_lock = &tscs454->sub_ram.lock;
+		coeff_ram_synced = &tscs454->sub_ram.synced;
+		r_stat = R_SUBCRS;
+		r_addr = R_SUBCRADD;
+		r_wr = R_SUBCRWDL;
+	} else {
+		return -EINVAL;
+	}
+
+	mutex_lock(coeff_ram_lock);
+
+	*coeff_ram_synced = false;
+
+	memcpy(&coeff_ram[ctl->addr * COEFF_SIZE],
+		ucontrol->value.bytes.data, params->max);
+
+	mutex_lock(&tscs454->pll1.lock);
+	mutex_lock(&tscs454->pll2.lock);
+
+	ret = snd_soc_component_read(component, R_PLLSTAT, &val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to read PLL status (%d)\n",
+				ret);
+		goto exit;
+	}
+	if (val) { /* PLLs locked */
+		ret = write_coeff_ram(component, coeff_ram,
+			r_stat, r_addr, r_wr,
+			ctl->addr, coeff_cnt);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to flush coeff ram cache (%d)\n", ret);
+			goto exit;
+		}
+		*coeff_ram_synced = true;
+	}
+
+	ret = 0;
+exit:
+	mutex_unlock(&tscs454->pll2.lock);
+	mutex_unlock(&tscs454->pll1.lock);
+	mutex_unlock(coeff_ram_lock);
+
+	return ret;
+}
+
+static inline int coeff_ram_sync(struct snd_soc_component *component,
+		struct tscs454 *tscs454)
+{
+	int ret;
+
+	mutex_lock(&tscs454->dac_ram.lock);
+	if (!tscs454->dac_ram.synced) {
+		ret = write_coeff_ram(component, tscs454->dac_ram.cache,
+				R_DACCRS, R_DACCRADD, R_DACCRWDL,
+				0x00, COEFF_RAM_COEFF_COUNT);
+		if (ret < 0) {
+			mutex_unlock(&tscs454->dac_ram.lock);
+			return ret;
+		}
+	}
+	mutex_unlock(&tscs454->dac_ram.lock);
+
+	mutex_lock(&tscs454->spk_ram.lock);
+	if (!tscs454->spk_ram.synced) {
+		ret = write_coeff_ram(component, tscs454->spk_ram.cache,
+				R_SPKCRS, R_SPKCRADD, R_SPKCRWDL,
+				0x00, COEFF_RAM_COEFF_COUNT);
+		if (ret < 0) {
+			mutex_unlock(&tscs454->spk_ram.lock);
+			return ret;
+		}
+	}
+	mutex_unlock(&tscs454->spk_ram.lock);
+
+	mutex_lock(&tscs454->sub_ram.lock);
+	if (!tscs454->sub_ram.synced) {
+		ret = write_coeff_ram(component, tscs454->sub_ram.cache,
+				R_SUBCRS, R_SUBCRADD, R_SUBCRWDL,
+				0x00, COEFF_RAM_COEFF_COUNT);
+		if (ret < 0) {
+			mutex_unlock(&tscs454->sub_ram.lock);
+			return ret;
+		}
+	}
+	mutex_unlock(&tscs454->sub_ram.lock);
+
+	return 0;
+}
+
+#define PLL_REG_SETTINGS_COUNT 11
+struct pll_ctl {
+	int freq_in;
+	struct reg_setting settings[PLL_REG_SETTINGS_COUNT];
+};
+
+#define PLL_CTL(f, t, c1, r1, o1, f1l, f1h, c2, r2, o2, f2l, f2h)	\
+	{								\
+		.freq_in = f,						\
+		.settings = {						\
+			{R_PLL1CTL,	c1},				\
+			{R_PLL1RDIV,	r1},				\
+			{R_PLL1ODIV,	o1},				\
+			{R_PLL1FDIVL,	f1l},				\
+			{R_PLL1FDIVH,	f1h},				\
+			{R_PLL2CTL,	c2},				\
+			{R_PLL2RDIV,	r2},				\
+			{R_PLL2ODIV,	o2},				\
+			{R_PLL2FDIVL,	f2l},				\
+			{R_PLL2FDIVH,	f2h},				\
+			{R_TIMEBASE,	t},				\
+		},							\
+	}
+
+static const struct pll_ctl pll_ctls[] = {
+	PLL_CTL(1411200, 0x05,
+		0xB9, 0x07, 0x02, 0xC3, 0x04,
+		0x5A, 0x02, 0x03, 0xE0, 0x01),
+	PLL_CTL(1536000, 0x05,
+		0x5A, 0x02, 0x03, 0xE0, 0x01,
+		0x5A, 0x02, 0x03, 0xB9, 0x01),
+	PLL_CTL(2822400, 0x0A,
+		0x63, 0x07, 0x04, 0xC3, 0x04,
+		0x62, 0x07, 0x03, 0x48, 0x03),
+	PLL_CTL(3072000, 0x0B,
+		0x62, 0x07, 0x03, 0x48, 0x03,
+		0x5A, 0x04, 0x03, 0xB9, 0x01),
+	PLL_CTL(5644800, 0x15,
+		0x63, 0x0E, 0x04, 0xC3, 0x04,
+		0x5A, 0x08, 0x03, 0xE0, 0x01),
+	PLL_CTL(6144000, 0x17,
+		0x5A, 0x08, 0x03, 0xE0, 0x01,
+		0x5A, 0x08, 0x03, 0xB9, 0x01),
+	PLL_CTL(12000000, 0x2E,
+		0x5B, 0x19, 0x03, 0x00, 0x03,
+		0x6A, 0x19, 0x05, 0x98, 0x04),
+	PLL_CTL(19200000, 0x4A,
+		0x53, 0x14, 0x03, 0x80, 0x01,
+		0x5A, 0x19, 0x03, 0xB9, 0x01),
+	PLL_CTL(22000000, 0x55,
+		0x6A, 0x37, 0x05, 0x00, 0x06,
+		0x62, 0x26, 0x03, 0x49, 0x02),
+	PLL_CTL(22579200, 0x57,
+		0x62, 0x31, 0x03, 0x20, 0x03,
+		0x53, 0x1D, 0x03, 0xB3, 0x01),
+	PLL_CTL(24000000, 0x5D,
+		0x53, 0x19, 0x03, 0x80, 0x01,
+		0x5B, 0x19, 0x05, 0x4C, 0x02),
+	PLL_CTL(24576000, 0x5F,
+		0x53, 0x1D, 0x03, 0xB3, 0x01,
+		0x62, 0x40, 0x03, 0x72, 0x03),
+	PLL_CTL(27000000, 0x68,
+		0x62, 0x4B, 0x03, 0x00, 0x04,
+		0x6A, 0x7D, 0x03, 0x20, 0x06),
+	PLL_CTL(36000000, 0x8C,
+		0x5B, 0x4B, 0x03, 0x00, 0x03,
+		0x6A, 0x7D, 0x03, 0x98, 0x04),
+	PLL_CTL(11289600, 0x2B,
+		0x6A, 0x31, 0x03, 0x40, 0x06,
+		0x5A, 0x12, 0x03, 0x1C, 0x02),
+	PLL_CTL(26000000, 0x65,
+		0x63, 0x41, 0x05, 0x00, 0x06,
+		0x5A, 0x26, 0x03, 0xEF, 0x01),
+	PLL_CTL(12288000, 0x2F,
+		0x5A, 0x12, 0x03, 0x1C, 0x02,
+		0x62, 0x20, 0x03, 0x72, 0x03),
+	PLL_CTL(40000000, 0x9B,
+		0xA2, 0x7D, 0x03, 0x80, 0x04,
+		0x63, 0x7D, 0x05, 0xE4, 0x06),
+	PLL_CTL(512000, 0x01,
+		0x62, 0x01, 0x03, 0xD0, 0x02,
+		0x5B, 0x01, 0x04, 0x72, 0x03),
+	PLL_CTL(705600, 0x02,
+		0x62, 0x02, 0x03, 0x15, 0x04,
+		0x62, 0x01, 0x04, 0x80, 0x02),
+	PLL_CTL(1024000, 0x03,
+		0x62, 0x02, 0x03, 0xD0, 0x02,
+		0x5B, 0x02, 0x04, 0x72, 0x03),
+	PLL_CTL(2048000, 0x07,
+		0x62, 0x04, 0x03, 0xD0, 0x02,
+		0x5B, 0x04, 0x04, 0x72, 0x03),
+	PLL_CTL(2400000, 0x08,
+		0x62, 0x05, 0x03, 0x00, 0x03,
+		0x63, 0x05, 0x05, 0x98, 0x04),
+};
+
+static inline const struct pll_ctl *get_pll_ctl(unsigned long freq_in)
+{
+	int i;
+	struct pll_ctl const *pll_ctl = NULL;
+
+	for (i = 0; i < ARRAY_SIZE(pll_ctls); ++i)
+		if (pll_ctls[i].freq_in == freq_in) {
+			pll_ctl = &pll_ctls[i];
+			break;
+		}
+
+	return pll_ctl;
+}
+
+enum {
+	PLL_INPUT_XTAL = 0,
+	PLL_INPUT_MCLK1,
+	PLL_INPUT_MCLK2,
+	PLL_INPUT_BCLK,
+};
+
+static int set_sysclk(struct snd_soc_component *component)
+{
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	struct pll_ctl const *pll_ctl;
+	unsigned long freq;
+	int i;
+	int ret;
+
+	if (tscs454->sysclk_src_id < PLL_INPUT_BCLK)
+		freq = clk_get_rate(tscs454->sysclk);
+	else
+		freq = tscs454->bclk_freq;
+	pll_ctl = get_pll_ctl(freq);
+	if (!pll_ctl) {
+		ret = -EINVAL;
+		dev_err(component->dev,
+				"Invalid PLL input %lu (%d)\n", freq, ret);
+		return ret;
+	}
+
+	for (i = 0; i < PLL_REG_SETTINGS_COUNT; ++i) {
+		ret = snd_soc_component_write(component,
+				pll_ctl->settings[i].addr,
+				pll_ctl->settings[i].val);
+		if (ret < 0) {
+			dev_err(component->dev,
+					"Failed to set pll setting (%d)\n",
+					ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static inline void reserve_pll(struct pll *pll)
+{
+	mutex_lock(&pll->lock);
+	pll->users++;
+	mutex_unlock(&pll->lock);
+}
+
+static inline void free_pll(struct pll *pll)
+{
+	mutex_lock(&pll->lock);
+	pll->users--;
+	mutex_unlock(&pll->lock);
+}
+
+static int pll_connected(struct snd_soc_dapm_widget *source,
+		struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(source->dapm);
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	int users;
+
+	if (strstr(source->name, "PLL 1")) {
+		mutex_lock(&tscs454->pll1.lock);
+		users = tscs454->pll1.users;
+		mutex_unlock(&tscs454->pll1.lock);
+		dev_dbg(component->dev, "%s(): PLL 1 users = %d\n", __func__,
+				users);
+	} else {
+		mutex_lock(&tscs454->pll2.lock);
+		users = tscs454->pll2.users;
+		mutex_unlock(&tscs454->pll2.lock);
+		dev_dbg(component->dev, "%s(): PLL 2 users = %d\n", __func__,
+				users);
+	}
+
+	return users;
+}
+
+/*
+ * PLL must be enabled after power up and must be disabled before power down
+ * for proper clock switching.
+ */
+static int pll_power_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	bool enable;
+	bool pll1;
+	unsigned int msk;
+	unsigned int val;
+	int ret;
+
+	if (strstr(w->name, "PLL 1"))
+		pll1 = true;
+	else
+		pll1 = false;
+
+	msk = pll1 ? FM_PLLCTL_PLL1CLKEN : FM_PLLCTL_PLL2CLKEN;
+
+	if (event == SND_SOC_DAPM_POST_PMU)
+		enable = true;
+	else
+		enable = false;
+
+	if (enable)
+		val = pll1 ? FV_PLL1CLKEN_ENABLE : FV_PLL2CLKEN_ENABLE;
+	else
+		val = pll1 ? FV_PLL1CLKEN_DISABLE : FV_PLL2CLKEN_DISABLE;
+
+	ret = snd_soc_component_update_bits(component, R_PLLCTL, msk, val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to %s PLL %d  (%d)\n",
+				enable ? "enable" : "disable",
+				pll1 ? 1 : 2,
+				ret);
+		return ret;
+	}
+
+	if (enable) {
+		msleep(20); // Wait for lock
+		ret = coeff_ram_sync(component, tscs454);
+		if (ret < 0) {
+			dev_err(component->dev,
+					"Failed to sync coeff ram (%d)\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static inline int aif_set_master(struct snd_soc_component *component,
+		unsigned int aif_id, bool master)
+{
+	unsigned int reg;
+	unsigned int mask;
+	unsigned int val;
+	int ret;
+
+	switch (aif_id) {
+	case TSCS454_DAI1_ID:
+		reg = R_I2SP1CTL;
+		break;
+	case TSCS454_DAI2_ID:
+		reg = R_I2SP2CTL;
+		break;
+	case TSCS454_DAI3_ID:
+		reg = R_I2SP3CTL;
+		break;
+	default:
+		ret = -ENODEV;
+		dev_err(component->dev, "Unknown DAI %d (%d)\n", aif_id, ret);
+		return ret;
+	}
+	mask = FM_I2SPCTL_PORTMS;
+	val = master ? FV_PORTMS_MASTER : FV_PORTMS_SLAVE;
+
+	ret = snd_soc_component_update_bits(component, reg, mask, val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set DAI %d to %s (%d)\n",
+			aif_id, master ? "master" : "slave", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline
+int aif_prepare(struct snd_soc_component *component, struct aif *aif)
+{
+	int ret;
+
+	ret = aif_set_master(component, aif->id, aif->master);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static inline int aif_free(struct snd_soc_component *component,
+		struct aif *aif, bool playback)
+{
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+
+	mutex_lock(&tscs454->aifs_status_lock);
+
+	dev_dbg(component->dev, "%s(): aif %d\n", __func__, aif->id);
+
+	set_aif_status_inactive(&tscs454->aifs_status, aif->id, playback);
+
+	dev_dbg(component->dev, "Set aif %d inactive. Streams status is 0x%x\n",
+		aif->id, tscs454->aifs_status.streams);
+
+	if (!aif_active(&tscs454->aifs_status, aif->id)) {
+		/* Do config in slave mode */
+		aif_set_master(component, aif->id, false);
+		dev_dbg(component->dev, "Freeing pll %d from aif %d\n",
+				aif->pll->id, aif->id);
+		free_pll(aif->pll);
+	}
+
+	if (!aifs_active(&tscs454->aifs_status)) {
+		dev_dbg(component->dev, "Freeing pll %d from ir\n",
+				tscs454->internal_rate.pll->id);
+		free_pll(tscs454->internal_rate.pll);
+	}
+
+	mutex_unlock(&tscs454->aifs_status_lock);
+
+	return 0;
+}
+
+/* R_PLLCTL PG 0 ADDR 0x15 */
+static char const * const bclk_sel_txt[] = {
+		"BCLK 1", "BCLK 2", "BCLK 3"};
+
+static struct soc_enum const bclk_sel_enum =
+		SOC_ENUM_SINGLE(R_PLLCTL, FB_PLLCTL_BCLKSEL,
+				ARRAY_SIZE(bclk_sel_txt), bclk_sel_txt);
+
+/* R_ISRC PG 0 ADDR 0x16 */
+static char const * const isrc_br_txt[] = {
+		"44.1kHz", "48kHz"};
+
+static struct soc_enum const isrc_br_enum =
+		SOC_ENUM_SINGLE(R_ISRC, FB_ISRC_IBR,
+				ARRAY_SIZE(isrc_br_txt), isrc_br_txt);
+
+static char const * const isrc_bm_txt[] = {
+		"0.25x", "0.5x", "1.0x", "2.0x"};
+
+static struct soc_enum const isrc_bm_enum =
+		SOC_ENUM_SINGLE(R_ISRC, FB_ISRC_IBM,
+				ARRAY_SIZE(isrc_bm_txt), isrc_bm_txt);
+
+/* R_SCLKCTL PG 0 ADDR 0x18 */
+static char const * const modular_rate_txt[] = {
+	"Reserved", "Half", "Full", "Auto",};
+
+static struct soc_enum const adc_modular_rate_enum =
+	SOC_ENUM_SINGLE(R_SCLKCTL, FB_SCLKCTL_ASDM,
+			ARRAY_SIZE(modular_rate_txt), modular_rate_txt);
+
+static struct soc_enum const dac_modular_rate_enum =
+	SOC_ENUM_SINGLE(R_SCLKCTL, FB_SCLKCTL_DSDM,
+			ARRAY_SIZE(modular_rate_txt), modular_rate_txt);
+
+/* R_I2SIDCTL PG 0 ADDR 0x38 */
+static char const * const data_ctrl_txt[] = {
+	"L/R", "L/L", "R/R", "R/L"};
+
+static struct soc_enum const data_in_ctrl_enums[] = {
+	SOC_ENUM_SINGLE(R_I2SIDCTL, FB_I2SIDCTL_I2SI1DCTL,
+			ARRAY_SIZE(data_ctrl_txt), data_ctrl_txt),
+	SOC_ENUM_SINGLE(R_I2SIDCTL, FB_I2SIDCTL_I2SI2DCTL,
+			ARRAY_SIZE(data_ctrl_txt), data_ctrl_txt),
+	SOC_ENUM_SINGLE(R_I2SIDCTL, FB_I2SIDCTL_I2SI3DCTL,
+			ARRAY_SIZE(data_ctrl_txt), data_ctrl_txt),
+};
+
+/* R_I2SODCTL PG 0 ADDR 0x39 */
+static struct soc_enum const data_out_ctrl_enums[] = {
+	SOC_ENUM_SINGLE(R_I2SODCTL, FB_I2SODCTL_I2SO1DCTL,
+			ARRAY_SIZE(data_ctrl_txt), data_ctrl_txt),
+	SOC_ENUM_SINGLE(R_I2SODCTL, FB_I2SODCTL_I2SO2DCTL,
+			ARRAY_SIZE(data_ctrl_txt), data_ctrl_txt),
+	SOC_ENUM_SINGLE(R_I2SODCTL, FB_I2SODCTL_I2SO3DCTL,
+			ARRAY_SIZE(data_ctrl_txt), data_ctrl_txt),
+};
+
+/* R_AUDIOMUX1 PG 0 ADDR 0x3A */
+static char const * const asrc_mux_txt[] = {
+		"None", "DAI 1", "DAI 2", "DAI 3"};
+
+static struct soc_enum const asrc_in_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX1, FB_AUDIOMUX1_ASRCIMUX,
+				ARRAY_SIZE(asrc_mux_txt), asrc_mux_txt);
+
+static char const * const dai_mux_txt[] = {
+		"CH 0_1", "CH 2_3", "CH 4_5", "ADC/DMic 1",
+		"DMic 2", "ClassD", "DAC", "Sub"};
+
+static struct soc_enum const dai2_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX1, FB_AUDIOMUX1_I2S2MUX,
+				ARRAY_SIZE(dai_mux_txt), dai_mux_txt);
+
+static struct snd_kcontrol_new const dai2_mux_dapm_enum =
+		SOC_DAPM_ENUM("DAI 2 Mux",  dai2_mux_enum);
+
+static struct soc_enum const dai1_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX1, FB_AUDIOMUX1_I2S1MUX,
+				ARRAY_SIZE(dai_mux_txt), dai_mux_txt);
+
+static struct snd_kcontrol_new const dai1_mux_dapm_enum =
+		SOC_DAPM_ENUM("DAI 1 Mux", dai1_mux_enum);
+
+/* R_AUDIOMUX2 PG 0 ADDR 0x3B */
+static struct soc_enum const asrc_out_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX2, FB_AUDIOMUX2_ASRCOMUX,
+				ARRAY_SIZE(asrc_mux_txt), asrc_mux_txt);
+
+static struct soc_enum const dac_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX2, FB_AUDIOMUX2_DACMUX,
+				ARRAY_SIZE(dai_mux_txt), dai_mux_txt);
+
+static struct snd_kcontrol_new const dac_mux_dapm_enum =
+		SOC_DAPM_ENUM("DAC Mux", dac_mux_enum);
+
+static struct soc_enum const dai3_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX2, FB_AUDIOMUX2_I2S3MUX,
+				ARRAY_SIZE(dai_mux_txt), dai_mux_txt);
+
+static struct snd_kcontrol_new const dai3_mux_dapm_enum =
+		SOC_DAPM_ENUM("DAI 3 Mux", dai3_mux_enum);
+
+/* R_AUDIOMUX3 PG 0 ADDR 0x3C */
+static char const * const sub_mux_txt[] = {
+		"CH 0", "CH 1", "CH 0 + 1",
+		"CH 2", "CH 3", "CH 2 + 3",
+		"CH 4", "CH 5", "CH 4 + 5",
+		"ADC/DMic 1 Left", "ADC/DMic 1 Right",
+		"ADC/DMic 1 Left Plus Right",
+		"DMic 2 Left", "DMic 2 Right", "DMic 2 Left Plus Right",
+		"ClassD Left", "ClassD Right", "ClassD Left Plus Right"};
+
+static struct soc_enum const sub_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX3, FB_AUDIOMUX3_SUBMUX,
+				ARRAY_SIZE(sub_mux_txt), sub_mux_txt);
+
+static struct snd_kcontrol_new const sub_mux_dapm_enum =
+		SOC_DAPM_ENUM("Sub Mux", sub_mux_enum);
+
+static struct soc_enum const classd_mux_enum =
+		SOC_ENUM_SINGLE(R_AUDIOMUX3, FB_AUDIOMUX3_CLSSDMUX,
+				ARRAY_SIZE(dai_mux_txt), dai_mux_txt);
+
+static struct snd_kcontrol_new const classd_mux_dapm_enum =
+		SOC_DAPM_ENUM("ClassD Mux", classd_mux_enum);
+
+/* R_HSDCTL1 PG 1 ADDR 0x01 */
+static char const * const jack_type_txt[] = {
+		"3 Terminal", "4 Terminal"};
+
+static struct soc_enum const hp_jack_type_enum =
+		SOC_ENUM_SINGLE(R_HSDCTL1, FB_HSDCTL1_HPJKTYPE,
+				ARRAY_SIZE(jack_type_txt), jack_type_txt);
+
+static char const * const hs_det_pol_txt[] = {
+		"Rising", "Falling"};
+
+static struct soc_enum const hs_det_pol_enum =
+		SOC_ENUM_SINGLE(R_HSDCTL1, FB_HSDCTL1_HSDETPOL,
+				ARRAY_SIZE(hs_det_pol_txt), hs_det_pol_txt);
+
+/* R_HSDCTL1 PG 1 ADDR 0x02 */
+static char const * const hs_mic_bias_force_txt[] = {
+		"Off", "Ring", "Sleeve"};
+
+static struct soc_enum const hs_mic_bias_force_enum =
+		SOC_ENUM_SINGLE(R_HSDCTL2, FB_HSDCTL2_FMICBIAS1,
+				ARRAY_SIZE(hs_mic_bias_force_txt),
+				hs_mic_bias_force_txt);
+
+static char const * const plug_type_txt[] = {
+		"OMTP", "CTIA", "Reserved", "Headphone"};
+
+static struct soc_enum const plug_type_force_enum =
+		SOC_ENUM_SINGLE(R_HSDCTL2, FB_HSDCTL2_FPLUGTYPE,
+		ARRAY_SIZE(plug_type_txt), plug_type_txt);
+
+
+/* R_CH0AIC PG 1 ADDR 0x06 */
+static char const * const in_bst_mux_txt[] = {
+		"Input 1", "Input 2", "Input 3", "D2S"};
+
+static struct soc_enum const in_bst_mux_ch0_enum =
+		SOC_ENUM_SINGLE(R_CH0AIC, FB_CH0AIC_INSELL,
+				ARRAY_SIZE(in_bst_mux_txt),
+				in_bst_mux_txt);
+static struct snd_kcontrol_new const in_bst_mux_ch0_dapm_enum =
+		SOC_DAPM_ENUM("Input Boost Channel 0 Enum",
+				in_bst_mux_ch0_enum);
+
+static DECLARE_TLV_DB_SCALE(in_bst_vol_tlv_arr, 0, 1000, 0);
+
+static char const * const adc_mux_txt[] = {
+		"Input 1 Boost Bypass", "Input 2 Boost Bypass",
+		"Input 3 Boost Bypass", "Input Boost"};
+
+static struct soc_enum const adc_mux_ch0_enum =
+		SOC_ENUM_SINGLE(R_CH0AIC, FB_CH0AIC_LADCIN,
+				ARRAY_SIZE(adc_mux_txt), adc_mux_txt);
+static struct snd_kcontrol_new const adc_mux_ch0_dapm_enum =
+		SOC_DAPM_ENUM("ADC Channel 0 Enum", adc_mux_ch0_enum);
+
+static char const * const in_proc_mux_txt[] = {
+		"ADC", "DMic"};
+
+static struct soc_enum const in_proc_ch0_enum =
+		SOC_ENUM_SINGLE(R_CH0AIC, FB_CH0AIC_IPCH0S,
+				ARRAY_SIZE(in_proc_mux_txt), in_proc_mux_txt);
+static struct snd_kcontrol_new const in_proc_mux_ch0_dapm_enum =
+		SOC_DAPM_ENUM("Input Processor Channel 0 Enum",
+				in_proc_ch0_enum);
+
+/* R_CH1AIC PG 1 ADDR 0x07 */
+static struct soc_enum const in_bst_mux_ch1_enum =
+		SOC_ENUM_SINGLE(R_CH1AIC, FB_CH1AIC_INSELR,
+				ARRAY_SIZE(in_bst_mux_txt),
+				in_bst_mux_txt);
+static struct snd_kcontrol_new const in_bst_mux_ch1_dapm_enum =
+		SOC_DAPM_ENUM("Input Boost Channel 1 Enum",
+				in_bst_mux_ch1_enum);
+
+static struct soc_enum const adc_mux_ch1_enum =
+		SOC_ENUM_SINGLE(R_CH1AIC, FB_CH1AIC_RADCIN,
+				ARRAY_SIZE(adc_mux_txt), adc_mux_txt);
+static struct snd_kcontrol_new const adc_mux_ch1_dapm_enum =
+		SOC_DAPM_ENUM("ADC Channel 1 Enum", adc_mux_ch1_enum);
+
+static struct soc_enum const in_proc_ch1_enum =
+		SOC_ENUM_SINGLE(R_CH1AIC, FB_CH1AIC_IPCH1S,
+				ARRAY_SIZE(in_proc_mux_txt), in_proc_mux_txt);
+static struct snd_kcontrol_new const in_proc_mux_ch1_dapm_enum =
+		SOC_DAPM_ENUM("Input Processor Channel 1 Enum",
+				in_proc_ch1_enum);
+
+/* R_ICTL0 PG 1 ADDR 0x0A */
+static char const * const pol_txt[] = {
+		"Normal", "Invert"};
+
+static struct soc_enum const in_pol_ch1_enum =
+		SOC_ENUM_SINGLE(R_ICTL0, FB_ICTL0_IN0POL,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+static struct soc_enum const in_pol_ch0_enum =
+		SOC_ENUM_SINGLE(R_ICTL0, FB_ICTL0_IN1POL,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+static char const * const in_proc_ch_sel_txt[] = {
+		"Normal", "Mono Mix to Channel 0",
+		"Mono Mix to Channel 1", "Add"};
+
+static struct soc_enum const in_proc_ch01_sel_enum =
+		SOC_ENUM_SINGLE(R_ICTL0, FB_ICTL0_INPCH10SEL,
+				ARRAY_SIZE(in_proc_ch_sel_txt),
+				in_proc_ch_sel_txt);
+
+/* R_ICTL1 PG 1 ADDR 0x0B */
+static struct soc_enum const in_pol_ch3_enum =
+		SOC_ENUM_SINGLE(R_ICTL1, FB_ICTL1_IN2POL,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+static struct soc_enum const in_pol_ch2_enum =
+		SOC_ENUM_SINGLE(R_ICTL1, FB_ICTL1_IN3POL,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+static struct soc_enum const in_proc_ch23_sel_enum =
+		SOC_ENUM_SINGLE(R_ICTL1, FB_ICTL1_INPCH32SEL,
+				ARRAY_SIZE(in_proc_ch_sel_txt),
+				in_proc_ch_sel_txt);
+
+/* R_MICBIAS PG 1 ADDR 0x0C */
+static char const * const mic_bias_txt[] = {
+		"2.5V", "2.1V", "1.8V", "Vdd"};
+
+static struct soc_enum const mic_bias_2_enum =
+		SOC_ENUM_SINGLE(R_MICBIAS, FB_MICBIAS_MICBOV2,
+				ARRAY_SIZE(mic_bias_txt), mic_bias_txt);
+
+static struct soc_enum const mic_bias_1_enum =
+		SOC_ENUM_SINGLE(R_MICBIAS, FB_MICBIAS_MICBOV1,
+				ARRAY_SIZE(mic_bias_txt), mic_bias_txt);
+
+/* R_PGACTL0 PG 1 ADDR 0x0D */
+/* R_PGACTL1 PG 1 ADDR 0x0E */
+/* R_PGACTL2 PG 1 ADDR 0x0F */
+/* R_PGACTL3 PG 1 ADDR 0x10 */
+static DECLARE_TLV_DB_SCALE(in_pga_vol_tlv_arr, -1725, 75, 0);
+
+/* R_ICH0VOL PG1 ADDR 0x12 */
+/* R_ICH1VOL PG1 ADDR 0x13 */
+/* R_ICH2VOL PG1 ADDR 0x14 */
+/* R_ICH3VOL PG1 ADDR 0x15 */
+static DECLARE_TLV_DB_MINMAX(in_vol_tlv_arr, -7125, 2400);
+
+/* R_ASRCILVOL PG1 ADDR 0x16 */
+/* R_ASRCIRVOL PG1 ADDR 0x17 */
+/* R_ASRCOLVOL PG1 ADDR 0x18 */
+/* R_ASRCORVOL PG1 ADDR 0x19 */
+static DECLARE_TLV_DB_MINMAX(asrc_vol_tlv_arr, -9562, 600);
+
+/* R_ALCCTL0 PG1 ADDR 0x1D */
+static char const * const alc_mode_txt[] = {
+		"ALC", "Limiter"};
+
+static struct soc_enum const alc_mode_enum =
+		SOC_ENUM_SINGLE(R_ALCCTL0, FB_ALCCTL0_ALCMODE,
+				ARRAY_SIZE(alc_mode_txt), alc_mode_txt);
+
+static char const * const alc_ref_text[] = {
+		"Channel 0", "Channel 1", "Channel 2", "Channel 3", "Peak"};
+
+static struct soc_enum const alc_ref_enum =
+		SOC_ENUM_SINGLE(R_ALCCTL0, FB_ALCCTL0_ALCREF,
+				ARRAY_SIZE(alc_ref_text), alc_ref_text);
+
+/* R_ALCCTL1 PG 1 ADDR 0x1E */
+static DECLARE_TLV_DB_SCALE(alc_max_gain_tlv_arr, -1200, 600, 0);
+static DECLARE_TLV_DB_SCALE(alc_target_tlv_arr, -2850, 150, 0);
+
+/* R_ALCCTL2 PG 1 ADDR 0x1F */
+static DECLARE_TLV_DB_SCALE(alc_min_gain_tlv_arr, -1725, 600, 0);
+
+/* R_NGATE PG 1 ADDR 0x21 */
+static DECLARE_TLV_DB_SCALE(ngth_tlv_arr, -7650, 150, 0);
+
+static char const * const ngate_type_txt[] = {
+		"PGA Constant", "ADC Mute"};
+
+static struct soc_enum const ngate_type_enum =
+		SOC_ENUM_SINGLE(R_NGATE, FB_NGATE_NGG,
+				ARRAY_SIZE(ngate_type_txt), ngate_type_txt);
+
+/* R_DMICCTL PG 1 ADDR 0x22 */
+static char const * const dmic_mono_sel_txt[] = {
+		"Stereo", "Mono"};
+
+static struct soc_enum const dmic_mono_sel_enum =
+		SOC_ENUM_SINGLE(R_DMICCTL, FB_DMICCTL_DMONO,
+			ARRAY_SIZE(dmic_mono_sel_txt), dmic_mono_sel_txt);
+
+/* R_DACCTL PG 2 ADDR 0x01 */
+static struct soc_enum const dac_pol_r_enum =
+		SOC_ENUM_SINGLE(R_DACCTL, FB_DACCTL_DACPOLR,
+			ARRAY_SIZE(pol_txt), pol_txt);
+
+static struct soc_enum const dac_pol_l_enum =
+		SOC_ENUM_SINGLE(R_DACCTL, FB_DACCTL_DACPOLL,
+			ARRAY_SIZE(pol_txt), pol_txt);
+
+static char const * const dac_dith_txt[] = {
+		"Half", "Full", "Disabled", "Static"};
+
+static struct soc_enum const dac_dith_enum =
+		SOC_ENUM_SINGLE(R_DACCTL, FB_DACCTL_DACDITH,
+			ARRAY_SIZE(dac_dith_txt), dac_dith_txt);
+
+/* R_SPKCTL PG 2 ADDR 0x02 */
+static struct soc_enum const spk_pol_r_enum =
+		SOC_ENUM_SINGLE(R_SPKCTL, FB_SPKCTL_SPKPOLR,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+static struct soc_enum const spk_pol_l_enum =
+		SOC_ENUM_SINGLE(R_SPKCTL, FB_SPKCTL_SPKPOLL,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_SUBCTL PG 2 ADDR 0x03 */
+static struct soc_enum const sub_pol_enum =
+		SOC_ENUM_SINGLE(R_SUBCTL, FB_SUBCTL_SUBPOL,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_MVOLL PG 2 ADDR 0x08 */
+/* R_MVOLR PG 2 ADDR 0x09 */
+static DECLARE_TLV_DB_MINMAX(mvol_tlv_arr, -9562, 0);
+
+/* R_HPVOLL PG 2 ADDR 0x0A */
+/* R_HPVOLR PG 2 ADDR 0x0B */
+static DECLARE_TLV_DB_SCALE(hp_vol_tlv_arr, -8850, 75, 0);
+
+/* R_SPKVOLL PG 2 ADDR 0x0C */
+/* R_SPKVOLR PG 2 ADDR 0x0D */
+static DECLARE_TLV_DB_SCALE(spk_vol_tlv_arr, -7725, 75, 0);
+
+/* R_SPKEQFILT PG 3 ADDR 0x01 */
+static char const * const eq_txt[] = {
+	"Pre Scale",
+	"Pre Scale + EQ Band 0",
+	"Pre Scale + EQ Band 0 - 1",
+	"Pre Scale + EQ Band 0 - 2",
+	"Pre Scale + EQ Band 0 - 3",
+	"Pre Scale + EQ Band 0 - 4",
+	"Pre Scale + EQ Band 0 - 5",
+};
+
+static struct soc_enum const spk_eq_enums[] = {
+	SOC_ENUM_SINGLE(R_SPKEQFILT, FB_SPKEQFILT_EQ2BE,
+		ARRAY_SIZE(eq_txt), eq_txt),
+	SOC_ENUM_SINGLE(R_SPKEQFILT, FB_SPKEQFILT_EQ1BE,
+		ARRAY_SIZE(eq_txt), eq_txt),
+};
+
+/* R_SPKMBCCTL PG 3 ADDR 0x0B */
+static char const * const lvl_mode_txt[] = {
+		"Average", "Peak"};
+
+static struct soc_enum const spk_mbc3_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCCTL, FB_SPKMBCCTL_LVLMODE3,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static char const * const win_sel_txt[] = {
+		"512", "64"};
+
+static struct soc_enum const spk_mbc3_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCCTL, FB_SPKMBCCTL_WINSEL3,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+static struct soc_enum const spk_mbc2_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCCTL, FB_SPKMBCCTL_LVLMODE2,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const spk_mbc2_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCCTL, FB_SPKMBCCTL_WINSEL2,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+static struct soc_enum const spk_mbc1_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCCTL, FB_SPKMBCCTL_LVLMODE1,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const spk_mbc1_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCCTL, FB_SPKMBCCTL_WINSEL1,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+/* R_SPKMBCMUG1 PG 3 ADDR 0x0C */
+static struct soc_enum const spk_mbc1_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCMUG1, FB_SPKMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+static DECLARE_TLV_DB_MINMAX(mbc_mug_tlv_arr, -4650, 0);
+
+/* R_SPKMBCTHR1 PG 3 ADDR 0x0D */
+static DECLARE_TLV_DB_MINMAX(thr_tlv_arr, -9562, 0);
+
+/* R_SPKMBCRAT1 PG 3 ADDR 0x0E */
+static char const * const comp_rat_txt[] = {
+		"Reserved", "1.5:1", "2:1", "3:1", "4:1", "5:1", "6:1",
+		"7:1", "8:1", "9:1", "10:1", "11:1", "12:1", "13:1", "14:1",
+		"15:1", "16:1", "17:1", "18:1", "19:1", "20:1"};
+
+static struct soc_enum const spk_mbc1_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCRAT1, FB_SPKMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SPKMBCMUG2 PG 3 ADDR 0x13 */
+static struct soc_enum const spk_mbc2_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCMUG2, FB_SPKMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_SPKMBCRAT2 PG 3 ADDR 0x15 */
+static struct soc_enum const spk_mbc2_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCRAT2, FB_SPKMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SPKMBCMUG3 PG 3 ADDR 0x1A */
+static struct soc_enum const spk_mbc3_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCMUG3, FB_SPKMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_SPKMBCRAT3 PG 3 ADDR 0x1C */
+static struct soc_enum const spk_mbc3_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SPKMBCRAT3, FB_SPKMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SPKCLECTL PG 3 ADDR 0x21 */
+static struct soc_enum const spk_cle_lvl_mode_enum =
+		SOC_ENUM_SINGLE(R_SPKCLECTL, FB_SPKCLECTL_LVLMODE,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const spk_cle_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SPKCLECTL, FB_SPKCLECTL_WINSEL,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+/* R_SPKCLEMUG PG 3 ADDR 0x22 */
+static DECLARE_TLV_DB_MINMAX(cle_mug_tlv_arr, 0, 4650);
+
+/* R_SPKCOMPRAT PG 3 ADDR 0x24 */
+static struct soc_enum const spk_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SPKCOMPRAT, FB_SPKCOMPRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SPKEXPTHR PG 3 ADDR 0x2F */
+static char const * const exp_rat_txt[] = {
+		"Reserved", "Reserved", "1:2", "1:3",
+		"1:4", "1:5", "1:6", "1:7"};
+
+static struct soc_enum const spk_exp_rat_enum =
+		SOC_ENUM_SINGLE(R_SPKEXPRAT, FB_SPKEXPRAT_RATIO,
+				ARRAY_SIZE(exp_rat_txt), exp_rat_txt);
+
+/* R_DACEQFILT PG 4 ADDR 0x01 */
+static struct soc_enum const dac_eq_enums[] = {
+	SOC_ENUM_SINGLE(R_DACEQFILT, FB_DACEQFILT_EQ2BE,
+		ARRAY_SIZE(eq_txt), eq_txt),
+	SOC_ENUM_SINGLE(R_DACEQFILT, FB_DACEQFILT_EQ1BE,
+		ARRAY_SIZE(eq_txt), eq_txt),
+};
+
+/* R_DACMBCCTL PG 4 ADDR 0x0B */
+static struct soc_enum const dac_mbc3_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE3,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const dac_mbc3_win_sel_enum =
+		SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL3,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+static struct soc_enum const dac_mbc2_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE2,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const dac_mbc2_win_sel_enum =
+		SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL2,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+static struct soc_enum const dac_mbc1_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE1,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const dac_mbc1_win_sel_enum =
+		SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL1,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+/* R_DACMBCMUG1 PG 4 ADDR 0x0C */
+static struct soc_enum const dac_mbc1_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_DACMBCMUG1, FB_DACMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_DACMBCRAT1 PG 4 ADDR 0x0E */
+static struct soc_enum const dac_mbc1_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_DACMBCRAT1, FB_DACMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_DACMBCMUG2 PG 4 ADDR 0x13 */
+static struct soc_enum const dac_mbc2_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_DACMBCMUG2, FB_DACMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_DACMBCRAT2 PG 4 ADDR 0x15 */
+static struct soc_enum const dac_mbc2_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_DACMBCRAT2, FB_DACMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_DACMBCMUG3 PG 4 ADDR 0x1A */
+static struct soc_enum const dac_mbc3_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_DACMBCMUG3, FB_DACMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_DACMBCRAT3 PG 4 ADDR 0x1C */
+static struct soc_enum const dac_mbc3_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_DACMBCRAT3, FB_DACMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_DACCLECTL PG 4 ADDR 0x21 */
+static struct soc_enum const dac_cle_lvl_mode_enum =
+		SOC_ENUM_SINGLE(R_DACCLECTL, FB_DACCLECTL_LVLMODE,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const dac_cle_win_sel_enum =
+		SOC_ENUM_SINGLE(R_DACCLECTL, FB_DACCLECTL_WINSEL,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+/* R_DACCOMPRAT PG 4 ADDR 0x24 */
+static struct soc_enum const dac_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_DACCOMPRAT, FB_DACCOMPRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_DACEXPRAT PG 4 ADDR 0x30 */
+static struct soc_enum const dac_exp_rat_enum =
+		SOC_ENUM_SINGLE(R_DACEXPRAT, FB_DACEXPRAT_RATIO,
+				ARRAY_SIZE(exp_rat_txt), exp_rat_txt);
+
+/* R_SUBEQFILT PG 5 ADDR 0x01 */
+static struct soc_enum const sub_eq_enums[] = {
+	SOC_ENUM_SINGLE(R_SUBEQFILT, FB_SUBEQFILT_EQ2BE,
+		ARRAY_SIZE(eq_txt), eq_txt),
+	SOC_ENUM_SINGLE(R_SUBEQFILT, FB_SUBEQFILT_EQ1BE,
+		ARRAY_SIZE(eq_txt), eq_txt),
+};
+
+/* R_SUBMBCCTL PG 5 ADDR 0x0B */
+static struct soc_enum const sub_mbc3_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCCTL, FB_SUBMBCCTL_LVLMODE3,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const sub_mbc3_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCCTL, FB_SUBMBCCTL_WINSEL3,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+static struct soc_enum const sub_mbc2_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCCTL, FB_SUBMBCCTL_LVLMODE2,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const sub_mbc2_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCCTL, FB_SUBMBCCTL_WINSEL2,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+static struct soc_enum const sub_mbc1_lvl_det_mode_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCCTL, FB_SUBMBCCTL_LVLMODE1,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+
+static struct soc_enum const sub_mbc1_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCCTL, FB_SUBMBCCTL_WINSEL1,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+/* R_SUBMBCMUG1 PG 5 ADDR 0x0C */
+static struct soc_enum const sub_mbc1_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCMUG1, FB_SUBMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_SUBMBCRAT1 PG 5 ADDR 0x0E */
+static struct soc_enum const sub_mbc1_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCRAT1, FB_SUBMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SUBMBCMUG2 PG 5 ADDR 0x13 */
+static struct soc_enum const sub_mbc2_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCMUG2, FB_SUBMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_SUBMBCRAT2 PG 5 ADDR 0x15 */
+static struct soc_enum const sub_mbc2_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCRAT2, FB_SUBMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SUBMBCMUG3 PG 5 ADDR 0x1A */
+static struct soc_enum const sub_mbc3_phase_pol_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCMUG3, FB_SUBMBCMUG_PHASE,
+				ARRAY_SIZE(pol_txt), pol_txt);
+
+/* R_SUBMBCRAT3 PG 5 ADDR 0x1C */
+static struct soc_enum const sub_mbc3_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SUBMBCRAT3, FB_SUBMBCRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SUBCLECTL PG 5 ADDR 0x21 */
+static struct soc_enum const sub_cle_lvl_mode_enum =
+		SOC_ENUM_SINGLE(R_SUBCLECTL, FB_SUBCLECTL_LVLMODE,
+				ARRAY_SIZE(lvl_mode_txt), lvl_mode_txt);
+static struct soc_enum const sub_cle_win_sel_enum =
+		SOC_ENUM_SINGLE(R_SUBCLECTL, FB_SUBCLECTL_WINSEL,
+				ARRAY_SIZE(win_sel_txt), win_sel_txt);
+
+/* R_SUBCOMPRAT PG 5 ADDR 0x24 */
+static struct soc_enum const sub_comp_rat_enum =
+		SOC_ENUM_SINGLE(R_SUBCOMPRAT, FB_SUBCOMPRAT_RATIO,
+				ARRAY_SIZE(comp_rat_txt), comp_rat_txt);
+
+/* R_SUBEXPRAT PG 5 ADDR 0x30 */
+static struct soc_enum const sub_exp_rat_enum =
+		SOC_ENUM_SINGLE(R_SUBEXPRAT, FB_SUBEXPRAT_RATIO,
+				ARRAY_SIZE(exp_rat_txt), exp_rat_txt);
+
+static int bytes_info_ext(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *ucontrol)
+{
+	struct coeff_ram_ctl *ctl =
+		(struct coeff_ram_ctl *)kcontrol->private_value;
+	struct soc_bytes_ext *params = &ctl->bytes_ext;
+
+	ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	ucontrol->count = params->max;
+
+	return 0;
+}
+
+/* CH 0_1 Input Mux */
+static char const * const ch_0_1_mux_txt[] = {"DAI 1", "TDM 0_1"};
+
+static struct soc_enum const ch_0_1_mux_enum =
+		SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+				ARRAY_SIZE(ch_0_1_mux_txt), ch_0_1_mux_txt);
+
+static struct snd_kcontrol_new const ch_0_1_mux_dapm_enum =
+		SOC_DAPM_ENUM("CH 0_1 Input Mux", ch_0_1_mux_enum);
+
+/* CH 2_3 Input Mux */
+static char const * const ch_2_3_mux_txt[] = {"DAI 2", "TDM 2_3"};
+
+static struct soc_enum const ch_2_3_mux_enum =
+		SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+				ARRAY_SIZE(ch_2_3_mux_txt), ch_2_3_mux_txt);
+
+static struct snd_kcontrol_new const ch_2_3_mux_dapm_enum =
+		SOC_DAPM_ENUM("CH 2_3 Input Mux", ch_2_3_mux_enum);
+
+/* CH 4_5 Input Mux */
+static char const * const ch_4_5_mux_txt[] = {"DAI 3", "TDM 4_5"};
+
+static struct soc_enum const ch_4_5_mux_enum =
+		SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+				ARRAY_SIZE(ch_4_5_mux_txt), ch_4_5_mux_txt);
+
+static struct snd_kcontrol_new const ch_4_5_mux_dapm_enum =
+		SOC_DAPM_ENUM("CH 4_5 Input Mux", ch_4_5_mux_enum);
+
+#define COEFF_RAM_CTL(xname, xcount, xaddr) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = bytes_info_ext, \
+	.get = coeff_ram_get, .put = coeff_ram_put, \
+	.private_value = (unsigned long)&(struct coeff_ram_ctl) { \
+		.addr = xaddr, \
+		.bytes_ext = {.max = xcount, }, \
+	} \
+}
+
+static struct snd_kcontrol_new const tscs454_snd_controls[] = {
+	/* R_PLLCTL PG 0 ADDR 0x15 */
+	SOC_ENUM("PLL BCLK Input", bclk_sel_enum),
+	/* R_ISRC PG 0 ADDR 0x16 */
+	SOC_ENUM("Internal Rate", isrc_br_enum),
+	SOC_ENUM("Internal Rate Multiple", isrc_bm_enum),
+	/* R_SCLKCTL PG 0 ADDR 0x18 */
+	SOC_ENUM("ADC Modular Rate", adc_modular_rate_enum),
+	SOC_ENUM("DAC Modular Rate", dac_modular_rate_enum),
+	/* R_ASRC PG 0 ADDR 0x28 */
+	SOC_SINGLE("ASRC Out High Bandwidth Switch",
+			R_ASRC, FB_ASRC_ASRCOBW, 1, 0),
+	SOC_SINGLE("ASRC In High Bandwidth Switch",
+			R_ASRC, FB_ASRC_ASRCIBW, 1, 0),
+	/* R_I2SIDCTL PG 0 ADDR 0x38 */
+	SOC_ENUM("I2S 1 Data In Control", data_in_ctrl_enums[0]),
+	SOC_ENUM("I2S 2 Data In Control", data_in_ctrl_enums[1]),
+	SOC_ENUM("I2S 3 Data In Control", data_in_ctrl_enums[2]),
+	/* R_I2SODCTL PG 0 ADDR 0x39 */
+	SOC_ENUM("I2S 1 Data Out Control", data_out_ctrl_enums[0]),
+	SOC_ENUM("I2S 2 Data Out Control", data_out_ctrl_enums[1]),
+	SOC_ENUM("I2S 3 Data Out Control", data_out_ctrl_enums[2]),
+	/* R_AUDIOMUX1 PG 0 ADDR 0x3A */
+	SOC_ENUM("ASRC In", asrc_in_mux_enum),
+	/* R_AUDIOMUX2 PG 0 ADDR 0x3B */
+	SOC_ENUM("ASRC Out", asrc_out_mux_enum),
+	/* R_HSDCTL1 PG 1 ADDR 0x01 */
+	SOC_ENUM("Headphone Jack Type", hp_jack_type_enum),
+	SOC_ENUM("Headset Detection Polarity", hs_det_pol_enum),
+	SOC_SINGLE("Headphone Detection Switch",
+			R_HSDCTL1, FB_HSDCTL1_HPID_EN, 1, 0),
+	SOC_SINGLE("Headset OMTP/CTIA Switch",
+			R_HSDCTL1, FB_HSDCTL1_GBLHS_EN, 1, 0),
+	/* R_HSDCTL1 PG 1 ADDR 0x02 */
+	SOC_ENUM("Headset Mic Bias Force", hs_mic_bias_force_enum),
+	SOC_SINGLE("Manual Mic Bias Switch",
+			R_HSDCTL2, FB_HSDCTL2_MB1MODE, 1, 0),
+	SOC_SINGLE("Ring/Sleeve Auto Switch",
+			R_HSDCTL2, FB_HSDCTL2_SWMODE, 1, 0),
+	SOC_ENUM("Manual Mode Plug Type", plug_type_force_enum),
+	/* R_CH0AIC PG 1 ADDR 0x06 */
+	SOC_SINGLE_TLV("Input Boost Channel 0 Volume", R_CH0AIC,
+			FB_CHAIC_MICBST, 0x3, 0, in_bst_vol_tlv_arr),
+	/* R_CH1AIC PG 1 ADDR 0x07 */
+	SOC_SINGLE_TLV("Input Boost Channel 1 Volume", R_CH1AIC,
+			FB_CHAIC_MICBST, 0x3, 0, in_bst_vol_tlv_arr),
+	/* R_CH2AIC PG 1 ADDR 0x08 */
+	SOC_SINGLE_TLV("Input Boost Channel 2 Volume", R_CH2AIC,
+			FB_CHAIC_MICBST, 0x3, 0, in_bst_vol_tlv_arr),
+	/* R_CH3AIC PG 1 ADDR 0x09 */
+	SOC_SINGLE_TLV("Input Boost Channel 3 Volume", R_CH3AIC,
+			FB_CHAIC_MICBST, 0x3, 0, in_bst_vol_tlv_arr),
+	/* R_ICTL0 PG 1 ADDR 0x0A */
+	SOC_ENUM("Input Channel 1 Polarity", in_pol_ch1_enum),
+	SOC_ENUM("Input Channel 0 Polarity", in_pol_ch0_enum),
+	SOC_ENUM("Input Processor Channel 0/1 Operation",
+			in_proc_ch01_sel_enum),
+	SOC_SINGLE("Input Channel 1 Mute Switch",
+			R_ICTL0, FB_ICTL0_IN1MUTE, 1, 0),
+	SOC_SINGLE("Input Channel 0 Mute Switch",
+			R_ICTL0, FB_ICTL0_IN0MUTE, 1, 0),
+	SOC_SINGLE("Input Channel 1 HPF Disable Switch",
+			R_ICTL0, FB_ICTL0_IN1HP, 1, 0),
+	SOC_SINGLE("Input Channel 0 HPF Disable Switch",
+			R_ICTL0, FB_ICTL0_IN0HP, 1, 0),
+	/* R_ICTL1 PG 1 ADDR 0x0B */
+	SOC_ENUM("Input Channel 3 Polarity", in_pol_ch3_enum),
+	SOC_ENUM("Input Channel 2 Polarity", in_pol_ch2_enum),
+	SOC_ENUM("Input Processor Channel 2/3 Operation",
+			in_proc_ch23_sel_enum),
+	SOC_SINGLE("Input Channel 3 Mute Switch",
+			R_ICTL1, FB_ICTL1_IN3MUTE, 1, 0),
+	SOC_SINGLE("Input Channel 2 Mute Switch",
+			R_ICTL1, FB_ICTL1_IN2MUTE, 1, 0),
+	SOC_SINGLE("Input Channel 3 HPF Disable Switch",
+			R_ICTL1, FB_ICTL1_IN3HP, 1, 0),
+	SOC_SINGLE("Input Channel 2 HPF Disable Switch",
+			R_ICTL1, FB_ICTL1_IN2HP, 1, 0),
+	/* R_MICBIAS PG 1 ADDR 0x0C */
+	SOC_ENUM("Mic Bias 2 Voltage", mic_bias_2_enum),
+	SOC_ENUM("Mic Bias 1 Voltage", mic_bias_1_enum),
+	/* R_PGACTL0 PG 1 ADDR 0x0D */
+	SOC_SINGLE("Input Channel 0 PGA Mute Switch",
+			R_PGACTL0, FB_PGACTL_PGAMUTE, 1, 0),
+	SOC_SINGLE_TLV("Input Channel 0 PGA Volume", R_PGACTL0,
+			FB_PGACTL_PGAVOL,
+			FM_PGACTL_PGAVOL, 0, in_pga_vol_tlv_arr),
+	/* R_PGACTL1 PG 1 ADDR 0x0E */
+	SOC_SINGLE("Input Channel 1 PGA Mute Switch",
+			R_PGACTL1, FB_PGACTL_PGAMUTE, 1, 0),
+	SOC_SINGLE_TLV("Input Channel 1 PGA Volume", R_PGACTL1,
+			FB_PGACTL_PGAVOL,
+			FM_PGACTL_PGAVOL, 0, in_pga_vol_tlv_arr),
+	/* R_PGACTL2 PG 1 ADDR 0x0F */
+	SOC_SINGLE("Input Channel 2 PGA Mute Switch",
+			R_PGACTL2, FB_PGACTL_PGAMUTE, 1, 0),
+	SOC_SINGLE_TLV("Input Channel 2 PGA Volume", R_PGACTL2,
+			FB_PGACTL_PGAVOL,
+			FM_PGACTL_PGAVOL, 0, in_pga_vol_tlv_arr),
+	/* R_PGACTL3 PG 1 ADDR 0x10 */
+	SOC_SINGLE("Input Channel 3 PGA Mute Switch",
+			R_PGACTL3, FB_PGACTL_PGAMUTE, 1, 0),
+	SOC_SINGLE_TLV("Input Channel 3 PGA Volume", R_PGACTL3,
+			FB_PGACTL_PGAVOL,
+			FM_PGACTL_PGAVOL, 0, in_pga_vol_tlv_arr),
+	/* R_ICH0VOL PG 1 ADDR 0x12 */
+	SOC_SINGLE_TLV("Input Channel 0 Volume", R_ICH0VOL,
+			FB_ICHVOL_ICHVOL, FM_ICHVOL_ICHVOL, 0, in_vol_tlv_arr),
+	/* R_ICH1VOL PG 1 ADDR 0x13 */
+	SOC_SINGLE_TLV("Input Channel 1 Volume", R_ICH1VOL,
+			FB_ICHVOL_ICHVOL, FM_ICHVOL_ICHVOL, 0, in_vol_tlv_arr),
+	/* R_ICH2VOL PG 1 ADDR 0x14 */
+	SOC_SINGLE_TLV("Input Channel 2 Volume", R_ICH2VOL,
+			FB_ICHVOL_ICHVOL, FM_ICHVOL_ICHVOL, 0, in_vol_tlv_arr),
+	/* R_ICH3VOL PG 1 ADDR 0x15 */
+	SOC_SINGLE_TLV("Input Channel 3 Volume", R_ICH3VOL,
+			FB_ICHVOL_ICHVOL, FM_ICHVOL_ICHVOL, 0, in_vol_tlv_arr),
+	/* R_ASRCILVOL PG 1 ADDR 0x16 */
+	SOC_SINGLE_TLV("ASRC Input Left Volume", R_ASRCILVOL,
+			FB_ASRCILVOL_ASRCILVOL, FM_ASRCILVOL_ASRCILVOL,
+			0, asrc_vol_tlv_arr),
+	/* R_ASRCIRVOL PG 1 ADDR 0x17 */
+	SOC_SINGLE_TLV("ASRC Input Right Volume", R_ASRCIRVOL,
+			FB_ASRCIRVOL_ASRCIRVOL, FM_ASRCIRVOL_ASRCIRVOL,
+			0, asrc_vol_tlv_arr),
+	/* R_ASRCOLVOL PG 1 ADDR 0x18 */
+	SOC_SINGLE_TLV("ASRC Output Left Volume", R_ASRCOLVOL,
+			FB_ASRCOLVOL_ASRCOLVOL, FM_ASRCOLVOL_ASRCOLVOL,
+			0, asrc_vol_tlv_arr),
+	/* R_ASRCORVOL PG 1 ADDR 0x19 */
+	SOC_SINGLE_TLV("ASRC Output Right Volume", R_ASRCORVOL,
+			FB_ASRCORVOL_ASRCOLVOL, FM_ASRCORVOL_ASRCOLVOL,
+			0, asrc_vol_tlv_arr),
+	/* R_IVOLCTLU PG 1 ADDR 0x1C */
+	/* R_ALCCTL0 PG 1 ADDR 0x1D */
+	SOC_ENUM("ALC Mode", alc_mode_enum),
+	SOC_ENUM("ALC Reference", alc_ref_enum),
+	SOC_SINGLE("Input Channel 3 ALC Switch",
+			R_ALCCTL0, FB_ALCCTL0_ALCEN3, 1, 0),
+	SOC_SINGLE("Input Channel 2 ALC Switch",
+			R_ALCCTL0, FB_ALCCTL0_ALCEN2, 1, 0),
+	SOC_SINGLE("Input Channel 1 ALC Switch",
+			R_ALCCTL0, FB_ALCCTL0_ALCEN1, 1, 0),
+	SOC_SINGLE("Input Channel 0 ALC Switch",
+			R_ALCCTL0, FB_ALCCTL0_ALCEN0, 1, 0),
+	/* R_ALCCTL1 PG 1 ADDR 0x1E */
+	SOC_SINGLE_TLV("ALC Max Gain Volume", R_ALCCTL1,
+			FB_ALCCTL1_MAXGAIN, FM_ALCCTL1_MAXGAIN,
+			0, alc_max_gain_tlv_arr),
+	SOC_SINGLE_TLV("ALC Target Volume", R_ALCCTL1,
+			FB_ALCCTL1_ALCL, FM_ALCCTL1_ALCL,
+			0, alc_target_tlv_arr),
+	/* R_ALCCTL2 PG 1 ADDR 0x1F */
+	SOC_SINGLE("ALC Zero Cross Switch",
+			R_ALCCTL2, FB_ALCCTL2_ALCZC, 1, 0),
+	SOC_SINGLE_TLV("ALC Min Gain Volume", R_ALCCTL2,
+			FB_ALCCTL2_MINGAIN, FM_ALCCTL2_MINGAIN,
+			0, alc_min_gain_tlv_arr),
+	SOC_SINGLE_RANGE("ALC Hold", R_ALCCTL2,
+			FB_ALCCTL2_HLD, 0, FM_ALCCTL2_HLD, 0),
+	/* R_ALCCTL3 PG 1 ADDR 0x20 */
+	SOC_SINGLE_RANGE("ALC Decay", R_ALCCTL3,
+			FB_ALCCTL3_DCY, 0, FM_ALCCTL3_DCY, 0),
+	SOC_SINGLE_RANGE("ALC Attack", R_ALCCTL3,
+			FB_ALCCTL3_ATK, 0, FM_ALCCTL3_ATK, 0),
+	/* R_NGATE PG 1 ADDR 0x21 */
+	SOC_SINGLE_TLV("Noise Gate Threshold Volume", R_NGATE,
+			FB_NGATE_NGTH, FM_NGATE_NGTH, 0, ngth_tlv_arr),
+	SOC_ENUM("Noise Gate Type", ngate_type_enum),
+	SOC_SINGLE("Noise Gate Switch", R_NGATE, FB_NGATE_NGAT, 1, 0),
+	/* R_DMICCTL PG 1 ADDR 0x22 */
+	SOC_SINGLE("Digital Mic 2 Switch", R_DMICCTL, FB_DMICCTL_DMIC2EN, 1, 0),
+	SOC_SINGLE("Digital Mic 1 Switch", R_DMICCTL, FB_DMICCTL_DMIC1EN, 1, 0),
+	SOC_ENUM("Digital Mic Mono Select", dmic_mono_sel_enum),
+	/* R_DACCTL PG 2 ADDR 0x01 */
+	SOC_ENUM("DAC Polarity Left", dac_pol_r_enum),
+	SOC_ENUM("DAC Polarity Right", dac_pol_l_enum),
+	SOC_ENUM("DAC Dither", dac_dith_enum),
+	SOC_SINGLE("DAC Mute Switch", R_DACCTL, FB_DACCTL_DACMUTE, 1, 0),
+	SOC_SINGLE("DAC De-Emphasis Switch", R_DACCTL, FB_DACCTL_DACDEM, 1, 0),
+	/* R_SPKCTL PG 2 ADDR 0x02 */
+	SOC_ENUM("Speaker Polarity Right", spk_pol_r_enum),
+	SOC_ENUM("Speaker Polarity Left", spk_pol_l_enum),
+	SOC_SINGLE("Speaker Mute Switch", R_SPKCTL, FB_SPKCTL_SPKMUTE, 1, 0),
+	SOC_SINGLE("Speaker De-Emphasis Switch",
+			R_SPKCTL, FB_SPKCTL_SPKDEM, 1, 0),
+	/* R_SUBCTL PG 2 ADDR 0x03 */
+	SOC_ENUM("Sub Polarity", sub_pol_enum),
+	SOC_SINGLE("SUB Mute Switch", R_SUBCTL, FB_SUBCTL_SUBMUTE, 1, 0),
+	SOC_SINGLE("Sub De-Emphasis Switch", R_SUBCTL, FB_SUBCTL_SUBDEM, 1, 0),
+	/* R_DCCTL PG 2 ADDR 0x04 */
+	SOC_SINGLE("Sub DC Removal Switch", R_DCCTL, FB_DCCTL_SUBDCBYP, 1, 1),
+	SOC_SINGLE("DAC DC Removal Switch", R_DCCTL, FB_DCCTL_DACDCBYP, 1, 1),
+	SOC_SINGLE("Speaker DC Removal Switch",
+			R_DCCTL, FB_DCCTL_SPKDCBYP, 1, 1),
+	SOC_SINGLE("DC Removal Coefficient Switch", R_DCCTL, FB_DCCTL_DCCOEFSEL,
+			FM_DCCTL_DCCOEFSEL, 0),
+	/* R_OVOLCTLU PG 2 ADDR 0x06 */
+	SOC_SINGLE("Output Fade Switch", R_OVOLCTLU, FB_OVOLCTLU_OFADE, 1, 0),
+	/* R_MVOLL PG 2 ADDR 0x08 */
+	/* R_MVOLR PG 2 ADDR 0x09 */
+	SOC_DOUBLE_R_TLV("Master Volume", R_MVOLL, R_MVOLR,
+			FB_MVOLL_MVOL_L, FM_MVOLL_MVOL_L, 0, mvol_tlv_arr),
+	/* R_HPVOLL PG 2 ADDR 0x0A */
+	/* R_HPVOLR PG 2 ADDR 0x0B */
+	SOC_DOUBLE_R_TLV("Headphone Volume", R_HPVOLL, R_HPVOLR,
+			FB_HPVOLL_HPVOL_L, FM_HPVOLL_HPVOL_L, 0,
+			hp_vol_tlv_arr),
+	/* R_SPKVOLL PG 2 ADDR 0x0C */
+	/* R_SPKVOLR PG 2 ADDR 0x0D */
+	SOC_DOUBLE_R_TLV("Speaker Volume", R_SPKVOLL, R_SPKVOLR,
+			FB_SPKVOLL_SPKVOL_L, FM_SPKVOLL_SPKVOL_L, 0,
+			spk_vol_tlv_arr),
+	/* R_SUBVOL PG 2 ADDR 0x10 */
+	SOC_SINGLE_TLV("Sub Volume", R_SUBVOL,
+			FB_SUBVOL_SUBVOL, FM_SUBVOL_SUBVOL, 0, spk_vol_tlv_arr),
+	/* R_SPKEQFILT PG 3 ADDR 0x01 */
+	SOC_SINGLE("Speaker EQ 2 Switch",
+			R_SPKEQFILT, FB_SPKEQFILT_EQ2EN, 1, 0),
+	SOC_ENUM("Speaker EQ 2 Band", spk_eq_enums[0]),
+	SOC_SINGLE("Speaker EQ 1 Switch",
+			R_SPKEQFILT, FB_SPKEQFILT_EQ1EN, 1, 0),
+	SOC_ENUM("Speaker EQ 1 Band", spk_eq_enums[1]),
+	/* R_SPKMBCEN PG 3 ADDR 0x0A */
+	SOC_SINGLE("Speaker MBC 3 Switch",
+			R_SPKMBCEN, FB_SPKMBCEN_MBCEN3, 1, 0),
+	SOC_SINGLE("Speaker MBC 2 Switch",
+			R_SPKMBCEN, FB_SPKMBCEN_MBCEN2, 1, 0),
+	SOC_SINGLE("Speaker MBC 1 Switch",
+			R_SPKMBCEN, FB_SPKMBCEN_MBCEN1, 1, 0),
+	/* R_SPKMBCCTL PG 3 ADDR 0x0B */
+	SOC_ENUM("Speaker MBC 3 Mode", spk_mbc3_lvl_det_mode_enum),
+	SOC_ENUM("Speaker MBC 3 Window", spk_mbc3_win_sel_enum),
+	SOC_ENUM("Speaker MBC 2 Mode", spk_mbc2_lvl_det_mode_enum),
+	SOC_ENUM("Speaker MBC 2 Window", spk_mbc2_win_sel_enum),
+	SOC_ENUM("Speaker MBC 1 Mode", spk_mbc1_lvl_det_mode_enum),
+	SOC_ENUM("Speaker MBC 1 Window", spk_mbc1_win_sel_enum),
+	/* R_SPKMBCMUG1 PG 3 ADDR 0x0C */
+	SOC_ENUM("Speaker MBC 1 Phase Polarity", spk_mbc1_phase_pol_enum),
+	SOC_SINGLE_TLV("Speaker MBC1 Make-Up Gain Volume", R_SPKMBCMUG1,
+			FB_SPKMBCMUG_MUGAIN, FM_SPKMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_SPKMBCTHR1 PG 3 ADDR 0x0D */
+	SOC_SINGLE_TLV("Speaker MBC 1 Compressor Threshold Volume",
+			R_SPKMBCTHR1, FB_SPKMBCTHR_THRESH, FM_SPKMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SPKMBCRAT1 PG 3 ADDR 0x0E */
+	SOC_ENUM("Speaker MBC 1 Compressor Ratio", spk_mbc1_comp_rat_enum),
+	/* R_SPKMBCATK1L PG 3 ADDR 0x0F */
+	/* R_SPKMBCATK1H PG 3 ADDR 0x10 */
+	SND_SOC_BYTES("Speaker MBC 1 Attack", R_SPKMBCATK1L, 2),
+	/* R_SPKMBCREL1L PG 3 ADDR 0x11 */
+	/* R_SPKMBCREL1H PG 3 ADDR 0x12 */
+	SND_SOC_BYTES("Speaker MBC 1 Release", R_SPKMBCREL1L, 2),
+	/* R_SPKMBCMUG2 PG 3 ADDR 0x13 */
+	SOC_ENUM("Speaker MBC 2 Phase Polarity", spk_mbc2_phase_pol_enum),
+	SOC_SINGLE_TLV("Speaker MBC2 Make-Up Gain Volume", R_SPKMBCMUG2,
+			FB_SPKMBCMUG_MUGAIN, FM_SPKMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_SPKMBCTHR2 PG 3 ADDR 0x14 */
+	SOC_SINGLE_TLV("Speaker MBC 2 Compressor Threshold Volume",
+			R_SPKMBCTHR2, FB_SPKMBCTHR_THRESH, FM_SPKMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SPKMBCRAT2 PG 3 ADDR 0x15 */
+	SOC_ENUM("Speaker MBC 2 Compressor Ratio", spk_mbc2_comp_rat_enum),
+	/* R_SPKMBCATK2L PG 3 ADDR 0x16 */
+	/* R_SPKMBCATK2H PG 3 ADDR 0x17 */
+	SND_SOC_BYTES("Speaker MBC 2 Attack", R_SPKMBCATK2L, 2),
+	/* R_SPKMBCREL2L PG 3 ADDR 0x18 */
+	/* R_SPKMBCREL2H PG 3 ADDR 0x19 */
+	SND_SOC_BYTES("Speaker MBC 2 Release", R_SPKMBCREL2L, 2),
+	/* R_SPKMBCMUG3 PG 3 ADDR 0x1A */
+	SOC_ENUM("Speaker MBC 3 Phase Polarity", spk_mbc3_phase_pol_enum),
+	SOC_SINGLE_TLV("Speaker MBC 3 Make-Up Gain Volume", R_SPKMBCMUG3,
+			FB_SPKMBCMUG_MUGAIN, FM_SPKMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_SPKMBCTHR3 PG 3 ADDR 0x1B */
+	SOC_SINGLE_TLV("Speaker MBC 3 Threshold Volume", R_SPKMBCTHR3,
+			FB_SPKMBCTHR_THRESH, FM_SPKMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SPKMBCRAT3 PG 3 ADDR 0x1C */
+	SOC_ENUM("Speaker MBC 3 Compressor Ratio", spk_mbc3_comp_rat_enum),
+	/* R_SPKMBCATK3L PG 3 ADDR 0x1D */
+	/* R_SPKMBCATK3H PG 3 ADDR 0x1E */
+	SND_SOC_BYTES("Speaker MBC 3 Attack", R_SPKMBCATK3L, 3),
+	/* R_SPKMBCREL3L PG 3 ADDR 0x1F */
+	/* R_SPKMBCREL3H PG 3 ADDR 0x20 */
+	SND_SOC_BYTES("Speaker MBC 3 Release", R_SPKMBCREL3L, 3),
+	/* R_SPKCLECTL PG 3 ADDR 0x21 */
+	SOC_ENUM("Speaker CLE Level Mode", spk_cle_lvl_mode_enum),
+	SOC_ENUM("Speaker CLE Window", spk_cle_win_sel_enum),
+	SOC_SINGLE("Speaker CLE Expander Switch",
+			R_SPKCLECTL, FB_SPKCLECTL_EXPEN, 1, 0),
+	SOC_SINGLE("Speaker CLE Limiter Switch",
+			R_SPKCLECTL, FB_SPKCLECTL_LIMEN, 1, 0),
+	SOC_SINGLE("Speaker CLE Compressor Switch",
+			R_SPKCLECTL, FB_SPKCLECTL_COMPEN, 1, 0),
+	/* R_SPKCLEMUG PG 3 ADDR 0x22 */
+	SOC_SINGLE_TLV("Speaker CLE Make-Up Gain Volume", R_SPKCLEMUG,
+			FB_SPKCLEMUG_MUGAIN, FM_SPKCLEMUG_MUGAIN,
+			0, cle_mug_tlv_arr),
+	/* R_SPKCOMPTHR PG 3 ADDR 0x23 */
+	SOC_SINGLE_TLV("Speaker Compressor Threshold Volume", R_SPKCOMPTHR,
+			FB_SPKCOMPTHR_THRESH, FM_SPKCOMPTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SPKCOMPRAT PG 3 ADDR 0x24 */
+	SOC_ENUM("Speaker Compressor Ratio", spk_comp_rat_enum),
+	/* R_SPKCOMPATKL PG 3 ADDR 0x25 */
+	/* R_SPKCOMPATKH PG 3 ADDR 0x26 */
+	SND_SOC_BYTES("Speaker Compressor Attack", R_SPKCOMPATKL, 2),
+	/* R_SPKCOMPRELL PG 3 ADDR 0x27 */
+	/* R_SPKCOMPRELH PG 3 ADDR 0x28 */
+	SND_SOC_BYTES("Speaker Compressor Release", R_SPKCOMPRELL, 2),
+	/* R_SPKLIMTHR PG 3 ADDR 0x29 */
+	SOC_SINGLE_TLV("Speaker Limiter Threshold Volume", R_SPKLIMTHR,
+			FB_SPKLIMTHR_THRESH, FM_SPKLIMTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SPKLIMTGT PG 3 ADDR 0x2A */
+	SOC_SINGLE_TLV("Speaker Limiter Target Volume", R_SPKLIMTGT,
+			FB_SPKLIMTGT_TARGET, FM_SPKLIMTGT_TARGET,
+			0, thr_tlv_arr),
+	/* R_SPKLIMATKL PG 3 ADDR 0x2B */
+	/* R_SPKLIMATKH PG 3 ADDR 0x2C */
+	SND_SOC_BYTES("Speaker Limiter Attack", R_SPKLIMATKL, 2),
+	/* R_SPKLIMRELL PG 3 ADDR 0x2D */
+	/* R_SPKLIMRELR PG 3 ADDR 0x2E */
+	SND_SOC_BYTES("Speaker Limiter Release", R_SPKLIMRELL, 2),
+	/* R_SPKEXPTHR PG 3 ADDR 0x2F */
+	SOC_SINGLE_TLV("Speaker Expander Threshold Volume", R_SPKEXPTHR,
+			FB_SPKEXPTHR_THRESH, FM_SPKEXPTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SPKEXPRAT PG 3 ADDR 0x30 */
+	SOC_ENUM("Speaker Expander Ratio", spk_exp_rat_enum),
+	/* R_SPKEXPATKL PG 3 ADDR 0x31 */
+	/* R_SPKEXPATKR PG 3 ADDR 0x32 */
+	SND_SOC_BYTES("Speaker Expander Attack", R_SPKEXPATKL, 2),
+	/* R_SPKEXPRELL PG 3 ADDR 0x33 */
+	/* R_SPKEXPRELR PG 3 ADDR 0x34 */
+	SND_SOC_BYTES("Speaker Expander Release", R_SPKEXPRELL, 2),
+	/* R_SPKFXCTL PG 3 ADDR 0x35 */
+	SOC_SINGLE("Speaker 3D Switch", R_SPKFXCTL, FB_SPKFXCTL_3DEN, 1, 0),
+	SOC_SINGLE("Speaker Treble Enhancement Switch",
+			R_SPKFXCTL, FB_SPKFXCTL_TEEN, 1, 0),
+	SOC_SINGLE("Speaker Treble NLF Switch",
+			R_SPKFXCTL, FB_SPKFXCTL_TNLFBYP, 1, 1),
+	SOC_SINGLE("Speaker Bass Enhancement Switch",
+			R_SPKFXCTL, FB_SPKFXCTL_BEEN, 1, 0),
+	SOC_SINGLE("Speaker Bass NLF Switch",
+			R_SPKFXCTL, FB_SPKFXCTL_BNLFBYP, 1, 1),
+	/* R_DACEQFILT PG 4 ADDR 0x01 */
+	SOC_SINGLE("DAC EQ 2 Switch",
+			R_DACEQFILT, FB_DACEQFILT_EQ2EN, 1, 0),
+	SOC_ENUM("DAC EQ 2 Band", dac_eq_enums[0]),
+	SOC_SINGLE("DAC EQ 1 Switch", R_DACEQFILT, FB_DACEQFILT_EQ1EN, 1, 0),
+	SOC_ENUM("DAC EQ 1 Band", dac_eq_enums[1]),
+	/* R_DACMBCEN PG 4 ADDR 0x0A */
+	SOC_SINGLE("DAC MBC 3 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN3, 1, 0),
+	SOC_SINGLE("DAC MBC 2 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN2, 1, 0),
+	SOC_SINGLE("DAC MBC 1 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN1, 1, 0),
+	/* R_DACMBCCTL PG 4 ADDR 0x0B */
+	SOC_ENUM("DAC MBC 3 Mode", dac_mbc3_lvl_det_mode_enum),
+	SOC_ENUM("DAC MBC 3 Window", dac_mbc3_win_sel_enum),
+	SOC_ENUM("DAC MBC 2 Mode", dac_mbc2_lvl_det_mode_enum),
+	SOC_ENUM("DAC MBC 2 Window", dac_mbc2_win_sel_enum),
+	SOC_ENUM("DAC MBC 1 Mode", dac_mbc1_lvl_det_mode_enum),
+	SOC_ENUM("DAC MBC 1 Window", dac_mbc1_win_sel_enum),
+	/* R_DACMBCMUG1 PG 4 ADDR 0x0C */
+	SOC_ENUM("DAC MBC 1 Phase Polarity", dac_mbc1_phase_pol_enum),
+	SOC_SINGLE_TLV("DAC MBC 1 Make-Up Gain Volume", R_DACMBCMUG1,
+			FB_DACMBCMUG_MUGAIN, FM_DACMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_DACMBCTHR1 PG 4 ADDR 0x0D */
+	SOC_SINGLE_TLV("DAC MBC 1 Compressor Threshold Volume", R_DACMBCTHR1,
+			FB_DACMBCTHR_THRESH, FM_DACMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_DACMBCRAT1 PG 4 ADDR 0x0E */
+	SOC_ENUM("DAC MBC 1 Compressor Ratio", dac_mbc1_comp_rat_enum),
+	/* R_DACMBCATK1L PG 4 ADDR 0x0F */
+	/* R_DACMBCATK1H PG 4 ADDR 0x10 */
+	SND_SOC_BYTES("DAC MBC 1 Attack", R_DACMBCATK1L, 2),
+	/* R_DACMBCREL1L PG 4 ADDR 0x11 */
+	/* R_DACMBCREL1H PG 4 ADDR 0x12 */
+	SND_SOC_BYTES("DAC MBC 1 Release", R_DACMBCREL1L, 2),
+	/* R_DACMBCMUG2 PG 4 ADDR 0x13 */
+	SOC_ENUM("DAC MBC 2 Phase Polarity", dac_mbc2_phase_pol_enum),
+	SOC_SINGLE_TLV("DAC MBC 2 Make-Up Gain Volume", R_DACMBCMUG2,
+			FB_DACMBCMUG_MUGAIN, FM_DACMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_DACMBCTHR2 PG 4 ADDR 0x14 */
+	SOC_SINGLE_TLV("DAC MBC 2 Compressor Threshold Volume", R_DACMBCTHR2,
+			FB_DACMBCTHR_THRESH, FM_DACMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_DACMBCRAT2 PG 4 ADDR 0x15 */
+	SOC_ENUM("DAC MBC 2 Compressor Ratio", dac_mbc2_comp_rat_enum),
+	/* R_DACMBCATK2L PG 4 ADDR 0x16 */
+	/* R_DACMBCATK2H PG 4 ADDR 0x17 */
+	SND_SOC_BYTES("DAC MBC 2 Attack", R_DACMBCATK2L, 2),
+	/* R_DACMBCREL2L PG 4 ADDR 0x18 */
+	/* R_DACMBCREL2H PG 4 ADDR 0x19 */
+	SND_SOC_BYTES("DAC MBC 2 Release", R_DACMBCREL2L, 2),
+	/* R_DACMBCMUG3 PG 4 ADDR 0x1A */
+	SOC_ENUM("DAC MBC 3 Phase Polarity", dac_mbc3_phase_pol_enum),
+	SOC_SINGLE_TLV("DAC MBC 3 Make-Up Gain Volume", R_DACMBCMUG3,
+			FB_DACMBCMUG_MUGAIN, FM_DACMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_DACMBCTHR3 PG 4 ADDR 0x1B */
+	SOC_SINGLE_TLV("DAC MBC 3 Threshold Volume", R_DACMBCTHR3,
+			FB_DACMBCTHR_THRESH, FM_DACMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_DACMBCRAT3 PG 4 ADDR 0x1C */
+	SOC_ENUM("DAC MBC 3 Compressor Ratio", dac_mbc3_comp_rat_enum),
+	/* R_DACMBCATK3L PG 4 ADDR 0x1D */
+	/* R_DACMBCATK3H PG 4 ADDR 0x1E */
+	SND_SOC_BYTES("DAC MBC 3 Attack", R_DACMBCATK3L, 3),
+	/* R_DACMBCREL3L PG 4 ADDR 0x1F */
+	/* R_DACMBCREL3H PG 4 ADDR 0x20 */
+	SND_SOC_BYTES("DAC MBC 3 Release", R_DACMBCREL3L, 3),
+	/* R_DACCLECTL PG 4 ADDR 0x21 */
+	SOC_ENUM("DAC CLE Level Mode", dac_cle_lvl_mode_enum),
+	SOC_ENUM("DAC CLE Window", dac_cle_win_sel_enum),
+	SOC_SINGLE("DAC CLE Expander Switch",
+			R_DACCLECTL, FB_DACCLECTL_EXPEN, 1, 0),
+	SOC_SINGLE("DAC CLE Limiter Switch",
+			R_DACCLECTL, FB_DACCLECTL_LIMEN, 1, 0),
+	SOC_SINGLE("DAC CLE Compressor Switch",
+			R_DACCLECTL, FB_DACCLECTL_COMPEN, 1, 0),
+	/* R_DACCLEMUG PG 4 ADDR 0x22 */
+	SOC_SINGLE_TLV("DAC CLE Make-Up Gain Volume", R_DACCLEMUG,
+			FB_DACCLEMUG_MUGAIN, FM_DACCLEMUG_MUGAIN,
+			0, cle_mug_tlv_arr),
+	/* R_DACCOMPTHR PG 4 ADDR 0x23 */
+	SOC_SINGLE_TLV("DAC Compressor Threshold Volume", R_DACCOMPTHR,
+			FB_DACCOMPTHR_THRESH, FM_DACCOMPTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_DACCOMPRAT PG 4 ADDR 0x24 */
+	SOC_ENUM("DAC Compressor Ratio", dac_comp_rat_enum),
+	/* R_DACCOMPATKL PG 4 ADDR 0x25 */
+	/* R_DACCOMPATKH PG 4 ADDR 0x26 */
+	SND_SOC_BYTES("DAC Compressor Attack", R_DACCOMPATKL, 2),
+	/* R_DACCOMPRELL PG 4 ADDR 0x27 */
+	/* R_DACCOMPRELH PG 4 ADDR 0x28 */
+	SND_SOC_BYTES("DAC Compressor Release", R_DACCOMPRELL, 2),
+	/* R_DACLIMTHR PG 4 ADDR 0x29 */
+	SOC_SINGLE_TLV("DAC Limiter Threshold Volume", R_DACLIMTHR,
+			FB_DACLIMTHR_THRESH, FM_DACLIMTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_DACLIMTGT PG 4 ADDR 0x2A */
+	SOC_SINGLE_TLV("DAC Limiter Target Volume", R_DACLIMTGT,
+			FB_DACLIMTGT_TARGET, FM_DACLIMTGT_TARGET,
+			0, thr_tlv_arr),
+	/* R_DACLIMATKL PG 4 ADDR 0x2B */
+	/* R_DACLIMATKH PG 4 ADDR 0x2C */
+	SND_SOC_BYTES("DAC Limiter Attack", R_DACLIMATKL, 2),
+	/* R_DACLIMRELL PG 4 ADDR 0x2D */
+	/* R_DACLIMRELR PG 4 ADDR 0x2E */
+	SND_SOC_BYTES("DAC Limiter Release", R_DACLIMRELL, 2),
+	/* R_DACEXPTHR PG 4 ADDR 0x2F */
+	SOC_SINGLE_TLV("DAC Expander Threshold Volume", R_DACEXPTHR,
+			FB_DACEXPTHR_THRESH, FM_DACEXPTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_DACEXPRAT PG 4 ADDR 0x30 */
+	SOC_ENUM("DAC Expander Ratio", dac_exp_rat_enum),
+	/* R_DACEXPATKL PG 4 ADDR 0x31 */
+	/* R_DACEXPATKR PG 4 ADDR 0x32 */
+	SND_SOC_BYTES("DAC Expander Attack", R_DACEXPATKL, 2),
+	/* R_DACEXPRELL PG 4 ADDR 0x33 */
+	/* R_DACEXPRELR PG 4 ADDR 0x34 */
+	SND_SOC_BYTES("DAC Expander Release", R_DACEXPRELL, 2),
+	/* R_DACFXCTL PG 4 ADDR 0x35 */
+	SOC_SINGLE("DAC 3D Switch", R_DACFXCTL, FB_DACFXCTL_3DEN, 1, 0),
+	SOC_SINGLE("DAC Treble Enhancement Switch",
+			R_DACFXCTL, FB_DACFXCTL_TEEN, 1, 0),
+	SOC_SINGLE("DAC Treble NLF Switch",
+			R_DACFXCTL, FB_DACFXCTL_TNLFBYP, 1, 1),
+	SOC_SINGLE("DAC Bass Enhancement Switch",
+			R_DACFXCTL, FB_DACFXCTL_BEEN, 1, 0),
+	SOC_SINGLE("DAC Bass NLF Switch",
+			R_DACFXCTL, FB_DACFXCTL_BNLFBYP, 1, 1),
+	/* R_SUBEQFILT PG 5 ADDR 0x01 */
+	SOC_SINGLE("Sub EQ 2 Switch",
+			R_SUBEQFILT, FB_SUBEQFILT_EQ2EN, 1, 0),
+	SOC_ENUM("Sub EQ 2 Band", sub_eq_enums[0]),
+	SOC_SINGLE("Sub EQ 1 Switch", R_SUBEQFILT, FB_SUBEQFILT_EQ1EN, 1, 0),
+	SOC_ENUM("Sub EQ 1 Band", sub_eq_enums[1]),
+	/* R_SUBMBCEN PG 5 ADDR 0x0A */
+	SOC_SINGLE("Sub MBC 3 Switch", R_SUBMBCEN, FB_SUBMBCEN_MBCEN3, 1, 0),
+	SOC_SINGLE("Sub MBC 2 Switch", R_SUBMBCEN, FB_SUBMBCEN_MBCEN2, 1, 0),
+	SOC_SINGLE("Sub MBC 1 Switch", R_SUBMBCEN, FB_SUBMBCEN_MBCEN1, 1, 0),
+	/* R_SUBMBCCTL PG 5 ADDR 0x0B */
+	SOC_ENUM("Sub MBC 3 Mode", sub_mbc3_lvl_det_mode_enum),
+	SOC_ENUM("Sub MBC 3 Window", sub_mbc3_win_sel_enum),
+	SOC_ENUM("Sub MBC 2 Mode", sub_mbc2_lvl_det_mode_enum),
+	SOC_ENUM("Sub MBC 2 Window", sub_mbc2_win_sel_enum),
+	SOC_ENUM("Sub MBC 1 Mode", sub_mbc1_lvl_det_mode_enum),
+	SOC_ENUM("Sub MBC 1 Window", sub_mbc1_win_sel_enum),
+	/* R_SUBMBCMUG1 PG 5 ADDR 0x0C */
+	SOC_ENUM("Sub MBC 1 Phase Polarity", sub_mbc1_phase_pol_enum),
+	SOC_SINGLE_TLV("Sub MBC 1 Make-Up Gain Volume", R_SUBMBCMUG1,
+			FB_SUBMBCMUG_MUGAIN, FM_SUBMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_SUBMBCTHR1 PG 5 ADDR 0x0D */
+	SOC_SINGLE_TLV("Sub MBC 1 Compressor Threshold Volume", R_SUBMBCTHR1,
+			FB_SUBMBCTHR_THRESH, FM_SUBMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SUBMBCRAT1 PG 5 ADDR 0x0E */
+	SOC_ENUM("Sub MBC 1 Compressor Ratio", sub_mbc1_comp_rat_enum),
+	/* R_SUBMBCATK1L PG 5 ADDR 0x0F */
+	/* R_SUBMBCATK1H PG 5 ADDR 0x10 */
+	SND_SOC_BYTES("Sub MBC 1 Attack", R_SUBMBCATK1L, 2),
+	/* R_SUBMBCREL1L PG 5 ADDR 0x11 */
+	/* R_SUBMBCREL1H PG 5 ADDR 0x12 */
+	SND_SOC_BYTES("Sub MBC 1 Release", R_SUBMBCREL1L, 2),
+	/* R_SUBMBCMUG2 PG 5 ADDR 0x13 */
+	SOC_ENUM("Sub MBC 2 Phase Polarity", sub_mbc2_phase_pol_enum),
+	SOC_SINGLE_TLV("Sub MBC 2 Make-Up Gain Volume", R_SUBMBCMUG2,
+			FB_SUBMBCMUG_MUGAIN, FM_SUBMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_SUBMBCTHR2 PG 5 ADDR 0x14 */
+	SOC_SINGLE_TLV("Sub MBC 2 Compressor Threshold Volume", R_SUBMBCTHR2,
+			FB_SUBMBCTHR_THRESH, FM_SUBMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SUBMBCRAT2 PG 5 ADDR 0x15 */
+	SOC_ENUM("Sub MBC 2 Compressor Ratio", sub_mbc2_comp_rat_enum),
+	/* R_SUBMBCATK2L PG 5 ADDR 0x16 */
+	/* R_SUBMBCATK2H PG 5 ADDR 0x17 */
+	SND_SOC_BYTES("Sub MBC 2 Attack", R_SUBMBCATK2L, 2),
+	/* R_SUBMBCREL2L PG 5 ADDR 0x18 */
+	/* R_SUBMBCREL2H PG 5 ADDR 0x19 */
+	SND_SOC_BYTES("Sub MBC 2 Release", R_SUBMBCREL2L, 2),
+	/* R_SUBMBCMUG3 PG 5 ADDR 0x1A */
+	SOC_ENUM("Sub MBC 3 Phase Polarity", sub_mbc3_phase_pol_enum),
+	SOC_SINGLE_TLV("Sub MBC 3 Make-Up Gain Volume", R_SUBMBCMUG3,
+			FB_SUBMBCMUG_MUGAIN, FM_SUBMBCMUG_MUGAIN,
+			0, mbc_mug_tlv_arr),
+	/* R_SUBMBCTHR3 PG 5 ADDR 0x1B */
+	SOC_SINGLE_TLV("Sub MBC 3 Threshold Volume", R_SUBMBCTHR3,
+			FB_SUBMBCTHR_THRESH, FM_SUBMBCTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SUBMBCRAT3 PG 5 ADDR 0x1C */
+	SOC_ENUM("Sub MBC 3 Compressor Ratio", sub_mbc3_comp_rat_enum),
+	/* R_SUBMBCATK3L PG 5 ADDR 0x1D */
+	/* R_SUBMBCATK3H PG 5 ADDR 0x1E */
+	SND_SOC_BYTES("Sub MBC 3 Attack", R_SUBMBCATK3L, 3),
+	/* R_SUBMBCREL3L PG 5 ADDR 0x1F */
+	/* R_SUBMBCREL3H PG 5 ADDR 0x20 */
+	SND_SOC_BYTES("Sub MBC 3 Release", R_SUBMBCREL3L, 3),
+	/* R_SUBCLECTL PG 5 ADDR 0x21 */
+	SOC_ENUM("Sub CLE Level Mode", sub_cle_lvl_mode_enum),
+	SOC_ENUM("Sub CLE Window", sub_cle_win_sel_enum),
+	SOC_SINGLE("Sub CLE Expander Switch",
+			R_SUBCLECTL, FB_SUBCLECTL_EXPEN, 1, 0),
+	SOC_SINGLE("Sub CLE Limiter Switch",
+			R_SUBCLECTL, FB_SUBCLECTL_LIMEN, 1, 0),
+	SOC_SINGLE("Sub CLE Compressor Switch",
+			R_SUBCLECTL, FB_SUBCLECTL_COMPEN, 1, 0),
+	/* R_SUBCLEMUG PG 5 ADDR 0x22 */
+	SOC_SINGLE_TLV("Sub CLE Make-Up Gain Volume", R_SUBCLEMUG,
+			FB_SUBCLEMUG_MUGAIN, FM_SUBCLEMUG_MUGAIN,
+			0, cle_mug_tlv_arr),
+	/* R_SUBCOMPTHR PG 5 ADDR 0x23 */
+	SOC_SINGLE_TLV("Sub Compressor Threshold Volume", R_SUBCOMPTHR,
+			FB_SUBCOMPTHR_THRESH, FM_SUBCOMPTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SUBCOMPRAT PG 5 ADDR 0x24 */
+	SOC_ENUM("Sub Compressor Ratio", sub_comp_rat_enum),
+	/* R_SUBCOMPATKL PG 5 ADDR 0x25 */
+	/* R_SUBCOMPATKH PG 5 ADDR 0x26 */
+	SND_SOC_BYTES("Sub Compressor Attack", R_SUBCOMPATKL, 2),
+	/* R_SUBCOMPRELL PG 5 ADDR 0x27 */
+	/* R_SUBCOMPRELH PG 5 ADDR 0x28 */
+	SND_SOC_BYTES("Sub Compressor Release", R_SUBCOMPRELL, 2),
+	/* R_SUBLIMTHR PG 5 ADDR 0x29 */
+	SOC_SINGLE_TLV("Sub Limiter Threshold Volume", R_SUBLIMTHR,
+			FB_SUBLIMTHR_THRESH, FM_SUBLIMTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SUBLIMTGT PG 5 ADDR 0x2A */
+	SOC_SINGLE_TLV("Sub Limiter Target Volume", R_SUBLIMTGT,
+			FB_SUBLIMTGT_TARGET, FM_SUBLIMTGT_TARGET,
+			0, thr_tlv_arr),
+	/* R_SUBLIMATKL PG 5 ADDR 0x2B */
+	/* R_SUBLIMATKH PG 5 ADDR 0x2C */
+	SND_SOC_BYTES("Sub Limiter Attack", R_SUBLIMATKL, 2),
+	/* R_SUBLIMRELL PG 5 ADDR 0x2D */
+	/* R_SUBLIMRELR PG 5 ADDR 0x2E */
+	SND_SOC_BYTES("Sub Limiter Release", R_SUBLIMRELL, 2),
+	/* R_SUBEXPTHR PG 5 ADDR 0x2F */
+	SOC_SINGLE_TLV("Sub Expander Threshold Volume", R_SUBEXPTHR,
+			FB_SUBEXPTHR_THRESH, FM_SUBEXPTHR_THRESH,
+			0, thr_tlv_arr),
+	/* R_SUBEXPRAT PG 5 ADDR 0x30 */
+	SOC_ENUM("Sub Expander Ratio", sub_exp_rat_enum),
+	/* R_SUBEXPATKL PG 5 ADDR 0x31 */
+	/* R_SUBEXPATKR PG 5 ADDR 0x32 */
+	SND_SOC_BYTES("Sub Expander Attack", R_SUBEXPATKL, 2),
+	/* R_SUBEXPRELL PG 5 ADDR 0x33 */
+	/* R_SUBEXPRELR PG 5 ADDR 0x34 */
+	SND_SOC_BYTES("Sub Expander Release", R_SUBEXPRELL, 2),
+	/* R_SUBFXCTL PG 5 ADDR 0x35 */
+	SOC_SINGLE("Sub Treble Enhancement Switch",
+			R_SUBFXCTL, FB_SUBFXCTL_TEEN, 1, 0),
+	SOC_SINGLE("Sub Treble NLF Switch",
+			R_SUBFXCTL, FB_SUBFXCTL_TNLFBYP, 1, 1),
+	SOC_SINGLE("Sub Bass Enhancement Switch",
+			R_SUBFXCTL, FB_SUBFXCTL_BEEN, 1, 0),
+	SOC_SINGLE("Sub Bass NLF Switch",
+			R_SUBFXCTL, FB_SUBFXCTL_BNLFBYP, 1, 1),
+	COEFF_RAM_CTL("DAC Cascade 1 Left BiQuad 1", BIQUAD_SIZE, 0x00),
+	COEFF_RAM_CTL("DAC Cascade 1 Left BiQuad 2", BIQUAD_SIZE, 0x05),
+	COEFF_RAM_CTL("DAC Cascade 1 Left BiQuad 3", BIQUAD_SIZE, 0x0a),
+	COEFF_RAM_CTL("DAC Cascade 1 Left BiQuad 4", BIQUAD_SIZE, 0x0f),
+	COEFF_RAM_CTL("DAC Cascade 1 Left BiQuad 5", BIQUAD_SIZE, 0x14),
+	COEFF_RAM_CTL("DAC Cascade 1 Left BiQuad 6", BIQUAD_SIZE, 0x19),
+
+	COEFF_RAM_CTL("DAC Cascade 1 Right BiQuad 1", BIQUAD_SIZE, 0x20),
+	COEFF_RAM_CTL("DAC Cascade 1 Right BiQuad 2", BIQUAD_SIZE, 0x25),
+	COEFF_RAM_CTL("DAC Cascade 1 Right BiQuad 3", BIQUAD_SIZE, 0x2a),
+	COEFF_RAM_CTL("DAC Cascade 1 Right BiQuad 4", BIQUAD_SIZE, 0x2f),
+	COEFF_RAM_CTL("DAC Cascade 1 Right BiQuad 5", BIQUAD_SIZE, 0x34),
+	COEFF_RAM_CTL("DAC Cascade 1 Right BiQuad 6", BIQUAD_SIZE, 0x39),
+
+	COEFF_RAM_CTL("DAC Cascade 1 Left Prescale", COEFF_SIZE, 0x1f),
+	COEFF_RAM_CTL("DAC Cascade 1 Right Prescale", COEFF_SIZE, 0x3f),
+
+	COEFF_RAM_CTL("DAC Cascade 2 Left BiQuad 1", BIQUAD_SIZE, 0x40),
+	COEFF_RAM_CTL("DAC Cascade 2 Left BiQuad 2", BIQUAD_SIZE, 0x45),
+	COEFF_RAM_CTL("DAC Cascade 2 Left BiQuad 3", BIQUAD_SIZE, 0x4a),
+	COEFF_RAM_CTL("DAC Cascade 2 Left BiQuad 4", BIQUAD_SIZE, 0x4f),
+	COEFF_RAM_CTL("DAC Cascade 2 Left BiQuad 5", BIQUAD_SIZE, 0x54),
+	COEFF_RAM_CTL("DAC Cascade 2 Left BiQuad 6", BIQUAD_SIZE, 0x59),
+
+	COEFF_RAM_CTL("DAC Cascade 2 Right BiQuad 1", BIQUAD_SIZE, 0x60),
+	COEFF_RAM_CTL("DAC Cascade 2 Right BiQuad 2", BIQUAD_SIZE, 0x65),
+	COEFF_RAM_CTL("DAC Cascade 2 Right BiQuad 3", BIQUAD_SIZE, 0x6a),
+	COEFF_RAM_CTL("DAC Cascade 2 Right BiQuad 4", BIQUAD_SIZE, 0x6f),
+	COEFF_RAM_CTL("DAC Cascade 2 Right BiQuad 5", BIQUAD_SIZE, 0x74),
+	COEFF_RAM_CTL("DAC Cascade 2 Right BiQuad 6", BIQUAD_SIZE, 0x79),
+
+	COEFF_RAM_CTL("DAC Cascade 2 Left Prescale", COEFF_SIZE, 0x5f),
+	COEFF_RAM_CTL("DAC Cascade 2 Right Prescale", COEFF_SIZE, 0x7f),
+
+	COEFF_RAM_CTL("DAC Bass Extraction BiQuad 1", BIQUAD_SIZE, 0x80),
+	COEFF_RAM_CTL("DAC Bass Extraction BiQuad 2", BIQUAD_SIZE, 0x85),
+
+	COEFF_RAM_CTL("DAC Bass Non Linear Function 1", COEFF_SIZE, 0x8a),
+	COEFF_RAM_CTL("DAC Bass Non Linear Function 2", COEFF_SIZE, 0x8b),
+
+	COEFF_RAM_CTL("DAC Bass Limiter BiQuad", BIQUAD_SIZE, 0x8c),
+
+	COEFF_RAM_CTL("DAC Bass Cut Off BiQuad", BIQUAD_SIZE, 0x91),
+
+	COEFF_RAM_CTL("DAC Bass Mix", COEFF_SIZE, 0x96),
+
+	COEFF_RAM_CTL("DAC Treb Extraction BiQuad 1", BIQUAD_SIZE, 0x97),
+	COEFF_RAM_CTL("DAC Treb Extraction BiQuad 2", BIQUAD_SIZE, 0x9c),
+
+	COEFF_RAM_CTL("DAC Treb Non Linear Function 1", COEFF_SIZE, 0xa1),
+	COEFF_RAM_CTL("DAC Treb Non Linear Function 2", COEFF_SIZE, 0xa2),
+
+	COEFF_RAM_CTL("DAC Treb Limiter BiQuad", BIQUAD_SIZE, 0xa3),
+
+	COEFF_RAM_CTL("DAC Treb Cut Off BiQuad", BIQUAD_SIZE, 0xa8),
+
+	COEFF_RAM_CTL("DAC Treb Mix", COEFF_SIZE, 0xad),
+
+	COEFF_RAM_CTL("DAC 3D", COEFF_SIZE, 0xae),
+
+	COEFF_RAM_CTL("DAC 3D Mix", COEFF_SIZE, 0xaf),
+
+	COEFF_RAM_CTL("DAC MBC 1 BiQuad 1", BIQUAD_SIZE, 0xb0),
+	COEFF_RAM_CTL("DAC MBC 1 BiQuad 2", BIQUAD_SIZE, 0xb5),
+
+	COEFF_RAM_CTL("DAC MBC 2 BiQuad 1", BIQUAD_SIZE, 0xba),
+	COEFF_RAM_CTL("DAC MBC 2 BiQuad 2", BIQUAD_SIZE, 0xbf),
+
+	COEFF_RAM_CTL("DAC MBC 3 BiQuad 1", BIQUAD_SIZE, 0xc4),
+	COEFF_RAM_CTL("DAC MBC 3 BiQuad 2", BIQUAD_SIZE, 0xc9),
+
+	COEFF_RAM_CTL("Speaker Cascade 1 Left BiQuad 1", BIQUAD_SIZE, 0x00),
+	COEFF_RAM_CTL("Speaker Cascade 1 Left BiQuad 2", BIQUAD_SIZE, 0x05),
+	COEFF_RAM_CTL("Speaker Cascade 1 Left BiQuad 3", BIQUAD_SIZE, 0x0a),
+	COEFF_RAM_CTL("Speaker Cascade 1 Left BiQuad 4", BIQUAD_SIZE, 0x0f),
+	COEFF_RAM_CTL("Speaker Cascade 1 Left BiQuad 5", BIQUAD_SIZE, 0x14),
+	COEFF_RAM_CTL("Speaker Cascade 1 Left BiQuad 6", BIQUAD_SIZE, 0x19),
+
+	COEFF_RAM_CTL("Speaker Cascade 1 Right BiQuad 1", BIQUAD_SIZE, 0x20),
+	COEFF_RAM_CTL("Speaker Cascade 1 Right BiQuad 2", BIQUAD_SIZE, 0x25),
+	COEFF_RAM_CTL("Speaker Cascade 1 Right BiQuad 3", BIQUAD_SIZE, 0x2a),
+	COEFF_RAM_CTL("Speaker Cascade 1 Right BiQuad 4", BIQUAD_SIZE, 0x2f),
+	COEFF_RAM_CTL("Speaker Cascade 1 Right BiQuad 5", BIQUAD_SIZE, 0x34),
+	COEFF_RAM_CTL("Speaker Cascade 1 Right BiQuad 6", BIQUAD_SIZE, 0x39),
+
+	COEFF_RAM_CTL("Speaker Cascade 1 Left Prescale", COEFF_SIZE, 0x1f),
+	COEFF_RAM_CTL("Speaker Cascade 1 Right Prescale", COEFF_SIZE, 0x3f),
+
+	COEFF_RAM_CTL("Speaker Cascade 2 Left BiQuad 1", BIQUAD_SIZE, 0x40),
+	COEFF_RAM_CTL("Speaker Cascade 2 Left BiQuad 2", BIQUAD_SIZE, 0x45),
+	COEFF_RAM_CTL("Speaker Cascade 2 Left BiQuad 3", BIQUAD_SIZE, 0x4a),
+	COEFF_RAM_CTL("Speaker Cascade 2 Left BiQuad 4", BIQUAD_SIZE, 0x4f),
+	COEFF_RAM_CTL("Speaker Cascade 2 Left BiQuad 5", BIQUAD_SIZE, 0x54),
+	COEFF_RAM_CTL("Speaker Cascade 2 Left BiQuad 6", BIQUAD_SIZE, 0x59),
+
+	COEFF_RAM_CTL("Speaker Cascade 2 Right BiQuad 1", BIQUAD_SIZE, 0x60),
+	COEFF_RAM_CTL("Speaker Cascade 2 Right BiQuad 2", BIQUAD_SIZE, 0x65),
+	COEFF_RAM_CTL("Speaker Cascade 2 Right BiQuad 3", BIQUAD_SIZE, 0x6a),
+	COEFF_RAM_CTL("Speaker Cascade 2 Right BiQuad 4", BIQUAD_SIZE, 0x6f),
+	COEFF_RAM_CTL("Speaker Cascade 2 Right BiQuad 5", BIQUAD_SIZE, 0x74),
+	COEFF_RAM_CTL("Speaker Cascade 2 Right BiQuad 6", BIQUAD_SIZE, 0x79),
+
+	COEFF_RAM_CTL("Speaker Cascade 2 Left Prescale", COEFF_SIZE, 0x5f),
+	COEFF_RAM_CTL("Speaker Cascade 2 Right Prescale", COEFF_SIZE, 0x7f),
+
+	COEFF_RAM_CTL("Speaker Bass Extraction BiQuad 1", BIQUAD_SIZE, 0x80),
+	COEFF_RAM_CTL("Speaker Bass Extraction BiQuad 2", BIQUAD_SIZE, 0x85),
+
+	COEFF_RAM_CTL("Speaker Bass Non Linear Function 1", COEFF_SIZE, 0x8a),
+	COEFF_RAM_CTL("Speaker Bass Non Linear Function 2", COEFF_SIZE, 0x8b),
+
+	COEFF_RAM_CTL("Speaker Bass Limiter BiQuad", BIQUAD_SIZE, 0x8c),
+
+	COEFF_RAM_CTL("Speaker Bass Cut Off BiQuad", BIQUAD_SIZE, 0x91),
+
+	COEFF_RAM_CTL("Speaker Bass Mix", COEFF_SIZE, 0x96),
+
+	COEFF_RAM_CTL("Speaker Treb Extraction BiQuad 1", BIQUAD_SIZE, 0x97),
+	COEFF_RAM_CTL("Speaker Treb Extraction BiQuad 2", BIQUAD_SIZE, 0x9c),
+
+	COEFF_RAM_CTL("Speaker Treb Non Linear Function 1", COEFF_SIZE, 0xa1),
+	COEFF_RAM_CTL("Speaker Treb Non Linear Function 2", COEFF_SIZE, 0xa2),
+
+	COEFF_RAM_CTL("Speaker Treb Limiter BiQuad", BIQUAD_SIZE, 0xa3),
+
+	COEFF_RAM_CTL("Speaker Treb Cut Off BiQuad", BIQUAD_SIZE, 0xa8),
+
+	COEFF_RAM_CTL("Speaker Treb Mix", COEFF_SIZE, 0xad),
+
+	COEFF_RAM_CTL("Speaker 3D", COEFF_SIZE, 0xae),
+
+	COEFF_RAM_CTL("Speaker 3D Mix", COEFF_SIZE, 0xaf),
+
+	COEFF_RAM_CTL("Speaker MBC 1 BiQuad 1", BIQUAD_SIZE, 0xb0),
+	COEFF_RAM_CTL("Speaker MBC 1 BiQuad 2", BIQUAD_SIZE, 0xb5),
+
+	COEFF_RAM_CTL("Speaker MBC 2 BiQuad 1", BIQUAD_SIZE, 0xba),
+	COEFF_RAM_CTL("Speaker MBC 2 BiQuad 2", BIQUAD_SIZE, 0xbf),
+
+	COEFF_RAM_CTL("Speaker MBC 3 BiQuad 1", BIQUAD_SIZE, 0xc4),
+	COEFF_RAM_CTL("Speaker MBC 3 BiQuad 2", BIQUAD_SIZE, 0xc9),
+
+	COEFF_RAM_CTL("Sub Cascade 1 Left BiQuad 1", BIQUAD_SIZE, 0x00),
+	COEFF_RAM_CTL("Sub Cascade 1 Left BiQuad 2", BIQUAD_SIZE, 0x05),
+	COEFF_RAM_CTL("Sub Cascade 1 Left BiQuad 3", BIQUAD_SIZE, 0x0a),
+	COEFF_RAM_CTL("Sub Cascade 1 Left BiQuad 4", BIQUAD_SIZE, 0x0f),
+	COEFF_RAM_CTL("Sub Cascade 1 Left BiQuad 5", BIQUAD_SIZE, 0x14),
+	COEFF_RAM_CTL("Sub Cascade 1 Left BiQuad 6", BIQUAD_SIZE, 0x19),
+
+	COEFF_RAM_CTL("Sub Cascade 1 Right BiQuad 1", BIQUAD_SIZE, 0x20),
+	COEFF_RAM_CTL("Sub Cascade 1 Right BiQuad 2", BIQUAD_SIZE, 0x25),
+	COEFF_RAM_CTL("Sub Cascade 1 Right BiQuad 3", BIQUAD_SIZE, 0x2a),
+	COEFF_RAM_CTL("Sub Cascade 1 Right BiQuad 4", BIQUAD_SIZE, 0x2f),
+	COEFF_RAM_CTL("Sub Cascade 1 Right BiQuad 5", BIQUAD_SIZE, 0x34),
+	COEFF_RAM_CTL("Sub Cascade 1 Right BiQuad 6", BIQUAD_SIZE, 0x39),
+
+	COEFF_RAM_CTL("Sub Cascade 1 Left Prescale", COEFF_SIZE, 0x1f),
+	COEFF_RAM_CTL("Sub Cascade 1 Right Prescale", COEFF_SIZE, 0x3f),
+
+	COEFF_RAM_CTL("Sub Cascade 2 Left BiQuad 1", BIQUAD_SIZE, 0x40),
+	COEFF_RAM_CTL("Sub Cascade 2 Left BiQuad 2", BIQUAD_SIZE, 0x45),
+	COEFF_RAM_CTL("Sub Cascade 2 Left BiQuad 3", BIQUAD_SIZE, 0x4a),
+	COEFF_RAM_CTL("Sub Cascade 2 Left BiQuad 4", BIQUAD_SIZE, 0x4f),
+	COEFF_RAM_CTL("Sub Cascade 2 Left BiQuad 5", BIQUAD_SIZE, 0x54),
+	COEFF_RAM_CTL("Sub Cascade 2 Left BiQuad 6", BIQUAD_SIZE, 0x59),
+
+	COEFF_RAM_CTL("Sub Cascade 2 Right BiQuad 1", BIQUAD_SIZE, 0x60),
+	COEFF_RAM_CTL("Sub Cascade 2 Right BiQuad 2", BIQUAD_SIZE, 0x65),
+	COEFF_RAM_CTL("Sub Cascade 2 Right BiQuad 3", BIQUAD_SIZE, 0x6a),
+	COEFF_RAM_CTL("Sub Cascade 2 Right BiQuad 4", BIQUAD_SIZE, 0x6f),
+	COEFF_RAM_CTL("Sub Cascade 2 Right BiQuad 5", BIQUAD_SIZE, 0x74),
+	COEFF_RAM_CTL("Sub Cascade 2 Right BiQuad 6", BIQUAD_SIZE, 0x79),
+
+	COEFF_RAM_CTL("Sub Cascade 2 Left Prescale", COEFF_SIZE, 0x5f),
+	COEFF_RAM_CTL("Sub Cascade 2 Right Prescale", COEFF_SIZE, 0x7f),
+
+	COEFF_RAM_CTL("Sub Bass Extraction BiQuad 1", BIQUAD_SIZE, 0x80),
+	COEFF_RAM_CTL("Sub Bass Extraction BiQuad 2", BIQUAD_SIZE, 0x85),
+
+	COEFF_RAM_CTL("Sub Bass Non Linear Function 1", COEFF_SIZE, 0x8a),
+	COEFF_RAM_CTL("Sub Bass Non Linear Function 2", COEFF_SIZE, 0x8b),
+
+	COEFF_RAM_CTL("Sub Bass Limiter BiQuad", BIQUAD_SIZE, 0x8c),
+
+	COEFF_RAM_CTL("Sub Bass Cut Off BiQuad", BIQUAD_SIZE, 0x91),
+
+	COEFF_RAM_CTL("Sub Bass Mix", COEFF_SIZE, 0x96),
+
+	COEFF_RAM_CTL("Sub Treb Extraction BiQuad 1", BIQUAD_SIZE, 0x97),
+	COEFF_RAM_CTL("Sub Treb Extraction BiQuad 2", BIQUAD_SIZE, 0x9c),
+
+	COEFF_RAM_CTL("Sub Treb Non Linear Function 1", COEFF_SIZE, 0xa1),
+	COEFF_RAM_CTL("Sub Treb Non Linear Function 2", COEFF_SIZE, 0xa2),
+
+	COEFF_RAM_CTL("Sub Treb Limiter BiQuad", BIQUAD_SIZE, 0xa3),
+
+	COEFF_RAM_CTL("Sub Treb Cut Off BiQuad", BIQUAD_SIZE, 0xa8),
+
+	COEFF_RAM_CTL("Sub Treb Mix", COEFF_SIZE, 0xad),
+
+	COEFF_RAM_CTL("Sub 3D", COEFF_SIZE, 0xae),
+
+	COEFF_RAM_CTL("Sub 3D Mix", COEFF_SIZE, 0xaf),
+
+	COEFF_RAM_CTL("Sub MBC 1 BiQuad 1", BIQUAD_SIZE, 0xb0),
+	COEFF_RAM_CTL("Sub MBC 1 BiQuad 2", BIQUAD_SIZE, 0xb5),
+
+	COEFF_RAM_CTL("Sub MBC 2 BiQuad 1", BIQUAD_SIZE, 0xba),
+	COEFF_RAM_CTL("Sub MBC 2 BiQuad 2", BIQUAD_SIZE, 0xbf),
+
+	COEFF_RAM_CTL("Sub MBC 3 BiQuad 1", BIQUAD_SIZE, 0xc4),
+	COEFF_RAM_CTL("Sub MBC 3 BiQuad 2", BIQUAD_SIZE, 0xc9),
+};
+
+static struct snd_soc_dapm_widget const tscs454_dapm_widgets[] = {
+	/* R_PLLCTL PG 0 ADDR 0x15 */
+	SND_SOC_DAPM_SUPPLY("PLL 1 Power", R_PLLCTL, FB_PLLCTL_PU_PLL1, 0,
+			pll_power_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("PLL 2 Power", R_PLLCTL, FB_PLLCTL_PU_PLL2, 0,
+			pll_power_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
+	/* R_I2SPINC0 PG 0 ADDR 0x22 */
+	SND_SOC_DAPM_AIF_OUT("DAI 3 Out", "DAI 3 Capture", 0,
+			R_I2SPINC0, FB_I2SPINC0_SDO3TRI, 1),
+	SND_SOC_DAPM_AIF_OUT("DAI 2 Out", "DAI 2 Capture", 0,
+			R_I2SPINC0, FB_I2SPINC0_SDO2TRI, 1),
+	SND_SOC_DAPM_AIF_OUT("DAI 1 Out", "DAI 1 Capture", 0,
+			R_I2SPINC0, FB_I2SPINC0_SDO1TRI, 1),
+	/* R_PWRM0 PG 0 ADDR 0x33 */
+	SND_SOC_DAPM_ADC("Input Processor Channel 3", NULL,
+			R_PWRM0, FB_PWRM0_INPROC3PU, 0),
+	SND_SOC_DAPM_ADC("Input Processor Channel 2", NULL,
+			R_PWRM0, FB_PWRM0_INPROC2PU, 0),
+	SND_SOC_DAPM_ADC("Input Processor Channel 1", NULL,
+			R_PWRM0, FB_PWRM0_INPROC1PU, 0),
+	SND_SOC_DAPM_ADC("Input Processor Channel 0", NULL,
+			R_PWRM0, FB_PWRM0_INPROC0PU, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Bias 2",
+			R_PWRM0, FB_PWRM0_MICB2PU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Bias 1", R_PWRM0,
+			FB_PWRM0_MICB1PU, 0, NULL, 0),
+	/* R_PWRM1 PG 0 ADDR 0x34 */
+	SND_SOC_DAPM_SUPPLY("Sub Power", R_PWRM1, FB_PWRM1_SUBPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Left Power",
+			R_PWRM1, FB_PWRM1_HPLPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headphone Right Power",
+			R_PWRM1, FB_PWRM1_HPRPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Speaker Left Power",
+			R_PWRM1, FB_PWRM1_SPKLPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Speaker Right Power",
+			R_PWRM1, FB_PWRM1_SPKRPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Differential Input 2 Power",
+			R_PWRM1, FB_PWRM1_D2S2PU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Differential Input 1 Power",
+			R_PWRM1, FB_PWRM1_D2S1PU, 0, NULL, 0),
+	/* R_PWRM2 PG 0 ADDR 0x35 */
+	SND_SOC_DAPM_SUPPLY("DAI 3 Out Power",
+			R_PWRM2, FB_PWRM2_I2S3OPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAI 2 Out Power",
+			R_PWRM2, FB_PWRM2_I2S2OPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAI 1 Out Power",
+			R_PWRM2, FB_PWRM2_I2S1OPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAI 3 In Power",
+			R_PWRM2, FB_PWRM2_I2S3IPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAI 2 In Power",
+			R_PWRM2, FB_PWRM2_I2S2IPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAI 1 In Power",
+			R_PWRM2, FB_PWRM2_I2S1IPU, 0, NULL, 0),
+	/* R_PWRM3 PG 0 ADDR 0x36 */
+	SND_SOC_DAPM_SUPPLY("Line Out Left Power",
+			R_PWRM3, FB_PWRM3_LLINEPU, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Line Out Right Power",
+			R_PWRM3, FB_PWRM3_RLINEPU, 0, NULL, 0),
+	/* R_PWRM4 PG 0 ADDR 0x37 */
+	SND_SOC_DAPM_DAC("Sub", NULL, R_PWRM4, FB_PWRM4_OPSUBPU, 0),
+	SND_SOC_DAPM_DAC("DAC Left", NULL, R_PWRM4, FB_PWRM4_OPDACLPU, 0),
+	SND_SOC_DAPM_DAC("DAC Right", NULL, R_PWRM4, FB_PWRM4_OPDACRPU, 0),
+	SND_SOC_DAPM_DAC("ClassD Left", NULL, R_PWRM4, FB_PWRM4_OPSPKLPU, 0),
+	SND_SOC_DAPM_DAC("ClassD Right", NULL, R_PWRM4, FB_PWRM4_OPSPKRPU, 0),
+	/* R_AUDIOMUX1  PG 0 ADDR 0x3A */
+	SND_SOC_DAPM_MUX("DAI 2 Out Mux", SND_SOC_NOPM, 0, 0,
+			&dai2_mux_dapm_enum),
+	SND_SOC_DAPM_MUX("DAI 1 Out Mux", SND_SOC_NOPM, 0, 0,
+			&dai1_mux_dapm_enum),
+	/* R_AUDIOMUX2 PG 0 ADDR 0x3B */
+	SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0,
+			&dac_mux_dapm_enum),
+	SND_SOC_DAPM_MUX("DAI 3 Out Mux", SND_SOC_NOPM, 0, 0,
+			&dai3_mux_dapm_enum),
+	/* R_AUDIOMUX3 PG 0 ADDR 0x3C */
+	SND_SOC_DAPM_MUX("Sub Mux", SND_SOC_NOPM, 0, 0,
+			&sub_mux_dapm_enum),
+	SND_SOC_DAPM_MUX("Speaker Mux", SND_SOC_NOPM, 0, 0,
+			&classd_mux_dapm_enum),
+	/* R_HSDCTL1 PG 1 ADDR 0x01 */
+	SND_SOC_DAPM_SUPPLY("GHS Detect Power", R_HSDCTL1,
+			FB_HSDCTL1_CON_DET_PWD, 1, NULL, 0),
+	/* R_CH0AIC PG 1 ADDR 0x06 */
+	SND_SOC_DAPM_MUX("Input Boost Channel 0 Mux", SND_SOC_NOPM, 0, 0,
+			&in_bst_mux_ch0_dapm_enum),
+	SND_SOC_DAPM_MUX("ADC Channel 0 Mux", SND_SOC_NOPM, 0, 0,
+			&adc_mux_ch0_dapm_enum),
+	SND_SOC_DAPM_MUX("Input Processor Channel 0 Mux", SND_SOC_NOPM, 0, 0,
+			&in_proc_mux_ch0_dapm_enum),
+	/* R_CH1AIC PG 1 ADDR 0x07 */
+	SND_SOC_DAPM_MUX("Input Boost Channel 1 Mux", SND_SOC_NOPM, 0, 0,
+			&in_bst_mux_ch1_dapm_enum),
+	SND_SOC_DAPM_MUX("ADC Channel 1 Mux", SND_SOC_NOPM, 0, 0,
+			&adc_mux_ch1_dapm_enum),
+	SND_SOC_DAPM_MUX("Input Processor Channel 1 Mux", SND_SOC_NOPM, 0, 0,
+			&in_proc_mux_ch1_dapm_enum),
+	/* Virtual */
+	SND_SOC_DAPM_AIF_IN("DAI 3 In", "DAI 3 Playback", 0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DAI 2 In", "DAI 2 Playback", 0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DAI 1 In", "DAI 1 Playback", 0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_SUPPLY("PLLs", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("Sub Out"),
+	SND_SOC_DAPM_OUTPUT("Headphone Left"),
+	SND_SOC_DAPM_OUTPUT("Headphone Right"),
+	SND_SOC_DAPM_OUTPUT("Speaker Left"),
+	SND_SOC_DAPM_OUTPUT("Speaker Right"),
+	SND_SOC_DAPM_OUTPUT("Line Out Left"),
+	SND_SOC_DAPM_OUTPUT("Line Out Right"),
+	SND_SOC_DAPM_INPUT("D2S 2"),
+	SND_SOC_DAPM_INPUT("D2S 1"),
+	SND_SOC_DAPM_INPUT("Line In 1 Left"),
+	SND_SOC_DAPM_INPUT("Line In 1 Right"),
+	SND_SOC_DAPM_INPUT("Line In 2 Left"),
+	SND_SOC_DAPM_INPUT("Line In 2 Right"),
+	SND_SOC_DAPM_INPUT("Line In 3 Left"),
+	SND_SOC_DAPM_INPUT("Line In 3 Right"),
+	SND_SOC_DAPM_INPUT("DMic 1"),
+	SND_SOC_DAPM_INPUT("DMic 2"),
+
+	SND_SOC_DAPM_MUX("CH 0_1 Mux", SND_SOC_NOPM, 0, 0,
+			&ch_0_1_mux_dapm_enum),
+	SND_SOC_DAPM_MUX("CH 2_3 Mux", SND_SOC_NOPM, 0, 0,
+			&ch_2_3_mux_dapm_enum),
+	SND_SOC_DAPM_MUX("CH 4_5 Mux", SND_SOC_NOPM, 0, 0,
+			&ch_4_5_mux_dapm_enum),
+};
+
+static struct snd_soc_dapm_route const tscs454_intercon[] = {
+	/* PLLs */
+	{"PLLs", NULL, "PLL 1 Power", pll_connected},
+	{"PLLs", NULL, "PLL 2 Power", pll_connected},
+	/* Inputs */
+	{"DAI 3 In", NULL, "DAI 3 In Power"},
+	{"DAI 2 In", NULL, "DAI 2 In Power"},
+	{"DAI 1 In", NULL, "DAI 1 In Power"},
+	/* Outputs */
+	{"DAI 3 Out", NULL, "DAI 3 Out Power"},
+	{"DAI 2 Out", NULL, "DAI 2 Out Power"},
+	{"DAI 1 Out", NULL, "DAI 1 Out Power"},
+	/* Ch Muxing */
+	{"CH 0_1 Mux", "DAI 1", "DAI 1 In"},
+	{"CH 0_1 Mux", "TDM 0_1", "DAI 1 In"},
+	{"CH 2_3 Mux", "DAI 2", "DAI 2 In"},
+	{"CH 2_3 Mux", "TDM 2_3", "DAI 1 In"},
+	{"CH 4_5 Mux", "DAI 3", "DAI 2 In"},
+	{"CH 4_5 Mux", "TDM 4_5", "DAI 1 In"},
+	/* In/Out Muxing */
+	{"DAI 1 Out Mux", "CH 0_1", "CH 0_1 Mux"},
+	{"DAI 1 Out Mux", "CH 2_3", "CH 2_3 Mux"},
+	{"DAI 1 Out Mux", "CH 4_5", "CH 4_5 Mux"},
+	{"DAI 2 Out Mux", "CH 0_1", "CH 0_1 Mux"},
+	{"DAI 2 Out Mux", "CH 2_3", "CH 2_3 Mux"},
+	{"DAI 2 Out Mux", "CH 4_5", "CH 4_5 Mux"},
+	{"DAI 3 Out Mux", "CH 0_1", "CH 0_1 Mux"},
+	{"DAI 3 Out Mux", "CH 2_3", "CH 2_3 Mux"},
+	{"DAI 3 Out Mux", "CH 4_5", "CH 4_5 Mux"},
+	/******************
+	 * Playback Paths *
+	 ******************/
+	/* DAC Path */
+	{"DAC Mux", "CH 4_5", "CH 4_5 Mux"},
+	{"DAC Mux", "CH 2_3", "CH 2_3 Mux"},
+	{"DAC Mux", "CH 0_1", "CH 0_1 Mux"},
+	{"DAC Left", NULL, "DAC Mux"},
+	{"DAC Right", NULL, "DAC Mux"},
+	{"DAC Left", NULL, "PLLs"},
+	{"DAC Right", NULL, "PLLs"},
+	{"Headphone Left", NULL, "Headphone Left Power"},
+	{"Headphone Right", NULL, "Headphone Right Power"},
+	{"Headphone Left", NULL, "DAC Left"},
+	{"Headphone Right", NULL, "DAC Right"},
+	/* Line Out */
+	{"Line Out Left", NULL, "Line Out Left Power"},
+	{"Line Out Right", NULL, "Line Out Right Power"},
+	{"Line Out Left", NULL, "DAC Left"},
+	{"Line Out Right", NULL, "DAC Right"},
+	/* ClassD Path */
+	{"Speaker Mux", "CH 4_5", "CH 4_5 Mux"},
+	{"Speaker Mux", "CH 2_3", "CH 2_3 Mux"},
+	{"Speaker Mux", "CH 0_1", "CH 0_1 Mux"},
+	{"ClassD Left", NULL, "Speaker Mux"},
+	{"ClassD Right", NULL, "Speaker Mux"},
+	{"ClassD Left", NULL, "PLLs"},
+	{"ClassD Right", NULL, "PLLs"},
+	{"Speaker Left", NULL, "Speaker Left Power"},
+	{"Speaker Right", NULL, "Speaker Right Power"},
+	{"Speaker Left", NULL, "ClassD Left"},
+	{"Speaker Right", NULL, "ClassD Right"},
+	/* Sub Path */
+	{"Sub Mux", "CH 4", "CH 4_5 Mux"},
+	{"Sub Mux", "CH 5", "CH 4_5 Mux"},
+	{"Sub Mux", "CH 4 + 5", "CH 4_5 Mux"},
+	{"Sub Mux", "CH 2", "CH 2_3 Mux"},
+	{"Sub Mux", "CH 3", "CH 2_3 Mux"},
+	{"Sub Mux", "CH 2 + 3", "CH 2_3 Mux"},
+	{"Sub Mux", "CH 0", "CH 0_1 Mux"},
+	{"Sub Mux", "CH 1", "CH 0_1 Mux"},
+	{"Sub Mux", "CH 0 + 1", "CH 0_1 Mux"},
+	{"Sub Mux", "ADC/DMic 1 Left", "Input Processor Channel 0"},
+	{"Sub Mux", "ADC/DMic 1 Right", "Input Processor Channel 1"},
+	{"Sub Mux", "ADC/DMic 1 Left Plus Right", "Input Processor Channel 0"},
+	{"Sub Mux", "ADC/DMic 1 Left Plus Right", "Input Processor Channel 1"},
+	{"Sub Mux", "DMic 2 Left", "DMic 2"},
+	{"Sub Mux", "DMic 2 Right", "DMic 2"},
+	{"Sub Mux", "DMic 2 Left Plus Right", "DMic 2"},
+	{"Sub Mux", "ClassD Left", "ClassD Left"},
+	{"Sub Mux", "ClassD Right", "ClassD Right"},
+	{"Sub Mux", "ClassD Left Plus Right", "ClassD Left"},
+	{"Sub Mux", "ClassD Left Plus Right", "ClassD Right"},
+	{"Sub", NULL, "Sub Mux"},
+	{"Sub", NULL, "PLLs"},
+	{"Sub Out", NULL, "Sub Power"},
+	{"Sub Out", NULL, "Sub"},
+	/*****************
+	 * Capture Paths *
+	 *****************/
+	{"Input Boost Channel 0 Mux", "Input 3", "Line In 3 Left"},
+	{"Input Boost Channel 0 Mux", "Input 2", "Line In 2 Left"},
+	{"Input Boost Channel 0 Mux", "Input 1", "Line In 1 Left"},
+	{"Input Boost Channel 0 Mux", "D2S", "D2S 1"},
+
+	{"Input Boost Channel 1 Mux", "Input 3", "Line In 3 Right"},
+	{"Input Boost Channel 1 Mux", "Input 2", "Line In 2 Right"},
+	{"Input Boost Channel 1 Mux", "Input 1", "Line In 1 Right"},
+	{"Input Boost Channel 1 Mux", "D2S", "D2S 2"},
+
+	{"ADC Channel 0 Mux", "Input 3 Boost Bypass", "Line In 3 Left"},
+	{"ADC Channel 0 Mux", "Input 2 Boost Bypass", "Line In 2 Left"},
+	{"ADC Channel 0 Mux", "Input 1 Boost Bypass", "Line In 1 Left"},
+	{"ADC Channel 0 Mux", "Input Boost", "Input Boost Channel 0 Mux"},
+
+	{"ADC Channel 1 Mux", "Input 3 Boost Bypass", "Line In 3 Right"},
+	{"ADC Channel 1 Mux", "Input 2 Boost Bypass", "Line In 2 Right"},
+	{"ADC Channel 1 Mux", "Input 1 Boost Bypass", "Line In 1 Right"},
+	{"ADC Channel 1 Mux", "Input Boost", "Input Boost Channel 1 Mux"},
+
+	{"Input Processor Channel 0 Mux", "ADC", "ADC Channel 0 Mux"},
+	{"Input Processor Channel 0 Mux", "DMic", "DMic 1"},
+
+	{"Input Processor Channel 0", NULL, "PLLs"},
+	{"Input Processor Channel 0", NULL, "Input Processor Channel 0 Mux"},
+
+	{"Input Processor Channel 1 Mux", "ADC", "ADC Channel 1 Mux"},
+	{"Input Processor Channel 1 Mux", "DMic", "DMic 1"},
+
+	{"Input Processor Channel 1", NULL, "PLLs"},
+	{"Input Processor Channel 1", NULL, "Input Processor Channel 1 Mux"},
+
+	{"Input Processor Channel 2", NULL, "PLLs"},
+	{"Input Processor Channel 2", NULL, "DMic 2"},
+
+	{"Input Processor Channel 3", NULL, "PLLs"},
+	{"Input Processor Channel 3", NULL, "DMic 2"},
+
+	{"DAI 1 Out Mux", "ADC/DMic 1", "Input Processor Channel 0"},
+	{"DAI 1 Out Mux", "ADC/DMic 1", "Input Processor Channel 1"},
+	{"DAI 1 Out Mux", "DMic 2", "Input Processor Channel 2"},
+	{"DAI 1 Out Mux", "DMic 2", "Input Processor Channel 3"},
+
+	{"DAI 2 Out Mux", "ADC/DMic 1", "Input Processor Channel 0"},
+	{"DAI 2 Out Mux", "ADC/DMic 1", "Input Processor Channel 1"},
+	{"DAI 2 Out Mux", "DMic 2", "Input Processor Channel 2"},
+	{"DAI 2 Out Mux", "DMic 2", "Input Processor Channel 3"},
+
+	{"DAI 3 Out Mux", "ADC/DMic 1", "Input Processor Channel 0"},
+	{"DAI 3 Out Mux", "ADC/DMic 1", "Input Processor Channel 1"},
+	{"DAI 3 Out Mux", "DMic 2", "Input Processor Channel 2"},
+	{"DAI 3 Out Mux", "DMic 2", "Input Processor Channel 3"},
+
+	{"DAI 1 Out", NULL, "DAI 1 Out Mux"},
+	{"DAI 2 Out", NULL, "DAI 2 Out Mux"},
+	{"DAI 3 Out", NULL, "DAI 3 Out Mux"},
+};
+
+/* This is used when BCLK is sourcing the PLLs */
+static int tscs454_set_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+	int bclk_dai;
+	int ret;
+
+	dev_dbg(component->dev, "%s(): freq = %u\n", __func__, freq);
+
+	ret = snd_soc_component_read(component, R_PLLCTL, &val);
+	if (ret < 0)
+		return ret;
+
+	bclk_dai = (val & FM_PLLCTL_BCLKSEL) >> FB_PLLCTL_BCLKSEL;
+	if (bclk_dai != dai->id)
+		return 0;
+
+	tscs454->bclk_freq = freq;
+	return set_sysclk(component);
+}
+
+static int tscs454_set_bclk_ratio(struct snd_soc_dai *dai,
+		unsigned int ratio)
+{
+	unsigned int mask;
+	int ret;
+	struct snd_soc_component *component = dai->component;
+	unsigned int val;
+	int shift;
+
+	dev_dbg(component->dev, "set_bclk_ratio() id = %d ratio = %u\n",
+			dai->id, ratio);
+
+	switch (dai->id) {
+	case TSCS454_DAI1_ID:
+		mask = FM_I2SCMC_BCMP1;
+		shift = FB_I2SCMC_BCMP1;
+		break;
+	case TSCS454_DAI2_ID:
+		mask = FM_I2SCMC_BCMP2;
+		shift = FB_I2SCMC_BCMP2;
+		break;
+	case TSCS454_DAI3_ID:
+		mask = FM_I2SCMC_BCMP3;
+		shift = FB_I2SCMC_BCMP3;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Unknown audio interface (%d)\n", ret);
+		return ret;
+	}
+
+	switch (ratio) {
+	case 32:
+		val = I2SCMC_BCMP_32X;
+		break;
+	case 40:
+		val = I2SCMC_BCMP_40X;
+		break;
+	case 64:
+		val = I2SCMC_BCMP_64X;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Unsupported bclk ratio (%d)\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_update_bits(component,
+			R_I2SCMC, mask, val << shift);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to set DAI BCLK ratio (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int set_aif_master_from_fmt(struct snd_soc_component *component,
+		struct aif *aif, unsigned int fmt)
+{
+	int ret;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif->master = true;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		aif->master = false;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Unsupported format (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int set_aif_tdm_delay(struct snd_soc_component *component,
+		unsigned int dai_id, bool delay)
+{
+	unsigned int reg;
+	int ret;
+
+	switch (dai_id) {
+	case TSCS454_DAI1_ID:
+		reg = R_TDMCTL0;
+		break;
+	case TSCS454_DAI2_ID:
+		reg = R_PCMP2CTL0;
+		break;
+	case TSCS454_DAI3_ID:
+		reg = R_PCMP3CTL0;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev,
+				"DAI %d unknown (%d)\n", dai_id + 1, ret);
+		return ret;
+	}
+	ret = snd_soc_component_update_bits(component,
+			reg, FM_TDMCTL0_BDELAY, delay);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to setup tdm format (%d)\n",
+				ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int set_aif_format_from_fmt(struct snd_soc_component *component,
+		unsigned int dai_id, unsigned int fmt)
+{
+	unsigned int reg;
+	unsigned int val;
+	int ret;
+
+	switch (dai_id) {
+	case TSCS454_DAI1_ID:
+		reg = R_I2SP1CTL;
+		break;
+	case TSCS454_DAI2_ID:
+		reg = R_I2SP2CTL;
+		break;
+	case TSCS454_DAI3_ID:
+		reg = R_I2SP3CTL;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev,
+				"DAI %d unknown (%d)\n", dai_id + 1, ret);
+		return ret;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val = FV_FORMAT_RIGHT;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val = FV_FORMAT_LEFT;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		val = FV_FORMAT_I2S;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		ret = set_aif_tdm_delay(component, dai_id, true);
+		if (ret < 0)
+			return ret;
+		val = FV_FORMAT_TDM;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		ret = set_aif_tdm_delay(component, dai_id, false);
+		if (ret < 0)
+			return ret;
+		val = FV_FORMAT_TDM;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Format unsupported (%d)\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_update_bits(component,
+			reg, FM_I2SPCTL_FORMAT, val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set DAI %d format (%d)\n",
+				dai_id + 1, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int
+set_aif_clock_format_from_fmt(struct snd_soc_component *component,
+		unsigned int dai_id, unsigned int fmt)
+{
+	unsigned int reg;
+	unsigned int val;
+	int ret;
+
+	switch (dai_id) {
+	case TSCS454_DAI1_ID:
+		reg = R_I2SP1CTL;
+		break;
+	case TSCS454_DAI2_ID:
+		reg = R_I2SP2CTL;
+		break;
+	case TSCS454_DAI3_ID:
+		reg = R_I2SP3CTL;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev,
+				"DAI %d unknown (%d)\n", dai_id + 1, ret);
+		return ret;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		val = FV_BCLKP_NOT_INVERTED | FV_LRCLKP_NOT_INVERTED;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		val = FV_BCLKP_NOT_INVERTED | FV_LRCLKP_INVERTED;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		val = FV_BCLKP_INVERTED | FV_LRCLKP_NOT_INVERTED;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		val = FV_BCLKP_INVERTED | FV_LRCLKP_INVERTED;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Format unknown (%d)\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_update_bits(component, reg,
+			FM_I2SPCTL_BCLKP | FM_I2SPCTL_LRCLKP, val);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to set clock polarity for DAI%d (%d)\n",
+				dai_id + 1, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tscs454_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	struct aif *aif = &tscs454->aifs[dai->id];
+	int ret;
+
+	ret = set_aif_master_from_fmt(component, aif, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = set_aif_format_from_fmt(component, dai->id, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = set_aif_clock_format_from_fmt(component, dai->id, fmt);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int tscs454_dai1_set_tdm_slot(struct snd_soc_dai *dai,
+		unsigned int tx_mask, unsigned int rx_mask, int slots,
+		int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int val;
+	int ret;
+
+	if (!slots)
+		return 0;
+
+	if (tx_mask >= (1 << slots) || rx_mask >= (1 << slots)) {
+		ret = -EINVAL;
+		dev_err(component->dev, "Invalid TDM slot mask (%d)\n", ret);
+		return ret;
+	}
+
+	switch (slots) {
+	case 2:
+		val = FV_TDMSO_2 | FV_TDMSI_2;
+		break;
+	case 4:
+		val = FV_TDMSO_4 | FV_TDMSI_4;
+		break;
+	case 6:
+		val = FV_TDMSO_6 | FV_TDMSI_6;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Invalid number of slots (%d)\n", ret);
+		return ret;
+	}
+
+	switch (slot_width) {
+	case 16:
+		val = val | FV_TDMDSS_16;
+		break;
+	case 24:
+		val = val | FV_TDMDSS_24;
+		break;
+	case 32:
+		val = val | FV_TDMDSS_32;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Invalid TDM slot width (%d)\n", ret);
+		return ret;
+	}
+	ret = snd_soc_component_write(component, R_TDMCTL1, val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set slots (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tscs454_dai23_set_tdm_slot(struct snd_soc_dai *dai,
+		unsigned int tx_mask, unsigned int rx_mask, int slots,
+		int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int reg;
+	unsigned int val;
+	int ret;
+
+	if (!slots)
+		return 0;
+
+	if (tx_mask >= (1 << slots) || rx_mask >= (1 << slots)) {
+		ret = -EINVAL;
+		dev_err(component->dev, "Invalid TDM slot mask (%d)\n", ret);
+		return ret;
+	}
+
+	switch (dai->id) {
+	case TSCS454_DAI2_ID:
+		reg = R_PCMP2CTL1;
+		break;
+	case TSCS454_DAI3_ID:
+		reg = R_PCMP3CTL1;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Unrecognized interface %d (%d)\n",
+				dai->id, ret);
+		return ret;
+	}
+
+	switch (slots) {
+	case 1:
+		val = FV_PCMSOP_1 | FV_PCMSIP_1;
+		break;
+	case 2:
+		val = FV_PCMSOP_2 | FV_PCMSIP_2;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Invalid number of slots (%d)\n", ret);
+		return ret;
+	}
+
+	switch (slot_width) {
+	case 16:
+		val = val | FV_PCMDSSP_16;
+		break;
+	case 24:
+		val = val | FV_PCMDSSP_24;
+		break;
+	case 32:
+		val = val | FV_PCMDSSP_32;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Invalid TDM slot width (%d)\n", ret);
+		return ret;
+	}
+	ret = snd_soc_component_write(component, reg, val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set slots (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int set_aif_fs(struct snd_soc_component *component,
+		unsigned int id,
+		unsigned int rate)
+{
+	unsigned int reg;
+	unsigned int br;
+	unsigned int bm;
+	int ret;
+
+	switch (rate) {
+	case 8000:
+		br = FV_I2SMBR_32;
+		bm = FV_I2SMBM_0PT25;
+		break;
+	case 16000:
+		br = FV_I2SMBR_32;
+		bm = FV_I2SMBM_0PT5;
+		break;
+	case 24000:
+		br = FV_I2SMBR_48;
+		bm = FV_I2SMBM_0PT5;
+		break;
+	case 32000:
+		br = FV_I2SMBR_32;
+		bm = FV_I2SMBM_1;
+		break;
+	case 48000:
+		br = FV_I2SMBR_48;
+		bm = FV_I2SMBM_1;
+		break;
+	case 96000:
+		br = FV_I2SMBR_48;
+		bm = FV_I2SMBM_2;
+		break;
+	case 11025:
+		br = FV_I2SMBR_44PT1;
+		bm = FV_I2SMBM_0PT25;
+		break;
+	case 22050:
+		br = FV_I2SMBR_44PT1;
+		bm = FV_I2SMBM_0PT5;
+		break;
+	case 44100:
+		br = FV_I2SMBR_44PT1;
+		bm = FV_I2SMBM_1;
+		break;
+	case 88200:
+		br = FV_I2SMBR_44PT1;
+		bm = FV_I2SMBM_2;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Unsupported sample rate (%d)\n", ret);
+		return ret;
+	}
+
+	switch (id) {
+	case TSCS454_DAI1_ID:
+		reg = R_I2S1MRATE;
+		break;
+	case TSCS454_DAI2_ID:
+		reg = R_I2S2MRATE;
+		break;
+	case TSCS454_DAI3_ID:
+		reg = R_I2S3MRATE;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "DAI ID not recognized (%d)\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_update_bits(component, reg,
+			FM_I2SMRATE_I2SMBR | FM_I2SMRATE_I2SMBM, br|bm);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to update register (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int set_aif_sample_format(struct snd_soc_component *component,
+		snd_pcm_format_t format,
+		int aif_id)
+{
+	unsigned int reg;
+	unsigned int width;
+	int ret;
+
+	switch (format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		width = FV_WL_16;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		width = FV_WL_20;
+		break;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		width = FV_WL_24;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+	case SNDRV_PCM_FORMAT_S32_LE:
+		width = FV_WL_32;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Unsupported format width (%d)\n", ret);
+		return ret;
+	}
+
+	switch (aif_id) {
+	case TSCS454_DAI1_ID:
+		reg = R_I2SP1CTL;
+		break;
+	case TSCS454_DAI2_ID:
+		reg = R_I2SP2CTL;
+		break;
+	case TSCS454_DAI3_ID:
+		reg = R_I2SP3CTL;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "AIF ID not recognized (%d)\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_update_bits(component,
+			reg, FM_I2SPCTL_WL, width);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to set sample width (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tscs454_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	unsigned int fs = params_rate(params);
+	struct aif *aif = &tscs454->aifs[dai->id];
+	unsigned int val;
+	int ret;
+
+	mutex_lock(&tscs454->aifs_status_lock);
+
+	dev_dbg(component->dev, "%s(): aif %d fs = %u\n", __func__,
+			aif->id, fs);
+
+	if (!aif_active(&tscs454->aifs_status, aif->id)) {
+		if (PLL_44_1K_RATE % fs)
+			aif->pll = &tscs454->pll1;
+		else
+			aif->pll = &tscs454->pll2;
+
+		dev_dbg(component->dev, "Reserving pll %d for aif %d\n",
+				aif->pll->id, aif->id);
+
+		reserve_pll(aif->pll);
+	}
+
+	if (!aifs_active(&tscs454->aifs_status)) { /* First active aif */
+		ret = snd_soc_component_read(component, R_ISRC, &val);
+		if (ret < 0)
+			goto exit;
+
+		if ((val & FM_ISRC_IBR) == FV_IBR_48)
+			tscs454->internal_rate.pll = &tscs454->pll1;
+		else
+			tscs454->internal_rate.pll = &tscs454->pll2;
+
+		dev_dbg(component->dev, "Reserving pll %d for ir\n",
+				tscs454->internal_rate.pll->id);
+
+		reserve_pll(tscs454->internal_rate.pll);
+	}
+
+	ret = set_aif_fs(component, aif->id, fs);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set aif fs (%d)\n", ret);
+		goto exit;
+	}
+
+	ret = set_aif_sample_format(component, params_format(params), aif->id);
+	if (ret < 0) {
+		dev_err(component->dev,
+				"Failed to set aif sample format (%d)\n", ret);
+		goto exit;
+	}
+
+	set_aif_status_active(&tscs454->aifs_status, aif->id,
+			substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+
+	dev_dbg(component->dev, "Set aif %d active. Streams status is 0x%x\n",
+		aif->id, tscs454->aifs_status.streams);
+
+	ret = 0;
+exit:
+	mutex_unlock(&tscs454->aifs_status_lock);
+
+	return ret;
+}
+
+static int tscs454_hw_free(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	struct aif *aif = &tscs454->aifs[dai->id];
+
+	return aif_free(component, aif,
+			substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+}
+
+static int tscs454_prepare(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	int ret;
+	struct snd_soc_component *component = dai->component;
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	struct aif *aif = &tscs454->aifs[dai->id];
+
+	ret = aif_prepare(component, aif);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops const tscs454_dai1_ops = {
+	.set_sysclk	= tscs454_set_sysclk,
+	.set_bclk_ratio = tscs454_set_bclk_ratio,
+	.set_fmt	= tscs454_set_dai_fmt,
+	.set_tdm_slot	= tscs454_dai1_set_tdm_slot,
+	.hw_params	= tscs454_hw_params,
+	.hw_free	= tscs454_hw_free,
+	.prepare	= tscs454_prepare,
+};
+
+static struct snd_soc_dai_ops const tscs454_dai23_ops = {
+	.set_sysclk	= tscs454_set_sysclk,
+	.set_bclk_ratio = tscs454_set_bclk_ratio,
+	.set_fmt	= tscs454_set_dai_fmt,
+	.set_tdm_slot	= tscs454_dai23_set_tdm_slot,
+	.hw_params	= tscs454_hw_params,
+	.hw_free	= tscs454_hw_free,
+	.prepare	= tscs454_prepare,
+};
+
+static int tscs454_probe(struct snd_soc_component *component)
+{
+	struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+	int ret = 0;
+
+	switch (tscs454->sysclk_src_id) {
+	case PLL_INPUT_XTAL:
+		val = FV_PLLISEL_XTAL;
+		break;
+	case PLL_INPUT_MCLK1:
+		val = FV_PLLISEL_MCLK1;
+		break;
+	case PLL_INPUT_MCLK2:
+		val = FV_PLLISEL_MCLK2;
+		break;
+	case PLL_INPUT_BCLK:
+		val = FV_PLLISEL_BCLK;
+		break;
+	default:
+		ret = -EINVAL;
+		dev_err(component->dev, "Invalid sysclk src id (%d)\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_component_update_bits(component, R_PLLCTL,
+			FM_PLLCTL_PLLISEL, val);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to set PLL input (%d)\n", ret);
+		return ret;
+	}
+
+	if (tscs454->sysclk_src_id < PLL_INPUT_BCLK)
+		ret = set_sysclk(component);
+
+	return ret;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_tscs454 = {
+	.probe =	tscs454_probe,
+	.dapm_widgets = tscs454_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tscs454_dapm_widgets),
+	.dapm_routes = tscs454_intercon,
+	.num_dapm_routes = ARRAY_SIZE(tscs454_intercon),
+	.controls =	tscs454_snd_controls,
+	.num_controls = ARRAY_SIZE(tscs454_snd_controls),
+};
+
+#define TSCS454_RATES SNDRV_PCM_RATE_8000_96000
+
+#define TSCS454_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+	| SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE \
+	| SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver tscs454_dais[] = {
+	{
+		.name = "tscs454-dai1",
+		.id = TSCS454_DAI1_ID,
+		.playback = {
+			.stream_name = "DAI 1 Playback",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = TSCS454_RATES,
+			.formats = TSCS454_FORMATS,},
+		.capture = {
+			.stream_name = "DAI 1 Capture",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = TSCS454_RATES,
+			.formats = TSCS454_FORMATS,},
+		.ops = &tscs454_dai1_ops,
+		.symmetric_rates = 1,
+		.symmetric_channels = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "tscs454-dai2",
+		.id = TSCS454_DAI2_ID,
+		.playback = {
+			.stream_name = "DAI 2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = TSCS454_RATES,
+			.formats = TSCS454_FORMATS,},
+		.capture = {
+			.stream_name = "DAI 2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = TSCS454_RATES,
+			.formats = TSCS454_FORMATS,},
+		.ops = &tscs454_dai23_ops,
+		.symmetric_rates = 1,
+		.symmetric_channels = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "tscs454-dai3",
+		.id = TSCS454_DAI3_ID,
+		.playback = {
+			.stream_name = "DAI 3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = TSCS454_RATES,
+			.formats = TSCS454_FORMATS,},
+		.capture = {
+			.stream_name = "DAI 3 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = TSCS454_RATES,
+			.formats = TSCS454_FORMATS,},
+		.ops = &tscs454_dai23_ops,
+		.symmetric_rates = 1,
+		.symmetric_channels = 1,
+		.symmetric_samplebits = 1,
+	},
+};
+
+static char const * const src_names[] = {
+	"xtal", "mclk1", "mclk2", "bclk"};
+
+static int tscs454_i2c_probe(struct i2c_client *i2c,
+		const struct i2c_device_id *id)
+{
+	struct tscs454 *tscs454;
+	int src;
+	int ret;
+
+	tscs454 = devm_kzalloc(&i2c->dev, sizeof(*tscs454), GFP_KERNEL);
+	if (!tscs454)
+		return -ENOMEM;
+
+	ret = tscs454_data_init(tscs454, i2c);
+	if (ret < 0)
+		return ret;
+
+	i2c_set_clientdata(i2c, tscs454);
+
+	for (src = PLL_INPUT_XTAL; src < PLL_INPUT_BCLK; src++) {
+		tscs454->sysclk = devm_clk_get(&i2c->dev, src_names[src]);
+		if (!IS_ERR(tscs454->sysclk)) {
+			break;
+		} else if (PTR_ERR(tscs454->sysclk) != -ENOENT) {
+			ret = PTR_ERR(tscs454->sysclk);
+			dev_err(&i2c->dev, "Failed to get sysclk (%d)\n", ret);
+			return ret;
+		}
+	}
+	dev_dbg(&i2c->dev, "PLL input is %s\n", src_names[src]);
+	tscs454->sysclk_src_id = src;
+
+	ret = regmap_write(tscs454->regmap,
+			R_RESET, FV_RESET_PWR_ON_DEFAULTS);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to reset the component (%d)\n", ret);
+		return ret;
+	}
+	regcache_mark_dirty(tscs454->regmap);
+
+	ret = regmap_register_patch(tscs454->regmap, tscs454_patch,
+			ARRAY_SIZE(tscs454_patch));
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to apply patch (%d)\n", ret);
+		return ret;
+	}
+	/* Sync pg sel reg with cache */
+	regmap_write(tscs454->regmap, R_PAGESEL, 0x00);
+
+	ret = snd_soc_register_component(&i2c->dev, &soc_component_dev_tscs454,
+			tscs454_dais, ARRAY_SIZE(tscs454_dais));
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to register component (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct i2c_device_id tscs454_i2c_id[] = {
+	{ "tscs454", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tscs454_i2c_id);
+
+static const struct of_device_id tscs454_of_match[] = {
+	{ .compatible = "tempo,tscs454", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tscs454_of_match);
+
+static struct i2c_driver tscs454_i2c_driver = {
+	.driver = {
+		.name = "tscs454",
+		.of_match_table = tscs454_of_match,
+	},
+	.probe =    tscs454_i2c_probe,
+	.id_table = tscs454_i2c_id,
+};
+
+module_i2c_driver(tscs454_i2c_driver);
+
+MODULE_AUTHOR("Tempo Semiconductor <steven.eckhoff.opensource@gmail.com");
+MODULE_DESCRIPTION("ASoC TSCS454 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/tscs454.h b/sound/soc/codecs/tscs454.h
new file mode 100644
index 0000000..1142d73
--- /dev/null
+++ b/sound/soc/codecs/tscs454.h
@@ -0,0 +1,2323 @@
+// SPDX-License-Identifier: GPL-2.0
+// tscs454.h -- TSCS454 ALSA SoC Audio driver
+// Copyright 2018 Tempo Semiconductor, Inc.
+// Author: Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
+
+#ifndef __REDWOODPUBLIC_H__
+#define __REDWOODPUBLIC_H__
+
+#define VIRT_BASE 0x00
+#define PAGE_LEN 0x100
+#define VIRT_PAGE_BASE(page) (VIRT_BASE + (PAGE_LEN * page))
+#define VIRT_ADDR(page, address) (VIRT_PAGE_BASE(page) + address)
+#define ADDR(page, virt_address) (virt_address - VIRT_PAGE_BASE(page))
+
+#define R_PAGESEL                       0x0
+#define R_RESET                         VIRT_ADDR(0x0, 0x1)
+#define R_IRQEN                         VIRT_ADDR(0x0, 0x2)
+#define R_IRQMASK                       VIRT_ADDR(0x0, 0x3)
+#define R_IRQSTAT                       VIRT_ADDR(0x0, 0x4)
+#define R_DEVADD0                       VIRT_ADDR(0x0, 0x6)
+#define R_DEVID                         VIRT_ADDR(0x0, 0x8)
+#define R_DEVREV                        VIRT_ADDR(0x0, 0x9)
+#define R_PLLSTAT                       VIRT_ADDR(0x0, 0x0A)
+#define R_PLL1CTL                       VIRT_ADDR(0x0, 0x0B)
+#define R_PLL1RDIV                      VIRT_ADDR(0x0, 0x0C)
+#define R_PLL1ODIV                      VIRT_ADDR(0x0, 0x0D)
+#define R_PLL1FDIVL                     VIRT_ADDR(0x0, 0x0E)
+#define R_PLL1FDIVH                     VIRT_ADDR(0x0, 0x0F)
+#define R_PLL2CTL                       VIRT_ADDR(0x0, 0x10)
+#define R_PLL2RDIV                      VIRT_ADDR(0x0, 0x11)
+#define R_PLL2ODIV                      VIRT_ADDR(0x0, 0x12)
+#define R_PLL2FDIVL                     VIRT_ADDR(0x0, 0x13)
+#define R_PLL2FDIVH                     VIRT_ADDR(0x0, 0x14)
+#define R_PLLCTL                        VIRT_ADDR(0x0, 0x15)
+#define R_ISRC                          VIRT_ADDR(0x0, 0x16)
+#define R_SCLKCTL                       VIRT_ADDR(0x0, 0x18)
+#define R_TIMEBASE                      VIRT_ADDR(0x0, 0x19)
+#define R_I2SP1CTL                      VIRT_ADDR(0x0, 0x1A)
+#define R_I2SP2CTL                      VIRT_ADDR(0x0, 0x1B)
+#define R_I2SP3CTL                      VIRT_ADDR(0x0, 0x1C)
+#define R_I2S1MRATE                     VIRT_ADDR(0x0, 0x1D)
+#define R_I2S2MRATE                     VIRT_ADDR(0x0, 0x1E)
+#define R_I2S3MRATE                     VIRT_ADDR(0x0, 0x1F)
+#define R_I2SCMC                        VIRT_ADDR(0x0, 0x20)
+#define R_MCLK2PINC                     VIRT_ADDR(0x0, 0x21)
+#define R_I2SPINC0                      VIRT_ADDR(0x0, 0x22)
+#define R_I2SPINC1                      VIRT_ADDR(0x0, 0x23)
+#define R_I2SPINC2                      VIRT_ADDR(0x0, 0x24)
+#define R_GPIOCTL0                      VIRT_ADDR(0x0, 0x25)
+#define R_GPIOCTL1                      VIRT_ADDR(0x0, 0x26)
+#define R_ASRC                          VIRT_ADDR(0x0, 0x28)
+#define R_TDMCTL0                       VIRT_ADDR(0x0, 0x2D)
+#define R_TDMCTL1                       VIRT_ADDR(0x0, 0x2E)
+#define R_PCMP2CTL0                     VIRT_ADDR(0x0, 0x2F)
+#define R_PCMP2CTL1                     VIRT_ADDR(0x0, 0x30)
+#define R_PCMP3CTL0                     VIRT_ADDR(0x0, 0x31)
+#define R_PCMP3CTL1                     VIRT_ADDR(0x0, 0x32)
+#define R_PWRM0                         VIRT_ADDR(0x0, 0x33)
+#define R_PWRM1                         VIRT_ADDR(0x0, 0x34)
+#define R_PWRM2                         VIRT_ADDR(0x0, 0x35)
+#define R_PWRM3                         VIRT_ADDR(0x0, 0x36)
+#define R_PWRM4                         VIRT_ADDR(0x0, 0x37)
+#define R_I2SIDCTL                      VIRT_ADDR(0x0, 0x38)
+#define R_I2SODCTL                      VIRT_ADDR(0x0, 0x39)
+#define R_AUDIOMUX1                     VIRT_ADDR(0x0, 0x3A)
+#define R_AUDIOMUX2                     VIRT_ADDR(0x0, 0x3B)
+#define R_AUDIOMUX3                     VIRT_ADDR(0x0, 0x3C)
+#define R_HSDCTL1                       VIRT_ADDR(0x1, 0x1)
+#define R_HSDCTL2                       VIRT_ADDR(0x1, 0x2)
+#define R_HSDSTAT                       VIRT_ADDR(0x1, 0x3)
+#define R_HSDDELAY                      VIRT_ADDR(0x1, 0x4)
+#define R_BUTCTL                        VIRT_ADDR(0x1, 0x5)
+#define R_CH0AIC                        VIRT_ADDR(0x1, 0x6)
+#define R_CH1AIC                        VIRT_ADDR(0x1, 0x7)
+#define R_CH2AIC                        VIRT_ADDR(0x1, 0x8)
+#define R_CH3AIC                        VIRT_ADDR(0x1, 0x9)
+#define R_ICTL0                         VIRT_ADDR(0x1, 0x0A)
+#define R_ICTL1                         VIRT_ADDR(0x1, 0x0B)
+#define R_MICBIAS                       VIRT_ADDR(0x1, 0x0C)
+#define R_PGACTL0                       VIRT_ADDR(0x1, 0x0D)
+#define R_PGACTL1                       VIRT_ADDR(0x1, 0x0E)
+#define R_PGACTL2                       VIRT_ADDR(0x1, 0x0F)
+#define R_PGACTL3                       VIRT_ADDR(0x1, 0x10)
+#define R_PGAZ                          VIRT_ADDR(0x1, 0x11)
+#define R_ICH0VOL                       VIRT_ADDR(0x1, 0x12)
+#define R_ICH1VOL                       VIRT_ADDR(0x1, 0x13)
+#define R_ICH2VOL                       VIRT_ADDR(0x1, 0x14)
+#define R_ICH3VOL                       VIRT_ADDR(0x1, 0x15)
+#define R_ASRCILVOL                     VIRT_ADDR(0x1, 0x16)
+#define R_ASRCIRVOL                     VIRT_ADDR(0x1, 0x17)
+#define R_ASRCOLVOL                     VIRT_ADDR(0x1, 0x18)
+#define R_ASRCORVOL                     VIRT_ADDR(0x1, 0x19)
+#define R_IVOLCTLU                      VIRT_ADDR(0x1, 0x1C)
+#define R_ALCCTL0                       VIRT_ADDR(0x1, 0x1D)
+#define R_ALCCTL1                       VIRT_ADDR(0x1, 0x1E)
+#define R_ALCCTL2                       VIRT_ADDR(0x1, 0x1F)
+#define R_ALCCTL3                       VIRT_ADDR(0x1, 0x20)
+#define R_NGATE                         VIRT_ADDR(0x1, 0x21)
+#define R_DMICCTL                       VIRT_ADDR(0x1, 0x22)
+#define R_DACCTL                        VIRT_ADDR(0x2, 0x1)
+#define R_SPKCTL                        VIRT_ADDR(0x2, 0x2)
+#define R_SUBCTL                        VIRT_ADDR(0x2, 0x3)
+#define R_DCCTL                         VIRT_ADDR(0x2, 0x4)
+#define R_OVOLCTLU                      VIRT_ADDR(0x2, 0x6)
+#define R_MUTEC                         VIRT_ADDR(0x2, 0x7)
+#define R_MVOLL                         VIRT_ADDR(0x2, 0x8)
+#define R_MVOLR                         VIRT_ADDR(0x2, 0x9)
+#define R_HPVOLL                        VIRT_ADDR(0x2, 0x0A)
+#define R_HPVOLR                        VIRT_ADDR(0x2, 0x0B)
+#define R_SPKVOLL                       VIRT_ADDR(0x2, 0x0C)
+#define R_SPKVOLR                       VIRT_ADDR(0x2, 0x0D)
+#define R_SUBVOL                        VIRT_ADDR(0x2, 0x10)
+#define R_COP0                          VIRT_ADDR(0x2, 0x11)
+#define R_COP1                          VIRT_ADDR(0x2, 0x12)
+#define R_COPSTAT                       VIRT_ADDR(0x2, 0x13)
+#define R_PWM0                          VIRT_ADDR(0x2, 0x14)
+#define R_PWM1                          VIRT_ADDR(0x2, 0x15)
+#define R_PWM2                          VIRT_ADDR(0x2, 0x16)
+#define R_PWM3                          VIRT_ADDR(0x2, 0x17)
+#define R_HPSW                          VIRT_ADDR(0x2, 0x18)
+#define R_THERMTS                       VIRT_ADDR(0x2, 0x19)
+#define R_THERMSPK1                     VIRT_ADDR(0x2, 0x1A)
+#define R_THERMSTAT                     VIRT_ADDR(0x2, 0x1B)
+#define R_SCSTAT                        VIRT_ADDR(0x2, 0x1C)
+#define R_SDMON                         VIRT_ADDR(0x2, 0x1D)
+#define R_SPKEQFILT                     VIRT_ADDR(0x3, 0x1)
+#define R_SPKCRWDL                      VIRT_ADDR(0x3, 0x2)
+#define R_SPKCRWDM                      VIRT_ADDR(0x3, 0x3)
+#define R_SPKCRWDH                      VIRT_ADDR(0x3, 0x4)
+#define R_SPKCRRDL                      VIRT_ADDR(0x3, 0x5)
+#define R_SPKCRRDM                      VIRT_ADDR(0x3, 0x6)
+#define R_SPKCRRDH                      VIRT_ADDR(0x3, 0x7)
+#define R_SPKCRADD                      VIRT_ADDR(0x3, 0x8)
+#define R_SPKCRS                        VIRT_ADDR(0x3, 0x9)
+#define R_SPKMBCEN                      VIRT_ADDR(0x3, 0x0A)
+#define R_SPKMBCCTL                     VIRT_ADDR(0x3, 0x0B)
+#define R_SPKMBCMUG1                    VIRT_ADDR(0x3, 0x0C)
+#define R_SPKMBCTHR1                    VIRT_ADDR(0x3, 0x0D)
+#define R_SPKMBCRAT1                    VIRT_ADDR(0x3, 0x0E)
+#define R_SPKMBCATK1L                   VIRT_ADDR(0x3, 0x0F)
+#define R_SPKMBCATK1H                   VIRT_ADDR(0x3, 0x10)
+#define R_SPKMBCREL1L                   VIRT_ADDR(0x3, 0x11)
+#define R_SPKMBCREL1H                   VIRT_ADDR(0x3, 0x12)
+#define R_SPKMBCMUG2                    VIRT_ADDR(0x3, 0x13)
+#define R_SPKMBCTHR2                    VIRT_ADDR(0x3, 0x14)
+#define R_SPKMBCRAT2                    VIRT_ADDR(0x3, 0x15)
+#define R_SPKMBCATK2L                   VIRT_ADDR(0x3, 0x16)
+#define R_SPKMBCATK2H                   VIRT_ADDR(0x3, 0x17)
+#define R_SPKMBCREL2L                   VIRT_ADDR(0x3, 0x18)
+#define R_SPKMBCREL2H                   VIRT_ADDR(0x3, 0x19)
+#define R_SPKMBCMUG3                    VIRT_ADDR(0x3, 0x1A)
+#define R_SPKMBCTHR3                    VIRT_ADDR(0x3, 0x1B)
+#define R_SPKMBCRAT3                    VIRT_ADDR(0x3, 0x1C)
+#define R_SPKMBCATK3L                   VIRT_ADDR(0x3, 0x1D)
+#define R_SPKMBCATK3H                   VIRT_ADDR(0x3, 0x1E)
+#define R_SPKMBCREL3L                   VIRT_ADDR(0x3, 0x1F)
+#define R_SPKMBCREL3H                   VIRT_ADDR(0x3, 0x20)
+#define R_SPKCLECTL                     VIRT_ADDR(0x3, 0x21)
+#define R_SPKCLEMUG                     VIRT_ADDR(0x3, 0x22)
+#define R_SPKCOMPTHR                    VIRT_ADDR(0x3, 0x23)
+#define R_SPKCOMPRAT                    VIRT_ADDR(0x3, 0x24)
+#define R_SPKCOMPATKL                   VIRT_ADDR(0x3, 0x25)
+#define R_SPKCOMPATKH                   VIRT_ADDR(0x3, 0x26)
+#define R_SPKCOMPRELL                   VIRT_ADDR(0x3, 0x27)
+#define R_SPKCOMPRELH                   VIRT_ADDR(0x3, 0x28)
+#define R_SPKLIMTHR                     VIRT_ADDR(0x3, 0x29)
+#define R_SPKLIMTGT                     VIRT_ADDR(0x3, 0x2A)
+#define R_SPKLIMATKL                    VIRT_ADDR(0x3, 0x2B)
+#define R_SPKLIMATKH                    VIRT_ADDR(0x3, 0x2C)
+#define R_SPKLIMRELL                    VIRT_ADDR(0x3, 0x2D)
+#define R_SPKLIMRELH                    VIRT_ADDR(0x3, 0x2E)
+#define R_SPKEXPTHR                     VIRT_ADDR(0x3, 0x2F)
+#define R_SPKEXPRAT                     VIRT_ADDR(0x3, 0x30)
+#define R_SPKEXPATKL                    VIRT_ADDR(0x3, 0x31)
+#define R_SPKEXPATKH                    VIRT_ADDR(0x3, 0x32)
+#define R_SPKEXPRELL                    VIRT_ADDR(0x3, 0x33)
+#define R_SPKEXPRELH                    VIRT_ADDR(0x3, 0x34)
+#define R_SPKFXCTL                      VIRT_ADDR(0x3, 0x35)
+#define R_DACEQFILT                     VIRT_ADDR(0x4, 0x1)
+#define R_DACCRWDL                      VIRT_ADDR(0x4, 0x2)
+#define R_DACCRWDM                      VIRT_ADDR(0x4, 0x3)
+#define R_DACCRWDH                      VIRT_ADDR(0x4, 0x4)
+#define R_DACCRRDL                      VIRT_ADDR(0x4, 0x5)
+#define R_DACCRRDM                      VIRT_ADDR(0x4, 0x6)
+#define R_DACCRRDH                      VIRT_ADDR(0x4, 0x7)
+#define R_DACCRADD                      VIRT_ADDR(0x4, 0x8)
+#define R_DACCRS                        VIRT_ADDR(0x4, 0x9)
+#define R_DACMBCEN                      VIRT_ADDR(0x4, 0x0A)
+#define R_DACMBCCTL                     VIRT_ADDR(0x4, 0x0B)
+#define R_DACMBCMUG1                    VIRT_ADDR(0x4, 0x0C)
+#define R_DACMBCTHR1                    VIRT_ADDR(0x4, 0x0D)
+#define R_DACMBCRAT1                    VIRT_ADDR(0x4, 0x0E)
+#define R_DACMBCATK1L                   VIRT_ADDR(0x4, 0x0F)
+#define R_DACMBCATK1H                   VIRT_ADDR(0x4, 0x10)
+#define R_DACMBCREL1L                   VIRT_ADDR(0x4, 0x11)
+#define R_DACMBCREL1H                   VIRT_ADDR(0x4, 0x12)
+#define R_DACMBCMUG2                    VIRT_ADDR(0x4, 0x13)
+#define R_DACMBCTHR2                    VIRT_ADDR(0x4, 0x14)
+#define R_DACMBCRAT2                    VIRT_ADDR(0x4, 0x15)
+#define R_DACMBCATK2L                   VIRT_ADDR(0x4, 0x16)
+#define R_DACMBCATK2H                   VIRT_ADDR(0x4, 0x17)
+#define R_DACMBCREL2L                   VIRT_ADDR(0x4, 0x18)
+#define R_DACMBCREL2H                   VIRT_ADDR(0x4, 0x19)
+#define R_DACMBCMUG3                    VIRT_ADDR(0x4, 0x1A)
+#define R_DACMBCTHR3                    VIRT_ADDR(0x4, 0x1B)
+#define R_DACMBCRAT3                    VIRT_ADDR(0x4, 0x1C)
+#define R_DACMBCATK3L                   VIRT_ADDR(0x4, 0x1D)
+#define R_DACMBCATK3H                   VIRT_ADDR(0x4, 0x1E)
+#define R_DACMBCREL3L                   VIRT_ADDR(0x4, 0x1F)
+#define R_DACMBCREL3H                   VIRT_ADDR(0x4, 0x20)
+#define R_DACCLECTL                     VIRT_ADDR(0x4, 0x21)
+#define R_DACCLEMUG                     VIRT_ADDR(0x4, 0x22)
+#define R_DACCOMPTHR                    VIRT_ADDR(0x4, 0x23)
+#define R_DACCOMPRAT                    VIRT_ADDR(0x4, 0x24)
+#define R_DACCOMPATKL                   VIRT_ADDR(0x4, 0x25)
+#define R_DACCOMPATKH                   VIRT_ADDR(0x4, 0x26)
+#define R_DACCOMPRELL                   VIRT_ADDR(0x4, 0x27)
+#define R_DACCOMPRELH                   VIRT_ADDR(0x4, 0x28)
+#define R_DACLIMTHR                     VIRT_ADDR(0x4, 0x29)
+#define R_DACLIMTGT                     VIRT_ADDR(0x4, 0x2A)
+#define R_DACLIMATKL                    VIRT_ADDR(0x4, 0x2B)
+#define R_DACLIMATKH                    VIRT_ADDR(0x4, 0x2C)
+#define R_DACLIMRELL                    VIRT_ADDR(0x4, 0x2D)
+#define R_DACLIMRELH                    VIRT_ADDR(0x4, 0x2E)
+#define R_DACEXPTHR                     VIRT_ADDR(0x4, 0x2F)
+#define R_DACEXPRAT                     VIRT_ADDR(0x4, 0x30)
+#define R_DACEXPATKL                    VIRT_ADDR(0x4, 0x31)
+#define R_DACEXPATKH                    VIRT_ADDR(0x4, 0x32)
+#define R_DACEXPRELL                    VIRT_ADDR(0x4, 0x33)
+#define R_DACEXPRELH                    VIRT_ADDR(0x4, 0x34)
+#define R_DACFXCTL                      VIRT_ADDR(0x4, 0x35)
+#define R_SUBEQFILT                     VIRT_ADDR(0x5, 0x1)
+#define R_SUBCRWDL                      VIRT_ADDR(0x5, 0x2)
+#define R_SUBCRWDM                      VIRT_ADDR(0x5, 0x3)
+#define R_SUBCRWDH                      VIRT_ADDR(0x5, 0x4)
+#define R_SUBCRRDL                      VIRT_ADDR(0x5, 0x5)
+#define R_SUBCRRDM                      VIRT_ADDR(0x5, 0x6)
+#define R_SUBCRRDH                      VIRT_ADDR(0x5, 0x7)
+#define R_SUBCRADD                      VIRT_ADDR(0x5, 0x8)
+#define R_SUBCRS                        VIRT_ADDR(0x5, 0x9)
+#define R_SUBMBCEN                      VIRT_ADDR(0x5, 0x0A)
+#define R_SUBMBCCTL                     VIRT_ADDR(0x5, 0x0B)
+#define R_SUBMBCMUG1                    VIRT_ADDR(0x5, 0x0C)
+#define R_SUBMBCTHR1                    VIRT_ADDR(0x5, 0x0D)
+#define R_SUBMBCRAT1                    VIRT_ADDR(0x5, 0x0E)
+#define R_SUBMBCATK1L                   VIRT_ADDR(0x5, 0x0F)
+#define R_SUBMBCATK1H                   VIRT_ADDR(0x5, 0x10)
+#define R_SUBMBCREL1L                   VIRT_ADDR(0x5, 0x11)
+#define R_SUBMBCREL1H                   VIRT_ADDR(0x5, 0x12)
+#define R_SUBMBCMUG2                    VIRT_ADDR(0x5, 0x13)
+#define R_SUBMBCTHR2                    VIRT_ADDR(0x5, 0x14)
+#define R_SUBMBCRAT2                    VIRT_ADDR(0x5, 0x15)
+#define R_SUBMBCATK2L                   VIRT_ADDR(0x5, 0x16)
+#define R_SUBMBCATK2H                   VIRT_ADDR(0x5, 0x17)
+#define R_SUBMBCREL2L                   VIRT_ADDR(0x5, 0x18)
+#define R_SUBMBCREL2H                   VIRT_ADDR(0x5, 0x19)
+#define R_SUBMBCMUG3                    VIRT_ADDR(0x5, 0x1A)
+#define R_SUBMBCTHR3                    VIRT_ADDR(0x5, 0x1B)
+#define R_SUBMBCRAT3                    VIRT_ADDR(0x5, 0x1C)
+#define R_SUBMBCATK3L                   VIRT_ADDR(0x5, 0x1D)
+#define R_SUBMBCATK3H                   VIRT_ADDR(0x5, 0x1E)
+#define R_SUBMBCREL3L                   VIRT_ADDR(0x5, 0x1F)
+#define R_SUBMBCREL3H                   VIRT_ADDR(0x5, 0x20)
+#define R_SUBCLECTL                     VIRT_ADDR(0x5, 0x21)
+#define R_SUBCLEMUG                     VIRT_ADDR(0x5, 0x22)
+#define R_SUBCOMPTHR                    VIRT_ADDR(0x5, 0x23)
+#define R_SUBCOMPRAT                    VIRT_ADDR(0x5, 0x24)
+#define R_SUBCOMPATKL                   VIRT_ADDR(0x5, 0x25)
+#define R_SUBCOMPATKH                   VIRT_ADDR(0x5, 0x26)
+#define R_SUBCOMPRELL                   VIRT_ADDR(0x5, 0x27)
+#define R_SUBCOMPRELH                   VIRT_ADDR(0x5, 0x28)
+#define R_SUBLIMTHR                     VIRT_ADDR(0x5, 0x29)
+#define R_SUBLIMTGT                     VIRT_ADDR(0x5, 0x2A)
+#define R_SUBLIMATKL                    VIRT_ADDR(0x5, 0x2B)
+#define R_SUBLIMATKH                    VIRT_ADDR(0x5, 0x2C)
+#define R_SUBLIMRELL                    VIRT_ADDR(0x5, 0x2D)
+#define R_SUBLIMRELH                    VIRT_ADDR(0x5, 0x2E)
+#define R_SUBEXPTHR                     VIRT_ADDR(0x5, 0x2F)
+#define R_SUBEXPRAT                     VIRT_ADDR(0x5, 0x30)
+#define R_SUBEXPATKL                    VIRT_ADDR(0x5, 0x31)
+#define R_SUBEXPATKH                    VIRT_ADDR(0x5, 0x32)
+#define R_SUBEXPRELL                    VIRT_ADDR(0x5, 0x33)
+#define R_SUBEXPRELH                    VIRT_ADDR(0x5, 0x34)
+#define R_SUBFXCTL                      VIRT_ADDR(0x5, 0x35)
+
+// *** PLLCTL ***
+#define FB_PLLCTL_VCCI_PLL                                  6
+#define FM_PLLCTL_VCCI_PLL                                  0xC0
+
+#define FB_PLLCTL_RZ_PLL                                    3
+#define FM_PLLCTL_RZ_PLL                                    0x38
+
+#define FB_PLLCTL_CP_PLL                                    0
+#define FM_PLLCTL_CP_PLL                                    0x7
+
+// *** PLLRDIV ***
+#define FB_PLLRDIV_REFDIV_PLL                               0
+#define FM_PLLRDIV_REFDIV_PLL                               0xFF
+
+// *** PLLODIV ***
+#define FB_PLLODIV_OUTDIV_PLL                               0
+#define FM_PLLODIV_OUTDIV_PLL                               0xFF
+
+// *** PLLFDIVL ***
+#define FB_PLLFDIVL_FBDIVL_PLL                              0
+#define FM_PLLFDIVL_FBDIVL_PLL                              0xFF
+
+// *** PLLFDIVH ***
+#define FB_PLLFDIVH_FBDIVH_PLL                              0
+#define FM_PLLFDIVH_FBDIVH_PLL                              0xF
+
+// *** I2SPCTL ***
+#define FB_I2SPCTL_BCLKSTAT                                 7
+#define FM_I2SPCTL_BCLKSTAT                                 0x80
+#define FV_BCLKSTAT_LOST                                    0x80
+#define FV_BCLKSTAT_NOT_LOST                                0x0
+
+#define FB_I2SPCTL_BCLKP                                    6
+#define FM_I2SPCTL_BCLKP                                    0x40
+#define FV_BCLKP_NOT_INVERTED                               0x0
+#define FV_BCLKP_INVERTED                                   0x40
+
+#define FB_I2SPCTL_PORTMS                                   5
+#define FM_I2SPCTL_PORTMS                                   0x20
+#define FV_PORTMS_SLAVE                                     0x0
+#define FV_PORTMS_MASTER                                    0x20
+
+#define FB_I2SPCTL_LRCLKP                                   4
+#define FM_I2SPCTL_LRCLKP                                   0x10
+#define FV_LRCLKP_NOT_INVERTED                              0x0
+#define FV_LRCLKP_INVERTED                                  0x10
+
+#define FB_I2SPCTL_WL                                       2
+#define FM_I2SPCTL_WL                                       0xC
+#define FV_WL_16                                            0x0
+#define FV_WL_20                                            0x4
+#define FV_WL_24                                            0x8
+#define FV_WL_32                                            0xC
+
+#define FB_I2SPCTL_FORMAT                                   0
+#define FM_I2SPCTL_FORMAT                                   0x3
+#define FV_FORMAT_RIGHT                                     0x0
+#define FV_FORMAT_LEFT                                      0x1
+#define FV_FORMAT_I2S                                       0x2
+#define FV_FORMAT_TDM                                       0x3
+
+// *** I2SMRATE ***
+#define FB_I2SMRATE_I2SMCLKHALF                             7
+#define FM_I2SMRATE_I2SMCLKHALF                             0x80
+#define FV_I2SMCLKHALF_I2S1MCLKDIV_DIV_2                    0x0
+#define FV_I2SMCLKHALF_I2S1MCLKDIV_ONLY                     0x80
+
+#define FB_I2SMRATE_I2SMCLKDIV                              5
+#define FM_I2SMRATE_I2SMCLKDIV                              0x60
+#define FV_I2SMCLKDIV_125                                   0x0
+#define FV_I2SMCLKDIV_128                                   0x20
+#define FV_I2SMCLKDIV_136                                   0x40
+#define FV_I2SMCLKDIV_192                                   0x60
+
+#define FB_I2SMRATE_I2SMBR                                  3
+#define FM_I2SMRATE_I2SMBR                                  0x18
+#define FV_I2SMBR_32                                        0x0
+#define FV_I2SMBR_44PT1                                     0x8
+#define FV_I2SMBR_48                                        0x10
+#define FV_I2SMBR_MCLK_MODE                                 0x18
+
+#define FB_I2SMRATE_I2SMBM                                  0
+#define FM_I2SMRATE_I2SMBM                                  0x3
+#define FV_I2SMBM_0PT25                                     0x0
+#define FV_I2SMBM_0PT5                                      0x1
+#define FV_I2SMBM_1                                         0x2
+#define FV_I2SMBM_2                                         0x3
+
+// *** PCMPCTL0 ***
+#define FB_PCMPCTL0_PCMFLENP                                2
+#define FM_PCMPCTL0_PCMFLENP                                0x4
+#define FV_PCMFLENP_128                                     0x0
+#define FV_PCMFLENP_256                                     0x4
+
+#define FB_PCMPCTL0_SLSYNCP                                 1
+#define FM_PCMPCTL0_SLSYNCP                                 0x2
+#define FV_SLSYNCP_SHORT                                    0x0
+#define FV_SLSYNCP_LONG                                     0x2
+
+#define FB_PCMPCTL0_BDELAYP                                 0
+#define FM_PCMPCTL0_BDELAYP                                 0x1
+#define FV_BDELAYP_NO_DELAY                                 0x0
+#define FV_BDELAYP_1BCLK_DELAY                              0x1
+
+// *** PCMPCTL1 ***
+#define FB_PCMPCTL1_PCMMOMP                                 6
+#define FM_PCMPCTL1_PCMMOMP                                 0x40
+
+#define FB_PCMPCTL1_PCMSOP                                  5
+#define FM_PCMPCTL1_PCMSOP                                  0x20
+#define FV_PCMSOP_1                                         0x0
+#define FV_PCMSOP_2                                         0x20
+
+#define FB_PCMPCTL1_PCMDSSP                                 3
+#define FM_PCMPCTL1_PCMDSSP                                 0x18
+#define FV_PCMDSSP_16                                       0x0
+#define FV_PCMDSSP_24                                       0x8
+#define FV_PCMDSSP_32                                       0x10
+
+#define FB_PCMPCTL1_PCMMIMP                                 1
+#define FM_PCMPCTL1_PCMMIMP                                 0x2
+
+#define FB_PCMPCTL1_PCMSIP                                  0
+#define FM_PCMPCTL1_PCMSIP                                  0x1
+#define FV_PCMSIP_1                                         0x0
+#define FV_PCMSIP_2                                         0x1
+
+// *** CHAIC ***
+#define FB_CHAIC_MICBST                                     4
+#define FM_CHAIC_MICBST                                     0x30
+
+// *** PGACTL ***
+#define FB_PGACTL_PGAMUTE                                   7
+#define FM_PGACTL_PGAMUTE                                   0x80
+
+#define FB_PGACTL_PGAVOL                                    0
+#define FM_PGACTL_PGAVOL                                    0x3F
+
+// *** ICHVOL ***
+#define FB_ICHVOL_ICHVOL                                    0
+#define FM_ICHVOL_ICHVOL                                    0xFF
+
+// *** SPKMBCMUG ***
+#define FB_SPKMBCMUG_PHASE                                  5
+#define FM_SPKMBCMUG_PHASE                                  0x20
+
+#define FB_SPKMBCMUG_MUGAIN                                 0
+#define FM_SPKMBCMUG_MUGAIN                                 0x1F
+
+// *** SPKMBCTHR ***
+#define FB_SPKMBCTHR_THRESH                                 0
+#define FM_SPKMBCTHR_THRESH                                 0xFF
+
+// *** SPKMBCRAT ***
+#define FB_SPKMBCRAT_RATIO                                  0
+#define FM_SPKMBCRAT_RATIO                                  0x1F
+
+// *** SPKMBCATKL ***
+#define FB_SPKMBCATKL_TCATKL                                0
+#define FM_SPKMBCATKL_TCATKL                                0xFF
+
+// *** SPKMBCATKH ***
+#define FB_SPKMBCATKH_TCATKH                                0
+#define FM_SPKMBCATKH_TCATKH                                0xFF
+
+// *** SPKMBCRELL ***
+#define FB_SPKMBCRELL_TCRELL                                0
+#define FM_SPKMBCRELL_TCRELL                                0xFF
+
+// *** SPKMBCRELH ***
+#define FB_SPKMBCRELH_TCRELH                                0
+#define FM_SPKMBCRELH_TCRELH                                0xFF
+
+// *** DACMBCMUG ***
+#define FB_DACMBCMUG_PHASE                                  5
+#define FM_DACMBCMUG_PHASE                                  0x20
+
+#define FB_DACMBCMUG_MUGAIN                                 0
+#define FM_DACMBCMUG_MUGAIN                                 0x1F
+
+// *** DACMBCTHR ***
+#define FB_DACMBCTHR_THRESH                                 0
+#define FM_DACMBCTHR_THRESH                                 0xFF
+
+// *** DACMBCRAT ***
+#define FB_DACMBCRAT_RATIO                                  0
+#define FM_DACMBCRAT_RATIO                                  0x1F
+
+// *** DACMBCATKL ***
+#define FB_DACMBCATKL_TCATKL                                0
+#define FM_DACMBCATKL_TCATKL                                0xFF
+
+// *** DACMBCATKH ***
+#define FB_DACMBCATKH_TCATKH                                0
+#define FM_DACMBCATKH_TCATKH                                0xFF
+
+// *** DACMBCRELL ***
+#define FB_DACMBCRELL_TCRELL                                0
+#define FM_DACMBCRELL_TCRELL                                0xFF
+
+// *** DACMBCRELH ***
+#define FB_DACMBCRELH_TCRELH                                0
+#define FM_DACMBCRELH_TCRELH                                0xFF
+
+// *** SUBMBCMUG ***
+#define FB_SUBMBCMUG_PHASE                                  5
+#define FM_SUBMBCMUG_PHASE                                  0x20
+
+#define FB_SUBMBCMUG_MUGAIN                                 0
+#define FM_SUBMBCMUG_MUGAIN                                 0x1F
+
+// *** SUBMBCTHR ***
+#define FB_SUBMBCTHR_THRESH                                 0
+#define FM_SUBMBCTHR_THRESH                                 0xFF
+
+// *** SUBMBCRAT ***
+#define FB_SUBMBCRAT_RATIO                                  0
+#define FM_SUBMBCRAT_RATIO                                  0x1F
+
+// *** SUBMBCATKL ***
+#define FB_SUBMBCATKL_TCATKL                                0
+#define FM_SUBMBCATKL_TCATKL                                0xFF
+
+// *** SUBMBCATKH ***
+#define FB_SUBMBCATKH_TCATKH                                0
+#define FM_SUBMBCATKH_TCATKH                                0xFF
+
+// *** SUBMBCRELL ***
+#define FB_SUBMBCRELL_TCRELL                                0
+#define FM_SUBMBCRELL_TCRELL                                0xFF
+
+// *** SUBMBCRELH ***
+#define FB_SUBMBCRELH_TCRELH                                0
+#define FM_SUBMBCRELH_TCRELH                                0xFF
+
+// *** PAGESEL ***
+#define FB_PAGESEL_PAGESEL                                  0
+#define FM_PAGESEL_PAGESEL                                  0xFF
+
+// *** RESET ***
+#define FB_RESET_RESET                                      0
+#define FM_RESET_RESET                                      0xFF
+#define FV_RESET_PWR_ON_DEFAULTS                            0x85
+
+// *** IRQEN ***
+#define FB_IRQEN_THRMINTEN                                  6
+#define FM_IRQEN_THRMINTEN                                  0x40
+#define FV_THRMINTEN_ENABLED                                0x40
+#define FV_THRMINTEN_DISABLED                               0x0
+
+#define FB_IRQEN_HBPINTEN                                   5
+#define FM_IRQEN_HBPINTEN                                   0x20
+#define FV_HBPINTEN_ENABLED                                 0x20
+#define FV_HBPINTEN_DISABLED                                0x0
+
+#define FB_IRQEN_HSDINTEN                                   4
+#define FM_IRQEN_HSDINTEN                                   0x10
+#define FV_HSDINTEN_ENABLED                                 0x10
+#define FV_HSDINTEN_DISABLED                                0x0
+
+#define FB_IRQEN_HPDINTEN                                   3
+#define FM_IRQEN_HPDINTEN                                   0x8
+#define FV_HPDINTEN_ENABLED                                 0x8
+#define FV_HPDINTEN_DISABLED                                0x0
+
+#define FB_IRQEN_GPIO3INTEN                                 1
+#define FM_IRQEN_GPIO3INTEN                                 0x2
+#define FV_GPIO3INTEN_ENABLED                               0x2
+#define FV_GPIO3INTEN_DISABLED                              0x0
+
+#define FB_IRQEN_GPIO2INTEN                                 0
+#define FM_IRQEN_GPIO2INTEN                                 0x1
+#define FV_GPIO2INTEN_ENABLED                               0x1
+#define FV_GPIO2INTEN_DISABLED                              0x0
+
+#define IRQEN_GPIOINTEN_ENABLED                             0x1
+#define IRQEN_GPIOINTEN_DISABLED                            0x0
+
+// *** IRQMASK ***
+#define FB_IRQMASK_THRMIM                                   6
+#define FM_IRQMASK_THRMIM                                   0x40
+#define FV_THRMIM_MASKED                                    0x0
+#define FV_THRMIM_NOT_MASKED                                0x40
+
+#define FB_IRQMASK_HBPIM                                    5
+#define FM_IRQMASK_HBPIM                                    0x20
+#define FV_HBPIM_MASKED                                     0x0
+#define FV_HBPIM_NOT_MASKED                                 0x20
+
+#define FB_IRQMASK_HSDIM                                    4
+#define FM_IRQMASK_HSDIM                                    0x10
+#define FV_HSDIM_MASKED                                     0x0
+#define FV_HSDIM_NOT_MASKED                                 0x10
+
+#define FB_IRQMASK_HPDIM                                    3
+#define FM_IRQMASK_HPDIM                                    0x8
+#define FV_HPDIM_MASKED                                     0x0
+#define FV_HPDIM_NOT_MASKED                                 0x8
+
+#define FB_IRQMASK_GPIO3M                                   1
+#define FM_IRQMASK_GPIO3M                                   0x2
+#define FV_GPIO3M_MASKED                                    0x0
+#define FV_GPIO3M_NOT_MASKED                                0x2
+
+#define FB_IRQMASK_GPIO2M                                   0
+#define FM_IRQMASK_GPIO2M                                   0x1
+#define FV_GPIO2M_MASKED                                    0x0
+#define FV_GPIO2M_NOT_MASKED                                0x1
+
+#define IRQMASK_GPIOM_MASKED                                0x0
+#define IRQMASK_GPIOM_NOT_MASKED                            0x1
+
+// *** IRQSTAT ***
+#define FB_IRQSTAT_THRMINT                                  6
+#define FM_IRQSTAT_THRMINT                                  0x40
+#define FV_THRMINT_INTERRUPTED                              0x40
+#define FV_THRMINT_NOT_INTERRUPTED                          0x0
+
+#define FB_IRQSTAT_HBPINT                                   5
+#define FM_IRQSTAT_HBPINT                                   0x20
+#define FV_HBPINT_INTERRUPTED                               0x20
+#define FV_HBPINT_NOT_INTERRUPTED                           0x0
+
+#define FB_IRQSTAT_HSDINT                                   4
+#define FM_IRQSTAT_HSDINT                                   0x10
+#define FV_HSDINT_INTERRUPTED                               0x10
+#define FV_HSDINT_NOT_INTERRUPTED                           0x0
+
+#define FB_IRQSTAT_HPDINT                                   3
+#define FM_IRQSTAT_HPDINT                                   0x8
+#define FV_HPDINT_INTERRUPTED                               0x8
+#define FV_HPDINT_NOT_INTERRUPTED                           0x0
+
+#define FB_IRQSTAT_GPIO3INT                                 1
+#define FM_IRQSTAT_GPIO3INT                                 0x2
+#define FV_GPIO3INT_INTERRUPTED                             0x2
+#define FV_GPIO3INT_NOT_INTERRUPTED                         0x0
+
+#define FB_IRQSTAT_GPIO2INT                                 0
+#define FM_IRQSTAT_GPIO2INT                                 0x1
+#define FV_GPIO2INT_INTERRUPTED                             0x1
+#define FV_GPIO2INT_NOT_INTERRUPTED                         0x0
+
+#define IRQSTAT_GPIOINT_INTERRUPTED                         0x1
+#define IRQSTAT_GPIOINT_NOT_INTERRUPTED                     0x0
+
+// *** DEVADD0 ***
+#define FB_DEVADD0_DEVADD0                                  1
+#define FM_DEVADD0_DEVADD0                                  0xFE
+
+#define FB_DEVADD0_I2C_ADDRLK                               0
+#define FM_DEVADD0_I2C_ADDRLK                               0x1
+#define FV_I2C_ADDRLK_LOCK                                  0x1
+
+// *** DEVID ***
+#define FB_DEVID_DEV_ID                                     0
+#define FM_DEVID_DEV_ID                                     0xFF
+
+// *** DEVREV ***
+#define FB_DEVREV_MAJ_REV                                   4
+#define FM_DEVREV_MAJ_REV                                   0xF0
+
+#define FB_DEVREV_MIN_REV                                   0
+#define FM_DEVREV_MIN_REV                                   0xF
+
+// *** PLLSTAT ***
+#define FB_PLLSTAT_PLL2LK                                   1
+#define FM_PLLSTAT_PLL2LK                                   0x2
+#define FV_PLL2LK_LOCKED                                    0x2
+#define FV_PLL2LK_UNLOCKED                                  0x0
+
+#define FB_PLLSTAT_PLL1LK                                   0
+#define FM_PLLSTAT_PLL1LK                                   0x1
+#define FV_PLL1LK_LOCKED                                    0x1
+#define FV_PLL1LK_UNLOCKED                                  0x0
+
+#define PLLSTAT_PLLLK_LOCKED                                0x1
+#define PLLSTAT_PLLLK_UNLOCKED                              0x0
+
+// *** PLLCTL ***
+#define FB_PLLCTL_PU_PLL2                                   7
+#define FM_PLLCTL_PU_PLL2                                   0x80
+#define FV_PU_PLL2_PWR_UP                                   0x80
+#define FV_PU_PLL2_PWR_DWN                                  0x0
+
+#define FB_PLLCTL_PU_PLL1                                   6
+#define FM_PLLCTL_PU_PLL1                                   0x40
+#define FV_PU_PLL1_PWR_UP                                   0x40
+#define FV_PU_PLL1_PWR_DWN                                  0x0
+
+#define FB_PLLCTL_PLL2CLKEN                                 5
+#define FM_PLLCTL_PLL2CLKEN                                 0x20
+#define FV_PLL2CLKEN_ENABLE                                 0x20
+#define FV_PLL2CLKEN_DISABLE                                0x0
+
+#define FB_PLLCTL_PLL1CLKEN                                 4
+#define FM_PLLCTL_PLL1CLKEN                                 0x10
+#define FV_PLL1CLKEN_ENABLE                                 0x10
+#define FV_PLL1CLKEN_DISABLE                                0x0
+
+#define FB_PLLCTL_BCLKSEL                                   2
+#define FM_PLLCTL_BCLKSEL                                   0xC
+#define FV_BCLKSEL_BCLK1                                    0x0
+#define FV_BCLKSEL_BCLK2                                    0x4
+#define FV_BCLKSEL_BCLK3                                    0x8
+
+#define FB_PLLCTL_PLLISEL                                   0
+#define FM_PLLCTL_PLLISEL                                   0x3
+#define FV_PLLISEL_XTAL                                     0x0
+#define FV_PLLISEL_MCLK1                                    0x1
+#define FV_PLLISEL_MCLK2                                    0x2
+#define FV_PLLISEL_BCLK                                     0x3
+
+#define PLLCTL_PU_PLL_PWR_UP                                0x1
+#define PLLCTL_PU_PLL_PWR_DWN                               0x0
+#define PLLCTL_PLLCLKEN_ENABLE                              0x1
+#define PLLCTL_PLLCLKEN_DISABLE                             0x0
+
+// *** ISRC ***
+#define FB_ISRC_IBR                                         2
+#define FM_ISRC_IBR                                         0x4
+#define FV_IBR_44PT1                                        0x0
+#define FV_IBR_48                                           0x4
+
+#define FB_ISRC_IBM                                         0
+#define FM_ISRC_IBM                                         0x3
+#define FV_IBM_0PT25                                        0x0
+#define FV_IBM_0PT5                                         0x1
+#define FV_IBM_1                                            0x2
+#define FV_IBM_2                                            0x3
+
+// *** SCLKCTL ***
+#define FB_SCLKCTL_ASDM                                     6
+#define FM_SCLKCTL_ASDM                                     0xC0
+#define FV_ASDM_HALF                                        0x40
+#define FV_ASDM_FULL                                        0x80
+#define FV_ASDM_AUTO                                        0xC0
+
+#define FB_SCLKCTL_DSDM                                     4
+#define FM_SCLKCTL_DSDM                                     0x30
+#define FV_DSDM_HALF                                        0x10
+#define FV_DSDM_FULL                                        0x20
+#define FV_DSDM_AUTO                                        0x30
+
+// *** TIMEBASE ***
+#define FB_TIMEBASE_TIMEBASE                                0
+#define FM_TIMEBASE_TIMEBASE                                0xFF
+
+// *** I2SCMC ***
+#define FB_I2SCMC_BCMP3                                     4
+#define FM_I2SCMC_BCMP3                                     0x30
+#define FV_BCMP3_AUTO                                       0x0
+#define FV_BCMP3_32X                                        0x10
+#define FV_BCMP3_40X                                        0x20
+#define FV_BCMP3_64X                                        0x30
+
+#define FB_I2SCMC_BCMP2                                     2
+#define FM_I2SCMC_BCMP2                                     0xC
+#define FV_BCMP2_AUTO                                       0x0
+#define FV_BCMP2_32X                                        0x4
+#define FV_BCMP2_40X                                        0x8
+#define FV_BCMP2_64X                                        0xC
+
+#define FB_I2SCMC_BCMP1                                     0
+#define FM_I2SCMC_BCMP1                                     0x3
+#define FV_BCMP1_AUTO                                       0x0
+#define FV_BCMP1_32X                                        0x1
+#define FV_BCMP1_40X                                        0x2
+#define FV_BCMP1_64X                                        0x3
+
+#define I2SCMC_BCMP_AUTO                                    0x0
+#define I2SCMC_BCMP_32X                                     0x1
+#define I2SCMC_BCMP_40X                                     0x2
+#define I2SCMC_BCMP_64X                                     0x3
+
+// *** MCLK2PINC ***
+#define FB_MCLK2PINC_SLEWOUT                                4
+#define FM_MCLK2PINC_SLEWOUT                                0xF0
+
+#define FB_MCLK2PINC_MCLK2IO                                2
+#define FM_MCLK2PINC_MCLK2IO                                0x4
+#define FV_MCLK2IO_INPUT                                    0x0
+#define FV_MCLK2IO_OUTPUT                                   0x4
+
+#define FB_MCLK2PINC_MCLK2OS                                0
+#define FM_MCLK2PINC_MCLK2OS                                0x3
+#define FV_MCLK2OS_24PT576                                  0x0
+#define FV_MCLK2OS_22PT5792                                 0x1
+#define FV_MCLK2OS_PLL2                                     0x2
+
+// *** I2SPINC0 ***
+#define FB_I2SPINC0_SDO3TRI                                 7
+#define FM_I2SPINC0_SDO3TRI                                 0x80
+
+#define FB_I2SPINC0_SDO2TRI                                 6
+#define FM_I2SPINC0_SDO2TRI                                 0x40
+
+#define FB_I2SPINC0_SDO1TRI                                 5
+#define FM_I2SPINC0_SDO1TRI                                 0x20
+
+#define FB_I2SPINC0_PCM3TRI                                 2
+#define FM_I2SPINC0_PCM3TRI                                 0x4
+
+#define FB_I2SPINC0_PCM2TRI                                 1
+#define FM_I2SPINC0_PCM2TRI                                 0x2
+
+#define FB_I2SPINC0_PCM1TRI                                 0
+#define FM_I2SPINC0_PCM1TRI                                 0x1
+
+// *** I2SPINC1 ***
+#define FB_I2SPINC1_SDO3PDD                                 2
+#define FM_I2SPINC1_SDO3PDD                                 0x4
+
+#define FB_I2SPINC1_SDO2PDD                                 1
+#define FM_I2SPINC1_SDO2PDD                                 0x2
+
+#define FB_I2SPINC1_SDO1PDD                                 0
+#define FM_I2SPINC1_SDO1PDD                                 0x1
+
+// *** I2SPINC2 ***
+#define FB_I2SPINC2_LR3PDD                                  5
+#define FM_I2SPINC2_LR3PDD                                  0x20
+
+#define FB_I2SPINC2_BC3PDD                                  4
+#define FM_I2SPINC2_BC3PDD                                  0x10
+
+#define FB_I2SPINC2_LR2PDD                                  3
+#define FM_I2SPINC2_LR2PDD                                  0x8
+
+#define FB_I2SPINC2_BC2PDD                                  2
+#define FM_I2SPINC2_BC2PDD                                  0x4
+
+#define FB_I2SPINC2_LR1PDD                                  1
+#define FM_I2SPINC2_LR1PDD                                  0x2
+
+#define FB_I2SPINC2_BC1PDD                                  0
+#define FM_I2SPINC2_BC1PDD                                  0x1
+
+// *** GPIOCTL0 ***
+#define FB_GPIOCTL0_GPIO3INTP                               7
+#define FM_GPIOCTL0_GPIO3INTP                               0x80
+
+#define FB_GPIOCTL0_GPIO2INTP                               6
+#define FM_GPIOCTL0_GPIO2INTP                               0x40
+
+#define FB_GPIOCTL0_GPIO3CFG                                5
+#define FM_GPIOCTL0_GPIO3CFG                                0x20
+
+#define FB_GPIOCTL0_GPIO2CFG                                4
+#define FM_GPIOCTL0_GPIO2CFG                                0x10
+
+#define FB_GPIOCTL0_GPIO3IO                                 3
+#define FM_GPIOCTL0_GPIO3IO                                 0x8
+
+#define FB_GPIOCTL0_GPIO2IO                                 2
+#define FM_GPIOCTL0_GPIO2IO                                 0x4
+
+#define FB_GPIOCTL0_GPIO1IO                                 1
+#define FM_GPIOCTL0_GPIO1IO                                 0x2
+
+#define FB_GPIOCTL0_GPIO0IO                                 0
+#define FM_GPIOCTL0_GPIO0IO                                 0x1
+
+// *** GPIOCTL1 ***
+#define FB_GPIOCTL1_GPIO3                                   7
+#define FM_GPIOCTL1_GPIO3                                   0x80
+
+#define FB_GPIOCTL1_GPIO2                                   6
+#define FM_GPIOCTL1_GPIO2                                   0x40
+
+#define FB_GPIOCTL1_GPIO1                                   5
+#define FM_GPIOCTL1_GPIO1                                   0x20
+
+#define FB_GPIOCTL1_GPIO0                                   4
+#define FM_GPIOCTL1_GPIO0                                   0x10
+
+#define FB_GPIOCTL1_GPIO3RD                                 3
+#define FM_GPIOCTL1_GPIO3RD                                 0x8
+
+#define FB_GPIOCTL1_GPIO2RD                                 2
+#define FM_GPIOCTL1_GPIO2RD                                 0x4
+
+#define FB_GPIOCTL1_GPIO1RD                                 1
+#define FM_GPIOCTL1_GPIO1RD                                 0x2
+
+#define FB_GPIOCTL1_GPIO0RD                                 0
+#define FM_GPIOCTL1_GPIO0RD                                 0x1
+
+// *** ASRC ***
+#define FB_ASRC_ASRCOBW                                     7
+#define FM_ASRC_ASRCOBW                                     0x80
+
+#define FB_ASRC_ASRCIBW                                     6
+#define FM_ASRC_ASRCIBW                                     0x40
+
+#define FB_ASRC_ASRCOB                                      5
+#define FM_ASRC_ASRCOB                                      0x20
+#define FV_ASRCOB_ACTIVE                                    0x0
+#define FV_ASRCOB_BYPASSED                                  0x20
+
+#define FB_ASRC_ASRCIB                                      4
+#define FM_ASRC_ASRCIB                                      0x10
+#define FV_ASRCIB_ACTIVE                                    0x0
+#define FV_ASRCIB_BYPASSED                                  0x10
+
+#define FB_ASRC_ASRCOL                                      3
+#define FM_ASRC_ASRCOL                                      0x8
+
+#define FB_ASRC_ASRCIL                                      2
+#define FM_ASRC_ASRCIL                                      0x4
+
+// *** TDMCTL0 ***
+#define FB_TDMCTL0_TDMMD                                    2
+#define FM_TDMCTL0_TDMMD                                    0x4
+#define FV_TDMMD_200                                        0x0
+#define FV_TDMMD_256                                        0x4
+
+#define FB_TDMCTL0_SLSYNC                                   1
+#define FM_TDMCTL0_SLSYNC                                   0x2
+#define FV_SLSYNC_SHORT                                     0x0
+#define FV_SLSYNC_LONG                                      0x2
+
+#define FB_TDMCTL0_BDELAY                                   0
+#define FM_TDMCTL0_BDELAY                                   0x1
+#define FV_BDELAY_NO_DELAY                                  0x0
+#define FV_BDELAY_1BCLK_DELAY                               0x1
+
+// *** TDMCTL1 ***
+#define FB_TDMCTL1_TDMSO                                    5
+#define FM_TDMCTL1_TDMSO                                    0x60
+#define FV_TDMSO_2                                          0x0
+#define FV_TDMSO_4                                          0x20
+#define FV_TDMSO_6                                          0x40
+
+#define FB_TDMCTL1_TDMDSS                                   3
+#define FM_TDMCTL1_TDMDSS                                   0x18
+#define FV_TDMDSS_16                                        0x0
+#define FV_TDMDSS_24                                        0x10
+#define FV_TDMDSS_32                                        0x18
+
+#define FB_TDMCTL1_TDMSI                                    0
+#define FM_TDMCTL1_TDMSI                                    0x3
+#define FV_TDMSI_2                                          0x0
+#define FV_TDMSI_4                                          0x1
+#define FV_TDMSI_6                                          0x2
+
+// *** PWRM0 ***
+#define FB_PWRM0_INPROC3PU                                  6
+#define FM_PWRM0_INPROC3PU                                  0x40
+
+#define FB_PWRM0_INPROC2PU                                  5
+#define FM_PWRM0_INPROC2PU                                  0x20
+
+#define FB_PWRM0_INPROC1PU                                  4
+#define FM_PWRM0_INPROC1PU                                  0x10
+
+#define FB_PWRM0_INPROC0PU                                  3
+#define FM_PWRM0_INPROC0PU                                  0x8
+
+#define FB_PWRM0_MICB2PU                                    2
+#define FM_PWRM0_MICB2PU                                    0x4
+
+#define FB_PWRM0_MICB1PU                                    1
+#define FM_PWRM0_MICB1PU                                    0x2
+
+#define FB_PWRM0_MCLKPEN                                    0
+#define FM_PWRM0_MCLKPEN                                    0x1
+
+// *** PWRM1 ***
+#define FB_PWRM1_SUBPU                                      7
+#define FM_PWRM1_SUBPU                                      0x80
+
+#define FB_PWRM1_HPLPU                                      6
+#define FM_PWRM1_HPLPU                                      0x40
+
+#define FB_PWRM1_HPRPU                                      5
+#define FM_PWRM1_HPRPU                                      0x20
+
+#define FB_PWRM1_SPKLPU                                     4
+#define FM_PWRM1_SPKLPU                                     0x10
+
+#define FB_PWRM1_SPKRPU                                     3
+#define FM_PWRM1_SPKRPU                                     0x8
+
+#define FB_PWRM1_D2S2PU                                     2
+#define FM_PWRM1_D2S2PU                                     0x4
+
+#define FB_PWRM1_D2S1PU                                     1
+#define FM_PWRM1_D2S1PU                                     0x2
+
+#define FB_PWRM1_VREFPU                                     0
+#define FM_PWRM1_VREFPU                                     0x1
+
+// *** PWRM2 ***
+#define FB_PWRM2_I2S3OPU                                    5
+#define FM_PWRM2_I2S3OPU                                    0x20
+#define FV_I2S3OPU_PWR_DOWN                                 0x0
+#define FV_I2S3OPU_PWR_UP                                   0x20
+
+#define FB_PWRM2_I2S2OPU                                    4
+#define FM_PWRM2_I2S2OPU                                    0x10
+#define FV_I2S2OPU_PWR_DOWN                                 0x0
+#define FV_I2S2OPU_PWR_UP                                   0x10
+
+#define FB_PWRM2_I2S1OPU                                    3
+#define FM_PWRM2_I2S1OPU                                    0x8
+#define FV_I2S1OPU_PWR_DOWN                                 0x0
+#define FV_I2S1OPU_PWR_UP                                   0x8
+
+#define FB_PWRM2_I2S3IPU                                    2
+#define FM_PWRM2_I2S3IPU                                    0x4
+#define FV_I2S3IPU_PWR_DOWN                                 0x0
+#define FV_I2S3IPU_PWR_UP                                   0x4
+
+#define FB_PWRM2_I2S2IPU                                    1
+#define FM_PWRM2_I2S2IPU                                    0x2
+#define FV_I2S2IPU_PWR_DOWN                                 0x0
+#define FV_I2S2IPU_PWR_UP                                   0x2
+
+#define FB_PWRM2_I2S1IPU                                    0
+#define FM_PWRM2_I2S1IPU                                    0x1
+#define FV_I2S1IPU_PWR_DOWN                                 0x0
+#define FV_I2S1IPU_PWR_UP                                   0x1
+
+#define PWRM2_I2SOPU_PWR_DOWN                               0x0
+#define PWRM2_I2SOPU_PWR_UP                                 0x1
+#define PWRM2_I2SIPU_PWR_DOWN                               0x0
+#define PWRM2_I2SIPU_PWR_UP                                 0x1
+
+// *** PWRM3 ***
+#define FB_PWRM3_BGSBUP                                     6
+#define FM_PWRM3_BGSBUP                                     0x40
+#define FV_BGSBUP_ON                                        0x0
+#define FV_BGSBUP_OFF                                       0x40
+
+#define FB_PWRM3_VGBAPU                                     5
+#define FM_PWRM3_VGBAPU                                     0x20
+#define FV_VGBAPU_ON                                        0x0
+#define FV_VGBAPU_OFF                                       0x20
+
+#define FB_PWRM3_LLINEPU                                    4
+#define FM_PWRM3_LLINEPU                                    0x10
+
+#define FB_PWRM3_RLINEPU                                    3
+#define FM_PWRM3_RLINEPU                                    0x8
+
+// *** PWRM4 ***
+#define FB_PWRM4_OPSUBPU                                    4
+#define FM_PWRM4_OPSUBPU                                    0x10
+
+#define FB_PWRM4_OPDACLPU                                   3
+#define FM_PWRM4_OPDACLPU                                   0x8
+
+#define FB_PWRM4_OPDACRPU                                   2
+#define FM_PWRM4_OPDACRPU                                   0x4
+
+#define FB_PWRM4_OPSPKLPU                                   1
+#define FM_PWRM4_OPSPKLPU                                   0x2
+
+#define FB_PWRM4_OPSPKRPU                                   0
+#define FM_PWRM4_OPSPKRPU                                   0x1
+
+// *** I2SIDCTL ***
+#define FB_I2SIDCTL_I2SI3DCTL                               4
+#define FM_I2SIDCTL_I2SI3DCTL                               0x30
+
+#define FB_I2SIDCTL_I2SI2DCTL                               2
+#define FM_I2SIDCTL_I2SI2DCTL                               0xC
+
+#define FB_I2SIDCTL_I2SI1DCTL                               0
+#define FM_I2SIDCTL_I2SI1DCTL                               0x3
+
+// *** I2SODCTL ***
+#define FB_I2SODCTL_I2SO3DCTL                               4
+#define FM_I2SODCTL_I2SO3DCTL                               0x30
+
+#define FB_I2SODCTL_I2SO2DCTL                               2
+#define FM_I2SODCTL_I2SO2DCTL                               0xC
+
+#define FB_I2SODCTL_I2SO1DCTL                               0
+#define FM_I2SODCTL_I2SO1DCTL                               0x3
+
+// *** AUDIOMUX1 ***
+#define FB_AUDIOMUX1_ASRCIMUX                               6
+#define FM_AUDIOMUX1_ASRCIMUX                               0xC0
+#define FV_ASRCIMUX_NONE                                    0x0
+#define FV_ASRCIMUX_I2S1                                    0x40
+#define FV_ASRCIMUX_I2S2                                    0x80
+#define FV_ASRCIMUX_I2S3                                    0xC0
+
+#define FB_AUDIOMUX1_I2S2MUX                                3
+#define FM_AUDIOMUX1_I2S2MUX                                0x38
+#define FV_I2S2MUX_I2S1                                     0x0
+#define FV_I2S2MUX_I2S2                                     0x8
+#define FV_I2S2MUX_I2S3                                     0x10
+#define FV_I2S2MUX_ADC_DMIC                                 0x18
+#define FV_I2S2MUX_DMIC2                                    0x20
+#define FV_I2S2MUX_CLASSD_DSP                               0x28
+#define FV_I2S2MUX_DAC_DSP                                  0x30
+#define FV_I2S2MUX_SUB_DSP                                  0x38
+
+#define FB_AUDIOMUX1_I2S1MUX                                0
+#define FM_AUDIOMUX1_I2S1MUX                                0x7
+#define FV_I2S1MUX_I2S1                                     0x0
+#define FV_I2S1MUX_I2S2                                     0x1
+#define FV_I2S1MUX_I2S3                                     0x2
+#define FV_I2S1MUX_ADC_DMIC                                 0x3
+#define FV_I2S1MUX_DMIC2                                    0x4
+#define FV_I2S1MUX_CLASSD_DSP                               0x5
+#define FV_I2S1MUX_DAC_DSP                                  0x6
+#define FV_I2S1MUX_SUB_DSP                                  0x7
+
+#define AUDIOMUX1_I2SMUX_I2S1                               0x0
+#define AUDIOMUX1_I2SMUX_I2S2                               0x1
+#define AUDIOMUX1_I2SMUX_I2S3                               0x2
+#define AUDIOMUX1_I2SMUX_ADC_DMIC                           0x3
+#define AUDIOMUX1_I2SMUX_DMIC2                              0x4
+#define AUDIOMUX1_I2SMUX_CLASSD_DSP                         0x5
+#define AUDIOMUX1_I2SMUX_DAC_DSP                            0x6
+#define AUDIOMUX1_I2SMUX_SUB_DSP                            0x7
+
+// *** AUDIOMUX2 ***
+#define FB_AUDIOMUX2_ASRCOMUX                               6
+#define FM_AUDIOMUX2_ASRCOMUX                               0xC0
+#define FV_ASRCOMUX_NONE                                    0x0
+#define FV_ASRCOMUX_I2S1                                    0x40
+#define FV_ASRCOMUX_I2S2                                    0x80
+#define FV_ASRCOMUX_I2S3                                    0xC0
+
+#define FB_AUDIOMUX2_DACMUX                                 3
+#define FM_AUDIOMUX2_DACMUX                                 0x38
+#define FV_DACMUX_I2S1                                      0x0
+#define FV_DACMUX_I2S2                                      0x8
+#define FV_DACMUX_I2S3                                      0x10
+#define FV_DACMUX_ADC_DMIC                                  0x18
+#define FV_DACMUX_DMIC2                                     0x20
+#define FV_DACMUX_CLASSD_DSP                                0x28
+#define FV_DACMUX_DAC_DSP                                   0x30
+#define FV_DACMUX_SUB_DSP                                   0x38
+
+#define FB_AUDIOMUX2_I2S3MUX                                0
+#define FM_AUDIOMUX2_I2S3MUX                                0x7
+#define FV_I2S3MUX_I2S1                                     0x0
+#define FV_I2S3MUX_I2S2                                     0x1
+#define FV_I2S3MUX_I2S3                                     0x2
+#define FV_I2S3MUX_ADC_DMIC                                 0x3
+#define FV_I2S3MUX_DMIC2                                    0x4
+#define FV_I2S3MUX_CLASSD_DSP                               0x5
+#define FV_I2S3MUX_DAC_DSP                                  0x6
+#define FV_I2S3MUX_SUB_DSP                                  0x7
+
+// *** AUDIOMUX3 ***
+#define FB_AUDIOMUX3_SUBMUX                                 3
+#define FM_AUDIOMUX3_SUBMUX                                 0xF8
+#define FV_SUBMUX_I2S1_L                                    0x0
+#define FV_SUBMUX_I2S1_R                                    0x8
+#define FV_SUBMUX_I2S1_LR                                   0x10
+#define FV_SUBMUX_I2S2_L                                    0x18
+#define FV_SUBMUX_I2S2_R                                    0x20
+#define FV_SUBMUX_I2S2_LR                                   0x28
+#define FV_SUBMUX_I2S3_L                                    0x30
+#define FV_SUBMUX_I2S3_R                                    0x38
+#define FV_SUBMUX_I2S3_LR                                   0x40
+#define FV_SUBMUX_ADC_DMIC_L                                0x48
+#define FV_SUBMUX_ADC_DMIC_R                                0x50
+#define FV_SUBMUX_ADC_DMIC_LR                               0x58
+#define FV_SUBMUX_DMIC_L                                    0x60
+#define FV_SUBMUX_DMIC_R                                    0x68
+#define FV_SUBMUX_DMIC_LR                                   0x70
+#define FV_SUBMUX_CLASSD_DSP_L                              0x78
+#define FV_SUBMUX_CLASSD_DSP_R                              0x80
+#define FV_SUBMUX_CLASSD_DSP_LR                             0x88
+
+#define FB_AUDIOMUX3_CLSSDMUX                               0
+#define FM_AUDIOMUX3_CLSSDMUX                               0x7
+#define FV_CLSSDMUX_I2S1                                    0x0
+#define FV_CLSSDMUX_I2S2                                    0x1
+#define FV_CLSSDMUX_I2S3                                    0x2
+#define FV_CLSSDMUX_ADC_DMIC                                0x3
+#define FV_CLSSDMUX_DMIC2                                   0x4
+#define FV_CLSSDMUX_CLASSD_DSP                              0x5
+#define FV_CLSSDMUX_DAC_DSP                                 0x6
+#define FV_CLSSDMUX_SUB_DSP                                 0x7
+
+// *** HSDCTL1 ***
+#define FB_HSDCTL1_HPJKTYPE                                 7
+#define FM_HSDCTL1_HPJKTYPE                                 0x80
+
+#define FB_HSDCTL1_CON_DET_PWD                              6
+#define FM_HSDCTL1_CON_DET_PWD                              0x40
+
+#define FB_HSDCTL1_DETCYC                                   4
+#define FM_HSDCTL1_DETCYC                                   0x30
+
+#define FB_HSDCTL1_HPDLYBYP                                 3
+#define FM_HSDCTL1_HPDLYBYP                                 0x8
+
+#define FB_HSDCTL1_HSDETPOL                                 2
+#define FM_HSDCTL1_HSDETPOL                                 0x4
+
+#define FB_HSDCTL1_HPID_EN                                  1
+#define FM_HSDCTL1_HPID_EN                                  0x2
+
+#define FB_HSDCTL1_GBLHS_EN                                 0
+#define FM_HSDCTL1_GBLHS_EN                                 0x1
+
+// *** HSDCTL2 ***
+#define FB_HSDCTL2_FMICBIAS1                                6
+#define FM_HSDCTL2_FMICBIAS1                                0xC0
+
+#define FB_HSDCTL2_MB1MODE                                  5
+#define FM_HSDCTL2_MB1MODE                                  0x20
+#define FV_MB1MODE_AUTO                                     0x0
+#define FV_MB1MODE_MANUAL                                   0x20
+
+#define FB_HSDCTL2_FORCETRG                                 4
+#define FM_HSDCTL2_FORCETRG                                 0x10
+
+#define FB_HSDCTL2_SWMODE                                   3
+#define FM_HSDCTL2_SWMODE                                   0x8
+
+#define FB_HSDCTL2_GHSHIZ                                   2
+#define FM_HSDCTL2_GHSHIZ                                   0x4
+
+#define FB_HSDCTL2_FPLUGTYPE                                0
+#define FM_HSDCTL2_FPLUGTYPE                                0x3
+
+// *** HSDSTAT ***
+#define FB_HSDSTAT_MBIAS1DRV                                5
+#define FM_HSDSTAT_MBIAS1DRV                                0x60
+
+#define FB_HSDSTAT_HSDETSTAT                                3
+#define FM_HSDSTAT_HSDETSTAT                                0x8
+
+#define FB_HSDSTAT_PLUGTYPE                                 1
+#define FM_HSDSTAT_PLUGTYPE                                 0x6
+
+#define FB_HSDSTAT_HSDETDONE                                0
+#define FM_HSDSTAT_HSDETDONE                                0x1
+
+// *** HSDDELAY ***
+#define FB_HSDDELAY_T_STABLE                                0
+#define FM_HSDDELAY_T_STABLE                                0x7
+
+// *** BUTCTL ***
+#define FB_BUTCTL_BPUSHSTAT                                 7
+#define FM_BUTCTL_BPUSHSTAT                                 0x80
+
+#define FB_BUTCTL_BPUSHDET                                  6
+#define FM_BUTCTL_BPUSHDET                                  0x40
+
+#define FB_BUTCTL_BPUSHEN                                   5
+#define FM_BUTCTL_BPUSHEN                                   0x20
+
+#define FB_BUTCTL_BSTABLE_L                                 3
+#define FM_BUTCTL_BSTABLE_L                                 0x18
+
+#define FB_BUTCTL_BSTABLE_S                                 0
+#define FM_BUTCTL_BSTABLE_S                                 0x7
+
+// *** CH0AIC ***
+#define FB_CH0AIC_INSELL                                    6
+#define FM_CH0AIC_INSELL                                    0xC0
+
+#define FB_CH0AIC_MICBST0                                   4
+#define FM_CH0AIC_MICBST0                                   0x30
+
+#define FB_CH0AIC_LADCIN                                    2
+#define FM_CH0AIC_LADCIN                                    0xC
+
+#define FB_CH0AIC_IN_BYPS_L_SEL                             1
+#define FM_CH0AIC_IN_BYPS_L_SEL                             0x2
+
+#define FB_CH0AIC_IPCH0S                                    0
+#define FM_CH0AIC_IPCH0S                                    0x1
+
+// *** CH1AIC ***
+#define FB_CH1AIC_INSELR                                    6
+#define FM_CH1AIC_INSELR                                    0xC0
+
+#define FB_CH1AIC_MICBST1                                   4
+#define FM_CH1AIC_MICBST1                                   0x30
+
+#define FB_CH1AIC_RADCIN                                    2
+#define FM_CH1AIC_RADCIN                                    0xC
+
+#define FB_CH1AIC_IN_BYPS_R_SEL                             1
+#define FM_CH1AIC_IN_BYPS_R_SEL                             0x2
+
+#define FB_CH1AIC_IPCH1S                                    0
+#define FM_CH1AIC_IPCH1S                                    0x1
+
+// *** ICTL0 ***
+#define FB_ICTL0_IN1POL                                     7
+#define FM_ICTL0_IN1POL                                     0x80
+
+#define FB_ICTL0_IN0POL                                     6
+#define FM_ICTL0_IN0POL                                     0x40
+
+#define FB_ICTL0_INPCH10SEL                                 4
+#define FM_ICTL0_INPCH10SEL                                 0x30
+
+#define FB_ICTL0_IN1MUTE                                    3
+#define FM_ICTL0_IN1MUTE                                    0x8
+
+#define FB_ICTL0_IN0MUTE                                    2
+#define FM_ICTL0_IN0MUTE                                    0x4
+
+#define FB_ICTL0_IN1HP                                      1
+#define FM_ICTL0_IN1HP                                      0x2
+
+#define FB_ICTL0_IN0HP                                      0
+#define FM_ICTL0_IN0HP                                      0x1
+
+// *** ICTL1 ***
+#define FB_ICTL1_IN3POL                                     7
+#define FM_ICTL1_IN3POL                                     0x80
+
+#define FB_ICTL1_IN2POL                                     6
+#define FM_ICTL1_IN2POL                                     0x40
+
+#define FB_ICTL1_INPCH32SEL                                 4
+#define FM_ICTL1_INPCH32SEL                                 0x30
+
+#define FB_ICTL1_IN3MUTE                                    3
+#define FM_ICTL1_IN3MUTE                                    0x8
+
+#define FB_ICTL1_IN2MUTE                                    2
+#define FM_ICTL1_IN2MUTE                                    0x4
+
+#define FB_ICTL1_IN3HP                                      1
+#define FM_ICTL1_IN3HP                                      0x2
+
+#define FB_ICTL1_IN2HP                                      0
+#define FM_ICTL1_IN2HP                                      0x1
+
+// *** MICBIAS ***
+#define FB_MICBIAS_MICBOV2                                  4
+#define FM_MICBIAS_MICBOV2                                  0x30
+
+#define FB_MICBIAS_MICBOV1                                  6
+#define FM_MICBIAS_MICBOV1                                  0xC0
+
+#define FB_MICBIAS_SPARE1                                   2
+#define FM_MICBIAS_SPARE1                                   0xC
+
+#define FB_MICBIAS_SPARE2                                   0
+#define FM_MICBIAS_SPARE2                                   0x3
+
+// *** PGAZ ***
+#define FB_PGAZ_INHPOR                                      1
+#define FM_PGAZ_INHPOR                                      0x2
+
+#define FB_PGAZ_TOEN                                        0
+#define FM_PGAZ_TOEN                                        0x1
+
+// *** ASRCILVOL ***
+#define FB_ASRCILVOL_ASRCILVOL                              0
+#define FM_ASRCILVOL_ASRCILVOL                              0xFF
+
+// *** ASRCIRVOL ***
+#define FB_ASRCIRVOL_ASRCIRVOL                              0
+#define FM_ASRCIRVOL_ASRCIRVOL                              0xFF
+
+// *** ASRCOLVOL ***
+#define FB_ASRCOLVOL_ASRCOLVOL                              0
+#define FM_ASRCOLVOL_ASRCOLVOL                              0xFF
+
+// *** ASRCORVOL ***
+#define FB_ASRCORVOL_ASRCOLVOL                              0
+#define FM_ASRCORVOL_ASRCOLVOL                              0xFF
+
+// *** IVOLCTLU ***
+#define FB_IVOLCTLU_IFADE                                   3
+#define FM_IVOLCTLU_IFADE                                   0x8
+
+#define FB_IVOLCTLU_INPVOLU                                 2
+#define FM_IVOLCTLU_INPVOLU                                 0x4
+
+#define FB_IVOLCTLU_PGAVOLU                                 1
+#define FM_IVOLCTLU_PGAVOLU                                 0x2
+
+#define FB_IVOLCTLU_ASRCVOLU                                0
+#define FM_IVOLCTLU_ASRCVOLU                                0x1
+
+// *** ALCCTL0 ***
+#define FB_ALCCTL0_ALCMODE                                  7
+#define FM_ALCCTL0_ALCMODE                                  0x80
+
+#define FB_ALCCTL0_ALCREF                                   4
+#define FM_ALCCTL0_ALCREF                                   0x70
+
+#define FB_ALCCTL0_ALCEN3                                   3
+#define FM_ALCCTL0_ALCEN3                                   0x8
+
+#define FB_ALCCTL0_ALCEN2                                   2
+#define FM_ALCCTL0_ALCEN2                                   0x4
+
+#define FB_ALCCTL0_ALCEN1                                   1
+#define FM_ALCCTL0_ALCEN1                                   0x2
+
+#define FB_ALCCTL0_ALCEN0                                   0
+#define FM_ALCCTL0_ALCEN0                                   0x1
+
+// *** ALCCTL1 ***
+#define FB_ALCCTL1_MAXGAIN                                  4
+#define FM_ALCCTL1_MAXGAIN                                  0x70
+
+#define FB_ALCCTL1_ALCL                                     0
+#define FM_ALCCTL1_ALCL                                     0xF
+
+// *** ALCCTL2 ***
+#define FB_ALCCTL2_ALCZC                                    7
+#define FM_ALCCTL2_ALCZC                                    0x80
+
+#define FB_ALCCTL2_MINGAIN                                  4
+#define FM_ALCCTL2_MINGAIN                                  0x70
+
+#define FB_ALCCTL2_HLD                                      0
+#define FM_ALCCTL2_HLD                                      0xF
+
+// *** ALCCTL3 ***
+#define FB_ALCCTL3_DCY                                      4
+#define FM_ALCCTL3_DCY                                      0xF0
+
+#define FB_ALCCTL3_ATK                                      0
+#define FM_ALCCTL3_ATK                                      0xF
+
+// *** NGATE ***
+#define FB_NGATE_NGTH                                       3
+#define FM_NGATE_NGTH                                       0xF8
+
+#define FB_NGATE_NGG                                        1
+#define FM_NGATE_NGG                                        0x6
+
+#define FB_NGATE_NGAT                                       0
+#define FM_NGATE_NGAT                                       0x1
+
+// *** DMICCTL ***
+#define FB_DMICCTL_DMIC2EN                                  7
+#define FM_DMICCTL_DMIC2EN                                  0x80
+
+#define FB_DMICCTL_DMIC1EN                                  6
+#define FM_DMICCTL_DMIC1EN                                  0x40
+
+#define FB_DMICCTL_DMONO                                    4
+#define FM_DMICCTL_DMONO                                    0x10
+
+#define FB_DMICCTL_DMDCLK                                   2
+#define FM_DMICCTL_DMDCLK                                   0xC
+
+#define FB_DMICCTL_DMRATE                                   0
+#define FM_DMICCTL_DMRATE                                   0x3
+
+// *** DACCTL ***
+#define FB_DACCTL_DACPOLR                                   7
+#define FM_DACCTL_DACPOLR                                   0x80
+#define FV_DACPOLR_NORMAL                                   0x0
+#define FV_DACPOLR_INVERTED                                 0x80
+
+#define FB_DACCTL_DACPOLL                                   6
+#define FM_DACCTL_DACPOLL                                   0x40
+#define FV_DACPOLL_NORMAL                                   0x0
+#define FV_DACPOLL_INVERTED                                 0x40
+
+#define FB_DACCTL_DACDITH                                   4
+#define FM_DACCTL_DACDITH                                   0x30
+#define FV_DACDITH_DYNAMIC_HALF                             0x0
+#define FV_DACDITH_DYNAMIC_FULL                             0x10
+#define FV_DACDITH_DISABLED                                 0x20
+#define FV_DACDITH_STATIC                                   0x30
+
+#define FB_DACCTL_DACMUTE                                   3
+#define FM_DACCTL_DACMUTE                                   0x8
+#define FV_DACMUTE_ENABLE                                   0x8
+#define FV_DACMUTE_DISABLE                                  0x0
+
+#define FB_DACCTL_DACDEM                                    2
+#define FM_DACCTL_DACDEM                                    0x4
+#define FV_DACDEM_ENABLE                                    0x4
+#define FV_DACDEM_DISABLE                                   0x0
+
+#define FB_DACCTL_ABYPASS                                   0
+#define FM_DACCTL_ABYPASS                                   0x1
+
+// *** SPKCTL ***
+#define FB_SPKCTL_SPKPOLR                                   7
+#define FM_SPKCTL_SPKPOLR                                   0x80
+#define FV_SPKPOLR_NORMAL                                   0x0
+#define FV_SPKPOLR_INVERTED                                 0x80
+
+#define FB_SPKCTL_SPKPOLL                                   6
+#define FM_SPKCTL_SPKPOLL                                   0x40
+#define FV_SPKPOLL_NORMAL                                   0x0
+#define FV_SPKPOLL_INVERTED                                 0x40
+
+#define FB_SPKCTL_SPKMUTE                                   3
+#define FM_SPKCTL_SPKMUTE                                   0x8
+#define FV_SPKMUTE_ENABLE                                   0x8
+#define FV_SPKMUTE_DISABLE                                  0x0
+
+#define FB_SPKCTL_SPKDEM                                    2
+#define FM_SPKCTL_SPKDEM                                    0x4
+#define FV_SPKDEM_ENABLE                                    0x4
+#define FV_SPKDEM_DISABLE                                   0x0
+
+// *** SUBCTL ***
+#define FB_SUBCTL_SUBPOL                                    7
+#define FM_SUBCTL_SUBPOL                                    0x80
+
+#define FB_SUBCTL_SUBMUTE                                   3
+#define FM_SUBCTL_SUBMUTE                                   0x8
+
+#define FB_SUBCTL_SUBDEM                                    2
+#define FM_SUBCTL_SUBDEM                                    0x4
+
+#define FB_SUBCTL_SUBMUX                                    1
+#define FM_SUBCTL_SUBMUX                                    0x2
+
+#define FB_SUBCTL_SUBILMDIS                                 0
+#define FM_SUBCTL_SUBILMDIS                                 0x1
+
+// *** DCCTL ***
+#define FB_DCCTL_SUBDCBYP                                   7
+#define FM_DCCTL_SUBDCBYP                                   0x80
+
+#define FB_DCCTL_DACDCBYP                                   6
+#define FM_DCCTL_DACDCBYP                                   0x40
+
+#define FB_DCCTL_SPKDCBYP                                   5
+#define FM_DCCTL_SPKDCBYP                                   0x20
+
+#define FB_DCCTL_DCCOEFSEL                                  0
+#define FM_DCCTL_DCCOEFSEL                                  0x7
+
+// *** OVOLCTLU ***
+#define FB_OVOLCTLU_OFADE                                   4
+#define FM_OVOLCTLU_OFADE                                   0x10
+
+#define FB_OVOLCTLU_SUBVOLU                                 3
+#define FM_OVOLCTLU_SUBVOLU                                 0x8
+
+#define FB_OVOLCTLU_MVOLU                                   2
+#define FM_OVOLCTLU_MVOLU                                   0x4
+
+#define FB_OVOLCTLU_SPKVOLU                                 1
+#define FM_OVOLCTLU_SPKVOLU                                 0x2
+
+#define FB_OVOLCTLU_HPVOLU                                  0
+#define FM_OVOLCTLU_HPVOLU                                  0x1
+
+// *** MUTEC ***
+#define FB_MUTEC_ZDSTAT                                     7
+#define FM_MUTEC_ZDSTAT                                     0x80
+
+#define FB_MUTEC_ZDLEN                                      4
+#define FM_MUTEC_ZDLEN                                      0x30
+
+#define FB_MUTEC_APWD                                       3
+#define FM_MUTEC_APWD                                       0x8
+
+#define FB_MUTEC_AMUTE                                      2
+#define FM_MUTEC_AMUTE                                      0x4
+
+// *** MVOLL ***
+#define FB_MVOLL_MVOL_L                                     0
+#define FM_MVOLL_MVOL_L                                     0xFF
+
+// *** MVOLR ***
+#define FB_MVOLR_MVOL_R                                     0
+#define FM_MVOLR_MVOL_R                                     0xFF
+
+// *** HPVOLL ***
+#define FB_HPVOLL_HPVOL_L                                   0
+#define FM_HPVOLL_HPVOL_L                                   0x7F
+
+// *** HPVOLR ***
+#define FB_HPVOLR_HPVOL_R                                   0
+#define FM_HPVOLR_HPVOL_R                                   0x7F
+
+// *** SPKVOLL ***
+#define FB_SPKVOLL_SPKVOL_L                                 0
+#define FM_SPKVOLL_SPKVOL_L                                 0x7F
+
+// *** SPKVOLR ***
+#define FB_SPKVOLR_SPKVOL_R                                 0
+#define FM_SPKVOLR_SPKVOL_R                                 0x7F
+
+// *** SUBVOL ***
+#define FB_SUBVOL_SUBVOL                                    0
+#define FM_SUBVOL_SUBVOL                                    0x7F
+
+// *** COP0 ***
+#define FB_COP0_COPATTEN                                    7
+#define FM_COP0_COPATTEN                                    0x80
+
+#define FB_COP0_COPGAIN                                     6
+#define FM_COP0_COPGAIN                                     0x40
+
+#define FB_COP0_HDELTAEN                                    5
+#define FM_COP0_HDELTAEN                                    0x20
+
+#define FB_COP0_COPTARGET                                   0
+#define FM_COP0_COPTARGET                                   0x1F
+
+// *** COP1 ***
+#define FB_COP1_HDCOMPMODE                                  6
+#define FM_COP1_HDCOMPMODE                                  0x40
+
+#define FB_COP1_AVGLENGTH                                   2
+#define FM_COP1_AVGLENGTH                                   0x3C
+
+#define FB_COP1_MONRATE                                     0
+#define FM_COP1_MONRATE                                     0x3
+
+// *** COPSTAT ***
+#define FB_COPSTAT_HDELTADET                                7
+#define FM_COPSTAT_HDELTADET                                0x80
+
+#define FB_COPSTAT_UV                                       6
+#define FM_COPSTAT_UV                                       0x40
+
+#define FB_COPSTAT_COPADJ                                   0
+#define FM_COPSTAT_COPADJ                                   0x3F
+
+// *** PWM0 ***
+#define FB_PWM0_SCTO                                        6
+#define FM_PWM0_SCTO                                        0xC0
+
+#define FB_PWM0_UVLO                                        5
+#define FM_PWM0_UVLO                                        0x20
+
+#define FB_PWM0_BFDIS                                       3
+#define FM_PWM0_BFDIS                                       0x8
+
+#define FB_PWM0_PWMMODE                                     2
+#define FM_PWM0_PWMMODE                                     0x4
+
+#define FB_PWM0_NOOFFSET                                    0
+#define FM_PWM0_NOOFFSET                                    0x1
+
+// *** PWM1 ***
+#define FB_PWM1_DITHPOS                                     4
+#define FM_PWM1_DITHPOS                                     0x70
+
+#define FB_PWM1_DYNDITH                                     1
+#define FM_PWM1_DYNDITH                                     0x2
+
+#define FB_PWM1_DITHDIS                                     0
+#define FM_PWM1_DITHDIS                                     0x1
+
+// *** PWM2 ***
+// *** PWM3 ***
+#define FB_PWM3_PWMMUX                                      6
+#define FM_PWM3_PWMMUX                                      0xC0
+
+#define FB_PWM3_CVALUE                                      0
+#define FM_PWM3_CVALUE                                      0x7
+
+// *** HPSW ***
+#define FB_HPSW_HPDETSTATE                                  4
+#define FM_HPSW_HPDETSTATE                                  0x10
+
+#define FB_HPSW_HPSWEN                                      2
+#define FM_HPSW_HPSWEN                                      0xC
+
+#define FB_HPSW_HPSWPOL                                     1
+#define FM_HPSW_HPSWPOL                                     0x2
+
+#define FB_HPSW_TSDEN                                       0
+#define FM_HPSW_TSDEN                                       0x1
+
+// *** THERMTS ***
+#define FB_THERMTS_TRIPHS                                   7
+#define FM_THERMTS_TRIPHS                                   0x80
+
+#define FB_THERMTS_TRIPLS                                   6
+#define FM_THERMTS_TRIPLS                                   0x40
+
+#define FB_THERMTS_TRIPSPLIT                                4
+#define FM_THERMTS_TRIPSPLIT                                0x30
+
+#define FB_THERMTS_TRIPSHIFT                                2
+#define FM_THERMTS_TRIPSHIFT                                0xC
+
+#define FB_THERMTS_TSPOLL                                   0
+#define FM_THERMTS_TSPOLL                                   0x3
+
+// *** THERMSPK1 ***
+#define FB_THERMSPK1_FORCEPWD                               7
+#define FM_THERMSPK1_FORCEPWD                               0x80
+
+#define FB_THERMSPK1_INSTCUTMODE                            6
+#define FM_THERMSPK1_INSTCUTMODE                            0x40
+
+#define FB_THERMSPK1_INCRATIO                               4
+#define FM_THERMSPK1_INCRATIO                               0x30
+
+#define FB_THERMSPK1_INCSTEP                                2
+#define FM_THERMSPK1_INCSTEP                                0xC
+
+#define FB_THERMSPK1_DECSTEP                                0
+#define FM_THERMSPK1_DECSTEP                                0x3
+
+// *** THERMSTAT ***
+#define FB_THERMSTAT_FPWDS                                  7
+#define FM_THERMSTAT_FPWDS                                  0x80
+
+#define FB_THERMSTAT_VOLSTAT                                0
+#define FM_THERMSTAT_VOLSTAT                                0x7F
+
+// *** SCSTAT ***
+#define FB_SCSTAT_ESDF                                      3
+#define FM_SCSTAT_ESDF                                      0x18
+
+#define FB_SCSTAT_CPF                                       2
+#define FM_SCSTAT_CPF                                       0x4
+
+#define FB_SCSTAT_CLSDF                                     0
+#define FM_SCSTAT_CLSDF                                     0x3
+
+// *** SDMON ***
+#define FB_SDMON_SDFORCE                                    7
+#define FM_SDMON_SDFORCE                                    0x80
+
+#define FB_SDMON_SDVALUE                                    0
+#define FM_SDMON_SDVALUE                                    0x1F
+
+// *** SPKEQFILT ***
+#define FB_SPKEQFILT_EQ2EN                                  7
+#define FM_SPKEQFILT_EQ2EN                                  0x80
+#define FV_EQ2EN_ENABLE                                     0x80
+#define FV_EQ2EN_DISABLE                                    0x0
+
+#define FB_SPKEQFILT_EQ2BE                                  4
+#define FM_SPKEQFILT_EQ2BE                                  0x70
+
+#define FB_SPKEQFILT_EQ1EN                                  3
+#define FM_SPKEQFILT_EQ1EN                                  0x8
+#define FV_EQ1EN_ENABLE                                     0x8
+#define FV_EQ1EN_DISABLE                                    0x0
+
+#define FB_SPKEQFILT_EQ1BE                                  0
+#define FM_SPKEQFILT_EQ1BE                                  0x7
+
+#define SPKEQFILT_EQEN_ENABLE                               0x1
+#define SPKEQFILT_EQEN_DISABLE                              0x0
+
+// *** SPKCRWDL ***
+#define FB_SPKCRWDL_WDATA_L                                 0
+#define FM_SPKCRWDL_WDATA_L                                 0xFF
+
+// *** SPKCRWDM ***
+#define FB_SPKCRWDM_WDATA_M                                 0
+#define FM_SPKCRWDM_WDATA_M                                 0xFF
+
+// *** SPKCRWDH ***
+#define FB_SPKCRWDH_WDATA_H                                 0
+#define FM_SPKCRWDH_WDATA_H                                 0xFF
+
+// *** SPKCRRDL ***
+#define FB_SPKCRRDL_RDATA_L                                 0
+#define FM_SPKCRRDL_RDATA_L                                 0xFF
+
+// *** SPKCRRDM ***
+#define FB_SPKCRRDM_RDATA_M                                 0
+#define FM_SPKCRRDM_RDATA_M                                 0xFF
+
+// *** SPKCRRDH ***
+#define FB_SPKCRRDH_RDATA_H                                 0
+#define FM_SPKCRRDH_RDATA_H                                 0xFF
+
+// *** SPKCRADD ***
+#define FB_SPKCRADD_ADDRESS                                 0
+#define FM_SPKCRADD_ADDRESS                                 0xFF
+
+// *** SPKCRS ***
+#define FB_SPKCRS_ACCSTAT                                   7
+#define FM_SPKCRS_ACCSTAT                                   0x80
+
+// *** SPKMBCEN ***
+#define FB_SPKMBCEN_MBCEN3                                  2
+#define FM_SPKMBCEN_MBCEN3                                  0x4
+#define FV_MBCEN3_ENABLE                                    0x4
+#define FV_MBCEN3_DISABLE                                   0x0
+
+#define FB_SPKMBCEN_MBCEN2                                  1
+#define FM_SPKMBCEN_MBCEN2                                  0x2
+#define FV_MBCEN2_ENABLE                                    0x2
+#define FV_MBCEN2_DISABLE                                   0x0
+
+#define FB_SPKMBCEN_MBCEN1                                  0
+#define FM_SPKMBCEN_MBCEN1                                  0x1
+#define FV_MBCEN1_ENABLE                                    0x1
+#define FV_MBCEN1_DISABLE                                   0x0
+
+#define SPKMBCEN_MBCEN_ENABLE                               0x1
+#define SPKMBCEN_MBCEN_DISABLE                              0x0
+
+// *** SPKMBCCTL ***
+#define FB_SPKMBCCTL_LVLMODE3                               5
+#define FM_SPKMBCCTL_LVLMODE3                               0x20
+
+#define FB_SPKMBCCTL_WINSEL3                                4
+#define FM_SPKMBCCTL_WINSEL3                                0x10
+
+#define FB_SPKMBCCTL_LVLMODE2                               3
+#define FM_SPKMBCCTL_LVLMODE2                               0x8
+
+#define FB_SPKMBCCTL_WINSEL2                                2
+#define FM_SPKMBCCTL_WINSEL2                                0x4
+
+#define FB_SPKMBCCTL_LVLMODE1                               1
+#define FM_SPKMBCCTL_LVLMODE1                               0x2
+
+#define FB_SPKMBCCTL_WINSEL1                                0
+#define FM_SPKMBCCTL_WINSEL1                                0x1
+
+// *** SPKCLECTL ***
+#define FB_SPKCLECTL_LVLMODE                                4
+#define FM_SPKCLECTL_LVLMODE                                0x10
+
+#define FB_SPKCLECTL_WINSEL                                 3
+#define FM_SPKCLECTL_WINSEL                                 0x8
+
+#define FB_SPKCLECTL_EXPEN                                  2
+#define FM_SPKCLECTL_EXPEN                                  0x4
+#define FV_EXPEN_ENABLE                                     0x4
+#define FV_EXPEN_DISABLE                                    0x0
+
+#define FB_SPKCLECTL_LIMEN                                  1
+#define FM_SPKCLECTL_LIMEN                                  0x2
+#define FV_LIMEN_ENABLE                                     0x2
+#define FV_LIMEN_DISABLE                                    0x0
+
+#define FB_SPKCLECTL_COMPEN                                 0
+#define FM_SPKCLECTL_COMPEN                                 0x1
+#define FV_COMPEN_ENABLE                                    0x1
+#define FV_COMPEN_DISABLE                                   0x0
+
+// *** SPKCLEMUG ***
+#define FB_SPKCLEMUG_MUGAIN                                 0
+#define FM_SPKCLEMUG_MUGAIN                                 0x1F
+
+// *** SPKCOMPTHR ***
+#define FB_SPKCOMPTHR_THRESH                                0
+#define FM_SPKCOMPTHR_THRESH                                0xFF
+
+// *** SPKCOMPRAT ***
+#define FB_SPKCOMPRAT_RATIO                                 0
+#define FM_SPKCOMPRAT_RATIO                                 0x1F
+
+// *** SPKCOMPATKL ***
+#define FB_SPKCOMPATKL_TCATKL                               0
+#define FM_SPKCOMPATKL_TCATKL                               0xFF
+
+// *** SPKCOMPATKH ***
+#define FB_SPKCOMPATKH_TCATKH                               0
+#define FM_SPKCOMPATKH_TCATKH                               0xFF
+
+// *** SPKCOMPRELL ***
+#define FB_SPKCOMPRELL_TCRELL                               0
+#define FM_SPKCOMPRELL_TCRELL                               0xFF
+
+// *** SPKCOMPRELH ***
+#define FB_SPKCOMPRELH_TCRELH                               0
+#define FM_SPKCOMPRELH_TCRELH                               0xFF
+
+// *** SPKLIMTHR ***
+#define FB_SPKLIMTHR_THRESH                                 0
+#define FM_SPKLIMTHR_THRESH                                 0xFF
+
+// *** SPKLIMTGT ***
+#define FB_SPKLIMTGT_TARGET                                 0
+#define FM_SPKLIMTGT_TARGET                                 0xFF
+
+// *** SPKLIMATKL ***
+#define FB_SPKLIMATKL_TCATKL                                0
+#define FM_SPKLIMATKL_TCATKL                                0xFF
+
+// *** SPKLIMATKH ***
+#define FB_SPKLIMATKH_TCATKH                                0
+#define FM_SPKLIMATKH_TCATKH                                0xFF
+
+// *** SPKLIMRELL ***
+#define FB_SPKLIMRELL_TCRELL                                0
+#define FM_SPKLIMRELL_TCRELL                                0xFF
+
+// *** SPKLIMRELH ***
+#define FB_SPKLIMRELH_TCRELH                                0
+#define FM_SPKLIMRELH_TCRELH                                0xFF
+
+// *** SPKEXPTHR ***
+#define FB_SPKEXPTHR_THRESH                                 0
+#define FM_SPKEXPTHR_THRESH                                 0xFF
+
+// *** SPKEXPRAT ***
+#define FB_SPKEXPRAT_RATIO                                  0
+#define FM_SPKEXPRAT_RATIO                                  0x7
+
+// *** SPKEXPATKL ***
+#define FB_SPKEXPATKL_TCATKL                                0
+#define FM_SPKEXPATKL_TCATKL                                0xFF
+
+// *** SPKEXPATKH ***
+#define FB_SPKEXPATKH_TCATKH                                0
+#define FM_SPKEXPATKH_TCATKH                                0xFF
+
+// *** SPKEXPRELL ***
+#define FB_SPKEXPRELL_TCRELL                                0
+#define FM_SPKEXPRELL_TCRELL                                0xFF
+
+// *** SPKEXPRELH ***
+#define FB_SPKEXPRELH_TCRELH                                0
+#define FM_SPKEXPRELH_TCRELH                                0xFF
+
+// *** SPKFXCTL ***
+#define FB_SPKFXCTL_3DEN                                    4
+#define FM_SPKFXCTL_3DEN                                    0x10
+
+#define FB_SPKFXCTL_TEEN                                    3
+#define FM_SPKFXCTL_TEEN                                    0x8
+
+#define FB_SPKFXCTL_TNLFBYP                                 2
+#define FM_SPKFXCTL_TNLFBYP                                 0x4
+
+#define FB_SPKFXCTL_BEEN                                    1
+#define FM_SPKFXCTL_BEEN                                    0x2
+
+#define FB_SPKFXCTL_BNLFBYP                                 0
+#define FM_SPKFXCTL_BNLFBYP                                 0x1
+
+// *** DACEQFILT ***
+#define FB_DACEQFILT_EQ2EN                                  7
+#define FM_DACEQFILT_EQ2EN                                  0x80
+#define FV_EQ2EN_ENABLE                                     0x80
+#define FV_EQ2EN_DISABLE                                    0x0
+
+#define FB_DACEQFILT_EQ2BE                                  4
+#define FM_DACEQFILT_EQ2BE                                  0x70
+
+#define FB_DACEQFILT_EQ1EN                                  3
+#define FM_DACEQFILT_EQ1EN                                  0x8
+#define FV_EQ1EN_ENABLE                                     0x8
+#define FV_EQ1EN_DISABLE                                    0x0
+
+#define FB_DACEQFILT_EQ1BE                                  0
+#define FM_DACEQFILT_EQ1BE                                  0x7
+
+#define DACEQFILT_EQEN_ENABLE                               0x1
+#define DACEQFILT_EQEN_DISABLE                              0x0
+
+// *** DACCRWDL ***
+#define FB_DACCRWDL_WDATA_L                                 0
+#define FM_DACCRWDL_WDATA_L                                 0xFF
+
+// *** DACCRWDM ***
+#define FB_DACCRWDM_WDATA_M                                 0
+#define FM_DACCRWDM_WDATA_M                                 0xFF
+
+// *** DACCRWDH ***
+#define FB_DACCRWDH_WDATA_H                                 0
+#define FM_DACCRWDH_WDATA_H                                 0xFF
+
+// *** DACCRRDL ***
+#define FB_DACCRRDL_RDATA_L                                 0
+#define FM_DACCRRDL_RDATA_L                                 0xFF
+
+// *** DACCRRDM ***
+#define FB_DACCRRDM_RDATA_M                                 0
+#define FM_DACCRRDM_RDATA_M                                 0xFF
+
+// *** DACCRRDH ***
+#define FB_DACCRRDH_RDATA_H                                 0
+#define FM_DACCRRDH_RDATA_H                                 0xFF
+
+// *** DACCRADD ***
+#define FB_DACCRADD_ADDRESS                                 0
+#define FM_DACCRADD_ADDRESS                                 0xFF
+
+// *** DACCRS ***
+#define FB_DACCRS_ACCSTAT                                   7
+#define FM_DACCRS_ACCSTAT                                   0x80
+
+// *** DACMBCEN ***
+#define FB_DACMBCEN_MBCEN3                                  2
+#define FM_DACMBCEN_MBCEN3                                  0x4
+#define FV_MBCEN3_ENABLE                                    0x4
+#define FV_MBCEN3_DISABLE                                   0x0
+
+#define FB_DACMBCEN_MBCEN2                                  1
+#define FM_DACMBCEN_MBCEN2                                  0x2
+#define FV_MBCEN2_ENABLE                                    0x2
+#define FV_MBCEN2_DISABLE                                   0x0
+
+#define FB_DACMBCEN_MBCEN1                                  0
+#define FM_DACMBCEN_MBCEN1                                  0x1
+#define FV_MBCEN1_ENABLE                                    0x1
+#define FV_MBCEN1_DISABLE                                   0x0
+
+#define DACMBCEN_MBCEN_ENABLE                               0x1
+#define DACMBCEN_MBCEN_DISABLE                              0x0
+
+// *** DACMBCCTL ***
+#define FB_DACMBCCTL_LVLMODE3                               5
+#define FM_DACMBCCTL_LVLMODE3                               0x20
+
+#define FB_DACMBCCTL_WINSEL3                                4
+#define FM_DACMBCCTL_WINSEL3                                0x10
+
+#define FB_DACMBCCTL_LVLMODE2                               3
+#define FM_DACMBCCTL_LVLMODE2                               0x8
+
+#define FB_DACMBCCTL_WINSEL2                                2
+#define FM_DACMBCCTL_WINSEL2                                0x4
+
+#define FB_DACMBCCTL_LVLMODE1                               1
+#define FM_DACMBCCTL_LVLMODE1                               0x2
+
+#define FB_DACMBCCTL_WINSEL1                                0
+#define FM_DACMBCCTL_WINSEL1                                0x1
+
+// *** DACCLECTL ***
+#define FB_DACCLECTL_LVLMODE                                4
+#define FM_DACCLECTL_LVLMODE                                0x10
+
+#define FB_DACCLECTL_WINSEL                                 3
+#define FM_DACCLECTL_WINSEL                                 0x8
+
+#define FB_DACCLECTL_EXPEN                                  2
+#define FM_DACCLECTL_EXPEN                                  0x4
+#define FV_EXPEN_ENABLE                                     0x4
+#define FV_EXPEN_DISABLE                                    0x0
+
+#define FB_DACCLECTL_LIMEN                                  1
+#define FM_DACCLECTL_LIMEN                                  0x2
+#define FV_LIMEN_ENABLE                                     0x2
+#define FV_LIMEN_DISABLE                                    0x0
+
+#define FB_DACCLECTL_COMPEN                                 0
+#define FM_DACCLECTL_COMPEN                                 0x1
+#define FV_COMPEN_ENABLE                                    0x1
+#define FV_COMPEN_DISABLE                                   0x0
+
+// *** DACCLEMUG ***
+#define FB_DACCLEMUG_MUGAIN                                 0
+#define FM_DACCLEMUG_MUGAIN                                 0x1F
+
+// *** DACCOMPTHR ***
+#define FB_DACCOMPTHR_THRESH                                0
+#define FM_DACCOMPTHR_THRESH                                0xFF
+
+// *** DACCOMPRAT ***
+#define FB_DACCOMPRAT_RATIO                                 0
+#define FM_DACCOMPRAT_RATIO                                 0x1F
+
+// *** DACCOMPATKL ***
+#define FB_DACCOMPATKL_TCATKL                               0
+#define FM_DACCOMPATKL_TCATKL                               0xFF
+
+// *** DACCOMPATKH ***
+#define FB_DACCOMPATKH_TCATKH                               0
+#define FM_DACCOMPATKH_TCATKH                               0xFF
+
+// *** DACCOMPRELL ***
+#define FB_DACCOMPRELL_TCRELL                               0
+#define FM_DACCOMPRELL_TCRELL                               0xFF
+
+// *** DACCOMPRELH ***
+#define FB_DACCOMPRELH_TCRELH                               0
+#define FM_DACCOMPRELH_TCRELH                               0xFF
+
+// *** DACLIMTHR ***
+#define FB_DACLIMTHR_THRESH                                 0
+#define FM_DACLIMTHR_THRESH                                 0xFF
+
+// *** DACLIMTGT ***
+#define FB_DACLIMTGT_TARGET                                 0
+#define FM_DACLIMTGT_TARGET                                 0xFF
+
+// *** DACLIMATKL ***
+#define FB_DACLIMATKL_TCATKL                                0
+#define FM_DACLIMATKL_TCATKL                                0xFF
+
+// *** DACLIMATKH ***
+#define FB_DACLIMATKH_TCATKH                                0
+#define FM_DACLIMATKH_TCATKH                                0xFF
+
+// *** DACLIMRELL ***
+#define FB_DACLIMRELL_TCRELL                                0
+#define FM_DACLIMRELL_TCRELL                                0xFF
+
+// *** DACLIMRELH ***
+#define FB_DACLIMRELH_TCRELH                                0
+#define FM_DACLIMRELH_TCRELH                                0xFF
+
+// *** DACEXPTHR ***
+#define FB_DACEXPTHR_THRESH                                 0
+#define FM_DACEXPTHR_THRESH                                 0xFF
+
+// *** DACEXPRAT ***
+#define FB_DACEXPRAT_RATIO                                  0
+#define FM_DACEXPRAT_RATIO                                  0x7
+
+// *** DACEXPATKL ***
+#define FB_DACEXPATKL_TCATKL                                0
+#define FM_DACEXPATKL_TCATKL                                0xFF
+
+// *** DACEXPATKH ***
+#define FB_DACEXPATKH_TCATKH                                0
+#define FM_DACEXPATKH_TCATKH                                0xFF
+
+// *** DACEXPRELL ***
+#define FB_DACEXPRELL_TCRELL                                0
+#define FM_DACEXPRELL_TCRELL                                0xFF
+
+// *** DACEXPRELH ***
+#define FB_DACEXPRELH_TCRELH                                0
+#define FM_DACEXPRELH_TCRELH                                0xFF
+
+// *** DACFXCTL ***
+#define FB_DACFXCTL_3DEN                                    4
+#define FM_DACFXCTL_3DEN                                    0x10
+
+#define FB_DACFXCTL_TEEN                                    3
+#define FM_DACFXCTL_TEEN                                    0x8
+
+#define FB_DACFXCTL_TNLFBYP                                 2
+#define FM_DACFXCTL_TNLFBYP                                 0x4
+
+#define FB_DACFXCTL_BEEN                                    1
+#define FM_DACFXCTL_BEEN                                    0x2
+
+#define FB_DACFXCTL_BNLFBYP                                 0
+#define FM_DACFXCTL_BNLFBYP                                 0x1
+
+// *** SUBEQFILT ***
+#define FB_SUBEQFILT_EQ2EN                                  7
+#define FM_SUBEQFILT_EQ2EN                                  0x80
+#define FV_EQ2EN_ENABLE                                     0x80
+#define FV_EQ2EN_DISABLE                                    0x0
+
+#define FB_SUBEQFILT_EQ2BE                                  4
+#define FM_SUBEQFILT_EQ2BE                                  0x70
+
+#define FB_SUBEQFILT_EQ1EN                                  3
+#define FM_SUBEQFILT_EQ1EN                                  0x8
+#define FV_EQ1EN_ENABLE                                     0x8
+#define FV_EQ1EN_DISABLE                                    0x0
+
+#define FB_SUBEQFILT_EQ1BE                                  0
+#define FM_SUBEQFILT_EQ1BE                                  0x7
+
+#define SUBEQFILT_EQEN_ENABLE                               0x1
+#define SUBEQFILT_EQEN_DISABLE                              0x0
+
+// *** SUBCRWDL ***
+#define FB_SUBCRWDL_WDATA_L                                 0
+#define FM_SUBCRWDL_WDATA_L                                 0xFF
+
+// *** SUBCRWDM ***
+#define FB_SUBCRWDM_WDATA_M                                 0
+#define FM_SUBCRWDM_WDATA_M                                 0xFF
+
+// *** SUBCRWDH ***
+#define FB_SUBCRWDH_WDATA_H                                 0
+#define FM_SUBCRWDH_WDATA_H                                 0xFF
+
+// *** SUBCRRDL ***
+#define FB_SUBCRRDL_RDATA_L                                 0
+#define FM_SUBCRRDL_RDATA_L                                 0xFF
+
+// *** SUBCRRDM ***
+#define FB_SUBCRRDM_RDATA_M                                 0
+#define FM_SUBCRRDM_RDATA_M                                 0xFF
+
+// *** SUBCRRDH ***
+#define FB_SUBCRRDH_RDATA_H                                 0
+#define FM_SUBCRRDH_RDATA_H                                 0xFF
+
+// *** SUBCRADD ***
+#define FB_SUBCRADD_ADDRESS                                 0
+#define FM_SUBCRADD_ADDRESS                                 0xFF
+
+// *** SUBCRS ***
+#define FB_SUBCRS_ACCSTAT                                   7
+#define FM_SUBCRS_ACCSTAT                                   0x80
+
+// *** SUBMBCEN ***
+#define FB_SUBMBCEN_MBCEN3                                  2
+#define FM_SUBMBCEN_MBCEN3                                  0x4
+#define FV_MBCEN3_ENABLE                                    0x4
+#define FV_MBCEN3_DISABLE                                   0x0
+
+#define FB_SUBMBCEN_MBCEN2                                  1
+#define FM_SUBMBCEN_MBCEN2                                  0x2
+#define FV_MBCEN2_ENABLE                                    0x2
+#define FV_MBCEN2_DISABLE                                   0x0
+
+#define FB_SUBMBCEN_MBCEN1                                  0
+#define FM_SUBMBCEN_MBCEN1                                  0x1
+#define FV_MBCEN1_ENABLE                                    0x1
+#define FV_MBCEN1_DISABLE                                   0x0
+
+#define SUBMBCEN_MBCEN_ENABLE                               0x1
+#define SUBMBCEN_MBCEN_DISABLE                              0x0
+
+// *** SUBMBCCTL ***
+#define FB_SUBMBCCTL_LVLMODE3                               5
+#define FM_SUBMBCCTL_LVLMODE3                               0x20
+
+#define FB_SUBMBCCTL_WINSEL3                                4
+#define FM_SUBMBCCTL_WINSEL3                                0x10
+
+#define FB_SUBMBCCTL_LVLMODE2                               3
+#define FM_SUBMBCCTL_LVLMODE2                               0x8
+
+#define FB_SUBMBCCTL_WINSEL2                                2
+#define FM_SUBMBCCTL_WINSEL2                                0x4
+
+#define FB_SUBMBCCTL_LVLMODE1                               1
+#define FM_SUBMBCCTL_LVLMODE1                               0x2
+
+#define FB_SUBMBCCTL_WINSEL1                                0
+#define FM_SUBMBCCTL_WINSEL1                                0x1
+
+// *** SUBCLECTL ***
+#define FB_SUBCLECTL_LVLMODE                                4
+#define FM_SUBCLECTL_LVLMODE                                0x10
+
+#define FB_SUBCLECTL_WINSEL                                 3
+#define FM_SUBCLECTL_WINSEL                                 0x8
+
+#define FB_SUBCLECTL_EXPEN                                  2
+#define FM_SUBCLECTL_EXPEN                                  0x4
+#define FV_EXPEN_ENABLE                                     0x4
+#define FV_EXPEN_DISABLE                                    0x0
+
+#define FB_SUBCLECTL_LIMEN                                  1
+#define FM_SUBCLECTL_LIMEN                                  0x2
+#define FV_LIMEN_ENABLE                                     0x2
+#define FV_LIMEN_DISABLE                                    0x0
+
+#define FB_SUBCLECTL_COMPEN                                 0
+#define FM_SUBCLECTL_COMPEN                                 0x1
+#define FV_COMPEN_ENABLE                                    0x1
+#define FV_COMPEN_DISABLE                                   0x0
+
+// *** SUBCLEMUG ***
+#define FB_SUBCLEMUG_MUGAIN                                 0
+#define FM_SUBCLEMUG_MUGAIN                                 0x1F
+
+// *** SUBCOMPTHR ***
+#define FB_SUBCOMPTHR_THRESH                                0
+#define FM_SUBCOMPTHR_THRESH                                0xFF
+
+// *** SUBCOMPRAT ***
+#define FB_SUBCOMPRAT_RATIO                                 0
+#define FM_SUBCOMPRAT_RATIO                                 0x1F
+
+// *** SUBCOMPATKL ***
+#define FB_SUBCOMPATKL_TCATKL                               0
+#define FM_SUBCOMPATKL_TCATKL                               0xFF
+
+// *** SUBCOMPATKH ***
+#define FB_SUBCOMPATKH_TCATKH                               0
+#define FM_SUBCOMPATKH_TCATKH                               0xFF
+
+// *** SUBCOMPRELL ***
+#define FB_SUBCOMPRELL_TCRELL                               0
+#define FM_SUBCOMPRELL_TCRELL                               0xFF
+
+// *** SUBCOMPRELH ***
+#define FB_SUBCOMPRELH_TCRELH                               0
+#define FM_SUBCOMPRELH_TCRELH                               0xFF
+
+// *** SUBLIMTHR ***
+#define FB_SUBLIMTHR_THRESH                                 0
+#define FM_SUBLIMTHR_THRESH                                 0xFF
+
+// *** SUBLIMTGT ***
+#define FB_SUBLIMTGT_TARGET                                 0
+#define FM_SUBLIMTGT_TARGET                                 0xFF
+
+// *** SUBLIMATKL ***
+#define FB_SUBLIMATKL_TCATKL                                0
+#define FM_SUBLIMATKL_TCATKL                                0xFF
+
+// *** SUBLIMATKH ***
+#define FB_SUBLIMATKH_TCATKH                                0
+#define FM_SUBLIMATKH_TCATKH                                0xFF
+
+// *** SUBLIMRELL ***
+#define FB_SUBLIMRELL_TCRELL                                0
+#define FM_SUBLIMRELL_TCRELL                                0xFF
+
+// *** SUBLIMRELH ***
+#define FB_SUBLIMRELH_TCRELH                                0
+#define FM_SUBLIMRELH_TCRELH                                0xFF
+
+// *** SUBEXPTHR ***
+#define FB_SUBEXPTHR_THRESH                                 0
+#define FM_SUBEXPTHR_THRESH                                 0xFF
+
+// *** SUBEXPRAT ***
+#define FB_SUBEXPRAT_RATIO                                  0
+#define FM_SUBEXPRAT_RATIO                                  0x7
+
+// *** SUBEXPATKL ***
+#define FB_SUBEXPATKL_TCATKL                                0
+#define FM_SUBEXPATKL_TCATKL                                0xFF
+
+// *** SUBEXPATKH ***
+#define FB_SUBEXPATKH_TCATKH                                0
+#define FM_SUBEXPATKH_TCATKH                                0xFF
+
+// *** SUBEXPRELL ***
+#define FB_SUBEXPRELL_TCRELL                                0
+#define FM_SUBEXPRELL_TCRELL                                0xFF
+
+// *** SUBEXPRELH ***
+#define FB_SUBEXPRELH_TCRELH                                0
+#define FM_SUBEXPRELH_TCRELH                                0xFF
+
+// *** SUBFXCTL ***
+#define FB_SUBFXCTL_TEEN                                    3
+#define FM_SUBFXCTL_TEEN                                    0x8
+
+#define FB_SUBFXCTL_TNLFBYP                                 2
+#define FM_SUBFXCTL_TNLFBYP                                 0x4
+
+#define FB_SUBFXCTL_BEEN                                    1
+#define FM_SUBFXCTL_BEEN                                    0x2
+
+#define FB_SUBFXCTL_BNLFBYP                                 0
+#define FM_SUBFXCTL_BNLFBYP                                 0x1
+
+#endif /* __REDWOODPUBLIC_H__ */
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
new file mode 100644
index 0000000..25b752c
--- /dev/null
+++ b/sound/soc/codecs/twl4030.c
@@ -0,0 +1,2230 @@
+/*
+ * ALSA SoC TWL4030 codec driver
+ *
+ * Author:      Steve Sakoman, <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/mfd/twl.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+/* Register descriptions are here */
+#include <linux/mfd/twl4030-audio.h>
+
+/* TWL4030 PMBR1 Register */
+#define TWL4030_PMBR1_REG		0x0D
+/* TWL4030 PMBR1 Register GPIO6 mux bits */
+#define TWL4030_GPIO6_PWM0_MUTE(value)	((value & 0x03) << 2)
+
+#define TWL4030_CACHEREGNUM	(TWL4030_REG_MISC_SET_2 + 1)
+
+/* codec private data */
+struct twl4030_priv {
+	unsigned int codec_powered;
+
+	/* reference counts of AIF/APLL users */
+	unsigned int apll_enabled;
+
+	struct snd_pcm_substream *master_substream;
+	struct snd_pcm_substream *slave_substream;
+
+	unsigned int configured;
+	unsigned int rate;
+	unsigned int sample_bits;
+	unsigned int channels;
+
+	unsigned int sysclk;
+
+	/* Output (with associated amp) states */
+	u8 hsl_enabled, hsr_enabled;
+	u8 earpiece_enabled;
+	u8 predrivel_enabled, predriver_enabled;
+	u8 carkitl_enabled, carkitr_enabled;
+	u8 ctl_cache[TWL4030_REG_PRECKR_CTL - TWL4030_REG_EAR_CTL + 1];
+
+	struct twl4030_codec_data *pdata;
+};
+
+static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030)
+{
+	int i;
+	u8 byte;
+
+	for (i = TWL4030_REG_EAR_CTL; i <= TWL4030_REG_PRECKR_CTL; i++) {
+		twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, i);
+		twl4030->ctl_cache[i - TWL4030_REG_EAR_CTL] = byte;
+	}
+}
+
+static unsigned int twl4030_read(struct snd_soc_component *component, unsigned int reg)
+{
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+	u8 value = 0;
+
+	if (reg >= TWL4030_CACHEREGNUM)
+		return -EIO;
+
+	switch (reg) {
+	case TWL4030_REG_EAR_CTL:
+	case TWL4030_REG_PREDL_CTL:
+	case TWL4030_REG_PREDR_CTL:
+	case TWL4030_REG_PRECKL_CTL:
+	case TWL4030_REG_PRECKR_CTL:
+	case TWL4030_REG_HS_GAIN_SET:
+		value = twl4030->ctl_cache[reg - TWL4030_REG_EAR_CTL];
+		break;
+	default:
+		twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &value, reg);
+		break;
+	}
+
+	return value;
+}
+
+static bool twl4030_can_write_to_chip(struct twl4030_priv *twl4030,
+				      unsigned int reg)
+{
+	bool write_to_reg = false;
+
+	/* Decide if the given register can be written */
+	switch (reg) {
+	case TWL4030_REG_EAR_CTL:
+		if (twl4030->earpiece_enabled)
+			write_to_reg = true;
+		break;
+	case TWL4030_REG_PREDL_CTL:
+		if (twl4030->predrivel_enabled)
+			write_to_reg = true;
+		break;
+	case TWL4030_REG_PREDR_CTL:
+		if (twl4030->predriver_enabled)
+			write_to_reg = true;
+		break;
+	case TWL4030_REG_PRECKL_CTL:
+		if (twl4030->carkitl_enabled)
+			write_to_reg = true;
+		break;
+	case TWL4030_REG_PRECKR_CTL:
+		if (twl4030->carkitr_enabled)
+			write_to_reg = true;
+		break;
+	case TWL4030_REG_HS_GAIN_SET:
+		if (twl4030->hsl_enabled || twl4030->hsr_enabled)
+			write_to_reg = true;
+		break;
+	default:
+		/* All other register can be written */
+		write_to_reg = true;
+		break;
+	}
+
+	return write_to_reg;
+}
+
+static int twl4030_write(struct snd_soc_component *component, unsigned int reg,
+			 unsigned int value)
+{
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+
+	/* Update the ctl cache */
+	switch (reg) {
+	case TWL4030_REG_EAR_CTL:
+	case TWL4030_REG_PREDL_CTL:
+	case TWL4030_REG_PREDR_CTL:
+	case TWL4030_REG_PRECKL_CTL:
+	case TWL4030_REG_PRECKR_CTL:
+	case TWL4030_REG_HS_GAIN_SET:
+		twl4030->ctl_cache[reg - TWL4030_REG_EAR_CTL] = value;
+		break;
+	default:
+		break;
+	}
+
+	if (twl4030_can_write_to_chip(twl4030, reg))
+		return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
+
+	return 0;
+}
+
+static inline void twl4030_wait_ms(int time)
+{
+	if (time < 60) {
+		time *= 1000;
+		usleep_range(time, time + 500);
+	} else {
+		msleep(time);
+	}
+}
+
+static void twl4030_codec_enable(struct snd_soc_component *component, int enable)
+{
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+	int mode;
+
+	if (enable == twl4030->codec_powered)
+		return;
+
+	if (enable)
+		mode = twl4030_audio_enable_resource(TWL4030_AUDIO_RES_POWER);
+	else
+		mode = twl4030_audio_disable_resource(TWL4030_AUDIO_RES_POWER);
+
+	if (mode >= 0)
+		twl4030->codec_powered = enable;
+
+	/* REVISIT: this delay is present in TI sample drivers */
+	/* but there seems to be no TRM requirement for it     */
+	udelay(10);
+}
+
+static void twl4030_setup_pdata_of(struct twl4030_codec_data *pdata,
+				   struct device_node *node)
+{
+	int value;
+
+	of_property_read_u32(node, "ti,digimic_delay",
+			     &pdata->digimic_delay);
+	of_property_read_u32(node, "ti,ramp_delay_value",
+			     &pdata->ramp_delay_value);
+	of_property_read_u32(node, "ti,offset_cncl_path",
+			     &pdata->offset_cncl_path);
+	if (!of_property_read_u32(node, "ti,hs_extmute", &value))
+		pdata->hs_extmute = value;
+
+	pdata->hs_extmute_gpio = of_get_named_gpio(node,
+						   "ti,hs_extmute_gpio", 0);
+	if (gpio_is_valid(pdata->hs_extmute_gpio))
+		pdata->hs_extmute = 1;
+}
+
+static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_component *component)
+{
+	struct twl4030_codec_data *pdata = dev_get_platdata(component->dev);
+	struct device_node *twl4030_codec_node = NULL;
+
+	twl4030_codec_node = of_get_child_by_name(component->dev->parent->of_node,
+						  "codec");
+
+	if (!pdata && twl4030_codec_node) {
+		pdata = devm_kzalloc(component->dev,
+				     sizeof(struct twl4030_codec_data),
+				     GFP_KERNEL);
+		if (!pdata) {
+			of_node_put(twl4030_codec_node);
+			return NULL;
+		}
+		twl4030_setup_pdata_of(pdata, twl4030_codec_node);
+		of_node_put(twl4030_codec_node);
+	}
+
+	return pdata;
+}
+
+static void twl4030_init_chip(struct snd_soc_component *component)
+{
+	struct twl4030_codec_data *pdata;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+	u8 reg, byte;
+	int i = 0;
+
+	pdata = twl4030_get_pdata(component);
+
+	if (pdata && pdata->hs_extmute) {
+		if (gpio_is_valid(pdata->hs_extmute_gpio)) {
+			int ret;
+
+			if (!pdata->hs_extmute_gpio)
+				dev_warn(component->dev,
+					"Extmute GPIO is 0 is this correct?\n");
+
+			ret = gpio_request_one(pdata->hs_extmute_gpio,
+					       GPIOF_OUT_INIT_LOW,
+					       "hs_extmute");
+			if (ret) {
+				dev_err(component->dev,
+					"Failed to get hs_extmute GPIO\n");
+				pdata->hs_extmute_gpio = -1;
+			}
+		} else {
+			u8 pin_mux;
+
+			/* Set TWL4030 GPIO6 as EXTMUTE signal */
+			twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux,
+					TWL4030_PMBR1_REG);
+			pin_mux &= ~TWL4030_GPIO6_PWM0_MUTE(0x03);
+			pin_mux |= TWL4030_GPIO6_PWM0_MUTE(0x02);
+			twl_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux,
+					 TWL4030_PMBR1_REG);
+		}
+	}
+
+	/* Initialize the local ctl register cache */
+	tw4030_init_ctl_cache(twl4030);
+
+	/* anti-pop when changing analog gain */
+	reg = twl4030_read(component, TWL4030_REG_MISC_SET_1);
+	twl4030_write(component, TWL4030_REG_MISC_SET_1,
+		      reg | TWL4030_SMOOTH_ANAVOL_EN);
+
+	twl4030_write(component, TWL4030_REG_OPTION,
+		      TWL4030_ATXL1_EN | TWL4030_ATXR1_EN |
+		      TWL4030_ARXL2_EN | TWL4030_ARXR2_EN);
+
+	/* REG_ARXR2_APGA_CTL reset according to the TRM: 0dB, DA_EN */
+	twl4030_write(component, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
+
+	/* Machine dependent setup */
+	if (!pdata)
+		return;
+
+	twl4030->pdata = pdata;
+
+	reg = twl4030_read(component, TWL4030_REG_HS_POPN_SET);
+	reg &= ~TWL4030_RAMP_DELAY;
+	reg |= (pdata->ramp_delay_value << 2);
+	twl4030_write(component, TWL4030_REG_HS_POPN_SET, reg);
+
+	/* initiate offset cancellation */
+	twl4030_codec_enable(component, 1);
+
+	reg = twl4030_read(component, TWL4030_REG_ANAMICL);
+	reg &= ~TWL4030_OFFSET_CNCL_SEL;
+	reg |= pdata->offset_cncl_path;
+	twl4030_write(component, TWL4030_REG_ANAMICL,
+		      reg | TWL4030_CNCL_OFFSET_START);
+
+	/*
+	 * Wait for offset cancellation to complete.
+	 * Since this takes a while, do not slam the i2c.
+	 * Start polling the status after ~20ms.
+	 */
+	msleep(20);
+	do {
+		usleep_range(1000, 2000);
+		twl_set_regcache_bypass(TWL4030_MODULE_AUDIO_VOICE, true);
+		twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
+				TWL4030_REG_ANAMICL);
+		twl_set_regcache_bypass(TWL4030_MODULE_AUDIO_VOICE, false);
+	} while ((i++ < 100) &&
+		 ((byte & TWL4030_CNCL_OFFSET_START) ==
+		  TWL4030_CNCL_OFFSET_START));
+
+	twl4030_codec_enable(component, 0);
+}
+
+static void twl4030_apll_enable(struct snd_soc_component *component, int enable)
+{
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+
+	if (enable) {
+		twl4030->apll_enabled++;
+		if (twl4030->apll_enabled == 1)
+			twl4030_audio_enable_resource(
+							TWL4030_AUDIO_RES_APLL);
+	} else {
+		twl4030->apll_enabled--;
+		if (!twl4030->apll_enabled)
+			twl4030_audio_disable_resource(
+							TWL4030_AUDIO_RES_APLL);
+	}
+}
+
+/* Earpiece */
+static const struct snd_kcontrol_new twl4030_dapm_earpiece_controls[] = {
+	SOC_DAPM_SINGLE("Voice", TWL4030_REG_EAR_CTL, 0, 1, 0),
+	SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_EAR_CTL, 1, 1, 0),
+	SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_EAR_CTL, 2, 1, 0),
+	SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_EAR_CTL, 3, 1, 0),
+};
+
+/* PreDrive Left */
+static const struct snd_kcontrol_new twl4030_dapm_predrivel_controls[] = {
+	SOC_DAPM_SINGLE("Voice", TWL4030_REG_PREDL_CTL, 0, 1, 0),
+	SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_PREDL_CTL, 1, 1, 0),
+	SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PREDL_CTL, 2, 1, 0),
+	SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PREDL_CTL, 3, 1, 0),
+};
+
+/* PreDrive Right */
+static const struct snd_kcontrol_new twl4030_dapm_predriver_controls[] = {
+	SOC_DAPM_SINGLE("Voice", TWL4030_REG_PREDR_CTL, 0, 1, 0),
+	SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_PREDR_CTL, 1, 1, 0),
+	SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PREDR_CTL, 2, 1, 0),
+	SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PREDR_CTL, 3, 1, 0),
+};
+
+/* Headset Left */
+static const struct snd_kcontrol_new twl4030_dapm_hsol_controls[] = {
+	SOC_DAPM_SINGLE("Voice", TWL4030_REG_HS_SEL, 0, 1, 0),
+	SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_HS_SEL, 1, 1, 0),
+	SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_HS_SEL, 2, 1, 0),
+};
+
+/* Headset Right */
+static const struct snd_kcontrol_new twl4030_dapm_hsor_controls[] = {
+	SOC_DAPM_SINGLE("Voice", TWL4030_REG_HS_SEL, 3, 1, 0),
+	SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_HS_SEL, 4, 1, 0),
+	SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_HS_SEL, 5, 1, 0),
+};
+
+/* Carkit Left */
+static const struct snd_kcontrol_new twl4030_dapm_carkitl_controls[] = {
+	SOC_DAPM_SINGLE("Voice", TWL4030_REG_PRECKL_CTL, 0, 1, 0),
+	SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_PRECKL_CTL, 1, 1, 0),
+	SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PRECKL_CTL, 2, 1, 0),
+};
+
+/* Carkit Right */
+static const struct snd_kcontrol_new twl4030_dapm_carkitr_controls[] = {
+	SOC_DAPM_SINGLE("Voice", TWL4030_REG_PRECKR_CTL, 0, 1, 0),
+	SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_PRECKR_CTL, 1, 1, 0),
+	SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PRECKR_CTL, 2, 1, 0),
+};
+
+/* Handsfree Left */
+static const char *twl4030_handsfreel_texts[] =
+		{"Voice", "AudioL1", "AudioL2", "AudioR2"};
+
+static SOC_ENUM_SINGLE_DECL(twl4030_handsfreel_enum,
+			    TWL4030_REG_HFL_CTL, 0,
+			    twl4030_handsfreel_texts);
+
+static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control =
+SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum);
+
+/* Handsfree Left virtual mute */
+static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control =
+	SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+/* Handsfree Right */
+static const char *twl4030_handsfreer_texts[] =
+		{"Voice", "AudioR1", "AudioR2", "AudioL2"};
+
+static SOC_ENUM_SINGLE_DECL(twl4030_handsfreer_enum,
+			    TWL4030_REG_HFR_CTL, 0,
+			    twl4030_handsfreer_texts);
+
+static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control =
+SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum);
+
+/* Handsfree Right virtual mute */
+static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control =
+	SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+/* Vibra */
+/* Vibra audio path selection */
+static const char *twl4030_vibra_texts[] =
+		{"AudioL1", "AudioR1", "AudioL2", "AudioR2"};
+
+static SOC_ENUM_SINGLE_DECL(twl4030_vibra_enum,
+			    TWL4030_REG_VIBRA_CTL, 2,
+			    twl4030_vibra_texts);
+
+static const struct snd_kcontrol_new twl4030_dapm_vibra_control =
+SOC_DAPM_ENUM("Route", twl4030_vibra_enum);
+
+/* Vibra path selection: local vibrator (PWM) or audio driven */
+static const char *twl4030_vibrapath_texts[] =
+		{"Local vibrator", "Audio"};
+
+static SOC_ENUM_SINGLE_DECL(twl4030_vibrapath_enum,
+			    TWL4030_REG_VIBRA_CTL, 4,
+			    twl4030_vibrapath_texts);
+
+static const struct snd_kcontrol_new twl4030_dapm_vibrapath_control =
+SOC_DAPM_ENUM("Route", twl4030_vibrapath_enum);
+
+/* Left analog microphone selection */
+static const struct snd_kcontrol_new twl4030_dapm_analoglmic_controls[] = {
+	SOC_DAPM_SINGLE("Main Mic Capture Switch",
+			TWL4030_REG_ANAMICL, 0, 1, 0),
+	SOC_DAPM_SINGLE("Headset Mic Capture Switch",
+			TWL4030_REG_ANAMICL, 1, 1, 0),
+	SOC_DAPM_SINGLE("AUXL Capture Switch",
+			TWL4030_REG_ANAMICL, 2, 1, 0),
+	SOC_DAPM_SINGLE("Carkit Mic Capture Switch",
+			TWL4030_REG_ANAMICL, 3, 1, 0),
+};
+
+/* Right analog microphone selection */
+static const struct snd_kcontrol_new twl4030_dapm_analogrmic_controls[] = {
+	SOC_DAPM_SINGLE("Sub Mic Capture Switch", TWL4030_REG_ANAMICR, 0, 1, 0),
+	SOC_DAPM_SINGLE("AUXR Capture Switch", TWL4030_REG_ANAMICR, 2, 1, 0),
+};
+
+/* TX1 L/R Analog/Digital microphone selection */
+static const char *twl4030_micpathtx1_texts[] =
+		{"Analog", "Digimic0"};
+
+static SOC_ENUM_SINGLE_DECL(twl4030_micpathtx1_enum,
+			    TWL4030_REG_ADCMICSEL, 0,
+			    twl4030_micpathtx1_texts);
+
+static const struct snd_kcontrol_new twl4030_dapm_micpathtx1_control =
+SOC_DAPM_ENUM("Route", twl4030_micpathtx1_enum);
+
+/* TX2 L/R Analog/Digital microphone selection */
+static const char *twl4030_micpathtx2_texts[] =
+		{"Analog", "Digimic1"};
+
+static SOC_ENUM_SINGLE_DECL(twl4030_micpathtx2_enum,
+			    TWL4030_REG_ADCMICSEL, 2,
+			    twl4030_micpathtx2_texts);
+
+static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control =
+SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum);
+
+/* Analog bypass for AudioR1 */
+static const struct snd_kcontrol_new twl4030_dapm_abypassr1_control =
+	SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXR1_APGA_CTL, 2, 1, 0);
+
+/* Analog bypass for AudioL1 */
+static const struct snd_kcontrol_new twl4030_dapm_abypassl1_control =
+	SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXL1_APGA_CTL, 2, 1, 0);
+
+/* Analog bypass for AudioR2 */
+static const struct snd_kcontrol_new twl4030_dapm_abypassr2_control =
+	SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXR2_APGA_CTL, 2, 1, 0);
+
+/* Analog bypass for AudioL2 */
+static const struct snd_kcontrol_new twl4030_dapm_abypassl2_control =
+	SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXL2_APGA_CTL, 2, 1, 0);
+
+/* Analog bypass for Voice */
+static const struct snd_kcontrol_new twl4030_dapm_abypassv_control =
+	SOC_DAPM_SINGLE("Switch", TWL4030_REG_VDL_APGA_CTL, 2, 1, 0);
+
+/* Digital bypass gain, mute instead of -30dB */
+static const DECLARE_TLV_DB_RANGE(twl4030_dapm_dbypass_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(-3000, 600, 1),
+	2, 3, TLV_DB_SCALE_ITEM(-2400, 0, 0),
+	4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0)
+);
+
+/* Digital bypass left (TX1L -> RX2L) */
+static const struct snd_kcontrol_new twl4030_dapm_dbypassl_control =
+	SOC_DAPM_SINGLE_TLV("Volume",
+			TWL4030_REG_ATX2ARXPGA, 3, 7, 0,
+			twl4030_dapm_dbypass_tlv);
+
+/* Digital bypass right (TX1R -> RX2R) */
+static const struct snd_kcontrol_new twl4030_dapm_dbypassr_control =
+	SOC_DAPM_SINGLE_TLV("Volume",
+			TWL4030_REG_ATX2ARXPGA, 0, 7, 0,
+			twl4030_dapm_dbypass_tlv);
+
+/*
+ * Voice Sidetone GAIN volume control:
+ * from -51 to -10 dB in 1 dB steps (mute instead of -51 dB)
+ */
+static DECLARE_TLV_DB_SCALE(twl4030_dapm_dbypassv_tlv, -5100, 100, 1);
+
+/* Digital bypass voice: sidetone (VUL -> VDL)*/
+static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =
+	SOC_DAPM_SINGLE_TLV("Volume",
+			TWL4030_REG_VSTPGA, 0, 0x29, 0,
+			twl4030_dapm_dbypassv_tlv);
+
+/*
+ * Output PGA builder:
+ * Handle the muting and unmuting of the given output (turning off the
+ * amplifier associated with the output pin)
+ * On mute bypass the reg_cache and write 0 to the register
+ * On unmute: restore the register content from the reg_cache
+ * Outputs handled in this way:  Earpiece, PreDrivL/R, CarkitL/R
+ */
+#define TWL4030_OUTPUT_PGA(pin_name, reg, mask)				\
+static int pin_name##pga_event(struct snd_soc_dapm_widget *w,		\
+			       struct snd_kcontrol *kcontrol, int event) \
+{									\
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);	\
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component); \
+									\
+	switch (event) {						\
+	case SND_SOC_DAPM_POST_PMU:					\
+		twl4030->pin_name##_enabled = 1;			\
+		twl4030_write(component, reg, twl4030_read(component, reg));	\
+		break;							\
+	case SND_SOC_DAPM_POST_PMD:					\
+		twl4030->pin_name##_enabled = 0;			\
+		twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, 0, reg);	\
+		break;							\
+	}								\
+	return 0;							\
+}
+
+TWL4030_OUTPUT_PGA(earpiece, TWL4030_REG_EAR_CTL, TWL4030_EAR_GAIN);
+TWL4030_OUTPUT_PGA(predrivel, TWL4030_REG_PREDL_CTL, TWL4030_PREDL_GAIN);
+TWL4030_OUTPUT_PGA(predriver, TWL4030_REG_PREDR_CTL, TWL4030_PREDR_GAIN);
+TWL4030_OUTPUT_PGA(carkitl, TWL4030_REG_PRECKL_CTL, TWL4030_PRECKL_GAIN);
+TWL4030_OUTPUT_PGA(carkitr, TWL4030_REG_PRECKR_CTL, TWL4030_PRECKR_GAIN);
+
+static void handsfree_ramp(struct snd_soc_component *component, int reg, int ramp)
+{
+	unsigned char hs_ctl;
+
+	hs_ctl = twl4030_read(component, reg);
+
+	if (ramp) {
+		/* HF ramp-up */
+		hs_ctl |= TWL4030_HF_CTL_REF_EN;
+		twl4030_write(component, reg, hs_ctl);
+		udelay(10);
+		hs_ctl |= TWL4030_HF_CTL_RAMP_EN;
+		twl4030_write(component, reg, hs_ctl);
+		udelay(40);
+		hs_ctl |= TWL4030_HF_CTL_LOOP_EN;
+		hs_ctl |= TWL4030_HF_CTL_HB_EN;
+		twl4030_write(component, reg, hs_ctl);
+	} else {
+		/* HF ramp-down */
+		hs_ctl &= ~TWL4030_HF_CTL_LOOP_EN;
+		hs_ctl &= ~TWL4030_HF_CTL_HB_EN;
+		twl4030_write(component, reg, hs_ctl);
+		hs_ctl &= ~TWL4030_HF_CTL_RAMP_EN;
+		twl4030_write(component, reg, hs_ctl);
+		udelay(40);
+		hs_ctl &= ~TWL4030_HF_CTL_REF_EN;
+		twl4030_write(component, reg, hs_ctl);
+	}
+}
+
+static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		handsfree_ramp(component, TWL4030_REG_HFL_CTL, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		handsfree_ramp(component, TWL4030_REG_HFL_CTL, 0);
+		break;
+	}
+	return 0;
+}
+
+static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		handsfree_ramp(component, TWL4030_REG_HFR_CTL, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		handsfree_ramp(component, TWL4030_REG_HFR_CTL, 0);
+		break;
+	}
+	return 0;
+}
+
+static int vibramux_event(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	twl4030_write(component, TWL4030_REG_VIBRA_SET, 0xff);
+	return 0;
+}
+
+static int apll_event(struct snd_soc_dapm_widget *w,
+		      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		twl4030_apll_enable(component, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		twl4030_apll_enable(component, 0);
+		break;
+	}
+	return 0;
+}
+
+static int aif_event(struct snd_soc_dapm_widget *w,
+		     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u8 audio_if;
+
+	audio_if = twl4030_read(component, TWL4030_REG_AUDIO_IF);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Enable AIF */
+		/* enable the PLL before we use it to clock the DAI */
+		twl4030_apll_enable(component, 1);
+
+		twl4030_write(component, TWL4030_REG_AUDIO_IF,
+			      audio_if | TWL4030_AIF_EN);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* disable the DAI before we stop it's source PLL */
+		twl4030_write(component, TWL4030_REG_AUDIO_IF,
+			      audio_if &  ~TWL4030_AIF_EN);
+		twl4030_apll_enable(component, 0);
+		break;
+	}
+	return 0;
+}
+
+static void headset_ramp(struct snd_soc_component *component, int ramp)
+{
+	unsigned char hs_gain, hs_pop;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+	struct twl4030_codec_data *pdata = twl4030->pdata;
+	/* Base values for ramp delay calculation: 2^19 - 2^26 */
+	unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
+				    8388608, 16777216, 33554432, 67108864};
+	unsigned int delay;
+
+	hs_gain = twl4030_read(component, TWL4030_REG_HS_GAIN_SET);
+	hs_pop = twl4030_read(component, TWL4030_REG_HS_POPN_SET);
+	delay = (ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
+		twl4030->sysclk) + 1;
+
+	/* Enable external mute control, this dramatically reduces
+	 * the pop-noise */
+	if (pdata && pdata->hs_extmute) {
+		if (gpio_is_valid(pdata->hs_extmute_gpio)) {
+			gpio_set_value(pdata->hs_extmute_gpio, 1);
+		} else {
+			hs_pop |= TWL4030_EXTMUTE;
+			twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
+		}
+	}
+
+	if (ramp) {
+		/* Headset ramp-up according to the TRM */
+		hs_pop |= TWL4030_VMID_EN;
+		twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
+		/* Actually write to the register */
+		twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain,
+				 TWL4030_REG_HS_GAIN_SET);
+		hs_pop |= TWL4030_RAMP_EN;
+		twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
+		/* Wait ramp delay time + 1, so the VMID can settle */
+		twl4030_wait_ms(delay);
+	} else {
+		/* Headset ramp-down _not_ according to
+		 * the TRM, but in a way that it is working */
+		hs_pop &= ~TWL4030_RAMP_EN;
+		twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
+		/* Wait ramp delay time + 1, so the VMID can settle */
+		twl4030_wait_ms(delay);
+		/* Bypass the reg_cache to mute the headset */
+		twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain & (~0x0f),
+				 TWL4030_REG_HS_GAIN_SET);
+
+		hs_pop &= ~TWL4030_VMID_EN;
+		twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
+	}
+
+	/* Disable external mute */
+	if (pdata && pdata->hs_extmute) {
+		if (gpio_is_valid(pdata->hs_extmute_gpio)) {
+			gpio_set_value(pdata->hs_extmute_gpio, 0);
+		} else {
+			hs_pop &= ~TWL4030_EXTMUTE;
+			twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
+		}
+	}
+}
+
+static int headsetlpga_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Do the ramp-up only once */
+		if (!twl4030->hsr_enabled)
+			headset_ramp(component, 1);
+
+		twl4030->hsl_enabled = 1;
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Do the ramp-down only if both headsetL/R is disabled */
+		if (!twl4030->hsr_enabled)
+			headset_ramp(component, 0);
+
+		twl4030->hsl_enabled = 0;
+		break;
+	}
+	return 0;
+}
+
+static int headsetrpga_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Do the ramp-up only once */
+		if (!twl4030->hsl_enabled)
+			headset_ramp(component, 1);
+
+		twl4030->hsr_enabled = 1;
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* Do the ramp-down only if both headsetL/R is disabled */
+		if (!twl4030->hsl_enabled)
+			headset_ramp(component, 0);
+
+		twl4030->hsr_enabled = 0;
+		break;
+	}
+	return 0;
+}
+
+static int digimic_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+	struct twl4030_codec_data *pdata = twl4030->pdata;
+
+	if (pdata && pdata->digimic_delay)
+		twl4030_wait_ms(pdata->digimic_delay);
+	return 0;
+}
+
+/*
+ * Some of the gain controls in TWL (mostly those which are associated with
+ * the outputs) are implemented in an interesting way:
+ * 0x0 : Power down (mute)
+ * 0x1 : 6dB
+ * 0x2 : 0 dB
+ * 0x3 : -6 dB
+ * Inverting not going to help with these.
+ * Custom volsw and volsw_2r get/put functions to handle these gain bits.
+ */
+static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int shift = mc->shift;
+	unsigned int rshift = mc->rshift;
+	int max = mc->max;
+	int mask = (1 << fls(max)) - 1;
+
+	ucontrol->value.integer.value[0] =
+		(twl4030_read(component, reg) >> shift) & mask;
+	if (ucontrol->value.integer.value[0])
+		ucontrol->value.integer.value[0] =
+			max + 1 - ucontrol->value.integer.value[0];
+
+	if (shift != rshift) {
+		ucontrol->value.integer.value[1] =
+			(twl4030_read(component, reg) >> rshift) & mask;
+		if (ucontrol->value.integer.value[1])
+			ucontrol->value.integer.value[1] =
+				max + 1 - ucontrol->value.integer.value[1];
+	}
+
+	return 0;
+}
+
+static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int shift = mc->shift;
+	unsigned int rshift = mc->rshift;
+	int max = mc->max;
+	int mask = (1 << fls(max)) - 1;
+	unsigned short val, val2, val_mask;
+
+	val = (ucontrol->value.integer.value[0] & mask);
+
+	val_mask = mask << shift;
+	if (val)
+		val = max + 1 - val;
+	val = val << shift;
+	if (shift != rshift) {
+		val2 = (ucontrol->value.integer.value[1] & mask);
+		val_mask |= mask << rshift;
+		if (val2)
+			val2 = max + 1 - val2;
+		val |= val2 << rshift;
+	}
+	return snd_soc_component_update_bits(component, reg, val_mask, val);
+}
+
+static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	unsigned int shift = mc->shift;
+	int max = mc->max;
+	int mask = (1<<fls(max))-1;
+
+	ucontrol->value.integer.value[0] =
+		(twl4030_read(component, reg) >> shift) & mask;
+	ucontrol->value.integer.value[1] =
+		(twl4030_read(component, reg2) >> shift) & mask;
+
+	if (ucontrol->value.integer.value[0])
+		ucontrol->value.integer.value[0] =
+			max + 1 - ucontrol->value.integer.value[0];
+	if (ucontrol->value.integer.value[1])
+		ucontrol->value.integer.value[1] =
+			max + 1 - ucontrol->value.integer.value[1];
+
+	return 0;
+}
+
+static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	unsigned int shift = mc->shift;
+	int max = mc->max;
+	int mask = (1 << fls(max)) - 1;
+	int err;
+	unsigned short val, val2, val_mask;
+
+	val_mask = mask << shift;
+	val = (ucontrol->value.integer.value[0] & mask);
+	val2 = (ucontrol->value.integer.value[1] & mask);
+
+	if (val)
+		val = max + 1 - val;
+	if (val2)
+		val2 = max + 1 - val2;
+
+	val = val << shift;
+	val2 = val2 << shift;
+
+	err = snd_soc_component_update_bits(component, reg, val_mask, val);
+	if (err < 0)
+		return err;
+
+	err = snd_soc_component_update_bits(component, reg2, val_mask, val2);
+	return err;
+}
+
+/* Codec operation modes */
+static const char *twl4030_op_modes_texts[] = {
+	"Option 2 (voice/audio)", "Option 1 (audio)"
+};
+
+static SOC_ENUM_SINGLE_DECL(twl4030_op_modes_enum,
+			    TWL4030_REG_CODEC_MODE, 0,
+			    twl4030_op_modes_texts);
+
+static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+
+	if (twl4030->configured) {
+		dev_err(component->dev,
+			"operation mode cannot be changed on-the-fly\n");
+		return -EBUSY;
+	}
+
+	return snd_soc_put_enum_double(kcontrol, ucontrol);
+}
+
+/*
+ * FGAIN volume control:
+ * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB)
+ */
+static DECLARE_TLV_DB_SCALE(digital_fine_tlv, -6300, 100, 1);
+
+/*
+ * CGAIN volume control:
+ * 0 dB to 12 dB in 6 dB steps
+ * value 2 and 3 means 12 dB
+ */
+static DECLARE_TLV_DB_SCALE(digital_coarse_tlv, 0, 600, 0);
+
+/*
+ * Voice Downlink GAIN volume control:
+ * from -37 to 12 dB in 1 dB steps (mute instead of -37 dB)
+ */
+static DECLARE_TLV_DB_SCALE(digital_voice_downlink_tlv, -3700, 100, 1);
+
+/*
+ * Analog playback gain
+ * -24 dB to 12 dB in 2 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(analog_tlv, -2400, 200, 0);
+
+/*
+ * Gain controls tied to outputs
+ * -6 dB to 6 dB in 6 dB steps (mute instead of -12)
+ */
+static DECLARE_TLV_DB_SCALE(output_tvl, -1200, 600, 1);
+
+/*
+ * Gain control for earpiece amplifier
+ * 0 dB to 12 dB in 6 dB steps (mute instead of -6)
+ */
+static DECLARE_TLV_DB_SCALE(output_ear_tvl, -600, 600, 1);
+
+/*
+ * Capture gain after the ADCs
+ * from 0 dB to 31 dB in 1 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0);
+
+/*
+ * Gain control for input amplifiers
+ * 0 dB to 30 dB in 6 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0);
+
+/* AVADC clock priority */
+static const char *twl4030_avadc_clk_priority_texts[] = {
+	"Voice high priority", "HiFi high priority"
+};
+
+static SOC_ENUM_SINGLE_DECL(twl4030_avadc_clk_priority_enum,
+			    TWL4030_REG_AVADC_CTL, 2,
+			    twl4030_avadc_clk_priority_texts);
+
+static const char *twl4030_rampdelay_texts[] = {
+	"27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms",
+	"437/323/218 ms", "874/645/437 ms", "1748/1291/874 ms",
+	"3495/2581/1748 ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(twl4030_rampdelay_enum,
+			    TWL4030_REG_HS_POPN_SET, 2,
+			    twl4030_rampdelay_texts);
+
+/* Vibra H-bridge direction mode */
+static const char *twl4030_vibradirmode_texts[] = {
+	"Vibra H-bridge direction", "Audio data MSB",
+};
+
+static SOC_ENUM_SINGLE_DECL(twl4030_vibradirmode_enum,
+			    TWL4030_REG_VIBRA_CTL, 5,
+			    twl4030_vibradirmode_texts);
+
+/* Vibra H-bridge direction */
+static const char *twl4030_vibradir_texts[] = {
+	"Positive polarity", "Negative polarity",
+};
+
+static SOC_ENUM_SINGLE_DECL(twl4030_vibradir_enum,
+			    TWL4030_REG_VIBRA_CTL, 1,
+			    twl4030_vibradir_texts);
+
+/* Digimic Left and right swapping */
+static const char *twl4030_digimicswap_texts[] = {
+	"Not swapped", "Swapped",
+};
+
+static SOC_ENUM_SINGLE_DECL(twl4030_digimicswap_enum,
+			    TWL4030_REG_MISC_SET_1, 0,
+			    twl4030_digimicswap_texts);
+
+static const struct snd_kcontrol_new twl4030_snd_controls[] = {
+	/* Codec operation mode control */
+	SOC_ENUM_EXT("Codec Operation Mode", twl4030_op_modes_enum,
+		snd_soc_get_enum_double,
+		snd_soc_put_twl4030_opmode_enum_double),
+
+	/* Common playback gain controls */
+	SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume",
+		TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA,
+		0, 0x3f, 0, digital_fine_tlv),
+	SOC_DOUBLE_R_TLV("DAC2 Digital Fine Playback Volume",
+		TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA,
+		0, 0x3f, 0, digital_fine_tlv),
+
+	SOC_DOUBLE_R_TLV("DAC1 Digital Coarse Playback Volume",
+		TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA,
+		6, 0x2, 0, digital_coarse_tlv),
+	SOC_DOUBLE_R_TLV("DAC2 Digital Coarse Playback Volume",
+		TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA,
+		6, 0x2, 0, digital_coarse_tlv),
+
+	SOC_DOUBLE_R_TLV("DAC1 Analog Playback Volume",
+		TWL4030_REG_ARXL1_APGA_CTL, TWL4030_REG_ARXR1_APGA_CTL,
+		3, 0x12, 1, analog_tlv),
+	SOC_DOUBLE_R_TLV("DAC2 Analog Playback Volume",
+		TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL,
+		3, 0x12, 1, analog_tlv),
+	SOC_DOUBLE_R("DAC1 Analog Playback Switch",
+		TWL4030_REG_ARXL1_APGA_CTL, TWL4030_REG_ARXR1_APGA_CTL,
+		1, 1, 0),
+	SOC_DOUBLE_R("DAC2 Analog Playback Switch",
+		TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL,
+		1, 1, 0),
+
+	/* Common voice downlink gain controls */
+	SOC_SINGLE_TLV("DAC Voice Digital Downlink Volume",
+		TWL4030_REG_VRXPGA, 0, 0x31, 0, digital_voice_downlink_tlv),
+
+	SOC_SINGLE_TLV("DAC Voice Analog Downlink Volume",
+		TWL4030_REG_VDL_APGA_CTL, 3, 0x12, 1, analog_tlv),
+
+	SOC_SINGLE("DAC Voice Analog Downlink Switch",
+		TWL4030_REG_VDL_APGA_CTL, 1, 1, 0),
+
+	/* Separate output gain controls */
+	SOC_DOUBLE_R_EXT_TLV("PreDriv Playback Volume",
+		TWL4030_REG_PREDL_CTL, TWL4030_REG_PREDR_CTL,
+		4, 3, 0, snd_soc_get_volsw_r2_twl4030,
+		snd_soc_put_volsw_r2_twl4030, output_tvl),
+
+	SOC_DOUBLE_EXT_TLV("Headset Playback Volume",
+		TWL4030_REG_HS_GAIN_SET, 0, 2, 3, 0, snd_soc_get_volsw_twl4030,
+		snd_soc_put_volsw_twl4030, output_tvl),
+
+	SOC_DOUBLE_R_EXT_TLV("Carkit Playback Volume",
+		TWL4030_REG_PRECKL_CTL, TWL4030_REG_PRECKR_CTL,
+		4, 3, 0, snd_soc_get_volsw_r2_twl4030,
+		snd_soc_put_volsw_r2_twl4030, output_tvl),
+
+	SOC_SINGLE_EXT_TLV("Earpiece Playback Volume",
+		TWL4030_REG_EAR_CTL, 4, 3, 0, snd_soc_get_volsw_twl4030,
+		snd_soc_put_volsw_twl4030, output_ear_tvl),
+
+	/* Common capture gain controls */
+	SOC_DOUBLE_R_TLV("TX1 Digital Capture Volume",
+		TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA,
+		0, 0x1f, 0, digital_capture_tlv),
+	SOC_DOUBLE_R_TLV("TX2 Digital Capture Volume",
+		TWL4030_REG_AVTXL2PGA, TWL4030_REG_AVTXR2PGA,
+		0, 0x1f, 0, digital_capture_tlv),
+
+	SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN,
+		0, 3, 5, 0, input_gain_tlv),
+
+	SOC_ENUM("AVADC Clock Priority", twl4030_avadc_clk_priority_enum),
+
+	SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum),
+
+	SOC_ENUM("Vibra H-bridge mode", twl4030_vibradirmode_enum),
+	SOC_ENUM("Vibra H-bridge direction", twl4030_vibradir_enum),
+
+	SOC_ENUM("Digimic LR Swap", twl4030_digimicswap_enum),
+};
+
+static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
+	/* Left channel inputs */
+	SND_SOC_DAPM_INPUT("MAINMIC"),
+	SND_SOC_DAPM_INPUT("HSMIC"),
+	SND_SOC_DAPM_INPUT("AUXL"),
+	SND_SOC_DAPM_INPUT("CARKITMIC"),
+	/* Right channel inputs */
+	SND_SOC_DAPM_INPUT("SUBMIC"),
+	SND_SOC_DAPM_INPUT("AUXR"),
+	/* Digital microphones (Stereo) */
+	SND_SOC_DAPM_INPUT("DIGIMIC0"),
+	SND_SOC_DAPM_INPUT("DIGIMIC1"),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("EARPIECE"),
+	SND_SOC_DAPM_OUTPUT("PREDRIVEL"),
+	SND_SOC_DAPM_OUTPUT("PREDRIVER"),
+	SND_SOC_DAPM_OUTPUT("HSOL"),
+	SND_SOC_DAPM_OUTPUT("HSOR"),
+	SND_SOC_DAPM_OUTPUT("CARKITL"),
+	SND_SOC_DAPM_OUTPUT("CARKITR"),
+	SND_SOC_DAPM_OUTPUT("HFL"),
+	SND_SOC_DAPM_OUTPUT("HFR"),
+	SND_SOC_DAPM_OUTPUT("VIBRA"),
+
+	/* AIF and APLL clocks for running DAIs (including loopback) */
+	SND_SOC_DAPM_OUTPUT("Virtual HiFi OUT"),
+	SND_SOC_DAPM_INPUT("Virtual HiFi IN"),
+	SND_SOC_DAPM_OUTPUT("Virtual Voice OUT"),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC Right1", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC Left1", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC Right2", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC Left2", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC Voice", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_IN("VAIFIN", "Voice Playback", 0,
+			    TWL4030_REG_VOICE_IF, 6, 0),
+
+	/* Analog bypasses */
+	SND_SOC_DAPM_SWITCH("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_abypassr1_control),
+	SND_SOC_DAPM_SWITCH("Left1 Analog Loopback", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_abypassl1_control),
+	SND_SOC_DAPM_SWITCH("Right2 Analog Loopback", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_abypassr2_control),
+	SND_SOC_DAPM_SWITCH("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_abypassl2_control),
+	SND_SOC_DAPM_SWITCH("Voice Analog Loopback", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_abypassv_control),
+
+	/* Master analog loopback switch */
+	SND_SOC_DAPM_SUPPLY("FM Loop Enable", TWL4030_REG_MISC_SET_1, 5, 0,
+			    NULL, 0),
+
+	/* Digital bypasses */
+	SND_SOC_DAPM_SWITCH("Left Digital Loopback", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_dbypassl_control),
+	SND_SOC_DAPM_SWITCH("Right Digital Loopback", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_dbypassr_control),
+	SND_SOC_DAPM_SWITCH("Voice Digital Loopback", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_dbypassv_control),
+
+	/* Digital mixers, power control for the physical DACs */
+	SND_SOC_DAPM_MIXER("Digital R1 Playback Mixer",
+			TWL4030_REG_AVDAC_CTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Digital L1 Playback Mixer",
+			TWL4030_REG_AVDAC_CTL, 1, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Digital R2 Playback Mixer",
+			TWL4030_REG_AVDAC_CTL, 2, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Digital L2 Playback Mixer",
+			TWL4030_REG_AVDAC_CTL, 3, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Digital Voice Playback Mixer",
+			TWL4030_REG_AVDAC_CTL, 4, 0, NULL, 0),
+
+	/* Analog mixers, power control for the physical PGAs */
+	SND_SOC_DAPM_MIXER("Analog R1 Playback Mixer",
+			TWL4030_REG_ARXR1_APGA_CTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Analog L1 Playback Mixer",
+			TWL4030_REG_ARXL1_APGA_CTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Analog R2 Playback Mixer",
+			TWL4030_REG_ARXR2_APGA_CTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Analog L2 Playback Mixer",
+			TWL4030_REG_ARXL2_APGA_CTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Analog Voice Playback Mixer",
+			TWL4030_REG_VDL_APGA_CTL, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event,
+			    SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY("AIF Enable", SND_SOC_NOPM, 0, 0, aif_event,
+			    SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD),
+
+	/* Output MIXER controls */
+	/* Earpiece */
+	SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_earpiece_controls[0],
+			ARRAY_SIZE(twl4030_dapm_earpiece_controls)),
+	SND_SOC_DAPM_PGA_E("Earpiece PGA", SND_SOC_NOPM,
+			0, 0, NULL, 0, earpiecepga_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+	/* PreDrivL/R */
+	SND_SOC_DAPM_MIXER("PredriveL Mixer", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_predrivel_controls[0],
+			ARRAY_SIZE(twl4030_dapm_predrivel_controls)),
+	SND_SOC_DAPM_PGA_E("PredriveL PGA", SND_SOC_NOPM,
+			0, 0, NULL, 0, predrivelpga_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("PredriveR Mixer", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_predriver_controls[0],
+			ARRAY_SIZE(twl4030_dapm_predriver_controls)),
+	SND_SOC_DAPM_PGA_E("PredriveR PGA", SND_SOC_NOPM,
+			0, 0, NULL, 0, predriverpga_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+	/* HeadsetL/R */
+	SND_SOC_DAPM_MIXER("HeadsetL Mixer", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_hsol_controls[0],
+			ARRAY_SIZE(twl4030_dapm_hsol_controls)),
+	SND_SOC_DAPM_PGA_E("HeadsetL PGA", SND_SOC_NOPM,
+			0, 0, NULL, 0, headsetlpga_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("HeadsetR Mixer", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_hsor_controls[0],
+			ARRAY_SIZE(twl4030_dapm_hsor_controls)),
+	SND_SOC_DAPM_PGA_E("HeadsetR PGA", SND_SOC_NOPM,
+			0, 0, NULL, 0, headsetrpga_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+	/* CarkitL/R */
+	SND_SOC_DAPM_MIXER("CarkitL Mixer", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_carkitl_controls[0],
+			ARRAY_SIZE(twl4030_dapm_carkitl_controls)),
+	SND_SOC_DAPM_PGA_E("CarkitL PGA", SND_SOC_NOPM,
+			0, 0, NULL, 0, carkitlpga_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MIXER("CarkitR Mixer", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_carkitr_controls[0],
+			ARRAY_SIZE(twl4030_dapm_carkitr_controls)),
+	SND_SOC_DAPM_PGA_E("CarkitR PGA", SND_SOC_NOPM,
+			0, 0, NULL, 0, carkitrpga_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+
+	/* Output MUX controls */
+	/* HandsfreeL/R */
+	SND_SOC_DAPM_MUX("HandsfreeL Mux", SND_SOC_NOPM, 0, 0,
+		&twl4030_dapm_handsfreel_control),
+	SND_SOC_DAPM_SWITCH("HandsfreeL", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_handsfreelmute_control),
+	SND_SOC_DAPM_PGA_E("HandsfreeL PGA", SND_SOC_NOPM,
+			0, 0, NULL, 0, handsfreelpga_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX("HandsfreeR Mux", SND_SOC_NOPM, 5, 0,
+		&twl4030_dapm_handsfreer_control),
+	SND_SOC_DAPM_SWITCH("HandsfreeR", SND_SOC_NOPM, 0, 0,
+			&twl4030_dapm_handsfreermute_control),
+	SND_SOC_DAPM_PGA_E("HandsfreeR PGA", SND_SOC_NOPM,
+			0, 0, NULL, 0, handsfreerpga_event,
+			SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+	/* Vibra */
+	SND_SOC_DAPM_MUX_E("Vibra Mux", TWL4030_REG_VIBRA_CTL, 0, 0,
+			   &twl4030_dapm_vibra_control, vibramux_event,
+			   SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_MUX("Vibra Route", SND_SOC_NOPM, 0, 0,
+		&twl4030_dapm_vibrapath_control),
+
+	/* Introducing four virtual ADC, since TWL4030 have four channel for
+	   capture */
+	SND_SOC_DAPM_ADC("ADC Virtual Left1", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC Virtual Right1", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC Virtual Left2", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC Virtual Right2", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_AIF_OUT("VAIFOUT", "Voice Capture", 0,
+			     TWL4030_REG_VOICE_IF, 5, 0),
+
+	/* Analog/Digital mic path selection.
+	   TX1 Left/Right: either analog Left/Right or Digimic0
+	   TX2 Left/Right: either analog Left/Right or Digimic1 */
+	SND_SOC_DAPM_MUX("TX1 Capture Route", SND_SOC_NOPM, 0, 0,
+		&twl4030_dapm_micpathtx1_control),
+	SND_SOC_DAPM_MUX("TX2 Capture Route", SND_SOC_NOPM, 0, 0,
+		&twl4030_dapm_micpathtx2_control),
+
+	/* Analog input mixers for the capture amplifiers */
+	SND_SOC_DAPM_MIXER("Analog Left",
+		TWL4030_REG_ANAMICL, 4, 0,
+		&twl4030_dapm_analoglmic_controls[0],
+		ARRAY_SIZE(twl4030_dapm_analoglmic_controls)),
+	SND_SOC_DAPM_MIXER("Analog Right",
+		TWL4030_REG_ANAMICR, 4, 0,
+		&twl4030_dapm_analogrmic_controls[0],
+		ARRAY_SIZE(twl4030_dapm_analogrmic_controls)),
+
+	SND_SOC_DAPM_PGA("ADC Physical Left",
+		TWL4030_REG_AVADC_CTL, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC Physical Right",
+		TWL4030_REG_AVADC_CTL, 1, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA_E("Digimic0 Enable",
+		TWL4030_REG_ADCMICSEL, 1, 0, NULL, 0,
+		digimic_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_E("Digimic1 Enable",
+		TWL4030_REG_ADCMICSEL, 3, 0, NULL, 0,
+		digimic_event, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_SUPPLY("micbias1 select", TWL4030_REG_MICBIAS_CTL, 5, 0,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("micbias2 select", TWL4030_REG_MICBIAS_CTL, 6, 0,
+			    NULL, 0),
+
+	/* Microphone bias */
+	SND_SOC_DAPM_SUPPLY("Mic Bias 1",
+			    TWL4030_REG_MICBIAS_CTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Bias 2",
+			    TWL4030_REG_MICBIAS_CTL, 1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Headset Mic Bias",
+			    TWL4030_REG_MICBIAS_CTL, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("VIF Enable", TWL4030_REG_VOICE_IF, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	/* Stream -> DAC mapping */
+	{"DAC Right1", NULL, "HiFi Playback"},
+	{"DAC Left1", NULL, "HiFi Playback"},
+	{"DAC Right2", NULL, "HiFi Playback"},
+	{"DAC Left2", NULL, "HiFi Playback"},
+	{"DAC Voice", NULL, "VAIFIN"},
+
+	/* ADC -> Stream mapping */
+	{"HiFi Capture", NULL, "ADC Virtual Left1"},
+	{"HiFi Capture", NULL, "ADC Virtual Right1"},
+	{"HiFi Capture", NULL, "ADC Virtual Left2"},
+	{"HiFi Capture", NULL, "ADC Virtual Right2"},
+	{"VAIFOUT", NULL, "ADC Virtual Left2"},
+	{"VAIFOUT", NULL, "ADC Virtual Right2"},
+	{"VAIFOUT", NULL, "VIF Enable"},
+
+	{"Digital L1 Playback Mixer", NULL, "DAC Left1"},
+	{"Digital R1 Playback Mixer", NULL, "DAC Right1"},
+	{"Digital L2 Playback Mixer", NULL, "DAC Left2"},
+	{"Digital R2 Playback Mixer", NULL, "DAC Right2"},
+	{"Digital Voice Playback Mixer", NULL, "DAC Voice"},
+
+	/* Supply for the digital part (APLL) */
+	{"Digital Voice Playback Mixer", NULL, "APLL Enable"},
+
+	{"DAC Left1", NULL, "AIF Enable"},
+	{"DAC Right1", NULL, "AIF Enable"},
+	{"DAC Left2", NULL, "AIF Enable"},
+	{"DAC Right1", NULL, "AIF Enable"},
+	{"DAC Voice", NULL, "VIF Enable"},
+
+	{"Digital R2 Playback Mixer", NULL, "AIF Enable"},
+	{"Digital L2 Playback Mixer", NULL, "AIF Enable"},
+
+	{"Analog L1 Playback Mixer", NULL, "Digital L1 Playback Mixer"},
+	{"Analog R1 Playback Mixer", NULL, "Digital R1 Playback Mixer"},
+	{"Analog L2 Playback Mixer", NULL, "Digital L2 Playback Mixer"},
+	{"Analog R2 Playback Mixer", NULL, "Digital R2 Playback Mixer"},
+	{"Analog Voice Playback Mixer", NULL, "Digital Voice Playback Mixer"},
+
+	/* Internal playback routings */
+	/* Earpiece */
+	{"Earpiece Mixer", "Voice", "Analog Voice Playback Mixer"},
+	{"Earpiece Mixer", "AudioL1", "Analog L1 Playback Mixer"},
+	{"Earpiece Mixer", "AudioL2", "Analog L2 Playback Mixer"},
+	{"Earpiece Mixer", "AudioR1", "Analog R1 Playback Mixer"},
+	{"Earpiece PGA", NULL, "Earpiece Mixer"},
+	/* PreDrivL */
+	{"PredriveL Mixer", "Voice", "Analog Voice Playback Mixer"},
+	{"PredriveL Mixer", "AudioL1", "Analog L1 Playback Mixer"},
+	{"PredriveL Mixer", "AudioL2", "Analog L2 Playback Mixer"},
+	{"PredriveL Mixer", "AudioR2", "Analog R2 Playback Mixer"},
+	{"PredriveL PGA", NULL, "PredriveL Mixer"},
+	/* PreDrivR */
+	{"PredriveR Mixer", "Voice", "Analog Voice Playback Mixer"},
+	{"PredriveR Mixer", "AudioR1", "Analog R1 Playback Mixer"},
+	{"PredriveR Mixer", "AudioR2", "Analog R2 Playback Mixer"},
+	{"PredriveR Mixer", "AudioL2", "Analog L2 Playback Mixer"},
+	{"PredriveR PGA", NULL, "PredriveR Mixer"},
+	/* HeadsetL */
+	{"HeadsetL Mixer", "Voice", "Analog Voice Playback Mixer"},
+	{"HeadsetL Mixer", "AudioL1", "Analog L1 Playback Mixer"},
+	{"HeadsetL Mixer", "AudioL2", "Analog L2 Playback Mixer"},
+	{"HeadsetL PGA", NULL, "HeadsetL Mixer"},
+	/* HeadsetR */
+	{"HeadsetR Mixer", "Voice", "Analog Voice Playback Mixer"},
+	{"HeadsetR Mixer", "AudioR1", "Analog R1 Playback Mixer"},
+	{"HeadsetR Mixer", "AudioR2", "Analog R2 Playback Mixer"},
+	{"HeadsetR PGA", NULL, "HeadsetR Mixer"},
+	/* CarkitL */
+	{"CarkitL Mixer", "Voice", "Analog Voice Playback Mixer"},
+	{"CarkitL Mixer", "AudioL1", "Analog L1 Playback Mixer"},
+	{"CarkitL Mixer", "AudioL2", "Analog L2 Playback Mixer"},
+	{"CarkitL PGA", NULL, "CarkitL Mixer"},
+	/* CarkitR */
+	{"CarkitR Mixer", "Voice", "Analog Voice Playback Mixer"},
+	{"CarkitR Mixer", "AudioR1", "Analog R1 Playback Mixer"},
+	{"CarkitR Mixer", "AudioR2", "Analog R2 Playback Mixer"},
+	{"CarkitR PGA", NULL, "CarkitR Mixer"},
+	/* HandsfreeL */
+	{"HandsfreeL Mux", "Voice", "Analog Voice Playback Mixer"},
+	{"HandsfreeL Mux", "AudioL1", "Analog L1 Playback Mixer"},
+	{"HandsfreeL Mux", "AudioL2", "Analog L2 Playback Mixer"},
+	{"HandsfreeL Mux", "AudioR2", "Analog R2 Playback Mixer"},
+	{"HandsfreeL", "Switch", "HandsfreeL Mux"},
+	{"HandsfreeL PGA", NULL, "HandsfreeL"},
+	/* HandsfreeR */
+	{"HandsfreeR Mux", "Voice", "Analog Voice Playback Mixer"},
+	{"HandsfreeR Mux", "AudioR1", "Analog R1 Playback Mixer"},
+	{"HandsfreeR Mux", "AudioR2", "Analog R2 Playback Mixer"},
+	{"HandsfreeR Mux", "AudioL2", "Analog L2 Playback Mixer"},
+	{"HandsfreeR", "Switch", "HandsfreeR Mux"},
+	{"HandsfreeR PGA", NULL, "HandsfreeR"},
+	/* Vibra */
+	{"Vibra Mux", "AudioL1", "DAC Left1"},
+	{"Vibra Mux", "AudioR1", "DAC Right1"},
+	{"Vibra Mux", "AudioL2", "DAC Left2"},
+	{"Vibra Mux", "AudioR2", "DAC Right2"},
+
+	/* outputs */
+	/* Must be always connected (for AIF and APLL) */
+	{"Virtual HiFi OUT", NULL, "DAC Left1"},
+	{"Virtual HiFi OUT", NULL, "DAC Right1"},
+	{"Virtual HiFi OUT", NULL, "DAC Left2"},
+	{"Virtual HiFi OUT", NULL, "DAC Right2"},
+	/* Must be always connected (for APLL) */
+	{"Virtual Voice OUT", NULL, "Digital Voice Playback Mixer"},
+	/* Physical outputs */
+	{"EARPIECE", NULL, "Earpiece PGA"},
+	{"PREDRIVEL", NULL, "PredriveL PGA"},
+	{"PREDRIVER", NULL, "PredriveR PGA"},
+	{"HSOL", NULL, "HeadsetL PGA"},
+	{"HSOR", NULL, "HeadsetR PGA"},
+	{"CARKITL", NULL, "CarkitL PGA"},
+	{"CARKITR", NULL, "CarkitR PGA"},
+	{"HFL", NULL, "HandsfreeL PGA"},
+	{"HFR", NULL, "HandsfreeR PGA"},
+	{"Vibra Route", "Audio", "Vibra Mux"},
+	{"VIBRA", NULL, "Vibra Route"},
+
+	/* Capture path */
+	/* Must be always connected (for AIF and APLL) */
+	{"ADC Virtual Left1", NULL, "Virtual HiFi IN"},
+	{"ADC Virtual Right1", NULL, "Virtual HiFi IN"},
+	{"ADC Virtual Left2", NULL, "Virtual HiFi IN"},
+	{"ADC Virtual Right2", NULL, "Virtual HiFi IN"},
+	/* Physical inputs */
+	{"Analog Left", "Main Mic Capture Switch", "MAINMIC"},
+	{"Analog Left", "Headset Mic Capture Switch", "HSMIC"},
+	{"Analog Left", "AUXL Capture Switch", "AUXL"},
+	{"Analog Left", "Carkit Mic Capture Switch", "CARKITMIC"},
+
+	{"Analog Right", "Sub Mic Capture Switch", "SUBMIC"},
+	{"Analog Right", "AUXR Capture Switch", "AUXR"},
+
+	{"ADC Physical Left", NULL, "Analog Left"},
+	{"ADC Physical Right", NULL, "Analog Right"},
+
+	{"Digimic0 Enable", NULL, "DIGIMIC0"},
+	{"Digimic1 Enable", NULL, "DIGIMIC1"},
+
+	{"DIGIMIC0", NULL, "micbias1 select"},
+	{"DIGIMIC1", NULL, "micbias2 select"},
+
+	/* TX1 Left capture path */
+	{"TX1 Capture Route", "Analog", "ADC Physical Left"},
+	{"TX1 Capture Route", "Digimic0", "Digimic0 Enable"},
+	/* TX1 Right capture path */
+	{"TX1 Capture Route", "Analog", "ADC Physical Right"},
+	{"TX1 Capture Route", "Digimic0", "Digimic0 Enable"},
+	/* TX2 Left capture path */
+	{"TX2 Capture Route", "Analog", "ADC Physical Left"},
+	{"TX2 Capture Route", "Digimic1", "Digimic1 Enable"},
+	/* TX2 Right capture path */
+	{"TX2 Capture Route", "Analog", "ADC Physical Right"},
+	{"TX2 Capture Route", "Digimic1", "Digimic1 Enable"},
+
+	{"ADC Virtual Left1", NULL, "TX1 Capture Route"},
+	{"ADC Virtual Right1", NULL, "TX1 Capture Route"},
+	{"ADC Virtual Left2", NULL, "TX2 Capture Route"},
+	{"ADC Virtual Right2", NULL, "TX2 Capture Route"},
+
+	{"ADC Virtual Left1", NULL, "AIF Enable"},
+	{"ADC Virtual Right1", NULL, "AIF Enable"},
+	{"ADC Virtual Left2", NULL, "AIF Enable"},
+	{"ADC Virtual Right2", NULL, "AIF Enable"},
+
+	/* Analog bypass routes */
+	{"Right1 Analog Loopback", "Switch", "Analog Right"},
+	{"Left1 Analog Loopback", "Switch", "Analog Left"},
+	{"Right2 Analog Loopback", "Switch", "Analog Right"},
+	{"Left2 Analog Loopback", "Switch", "Analog Left"},
+	{"Voice Analog Loopback", "Switch", "Analog Left"},
+
+	/* Supply for the Analog loopbacks */
+	{"Right1 Analog Loopback", NULL, "FM Loop Enable"},
+	{"Left1 Analog Loopback", NULL, "FM Loop Enable"},
+	{"Right2 Analog Loopback", NULL, "FM Loop Enable"},
+	{"Left2 Analog Loopback", NULL, "FM Loop Enable"},
+	{"Voice Analog Loopback", NULL, "FM Loop Enable"},
+
+	{"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"},
+	{"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"},
+	{"Analog R2 Playback Mixer", NULL, "Right2 Analog Loopback"},
+	{"Analog L2 Playback Mixer", NULL, "Left2 Analog Loopback"},
+	{"Analog Voice Playback Mixer", NULL, "Voice Analog Loopback"},
+
+	/* Digital bypass routes */
+	{"Right Digital Loopback", "Volume", "TX1 Capture Route"},
+	{"Left Digital Loopback", "Volume", "TX1 Capture Route"},
+	{"Voice Digital Loopback", "Volume", "TX2 Capture Route"},
+
+	{"Digital R2 Playback Mixer", NULL, "Right Digital Loopback"},
+	{"Digital L2 Playback Mixer", NULL, "Left Digital Loopback"},
+	{"Digital Voice Playback Mixer", NULL, "Voice Digital Loopback"},
+
+};
+
+static int twl4030_set_bias_level(struct snd_soc_component *component,
+				  enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			twl4030_codec_enable(component, 1);
+		break;
+	case SND_SOC_BIAS_OFF:
+		twl4030_codec_enable(component, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static void twl4030_constraints(struct twl4030_priv *twl4030,
+				struct snd_pcm_substream *mst_substream)
+{
+	struct snd_pcm_substream *slv_substream;
+
+	/* Pick the stream, which need to be constrained */
+	if (mst_substream == twl4030->master_substream)
+		slv_substream = twl4030->slave_substream;
+	else if (mst_substream == twl4030->slave_substream)
+		slv_substream = twl4030->master_substream;
+	else /* This should not happen.. */
+		return;
+
+	/* Set the constraints according to the already configured stream */
+	snd_pcm_hw_constraint_single(slv_substream->runtime,
+				SNDRV_PCM_HW_PARAM_RATE,
+				twl4030->rate);
+
+	snd_pcm_hw_constraint_single(slv_substream->runtime,
+				SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+				twl4030->sample_bits);
+
+	snd_pcm_hw_constraint_single(slv_substream->runtime,
+				SNDRV_PCM_HW_PARAM_CHANNELS,
+				twl4030->channels);
+}
+
+/* In case of 4 channel mode, the RX1 L/R for playback and the TX2 L/R for
+ * capture has to be enabled/disabled. */
+static void twl4030_tdm_enable(struct snd_soc_component *component, int direction,
+			       int enable)
+{
+	u8 reg, mask;
+
+	reg = twl4030_read(component, TWL4030_REG_OPTION);
+
+	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+		mask = TWL4030_ARXL1_VRX_EN | TWL4030_ARXR1_EN;
+	else
+		mask = TWL4030_ATXL2_VTXL_EN | TWL4030_ATXR2_VTXR_EN;
+
+	if (enable)
+		reg |= mask;
+	else
+		reg &= ~mask;
+
+	twl4030_write(component, TWL4030_REG_OPTION, reg);
+}
+
+static int twl4030_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+
+	if (twl4030->master_substream) {
+		twl4030->slave_substream = substream;
+		/* The DAI has one configuration for playback and capture, so
+		 * if the DAI has been already configured then constrain this
+		 * substream to match it. */
+		if (twl4030->configured)
+			twl4030_constraints(twl4030, twl4030->master_substream);
+	} else {
+		if (!(twl4030_read(component, TWL4030_REG_CODEC_MODE) &
+			TWL4030_OPTION_1)) {
+			/* In option2 4 channel is not supported, set the
+			 * constraint for the first stream for channels, the
+			 * second stream will 'inherit' this cosntraint */
+			snd_pcm_hw_constraint_single(substream->runtime,
+						     SNDRV_PCM_HW_PARAM_CHANNELS,
+						     2);
+		}
+		twl4030->master_substream = substream;
+	}
+
+	return 0;
+}
+
+static void twl4030_shutdown(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+
+	if (twl4030->master_substream == substream)
+		twl4030->master_substream = twl4030->slave_substream;
+
+	twl4030->slave_substream = NULL;
+
+	/* If all streams are closed, or the remaining stream has not yet
+	 * been configured than set the DAI as not configured. */
+	if (!twl4030->master_substream)
+		twl4030->configured = 0;
+	 else if (!twl4030->master_substream->runtime->channels)
+		twl4030->configured = 0;
+
+	 /* If the closing substream had 4 channel, do the necessary cleanup */
+	if (substream->runtime->channels == 4)
+		twl4030_tdm_enable(component, substream->stream, 0);
+}
+
+static int twl4030_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+	u8 mode, old_mode, format, old_format;
+
+	 /* If the substream has 4 channel, do the necessary setup */
+	if (params_channels(params) == 4) {
+		format = twl4030_read(component, TWL4030_REG_AUDIO_IF);
+		mode = twl4030_read(component, TWL4030_REG_CODEC_MODE);
+
+		/* Safety check: are we in the correct operating mode and
+		 * the interface is in TDM mode? */
+		if ((mode & TWL4030_OPTION_1) &&
+		    ((format & TWL4030_AIF_FORMAT) == TWL4030_AIF_FORMAT_TDM))
+			twl4030_tdm_enable(component, substream->stream, 1);
+		else
+			return -EINVAL;
+	}
+
+	if (twl4030->configured)
+		/* Ignoring hw_params for already configured DAI */
+		return 0;
+
+	/* bit rate */
+	old_mode = twl4030_read(component,
+				TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
+	mode = old_mode & ~TWL4030_APLL_RATE;
+
+	switch (params_rate(params)) {
+	case 8000:
+		mode |= TWL4030_APLL_RATE_8000;
+		break;
+	case 11025:
+		mode |= TWL4030_APLL_RATE_11025;
+		break;
+	case 12000:
+		mode |= TWL4030_APLL_RATE_12000;
+		break;
+	case 16000:
+		mode |= TWL4030_APLL_RATE_16000;
+		break;
+	case 22050:
+		mode |= TWL4030_APLL_RATE_22050;
+		break;
+	case 24000:
+		mode |= TWL4030_APLL_RATE_24000;
+		break;
+	case 32000:
+		mode |= TWL4030_APLL_RATE_32000;
+		break;
+	case 44100:
+		mode |= TWL4030_APLL_RATE_44100;
+		break;
+	case 48000:
+		mode |= TWL4030_APLL_RATE_48000;
+		break;
+	case 96000:
+		mode |= TWL4030_APLL_RATE_96000;
+		break;
+	default:
+		dev_err(component->dev, "%s: unknown rate %d\n", __func__,
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	/* sample size */
+	old_format = twl4030_read(component, TWL4030_REG_AUDIO_IF);
+	format = old_format;
+	format &= ~TWL4030_DATA_WIDTH;
+	switch (params_width(params)) {
+	case 16:
+		format |= TWL4030_DATA_WIDTH_16S_16W;
+		break;
+	case 32:
+		format |= TWL4030_DATA_WIDTH_32S_24W;
+		break;
+	default:
+		dev_err(component->dev, "%s: unsupported bits/sample %d\n",
+			__func__, params_width(params));
+		return -EINVAL;
+	}
+
+	if (format != old_format || mode != old_mode) {
+		if (twl4030->codec_powered) {
+			/*
+			 * If the codec is powered, than we need to toggle the
+			 * codec power.
+			 */
+			twl4030_codec_enable(component, 0);
+			twl4030_write(component, TWL4030_REG_CODEC_MODE, mode);
+			twl4030_write(component, TWL4030_REG_AUDIO_IF, format);
+			twl4030_codec_enable(component, 1);
+		} else {
+			twl4030_write(component, TWL4030_REG_CODEC_MODE, mode);
+			twl4030_write(component, TWL4030_REG_AUDIO_IF, format);
+		}
+	}
+
+	/* Store the important parameters for the DAI configuration and set
+	 * the DAI as configured */
+	twl4030->configured = 1;
+	twl4030->rate = params_rate(params);
+	twl4030->sample_bits = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
+	twl4030->channels = params_channels(params);
+
+	/* If both playback and capture streams are open, and one of them
+	 * is setting the hw parameters right now (since we are here), set
+	 * constraints to the other stream to match the current one. */
+	if (twl4030->slave_substream)
+		twl4030_constraints(twl4030, substream);
+
+	return 0;
+}
+
+static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
+				  unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+
+	switch (freq) {
+	case 19200000:
+	case 26000000:
+	case 38400000:
+		break;
+	default:
+		dev_err(component->dev, "Unsupported HFCLKIN: %u\n", freq);
+		return -EINVAL;
+	}
+
+	if ((freq / 1000) != twl4030->sysclk) {
+		dev_err(component->dev,
+			"Mismatch in HFCLKIN: %u (configured: %u)\n",
+			freq, twl4030->sysclk * 1000);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+	u8 old_format, format;
+
+	/* get format */
+	old_format = twl4030_read(component, TWL4030_REG_AUDIO_IF);
+	format = old_format;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		format &= ~(TWL4030_AIF_SLAVE_EN);
+		format &= ~(TWL4030_CLK256FS_EN);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		format |= TWL4030_AIF_SLAVE_EN;
+		format |= TWL4030_CLK256FS_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	format &= ~TWL4030_AIF_FORMAT;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		format |= TWL4030_AIF_FORMAT_CODEC;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		format |= TWL4030_AIF_FORMAT_TDM;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (format != old_format) {
+		if (twl4030->codec_powered) {
+			/*
+			 * If the codec is powered, than we need to toggle the
+			 * codec power.
+			 */
+			twl4030_codec_enable(component, 0);
+			twl4030_write(component, TWL4030_REG_AUDIO_IF, format);
+			twl4030_codec_enable(component, 1);
+		} else {
+			twl4030_write(component, TWL4030_REG_AUDIO_IF, format);
+		}
+	}
+
+	return 0;
+}
+
+static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 reg = twl4030_read(component, TWL4030_REG_AUDIO_IF);
+
+	if (tristate)
+		reg |= TWL4030_AIF_TRI_EN;
+	else
+		reg &= ~TWL4030_AIF_TRI_EN;
+
+	return twl4030_write(component, TWL4030_REG_AUDIO_IF, reg);
+}
+
+/* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R
+ * (VTXL, VTXR) for uplink has to be enabled/disabled. */
+static void twl4030_voice_enable(struct snd_soc_component *component, int direction,
+				 int enable)
+{
+	u8 reg, mask;
+
+	reg = twl4030_read(component, TWL4030_REG_OPTION);
+
+	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+		mask = TWL4030_ARXL1_VRX_EN;
+	else
+		mask = TWL4030_ATXL2_VTXL_EN | TWL4030_ATXR2_VTXR_EN;
+
+	if (enable)
+		reg |= mask;
+	else
+		reg &= ~mask;
+
+	twl4030_write(component, TWL4030_REG_OPTION, reg);
+}
+
+static int twl4030_voice_startup(struct snd_pcm_substream *substream,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+	u8 mode;
+
+	/* If the system master clock is not 26MHz, the voice PCM interface is
+	 * not available.
+	 */
+	if (twl4030->sysclk != 26000) {
+		dev_err(component->dev,
+			"%s: HFCLKIN is %u KHz, voice interface needs 26MHz\n",
+			__func__, twl4030->sysclk);
+		return -EINVAL;
+	}
+
+	/* If the codec mode is not option2, the voice PCM interface is not
+	 * available.
+	 */
+	mode = twl4030_read(component, TWL4030_REG_CODEC_MODE)
+		& TWL4030_OPT_MODE;
+
+	if (mode != TWL4030_OPTION_2) {
+		dev_err(component->dev, "%s: the codec mode is not option2\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+
+	/* Enable voice digital filters */
+	twl4030_voice_enable(component, substream->stream, 0);
+}
+
+static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+	u8 old_mode, mode;
+
+	/* Enable voice digital filters */
+	twl4030_voice_enable(component, substream->stream, 1);
+
+	/* bit rate */
+	old_mode = twl4030_read(component,
+				TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
+	mode = old_mode;
+
+	switch (params_rate(params)) {
+	case 8000:
+		mode &= ~(TWL4030_SEL_16K);
+		break;
+	case 16000:
+		mode |= TWL4030_SEL_16K;
+		break;
+	default:
+		dev_err(component->dev, "%s: unknown rate %d\n", __func__,
+			params_rate(params));
+		return -EINVAL;
+	}
+
+	if (mode != old_mode) {
+		if (twl4030->codec_powered) {
+			/*
+			 * If the codec is powered, than we need to toggle the
+			 * codec power.
+			 */
+			twl4030_codec_enable(component, 0);
+			twl4030_write(component, TWL4030_REG_CODEC_MODE, mode);
+			twl4030_codec_enable(component, 1);
+		} else {
+			twl4030_write(component, TWL4030_REG_CODEC_MODE, mode);
+		}
+	}
+
+	return 0;
+}
+
+static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+					int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+
+	if (freq != 26000000) {
+		dev_err(component->dev,
+			"%s: HFCLKIN is %u KHz, voice interface needs 26MHz\n",
+			__func__, freq / 1000);
+		return -EINVAL;
+	}
+	if ((freq / 1000) != twl4030->sysclk) {
+		dev_err(component->dev,
+			"Mismatch in HFCLKIN: %u (configured: %u)\n",
+			freq, twl4030->sysclk * 1000);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				     unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+	u8 old_format, format;
+
+	/* get format */
+	old_format = twl4030_read(component, TWL4030_REG_VOICE_IF);
+	format = old_format;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		format &= ~(TWL4030_VIF_SLAVE_EN);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		format |= TWL4030_VIF_SLAVE_EN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_NF:
+		format &= ~(TWL4030_VIF_FORMAT);
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		format |= TWL4030_VIF_FORMAT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (format != old_format) {
+		if (twl4030->codec_powered) {
+			/*
+			 * If the codec is powered, than we need to toggle the
+			 * codec power.
+			 */
+			twl4030_codec_enable(component, 0);
+			twl4030_write(component, TWL4030_REG_VOICE_IF, format);
+			twl4030_codec_enable(component, 1);
+		} else {
+			twl4030_write(component, TWL4030_REG_VOICE_IF, format);
+		}
+	}
+
+	return 0;
+}
+
+static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 reg = twl4030_read(component, TWL4030_REG_VOICE_IF);
+
+	if (tristate)
+		reg |= TWL4030_VIF_TRI_EN;
+	else
+		reg &= ~TWL4030_VIF_TRI_EN;
+
+	return twl4030_write(component, TWL4030_REG_VOICE_IF, reg);
+}
+
+#define TWL4030_RATES	 (SNDRV_PCM_RATE_8000_48000)
+#define TWL4030_FORMATS	 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops twl4030_dai_hifi_ops = {
+	.startup	= twl4030_startup,
+	.shutdown	= twl4030_shutdown,
+	.hw_params	= twl4030_hw_params,
+	.set_sysclk	= twl4030_set_dai_sysclk,
+	.set_fmt	= twl4030_set_dai_fmt,
+	.set_tristate	= twl4030_set_tristate,
+};
+
+static const struct snd_soc_dai_ops twl4030_dai_voice_ops = {
+	.startup	= twl4030_voice_startup,
+	.shutdown	= twl4030_voice_shutdown,
+	.hw_params	= twl4030_voice_hw_params,
+	.set_sysclk	= twl4030_voice_set_dai_sysclk,
+	.set_fmt	= twl4030_voice_set_dai_fmt,
+	.set_tristate	= twl4030_voice_set_tristate,
+};
+
+static struct snd_soc_dai_driver twl4030_dai[] = {
+{
+	.name = "twl4030-hifi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 2,
+		.channels_max = 4,
+		.rates = TWL4030_RATES | SNDRV_PCM_RATE_96000,
+		.formats = TWL4030_FORMATS,
+		.sig_bits = 24,},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 2,
+		.channels_max = 4,
+		.rates = TWL4030_RATES,
+		.formats = TWL4030_FORMATS,
+		.sig_bits = 24,},
+	.ops = &twl4030_dai_hifi_ops,
+},
+{
+	.name = "twl4030-voice",
+	.playback = {
+		.stream_name = "Voice Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.stream_name = "Voice Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = &twl4030_dai_voice_ops,
+},
+};
+
+static int twl4030_soc_probe(struct snd_soc_component *component)
+{
+	struct twl4030_priv *twl4030;
+
+	twl4030 = devm_kzalloc(component->dev, sizeof(struct twl4030_priv),
+			       GFP_KERNEL);
+	if (!twl4030)
+		return -ENOMEM;
+	snd_soc_component_set_drvdata(component, twl4030);
+	/* Set the defaults, and power up the codec */
+	twl4030->sysclk = twl4030_audio_get_mclk() / 1000;
+
+	twl4030_init_chip(component);
+
+	return 0;
+}
+
+static void twl4030_soc_remove(struct snd_soc_component *component)
+{
+	struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+	struct twl4030_codec_data *pdata = twl4030->pdata;
+
+	if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio))
+		gpio_free(pdata->hs_extmute_gpio);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_twl4030 = {
+	.probe			= twl4030_soc_probe,
+	.remove			= twl4030_soc_remove,
+	.read			= twl4030_read,
+	.write			= twl4030_write,
+	.set_bias_level		= twl4030_set_bias_level,
+	.controls		= twl4030_snd_controls,
+	.num_controls		= ARRAY_SIZE(twl4030_snd_controls),
+	.dapm_widgets		= twl4030_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(twl4030_dapm_widgets),
+	.dapm_routes		= intercon,
+	.num_dapm_routes	= ARRAY_SIZE(intercon),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int twl4030_codec_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_twl4030,
+				      twl4030_dai, ARRAY_SIZE(twl4030_dai));
+}
+
+MODULE_ALIAS("platform:twl4030-codec");
+
+static struct platform_driver twl4030_codec_driver = {
+	.probe		= twl4030_codec_probe,
+	.driver		= {
+		.name	= "twl4030-codec",
+	},
+};
+
+module_platform_driver(twl4030_codec_driver);
+
+MODULE_DESCRIPTION("ASoC TWL4030 codec driver");
+MODULE_AUTHOR("Steve Sakoman");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
new file mode 100644
index 0000000..94675da
--- /dev/null
+++ b/sound/soc/codecs/twl6040.c
@@ -0,0 +1,1192 @@
+/*
+ * ALSA SoC TWL6040 codec driver
+ *
+ * Author:	 Misael Lopez Cruz <x0052729@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mfd/twl6040.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "twl6040.h"
+
+enum twl6040_dai_id {
+	TWL6040_DAI_LEGACY = 0,
+	TWL6040_DAI_UL,
+	TWL6040_DAI_DL1,
+	TWL6040_DAI_DL2,
+	TWL6040_DAI_VIB,
+};
+
+#define TWL6040_RATES		SNDRV_PCM_RATE_8000_96000
+#define TWL6040_FORMATS	(SNDRV_PCM_FMTBIT_S32_LE)
+
+#define TWL6040_OUTHS_0dB 0x00
+#define TWL6040_OUTHS_M30dB 0x0F
+#define TWL6040_OUTHF_0dB 0x03
+#define TWL6040_OUTHF_M52dB 0x1D
+
+#define TWL6040_CACHEREGNUM	(TWL6040_REG_STATUS + 1)
+
+struct twl6040_jack_data {
+	struct snd_soc_jack *jack;
+	struct delayed_work work;
+	int report;
+};
+
+/* codec private data */
+struct twl6040_data {
+	int plug_irq;
+	int codec_powered;
+	int pll;
+	int pll_power_mode;
+	int hs_power_mode;
+	int hs_power_mode_locked;
+	bool dl1_unmuted;
+	bool dl2_unmuted;
+	u8 dl12_cache[TWL6040_REG_HFRCTL - TWL6040_REG_HSLCTL + 1];
+	unsigned int clk_in;
+	unsigned int sysclk;
+	struct twl6040_jack_data hs_jack;
+	struct snd_soc_component *component;
+	struct mutex mutex;
+};
+
+/* set of rates for each pll: low-power and high-performance */
+static const unsigned int lp_rates[] = {
+	8000,
+	11250,
+	16000,
+	22500,
+	32000,
+	44100,
+	48000,
+	88200,
+	96000,
+};
+
+static const unsigned int hp_rates[] = {
+	8000,
+	16000,
+	32000,
+	48000,
+	96000,
+};
+
+static const struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
+	{ .count = ARRAY_SIZE(lp_rates), .list = lp_rates, },
+	{ .count = ARRAY_SIZE(hp_rates), .list = hp_rates, },
+};
+
+#define to_twl6040(component)	dev_get_drvdata((component)->dev->parent)
+
+static unsigned int twl6040_read(struct snd_soc_component *component, unsigned int reg)
+{
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+	struct twl6040 *twl6040 = to_twl6040(component);
+	u8 value;
+
+	if (reg >= TWL6040_CACHEREGNUM)
+		return -EIO;
+
+	switch (reg) {
+	case TWL6040_REG_HSLCTL:
+	case TWL6040_REG_HSRCTL:
+	case TWL6040_REG_EARCTL:
+	case TWL6040_REG_HFLCTL:
+	case TWL6040_REG_HFRCTL:
+		value = priv->dl12_cache[reg - TWL6040_REG_HSLCTL];
+		break;
+	default:
+		value = twl6040_reg_read(twl6040, reg);
+		break;
+	}
+
+	return value;
+}
+
+static bool twl6040_can_write_to_chip(struct snd_soc_component *component,
+				  unsigned int reg)
+{
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+
+	switch (reg) {
+	case TWL6040_REG_HSLCTL:
+	case TWL6040_REG_HSRCTL:
+	case TWL6040_REG_EARCTL:
+		/* DL1 path */
+		return priv->dl1_unmuted;
+	case TWL6040_REG_HFLCTL:
+	case TWL6040_REG_HFRCTL:
+		return priv->dl2_unmuted;
+	default:
+		return true;
+	}
+}
+
+static inline void twl6040_update_dl12_cache(struct snd_soc_component *component,
+					     u8 reg, u8 value)
+{
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+
+	switch (reg) {
+	case TWL6040_REG_HSLCTL:
+	case TWL6040_REG_HSRCTL:
+	case TWL6040_REG_EARCTL:
+	case TWL6040_REG_HFLCTL:
+	case TWL6040_REG_HFRCTL:
+		priv->dl12_cache[reg - TWL6040_REG_HSLCTL] = value;
+		break;
+	default:
+		break;
+	}
+}
+
+static int twl6040_write(struct snd_soc_component *component,
+			unsigned int reg, unsigned int value)
+{
+	struct twl6040 *twl6040 = to_twl6040(component);
+
+	if (reg >= TWL6040_CACHEREGNUM)
+		return -EIO;
+
+	twl6040_update_dl12_cache(component, reg, value);
+	if (twl6040_can_write_to_chip(component, reg))
+		return twl6040_reg_write(twl6040, reg, value);
+	else
+		return 0;
+}
+
+static void twl6040_init_chip(struct snd_soc_component *component)
+{
+	twl6040_read(component, TWL6040_REG_TRIM1);
+	twl6040_read(component, TWL6040_REG_TRIM2);
+	twl6040_read(component, TWL6040_REG_TRIM3);
+	twl6040_read(component, TWL6040_REG_HSOTRIM);
+	twl6040_read(component, TWL6040_REG_HFOTRIM);
+
+	/* Change chip defaults */
+	/* No imput selected for microphone amplifiers */
+	twl6040_write(component, TWL6040_REG_MICLCTL, 0x18);
+	twl6040_write(component, TWL6040_REG_MICRCTL, 0x18);
+
+	/*
+	 * We need to lower the default gain values, so the ramp code
+	 * can work correctly for the first playback.
+	 * This reduces the pop noise heard at the first playback.
+	 */
+	twl6040_write(component, TWL6040_REG_HSGAIN, 0xff);
+	twl6040_write(component, TWL6040_REG_EARCTL, 0x1e);
+	twl6040_write(component, TWL6040_REG_HFLGAIN, 0x1d);
+	twl6040_write(component, TWL6040_REG_HFRGAIN, 0x1d);
+	twl6040_write(component, TWL6040_REG_LINEGAIN, 0);
+}
+
+/* set headset dac and driver power mode */
+static int headset_power_mode(struct snd_soc_component *component, int high_perf)
+{
+	int hslctl, hsrctl;
+	int mask = TWL6040_HSDRVMODE | TWL6040_HSDACMODE;
+
+	hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
+	hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
+
+	if (high_perf) {
+		hslctl &= ~mask;
+		hsrctl &= ~mask;
+	} else {
+		hslctl |= mask;
+		hsrctl |= mask;
+	}
+
+	twl6040_write(component, TWL6040_REG_HSLCTL, hslctl);
+	twl6040_write(component, TWL6040_REG_HSRCTL, hsrctl);
+
+	return 0;
+}
+
+static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u8 hslctl, hsrctl;
+
+	/*
+	 * Workaround for Headset DC offset caused pop noise:
+	 * Both HS DAC need to be turned on (before the HS driver) and off at
+	 * the same time.
+	 */
+	hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
+	hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		hslctl |= TWL6040_HSDACENA;
+		hsrctl |= TWL6040_HSDACENA;
+	} else {
+		hslctl &= ~TWL6040_HSDACENA;
+		hsrctl &= ~TWL6040_HSDACENA;
+	}
+	twl6040_write(component, TWL6040_REG_HSLCTL, hslctl);
+	twl6040_write(component, TWL6040_REG_HSRCTL, hsrctl);
+
+	msleep(1);
+	return 0;
+}
+
+static int twl6040_ep_drv_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* Earphone doesn't support low power mode */
+		priv->hs_power_mode_locked = 1;
+		ret = headset_power_mode(component, 1);
+	} else {
+		priv->hs_power_mode_locked = 0;
+		ret = headset_power_mode(component, priv->hs_power_mode);
+	}
+
+	msleep(1);
+
+	return ret;
+}
+
+static void twl6040_hs_jack_report(struct snd_soc_component *component,
+				   struct snd_soc_jack *jack, int report)
+{
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+	int status;
+
+	mutex_lock(&priv->mutex);
+
+	/* Sync status */
+	status = twl6040_read(component, TWL6040_REG_STATUS);
+	if (status & TWL6040_PLUGCOMP)
+		snd_soc_jack_report(jack, report, report);
+	else
+		snd_soc_jack_report(jack, 0, report);
+
+	mutex_unlock(&priv->mutex);
+}
+
+void twl6040_hs_jack_detect(struct snd_soc_component *component,
+				struct snd_soc_jack *jack, int report)
+{
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+	struct twl6040_jack_data *hs_jack = &priv->hs_jack;
+
+	hs_jack->jack = jack;
+	hs_jack->report = report;
+
+	twl6040_hs_jack_report(component, hs_jack->jack, hs_jack->report);
+}
+EXPORT_SYMBOL_GPL(twl6040_hs_jack_detect);
+
+static void twl6040_accessory_work(struct work_struct *work)
+{
+	struct twl6040_data *priv = container_of(work,
+					struct twl6040_data, hs_jack.work.work);
+	struct snd_soc_component *component = priv->component;
+	struct twl6040_jack_data *hs_jack = &priv->hs_jack;
+
+	twl6040_hs_jack_report(component, hs_jack->jack, hs_jack->report);
+}
+
+/* audio interrupt handler */
+static irqreturn_t twl6040_audio_handler(int irq, void *data)
+{
+	struct snd_soc_component *component = data;
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+
+	queue_delayed_work(system_power_efficient_wq,
+			   &priv->hs_jack.work, msecs_to_jiffies(200));
+
+	return IRQ_HANDLED;
+}
+
+static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int val;
+
+	/* Do not allow changes while Input/FF efect is running */
+	val = twl6040_read(component, e->reg);
+	if (val & TWL6040_VIBENA && !(val & TWL6040_VIBSEL))
+		return -EBUSY;
+
+	return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
+/*
+ * MICATT volume control:
+ * from -6 to 0 dB in 6 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(mic_preamp_tlv, -600, 600, 0);
+
+/*
+ * MICGAIN volume control:
+ * from 6 to 30 dB in 6 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(mic_amp_tlv, 600, 600, 0);
+
+/*
+ * AFMGAIN volume control:
+ * from -18 to 24 dB in 6 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(afm_amp_tlv, -1800, 600, 0);
+
+/*
+ * HSGAIN volume control:
+ * from -30 to 0 dB in 2 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(hs_tlv, -3000, 200, 0);
+
+/*
+ * HFGAIN volume control:
+ * from -52 to 6 dB in 2 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(hf_tlv, -5200, 200, 0);
+
+/*
+ * EPGAIN volume control:
+ * from -24 to 6 dB in 2 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(ep_tlv, -2400, 200, 0);
+
+/* Left analog microphone selection */
+static const char *twl6040_amicl_texts[] =
+	{"Headset Mic", "Main Mic", "Aux/FM Left", "Off"};
+
+/* Right analog microphone selection */
+static const char *twl6040_amicr_texts[] =
+	{"Headset Mic", "Sub Mic", "Aux/FM Right", "Off"};
+
+static const struct soc_enum twl6040_enum[] = {
+	SOC_ENUM_SINGLE(TWL6040_REG_MICLCTL, 3,
+			ARRAY_SIZE(twl6040_amicl_texts), twl6040_amicl_texts),
+	SOC_ENUM_SINGLE(TWL6040_REG_MICRCTL, 3,
+			ARRAY_SIZE(twl6040_amicr_texts), twl6040_amicr_texts),
+};
+
+static const char *twl6040_hs_texts[] = {
+	"Off", "HS DAC", "Line-In amp"
+};
+
+static const struct soc_enum twl6040_hs_enum[] = {
+	SOC_ENUM_SINGLE(TWL6040_REG_HSLCTL, 5, ARRAY_SIZE(twl6040_hs_texts),
+			twl6040_hs_texts),
+	SOC_ENUM_SINGLE(TWL6040_REG_HSRCTL, 5, ARRAY_SIZE(twl6040_hs_texts),
+			twl6040_hs_texts),
+};
+
+static const char *twl6040_hf_texts[] = {
+	"Off", "HF DAC", "Line-In amp"
+};
+
+static const struct soc_enum twl6040_hf_enum[] = {
+	SOC_ENUM_SINGLE(TWL6040_REG_HFLCTL, 2, ARRAY_SIZE(twl6040_hf_texts),
+			twl6040_hf_texts),
+	SOC_ENUM_SINGLE(TWL6040_REG_HFRCTL, 2, ARRAY_SIZE(twl6040_hf_texts),
+			twl6040_hf_texts),
+};
+
+static const char *twl6040_vibrapath_texts[] = {
+	"Input FF", "Audio PDM"
+};
+
+static const struct soc_enum twl6040_vibra_enum[] = {
+	SOC_ENUM_SINGLE(TWL6040_REG_VIBCTLL, 1,
+			ARRAY_SIZE(twl6040_vibrapath_texts),
+			twl6040_vibrapath_texts),
+	SOC_ENUM_SINGLE(TWL6040_REG_VIBCTLR, 1,
+			ARRAY_SIZE(twl6040_vibrapath_texts),
+			twl6040_vibrapath_texts),
+};
+
+static const struct snd_kcontrol_new amicl_control =
+	SOC_DAPM_ENUM("Route", twl6040_enum[0]);
+
+static const struct snd_kcontrol_new amicr_control =
+	SOC_DAPM_ENUM("Route", twl6040_enum[1]);
+
+/* Headset DAC playback switches */
+static const struct snd_kcontrol_new hsl_mux_controls =
+	SOC_DAPM_ENUM("Route", twl6040_hs_enum[0]);
+
+static const struct snd_kcontrol_new hsr_mux_controls =
+	SOC_DAPM_ENUM("Route", twl6040_hs_enum[1]);
+
+/* Handsfree DAC playback switches */
+static const struct snd_kcontrol_new hfl_mux_controls =
+	SOC_DAPM_ENUM("Route", twl6040_hf_enum[0]);
+
+static const struct snd_kcontrol_new hfr_mux_controls =
+	SOC_DAPM_ENUM("Route", twl6040_hf_enum[1]);
+
+static const struct snd_kcontrol_new ep_path_enable_control =
+	SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+static const struct snd_kcontrol_new auxl_switch_control =
+	SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 6, 1, 0);
+
+static const struct snd_kcontrol_new auxr_switch_control =
+	SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 6, 1, 0);
+
+/* Vibra playback switches */
+static const struct snd_kcontrol_new vibral_mux_controls =
+	SOC_DAPM_ENUM_EXT("Route", twl6040_vibra_enum[0],
+		snd_soc_dapm_get_enum_double,
+		twl6040_soc_dapm_put_vibra_enum);
+
+static const struct snd_kcontrol_new vibrar_mux_controls =
+	SOC_DAPM_ENUM_EXT("Route", twl6040_vibra_enum[1],
+		snd_soc_dapm_get_enum_double,
+		twl6040_soc_dapm_put_vibra_enum);
+
+/* Headset power mode */
+static const char *twl6040_power_mode_texts[] = {
+	"Low-Power", "High-Performance",
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum,
+				twl6040_power_mode_texts);
+
+static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.enumerated.item[0] = priv->hs_power_mode;
+
+	return 0;
+}
+
+static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+	int high_perf = ucontrol->value.enumerated.item[0];
+	int ret = 0;
+
+	if (!priv->hs_power_mode_locked)
+		ret = headset_power_mode(component, high_perf);
+
+	if (!ret)
+		priv->hs_power_mode = high_perf;
+
+	return ret;
+}
+
+static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.enumerated.item[0] = priv->pll_power_mode;
+
+	return 0;
+}
+
+static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+
+	priv->pll_power_mode = ucontrol->value.enumerated.item[0];
+
+	return 0;
+}
+
+int twl6040_get_dl1_gain(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	if (snd_soc_dapm_get_pin_status(dapm, "EP"))
+		return -1; /* -1dB */
+
+	if (snd_soc_dapm_get_pin_status(dapm, "HSOR") ||
+		snd_soc_dapm_get_pin_status(dapm, "HSOL")) {
+
+		u8 val = twl6040_read(component, TWL6040_REG_HSLCTL);
+		if (val & TWL6040_HSDACMODE)
+			/* HSDACL in LP mode */
+			return -8; /* -8dB */
+		else
+			/* HSDACL in HP mode */
+			return -1; /* -1dB */
+	}
+	return 0; /* 0dB */
+}
+EXPORT_SYMBOL_GPL(twl6040_get_dl1_gain);
+
+int twl6040_get_clk_id(struct snd_soc_component *component)
+{
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+
+	return priv->pll_power_mode;
+}
+EXPORT_SYMBOL_GPL(twl6040_get_clk_id);
+
+int twl6040_get_trim_value(struct snd_soc_component *component, enum twl6040_trim trim)
+{
+	if (unlikely(trim >= TWL6040_TRIM_INVAL))
+		return -EINVAL;
+
+	return twl6040_read(component, TWL6040_REG_TRIM1 + trim);
+}
+EXPORT_SYMBOL_GPL(twl6040_get_trim_value);
+
+int twl6040_get_hs_step_size(struct snd_soc_component *component)
+{
+	struct twl6040 *twl6040 = to_twl6040(component);
+
+	if (twl6040_get_revid(twl6040) < TWL6040_REV_ES1_3)
+		/* For ES under ES_1.3 HS step is 2 mV */
+		return 2;
+	else
+		/* For ES_1.3 HS step is 1 mV */
+		return 1;
+}
+EXPORT_SYMBOL_GPL(twl6040_get_hs_step_size);
+
+static const struct snd_kcontrol_new twl6040_snd_controls[] = {
+	/* Capture gains */
+	SOC_DOUBLE_TLV("Capture Preamplifier Volume",
+		TWL6040_REG_MICGAIN, 6, 7, 1, 1, mic_preamp_tlv),
+	SOC_DOUBLE_TLV("Capture Volume",
+		TWL6040_REG_MICGAIN, 0, 3, 4, 0, mic_amp_tlv),
+
+	/* AFM gains */
+	SOC_DOUBLE_TLV("Aux FM Volume",
+		TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv),
+
+	/* Playback gains */
+	SOC_DOUBLE_TLV("Headset Playback Volume",
+		TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, hs_tlv),
+	SOC_DOUBLE_R_TLV("Handsfree Playback Volume",
+		TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv),
+	SOC_SINGLE_TLV("Earphone Playback Volume",
+		TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv),
+
+	SOC_ENUM_EXT("Headset Power Mode", twl6040_power_mode_enum,
+		twl6040_headset_power_get_enum,
+		twl6040_headset_power_put_enum),
+
+	/* Left HS PDM data routed to Right HSDAC */
+	SOC_SINGLE("Headset Mono to Stereo Playback Switch",
+		TWL6040_REG_HSRCTL, 7, 1, 0),
+
+	/* Left HF PDM data routed to Right HFDAC */
+	SOC_SINGLE("Handsfree Mono to Stereo Playback Switch",
+		TWL6040_REG_HFRCTL, 5, 1, 0),
+
+	SOC_ENUM_EXT("PLL Selection", twl6040_power_mode_enum,
+		twl6040_pll_get_enum, twl6040_pll_put_enum),
+};
+
+static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("MAINMIC"),
+	SND_SOC_DAPM_INPUT("HSMIC"),
+	SND_SOC_DAPM_INPUT("SUBMIC"),
+	SND_SOC_DAPM_INPUT("AFML"),
+	SND_SOC_DAPM_INPUT("AFMR"),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("HSOL"),
+	SND_SOC_DAPM_OUTPUT("HSOR"),
+	SND_SOC_DAPM_OUTPUT("HFL"),
+	SND_SOC_DAPM_OUTPUT("HFR"),
+	SND_SOC_DAPM_OUTPUT("EP"),
+	SND_SOC_DAPM_OUTPUT("AUXL"),
+	SND_SOC_DAPM_OUTPUT("AUXR"),
+	SND_SOC_DAPM_OUTPUT("VIBRAL"),
+	SND_SOC_DAPM_OUTPUT("VIBRAR"),
+
+	/* Analog input muxes for the capture amplifiers */
+	SND_SOC_DAPM_MUX("Analog Left Capture Route",
+			SND_SOC_NOPM, 0, 0, &amicl_control),
+	SND_SOC_DAPM_MUX("Analog Right Capture Route",
+			SND_SOC_NOPM, 0, 0, &amicr_control),
+
+	/* Analog capture PGAs */
+	SND_SOC_DAPM_PGA("MicAmpL",
+			TWL6040_REG_MICLCTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MicAmpR",
+			TWL6040_REG_MICRCTL, 0, 0, NULL, 0),
+
+	/* Auxiliary FM PGAs */
+	SND_SOC_DAPM_PGA("AFMAmpL",
+			TWL6040_REG_MICLCTL, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AFMAmpR",
+			TWL6040_REG_MICRCTL, 1, 0, NULL, 0),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC Left", NULL, TWL6040_REG_MICLCTL, 2, 0),
+	SND_SOC_DAPM_ADC("ADC Right", NULL, TWL6040_REG_MICRCTL, 2, 0),
+
+	/* Microphone bias */
+	SND_SOC_DAPM_SUPPLY("Headset Mic Bias",
+			    TWL6040_REG_AMICBCTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Main Mic Bias",
+			    TWL6040_REG_AMICBCTL, 4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Digital Mic1 Bias",
+			    TWL6040_REG_DMICBCTL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Digital Mic2 Bias",
+			    TWL6040_REG_DMICBCTL, 4, 0, NULL, 0),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("HSDAC Left", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("HSDAC Right", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("HFDAC Left", NULL, TWL6040_REG_HFLCTL, 0, 0),
+	SND_SOC_DAPM_DAC("HFDAC Right", NULL, TWL6040_REG_HFRCTL, 0, 0),
+	/* Virtual DAC for vibra path (DL4 channel) */
+	SND_SOC_DAPM_DAC("VIBRA DAC", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MUX("Handsfree Left Playback",
+			SND_SOC_NOPM, 0, 0, &hfl_mux_controls),
+	SND_SOC_DAPM_MUX("Handsfree Right Playback",
+			SND_SOC_NOPM, 0, 0, &hfr_mux_controls),
+	/* Analog playback Muxes */
+	SND_SOC_DAPM_MUX("Headset Left Playback",
+			SND_SOC_NOPM, 0, 0, &hsl_mux_controls),
+	SND_SOC_DAPM_MUX("Headset Right Playback",
+			SND_SOC_NOPM, 0, 0, &hsr_mux_controls),
+
+	SND_SOC_DAPM_MUX("Vibra Left Playback", SND_SOC_NOPM, 0, 0,
+			&vibral_mux_controls),
+	SND_SOC_DAPM_MUX("Vibra Right Playback", SND_SOC_NOPM, 0, 0,
+			&vibrar_mux_controls),
+
+	SND_SOC_DAPM_SWITCH("Earphone Playback", SND_SOC_NOPM, 0, 0,
+			&ep_path_enable_control),
+	SND_SOC_DAPM_SWITCH("AUXL Playback", SND_SOC_NOPM, 0, 0,
+			&auxl_switch_control),
+	SND_SOC_DAPM_SWITCH("AUXR Playback", SND_SOC_NOPM, 0, 0,
+			&auxr_switch_control),
+
+	/* Analog playback drivers */
+	SND_SOC_DAPM_OUT_DRV("HF Left Driver",
+			TWL6040_REG_HFLCTL, 4, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("HF Right Driver",
+			TWL6040_REG_HFRCTL, 4, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("HS Left Driver",
+			TWL6040_REG_HSLCTL, 2, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("HS Right Driver",
+			TWL6040_REG_HSRCTL, 2, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV_E("Earphone Driver",
+			TWL6040_REG_EARCTL, 0, 0, NULL, 0,
+			twl6040_ep_drv_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_OUT_DRV("Vibra Left Driver",
+			TWL6040_REG_VIBCTLL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUT_DRV("Vibra Right Driver",
+			TWL6040_REG_VIBCTLR, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Vibra Left Control", TWL6040_REG_VIBCTLL, 2, 0,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Vibra Right Control", TWL6040_REG_VIBCTLR, 2, 0,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("HSDAC Power", 1, SND_SOC_NOPM, 0, 0,
+			      twl6040_hs_dac_event,
+			      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* Analog playback PGAs */
+	SND_SOC_DAPM_PGA("HF Left PGA",
+			TWL6040_REG_HFLCTL, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HF Right PGA",
+			TWL6040_REG_HFRCTL, 1, 0, NULL, 0),
+
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	/* Stream -> DAC mapping */
+	{"HSDAC Left", NULL, "Legacy Playback"},
+	{"HSDAC Left", NULL, "Headset Playback"},
+	{"HSDAC Right", NULL, "Legacy Playback"},
+	{"HSDAC Right", NULL, "Headset Playback"},
+
+	{"HFDAC Left", NULL, "Legacy Playback"},
+	{"HFDAC Left", NULL, "Handsfree Playback"},
+	{"HFDAC Right", NULL, "Legacy Playback"},
+	{"HFDAC Right", NULL, "Handsfree Playback"},
+
+	{"VIBRA DAC", NULL, "Legacy Playback"},
+	{"VIBRA DAC", NULL, "Vibra Playback"},
+
+	/* ADC -> Stream mapping */
+	{"Legacy Capture" , NULL, "ADC Left"},
+	{"Capture", NULL, "ADC Left"},
+	{"Legacy Capture", NULL, "ADC Right"},
+	{"Capture" , NULL, "ADC Right"},
+
+	/* Capture path */
+	{"Analog Left Capture Route", "Headset Mic", "HSMIC"},
+	{"Analog Left Capture Route", "Main Mic", "MAINMIC"},
+	{"Analog Left Capture Route", "Aux/FM Left", "AFML"},
+
+	{"Analog Right Capture Route", "Headset Mic", "HSMIC"},
+	{"Analog Right Capture Route", "Sub Mic", "SUBMIC"},
+	{"Analog Right Capture Route", "Aux/FM Right", "AFMR"},
+
+	{"MicAmpL", NULL, "Analog Left Capture Route"},
+	{"MicAmpR", NULL, "Analog Right Capture Route"},
+
+	{"ADC Left", NULL, "MicAmpL"},
+	{"ADC Right", NULL, "MicAmpR"},
+
+	/* AFM path */
+	{"AFMAmpL", NULL, "AFML"},
+	{"AFMAmpR", NULL, "AFMR"},
+
+	{"HSDAC Left", NULL, "HSDAC Power"},
+	{"HSDAC Right", NULL, "HSDAC Power"},
+
+	{"Headset Left Playback", "HS DAC", "HSDAC Left"},
+	{"Headset Left Playback", "Line-In amp", "AFMAmpL"},
+
+	{"Headset Right Playback", "HS DAC", "HSDAC Right"},
+	{"Headset Right Playback", "Line-In amp", "AFMAmpR"},
+
+	{"HS Left Driver", NULL, "Headset Left Playback"},
+	{"HS Right Driver", NULL, "Headset Right Playback"},
+
+	{"HSOL", NULL, "HS Left Driver"},
+	{"HSOR", NULL, "HS Right Driver"},
+
+	/* Earphone playback path */
+	{"Earphone Playback", "Switch", "HSDAC Left"},
+	{"Earphone Driver", NULL, "Earphone Playback"},
+	{"EP", NULL, "Earphone Driver"},
+
+	{"Handsfree Left Playback", "HF DAC", "HFDAC Left"},
+	{"Handsfree Left Playback", "Line-In amp", "AFMAmpL"},
+
+	{"Handsfree Right Playback", "HF DAC", "HFDAC Right"},
+	{"Handsfree Right Playback", "Line-In amp", "AFMAmpR"},
+
+	{"HF Left PGA", NULL, "Handsfree Left Playback"},
+	{"HF Right PGA", NULL, "Handsfree Right Playback"},
+
+	{"HF Left Driver", NULL, "HF Left PGA"},
+	{"HF Right Driver", NULL, "HF Right PGA"},
+
+	{"HFL", NULL, "HF Left Driver"},
+	{"HFR", NULL, "HF Right Driver"},
+
+	{"AUXL Playback", "Switch", "HF Left PGA"},
+	{"AUXR Playback", "Switch", "HF Right PGA"},
+
+	{"AUXL", NULL, "AUXL Playback"},
+	{"AUXR", NULL, "AUXR Playback"},
+
+	/* Vibrator paths */
+	{"Vibra Left Playback", "Audio PDM", "VIBRA DAC"},
+	{"Vibra Right Playback", "Audio PDM", "VIBRA DAC"},
+
+	{"Vibra Left Driver", NULL, "Vibra Left Playback"},
+	{"Vibra Right Driver", NULL, "Vibra Right Playback"},
+	{"Vibra Left Driver", NULL, "Vibra Left Control"},
+	{"Vibra Right Driver", NULL, "Vibra Right Control"},
+
+	{"VIBRAL", NULL, "Vibra Left Driver"},
+	{"VIBRAR", NULL, "Vibra Right Driver"},
+};
+
+static int twl6040_set_bias_level(struct snd_soc_component *component,
+				enum snd_soc_bias_level level)
+{
+	struct twl6040 *twl6040 = to_twl6040(component);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (priv->codec_powered) {
+			/* Select low power PLL in standby */
+			ret = twl6040_set_pll(twl6040, TWL6040_SYSCLK_SEL_LPPLL,
+					      32768, 19200000);
+			break;
+		}
+
+		ret = twl6040_power(twl6040, 1);
+		if (ret)
+			break;
+
+		priv->codec_powered = 1;
+
+		/* Set external boost GPO */
+		twl6040_write(component, TWL6040_REG_GPOCTL, 0x02);
+		break;
+	case SND_SOC_BIAS_OFF:
+		if (!priv->codec_powered)
+			break;
+
+		twl6040_power(twl6040, 0);
+		priv->codec_powered = 0;
+		break;
+	}
+
+	return ret;
+}
+
+static int twl6040_startup(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&sysclk_constraints[priv->pll_power_mode]);
+
+	return 0;
+}
+
+static int twl6040_hw_params(struct snd_pcm_substream *substream,
+			struct snd_pcm_hw_params *params,
+			struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+	int rate;
+
+	rate = params_rate(params);
+	switch (rate) {
+	case 11250:
+	case 22500:
+	case 44100:
+	case 88200:
+		/* These rates are not supported when HPPLL is in use */
+		if (unlikely(priv->pll == TWL6040_SYSCLK_SEL_HPPLL)) {
+			dev_err(component->dev, "HPPLL does not support rate %d\n",
+				rate);
+			return -EINVAL;
+		}
+		priv->sysclk = 17640000;
+		break;
+	case 8000:
+	case 16000:
+	case 32000:
+	case 48000:
+	case 96000:
+		priv->sysclk = 19200000;
+		break;
+	default:
+		dev_err(component->dev, "unsupported rate %d\n", rate);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int twl6040_prepare(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct twl6040 *twl6040 = to_twl6040(component);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	if (!priv->sysclk) {
+		dev_err(component->dev,
+			"no mclk configured, call set_sysclk() on init\n");
+		return -EINVAL;
+	}
+
+	ret = twl6040_set_pll(twl6040, priv->pll, priv->clk_in, priv->sysclk);
+	if (ret) {
+		dev_err(component->dev, "Can not set PLL (%d)\n", ret);
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case TWL6040_SYSCLK_SEL_LPPLL:
+	case TWL6040_SYSCLK_SEL_HPPLL:
+		priv->pll = clk_id;
+		priv->clk_in = freq;
+		break;
+	default:
+		dev_err(component->dev, "unknown clk_id %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void twl6040_mute_path(struct snd_soc_component *component, enum twl6040_dai_id id,
+			     int mute)
+{
+	struct twl6040 *twl6040 = to_twl6040(component);
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+	int hslctl, hsrctl, earctl;
+	int hflctl, hfrctl;
+
+	switch (id) {
+	case TWL6040_DAI_DL1:
+		hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
+		hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
+		earctl = twl6040_read(component, TWL6040_REG_EARCTL);
+
+		if (mute) {
+			/* Power down drivers and DACs */
+			earctl &= ~0x01;
+			hslctl &= ~(TWL6040_HSDRVENA | TWL6040_HSDACENA);
+			hsrctl &= ~(TWL6040_HSDRVENA | TWL6040_HSDACENA);
+
+		}
+
+		twl6040_reg_write(twl6040, TWL6040_REG_EARCTL, earctl);
+		twl6040_reg_write(twl6040, TWL6040_REG_HSLCTL, hslctl);
+		twl6040_reg_write(twl6040, TWL6040_REG_HSRCTL, hsrctl);
+		priv->dl1_unmuted = !mute;
+		break;
+	case TWL6040_DAI_DL2:
+		hflctl = twl6040_read(component, TWL6040_REG_HFLCTL);
+		hfrctl = twl6040_read(component, TWL6040_REG_HFRCTL);
+
+		if (mute) {
+			/* Power down drivers and DACs */
+			hflctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA |
+				    TWL6040_HFDRVENA | TWL6040_HFSWENA);
+			hfrctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA |
+				    TWL6040_HFDRVENA | TWL6040_HFSWENA);
+		}
+
+		twl6040_reg_write(twl6040, TWL6040_REG_HFLCTL, hflctl);
+		twl6040_reg_write(twl6040, TWL6040_REG_HFRCTL, hfrctl);
+		priv->dl2_unmuted = !mute;
+		break;
+	default:
+		break;
+	}
+}
+
+static int twl6040_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	switch (dai->id) {
+	case TWL6040_DAI_LEGACY:
+		twl6040_mute_path(dai->component, TWL6040_DAI_DL1, mute);
+		twl6040_mute_path(dai->component, TWL6040_DAI_DL2, mute);
+		break;
+	case TWL6040_DAI_DL1:
+	case TWL6040_DAI_DL2:
+		twl6040_mute_path(dai->component, dai->id, mute);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops twl6040_dai_ops = {
+	.startup	= twl6040_startup,
+	.hw_params	= twl6040_hw_params,
+	.prepare	= twl6040_prepare,
+	.set_sysclk	= twl6040_set_dai_sysclk,
+	.digital_mute	= twl6040_digital_mute,
+};
+
+static struct snd_soc_dai_driver twl6040_dai[] = {
+{
+	.name = "twl6040-legacy",
+	.id = TWL6040_DAI_LEGACY,
+	.playback = {
+		.stream_name = "Legacy Playback",
+		.channels_min = 1,
+		.channels_max = 5,
+		.rates = TWL6040_RATES,
+		.formats = TWL6040_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Legacy Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = TWL6040_RATES,
+		.formats = TWL6040_FORMATS,
+	},
+	.ops = &twl6040_dai_ops,
+},
+{
+	.name = "twl6040-ul",
+	.id = TWL6040_DAI_UL,
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = TWL6040_RATES,
+		.formats = TWL6040_FORMATS,
+	},
+	.ops = &twl6040_dai_ops,
+},
+{
+	.name = "twl6040-dl1",
+	.id = TWL6040_DAI_DL1,
+	.playback = {
+		.stream_name = "Headset Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = TWL6040_RATES,
+		.formats = TWL6040_FORMATS,
+	},
+	.ops = &twl6040_dai_ops,
+},
+{
+	.name = "twl6040-dl2",
+	.id = TWL6040_DAI_DL2,
+	.playback = {
+		.stream_name = "Handsfree Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = TWL6040_RATES,
+		.formats = TWL6040_FORMATS,
+	},
+	.ops = &twl6040_dai_ops,
+},
+{
+	.name = "twl6040-vib",
+	.id = TWL6040_DAI_VIB,
+	.playback = {
+		.stream_name = "Vibra Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_CONTINUOUS,
+		.formats = TWL6040_FORMATS,
+	},
+	.ops = &twl6040_dai_ops,
+},
+};
+
+static int twl6040_probe(struct snd_soc_component *component)
+{
+	struct twl6040_data *priv;
+	struct platform_device *pdev = to_platform_device(component->dev);
+	int ret = 0;
+
+	priv = devm_kzalloc(component->dev, sizeof(*priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	snd_soc_component_set_drvdata(component, priv);
+
+	priv->component = component;
+
+	priv->plug_irq = platform_get_irq(pdev, 0);
+	if (priv->plug_irq < 0) {
+		dev_err(component->dev, "invalid irq: %d\n", priv->plug_irq);
+		return priv->plug_irq;
+	}
+
+	INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work);
+
+	mutex_init(&priv->mutex);
+
+	ret = request_threaded_irq(priv->plug_irq, NULL,
+					twl6040_audio_handler,
+					IRQF_NO_SUSPEND | IRQF_ONESHOT,
+					"twl6040_irq_plug", component);
+	if (ret) {
+		dev_err(component->dev, "PLUG IRQ request failed: %d\n", ret);
+		return ret;
+	}
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+	twl6040_init_chip(component);
+
+	return 0;
+}
+
+static void twl6040_remove(struct snd_soc_component *component)
+{
+	struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+
+	free_irq(priv->plug_irq, component);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_twl6040 = {
+	.probe			= twl6040_probe,
+	.remove			= twl6040_remove,
+	.read			= twl6040_read,
+	.write			= twl6040_write,
+	.set_bias_level		= twl6040_set_bias_level,
+	.controls		= twl6040_snd_controls,
+	.num_controls		= ARRAY_SIZE(twl6040_snd_controls),
+	.dapm_widgets		= twl6040_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(twl6040_dapm_widgets),
+	.dapm_routes		= intercon,
+	.num_dapm_routes	= ARRAY_SIZE(intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int twl6040_codec_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_twl6040,
+				      twl6040_dai, ARRAY_SIZE(twl6040_dai));
+}
+
+static struct platform_driver twl6040_codec_driver = {
+	.driver = {
+		.name = "twl6040-codec",
+	},
+	.probe = twl6040_codec_probe,
+};
+
+module_platform_driver(twl6040_codec_driver);
+
+MODULE_DESCRIPTION("ASoC TWL6040 codec driver");
+MODULE_AUTHOR("Misael Lopez Cruz");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/twl6040.h b/sound/soc/codecs/twl6040.h
new file mode 100644
index 0000000..3d9f957
--- /dev/null
+++ b/sound/soc/codecs/twl6040.h
@@ -0,0 +1,44 @@
+/*
+ * ALSA SoC TWL6040 codec driver
+ *
+ * Author:	Misael Lopez Cruz <x0052729@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TWL6040_H__
+#define __TWL6040_H__
+
+enum twl6040_trim {
+	TWL6040_TRIM_TRIM1 = 0,
+	TWL6040_TRIM_TRIM2,
+	TWL6040_TRIM_TRIM3,
+	TWL6040_TRIM_HSOTRIM,
+	TWL6040_TRIM_HFOTRIM,
+	TWL6040_TRIM_INVAL,
+};
+
+#define TWL6040_HSF_TRIM_LEFT(x)	(x & 0x0f)
+#define TWL6040_HSF_TRIM_RIGHT(x)	((x >> 4) & 0x0f)
+
+int twl6040_get_dl1_gain(struct snd_soc_component *component);
+void twl6040_hs_jack_detect(struct snd_soc_component *component,
+			    struct snd_soc_jack *jack, int report);
+int twl6040_get_clk_id(struct snd_soc_component *component);
+int twl6040_get_trim_value(struct snd_soc_component *component, enum twl6040_trim trim);
+int twl6040_get_hs_step_size(struct snd_soc_component *component);
+
+#endif /* End of __TWL6040_H__ */
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
new file mode 100644
index 0000000..3c935a9
--- /dev/null
+++ b/sound/soc/codecs/uda134x.c
@@ -0,0 +1,590 @@
+/*
+ * uda134x.c  --  UDA134X ALSA SoC Codec driver
+ *
+ * Modifications by Christian Pellegrin <chripell@evolware.org>
+ *
+ * Copyright 2007 Dension Audio Systems Ltd.
+ * Author: Zoltan Devai
+ *
+ * Based on the WM87xx drivers by Liam Girdwood and Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include <sound/uda134x.h>
+#include <sound/l3.h>
+
+#include "uda134x.h"
+
+
+#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000
+#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
+		SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
+
+struct uda134x_priv {
+	int sysclk;
+	int dai_fmt;
+
+	struct snd_pcm_substream *master_substream;
+	struct snd_pcm_substream *slave_substream;
+
+	struct regmap *regmap;
+	struct uda134x_platform_data *pd;
+};
+
+static const struct reg_default uda134x_reg_defaults[] = {
+	{ UDA134X_EA000, 0x04 },
+	{ UDA134X_EA001, 0x04 },
+	{ UDA134X_EA010, 0x04 },
+	{ UDA134X_EA011, 0x00 },
+	{ UDA134X_EA100, 0x00 },
+	{ UDA134X_EA101, 0x00 },
+	{ UDA134X_EA110, 0x00 },
+	{ UDA134X_EA111, 0x00 },
+	{ UDA134X_STATUS0, 0x00 },
+	{ UDA134X_STATUS1, 0x03 },
+	{ UDA134X_DATA000, 0x00 },
+	{ UDA134X_DATA001, 0x00 },
+	{ UDA134X_DATA010, 0x00 },
+	{ UDA134X_DATA011, 0x00 },
+	{ UDA134X_DATA1, 0x00 },
+};
+
+/*
+ * Write to the uda134x registers
+ *
+ */
+static int uda134x_regmap_write(void *context, unsigned int reg,
+	unsigned int value)
+{
+	struct uda134x_platform_data *pd = context;
+	int ret;
+	u8 addr;
+	u8 data = value;
+
+	switch (reg) {
+	case UDA134X_STATUS0:
+	case UDA134X_STATUS1:
+		addr = UDA134X_STATUS_ADDR;
+		data |= (reg - UDA134X_STATUS0) << 7;
+		break;
+	case UDA134X_DATA000:
+	case UDA134X_DATA001:
+	case UDA134X_DATA010:
+	case UDA134X_DATA011:
+		addr = UDA134X_DATA0_ADDR;
+		data |= (reg - UDA134X_DATA000) << 6;
+		break;
+	case UDA134X_DATA1:
+		addr = UDA134X_DATA1_ADDR;
+		break;
+	default:
+		/* It's an extended address register */
+		addr =  (reg | UDA134X_EXTADDR_PREFIX);
+
+		ret = l3_write(&pd->l3,
+			       UDA134X_DATA0_ADDR, &addr, 1);
+		if (ret != 1)
+			return -EIO;
+
+		addr = UDA134X_DATA0_ADDR;
+		data = (value | UDA134X_EXTDATA_PREFIX);
+		break;
+	}
+
+	ret = l3_write(&pd->l3,
+		       addr, &data, 1);
+	if (ret != 1)
+		return -EIO;
+
+	return 0;
+}
+
+static inline void uda134x_reset(struct snd_soc_component *component)
+{
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
+	unsigned int mask = 1<<6;
+
+	regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, mask);
+	msleep(1);
+	regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, 0);
+}
+
+static int uda134x_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(dai->component);
+	unsigned int mask = 1<<2;
+	unsigned int val;
+
+	pr_debug("%s mute: %d\n", __func__, mute);
+
+	if (mute)
+		val = mask;
+	else
+		val = 0;
+
+	return regmap_update_bits(uda134x->regmap, UDA134X_DATA010, mask, val);
+}
+
+static int uda134x_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
+	struct snd_pcm_runtime *master_runtime;
+
+	if (uda134x->master_substream) {
+		master_runtime = uda134x->master_substream->runtime;
+
+		pr_debug("%s constraining to %d bits at %d\n", __func__,
+			 master_runtime->sample_bits,
+			 master_runtime->rate);
+
+		snd_pcm_hw_constraint_single(substream->runtime,
+					     SNDRV_PCM_HW_PARAM_RATE,
+					     master_runtime->rate);
+
+		snd_pcm_hw_constraint_single(substream->runtime,
+					     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+					     master_runtime->sample_bits);
+
+		uda134x->slave_substream = substream;
+	} else
+		uda134x->master_substream = substream;
+
+	return 0;
+}
+
+static void uda134x_shutdown(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
+
+	if (uda134x->master_substream == substream)
+		uda134x->master_substream = uda134x->slave_substream;
+
+	uda134x->slave_substream = NULL;
+}
+
+static int uda134x_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
+	unsigned int hw_params = 0;
+
+	if (substream == uda134x->slave_substream) {
+		pr_debug("%s ignoring hw_params for slave substream\n",
+			 __func__);
+		return 0;
+	}
+
+	pr_debug("%s sysclk: %d, rate:%d\n", __func__,
+		 uda134x->sysclk, params_rate(params));
+
+	/* set SYSCLK / fs ratio */
+	switch (uda134x->sysclk / params_rate(params)) {
+	case 512:
+		break;
+	case 384:
+		hw_params |= (1<<4);
+		break;
+	case 256:
+		hw_params |= (1<<5);
+		break;
+	default:
+		printk(KERN_ERR "%s unsupported fs\n", __func__);
+		return -EINVAL;
+	}
+
+	pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__,
+		 uda134x->dai_fmt, params_format(params));
+
+	/* set DAI format and word length */
+	switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (params_width(params)) {
+		case 16:
+			hw_params |= (1<<1);
+			break;
+		case 18:
+			hw_params |= (1<<2);
+			break;
+		case 20:
+			hw_params |= ((1<<2) | (1<<1));
+			break;
+		default:
+			printk(KERN_ERR "%s unsupported format (right)\n",
+			       __func__);
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		hw_params |= (1<<3);
+		break;
+	default:
+		printk(KERN_ERR "%s unsupported format\n", __func__);
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(uda134x->regmap, UDA134X_STATUS0,
+		STATUS0_SYSCLK_MASK | STATUS0_DAIFMT_MASK, hw_params);
+}
+
+static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
+
+	pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
+		 clk_id, freq, dir);
+
+	/* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable
+	   because the codec is slave. Of course limitations of the clock
+	   master (the IIS controller) apply.
+	   We'll error out on set_hw_params if it's not OK */
+	if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
+		uda134x->sysclk = freq;
+		return 0;
+	}
+
+	printk(KERN_ERR "%s unsupported sysclk\n", __func__);
+	return -EINVAL;
+}
+
+static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			       unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
+
+	pr_debug("%s fmt: %08X\n", __func__, fmt);
+
+	/* codec supports only full slave mode */
+	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+		printk(KERN_ERR "%s unsupported slave mode\n", __func__);
+		return -EINVAL;
+	}
+
+	/* no support for clock inversion */
+	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
+		printk(KERN_ERR "%s unsupported clock inversion\n", __func__);
+		return -EINVAL;
+	}
+
+	/* We can't setup DAI format here as it depends on the word bit num */
+	/* so let's just store the value for later */
+	uda134x->dai_fmt = fmt;
+
+	return 0;
+}
+
+static int uda134x_set_bias_level(struct snd_soc_component *component,
+				  enum snd_soc_bias_level level)
+{
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
+	struct uda134x_platform_data *pd = uda134x->pd;
+	pr_debug("%s bias level %d\n", __func__, level);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* power on */
+		if (pd->power) {
+			pd->power(1);
+			regcache_sync(uda134x->regmap);
+		}
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* power off */
+		if (pd->power) {
+			pd->power(0);
+			regcache_mark_dirty(uda134x->regmap);
+		}
+		break;
+	}
+	return 0;
+}
+
+static const char *uda134x_dsp_setting[] = {"Flat", "Minimum1",
+					    "Minimum2", "Maximum"};
+static const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+static const char *uda134x_mixmode[] = {"Differential", "Analog1",
+					"Analog2", "Both"};
+
+static const struct soc_enum uda134x_mixer_enum[] = {
+SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting),
+SOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph),
+SOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode),
+};
+
+static const struct snd_kcontrol_new uda1341_snd_controls[] = {
+SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
+SOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0),
+SOC_SINGLE("Analog1 Volume", UDA134X_EA000, 0, 0x1F, 1),
+SOC_SINGLE("Analog2 Volume", UDA134X_EA001, 0, 0x1F, 1),
+
+SOC_SINGLE("Mic Sensitivity", UDA134X_EA010, 2, 7, 0),
+SOC_SINGLE("Mic Volume", UDA134X_EA101, 0, 0x1F, 0),
+
+SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
+SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
+
+SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
+SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
+SOC_ENUM("Input Mux", uda134x_mixer_enum[2]),
+
+SOC_SINGLE("AGC Switch", UDA134X_EA100, 4, 1, 0),
+SOC_SINGLE("AGC Target Volume", UDA134X_EA110, 0, 0x03, 1),
+SOC_SINGLE("AGC Timing", UDA134X_EA110, 2, 0x07, 0),
+
+SOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1, 6, 1, 0),
+SOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1, 5, 1, 0),
+SOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1, 4, 1, 0),
+SOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1, 3, 1, 0),
+SOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1, 2, 1, 0),
+SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new uda1340_snd_controls[] = {
+SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
+
+SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
+SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
+
+SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
+SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
+
+SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new uda1345_snd_controls[] = {
+SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
+
+SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
+
+SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
+};
+
+/* UDA1341 has the DAC/ADC power down in STATUS1 */
+static const struct snd_soc_dapm_widget uda1341_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_STATUS1, 0, 0),
+	SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_STATUS1, 1, 0),
+};
+
+/* UDA1340/4/5 has the DAC/ADC pwoer down in DATA0 11 */
+static const struct snd_soc_dapm_widget uda1340_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_DATA011, 0, 0),
+	SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_DATA011, 1, 0),
+};
+
+/* Common DAPM widgets */
+static const struct snd_soc_dapm_widget uda134x_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("VINL1"),
+	SND_SOC_DAPM_INPUT("VINR1"),
+	SND_SOC_DAPM_INPUT("VINL2"),
+	SND_SOC_DAPM_INPUT("VINR2"),
+	SND_SOC_DAPM_OUTPUT("VOUTL"),
+	SND_SOC_DAPM_OUTPUT("VOUTR"),
+};
+
+static const struct snd_soc_dapm_route uda134x_dapm_routes[] = {
+	{ "ADC", NULL, "VINL1" },
+	{ "ADC", NULL, "VINR1" },
+	{ "ADC", NULL, "VINL2" },
+	{ "ADC", NULL, "VINR2" },
+	{ "VOUTL", NULL, "DAC" },
+	{ "VOUTR", NULL, "DAC" },
+};
+
+static const struct snd_soc_dai_ops uda134x_dai_ops = {
+	.startup	= uda134x_startup,
+	.shutdown	= uda134x_shutdown,
+	.hw_params	= uda134x_hw_params,
+	.digital_mute	= uda134x_mute,
+	.set_sysclk	= uda134x_set_dai_sysclk,
+	.set_fmt	= uda134x_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver uda134x_dai = {
+	.name = "uda134x-hifi",
+	/* playback capabilities */
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = UDA134X_RATES,
+		.formats = UDA134X_FORMATS,
+	},
+	/* capture capabilities */
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = UDA134X_RATES,
+		.formats = UDA134X_FORMATS,
+	},
+	/* pcm operations */
+	.ops = &uda134x_dai_ops,
+};
+
+static int uda134x_soc_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
+	struct uda134x_platform_data *pd = uda134x->pd;
+	const struct snd_soc_dapm_widget *widgets;
+	unsigned num_widgets;
+	int ret;
+
+	printk(KERN_INFO "UDA134X SoC Audio Codec\n");
+
+	switch (pd->model) {
+	case UDA134X_UDA1340:
+	case UDA134X_UDA1341:
+	case UDA134X_UDA1344:
+	case UDA134X_UDA1345:
+		break;
+	default:
+		printk(KERN_ERR "UDA134X SoC codec: "
+		       "unsupported model %d\n",
+			pd->model);
+		return -EINVAL;
+	}
+
+	if (pd->power)
+		pd->power(1);
+
+	uda134x_reset(component);
+
+	if (pd->model == UDA134X_UDA1341) {
+		widgets = uda1341_dapm_widgets;
+		num_widgets = ARRAY_SIZE(uda1341_dapm_widgets);
+	} else {
+		widgets = uda1340_dapm_widgets;
+		num_widgets = ARRAY_SIZE(uda1340_dapm_widgets);
+	}
+
+	ret = snd_soc_dapm_new_controls(dapm, widgets, num_widgets);
+	if (ret) {
+		printk(KERN_ERR "%s failed to register dapm controls: %d",
+			__func__, ret);
+		return ret;
+	}
+
+	switch (pd->model) {
+	case UDA134X_UDA1340:
+	case UDA134X_UDA1344:
+		ret = snd_soc_add_component_controls(component, uda1340_snd_controls,
+					ARRAY_SIZE(uda1340_snd_controls));
+	break;
+	case UDA134X_UDA1341:
+		ret = snd_soc_add_component_controls(component, uda1341_snd_controls,
+					ARRAY_SIZE(uda1341_snd_controls));
+	break;
+	case UDA134X_UDA1345:
+		ret = snd_soc_add_component_controls(component, uda1345_snd_controls,
+					ARRAY_SIZE(uda1345_snd_controls));
+	break;
+	default:
+		printk(KERN_ERR "%s unknown codec type: %d",
+			__func__, pd->model);
+		return -EINVAL;
+	}
+
+	if (ret < 0) {
+		printk(KERN_ERR "UDA134X: failed to register controls\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_uda134x = {
+	.probe			= uda134x_soc_probe,
+	.set_bias_level		= uda134x_set_bias_level,
+	.dapm_widgets		= uda134x_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(uda134x_dapm_widgets),
+	.dapm_routes		= uda134x_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(uda134x_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config uda134x_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = UDA134X_DATA1,
+	.reg_defaults = uda134x_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(uda134x_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.reg_write = uda134x_regmap_write,
+};
+
+static int uda134x_codec_probe(struct platform_device *pdev)
+{
+	struct uda134x_platform_data *pd = pdev->dev.platform_data;
+	struct uda134x_priv *uda134x;
+	int ret;
+
+	if (!pd) {
+		dev_err(&pdev->dev, "Missing L3 bitbang function\n");
+		return -ENODEV;
+	}
+
+	uda134x = devm_kzalloc(&pdev->dev, sizeof(*uda134x), GFP_KERNEL);
+	if (!uda134x)
+		return -ENOMEM;
+
+	uda134x->pd = pd;
+	platform_set_drvdata(pdev, uda134x);
+
+	if (pd->l3.use_gpios) {
+		ret = l3_set_gpio_ops(&pdev->dev, &uda134x->pd->l3);
+		if (ret < 0)
+			return ret;
+	}
+
+	uda134x->regmap = devm_regmap_init(&pdev->dev, NULL, pd,
+		&uda134x_regmap_config);
+	if (IS_ERR(uda134x->regmap))
+		return PTR_ERR(uda134x->regmap);
+
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_uda134x, &uda134x_dai, 1);
+}
+
+static struct platform_driver uda134x_codec_driver = {
+	.driver = {
+		.name = "uda134x-codec",
+	},
+	.probe = uda134x_codec_probe,
+};
+
+module_platform_driver(uda134x_codec_driver);
+
+MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
+MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h
new file mode 100644
index 0000000..664618c
--- /dev/null
+++ b/sound/soc/codecs/uda134x.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _UDA134X_CODEC_H
+#define _UDA134X_CODEC_H
+
+#define UDA134X_L3ADDR	5
+#define UDA134X_DATA0_ADDR	((UDA134X_L3ADDR << 2) | 0)
+#define UDA134X_DATA1_ADDR	((UDA134X_L3ADDR << 2) | 1)
+#define UDA134X_STATUS_ADDR	((UDA134X_L3ADDR << 2) | 2)
+
+#define UDA134X_EXTADDR_PREFIX	0xC0
+#define UDA134X_EXTDATA_PREFIX	0xE0
+
+/* UDA134X registers */
+#define UDA134X_EA000	0
+#define UDA134X_EA001	1
+#define UDA134X_EA010	2
+#define UDA134X_EA011	3
+#define UDA134X_EA100	4
+#define UDA134X_EA101	5
+#define UDA134X_EA110	6
+#define UDA134X_EA111	7
+#define UDA134X_STATUS0 8
+#define UDA134X_STATUS1 9
+#define UDA134X_DATA000 10
+#define UDA134X_DATA001 11
+#define UDA134X_DATA010 12
+#define UDA134X_DATA011 13
+#define UDA134X_DATA1   14
+
+#define STATUS0_DAIFMT_MASK (~(7<<1))
+#define STATUS0_SYSCLK_MASK (~(3<<4))
+
+#endif
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
new file mode 100644
index 0000000..584a032
--- /dev/null
+++ b/sound/soc/codecs/uda1380.c
@@ -0,0 +1,814 @@
+/*
+ * uda1380.c - Philips UDA1380 ALSA SoC audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (c) 2007-2009 Philipp Zabel <philipp.zabel@gmail.com>
+ *
+ * Modified by Richard Purdie <richard@openedhand.com> to fit into SoC
+ * codec model.
+ *
+ * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org>
+ * Copyright 2005 Openedhand Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/uda1380.h>
+
+#include "uda1380.h"
+
+/* codec private data */
+struct uda1380_priv {
+	struct snd_soc_component *component;
+	unsigned int dac_clk;
+	struct work_struct work;
+	struct i2c_client *i2c;
+	u16 *reg_cache;
+};
+
+/*
+ * uda1380 register cache
+ */
+static const u16 uda1380_reg[UDA1380_CACHEREGNUM] = {
+	0x0502, 0x0000, 0x0000, 0x3f3f,
+	0x0202, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0xff00, 0x0000, 0x4800,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x8000, 0x0002, 0x0000,
+};
+
+static unsigned long uda1380_cache_dirty;
+
+/*
+ * read uda1380 register cache
+ */
+static inline unsigned int uda1380_read_reg_cache(struct snd_soc_component *component,
+	unsigned int reg)
+{
+	struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
+	u16 *cache = uda1380->reg_cache;
+
+	if (reg == UDA1380_RESET)
+		return 0;
+	if (reg >= UDA1380_CACHEREGNUM)
+		return -1;
+	return cache[reg];
+}
+
+/*
+ * write uda1380 register cache
+ */
+static inline void uda1380_write_reg_cache(struct snd_soc_component *component,
+	u16 reg, unsigned int value)
+{
+	struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
+	u16 *cache = uda1380->reg_cache;
+
+	if (reg >= UDA1380_CACHEREGNUM)
+		return;
+	if ((reg >= 0x10) && (cache[reg] != value))
+		set_bit(reg - 0x10, &uda1380_cache_dirty);
+	cache[reg] = value;
+}
+
+/*
+ * write to the UDA1380 register space
+ */
+static int uda1380_write(struct snd_soc_component *component, unsigned int reg,
+	unsigned int value)
+{
+	struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
+	u8 data[3];
+
+	/* data is
+	 *   data[0] is register offset
+	 *   data[1] is MS byte
+	 *   data[2] is LS byte
+	 */
+	data[0] = reg;
+	data[1] = (value & 0xff00) >> 8;
+	data[2] = value & 0x00ff;
+
+	uda1380_write_reg_cache(component, reg, value);
+
+	/* the interpolator & decimator regs must only be written when the
+	 * codec DAI is active.
+	 */
+	if (!snd_soc_component_is_active(component) && (reg >= UDA1380_MVOL))
+		return 0;
+	pr_debug("uda1380: hw write %x val %x\n", reg, value);
+	if (i2c_master_send(uda1380->i2c, data, 3) == 3) {
+		unsigned int val;
+		i2c_master_send(uda1380->i2c, data, 1);
+		i2c_master_recv(uda1380->i2c, data, 2);
+		val = (data[0]<<8) | data[1];
+		if (val != value) {
+			pr_debug("uda1380: READ BACK VAL %x\n",
+					(data[0]<<8) | data[1]);
+			return -EIO;
+		}
+		if (reg >= 0x10)
+			clear_bit(reg - 0x10, &uda1380_cache_dirty);
+		return 0;
+	} else
+		return -EIO;
+}
+
+static void uda1380_sync_cache(struct snd_soc_component *component)
+{
+	struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
+	int reg;
+	u8 data[3];
+	u16 *cache = uda1380->reg_cache;
+
+	/* Sync reg_cache with the hardware */
+	for (reg = 0; reg < UDA1380_MVOL; reg++) {
+		data[0] = reg;
+		data[1] = (cache[reg] & 0xff00) >> 8;
+		data[2] = cache[reg] & 0x00ff;
+		if (i2c_master_send(uda1380->i2c, data, 3) != 3)
+			dev_err(component->dev, "%s: write to reg 0x%x failed\n",
+				__func__, reg);
+	}
+}
+
+static int uda1380_reset(struct snd_soc_component *component)
+{
+	struct uda1380_platform_data *pdata = component->dev->platform_data;
+	struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
+
+	if (gpio_is_valid(pdata->gpio_reset)) {
+		gpio_set_value(pdata->gpio_reset, 1);
+		mdelay(1);
+		gpio_set_value(pdata->gpio_reset, 0);
+	} else {
+		u8 data[3];
+
+		data[0] = UDA1380_RESET;
+		data[1] = 0;
+		data[2] = 0;
+
+		if (i2c_master_send(uda1380->i2c, data, 3) != 3) {
+			dev_err(component->dev, "%s: failed\n", __func__);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static void uda1380_flush_work(struct work_struct *work)
+{
+	struct uda1380_priv *uda1380 = container_of(work, struct uda1380_priv, work);
+	struct snd_soc_component *uda1380_component = uda1380->component;
+	int bit, reg;
+
+	for_each_set_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) {
+		reg = 0x10 + bit;
+		pr_debug("uda1380: flush reg %x val %x:\n", reg,
+				uda1380_read_reg_cache(uda1380_component, reg));
+		uda1380_write(uda1380_component, reg,
+				uda1380_read_reg_cache(uda1380_component, reg));
+		clear_bit(bit, &uda1380_cache_dirty);
+	}
+
+}
+
+/* declarations of ALSA reg_elem_REAL controls */
+static const char *uda1380_deemp[] = {
+	"None",
+	"32kHz",
+	"44.1kHz",
+	"48kHz",
+	"96kHz",
+};
+static const char *uda1380_input_sel[] = {
+	"Line",
+	"Mic + Line R",
+	"Line L",
+	"Mic",
+};
+static const char *uda1380_output_sel[] = {
+	"DAC",
+	"Analog Mixer",
+};
+static const char *uda1380_spf_mode[] = {
+	"Flat",
+	"Minimum1",
+	"Minimum2",
+	"Maximum"
+};
+static const char *uda1380_capture_sel[] = {
+	"ADC",
+	"Digital Mixer"
+};
+static const char *uda1380_sel_ns[] = {
+	"3rd-order",
+	"5th-order"
+};
+static const char *uda1380_mix_control[] = {
+	"off",
+	"PCM only",
+	"before sound processing",
+	"after sound processing"
+};
+static const char *uda1380_sdet_setting[] = {
+	"3200",
+	"4800",
+	"9600",
+	"19200"
+};
+static const char *uda1380_os_setting[] = {
+	"single-speed",
+	"double-speed (no mixing)",
+	"quad-speed (no mixing)"
+};
+
+static const struct soc_enum uda1380_deemp_enum[] = {
+	SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, ARRAY_SIZE(uda1380_deemp),
+			uda1380_deemp),
+	SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, ARRAY_SIZE(uda1380_deemp),
+			uda1380_deemp),
+};
+static SOC_ENUM_SINGLE_DECL(uda1380_input_sel_enum,
+			    UDA1380_ADC, 2, uda1380_input_sel);		/* SEL_MIC, SEL_LNA */
+static SOC_ENUM_SINGLE_DECL(uda1380_output_sel_enum,
+			    UDA1380_PM, 7, uda1380_output_sel);		/* R02_EN_AVC */
+static SOC_ENUM_SINGLE_DECL(uda1380_spf_enum,
+			    UDA1380_MODE, 14, uda1380_spf_mode);		/* M */
+static SOC_ENUM_SINGLE_DECL(uda1380_capture_sel_enum,
+			    UDA1380_IFACE, 6, uda1380_capture_sel);	/* SEL_SOURCE */
+static SOC_ENUM_SINGLE_DECL(uda1380_sel_ns_enum,
+			    UDA1380_MIXER, 14, uda1380_sel_ns);		/* SEL_NS */
+static SOC_ENUM_SINGLE_DECL(uda1380_mix_enum,
+			    UDA1380_MIXER, 12, uda1380_mix_control);	/* MIX, MIX_POS */
+static SOC_ENUM_SINGLE_DECL(uda1380_sdet_enum,
+			    UDA1380_MIXER, 4, uda1380_sdet_setting);	/* SD_VALUE */
+static SOC_ENUM_SINGLE_DECL(uda1380_os_enum,
+			    UDA1380_MIXER, 0, uda1380_os_setting);	/* OS */
+
+/*
+ * from -48 dB in 1.5 dB steps (mute instead of -49.5 dB)
+ */
+static DECLARE_TLV_DB_SCALE(amix_tlv, -4950, 150, 1);
+
+/*
+ * from -78 dB in 1 dB steps (3 dB steps, really. LSB are ignored),
+ * from -66 dB in 0.5 dB steps (2 dB steps, really) and
+ * from -52 dB in 0.25 dB steps
+ */
+static const DECLARE_TLV_DB_RANGE(mvol_tlv,
+	0, 15, TLV_DB_SCALE_ITEM(-8200, 100, 1),
+	16, 43, TLV_DB_SCALE_ITEM(-6600, 50, 0),
+	44, 252, TLV_DB_SCALE_ITEM(-5200, 25, 0)
+);
+
+/*
+ * from -72 dB in 1.5 dB steps (6 dB steps really),
+ * from -66 dB in 0.75 dB steps (3 dB steps really),
+ * from -60 dB in 0.5 dB steps (2 dB steps really) and
+ * from -46 dB in 0.25 dB steps
+ */
+static const DECLARE_TLV_DB_RANGE(vc_tlv,
+	0, 7, TLV_DB_SCALE_ITEM(-7800, 150, 1),
+	8, 15, TLV_DB_SCALE_ITEM(-6600, 75, 0),
+	16, 43, TLV_DB_SCALE_ITEM(-6000, 50, 0),
+	44, 228, TLV_DB_SCALE_ITEM(-4600, 25, 0)
+);
+
+/* from 0 to 6 dB in 2 dB steps if SPF mode != flat */
+static DECLARE_TLV_DB_SCALE(tr_tlv, 0, 200, 0);
+
+/* from 0 to 24 dB in 2 dB steps, if SPF mode == maximum, otherwise cuts
+ * off at 18 dB max) */
+static DECLARE_TLV_DB_SCALE(bb_tlv, 0, 200, 0);
+
+/* from -63 to 24 dB in 0.5 dB steps (-128...48) */
+static DECLARE_TLV_DB_SCALE(dec_tlv, -6400, 50, 1);
+
+/* from 0 to 24 dB in 3 dB steps */
+static DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0);
+
+/* from 0 to 30 dB in 2 dB steps */
+static DECLARE_TLV_DB_SCALE(vga_tlv, 0, 200, 0);
+
+static const struct snd_kcontrol_new uda1380_snd_controls[] = {
+	SOC_DOUBLE_TLV("Analog Mixer Volume", UDA1380_AMIX, 0, 8, 44, 1, amix_tlv),	/* AVCR, AVCL */
+	SOC_DOUBLE_TLV("Master Playback Volume", UDA1380_MVOL, 0, 8, 252, 1, mvol_tlv),	/* MVCL, MVCR */
+	SOC_SINGLE_TLV("ADC Playback Volume", UDA1380_MIXVOL, 8, 228, 1, vc_tlv),	/* VC2 */
+	SOC_SINGLE_TLV("PCM Playback Volume", UDA1380_MIXVOL, 0, 228, 1, vc_tlv),	/* VC1 */
+	SOC_ENUM("Sound Processing Filter", uda1380_spf_enum),				/* M */
+	SOC_DOUBLE_TLV("Tone Control - Treble", UDA1380_MODE, 4, 12, 3, 0, tr_tlv), 	/* TRL, TRR */
+	SOC_DOUBLE_TLV("Tone Control - Bass", UDA1380_MODE, 0, 8, 15, 0, bb_tlv),	/* BBL, BBR */
+/**/	SOC_SINGLE("Master Playback Switch", UDA1380_DEEMP, 14, 1, 1),		/* MTM */
+	SOC_SINGLE("ADC Playback Switch", UDA1380_DEEMP, 11, 1, 1),		/* MT2 from decimation filter */
+	SOC_ENUM("ADC Playback De-emphasis", uda1380_deemp_enum[0]),		/* DE2 */
+	SOC_SINGLE("PCM Playback Switch", UDA1380_DEEMP, 3, 1, 1),		/* MT1, from digital data input */
+	SOC_ENUM("PCM Playback De-emphasis", uda1380_deemp_enum[1]),		/* DE1 */
+	SOC_SINGLE("DAC Polarity inverting Switch", UDA1380_MIXER, 15, 1, 0),	/* DA_POL_INV */
+	SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum),				/* SEL_NS */
+	SOC_ENUM("Digital Mixer Signal Control", uda1380_mix_enum),		/* MIX_POS, MIX */
+	SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0),		/* SDET_ON */
+	SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum),		/* SD_VALUE */
+	SOC_ENUM("Oversampling Input", uda1380_os_enum),			/* OS */
+	SOC_DOUBLE_S8_TLV("ADC Capture Volume", UDA1380_DEC, -128, 48, dec_tlv),	/* ML_DEC, MR_DEC */
+/**/	SOC_SINGLE("ADC Capture Switch", UDA1380_PGA, 15, 1, 1),		/* MT_ADC */
+	SOC_DOUBLE_TLV("Line Capture Volume", UDA1380_PGA, 0, 8, 8, 0, pga_tlv), /* PGA_GAINCTRLL, PGA_GAINCTRLR */
+	SOC_SINGLE("ADC Polarity inverting Switch", UDA1380_ADC, 12, 1, 0),	/* ADCPOL_INV */
+	SOC_SINGLE_TLV("Mic Capture Volume", UDA1380_ADC, 8, 15, 0, vga_tlv),	/* VGA_CTRL */
+	SOC_SINGLE("DC Filter Bypass Switch", UDA1380_ADC, 1, 1, 0),		/* SKIP_DCFIL (before decimator) */
+	SOC_SINGLE("DC Filter Enable Switch", UDA1380_ADC, 0, 1, 0),		/* EN_DCFIL (at output of decimator) */
+	SOC_SINGLE("AGC Timing", UDA1380_AGC, 8, 7, 0),			/* TODO: enum, see table 62 */
+	SOC_SINGLE("AGC Target level", UDA1380_AGC, 2, 3, 1),			/* AGC_LEVEL */
+	/* -5.5, -8, -11.5, -14 dBFS */
+	SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0),
+};
+
+/* Input mux */
+static const struct snd_kcontrol_new uda1380_input_mux_control =
+	SOC_DAPM_ENUM("Route", uda1380_input_sel_enum);
+
+/* Output mux */
+static const struct snd_kcontrol_new uda1380_output_mux_control =
+	SOC_DAPM_ENUM("Route", uda1380_output_sel_enum);
+
+/* Capture mux */
+static const struct snd_kcontrol_new uda1380_capture_mux_control =
+	SOC_DAPM_ENUM("Route", uda1380_capture_sel_enum);
+
+
+static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
+	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+		&uda1380_input_mux_control),
+	SND_SOC_DAPM_MUX("Output Mux", SND_SOC_NOPM, 0, 0,
+		&uda1380_output_mux_control),
+	SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0,
+		&uda1380_capture_mux_control),
+	SND_SOC_DAPM_PGA("Left PGA", UDA1380_PM, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right PGA", UDA1380_PM, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mic LNA", UDA1380_PM, 4, 0, NULL, 0),
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", UDA1380_PM, 2, 0),
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", UDA1380_PM, 0, 0),
+	SND_SOC_DAPM_INPUT("VINM"),
+	SND_SOC_DAPM_INPUT("VINL"),
+	SND_SOC_DAPM_INPUT("VINR"),
+	SND_SOC_DAPM_MIXER("Analog Mixer", UDA1380_PM, 6, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("VOUTLHP"),
+	SND_SOC_DAPM_OUTPUT("VOUTRHP"),
+	SND_SOC_DAPM_OUTPUT("VOUTL"),
+	SND_SOC_DAPM_OUTPUT("VOUTR"),
+	SND_SOC_DAPM_DAC("DAC", "Playback", UDA1380_PM, 10, 0),
+	SND_SOC_DAPM_PGA("HeadPhone Driver", UDA1380_PM, 13, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route uda1380_dapm_routes[] = {
+
+	/* output mux */
+	{"HeadPhone Driver", NULL, "Output Mux"},
+	{"VOUTR", NULL, "Output Mux"},
+	{"VOUTL", NULL, "Output Mux"},
+
+	{"Analog Mixer", NULL, "VINR"},
+	{"Analog Mixer", NULL, "VINL"},
+	{"Analog Mixer", NULL, "DAC"},
+
+	{"Output Mux", "DAC", "DAC"},
+	{"Output Mux", "Analog Mixer", "Analog Mixer"},
+
+	/* {"DAC", "Digital Mixer", "I2S" } */
+
+	/* headphone driver */
+	{"VOUTLHP", NULL, "HeadPhone Driver"},
+	{"VOUTRHP", NULL, "HeadPhone Driver"},
+
+	/* input mux */
+	{"Left ADC", NULL, "Input Mux"},
+	{"Input Mux", "Mic", "Mic LNA"},
+	{"Input Mux", "Mic + Line R", "Mic LNA"},
+	{"Input Mux", "Line L", "Left PGA"},
+	{"Input Mux", "Line", "Left PGA"},
+
+	/* right input */
+	{"Right ADC", "Mic + Line R", "Right PGA"},
+	{"Right ADC", "Line", "Right PGA"},
+
+	/* inputs */
+	{"Mic LNA", NULL, "VINM"},
+	{"Left PGA", NULL, "VINL"},
+	{"Right PGA", NULL, "VINR"},
+};
+
+static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	int iface;
+
+	/* set up DAI based upon fmt */
+	iface = uda1380_read_reg_cache(component, UDA1380_IFACE);
+	iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK);
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= R01_SFORI_I2S | R01_SFORO_I2S;
+		break;
+	case SND_SOC_DAIFMT_LSB:
+		iface |= R01_SFORI_LSB16 | R01_SFORO_LSB16;
+		break;
+	case SND_SOC_DAIFMT_MSB:
+		iface |= R01_SFORI_MSB | R01_SFORO_MSB;
+	}
+
+	/* DATAI is slave only, so in single-link mode, this has to be slave */
+	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+		return -EINVAL;
+
+	uda1380_write_reg_cache(component, UDA1380_IFACE, iface);
+
+	return 0;
+}
+
+static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	int iface;
+
+	/* set up DAI based upon fmt */
+	iface = uda1380_read_reg_cache(component, UDA1380_IFACE);
+	iface &= ~R01_SFORI_MASK;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= R01_SFORI_I2S;
+		break;
+	case SND_SOC_DAIFMT_LSB:
+		iface |= R01_SFORI_LSB16;
+		break;
+	case SND_SOC_DAIFMT_MSB:
+		iface |= R01_SFORI_MSB;
+	}
+
+	/* DATAI is slave only, so this has to be slave */
+	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+		return -EINVAL;
+
+	uda1380_write(component, UDA1380_IFACE, iface);
+
+	return 0;
+}
+
+static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	int iface;
+
+	/* set up DAI based upon fmt */
+	iface = uda1380_read_reg_cache(component, UDA1380_IFACE);
+	iface &= ~(R01_SIM | R01_SFORO_MASK);
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= R01_SFORO_I2S;
+		break;
+	case SND_SOC_DAIFMT_LSB:
+		iface |= R01_SFORO_LSB16;
+		break;
+	case SND_SOC_DAIFMT_MSB:
+		iface |= R01_SFORO_MSB;
+	}
+
+	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
+		iface |= R01_SIM;
+
+	uda1380_write(component, UDA1380_IFACE, iface);
+
+	return 0;
+}
+
+static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
+	int mixer = uda1380_read_reg_cache(component, UDA1380_MIXER);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		uda1380_write_reg_cache(component, UDA1380_MIXER,
+					mixer & ~R14_SILENCE);
+		schedule_work(&uda1380->work);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		uda1380_write_reg_cache(component, UDA1380_MIXER,
+					mixer | R14_SILENCE);
+		schedule_work(&uda1380->work);
+		break;
+	}
+	return 0;
+}
+
+static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 clk = uda1380_read_reg_cache(component, UDA1380_CLK);
+
+	/* set WSPLL power and divider if running from this clock */
+	if (clk & R00_DAC_CLK) {
+		int rate = params_rate(params);
+		u16 pm = uda1380_read_reg_cache(component, UDA1380_PM);
+		clk &= ~0x3; /* clear SEL_LOOP_DIV */
+		switch (rate) {
+		case 6250 ... 12500:
+			clk |= 0x0;
+			break;
+		case 12501 ... 25000:
+			clk |= 0x1;
+			break;
+		case 25001 ... 50000:
+			clk |= 0x2;
+			break;
+		case 50001 ... 100000:
+			clk |= 0x3;
+			break;
+		}
+		uda1380_write(component, UDA1380_PM, R02_PON_PLL | pm);
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		clk |= R00_EN_DAC | R00_EN_INT;
+	else
+		clk |= R00_EN_ADC | R00_EN_DEC;
+
+	uda1380_write(component, UDA1380_CLK, clk);
+	return 0;
+}
+
+static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 clk = uda1380_read_reg_cache(component, UDA1380_CLK);
+
+	/* shut down WSPLL power if running from this clock */
+	if (clk & R00_DAC_CLK) {
+		u16 pm = uda1380_read_reg_cache(component, UDA1380_PM);
+		uda1380_write(component, UDA1380_PM, ~R02_PON_PLL & pm);
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		clk &= ~(R00_EN_DAC | R00_EN_INT);
+	else
+		clk &= ~(R00_EN_ADC | R00_EN_DEC);
+
+	uda1380_write(component, UDA1380_CLK, clk);
+}
+
+static int uda1380_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	int pm = uda1380_read_reg_cache(component, UDA1380_PM);
+	int reg;
+	struct uda1380_platform_data *pdata = component->dev->platform_data;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		/* ADC, DAC on */
+		uda1380_write(component, UDA1380_PM, R02_PON_BIAS | pm);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			if (gpio_is_valid(pdata->gpio_power)) {
+				gpio_set_value(pdata->gpio_power, 1);
+				mdelay(1);
+				uda1380_reset(component);
+			}
+
+			uda1380_sync_cache(component);
+		}
+		uda1380_write(component, UDA1380_PM, 0x0);
+		break;
+	case SND_SOC_BIAS_OFF:
+		if (!gpio_is_valid(pdata->gpio_power))
+			break;
+
+		gpio_set_value(pdata->gpio_power, 0);
+
+		/* Mark mixer regs cache dirty to sync them with
+		 * codec regs on power on.
+		 */
+		for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++)
+			set_bit(reg - 0x10, &uda1380_cache_dirty);
+	}
+	return 0;
+}
+
+#define UDA1380_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		       SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+		       SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+static const struct snd_soc_dai_ops uda1380_dai_ops = {
+	.hw_params	= uda1380_pcm_hw_params,
+	.shutdown	= uda1380_pcm_shutdown,
+	.trigger	= uda1380_trigger,
+	.set_fmt	= uda1380_set_dai_fmt_both,
+};
+
+static const struct snd_soc_dai_ops uda1380_dai_ops_playback = {
+	.hw_params	= uda1380_pcm_hw_params,
+	.shutdown	= uda1380_pcm_shutdown,
+	.trigger	= uda1380_trigger,
+	.set_fmt	= uda1380_set_dai_fmt_playback,
+};
+
+static const struct snd_soc_dai_ops uda1380_dai_ops_capture = {
+	.hw_params	= uda1380_pcm_hw_params,
+	.shutdown	= uda1380_pcm_shutdown,
+	.trigger	= uda1380_trigger,
+	.set_fmt	= uda1380_set_dai_fmt_capture,
+};
+
+static struct snd_soc_dai_driver uda1380_dai[] = {
+{
+	.name = "uda1380-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = UDA1380_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = UDA1380_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = &uda1380_dai_ops,
+},
+{ /* playback only - dual interface */
+	.name = "uda1380-hifi-playback",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = UDA1380_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &uda1380_dai_ops_playback,
+},
+{ /* capture only - dual interface*/
+	.name = "uda1380-hifi-capture",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = UDA1380_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &uda1380_dai_ops_capture,
+},
+};
+
+static int uda1380_probe(struct snd_soc_component *component)
+{
+	struct uda1380_platform_data *pdata =component->dev->platform_data;
+	struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	uda1380->component = component;
+
+	if (!gpio_is_valid(pdata->gpio_power)) {
+		ret = uda1380_reset(component);
+		if (ret)
+			return ret;
+	}
+
+	INIT_WORK(&uda1380->work, uda1380_flush_work);
+
+	/* set clock input */
+	switch (pdata->dac_clk) {
+	case UDA1380_DAC_CLK_SYSCLK:
+		uda1380_write_reg_cache(component, UDA1380_CLK, 0);
+		break;
+	case UDA1380_DAC_CLK_WSPLL:
+		uda1380_write_reg_cache(component, UDA1380_CLK,
+			R00_DAC_CLK);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_uda1380 = {
+	.probe			= uda1380_probe,
+	.read			= uda1380_read_reg_cache,
+	.write			= uda1380_write,
+	.set_bias_level		= uda1380_set_bias_level,
+	.controls		= uda1380_snd_controls,
+	.num_controls		= ARRAY_SIZE(uda1380_snd_controls),
+	.dapm_widgets		= uda1380_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(uda1380_dapm_widgets),
+	.dapm_routes		= uda1380_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(uda1380_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int uda1380_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct uda1380_platform_data *pdata = i2c->dev.platform_data;
+	struct uda1380_priv *uda1380;
+	int ret;
+
+	if (!pdata)
+		return -EINVAL;
+
+	uda1380 = devm_kzalloc(&i2c->dev, sizeof(struct uda1380_priv),
+			       GFP_KERNEL);
+	if (uda1380 == NULL)
+		return -ENOMEM;
+
+	if (gpio_is_valid(pdata->gpio_reset)) {
+		ret = devm_gpio_request_one(&i2c->dev, pdata->gpio_reset,
+			GPIOF_OUT_INIT_LOW, "uda1380 reset");
+		if (ret)
+			return ret;
+	}
+
+	if (gpio_is_valid(pdata->gpio_power)) {
+		ret = devm_gpio_request_one(&i2c->dev, pdata->gpio_power,
+			GPIOF_OUT_INIT_LOW, "uda1380 power");
+		if (ret)
+			return ret;
+	}
+
+	uda1380->reg_cache = devm_kmemdup(&i2c->dev,
+					uda1380_reg,
+					ARRAY_SIZE(uda1380_reg) * sizeof(u16),
+					GFP_KERNEL);
+	if (!uda1380->reg_cache)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, uda1380);
+	uda1380->i2c = i2c;
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
+	return ret;
+}
+
+static const struct i2c_device_id uda1380_i2c_id[] = {
+	{ "uda1380", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id);
+
+static const struct of_device_id uda1380_of_match[] = {
+	{ .compatible = "nxp,uda1380", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, uda1380_of_match);
+
+static struct i2c_driver uda1380_i2c_driver = {
+	.driver = {
+		.name =  "uda1380-codec",
+		.of_match_table = uda1380_of_match,
+	},
+	.probe =    uda1380_i2c_probe,
+	.id_table = uda1380_i2c_id,
+};
+
+module_i2c_driver(uda1380_i2c_driver);
+
+MODULE_AUTHOR("Giorgio Padrin");
+MODULE_DESCRIPTION("Audio support for codec Philips UDA1380");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h
new file mode 100644
index 0000000..69a326a
--- /dev/null
+++ b/sound/soc/codecs/uda1380.h
@@ -0,0 +1,75 @@
+/*
+ * Audio support for Philips UDA1380
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org>
+ */
+
+#ifndef _UDA1380_H
+#define _UDA1380_H
+
+#define UDA1380_CLK	0x00
+#define UDA1380_IFACE	0x01
+#define UDA1380_PM	0x02
+#define UDA1380_AMIX	0x03
+#define UDA1380_HP	0x04
+#define UDA1380_MVOL	0x10
+#define UDA1380_MIXVOL	0x11
+#define UDA1380_MODE	0x12
+#define UDA1380_DEEMP	0x13
+#define UDA1380_MIXER	0x14
+#define UDA1380_INTSTAT	0x18
+#define UDA1380_DEC	0x20
+#define UDA1380_PGA	0x21
+#define UDA1380_ADC	0x22
+#define UDA1380_AGC	0x23
+#define UDA1380_DECSTAT	0x28
+#define UDA1380_RESET	0x7f
+
+#define UDA1380_CACHEREGNUM 0x24
+
+/* Register flags */
+#define R00_EN_ADC	0x0800
+#define R00_EN_DEC	0x0400
+#define R00_EN_DAC	0x0200
+#define R00_EN_INT	0x0100
+#define R00_DAC_CLK	0x0010
+#define R01_SFORI_I2S   0x0000
+#define R01_SFORI_LSB16 0x0100
+#define R01_SFORI_LSB18 0x0200
+#define R01_SFORI_LSB20 0x0300
+#define R01_SFORI_MSB   0x0500
+#define R01_SFORI_MASK  0x0700
+#define R01_SFORO_I2S   0x0000
+#define R01_SFORO_LSB16 0x0001
+#define R01_SFORO_LSB18 0x0002
+#define R01_SFORO_LSB20 0x0003
+#define R01_SFORO_LSB24 0x0004
+#define R01_SFORO_MSB   0x0005
+#define R01_SFORO_MASK  0x0007
+#define R01_SEL_SOURCE  0x0040
+#define R01_SIM		0x0010
+#define R02_PON_PLL	0x8000
+#define R02_PON_HP	0x2000
+#define R02_PON_DAC	0x0400
+#define R02_PON_BIAS	0x0100
+#define R02_EN_AVC	0x0080
+#define R02_PON_AVC	0x0040
+#define R02_PON_LNA	0x0010
+#define R02_PON_PGAL	0x0008
+#define R02_PON_ADCL	0x0004
+#define R02_PON_PGAR	0x0002
+#define R02_PON_ADCR	0x0001
+#define R13_MTM		0x4000
+#define R14_SILENCE	0x0080
+#define R14_SDET_ON	0x0040
+#define R21_MT_ADC	0x8000
+#define R22_SEL_LNA	0x0008
+#define R22_SEL_MIC	0x0004
+#define R22_SKIP_DCFIL	0x0002
+#define R23_AGC_EN	0x0001
+
+#endif /* _UDA1380_H */
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
new file mode 100644
index 0000000..929ef1f
--- /dev/null
+++ b/sound/soc/codecs/wl1273.c
@@ -0,0 +1,522 @@
+/*
+ * ALSA SoC WL1273 codec driver
+ *
+ * Author:      Matti Aaltonen, <matti.j.aaltonen@nokia.com>
+ *
+ * Copyright:   (C) 2010, 2011 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/mfd/wl1273-core.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include "wl1273.h"
+
+enum wl1273_mode { WL1273_MODE_BT, WL1273_MODE_FM_RX, WL1273_MODE_FM_TX };
+
+/* codec private data */
+struct wl1273_priv {
+	enum wl1273_mode mode;
+	struct wl1273_core *core;
+	unsigned int channels;
+};
+
+static int snd_wl1273_fm_set_i2s_mode(struct wl1273_core *core,
+				      int rate, int width)
+{
+	struct device *dev = &core->client->dev;
+	int r = 0;
+	u16 mode;
+
+	dev_dbg(dev, "rate: %d\n", rate);
+	dev_dbg(dev, "width: %d\n", width);
+
+	mutex_lock(&core->lock);
+
+	mode = core->i2s_mode & ~WL1273_IS2_WIDTH & ~WL1273_IS2_RATE;
+
+	switch (rate) {
+	case 48000:
+		mode |= WL1273_IS2_RATE_48K;
+		break;
+	case 44100:
+		mode |= WL1273_IS2_RATE_44_1K;
+		break;
+	case 32000:
+		mode |= WL1273_IS2_RATE_32K;
+		break;
+	case 22050:
+		mode |= WL1273_IS2_RATE_22_05K;
+		break;
+	case 16000:
+		mode |= WL1273_IS2_RATE_16K;
+		break;
+	case 12000:
+		mode |= WL1273_IS2_RATE_12K;
+		break;
+	case 11025:
+		mode |= WL1273_IS2_RATE_11_025;
+		break;
+	case 8000:
+		mode |= WL1273_IS2_RATE_8K;
+		break;
+	default:
+		dev_err(dev, "Sampling rate: %d not supported\n", rate);
+		r = -EINVAL;
+		goto out;
+	}
+
+	switch (width) {
+	case 16:
+		mode |= WL1273_IS2_WIDTH_32;
+		break;
+	case 20:
+		mode |= WL1273_IS2_WIDTH_40;
+		break;
+	case 24:
+		mode |= WL1273_IS2_WIDTH_48;
+		break;
+	case 25:
+		mode |= WL1273_IS2_WIDTH_50;
+		break;
+	case 30:
+		mode |= WL1273_IS2_WIDTH_60;
+		break;
+	case 32:
+		mode |= WL1273_IS2_WIDTH_64;
+		break;
+	case 40:
+		mode |= WL1273_IS2_WIDTH_80;
+		break;
+	case 48:
+		mode |= WL1273_IS2_WIDTH_96;
+		break;
+	case 64:
+		mode |= WL1273_IS2_WIDTH_128;
+		break;
+	default:
+		dev_err(dev, "Data width: %d not supported\n", width);
+		r = -EINVAL;
+		goto out;
+	}
+
+	dev_dbg(dev, "WL1273_I2S_DEF_MODE: 0x%04x\n",  WL1273_I2S_DEF_MODE);
+	dev_dbg(dev, "core->i2s_mode: 0x%04x\n", core->i2s_mode);
+	dev_dbg(dev, "mode: 0x%04x\n", mode);
+
+	if (core->i2s_mode != mode) {
+		r = core->write(core, WL1273_I2S_MODE_CONFIG_SET, mode);
+		if (r)
+			goto out;
+
+		core->i2s_mode = mode;
+		r = core->write(core, WL1273_AUDIO_ENABLE,
+				WL1273_AUDIO_ENABLE_I2S);
+		if (r)
+			goto out;
+	}
+out:
+	mutex_unlock(&core->lock);
+
+	return r;
+}
+
+static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core,
+					    int channel_number)
+{
+	struct device *dev = &core->client->dev;
+	int r = 0;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	mutex_lock(&core->lock);
+
+	if (core->channel_number == channel_number)
+		goto out;
+
+	if (channel_number == 1 && core->mode == WL1273_MODE_RX)
+		r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_MONO);
+	else if (channel_number == 1 && core->mode == WL1273_MODE_TX)
+		r = core->write(core, WL1273_MONO_SET, WL1273_TX_MONO);
+	else if (channel_number == 2 && core->mode == WL1273_MODE_RX)
+		r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_STEREO);
+	else if (channel_number == 2 && core->mode == WL1273_MODE_TX)
+		r = core->write(core, WL1273_MONO_SET, WL1273_TX_STEREO);
+	else
+		r = -EINVAL;
+out:
+	mutex_unlock(&core->lock);
+
+	return r;
+}
+
+static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.enumerated.item[0] = wl1273->mode;
+
+	return 0;
+}
+
+/*
+ * TODO: Implement the audio routing in the driver. Now this control
+ * only indicates the setting that has been done elsewhere (in the user
+ * space).
+ */
+static const char * const wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" };
+
+static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
+
+	if (wl1273->mode == ucontrol->value.enumerated.item[0])
+		return 0;
+
+	/* Do not allow changes while stream is running */
+	if (snd_soc_component_is_active(component))
+		return -EPERM;
+
+	if (ucontrol->value.enumerated.item[0] >=  ARRAY_SIZE(wl1273_audio_route))
+		return -EINVAL;
+
+	wl1273->mode = ucontrol->value.enumerated.item[0];
+
+	return 1;
+}
+
+static SOC_ENUM_SINGLE_EXT_DECL(wl1273_enum, wl1273_audio_route);
+
+static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "%s: enter.\n", __func__);
+
+	ucontrol->value.enumerated.item[0] = wl1273->core->audio_mode;
+
+	return 0;
+}
+
+static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
+	int val, r = 0;
+
+	dev_dbg(component->dev, "%s: enter.\n", __func__);
+
+	val = ucontrol->value.enumerated.item[0];
+	if (wl1273->core->audio_mode == val)
+		return 0;
+
+	r = wl1273->core->set_audio(wl1273->core, val);
+	if (r < 0)
+		return r;
+
+	return 1;
+}
+
+static const char * const wl1273_audio_strings[] = { "Digital", "Analog" };
+
+static SOC_ENUM_SINGLE_EXT_DECL(wl1273_audio_enum, wl1273_audio_strings);
+
+static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "%s: enter.\n", __func__);
+
+	ucontrol->value.integer.value[0] = wl1273->core->volume;
+
+	return 0;
+}
+
+static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
+	int r;
+
+	dev_dbg(component->dev, "%s: enter.\n", __func__);
+
+	r = wl1273->core->set_volume(wl1273->core,
+				     ucontrol->value.integer.value[0]);
+	if (r)
+		return r;
+
+	return 1;
+}
+
+static const struct snd_kcontrol_new wl1273_controls[] = {
+	SOC_ENUM_EXT("Codec Mode", wl1273_enum,
+		     snd_wl1273_get_audio_route, snd_wl1273_set_audio_route),
+	SOC_ENUM_EXT("Audio Switch", wl1273_audio_enum,
+		     snd_wl1273_fm_audio_get,  snd_wl1273_fm_audio_put),
+	SOC_SINGLE_EXT("Volume", 0, 0, WL1273_MAX_VOLUME, 0,
+		       snd_wl1273_fm_volume_get, snd_wl1273_fm_volume_put),
+};
+
+static const struct snd_soc_dapm_widget wl1273_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("RX"),
+
+	SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route wl1273_dapm_routes[] = {
+	{ "Capture", NULL, "RX" },
+
+	{ "TX", NULL, "Playback" },
+};
+
+static int wl1273_startup(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
+
+	switch (wl1273->mode) {
+	case WL1273_MODE_BT:
+		snd_pcm_hw_constraint_single(substream->runtime,
+					     SNDRV_PCM_HW_PARAM_RATE, 8000);
+		snd_pcm_hw_constraint_single(substream->runtime,
+					     SNDRV_PCM_HW_PARAM_CHANNELS, 1);
+		break;
+	case WL1273_MODE_FM_RX:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			pr_err("Cannot play in RX mode.\n");
+			return -EINVAL;
+		}
+		break;
+	case WL1273_MODE_FM_TX:
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			pr_err("Cannot capture in TX mode.\n");
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+		break;
+	}
+
+	return 0;
+}
+
+static int wl1273_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(dai->component);
+	struct wl1273_core *core = wl1273->core;
+	unsigned int rate, width, r;
+
+	if (params_width(params) != 16) {
+		dev_err(dai->dev, "%d bits/sample not supported\n",
+			params_width(params));
+		return -EINVAL;
+	}
+
+	rate = params_rate(params);
+	width =  hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
+
+	if (wl1273->mode == WL1273_MODE_BT) {
+		if (rate != 8000) {
+			pr_err("Rate %d not supported.\n", params_rate(params));
+			return -EINVAL;
+		}
+
+		if (params_channels(params) != 1) {
+			pr_err("Only mono supported.\n");
+			return -EINVAL;
+		}
+
+		return 0;
+	}
+
+	if (wl1273->mode == WL1273_MODE_FM_TX &&
+	    substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		pr_err("Only playback supported with TX.\n");
+		return -EINVAL;
+	}
+
+	if (wl1273->mode == WL1273_MODE_FM_RX  &&
+	    substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_err("Only capture supported with RX.\n");
+		return -EINVAL;
+	}
+
+	if (wl1273->mode != WL1273_MODE_FM_RX  &&
+	    wl1273->mode != WL1273_MODE_FM_TX) {
+		pr_err("Unexpected mode: %d.\n", wl1273->mode);
+		return -EINVAL;
+	}
+
+	r = snd_wl1273_fm_set_i2s_mode(core, rate, width);
+	if (r)
+		return r;
+
+	wl1273->channels = params_channels(params);
+	r = snd_wl1273_fm_set_channel_number(core, wl1273->channels);
+	if (r)
+		return r;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops wl1273_dai_ops = {
+	.startup	= wl1273_startup,
+	.hw_params	= wl1273_hw_params,
+};
+
+static struct snd_soc_dai_driver wl1273_dai = {
+	.name = "wl1273-fm",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE},
+	.ops = &wl1273_dai_ops,
+};
+
+/* Audio interface format for the soc_card driver */
+int wl1273_get_format(struct snd_soc_component *component, unsigned int *fmt)
+{
+	struct wl1273_priv *wl1273;
+
+	if (component == NULL || fmt == NULL)
+		return -EINVAL;
+
+	wl1273 = snd_soc_component_get_drvdata(component);
+
+	switch (wl1273->mode) {
+	case WL1273_MODE_FM_RX:
+	case WL1273_MODE_FM_TX:
+		*fmt =	SND_SOC_DAIFMT_I2S |
+			SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBM_CFM;
+
+		break;
+	case WL1273_MODE_BT:
+		*fmt =	SND_SOC_DAIFMT_DSP_A |
+			SND_SOC_DAIFMT_IB_NF |
+			SND_SOC_DAIFMT_CBM_CFM;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wl1273_get_format);
+
+static int wl1273_probe(struct snd_soc_component *component)
+{
+	struct wl1273_core **core = component->dev->platform_data;
+	struct wl1273_priv *wl1273;
+
+	dev_dbg(component->dev, "%s.\n", __func__);
+
+	if (!core) {
+		dev_err(component->dev, "Platform data is missing.\n");
+		return -EINVAL;
+	}
+
+	wl1273 = kzalloc(sizeof(struct wl1273_priv), GFP_KERNEL);
+	if (!wl1273)
+		return -ENOMEM;
+
+	wl1273->mode = WL1273_MODE_BT;
+	wl1273->core = *core;
+
+	snd_soc_component_set_drvdata(component, wl1273);
+
+	return 0;
+}
+
+static void wl1273_remove(struct snd_soc_component *component)
+{
+	struct wl1273_priv *wl1273 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "%s\n", __func__);
+	kfree(wl1273);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wl1273 = {
+	.probe			= wl1273_probe,
+	.remove			= wl1273_remove,
+	.controls		= wl1273_controls,
+	.num_controls		= ARRAY_SIZE(wl1273_controls),
+	.dapm_widgets		= wl1273_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wl1273_dapm_widgets),
+	.dapm_routes		= wl1273_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wl1273_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wl1273_platform_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+				      &soc_component_dev_wl1273,
+				      &wl1273_dai, 1);
+}
+
+static int wl1273_platform_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+MODULE_ALIAS("platform:wl1273-codec");
+
+static struct platform_driver wl1273_platform_driver = {
+	.driver		= {
+		.name	= "wl1273-codec",
+	},
+	.probe		= wl1273_platform_probe,
+	.remove		= wl1273_platform_remove,
+};
+
+module_platform_driver(wl1273_platform_driver);
+
+MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
+MODULE_DESCRIPTION("ASoC WL1273 codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wl1273.h b/sound/soc/codecs/wl1273.h
new file mode 100644
index 0000000..43a81d5
--- /dev/null
+++ b/sound/soc/codecs/wl1273.h
@@ -0,0 +1,30 @@
+/*
+ * sound/soc/codec/wl1273.h
+ *
+ * ALSA SoC WL1273 codec driver
+ *
+ * Copyright (C) Nokia Corporation
+ * Author: Matti Aaltonen <matti.j.aaltonen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1273_CODEC_H__
+#define __WL1273_CODEC_H__
+
+int wl1273_get_format(struct snd_soc_component *component, unsigned int *fmt);
+
+#endif	/* End of __WL1273_CODEC_H__ */
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
new file mode 100644
index 0000000..abd2def
--- /dev/null
+++ b/sound/soc/codecs/wm0010.c
@@ -0,0 +1,1005 @@
+/*
+ * wm0010.c  --  WM0010 DSP Driver
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ *
+ * Authors: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *          Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *          Scott Ling <sl@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#include <sound/soc.h>
+#include <sound/wm0010.h>
+
+#define DEVICE_ID_WM0010	10
+
+/* We only support v1 of the .dfw INFO record */
+#define INFO_VERSION		1
+
+enum dfw_cmd {
+	DFW_CMD_FUSE = 0x01,
+	DFW_CMD_CODE_HDR,
+	DFW_CMD_CODE_DATA,
+	DFW_CMD_PLL,
+	DFW_CMD_INFO = 0xff
+};
+
+struct dfw_binrec {
+	u8 command;
+	u32 length:24;
+	u32 address;
+	uint8_t data[0];
+} __packed;
+
+struct dfw_inforec {
+	u8 info_version;
+	u8 tool_major_version;
+	u8 tool_minor_version;
+	u8 dsp_target;
+};
+
+struct dfw_pllrec {
+	u8 command;
+	u32 length:24;
+	u32 address;
+	u32 clkctrl1;
+	u32 clkctrl2;
+	u32 clkctrl3;
+	u32 ldetctrl;
+	u32 uart_div;
+	u32 spi_div;
+} __packed;
+
+static struct pll_clock_map {
+	int max_sysclk;
+	int max_pll_spi_speed;
+	u32 pll_clkctrl1;
+} pll_clock_map[] = {			   /* Dividers */
+	{ 22000000, 26000000, 0x00201f11 }, /* 2,32,2  */
+	{ 18000000, 26000000, 0x00203f21 }, /* 2,64,4  */
+	{ 14000000, 26000000, 0x00202620 }, /* 1,39,4  */
+	{ 10000000, 22000000, 0x00203120 }, /* 1,50,4  */
+	{  6500000, 22000000, 0x00204520 }, /* 1,70,4  */
+	{  5500000, 22000000, 0x00103f10 }, /* 1,64,2  */
+};
+
+enum wm0010_state {
+	WM0010_POWER_OFF,
+	WM0010_OUT_OF_RESET,
+	WM0010_BOOTROM,
+	WM0010_STAGE2,
+	WM0010_FIRMWARE,
+};
+
+struct wm0010_priv {
+	struct snd_soc_component *component;
+
+	struct mutex lock;
+	struct device *dev;
+
+	struct wm0010_pdata pdata;
+
+	int gpio_reset;
+	int gpio_reset_value;
+
+	struct regulator_bulk_data core_supplies[2];
+	struct regulator *dbvdd;
+
+	int sysclk;
+
+	enum wm0010_state state;
+	bool boot_failed;
+	bool ready;
+	bool pll_running;
+	int max_spi_freq;
+	int board_max_spi_speed;
+	u32 pll_clkctrl1;
+
+	spinlock_t irq_lock;
+	int irq;
+
+	struct completion boot_completion;
+};
+
+struct wm0010_spi_msg {
+	struct spi_message m;
+	struct spi_transfer t;
+	u8 *tx_buf;
+	u8 *rx_buf;
+	size_t len;
+};
+
+static const struct snd_soc_dapm_widget wm0010_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("CLKIN",  SND_SOC_NOPM, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route wm0010_dapm_routes[] = {
+	{ "SDI2 Capture", NULL, "SDI1 Playback" },
+	{ "SDI1 Capture", NULL, "SDI2 Playback" },
+
+	{ "SDI1 Capture", NULL, "CLKIN" },
+	{ "SDI2 Capture", NULL, "CLKIN" },
+	{ "SDI1 Playback", NULL, "CLKIN" },
+	{ "SDI2 Playback", NULL, "CLKIN" },
+};
+
+static const char *wm0010_state_to_str(enum wm0010_state state)
+{
+	static const char * const state_to_str[] = {
+		"Power off",
+		"Out of reset",
+		"Boot ROM",
+		"Stage2",
+		"Firmware"
+	};
+
+	if (state < 0 || state >= ARRAY_SIZE(state_to_str))
+		return "null";
+	return state_to_str[state];
+}
+
+/* Called with wm0010->lock held */
+static void wm0010_halt(struct snd_soc_component *component)
+{
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
+	unsigned long flags;
+	enum wm0010_state state;
+
+	/* Fetch the wm0010 state */
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	state = wm0010->state;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	switch (state) {
+	case WM0010_POWER_OFF:
+		/* If there's nothing to do, bail out */
+		return;
+	case WM0010_OUT_OF_RESET:
+	case WM0010_BOOTROM:
+	case WM0010_STAGE2:
+	case WM0010_FIRMWARE:
+		/* Remember to put chip back into reset */
+		gpio_set_value_cansleep(wm0010->gpio_reset,
+					wm0010->gpio_reset_value);
+		/* Disable the regulators */
+		regulator_disable(wm0010->dbvdd);
+		regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies),
+				       wm0010->core_supplies);
+		break;
+	}
+
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	wm0010->state = WM0010_POWER_OFF;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+}
+
+struct wm0010_boot_xfer {
+	struct list_head list;
+	struct snd_soc_component *component;
+	struct completion *done;
+	struct spi_message m;
+	struct spi_transfer t;
+};
+
+/* Called with wm0010->lock held */
+static void wm0010_mark_boot_failure(struct wm0010_priv *wm0010)
+{
+	enum wm0010_state state;
+	unsigned long flags;
+
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	state = wm0010->state;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	dev_err(wm0010->dev, "Failed to transition from `%s' state to `%s' state\n",
+		wm0010_state_to_str(state), wm0010_state_to_str(state + 1));
+
+	wm0010->boot_failed = true;
+}
+
+static void wm0010_boot_xfer_complete(void *data)
+{
+	struct wm0010_boot_xfer *xfer = data;
+	struct snd_soc_component *component = xfer->component;
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
+	u32 *out32 = xfer->t.rx_buf;
+	int i;
+
+	if (xfer->m.status != 0) {
+		dev_err(component->dev, "SPI transfer failed: %d\n",
+			xfer->m.status);
+		wm0010_mark_boot_failure(wm0010);
+		if (xfer->done)
+			complete(xfer->done);
+		return;
+	}
+
+	for (i = 0; i < xfer->t.len / 4; i++) {
+		dev_dbg(component->dev, "%d: %04x\n", i, out32[i]);
+
+		switch (be32_to_cpu(out32[i])) {
+		case 0xe0e0e0e0:
+			dev_err(component->dev,
+				"%d: ROM error reported in stage 2\n", i);
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x55555555:
+			if (wm0010->state < WM0010_STAGE2)
+				break;
+			dev_err(component->dev,
+				"%d: ROM bootloader running in stage 2\n", i);
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed0000:
+			dev_dbg(component->dev, "Stage2 loader running\n");
+			break;
+
+		case 0x0fed0007:
+			dev_dbg(component->dev, "CODE_HDR packet received\n");
+			break;
+
+		case 0x0fed0008:
+			dev_dbg(component->dev, "CODE_DATA packet received\n");
+			break;
+
+		case 0x0fed0009:
+			dev_dbg(component->dev, "Download complete\n");
+			break;
+
+		case 0x0fed000c:
+			dev_dbg(component->dev, "Application start\n");
+			break;
+
+		case 0x0fed000e:
+			dev_dbg(component->dev, "PLL packet received\n");
+			wm0010->pll_running = true;
+			break;
+
+		case 0x0fed0025:
+			dev_err(component->dev, "Device reports image too long\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed002c:
+			dev_err(component->dev, "Device reports bad SPI packet\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed0031:
+			dev_err(component->dev, "Device reports SPI read overflow\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed0032:
+			dev_err(component->dev, "Device reports SPI underclock\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed0033:
+			dev_err(component->dev, "Device reports bad header packet\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed0034:
+			dev_err(component->dev, "Device reports invalid packet type\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed0035:
+			dev_err(component->dev, "Device reports data before header error\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		case 0x0fed0038:
+			dev_err(component->dev, "Device reports invalid PLL packet\n");
+			break;
+
+		case 0x0fed003a:
+			dev_err(component->dev, "Device reports packet alignment error\n");
+			wm0010_mark_boot_failure(wm0010);
+			break;
+
+		default:
+			dev_err(component->dev, "Unrecognised return 0x%x\n",
+			    be32_to_cpu(out32[i]));
+			wm0010_mark_boot_failure(wm0010);
+			break;
+		}
+
+		if (wm0010->boot_failed)
+			break;
+	}
+
+	if (xfer->done)
+		complete(xfer->done);
+}
+
+static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len)
+{
+	int i;
+
+	for (i = 0; i < len / 8; i++)
+		data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i]));
+}
+
+static int wm0010_firmware_load(const char *name, struct snd_soc_component *component)
+{
+	struct spi_device *spi = to_spi_device(component->dev);
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
+	struct list_head xfer_list;
+	struct wm0010_boot_xfer *xfer;
+	int ret;
+	struct completion done;
+	const struct firmware *fw;
+	const struct dfw_binrec *rec;
+	const struct dfw_inforec *inforec;
+	u64 *img;
+	u8 *out, dsp;
+	u32 len, offset;
+
+	INIT_LIST_HEAD(&xfer_list);
+
+	ret = request_firmware(&fw, name, component->dev);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to request application(%s): %d\n",
+			name, ret);
+		return ret;
+	}
+
+	rec = (const struct dfw_binrec *)fw->data;
+	inforec = (const struct dfw_inforec *)rec->data;
+	offset = 0;
+	dsp = inforec->dsp_target;
+	wm0010->boot_failed = false;
+	if (WARN_ON(!list_empty(&xfer_list)))
+		return -EINVAL;
+	init_completion(&done);
+
+	/* First record should be INFO */
+	if (rec->command != DFW_CMD_INFO) {
+		dev_err(component->dev, "First record not INFO\r\n");
+		ret = -EINVAL;
+		goto abort;
+	}
+
+	if (inforec->info_version != INFO_VERSION) {
+		dev_err(component->dev,
+			"Unsupported version (%02d) of INFO record\r\n",
+			inforec->info_version);
+		ret = -EINVAL;
+		goto abort;
+	}
+
+	dev_dbg(component->dev, "Version v%02d INFO record found\r\n",
+		inforec->info_version);
+
+	/* Check it's a DSP file */
+	if (dsp != DEVICE_ID_WM0010) {
+		dev_err(component->dev, "Not a WM0010 firmware file.\r\n");
+		ret = -EINVAL;
+		goto abort;
+	}
+
+	/* Skip the info record as we don't need to send it */
+	offset += ((rec->length) + 8);
+	rec = (void *)&rec->data[rec->length];
+
+	while (offset < fw->size) {
+		dev_dbg(component->dev,
+			"Packet: command %d, data length = 0x%x\r\n",
+			rec->command, rec->length);
+		len = rec->length + 8;
+
+		xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
+		if (!xfer) {
+			ret = -ENOMEM;
+			goto abort;
+		}
+
+		xfer->component = component;
+		list_add_tail(&xfer->list, &xfer_list);
+
+		out = kzalloc(len, GFP_KERNEL | GFP_DMA);
+		if (!out) {
+			ret = -ENOMEM;
+			goto abort1;
+		}
+		xfer->t.rx_buf = out;
+
+		img = kzalloc(len, GFP_KERNEL | GFP_DMA);
+		if (!img) {
+			ret = -ENOMEM;
+			goto abort1;
+		}
+		xfer->t.tx_buf = img;
+
+		byte_swap_64((u64 *)&rec->command, img, len);
+
+		spi_message_init(&xfer->m);
+		xfer->m.complete = wm0010_boot_xfer_complete;
+		xfer->m.context = xfer;
+		xfer->t.len = len;
+		xfer->t.bits_per_word = 8;
+
+		if (!wm0010->pll_running) {
+			xfer->t.speed_hz = wm0010->sysclk / 6;
+		} else {
+			xfer->t.speed_hz = wm0010->max_spi_freq;
+
+			if (wm0010->board_max_spi_speed &&
+			   (wm0010->board_max_spi_speed < wm0010->max_spi_freq))
+					xfer->t.speed_hz = wm0010->board_max_spi_speed;
+		}
+
+		/* Store max usable spi frequency for later use */
+		wm0010->max_spi_freq = xfer->t.speed_hz;
+
+		spi_message_add_tail(&xfer->t, &xfer->m);
+
+		offset += ((rec->length) + 8);
+		rec = (void *)&rec->data[rec->length];
+
+		if (offset >= fw->size) {
+			dev_dbg(component->dev, "All transfers scheduled\n");
+			xfer->done = &done;
+		}
+
+		ret = spi_async(spi, &xfer->m);
+		if (ret != 0) {
+			dev_err(component->dev, "Write failed: %d\n", ret);
+			goto abort1;
+		}
+
+		if (wm0010->boot_failed) {
+			dev_dbg(component->dev, "Boot fail!\n");
+			ret = -EINVAL;
+			goto abort1;
+		}
+	}
+
+	wait_for_completion(&done);
+
+	ret = 0;
+
+abort1:
+	while (!list_empty(&xfer_list)) {
+		xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer,
+					list);
+		kfree(xfer->t.rx_buf);
+		kfree(xfer->t.tx_buf);
+		list_del(&xfer->list);
+		kfree(xfer);
+	}
+
+abort:
+	release_firmware(fw);
+	return ret;
+}
+
+static int wm0010_stage2_load(struct snd_soc_component *component)
+{
+	struct spi_device *spi = to_spi_device(component->dev);
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
+	const struct firmware *fw;
+	struct spi_message m;
+	struct spi_transfer t;
+	u32 *img;
+	u8 *out;
+	int i;
+	int ret = 0;
+
+	ret = request_firmware(&fw, "wm0010_stage2.bin", component->dev);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to request stage2 loader: %d\n",
+			ret);
+		return ret;
+	}
+
+	dev_dbg(component->dev, "Downloading %zu byte stage 2 loader\n", fw->size);
+
+	/* Copy to local buffer first as vmalloc causes problems for dma */
+	img = kzalloc(fw->size, GFP_KERNEL | GFP_DMA);
+	if (!img) {
+		ret = -ENOMEM;
+		goto abort2;
+	}
+
+	out = kzalloc(fw->size, GFP_KERNEL | GFP_DMA);
+	if (!out) {
+		ret = -ENOMEM;
+		goto abort1;
+	}
+
+	memcpy(img, &fw->data[0], fw->size);
+
+	spi_message_init(&m);
+	memset(&t, 0, sizeof(t));
+	t.rx_buf = out;
+	t.tx_buf = img;
+	t.len = fw->size;
+	t.bits_per_word = 8;
+	t.speed_hz = wm0010->sysclk / 10;
+	spi_message_add_tail(&t, &m);
+
+	dev_dbg(component->dev, "Starting initial download at %dHz\n",
+		t.speed_hz);
+
+	ret = spi_sync(spi, &m);
+	if (ret != 0) {
+		dev_err(component->dev, "Initial download failed: %d\n", ret);
+		goto abort;
+	}
+
+	/* Look for errors from the boot ROM */
+	for (i = 0; i < fw->size; i++) {
+		if (out[i] != 0x55) {
+			dev_err(component->dev, "Boot ROM error: %x in %d\n",
+				out[i], i);
+			wm0010_mark_boot_failure(wm0010);
+			ret = -EBUSY;
+			goto abort;
+		}
+	}
+abort:
+	kfree(out);
+abort1:
+	kfree(img);
+abort2:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int wm0010_boot(struct snd_soc_component *component)
+{
+	struct spi_device *spi = to_spi_device(component->dev);
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
+	unsigned long flags;
+	int ret;
+	struct spi_message m;
+	struct spi_transfer t;
+	struct dfw_pllrec pll_rec;
+	u32 *p, len;
+	u64 *img_swap;
+	u8 *out;
+	int i;
+
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	if (wm0010->state != WM0010_POWER_OFF)
+		dev_warn(wm0010->dev, "DSP already powered up!\n");
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	if (wm0010->sysclk > 26000000) {
+		dev_err(component->dev, "Max DSP clock frequency is 26MHz\n");
+		ret = -ECANCELED;
+		goto err;
+	}
+
+	mutex_lock(&wm0010->lock);
+	wm0010->pll_running = false;
+
+	dev_dbg(component->dev, "max_spi_freq: %d\n", wm0010->max_spi_freq);
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm0010->core_supplies),
+				    wm0010->core_supplies);
+	if (ret != 0) {
+		dev_err(&spi->dev, "Failed to enable core supplies: %d\n",
+			ret);
+		mutex_unlock(&wm0010->lock);
+		goto err;
+	}
+
+	ret = regulator_enable(wm0010->dbvdd);
+	if (ret != 0) {
+		dev_err(&spi->dev, "Failed to enable DBVDD: %d\n", ret);
+		goto err_core;
+	}
+
+	/* Release reset */
+	gpio_set_value_cansleep(wm0010->gpio_reset, !wm0010->gpio_reset_value);
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	wm0010->state = WM0010_OUT_OF_RESET;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	if (!wait_for_completion_timeout(&wm0010->boot_completion,
+					 msecs_to_jiffies(20)))
+		dev_err(component->dev, "Failed to get interrupt from DSP\n");
+
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	wm0010->state = WM0010_BOOTROM;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	ret = wm0010_stage2_load(component);
+	if (ret)
+		goto abort;
+
+	if (!wait_for_completion_timeout(&wm0010->boot_completion,
+					 msecs_to_jiffies(20)))
+		dev_err(component->dev, "Failed to get interrupt from DSP loader.\n");
+
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	wm0010->state = WM0010_STAGE2;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	/* Only initialise PLL if max_spi_freq initialised */
+	if (wm0010->max_spi_freq) {
+
+		/* Initialise a PLL record */
+		memset(&pll_rec, 0, sizeof(pll_rec));
+		pll_rec.command = DFW_CMD_PLL;
+		pll_rec.length = (sizeof(pll_rec) - 8);
+
+		/* On wm0010 only the CLKCTRL1 value is used */
+		pll_rec.clkctrl1 = wm0010->pll_clkctrl1;
+
+		ret = -ENOMEM;
+		len = pll_rec.length + 8;
+		out = kzalloc(len, GFP_KERNEL | GFP_DMA);
+		if (!out)
+			goto abort;
+
+		img_swap = kzalloc(len, GFP_KERNEL | GFP_DMA);
+		if (!img_swap)
+			goto abort_out;
+
+		/* We need to re-order for 0010 */
+		byte_swap_64((u64 *)&pll_rec, img_swap, len);
+
+		spi_message_init(&m);
+		memset(&t, 0, sizeof(t));
+		t.rx_buf = out;
+		t.tx_buf = img_swap;
+		t.len = len;
+		t.bits_per_word = 8;
+		t.speed_hz = wm0010->sysclk / 6;
+		spi_message_add_tail(&t, &m);
+
+		ret = spi_sync(spi, &m);
+		if (ret) {
+			dev_err(component->dev, "First PLL write failed: %d\n", ret);
+			goto abort_swap;
+		}
+
+		/* Use a second send of the message to get the return status */
+		ret = spi_sync(spi, &m);
+		if (ret) {
+			dev_err(component->dev, "Second PLL write failed: %d\n", ret);
+			goto abort_swap;
+		}
+
+		p = (u32 *)out;
+
+		/* Look for PLL active code from the DSP */
+		for (i = 0; i < len / 4; i++) {
+			if (*p == 0x0e00ed0f) {
+				dev_dbg(component->dev, "PLL packet received\n");
+				wm0010->pll_running = true;
+				break;
+			}
+			p++;
+		}
+
+		kfree(img_swap);
+		kfree(out);
+	} else
+		dev_dbg(component->dev, "Not enabling DSP PLL.");
+
+	ret = wm0010_firmware_load("wm0010.dfw", component);
+
+	if (ret != 0)
+		goto abort;
+
+	spin_lock_irqsave(&wm0010->irq_lock, flags);
+	wm0010->state = WM0010_FIRMWARE;
+	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+	mutex_unlock(&wm0010->lock);
+
+	return 0;
+
+abort_swap:
+	kfree(img_swap);
+abort_out:
+	kfree(out);
+abort:
+	/* Put the chip back into reset */
+	wm0010_halt(component);
+	mutex_unlock(&wm0010->lock);
+	return ret;
+
+err_core:
+	mutex_unlock(&wm0010->lock);
+	regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies),
+			       wm0010->core_supplies);
+err:
+	return ret;
+}
+
+static int wm0010_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE)
+			wm0010_boot(component);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE) {
+			mutex_lock(&wm0010->lock);
+			wm0010_halt(component);
+			mutex_unlock(&wm0010->lock);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		break;
+	}
+
+	return 0;
+}
+
+static int wm0010_set_sysclk(struct snd_soc_component *component, int source,
+			     int clk_id, unsigned int freq, int dir)
+{
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
+	unsigned int i;
+
+	wm0010->sysclk = freq;
+
+	if (freq < pll_clock_map[ARRAY_SIZE(pll_clock_map)-1].max_sysclk) {
+		wm0010->max_spi_freq = 0;
+	} else {
+		for (i = 0; i < ARRAY_SIZE(pll_clock_map); i++)
+			if (freq >= pll_clock_map[i].max_sysclk) {
+				wm0010->max_spi_freq = pll_clock_map[i].max_pll_spi_speed;
+				wm0010->pll_clkctrl1 = pll_clock_map[i].pll_clkctrl1;
+				break;
+			}
+	}
+
+	return 0;
+}
+
+static int wm0010_probe(struct snd_soc_component *component);
+
+static const struct snd_soc_component_driver soc_component_dev_wm0010 = {
+	.probe			= wm0010_probe,
+	.set_bias_level		= wm0010_set_bias_level,
+	.set_sysclk		= wm0010_set_sysclk,
+	.dapm_widgets		= wm0010_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm0010_dapm_widgets),
+	.dapm_routes		= wm0010_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm0010_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+#define WM0010_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define WM0010_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |\
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm0010_dai[] = {
+	{
+		.name = "wm0010-sdi1",
+		.playback = {
+			.stream_name = "SDI1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM0010_RATES,
+			.formats = WM0010_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "SDI1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM0010_RATES,
+			 .formats = WM0010_FORMATS,
+		 },
+	},
+	{
+		.name = "wm0010-sdi2",
+		.playback = {
+			.stream_name = "SDI2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM0010_RATES,
+			.formats = WM0010_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "SDI2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM0010_RATES,
+			 .formats = WM0010_FORMATS,
+		 },
+	},
+};
+
+static irqreturn_t wm0010_irq(int irq, void *data)
+{
+	struct wm0010_priv *wm0010 = data;
+
+	switch (wm0010->state) {
+	case WM0010_OUT_OF_RESET:
+	case WM0010_BOOTROM:
+	case WM0010_STAGE2:
+		spin_lock(&wm0010->irq_lock);
+		complete(&wm0010->boot_completion);
+		spin_unlock(&wm0010->irq_lock);
+		return IRQ_HANDLED;
+	default:
+		return IRQ_NONE;
+	}
+
+	return IRQ_NONE;
+}
+
+static int wm0010_probe(struct snd_soc_component *component)
+{
+	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
+
+	wm0010->component = component;
+
+	return 0;
+}
+
+static int wm0010_spi_probe(struct spi_device *spi)
+{
+	unsigned long gpio_flags;
+	int ret;
+	int trigger;
+	int irq;
+	struct wm0010_priv *wm0010;
+
+	wm0010 = devm_kzalloc(&spi->dev, sizeof(*wm0010),
+			      GFP_KERNEL);
+	if (!wm0010)
+		return -ENOMEM;
+
+	mutex_init(&wm0010->lock);
+	spin_lock_init(&wm0010->irq_lock);
+
+	spi_set_drvdata(spi, wm0010);
+	wm0010->dev = &spi->dev;
+
+	if (dev_get_platdata(&spi->dev))
+		memcpy(&wm0010->pdata, dev_get_platdata(&spi->dev),
+		       sizeof(wm0010->pdata));
+
+	init_completion(&wm0010->boot_completion);
+
+	wm0010->core_supplies[0].supply = "AVDD";
+	wm0010->core_supplies[1].supply = "DCVDD";
+	ret = devm_regulator_bulk_get(wm0010->dev, ARRAY_SIZE(wm0010->core_supplies),
+				      wm0010->core_supplies);
+	if (ret != 0) {
+		dev_err(wm0010->dev, "Failed to obtain core supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	wm0010->dbvdd = devm_regulator_get(wm0010->dev, "DBVDD");
+	if (IS_ERR(wm0010->dbvdd)) {
+		ret = PTR_ERR(wm0010->dbvdd);
+		dev_err(wm0010->dev, "Failed to obtain DBVDD: %d\n", ret);
+		return ret;
+	}
+
+	if (wm0010->pdata.gpio_reset) {
+		wm0010->gpio_reset = wm0010->pdata.gpio_reset;
+
+		if (wm0010->pdata.reset_active_high)
+			wm0010->gpio_reset_value = 1;
+		else
+			wm0010->gpio_reset_value = 0;
+
+		if (wm0010->gpio_reset_value)
+			gpio_flags = GPIOF_OUT_INIT_HIGH;
+		else
+			gpio_flags = GPIOF_OUT_INIT_LOW;
+
+		ret = devm_gpio_request_one(wm0010->dev, wm0010->gpio_reset,
+					    gpio_flags, "wm0010 reset");
+		if (ret < 0) {
+			dev_err(wm0010->dev,
+				"Failed to request GPIO for DSP reset: %d\n",
+				ret);
+			return ret;
+		}
+	} else {
+		dev_err(wm0010->dev, "No reset GPIO configured\n");
+		return -EINVAL;
+	}
+
+	wm0010->state = WM0010_POWER_OFF;
+
+	irq = spi->irq;
+	if (wm0010->pdata.irq_flags)
+		trigger = wm0010->pdata.irq_flags;
+	else
+		trigger = IRQF_TRIGGER_FALLING;
+	trigger |= IRQF_ONESHOT;
+
+	ret = request_threaded_irq(irq, NULL, wm0010_irq, trigger,
+				   "wm0010", wm0010);
+	if (ret) {
+		dev_err(wm0010->dev, "Failed to request IRQ %d: %d\n",
+			irq, ret);
+		return ret;
+	}
+	wm0010->irq = irq;
+
+	ret = irq_set_irq_wake(irq, 1);
+	if (ret) {
+		dev_err(wm0010->dev, "Failed to set IRQ %d as wake source: %d\n",
+			irq, ret);
+		return ret;
+	}
+
+	if (spi->max_speed_hz)
+		wm0010->board_max_spi_speed = spi->max_speed_hz;
+	else
+		wm0010->board_max_spi_speed = 0;
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+				     &soc_component_dev_wm0010, wm0010_dai,
+				     ARRAY_SIZE(wm0010_dai));
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int wm0010_spi_remove(struct spi_device *spi)
+{
+	struct wm0010_priv *wm0010 = spi_get_drvdata(spi);
+
+	gpio_set_value_cansleep(wm0010->gpio_reset,
+				wm0010->gpio_reset_value);
+
+	irq_set_irq_wake(wm0010->irq, 0);
+
+	if (wm0010->irq)
+		free_irq(wm0010->irq, wm0010);
+
+	return 0;
+}
+
+static struct spi_driver wm0010_spi_driver = {
+	.driver = {
+		.name	= "wm0010",
+	},
+	.probe		= wm0010_spi_probe,
+	.remove		= wm0010_spi_remove,
+};
+
+module_spi_driver(wm0010_spi_driver);
+
+MODULE_DESCRIPTION("ASoC WM0010 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c
new file mode 100644
index 0000000..9727eec
--- /dev/null
+++ b/sound/soc/codecs/wm1250-ev1.c
@@ -0,0 +1,264 @@
+/*
+ * Driver for the 1250-EV1 audio I/O module
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/wm1250-ev1.h>
+
+static const char *wm1250_gpio_names[WM1250_EV1_NUM_GPIOS] = {
+	"WM1250 CLK_ENA",
+	"WM1250 CLK_SEL0",
+	"WM1250 CLK_SEL1",
+	"WM1250 OSR",
+	"WM1250 MASTER",
+};
+
+struct wm1250_priv {
+	struct gpio gpios[WM1250_EV1_NUM_GPIOS];
+};
+
+static int wm1250_ev1_set_bias_level(struct snd_soc_component *component,
+				     enum snd_soc_bias_level level)
+{
+	struct wm1250_priv *wm1250 = dev_get_drvdata(component->dev);
+	int ena;
+
+	if (wm1250)
+		ena = wm1250->gpios[WM1250_EV1_GPIO_CLK_ENA].gpio;
+	else
+		ena = -1;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (ena >= 0)
+			gpio_set_value_cansleep(ena, 1);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		if (ena >= 0)
+			gpio_set_value_cansleep(ena, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget wm1250_ev1_dapm_widgets[] = {
+SND_SOC_DAPM_ADC("ADC", "wm1250-ev1 Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_DAC("DAC", "wm1250-ev1 Playback", SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_INPUT("WM1250 Input"),
+SND_SOC_DAPM_OUTPUT("WM1250 Output"),
+};
+
+static const struct snd_soc_dapm_route wm1250_ev1_dapm_routes[] = {
+	{ "ADC", NULL, "WM1250 Input" },
+	{ "WM1250 Output", NULL, "DAC" },
+};
+
+static int wm1250_ev1_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct wm1250_priv *wm1250 = snd_soc_component_get_drvdata(dai->component);
+
+	switch (params_rate(params)) {
+	case 8000:
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+			       1);
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+			       1);
+		break;
+	case 16000:
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+			       0);
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+			       1);
+		break;
+	case 32000:
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+			       1);
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+			       0);
+		break;
+	case 64000:
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+			       0);
+		gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+			       0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops wm1250_ev1_ops = {
+	.hw_params = wm1250_ev1_hw_params,
+};
+
+#define WM1250_EV1_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			  SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_64000)
+
+static struct snd_soc_dai_driver wm1250_ev1_dai = {
+	.name = "wm1250-ev1",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM1250_EV1_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM1250_EV1_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &wm1250_ev1_ops,
+};
+
+static const struct snd_soc_component_driver soc_component_dev_wm1250_ev1 = {
+	.dapm_widgets		= wm1250_ev1_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm1250_ev1_dapm_widgets),
+	.dapm_routes		= wm1250_ev1_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm1250_ev1_dapm_routes),
+	.set_bias_level		= wm1250_ev1_set_bias_level,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm1250_ev1_pdata(struct i2c_client *i2c)
+{
+	struct wm1250_ev1_pdata *pdata = dev_get_platdata(&i2c->dev);
+	struct wm1250_priv *wm1250;
+	int i, ret;
+
+	if (!pdata)
+		return 0;
+
+	wm1250 = devm_kzalloc(&i2c->dev, sizeof(*wm1250), GFP_KERNEL);
+	if (!wm1250) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm1250->gpios); i++) {
+		wm1250->gpios[i].gpio = pdata->gpios[i];
+		wm1250->gpios[i].label = wm1250_gpio_names[i];
+		wm1250->gpios[i].flags = GPIOF_OUT_INIT_LOW;
+	}
+	wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].flags = GPIOF_OUT_INIT_HIGH;
+	wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].flags = GPIOF_OUT_INIT_HIGH;
+
+	ret = gpio_request_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios));
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to get GPIOs: %d\n", ret);
+		goto err;
+	}
+
+	dev_set_drvdata(&i2c->dev, wm1250);
+
+	return ret;
+
+err:
+	return ret;
+}
+
+static void wm1250_ev1_free(struct i2c_client *i2c)
+{
+	struct wm1250_priv *wm1250 = dev_get_drvdata(&i2c->dev);
+
+	if (wm1250)
+		gpio_free_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios));
+}
+
+static int wm1250_ev1_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *i2c_id)
+{
+	int id, board, rev, ret;
+
+	dev_set_drvdata(&i2c->dev, NULL);
+
+	board = i2c_smbus_read_byte_data(i2c, 0);
+	if (board < 0) {
+		dev_err(&i2c->dev, "Failed to read ID: %d\n", board);
+		return board;
+	}
+
+	id = (board & 0xfe) >> 2;
+	rev = board & 0x3;
+
+	if (id != 1) {
+		dev_err(&i2c->dev, "Unknown board ID %d\n", id);
+		return -ENODEV;
+	}
+
+	dev_info(&i2c->dev, "revision %d\n", rev + 1);
+
+	ret = wm1250_ev1_pdata(i2c);
+	if (ret != 0)
+		return ret;
+
+	ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_wm1250_ev1,
+				     &wm1250_ev1_dai, 1);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+		wm1250_ev1_free(i2c);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int wm1250_ev1_remove(struct i2c_client *i2c)
+{
+	wm1250_ev1_free(i2c);
+
+	return 0;
+}
+
+static const struct i2c_device_id wm1250_ev1_i2c_id[] = {
+	{ "wm1250-ev1", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm1250_ev1_i2c_id);
+
+static struct i2c_driver wm1250_ev1_i2c_driver = {
+	.driver = {
+		.name = "wm1250-ev1",
+	},
+	.probe =    wm1250_ev1_probe,
+	.remove =   wm1250_ev1_remove,
+	.id_table = wm1250_ev1_i2c_id,
+};
+
+module_i2c_driver(wm1250_ev1_i2c_driver);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM1250-EV1 audio I/O module driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
new file mode 100644
index 0000000..c5ae072
--- /dev/null
+++ b/sound/soc/codecs/wm2000.c
@@ -0,0 +1,949 @@
+/*
+ * wm2000.c  --  WM2000 ALSA Soc Audio driver
+ *
+ * Copyright 2008-2011 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The download image for the WM2000 will be requested as
+ * 'wm2000_anc.bin' by default (overridable via platform data) at
+ * runtime and is expected to be in flat binary format.  This is
+ * generated by Wolfson configuration tools and includes
+ * system-specific calibration information.  If supplied as a
+ * sequence of ASCII-encoded hexidecimal bytes this can be converted
+ * into a flat binary with a command such as this on the command line:
+ *
+ * perl -e 'while (<>) { s/[\r\n]+// ; printf("%c", hex($_)); }'
+ *                 < file  > wm2000_anc.bin
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/debugfs.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <sound/wm2000.h>
+
+#include "wm2000.h"
+
+#define WM2000_NUM_SUPPLIES 3
+
+static const char *wm2000_supplies[WM2000_NUM_SUPPLIES] = {
+	"SPKVDD",
+	"DBVDD",
+	"DCVDD",
+};
+
+enum wm2000_anc_mode {
+	ANC_ACTIVE = 0,
+	ANC_BYPASS = 1,
+	ANC_STANDBY = 2,
+	ANC_OFF = 3,
+};
+
+struct wm2000_priv {
+	struct i2c_client *i2c;
+	struct regmap *regmap;
+	struct clk *mclk;
+
+	struct regulator_bulk_data supplies[WM2000_NUM_SUPPLIES];
+
+	enum wm2000_anc_mode anc_mode;
+
+	unsigned int anc_active:1;
+	unsigned int anc_eng_ena:1;
+	unsigned int spk_ena:1;
+
+	unsigned int speech_clarity:1;
+
+	int anc_download_size;
+	char *anc_download;
+
+	struct mutex lock;
+};
+
+static int wm2000_write(struct i2c_client *i2c, unsigned int reg,
+			unsigned int value)
+{
+	struct wm2000_priv *wm2000 = i2c_get_clientdata(i2c);
+	return regmap_write(wm2000->regmap, reg, value);
+}
+
+static unsigned int wm2000_read(struct i2c_client *i2c, unsigned int r)
+{
+	struct wm2000_priv *wm2000 = i2c_get_clientdata(i2c);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(wm2000->regmap, r, &val);
+	if (ret < 0)
+		return -1;
+
+	return val;
+}
+
+static void wm2000_reset(struct wm2000_priv *wm2000)
+{
+	struct i2c_client *i2c = wm2000->i2c;
+
+	wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_CLR);
+	wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR);
+	wm2000_write(i2c, WM2000_REG_ID1, 0);
+
+	wm2000->anc_mode = ANC_OFF;
+}
+
+static int wm2000_poll_bit(struct i2c_client *i2c,
+			   unsigned int reg, u8 mask)
+{
+	int timeout = 4000;
+	int val;
+
+	val = wm2000_read(i2c, reg);
+
+	while (!(val & mask) && --timeout) {
+		msleep(1);
+		val = wm2000_read(i2c, reg);
+	}
+
+	if (timeout == 0)
+		return 0;
+	else
+		return 1;
+}
+
+static int wm2000_power_up(struct i2c_client *i2c, int analogue)
+{
+	struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+	unsigned long rate;
+	int ret;
+
+	if (WARN_ON(wm2000->anc_mode != ANC_OFF))
+		return -EINVAL;
+
+	dev_dbg(&i2c->dev, "Beginning power up\n");
+
+	ret = regulator_bulk_enable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	rate = clk_get_rate(wm2000->mclk);
+	if (rate <= 13500000) {
+		dev_dbg(&i2c->dev, "Disabling MCLK divider\n");
+		wm2000_write(i2c, WM2000_REG_SYS_CTL2,
+			     WM2000_MCLK_DIV2_ENA_CLR);
+	} else {
+		dev_dbg(&i2c->dev, "Enabling MCLK divider\n");
+		wm2000_write(i2c, WM2000_REG_SYS_CTL2,
+			     WM2000_MCLK_DIV2_ENA_SET);
+	}
+
+	wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_CLR);
+	wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_ENG_SET);
+
+	/* Wait for ANC engine to become ready */
+	if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT,
+			     WM2000_ANC_ENG_IDLE)) {
+		dev_err(&i2c->dev, "ANC engine failed to reset\n");
+		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+		return -ETIMEDOUT;
+	}
+
+	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
+			     WM2000_STATUS_BOOT_COMPLETE)) {
+		dev_err(&i2c->dev, "ANC engine failed to initialise\n");
+		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+		return -ETIMEDOUT;
+	}
+
+	wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET);
+
+	/* Open code download of the data since it is the only bulk
+	 * write we do. */
+	dev_dbg(&i2c->dev, "Downloading %d bytes\n",
+		wm2000->anc_download_size - 2);
+
+	ret = i2c_master_send(i2c, wm2000->anc_download,
+			      wm2000->anc_download_size);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "i2c_transfer() failed: %d\n", ret);
+		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+		return ret;
+	}
+	if (ret != wm2000->anc_download_size) {
+		dev_err(&i2c->dev, "i2c_transfer() failed, %d != %d\n",
+			ret, wm2000->anc_download_size);
+		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+		return -EIO;
+	}
+
+	dev_dbg(&i2c->dev, "Download complete\n");
+
+	if (analogue) {
+		wm2000_write(i2c, WM2000_REG_ANA_VMID_PU_TIME, 248 / 4);
+
+		wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+			     WM2000_MODE_ANA_SEQ_INCLUDE |
+			     WM2000_MODE_MOUSE_ENABLE |
+			     WM2000_MODE_THERMAL_ENABLE);
+	} else {
+		wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+			     WM2000_MODE_MOUSE_ENABLE |
+			     WM2000_MODE_THERMAL_ENABLE);
+	}
+
+	ret = wm2000_read(i2c, WM2000_REG_SPEECH_CLARITY);
+	if (wm2000->speech_clarity)
+		ret |= WM2000_SPEECH_CLARITY;
+	else
+		ret &= ~WM2000_SPEECH_CLARITY;
+	wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, ret);
+
+	wm2000_write(i2c, WM2000_REG_SYS_START0, 0x33);
+	wm2000_write(i2c, WM2000_REG_SYS_START1, 0x02);
+
+	wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR);
+
+	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
+			     WM2000_STATUS_MOUSE_ACTIVE)) {
+		dev_err(&i2c->dev, "Timed out waiting for device\n");
+		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+		return -ETIMEDOUT;
+	}
+
+	dev_dbg(&i2c->dev, "ANC active\n");
+	if (analogue)
+		dev_dbg(&i2c->dev, "Analogue active\n");
+	wm2000->anc_mode = ANC_ACTIVE;
+
+	return 0;
+}
+
+static int wm2000_power_down(struct i2c_client *i2c, int analogue)
+{
+	struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+
+	if (analogue) {
+		wm2000_write(i2c, WM2000_REG_ANA_VMID_PD_TIME, 248 / 4);
+		wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+			     WM2000_MODE_ANA_SEQ_INCLUDE |
+			     WM2000_MODE_POWER_DOWN);
+	} else {
+		wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+			     WM2000_MODE_POWER_DOWN);
+	}
+
+	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
+			     WM2000_STATUS_POWER_DOWN_COMPLETE)) {
+		dev_err(&i2c->dev, "Timeout waiting for ANC power down\n");
+		return -ETIMEDOUT;
+	}
+
+	if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT,
+			     WM2000_ANC_ENG_IDLE)) {
+		dev_err(&i2c->dev, "Timeout waiting for ANC engine idle\n");
+		return -ETIMEDOUT;
+	}
+
+	regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+
+	dev_dbg(&i2c->dev, "powered off\n");
+	wm2000->anc_mode = ANC_OFF;
+
+	return 0;
+}
+
+static int wm2000_enter_bypass(struct i2c_client *i2c, int analogue)
+{
+	struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+
+	if (WARN_ON(wm2000->anc_mode != ANC_ACTIVE))
+		return -EINVAL;
+
+	if (analogue) {
+		wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+			     WM2000_MODE_ANA_SEQ_INCLUDE |
+			     WM2000_MODE_THERMAL_ENABLE |
+			     WM2000_MODE_BYPASS_ENTRY);
+	} else {
+		wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+			     WM2000_MODE_THERMAL_ENABLE |
+			     WM2000_MODE_BYPASS_ENTRY);
+	}
+
+	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
+			     WM2000_STATUS_ANC_DISABLED)) {
+		dev_err(&i2c->dev, "Timeout waiting for ANC disable\n");
+		return -ETIMEDOUT;
+	}
+
+	if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT,
+			     WM2000_ANC_ENG_IDLE)) {
+		dev_err(&i2c->dev, "Timeout waiting for ANC engine idle\n");
+		return -ETIMEDOUT;
+	}
+
+	wm2000_write(i2c, WM2000_REG_SYS_CTL1, WM2000_SYS_STBY);
+	wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR);
+
+	wm2000->anc_mode = ANC_BYPASS;
+	dev_dbg(&i2c->dev, "bypass enabled\n");
+
+	return 0;
+}
+
+static int wm2000_exit_bypass(struct i2c_client *i2c, int analogue)
+{
+	struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+
+	if (WARN_ON(wm2000->anc_mode != ANC_BYPASS))
+		return -EINVAL;
+	
+	wm2000_write(i2c, WM2000_REG_SYS_CTL1, 0);
+
+	if (analogue) {
+		wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+			     WM2000_MODE_ANA_SEQ_INCLUDE |
+			     WM2000_MODE_MOUSE_ENABLE |
+			     WM2000_MODE_THERMAL_ENABLE);
+	} else {
+		wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+			     WM2000_MODE_MOUSE_ENABLE |
+			     WM2000_MODE_THERMAL_ENABLE);
+	}
+
+	wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET);
+	wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR);
+
+	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
+			     WM2000_STATUS_MOUSE_ACTIVE)) {
+		dev_err(&i2c->dev, "Timed out waiting for MOUSE\n");
+		return -ETIMEDOUT;
+	}
+
+	wm2000->anc_mode = ANC_ACTIVE;
+	dev_dbg(&i2c->dev, "MOUSE active\n");
+
+	return 0;
+}
+
+static int wm2000_enter_standby(struct i2c_client *i2c, int analogue)
+{
+	struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+
+	if (WARN_ON(wm2000->anc_mode != ANC_ACTIVE))
+		return -EINVAL;
+
+	if (analogue) {
+		wm2000_write(i2c, WM2000_REG_ANA_VMID_PD_TIME, 248 / 4);
+
+		wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+			     WM2000_MODE_ANA_SEQ_INCLUDE |
+			     WM2000_MODE_THERMAL_ENABLE |
+			     WM2000_MODE_STANDBY_ENTRY);
+	} else {
+		wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+			     WM2000_MODE_THERMAL_ENABLE |
+			     WM2000_MODE_STANDBY_ENTRY);
+	}
+
+	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
+			     WM2000_STATUS_ANC_DISABLED)) {
+		dev_err(&i2c->dev,
+			"Timed out waiting for ANC disable after 1ms\n");
+		return -ETIMEDOUT;
+	}
+
+	if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT, WM2000_ANC_ENG_IDLE)) {
+		dev_err(&i2c->dev,
+			"Timed out waiting for standby\n");
+		return -ETIMEDOUT;
+	}
+
+	wm2000_write(i2c, WM2000_REG_SYS_CTL1, WM2000_SYS_STBY);
+	wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_CLR);
+
+	wm2000->anc_mode = ANC_STANDBY;
+	dev_dbg(&i2c->dev, "standby\n");
+	if (analogue)
+		dev_dbg(&i2c->dev, "Analogue disabled\n");
+
+	return 0;
+}
+
+static int wm2000_exit_standby(struct i2c_client *i2c, int analogue)
+{
+	struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
+
+	if (WARN_ON(wm2000->anc_mode != ANC_STANDBY))
+		return -EINVAL;
+
+	wm2000_write(i2c, WM2000_REG_SYS_CTL1, 0);
+
+	if (analogue) {
+		wm2000_write(i2c, WM2000_REG_ANA_VMID_PU_TIME, 248 / 4);
+
+		wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+			     WM2000_MODE_ANA_SEQ_INCLUDE |
+			     WM2000_MODE_THERMAL_ENABLE |
+			     WM2000_MODE_MOUSE_ENABLE);
+	} else {
+		wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
+			     WM2000_MODE_THERMAL_ENABLE |
+			     WM2000_MODE_MOUSE_ENABLE);
+	}
+
+	wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_RAM_SET);
+	wm2000_write(i2c, WM2000_REG_SYS_CTL2, WM2000_ANC_INT_N_CLR);
+
+	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
+			     WM2000_STATUS_MOUSE_ACTIVE)) {
+		dev_err(&i2c->dev, "Timed out waiting for MOUSE\n");
+		return -ETIMEDOUT;
+	}
+
+	wm2000->anc_mode = ANC_ACTIVE;
+	dev_dbg(&i2c->dev, "MOUSE active\n");
+	if (analogue)
+		dev_dbg(&i2c->dev, "Analogue enabled\n");
+
+	return 0;
+}
+
+typedef int (*wm2000_mode_fn)(struct i2c_client *i2c, int analogue);
+
+static struct {
+	enum wm2000_anc_mode source;
+	enum wm2000_anc_mode dest;
+	int analogue;
+	wm2000_mode_fn step[2];
+} anc_transitions[] = {
+	{
+		.source = ANC_OFF,
+		.dest = ANC_ACTIVE,
+		.analogue = 1,
+		.step = {
+			wm2000_power_up,
+		},
+	},
+	{
+		.source = ANC_OFF,
+		.dest = ANC_STANDBY,
+		.step = {
+			wm2000_power_up,
+			wm2000_enter_standby,
+		},
+	},
+	{
+		.source = ANC_OFF,
+		.dest = ANC_BYPASS,
+		.analogue = 1,
+		.step = {
+			wm2000_power_up,
+			wm2000_enter_bypass,
+		},
+	},
+	{
+		.source = ANC_ACTIVE,
+		.dest = ANC_BYPASS,
+		.analogue = 1,
+		.step = {
+			wm2000_enter_bypass,
+		},
+	},
+	{
+		.source = ANC_ACTIVE,
+		.dest = ANC_STANDBY,
+		.analogue = 1,
+		.step = {
+			wm2000_enter_standby,
+		},
+	},
+	{
+		.source = ANC_ACTIVE,
+		.dest = ANC_OFF,
+		.analogue = 1,
+		.step = {
+			wm2000_power_down,
+		},
+	},
+	{
+		.source = ANC_BYPASS,
+		.dest = ANC_ACTIVE,
+		.analogue = 1,
+		.step = {
+			wm2000_exit_bypass,
+		},
+	},
+	{
+		.source = ANC_BYPASS,
+		.dest = ANC_STANDBY,
+		.analogue = 1,
+		.step = {
+			wm2000_exit_bypass,
+			wm2000_enter_standby,
+		},
+	},
+	{
+		.source = ANC_BYPASS,
+		.dest = ANC_OFF,
+		.step = {
+			wm2000_exit_bypass,
+			wm2000_power_down,
+		},
+	},
+	{
+		.source = ANC_STANDBY,
+		.dest = ANC_ACTIVE,
+		.analogue = 1,
+		.step = {
+			wm2000_exit_standby,
+		},
+	},
+	{
+		.source = ANC_STANDBY,
+		.dest = ANC_BYPASS,
+		.analogue = 1,
+		.step = {
+			wm2000_exit_standby,
+			wm2000_enter_bypass,
+		},
+	},
+	{
+		.source = ANC_STANDBY,
+		.dest = ANC_OFF,
+		.step = {
+			wm2000_exit_standby,
+			wm2000_power_down,
+		},
+	},
+};
+
+static int wm2000_anc_transition(struct wm2000_priv *wm2000,
+				 enum wm2000_anc_mode mode)
+{
+	struct i2c_client *i2c = wm2000->i2c;
+	int i, j;
+	int ret;
+
+	if (wm2000->anc_mode == mode)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(anc_transitions); i++)
+		if (anc_transitions[i].source == wm2000->anc_mode &&
+		    anc_transitions[i].dest == mode)
+			break;
+	if (i == ARRAY_SIZE(anc_transitions)) {
+		dev_err(&i2c->dev, "No transition for %d->%d\n",
+			wm2000->anc_mode, mode);
+		return -EINVAL;
+	}
+
+	/* Maintain clock while active */
+	if (anc_transitions[i].source == ANC_OFF) {
+		ret = clk_prepare_enable(wm2000->mclk);
+		if (ret != 0) {
+			dev_err(&i2c->dev, "Failed to enable MCLK: %d\n", ret);
+			return ret;
+		}
+	}
+
+	for (j = 0; j < ARRAY_SIZE(anc_transitions[j].step); j++) {
+		if (!anc_transitions[i].step[j])
+			break;
+		ret = anc_transitions[i].step[j](i2c,
+						 anc_transitions[i].analogue);
+		if (ret != 0)
+			return ret;
+	}
+
+	if (anc_transitions[i].dest == ANC_OFF)
+		clk_disable_unprepare(wm2000->mclk);
+
+	return 0;
+}
+
+static int wm2000_anc_set_mode(struct wm2000_priv *wm2000)
+{
+	struct i2c_client *i2c = wm2000->i2c;
+	enum wm2000_anc_mode mode;
+
+	if (wm2000->anc_eng_ena && wm2000->spk_ena)
+		if (wm2000->anc_active)
+			mode = ANC_ACTIVE;
+		else
+			mode = ANC_BYPASS;
+	else
+		mode = ANC_STANDBY;
+
+	dev_dbg(&i2c->dev, "Set mode %d (enabled %d, mute %d, active %d)\n",
+		mode, wm2000->anc_eng_ena, !wm2000->spk_ena,
+		wm2000->anc_active);
+
+	return wm2000_anc_transition(wm2000, mode);
+}
+
+static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
+
+	ucontrol->value.integer.value[0] = wm2000->anc_active;
+
+	return 0;
+}
+
+static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
+	unsigned int anc_active = ucontrol->value.integer.value[0];
+	int ret;
+
+	if (anc_active > 1)
+		return -EINVAL;
+
+	mutex_lock(&wm2000->lock);
+
+	wm2000->anc_active = anc_active;
+
+	ret = wm2000_anc_set_mode(wm2000);
+
+	mutex_unlock(&wm2000->lock);
+
+	return ret;
+}
+
+static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
+
+	ucontrol->value.integer.value[0] = wm2000->spk_ena;
+
+	return 0;
+}
+
+static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
+	unsigned int val = ucontrol->value.integer.value[0];
+	int ret;
+
+	if (val > 1)
+		return -EINVAL;
+
+	mutex_lock(&wm2000->lock);
+
+	wm2000->spk_ena = val;
+
+	ret = wm2000_anc_set_mode(wm2000);
+
+	mutex_unlock(&wm2000->lock);
+
+	return ret;
+}
+
+static const struct snd_kcontrol_new wm2000_controls[] = {
+	SOC_SINGLE("ANC Volume", WM2000_REG_ANC_GAIN_CTRL, 0, 255, 0),
+	SOC_SINGLE_BOOL_EXT("WM2000 ANC Switch", 0,
+			    wm2000_anc_mode_get,
+			    wm2000_anc_mode_put),
+	SOC_SINGLE_BOOL_EXT("WM2000 Switch", 0,
+			    wm2000_speaker_get,
+			    wm2000_speaker_put),
+};
+
+static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
+	int ret;
+
+	mutex_lock(&wm2000->lock);
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		wm2000->anc_eng_ena = 1;
+
+	if (SND_SOC_DAPM_EVENT_OFF(event))
+		wm2000->anc_eng_ena = 0;
+
+	ret = wm2000_anc_set_mode(wm2000);
+
+	mutex_unlock(&wm2000->lock);
+
+	return ret;
+}
+
+static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = {
+/* Externally visible pins */
+SND_SOC_DAPM_OUTPUT("SPKN"),
+SND_SOC_DAPM_OUTPUT("SPKP"),
+
+SND_SOC_DAPM_INPUT("LINN"),
+SND_SOC_DAPM_INPUT("LINP"),
+
+SND_SOC_DAPM_PGA_E("ANC Engine", SND_SOC_NOPM, 0, 0, NULL, 0,
+		   wm2000_anc_power_event,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+};
+
+/* Target, Path, Source */
+static const struct snd_soc_dapm_route wm2000_audio_map[] = {
+	{ "SPKN", NULL, "ANC Engine" },
+	{ "SPKP", NULL, "ANC Engine" },
+	{ "ANC Engine", NULL, "LINN" },
+	{ "ANC Engine", NULL, "LINP" },
+};
+
+#ifdef CONFIG_PM
+static int wm2000_suspend(struct snd_soc_component *component)
+{
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
+
+	return wm2000_anc_transition(wm2000, ANC_OFF);
+}
+
+static int wm2000_resume(struct snd_soc_component *component)
+{
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
+
+	return wm2000_anc_set_mode(wm2000);
+}
+#else
+#define wm2000_suspend NULL
+#define wm2000_resume NULL
+#endif
+
+static bool wm2000_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM2000_REG_SYS_START:
+	case WM2000_REG_ANC_GAIN_CTRL:
+	case WM2000_REG_MSE_TH1:
+	case WM2000_REG_MSE_TH2:
+	case WM2000_REG_SPEECH_CLARITY:
+	case WM2000_REG_SYS_WATCHDOG:
+	case WM2000_REG_ANA_VMID_PD_TIME:
+	case WM2000_REG_ANA_VMID_PU_TIME:
+	case WM2000_REG_CAT_FLTR_INDX:
+	case WM2000_REG_CAT_GAIN_0:
+	case WM2000_REG_SYS_STATUS:
+	case WM2000_REG_SYS_MODE_CNTRL:
+	case WM2000_REG_SYS_START0:
+	case WM2000_REG_SYS_START1:
+	case WM2000_REG_ID1:
+	case WM2000_REG_ID2:
+	case WM2000_REG_REVISON:
+	case WM2000_REG_SYS_CTL1:
+	case WM2000_REG_SYS_CTL2:
+	case WM2000_REG_ANC_STAT:
+	case WM2000_REG_IF_CTL:
+	case WM2000_REG_ANA_MIC_CTL:
+	case WM2000_REG_SPK_CTL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config wm2000_regmap = {
+	.reg_bits = 16,
+	.val_bits = 8,
+
+	.max_register = WM2000_REG_SPK_CTL,
+	.readable_reg = wm2000_readable_reg,
+};
+
+static int wm2000_probe(struct snd_soc_component *component)
+{
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
+
+	/* This will trigger a transition to standby mode by default */
+	wm2000_anc_set_mode(wm2000);
+
+	return 0;
+}
+
+static void wm2000_remove(struct snd_soc_component *component)
+{
+	struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
+
+	wm2000_anc_transition(wm2000, ANC_OFF);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm2000 = {
+	.probe			= wm2000_probe,
+	.remove			= wm2000_remove,
+	.suspend		= wm2000_suspend,
+	.resume			= wm2000_resume,
+	.controls		= wm2000_controls,
+	.num_controls		= ARRAY_SIZE(wm2000_controls),
+	.dapm_widgets		= wm2000_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm2000_dapm_widgets),
+	.dapm_routes		= wm2000_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(wm2000_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm2000_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *i2c_id)
+{
+	struct wm2000_priv *wm2000;
+	struct wm2000_platform_data *pdata;
+	const char *filename;
+	const struct firmware *fw = NULL;
+	int ret, i;
+	int reg;
+	u16 id;
+
+	wm2000 = devm_kzalloc(&i2c->dev, sizeof(*wm2000), GFP_KERNEL);
+	if (!wm2000)
+		return -ENOMEM;
+
+	mutex_init(&wm2000->lock);
+
+	dev_set_drvdata(&i2c->dev, wm2000);
+
+	wm2000->regmap = devm_regmap_init_i2c(i2c, &wm2000_regmap);
+	if (IS_ERR(wm2000->regmap)) {
+		ret = PTR_ERR(wm2000->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		goto out;
+	}
+
+	for (i = 0; i < WM2000_NUM_SUPPLIES; i++)
+		wm2000->supplies[i].supply = wm2000_supplies[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, WM2000_NUM_SUPPLIES,
+				      wm2000->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to get supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	/* Verify that this is a WM2000 */
+	reg = wm2000_read(i2c, WM2000_REG_ID1);
+	id = reg << 8;
+	reg = wm2000_read(i2c, WM2000_REG_ID2);
+	id |= reg & 0xff;
+
+	if (id != 0x2000) {
+		dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id);
+		ret = -ENODEV;
+		goto err_supplies;
+	}
+
+	reg = wm2000_read(i2c, WM2000_REG_REVISON);
+	dev_info(&i2c->dev, "revision %c\n", reg + 'A');
+
+	wm2000->mclk = devm_clk_get(&i2c->dev, "MCLK");
+	if (IS_ERR(wm2000->mclk)) {
+		ret = PTR_ERR(wm2000->mclk);
+		dev_err(&i2c->dev, "Failed to get MCLK: %d\n", ret);
+		goto err_supplies;
+	}
+
+	filename = "wm2000_anc.bin";
+	pdata = dev_get_platdata(&i2c->dev);
+	if (pdata) {
+		wm2000->speech_clarity = !pdata->speech_enh_disable;
+
+		if (pdata->download_file)
+			filename = pdata->download_file;
+	}
+
+	ret = request_firmware(&fw, filename, &i2c->dev);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret);
+		goto err_supplies;
+	}
+
+	/* Pre-cook the concatenation of the register address onto the image */
+	wm2000->anc_download_size = fw->size + 2;
+	wm2000->anc_download = devm_kzalloc(&i2c->dev,
+					    wm2000->anc_download_size,
+					    GFP_KERNEL);
+	if (wm2000->anc_download == NULL) {
+		ret = -ENOMEM;
+		goto err_supplies;
+	}
+
+	wm2000->anc_download[0] = 0x80;
+	wm2000->anc_download[1] = 0x00;
+	memcpy(wm2000->anc_download + 2, fw->data, fw->size);
+
+	wm2000->anc_eng_ena = 1;
+	wm2000->anc_active = 1;
+	wm2000->spk_ena = 1;
+	wm2000->i2c = i2c;
+
+	wm2000_reset(wm2000);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+					&soc_component_dev_wm2000, NULL, 0);
+
+err_supplies:
+	regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+
+out:
+	release_firmware(fw);
+	return ret;
+}
+
+static const struct i2c_device_id wm2000_i2c_id[] = {
+	{ "wm2000", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm2000_i2c_id);
+
+static struct i2c_driver wm2000_i2c_driver = {
+	.driver = {
+		.name = "wm2000",
+	},
+	.probe = wm2000_i2c_probe,
+	.id_table = wm2000_i2c_id,
+};
+
+module_i2c_driver(wm2000_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM2000 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm2000.h b/sound/soc/codecs/wm2000.h
new file mode 100644
index 0000000..3870c0e
--- /dev/null
+++ b/sound/soc/codecs/wm2000.h
@@ -0,0 +1,74 @@
+/*
+ * wm2000.h  --  WM2000 Soc Audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM2000_H
+#define _WM2000_H
+
+#define WM2000_REG_SYS_START	    0x8000
+#define WM2000_REG_ANC_GAIN_CTRL    0x8fa2
+#define WM2000_REG_MSE_TH2          0x8fdf
+#define WM2000_REG_MSE_TH1          0x8fe0
+#define WM2000_REG_SPEECH_CLARITY   0x8fef
+#define WM2000_REG_SYS_WATCHDOG     0x8ff6
+#define WM2000_REG_ANA_VMID_PD_TIME 0x8ff7
+#define WM2000_REG_ANA_VMID_PU_TIME 0x8ff8
+#define WM2000_REG_CAT_FLTR_INDX    0x8ff9
+#define WM2000_REG_CAT_GAIN_0       0x8ffa
+#define WM2000_REG_SYS_STATUS       0x8ffc
+#define WM2000_REG_SYS_MODE_CNTRL   0x8ffd
+#define WM2000_REG_SYS_START0       0x8ffe
+#define WM2000_REG_SYS_START1       0x8fff
+#define WM2000_REG_ID1              0xf000
+#define WM2000_REG_ID2              0xf001
+#define WM2000_REG_REVISON          0xf002
+#define WM2000_REG_SYS_CTL1         0xf003
+#define WM2000_REG_SYS_CTL2         0xf004
+#define WM2000_REG_ANC_STAT         0xf005
+#define WM2000_REG_IF_CTL           0xf006
+#define WM2000_REG_ANA_MIC_CTL      0xf028
+#define WM2000_REG_SPK_CTL          0xf034
+
+/* SPEECH_CLARITY */
+#define WM2000_SPEECH_CLARITY   0x01
+
+/* SYS_STATUS */
+#define WM2000_STATUS_MOUSE_ACTIVE              0x40
+#define WM2000_STATUS_CAT_FREQ_COMPLETE         0x20
+#define WM2000_STATUS_CAT_GAIN_COMPLETE         0x10
+#define WM2000_STATUS_THERMAL_SHUTDOWN_COMPLETE 0x08
+#define WM2000_STATUS_ANC_DISABLED              0x04
+#define WM2000_STATUS_POWER_DOWN_COMPLETE       0x02
+#define WM2000_STATUS_BOOT_COMPLETE             0x01
+
+/* SYS_MODE_CNTRL */
+#define WM2000_MODE_ANA_SEQ_INCLUDE 0x80
+#define WM2000_MODE_MOUSE_ENABLE    0x40
+#define WM2000_MODE_CAT_FREQ_ENABLE 0x20
+#define WM2000_MODE_CAT_GAIN_ENABLE 0x10
+#define WM2000_MODE_BYPASS_ENTRY    0x08
+#define WM2000_MODE_STANDBY_ENTRY   0x04
+#define WM2000_MODE_THERMAL_ENABLE  0x02
+#define WM2000_MODE_POWER_DOWN      0x01
+
+/* SYS_CTL1 */
+#define WM2000_SYS_STBY          0x01
+
+/* SYS_CTL2 */
+#define WM2000_MCLK_DIV2_ENA_CLR 0x80
+#define WM2000_MCLK_DIV2_ENA_SET 0x40
+#define WM2000_ANC_ENG_CLR       0x20
+#define WM2000_ANC_ENG_SET       0x10
+#define WM2000_ANC_INT_N_CLR     0x08
+#define WM2000_ANC_INT_N_SET     0x04
+#define WM2000_RAM_CLR           0x02
+#define WM2000_RAM_SET           0x01
+
+/* ANC_STAT */
+#define WM2000_ANC_ENG_IDLE      0x01
+
+#endif
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
new file mode 100644
index 0000000..deff651
--- /dev/null
+++ b/sound/soc/codecs/wm2200.c
@@ -0,0 +1,2507 @@
+/*
+ * wm2200.c  --  WM2200 ALSA SoC Audio driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/firmware.h>
+#include <linux/gcd.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/fixed.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/wm2200.h>
+
+#include "wm2200.h"
+#include "wmfw.h"
+#include "wm_adsp.h"
+
+#define WM2200_DSP_CONTROL_1                   0x00
+#define WM2200_DSP_CONTROL_2                   0x02
+#define WM2200_DSP_CONTROL_3                   0x03
+#define WM2200_DSP_CONTROL_4                   0x04
+#define WM2200_DSP_CONTROL_5                   0x06
+#define WM2200_DSP_CONTROL_6                   0x07
+#define WM2200_DSP_CONTROL_7                   0x08
+#define WM2200_DSP_CONTROL_8                   0x09
+#define WM2200_DSP_CONTROL_9                   0x0A
+#define WM2200_DSP_CONTROL_10                  0x0B
+#define WM2200_DSP_CONTROL_11                  0x0C
+#define WM2200_DSP_CONTROL_12                  0x0D
+#define WM2200_DSP_CONTROL_13                  0x0F
+#define WM2200_DSP_CONTROL_14                  0x10
+#define WM2200_DSP_CONTROL_15                  0x11
+#define WM2200_DSP_CONTROL_16                  0x12
+#define WM2200_DSP_CONTROL_17                  0x13
+#define WM2200_DSP_CONTROL_18                  0x14
+#define WM2200_DSP_CONTROL_19                  0x16
+#define WM2200_DSP_CONTROL_20                  0x17
+#define WM2200_DSP_CONTROL_21                  0x18
+#define WM2200_DSP_CONTROL_22                  0x1A
+#define WM2200_DSP_CONTROL_23                  0x1B
+#define WM2200_DSP_CONTROL_24                  0x1C
+#define WM2200_DSP_CONTROL_25                  0x1E
+#define WM2200_DSP_CONTROL_26                  0x20
+#define WM2200_DSP_CONTROL_27                  0x21
+#define WM2200_DSP_CONTROL_28                  0x22
+#define WM2200_DSP_CONTROL_29                  0x23
+#define WM2200_DSP_CONTROL_30                  0x24
+#define WM2200_DSP_CONTROL_31                  0x26
+
+/* The code assumes DCVDD is generated internally */
+#define WM2200_NUM_CORE_SUPPLIES 2
+static const char *wm2200_core_supply_names[WM2200_NUM_CORE_SUPPLIES] = {
+	"DBVDD",
+	"LDOVDD",
+};
+
+struct wm2200_fll {
+	int fref;
+	int fout;
+	int src;
+	struct completion lock;
+};
+
+/* codec private data */
+struct wm2200_priv {
+	struct wm_adsp dsp[2];
+	struct regmap *regmap;
+	struct device *dev;
+	struct snd_soc_component *component;
+	struct wm2200_pdata pdata;
+	struct regulator_bulk_data core_supplies[WM2200_NUM_CORE_SUPPLIES];
+
+	struct completion fll_lock;
+	int fll_fout;
+	int fll_fref;
+	int fll_src;
+
+	int rev;
+	int sysclk;
+
+	unsigned int symmetric_rates:1;
+};
+
+#define WM2200_DSP_RANGE_BASE (WM2200_MAX_REGISTER + 1)
+#define WM2200_DSP_SPACING 12288
+
+#define WM2200_DSP1_DM_BASE (WM2200_DSP_RANGE_BASE + (0 * WM2200_DSP_SPACING))
+#define WM2200_DSP1_PM_BASE (WM2200_DSP_RANGE_BASE + (1 * WM2200_DSP_SPACING))
+#define WM2200_DSP1_ZM_BASE (WM2200_DSP_RANGE_BASE + (2 * WM2200_DSP_SPACING))
+#define WM2200_DSP2_DM_BASE (WM2200_DSP_RANGE_BASE + (3 * WM2200_DSP_SPACING))
+#define WM2200_DSP2_PM_BASE (WM2200_DSP_RANGE_BASE + (4 * WM2200_DSP_SPACING))
+#define WM2200_DSP2_ZM_BASE (WM2200_DSP_RANGE_BASE + (5 * WM2200_DSP_SPACING))
+
+static const struct regmap_range_cfg wm2200_ranges[] = {
+	{ .name = "DSP1DM", .range_min = WM2200_DSP1_DM_BASE,
+	  .range_max = WM2200_DSP1_DM_BASE + 12287,
+	  .selector_reg = WM2200_DSP1_CONTROL_3,
+	  .selector_mask = WM2200_DSP1_PAGE_BASE_DM_0_MASK,
+	  .selector_shift = WM2200_DSP1_PAGE_BASE_DM_0_SHIFT,
+	  .window_start = WM2200_DSP1_DM_0, .window_len = 2048, },
+
+	{ .name = "DSP1PM", .range_min = WM2200_DSP1_PM_BASE,
+	  .range_max = WM2200_DSP1_PM_BASE + 12287,
+	  .selector_reg = WM2200_DSP1_CONTROL_2,
+	  .selector_mask = WM2200_DSP1_PAGE_BASE_PM_0_MASK,
+	  .selector_shift = WM2200_DSP1_PAGE_BASE_PM_0_SHIFT,
+	  .window_start = WM2200_DSP1_PM_0, .window_len = 768, },
+
+	{ .name = "DSP1ZM", .range_min = WM2200_DSP1_ZM_BASE,
+	  .range_max = WM2200_DSP1_ZM_BASE + 2047,
+	  .selector_reg = WM2200_DSP1_CONTROL_4,
+	  .selector_mask = WM2200_DSP1_PAGE_BASE_ZM_0_MASK,
+	  .selector_shift = WM2200_DSP1_PAGE_BASE_ZM_0_SHIFT,
+	  .window_start = WM2200_DSP1_ZM_0, .window_len = 1024, },
+
+	{ .name = "DSP2DM", .range_min = WM2200_DSP2_DM_BASE,
+	  .range_max = WM2200_DSP2_DM_BASE + 4095,
+	  .selector_reg = WM2200_DSP2_CONTROL_3,
+	  .selector_mask = WM2200_DSP2_PAGE_BASE_DM_0_MASK,
+	  .selector_shift = WM2200_DSP2_PAGE_BASE_DM_0_SHIFT,
+	  .window_start = WM2200_DSP2_DM_0, .window_len = 2048, },
+
+	{ .name = "DSP2PM", .range_min = WM2200_DSP2_PM_BASE,
+	  .range_max = WM2200_DSP2_PM_BASE + 11287,
+	  .selector_reg = WM2200_DSP2_CONTROL_2,
+	  .selector_mask = WM2200_DSP2_PAGE_BASE_PM_0_MASK,
+	  .selector_shift = WM2200_DSP2_PAGE_BASE_PM_0_SHIFT,
+	  .window_start = WM2200_DSP2_PM_0, .window_len = 768, },
+
+	{ .name = "DSP2ZM", .range_min = WM2200_DSP2_ZM_BASE,
+	  .range_max = WM2200_DSP2_ZM_BASE + 2047,
+	  .selector_reg = WM2200_DSP2_CONTROL_4,
+	  .selector_mask = WM2200_DSP2_PAGE_BASE_ZM_0_MASK,
+	  .selector_shift = WM2200_DSP2_PAGE_BASE_ZM_0_SHIFT,
+	  .window_start = WM2200_DSP2_ZM_0, .window_len = 1024, },
+};
+
+static const struct wm_adsp_region wm2200_dsp1_regions[] = {
+	{ .type = WMFW_ADSP1_PM, .base = WM2200_DSP1_PM_BASE },
+	{ .type = WMFW_ADSP1_DM, .base = WM2200_DSP1_DM_BASE },
+	{ .type = WMFW_ADSP1_ZM, .base = WM2200_DSP1_ZM_BASE },
+};
+
+static const struct wm_adsp_region wm2200_dsp2_regions[] = {
+	{ .type = WMFW_ADSP1_PM, .base = WM2200_DSP2_PM_BASE },
+	{ .type = WMFW_ADSP1_DM, .base = WM2200_DSP2_DM_BASE },
+	{ .type = WMFW_ADSP1_ZM, .base = WM2200_DSP2_ZM_BASE },
+};
+
+static const struct reg_default wm2200_reg_defaults[] = {
+	{ 0x000B, 0x0000 },   /* R11    - Tone Generator 1 */
+	{ 0x0102, 0x0000 },   /* R258   - Clocking 3 */
+	{ 0x0103, 0x0011 },   /* R259   - Clocking 4 */
+	{ 0x0111, 0x0000 },   /* R273   - FLL Control 1 */
+	{ 0x0112, 0x0000 },   /* R274   - FLL Control 2 */
+	{ 0x0113, 0x0000 },   /* R275   - FLL Control 3 */
+	{ 0x0114, 0x0000 },   /* R276   - FLL Control 4 */
+	{ 0x0116, 0x0177 },   /* R278   - FLL Control 6 */
+	{ 0x0117, 0x0004 },   /* R279   - FLL Control 7 */
+	{ 0x0119, 0x0000 },   /* R281   - FLL EFS 1 */
+	{ 0x011A, 0x0002 },   /* R282   - FLL EFS 2 */
+	{ 0x0200, 0x0000 },   /* R512   - Mic Charge Pump 1 */
+	{ 0x0201, 0x03FF },   /* R513   - Mic Charge Pump 2 */
+	{ 0x0202, 0x9BDE },   /* R514   - DM Charge Pump 1 */
+	{ 0x020C, 0x0000 },   /* R524   - Mic Bias Ctrl 1 */
+	{ 0x020D, 0x0000 },   /* R525   - Mic Bias Ctrl 2 */
+	{ 0x020F, 0x0000 },   /* R527   - Ear Piece Ctrl 1 */
+	{ 0x0210, 0x0000 },   /* R528   - Ear Piece Ctrl 2 */
+	{ 0x0301, 0x0000 },   /* R769   - Input Enables */
+	{ 0x0302, 0x2240 },   /* R770   - IN1L Control */
+	{ 0x0303, 0x0040 },   /* R771   - IN1R Control */
+	{ 0x0304, 0x2240 },   /* R772   - IN2L Control */
+	{ 0x0305, 0x0040 },   /* R773   - IN2R Control */
+	{ 0x0306, 0x2240 },   /* R774   - IN3L Control */
+	{ 0x0307, 0x0040 },   /* R775   - IN3R Control */
+	{ 0x030A, 0x0000 },   /* R778   - RXANC_SRC */
+	{ 0x030B, 0x0022 },   /* R779   - Input Volume Ramp */
+	{ 0x030C, 0x0180 },   /* R780   - ADC Digital Volume 1L */
+	{ 0x030D, 0x0180 },   /* R781   - ADC Digital Volume 1R */
+	{ 0x030E, 0x0180 },   /* R782   - ADC Digital Volume 2L */
+	{ 0x030F, 0x0180 },   /* R783   - ADC Digital Volume 2R */
+	{ 0x0310, 0x0180 },   /* R784   - ADC Digital Volume 3L */
+	{ 0x0311, 0x0180 },   /* R785   - ADC Digital Volume 3R */
+	{ 0x0400, 0x0000 },   /* R1024  - Output Enables */
+	{ 0x0401, 0x0000 },   /* R1025  - DAC Volume Limit 1L */
+	{ 0x0402, 0x0000 },   /* R1026  - DAC Volume Limit 1R */
+	{ 0x0403, 0x0000 },   /* R1027  - DAC Volume Limit 2L */
+	{ 0x0404, 0x0000 },   /* R1028  - DAC Volume Limit 2R */
+	{ 0x0409, 0x0000 },   /* R1033  - DAC AEC Control 1 */
+	{ 0x040A, 0x0022 },   /* R1034  - Output Volume Ramp */
+	{ 0x040B, 0x0180 },   /* R1035  - DAC Digital Volume 1L */
+	{ 0x040C, 0x0180 },   /* R1036  - DAC Digital Volume 1R */
+	{ 0x040D, 0x0180 },   /* R1037  - DAC Digital Volume 2L */
+	{ 0x040E, 0x0180 },   /* R1038  - DAC Digital Volume 2R */
+	{ 0x0417, 0x0069 },   /* R1047  - PDM 1 */
+	{ 0x0418, 0x0000 },   /* R1048  - PDM 2 */
+	{ 0x0500, 0x0000 },   /* R1280  - Audio IF 1_1 */
+	{ 0x0501, 0x0008 },   /* R1281  - Audio IF 1_2 */
+	{ 0x0502, 0x0000 },   /* R1282  - Audio IF 1_3 */
+	{ 0x0503, 0x0000 },   /* R1283  - Audio IF 1_4 */
+	{ 0x0504, 0x0000 },   /* R1284  - Audio IF 1_5 */
+	{ 0x0505, 0x0001 },   /* R1285  - Audio IF 1_6 */
+	{ 0x0506, 0x0001 },   /* R1286  - Audio IF 1_7 */
+	{ 0x0507, 0x0000 },   /* R1287  - Audio IF 1_8 */
+	{ 0x0508, 0x0000 },   /* R1288  - Audio IF 1_9 */
+	{ 0x0509, 0x0000 },   /* R1289  - Audio IF 1_10 */
+	{ 0x050A, 0x0000 },   /* R1290  - Audio IF 1_11 */
+	{ 0x050B, 0x0000 },   /* R1291  - Audio IF 1_12 */
+	{ 0x050C, 0x0000 },   /* R1292  - Audio IF 1_13 */
+	{ 0x050D, 0x0000 },   /* R1293  - Audio IF 1_14 */
+	{ 0x050E, 0x0000 },   /* R1294  - Audio IF 1_15 */
+	{ 0x050F, 0x0000 },   /* R1295  - Audio IF 1_16 */
+	{ 0x0510, 0x0000 },   /* R1296  - Audio IF 1_17 */
+	{ 0x0511, 0x0000 },   /* R1297  - Audio IF 1_18 */
+	{ 0x0512, 0x0000 },   /* R1298  - Audio IF 1_19 */
+	{ 0x0513, 0x0000 },   /* R1299  - Audio IF 1_20 */
+	{ 0x0514, 0x0000 },   /* R1300  - Audio IF 1_21 */
+	{ 0x0515, 0x0001 },   /* R1301  - Audio IF 1_22 */
+	{ 0x0600, 0x0000 },   /* R1536  - OUT1LMIX Input 1 Source */
+	{ 0x0601, 0x0080 },   /* R1537  - OUT1LMIX Input 1 Volume */
+	{ 0x0602, 0x0000 },   /* R1538  - OUT1LMIX Input 2 Source */
+	{ 0x0603, 0x0080 },   /* R1539  - OUT1LMIX Input 2 Volume */
+	{ 0x0604, 0x0000 },   /* R1540  - OUT1LMIX Input 3 Source */
+	{ 0x0605, 0x0080 },   /* R1541  - OUT1LMIX Input 3 Volume */
+	{ 0x0606, 0x0000 },   /* R1542  - OUT1LMIX Input 4 Source */
+	{ 0x0607, 0x0080 },   /* R1543  - OUT1LMIX Input 4 Volume */
+	{ 0x0608, 0x0000 },   /* R1544  - OUT1RMIX Input 1 Source */
+	{ 0x0609, 0x0080 },   /* R1545  - OUT1RMIX Input 1 Volume */
+	{ 0x060A, 0x0000 },   /* R1546  - OUT1RMIX Input 2 Source */
+	{ 0x060B, 0x0080 },   /* R1547  - OUT1RMIX Input 2 Volume */
+	{ 0x060C, 0x0000 },   /* R1548  - OUT1RMIX Input 3 Source */
+	{ 0x060D, 0x0080 },   /* R1549  - OUT1RMIX Input 3 Volume */
+	{ 0x060E, 0x0000 },   /* R1550  - OUT1RMIX Input 4 Source */
+	{ 0x060F, 0x0080 },   /* R1551  - OUT1RMIX Input 4 Volume */
+	{ 0x0610, 0x0000 },   /* R1552  - OUT2LMIX Input 1 Source */
+	{ 0x0611, 0x0080 },   /* R1553  - OUT2LMIX Input 1 Volume */
+	{ 0x0612, 0x0000 },   /* R1554  - OUT2LMIX Input 2 Source */
+	{ 0x0613, 0x0080 },   /* R1555  - OUT2LMIX Input 2 Volume */
+	{ 0x0614, 0x0000 },   /* R1556  - OUT2LMIX Input 3 Source */
+	{ 0x0615, 0x0080 },   /* R1557  - OUT2LMIX Input 3 Volume */
+	{ 0x0616, 0x0000 },   /* R1558  - OUT2LMIX Input 4 Source */
+	{ 0x0617, 0x0080 },   /* R1559  - OUT2LMIX Input 4 Volume */
+	{ 0x0618, 0x0000 },   /* R1560  - OUT2RMIX Input 1 Source */
+	{ 0x0619, 0x0080 },   /* R1561  - OUT2RMIX Input 1 Volume */
+	{ 0x061A, 0x0000 },   /* R1562  - OUT2RMIX Input 2 Source */
+	{ 0x061B, 0x0080 },   /* R1563  - OUT2RMIX Input 2 Volume */
+	{ 0x061C, 0x0000 },   /* R1564  - OUT2RMIX Input 3 Source */
+	{ 0x061D, 0x0080 },   /* R1565  - OUT2RMIX Input 3 Volume */
+	{ 0x061E, 0x0000 },   /* R1566  - OUT2RMIX Input 4 Source */
+	{ 0x061F, 0x0080 },   /* R1567  - OUT2RMIX Input 4 Volume */
+	{ 0x0620, 0x0000 },   /* R1568  - AIF1TX1MIX Input 1 Source */
+	{ 0x0621, 0x0080 },   /* R1569  - AIF1TX1MIX Input 1 Volume */
+	{ 0x0622, 0x0000 },   /* R1570  - AIF1TX1MIX Input 2 Source */
+	{ 0x0623, 0x0080 },   /* R1571  - AIF1TX1MIX Input 2 Volume */
+	{ 0x0624, 0x0000 },   /* R1572  - AIF1TX1MIX Input 3 Source */
+	{ 0x0625, 0x0080 },   /* R1573  - AIF1TX1MIX Input 3 Volume */
+	{ 0x0626, 0x0000 },   /* R1574  - AIF1TX1MIX Input 4 Source */
+	{ 0x0627, 0x0080 },   /* R1575  - AIF1TX1MIX Input 4 Volume */
+	{ 0x0628, 0x0000 },   /* R1576  - AIF1TX2MIX Input 1 Source */
+	{ 0x0629, 0x0080 },   /* R1577  - AIF1TX2MIX Input 1 Volume */
+	{ 0x062A, 0x0000 },   /* R1578  - AIF1TX2MIX Input 2 Source */
+	{ 0x062B, 0x0080 },   /* R1579  - AIF1TX2MIX Input 2 Volume */
+	{ 0x062C, 0x0000 },   /* R1580  - AIF1TX2MIX Input 3 Source */
+	{ 0x062D, 0x0080 },   /* R1581  - AIF1TX2MIX Input 3 Volume */
+	{ 0x062E, 0x0000 },   /* R1582  - AIF1TX2MIX Input 4 Source */
+	{ 0x062F, 0x0080 },   /* R1583  - AIF1TX2MIX Input 4 Volume */
+	{ 0x0630, 0x0000 },   /* R1584  - AIF1TX3MIX Input 1 Source */
+	{ 0x0631, 0x0080 },   /* R1585  - AIF1TX3MIX Input 1 Volume */
+	{ 0x0632, 0x0000 },   /* R1586  - AIF1TX3MIX Input 2 Source */
+	{ 0x0633, 0x0080 },   /* R1587  - AIF1TX3MIX Input 2 Volume */
+	{ 0x0634, 0x0000 },   /* R1588  - AIF1TX3MIX Input 3 Source */
+	{ 0x0635, 0x0080 },   /* R1589  - AIF1TX3MIX Input 3 Volume */
+	{ 0x0636, 0x0000 },   /* R1590  - AIF1TX3MIX Input 4 Source */
+	{ 0x0637, 0x0080 },   /* R1591  - AIF1TX3MIX Input 4 Volume */
+	{ 0x0638, 0x0000 },   /* R1592  - AIF1TX4MIX Input 1 Source */
+	{ 0x0639, 0x0080 },   /* R1593  - AIF1TX4MIX Input 1 Volume */
+	{ 0x063A, 0x0000 },   /* R1594  - AIF1TX4MIX Input 2 Source */
+	{ 0x063B, 0x0080 },   /* R1595  - AIF1TX4MIX Input 2 Volume */
+	{ 0x063C, 0x0000 },   /* R1596  - AIF1TX4MIX Input 3 Source */
+	{ 0x063D, 0x0080 },   /* R1597  - AIF1TX4MIX Input 3 Volume */
+	{ 0x063E, 0x0000 },   /* R1598  - AIF1TX4MIX Input 4 Source */
+	{ 0x063F, 0x0080 },   /* R1599  - AIF1TX4MIX Input 4 Volume */
+	{ 0x0640, 0x0000 },   /* R1600  - AIF1TX5MIX Input 1 Source */
+	{ 0x0641, 0x0080 },   /* R1601  - AIF1TX5MIX Input 1 Volume */
+	{ 0x0642, 0x0000 },   /* R1602  - AIF1TX5MIX Input 2 Source */
+	{ 0x0643, 0x0080 },   /* R1603  - AIF1TX5MIX Input 2 Volume */
+	{ 0x0644, 0x0000 },   /* R1604  - AIF1TX5MIX Input 3 Source */
+	{ 0x0645, 0x0080 },   /* R1605  - AIF1TX5MIX Input 3 Volume */
+	{ 0x0646, 0x0000 },   /* R1606  - AIF1TX5MIX Input 4 Source */
+	{ 0x0647, 0x0080 },   /* R1607  - AIF1TX5MIX Input 4 Volume */
+	{ 0x0648, 0x0000 },   /* R1608  - AIF1TX6MIX Input 1 Source */
+	{ 0x0649, 0x0080 },   /* R1609  - AIF1TX6MIX Input 1 Volume */
+	{ 0x064A, 0x0000 },   /* R1610  - AIF1TX6MIX Input 2 Source */
+	{ 0x064B, 0x0080 },   /* R1611  - AIF1TX6MIX Input 2 Volume */
+	{ 0x064C, 0x0000 },   /* R1612  - AIF1TX6MIX Input 3 Source */
+	{ 0x064D, 0x0080 },   /* R1613  - AIF1TX6MIX Input 3 Volume */
+	{ 0x064E, 0x0000 },   /* R1614  - AIF1TX6MIX Input 4 Source */
+	{ 0x064F, 0x0080 },   /* R1615  - AIF1TX6MIX Input 4 Volume */
+	{ 0x0650, 0x0000 },   /* R1616  - EQLMIX Input 1 Source */
+	{ 0x0651, 0x0080 },   /* R1617  - EQLMIX Input 1 Volume */
+	{ 0x0652, 0x0000 },   /* R1618  - EQLMIX Input 2 Source */
+	{ 0x0653, 0x0080 },   /* R1619  - EQLMIX Input 2 Volume */
+	{ 0x0654, 0x0000 },   /* R1620  - EQLMIX Input 3 Source */
+	{ 0x0655, 0x0080 },   /* R1621  - EQLMIX Input 3 Volume */
+	{ 0x0656, 0x0000 },   /* R1622  - EQLMIX Input 4 Source */
+	{ 0x0657, 0x0080 },   /* R1623  - EQLMIX Input 4 Volume */
+	{ 0x0658, 0x0000 },   /* R1624  - EQRMIX Input 1 Source */
+	{ 0x0659, 0x0080 },   /* R1625  - EQRMIX Input 1 Volume */
+	{ 0x065A, 0x0000 },   /* R1626  - EQRMIX Input 2 Source */
+	{ 0x065B, 0x0080 },   /* R1627  - EQRMIX Input 2 Volume */
+	{ 0x065C, 0x0000 },   /* R1628  - EQRMIX Input 3 Source */
+	{ 0x065D, 0x0080 },   /* R1629  - EQRMIX Input 3 Volume */
+	{ 0x065E, 0x0000 },   /* R1630  - EQRMIX Input 4 Source */
+	{ 0x065F, 0x0080 },   /* R1631  - EQRMIX Input 4 Volume */
+	{ 0x0660, 0x0000 },   /* R1632  - LHPF1MIX Input 1 Source */
+	{ 0x0661, 0x0080 },   /* R1633  - LHPF1MIX Input 1 Volume */
+	{ 0x0662, 0x0000 },   /* R1634  - LHPF1MIX Input 2 Source */
+	{ 0x0663, 0x0080 },   /* R1635  - LHPF1MIX Input 2 Volume */
+	{ 0x0664, 0x0000 },   /* R1636  - LHPF1MIX Input 3 Source */
+	{ 0x0665, 0x0080 },   /* R1637  - LHPF1MIX Input 3 Volume */
+	{ 0x0666, 0x0000 },   /* R1638  - LHPF1MIX Input 4 Source */
+	{ 0x0667, 0x0080 },   /* R1639  - LHPF1MIX Input 4 Volume */
+	{ 0x0668, 0x0000 },   /* R1640  - LHPF2MIX Input 1 Source */
+	{ 0x0669, 0x0080 },   /* R1641  - LHPF2MIX Input 1 Volume */
+	{ 0x066A, 0x0000 },   /* R1642  - LHPF2MIX Input 2 Source */
+	{ 0x066B, 0x0080 },   /* R1643  - LHPF2MIX Input 2 Volume */
+	{ 0x066C, 0x0000 },   /* R1644  - LHPF2MIX Input 3 Source */
+	{ 0x066D, 0x0080 },   /* R1645  - LHPF2MIX Input 3 Volume */
+	{ 0x066E, 0x0000 },   /* R1646  - LHPF2MIX Input 4 Source */
+	{ 0x066F, 0x0080 },   /* R1647  - LHPF2MIX Input 4 Volume */
+	{ 0x0670, 0x0000 },   /* R1648  - DSP1LMIX Input 1 Source */
+	{ 0x0671, 0x0080 },   /* R1649  - DSP1LMIX Input 1 Volume */
+	{ 0x0672, 0x0000 },   /* R1650  - DSP1LMIX Input 2 Source */
+	{ 0x0673, 0x0080 },   /* R1651  - DSP1LMIX Input 2 Volume */
+	{ 0x0674, 0x0000 },   /* R1652  - DSP1LMIX Input 3 Source */
+	{ 0x0675, 0x0080 },   /* R1653  - DSP1LMIX Input 3 Volume */
+	{ 0x0676, 0x0000 },   /* R1654  - DSP1LMIX Input 4 Source */
+	{ 0x0677, 0x0080 },   /* R1655  - DSP1LMIX Input 4 Volume */
+	{ 0x0678, 0x0000 },   /* R1656  - DSP1RMIX Input 1 Source */
+	{ 0x0679, 0x0080 },   /* R1657  - DSP1RMIX Input 1 Volume */
+	{ 0x067A, 0x0000 },   /* R1658  - DSP1RMIX Input 2 Source */
+	{ 0x067B, 0x0080 },   /* R1659  - DSP1RMIX Input 2 Volume */
+	{ 0x067C, 0x0000 },   /* R1660  - DSP1RMIX Input 3 Source */
+	{ 0x067D, 0x0080 },   /* R1661  - DSP1RMIX Input 3 Volume */
+	{ 0x067E, 0x0000 },   /* R1662  - DSP1RMIX Input 4 Source */
+	{ 0x067F, 0x0080 },   /* R1663  - DSP1RMIX Input 4 Volume */
+	{ 0x0680, 0x0000 },   /* R1664  - DSP1AUX1MIX Input 1 Source */
+	{ 0x0681, 0x0000 },   /* R1665  - DSP1AUX2MIX Input 1 Source */
+	{ 0x0682, 0x0000 },   /* R1666  - DSP1AUX3MIX Input 1 Source */
+	{ 0x0683, 0x0000 },   /* R1667  - DSP1AUX4MIX Input 1 Source */
+	{ 0x0684, 0x0000 },   /* R1668  - DSP1AUX5MIX Input 1 Source */
+	{ 0x0685, 0x0000 },   /* R1669  - DSP1AUX6MIX Input 1 Source */
+	{ 0x0686, 0x0000 },   /* R1670  - DSP2LMIX Input 1 Source */
+	{ 0x0687, 0x0080 },   /* R1671  - DSP2LMIX Input 1 Volume */
+	{ 0x0688, 0x0000 },   /* R1672  - DSP2LMIX Input 2 Source */
+	{ 0x0689, 0x0080 },   /* R1673  - DSP2LMIX Input 2 Volume */
+	{ 0x068A, 0x0000 },   /* R1674  - DSP2LMIX Input 3 Source */
+	{ 0x068B, 0x0080 },   /* R1675  - DSP2LMIX Input 3 Volume */
+	{ 0x068C, 0x0000 },   /* R1676  - DSP2LMIX Input 4 Source */
+	{ 0x068D, 0x0080 },   /* R1677  - DSP2LMIX Input 4 Volume */
+	{ 0x068E, 0x0000 },   /* R1678  - DSP2RMIX Input 1 Source */
+	{ 0x068F, 0x0080 },   /* R1679  - DSP2RMIX Input 1 Volume */
+	{ 0x0690, 0x0000 },   /* R1680  - DSP2RMIX Input 2 Source */
+	{ 0x0691, 0x0080 },   /* R1681  - DSP2RMIX Input 2 Volume */
+	{ 0x0692, 0x0000 },   /* R1682  - DSP2RMIX Input 3 Source */
+	{ 0x0693, 0x0080 },   /* R1683  - DSP2RMIX Input 3 Volume */
+	{ 0x0694, 0x0000 },   /* R1684  - DSP2RMIX Input 4 Source */
+	{ 0x0695, 0x0080 },   /* R1685  - DSP2RMIX Input 4 Volume */
+	{ 0x0696, 0x0000 },   /* R1686  - DSP2AUX1MIX Input 1 Source */
+	{ 0x0697, 0x0000 },   /* R1687  - DSP2AUX2MIX Input 1 Source */
+	{ 0x0698, 0x0000 },   /* R1688  - DSP2AUX3MIX Input 1 Source */
+	{ 0x0699, 0x0000 },   /* R1689  - DSP2AUX4MIX Input 1 Source */
+	{ 0x069A, 0x0000 },   /* R1690  - DSP2AUX5MIX Input 1 Source */
+	{ 0x069B, 0x0000 },   /* R1691  - DSP2AUX6MIX Input 1 Source */
+	{ 0x0700, 0xA101 },   /* R1792  - GPIO CTRL 1 */
+	{ 0x0701, 0xA101 },   /* R1793  - GPIO CTRL 2 */
+	{ 0x0702, 0xA101 },   /* R1794  - GPIO CTRL 3 */
+	{ 0x0703, 0xA101 },   /* R1795  - GPIO CTRL 4 */
+	{ 0x0709, 0x0000 },   /* R1801  - Misc Pad Ctrl 1 */
+	{ 0x0801, 0x00FF },   /* R2049  - Interrupt Status 1 Mask */
+	{ 0x0804, 0xFFFF },   /* R2052  - Interrupt Status 2 Mask */
+	{ 0x0808, 0x0000 },   /* R2056  - Interrupt Control */
+	{ 0x0900, 0x0000 },   /* R2304  - EQL_1 */
+	{ 0x0901, 0x0000 },   /* R2305  - EQL_2 */
+	{ 0x0902, 0x0000 },   /* R2306  - EQL_3 */
+	{ 0x0903, 0x0000 },   /* R2307  - EQL_4 */
+	{ 0x0904, 0x0000 },   /* R2308  - EQL_5 */
+	{ 0x0905, 0x0000 },   /* R2309  - EQL_6 */
+	{ 0x0906, 0x0000 },   /* R2310  - EQL_7 */
+	{ 0x0907, 0x0000 },   /* R2311  - EQL_8 */
+	{ 0x0908, 0x0000 },   /* R2312  - EQL_9 */
+	{ 0x0909, 0x0000 },   /* R2313  - EQL_10 */
+	{ 0x090A, 0x0000 },   /* R2314  - EQL_11 */
+	{ 0x090B, 0x0000 },   /* R2315  - EQL_12 */
+	{ 0x090C, 0x0000 },   /* R2316  - EQL_13 */
+	{ 0x090D, 0x0000 },   /* R2317  - EQL_14 */
+	{ 0x090E, 0x0000 },   /* R2318  - EQL_15 */
+	{ 0x090F, 0x0000 },   /* R2319  - EQL_16 */
+	{ 0x0910, 0x0000 },   /* R2320  - EQL_17 */
+	{ 0x0911, 0x0000 },   /* R2321  - EQL_18 */
+	{ 0x0912, 0x0000 },   /* R2322  - EQL_19 */
+	{ 0x0913, 0x0000 },   /* R2323  - EQL_20 */
+	{ 0x0916, 0x0000 },   /* R2326  - EQR_1 */
+	{ 0x0917, 0x0000 },   /* R2327  - EQR_2 */
+	{ 0x0918, 0x0000 },   /* R2328  - EQR_3 */
+	{ 0x0919, 0x0000 },   /* R2329  - EQR_4 */
+	{ 0x091A, 0x0000 },   /* R2330  - EQR_5 */
+	{ 0x091B, 0x0000 },   /* R2331  - EQR_6 */
+	{ 0x091C, 0x0000 },   /* R2332  - EQR_7 */
+	{ 0x091D, 0x0000 },   /* R2333  - EQR_8 */
+	{ 0x091E, 0x0000 },   /* R2334  - EQR_9 */
+	{ 0x091F, 0x0000 },   /* R2335  - EQR_10 */
+	{ 0x0920, 0x0000 },   /* R2336  - EQR_11 */
+	{ 0x0921, 0x0000 },   /* R2337  - EQR_12 */
+	{ 0x0922, 0x0000 },   /* R2338  - EQR_13 */
+	{ 0x0923, 0x0000 },   /* R2339  - EQR_14 */
+	{ 0x0924, 0x0000 },   /* R2340  - EQR_15 */
+	{ 0x0925, 0x0000 },   /* R2341  - EQR_16 */
+	{ 0x0926, 0x0000 },   /* R2342  - EQR_17 */
+	{ 0x0927, 0x0000 },   /* R2343  - EQR_18 */
+	{ 0x0928, 0x0000 },   /* R2344  - EQR_19 */
+	{ 0x0929, 0x0000 },   /* R2345  - EQR_20 */
+	{ 0x093E, 0x0000 },   /* R2366  - HPLPF1_1 */
+	{ 0x093F, 0x0000 },   /* R2367  - HPLPF1_2 */
+	{ 0x0942, 0x0000 },   /* R2370  - HPLPF2_1 */
+	{ 0x0943, 0x0000 },   /* R2371  - HPLPF2_2 */
+	{ 0x0A00, 0x0000 },   /* R2560  - DSP1 Control 1 */
+	{ 0x0A02, 0x0000 },   /* R2562  - DSP1 Control 2 */
+	{ 0x0A03, 0x0000 },   /* R2563  - DSP1 Control 3 */
+	{ 0x0A04, 0x0000 },   /* R2564  - DSP1 Control 4 */
+	{ 0x0A06, 0x0000 },   /* R2566  - DSP1 Control 5 */
+	{ 0x0A07, 0x0000 },   /* R2567  - DSP1 Control 6 */
+	{ 0x0A08, 0x0000 },   /* R2568  - DSP1 Control 7 */
+	{ 0x0A09, 0x0000 },   /* R2569  - DSP1 Control 8 */
+	{ 0x0A0A, 0x0000 },   /* R2570  - DSP1 Control 9 */
+	{ 0x0A0B, 0x0000 },   /* R2571  - DSP1 Control 10 */
+	{ 0x0A0C, 0x0000 },   /* R2572  - DSP1 Control 11 */
+	{ 0x0A0D, 0x0000 },   /* R2573  - DSP1 Control 12 */
+	{ 0x0A0F, 0x0000 },   /* R2575  - DSP1 Control 13 */
+	{ 0x0A10, 0x0000 },   /* R2576  - DSP1 Control 14 */
+	{ 0x0A11, 0x0000 },   /* R2577  - DSP1 Control 15 */
+	{ 0x0A12, 0x0000 },   /* R2578  - DSP1 Control 16 */
+	{ 0x0A13, 0x0000 },   /* R2579  - DSP1 Control 17 */
+	{ 0x0A14, 0x0000 },   /* R2580  - DSP1 Control 18 */
+	{ 0x0A16, 0x0000 },   /* R2582  - DSP1 Control 19 */
+	{ 0x0A17, 0x0000 },   /* R2583  - DSP1 Control 20 */
+	{ 0x0A18, 0x0000 },   /* R2584  - DSP1 Control 21 */
+	{ 0x0A1A, 0x1800 },   /* R2586  - DSP1 Control 22 */
+	{ 0x0A1B, 0x1000 },   /* R2587  - DSP1 Control 23 */
+	{ 0x0A1C, 0x0400 },   /* R2588  - DSP1 Control 24 */
+	{ 0x0A1E, 0x0000 },   /* R2590  - DSP1 Control 25 */
+	{ 0x0A20, 0x0000 },   /* R2592  - DSP1 Control 26 */
+	{ 0x0A21, 0x0000 },   /* R2593  - DSP1 Control 27 */
+	{ 0x0A22, 0x0000 },   /* R2594  - DSP1 Control 28 */
+	{ 0x0A23, 0x0000 },   /* R2595  - DSP1 Control 29 */
+	{ 0x0A24, 0x0000 },   /* R2596  - DSP1 Control 30 */
+	{ 0x0A26, 0x0000 },   /* R2598  - DSP1 Control 31 */
+	{ 0x0B00, 0x0000 },   /* R2816  - DSP2 Control 1 */
+	{ 0x0B02, 0x0000 },   /* R2818  - DSP2 Control 2 */
+	{ 0x0B03, 0x0000 },   /* R2819  - DSP2 Control 3 */
+	{ 0x0B04, 0x0000 },   /* R2820  - DSP2 Control 4 */
+	{ 0x0B06, 0x0000 },   /* R2822  - DSP2 Control 5 */
+	{ 0x0B07, 0x0000 },   /* R2823  - DSP2 Control 6 */
+	{ 0x0B08, 0x0000 },   /* R2824  - DSP2 Control 7 */
+	{ 0x0B09, 0x0000 },   /* R2825  - DSP2 Control 8 */
+	{ 0x0B0A, 0x0000 },   /* R2826  - DSP2 Control 9 */
+	{ 0x0B0B, 0x0000 },   /* R2827  - DSP2 Control 10 */
+	{ 0x0B0C, 0x0000 },   /* R2828  - DSP2 Control 11 */
+	{ 0x0B0D, 0x0000 },   /* R2829  - DSP2 Control 12 */
+	{ 0x0B0F, 0x0000 },   /* R2831  - DSP2 Control 13 */
+	{ 0x0B10, 0x0000 },   /* R2832  - DSP2 Control 14 */
+	{ 0x0B11, 0x0000 },   /* R2833  - DSP2 Control 15 */
+	{ 0x0B12, 0x0000 },   /* R2834  - DSP2 Control 16 */
+	{ 0x0B13, 0x0000 },   /* R2835  - DSP2 Control 17 */
+	{ 0x0B14, 0x0000 },   /* R2836  - DSP2 Control 18 */
+	{ 0x0B16, 0x0000 },   /* R2838  - DSP2 Control 19 */
+	{ 0x0B17, 0x0000 },   /* R2839  - DSP2 Control 20 */
+	{ 0x0B18, 0x0000 },   /* R2840  - DSP2 Control 21 */
+	{ 0x0B1A, 0x0800 },   /* R2842  - DSP2 Control 22 */
+	{ 0x0B1B, 0x1000 },   /* R2843  - DSP2 Control 23 */
+	{ 0x0B1C, 0x0400 },   /* R2844  - DSP2 Control 24 */
+	{ 0x0B1E, 0x0000 },   /* R2846  - DSP2 Control 25 */
+	{ 0x0B20, 0x0000 },   /* R2848  - DSP2 Control 26 */
+	{ 0x0B21, 0x0000 },   /* R2849  - DSP2 Control 27 */
+	{ 0x0B22, 0x0000 },   /* R2850  - DSP2 Control 28 */
+	{ 0x0B23, 0x0000 },   /* R2851  - DSP2 Control 29 */
+	{ 0x0B24, 0x0000 },   /* R2852  - DSP2 Control 30 */
+	{ 0x0B26, 0x0000 },   /* R2854  - DSP2 Control 31 */
+};
+
+static bool wm2200_volatile_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wm2200_ranges); i++)
+		if ((reg >= wm2200_ranges[i].window_start &&
+		     reg <= wm2200_ranges[i].window_start +
+		     wm2200_ranges[i].window_len) ||
+		    (reg >= wm2200_ranges[i].range_min &&
+		     reg <= wm2200_ranges[i].range_max))
+			return true;
+
+	switch (reg) {
+	case WM2200_SOFTWARE_RESET:
+	case WM2200_DEVICE_REVISION:
+	case WM2200_ADPS1_IRQ0:
+	case WM2200_ADPS1_IRQ1:
+	case WM2200_INTERRUPT_STATUS_1:
+	case WM2200_INTERRUPT_STATUS_2:
+	case WM2200_INTERRUPT_RAW_STATUS_2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm2200_readable_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wm2200_ranges); i++)
+		if ((reg >= wm2200_ranges[i].window_start &&
+		     reg <= wm2200_ranges[i].window_start +
+		     wm2200_ranges[i].window_len) ||
+		    (reg >= wm2200_ranges[i].range_min &&
+		     reg <= wm2200_ranges[i].range_max))
+			return true;
+
+	switch (reg) {
+	case WM2200_SOFTWARE_RESET:
+	case WM2200_DEVICE_REVISION:
+	case WM2200_TONE_GENERATOR_1:
+	case WM2200_CLOCKING_3:
+	case WM2200_CLOCKING_4:
+	case WM2200_FLL_CONTROL_1:
+	case WM2200_FLL_CONTROL_2:
+	case WM2200_FLL_CONTROL_3:
+	case WM2200_FLL_CONTROL_4:
+	case WM2200_FLL_CONTROL_6:
+	case WM2200_FLL_CONTROL_7:
+	case WM2200_FLL_EFS_1:
+	case WM2200_FLL_EFS_2:
+	case WM2200_MIC_CHARGE_PUMP_1:
+	case WM2200_MIC_CHARGE_PUMP_2:
+	case WM2200_DM_CHARGE_PUMP_1:
+	case WM2200_MIC_BIAS_CTRL_1:
+	case WM2200_MIC_BIAS_CTRL_2:
+	case WM2200_EAR_PIECE_CTRL_1:
+	case WM2200_EAR_PIECE_CTRL_2:
+	case WM2200_INPUT_ENABLES:
+	case WM2200_IN1L_CONTROL:
+	case WM2200_IN1R_CONTROL:
+	case WM2200_IN2L_CONTROL:
+	case WM2200_IN2R_CONTROL:
+	case WM2200_IN3L_CONTROL:
+	case WM2200_IN3R_CONTROL:
+	case WM2200_RXANC_SRC:
+	case WM2200_INPUT_VOLUME_RAMP:
+	case WM2200_ADC_DIGITAL_VOLUME_1L:
+	case WM2200_ADC_DIGITAL_VOLUME_1R:
+	case WM2200_ADC_DIGITAL_VOLUME_2L:
+	case WM2200_ADC_DIGITAL_VOLUME_2R:
+	case WM2200_ADC_DIGITAL_VOLUME_3L:
+	case WM2200_ADC_DIGITAL_VOLUME_3R:
+	case WM2200_OUTPUT_ENABLES:
+	case WM2200_DAC_VOLUME_LIMIT_1L:
+	case WM2200_DAC_VOLUME_LIMIT_1R:
+	case WM2200_DAC_VOLUME_LIMIT_2L:
+	case WM2200_DAC_VOLUME_LIMIT_2R:
+	case WM2200_DAC_AEC_CONTROL_1:
+	case WM2200_OUTPUT_VOLUME_RAMP:
+	case WM2200_DAC_DIGITAL_VOLUME_1L:
+	case WM2200_DAC_DIGITAL_VOLUME_1R:
+	case WM2200_DAC_DIGITAL_VOLUME_2L:
+	case WM2200_DAC_DIGITAL_VOLUME_2R:
+	case WM2200_PDM_1:
+	case WM2200_PDM_2:
+	case WM2200_AUDIO_IF_1_1:
+	case WM2200_AUDIO_IF_1_2:
+	case WM2200_AUDIO_IF_1_3:
+	case WM2200_AUDIO_IF_1_4:
+	case WM2200_AUDIO_IF_1_5:
+	case WM2200_AUDIO_IF_1_6:
+	case WM2200_AUDIO_IF_1_7:
+	case WM2200_AUDIO_IF_1_8:
+	case WM2200_AUDIO_IF_1_9:
+	case WM2200_AUDIO_IF_1_10:
+	case WM2200_AUDIO_IF_1_11:
+	case WM2200_AUDIO_IF_1_12:
+	case WM2200_AUDIO_IF_1_13:
+	case WM2200_AUDIO_IF_1_14:
+	case WM2200_AUDIO_IF_1_15:
+	case WM2200_AUDIO_IF_1_16:
+	case WM2200_AUDIO_IF_1_17:
+	case WM2200_AUDIO_IF_1_18:
+	case WM2200_AUDIO_IF_1_19:
+	case WM2200_AUDIO_IF_1_20:
+	case WM2200_AUDIO_IF_1_21:
+	case WM2200_AUDIO_IF_1_22:
+	case WM2200_OUT1LMIX_INPUT_1_SOURCE:
+	case WM2200_OUT1LMIX_INPUT_1_VOLUME:
+	case WM2200_OUT1LMIX_INPUT_2_SOURCE:
+	case WM2200_OUT1LMIX_INPUT_2_VOLUME:
+	case WM2200_OUT1LMIX_INPUT_3_SOURCE:
+	case WM2200_OUT1LMIX_INPUT_3_VOLUME:
+	case WM2200_OUT1LMIX_INPUT_4_SOURCE:
+	case WM2200_OUT1LMIX_INPUT_4_VOLUME:
+	case WM2200_OUT1RMIX_INPUT_1_SOURCE:
+	case WM2200_OUT1RMIX_INPUT_1_VOLUME:
+	case WM2200_OUT1RMIX_INPUT_2_SOURCE:
+	case WM2200_OUT1RMIX_INPUT_2_VOLUME:
+	case WM2200_OUT1RMIX_INPUT_3_SOURCE:
+	case WM2200_OUT1RMIX_INPUT_3_VOLUME:
+	case WM2200_OUT1RMIX_INPUT_4_SOURCE:
+	case WM2200_OUT1RMIX_INPUT_4_VOLUME:
+	case WM2200_OUT2LMIX_INPUT_1_SOURCE:
+	case WM2200_OUT2LMIX_INPUT_1_VOLUME:
+	case WM2200_OUT2LMIX_INPUT_2_SOURCE:
+	case WM2200_OUT2LMIX_INPUT_2_VOLUME:
+	case WM2200_OUT2LMIX_INPUT_3_SOURCE:
+	case WM2200_OUT2LMIX_INPUT_3_VOLUME:
+	case WM2200_OUT2LMIX_INPUT_4_SOURCE:
+	case WM2200_OUT2LMIX_INPUT_4_VOLUME:
+	case WM2200_OUT2RMIX_INPUT_1_SOURCE:
+	case WM2200_OUT2RMIX_INPUT_1_VOLUME:
+	case WM2200_OUT2RMIX_INPUT_2_SOURCE:
+	case WM2200_OUT2RMIX_INPUT_2_VOLUME:
+	case WM2200_OUT2RMIX_INPUT_3_SOURCE:
+	case WM2200_OUT2RMIX_INPUT_3_VOLUME:
+	case WM2200_OUT2RMIX_INPUT_4_SOURCE:
+	case WM2200_OUT2RMIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX1MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX1MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX1MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX1MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX1MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX1MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX1MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX1MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX2MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX2MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX2MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX2MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX2MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX2MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX2MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX2MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX3MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX3MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX3MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX3MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX3MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX3MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX3MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX3MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX4MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX4MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX4MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX4MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX4MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX4MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX4MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX4MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX5MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX5MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX5MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX5MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX5MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX5MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX5MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX5MIX_INPUT_4_VOLUME:
+	case WM2200_AIF1TX6MIX_INPUT_1_SOURCE:
+	case WM2200_AIF1TX6MIX_INPUT_1_VOLUME:
+	case WM2200_AIF1TX6MIX_INPUT_2_SOURCE:
+	case WM2200_AIF1TX6MIX_INPUT_2_VOLUME:
+	case WM2200_AIF1TX6MIX_INPUT_3_SOURCE:
+	case WM2200_AIF1TX6MIX_INPUT_3_VOLUME:
+	case WM2200_AIF1TX6MIX_INPUT_4_SOURCE:
+	case WM2200_AIF1TX6MIX_INPUT_4_VOLUME:
+	case WM2200_EQLMIX_INPUT_1_SOURCE:
+	case WM2200_EQLMIX_INPUT_1_VOLUME:
+	case WM2200_EQLMIX_INPUT_2_SOURCE:
+	case WM2200_EQLMIX_INPUT_2_VOLUME:
+	case WM2200_EQLMIX_INPUT_3_SOURCE:
+	case WM2200_EQLMIX_INPUT_3_VOLUME:
+	case WM2200_EQLMIX_INPUT_4_SOURCE:
+	case WM2200_EQLMIX_INPUT_4_VOLUME:
+	case WM2200_EQRMIX_INPUT_1_SOURCE:
+	case WM2200_EQRMIX_INPUT_1_VOLUME:
+	case WM2200_EQRMIX_INPUT_2_SOURCE:
+	case WM2200_EQRMIX_INPUT_2_VOLUME:
+	case WM2200_EQRMIX_INPUT_3_SOURCE:
+	case WM2200_EQRMIX_INPUT_3_VOLUME:
+	case WM2200_EQRMIX_INPUT_4_SOURCE:
+	case WM2200_EQRMIX_INPUT_4_VOLUME:
+	case WM2200_LHPF1MIX_INPUT_1_SOURCE:
+	case WM2200_LHPF1MIX_INPUT_1_VOLUME:
+	case WM2200_LHPF1MIX_INPUT_2_SOURCE:
+	case WM2200_LHPF1MIX_INPUT_2_VOLUME:
+	case WM2200_LHPF1MIX_INPUT_3_SOURCE:
+	case WM2200_LHPF1MIX_INPUT_3_VOLUME:
+	case WM2200_LHPF1MIX_INPUT_4_SOURCE:
+	case WM2200_LHPF1MIX_INPUT_4_VOLUME:
+	case WM2200_LHPF2MIX_INPUT_1_SOURCE:
+	case WM2200_LHPF2MIX_INPUT_1_VOLUME:
+	case WM2200_LHPF2MIX_INPUT_2_SOURCE:
+	case WM2200_LHPF2MIX_INPUT_2_VOLUME:
+	case WM2200_LHPF2MIX_INPUT_3_SOURCE:
+	case WM2200_LHPF2MIX_INPUT_3_VOLUME:
+	case WM2200_LHPF2MIX_INPUT_4_SOURCE:
+	case WM2200_LHPF2MIX_INPUT_4_VOLUME:
+	case WM2200_DSP1LMIX_INPUT_1_SOURCE:
+	case WM2200_DSP1LMIX_INPUT_1_VOLUME:
+	case WM2200_DSP1LMIX_INPUT_2_SOURCE:
+	case WM2200_DSP1LMIX_INPUT_2_VOLUME:
+	case WM2200_DSP1LMIX_INPUT_3_SOURCE:
+	case WM2200_DSP1LMIX_INPUT_3_VOLUME:
+	case WM2200_DSP1LMIX_INPUT_4_SOURCE:
+	case WM2200_DSP1LMIX_INPUT_4_VOLUME:
+	case WM2200_DSP1RMIX_INPUT_1_SOURCE:
+	case WM2200_DSP1RMIX_INPUT_1_VOLUME:
+	case WM2200_DSP1RMIX_INPUT_2_SOURCE:
+	case WM2200_DSP1RMIX_INPUT_2_VOLUME:
+	case WM2200_DSP1RMIX_INPUT_3_SOURCE:
+	case WM2200_DSP1RMIX_INPUT_3_VOLUME:
+	case WM2200_DSP1RMIX_INPUT_4_SOURCE:
+	case WM2200_DSP1RMIX_INPUT_4_VOLUME:
+	case WM2200_DSP1AUX1MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX2MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX3MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX4MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX5MIX_INPUT_1_SOURCE:
+	case WM2200_DSP1AUX6MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_1_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_1_VOLUME:
+	case WM2200_DSP2LMIX_INPUT_2_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_2_VOLUME:
+	case WM2200_DSP2LMIX_INPUT_3_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_3_VOLUME:
+	case WM2200_DSP2LMIX_INPUT_4_SOURCE:
+	case WM2200_DSP2LMIX_INPUT_4_VOLUME:
+	case WM2200_DSP2RMIX_INPUT_1_SOURCE:
+	case WM2200_DSP2RMIX_INPUT_1_VOLUME:
+	case WM2200_DSP2RMIX_INPUT_2_SOURCE:
+	case WM2200_DSP2RMIX_INPUT_2_VOLUME:
+	case WM2200_DSP2RMIX_INPUT_3_SOURCE:
+	case WM2200_DSP2RMIX_INPUT_3_VOLUME:
+	case WM2200_DSP2RMIX_INPUT_4_SOURCE:
+	case WM2200_DSP2RMIX_INPUT_4_VOLUME:
+	case WM2200_DSP2AUX1MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX2MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX3MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX4MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX5MIX_INPUT_1_SOURCE:
+	case WM2200_DSP2AUX6MIX_INPUT_1_SOURCE:
+	case WM2200_GPIO_CTRL_1:
+	case WM2200_GPIO_CTRL_2:
+	case WM2200_GPIO_CTRL_3:
+	case WM2200_GPIO_CTRL_4:
+	case WM2200_ADPS1_IRQ0:
+	case WM2200_ADPS1_IRQ1:
+	case WM2200_MISC_PAD_CTRL_1:
+	case WM2200_INTERRUPT_STATUS_1:
+	case WM2200_INTERRUPT_STATUS_1_MASK:
+	case WM2200_INTERRUPT_STATUS_2:
+	case WM2200_INTERRUPT_RAW_STATUS_2:
+	case WM2200_INTERRUPT_STATUS_2_MASK:
+	case WM2200_INTERRUPT_CONTROL:
+	case WM2200_EQL_1:
+	case WM2200_EQL_2:
+	case WM2200_EQL_3:
+	case WM2200_EQL_4:
+	case WM2200_EQL_5:
+	case WM2200_EQL_6:
+	case WM2200_EQL_7:
+	case WM2200_EQL_8:
+	case WM2200_EQL_9:
+	case WM2200_EQL_10:
+	case WM2200_EQL_11:
+	case WM2200_EQL_12:
+	case WM2200_EQL_13:
+	case WM2200_EQL_14:
+	case WM2200_EQL_15:
+	case WM2200_EQL_16:
+	case WM2200_EQL_17:
+	case WM2200_EQL_18:
+	case WM2200_EQL_19:
+	case WM2200_EQL_20:
+	case WM2200_EQR_1:
+	case WM2200_EQR_2:
+	case WM2200_EQR_3:
+	case WM2200_EQR_4:
+	case WM2200_EQR_5:
+	case WM2200_EQR_6:
+	case WM2200_EQR_7:
+	case WM2200_EQR_8:
+	case WM2200_EQR_9:
+	case WM2200_EQR_10:
+	case WM2200_EQR_11:
+	case WM2200_EQR_12:
+	case WM2200_EQR_13:
+	case WM2200_EQR_14:
+	case WM2200_EQR_15:
+	case WM2200_EQR_16:
+	case WM2200_EQR_17:
+	case WM2200_EQR_18:
+	case WM2200_EQR_19:
+	case WM2200_EQR_20:
+	case WM2200_HPLPF1_1:
+	case WM2200_HPLPF1_2:
+	case WM2200_HPLPF2_1:
+	case WM2200_HPLPF2_2:
+	case WM2200_DSP1_CONTROL_1:
+	case WM2200_DSP1_CONTROL_2:
+	case WM2200_DSP1_CONTROL_3:
+	case WM2200_DSP1_CONTROL_4:
+	case WM2200_DSP1_CONTROL_5:
+	case WM2200_DSP1_CONTROL_6:
+	case WM2200_DSP1_CONTROL_7:
+	case WM2200_DSP1_CONTROL_8:
+	case WM2200_DSP1_CONTROL_9:
+	case WM2200_DSP1_CONTROL_10:
+	case WM2200_DSP1_CONTROL_11:
+	case WM2200_DSP1_CONTROL_12:
+	case WM2200_DSP1_CONTROL_13:
+	case WM2200_DSP1_CONTROL_14:
+	case WM2200_DSP1_CONTROL_15:
+	case WM2200_DSP1_CONTROL_16:
+	case WM2200_DSP1_CONTROL_17:
+	case WM2200_DSP1_CONTROL_18:
+	case WM2200_DSP1_CONTROL_19:
+	case WM2200_DSP1_CONTROL_20:
+	case WM2200_DSP1_CONTROL_21:
+	case WM2200_DSP1_CONTROL_22:
+	case WM2200_DSP1_CONTROL_23:
+	case WM2200_DSP1_CONTROL_24:
+	case WM2200_DSP1_CONTROL_25:
+	case WM2200_DSP1_CONTROL_26:
+	case WM2200_DSP1_CONTROL_27:
+	case WM2200_DSP1_CONTROL_28:
+	case WM2200_DSP1_CONTROL_29:
+	case WM2200_DSP1_CONTROL_30:
+	case WM2200_DSP1_CONTROL_31:
+	case WM2200_DSP2_CONTROL_1:
+	case WM2200_DSP2_CONTROL_2:
+	case WM2200_DSP2_CONTROL_3:
+	case WM2200_DSP2_CONTROL_4:
+	case WM2200_DSP2_CONTROL_5:
+	case WM2200_DSP2_CONTROL_6:
+	case WM2200_DSP2_CONTROL_7:
+	case WM2200_DSP2_CONTROL_8:
+	case WM2200_DSP2_CONTROL_9:
+	case WM2200_DSP2_CONTROL_10:
+	case WM2200_DSP2_CONTROL_11:
+	case WM2200_DSP2_CONTROL_12:
+	case WM2200_DSP2_CONTROL_13:
+	case WM2200_DSP2_CONTROL_14:
+	case WM2200_DSP2_CONTROL_15:
+	case WM2200_DSP2_CONTROL_16:
+	case WM2200_DSP2_CONTROL_17:
+	case WM2200_DSP2_CONTROL_18:
+	case WM2200_DSP2_CONTROL_19:
+	case WM2200_DSP2_CONTROL_20:
+	case WM2200_DSP2_CONTROL_21:
+	case WM2200_DSP2_CONTROL_22:
+	case WM2200_DSP2_CONTROL_23:
+	case WM2200_DSP2_CONTROL_24:
+	case WM2200_DSP2_CONTROL_25:
+	case WM2200_DSP2_CONTROL_26:
+	case WM2200_DSP2_CONTROL_27:
+	case WM2200_DSP2_CONTROL_28:
+	case WM2200_DSP2_CONTROL_29:
+	case WM2200_DSP2_CONTROL_30:
+	case WM2200_DSP2_CONTROL_31:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct reg_sequence wm2200_reva_patch[] = {
+	{ 0x07, 0x0003 },
+	{ 0x102, 0x0200 },
+	{ 0x203, 0x0084 },
+	{ 0x201, 0x83FF },
+	{ 0x20C, 0x0062 },
+	{ 0x20D, 0x0062 },
+	{ 0x207, 0x2002 },
+	{ 0x208, 0x20C0 },
+	{ 0x21D, 0x01C0 },
+	{ 0x50A, 0x0001 },
+	{ 0x50B, 0x0002 },
+	{ 0x50C, 0x0003 },
+	{ 0x50D, 0x0004 },
+	{ 0x50E, 0x0005 },
+	{ 0x510, 0x0001 },
+	{ 0x511, 0x0002 },
+	{ 0x512, 0x0003 },
+	{ 0x513, 0x0004 },
+	{ 0x514, 0x0005 },
+	{ 0x515, 0x0000 },
+	{ 0x201, 0x8084 },
+	{ 0x202, 0xBBDE },
+	{ 0x203, 0x00EC },
+	{ 0x500, 0x8000 },
+	{ 0x507, 0x1820 },
+	{ 0x508, 0x1820 },
+	{ 0x505, 0x0300 },
+	{ 0x506, 0x0300 },
+	{ 0x302, 0x2280 },
+	{ 0x303, 0x0080 },
+	{ 0x304, 0x2280 },
+	{ 0x305, 0x0080 },
+	{ 0x306, 0x2280 },
+	{ 0x307, 0x0080 },
+	{ 0x401, 0x0080 },
+	{ 0x402, 0x0080 },
+	{ 0x417, 0x3069 },
+	{ 0x900, 0x6318 },
+	{ 0x901, 0x6300 },
+	{ 0x902, 0x0FC8 },
+	{ 0x903, 0x03FE },
+	{ 0x904, 0x00E0 },
+	{ 0x905, 0x1EC4 },
+	{ 0x906, 0xF136 },
+	{ 0x907, 0x0409 },
+	{ 0x908, 0x04CC },
+	{ 0x909, 0x1C9B },
+	{ 0x90A, 0xF337 },
+	{ 0x90B, 0x040B },
+	{ 0x90C, 0x0CBB },
+	{ 0x90D, 0x16F8 },
+	{ 0x90E, 0xF7D9 },
+	{ 0x90F, 0x040A },
+	{ 0x910, 0x1F14 },
+	{ 0x911, 0x058C },
+	{ 0x912, 0x0563 },
+	{ 0x913, 0x4000 },
+	{ 0x916, 0x6318 },
+	{ 0x917, 0x6300 },
+	{ 0x918, 0x0FC8 },
+	{ 0x919, 0x03FE },
+	{ 0x91A, 0x00E0 },
+	{ 0x91B, 0x1EC4 },
+	{ 0x91C, 0xF136 },
+	{ 0x91D, 0x0409 },
+	{ 0x91E, 0x04CC },
+	{ 0x91F, 0x1C9B },
+	{ 0x920, 0xF337 },
+	{ 0x921, 0x040B },
+	{ 0x922, 0x0CBB },
+	{ 0x923, 0x16F8 },
+	{ 0x924, 0xF7D9 },
+	{ 0x925, 0x040A },
+	{ 0x926, 0x1F14 },
+	{ 0x927, 0x058C },
+	{ 0x928, 0x0563 },
+	{ 0x929, 0x4000 },
+	{ 0x709, 0x2000 },
+	{ 0x207, 0x200E },
+	{ 0x208, 0x20D4 },
+	{ 0x20A, 0x0080 },
+	{ 0x07, 0x0000 },
+};
+
+static int wm2200_reset(struct wm2200_priv *wm2200)
+{
+	if (wm2200->pdata.reset) {
+		gpio_set_value_cansleep(wm2200->pdata.reset, 0);
+		gpio_set_value_cansleep(wm2200->pdata.reset, 1);
+
+		return 0;
+	} else {
+		return regmap_write(wm2200->regmap, WM2200_SOFTWARE_RESET,
+				    0x2200);
+	}
+}
+
+static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0);
+
+static const char * const wm2200_mixer_texts[] = {
+	"None",
+	"Tone Generator",
+	"AEC Loopback",
+	"IN1L",
+	"IN1R",
+	"IN2L",
+	"IN2R",
+	"IN3L",
+	"IN3R",
+	"AIF1RX1",
+	"AIF1RX2",
+	"AIF1RX3",
+	"AIF1RX4",
+	"AIF1RX5",
+	"AIF1RX6",
+	"EQL",
+	"EQR",
+	"LHPF1",
+	"LHPF2",
+	"DSP1.1",
+	"DSP1.2",
+	"DSP1.3",
+	"DSP1.4",
+	"DSP1.5",
+	"DSP1.6",
+	"DSP2.1",
+	"DSP2.2",
+	"DSP2.3",
+	"DSP2.4",
+	"DSP2.5",
+	"DSP2.6",
+};
+
+static unsigned int wm2200_mixer_values[] = {
+	0x00,
+	0x04,   /* Tone */
+	0x08,   /* AEC */
+	0x10,   /* Input */
+	0x11,
+	0x12,
+	0x13,
+	0x14,
+	0x15,
+	0x20,   /* AIF */
+	0x21,
+	0x22,
+	0x23,
+	0x24,
+	0x25,
+	0x50,   /* EQ */
+	0x51,
+	0x60,   /* LHPF1 */
+	0x61,   /* LHPF2 */
+	0x68,   /* DSP1 */
+	0x69,
+	0x6a,
+	0x6b,
+	0x6c,
+	0x6d,
+	0x70,   /* DSP2 */
+	0x71,
+	0x72,
+	0x73,
+	0x74,
+	0x75,
+};
+
+#define WM2200_MIXER_CONTROLS(name, base) \
+	SOC_SINGLE_TLV(name " Input 1 Volume", base + 1 , \
+		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+	SOC_SINGLE_TLV(name " Input 2 Volume", base + 3 , \
+		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+	SOC_SINGLE_TLV(name " Input 3 Volume", base + 5 , \
+		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+	SOC_SINGLE_TLV(name " Input 4 Volume", base + 7 , \
+		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv)
+
+#define WM2200_MUX_ENUM_DECL(name, reg) \
+	SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, 			\
+				   wm2200_mixer_texts, wm2200_mixer_values)
+
+#define WM2200_MUX_CTL_DECL(name) \
+	const struct snd_kcontrol_new name##_mux =	\
+		SOC_DAPM_ENUM("Route", name##_enum)
+
+#define WM2200_MIXER_ENUMS(name, base_reg) \
+	static WM2200_MUX_ENUM_DECL(name##_in1_enum, base_reg);	     \
+	static WM2200_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2);  \
+	static WM2200_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4);  \
+	static WM2200_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6);  \
+	static WM2200_MUX_CTL_DECL(name##_in1); \
+	static WM2200_MUX_CTL_DECL(name##_in2); \
+	static WM2200_MUX_CTL_DECL(name##_in3); \
+	static WM2200_MUX_CTL_DECL(name##_in4)
+
+#define WM2200_DSP_ENUMS(name, base_reg) \
+	static WM2200_MUX_ENUM_DECL(name##_aux1_enum, base_reg);     \
+	static WM2200_MUX_ENUM_DECL(name##_aux2_enum, base_reg + 1); \
+	static WM2200_MUX_ENUM_DECL(name##_aux3_enum, base_reg + 2); \
+	static WM2200_MUX_ENUM_DECL(name##_aux4_enum, base_reg + 3); \
+	static WM2200_MUX_ENUM_DECL(name##_aux5_enum, base_reg + 4); \
+	static WM2200_MUX_ENUM_DECL(name##_aux6_enum, base_reg + 5); \
+	static WM2200_MUX_CTL_DECL(name##_aux1); \
+	static WM2200_MUX_CTL_DECL(name##_aux2); \
+	static WM2200_MUX_CTL_DECL(name##_aux3); \
+	static WM2200_MUX_CTL_DECL(name##_aux4); \
+	static WM2200_MUX_CTL_DECL(name##_aux5); \
+	static WM2200_MUX_CTL_DECL(name##_aux6);
+
+static const char *wm2200_rxanc_input_sel_texts[] = {
+	"None", "IN1", "IN2", "IN3",
+};
+
+static SOC_ENUM_SINGLE_DECL(wm2200_rxanc_input_sel,
+			    WM2200_RXANC_SRC,
+			    WM2200_IN_RXANC_SEL_SHIFT,
+			    wm2200_rxanc_input_sel_texts);
+
+static const struct snd_kcontrol_new wm2200_snd_controls[] = {
+SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL,
+	   WM2200_IN1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN2 High Performance Switch", WM2200_IN2L_CONTROL,
+	   WM2200_IN2_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN3 High Performance Switch", WM2200_IN3L_CONTROL,
+	   WM2200_IN3_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R_TLV("IN1 Volume", WM2200_IN1L_CONTROL, WM2200_IN1R_CONTROL,
+		 WM2200_IN1L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
+SOC_DOUBLE_R_TLV("IN2 Volume", WM2200_IN2L_CONTROL, WM2200_IN2R_CONTROL,
+		 WM2200_IN2L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
+SOC_DOUBLE_R_TLV("IN3 Volume", WM2200_IN3L_CONTROL, WM2200_IN3R_CONTROL,
+		 WM2200_IN3L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
+
+SOC_DOUBLE_R("IN1 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
+	     WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_2L,
+	     WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_3L,
+	     WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_1L,
+		 WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_DIG_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("IN2 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_2L,
+		 WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_DIG_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_3L,
+		 WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_DIG_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+
+SND_SOC_BYTES_MASK("EQL Coefficients", WM2200_EQL_1, 20, WM2200_EQL_ENA),
+SND_SOC_BYTES_MASK("EQR Coefficients", WM2200_EQR_1, 20, WM2200_EQR_ENA),
+
+SND_SOC_BYTES("LHPF1 Coefficients", WM2200_HPLPF1_2, 1),
+SND_SOC_BYTES("LHPF2 Coefficients", WM2200_HPLPF2_2, 1),
+
+SOC_SINGLE("OUT1 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_1L,
+	   WM2200_OUT1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("OUT2 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_2L,
+	   WM2200_OUT2_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R("OUT1 Digital Switch", WM2200_DAC_DIGITAL_VOLUME_1L,
+	     WM2200_DAC_DIGITAL_VOLUME_1R, WM2200_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R_TLV("OUT1 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_1L,
+		 WM2200_DAC_DIGITAL_VOLUME_1R, WM2200_OUT1L_VOL_SHIFT, 0x9f, 0,
+		 digital_tlv),
+SOC_DOUBLE_R_TLV("OUT1 Volume", WM2200_DAC_VOLUME_LIMIT_1L,
+		 WM2200_DAC_VOLUME_LIMIT_1R, WM2200_OUT1L_PGA_VOL_SHIFT,
+		 0x46, 0, out_tlv),
+
+SOC_DOUBLE_R("OUT2 Digital Switch", WM2200_DAC_DIGITAL_VOLUME_2L,
+	     WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L,
+		 WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_VOL_SHIFT, 0x9f, 0,
+		 digital_tlv),
+SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT,
+	   WM2200_SPK1R_MUTE_SHIFT, 1, 1),
+SOC_ENUM("RxANC Src", wm2200_rxanc_input_sel),
+
+WM_ADSP_FW_CONTROL("DSP1", 0),
+WM_ADSP_FW_CONTROL("DSP2", 1),
+};
+
+WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(OUT1R, WM2200_OUT1RMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(OUT2L, WM2200_OUT2LMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(OUT2R, WM2200_OUT2RMIX_INPUT_1_SOURCE);
+
+WM2200_MIXER_ENUMS(AIF1TX1, WM2200_AIF1TX1MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX2, WM2200_AIF1TX2MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX3, WM2200_AIF1TX3MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX4, WM2200_AIF1TX4MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX5, WM2200_AIF1TX5MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(AIF1TX6, WM2200_AIF1TX6MIX_INPUT_1_SOURCE);
+
+WM2200_MIXER_ENUMS(EQL, WM2200_EQLMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(EQR, WM2200_EQRMIX_INPUT_1_SOURCE);
+
+WM2200_MIXER_ENUMS(DSP1L, WM2200_DSP1LMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(DSP1R, WM2200_DSP1RMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(DSP2L, WM2200_DSP2LMIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(DSP2R, WM2200_DSP2RMIX_INPUT_1_SOURCE);
+
+WM2200_DSP_ENUMS(DSP1, WM2200_DSP1AUX1MIX_INPUT_1_SOURCE);
+WM2200_DSP_ENUMS(DSP2, WM2200_DSP2AUX1MIX_INPUT_1_SOURCE);
+
+WM2200_MIXER_ENUMS(LHPF1, WM2200_LHPF1MIX_INPUT_1_SOURCE);
+WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE);
+
+#define WM2200_MUX(name, ctrl) \
+	SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+
+#define WM2200_MIXER_WIDGETS(name, name_str)	\
+	WM2200_MUX(name_str " Input 1", &name##_in1_mux), \
+	WM2200_MUX(name_str " Input 2", &name##_in2_mux), \
+	WM2200_MUX(name_str " Input 3", &name##_in3_mux), \
+	WM2200_MUX(name_str " Input 4", &name##_in4_mux), \
+	SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
+
+#define WM2200_DSP_WIDGETS(name, name_str) \
+	WM2200_MIXER_WIDGETS(name##L, name_str "L"), \
+	WM2200_MIXER_WIDGETS(name##R, name_str "R"), \
+	WM2200_MUX(name_str " Aux 1", &name##_aux1_mux), \
+	WM2200_MUX(name_str " Aux 2", &name##_aux2_mux), \
+	WM2200_MUX(name_str " Aux 3", &name##_aux3_mux), \
+	WM2200_MUX(name_str " Aux 4", &name##_aux4_mux), \
+	WM2200_MUX(name_str " Aux 5", &name##_aux5_mux), \
+	WM2200_MUX(name_str " Aux 6", &name##_aux6_mux)
+
+#define WM2200_MIXER_INPUT_ROUTES(name)	\
+	{ name, "Tone Generator", "Tone Generator" }, \
+	{ name, "AEC Loopback", "AEC Loopback" }, \
+        { name, "IN1L", "IN1L PGA" }, \
+        { name, "IN1R", "IN1R PGA" }, \
+        { name, "IN2L", "IN2L PGA" }, \
+        { name, "IN2R", "IN2R PGA" }, \
+        { name, "IN3L", "IN3L PGA" }, \
+        { name, "IN3R", "IN3R PGA" }, \
+        { name, "DSP1.1", "DSP1" }, \
+        { name, "DSP1.2", "DSP1" }, \
+        { name, "DSP1.3", "DSP1" }, \
+        { name, "DSP1.4", "DSP1" }, \
+        { name, "DSP1.5", "DSP1" }, \
+        { name, "DSP1.6", "DSP1" }, \
+        { name, "DSP2.1", "DSP2" }, \
+        { name, "DSP2.2", "DSP2" }, \
+        { name, "DSP2.3", "DSP2" }, \
+        { name, "DSP2.4", "DSP2" }, \
+        { name, "DSP2.5", "DSP2" }, \
+        { name, "DSP2.6", "DSP2" }, \
+        { name, "AIF1RX1", "AIF1RX1" }, \
+        { name, "AIF1RX2", "AIF1RX2" }, \
+        { name, "AIF1RX3", "AIF1RX3" }, \
+        { name, "AIF1RX4", "AIF1RX4" }, \
+        { name, "AIF1RX5", "AIF1RX5" }, \
+        { name, "AIF1RX6", "AIF1RX6" }, \
+        { name, "EQL", "EQL" }, \
+        { name, "EQR", "EQR" }, \
+        { name, "LHPF1", "LHPF1" }, \
+        { name, "LHPF2", "LHPF2" }
+
+#define WM2200_MIXER_ROUTES(widget, name) \
+	{ widget, NULL, name " Mixer" },         \
+	{ name " Mixer", NULL, name " Input 1" }, \
+	{ name " Mixer", NULL, name " Input 2" }, \
+	{ name " Mixer", NULL, name " Input 3" }, \
+	{ name " Mixer", NULL, name " Input 4" }, \
+	WM2200_MIXER_INPUT_ROUTES(name " Input 1"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Input 2"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Input 3"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Input 4")
+
+#define WM2200_DSP_AUX_ROUTES(name) \
+	{ name, NULL, name " Aux 1" }, \
+	{ name, NULL, name " Aux 2" }, \
+	{ name, NULL, name " Aux 3" }, \
+	{ name, NULL, name " Aux 4" }, \
+	{ name, NULL, name " Aux 5" }, \
+	{ name, NULL, name " Aux 6" }, \
+	WM2200_MIXER_INPUT_ROUTES(name " Aux 1"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Aux 2"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Aux 3"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Aux 4"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Aux 5"), \
+	WM2200_MIXER_INPUT_ROUTES(name " Aux 6")
+
+static const char *wm2200_aec_loopback_texts[] = {
+	"OUT1L", "OUT1R", "OUT2L", "OUT2R",
+};
+
+static SOC_ENUM_SINGLE_DECL(wm2200_aec_loopback,
+			    WM2200_DAC_AEC_CONTROL_1,
+			    WM2200_AEC_LOOPBACK_SRC_SHIFT,
+			    wm2200_aec_loopback_texts);
+
+static const struct snd_kcontrol_new wm2200_aec_loopback_mux =
+	SOC_DAPM_ENUM("AEC Loopback", wm2200_aec_loopback);
+
+static const struct snd_soc_dapm_widget wm2200_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM2200_CLOCKING_3, WM2200_SYSCLK_ENA_SHIFT, 0,
+		    NULL, 0),
+SND_SOC_DAPM_SUPPLY("CP1", WM2200_DM_CHARGE_PUMP_1, WM2200_CPDM_ENA_SHIFT, 0,
+		    NULL, 0),
+SND_SOC_DAPM_SUPPLY("CP2", WM2200_MIC_CHARGE_PUMP_1, WM2200_CPMIC_ENA_SHIFT, 0,
+		    NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS1", WM2200_MIC_BIAS_CTRL_1, WM2200_MICB1_ENA_SHIFT,
+		    0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", WM2200_MIC_BIAS_CTRL_2, WM2200_MICB2_ENA_SHIFT,
+		    0, NULL, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("AVDD", 20, 0),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_PGA("Tone Generator", WM2200_TONE_GENERATOR_1,
+		 WM2200_TONE_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("IN1L PGA", WM2200_INPUT_ENABLES, WM2200_IN1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN1R PGA", WM2200_INPUT_ENABLES, WM2200_IN1R_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN2L PGA", WM2200_INPUT_ENABLES, WM2200_IN2L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN2R PGA", WM2200_INPUT_ENABLES, WM2200_IN2R_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN3L PGA", WM2200_INPUT_ENABLES, WM2200_IN3L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("IN3R PGA", WM2200_INPUT_ENABLES, WM2200_IN3R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", "Playback", 0,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", "Playback", 1,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", "Playback", 2,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", "Playback", 3,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", "Playback", 4,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", "Playback", 5,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA("EQL", WM2200_EQL_1, WM2200_EQL_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQR", WM2200_EQR_1, WM2200_EQR_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", WM2200_HPLPF1_1, WM2200_LHPF1_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", WM2200_HPLPF2_1, WM2200_LHPF2_ENA_SHIFT, 0,
+		 NULL, 0),
+
+WM_ADSP1("DSP1", 0),
+WM_ADSP1("DSP2", 1),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 1,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 2,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 3,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 4,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 5,
+		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_MUX("AEC Loopback", WM2200_DAC_AEC_CONTROL_1,
+		 WM2200_AEC_LOOPBACK_ENA_SHIFT, 0, &wm2200_aec_loopback_mux),
+
+SND_SOC_DAPM_PGA_S("OUT1L", 0, WM2200_OUTPUT_ENABLES,
+		   WM2200_OUT1L_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("OUT1R", 0, WM2200_OUTPUT_ENABLES,
+		   WM2200_OUT1R_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("EPD_LP", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_LP_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_OUTP_LP", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_OUTP_LP_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_LP", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_RMV_SHRT_LP_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("EPD_LN", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_LN_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_OUTP_LN", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_OUTP_LN_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_LN", 1, WM2200_EAR_PIECE_CTRL_1,
+		   WM2200_EPD_RMV_SHRT_LN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("EPD_RP", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_RP_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_OUTP_RP", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_OUTP_RP_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_RP", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_RMV_SHRT_RP_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("EPD_RN", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_RN_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_OUTP_RN", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_OUTP_RN_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_RN", 1, WM2200_EAR_PIECE_CTRL_2,
+		   WM2200_EPD_RMV_SHRT_RN_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("OUT2L", WM2200_OUTPUT_ENABLES, WM2200_OUT2L_ENA_SHIFT,
+		 0, NULL, 0),
+SND_SOC_DAPM_PGA("OUT2R", WM2200_OUTPUT_ENABLES, WM2200_OUT2R_ENA_SHIFT,
+		 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("EPOUTLN"),
+SND_SOC_DAPM_OUTPUT("EPOUTLP"),
+SND_SOC_DAPM_OUTPUT("EPOUTRN"),
+SND_SOC_DAPM_OUTPUT("EPOUTRP"),
+SND_SOC_DAPM_OUTPUT("SPK"),
+
+WM2200_MIXER_WIDGETS(EQL, "EQL"),
+WM2200_MIXER_WIDGETS(EQR, "EQR"),
+
+WM2200_MIXER_WIDGETS(LHPF1, "LHPF1"),
+WM2200_MIXER_WIDGETS(LHPF2, "LHPF2"),
+
+WM2200_DSP_WIDGETS(DSP1, "DSP1"),
+WM2200_DSP_WIDGETS(DSP2, "DSP2"),
+
+WM2200_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+WM2200_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+WM2200_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+WM2200_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+WM2200_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+WM2200_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+
+WM2200_MIXER_WIDGETS(OUT1L, "OUT1L"),
+WM2200_MIXER_WIDGETS(OUT1R, "OUT1R"),
+WM2200_MIXER_WIDGETS(OUT2L, "OUT2L"),
+WM2200_MIXER_WIDGETS(OUT2R, "OUT2R"),
+};
+
+static const struct snd_soc_dapm_route wm2200_dapm_routes[] = {
+	/* Everything needs SYSCLK but only hook up things on the edge
+	 * of the chip */
+	{ "IN1L", NULL, "SYSCLK" },
+	{ "IN1R", NULL, "SYSCLK" },
+	{ "IN2L", NULL, "SYSCLK" },
+	{ "IN2R", NULL, "SYSCLK" },
+	{ "IN3L", NULL, "SYSCLK" },
+	{ "IN3R", NULL, "SYSCLK" },
+	{ "OUT1L", NULL, "SYSCLK" },
+	{ "OUT1R", NULL, "SYSCLK" },
+	{ "OUT2L", NULL, "SYSCLK" },
+	{ "OUT2R", NULL, "SYSCLK" },
+	{ "AIF1RX1", NULL, "SYSCLK" },
+	{ "AIF1RX2", NULL, "SYSCLK" },
+	{ "AIF1RX3", NULL, "SYSCLK" },
+	{ "AIF1RX4", NULL, "SYSCLK" },
+	{ "AIF1RX5", NULL, "SYSCLK" },
+	{ "AIF1RX6", NULL, "SYSCLK" },
+	{ "AIF1TX1", NULL, "SYSCLK" },
+	{ "AIF1TX2", NULL, "SYSCLK" },
+	{ "AIF1TX3", NULL, "SYSCLK" },
+	{ "AIF1TX4", NULL, "SYSCLK" },
+	{ "AIF1TX5", NULL, "SYSCLK" },
+	{ "AIF1TX6", NULL, "SYSCLK" },
+
+	{ "IN1L", NULL, "AVDD" },
+	{ "IN1R", NULL, "AVDD" },
+	{ "IN2L", NULL, "AVDD" },
+	{ "IN2R", NULL, "AVDD" },
+	{ "IN3L", NULL, "AVDD" },
+	{ "IN3R", NULL, "AVDD" },
+	{ "OUT1L", NULL, "AVDD" },
+	{ "OUT1R", NULL, "AVDD" },
+
+	{ "IN1L PGA", NULL, "IN1L" },
+	{ "IN1R PGA", NULL, "IN1R" },
+	{ "IN2L PGA", NULL, "IN2L" },
+	{ "IN2R PGA", NULL, "IN2R" },
+	{ "IN3L PGA", NULL, "IN3L" },
+	{ "IN3R PGA", NULL, "IN3R" },
+
+	{ "Tone Generator", NULL, "TONE" },
+
+	{ "CP2", NULL, "CPVDD" },
+	{ "MICBIAS1", NULL, "CP2" },
+	{ "MICBIAS2", NULL, "CP2" },
+
+	{ "CP1", NULL, "CPVDD" },
+	{ "EPD_LN", NULL, "CP1" },
+	{ "EPD_LP", NULL, "CP1" },
+	{ "EPD_RN", NULL, "CP1" },
+	{ "EPD_RP", NULL, "CP1" },
+
+	{ "EPD_LP", NULL, "OUT1L" },
+	{ "EPD_OUTP_LP", NULL, "EPD_LP" },
+	{ "EPD_RMV_SHRT_LP", NULL, "EPD_OUTP_LP" },
+	{ "EPOUTLP", NULL, "EPD_RMV_SHRT_LP" },
+
+	{ "EPD_LN", NULL, "OUT1L" },
+	{ "EPD_OUTP_LN", NULL, "EPD_LN" },
+	{ "EPD_RMV_SHRT_LN", NULL, "EPD_OUTP_LN" },
+	{ "EPOUTLN", NULL, "EPD_RMV_SHRT_LN" },
+
+	{ "EPD_RP", NULL, "OUT1R" },
+	{ "EPD_OUTP_RP", NULL, "EPD_RP" },
+	{ "EPD_RMV_SHRT_RP", NULL, "EPD_OUTP_RP" },
+	{ "EPOUTRP", NULL, "EPD_RMV_SHRT_RP" },
+
+	{ "EPD_RN", NULL, "OUT1R" },
+	{ "EPD_OUTP_RN", NULL, "EPD_RN" },
+	{ "EPD_RMV_SHRT_RN", NULL, "EPD_OUTP_RN" },
+	{ "EPOUTRN", NULL, "EPD_RMV_SHRT_RN" },
+
+	{ "SPK", NULL, "OUT2L" },
+	{ "SPK", NULL, "OUT2R" },
+
+	{ "AEC Loopback", "OUT1L", "OUT1L" },
+	{ "AEC Loopback", "OUT1R", "OUT1R" },
+	{ "AEC Loopback", "OUT2L", "OUT2L" },
+	{ "AEC Loopback", "OUT2R", "OUT2R" },
+
+	WM2200_MIXER_ROUTES("DSP1", "DSP1L"),
+	WM2200_MIXER_ROUTES("DSP1", "DSP1R"),
+	WM2200_MIXER_ROUTES("DSP2", "DSP2L"),
+	WM2200_MIXER_ROUTES("DSP2", "DSP2R"),
+
+	WM2200_DSP_AUX_ROUTES("DSP1"),
+	WM2200_DSP_AUX_ROUTES("DSP2"),
+
+	WM2200_MIXER_ROUTES("OUT1L", "OUT1L"),
+	WM2200_MIXER_ROUTES("OUT1R", "OUT1R"),
+	WM2200_MIXER_ROUTES("OUT2L", "OUT2L"),
+	WM2200_MIXER_ROUTES("OUT2R", "OUT2R"),
+
+	WM2200_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+	WM2200_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+	WM2200_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+	WM2200_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+	WM2200_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+	WM2200_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+
+	WM2200_MIXER_ROUTES("EQL", "EQL"),
+	WM2200_MIXER_ROUTES("EQR", "EQR"),
+
+	WM2200_MIXER_ROUTES("LHPF1", "LHPF1"),
+	WM2200_MIXER_ROUTES("LHPF2", "LHPF2"),
+};
+
+static int wm2200_probe(struct snd_soc_component *component)
+{
+	struct wm2200_priv *wm2200 = snd_soc_component_get_drvdata(component);
+
+	wm2200->component = component;
+
+	return 0;
+}
+
+static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	int lrclk, bclk, fmt_val;
+
+	lrclk = 0;
+	bclk = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		fmt_val = 0;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		fmt_val = 2;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported DAI format %d\n",
+			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		lrclk |= WM2200_AIF1TX_LRCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		bclk |= WM2200_AIF1_BCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		lrclk |= WM2200_AIF1TX_LRCLK_MSTR;
+		bclk |= WM2200_AIF1_BCLK_MSTR;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported master mode %d\n",
+			fmt & SND_SOC_DAIFMT_MASTER_MASK);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		bclk |= WM2200_AIF1_BCLK_INV;
+		lrclk |= WM2200_AIF1TX_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		bclk |= WM2200_AIF1_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		lrclk |= WM2200_AIF1TX_LRCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_1, WM2200_AIF1_BCLK_MSTR |
+			    WM2200_AIF1_BCLK_INV, bclk);
+	snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_2,
+			    WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV,
+			    lrclk);
+	snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_3,
+			    WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV,
+			    lrclk);
+	snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_5,
+			    WM2200_AIF1_FMT_MASK, fmt_val);
+
+	return 0;
+}
+
+static int wm2200_sr_code[] = {
+	0,
+	12000,
+	24000,
+	48000,
+	96000,
+	192000,
+	384000,
+	768000,
+	0,
+	11025,
+	22050,
+	44100,
+	88200,
+	176400,
+	352800,
+	705600,
+	4000,
+	8000,
+	16000,
+	32000,
+	64000,
+	128000,
+	256000,
+	512000,
+};
+
+#define WM2200_NUM_BCLK_RATES 12
+
+static int wm2200_bclk_rates_dat[WM2200_NUM_BCLK_RATES] = {
+	6144000,
+	3072000,
+	2048000,
+	1536000,
+	768000,
+	512000,
+	384000,
+	256000,
+	192000,
+	128000,
+	96000,
+	64000,
+};	
+
+static int wm2200_bclk_rates_cd[WM2200_NUM_BCLK_RATES] = {
+	5644800,
+	3763200,
+	2882400,
+	1881600,
+	1411200,
+	705600,
+	470400,
+	352800,
+	176400,
+	117600,
+	88200,
+	58800,
+};
+
+static int wm2200_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm2200_priv *wm2200 = snd_soc_component_get_drvdata(component);
+	int i, bclk, lrclk, wl, fl, sr_code;
+	int *bclk_rates;
+
+	/* Data sizes if not using TDM */
+	wl = params_width(params);
+	if (wl < 0)
+		return wl;
+	fl = snd_soc_params_to_frame_size(params);
+	if (fl < 0)
+		return fl;
+
+	dev_dbg(component->dev, "Word length %d bits, frame length %d bits\n",
+		wl, fl);
+
+	/* Target BCLK rate */
+	bclk = snd_soc_params_to_bclk(params);
+	if (bclk < 0)
+		return bclk;
+
+	if (!wm2200->sysclk) {
+		dev_err(component->dev, "SYSCLK has no rate set\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm2200_sr_code); i++)
+		if (wm2200_sr_code[i] == params_rate(params))
+			break;
+	if (i == ARRAY_SIZE(wm2200_sr_code)) {
+		dev_err(component->dev, "Unsupported sample rate: %dHz\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	sr_code = i;
+
+	dev_dbg(component->dev, "Target BCLK is %dHz, using %dHz SYSCLK\n",
+		bclk, wm2200->sysclk);
+
+	if (wm2200->sysclk % 4000)
+		bclk_rates = wm2200_bclk_rates_cd;
+	else
+		bclk_rates = wm2200_bclk_rates_dat;
+
+	for (i = 0; i < WM2200_NUM_BCLK_RATES; i++)
+		if (bclk_rates[i] >= bclk && (bclk_rates[i] % bclk == 0))
+			break;
+	if (i == WM2200_NUM_BCLK_RATES) {
+		dev_err(component->dev,
+			"No valid BCLK for %dHz found from %dHz SYSCLK\n",
+			bclk, wm2200->sysclk);
+		return -EINVAL;
+	}
+
+	bclk = i;
+	dev_dbg(component->dev, "Setting %dHz BCLK\n", bclk_rates[bclk]);
+	snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_1,
+			    WM2200_AIF1_BCLK_DIV_MASK, bclk);
+
+	lrclk = bclk_rates[bclk] / params_rate(params);
+	dev_dbg(component->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+	    wm2200->symmetric_rates)
+		snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_7,
+				    WM2200_AIF1RX_BCPF_MASK, lrclk);
+	else
+		snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_6,
+				    WM2200_AIF1TX_BCPF_MASK, lrclk);
+
+	i = (wl << WM2200_AIF1TX_WL_SHIFT) | wl;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_9,
+				    WM2200_AIF1RX_WL_MASK |
+				    WM2200_AIF1RX_SLOT_LEN_MASK, i);
+	else
+		snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_8,
+				    WM2200_AIF1TX_WL_MASK |
+				    WM2200_AIF1TX_SLOT_LEN_MASK, i);
+
+	snd_soc_component_update_bits(component, WM2200_CLOCKING_4,
+			    WM2200_SAMPLE_RATE_1_MASK, sr_code);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops wm2200_dai_ops = {
+	.set_fmt = wm2200_set_fmt,
+	.hw_params = wm2200_hw_params,
+};
+
+static int wm2200_set_sysclk(struct snd_soc_component *component, int clk_id,
+			     int source, unsigned int freq, int dir)
+{
+	struct wm2200_priv *wm2200 = snd_soc_component_get_drvdata(component);
+	int fval;
+
+	switch (clk_id) {
+	case WM2200_CLK_SYSCLK:
+		break;
+
+	default:
+		dev_err(component->dev, "Unknown clock %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	switch (source) {
+	case WM2200_CLKSRC_MCLK1:
+	case WM2200_CLKSRC_MCLK2:
+	case WM2200_CLKSRC_FLL:
+	case WM2200_CLKSRC_BCLK1:
+		break;
+	default:
+		dev_err(component->dev, "Invalid source %d\n", source);
+		return -EINVAL;
+	}
+
+	switch (freq) {
+	case 22579200:
+	case 24576000:
+		fval = 2;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock rate: %d\n", freq);
+		return -EINVAL;
+	}
+
+	/* TODO: Check if MCLKs are in use and enable/disable pulls to
+	 * match.
+	 */
+
+	snd_soc_component_update_bits(component, WM2200_CLOCKING_3, WM2200_SYSCLK_FREQ_MASK |
+			    WM2200_SYSCLK_SRC_MASK,
+			    fval << WM2200_SYSCLK_FREQ_SHIFT | source);
+
+	wm2200->sysclk = freq;
+
+	return 0;
+}
+
+struct _fll_div {
+	u16 fll_fratio;
+	u16 fll_outdiv;
+	u16 fll_refclk_div;
+	u16 n;
+	u16 theta;
+	u16 lambda;
+};
+
+static struct {
+	unsigned int min;
+	unsigned int max;
+	u16 fll_fratio;
+	int ratio;
+} fll_fratios[] = {
+	{       0,    64000, 4, 16 },
+	{   64000,   128000, 3,  8 },
+	{  128000,   256000, 2,  4 },
+	{  256000,  1000000, 1,  2 },
+	{ 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+		       unsigned int Fout)
+{
+	unsigned int target;
+	unsigned int div;
+	unsigned int fratio, gcd_fll;
+	int i;
+
+	/* Fref must be <=13.5MHz */
+	div = 1;
+	fll_div->fll_refclk_div = 0;
+	while ((Fref / div) > 13500000) {
+		div *= 2;
+		fll_div->fll_refclk_div++;
+
+		if (div > 8) {
+			pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+			       Fref);
+			return -EINVAL;
+		}
+	}
+
+	pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+	/* Apply the division for our remaining calculations */
+	Fref /= div;
+
+	/* Fvco should be 90-100MHz; don't check the upper bound */
+	div = 2;
+	while (Fout * div < 90000000) {
+		div++;
+		if (div > 64) {
+			pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+			       Fout);
+			return -EINVAL;
+		}
+	}
+	target = Fout * div;
+	fll_div->fll_outdiv = div - 1;
+
+	pr_debug("FLL Fvco=%dHz\n", target);
+
+	/* Find an appropraite FLL_FRATIO and factor it out of the target */
+	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+			fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+			fratio = fll_fratios[i].ratio;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(fll_fratios)) {
+		pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+		return -EINVAL;
+	}
+
+	fll_div->n = target / (fratio * Fref);
+
+	if (target % Fref == 0) {
+		fll_div->theta = 0;
+		fll_div->lambda = 0;
+	} else {
+		gcd_fll = gcd(target, fratio * Fref);
+
+		fll_div->theta = (target - (fll_div->n * fratio * Fref))
+			/ gcd_fll;
+		fll_div->lambda = (fratio * Fref) / gcd_fll;
+	}
+
+	pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+		 fll_div->n, fll_div->theta, fll_div->lambda);
+	pr_debug("FLL_FRATIO=%x(%d) FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+		 fll_div->fll_fratio, fratio, fll_div->fll_outdiv,
+		 fll_div->fll_refclk_div);
+
+	return 0;
+}
+
+static int wm2200_set_fll(struct snd_soc_component *component, int fll_id, int source,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct i2c_client *i2c = to_i2c_client(component->dev);
+	struct wm2200_priv *wm2200 = snd_soc_component_get_drvdata(component);
+	struct _fll_div factors;
+	int ret, i, timeout;
+	unsigned long time_left;
+
+	if (!Fout) {
+		dev_dbg(component->dev, "FLL disabled");
+
+		if (wm2200->fll_fout)
+			pm_runtime_put(component->dev);
+
+		wm2200->fll_fout = 0;
+		snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_1,
+				    WM2200_FLL_ENA, 0);
+		return 0;
+	}
+
+	switch (source) {
+	case WM2200_FLL_SRC_MCLK1:
+	case WM2200_FLL_SRC_MCLK2:
+	case WM2200_FLL_SRC_BCLK:
+		break;
+	default:
+		dev_err(component->dev, "Invalid FLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = fll_factors(&factors, Fref, Fout);
+	if (ret < 0)
+		return ret;
+
+	/* Disable the FLL while we reconfigure */
+	snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_1, WM2200_FLL_ENA, 0);
+
+	snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_2,
+			    WM2200_FLL_OUTDIV_MASK | WM2200_FLL_FRATIO_MASK,
+			    (factors.fll_outdiv << WM2200_FLL_OUTDIV_SHIFT) |
+			    factors.fll_fratio);
+	if (factors.theta) {
+		snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_3,
+				    WM2200_FLL_FRACN_ENA,
+				    WM2200_FLL_FRACN_ENA);
+		snd_soc_component_update_bits(component, WM2200_FLL_EFS_2,
+				    WM2200_FLL_EFS_ENA,
+				    WM2200_FLL_EFS_ENA);
+	} else {
+		snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_3,
+				    WM2200_FLL_FRACN_ENA, 0);
+		snd_soc_component_update_bits(component, WM2200_FLL_EFS_2,
+				    WM2200_FLL_EFS_ENA, 0);
+	}
+
+	snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_4, WM2200_FLL_THETA_MASK,
+			    factors.theta);
+	snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_6, WM2200_FLL_N_MASK,
+			    factors.n);
+	snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_7,
+			    WM2200_FLL_CLK_REF_DIV_MASK |
+			    WM2200_FLL_CLK_REF_SRC_MASK,
+			    (factors.fll_refclk_div
+			     << WM2200_FLL_CLK_REF_DIV_SHIFT) | source);
+	snd_soc_component_update_bits(component, WM2200_FLL_EFS_1,
+			    WM2200_FLL_LAMBDA_MASK, factors.lambda);
+
+	/* Clear any pending completions */
+	try_wait_for_completion(&wm2200->fll_lock);
+
+	pm_runtime_get_sync(component->dev);
+
+	snd_soc_component_update_bits(component, WM2200_FLL_CONTROL_1,
+			    WM2200_FLL_ENA, WM2200_FLL_ENA);
+
+	if (i2c->irq)
+		timeout = 2;
+	else
+		timeout = 50;
+
+	snd_soc_component_update_bits(component, WM2200_CLOCKING_3, WM2200_SYSCLK_ENA,
+			    WM2200_SYSCLK_ENA);
+
+	/* Poll for the lock; will use the interrupt to exit quickly */
+	for (i = 0; i < timeout; i++) {
+		if (i2c->irq) {
+			time_left = wait_for_completion_timeout(
+							&wm2200->fll_lock,
+							msecs_to_jiffies(25));
+			if (time_left > 0)
+				break;
+		} else {
+			msleep(1);
+		}
+
+		ret = snd_soc_component_read32(component,
+				   WM2200_INTERRUPT_RAW_STATUS_2);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to read FLL status: %d\n",
+				ret);
+			continue;
+		}
+		if (ret & WM2200_FLL_LOCK_STS)
+			break;
+	}
+	if (i == timeout) {
+		dev_err(component->dev, "FLL lock timed out\n");
+		pm_runtime_put(component->dev);
+		return -ETIMEDOUT;
+	}
+
+	wm2200->fll_src = source;
+	wm2200->fll_fref = Fref;
+	wm2200->fll_fout = Fout;
+
+	dev_dbg(component->dev, "FLL running %dHz->%dHz\n", Fref, Fout);
+
+	return 0;
+}
+
+static int wm2200_dai_probe(struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm2200_priv *wm2200 = snd_soc_component_get_drvdata(component);
+	unsigned int val = 0;
+	int ret;
+
+	ret = snd_soc_component_read32(component, WM2200_GPIO_CTRL_1);
+	if (ret >= 0) {
+		if ((ret & WM2200_GP1_FN_MASK) != 0) {
+			wm2200->symmetric_rates = true;
+			val = WM2200_AIF1TX_LRCLK_SRC;
+		}
+	} else {
+		dev_err(component->dev, "Failed to read GPIO 1 config: %d\n", ret);
+	}
+
+	snd_soc_component_update_bits(component, WM2200_AUDIO_IF_1_2,
+			    WM2200_AIF1TX_LRCLK_SRC, val);
+
+	return 0;
+}
+
+#define WM2200_RATES SNDRV_PCM_RATE_8000_48000
+
+#define WM2200_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm2200_dai = {
+	.name = "wm2200",
+	.probe = wm2200_dai_probe,
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM2200_RATES,
+		.formats = WM2200_FORMATS,
+	},
+	.capture = {
+		 .stream_name = "Capture",
+		 .channels_min = 2,
+		 .channels_max = 2,
+		 .rates = WM2200_RATES,
+		 .formats = WM2200_FORMATS,
+	 },
+	.ops = &wm2200_dai_ops,
+};
+
+static const struct snd_soc_component_driver soc_component_wm2200 = {
+	.probe			= wm2200_probe,
+	.set_sysclk		= wm2200_set_sysclk,
+	.set_pll		= wm2200_set_fll,
+	.controls		= wm2200_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm2200_snd_controls),
+	.dapm_widgets		= wm2200_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm2200_dapm_widgets),
+	.dapm_routes		= wm2200_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm2200_dapm_routes),
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static irqreturn_t wm2200_irq(int irq, void *data)
+{
+	struct wm2200_priv *wm2200 = data;
+	unsigned int val, mask;
+	int ret;
+
+	ret = regmap_read(wm2200->regmap, WM2200_INTERRUPT_STATUS_2, &val);
+	if (ret != 0) {
+		dev_err(wm2200->dev, "Failed to read IRQ status: %d\n", ret);
+		return IRQ_NONE;
+	}
+
+	ret = regmap_read(wm2200->regmap, WM2200_INTERRUPT_STATUS_2_MASK,
+			   &mask);
+	if (ret != 0) {
+		dev_warn(wm2200->dev, "Failed to read IRQ mask: %d\n", ret);
+		mask = 0;
+	}
+
+	val &= ~mask;
+
+	if (val & WM2200_FLL_LOCK_EINT) {
+		dev_dbg(wm2200->dev, "FLL locked\n");
+		complete(&wm2200->fll_lock);
+	}
+
+	if (val) {
+		regmap_write(wm2200->regmap, WM2200_INTERRUPT_STATUS_2, val);
+		
+		return IRQ_HANDLED;
+	} else {
+		return IRQ_NONE;
+	}
+}
+
+static const struct regmap_config wm2200_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+
+	.max_register = WM2200_MAX_REGISTER + (ARRAY_SIZE(wm2200_ranges) *
+					       WM2200_DSP_SPACING),
+	.reg_defaults = wm2200_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm2200_reg_defaults),
+	.volatile_reg = wm2200_volatile_register,
+	.readable_reg = wm2200_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.ranges = wm2200_ranges,
+	.num_ranges = ARRAY_SIZE(wm2200_ranges),
+};
+
+static const unsigned int wm2200_dig_vu[] = {
+	WM2200_DAC_DIGITAL_VOLUME_1L,
+	WM2200_DAC_DIGITAL_VOLUME_1R,
+	WM2200_DAC_DIGITAL_VOLUME_2L,
+	WM2200_DAC_DIGITAL_VOLUME_2R,
+	WM2200_ADC_DIGITAL_VOLUME_1L,
+	WM2200_ADC_DIGITAL_VOLUME_1R,
+	WM2200_ADC_DIGITAL_VOLUME_2L,
+	WM2200_ADC_DIGITAL_VOLUME_2R,
+	WM2200_ADC_DIGITAL_VOLUME_3L,
+	WM2200_ADC_DIGITAL_VOLUME_3R,
+};
+
+static const unsigned int wm2200_mic_ctrl_reg[] = {
+	WM2200_IN1L_CONTROL,
+	WM2200_IN2L_CONTROL,
+	WM2200_IN3L_CONTROL,
+};
+
+static int wm2200_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm2200_pdata *pdata = dev_get_platdata(&i2c->dev);
+	struct wm2200_priv *wm2200;
+	unsigned int reg;
+	int ret, i;
+	int val;
+
+	wm2200 = devm_kzalloc(&i2c->dev, sizeof(struct wm2200_priv),
+			      GFP_KERNEL);
+	if (wm2200 == NULL)
+		return -ENOMEM;
+
+	wm2200->dev = &i2c->dev;
+	init_completion(&wm2200->fll_lock);
+
+	wm2200->regmap = devm_regmap_init_i2c(i2c, &wm2200_regmap);
+	if (IS_ERR(wm2200->regmap)) {
+		ret = PTR_ERR(wm2200->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	for (i = 0; i < 2; i++) {
+		wm2200->dsp[i].type = WMFW_ADSP1;
+		wm2200->dsp[i].part = "wm2200";
+		wm2200->dsp[i].num = i + 1;
+		wm2200->dsp[i].dev = &i2c->dev;
+		wm2200->dsp[i].regmap = wm2200->regmap;
+		wm2200->dsp[i].sysclk_reg = WM2200_CLOCKING_3;
+		wm2200->dsp[i].sysclk_mask = WM2200_SYSCLK_FREQ_MASK;
+		wm2200->dsp[i].sysclk_shift =  WM2200_SYSCLK_FREQ_SHIFT;
+	}
+
+	wm2200->dsp[0].base = WM2200_DSP1_CONTROL_1;
+	wm2200->dsp[0].mem = wm2200_dsp1_regions;
+	wm2200->dsp[0].num_mems = ARRAY_SIZE(wm2200_dsp1_regions);
+
+	wm2200->dsp[1].base = WM2200_DSP2_CONTROL_1;
+	wm2200->dsp[1].mem = wm2200_dsp2_regions;
+	wm2200->dsp[1].num_mems = ARRAY_SIZE(wm2200_dsp2_regions);
+
+	for (i = 0; i < ARRAY_SIZE(wm2200->dsp); i++)
+		wm_adsp1_init(&wm2200->dsp[i]);
+
+	if (pdata)
+		wm2200->pdata = *pdata;
+
+	i2c_set_clientdata(i2c, wm2200);
+
+	for (i = 0; i < ARRAY_SIZE(wm2200->core_supplies); i++)
+		wm2200->core_supplies[i].supply = wm2200_core_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev,
+				      ARRAY_SIZE(wm2200->core_supplies),
+				      wm2200->core_supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request core supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies),
+				    wm2200->core_supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable core supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (wm2200->pdata.ldo_ena) {
+		ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.ldo_ena,
+					    GPIOF_OUT_INIT_HIGH,
+					    "WM2200 LDOENA");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n",
+				wm2200->pdata.ldo_ena, ret);
+			goto err_enable;
+		}
+		msleep(2);
+	}
+
+	if (wm2200->pdata.reset) {
+		ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.reset,
+					    GPIOF_OUT_INIT_HIGH,
+					    "WM2200 /RESET");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n",
+				wm2200->pdata.reset, ret);
+			goto err_ldo;
+		}
+	}
+
+	ret = regmap_read(wm2200->regmap, WM2200_SOFTWARE_RESET, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
+		goto err_reset;
+	}
+	switch (reg) {
+	case 0x2200:
+		break;
+
+	default:
+		dev_err(&i2c->dev, "Device is not a WM2200, ID is %x\n", reg);
+		ret = -EINVAL;
+		goto err_reset;
+	}
+
+	ret = regmap_read(wm2200->regmap, WM2200_DEVICE_REVISION, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read revision register\n");
+		goto err_reset;
+	}
+
+	wm2200->rev = reg & WM2200_DEVICE_REVISION_MASK;
+
+	dev_info(&i2c->dev, "revision %c\n", wm2200->rev + 'A');
+
+	switch (wm2200->rev) {
+	case 0:
+	case 1:
+		ret = regmap_register_patch(wm2200->regmap, wm2200_reva_patch,
+					    ARRAY_SIZE(wm2200_reva_patch));
+		if (ret != 0) {
+			dev_err(&i2c->dev, "Failed to register patch: %d\n",
+				ret);
+		}
+		break;
+	default:
+		break;
+	}
+
+	ret = wm2200_reset(wm2200);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to issue reset\n");
+		goto err_reset;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm2200->pdata.gpio_defaults); i++) {
+		if (!wm2200->pdata.gpio_defaults[i])
+			continue;
+
+		regmap_write(wm2200->regmap, WM2200_GPIO_CTRL_1 + i,
+			     wm2200->pdata.gpio_defaults[i]);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm2200_dig_vu); i++)
+		regmap_update_bits(wm2200->regmap, wm2200_dig_vu[i],
+				   WM2200_OUT_VU, WM2200_OUT_VU);
+
+	/* Assign slots 1-6 to channels 1-6 for both TX and RX */
+	for (i = 0; i < 6; i++) {
+		regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_10 + i, i);
+		regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_16 + i, i);
+	}
+
+	for (i = 0; i < WM2200_MAX_MICBIAS; i++) {
+		if (!wm2200->pdata.micbias[i].mb_lvl &&
+		    !wm2200->pdata.micbias[i].bypass)
+			continue;
+
+		/* Apply default for bypass mode */
+		if (!wm2200->pdata.micbias[i].mb_lvl)
+			wm2200->pdata.micbias[i].mb_lvl
+					= WM2200_MBIAS_LVL_1V5;
+
+		val = (wm2200->pdata.micbias[i].mb_lvl -1)
+					<< WM2200_MICB1_LVL_SHIFT;
+
+		if (wm2200->pdata.micbias[i].discharge)
+			val |= WM2200_MICB1_DISCH;
+
+		if (wm2200->pdata.micbias[i].fast_start)
+			val |= WM2200_MICB1_RATE;
+
+		if (wm2200->pdata.micbias[i].bypass)
+			val |= WM2200_MICB1_MODE;
+
+		regmap_update_bits(wm2200->regmap,
+				   WM2200_MIC_BIAS_CTRL_1 + i,
+				   WM2200_MICB1_LVL_MASK |
+				   WM2200_MICB1_DISCH |
+				   WM2200_MICB1_MODE |
+				   WM2200_MICB1_RATE, val);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm2200->pdata.in_mode); i++) {
+		regmap_update_bits(wm2200->regmap, wm2200_mic_ctrl_reg[i],
+				   WM2200_IN1_MODE_MASK |
+				   WM2200_IN1_DMIC_SUP_MASK,
+				   (wm2200->pdata.in_mode[i] <<
+				    WM2200_IN1_MODE_SHIFT) |
+				   (wm2200->pdata.dmic_sup[i] <<
+				    WM2200_IN1_DMIC_SUP_SHIFT));
+	}
+
+	if (i2c->irq) {
+		ret = request_threaded_irq(i2c->irq, NULL, wm2200_irq,
+					   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					   "wm2200", wm2200);
+		if (ret == 0)
+			regmap_update_bits(wm2200->regmap,
+					   WM2200_INTERRUPT_STATUS_2_MASK,
+					   WM2200_FLL_LOCK_EINT, 0);
+		else
+			dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
+				i2c->irq, ret);
+	}
+
+	pm_runtime_set_active(&i2c->dev);
+	pm_runtime_enable(&i2c->dev);
+	pm_request_idle(&i2c->dev);
+
+	ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_wm2200,
+				     &wm2200_dai, 1);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+		goto err_pm_runtime;
+	}
+
+	return 0;
+
+err_pm_runtime:
+	pm_runtime_disable(&i2c->dev);
+err_reset:
+	if (wm2200->pdata.reset)
+		gpio_set_value_cansleep(wm2200->pdata.reset, 0);
+err_ldo:
+	if (wm2200->pdata.ldo_ena)
+		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
+			       wm2200->core_supplies);
+	return ret;
+}
+
+static int wm2200_i2c_remove(struct i2c_client *i2c)
+{
+	struct wm2200_priv *wm2200 = i2c_get_clientdata(i2c);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, wm2200);
+	if (wm2200->pdata.reset)
+		gpio_set_value_cansleep(wm2200->pdata.reset, 0);
+	if (wm2200->pdata.ldo_ena)
+		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm2200_runtime_suspend(struct device *dev)
+{
+	struct wm2200_priv *wm2200 = dev_get_drvdata(dev);
+
+	regcache_cache_only(wm2200->regmap, true);
+	regcache_mark_dirty(wm2200->regmap);
+	if (wm2200->pdata.ldo_ena)
+		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
+	regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
+			       wm2200->core_supplies);
+
+	return 0;
+}
+
+static int wm2200_runtime_resume(struct device *dev)
+{
+	struct wm2200_priv *wm2200 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies),
+				    wm2200->core_supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (wm2200->pdata.ldo_ena) {
+		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 1);
+		msleep(2);
+	}
+
+	regcache_cache_only(wm2200->regmap, false);
+	regcache_sync(wm2200->regmap);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops wm2200_pm = {
+	SET_RUNTIME_PM_OPS(wm2200_runtime_suspend, wm2200_runtime_resume,
+			   NULL)
+};
+
+static const struct i2c_device_id wm2200_i2c_id[] = {
+	{ "wm2200", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm2200_i2c_id);
+
+static struct i2c_driver wm2200_i2c_driver = {
+	.driver = {
+		.name = "wm2200",
+		.pm = &wm2200_pm,
+	},
+	.probe =    wm2200_i2c_probe,
+	.remove =   wm2200_i2c_remove,
+	.id_table = wm2200_i2c_id,
+};
+
+module_i2c_driver(wm2200_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM2200 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm2200.h b/sound/soc/codecs/wm2200.h
new file mode 100644
index 0000000..5d719d6
--- /dev/null
+++ b/sound/soc/codecs/wm2200.h
@@ -0,0 +1,3674 @@
+/*
+ * wm2200.h - WM2200 audio codec interface
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _WM2200_H
+#define _WM2200_H
+
+#define WM2200_CLK_SYSCLK 1
+
+#define WM2200_CLKSRC_MCLK1  0
+#define WM2200_CLKSRC_MCLK2  1
+#define WM2200_CLKSRC_FLL    4
+#define WM2200_CLKSRC_BCLK1  8
+
+#define WM2200_FLL_SRC_MCLK1 0
+#define WM2200_FLL_SRC_MCLK2 1
+#define WM2200_FLL_SRC_BCLK  2
+
+/*
+ * Register values.
+ */
+#define WM2200_SOFTWARE_RESET                   0x00
+#define WM2200_DEVICE_REVISION                  0x01
+#define WM2200_TONE_GENERATOR_1                 0x0B
+#define WM2200_CLOCKING_3                       0x102
+#define WM2200_CLOCKING_4                       0x103
+#define WM2200_FLL_CONTROL_1                    0x111
+#define WM2200_FLL_CONTROL_2                    0x112
+#define WM2200_FLL_CONTROL_3                    0x113
+#define WM2200_FLL_CONTROL_4                    0x114
+#define WM2200_FLL_CONTROL_6                    0x116
+#define WM2200_FLL_CONTROL_7                    0x117
+#define WM2200_FLL_EFS_1                        0x119
+#define WM2200_FLL_EFS_2                        0x11A
+#define WM2200_MIC_CHARGE_PUMP_1                0x200
+#define WM2200_MIC_CHARGE_PUMP_2                0x201
+#define WM2200_DM_CHARGE_PUMP_1                 0x202
+#define WM2200_MIC_BIAS_CTRL_1                  0x20C
+#define WM2200_MIC_BIAS_CTRL_2                  0x20D
+#define WM2200_EAR_PIECE_CTRL_1                 0x20F
+#define WM2200_EAR_PIECE_CTRL_2                 0x210
+#define WM2200_INPUT_ENABLES                    0x301
+#define WM2200_IN1L_CONTROL                     0x302
+#define WM2200_IN1R_CONTROL                     0x303
+#define WM2200_IN2L_CONTROL                     0x304
+#define WM2200_IN2R_CONTROL                     0x305
+#define WM2200_IN3L_CONTROL                     0x306
+#define WM2200_IN3R_CONTROL                     0x307
+#define WM2200_RXANC_SRC                        0x30A
+#define WM2200_INPUT_VOLUME_RAMP                0x30B
+#define WM2200_ADC_DIGITAL_VOLUME_1L            0x30C
+#define WM2200_ADC_DIGITAL_VOLUME_1R            0x30D
+#define WM2200_ADC_DIGITAL_VOLUME_2L            0x30E
+#define WM2200_ADC_DIGITAL_VOLUME_2R            0x30F
+#define WM2200_ADC_DIGITAL_VOLUME_3L            0x310
+#define WM2200_ADC_DIGITAL_VOLUME_3R            0x311
+#define WM2200_OUTPUT_ENABLES                   0x400
+#define WM2200_DAC_VOLUME_LIMIT_1L              0x401
+#define WM2200_DAC_VOLUME_LIMIT_1R              0x402
+#define WM2200_DAC_VOLUME_LIMIT_2L              0x403
+#define WM2200_DAC_VOLUME_LIMIT_2R              0x404
+#define WM2200_DAC_AEC_CONTROL_1                0x409
+#define WM2200_OUTPUT_VOLUME_RAMP               0x40A
+#define WM2200_DAC_DIGITAL_VOLUME_1L            0x40B
+#define WM2200_DAC_DIGITAL_VOLUME_1R            0x40C
+#define WM2200_DAC_DIGITAL_VOLUME_2L            0x40D
+#define WM2200_DAC_DIGITAL_VOLUME_2R            0x40E
+#define WM2200_PDM_1                            0x417
+#define WM2200_PDM_2                            0x418
+#define WM2200_AUDIO_IF_1_1                     0x500
+#define WM2200_AUDIO_IF_1_2                     0x501
+#define WM2200_AUDIO_IF_1_3                     0x502
+#define WM2200_AUDIO_IF_1_4                     0x503
+#define WM2200_AUDIO_IF_1_5                     0x504
+#define WM2200_AUDIO_IF_1_6                     0x505
+#define WM2200_AUDIO_IF_1_7                     0x506
+#define WM2200_AUDIO_IF_1_8                     0x507
+#define WM2200_AUDIO_IF_1_9                     0x508
+#define WM2200_AUDIO_IF_1_10                    0x509
+#define WM2200_AUDIO_IF_1_11                    0x50A
+#define WM2200_AUDIO_IF_1_12                    0x50B
+#define WM2200_AUDIO_IF_1_13                    0x50C
+#define WM2200_AUDIO_IF_1_14                    0x50D
+#define WM2200_AUDIO_IF_1_15                    0x50E
+#define WM2200_AUDIO_IF_1_16                    0x50F
+#define WM2200_AUDIO_IF_1_17                    0x510
+#define WM2200_AUDIO_IF_1_18                    0x511
+#define WM2200_AUDIO_IF_1_19                    0x512
+#define WM2200_AUDIO_IF_1_20                    0x513
+#define WM2200_AUDIO_IF_1_21                    0x514
+#define WM2200_AUDIO_IF_1_22                    0x515
+#define WM2200_OUT1LMIX_INPUT_1_SOURCE          0x600
+#define WM2200_OUT1LMIX_INPUT_1_VOLUME          0x601
+#define WM2200_OUT1LMIX_INPUT_2_SOURCE          0x602
+#define WM2200_OUT1LMIX_INPUT_2_VOLUME          0x603
+#define WM2200_OUT1LMIX_INPUT_3_SOURCE          0x604
+#define WM2200_OUT1LMIX_INPUT_3_VOLUME          0x605
+#define WM2200_OUT1LMIX_INPUT_4_SOURCE          0x606
+#define WM2200_OUT1LMIX_INPUT_4_VOLUME          0x607
+#define WM2200_OUT1RMIX_INPUT_1_SOURCE          0x608
+#define WM2200_OUT1RMIX_INPUT_1_VOLUME          0x609
+#define WM2200_OUT1RMIX_INPUT_2_SOURCE          0x60A
+#define WM2200_OUT1RMIX_INPUT_2_VOLUME          0x60B
+#define WM2200_OUT1RMIX_INPUT_3_SOURCE          0x60C
+#define WM2200_OUT1RMIX_INPUT_3_VOLUME          0x60D
+#define WM2200_OUT1RMIX_INPUT_4_SOURCE          0x60E
+#define WM2200_OUT1RMIX_INPUT_4_VOLUME          0x60F
+#define WM2200_OUT2LMIX_INPUT_1_SOURCE          0x610
+#define WM2200_OUT2LMIX_INPUT_1_VOLUME          0x611
+#define WM2200_OUT2LMIX_INPUT_2_SOURCE          0x612
+#define WM2200_OUT2LMIX_INPUT_2_VOLUME          0x613
+#define WM2200_OUT2LMIX_INPUT_3_SOURCE          0x614
+#define WM2200_OUT2LMIX_INPUT_3_VOLUME          0x615
+#define WM2200_OUT2LMIX_INPUT_4_SOURCE          0x616
+#define WM2200_OUT2LMIX_INPUT_4_VOLUME          0x617
+#define WM2200_OUT2RMIX_INPUT_1_SOURCE          0x618
+#define WM2200_OUT2RMIX_INPUT_1_VOLUME          0x619
+#define WM2200_OUT2RMIX_INPUT_2_SOURCE          0x61A
+#define WM2200_OUT2RMIX_INPUT_2_VOLUME          0x61B
+#define WM2200_OUT2RMIX_INPUT_3_SOURCE          0x61C
+#define WM2200_OUT2RMIX_INPUT_3_VOLUME          0x61D
+#define WM2200_OUT2RMIX_INPUT_4_SOURCE          0x61E
+#define WM2200_OUT2RMIX_INPUT_4_VOLUME          0x61F
+#define WM2200_AIF1TX1MIX_INPUT_1_SOURCE        0x620
+#define WM2200_AIF1TX1MIX_INPUT_1_VOLUME        0x621
+#define WM2200_AIF1TX1MIX_INPUT_2_SOURCE        0x622
+#define WM2200_AIF1TX1MIX_INPUT_2_VOLUME        0x623
+#define WM2200_AIF1TX1MIX_INPUT_3_SOURCE        0x624
+#define WM2200_AIF1TX1MIX_INPUT_3_VOLUME        0x625
+#define WM2200_AIF1TX1MIX_INPUT_4_SOURCE        0x626
+#define WM2200_AIF1TX1MIX_INPUT_4_VOLUME        0x627
+#define WM2200_AIF1TX2MIX_INPUT_1_SOURCE        0x628
+#define WM2200_AIF1TX2MIX_INPUT_1_VOLUME        0x629
+#define WM2200_AIF1TX2MIX_INPUT_2_SOURCE        0x62A
+#define WM2200_AIF1TX2MIX_INPUT_2_VOLUME        0x62B
+#define WM2200_AIF1TX2MIX_INPUT_3_SOURCE        0x62C
+#define WM2200_AIF1TX2MIX_INPUT_3_VOLUME        0x62D
+#define WM2200_AIF1TX2MIX_INPUT_4_SOURCE        0x62E
+#define WM2200_AIF1TX2MIX_INPUT_4_VOLUME        0x62F
+#define WM2200_AIF1TX3MIX_INPUT_1_SOURCE        0x630
+#define WM2200_AIF1TX3MIX_INPUT_1_VOLUME        0x631
+#define WM2200_AIF1TX3MIX_INPUT_2_SOURCE        0x632
+#define WM2200_AIF1TX3MIX_INPUT_2_VOLUME        0x633
+#define WM2200_AIF1TX3MIX_INPUT_3_SOURCE        0x634
+#define WM2200_AIF1TX3MIX_INPUT_3_VOLUME        0x635
+#define WM2200_AIF1TX3MIX_INPUT_4_SOURCE        0x636
+#define WM2200_AIF1TX3MIX_INPUT_4_VOLUME        0x637
+#define WM2200_AIF1TX4MIX_INPUT_1_SOURCE        0x638
+#define WM2200_AIF1TX4MIX_INPUT_1_VOLUME        0x639
+#define WM2200_AIF1TX4MIX_INPUT_2_SOURCE        0x63A
+#define WM2200_AIF1TX4MIX_INPUT_2_VOLUME        0x63B
+#define WM2200_AIF1TX4MIX_INPUT_3_SOURCE        0x63C
+#define WM2200_AIF1TX4MIX_INPUT_3_VOLUME        0x63D
+#define WM2200_AIF1TX4MIX_INPUT_4_SOURCE        0x63E
+#define WM2200_AIF1TX4MIX_INPUT_4_VOLUME        0x63F
+#define WM2200_AIF1TX5MIX_INPUT_1_SOURCE        0x640
+#define WM2200_AIF1TX5MIX_INPUT_1_VOLUME        0x641
+#define WM2200_AIF1TX5MIX_INPUT_2_SOURCE        0x642
+#define WM2200_AIF1TX5MIX_INPUT_2_VOLUME        0x643
+#define WM2200_AIF1TX5MIX_INPUT_3_SOURCE        0x644
+#define WM2200_AIF1TX5MIX_INPUT_3_VOLUME        0x645
+#define WM2200_AIF1TX5MIX_INPUT_4_SOURCE        0x646
+#define WM2200_AIF1TX5MIX_INPUT_4_VOLUME        0x647
+#define WM2200_AIF1TX6MIX_INPUT_1_SOURCE        0x648
+#define WM2200_AIF1TX6MIX_INPUT_1_VOLUME        0x649
+#define WM2200_AIF1TX6MIX_INPUT_2_SOURCE        0x64A
+#define WM2200_AIF1TX6MIX_INPUT_2_VOLUME        0x64B
+#define WM2200_AIF1TX6MIX_INPUT_3_SOURCE        0x64C
+#define WM2200_AIF1TX6MIX_INPUT_3_VOLUME        0x64D
+#define WM2200_AIF1TX6MIX_INPUT_4_SOURCE        0x64E
+#define WM2200_AIF1TX6MIX_INPUT_4_VOLUME        0x64F
+#define WM2200_EQLMIX_INPUT_1_SOURCE            0x650
+#define WM2200_EQLMIX_INPUT_1_VOLUME            0x651
+#define WM2200_EQLMIX_INPUT_2_SOURCE            0x652
+#define WM2200_EQLMIX_INPUT_2_VOLUME            0x653
+#define WM2200_EQLMIX_INPUT_3_SOURCE            0x654
+#define WM2200_EQLMIX_INPUT_3_VOLUME            0x655
+#define WM2200_EQLMIX_INPUT_4_SOURCE            0x656
+#define WM2200_EQLMIX_INPUT_4_VOLUME            0x657
+#define WM2200_EQRMIX_INPUT_1_SOURCE            0x658
+#define WM2200_EQRMIX_INPUT_1_VOLUME            0x659
+#define WM2200_EQRMIX_INPUT_2_SOURCE            0x65A
+#define WM2200_EQRMIX_INPUT_2_VOLUME            0x65B
+#define WM2200_EQRMIX_INPUT_3_SOURCE            0x65C
+#define WM2200_EQRMIX_INPUT_3_VOLUME            0x65D
+#define WM2200_EQRMIX_INPUT_4_SOURCE            0x65E
+#define WM2200_EQRMIX_INPUT_4_VOLUME            0x65F
+#define WM2200_LHPF1MIX_INPUT_1_SOURCE          0x660
+#define WM2200_LHPF1MIX_INPUT_1_VOLUME          0x661
+#define WM2200_LHPF1MIX_INPUT_2_SOURCE          0x662
+#define WM2200_LHPF1MIX_INPUT_2_VOLUME          0x663
+#define WM2200_LHPF1MIX_INPUT_3_SOURCE          0x664
+#define WM2200_LHPF1MIX_INPUT_3_VOLUME          0x665
+#define WM2200_LHPF1MIX_INPUT_4_SOURCE          0x666
+#define WM2200_LHPF1MIX_INPUT_4_VOLUME          0x667
+#define WM2200_LHPF2MIX_INPUT_1_SOURCE          0x668
+#define WM2200_LHPF2MIX_INPUT_1_VOLUME          0x669
+#define WM2200_LHPF2MIX_INPUT_2_SOURCE          0x66A
+#define WM2200_LHPF2MIX_INPUT_2_VOLUME          0x66B
+#define WM2200_LHPF2MIX_INPUT_3_SOURCE          0x66C
+#define WM2200_LHPF2MIX_INPUT_3_VOLUME          0x66D
+#define WM2200_LHPF2MIX_INPUT_4_SOURCE          0x66E
+#define WM2200_LHPF2MIX_INPUT_4_VOLUME          0x66F
+#define WM2200_DSP1LMIX_INPUT_1_SOURCE          0x670
+#define WM2200_DSP1LMIX_INPUT_1_VOLUME          0x671
+#define WM2200_DSP1LMIX_INPUT_2_SOURCE          0x672
+#define WM2200_DSP1LMIX_INPUT_2_VOLUME          0x673
+#define WM2200_DSP1LMIX_INPUT_3_SOURCE          0x674
+#define WM2200_DSP1LMIX_INPUT_3_VOLUME          0x675
+#define WM2200_DSP1LMIX_INPUT_4_SOURCE          0x676
+#define WM2200_DSP1LMIX_INPUT_4_VOLUME          0x677
+#define WM2200_DSP1RMIX_INPUT_1_SOURCE          0x678
+#define WM2200_DSP1RMIX_INPUT_1_VOLUME          0x679
+#define WM2200_DSP1RMIX_INPUT_2_SOURCE          0x67A
+#define WM2200_DSP1RMIX_INPUT_2_VOLUME          0x67B
+#define WM2200_DSP1RMIX_INPUT_3_SOURCE          0x67C
+#define WM2200_DSP1RMIX_INPUT_3_VOLUME          0x67D
+#define WM2200_DSP1RMIX_INPUT_4_SOURCE          0x67E
+#define WM2200_DSP1RMIX_INPUT_4_VOLUME          0x67F
+#define WM2200_DSP1AUX1MIX_INPUT_1_SOURCE       0x680
+#define WM2200_DSP1AUX2MIX_INPUT_1_SOURCE       0x681
+#define WM2200_DSP1AUX3MIX_INPUT_1_SOURCE       0x682
+#define WM2200_DSP1AUX4MIX_INPUT_1_SOURCE       0x683
+#define WM2200_DSP1AUX5MIX_INPUT_1_SOURCE       0x684
+#define WM2200_DSP1AUX6MIX_INPUT_1_SOURCE       0x685
+#define WM2200_DSP2LMIX_INPUT_1_SOURCE          0x686
+#define WM2200_DSP2LMIX_INPUT_1_VOLUME          0x687
+#define WM2200_DSP2LMIX_INPUT_2_SOURCE          0x688
+#define WM2200_DSP2LMIX_INPUT_2_VOLUME          0x689
+#define WM2200_DSP2LMIX_INPUT_3_SOURCE          0x68A
+#define WM2200_DSP2LMIX_INPUT_3_VOLUME          0x68B
+#define WM2200_DSP2LMIX_INPUT_4_SOURCE          0x68C
+#define WM2200_DSP2LMIX_INPUT_4_VOLUME          0x68D
+#define WM2200_DSP2RMIX_INPUT_1_SOURCE          0x68E
+#define WM2200_DSP2RMIX_INPUT_1_VOLUME          0x68F
+#define WM2200_DSP2RMIX_INPUT_2_SOURCE          0x690
+#define WM2200_DSP2RMIX_INPUT_2_VOLUME          0x691
+#define WM2200_DSP2RMIX_INPUT_3_SOURCE          0x692
+#define WM2200_DSP2RMIX_INPUT_3_VOLUME          0x693
+#define WM2200_DSP2RMIX_INPUT_4_SOURCE          0x694
+#define WM2200_DSP2RMIX_INPUT_4_VOLUME          0x695
+#define WM2200_DSP2AUX1MIX_INPUT_1_SOURCE       0x696
+#define WM2200_DSP2AUX2MIX_INPUT_1_SOURCE       0x697
+#define WM2200_DSP2AUX3MIX_INPUT_1_SOURCE       0x698
+#define WM2200_DSP2AUX4MIX_INPUT_1_SOURCE       0x699
+#define WM2200_DSP2AUX5MIX_INPUT_1_SOURCE       0x69A
+#define WM2200_DSP2AUX6MIX_INPUT_1_SOURCE       0x69B
+#define WM2200_GPIO_CTRL_1                      0x700
+#define WM2200_GPIO_CTRL_2                      0x701
+#define WM2200_GPIO_CTRL_3                      0x702
+#define WM2200_GPIO_CTRL_4                      0x703
+#define WM2200_ADPS1_IRQ0                       0x707
+#define WM2200_ADPS1_IRQ1                       0x708
+#define WM2200_MISC_PAD_CTRL_1                  0x709
+#define WM2200_INTERRUPT_STATUS_1               0x800
+#define WM2200_INTERRUPT_STATUS_1_MASK          0x801
+#define WM2200_INTERRUPT_STATUS_2               0x802
+#define WM2200_INTERRUPT_RAW_STATUS_2           0x803
+#define WM2200_INTERRUPT_STATUS_2_MASK          0x804
+#define WM2200_INTERRUPT_CONTROL                0x808
+#define WM2200_EQL_1                            0x900
+#define WM2200_EQL_2                            0x901
+#define WM2200_EQL_3                            0x902
+#define WM2200_EQL_4                            0x903
+#define WM2200_EQL_5                            0x904
+#define WM2200_EQL_6                            0x905
+#define WM2200_EQL_7                            0x906
+#define WM2200_EQL_8                            0x907
+#define WM2200_EQL_9                            0x908
+#define WM2200_EQL_10                           0x909
+#define WM2200_EQL_11                           0x90A
+#define WM2200_EQL_12                           0x90B
+#define WM2200_EQL_13                           0x90C
+#define WM2200_EQL_14                           0x90D
+#define WM2200_EQL_15                           0x90E
+#define WM2200_EQL_16                           0x90F
+#define WM2200_EQL_17                           0x910
+#define WM2200_EQL_18                           0x911
+#define WM2200_EQL_19                           0x912
+#define WM2200_EQL_20                           0x913
+#define WM2200_EQR_1                            0x916
+#define WM2200_EQR_2                            0x917
+#define WM2200_EQR_3                            0x918
+#define WM2200_EQR_4                            0x919
+#define WM2200_EQR_5                            0x91A
+#define WM2200_EQR_6                            0x91B
+#define WM2200_EQR_7                            0x91C
+#define WM2200_EQR_8                            0x91D
+#define WM2200_EQR_9                            0x91E
+#define WM2200_EQR_10                           0x91F
+#define WM2200_EQR_11                           0x920
+#define WM2200_EQR_12                           0x921
+#define WM2200_EQR_13                           0x922
+#define WM2200_EQR_14                           0x923
+#define WM2200_EQR_15                           0x924
+#define WM2200_EQR_16                           0x925
+#define WM2200_EQR_17                           0x926
+#define WM2200_EQR_18                           0x927
+#define WM2200_EQR_19                           0x928
+#define WM2200_EQR_20                           0x929
+#define WM2200_HPLPF1_1                         0x93E
+#define WM2200_HPLPF1_2                         0x93F
+#define WM2200_HPLPF2_1                         0x942
+#define WM2200_HPLPF2_2                         0x943
+#define WM2200_DSP1_CONTROL_1                   0xA00
+#define WM2200_DSP1_CONTROL_2                   0xA02
+#define WM2200_DSP1_CONTROL_3                   0xA03
+#define WM2200_DSP1_CONTROL_4                   0xA04
+#define WM2200_DSP1_CONTROL_5                   0xA06
+#define WM2200_DSP1_CONTROL_6                   0xA07
+#define WM2200_DSP1_CONTROL_7                   0xA08
+#define WM2200_DSP1_CONTROL_8                   0xA09
+#define WM2200_DSP1_CONTROL_9                   0xA0A
+#define WM2200_DSP1_CONTROL_10                  0xA0B
+#define WM2200_DSP1_CONTROL_11                  0xA0C
+#define WM2200_DSP1_CONTROL_12                  0xA0D
+#define WM2200_DSP1_CONTROL_13                  0xA0F
+#define WM2200_DSP1_CONTROL_14                  0xA10
+#define WM2200_DSP1_CONTROL_15                  0xA11
+#define WM2200_DSP1_CONTROL_16                  0xA12
+#define WM2200_DSP1_CONTROL_17                  0xA13
+#define WM2200_DSP1_CONTROL_18                  0xA14
+#define WM2200_DSP1_CONTROL_19                  0xA16
+#define WM2200_DSP1_CONTROL_20                  0xA17
+#define WM2200_DSP1_CONTROL_21                  0xA18
+#define WM2200_DSP1_CONTROL_22                  0xA1A
+#define WM2200_DSP1_CONTROL_23                  0xA1B
+#define WM2200_DSP1_CONTROL_24                  0xA1C
+#define WM2200_DSP1_CONTROL_25                  0xA1E
+#define WM2200_DSP1_CONTROL_26                  0xA20
+#define WM2200_DSP1_CONTROL_27                  0xA21
+#define WM2200_DSP1_CONTROL_28                  0xA22
+#define WM2200_DSP1_CONTROL_29                  0xA23
+#define WM2200_DSP1_CONTROL_30                  0xA24
+#define WM2200_DSP1_CONTROL_31                  0xA26
+#define WM2200_DSP2_CONTROL_1                   0xB00
+#define WM2200_DSP2_CONTROL_2                   0xB02
+#define WM2200_DSP2_CONTROL_3                   0xB03
+#define WM2200_DSP2_CONTROL_4                   0xB04
+#define WM2200_DSP2_CONTROL_5                   0xB06
+#define WM2200_DSP2_CONTROL_6                   0xB07
+#define WM2200_DSP2_CONTROL_7                   0xB08
+#define WM2200_DSP2_CONTROL_8                   0xB09
+#define WM2200_DSP2_CONTROL_9                   0xB0A
+#define WM2200_DSP2_CONTROL_10                  0xB0B
+#define WM2200_DSP2_CONTROL_11                  0xB0C
+#define WM2200_DSP2_CONTROL_12                  0xB0D
+#define WM2200_DSP2_CONTROL_13                  0xB0F
+#define WM2200_DSP2_CONTROL_14                  0xB10
+#define WM2200_DSP2_CONTROL_15                  0xB11
+#define WM2200_DSP2_CONTROL_16                  0xB12
+#define WM2200_DSP2_CONTROL_17                  0xB13
+#define WM2200_DSP2_CONTROL_18                  0xB14
+#define WM2200_DSP2_CONTROL_19                  0xB16
+#define WM2200_DSP2_CONTROL_20                  0xB17
+#define WM2200_DSP2_CONTROL_21                  0xB18
+#define WM2200_DSP2_CONTROL_22                  0xB1A
+#define WM2200_DSP2_CONTROL_23                  0xB1B
+#define WM2200_DSP2_CONTROL_24                  0xB1C
+#define WM2200_DSP2_CONTROL_25                  0xB1E
+#define WM2200_DSP2_CONTROL_26                  0xB20
+#define WM2200_DSP2_CONTROL_27                  0xB21
+#define WM2200_DSP2_CONTROL_28                  0xB22
+#define WM2200_DSP2_CONTROL_29                  0xB23
+#define WM2200_DSP2_CONTROL_30                  0xB24
+#define WM2200_DSP2_CONTROL_31                  0xB26
+#define WM2200_ANC_CTRL1                        0xD00
+#define WM2200_ANC_CTRL2                        0xD01
+#define WM2200_ANC_CTRL3                        0xD02
+#define WM2200_ANC_CTRL7                        0xD08
+#define WM2200_ANC_CTRL8                        0xD09
+#define WM2200_ANC_CTRL9                        0xD0A
+#define WM2200_ANC_CTRL10                       0xD0B
+#define WM2200_ANC_CTRL11                       0xD0C
+#define WM2200_ANC_CTRL12                       0xD0D
+#define WM2200_ANC_CTRL13                       0xD0E
+#define WM2200_ANC_CTRL14                       0xD0F
+#define WM2200_ANC_CTRL15                       0xD10
+#define WM2200_ANC_CTRL16                       0xD11
+#define WM2200_ANC_CTRL17                       0xD12
+#define WM2200_ANC_CTRL18                       0xD15
+#define WM2200_ANC_CTRL19                       0xD16
+#define WM2200_ANC_CTRL20                       0xD17
+#define WM2200_ANC_CTRL21                       0xD18
+#define WM2200_ANC_CTRL22                       0xD19
+#define WM2200_ANC_CTRL23                       0xD1A
+#define WM2200_ANC_CTRL24                       0xD1B
+#define WM2200_ANC_CTRL25                       0xD1C
+#define WM2200_ANC_CTRL26                       0xD1D
+#define WM2200_ANC_CTRL27                       0xD1E
+#define WM2200_ANC_CTRL28                       0xD1F
+#define WM2200_ANC_CTRL29                       0xD20
+#define WM2200_ANC_CTRL30                       0xD21
+#define WM2200_ANC_CTRL31                       0xD23
+#define WM2200_ANC_CTRL32                       0xD24
+#define WM2200_ANC_CTRL33                       0xD25
+#define WM2200_ANC_CTRL34                       0xD27
+#define WM2200_ANC_CTRL35                       0xD28
+#define WM2200_ANC_CTRL36                       0xD29
+#define WM2200_ANC_CTRL37                       0xD2A
+#define WM2200_ANC_CTRL38                       0xD2B
+#define WM2200_ANC_CTRL39                       0xD2C
+#define WM2200_ANC_CTRL40                       0xD2D
+#define WM2200_ANC_CTRL41                       0xD2E
+#define WM2200_ANC_CTRL42                       0xD2F
+#define WM2200_ANC_CTRL43                       0xD30
+#define WM2200_ANC_CTRL44                       0xD31
+#define WM2200_ANC_CTRL45                       0xD32
+#define WM2200_ANC_CTRL46                       0xD33
+#define WM2200_ANC_CTRL47                       0xD34
+#define WM2200_ANC_CTRL48                       0xD35
+#define WM2200_ANC_CTRL49                       0xD36
+#define WM2200_ANC_CTRL50                       0xD37
+#define WM2200_ANC_CTRL51                       0xD38
+#define WM2200_ANC_CTRL52                       0xD39
+#define WM2200_ANC_CTRL53                       0xD3A
+#define WM2200_ANC_CTRL54                       0xD3B
+#define WM2200_ANC_CTRL55                       0xD3C
+#define WM2200_ANC_CTRL56                       0xD3D
+#define WM2200_ANC_CTRL57                       0xD3E
+#define WM2200_ANC_CTRL58                       0xD3F
+#define WM2200_ANC_CTRL59                       0xD40
+#define WM2200_ANC_CTRL60                       0xD41
+#define WM2200_ANC_CTRL61                       0xD42
+#define WM2200_ANC_CTRL62                       0xD43
+#define WM2200_ANC_CTRL63                       0xD44
+#define WM2200_ANC_CTRL64                       0xD45
+#define WM2200_ANC_CTRL65                       0xD46
+#define WM2200_ANC_CTRL66                       0xD47
+#define WM2200_ANC_CTRL67                       0xD48
+#define WM2200_ANC_CTRL68                       0xD49
+#define WM2200_ANC_CTRL69                       0xD4A
+#define WM2200_ANC_CTRL70                       0xD4B
+#define WM2200_ANC_CTRL71                       0xD4C
+#define WM2200_ANC_CTRL72                       0xD4D
+#define WM2200_ANC_CTRL73                       0xD4E
+#define WM2200_ANC_CTRL74                       0xD4F
+#define WM2200_ANC_CTRL75                       0xD50
+#define WM2200_ANC_CTRL76                       0xD51
+#define WM2200_ANC_CTRL77                       0xD52
+#define WM2200_ANC_CTRL78                       0xD53
+#define WM2200_ANC_CTRL79                       0xD54
+#define WM2200_ANC_CTRL80                       0xD55
+#define WM2200_ANC_CTRL81                       0xD56
+#define WM2200_ANC_CTRL82                       0xD57
+#define WM2200_ANC_CTRL83                       0xD58
+#define WM2200_ANC_CTRL84                       0xD5B
+#define WM2200_ANC_CTRL85                       0xD5C
+#define WM2200_ANC_CTRL86                       0xD5F
+#define WM2200_ANC_CTRL87                       0xD60
+#define WM2200_ANC_CTRL88                       0xD61
+#define WM2200_ANC_CTRL89                       0xD62
+#define WM2200_ANC_CTRL90                       0xD63
+#define WM2200_ANC_CTRL91                       0xD64
+#define WM2200_ANC_CTRL92                       0xD65
+#define WM2200_ANC_CTRL93                       0xD66
+#define WM2200_ANC_CTRL94                       0xD67
+#define WM2200_ANC_CTRL95                       0xD68
+#define WM2200_ANC_CTRL96                       0xD69
+#define WM2200_DSP1_DM_0                        0x3000
+#define WM2200_DSP1_DM_1                        0x3001
+#define WM2200_DSP1_DM_2                        0x3002
+#define WM2200_DSP1_DM_3                        0x3003
+#define WM2200_DSP1_DM_2044                     0x37FC
+#define WM2200_DSP1_DM_2045                     0x37FD
+#define WM2200_DSP1_DM_2046                     0x37FE
+#define WM2200_DSP1_DM_2047                     0x37FF
+#define WM2200_DSP1_PM_0                        0x3800
+#define WM2200_DSP1_PM_1                        0x3801
+#define WM2200_DSP1_PM_2                        0x3802
+#define WM2200_DSP1_PM_3                        0x3803
+#define WM2200_DSP1_PM_4                        0x3804
+#define WM2200_DSP1_PM_5                        0x3805
+#define WM2200_DSP1_PM_762                      0x3AFA
+#define WM2200_DSP1_PM_763                      0x3AFB
+#define WM2200_DSP1_PM_764                      0x3AFC
+#define WM2200_DSP1_PM_765                      0x3AFD
+#define WM2200_DSP1_PM_766                      0x3AFE
+#define WM2200_DSP1_PM_767                      0x3AFF
+#define WM2200_DSP1_ZM_0                        0x3C00
+#define WM2200_DSP1_ZM_1                        0x3C01
+#define WM2200_DSP1_ZM_2                        0x3C02
+#define WM2200_DSP1_ZM_3                        0x3C03
+#define WM2200_DSP1_ZM_1020                     0x3FFC
+#define WM2200_DSP1_ZM_1021                     0x3FFD
+#define WM2200_DSP1_ZM_1022                     0x3FFE
+#define WM2200_DSP1_ZM_1023                     0x3FFF
+#define WM2200_DSP2_DM_0                        0x4000
+#define WM2200_DSP2_DM_1                        0x4001
+#define WM2200_DSP2_DM_2                        0x4002
+#define WM2200_DSP2_DM_3                        0x4003
+#define WM2200_DSP2_DM_2044                     0x47FC
+#define WM2200_DSP2_DM_2045                     0x47FD
+#define WM2200_DSP2_DM_2046                     0x47FE
+#define WM2200_DSP2_DM_2047                     0x47FF
+#define WM2200_DSP2_PM_0                        0x4800
+#define WM2200_DSP2_PM_1                        0x4801
+#define WM2200_DSP2_PM_2                        0x4802
+#define WM2200_DSP2_PM_3                        0x4803
+#define WM2200_DSP2_PM_4                        0x4804
+#define WM2200_DSP2_PM_5                        0x4805
+#define WM2200_DSP2_PM_762                      0x4AFA
+#define WM2200_DSP2_PM_763                      0x4AFB
+#define WM2200_DSP2_PM_764                      0x4AFC
+#define WM2200_DSP2_PM_765                      0x4AFD
+#define WM2200_DSP2_PM_766                      0x4AFE
+#define WM2200_DSP2_PM_767                      0x4AFF
+#define WM2200_DSP2_ZM_0                        0x4C00
+#define WM2200_DSP2_ZM_1                        0x4C01
+#define WM2200_DSP2_ZM_2                        0x4C02
+#define WM2200_DSP2_ZM_3                        0x4C03
+#define WM2200_DSP2_ZM_1020                     0x4FFC
+#define WM2200_DSP2_ZM_1021                     0x4FFD
+#define WM2200_DSP2_ZM_1022                     0x4FFE
+#define WM2200_DSP2_ZM_1023                     0x4FFF
+
+#define WM2200_REGISTER_COUNT                   494
+#define WM2200_MAX_REGISTER                     0x4FFF
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - software reset
+ */
+#define WM2200_SW_RESET_CHIP_ID1_MASK           0xFFFF  /* SW_RESET_CHIP_ID1 - [15:0] */
+#define WM2200_SW_RESET_CHIP_ID1_SHIFT               0  /* SW_RESET_CHIP_ID1 - [15:0] */
+#define WM2200_SW_RESET_CHIP_ID1_WIDTH              16  /* SW_RESET_CHIP_ID1 - [15:0] */
+
+/*
+ * R1 (0x01) - Device Revision
+ */
+#define WM2200_DEVICE_REVISION_MASK             0x000F  /* DEVICE_REVISION - [3:0] */
+#define WM2200_DEVICE_REVISION_SHIFT                 0  /* DEVICE_REVISION - [3:0] */
+#define WM2200_DEVICE_REVISION_WIDTH                 4  /* DEVICE_REVISION - [3:0] */
+
+/*
+ * R11 (0x0B) - Tone Generator 1
+ */
+#define WM2200_TONE_ENA                         0x0001  /* TONE_ENA */
+#define WM2200_TONE_ENA_MASK                    0x0001  /* TONE_ENA */
+#define WM2200_TONE_ENA_SHIFT                        0  /* TONE_ENA */
+#define WM2200_TONE_ENA_WIDTH                        1  /* TONE_ENA */
+
+/*
+ * R258 (0x102) - Clocking 3
+ */
+#define WM2200_SYSCLK_FREQ_MASK                 0x0700  /* SYSCLK_FREQ - [10:8] */
+#define WM2200_SYSCLK_FREQ_SHIFT                     8  /* SYSCLK_FREQ - [10:8] */
+#define WM2200_SYSCLK_FREQ_WIDTH                     3  /* SYSCLK_FREQ - [10:8] */
+#define WM2200_SYSCLK_ENA                       0x0040  /* SYSCLK_ENA */
+#define WM2200_SYSCLK_ENA_MASK                  0x0040  /* SYSCLK_ENA */
+#define WM2200_SYSCLK_ENA_SHIFT                      6  /* SYSCLK_ENA */
+#define WM2200_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+#define WM2200_SYSCLK_SRC_MASK                  0x000F  /* SYSCLK_SRC - [3:0] */
+#define WM2200_SYSCLK_SRC_SHIFT                      0  /* SYSCLK_SRC - [3:0] */
+#define WM2200_SYSCLK_SRC_WIDTH                      4  /* SYSCLK_SRC - [3:0] */
+
+/*
+ * R259 (0x103) - Clocking 4
+ */
+#define WM2200_SAMPLE_RATE_1_MASK               0x001F  /* SAMPLE_RATE_1 - [4:0] */
+#define WM2200_SAMPLE_RATE_1_SHIFT                   0  /* SAMPLE_RATE_1 - [4:0] */
+#define WM2200_SAMPLE_RATE_1_WIDTH                   5  /* SAMPLE_RATE_1 - [4:0] */
+
+/*
+ * R273 (0x111) - FLL Control 1
+ */
+#define WM2200_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM2200_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM2200_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM2200_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R274 (0x112) - FLL Control 2
+ */
+#define WM2200_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
+#define WM2200_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
+#define WM2200_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
+#define WM2200_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM2200_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM2200_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R275 (0x113) - FLL Control 3
+ */
+#define WM2200_FLL_FRACN_ENA                    0x0001  /* FLL_FRACN_ENA */
+#define WM2200_FLL_FRACN_ENA_MASK               0x0001  /* FLL_FRACN_ENA */
+#define WM2200_FLL_FRACN_ENA_SHIFT                   0  /* FLL_FRACN_ENA */
+#define WM2200_FLL_FRACN_ENA_WIDTH                   1  /* FLL_FRACN_ENA */
+
+/*
+ * R276 (0x114) - FLL Control 4
+ */
+#define WM2200_FLL_THETA_MASK                   0xFFFF  /* FLL_THETA - [15:0] */
+#define WM2200_FLL_THETA_SHIFT                       0  /* FLL_THETA - [15:0] */
+#define WM2200_FLL_THETA_WIDTH                      16  /* FLL_THETA - [15:0] */
+
+/*
+ * R278 (0x116) - FLL Control 6
+ */
+#define WM2200_FLL_N_MASK                       0x03FF  /* FLL_N - [9:0] */
+#define WM2200_FLL_N_SHIFT                           0  /* FLL_N - [9:0] */
+#define WM2200_FLL_N_WIDTH                          10  /* FLL_N - [9:0] */
+
+/*
+ * R279 (0x117) - FLL Control 7
+ */
+#define WM2200_FLL_CLK_REF_DIV_MASK             0x0030  /* FLL_CLK_REF_DIV - [5:4] */
+#define WM2200_FLL_CLK_REF_DIV_SHIFT                 4  /* FLL_CLK_REF_DIV - [5:4] */
+#define WM2200_FLL_CLK_REF_DIV_WIDTH                 2  /* FLL_CLK_REF_DIV - [5:4] */
+#define WM2200_FLL_CLK_REF_SRC_MASK             0x0003  /* FLL_CLK_REF_SRC - [1:0] */
+#define WM2200_FLL_CLK_REF_SRC_SHIFT                 0  /* FLL_CLK_REF_SRC - [1:0] */
+#define WM2200_FLL_CLK_REF_SRC_WIDTH                 2  /* FLL_CLK_REF_SRC - [1:0] */
+
+/*
+ * R281 (0x119) - FLL EFS 1
+ */
+#define WM2200_FLL_LAMBDA_MASK                  0xFFFF  /* FLL_LAMBDA - [15:0] */
+#define WM2200_FLL_LAMBDA_SHIFT                      0  /* FLL_LAMBDA - [15:0] */
+#define WM2200_FLL_LAMBDA_WIDTH                     16  /* FLL_LAMBDA - [15:0] */
+
+/*
+ * R282 (0x11A) - FLL EFS 2
+ */
+#define WM2200_FLL_EFS_ENA                      0x0001  /* FLL_EFS_ENA */
+#define WM2200_FLL_EFS_ENA_MASK                 0x0001  /* FLL_EFS_ENA */
+#define WM2200_FLL_EFS_ENA_SHIFT                     0  /* FLL_EFS_ENA */
+#define WM2200_FLL_EFS_ENA_WIDTH                     1  /* FLL_EFS_ENA */
+
+/*
+ * R512 (0x200) - Mic Charge Pump 1
+ */
+#define WM2200_CPMIC_BYPASS_MODE                0x0020  /* CPMIC_BYPASS_MODE */
+#define WM2200_CPMIC_BYPASS_MODE_MASK           0x0020  /* CPMIC_BYPASS_MODE */
+#define WM2200_CPMIC_BYPASS_MODE_SHIFT               5  /* CPMIC_BYPASS_MODE */
+#define WM2200_CPMIC_BYPASS_MODE_WIDTH               1  /* CPMIC_BYPASS_MODE */
+#define WM2200_CPMIC_ENA                        0x0001  /* CPMIC_ENA */
+#define WM2200_CPMIC_ENA_MASK                   0x0001  /* CPMIC_ENA */
+#define WM2200_CPMIC_ENA_SHIFT                       0  /* CPMIC_ENA */
+#define WM2200_CPMIC_ENA_WIDTH                       1  /* CPMIC_ENA */
+
+/*
+ * R513 (0x201) - Mic Charge Pump 2
+ */
+#define WM2200_CPMIC_LDO_VSEL_OVERRIDE_MASK     0xF800  /* CPMIC_LDO_VSEL_OVERRIDE - [15:11] */
+#define WM2200_CPMIC_LDO_VSEL_OVERRIDE_SHIFT        11  /* CPMIC_LDO_VSEL_OVERRIDE - [15:11] */
+#define WM2200_CPMIC_LDO_VSEL_OVERRIDE_WIDTH         5  /* CPMIC_LDO_VSEL_OVERRIDE - [15:11] */
+
+/*
+ * R514 (0x202) - DM Charge Pump 1
+ */
+#define WM2200_CPDM_ENA                         0x0001  /* CPDM_ENA */
+#define WM2200_CPDM_ENA_MASK                    0x0001  /* CPDM_ENA */
+#define WM2200_CPDM_ENA_SHIFT                        0  /* CPDM_ENA */
+#define WM2200_CPDM_ENA_WIDTH                        1  /* CPDM_ENA */
+
+/*
+ * R524 (0x20C) - Mic Bias Ctrl 1
+ */
+#define WM2200_MICB1_DISCH                      0x0040  /* MICB1_DISCH */
+#define WM2200_MICB1_DISCH_MASK                 0x0040  /* MICB1_DISCH */
+#define WM2200_MICB1_DISCH_SHIFT                     6  /* MICB1_DISCH */
+#define WM2200_MICB1_DISCH_WIDTH                     1  /* MICB1_DISCH */
+#define WM2200_MICB1_RATE                       0x0020  /* MICB1_RATE */
+#define WM2200_MICB1_RATE_MASK                  0x0020  /* MICB1_RATE */
+#define WM2200_MICB1_RATE_SHIFT                      5  /* MICB1_RATE */
+#define WM2200_MICB1_RATE_WIDTH                      1  /* MICB1_RATE */
+#define WM2200_MICB1_LVL_MASK                   0x001C  /* MICB1_LVL - [4:2] */
+#define WM2200_MICB1_LVL_SHIFT                       2  /* MICB1_LVL - [4:2] */
+#define WM2200_MICB1_LVL_WIDTH                       3  /* MICB1_LVL - [4:2] */
+#define WM2200_MICB1_MODE                       0x0002  /* MICB1_MODE */
+#define WM2200_MICB1_MODE_MASK                  0x0002  /* MICB1_MODE */
+#define WM2200_MICB1_MODE_SHIFT                      1  /* MICB1_MODE */
+#define WM2200_MICB1_MODE_WIDTH                      1  /* MICB1_MODE */
+#define WM2200_MICB1_ENA                        0x0001  /* MICB1_ENA */
+#define WM2200_MICB1_ENA_MASK                   0x0001  /* MICB1_ENA */
+#define WM2200_MICB1_ENA_SHIFT                       0  /* MICB1_ENA */
+#define WM2200_MICB1_ENA_WIDTH                       1  /* MICB1_ENA */
+
+/*
+ * R525 (0x20D) - Mic Bias Ctrl 2
+ */
+#define WM2200_MICB2_DISCH                      0x0040  /* MICB2_DISCH */
+#define WM2200_MICB2_DISCH_MASK                 0x0040  /* MICB2_DISCH */
+#define WM2200_MICB2_DISCH_SHIFT                     6  /* MICB2_DISCH */
+#define WM2200_MICB2_DISCH_WIDTH                     1  /* MICB2_DISCH */
+#define WM2200_MICB2_RATE                       0x0020  /* MICB2_RATE */
+#define WM2200_MICB2_RATE_MASK                  0x0020  /* MICB2_RATE */
+#define WM2200_MICB2_RATE_SHIFT                      5  /* MICB2_RATE */
+#define WM2200_MICB2_RATE_WIDTH                      1  /* MICB2_RATE */
+#define WM2200_MICB2_LVL_MASK                   0x001C  /* MICB2_LVL - [4:2] */
+#define WM2200_MICB2_LVL_SHIFT                       2  /* MICB2_LVL - [4:2] */
+#define WM2200_MICB2_LVL_WIDTH                       3  /* MICB2_LVL - [4:2] */
+#define WM2200_MICB2_MODE                       0x0002  /* MICB2_MODE */
+#define WM2200_MICB2_MODE_MASK                  0x0002  /* MICB2_MODE */
+#define WM2200_MICB2_MODE_SHIFT                      1  /* MICB2_MODE */
+#define WM2200_MICB2_MODE_WIDTH                      1  /* MICB2_MODE */
+#define WM2200_MICB2_ENA                        0x0001  /* MICB2_ENA */
+#define WM2200_MICB2_ENA_MASK                   0x0001  /* MICB2_ENA */
+#define WM2200_MICB2_ENA_SHIFT                       0  /* MICB2_ENA */
+#define WM2200_MICB2_ENA_WIDTH                       1  /* MICB2_ENA */
+
+/*
+ * R527 (0x20F) - Ear Piece Ctrl 1
+ */
+#define WM2200_EPD_LP_ENA                       0x4000  /* EPD_LP_ENA */
+#define WM2200_EPD_LP_ENA_MASK                  0x4000  /* EPD_LP_ENA */
+#define WM2200_EPD_LP_ENA_SHIFT                     14  /* EPD_LP_ENA */
+#define WM2200_EPD_LP_ENA_WIDTH                      1  /* EPD_LP_ENA */
+#define WM2200_EPD_OUTP_LP_ENA                  0x2000  /* EPD_OUTP_LP_ENA */
+#define WM2200_EPD_OUTP_LP_ENA_MASK             0x2000  /* EPD_OUTP_LP_ENA */
+#define WM2200_EPD_OUTP_LP_ENA_SHIFT                13  /* EPD_OUTP_LP_ENA */
+#define WM2200_EPD_OUTP_LP_ENA_WIDTH                 1  /* EPD_OUTP_LP_ENA */
+#define WM2200_EPD_RMV_SHRT_LP                  0x1000  /* EPD_RMV_SHRT_LP */
+#define WM2200_EPD_RMV_SHRT_LP_MASK             0x1000  /* EPD_RMV_SHRT_LP */
+#define WM2200_EPD_RMV_SHRT_LP_SHIFT                12  /* EPD_RMV_SHRT_LP */
+#define WM2200_EPD_RMV_SHRT_LP_WIDTH                 1  /* EPD_RMV_SHRT_LP */
+#define WM2200_EPD_LN_ENA                       0x0800  /* EPD_LN_ENA */
+#define WM2200_EPD_LN_ENA_MASK                  0x0800  /* EPD_LN_ENA */
+#define WM2200_EPD_LN_ENA_SHIFT                     11  /* EPD_LN_ENA */
+#define WM2200_EPD_LN_ENA_WIDTH                      1  /* EPD_LN_ENA */
+#define WM2200_EPD_OUTP_LN_ENA                  0x0400  /* EPD_OUTP_LN_ENA */
+#define WM2200_EPD_OUTP_LN_ENA_MASK             0x0400  /* EPD_OUTP_LN_ENA */
+#define WM2200_EPD_OUTP_LN_ENA_SHIFT                10  /* EPD_OUTP_LN_ENA */
+#define WM2200_EPD_OUTP_LN_ENA_WIDTH                 1  /* EPD_OUTP_LN_ENA */
+#define WM2200_EPD_RMV_SHRT_LN                  0x0200  /* EPD_RMV_SHRT_LN */
+#define WM2200_EPD_RMV_SHRT_LN_MASK             0x0200  /* EPD_RMV_SHRT_LN */
+#define WM2200_EPD_RMV_SHRT_LN_SHIFT                 9  /* EPD_RMV_SHRT_LN */
+#define WM2200_EPD_RMV_SHRT_LN_WIDTH                 1  /* EPD_RMV_SHRT_LN */
+
+/*
+ * R528 (0x210) - Ear Piece Ctrl 2
+ */
+#define WM2200_EPD_RP_ENA                       0x4000  /* EPD_RP_ENA */
+#define WM2200_EPD_RP_ENA_MASK                  0x4000  /* EPD_RP_ENA */
+#define WM2200_EPD_RP_ENA_SHIFT                     14  /* EPD_RP_ENA */
+#define WM2200_EPD_RP_ENA_WIDTH                      1  /* EPD_RP_ENA */
+#define WM2200_EPD_OUTP_RP_ENA                  0x2000  /* EPD_OUTP_RP_ENA */
+#define WM2200_EPD_OUTP_RP_ENA_MASK             0x2000  /* EPD_OUTP_RP_ENA */
+#define WM2200_EPD_OUTP_RP_ENA_SHIFT                13  /* EPD_OUTP_RP_ENA */
+#define WM2200_EPD_OUTP_RP_ENA_WIDTH                 1  /* EPD_OUTP_RP_ENA */
+#define WM2200_EPD_RMV_SHRT_RP                  0x1000  /* EPD_RMV_SHRT_RP */
+#define WM2200_EPD_RMV_SHRT_RP_MASK             0x1000  /* EPD_RMV_SHRT_RP */
+#define WM2200_EPD_RMV_SHRT_RP_SHIFT                12  /* EPD_RMV_SHRT_RP */
+#define WM2200_EPD_RMV_SHRT_RP_WIDTH                 1  /* EPD_RMV_SHRT_RP */
+#define WM2200_EPD_RN_ENA                       0x0800  /* EPD_RN_ENA */
+#define WM2200_EPD_RN_ENA_MASK                  0x0800  /* EPD_RN_ENA */
+#define WM2200_EPD_RN_ENA_SHIFT                     11  /* EPD_RN_ENA */
+#define WM2200_EPD_RN_ENA_WIDTH                      1  /* EPD_RN_ENA */
+#define WM2200_EPD_OUTP_RN_ENA                  0x0400  /* EPD_OUTP_RN_ENA */
+#define WM2200_EPD_OUTP_RN_ENA_MASK             0x0400  /* EPD_OUTP_RN_ENA */
+#define WM2200_EPD_OUTP_RN_ENA_SHIFT                10  /* EPD_OUTP_RN_ENA */
+#define WM2200_EPD_OUTP_RN_ENA_WIDTH                 1  /* EPD_OUTP_RN_ENA */
+#define WM2200_EPD_RMV_SHRT_RN                  0x0200  /* EPD_RMV_SHRT_RN */
+#define WM2200_EPD_RMV_SHRT_RN_MASK             0x0200  /* EPD_RMV_SHRT_RN */
+#define WM2200_EPD_RMV_SHRT_RN_SHIFT                 9  /* EPD_RMV_SHRT_RN */
+#define WM2200_EPD_RMV_SHRT_RN_WIDTH                 1  /* EPD_RMV_SHRT_RN */
+
+/*
+ * R769 (0x301) - Input Enables
+ */
+#define WM2200_IN3L_ENA                         0x0020  /* IN3L_ENA */
+#define WM2200_IN3L_ENA_MASK                    0x0020  /* IN3L_ENA */
+#define WM2200_IN3L_ENA_SHIFT                        5  /* IN3L_ENA */
+#define WM2200_IN3L_ENA_WIDTH                        1  /* IN3L_ENA */
+#define WM2200_IN3R_ENA                         0x0010  /* IN3R_ENA */
+#define WM2200_IN3R_ENA_MASK                    0x0010  /* IN3R_ENA */
+#define WM2200_IN3R_ENA_SHIFT                        4  /* IN3R_ENA */
+#define WM2200_IN3R_ENA_WIDTH                        1  /* IN3R_ENA */
+#define WM2200_IN2L_ENA                         0x0008  /* IN2L_ENA */
+#define WM2200_IN2L_ENA_MASK                    0x0008  /* IN2L_ENA */
+#define WM2200_IN2L_ENA_SHIFT                        3  /* IN2L_ENA */
+#define WM2200_IN2L_ENA_WIDTH                        1  /* IN2L_ENA */
+#define WM2200_IN2R_ENA                         0x0004  /* IN2R_ENA */
+#define WM2200_IN2R_ENA_MASK                    0x0004  /* IN2R_ENA */
+#define WM2200_IN2R_ENA_SHIFT                        2  /* IN2R_ENA */
+#define WM2200_IN2R_ENA_WIDTH                        1  /* IN2R_ENA */
+#define WM2200_IN1L_ENA                         0x0002  /* IN1L_ENA */
+#define WM2200_IN1L_ENA_MASK                    0x0002  /* IN1L_ENA */
+#define WM2200_IN1L_ENA_SHIFT                        1  /* IN1L_ENA */
+#define WM2200_IN1L_ENA_WIDTH                        1  /* IN1L_ENA */
+#define WM2200_IN1R_ENA                         0x0001  /* IN1R_ENA */
+#define WM2200_IN1R_ENA_MASK                    0x0001  /* IN1R_ENA */
+#define WM2200_IN1R_ENA_SHIFT                        0  /* IN1R_ENA */
+#define WM2200_IN1R_ENA_WIDTH                        1  /* IN1R_ENA */
+
+/*
+ * R770 (0x302) - IN1L Control
+ */
+#define WM2200_IN1_OSR                          0x2000  /* IN1_OSR */
+#define WM2200_IN1_OSR_MASK                     0x2000  /* IN1_OSR */
+#define WM2200_IN1_OSR_SHIFT                        13  /* IN1_OSR */
+#define WM2200_IN1_OSR_WIDTH                         1  /* IN1_OSR */
+#define WM2200_IN1_DMIC_SUP_MASK                0x1800  /* IN1_DMIC_SUP - [12:11] */
+#define WM2200_IN1_DMIC_SUP_SHIFT                   11  /* IN1_DMIC_SUP - [12:11] */
+#define WM2200_IN1_DMIC_SUP_WIDTH                    2  /* IN1_DMIC_SUP - [12:11] */
+#define WM2200_IN1_MODE_MASK                    0x0600  /* IN1_MODE - [10:9] */
+#define WM2200_IN1_MODE_SHIFT                        9  /* IN1_MODE - [10:9] */
+#define WM2200_IN1_MODE_WIDTH                        2  /* IN1_MODE - [10:9] */
+#define WM2200_IN1L_PGA_VOL_MASK                0x00FE  /* IN1L_PGA_VOL - [7:1] */
+#define WM2200_IN1L_PGA_VOL_SHIFT                    1  /* IN1L_PGA_VOL - [7:1] */
+#define WM2200_IN1L_PGA_VOL_WIDTH                    7  /* IN1L_PGA_VOL - [7:1] */
+
+/*
+ * R771 (0x303) - IN1R Control
+ */
+#define WM2200_IN1R_PGA_VOL_MASK                0x00FE  /* IN1R_PGA_VOL - [7:1] */
+#define WM2200_IN1R_PGA_VOL_SHIFT                    1  /* IN1R_PGA_VOL - [7:1] */
+#define WM2200_IN1R_PGA_VOL_WIDTH                    7  /* IN1R_PGA_VOL - [7:1] */
+
+/*
+ * R772 (0x304) - IN2L Control
+ */
+#define WM2200_IN2_OSR                          0x2000  /* IN2_OSR */
+#define WM2200_IN2_OSR_MASK                     0x2000  /* IN2_OSR */
+#define WM2200_IN2_OSR_SHIFT                        13  /* IN2_OSR */
+#define WM2200_IN2_OSR_WIDTH                         1  /* IN2_OSR */
+#define WM2200_IN2_DMIC_SUP_MASK                0x1800  /* IN2_DMIC_SUP - [12:11] */
+#define WM2200_IN2_DMIC_SUP_SHIFT                   11  /* IN2_DMIC_SUP - [12:11] */
+#define WM2200_IN2_DMIC_SUP_WIDTH                    2  /* IN2_DMIC_SUP - [12:11] */
+#define WM2200_IN2_MODE_MASK                    0x0600  /* IN2_MODE - [10:9] */
+#define WM2200_IN2_MODE_SHIFT                        9  /* IN2_MODE - [10:9] */
+#define WM2200_IN2_MODE_WIDTH                        2  /* IN2_MODE - [10:9] */
+#define WM2200_IN2L_PGA_VOL_MASK                0x00FE  /* IN2L_PGA_VOL - [7:1] */
+#define WM2200_IN2L_PGA_VOL_SHIFT                    1  /* IN2L_PGA_VOL - [7:1] */
+#define WM2200_IN2L_PGA_VOL_WIDTH                    7  /* IN2L_PGA_VOL - [7:1] */
+
+/*
+ * R773 (0x305) - IN2R Control
+ */
+#define WM2200_IN2R_PGA_VOL_MASK                0x00FE  /* IN2R_PGA_VOL - [7:1] */
+#define WM2200_IN2R_PGA_VOL_SHIFT                    1  /* IN2R_PGA_VOL - [7:1] */
+#define WM2200_IN2R_PGA_VOL_WIDTH                    7  /* IN2R_PGA_VOL - [7:1] */
+
+/*
+ * R774 (0x306) - IN3L Control
+ */
+#define WM2200_IN3_OSR                          0x2000  /* IN3_OSR */
+#define WM2200_IN3_OSR_MASK                     0x2000  /* IN3_OSR */
+#define WM2200_IN3_OSR_SHIFT                        13  /* IN3_OSR */
+#define WM2200_IN3_OSR_WIDTH                         1  /* IN3_OSR */
+#define WM2200_IN3_DMIC_SUP_MASK                0x1800  /* IN3_DMIC_SUP - [12:11] */
+#define WM2200_IN3_DMIC_SUP_SHIFT                   11  /* IN3_DMIC_SUP - [12:11] */
+#define WM2200_IN3_DMIC_SUP_WIDTH                    2  /* IN3_DMIC_SUP - [12:11] */
+#define WM2200_IN3_MODE_MASK                    0x0600  /* IN3_MODE - [10:9] */
+#define WM2200_IN3_MODE_SHIFT                        9  /* IN3_MODE - [10:9] */
+#define WM2200_IN3_MODE_WIDTH                        2  /* IN3_MODE - [10:9] */
+#define WM2200_IN3L_PGA_VOL_MASK                0x00FE  /* IN3L_PGA_VOL - [7:1] */
+#define WM2200_IN3L_PGA_VOL_SHIFT                    1  /* IN3L_PGA_VOL - [7:1] */
+#define WM2200_IN3L_PGA_VOL_WIDTH                    7  /* IN3L_PGA_VOL - [7:1] */
+
+/*
+ * R775 (0x307) - IN3R Control
+ */
+#define WM2200_IN3R_PGA_VOL_MASK                0x00FE  /* IN3R_PGA_VOL - [7:1] */
+#define WM2200_IN3R_PGA_VOL_SHIFT                    1  /* IN3R_PGA_VOL - [7:1] */
+#define WM2200_IN3R_PGA_VOL_WIDTH                    7  /* IN3R_PGA_VOL - [7:1] */
+
+/*
+ * R778 (0x30A) - RXANC_SRC
+ */
+#define WM2200_IN_RXANC_SEL_MASK                0x0007  /* IN_RXANC_SEL - [2:0] */
+#define WM2200_IN_RXANC_SEL_SHIFT                    0  /* IN_RXANC_SEL - [2:0] */
+#define WM2200_IN_RXANC_SEL_WIDTH                    3  /* IN_RXANC_SEL - [2:0] */
+
+/*
+ * R779 (0x30B) - Input Volume Ramp
+ */
+#define WM2200_IN_VD_RAMP_MASK                  0x0070  /* IN_VD_RAMP - [6:4] */
+#define WM2200_IN_VD_RAMP_SHIFT                      4  /* IN_VD_RAMP - [6:4] */
+#define WM2200_IN_VD_RAMP_WIDTH                      3  /* IN_VD_RAMP - [6:4] */
+#define WM2200_IN_VI_RAMP_MASK                  0x0007  /* IN_VI_RAMP - [2:0] */
+#define WM2200_IN_VI_RAMP_SHIFT                      0  /* IN_VI_RAMP - [2:0] */
+#define WM2200_IN_VI_RAMP_WIDTH                      3  /* IN_VI_RAMP - [2:0] */
+
+/*
+ * R780 (0x30C) - ADC Digital Volume 1L
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN1L_MUTE                        0x0100  /* IN1L_MUTE */
+#define WM2200_IN1L_MUTE_MASK                   0x0100  /* IN1L_MUTE */
+#define WM2200_IN1L_MUTE_SHIFT                       8  /* IN1L_MUTE */
+#define WM2200_IN1L_MUTE_WIDTH                       1  /* IN1L_MUTE */
+#define WM2200_IN1L_DIG_VOL_MASK                0x00FF  /* IN1L_DIG_VOL - [7:0] */
+#define WM2200_IN1L_DIG_VOL_SHIFT                    0  /* IN1L_DIG_VOL - [7:0] */
+#define WM2200_IN1L_DIG_VOL_WIDTH                    8  /* IN1L_DIG_VOL - [7:0] */
+
+/*
+ * R781 (0x30D) - ADC Digital Volume 1R
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN1R_MUTE                        0x0100  /* IN1R_MUTE */
+#define WM2200_IN1R_MUTE_MASK                   0x0100  /* IN1R_MUTE */
+#define WM2200_IN1R_MUTE_SHIFT                       8  /* IN1R_MUTE */
+#define WM2200_IN1R_MUTE_WIDTH                       1  /* IN1R_MUTE */
+#define WM2200_IN1R_DIG_VOL_MASK                0x00FF  /* IN1R_DIG_VOL - [7:0] */
+#define WM2200_IN1R_DIG_VOL_SHIFT                    0  /* IN1R_DIG_VOL - [7:0] */
+#define WM2200_IN1R_DIG_VOL_WIDTH                    8  /* IN1R_DIG_VOL - [7:0] */
+
+/*
+ * R782 (0x30E) - ADC Digital Volume 2L
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN2L_MUTE                        0x0100  /* IN2L_MUTE */
+#define WM2200_IN2L_MUTE_MASK                   0x0100  /* IN2L_MUTE */
+#define WM2200_IN2L_MUTE_SHIFT                       8  /* IN2L_MUTE */
+#define WM2200_IN2L_MUTE_WIDTH                       1  /* IN2L_MUTE */
+#define WM2200_IN2L_DIG_VOL_MASK                0x00FF  /* IN2L_DIG_VOL - [7:0] */
+#define WM2200_IN2L_DIG_VOL_SHIFT                    0  /* IN2L_DIG_VOL - [7:0] */
+#define WM2200_IN2L_DIG_VOL_WIDTH                    8  /* IN2L_DIG_VOL - [7:0] */
+
+/*
+ * R783 (0x30F) - ADC Digital Volume 2R
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN2R_MUTE                        0x0100  /* IN2R_MUTE */
+#define WM2200_IN2R_MUTE_MASK                   0x0100  /* IN2R_MUTE */
+#define WM2200_IN2R_MUTE_SHIFT                       8  /* IN2R_MUTE */
+#define WM2200_IN2R_MUTE_WIDTH                       1  /* IN2R_MUTE */
+#define WM2200_IN2R_DIG_VOL_MASK                0x00FF  /* IN2R_DIG_VOL - [7:0] */
+#define WM2200_IN2R_DIG_VOL_SHIFT                    0  /* IN2R_DIG_VOL - [7:0] */
+#define WM2200_IN2R_DIG_VOL_WIDTH                    8  /* IN2R_DIG_VOL - [7:0] */
+
+/*
+ * R784 (0x310) - ADC Digital Volume 3L
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN3L_MUTE                        0x0100  /* IN3L_MUTE */
+#define WM2200_IN3L_MUTE_MASK                   0x0100  /* IN3L_MUTE */
+#define WM2200_IN3L_MUTE_SHIFT                       8  /* IN3L_MUTE */
+#define WM2200_IN3L_MUTE_WIDTH                       1  /* IN3L_MUTE */
+#define WM2200_IN3L_DIG_VOL_MASK                0x00FF  /* IN3L_DIG_VOL - [7:0] */
+#define WM2200_IN3L_DIG_VOL_SHIFT                    0  /* IN3L_DIG_VOL - [7:0] */
+#define WM2200_IN3L_DIG_VOL_WIDTH                    8  /* IN3L_DIG_VOL - [7:0] */
+
+/*
+ * R785 (0x311) - ADC Digital Volume 3R
+ */
+#define WM2200_IN_VU                            0x0200  /* IN_VU */
+#define WM2200_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM2200_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM2200_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM2200_IN3R_MUTE                        0x0100  /* IN3R_MUTE */
+#define WM2200_IN3R_MUTE_MASK                   0x0100  /* IN3R_MUTE */
+#define WM2200_IN3R_MUTE_SHIFT                       8  /* IN3R_MUTE */
+#define WM2200_IN3R_MUTE_WIDTH                       1  /* IN3R_MUTE */
+#define WM2200_IN3R_DIG_VOL_MASK                0x00FF  /* IN3R_DIG_VOL - [7:0] */
+#define WM2200_IN3R_DIG_VOL_SHIFT                    0  /* IN3R_DIG_VOL - [7:0] */
+#define WM2200_IN3R_DIG_VOL_WIDTH                    8  /* IN3R_DIG_VOL - [7:0] */
+
+/*
+ * R1024 (0x400) - Output Enables
+ */
+#define WM2200_OUT2L_ENA                        0x0008  /* OUT2L_ENA */
+#define WM2200_OUT2L_ENA_MASK                   0x0008  /* OUT2L_ENA */
+#define WM2200_OUT2L_ENA_SHIFT                       3  /* OUT2L_ENA */
+#define WM2200_OUT2L_ENA_WIDTH                       1  /* OUT2L_ENA */
+#define WM2200_OUT2R_ENA                        0x0004  /* OUT2R_ENA */
+#define WM2200_OUT2R_ENA_MASK                   0x0004  /* OUT2R_ENA */
+#define WM2200_OUT2R_ENA_SHIFT                       2  /* OUT2R_ENA */
+#define WM2200_OUT2R_ENA_WIDTH                       1  /* OUT2R_ENA */
+#define WM2200_OUT1L_ENA                        0x0002  /* OUT1L_ENA */
+#define WM2200_OUT1L_ENA_MASK                   0x0002  /* OUT1L_ENA */
+#define WM2200_OUT1L_ENA_SHIFT                       1  /* OUT1L_ENA */
+#define WM2200_OUT1L_ENA_WIDTH                       1  /* OUT1L_ENA */
+#define WM2200_OUT1R_ENA                        0x0001  /* OUT1R_ENA */
+#define WM2200_OUT1R_ENA_MASK                   0x0001  /* OUT1R_ENA */
+#define WM2200_OUT1R_ENA_SHIFT                       0  /* OUT1R_ENA */
+#define WM2200_OUT1R_ENA_WIDTH                       1  /* OUT1R_ENA */
+
+/*
+ * R1025 (0x401) - DAC Volume Limit 1L
+ */
+#define WM2200_OUT1_OSR                         0x2000  /* OUT1_OSR */
+#define WM2200_OUT1_OSR_MASK                    0x2000  /* OUT1_OSR */
+#define WM2200_OUT1_OSR_SHIFT                       13  /* OUT1_OSR */
+#define WM2200_OUT1_OSR_WIDTH                        1  /* OUT1_OSR */
+#define WM2200_OUT1L_ANC_SRC                    0x0800  /* OUT1L_ANC_SRC */
+#define WM2200_OUT1L_ANC_SRC_MASK               0x0800  /* OUT1L_ANC_SRC */
+#define WM2200_OUT1L_ANC_SRC_SHIFT                  11  /* OUT1L_ANC_SRC */
+#define WM2200_OUT1L_ANC_SRC_WIDTH                   1  /* OUT1L_ANC_SRC */
+#define WM2200_OUT1L_PGA_VOL_MASK               0x00FE  /* OUT1L_PGA_VOL - [7:1] */
+#define WM2200_OUT1L_PGA_VOL_SHIFT                   1  /* OUT1L_PGA_VOL - [7:1] */
+#define WM2200_OUT1L_PGA_VOL_WIDTH                   7  /* OUT1L_PGA_VOL - [7:1] */
+
+/*
+ * R1026 (0x402) - DAC Volume Limit 1R
+ */
+#define WM2200_OUT1R_ANC_SRC                    0x0800  /* OUT1R_ANC_SRC */
+#define WM2200_OUT1R_ANC_SRC_MASK               0x0800  /* OUT1R_ANC_SRC */
+#define WM2200_OUT1R_ANC_SRC_SHIFT                  11  /* OUT1R_ANC_SRC */
+#define WM2200_OUT1R_ANC_SRC_WIDTH                   1  /* OUT1R_ANC_SRC */
+#define WM2200_OUT1R_PGA_VOL_MASK               0x00FE  /* OUT1R_PGA_VOL - [7:1] */
+#define WM2200_OUT1R_PGA_VOL_SHIFT                   1  /* OUT1R_PGA_VOL - [7:1] */
+#define WM2200_OUT1R_PGA_VOL_WIDTH                   7  /* OUT1R_PGA_VOL - [7:1] */
+
+/*
+ * R1027 (0x403) - DAC Volume Limit 2L
+ */
+#define WM2200_OUT2_OSR                         0x2000  /* OUT2_OSR */
+#define WM2200_OUT2_OSR_MASK                    0x2000  /* OUT2_OSR */
+#define WM2200_OUT2_OSR_SHIFT                       13  /* OUT2_OSR */
+#define WM2200_OUT2_OSR_WIDTH                        1  /* OUT2_OSR */
+#define WM2200_OUT2L_ANC_SRC                    0x0800  /* OUT2L_ANC_SRC */
+#define WM2200_OUT2L_ANC_SRC_MASK               0x0800  /* OUT2L_ANC_SRC */
+#define WM2200_OUT2L_ANC_SRC_SHIFT                  11  /* OUT2L_ANC_SRC */
+#define WM2200_OUT2L_ANC_SRC_WIDTH                   1  /* OUT2L_ANC_SRC */
+
+/*
+ * R1028 (0x404) - DAC Volume Limit 2R
+ */
+#define WM2200_OUT2R_ANC_SRC                    0x0800  /* OUT2R_ANC_SRC */
+#define WM2200_OUT2R_ANC_SRC_MASK               0x0800  /* OUT2R_ANC_SRC */
+#define WM2200_OUT2R_ANC_SRC_SHIFT                  11  /* OUT2R_ANC_SRC */
+#define WM2200_OUT2R_ANC_SRC_WIDTH                   1  /* OUT2R_ANC_SRC */
+
+/*
+ * R1033 (0x409) - DAC AEC Control 1
+ */
+#define WM2200_AEC_LOOPBACK_ENA                 0x0004  /* AEC_LOOPBACK_ENA */
+#define WM2200_AEC_LOOPBACK_ENA_MASK            0x0004  /* AEC_LOOPBACK_ENA */
+#define WM2200_AEC_LOOPBACK_ENA_SHIFT                2  /* AEC_LOOPBACK_ENA */
+#define WM2200_AEC_LOOPBACK_ENA_WIDTH                1  /* AEC_LOOPBACK_ENA */
+#define WM2200_AEC_LOOPBACK_SRC_MASK            0x0003  /* AEC_LOOPBACK_SRC - [1:0] */
+#define WM2200_AEC_LOOPBACK_SRC_SHIFT                0  /* AEC_LOOPBACK_SRC - [1:0] */
+#define WM2200_AEC_LOOPBACK_SRC_WIDTH                2  /* AEC_LOOPBACK_SRC - [1:0] */
+
+/*
+ * R1034 (0x40A) - Output Volume Ramp
+ */
+#define WM2200_OUT_VD_RAMP_MASK                 0x0070  /* OUT_VD_RAMP - [6:4] */
+#define WM2200_OUT_VD_RAMP_SHIFT                     4  /* OUT_VD_RAMP - [6:4] */
+#define WM2200_OUT_VD_RAMP_WIDTH                     3  /* OUT_VD_RAMP - [6:4] */
+#define WM2200_OUT_VI_RAMP_MASK                 0x0007  /* OUT_VI_RAMP - [2:0] */
+#define WM2200_OUT_VI_RAMP_SHIFT                     0  /* OUT_VI_RAMP - [2:0] */
+#define WM2200_OUT_VI_RAMP_WIDTH                     3  /* OUT_VI_RAMP - [2:0] */
+
+/*
+ * R1035 (0x40B) - DAC Digital Volume 1L
+ */
+#define WM2200_OUT_VU                           0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM2200_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM2200_OUT1L_MUTE                       0x0100  /* OUT1L_MUTE */
+#define WM2200_OUT1L_MUTE_MASK                  0x0100  /* OUT1L_MUTE */
+#define WM2200_OUT1L_MUTE_SHIFT                      8  /* OUT1L_MUTE */
+#define WM2200_OUT1L_MUTE_WIDTH                      1  /* OUT1L_MUTE */
+#define WM2200_OUT1L_VOL_MASK                   0x00FF  /* OUT1L_VOL - [7:0] */
+#define WM2200_OUT1L_VOL_SHIFT                       0  /* OUT1L_VOL - [7:0] */
+#define WM2200_OUT1L_VOL_WIDTH                       8  /* OUT1L_VOL - [7:0] */
+
+/*
+ * R1036 (0x40C) - DAC Digital Volume 1R
+ */
+#define WM2200_OUT_VU                           0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM2200_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM2200_OUT1R_MUTE                       0x0100  /* OUT1R_MUTE */
+#define WM2200_OUT1R_MUTE_MASK                  0x0100  /* OUT1R_MUTE */
+#define WM2200_OUT1R_MUTE_SHIFT                      8  /* OUT1R_MUTE */
+#define WM2200_OUT1R_MUTE_WIDTH                      1  /* OUT1R_MUTE */
+#define WM2200_OUT1R_VOL_MASK                   0x00FF  /* OUT1R_VOL - [7:0] */
+#define WM2200_OUT1R_VOL_SHIFT                       0  /* OUT1R_VOL - [7:0] */
+#define WM2200_OUT1R_VOL_WIDTH                       8  /* OUT1R_VOL - [7:0] */
+
+/*
+ * R1037 (0x40D) - DAC Digital Volume 2L
+ */
+#define WM2200_OUT_VU                           0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM2200_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM2200_OUT2L_MUTE                       0x0100  /* OUT2L_MUTE */
+#define WM2200_OUT2L_MUTE_MASK                  0x0100  /* OUT2L_MUTE */
+#define WM2200_OUT2L_MUTE_SHIFT                      8  /* OUT2L_MUTE */
+#define WM2200_OUT2L_MUTE_WIDTH                      1  /* OUT2L_MUTE */
+#define WM2200_OUT2L_VOL_MASK                   0x00FF  /* OUT2L_VOL - [7:0] */
+#define WM2200_OUT2L_VOL_SHIFT                       0  /* OUT2L_VOL - [7:0] */
+#define WM2200_OUT2L_VOL_WIDTH                       8  /* OUT2L_VOL - [7:0] */
+
+/*
+ * R1038 (0x40E) - DAC Digital Volume 2R
+ */
+#define WM2200_OUT_VU                           0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM2200_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM2200_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM2200_OUT2R_MUTE                       0x0100  /* OUT2R_MUTE */
+#define WM2200_OUT2R_MUTE_MASK                  0x0100  /* OUT2R_MUTE */
+#define WM2200_OUT2R_MUTE_SHIFT                      8  /* OUT2R_MUTE */
+#define WM2200_OUT2R_MUTE_WIDTH                      1  /* OUT2R_MUTE */
+#define WM2200_OUT2R_VOL_MASK                   0x00FF  /* OUT2R_VOL - [7:0] */
+#define WM2200_OUT2R_VOL_SHIFT                       0  /* OUT2R_VOL - [7:0] */
+#define WM2200_OUT2R_VOL_WIDTH                       8  /* OUT2R_VOL - [7:0] */
+
+/*
+ * R1047 (0x417) - PDM 1
+ */
+#define WM2200_SPK1R_MUTE                       0x2000  /* SPK1R_MUTE */
+#define WM2200_SPK1R_MUTE_MASK                  0x2000  /* SPK1R_MUTE */
+#define WM2200_SPK1R_MUTE_SHIFT                     13  /* SPK1R_MUTE */
+#define WM2200_SPK1R_MUTE_WIDTH                      1  /* SPK1R_MUTE */
+#define WM2200_SPK1L_MUTE                       0x1000  /* SPK1L_MUTE */
+#define WM2200_SPK1L_MUTE_MASK                  0x1000  /* SPK1L_MUTE */
+#define WM2200_SPK1L_MUTE_SHIFT                     12  /* SPK1L_MUTE */
+#define WM2200_SPK1L_MUTE_WIDTH                      1  /* SPK1L_MUTE */
+#define WM2200_SPK1_MUTE_ENDIAN                 0x0100  /* SPK1_MUTE_ENDIAN */
+#define WM2200_SPK1_MUTE_ENDIAN_MASK            0x0100  /* SPK1_MUTE_ENDIAN */
+#define WM2200_SPK1_MUTE_ENDIAN_SHIFT                8  /* SPK1_MUTE_ENDIAN */
+#define WM2200_SPK1_MUTE_ENDIAN_WIDTH                1  /* SPK1_MUTE_ENDIAN */
+#define WM2200_SPK1_MUTE_SEQL_MASK              0x00FF  /* SPK1_MUTE_SEQL - [7:0] */
+#define WM2200_SPK1_MUTE_SEQL_SHIFT                  0  /* SPK1_MUTE_SEQL - [7:0] */
+#define WM2200_SPK1_MUTE_SEQL_WIDTH                  8  /* SPK1_MUTE_SEQL - [7:0] */
+
+/*
+ * R1048 (0x418) - PDM 2
+ */
+#define WM2200_SPK1_FMT                         0x0001  /* SPK1_FMT */
+#define WM2200_SPK1_FMT_MASK                    0x0001  /* SPK1_FMT */
+#define WM2200_SPK1_FMT_SHIFT                        0  /* SPK1_FMT */
+#define WM2200_SPK1_FMT_WIDTH                        1  /* SPK1_FMT */
+
+/*
+ * R1280 (0x500) - Audio IF 1_1
+ */
+#define WM2200_AIF1_BCLK_INV                    0x0040  /* AIF1_BCLK_INV */
+#define WM2200_AIF1_BCLK_INV_MASK               0x0040  /* AIF1_BCLK_INV */
+#define WM2200_AIF1_BCLK_INV_SHIFT                   6  /* AIF1_BCLK_INV */
+#define WM2200_AIF1_BCLK_INV_WIDTH                   1  /* AIF1_BCLK_INV */
+#define WM2200_AIF1_BCLK_FRC                    0x0020  /* AIF1_BCLK_FRC */
+#define WM2200_AIF1_BCLK_FRC_MASK               0x0020  /* AIF1_BCLK_FRC */
+#define WM2200_AIF1_BCLK_FRC_SHIFT                   5  /* AIF1_BCLK_FRC */
+#define WM2200_AIF1_BCLK_FRC_WIDTH                   1  /* AIF1_BCLK_FRC */
+#define WM2200_AIF1_BCLK_MSTR                   0x0010  /* AIF1_BCLK_MSTR */
+#define WM2200_AIF1_BCLK_MSTR_MASK              0x0010  /* AIF1_BCLK_MSTR */
+#define WM2200_AIF1_BCLK_MSTR_SHIFT                  4  /* AIF1_BCLK_MSTR */
+#define WM2200_AIF1_BCLK_MSTR_WIDTH                  1  /* AIF1_BCLK_MSTR */
+#define WM2200_AIF1_BCLK_DIV_MASK               0x000F  /* AIF1_BCLK_DIV - [3:0] */
+#define WM2200_AIF1_BCLK_DIV_SHIFT                   0  /* AIF1_BCLK_DIV - [3:0] */
+#define WM2200_AIF1_BCLK_DIV_WIDTH                   4  /* AIF1_BCLK_DIV - [3:0] */
+
+/*
+ * R1281 (0x501) - Audio IF 1_2
+ */
+#define WM2200_AIF1TX_DAT_TRI                   0x0020  /* AIF1TX_DAT_TRI */
+#define WM2200_AIF1TX_DAT_TRI_MASK              0x0020  /* AIF1TX_DAT_TRI */
+#define WM2200_AIF1TX_DAT_TRI_SHIFT                  5  /* AIF1TX_DAT_TRI */
+#define WM2200_AIF1TX_DAT_TRI_WIDTH                  1  /* AIF1TX_DAT_TRI */
+#define WM2200_AIF1TX_LRCLK_SRC                 0x0008  /* AIF1TX_LRCLK_SRC */
+#define WM2200_AIF1TX_LRCLK_SRC_MASK            0x0008  /* AIF1TX_LRCLK_SRC */
+#define WM2200_AIF1TX_LRCLK_SRC_SHIFT                3  /* AIF1TX_LRCLK_SRC */
+#define WM2200_AIF1TX_LRCLK_SRC_WIDTH                1  /* AIF1TX_LRCLK_SRC */
+#define WM2200_AIF1TX_LRCLK_INV                 0x0004  /* AIF1TX_LRCLK_INV */
+#define WM2200_AIF1TX_LRCLK_INV_MASK            0x0004  /* AIF1TX_LRCLK_INV */
+#define WM2200_AIF1TX_LRCLK_INV_SHIFT                2  /* AIF1TX_LRCLK_INV */
+#define WM2200_AIF1TX_LRCLK_INV_WIDTH                1  /* AIF1TX_LRCLK_INV */
+#define WM2200_AIF1TX_LRCLK_FRC                 0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM2200_AIF1TX_LRCLK_FRC_MASK            0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM2200_AIF1TX_LRCLK_FRC_SHIFT                1  /* AIF1TX_LRCLK_FRC */
+#define WM2200_AIF1TX_LRCLK_FRC_WIDTH                1  /* AIF1TX_LRCLK_FRC */
+#define WM2200_AIF1TX_LRCLK_MSTR                0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM2200_AIF1TX_LRCLK_MSTR_MASK           0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM2200_AIF1TX_LRCLK_MSTR_SHIFT               0  /* AIF1TX_LRCLK_MSTR */
+#define WM2200_AIF1TX_LRCLK_MSTR_WIDTH               1  /* AIF1TX_LRCLK_MSTR */
+
+/*
+ * R1282 (0x502) - Audio IF 1_3
+ */
+#define WM2200_AIF1RX_LRCLK_INV                 0x0004  /* AIF1RX_LRCLK_INV */
+#define WM2200_AIF1RX_LRCLK_INV_MASK            0x0004  /* AIF1RX_LRCLK_INV */
+#define WM2200_AIF1RX_LRCLK_INV_SHIFT                2  /* AIF1RX_LRCLK_INV */
+#define WM2200_AIF1RX_LRCLK_INV_WIDTH                1  /* AIF1RX_LRCLK_INV */
+#define WM2200_AIF1RX_LRCLK_FRC                 0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM2200_AIF1RX_LRCLK_FRC_MASK            0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM2200_AIF1RX_LRCLK_FRC_SHIFT                1  /* AIF1RX_LRCLK_FRC */
+#define WM2200_AIF1RX_LRCLK_FRC_WIDTH                1  /* AIF1RX_LRCLK_FRC */
+#define WM2200_AIF1RX_LRCLK_MSTR                0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM2200_AIF1RX_LRCLK_MSTR_MASK           0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM2200_AIF1RX_LRCLK_MSTR_SHIFT               0  /* AIF1RX_LRCLK_MSTR */
+#define WM2200_AIF1RX_LRCLK_MSTR_WIDTH               1  /* AIF1RX_LRCLK_MSTR */
+
+/*
+ * R1283 (0x503) - Audio IF 1_4
+ */
+#define WM2200_AIF1_TRI                         0x0040  /* AIF1_TRI */
+#define WM2200_AIF1_TRI_MASK                    0x0040  /* AIF1_TRI */
+#define WM2200_AIF1_TRI_SHIFT                        6  /* AIF1_TRI */
+#define WM2200_AIF1_TRI_WIDTH                        1  /* AIF1_TRI */
+
+/*
+ * R1284 (0x504) - Audio IF 1_5
+ */
+#define WM2200_AIF1_FMT_MASK                    0x0007  /* AIF1_FMT - [2:0] */
+#define WM2200_AIF1_FMT_SHIFT                        0  /* AIF1_FMT - [2:0] */
+#define WM2200_AIF1_FMT_WIDTH                        3  /* AIF1_FMT - [2:0] */
+
+/*
+ * R1285 (0x505) - Audio IF 1_6
+ */
+#define WM2200_AIF1TX_BCPF_MASK                 0x07FF  /* AIF1TX_BCPF - [10:0] */
+#define WM2200_AIF1TX_BCPF_SHIFT                     0  /* AIF1TX_BCPF - [10:0] */
+#define WM2200_AIF1TX_BCPF_WIDTH                    11  /* AIF1TX_BCPF - [10:0] */
+
+/*
+ * R1286 (0x506) - Audio IF 1_7
+ */
+#define WM2200_AIF1RX_BCPF_MASK                 0x07FF  /* AIF1RX_BCPF - [10:0] */
+#define WM2200_AIF1RX_BCPF_SHIFT                     0  /* AIF1RX_BCPF - [10:0] */
+#define WM2200_AIF1RX_BCPF_WIDTH                    11  /* AIF1RX_BCPF - [10:0] */
+
+/*
+ * R1287 (0x507) - Audio IF 1_8
+ */
+#define WM2200_AIF1TX_WL_MASK                   0x3F00  /* AIF1TX_WL - [13:8] */
+#define WM2200_AIF1TX_WL_SHIFT                       8  /* AIF1TX_WL - [13:8] */
+#define WM2200_AIF1TX_WL_WIDTH                       6  /* AIF1TX_WL - [13:8] */
+#define WM2200_AIF1TX_SLOT_LEN_MASK             0x00FF  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM2200_AIF1TX_SLOT_LEN_SHIFT                 0  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM2200_AIF1TX_SLOT_LEN_WIDTH                 8  /* AIF1TX_SLOT_LEN - [7:0] */
+
+/*
+ * R1288 (0x508) - Audio IF 1_9
+ */
+#define WM2200_AIF1RX_WL_MASK                   0x3F00  /* AIF1RX_WL - [13:8] */
+#define WM2200_AIF1RX_WL_SHIFT                       8  /* AIF1RX_WL - [13:8] */
+#define WM2200_AIF1RX_WL_WIDTH                       6  /* AIF1RX_WL - [13:8] */
+#define WM2200_AIF1RX_SLOT_LEN_MASK             0x00FF  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM2200_AIF1RX_SLOT_LEN_SHIFT                 0  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM2200_AIF1RX_SLOT_LEN_WIDTH                 8  /* AIF1RX_SLOT_LEN - [7:0] */
+
+/*
+ * R1289 (0x509) - Audio IF 1_10
+ */
+#define WM2200_AIF1TX1_SLOT_MASK                0x003F  /* AIF1TX1_SLOT - [5:0] */
+#define WM2200_AIF1TX1_SLOT_SHIFT                    0  /* AIF1TX1_SLOT - [5:0] */
+#define WM2200_AIF1TX1_SLOT_WIDTH                    6  /* AIF1TX1_SLOT - [5:0] */
+
+/*
+ * R1290 (0x50A) - Audio IF 1_11
+ */
+#define WM2200_AIF1TX2_SLOT_MASK                0x003F  /* AIF1TX2_SLOT - [5:0] */
+#define WM2200_AIF1TX2_SLOT_SHIFT                    0  /* AIF1TX2_SLOT - [5:0] */
+#define WM2200_AIF1TX2_SLOT_WIDTH                    6  /* AIF1TX2_SLOT - [5:0] */
+
+/*
+ * R1291 (0x50B) - Audio IF 1_12
+ */
+#define WM2200_AIF1TX3_SLOT_MASK                0x003F  /* AIF1TX3_SLOT - [5:0] */
+#define WM2200_AIF1TX3_SLOT_SHIFT                    0  /* AIF1TX3_SLOT - [5:0] */
+#define WM2200_AIF1TX3_SLOT_WIDTH                    6  /* AIF1TX3_SLOT - [5:0] */
+
+/*
+ * R1292 (0x50C) - Audio IF 1_13
+ */
+#define WM2200_AIF1TX4_SLOT_MASK                0x003F  /* AIF1TX4_SLOT - [5:0] */
+#define WM2200_AIF1TX4_SLOT_SHIFT                    0  /* AIF1TX4_SLOT - [5:0] */
+#define WM2200_AIF1TX4_SLOT_WIDTH                    6  /* AIF1TX4_SLOT - [5:0] */
+
+/*
+ * R1293 (0x50D) - Audio IF 1_14
+ */
+#define WM2200_AIF1TX5_SLOT_MASK                0x003F  /* AIF1TX5_SLOT - [5:0] */
+#define WM2200_AIF1TX5_SLOT_SHIFT                    0  /* AIF1TX5_SLOT - [5:0] */
+#define WM2200_AIF1TX5_SLOT_WIDTH                    6  /* AIF1TX5_SLOT - [5:0] */
+
+/*
+ * R1294 (0x50E) - Audio IF 1_15
+ */
+#define WM2200_AIF1TX6_SLOT_MASK                0x003F  /* AIF1TX6_SLOT - [5:0] */
+#define WM2200_AIF1TX6_SLOT_SHIFT                    0  /* AIF1TX6_SLOT - [5:0] */
+#define WM2200_AIF1TX6_SLOT_WIDTH                    6  /* AIF1TX6_SLOT - [5:0] */
+
+/*
+ * R1295 (0x50F) - Audio IF 1_16
+ */
+#define WM2200_AIF1RX1_SLOT_MASK                0x003F  /* AIF1RX1_SLOT - [5:0] */
+#define WM2200_AIF1RX1_SLOT_SHIFT                    0  /* AIF1RX1_SLOT - [5:0] */
+#define WM2200_AIF1RX1_SLOT_WIDTH                    6  /* AIF1RX1_SLOT - [5:0] */
+
+/*
+ * R1296 (0x510) - Audio IF 1_17
+ */
+#define WM2200_AIF1RX2_SLOT_MASK                0x003F  /* AIF1RX2_SLOT - [5:0] */
+#define WM2200_AIF1RX2_SLOT_SHIFT                    0  /* AIF1RX2_SLOT - [5:0] */
+#define WM2200_AIF1RX2_SLOT_WIDTH                    6  /* AIF1RX2_SLOT - [5:0] */
+
+/*
+ * R1297 (0x511) - Audio IF 1_18
+ */
+#define WM2200_AIF1RX3_SLOT_MASK                0x003F  /* AIF1RX3_SLOT - [5:0] */
+#define WM2200_AIF1RX3_SLOT_SHIFT                    0  /* AIF1RX3_SLOT - [5:0] */
+#define WM2200_AIF1RX3_SLOT_WIDTH                    6  /* AIF1RX3_SLOT - [5:0] */
+
+/*
+ * R1298 (0x512) - Audio IF 1_19
+ */
+#define WM2200_AIF1RX4_SLOT_MASK                0x003F  /* AIF1RX4_SLOT - [5:0] */
+#define WM2200_AIF1RX4_SLOT_SHIFT                    0  /* AIF1RX4_SLOT - [5:0] */
+#define WM2200_AIF1RX4_SLOT_WIDTH                    6  /* AIF1RX4_SLOT - [5:0] */
+
+/*
+ * R1299 (0x513) - Audio IF 1_20
+ */
+#define WM2200_AIF1RX5_SLOT_MASK                0x003F  /* AIF1RX5_SLOT - [5:0] */
+#define WM2200_AIF1RX5_SLOT_SHIFT                    0  /* AIF1RX5_SLOT - [5:0] */
+#define WM2200_AIF1RX5_SLOT_WIDTH                    6  /* AIF1RX5_SLOT - [5:0] */
+
+/*
+ * R1300 (0x514) - Audio IF 1_21
+ */
+#define WM2200_AIF1RX6_SLOT_MASK                0x003F  /* AIF1RX6_SLOT - [5:0] */
+#define WM2200_AIF1RX6_SLOT_SHIFT                    0  /* AIF1RX6_SLOT - [5:0] */
+#define WM2200_AIF1RX6_SLOT_WIDTH                    6  /* AIF1RX6_SLOT - [5:0] */
+
+/*
+ * R1301 (0x515) - Audio IF 1_22
+ */
+#define WM2200_AIF1RX6_ENA                      0x0800  /* AIF1RX6_ENA */
+#define WM2200_AIF1RX6_ENA_MASK                 0x0800  /* AIF1RX6_ENA */
+#define WM2200_AIF1RX6_ENA_SHIFT                    11  /* AIF1RX6_ENA */
+#define WM2200_AIF1RX6_ENA_WIDTH                     1  /* AIF1RX6_ENA */
+#define WM2200_AIF1RX5_ENA                      0x0400  /* AIF1RX5_ENA */
+#define WM2200_AIF1RX5_ENA_MASK                 0x0400  /* AIF1RX5_ENA */
+#define WM2200_AIF1RX5_ENA_SHIFT                    10  /* AIF1RX5_ENA */
+#define WM2200_AIF1RX5_ENA_WIDTH                     1  /* AIF1RX5_ENA */
+#define WM2200_AIF1RX4_ENA                      0x0200  /* AIF1RX4_ENA */
+#define WM2200_AIF1RX4_ENA_MASK                 0x0200  /* AIF1RX4_ENA */
+#define WM2200_AIF1RX4_ENA_SHIFT                     9  /* AIF1RX4_ENA */
+#define WM2200_AIF1RX4_ENA_WIDTH                     1  /* AIF1RX4_ENA */
+#define WM2200_AIF1RX3_ENA                      0x0100  /* AIF1RX3_ENA */
+#define WM2200_AIF1RX3_ENA_MASK                 0x0100  /* AIF1RX3_ENA */
+#define WM2200_AIF1RX3_ENA_SHIFT                     8  /* AIF1RX3_ENA */
+#define WM2200_AIF1RX3_ENA_WIDTH                     1  /* AIF1RX3_ENA */
+#define WM2200_AIF1RX2_ENA                      0x0080  /* AIF1RX2_ENA */
+#define WM2200_AIF1RX2_ENA_MASK                 0x0080  /* AIF1RX2_ENA */
+#define WM2200_AIF1RX2_ENA_SHIFT                     7  /* AIF1RX2_ENA */
+#define WM2200_AIF1RX2_ENA_WIDTH                     1  /* AIF1RX2_ENA */
+#define WM2200_AIF1RX1_ENA                      0x0040  /* AIF1RX1_ENA */
+#define WM2200_AIF1RX1_ENA_MASK                 0x0040  /* AIF1RX1_ENA */
+#define WM2200_AIF1RX1_ENA_SHIFT                     6  /* AIF1RX1_ENA */
+#define WM2200_AIF1RX1_ENA_WIDTH                     1  /* AIF1RX1_ENA */
+#define WM2200_AIF1TX6_ENA                      0x0020  /* AIF1TX6_ENA */
+#define WM2200_AIF1TX6_ENA_MASK                 0x0020  /* AIF1TX6_ENA */
+#define WM2200_AIF1TX6_ENA_SHIFT                     5  /* AIF1TX6_ENA */
+#define WM2200_AIF1TX6_ENA_WIDTH                     1  /* AIF1TX6_ENA */
+#define WM2200_AIF1TX5_ENA                      0x0010  /* AIF1TX5_ENA */
+#define WM2200_AIF1TX5_ENA_MASK                 0x0010  /* AIF1TX5_ENA */
+#define WM2200_AIF1TX5_ENA_SHIFT                     4  /* AIF1TX5_ENA */
+#define WM2200_AIF1TX5_ENA_WIDTH                     1  /* AIF1TX5_ENA */
+#define WM2200_AIF1TX4_ENA                      0x0008  /* AIF1TX4_ENA */
+#define WM2200_AIF1TX4_ENA_MASK                 0x0008  /* AIF1TX4_ENA */
+#define WM2200_AIF1TX4_ENA_SHIFT                     3  /* AIF1TX4_ENA */
+#define WM2200_AIF1TX4_ENA_WIDTH                     1  /* AIF1TX4_ENA */
+#define WM2200_AIF1TX3_ENA                      0x0004  /* AIF1TX3_ENA */
+#define WM2200_AIF1TX3_ENA_MASK                 0x0004  /* AIF1TX3_ENA */
+#define WM2200_AIF1TX3_ENA_SHIFT                     2  /* AIF1TX3_ENA */
+#define WM2200_AIF1TX3_ENA_WIDTH                     1  /* AIF1TX3_ENA */
+#define WM2200_AIF1TX2_ENA                      0x0002  /* AIF1TX2_ENA */
+#define WM2200_AIF1TX2_ENA_MASK                 0x0002  /* AIF1TX2_ENA */
+#define WM2200_AIF1TX2_ENA_SHIFT                     1  /* AIF1TX2_ENA */
+#define WM2200_AIF1TX2_ENA_WIDTH                     1  /* AIF1TX2_ENA */
+#define WM2200_AIF1TX1_ENA                      0x0001  /* AIF1TX1_ENA */
+#define WM2200_AIF1TX1_ENA_MASK                 0x0001  /* AIF1TX1_ENA */
+#define WM2200_AIF1TX1_ENA_SHIFT                     0  /* AIF1TX1_ENA */
+#define WM2200_AIF1TX1_ENA_WIDTH                     1  /* AIF1TX1_ENA */
+
+/*
+ * R1536 (0x600) - OUT1LMIX Input 1 Source
+ */
+#define WM2200_OUT1LMIX_SRC1_MASK               0x007F  /* OUT1LMIX_SRC1 - [6:0] */
+#define WM2200_OUT1LMIX_SRC1_SHIFT                   0  /* OUT1LMIX_SRC1 - [6:0] */
+#define WM2200_OUT1LMIX_SRC1_WIDTH                   7  /* OUT1LMIX_SRC1 - [6:0] */
+
+/*
+ * R1537 (0x601) - OUT1LMIX Input 1 Volume
+ */
+#define WM2200_OUT1LMIX_VOL1_MASK               0x00FE  /* OUT1LMIX_VOL1 - [7:1] */
+#define WM2200_OUT1LMIX_VOL1_SHIFT                   1  /* OUT1LMIX_VOL1 - [7:1] */
+#define WM2200_OUT1LMIX_VOL1_WIDTH                   7  /* OUT1LMIX_VOL1 - [7:1] */
+
+/*
+ * R1538 (0x602) - OUT1LMIX Input 2 Source
+ */
+#define WM2200_OUT1LMIX_SRC2_MASK               0x007F  /* OUT1LMIX_SRC2 - [6:0] */
+#define WM2200_OUT1LMIX_SRC2_SHIFT                   0  /* OUT1LMIX_SRC2 - [6:0] */
+#define WM2200_OUT1LMIX_SRC2_WIDTH                   7  /* OUT1LMIX_SRC2 - [6:0] */
+
+/*
+ * R1539 (0x603) - OUT1LMIX Input 2 Volume
+ */
+#define WM2200_OUT1LMIX_VOL2_MASK               0x00FE  /* OUT1LMIX_VOL2 - [7:1] */
+#define WM2200_OUT1LMIX_VOL2_SHIFT                   1  /* OUT1LMIX_VOL2 - [7:1] */
+#define WM2200_OUT1LMIX_VOL2_WIDTH                   7  /* OUT1LMIX_VOL2 - [7:1] */
+
+/*
+ * R1540 (0x604) - OUT1LMIX Input 3 Source
+ */
+#define WM2200_OUT1LMIX_SRC3_MASK               0x007F  /* OUT1LMIX_SRC3 - [6:0] */
+#define WM2200_OUT1LMIX_SRC3_SHIFT                   0  /* OUT1LMIX_SRC3 - [6:0] */
+#define WM2200_OUT1LMIX_SRC3_WIDTH                   7  /* OUT1LMIX_SRC3 - [6:0] */
+
+/*
+ * R1541 (0x605) - OUT1LMIX Input 3 Volume
+ */
+#define WM2200_OUT1LMIX_VOL3_MASK               0x00FE  /* OUT1LMIX_VOL3 - [7:1] */
+#define WM2200_OUT1LMIX_VOL3_SHIFT                   1  /* OUT1LMIX_VOL3 - [7:1] */
+#define WM2200_OUT1LMIX_VOL3_WIDTH                   7  /* OUT1LMIX_VOL3 - [7:1] */
+
+/*
+ * R1542 (0x606) - OUT1LMIX Input 4 Source
+ */
+#define WM2200_OUT1LMIX_SRC4_MASK               0x007F  /* OUT1LMIX_SRC4 - [6:0] */
+#define WM2200_OUT1LMIX_SRC4_SHIFT                   0  /* OUT1LMIX_SRC4 - [6:0] */
+#define WM2200_OUT1LMIX_SRC4_WIDTH                   7  /* OUT1LMIX_SRC4 - [6:0] */
+
+/*
+ * R1543 (0x607) - OUT1LMIX Input 4 Volume
+ */
+#define WM2200_OUT1LMIX_VOL4_MASK               0x00FE  /* OUT1LMIX_VOL4 - [7:1] */
+#define WM2200_OUT1LMIX_VOL4_SHIFT                   1  /* OUT1LMIX_VOL4 - [7:1] */
+#define WM2200_OUT1LMIX_VOL4_WIDTH                   7  /* OUT1LMIX_VOL4 - [7:1] */
+
+/*
+ * R1544 (0x608) - OUT1RMIX Input 1 Source
+ */
+#define WM2200_OUT1RMIX_SRC1_MASK               0x007F  /* OUT1RMIX_SRC1 - [6:0] */
+#define WM2200_OUT1RMIX_SRC1_SHIFT                   0  /* OUT1RMIX_SRC1 - [6:0] */
+#define WM2200_OUT1RMIX_SRC1_WIDTH                   7  /* OUT1RMIX_SRC1 - [6:0] */
+
+/*
+ * R1545 (0x609) - OUT1RMIX Input 1 Volume
+ */
+#define WM2200_OUT1RMIX_VOL1_MASK               0x00FE  /* OUT1RMIX_VOL1 - [7:1] */
+#define WM2200_OUT1RMIX_VOL1_SHIFT                   1  /* OUT1RMIX_VOL1 - [7:1] */
+#define WM2200_OUT1RMIX_VOL1_WIDTH                   7  /* OUT1RMIX_VOL1 - [7:1] */
+
+/*
+ * R1546 (0x60A) - OUT1RMIX Input 2 Source
+ */
+#define WM2200_OUT1RMIX_SRC2_MASK               0x007F  /* OUT1RMIX_SRC2 - [6:0] */
+#define WM2200_OUT1RMIX_SRC2_SHIFT                   0  /* OUT1RMIX_SRC2 - [6:0] */
+#define WM2200_OUT1RMIX_SRC2_WIDTH                   7  /* OUT1RMIX_SRC2 - [6:0] */
+
+/*
+ * R1547 (0x60B) - OUT1RMIX Input 2 Volume
+ */
+#define WM2200_OUT1RMIX_VOL2_MASK               0x00FE  /* OUT1RMIX_VOL2 - [7:1] */
+#define WM2200_OUT1RMIX_VOL2_SHIFT                   1  /* OUT1RMIX_VOL2 - [7:1] */
+#define WM2200_OUT1RMIX_VOL2_WIDTH                   7  /* OUT1RMIX_VOL2 - [7:1] */
+
+/*
+ * R1548 (0x60C) - OUT1RMIX Input 3 Source
+ */
+#define WM2200_OUT1RMIX_SRC3_MASK               0x007F  /* OUT1RMIX_SRC3 - [6:0] */
+#define WM2200_OUT1RMIX_SRC3_SHIFT                   0  /* OUT1RMIX_SRC3 - [6:0] */
+#define WM2200_OUT1RMIX_SRC3_WIDTH                   7  /* OUT1RMIX_SRC3 - [6:0] */
+
+/*
+ * R1549 (0x60D) - OUT1RMIX Input 3 Volume
+ */
+#define WM2200_OUT1RMIX_VOL3_MASK               0x00FE  /* OUT1RMIX_VOL3 - [7:1] */
+#define WM2200_OUT1RMIX_VOL3_SHIFT                   1  /* OUT1RMIX_VOL3 - [7:1] */
+#define WM2200_OUT1RMIX_VOL3_WIDTH                   7  /* OUT1RMIX_VOL3 - [7:1] */
+
+/*
+ * R1550 (0x60E) - OUT1RMIX Input 4 Source
+ */
+#define WM2200_OUT1RMIX_SRC4_MASK               0x007F  /* OUT1RMIX_SRC4 - [6:0] */
+#define WM2200_OUT1RMIX_SRC4_SHIFT                   0  /* OUT1RMIX_SRC4 - [6:0] */
+#define WM2200_OUT1RMIX_SRC4_WIDTH                   7  /* OUT1RMIX_SRC4 - [6:0] */
+
+/*
+ * R1551 (0x60F) - OUT1RMIX Input 4 Volume
+ */
+#define WM2200_OUT1RMIX_VOL4_MASK               0x00FE  /* OUT1RMIX_VOL4 - [7:1] */
+#define WM2200_OUT1RMIX_VOL4_SHIFT                   1  /* OUT1RMIX_VOL4 - [7:1] */
+#define WM2200_OUT1RMIX_VOL4_WIDTH                   7  /* OUT1RMIX_VOL4 - [7:1] */
+
+/*
+ * R1552 (0x610) - OUT2LMIX Input 1 Source
+ */
+#define WM2200_OUT2LMIX_SRC1_MASK               0x007F  /* OUT2LMIX_SRC1 - [6:0] */
+#define WM2200_OUT2LMIX_SRC1_SHIFT                   0  /* OUT2LMIX_SRC1 - [6:0] */
+#define WM2200_OUT2LMIX_SRC1_WIDTH                   7  /* OUT2LMIX_SRC1 - [6:0] */
+
+/*
+ * R1553 (0x611) - OUT2LMIX Input 1 Volume
+ */
+#define WM2200_OUT2LMIX_VOL1_MASK               0x00FE  /* OUT2LMIX_VOL1 - [7:1] */
+#define WM2200_OUT2LMIX_VOL1_SHIFT                   1  /* OUT2LMIX_VOL1 - [7:1] */
+#define WM2200_OUT2LMIX_VOL1_WIDTH                   7  /* OUT2LMIX_VOL1 - [7:1] */
+
+/*
+ * R1554 (0x612) - OUT2LMIX Input 2 Source
+ */
+#define WM2200_OUT2LMIX_SRC2_MASK               0x007F  /* OUT2LMIX_SRC2 - [6:0] */
+#define WM2200_OUT2LMIX_SRC2_SHIFT                   0  /* OUT2LMIX_SRC2 - [6:0] */
+#define WM2200_OUT2LMIX_SRC2_WIDTH                   7  /* OUT2LMIX_SRC2 - [6:0] */
+
+/*
+ * R1555 (0x613) - OUT2LMIX Input 2 Volume
+ */
+#define WM2200_OUT2LMIX_VOL2_MASK               0x00FE  /* OUT2LMIX_VOL2 - [7:1] */
+#define WM2200_OUT2LMIX_VOL2_SHIFT                   1  /* OUT2LMIX_VOL2 - [7:1] */
+#define WM2200_OUT2LMIX_VOL2_WIDTH                   7  /* OUT2LMIX_VOL2 - [7:1] */
+
+/*
+ * R1556 (0x614) - OUT2LMIX Input 3 Source
+ */
+#define WM2200_OUT2LMIX_SRC3_MASK               0x007F  /* OUT2LMIX_SRC3 - [6:0] */
+#define WM2200_OUT2LMIX_SRC3_SHIFT                   0  /* OUT2LMIX_SRC3 - [6:0] */
+#define WM2200_OUT2LMIX_SRC3_WIDTH                   7  /* OUT2LMIX_SRC3 - [6:0] */
+
+/*
+ * R1557 (0x615) - OUT2LMIX Input 3 Volume
+ */
+#define WM2200_OUT2LMIX_VOL3_MASK               0x00FE  /* OUT2LMIX_VOL3 - [7:1] */
+#define WM2200_OUT2LMIX_VOL3_SHIFT                   1  /* OUT2LMIX_VOL3 - [7:1] */
+#define WM2200_OUT2LMIX_VOL3_WIDTH                   7  /* OUT2LMIX_VOL3 - [7:1] */
+
+/*
+ * R1558 (0x616) - OUT2LMIX Input 4 Source
+ */
+#define WM2200_OUT2LMIX_SRC4_MASK               0x007F  /* OUT2LMIX_SRC4 - [6:0] */
+#define WM2200_OUT2LMIX_SRC4_SHIFT                   0  /* OUT2LMIX_SRC4 - [6:0] */
+#define WM2200_OUT2LMIX_SRC4_WIDTH                   7  /* OUT2LMIX_SRC4 - [6:0] */
+
+/*
+ * R1559 (0x617) - OUT2LMIX Input 4 Volume
+ */
+#define WM2200_OUT2LMIX_VOL4_MASK               0x00FE  /* OUT2LMIX_VOL4 - [7:1] */
+#define WM2200_OUT2LMIX_VOL4_SHIFT                   1  /* OUT2LMIX_VOL4 - [7:1] */
+#define WM2200_OUT2LMIX_VOL4_WIDTH                   7  /* OUT2LMIX_VOL4 - [7:1] */
+
+/*
+ * R1560 (0x618) - OUT2RMIX Input 1 Source
+ */
+#define WM2200_OUT2RMIX_SRC1_MASK               0x007F  /* OUT2RMIX_SRC1 - [6:0] */
+#define WM2200_OUT2RMIX_SRC1_SHIFT                   0  /* OUT2RMIX_SRC1 - [6:0] */
+#define WM2200_OUT2RMIX_SRC1_WIDTH                   7  /* OUT2RMIX_SRC1 - [6:0] */
+
+/*
+ * R1561 (0x619) - OUT2RMIX Input 1 Volume
+ */
+#define WM2200_OUT2RMIX_VOL1_MASK               0x00FE  /* OUT2RMIX_VOL1 - [7:1] */
+#define WM2200_OUT2RMIX_VOL1_SHIFT                   1  /* OUT2RMIX_VOL1 - [7:1] */
+#define WM2200_OUT2RMIX_VOL1_WIDTH                   7  /* OUT2RMIX_VOL1 - [7:1] */
+
+/*
+ * R1562 (0x61A) - OUT2RMIX Input 2 Source
+ */
+#define WM2200_OUT2RMIX_SRC2_MASK               0x007F  /* OUT2RMIX_SRC2 - [6:0] */
+#define WM2200_OUT2RMIX_SRC2_SHIFT                   0  /* OUT2RMIX_SRC2 - [6:0] */
+#define WM2200_OUT2RMIX_SRC2_WIDTH                   7  /* OUT2RMIX_SRC2 - [6:0] */
+
+/*
+ * R1563 (0x61B) - OUT2RMIX Input 2 Volume
+ */
+#define WM2200_OUT2RMIX_VOL2_MASK               0x00FE  /* OUT2RMIX_VOL2 - [7:1] */
+#define WM2200_OUT2RMIX_VOL2_SHIFT                   1  /* OUT2RMIX_VOL2 - [7:1] */
+#define WM2200_OUT2RMIX_VOL2_WIDTH                   7  /* OUT2RMIX_VOL2 - [7:1] */
+
+/*
+ * R1564 (0x61C) - OUT2RMIX Input 3 Source
+ */
+#define WM2200_OUT2RMIX_SRC3_MASK               0x007F  /* OUT2RMIX_SRC3 - [6:0] */
+#define WM2200_OUT2RMIX_SRC3_SHIFT                   0  /* OUT2RMIX_SRC3 - [6:0] */
+#define WM2200_OUT2RMIX_SRC3_WIDTH                   7  /* OUT2RMIX_SRC3 - [6:0] */
+
+/*
+ * R1565 (0x61D) - OUT2RMIX Input 3 Volume
+ */
+#define WM2200_OUT2RMIX_VOL3_MASK               0x00FE  /* OUT2RMIX_VOL3 - [7:1] */
+#define WM2200_OUT2RMIX_VOL3_SHIFT                   1  /* OUT2RMIX_VOL3 - [7:1] */
+#define WM2200_OUT2RMIX_VOL3_WIDTH                   7  /* OUT2RMIX_VOL3 - [7:1] */
+
+/*
+ * R1566 (0x61E) - OUT2RMIX Input 4 Source
+ */
+#define WM2200_OUT2RMIX_SRC4_MASK               0x007F  /* OUT2RMIX_SRC4 - [6:0] */
+#define WM2200_OUT2RMIX_SRC4_SHIFT                   0  /* OUT2RMIX_SRC4 - [6:0] */
+#define WM2200_OUT2RMIX_SRC4_WIDTH                   7  /* OUT2RMIX_SRC4 - [6:0] */
+
+/*
+ * R1567 (0x61F) - OUT2RMIX Input 4 Volume
+ */
+#define WM2200_OUT2RMIX_VOL4_MASK               0x00FE  /* OUT2RMIX_VOL4 - [7:1] */
+#define WM2200_OUT2RMIX_VOL4_SHIFT                   1  /* OUT2RMIX_VOL4 - [7:1] */
+#define WM2200_OUT2RMIX_VOL4_WIDTH                   7  /* OUT2RMIX_VOL4 - [7:1] */
+
+/*
+ * R1568 (0x620) - AIF1TX1MIX Input 1 Source
+ */
+#define WM2200_AIF1TX1MIX_SRC1_MASK             0x007F  /* AIF1TX1MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC1_SHIFT                 0  /* AIF1TX1MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC1_WIDTH                 7  /* AIF1TX1MIX_SRC1 - [6:0] */
+
+/*
+ * R1569 (0x621) - AIF1TX1MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX1MIX_VOL1_MASK             0x00FE  /* AIF1TX1MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL1_SHIFT                 1  /* AIF1TX1MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL1_WIDTH                 7  /* AIF1TX1MIX_VOL1 - [7:1] */
+
+/*
+ * R1570 (0x622) - AIF1TX1MIX Input 2 Source
+ */
+#define WM2200_AIF1TX1MIX_SRC2_MASK             0x007F  /* AIF1TX1MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC2_SHIFT                 0  /* AIF1TX1MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC2_WIDTH                 7  /* AIF1TX1MIX_SRC2 - [6:0] */
+
+/*
+ * R1571 (0x623) - AIF1TX1MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX1MIX_VOL2_MASK             0x00FE  /* AIF1TX1MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL2_SHIFT                 1  /* AIF1TX1MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL2_WIDTH                 7  /* AIF1TX1MIX_VOL2 - [7:1] */
+
+/*
+ * R1572 (0x624) - AIF1TX1MIX Input 3 Source
+ */
+#define WM2200_AIF1TX1MIX_SRC3_MASK             0x007F  /* AIF1TX1MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC3_SHIFT                 0  /* AIF1TX1MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC3_WIDTH                 7  /* AIF1TX1MIX_SRC3 - [6:0] */
+
+/*
+ * R1573 (0x625) - AIF1TX1MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX1MIX_VOL3_MASK             0x00FE  /* AIF1TX1MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL3_SHIFT                 1  /* AIF1TX1MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL3_WIDTH                 7  /* AIF1TX1MIX_VOL3 - [7:1] */
+
+/*
+ * R1574 (0x626) - AIF1TX1MIX Input 4 Source
+ */
+#define WM2200_AIF1TX1MIX_SRC4_MASK             0x007F  /* AIF1TX1MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC4_SHIFT                 0  /* AIF1TX1MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX1MIX_SRC4_WIDTH                 7  /* AIF1TX1MIX_SRC4 - [6:0] */
+
+/*
+ * R1575 (0x627) - AIF1TX1MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX1MIX_VOL4_MASK             0x00FE  /* AIF1TX1MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL4_SHIFT                 1  /* AIF1TX1MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX1MIX_VOL4_WIDTH                 7  /* AIF1TX1MIX_VOL4 - [7:1] */
+
+/*
+ * R1576 (0x628) - AIF1TX2MIX Input 1 Source
+ */
+#define WM2200_AIF1TX2MIX_SRC1_MASK             0x007F  /* AIF1TX2MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC1_SHIFT                 0  /* AIF1TX2MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC1_WIDTH                 7  /* AIF1TX2MIX_SRC1 - [6:0] */
+
+/*
+ * R1577 (0x629) - AIF1TX2MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX2MIX_VOL1_MASK             0x00FE  /* AIF1TX2MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL1_SHIFT                 1  /* AIF1TX2MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL1_WIDTH                 7  /* AIF1TX2MIX_VOL1 - [7:1] */
+
+/*
+ * R1578 (0x62A) - AIF1TX2MIX Input 2 Source
+ */
+#define WM2200_AIF1TX2MIX_SRC2_MASK             0x007F  /* AIF1TX2MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC2_SHIFT                 0  /* AIF1TX2MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC2_WIDTH                 7  /* AIF1TX2MIX_SRC2 - [6:0] */
+
+/*
+ * R1579 (0x62B) - AIF1TX2MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX2MIX_VOL2_MASK             0x00FE  /* AIF1TX2MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL2_SHIFT                 1  /* AIF1TX2MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL2_WIDTH                 7  /* AIF1TX2MIX_VOL2 - [7:1] */
+
+/*
+ * R1580 (0x62C) - AIF1TX2MIX Input 3 Source
+ */
+#define WM2200_AIF1TX2MIX_SRC3_MASK             0x007F  /* AIF1TX2MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC3_SHIFT                 0  /* AIF1TX2MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC3_WIDTH                 7  /* AIF1TX2MIX_SRC3 - [6:0] */
+
+/*
+ * R1581 (0x62D) - AIF1TX2MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX2MIX_VOL3_MASK             0x00FE  /* AIF1TX2MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL3_SHIFT                 1  /* AIF1TX2MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL3_WIDTH                 7  /* AIF1TX2MIX_VOL3 - [7:1] */
+
+/*
+ * R1582 (0x62E) - AIF1TX2MIX Input 4 Source
+ */
+#define WM2200_AIF1TX2MIX_SRC4_MASK             0x007F  /* AIF1TX2MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC4_SHIFT                 0  /* AIF1TX2MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX2MIX_SRC4_WIDTH                 7  /* AIF1TX2MIX_SRC4 - [6:0] */
+
+/*
+ * R1583 (0x62F) - AIF1TX2MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX2MIX_VOL4_MASK             0x00FE  /* AIF1TX2MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL4_SHIFT                 1  /* AIF1TX2MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX2MIX_VOL4_WIDTH                 7  /* AIF1TX2MIX_VOL4 - [7:1] */
+
+/*
+ * R1584 (0x630) - AIF1TX3MIX Input 1 Source
+ */
+#define WM2200_AIF1TX3MIX_SRC1_MASK             0x007F  /* AIF1TX3MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC1_SHIFT                 0  /* AIF1TX3MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC1_WIDTH                 7  /* AIF1TX3MIX_SRC1 - [6:0] */
+
+/*
+ * R1585 (0x631) - AIF1TX3MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX3MIX_VOL1_MASK             0x00FE  /* AIF1TX3MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL1_SHIFT                 1  /* AIF1TX3MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL1_WIDTH                 7  /* AIF1TX3MIX_VOL1 - [7:1] */
+
+/*
+ * R1586 (0x632) - AIF1TX3MIX Input 2 Source
+ */
+#define WM2200_AIF1TX3MIX_SRC2_MASK             0x007F  /* AIF1TX3MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC2_SHIFT                 0  /* AIF1TX3MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC2_WIDTH                 7  /* AIF1TX3MIX_SRC2 - [6:0] */
+
+/*
+ * R1587 (0x633) - AIF1TX3MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX3MIX_VOL2_MASK             0x00FE  /* AIF1TX3MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL2_SHIFT                 1  /* AIF1TX3MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL2_WIDTH                 7  /* AIF1TX3MIX_VOL2 - [7:1] */
+
+/*
+ * R1588 (0x634) - AIF1TX3MIX Input 3 Source
+ */
+#define WM2200_AIF1TX3MIX_SRC3_MASK             0x007F  /* AIF1TX3MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC3_SHIFT                 0  /* AIF1TX3MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC3_WIDTH                 7  /* AIF1TX3MIX_SRC3 - [6:0] */
+
+/*
+ * R1589 (0x635) - AIF1TX3MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX3MIX_VOL3_MASK             0x00FE  /* AIF1TX3MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL3_SHIFT                 1  /* AIF1TX3MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL3_WIDTH                 7  /* AIF1TX3MIX_VOL3 - [7:1] */
+
+/*
+ * R1590 (0x636) - AIF1TX3MIX Input 4 Source
+ */
+#define WM2200_AIF1TX3MIX_SRC4_MASK             0x007F  /* AIF1TX3MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC4_SHIFT                 0  /* AIF1TX3MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX3MIX_SRC4_WIDTH                 7  /* AIF1TX3MIX_SRC4 - [6:0] */
+
+/*
+ * R1591 (0x637) - AIF1TX3MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX3MIX_VOL4_MASK             0x00FE  /* AIF1TX3MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL4_SHIFT                 1  /* AIF1TX3MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX3MIX_VOL4_WIDTH                 7  /* AIF1TX3MIX_VOL4 - [7:1] */
+
+/*
+ * R1592 (0x638) - AIF1TX4MIX Input 1 Source
+ */
+#define WM2200_AIF1TX4MIX_SRC1_MASK             0x007F  /* AIF1TX4MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC1_SHIFT                 0  /* AIF1TX4MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC1_WIDTH                 7  /* AIF1TX4MIX_SRC1 - [6:0] */
+
+/*
+ * R1593 (0x639) - AIF1TX4MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX4MIX_VOL1_MASK             0x00FE  /* AIF1TX4MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL1_SHIFT                 1  /* AIF1TX4MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL1_WIDTH                 7  /* AIF1TX4MIX_VOL1 - [7:1] */
+
+/*
+ * R1594 (0x63A) - AIF1TX4MIX Input 2 Source
+ */
+#define WM2200_AIF1TX4MIX_SRC2_MASK             0x007F  /* AIF1TX4MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC2_SHIFT                 0  /* AIF1TX4MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC2_WIDTH                 7  /* AIF1TX4MIX_SRC2 - [6:0] */
+
+/*
+ * R1595 (0x63B) - AIF1TX4MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX4MIX_VOL2_MASK             0x00FE  /* AIF1TX4MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL2_SHIFT                 1  /* AIF1TX4MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL2_WIDTH                 7  /* AIF1TX4MIX_VOL2 - [7:1] */
+
+/*
+ * R1596 (0x63C) - AIF1TX4MIX Input 3 Source
+ */
+#define WM2200_AIF1TX4MIX_SRC3_MASK             0x007F  /* AIF1TX4MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC3_SHIFT                 0  /* AIF1TX4MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC3_WIDTH                 7  /* AIF1TX4MIX_SRC3 - [6:0] */
+
+/*
+ * R1597 (0x63D) - AIF1TX4MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX4MIX_VOL3_MASK             0x00FE  /* AIF1TX4MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL3_SHIFT                 1  /* AIF1TX4MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL3_WIDTH                 7  /* AIF1TX4MIX_VOL3 - [7:1] */
+
+/*
+ * R1598 (0x63E) - AIF1TX4MIX Input 4 Source
+ */
+#define WM2200_AIF1TX4MIX_SRC4_MASK             0x007F  /* AIF1TX4MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC4_SHIFT                 0  /* AIF1TX4MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX4MIX_SRC4_WIDTH                 7  /* AIF1TX4MIX_SRC4 - [6:0] */
+
+/*
+ * R1599 (0x63F) - AIF1TX4MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX4MIX_VOL4_MASK             0x00FE  /* AIF1TX4MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL4_SHIFT                 1  /* AIF1TX4MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX4MIX_VOL4_WIDTH                 7  /* AIF1TX4MIX_VOL4 - [7:1] */
+
+/*
+ * R1600 (0x640) - AIF1TX5MIX Input 1 Source
+ */
+#define WM2200_AIF1TX5MIX_SRC1_MASK             0x007F  /* AIF1TX5MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC1_SHIFT                 0  /* AIF1TX5MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC1_WIDTH                 7  /* AIF1TX5MIX_SRC1 - [6:0] */
+
+/*
+ * R1601 (0x641) - AIF1TX5MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX5MIX_VOL1_MASK             0x00FE  /* AIF1TX5MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL1_SHIFT                 1  /* AIF1TX5MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL1_WIDTH                 7  /* AIF1TX5MIX_VOL1 - [7:1] */
+
+/*
+ * R1602 (0x642) - AIF1TX5MIX Input 2 Source
+ */
+#define WM2200_AIF1TX5MIX_SRC2_MASK             0x007F  /* AIF1TX5MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC2_SHIFT                 0  /* AIF1TX5MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC2_WIDTH                 7  /* AIF1TX5MIX_SRC2 - [6:0] */
+
+/*
+ * R1603 (0x643) - AIF1TX5MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX5MIX_VOL2_MASK             0x00FE  /* AIF1TX5MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL2_SHIFT                 1  /* AIF1TX5MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL2_WIDTH                 7  /* AIF1TX5MIX_VOL2 - [7:1] */
+
+/*
+ * R1604 (0x644) - AIF1TX5MIX Input 3 Source
+ */
+#define WM2200_AIF1TX5MIX_SRC3_MASK             0x007F  /* AIF1TX5MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC3_SHIFT                 0  /* AIF1TX5MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC3_WIDTH                 7  /* AIF1TX5MIX_SRC3 - [6:0] */
+
+/*
+ * R1605 (0x645) - AIF1TX5MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX5MIX_VOL3_MASK             0x00FE  /* AIF1TX5MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL3_SHIFT                 1  /* AIF1TX5MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL3_WIDTH                 7  /* AIF1TX5MIX_VOL3 - [7:1] */
+
+/*
+ * R1606 (0x646) - AIF1TX5MIX Input 4 Source
+ */
+#define WM2200_AIF1TX5MIX_SRC4_MASK             0x007F  /* AIF1TX5MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC4_SHIFT                 0  /* AIF1TX5MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX5MIX_SRC4_WIDTH                 7  /* AIF1TX5MIX_SRC4 - [6:0] */
+
+/*
+ * R1607 (0x647) - AIF1TX5MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX5MIX_VOL4_MASK             0x00FE  /* AIF1TX5MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL4_SHIFT                 1  /* AIF1TX5MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX5MIX_VOL4_WIDTH                 7  /* AIF1TX5MIX_VOL4 - [7:1] */
+
+/*
+ * R1608 (0x648) - AIF1TX6MIX Input 1 Source
+ */
+#define WM2200_AIF1TX6MIX_SRC1_MASK             0x007F  /* AIF1TX6MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC1_SHIFT                 0  /* AIF1TX6MIX_SRC1 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC1_WIDTH                 7  /* AIF1TX6MIX_SRC1 - [6:0] */
+
+/*
+ * R1609 (0x649) - AIF1TX6MIX Input 1 Volume
+ */
+#define WM2200_AIF1TX6MIX_VOL1_MASK             0x00FE  /* AIF1TX6MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL1_SHIFT                 1  /* AIF1TX6MIX_VOL1 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL1_WIDTH                 7  /* AIF1TX6MIX_VOL1 - [7:1] */
+
+/*
+ * R1610 (0x64A) - AIF1TX6MIX Input 2 Source
+ */
+#define WM2200_AIF1TX6MIX_SRC2_MASK             0x007F  /* AIF1TX6MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC2_SHIFT                 0  /* AIF1TX6MIX_SRC2 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC2_WIDTH                 7  /* AIF1TX6MIX_SRC2 - [6:0] */
+
+/*
+ * R1611 (0x64B) - AIF1TX6MIX Input 2 Volume
+ */
+#define WM2200_AIF1TX6MIX_VOL2_MASK             0x00FE  /* AIF1TX6MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL2_SHIFT                 1  /* AIF1TX6MIX_VOL2 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL2_WIDTH                 7  /* AIF1TX6MIX_VOL2 - [7:1] */
+
+/*
+ * R1612 (0x64C) - AIF1TX6MIX Input 3 Source
+ */
+#define WM2200_AIF1TX6MIX_SRC3_MASK             0x007F  /* AIF1TX6MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC3_SHIFT                 0  /* AIF1TX6MIX_SRC3 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC3_WIDTH                 7  /* AIF1TX6MIX_SRC3 - [6:0] */
+
+/*
+ * R1613 (0x64D) - AIF1TX6MIX Input 3 Volume
+ */
+#define WM2200_AIF1TX6MIX_VOL3_MASK             0x00FE  /* AIF1TX6MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL3_SHIFT                 1  /* AIF1TX6MIX_VOL3 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL3_WIDTH                 7  /* AIF1TX6MIX_VOL3 - [7:1] */
+
+/*
+ * R1614 (0x64E) - AIF1TX6MIX Input 4 Source
+ */
+#define WM2200_AIF1TX6MIX_SRC4_MASK             0x007F  /* AIF1TX6MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC4_SHIFT                 0  /* AIF1TX6MIX_SRC4 - [6:0] */
+#define WM2200_AIF1TX6MIX_SRC4_WIDTH                 7  /* AIF1TX6MIX_SRC4 - [6:0] */
+
+/*
+ * R1615 (0x64F) - AIF1TX6MIX Input 4 Volume
+ */
+#define WM2200_AIF1TX6MIX_VOL4_MASK             0x00FE  /* AIF1TX6MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL4_SHIFT                 1  /* AIF1TX6MIX_VOL4 - [7:1] */
+#define WM2200_AIF1TX6MIX_VOL4_WIDTH                 7  /* AIF1TX6MIX_VOL4 - [7:1] */
+
+/*
+ * R1616 (0x650) - EQLMIX Input 1 Source
+ */
+#define WM2200_EQLMIX_SRC1_MASK                 0x007F  /* EQLMIX_SRC1 - [6:0] */
+#define WM2200_EQLMIX_SRC1_SHIFT                     0  /* EQLMIX_SRC1 - [6:0] */
+#define WM2200_EQLMIX_SRC1_WIDTH                     7  /* EQLMIX_SRC1 - [6:0] */
+
+/*
+ * R1617 (0x651) - EQLMIX Input 1 Volume
+ */
+#define WM2200_EQLMIX_VOL1_MASK                 0x00FE  /* EQLMIX_VOL1 - [7:1] */
+#define WM2200_EQLMIX_VOL1_SHIFT                     1  /* EQLMIX_VOL1 - [7:1] */
+#define WM2200_EQLMIX_VOL1_WIDTH                     7  /* EQLMIX_VOL1 - [7:1] */
+
+/*
+ * R1618 (0x652) - EQLMIX Input 2 Source
+ */
+#define WM2200_EQLMIX_SRC2_MASK                 0x007F  /* EQLMIX_SRC2 - [6:0] */
+#define WM2200_EQLMIX_SRC2_SHIFT                     0  /* EQLMIX_SRC2 - [6:0] */
+#define WM2200_EQLMIX_SRC2_WIDTH                     7  /* EQLMIX_SRC2 - [6:0] */
+
+/*
+ * R1619 (0x653) - EQLMIX Input 2 Volume
+ */
+#define WM2200_EQLMIX_VOL2_MASK                 0x00FE  /* EQLMIX_VOL2 - [7:1] */
+#define WM2200_EQLMIX_VOL2_SHIFT                     1  /* EQLMIX_VOL2 - [7:1] */
+#define WM2200_EQLMIX_VOL2_WIDTH                     7  /* EQLMIX_VOL2 - [7:1] */
+
+/*
+ * R1620 (0x654) - EQLMIX Input 3 Source
+ */
+#define WM2200_EQLMIX_SRC3_MASK                 0x007F  /* EQLMIX_SRC3 - [6:0] */
+#define WM2200_EQLMIX_SRC3_SHIFT                     0  /* EQLMIX_SRC3 - [6:0] */
+#define WM2200_EQLMIX_SRC3_WIDTH                     7  /* EQLMIX_SRC3 - [6:0] */
+
+/*
+ * R1621 (0x655) - EQLMIX Input 3 Volume
+ */
+#define WM2200_EQLMIX_VOL3_MASK                 0x00FE  /* EQLMIX_VOL3 - [7:1] */
+#define WM2200_EQLMIX_VOL3_SHIFT                     1  /* EQLMIX_VOL3 - [7:1] */
+#define WM2200_EQLMIX_VOL3_WIDTH                     7  /* EQLMIX_VOL3 - [7:1] */
+
+/*
+ * R1622 (0x656) - EQLMIX Input 4 Source
+ */
+#define WM2200_EQLMIX_SRC4_MASK                 0x007F  /* EQLMIX_SRC4 - [6:0] */
+#define WM2200_EQLMIX_SRC4_SHIFT                     0  /* EQLMIX_SRC4 - [6:0] */
+#define WM2200_EQLMIX_SRC4_WIDTH                     7  /* EQLMIX_SRC4 - [6:0] */
+
+/*
+ * R1623 (0x657) - EQLMIX Input 4 Volume
+ */
+#define WM2200_EQLMIX_VOL4_MASK                 0x00FE  /* EQLMIX_VOL4 - [7:1] */
+#define WM2200_EQLMIX_VOL4_SHIFT                     1  /* EQLMIX_VOL4 - [7:1] */
+#define WM2200_EQLMIX_VOL4_WIDTH                     7  /* EQLMIX_VOL4 - [7:1] */
+
+/*
+ * R1624 (0x658) - EQRMIX Input 1 Source
+ */
+#define WM2200_EQRMIX_SRC1_MASK                 0x007F  /* EQRMIX_SRC1 - [6:0] */
+#define WM2200_EQRMIX_SRC1_SHIFT                     0  /* EQRMIX_SRC1 - [6:0] */
+#define WM2200_EQRMIX_SRC1_WIDTH                     7  /* EQRMIX_SRC1 - [6:0] */
+
+/*
+ * R1625 (0x659) - EQRMIX Input 1 Volume
+ */
+#define WM2200_EQRMIX_VOL1_MASK                 0x00FE  /* EQRMIX_VOL1 - [7:1] */
+#define WM2200_EQRMIX_VOL1_SHIFT                     1  /* EQRMIX_VOL1 - [7:1] */
+#define WM2200_EQRMIX_VOL1_WIDTH                     7  /* EQRMIX_VOL1 - [7:1] */
+
+/*
+ * R1626 (0x65A) - EQRMIX Input 2 Source
+ */
+#define WM2200_EQRMIX_SRC2_MASK                 0x007F  /* EQRMIX_SRC2 - [6:0] */
+#define WM2200_EQRMIX_SRC2_SHIFT                     0  /* EQRMIX_SRC2 - [6:0] */
+#define WM2200_EQRMIX_SRC2_WIDTH                     7  /* EQRMIX_SRC2 - [6:0] */
+
+/*
+ * R1627 (0x65B) - EQRMIX Input 2 Volume
+ */
+#define WM2200_EQRMIX_VOL2_MASK                 0x00FE  /* EQRMIX_VOL2 - [7:1] */
+#define WM2200_EQRMIX_VOL2_SHIFT                     1  /* EQRMIX_VOL2 - [7:1] */
+#define WM2200_EQRMIX_VOL2_WIDTH                     7  /* EQRMIX_VOL2 - [7:1] */
+
+/*
+ * R1628 (0x65C) - EQRMIX Input 3 Source
+ */
+#define WM2200_EQRMIX_SRC3_MASK                 0x007F  /* EQRMIX_SRC3 - [6:0] */
+#define WM2200_EQRMIX_SRC3_SHIFT                     0  /* EQRMIX_SRC3 - [6:0] */
+#define WM2200_EQRMIX_SRC3_WIDTH                     7  /* EQRMIX_SRC3 - [6:0] */
+
+/*
+ * R1629 (0x65D) - EQRMIX Input 3 Volume
+ */
+#define WM2200_EQRMIX_VOL3_MASK                 0x00FE  /* EQRMIX_VOL3 - [7:1] */
+#define WM2200_EQRMIX_VOL3_SHIFT                     1  /* EQRMIX_VOL3 - [7:1] */
+#define WM2200_EQRMIX_VOL3_WIDTH                     7  /* EQRMIX_VOL3 - [7:1] */
+
+/*
+ * R1630 (0x65E) - EQRMIX Input 4 Source
+ */
+#define WM2200_EQRMIX_SRC4_MASK                 0x007F  /* EQRMIX_SRC4 - [6:0] */
+#define WM2200_EQRMIX_SRC4_SHIFT                     0  /* EQRMIX_SRC4 - [6:0] */
+#define WM2200_EQRMIX_SRC4_WIDTH                     7  /* EQRMIX_SRC4 - [6:0] */
+
+/*
+ * R1631 (0x65F) - EQRMIX Input 4 Volume
+ */
+#define WM2200_EQRMIX_VOL4_MASK                 0x00FE  /* EQRMIX_VOL4 - [7:1] */
+#define WM2200_EQRMIX_VOL4_SHIFT                     1  /* EQRMIX_VOL4 - [7:1] */
+#define WM2200_EQRMIX_VOL4_WIDTH                     7  /* EQRMIX_VOL4 - [7:1] */
+
+/*
+ * R1632 (0x660) - LHPF1MIX Input 1 Source
+ */
+#define WM2200_LHPF1MIX_SRC1_MASK               0x007F  /* LHPF1MIX_SRC1 - [6:0] */
+#define WM2200_LHPF1MIX_SRC1_SHIFT                   0  /* LHPF1MIX_SRC1 - [6:0] */
+#define WM2200_LHPF1MIX_SRC1_WIDTH                   7  /* LHPF1MIX_SRC1 - [6:0] */
+
+/*
+ * R1633 (0x661) - LHPF1MIX Input 1 Volume
+ */
+#define WM2200_LHPF1MIX_VOL1_MASK               0x00FE  /* LHPF1MIX_VOL1 - [7:1] */
+#define WM2200_LHPF1MIX_VOL1_SHIFT                   1  /* LHPF1MIX_VOL1 - [7:1] */
+#define WM2200_LHPF1MIX_VOL1_WIDTH                   7  /* LHPF1MIX_VOL1 - [7:1] */
+
+/*
+ * R1634 (0x662) - LHPF1MIX Input 2 Source
+ */
+#define WM2200_LHPF1MIX_SRC2_MASK               0x007F  /* LHPF1MIX_SRC2 - [6:0] */
+#define WM2200_LHPF1MIX_SRC2_SHIFT                   0  /* LHPF1MIX_SRC2 - [6:0] */
+#define WM2200_LHPF1MIX_SRC2_WIDTH                   7  /* LHPF1MIX_SRC2 - [6:0] */
+
+/*
+ * R1635 (0x663) - LHPF1MIX Input 2 Volume
+ */
+#define WM2200_LHPF1MIX_VOL2_MASK               0x00FE  /* LHPF1MIX_VOL2 - [7:1] */
+#define WM2200_LHPF1MIX_VOL2_SHIFT                   1  /* LHPF1MIX_VOL2 - [7:1] */
+#define WM2200_LHPF1MIX_VOL2_WIDTH                   7  /* LHPF1MIX_VOL2 - [7:1] */
+
+/*
+ * R1636 (0x664) - LHPF1MIX Input 3 Source
+ */
+#define WM2200_LHPF1MIX_SRC3_MASK               0x007F  /* LHPF1MIX_SRC3 - [6:0] */
+#define WM2200_LHPF1MIX_SRC3_SHIFT                   0  /* LHPF1MIX_SRC3 - [6:0] */
+#define WM2200_LHPF1MIX_SRC3_WIDTH                   7  /* LHPF1MIX_SRC3 - [6:0] */
+
+/*
+ * R1637 (0x665) - LHPF1MIX Input 3 Volume
+ */
+#define WM2200_LHPF1MIX_VOL3_MASK               0x00FE  /* LHPF1MIX_VOL3 - [7:1] */
+#define WM2200_LHPF1MIX_VOL3_SHIFT                   1  /* LHPF1MIX_VOL3 - [7:1] */
+#define WM2200_LHPF1MIX_VOL3_WIDTH                   7  /* LHPF1MIX_VOL3 - [7:1] */
+
+/*
+ * R1638 (0x666) - LHPF1MIX Input 4 Source
+ */
+#define WM2200_LHPF1MIX_SRC4_MASK               0x007F  /* LHPF1MIX_SRC4 - [6:0] */
+#define WM2200_LHPF1MIX_SRC4_SHIFT                   0  /* LHPF1MIX_SRC4 - [6:0] */
+#define WM2200_LHPF1MIX_SRC4_WIDTH                   7  /* LHPF1MIX_SRC4 - [6:0] */
+
+/*
+ * R1639 (0x667) - LHPF1MIX Input 4 Volume
+ */
+#define WM2200_LHPF1MIX_VOL4_MASK               0x00FE  /* LHPF1MIX_VOL4 - [7:1] */
+#define WM2200_LHPF1MIX_VOL4_SHIFT                   1  /* LHPF1MIX_VOL4 - [7:1] */
+#define WM2200_LHPF1MIX_VOL4_WIDTH                   7  /* LHPF1MIX_VOL4 - [7:1] */
+
+/*
+ * R1640 (0x668) - LHPF2MIX Input 1 Source
+ */
+#define WM2200_LHPF2MIX_SRC1_MASK               0x007F  /* LHPF2MIX_SRC1 - [6:0] */
+#define WM2200_LHPF2MIX_SRC1_SHIFT                   0  /* LHPF2MIX_SRC1 - [6:0] */
+#define WM2200_LHPF2MIX_SRC1_WIDTH                   7  /* LHPF2MIX_SRC1 - [6:0] */
+
+/*
+ * R1641 (0x669) - LHPF2MIX Input 1 Volume
+ */
+#define WM2200_LHPF2MIX_VOL1_MASK               0x00FE  /* LHPF2MIX_VOL1 - [7:1] */
+#define WM2200_LHPF2MIX_VOL1_SHIFT                   1  /* LHPF2MIX_VOL1 - [7:1] */
+#define WM2200_LHPF2MIX_VOL1_WIDTH                   7  /* LHPF2MIX_VOL1 - [7:1] */
+
+/*
+ * R1642 (0x66A) - LHPF2MIX Input 2 Source
+ */
+#define WM2200_LHPF2MIX_SRC2_MASK               0x007F  /* LHPF2MIX_SRC2 - [6:0] */
+#define WM2200_LHPF2MIX_SRC2_SHIFT                   0  /* LHPF2MIX_SRC2 - [6:0] */
+#define WM2200_LHPF2MIX_SRC2_WIDTH                   7  /* LHPF2MIX_SRC2 - [6:0] */
+
+/*
+ * R1643 (0x66B) - LHPF2MIX Input 2 Volume
+ */
+#define WM2200_LHPF2MIX_VOL2_MASK               0x00FE  /* LHPF2MIX_VOL2 - [7:1] */
+#define WM2200_LHPF2MIX_VOL2_SHIFT                   1  /* LHPF2MIX_VOL2 - [7:1] */
+#define WM2200_LHPF2MIX_VOL2_WIDTH                   7  /* LHPF2MIX_VOL2 - [7:1] */
+
+/*
+ * R1644 (0x66C) - LHPF2MIX Input 3 Source
+ */
+#define WM2200_LHPF2MIX_SRC3_MASK               0x007F  /* LHPF2MIX_SRC3 - [6:0] */
+#define WM2200_LHPF2MIX_SRC3_SHIFT                   0  /* LHPF2MIX_SRC3 - [6:0] */
+#define WM2200_LHPF2MIX_SRC3_WIDTH                   7  /* LHPF2MIX_SRC3 - [6:0] */
+
+/*
+ * R1645 (0x66D) - LHPF2MIX Input 3 Volume
+ */
+#define WM2200_LHPF2MIX_VOL3_MASK               0x00FE  /* LHPF2MIX_VOL3 - [7:1] */
+#define WM2200_LHPF2MIX_VOL3_SHIFT                   1  /* LHPF2MIX_VOL3 - [7:1] */
+#define WM2200_LHPF2MIX_VOL3_WIDTH                   7  /* LHPF2MIX_VOL3 - [7:1] */
+
+/*
+ * R1646 (0x66E) - LHPF2MIX Input 4 Source
+ */
+#define WM2200_LHPF2MIX_SRC4_MASK               0x007F  /* LHPF2MIX_SRC4 - [6:0] */
+#define WM2200_LHPF2MIX_SRC4_SHIFT                   0  /* LHPF2MIX_SRC4 - [6:0] */
+#define WM2200_LHPF2MIX_SRC4_WIDTH                   7  /* LHPF2MIX_SRC4 - [6:0] */
+
+/*
+ * R1647 (0x66F) - LHPF2MIX Input 4 Volume
+ */
+#define WM2200_LHPF2MIX_VOL4_MASK               0x00FE  /* LHPF2MIX_VOL4 - [7:1] */
+#define WM2200_LHPF2MIX_VOL4_SHIFT                   1  /* LHPF2MIX_VOL4 - [7:1] */
+#define WM2200_LHPF2MIX_VOL4_WIDTH                   7  /* LHPF2MIX_VOL4 - [7:1] */
+
+/*
+ * R1648 (0x670) - DSP1LMIX Input 1 Source
+ */
+#define WM2200_DSP1LMIX_SRC1_MASK               0x007F  /* DSP1LMIX_SRC1 - [6:0] */
+#define WM2200_DSP1LMIX_SRC1_SHIFT                   0  /* DSP1LMIX_SRC1 - [6:0] */
+#define WM2200_DSP1LMIX_SRC1_WIDTH                   7  /* DSP1LMIX_SRC1 - [6:0] */
+
+/*
+ * R1649 (0x671) - DSP1LMIX Input 1 Volume
+ */
+#define WM2200_DSP1LMIX_VOL1_MASK               0x00FE  /* DSP1LMIX_VOL1 - [7:1] */
+#define WM2200_DSP1LMIX_VOL1_SHIFT                   1  /* DSP1LMIX_VOL1 - [7:1] */
+#define WM2200_DSP1LMIX_VOL1_WIDTH                   7  /* DSP1LMIX_VOL1 - [7:1] */
+
+/*
+ * R1650 (0x672) - DSP1LMIX Input 2 Source
+ */
+#define WM2200_DSP1LMIX_SRC2_MASK               0x007F  /* DSP1LMIX_SRC2 - [6:0] */
+#define WM2200_DSP1LMIX_SRC2_SHIFT                   0  /* DSP1LMIX_SRC2 - [6:0] */
+#define WM2200_DSP1LMIX_SRC2_WIDTH                   7  /* DSP1LMIX_SRC2 - [6:0] */
+
+/*
+ * R1651 (0x673) - DSP1LMIX Input 2 Volume
+ */
+#define WM2200_DSP1LMIX_VOL2_MASK               0x00FE  /* DSP1LMIX_VOL2 - [7:1] */
+#define WM2200_DSP1LMIX_VOL2_SHIFT                   1  /* DSP1LMIX_VOL2 - [7:1] */
+#define WM2200_DSP1LMIX_VOL2_WIDTH                   7  /* DSP1LMIX_VOL2 - [7:1] */
+
+/*
+ * R1652 (0x674) - DSP1LMIX Input 3 Source
+ */
+#define WM2200_DSP1LMIX_SRC3_MASK               0x007F  /* DSP1LMIX_SRC3 - [6:0] */
+#define WM2200_DSP1LMIX_SRC3_SHIFT                   0  /* DSP1LMIX_SRC3 - [6:0] */
+#define WM2200_DSP1LMIX_SRC3_WIDTH                   7  /* DSP1LMIX_SRC3 - [6:0] */
+
+/*
+ * R1653 (0x675) - DSP1LMIX Input 3 Volume
+ */
+#define WM2200_DSP1LMIX_VOL3_MASK               0x00FE  /* DSP1LMIX_VOL3 - [7:1] */
+#define WM2200_DSP1LMIX_VOL3_SHIFT                   1  /* DSP1LMIX_VOL3 - [7:1] */
+#define WM2200_DSP1LMIX_VOL3_WIDTH                   7  /* DSP1LMIX_VOL3 - [7:1] */
+
+/*
+ * R1654 (0x676) - DSP1LMIX Input 4 Source
+ */
+#define WM2200_DSP1LMIX_SRC4_MASK               0x007F  /* DSP1LMIX_SRC4 - [6:0] */
+#define WM2200_DSP1LMIX_SRC4_SHIFT                   0  /* DSP1LMIX_SRC4 - [6:0] */
+#define WM2200_DSP1LMIX_SRC4_WIDTH                   7  /* DSP1LMIX_SRC4 - [6:0] */
+
+/*
+ * R1655 (0x677) - DSP1LMIX Input 4 Volume
+ */
+#define WM2200_DSP1LMIX_VOL4_MASK               0x00FE  /* DSP1LMIX_VOL4 - [7:1] */
+#define WM2200_DSP1LMIX_VOL4_SHIFT                   1  /* DSP1LMIX_VOL4 - [7:1] */
+#define WM2200_DSP1LMIX_VOL4_WIDTH                   7  /* DSP1LMIX_VOL4 - [7:1] */
+
+/*
+ * R1656 (0x678) - DSP1RMIX Input 1 Source
+ */
+#define WM2200_DSP1RMIX_SRC1_MASK               0x007F  /* DSP1RMIX_SRC1 - [6:0] */
+#define WM2200_DSP1RMIX_SRC1_SHIFT                   0  /* DSP1RMIX_SRC1 - [6:0] */
+#define WM2200_DSP1RMIX_SRC1_WIDTH                   7  /* DSP1RMIX_SRC1 - [6:0] */
+
+/*
+ * R1657 (0x679) - DSP1RMIX Input 1 Volume
+ */
+#define WM2200_DSP1RMIX_VOL1_MASK               0x00FE  /* DSP1RMIX_VOL1 - [7:1] */
+#define WM2200_DSP1RMIX_VOL1_SHIFT                   1  /* DSP1RMIX_VOL1 - [7:1] */
+#define WM2200_DSP1RMIX_VOL1_WIDTH                   7  /* DSP1RMIX_VOL1 - [7:1] */
+
+/*
+ * R1658 (0x67A) - DSP1RMIX Input 2 Source
+ */
+#define WM2200_DSP1RMIX_SRC2_MASK               0x007F  /* DSP1RMIX_SRC2 - [6:0] */
+#define WM2200_DSP1RMIX_SRC2_SHIFT                   0  /* DSP1RMIX_SRC2 - [6:0] */
+#define WM2200_DSP1RMIX_SRC2_WIDTH                   7  /* DSP1RMIX_SRC2 - [6:0] */
+
+/*
+ * R1659 (0x67B) - DSP1RMIX Input 2 Volume
+ */
+#define WM2200_DSP1RMIX_VOL2_MASK               0x00FE  /* DSP1RMIX_VOL2 - [7:1] */
+#define WM2200_DSP1RMIX_VOL2_SHIFT                   1  /* DSP1RMIX_VOL2 - [7:1] */
+#define WM2200_DSP1RMIX_VOL2_WIDTH                   7  /* DSP1RMIX_VOL2 - [7:1] */
+
+/*
+ * R1660 (0x67C) - DSP1RMIX Input 3 Source
+ */
+#define WM2200_DSP1RMIX_SRC3_MASK               0x007F  /* DSP1RMIX_SRC3 - [6:0] */
+#define WM2200_DSP1RMIX_SRC3_SHIFT                   0  /* DSP1RMIX_SRC3 - [6:0] */
+#define WM2200_DSP1RMIX_SRC3_WIDTH                   7  /* DSP1RMIX_SRC3 - [6:0] */
+
+/*
+ * R1661 (0x67D) - DSP1RMIX Input 3 Volume
+ */
+#define WM2200_DSP1RMIX_VOL3_MASK               0x00FE  /* DSP1RMIX_VOL3 - [7:1] */
+#define WM2200_DSP1RMIX_VOL3_SHIFT                   1  /* DSP1RMIX_VOL3 - [7:1] */
+#define WM2200_DSP1RMIX_VOL3_WIDTH                   7  /* DSP1RMIX_VOL3 - [7:1] */
+
+/*
+ * R1662 (0x67E) - DSP1RMIX Input 4 Source
+ */
+#define WM2200_DSP1RMIX_SRC4_MASK               0x007F  /* DSP1RMIX_SRC4 - [6:0] */
+#define WM2200_DSP1RMIX_SRC4_SHIFT                   0  /* DSP1RMIX_SRC4 - [6:0] */
+#define WM2200_DSP1RMIX_SRC4_WIDTH                   7  /* DSP1RMIX_SRC4 - [6:0] */
+
+/*
+ * R1663 (0x67F) - DSP1RMIX Input 4 Volume
+ */
+#define WM2200_DSP1RMIX_VOL4_MASK               0x00FE  /* DSP1RMIX_VOL4 - [7:1] */
+#define WM2200_DSP1RMIX_VOL4_SHIFT                   1  /* DSP1RMIX_VOL4 - [7:1] */
+#define WM2200_DSP1RMIX_VOL4_WIDTH                   7  /* DSP1RMIX_VOL4 - [7:1] */
+
+/*
+ * R1664 (0x680) - DSP1AUX1MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX1MIX_SRC1_MASK            0x007F  /* DSP1AUX1MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX1MIX_SRC1_SHIFT                0  /* DSP1AUX1MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX1MIX_SRC1_WIDTH                7  /* DSP1AUX1MIX_SRC1 - [6:0] */
+
+/*
+ * R1665 (0x681) - DSP1AUX2MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX2MIX_SRC1_MASK            0x007F  /* DSP1AUX2MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX2MIX_SRC1_SHIFT                0  /* DSP1AUX2MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX2MIX_SRC1_WIDTH                7  /* DSP1AUX2MIX_SRC1 - [6:0] */
+
+/*
+ * R1666 (0x682) - DSP1AUX3MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX3MIX_SRC1_MASK            0x007F  /* DSP1AUX3MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX3MIX_SRC1_SHIFT                0  /* DSP1AUX3MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX3MIX_SRC1_WIDTH                7  /* DSP1AUX3MIX_SRC1 - [6:0] */
+
+/*
+ * R1667 (0x683) - DSP1AUX4MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX4MIX_SRC1_MASK            0x007F  /* DSP1AUX4MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX4MIX_SRC1_SHIFT                0  /* DSP1AUX4MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX4MIX_SRC1_WIDTH                7  /* DSP1AUX4MIX_SRC1 - [6:0] */
+
+/*
+ * R1668 (0x684) - DSP1AUX5MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX5MIX_SRC1_MASK            0x007F  /* DSP1AUX5MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX5MIX_SRC1_SHIFT                0  /* DSP1AUX5MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX5MIX_SRC1_WIDTH                7  /* DSP1AUX5MIX_SRC1 - [6:0] */
+
+/*
+ * R1669 (0x685) - DSP1AUX6MIX Input 1 Source
+ */
+#define WM2200_DSP1AUX6MIX_SRC1_MASK            0x007F  /* DSP1AUX6MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX6MIX_SRC1_SHIFT                0  /* DSP1AUX6MIX_SRC1 - [6:0] */
+#define WM2200_DSP1AUX6MIX_SRC1_WIDTH                7  /* DSP1AUX6MIX_SRC1 - [6:0] */
+
+/*
+ * R1670 (0x686) - DSP2LMIX Input 1 Source
+ */
+#define WM2200_DSP2LMIX_SRC1_MASK               0x007F  /* DSP2LMIX_SRC1 - [6:0] */
+#define WM2200_DSP2LMIX_SRC1_SHIFT                   0  /* DSP2LMIX_SRC1 - [6:0] */
+#define WM2200_DSP2LMIX_SRC1_WIDTH                   7  /* DSP2LMIX_SRC1 - [6:0] */
+
+/*
+ * R1671 (0x687) - DSP2LMIX Input 1 Volume
+ */
+#define WM2200_DSP2LMIX_VOL1_MASK               0x00FE  /* DSP2LMIX_VOL1 - [7:1] */
+#define WM2200_DSP2LMIX_VOL1_SHIFT                   1  /* DSP2LMIX_VOL1 - [7:1] */
+#define WM2200_DSP2LMIX_VOL1_WIDTH                   7  /* DSP2LMIX_VOL1 - [7:1] */
+
+/*
+ * R1672 (0x688) - DSP2LMIX Input 2 Source
+ */
+#define WM2200_DSP2LMIX_SRC2_MASK               0x007F  /* DSP2LMIX_SRC2 - [6:0] */
+#define WM2200_DSP2LMIX_SRC2_SHIFT                   0  /* DSP2LMIX_SRC2 - [6:0] */
+#define WM2200_DSP2LMIX_SRC2_WIDTH                   7  /* DSP2LMIX_SRC2 - [6:0] */
+
+/*
+ * R1673 (0x689) - DSP2LMIX Input 2 Volume
+ */
+#define WM2200_DSP2LMIX_VOL2_MASK               0x00FE  /* DSP2LMIX_VOL2 - [7:1] */
+#define WM2200_DSP2LMIX_VOL2_SHIFT                   1  /* DSP2LMIX_VOL2 - [7:1] */
+#define WM2200_DSP2LMIX_VOL2_WIDTH                   7  /* DSP2LMIX_VOL2 - [7:1] */
+
+/*
+ * R1674 (0x68A) - DSP2LMIX Input 3 Source
+ */
+#define WM2200_DSP2LMIX_SRC3_MASK               0x007F  /* DSP2LMIX_SRC3 - [6:0] */
+#define WM2200_DSP2LMIX_SRC3_SHIFT                   0  /* DSP2LMIX_SRC3 - [6:0] */
+#define WM2200_DSP2LMIX_SRC3_WIDTH                   7  /* DSP2LMIX_SRC3 - [6:0] */
+
+/*
+ * R1675 (0x68B) - DSP2LMIX Input 3 Volume
+ */
+#define WM2200_DSP2LMIX_VOL3_MASK               0x00FE  /* DSP2LMIX_VOL3 - [7:1] */
+#define WM2200_DSP2LMIX_VOL3_SHIFT                   1  /* DSP2LMIX_VOL3 - [7:1] */
+#define WM2200_DSP2LMIX_VOL3_WIDTH                   7  /* DSP2LMIX_VOL3 - [7:1] */
+
+/*
+ * R1676 (0x68C) - DSP2LMIX Input 4 Source
+ */
+#define WM2200_DSP2LMIX_SRC4_MASK               0x007F  /* DSP2LMIX_SRC4 - [6:0] */
+#define WM2200_DSP2LMIX_SRC4_SHIFT                   0  /* DSP2LMIX_SRC4 - [6:0] */
+#define WM2200_DSP2LMIX_SRC4_WIDTH                   7  /* DSP2LMIX_SRC4 - [6:0] */
+
+/*
+ * R1677 (0x68D) - DSP2LMIX Input 4 Volume
+ */
+#define WM2200_DSP2LMIX_VOL4_MASK               0x00FE  /* DSP2LMIX_VOL4 - [7:1] */
+#define WM2200_DSP2LMIX_VOL4_SHIFT                   1  /* DSP2LMIX_VOL4 - [7:1] */
+#define WM2200_DSP2LMIX_VOL4_WIDTH                   7  /* DSP2LMIX_VOL4 - [7:1] */
+
+/*
+ * R1678 (0x68E) - DSP2RMIX Input 1 Source
+ */
+#define WM2200_DSP2RMIX_SRC1_MASK               0x007F  /* DSP2RMIX_SRC1 - [6:0] */
+#define WM2200_DSP2RMIX_SRC1_SHIFT                   0  /* DSP2RMIX_SRC1 - [6:0] */
+#define WM2200_DSP2RMIX_SRC1_WIDTH                   7  /* DSP2RMIX_SRC1 - [6:0] */
+
+/*
+ * R1679 (0x68F) - DSP2RMIX Input 1 Volume
+ */
+#define WM2200_DSP2RMIX_VOL1_MASK               0x00FE  /* DSP2RMIX_VOL1 - [7:1] */
+#define WM2200_DSP2RMIX_VOL1_SHIFT                   1  /* DSP2RMIX_VOL1 - [7:1] */
+#define WM2200_DSP2RMIX_VOL1_WIDTH                   7  /* DSP2RMIX_VOL1 - [7:1] */
+
+/*
+ * R1680 (0x690) - DSP2RMIX Input 2 Source
+ */
+#define WM2200_DSP2RMIX_SRC2_MASK               0x007F  /* DSP2RMIX_SRC2 - [6:0] */
+#define WM2200_DSP2RMIX_SRC2_SHIFT                   0  /* DSP2RMIX_SRC2 - [6:0] */
+#define WM2200_DSP2RMIX_SRC2_WIDTH                   7  /* DSP2RMIX_SRC2 - [6:0] */
+
+/*
+ * R1681 (0x691) - DSP2RMIX Input 2 Volume
+ */
+#define WM2200_DSP2RMIX_VOL2_MASK               0x00FE  /* DSP2RMIX_VOL2 - [7:1] */
+#define WM2200_DSP2RMIX_VOL2_SHIFT                   1  /* DSP2RMIX_VOL2 - [7:1] */
+#define WM2200_DSP2RMIX_VOL2_WIDTH                   7  /* DSP2RMIX_VOL2 - [7:1] */
+
+/*
+ * R1682 (0x692) - DSP2RMIX Input 3 Source
+ */
+#define WM2200_DSP2RMIX_SRC3_MASK               0x007F  /* DSP2RMIX_SRC3 - [6:0] */
+#define WM2200_DSP2RMIX_SRC3_SHIFT                   0  /* DSP2RMIX_SRC3 - [6:0] */
+#define WM2200_DSP2RMIX_SRC3_WIDTH                   7  /* DSP2RMIX_SRC3 - [6:0] */
+
+/*
+ * R1683 (0x693) - DSP2RMIX Input 3 Volume
+ */
+#define WM2200_DSP2RMIX_VOL3_MASK               0x00FE  /* DSP2RMIX_VOL3 - [7:1] */
+#define WM2200_DSP2RMIX_VOL3_SHIFT                   1  /* DSP2RMIX_VOL3 - [7:1] */
+#define WM2200_DSP2RMIX_VOL3_WIDTH                   7  /* DSP2RMIX_VOL3 - [7:1] */
+
+/*
+ * R1684 (0x694) - DSP2RMIX Input 4 Source
+ */
+#define WM2200_DSP2RMIX_SRC4_MASK               0x007F  /* DSP2RMIX_SRC4 - [6:0] */
+#define WM2200_DSP2RMIX_SRC4_SHIFT                   0  /* DSP2RMIX_SRC4 - [6:0] */
+#define WM2200_DSP2RMIX_SRC4_WIDTH                   7  /* DSP2RMIX_SRC4 - [6:0] */
+
+/*
+ * R1685 (0x695) - DSP2RMIX Input 4 Volume
+ */
+#define WM2200_DSP2RMIX_VOL4_MASK               0x00FE  /* DSP2RMIX_VOL4 - [7:1] */
+#define WM2200_DSP2RMIX_VOL4_SHIFT                   1  /* DSP2RMIX_VOL4 - [7:1] */
+#define WM2200_DSP2RMIX_VOL4_WIDTH                   7  /* DSP2RMIX_VOL4 - [7:1] */
+
+/*
+ * R1686 (0x696) - DSP2AUX1MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX1MIX_SRC1_MASK            0x007F  /* DSP2AUX1MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX1MIX_SRC1_SHIFT                0  /* DSP2AUX1MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX1MIX_SRC1_WIDTH                7  /* DSP2AUX1MIX_SRC1 - [6:0] */
+
+/*
+ * R1687 (0x697) - DSP2AUX2MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX2MIX_SRC1_MASK            0x007F  /* DSP2AUX2MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX2MIX_SRC1_SHIFT                0  /* DSP2AUX2MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX2MIX_SRC1_WIDTH                7  /* DSP2AUX2MIX_SRC1 - [6:0] */
+
+/*
+ * R1688 (0x698) - DSP2AUX3MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX3MIX_SRC1_MASK            0x007F  /* DSP2AUX3MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX3MIX_SRC1_SHIFT                0  /* DSP2AUX3MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX3MIX_SRC1_WIDTH                7  /* DSP2AUX3MIX_SRC1 - [6:0] */
+
+/*
+ * R1689 (0x699) - DSP2AUX4MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX4MIX_SRC1_MASK            0x007F  /* DSP2AUX4MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX4MIX_SRC1_SHIFT                0  /* DSP2AUX4MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX4MIX_SRC1_WIDTH                7  /* DSP2AUX4MIX_SRC1 - [6:0] */
+
+/*
+ * R1690 (0x69A) - DSP2AUX5MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX5MIX_SRC1_MASK            0x007F  /* DSP2AUX5MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX5MIX_SRC1_SHIFT                0  /* DSP2AUX5MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX5MIX_SRC1_WIDTH                7  /* DSP2AUX5MIX_SRC1 - [6:0] */
+
+/*
+ * R1691 (0x69B) - DSP2AUX6MIX Input 1 Source
+ */
+#define WM2200_DSP2AUX6MIX_SRC1_MASK            0x007F  /* DSP2AUX6MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX6MIX_SRC1_SHIFT                0  /* DSP2AUX6MIX_SRC1 - [6:0] */
+#define WM2200_DSP2AUX6MIX_SRC1_WIDTH                7  /* DSP2AUX6MIX_SRC1 - [6:0] */
+
+/*
+ * R1792 (0x700) - GPIO CTRL 1
+ */
+#define WM2200_GP1_DIR                          0x8000  /* GP1_DIR */
+#define WM2200_GP1_DIR_MASK                     0x8000  /* GP1_DIR */
+#define WM2200_GP1_DIR_SHIFT                        15  /* GP1_DIR */
+#define WM2200_GP1_DIR_WIDTH                         1  /* GP1_DIR */
+#define WM2200_GP1_PU                           0x4000  /* GP1_PU */
+#define WM2200_GP1_PU_MASK                      0x4000  /* GP1_PU */
+#define WM2200_GP1_PU_SHIFT                         14  /* GP1_PU */
+#define WM2200_GP1_PU_WIDTH                          1  /* GP1_PU */
+#define WM2200_GP1_PD                           0x2000  /* GP1_PD */
+#define WM2200_GP1_PD_MASK                      0x2000  /* GP1_PD */
+#define WM2200_GP1_PD_SHIFT                         13  /* GP1_PD */
+#define WM2200_GP1_PD_WIDTH                          1  /* GP1_PD */
+#define WM2200_GP1_POL                          0x0400  /* GP1_POL */
+#define WM2200_GP1_POL_MASK                     0x0400  /* GP1_POL */
+#define WM2200_GP1_POL_SHIFT                        10  /* GP1_POL */
+#define WM2200_GP1_POL_WIDTH                         1  /* GP1_POL */
+#define WM2200_GP1_OP_CFG                       0x0200  /* GP1_OP_CFG */
+#define WM2200_GP1_OP_CFG_MASK                  0x0200  /* GP1_OP_CFG */
+#define WM2200_GP1_OP_CFG_SHIFT                      9  /* GP1_OP_CFG */
+#define WM2200_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
+#define WM2200_GP1_DB                           0x0100  /* GP1_DB */
+#define WM2200_GP1_DB_MASK                      0x0100  /* GP1_DB */
+#define WM2200_GP1_DB_SHIFT                          8  /* GP1_DB */
+#define WM2200_GP1_DB_WIDTH                          1  /* GP1_DB */
+#define WM2200_GP1_LVL                          0x0040  /* GP1_LVL */
+#define WM2200_GP1_LVL_MASK                     0x0040  /* GP1_LVL */
+#define WM2200_GP1_LVL_SHIFT                         6  /* GP1_LVL */
+#define WM2200_GP1_LVL_WIDTH                         1  /* GP1_LVL */
+#define WM2200_GP1_FN_MASK                      0x003F  /* GP1_FN - [5:0] */
+#define WM2200_GP1_FN_SHIFT                          0  /* GP1_FN - [5:0] */
+#define WM2200_GP1_FN_WIDTH                          6  /* GP1_FN - [5:0] */
+
+/*
+ * R1793 (0x701) - GPIO CTRL 2
+ */
+#define WM2200_GP2_DIR                          0x8000  /* GP2_DIR */
+#define WM2200_GP2_DIR_MASK                     0x8000  /* GP2_DIR */
+#define WM2200_GP2_DIR_SHIFT                        15  /* GP2_DIR */
+#define WM2200_GP2_DIR_WIDTH                         1  /* GP2_DIR */
+#define WM2200_GP2_PU                           0x4000  /* GP2_PU */
+#define WM2200_GP2_PU_MASK                      0x4000  /* GP2_PU */
+#define WM2200_GP2_PU_SHIFT                         14  /* GP2_PU */
+#define WM2200_GP2_PU_WIDTH                          1  /* GP2_PU */
+#define WM2200_GP2_PD                           0x2000  /* GP2_PD */
+#define WM2200_GP2_PD_MASK                      0x2000  /* GP2_PD */
+#define WM2200_GP2_PD_SHIFT                         13  /* GP2_PD */
+#define WM2200_GP2_PD_WIDTH                          1  /* GP2_PD */
+#define WM2200_GP2_POL                          0x0400  /* GP2_POL */
+#define WM2200_GP2_POL_MASK                     0x0400  /* GP2_POL */
+#define WM2200_GP2_POL_SHIFT                        10  /* GP2_POL */
+#define WM2200_GP2_POL_WIDTH                         1  /* GP2_POL */
+#define WM2200_GP2_OP_CFG                       0x0200  /* GP2_OP_CFG */
+#define WM2200_GP2_OP_CFG_MASK                  0x0200  /* GP2_OP_CFG */
+#define WM2200_GP2_OP_CFG_SHIFT                      9  /* GP2_OP_CFG */
+#define WM2200_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
+#define WM2200_GP2_DB                           0x0100  /* GP2_DB */
+#define WM2200_GP2_DB_MASK                      0x0100  /* GP2_DB */
+#define WM2200_GP2_DB_SHIFT                          8  /* GP2_DB */
+#define WM2200_GP2_DB_WIDTH                          1  /* GP2_DB */
+#define WM2200_GP2_LVL                          0x0040  /* GP2_LVL */
+#define WM2200_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
+#define WM2200_GP2_LVL_SHIFT                         6  /* GP2_LVL */
+#define WM2200_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM2200_GP2_FN_MASK                      0x003F  /* GP2_FN - [5:0] */
+#define WM2200_GP2_FN_SHIFT                          0  /* GP2_FN - [5:0] */
+#define WM2200_GP2_FN_WIDTH                          6  /* GP2_FN - [5:0] */
+
+/*
+ * R1794 (0x702) - GPIO CTRL 3
+ */
+#define WM2200_GP3_DIR                          0x8000  /* GP3_DIR */
+#define WM2200_GP3_DIR_MASK                     0x8000  /* GP3_DIR */
+#define WM2200_GP3_DIR_SHIFT                        15  /* GP3_DIR */
+#define WM2200_GP3_DIR_WIDTH                         1  /* GP3_DIR */
+#define WM2200_GP3_PU                           0x4000  /* GP3_PU */
+#define WM2200_GP3_PU_MASK                      0x4000  /* GP3_PU */
+#define WM2200_GP3_PU_SHIFT                         14  /* GP3_PU */
+#define WM2200_GP3_PU_WIDTH                          1  /* GP3_PU */
+#define WM2200_GP3_PD                           0x2000  /* GP3_PD */
+#define WM2200_GP3_PD_MASK                      0x2000  /* GP3_PD */
+#define WM2200_GP3_PD_SHIFT                         13  /* GP3_PD */
+#define WM2200_GP3_PD_WIDTH                          1  /* GP3_PD */
+#define WM2200_GP3_POL                          0x0400  /* GP3_POL */
+#define WM2200_GP3_POL_MASK                     0x0400  /* GP3_POL */
+#define WM2200_GP3_POL_SHIFT                        10  /* GP3_POL */
+#define WM2200_GP3_POL_WIDTH                         1  /* GP3_POL */
+#define WM2200_GP3_OP_CFG                       0x0200  /* GP3_OP_CFG */
+#define WM2200_GP3_OP_CFG_MASK                  0x0200  /* GP3_OP_CFG */
+#define WM2200_GP3_OP_CFG_SHIFT                      9  /* GP3_OP_CFG */
+#define WM2200_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
+#define WM2200_GP3_DB                           0x0100  /* GP3_DB */
+#define WM2200_GP3_DB_MASK                      0x0100  /* GP3_DB */
+#define WM2200_GP3_DB_SHIFT                          8  /* GP3_DB */
+#define WM2200_GP3_DB_WIDTH                          1  /* GP3_DB */
+#define WM2200_GP3_LVL                          0x0040  /* GP3_LVL */
+#define WM2200_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
+#define WM2200_GP3_LVL_SHIFT                         6  /* GP3_LVL */
+#define WM2200_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM2200_GP3_FN_MASK                      0x003F  /* GP3_FN - [5:0] */
+#define WM2200_GP3_FN_SHIFT                          0  /* GP3_FN - [5:0] */
+#define WM2200_GP3_FN_WIDTH                          6  /* GP3_FN - [5:0] */
+
+/*
+ * R1795 (0x703) - GPIO CTRL 4
+ */
+#define WM2200_GP4_DIR                          0x8000  /* GP4_DIR */
+#define WM2200_GP4_DIR_MASK                     0x8000  /* GP4_DIR */
+#define WM2200_GP4_DIR_SHIFT                        15  /* GP4_DIR */
+#define WM2200_GP4_DIR_WIDTH                         1  /* GP4_DIR */
+#define WM2200_GP4_PU                           0x4000  /* GP4_PU */
+#define WM2200_GP4_PU_MASK                      0x4000  /* GP4_PU */
+#define WM2200_GP4_PU_SHIFT                         14  /* GP4_PU */
+#define WM2200_GP4_PU_WIDTH                          1  /* GP4_PU */
+#define WM2200_GP4_PD                           0x2000  /* GP4_PD */
+#define WM2200_GP4_PD_MASK                      0x2000  /* GP4_PD */
+#define WM2200_GP4_PD_SHIFT                         13  /* GP4_PD */
+#define WM2200_GP4_PD_WIDTH                          1  /* GP4_PD */
+#define WM2200_GP4_POL                          0x0400  /* GP4_POL */
+#define WM2200_GP4_POL_MASK                     0x0400  /* GP4_POL */
+#define WM2200_GP4_POL_SHIFT                        10  /* GP4_POL */
+#define WM2200_GP4_POL_WIDTH                         1  /* GP4_POL */
+#define WM2200_GP4_OP_CFG                       0x0200  /* GP4_OP_CFG */
+#define WM2200_GP4_OP_CFG_MASK                  0x0200  /* GP4_OP_CFG */
+#define WM2200_GP4_OP_CFG_SHIFT                      9  /* GP4_OP_CFG */
+#define WM2200_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
+#define WM2200_GP4_DB                           0x0100  /* GP4_DB */
+#define WM2200_GP4_DB_MASK                      0x0100  /* GP4_DB */
+#define WM2200_GP4_DB_SHIFT                          8  /* GP4_DB */
+#define WM2200_GP4_DB_WIDTH                          1  /* GP4_DB */
+#define WM2200_GP4_LVL                          0x0040  /* GP4_LVL */
+#define WM2200_GP4_LVL_MASK                     0x0040  /* GP4_LVL */
+#define WM2200_GP4_LVL_SHIFT                         6  /* GP4_LVL */
+#define WM2200_GP4_LVL_WIDTH                         1  /* GP4_LVL */
+#define WM2200_GP4_FN_MASK                      0x003F  /* GP4_FN - [5:0] */
+#define WM2200_GP4_FN_SHIFT                          0  /* GP4_FN - [5:0] */
+#define WM2200_GP4_FN_WIDTH                          6  /* GP4_FN - [5:0] */
+
+/*
+ * R1799 (0x707) - ADPS1 IRQ0
+ */
+#define WM2200_DSP_IRQ1                         0x0002  /* DSP_IRQ1 */
+#define WM2200_DSP_IRQ1_MASK                    0x0002  /* DSP_IRQ1 */
+#define WM2200_DSP_IRQ1_SHIFT                        1  /* DSP_IRQ1 */
+#define WM2200_DSP_IRQ1_WIDTH                        1  /* DSP_IRQ1 */
+#define WM2200_DSP_IRQ0                         0x0001  /* DSP_IRQ0 */
+#define WM2200_DSP_IRQ0_MASK                    0x0001  /* DSP_IRQ0 */
+#define WM2200_DSP_IRQ0_SHIFT                        0  /* DSP_IRQ0 */
+#define WM2200_DSP_IRQ0_WIDTH                        1  /* DSP_IRQ0 */
+
+/*
+ * R1800 (0x708) - ADPS1 IRQ1
+ */
+#define WM2200_DSP_IRQ3                         0x0002  /* DSP_IRQ3 */
+#define WM2200_DSP_IRQ3_MASK                    0x0002  /* DSP_IRQ3 */
+#define WM2200_DSP_IRQ3_SHIFT                        1  /* DSP_IRQ3 */
+#define WM2200_DSP_IRQ3_WIDTH                        1  /* DSP_IRQ3 */
+#define WM2200_DSP_IRQ2                         0x0001  /* DSP_IRQ2 */
+#define WM2200_DSP_IRQ2_MASK                    0x0001  /* DSP_IRQ2 */
+#define WM2200_DSP_IRQ2_SHIFT                        0  /* DSP_IRQ2 */
+#define WM2200_DSP_IRQ2_WIDTH                        1  /* DSP_IRQ2 */
+
+/*
+ * R1801 (0x709) - Misc Pad Ctrl 1
+ */
+#define WM2200_LDO1ENA_PD                       0x8000  /* LDO1ENA_PD */
+#define WM2200_LDO1ENA_PD_MASK                  0x8000  /* LDO1ENA_PD */
+#define WM2200_LDO1ENA_PD_SHIFT                     15  /* LDO1ENA_PD */
+#define WM2200_LDO1ENA_PD_WIDTH                      1  /* LDO1ENA_PD */
+#define WM2200_MCLK2_PD                         0x2000  /* MCLK2_PD */
+#define WM2200_MCLK2_PD_MASK                    0x2000  /* MCLK2_PD */
+#define WM2200_MCLK2_PD_SHIFT                       13  /* MCLK2_PD */
+#define WM2200_MCLK2_PD_WIDTH                        1  /* MCLK2_PD */
+#define WM2200_MCLK1_PD                         0x1000  /* MCLK1_PD */
+#define WM2200_MCLK1_PD_MASK                    0x1000  /* MCLK1_PD */
+#define WM2200_MCLK1_PD_SHIFT                       12  /* MCLK1_PD */
+#define WM2200_MCLK1_PD_WIDTH                        1  /* MCLK1_PD */
+#define WM2200_DACLRCLK1_PU                     0x0400  /* DACLRCLK1_PU */
+#define WM2200_DACLRCLK1_PU_MASK                0x0400  /* DACLRCLK1_PU */
+#define WM2200_DACLRCLK1_PU_SHIFT                   10  /* DACLRCLK1_PU */
+#define WM2200_DACLRCLK1_PU_WIDTH                    1  /* DACLRCLK1_PU */
+#define WM2200_DACLRCLK1_PD                     0x0200  /* DACLRCLK1_PD */
+#define WM2200_DACLRCLK1_PD_MASK                0x0200  /* DACLRCLK1_PD */
+#define WM2200_DACLRCLK1_PD_SHIFT                    9  /* DACLRCLK1_PD */
+#define WM2200_DACLRCLK1_PD_WIDTH                    1  /* DACLRCLK1_PD */
+#define WM2200_BCLK1_PU                         0x0100  /* BCLK1_PU */
+#define WM2200_BCLK1_PU_MASK                    0x0100  /* BCLK1_PU */
+#define WM2200_BCLK1_PU_SHIFT                        8  /* BCLK1_PU */
+#define WM2200_BCLK1_PU_WIDTH                        1  /* BCLK1_PU */
+#define WM2200_BCLK1_PD                         0x0080  /* BCLK1_PD */
+#define WM2200_BCLK1_PD_MASK                    0x0080  /* BCLK1_PD */
+#define WM2200_BCLK1_PD_SHIFT                        7  /* BCLK1_PD */
+#define WM2200_BCLK1_PD_WIDTH                        1  /* BCLK1_PD */
+#define WM2200_DACDAT1_PU                       0x0040  /* DACDAT1_PU */
+#define WM2200_DACDAT1_PU_MASK                  0x0040  /* DACDAT1_PU */
+#define WM2200_DACDAT1_PU_SHIFT                      6  /* DACDAT1_PU */
+#define WM2200_DACDAT1_PU_WIDTH                      1  /* DACDAT1_PU */
+#define WM2200_DACDAT1_PD                       0x0020  /* DACDAT1_PD */
+#define WM2200_DACDAT1_PD_MASK                  0x0020  /* DACDAT1_PD */
+#define WM2200_DACDAT1_PD_SHIFT                      5  /* DACDAT1_PD */
+#define WM2200_DACDAT1_PD_WIDTH                      1  /* DACDAT1_PD */
+#define WM2200_DMICDAT3_PD                      0x0010  /* DMICDAT3_PD */
+#define WM2200_DMICDAT3_PD_MASK                 0x0010  /* DMICDAT3_PD */
+#define WM2200_DMICDAT3_PD_SHIFT                     4  /* DMICDAT3_PD */
+#define WM2200_DMICDAT3_PD_WIDTH                     1  /* DMICDAT3_PD */
+#define WM2200_DMICDAT2_PD                      0x0008  /* DMICDAT2_PD */
+#define WM2200_DMICDAT2_PD_MASK                 0x0008  /* DMICDAT2_PD */
+#define WM2200_DMICDAT2_PD_SHIFT                     3  /* DMICDAT2_PD */
+#define WM2200_DMICDAT2_PD_WIDTH                     1  /* DMICDAT2_PD */
+#define WM2200_DMICDAT1_PD                      0x0004  /* DMICDAT1_PD */
+#define WM2200_DMICDAT1_PD_MASK                 0x0004  /* DMICDAT1_PD */
+#define WM2200_DMICDAT1_PD_SHIFT                     2  /* DMICDAT1_PD */
+#define WM2200_DMICDAT1_PD_WIDTH                     1  /* DMICDAT1_PD */
+#define WM2200_RSTB_PU                          0x0002  /* RSTB_PU */
+#define WM2200_RSTB_PU_MASK                     0x0002  /* RSTB_PU */
+#define WM2200_RSTB_PU_SHIFT                         1  /* RSTB_PU */
+#define WM2200_RSTB_PU_WIDTH                         1  /* RSTB_PU */
+#define WM2200_ADDR_PD                          0x0001  /* ADDR_PD */
+#define WM2200_ADDR_PD_MASK                     0x0001  /* ADDR_PD */
+#define WM2200_ADDR_PD_SHIFT                         0  /* ADDR_PD */
+#define WM2200_ADDR_PD_WIDTH                         1  /* ADDR_PD */
+
+/*
+ * R2048 (0x800) - Interrupt Status 1
+ */
+#define WM2200_DSP_IRQ0_EINT                    0x0080  /* DSP_IRQ0_EINT */
+#define WM2200_DSP_IRQ0_EINT_MASK               0x0080  /* DSP_IRQ0_EINT */
+#define WM2200_DSP_IRQ0_EINT_SHIFT                   7  /* DSP_IRQ0_EINT */
+#define WM2200_DSP_IRQ0_EINT_WIDTH                   1  /* DSP_IRQ0_EINT */
+#define WM2200_DSP_IRQ1_EINT                    0x0040  /* DSP_IRQ1_EINT */
+#define WM2200_DSP_IRQ1_EINT_MASK               0x0040  /* DSP_IRQ1_EINT */
+#define WM2200_DSP_IRQ1_EINT_SHIFT                   6  /* DSP_IRQ1_EINT */
+#define WM2200_DSP_IRQ1_EINT_WIDTH                   1  /* DSP_IRQ1_EINT */
+#define WM2200_DSP_IRQ2_EINT                    0x0020  /* DSP_IRQ2_EINT */
+#define WM2200_DSP_IRQ2_EINT_MASK               0x0020  /* DSP_IRQ2_EINT */
+#define WM2200_DSP_IRQ2_EINT_SHIFT                   5  /* DSP_IRQ2_EINT */
+#define WM2200_DSP_IRQ2_EINT_WIDTH                   1  /* DSP_IRQ2_EINT */
+#define WM2200_DSP_IRQ3_EINT                    0x0010  /* DSP_IRQ3_EINT */
+#define WM2200_DSP_IRQ3_EINT_MASK               0x0010  /* DSP_IRQ3_EINT */
+#define WM2200_DSP_IRQ3_EINT_SHIFT                   4  /* DSP_IRQ3_EINT */
+#define WM2200_DSP_IRQ3_EINT_WIDTH                   1  /* DSP_IRQ3_EINT */
+#define WM2200_GP4_EINT                         0x0008  /* GP4_EINT */
+#define WM2200_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
+#define WM2200_GP4_EINT_SHIFT                        3  /* GP4_EINT */
+#define WM2200_GP4_EINT_WIDTH                        1  /* GP4_EINT */
+#define WM2200_GP3_EINT                         0x0004  /* GP3_EINT */
+#define WM2200_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
+#define WM2200_GP3_EINT_SHIFT                        2  /* GP3_EINT */
+#define WM2200_GP3_EINT_WIDTH                        1  /* GP3_EINT */
+#define WM2200_GP2_EINT                         0x0002  /* GP2_EINT */
+#define WM2200_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
+#define WM2200_GP2_EINT_SHIFT                        1  /* GP2_EINT */
+#define WM2200_GP2_EINT_WIDTH                        1  /* GP2_EINT */
+#define WM2200_GP1_EINT                         0x0001  /* GP1_EINT */
+#define WM2200_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
+#define WM2200_GP1_EINT_SHIFT                        0  /* GP1_EINT */
+#define WM2200_GP1_EINT_WIDTH                        1  /* GP1_EINT */
+
+/*
+ * R2049 (0x801) - Interrupt Status 1 Mask
+ */
+#define WM2200_IM_DSP_IRQ0_EINT                 0x0080  /* IM_DSP_IRQ0_EINT */
+#define WM2200_IM_DSP_IRQ0_EINT_MASK            0x0080  /* IM_DSP_IRQ0_EINT */
+#define WM2200_IM_DSP_IRQ0_EINT_SHIFT                7  /* IM_DSP_IRQ0_EINT */
+#define WM2200_IM_DSP_IRQ0_EINT_WIDTH                1  /* IM_DSP_IRQ0_EINT */
+#define WM2200_IM_DSP_IRQ1_EINT                 0x0040  /* IM_DSP_IRQ1_EINT */
+#define WM2200_IM_DSP_IRQ1_EINT_MASK            0x0040  /* IM_DSP_IRQ1_EINT */
+#define WM2200_IM_DSP_IRQ1_EINT_SHIFT                6  /* IM_DSP_IRQ1_EINT */
+#define WM2200_IM_DSP_IRQ1_EINT_WIDTH                1  /* IM_DSP_IRQ1_EINT */
+#define WM2200_IM_DSP_IRQ2_EINT                 0x0020  /* IM_DSP_IRQ2_EINT */
+#define WM2200_IM_DSP_IRQ2_EINT_MASK            0x0020  /* IM_DSP_IRQ2_EINT */
+#define WM2200_IM_DSP_IRQ2_EINT_SHIFT                5  /* IM_DSP_IRQ2_EINT */
+#define WM2200_IM_DSP_IRQ2_EINT_WIDTH                1  /* IM_DSP_IRQ2_EINT */
+#define WM2200_IM_DSP_IRQ3_EINT                 0x0010  /* IM_DSP_IRQ3_EINT */
+#define WM2200_IM_DSP_IRQ3_EINT_MASK            0x0010  /* IM_DSP_IRQ3_EINT */
+#define WM2200_IM_DSP_IRQ3_EINT_SHIFT                4  /* IM_DSP_IRQ3_EINT */
+#define WM2200_IM_DSP_IRQ3_EINT_WIDTH                1  /* IM_DSP_IRQ3_EINT */
+#define WM2200_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
+#define WM2200_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
+#define WM2200_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
+#define WM2200_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
+#define WM2200_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
+#define WM2200_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
+#define WM2200_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
+#define WM2200_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
+#define WM2200_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
+#define WM2200_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
+#define WM2200_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
+#define WM2200_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
+#define WM2200_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
+#define WM2200_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
+#define WM2200_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
+#define WM2200_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
+
+/*
+ * R2050 (0x802) - Interrupt Status 2
+ */
+#define WM2200_WSEQ_BUSY_EINT                   0x0100  /* WSEQ_BUSY_EINT */
+#define WM2200_WSEQ_BUSY_EINT_MASK              0x0100  /* WSEQ_BUSY_EINT */
+#define WM2200_WSEQ_BUSY_EINT_SHIFT                  8  /* WSEQ_BUSY_EINT */
+#define WM2200_WSEQ_BUSY_EINT_WIDTH                  1  /* WSEQ_BUSY_EINT */
+#define WM2200_FLL_LOCK_EINT                    0x0002  /* FLL_LOCK_EINT */
+#define WM2200_FLL_LOCK_EINT_MASK               0x0002  /* FLL_LOCK_EINT */
+#define WM2200_FLL_LOCK_EINT_SHIFT                   1  /* FLL_LOCK_EINT */
+#define WM2200_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM2200_CLKGEN_EINT                      0x0001  /* CLKGEN_EINT */
+#define WM2200_CLKGEN_EINT_MASK                 0x0001  /* CLKGEN_EINT */
+#define WM2200_CLKGEN_EINT_SHIFT                     0  /* CLKGEN_EINT */
+#define WM2200_CLKGEN_EINT_WIDTH                     1  /* CLKGEN_EINT */
+
+/*
+ * R2051 (0x803) - Interrupt Raw Status 2
+ */
+#define WM2200_WSEQ_BUSY_STS                    0x0100  /* WSEQ_BUSY_STS */
+#define WM2200_WSEQ_BUSY_STS_MASK               0x0100  /* WSEQ_BUSY_STS */
+#define WM2200_WSEQ_BUSY_STS_SHIFT                   8  /* WSEQ_BUSY_STS */
+#define WM2200_WSEQ_BUSY_STS_WIDTH                   1  /* WSEQ_BUSY_STS */
+#define WM2200_FLL_LOCK_STS                     0x0002  /* FLL_LOCK_STS */
+#define WM2200_FLL_LOCK_STS_MASK                0x0002  /* FLL_LOCK_STS */
+#define WM2200_FLL_LOCK_STS_SHIFT                    1  /* FLL_LOCK_STS */
+#define WM2200_FLL_LOCK_STS_WIDTH                    1  /* FLL_LOCK_STS */
+#define WM2200_CLKGEN_STS                       0x0001  /* CLKGEN_STS */
+#define WM2200_CLKGEN_STS_MASK                  0x0001  /* CLKGEN_STS */
+#define WM2200_CLKGEN_STS_SHIFT                      0  /* CLKGEN_STS */
+#define WM2200_CLKGEN_STS_WIDTH                      1  /* CLKGEN_STS */
+
+/*
+ * R2052 (0x804) - Interrupt Status 2 Mask
+ */
+#define WM2200_IM_WSEQ_BUSY_EINT                0x0100  /* IM_WSEQ_BUSY_EINT */
+#define WM2200_IM_WSEQ_BUSY_EINT_MASK           0x0100  /* IM_WSEQ_BUSY_EINT */
+#define WM2200_IM_WSEQ_BUSY_EINT_SHIFT               8  /* IM_WSEQ_BUSY_EINT */
+#define WM2200_IM_WSEQ_BUSY_EINT_WIDTH               1  /* IM_WSEQ_BUSY_EINT */
+#define WM2200_IM_FLL_LOCK_EINT                 0x0002  /* IM_FLL_LOCK_EINT */
+#define WM2200_IM_FLL_LOCK_EINT_MASK            0x0002  /* IM_FLL_LOCK_EINT */
+#define WM2200_IM_FLL_LOCK_EINT_SHIFT                1  /* IM_FLL_LOCK_EINT */
+#define WM2200_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM2200_IM_CLKGEN_EINT                   0x0001  /* IM_CLKGEN_EINT */
+#define WM2200_IM_CLKGEN_EINT_MASK              0x0001  /* IM_CLKGEN_EINT */
+#define WM2200_IM_CLKGEN_EINT_SHIFT                  0  /* IM_CLKGEN_EINT */
+#define WM2200_IM_CLKGEN_EINT_WIDTH                  1  /* IM_CLKGEN_EINT */
+
+/*
+ * R2056 (0x808) - Interrupt Control
+ */
+#define WM2200_IM_IRQ                           0x0001  /* IM_IRQ */
+#define WM2200_IM_IRQ_MASK                      0x0001  /* IM_IRQ */
+#define WM2200_IM_IRQ_SHIFT                          0  /* IM_IRQ */
+#define WM2200_IM_IRQ_WIDTH                          1  /* IM_IRQ */
+
+/*
+ * R2304 (0x900) - EQL_1
+ */
+#define WM2200_EQL_B1_GAIN_MASK                 0xF800  /* EQL_B1_GAIN - [15:11] */
+#define WM2200_EQL_B1_GAIN_SHIFT                    11  /* EQL_B1_GAIN - [15:11] */
+#define WM2200_EQL_B1_GAIN_WIDTH                     5  /* EQL_B1_GAIN - [15:11] */
+#define WM2200_EQL_B2_GAIN_MASK                 0x07C0  /* EQL_B2_GAIN - [10:6] */
+#define WM2200_EQL_B2_GAIN_SHIFT                     6  /* EQL_B2_GAIN - [10:6] */
+#define WM2200_EQL_B2_GAIN_WIDTH                     5  /* EQL_B2_GAIN - [10:6] */
+#define WM2200_EQL_B3_GAIN_MASK                 0x003E  /* EQL_B3_GAIN - [5:1] */
+#define WM2200_EQL_B3_GAIN_SHIFT                     1  /* EQL_B3_GAIN - [5:1] */
+#define WM2200_EQL_B3_GAIN_WIDTH                     5  /* EQL_B3_GAIN - [5:1] */
+#define WM2200_EQL_ENA                          0x0001  /* EQL_ENA */
+#define WM2200_EQL_ENA_MASK                     0x0001  /* EQL_ENA */
+#define WM2200_EQL_ENA_SHIFT                         0  /* EQL_ENA */
+#define WM2200_EQL_ENA_WIDTH                         1  /* EQL_ENA */
+
+/*
+ * R2305 (0x901) - EQL_2
+ */
+#define WM2200_EQL_B4_GAIN_MASK                 0xF800  /* EQL_B4_GAIN - [15:11] */
+#define WM2200_EQL_B4_GAIN_SHIFT                    11  /* EQL_B4_GAIN - [15:11] */
+#define WM2200_EQL_B4_GAIN_WIDTH                     5  /* EQL_B4_GAIN - [15:11] */
+#define WM2200_EQL_B5_GAIN_MASK                 0x07C0  /* EQL_B5_GAIN - [10:6] */
+#define WM2200_EQL_B5_GAIN_SHIFT                     6  /* EQL_B5_GAIN - [10:6] */
+#define WM2200_EQL_B5_GAIN_WIDTH                     5  /* EQL_B5_GAIN - [10:6] */
+
+/*
+ * R2306 (0x902) - EQL_3
+ */
+#define WM2200_EQL_B1_A_MASK                    0xFFFF  /* EQL_B1_A - [15:0] */
+#define WM2200_EQL_B1_A_SHIFT                        0  /* EQL_B1_A - [15:0] */
+#define WM2200_EQL_B1_A_WIDTH                       16  /* EQL_B1_A - [15:0] */
+
+/*
+ * R2307 (0x903) - EQL_4
+ */
+#define WM2200_EQL_B1_B_MASK                    0xFFFF  /* EQL_B1_B - [15:0] */
+#define WM2200_EQL_B1_B_SHIFT                        0  /* EQL_B1_B - [15:0] */
+#define WM2200_EQL_B1_B_WIDTH                       16  /* EQL_B1_B - [15:0] */
+
+/*
+ * R2308 (0x904) - EQL_5
+ */
+#define WM2200_EQL_B1_PG_MASK                   0xFFFF  /* EQL_B1_PG - [15:0] */
+#define WM2200_EQL_B1_PG_SHIFT                       0  /* EQL_B1_PG - [15:0] */
+#define WM2200_EQL_B1_PG_WIDTH                      16  /* EQL_B1_PG - [15:0] */
+
+/*
+ * R2309 (0x905) - EQL_6
+ */
+#define WM2200_EQL_B2_A_MASK                    0xFFFF  /* EQL_B2_A - [15:0] */
+#define WM2200_EQL_B2_A_SHIFT                        0  /* EQL_B2_A - [15:0] */
+#define WM2200_EQL_B2_A_WIDTH                       16  /* EQL_B2_A - [15:0] */
+
+/*
+ * R2310 (0x906) - EQL_7
+ */
+#define WM2200_EQL_B2_B_MASK                    0xFFFF  /* EQL_B2_B - [15:0] */
+#define WM2200_EQL_B2_B_SHIFT                        0  /* EQL_B2_B - [15:0] */
+#define WM2200_EQL_B2_B_WIDTH                       16  /* EQL_B2_B - [15:0] */
+
+/*
+ * R2311 (0x907) - EQL_8
+ */
+#define WM2200_EQL_B2_C_MASK                    0xFFFF  /* EQL_B2_C - [15:0] */
+#define WM2200_EQL_B2_C_SHIFT                        0  /* EQL_B2_C - [15:0] */
+#define WM2200_EQL_B2_C_WIDTH                       16  /* EQL_B2_C - [15:0] */
+
+/*
+ * R2312 (0x908) - EQL_9
+ */
+#define WM2200_EQL_B2_PG_MASK                   0xFFFF  /* EQL_B2_PG - [15:0] */
+#define WM2200_EQL_B2_PG_SHIFT                       0  /* EQL_B2_PG - [15:0] */
+#define WM2200_EQL_B2_PG_WIDTH                      16  /* EQL_B2_PG - [15:0] */
+
+/*
+ * R2313 (0x909) - EQL_10
+ */
+#define WM2200_EQL_B3_A_MASK                    0xFFFF  /* EQL_B3_A - [15:0] */
+#define WM2200_EQL_B3_A_SHIFT                        0  /* EQL_B3_A - [15:0] */
+#define WM2200_EQL_B3_A_WIDTH                       16  /* EQL_B3_A - [15:0] */
+
+/*
+ * R2314 (0x90A) - EQL_11
+ */
+#define WM2200_EQL_B3_B_MASK                    0xFFFF  /* EQL_B3_B - [15:0] */
+#define WM2200_EQL_B3_B_SHIFT                        0  /* EQL_B3_B - [15:0] */
+#define WM2200_EQL_B3_B_WIDTH                       16  /* EQL_B3_B - [15:0] */
+
+/*
+ * R2315 (0x90B) - EQL_12
+ */
+#define WM2200_EQL_B3_C_MASK                    0xFFFF  /* EQL_B3_C - [15:0] */
+#define WM2200_EQL_B3_C_SHIFT                        0  /* EQL_B3_C - [15:0] */
+#define WM2200_EQL_B3_C_WIDTH                       16  /* EQL_B3_C - [15:0] */
+
+/*
+ * R2316 (0x90C) - EQL_13
+ */
+#define WM2200_EQL_B3_PG_MASK                   0xFFFF  /* EQL_B3_PG - [15:0] */
+#define WM2200_EQL_B3_PG_SHIFT                       0  /* EQL_B3_PG - [15:0] */
+#define WM2200_EQL_B3_PG_WIDTH                      16  /* EQL_B3_PG - [15:0] */
+
+/*
+ * R2317 (0x90D) - EQL_14
+ */
+#define WM2200_EQL_B4_A_MASK                    0xFFFF  /* EQL_B4_A - [15:0] */
+#define WM2200_EQL_B4_A_SHIFT                        0  /* EQL_B4_A - [15:0] */
+#define WM2200_EQL_B4_A_WIDTH                       16  /* EQL_B4_A - [15:0] */
+
+/*
+ * R2318 (0x90E) - EQL_15
+ */
+#define WM2200_EQL_B4_B_MASK                    0xFFFF  /* EQL_B4_B - [15:0] */
+#define WM2200_EQL_B4_B_SHIFT                        0  /* EQL_B4_B - [15:0] */
+#define WM2200_EQL_B4_B_WIDTH                       16  /* EQL_B4_B - [15:0] */
+
+/*
+ * R2319 (0x90F) - EQL_16
+ */
+#define WM2200_EQL_B4_C_MASK                    0xFFFF  /* EQL_B4_C - [15:0] */
+#define WM2200_EQL_B4_C_SHIFT                        0  /* EQL_B4_C - [15:0] */
+#define WM2200_EQL_B4_C_WIDTH                       16  /* EQL_B4_C - [15:0] */
+
+/*
+ * R2320 (0x910) - EQL_17
+ */
+#define WM2200_EQL_B4_PG_MASK                   0xFFFF  /* EQL_B4_PG - [15:0] */
+#define WM2200_EQL_B4_PG_SHIFT                       0  /* EQL_B4_PG - [15:0] */
+#define WM2200_EQL_B4_PG_WIDTH                      16  /* EQL_B4_PG - [15:0] */
+
+/*
+ * R2321 (0x911) - EQL_18
+ */
+#define WM2200_EQL_B5_A_MASK                    0xFFFF  /* EQL_B5_A - [15:0] */
+#define WM2200_EQL_B5_A_SHIFT                        0  /* EQL_B5_A - [15:0] */
+#define WM2200_EQL_B5_A_WIDTH                       16  /* EQL_B5_A - [15:0] */
+
+/*
+ * R2322 (0x912) - EQL_19
+ */
+#define WM2200_EQL_B5_B_MASK                    0xFFFF  /* EQL_B5_B - [15:0] */
+#define WM2200_EQL_B5_B_SHIFT                        0  /* EQL_B5_B - [15:0] */
+#define WM2200_EQL_B5_B_WIDTH                       16  /* EQL_B5_B - [15:0] */
+
+/*
+ * R2323 (0x913) - EQL_20
+ */
+#define WM2200_EQL_B5_PG_MASK                   0xFFFF  /* EQL_B5_PG - [15:0] */
+#define WM2200_EQL_B5_PG_SHIFT                       0  /* EQL_B5_PG - [15:0] */
+#define WM2200_EQL_B5_PG_WIDTH                      16  /* EQL_B5_PG - [15:0] */
+
+/*
+ * R2326 (0x916) - EQR_1
+ */
+#define WM2200_EQR_B1_GAIN_MASK                 0xF800  /* EQR_B1_GAIN - [15:11] */
+#define WM2200_EQR_B1_GAIN_SHIFT                    11  /* EQR_B1_GAIN - [15:11] */
+#define WM2200_EQR_B1_GAIN_WIDTH                     5  /* EQR_B1_GAIN - [15:11] */
+#define WM2200_EQR_B2_GAIN_MASK                 0x07C0  /* EQR_B2_GAIN - [10:6] */
+#define WM2200_EQR_B2_GAIN_SHIFT                     6  /* EQR_B2_GAIN - [10:6] */
+#define WM2200_EQR_B2_GAIN_WIDTH                     5  /* EQR_B2_GAIN - [10:6] */
+#define WM2200_EQR_B3_GAIN_MASK                 0x003E  /* EQR_B3_GAIN - [5:1] */
+#define WM2200_EQR_B3_GAIN_SHIFT                     1  /* EQR_B3_GAIN - [5:1] */
+#define WM2200_EQR_B3_GAIN_WIDTH                     5  /* EQR_B3_GAIN - [5:1] */
+#define WM2200_EQR_ENA                          0x0001  /* EQR_ENA */
+#define WM2200_EQR_ENA_MASK                     0x0001  /* EQR_ENA */
+#define WM2200_EQR_ENA_SHIFT                         0  /* EQR_ENA */
+#define WM2200_EQR_ENA_WIDTH                         1  /* EQR_ENA */
+
+/*
+ * R2327 (0x917) - EQR_2
+ */
+#define WM2200_EQR_B4_GAIN_MASK                 0xF800  /* EQR_B4_GAIN - [15:11] */
+#define WM2200_EQR_B4_GAIN_SHIFT                    11  /* EQR_B4_GAIN - [15:11] */
+#define WM2200_EQR_B4_GAIN_WIDTH                     5  /* EQR_B4_GAIN - [15:11] */
+#define WM2200_EQR_B5_GAIN_MASK                 0x07C0  /* EQR_B5_GAIN - [10:6] */
+#define WM2200_EQR_B5_GAIN_SHIFT                     6  /* EQR_B5_GAIN - [10:6] */
+#define WM2200_EQR_B5_GAIN_WIDTH                     5  /* EQR_B5_GAIN - [10:6] */
+
+/*
+ * R2328 (0x918) - EQR_3
+ */
+#define WM2200_EQR_B1_A_MASK                    0xFFFF  /* EQR_B1_A - [15:0] */
+#define WM2200_EQR_B1_A_SHIFT                        0  /* EQR_B1_A - [15:0] */
+#define WM2200_EQR_B1_A_WIDTH                       16  /* EQR_B1_A - [15:0] */
+
+/*
+ * R2329 (0x919) - EQR_4
+ */
+#define WM2200_EQR_B1_B_MASK                    0xFFFF  /* EQR_B1_B - [15:0] */
+#define WM2200_EQR_B1_B_SHIFT                        0  /* EQR_B1_B - [15:0] */
+#define WM2200_EQR_B1_B_WIDTH                       16  /* EQR_B1_B - [15:0] */
+
+/*
+ * R2330 (0x91A) - EQR_5
+ */
+#define WM2200_EQR_B1_PG_MASK                   0xFFFF  /* EQR_B1_PG - [15:0] */
+#define WM2200_EQR_B1_PG_SHIFT                       0  /* EQR_B1_PG - [15:0] */
+#define WM2200_EQR_B1_PG_WIDTH                      16  /* EQR_B1_PG - [15:0] */
+
+/*
+ * R2331 (0x91B) - EQR_6
+ */
+#define WM2200_EQR_B2_A_MASK                    0xFFFF  /* EQR_B2_A - [15:0] */
+#define WM2200_EQR_B2_A_SHIFT                        0  /* EQR_B2_A - [15:0] */
+#define WM2200_EQR_B2_A_WIDTH                       16  /* EQR_B2_A - [15:0] */
+
+/*
+ * R2332 (0x91C) - EQR_7
+ */
+#define WM2200_EQR_B2_B_MASK                    0xFFFF  /* EQR_B2_B - [15:0] */
+#define WM2200_EQR_B2_B_SHIFT                        0  /* EQR_B2_B - [15:0] */
+#define WM2200_EQR_B2_B_WIDTH                       16  /* EQR_B2_B - [15:0] */
+
+/*
+ * R2333 (0x91D) - EQR_8
+ */
+#define WM2200_EQR_B2_C_MASK                    0xFFFF  /* EQR_B2_C - [15:0] */
+#define WM2200_EQR_B2_C_SHIFT                        0  /* EQR_B2_C - [15:0] */
+#define WM2200_EQR_B2_C_WIDTH                       16  /* EQR_B2_C - [15:0] */
+
+/*
+ * R2334 (0x91E) - EQR_9
+ */
+#define WM2200_EQR_B2_PG_MASK                   0xFFFF  /* EQR_B2_PG - [15:0] */
+#define WM2200_EQR_B2_PG_SHIFT                       0  /* EQR_B2_PG - [15:0] */
+#define WM2200_EQR_B2_PG_WIDTH                      16  /* EQR_B2_PG - [15:0] */
+
+/*
+ * R2335 (0x91F) - EQR_10
+ */
+#define WM2200_EQR_B3_A_MASK                    0xFFFF  /* EQR_B3_A - [15:0] */
+#define WM2200_EQR_B3_A_SHIFT                        0  /* EQR_B3_A - [15:0] */
+#define WM2200_EQR_B3_A_WIDTH                       16  /* EQR_B3_A - [15:0] */
+
+/*
+ * R2336 (0x920) - EQR_11
+ */
+#define WM2200_EQR_B3_B_MASK                    0xFFFF  /* EQR_B3_B - [15:0] */
+#define WM2200_EQR_B3_B_SHIFT                        0  /* EQR_B3_B - [15:0] */
+#define WM2200_EQR_B3_B_WIDTH                       16  /* EQR_B3_B - [15:0] */
+
+/*
+ * R2337 (0x921) - EQR_12
+ */
+#define WM2200_EQR_B3_C_MASK                    0xFFFF  /* EQR_B3_C - [15:0] */
+#define WM2200_EQR_B3_C_SHIFT                        0  /* EQR_B3_C - [15:0] */
+#define WM2200_EQR_B3_C_WIDTH                       16  /* EQR_B3_C - [15:0] */
+
+/*
+ * R2338 (0x922) - EQR_13
+ */
+#define WM2200_EQR_B3_PG_MASK                   0xFFFF  /* EQR_B3_PG - [15:0] */
+#define WM2200_EQR_B3_PG_SHIFT                       0  /* EQR_B3_PG - [15:0] */
+#define WM2200_EQR_B3_PG_WIDTH                      16  /* EQR_B3_PG - [15:0] */
+
+/*
+ * R2339 (0x923) - EQR_14
+ */
+#define WM2200_EQR_B4_A_MASK                    0xFFFF  /* EQR_B4_A - [15:0] */
+#define WM2200_EQR_B4_A_SHIFT                        0  /* EQR_B4_A - [15:0] */
+#define WM2200_EQR_B4_A_WIDTH                       16  /* EQR_B4_A - [15:0] */
+
+/*
+ * R2340 (0x924) - EQR_15
+ */
+#define WM2200_EQR_B4_B_MASK                    0xFFFF  /* EQR_B4_B - [15:0] */
+#define WM2200_EQR_B4_B_SHIFT                        0  /* EQR_B4_B - [15:0] */
+#define WM2200_EQR_B4_B_WIDTH                       16  /* EQR_B4_B - [15:0] */
+
+/*
+ * R2341 (0x925) - EQR_16
+ */
+#define WM2200_EQR_B4_C_MASK                    0xFFFF  /* EQR_B4_C - [15:0] */
+#define WM2200_EQR_B4_C_SHIFT                        0  /* EQR_B4_C - [15:0] */
+#define WM2200_EQR_B4_C_WIDTH                       16  /* EQR_B4_C - [15:0] */
+
+/*
+ * R2342 (0x926) - EQR_17
+ */
+#define WM2200_EQR_B4_PG_MASK                   0xFFFF  /* EQR_B4_PG - [15:0] */
+#define WM2200_EQR_B4_PG_SHIFT                       0  /* EQR_B4_PG - [15:0] */
+#define WM2200_EQR_B4_PG_WIDTH                      16  /* EQR_B4_PG - [15:0] */
+
+/*
+ * R2343 (0x927) - EQR_18
+ */
+#define WM2200_EQR_B5_A_MASK                    0xFFFF  /* EQR_B5_A - [15:0] */
+#define WM2200_EQR_B5_A_SHIFT                        0  /* EQR_B5_A - [15:0] */
+#define WM2200_EQR_B5_A_WIDTH                       16  /* EQR_B5_A - [15:0] */
+
+/*
+ * R2344 (0x928) - EQR_19
+ */
+#define WM2200_EQR_B5_B_MASK                    0xFFFF  /* EQR_B5_B - [15:0] */
+#define WM2200_EQR_B5_B_SHIFT                        0  /* EQR_B5_B - [15:0] */
+#define WM2200_EQR_B5_B_WIDTH                       16  /* EQR_B5_B - [15:0] */
+
+/*
+ * R2345 (0x929) - EQR_20
+ */
+#define WM2200_EQR_B5_PG_MASK                   0xFFFF  /* EQR_B5_PG - [15:0] */
+#define WM2200_EQR_B5_PG_SHIFT                       0  /* EQR_B5_PG - [15:0] */
+#define WM2200_EQR_B5_PG_WIDTH                      16  /* EQR_B5_PG - [15:0] */
+
+/*
+ * R2366 (0x93E) - HPLPF1_1
+ */
+#define WM2200_LHPF1_MODE                       0x0002  /* LHPF1_MODE */
+#define WM2200_LHPF1_MODE_MASK                  0x0002  /* LHPF1_MODE */
+#define WM2200_LHPF1_MODE_SHIFT                      1  /* LHPF1_MODE */
+#define WM2200_LHPF1_MODE_WIDTH                      1  /* LHPF1_MODE */
+#define WM2200_LHPF1_ENA                        0x0001  /* LHPF1_ENA */
+#define WM2200_LHPF1_ENA_MASK                   0x0001  /* LHPF1_ENA */
+#define WM2200_LHPF1_ENA_SHIFT                       0  /* LHPF1_ENA */
+#define WM2200_LHPF1_ENA_WIDTH                       1  /* LHPF1_ENA */
+
+/*
+ * R2367 (0x93F) - HPLPF1_2
+ */
+#define WM2200_LHPF1_COEFF_MASK                 0xFFFF  /* LHPF1_COEFF - [15:0] */
+#define WM2200_LHPF1_COEFF_SHIFT                     0  /* LHPF1_COEFF - [15:0] */
+#define WM2200_LHPF1_COEFF_WIDTH                    16  /* LHPF1_COEFF - [15:0] */
+
+/*
+ * R2370 (0x942) - HPLPF2_1
+ */
+#define WM2200_LHPF2_MODE                       0x0002  /* LHPF2_MODE */
+#define WM2200_LHPF2_MODE_MASK                  0x0002  /* LHPF2_MODE */
+#define WM2200_LHPF2_MODE_SHIFT                      1  /* LHPF2_MODE */
+#define WM2200_LHPF2_MODE_WIDTH                      1  /* LHPF2_MODE */
+#define WM2200_LHPF2_ENA                        0x0001  /* LHPF2_ENA */
+#define WM2200_LHPF2_ENA_MASK                   0x0001  /* LHPF2_ENA */
+#define WM2200_LHPF2_ENA_SHIFT                       0  /* LHPF2_ENA */
+#define WM2200_LHPF2_ENA_WIDTH                       1  /* LHPF2_ENA */
+
+/*
+ * R2371 (0x943) - HPLPF2_2
+ */
+#define WM2200_LHPF2_COEFF_MASK                 0xFFFF  /* LHPF2_COEFF - [15:0] */
+#define WM2200_LHPF2_COEFF_SHIFT                     0  /* LHPF2_COEFF - [15:0] */
+#define WM2200_LHPF2_COEFF_WIDTH                    16  /* LHPF2_COEFF - [15:0] */
+
+/*
+ * R2560 (0xA00) - DSP1 Control 1
+ */
+#define WM2200_DSP1_RW_SEQUENCE_ENA             0x0001  /* DSP1_RW_SEQUENCE_ENA */
+#define WM2200_DSP1_RW_SEQUENCE_ENA_MASK        0x0001  /* DSP1_RW_SEQUENCE_ENA */
+#define WM2200_DSP1_RW_SEQUENCE_ENA_SHIFT            0  /* DSP1_RW_SEQUENCE_ENA */
+#define WM2200_DSP1_RW_SEQUENCE_ENA_WIDTH            1  /* DSP1_RW_SEQUENCE_ENA */
+
+/*
+ * R2562 (0xA02) - DSP1 Control 2
+ */
+#define WM2200_DSP1_PAGE_BASE_PM_0_MASK         0xFF00  /* DSP1_PAGE_BASE_PM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_PM_0_SHIFT             8  /* DSP1_PAGE_BASE_PM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_PM_0_WIDTH             8  /* DSP1_PAGE_BASE_PM - [15:8] */
+
+/*
+ * R2563 (0xA03) - DSP1 Control 3
+ */
+#define WM2200_DSP1_PAGE_BASE_DM_0_MASK         0xFF00  /* DSP1_PAGE_BASE_DM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_DM_0_SHIFT             8  /* DSP1_PAGE_BASE_DM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_DM_0_WIDTH             8  /* DSP1_PAGE_BASE_DM - [15:8] */
+
+/*
+ * R2564 (0xA04) - DSP1 Control 4
+ */
+#define WM2200_DSP1_PAGE_BASE_ZM_0_MASK         0xFF00  /* DSP1_PAGE_BASE_ZM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_ZM_0_SHIFT             8  /* DSP1_PAGE_BASE_ZM - [15:8] */
+#define WM2200_DSP1_PAGE_BASE_ZM_0_WIDTH             8  /* DSP1_PAGE_BASE_ZM - [15:8] */
+
+/*
+ * R2566 (0xA06) - DSP1 Control 5
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_0_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_0_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_0_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+
+/*
+ * R2567 (0xA07) - DSP1 Control 6
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_1_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_1_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_1_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+
+/*
+ * R2568 (0xA08) - DSP1 Control 7
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_2_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_2_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_2_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+
+/*
+ * R2569 (0xA09) - DSP1 Control 8
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_3_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_3_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_3_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+
+/*
+ * R2570 (0xA0A) - DSP1 Control 9
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_4_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_4_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_4_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+
+/*
+ * R2571 (0xA0B) - DSP1 Control 10
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_5_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_5_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_5_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+
+/*
+ * R2572 (0xA0C) - DSP1 Control 11
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_6_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_6_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_6_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+
+/*
+ * R2573 (0xA0D) - DSP1 Control 12
+ */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_7_MASK 0x3FFF  /* DSP1_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_7_SHIFT      0  /* DSP1_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_WDMA_BUFFER_7_WIDTH     14  /* DSP1_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+
+/*
+ * R2575 (0xA0F) - DSP1 Control 13
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_0_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_0_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_0_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+
+/*
+ * R2576 (0xA10) - DSP1 Control 14
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_1_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_1_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_1_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+
+/*
+ * R2577 (0xA11) - DSP1 Control 15
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_2_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_2_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_2_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+
+/*
+ * R2578 (0xA12) - DSP1 Control 16
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_3_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_3_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_3_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+
+/*
+ * R2579 (0xA13) - DSP1 Control 17
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_4_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_4_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_4_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+
+/*
+ * R2580 (0xA14) - DSP1 Control 18
+ */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_5_MASK 0x3FFF  /* DSP1_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_5_SHIFT      0  /* DSP1_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP1_START_ADDRESS_RDMA_BUFFER_5_WIDTH     14  /* DSP1_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+
+/*
+ * R2582 (0xA16) - DSP1 Control 19
+ */
+#define WM2200_DSP1_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+#define WM2200_DSP1_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+#define WM2200_DSP1_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+
+/*
+ * R2583 (0xA17) - DSP1 Control 20
+ */
+#define WM2200_DSP1_WDMA_CHANNEL_ENABLE_MASK    0x00FF  /* DSP1_WDMA_CHANNEL_ENABLE - [7:0] */
+#define WM2200_DSP1_WDMA_CHANNEL_ENABLE_SHIFT        0  /* DSP1_WDMA_CHANNEL_ENABLE - [7:0] */
+#define WM2200_DSP1_WDMA_CHANNEL_ENABLE_WIDTH        8  /* DSP1_WDMA_CHANNEL_ENABLE - [7:0] */
+
+/*
+ * R2584 (0xA18) - DSP1 Control 21
+ */
+#define WM2200_DSP1_RDMA_CHANNEL_ENABLE_MASK    0x003F  /* DSP1_RDMA_CHANNEL_ENABLE - [5:0] */
+#define WM2200_DSP1_RDMA_CHANNEL_ENABLE_SHIFT        0  /* DSP1_RDMA_CHANNEL_ENABLE - [5:0] */
+#define WM2200_DSP1_RDMA_CHANNEL_ENABLE_WIDTH        6  /* DSP1_RDMA_CHANNEL_ENABLE - [5:0] */
+
+/*
+ * R2586 (0xA1A) - DSP1 Control 22
+ */
+#define WM2200_DSP1_DM_SIZE_MASK                0xFFFF  /* DSP1_DM_SIZE - [15:0] */
+#define WM2200_DSP1_DM_SIZE_SHIFT                    0  /* DSP1_DM_SIZE - [15:0] */
+#define WM2200_DSP1_DM_SIZE_WIDTH                   16  /* DSP1_DM_SIZE - [15:0] */
+
+/*
+ * R2587 (0xA1B) - DSP1 Control 23
+ */
+#define WM2200_DSP1_PM_SIZE_MASK                0xFFFF  /* DSP1_PM_SIZE - [15:0] */
+#define WM2200_DSP1_PM_SIZE_SHIFT                    0  /* DSP1_PM_SIZE - [15:0] */
+#define WM2200_DSP1_PM_SIZE_WIDTH                   16  /* DSP1_PM_SIZE - [15:0] */
+
+/*
+ * R2588 (0xA1C) - DSP1 Control 24
+ */
+#define WM2200_DSP1_ZM_SIZE_MASK                0xFFFF  /* DSP1_ZM_SIZE - [15:0] */
+#define WM2200_DSP1_ZM_SIZE_SHIFT                    0  /* DSP1_ZM_SIZE - [15:0] */
+#define WM2200_DSP1_ZM_SIZE_WIDTH                   16  /* DSP1_ZM_SIZE - [15:0] */
+
+/*
+ * R2590 (0xA1E) - DSP1 Control 25
+ */
+#define WM2200_DSP1_PING_FULL                   0x8000  /* DSP1_PING_FULL */
+#define WM2200_DSP1_PING_FULL_MASK              0x8000  /* DSP1_PING_FULL */
+#define WM2200_DSP1_PING_FULL_SHIFT                 15  /* DSP1_PING_FULL */
+#define WM2200_DSP1_PING_FULL_WIDTH                  1  /* DSP1_PING_FULL */
+#define WM2200_DSP1_PONG_FULL                   0x4000  /* DSP1_PONG_FULL */
+#define WM2200_DSP1_PONG_FULL_MASK              0x4000  /* DSP1_PONG_FULL */
+#define WM2200_DSP1_PONG_FULL_SHIFT                 14  /* DSP1_PONG_FULL */
+#define WM2200_DSP1_PONG_FULL_WIDTH                  1  /* DSP1_PONG_FULL */
+#define WM2200_DSP1_WDMA_ACTIVE_CHANNELS_MASK   0x00FF  /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */
+#define WM2200_DSP1_WDMA_ACTIVE_CHANNELS_SHIFT       0  /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */
+#define WM2200_DSP1_WDMA_ACTIVE_CHANNELS_WIDTH       8  /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */
+
+/*
+ * R2592 (0xA20) - DSP1 Control 26
+ */
+#define WM2200_DSP1_SCRATCH_0_MASK              0xFFFF  /* DSP1_SCRATCH_0 - [15:0] */
+#define WM2200_DSP1_SCRATCH_0_SHIFT                  0  /* DSP1_SCRATCH_0 - [15:0] */
+#define WM2200_DSP1_SCRATCH_0_WIDTH                 16  /* DSP1_SCRATCH_0 - [15:0] */
+
+/*
+ * R2593 (0xA21) - DSP1 Control 27
+ */
+#define WM2200_DSP1_SCRATCH_1_MASK              0xFFFF  /* DSP1_SCRATCH_1 - [15:0] */
+#define WM2200_DSP1_SCRATCH_1_SHIFT                  0  /* DSP1_SCRATCH_1 - [15:0] */
+#define WM2200_DSP1_SCRATCH_1_WIDTH                 16  /* DSP1_SCRATCH_1 - [15:0] */
+
+/*
+ * R2594 (0xA22) - DSP1 Control 28
+ */
+#define WM2200_DSP1_SCRATCH_2_MASK              0xFFFF  /* DSP1_SCRATCH_2 - [15:0] */
+#define WM2200_DSP1_SCRATCH_2_SHIFT                  0  /* DSP1_SCRATCH_2 - [15:0] */
+#define WM2200_DSP1_SCRATCH_2_WIDTH                 16  /* DSP1_SCRATCH_2 - [15:0] */
+
+/*
+ * R2595 (0xA23) - DSP1 Control 29
+ */
+#define WM2200_DSP1_SCRATCH_3_MASK              0xFFFF  /* DSP1_SCRATCH_3 - [15:0] */
+#define WM2200_DSP1_SCRATCH_3_SHIFT                  0  /* DSP1_SCRATCH_3 - [15:0] */
+#define WM2200_DSP1_SCRATCH_3_WIDTH                 16  /* DSP1_SCRATCH_3 - [15:0] */
+
+/*
+ * R2596 (0xA24) - DSP1 Control 30
+ */
+#define WM2200_DSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
+#define WM2200_DSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
+#define WM2200_DSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
+#define WM2200_DSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
+#define WM2200_DSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
+#define WM2200_DSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
+#define WM2200_DSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
+#define WM2200_DSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
+#define WM2200_DSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
+#define WM2200_DSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
+#define WM2200_DSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
+#define WM2200_DSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
+#define WM2200_DSP1_START                       0x0001  /* DSP1_START */
+#define WM2200_DSP1_START_MASK                  0x0001  /* DSP1_START */
+#define WM2200_DSP1_START_SHIFT                      0  /* DSP1_START */
+#define WM2200_DSP1_START_WIDTH                      1  /* DSP1_START */
+
+/*
+ * R2598 (0xA26) - DSP1 Control 31
+ */
+#define WM2200_DSP1_CLK_RATE_MASK               0x0018  /* DSP1_CLK_RATE - [4:3] */
+#define WM2200_DSP1_CLK_RATE_SHIFT                   3  /* DSP1_CLK_RATE - [4:3] */
+#define WM2200_DSP1_CLK_RATE_WIDTH                   2  /* DSP1_CLK_RATE - [4:3] */
+#define WM2200_DSP1_CLK_AVAIL                   0x0004  /* DSP1_CLK_AVAIL */
+#define WM2200_DSP1_CLK_AVAIL_MASK              0x0004  /* DSP1_CLK_AVAIL */
+#define WM2200_DSP1_CLK_AVAIL_SHIFT                  2  /* DSP1_CLK_AVAIL */
+#define WM2200_DSP1_CLK_AVAIL_WIDTH                  1  /* DSP1_CLK_AVAIL */
+#define WM2200_DSP1_CLK_REQ_MASK                0x0003  /* DSP1_CLK_REQ - [1:0] */
+#define WM2200_DSP1_CLK_REQ_SHIFT                    0  /* DSP1_CLK_REQ - [1:0] */
+#define WM2200_DSP1_CLK_REQ_WIDTH                    2  /* DSP1_CLK_REQ - [1:0] */
+
+/*
+ * R2816 (0xB00) - DSP2 Control 1
+ */
+#define WM2200_DSP2_RW_SEQUENCE_ENA             0x0001  /* DSP2_RW_SEQUENCE_ENA */
+#define WM2200_DSP2_RW_SEQUENCE_ENA_MASK        0x0001  /* DSP2_RW_SEQUENCE_ENA */
+#define WM2200_DSP2_RW_SEQUENCE_ENA_SHIFT            0  /* DSP2_RW_SEQUENCE_ENA */
+#define WM2200_DSP2_RW_SEQUENCE_ENA_WIDTH            1  /* DSP2_RW_SEQUENCE_ENA */
+
+/*
+ * R2818 (0xB02) - DSP2 Control 2
+ */
+#define WM2200_DSP2_PAGE_BASE_PM_0_MASK         0xFF00  /* DSP2_PAGE_BASE_PM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_PM_0_SHIFT             8  /* DSP2_PAGE_BASE_PM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_PM_0_WIDTH             8  /* DSP2_PAGE_BASE_PM - [15:8] */
+
+/*
+ * R2819 (0xB03) - DSP2 Control 3
+ */
+#define WM2200_DSP2_PAGE_BASE_DM_0_MASK         0xFF00  /* DSP2_PAGE_BASE_DM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_DM_0_SHIFT             8  /* DSP2_PAGE_BASE_DM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_DM_0_WIDTH             8  /* DSP2_PAGE_BASE_DM - [15:8] */
+
+/*
+ * R2820 (0xB04) - DSP2 Control 4
+ */
+#define WM2200_DSP2_PAGE_BASE_ZM_0_MASK         0xFF00  /* DSP2_PAGE_BASE_ZM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_ZM_0_SHIFT             8  /* DSP2_PAGE_BASE_ZM - [15:8] */
+#define WM2200_DSP2_PAGE_BASE_ZM_0_WIDTH             8  /* DSP2_PAGE_BASE_ZM - [15:8] */
+
+/*
+ * R2822 (0xB06) - DSP2 Control 5
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_0_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_0_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_0_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_0 - [13:0] */
+
+/*
+ * R2823 (0xB07) - DSP2 Control 6
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_1_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_1_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_1_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_1 - [13:0] */
+
+/*
+ * R2824 (0xB08) - DSP2 Control 7
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_2_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_2_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_2_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_2 - [13:0] */
+
+/*
+ * R2825 (0xB09) - DSP2 Control 8
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_3_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_3_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_3_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_3 - [13:0] */
+
+/*
+ * R2826 (0xB0A) - DSP2 Control 9
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_4_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_4_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_4_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_4 - [13:0] */
+
+/*
+ * R2827 (0xB0B) - DSP2 Control 10
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_5_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_5_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_5_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_5 - [13:0] */
+
+/*
+ * R2828 (0xB0C) - DSP2 Control 11
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_6_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_6_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_6_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_6 - [13:0] */
+
+/*
+ * R2829 (0xB0D) - DSP2 Control 12
+ */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_7_MASK 0x3FFF  /* DSP2_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_7_SHIFT      0  /* DSP2_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_WDMA_BUFFER_7_WIDTH     14  /* DSP2_START_ADDRESS_WDMA_BUFFER_7 - [13:0] */
+
+/*
+ * R2831 (0xB0F) - DSP2 Control 13
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_0_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_0_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_0_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_0 - [13:0] */
+
+/*
+ * R2832 (0xB10) - DSP2 Control 14
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_1_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_1_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_1_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_1 - [13:0] */
+
+/*
+ * R2833 (0xB11) - DSP2 Control 15
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_2_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_2_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_2_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_2 - [13:0] */
+
+/*
+ * R2834 (0xB12) - DSP2 Control 16
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_3_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_3_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_3_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_3 - [13:0] */
+
+/*
+ * R2835 (0xB13) - DSP2 Control 17
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_4_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_4_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_4_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_4 - [13:0] */
+
+/*
+ * R2836 (0xB14) - DSP2 Control 18
+ */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_5_MASK 0x3FFF  /* DSP2_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_5_SHIFT      0  /* DSP2_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+#define WM2200_DSP2_START_ADDRESS_RDMA_BUFFER_5_WIDTH     14  /* DSP2_START_ADDRESS_RDMA_BUFFER_5 - [13:0] */
+
+/*
+ * R2838 (0xB16) - DSP2 Control 19
+ */
+#define WM2200_DSP2_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP2_WDMA_BUFFER_LENGTH - [7:0] */
+#define WM2200_DSP2_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP2_WDMA_BUFFER_LENGTH - [7:0] */
+#define WM2200_DSP2_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP2_WDMA_BUFFER_LENGTH - [7:0] */
+
+/*
+ * R2839 (0xB17) - DSP2 Control 20
+ */
+#define WM2200_DSP2_WDMA_CHANNEL_ENABLE_MASK    0x00FF  /* DSP2_WDMA_CHANNEL_ENABLE - [7:0] */
+#define WM2200_DSP2_WDMA_CHANNEL_ENABLE_SHIFT        0  /* DSP2_WDMA_CHANNEL_ENABLE - [7:0] */
+#define WM2200_DSP2_WDMA_CHANNEL_ENABLE_WIDTH        8  /* DSP2_WDMA_CHANNEL_ENABLE - [7:0] */
+
+/*
+ * R2840 (0xB18) - DSP2 Control 21
+ */
+#define WM2200_DSP2_RDMA_CHANNEL_ENABLE_MASK    0x003F  /* DSP2_RDMA_CHANNEL_ENABLE - [5:0] */
+#define WM2200_DSP2_RDMA_CHANNEL_ENABLE_SHIFT        0  /* DSP2_RDMA_CHANNEL_ENABLE - [5:0] */
+#define WM2200_DSP2_RDMA_CHANNEL_ENABLE_WIDTH        6  /* DSP2_RDMA_CHANNEL_ENABLE - [5:0] */
+
+/*
+ * R2842 (0xB1A) - DSP2 Control 22
+ */
+#define WM2200_DSP2_DM_SIZE_MASK                0xFFFF  /* DSP2_DM_SIZE - [15:0] */
+#define WM2200_DSP2_DM_SIZE_SHIFT                    0  /* DSP2_DM_SIZE - [15:0] */
+#define WM2200_DSP2_DM_SIZE_WIDTH                   16  /* DSP2_DM_SIZE - [15:0] */
+
+/*
+ * R2843 (0xB1B) - DSP2 Control 23
+ */
+#define WM2200_DSP2_PM_SIZE_MASK                0xFFFF  /* DSP2_PM_SIZE - [15:0] */
+#define WM2200_DSP2_PM_SIZE_SHIFT                    0  /* DSP2_PM_SIZE - [15:0] */
+#define WM2200_DSP2_PM_SIZE_WIDTH                   16  /* DSP2_PM_SIZE - [15:0] */
+
+/*
+ * R2844 (0xB1C) - DSP2 Control 24
+ */
+#define WM2200_DSP2_ZM_SIZE_MASK                0xFFFF  /* DSP2_ZM_SIZE - [15:0] */
+#define WM2200_DSP2_ZM_SIZE_SHIFT                    0  /* DSP2_ZM_SIZE - [15:0] */
+#define WM2200_DSP2_ZM_SIZE_WIDTH                   16  /* DSP2_ZM_SIZE - [15:0] */
+
+/*
+ * R2846 (0xB1E) - DSP2 Control 25
+ */
+#define WM2200_DSP2_PING_FULL                   0x8000  /* DSP2_PING_FULL */
+#define WM2200_DSP2_PING_FULL_MASK              0x8000  /* DSP2_PING_FULL */
+#define WM2200_DSP2_PING_FULL_SHIFT                 15  /* DSP2_PING_FULL */
+#define WM2200_DSP2_PING_FULL_WIDTH                  1  /* DSP2_PING_FULL */
+#define WM2200_DSP2_PONG_FULL                   0x4000  /* DSP2_PONG_FULL */
+#define WM2200_DSP2_PONG_FULL_MASK              0x4000  /* DSP2_PONG_FULL */
+#define WM2200_DSP2_PONG_FULL_SHIFT                 14  /* DSP2_PONG_FULL */
+#define WM2200_DSP2_PONG_FULL_WIDTH                  1  /* DSP2_PONG_FULL */
+#define WM2200_DSP2_WDMA_ACTIVE_CHANNELS_MASK   0x00FF  /* DSP2_WDMA_ACTIVE_CHANNELS - [7:0] */
+#define WM2200_DSP2_WDMA_ACTIVE_CHANNELS_SHIFT       0  /* DSP2_WDMA_ACTIVE_CHANNELS - [7:0] */
+#define WM2200_DSP2_WDMA_ACTIVE_CHANNELS_WIDTH       8  /* DSP2_WDMA_ACTIVE_CHANNELS - [7:0] */
+
+/*
+ * R2848 (0xB20) - DSP2 Control 26
+ */
+#define WM2200_DSP2_SCRATCH_0_MASK              0xFFFF  /* DSP2_SCRATCH_0 - [15:0] */
+#define WM2200_DSP2_SCRATCH_0_SHIFT                  0  /* DSP2_SCRATCH_0 - [15:0] */
+#define WM2200_DSP2_SCRATCH_0_WIDTH                 16  /* DSP2_SCRATCH_0 - [15:0] */
+
+/*
+ * R2849 (0xB21) - DSP2 Control 27
+ */
+#define WM2200_DSP2_SCRATCH_1_MASK              0xFFFF  /* DSP2_SCRATCH_1 - [15:0] */
+#define WM2200_DSP2_SCRATCH_1_SHIFT                  0  /* DSP2_SCRATCH_1 - [15:0] */
+#define WM2200_DSP2_SCRATCH_1_WIDTH                 16  /* DSP2_SCRATCH_1 - [15:0] */
+
+/*
+ * R2850 (0xB22) - DSP2 Control 28
+ */
+#define WM2200_DSP2_SCRATCH_2_MASK              0xFFFF  /* DSP2_SCRATCH_2 - [15:0] */
+#define WM2200_DSP2_SCRATCH_2_SHIFT                  0  /* DSP2_SCRATCH_2 - [15:0] */
+#define WM2200_DSP2_SCRATCH_2_WIDTH                 16  /* DSP2_SCRATCH_2 - [15:0] */
+
+/*
+ * R2851 (0xB23) - DSP2 Control 29
+ */
+#define WM2200_DSP2_SCRATCH_3_MASK              0xFFFF  /* DSP2_SCRATCH_3 - [15:0] */
+#define WM2200_DSP2_SCRATCH_3_SHIFT                  0  /* DSP2_SCRATCH_3 - [15:0] */
+#define WM2200_DSP2_SCRATCH_3_WIDTH                 16  /* DSP2_SCRATCH_3 - [15:0] */
+
+/*
+ * R2852 (0xB24) - DSP2 Control 30
+ */
+#define WM2200_DSP2_DBG_CLK_ENA                 0x0008  /* DSP2_DBG_CLK_ENA */
+#define WM2200_DSP2_DBG_CLK_ENA_MASK            0x0008  /* DSP2_DBG_CLK_ENA */
+#define WM2200_DSP2_DBG_CLK_ENA_SHIFT                3  /* DSP2_DBG_CLK_ENA */
+#define WM2200_DSP2_DBG_CLK_ENA_WIDTH                1  /* DSP2_DBG_CLK_ENA */
+#define WM2200_DSP2_SYS_ENA                     0x0004  /* DSP2_SYS_ENA */
+#define WM2200_DSP2_SYS_ENA_MASK                0x0004  /* DSP2_SYS_ENA */
+#define WM2200_DSP2_SYS_ENA_SHIFT                    2  /* DSP2_SYS_ENA */
+#define WM2200_DSP2_SYS_ENA_WIDTH                    1  /* DSP2_SYS_ENA */
+#define WM2200_DSP2_CORE_ENA                    0x0002  /* DSP2_CORE_ENA */
+#define WM2200_DSP2_CORE_ENA_MASK               0x0002  /* DSP2_CORE_ENA */
+#define WM2200_DSP2_CORE_ENA_SHIFT                   1  /* DSP2_CORE_ENA */
+#define WM2200_DSP2_CORE_ENA_WIDTH                   1  /* DSP2_CORE_ENA */
+#define WM2200_DSP2_START                       0x0001  /* DSP2_START */
+#define WM2200_DSP2_START_MASK                  0x0001  /* DSP2_START */
+#define WM2200_DSP2_START_SHIFT                      0  /* DSP2_START */
+#define WM2200_DSP2_START_WIDTH                      1  /* DSP2_START */
+
+/*
+ * R2854 (0xB26) - DSP2 Control 31
+ */
+#define WM2200_DSP2_CLK_RATE_MASK               0x0018  /* DSP2_CLK_RATE - [4:3] */
+#define WM2200_DSP2_CLK_RATE_SHIFT                   3  /* DSP2_CLK_RATE - [4:3] */
+#define WM2200_DSP2_CLK_RATE_WIDTH                   2  /* DSP2_CLK_RATE - [4:3] */
+#define WM2200_DSP2_CLK_AVAIL                   0x0004  /* DSP2_CLK_AVAIL */
+#define WM2200_DSP2_CLK_AVAIL_MASK              0x0004  /* DSP2_CLK_AVAIL */
+#define WM2200_DSP2_CLK_AVAIL_SHIFT                  2  /* DSP2_CLK_AVAIL */
+#define WM2200_DSP2_CLK_AVAIL_WIDTH                  1  /* DSP2_CLK_AVAIL */
+#define WM2200_DSP2_CLK_REQ_MASK                0x0003  /* DSP2_CLK_REQ - [1:0] */
+#define WM2200_DSP2_CLK_REQ_SHIFT                    0  /* DSP2_CLK_REQ - [1:0] */
+#define WM2200_DSP2_CLK_REQ_WIDTH                    2  /* DSP2_CLK_REQ - [1:0] */
+
+#endif
diff --git a/sound/soc/codecs/wm5100-tables.c b/sound/soc/codecs/wm5100-tables.c
new file mode 100644
index 0000000..9e987cf
--- /dev/null
+++ b/sound/soc/codecs/wm5100-tables.c
@@ -0,0 +1,1485 @@
+/*
+ * wm5100-tables.c  --  WM5100 ALSA SoC Audio driver data
+ *
+ * Copyright 2011-2 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "wm5100.h"
+
+bool wm5100_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM5100_SOFTWARE_RESET:
+	case WM5100_DEVICE_REVISION:
+	case WM5100_FX_CTRL:
+	case WM5100_INTERRUPT_STATUS_1:
+	case WM5100_INTERRUPT_STATUS_2:
+	case WM5100_INTERRUPT_STATUS_3:
+	case WM5100_INTERRUPT_STATUS_4:
+	case WM5100_INTERRUPT_RAW_STATUS_2:
+	case WM5100_INTERRUPT_RAW_STATUS_3:
+	case WM5100_INTERRUPT_RAW_STATUS_4:
+	case WM5100_OUTPUT_STATUS_1:
+	case WM5100_OUTPUT_STATUS_2:
+	case WM5100_INPUT_ENABLES_STATUS:
+	case WM5100_MIC_DETECT_3:
+		return true;
+	default:
+		if ((reg >= WM5100_DSP1_PM_0 && reg <= WM5100_DSP1_PM_1535) ||
+		    (reg >= WM5100_DSP1_ZM_0 && reg <= WM5100_DSP1_ZM_2047) ||
+		    (reg >= WM5100_DSP1_DM_0 && reg <= WM5100_DSP1_DM_511) ||
+		    (reg >= WM5100_DSP2_PM_0 && reg <= WM5100_DSP2_PM_1535) ||
+		    (reg >= WM5100_DSP2_ZM_0 && reg <= WM5100_DSP2_ZM_2047) ||
+		    (reg >= WM5100_DSP2_DM_0 && reg <= WM5100_DSP2_DM_511) ||
+		    (reg >= WM5100_DSP3_PM_0 && reg <= WM5100_DSP3_PM_1535) ||
+		    (reg >= WM5100_DSP3_ZM_0 && reg <= WM5100_DSP3_ZM_2047) ||
+		    (reg >= WM5100_DSP3_DM_0 && reg <= WM5100_DSP3_DM_511))
+			return true;
+		else
+			return false;
+	}
+}
+
+bool wm5100_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM5100_SOFTWARE_RESET:
+	case WM5100_DEVICE_REVISION:
+	case WM5100_CTRL_IF_1:
+	case WM5100_TONE_GENERATOR_1:
+	case WM5100_PWM_DRIVE_1:
+	case WM5100_PWM_DRIVE_2:
+	case WM5100_PWM_DRIVE_3:
+	case WM5100_CLOCKING_1:
+	case WM5100_CLOCKING_3:
+	case WM5100_CLOCKING_4:
+	case WM5100_CLOCKING_5:
+	case WM5100_CLOCKING_6:
+	case WM5100_CLOCKING_7:
+	case WM5100_CLOCKING_8:
+	case WM5100_ASRC_ENABLE:
+	case WM5100_ASRC_STATUS:
+	case WM5100_ASRC_RATE1:
+	case WM5100_ISRC_1_CTRL_1:
+	case WM5100_ISRC_1_CTRL_2:
+	case WM5100_ISRC_2_CTRL1:
+	case WM5100_ISRC_2_CTRL_2:
+	case WM5100_FLL1_CONTROL_1:
+	case WM5100_FLL1_CONTROL_2:
+	case WM5100_FLL1_CONTROL_3:
+	case WM5100_FLL1_CONTROL_5:
+	case WM5100_FLL1_CONTROL_6:
+	case WM5100_FLL1_EFS_1:
+	case WM5100_FLL2_CONTROL_1:
+	case WM5100_FLL2_CONTROL_2:
+	case WM5100_FLL2_CONTROL_3:
+	case WM5100_FLL2_CONTROL_5:
+	case WM5100_FLL2_CONTROL_6:
+	case WM5100_FLL2_EFS_1:
+	case WM5100_MIC_CHARGE_PUMP_1:
+	case WM5100_MIC_CHARGE_PUMP_2:
+	case WM5100_HP_CHARGE_PUMP_1:
+	case WM5100_LDO1_CONTROL:
+	case WM5100_MIC_BIAS_CTRL_1:
+	case WM5100_MIC_BIAS_CTRL_2:
+	case WM5100_MIC_BIAS_CTRL_3:
+	case WM5100_ACCESSORY_DETECT_MODE_1:
+	case WM5100_HEADPHONE_DETECT_1:
+	case WM5100_HEADPHONE_DETECT_2:
+	case WM5100_MIC_DETECT_1:
+	case WM5100_MIC_DETECT_2:
+	case WM5100_MIC_DETECT_3:
+	case WM5100_MISC_CONTROL:
+	case WM5100_INPUT_ENABLES:
+	case WM5100_INPUT_ENABLES_STATUS:
+	case WM5100_IN1L_CONTROL:
+	case WM5100_IN1R_CONTROL:
+	case WM5100_IN2L_CONTROL:
+	case WM5100_IN2R_CONTROL:
+	case WM5100_IN3L_CONTROL:
+	case WM5100_IN3R_CONTROL:
+	case WM5100_IN4L_CONTROL:
+	case WM5100_IN4R_CONTROL:
+	case WM5100_RXANC_SRC:
+	case WM5100_INPUT_VOLUME_RAMP:
+	case WM5100_ADC_DIGITAL_VOLUME_1L:
+	case WM5100_ADC_DIGITAL_VOLUME_1R:
+	case WM5100_ADC_DIGITAL_VOLUME_2L:
+	case WM5100_ADC_DIGITAL_VOLUME_2R:
+	case WM5100_ADC_DIGITAL_VOLUME_3L:
+	case WM5100_ADC_DIGITAL_VOLUME_3R:
+	case WM5100_ADC_DIGITAL_VOLUME_4L:
+	case WM5100_ADC_DIGITAL_VOLUME_4R:
+	case WM5100_OUTPUT_ENABLES_2:
+	case WM5100_OUTPUT_STATUS_1:
+	case WM5100_OUTPUT_STATUS_2:
+	case WM5100_CHANNEL_ENABLES_1:
+	case WM5100_OUT_VOLUME_1L:
+	case WM5100_OUT_VOLUME_1R:
+	case WM5100_DAC_VOLUME_LIMIT_1L:
+	case WM5100_DAC_VOLUME_LIMIT_1R:
+	case WM5100_OUT_VOLUME_2L:
+	case WM5100_OUT_VOLUME_2R:
+	case WM5100_DAC_VOLUME_LIMIT_2L:
+	case WM5100_DAC_VOLUME_LIMIT_2R:
+	case WM5100_OUT_VOLUME_3L:
+	case WM5100_OUT_VOLUME_3R:
+	case WM5100_DAC_VOLUME_LIMIT_3L:
+	case WM5100_DAC_VOLUME_LIMIT_3R:
+	case WM5100_OUT_VOLUME_4L:
+	case WM5100_OUT_VOLUME_4R:
+	case WM5100_DAC_VOLUME_LIMIT_5L:
+	case WM5100_DAC_VOLUME_LIMIT_5R:
+	case WM5100_DAC_VOLUME_LIMIT_6L:
+	case WM5100_DAC_VOLUME_LIMIT_6R:
+	case WM5100_DAC_AEC_CONTROL_1:
+	case WM5100_OUTPUT_VOLUME_RAMP:
+	case WM5100_DAC_DIGITAL_VOLUME_1L:
+	case WM5100_DAC_DIGITAL_VOLUME_1R:
+	case WM5100_DAC_DIGITAL_VOLUME_2L:
+	case WM5100_DAC_DIGITAL_VOLUME_2R:
+	case WM5100_DAC_DIGITAL_VOLUME_3L:
+	case WM5100_DAC_DIGITAL_VOLUME_3R:
+	case WM5100_DAC_DIGITAL_VOLUME_4L:
+	case WM5100_DAC_DIGITAL_VOLUME_4R:
+	case WM5100_DAC_DIGITAL_VOLUME_5L:
+	case WM5100_DAC_DIGITAL_VOLUME_5R:
+	case WM5100_DAC_DIGITAL_VOLUME_6L:
+	case WM5100_DAC_DIGITAL_VOLUME_6R:
+	case WM5100_PDM_SPK1_CTRL_1:
+	case WM5100_PDM_SPK1_CTRL_2:
+	case WM5100_PDM_SPK2_CTRL_1:
+	case WM5100_PDM_SPK2_CTRL_2:
+	case WM5100_AUDIO_IF_1_1:
+	case WM5100_AUDIO_IF_1_2:
+	case WM5100_AUDIO_IF_1_3:
+	case WM5100_AUDIO_IF_1_4:
+	case WM5100_AUDIO_IF_1_5:
+	case WM5100_AUDIO_IF_1_6:
+	case WM5100_AUDIO_IF_1_7:
+	case WM5100_AUDIO_IF_1_8:
+	case WM5100_AUDIO_IF_1_9:
+	case WM5100_AUDIO_IF_1_10:
+	case WM5100_AUDIO_IF_1_11:
+	case WM5100_AUDIO_IF_1_12:
+	case WM5100_AUDIO_IF_1_13:
+	case WM5100_AUDIO_IF_1_14:
+	case WM5100_AUDIO_IF_1_15:
+	case WM5100_AUDIO_IF_1_16:
+	case WM5100_AUDIO_IF_1_17:
+	case WM5100_AUDIO_IF_1_18:
+	case WM5100_AUDIO_IF_1_19:
+	case WM5100_AUDIO_IF_1_20:
+	case WM5100_AUDIO_IF_1_21:
+	case WM5100_AUDIO_IF_1_22:
+	case WM5100_AUDIO_IF_1_23:
+	case WM5100_AUDIO_IF_1_24:
+	case WM5100_AUDIO_IF_1_25:
+	case WM5100_AUDIO_IF_1_26:
+	case WM5100_AUDIO_IF_1_27:
+	case WM5100_AUDIO_IF_2_1:
+	case WM5100_AUDIO_IF_2_2:
+	case WM5100_AUDIO_IF_2_3:
+	case WM5100_AUDIO_IF_2_4:
+	case WM5100_AUDIO_IF_2_5:
+	case WM5100_AUDIO_IF_2_6:
+	case WM5100_AUDIO_IF_2_7:
+	case WM5100_AUDIO_IF_2_8:
+	case WM5100_AUDIO_IF_2_9:
+	case WM5100_AUDIO_IF_2_10:
+	case WM5100_AUDIO_IF_2_11:
+	case WM5100_AUDIO_IF_2_18:
+	case WM5100_AUDIO_IF_2_19:
+	case WM5100_AUDIO_IF_2_26:
+	case WM5100_AUDIO_IF_2_27:
+	case WM5100_AUDIO_IF_3_1:
+	case WM5100_AUDIO_IF_3_2:
+	case WM5100_AUDIO_IF_3_3:
+	case WM5100_AUDIO_IF_3_4:
+	case WM5100_AUDIO_IF_3_5:
+	case WM5100_AUDIO_IF_3_6:
+	case WM5100_AUDIO_IF_3_7:
+	case WM5100_AUDIO_IF_3_8:
+	case WM5100_AUDIO_IF_3_9:
+	case WM5100_AUDIO_IF_3_10:
+	case WM5100_AUDIO_IF_3_11:
+	case WM5100_AUDIO_IF_3_18:
+	case WM5100_AUDIO_IF_3_19:
+	case WM5100_AUDIO_IF_3_26:
+	case WM5100_AUDIO_IF_3_27:
+	case WM5100_PWM1MIX_INPUT_1_SOURCE:
+	case WM5100_PWM1MIX_INPUT_1_VOLUME:
+	case WM5100_PWM1MIX_INPUT_2_SOURCE:
+	case WM5100_PWM1MIX_INPUT_2_VOLUME:
+	case WM5100_PWM1MIX_INPUT_3_SOURCE:
+	case WM5100_PWM1MIX_INPUT_3_VOLUME:
+	case WM5100_PWM1MIX_INPUT_4_SOURCE:
+	case WM5100_PWM1MIX_INPUT_4_VOLUME:
+	case WM5100_PWM2MIX_INPUT_1_SOURCE:
+	case WM5100_PWM2MIX_INPUT_1_VOLUME:
+	case WM5100_PWM2MIX_INPUT_2_SOURCE:
+	case WM5100_PWM2MIX_INPUT_2_VOLUME:
+	case WM5100_PWM2MIX_INPUT_3_SOURCE:
+	case WM5100_PWM2MIX_INPUT_3_VOLUME:
+	case WM5100_PWM2MIX_INPUT_4_SOURCE:
+	case WM5100_PWM2MIX_INPUT_4_VOLUME:
+	case WM5100_OUT1LMIX_INPUT_1_SOURCE:
+	case WM5100_OUT1LMIX_INPUT_1_VOLUME:
+	case WM5100_OUT1LMIX_INPUT_2_SOURCE:
+	case WM5100_OUT1LMIX_INPUT_2_VOLUME:
+	case WM5100_OUT1LMIX_INPUT_3_SOURCE:
+	case WM5100_OUT1LMIX_INPUT_3_VOLUME:
+	case WM5100_OUT1LMIX_INPUT_4_SOURCE:
+	case WM5100_OUT1LMIX_INPUT_4_VOLUME:
+	case WM5100_OUT1RMIX_INPUT_1_SOURCE:
+	case WM5100_OUT1RMIX_INPUT_1_VOLUME:
+	case WM5100_OUT1RMIX_INPUT_2_SOURCE:
+	case WM5100_OUT1RMIX_INPUT_2_VOLUME:
+	case WM5100_OUT1RMIX_INPUT_3_SOURCE:
+	case WM5100_OUT1RMIX_INPUT_3_VOLUME:
+	case WM5100_OUT1RMIX_INPUT_4_SOURCE:
+	case WM5100_OUT1RMIX_INPUT_4_VOLUME:
+	case WM5100_OUT2LMIX_INPUT_1_SOURCE:
+	case WM5100_OUT2LMIX_INPUT_1_VOLUME:
+	case WM5100_OUT2LMIX_INPUT_2_SOURCE:
+	case WM5100_OUT2LMIX_INPUT_2_VOLUME:
+	case WM5100_OUT2LMIX_INPUT_3_SOURCE:
+	case WM5100_OUT2LMIX_INPUT_3_VOLUME:
+	case WM5100_OUT2LMIX_INPUT_4_SOURCE:
+	case WM5100_OUT2LMIX_INPUT_4_VOLUME:
+	case WM5100_OUT2RMIX_INPUT_1_SOURCE:
+	case WM5100_OUT2RMIX_INPUT_1_VOLUME:
+	case WM5100_OUT2RMIX_INPUT_2_SOURCE:
+	case WM5100_OUT2RMIX_INPUT_2_VOLUME:
+	case WM5100_OUT2RMIX_INPUT_3_SOURCE:
+	case WM5100_OUT2RMIX_INPUT_3_VOLUME:
+	case WM5100_OUT2RMIX_INPUT_4_SOURCE:
+	case WM5100_OUT2RMIX_INPUT_4_VOLUME:
+	case WM5100_OUT3LMIX_INPUT_1_SOURCE:
+	case WM5100_OUT3LMIX_INPUT_1_VOLUME:
+	case WM5100_OUT3LMIX_INPUT_2_SOURCE:
+	case WM5100_OUT3LMIX_INPUT_2_VOLUME:
+	case WM5100_OUT3LMIX_INPUT_3_SOURCE:
+	case WM5100_OUT3LMIX_INPUT_3_VOLUME:
+	case WM5100_OUT3LMIX_INPUT_4_SOURCE:
+	case WM5100_OUT3LMIX_INPUT_4_VOLUME:
+	case WM5100_OUT3RMIX_INPUT_1_SOURCE:
+	case WM5100_OUT3RMIX_INPUT_1_VOLUME:
+	case WM5100_OUT3RMIX_INPUT_2_SOURCE:
+	case WM5100_OUT3RMIX_INPUT_2_VOLUME:
+	case WM5100_OUT3RMIX_INPUT_3_SOURCE:
+	case WM5100_OUT3RMIX_INPUT_3_VOLUME:
+	case WM5100_OUT3RMIX_INPUT_4_SOURCE:
+	case WM5100_OUT3RMIX_INPUT_4_VOLUME:
+	case WM5100_OUT4LMIX_INPUT_1_SOURCE:
+	case WM5100_OUT4LMIX_INPUT_1_VOLUME:
+	case WM5100_OUT4LMIX_INPUT_2_SOURCE:
+	case WM5100_OUT4LMIX_INPUT_2_VOLUME:
+	case WM5100_OUT4LMIX_INPUT_3_SOURCE:
+	case WM5100_OUT4LMIX_INPUT_3_VOLUME:
+	case WM5100_OUT4LMIX_INPUT_4_SOURCE:
+	case WM5100_OUT4LMIX_INPUT_4_VOLUME:
+	case WM5100_OUT4RMIX_INPUT_1_SOURCE:
+	case WM5100_OUT4RMIX_INPUT_1_VOLUME:
+	case WM5100_OUT4RMIX_INPUT_2_SOURCE:
+	case WM5100_OUT4RMIX_INPUT_2_VOLUME:
+	case WM5100_OUT4RMIX_INPUT_3_SOURCE:
+	case WM5100_OUT4RMIX_INPUT_3_VOLUME:
+	case WM5100_OUT4RMIX_INPUT_4_SOURCE:
+	case WM5100_OUT4RMIX_INPUT_4_VOLUME:
+	case WM5100_OUT5LMIX_INPUT_1_SOURCE:
+	case WM5100_OUT5LMIX_INPUT_1_VOLUME:
+	case WM5100_OUT5LMIX_INPUT_2_SOURCE:
+	case WM5100_OUT5LMIX_INPUT_2_VOLUME:
+	case WM5100_OUT5LMIX_INPUT_3_SOURCE:
+	case WM5100_OUT5LMIX_INPUT_3_VOLUME:
+	case WM5100_OUT5LMIX_INPUT_4_SOURCE:
+	case WM5100_OUT5LMIX_INPUT_4_VOLUME:
+	case WM5100_OUT5RMIX_INPUT_1_SOURCE:
+	case WM5100_OUT5RMIX_INPUT_1_VOLUME:
+	case WM5100_OUT5RMIX_INPUT_2_SOURCE:
+	case WM5100_OUT5RMIX_INPUT_2_VOLUME:
+	case WM5100_OUT5RMIX_INPUT_3_SOURCE:
+	case WM5100_OUT5RMIX_INPUT_3_VOLUME:
+	case WM5100_OUT5RMIX_INPUT_4_SOURCE:
+	case WM5100_OUT5RMIX_INPUT_4_VOLUME:
+	case WM5100_OUT6LMIX_INPUT_1_SOURCE:
+	case WM5100_OUT6LMIX_INPUT_1_VOLUME:
+	case WM5100_OUT6LMIX_INPUT_2_SOURCE:
+	case WM5100_OUT6LMIX_INPUT_2_VOLUME:
+	case WM5100_OUT6LMIX_INPUT_3_SOURCE:
+	case WM5100_OUT6LMIX_INPUT_3_VOLUME:
+	case WM5100_OUT6LMIX_INPUT_4_SOURCE:
+	case WM5100_OUT6LMIX_INPUT_4_VOLUME:
+	case WM5100_OUT6RMIX_INPUT_1_SOURCE:
+	case WM5100_OUT6RMIX_INPUT_1_VOLUME:
+	case WM5100_OUT6RMIX_INPUT_2_SOURCE:
+	case WM5100_OUT6RMIX_INPUT_2_VOLUME:
+	case WM5100_OUT6RMIX_INPUT_3_SOURCE:
+	case WM5100_OUT6RMIX_INPUT_3_VOLUME:
+	case WM5100_OUT6RMIX_INPUT_4_SOURCE:
+	case WM5100_OUT6RMIX_INPUT_4_VOLUME:
+	case WM5100_AIF1TX1MIX_INPUT_1_SOURCE:
+	case WM5100_AIF1TX1MIX_INPUT_1_VOLUME:
+	case WM5100_AIF1TX1MIX_INPUT_2_SOURCE:
+	case WM5100_AIF1TX1MIX_INPUT_2_VOLUME:
+	case WM5100_AIF1TX1MIX_INPUT_3_SOURCE:
+	case WM5100_AIF1TX1MIX_INPUT_3_VOLUME:
+	case WM5100_AIF1TX1MIX_INPUT_4_SOURCE:
+	case WM5100_AIF1TX1MIX_INPUT_4_VOLUME:
+	case WM5100_AIF1TX2MIX_INPUT_1_SOURCE:
+	case WM5100_AIF1TX2MIX_INPUT_1_VOLUME:
+	case WM5100_AIF1TX2MIX_INPUT_2_SOURCE:
+	case WM5100_AIF1TX2MIX_INPUT_2_VOLUME:
+	case WM5100_AIF1TX2MIX_INPUT_3_SOURCE:
+	case WM5100_AIF1TX2MIX_INPUT_3_VOLUME:
+	case WM5100_AIF1TX2MIX_INPUT_4_SOURCE:
+	case WM5100_AIF1TX2MIX_INPUT_4_VOLUME:
+	case WM5100_AIF1TX3MIX_INPUT_1_SOURCE:
+	case WM5100_AIF1TX3MIX_INPUT_1_VOLUME:
+	case WM5100_AIF1TX3MIX_INPUT_2_SOURCE:
+	case WM5100_AIF1TX3MIX_INPUT_2_VOLUME:
+	case WM5100_AIF1TX3MIX_INPUT_3_SOURCE:
+	case WM5100_AIF1TX3MIX_INPUT_3_VOLUME:
+	case WM5100_AIF1TX3MIX_INPUT_4_SOURCE:
+	case WM5100_AIF1TX3MIX_INPUT_4_VOLUME:
+	case WM5100_AIF1TX4MIX_INPUT_1_SOURCE:
+	case WM5100_AIF1TX4MIX_INPUT_1_VOLUME:
+	case WM5100_AIF1TX4MIX_INPUT_2_SOURCE:
+	case WM5100_AIF1TX4MIX_INPUT_2_VOLUME:
+	case WM5100_AIF1TX4MIX_INPUT_3_SOURCE:
+	case WM5100_AIF1TX4MIX_INPUT_3_VOLUME:
+	case WM5100_AIF1TX4MIX_INPUT_4_SOURCE:
+	case WM5100_AIF1TX4MIX_INPUT_4_VOLUME:
+	case WM5100_AIF1TX5MIX_INPUT_1_SOURCE:
+	case WM5100_AIF1TX5MIX_INPUT_1_VOLUME:
+	case WM5100_AIF1TX5MIX_INPUT_2_SOURCE:
+	case WM5100_AIF1TX5MIX_INPUT_2_VOLUME:
+	case WM5100_AIF1TX5MIX_INPUT_3_SOURCE:
+	case WM5100_AIF1TX5MIX_INPUT_3_VOLUME:
+	case WM5100_AIF1TX5MIX_INPUT_4_SOURCE:
+	case WM5100_AIF1TX5MIX_INPUT_4_VOLUME:
+	case WM5100_AIF1TX6MIX_INPUT_1_SOURCE:
+	case WM5100_AIF1TX6MIX_INPUT_1_VOLUME:
+	case WM5100_AIF1TX6MIX_INPUT_2_SOURCE:
+	case WM5100_AIF1TX6MIX_INPUT_2_VOLUME:
+	case WM5100_AIF1TX6MIX_INPUT_3_SOURCE:
+	case WM5100_AIF1TX6MIX_INPUT_3_VOLUME:
+	case WM5100_AIF1TX6MIX_INPUT_4_SOURCE:
+	case WM5100_AIF1TX6MIX_INPUT_4_VOLUME:
+	case WM5100_AIF1TX7MIX_INPUT_1_SOURCE:
+	case WM5100_AIF1TX7MIX_INPUT_1_VOLUME:
+	case WM5100_AIF1TX7MIX_INPUT_2_SOURCE:
+	case WM5100_AIF1TX7MIX_INPUT_2_VOLUME:
+	case WM5100_AIF1TX7MIX_INPUT_3_SOURCE:
+	case WM5100_AIF1TX7MIX_INPUT_3_VOLUME:
+	case WM5100_AIF1TX7MIX_INPUT_4_SOURCE:
+	case WM5100_AIF1TX7MIX_INPUT_4_VOLUME:
+	case WM5100_AIF1TX8MIX_INPUT_1_SOURCE:
+	case WM5100_AIF1TX8MIX_INPUT_1_VOLUME:
+	case WM5100_AIF1TX8MIX_INPUT_2_SOURCE:
+	case WM5100_AIF1TX8MIX_INPUT_2_VOLUME:
+	case WM5100_AIF1TX8MIX_INPUT_3_SOURCE:
+	case WM5100_AIF1TX8MIX_INPUT_3_VOLUME:
+	case WM5100_AIF1TX8MIX_INPUT_4_SOURCE:
+	case WM5100_AIF1TX8MIX_INPUT_4_VOLUME:
+	case WM5100_AIF2TX1MIX_INPUT_1_SOURCE:
+	case WM5100_AIF2TX1MIX_INPUT_1_VOLUME:
+	case WM5100_AIF2TX1MIX_INPUT_2_SOURCE:
+	case WM5100_AIF2TX1MIX_INPUT_2_VOLUME:
+	case WM5100_AIF2TX1MIX_INPUT_3_SOURCE:
+	case WM5100_AIF2TX1MIX_INPUT_3_VOLUME:
+	case WM5100_AIF2TX1MIX_INPUT_4_SOURCE:
+	case WM5100_AIF2TX1MIX_INPUT_4_VOLUME:
+	case WM5100_AIF2TX2MIX_INPUT_1_SOURCE:
+	case WM5100_AIF2TX2MIX_INPUT_1_VOLUME:
+	case WM5100_AIF2TX2MIX_INPUT_2_SOURCE:
+	case WM5100_AIF2TX2MIX_INPUT_2_VOLUME:
+	case WM5100_AIF2TX2MIX_INPUT_3_SOURCE:
+	case WM5100_AIF2TX2MIX_INPUT_3_VOLUME:
+	case WM5100_AIF2TX2MIX_INPUT_4_SOURCE:
+	case WM5100_AIF2TX2MIX_INPUT_4_VOLUME:
+	case WM5100_AIF3TX1MIX_INPUT_1_SOURCE:
+	case WM5100_AIF3TX1MIX_INPUT_1_VOLUME:
+	case WM5100_AIF3TX1MIX_INPUT_2_SOURCE:
+	case WM5100_AIF3TX1MIX_INPUT_2_VOLUME:
+	case WM5100_AIF3TX1MIX_INPUT_3_SOURCE:
+	case WM5100_AIF3TX1MIX_INPUT_3_VOLUME:
+	case WM5100_AIF3TX1MIX_INPUT_4_SOURCE:
+	case WM5100_AIF3TX1MIX_INPUT_4_VOLUME:
+	case WM5100_AIF3TX2MIX_INPUT_1_SOURCE:
+	case WM5100_AIF3TX2MIX_INPUT_1_VOLUME:
+	case WM5100_AIF3TX2MIX_INPUT_2_SOURCE:
+	case WM5100_AIF3TX2MIX_INPUT_2_VOLUME:
+	case WM5100_AIF3TX2MIX_INPUT_3_SOURCE:
+	case WM5100_AIF3TX2MIX_INPUT_3_VOLUME:
+	case WM5100_AIF3TX2MIX_INPUT_4_SOURCE:
+	case WM5100_AIF3TX2MIX_INPUT_4_VOLUME:
+	case WM5100_EQ1MIX_INPUT_1_SOURCE:
+	case WM5100_EQ1MIX_INPUT_1_VOLUME:
+	case WM5100_EQ1MIX_INPUT_2_SOURCE:
+	case WM5100_EQ1MIX_INPUT_2_VOLUME:
+	case WM5100_EQ1MIX_INPUT_3_SOURCE:
+	case WM5100_EQ1MIX_INPUT_3_VOLUME:
+	case WM5100_EQ1MIX_INPUT_4_SOURCE:
+	case WM5100_EQ1MIX_INPUT_4_VOLUME:
+	case WM5100_EQ2MIX_INPUT_1_SOURCE:
+	case WM5100_EQ2MIX_INPUT_1_VOLUME:
+	case WM5100_EQ2MIX_INPUT_2_SOURCE:
+	case WM5100_EQ2MIX_INPUT_2_VOLUME:
+	case WM5100_EQ2MIX_INPUT_3_SOURCE:
+	case WM5100_EQ2MIX_INPUT_3_VOLUME:
+	case WM5100_EQ2MIX_INPUT_4_SOURCE:
+	case WM5100_EQ2MIX_INPUT_4_VOLUME:
+	case WM5100_EQ3MIX_INPUT_1_SOURCE:
+	case WM5100_EQ3MIX_INPUT_1_VOLUME:
+	case WM5100_EQ3MIX_INPUT_2_SOURCE:
+	case WM5100_EQ3MIX_INPUT_2_VOLUME:
+	case WM5100_EQ3MIX_INPUT_3_SOURCE:
+	case WM5100_EQ3MIX_INPUT_3_VOLUME:
+	case WM5100_EQ3MIX_INPUT_4_SOURCE:
+	case WM5100_EQ3MIX_INPUT_4_VOLUME:
+	case WM5100_EQ4MIX_INPUT_1_SOURCE:
+	case WM5100_EQ4MIX_INPUT_1_VOLUME:
+	case WM5100_EQ4MIX_INPUT_2_SOURCE:
+	case WM5100_EQ4MIX_INPUT_2_VOLUME:
+	case WM5100_EQ4MIX_INPUT_3_SOURCE:
+	case WM5100_EQ4MIX_INPUT_3_VOLUME:
+	case WM5100_EQ4MIX_INPUT_4_SOURCE:
+	case WM5100_EQ4MIX_INPUT_4_VOLUME:
+	case WM5100_DRC1LMIX_INPUT_1_SOURCE:
+	case WM5100_DRC1LMIX_INPUT_1_VOLUME:
+	case WM5100_DRC1LMIX_INPUT_2_SOURCE:
+	case WM5100_DRC1LMIX_INPUT_2_VOLUME:
+	case WM5100_DRC1LMIX_INPUT_3_SOURCE:
+	case WM5100_DRC1LMIX_INPUT_3_VOLUME:
+	case WM5100_DRC1LMIX_INPUT_4_SOURCE:
+	case WM5100_DRC1LMIX_INPUT_4_VOLUME:
+	case WM5100_DRC1RMIX_INPUT_1_SOURCE:
+	case WM5100_DRC1RMIX_INPUT_1_VOLUME:
+	case WM5100_DRC1RMIX_INPUT_2_SOURCE:
+	case WM5100_DRC1RMIX_INPUT_2_VOLUME:
+	case WM5100_DRC1RMIX_INPUT_3_SOURCE:
+	case WM5100_DRC1RMIX_INPUT_3_VOLUME:
+	case WM5100_DRC1RMIX_INPUT_4_SOURCE:
+	case WM5100_DRC1RMIX_INPUT_4_VOLUME:
+	case WM5100_HPLP1MIX_INPUT_1_SOURCE:
+	case WM5100_HPLP1MIX_INPUT_1_VOLUME:
+	case WM5100_HPLP1MIX_INPUT_2_SOURCE:
+	case WM5100_HPLP1MIX_INPUT_2_VOLUME:
+	case WM5100_HPLP1MIX_INPUT_3_SOURCE:
+	case WM5100_HPLP1MIX_INPUT_3_VOLUME:
+	case WM5100_HPLP1MIX_INPUT_4_SOURCE:
+	case WM5100_HPLP1MIX_INPUT_4_VOLUME:
+	case WM5100_HPLP2MIX_INPUT_1_SOURCE:
+	case WM5100_HPLP2MIX_INPUT_1_VOLUME:
+	case WM5100_HPLP2MIX_INPUT_2_SOURCE:
+	case WM5100_HPLP2MIX_INPUT_2_VOLUME:
+	case WM5100_HPLP2MIX_INPUT_3_SOURCE:
+	case WM5100_HPLP2MIX_INPUT_3_VOLUME:
+	case WM5100_HPLP2MIX_INPUT_4_SOURCE:
+	case WM5100_HPLP2MIX_INPUT_4_VOLUME:
+	case WM5100_HPLP3MIX_INPUT_1_SOURCE:
+	case WM5100_HPLP3MIX_INPUT_1_VOLUME:
+	case WM5100_HPLP3MIX_INPUT_2_SOURCE:
+	case WM5100_HPLP3MIX_INPUT_2_VOLUME:
+	case WM5100_HPLP3MIX_INPUT_3_SOURCE:
+	case WM5100_HPLP3MIX_INPUT_3_VOLUME:
+	case WM5100_HPLP3MIX_INPUT_4_SOURCE:
+	case WM5100_HPLP3MIX_INPUT_4_VOLUME:
+	case WM5100_HPLP4MIX_INPUT_1_SOURCE:
+	case WM5100_HPLP4MIX_INPUT_1_VOLUME:
+	case WM5100_HPLP4MIX_INPUT_2_SOURCE:
+	case WM5100_HPLP4MIX_INPUT_2_VOLUME:
+	case WM5100_HPLP4MIX_INPUT_3_SOURCE:
+	case WM5100_HPLP4MIX_INPUT_3_VOLUME:
+	case WM5100_HPLP4MIX_INPUT_4_SOURCE:
+	case WM5100_HPLP4MIX_INPUT_4_VOLUME:
+	case WM5100_DSP1LMIX_INPUT_1_SOURCE:
+	case WM5100_DSP1LMIX_INPUT_1_VOLUME:
+	case WM5100_DSP1LMIX_INPUT_2_SOURCE:
+	case WM5100_DSP1LMIX_INPUT_2_VOLUME:
+	case WM5100_DSP1LMIX_INPUT_3_SOURCE:
+	case WM5100_DSP1LMIX_INPUT_3_VOLUME:
+	case WM5100_DSP1LMIX_INPUT_4_SOURCE:
+	case WM5100_DSP1LMIX_INPUT_4_VOLUME:
+	case WM5100_DSP1RMIX_INPUT_1_SOURCE:
+	case WM5100_DSP1RMIX_INPUT_1_VOLUME:
+	case WM5100_DSP1RMIX_INPUT_2_SOURCE:
+	case WM5100_DSP1RMIX_INPUT_2_VOLUME:
+	case WM5100_DSP1RMIX_INPUT_3_SOURCE:
+	case WM5100_DSP1RMIX_INPUT_3_VOLUME:
+	case WM5100_DSP1RMIX_INPUT_4_SOURCE:
+	case WM5100_DSP1RMIX_INPUT_4_VOLUME:
+	case WM5100_DSP1AUX1MIX_INPUT_1_SOURCE:
+	case WM5100_DSP1AUX2MIX_INPUT_1_SOURCE:
+	case WM5100_DSP1AUX3MIX_INPUT_1_SOURCE:
+	case WM5100_DSP1AUX4MIX_INPUT_1_SOURCE:
+	case WM5100_DSP1AUX5MIX_INPUT_1_SOURCE:
+	case WM5100_DSP1AUX6MIX_INPUT_1_SOURCE:
+	case WM5100_DSP2LMIX_INPUT_1_SOURCE:
+	case WM5100_DSP2LMIX_INPUT_1_VOLUME:
+	case WM5100_DSP2LMIX_INPUT_2_SOURCE:
+	case WM5100_DSP2LMIX_INPUT_2_VOLUME:
+	case WM5100_DSP2LMIX_INPUT_3_SOURCE:
+	case WM5100_DSP2LMIX_INPUT_3_VOLUME:
+	case WM5100_DSP2LMIX_INPUT_4_SOURCE:
+	case WM5100_DSP2LMIX_INPUT_4_VOLUME:
+	case WM5100_DSP2RMIX_INPUT_1_SOURCE:
+	case WM5100_DSP2RMIX_INPUT_1_VOLUME:
+	case WM5100_DSP2RMIX_INPUT_2_SOURCE:
+	case WM5100_DSP2RMIX_INPUT_2_VOLUME:
+	case WM5100_DSP2RMIX_INPUT_3_SOURCE:
+	case WM5100_DSP2RMIX_INPUT_3_VOLUME:
+	case WM5100_DSP2RMIX_INPUT_4_SOURCE:
+	case WM5100_DSP2RMIX_INPUT_4_VOLUME:
+	case WM5100_DSP2AUX1MIX_INPUT_1_SOURCE:
+	case WM5100_DSP2AUX2MIX_INPUT_1_SOURCE:
+	case WM5100_DSP2AUX3MIX_INPUT_1_SOURCE:
+	case WM5100_DSP2AUX4MIX_INPUT_1_SOURCE:
+	case WM5100_DSP2AUX5MIX_INPUT_1_SOURCE:
+	case WM5100_DSP2AUX6MIX_INPUT_1_SOURCE:
+	case WM5100_DSP3LMIX_INPUT_1_SOURCE:
+	case WM5100_DSP3LMIX_INPUT_1_VOLUME:
+	case WM5100_DSP3LMIX_INPUT_2_SOURCE:
+	case WM5100_DSP3LMIX_INPUT_2_VOLUME:
+	case WM5100_DSP3LMIX_INPUT_3_SOURCE:
+	case WM5100_DSP3LMIX_INPUT_3_VOLUME:
+	case WM5100_DSP3LMIX_INPUT_4_SOURCE:
+	case WM5100_DSP3LMIX_INPUT_4_VOLUME:
+	case WM5100_DSP3RMIX_INPUT_1_SOURCE:
+	case WM5100_DSP3RMIX_INPUT_1_VOLUME:
+	case WM5100_DSP3RMIX_INPUT_2_SOURCE:
+	case WM5100_DSP3RMIX_INPUT_2_VOLUME:
+	case WM5100_DSP3RMIX_INPUT_3_SOURCE:
+	case WM5100_DSP3RMIX_INPUT_3_VOLUME:
+	case WM5100_DSP3RMIX_INPUT_4_SOURCE:
+	case WM5100_DSP3RMIX_INPUT_4_VOLUME:
+	case WM5100_DSP3AUX1MIX_INPUT_1_SOURCE:
+	case WM5100_DSP3AUX2MIX_INPUT_1_SOURCE:
+	case WM5100_DSP3AUX3MIX_INPUT_1_SOURCE:
+	case WM5100_DSP3AUX4MIX_INPUT_1_SOURCE:
+	case WM5100_DSP3AUX5MIX_INPUT_1_SOURCE:
+	case WM5100_DSP3AUX6MIX_INPUT_1_SOURCE:
+	case WM5100_ASRC1LMIX_INPUT_1_SOURCE:
+	case WM5100_ASRC1RMIX_INPUT_1_SOURCE:
+	case WM5100_ASRC2LMIX_INPUT_1_SOURCE:
+	case WM5100_ASRC2RMIX_INPUT_1_SOURCE:
+	case WM5100_ISRC1DEC1MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC1DEC2MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC1DEC3MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC1DEC4MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC1INT1MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC1INT2MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC1INT3MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC1INT4MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC2DEC1MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC2DEC2MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC2DEC3MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC2DEC4MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC2INT1MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC2INT2MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC2INT3MIX_INPUT_1_SOURCE:
+	case WM5100_ISRC2INT4MIX_INPUT_1_SOURCE:
+	case WM5100_GPIO_CTRL_1:
+	case WM5100_GPIO_CTRL_2:
+	case WM5100_GPIO_CTRL_3:
+	case WM5100_GPIO_CTRL_4:
+	case WM5100_GPIO_CTRL_5:
+	case WM5100_GPIO_CTRL_6:
+	case WM5100_MISC_PAD_CTRL_1:
+	case WM5100_MISC_PAD_CTRL_2:
+	case WM5100_MISC_PAD_CTRL_3:
+	case WM5100_MISC_PAD_CTRL_4:
+	case WM5100_MISC_PAD_CTRL_5:
+	case WM5100_MISC_GPIO_1:
+	case WM5100_INTERRUPT_STATUS_1:
+	case WM5100_INTERRUPT_STATUS_2:
+	case WM5100_INTERRUPT_STATUS_3:
+	case WM5100_INTERRUPT_STATUS_4:
+	case WM5100_INTERRUPT_RAW_STATUS_2:
+	case WM5100_INTERRUPT_RAW_STATUS_3:
+	case WM5100_INTERRUPT_RAW_STATUS_4:
+	case WM5100_INTERRUPT_STATUS_1_MASK:
+	case WM5100_INTERRUPT_STATUS_2_MASK:
+	case WM5100_INTERRUPT_STATUS_3_MASK:
+	case WM5100_INTERRUPT_STATUS_4_MASK:
+	case WM5100_INTERRUPT_CONTROL:
+	case WM5100_IRQ_DEBOUNCE_1:
+	case WM5100_IRQ_DEBOUNCE_2:
+	case WM5100_FX_CTRL:
+	case WM5100_EQ1_1:
+	case WM5100_EQ1_2:
+	case WM5100_EQ1_3:
+	case WM5100_EQ1_4:
+	case WM5100_EQ1_5:
+	case WM5100_EQ1_6:
+	case WM5100_EQ1_7:
+	case WM5100_EQ1_8:
+	case WM5100_EQ1_9:
+	case WM5100_EQ1_10:
+	case WM5100_EQ1_11:
+	case WM5100_EQ1_12:
+	case WM5100_EQ1_13:
+	case WM5100_EQ1_14:
+	case WM5100_EQ1_15:
+	case WM5100_EQ1_16:
+	case WM5100_EQ1_17:
+	case WM5100_EQ1_18:
+	case WM5100_EQ1_19:
+	case WM5100_EQ1_20:
+	case WM5100_EQ2_1:
+	case WM5100_EQ2_2:
+	case WM5100_EQ2_3:
+	case WM5100_EQ2_4:
+	case WM5100_EQ2_5:
+	case WM5100_EQ2_6:
+	case WM5100_EQ2_7:
+	case WM5100_EQ2_8:
+	case WM5100_EQ2_9:
+	case WM5100_EQ2_10:
+	case WM5100_EQ2_11:
+	case WM5100_EQ2_12:
+	case WM5100_EQ2_13:
+	case WM5100_EQ2_14:
+	case WM5100_EQ2_15:
+	case WM5100_EQ2_16:
+	case WM5100_EQ2_17:
+	case WM5100_EQ2_18:
+	case WM5100_EQ2_19:
+	case WM5100_EQ2_20:
+	case WM5100_EQ3_1:
+	case WM5100_EQ3_2:
+	case WM5100_EQ3_3:
+	case WM5100_EQ3_4:
+	case WM5100_EQ3_5:
+	case WM5100_EQ3_6:
+	case WM5100_EQ3_7:
+	case WM5100_EQ3_8:
+	case WM5100_EQ3_9:
+	case WM5100_EQ3_10:
+	case WM5100_EQ3_11:
+	case WM5100_EQ3_12:
+	case WM5100_EQ3_13:
+	case WM5100_EQ3_14:
+	case WM5100_EQ3_15:
+	case WM5100_EQ3_16:
+	case WM5100_EQ3_17:
+	case WM5100_EQ3_18:
+	case WM5100_EQ3_19:
+	case WM5100_EQ3_20:
+	case WM5100_EQ4_1:
+	case WM5100_EQ4_2:
+	case WM5100_EQ4_3:
+	case WM5100_EQ4_4:
+	case WM5100_EQ4_5:
+	case WM5100_EQ4_6:
+	case WM5100_EQ4_7:
+	case WM5100_EQ4_8:
+	case WM5100_EQ4_9:
+	case WM5100_EQ4_10:
+	case WM5100_EQ4_11:
+	case WM5100_EQ4_12:
+	case WM5100_EQ4_13:
+	case WM5100_EQ4_14:
+	case WM5100_EQ4_15:
+	case WM5100_EQ4_16:
+	case WM5100_EQ4_17:
+	case WM5100_EQ4_18:
+	case WM5100_EQ4_19:
+	case WM5100_EQ4_20:
+	case WM5100_DRC1_CTRL1:
+	case WM5100_DRC1_CTRL2:
+	case WM5100_DRC1_CTRL3:
+	case WM5100_DRC1_CTRL4:
+	case WM5100_DRC1_CTRL5:
+	case WM5100_HPLPF1_1:
+	case WM5100_HPLPF1_2:
+	case WM5100_HPLPF2_1:
+	case WM5100_HPLPF2_2:
+	case WM5100_HPLPF3_1:
+	case WM5100_HPLPF3_2:
+	case WM5100_HPLPF4_1:
+	case WM5100_HPLPF4_2:
+	case WM5100_DSP1_CONTROL_1:
+	case WM5100_DSP1_CONTROL_2:
+	case WM5100_DSP1_CONTROL_3:
+	case WM5100_DSP1_CONTROL_4:
+	case WM5100_DSP1_CONTROL_5:
+	case WM5100_DSP1_CONTROL_6:
+	case WM5100_DSP1_CONTROL_7:
+	case WM5100_DSP1_CONTROL_8:
+	case WM5100_DSP1_CONTROL_9:
+	case WM5100_DSP1_CONTROL_10:
+	case WM5100_DSP1_CONTROL_11:
+	case WM5100_DSP1_CONTROL_12:
+	case WM5100_DSP1_CONTROL_13:
+	case WM5100_DSP1_CONTROL_14:
+	case WM5100_DSP1_CONTROL_15:
+	case WM5100_DSP1_CONTROL_16:
+	case WM5100_DSP1_CONTROL_17:
+	case WM5100_DSP1_CONTROL_18:
+	case WM5100_DSP1_CONTROL_19:
+	case WM5100_DSP1_CONTROL_20:
+	case WM5100_DSP1_CONTROL_21:
+	case WM5100_DSP1_CONTROL_22:
+	case WM5100_DSP1_CONTROL_23:
+	case WM5100_DSP1_CONTROL_24:
+	case WM5100_DSP1_CONTROL_25:
+	case WM5100_DSP1_CONTROL_26:
+	case WM5100_DSP1_CONTROL_27:
+	case WM5100_DSP1_CONTROL_28:
+	case WM5100_DSP1_CONTROL_29:
+	case WM5100_DSP1_CONTROL_30:
+	case WM5100_DSP2_CONTROL_1:
+	case WM5100_DSP2_CONTROL_2:
+	case WM5100_DSP2_CONTROL_3:
+	case WM5100_DSP2_CONTROL_4:
+	case WM5100_DSP2_CONTROL_5:
+	case WM5100_DSP2_CONTROL_6:
+	case WM5100_DSP2_CONTROL_7:
+	case WM5100_DSP2_CONTROL_8:
+	case WM5100_DSP2_CONTROL_9:
+	case WM5100_DSP2_CONTROL_10:
+	case WM5100_DSP2_CONTROL_11:
+	case WM5100_DSP2_CONTROL_12:
+	case WM5100_DSP2_CONTROL_13:
+	case WM5100_DSP2_CONTROL_14:
+	case WM5100_DSP2_CONTROL_15:
+	case WM5100_DSP2_CONTROL_16:
+	case WM5100_DSP2_CONTROL_17:
+	case WM5100_DSP2_CONTROL_18:
+	case WM5100_DSP2_CONTROL_19:
+	case WM5100_DSP2_CONTROL_20:
+	case WM5100_DSP2_CONTROL_21:
+	case WM5100_DSP2_CONTROL_22:
+	case WM5100_DSP2_CONTROL_23:
+	case WM5100_DSP2_CONTROL_24:
+	case WM5100_DSP2_CONTROL_25:
+	case WM5100_DSP2_CONTROL_26:
+	case WM5100_DSP2_CONTROL_27:
+	case WM5100_DSP2_CONTROL_28:
+	case WM5100_DSP2_CONTROL_29:
+	case WM5100_DSP2_CONTROL_30:
+	case WM5100_DSP3_CONTROL_1:
+	case WM5100_DSP3_CONTROL_2:
+	case WM5100_DSP3_CONTROL_3:
+	case WM5100_DSP3_CONTROL_4:
+	case WM5100_DSP3_CONTROL_5:
+	case WM5100_DSP3_CONTROL_6:
+	case WM5100_DSP3_CONTROL_7:
+	case WM5100_DSP3_CONTROL_8:
+	case WM5100_DSP3_CONTROL_9:
+	case WM5100_DSP3_CONTROL_10:
+	case WM5100_DSP3_CONTROL_11:
+	case WM5100_DSP3_CONTROL_12:
+	case WM5100_DSP3_CONTROL_13:
+	case WM5100_DSP3_CONTROL_14:
+	case WM5100_DSP3_CONTROL_15:
+	case WM5100_DSP3_CONTROL_16:
+	case WM5100_DSP3_CONTROL_17:
+	case WM5100_DSP3_CONTROL_18:
+	case WM5100_DSP3_CONTROL_19:
+	case WM5100_DSP3_CONTROL_20:
+	case WM5100_DSP3_CONTROL_21:
+	case WM5100_DSP3_CONTROL_22:
+	case WM5100_DSP3_CONTROL_23:
+	case WM5100_DSP3_CONTROL_24:
+	case WM5100_DSP3_CONTROL_25:
+	case WM5100_DSP3_CONTROL_26:
+	case WM5100_DSP3_CONTROL_27:
+	case WM5100_DSP3_CONTROL_28:
+	case WM5100_DSP3_CONTROL_29:
+	case WM5100_DSP3_CONTROL_30:
+		return true;
+	default:
+		if ((reg >= WM5100_DSP1_PM_0 && reg <= WM5100_DSP1_PM_1535) ||
+		    (reg >= WM5100_DSP1_ZM_0 && reg <= WM5100_DSP1_ZM_2047) ||
+		    (reg >= WM5100_DSP1_DM_0 && reg <= WM5100_DSP1_DM_511) ||
+		    (reg >= WM5100_DSP2_PM_0 && reg <= WM5100_DSP2_PM_1535) ||
+		    (reg >= WM5100_DSP2_ZM_0 && reg <= WM5100_DSP2_ZM_2047) ||
+		    (reg >= WM5100_DSP2_DM_0 && reg <= WM5100_DSP2_DM_511) ||
+		    (reg >= WM5100_DSP3_PM_0 && reg <= WM5100_DSP3_PM_1535) ||
+		    (reg >= WM5100_DSP3_ZM_0 && reg <= WM5100_DSP3_ZM_2047) ||
+		    (reg >= WM5100_DSP3_DM_0 && reg <= WM5100_DSP3_DM_511))
+			return true;
+		else
+			return false;
+	}
+}
+
+struct reg_default wm5100_reg_defaults[WM5100_REGISTER_COUNT] = {
+	{ 0x0000, 0x0000 },  /* R0     - software reset */
+	{ 0x0001, 0x0000 },  /* R1     - Device Revision */
+	{ 0x0010, 0x0801 },  /* R16    - Ctrl IF 1 */
+	{ 0x0020, 0x0000 },  /* R32    - Tone Generator 1 */
+	{ 0x0030, 0x0000 },  /* R48    - PWM Drive 1 */
+	{ 0x0031, 0x0100 },  /* R49    - PWM Drive 2 */
+	{ 0x0032, 0x0100 },  /* R50    - PWM Drive 3 */
+	{ 0x0100, 0x0002 },  /* R256   - Clocking 1 */
+	{ 0x0101, 0x0000 },  /* R257   - Clocking 3 */
+	{ 0x0102, 0x0011 },  /* R258   - Clocking 4 */
+	{ 0x0103, 0x0011 },  /* R259   - Clocking 5 */
+	{ 0x0104, 0x0011 },  /* R260   - Clocking 6 */
+	{ 0x0107, 0x0000 },  /* R263   - Clocking 7 */
+	{ 0x0108, 0x0000 },  /* R264   - Clocking 8 */
+	{ 0x0120, 0x0000 },  /* R288   - ASRC_ENABLE */
+	{ 0x0121, 0x0000 },  /* R289   - ASRC_STATUS */
+	{ 0x0122, 0x0000 },  /* R290   - ASRC_RATE1 */
+	{ 0x0141, 0x8000 },  /* R321   - ISRC 1 CTRL 1 */
+	{ 0x0142, 0x0000 },  /* R322   - ISRC 1 CTRL 2 */
+	{ 0x0143, 0x8000 },  /* R323   - ISRC 2 CTRL1 */
+	{ 0x0144, 0x0000 },  /* R324   - ISRC 2 CTRL 2 */
+	{ 0x0182, 0x0000 },  /* R386   - FLL1 Control 1 */
+	{ 0x0183, 0x0000 },  /* R387   - FLL1 Control 2 */
+	{ 0x0184, 0x0000 },  /* R388   - FLL1 Control 3 */
+	{ 0x0186, 0x0177 },  /* R390   - FLL1 Control 5 */
+	{ 0x0187, 0x0001 },  /* R391   - FLL1 Control 6 */
+	{ 0x0188, 0x0000 },  /* R392   - FLL1 EFS 1 */
+	{ 0x01A2, 0x0000 },  /* R418   - FLL2 Control 1 */
+	{ 0x01A3, 0x0000 },  /* R419   - FLL2 Control 2 */
+	{ 0x01A4, 0x0000 },  /* R420   - FLL2 Control 3 */
+	{ 0x01A6, 0x0177 },  /* R422   - FLL2 Control 5 */
+	{ 0x01A7, 0x0001 },  /* R423   - FLL2 Control 6 */
+	{ 0x01A8, 0x0000 },  /* R424   - FLL2 EFS 1 */
+	{ 0x0200, 0x0020 },  /* R512   - Mic Charge Pump 1 */
+	{ 0x0201, 0xB084 },  /* R513   - Mic Charge Pump 2 */
+	{ 0x0202, 0xBBDE },  /* R514   - HP Charge Pump 1 */
+	{ 0x0211, 0x20D4 },  /* R529   - LDO1 Control */
+	{ 0x0215, 0x0062 },  /* R533   - Mic Bias Ctrl 1 */
+	{ 0x0216, 0x0062 },  /* R534   - Mic Bias Ctrl 2 */
+	{ 0x0217, 0x0062 },  /* R535   - Mic Bias Ctrl 3 */
+	{ 0x0280, 0x0004 },  /* R640   - Accessory Detect Mode 1 */
+	{ 0x0288, 0x0020 },  /* R648   - Headphone Detect 1 */
+	{ 0x0289, 0x0000 },  /* R649   - Headphone Detect 2 */
+	{ 0x0290, 0x1100 },  /* R656   - Mic Detect 1 */
+	{ 0x0291, 0x009F },  /* R657   - Mic Detect 2 */
+	{ 0x0292, 0x0000 },  /* R658   - Mic Detect 3 */
+	{ 0x0301, 0x0000 },  /* R769   - Input Enables */
+	{ 0x0302, 0x0000 },  /* R770   - Input Enables Status */
+	{ 0x0310, 0x2280 },  /* R784   - Status */
+	{ 0x0311, 0x0080 },  /* R785   - IN1R Control */
+	{ 0x0312, 0x2280 },  /* R786   - IN2L Control */
+	{ 0x0313, 0x0080 },  /* R787   - IN2R Control */
+	{ 0x0314, 0x2280 },  /* R788   - IN3L Control */
+	{ 0x0315, 0x0080 },  /* R789   - IN3R Control */
+	{ 0x0316, 0x2280 },  /* R790   - IN4L Control */
+	{ 0x0317, 0x0080 },  /* R791   - IN4R Control */
+	{ 0x0318, 0x0000 },  /* R792   - RXANC_SRC */
+	{ 0x0319, 0x0022 },  /* R793   - Input Volume Ramp */
+	{ 0x0320, 0x0180 },  /* R800   - ADC Digital Volume 1L */
+	{ 0x0321, 0x0180 },  /* R801   - ADC Digital Volume 1R */
+	{ 0x0322, 0x0180 },  /* R802   - ADC Digital Volume 2L */
+	{ 0x0323, 0x0180 },  /* R803   - ADC Digital Volume 2R */
+	{ 0x0324, 0x0180 },  /* R804   - ADC Digital Volume 3L */
+	{ 0x0325, 0x0180 },  /* R805   - ADC Digital Volume 3R */
+	{ 0x0326, 0x0180 },  /* R806   - ADC Digital Volume 4L */
+	{ 0x0327, 0x0180 },  /* R807   - ADC Digital Volume 4R */
+	{ 0x0401, 0x0000 },  /* R1025  - Output Enables 2 */
+	{ 0x0402, 0x0000 },  /* R1026  - Output Status 1 */
+	{ 0x0403, 0x0000 },  /* R1027  - Output Status 2 */
+	{ 0x0408, 0x0000 },  /* R1032  - Channel Enables 1 */
+	{ 0x0410, 0x0080 },  /* R1040  - Out Volume 1L */
+	{ 0x0411, 0x0080 },  /* R1041  - Out Volume 1R */
+	{ 0x0412, 0x0080 },  /* R1042  - DAC Volume Limit 1L */
+	{ 0x0413, 0x0080 },  /* R1043  - DAC Volume Limit 1R */
+	{ 0x0414, 0x0080 },  /* R1044  - Out Volume 2L */
+	{ 0x0415, 0x0080 },  /* R1045  - Out Volume 2R */
+	{ 0x0416, 0x0080 },  /* R1046  - DAC Volume Limit 2L */
+	{ 0x0417, 0x0080 },  /* R1047  - DAC Volume Limit 2R */
+	{ 0x0418, 0x0080 },  /* R1048  - Out Volume 3L */
+	{ 0x0419, 0x0080 },  /* R1049  - Out Volume 3R */
+	{ 0x041A, 0x0080 },  /* R1050  - DAC Volume Limit 3L */
+	{ 0x041B, 0x0080 },  /* R1051  - DAC Volume Limit 3R */
+	{ 0x041C, 0x0080 },  /* R1052  - Out Volume 4L */
+	{ 0x041D, 0x0080 },  /* R1053  - Out Volume 4R */
+	{ 0x041E, 0x0080 },  /* R1054  - DAC Volume Limit 5L */
+	{ 0x041F, 0x0080 },  /* R1055  - DAC Volume Limit 5R */
+	{ 0x0420, 0x0080 },  /* R1056  - DAC Volume Limit 6L */
+	{ 0x0421, 0x0080 },  /* R1057  - DAC Volume Limit 6R */
+	{ 0x0440, 0x0000 },  /* R1088  - DAC AEC Control 1 */
+	{ 0x0441, 0x0022 },  /* R1089  - Output Volume Ramp */
+	{ 0x0480, 0x0180 },  /* R1152  - DAC Digital Volume 1L */
+	{ 0x0481, 0x0180 },  /* R1153  - DAC Digital Volume 1R */
+	{ 0x0482, 0x0180 },  /* R1154  - DAC Digital Volume 2L */
+	{ 0x0483, 0x0180 },  /* R1155  - DAC Digital Volume 2R */
+	{ 0x0484, 0x0180 },  /* R1156  - DAC Digital Volume 3L */
+	{ 0x0485, 0x0180 },  /* R1157  - DAC Digital Volume 3R */
+	{ 0x0486, 0x0180 },  /* R1158  - DAC Digital Volume 4L */
+	{ 0x0487, 0x0180 },  /* R1159  - DAC Digital Volume 4R */
+	{ 0x0488, 0x0180 },  /* R1160  - DAC Digital Volume 5L */
+	{ 0x0489, 0x0180 },  /* R1161  - DAC Digital Volume 5R */
+	{ 0x048A, 0x0180 },  /* R1162  - DAC Digital Volume 6L */
+	{ 0x048B, 0x0180 },  /* R1163  - DAC Digital Volume 6R */
+	{ 0x04C0, 0x0069 },  /* R1216  - PDM SPK1 CTRL 1 */
+	{ 0x04C1, 0x0000 },  /* R1217  - PDM SPK1 CTRL 2 */
+	{ 0x04C2, 0x0069 },  /* R1218  - PDM SPK2 CTRL 1 */
+	{ 0x04C3, 0x0000 },  /* R1219  - PDM SPK2 CTRL 2 */
+	{ 0x0500, 0x000C },  /* R1280  - Audio IF 1_1 */
+	{ 0x0501, 0x0008 },  /* R1281  - Audio IF 1_2 */
+	{ 0x0502, 0x0000 },  /* R1282  - Audio IF 1_3 */
+	{ 0x0503, 0x0000 },  /* R1283  - Audio IF 1_4 */
+	{ 0x0504, 0x0000 },  /* R1284  - Audio IF 1_5 */
+	{ 0x0505, 0x0300 },  /* R1285  - Audio IF 1_6 */
+	{ 0x0506, 0x0300 },  /* R1286  - Audio IF 1_7 */
+	{ 0x0507, 0x1820 },  /* R1287  - Audio IF 1_8 */
+	{ 0x0508, 0x1820 },  /* R1288  - Audio IF 1_9 */
+	{ 0x0509, 0x0000 },  /* R1289  - Audio IF 1_10 */
+	{ 0x050A, 0x0001 },  /* R1290  - Audio IF 1_11 */
+	{ 0x050B, 0x0002 },  /* R1291  - Audio IF 1_12 */
+	{ 0x050C, 0x0003 },  /* R1292  - Audio IF 1_13 */
+	{ 0x050D, 0x0004 },  /* R1293  - Audio IF 1_14 */
+	{ 0x050E, 0x0005 },  /* R1294  - Audio IF 1_15 */
+	{ 0x050F, 0x0006 },  /* R1295  - Audio IF 1_16 */
+	{ 0x0510, 0x0007 },  /* R1296  - Audio IF 1_17 */
+	{ 0x0511, 0x0000 },  /* R1297  - Audio IF 1_18 */
+	{ 0x0512, 0x0001 },  /* R1298  - Audio IF 1_19 */
+	{ 0x0513, 0x0002 },  /* R1299  - Audio IF 1_20 */
+	{ 0x0514, 0x0003 },  /* R1300  - Audio IF 1_21 */
+	{ 0x0515, 0x0004 },  /* R1301  - Audio IF 1_22 */
+	{ 0x0516, 0x0005 },  /* R1302  - Audio IF 1_23 */
+	{ 0x0517, 0x0006 },  /* R1303  - Audio IF 1_24 */
+	{ 0x0518, 0x0007 },  /* R1304  - Audio IF 1_25 */
+	{ 0x0519, 0x0000 },  /* R1305  - Audio IF 1_26 */
+	{ 0x051A, 0x0000 },  /* R1306  - Audio IF 1_27 */
+	{ 0x0540, 0x000C },  /* R1344  - Audio IF 2_1 */
+	{ 0x0541, 0x0008 },  /* R1345  - Audio IF 2_2 */
+	{ 0x0542, 0x0000 },  /* R1346  - Audio IF 2_3 */
+	{ 0x0543, 0x0000 },  /* R1347  - Audio IF 2_4 */
+	{ 0x0544, 0x0000 },  /* R1348  - Audio IF 2_5 */
+	{ 0x0545, 0x0300 },  /* R1349  - Audio IF 2_6 */
+	{ 0x0546, 0x0300 },  /* R1350  - Audio IF 2_7 */
+	{ 0x0547, 0x1820 },  /* R1351  - Audio IF 2_8 */
+	{ 0x0548, 0x1820 },  /* R1352  - Audio IF 2_9 */
+	{ 0x0549, 0x0000 },  /* R1353  - Audio IF 2_10 */
+	{ 0x054A, 0x0001 },  /* R1354  - Audio IF 2_11 */
+	{ 0x0551, 0x0000 },  /* R1361  - Audio IF 2_18 */
+	{ 0x0552, 0x0001 },  /* R1362  - Audio IF 2_19 */
+	{ 0x0559, 0x0000 },  /* R1369  - Audio IF 2_26 */
+	{ 0x055A, 0x0000 },  /* R1370  - Audio IF 2_27 */
+	{ 0x0580, 0x000C },  /* R1408  - Audio IF 3_1 */
+	{ 0x0581, 0x0008 },  /* R1409  - Audio IF 3_2 */
+	{ 0x0582, 0x0000 },  /* R1410  - Audio IF 3_3 */
+	{ 0x0583, 0x0000 },  /* R1411  - Audio IF 3_4 */
+	{ 0x0584, 0x0000 },  /* R1412  - Audio IF 3_5 */
+	{ 0x0585, 0x0300 },  /* R1413  - Audio IF 3_6 */
+	{ 0x0586, 0x0300 },  /* R1414  - Audio IF 3_7 */
+	{ 0x0587, 0x1820 },  /* R1415  - Audio IF 3_8 */
+	{ 0x0588, 0x1820 },  /* R1416  - Audio IF 3_9 */
+	{ 0x0589, 0x0000 },  /* R1417  - Audio IF 3_10 */
+	{ 0x058A, 0x0001 },  /* R1418  - Audio IF 3_11 */
+	{ 0x0591, 0x0000 },  /* R1425  - Audio IF 3_18 */
+	{ 0x0592, 0x0001 },  /* R1426  - Audio IF 3_19 */
+	{ 0x0599, 0x0000 },  /* R1433  - Audio IF 3_26 */
+	{ 0x059A, 0x0000 },  /* R1434  - Audio IF 3_27 */
+	{ 0x0640, 0x0000 },  /* R1600  - PWM1MIX Input 1 Source */
+	{ 0x0641, 0x0080 },  /* R1601  - PWM1MIX Input 1 Volume */
+	{ 0x0642, 0x0000 },  /* R1602  - PWM1MIX Input 2 Source */
+	{ 0x0643, 0x0080 },  /* R1603  - PWM1MIX Input 2 Volume */
+	{ 0x0644, 0x0000 },  /* R1604  - PWM1MIX Input 3 Source */
+	{ 0x0645, 0x0080 },  /* R1605  - PWM1MIX Input 3 Volume */
+	{ 0x0646, 0x0000 },  /* R1606  - PWM1MIX Input 4 Source */
+	{ 0x0647, 0x0080 },  /* R1607  - PWM1MIX Input 4 Volume */
+	{ 0x0648, 0x0000 },  /* R1608  - PWM2MIX Input 1 Source */
+	{ 0x0649, 0x0080 },  /* R1609  - PWM2MIX Input 1 Volume */
+	{ 0x064A, 0x0000 },  /* R1610  - PWM2MIX Input 2 Source */
+	{ 0x064B, 0x0080 },  /* R1611  - PWM2MIX Input 2 Volume */
+	{ 0x064C, 0x0000 },  /* R1612  - PWM2MIX Input 3 Source */
+	{ 0x064D, 0x0080 },  /* R1613  - PWM2MIX Input 3 Volume */
+	{ 0x064E, 0x0000 },  /* R1614  - PWM2MIX Input 4 Source */
+	{ 0x064F, 0x0080 },  /* R1615  - PWM2MIX Input 4 Volume */
+	{ 0x0680, 0x0000 },  /* R1664  - OUT1LMIX Input 1 Source */
+	{ 0x0681, 0x0080 },  /* R1665  - OUT1LMIX Input 1 Volume */
+	{ 0x0682, 0x0000 },  /* R1666  - OUT1LMIX Input 2 Source */
+	{ 0x0683, 0x0080 },  /* R1667  - OUT1LMIX Input 2 Volume */
+	{ 0x0684, 0x0000 },  /* R1668  - OUT1LMIX Input 3 Source */
+	{ 0x0685, 0x0080 },  /* R1669  - OUT1LMIX Input 3 Volume */
+	{ 0x0686, 0x0000 },  /* R1670  - OUT1LMIX Input 4 Source */
+	{ 0x0687, 0x0080 },  /* R1671  - OUT1LMIX Input 4 Volume */
+	{ 0x0688, 0x0000 },  /* R1672  - OUT1RMIX Input 1 Source */
+	{ 0x0689, 0x0080 },  /* R1673  - OUT1RMIX Input 1 Volume */
+	{ 0x068A, 0x0000 },  /* R1674  - OUT1RMIX Input 2 Source */
+	{ 0x068B, 0x0080 },  /* R1675  - OUT1RMIX Input 2 Volume */
+	{ 0x068C, 0x0000 },  /* R1676  - OUT1RMIX Input 3 Source */
+	{ 0x068D, 0x0080 },  /* R1677  - OUT1RMIX Input 3 Volume */
+	{ 0x068E, 0x0000 },  /* R1678  - OUT1RMIX Input 4 Source */
+	{ 0x068F, 0x0080 },  /* R1679  - OUT1RMIX Input 4 Volume */
+	{ 0x0690, 0x0000 },  /* R1680  - OUT2LMIX Input 1 Source */
+	{ 0x0691, 0x0080 },  /* R1681  - OUT2LMIX Input 1 Volume */
+	{ 0x0692, 0x0000 },  /* R1682  - OUT2LMIX Input 2 Source */
+	{ 0x0693, 0x0080 },  /* R1683  - OUT2LMIX Input 2 Volume */
+	{ 0x0694, 0x0000 },  /* R1684  - OUT2LMIX Input 3 Source */
+	{ 0x0695, 0x0080 },  /* R1685  - OUT2LMIX Input 3 Volume */
+	{ 0x0696, 0x0000 },  /* R1686  - OUT2LMIX Input 4 Source */
+	{ 0x0697, 0x0080 },  /* R1687  - OUT2LMIX Input 4 Volume */
+	{ 0x0698, 0x0000 },  /* R1688  - OUT2RMIX Input 1 Source */
+	{ 0x0699, 0x0080 },  /* R1689  - OUT2RMIX Input 1 Volume */
+	{ 0x069A, 0x0000 },  /* R1690  - OUT2RMIX Input 2 Source */
+	{ 0x069B, 0x0080 },  /* R1691  - OUT2RMIX Input 2 Volume */
+	{ 0x069C, 0x0000 },  /* R1692  - OUT2RMIX Input 3 Source */
+	{ 0x069D, 0x0080 },  /* R1693  - OUT2RMIX Input 3 Volume */
+	{ 0x069E, 0x0000 },  /* R1694  - OUT2RMIX Input 4 Source */
+	{ 0x069F, 0x0080 },  /* R1695  - OUT2RMIX Input 4 Volume */
+	{ 0x06A0, 0x0000 },  /* R1696  - OUT3LMIX Input 1 Source */
+	{ 0x06A1, 0x0080 },  /* R1697  - OUT3LMIX Input 1 Volume */
+	{ 0x06A2, 0x0000 },  /* R1698  - OUT3LMIX Input 2 Source */
+	{ 0x06A3, 0x0080 },  /* R1699  - OUT3LMIX Input 2 Volume */
+	{ 0x06A4, 0x0000 },  /* R1700  - OUT3LMIX Input 3 Source */
+	{ 0x06A5, 0x0080 },  /* R1701  - OUT3LMIX Input 3 Volume */
+	{ 0x06A6, 0x0000 },  /* R1702  - OUT3LMIX Input 4 Source */
+	{ 0x06A7, 0x0080 },  /* R1703  - OUT3LMIX Input 4 Volume */
+	{ 0x06A8, 0x0000 },  /* R1704  - OUT3RMIX Input 1 Source */
+	{ 0x06A9, 0x0080 },  /* R1705  - OUT3RMIX Input 1 Volume */
+	{ 0x06AA, 0x0000 },  /* R1706  - OUT3RMIX Input 2 Source */
+	{ 0x06AB, 0x0080 },  /* R1707  - OUT3RMIX Input 2 Volume */
+	{ 0x06AC, 0x0000 },  /* R1708  - OUT3RMIX Input 3 Source */
+	{ 0x06AD, 0x0080 },  /* R1709  - OUT3RMIX Input 3 Volume */
+	{ 0x06AE, 0x0000 },  /* R1710  - OUT3RMIX Input 4 Source */
+	{ 0x06AF, 0x0080 },  /* R1711  - OUT3RMIX Input 4 Volume */
+	{ 0x06B0, 0x0000 },  /* R1712  - OUT4LMIX Input 1 Source */
+	{ 0x06B1, 0x0080 },  /* R1713  - OUT4LMIX Input 1 Volume */
+	{ 0x06B2, 0x0000 },  /* R1714  - OUT4LMIX Input 2 Source */
+	{ 0x06B3, 0x0080 },  /* R1715  - OUT4LMIX Input 2 Volume */
+	{ 0x06B4, 0x0000 },  /* R1716  - OUT4LMIX Input 3 Source */
+	{ 0x06B5, 0x0080 },  /* R1717  - OUT4LMIX Input 3 Volume */
+	{ 0x06B6, 0x0000 },  /* R1718  - OUT4LMIX Input 4 Source */
+	{ 0x06B7, 0x0080 },  /* R1719  - OUT4LMIX Input 4 Volume */
+	{ 0x06B8, 0x0000 },  /* R1720  - OUT4RMIX Input 1 Source */
+	{ 0x06B9, 0x0080 },  /* R1721  - OUT4RMIX Input 1 Volume */
+	{ 0x06BA, 0x0000 },  /* R1722  - OUT4RMIX Input 2 Source */
+	{ 0x06BB, 0x0080 },  /* R1723  - OUT4RMIX Input 2 Volume */
+	{ 0x06BC, 0x0000 },  /* R1724  - OUT4RMIX Input 3 Source */
+	{ 0x06BD, 0x0080 },  /* R1725  - OUT4RMIX Input 3 Volume */
+	{ 0x06BE, 0x0000 },  /* R1726  - OUT4RMIX Input 4 Source */
+	{ 0x06BF, 0x0080 },  /* R1727  - OUT4RMIX Input 4 Volume */
+	{ 0x06C0, 0x0000 },  /* R1728  - OUT5LMIX Input 1 Source */
+	{ 0x06C1, 0x0080 },  /* R1729  - OUT5LMIX Input 1 Volume */
+	{ 0x06C2, 0x0000 },  /* R1730  - OUT5LMIX Input 2 Source */
+	{ 0x06C3, 0x0080 },  /* R1731  - OUT5LMIX Input 2 Volume */
+	{ 0x06C4, 0x0000 },  /* R1732  - OUT5LMIX Input 3 Source */
+	{ 0x06C5, 0x0080 },  /* R1733  - OUT5LMIX Input 3 Volume */
+	{ 0x06C6, 0x0000 },  /* R1734  - OUT5LMIX Input 4 Source */
+	{ 0x06C7, 0x0080 },  /* R1735  - OUT5LMIX Input 4 Volume */
+	{ 0x06C8, 0x0000 },  /* R1736  - OUT5RMIX Input 1 Source */
+	{ 0x06C9, 0x0080 },  /* R1737  - OUT5RMIX Input 1 Volume */
+	{ 0x06CA, 0x0000 },  /* R1738  - OUT5RMIX Input 2 Source */
+	{ 0x06CB, 0x0080 },  /* R1739  - OUT5RMIX Input 2 Volume */
+	{ 0x06CC, 0x0000 },  /* R1740  - OUT5RMIX Input 3 Source */
+	{ 0x06CD, 0x0080 },  /* R1741  - OUT5RMIX Input 3 Volume */
+	{ 0x06CE, 0x0000 },  /* R1742  - OUT5RMIX Input 4 Source */
+	{ 0x06CF, 0x0080 },  /* R1743  - OUT5RMIX Input 4 Volume */
+	{ 0x06D0, 0x0000 },  /* R1744  - OUT6LMIX Input 1 Source */
+	{ 0x06D1, 0x0080 },  /* R1745  - OUT6LMIX Input 1 Volume */
+	{ 0x06D2, 0x0000 },  /* R1746  - OUT6LMIX Input 2 Source */
+	{ 0x06D3, 0x0080 },  /* R1747  - OUT6LMIX Input 2 Volume */
+	{ 0x06D4, 0x0000 },  /* R1748  - OUT6LMIX Input 3 Source */
+	{ 0x06D5, 0x0080 },  /* R1749  - OUT6LMIX Input 3 Volume */
+	{ 0x06D6, 0x0000 },  /* R1750  - OUT6LMIX Input 4 Source */
+	{ 0x06D7, 0x0080 },  /* R1751  - OUT6LMIX Input 4 Volume */
+	{ 0x06D8, 0x0000 },  /* R1752  - OUT6RMIX Input 1 Source */
+	{ 0x06D9, 0x0080 },  /* R1753  - OUT6RMIX Input 1 Volume */
+	{ 0x06DA, 0x0000 },  /* R1754  - OUT6RMIX Input 2 Source */
+	{ 0x06DB, 0x0080 },  /* R1755  - OUT6RMIX Input 2 Volume */
+	{ 0x06DC, 0x0000 },  /* R1756  - OUT6RMIX Input 3 Source */
+	{ 0x06DD, 0x0080 },  /* R1757  - OUT6RMIX Input 3 Volume */
+	{ 0x06DE, 0x0000 },  /* R1758  - OUT6RMIX Input 4 Source */
+	{ 0x06DF, 0x0080 },  /* R1759  - OUT6RMIX Input 4 Volume */
+	{ 0x0700, 0x0000 },  /* R1792  - AIF1TX1MIX Input 1 Source */
+	{ 0x0701, 0x0080 },  /* R1793  - AIF1TX1MIX Input 1 Volume */
+	{ 0x0702, 0x0000 },  /* R1794  - AIF1TX1MIX Input 2 Source */
+	{ 0x0703, 0x0080 },  /* R1795  - AIF1TX1MIX Input 2 Volume */
+	{ 0x0704, 0x0000 },  /* R1796  - AIF1TX1MIX Input 3 Source */
+	{ 0x0705, 0x0080 },  /* R1797  - AIF1TX1MIX Input 3 Volume */
+	{ 0x0706, 0x0000 },  /* R1798  - AIF1TX1MIX Input 4 Source */
+	{ 0x0707, 0x0080 },  /* R1799  - AIF1TX1MIX Input 4 Volume */
+	{ 0x0708, 0x0000 },  /* R1800  - AIF1TX2MIX Input 1 Source */
+	{ 0x0709, 0x0080 },  /* R1801  - AIF1TX2MIX Input 1 Volume */
+	{ 0x070A, 0x0000 },  /* R1802  - AIF1TX2MIX Input 2 Source */
+	{ 0x070B, 0x0080 },  /* R1803  - AIF1TX2MIX Input 2 Volume */
+	{ 0x070C, 0x0000 },  /* R1804  - AIF1TX2MIX Input 3 Source */
+	{ 0x070D, 0x0080 },  /* R1805  - AIF1TX2MIX Input 3 Volume */
+	{ 0x070E, 0x0000 },  /* R1806  - AIF1TX2MIX Input 4 Source */
+	{ 0x070F, 0x0080 },  /* R1807  - AIF1TX2MIX Input 4 Volume */
+	{ 0x0710, 0x0000 },  /* R1808  - AIF1TX3MIX Input 1 Source */
+	{ 0x0711, 0x0080 },  /* R1809  - AIF1TX3MIX Input 1 Volume */
+	{ 0x0712, 0x0000 },  /* R1810  - AIF1TX3MIX Input 2 Source */
+	{ 0x0713, 0x0080 },  /* R1811  - AIF1TX3MIX Input 2 Volume */
+	{ 0x0714, 0x0000 },  /* R1812  - AIF1TX3MIX Input 3 Source */
+	{ 0x0715, 0x0080 },  /* R1813  - AIF1TX3MIX Input 3 Volume */
+	{ 0x0716, 0x0000 },  /* R1814  - AIF1TX3MIX Input 4 Source */
+	{ 0x0717, 0x0080 },  /* R1815  - AIF1TX3MIX Input 4 Volume */
+	{ 0x0718, 0x0000 },  /* R1816  - AIF1TX4MIX Input 1 Source */
+	{ 0x0719, 0x0080 },  /* R1817  - AIF1TX4MIX Input 1 Volume */
+	{ 0x071A, 0x0000 },  /* R1818  - AIF1TX4MIX Input 2 Source */
+	{ 0x071B, 0x0080 },  /* R1819  - AIF1TX4MIX Input 2 Volume */
+	{ 0x071C, 0x0000 },  /* R1820  - AIF1TX4MIX Input 3 Source */
+	{ 0x071D, 0x0080 },  /* R1821  - AIF1TX4MIX Input 3 Volume */
+	{ 0x071E, 0x0000 },  /* R1822  - AIF1TX4MIX Input 4 Source */
+	{ 0x071F, 0x0080 },  /* R1823  - AIF1TX4MIX Input 4 Volume */
+	{ 0x0720, 0x0000 },  /* R1824  - AIF1TX5MIX Input 1 Source */
+	{ 0x0721, 0x0080 },  /* R1825  - AIF1TX5MIX Input 1 Volume */
+	{ 0x0722, 0x0000 },  /* R1826  - AIF1TX5MIX Input 2 Source */
+	{ 0x0723, 0x0080 },  /* R1827  - AIF1TX5MIX Input 2 Volume */
+	{ 0x0724, 0x0000 },  /* R1828  - AIF1TX5MIX Input 3 Source */
+	{ 0x0725, 0x0080 },  /* R1829  - AIF1TX5MIX Input 3 Volume */
+	{ 0x0726, 0x0000 },  /* R1830  - AIF1TX5MIX Input 4 Source */
+	{ 0x0727, 0x0080 },  /* R1831  - AIF1TX5MIX Input 4 Volume */
+	{ 0x0728, 0x0000 },  /* R1832  - AIF1TX6MIX Input 1 Source */
+	{ 0x0729, 0x0080 },  /* R1833  - AIF1TX6MIX Input 1 Volume */
+	{ 0x072A, 0x0000 },  /* R1834  - AIF1TX6MIX Input 2 Source */
+	{ 0x072B, 0x0080 },  /* R1835  - AIF1TX6MIX Input 2 Volume */
+	{ 0x072C, 0x0000 },  /* R1836  - AIF1TX6MIX Input 3 Source */
+	{ 0x072D, 0x0080 },  /* R1837  - AIF1TX6MIX Input 3 Volume */
+	{ 0x072E, 0x0000 },  /* R1838  - AIF1TX6MIX Input 4 Source */
+	{ 0x072F, 0x0080 },  /* R1839  - AIF1TX6MIX Input 4 Volume */
+	{ 0x0730, 0x0000 },  /* R1840  - AIF1TX7MIX Input 1 Source */
+	{ 0x0731, 0x0080 },  /* R1841  - AIF1TX7MIX Input 1 Volume */
+	{ 0x0732, 0x0000 },  /* R1842  - AIF1TX7MIX Input 2 Source */
+	{ 0x0733, 0x0080 },  /* R1843  - AIF1TX7MIX Input 2 Volume */
+	{ 0x0734, 0x0000 },  /* R1844  - AIF1TX7MIX Input 3 Source */
+	{ 0x0735, 0x0080 },  /* R1845  - AIF1TX7MIX Input 3 Volume */
+	{ 0x0736, 0x0000 },  /* R1846  - AIF1TX7MIX Input 4 Source */
+	{ 0x0737, 0x0080 },  /* R1847  - AIF1TX7MIX Input 4 Volume */
+	{ 0x0738, 0x0000 },  /* R1848  - AIF1TX8MIX Input 1 Source */
+	{ 0x0739, 0x0080 },  /* R1849  - AIF1TX8MIX Input 1 Volume */
+	{ 0x073A, 0x0000 },  /* R1850  - AIF1TX8MIX Input 2 Source */
+	{ 0x073B, 0x0080 },  /* R1851  - AIF1TX8MIX Input 2 Volume */
+	{ 0x073C, 0x0000 },  /* R1852  - AIF1TX8MIX Input 3 Source */
+	{ 0x073D, 0x0080 },  /* R1853  - AIF1TX8MIX Input 3 Volume */
+	{ 0x073E, 0x0000 },  /* R1854  - AIF1TX8MIX Input 4 Source */
+	{ 0x073F, 0x0080 },  /* R1855  - AIF1TX8MIX Input 4 Volume */
+	{ 0x0740, 0x0000 },  /* R1856  - AIF2TX1MIX Input 1 Source */
+	{ 0x0741, 0x0080 },  /* R1857  - AIF2TX1MIX Input 1 Volume */
+	{ 0x0742, 0x0000 },  /* R1858  - AIF2TX1MIX Input 2 Source */
+	{ 0x0743, 0x0080 },  /* R1859  - AIF2TX1MIX Input 2 Volume */
+	{ 0x0744, 0x0000 },  /* R1860  - AIF2TX1MIX Input 3 Source */
+	{ 0x0745, 0x0080 },  /* R1861  - AIF2TX1MIX Input 3 Volume */
+	{ 0x0746, 0x0000 },  /* R1862  - AIF2TX1MIX Input 4 Source */
+	{ 0x0747, 0x0080 },  /* R1863  - AIF2TX1MIX Input 4 Volume */
+	{ 0x0748, 0x0000 },  /* R1864  - AIF2TX2MIX Input 1 Source */
+	{ 0x0749, 0x0080 },  /* R1865  - AIF2TX2MIX Input 1 Volume */
+	{ 0x074A, 0x0000 },  /* R1866  - AIF2TX2MIX Input 2 Source */
+	{ 0x074B, 0x0080 },  /* R1867  - AIF2TX2MIX Input 2 Volume */
+	{ 0x074C, 0x0000 },  /* R1868  - AIF2TX2MIX Input 3 Source */
+	{ 0x074D, 0x0080 },  /* R1869  - AIF2TX2MIX Input 3 Volume */
+	{ 0x074E, 0x0000 },  /* R1870  - AIF2TX2MIX Input 4 Source */
+	{ 0x074F, 0x0080 },  /* R1871  - AIF2TX2MIX Input 4 Volume */
+	{ 0x0780, 0x0000 },  /* R1920  - AIF3TX1MIX Input 1 Source */
+	{ 0x0781, 0x0080 },  /* R1921  - AIF3TX1MIX Input 1 Volume */
+	{ 0x0782, 0x0000 },  /* R1922  - AIF3TX1MIX Input 2 Source */
+	{ 0x0783, 0x0080 },  /* R1923  - AIF3TX1MIX Input 2 Volume */
+	{ 0x0784, 0x0000 },  /* R1924  - AIF3TX1MIX Input 3 Source */
+	{ 0x0785, 0x0080 },  /* R1925  - AIF3TX1MIX Input 3 Volume */
+	{ 0x0786, 0x0000 },  /* R1926  - AIF3TX1MIX Input 4 Source */
+	{ 0x0787, 0x0080 },  /* R1927  - AIF3TX1MIX Input 4 Volume */
+	{ 0x0788, 0x0000 },  /* R1928  - AIF3TX2MIX Input 1 Source */
+	{ 0x0789, 0x0080 },  /* R1929  - AIF3TX2MIX Input 1 Volume */
+	{ 0x078A, 0x0000 },  /* R1930  - AIF3TX2MIX Input 2 Source */
+	{ 0x078B, 0x0080 },  /* R1931  - AIF3TX2MIX Input 2 Volume */
+	{ 0x078C, 0x0000 },  /* R1932  - AIF3TX2MIX Input 3 Source */
+	{ 0x078D, 0x0080 },  /* R1933  - AIF3TX2MIX Input 3 Volume */
+	{ 0x078E, 0x0000 },  /* R1934  - AIF3TX2MIX Input 4 Source */
+	{ 0x078F, 0x0080 },  /* R1935  - AIF3TX2MIX Input 4 Volume */
+	{ 0x0880, 0x0000 },  /* R2176  - EQ1MIX Input 1 Source */
+	{ 0x0881, 0x0080 },  /* R2177  - EQ1MIX Input 1 Volume */
+	{ 0x0882, 0x0000 },  /* R2178  - EQ1MIX Input 2 Source */
+	{ 0x0883, 0x0080 },  /* R2179  - EQ1MIX Input 2 Volume */
+	{ 0x0884, 0x0000 },  /* R2180  - EQ1MIX Input 3 Source */
+	{ 0x0885, 0x0080 },  /* R2181  - EQ1MIX Input 3 Volume */
+	{ 0x0886, 0x0000 },  /* R2182  - EQ1MIX Input 4 Source */
+	{ 0x0887, 0x0080 },  /* R2183  - EQ1MIX Input 4 Volume */
+	{ 0x0888, 0x0000 },  /* R2184  - EQ2MIX Input 1 Source */
+	{ 0x0889, 0x0080 },  /* R2185  - EQ2MIX Input 1 Volume */
+	{ 0x088A, 0x0000 },  /* R2186  - EQ2MIX Input 2 Source */
+	{ 0x088B, 0x0080 },  /* R2187  - EQ2MIX Input 2 Volume */
+	{ 0x088C, 0x0000 },  /* R2188  - EQ2MIX Input 3 Source */
+	{ 0x088D, 0x0080 },  /* R2189  - EQ2MIX Input 3 Volume */
+	{ 0x088E, 0x0000 },  /* R2190  - EQ2MIX Input 4 Source */
+	{ 0x088F, 0x0080 },  /* R2191  - EQ2MIX Input 4 Volume */
+	{ 0x0890, 0x0000 },  /* R2192  - EQ3MIX Input 1 Source */
+	{ 0x0891, 0x0080 },  /* R2193  - EQ3MIX Input 1 Volume */
+	{ 0x0892, 0x0000 },  /* R2194  - EQ3MIX Input 2 Source */
+	{ 0x0893, 0x0080 },  /* R2195  - EQ3MIX Input 2 Volume */
+	{ 0x0894, 0x0000 },  /* R2196  - EQ3MIX Input 3 Source */
+	{ 0x0895, 0x0080 },  /* R2197  - EQ3MIX Input 3 Volume */
+	{ 0x0896, 0x0000 },  /* R2198  - EQ3MIX Input 4 Source */
+	{ 0x0897, 0x0080 },  /* R2199  - EQ3MIX Input 4 Volume */
+	{ 0x0898, 0x0000 },  /* R2200  - EQ4MIX Input 1 Source */
+	{ 0x0899, 0x0080 },  /* R2201  - EQ4MIX Input 1 Volume */
+	{ 0x089A, 0x0000 },  /* R2202  - EQ4MIX Input 2 Source */
+	{ 0x089B, 0x0080 },  /* R2203  - EQ4MIX Input 2 Volume */
+	{ 0x089C, 0x0000 },  /* R2204  - EQ4MIX Input 3 Source */
+	{ 0x089D, 0x0080 },  /* R2205  - EQ4MIX Input 3 Volume */
+	{ 0x089E, 0x0000 },  /* R2206  - EQ4MIX Input 4 Source */
+	{ 0x089F, 0x0080 },  /* R2207  - EQ4MIX Input 4 Volume */
+	{ 0x08C0, 0x0000 },  /* R2240  - DRC1LMIX Input 1 Source */
+	{ 0x08C1, 0x0080 },  /* R2241  - DRC1LMIX Input 1 Volume */
+	{ 0x08C2, 0x0000 },  /* R2242  - DRC1LMIX Input 2 Source */
+	{ 0x08C3, 0x0080 },  /* R2243  - DRC1LMIX Input 2 Volume */
+	{ 0x08C4, 0x0000 },  /* R2244  - DRC1LMIX Input 3 Source */
+	{ 0x08C5, 0x0080 },  /* R2245  - DRC1LMIX Input 3 Volume */
+	{ 0x08C6, 0x0000 },  /* R2246  - DRC1LMIX Input 4 Source */
+	{ 0x08C7, 0x0080 },  /* R2247  - DRC1LMIX Input 4 Volume */
+	{ 0x08C8, 0x0000 },  /* R2248  - DRC1RMIX Input 1 Source */
+	{ 0x08C9, 0x0080 },  /* R2249  - DRC1RMIX Input 1 Volume */
+	{ 0x08CA, 0x0000 },  /* R2250  - DRC1RMIX Input 2 Source */
+	{ 0x08CB, 0x0080 },  /* R2251  - DRC1RMIX Input 2 Volume */
+	{ 0x08CC, 0x0000 },  /* R2252  - DRC1RMIX Input 3 Source */
+	{ 0x08CD, 0x0080 },  /* R2253  - DRC1RMIX Input 3 Volume */
+	{ 0x08CE, 0x0000 },  /* R2254  - DRC1RMIX Input 4 Source */
+	{ 0x08CF, 0x0080 },  /* R2255  - DRC1RMIX Input 4 Volume */
+	{ 0x0900, 0x0000 },  /* R2304  - HPLP1MIX Input 1 Source */
+	{ 0x0901, 0x0080 },  /* R2305  - HPLP1MIX Input 1 Volume */
+	{ 0x0902, 0x0000 },  /* R2306  - HPLP1MIX Input 2 Source */
+	{ 0x0903, 0x0080 },  /* R2307  - HPLP1MIX Input 2 Volume */
+	{ 0x0904, 0x0000 },  /* R2308  - HPLP1MIX Input 3 Source */
+	{ 0x0905, 0x0080 },  /* R2309  - HPLP1MIX Input 3 Volume */
+	{ 0x0906, 0x0000 },  /* R2310  - HPLP1MIX Input 4 Source */
+	{ 0x0907, 0x0080 },  /* R2311  - HPLP1MIX Input 4 Volume */
+	{ 0x0908, 0x0000 },  /* R2312  - HPLP2MIX Input 1 Source */
+	{ 0x0909, 0x0080 },  /* R2313  - HPLP2MIX Input 1 Volume */
+	{ 0x090A, 0x0000 },  /* R2314  - HPLP2MIX Input 2 Source */
+	{ 0x090B, 0x0080 },  /* R2315  - HPLP2MIX Input 2 Volume */
+	{ 0x090C, 0x0000 },  /* R2316  - HPLP2MIX Input 3 Source */
+	{ 0x090D, 0x0080 },  /* R2317  - HPLP2MIX Input 3 Volume */
+	{ 0x090E, 0x0000 },  /* R2318  - HPLP2MIX Input 4 Source */
+	{ 0x090F, 0x0080 },  /* R2319  - HPLP2MIX Input 4 Volume */
+	{ 0x0910, 0x0000 },  /* R2320  - HPLP3MIX Input 1 Source */
+	{ 0x0911, 0x0080 },  /* R2321  - HPLP3MIX Input 1 Volume */
+	{ 0x0912, 0x0000 },  /* R2322  - HPLP3MIX Input 2 Source */
+	{ 0x0913, 0x0080 },  /* R2323  - HPLP3MIX Input 2 Volume */
+	{ 0x0914, 0x0000 },  /* R2324  - HPLP3MIX Input 3 Source */
+	{ 0x0915, 0x0080 },  /* R2325  - HPLP3MIX Input 3 Volume */
+	{ 0x0916, 0x0000 },  /* R2326  - HPLP3MIX Input 4 Source */
+	{ 0x0917, 0x0080 },  /* R2327  - HPLP3MIX Input 4 Volume */
+	{ 0x0918, 0x0000 },  /* R2328  - HPLP4MIX Input 1 Source */
+	{ 0x0919, 0x0080 },  /* R2329  - HPLP4MIX Input 1 Volume */
+	{ 0x091A, 0x0000 },  /* R2330  - HPLP4MIX Input 2 Source */
+	{ 0x091B, 0x0080 },  /* R2331  - HPLP4MIX Input 2 Volume */
+	{ 0x091C, 0x0000 },  /* R2332  - HPLP4MIX Input 3 Source */
+	{ 0x091D, 0x0080 },  /* R2333  - HPLP4MIX Input 3 Volume */
+	{ 0x091E, 0x0000 },  /* R2334  - HPLP4MIX Input 4 Source */
+	{ 0x091F, 0x0080 },  /* R2335  - HPLP4MIX Input 4 Volume */
+	{ 0x0940, 0x0000 },  /* R2368  - DSP1LMIX Input 1 Source */
+	{ 0x0941, 0x0080 },  /* R2369  - DSP1LMIX Input 1 Volume */
+	{ 0x0942, 0x0000 },  /* R2370  - DSP1LMIX Input 2 Source */
+	{ 0x0943, 0x0080 },  /* R2371  - DSP1LMIX Input 2 Volume */
+	{ 0x0944, 0x0000 },  /* R2372  - DSP1LMIX Input 3 Source */
+	{ 0x0945, 0x0080 },  /* R2373  - DSP1LMIX Input 3 Volume */
+	{ 0x0946, 0x0000 },  /* R2374  - DSP1LMIX Input 4 Source */
+	{ 0x0947, 0x0080 },  /* R2375  - DSP1LMIX Input 4 Volume */
+	{ 0x0948, 0x0000 },  /* R2376  - DSP1RMIX Input 1 Source */
+	{ 0x0949, 0x0080 },  /* R2377  - DSP1RMIX Input 1 Volume */
+	{ 0x094A, 0x0000 },  /* R2378  - DSP1RMIX Input 2 Source */
+	{ 0x094B, 0x0080 },  /* R2379  - DSP1RMIX Input 2 Volume */
+	{ 0x094C, 0x0000 },  /* R2380  - DSP1RMIX Input 3 Source */
+	{ 0x094D, 0x0080 },  /* R2381  - DSP1RMIX Input 3 Volume */
+	{ 0x094E, 0x0000 },  /* R2382  - DSP1RMIX Input 4 Source */
+	{ 0x094F, 0x0080 },  /* R2383  - DSP1RMIX Input 4 Volume */
+	{ 0x0950, 0x0000 },  /* R2384  - DSP1AUX1MIX Input 1 Source */
+	{ 0x0958, 0x0000 },  /* R2392  - DSP1AUX2MIX Input 1 Source */
+	{ 0x0960, 0x0000 },  /* R2400  - DSP1AUX3MIX Input 1 Source */
+	{ 0x0968, 0x0000 },  /* R2408  - DSP1AUX4MIX Input 1 Source */
+	{ 0x0970, 0x0000 },  /* R2416  - DSP1AUX5MIX Input 1 Source */
+	{ 0x0978, 0x0000 },  /* R2424  - DSP1AUX6MIX Input 1 Source */
+	{ 0x0980, 0x0000 },  /* R2432  - DSP2LMIX Input 1 Source */
+	{ 0x0981, 0x0080 },  /* R2433  - DSP2LMIX Input 1 Volume */
+	{ 0x0982, 0x0000 },  /* R2434  - DSP2LMIX Input 2 Source */
+	{ 0x0983, 0x0080 },  /* R2435  - DSP2LMIX Input 2 Volume */
+	{ 0x0984, 0x0000 },  /* R2436  - DSP2LMIX Input 3 Source */
+	{ 0x0985, 0x0080 },  /* R2437  - DSP2LMIX Input 3 Volume */
+	{ 0x0986, 0x0000 },  /* R2438  - DSP2LMIX Input 4 Source */
+	{ 0x0987, 0x0080 },  /* R2439  - DSP2LMIX Input 4 Volume */
+	{ 0x0988, 0x0000 },  /* R2440  - DSP2RMIX Input 1 Source */
+	{ 0x0989, 0x0080 },  /* R2441  - DSP2RMIX Input 1 Volume */
+	{ 0x098A, 0x0000 },  /* R2442  - DSP2RMIX Input 2 Source */
+	{ 0x098B, 0x0080 },  /* R2443  - DSP2RMIX Input 2 Volume */
+	{ 0x098C, 0x0000 },  /* R2444  - DSP2RMIX Input 3 Source */
+	{ 0x098D, 0x0080 },  /* R2445  - DSP2RMIX Input 3 Volume */
+	{ 0x098E, 0x0000 },  /* R2446  - DSP2RMIX Input 4 Source */
+	{ 0x098F, 0x0080 },  /* R2447  - DSP2RMIX Input 4 Volume */
+	{ 0x0990, 0x0000 },  /* R2448  - DSP2AUX1MIX Input 1 Source */
+	{ 0x0998, 0x0000 },  /* R2456  - DSP2AUX2MIX Input 1 Source */
+	{ 0x09A0, 0x0000 },  /* R2464  - DSP2AUX3MIX Input 1 Source */
+	{ 0x09A8, 0x0000 },  /* R2472  - DSP2AUX4MIX Input 1 Source */
+	{ 0x09B0, 0x0000 },  /* R2480  - DSP2AUX5MIX Input 1 Source */
+	{ 0x09B8, 0x0000 },  /* R2488  - DSP2AUX6MIX Input 1 Source */
+	{ 0x09C0, 0x0000 },  /* R2496  - DSP3LMIX Input 1 Source */
+	{ 0x09C1, 0x0080 },  /* R2497  - DSP3LMIX Input 1 Volume */
+	{ 0x09C2, 0x0000 },  /* R2498  - DSP3LMIX Input 2 Source */
+	{ 0x09C3, 0x0080 },  /* R2499  - DSP3LMIX Input 2 Volume */
+	{ 0x09C4, 0x0000 },  /* R2500  - DSP3LMIX Input 3 Source */
+	{ 0x09C5, 0x0080 },  /* R2501  - DSP3LMIX Input 3 Volume */
+	{ 0x09C6, 0x0000 },  /* R2502  - DSP3LMIX Input 4 Source */
+	{ 0x09C7, 0x0080 },  /* R2503  - DSP3LMIX Input 4 Volume */
+	{ 0x09C8, 0x0000 },  /* R2504  - DSP3RMIX Input 1 Source */
+	{ 0x09C9, 0x0080 },  /* R2505  - DSP3RMIX Input 1 Volume */
+	{ 0x09CA, 0x0000 },  /* R2506  - DSP3RMIX Input 2 Source */
+	{ 0x09CB, 0x0080 },  /* R2507  - DSP3RMIX Input 2 Volume */
+	{ 0x09CC, 0x0000 },  /* R2508  - DSP3RMIX Input 3 Source */
+	{ 0x09CD, 0x0080 },  /* R2509  - DSP3RMIX Input 3 Volume */
+	{ 0x09CE, 0x0000 },  /* R2510  - DSP3RMIX Input 4 Source */
+	{ 0x09CF, 0x0080 },  /* R2511  - DSP3RMIX Input 4 Volume */
+	{ 0x09D0, 0x0000 },  /* R2512  - DSP3AUX1MIX Input 1 Source */
+	{ 0x09D8, 0x0000 },  /* R2520  - DSP3AUX2MIX Input 1 Source */
+	{ 0x09E0, 0x0000 },  /* R2528  - DSP3AUX3MIX Input 1 Source */
+	{ 0x09E8, 0x0000 },  /* R2536  - DSP3AUX4MIX Input 1 Source */
+	{ 0x09F0, 0x0000 },  /* R2544  - DSP3AUX5MIX Input 1 Source */
+	{ 0x09F8, 0x0000 },  /* R2552  - DSP3AUX6MIX Input 1 Source */
+	{ 0x0A80, 0x0000 },  /* R2688  - ASRC1LMIX Input 1 Source */
+	{ 0x0A88, 0x0000 },  /* R2696  - ASRC1RMIX Input 1 Source */
+	{ 0x0A90, 0x0000 },  /* R2704  - ASRC2LMIX Input 1 Source */
+	{ 0x0A98, 0x0000 },  /* R2712  - ASRC2RMIX Input 1 Source */
+	{ 0x0B00, 0x0000 },  /* R2816  - ISRC1DEC1MIX Input 1 Source */
+	{ 0x0B08, 0x0000 },  /* R2824  - ISRC1DEC2MIX Input 1 Source */
+	{ 0x0B10, 0x0000 },  /* R2832  - ISRC1DEC3MIX Input 1 Source */
+	{ 0x0B18, 0x0000 },  /* R2840  - ISRC1DEC4MIX Input 1 Source */
+	{ 0x0B20, 0x0000 },  /* R2848  - ISRC1INT1MIX Input 1 Source */
+	{ 0x0B28, 0x0000 },  /* R2856  - ISRC1INT2MIX Input 1 Source */
+	{ 0x0B30, 0x0000 },  /* R2864  - ISRC1INT3MIX Input 1 Source */
+	{ 0x0B38, 0x0000 },  /* R2872  - ISRC1INT4MIX Input 1 Source */
+	{ 0x0B40, 0x0000 },  /* R2880  - ISRC2DEC1MIX Input 1 Source */
+	{ 0x0B48, 0x0000 },  /* R2888  - ISRC2DEC2MIX Input 1 Source */
+	{ 0x0B50, 0x0000 },  /* R2896  - ISRC2DEC3MIX Input 1 Source */
+	{ 0x0B58, 0x0000 },  /* R2904  - ISRC2DEC4MIX Input 1 Source */
+	{ 0x0B60, 0x0000 },  /* R2912  - ISRC2INT1MIX Input 1 Source */
+	{ 0x0B68, 0x0000 },  /* R2920  - ISRC2INT2MIX Input 1 Source */
+	{ 0x0B70, 0x0000 },  /* R2928  - ISRC2INT3MIX Input 1 Source */
+	{ 0x0B78, 0x0000 },  /* R2936  - ISRC2INT4MIX Input 1 Source */
+	{ 0x0C00, 0xA001 },  /* R3072  - GPIO CTRL 1 */
+	{ 0x0C01, 0xA001 },  /* R3073  - GPIO CTRL 2 */
+	{ 0x0C02, 0xA001 },  /* R3074  - GPIO CTRL 3 */
+	{ 0x0C03, 0xA001 },  /* R3075  - GPIO CTRL 4 */
+	{ 0x0C04, 0xA001 },  /* R3076  - GPIO CTRL 5 */
+	{ 0x0C05, 0xA001 },  /* R3077  - GPIO CTRL 6 */
+	{ 0x0C23, 0x4003 },  /* R3107  - Misc Pad Ctrl 1 */
+	{ 0x0C24, 0x0000 },  /* R3108  - Misc Pad Ctrl 2 */
+	{ 0x0C25, 0x0000 },  /* R3109  - Misc Pad Ctrl 3 */
+	{ 0x0C26, 0x0000 },  /* R3110  - Misc Pad Ctrl 4 */
+	{ 0x0C27, 0x0000 },  /* R3111  - Misc Pad Ctrl 5 */
+	{ 0x0C28, 0x0000 },  /* R3112  - Misc GPIO 1 */
+	{ 0x0D00, 0x0000 },  /* R3328  - Interrupt Status 1 */
+	{ 0x0D01, 0x0000 },  /* R3329  - Interrupt Status 2 */
+	{ 0x0D02, 0x0000 },  /* R3330  - Interrupt Status 3 */
+	{ 0x0D03, 0x0000 },  /* R3331  - Interrupt Status 4 */
+	{ 0x0D04, 0x0000 },  /* R3332  - Interrupt Raw Status 2 */
+	{ 0x0D05, 0x0000 },  /* R3333  - Interrupt Raw Status 3 */
+	{ 0x0D06, 0x0000 },  /* R3334  - Interrupt Raw Status 4 */
+	{ 0x0D07, 0xFFFF },  /* R3335  - Interrupt Status 1 Mask */
+	{ 0x0D08, 0xFFFF },  /* R3336  - Interrupt Status 2 Mask */
+	{ 0x0D09, 0xFFFF },  /* R3337  - Interrupt Status 3 Mask */
+	{ 0x0D0A, 0xFFFF },  /* R3338  - Interrupt Status 4 Mask */
+	{ 0x0D1F, 0x0000 },  /* R3359  - Interrupt Control */
+	{ 0x0D20, 0xFFFF },  /* R3360  - IRQ Debounce 1 */
+	{ 0x0D21, 0xFFFF },  /* R3361  - IRQ Debounce 2 */
+	{ 0x0E00, 0x0000 },  /* R3584  - FX_Ctrl */
+	{ 0x0E10, 0x6318 },  /* R3600  - EQ1_1 */
+	{ 0x0E11, 0x6300 },  /* R3601  - EQ1_2 */
+	{ 0x0E12, 0x0FC8 },  /* R3602  - EQ1_3 */
+	{ 0x0E13, 0x03FE },  /* R3603  - EQ1_4 */
+	{ 0x0E14, 0x00E0 },  /* R3604  - EQ1_5 */
+	{ 0x0E15, 0x1EC4 },  /* R3605  - EQ1_6 */
+	{ 0x0E16, 0xF136 },  /* R3606  - EQ1_7 */
+	{ 0x0E17, 0x0409 },  /* R3607  - EQ1_8 */
+	{ 0x0E18, 0x04CC },  /* R3608  - EQ1_9 */
+	{ 0x0E19, 0x1C9B },  /* R3609  - EQ1_10 */
+	{ 0x0E1A, 0xF337 },  /* R3610  - EQ1_11 */
+	{ 0x0E1B, 0x040B },  /* R3611  - EQ1_12 */
+	{ 0x0E1C, 0x0CBB },  /* R3612  - EQ1_13 */
+	{ 0x0E1D, 0x16F8 },  /* R3613  - EQ1_14 */
+	{ 0x0E1E, 0xF7D9 },  /* R3614  - EQ1_15 */
+	{ 0x0E1F, 0x040A },  /* R3615  - EQ1_16 */
+	{ 0x0E20, 0x1F14 },  /* R3616  - EQ1_17 */
+	{ 0x0E21, 0x058C },  /* R3617  - EQ1_18 */
+	{ 0x0E22, 0x0563 },  /* R3618  - EQ1_19 */
+	{ 0x0E23, 0x4000 },  /* R3619  - EQ1_20 */
+	{ 0x0E26, 0x6318 },  /* R3622  - EQ2_1 */
+	{ 0x0E27, 0x6300 },  /* R3623  - EQ2_2 */
+	{ 0x0E28, 0x0FC8 },  /* R3624  - EQ2_3 */
+	{ 0x0E29, 0x03FE },  /* R3625  - EQ2_4 */
+	{ 0x0E2A, 0x00E0 },  /* R3626  - EQ2_5 */
+	{ 0x0E2B, 0x1EC4 },  /* R3627  - EQ2_6 */
+	{ 0x0E2C, 0xF136 },  /* R3628  - EQ2_7 */
+	{ 0x0E2D, 0x0409 },  /* R3629  - EQ2_8 */
+	{ 0x0E2E, 0x04CC },  /* R3630  - EQ2_9 */
+	{ 0x0E2F, 0x1C9B },  /* R3631  - EQ2_10 */
+	{ 0x0E30, 0xF337 },  /* R3632  - EQ2_11 */
+	{ 0x0E31, 0x040B },  /* R3633  - EQ2_12 */
+	{ 0x0E32, 0x0CBB },  /* R3634  - EQ2_13 */
+	{ 0x0E33, 0x16F8 },  /* R3635  - EQ2_14 */
+	{ 0x0E34, 0xF7D9 },  /* R3636  - EQ2_15 */
+	{ 0x0E35, 0x040A },  /* R3637  - EQ2_16 */
+	{ 0x0E36, 0x1F14 },  /* R3638  - EQ2_17 */
+	{ 0x0E37, 0x058C },  /* R3639  - EQ2_18 */
+	{ 0x0E38, 0x0563 },  /* R3640  - EQ2_19 */
+	{ 0x0E39, 0x4000 },  /* R3641  - EQ2_20 */
+	{ 0x0E3C, 0x6318 },  /* R3644  - EQ3_1 */
+	{ 0x0E3D, 0x6300 },  /* R3645  - EQ3_2 */
+	{ 0x0E3E, 0x0FC8 },  /* R3646  - EQ3_3 */
+	{ 0x0E3F, 0x03FE },  /* R3647  - EQ3_4 */
+	{ 0x0E40, 0x00E0 },  /* R3648  - EQ3_5 */
+	{ 0x0E41, 0x1EC4 },  /* R3649  - EQ3_6 */
+	{ 0x0E42, 0xF136 },  /* R3650  - EQ3_7 */
+	{ 0x0E43, 0x0409 },  /* R3651  - EQ3_8 */
+	{ 0x0E44, 0x04CC },  /* R3652  - EQ3_9 */
+	{ 0x0E45, 0x1C9B },  /* R3653  - EQ3_10 */
+	{ 0x0E46, 0xF337 },  /* R3654  - EQ3_11 */
+	{ 0x0E47, 0x040B },  /* R3655  - EQ3_12 */
+	{ 0x0E48, 0x0CBB },  /* R3656  - EQ3_13 */
+	{ 0x0E49, 0x16F8 },  /* R3657  - EQ3_14 */
+	{ 0x0E4A, 0xF7D9 },  /* R3658  - EQ3_15 */
+	{ 0x0E4B, 0x040A },  /* R3659  - EQ3_16 */
+	{ 0x0E4C, 0x1F14 },  /* R3660  - EQ3_17 */
+	{ 0x0E4D, 0x058C },  /* R3661  - EQ3_18 */
+	{ 0x0E4E, 0x0563 },  /* R3662  - EQ3_19 */
+	{ 0x0E4F, 0x4000 },  /* R3663  - EQ3_20 */
+	{ 0x0E52, 0x6318 },  /* R3666  - EQ4_1 */
+	{ 0x0E53, 0x6300 },  /* R3667  - EQ4_2 */
+	{ 0x0E54, 0x0FC8 },  /* R3668  - EQ4_3 */
+	{ 0x0E55, 0x03FE },  /* R3669  - EQ4_4 */
+	{ 0x0E56, 0x00E0 },  /* R3670  - EQ4_5 */
+	{ 0x0E57, 0x1EC4 },  /* R3671  - EQ4_6 */
+	{ 0x0E58, 0xF136 },  /* R3672  - EQ4_7 */
+	{ 0x0E59, 0x0409 },  /* R3673  - EQ4_8 */
+	{ 0x0E5A, 0x04CC },  /* R3674  - EQ4_9 */
+	{ 0x0E5B, 0x1C9B },  /* R3675  - EQ4_10 */
+	{ 0x0E5C, 0xF337 },  /* R3676  - EQ4_11 */
+	{ 0x0E5D, 0x040B },  /* R3677  - EQ4_12 */
+	{ 0x0E5E, 0x0CBB },  /* R3678  - EQ4_13 */
+	{ 0x0E5F, 0x16F8 },  /* R3679  - EQ4_14 */
+	{ 0x0E60, 0xF7D9 },  /* R3680  - EQ4_15 */
+	{ 0x0E61, 0x040A },  /* R3681  - EQ4_16 */
+	{ 0x0E62, 0x1F14 },  /* R3682  - EQ4_17 */
+	{ 0x0E63, 0x058C },  /* R3683  - EQ4_18 */
+	{ 0x0E64, 0x0563 },  /* R3684  - EQ4_19 */
+	{ 0x0E65, 0x4000 },  /* R3685  - EQ4_20 */
+	{ 0x0E80, 0x0018 },  /* R3712  - DRC1 ctrl1 */
+	{ 0x0E81, 0x0933 },  /* R3713  - DRC1 ctrl2 */
+	{ 0x0E82, 0x0018 },  /* R3714  - DRC1 ctrl3 */
+	{ 0x0E83, 0x0000 },  /* R3715  - DRC1 ctrl4 */
+	{ 0x0E84, 0x0000 },  /* R3716  - DRC1 ctrl5 */
+	{ 0x0EC0, 0x0000 },  /* R3776  - HPLPF1_1 */
+	{ 0x0EC1, 0x0000 },  /* R3777  - HPLPF1_2 */
+	{ 0x0EC4, 0x0000 },  /* R3780  - HPLPF2_1 */
+	{ 0x0EC5, 0x0000 },  /* R3781  - HPLPF2_2 */
+	{ 0x0EC8, 0x0000 },  /* R3784  - HPLPF3_1 */
+	{ 0x0EC9, 0x0000 },  /* R3785  - HPLPF3_2 */
+	{ 0x0ECC, 0x0000 },  /* R3788  - HPLPF4_1 */
+	{ 0x0ECD, 0x0000 },  /* R3789  - HPLPF4_2 */
+	{ 0x0F02, 0x0000 },  /* R3842  - DSP1 Control 2 */
+	{ 0x0F03, 0x0000 },  /* R3843  - DSP1 Control 3 */
+	{ 0x0F04, 0x0000 },  /* R3844  - DSP1 Control 4 */
+	{ 0x1002, 0x0000 },  /* R4098  - DSP2 Control 2 */
+	{ 0x1003, 0x0000 },  /* R4099  - DSP2 Control 3 */
+	{ 0x1004, 0x0000 },  /* R4100  - DSP2 Control 4 */
+	{ 0x1102, 0x0000 },  /* R4354  - DSP3 Control 2 */
+	{ 0x1103, 0x0000 },  /* R4355  - DSP3 Control 3 */
+	{ 0x1104, 0x0000 },  /* R4356  - DSP3 Control 4 */
+};
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
new file mode 100644
index 0000000..ba89d9d
--- /dev/null
+++ b/sound/soc/codecs/wm5100.c
@@ -0,0 +1,2726 @@
+/*
+ * wm5100.c  --  WM5100 ALSA SoC Audio driver
+ *
+ * Copyright 2011-2 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/fixed.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/wm5100.h>
+
+#include "wm5100.h"
+
+#define WM5100_NUM_CORE_SUPPLIES 2
+static const char *wm5100_core_supply_names[WM5100_NUM_CORE_SUPPLIES] = {
+	"DBVDD1",
+	"LDOVDD", /* If DCVDD is supplied externally specify as LDOVDD */
+};
+
+#define WM5100_AIFS     3
+#define WM5100_SYNC_SRS 3
+
+struct wm5100_fll {
+	int fref;
+	int fout;
+	int src;
+	struct completion lock;
+};
+
+/* codec private data */
+struct wm5100_priv {
+	struct device *dev;
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+
+	struct regulator_bulk_data core_supplies[WM5100_NUM_CORE_SUPPLIES];
+
+	int rev;
+
+	int sysclk;
+	int asyncclk;
+
+	bool aif_async[WM5100_AIFS];
+	bool aif_symmetric[WM5100_AIFS];
+	int sr_ref[WM5100_SYNC_SRS];
+
+	bool out_ena[2];
+
+	struct snd_soc_jack *jack;
+	bool jack_detecting;
+	bool jack_mic;
+	int jack_mode;
+	int jack_flips;
+
+	struct wm5100_fll fll[2];
+
+	struct wm5100_pdata pdata;
+
+#ifdef CONFIG_GPIOLIB
+	struct gpio_chip gpio_chip;
+#endif
+};
+
+static int wm5100_sr_code[] = {
+	0,
+	12000,
+	24000,
+	48000,
+	96000,
+	192000,
+	384000,
+	768000,
+	0,
+	11025,
+	22050,
+	44100,
+	88200,
+	176400,
+	352800,
+	705600,
+	4000,
+	8000,
+	16000,
+	32000,
+	64000,
+	128000,
+	256000,
+	512000,
+};
+
+static int wm5100_sr_regs[WM5100_SYNC_SRS] = {
+	WM5100_CLOCKING_4,
+	WM5100_CLOCKING_5,
+	WM5100_CLOCKING_6,
+};
+
+static int wm5100_alloc_sr(struct snd_soc_component *component, int rate)
+{
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
+	int sr_code, sr_free, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm5100_sr_code); i++)
+		if (wm5100_sr_code[i] == rate)
+			break;
+	if (i == ARRAY_SIZE(wm5100_sr_code)) {
+		dev_err(component->dev, "Unsupported sample rate: %dHz\n", rate);
+		return -EINVAL;
+	}
+	sr_code = i;
+
+	if ((wm5100->sysclk % rate) == 0) {
+		/* Is this rate already in use? */
+		sr_free = -1;
+		for (i = 0; i < ARRAY_SIZE(wm5100_sr_regs); i++) {
+			if (!wm5100->sr_ref[i] && sr_free == -1) {
+				sr_free = i;
+				continue;
+			}
+			if ((snd_soc_component_read32(component, wm5100_sr_regs[i]) &
+			     WM5100_SAMPLE_RATE_1_MASK) == sr_code)
+				break;
+		}
+
+		if (i < ARRAY_SIZE(wm5100_sr_regs)) {
+			wm5100->sr_ref[i]++;
+			dev_dbg(component->dev, "SR %dHz, slot %d, ref %d\n",
+				rate, i, wm5100->sr_ref[i]);
+			return i;
+		}
+
+		if (sr_free == -1) {
+			dev_err(component->dev, "All SR slots already in use\n");
+			return -EBUSY;
+		}
+
+		dev_dbg(component->dev, "Allocating SR slot %d for %dHz\n",
+			sr_free, rate);
+		wm5100->sr_ref[sr_free]++;
+		snd_soc_component_update_bits(component, wm5100_sr_regs[sr_free],
+				    WM5100_SAMPLE_RATE_1_MASK,
+				    sr_code);
+
+		return sr_free;
+
+	} else {
+		dev_err(component->dev,
+			"SR %dHz incompatible with %dHz SYSCLK and %dHz ASYNCCLK\n",
+			rate, wm5100->sysclk, wm5100->asyncclk);
+		return -EINVAL;
+	}
+}
+
+static void wm5100_free_sr(struct snd_soc_component *component, int rate)
+{
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
+	int i, sr_code;
+
+	for (i = 0; i < ARRAY_SIZE(wm5100_sr_code); i++)
+		if (wm5100_sr_code[i] == rate)
+			break;
+	if (i == ARRAY_SIZE(wm5100_sr_code)) {
+		dev_err(component->dev, "Unsupported sample rate: %dHz\n", rate);
+		return;
+	}
+	sr_code = wm5100_sr_code[i];
+
+	for (i = 0; i < ARRAY_SIZE(wm5100_sr_regs); i++) {
+		if (!wm5100->sr_ref[i])
+			continue;
+
+		if ((snd_soc_component_read32(component, wm5100_sr_regs[i]) &
+		     WM5100_SAMPLE_RATE_1_MASK) == sr_code)
+			break;
+	}
+	if (i < ARRAY_SIZE(wm5100_sr_regs)) {
+		wm5100->sr_ref[i]--;
+		dev_dbg(component->dev, "Dereference SR %dHz, count now %d\n",
+			rate, wm5100->sr_ref[i]);
+	} else {
+		dev_warn(component->dev, "Freeing unreferenced sample rate %dHz\n",
+			 rate);
+	}
+}
+
+static int wm5100_reset(struct wm5100_priv *wm5100)
+{
+	if (wm5100->pdata.reset) {
+		gpio_set_value_cansleep(wm5100->pdata.reset, 0);
+		gpio_set_value_cansleep(wm5100->pdata.reset, 1);
+
+		return 0;
+	} else {
+		return regmap_write(wm5100->regmap, WM5100_SOFTWARE_RESET, 0);
+	}
+}
+
+static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0);
+static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(mixer_tlv, -3200, 100, 0);
+static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+
+static const char *wm5100_mixer_texts[] = {
+	"None",
+	"Tone Generator 1",
+	"Tone Generator 2",
+	"AEC loopback",
+	"IN1L",
+	"IN1R",
+	"IN2L",
+	"IN2R",
+	"IN3L",
+	"IN3R",
+	"IN4L",
+	"IN4R",
+	"AIF1RX1",
+	"AIF1RX2",
+	"AIF1RX3",
+	"AIF1RX4",
+	"AIF1RX5",
+	"AIF1RX6",
+	"AIF1RX7",
+	"AIF1RX8",
+	"AIF2RX1",
+	"AIF2RX2",
+	"AIF3RX1",
+	"AIF3RX2",
+	"EQ1",
+	"EQ2",
+	"EQ3",
+	"EQ4",
+	"DRC1L",
+	"DRC1R",
+	"LHPF1",
+	"LHPF2",
+	"LHPF3",
+	"LHPF4",
+	"DSP1.1",
+	"DSP1.2",
+	"DSP1.3",
+	"DSP1.4",
+	"DSP1.5",
+	"DSP1.6",
+	"DSP2.1",
+	"DSP2.2",
+	"DSP2.3",
+	"DSP2.4",
+	"DSP2.5",
+	"DSP2.6",
+	"DSP3.1",
+	"DSP3.2",
+	"DSP3.3",
+	"DSP3.4",
+	"DSP3.5",
+	"DSP3.6",
+	"ASRC1L",
+	"ASRC1R",
+	"ASRC2L",
+	"ASRC2R",
+	"ISRC1INT1",
+	"ISRC1INT2",
+	"ISRC1INT3",
+	"ISRC1INT4",
+	"ISRC2INT1",
+	"ISRC2INT2",
+	"ISRC2INT3",
+	"ISRC2INT4",
+	"ISRC1DEC1",
+	"ISRC1DEC2",
+	"ISRC1DEC3",
+	"ISRC1DEC4",
+	"ISRC2DEC1",
+	"ISRC2DEC2",
+	"ISRC2DEC3",
+	"ISRC2DEC4",
+};
+
+static int wm5100_mixer_values[] = {
+	0x00,
+	0x04,   /* Tone */
+	0x05,
+	0x08,   /* AEC */
+	0x10,   /* Input */
+	0x11,
+	0x12,
+	0x13,
+	0x14,
+	0x15,
+	0x16,
+	0x17,
+	0x20,   /* AIF */
+	0x21,
+	0x22,
+	0x23,
+	0x24,
+	0x25,
+	0x26,
+	0x27,
+	0x28,
+	0x29,
+	0x30,   /* AIF3 - check */
+	0x31,
+	0x50,   /* EQ */
+	0x51,
+	0x52,
+	0x53,
+	0x54,
+	0x58,   /* DRC */
+	0x59,
+	0x60,   /* LHPF1 */
+	0x61,   /* LHPF2 */
+	0x62,   /* LHPF3 */
+	0x63,   /* LHPF4 */
+	0x68,   /* DSP1 */
+	0x69,
+	0x6a,
+	0x6b,
+	0x6c,
+	0x6d,
+	0x70,   /* DSP2 */
+	0x71,
+	0x72,
+	0x73,
+	0x74,
+	0x75,
+	0x78,   /* DSP3 */
+	0x79,
+	0x7a,
+	0x7b,
+	0x7c,
+	0x7d,
+	0x90,   /* ASRC1 */
+	0x91,
+	0x92,   /* ASRC2 */
+	0x93,
+	0xa0,   /* ISRC1DEC1 */
+	0xa1,
+	0xa2,
+	0xa3,
+	0xa4,   /* ISRC1INT1 */
+	0xa5,
+	0xa6,
+	0xa7,
+	0xa8,   /* ISRC2DEC1 */
+	0xa9,
+	0xaa,
+	0xab,
+	0xac,   /* ISRC2INT1 */
+	0xad,
+	0xae,
+	0xaf,
+};
+
+#define WM5100_MIXER_CONTROLS(name, base) \
+	SOC_SINGLE_TLV(name " Input 1 Volume", base + 1 , \
+		       WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+	SOC_SINGLE_TLV(name " Input 2 Volume", base + 3 , \
+		       WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+	SOC_SINGLE_TLV(name " Input 3 Volume", base + 5 , \
+		       WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
+	SOC_SINGLE_TLV(name " Input 4 Volume", base + 7 , \
+		       WM5100_MIXER_VOL_SHIFT, 80, 0, mixer_tlv)
+
+#define WM5100_MUX_ENUM_DECL(name, reg) \
+	SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, 			\
+				   wm5100_mixer_texts, wm5100_mixer_values)
+
+#define WM5100_MUX_CTL_DECL(name) \
+	const struct snd_kcontrol_new name##_mux =	\
+		SOC_DAPM_ENUM("Route", name##_enum)
+
+#define WM5100_MIXER_ENUMS(name, base_reg) \
+	static WM5100_MUX_ENUM_DECL(name##_in1_enum, base_reg);	     \
+	static WM5100_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2);  \
+	static WM5100_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4);  \
+	static WM5100_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6);  \
+	static WM5100_MUX_CTL_DECL(name##_in1); \
+	static WM5100_MUX_CTL_DECL(name##_in2); \
+	static WM5100_MUX_CTL_DECL(name##_in3); \
+	static WM5100_MUX_CTL_DECL(name##_in4) 
+
+WM5100_MIXER_ENUMS(HPOUT1L, WM5100_OUT1LMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(HPOUT1R, WM5100_OUT1RMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(HPOUT2L, WM5100_OUT2LMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(HPOUT2R, WM5100_OUT2RMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(HPOUT3L, WM5100_OUT3LMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(HPOUT3R, WM5100_OUT3RMIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(SPKOUTL, WM5100_OUT4LMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(SPKOUTR, WM5100_OUT4RMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(SPKDAT1L, WM5100_OUT5LMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(SPKDAT1R, WM5100_OUT5RMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(SPKDAT2L, WM5100_OUT6LMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(SPKDAT2R, WM5100_OUT6RMIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(PWM1, WM5100_PWM1MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(PWM2, WM5100_PWM1MIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(AIF1TX1, WM5100_AIF1TX1MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF1TX2, WM5100_AIF1TX2MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF1TX3, WM5100_AIF1TX3MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF1TX4, WM5100_AIF1TX4MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF1TX5, WM5100_AIF1TX5MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF1TX6, WM5100_AIF1TX6MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF1TX7, WM5100_AIF1TX7MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF1TX8, WM5100_AIF1TX8MIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(AIF2TX1, WM5100_AIF2TX1MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF2TX2, WM5100_AIF2TX2MIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(AIF3TX1, WM5100_AIF1TX1MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(AIF3TX2, WM5100_AIF1TX2MIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(EQ1, WM5100_EQ1MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(EQ2, WM5100_EQ2MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(EQ3, WM5100_EQ3MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(EQ4, WM5100_EQ4MIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(DRC1L, WM5100_DRC1LMIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(DRC1R, WM5100_DRC1RMIX_INPUT_1_SOURCE);
+
+WM5100_MIXER_ENUMS(LHPF1, WM5100_HPLP1MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(LHPF2, WM5100_HPLP2MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(LHPF3, WM5100_HPLP3MIX_INPUT_1_SOURCE);
+WM5100_MIXER_ENUMS(LHPF4, WM5100_HPLP4MIX_INPUT_1_SOURCE);
+
+#define WM5100_MUX(name, ctrl) \
+	SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
+
+#define WM5100_MIXER_WIDGETS(name, name_str)	\
+	WM5100_MUX(name_str " Input 1", &name##_in1_mux), \
+	WM5100_MUX(name_str " Input 2", &name##_in2_mux), \
+	WM5100_MUX(name_str " Input 3", &name##_in3_mux), \
+	WM5100_MUX(name_str " Input 4", &name##_in4_mux), \
+	SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
+
+#define WM5100_MIXER_INPUT_ROUTES(name)	\
+	{ name, "Tone Generator 1", "Tone Generator 1" }, \
+        { name, "Tone Generator 2", "Tone Generator 2" }, \
+        { name, "IN1L", "IN1L PGA" }, \
+        { name, "IN1R", "IN1R PGA" }, \
+        { name, "IN2L", "IN2L PGA" }, \
+        { name, "IN2R", "IN2R PGA" }, \
+        { name, "IN3L", "IN3L PGA" }, \
+        { name, "IN3R", "IN3R PGA" }, \
+        { name, "IN4L", "IN4L PGA" }, \
+        { name, "IN4R", "IN4R PGA" }, \
+        { name, "AIF1RX1", "AIF1RX1" }, \
+        { name, "AIF1RX2", "AIF1RX2" }, \
+        { name, "AIF1RX3", "AIF1RX3" }, \
+        { name, "AIF1RX4", "AIF1RX4" }, \
+        { name, "AIF1RX5", "AIF1RX5" }, \
+        { name, "AIF1RX6", "AIF1RX6" }, \
+        { name, "AIF1RX7", "AIF1RX7" }, \
+        { name, "AIF1RX8", "AIF1RX8" }, \
+        { name, "AIF2RX1", "AIF2RX1" }, \
+        { name, "AIF2RX2", "AIF2RX2" }, \
+        { name, "AIF3RX1", "AIF3RX1" }, \
+        { name, "AIF3RX2", "AIF3RX2" }, \
+        { name, "EQ1", "EQ1" }, \
+        { name, "EQ2", "EQ2" }, \
+        { name, "EQ3", "EQ3" }, \
+        { name, "EQ4", "EQ4" }, \
+        { name, "DRC1L", "DRC1L" }, \
+        { name, "DRC1R", "DRC1R" }, \
+        { name, "LHPF1", "LHPF1" }, \
+        { name, "LHPF2", "LHPF2" }, \
+        { name, "LHPF3", "LHPF3" }, \
+        { name, "LHPF4", "LHPF4" }
+
+#define WM5100_MIXER_ROUTES(widget, name) \
+	{ widget, NULL, name " Mixer" },         \
+	{ name " Mixer", NULL, name " Input 1" }, \
+	{ name " Mixer", NULL, name " Input 2" }, \
+	{ name " Mixer", NULL, name " Input 3" }, \
+	{ name " Mixer", NULL, name " Input 4" }, \
+	WM5100_MIXER_INPUT_ROUTES(name " Input 1"), \
+	WM5100_MIXER_INPUT_ROUTES(name " Input 2"), \
+	WM5100_MIXER_INPUT_ROUTES(name " Input 3"), \
+	WM5100_MIXER_INPUT_ROUTES(name " Input 4")
+
+static const char *wm5100_lhpf_mode_text[] = {
+	"Low-pass", "High-pass"
+};
+
+static SOC_ENUM_SINGLE_DECL(wm5100_lhpf1_mode,
+			    WM5100_HPLPF1_1, WM5100_LHPF1_MODE_SHIFT,
+			    wm5100_lhpf_mode_text);
+
+static SOC_ENUM_SINGLE_DECL(wm5100_lhpf2_mode,
+			    WM5100_HPLPF2_1, WM5100_LHPF2_MODE_SHIFT,
+			    wm5100_lhpf_mode_text);
+
+static SOC_ENUM_SINGLE_DECL(wm5100_lhpf3_mode,
+			    WM5100_HPLPF3_1, WM5100_LHPF3_MODE_SHIFT,
+			    wm5100_lhpf_mode_text);
+
+static SOC_ENUM_SINGLE_DECL(wm5100_lhpf4_mode,
+			    WM5100_HPLPF4_1, WM5100_LHPF4_MODE_SHIFT,
+			    wm5100_lhpf_mode_text);
+
+static const struct snd_kcontrol_new wm5100_snd_controls[] = {
+SOC_SINGLE("IN1 High Performance Switch", WM5100_IN1L_CONTROL,
+	   WM5100_IN1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN2 High Performance Switch", WM5100_IN2L_CONTROL,
+	   WM5100_IN2_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN3 High Performance Switch", WM5100_IN3L_CONTROL,
+	   WM5100_IN3_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN4 High Performance Switch", WM5100_IN4L_CONTROL,
+	   WM5100_IN4_OSR_SHIFT, 1, 0),
+
+/* Only applicable for analogue inputs */
+SOC_DOUBLE_R_TLV("IN1 Volume", WM5100_IN1L_CONTROL, WM5100_IN1R_CONTROL,
+		 WM5100_IN1L_PGA_VOL_SHIFT, 94, 0, in_tlv),
+SOC_DOUBLE_R_TLV("IN2 Volume", WM5100_IN2L_CONTROL, WM5100_IN2R_CONTROL,
+		 WM5100_IN2L_PGA_VOL_SHIFT, 94, 0, in_tlv),
+SOC_DOUBLE_R_TLV("IN3 Volume", WM5100_IN3L_CONTROL, WM5100_IN3R_CONTROL,
+		 WM5100_IN3L_PGA_VOL_SHIFT, 94, 0, in_tlv),
+SOC_DOUBLE_R_TLV("IN4 Volume", WM5100_IN4L_CONTROL, WM5100_IN4R_CONTROL,
+		 WM5100_IN4L_PGA_VOL_SHIFT, 94, 0, in_tlv),
+
+SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_1L,
+		 WM5100_ADC_DIGITAL_VOLUME_1R, WM5100_IN1L_VOL_SHIFT, 191,
+		 0, digital_tlv),
+SOC_DOUBLE_R_TLV("IN2 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_2L,
+		 WM5100_ADC_DIGITAL_VOLUME_2R, WM5100_IN2L_VOL_SHIFT, 191,
+		 0, digital_tlv),
+SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_3L,
+		 WM5100_ADC_DIGITAL_VOLUME_3R, WM5100_IN3L_VOL_SHIFT, 191,
+		 0, digital_tlv),
+SOC_DOUBLE_R_TLV("IN4 Digital Volume", WM5100_ADC_DIGITAL_VOLUME_4L,
+		 WM5100_ADC_DIGITAL_VOLUME_4R, WM5100_IN4L_VOL_SHIFT, 191,
+		 0, digital_tlv),
+
+SOC_DOUBLE_R("IN1 Switch", WM5100_ADC_DIGITAL_VOLUME_1L,
+	     WM5100_ADC_DIGITAL_VOLUME_1R, WM5100_IN1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("IN2 Switch", WM5100_ADC_DIGITAL_VOLUME_2L,
+	     WM5100_ADC_DIGITAL_VOLUME_2R, WM5100_IN2L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("IN3 Switch", WM5100_ADC_DIGITAL_VOLUME_3L,
+	     WM5100_ADC_DIGITAL_VOLUME_3R, WM5100_IN3L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("IN4 Switch", WM5100_ADC_DIGITAL_VOLUME_4L,
+	     WM5100_ADC_DIGITAL_VOLUME_4R, WM5100_IN4L_MUTE_SHIFT, 1, 1),
+
+SND_SOC_BYTES_MASK("EQ1 Coefficients", WM5100_EQ1_1, 20, WM5100_EQ1_ENA),
+SND_SOC_BYTES_MASK("EQ2 Coefficients", WM5100_EQ2_1, 20, WM5100_EQ2_ENA),
+SND_SOC_BYTES_MASK("EQ3 Coefficients", WM5100_EQ3_1, 20, WM5100_EQ3_ENA),
+SND_SOC_BYTES_MASK("EQ4 Coefficients", WM5100_EQ4_1, 20, WM5100_EQ4_ENA),
+
+SND_SOC_BYTES_MASK("DRC Coefficients", WM5100_DRC1_CTRL1, 5,
+		   WM5100_DRCL_ENA | WM5100_DRCR_ENA),
+
+SND_SOC_BYTES("LHPF1 Coefficients", WM5100_HPLPF1_2, 1),
+SND_SOC_BYTES("LHPF2 Coefficients", WM5100_HPLPF2_2, 1),
+SND_SOC_BYTES("LHPF3 Coefficients", WM5100_HPLPF3_2, 1),
+SND_SOC_BYTES("LHPF4 Coefficients", WM5100_HPLPF4_2, 1),
+
+SOC_SINGLE("HPOUT1 High Performance Switch", WM5100_OUT_VOLUME_1L,
+	   WM5100_OUT1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("HPOUT2 High Performance Switch", WM5100_OUT_VOLUME_2L,
+	   WM5100_OUT2_OSR_SHIFT, 1, 0),
+SOC_SINGLE("HPOUT3 High Performance Switch", WM5100_OUT_VOLUME_3L,
+	   WM5100_OUT3_OSR_SHIFT, 1, 0),
+SOC_SINGLE("SPKOUT High Performance Switch", WM5100_OUT_VOLUME_4L,
+	   WM5100_OUT4_OSR_SHIFT, 1, 0),
+SOC_SINGLE("SPKDAT1 High Performance Switch", WM5100_DAC_VOLUME_LIMIT_5L,
+	   WM5100_OUT5_OSR_SHIFT, 1, 0),
+SOC_SINGLE("SPKDAT2 High Performance Switch", WM5100_DAC_VOLUME_LIMIT_6L,
+	   WM5100_OUT6_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_1L,
+		 WM5100_DAC_DIGITAL_VOLUME_1R, WM5100_OUT1L_VOL_SHIFT, 159, 0,
+		 digital_tlv),
+SOC_DOUBLE_R_TLV("HPOUT2 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_2L,
+		 WM5100_DAC_DIGITAL_VOLUME_2R, WM5100_OUT2L_VOL_SHIFT, 159, 0,
+		 digital_tlv),
+SOC_DOUBLE_R_TLV("HPOUT3 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_3L,
+		 WM5100_DAC_DIGITAL_VOLUME_3R, WM5100_OUT3L_VOL_SHIFT, 159, 0,
+		 digital_tlv),
+SOC_DOUBLE_R_TLV("SPKOUT Digital Volume", WM5100_DAC_DIGITAL_VOLUME_4L,
+		 WM5100_DAC_DIGITAL_VOLUME_4R, WM5100_OUT4L_VOL_SHIFT, 159, 0,
+		 digital_tlv),
+SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_5L,
+		 WM5100_DAC_DIGITAL_VOLUME_5R, WM5100_OUT5L_VOL_SHIFT, 159, 0,
+		 digital_tlv),
+SOC_DOUBLE_R_TLV("SPKDAT2 Digital Volume", WM5100_DAC_DIGITAL_VOLUME_6L,
+		 WM5100_DAC_DIGITAL_VOLUME_6R, WM5100_OUT6L_VOL_SHIFT, 159, 0,
+		 digital_tlv),
+
+SOC_DOUBLE_R("HPOUT1 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_1L,
+	     WM5100_DAC_DIGITAL_VOLUME_1R, WM5100_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("HPOUT2 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_2L,
+	     WM5100_DAC_DIGITAL_VOLUME_2R, WM5100_OUT2L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("HPOUT3 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_3L,
+	     WM5100_DAC_DIGITAL_VOLUME_3R, WM5100_OUT3L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKOUT Digital Switch", WM5100_DAC_DIGITAL_VOLUME_4L,
+	     WM5100_DAC_DIGITAL_VOLUME_4R, WM5100_OUT4L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKDAT1 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_5L,
+	     WM5100_DAC_DIGITAL_VOLUME_5R, WM5100_OUT5L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKDAT2 Digital Switch", WM5100_DAC_DIGITAL_VOLUME_6L,
+	     WM5100_DAC_DIGITAL_VOLUME_6R, WM5100_OUT6L_MUTE_SHIFT, 1, 1),
+
+/* FIXME: Only valid from -12dB to 0dB (52-64) */
+SOC_DOUBLE_R_TLV("HPOUT1 Volume", WM5100_OUT_VOLUME_1L, WM5100_OUT_VOLUME_1R,
+		 WM5100_OUT1L_PGA_VOL_SHIFT, 64, 0, out_tlv),
+SOC_DOUBLE_R_TLV("HPOUT2 Volume", WM5100_OUT_VOLUME_2L, WM5100_OUT_VOLUME_2R,
+		 WM5100_OUT2L_PGA_VOL_SHIFT, 64, 0, out_tlv),
+SOC_DOUBLE_R_TLV("HPOUT3 Volume", WM5100_OUT_VOLUME_3L, WM5100_OUT_VOLUME_3R,
+		 WM5100_OUT2L_PGA_VOL_SHIFT, 64, 0, out_tlv),
+
+SOC_DOUBLE("SPKDAT1 Switch", WM5100_PDM_SPK1_CTRL_1, WM5100_SPK1L_MUTE_SHIFT,
+	   WM5100_SPK1R_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE("SPKDAT2 Switch", WM5100_PDM_SPK2_CTRL_1, WM5100_SPK2L_MUTE_SHIFT,
+	   WM5100_SPK2R_MUTE_SHIFT, 1, 1),
+
+SOC_SINGLE_TLV("EQ1 Band 1 Volume", WM5100_EQ1_1, WM5100_EQ1_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 Band 2 Volume", WM5100_EQ1_1, WM5100_EQ1_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 Band 3 Volume", WM5100_EQ1_1, WM5100_EQ1_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 Band 4 Volume", WM5100_EQ1_2, WM5100_EQ1_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 Band 5 Volume", WM5100_EQ1_2, WM5100_EQ1_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ2 Band 1 Volume", WM5100_EQ2_1, WM5100_EQ2_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Band 2 Volume", WM5100_EQ2_1, WM5100_EQ2_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Band 3 Volume", WM5100_EQ2_1, WM5100_EQ2_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Band 4 Volume", WM5100_EQ2_2, WM5100_EQ2_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Band 5 Volume", WM5100_EQ2_2, WM5100_EQ2_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ3 Band 1 Volume", WM5100_EQ1_1, WM5100_EQ3_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Band 2 Volume", WM5100_EQ3_1, WM5100_EQ3_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Band 3 Volume", WM5100_EQ3_1, WM5100_EQ3_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Band 4 Volume", WM5100_EQ3_2, WM5100_EQ3_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Band 5 Volume", WM5100_EQ3_2, WM5100_EQ3_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ4 Band 1 Volume", WM5100_EQ4_1, WM5100_EQ4_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Band 2 Volume", WM5100_EQ4_1, WM5100_EQ4_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Band 3 Volume", WM5100_EQ4_1, WM5100_EQ4_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Band 4 Volume", WM5100_EQ4_2, WM5100_EQ4_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Band 5 Volume", WM5100_EQ4_2, WM5100_EQ4_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+SOC_ENUM("LHPF1 Mode", wm5100_lhpf1_mode),
+SOC_ENUM("LHPF2 Mode", wm5100_lhpf2_mode),
+SOC_ENUM("LHPF3 Mode", wm5100_lhpf3_mode),
+SOC_ENUM("LHPF4 Mode", wm5100_lhpf4_mode),
+
+WM5100_MIXER_CONTROLS("HPOUT1L", WM5100_OUT1LMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("HPOUT1R", WM5100_OUT1RMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("HPOUT2L", WM5100_OUT2LMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("HPOUT2R", WM5100_OUT2RMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("HPOUT3L", WM5100_OUT3LMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("HPOUT3R", WM5100_OUT3RMIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("SPKOUTL", WM5100_OUT4LMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("SPKOUTR", WM5100_OUT4RMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("SPKDAT1L", WM5100_OUT5LMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("SPKDAT1R", WM5100_OUT5RMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("SPKDAT2L", WM5100_OUT6LMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("SPKDAT2R", WM5100_OUT6RMIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("PWM1", WM5100_PWM1MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("PWM2", WM5100_PWM2MIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("AIF1TX1", WM5100_AIF1TX1MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF1TX2", WM5100_AIF1TX2MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF1TX3", WM5100_AIF1TX3MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF1TX4", WM5100_AIF1TX4MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF1TX5", WM5100_AIF1TX5MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF1TX6", WM5100_AIF1TX6MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF1TX7", WM5100_AIF1TX7MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF1TX8", WM5100_AIF1TX8MIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("AIF2TX1", WM5100_AIF2TX1MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF2TX2", WM5100_AIF2TX2MIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("AIF3TX1", WM5100_AIF3TX1MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("AIF3TX2", WM5100_AIF3TX2MIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("EQ1", WM5100_EQ1MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("EQ2", WM5100_EQ2MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("EQ3", WM5100_EQ3MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("EQ4", WM5100_EQ4MIX_INPUT_1_SOURCE),
+
+WM5100_MIXER_CONTROLS("DRC1L", WM5100_DRC1LMIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("DRC1R", WM5100_DRC1RMIX_INPUT_1_SOURCE),
+SND_SOC_BYTES_MASK("DRC", WM5100_DRC1_CTRL1, 5,
+		   WM5100_DRCL_ENA | WM5100_DRCR_ENA),
+
+WM5100_MIXER_CONTROLS("LHPF1", WM5100_HPLP1MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("LHPF2", WM5100_HPLP2MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("LHPF3", WM5100_HPLP3MIX_INPUT_1_SOURCE),
+WM5100_MIXER_CONTROLS("LHPF4", WM5100_HPLP4MIX_INPUT_1_SOURCE),
+};
+
+static void wm5100_seq_notifier(struct snd_soc_component *component,
+				enum snd_soc_dapm_type event, int subseq)
+{
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
+	u16 val, expect, i;
+
+	/* Wait for the outputs to flag themselves as enabled */
+	if (wm5100->out_ena[0]) {
+		expect = snd_soc_component_read32(component, WM5100_CHANNEL_ENABLES_1);
+		for (i = 0; i < 200; i++) {
+			val = snd_soc_component_read32(component, WM5100_OUTPUT_STATUS_1);
+			if (val == expect) {
+				wm5100->out_ena[0] = false;
+				break;
+			}
+		}
+		if (i == 200) {
+			dev_err(component->dev, "Timeout waiting for OUTPUT1 %x\n",
+				expect);
+		}
+	}
+
+	if (wm5100->out_ena[1]) {
+		expect = snd_soc_component_read32(component, WM5100_OUTPUT_ENABLES_2);
+		for (i = 0; i < 200; i++) {
+			val = snd_soc_component_read32(component, WM5100_OUTPUT_STATUS_2);
+			if (val == expect) {
+				wm5100->out_ena[1] = false;
+				break;
+			}
+		}
+		if (i == 200) {
+			dev_err(component->dev, "Timeout waiting for OUTPUT2 %x\n",
+				expect);
+		}
+	}
+}
+
+static int wm5100_out_ev(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol,
+			 int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
+
+	switch (w->reg) {
+	case WM5100_CHANNEL_ENABLES_1:
+		wm5100->out_ena[0] = true;
+		break;
+	case WM5100_OUTPUT_ENABLES_2:
+		wm5100->out_ena[0] = true;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static void wm5100_log_status3(struct wm5100_priv *wm5100, int val)
+{
+	if (val & WM5100_SPK_SHUTDOWN_WARN_EINT)
+		dev_crit(wm5100->dev, "Speaker shutdown warning\n");
+	if (val & WM5100_SPK_SHUTDOWN_EINT)
+		dev_crit(wm5100->dev, "Speaker shutdown\n");
+	if (val & WM5100_CLKGEN_ERR_EINT)
+		dev_crit(wm5100->dev, "SYSCLK underclocked\n");
+	if (val & WM5100_CLKGEN_ERR_ASYNC_EINT)
+		dev_crit(wm5100->dev, "ASYNCCLK underclocked\n");
+}
+
+static void wm5100_log_status4(struct wm5100_priv *wm5100, int val)
+{
+	if (val & WM5100_AIF3_ERR_EINT)
+		dev_err(wm5100->dev, "AIF3 configuration error\n");
+	if (val & WM5100_AIF2_ERR_EINT)
+		dev_err(wm5100->dev, "AIF2 configuration error\n");
+	if (val & WM5100_AIF1_ERR_EINT)
+		dev_err(wm5100->dev, "AIF1 configuration error\n");
+	if (val & WM5100_CTRLIF_ERR_EINT)
+		dev_err(wm5100->dev, "Control interface error\n");
+	if (val & WM5100_ISRC2_UNDERCLOCKED_EINT)
+		dev_err(wm5100->dev, "ISRC2 underclocked\n");
+	if (val & WM5100_ISRC1_UNDERCLOCKED_EINT)
+		dev_err(wm5100->dev, "ISRC1 underclocked\n");
+	if (val & WM5100_FX_UNDERCLOCKED_EINT)
+		dev_err(wm5100->dev, "FX underclocked\n");
+	if (val & WM5100_AIF3_UNDERCLOCKED_EINT)
+		dev_err(wm5100->dev, "AIF3 underclocked\n");
+	if (val & WM5100_AIF2_UNDERCLOCKED_EINT)
+		dev_err(wm5100->dev, "AIF2 underclocked\n");
+	if (val & WM5100_AIF1_UNDERCLOCKED_EINT)
+		dev_err(wm5100->dev, "AIF1 underclocked\n");
+	if (val & WM5100_ASRC_UNDERCLOCKED_EINT)
+		dev_err(wm5100->dev, "ASRC underclocked\n");
+	if (val & WM5100_DAC_UNDERCLOCKED_EINT)
+		dev_err(wm5100->dev, "DAC underclocked\n");
+	if (val & WM5100_ADC_UNDERCLOCKED_EINT)
+		dev_err(wm5100->dev, "ADC underclocked\n");
+	if (val & WM5100_MIXER_UNDERCLOCKED_EINT)
+		dev_err(wm5100->dev, "Mixer underclocked\n");
+}
+
+static int wm5100_post_ev(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol,
+			  int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = snd_soc_component_read32(component, WM5100_INTERRUPT_RAW_STATUS_3);
+	ret &= WM5100_SPK_SHUTDOWN_WARN_STS |
+		WM5100_SPK_SHUTDOWN_STS | WM5100_CLKGEN_ERR_STS |
+		WM5100_CLKGEN_ERR_ASYNC_STS;
+	wm5100_log_status3(wm5100, ret);
+
+	ret = snd_soc_component_read32(component, WM5100_INTERRUPT_RAW_STATUS_4);
+	wm5100_log_status4(wm5100, ret);
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget wm5100_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM5100_CLOCKING_3, WM5100_SYSCLK_ENA_SHIFT, 0,
+		    NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCCLK", WM5100_CLOCKING_6, WM5100_ASYNC_CLK_ENA_SHIFT,
+		    0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),
+
+SND_SOC_DAPM_SUPPLY("CP1", WM5100_HP_CHARGE_PUMP_1, WM5100_CP1_ENA_SHIFT, 0,
+		    NULL, 0),
+SND_SOC_DAPM_SUPPLY("CP2", WM5100_MIC_CHARGE_PUMP_1, WM5100_CP2_ENA_SHIFT, 0,
+		    NULL, 0),
+SND_SOC_DAPM_SUPPLY("CP2 Active", WM5100_MIC_CHARGE_PUMP_1,
+		    WM5100_CP2_BYPASS_SHIFT, 1, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS1", WM5100_MIC_BIAS_CTRL_1, WM5100_MICB1_ENA_SHIFT,
+		    0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", WM5100_MIC_BIAS_CTRL_2, WM5100_MICB2_ENA_SHIFT,
+		    0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS3", WM5100_MIC_BIAS_CTRL_3, WM5100_MICB3_ENA_SHIFT,
+		    0, NULL, 0),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+SND_SOC_DAPM_INPUT("IN4L"),
+SND_SOC_DAPM_INPUT("IN4R"),
+SND_SOC_DAPM_SIGGEN("TONE"),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", WM5100_INPUT_ENABLES, WM5100_IN1L_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", WM5100_INPUT_ENABLES, WM5100_IN1R_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2L PGA", WM5100_INPUT_ENABLES, WM5100_IN2L_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2R PGA", WM5100_INPUT_ENABLES, WM5100_IN2R_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN3L PGA", WM5100_INPUT_ENABLES, WM5100_IN3L_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN3R PGA", WM5100_INPUT_ENABLES, WM5100_IN3R_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN4L PGA", WM5100_INPUT_ENABLES, WM5100_IN4L_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN4R PGA", WM5100_INPUT_ENABLES, WM5100_IN4R_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA("Tone Generator 1", WM5100_TONE_GENERATOR_1,
+		 WM5100_TONE1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", WM5100_TONE_GENERATOR_1,
+		 WM5100_TONE2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", "AIF1 Playback", 0,
+		    WM5100_AUDIO_IF_1_27, WM5100_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", "AIF1 Playback", 1,
+		    WM5100_AUDIO_IF_1_27, WM5100_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", "AIF1 Playback", 2,
+		    WM5100_AUDIO_IF_1_27, WM5100_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", "AIF1 Playback", 3,
+		    WM5100_AUDIO_IF_1_27, WM5100_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 4,
+		    WM5100_AUDIO_IF_1_27, WM5100_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", "AIF1 Playback", 5,
+		    WM5100_AUDIO_IF_1_27, WM5100_AIF1RX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX7", "AIF1 Playback", 6,
+		    WM5100_AUDIO_IF_1_27, WM5100_AIF1RX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX8", "AIF1 Playback", 7,
+		    WM5100_AUDIO_IF_1_27, WM5100_AIF1RX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 0,
+		    WM5100_AUDIO_IF_2_27, WM5100_AIF2RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX2", "AIF2 Playback", 1,
+		    WM5100_AUDIO_IF_2_27, WM5100_AIF2RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF3RX1", "AIF3 Playback", 0,
+		    WM5100_AUDIO_IF_3_27, WM5100_AIF3RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF3RX2", "AIF3 Playback", 1,
+		    WM5100_AUDIO_IF_3_27, WM5100_AIF3RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", "AIF1 Capture", 0,
+		    WM5100_AUDIO_IF_1_26, WM5100_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", "AIF1 Capture", 1,
+		    WM5100_AUDIO_IF_1_26, WM5100_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", "AIF1 Capture", 2,
+		    WM5100_AUDIO_IF_1_26, WM5100_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", "AIF1 Capture", 3,
+		    WM5100_AUDIO_IF_1_26, WM5100_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", "AIF1 Capture", 4,
+		    WM5100_AUDIO_IF_1_26, WM5100_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", "AIF1 Capture", 5,
+		    WM5100_AUDIO_IF_1_26, WM5100_AIF1TX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX7", "AIF1 Capture", 6,
+		    WM5100_AUDIO_IF_1_26, WM5100_AIF1TX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX8", "AIF1 Capture", 7,
+		    WM5100_AUDIO_IF_1_26, WM5100_AIF1TX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", "AIF2 Capture", 0,
+		    WM5100_AUDIO_IF_2_26, WM5100_AIF2TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX2", "AIF2 Capture", 1,
+		    WM5100_AUDIO_IF_2_26, WM5100_AIF2TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF3TX1", "AIF3 Capture", 0,
+		    WM5100_AUDIO_IF_3_26, WM5100_AIF3TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3TX2", "AIF3 Capture", 1,
+		    WM5100_AUDIO_IF_3_26, WM5100_AIF3TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA_E("OUT6L", WM5100_OUTPUT_ENABLES_2, WM5100_OUT6L_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT6R", WM5100_OUTPUT_ENABLES_2, WM5100_OUT6R_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5L", WM5100_OUTPUT_ENABLES_2, WM5100_OUT5L_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5R", WM5100_OUTPUT_ENABLES_2, WM5100_OUT5R_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT4L", WM5100_OUTPUT_ENABLES_2, WM5100_OUT4L_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT4R", WM5100_OUTPUT_ENABLES_2, WM5100_OUT4R_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT3L", WM5100_CHANNEL_ENABLES_1, WM5100_HP3L_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT3R", WM5100_CHANNEL_ENABLES_1, WM5100_HP3R_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT2L", WM5100_CHANNEL_ENABLES_1, WM5100_HP2L_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT2R", WM5100_CHANNEL_ENABLES_1, WM5100_HP2R_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1L", WM5100_CHANNEL_ENABLES_1, WM5100_HP1L_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1R", WM5100_CHANNEL_ENABLES_1, WM5100_HP1R_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("PWM1 Driver", WM5100_PWM_DRIVE_1, WM5100_PWM1_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("PWM2 Driver", WM5100_PWM_DRIVE_1, WM5100_PWM2_ENA_SHIFT, 0,
+		   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA("EQ1", WM5100_EQ1_1, WM5100_EQ1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ2", WM5100_EQ2_1, WM5100_EQ2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ3", WM5100_EQ3_1, WM5100_EQ3_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ4", WM5100_EQ4_1, WM5100_EQ4_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("DRC1L", WM5100_DRC1_CTRL1, WM5100_DRCL_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", WM5100_DRC1_CTRL1, WM5100_DRCR_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", WM5100_HPLPF1_1, WM5100_LHPF1_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", WM5100_HPLPF2_1, WM5100_LHPF2_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", WM5100_HPLPF3_1, WM5100_LHPF3_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", WM5100_HPLPF4_1, WM5100_LHPF4_ENA_SHIFT, 0,
+		 NULL, 0),
+
+WM5100_MIXER_WIDGETS(EQ1, "EQ1"),
+WM5100_MIXER_WIDGETS(EQ2, "EQ2"),
+WM5100_MIXER_WIDGETS(EQ3, "EQ3"),
+WM5100_MIXER_WIDGETS(EQ4, "EQ4"),
+
+WM5100_MIXER_WIDGETS(DRC1L, "DRC1L"),
+WM5100_MIXER_WIDGETS(DRC1R, "DRC1R"),
+
+WM5100_MIXER_WIDGETS(LHPF1, "LHPF1"),
+WM5100_MIXER_WIDGETS(LHPF2, "LHPF2"),
+WM5100_MIXER_WIDGETS(LHPF3, "LHPF3"),
+WM5100_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+WM5100_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+WM5100_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+WM5100_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+WM5100_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+WM5100_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+WM5100_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+WM5100_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
+WM5100_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
+
+WM5100_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
+WM5100_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+
+WM5100_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
+WM5100_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
+
+WM5100_MIXER_WIDGETS(HPOUT1L, "HPOUT1L"),
+WM5100_MIXER_WIDGETS(HPOUT1R, "HPOUT1R"),
+WM5100_MIXER_WIDGETS(HPOUT2L, "HPOUT2L"),
+WM5100_MIXER_WIDGETS(HPOUT2R, "HPOUT2R"),
+WM5100_MIXER_WIDGETS(HPOUT3L, "HPOUT3L"),
+WM5100_MIXER_WIDGETS(HPOUT3R, "HPOUT3R"),
+
+WM5100_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"),
+WM5100_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"),
+WM5100_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"),
+WM5100_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"),
+WM5100_MIXER_WIDGETS(SPKDAT2L, "SPKDAT2L"),
+WM5100_MIXER_WIDGETS(SPKDAT2R, "SPKDAT2R"),
+
+WM5100_MIXER_WIDGETS(PWM1, "PWM1"),
+WM5100_MIXER_WIDGETS(PWM2, "PWM2"),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("HPOUT2L"),
+SND_SOC_DAPM_OUTPUT("HPOUT2R"),
+SND_SOC_DAPM_OUTPUT("HPOUT3L"),
+SND_SOC_DAPM_OUTPUT("HPOUT3R"),
+SND_SOC_DAPM_OUTPUT("SPKOUTL"),
+SND_SOC_DAPM_OUTPUT("SPKOUTR"),
+SND_SOC_DAPM_OUTPUT("SPKDAT1"),
+SND_SOC_DAPM_OUTPUT("SPKDAT2"),
+SND_SOC_DAPM_OUTPUT("PWM1"),
+SND_SOC_DAPM_OUTPUT("PWM2"),
+};
+
+/* We register a _POST event if we don't have IRQ support so we can
+ * look at the error status from the CODEC - if we've got the IRQ
+ * hooked up then we will get prompted to look by an interrupt.
+ */
+static const struct snd_soc_dapm_widget wm5100_dapm_widgets_noirq[] = {
+SND_SOC_DAPM_POST("Post", wm5100_post_ev),
+};
+
+static const struct snd_soc_dapm_route wm5100_dapm_routes[] = {
+	{ "CP1", NULL, "CPVDD" },
+	{ "CP2 Active", NULL, "CPVDD" },
+
+	{ "IN1L", NULL, "SYSCLK" },
+	{ "IN1R", NULL, "SYSCLK" },
+	{ "IN2L", NULL, "SYSCLK" },
+	{ "IN2R", NULL, "SYSCLK" },
+	{ "IN3L", NULL, "SYSCLK" },
+	{ "IN3R", NULL, "SYSCLK" },
+	{ "IN4L", NULL, "SYSCLK" },
+	{ "IN4R", NULL, "SYSCLK" },
+
+	{ "OUT1L", NULL, "SYSCLK" },
+	{ "OUT1R", NULL, "SYSCLK" },
+	{ "OUT2L", NULL, "SYSCLK" },
+	{ "OUT2R", NULL, "SYSCLK" },
+	{ "OUT3L", NULL, "SYSCLK" },
+	{ "OUT3R", NULL, "SYSCLK" },
+	{ "OUT4L", NULL, "SYSCLK" },
+	{ "OUT4R", NULL, "SYSCLK" },
+	{ "OUT5L", NULL, "SYSCLK" },
+	{ "OUT5R", NULL, "SYSCLK" },
+	{ "OUT6L", NULL, "SYSCLK" },
+	{ "OUT6R", NULL, "SYSCLK" },
+
+	{ "AIF1RX1", NULL, "SYSCLK" },
+	{ "AIF1RX2", NULL, "SYSCLK" },
+	{ "AIF1RX3", NULL, "SYSCLK" },
+	{ "AIF1RX4", NULL, "SYSCLK" },
+	{ "AIF1RX5", NULL, "SYSCLK" },
+	{ "AIF1RX6", NULL, "SYSCLK" },
+	{ "AIF1RX7", NULL, "SYSCLK" },
+	{ "AIF1RX8", NULL, "SYSCLK" },
+
+	{ "AIF2RX1", NULL, "SYSCLK" },
+	{ "AIF2RX1", NULL, "DBVDD2" },
+	{ "AIF2RX2", NULL, "SYSCLK" },
+	{ "AIF2RX2", NULL, "DBVDD2" },
+
+	{ "AIF3RX1", NULL, "SYSCLK" },
+	{ "AIF3RX1", NULL, "DBVDD3" },
+	{ "AIF3RX2", NULL, "SYSCLK" },
+	{ "AIF3RX2", NULL, "DBVDD3" },
+
+	{ "AIF1TX1", NULL, "SYSCLK" },
+	{ "AIF1TX2", NULL, "SYSCLK" },
+	{ "AIF1TX3", NULL, "SYSCLK" },
+	{ "AIF1TX4", NULL, "SYSCLK" },
+	{ "AIF1TX5", NULL, "SYSCLK" },
+	{ "AIF1TX6", NULL, "SYSCLK" },
+	{ "AIF1TX7", NULL, "SYSCLK" },
+	{ "AIF1TX8", NULL, "SYSCLK" },
+
+	{ "AIF2TX1", NULL, "SYSCLK" },
+	{ "AIF2TX1", NULL, "DBVDD2" },
+	{ "AIF2TX2", NULL, "SYSCLK" },
+	{ "AIF2TX2", NULL, "DBVDD2" },
+
+	{ "AIF3TX1", NULL, "SYSCLK" },
+	{ "AIF3TX1", NULL, "DBVDD3" },
+	{ "AIF3TX2", NULL, "SYSCLK" },
+	{ "AIF3TX2", NULL, "DBVDD3" },
+
+	{ "MICBIAS1", NULL, "CP2" },
+	{ "MICBIAS2", NULL, "CP2" },
+	{ "MICBIAS3", NULL, "CP2" },
+
+	{ "IN1L PGA", NULL, "CP2" },
+	{ "IN1R PGA", NULL, "CP2" },
+	{ "IN2L PGA", NULL, "CP2" },
+	{ "IN2R PGA", NULL, "CP2" },
+	{ "IN3L PGA", NULL, "CP2" },
+	{ "IN3R PGA", NULL, "CP2" },
+	{ "IN4L PGA", NULL, "CP2" },
+	{ "IN4R PGA", NULL, "CP2" },
+
+	{ "IN1L PGA", NULL, "CP2 Active" },
+	{ "IN1R PGA", NULL, "CP2 Active" },
+	{ "IN2L PGA", NULL, "CP2 Active" },
+	{ "IN2R PGA", NULL, "CP2 Active" },
+	{ "IN3L PGA", NULL, "CP2 Active" },
+	{ "IN3R PGA", NULL, "CP2 Active" },
+	{ "IN4L PGA", NULL, "CP2 Active" },
+	{ "IN4R PGA", NULL, "CP2 Active" },
+
+	{ "OUT1L", NULL, "CP1" },
+	{ "OUT1R", NULL, "CP1" },
+	{ "OUT2L", NULL, "CP1" },
+	{ "OUT2R", NULL, "CP1" },
+	{ "OUT3L", NULL, "CP1" },
+	{ "OUT3R", NULL, "CP1" },
+
+	{ "Tone Generator 1", NULL, "TONE" },
+	{ "Tone Generator 2", NULL, "TONE" },
+
+	{ "IN1L PGA", NULL, "IN1L" },
+	{ "IN1R PGA", NULL, "IN1R" },
+	{ "IN2L PGA", NULL, "IN2L" },
+	{ "IN2R PGA", NULL, "IN2R" },
+	{ "IN3L PGA", NULL, "IN3L" },
+	{ "IN3R PGA", NULL, "IN3R" },
+	{ "IN4L PGA", NULL, "IN4L" },
+	{ "IN4R PGA", NULL, "IN4R" },
+
+	WM5100_MIXER_ROUTES("OUT1L", "HPOUT1L"),
+	WM5100_MIXER_ROUTES("OUT1R", "HPOUT1R"),
+	WM5100_MIXER_ROUTES("OUT2L", "HPOUT2L"),
+	WM5100_MIXER_ROUTES("OUT2R", "HPOUT2R"),
+	WM5100_MIXER_ROUTES("OUT3L", "HPOUT3L"),
+	WM5100_MIXER_ROUTES("OUT3R", "HPOUT3R"),
+
+	WM5100_MIXER_ROUTES("OUT4L", "SPKOUTL"),
+	WM5100_MIXER_ROUTES("OUT4R", "SPKOUTR"),
+	WM5100_MIXER_ROUTES("OUT5L", "SPKDAT1L"),
+	WM5100_MIXER_ROUTES("OUT5R", "SPKDAT1R"),
+	WM5100_MIXER_ROUTES("OUT6L", "SPKDAT2L"),
+	WM5100_MIXER_ROUTES("OUT6R", "SPKDAT2R"),
+
+	WM5100_MIXER_ROUTES("PWM1 Driver", "PWM1"),
+	WM5100_MIXER_ROUTES("PWM2 Driver", "PWM2"),
+
+	WM5100_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+	WM5100_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+	WM5100_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+	WM5100_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+	WM5100_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+	WM5100_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+	WM5100_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
+	WM5100_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
+
+	WM5100_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
+	WM5100_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+
+	WM5100_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
+	WM5100_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
+
+	WM5100_MIXER_ROUTES("EQ1", "EQ1"),
+	WM5100_MIXER_ROUTES("EQ2", "EQ2"),
+	WM5100_MIXER_ROUTES("EQ3", "EQ3"),
+	WM5100_MIXER_ROUTES("EQ4", "EQ4"),
+
+	WM5100_MIXER_ROUTES("DRC1L", "DRC1L"),
+	WM5100_MIXER_ROUTES("DRC1R", "DRC1R"),
+
+	WM5100_MIXER_ROUTES("LHPF1", "LHPF1"),
+	WM5100_MIXER_ROUTES("LHPF2", "LHPF2"),
+	WM5100_MIXER_ROUTES("LHPF3", "LHPF3"),
+	WM5100_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+	{ "HPOUT1L", NULL, "OUT1L" },
+	{ "HPOUT1R", NULL, "OUT1R" },
+	{ "HPOUT2L", NULL, "OUT2L" },
+	{ "HPOUT2R", NULL, "OUT2R" },
+	{ "HPOUT3L", NULL, "OUT3L" },
+	{ "HPOUT3R", NULL, "OUT3R" },
+	{ "SPKOUTL", NULL, "OUT4L" },
+	{ "SPKOUTR", NULL, "OUT4R" },
+	{ "SPKDAT1", NULL, "OUT5L" },
+	{ "SPKDAT1", NULL, "OUT5R" },
+	{ "SPKDAT2", NULL, "OUT6L" },
+	{ "SPKDAT2", NULL, "OUT6R" },
+	{ "PWM1", NULL, "PWM1 Driver" },
+	{ "PWM2", NULL, "PWM2 Driver" },
+};
+
+static const struct reg_sequence wm5100_reva_patches[] = {
+	{ WM5100_AUDIO_IF_1_10, 0 },
+	{ WM5100_AUDIO_IF_1_11, 1 },
+	{ WM5100_AUDIO_IF_1_12, 2 },
+	{ WM5100_AUDIO_IF_1_13, 3 },
+	{ WM5100_AUDIO_IF_1_14, 4 },
+	{ WM5100_AUDIO_IF_1_15, 5 },
+	{ WM5100_AUDIO_IF_1_16, 6 },
+	{ WM5100_AUDIO_IF_1_17, 7 },
+
+	{ WM5100_AUDIO_IF_1_18, 0 },
+	{ WM5100_AUDIO_IF_1_19, 1 },
+	{ WM5100_AUDIO_IF_1_20, 2 },
+	{ WM5100_AUDIO_IF_1_21, 3 },
+	{ WM5100_AUDIO_IF_1_22, 4 },
+	{ WM5100_AUDIO_IF_1_23, 5 },
+	{ WM5100_AUDIO_IF_1_24, 6 },
+	{ WM5100_AUDIO_IF_1_25, 7 },
+
+	{ WM5100_AUDIO_IF_2_10, 0 },
+	{ WM5100_AUDIO_IF_2_11, 1 },
+
+	{ WM5100_AUDIO_IF_2_18, 0 },
+	{ WM5100_AUDIO_IF_2_19, 1 },
+
+	{ WM5100_AUDIO_IF_3_10, 0 },
+	{ WM5100_AUDIO_IF_3_11, 1 },
+
+	{ WM5100_AUDIO_IF_3_18, 0 },
+	{ WM5100_AUDIO_IF_3_19, 1 },
+};
+
+static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	int lrclk, bclk, mask, base;
+
+	base = dai->driver->base;
+
+	lrclk = 0;
+	bclk = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		mask = 0;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		mask = 2;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported DAI format %d\n",
+			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		lrclk |= WM5100_AIF1TX_LRCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		bclk |= WM5100_AIF1_BCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		lrclk |= WM5100_AIF1TX_LRCLK_MSTR;
+		bclk |= WM5100_AIF1_BCLK_MSTR;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported master mode %d\n",
+			fmt & SND_SOC_DAIFMT_MASTER_MASK);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		bclk |= WM5100_AIF1_BCLK_INV;
+		lrclk |= WM5100_AIF1TX_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		bclk |= WM5100_AIF1_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		lrclk |= WM5100_AIF1TX_LRCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, base + 1, WM5100_AIF1_BCLK_MSTR |
+			    WM5100_AIF1_BCLK_INV, bclk);
+	snd_soc_component_update_bits(component, base + 2, WM5100_AIF1TX_LRCLK_MSTR |
+			    WM5100_AIF1TX_LRCLK_INV, lrclk);
+	snd_soc_component_update_bits(component, base + 3, WM5100_AIF1TX_LRCLK_MSTR |
+			    WM5100_AIF1TX_LRCLK_INV, lrclk);
+	snd_soc_component_update_bits(component, base + 5, WM5100_AIF1_FMT_MASK, mask);
+
+	return 0;
+}
+
+#define WM5100_NUM_BCLK_RATES 19
+
+static int wm5100_bclk_rates_dat[WM5100_NUM_BCLK_RATES] = {
+	32000,
+	48000,
+	64000,
+	96000,
+	128000,
+	192000,
+	256000,
+	384000,
+	512000,
+	768000,
+	1024000,
+	1536000,
+	2048000,
+	3072000,
+	4096000,
+	6144000,
+	8192000,
+	12288000,
+	24576000,
+};
+
+static int wm5100_bclk_rates_cd[WM5100_NUM_BCLK_RATES] = {
+	29400,
+	44100,
+	58800,
+	88200,
+	117600,
+	176400,
+	235200,
+	352800,
+	470400,
+	705600,
+	940800,
+	1411200,
+	1881600,
+	2882400,
+	3763200,
+	5644800,
+	7526400,
+	11289600,
+	22579600,
+};
+
+static int wm5100_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
+	bool async = wm5100->aif_async[dai->id];
+	int i, base, bclk, aif_rate, lrclk, wl, fl, sr;
+	int *bclk_rates;
+
+	base = dai->driver->base;
+
+	/* Data sizes if not using TDM */
+	wl = params_width(params);
+	if (wl < 0)
+		return wl;
+	fl = snd_soc_params_to_frame_size(params);
+	if (fl < 0)
+		return fl;
+
+	dev_dbg(component->dev, "Word length %d bits, frame length %d bits\n",
+		wl, fl);
+
+	/* Target BCLK rate */
+	bclk = snd_soc_params_to_bclk(params);
+	if (bclk < 0)
+		return bclk;
+
+	/* Root for BCLK depends on SYS/ASYNCCLK */
+	if (!async) {
+		aif_rate = wm5100->sysclk;
+		sr = wm5100_alloc_sr(component, params_rate(params));
+		if (sr < 0)
+			return sr;
+	} else {
+		/* If we're in ASYNCCLK set the ASYNC sample rate */
+		aif_rate = wm5100->asyncclk;
+		sr = 3;
+
+		for (i = 0; i < ARRAY_SIZE(wm5100_sr_code); i++)
+			if (params_rate(params) == wm5100_sr_code[i])
+				break;
+		if (i == ARRAY_SIZE(wm5100_sr_code)) {
+			dev_err(component->dev, "Invalid rate %dHzn",
+				params_rate(params));
+			return -EINVAL;
+		}
+
+		/* TODO: We should really check for symmetry */
+		snd_soc_component_update_bits(component, WM5100_CLOCKING_8,
+				    WM5100_ASYNC_SAMPLE_RATE_MASK, i);
+	}
+
+	if (!aif_rate) {
+		dev_err(component->dev, "%s has no rate set\n",
+			async ? "ASYNCCLK" : "SYSCLK");
+		return -EINVAL;
+	}
+
+	dev_dbg(component->dev, "Target BCLK is %dHz, using %dHz %s\n",
+		bclk, aif_rate, async ? "ASYNCCLK" : "SYSCLK");
+
+	if (aif_rate % 4000)
+		bclk_rates = wm5100_bclk_rates_cd;
+	else
+		bclk_rates = wm5100_bclk_rates_dat;
+
+	for (i = 0; i < WM5100_NUM_BCLK_RATES; i++)
+		if (bclk_rates[i] >= bclk && (bclk_rates[i] % bclk == 0))
+			break;
+	if (i == WM5100_NUM_BCLK_RATES) {
+		dev_err(component->dev,
+			"No valid BCLK for %dHz found from %dHz %s\n",
+			bclk, aif_rate, async ? "ASYNCCLK" : "SYSCLK");
+		return -EINVAL;
+	}
+
+	bclk = i;
+	dev_dbg(component->dev, "Setting %dHz BCLK\n", bclk_rates[bclk]);
+	snd_soc_component_update_bits(component, base + 1, WM5100_AIF1_BCLK_FREQ_MASK, bclk);
+
+	lrclk = bclk_rates[bclk] / params_rate(params);
+	dev_dbg(component->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+	    wm5100->aif_symmetric[dai->id])
+		snd_soc_component_update_bits(component, base + 7,
+				    WM5100_AIF1RX_BCPF_MASK, lrclk);
+	else
+		snd_soc_component_update_bits(component, base + 6,
+				    WM5100_AIF1TX_BCPF_MASK, lrclk);
+
+	i = (wl << WM5100_AIF1TX_WL_SHIFT) | fl;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snd_soc_component_update_bits(component, base + 9,
+				    WM5100_AIF1RX_WL_MASK |
+				    WM5100_AIF1RX_SLOT_LEN_MASK, i);
+	else
+		snd_soc_component_update_bits(component, base + 8,
+				    WM5100_AIF1TX_WL_MASK |
+				    WM5100_AIF1TX_SLOT_LEN_MASK, i);
+
+	snd_soc_component_update_bits(component, base + 4, WM5100_AIF1_RATE_MASK, sr);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops wm5100_dai_ops = {
+	.set_fmt = wm5100_set_fmt,
+	.hw_params = wm5100_hw_params,
+};
+
+static int wm5100_set_sysclk(struct snd_soc_component *component, int clk_id,
+			     int source, unsigned int freq, int dir)
+{
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
+	int *rate_store;
+	int fval, audio_rate, ret, reg;
+
+	switch (clk_id) {
+	case WM5100_CLK_SYSCLK:
+		reg = WM5100_CLOCKING_3;
+		rate_store = &wm5100->sysclk;
+		break;
+	case WM5100_CLK_ASYNCCLK:
+		reg = WM5100_CLOCKING_7;
+		rate_store = &wm5100->asyncclk;
+		break;
+	case WM5100_CLK_32KHZ:
+		/* The 32kHz clock is slightly different to the others */
+		switch (source) {
+		case WM5100_CLKSRC_MCLK1:
+		case WM5100_CLKSRC_MCLK2:
+		case WM5100_CLKSRC_SYSCLK:
+			snd_soc_component_update_bits(component, WM5100_CLOCKING_1,
+					    WM5100_CLK_32K_SRC_MASK,
+					    source);
+			break;
+		default:
+			return -EINVAL;
+		}
+		return 0;
+
+	case WM5100_CLK_AIF1:
+	case WM5100_CLK_AIF2:
+	case WM5100_CLK_AIF3:
+		/* Not real clocks, record which clock domain they're in */
+		switch (source) {
+		case WM5100_CLKSRC_SYSCLK:
+			wm5100->aif_async[clk_id - 1] = false;
+			break;
+		case WM5100_CLKSRC_ASYNCCLK:
+			wm5100->aif_async[clk_id - 1] = true;
+			break;
+		default:
+			dev_err(component->dev, "Invalid source %d\n", source);
+			return -EINVAL;
+		}	
+		return 0;
+
+	case WM5100_CLK_OPCLK:
+		switch (freq) {
+		case 5644800:
+		case 6144000:
+			snd_soc_component_update_bits(component, WM5100_MISC_GPIO_1,
+					    WM5100_OPCLK_SEL_MASK, 0);
+			break;
+		case 11289600:
+		case 12288000:
+			snd_soc_component_update_bits(component, WM5100_MISC_GPIO_1,
+					    WM5100_OPCLK_SEL_MASK, 0);
+			break;
+		case 22579200:
+		case 24576000:
+			snd_soc_component_update_bits(component, WM5100_MISC_GPIO_1,
+					    WM5100_OPCLK_SEL_MASK, 0);
+			break;
+		default:
+			dev_err(component->dev, "Unsupported OPCLK %dHz\n",
+				freq);
+			return -EINVAL;
+		}
+		return 0;
+
+	default:
+		dev_err(component->dev, "Unknown clock %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	switch (source) {
+	case WM5100_CLKSRC_SYSCLK:
+	case WM5100_CLKSRC_ASYNCCLK:
+		dev_err(component->dev, "Invalid source %d\n", source);
+		return -EINVAL;
+	}
+
+	switch (freq) {
+	case 5644800:
+	case 6144000:
+		fval = 0;
+		break;
+	case 11289600:
+	case 12288000:
+		fval = 1;
+		break;
+	case 22579200:
+	case 24576000:
+		fval = 2;
+		break;
+	default:
+		dev_err(component->dev, "Invalid clock rate: %d\n", freq);
+		return -EINVAL;
+	}
+
+	switch (freq) {
+	case 5644800:
+	case 11289600:
+	case 22579200:
+		audio_rate = 44100;
+		break;
+
+	case 6144000:
+	case 12288000:
+	case 24576000:
+		audio_rate = 48000;
+		break;
+
+	default:
+		BUG();
+		audio_rate = 0;
+		break;
+	}
+
+	/* TODO: Check if MCLKs are in use and enable/disable pulls to
+	 * match.
+	 */
+
+	snd_soc_component_update_bits(component, reg, WM5100_SYSCLK_FREQ_MASK |
+			    WM5100_SYSCLK_SRC_MASK,
+			    fval << WM5100_SYSCLK_FREQ_SHIFT | source);
+
+	/* If this is SYSCLK then configure the clock rate for the
+	 * internal audio functions to the natural sample rate for
+	 * this clock rate.
+	 */
+	if (clk_id == WM5100_CLK_SYSCLK) {
+		dev_dbg(component->dev, "Setting primary audio rate to %dHz",
+			audio_rate);
+		if (0 && *rate_store)
+			wm5100_free_sr(component, audio_rate);
+		ret = wm5100_alloc_sr(component, audio_rate);
+		if (ret != 0)
+			dev_warn(component->dev, "Primary audio slot is %d\n",
+				 ret);
+	}
+
+	*rate_store = freq;
+
+	return 0;
+}
+
+struct _fll_div {
+	u16 fll_fratio;
+	u16 fll_outdiv;
+	u16 fll_refclk_div;
+	u16 n;
+	u16 theta;
+	u16 lambda;
+};
+
+static struct {
+	unsigned int min;
+	unsigned int max;
+	u16 fll_fratio;
+	int ratio;
+} fll_fratios[] = {
+	{       0,    64000, 4, 16 },
+	{   64000,   128000, 3,  8 },
+	{  128000,   256000, 2,  4 },
+	{  256000,  1000000, 1,  2 },
+	{ 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+		       unsigned int Fout)
+{
+	unsigned int target;
+	unsigned int div;
+	unsigned int fratio, gcd_fll;
+	int i;
+
+	/* Fref must be <=13.5MHz */
+	div = 1;
+	fll_div->fll_refclk_div = 0;
+	while ((Fref / div) > 13500000) {
+		div *= 2;
+		fll_div->fll_refclk_div++;
+
+		if (div > 8) {
+			pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+			       Fref);
+			return -EINVAL;
+		}
+	}
+
+	pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+	/* Apply the division for our remaining calculations */
+	Fref /= div;
+
+	/* Fvco should be 90-100MHz; don't check the upper bound */
+	div = 2;
+	while (Fout * div < 90000000) {
+		div++;
+		if (div > 64) {
+			pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+			       Fout);
+			return -EINVAL;
+		}
+	}
+	target = Fout * div;
+	fll_div->fll_outdiv = div - 1;
+
+	pr_debug("FLL Fvco=%dHz\n", target);
+
+	/* Find an appropraite FLL_FRATIO and factor it out of the target */
+	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+			fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+			fratio = fll_fratios[i].ratio;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(fll_fratios)) {
+		pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+		return -EINVAL;
+	}
+
+	fll_div->n = target / (fratio * Fref);
+
+	if (target % Fref == 0) {
+		fll_div->theta = 0;
+		fll_div->lambda = 0;
+	} else {
+		gcd_fll = gcd(target, fratio * Fref);
+
+		fll_div->theta = (target - (fll_div->n * fratio * Fref))
+			/ gcd_fll;
+		fll_div->lambda = (fratio * Fref) / gcd_fll;
+	}
+
+	pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+		 fll_div->n, fll_div->theta, fll_div->lambda);
+	pr_debug("FLL_FRATIO=%x(%d) FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+		 fll_div->fll_fratio, fratio, fll_div->fll_outdiv,
+		 fll_div->fll_refclk_div);
+
+	return 0;
+}
+
+static int wm5100_set_fll(struct snd_soc_component *component, int fll_id, int source,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct i2c_client *i2c = to_i2c_client(component->dev);
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
+	struct _fll_div factors;
+	struct wm5100_fll *fll;
+	int ret, base, lock, i, timeout;
+	unsigned long time_left;
+
+	switch (fll_id) {
+	case WM5100_FLL1:
+		fll = &wm5100->fll[0];
+		base = WM5100_FLL1_CONTROL_1 - 1;
+		lock = WM5100_FLL1_LOCK_STS;
+		break;
+	case WM5100_FLL2:
+		fll = &wm5100->fll[1];
+		base = WM5100_FLL2_CONTROL_2 - 1;
+		lock = WM5100_FLL2_LOCK_STS;
+		break;
+	default:
+		dev_err(component->dev, "Unknown FLL %d\n",fll_id);
+		return -EINVAL;
+	}
+
+	if (!Fout) {
+		dev_dbg(component->dev, "FLL%d disabled", fll_id);
+		if (fll->fout)
+			pm_runtime_put(component->dev);
+		fll->fout = 0;
+		snd_soc_component_update_bits(component, base + 1, WM5100_FLL1_ENA, 0);
+		return 0;
+	}
+
+	switch (source) {
+	case WM5100_FLL_SRC_MCLK1:
+	case WM5100_FLL_SRC_MCLK2:
+	case WM5100_FLL_SRC_FLL1:
+	case WM5100_FLL_SRC_FLL2:
+	case WM5100_FLL_SRC_AIF1BCLK:
+	case WM5100_FLL_SRC_AIF2BCLK:
+	case WM5100_FLL_SRC_AIF3BCLK:
+		break;
+	default:
+		dev_err(component->dev, "Invalid FLL source %d\n", source);
+		return -EINVAL;
+	}
+
+	ret = fll_factors(&factors, Fref, Fout);
+	if (ret < 0)
+		return ret;
+
+	/* Disable the FLL while we reconfigure */
+	snd_soc_component_update_bits(component, base + 1, WM5100_FLL1_ENA, 0);
+
+	snd_soc_component_update_bits(component, base + 2,
+			    WM5100_FLL1_OUTDIV_MASK | WM5100_FLL1_FRATIO_MASK,
+			    (factors.fll_outdiv << WM5100_FLL1_OUTDIV_SHIFT) |
+			    factors.fll_fratio);
+	snd_soc_component_update_bits(component, base + 3, WM5100_FLL1_THETA_MASK,
+			    factors.theta);
+	snd_soc_component_update_bits(component, base + 5, WM5100_FLL1_N_MASK, factors.n);
+	snd_soc_component_update_bits(component, base + 6,
+			    WM5100_FLL1_REFCLK_DIV_MASK |
+			    WM5100_FLL1_REFCLK_SRC_MASK,
+			    (factors.fll_refclk_div
+			     << WM5100_FLL1_REFCLK_DIV_SHIFT) | source);
+	snd_soc_component_update_bits(component, base + 7, WM5100_FLL1_LAMBDA_MASK,
+			    factors.lambda);
+
+	/* Clear any pending completions */
+	try_wait_for_completion(&fll->lock);
+
+	pm_runtime_get_sync(component->dev);
+
+	snd_soc_component_update_bits(component, base + 1, WM5100_FLL1_ENA, WM5100_FLL1_ENA);
+
+	if (i2c->irq)
+		timeout = 2;
+	else
+		timeout = 50;
+
+	snd_soc_component_update_bits(component, WM5100_CLOCKING_3, WM5100_SYSCLK_ENA,
+			    WM5100_SYSCLK_ENA);
+
+	/* Poll for the lock; will use interrupt when we can test */
+	for (i = 0; i < timeout; i++) {
+		if (i2c->irq) {
+			time_left = wait_for_completion_timeout(&fll->lock,
+							msecs_to_jiffies(25));
+			if (time_left > 0)
+				break;
+		} else {
+			msleep(1);
+		}
+
+		ret = snd_soc_component_read32(component,
+				   WM5100_INTERRUPT_RAW_STATUS_3);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to read FLL status: %d\n",
+				ret);
+			continue;
+		}
+		if (ret & lock)
+			break;
+	}
+	if (i == timeout) {
+		dev_err(component->dev, "FLL%d lock timed out\n", fll_id);
+		pm_runtime_put(component->dev);
+		return -ETIMEDOUT;
+	}
+
+	fll->src = source;
+	fll->fref = Fref;
+	fll->fout = Fout;
+
+	dev_dbg(component->dev, "FLL%d running %dHz->%dHz\n", fll_id,
+		Fref, Fout);
+
+	return 0;
+}
+
+/* Actually go much higher */
+#define WM5100_RATES SNDRV_PCM_RATE_8000_192000
+
+#define WM5100_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm5100_dai[] = {
+	{
+		.name = "wm5100-aif1",
+		.base = WM5100_AUDIO_IF_1_1 - 1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = WM5100_RATES,
+			.formats = WM5100_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF1 Capture",
+			 .channels_min = 2,
+			 .channels_max = 2,
+			 .rates = WM5100_RATES,
+			 .formats = WM5100_FORMATS,
+		 },
+		.ops = &wm5100_dai_ops,
+	},
+	{
+		.name = "wm5100-aif2",
+		.id = 1,
+		.base = WM5100_AUDIO_IF_2_1 - 1,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = WM5100_RATES,
+			.formats = WM5100_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF2 Capture",
+			 .channels_min = 2,
+			 .channels_max = 2,
+			 .rates = WM5100_RATES,
+			 .formats = WM5100_FORMATS,
+		 },
+		.ops = &wm5100_dai_ops,
+	},
+	{
+		.name = "wm5100-aif3",
+		.id = 2,
+		.base = WM5100_AUDIO_IF_3_1 - 1,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = WM5100_RATES,
+			.formats = WM5100_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF3 Capture",
+			 .channels_min = 2,
+			 .channels_max = 2,
+			 .rates = WM5100_RATES,
+			 .formats = WM5100_FORMATS,
+		 },
+		.ops = &wm5100_dai_ops,
+	},
+};
+
+static int wm5100_dig_vu[] = {
+	WM5100_ADC_DIGITAL_VOLUME_1L,
+	WM5100_ADC_DIGITAL_VOLUME_1R,
+	WM5100_ADC_DIGITAL_VOLUME_2L,
+	WM5100_ADC_DIGITAL_VOLUME_2R,
+	WM5100_ADC_DIGITAL_VOLUME_3L,
+	WM5100_ADC_DIGITAL_VOLUME_3R,
+	WM5100_ADC_DIGITAL_VOLUME_4L,
+	WM5100_ADC_DIGITAL_VOLUME_4R,
+
+	WM5100_DAC_DIGITAL_VOLUME_1L,
+	WM5100_DAC_DIGITAL_VOLUME_1R,
+	WM5100_DAC_DIGITAL_VOLUME_2L,
+	WM5100_DAC_DIGITAL_VOLUME_2R,
+	WM5100_DAC_DIGITAL_VOLUME_3L,
+	WM5100_DAC_DIGITAL_VOLUME_3R,
+	WM5100_DAC_DIGITAL_VOLUME_4L,
+	WM5100_DAC_DIGITAL_VOLUME_4R,
+	WM5100_DAC_DIGITAL_VOLUME_5L,
+	WM5100_DAC_DIGITAL_VOLUME_5R,
+	WM5100_DAC_DIGITAL_VOLUME_6L,
+	WM5100_DAC_DIGITAL_VOLUME_6R,
+};
+
+static void wm5100_set_detect_mode(struct wm5100_priv *wm5100, int the_mode)
+{
+	struct wm5100_jack_mode *mode = &wm5100->pdata.jack_modes[the_mode];
+
+	if (WARN_ON(the_mode >= ARRAY_SIZE(wm5100->pdata.jack_modes)))
+		return;
+
+	gpio_set_value_cansleep(wm5100->pdata.hp_pol, mode->hp_pol);
+	regmap_update_bits(wm5100->regmap, WM5100_ACCESSORY_DETECT_MODE_1,
+			   WM5100_ACCDET_BIAS_SRC_MASK |
+			   WM5100_ACCDET_SRC,
+			   (mode->bias << WM5100_ACCDET_BIAS_SRC_SHIFT) |
+			   mode->micd_src << WM5100_ACCDET_SRC_SHIFT);
+	regmap_update_bits(wm5100->regmap, WM5100_MISC_CONTROL,
+			   WM5100_HPCOM_SRC,
+			   mode->micd_src << WM5100_HPCOM_SRC_SHIFT);
+
+	wm5100->jack_mode = the_mode;
+
+	dev_dbg(wm5100->dev, "Set microphone polarity to %d\n",
+		wm5100->jack_mode);
+}
+
+static void wm5100_report_headphone(struct wm5100_priv *wm5100)
+{
+	dev_dbg(wm5100->dev, "Headphone detected\n");
+	wm5100->jack_detecting = false;
+	snd_soc_jack_report(wm5100->jack, SND_JACK_HEADPHONE,
+			    SND_JACK_HEADPHONE);
+
+	/* Increase the detection rate a bit for responsiveness. */
+	regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1,
+			   WM5100_ACCDET_RATE_MASK,
+			   7 << WM5100_ACCDET_RATE_SHIFT);
+}
+
+static void wm5100_micd_irq(struct wm5100_priv *wm5100)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(wm5100->regmap, WM5100_MIC_DETECT_3, &val);
+	if (ret != 0) {
+		dev_err(wm5100->dev, "Failed to read microphone status: %d\n",
+			ret);
+		return;
+	}
+
+	dev_dbg(wm5100->dev, "Microphone event: %x\n", val);
+
+	if (!(val & WM5100_ACCDET_VALID)) {
+		dev_warn(wm5100->dev, "Microphone detection state invalid\n");
+		return;
+	}
+
+	/* No accessory, reset everything and report removal */
+	if (!(val & WM5100_ACCDET_STS)) {
+		dev_dbg(wm5100->dev, "Jack removal detected\n");
+		wm5100->jack_mic = false;
+		wm5100->jack_detecting = true;
+		wm5100->jack_flips = 0;
+		snd_soc_jack_report(wm5100->jack, 0,
+				    SND_JACK_LINEOUT | SND_JACK_HEADSET |
+				    SND_JACK_BTN_0);
+
+		regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1,
+				   WM5100_ACCDET_RATE_MASK,
+				   WM5100_ACCDET_RATE_MASK);
+		return;
+	}
+
+	/* If the measurement is very high we've got a microphone,
+	 * either we just detected one or if we already reported then
+	 * we've got a button release event.
+	 */
+	if (val & 0x400) {
+		if (wm5100->jack_detecting) {
+			dev_dbg(wm5100->dev, "Microphone detected\n");
+			wm5100->jack_mic = true;
+			wm5100->jack_detecting = false;
+			snd_soc_jack_report(wm5100->jack,
+					    SND_JACK_HEADSET,
+					    SND_JACK_HEADSET | SND_JACK_BTN_0);
+
+			/* Increase poll rate to give better responsiveness
+			 * for buttons */
+			regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1,
+					   WM5100_ACCDET_RATE_MASK,
+					   5 << WM5100_ACCDET_RATE_SHIFT);
+		} else {
+			dev_dbg(wm5100->dev, "Mic button up\n");
+			snd_soc_jack_report(wm5100->jack, 0, SND_JACK_BTN_0);
+		}
+
+		return;
+	}
+
+	/* If we detected a lower impedence during initial startup
+	 * then we probably have the wrong polarity, flip it.  Don't
+	 * do this for the lowest impedences to speed up detection of
+	 * plain headphones and give up if neither polarity looks
+	 * sensible.
+	 */
+	if (wm5100->jack_detecting && (val & 0x3f8)) {
+		wm5100->jack_flips++;
+
+		if (wm5100->jack_flips > 1)
+			wm5100_report_headphone(wm5100);
+		else
+			wm5100_set_detect_mode(wm5100, !wm5100->jack_mode);
+
+		return;
+	}
+
+	/* Don't distinguish between buttons, just report any low
+	 * impedence as BTN_0.
+	 */
+	if (val & 0x3fc) {
+		if (wm5100->jack_mic) {
+			dev_dbg(wm5100->dev, "Mic button detected\n");
+			snd_soc_jack_report(wm5100->jack, SND_JACK_BTN_0,
+					    SND_JACK_BTN_0);
+		} else if (wm5100->jack_detecting) {
+			wm5100_report_headphone(wm5100);
+		}
+	}
+}
+
+int wm5100_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
+{
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	if (jack) {
+		wm5100->jack = jack;
+		wm5100->jack_detecting = true;
+		wm5100->jack_flips = 0;
+
+		wm5100_set_detect_mode(wm5100, 0);
+
+		/* Slowest detection rate, gives debounce for initial
+		 * detection */
+		snd_soc_component_update_bits(component, WM5100_MIC_DETECT_1,
+				    WM5100_ACCDET_BIAS_STARTTIME_MASK |
+				    WM5100_ACCDET_RATE_MASK,
+				    (7 << WM5100_ACCDET_BIAS_STARTTIME_SHIFT) |
+				    WM5100_ACCDET_RATE_MASK);
+
+		/* We need the charge pump to power MICBIAS */
+		snd_soc_dapm_mutex_lock(dapm);
+
+		snd_soc_dapm_force_enable_pin_unlocked(dapm, "CP2");
+		snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK");
+
+		snd_soc_dapm_sync_unlocked(dapm);
+
+		snd_soc_dapm_mutex_unlock(dapm);
+
+		/* We start off just enabling microphone detection - even a
+		 * plain headphone will trigger detection.
+		 */
+		snd_soc_component_update_bits(component, WM5100_MIC_DETECT_1,
+				    WM5100_ACCDET_ENA, WM5100_ACCDET_ENA);
+
+		snd_soc_component_update_bits(component, WM5100_INTERRUPT_STATUS_3_MASK,
+				    WM5100_IM_ACCDET_EINT, 0);
+	} else {
+		snd_soc_component_update_bits(component, WM5100_INTERRUPT_STATUS_3_MASK,
+				    WM5100_IM_HPDET_EINT |
+				    WM5100_IM_ACCDET_EINT,
+				    WM5100_IM_HPDET_EINT |
+				    WM5100_IM_ACCDET_EINT);
+		snd_soc_component_update_bits(component, WM5100_MIC_DETECT_1,
+				    WM5100_ACCDET_ENA, 0);
+		wm5100->jack = NULL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm5100_detect);
+
+static irqreturn_t wm5100_irq(int irq, void *data)
+{
+	struct wm5100_priv *wm5100 = data;
+	irqreturn_t status = IRQ_NONE;
+	unsigned int irq_val, mask_val;
+	int ret;
+
+	ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_3, &irq_val);
+	if (ret < 0) {
+		dev_err(wm5100->dev, "Failed to read IRQ status 3: %d\n",
+			ret);
+		irq_val = 0;
+	}
+
+	ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_3_MASK,
+			  &mask_val);
+	if (ret < 0) {
+		dev_err(wm5100->dev, "Failed to read IRQ mask 3: %d\n",
+			ret);
+		mask_val = 0xffff;
+	}
+
+	irq_val &= ~mask_val;
+
+	regmap_write(wm5100->regmap, WM5100_INTERRUPT_STATUS_3, irq_val);
+
+	if (irq_val)
+		status = IRQ_HANDLED;
+
+	wm5100_log_status3(wm5100, irq_val);
+
+	if (irq_val & WM5100_FLL1_LOCK_EINT) {
+		dev_dbg(wm5100->dev, "FLL1 locked\n");
+		complete(&wm5100->fll[0].lock);
+	}
+	if (irq_val & WM5100_FLL2_LOCK_EINT) {
+		dev_dbg(wm5100->dev, "FLL2 locked\n");
+		complete(&wm5100->fll[1].lock);
+	}
+
+	if (irq_val & WM5100_ACCDET_EINT)
+		wm5100_micd_irq(wm5100);
+
+	ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_4, &irq_val);
+	if (ret < 0) {
+		dev_err(wm5100->dev, "Failed to read IRQ status 4: %d\n",
+			ret);
+		irq_val = 0;
+	}
+
+	ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_4_MASK,
+			  &mask_val);
+	if (ret < 0) {
+		dev_err(wm5100->dev, "Failed to read IRQ mask 4: %d\n",
+			ret);
+		mask_val = 0xffff;
+	}
+
+	irq_val &= ~mask_val;
+
+	if (irq_val)
+		status = IRQ_HANDLED;
+
+	regmap_write(wm5100->regmap, WM5100_INTERRUPT_STATUS_4, irq_val);
+
+	wm5100_log_status4(wm5100, irq_val);
+
+	return status;
+}
+
+static irqreturn_t wm5100_edge_irq(int irq, void *data)
+{
+	irqreturn_t ret = IRQ_NONE;
+	irqreturn_t val;
+
+	do {
+		val = wm5100_irq(irq, data);
+		if (val != IRQ_NONE)
+			ret = val;
+	} while (val != IRQ_NONE);
+
+	return ret;
+}
+
+#ifdef CONFIG_GPIOLIB
+static void wm5100_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct wm5100_priv *wm5100 = gpiochip_get_data(chip);
+
+	regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset,
+			   WM5100_GP1_LVL, !!value << WM5100_GP1_LVL_SHIFT);
+}
+
+static int wm5100_gpio_direction_out(struct gpio_chip *chip,
+				     unsigned offset, int value)
+{
+	struct wm5100_priv *wm5100 = gpiochip_get_data(chip);
+	int val, ret;
+
+	val = (1 << WM5100_GP1_FN_SHIFT) | (!!value << WM5100_GP1_LVL_SHIFT);
+
+	ret = regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset,
+				 WM5100_GP1_FN_MASK | WM5100_GP1_DIR |
+				 WM5100_GP1_LVL, val);
+	if (ret < 0)
+		return ret;
+	else
+		return 0;
+}
+
+static int wm5100_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct wm5100_priv *wm5100 = gpiochip_get_data(chip);
+	unsigned int reg;
+	int ret;
+
+	ret = regmap_read(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset, &reg);
+	if (ret < 0)
+		return ret;
+
+	return (reg & WM5100_GP1_LVL) != 0;
+}
+
+static int wm5100_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+	struct wm5100_priv *wm5100 = gpiochip_get_data(chip);
+
+	return regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset,
+				  WM5100_GP1_FN_MASK | WM5100_GP1_DIR,
+				  (1 << WM5100_GP1_FN_SHIFT) |
+				  (1 << WM5100_GP1_DIR_SHIFT));
+}
+
+static const struct gpio_chip wm5100_template_chip = {
+	.label			= "wm5100",
+	.owner			= THIS_MODULE,
+	.direction_output	= wm5100_gpio_direction_out,
+	.set			= wm5100_gpio_set,
+	.direction_input	= wm5100_gpio_direction_in,
+	.get			= wm5100_gpio_get,
+	.can_sleep		= 1,
+};
+
+static void wm5100_init_gpio(struct i2c_client *i2c)
+{
+	struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
+	int ret;
+
+	wm5100->gpio_chip = wm5100_template_chip;
+	wm5100->gpio_chip.ngpio = 6;
+	wm5100->gpio_chip.parent = &i2c->dev;
+
+	if (wm5100->pdata.gpio_base)
+		wm5100->gpio_chip.base = wm5100->pdata.gpio_base;
+	else
+		wm5100->gpio_chip.base = -1;
+
+	ret = gpiochip_add_data(&wm5100->gpio_chip, wm5100);
+	if (ret != 0)
+		dev_err(&i2c->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm5100_free_gpio(struct i2c_client *i2c)
+{
+	struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
+
+	gpiochip_remove(&wm5100->gpio_chip);
+}
+#else
+static void wm5100_init_gpio(struct i2c_client *i2c)
+{
+}
+
+static void wm5100_free_gpio(struct i2c_client *i2c)
+{
+}
+#endif
+
+static int wm5100_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
+	int ret, i;
+
+	wm5100->component = component;
+
+	for (i = 0; i < ARRAY_SIZE(wm5100_dig_vu); i++)
+		snd_soc_component_update_bits(component, wm5100_dig_vu[i], WM5100_OUT_VU,
+				    WM5100_OUT_VU);
+
+	/* Don't debounce interrupts to support use of SYSCLK only */
+	snd_soc_component_write(component, WM5100_IRQ_DEBOUNCE_1, 0);
+	snd_soc_component_write(component, WM5100_IRQ_DEBOUNCE_2, 0);
+
+	/* TODO: check if we're symmetric */
+
+	if (i2c->irq)
+		snd_soc_dapm_new_controls(dapm, wm5100_dapm_widgets_noirq,
+					  ARRAY_SIZE(wm5100_dapm_widgets_noirq));
+
+	if (wm5100->pdata.hp_pol) {
+		ret = gpio_request_one(wm5100->pdata.hp_pol,
+				       GPIOF_OUT_INIT_HIGH, "WM5100 HP_POL");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request HP_POL %d: %d\n",
+				wm5100->pdata.hp_pol, ret);
+			goto err_gpio;
+		}
+	}
+
+	return 0;
+
+err_gpio:
+
+	return ret;
+}
+
+static void wm5100_remove(struct snd_soc_component *component)
+{
+	struct wm5100_priv *wm5100 = snd_soc_component_get_drvdata(component);
+
+	if (wm5100->pdata.hp_pol) {
+		gpio_free(wm5100->pdata.hp_pol);
+	}
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm5100 = {
+	.probe			= wm5100_probe,
+	.remove			= wm5100_remove,
+	.set_sysclk		= wm5100_set_sysclk,
+	.set_pll		= wm5100_set_fll,
+	.seq_notifier		= wm5100_seq_notifier,
+	.controls		= wm5100_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm5100_snd_controls),
+	.dapm_widgets		= wm5100_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm5100_dapm_widgets),
+	.dapm_routes		= wm5100_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm5100_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm5100_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+
+	.max_register = WM5100_MAX_REGISTER,
+	.reg_defaults = wm5100_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm5100_reg_defaults),
+	.volatile_reg = wm5100_volatile_register,
+	.readable_reg = wm5100_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const unsigned int wm5100_mic_ctrl_reg[] = {
+	WM5100_IN1L_CONTROL,
+	WM5100_IN2L_CONTROL,
+	WM5100_IN3L_CONTROL,
+	WM5100_IN4L_CONTROL,
+};
+
+static int wm5100_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm5100_pdata *pdata = dev_get_platdata(&i2c->dev);
+	struct wm5100_priv *wm5100;
+	unsigned int reg;
+	int ret, i, irq_flags;
+
+	wm5100 = devm_kzalloc(&i2c->dev, sizeof(struct wm5100_priv),
+			      GFP_KERNEL);
+	if (wm5100 == NULL)
+		return -ENOMEM;
+
+	wm5100->dev = &i2c->dev;
+
+	wm5100->regmap = devm_regmap_init_i2c(i2c, &wm5100_regmap);
+	if (IS_ERR(wm5100->regmap)) {
+		ret = PTR_ERR(wm5100->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm5100->fll); i++)
+		init_completion(&wm5100->fll[i].lock);
+
+	if (pdata)
+		wm5100->pdata = *pdata;
+
+	i2c_set_clientdata(i2c, wm5100);
+
+	for (i = 0; i < ARRAY_SIZE(wm5100->core_supplies); i++)
+		wm5100->core_supplies[i].supply = wm5100_core_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev,
+				      ARRAY_SIZE(wm5100->core_supplies),
+				      wm5100->core_supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request core supplies: %d\n",
+			ret);
+		goto err;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
+				    wm5100->core_supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable core supplies: %d\n",
+			ret);
+		goto err;
+	}
+
+	if (wm5100->pdata.ldo_ena) {
+		ret = gpio_request_one(wm5100->pdata.ldo_ena,
+				       GPIOF_OUT_INIT_HIGH, "WM5100 LDOENA");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n",
+				wm5100->pdata.ldo_ena, ret);
+			goto err_enable;
+		}
+		msleep(2);
+	}
+
+	if (wm5100->pdata.reset) {
+		ret = gpio_request_one(wm5100->pdata.reset,
+				       GPIOF_OUT_INIT_HIGH, "WM5100 /RESET");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n",
+				wm5100->pdata.reset, ret);
+			goto err_ldo;
+		}
+	}
+
+	ret = regmap_read(wm5100->regmap, WM5100_SOFTWARE_RESET, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
+		goto err_reset;
+	}
+	switch (reg) {
+	case 0x8997:
+	case 0x5100:
+		break;
+
+	default:
+		dev_err(&i2c->dev, "Device is not a WM5100, ID is %x\n", reg);
+		ret = -EINVAL;
+		goto err_reset;
+	}
+
+	ret = regmap_read(wm5100->regmap, WM5100_DEVICE_REVISION, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read revision register\n");
+		goto err_reset;
+	}
+	wm5100->rev = reg & WM5100_DEVICE_REVISION_MASK;
+
+	dev_info(&i2c->dev, "revision %c\n", wm5100->rev + 'A');
+
+	ret = wm5100_reset(wm5100);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to issue reset\n");
+		goto err_reset;
+	}
+
+	switch (wm5100->rev) {
+	case 0:
+		ret = regmap_register_patch(wm5100->regmap,
+					    wm5100_reva_patches,
+					    ARRAY_SIZE(wm5100_reva_patches));
+		if (ret != 0) {
+			dev_err(&i2c->dev, "Failed to register patches: %d\n",
+				ret);
+			goto err_reset;
+		}
+		break;
+	default:
+		break;
+	}
+
+
+	wm5100_init_gpio(i2c);
+
+	for (i = 0; i < ARRAY_SIZE(wm5100->pdata.gpio_defaults); i++) {
+		if (!wm5100->pdata.gpio_defaults[i])
+			continue;
+
+		regmap_write(wm5100->regmap, WM5100_GPIO_CTRL_1 + i,
+			     wm5100->pdata.gpio_defaults[i]);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm5100->pdata.in_mode); i++) {
+		regmap_update_bits(wm5100->regmap, wm5100_mic_ctrl_reg[i],
+				   WM5100_IN1_MODE_MASK |
+				   WM5100_IN1_DMIC_SUP_MASK,
+				   (wm5100->pdata.in_mode[i] <<
+				    WM5100_IN1_MODE_SHIFT) |
+				   (wm5100->pdata.dmic_sup[i] <<
+				    WM5100_IN1_DMIC_SUP_SHIFT));
+	}
+
+	if (i2c->irq) {
+		if (wm5100->pdata.irq_flags)
+			irq_flags = wm5100->pdata.irq_flags;
+		else
+			irq_flags = IRQF_TRIGGER_LOW;
+
+		irq_flags |= IRQF_ONESHOT;
+
+		if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+			ret = request_threaded_irq(i2c->irq, NULL,
+						   wm5100_edge_irq, irq_flags,
+						   "wm5100", wm5100);
+		else
+			ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq,
+						   irq_flags, "wm5100",
+						   wm5100);
+
+		if (ret != 0) {
+			dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
+				i2c->irq, ret);
+		} else {
+			/* Enable default interrupts */
+			regmap_update_bits(wm5100->regmap,
+					   WM5100_INTERRUPT_STATUS_3_MASK,
+					   WM5100_IM_SPK_SHUTDOWN_WARN_EINT |
+					   WM5100_IM_SPK_SHUTDOWN_EINT |
+					   WM5100_IM_ASRC2_LOCK_EINT |
+					   WM5100_IM_ASRC1_LOCK_EINT |
+					   WM5100_IM_FLL2_LOCK_EINT |
+					   WM5100_IM_FLL1_LOCK_EINT |
+					   WM5100_CLKGEN_ERR_EINT |
+					   WM5100_CLKGEN_ERR_ASYNC_EINT, 0);
+
+			regmap_update_bits(wm5100->regmap,
+					   WM5100_INTERRUPT_STATUS_4_MASK,
+					   WM5100_AIF3_ERR_EINT |
+					   WM5100_AIF2_ERR_EINT |
+					   WM5100_AIF1_ERR_EINT |
+					   WM5100_CTRLIF_ERR_EINT |
+					   WM5100_ISRC2_UNDERCLOCKED_EINT |
+					   WM5100_ISRC1_UNDERCLOCKED_EINT |
+					   WM5100_FX_UNDERCLOCKED_EINT |
+					   WM5100_AIF3_UNDERCLOCKED_EINT |
+					   WM5100_AIF2_UNDERCLOCKED_EINT |
+					   WM5100_AIF1_UNDERCLOCKED_EINT |
+					   WM5100_ASRC_UNDERCLOCKED_EINT |
+					   WM5100_DAC_UNDERCLOCKED_EINT |
+					   WM5100_ADC_UNDERCLOCKED_EINT |
+					   WM5100_MIXER_UNDERCLOCKED_EINT, 0);
+		}
+	}
+
+	pm_runtime_set_active(&i2c->dev);
+	pm_runtime_enable(&i2c->dev);
+	pm_request_idle(&i2c->dev);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_wm5100, wm5100_dai,
+				     ARRAY_SIZE(wm5100_dai));
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register WM5100: %d\n", ret);
+		goto err_reset;
+	}
+
+	return ret;
+
+err_reset:
+	if (i2c->irq)
+		free_irq(i2c->irq, wm5100);
+	wm5100_free_gpio(i2c);
+	if (wm5100->pdata.reset) {
+		gpio_set_value_cansleep(wm5100->pdata.reset, 0);
+		gpio_free(wm5100->pdata.reset);
+	}
+err_ldo:
+	if (wm5100->pdata.ldo_ena) {
+		gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
+		gpio_free(wm5100->pdata.ldo_ena);
+	}
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
+			       wm5100->core_supplies);
+err:
+	return ret;
+}
+
+static int wm5100_i2c_remove(struct i2c_client *i2c)
+{
+	struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, wm5100);
+	wm5100_free_gpio(i2c);
+	if (wm5100->pdata.reset) {
+		gpio_set_value_cansleep(wm5100->pdata.reset, 0);
+		gpio_free(wm5100->pdata.reset);
+	}
+	if (wm5100->pdata.ldo_ena) {
+		gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
+		gpio_free(wm5100->pdata.ldo_ena);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm5100_runtime_suspend(struct device *dev)
+{
+	struct wm5100_priv *wm5100 = dev_get_drvdata(dev);
+
+	regcache_cache_only(wm5100->regmap, true);
+	regcache_mark_dirty(wm5100->regmap);
+	if (wm5100->pdata.ldo_ena)
+		gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
+	regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
+			       wm5100->core_supplies);
+
+	return 0;
+}
+
+static int wm5100_runtime_resume(struct device *dev)
+{
+	struct wm5100_priv *wm5100 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
+				    wm5100->core_supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable supplies: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (wm5100->pdata.ldo_ena) {
+		gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 1);
+		msleep(2);
+	}
+
+	regcache_cache_only(wm5100->regmap, false);
+	regcache_sync(wm5100->regmap);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops wm5100_pm = {
+	SET_RUNTIME_PM_OPS(wm5100_runtime_suspend, wm5100_runtime_resume,
+			   NULL)
+};
+
+static const struct i2c_device_id wm5100_i2c_id[] = {
+	{ "wm5100", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm5100_i2c_id);
+
+static struct i2c_driver wm5100_i2c_driver = {
+	.driver = {
+		.name = "wm5100",
+		.pm = &wm5100_pm,
+	},
+	.probe =    wm5100_i2c_probe,
+	.remove =   wm5100_i2c_remove,
+	.id_table = wm5100_i2c_id,
+};
+
+module_i2c_driver(wm5100_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM5100 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm5100.h b/sound/soc/codecs/wm5100.h
new file mode 100644
index 0000000..6076493
--- /dev/null
+++ b/sound/soc/codecs/wm5100.h
@@ -0,0 +1,5315 @@
+/*
+ * wm5100.h  --  WM5100 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef WM5100_ASOC_H
+#define WM5100_ASOC_H
+
+#include <sound/soc.h>
+#include <linux/regmap.h>
+
+int wm5100_detect(struct snd_soc_component *component, struct snd_soc_jack *jack);
+
+#define WM5100_CLK_AIF1     1
+#define WM5100_CLK_AIF2     2
+#define WM5100_CLK_AIF3     3
+#define WM5100_CLK_SYSCLK   4
+#define WM5100_CLK_ASYNCCLK 5
+#define WM5100_CLK_32KHZ    6
+#define WM5100_CLK_OPCLK    7
+
+#define WM5100_CLKSRC_MCLK1    0
+#define WM5100_CLKSRC_MCLK2    1
+#define WM5100_CLKSRC_SYSCLK   2
+#define WM5100_CLKSRC_FLL1     4
+#define WM5100_CLKSRC_FLL2     5
+#define WM5100_CLKSRC_AIF1BCLK 8
+#define WM5100_CLKSRC_AIF2BCLK 9
+#define WM5100_CLKSRC_AIF3BCLK 10
+#define WM5100_CLKSRC_ASYNCCLK 0x100
+
+#define WM5100_FLL1 1
+#define WM5100_FLL2 2
+
+#define WM5100_FLL_SRC_MCLK1    0x0
+#define WM5100_FLL_SRC_MCLK2    0x1
+#define WM5100_FLL_SRC_FLL1     0x4
+#define WM5100_FLL_SRC_FLL2     0x5
+#define WM5100_FLL_SRC_AIF1BCLK 0x8
+#define WM5100_FLL_SRC_AIF2BCLK 0x9
+#define WM5100_FLL_SRC_AIF3BCLK 0xa
+
+/*
+ * Register values.
+ */
+#define WM5100_SOFTWARE_RESET                   0x00
+#define WM5100_DEVICE_REVISION                  0x01
+#define WM5100_CTRL_IF_1                        0x10
+#define WM5100_TONE_GENERATOR_1                 0x20
+#define WM5100_PWM_DRIVE_1                      0x30
+#define WM5100_PWM_DRIVE_2                      0x31
+#define WM5100_PWM_DRIVE_3                      0x32
+#define WM5100_CLOCKING_1                       0x100
+#define WM5100_CLOCKING_3                       0x101
+#define WM5100_CLOCKING_4                       0x102
+#define WM5100_CLOCKING_5                       0x103
+#define WM5100_CLOCKING_6                       0x104
+#define WM5100_CLOCKING_7                       0x107
+#define WM5100_CLOCKING_8                       0x108
+#define WM5100_ASRC_ENABLE                      0x120
+#define WM5100_ASRC_STATUS                      0x121
+#define WM5100_ASRC_RATE1                       0x122
+#define WM5100_ISRC_1_CTRL_1                    0x141
+#define WM5100_ISRC_1_CTRL_2                    0x142
+#define WM5100_ISRC_2_CTRL1                     0x143
+#define WM5100_ISRC_2_CTRL_2                    0x144
+#define WM5100_FLL1_CONTROL_1                   0x182
+#define WM5100_FLL1_CONTROL_2                   0x183
+#define WM5100_FLL1_CONTROL_3                   0x184
+#define WM5100_FLL1_CONTROL_5                   0x186
+#define WM5100_FLL1_CONTROL_6                   0x187
+#define WM5100_FLL1_EFS_1                       0x188
+#define WM5100_FLL2_CONTROL_1                   0x1A2
+#define WM5100_FLL2_CONTROL_2                   0x1A3
+#define WM5100_FLL2_CONTROL_3                   0x1A4
+#define WM5100_FLL2_CONTROL_5                   0x1A6
+#define WM5100_FLL2_CONTROL_6                   0x1A7
+#define WM5100_FLL2_EFS_1                       0x1A8
+#define WM5100_MIC_CHARGE_PUMP_1                0x200
+#define WM5100_MIC_CHARGE_PUMP_2                0x201
+#define WM5100_HP_CHARGE_PUMP_1                 0x202
+#define WM5100_LDO1_CONTROL                     0x211
+#define WM5100_MIC_BIAS_CTRL_1                  0x215
+#define WM5100_MIC_BIAS_CTRL_2                  0x216
+#define WM5100_MIC_BIAS_CTRL_3                  0x217
+#define WM5100_ACCESSORY_DETECT_MODE_1          0x280
+#define WM5100_HEADPHONE_DETECT_1               0x288
+#define WM5100_HEADPHONE_DETECT_2               0x289
+#define WM5100_MIC_DETECT_1                     0x290
+#define WM5100_MIC_DETECT_2                     0x291
+#define WM5100_MIC_DETECT_3                     0x292
+#define WM5100_MISC_CONTROL                     0x2BB
+#define WM5100_INPUT_ENABLES                    0x301
+#define WM5100_INPUT_ENABLES_STATUS             0x302
+#define WM5100_IN1L_CONTROL                     0x310
+#define WM5100_IN1R_CONTROL                     0x311
+#define WM5100_IN2L_CONTROL                     0x312
+#define WM5100_IN2R_CONTROL                     0x313
+#define WM5100_IN3L_CONTROL                     0x314
+#define WM5100_IN3R_CONTROL                     0x315
+#define WM5100_IN4L_CONTROL                     0x316
+#define WM5100_IN4R_CONTROL                     0x317
+#define WM5100_RXANC_SRC                        0x318
+#define WM5100_INPUT_VOLUME_RAMP                0x319
+#define WM5100_ADC_DIGITAL_VOLUME_1L            0x320
+#define WM5100_ADC_DIGITAL_VOLUME_1R            0x321
+#define WM5100_ADC_DIGITAL_VOLUME_2L            0x322
+#define WM5100_ADC_DIGITAL_VOLUME_2R            0x323
+#define WM5100_ADC_DIGITAL_VOLUME_3L            0x324
+#define WM5100_ADC_DIGITAL_VOLUME_3R            0x325
+#define WM5100_ADC_DIGITAL_VOLUME_4L            0x326
+#define WM5100_ADC_DIGITAL_VOLUME_4R            0x327
+#define WM5100_OUTPUT_ENABLES_2                 0x401
+#define WM5100_OUTPUT_STATUS_1                  0x402
+#define WM5100_OUTPUT_STATUS_2                  0x403
+#define WM5100_CHANNEL_ENABLES_1                0x408
+#define WM5100_OUT_VOLUME_1L                    0x410
+#define WM5100_OUT_VOLUME_1R                    0x411
+#define WM5100_DAC_VOLUME_LIMIT_1L              0x412
+#define WM5100_DAC_VOLUME_LIMIT_1R              0x413
+#define WM5100_OUT_VOLUME_2L                    0x414
+#define WM5100_OUT_VOLUME_2R                    0x415
+#define WM5100_DAC_VOLUME_LIMIT_2L              0x416
+#define WM5100_DAC_VOLUME_LIMIT_2R              0x417
+#define WM5100_OUT_VOLUME_3L                    0x418
+#define WM5100_OUT_VOLUME_3R                    0x419
+#define WM5100_DAC_VOLUME_LIMIT_3L              0x41A
+#define WM5100_DAC_VOLUME_LIMIT_3R              0x41B
+#define WM5100_OUT_VOLUME_4L                    0x41C
+#define WM5100_OUT_VOLUME_4R                    0x41D
+#define WM5100_DAC_VOLUME_LIMIT_5L              0x41E
+#define WM5100_DAC_VOLUME_LIMIT_5R              0x41F
+#define WM5100_DAC_VOLUME_LIMIT_6L              0x420
+#define WM5100_DAC_VOLUME_LIMIT_6R              0x421
+#define WM5100_DAC_AEC_CONTROL_1                0x440
+#define WM5100_OUTPUT_VOLUME_RAMP               0x441
+#define WM5100_DAC_DIGITAL_VOLUME_1L            0x480
+#define WM5100_DAC_DIGITAL_VOLUME_1R            0x481
+#define WM5100_DAC_DIGITAL_VOLUME_2L            0x482
+#define WM5100_DAC_DIGITAL_VOLUME_2R            0x483
+#define WM5100_DAC_DIGITAL_VOLUME_3L            0x484
+#define WM5100_DAC_DIGITAL_VOLUME_3R            0x485
+#define WM5100_DAC_DIGITAL_VOLUME_4L            0x486
+#define WM5100_DAC_DIGITAL_VOLUME_4R            0x487
+#define WM5100_DAC_DIGITAL_VOLUME_5L            0x488
+#define WM5100_DAC_DIGITAL_VOLUME_5R            0x489
+#define WM5100_DAC_DIGITAL_VOLUME_6L            0x48A
+#define WM5100_DAC_DIGITAL_VOLUME_6R            0x48B
+#define WM5100_PDM_SPK1_CTRL_1                  0x4C0
+#define WM5100_PDM_SPK1_CTRL_2                  0x4C1
+#define WM5100_PDM_SPK2_CTRL_1                  0x4C2
+#define WM5100_PDM_SPK2_CTRL_2                  0x4C3
+#define WM5100_AUDIO_IF_1_1                     0x500
+#define WM5100_AUDIO_IF_1_2                     0x501
+#define WM5100_AUDIO_IF_1_3                     0x502
+#define WM5100_AUDIO_IF_1_4                     0x503
+#define WM5100_AUDIO_IF_1_5                     0x504
+#define WM5100_AUDIO_IF_1_6                     0x505
+#define WM5100_AUDIO_IF_1_7                     0x506
+#define WM5100_AUDIO_IF_1_8                     0x507
+#define WM5100_AUDIO_IF_1_9                     0x508
+#define WM5100_AUDIO_IF_1_10                    0x509
+#define WM5100_AUDIO_IF_1_11                    0x50A
+#define WM5100_AUDIO_IF_1_12                    0x50B
+#define WM5100_AUDIO_IF_1_13                    0x50C
+#define WM5100_AUDIO_IF_1_14                    0x50D
+#define WM5100_AUDIO_IF_1_15                    0x50E
+#define WM5100_AUDIO_IF_1_16                    0x50F
+#define WM5100_AUDIO_IF_1_17                    0x510
+#define WM5100_AUDIO_IF_1_18                    0x511
+#define WM5100_AUDIO_IF_1_19                    0x512
+#define WM5100_AUDIO_IF_1_20                    0x513
+#define WM5100_AUDIO_IF_1_21                    0x514
+#define WM5100_AUDIO_IF_1_22                    0x515
+#define WM5100_AUDIO_IF_1_23                    0x516
+#define WM5100_AUDIO_IF_1_24                    0x517
+#define WM5100_AUDIO_IF_1_25                    0x518
+#define WM5100_AUDIO_IF_1_26                    0x519
+#define WM5100_AUDIO_IF_1_27                    0x51A
+#define WM5100_AUDIO_IF_2_1                     0x540
+#define WM5100_AUDIO_IF_2_2                     0x541
+#define WM5100_AUDIO_IF_2_3                     0x542
+#define WM5100_AUDIO_IF_2_4                     0x543
+#define WM5100_AUDIO_IF_2_5                     0x544
+#define WM5100_AUDIO_IF_2_6                     0x545
+#define WM5100_AUDIO_IF_2_7                     0x546
+#define WM5100_AUDIO_IF_2_8                     0x547
+#define WM5100_AUDIO_IF_2_9                     0x548
+#define WM5100_AUDIO_IF_2_10                    0x549
+#define WM5100_AUDIO_IF_2_11                    0x54A
+#define WM5100_AUDIO_IF_2_18                    0x551
+#define WM5100_AUDIO_IF_2_19                    0x552
+#define WM5100_AUDIO_IF_2_26                    0x559
+#define WM5100_AUDIO_IF_2_27                    0x55A
+#define WM5100_AUDIO_IF_3_1                     0x580
+#define WM5100_AUDIO_IF_3_2                     0x581
+#define WM5100_AUDIO_IF_3_3                     0x582
+#define WM5100_AUDIO_IF_3_4                     0x583
+#define WM5100_AUDIO_IF_3_5                     0x584
+#define WM5100_AUDIO_IF_3_6                     0x585
+#define WM5100_AUDIO_IF_3_7                     0x586
+#define WM5100_AUDIO_IF_3_8                     0x587
+#define WM5100_AUDIO_IF_3_9                     0x588
+#define WM5100_AUDIO_IF_3_10                    0x589
+#define WM5100_AUDIO_IF_3_11                    0x58A
+#define WM5100_AUDIO_IF_3_18                    0x591
+#define WM5100_AUDIO_IF_3_19                    0x592
+#define WM5100_AUDIO_IF_3_26                    0x599
+#define WM5100_AUDIO_IF_3_27                    0x59A
+#define WM5100_PWM1MIX_INPUT_1_SOURCE           0x640
+#define WM5100_PWM1MIX_INPUT_1_VOLUME           0x641
+#define WM5100_PWM1MIX_INPUT_2_SOURCE           0x642
+#define WM5100_PWM1MIX_INPUT_2_VOLUME           0x643
+#define WM5100_PWM1MIX_INPUT_3_SOURCE           0x644
+#define WM5100_PWM1MIX_INPUT_3_VOLUME           0x645
+#define WM5100_PWM1MIX_INPUT_4_SOURCE           0x646
+#define WM5100_PWM1MIX_INPUT_4_VOLUME           0x647
+#define WM5100_PWM2MIX_INPUT_1_SOURCE           0x648
+#define WM5100_PWM2MIX_INPUT_1_VOLUME           0x649
+#define WM5100_PWM2MIX_INPUT_2_SOURCE           0x64A
+#define WM5100_PWM2MIX_INPUT_2_VOLUME           0x64B
+#define WM5100_PWM2MIX_INPUT_3_SOURCE           0x64C
+#define WM5100_PWM2MIX_INPUT_3_VOLUME           0x64D
+#define WM5100_PWM2MIX_INPUT_4_SOURCE           0x64E
+#define WM5100_PWM2MIX_INPUT_4_VOLUME           0x64F
+#define WM5100_OUT1LMIX_INPUT_1_SOURCE          0x680
+#define WM5100_OUT1LMIX_INPUT_1_VOLUME          0x681
+#define WM5100_OUT1LMIX_INPUT_2_SOURCE          0x682
+#define WM5100_OUT1LMIX_INPUT_2_VOLUME          0x683
+#define WM5100_OUT1LMIX_INPUT_3_SOURCE          0x684
+#define WM5100_OUT1LMIX_INPUT_3_VOLUME          0x685
+#define WM5100_OUT1LMIX_INPUT_4_SOURCE          0x686
+#define WM5100_OUT1LMIX_INPUT_4_VOLUME          0x687
+#define WM5100_OUT1RMIX_INPUT_1_SOURCE          0x688
+#define WM5100_OUT1RMIX_INPUT_1_VOLUME          0x689
+#define WM5100_OUT1RMIX_INPUT_2_SOURCE          0x68A
+#define WM5100_OUT1RMIX_INPUT_2_VOLUME          0x68B
+#define WM5100_OUT1RMIX_INPUT_3_SOURCE          0x68C
+#define WM5100_OUT1RMIX_INPUT_3_VOLUME          0x68D
+#define WM5100_OUT1RMIX_INPUT_4_SOURCE          0x68E
+#define WM5100_OUT1RMIX_INPUT_4_VOLUME          0x68F
+#define WM5100_OUT2LMIX_INPUT_1_SOURCE          0x690
+#define WM5100_OUT2LMIX_INPUT_1_VOLUME          0x691
+#define WM5100_OUT2LMIX_INPUT_2_SOURCE          0x692
+#define WM5100_OUT2LMIX_INPUT_2_VOLUME          0x693
+#define WM5100_OUT2LMIX_INPUT_3_SOURCE          0x694
+#define WM5100_OUT2LMIX_INPUT_3_VOLUME          0x695
+#define WM5100_OUT2LMIX_INPUT_4_SOURCE          0x696
+#define WM5100_OUT2LMIX_INPUT_4_VOLUME          0x697
+#define WM5100_OUT2RMIX_INPUT_1_SOURCE          0x698
+#define WM5100_OUT2RMIX_INPUT_1_VOLUME          0x699
+#define WM5100_OUT2RMIX_INPUT_2_SOURCE          0x69A
+#define WM5100_OUT2RMIX_INPUT_2_VOLUME          0x69B
+#define WM5100_OUT2RMIX_INPUT_3_SOURCE          0x69C
+#define WM5100_OUT2RMIX_INPUT_3_VOLUME          0x69D
+#define WM5100_OUT2RMIX_INPUT_4_SOURCE          0x69E
+#define WM5100_OUT2RMIX_INPUT_4_VOLUME          0x69F
+#define WM5100_OUT3LMIX_INPUT_1_SOURCE          0x6A0
+#define WM5100_OUT3LMIX_INPUT_1_VOLUME          0x6A1
+#define WM5100_OUT3LMIX_INPUT_2_SOURCE          0x6A2
+#define WM5100_OUT3LMIX_INPUT_2_VOLUME          0x6A3
+#define WM5100_OUT3LMIX_INPUT_3_SOURCE          0x6A4
+#define WM5100_OUT3LMIX_INPUT_3_VOLUME          0x6A5
+#define WM5100_OUT3LMIX_INPUT_4_SOURCE          0x6A6
+#define WM5100_OUT3LMIX_INPUT_4_VOLUME          0x6A7
+#define WM5100_OUT3RMIX_INPUT_1_SOURCE          0x6A8
+#define WM5100_OUT3RMIX_INPUT_1_VOLUME          0x6A9
+#define WM5100_OUT3RMIX_INPUT_2_SOURCE          0x6AA
+#define WM5100_OUT3RMIX_INPUT_2_VOLUME          0x6AB
+#define WM5100_OUT3RMIX_INPUT_3_SOURCE          0x6AC
+#define WM5100_OUT3RMIX_INPUT_3_VOLUME          0x6AD
+#define WM5100_OUT3RMIX_INPUT_4_SOURCE          0x6AE
+#define WM5100_OUT3RMIX_INPUT_4_VOLUME          0x6AF
+#define WM5100_OUT4LMIX_INPUT_1_SOURCE          0x6B0
+#define WM5100_OUT4LMIX_INPUT_1_VOLUME          0x6B1
+#define WM5100_OUT4LMIX_INPUT_2_SOURCE          0x6B2
+#define WM5100_OUT4LMIX_INPUT_2_VOLUME          0x6B3
+#define WM5100_OUT4LMIX_INPUT_3_SOURCE          0x6B4
+#define WM5100_OUT4LMIX_INPUT_3_VOLUME          0x6B5
+#define WM5100_OUT4LMIX_INPUT_4_SOURCE          0x6B6
+#define WM5100_OUT4LMIX_INPUT_4_VOLUME          0x6B7
+#define WM5100_OUT4RMIX_INPUT_1_SOURCE          0x6B8
+#define WM5100_OUT4RMIX_INPUT_1_VOLUME          0x6B9
+#define WM5100_OUT4RMIX_INPUT_2_SOURCE          0x6BA
+#define WM5100_OUT4RMIX_INPUT_2_VOLUME          0x6BB
+#define WM5100_OUT4RMIX_INPUT_3_SOURCE          0x6BC
+#define WM5100_OUT4RMIX_INPUT_3_VOLUME          0x6BD
+#define WM5100_OUT4RMIX_INPUT_4_SOURCE          0x6BE
+#define WM5100_OUT4RMIX_INPUT_4_VOLUME          0x6BF
+#define WM5100_OUT5LMIX_INPUT_1_SOURCE          0x6C0
+#define WM5100_OUT5LMIX_INPUT_1_VOLUME          0x6C1
+#define WM5100_OUT5LMIX_INPUT_2_SOURCE          0x6C2
+#define WM5100_OUT5LMIX_INPUT_2_VOLUME          0x6C3
+#define WM5100_OUT5LMIX_INPUT_3_SOURCE          0x6C4
+#define WM5100_OUT5LMIX_INPUT_3_VOLUME          0x6C5
+#define WM5100_OUT5LMIX_INPUT_4_SOURCE          0x6C6
+#define WM5100_OUT5LMIX_INPUT_4_VOLUME          0x6C7
+#define WM5100_OUT5RMIX_INPUT_1_SOURCE          0x6C8
+#define WM5100_OUT5RMIX_INPUT_1_VOLUME          0x6C9
+#define WM5100_OUT5RMIX_INPUT_2_SOURCE          0x6CA
+#define WM5100_OUT5RMIX_INPUT_2_VOLUME          0x6CB
+#define WM5100_OUT5RMIX_INPUT_3_SOURCE          0x6CC
+#define WM5100_OUT5RMIX_INPUT_3_VOLUME          0x6CD
+#define WM5100_OUT5RMIX_INPUT_4_SOURCE          0x6CE
+#define WM5100_OUT5RMIX_INPUT_4_VOLUME          0x6CF
+#define WM5100_OUT6LMIX_INPUT_1_SOURCE          0x6D0
+#define WM5100_OUT6LMIX_INPUT_1_VOLUME          0x6D1
+#define WM5100_OUT6LMIX_INPUT_2_SOURCE          0x6D2
+#define WM5100_OUT6LMIX_INPUT_2_VOLUME          0x6D3
+#define WM5100_OUT6LMIX_INPUT_3_SOURCE          0x6D4
+#define WM5100_OUT6LMIX_INPUT_3_VOLUME          0x6D5
+#define WM5100_OUT6LMIX_INPUT_4_SOURCE          0x6D6
+#define WM5100_OUT6LMIX_INPUT_4_VOLUME          0x6D7
+#define WM5100_OUT6RMIX_INPUT_1_SOURCE          0x6D8
+#define WM5100_OUT6RMIX_INPUT_1_VOLUME          0x6D9
+#define WM5100_OUT6RMIX_INPUT_2_SOURCE          0x6DA
+#define WM5100_OUT6RMIX_INPUT_2_VOLUME          0x6DB
+#define WM5100_OUT6RMIX_INPUT_3_SOURCE          0x6DC
+#define WM5100_OUT6RMIX_INPUT_3_VOLUME          0x6DD
+#define WM5100_OUT6RMIX_INPUT_4_SOURCE          0x6DE
+#define WM5100_OUT6RMIX_INPUT_4_VOLUME          0x6DF
+#define WM5100_AIF1TX1MIX_INPUT_1_SOURCE        0x700
+#define WM5100_AIF1TX1MIX_INPUT_1_VOLUME        0x701
+#define WM5100_AIF1TX1MIX_INPUT_2_SOURCE        0x702
+#define WM5100_AIF1TX1MIX_INPUT_2_VOLUME        0x703
+#define WM5100_AIF1TX1MIX_INPUT_3_SOURCE        0x704
+#define WM5100_AIF1TX1MIX_INPUT_3_VOLUME        0x705
+#define WM5100_AIF1TX1MIX_INPUT_4_SOURCE        0x706
+#define WM5100_AIF1TX1MIX_INPUT_4_VOLUME        0x707
+#define WM5100_AIF1TX2MIX_INPUT_1_SOURCE        0x708
+#define WM5100_AIF1TX2MIX_INPUT_1_VOLUME        0x709
+#define WM5100_AIF1TX2MIX_INPUT_2_SOURCE        0x70A
+#define WM5100_AIF1TX2MIX_INPUT_2_VOLUME        0x70B
+#define WM5100_AIF1TX2MIX_INPUT_3_SOURCE        0x70C
+#define WM5100_AIF1TX2MIX_INPUT_3_VOLUME        0x70D
+#define WM5100_AIF1TX2MIX_INPUT_4_SOURCE        0x70E
+#define WM5100_AIF1TX2MIX_INPUT_4_VOLUME        0x70F
+#define WM5100_AIF1TX3MIX_INPUT_1_SOURCE        0x710
+#define WM5100_AIF1TX3MIX_INPUT_1_VOLUME        0x711
+#define WM5100_AIF1TX3MIX_INPUT_2_SOURCE        0x712
+#define WM5100_AIF1TX3MIX_INPUT_2_VOLUME        0x713
+#define WM5100_AIF1TX3MIX_INPUT_3_SOURCE        0x714
+#define WM5100_AIF1TX3MIX_INPUT_3_VOLUME        0x715
+#define WM5100_AIF1TX3MIX_INPUT_4_SOURCE        0x716
+#define WM5100_AIF1TX3MIX_INPUT_4_VOLUME        0x717
+#define WM5100_AIF1TX4MIX_INPUT_1_SOURCE        0x718
+#define WM5100_AIF1TX4MIX_INPUT_1_VOLUME        0x719
+#define WM5100_AIF1TX4MIX_INPUT_2_SOURCE        0x71A
+#define WM5100_AIF1TX4MIX_INPUT_2_VOLUME        0x71B
+#define WM5100_AIF1TX4MIX_INPUT_3_SOURCE        0x71C
+#define WM5100_AIF1TX4MIX_INPUT_3_VOLUME        0x71D
+#define WM5100_AIF1TX4MIX_INPUT_4_SOURCE        0x71E
+#define WM5100_AIF1TX4MIX_INPUT_4_VOLUME        0x71F
+#define WM5100_AIF1TX5MIX_INPUT_1_SOURCE        0x720
+#define WM5100_AIF1TX5MIX_INPUT_1_VOLUME        0x721
+#define WM5100_AIF1TX5MIX_INPUT_2_SOURCE        0x722
+#define WM5100_AIF1TX5MIX_INPUT_2_VOLUME        0x723
+#define WM5100_AIF1TX5MIX_INPUT_3_SOURCE        0x724
+#define WM5100_AIF1TX5MIX_INPUT_3_VOLUME        0x725
+#define WM5100_AIF1TX5MIX_INPUT_4_SOURCE        0x726
+#define WM5100_AIF1TX5MIX_INPUT_4_VOLUME        0x727
+#define WM5100_AIF1TX6MIX_INPUT_1_SOURCE        0x728
+#define WM5100_AIF1TX6MIX_INPUT_1_VOLUME        0x729
+#define WM5100_AIF1TX6MIX_INPUT_2_SOURCE        0x72A
+#define WM5100_AIF1TX6MIX_INPUT_2_VOLUME        0x72B
+#define WM5100_AIF1TX6MIX_INPUT_3_SOURCE        0x72C
+#define WM5100_AIF1TX6MIX_INPUT_3_VOLUME        0x72D
+#define WM5100_AIF1TX6MIX_INPUT_4_SOURCE        0x72E
+#define WM5100_AIF1TX6MIX_INPUT_4_VOLUME        0x72F
+#define WM5100_AIF1TX7MIX_INPUT_1_SOURCE        0x730
+#define WM5100_AIF1TX7MIX_INPUT_1_VOLUME        0x731
+#define WM5100_AIF1TX7MIX_INPUT_2_SOURCE        0x732
+#define WM5100_AIF1TX7MIX_INPUT_2_VOLUME        0x733
+#define WM5100_AIF1TX7MIX_INPUT_3_SOURCE        0x734
+#define WM5100_AIF1TX7MIX_INPUT_3_VOLUME        0x735
+#define WM5100_AIF1TX7MIX_INPUT_4_SOURCE        0x736
+#define WM5100_AIF1TX7MIX_INPUT_4_VOLUME        0x737
+#define WM5100_AIF1TX8MIX_INPUT_1_SOURCE        0x738
+#define WM5100_AIF1TX8MIX_INPUT_1_VOLUME        0x739
+#define WM5100_AIF1TX8MIX_INPUT_2_SOURCE        0x73A
+#define WM5100_AIF1TX8MIX_INPUT_2_VOLUME        0x73B
+#define WM5100_AIF1TX8MIX_INPUT_3_SOURCE        0x73C
+#define WM5100_AIF1TX8MIX_INPUT_3_VOLUME        0x73D
+#define WM5100_AIF1TX8MIX_INPUT_4_SOURCE        0x73E
+#define WM5100_AIF1TX8MIX_INPUT_4_VOLUME        0x73F
+#define WM5100_AIF2TX1MIX_INPUT_1_SOURCE        0x740
+#define WM5100_AIF2TX1MIX_INPUT_1_VOLUME        0x741
+#define WM5100_AIF2TX1MIX_INPUT_2_SOURCE        0x742
+#define WM5100_AIF2TX1MIX_INPUT_2_VOLUME        0x743
+#define WM5100_AIF2TX1MIX_INPUT_3_SOURCE        0x744
+#define WM5100_AIF2TX1MIX_INPUT_3_VOLUME        0x745
+#define WM5100_AIF2TX1MIX_INPUT_4_SOURCE        0x746
+#define WM5100_AIF2TX1MIX_INPUT_4_VOLUME        0x747
+#define WM5100_AIF2TX2MIX_INPUT_1_SOURCE        0x748
+#define WM5100_AIF2TX2MIX_INPUT_1_VOLUME        0x749
+#define WM5100_AIF2TX2MIX_INPUT_2_SOURCE        0x74A
+#define WM5100_AIF2TX2MIX_INPUT_2_VOLUME        0x74B
+#define WM5100_AIF2TX2MIX_INPUT_3_SOURCE        0x74C
+#define WM5100_AIF2TX2MIX_INPUT_3_VOLUME        0x74D
+#define WM5100_AIF2TX2MIX_INPUT_4_SOURCE        0x74E
+#define WM5100_AIF2TX2MIX_INPUT_4_VOLUME        0x74F
+#define WM5100_AIF3TX1MIX_INPUT_1_SOURCE        0x780
+#define WM5100_AIF3TX1MIX_INPUT_1_VOLUME        0x781
+#define WM5100_AIF3TX1MIX_INPUT_2_SOURCE        0x782
+#define WM5100_AIF3TX1MIX_INPUT_2_VOLUME        0x783
+#define WM5100_AIF3TX1MIX_INPUT_3_SOURCE        0x784
+#define WM5100_AIF3TX1MIX_INPUT_3_VOLUME        0x785
+#define WM5100_AIF3TX1MIX_INPUT_4_SOURCE        0x786
+#define WM5100_AIF3TX1MIX_INPUT_4_VOLUME        0x787
+#define WM5100_AIF3TX2MIX_INPUT_1_SOURCE        0x788
+#define WM5100_AIF3TX2MIX_INPUT_1_VOLUME        0x789
+#define WM5100_AIF3TX2MIX_INPUT_2_SOURCE        0x78A
+#define WM5100_AIF3TX2MIX_INPUT_2_VOLUME        0x78B
+#define WM5100_AIF3TX2MIX_INPUT_3_SOURCE        0x78C
+#define WM5100_AIF3TX2MIX_INPUT_3_VOLUME        0x78D
+#define WM5100_AIF3TX2MIX_INPUT_4_SOURCE        0x78E
+#define WM5100_AIF3TX2MIX_INPUT_4_VOLUME        0x78F
+#define WM5100_EQ1MIX_INPUT_1_SOURCE            0x880
+#define WM5100_EQ1MIX_INPUT_1_VOLUME            0x881
+#define WM5100_EQ1MIX_INPUT_2_SOURCE            0x882
+#define WM5100_EQ1MIX_INPUT_2_VOLUME            0x883
+#define WM5100_EQ1MIX_INPUT_3_SOURCE            0x884
+#define WM5100_EQ1MIX_INPUT_3_VOLUME            0x885
+#define WM5100_EQ1MIX_INPUT_4_SOURCE            0x886
+#define WM5100_EQ1MIX_INPUT_4_VOLUME            0x887
+#define WM5100_EQ2MIX_INPUT_1_SOURCE            0x888
+#define WM5100_EQ2MIX_INPUT_1_VOLUME            0x889
+#define WM5100_EQ2MIX_INPUT_2_SOURCE            0x88A
+#define WM5100_EQ2MIX_INPUT_2_VOLUME            0x88B
+#define WM5100_EQ2MIX_INPUT_3_SOURCE            0x88C
+#define WM5100_EQ2MIX_INPUT_3_VOLUME            0x88D
+#define WM5100_EQ2MIX_INPUT_4_SOURCE            0x88E
+#define WM5100_EQ2MIX_INPUT_4_VOLUME            0x88F
+#define WM5100_EQ3MIX_INPUT_1_SOURCE            0x890
+#define WM5100_EQ3MIX_INPUT_1_VOLUME            0x891
+#define WM5100_EQ3MIX_INPUT_2_SOURCE            0x892
+#define WM5100_EQ3MIX_INPUT_2_VOLUME            0x893
+#define WM5100_EQ3MIX_INPUT_3_SOURCE            0x894
+#define WM5100_EQ3MIX_INPUT_3_VOLUME            0x895
+#define WM5100_EQ3MIX_INPUT_4_SOURCE            0x896
+#define WM5100_EQ3MIX_INPUT_4_VOLUME            0x897
+#define WM5100_EQ4MIX_INPUT_1_SOURCE            0x898
+#define WM5100_EQ4MIX_INPUT_1_VOLUME            0x899
+#define WM5100_EQ4MIX_INPUT_2_SOURCE            0x89A
+#define WM5100_EQ4MIX_INPUT_2_VOLUME            0x89B
+#define WM5100_EQ4MIX_INPUT_3_SOURCE            0x89C
+#define WM5100_EQ4MIX_INPUT_3_VOLUME            0x89D
+#define WM5100_EQ4MIX_INPUT_4_SOURCE            0x89E
+#define WM5100_EQ4MIX_INPUT_4_VOLUME            0x89F
+#define WM5100_DRC1LMIX_INPUT_1_SOURCE          0x8C0
+#define WM5100_DRC1LMIX_INPUT_1_VOLUME          0x8C1
+#define WM5100_DRC1LMIX_INPUT_2_SOURCE          0x8C2
+#define WM5100_DRC1LMIX_INPUT_2_VOLUME          0x8C3
+#define WM5100_DRC1LMIX_INPUT_3_SOURCE          0x8C4
+#define WM5100_DRC1LMIX_INPUT_3_VOLUME          0x8C5
+#define WM5100_DRC1LMIX_INPUT_4_SOURCE          0x8C6
+#define WM5100_DRC1LMIX_INPUT_4_VOLUME          0x8C7
+#define WM5100_DRC1RMIX_INPUT_1_SOURCE          0x8C8
+#define WM5100_DRC1RMIX_INPUT_1_VOLUME          0x8C9
+#define WM5100_DRC1RMIX_INPUT_2_SOURCE          0x8CA
+#define WM5100_DRC1RMIX_INPUT_2_VOLUME          0x8CB
+#define WM5100_DRC1RMIX_INPUT_3_SOURCE          0x8CC
+#define WM5100_DRC1RMIX_INPUT_3_VOLUME          0x8CD
+#define WM5100_DRC1RMIX_INPUT_4_SOURCE          0x8CE
+#define WM5100_DRC1RMIX_INPUT_4_VOLUME          0x8CF
+#define WM5100_HPLP1MIX_INPUT_1_SOURCE          0x900
+#define WM5100_HPLP1MIX_INPUT_1_VOLUME          0x901
+#define WM5100_HPLP1MIX_INPUT_2_SOURCE          0x902
+#define WM5100_HPLP1MIX_INPUT_2_VOLUME          0x903
+#define WM5100_HPLP1MIX_INPUT_3_SOURCE          0x904
+#define WM5100_HPLP1MIX_INPUT_3_VOLUME          0x905
+#define WM5100_HPLP1MIX_INPUT_4_SOURCE          0x906
+#define WM5100_HPLP1MIX_INPUT_4_VOLUME          0x907
+#define WM5100_HPLP2MIX_INPUT_1_SOURCE          0x908
+#define WM5100_HPLP2MIX_INPUT_1_VOLUME          0x909
+#define WM5100_HPLP2MIX_INPUT_2_SOURCE          0x90A
+#define WM5100_HPLP2MIX_INPUT_2_VOLUME          0x90B
+#define WM5100_HPLP2MIX_INPUT_3_SOURCE          0x90C
+#define WM5100_HPLP2MIX_INPUT_3_VOLUME          0x90D
+#define WM5100_HPLP2MIX_INPUT_4_SOURCE          0x90E
+#define WM5100_HPLP2MIX_INPUT_4_VOLUME          0x90F
+#define WM5100_HPLP3MIX_INPUT_1_SOURCE          0x910
+#define WM5100_HPLP3MIX_INPUT_1_VOLUME          0x911
+#define WM5100_HPLP3MIX_INPUT_2_SOURCE          0x912
+#define WM5100_HPLP3MIX_INPUT_2_VOLUME          0x913
+#define WM5100_HPLP3MIX_INPUT_3_SOURCE          0x914
+#define WM5100_HPLP3MIX_INPUT_3_VOLUME          0x915
+#define WM5100_HPLP3MIX_INPUT_4_SOURCE          0x916
+#define WM5100_HPLP3MIX_INPUT_4_VOLUME          0x917
+#define WM5100_HPLP4MIX_INPUT_1_SOURCE          0x918
+#define WM5100_HPLP4MIX_INPUT_1_VOLUME          0x919
+#define WM5100_HPLP4MIX_INPUT_2_SOURCE          0x91A
+#define WM5100_HPLP4MIX_INPUT_2_VOLUME          0x91B
+#define WM5100_HPLP4MIX_INPUT_3_SOURCE          0x91C
+#define WM5100_HPLP4MIX_INPUT_3_VOLUME          0x91D
+#define WM5100_HPLP4MIX_INPUT_4_SOURCE          0x91E
+#define WM5100_HPLP4MIX_INPUT_4_VOLUME          0x91F
+#define WM5100_DSP1LMIX_INPUT_1_SOURCE          0x940
+#define WM5100_DSP1LMIX_INPUT_1_VOLUME          0x941
+#define WM5100_DSP1LMIX_INPUT_2_SOURCE          0x942
+#define WM5100_DSP1LMIX_INPUT_2_VOLUME          0x943
+#define WM5100_DSP1LMIX_INPUT_3_SOURCE          0x944
+#define WM5100_DSP1LMIX_INPUT_3_VOLUME          0x945
+#define WM5100_DSP1LMIX_INPUT_4_SOURCE          0x946
+#define WM5100_DSP1LMIX_INPUT_4_VOLUME          0x947
+#define WM5100_DSP1RMIX_INPUT_1_SOURCE          0x948
+#define WM5100_DSP1RMIX_INPUT_1_VOLUME          0x949
+#define WM5100_DSP1RMIX_INPUT_2_SOURCE          0x94A
+#define WM5100_DSP1RMIX_INPUT_2_VOLUME          0x94B
+#define WM5100_DSP1RMIX_INPUT_3_SOURCE          0x94C
+#define WM5100_DSP1RMIX_INPUT_3_VOLUME          0x94D
+#define WM5100_DSP1RMIX_INPUT_4_SOURCE          0x94E
+#define WM5100_DSP1RMIX_INPUT_4_VOLUME          0x94F
+#define WM5100_DSP1AUX1MIX_INPUT_1_SOURCE       0x950
+#define WM5100_DSP1AUX2MIX_INPUT_1_SOURCE       0x958
+#define WM5100_DSP1AUX3MIX_INPUT_1_SOURCE       0x960
+#define WM5100_DSP1AUX4MIX_INPUT_1_SOURCE       0x968
+#define WM5100_DSP1AUX5MIX_INPUT_1_SOURCE       0x970
+#define WM5100_DSP1AUX6MIX_INPUT_1_SOURCE       0x978
+#define WM5100_DSP2LMIX_INPUT_1_SOURCE          0x980
+#define WM5100_DSP2LMIX_INPUT_1_VOLUME          0x981
+#define WM5100_DSP2LMIX_INPUT_2_SOURCE          0x982
+#define WM5100_DSP2LMIX_INPUT_2_VOLUME          0x983
+#define WM5100_DSP2LMIX_INPUT_3_SOURCE          0x984
+#define WM5100_DSP2LMIX_INPUT_3_VOLUME          0x985
+#define WM5100_DSP2LMIX_INPUT_4_SOURCE          0x986
+#define WM5100_DSP2LMIX_INPUT_4_VOLUME          0x987
+#define WM5100_DSP2RMIX_INPUT_1_SOURCE          0x988
+#define WM5100_DSP2RMIX_INPUT_1_VOLUME          0x989
+#define WM5100_DSP2RMIX_INPUT_2_SOURCE          0x98A
+#define WM5100_DSP2RMIX_INPUT_2_VOLUME          0x98B
+#define WM5100_DSP2RMIX_INPUT_3_SOURCE          0x98C
+#define WM5100_DSP2RMIX_INPUT_3_VOLUME          0x98D
+#define WM5100_DSP2RMIX_INPUT_4_SOURCE          0x98E
+#define WM5100_DSP2RMIX_INPUT_4_VOLUME          0x98F
+#define WM5100_DSP2AUX1MIX_INPUT_1_SOURCE       0x990
+#define WM5100_DSP2AUX2MIX_INPUT_1_SOURCE       0x998
+#define WM5100_DSP2AUX3MIX_INPUT_1_SOURCE       0x9A0
+#define WM5100_DSP2AUX4MIX_INPUT_1_SOURCE       0x9A8
+#define WM5100_DSP2AUX5MIX_INPUT_1_SOURCE       0x9B0
+#define WM5100_DSP2AUX6MIX_INPUT_1_SOURCE       0x9B8
+#define WM5100_DSP3LMIX_INPUT_1_SOURCE          0x9C0
+#define WM5100_DSP3LMIX_INPUT_1_VOLUME          0x9C1
+#define WM5100_DSP3LMIX_INPUT_2_SOURCE          0x9C2
+#define WM5100_DSP3LMIX_INPUT_2_VOLUME          0x9C3
+#define WM5100_DSP3LMIX_INPUT_3_SOURCE          0x9C4
+#define WM5100_DSP3LMIX_INPUT_3_VOLUME          0x9C5
+#define WM5100_DSP3LMIX_INPUT_4_SOURCE          0x9C6
+#define WM5100_DSP3LMIX_INPUT_4_VOLUME          0x9C7
+#define WM5100_DSP3RMIX_INPUT_1_SOURCE          0x9C8
+#define WM5100_DSP3RMIX_INPUT_1_VOLUME          0x9C9
+#define WM5100_DSP3RMIX_INPUT_2_SOURCE          0x9CA
+#define WM5100_DSP3RMIX_INPUT_2_VOLUME          0x9CB
+#define WM5100_DSP3RMIX_INPUT_3_SOURCE          0x9CC
+#define WM5100_DSP3RMIX_INPUT_3_VOLUME          0x9CD
+#define WM5100_DSP3RMIX_INPUT_4_SOURCE          0x9CE
+#define WM5100_DSP3RMIX_INPUT_4_VOLUME          0x9CF
+#define WM5100_DSP3AUX1MIX_INPUT_1_SOURCE       0x9D0
+#define WM5100_DSP3AUX2MIX_INPUT_1_SOURCE       0x9D8
+#define WM5100_DSP3AUX3MIX_INPUT_1_SOURCE       0x9E0
+#define WM5100_DSP3AUX4MIX_INPUT_1_SOURCE       0x9E8
+#define WM5100_DSP3AUX5MIX_INPUT_1_SOURCE       0x9F0
+#define WM5100_DSP3AUX6MIX_INPUT_1_SOURCE       0x9F8
+#define WM5100_ASRC1LMIX_INPUT_1_SOURCE         0xA80
+#define WM5100_ASRC1RMIX_INPUT_1_SOURCE         0xA88
+#define WM5100_ASRC2LMIX_INPUT_1_SOURCE         0xA90
+#define WM5100_ASRC2RMIX_INPUT_1_SOURCE         0xA98
+#define WM5100_ISRC1DEC1MIX_INPUT_1_SOURCE      0xB00
+#define WM5100_ISRC1DEC2MIX_INPUT_1_SOURCE      0xB08
+#define WM5100_ISRC1DEC3MIX_INPUT_1_SOURCE      0xB10
+#define WM5100_ISRC1DEC4MIX_INPUT_1_SOURCE      0xB18
+#define WM5100_ISRC1INT1MIX_INPUT_1_SOURCE      0xB20
+#define WM5100_ISRC1INT2MIX_INPUT_1_SOURCE      0xB28
+#define WM5100_ISRC1INT3MIX_INPUT_1_SOURCE      0xB30
+#define WM5100_ISRC1INT4MIX_INPUT_1_SOURCE      0xB38
+#define WM5100_ISRC2DEC1MIX_INPUT_1_SOURCE      0xB40
+#define WM5100_ISRC2DEC2MIX_INPUT_1_SOURCE      0xB48
+#define WM5100_ISRC2DEC3MIX_INPUT_1_SOURCE      0xB50
+#define WM5100_ISRC2DEC4MIX_INPUT_1_SOURCE      0xB58
+#define WM5100_ISRC2INT1MIX_INPUT_1_SOURCE      0xB60
+#define WM5100_ISRC2INT2MIX_INPUT_1_SOURCE      0xB68
+#define WM5100_ISRC2INT3MIX_INPUT_1_SOURCE      0xB70
+#define WM5100_ISRC2INT4MIX_INPUT_1_SOURCE      0xB78
+#define WM5100_GPIO_CTRL_1                      0xC00
+#define WM5100_GPIO_CTRL_2                      0xC01
+#define WM5100_GPIO_CTRL_3                      0xC02
+#define WM5100_GPIO_CTRL_4                      0xC03
+#define WM5100_GPIO_CTRL_5                      0xC04
+#define WM5100_GPIO_CTRL_6                      0xC05
+#define WM5100_MISC_PAD_CTRL_1                  0xC23
+#define WM5100_MISC_PAD_CTRL_2                  0xC24
+#define WM5100_MISC_PAD_CTRL_3                  0xC25
+#define WM5100_MISC_PAD_CTRL_4                  0xC26
+#define WM5100_MISC_PAD_CTRL_5                  0xC27
+#define WM5100_MISC_GPIO_1                      0xC28
+#define WM5100_INTERRUPT_STATUS_1               0xD00
+#define WM5100_INTERRUPT_STATUS_2               0xD01
+#define WM5100_INTERRUPT_STATUS_3               0xD02
+#define WM5100_INTERRUPT_STATUS_4               0xD03
+#define WM5100_INTERRUPT_RAW_STATUS_2           0xD04
+#define WM5100_INTERRUPT_RAW_STATUS_3           0xD05
+#define WM5100_INTERRUPT_RAW_STATUS_4           0xD06
+#define WM5100_INTERRUPT_STATUS_1_MASK          0xD07
+#define WM5100_INTERRUPT_STATUS_2_MASK          0xD08
+#define WM5100_INTERRUPT_STATUS_3_MASK          0xD09
+#define WM5100_INTERRUPT_STATUS_4_MASK          0xD0A
+#define WM5100_INTERRUPT_CONTROL                0xD1F
+#define WM5100_IRQ_DEBOUNCE_1                   0xD20
+#define WM5100_IRQ_DEBOUNCE_2                   0xD21
+#define WM5100_FX_CTRL                          0xE00
+#define WM5100_EQ1_1                            0xE10
+#define WM5100_EQ1_2                            0xE11
+#define WM5100_EQ1_3                            0xE12
+#define WM5100_EQ1_4                            0xE13
+#define WM5100_EQ1_5                            0xE14
+#define WM5100_EQ1_6                            0xE15
+#define WM5100_EQ1_7                            0xE16
+#define WM5100_EQ1_8                            0xE17
+#define WM5100_EQ1_9                            0xE18
+#define WM5100_EQ1_10                           0xE19
+#define WM5100_EQ1_11                           0xE1A
+#define WM5100_EQ1_12                           0xE1B
+#define WM5100_EQ1_13                           0xE1C
+#define WM5100_EQ1_14                           0xE1D
+#define WM5100_EQ1_15                           0xE1E
+#define WM5100_EQ1_16                           0xE1F
+#define WM5100_EQ1_17                           0xE20
+#define WM5100_EQ1_18                           0xE21
+#define WM5100_EQ1_19                           0xE22
+#define WM5100_EQ1_20                           0xE23
+#define WM5100_EQ2_1                            0xE26
+#define WM5100_EQ2_2                            0xE27
+#define WM5100_EQ2_3                            0xE28
+#define WM5100_EQ2_4                            0xE29
+#define WM5100_EQ2_5                            0xE2A
+#define WM5100_EQ2_6                            0xE2B
+#define WM5100_EQ2_7                            0xE2C
+#define WM5100_EQ2_8                            0xE2D
+#define WM5100_EQ2_9                            0xE2E
+#define WM5100_EQ2_10                           0xE2F
+#define WM5100_EQ2_11                           0xE30
+#define WM5100_EQ2_12                           0xE31
+#define WM5100_EQ2_13                           0xE32
+#define WM5100_EQ2_14                           0xE33
+#define WM5100_EQ2_15                           0xE34
+#define WM5100_EQ2_16                           0xE35
+#define WM5100_EQ2_17                           0xE36
+#define WM5100_EQ2_18                           0xE37
+#define WM5100_EQ2_19                           0xE38
+#define WM5100_EQ2_20                           0xE39
+#define WM5100_EQ3_1                            0xE3C
+#define WM5100_EQ3_2                            0xE3D
+#define WM5100_EQ3_3                            0xE3E
+#define WM5100_EQ3_4                            0xE3F
+#define WM5100_EQ3_5                            0xE40
+#define WM5100_EQ3_6                            0xE41
+#define WM5100_EQ3_7                            0xE42
+#define WM5100_EQ3_8                            0xE43
+#define WM5100_EQ3_9                            0xE44
+#define WM5100_EQ3_10                           0xE45
+#define WM5100_EQ3_11                           0xE46
+#define WM5100_EQ3_12                           0xE47
+#define WM5100_EQ3_13                           0xE48
+#define WM5100_EQ3_14                           0xE49
+#define WM5100_EQ3_15                           0xE4A
+#define WM5100_EQ3_16                           0xE4B
+#define WM5100_EQ3_17                           0xE4C
+#define WM5100_EQ3_18                           0xE4D
+#define WM5100_EQ3_19                           0xE4E
+#define WM5100_EQ3_20                           0xE4F
+#define WM5100_EQ4_1                            0xE52
+#define WM5100_EQ4_2                            0xE53
+#define WM5100_EQ4_3                            0xE54
+#define WM5100_EQ4_4                            0xE55
+#define WM5100_EQ4_5                            0xE56
+#define WM5100_EQ4_6                            0xE57
+#define WM5100_EQ4_7                            0xE58
+#define WM5100_EQ4_8                            0xE59
+#define WM5100_EQ4_9                            0xE5A
+#define WM5100_EQ4_10                           0xE5B
+#define WM5100_EQ4_11                           0xE5C
+#define WM5100_EQ4_12                           0xE5D
+#define WM5100_EQ4_13                           0xE5E
+#define WM5100_EQ4_14                           0xE5F
+#define WM5100_EQ4_15                           0xE60
+#define WM5100_EQ4_16                           0xE61
+#define WM5100_EQ4_17                           0xE62
+#define WM5100_EQ4_18                           0xE63
+#define WM5100_EQ4_19                           0xE64
+#define WM5100_EQ4_20                           0xE65
+#define WM5100_DRC1_CTRL1                       0xE80
+#define WM5100_DRC1_CTRL2                       0xE81
+#define WM5100_DRC1_CTRL3                       0xE82
+#define WM5100_DRC1_CTRL4                       0xE83
+#define WM5100_DRC1_CTRL5                       0xE84
+#define WM5100_HPLPF1_1                         0xEC0
+#define WM5100_HPLPF1_2                         0xEC1
+#define WM5100_HPLPF2_1                         0xEC4
+#define WM5100_HPLPF2_2                         0xEC5
+#define WM5100_HPLPF3_1                         0xEC8
+#define WM5100_HPLPF3_2                         0xEC9
+#define WM5100_HPLPF4_1                         0xECC
+#define WM5100_HPLPF4_2                         0xECD
+#define WM5100_DSP1_CONTROL_1                   0xF00
+#define WM5100_DSP1_CONTROL_2                   0xF02
+#define WM5100_DSP1_CONTROL_3                   0xF03
+#define WM5100_DSP1_CONTROL_4                   0xF04
+#define WM5100_DSP1_CONTROL_5                   0xF06
+#define WM5100_DSP1_CONTROL_6                   0xF07
+#define WM5100_DSP1_CONTROL_7                   0xF08
+#define WM5100_DSP1_CONTROL_8                   0xF09
+#define WM5100_DSP1_CONTROL_9                   0xF0A
+#define WM5100_DSP1_CONTROL_10                  0xF0B
+#define WM5100_DSP1_CONTROL_11                  0xF0C
+#define WM5100_DSP1_CONTROL_12                  0xF0D
+#define WM5100_DSP1_CONTROL_13                  0xF0F
+#define WM5100_DSP1_CONTROL_14                  0xF10
+#define WM5100_DSP1_CONTROL_15                  0xF11
+#define WM5100_DSP1_CONTROL_16                  0xF12
+#define WM5100_DSP1_CONTROL_17                  0xF13
+#define WM5100_DSP1_CONTROL_18                  0xF14
+#define WM5100_DSP1_CONTROL_19                  0xF16
+#define WM5100_DSP1_CONTROL_20                  0xF17
+#define WM5100_DSP1_CONTROL_21                  0xF18
+#define WM5100_DSP1_CONTROL_22                  0xF1A
+#define WM5100_DSP1_CONTROL_23                  0xF1B
+#define WM5100_DSP1_CONTROL_24                  0xF1C
+#define WM5100_DSP1_CONTROL_25                  0xF1E
+#define WM5100_DSP1_CONTROL_26                  0xF20
+#define WM5100_DSP1_CONTROL_27                  0xF21
+#define WM5100_DSP1_CONTROL_28                  0xF22
+#define WM5100_DSP1_CONTROL_29                  0xF23
+#define WM5100_DSP1_CONTROL_30                  0xF24
+#define WM5100_DSP2_CONTROL_1                   0x1000
+#define WM5100_DSP2_CONTROL_2                   0x1002
+#define WM5100_DSP2_CONTROL_3                   0x1003
+#define WM5100_DSP2_CONTROL_4                   0x1004
+#define WM5100_DSP2_CONTROL_5                   0x1006
+#define WM5100_DSP2_CONTROL_6                   0x1007
+#define WM5100_DSP2_CONTROL_7                   0x1008
+#define WM5100_DSP2_CONTROL_8                   0x1009
+#define WM5100_DSP2_CONTROL_9                   0x100A
+#define WM5100_DSP2_CONTROL_10                  0x100B
+#define WM5100_DSP2_CONTROL_11                  0x100C
+#define WM5100_DSP2_CONTROL_12                  0x100D
+#define WM5100_DSP2_CONTROL_13                  0x100F
+#define WM5100_DSP2_CONTROL_14                  0x1010
+#define WM5100_DSP2_CONTROL_15                  0x1011
+#define WM5100_DSP2_CONTROL_16                  0x1012
+#define WM5100_DSP2_CONTROL_17                  0x1013
+#define WM5100_DSP2_CONTROL_18                  0x1014
+#define WM5100_DSP2_CONTROL_19                  0x1016
+#define WM5100_DSP2_CONTROL_20                  0x1017
+#define WM5100_DSP2_CONTROL_21                  0x1018
+#define WM5100_DSP2_CONTROL_22                  0x101A
+#define WM5100_DSP2_CONTROL_23                  0x101B
+#define WM5100_DSP2_CONTROL_24                  0x101C
+#define WM5100_DSP2_CONTROL_25                  0x101E
+#define WM5100_DSP2_CONTROL_26                  0x1020
+#define WM5100_DSP2_CONTROL_27                  0x1021
+#define WM5100_DSP2_CONTROL_28                  0x1022
+#define WM5100_DSP2_CONTROL_29                  0x1023
+#define WM5100_DSP2_CONTROL_30                  0x1024
+#define WM5100_DSP3_CONTROL_1                   0x1100
+#define WM5100_DSP3_CONTROL_2                   0x1102
+#define WM5100_DSP3_CONTROL_3                   0x1103
+#define WM5100_DSP3_CONTROL_4                   0x1104
+#define WM5100_DSP3_CONTROL_5                   0x1106
+#define WM5100_DSP3_CONTROL_6                   0x1107
+#define WM5100_DSP3_CONTROL_7                   0x1108
+#define WM5100_DSP3_CONTROL_8                   0x1109
+#define WM5100_DSP3_CONTROL_9                   0x110A
+#define WM5100_DSP3_CONTROL_10                  0x110B
+#define WM5100_DSP3_CONTROL_11                  0x110C
+#define WM5100_DSP3_CONTROL_12                  0x110D
+#define WM5100_DSP3_CONTROL_13                  0x110F
+#define WM5100_DSP3_CONTROL_14                  0x1110
+#define WM5100_DSP3_CONTROL_15                  0x1111
+#define WM5100_DSP3_CONTROL_16                  0x1112
+#define WM5100_DSP3_CONTROL_17                  0x1113
+#define WM5100_DSP3_CONTROL_18                  0x1114
+#define WM5100_DSP3_CONTROL_19                  0x1116
+#define WM5100_DSP3_CONTROL_20                  0x1117
+#define WM5100_DSP3_CONTROL_21                  0x1118
+#define WM5100_DSP3_CONTROL_22                  0x111A
+#define WM5100_DSP3_CONTROL_23                  0x111B
+#define WM5100_DSP3_CONTROL_24                  0x111C
+#define WM5100_DSP3_CONTROL_25                  0x111E
+#define WM5100_DSP3_CONTROL_26                  0x1120
+#define WM5100_DSP3_CONTROL_27                  0x1121
+#define WM5100_DSP3_CONTROL_28                  0x1122
+#define WM5100_DSP3_CONTROL_29                  0x1123
+#define WM5100_DSP3_CONTROL_30                  0x1124
+#define WM5100_DSP1_DM_0                        0x4000
+#define WM5100_DSP1_DM_1                        0x4001
+#define WM5100_DSP1_DM_2                        0x4002
+#define WM5100_DSP1_DM_3                        0x4003
+#define WM5100_DSP1_DM_508                      0x41FC
+#define WM5100_DSP1_DM_509                      0x41FD
+#define WM5100_DSP1_DM_510                      0x41FE
+#define WM5100_DSP1_DM_511                      0x41FF
+#define WM5100_DSP1_PM_0                        0x4800
+#define WM5100_DSP1_PM_1                        0x4801
+#define WM5100_DSP1_PM_2                        0x4802
+#define WM5100_DSP1_PM_3                        0x4803
+#define WM5100_DSP1_PM_4                        0x4804
+#define WM5100_DSP1_PM_5                        0x4805
+#define WM5100_DSP1_PM_1530                     0x4DFA
+#define WM5100_DSP1_PM_1531                     0x4DFB
+#define WM5100_DSP1_PM_1532                     0x4DFC
+#define WM5100_DSP1_PM_1533                     0x4DFD
+#define WM5100_DSP1_PM_1534                     0x4DFE
+#define WM5100_DSP1_PM_1535                     0x4DFF
+#define WM5100_DSP1_ZM_0                        0x5000
+#define WM5100_DSP1_ZM_1                        0x5001
+#define WM5100_DSP1_ZM_2                        0x5002
+#define WM5100_DSP1_ZM_3                        0x5003
+#define WM5100_DSP1_ZM_2044                     0x57FC
+#define WM5100_DSP1_ZM_2045                     0x57FD
+#define WM5100_DSP1_ZM_2046                     0x57FE
+#define WM5100_DSP1_ZM_2047                     0x57FF
+#define WM5100_DSP2_DM_0                        0x6000
+#define WM5100_DSP2_DM_1                        0x6001
+#define WM5100_DSP2_DM_2                        0x6002
+#define WM5100_DSP2_DM_3                        0x6003
+#define WM5100_DSP2_DM_508                      0x61FC
+#define WM5100_DSP2_DM_509                      0x61FD
+#define WM5100_DSP2_DM_510                      0x61FE
+#define WM5100_DSP2_DM_511                      0x61FF
+#define WM5100_DSP2_PM_0                        0x6800
+#define WM5100_DSP2_PM_1                        0x6801
+#define WM5100_DSP2_PM_2                        0x6802
+#define WM5100_DSP2_PM_3                        0x6803
+#define WM5100_DSP2_PM_4                        0x6804
+#define WM5100_DSP2_PM_5                        0x6805
+#define WM5100_DSP2_PM_1530                     0x6DFA
+#define WM5100_DSP2_PM_1531                     0x6DFB
+#define WM5100_DSP2_PM_1532                     0x6DFC
+#define WM5100_DSP2_PM_1533                     0x6DFD
+#define WM5100_DSP2_PM_1534                     0x6DFE
+#define WM5100_DSP2_PM_1535                     0x6DFF
+#define WM5100_DSP2_ZM_0                        0x7000
+#define WM5100_DSP2_ZM_1                        0x7001
+#define WM5100_DSP2_ZM_2                        0x7002
+#define WM5100_DSP2_ZM_3                        0x7003
+#define WM5100_DSP2_ZM_2044                     0x77FC
+#define WM5100_DSP2_ZM_2045                     0x77FD
+#define WM5100_DSP2_ZM_2046                     0x77FE
+#define WM5100_DSP2_ZM_2047                     0x77FF
+#define WM5100_DSP3_DM_0                        0x8000
+#define WM5100_DSP3_DM_1                        0x8001
+#define WM5100_DSP3_DM_2                        0x8002
+#define WM5100_DSP3_DM_3                        0x8003
+#define WM5100_DSP3_DM_508                      0x81FC
+#define WM5100_DSP3_DM_509                      0x81FD
+#define WM5100_DSP3_DM_510                      0x81FE
+#define WM5100_DSP3_DM_511                      0x81FF
+#define WM5100_DSP3_PM_0                        0x8800
+#define WM5100_DSP3_PM_1                        0x8801
+#define WM5100_DSP3_PM_2                        0x8802
+#define WM5100_DSP3_PM_3                        0x8803
+#define WM5100_DSP3_PM_4                        0x8804
+#define WM5100_DSP3_PM_5                        0x8805
+#define WM5100_DSP3_PM_1530                     0x8DFA
+#define WM5100_DSP3_PM_1531                     0x8DFB
+#define WM5100_DSP3_PM_1532                     0x8DFC
+#define WM5100_DSP3_PM_1533                     0x8DFD
+#define WM5100_DSP3_PM_1534                     0x8DFE
+#define WM5100_DSP3_PM_1535                     0x8DFF
+#define WM5100_DSP3_ZM_0                        0x9000
+#define WM5100_DSP3_ZM_1                        0x9001
+#define WM5100_DSP3_ZM_2                        0x9002
+#define WM5100_DSP3_ZM_3                        0x9003
+#define WM5100_DSP3_ZM_2044                     0x97FC
+#define WM5100_DSP3_ZM_2045                     0x97FD
+#define WM5100_DSP3_ZM_2046                     0x97FE
+#define WM5100_DSP3_ZM_2047                     0x97FF
+
+#define WM5100_REGISTER_COUNT                   1435
+#define WM5100_MAX_REGISTER                     0x97FF
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - software reset
+ */
+#define WM5100_SW_RST_DEV_ID1_MASK              0xFFFF  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM5100_SW_RST_DEV_ID1_SHIFT                  0  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM5100_SW_RST_DEV_ID1_WIDTH                 16  /* SW_RST_DEV_ID1 - [15:0] */
+
+/*
+ * R1 (0x01) - Device Revision
+ */
+#define WM5100_DEVICE_REVISION_MASK             0x000F  /* DEVICE_REVISION - [3:0] */
+#define WM5100_DEVICE_REVISION_SHIFT                 0  /* DEVICE_REVISION - [3:0] */
+#define WM5100_DEVICE_REVISION_WIDTH                 4  /* DEVICE_REVISION - [3:0] */
+
+/*
+ * R16 (0x10) - Ctrl IF 1
+ */
+#define WM5100_AUTO_INC                         0x0001  /* AUTO_INC */
+#define WM5100_AUTO_INC_MASK                    0x0001  /* AUTO_INC */
+#define WM5100_AUTO_INC_SHIFT                        0  /* AUTO_INC */
+#define WM5100_AUTO_INC_WIDTH                        1  /* AUTO_INC */
+
+/*
+ * R32 (0x20) - Tone Generator 1
+ */
+#define WM5100_TONE_RATE_MASK                   0x3000  /* TONE_RATE - [13:12] */
+#define WM5100_TONE_RATE_SHIFT                      12  /* TONE_RATE - [13:12] */
+#define WM5100_TONE_RATE_WIDTH                       2  /* TONE_RATE - [13:12] */
+#define WM5100_TONE_OFFSET_MASK                 0x0300  /* TONE_OFFSET - [9:8] */
+#define WM5100_TONE_OFFSET_SHIFT                     8  /* TONE_OFFSET - [9:8] */
+#define WM5100_TONE_OFFSET_WIDTH                     2  /* TONE_OFFSET - [9:8] */
+#define WM5100_TONE2_ENA                        0x0002  /* TONE2_ENA */
+#define WM5100_TONE2_ENA_MASK                   0x0002  /* TONE2_ENA */
+#define WM5100_TONE2_ENA_SHIFT                       1  /* TONE2_ENA */
+#define WM5100_TONE2_ENA_WIDTH                       1  /* TONE2_ENA */
+#define WM5100_TONE1_ENA                        0x0001  /* TONE1_ENA */
+#define WM5100_TONE1_ENA_MASK                   0x0001  /* TONE1_ENA */
+#define WM5100_TONE1_ENA_SHIFT                       0  /* TONE1_ENA */
+#define WM5100_TONE1_ENA_WIDTH                       1  /* TONE1_ENA */
+
+/*
+ * R48 (0x30) - PWM Drive 1
+ */
+#define WM5100_PWM_RATE_MASK                    0x3000  /* PWM_RATE - [13:12] */
+#define WM5100_PWM_RATE_SHIFT                       12  /* PWM_RATE - [13:12] */
+#define WM5100_PWM_RATE_WIDTH                        2  /* PWM_RATE - [13:12] */
+#define WM5100_PWM_CLK_SEL_MASK                 0x0300  /* PWM_CLK_SEL - [9:8] */
+#define WM5100_PWM_CLK_SEL_SHIFT                     8  /* PWM_CLK_SEL - [9:8] */
+#define WM5100_PWM_CLK_SEL_WIDTH                     2  /* PWM_CLK_SEL - [9:8] */
+#define WM5100_PWM2_OVD                         0x0020  /* PWM2_OVD */
+#define WM5100_PWM2_OVD_MASK                    0x0020  /* PWM2_OVD */
+#define WM5100_PWM2_OVD_SHIFT                        5  /* PWM2_OVD */
+#define WM5100_PWM2_OVD_WIDTH                        1  /* PWM2_OVD */
+#define WM5100_PWM1_OVD                         0x0010  /* PWM1_OVD */
+#define WM5100_PWM1_OVD_MASK                    0x0010  /* PWM1_OVD */
+#define WM5100_PWM1_OVD_SHIFT                        4  /* PWM1_OVD */
+#define WM5100_PWM1_OVD_WIDTH                        1  /* PWM1_OVD */
+#define WM5100_PWM2_ENA                         0x0002  /* PWM2_ENA */
+#define WM5100_PWM2_ENA_MASK                    0x0002  /* PWM2_ENA */
+#define WM5100_PWM2_ENA_SHIFT                        1  /* PWM2_ENA */
+#define WM5100_PWM2_ENA_WIDTH                        1  /* PWM2_ENA */
+#define WM5100_PWM1_ENA                         0x0001  /* PWM1_ENA */
+#define WM5100_PWM1_ENA_MASK                    0x0001  /* PWM1_ENA */
+#define WM5100_PWM1_ENA_SHIFT                        0  /* PWM1_ENA */
+#define WM5100_PWM1_ENA_WIDTH                        1  /* PWM1_ENA */
+
+/*
+ * R49 (0x31) - PWM Drive 2
+ */
+#define WM5100_PWM1_LVL_MASK                    0x03FF  /* PWM1_LVL - [9:0] */
+#define WM5100_PWM1_LVL_SHIFT                        0  /* PWM1_LVL - [9:0] */
+#define WM5100_PWM1_LVL_WIDTH                       10  /* PWM1_LVL - [9:0] */
+
+/*
+ * R50 (0x32) - PWM Drive 3
+ */
+#define WM5100_PWM2_LVL_MASK                    0x03FF  /* PWM2_LVL - [9:0] */
+#define WM5100_PWM2_LVL_SHIFT                        0  /* PWM2_LVL - [9:0] */
+#define WM5100_PWM2_LVL_WIDTH                       10  /* PWM2_LVL - [9:0] */
+
+/*
+ * R256 (0x100) - Clocking 1
+ */
+#define WM5100_CLK_32K_SRC_MASK                 0x000F  /* CLK_32K_SRC - [3:0] */
+#define WM5100_CLK_32K_SRC_SHIFT                     0  /* CLK_32K_SRC - [3:0] */
+#define WM5100_CLK_32K_SRC_WIDTH                     4  /* CLK_32K_SRC - [3:0] */
+
+/*
+ * R257 (0x101) - Clocking 3
+ */
+#define WM5100_SYSCLK_FREQ_MASK                 0x0700  /* SYSCLK_FREQ - [10:8] */
+#define WM5100_SYSCLK_FREQ_SHIFT                     8  /* SYSCLK_FREQ - [10:8] */
+#define WM5100_SYSCLK_FREQ_WIDTH                     3  /* SYSCLK_FREQ - [10:8] */
+#define WM5100_SYSCLK_ENA                       0x0040  /* SYSCLK_ENA */
+#define WM5100_SYSCLK_ENA_MASK                  0x0040  /* SYSCLK_ENA */
+#define WM5100_SYSCLK_ENA_SHIFT                      6  /* SYSCLK_ENA */
+#define WM5100_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+#define WM5100_SYSCLK_SRC_MASK                  0x000F  /* SYSCLK_SRC - [3:0] */
+#define WM5100_SYSCLK_SRC_SHIFT                      0  /* SYSCLK_SRC - [3:0] */
+#define WM5100_SYSCLK_SRC_WIDTH                      4  /* SYSCLK_SRC - [3:0] */
+
+/*
+ * R258 (0x102) - Clocking 4
+ */
+#define WM5100_SAMPLE_RATE_1_MASK               0x001F  /* SAMPLE_RATE_1 - [4:0] */
+#define WM5100_SAMPLE_RATE_1_SHIFT                   0  /* SAMPLE_RATE_1 - [4:0] */
+#define WM5100_SAMPLE_RATE_1_WIDTH                   5  /* SAMPLE_RATE_1 - [4:0] */
+
+/*
+ * R259 (0x103) - Clocking 5
+ */
+#define WM5100_SAMPLE_RATE_2_MASK               0x001F  /* SAMPLE_RATE_2 - [4:0] */
+#define WM5100_SAMPLE_RATE_2_SHIFT                   0  /* SAMPLE_RATE_2 - [4:0] */
+#define WM5100_SAMPLE_RATE_2_WIDTH                   5  /* SAMPLE_RATE_2 - [4:0] */
+
+/*
+ * R260 (0x104) - Clocking 6
+ */
+#define WM5100_SAMPLE_RATE_3_MASK               0x001F  /* SAMPLE_RATE_3 - [4:0] */
+#define WM5100_SAMPLE_RATE_3_SHIFT                   0  /* SAMPLE_RATE_3 - [4:0] */
+#define WM5100_SAMPLE_RATE_3_WIDTH                   5  /* SAMPLE_RATE_3 - [4:0] */
+
+/*
+ * R263 (0x107) - Clocking 7
+ */
+#define WM5100_ASYNC_CLK_FREQ_MASK              0x0700  /* ASYNC_CLK_FREQ - [10:8] */
+#define WM5100_ASYNC_CLK_FREQ_SHIFT                  8  /* ASYNC_CLK_FREQ - [10:8] */
+#define WM5100_ASYNC_CLK_FREQ_WIDTH                  3  /* ASYNC_CLK_FREQ - [10:8] */
+#define WM5100_ASYNC_CLK_ENA                    0x0040  /* ASYNC_CLK_ENA */
+#define WM5100_ASYNC_CLK_ENA_MASK               0x0040  /* ASYNC_CLK_ENA */
+#define WM5100_ASYNC_CLK_ENA_SHIFT                   6  /* ASYNC_CLK_ENA */
+#define WM5100_ASYNC_CLK_ENA_WIDTH                   1  /* ASYNC_CLK_ENA */
+#define WM5100_ASYNC_CLK_SRC_MASK               0x000F  /* ASYNC_CLK_SRC - [3:0] */
+#define WM5100_ASYNC_CLK_SRC_SHIFT                   0  /* ASYNC_CLK_SRC - [3:0] */
+#define WM5100_ASYNC_CLK_SRC_WIDTH                   4  /* ASYNC_CLK_SRC - [3:0] */
+
+/*
+ * R264 (0x108) - Clocking 8
+ */
+#define WM5100_ASYNC_SAMPLE_RATE_MASK           0x001F  /* ASYNC_SAMPLE_RATE - [4:0] */
+#define WM5100_ASYNC_SAMPLE_RATE_SHIFT               0  /* ASYNC_SAMPLE_RATE - [4:0] */
+#define WM5100_ASYNC_SAMPLE_RATE_WIDTH               5  /* ASYNC_SAMPLE_RATE - [4:0] */
+
+/*
+ * R288 (0x120) - ASRC_ENABLE
+ */
+#define WM5100_ASRC2L_ENA                       0x0008  /* ASRC2L_ENA */
+#define WM5100_ASRC2L_ENA_MASK                  0x0008  /* ASRC2L_ENA */
+#define WM5100_ASRC2L_ENA_SHIFT                      3  /* ASRC2L_ENA */
+#define WM5100_ASRC2L_ENA_WIDTH                      1  /* ASRC2L_ENA */
+#define WM5100_ASRC2R_ENA                       0x0004  /* ASRC2R_ENA */
+#define WM5100_ASRC2R_ENA_MASK                  0x0004  /* ASRC2R_ENA */
+#define WM5100_ASRC2R_ENA_SHIFT                      2  /* ASRC2R_ENA */
+#define WM5100_ASRC2R_ENA_WIDTH                      1  /* ASRC2R_ENA */
+#define WM5100_ASRC1L_ENA                       0x0002  /* ASRC1L_ENA */
+#define WM5100_ASRC1L_ENA_MASK                  0x0002  /* ASRC1L_ENA */
+#define WM5100_ASRC1L_ENA_SHIFT                      1  /* ASRC1L_ENA */
+#define WM5100_ASRC1L_ENA_WIDTH                      1  /* ASRC1L_ENA */
+#define WM5100_ASRC1R_ENA                       0x0001  /* ASRC1R_ENA */
+#define WM5100_ASRC1R_ENA_MASK                  0x0001  /* ASRC1R_ENA */
+#define WM5100_ASRC1R_ENA_SHIFT                      0  /* ASRC1R_ENA */
+#define WM5100_ASRC1R_ENA_WIDTH                      1  /* ASRC1R_ENA */
+
+/*
+ * R289 (0x121) - ASRC_STATUS
+ */
+#define WM5100_ASRC2L_ENA_STS                   0x0008  /* ASRC2L_ENA_STS */
+#define WM5100_ASRC2L_ENA_STS_MASK              0x0008  /* ASRC2L_ENA_STS */
+#define WM5100_ASRC2L_ENA_STS_SHIFT                  3  /* ASRC2L_ENA_STS */
+#define WM5100_ASRC2L_ENA_STS_WIDTH                  1  /* ASRC2L_ENA_STS */
+#define WM5100_ASRC2R_ENA_STS                   0x0004  /* ASRC2R_ENA_STS */
+#define WM5100_ASRC2R_ENA_STS_MASK              0x0004  /* ASRC2R_ENA_STS */
+#define WM5100_ASRC2R_ENA_STS_SHIFT                  2  /* ASRC2R_ENA_STS */
+#define WM5100_ASRC2R_ENA_STS_WIDTH                  1  /* ASRC2R_ENA_STS */
+#define WM5100_ASRC1L_ENA_STS                   0x0002  /* ASRC1L_ENA_STS */
+#define WM5100_ASRC1L_ENA_STS_MASK              0x0002  /* ASRC1L_ENA_STS */
+#define WM5100_ASRC1L_ENA_STS_SHIFT                  1  /* ASRC1L_ENA_STS */
+#define WM5100_ASRC1L_ENA_STS_WIDTH                  1  /* ASRC1L_ENA_STS */
+#define WM5100_ASRC1R_ENA_STS                   0x0001  /* ASRC1R_ENA_STS */
+#define WM5100_ASRC1R_ENA_STS_MASK              0x0001  /* ASRC1R_ENA_STS */
+#define WM5100_ASRC1R_ENA_STS_SHIFT                  0  /* ASRC1R_ENA_STS */
+#define WM5100_ASRC1R_ENA_STS_WIDTH                  1  /* ASRC1R_ENA_STS */
+
+/*
+ * R290 (0x122) - ASRC_RATE1
+ */
+#define WM5100_ASRC_RATE1_MASK                  0x0006  /* ASRC_RATE1 - [2:1] */
+#define WM5100_ASRC_RATE1_SHIFT                      1  /* ASRC_RATE1 - [2:1] */
+#define WM5100_ASRC_RATE1_WIDTH                      2  /* ASRC_RATE1 - [2:1] */
+
+/*
+ * R321 (0x141) - ISRC 1 CTRL 1
+ */
+#define WM5100_ISRC1_DFS_ENA                    0x2000  /* ISRC1_DFS_ENA */
+#define WM5100_ISRC1_DFS_ENA_MASK               0x2000  /* ISRC1_DFS_ENA */
+#define WM5100_ISRC1_DFS_ENA_SHIFT                  13  /* ISRC1_DFS_ENA */
+#define WM5100_ISRC1_DFS_ENA_WIDTH                   1  /* ISRC1_DFS_ENA */
+#define WM5100_ISRC1_CLK_SEL_MASK               0x0300  /* ISRC1_CLK_SEL - [9:8] */
+#define WM5100_ISRC1_CLK_SEL_SHIFT                   8  /* ISRC1_CLK_SEL - [9:8] */
+#define WM5100_ISRC1_CLK_SEL_WIDTH                   2  /* ISRC1_CLK_SEL - [9:8] */
+#define WM5100_ISRC1_FSH_MASK                   0x000C  /* ISRC1_FSH - [3:2] */
+#define WM5100_ISRC1_FSH_SHIFT                       2  /* ISRC1_FSH - [3:2] */
+#define WM5100_ISRC1_FSH_WIDTH                       2  /* ISRC1_FSH - [3:2] */
+#define WM5100_ISRC1_FSL_MASK                   0x0003  /* ISRC1_FSL - [1:0] */
+#define WM5100_ISRC1_FSL_SHIFT                       0  /* ISRC1_FSL - [1:0] */
+#define WM5100_ISRC1_FSL_WIDTH                       2  /* ISRC1_FSL - [1:0] */
+
+/*
+ * R322 (0x142) - ISRC 1 CTRL 2
+ */
+#define WM5100_ISRC1_INT1_ENA                   0x8000  /* ISRC1_INT1_ENA */
+#define WM5100_ISRC1_INT1_ENA_MASK              0x8000  /* ISRC1_INT1_ENA */
+#define WM5100_ISRC1_INT1_ENA_SHIFT                 15  /* ISRC1_INT1_ENA */
+#define WM5100_ISRC1_INT1_ENA_WIDTH                  1  /* ISRC1_INT1_ENA */
+#define WM5100_ISRC1_INT2_ENA                   0x4000  /* ISRC1_INT2_ENA */
+#define WM5100_ISRC1_INT2_ENA_MASK              0x4000  /* ISRC1_INT2_ENA */
+#define WM5100_ISRC1_INT2_ENA_SHIFT                 14  /* ISRC1_INT2_ENA */
+#define WM5100_ISRC1_INT2_ENA_WIDTH                  1  /* ISRC1_INT2_ENA */
+#define WM5100_ISRC1_INT3_ENA                   0x2000  /* ISRC1_INT3_ENA */
+#define WM5100_ISRC1_INT3_ENA_MASK              0x2000  /* ISRC1_INT3_ENA */
+#define WM5100_ISRC1_INT3_ENA_SHIFT                 13  /* ISRC1_INT3_ENA */
+#define WM5100_ISRC1_INT3_ENA_WIDTH                  1  /* ISRC1_INT3_ENA */
+#define WM5100_ISRC1_INT4_ENA                   0x1000  /* ISRC1_INT4_ENA */
+#define WM5100_ISRC1_INT4_ENA_MASK              0x1000  /* ISRC1_INT4_ENA */
+#define WM5100_ISRC1_INT4_ENA_SHIFT                 12  /* ISRC1_INT4_ENA */
+#define WM5100_ISRC1_INT4_ENA_WIDTH                  1  /* ISRC1_INT4_ENA */
+#define WM5100_ISRC1_DEC1_ENA                   0x0200  /* ISRC1_DEC1_ENA */
+#define WM5100_ISRC1_DEC1_ENA_MASK              0x0200  /* ISRC1_DEC1_ENA */
+#define WM5100_ISRC1_DEC1_ENA_SHIFT                  9  /* ISRC1_DEC1_ENA */
+#define WM5100_ISRC1_DEC1_ENA_WIDTH                  1  /* ISRC1_DEC1_ENA */
+#define WM5100_ISRC1_DEC2_ENA                   0x0100  /* ISRC1_DEC2_ENA */
+#define WM5100_ISRC1_DEC2_ENA_MASK              0x0100  /* ISRC1_DEC2_ENA */
+#define WM5100_ISRC1_DEC2_ENA_SHIFT                  8  /* ISRC1_DEC2_ENA */
+#define WM5100_ISRC1_DEC2_ENA_WIDTH                  1  /* ISRC1_DEC2_ENA */
+#define WM5100_ISRC1_DEC3_ENA                   0x0080  /* ISRC1_DEC3_ENA */
+#define WM5100_ISRC1_DEC3_ENA_MASK              0x0080  /* ISRC1_DEC3_ENA */
+#define WM5100_ISRC1_DEC3_ENA_SHIFT                  7  /* ISRC1_DEC3_ENA */
+#define WM5100_ISRC1_DEC3_ENA_WIDTH                  1  /* ISRC1_DEC3_ENA */
+#define WM5100_ISRC1_DEC4_ENA                   0x0040  /* ISRC1_DEC4_ENA */
+#define WM5100_ISRC1_DEC4_ENA_MASK              0x0040  /* ISRC1_DEC4_ENA */
+#define WM5100_ISRC1_DEC4_ENA_SHIFT                  6  /* ISRC1_DEC4_ENA */
+#define WM5100_ISRC1_DEC4_ENA_WIDTH                  1  /* ISRC1_DEC4_ENA */
+#define WM5100_ISRC1_NOTCH_ENA                  0x0001  /* ISRC1_NOTCH_ENA */
+#define WM5100_ISRC1_NOTCH_ENA_MASK             0x0001  /* ISRC1_NOTCH_ENA */
+#define WM5100_ISRC1_NOTCH_ENA_SHIFT                 0  /* ISRC1_NOTCH_ENA */
+#define WM5100_ISRC1_NOTCH_ENA_WIDTH                 1  /* ISRC1_NOTCH_ENA */
+
+/*
+ * R323 (0x143) - ISRC 2 CTRL1
+ */
+#define WM5100_ISRC2_DFS_ENA                    0x2000  /* ISRC2_DFS_ENA */
+#define WM5100_ISRC2_DFS_ENA_MASK               0x2000  /* ISRC2_DFS_ENA */
+#define WM5100_ISRC2_DFS_ENA_SHIFT                  13  /* ISRC2_DFS_ENA */
+#define WM5100_ISRC2_DFS_ENA_WIDTH                   1  /* ISRC2_DFS_ENA */
+#define WM5100_ISRC2_CLK_SEL_MASK               0x0300  /* ISRC2_CLK_SEL - [9:8] */
+#define WM5100_ISRC2_CLK_SEL_SHIFT                   8  /* ISRC2_CLK_SEL - [9:8] */
+#define WM5100_ISRC2_CLK_SEL_WIDTH                   2  /* ISRC2_CLK_SEL - [9:8] */
+#define WM5100_ISRC2_FSH_MASK                   0x000C  /* ISRC2_FSH - [3:2] */
+#define WM5100_ISRC2_FSH_SHIFT                       2  /* ISRC2_FSH - [3:2] */
+#define WM5100_ISRC2_FSH_WIDTH                       2  /* ISRC2_FSH - [3:2] */
+#define WM5100_ISRC2_FSL_MASK                   0x0003  /* ISRC2_FSL - [1:0] */
+#define WM5100_ISRC2_FSL_SHIFT                       0  /* ISRC2_FSL - [1:0] */
+#define WM5100_ISRC2_FSL_WIDTH                       2  /* ISRC2_FSL - [1:0] */
+
+/*
+ * R324 (0x144) - ISRC 2 CTRL 2
+ */
+#define WM5100_ISRC2_INT1_ENA                   0x8000  /* ISRC2_INT1_ENA */
+#define WM5100_ISRC2_INT1_ENA_MASK              0x8000  /* ISRC2_INT1_ENA */
+#define WM5100_ISRC2_INT1_ENA_SHIFT                 15  /* ISRC2_INT1_ENA */
+#define WM5100_ISRC2_INT1_ENA_WIDTH                  1  /* ISRC2_INT1_ENA */
+#define WM5100_ISRC2_INT2_ENA                   0x4000  /* ISRC2_INT2_ENA */
+#define WM5100_ISRC2_INT2_ENA_MASK              0x4000  /* ISRC2_INT2_ENA */
+#define WM5100_ISRC2_INT2_ENA_SHIFT                 14  /* ISRC2_INT2_ENA */
+#define WM5100_ISRC2_INT2_ENA_WIDTH                  1  /* ISRC2_INT2_ENA */
+#define WM5100_ISRC2_INT3_ENA                   0x2000  /* ISRC2_INT3_ENA */
+#define WM5100_ISRC2_INT3_ENA_MASK              0x2000  /* ISRC2_INT3_ENA */
+#define WM5100_ISRC2_INT3_ENA_SHIFT                 13  /* ISRC2_INT3_ENA */
+#define WM5100_ISRC2_INT3_ENA_WIDTH                  1  /* ISRC2_INT3_ENA */
+#define WM5100_ISRC2_INT4_ENA                   0x1000  /* ISRC2_INT4_ENA */
+#define WM5100_ISRC2_INT4_ENA_MASK              0x1000  /* ISRC2_INT4_ENA */
+#define WM5100_ISRC2_INT4_ENA_SHIFT                 12  /* ISRC2_INT4_ENA */
+#define WM5100_ISRC2_INT4_ENA_WIDTH                  1  /* ISRC2_INT4_ENA */
+#define WM5100_ISRC2_DEC1_ENA                   0x0200  /* ISRC2_DEC1_ENA */
+#define WM5100_ISRC2_DEC1_ENA_MASK              0x0200  /* ISRC2_DEC1_ENA */
+#define WM5100_ISRC2_DEC1_ENA_SHIFT                  9  /* ISRC2_DEC1_ENA */
+#define WM5100_ISRC2_DEC1_ENA_WIDTH                  1  /* ISRC2_DEC1_ENA */
+#define WM5100_ISRC2_DEC2_ENA                   0x0100  /* ISRC2_DEC2_ENA */
+#define WM5100_ISRC2_DEC2_ENA_MASK              0x0100  /* ISRC2_DEC2_ENA */
+#define WM5100_ISRC2_DEC2_ENA_SHIFT                  8  /* ISRC2_DEC2_ENA */
+#define WM5100_ISRC2_DEC2_ENA_WIDTH                  1  /* ISRC2_DEC2_ENA */
+#define WM5100_ISRC2_DEC3_ENA                   0x0080  /* ISRC2_DEC3_ENA */
+#define WM5100_ISRC2_DEC3_ENA_MASK              0x0080  /* ISRC2_DEC3_ENA */
+#define WM5100_ISRC2_DEC3_ENA_SHIFT                  7  /* ISRC2_DEC3_ENA */
+#define WM5100_ISRC2_DEC3_ENA_WIDTH                  1  /* ISRC2_DEC3_ENA */
+#define WM5100_ISRC2_DEC4_ENA                   0x0040  /* ISRC2_DEC4_ENA */
+#define WM5100_ISRC2_DEC4_ENA_MASK              0x0040  /* ISRC2_DEC4_ENA */
+#define WM5100_ISRC2_DEC4_ENA_SHIFT                  6  /* ISRC2_DEC4_ENA */
+#define WM5100_ISRC2_DEC4_ENA_WIDTH                  1  /* ISRC2_DEC4_ENA */
+#define WM5100_ISRC2_NOTCH_ENA                  0x0001  /* ISRC2_NOTCH_ENA */
+#define WM5100_ISRC2_NOTCH_ENA_MASK             0x0001  /* ISRC2_NOTCH_ENA */
+#define WM5100_ISRC2_NOTCH_ENA_SHIFT                 0  /* ISRC2_NOTCH_ENA */
+#define WM5100_ISRC2_NOTCH_ENA_WIDTH                 1  /* ISRC2_NOTCH_ENA */
+
+/*
+ * R386 (0x182) - FLL1 Control 1
+ */
+#define WM5100_FLL1_ENA                         0x0001  /* FLL1_ENA */
+#define WM5100_FLL1_ENA_MASK                    0x0001  /* FLL1_ENA */
+#define WM5100_FLL1_ENA_SHIFT                        0  /* FLL1_ENA */
+#define WM5100_FLL1_ENA_WIDTH                        1  /* FLL1_ENA */
+
+/*
+ * R387 (0x183) - FLL1 Control 2
+ */
+#define WM5100_FLL1_OUTDIV_MASK                 0x3F00  /* FLL1_OUTDIV - [13:8] */
+#define WM5100_FLL1_OUTDIV_SHIFT                     8  /* FLL1_OUTDIV - [13:8] */
+#define WM5100_FLL1_OUTDIV_WIDTH                     6  /* FLL1_OUTDIV - [13:8] */
+#define WM5100_FLL1_FRATIO_MASK                 0x0007  /* FLL1_FRATIO - [2:0] */
+#define WM5100_FLL1_FRATIO_SHIFT                     0  /* FLL1_FRATIO - [2:0] */
+#define WM5100_FLL1_FRATIO_WIDTH                     3  /* FLL1_FRATIO - [2:0] */
+
+/*
+ * R388 (0x184) - FLL1 Control 3
+ */
+#define WM5100_FLL1_THETA_MASK                  0xFFFF  /* FLL1_THETA - [15:0] */
+#define WM5100_FLL1_THETA_SHIFT                      0  /* FLL1_THETA - [15:0] */
+#define WM5100_FLL1_THETA_WIDTH                     16  /* FLL1_THETA - [15:0] */
+
+/*
+ * R390 (0x186) - FLL1 Control 5
+ */
+#define WM5100_FLL1_N_MASK                      0x03FF  /* FLL1_N - [9:0] */
+#define WM5100_FLL1_N_SHIFT                          0  /* FLL1_N - [9:0] */
+#define WM5100_FLL1_N_WIDTH                         10  /* FLL1_N - [9:0] */
+
+/*
+ * R391 (0x187) - FLL1 Control 6
+ */
+#define WM5100_FLL1_REFCLK_DIV_MASK             0x00C0  /* FLL1_REFCLK_DIV - [7:6] */
+#define WM5100_FLL1_REFCLK_DIV_SHIFT                 6  /* FLL1_REFCLK_DIV - [7:6] */
+#define WM5100_FLL1_REFCLK_DIV_WIDTH                 2  /* FLL1_REFCLK_DIV - [7:6] */
+#define WM5100_FLL1_REFCLK_SRC_MASK             0x000F  /* FLL1_REFCLK_SRC - [3:0] */
+#define WM5100_FLL1_REFCLK_SRC_SHIFT                 0  /* FLL1_REFCLK_SRC - [3:0] */
+#define WM5100_FLL1_REFCLK_SRC_WIDTH                 4  /* FLL1_REFCLK_SRC - [3:0] */
+
+/*
+ * R392 (0x188) - FLL1 EFS 1
+ */
+#define WM5100_FLL1_LAMBDA_MASK                 0xFFFF  /* FLL1_LAMBDA - [15:0] */
+#define WM5100_FLL1_LAMBDA_SHIFT                     0  /* FLL1_LAMBDA - [15:0] */
+#define WM5100_FLL1_LAMBDA_WIDTH                    16  /* FLL1_LAMBDA - [15:0] */
+
+/*
+ * R418 (0x1A2) - FLL2 Control 1
+ */
+#define WM5100_FLL2_ENA                         0x0001  /* FLL2_ENA */
+#define WM5100_FLL2_ENA_MASK                    0x0001  /* FLL2_ENA */
+#define WM5100_FLL2_ENA_SHIFT                        0  /* FLL2_ENA */
+#define WM5100_FLL2_ENA_WIDTH                        1  /* FLL2_ENA */
+
+/*
+ * R419 (0x1A3) - FLL2 Control 2
+ */
+#define WM5100_FLL2_OUTDIV_MASK                 0x3F00  /* FLL2_OUTDIV - [13:8] */
+#define WM5100_FLL2_OUTDIV_SHIFT                     8  /* FLL2_OUTDIV - [13:8] */
+#define WM5100_FLL2_OUTDIV_WIDTH                     6  /* FLL2_OUTDIV - [13:8] */
+#define WM5100_FLL2_FRATIO_MASK                 0x0007  /* FLL2_FRATIO - [2:0] */
+#define WM5100_FLL2_FRATIO_SHIFT                     0  /* FLL2_FRATIO - [2:0] */
+#define WM5100_FLL2_FRATIO_WIDTH                     3  /* FLL2_FRATIO - [2:0] */
+
+/*
+ * R420 (0x1A4) - FLL2 Control 3
+ */
+#define WM5100_FLL2_THETA_MASK                  0xFFFF  /* FLL2_THETA - [15:0] */
+#define WM5100_FLL2_THETA_SHIFT                      0  /* FLL2_THETA - [15:0] */
+#define WM5100_FLL2_THETA_WIDTH                     16  /* FLL2_THETA - [15:0] */
+
+/*
+ * R422 (0x1A6) - FLL2 Control 5
+ */
+#define WM5100_FLL2_N_MASK                      0x03FF  /* FLL2_N - [9:0] */
+#define WM5100_FLL2_N_SHIFT                          0  /* FLL2_N - [9:0] */
+#define WM5100_FLL2_N_WIDTH                         10  /* FLL2_N - [9:0] */
+
+/*
+ * R423 (0x1A7) - FLL2 Control 6
+ */
+#define WM5100_FLL2_REFCLK_DIV_MASK             0x00C0  /* FLL2_REFCLK_DIV - [7:6] */
+#define WM5100_FLL2_REFCLK_DIV_SHIFT                 6  /* FLL2_REFCLK_DIV - [7:6] */
+#define WM5100_FLL2_REFCLK_DIV_WIDTH                 2  /* FLL2_REFCLK_DIV - [7:6] */
+#define WM5100_FLL2_REFCLK_SRC_MASK             0x000F  /* FLL2_REFCLK_SRC - [3:0] */
+#define WM5100_FLL2_REFCLK_SRC_SHIFT                 0  /* FLL2_REFCLK_SRC - [3:0] */
+#define WM5100_FLL2_REFCLK_SRC_WIDTH                 4  /* FLL2_REFCLK_SRC - [3:0] */
+
+/*
+ * R424 (0x1A8) - FLL2 EFS 1
+ */
+#define WM5100_FLL2_LAMBDA_MASK                 0xFFFF  /* FLL2_LAMBDA - [15:0] */
+#define WM5100_FLL2_LAMBDA_SHIFT                     0  /* FLL2_LAMBDA - [15:0] */
+#define WM5100_FLL2_LAMBDA_WIDTH                    16  /* FLL2_LAMBDA - [15:0] */
+
+/*
+ * R512 (0x200) - Mic Charge Pump 1
+ */
+#define WM5100_CP2_BYPASS                       0x0020  /* CP2_BYPASS */
+#define WM5100_CP2_BYPASS_MASK                  0x0020  /* CP2_BYPASS */
+#define WM5100_CP2_BYPASS_SHIFT                      5  /* CP2_BYPASS */
+#define WM5100_CP2_BYPASS_WIDTH                      1  /* CP2_BYPASS */
+#define WM5100_CP2_ENA                          0x0001  /* CP2_ENA */
+#define WM5100_CP2_ENA_MASK                     0x0001  /* CP2_ENA */
+#define WM5100_CP2_ENA_SHIFT                         0  /* CP2_ENA */
+#define WM5100_CP2_ENA_WIDTH                         1  /* CP2_ENA */
+
+/*
+ * R513 (0x201) - Mic Charge Pump 2
+ */
+#define WM5100_LDO2_VSEL_MASK                   0xF800  /* LDO2_VSEL - [15:11] */
+#define WM5100_LDO2_VSEL_SHIFT                      11  /* LDO2_VSEL - [15:11] */
+#define WM5100_LDO2_VSEL_WIDTH                       5  /* LDO2_VSEL - [15:11] */
+
+/*
+ * R514 (0x202) - HP Charge Pump 1
+ */
+#define WM5100_CP1_ENA                          0x0001  /* CP1_ENA */
+#define WM5100_CP1_ENA_MASK                     0x0001  /* CP1_ENA */
+#define WM5100_CP1_ENA_SHIFT                         0  /* CP1_ENA */
+#define WM5100_CP1_ENA_WIDTH                         1  /* CP1_ENA */
+
+/*
+ * R529 (0x211) - LDO1 Control
+ */
+#define WM5100_LDO1_BYPASS                      0x0002  /* LDO1_BYPASS */
+#define WM5100_LDO1_BYPASS_MASK                 0x0002  /* LDO1_BYPASS */
+#define WM5100_LDO1_BYPASS_SHIFT                     1  /* LDO1_BYPASS */
+#define WM5100_LDO1_BYPASS_WIDTH                     1  /* LDO1_BYPASS */
+
+/*
+ * R533 (0x215) - Mic Bias Ctrl 1
+ */
+#define WM5100_MICB1_DISCH                      0x0040  /* MICB1_DISCH */
+#define WM5100_MICB1_DISCH_MASK                 0x0040  /* MICB1_DISCH */
+#define WM5100_MICB1_DISCH_SHIFT                     6  /* MICB1_DISCH */
+#define WM5100_MICB1_DISCH_WIDTH                     1  /* MICB1_DISCH */
+#define WM5100_MICB1_RATE                       0x0020  /* MICB1_RATE */
+#define WM5100_MICB1_RATE_MASK                  0x0020  /* MICB1_RATE */
+#define WM5100_MICB1_RATE_SHIFT                      5  /* MICB1_RATE */
+#define WM5100_MICB1_RATE_WIDTH                      1  /* MICB1_RATE */
+#define WM5100_MICB1_LVL_MASK                   0x001C  /* MICB1_LVL - [4:2] */
+#define WM5100_MICB1_LVL_SHIFT                       2  /* MICB1_LVL - [4:2] */
+#define WM5100_MICB1_LVL_WIDTH                       3  /* MICB1_LVL - [4:2] */
+#define WM5100_MICB1_BYPASS                     0x0002  /* MICB1_BYPASS */
+#define WM5100_MICB1_BYPASS_MASK                0x0002  /* MICB1_BYPASS */
+#define WM5100_MICB1_BYPASS_SHIFT                    1  /* MICB1_BYPASS */
+#define WM5100_MICB1_BYPASS_WIDTH                    1  /* MICB1_BYPASS */
+#define WM5100_MICB1_ENA                        0x0001  /* MICB1_ENA */
+#define WM5100_MICB1_ENA_MASK                   0x0001  /* MICB1_ENA */
+#define WM5100_MICB1_ENA_SHIFT                       0  /* MICB1_ENA */
+#define WM5100_MICB1_ENA_WIDTH                       1  /* MICB1_ENA */
+
+/*
+ * R534 (0x216) - Mic Bias Ctrl 2
+ */
+#define WM5100_MICB2_DISCH                      0x0040  /* MICB2_DISCH */
+#define WM5100_MICB2_DISCH_MASK                 0x0040  /* MICB2_DISCH */
+#define WM5100_MICB2_DISCH_SHIFT                     6  /* MICB2_DISCH */
+#define WM5100_MICB2_DISCH_WIDTH                     1  /* MICB2_DISCH */
+#define WM5100_MICB2_RATE                       0x0020  /* MICB2_RATE */
+#define WM5100_MICB2_RATE_MASK                  0x0020  /* MICB2_RATE */
+#define WM5100_MICB2_RATE_SHIFT                      5  /* MICB2_RATE */
+#define WM5100_MICB2_RATE_WIDTH                      1  /* MICB2_RATE */
+#define WM5100_MICB2_LVL_MASK                   0x001C  /* MICB2_LVL - [4:2] */
+#define WM5100_MICB2_LVL_SHIFT                       2  /* MICB2_LVL - [4:2] */
+#define WM5100_MICB2_LVL_WIDTH                       3  /* MICB2_LVL - [4:2] */
+#define WM5100_MICB2_BYPASS                     0x0002  /* MICB2_BYPASS */
+#define WM5100_MICB2_BYPASS_MASK                0x0002  /* MICB2_BYPASS */
+#define WM5100_MICB2_BYPASS_SHIFT                    1  /* MICB2_BYPASS */
+#define WM5100_MICB2_BYPASS_WIDTH                    1  /* MICB2_BYPASS */
+#define WM5100_MICB2_ENA                        0x0001  /* MICB2_ENA */
+#define WM5100_MICB2_ENA_MASK                   0x0001  /* MICB2_ENA */
+#define WM5100_MICB2_ENA_SHIFT                       0  /* MICB2_ENA */
+#define WM5100_MICB2_ENA_WIDTH                       1  /* MICB2_ENA */
+
+/*
+ * R535 (0x217) - Mic Bias Ctrl 3
+ */
+#define WM5100_MICB3_DISCH                      0x0040  /* MICB3_DISCH */
+#define WM5100_MICB3_DISCH_MASK                 0x0040  /* MICB3_DISCH */
+#define WM5100_MICB3_DISCH_SHIFT                     6  /* MICB3_DISCH */
+#define WM5100_MICB3_DISCH_WIDTH                     1  /* MICB3_DISCH */
+#define WM5100_MICB3_RATE                       0x0020  /* MICB3_RATE */
+#define WM5100_MICB3_RATE_MASK                  0x0020  /* MICB3_RATE */
+#define WM5100_MICB3_RATE_SHIFT                      5  /* MICB3_RATE */
+#define WM5100_MICB3_RATE_WIDTH                      1  /* MICB3_RATE */
+#define WM5100_MICB3_LVL_MASK                   0x001C  /* MICB3_LVL - [4:2] */
+#define WM5100_MICB3_LVL_SHIFT                       2  /* MICB3_LVL - [4:2] */
+#define WM5100_MICB3_LVL_WIDTH                       3  /* MICB3_LVL - [4:2] */
+#define WM5100_MICB3_BYPASS                     0x0002  /* MICB3_BYPASS */
+#define WM5100_MICB3_BYPASS_MASK                0x0002  /* MICB3_BYPASS */
+#define WM5100_MICB3_BYPASS_SHIFT                    1  /* MICB3_BYPASS */
+#define WM5100_MICB3_BYPASS_WIDTH                    1  /* MICB3_BYPASS */
+#define WM5100_MICB3_ENA                        0x0001  /* MICB3_ENA */
+#define WM5100_MICB3_ENA_MASK                   0x0001  /* MICB3_ENA */
+#define WM5100_MICB3_ENA_SHIFT                       0  /* MICB3_ENA */
+#define WM5100_MICB3_ENA_WIDTH                       1  /* MICB3_ENA */
+
+/*
+ * R640 (0x280) - Accessory Detect Mode 1
+ */
+#define WM5100_ACCDET_BIAS_SRC_MASK             0xC000  /* ACCDET_BIAS_SRC - [15:14] */
+#define WM5100_ACCDET_BIAS_SRC_SHIFT                14  /* ACCDET_BIAS_SRC - [15:14] */
+#define WM5100_ACCDET_BIAS_SRC_WIDTH                 2  /* ACCDET_BIAS_SRC - [15:14] */
+#define WM5100_ACCDET_SRC                       0x2000  /* ACCDET_SRC */
+#define WM5100_ACCDET_SRC_MASK                  0x2000  /* ACCDET_SRC */
+#define WM5100_ACCDET_SRC_SHIFT                     13  /* ACCDET_SRC */
+#define WM5100_ACCDET_SRC_WIDTH                      1  /* ACCDET_SRC */
+#define WM5100_ACCDET_MODE_MASK                 0x0003  /* ACCDET_MODE - [1:0] */
+#define WM5100_ACCDET_MODE_SHIFT                     0  /* ACCDET_MODE - [1:0] */
+#define WM5100_ACCDET_MODE_WIDTH                     2  /* ACCDET_MODE - [1:0] */
+
+/*
+ * R648 (0x288) - Headphone Detect 1
+ */
+#define WM5100_HP_HOLDTIME_MASK                 0x00E0  /* HP_HOLDTIME - [7:5] */
+#define WM5100_HP_HOLDTIME_SHIFT                     5  /* HP_HOLDTIME - [7:5] */
+#define WM5100_HP_HOLDTIME_WIDTH                     3  /* HP_HOLDTIME - [7:5] */
+#define WM5100_HP_CLK_DIV_MASK                  0x0018  /* HP_CLK_DIV - [4:3] */
+#define WM5100_HP_CLK_DIV_SHIFT                      3  /* HP_CLK_DIV - [4:3] */
+#define WM5100_HP_CLK_DIV_WIDTH                      2  /* HP_CLK_DIV - [4:3] */
+#define WM5100_HP_STEP_SIZE                     0x0002  /* HP_STEP_SIZE */
+#define WM5100_HP_STEP_SIZE_MASK                0x0002  /* HP_STEP_SIZE */
+#define WM5100_HP_STEP_SIZE_SHIFT                    1  /* HP_STEP_SIZE */
+#define WM5100_HP_STEP_SIZE_WIDTH                    1  /* HP_STEP_SIZE */
+#define WM5100_HP_POLL                          0x0001  /* HP_POLL */
+#define WM5100_HP_POLL_MASK                     0x0001  /* HP_POLL */
+#define WM5100_HP_POLL_SHIFT                         0  /* HP_POLL */
+#define WM5100_HP_POLL_WIDTH                         1  /* HP_POLL */
+
+/*
+ * R649 (0x289) - Headphone Detect 2
+ */
+#define WM5100_HP_DONE                          0x0080  /* HP_DONE */
+#define WM5100_HP_DONE_MASK                     0x0080  /* HP_DONE */
+#define WM5100_HP_DONE_SHIFT                         7  /* HP_DONE */
+#define WM5100_HP_DONE_WIDTH                         1  /* HP_DONE */
+#define WM5100_HP_LVL_MASK                      0x007F  /* HP_LVL - [6:0] */
+#define WM5100_HP_LVL_SHIFT                          0  /* HP_LVL - [6:0] */
+#define WM5100_HP_LVL_WIDTH                          7  /* HP_LVL - [6:0] */
+
+/*
+ * R656 (0x290) - Mic Detect 1
+ */
+#define WM5100_ACCDET_BIAS_STARTTIME_MASK       0xF000  /* ACCDET_BIAS_STARTTIME - [15:12] */
+#define WM5100_ACCDET_BIAS_STARTTIME_SHIFT          12  /* ACCDET_BIAS_STARTTIME - [15:12] */
+#define WM5100_ACCDET_BIAS_STARTTIME_WIDTH           4  /* ACCDET_BIAS_STARTTIME - [15:12] */
+#define WM5100_ACCDET_RATE_MASK                 0x0F00  /* ACCDET_RATE - [11:8] */
+#define WM5100_ACCDET_RATE_SHIFT                     8  /* ACCDET_RATE - [11:8] */
+#define WM5100_ACCDET_RATE_WIDTH                     4  /* ACCDET_RATE - [11:8] */
+#define WM5100_ACCDET_DBTIME                    0x0002  /* ACCDET_DBTIME */
+#define WM5100_ACCDET_DBTIME_MASK               0x0002  /* ACCDET_DBTIME */
+#define WM5100_ACCDET_DBTIME_SHIFT                   1  /* ACCDET_DBTIME */
+#define WM5100_ACCDET_DBTIME_WIDTH                   1  /* ACCDET_DBTIME */
+#define WM5100_ACCDET_ENA                       0x0001  /* ACCDET_ENA */
+#define WM5100_ACCDET_ENA_MASK                  0x0001  /* ACCDET_ENA */
+#define WM5100_ACCDET_ENA_SHIFT                      0  /* ACCDET_ENA */
+#define WM5100_ACCDET_ENA_WIDTH                      1  /* ACCDET_ENA */
+
+/*
+ * R657 (0x291) - Mic Detect 2
+ */
+#define WM5100_ACCDET_LVL_SEL_MASK              0x00FF  /* ACCDET_LVL_SEL - [7:0] */
+#define WM5100_ACCDET_LVL_SEL_SHIFT                  0  /* ACCDET_LVL_SEL - [7:0] */
+#define WM5100_ACCDET_LVL_SEL_WIDTH                  8  /* ACCDET_LVL_SEL - [7:0] */
+
+/*
+ * R658 (0x292) - Mic Detect 3
+ */
+#define WM5100_ACCDET_LVL_MASK                  0x07FC  /* ACCDET_LVL - [10:2] */
+#define WM5100_ACCDET_LVL_SHIFT                      2  /* ACCDET_LVL - [10:2] */
+#define WM5100_ACCDET_LVL_WIDTH                      9  /* ACCDET_LVL - [10:2] */
+#define WM5100_ACCDET_VALID                     0x0002  /* ACCDET_VALID */
+#define WM5100_ACCDET_VALID_MASK                0x0002  /* ACCDET_VALID */
+#define WM5100_ACCDET_VALID_SHIFT                    1  /* ACCDET_VALID */
+#define WM5100_ACCDET_VALID_WIDTH                    1  /* ACCDET_VALID */
+#define WM5100_ACCDET_STS                       0x0001  /* ACCDET_STS */
+#define WM5100_ACCDET_STS_MASK                  0x0001  /* ACCDET_STS */
+#define WM5100_ACCDET_STS_SHIFT                      0  /* ACCDET_STS */
+#define WM5100_ACCDET_STS_WIDTH                      1  /* ACCDET_STS */
+
+/*
+ * R699 (0x2BB) - Misc Control
+ */
+#define WM5100_HPCOM_SRC                         0x200  /* HPCOM_SRC */
+#define WM5100_HPCOM_SRC_SHIFT                       9  /* HPCOM_SRC */
+
+/*
+ * R769 (0x301) - Input Enables
+ */
+#define WM5100_IN4L_ENA                         0x0080  /* IN4L_ENA */
+#define WM5100_IN4L_ENA_MASK                    0x0080  /* IN4L_ENA */
+#define WM5100_IN4L_ENA_SHIFT                        7  /* IN4L_ENA */
+#define WM5100_IN4L_ENA_WIDTH                        1  /* IN4L_ENA */
+#define WM5100_IN4R_ENA                         0x0040  /* IN4R_ENA */
+#define WM5100_IN4R_ENA_MASK                    0x0040  /* IN4R_ENA */
+#define WM5100_IN4R_ENA_SHIFT                        6  /* IN4R_ENA */
+#define WM5100_IN4R_ENA_WIDTH                        1  /* IN4R_ENA */
+#define WM5100_IN3L_ENA                         0x0020  /* IN3L_ENA */
+#define WM5100_IN3L_ENA_MASK                    0x0020  /* IN3L_ENA */
+#define WM5100_IN3L_ENA_SHIFT                        5  /* IN3L_ENA */
+#define WM5100_IN3L_ENA_WIDTH                        1  /* IN3L_ENA */
+#define WM5100_IN3R_ENA                         0x0010  /* IN3R_ENA */
+#define WM5100_IN3R_ENA_MASK                    0x0010  /* IN3R_ENA */
+#define WM5100_IN3R_ENA_SHIFT                        4  /* IN3R_ENA */
+#define WM5100_IN3R_ENA_WIDTH                        1  /* IN3R_ENA */
+#define WM5100_IN2L_ENA                         0x0008  /* IN2L_ENA */
+#define WM5100_IN2L_ENA_MASK                    0x0008  /* IN2L_ENA */
+#define WM5100_IN2L_ENA_SHIFT                        3  /* IN2L_ENA */
+#define WM5100_IN2L_ENA_WIDTH                        1  /* IN2L_ENA */
+#define WM5100_IN2R_ENA                         0x0004  /* IN2R_ENA */
+#define WM5100_IN2R_ENA_MASK                    0x0004  /* IN2R_ENA */
+#define WM5100_IN2R_ENA_SHIFT                        2  /* IN2R_ENA */
+#define WM5100_IN2R_ENA_WIDTH                        1  /* IN2R_ENA */
+#define WM5100_IN1L_ENA                         0x0002  /* IN1L_ENA */
+#define WM5100_IN1L_ENA_MASK                    0x0002  /* IN1L_ENA */
+#define WM5100_IN1L_ENA_SHIFT                        1  /* IN1L_ENA */
+#define WM5100_IN1L_ENA_WIDTH                        1  /* IN1L_ENA */
+#define WM5100_IN1R_ENA                         0x0001  /* IN1R_ENA */
+#define WM5100_IN1R_ENA_MASK                    0x0001  /* IN1R_ENA */
+#define WM5100_IN1R_ENA_SHIFT                        0  /* IN1R_ENA */
+#define WM5100_IN1R_ENA_WIDTH                        1  /* IN1R_ENA */
+
+/*
+ * R770 (0x302) - Input Enables Status
+ */
+#define WM5100_IN4L_ENA_STS                     0x0080  /* IN4L_ENA_STS */
+#define WM5100_IN4L_ENA_STS_MASK                0x0080  /* IN4L_ENA_STS */
+#define WM5100_IN4L_ENA_STS_SHIFT                    7  /* IN4L_ENA_STS */
+#define WM5100_IN4L_ENA_STS_WIDTH                    1  /* IN4L_ENA_STS */
+#define WM5100_IN4R_ENA_STS                     0x0040  /* IN4R_ENA_STS */
+#define WM5100_IN4R_ENA_STS_MASK                0x0040  /* IN4R_ENA_STS */
+#define WM5100_IN4R_ENA_STS_SHIFT                    6  /* IN4R_ENA_STS */
+#define WM5100_IN4R_ENA_STS_WIDTH                    1  /* IN4R_ENA_STS */
+#define WM5100_IN3L_ENA_STS                     0x0020  /* IN3L_ENA_STS */
+#define WM5100_IN3L_ENA_STS_MASK                0x0020  /* IN3L_ENA_STS */
+#define WM5100_IN3L_ENA_STS_SHIFT                    5  /* IN3L_ENA_STS */
+#define WM5100_IN3L_ENA_STS_WIDTH                    1  /* IN3L_ENA_STS */
+#define WM5100_IN3R_ENA_STS                     0x0010  /* IN3R_ENA_STS */
+#define WM5100_IN3R_ENA_STS_MASK                0x0010  /* IN3R_ENA_STS */
+#define WM5100_IN3R_ENA_STS_SHIFT                    4  /* IN3R_ENA_STS */
+#define WM5100_IN3R_ENA_STS_WIDTH                    1  /* IN3R_ENA_STS */
+#define WM5100_IN2L_ENA_STS                     0x0008  /* IN2L_ENA_STS */
+#define WM5100_IN2L_ENA_STS_MASK                0x0008  /* IN2L_ENA_STS */
+#define WM5100_IN2L_ENA_STS_SHIFT                    3  /* IN2L_ENA_STS */
+#define WM5100_IN2L_ENA_STS_WIDTH                    1  /* IN2L_ENA_STS */
+#define WM5100_IN2R_ENA_STS                     0x0004  /* IN2R_ENA_STS */
+#define WM5100_IN2R_ENA_STS_MASK                0x0004  /* IN2R_ENA_STS */
+#define WM5100_IN2R_ENA_STS_SHIFT                    2  /* IN2R_ENA_STS */
+#define WM5100_IN2R_ENA_STS_WIDTH                    1  /* IN2R_ENA_STS */
+#define WM5100_IN1L_ENA_STS                     0x0002  /* IN1L_ENA_STS */
+#define WM5100_IN1L_ENA_STS_MASK                0x0002  /* IN1L_ENA_STS */
+#define WM5100_IN1L_ENA_STS_SHIFT                    1  /* IN1L_ENA_STS */
+#define WM5100_IN1L_ENA_STS_WIDTH                    1  /* IN1L_ENA_STS */
+#define WM5100_IN1R_ENA_STS                     0x0001  /* IN1R_ENA_STS */
+#define WM5100_IN1R_ENA_STS_MASK                0x0001  /* IN1R_ENA_STS */
+#define WM5100_IN1R_ENA_STS_SHIFT                    0  /* IN1R_ENA_STS */
+#define WM5100_IN1R_ENA_STS_WIDTH                    1  /* IN1R_ENA_STS */
+
+/*
+ * R784 (0x310) - IN1L Control
+ */
+#define WM5100_IN_RATE_MASK                     0xC000  /* IN_RATE - [15:14] */
+#define WM5100_IN_RATE_SHIFT                        14  /* IN_RATE - [15:14] */
+#define WM5100_IN_RATE_WIDTH                         2  /* IN_RATE - [15:14] */
+#define WM5100_IN1_OSR                          0x2000  /* IN1_OSR */
+#define WM5100_IN1_OSR_MASK                     0x2000  /* IN1_OSR */
+#define WM5100_IN1_OSR_SHIFT                        13  /* IN1_OSR */
+#define WM5100_IN1_OSR_WIDTH                         1  /* IN1_OSR */
+#define WM5100_IN1_DMIC_SUP_MASK                0x1800  /* IN1_DMIC_SUP - [12:11] */
+#define WM5100_IN1_DMIC_SUP_SHIFT                   11  /* IN1_DMIC_SUP - [12:11] */
+#define WM5100_IN1_DMIC_SUP_WIDTH                    2  /* IN1_DMIC_SUP - [12:11] */
+#define WM5100_IN1_MODE_MASK                    0x0600  /* IN1_MODE - [10:9] */
+#define WM5100_IN1_MODE_SHIFT                        9  /* IN1_MODE - [10:9] */
+#define WM5100_IN1_MODE_WIDTH                        2  /* IN1_MODE - [10:9] */
+#define WM5100_IN1L_PGA_VOL_MASK                0x00FE  /* IN1L_PGA_VOL - [7:1] */
+#define WM5100_IN1L_PGA_VOL_SHIFT                    1  /* IN1L_PGA_VOL - [7:1] */
+#define WM5100_IN1L_PGA_VOL_WIDTH                    7  /* IN1L_PGA_VOL - [7:1] */
+
+/*
+ * R785 (0x311) - IN1R Control
+ */
+#define WM5100_IN1R_PGA_VOL_MASK                0x00FE  /* IN1R_PGA_VOL - [7:1] */
+#define WM5100_IN1R_PGA_VOL_SHIFT                    1  /* IN1R_PGA_VOL - [7:1] */
+#define WM5100_IN1R_PGA_VOL_WIDTH                    7  /* IN1R_PGA_VOL - [7:1] */
+
+/*
+ * R786 (0x312) - IN2L Control
+ */
+#define WM5100_IN2_OSR                          0x2000  /* IN2_OSR */
+#define WM5100_IN2_OSR_MASK                     0x2000  /* IN2_OSR */
+#define WM5100_IN2_OSR_SHIFT                        13  /* IN2_OSR */
+#define WM5100_IN2_OSR_WIDTH                         1  /* IN2_OSR */
+#define WM5100_IN2_DMIC_SUP_MASK                0x1800  /* IN2_DMIC_SUP - [12:11] */
+#define WM5100_IN2_DMIC_SUP_SHIFT                   11  /* IN2_DMIC_SUP - [12:11] */
+#define WM5100_IN2_DMIC_SUP_WIDTH                    2  /* IN2_DMIC_SUP - [12:11] */
+#define WM5100_IN2_MODE_MASK                    0x0600  /* IN2_MODE - [10:9] */
+#define WM5100_IN2_MODE_SHIFT                        9  /* IN2_MODE - [10:9] */
+#define WM5100_IN2_MODE_WIDTH                        2  /* IN2_MODE - [10:9] */
+#define WM5100_IN2L_PGA_VOL_MASK                0x00FE  /* IN2L_PGA_VOL - [7:1] */
+#define WM5100_IN2L_PGA_VOL_SHIFT                    1  /* IN2L_PGA_VOL - [7:1] */
+#define WM5100_IN2L_PGA_VOL_WIDTH                    7  /* IN2L_PGA_VOL - [7:1] */
+
+/*
+ * R787 (0x313) - IN2R Control
+ */
+#define WM5100_IN2R_PGA_VOL_MASK                0x00FE  /* IN2R_PGA_VOL - [7:1] */
+#define WM5100_IN2R_PGA_VOL_SHIFT                    1  /* IN2R_PGA_VOL - [7:1] */
+#define WM5100_IN2R_PGA_VOL_WIDTH                    7  /* IN2R_PGA_VOL - [7:1] */
+
+/*
+ * R788 (0x314) - IN3L Control
+ */
+#define WM5100_IN3_OSR                          0x2000  /* IN3_OSR */
+#define WM5100_IN3_OSR_MASK                     0x2000  /* IN3_OSR */
+#define WM5100_IN3_OSR_SHIFT                        13  /* IN3_OSR */
+#define WM5100_IN3_OSR_WIDTH                         1  /* IN3_OSR */
+#define WM5100_IN3_DMIC_SUP_MASK                0x1800  /* IN3_DMIC_SUP - [12:11] */
+#define WM5100_IN3_DMIC_SUP_SHIFT                   11  /* IN3_DMIC_SUP - [12:11] */
+#define WM5100_IN3_DMIC_SUP_WIDTH                    2  /* IN3_DMIC_SUP - [12:11] */
+#define WM5100_IN3_MODE_MASK                    0x0600  /* IN3_MODE - [10:9] */
+#define WM5100_IN3_MODE_SHIFT                        9  /* IN3_MODE - [10:9] */
+#define WM5100_IN3_MODE_WIDTH                        2  /* IN3_MODE - [10:9] */
+#define WM5100_IN3L_PGA_VOL_MASK                0x00FE  /* IN3L_PGA_VOL - [7:1] */
+#define WM5100_IN3L_PGA_VOL_SHIFT                    1  /* IN3L_PGA_VOL - [7:1] */
+#define WM5100_IN3L_PGA_VOL_WIDTH                    7  /* IN3L_PGA_VOL - [7:1] */
+
+/*
+ * R789 (0x315) - IN3R Control
+ */
+#define WM5100_IN3R_PGA_VOL_MASK                0x00FE  /* IN3R_PGA_VOL - [7:1] */
+#define WM5100_IN3R_PGA_VOL_SHIFT                    1  /* IN3R_PGA_VOL - [7:1] */
+#define WM5100_IN3R_PGA_VOL_WIDTH                    7  /* IN3R_PGA_VOL - [7:1] */
+
+/*
+ * R790 (0x316) - IN4L Control
+ */
+#define WM5100_IN4_OSR                          0x2000  /* IN4_OSR */
+#define WM5100_IN4_OSR_MASK                     0x2000  /* IN4_OSR */
+#define WM5100_IN4_OSR_SHIFT                        13  /* IN4_OSR */
+#define WM5100_IN4_OSR_WIDTH                         1  /* IN4_OSR */
+#define WM5100_IN4_DMIC_SUP_MASK                0x1800  /* IN4_DMIC_SUP - [12:11] */
+#define WM5100_IN4_DMIC_SUP_SHIFT                   11  /* IN4_DMIC_SUP - [12:11] */
+#define WM5100_IN4_DMIC_SUP_WIDTH                    2  /* IN4_DMIC_SUP - [12:11] */
+#define WM5100_IN4_MODE_MASK                    0x0600  /* IN4_MODE - [10:9] */
+#define WM5100_IN4_MODE_SHIFT                        9  /* IN4_MODE - [10:9] */
+#define WM5100_IN4_MODE_WIDTH                        2  /* IN4_MODE - [10:9] */
+#define WM5100_IN4L_PGA_VOL_MASK                0x00FE  /* IN4L_PGA_VOL - [7:1] */
+#define WM5100_IN4L_PGA_VOL_SHIFT                    1  /* IN4L_PGA_VOL - [7:1] */
+#define WM5100_IN4L_PGA_VOL_WIDTH                    7  /* IN4L_PGA_VOL - [7:1] */
+
+/*
+ * R791 (0x317) - IN4R Control
+ */
+#define WM5100_IN4R_PGA_VOL_MASK                0x00FE  /* IN4R_PGA_VOL - [7:1] */
+#define WM5100_IN4R_PGA_VOL_SHIFT                    1  /* IN4R_PGA_VOL - [7:1] */
+#define WM5100_IN4R_PGA_VOL_WIDTH                    7  /* IN4R_PGA_VOL - [7:1] */
+
+/*
+ * R792 (0x318) - RXANC_SRC
+ */
+#define WM5100_IN_RXANC_SEL_MASK                0x0007  /* IN_RXANC_SEL - [2:0] */
+#define WM5100_IN_RXANC_SEL_SHIFT                    0  /* IN_RXANC_SEL - [2:0] */
+#define WM5100_IN_RXANC_SEL_WIDTH                    3  /* IN_RXANC_SEL - [2:0] */
+
+/*
+ * R793 (0x319) - Input Volume Ramp
+ */
+#define WM5100_IN_VD_RAMP_MASK                  0x0070  /* IN_VD_RAMP - [6:4] */
+#define WM5100_IN_VD_RAMP_SHIFT                      4  /* IN_VD_RAMP - [6:4] */
+#define WM5100_IN_VD_RAMP_WIDTH                      3  /* IN_VD_RAMP - [6:4] */
+#define WM5100_IN_VI_RAMP_MASK                  0x0007  /* IN_VI_RAMP - [2:0] */
+#define WM5100_IN_VI_RAMP_SHIFT                      0  /* IN_VI_RAMP - [2:0] */
+#define WM5100_IN_VI_RAMP_WIDTH                      3  /* IN_VI_RAMP - [2:0] */
+
+/*
+ * R800 (0x320) - ADC Digital Volume 1L
+ */
+#define WM5100_IN_VU                            0x0200  /* IN_VU */
+#define WM5100_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM5100_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM5100_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM5100_IN1L_MUTE                        0x0100  /* IN1L_MUTE */
+#define WM5100_IN1L_MUTE_MASK                   0x0100  /* IN1L_MUTE */
+#define WM5100_IN1L_MUTE_SHIFT                       8  /* IN1L_MUTE */
+#define WM5100_IN1L_MUTE_WIDTH                       1  /* IN1L_MUTE */
+#define WM5100_IN1L_VOL_MASK                    0x00FF  /* IN1L_VOL - [7:0] */
+#define WM5100_IN1L_VOL_SHIFT                        0  /* IN1L_VOL - [7:0] */
+#define WM5100_IN1L_VOL_WIDTH                        8  /* IN1L_VOL - [7:0] */
+
+/*
+ * R801 (0x321) - ADC Digital Volume 1R
+ */
+#define WM5100_IN_VU                            0x0200  /* IN_VU */
+#define WM5100_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM5100_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM5100_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM5100_IN1R_MUTE                        0x0100  /* IN1R_MUTE */
+#define WM5100_IN1R_MUTE_MASK                   0x0100  /* IN1R_MUTE */
+#define WM5100_IN1R_MUTE_SHIFT                       8  /* IN1R_MUTE */
+#define WM5100_IN1R_MUTE_WIDTH                       1  /* IN1R_MUTE */
+#define WM5100_IN1R_VOL_MASK                    0x00FF  /* IN1R_VOL - [7:0] */
+#define WM5100_IN1R_VOL_SHIFT                        0  /* IN1R_VOL - [7:0] */
+#define WM5100_IN1R_VOL_WIDTH                        8  /* IN1R_VOL - [7:0] */
+
+/*
+ * R802 (0x322) - ADC Digital Volume 2L
+ */
+#define WM5100_IN_VU                            0x0200  /* IN_VU */
+#define WM5100_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM5100_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM5100_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM5100_IN2L_MUTE                        0x0100  /* IN2L_MUTE */
+#define WM5100_IN2L_MUTE_MASK                   0x0100  /* IN2L_MUTE */
+#define WM5100_IN2L_MUTE_SHIFT                       8  /* IN2L_MUTE */
+#define WM5100_IN2L_MUTE_WIDTH                       1  /* IN2L_MUTE */
+#define WM5100_IN2L_VOL_MASK                    0x00FF  /* IN2L_VOL - [7:0] */
+#define WM5100_IN2L_VOL_SHIFT                        0  /* IN2L_VOL - [7:0] */
+#define WM5100_IN2L_VOL_WIDTH                        8  /* IN2L_VOL - [7:0] */
+
+/*
+ * R803 (0x323) - ADC Digital Volume 2R
+ */
+#define WM5100_IN_VU                            0x0200  /* IN_VU */
+#define WM5100_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM5100_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM5100_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM5100_IN2R_MUTE                        0x0100  /* IN2R_MUTE */
+#define WM5100_IN2R_MUTE_MASK                   0x0100  /* IN2R_MUTE */
+#define WM5100_IN2R_MUTE_SHIFT                       8  /* IN2R_MUTE */
+#define WM5100_IN2R_MUTE_WIDTH                       1  /* IN2R_MUTE */
+#define WM5100_IN2R_VOL_MASK                    0x00FF  /* IN2R_VOL - [7:0] */
+#define WM5100_IN2R_VOL_SHIFT                        0  /* IN2R_VOL - [7:0] */
+#define WM5100_IN2R_VOL_WIDTH                        8  /* IN2R_VOL - [7:0] */
+
+/*
+ * R804 (0x324) - ADC Digital Volume 3L
+ */
+#define WM5100_IN_VU                            0x0200  /* IN_VU */
+#define WM5100_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM5100_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM5100_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM5100_IN3L_MUTE                        0x0100  /* IN3L_MUTE */
+#define WM5100_IN3L_MUTE_MASK                   0x0100  /* IN3L_MUTE */
+#define WM5100_IN3L_MUTE_SHIFT                       8  /* IN3L_MUTE */
+#define WM5100_IN3L_MUTE_WIDTH                       1  /* IN3L_MUTE */
+#define WM5100_IN3L_VOL_MASK                    0x00FF  /* IN3L_VOL - [7:0] */
+#define WM5100_IN3L_VOL_SHIFT                        0  /* IN3L_VOL - [7:0] */
+#define WM5100_IN3L_VOL_WIDTH                        8  /* IN3L_VOL - [7:0] */
+
+/*
+ * R805 (0x325) - ADC Digital Volume 3R
+ */
+#define WM5100_IN_VU                            0x0200  /* IN_VU */
+#define WM5100_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM5100_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM5100_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM5100_IN3R_MUTE                        0x0100  /* IN3R_MUTE */
+#define WM5100_IN3R_MUTE_MASK                   0x0100  /* IN3R_MUTE */
+#define WM5100_IN3R_MUTE_SHIFT                       8  /* IN3R_MUTE */
+#define WM5100_IN3R_MUTE_WIDTH                       1  /* IN3R_MUTE */
+#define WM5100_IN3R_VOL_MASK                    0x00FF  /* IN3R_VOL - [7:0] */
+#define WM5100_IN3R_VOL_SHIFT                        0  /* IN3R_VOL - [7:0] */
+#define WM5100_IN3R_VOL_WIDTH                        8  /* IN3R_VOL - [7:0] */
+
+/*
+ * R806 (0x326) - ADC Digital Volume 4L
+ */
+#define WM5100_IN_VU                            0x0200  /* IN_VU */
+#define WM5100_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM5100_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM5100_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM5100_IN4L_MUTE                        0x0100  /* IN4L_MUTE */
+#define WM5100_IN4L_MUTE_MASK                   0x0100  /* IN4L_MUTE */
+#define WM5100_IN4L_MUTE_SHIFT                       8  /* IN4L_MUTE */
+#define WM5100_IN4L_MUTE_WIDTH                       1  /* IN4L_MUTE */
+#define WM5100_IN4L_VOL_MASK                    0x00FF  /* IN4L_VOL - [7:0] */
+#define WM5100_IN4L_VOL_SHIFT                        0  /* IN4L_VOL - [7:0] */
+#define WM5100_IN4L_VOL_WIDTH                        8  /* IN4L_VOL - [7:0] */
+
+/*
+ * R807 (0x327) - ADC Digital Volume 4R
+ */
+#define WM5100_IN_VU                            0x0200  /* IN_VU */
+#define WM5100_IN_VU_MASK                       0x0200  /* IN_VU */
+#define WM5100_IN_VU_SHIFT                           9  /* IN_VU */
+#define WM5100_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM5100_IN4R_MUTE                        0x0100  /* IN4R_MUTE */
+#define WM5100_IN4R_MUTE_MASK                   0x0100  /* IN4R_MUTE */
+#define WM5100_IN4R_MUTE_SHIFT                       8  /* IN4R_MUTE */
+#define WM5100_IN4R_MUTE_WIDTH                       1  /* IN4R_MUTE */
+#define WM5100_IN4R_VOL_MASK                    0x00FF  /* IN4R_VOL - [7:0] */
+#define WM5100_IN4R_VOL_SHIFT                        0  /* IN4R_VOL - [7:0] */
+#define WM5100_IN4R_VOL_WIDTH                        8  /* IN4R_VOL - [7:0] */
+
+/*
+ * R1025 (0x401) - Output Enables 2
+ */
+#define WM5100_OUT6L_ENA                        0x0800  /* OUT6L_ENA */
+#define WM5100_OUT6L_ENA_MASK                   0x0800  /* OUT6L_ENA */
+#define WM5100_OUT6L_ENA_SHIFT                      11  /* OUT6L_ENA */
+#define WM5100_OUT6L_ENA_WIDTH                       1  /* OUT6L_ENA */
+#define WM5100_OUT6R_ENA                        0x0400  /* OUT6R_ENA */
+#define WM5100_OUT6R_ENA_MASK                   0x0400  /* OUT6R_ENA */
+#define WM5100_OUT6R_ENA_SHIFT                      10  /* OUT6R_ENA */
+#define WM5100_OUT6R_ENA_WIDTH                       1  /* OUT6R_ENA */
+#define WM5100_OUT5L_ENA                        0x0200  /* OUT5L_ENA */
+#define WM5100_OUT5L_ENA_MASK                   0x0200  /* OUT5L_ENA */
+#define WM5100_OUT5L_ENA_SHIFT                       9  /* OUT5L_ENA */
+#define WM5100_OUT5L_ENA_WIDTH                       1  /* OUT5L_ENA */
+#define WM5100_OUT5R_ENA                        0x0100  /* OUT5R_ENA */
+#define WM5100_OUT5R_ENA_MASK                   0x0100  /* OUT5R_ENA */
+#define WM5100_OUT5R_ENA_SHIFT                       8  /* OUT5R_ENA */
+#define WM5100_OUT5R_ENA_WIDTH                       1  /* OUT5R_ENA */
+#define WM5100_OUT4L_ENA                        0x0080  /* OUT4L_ENA */
+#define WM5100_OUT4L_ENA_MASK                   0x0080  /* OUT4L_ENA */
+#define WM5100_OUT4L_ENA_SHIFT                       7  /* OUT4L_ENA */
+#define WM5100_OUT4L_ENA_WIDTH                       1  /* OUT4L_ENA */
+#define WM5100_OUT4R_ENA                        0x0040  /* OUT4R_ENA */
+#define WM5100_OUT4R_ENA_MASK                   0x0040  /* OUT4R_ENA */
+#define WM5100_OUT4R_ENA_SHIFT                       6  /* OUT4R_ENA */
+#define WM5100_OUT4R_ENA_WIDTH                       1  /* OUT4R_ENA */
+
+/*
+ * R1026 (0x402) - Output Status 1
+ */
+#define WM5100_OUT3L_ENA_STS                    0x0020  /* OUT3L_ENA_STS */
+#define WM5100_OUT3L_ENA_STS_MASK               0x0020  /* OUT3L_ENA_STS */
+#define WM5100_OUT3L_ENA_STS_SHIFT                   5  /* OUT3L_ENA_STS */
+#define WM5100_OUT3L_ENA_STS_WIDTH                   1  /* OUT3L_ENA_STS */
+#define WM5100_OUT3R_ENA_STS                    0x0010  /* OUT3R_ENA_STS */
+#define WM5100_OUT3R_ENA_STS_MASK               0x0010  /* OUT3R_ENA_STS */
+#define WM5100_OUT3R_ENA_STS_SHIFT                   4  /* OUT3R_ENA_STS */
+#define WM5100_OUT3R_ENA_STS_WIDTH                   1  /* OUT3R_ENA_STS */
+#define WM5100_OUT2L_ENA_STS                    0x0008  /* OUT2L_ENA_STS */
+#define WM5100_OUT2L_ENA_STS_MASK               0x0008  /* OUT2L_ENA_STS */
+#define WM5100_OUT2L_ENA_STS_SHIFT                   3  /* OUT2L_ENA_STS */
+#define WM5100_OUT2L_ENA_STS_WIDTH                   1  /* OUT2L_ENA_STS */
+#define WM5100_OUT2R_ENA_STS                    0x0004  /* OUT2R_ENA_STS */
+#define WM5100_OUT2R_ENA_STS_MASK               0x0004  /* OUT2R_ENA_STS */
+#define WM5100_OUT2R_ENA_STS_SHIFT                   2  /* OUT2R_ENA_STS */
+#define WM5100_OUT2R_ENA_STS_WIDTH                   1  /* OUT2R_ENA_STS */
+#define WM5100_OUT1L_ENA_STS                    0x0002  /* OUT1L_ENA_STS */
+#define WM5100_OUT1L_ENA_STS_MASK               0x0002  /* OUT1L_ENA_STS */
+#define WM5100_OUT1L_ENA_STS_SHIFT                   1  /* OUT1L_ENA_STS */
+#define WM5100_OUT1L_ENA_STS_WIDTH                   1  /* OUT1L_ENA_STS */
+#define WM5100_OUT1R_ENA_STS                    0x0001  /* OUT1R_ENA_STS */
+#define WM5100_OUT1R_ENA_STS_MASK               0x0001  /* OUT1R_ENA_STS */
+#define WM5100_OUT1R_ENA_STS_SHIFT                   0  /* OUT1R_ENA_STS */
+#define WM5100_OUT1R_ENA_STS_WIDTH                   1  /* OUT1R_ENA_STS */
+
+/*
+ * R1027 (0x403) - Output Status 2
+ */
+#define WM5100_OUT6L_ENA_STS                    0x0800  /* OUT6L_ENA_STS */
+#define WM5100_OUT6L_ENA_STS_MASK               0x0800  /* OUT6L_ENA_STS */
+#define WM5100_OUT6L_ENA_STS_SHIFT                  11  /* OUT6L_ENA_STS */
+#define WM5100_OUT6L_ENA_STS_WIDTH                   1  /* OUT6L_ENA_STS */
+#define WM5100_OUT6R_ENA_STS                    0x0400  /* OUT6R_ENA_STS */
+#define WM5100_OUT6R_ENA_STS_MASK               0x0400  /* OUT6R_ENA_STS */
+#define WM5100_OUT6R_ENA_STS_SHIFT                  10  /* OUT6R_ENA_STS */
+#define WM5100_OUT6R_ENA_STS_WIDTH                   1  /* OUT6R_ENA_STS */
+#define WM5100_OUT5L_ENA_STS                    0x0200  /* OUT5L_ENA_STS */
+#define WM5100_OUT5L_ENA_STS_MASK               0x0200  /* OUT5L_ENA_STS */
+#define WM5100_OUT5L_ENA_STS_SHIFT                   9  /* OUT5L_ENA_STS */
+#define WM5100_OUT5L_ENA_STS_WIDTH                   1  /* OUT5L_ENA_STS */
+#define WM5100_OUT5R_ENA_STS                    0x0100  /* OUT5R_ENA_STS */
+#define WM5100_OUT5R_ENA_STS_MASK               0x0100  /* OUT5R_ENA_STS */
+#define WM5100_OUT5R_ENA_STS_SHIFT                   8  /* OUT5R_ENA_STS */
+#define WM5100_OUT5R_ENA_STS_WIDTH                   1  /* OUT5R_ENA_STS */
+#define WM5100_OUT4L_ENA_STS                    0x0080  /* OUT4L_ENA_STS */
+#define WM5100_OUT4L_ENA_STS_MASK               0x0080  /* OUT4L_ENA_STS */
+#define WM5100_OUT4L_ENA_STS_SHIFT                   7  /* OUT4L_ENA_STS */
+#define WM5100_OUT4L_ENA_STS_WIDTH                   1  /* OUT4L_ENA_STS */
+#define WM5100_OUT4R_ENA_STS                    0x0040  /* OUT4R_ENA_STS */
+#define WM5100_OUT4R_ENA_STS_MASK               0x0040  /* OUT4R_ENA_STS */
+#define WM5100_OUT4R_ENA_STS_SHIFT                   6  /* OUT4R_ENA_STS */
+#define WM5100_OUT4R_ENA_STS_WIDTH                   1  /* OUT4R_ENA_STS */
+
+/*
+ * R1032 (0x408) - Channel Enables 1
+ */
+#define WM5100_HP3L_ENA                         0x0020  /* HP3L_ENA */
+#define WM5100_HP3L_ENA_MASK                    0x0020  /* HP3L_ENA */
+#define WM5100_HP3L_ENA_SHIFT                        5  /* HP3L_ENA */
+#define WM5100_HP3L_ENA_WIDTH                        1  /* HP3L_ENA */
+#define WM5100_HP3R_ENA                         0x0010  /* HP3R_ENA */
+#define WM5100_HP3R_ENA_MASK                    0x0010  /* HP3R_ENA */
+#define WM5100_HP3R_ENA_SHIFT                        4  /* HP3R_ENA */
+#define WM5100_HP3R_ENA_WIDTH                        1  /* HP3R_ENA */
+#define WM5100_HP2L_ENA                         0x0008  /* HP2L_ENA */
+#define WM5100_HP2L_ENA_MASK                    0x0008  /* HP2L_ENA */
+#define WM5100_HP2L_ENA_SHIFT                        3  /* HP2L_ENA */
+#define WM5100_HP2L_ENA_WIDTH                        1  /* HP2L_ENA */
+#define WM5100_HP2R_ENA                         0x0004  /* HP2R_ENA */
+#define WM5100_HP2R_ENA_MASK                    0x0004  /* HP2R_ENA */
+#define WM5100_HP2R_ENA_SHIFT                        2  /* HP2R_ENA */
+#define WM5100_HP2R_ENA_WIDTH                        1  /* HP2R_ENA */
+#define WM5100_HP1L_ENA                         0x0002  /* HP1L_ENA */
+#define WM5100_HP1L_ENA_MASK                    0x0002  /* HP1L_ENA */
+#define WM5100_HP1L_ENA_SHIFT                        1  /* HP1L_ENA */
+#define WM5100_HP1L_ENA_WIDTH                        1  /* HP1L_ENA */
+#define WM5100_HP1R_ENA                         0x0001  /* HP1R_ENA */
+#define WM5100_HP1R_ENA_MASK                    0x0001  /* HP1R_ENA */
+#define WM5100_HP1R_ENA_SHIFT                        0  /* HP1R_ENA */
+#define WM5100_HP1R_ENA_WIDTH                        1  /* HP1R_ENA */
+
+/*
+ * R1040 (0x410) - Out Volume 1L
+ */
+#define WM5100_OUT_RATE_MASK                    0xC000  /* OUT_RATE - [15:14] */
+#define WM5100_OUT_RATE_SHIFT                       14  /* OUT_RATE - [15:14] */
+#define WM5100_OUT_RATE_WIDTH                        2  /* OUT_RATE - [15:14] */
+#define WM5100_OUT1_OSR                         0x2000  /* OUT1_OSR */
+#define WM5100_OUT1_OSR_MASK                    0x2000  /* OUT1_OSR */
+#define WM5100_OUT1_OSR_SHIFT                       13  /* OUT1_OSR */
+#define WM5100_OUT1_OSR_WIDTH                        1  /* OUT1_OSR */
+#define WM5100_OUT1_MONO                        0x1000  /* OUT1_MONO */
+#define WM5100_OUT1_MONO_MASK                   0x1000  /* OUT1_MONO */
+#define WM5100_OUT1_MONO_SHIFT                      12  /* OUT1_MONO */
+#define WM5100_OUT1_MONO_WIDTH                       1  /* OUT1_MONO */
+#define WM5100_OUT1L_ANC_SRC                    0x0800  /* OUT1L_ANC_SRC */
+#define WM5100_OUT1L_ANC_SRC_MASK               0x0800  /* OUT1L_ANC_SRC */
+#define WM5100_OUT1L_ANC_SRC_SHIFT                  11  /* OUT1L_ANC_SRC */
+#define WM5100_OUT1L_ANC_SRC_WIDTH                   1  /* OUT1L_ANC_SRC */
+#define WM5100_OUT1L_PGA_VOL_MASK               0x00FE  /* OUT1L_PGA_VOL - [7:1] */
+#define WM5100_OUT1L_PGA_VOL_SHIFT                   1  /* OUT1L_PGA_VOL - [7:1] */
+#define WM5100_OUT1L_PGA_VOL_WIDTH                   7  /* OUT1L_PGA_VOL - [7:1] */
+
+/*
+ * R1041 (0x411) - Out Volume 1R
+ */
+#define WM5100_OUT1R_ANC_SRC                    0x0800  /* OUT1R_ANC_SRC */
+#define WM5100_OUT1R_ANC_SRC_MASK               0x0800  /* OUT1R_ANC_SRC */
+#define WM5100_OUT1R_ANC_SRC_SHIFT                  11  /* OUT1R_ANC_SRC */
+#define WM5100_OUT1R_ANC_SRC_WIDTH                   1  /* OUT1R_ANC_SRC */
+#define WM5100_OUT1R_PGA_VOL_MASK               0x00FE  /* OUT1R_PGA_VOL - [7:1] */
+#define WM5100_OUT1R_PGA_VOL_SHIFT                   1  /* OUT1R_PGA_VOL - [7:1] */
+#define WM5100_OUT1R_PGA_VOL_WIDTH                   7  /* OUT1R_PGA_VOL - [7:1] */
+
+/*
+ * R1042 (0x412) - DAC Volume Limit 1L
+ */
+#define WM5100_OUT1L_VOL_LIM_MASK               0x00FF  /* OUT1L_VOL_LIM - [7:0] */
+#define WM5100_OUT1L_VOL_LIM_SHIFT                   0  /* OUT1L_VOL_LIM - [7:0] */
+#define WM5100_OUT1L_VOL_LIM_WIDTH                   8  /* OUT1L_VOL_LIM - [7:0] */
+
+/*
+ * R1043 (0x413) - DAC Volume Limit 1R
+ */
+#define WM5100_OUT1R_VOL_LIM_MASK               0x00FF  /* OUT1R_VOL_LIM - [7:0] */
+#define WM5100_OUT1R_VOL_LIM_SHIFT                   0  /* OUT1R_VOL_LIM - [7:0] */
+#define WM5100_OUT1R_VOL_LIM_WIDTH                   8  /* OUT1R_VOL_LIM - [7:0] */
+
+/*
+ * R1044 (0x414) - Out Volume 2L
+ */
+#define WM5100_OUT2_OSR                         0x2000  /* OUT2_OSR */
+#define WM5100_OUT2_OSR_MASK                    0x2000  /* OUT2_OSR */
+#define WM5100_OUT2_OSR_SHIFT                       13  /* OUT2_OSR */
+#define WM5100_OUT2_OSR_WIDTH                        1  /* OUT2_OSR */
+#define WM5100_OUT2_MONO                        0x1000  /* OUT2_MONO */
+#define WM5100_OUT2_MONO_MASK                   0x1000  /* OUT2_MONO */
+#define WM5100_OUT2_MONO_SHIFT                      12  /* OUT2_MONO */
+#define WM5100_OUT2_MONO_WIDTH                       1  /* OUT2_MONO */
+#define WM5100_OUT2L_ANC_SRC                    0x0800  /* OUT2L_ANC_SRC */
+#define WM5100_OUT2L_ANC_SRC_MASK               0x0800  /* OUT2L_ANC_SRC */
+#define WM5100_OUT2L_ANC_SRC_SHIFT                  11  /* OUT2L_ANC_SRC */
+#define WM5100_OUT2L_ANC_SRC_WIDTH                   1  /* OUT2L_ANC_SRC */
+#define WM5100_OUT2L_PGA_VOL_MASK               0x00FE  /* OUT2L_PGA_VOL - [7:1] */
+#define WM5100_OUT2L_PGA_VOL_SHIFT                   1  /* OUT2L_PGA_VOL - [7:1] */
+#define WM5100_OUT2L_PGA_VOL_WIDTH                   7  /* OUT2L_PGA_VOL - [7:1] */
+
+/*
+ * R1045 (0x415) - Out Volume 2R
+ */
+#define WM5100_OUT2R_ANC_SRC                    0x0800  /* OUT2R_ANC_SRC */
+#define WM5100_OUT2R_ANC_SRC_MASK               0x0800  /* OUT2R_ANC_SRC */
+#define WM5100_OUT2R_ANC_SRC_SHIFT                  11  /* OUT2R_ANC_SRC */
+#define WM5100_OUT2R_ANC_SRC_WIDTH                   1  /* OUT2R_ANC_SRC */
+#define WM5100_OUT2R_PGA_VOL_MASK               0x00FE  /* OUT2R_PGA_VOL - [7:1] */
+#define WM5100_OUT2R_PGA_VOL_SHIFT                   1  /* OUT2R_PGA_VOL - [7:1] */
+#define WM5100_OUT2R_PGA_VOL_WIDTH                   7  /* OUT2R_PGA_VOL - [7:1] */
+
+/*
+ * R1046 (0x416) - DAC Volume Limit 2L
+ */
+#define WM5100_OUT2L_VOL_LIM_MASK               0x00FF  /* OUT2L_VOL_LIM - [7:0] */
+#define WM5100_OUT2L_VOL_LIM_SHIFT                   0  /* OUT2L_VOL_LIM - [7:0] */
+#define WM5100_OUT2L_VOL_LIM_WIDTH                   8  /* OUT2L_VOL_LIM - [7:0] */
+
+/*
+ * R1047 (0x417) - DAC Volume Limit 2R
+ */
+#define WM5100_OUT2R_VOL_LIM_MASK               0x00FF  /* OUT2R_VOL_LIM - [7:0] */
+#define WM5100_OUT2R_VOL_LIM_SHIFT                   0  /* OUT2R_VOL_LIM - [7:0] */
+#define WM5100_OUT2R_VOL_LIM_WIDTH                   8  /* OUT2R_VOL_LIM - [7:0] */
+
+/*
+ * R1048 (0x418) - Out Volume 3L
+ */
+#define WM5100_OUT3_OSR                         0x2000  /* OUT3_OSR */
+#define WM5100_OUT3_OSR_MASK                    0x2000  /* OUT3_OSR */
+#define WM5100_OUT3_OSR_SHIFT                       13  /* OUT3_OSR */
+#define WM5100_OUT3_OSR_WIDTH                        1  /* OUT3_OSR */
+#define WM5100_OUT3_MONO                        0x1000  /* OUT3_MONO */
+#define WM5100_OUT3_MONO_MASK                   0x1000  /* OUT3_MONO */
+#define WM5100_OUT3_MONO_SHIFT                      12  /* OUT3_MONO */
+#define WM5100_OUT3_MONO_WIDTH                       1  /* OUT3_MONO */
+#define WM5100_OUT3L_ANC_SRC                    0x0800  /* OUT3L_ANC_SRC */
+#define WM5100_OUT3L_ANC_SRC_MASK               0x0800  /* OUT3L_ANC_SRC */
+#define WM5100_OUT3L_ANC_SRC_SHIFT                  11  /* OUT3L_ANC_SRC */
+#define WM5100_OUT3L_ANC_SRC_WIDTH                   1  /* OUT3L_ANC_SRC */
+#define WM5100_OUT3L_PGA_VOL_MASK               0x00FE  /* OUT3L_PGA_VOL - [7:1] */
+#define WM5100_OUT3L_PGA_VOL_SHIFT                   1  /* OUT3L_PGA_VOL - [7:1] */
+#define WM5100_OUT3L_PGA_VOL_WIDTH                   7  /* OUT3L_PGA_VOL - [7:1] */
+
+/*
+ * R1049 (0x419) - Out Volume 3R
+ */
+#define WM5100_OUT3R_ANC_SRC                    0x0800  /* OUT3R_ANC_SRC */
+#define WM5100_OUT3R_ANC_SRC_MASK               0x0800  /* OUT3R_ANC_SRC */
+#define WM5100_OUT3R_ANC_SRC_SHIFT                  11  /* OUT3R_ANC_SRC */
+#define WM5100_OUT3R_ANC_SRC_WIDTH                   1  /* OUT3R_ANC_SRC */
+#define WM5100_OUT3R_PGA_VOL_MASK               0x00FE  /* OUT3R_PGA_VOL - [7:1] */
+#define WM5100_OUT3R_PGA_VOL_SHIFT                   1  /* OUT3R_PGA_VOL - [7:1] */
+#define WM5100_OUT3R_PGA_VOL_WIDTH                   7  /* OUT3R_PGA_VOL - [7:1] */
+
+/*
+ * R1050 (0x41A) - DAC Volume Limit 3L
+ */
+#define WM5100_OUT3L_VOL_LIM_MASK               0x00FF  /* OUT3L_VOL_LIM - [7:0] */
+#define WM5100_OUT3L_VOL_LIM_SHIFT                   0  /* OUT3L_VOL_LIM - [7:0] */
+#define WM5100_OUT3L_VOL_LIM_WIDTH                   8  /* OUT3L_VOL_LIM - [7:0] */
+
+/*
+ * R1051 (0x41B) - DAC Volume Limit 3R
+ */
+#define WM5100_OUT3R_VOL_LIM_MASK               0x00FF  /* OUT3R_VOL_LIM - [7:0] */
+#define WM5100_OUT3R_VOL_LIM_SHIFT                   0  /* OUT3R_VOL_LIM - [7:0] */
+#define WM5100_OUT3R_VOL_LIM_WIDTH                   8  /* OUT3R_VOL_LIM - [7:0] */
+
+/*
+ * R1052 (0x41C) - Out Volume 4L
+ */
+#define WM5100_OUT4_OSR                         0x2000  /* OUT4_OSR */
+#define WM5100_OUT4_OSR_MASK                    0x2000  /* OUT4_OSR */
+#define WM5100_OUT4_OSR_SHIFT                       13  /* OUT4_OSR */
+#define WM5100_OUT4_OSR_WIDTH                        1  /* OUT4_OSR */
+#define WM5100_OUT4L_ANC_SRC                    0x0800  /* OUT4L_ANC_SRC */
+#define WM5100_OUT4L_ANC_SRC_MASK               0x0800  /* OUT4L_ANC_SRC */
+#define WM5100_OUT4L_ANC_SRC_SHIFT                  11  /* OUT4L_ANC_SRC */
+#define WM5100_OUT4L_ANC_SRC_WIDTH                   1  /* OUT4L_ANC_SRC */
+#define WM5100_OUT4L_VOL_LIM_MASK               0x00FF  /* OUT4L_VOL_LIM - [7:0] */
+#define WM5100_OUT4L_VOL_LIM_SHIFT                   0  /* OUT4L_VOL_LIM - [7:0] */
+#define WM5100_OUT4L_VOL_LIM_WIDTH                   8  /* OUT4L_VOL_LIM - [7:0] */
+
+/*
+ * R1053 (0x41D) - Out Volume 4R
+ */
+#define WM5100_OUT4R_ANC_SRC                    0x0800  /* OUT4R_ANC_SRC */
+#define WM5100_OUT4R_ANC_SRC_MASK               0x0800  /* OUT4R_ANC_SRC */
+#define WM5100_OUT4R_ANC_SRC_SHIFT                  11  /* OUT4R_ANC_SRC */
+#define WM5100_OUT4R_ANC_SRC_WIDTH                   1  /* OUT4R_ANC_SRC */
+#define WM5100_OUT4R_VOL_LIM_MASK               0x00FF  /* OUT4R_VOL_LIM - [7:0] */
+#define WM5100_OUT4R_VOL_LIM_SHIFT                   0  /* OUT4R_VOL_LIM - [7:0] */
+#define WM5100_OUT4R_VOL_LIM_WIDTH                   8  /* OUT4R_VOL_LIM - [7:0] */
+
+/*
+ * R1054 (0x41E) - DAC Volume Limit 5L
+ */
+#define WM5100_OUT5_OSR                         0x2000  /* OUT5_OSR */
+#define WM5100_OUT5_OSR_MASK                    0x2000  /* OUT5_OSR */
+#define WM5100_OUT5_OSR_SHIFT                       13  /* OUT5_OSR */
+#define WM5100_OUT5_OSR_WIDTH                        1  /* OUT5_OSR */
+#define WM5100_OUT5L_ANC_SRC                    0x0800  /* OUT5L_ANC_SRC */
+#define WM5100_OUT5L_ANC_SRC_MASK               0x0800  /* OUT5L_ANC_SRC */
+#define WM5100_OUT5L_ANC_SRC_SHIFT                  11  /* OUT5L_ANC_SRC */
+#define WM5100_OUT5L_ANC_SRC_WIDTH                   1  /* OUT5L_ANC_SRC */
+#define WM5100_OUT5L_VOL_LIM_MASK               0x00FF  /* OUT5L_VOL_LIM - [7:0] */
+#define WM5100_OUT5L_VOL_LIM_SHIFT                   0  /* OUT5L_VOL_LIM - [7:0] */
+#define WM5100_OUT5L_VOL_LIM_WIDTH                   8  /* OUT5L_VOL_LIM - [7:0] */
+
+/*
+ * R1055 (0x41F) - DAC Volume Limit 5R
+ */
+#define WM5100_OUT5R_ANC_SRC                    0x0800  /* OUT5R_ANC_SRC */
+#define WM5100_OUT5R_ANC_SRC_MASK               0x0800  /* OUT5R_ANC_SRC */
+#define WM5100_OUT5R_ANC_SRC_SHIFT                  11  /* OUT5R_ANC_SRC */
+#define WM5100_OUT5R_ANC_SRC_WIDTH                   1  /* OUT5R_ANC_SRC */
+#define WM5100_OUT5R_VOL_LIM_MASK               0x00FF  /* OUT5R_VOL_LIM - [7:0] */
+#define WM5100_OUT5R_VOL_LIM_SHIFT                   0  /* OUT5R_VOL_LIM - [7:0] */
+#define WM5100_OUT5R_VOL_LIM_WIDTH                   8  /* OUT5R_VOL_LIM - [7:0] */
+
+/*
+ * R1056 (0x420) - DAC Volume Limit 6L
+ */
+#define WM5100_OUT6_OSR                         0x2000  /* OUT6_OSR */
+#define WM5100_OUT6_OSR_MASK                    0x2000  /* OUT6_OSR */
+#define WM5100_OUT6_OSR_SHIFT                       13  /* OUT6_OSR */
+#define WM5100_OUT6_OSR_WIDTH                        1  /* OUT6_OSR */
+#define WM5100_OUT6L_ANC_SRC                    0x0800  /* OUT6L_ANC_SRC */
+#define WM5100_OUT6L_ANC_SRC_MASK               0x0800  /* OUT6L_ANC_SRC */
+#define WM5100_OUT6L_ANC_SRC_SHIFT                  11  /* OUT6L_ANC_SRC */
+#define WM5100_OUT6L_ANC_SRC_WIDTH                   1  /* OUT6L_ANC_SRC */
+#define WM5100_OUT6L_VOL_LIM_MASK               0x00FF  /* OUT6L_VOL_LIM - [7:0] */
+#define WM5100_OUT6L_VOL_LIM_SHIFT                   0  /* OUT6L_VOL_LIM - [7:0] */
+#define WM5100_OUT6L_VOL_LIM_WIDTH                   8  /* OUT6L_VOL_LIM - [7:0] */
+
+/*
+ * R1057 (0x421) - DAC Volume Limit 6R
+ */
+#define WM5100_OUT6R_ANC_SRC                    0x0800  /* OUT6R_ANC_SRC */
+#define WM5100_OUT6R_ANC_SRC_MASK               0x0800  /* OUT6R_ANC_SRC */
+#define WM5100_OUT6R_ANC_SRC_SHIFT                  11  /* OUT6R_ANC_SRC */
+#define WM5100_OUT6R_ANC_SRC_WIDTH                   1  /* OUT6R_ANC_SRC */
+#define WM5100_OUT6R_VOL_LIM_MASK               0x00FF  /* OUT6R_VOL_LIM - [7:0] */
+#define WM5100_OUT6R_VOL_LIM_SHIFT                   0  /* OUT6R_VOL_LIM - [7:0] */
+#define WM5100_OUT6R_VOL_LIM_WIDTH                   8  /* OUT6R_VOL_LIM - [7:0] */
+
+/*
+ * R1088 (0x440) - DAC AEC Control 1
+ */
+#define WM5100_AEC_LOOPBACK_SRC_MASK            0x003C  /* AEC_LOOPBACK_SRC - [5:2] */
+#define WM5100_AEC_LOOPBACK_SRC_SHIFT                2  /* AEC_LOOPBACK_SRC - [5:2] */
+#define WM5100_AEC_LOOPBACK_SRC_WIDTH                4  /* AEC_LOOPBACK_SRC - [5:2] */
+#define WM5100_AEC_ENA_STS                      0x0002  /* AEC_ENA_STS */
+#define WM5100_AEC_ENA_STS_MASK                 0x0002  /* AEC_ENA_STS */
+#define WM5100_AEC_ENA_STS_SHIFT                     1  /* AEC_ENA_STS */
+#define WM5100_AEC_ENA_STS_WIDTH                     1  /* AEC_ENA_STS */
+#define WM5100_AEC_LOOPBACK_ENA                 0x0001  /* AEC_LOOPBACK_ENA */
+#define WM5100_AEC_LOOPBACK_ENA_MASK            0x0001  /* AEC_LOOPBACK_ENA */
+#define WM5100_AEC_LOOPBACK_ENA_SHIFT                0  /* AEC_LOOPBACK_ENA */
+#define WM5100_AEC_LOOPBACK_ENA_WIDTH                1  /* AEC_LOOPBACK_ENA */
+
+/*
+ * R1089 (0x441) - Output Volume Ramp
+ */
+#define WM5100_OUT_VD_RAMP_MASK                 0x0070  /* OUT_VD_RAMP - [6:4] */
+#define WM5100_OUT_VD_RAMP_SHIFT                     4  /* OUT_VD_RAMP - [6:4] */
+#define WM5100_OUT_VD_RAMP_WIDTH                     3  /* OUT_VD_RAMP - [6:4] */
+#define WM5100_OUT_VI_RAMP_MASK                 0x0007  /* OUT_VI_RAMP - [2:0] */
+#define WM5100_OUT_VI_RAMP_SHIFT                     0  /* OUT_VI_RAMP - [2:0] */
+#define WM5100_OUT_VI_RAMP_WIDTH                     3  /* OUT_VI_RAMP - [2:0] */
+
+/*
+ * R1152 (0x480) - DAC Digital Volume 1L
+ */
+#define WM5100_OUT_VU                           0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM5100_OUT1L_MUTE                       0x0100  /* OUT1L_MUTE */
+#define WM5100_OUT1L_MUTE_MASK                  0x0100  /* OUT1L_MUTE */
+#define WM5100_OUT1L_MUTE_SHIFT                      8  /* OUT1L_MUTE */
+#define WM5100_OUT1L_MUTE_WIDTH                      1  /* OUT1L_MUTE */
+#define WM5100_OUT1L_VOL_MASK                   0x00FF  /* OUT1L_VOL - [7:0] */
+#define WM5100_OUT1L_VOL_SHIFT                       0  /* OUT1L_VOL - [7:0] */
+#define WM5100_OUT1L_VOL_WIDTH                       8  /* OUT1L_VOL - [7:0] */
+
+/*
+ * R1153 (0x481) - DAC Digital Volume 1R
+ */
+#define WM5100_OUT_VU                           0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM5100_OUT1R_MUTE                       0x0100  /* OUT1R_MUTE */
+#define WM5100_OUT1R_MUTE_MASK                  0x0100  /* OUT1R_MUTE */
+#define WM5100_OUT1R_MUTE_SHIFT                      8  /* OUT1R_MUTE */
+#define WM5100_OUT1R_MUTE_WIDTH                      1  /* OUT1R_MUTE */
+#define WM5100_OUT1R_VOL_MASK                   0x00FF  /* OUT1R_VOL - [7:0] */
+#define WM5100_OUT1R_VOL_SHIFT                       0  /* OUT1R_VOL - [7:0] */
+#define WM5100_OUT1R_VOL_WIDTH                       8  /* OUT1R_VOL - [7:0] */
+
+/*
+ * R1154 (0x482) - DAC Digital Volume 2L
+ */
+#define WM5100_OUT_VU                           0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM5100_OUT2L_MUTE                       0x0100  /* OUT2L_MUTE */
+#define WM5100_OUT2L_MUTE_MASK                  0x0100  /* OUT2L_MUTE */
+#define WM5100_OUT2L_MUTE_SHIFT                      8  /* OUT2L_MUTE */
+#define WM5100_OUT2L_MUTE_WIDTH                      1  /* OUT2L_MUTE */
+#define WM5100_OUT2L_VOL_MASK                   0x00FF  /* OUT2L_VOL - [7:0] */
+#define WM5100_OUT2L_VOL_SHIFT                       0  /* OUT2L_VOL - [7:0] */
+#define WM5100_OUT2L_VOL_WIDTH                       8  /* OUT2L_VOL - [7:0] */
+
+/*
+ * R1155 (0x483) - DAC Digital Volume 2R
+ */
+#define WM5100_OUT_VU                           0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM5100_OUT2R_MUTE                       0x0100  /* OUT2R_MUTE */
+#define WM5100_OUT2R_MUTE_MASK                  0x0100  /* OUT2R_MUTE */
+#define WM5100_OUT2R_MUTE_SHIFT                      8  /* OUT2R_MUTE */
+#define WM5100_OUT2R_MUTE_WIDTH                      1  /* OUT2R_MUTE */
+#define WM5100_OUT2R_VOL_MASK                   0x00FF  /* OUT2R_VOL - [7:0] */
+#define WM5100_OUT2R_VOL_SHIFT                       0  /* OUT2R_VOL - [7:0] */
+#define WM5100_OUT2R_VOL_WIDTH                       8  /* OUT2R_VOL - [7:0] */
+
+/*
+ * R1156 (0x484) - DAC Digital Volume 3L
+ */
+#define WM5100_OUT_VU                           0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM5100_OUT3L_MUTE                       0x0100  /* OUT3L_MUTE */
+#define WM5100_OUT3L_MUTE_MASK                  0x0100  /* OUT3L_MUTE */
+#define WM5100_OUT3L_MUTE_SHIFT                      8  /* OUT3L_MUTE */
+#define WM5100_OUT3L_MUTE_WIDTH                      1  /* OUT3L_MUTE */
+#define WM5100_OUT3L_VOL_MASK                   0x00FF  /* OUT3L_VOL - [7:0] */
+#define WM5100_OUT3L_VOL_SHIFT                       0  /* OUT3L_VOL - [7:0] */
+#define WM5100_OUT3L_VOL_WIDTH                       8  /* OUT3L_VOL - [7:0] */
+
+/*
+ * R1157 (0x485) - DAC Digital Volume 3R
+ */
+#define WM5100_OUT_VU                           0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM5100_OUT3R_MUTE                       0x0100  /* OUT3R_MUTE */
+#define WM5100_OUT3R_MUTE_MASK                  0x0100  /* OUT3R_MUTE */
+#define WM5100_OUT3R_MUTE_SHIFT                      8  /* OUT3R_MUTE */
+#define WM5100_OUT3R_MUTE_WIDTH                      1  /* OUT3R_MUTE */
+#define WM5100_OUT3R_VOL_MASK                   0x00FF  /* OUT3R_VOL - [7:0] */
+#define WM5100_OUT3R_VOL_SHIFT                       0  /* OUT3R_VOL - [7:0] */
+#define WM5100_OUT3R_VOL_WIDTH                       8  /* OUT3R_VOL - [7:0] */
+
+/*
+ * R1158 (0x486) - DAC Digital Volume 4L
+ */
+#define WM5100_OUT_VU                           0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM5100_OUT4L_MUTE                       0x0100  /* OUT4L_MUTE */
+#define WM5100_OUT4L_MUTE_MASK                  0x0100  /* OUT4L_MUTE */
+#define WM5100_OUT4L_MUTE_SHIFT                      8  /* OUT4L_MUTE */
+#define WM5100_OUT4L_MUTE_WIDTH                      1  /* OUT4L_MUTE */
+#define WM5100_OUT4L_VOL_MASK                   0x00FF  /* OUT4L_VOL - [7:0] */
+#define WM5100_OUT4L_VOL_SHIFT                       0  /* OUT4L_VOL - [7:0] */
+#define WM5100_OUT4L_VOL_WIDTH                       8  /* OUT4L_VOL - [7:0] */
+
+/*
+ * R1159 (0x487) - DAC Digital Volume 4R
+ */
+#define WM5100_OUT_VU                           0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM5100_OUT4R_MUTE                       0x0100  /* OUT4R_MUTE */
+#define WM5100_OUT4R_MUTE_MASK                  0x0100  /* OUT4R_MUTE */
+#define WM5100_OUT4R_MUTE_SHIFT                      8  /* OUT4R_MUTE */
+#define WM5100_OUT4R_MUTE_WIDTH                      1  /* OUT4R_MUTE */
+#define WM5100_OUT4R_VOL_MASK                   0x00FF  /* OUT4R_VOL - [7:0] */
+#define WM5100_OUT4R_VOL_SHIFT                       0  /* OUT4R_VOL - [7:0] */
+#define WM5100_OUT4R_VOL_WIDTH                       8  /* OUT4R_VOL - [7:0] */
+
+/*
+ * R1160 (0x488) - DAC Digital Volume 5L
+ */
+#define WM5100_OUT_VU                           0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM5100_OUT5L_MUTE                       0x0100  /* OUT5L_MUTE */
+#define WM5100_OUT5L_MUTE_MASK                  0x0100  /* OUT5L_MUTE */
+#define WM5100_OUT5L_MUTE_SHIFT                      8  /* OUT5L_MUTE */
+#define WM5100_OUT5L_MUTE_WIDTH                      1  /* OUT5L_MUTE */
+#define WM5100_OUT5L_VOL_MASK                   0x00FF  /* OUT5L_VOL - [7:0] */
+#define WM5100_OUT5L_VOL_SHIFT                       0  /* OUT5L_VOL - [7:0] */
+#define WM5100_OUT5L_VOL_WIDTH                       8  /* OUT5L_VOL - [7:0] */
+
+/*
+ * R1161 (0x489) - DAC Digital Volume 5R
+ */
+#define WM5100_OUT_VU                           0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM5100_OUT5R_MUTE                       0x0100  /* OUT5R_MUTE */
+#define WM5100_OUT5R_MUTE_MASK                  0x0100  /* OUT5R_MUTE */
+#define WM5100_OUT5R_MUTE_SHIFT                      8  /* OUT5R_MUTE */
+#define WM5100_OUT5R_MUTE_WIDTH                      1  /* OUT5R_MUTE */
+#define WM5100_OUT5R_VOL_MASK                   0x00FF  /* OUT5R_VOL - [7:0] */
+#define WM5100_OUT5R_VOL_SHIFT                       0  /* OUT5R_VOL - [7:0] */
+#define WM5100_OUT5R_VOL_WIDTH                       8  /* OUT5R_VOL - [7:0] */
+
+/*
+ * R1162 (0x48A) - DAC Digital Volume 6L
+ */
+#define WM5100_OUT_VU                           0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM5100_OUT6L_MUTE                       0x0100  /* OUT6L_MUTE */
+#define WM5100_OUT6L_MUTE_MASK                  0x0100  /* OUT6L_MUTE */
+#define WM5100_OUT6L_MUTE_SHIFT                      8  /* OUT6L_MUTE */
+#define WM5100_OUT6L_MUTE_WIDTH                      1  /* OUT6L_MUTE */
+#define WM5100_OUT6L_VOL_MASK                   0x00FF  /* OUT6L_VOL - [7:0] */
+#define WM5100_OUT6L_VOL_SHIFT                       0  /* OUT6L_VOL - [7:0] */
+#define WM5100_OUT6L_VOL_WIDTH                       8  /* OUT6L_VOL - [7:0] */
+
+/*
+ * R1163 (0x48B) - DAC Digital Volume 6R
+ */
+#define WM5100_OUT_VU                           0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define WM5100_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define WM5100_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define WM5100_OUT6R_MUTE                       0x0100  /* OUT6R_MUTE */
+#define WM5100_OUT6R_MUTE_MASK                  0x0100  /* OUT6R_MUTE */
+#define WM5100_OUT6R_MUTE_SHIFT                      8  /* OUT6R_MUTE */
+#define WM5100_OUT6R_MUTE_WIDTH                      1  /* OUT6R_MUTE */
+#define WM5100_OUT6R_VOL_MASK                   0x00FF  /* OUT6R_VOL - [7:0] */
+#define WM5100_OUT6R_VOL_SHIFT                       0  /* OUT6R_VOL - [7:0] */
+#define WM5100_OUT6R_VOL_WIDTH                       8  /* OUT6R_VOL - [7:0] */
+
+/*
+ * R1216 (0x4C0) - PDM SPK1 CTRL 1
+ */
+#define WM5100_SPK1R_MUTE                       0x2000  /* SPK1R_MUTE */
+#define WM5100_SPK1R_MUTE_MASK                  0x2000  /* SPK1R_MUTE */
+#define WM5100_SPK1R_MUTE_SHIFT                     13  /* SPK1R_MUTE */
+#define WM5100_SPK1R_MUTE_WIDTH                      1  /* SPK1R_MUTE */
+#define WM5100_SPK1L_MUTE                       0x1000  /* SPK1L_MUTE */
+#define WM5100_SPK1L_MUTE_MASK                  0x1000  /* SPK1L_MUTE */
+#define WM5100_SPK1L_MUTE_SHIFT                     12  /* SPK1L_MUTE */
+#define WM5100_SPK1L_MUTE_WIDTH                      1  /* SPK1L_MUTE */
+#define WM5100_SPK1_MUTE_ENDIAN                 0x0100  /* SPK1_MUTE_ENDIAN */
+#define WM5100_SPK1_MUTE_ENDIAN_MASK            0x0100  /* SPK1_MUTE_ENDIAN */
+#define WM5100_SPK1_MUTE_ENDIAN_SHIFT                8  /* SPK1_MUTE_ENDIAN */
+#define WM5100_SPK1_MUTE_ENDIAN_WIDTH                1  /* SPK1_MUTE_ENDIAN */
+#define WM5100_SPK1_MUTE_SEQ1_MASK              0x00FF  /* SPK1_MUTE_SEQ1 - [7:0] */
+#define WM5100_SPK1_MUTE_SEQ1_SHIFT                  0  /* SPK1_MUTE_SEQ1 - [7:0] */
+#define WM5100_SPK1_MUTE_SEQ1_WIDTH                  8  /* SPK1_MUTE_SEQ1 - [7:0] */
+
+/*
+ * R1217 (0x4C1) - PDM SPK1 CTRL 2
+ */
+#define WM5100_SPK1_FMT                         0x0001  /* SPK1_FMT */
+#define WM5100_SPK1_FMT_MASK                    0x0001  /* SPK1_FMT */
+#define WM5100_SPK1_FMT_SHIFT                        0  /* SPK1_FMT */
+#define WM5100_SPK1_FMT_WIDTH                        1  /* SPK1_FMT */
+
+/*
+ * R1218 (0x4C2) - PDM SPK2 CTRL 1
+ */
+#define WM5100_SPK2R_MUTE                       0x2000  /* SPK2R_MUTE */
+#define WM5100_SPK2R_MUTE_MASK                  0x2000  /* SPK2R_MUTE */
+#define WM5100_SPK2R_MUTE_SHIFT                     13  /* SPK2R_MUTE */
+#define WM5100_SPK2R_MUTE_WIDTH                      1  /* SPK2R_MUTE */
+#define WM5100_SPK2L_MUTE                       0x1000  /* SPK2L_MUTE */
+#define WM5100_SPK2L_MUTE_MASK                  0x1000  /* SPK2L_MUTE */
+#define WM5100_SPK2L_MUTE_SHIFT                     12  /* SPK2L_MUTE */
+#define WM5100_SPK2L_MUTE_WIDTH                      1  /* SPK2L_MUTE */
+#define WM5100_SPK2_MUTE_ENDIAN                 0x0100  /* SPK2_MUTE_ENDIAN */
+#define WM5100_SPK2_MUTE_ENDIAN_MASK            0x0100  /* SPK2_MUTE_ENDIAN */
+#define WM5100_SPK2_MUTE_ENDIAN_SHIFT                8  /* SPK2_MUTE_ENDIAN */
+#define WM5100_SPK2_MUTE_ENDIAN_WIDTH                1  /* SPK2_MUTE_ENDIAN */
+#define WM5100_SPK2_MUTE_SEQ1_MASK              0x00FF  /* SPK2_MUTE_SEQ1 - [7:0] */
+#define WM5100_SPK2_MUTE_SEQ1_SHIFT                  0  /* SPK2_MUTE_SEQ1 - [7:0] */
+#define WM5100_SPK2_MUTE_SEQ1_WIDTH                  8  /* SPK2_MUTE_SEQ1 - [7:0] */
+
+/*
+ * R1219 (0x4C3) - PDM SPK2 CTRL 2
+ */
+#define WM5100_SPK2_FMT                         0x0001  /* SPK2_FMT */
+#define WM5100_SPK2_FMT_MASK                    0x0001  /* SPK2_FMT */
+#define WM5100_SPK2_FMT_SHIFT                        0  /* SPK2_FMT */
+#define WM5100_SPK2_FMT_WIDTH                        1  /* SPK2_FMT */
+
+/*
+ * R1280 (0x500) - Audio IF 1_1
+ */
+#define WM5100_AIF1_BCLK_INV                    0x0080  /* AIF1_BCLK_INV */
+#define WM5100_AIF1_BCLK_INV_MASK               0x0080  /* AIF1_BCLK_INV */
+#define WM5100_AIF1_BCLK_INV_SHIFT                   7  /* AIF1_BCLK_INV */
+#define WM5100_AIF1_BCLK_INV_WIDTH                   1  /* AIF1_BCLK_INV */
+#define WM5100_AIF1_BCLK_FRC                    0x0040  /* AIF1_BCLK_FRC */
+#define WM5100_AIF1_BCLK_FRC_MASK               0x0040  /* AIF1_BCLK_FRC */
+#define WM5100_AIF1_BCLK_FRC_SHIFT                   6  /* AIF1_BCLK_FRC */
+#define WM5100_AIF1_BCLK_FRC_WIDTH                   1  /* AIF1_BCLK_FRC */
+#define WM5100_AIF1_BCLK_MSTR                   0x0020  /* AIF1_BCLK_MSTR */
+#define WM5100_AIF1_BCLK_MSTR_MASK              0x0020  /* AIF1_BCLK_MSTR */
+#define WM5100_AIF1_BCLK_MSTR_SHIFT                  5  /* AIF1_BCLK_MSTR */
+#define WM5100_AIF1_BCLK_MSTR_WIDTH                  1  /* AIF1_BCLK_MSTR */
+#define WM5100_AIF1_BCLK_FREQ_MASK              0x001F  /* AIF1_BCLK_FREQ - [4:0] */
+#define WM5100_AIF1_BCLK_FREQ_SHIFT                  0  /* AIF1_BCLK_FREQ - [4:0] */
+#define WM5100_AIF1_BCLK_FREQ_WIDTH                  5  /* AIF1_BCLK_FREQ - [4:0] */
+
+/*
+ * R1281 (0x501) - Audio IF 1_2
+ */
+#define WM5100_AIF1TX_DAT_TRI                   0x0020  /* AIF1TX_DAT_TRI */
+#define WM5100_AIF1TX_DAT_TRI_MASK              0x0020  /* AIF1TX_DAT_TRI */
+#define WM5100_AIF1TX_DAT_TRI_SHIFT                  5  /* AIF1TX_DAT_TRI */
+#define WM5100_AIF1TX_DAT_TRI_WIDTH                  1  /* AIF1TX_DAT_TRI */
+#define WM5100_AIF1TX_LRCLK_SRC                 0x0008  /* AIF1TX_LRCLK_SRC */
+#define WM5100_AIF1TX_LRCLK_SRC_MASK            0x0008  /* AIF1TX_LRCLK_SRC */
+#define WM5100_AIF1TX_LRCLK_SRC_SHIFT                3  /* AIF1TX_LRCLK_SRC */
+#define WM5100_AIF1TX_LRCLK_SRC_WIDTH                1  /* AIF1TX_LRCLK_SRC */
+#define WM5100_AIF1TX_LRCLK_INV                 0x0004  /* AIF1TX_LRCLK_INV */
+#define WM5100_AIF1TX_LRCLK_INV_MASK            0x0004  /* AIF1TX_LRCLK_INV */
+#define WM5100_AIF1TX_LRCLK_INV_SHIFT                2  /* AIF1TX_LRCLK_INV */
+#define WM5100_AIF1TX_LRCLK_INV_WIDTH                1  /* AIF1TX_LRCLK_INV */
+#define WM5100_AIF1TX_LRCLK_FRC                 0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM5100_AIF1TX_LRCLK_FRC_MASK            0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM5100_AIF1TX_LRCLK_FRC_SHIFT                1  /* AIF1TX_LRCLK_FRC */
+#define WM5100_AIF1TX_LRCLK_FRC_WIDTH                1  /* AIF1TX_LRCLK_FRC */
+#define WM5100_AIF1TX_LRCLK_MSTR                0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM5100_AIF1TX_LRCLK_MSTR_MASK           0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM5100_AIF1TX_LRCLK_MSTR_SHIFT               0  /* AIF1TX_LRCLK_MSTR */
+#define WM5100_AIF1TX_LRCLK_MSTR_WIDTH               1  /* AIF1TX_LRCLK_MSTR */
+
+/*
+ * R1282 (0x502) - Audio IF 1_3
+ */
+#define WM5100_AIF1RX_LRCLK_INV                 0x0004  /* AIF1RX_LRCLK_INV */
+#define WM5100_AIF1RX_LRCLK_INV_MASK            0x0004  /* AIF1RX_LRCLK_INV */
+#define WM5100_AIF1RX_LRCLK_INV_SHIFT                2  /* AIF1RX_LRCLK_INV */
+#define WM5100_AIF1RX_LRCLK_INV_WIDTH                1  /* AIF1RX_LRCLK_INV */
+#define WM5100_AIF1RX_LRCLK_FRC                 0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM5100_AIF1RX_LRCLK_FRC_MASK            0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM5100_AIF1RX_LRCLK_FRC_SHIFT                1  /* AIF1RX_LRCLK_FRC */
+#define WM5100_AIF1RX_LRCLK_FRC_WIDTH                1  /* AIF1RX_LRCLK_FRC */
+#define WM5100_AIF1RX_LRCLK_MSTR                0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM5100_AIF1RX_LRCLK_MSTR_MASK           0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM5100_AIF1RX_LRCLK_MSTR_SHIFT               0  /* AIF1RX_LRCLK_MSTR */
+#define WM5100_AIF1RX_LRCLK_MSTR_WIDTH               1  /* AIF1RX_LRCLK_MSTR */
+
+/*
+ * R1283 (0x503) - Audio IF 1_4
+ */
+#define WM5100_AIF1_TRI                         0x0040  /* AIF1_TRI */
+#define WM5100_AIF1_TRI_MASK                    0x0040  /* AIF1_TRI */
+#define WM5100_AIF1_TRI_SHIFT                        6  /* AIF1_TRI */
+#define WM5100_AIF1_TRI_WIDTH                        1  /* AIF1_TRI */
+#define WM5100_AIF1_RATE_MASK                   0x0003  /* AIF1_RATE - [1:0] */
+#define WM5100_AIF1_RATE_SHIFT                       0  /* AIF1_RATE - [1:0] */
+#define WM5100_AIF1_RATE_WIDTH                       2  /* AIF1_RATE - [1:0] */
+
+/*
+ * R1284 (0x504) - Audio IF 1_5
+ */
+#define WM5100_AIF1_FMT_MASK                    0x0007  /* AIF1_FMT - [2:0] */
+#define WM5100_AIF1_FMT_SHIFT                        0  /* AIF1_FMT - [2:0] */
+#define WM5100_AIF1_FMT_WIDTH                        3  /* AIF1_FMT - [2:0] */
+
+/*
+ * R1285 (0x505) - Audio IF 1_6
+ */
+#define WM5100_AIF1TX_BCPF_MASK                 0x1FFF  /* AIF1TX_BCPF - [12:0] */
+#define WM5100_AIF1TX_BCPF_SHIFT                     0  /* AIF1TX_BCPF - [12:0] */
+#define WM5100_AIF1TX_BCPF_WIDTH                    13  /* AIF1TX_BCPF - [12:0] */
+
+/*
+ * R1286 (0x506) - Audio IF 1_7
+ */
+#define WM5100_AIF1RX_BCPF_MASK                 0x1FFF  /* AIF1RX_BCPF - [12:0] */
+#define WM5100_AIF1RX_BCPF_SHIFT                     0  /* AIF1RX_BCPF - [12:0] */
+#define WM5100_AIF1RX_BCPF_WIDTH                    13  /* AIF1RX_BCPF - [12:0] */
+
+/*
+ * R1287 (0x507) - Audio IF 1_8
+ */
+#define WM5100_AIF1TX_WL_MASK                   0x3F00  /* AIF1TX_WL - [13:8] */
+#define WM5100_AIF1TX_WL_SHIFT                       8  /* AIF1TX_WL - [13:8] */
+#define WM5100_AIF1TX_WL_WIDTH                       6  /* AIF1TX_WL - [13:8] */
+#define WM5100_AIF1TX_SLOT_LEN_MASK             0x00FF  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM5100_AIF1TX_SLOT_LEN_SHIFT                 0  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM5100_AIF1TX_SLOT_LEN_WIDTH                 8  /* AIF1TX_SLOT_LEN - [7:0] */
+
+/*
+ * R1288 (0x508) - Audio IF 1_9
+ */
+#define WM5100_AIF1RX_WL_MASK                   0x3F00  /* AIF1RX_WL - [13:8] */
+#define WM5100_AIF1RX_WL_SHIFT                       8  /* AIF1RX_WL - [13:8] */
+#define WM5100_AIF1RX_WL_WIDTH                       6  /* AIF1RX_WL - [13:8] */
+#define WM5100_AIF1RX_SLOT_LEN_MASK             0x00FF  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM5100_AIF1RX_SLOT_LEN_SHIFT                 0  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM5100_AIF1RX_SLOT_LEN_WIDTH                 8  /* AIF1RX_SLOT_LEN - [7:0] */
+
+/*
+ * R1289 (0x509) - Audio IF 1_10
+ */
+#define WM5100_AIF1TX1_SLOT_MASK                0x003F  /* AIF1TX1_SLOT - [5:0] */
+#define WM5100_AIF1TX1_SLOT_SHIFT                    0  /* AIF1TX1_SLOT - [5:0] */
+#define WM5100_AIF1TX1_SLOT_WIDTH                    6  /* AIF1TX1_SLOT - [5:0] */
+
+/*
+ * R1290 (0x50A) - Audio IF 1_11
+ */
+#define WM5100_AIF1TX2_SLOT_MASK                0x003F  /* AIF1TX2_SLOT - [5:0] */
+#define WM5100_AIF1TX2_SLOT_SHIFT                    0  /* AIF1TX2_SLOT - [5:0] */
+#define WM5100_AIF1TX2_SLOT_WIDTH                    6  /* AIF1TX2_SLOT - [5:0] */
+
+/*
+ * R1291 (0x50B) - Audio IF 1_12
+ */
+#define WM5100_AIF1TX3_SLOT_MASK                0x003F  /* AIF1TX3_SLOT - [5:0] */
+#define WM5100_AIF1TX3_SLOT_SHIFT                    0  /* AIF1TX3_SLOT - [5:0] */
+#define WM5100_AIF1TX3_SLOT_WIDTH                    6  /* AIF1TX3_SLOT - [5:0] */
+
+/*
+ * R1292 (0x50C) - Audio IF 1_13
+ */
+#define WM5100_AIF1TX4_SLOT_MASK                0x003F  /* AIF1TX4_SLOT - [5:0] */
+#define WM5100_AIF1TX4_SLOT_SHIFT                    0  /* AIF1TX4_SLOT - [5:0] */
+#define WM5100_AIF1TX4_SLOT_WIDTH                    6  /* AIF1TX4_SLOT - [5:0] */
+
+/*
+ * R1293 (0x50D) - Audio IF 1_14
+ */
+#define WM5100_AIF1TX5_SLOT_MASK                0x003F  /* AIF1TX5_SLOT - [5:0] */
+#define WM5100_AIF1TX5_SLOT_SHIFT                    0  /* AIF1TX5_SLOT - [5:0] */
+#define WM5100_AIF1TX5_SLOT_WIDTH                    6  /* AIF1TX5_SLOT - [5:0] */
+
+/*
+ * R1294 (0x50E) - Audio IF 1_15
+ */
+#define WM5100_AIF1TX6_SLOT_MASK                0x003F  /* AIF1TX6_SLOT - [5:0] */
+#define WM5100_AIF1TX6_SLOT_SHIFT                    0  /* AIF1TX6_SLOT - [5:0] */
+#define WM5100_AIF1TX6_SLOT_WIDTH                    6  /* AIF1TX6_SLOT - [5:0] */
+
+/*
+ * R1295 (0x50F) - Audio IF 1_16
+ */
+#define WM5100_AIF1TX7_SLOT_MASK                0x003F  /* AIF1TX7_SLOT - [5:0] */
+#define WM5100_AIF1TX7_SLOT_SHIFT                    0  /* AIF1TX7_SLOT - [5:0] */
+#define WM5100_AIF1TX7_SLOT_WIDTH                    6  /* AIF1TX7_SLOT - [5:0] */
+
+/*
+ * R1296 (0x510) - Audio IF 1_17
+ */
+#define WM5100_AIF1TX8_SLOT_MASK                0x003F  /* AIF1TX8_SLOT - [5:0] */
+#define WM5100_AIF1TX8_SLOT_SHIFT                    0  /* AIF1TX8_SLOT - [5:0] */
+#define WM5100_AIF1TX8_SLOT_WIDTH                    6  /* AIF1TX8_SLOT - [5:0] */
+
+/*
+ * R1297 (0x511) - Audio IF 1_18
+ */
+#define WM5100_AIF1RX1_SLOT_MASK                0x003F  /* AIF1RX1_SLOT - [5:0] */
+#define WM5100_AIF1RX1_SLOT_SHIFT                    0  /* AIF1RX1_SLOT - [5:0] */
+#define WM5100_AIF1RX1_SLOT_WIDTH                    6  /* AIF1RX1_SLOT - [5:0] */
+
+/*
+ * R1298 (0x512) - Audio IF 1_19
+ */
+#define WM5100_AIF1RX2_SLOT_MASK                0x003F  /* AIF1RX2_SLOT - [5:0] */
+#define WM5100_AIF1RX2_SLOT_SHIFT                    0  /* AIF1RX2_SLOT - [5:0] */
+#define WM5100_AIF1RX2_SLOT_WIDTH                    6  /* AIF1RX2_SLOT - [5:0] */
+
+/*
+ * R1299 (0x513) - Audio IF 1_20
+ */
+#define WM5100_AIF1RX3_SLOT_MASK                0x003F  /* AIF1RX3_SLOT - [5:0] */
+#define WM5100_AIF1RX3_SLOT_SHIFT                    0  /* AIF1RX3_SLOT - [5:0] */
+#define WM5100_AIF1RX3_SLOT_WIDTH                    6  /* AIF1RX3_SLOT - [5:0] */
+
+/*
+ * R1300 (0x514) - Audio IF 1_21
+ */
+#define WM5100_AIF1RX4_SLOT_MASK                0x003F  /* AIF1RX4_SLOT - [5:0] */
+#define WM5100_AIF1RX4_SLOT_SHIFT                    0  /* AIF1RX4_SLOT - [5:0] */
+#define WM5100_AIF1RX4_SLOT_WIDTH                    6  /* AIF1RX4_SLOT - [5:0] */
+
+/*
+ * R1301 (0x515) - Audio IF 1_22
+ */
+#define WM5100_AIF1RX5_SLOT_MASK                0x003F  /* AIF1RX5_SLOT - [5:0] */
+#define WM5100_AIF1RX5_SLOT_SHIFT                    0  /* AIF1RX5_SLOT - [5:0] */
+#define WM5100_AIF1RX5_SLOT_WIDTH                    6  /* AIF1RX5_SLOT - [5:0] */
+
+/*
+ * R1302 (0x516) - Audio IF 1_23
+ */
+#define WM5100_AIF1RX6_SLOT_MASK                0x003F  /* AIF1RX6_SLOT - [5:0] */
+#define WM5100_AIF1RX6_SLOT_SHIFT                    0  /* AIF1RX6_SLOT - [5:0] */
+#define WM5100_AIF1RX6_SLOT_WIDTH                    6  /* AIF1RX6_SLOT - [5:0] */
+
+/*
+ * R1303 (0x517) - Audio IF 1_24
+ */
+#define WM5100_AIF1RX7_SLOT_MASK                0x003F  /* AIF1RX7_SLOT - [5:0] */
+#define WM5100_AIF1RX7_SLOT_SHIFT                    0  /* AIF1RX7_SLOT - [5:0] */
+#define WM5100_AIF1RX7_SLOT_WIDTH                    6  /* AIF1RX7_SLOT - [5:0] */
+
+/*
+ * R1304 (0x518) - Audio IF 1_25
+ */
+#define WM5100_AIF1RX8_SLOT_MASK                0x003F  /* AIF1RX8_SLOT - [5:0] */
+#define WM5100_AIF1RX8_SLOT_SHIFT                    0  /* AIF1RX8_SLOT - [5:0] */
+#define WM5100_AIF1RX8_SLOT_WIDTH                    6  /* AIF1RX8_SLOT - [5:0] */
+
+/*
+ * R1305 (0x519) - Audio IF 1_26
+ */
+#define WM5100_AIF1TX8_ENA                      0x0080  /* AIF1TX8_ENA */
+#define WM5100_AIF1TX8_ENA_MASK                 0x0080  /* AIF1TX8_ENA */
+#define WM5100_AIF1TX8_ENA_SHIFT                     7  /* AIF1TX8_ENA */
+#define WM5100_AIF1TX8_ENA_WIDTH                     1  /* AIF1TX8_ENA */
+#define WM5100_AIF1TX7_ENA                      0x0040  /* AIF1TX7_ENA */
+#define WM5100_AIF1TX7_ENA_MASK                 0x0040  /* AIF1TX7_ENA */
+#define WM5100_AIF1TX7_ENA_SHIFT                     6  /* AIF1TX7_ENA */
+#define WM5100_AIF1TX7_ENA_WIDTH                     1  /* AIF1TX7_ENA */
+#define WM5100_AIF1TX6_ENA                      0x0020  /* AIF1TX6_ENA */
+#define WM5100_AIF1TX6_ENA_MASK                 0x0020  /* AIF1TX6_ENA */
+#define WM5100_AIF1TX6_ENA_SHIFT                     5  /* AIF1TX6_ENA */
+#define WM5100_AIF1TX6_ENA_WIDTH                     1  /* AIF1TX6_ENA */
+#define WM5100_AIF1TX5_ENA                      0x0010  /* AIF1TX5_ENA */
+#define WM5100_AIF1TX5_ENA_MASK                 0x0010  /* AIF1TX5_ENA */
+#define WM5100_AIF1TX5_ENA_SHIFT                     4  /* AIF1TX5_ENA */
+#define WM5100_AIF1TX5_ENA_WIDTH                     1  /* AIF1TX5_ENA */
+#define WM5100_AIF1TX4_ENA                      0x0008  /* AIF1TX4_ENA */
+#define WM5100_AIF1TX4_ENA_MASK                 0x0008  /* AIF1TX4_ENA */
+#define WM5100_AIF1TX4_ENA_SHIFT                     3  /* AIF1TX4_ENA */
+#define WM5100_AIF1TX4_ENA_WIDTH                     1  /* AIF1TX4_ENA */
+#define WM5100_AIF1TX3_ENA                      0x0004  /* AIF1TX3_ENA */
+#define WM5100_AIF1TX3_ENA_MASK                 0x0004  /* AIF1TX3_ENA */
+#define WM5100_AIF1TX3_ENA_SHIFT                     2  /* AIF1TX3_ENA */
+#define WM5100_AIF1TX3_ENA_WIDTH                     1  /* AIF1TX3_ENA */
+#define WM5100_AIF1TX2_ENA                      0x0002  /* AIF1TX2_ENA */
+#define WM5100_AIF1TX2_ENA_MASK                 0x0002  /* AIF1TX2_ENA */
+#define WM5100_AIF1TX2_ENA_SHIFT                     1  /* AIF1TX2_ENA */
+#define WM5100_AIF1TX2_ENA_WIDTH                     1  /* AIF1TX2_ENA */
+#define WM5100_AIF1TX1_ENA                      0x0001  /* AIF1TX1_ENA */
+#define WM5100_AIF1TX1_ENA_MASK                 0x0001  /* AIF1TX1_ENA */
+#define WM5100_AIF1TX1_ENA_SHIFT                     0  /* AIF1TX1_ENA */
+#define WM5100_AIF1TX1_ENA_WIDTH                     1  /* AIF1TX1_ENA */
+
+/*
+ * R1306 (0x51A) - Audio IF 1_27
+ */
+#define WM5100_AIF1RX8_ENA                      0x0080  /* AIF1RX8_ENA */
+#define WM5100_AIF1RX8_ENA_MASK                 0x0080  /* AIF1RX8_ENA */
+#define WM5100_AIF1RX8_ENA_SHIFT                     7  /* AIF1RX8_ENA */
+#define WM5100_AIF1RX8_ENA_WIDTH                     1  /* AIF1RX8_ENA */
+#define WM5100_AIF1RX7_ENA                      0x0040  /* AIF1RX7_ENA */
+#define WM5100_AIF1RX7_ENA_MASK                 0x0040  /* AIF1RX7_ENA */
+#define WM5100_AIF1RX7_ENA_SHIFT                     6  /* AIF1RX7_ENA */
+#define WM5100_AIF1RX7_ENA_WIDTH                     1  /* AIF1RX7_ENA */
+#define WM5100_AIF1RX6_ENA                      0x0020  /* AIF1RX6_ENA */
+#define WM5100_AIF1RX6_ENA_MASK                 0x0020  /* AIF1RX6_ENA */
+#define WM5100_AIF1RX6_ENA_SHIFT                     5  /* AIF1RX6_ENA */
+#define WM5100_AIF1RX6_ENA_WIDTH                     1  /* AIF1RX6_ENA */
+#define WM5100_AIF1RX5_ENA                      0x0010  /* AIF1RX5_ENA */
+#define WM5100_AIF1RX5_ENA_MASK                 0x0010  /* AIF1RX5_ENA */
+#define WM5100_AIF1RX5_ENA_SHIFT                     4  /* AIF1RX5_ENA */
+#define WM5100_AIF1RX5_ENA_WIDTH                     1  /* AIF1RX5_ENA */
+#define WM5100_AIF1RX4_ENA                      0x0008  /* AIF1RX4_ENA */
+#define WM5100_AIF1RX4_ENA_MASK                 0x0008  /* AIF1RX4_ENA */
+#define WM5100_AIF1RX4_ENA_SHIFT                     3  /* AIF1RX4_ENA */
+#define WM5100_AIF1RX4_ENA_WIDTH                     1  /* AIF1RX4_ENA */
+#define WM5100_AIF1RX3_ENA                      0x0004  /* AIF1RX3_ENA */
+#define WM5100_AIF1RX3_ENA_MASK                 0x0004  /* AIF1RX3_ENA */
+#define WM5100_AIF1RX3_ENA_SHIFT                     2  /* AIF1RX3_ENA */
+#define WM5100_AIF1RX3_ENA_WIDTH                     1  /* AIF1RX3_ENA */
+#define WM5100_AIF1RX2_ENA                      0x0002  /* AIF1RX2_ENA */
+#define WM5100_AIF1RX2_ENA_MASK                 0x0002  /* AIF1RX2_ENA */
+#define WM5100_AIF1RX2_ENA_SHIFT                     1  /* AIF1RX2_ENA */
+#define WM5100_AIF1RX2_ENA_WIDTH                     1  /* AIF1RX2_ENA */
+#define WM5100_AIF1RX1_ENA                      0x0001  /* AIF1RX1_ENA */
+#define WM5100_AIF1RX1_ENA_MASK                 0x0001  /* AIF1RX1_ENA */
+#define WM5100_AIF1RX1_ENA_SHIFT                     0  /* AIF1RX1_ENA */
+#define WM5100_AIF1RX1_ENA_WIDTH                     1  /* AIF1RX1_ENA */
+
+/*
+ * R1344 (0x540) - Audio IF 2_1
+ */
+#define WM5100_AIF2_BCLK_INV                    0x0080  /* AIF2_BCLK_INV */
+#define WM5100_AIF2_BCLK_INV_MASK               0x0080  /* AIF2_BCLK_INV */
+#define WM5100_AIF2_BCLK_INV_SHIFT                   7  /* AIF2_BCLK_INV */
+#define WM5100_AIF2_BCLK_INV_WIDTH                   1  /* AIF2_BCLK_INV */
+#define WM5100_AIF2_BCLK_FRC                    0x0040  /* AIF2_BCLK_FRC */
+#define WM5100_AIF2_BCLK_FRC_MASK               0x0040  /* AIF2_BCLK_FRC */
+#define WM5100_AIF2_BCLK_FRC_SHIFT                   6  /* AIF2_BCLK_FRC */
+#define WM5100_AIF2_BCLK_FRC_WIDTH                   1  /* AIF2_BCLK_FRC */
+#define WM5100_AIF2_BCLK_MSTR                   0x0020  /* AIF2_BCLK_MSTR */
+#define WM5100_AIF2_BCLK_MSTR_MASK              0x0020  /* AIF2_BCLK_MSTR */
+#define WM5100_AIF2_BCLK_MSTR_SHIFT                  5  /* AIF2_BCLK_MSTR */
+#define WM5100_AIF2_BCLK_MSTR_WIDTH                  1  /* AIF2_BCLK_MSTR */
+#define WM5100_AIF2_BCLK_FREQ_MASK              0x001F  /* AIF2_BCLK_FREQ - [4:0] */
+#define WM5100_AIF2_BCLK_FREQ_SHIFT                  0  /* AIF2_BCLK_FREQ - [4:0] */
+#define WM5100_AIF2_BCLK_FREQ_WIDTH                  5  /* AIF2_BCLK_FREQ - [4:0] */
+
+/*
+ * R1345 (0x541) - Audio IF 2_2
+ */
+#define WM5100_AIF2TX_DAT_TRI                   0x0020  /* AIF2TX_DAT_TRI */
+#define WM5100_AIF2TX_DAT_TRI_MASK              0x0020  /* AIF2TX_DAT_TRI */
+#define WM5100_AIF2TX_DAT_TRI_SHIFT                  5  /* AIF2TX_DAT_TRI */
+#define WM5100_AIF2TX_DAT_TRI_WIDTH                  1  /* AIF2TX_DAT_TRI */
+#define WM5100_AIF2TX_LRCLK_SRC                 0x0008  /* AIF2TX_LRCLK_SRC */
+#define WM5100_AIF2TX_LRCLK_SRC_MASK            0x0008  /* AIF2TX_LRCLK_SRC */
+#define WM5100_AIF2TX_LRCLK_SRC_SHIFT                3  /* AIF2TX_LRCLK_SRC */
+#define WM5100_AIF2TX_LRCLK_SRC_WIDTH                1  /* AIF2TX_LRCLK_SRC */
+#define WM5100_AIF2TX_LRCLK_INV                 0x0004  /* AIF2TX_LRCLK_INV */
+#define WM5100_AIF2TX_LRCLK_INV_MASK            0x0004  /* AIF2TX_LRCLK_INV */
+#define WM5100_AIF2TX_LRCLK_INV_SHIFT                2  /* AIF2TX_LRCLK_INV */
+#define WM5100_AIF2TX_LRCLK_INV_WIDTH                1  /* AIF2TX_LRCLK_INV */
+#define WM5100_AIF2TX_LRCLK_FRC                 0x0002  /* AIF2TX_LRCLK_FRC */
+#define WM5100_AIF2TX_LRCLK_FRC_MASK            0x0002  /* AIF2TX_LRCLK_FRC */
+#define WM5100_AIF2TX_LRCLK_FRC_SHIFT                1  /* AIF2TX_LRCLK_FRC */
+#define WM5100_AIF2TX_LRCLK_FRC_WIDTH                1  /* AIF2TX_LRCLK_FRC */
+#define WM5100_AIF2TX_LRCLK_MSTR                0x0001  /* AIF2TX_LRCLK_MSTR */
+#define WM5100_AIF2TX_LRCLK_MSTR_MASK           0x0001  /* AIF2TX_LRCLK_MSTR */
+#define WM5100_AIF2TX_LRCLK_MSTR_SHIFT               0  /* AIF2TX_LRCLK_MSTR */
+#define WM5100_AIF2TX_LRCLK_MSTR_WIDTH               1  /* AIF2TX_LRCLK_MSTR */
+
+/*
+ * R1346 (0x542) - Audio IF 2_3
+ */
+#define WM5100_AIF2RX_LRCLK_INV                 0x0004  /* AIF2RX_LRCLK_INV */
+#define WM5100_AIF2RX_LRCLK_INV_MASK            0x0004  /* AIF2RX_LRCLK_INV */
+#define WM5100_AIF2RX_LRCLK_INV_SHIFT                2  /* AIF2RX_LRCLK_INV */
+#define WM5100_AIF2RX_LRCLK_INV_WIDTH                1  /* AIF2RX_LRCLK_INV */
+#define WM5100_AIF2RX_LRCLK_FRC                 0x0002  /* AIF2RX_LRCLK_FRC */
+#define WM5100_AIF2RX_LRCLK_FRC_MASK            0x0002  /* AIF2RX_LRCLK_FRC */
+#define WM5100_AIF2RX_LRCLK_FRC_SHIFT                1  /* AIF2RX_LRCLK_FRC */
+#define WM5100_AIF2RX_LRCLK_FRC_WIDTH                1  /* AIF2RX_LRCLK_FRC */
+#define WM5100_AIF2RX_LRCLK_MSTR                0x0001  /* AIF2RX_LRCLK_MSTR */
+#define WM5100_AIF2RX_LRCLK_MSTR_MASK           0x0001  /* AIF2RX_LRCLK_MSTR */
+#define WM5100_AIF2RX_LRCLK_MSTR_SHIFT               0  /* AIF2RX_LRCLK_MSTR */
+#define WM5100_AIF2RX_LRCLK_MSTR_WIDTH               1  /* AIF2RX_LRCLK_MSTR */
+
+/*
+ * R1347 (0x543) - Audio IF 2_4
+ */
+#define WM5100_AIF2_TRI                         0x0040  /* AIF2_TRI */
+#define WM5100_AIF2_TRI_MASK                    0x0040  /* AIF2_TRI */
+#define WM5100_AIF2_TRI_SHIFT                        6  /* AIF2_TRI */
+#define WM5100_AIF2_TRI_WIDTH                        1  /* AIF2_TRI */
+#define WM5100_AIF2_RATE_MASK                   0x0003  /* AIF2_RATE - [1:0] */
+#define WM5100_AIF2_RATE_SHIFT                       0  /* AIF2_RATE - [1:0] */
+#define WM5100_AIF2_RATE_WIDTH                       2  /* AIF2_RATE - [1:0] */
+
+/*
+ * R1348 (0x544) - Audio IF 2_5
+ */
+#define WM5100_AIF2_FMT_MASK                    0x0007  /* AIF2_FMT - [2:0] */
+#define WM5100_AIF2_FMT_SHIFT                        0  /* AIF2_FMT - [2:0] */
+#define WM5100_AIF2_FMT_WIDTH                        3  /* AIF2_FMT - [2:0] */
+
+/*
+ * R1349 (0x545) - Audio IF 2_6
+ */
+#define WM5100_AIF2TX_BCPF_MASK                 0x1FFF  /* AIF2TX_BCPF - [12:0] */
+#define WM5100_AIF2TX_BCPF_SHIFT                     0  /* AIF2TX_BCPF - [12:0] */
+#define WM5100_AIF2TX_BCPF_WIDTH                    13  /* AIF2TX_BCPF - [12:0] */
+
+/*
+ * R1350 (0x546) - Audio IF 2_7
+ */
+#define WM5100_AIF2RX_BCPF_MASK                 0x1FFF  /* AIF2RX_BCPF - [12:0] */
+#define WM5100_AIF2RX_BCPF_SHIFT                     0  /* AIF2RX_BCPF - [12:0] */
+#define WM5100_AIF2RX_BCPF_WIDTH                    13  /* AIF2RX_BCPF - [12:0] */
+
+/*
+ * R1351 (0x547) - Audio IF 2_8
+ */
+#define WM5100_AIF2TX_WL_MASK                   0x3F00  /* AIF2TX_WL - [13:8] */
+#define WM5100_AIF2TX_WL_SHIFT                       8  /* AIF2TX_WL - [13:8] */
+#define WM5100_AIF2TX_WL_WIDTH                       6  /* AIF2TX_WL - [13:8] */
+#define WM5100_AIF2TX_SLOT_LEN_MASK             0x00FF  /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM5100_AIF2TX_SLOT_LEN_SHIFT                 0  /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM5100_AIF2TX_SLOT_LEN_WIDTH                 8  /* AIF2TX_SLOT_LEN - [7:0] */
+
+/*
+ * R1352 (0x548) - Audio IF 2_9
+ */
+#define WM5100_AIF2RX_WL_MASK                   0x3F00  /* AIF2RX_WL - [13:8] */
+#define WM5100_AIF2RX_WL_SHIFT                       8  /* AIF2RX_WL - [13:8] */
+#define WM5100_AIF2RX_WL_WIDTH                       6  /* AIF2RX_WL - [13:8] */
+#define WM5100_AIF2RX_SLOT_LEN_MASK             0x00FF  /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM5100_AIF2RX_SLOT_LEN_SHIFT                 0  /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM5100_AIF2RX_SLOT_LEN_WIDTH                 8  /* AIF2RX_SLOT_LEN - [7:0] */
+
+/*
+ * R1353 (0x549) - Audio IF 2_10
+ */
+#define WM5100_AIF2TX1_SLOT_MASK                0x003F  /* AIF2TX1_SLOT - [5:0] */
+#define WM5100_AIF2TX1_SLOT_SHIFT                    0  /* AIF2TX1_SLOT - [5:0] */
+#define WM5100_AIF2TX1_SLOT_WIDTH                    6  /* AIF2TX1_SLOT - [5:0] */
+
+/*
+ * R1354 (0x54A) - Audio IF 2_11
+ */
+#define WM5100_AIF2TX2_SLOT_MASK                0x003F  /* AIF2TX2_SLOT - [5:0] */
+#define WM5100_AIF2TX2_SLOT_SHIFT                    0  /* AIF2TX2_SLOT - [5:0] */
+#define WM5100_AIF2TX2_SLOT_WIDTH                    6  /* AIF2TX2_SLOT - [5:0] */
+
+/*
+ * R1361 (0x551) - Audio IF 2_18
+ */
+#define WM5100_AIF2RX1_SLOT_MASK                0x003F  /* AIF2RX1_SLOT - [5:0] */
+#define WM5100_AIF2RX1_SLOT_SHIFT                    0  /* AIF2RX1_SLOT - [5:0] */
+#define WM5100_AIF2RX1_SLOT_WIDTH                    6  /* AIF2RX1_SLOT - [5:0] */
+
+/*
+ * R1362 (0x552) - Audio IF 2_19
+ */
+#define WM5100_AIF2RX2_SLOT_MASK                0x003F  /* AIF2RX2_SLOT - [5:0] */
+#define WM5100_AIF2RX2_SLOT_SHIFT                    0  /* AIF2RX2_SLOT - [5:0] */
+#define WM5100_AIF2RX2_SLOT_WIDTH                    6  /* AIF2RX2_SLOT - [5:0] */
+
+/*
+ * R1369 (0x559) - Audio IF 2_26
+ */
+#define WM5100_AIF2TX2_ENA                      0x0002  /* AIF2TX2_ENA */
+#define WM5100_AIF2TX2_ENA_MASK                 0x0002  /* AIF2TX2_ENA */
+#define WM5100_AIF2TX2_ENA_SHIFT                     1  /* AIF2TX2_ENA */
+#define WM5100_AIF2TX2_ENA_WIDTH                     1  /* AIF2TX2_ENA */
+#define WM5100_AIF2TX1_ENA                      0x0001  /* AIF2TX1_ENA */
+#define WM5100_AIF2TX1_ENA_MASK                 0x0001  /* AIF2TX1_ENA */
+#define WM5100_AIF2TX1_ENA_SHIFT                     0  /* AIF2TX1_ENA */
+#define WM5100_AIF2TX1_ENA_WIDTH                     1  /* AIF2TX1_ENA */
+
+/*
+ * R1370 (0x55A) - Audio IF 2_27
+ */
+#define WM5100_AIF2RX2_ENA                      0x0002  /* AIF2RX2_ENA */
+#define WM5100_AIF2RX2_ENA_MASK                 0x0002  /* AIF2RX2_ENA */
+#define WM5100_AIF2RX2_ENA_SHIFT                     1  /* AIF2RX2_ENA */
+#define WM5100_AIF2RX2_ENA_WIDTH                     1  /* AIF2RX2_ENA */
+#define WM5100_AIF2RX1_ENA                      0x0001  /* AIF2RX1_ENA */
+#define WM5100_AIF2RX1_ENA_MASK                 0x0001  /* AIF2RX1_ENA */
+#define WM5100_AIF2RX1_ENA_SHIFT                     0  /* AIF2RX1_ENA */
+#define WM5100_AIF2RX1_ENA_WIDTH                     1  /* AIF2RX1_ENA */
+
+/*
+ * R1408 (0x580) - Audio IF 3_1
+ */
+#define WM5100_AIF3_BCLK_INV                    0x0080  /* AIF3_BCLK_INV */
+#define WM5100_AIF3_BCLK_INV_MASK               0x0080  /* AIF3_BCLK_INV */
+#define WM5100_AIF3_BCLK_INV_SHIFT                   7  /* AIF3_BCLK_INV */
+#define WM5100_AIF3_BCLK_INV_WIDTH                   1  /* AIF3_BCLK_INV */
+#define WM5100_AIF3_BCLK_FRC                    0x0040  /* AIF3_BCLK_FRC */
+#define WM5100_AIF3_BCLK_FRC_MASK               0x0040  /* AIF3_BCLK_FRC */
+#define WM5100_AIF3_BCLK_FRC_SHIFT                   6  /* AIF3_BCLK_FRC */
+#define WM5100_AIF3_BCLK_FRC_WIDTH                   1  /* AIF3_BCLK_FRC */
+#define WM5100_AIF3_BCLK_MSTR                   0x0020  /* AIF3_BCLK_MSTR */
+#define WM5100_AIF3_BCLK_MSTR_MASK              0x0020  /* AIF3_BCLK_MSTR */
+#define WM5100_AIF3_BCLK_MSTR_SHIFT                  5  /* AIF3_BCLK_MSTR */
+#define WM5100_AIF3_BCLK_MSTR_WIDTH                  1  /* AIF3_BCLK_MSTR */
+#define WM5100_AIF3_BCLK_FREQ_MASK              0x001F  /* AIF3_BCLK_FREQ - [4:0] */
+#define WM5100_AIF3_BCLK_FREQ_SHIFT                  0  /* AIF3_BCLK_FREQ - [4:0] */
+#define WM5100_AIF3_BCLK_FREQ_WIDTH                  5  /* AIF3_BCLK_FREQ - [4:0] */
+
+/*
+ * R1409 (0x581) - Audio IF 3_2
+ */
+#define WM5100_AIF3TX_DAT_TRI                   0x0020  /* AIF3TX_DAT_TRI */
+#define WM5100_AIF3TX_DAT_TRI_MASK              0x0020  /* AIF3TX_DAT_TRI */
+#define WM5100_AIF3TX_DAT_TRI_SHIFT                  5  /* AIF3TX_DAT_TRI */
+#define WM5100_AIF3TX_DAT_TRI_WIDTH                  1  /* AIF3TX_DAT_TRI */
+#define WM5100_AIF3TX_LRCLK_SRC                 0x0008  /* AIF3TX_LRCLK_SRC */
+#define WM5100_AIF3TX_LRCLK_SRC_MASK            0x0008  /* AIF3TX_LRCLK_SRC */
+#define WM5100_AIF3TX_LRCLK_SRC_SHIFT                3  /* AIF3TX_LRCLK_SRC */
+#define WM5100_AIF3TX_LRCLK_SRC_WIDTH                1  /* AIF3TX_LRCLK_SRC */
+#define WM5100_AIF3TX_LRCLK_INV                 0x0004  /* AIF3TX_LRCLK_INV */
+#define WM5100_AIF3TX_LRCLK_INV_MASK            0x0004  /* AIF3TX_LRCLK_INV */
+#define WM5100_AIF3TX_LRCLK_INV_SHIFT                2  /* AIF3TX_LRCLK_INV */
+#define WM5100_AIF3TX_LRCLK_INV_WIDTH                1  /* AIF3TX_LRCLK_INV */
+#define WM5100_AIF3TX_LRCLK_FRC                 0x0002  /* AIF3TX_LRCLK_FRC */
+#define WM5100_AIF3TX_LRCLK_FRC_MASK            0x0002  /* AIF3TX_LRCLK_FRC */
+#define WM5100_AIF3TX_LRCLK_FRC_SHIFT                1  /* AIF3TX_LRCLK_FRC */
+#define WM5100_AIF3TX_LRCLK_FRC_WIDTH                1  /* AIF3TX_LRCLK_FRC */
+#define WM5100_AIF3TX_LRCLK_MSTR                0x0001  /* AIF3TX_LRCLK_MSTR */
+#define WM5100_AIF3TX_LRCLK_MSTR_MASK           0x0001  /* AIF3TX_LRCLK_MSTR */
+#define WM5100_AIF3TX_LRCLK_MSTR_SHIFT               0  /* AIF3TX_LRCLK_MSTR */
+#define WM5100_AIF3TX_LRCLK_MSTR_WIDTH               1  /* AIF3TX_LRCLK_MSTR */
+
+/*
+ * R1410 (0x582) - Audio IF 3_3
+ */
+#define WM5100_AIF3RX_LRCLK_INV                 0x0004  /* AIF3RX_LRCLK_INV */
+#define WM5100_AIF3RX_LRCLK_INV_MASK            0x0004  /* AIF3RX_LRCLK_INV */
+#define WM5100_AIF3RX_LRCLK_INV_SHIFT                2  /* AIF3RX_LRCLK_INV */
+#define WM5100_AIF3RX_LRCLK_INV_WIDTH                1  /* AIF3RX_LRCLK_INV */
+#define WM5100_AIF3RX_LRCLK_FRC                 0x0002  /* AIF3RX_LRCLK_FRC */
+#define WM5100_AIF3RX_LRCLK_FRC_MASK            0x0002  /* AIF3RX_LRCLK_FRC */
+#define WM5100_AIF3RX_LRCLK_FRC_SHIFT                1  /* AIF3RX_LRCLK_FRC */
+#define WM5100_AIF3RX_LRCLK_FRC_WIDTH                1  /* AIF3RX_LRCLK_FRC */
+#define WM5100_AIF3RX_LRCLK_MSTR                0x0001  /* AIF3RX_LRCLK_MSTR */
+#define WM5100_AIF3RX_LRCLK_MSTR_MASK           0x0001  /* AIF3RX_LRCLK_MSTR */
+#define WM5100_AIF3RX_LRCLK_MSTR_SHIFT               0  /* AIF3RX_LRCLK_MSTR */
+#define WM5100_AIF3RX_LRCLK_MSTR_WIDTH               1  /* AIF3RX_LRCLK_MSTR */
+
+/*
+ * R1411 (0x583) - Audio IF 3_4
+ */
+#define WM5100_AIF3_TRI                         0x0040  /* AIF3_TRI */
+#define WM5100_AIF3_TRI_MASK                    0x0040  /* AIF3_TRI */
+#define WM5100_AIF3_TRI_SHIFT                        6  /* AIF3_TRI */
+#define WM5100_AIF3_TRI_WIDTH                        1  /* AIF3_TRI */
+#define WM5100_AIF3_RATE_MASK                   0x0003  /* AIF3_RATE - [1:0] */
+#define WM5100_AIF3_RATE_SHIFT                       0  /* AIF3_RATE - [1:0] */
+#define WM5100_AIF3_RATE_WIDTH                       2  /* AIF3_RATE - [1:0] */
+
+/*
+ * R1412 (0x584) - Audio IF 3_5
+ */
+#define WM5100_AIF3_FMT_MASK                    0x0007  /* AIF3_FMT - [2:0] */
+#define WM5100_AIF3_FMT_SHIFT                        0  /* AIF3_FMT - [2:0] */
+#define WM5100_AIF3_FMT_WIDTH                        3  /* AIF3_FMT - [2:0] */
+
+/*
+ * R1413 (0x585) - Audio IF 3_6
+ */
+#define WM5100_AIF3TX_BCPF_MASK                 0x1FFF  /* AIF3TX_BCPF - [12:0] */
+#define WM5100_AIF3TX_BCPF_SHIFT                     0  /* AIF3TX_BCPF - [12:0] */
+#define WM5100_AIF3TX_BCPF_WIDTH                    13  /* AIF3TX_BCPF - [12:0] */
+
+/*
+ * R1414 (0x586) - Audio IF 3_7
+ */
+#define WM5100_AIF3RX_BCPF_MASK                 0x1FFF  /* AIF3RX_BCPF - [12:0] */
+#define WM5100_AIF3RX_BCPF_SHIFT                     0  /* AIF3RX_BCPF - [12:0] */
+#define WM5100_AIF3RX_BCPF_WIDTH                    13  /* AIF3RX_BCPF - [12:0] */
+
+/*
+ * R1415 (0x587) - Audio IF 3_8
+ */
+#define WM5100_AIF3TX_WL_MASK                   0x3F00  /* AIF3TX_WL - [13:8] */
+#define WM5100_AIF3TX_WL_SHIFT                       8  /* AIF3TX_WL - [13:8] */
+#define WM5100_AIF3TX_WL_WIDTH                       6  /* AIF3TX_WL - [13:8] */
+#define WM5100_AIF3TX_SLOT_LEN_MASK             0x00FF  /* AIF3TX_SLOT_LEN - [7:0] */
+#define WM5100_AIF3TX_SLOT_LEN_SHIFT                 0  /* AIF3TX_SLOT_LEN - [7:0] */
+#define WM5100_AIF3TX_SLOT_LEN_WIDTH                 8  /* AIF3TX_SLOT_LEN - [7:0] */
+
+/*
+ * R1416 (0x588) - Audio IF 3_9
+ */
+#define WM5100_AIF3RX_WL_MASK                   0x3F00  /* AIF3RX_WL - [13:8] */
+#define WM5100_AIF3RX_WL_SHIFT                       8  /* AIF3RX_WL - [13:8] */
+#define WM5100_AIF3RX_WL_WIDTH                       6  /* AIF3RX_WL - [13:8] */
+#define WM5100_AIF3RX_SLOT_LEN_MASK             0x00FF  /* AIF3RX_SLOT_LEN - [7:0] */
+#define WM5100_AIF3RX_SLOT_LEN_SHIFT                 0  /* AIF3RX_SLOT_LEN - [7:0] */
+#define WM5100_AIF3RX_SLOT_LEN_WIDTH                 8  /* AIF3RX_SLOT_LEN - [7:0] */
+
+/*
+ * R1417 (0x589) - Audio IF 3_10
+ */
+#define WM5100_AIF3TX1_SLOT_MASK                0x003F  /* AIF3TX1_SLOT - [5:0] */
+#define WM5100_AIF3TX1_SLOT_SHIFT                    0  /* AIF3TX1_SLOT - [5:0] */
+#define WM5100_AIF3TX1_SLOT_WIDTH                    6  /* AIF3TX1_SLOT - [5:0] */
+
+/*
+ * R1418 (0x58A) - Audio IF 3_11
+ */
+#define WM5100_AIF3TX2_SLOT_MASK                0x003F  /* AIF3TX2_SLOT - [5:0] */
+#define WM5100_AIF3TX2_SLOT_SHIFT                    0  /* AIF3TX2_SLOT - [5:0] */
+#define WM5100_AIF3TX2_SLOT_WIDTH                    6  /* AIF3TX2_SLOT - [5:0] */
+
+/*
+ * R1425 (0x591) - Audio IF 3_18
+ */
+#define WM5100_AIF3RX1_SLOT_MASK                0x003F  /* AIF3RX1_SLOT - [5:0] */
+#define WM5100_AIF3RX1_SLOT_SHIFT                    0  /* AIF3RX1_SLOT - [5:0] */
+#define WM5100_AIF3RX1_SLOT_WIDTH                    6  /* AIF3RX1_SLOT - [5:0] */
+
+/*
+ * R1426 (0x592) - Audio IF 3_19
+ */
+#define WM5100_AIF3RX2_SLOT_MASK                0x003F  /* AIF3RX2_SLOT - [5:0] */
+#define WM5100_AIF3RX2_SLOT_SHIFT                    0  /* AIF3RX2_SLOT - [5:0] */
+#define WM5100_AIF3RX2_SLOT_WIDTH                    6  /* AIF3RX2_SLOT - [5:0] */
+
+/*
+ * R1433 (0x599) - Audio IF 3_26
+ */
+#define WM5100_AIF3TX2_ENA                      0x0002  /* AIF3TX2_ENA */
+#define WM5100_AIF3TX2_ENA_MASK                 0x0002  /* AIF3TX2_ENA */
+#define WM5100_AIF3TX2_ENA_SHIFT                     1  /* AIF3TX2_ENA */
+#define WM5100_AIF3TX2_ENA_WIDTH                     1  /* AIF3TX2_ENA */
+#define WM5100_AIF3TX1_ENA                      0x0001  /* AIF3TX1_ENA */
+#define WM5100_AIF3TX1_ENA_MASK                 0x0001  /* AIF3TX1_ENA */
+#define WM5100_AIF3TX1_ENA_SHIFT                     0  /* AIF3TX1_ENA */
+#define WM5100_AIF3TX1_ENA_WIDTH                     1  /* AIF3TX1_ENA */
+
+/*
+ * R1434 (0x59A) - Audio IF 3_27
+ */
+#define WM5100_AIF3RX2_ENA                      0x0002  /* AIF3RX2_ENA */
+#define WM5100_AIF3RX2_ENA_MASK                 0x0002  /* AIF3RX2_ENA */
+#define WM5100_AIF3RX2_ENA_SHIFT                     1  /* AIF3RX2_ENA */
+#define WM5100_AIF3RX2_ENA_WIDTH                     1  /* AIF3RX2_ENA */
+#define WM5100_AIF3RX1_ENA                      0x0001  /* AIF3RX1_ENA */
+#define WM5100_AIF3RX1_ENA_MASK                 0x0001  /* AIF3RX1_ENA */
+#define WM5100_AIF3RX1_ENA_SHIFT                     0  /* AIF3RX1_ENA */
+#define WM5100_AIF3RX1_ENA_WIDTH                     1  /* AIF3RX1_ENA */
+
+#define WM5100_MIXER_VOL_MASK                0x00FE  /* MIXER_VOL - [7:1] */
+#define WM5100_MIXER_VOL_SHIFT                    1  /* MIXER_VOL - [7:1] */
+#define WM5100_MIXER_VOL_WIDTH                    7  /* MIXER_VOL - [7:1] */
+
+/*
+ * R3072 (0xC00) - GPIO CTRL 1
+ */
+#define WM5100_GP1_DIR                          0x8000  /* GP1_DIR */
+#define WM5100_GP1_DIR_MASK                     0x8000  /* GP1_DIR */
+#define WM5100_GP1_DIR_SHIFT                        15  /* GP1_DIR */
+#define WM5100_GP1_DIR_WIDTH                         1  /* GP1_DIR */
+#define WM5100_GP1_PU                           0x4000  /* GP1_PU */
+#define WM5100_GP1_PU_MASK                      0x4000  /* GP1_PU */
+#define WM5100_GP1_PU_SHIFT                         14  /* GP1_PU */
+#define WM5100_GP1_PU_WIDTH                          1  /* GP1_PU */
+#define WM5100_GP1_PD                           0x2000  /* GP1_PD */
+#define WM5100_GP1_PD_MASK                      0x2000  /* GP1_PD */
+#define WM5100_GP1_PD_SHIFT                         13  /* GP1_PD */
+#define WM5100_GP1_PD_WIDTH                          1  /* GP1_PD */
+#define WM5100_GP1_POL                          0x0400  /* GP1_POL */
+#define WM5100_GP1_POL_MASK                     0x0400  /* GP1_POL */
+#define WM5100_GP1_POL_SHIFT                        10  /* GP1_POL */
+#define WM5100_GP1_POL_WIDTH                         1  /* GP1_POL */
+#define WM5100_GP1_OP_CFG                       0x0200  /* GP1_OP_CFG */
+#define WM5100_GP1_OP_CFG_MASK                  0x0200  /* GP1_OP_CFG */
+#define WM5100_GP1_OP_CFG_SHIFT                      9  /* GP1_OP_CFG */
+#define WM5100_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
+#define WM5100_GP1_DB                           0x0100  /* GP1_DB */
+#define WM5100_GP1_DB_MASK                      0x0100  /* GP1_DB */
+#define WM5100_GP1_DB_SHIFT                          8  /* GP1_DB */
+#define WM5100_GP1_DB_WIDTH                          1  /* GP1_DB */
+#define WM5100_GP1_LVL                          0x0040  /* GP1_LVL */
+#define WM5100_GP1_LVL_MASK                     0x0040  /* GP1_LVL */
+#define WM5100_GP1_LVL_SHIFT                         6  /* GP1_LVL */
+#define WM5100_GP1_LVL_WIDTH                         1  /* GP1_LVL */
+#define WM5100_GP1_FN_MASK                      0x003F  /* GP1_FN - [5:0] */
+#define WM5100_GP1_FN_SHIFT                          0  /* GP1_FN - [5:0] */
+#define WM5100_GP1_FN_WIDTH                          6  /* GP1_FN - [5:0] */
+
+/*
+ * R3073 (0xC01) - GPIO CTRL 2
+ */
+#define WM5100_GP2_DIR                          0x8000  /* GP2_DIR */
+#define WM5100_GP2_DIR_MASK                     0x8000  /* GP2_DIR */
+#define WM5100_GP2_DIR_SHIFT                        15  /* GP2_DIR */
+#define WM5100_GP2_DIR_WIDTH                         1  /* GP2_DIR */
+#define WM5100_GP2_PU                           0x4000  /* GP2_PU */
+#define WM5100_GP2_PU_MASK                      0x4000  /* GP2_PU */
+#define WM5100_GP2_PU_SHIFT                         14  /* GP2_PU */
+#define WM5100_GP2_PU_WIDTH                          1  /* GP2_PU */
+#define WM5100_GP2_PD                           0x2000  /* GP2_PD */
+#define WM5100_GP2_PD_MASK                      0x2000  /* GP2_PD */
+#define WM5100_GP2_PD_SHIFT                         13  /* GP2_PD */
+#define WM5100_GP2_PD_WIDTH                          1  /* GP2_PD */
+#define WM5100_GP2_POL                          0x0400  /* GP2_POL */
+#define WM5100_GP2_POL_MASK                     0x0400  /* GP2_POL */
+#define WM5100_GP2_POL_SHIFT                        10  /* GP2_POL */
+#define WM5100_GP2_POL_WIDTH                         1  /* GP2_POL */
+#define WM5100_GP2_OP_CFG                       0x0200  /* GP2_OP_CFG */
+#define WM5100_GP2_OP_CFG_MASK                  0x0200  /* GP2_OP_CFG */
+#define WM5100_GP2_OP_CFG_SHIFT                      9  /* GP2_OP_CFG */
+#define WM5100_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
+#define WM5100_GP2_DB                           0x0100  /* GP2_DB */
+#define WM5100_GP2_DB_MASK                      0x0100  /* GP2_DB */
+#define WM5100_GP2_DB_SHIFT                          8  /* GP2_DB */
+#define WM5100_GP2_DB_WIDTH                          1  /* GP2_DB */
+#define WM5100_GP2_LVL                          0x0040  /* GP2_LVL */
+#define WM5100_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
+#define WM5100_GP2_LVL_SHIFT                         6  /* GP2_LVL */
+#define WM5100_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM5100_GP2_FN_MASK                      0x003F  /* GP2_FN - [5:0] */
+#define WM5100_GP2_FN_SHIFT                          0  /* GP2_FN - [5:0] */
+#define WM5100_GP2_FN_WIDTH                          6  /* GP2_FN - [5:0] */
+
+/*
+ * R3074 (0xC02) - GPIO CTRL 3
+ */
+#define WM5100_GP3_DIR                          0x8000  /* GP3_DIR */
+#define WM5100_GP3_DIR_MASK                     0x8000  /* GP3_DIR */
+#define WM5100_GP3_DIR_SHIFT                        15  /* GP3_DIR */
+#define WM5100_GP3_DIR_WIDTH                         1  /* GP3_DIR */
+#define WM5100_GP3_PU                           0x4000  /* GP3_PU */
+#define WM5100_GP3_PU_MASK                      0x4000  /* GP3_PU */
+#define WM5100_GP3_PU_SHIFT                         14  /* GP3_PU */
+#define WM5100_GP3_PU_WIDTH                          1  /* GP3_PU */
+#define WM5100_GP3_PD                           0x2000  /* GP3_PD */
+#define WM5100_GP3_PD_MASK                      0x2000  /* GP3_PD */
+#define WM5100_GP3_PD_SHIFT                         13  /* GP3_PD */
+#define WM5100_GP3_PD_WIDTH                          1  /* GP3_PD */
+#define WM5100_GP3_POL                          0x0400  /* GP3_POL */
+#define WM5100_GP3_POL_MASK                     0x0400  /* GP3_POL */
+#define WM5100_GP3_POL_SHIFT                        10  /* GP3_POL */
+#define WM5100_GP3_POL_WIDTH                         1  /* GP3_POL */
+#define WM5100_GP3_OP_CFG                       0x0200  /* GP3_OP_CFG */
+#define WM5100_GP3_OP_CFG_MASK                  0x0200  /* GP3_OP_CFG */
+#define WM5100_GP3_OP_CFG_SHIFT                      9  /* GP3_OP_CFG */
+#define WM5100_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
+#define WM5100_GP3_DB                           0x0100  /* GP3_DB */
+#define WM5100_GP3_DB_MASK                      0x0100  /* GP3_DB */
+#define WM5100_GP3_DB_SHIFT                          8  /* GP3_DB */
+#define WM5100_GP3_DB_WIDTH                          1  /* GP3_DB */
+#define WM5100_GP3_LVL                          0x0040  /* GP3_LVL */
+#define WM5100_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
+#define WM5100_GP3_LVL_SHIFT                         6  /* GP3_LVL */
+#define WM5100_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM5100_GP3_FN_MASK                      0x003F  /* GP3_FN - [5:0] */
+#define WM5100_GP3_FN_SHIFT                          0  /* GP3_FN - [5:0] */
+#define WM5100_GP3_FN_WIDTH                          6  /* GP3_FN - [5:0] */
+
+/*
+ * R3075 (0xC03) - GPIO CTRL 4
+ */
+#define WM5100_GP4_DIR                          0x8000  /* GP4_DIR */
+#define WM5100_GP4_DIR_MASK                     0x8000  /* GP4_DIR */
+#define WM5100_GP4_DIR_SHIFT                        15  /* GP4_DIR */
+#define WM5100_GP4_DIR_WIDTH                         1  /* GP4_DIR */
+#define WM5100_GP4_PU                           0x4000  /* GP4_PU */
+#define WM5100_GP4_PU_MASK                      0x4000  /* GP4_PU */
+#define WM5100_GP4_PU_SHIFT                         14  /* GP4_PU */
+#define WM5100_GP4_PU_WIDTH                          1  /* GP4_PU */
+#define WM5100_GP4_PD                           0x2000  /* GP4_PD */
+#define WM5100_GP4_PD_MASK                      0x2000  /* GP4_PD */
+#define WM5100_GP4_PD_SHIFT                         13  /* GP4_PD */
+#define WM5100_GP4_PD_WIDTH                          1  /* GP4_PD */
+#define WM5100_GP4_POL                          0x0400  /* GP4_POL */
+#define WM5100_GP4_POL_MASK                     0x0400  /* GP4_POL */
+#define WM5100_GP4_POL_SHIFT                        10  /* GP4_POL */
+#define WM5100_GP4_POL_WIDTH                         1  /* GP4_POL */
+#define WM5100_GP4_OP_CFG                       0x0200  /* GP4_OP_CFG */
+#define WM5100_GP4_OP_CFG_MASK                  0x0200  /* GP4_OP_CFG */
+#define WM5100_GP4_OP_CFG_SHIFT                      9  /* GP4_OP_CFG */
+#define WM5100_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
+#define WM5100_GP4_DB                           0x0100  /* GP4_DB */
+#define WM5100_GP4_DB_MASK                      0x0100  /* GP4_DB */
+#define WM5100_GP4_DB_SHIFT                          8  /* GP4_DB */
+#define WM5100_GP4_DB_WIDTH                          1  /* GP4_DB */
+#define WM5100_GP4_LVL                          0x0040  /* GP4_LVL */
+#define WM5100_GP4_LVL_MASK                     0x0040  /* GP4_LVL */
+#define WM5100_GP4_LVL_SHIFT                         6  /* GP4_LVL */
+#define WM5100_GP4_LVL_WIDTH                         1  /* GP4_LVL */
+#define WM5100_GP4_FN_MASK                      0x003F  /* GP4_FN - [5:0] */
+#define WM5100_GP4_FN_SHIFT                          0  /* GP4_FN - [5:0] */
+#define WM5100_GP4_FN_WIDTH                          6  /* GP4_FN - [5:0] */
+
+/*
+ * R3076 (0xC04) - GPIO CTRL 5
+ */
+#define WM5100_GP5_DIR                          0x8000  /* GP5_DIR */
+#define WM5100_GP5_DIR_MASK                     0x8000  /* GP5_DIR */
+#define WM5100_GP5_DIR_SHIFT                        15  /* GP5_DIR */
+#define WM5100_GP5_DIR_WIDTH                         1  /* GP5_DIR */
+#define WM5100_GP5_PU                           0x4000  /* GP5_PU */
+#define WM5100_GP5_PU_MASK                      0x4000  /* GP5_PU */
+#define WM5100_GP5_PU_SHIFT                         14  /* GP5_PU */
+#define WM5100_GP5_PU_WIDTH                          1  /* GP5_PU */
+#define WM5100_GP5_PD                           0x2000  /* GP5_PD */
+#define WM5100_GP5_PD_MASK                      0x2000  /* GP5_PD */
+#define WM5100_GP5_PD_SHIFT                         13  /* GP5_PD */
+#define WM5100_GP5_PD_WIDTH                          1  /* GP5_PD */
+#define WM5100_GP5_POL                          0x0400  /* GP5_POL */
+#define WM5100_GP5_POL_MASK                     0x0400  /* GP5_POL */
+#define WM5100_GP5_POL_SHIFT                        10  /* GP5_POL */
+#define WM5100_GP5_POL_WIDTH                         1  /* GP5_POL */
+#define WM5100_GP5_OP_CFG                       0x0200  /* GP5_OP_CFG */
+#define WM5100_GP5_OP_CFG_MASK                  0x0200  /* GP5_OP_CFG */
+#define WM5100_GP5_OP_CFG_SHIFT                      9  /* GP5_OP_CFG */
+#define WM5100_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
+#define WM5100_GP5_DB                           0x0100  /* GP5_DB */
+#define WM5100_GP5_DB_MASK                      0x0100  /* GP5_DB */
+#define WM5100_GP5_DB_SHIFT                          8  /* GP5_DB */
+#define WM5100_GP5_DB_WIDTH                          1  /* GP5_DB */
+#define WM5100_GP5_LVL                          0x0040  /* GP5_LVL */
+#define WM5100_GP5_LVL_MASK                     0x0040  /* GP5_LVL */
+#define WM5100_GP5_LVL_SHIFT                         6  /* GP5_LVL */
+#define WM5100_GP5_LVL_WIDTH                         1  /* GP5_LVL */
+#define WM5100_GP5_FN_MASK                      0x003F  /* GP5_FN - [5:0] */
+#define WM5100_GP5_FN_SHIFT                          0  /* GP5_FN - [5:0] */
+#define WM5100_GP5_FN_WIDTH                          6  /* GP5_FN - [5:0] */
+
+/*
+ * R3077 (0xC05) - GPIO CTRL 6
+ */
+#define WM5100_GP6_DIR                          0x8000  /* GP6_DIR */
+#define WM5100_GP6_DIR_MASK                     0x8000  /* GP6_DIR */
+#define WM5100_GP6_DIR_SHIFT                        15  /* GP6_DIR */
+#define WM5100_GP6_DIR_WIDTH                         1  /* GP6_DIR */
+#define WM5100_GP6_PU                           0x4000  /* GP6_PU */
+#define WM5100_GP6_PU_MASK                      0x4000  /* GP6_PU */
+#define WM5100_GP6_PU_SHIFT                         14  /* GP6_PU */
+#define WM5100_GP6_PU_WIDTH                          1  /* GP6_PU */
+#define WM5100_GP6_PD                           0x2000  /* GP6_PD */
+#define WM5100_GP6_PD_MASK                      0x2000  /* GP6_PD */
+#define WM5100_GP6_PD_SHIFT                         13  /* GP6_PD */
+#define WM5100_GP6_PD_WIDTH                          1  /* GP6_PD */
+#define WM5100_GP6_POL                          0x0400  /* GP6_POL */
+#define WM5100_GP6_POL_MASK                     0x0400  /* GP6_POL */
+#define WM5100_GP6_POL_SHIFT                        10  /* GP6_POL */
+#define WM5100_GP6_POL_WIDTH                         1  /* GP6_POL */
+#define WM5100_GP6_OP_CFG                       0x0200  /* GP6_OP_CFG */
+#define WM5100_GP6_OP_CFG_MASK                  0x0200  /* GP6_OP_CFG */
+#define WM5100_GP6_OP_CFG_SHIFT                      9  /* GP6_OP_CFG */
+#define WM5100_GP6_OP_CFG_WIDTH                      1  /* GP6_OP_CFG */
+#define WM5100_GP6_DB                           0x0100  /* GP6_DB */
+#define WM5100_GP6_DB_MASK                      0x0100  /* GP6_DB */
+#define WM5100_GP6_DB_SHIFT                          8  /* GP6_DB */
+#define WM5100_GP6_DB_WIDTH                          1  /* GP6_DB */
+#define WM5100_GP6_LVL                          0x0040  /* GP6_LVL */
+#define WM5100_GP6_LVL_MASK                     0x0040  /* GP6_LVL */
+#define WM5100_GP6_LVL_SHIFT                         6  /* GP6_LVL */
+#define WM5100_GP6_LVL_WIDTH                         1  /* GP6_LVL */
+#define WM5100_GP6_FN_MASK                      0x003F  /* GP6_FN - [5:0] */
+#define WM5100_GP6_FN_SHIFT                          0  /* GP6_FN - [5:0] */
+#define WM5100_GP6_FN_WIDTH                          6  /* GP6_FN - [5:0] */
+
+/*
+ * R3107 (0xC23) - Misc Pad Ctrl 1
+ */
+#define WM5100_LDO1ENA_PD                       0x8000  /* LDO1ENA_PD */
+#define WM5100_LDO1ENA_PD_MASK                  0x8000  /* LDO1ENA_PD */
+#define WM5100_LDO1ENA_PD_SHIFT                     15  /* LDO1ENA_PD */
+#define WM5100_LDO1ENA_PD_WIDTH                      1  /* LDO1ENA_PD */
+#define WM5100_MCLK2_PD                         0x2000  /* MCLK2_PD */
+#define WM5100_MCLK2_PD_MASK                    0x2000  /* MCLK2_PD */
+#define WM5100_MCLK2_PD_SHIFT                       13  /* MCLK2_PD */
+#define WM5100_MCLK2_PD_WIDTH                        1  /* MCLK2_PD */
+#define WM5100_MCLK1_PD                         0x1000  /* MCLK1_PD */
+#define WM5100_MCLK1_PD_MASK                    0x1000  /* MCLK1_PD */
+#define WM5100_MCLK1_PD_SHIFT                       12  /* MCLK1_PD */
+#define WM5100_MCLK1_PD_WIDTH                        1  /* MCLK1_PD */
+#define WM5100_RESET_PU                         0x0002  /* RESET_PU */
+#define WM5100_RESET_PU_MASK                    0x0002  /* RESET_PU */
+#define WM5100_RESET_PU_SHIFT                        1  /* RESET_PU */
+#define WM5100_RESET_PU_WIDTH                        1  /* RESET_PU */
+#define WM5100_ADDR_PD                          0x0001  /* ADDR_PD */
+#define WM5100_ADDR_PD_MASK                     0x0001  /* ADDR_PD */
+#define WM5100_ADDR_PD_SHIFT                         0  /* ADDR_PD */
+#define WM5100_ADDR_PD_WIDTH                         1  /* ADDR_PD */
+
+/*
+ * R3108 (0xC24) - Misc Pad Ctrl 2
+ */
+#define WM5100_DMICDAT4_PD                      0x0008  /* DMICDAT4_PD */
+#define WM5100_DMICDAT4_PD_MASK                 0x0008  /* DMICDAT4_PD */
+#define WM5100_DMICDAT4_PD_SHIFT                     3  /* DMICDAT4_PD */
+#define WM5100_DMICDAT4_PD_WIDTH                     1  /* DMICDAT4_PD */
+#define WM5100_DMICDAT3_PD                      0x0004  /* DMICDAT3_PD */
+#define WM5100_DMICDAT3_PD_MASK                 0x0004  /* DMICDAT3_PD */
+#define WM5100_DMICDAT3_PD_SHIFT                     2  /* DMICDAT3_PD */
+#define WM5100_DMICDAT3_PD_WIDTH                     1  /* DMICDAT3_PD */
+#define WM5100_DMICDAT2_PD                      0x0002  /* DMICDAT2_PD */
+#define WM5100_DMICDAT2_PD_MASK                 0x0002  /* DMICDAT2_PD */
+#define WM5100_DMICDAT2_PD_SHIFT                     1  /* DMICDAT2_PD */
+#define WM5100_DMICDAT2_PD_WIDTH                     1  /* DMICDAT2_PD */
+#define WM5100_DMICDAT1_PD                      0x0001  /* DMICDAT1_PD */
+#define WM5100_DMICDAT1_PD_MASK                 0x0001  /* DMICDAT1_PD */
+#define WM5100_DMICDAT1_PD_SHIFT                     0  /* DMICDAT1_PD */
+#define WM5100_DMICDAT1_PD_WIDTH                     1  /* DMICDAT1_PD */
+
+/*
+ * R3109 (0xC25) - Misc Pad Ctrl 3
+ */
+#define WM5100_AIF1RXLRCLK_PU                   0x0020  /* AIF1RXLRCLK_PU */
+#define WM5100_AIF1RXLRCLK_PU_MASK              0x0020  /* AIF1RXLRCLK_PU */
+#define WM5100_AIF1RXLRCLK_PU_SHIFT                  5  /* AIF1RXLRCLK_PU */
+#define WM5100_AIF1RXLRCLK_PU_WIDTH                  1  /* AIF1RXLRCLK_PU */
+#define WM5100_AIF1RXLRCLK_PD                   0x0010  /* AIF1RXLRCLK_PD */
+#define WM5100_AIF1RXLRCLK_PD_MASK              0x0010  /* AIF1RXLRCLK_PD */
+#define WM5100_AIF1RXLRCLK_PD_SHIFT                  4  /* AIF1RXLRCLK_PD */
+#define WM5100_AIF1RXLRCLK_PD_WIDTH                  1  /* AIF1RXLRCLK_PD */
+#define WM5100_AIF1BCLK_PU                      0x0008  /* AIF1BCLK_PU */
+#define WM5100_AIF1BCLK_PU_MASK                 0x0008  /* AIF1BCLK_PU */
+#define WM5100_AIF1BCLK_PU_SHIFT                     3  /* AIF1BCLK_PU */
+#define WM5100_AIF1BCLK_PU_WIDTH                     1  /* AIF1BCLK_PU */
+#define WM5100_AIF1BCLK_PD                      0x0004  /* AIF1BCLK_PD */
+#define WM5100_AIF1BCLK_PD_MASK                 0x0004  /* AIF1BCLK_PD */
+#define WM5100_AIF1BCLK_PD_SHIFT                     2  /* AIF1BCLK_PD */
+#define WM5100_AIF1BCLK_PD_WIDTH                     1  /* AIF1BCLK_PD */
+#define WM5100_AIF1RXDAT_PU                     0x0002  /* AIF1RXDAT_PU */
+#define WM5100_AIF1RXDAT_PU_MASK                0x0002  /* AIF1RXDAT_PU */
+#define WM5100_AIF1RXDAT_PU_SHIFT                    1  /* AIF1RXDAT_PU */
+#define WM5100_AIF1RXDAT_PU_WIDTH                    1  /* AIF1RXDAT_PU */
+#define WM5100_AIF1RXDAT_PD                     0x0001  /* AIF1RXDAT_PD */
+#define WM5100_AIF1RXDAT_PD_MASK                0x0001  /* AIF1RXDAT_PD */
+#define WM5100_AIF1RXDAT_PD_SHIFT                    0  /* AIF1RXDAT_PD */
+#define WM5100_AIF1RXDAT_PD_WIDTH                    1  /* AIF1RXDAT_PD */
+
+/*
+ * R3110 (0xC26) - Misc Pad Ctrl 4
+ */
+#define WM5100_AIF2RXLRCLK_PU                   0x0020  /* AIF2RXLRCLK_PU */
+#define WM5100_AIF2RXLRCLK_PU_MASK              0x0020  /* AIF2RXLRCLK_PU */
+#define WM5100_AIF2RXLRCLK_PU_SHIFT                  5  /* AIF2RXLRCLK_PU */
+#define WM5100_AIF2RXLRCLK_PU_WIDTH                  1  /* AIF2RXLRCLK_PU */
+#define WM5100_AIF2RXLRCLK_PD                   0x0010  /* AIF2RXLRCLK_PD */
+#define WM5100_AIF2RXLRCLK_PD_MASK              0x0010  /* AIF2RXLRCLK_PD */
+#define WM5100_AIF2RXLRCLK_PD_SHIFT                  4  /* AIF2RXLRCLK_PD */
+#define WM5100_AIF2RXLRCLK_PD_WIDTH                  1  /* AIF2RXLRCLK_PD */
+#define WM5100_AIF2BCLK_PU                      0x0008  /* AIF2BCLK_PU */
+#define WM5100_AIF2BCLK_PU_MASK                 0x0008  /* AIF2BCLK_PU */
+#define WM5100_AIF2BCLK_PU_SHIFT                     3  /* AIF2BCLK_PU */
+#define WM5100_AIF2BCLK_PU_WIDTH                     1  /* AIF2BCLK_PU */
+#define WM5100_AIF2BCLK_PD                      0x0004  /* AIF2BCLK_PD */
+#define WM5100_AIF2BCLK_PD_MASK                 0x0004  /* AIF2BCLK_PD */
+#define WM5100_AIF2BCLK_PD_SHIFT                     2  /* AIF2BCLK_PD */
+#define WM5100_AIF2BCLK_PD_WIDTH                     1  /* AIF2BCLK_PD */
+#define WM5100_AIF2RXDAT_PU                     0x0002  /* AIF2RXDAT_PU */
+#define WM5100_AIF2RXDAT_PU_MASK                0x0002  /* AIF2RXDAT_PU */
+#define WM5100_AIF2RXDAT_PU_SHIFT                    1  /* AIF2RXDAT_PU */
+#define WM5100_AIF2RXDAT_PU_WIDTH                    1  /* AIF2RXDAT_PU */
+#define WM5100_AIF2RXDAT_PD                     0x0001  /* AIF2RXDAT_PD */
+#define WM5100_AIF2RXDAT_PD_MASK                0x0001  /* AIF2RXDAT_PD */
+#define WM5100_AIF2RXDAT_PD_SHIFT                    0  /* AIF2RXDAT_PD */
+#define WM5100_AIF2RXDAT_PD_WIDTH                    1  /* AIF2RXDAT_PD */
+
+/*
+ * R3111 (0xC27) - Misc Pad Ctrl 5
+ */
+#define WM5100_AIF3RXLRCLK_PU                   0x0020  /* AIF3RXLRCLK_PU */
+#define WM5100_AIF3RXLRCLK_PU_MASK              0x0020  /* AIF3RXLRCLK_PU */
+#define WM5100_AIF3RXLRCLK_PU_SHIFT                  5  /* AIF3RXLRCLK_PU */
+#define WM5100_AIF3RXLRCLK_PU_WIDTH                  1  /* AIF3RXLRCLK_PU */
+#define WM5100_AIF3RXLRCLK_PD                   0x0010  /* AIF3RXLRCLK_PD */
+#define WM5100_AIF3RXLRCLK_PD_MASK              0x0010  /* AIF3RXLRCLK_PD */
+#define WM5100_AIF3RXLRCLK_PD_SHIFT                  4  /* AIF3RXLRCLK_PD */
+#define WM5100_AIF3RXLRCLK_PD_WIDTH                  1  /* AIF3RXLRCLK_PD */
+#define WM5100_AIF3BCLK_PU                      0x0008  /* AIF3BCLK_PU */
+#define WM5100_AIF3BCLK_PU_MASK                 0x0008  /* AIF3BCLK_PU */
+#define WM5100_AIF3BCLK_PU_SHIFT                     3  /* AIF3BCLK_PU */
+#define WM5100_AIF3BCLK_PU_WIDTH                     1  /* AIF3BCLK_PU */
+#define WM5100_AIF3BCLK_PD                      0x0004  /* AIF3BCLK_PD */
+#define WM5100_AIF3BCLK_PD_MASK                 0x0004  /* AIF3BCLK_PD */
+#define WM5100_AIF3BCLK_PD_SHIFT                     2  /* AIF3BCLK_PD */
+#define WM5100_AIF3BCLK_PD_WIDTH                     1  /* AIF3BCLK_PD */
+#define WM5100_AIF3RXDAT_PU                     0x0002  /* AIF3RXDAT_PU */
+#define WM5100_AIF3RXDAT_PU_MASK                0x0002  /* AIF3RXDAT_PU */
+#define WM5100_AIF3RXDAT_PU_SHIFT                    1  /* AIF3RXDAT_PU */
+#define WM5100_AIF3RXDAT_PU_WIDTH                    1  /* AIF3RXDAT_PU */
+#define WM5100_AIF3RXDAT_PD                     0x0001  /* AIF3RXDAT_PD */
+#define WM5100_AIF3RXDAT_PD_MASK                0x0001  /* AIF3RXDAT_PD */
+#define WM5100_AIF3RXDAT_PD_SHIFT                    0  /* AIF3RXDAT_PD */
+#define WM5100_AIF3RXDAT_PD_WIDTH                    1  /* AIF3RXDAT_PD */
+
+/*
+ * R3112 (0xC28) - Misc GPIO 1
+ */
+#define WM5100_OPCLK_SEL_MASK                   0x0003  /* OPCLK_SEL - [1:0] */
+#define WM5100_OPCLK_SEL_SHIFT                       0  /* OPCLK_SEL - [1:0] */
+#define WM5100_OPCLK_SEL_WIDTH                       2  /* OPCLK_SEL - [1:0] */
+
+/*
+ * R3328 (0xD00) - Interrupt Status 1
+ */
+#define WM5100_GP6_EINT                         0x0020  /* GP6_EINT */
+#define WM5100_GP6_EINT_MASK                    0x0020  /* GP6_EINT */
+#define WM5100_GP6_EINT_SHIFT                        5  /* GP6_EINT */
+#define WM5100_GP6_EINT_WIDTH                        1  /* GP6_EINT */
+#define WM5100_GP5_EINT                         0x0010  /* GP5_EINT */
+#define WM5100_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
+#define WM5100_GP5_EINT_SHIFT                        4  /* GP5_EINT */
+#define WM5100_GP5_EINT_WIDTH                        1  /* GP5_EINT */
+#define WM5100_GP4_EINT                         0x0008  /* GP4_EINT */
+#define WM5100_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
+#define WM5100_GP4_EINT_SHIFT                        3  /* GP4_EINT */
+#define WM5100_GP4_EINT_WIDTH                        1  /* GP4_EINT */
+#define WM5100_GP3_EINT                         0x0004  /* GP3_EINT */
+#define WM5100_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
+#define WM5100_GP3_EINT_SHIFT                        2  /* GP3_EINT */
+#define WM5100_GP3_EINT_WIDTH                        1  /* GP3_EINT */
+#define WM5100_GP2_EINT                         0x0002  /* GP2_EINT */
+#define WM5100_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
+#define WM5100_GP2_EINT_SHIFT                        1  /* GP2_EINT */
+#define WM5100_GP2_EINT_WIDTH                        1  /* GP2_EINT */
+#define WM5100_GP1_EINT                         0x0001  /* GP1_EINT */
+#define WM5100_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
+#define WM5100_GP1_EINT_SHIFT                        0  /* GP1_EINT */
+#define WM5100_GP1_EINT_WIDTH                        1  /* GP1_EINT */
+
+/*
+ * R3329 (0xD01) - Interrupt Status 2
+ */
+#define WM5100_DSP_IRQ6_EINT                    0x0020  /* DSP_IRQ6_EINT */
+#define WM5100_DSP_IRQ6_EINT_MASK               0x0020  /* DSP_IRQ6_EINT */
+#define WM5100_DSP_IRQ6_EINT_SHIFT                   5  /* DSP_IRQ6_EINT */
+#define WM5100_DSP_IRQ6_EINT_WIDTH                   1  /* DSP_IRQ6_EINT */
+#define WM5100_DSP_IRQ5_EINT                    0x0010  /* DSP_IRQ5_EINT */
+#define WM5100_DSP_IRQ5_EINT_MASK               0x0010  /* DSP_IRQ5_EINT */
+#define WM5100_DSP_IRQ5_EINT_SHIFT                   4  /* DSP_IRQ5_EINT */
+#define WM5100_DSP_IRQ5_EINT_WIDTH                   1  /* DSP_IRQ5_EINT */
+#define WM5100_DSP_IRQ4_EINT                    0x0008  /* DSP_IRQ4_EINT */
+#define WM5100_DSP_IRQ4_EINT_MASK               0x0008  /* DSP_IRQ4_EINT */
+#define WM5100_DSP_IRQ4_EINT_SHIFT                   3  /* DSP_IRQ4_EINT */
+#define WM5100_DSP_IRQ4_EINT_WIDTH                   1  /* DSP_IRQ4_EINT */
+#define WM5100_DSP_IRQ3_EINT                    0x0004  /* DSP_IRQ3_EINT */
+#define WM5100_DSP_IRQ3_EINT_MASK               0x0004  /* DSP_IRQ3_EINT */
+#define WM5100_DSP_IRQ3_EINT_SHIFT                   2  /* DSP_IRQ3_EINT */
+#define WM5100_DSP_IRQ3_EINT_WIDTH                   1  /* DSP_IRQ3_EINT */
+#define WM5100_DSP_IRQ2_EINT                    0x0002  /* DSP_IRQ2_EINT */
+#define WM5100_DSP_IRQ2_EINT_MASK               0x0002  /* DSP_IRQ2_EINT */
+#define WM5100_DSP_IRQ2_EINT_SHIFT                   1  /* DSP_IRQ2_EINT */
+#define WM5100_DSP_IRQ2_EINT_WIDTH                   1  /* DSP_IRQ2_EINT */
+#define WM5100_DSP_IRQ1_EINT                    0x0001  /* DSP_IRQ1_EINT */
+#define WM5100_DSP_IRQ1_EINT_MASK               0x0001  /* DSP_IRQ1_EINT */
+#define WM5100_DSP_IRQ1_EINT_SHIFT                   0  /* DSP_IRQ1_EINT */
+#define WM5100_DSP_IRQ1_EINT_WIDTH                   1  /* DSP_IRQ1_EINT */
+
+/*
+ * R3330 (0xD02) - Interrupt Status 3
+ */
+#define WM5100_SPK_SHUTDOWN_WARN_EINT           0x8000  /* SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_SPK_SHUTDOWN_WARN_EINT_MASK      0x8000  /* SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_SPK_SHUTDOWN_WARN_EINT_SHIFT         15  /* SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_SPK_SHUTDOWN_WARN_EINT_WIDTH          1  /* SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_SPK_SHUTDOWN_EINT                0x4000  /* SPK_SHUTDOWN_EINT */
+#define WM5100_SPK_SHUTDOWN_EINT_MASK           0x4000  /* SPK_SHUTDOWN_EINT */
+#define WM5100_SPK_SHUTDOWN_EINT_SHIFT              14  /* SPK_SHUTDOWN_EINT */
+#define WM5100_SPK_SHUTDOWN_EINT_WIDTH               1  /* SPK_SHUTDOWN_EINT */
+#define WM5100_HPDET_EINT                       0x2000  /* HPDET_EINT */
+#define WM5100_HPDET_EINT_MASK                  0x2000  /* HPDET_EINT */
+#define WM5100_HPDET_EINT_SHIFT                     13  /* HPDET_EINT */
+#define WM5100_HPDET_EINT_WIDTH                      1  /* HPDET_EINT */
+#define WM5100_ACCDET_EINT                      0x1000  /* ACCDET_EINT */
+#define WM5100_ACCDET_EINT_MASK                 0x1000  /* ACCDET_EINT */
+#define WM5100_ACCDET_EINT_SHIFT                    12  /* ACCDET_EINT */
+#define WM5100_ACCDET_EINT_WIDTH                     1  /* ACCDET_EINT */
+#define WM5100_DRC_SIG_DET_EINT                 0x0200  /* DRC_SIG_DET_EINT */
+#define WM5100_DRC_SIG_DET_EINT_MASK            0x0200  /* DRC_SIG_DET_EINT */
+#define WM5100_DRC_SIG_DET_EINT_SHIFT                9  /* DRC_SIG_DET_EINT */
+#define WM5100_DRC_SIG_DET_EINT_WIDTH                1  /* DRC_SIG_DET_EINT */
+#define WM5100_ASRC2_LOCK_EINT                  0x0100  /* ASRC2_LOCK_EINT */
+#define WM5100_ASRC2_LOCK_EINT_MASK             0x0100  /* ASRC2_LOCK_EINT */
+#define WM5100_ASRC2_LOCK_EINT_SHIFT                 8  /* ASRC2_LOCK_EINT */
+#define WM5100_ASRC2_LOCK_EINT_WIDTH                 1  /* ASRC2_LOCK_EINT */
+#define WM5100_ASRC1_LOCK_EINT                  0x0080  /* ASRC1_LOCK_EINT */
+#define WM5100_ASRC1_LOCK_EINT_MASK             0x0080  /* ASRC1_LOCK_EINT */
+#define WM5100_ASRC1_LOCK_EINT_SHIFT                 7  /* ASRC1_LOCK_EINT */
+#define WM5100_ASRC1_LOCK_EINT_WIDTH                 1  /* ASRC1_LOCK_EINT */
+#define WM5100_FLL2_LOCK_EINT                   0x0008  /* FLL2_LOCK_EINT */
+#define WM5100_FLL2_LOCK_EINT_MASK              0x0008  /* FLL2_LOCK_EINT */
+#define WM5100_FLL2_LOCK_EINT_SHIFT                  3  /* FLL2_LOCK_EINT */
+#define WM5100_FLL2_LOCK_EINT_WIDTH                  1  /* FLL2_LOCK_EINT */
+#define WM5100_FLL1_LOCK_EINT                   0x0004  /* FLL1_LOCK_EINT */
+#define WM5100_FLL1_LOCK_EINT_MASK              0x0004  /* FLL1_LOCK_EINT */
+#define WM5100_FLL1_LOCK_EINT_SHIFT                  2  /* FLL1_LOCK_EINT */
+#define WM5100_FLL1_LOCK_EINT_WIDTH                  1  /* FLL1_LOCK_EINT */
+#define WM5100_CLKGEN_ERR_EINT                  0x0002  /* CLKGEN_ERR_EINT */
+#define WM5100_CLKGEN_ERR_EINT_MASK             0x0002  /* CLKGEN_ERR_EINT */
+#define WM5100_CLKGEN_ERR_EINT_SHIFT                 1  /* CLKGEN_ERR_EINT */
+#define WM5100_CLKGEN_ERR_EINT_WIDTH                 1  /* CLKGEN_ERR_EINT */
+#define WM5100_CLKGEN_ERR_ASYNC_EINT            0x0001  /* CLKGEN_ERR_ASYNC_EINT */
+#define WM5100_CLKGEN_ERR_ASYNC_EINT_MASK       0x0001  /* CLKGEN_ERR_ASYNC_EINT */
+#define WM5100_CLKGEN_ERR_ASYNC_EINT_SHIFT           0  /* CLKGEN_ERR_ASYNC_EINT */
+#define WM5100_CLKGEN_ERR_ASYNC_EINT_WIDTH           1  /* CLKGEN_ERR_ASYNC_EINT */
+
+/*
+ * R3331 (0xD03) - Interrupt Status 4
+ */
+#define WM5100_AIF3_ERR_EINT                    0x2000  /* AIF3_ERR_EINT */
+#define WM5100_AIF3_ERR_EINT_MASK               0x2000  /* AIF3_ERR_EINT */
+#define WM5100_AIF3_ERR_EINT_SHIFT                  13  /* AIF3_ERR_EINT */
+#define WM5100_AIF3_ERR_EINT_WIDTH                   1  /* AIF3_ERR_EINT */
+#define WM5100_AIF2_ERR_EINT                    0x1000  /* AIF2_ERR_EINT */
+#define WM5100_AIF2_ERR_EINT_MASK               0x1000  /* AIF2_ERR_EINT */
+#define WM5100_AIF2_ERR_EINT_SHIFT                  12  /* AIF2_ERR_EINT */
+#define WM5100_AIF2_ERR_EINT_WIDTH                   1  /* AIF2_ERR_EINT */
+#define WM5100_AIF1_ERR_EINT                    0x0800  /* AIF1_ERR_EINT */
+#define WM5100_AIF1_ERR_EINT_MASK               0x0800  /* AIF1_ERR_EINT */
+#define WM5100_AIF1_ERR_EINT_SHIFT                  11  /* AIF1_ERR_EINT */
+#define WM5100_AIF1_ERR_EINT_WIDTH                   1  /* AIF1_ERR_EINT */
+#define WM5100_CTRLIF_ERR_EINT                  0x0400  /* CTRLIF_ERR_EINT */
+#define WM5100_CTRLIF_ERR_EINT_MASK             0x0400  /* CTRLIF_ERR_EINT */
+#define WM5100_CTRLIF_ERR_EINT_SHIFT                10  /* CTRLIF_ERR_EINT */
+#define WM5100_CTRLIF_ERR_EINT_WIDTH                 1  /* CTRLIF_ERR_EINT */
+#define WM5100_ISRC2_UNDERCLOCKED_EINT          0x0200  /* ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_ISRC2_UNDERCLOCKED_EINT_MASK     0x0200  /* ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_ISRC2_UNDERCLOCKED_EINT_SHIFT         9  /* ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_ISRC2_UNDERCLOCKED_EINT_WIDTH         1  /* ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_ISRC1_UNDERCLOCKED_EINT          0x0100  /* ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_ISRC1_UNDERCLOCKED_EINT_MASK     0x0100  /* ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_ISRC1_UNDERCLOCKED_EINT_SHIFT         8  /* ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_ISRC1_UNDERCLOCKED_EINT_WIDTH         1  /* ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_FX_UNDERCLOCKED_EINT             0x0080  /* FX_UNDERCLOCKED_EINT */
+#define WM5100_FX_UNDERCLOCKED_EINT_MASK        0x0080  /* FX_UNDERCLOCKED_EINT */
+#define WM5100_FX_UNDERCLOCKED_EINT_SHIFT            7  /* FX_UNDERCLOCKED_EINT */
+#define WM5100_FX_UNDERCLOCKED_EINT_WIDTH            1  /* FX_UNDERCLOCKED_EINT */
+#define WM5100_AIF3_UNDERCLOCKED_EINT           0x0040  /* AIF3_UNDERCLOCKED_EINT */
+#define WM5100_AIF3_UNDERCLOCKED_EINT_MASK      0x0040  /* AIF3_UNDERCLOCKED_EINT */
+#define WM5100_AIF3_UNDERCLOCKED_EINT_SHIFT          6  /* AIF3_UNDERCLOCKED_EINT */
+#define WM5100_AIF3_UNDERCLOCKED_EINT_WIDTH          1  /* AIF3_UNDERCLOCKED_EINT */
+#define WM5100_AIF2_UNDERCLOCKED_EINT           0x0020  /* AIF2_UNDERCLOCKED_EINT */
+#define WM5100_AIF2_UNDERCLOCKED_EINT_MASK      0x0020  /* AIF2_UNDERCLOCKED_EINT */
+#define WM5100_AIF2_UNDERCLOCKED_EINT_SHIFT          5  /* AIF2_UNDERCLOCKED_EINT */
+#define WM5100_AIF2_UNDERCLOCKED_EINT_WIDTH          1  /* AIF2_UNDERCLOCKED_EINT */
+#define WM5100_AIF1_UNDERCLOCKED_EINT           0x0010  /* AIF1_UNDERCLOCKED_EINT */
+#define WM5100_AIF1_UNDERCLOCKED_EINT_MASK      0x0010  /* AIF1_UNDERCLOCKED_EINT */
+#define WM5100_AIF1_UNDERCLOCKED_EINT_SHIFT          4  /* AIF1_UNDERCLOCKED_EINT */
+#define WM5100_AIF1_UNDERCLOCKED_EINT_WIDTH          1  /* AIF1_UNDERCLOCKED_EINT */
+#define WM5100_ASRC_UNDERCLOCKED_EINT           0x0008  /* ASRC_UNDERCLOCKED_EINT */
+#define WM5100_ASRC_UNDERCLOCKED_EINT_MASK      0x0008  /* ASRC_UNDERCLOCKED_EINT */
+#define WM5100_ASRC_UNDERCLOCKED_EINT_SHIFT          3  /* ASRC_UNDERCLOCKED_EINT */
+#define WM5100_ASRC_UNDERCLOCKED_EINT_WIDTH          1  /* ASRC_UNDERCLOCKED_EINT */
+#define WM5100_DAC_UNDERCLOCKED_EINT            0x0004  /* DAC_UNDERCLOCKED_EINT */
+#define WM5100_DAC_UNDERCLOCKED_EINT_MASK       0x0004  /* DAC_UNDERCLOCKED_EINT */
+#define WM5100_DAC_UNDERCLOCKED_EINT_SHIFT           2  /* DAC_UNDERCLOCKED_EINT */
+#define WM5100_DAC_UNDERCLOCKED_EINT_WIDTH           1  /* DAC_UNDERCLOCKED_EINT */
+#define WM5100_ADC_UNDERCLOCKED_EINT            0x0002  /* ADC_UNDERCLOCKED_EINT */
+#define WM5100_ADC_UNDERCLOCKED_EINT_MASK       0x0002  /* ADC_UNDERCLOCKED_EINT */
+#define WM5100_ADC_UNDERCLOCKED_EINT_SHIFT           1  /* ADC_UNDERCLOCKED_EINT */
+#define WM5100_ADC_UNDERCLOCKED_EINT_WIDTH           1  /* ADC_UNDERCLOCKED_EINT */
+#define WM5100_MIXER_UNDERCLOCKED_EINT          0x0001  /* MIXER_UNDERCLOCKED_EINT */
+#define WM5100_MIXER_UNDERCLOCKED_EINT_MASK     0x0001  /* MIXER_UNDERCLOCKED_EINT */
+#define WM5100_MIXER_UNDERCLOCKED_EINT_SHIFT         0  /* MIXER_UNDERCLOCKED_EINT */
+#define WM5100_MIXER_UNDERCLOCKED_EINT_WIDTH         1  /* MIXER_UNDERCLOCKED_EINT */
+
+/*
+ * R3332 (0xD04) - Interrupt Raw Status 2
+ */
+#define WM5100_DSP_IRQ6_STS                     0x0020  /* DSP_IRQ6_STS */
+#define WM5100_DSP_IRQ6_STS_MASK                0x0020  /* DSP_IRQ6_STS */
+#define WM5100_DSP_IRQ6_STS_SHIFT                    5  /* DSP_IRQ6_STS */
+#define WM5100_DSP_IRQ6_STS_WIDTH                    1  /* DSP_IRQ6_STS */
+#define WM5100_DSP_IRQ5_STS                     0x0010  /* DSP_IRQ5_STS */
+#define WM5100_DSP_IRQ5_STS_MASK                0x0010  /* DSP_IRQ5_STS */
+#define WM5100_DSP_IRQ5_STS_SHIFT                    4  /* DSP_IRQ5_STS */
+#define WM5100_DSP_IRQ5_STS_WIDTH                    1  /* DSP_IRQ5_STS */
+#define WM5100_DSP_IRQ4_STS                     0x0008  /* DSP_IRQ4_STS */
+#define WM5100_DSP_IRQ4_STS_MASK                0x0008  /* DSP_IRQ4_STS */
+#define WM5100_DSP_IRQ4_STS_SHIFT                    3  /* DSP_IRQ4_STS */
+#define WM5100_DSP_IRQ4_STS_WIDTH                    1  /* DSP_IRQ4_STS */
+#define WM5100_DSP_IRQ3_STS                     0x0004  /* DSP_IRQ3_STS */
+#define WM5100_DSP_IRQ3_STS_MASK                0x0004  /* DSP_IRQ3_STS */
+#define WM5100_DSP_IRQ3_STS_SHIFT                    2  /* DSP_IRQ3_STS */
+#define WM5100_DSP_IRQ3_STS_WIDTH                    1  /* DSP_IRQ3_STS */
+#define WM5100_DSP_IRQ2_STS                     0x0002  /* DSP_IRQ2_STS */
+#define WM5100_DSP_IRQ2_STS_MASK                0x0002  /* DSP_IRQ2_STS */
+#define WM5100_DSP_IRQ2_STS_SHIFT                    1  /* DSP_IRQ2_STS */
+#define WM5100_DSP_IRQ2_STS_WIDTH                    1  /* DSP_IRQ2_STS */
+#define WM5100_DSP_IRQ1_STS                     0x0001  /* DSP_IRQ1_STS */
+#define WM5100_DSP_IRQ1_STS_MASK                0x0001  /* DSP_IRQ1_STS */
+#define WM5100_DSP_IRQ1_STS_SHIFT                    0  /* DSP_IRQ1_STS */
+#define WM5100_DSP_IRQ1_STS_WIDTH                    1  /* DSP_IRQ1_STS */
+
+/*
+ * R3333 (0xD05) - Interrupt Raw Status 3
+ */
+#define WM5100_SPK_SHUTDOWN_WARN_STS            0x8000  /* SPK_SHUTDOWN_WARN_STS */
+#define WM5100_SPK_SHUTDOWN_WARN_STS_MASK       0x8000  /* SPK_SHUTDOWN_WARN_STS */
+#define WM5100_SPK_SHUTDOWN_WARN_STS_SHIFT          15  /* SPK_SHUTDOWN_WARN_STS */
+#define WM5100_SPK_SHUTDOWN_WARN_STS_WIDTH           1  /* SPK_SHUTDOWN_WARN_STS */
+#define WM5100_SPK_SHUTDOWN_STS                 0x4000  /* SPK_SHUTDOWN_STS */
+#define WM5100_SPK_SHUTDOWN_STS_MASK            0x4000  /* SPK_SHUTDOWN_STS */
+#define WM5100_SPK_SHUTDOWN_STS_SHIFT               14  /* SPK_SHUTDOWN_STS */
+#define WM5100_SPK_SHUTDOWN_STS_WIDTH                1  /* SPK_SHUTDOWN_STS */
+#define WM5100_HPDET_STS                        0x2000  /* HPDET_STS */
+#define WM5100_HPDET_STS_MASK                   0x2000  /* HPDET_STS */
+#define WM5100_HPDET_STS_SHIFT                      13  /* HPDET_STS */
+#define WM5100_HPDET_STS_WIDTH                       1  /* HPDET_STS */
+#define WM5100_DRC_SID_DET_STS                  0x0200  /* DRC_SID_DET_STS */
+#define WM5100_DRC_SID_DET_STS_MASK             0x0200  /* DRC_SID_DET_STS */
+#define WM5100_DRC_SID_DET_STS_SHIFT                 9  /* DRC_SID_DET_STS */
+#define WM5100_DRC_SID_DET_STS_WIDTH                 1  /* DRC_SID_DET_STS */
+#define WM5100_ASRC2_LOCK_STS                   0x0100  /* ASRC2_LOCK_STS */
+#define WM5100_ASRC2_LOCK_STS_MASK              0x0100  /* ASRC2_LOCK_STS */
+#define WM5100_ASRC2_LOCK_STS_SHIFT                  8  /* ASRC2_LOCK_STS */
+#define WM5100_ASRC2_LOCK_STS_WIDTH                  1  /* ASRC2_LOCK_STS */
+#define WM5100_ASRC1_LOCK_STS                   0x0080  /* ASRC1_LOCK_STS */
+#define WM5100_ASRC1_LOCK_STS_MASK              0x0080  /* ASRC1_LOCK_STS */
+#define WM5100_ASRC1_LOCK_STS_SHIFT                  7  /* ASRC1_LOCK_STS */
+#define WM5100_ASRC1_LOCK_STS_WIDTH                  1  /* ASRC1_LOCK_STS */
+#define WM5100_FLL2_LOCK_STS                    0x0008  /* FLL2_LOCK_STS */
+#define WM5100_FLL2_LOCK_STS_MASK               0x0008  /* FLL2_LOCK_STS */
+#define WM5100_FLL2_LOCK_STS_SHIFT                   3  /* FLL2_LOCK_STS */
+#define WM5100_FLL2_LOCK_STS_WIDTH                   1  /* FLL2_LOCK_STS */
+#define WM5100_FLL1_LOCK_STS                    0x0004  /* FLL1_LOCK_STS */
+#define WM5100_FLL1_LOCK_STS_MASK               0x0004  /* FLL1_LOCK_STS */
+#define WM5100_FLL1_LOCK_STS_SHIFT                   2  /* FLL1_LOCK_STS */
+#define WM5100_FLL1_LOCK_STS_WIDTH                   1  /* FLL1_LOCK_STS */
+#define WM5100_CLKGEN_ERR_STS                   0x0002  /* CLKGEN_ERR_STS */
+#define WM5100_CLKGEN_ERR_STS_MASK              0x0002  /* CLKGEN_ERR_STS */
+#define WM5100_CLKGEN_ERR_STS_SHIFT                  1  /* CLKGEN_ERR_STS */
+#define WM5100_CLKGEN_ERR_STS_WIDTH                  1  /* CLKGEN_ERR_STS */
+#define WM5100_CLKGEN_ERR_ASYNC_STS             0x0001  /* CLKGEN_ERR_ASYNC_STS */
+#define WM5100_CLKGEN_ERR_ASYNC_STS_MASK        0x0001  /* CLKGEN_ERR_ASYNC_STS */
+#define WM5100_CLKGEN_ERR_ASYNC_STS_SHIFT            0  /* CLKGEN_ERR_ASYNC_STS */
+#define WM5100_CLKGEN_ERR_ASYNC_STS_WIDTH            1  /* CLKGEN_ERR_ASYNC_STS */
+
+/*
+ * R3334 (0xD06) - Interrupt Raw Status 4
+ */
+#define WM5100_AIF3_ERR_STS                     0x2000  /* AIF3_ERR_STS */
+#define WM5100_AIF3_ERR_STS_MASK                0x2000  /* AIF3_ERR_STS */
+#define WM5100_AIF3_ERR_STS_SHIFT                   13  /* AIF3_ERR_STS */
+#define WM5100_AIF3_ERR_STS_WIDTH                    1  /* AIF3_ERR_STS */
+#define WM5100_AIF2_ERR_STS                     0x1000  /* AIF2_ERR_STS */
+#define WM5100_AIF2_ERR_STS_MASK                0x1000  /* AIF2_ERR_STS */
+#define WM5100_AIF2_ERR_STS_SHIFT                   12  /* AIF2_ERR_STS */
+#define WM5100_AIF2_ERR_STS_WIDTH                    1  /* AIF2_ERR_STS */
+#define WM5100_AIF1_ERR_STS                     0x0800  /* AIF1_ERR_STS */
+#define WM5100_AIF1_ERR_STS_MASK                0x0800  /* AIF1_ERR_STS */
+#define WM5100_AIF1_ERR_STS_SHIFT                   11  /* AIF1_ERR_STS */
+#define WM5100_AIF1_ERR_STS_WIDTH                    1  /* AIF1_ERR_STS */
+#define WM5100_CTRLIF_ERR_STS                   0x0400  /* CTRLIF_ERR_STS */
+#define WM5100_CTRLIF_ERR_STS_MASK              0x0400  /* CTRLIF_ERR_STS */
+#define WM5100_CTRLIF_ERR_STS_SHIFT                 10  /* CTRLIF_ERR_STS */
+#define WM5100_CTRLIF_ERR_STS_WIDTH                  1  /* CTRLIF_ERR_STS */
+#define WM5100_ISRC2_UNDERCLOCKED_STS           0x0200  /* ISRC2_UNDERCLOCKED_STS */
+#define WM5100_ISRC2_UNDERCLOCKED_STS_MASK      0x0200  /* ISRC2_UNDERCLOCKED_STS */
+#define WM5100_ISRC2_UNDERCLOCKED_STS_SHIFT          9  /* ISRC2_UNDERCLOCKED_STS */
+#define WM5100_ISRC2_UNDERCLOCKED_STS_WIDTH          1  /* ISRC2_UNDERCLOCKED_STS */
+#define WM5100_ISRC1_UNDERCLOCKED_STS           0x0100  /* ISRC1_UNDERCLOCKED_STS */
+#define WM5100_ISRC1_UNDERCLOCKED_STS_MASK      0x0100  /* ISRC1_UNDERCLOCKED_STS */
+#define WM5100_ISRC1_UNDERCLOCKED_STS_SHIFT          8  /* ISRC1_UNDERCLOCKED_STS */
+#define WM5100_ISRC1_UNDERCLOCKED_STS_WIDTH          1  /* ISRC1_UNDERCLOCKED_STS */
+#define WM5100_FX_UNDERCLOCKED_STS              0x0080  /* FX_UNDERCLOCKED_STS */
+#define WM5100_FX_UNDERCLOCKED_STS_MASK         0x0080  /* FX_UNDERCLOCKED_STS */
+#define WM5100_FX_UNDERCLOCKED_STS_SHIFT             7  /* FX_UNDERCLOCKED_STS */
+#define WM5100_FX_UNDERCLOCKED_STS_WIDTH             1  /* FX_UNDERCLOCKED_STS */
+#define WM5100_AIF3_UNDERCLOCKED_STS            0x0040  /* AIF3_UNDERCLOCKED_STS */
+#define WM5100_AIF3_UNDERCLOCKED_STS_MASK       0x0040  /* AIF3_UNDERCLOCKED_STS */
+#define WM5100_AIF3_UNDERCLOCKED_STS_SHIFT           6  /* AIF3_UNDERCLOCKED_STS */
+#define WM5100_AIF3_UNDERCLOCKED_STS_WIDTH           1  /* AIF3_UNDERCLOCKED_STS */
+#define WM5100_AIF2_UNDERCLOCKED_STS            0x0020  /* AIF2_UNDERCLOCKED_STS */
+#define WM5100_AIF2_UNDERCLOCKED_STS_MASK       0x0020  /* AIF2_UNDERCLOCKED_STS */
+#define WM5100_AIF2_UNDERCLOCKED_STS_SHIFT           5  /* AIF2_UNDERCLOCKED_STS */
+#define WM5100_AIF2_UNDERCLOCKED_STS_WIDTH           1  /* AIF2_UNDERCLOCKED_STS */
+#define WM5100_AIF1_UNDERCLOCKED_STS            0x0010  /* AIF1_UNDERCLOCKED_STS */
+#define WM5100_AIF1_UNDERCLOCKED_STS_MASK       0x0010  /* AIF1_UNDERCLOCKED_STS */
+#define WM5100_AIF1_UNDERCLOCKED_STS_SHIFT           4  /* AIF1_UNDERCLOCKED_STS */
+#define WM5100_AIF1_UNDERCLOCKED_STS_WIDTH           1  /* AIF1_UNDERCLOCKED_STS */
+#define WM5100_ASRC_UNDERCLOCKED_STS            0x0008  /* ASRC_UNDERCLOCKED_STS */
+#define WM5100_ASRC_UNDERCLOCKED_STS_MASK       0x0008  /* ASRC_UNDERCLOCKED_STS */
+#define WM5100_ASRC_UNDERCLOCKED_STS_SHIFT           3  /* ASRC_UNDERCLOCKED_STS */
+#define WM5100_ASRC_UNDERCLOCKED_STS_WIDTH           1  /* ASRC_UNDERCLOCKED_STS */
+#define WM5100_DAC_UNDERCLOCKED_STS             0x0004  /* DAC_UNDERCLOCKED_STS */
+#define WM5100_DAC_UNDERCLOCKED_STS_MASK        0x0004  /* DAC_UNDERCLOCKED_STS */
+#define WM5100_DAC_UNDERCLOCKED_STS_SHIFT            2  /* DAC_UNDERCLOCKED_STS */
+#define WM5100_DAC_UNDERCLOCKED_STS_WIDTH            1  /* DAC_UNDERCLOCKED_STS */
+#define WM5100_ADC_UNDERCLOCKED_STS             0x0002  /* ADC_UNDERCLOCKED_STS */
+#define WM5100_ADC_UNDERCLOCKED_STS_MASK        0x0002  /* ADC_UNDERCLOCKED_STS */
+#define WM5100_ADC_UNDERCLOCKED_STS_SHIFT            1  /* ADC_UNDERCLOCKED_STS */
+#define WM5100_ADC_UNDERCLOCKED_STS_WIDTH            1  /* ADC_UNDERCLOCKED_STS */
+#define WM5100_MIXER_UNDERCLOCKED_STS           0x0001  /* MIXER_UNDERCLOCKED_STS */
+#define WM5100_MIXER_UNDERCLOCKED_STS_MASK      0x0001  /* MIXER_UNDERCLOCKED_STS */
+#define WM5100_MIXER_UNDERCLOCKED_STS_SHIFT          0  /* MIXER_UNDERCLOCKED_STS */
+#define WM5100_MIXER_UNDERCLOCKED_STS_WIDTH          1  /* MIXER_UNDERCLOCKED_STS */
+
+/*
+ * R3335 (0xD07) - Interrupt Status 1 Mask
+ */
+#define WM5100_IM_GP6_EINT                      0x0020  /* IM_GP6_EINT */
+#define WM5100_IM_GP6_EINT_MASK                 0x0020  /* IM_GP6_EINT */
+#define WM5100_IM_GP6_EINT_SHIFT                     5  /* IM_GP6_EINT */
+#define WM5100_IM_GP6_EINT_WIDTH                     1  /* IM_GP6_EINT */
+#define WM5100_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
+#define WM5100_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
+#define WM5100_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
+#define WM5100_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
+#define WM5100_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
+#define WM5100_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
+#define WM5100_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
+#define WM5100_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
+#define WM5100_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
+#define WM5100_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
+#define WM5100_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
+#define WM5100_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
+#define WM5100_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
+#define WM5100_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
+#define WM5100_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
+#define WM5100_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
+#define WM5100_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
+#define WM5100_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
+#define WM5100_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
+#define WM5100_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
+
+/*
+ * R3336 (0xD08) - Interrupt Status 2 Mask
+ */
+#define WM5100_IM_DSP_IRQ6_EINT                 0x0020  /* IM_DSP_IRQ6_EINT */
+#define WM5100_IM_DSP_IRQ6_EINT_MASK            0x0020  /* IM_DSP_IRQ6_EINT */
+#define WM5100_IM_DSP_IRQ6_EINT_SHIFT                5  /* IM_DSP_IRQ6_EINT */
+#define WM5100_IM_DSP_IRQ6_EINT_WIDTH                1  /* IM_DSP_IRQ6_EINT */
+#define WM5100_IM_DSP_IRQ5_EINT                 0x0010  /* IM_DSP_IRQ5_EINT */
+#define WM5100_IM_DSP_IRQ5_EINT_MASK            0x0010  /* IM_DSP_IRQ5_EINT */
+#define WM5100_IM_DSP_IRQ5_EINT_SHIFT                4  /* IM_DSP_IRQ5_EINT */
+#define WM5100_IM_DSP_IRQ5_EINT_WIDTH                1  /* IM_DSP_IRQ5_EINT */
+#define WM5100_IM_DSP_IRQ4_EINT                 0x0008  /* IM_DSP_IRQ4_EINT */
+#define WM5100_IM_DSP_IRQ4_EINT_MASK            0x0008  /* IM_DSP_IRQ4_EINT */
+#define WM5100_IM_DSP_IRQ4_EINT_SHIFT                3  /* IM_DSP_IRQ4_EINT */
+#define WM5100_IM_DSP_IRQ4_EINT_WIDTH                1  /* IM_DSP_IRQ4_EINT */
+#define WM5100_IM_DSP_IRQ3_EINT                 0x0004  /* IM_DSP_IRQ3_EINT */
+#define WM5100_IM_DSP_IRQ3_EINT_MASK            0x0004  /* IM_DSP_IRQ3_EINT */
+#define WM5100_IM_DSP_IRQ3_EINT_SHIFT                2  /* IM_DSP_IRQ3_EINT */
+#define WM5100_IM_DSP_IRQ3_EINT_WIDTH                1  /* IM_DSP_IRQ3_EINT */
+#define WM5100_IM_DSP_IRQ2_EINT                 0x0002  /* IM_DSP_IRQ2_EINT */
+#define WM5100_IM_DSP_IRQ2_EINT_MASK            0x0002  /* IM_DSP_IRQ2_EINT */
+#define WM5100_IM_DSP_IRQ2_EINT_SHIFT                1  /* IM_DSP_IRQ2_EINT */
+#define WM5100_IM_DSP_IRQ2_EINT_WIDTH                1  /* IM_DSP_IRQ2_EINT */
+#define WM5100_IM_DSP_IRQ1_EINT                 0x0001  /* IM_DSP_IRQ1_EINT */
+#define WM5100_IM_DSP_IRQ1_EINT_MASK            0x0001  /* IM_DSP_IRQ1_EINT */
+#define WM5100_IM_DSP_IRQ1_EINT_SHIFT                0  /* IM_DSP_IRQ1_EINT */
+#define WM5100_IM_DSP_IRQ1_EINT_WIDTH                1  /* IM_DSP_IRQ1_EINT */
+
+/*
+ * R3337 (0xD09) - Interrupt Status 3 Mask
+ */
+#define WM5100_IM_SPK_SHUTDOWN_WARN_EINT        0x8000  /* IM_SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_IM_SPK_SHUTDOWN_WARN_EINT_MASK   0x8000  /* IM_SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_IM_SPK_SHUTDOWN_WARN_EINT_SHIFT      15  /* IM_SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_IM_SPK_SHUTDOWN_WARN_EINT_WIDTH       1  /* IM_SPK_SHUTDOWN_WARN_EINT */
+#define WM5100_IM_SPK_SHUTDOWN_EINT             0x4000  /* IM_SPK_SHUTDOWN_EINT */
+#define WM5100_IM_SPK_SHUTDOWN_EINT_MASK        0x4000  /* IM_SPK_SHUTDOWN_EINT */
+#define WM5100_IM_SPK_SHUTDOWN_EINT_SHIFT           14  /* IM_SPK_SHUTDOWN_EINT */
+#define WM5100_IM_SPK_SHUTDOWN_EINT_WIDTH            1  /* IM_SPK_SHUTDOWN_EINT */
+#define WM5100_IM_HPDET_EINT                    0x2000  /* IM_HPDET_EINT */
+#define WM5100_IM_HPDET_EINT_MASK               0x2000  /* IM_HPDET_EINT */
+#define WM5100_IM_HPDET_EINT_SHIFT                  13  /* IM_HPDET_EINT */
+#define WM5100_IM_HPDET_EINT_WIDTH                   1  /* IM_HPDET_EINT */
+#define WM5100_IM_ACCDET_EINT                   0x1000  /* IM_ACCDET_EINT */
+#define WM5100_IM_ACCDET_EINT_MASK              0x1000  /* IM_ACCDET_EINT */
+#define WM5100_IM_ACCDET_EINT_SHIFT                 12  /* IM_ACCDET_EINT */
+#define WM5100_IM_ACCDET_EINT_WIDTH                  1  /* IM_ACCDET_EINT */
+#define WM5100_IM_DRC_SIG_DET_EINT              0x0200  /* IM_DRC_SIG_DET_EINT */
+#define WM5100_IM_DRC_SIG_DET_EINT_MASK         0x0200  /* IM_DRC_SIG_DET_EINT */
+#define WM5100_IM_DRC_SIG_DET_EINT_SHIFT             9  /* IM_DRC_SIG_DET_EINT */
+#define WM5100_IM_DRC_SIG_DET_EINT_WIDTH             1  /* IM_DRC_SIG_DET_EINT */
+#define WM5100_IM_ASRC2_LOCK_EINT               0x0100  /* IM_ASRC2_LOCK_EINT */
+#define WM5100_IM_ASRC2_LOCK_EINT_MASK          0x0100  /* IM_ASRC2_LOCK_EINT */
+#define WM5100_IM_ASRC2_LOCK_EINT_SHIFT              8  /* IM_ASRC2_LOCK_EINT */
+#define WM5100_IM_ASRC2_LOCK_EINT_WIDTH              1  /* IM_ASRC2_LOCK_EINT */
+#define WM5100_IM_ASRC1_LOCK_EINT               0x0080  /* IM_ASRC1_LOCK_EINT */
+#define WM5100_IM_ASRC1_LOCK_EINT_MASK          0x0080  /* IM_ASRC1_LOCK_EINT */
+#define WM5100_IM_ASRC1_LOCK_EINT_SHIFT              7  /* IM_ASRC1_LOCK_EINT */
+#define WM5100_IM_ASRC1_LOCK_EINT_WIDTH              1  /* IM_ASRC1_LOCK_EINT */
+#define WM5100_IM_FLL2_LOCK_EINT                0x0008  /* IM_FLL2_LOCK_EINT */
+#define WM5100_IM_FLL2_LOCK_EINT_MASK           0x0008  /* IM_FLL2_LOCK_EINT */
+#define WM5100_IM_FLL2_LOCK_EINT_SHIFT               3  /* IM_FLL2_LOCK_EINT */
+#define WM5100_IM_FLL2_LOCK_EINT_WIDTH               1  /* IM_FLL2_LOCK_EINT */
+#define WM5100_IM_FLL1_LOCK_EINT                0x0004  /* IM_FLL1_LOCK_EINT */
+#define WM5100_IM_FLL1_LOCK_EINT_MASK           0x0004  /* IM_FLL1_LOCK_EINT */
+#define WM5100_IM_FLL1_LOCK_EINT_SHIFT               2  /* IM_FLL1_LOCK_EINT */
+#define WM5100_IM_FLL1_LOCK_EINT_WIDTH               1  /* IM_FLL1_LOCK_EINT */
+#define WM5100_IM_CLKGEN_ERR_EINT               0x0002  /* IM_CLKGEN_ERR_EINT */
+#define WM5100_IM_CLKGEN_ERR_EINT_MASK          0x0002  /* IM_CLKGEN_ERR_EINT */
+#define WM5100_IM_CLKGEN_ERR_EINT_SHIFT              1  /* IM_CLKGEN_ERR_EINT */
+#define WM5100_IM_CLKGEN_ERR_EINT_WIDTH              1  /* IM_CLKGEN_ERR_EINT */
+#define WM5100_IM_CLKGEN_ERR_ASYNC_EINT         0x0001  /* IM_CLKGEN_ERR_ASYNC_EINT */
+#define WM5100_IM_CLKGEN_ERR_ASYNC_EINT_MASK    0x0001  /* IM_CLKGEN_ERR_ASYNC_EINT */
+#define WM5100_IM_CLKGEN_ERR_ASYNC_EINT_SHIFT        0  /* IM_CLKGEN_ERR_ASYNC_EINT */
+#define WM5100_IM_CLKGEN_ERR_ASYNC_EINT_WIDTH        1  /* IM_CLKGEN_ERR_ASYNC_EINT */
+
+/*
+ * R3338 (0xD0A) - Interrupt Status 4 Mask
+ */
+#define WM5100_IM_AIF3_ERR_EINT                 0x2000  /* IM_AIF3_ERR_EINT */
+#define WM5100_IM_AIF3_ERR_EINT_MASK            0x2000  /* IM_AIF3_ERR_EINT */
+#define WM5100_IM_AIF3_ERR_EINT_SHIFT               13  /* IM_AIF3_ERR_EINT */
+#define WM5100_IM_AIF3_ERR_EINT_WIDTH                1  /* IM_AIF3_ERR_EINT */
+#define WM5100_IM_AIF2_ERR_EINT                 0x1000  /* IM_AIF2_ERR_EINT */
+#define WM5100_IM_AIF2_ERR_EINT_MASK            0x1000  /* IM_AIF2_ERR_EINT */
+#define WM5100_IM_AIF2_ERR_EINT_SHIFT               12  /* IM_AIF2_ERR_EINT */
+#define WM5100_IM_AIF2_ERR_EINT_WIDTH                1  /* IM_AIF2_ERR_EINT */
+#define WM5100_IM_AIF1_ERR_EINT                 0x0800  /* IM_AIF1_ERR_EINT */
+#define WM5100_IM_AIF1_ERR_EINT_MASK            0x0800  /* IM_AIF1_ERR_EINT */
+#define WM5100_IM_AIF1_ERR_EINT_SHIFT               11  /* IM_AIF1_ERR_EINT */
+#define WM5100_IM_AIF1_ERR_EINT_WIDTH                1  /* IM_AIF1_ERR_EINT */
+#define WM5100_IM_CTRLIF_ERR_EINT               0x0400  /* IM_CTRLIF_ERR_EINT */
+#define WM5100_IM_CTRLIF_ERR_EINT_MASK          0x0400  /* IM_CTRLIF_ERR_EINT */
+#define WM5100_IM_CTRLIF_ERR_EINT_SHIFT             10  /* IM_CTRLIF_ERR_EINT */
+#define WM5100_IM_CTRLIF_ERR_EINT_WIDTH              1  /* IM_CTRLIF_ERR_EINT */
+#define WM5100_IM_ISRC2_UNDERCLOCKED_EINT       0x0200  /* IM_ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_IM_ISRC2_UNDERCLOCKED_EINT_MASK  0x0200  /* IM_ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_IM_ISRC2_UNDERCLOCKED_EINT_SHIFT      9  /* IM_ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_IM_ISRC2_UNDERCLOCKED_EINT_WIDTH      1  /* IM_ISRC2_UNDERCLOCKED_EINT */
+#define WM5100_IM_ISRC1_UNDERCLOCKED_EINT       0x0100  /* IM_ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_IM_ISRC1_UNDERCLOCKED_EINT_MASK  0x0100  /* IM_ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_IM_ISRC1_UNDERCLOCKED_EINT_SHIFT      8  /* IM_ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_IM_ISRC1_UNDERCLOCKED_EINT_WIDTH      1  /* IM_ISRC1_UNDERCLOCKED_EINT */
+#define WM5100_IM_FX_UNDERCLOCKED_EINT          0x0080  /* IM_FX_UNDERCLOCKED_EINT */
+#define WM5100_IM_FX_UNDERCLOCKED_EINT_MASK     0x0080  /* IM_FX_UNDERCLOCKED_EINT */
+#define WM5100_IM_FX_UNDERCLOCKED_EINT_SHIFT         7  /* IM_FX_UNDERCLOCKED_EINT */
+#define WM5100_IM_FX_UNDERCLOCKED_EINT_WIDTH         1  /* IM_FX_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF3_UNDERCLOCKED_EINT        0x0040  /* IM_AIF3_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF3_UNDERCLOCKED_EINT_MASK   0x0040  /* IM_AIF3_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF3_UNDERCLOCKED_EINT_SHIFT       6  /* IM_AIF3_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF3_UNDERCLOCKED_EINT_WIDTH       1  /* IM_AIF3_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF2_UNDERCLOCKED_EINT        0x0020  /* IM_AIF2_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF2_UNDERCLOCKED_EINT_MASK   0x0020  /* IM_AIF2_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF2_UNDERCLOCKED_EINT_SHIFT       5  /* IM_AIF2_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF2_UNDERCLOCKED_EINT_WIDTH       1  /* IM_AIF2_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF1_UNDERCLOCKED_EINT        0x0010  /* IM_AIF1_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF1_UNDERCLOCKED_EINT_MASK   0x0010  /* IM_AIF1_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF1_UNDERCLOCKED_EINT_SHIFT       4  /* IM_AIF1_UNDERCLOCKED_EINT */
+#define WM5100_IM_AIF1_UNDERCLOCKED_EINT_WIDTH       1  /* IM_AIF1_UNDERCLOCKED_EINT */
+#define WM5100_IM_ASRC_UNDERCLOCKED_EINT        0x0008  /* IM_ASRC_UNDERCLOCKED_EINT */
+#define WM5100_IM_ASRC_UNDERCLOCKED_EINT_MASK   0x0008  /* IM_ASRC_UNDERCLOCKED_EINT */
+#define WM5100_IM_ASRC_UNDERCLOCKED_EINT_SHIFT       3  /* IM_ASRC_UNDERCLOCKED_EINT */
+#define WM5100_IM_ASRC_UNDERCLOCKED_EINT_WIDTH       1  /* IM_ASRC_UNDERCLOCKED_EINT */
+#define WM5100_IM_DAC_UNDERCLOCKED_EINT         0x0004  /* IM_DAC_UNDERCLOCKED_EINT */
+#define WM5100_IM_DAC_UNDERCLOCKED_EINT_MASK    0x0004  /* IM_DAC_UNDERCLOCKED_EINT */
+#define WM5100_IM_DAC_UNDERCLOCKED_EINT_SHIFT        2  /* IM_DAC_UNDERCLOCKED_EINT */
+#define WM5100_IM_DAC_UNDERCLOCKED_EINT_WIDTH        1  /* IM_DAC_UNDERCLOCKED_EINT */
+#define WM5100_IM_ADC_UNDERCLOCKED_EINT         0x0002  /* IM_ADC_UNDERCLOCKED_EINT */
+#define WM5100_IM_ADC_UNDERCLOCKED_EINT_MASK    0x0002  /* IM_ADC_UNDERCLOCKED_EINT */
+#define WM5100_IM_ADC_UNDERCLOCKED_EINT_SHIFT        1  /* IM_ADC_UNDERCLOCKED_EINT */
+#define WM5100_IM_ADC_UNDERCLOCKED_EINT_WIDTH        1  /* IM_ADC_UNDERCLOCKED_EINT */
+#define WM5100_IM_MIXER_UNDERCLOCKED_EINT       0x0001  /* IM_MIXER_UNDERCLOCKED_EINT */
+#define WM5100_IM_MIXER_UNDERCLOCKED_EINT_MASK  0x0001  /* IM_MIXER_UNDERCLOCKED_EINT */
+#define WM5100_IM_MIXER_UNDERCLOCKED_EINT_SHIFT      0  /* IM_MIXER_UNDERCLOCKED_EINT */
+#define WM5100_IM_MIXER_UNDERCLOCKED_EINT_WIDTH      1  /* IM_MIXER_UNDERCLOCKED_EINT */
+
+/*
+ * R3359 (0xD1F) - Interrupt Control
+ */
+#define WM5100_IM_IRQ                           0x0001  /* IM_IRQ */
+#define WM5100_IM_IRQ_MASK                      0x0001  /* IM_IRQ */
+#define WM5100_IM_IRQ_SHIFT                          0  /* IM_IRQ */
+#define WM5100_IM_IRQ_WIDTH                          1  /* IM_IRQ */
+
+/*
+ * R3360 (0xD20) - IRQ Debounce 1
+ */
+#define WM5100_SPK_SHUTDOWN_WARN_DB             0x0200  /* SPK_SHUTDOWN_WARN_DB */
+#define WM5100_SPK_SHUTDOWN_WARN_DB_MASK        0x0200  /* SPK_SHUTDOWN_WARN_DB */
+#define WM5100_SPK_SHUTDOWN_WARN_DB_SHIFT            9  /* SPK_SHUTDOWN_WARN_DB */
+#define WM5100_SPK_SHUTDOWN_WARN_DB_WIDTH            1  /* SPK_SHUTDOWN_WARN_DB */
+#define WM5100_SPK_SHUTDOWN_DB                  0x0100  /* SPK_SHUTDOWN_DB */
+#define WM5100_SPK_SHUTDOWN_DB_MASK             0x0100  /* SPK_SHUTDOWN_DB */
+#define WM5100_SPK_SHUTDOWN_DB_SHIFT                 8  /* SPK_SHUTDOWN_DB */
+#define WM5100_SPK_SHUTDOWN_DB_WIDTH                 1  /* SPK_SHUTDOWN_DB */
+#define WM5100_FLL1_LOCK_IRQ_DB                 0x0008  /* FLL1_LOCK_IRQ_DB */
+#define WM5100_FLL1_LOCK_IRQ_DB_MASK            0x0008  /* FLL1_LOCK_IRQ_DB */
+#define WM5100_FLL1_LOCK_IRQ_DB_SHIFT                3  /* FLL1_LOCK_IRQ_DB */
+#define WM5100_FLL1_LOCK_IRQ_DB_WIDTH                1  /* FLL1_LOCK_IRQ_DB */
+#define WM5100_FLL2_LOCK_IRQ_DB                 0x0004  /* FLL2_LOCK_IRQ_DB */
+#define WM5100_FLL2_LOCK_IRQ_DB_MASK            0x0004  /* FLL2_LOCK_IRQ_DB */
+#define WM5100_FLL2_LOCK_IRQ_DB_SHIFT                2  /* FLL2_LOCK_IRQ_DB */
+#define WM5100_FLL2_LOCK_IRQ_DB_WIDTH                1  /* FLL2_LOCK_IRQ_DB */
+#define WM5100_CLKGEN_ERR_IRQ_DB                0x0002  /* CLKGEN_ERR_IRQ_DB */
+#define WM5100_CLKGEN_ERR_IRQ_DB_MASK           0x0002  /* CLKGEN_ERR_IRQ_DB */
+#define WM5100_CLKGEN_ERR_IRQ_DB_SHIFT               1  /* CLKGEN_ERR_IRQ_DB */
+#define WM5100_CLKGEN_ERR_IRQ_DB_WIDTH               1  /* CLKGEN_ERR_IRQ_DB */
+#define WM5100_CLKGEN_ERR_ASYNC_IRQ_DB          0x0001  /* CLKGEN_ERR_ASYNC_IRQ_DB */
+#define WM5100_CLKGEN_ERR_ASYNC_IRQ_DB_MASK     0x0001  /* CLKGEN_ERR_ASYNC_IRQ_DB */
+#define WM5100_CLKGEN_ERR_ASYNC_IRQ_DB_SHIFT         0  /* CLKGEN_ERR_ASYNC_IRQ_DB */
+#define WM5100_CLKGEN_ERR_ASYNC_IRQ_DB_WIDTH         1  /* CLKGEN_ERR_ASYNC_IRQ_DB */
+
+/*
+ * R3361 (0xD21) - IRQ Debounce 2
+ */
+#define WM5100_AIF_ERR_DB                       0x0001  /* AIF_ERR_DB */
+#define WM5100_AIF_ERR_DB_MASK                  0x0001  /* AIF_ERR_DB */
+#define WM5100_AIF_ERR_DB_SHIFT                      0  /* AIF_ERR_DB */
+#define WM5100_AIF_ERR_DB_WIDTH                      1  /* AIF_ERR_DB */
+
+/*
+ * R3584 (0xE00) - FX_Ctrl
+ */
+#define WM5100_FX_STS_MASK                      0xFFC0  /* FX_STS - [15:6] */
+#define WM5100_FX_STS_SHIFT                          6  /* FX_STS - [15:6] */
+#define WM5100_FX_STS_WIDTH                         10  /* FX_STS - [15:6] */
+#define WM5100_FX_RATE_MASK                     0x0003  /* FX_RATE - [1:0] */
+#define WM5100_FX_RATE_SHIFT                         0  /* FX_RATE - [1:0] */
+#define WM5100_FX_RATE_WIDTH                         2  /* FX_RATE - [1:0] */
+
+/*
+ * R3600 (0xE10) - EQ1_1
+ */
+#define WM5100_EQ1_B1_GAIN_MASK                 0xF800  /* EQ1_B1_GAIN - [15:11] */
+#define WM5100_EQ1_B1_GAIN_SHIFT                    11  /* EQ1_B1_GAIN - [15:11] */
+#define WM5100_EQ1_B1_GAIN_WIDTH                     5  /* EQ1_B1_GAIN - [15:11] */
+#define WM5100_EQ1_B2_GAIN_MASK                 0x07C0  /* EQ1_B2_GAIN - [10:6] */
+#define WM5100_EQ1_B2_GAIN_SHIFT                     6  /* EQ1_B2_GAIN - [10:6] */
+#define WM5100_EQ1_B2_GAIN_WIDTH                     5  /* EQ1_B2_GAIN - [10:6] */
+#define WM5100_EQ1_B3_GAIN_MASK                 0x003E  /* EQ1_B3_GAIN - [5:1] */
+#define WM5100_EQ1_B3_GAIN_SHIFT                     1  /* EQ1_B3_GAIN - [5:1] */
+#define WM5100_EQ1_B3_GAIN_WIDTH                     5  /* EQ1_B3_GAIN - [5:1] */
+#define WM5100_EQ1_ENA                          0x0001  /* EQ1_ENA */
+#define WM5100_EQ1_ENA_MASK                     0x0001  /* EQ1_ENA */
+#define WM5100_EQ1_ENA_SHIFT                         0  /* EQ1_ENA */
+#define WM5100_EQ1_ENA_WIDTH                         1  /* EQ1_ENA */
+
+/*
+ * R3601 (0xE11) - EQ1_2
+ */
+#define WM5100_EQ1_B4_GAIN_MASK                 0xF800  /* EQ1_B4_GAIN - [15:11] */
+#define WM5100_EQ1_B4_GAIN_SHIFT                    11  /* EQ1_B4_GAIN - [15:11] */
+#define WM5100_EQ1_B4_GAIN_WIDTH                     5  /* EQ1_B4_GAIN - [15:11] */
+#define WM5100_EQ1_B5_GAIN_MASK                 0x07C0  /* EQ1_B5_GAIN - [10:6] */
+#define WM5100_EQ1_B5_GAIN_SHIFT                     6  /* EQ1_B5_GAIN - [10:6] */
+#define WM5100_EQ1_B5_GAIN_WIDTH                     5  /* EQ1_B5_GAIN - [10:6] */
+
+/*
+ * R3602 (0xE12) - EQ1_3
+ */
+#define WM5100_EQ1_B1_A_MASK                    0xFFFF  /* EQ1_B1_A - [15:0] */
+#define WM5100_EQ1_B1_A_SHIFT                        0  /* EQ1_B1_A - [15:0] */
+#define WM5100_EQ1_B1_A_WIDTH                       16  /* EQ1_B1_A - [15:0] */
+
+/*
+ * R3603 (0xE13) - EQ1_4
+ */
+#define WM5100_EQ1_B1_B_MASK                    0xFFFF  /* EQ1_B1_B - [15:0] */
+#define WM5100_EQ1_B1_B_SHIFT                        0  /* EQ1_B1_B - [15:0] */
+#define WM5100_EQ1_B1_B_WIDTH                       16  /* EQ1_B1_B - [15:0] */
+
+/*
+ * R3604 (0xE14) - EQ1_5
+ */
+#define WM5100_EQ1_B1_PG_MASK                   0xFFFF  /* EQ1_B1_PG - [15:0] */
+#define WM5100_EQ1_B1_PG_SHIFT                       0  /* EQ1_B1_PG - [15:0] */
+#define WM5100_EQ1_B1_PG_WIDTH                      16  /* EQ1_B1_PG - [15:0] */
+
+/*
+ * R3605 (0xE15) - EQ1_6
+ */
+#define WM5100_EQ1_B2_A_MASK                    0xFFFF  /* EQ1_B2_A - [15:0] */
+#define WM5100_EQ1_B2_A_SHIFT                        0  /* EQ1_B2_A - [15:0] */
+#define WM5100_EQ1_B2_A_WIDTH                       16  /* EQ1_B2_A - [15:0] */
+
+/*
+ * R3606 (0xE16) - EQ1_7
+ */
+#define WM5100_EQ1_B2_B_MASK                    0xFFFF  /* EQ1_B2_B - [15:0] */
+#define WM5100_EQ1_B2_B_SHIFT                        0  /* EQ1_B2_B - [15:0] */
+#define WM5100_EQ1_B2_B_WIDTH                       16  /* EQ1_B2_B - [15:0] */
+
+/*
+ * R3607 (0xE17) - EQ1_8
+ */
+#define WM5100_EQ1_B2_C_MASK                    0xFFFF  /* EQ1_B2_C - [15:0] */
+#define WM5100_EQ1_B2_C_SHIFT                        0  /* EQ1_B2_C - [15:0] */
+#define WM5100_EQ1_B2_C_WIDTH                       16  /* EQ1_B2_C - [15:0] */
+
+/*
+ * R3608 (0xE18) - EQ1_9
+ */
+#define WM5100_EQ1_B2_PG_MASK                   0xFFFF  /* EQ1_B2_PG - [15:0] */
+#define WM5100_EQ1_B2_PG_SHIFT                       0  /* EQ1_B2_PG - [15:0] */
+#define WM5100_EQ1_B2_PG_WIDTH                      16  /* EQ1_B2_PG - [15:0] */
+
+/*
+ * R3609 (0xE19) - EQ1_10
+ */
+#define WM5100_EQ1_B3_A_MASK                    0xFFFF  /* EQ1_B3_A - [15:0] */
+#define WM5100_EQ1_B3_A_SHIFT                        0  /* EQ1_B3_A - [15:0] */
+#define WM5100_EQ1_B3_A_WIDTH                       16  /* EQ1_B3_A - [15:0] */
+
+/*
+ * R3610 (0xE1A) - EQ1_11
+ */
+#define WM5100_EQ1_B3_B_MASK                    0xFFFF  /* EQ1_B3_B - [15:0] */
+#define WM5100_EQ1_B3_B_SHIFT                        0  /* EQ1_B3_B - [15:0] */
+#define WM5100_EQ1_B3_B_WIDTH                       16  /* EQ1_B3_B - [15:0] */
+
+/*
+ * R3611 (0xE1B) - EQ1_12
+ */
+#define WM5100_EQ1_B3_C_MASK                    0xFFFF  /* EQ1_B3_C - [15:0] */
+#define WM5100_EQ1_B3_C_SHIFT                        0  /* EQ1_B3_C - [15:0] */
+#define WM5100_EQ1_B3_C_WIDTH                       16  /* EQ1_B3_C - [15:0] */
+
+/*
+ * R3612 (0xE1C) - EQ1_13
+ */
+#define WM5100_EQ1_B3_PG_MASK                   0xFFFF  /* EQ1_B3_PG - [15:0] */
+#define WM5100_EQ1_B3_PG_SHIFT                       0  /* EQ1_B3_PG - [15:0] */
+#define WM5100_EQ1_B3_PG_WIDTH                      16  /* EQ1_B3_PG - [15:0] */
+
+/*
+ * R3613 (0xE1D) - EQ1_14
+ */
+#define WM5100_EQ1_B4_A_MASK                    0xFFFF  /* EQ1_B4_A - [15:0] */
+#define WM5100_EQ1_B4_A_SHIFT                        0  /* EQ1_B4_A - [15:0] */
+#define WM5100_EQ1_B4_A_WIDTH                       16  /* EQ1_B4_A - [15:0] */
+
+/*
+ * R3614 (0xE1E) - EQ1_15
+ */
+#define WM5100_EQ1_B4_B_MASK                    0xFFFF  /* EQ1_B4_B - [15:0] */
+#define WM5100_EQ1_B4_B_SHIFT                        0  /* EQ1_B4_B - [15:0] */
+#define WM5100_EQ1_B4_B_WIDTH                       16  /* EQ1_B4_B - [15:0] */
+
+/*
+ * R3615 (0xE1F) - EQ1_16
+ */
+#define WM5100_EQ1_B4_C_MASK                    0xFFFF  /* EQ1_B4_C - [15:0] */
+#define WM5100_EQ1_B4_C_SHIFT                        0  /* EQ1_B4_C - [15:0] */
+#define WM5100_EQ1_B4_C_WIDTH                       16  /* EQ1_B4_C - [15:0] */
+
+/*
+ * R3616 (0xE20) - EQ1_17
+ */
+#define WM5100_EQ1_B4_PG_MASK                   0xFFFF  /* EQ1_B4_PG - [15:0] */
+#define WM5100_EQ1_B4_PG_SHIFT                       0  /* EQ1_B4_PG - [15:0] */
+#define WM5100_EQ1_B4_PG_WIDTH                      16  /* EQ1_B4_PG - [15:0] */
+
+/*
+ * R3617 (0xE21) - EQ1_18
+ */
+#define WM5100_EQ1_B5_A_MASK                    0xFFFF  /* EQ1_B5_A - [15:0] */
+#define WM5100_EQ1_B5_A_SHIFT                        0  /* EQ1_B5_A - [15:0] */
+#define WM5100_EQ1_B5_A_WIDTH                       16  /* EQ1_B5_A - [15:0] */
+
+/*
+ * R3618 (0xE22) - EQ1_19
+ */
+#define WM5100_EQ1_B5_B_MASK                    0xFFFF  /* EQ1_B5_B - [15:0] */
+#define WM5100_EQ1_B5_B_SHIFT                        0  /* EQ1_B5_B - [15:0] */
+#define WM5100_EQ1_B5_B_WIDTH                       16  /* EQ1_B5_B - [15:0] */
+
+/*
+ * R3619 (0xE23) - EQ1_20
+ */
+#define WM5100_EQ1_B5_PG_MASK                   0xFFFF  /* EQ1_B5_PG - [15:0] */
+#define WM5100_EQ1_B5_PG_SHIFT                       0  /* EQ1_B5_PG - [15:0] */
+#define WM5100_EQ1_B5_PG_WIDTH                      16  /* EQ1_B5_PG - [15:0] */
+
+/*
+ * R3622 (0xE26) - EQ2_1
+ */
+#define WM5100_EQ2_B1_GAIN_MASK                 0xF800  /* EQ2_B1_GAIN - [15:11] */
+#define WM5100_EQ2_B1_GAIN_SHIFT                    11  /* EQ2_B1_GAIN - [15:11] */
+#define WM5100_EQ2_B1_GAIN_WIDTH                     5  /* EQ2_B1_GAIN - [15:11] */
+#define WM5100_EQ2_B2_GAIN_MASK                 0x07C0  /* EQ2_B2_GAIN - [10:6] */
+#define WM5100_EQ2_B2_GAIN_SHIFT                     6  /* EQ2_B2_GAIN - [10:6] */
+#define WM5100_EQ2_B2_GAIN_WIDTH                     5  /* EQ2_B2_GAIN - [10:6] */
+#define WM5100_EQ2_B3_GAIN_MASK                 0x003E  /* EQ2_B3_GAIN - [5:1] */
+#define WM5100_EQ2_B3_GAIN_SHIFT                     1  /* EQ2_B3_GAIN - [5:1] */
+#define WM5100_EQ2_B3_GAIN_WIDTH                     5  /* EQ2_B3_GAIN - [5:1] */
+#define WM5100_EQ2_ENA                          0x0001  /* EQ2_ENA */
+#define WM5100_EQ2_ENA_MASK                     0x0001  /* EQ2_ENA */
+#define WM5100_EQ2_ENA_SHIFT                         0  /* EQ2_ENA */
+#define WM5100_EQ2_ENA_WIDTH                         1  /* EQ2_ENA */
+
+/*
+ * R3623 (0xE27) - EQ2_2
+ */
+#define WM5100_EQ2_B4_GAIN_MASK                 0xF800  /* EQ2_B4_GAIN - [15:11] */
+#define WM5100_EQ2_B4_GAIN_SHIFT                    11  /* EQ2_B4_GAIN - [15:11] */
+#define WM5100_EQ2_B4_GAIN_WIDTH                     5  /* EQ2_B4_GAIN - [15:11] */
+#define WM5100_EQ2_B5_GAIN_MASK                 0x07C0  /* EQ2_B5_GAIN - [10:6] */
+#define WM5100_EQ2_B5_GAIN_SHIFT                     6  /* EQ2_B5_GAIN - [10:6] */
+#define WM5100_EQ2_B5_GAIN_WIDTH                     5  /* EQ2_B5_GAIN - [10:6] */
+
+/*
+ * R3624 (0xE28) - EQ2_3
+ */
+#define WM5100_EQ2_B1_A_MASK                    0xFFFF  /* EQ2_B1_A - [15:0] */
+#define WM5100_EQ2_B1_A_SHIFT                        0  /* EQ2_B1_A - [15:0] */
+#define WM5100_EQ2_B1_A_WIDTH                       16  /* EQ2_B1_A - [15:0] */
+
+/*
+ * R3625 (0xE29) - EQ2_4
+ */
+#define WM5100_EQ2_B1_B_MASK                    0xFFFF  /* EQ2_B1_B - [15:0] */
+#define WM5100_EQ2_B1_B_SHIFT                        0  /* EQ2_B1_B - [15:0] */
+#define WM5100_EQ2_B1_B_WIDTH                       16  /* EQ2_B1_B - [15:0] */
+
+/*
+ * R3626 (0xE2A) - EQ2_5
+ */
+#define WM5100_EQ2_B1_PG_MASK                   0xFFFF  /* EQ2_B1_PG - [15:0] */
+#define WM5100_EQ2_B1_PG_SHIFT                       0  /* EQ2_B1_PG - [15:0] */
+#define WM5100_EQ2_B1_PG_WIDTH                      16  /* EQ2_B1_PG - [15:0] */
+
+/*
+ * R3627 (0xE2B) - EQ2_6
+ */
+#define WM5100_EQ2_B2_A_MASK                    0xFFFF  /* EQ2_B2_A - [15:0] */
+#define WM5100_EQ2_B2_A_SHIFT                        0  /* EQ2_B2_A - [15:0] */
+#define WM5100_EQ2_B2_A_WIDTH                       16  /* EQ2_B2_A - [15:0] */
+
+/*
+ * R3628 (0xE2C) - EQ2_7
+ */
+#define WM5100_EQ2_B2_B_MASK                    0xFFFF  /* EQ2_B2_B - [15:0] */
+#define WM5100_EQ2_B2_B_SHIFT                        0  /* EQ2_B2_B - [15:0] */
+#define WM5100_EQ2_B2_B_WIDTH                       16  /* EQ2_B2_B - [15:0] */
+
+/*
+ * R3629 (0xE2D) - EQ2_8
+ */
+#define WM5100_EQ2_B2_C_MASK                    0xFFFF  /* EQ2_B2_C - [15:0] */
+#define WM5100_EQ2_B2_C_SHIFT                        0  /* EQ2_B2_C - [15:0] */
+#define WM5100_EQ2_B2_C_WIDTH                       16  /* EQ2_B2_C - [15:0] */
+
+/*
+ * R3630 (0xE2E) - EQ2_9
+ */
+#define WM5100_EQ2_B2_PG_MASK                   0xFFFF  /* EQ2_B2_PG - [15:0] */
+#define WM5100_EQ2_B2_PG_SHIFT                       0  /* EQ2_B2_PG - [15:0] */
+#define WM5100_EQ2_B2_PG_WIDTH                      16  /* EQ2_B2_PG - [15:0] */
+
+/*
+ * R3631 (0xE2F) - EQ2_10
+ */
+#define WM5100_EQ2_B3_A_MASK                    0xFFFF  /* EQ2_B3_A - [15:0] */
+#define WM5100_EQ2_B3_A_SHIFT                        0  /* EQ2_B3_A - [15:0] */
+#define WM5100_EQ2_B3_A_WIDTH                       16  /* EQ2_B3_A - [15:0] */
+
+/*
+ * R3632 (0xE30) - EQ2_11
+ */
+#define WM5100_EQ2_B3_B_MASK                    0xFFFF  /* EQ2_B3_B - [15:0] */
+#define WM5100_EQ2_B3_B_SHIFT                        0  /* EQ2_B3_B - [15:0] */
+#define WM5100_EQ2_B3_B_WIDTH                       16  /* EQ2_B3_B - [15:0] */
+
+/*
+ * R3633 (0xE31) - EQ2_12
+ */
+#define WM5100_EQ2_B3_C_MASK                    0xFFFF  /* EQ2_B3_C - [15:0] */
+#define WM5100_EQ2_B3_C_SHIFT                        0  /* EQ2_B3_C - [15:0] */
+#define WM5100_EQ2_B3_C_WIDTH                       16  /* EQ2_B3_C - [15:0] */
+
+/*
+ * R3634 (0xE32) - EQ2_13
+ */
+#define WM5100_EQ2_B3_PG_MASK                   0xFFFF  /* EQ2_B3_PG - [15:0] */
+#define WM5100_EQ2_B3_PG_SHIFT                       0  /* EQ2_B3_PG - [15:0] */
+#define WM5100_EQ2_B3_PG_WIDTH                      16  /* EQ2_B3_PG - [15:0] */
+
+/*
+ * R3635 (0xE33) - EQ2_14
+ */
+#define WM5100_EQ2_B4_A_MASK                    0xFFFF  /* EQ2_B4_A - [15:0] */
+#define WM5100_EQ2_B4_A_SHIFT                        0  /* EQ2_B4_A - [15:0] */
+#define WM5100_EQ2_B4_A_WIDTH                       16  /* EQ2_B4_A - [15:0] */
+
+/*
+ * R3636 (0xE34) - EQ2_15
+ */
+#define WM5100_EQ2_B4_B_MASK                    0xFFFF  /* EQ2_B4_B - [15:0] */
+#define WM5100_EQ2_B4_B_SHIFT                        0  /* EQ2_B4_B - [15:0] */
+#define WM5100_EQ2_B4_B_WIDTH                       16  /* EQ2_B4_B - [15:0] */
+
+/*
+ * R3637 (0xE35) - EQ2_16
+ */
+#define WM5100_EQ2_B4_C_MASK                    0xFFFF  /* EQ2_B4_C - [15:0] */
+#define WM5100_EQ2_B4_C_SHIFT                        0  /* EQ2_B4_C - [15:0] */
+#define WM5100_EQ2_B4_C_WIDTH                       16  /* EQ2_B4_C - [15:0] */
+
+/*
+ * R3638 (0xE36) - EQ2_17
+ */
+#define WM5100_EQ2_B4_PG_MASK                   0xFFFF  /* EQ2_B4_PG - [15:0] */
+#define WM5100_EQ2_B4_PG_SHIFT                       0  /* EQ2_B4_PG - [15:0] */
+#define WM5100_EQ2_B4_PG_WIDTH                      16  /* EQ2_B4_PG - [15:0] */
+
+/*
+ * R3639 (0xE37) - EQ2_18
+ */
+#define WM5100_EQ2_B5_A_MASK                    0xFFFF  /* EQ2_B5_A - [15:0] */
+#define WM5100_EQ2_B5_A_SHIFT                        0  /* EQ2_B5_A - [15:0] */
+#define WM5100_EQ2_B5_A_WIDTH                       16  /* EQ2_B5_A - [15:0] */
+
+/*
+ * R3640 (0xE38) - EQ2_19
+ */
+#define WM5100_EQ2_B5_B_MASK                    0xFFFF  /* EQ2_B5_B - [15:0] */
+#define WM5100_EQ2_B5_B_SHIFT                        0  /* EQ2_B5_B - [15:0] */
+#define WM5100_EQ2_B5_B_WIDTH                       16  /* EQ2_B5_B - [15:0] */
+
+/*
+ * R3641 (0xE39) - EQ2_20
+ */
+#define WM5100_EQ2_B5_PG_MASK                   0xFFFF  /* EQ2_B5_PG - [15:0] */
+#define WM5100_EQ2_B5_PG_SHIFT                       0  /* EQ2_B5_PG - [15:0] */
+#define WM5100_EQ2_B5_PG_WIDTH                      16  /* EQ2_B5_PG - [15:0] */
+
+/*
+ * R3644 (0xE3C) - EQ3_1
+ */
+#define WM5100_EQ3_B1_GAIN_MASK                 0xF800  /* EQ3_B1_GAIN - [15:11] */
+#define WM5100_EQ3_B1_GAIN_SHIFT                    11  /* EQ3_B1_GAIN - [15:11] */
+#define WM5100_EQ3_B1_GAIN_WIDTH                     5  /* EQ3_B1_GAIN - [15:11] */
+#define WM5100_EQ3_B2_GAIN_MASK                 0x07C0  /* EQ3_B2_GAIN - [10:6] */
+#define WM5100_EQ3_B2_GAIN_SHIFT                     6  /* EQ3_B2_GAIN - [10:6] */
+#define WM5100_EQ3_B2_GAIN_WIDTH                     5  /* EQ3_B2_GAIN - [10:6] */
+#define WM5100_EQ3_B3_GAIN_MASK                 0x003E  /* EQ3_B3_GAIN - [5:1] */
+#define WM5100_EQ3_B3_GAIN_SHIFT                     1  /* EQ3_B3_GAIN - [5:1] */
+#define WM5100_EQ3_B3_GAIN_WIDTH                     5  /* EQ3_B3_GAIN - [5:1] */
+#define WM5100_EQ3_ENA                          0x0001  /* EQ3_ENA */
+#define WM5100_EQ3_ENA_MASK                     0x0001  /* EQ3_ENA */
+#define WM5100_EQ3_ENA_SHIFT                         0  /* EQ3_ENA */
+#define WM5100_EQ3_ENA_WIDTH                         1  /* EQ3_ENA */
+
+/*
+ * R3645 (0xE3D) - EQ3_2
+ */
+#define WM5100_EQ3_B4_GAIN_MASK                 0xF800  /* EQ3_B4_GAIN - [15:11] */
+#define WM5100_EQ3_B4_GAIN_SHIFT                    11  /* EQ3_B4_GAIN - [15:11] */
+#define WM5100_EQ3_B4_GAIN_WIDTH                     5  /* EQ3_B4_GAIN - [15:11] */
+#define WM5100_EQ3_B5_GAIN_MASK                 0x07C0  /* EQ3_B5_GAIN - [10:6] */
+#define WM5100_EQ3_B5_GAIN_SHIFT                     6  /* EQ3_B5_GAIN - [10:6] */
+#define WM5100_EQ3_B5_GAIN_WIDTH                     5  /* EQ3_B5_GAIN - [10:6] */
+
+/*
+ * R3646 (0xE3E) - EQ3_3
+ */
+#define WM5100_EQ3_B1_A_MASK                    0xFFFF  /* EQ3_B1_A - [15:0] */
+#define WM5100_EQ3_B1_A_SHIFT                        0  /* EQ3_B1_A - [15:0] */
+#define WM5100_EQ3_B1_A_WIDTH                       16  /* EQ3_B1_A - [15:0] */
+
+/*
+ * R3647 (0xE3F) - EQ3_4
+ */
+#define WM5100_EQ3_B1_B_MASK                    0xFFFF  /* EQ3_B1_B - [15:0] */
+#define WM5100_EQ3_B1_B_SHIFT                        0  /* EQ3_B1_B - [15:0] */
+#define WM5100_EQ3_B1_B_WIDTH                       16  /* EQ3_B1_B - [15:0] */
+
+/*
+ * R3648 (0xE40) - EQ3_5
+ */
+#define WM5100_EQ3_B1_PG_MASK                   0xFFFF  /* EQ3_B1_PG - [15:0] */
+#define WM5100_EQ3_B1_PG_SHIFT                       0  /* EQ3_B1_PG - [15:0] */
+#define WM5100_EQ3_B1_PG_WIDTH                      16  /* EQ3_B1_PG - [15:0] */
+
+/*
+ * R3649 (0xE41) - EQ3_6
+ */
+#define WM5100_EQ3_B2_A_MASK                    0xFFFF  /* EQ3_B2_A - [15:0] */
+#define WM5100_EQ3_B2_A_SHIFT                        0  /* EQ3_B2_A - [15:0] */
+#define WM5100_EQ3_B2_A_WIDTH                       16  /* EQ3_B2_A - [15:0] */
+
+/*
+ * R3650 (0xE42) - EQ3_7
+ */
+#define WM5100_EQ3_B2_B_MASK                    0xFFFF  /* EQ3_B2_B - [15:0] */
+#define WM5100_EQ3_B2_B_SHIFT                        0  /* EQ3_B2_B - [15:0] */
+#define WM5100_EQ3_B2_B_WIDTH                       16  /* EQ3_B2_B - [15:0] */
+
+/*
+ * R3651 (0xE43) - EQ3_8
+ */
+#define WM5100_EQ3_B2_C_MASK                    0xFFFF  /* EQ3_B2_C - [15:0] */
+#define WM5100_EQ3_B2_C_SHIFT                        0  /* EQ3_B2_C - [15:0] */
+#define WM5100_EQ3_B2_C_WIDTH                       16  /* EQ3_B2_C - [15:0] */
+
+/*
+ * R3652 (0xE44) - EQ3_9
+ */
+#define WM5100_EQ3_B2_PG_MASK                   0xFFFF  /* EQ3_B2_PG - [15:0] */
+#define WM5100_EQ3_B2_PG_SHIFT                       0  /* EQ3_B2_PG - [15:0] */
+#define WM5100_EQ3_B2_PG_WIDTH                      16  /* EQ3_B2_PG - [15:0] */
+
+/*
+ * R3653 (0xE45) - EQ3_10
+ */
+#define WM5100_EQ3_B3_A_MASK                    0xFFFF  /* EQ3_B3_A - [15:0] */
+#define WM5100_EQ3_B3_A_SHIFT                        0  /* EQ3_B3_A - [15:0] */
+#define WM5100_EQ3_B3_A_WIDTH                       16  /* EQ3_B3_A - [15:0] */
+
+/*
+ * R3654 (0xE46) - EQ3_11
+ */
+#define WM5100_EQ3_B3_B_MASK                    0xFFFF  /* EQ3_B3_B - [15:0] */
+#define WM5100_EQ3_B3_B_SHIFT                        0  /* EQ3_B3_B - [15:0] */
+#define WM5100_EQ3_B3_B_WIDTH                       16  /* EQ3_B3_B - [15:0] */
+
+/*
+ * R3655 (0xE47) - EQ3_12
+ */
+#define WM5100_EQ3_B3_C_MASK                    0xFFFF  /* EQ3_B3_C - [15:0] */
+#define WM5100_EQ3_B3_C_SHIFT                        0  /* EQ3_B3_C - [15:0] */
+#define WM5100_EQ3_B3_C_WIDTH                       16  /* EQ3_B3_C - [15:0] */
+
+/*
+ * R3656 (0xE48) - EQ3_13
+ */
+#define WM5100_EQ3_B3_PG_MASK                   0xFFFF  /* EQ3_B3_PG - [15:0] */
+#define WM5100_EQ3_B3_PG_SHIFT                       0  /* EQ3_B3_PG - [15:0] */
+#define WM5100_EQ3_B3_PG_WIDTH                      16  /* EQ3_B3_PG - [15:0] */
+
+/*
+ * R3657 (0xE49) - EQ3_14
+ */
+#define WM5100_EQ3_B4_A_MASK                    0xFFFF  /* EQ3_B4_A - [15:0] */
+#define WM5100_EQ3_B4_A_SHIFT                        0  /* EQ3_B4_A - [15:0] */
+#define WM5100_EQ3_B4_A_WIDTH                       16  /* EQ3_B4_A - [15:0] */
+
+/*
+ * R3658 (0xE4A) - EQ3_15
+ */
+#define WM5100_EQ3_B4_B_MASK                    0xFFFF  /* EQ3_B4_B - [15:0] */
+#define WM5100_EQ3_B4_B_SHIFT                        0  /* EQ3_B4_B - [15:0] */
+#define WM5100_EQ3_B4_B_WIDTH                       16  /* EQ3_B4_B - [15:0] */
+
+/*
+ * R3659 (0xE4B) - EQ3_16
+ */
+#define WM5100_EQ3_B4_C_MASK                    0xFFFF  /* EQ3_B4_C - [15:0] */
+#define WM5100_EQ3_B4_C_SHIFT                        0  /* EQ3_B4_C - [15:0] */
+#define WM5100_EQ3_B4_C_WIDTH                       16  /* EQ3_B4_C - [15:0] */
+
+/*
+ * R3660 (0xE4C) - EQ3_17
+ */
+#define WM5100_EQ3_B4_PG_MASK                   0xFFFF  /* EQ3_B4_PG - [15:0] */
+#define WM5100_EQ3_B4_PG_SHIFT                       0  /* EQ3_B4_PG - [15:0] */
+#define WM5100_EQ3_B4_PG_WIDTH                      16  /* EQ3_B4_PG - [15:0] */
+
+/*
+ * R3661 (0xE4D) - EQ3_18
+ */
+#define WM5100_EQ3_B5_A_MASK                    0xFFFF  /* EQ3_B5_A - [15:0] */
+#define WM5100_EQ3_B5_A_SHIFT                        0  /* EQ3_B5_A - [15:0] */
+#define WM5100_EQ3_B5_A_WIDTH                       16  /* EQ3_B5_A - [15:0] */
+
+/*
+ * R3662 (0xE4E) - EQ3_19
+ */
+#define WM5100_EQ3_B5_B_MASK                    0xFFFF  /* EQ3_B5_B - [15:0] */
+#define WM5100_EQ3_B5_B_SHIFT                        0  /* EQ3_B5_B - [15:0] */
+#define WM5100_EQ3_B5_B_WIDTH                       16  /* EQ3_B5_B - [15:0] */
+
+/*
+ * R3663 (0xE4F) - EQ3_20
+ */
+#define WM5100_EQ3_B5_PG_MASK                   0xFFFF  /* EQ3_B5_PG - [15:0] */
+#define WM5100_EQ3_B5_PG_SHIFT                       0  /* EQ3_B5_PG - [15:0] */
+#define WM5100_EQ3_B5_PG_WIDTH                      16  /* EQ3_B5_PG - [15:0] */
+
+/*
+ * R3666 (0xE52) - EQ4_1
+ */
+#define WM5100_EQ4_B1_GAIN_MASK                 0xF800  /* EQ4_B1_GAIN - [15:11] */
+#define WM5100_EQ4_B1_GAIN_SHIFT                    11  /* EQ4_B1_GAIN - [15:11] */
+#define WM5100_EQ4_B1_GAIN_WIDTH                     5  /* EQ4_B1_GAIN - [15:11] */
+#define WM5100_EQ4_B2_GAIN_MASK                 0x07C0  /* EQ4_B2_GAIN - [10:6] */
+#define WM5100_EQ4_B2_GAIN_SHIFT                     6  /* EQ4_B2_GAIN - [10:6] */
+#define WM5100_EQ4_B2_GAIN_WIDTH                     5  /* EQ4_B2_GAIN - [10:6] */
+#define WM5100_EQ4_B3_GAIN_MASK                 0x003E  /* EQ4_B3_GAIN - [5:1] */
+#define WM5100_EQ4_B3_GAIN_SHIFT                     1  /* EQ4_B3_GAIN - [5:1] */
+#define WM5100_EQ4_B3_GAIN_WIDTH                     5  /* EQ4_B3_GAIN - [5:1] */
+#define WM5100_EQ4_ENA                          0x0001  /* EQ4_ENA */
+#define WM5100_EQ4_ENA_MASK                     0x0001  /* EQ4_ENA */
+#define WM5100_EQ4_ENA_SHIFT                         0  /* EQ4_ENA */
+#define WM5100_EQ4_ENA_WIDTH                         1  /* EQ4_ENA */
+
+/*
+ * R3667 (0xE53) - EQ4_2
+ */
+#define WM5100_EQ4_B4_GAIN_MASK                 0xF800  /* EQ4_B4_GAIN - [15:11] */
+#define WM5100_EQ4_B4_GAIN_SHIFT                    11  /* EQ4_B4_GAIN - [15:11] */
+#define WM5100_EQ4_B4_GAIN_WIDTH                     5  /* EQ4_B4_GAIN - [15:11] */
+#define WM5100_EQ4_B5_GAIN_MASK                 0x07C0  /* EQ4_B5_GAIN - [10:6] */
+#define WM5100_EQ4_B5_GAIN_SHIFT                     6  /* EQ4_B5_GAIN - [10:6] */
+#define WM5100_EQ4_B5_GAIN_WIDTH                     5  /* EQ4_B5_GAIN - [10:6] */
+
+/*
+ * R3668 (0xE54) - EQ4_3
+ */
+#define WM5100_EQ4_B1_A_MASK                    0xFFFF  /* EQ4_B1_A - [15:0] */
+#define WM5100_EQ4_B1_A_SHIFT                        0  /* EQ4_B1_A - [15:0] */
+#define WM5100_EQ4_B1_A_WIDTH                       16  /* EQ4_B1_A - [15:0] */
+
+/*
+ * R3669 (0xE55) - EQ4_4
+ */
+#define WM5100_EQ4_B1_B_MASK                    0xFFFF  /* EQ4_B1_B - [15:0] */
+#define WM5100_EQ4_B1_B_SHIFT                        0  /* EQ4_B1_B - [15:0] */
+#define WM5100_EQ4_B1_B_WIDTH                       16  /* EQ4_B1_B - [15:0] */
+
+/*
+ * R3670 (0xE56) - EQ4_5
+ */
+#define WM5100_EQ4_B1_PG_MASK                   0xFFFF  /* EQ4_B1_PG - [15:0] */
+#define WM5100_EQ4_B1_PG_SHIFT                       0  /* EQ4_B1_PG - [15:0] */
+#define WM5100_EQ4_B1_PG_WIDTH                      16  /* EQ4_B1_PG - [15:0] */
+
+/*
+ * R3671 (0xE57) - EQ4_6
+ */
+#define WM5100_EQ4_B2_A_MASK                    0xFFFF  /* EQ4_B2_A - [15:0] */
+#define WM5100_EQ4_B2_A_SHIFT                        0  /* EQ4_B2_A - [15:0] */
+#define WM5100_EQ4_B2_A_WIDTH                       16  /* EQ4_B2_A - [15:0] */
+
+/*
+ * R3672 (0xE58) - EQ4_7
+ */
+#define WM5100_EQ4_B2_B_MASK                    0xFFFF  /* EQ4_B2_B - [15:0] */
+#define WM5100_EQ4_B2_B_SHIFT                        0  /* EQ4_B2_B - [15:0] */
+#define WM5100_EQ4_B2_B_WIDTH                       16  /* EQ4_B2_B - [15:0] */
+
+/*
+ * R3673 (0xE59) - EQ4_8
+ */
+#define WM5100_EQ4_B2_C_MASK                    0xFFFF  /* EQ4_B2_C - [15:0] */
+#define WM5100_EQ4_B2_C_SHIFT                        0  /* EQ4_B2_C - [15:0] */
+#define WM5100_EQ4_B2_C_WIDTH                       16  /* EQ4_B2_C - [15:0] */
+
+/*
+ * R3674 (0xE5A) - EQ4_9
+ */
+#define WM5100_EQ4_B2_PG_MASK                   0xFFFF  /* EQ4_B2_PG - [15:0] */
+#define WM5100_EQ4_B2_PG_SHIFT                       0  /* EQ4_B2_PG - [15:0] */
+#define WM5100_EQ4_B2_PG_WIDTH                      16  /* EQ4_B2_PG - [15:0] */
+
+/*
+ * R3675 (0xE5B) - EQ4_10
+ */
+#define WM5100_EQ4_B3_A_MASK                    0xFFFF  /* EQ4_B3_A - [15:0] */
+#define WM5100_EQ4_B3_A_SHIFT                        0  /* EQ4_B3_A - [15:0] */
+#define WM5100_EQ4_B3_A_WIDTH                       16  /* EQ4_B3_A - [15:0] */
+
+/*
+ * R3676 (0xE5C) - EQ4_11
+ */
+#define WM5100_EQ4_B3_B_MASK                    0xFFFF  /* EQ4_B3_B - [15:0] */
+#define WM5100_EQ4_B3_B_SHIFT                        0  /* EQ4_B3_B - [15:0] */
+#define WM5100_EQ4_B3_B_WIDTH                       16  /* EQ4_B3_B - [15:0] */
+
+/*
+ * R3677 (0xE5D) - EQ4_12
+ */
+#define WM5100_EQ4_B3_C_MASK                    0xFFFF  /* EQ4_B3_C - [15:0] */
+#define WM5100_EQ4_B3_C_SHIFT                        0  /* EQ4_B3_C - [15:0] */
+#define WM5100_EQ4_B3_C_WIDTH                       16  /* EQ4_B3_C - [15:0] */
+
+/*
+ * R3678 (0xE5E) - EQ4_13
+ */
+#define WM5100_EQ4_B3_PG_MASK                   0xFFFF  /* EQ4_B3_PG - [15:0] */
+#define WM5100_EQ4_B3_PG_SHIFT                       0  /* EQ4_B3_PG - [15:0] */
+#define WM5100_EQ4_B3_PG_WIDTH                      16  /* EQ4_B3_PG - [15:0] */
+
+/*
+ * R3679 (0xE5F) - EQ4_14
+ */
+#define WM5100_EQ4_B4_A_MASK                    0xFFFF  /* EQ4_B4_A - [15:0] */
+#define WM5100_EQ4_B4_A_SHIFT                        0  /* EQ4_B4_A - [15:0] */
+#define WM5100_EQ4_B4_A_WIDTH                       16  /* EQ4_B4_A - [15:0] */
+
+/*
+ * R3680 (0xE60) - EQ4_15
+ */
+#define WM5100_EQ4_B4_B_MASK                    0xFFFF  /* EQ4_B4_B - [15:0] */
+#define WM5100_EQ4_B4_B_SHIFT                        0  /* EQ4_B4_B - [15:0] */
+#define WM5100_EQ4_B4_B_WIDTH                       16  /* EQ4_B4_B - [15:0] */
+
+/*
+ * R3681 (0xE61) - EQ4_16
+ */
+#define WM5100_EQ4_B4_C_MASK                    0xFFFF  /* EQ4_B4_C - [15:0] */
+#define WM5100_EQ4_B4_C_SHIFT                        0  /* EQ4_B4_C - [15:0] */
+#define WM5100_EQ4_B4_C_WIDTH                       16  /* EQ4_B4_C - [15:0] */
+
+/*
+ * R3682 (0xE62) - EQ4_17
+ */
+#define WM5100_EQ4_B4_PG_MASK                   0xFFFF  /* EQ4_B4_PG - [15:0] */
+#define WM5100_EQ4_B4_PG_SHIFT                       0  /* EQ4_B4_PG - [15:0] */
+#define WM5100_EQ4_B4_PG_WIDTH                      16  /* EQ4_B4_PG - [15:0] */
+
+/*
+ * R3683 (0xE63) - EQ4_18
+ */
+#define WM5100_EQ4_B5_A_MASK                    0xFFFF  /* EQ4_B5_A - [15:0] */
+#define WM5100_EQ4_B5_A_SHIFT                        0  /* EQ4_B5_A - [15:0] */
+#define WM5100_EQ4_B5_A_WIDTH                       16  /* EQ4_B5_A - [15:0] */
+
+/*
+ * R3684 (0xE64) - EQ4_19
+ */
+#define WM5100_EQ4_B5_B_MASK                    0xFFFF  /* EQ4_B5_B - [15:0] */
+#define WM5100_EQ4_B5_B_SHIFT                        0  /* EQ4_B5_B - [15:0] */
+#define WM5100_EQ4_B5_B_WIDTH                       16  /* EQ4_B5_B - [15:0] */
+
+/*
+ * R3685 (0xE65) - EQ4_20
+ */
+#define WM5100_EQ4_B5_PG_MASK                   0xFFFF  /* EQ4_B5_PG - [15:0] */
+#define WM5100_EQ4_B5_PG_SHIFT                       0  /* EQ4_B5_PG - [15:0] */
+#define WM5100_EQ4_B5_PG_WIDTH                      16  /* EQ4_B5_PG - [15:0] */
+
+/*
+ * R3712 (0xE80) - DRC1 ctrl1
+ */
+#define WM5100_DRC_SIG_DET_RMS_MASK             0xF800  /* DRC_SIG_DET_RMS - [15:11] */
+#define WM5100_DRC_SIG_DET_RMS_SHIFT                11  /* DRC_SIG_DET_RMS - [15:11] */
+#define WM5100_DRC_SIG_DET_RMS_WIDTH                 5  /* DRC_SIG_DET_RMS - [15:11] */
+#define WM5100_DRC_SIG_DET_PK_MASK              0x0600  /* DRC_SIG_DET_PK - [10:9] */
+#define WM5100_DRC_SIG_DET_PK_SHIFT                  9  /* DRC_SIG_DET_PK - [10:9] */
+#define WM5100_DRC_SIG_DET_PK_WIDTH                  2  /* DRC_SIG_DET_PK - [10:9] */
+#define WM5100_DRC_NG_ENA                       0x0100  /* DRC_NG_ENA */
+#define WM5100_DRC_NG_ENA_MASK                  0x0100  /* DRC_NG_ENA */
+#define WM5100_DRC_NG_ENA_SHIFT                      8  /* DRC_NG_ENA */
+#define WM5100_DRC_NG_ENA_WIDTH                      1  /* DRC_NG_ENA */
+#define WM5100_DRC_SIG_DET_MODE                 0x0080  /* DRC_SIG_DET_MODE */
+#define WM5100_DRC_SIG_DET_MODE_MASK            0x0080  /* DRC_SIG_DET_MODE */
+#define WM5100_DRC_SIG_DET_MODE_SHIFT                7  /* DRC_SIG_DET_MODE */
+#define WM5100_DRC_SIG_DET_MODE_WIDTH                1  /* DRC_SIG_DET_MODE */
+#define WM5100_DRC_SIG_DET                      0x0040  /* DRC_SIG_DET */
+#define WM5100_DRC_SIG_DET_MASK                 0x0040  /* DRC_SIG_DET */
+#define WM5100_DRC_SIG_DET_SHIFT                     6  /* DRC_SIG_DET */
+#define WM5100_DRC_SIG_DET_WIDTH                     1  /* DRC_SIG_DET */
+#define WM5100_DRC_KNEE2_OP_ENA                 0x0020  /* DRC_KNEE2_OP_ENA */
+#define WM5100_DRC_KNEE2_OP_ENA_MASK            0x0020  /* DRC_KNEE2_OP_ENA */
+#define WM5100_DRC_KNEE2_OP_ENA_SHIFT                5  /* DRC_KNEE2_OP_ENA */
+#define WM5100_DRC_KNEE2_OP_ENA_WIDTH                1  /* DRC_KNEE2_OP_ENA */
+#define WM5100_DRC_QR                           0x0010  /* DRC_QR */
+#define WM5100_DRC_QR_MASK                      0x0010  /* DRC_QR */
+#define WM5100_DRC_QR_SHIFT                          4  /* DRC_QR */
+#define WM5100_DRC_QR_WIDTH                          1  /* DRC_QR */
+#define WM5100_DRC_ANTICLIP                     0x0008  /* DRC_ANTICLIP */
+#define WM5100_DRC_ANTICLIP_MASK                0x0008  /* DRC_ANTICLIP */
+#define WM5100_DRC_ANTICLIP_SHIFT                    3  /* DRC_ANTICLIP */
+#define WM5100_DRC_ANTICLIP_WIDTH                    1  /* DRC_ANTICLIP */
+#define WM5100_DRCL_ENA                         0x0002  /* DRCL_ENA */
+#define WM5100_DRCL_ENA_MASK                    0x0002  /* DRCL_ENA */
+#define WM5100_DRCL_ENA_SHIFT                        1  /* DRCL_ENA */
+#define WM5100_DRCL_ENA_WIDTH                        1  /* DRCL_ENA */
+#define WM5100_DRCR_ENA                         0x0001  /* DRCR_ENA */
+#define WM5100_DRCR_ENA_MASK                    0x0001  /* DRCR_ENA */
+#define WM5100_DRCR_ENA_SHIFT                        0  /* DRCR_ENA */
+#define WM5100_DRCR_ENA_WIDTH                        1  /* DRCR_ENA */
+
+/*
+ * R3713 (0xE81) - DRC1 ctrl2
+ */
+#define WM5100_DRC_ATK_MASK                     0x1E00  /* DRC_ATK - [12:9] */
+#define WM5100_DRC_ATK_SHIFT                         9  /* DRC_ATK - [12:9] */
+#define WM5100_DRC_ATK_WIDTH                         4  /* DRC_ATK - [12:9] */
+#define WM5100_DRC_DCY_MASK                     0x01E0  /* DRC_DCY - [8:5] */
+#define WM5100_DRC_DCY_SHIFT                         5  /* DRC_DCY - [8:5] */
+#define WM5100_DRC_DCY_WIDTH                         4  /* DRC_DCY - [8:5] */
+#define WM5100_DRC_MINGAIN_MASK                 0x001C  /* DRC_MINGAIN - [4:2] */
+#define WM5100_DRC_MINGAIN_SHIFT                     2  /* DRC_MINGAIN - [4:2] */
+#define WM5100_DRC_MINGAIN_WIDTH                     3  /* DRC_MINGAIN - [4:2] */
+#define WM5100_DRC_MAXGAIN_MASK                 0x0003  /* DRC_MAXGAIN - [1:0] */
+#define WM5100_DRC_MAXGAIN_SHIFT                     0  /* DRC_MAXGAIN - [1:0] */
+#define WM5100_DRC_MAXGAIN_WIDTH                     2  /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R3714 (0xE82) - DRC1 ctrl3
+ */
+#define WM5100_DRC_NG_MINGAIN_MASK              0xF000  /* DRC_NG_MINGAIN - [15:12] */
+#define WM5100_DRC_NG_MINGAIN_SHIFT                 12  /* DRC_NG_MINGAIN - [15:12] */
+#define WM5100_DRC_NG_MINGAIN_WIDTH                  4  /* DRC_NG_MINGAIN - [15:12] */
+#define WM5100_DRC_NG_EXP_MASK                  0x0C00  /* DRC_NG_EXP - [11:10] */
+#define WM5100_DRC_NG_EXP_SHIFT                     10  /* DRC_NG_EXP - [11:10] */
+#define WM5100_DRC_NG_EXP_WIDTH                      2  /* DRC_NG_EXP - [11:10] */
+#define WM5100_DRC_QR_THR_MASK                  0x0300  /* DRC_QR_THR - [9:8] */
+#define WM5100_DRC_QR_THR_SHIFT                      8  /* DRC_QR_THR - [9:8] */
+#define WM5100_DRC_QR_THR_WIDTH                      2  /* DRC_QR_THR - [9:8] */
+#define WM5100_DRC_QR_DCY_MASK                  0x00C0  /* DRC_QR_DCY - [7:6] */
+#define WM5100_DRC_QR_DCY_SHIFT                      6  /* DRC_QR_DCY - [7:6] */
+#define WM5100_DRC_QR_DCY_WIDTH                      2  /* DRC_QR_DCY - [7:6] */
+#define WM5100_DRC_HI_COMP_MASK                 0x0038  /* DRC_HI_COMP - [5:3] */
+#define WM5100_DRC_HI_COMP_SHIFT                     3  /* DRC_HI_COMP - [5:3] */
+#define WM5100_DRC_HI_COMP_WIDTH                     3  /* DRC_HI_COMP - [5:3] */
+#define WM5100_DRC_LO_COMP_MASK                 0x0007  /* DRC_LO_COMP - [2:0] */
+#define WM5100_DRC_LO_COMP_SHIFT                     0  /* DRC_LO_COMP - [2:0] */
+#define WM5100_DRC_LO_COMP_WIDTH                     3  /* DRC_LO_COMP - [2:0] */
+
+/*
+ * R3715 (0xE83) - DRC1 ctrl4
+ */
+#define WM5100_DRC_KNEE_IP_MASK                 0x07E0  /* DRC_KNEE_IP - [10:5] */
+#define WM5100_DRC_KNEE_IP_SHIFT                     5  /* DRC_KNEE_IP - [10:5] */
+#define WM5100_DRC_KNEE_IP_WIDTH                     6  /* DRC_KNEE_IP - [10:5] */
+#define WM5100_DRC_KNEE_OP_MASK                 0x001F  /* DRC_KNEE_OP - [4:0] */
+#define WM5100_DRC_KNEE_OP_SHIFT                     0  /* DRC_KNEE_OP - [4:0] */
+#define WM5100_DRC_KNEE_OP_WIDTH                     5  /* DRC_KNEE_OP - [4:0] */
+
+/*
+ * R3716 (0xE84) - DRC1 ctrl5
+ */
+#define WM5100_DRC_KNEE2_IP_MASK                0x03E0  /* DRC_KNEE2_IP - [9:5] */
+#define WM5100_DRC_KNEE2_IP_SHIFT                    5  /* DRC_KNEE2_IP - [9:5] */
+#define WM5100_DRC_KNEE2_IP_WIDTH                    5  /* DRC_KNEE2_IP - [9:5] */
+#define WM5100_DRC_KNEE2_OP_MASK                0x001F  /* DRC_KNEE2_OP - [4:0] */
+#define WM5100_DRC_KNEE2_OP_SHIFT                    0  /* DRC_KNEE2_OP - [4:0] */
+#define WM5100_DRC_KNEE2_OP_WIDTH                    5  /* DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R3776 (0xEC0) - HPLPF1_1
+ */
+#define WM5100_LHPF1_MODE                       0x0002  /* LHPF1_MODE */
+#define WM5100_LHPF1_MODE_MASK                  0x0002  /* LHPF1_MODE */
+#define WM5100_LHPF1_MODE_SHIFT                      1  /* LHPF1_MODE */
+#define WM5100_LHPF1_MODE_WIDTH                      1  /* LHPF1_MODE */
+#define WM5100_LHPF1_ENA                        0x0001  /* LHPF1_ENA */
+#define WM5100_LHPF1_ENA_MASK                   0x0001  /* LHPF1_ENA */
+#define WM5100_LHPF1_ENA_SHIFT                       0  /* LHPF1_ENA */
+#define WM5100_LHPF1_ENA_WIDTH                       1  /* LHPF1_ENA */
+
+/*
+ * R3777 (0xEC1) - HPLPF1_2
+ */
+#define WM5100_LHPF1_COEFF_MASK                 0xFFFF  /* LHPF1_COEFF - [15:0] */
+#define WM5100_LHPF1_COEFF_SHIFT                     0  /* LHPF1_COEFF - [15:0] */
+#define WM5100_LHPF1_COEFF_WIDTH                    16  /* LHPF1_COEFF - [15:0] */
+
+/*
+ * R3780 (0xEC4) - HPLPF2_1
+ */
+#define WM5100_LHPF2_MODE                       0x0002  /* LHPF2_MODE */
+#define WM5100_LHPF2_MODE_MASK                  0x0002  /* LHPF2_MODE */
+#define WM5100_LHPF2_MODE_SHIFT                      1  /* LHPF2_MODE */
+#define WM5100_LHPF2_MODE_WIDTH                      1  /* LHPF2_MODE */
+#define WM5100_LHPF2_ENA                        0x0001  /* LHPF2_ENA */
+#define WM5100_LHPF2_ENA_MASK                   0x0001  /* LHPF2_ENA */
+#define WM5100_LHPF2_ENA_SHIFT                       0  /* LHPF2_ENA */
+#define WM5100_LHPF2_ENA_WIDTH                       1  /* LHPF2_ENA */
+
+/*
+ * R3781 (0xEC5) - HPLPF2_2
+ */
+#define WM5100_LHPF2_COEFF_MASK                 0xFFFF  /* LHPF2_COEFF - [15:0] */
+#define WM5100_LHPF2_COEFF_SHIFT                     0  /* LHPF2_COEFF - [15:0] */
+#define WM5100_LHPF2_COEFF_WIDTH                    16  /* LHPF2_COEFF - [15:0] */
+
+/*
+ * R3784 (0xEC8) - HPLPF3_1
+ */
+#define WM5100_LHPF3_MODE                       0x0002  /* LHPF3_MODE */
+#define WM5100_LHPF3_MODE_MASK                  0x0002  /* LHPF3_MODE */
+#define WM5100_LHPF3_MODE_SHIFT                      1  /* LHPF3_MODE */
+#define WM5100_LHPF3_MODE_WIDTH                      1  /* LHPF3_MODE */
+#define WM5100_LHPF3_ENA                        0x0001  /* LHPF3_ENA */
+#define WM5100_LHPF3_ENA_MASK                   0x0001  /* LHPF3_ENA */
+#define WM5100_LHPF3_ENA_SHIFT                       0  /* LHPF3_ENA */
+#define WM5100_LHPF3_ENA_WIDTH                       1  /* LHPF3_ENA */
+
+/*
+ * R3785 (0xEC9) - HPLPF3_2
+ */
+#define WM5100_LHPF3_COEFF_MASK                 0xFFFF  /* LHPF3_COEFF - [15:0] */
+#define WM5100_LHPF3_COEFF_SHIFT                     0  /* LHPF3_COEFF - [15:0] */
+#define WM5100_LHPF3_COEFF_WIDTH                    16  /* LHPF3_COEFF - [15:0] */
+
+/*
+ * R3788 (0xECC) - HPLPF4_1
+ */
+#define WM5100_LHPF4_MODE                       0x0002  /* LHPF4_MODE */
+#define WM5100_LHPF4_MODE_MASK                  0x0002  /* LHPF4_MODE */
+#define WM5100_LHPF4_MODE_SHIFT                      1  /* LHPF4_MODE */
+#define WM5100_LHPF4_MODE_WIDTH                      1  /* LHPF4_MODE */
+#define WM5100_LHPF4_ENA                        0x0001  /* LHPF4_ENA */
+#define WM5100_LHPF4_ENA_MASK                   0x0001  /* LHPF4_ENA */
+#define WM5100_LHPF4_ENA_SHIFT                       0  /* LHPF4_ENA */
+#define WM5100_LHPF4_ENA_WIDTH                       1  /* LHPF4_ENA */
+
+/*
+ * R3789 (0xECD) - HPLPF4_2
+ */
+#define WM5100_LHPF4_COEFF_MASK                 0xFFFF  /* LHPF4_COEFF - [15:0] */
+#define WM5100_LHPF4_COEFF_SHIFT                     0  /* LHPF4_COEFF - [15:0] */
+#define WM5100_LHPF4_COEFF_WIDTH                    16  /* LHPF4_COEFF - [15:0] */
+
+/*
+ * R4132 (0x1024) - DSP2 Control 30
+ */
+#define WM5100_DSP2_RATE_MASK                   0xC000  /* DSP2_RATE - [15:14] */
+#define WM5100_DSP2_RATE_SHIFT                      14  /* DSP2_RATE - [15:14] */
+#define WM5100_DSP2_RATE_WIDTH                       2  /* DSP2_RATE - [15:14] */
+#define WM5100_DSP2_DBG_CLK_ENA                 0x0008  /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_DBG_CLK_ENA_MASK            0x0008  /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_DBG_CLK_ENA_SHIFT                3  /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_DBG_CLK_ENA_WIDTH                1  /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_SYS_ENA                     0x0004  /* DSP2_SYS_ENA */
+#define WM5100_DSP2_SYS_ENA_MASK                0x0004  /* DSP2_SYS_ENA */
+#define WM5100_DSP2_SYS_ENA_SHIFT                    2  /* DSP2_SYS_ENA */
+#define WM5100_DSP2_SYS_ENA_WIDTH                    1  /* DSP2_SYS_ENA */
+#define WM5100_DSP2_CORE_ENA                    0x0002  /* DSP2_CORE_ENA */
+#define WM5100_DSP2_CORE_ENA_MASK               0x0002  /* DSP2_CORE_ENA */
+#define WM5100_DSP2_CORE_ENA_SHIFT                   1  /* DSP2_CORE_ENA */
+#define WM5100_DSP2_CORE_ENA_WIDTH                   1  /* DSP2_CORE_ENA */
+#define WM5100_DSP2_START                       0x0001  /* DSP2_START */
+#define WM5100_DSP2_START_MASK                  0x0001  /* DSP2_START */
+#define WM5100_DSP2_START_SHIFT                      0  /* DSP2_START */
+#define WM5100_DSP2_START_WIDTH                      1  /* DSP2_START */
+
+/*
+ * R3876 (0xF24) - DSP1 Control 30
+ */
+#define WM5100_DSP1_RATE_MASK                   0xC000  /* DSP1_RATE - [15:14] */
+#define WM5100_DSP1_RATE_SHIFT                      14  /* DSP1_RATE - [15:14] */
+#define WM5100_DSP1_RATE_WIDTH                       2  /* DSP1_RATE - [15:14] */
+#define WM5100_DSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
+#define WM5100_DSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
+#define WM5100_DSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
+#define WM5100_DSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
+#define WM5100_DSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
+#define WM5100_DSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
+#define WM5100_DSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
+#define WM5100_DSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
+#define WM5100_DSP1_START                       0x0001  /* DSP1_START */
+#define WM5100_DSP1_START_MASK                  0x0001  /* DSP1_START */
+#define WM5100_DSP1_START_SHIFT                      0  /* DSP1_START */
+#define WM5100_DSP1_START_WIDTH                      1  /* DSP1_START */
+
+/*
+ * R4388 (0x1124) - DSP3 Control 30
+ */
+#define WM5100_DSP3_RATE_MASK                   0xC000  /* DSP3_RATE - [15:14] */
+#define WM5100_DSP3_RATE_SHIFT                      14  /* DSP3_RATE - [15:14] */
+#define WM5100_DSP3_RATE_WIDTH                       2  /* DSP3_RATE - [15:14] */
+#define WM5100_DSP3_DBG_CLK_ENA                 0x0008  /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_DBG_CLK_ENA_MASK            0x0008  /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_DBG_CLK_ENA_SHIFT                3  /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_DBG_CLK_ENA_WIDTH                1  /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_SYS_ENA                     0x0004  /* DSP3_SYS_ENA */
+#define WM5100_DSP3_SYS_ENA_MASK                0x0004  /* DSP3_SYS_ENA */
+#define WM5100_DSP3_SYS_ENA_SHIFT                    2  /* DSP3_SYS_ENA */
+#define WM5100_DSP3_SYS_ENA_WIDTH                    1  /* DSP3_SYS_ENA */
+#define WM5100_DSP3_CORE_ENA                    0x0002  /* DSP3_CORE_ENA */
+#define WM5100_DSP3_CORE_ENA_MASK               0x0002  /* DSP3_CORE_ENA */
+#define WM5100_DSP3_CORE_ENA_SHIFT                   1  /* DSP3_CORE_ENA */
+#define WM5100_DSP3_CORE_ENA_WIDTH                   1  /* DSP3_CORE_ENA */
+#define WM5100_DSP3_START                       0x0001  /* DSP3_START */
+#define WM5100_DSP3_START_MASK                  0x0001  /* DSP3_START */
+#define WM5100_DSP3_START_SHIFT                      0  /* DSP3_START */
+#define WM5100_DSP3_START_WIDTH                      1  /* DSP3_START */
+
+/*
+ * R16384 (0x4000) - DSP1 DM 0
+ */
+#define WM5100_DSP1_DM_START_1_MASK             0x00FF  /* DSP1_DM_START - [7:0] */
+#define WM5100_DSP1_DM_START_1_SHIFT                 0  /* DSP1_DM_START - [7:0] */
+#define WM5100_DSP1_DM_START_1_WIDTH                 8  /* DSP1_DM_START - [7:0] */
+
+/*
+ * R16385 (0x4001) - DSP1 DM 1
+ */
+#define WM5100_DSP1_DM_START_MASK               0xFFFF  /* DSP1_DM_START - [15:0] */
+#define WM5100_DSP1_DM_START_SHIFT                   0  /* DSP1_DM_START - [15:0] */
+#define WM5100_DSP1_DM_START_WIDTH                  16  /* DSP1_DM_START - [15:0] */
+
+/*
+ * R16386 (0x4002) - DSP1 DM 2
+ */
+#define WM5100_DSP1_DM_1_1_MASK                 0x00FF  /* DSP1_DM_1 - [7:0] */
+#define WM5100_DSP1_DM_1_1_SHIFT                     0  /* DSP1_DM_1 - [7:0] */
+#define WM5100_DSP1_DM_1_1_WIDTH                     8  /* DSP1_DM_1 - [7:0] */
+
+/*
+ * R16387 (0x4003) - DSP1 DM 3
+ */
+#define WM5100_DSP1_DM_1_MASK                   0xFFFF  /* DSP1_DM_1 - [15:0] */
+#define WM5100_DSP1_DM_1_SHIFT                       0  /* DSP1_DM_1 - [15:0] */
+#define WM5100_DSP1_DM_1_WIDTH                      16  /* DSP1_DM_1 - [15:0] */
+
+/*
+ * R16892 (0x41FC) - DSP1 DM 508
+ */
+#define WM5100_DSP1_DM_254_1_MASK               0x00FF  /* DSP1_DM_254 - [7:0] */
+#define WM5100_DSP1_DM_254_1_SHIFT                   0  /* DSP1_DM_254 - [7:0] */
+#define WM5100_DSP1_DM_254_1_WIDTH                   8  /* DSP1_DM_254 - [7:0] */
+
+/*
+ * R16893 (0x41FD) - DSP1 DM 509
+ */
+#define WM5100_DSP1_DM_254_MASK                 0xFFFF  /* DSP1_DM_254 - [15:0] */
+#define WM5100_DSP1_DM_254_SHIFT                     0  /* DSP1_DM_254 - [15:0] */
+#define WM5100_DSP1_DM_254_WIDTH                    16  /* DSP1_DM_254 - [15:0] */
+
+/*
+ * R16894 (0x41FE) - DSP1 DM 510
+ */
+#define WM5100_DSP1_DM_END_1_MASK               0x00FF  /* DSP1_DM_END - [7:0] */
+#define WM5100_DSP1_DM_END_1_SHIFT                   0  /* DSP1_DM_END - [7:0] */
+#define WM5100_DSP1_DM_END_1_WIDTH                   8  /* DSP1_DM_END - [7:0] */
+
+/*
+ * R16895 (0x41FF) - DSP1 DM 511
+ */
+#define WM5100_DSP1_DM_END_MASK                 0xFFFF  /* DSP1_DM_END - [15:0] */
+#define WM5100_DSP1_DM_END_SHIFT                     0  /* DSP1_DM_END - [15:0] */
+#define WM5100_DSP1_DM_END_WIDTH                    16  /* DSP1_DM_END - [15:0] */
+
+/*
+ * R18432 (0x4800) - DSP1 PM 0
+ */
+#define WM5100_DSP1_PM_START_2_MASK             0x00FF  /* DSP1_PM_START - [7:0] */
+#define WM5100_DSP1_PM_START_2_SHIFT                 0  /* DSP1_PM_START - [7:0] */
+#define WM5100_DSP1_PM_START_2_WIDTH                 8  /* DSP1_PM_START - [7:0] */
+
+/*
+ * R18433 (0x4801) - DSP1 PM 1
+ */
+#define WM5100_DSP1_PM_START_1_MASK             0xFFFF  /* DSP1_PM_START - [15:0] */
+#define WM5100_DSP1_PM_START_1_SHIFT                 0  /* DSP1_PM_START - [15:0] */
+#define WM5100_DSP1_PM_START_1_WIDTH                16  /* DSP1_PM_START - [15:0] */
+
+/*
+ * R18434 (0x4802) - DSP1 PM 2
+ */
+#define WM5100_DSP1_PM_START_MASK               0xFFFF  /* DSP1_PM_START - [15:0] */
+#define WM5100_DSP1_PM_START_SHIFT                   0  /* DSP1_PM_START - [15:0] */
+#define WM5100_DSP1_PM_START_WIDTH                  16  /* DSP1_PM_START - [15:0] */
+
+/*
+ * R18435 (0x4803) - DSP1 PM 3
+ */
+#define WM5100_DSP1_PM_1_2_MASK                 0x00FF  /* DSP1_PM_1 - [7:0] */
+#define WM5100_DSP1_PM_1_2_SHIFT                     0  /* DSP1_PM_1 - [7:0] */
+#define WM5100_DSP1_PM_1_2_WIDTH                     8  /* DSP1_PM_1 - [7:0] */
+
+/*
+ * R18436 (0x4804) - DSP1 PM 4
+ */
+#define WM5100_DSP1_PM_1_1_MASK                 0xFFFF  /* DSP1_PM_1 - [15:0] */
+#define WM5100_DSP1_PM_1_1_SHIFT                     0  /* DSP1_PM_1 - [15:0] */
+#define WM5100_DSP1_PM_1_1_WIDTH                    16  /* DSP1_PM_1 - [15:0] */
+
+/*
+ * R18437 (0x4805) - DSP1 PM 5
+ */
+#define WM5100_DSP1_PM_1_MASK                   0xFFFF  /* DSP1_PM_1 - [15:0] */
+#define WM5100_DSP1_PM_1_SHIFT                       0  /* DSP1_PM_1 - [15:0] */
+#define WM5100_DSP1_PM_1_WIDTH                      16  /* DSP1_PM_1 - [15:0] */
+
+/*
+ * R19962 (0x4DFA) - DSP1 PM 1530
+ */
+#define WM5100_DSP1_PM_510_2_MASK               0x00FF  /* DSP1_PM_510 - [7:0] */
+#define WM5100_DSP1_PM_510_2_SHIFT                   0  /* DSP1_PM_510 - [7:0] */
+#define WM5100_DSP1_PM_510_2_WIDTH                   8  /* DSP1_PM_510 - [7:0] */
+
+/*
+ * R19963 (0x4DFB) - DSP1 PM 1531
+ */
+#define WM5100_DSP1_PM_510_1_MASK               0xFFFF  /* DSP1_PM_510 - [15:0] */
+#define WM5100_DSP1_PM_510_1_SHIFT                   0  /* DSP1_PM_510 - [15:0] */
+#define WM5100_DSP1_PM_510_1_WIDTH                  16  /* DSP1_PM_510 - [15:0] */
+
+/*
+ * R19964 (0x4DFC) - DSP1 PM 1532
+ */
+#define WM5100_DSP1_PM_510_MASK                 0xFFFF  /* DSP1_PM_510 - [15:0] */
+#define WM5100_DSP1_PM_510_SHIFT                     0  /* DSP1_PM_510 - [15:0] */
+#define WM5100_DSP1_PM_510_WIDTH                    16  /* DSP1_PM_510 - [15:0] */
+
+/*
+ * R19965 (0x4DFD) - DSP1 PM 1533
+ */
+#define WM5100_DSP1_PM_END_2_MASK               0x00FF  /* DSP1_PM_END - [7:0] */
+#define WM5100_DSP1_PM_END_2_SHIFT                   0  /* DSP1_PM_END - [7:0] */
+#define WM5100_DSP1_PM_END_2_WIDTH                   8  /* DSP1_PM_END - [7:0] */
+
+/*
+ * R19966 (0x4DFE) - DSP1 PM 1534
+ */
+#define WM5100_DSP1_PM_END_1_MASK               0xFFFF  /* DSP1_PM_END - [15:0] */
+#define WM5100_DSP1_PM_END_1_SHIFT                   0  /* DSP1_PM_END - [15:0] */
+#define WM5100_DSP1_PM_END_1_WIDTH                  16  /* DSP1_PM_END - [15:0] */
+
+/*
+ * R19967 (0x4DFF) - DSP1 PM 1535
+ */
+#define WM5100_DSP1_PM_END_MASK                 0xFFFF  /* DSP1_PM_END - [15:0] */
+#define WM5100_DSP1_PM_END_SHIFT                     0  /* DSP1_PM_END - [15:0] */
+#define WM5100_DSP1_PM_END_WIDTH                    16  /* DSP1_PM_END - [15:0] */
+
+/*
+ * R20480 (0x5000) - DSP1 ZM 0
+ */
+#define WM5100_DSP1_ZM_START_1_MASK             0x00FF  /* DSP1_ZM_START - [7:0] */
+#define WM5100_DSP1_ZM_START_1_SHIFT                 0  /* DSP1_ZM_START - [7:0] */
+#define WM5100_DSP1_ZM_START_1_WIDTH                 8  /* DSP1_ZM_START - [7:0] */
+
+/*
+ * R20481 (0x5001) - DSP1 ZM 1
+ */
+#define WM5100_DSP1_ZM_START_MASK               0xFFFF  /* DSP1_ZM_START - [15:0] */
+#define WM5100_DSP1_ZM_START_SHIFT                   0  /* DSP1_ZM_START - [15:0] */
+#define WM5100_DSP1_ZM_START_WIDTH                  16  /* DSP1_ZM_START - [15:0] */
+
+/*
+ * R20482 (0x5002) - DSP1 ZM 2
+ */
+#define WM5100_DSP1_ZM_1_1_MASK                 0x00FF  /* DSP1_ZM_1 - [7:0] */
+#define WM5100_DSP1_ZM_1_1_SHIFT                     0  /* DSP1_ZM_1 - [7:0] */
+#define WM5100_DSP1_ZM_1_1_WIDTH                     8  /* DSP1_ZM_1 - [7:0] */
+
+/*
+ * R20483 (0x5003) - DSP1 ZM 3
+ */
+#define WM5100_DSP1_ZM_1_MASK                   0xFFFF  /* DSP1_ZM_1 - [15:0] */
+#define WM5100_DSP1_ZM_1_SHIFT                       0  /* DSP1_ZM_1 - [15:0] */
+#define WM5100_DSP1_ZM_1_WIDTH                      16  /* DSP1_ZM_1 - [15:0] */
+
+/*
+ * R22524 (0x57FC) - DSP1 ZM 2044
+ */
+#define WM5100_DSP1_ZM_1022_1_MASK              0x00FF  /* DSP1_ZM_1022 - [7:0] */
+#define WM5100_DSP1_ZM_1022_1_SHIFT                  0  /* DSP1_ZM_1022 - [7:0] */
+#define WM5100_DSP1_ZM_1022_1_WIDTH                  8  /* DSP1_ZM_1022 - [7:0] */
+
+/*
+ * R22525 (0x57FD) - DSP1 ZM 2045
+ */
+#define WM5100_DSP1_ZM_1022_MASK                0xFFFF  /* DSP1_ZM_1022 - [15:0] */
+#define WM5100_DSP1_ZM_1022_SHIFT                    0  /* DSP1_ZM_1022 - [15:0] */
+#define WM5100_DSP1_ZM_1022_WIDTH                   16  /* DSP1_ZM_1022 - [15:0] */
+
+/*
+ * R22526 (0x57FE) - DSP1 ZM 2046
+ */
+#define WM5100_DSP1_ZM_END_1_MASK               0x00FF  /* DSP1_ZM_END - [7:0] */
+#define WM5100_DSP1_ZM_END_1_SHIFT                   0  /* DSP1_ZM_END - [7:0] */
+#define WM5100_DSP1_ZM_END_1_WIDTH                   8  /* DSP1_ZM_END - [7:0] */
+
+/*
+ * R22527 (0x57FF) - DSP1 ZM 2047
+ */
+#define WM5100_DSP1_ZM_END_MASK                 0xFFFF  /* DSP1_ZM_END - [15:0] */
+#define WM5100_DSP1_ZM_END_SHIFT                     0  /* DSP1_ZM_END - [15:0] */
+#define WM5100_DSP1_ZM_END_WIDTH                    16  /* DSP1_ZM_END - [15:0] */
+
+/*
+ * R24576 (0x6000) - DSP2 DM 0
+ */
+#define WM5100_DSP2_DM_START_1_MASK             0x00FF  /* DSP2_DM_START - [7:0] */
+#define WM5100_DSP2_DM_START_1_SHIFT                 0  /* DSP2_DM_START - [7:0] */
+#define WM5100_DSP2_DM_START_1_WIDTH                 8  /* DSP2_DM_START - [7:0] */
+
+/*
+ * R24577 (0x6001) - DSP2 DM 1
+ */
+#define WM5100_DSP2_DM_START_MASK               0xFFFF  /* DSP2_DM_START - [15:0] */
+#define WM5100_DSP2_DM_START_SHIFT                   0  /* DSP2_DM_START - [15:0] */
+#define WM5100_DSP2_DM_START_WIDTH                  16  /* DSP2_DM_START - [15:0] */
+
+/*
+ * R24578 (0x6002) - DSP2 DM 2
+ */
+#define WM5100_DSP2_DM_1_1_MASK                 0x00FF  /* DSP2_DM_1 - [7:0] */
+#define WM5100_DSP2_DM_1_1_SHIFT                     0  /* DSP2_DM_1 - [7:0] */
+#define WM5100_DSP2_DM_1_1_WIDTH                     8  /* DSP2_DM_1 - [7:0] */
+
+/*
+ * R24579 (0x6003) - DSP2 DM 3
+ */
+#define WM5100_DSP2_DM_1_MASK                   0xFFFF  /* DSP2_DM_1 - [15:0] */
+#define WM5100_DSP2_DM_1_SHIFT                       0  /* DSP2_DM_1 - [15:0] */
+#define WM5100_DSP2_DM_1_WIDTH                      16  /* DSP2_DM_1 - [15:0] */
+
+/*
+ * R25084 (0x61FC) - DSP2 DM 508
+ */
+#define WM5100_DSP2_DM_254_1_MASK               0x00FF  /* DSP2_DM_254 - [7:0] */
+#define WM5100_DSP2_DM_254_1_SHIFT                   0  /* DSP2_DM_254 - [7:0] */
+#define WM5100_DSP2_DM_254_1_WIDTH                   8  /* DSP2_DM_254 - [7:0] */
+
+/*
+ * R25085 (0x61FD) - DSP2 DM 509
+ */
+#define WM5100_DSP2_DM_254_MASK                 0xFFFF  /* DSP2_DM_254 - [15:0] */
+#define WM5100_DSP2_DM_254_SHIFT                     0  /* DSP2_DM_254 - [15:0] */
+#define WM5100_DSP2_DM_254_WIDTH                    16  /* DSP2_DM_254 - [15:0] */
+
+/*
+ * R25086 (0x61FE) - DSP2 DM 510
+ */
+#define WM5100_DSP2_DM_END_1_MASK               0x00FF  /* DSP2_DM_END - [7:0] */
+#define WM5100_DSP2_DM_END_1_SHIFT                   0  /* DSP2_DM_END - [7:0] */
+#define WM5100_DSP2_DM_END_1_WIDTH                   8  /* DSP2_DM_END - [7:0] */
+
+/*
+ * R25087 (0x61FF) - DSP2 DM 511
+ */
+#define WM5100_DSP2_DM_END_MASK                 0xFFFF  /* DSP2_DM_END - [15:0] */
+#define WM5100_DSP2_DM_END_SHIFT                     0  /* DSP2_DM_END - [15:0] */
+#define WM5100_DSP2_DM_END_WIDTH                    16  /* DSP2_DM_END - [15:0] */
+
+/*
+ * R26624 (0x6800) - DSP2 PM 0
+ */
+#define WM5100_DSP2_PM_START_2_MASK             0x00FF  /* DSP2_PM_START - [7:0] */
+#define WM5100_DSP2_PM_START_2_SHIFT                 0  /* DSP2_PM_START - [7:0] */
+#define WM5100_DSP2_PM_START_2_WIDTH                 8  /* DSP2_PM_START - [7:0] */
+
+/*
+ * R26625 (0x6801) - DSP2 PM 1
+ */
+#define WM5100_DSP2_PM_START_1_MASK             0xFFFF  /* DSP2_PM_START - [15:0] */
+#define WM5100_DSP2_PM_START_1_SHIFT                 0  /* DSP2_PM_START - [15:0] */
+#define WM5100_DSP2_PM_START_1_WIDTH                16  /* DSP2_PM_START - [15:0] */
+
+/*
+ * R26626 (0x6802) - DSP2 PM 2
+ */
+#define WM5100_DSP2_PM_START_MASK               0xFFFF  /* DSP2_PM_START - [15:0] */
+#define WM5100_DSP2_PM_START_SHIFT                   0  /* DSP2_PM_START - [15:0] */
+#define WM5100_DSP2_PM_START_WIDTH                  16  /* DSP2_PM_START - [15:0] */
+
+/*
+ * R26627 (0x6803) - DSP2 PM 3
+ */
+#define WM5100_DSP2_PM_1_2_MASK                 0x00FF  /* DSP2_PM_1 - [7:0] */
+#define WM5100_DSP2_PM_1_2_SHIFT                     0  /* DSP2_PM_1 - [7:0] */
+#define WM5100_DSP2_PM_1_2_WIDTH                     8  /* DSP2_PM_1 - [7:0] */
+
+/*
+ * R26628 (0x6804) - DSP2 PM 4
+ */
+#define WM5100_DSP2_PM_1_1_MASK                 0xFFFF  /* DSP2_PM_1 - [15:0] */
+#define WM5100_DSP2_PM_1_1_SHIFT                     0  /* DSP2_PM_1 - [15:0] */
+#define WM5100_DSP2_PM_1_1_WIDTH                    16  /* DSP2_PM_1 - [15:0] */
+
+/*
+ * R26629 (0x6805) - DSP2 PM 5
+ */
+#define WM5100_DSP2_PM_1_MASK                   0xFFFF  /* DSP2_PM_1 - [15:0] */
+#define WM5100_DSP2_PM_1_SHIFT                       0  /* DSP2_PM_1 - [15:0] */
+#define WM5100_DSP2_PM_1_WIDTH                      16  /* DSP2_PM_1 - [15:0] */
+
+/*
+ * R28154 (0x6DFA) - DSP2 PM 1530
+ */
+#define WM5100_DSP2_PM_510_2_MASK               0x00FF  /* DSP2_PM_510 - [7:0] */
+#define WM5100_DSP2_PM_510_2_SHIFT                   0  /* DSP2_PM_510 - [7:0] */
+#define WM5100_DSP2_PM_510_2_WIDTH                   8  /* DSP2_PM_510 - [7:0] */
+
+/*
+ * R28155 (0x6DFB) - DSP2 PM 1531
+ */
+#define WM5100_DSP2_PM_510_1_MASK               0xFFFF  /* DSP2_PM_510 - [15:0] */
+#define WM5100_DSP2_PM_510_1_SHIFT                   0  /* DSP2_PM_510 - [15:0] */
+#define WM5100_DSP2_PM_510_1_WIDTH                  16  /* DSP2_PM_510 - [15:0] */
+
+/*
+ * R28156 (0x6DFC) - DSP2 PM 1532
+ */
+#define WM5100_DSP2_PM_510_MASK                 0xFFFF  /* DSP2_PM_510 - [15:0] */
+#define WM5100_DSP2_PM_510_SHIFT                     0  /* DSP2_PM_510 - [15:0] */
+#define WM5100_DSP2_PM_510_WIDTH                    16  /* DSP2_PM_510 - [15:0] */
+
+/*
+ * R28157 (0x6DFD) - DSP2 PM 1533
+ */
+#define WM5100_DSP2_PM_END_2_MASK               0x00FF  /* DSP2_PM_END - [7:0] */
+#define WM5100_DSP2_PM_END_2_SHIFT                   0  /* DSP2_PM_END - [7:0] */
+#define WM5100_DSP2_PM_END_2_WIDTH                   8  /* DSP2_PM_END - [7:0] */
+
+/*
+ * R28158 (0x6DFE) - DSP2 PM 1534
+ */
+#define WM5100_DSP2_PM_END_1_MASK               0xFFFF  /* DSP2_PM_END - [15:0] */
+#define WM5100_DSP2_PM_END_1_SHIFT                   0  /* DSP2_PM_END - [15:0] */
+#define WM5100_DSP2_PM_END_1_WIDTH                  16  /* DSP2_PM_END - [15:0] */
+
+/*
+ * R28159 (0x6DFF) - DSP2 PM 1535
+ */
+#define WM5100_DSP2_PM_END_MASK                 0xFFFF  /* DSP2_PM_END - [15:0] */
+#define WM5100_DSP2_PM_END_SHIFT                     0  /* DSP2_PM_END - [15:0] */
+#define WM5100_DSP2_PM_END_WIDTH                    16  /* DSP2_PM_END - [15:0] */
+
+/*
+ * R28672 (0x7000) - DSP2 ZM 0
+ */
+#define WM5100_DSP2_ZM_START_1_MASK             0x00FF  /* DSP2_ZM_START - [7:0] */
+#define WM5100_DSP2_ZM_START_1_SHIFT                 0  /* DSP2_ZM_START - [7:0] */
+#define WM5100_DSP2_ZM_START_1_WIDTH                 8  /* DSP2_ZM_START - [7:0] */
+
+/*
+ * R28673 (0x7001) - DSP2 ZM 1
+ */
+#define WM5100_DSP2_ZM_START_MASK               0xFFFF  /* DSP2_ZM_START - [15:0] */
+#define WM5100_DSP2_ZM_START_SHIFT                   0  /* DSP2_ZM_START - [15:0] */
+#define WM5100_DSP2_ZM_START_WIDTH                  16  /* DSP2_ZM_START - [15:0] */
+
+/*
+ * R28674 (0x7002) - DSP2 ZM 2
+ */
+#define WM5100_DSP2_ZM_1_1_MASK                 0x00FF  /* DSP2_ZM_1 - [7:0] */
+#define WM5100_DSP2_ZM_1_1_SHIFT                     0  /* DSP2_ZM_1 - [7:0] */
+#define WM5100_DSP2_ZM_1_1_WIDTH                     8  /* DSP2_ZM_1 - [7:0] */
+
+/*
+ * R28675 (0x7003) - DSP2 ZM 3
+ */
+#define WM5100_DSP2_ZM_1_MASK                   0xFFFF  /* DSP2_ZM_1 - [15:0] */
+#define WM5100_DSP2_ZM_1_SHIFT                       0  /* DSP2_ZM_1 - [15:0] */
+#define WM5100_DSP2_ZM_1_WIDTH                      16  /* DSP2_ZM_1 - [15:0] */
+
+/*
+ * R30716 (0x77FC) - DSP2 ZM 2044
+ */
+#define WM5100_DSP2_ZM_1022_1_MASK              0x00FF  /* DSP2_ZM_1022 - [7:0] */
+#define WM5100_DSP2_ZM_1022_1_SHIFT                  0  /* DSP2_ZM_1022 - [7:0] */
+#define WM5100_DSP2_ZM_1022_1_WIDTH                  8  /* DSP2_ZM_1022 - [7:0] */
+
+/*
+ * R30717 (0x77FD) - DSP2 ZM 2045
+ */
+#define WM5100_DSP2_ZM_1022_MASK                0xFFFF  /* DSP2_ZM_1022 - [15:0] */
+#define WM5100_DSP2_ZM_1022_SHIFT                    0  /* DSP2_ZM_1022 - [15:0] */
+#define WM5100_DSP2_ZM_1022_WIDTH                   16  /* DSP2_ZM_1022 - [15:0] */
+
+/*
+ * R30718 (0x77FE) - DSP2 ZM 2046
+ */
+#define WM5100_DSP2_ZM_END_1_MASK               0x00FF  /* DSP2_ZM_END - [7:0] */
+#define WM5100_DSP2_ZM_END_1_SHIFT                   0  /* DSP2_ZM_END - [7:0] */
+#define WM5100_DSP2_ZM_END_1_WIDTH                   8  /* DSP2_ZM_END - [7:0] */
+
+/*
+ * R30719 (0x77FF) - DSP2 ZM 2047
+ */
+#define WM5100_DSP2_ZM_END_MASK                 0xFFFF  /* DSP2_ZM_END - [15:0] */
+#define WM5100_DSP2_ZM_END_SHIFT                     0  /* DSP2_ZM_END - [15:0] */
+#define WM5100_DSP2_ZM_END_WIDTH                    16  /* DSP2_ZM_END - [15:0] */
+
+/*
+ * R32768 (0x8000) - DSP3 DM 0
+ */
+#define WM5100_DSP3_DM_START_1_MASK             0x00FF  /* DSP3_DM_START - [7:0] */
+#define WM5100_DSP3_DM_START_1_SHIFT                 0  /* DSP3_DM_START - [7:0] */
+#define WM5100_DSP3_DM_START_1_WIDTH                 8  /* DSP3_DM_START - [7:0] */
+
+/*
+ * R32769 (0x8001) - DSP3 DM 1
+ */
+#define WM5100_DSP3_DM_START_MASK               0xFFFF  /* DSP3_DM_START - [15:0] */
+#define WM5100_DSP3_DM_START_SHIFT                   0  /* DSP3_DM_START - [15:0] */
+#define WM5100_DSP3_DM_START_WIDTH                  16  /* DSP3_DM_START - [15:0] */
+
+/*
+ * R32770 (0x8002) - DSP3 DM 2
+ */
+#define WM5100_DSP3_DM_1_1_MASK                 0x00FF  /* DSP3_DM_1 - [7:0] */
+#define WM5100_DSP3_DM_1_1_SHIFT                     0  /* DSP3_DM_1 - [7:0] */
+#define WM5100_DSP3_DM_1_1_WIDTH                     8  /* DSP3_DM_1 - [7:0] */
+
+/*
+ * R32771 (0x8003) - DSP3 DM 3
+ */
+#define WM5100_DSP3_DM_1_MASK                   0xFFFF  /* DSP3_DM_1 - [15:0] */
+#define WM5100_DSP3_DM_1_SHIFT                       0  /* DSP3_DM_1 - [15:0] */
+#define WM5100_DSP3_DM_1_WIDTH                      16  /* DSP3_DM_1 - [15:0] */
+
+/*
+ * R33276 (0x81FC) - DSP3 DM 508
+ */
+#define WM5100_DSP3_DM_254_1_MASK               0x00FF  /* DSP3_DM_254 - [7:0] */
+#define WM5100_DSP3_DM_254_1_SHIFT                   0  /* DSP3_DM_254 - [7:0] */
+#define WM5100_DSP3_DM_254_1_WIDTH                   8  /* DSP3_DM_254 - [7:0] */
+
+/*
+ * R33277 (0x81FD) - DSP3 DM 509
+ */
+#define WM5100_DSP3_DM_254_MASK                 0xFFFF  /* DSP3_DM_254 - [15:0] */
+#define WM5100_DSP3_DM_254_SHIFT                     0  /* DSP3_DM_254 - [15:0] */
+#define WM5100_DSP3_DM_254_WIDTH                    16  /* DSP3_DM_254 - [15:0] */
+
+/*
+ * R33278 (0x81FE) - DSP3 DM 510
+ */
+#define WM5100_DSP3_DM_END_1_MASK               0x00FF  /* DSP3_DM_END - [7:0] */
+#define WM5100_DSP3_DM_END_1_SHIFT                   0  /* DSP3_DM_END - [7:0] */
+#define WM5100_DSP3_DM_END_1_WIDTH                   8  /* DSP3_DM_END - [7:0] */
+
+/*
+ * R33279 (0x81FF) - DSP3 DM 511
+ */
+#define WM5100_DSP3_DM_END_MASK                 0xFFFF  /* DSP3_DM_END - [15:0] */
+#define WM5100_DSP3_DM_END_SHIFT                     0  /* DSP3_DM_END - [15:0] */
+#define WM5100_DSP3_DM_END_WIDTH                    16  /* DSP3_DM_END - [15:0] */
+
+/*
+ * R34816 (0x8800) - DSP3 PM 0
+ */
+#define WM5100_DSP3_PM_START_2_MASK             0x00FF  /* DSP3_PM_START - [7:0] */
+#define WM5100_DSP3_PM_START_2_SHIFT                 0  /* DSP3_PM_START - [7:0] */
+#define WM5100_DSP3_PM_START_2_WIDTH                 8  /* DSP3_PM_START - [7:0] */
+
+/*
+ * R34817 (0x8801) - DSP3 PM 1
+ */
+#define WM5100_DSP3_PM_START_1_MASK             0xFFFF  /* DSP3_PM_START - [15:0] */
+#define WM5100_DSP3_PM_START_1_SHIFT                 0  /* DSP3_PM_START - [15:0] */
+#define WM5100_DSP3_PM_START_1_WIDTH                16  /* DSP3_PM_START - [15:0] */
+
+/*
+ * R34818 (0x8802) - DSP3 PM 2
+ */
+#define WM5100_DSP3_PM_START_MASK               0xFFFF  /* DSP3_PM_START - [15:0] */
+#define WM5100_DSP3_PM_START_SHIFT                   0  /* DSP3_PM_START - [15:0] */
+#define WM5100_DSP3_PM_START_WIDTH                  16  /* DSP3_PM_START - [15:0] */
+
+/*
+ * R34819 (0x8803) - DSP3 PM 3
+ */
+#define WM5100_DSP3_PM_1_2_MASK                 0x00FF  /* DSP3_PM_1 - [7:0] */
+#define WM5100_DSP3_PM_1_2_SHIFT                     0  /* DSP3_PM_1 - [7:0] */
+#define WM5100_DSP3_PM_1_2_WIDTH                     8  /* DSP3_PM_1 - [7:0] */
+
+/*
+ * R34820 (0x8804) - DSP3 PM 4
+ */
+#define WM5100_DSP3_PM_1_1_MASK                 0xFFFF  /* DSP3_PM_1 - [15:0] */
+#define WM5100_DSP3_PM_1_1_SHIFT                     0  /* DSP3_PM_1 - [15:0] */
+#define WM5100_DSP3_PM_1_1_WIDTH                    16  /* DSP3_PM_1 - [15:0] */
+
+/*
+ * R34821 (0x8805) - DSP3 PM 5
+ */
+#define WM5100_DSP3_PM_1_MASK                   0xFFFF  /* DSP3_PM_1 - [15:0] */
+#define WM5100_DSP3_PM_1_SHIFT                       0  /* DSP3_PM_1 - [15:0] */
+#define WM5100_DSP3_PM_1_WIDTH                      16  /* DSP3_PM_1 - [15:0] */
+
+/*
+ * R36346 (0x8DFA) - DSP3 PM 1530
+ */
+#define WM5100_DSP3_PM_510_2_MASK               0x00FF  /* DSP3_PM_510 - [7:0] */
+#define WM5100_DSP3_PM_510_2_SHIFT                   0  /* DSP3_PM_510 - [7:0] */
+#define WM5100_DSP3_PM_510_2_WIDTH                   8  /* DSP3_PM_510 - [7:0] */
+
+/*
+ * R36347 (0x8DFB) - DSP3 PM 1531
+ */
+#define WM5100_DSP3_PM_510_1_MASK               0xFFFF  /* DSP3_PM_510 - [15:0] */
+#define WM5100_DSP3_PM_510_1_SHIFT                   0  /* DSP3_PM_510 - [15:0] */
+#define WM5100_DSP3_PM_510_1_WIDTH                  16  /* DSP3_PM_510 - [15:0] */
+
+/*
+ * R36348 (0x8DFC) - DSP3 PM 1532
+ */
+#define WM5100_DSP3_PM_510_MASK                 0xFFFF  /* DSP3_PM_510 - [15:0] */
+#define WM5100_DSP3_PM_510_SHIFT                     0  /* DSP3_PM_510 - [15:0] */
+#define WM5100_DSP3_PM_510_WIDTH                    16  /* DSP3_PM_510 - [15:0] */
+
+/*
+ * R36349 (0x8DFD) - DSP3 PM 1533
+ */
+#define WM5100_DSP3_PM_END_2_MASK               0x00FF  /* DSP3_PM_END - [7:0] */
+#define WM5100_DSP3_PM_END_2_SHIFT                   0  /* DSP3_PM_END - [7:0] */
+#define WM5100_DSP3_PM_END_2_WIDTH                   8  /* DSP3_PM_END - [7:0] */
+
+/*
+ * R36350 (0x8DFE) - DSP3 PM 1534
+ */
+#define WM5100_DSP3_PM_END_1_MASK               0xFFFF  /* DSP3_PM_END - [15:0] */
+#define WM5100_DSP3_PM_END_1_SHIFT                   0  /* DSP3_PM_END - [15:0] */
+#define WM5100_DSP3_PM_END_1_WIDTH                  16  /* DSP3_PM_END - [15:0] */
+
+/*
+ * R36351 (0x8DFF) - DSP3 PM 1535
+ */
+#define WM5100_DSP3_PM_END_MASK                 0xFFFF  /* DSP3_PM_END - [15:0] */
+#define WM5100_DSP3_PM_END_SHIFT                     0  /* DSP3_PM_END - [15:0] */
+#define WM5100_DSP3_PM_END_WIDTH                    16  /* DSP3_PM_END - [15:0] */
+
+/*
+ * R36864 (0x9000) - DSP3 ZM 0
+ */
+#define WM5100_DSP3_ZM_START_1_MASK             0x00FF  /* DSP3_ZM_START - [7:0] */
+#define WM5100_DSP3_ZM_START_1_SHIFT                 0  /* DSP3_ZM_START - [7:0] */
+#define WM5100_DSP3_ZM_START_1_WIDTH                 8  /* DSP3_ZM_START - [7:0] */
+
+/*
+ * R36865 (0x9001) - DSP3 ZM 1
+ */
+#define WM5100_DSP3_ZM_START_MASK               0xFFFF  /* DSP3_ZM_START - [15:0] */
+#define WM5100_DSP3_ZM_START_SHIFT                   0  /* DSP3_ZM_START - [15:0] */
+#define WM5100_DSP3_ZM_START_WIDTH                  16  /* DSP3_ZM_START - [15:0] */
+
+/*
+ * R36866 (0x9002) - DSP3 ZM 2
+ */
+#define WM5100_DSP3_ZM_1_1_MASK                 0x00FF  /* DSP3_ZM_1 - [7:0] */
+#define WM5100_DSP3_ZM_1_1_SHIFT                     0  /* DSP3_ZM_1 - [7:0] */
+#define WM5100_DSP3_ZM_1_1_WIDTH                     8  /* DSP3_ZM_1 - [7:0] */
+
+/*
+ * R36867 (0x9003) - DSP3 ZM 3
+ */
+#define WM5100_DSP3_ZM_1_MASK                   0xFFFF  /* DSP3_ZM_1 - [15:0] */
+#define WM5100_DSP3_ZM_1_SHIFT                       0  /* DSP3_ZM_1 - [15:0] */
+#define WM5100_DSP3_ZM_1_WIDTH                      16  /* DSP3_ZM_1 - [15:0] */
+
+/*
+ * R38908 (0x97FC) - DSP3 ZM 2044
+ */
+#define WM5100_DSP3_ZM_1022_1_MASK              0x00FF  /* DSP3_ZM_1022 - [7:0] */
+#define WM5100_DSP3_ZM_1022_1_SHIFT                  0  /* DSP3_ZM_1022 - [7:0] */
+#define WM5100_DSP3_ZM_1022_1_WIDTH                  8  /* DSP3_ZM_1022 - [7:0] */
+
+/*
+ * R38909 (0x97FD) - DSP3 ZM 2045
+ */
+#define WM5100_DSP3_ZM_1022_MASK                0xFFFF  /* DSP3_ZM_1022 - [15:0] */
+#define WM5100_DSP3_ZM_1022_SHIFT                    0  /* DSP3_ZM_1022 - [15:0] */
+#define WM5100_DSP3_ZM_1022_WIDTH                   16  /* DSP3_ZM_1022 - [15:0] */
+
+/*
+ * R38910 (0x97FE) - DSP3 ZM 2046
+ */
+#define WM5100_DSP3_ZM_END_1_MASK               0x00FF  /* DSP3_ZM_END - [7:0] */
+#define WM5100_DSP3_ZM_END_1_SHIFT                   0  /* DSP3_ZM_END - [7:0] */
+#define WM5100_DSP3_ZM_END_1_WIDTH                   8  /* DSP3_ZM_END - [7:0] */
+
+/*
+ * R38911 (0x97FF) - DSP3 ZM 2047
+ */
+#define WM5100_DSP3_ZM_END_MASK                 0xFFFF  /* DSP3_ZM_END - [15:0] */
+#define WM5100_DSP3_ZM_END_SHIFT                     0  /* DSP3_ZM_END - [15:0] */
+#define WM5100_DSP3_ZM_END_WIDTH                    16  /* DSP3_ZM_END - [15:0] */
+
+bool wm5100_readable_register(struct device *dev, unsigned int reg);
+bool wm5100_volatile_register(struct device *dev, unsigned int reg);
+
+extern struct reg_default wm5100_reg_defaults[WM5100_REGISTER_COUNT];
+
+#endif
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
new file mode 100644
index 0000000..7e817e1
--- /dev/null
+++ b/sound/soc/codecs/wm5102.c
@@ -0,0 +1,2164 @@
+/*
+ * wm5102.c  --  WM5102 ALSA SoC Audio driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+#include <asm/unaligned.h>
+
+#include "arizona.h"
+#include "wm5102.h"
+#include "wm_adsp.h"
+
+#define DRV_NAME "wm5102-codec"
+
+struct wm5102_priv {
+	struct arizona_priv core;
+	struct arizona_fll fll[2];
+};
+
+static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
+static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
+
+static const struct wm_adsp_region wm5102_dsp1_regions[] = {
+	{ .type = WMFW_ADSP2_PM, .base = 0x100000 },
+	{ .type = WMFW_ADSP2_ZM, .base = 0x180000 },
+	{ .type = WMFW_ADSP2_XM, .base = 0x190000 },
+	{ .type = WMFW_ADSP2_YM, .base = 0x1a8000 },
+};
+
+static const struct reg_default wm5102_sysclk_reva_patch[] = {
+	{ 0x3000, 0x2225 },
+	{ 0x3001, 0x3a03 },
+	{ 0x3002, 0x0225 },
+	{ 0x3003, 0x0801 },
+	{ 0x3004, 0x6249 },
+	{ 0x3005, 0x0c04 },
+	{ 0x3006, 0x0225 },
+	{ 0x3007, 0x5901 },
+	{ 0x3008, 0xe249 },
+	{ 0x3009, 0x030d },
+	{ 0x300a, 0x0249 },
+	{ 0x300b, 0x2c01 },
+	{ 0x300c, 0xe249 },
+	{ 0x300d, 0x4342 },
+	{ 0x300e, 0xe249 },
+	{ 0x300f, 0x73c0 },
+	{ 0x3010, 0x4249 },
+	{ 0x3011, 0x0c00 },
+	{ 0x3012, 0x0225 },
+	{ 0x3013, 0x1f01 },
+	{ 0x3014, 0x0225 },
+	{ 0x3015, 0x1e01 },
+	{ 0x3016, 0x0225 },
+	{ 0x3017, 0xfa00 },
+	{ 0x3018, 0x0000 },
+	{ 0x3019, 0xf000 },
+	{ 0x301a, 0x0000 },
+	{ 0x301b, 0xf000 },
+	{ 0x301c, 0x0000 },
+	{ 0x301d, 0xf000 },
+	{ 0x301e, 0x0000 },
+	{ 0x301f, 0xf000 },
+	{ 0x3020, 0x0000 },
+	{ 0x3021, 0xf000 },
+	{ 0x3022, 0x0000 },
+	{ 0x3023, 0xf000 },
+	{ 0x3024, 0x0000 },
+	{ 0x3025, 0xf000 },
+	{ 0x3026, 0x0000 },
+	{ 0x3027, 0xf000 },
+	{ 0x3028, 0x0000 },
+	{ 0x3029, 0xf000 },
+	{ 0x302a, 0x0000 },
+	{ 0x302b, 0xf000 },
+	{ 0x302c, 0x0000 },
+	{ 0x302d, 0xf000 },
+	{ 0x302e, 0x0000 },
+	{ 0x302f, 0xf000 },
+	{ 0x3030, 0x0225 },
+	{ 0x3031, 0x1a01 },
+	{ 0x3032, 0x0225 },
+	{ 0x3033, 0x1e00 },
+	{ 0x3034, 0x0225 },
+	{ 0x3035, 0x1f00 },
+	{ 0x3036, 0x6225 },
+	{ 0x3037, 0xf800 },
+	{ 0x3038, 0x0000 },
+	{ 0x3039, 0xf000 },
+	{ 0x303a, 0x0000 },
+	{ 0x303b, 0xf000 },
+	{ 0x303c, 0x0000 },
+	{ 0x303d, 0xf000 },
+	{ 0x303e, 0x0000 },
+	{ 0x303f, 0xf000 },
+	{ 0x3040, 0x2226 },
+	{ 0x3041, 0x3a03 },
+	{ 0x3042, 0x0226 },
+	{ 0x3043, 0x0801 },
+	{ 0x3044, 0x6249 },
+	{ 0x3045, 0x0c06 },
+	{ 0x3046, 0x0226 },
+	{ 0x3047, 0x5901 },
+	{ 0x3048, 0xe249 },
+	{ 0x3049, 0x030d },
+	{ 0x304a, 0x0249 },
+	{ 0x304b, 0x2c01 },
+	{ 0x304c, 0xe249 },
+	{ 0x304d, 0x4342 },
+	{ 0x304e, 0xe249 },
+	{ 0x304f, 0x73c0 },
+	{ 0x3050, 0x4249 },
+	{ 0x3051, 0x0c00 },
+	{ 0x3052, 0x0226 },
+	{ 0x3053, 0x1f01 },
+	{ 0x3054, 0x0226 },
+	{ 0x3055, 0x1e01 },
+	{ 0x3056, 0x0226 },
+	{ 0x3057, 0xfa00 },
+	{ 0x3058, 0x0000 },
+	{ 0x3059, 0xf000 },
+	{ 0x305a, 0x0000 },
+	{ 0x305b, 0xf000 },
+	{ 0x305c, 0x0000 },
+	{ 0x305d, 0xf000 },
+	{ 0x305e, 0x0000 },
+	{ 0x305f, 0xf000 },
+	{ 0x3060, 0x0000 },
+	{ 0x3061, 0xf000 },
+	{ 0x3062, 0x0000 },
+	{ 0x3063, 0xf000 },
+	{ 0x3064, 0x0000 },
+	{ 0x3065, 0xf000 },
+	{ 0x3066, 0x0000 },
+	{ 0x3067, 0xf000 },
+	{ 0x3068, 0x0000 },
+	{ 0x3069, 0xf000 },
+	{ 0x306a, 0x0000 },
+	{ 0x306b, 0xf000 },
+	{ 0x306c, 0x0000 },
+	{ 0x306d, 0xf000 },
+	{ 0x306e, 0x0000 },
+	{ 0x306f, 0xf000 },
+	{ 0x3070, 0x0226 },
+	{ 0x3071, 0x1a01 },
+	{ 0x3072, 0x0226 },
+	{ 0x3073, 0x1e00 },
+	{ 0x3074, 0x0226 },
+	{ 0x3075, 0x1f00 },
+	{ 0x3076, 0x6226 },
+	{ 0x3077, 0xf800 },
+	{ 0x3078, 0x0000 },
+	{ 0x3079, 0xf000 },
+	{ 0x307a, 0x0000 },
+	{ 0x307b, 0xf000 },
+	{ 0x307c, 0x0000 },
+	{ 0x307d, 0xf000 },
+	{ 0x307e, 0x0000 },
+	{ 0x307f, 0xf000 },
+	{ 0x3080, 0x2227 },
+	{ 0x3081, 0x3a03 },
+	{ 0x3082, 0x0227 },
+	{ 0x3083, 0x0801 },
+	{ 0x3084, 0x6255 },
+	{ 0x3085, 0x0c04 },
+	{ 0x3086, 0x0227 },
+	{ 0x3087, 0x5901 },
+	{ 0x3088, 0xe255 },
+	{ 0x3089, 0x030d },
+	{ 0x308a, 0x0255 },
+	{ 0x308b, 0x2c01 },
+	{ 0x308c, 0xe255 },
+	{ 0x308d, 0x4342 },
+	{ 0x308e, 0xe255 },
+	{ 0x308f, 0x73c0 },
+	{ 0x3090, 0x4255 },
+	{ 0x3091, 0x0c00 },
+	{ 0x3092, 0x0227 },
+	{ 0x3093, 0x1f01 },
+	{ 0x3094, 0x0227 },
+	{ 0x3095, 0x1e01 },
+	{ 0x3096, 0x0227 },
+	{ 0x3097, 0xfa00 },
+	{ 0x3098, 0x0000 },
+	{ 0x3099, 0xf000 },
+	{ 0x309a, 0x0000 },
+	{ 0x309b, 0xf000 },
+	{ 0x309c, 0x0000 },
+	{ 0x309d, 0xf000 },
+	{ 0x309e, 0x0000 },
+	{ 0x309f, 0xf000 },
+	{ 0x30a0, 0x0000 },
+	{ 0x30a1, 0xf000 },
+	{ 0x30a2, 0x0000 },
+	{ 0x30a3, 0xf000 },
+	{ 0x30a4, 0x0000 },
+	{ 0x30a5, 0xf000 },
+	{ 0x30a6, 0x0000 },
+	{ 0x30a7, 0xf000 },
+	{ 0x30a8, 0x0000 },
+	{ 0x30a9, 0xf000 },
+	{ 0x30aa, 0x0000 },
+	{ 0x30ab, 0xf000 },
+	{ 0x30ac, 0x0000 },
+	{ 0x30ad, 0xf000 },
+	{ 0x30ae, 0x0000 },
+	{ 0x30af, 0xf000 },
+	{ 0x30b0, 0x0227 },
+	{ 0x30b1, 0x1a01 },
+	{ 0x30b2, 0x0227 },
+	{ 0x30b3, 0x1e00 },
+	{ 0x30b4, 0x0227 },
+	{ 0x30b5, 0x1f00 },
+	{ 0x30b6, 0x6227 },
+	{ 0x30b7, 0xf800 },
+	{ 0x30b8, 0x0000 },
+	{ 0x30b9, 0xf000 },
+	{ 0x30ba, 0x0000 },
+	{ 0x30bb, 0xf000 },
+	{ 0x30bc, 0x0000 },
+	{ 0x30bd, 0xf000 },
+	{ 0x30be, 0x0000 },
+	{ 0x30bf, 0xf000 },
+	{ 0x30c0, 0x2228 },
+	{ 0x30c1, 0x3a03 },
+	{ 0x30c2, 0x0228 },
+	{ 0x30c3, 0x0801 },
+	{ 0x30c4, 0x6255 },
+	{ 0x30c5, 0x0c06 },
+	{ 0x30c6, 0x0228 },
+	{ 0x30c7, 0x5901 },
+	{ 0x30c8, 0xe255 },
+	{ 0x30c9, 0x030d },
+	{ 0x30ca, 0x0255 },
+	{ 0x30cb, 0x2c01 },
+	{ 0x30cc, 0xe255 },
+	{ 0x30cd, 0x4342 },
+	{ 0x30ce, 0xe255 },
+	{ 0x30cf, 0x73c0 },
+	{ 0x30d0, 0x4255 },
+	{ 0x30d1, 0x0c00 },
+	{ 0x30d2, 0x0228 },
+	{ 0x30d3, 0x1f01 },
+	{ 0x30d4, 0x0228 },
+	{ 0x30d5, 0x1e01 },
+	{ 0x30d6, 0x0228 },
+	{ 0x30d7, 0xfa00 },
+	{ 0x30d8, 0x0000 },
+	{ 0x30d9, 0xf000 },
+	{ 0x30da, 0x0000 },
+	{ 0x30db, 0xf000 },
+	{ 0x30dc, 0x0000 },
+	{ 0x30dd, 0xf000 },
+	{ 0x30de, 0x0000 },
+	{ 0x30df, 0xf000 },
+	{ 0x30e0, 0x0000 },
+	{ 0x30e1, 0xf000 },
+	{ 0x30e2, 0x0000 },
+	{ 0x30e3, 0xf000 },
+	{ 0x30e4, 0x0000 },
+	{ 0x30e5, 0xf000 },
+	{ 0x30e6, 0x0000 },
+	{ 0x30e7, 0xf000 },
+	{ 0x30e8, 0x0000 },
+	{ 0x30e9, 0xf000 },
+	{ 0x30ea, 0x0000 },
+	{ 0x30eb, 0xf000 },
+	{ 0x30ec, 0x0000 },
+	{ 0x30ed, 0xf000 },
+	{ 0x30ee, 0x0000 },
+	{ 0x30ef, 0xf000 },
+	{ 0x30f0, 0x0228 },
+	{ 0x30f1, 0x1a01 },
+	{ 0x30f2, 0x0228 },
+	{ 0x30f3, 0x1e00 },
+	{ 0x30f4, 0x0228 },
+	{ 0x30f5, 0x1f00 },
+	{ 0x30f6, 0x6228 },
+	{ 0x30f7, 0xf800 },
+	{ 0x30f8, 0x0000 },
+	{ 0x30f9, 0xf000 },
+	{ 0x30fa, 0x0000 },
+	{ 0x30fb, 0xf000 },
+	{ 0x30fc, 0x0000 },
+	{ 0x30fd, 0xf000 },
+	{ 0x30fe, 0x0000 },
+	{ 0x30ff, 0xf000 },
+	{ 0x3100, 0x222b },
+	{ 0x3101, 0x3a03 },
+	{ 0x3102, 0x222b },
+	{ 0x3103, 0x5803 },
+	{ 0x3104, 0xe26f },
+	{ 0x3105, 0x030d },
+	{ 0x3106, 0x626f },
+	{ 0x3107, 0x2c01 },
+	{ 0x3108, 0xe26f },
+	{ 0x3109, 0x4342 },
+	{ 0x310a, 0xe26f },
+	{ 0x310b, 0x73c0 },
+	{ 0x310c, 0x026f },
+	{ 0x310d, 0x0c00 },
+	{ 0x310e, 0x022b },
+	{ 0x310f, 0x1f01 },
+	{ 0x3110, 0x022b },
+	{ 0x3111, 0x1e01 },
+	{ 0x3112, 0x022b },
+	{ 0x3113, 0xfa00 },
+	{ 0x3114, 0x0000 },
+	{ 0x3115, 0xf000 },
+	{ 0x3116, 0x0000 },
+	{ 0x3117, 0xf000 },
+	{ 0x3118, 0x0000 },
+	{ 0x3119, 0xf000 },
+	{ 0x311a, 0x0000 },
+	{ 0x311b, 0xf000 },
+	{ 0x311c, 0x0000 },
+	{ 0x311d, 0xf000 },
+	{ 0x311e, 0x0000 },
+	{ 0x311f, 0xf000 },
+	{ 0x3120, 0x022b },
+	{ 0x3121, 0x0a01 },
+	{ 0x3122, 0x022b },
+	{ 0x3123, 0x1e00 },
+	{ 0x3124, 0x022b },
+	{ 0x3125, 0x1f00 },
+	{ 0x3126, 0x622b },
+	{ 0x3127, 0xf800 },
+	{ 0x3128, 0x0000 },
+	{ 0x3129, 0xf000 },
+	{ 0x312a, 0x0000 },
+	{ 0x312b, 0xf000 },
+	{ 0x312c, 0x0000 },
+	{ 0x312d, 0xf000 },
+	{ 0x312e, 0x0000 },
+	{ 0x312f, 0xf000 },
+	{ 0x3130, 0x0000 },
+	{ 0x3131, 0xf000 },
+	{ 0x3132, 0x0000 },
+	{ 0x3133, 0xf000 },
+	{ 0x3134, 0x0000 },
+	{ 0x3135, 0xf000 },
+	{ 0x3136, 0x0000 },
+	{ 0x3137, 0xf000 },
+	{ 0x3138, 0x0000 },
+	{ 0x3139, 0xf000 },
+	{ 0x313a, 0x0000 },
+	{ 0x313b, 0xf000 },
+	{ 0x313c, 0x0000 },
+	{ 0x313d, 0xf000 },
+	{ 0x313e, 0x0000 },
+	{ 0x313f, 0xf000 },
+	{ 0x3140, 0x0000 },
+	{ 0x3141, 0xf000 },
+	{ 0x3142, 0x0000 },
+	{ 0x3143, 0xf000 },
+	{ 0x3144, 0x0000 },
+	{ 0x3145, 0xf000 },
+	{ 0x3146, 0x0000 },
+	{ 0x3147, 0xf000 },
+	{ 0x3148, 0x0000 },
+	{ 0x3149, 0xf000 },
+	{ 0x314a, 0x0000 },
+	{ 0x314b, 0xf000 },
+	{ 0x314c, 0x0000 },
+	{ 0x314d, 0xf000 },
+	{ 0x314e, 0x0000 },
+	{ 0x314f, 0xf000 },
+	{ 0x3150, 0x0000 },
+	{ 0x3151, 0xf000 },
+	{ 0x3152, 0x0000 },
+	{ 0x3153, 0xf000 },
+	{ 0x3154, 0x0000 },
+	{ 0x3155, 0xf000 },
+	{ 0x3156, 0x0000 },
+	{ 0x3157, 0xf000 },
+	{ 0x3158, 0x0000 },
+	{ 0x3159, 0xf000 },
+	{ 0x315a, 0x0000 },
+	{ 0x315b, 0xf000 },
+	{ 0x315c, 0x0000 },
+	{ 0x315d, 0xf000 },
+	{ 0x315e, 0x0000 },
+	{ 0x315f, 0xf000 },
+	{ 0x3160, 0x0000 },
+	{ 0x3161, 0xf000 },
+	{ 0x3162, 0x0000 },
+	{ 0x3163, 0xf000 },
+	{ 0x3164, 0x0000 },
+	{ 0x3165, 0xf000 },
+	{ 0x3166, 0x0000 },
+	{ 0x3167, 0xf000 },
+	{ 0x3168, 0x0000 },
+	{ 0x3169, 0xf000 },
+	{ 0x316a, 0x0000 },
+	{ 0x316b, 0xf000 },
+	{ 0x316c, 0x0000 },
+	{ 0x316d, 0xf000 },
+	{ 0x316e, 0x0000 },
+	{ 0x316f, 0xf000 },
+	{ 0x3170, 0x0000 },
+	{ 0x3171, 0xf000 },
+	{ 0x3172, 0x0000 },
+	{ 0x3173, 0xf000 },
+	{ 0x3174, 0x0000 },
+	{ 0x3175, 0xf000 },
+	{ 0x3176, 0x0000 },
+	{ 0x3177, 0xf000 },
+	{ 0x3178, 0x0000 },
+	{ 0x3179, 0xf000 },
+	{ 0x317a, 0x0000 },
+	{ 0x317b, 0xf000 },
+	{ 0x317c, 0x0000 },
+	{ 0x317d, 0xf000 },
+	{ 0x317e, 0x0000 },
+	{ 0x317f, 0xf000 },
+	{ 0x3180, 0x2001 },
+	{ 0x3181, 0xf101 },
+	{ 0x3182, 0x0000 },
+	{ 0x3183, 0xf000 },
+	{ 0x3184, 0x0000 },
+	{ 0x3185, 0xf000 },
+	{ 0x3186, 0x0000 },
+	{ 0x3187, 0xf000 },
+	{ 0x3188, 0x0000 },
+	{ 0x3189, 0xf000 },
+	{ 0x318a, 0x0000 },
+	{ 0x318b, 0xf000 },
+	{ 0x318c, 0x0000 },
+	{ 0x318d, 0xf000 },
+	{ 0x318e, 0x0000 },
+	{ 0x318f, 0xf000 },
+	{ 0x3190, 0x0000 },
+	{ 0x3191, 0xf000 },
+	{ 0x3192, 0x0000 },
+	{ 0x3193, 0xf000 },
+	{ 0x3194, 0x0000 },
+	{ 0x3195, 0xf000 },
+	{ 0x3196, 0x0000 },
+	{ 0x3197, 0xf000 },
+	{ 0x3198, 0x0000 },
+	{ 0x3199, 0xf000 },
+	{ 0x319a, 0x0000 },
+	{ 0x319b, 0xf000 },
+	{ 0x319c, 0x0000 },
+	{ 0x319d, 0xf000 },
+	{ 0x319e, 0x0000 },
+	{ 0x319f, 0xf000 },
+	{ 0x31a0, 0x0000 },
+	{ 0x31a1, 0xf000 },
+	{ 0x31a2, 0x0000 },
+	{ 0x31a3, 0xf000 },
+	{ 0x31a4, 0x0000 },
+	{ 0x31a5, 0xf000 },
+	{ 0x31a6, 0x0000 },
+	{ 0x31a7, 0xf000 },
+	{ 0x31a8, 0x0000 },
+	{ 0x31a9, 0xf000 },
+	{ 0x31aa, 0x0000 },
+	{ 0x31ab, 0xf000 },
+	{ 0x31ac, 0x0000 },
+	{ 0x31ad, 0xf000 },
+	{ 0x31ae, 0x0000 },
+	{ 0x31af, 0xf000 },
+	{ 0x31b0, 0x0000 },
+	{ 0x31b1, 0xf000 },
+	{ 0x31b2, 0x0000 },
+	{ 0x31b3, 0xf000 },
+	{ 0x31b4, 0x0000 },
+	{ 0x31b5, 0xf000 },
+	{ 0x31b6, 0x0000 },
+	{ 0x31b7, 0xf000 },
+	{ 0x31b8, 0x0000 },
+	{ 0x31b9, 0xf000 },
+	{ 0x31ba, 0x0000 },
+	{ 0x31bb, 0xf000 },
+	{ 0x31bc, 0x0000 },
+	{ 0x31bd, 0xf000 },
+	{ 0x31be, 0x0000 },
+	{ 0x31bf, 0xf000 },
+	{ 0x31c0, 0x0000 },
+	{ 0x31c1, 0xf000 },
+	{ 0x31c2, 0x0000 },
+	{ 0x31c3, 0xf000 },
+	{ 0x31c4, 0x0000 },
+	{ 0x31c5, 0xf000 },
+	{ 0x31c6, 0x0000 },
+	{ 0x31c7, 0xf000 },
+	{ 0x31c8, 0x0000 },
+	{ 0x31c9, 0xf000 },
+	{ 0x31ca, 0x0000 },
+	{ 0x31cb, 0xf000 },
+	{ 0x31cc, 0x0000 },
+	{ 0x31cd, 0xf000 },
+	{ 0x31ce, 0x0000 },
+	{ 0x31cf, 0xf000 },
+	{ 0x31d0, 0x0000 },
+	{ 0x31d1, 0xf000 },
+	{ 0x31d2, 0x0000 },
+	{ 0x31d3, 0xf000 },
+	{ 0x31d4, 0x0000 },
+	{ 0x31d5, 0xf000 },
+	{ 0x31d6, 0x0000 },
+	{ 0x31d7, 0xf000 },
+	{ 0x31d8, 0x0000 },
+	{ 0x31d9, 0xf000 },
+	{ 0x31da, 0x0000 },
+	{ 0x31db, 0xf000 },
+	{ 0x31dc, 0x0000 },
+	{ 0x31dd, 0xf000 },
+	{ 0x31de, 0x0000 },
+	{ 0x31df, 0xf000 },
+	{ 0x31e0, 0x0000 },
+	{ 0x31e1, 0xf000 },
+	{ 0x31e2, 0x0000 },
+	{ 0x31e3, 0xf000 },
+	{ 0x31e4, 0x0000 },
+	{ 0x31e5, 0xf000 },
+	{ 0x31e6, 0x0000 },
+	{ 0x31e7, 0xf000 },
+	{ 0x31e8, 0x0000 },
+	{ 0x31e9, 0xf000 },
+	{ 0x31ea, 0x0000 },
+	{ 0x31eb, 0xf000 },
+	{ 0x31ec, 0x0000 },
+	{ 0x31ed, 0xf000 },
+	{ 0x31ee, 0x0000 },
+	{ 0x31ef, 0xf000 },
+	{ 0x31f0, 0x0000 },
+	{ 0x31f1, 0xf000 },
+	{ 0x31f2, 0x0000 },
+	{ 0x31f3, 0xf000 },
+	{ 0x31f4, 0x0000 },
+	{ 0x31f5, 0xf000 },
+	{ 0x31f6, 0x0000 },
+	{ 0x31f7, 0xf000 },
+	{ 0x31f8, 0x0000 },
+	{ 0x31f9, 0xf000 },
+	{ 0x31fa, 0x0000 },
+	{ 0x31fb, 0xf000 },
+	{ 0x31fc, 0x0000 },
+	{ 0x31fd, 0xf000 },
+	{ 0x31fe, 0x0000 },
+	{ 0x31ff, 0xf000 },
+	{ 0x024d, 0xff50 },
+	{ 0x0252, 0xff50 },
+	{ 0x0259, 0x0112 },
+	{ 0x025e, 0x0112 },
+};
+
+static const struct reg_default wm5102_sysclk_revb_patch[] = {
+	{ 0x3081, 0x08FE },
+	{ 0x3083, 0x00ED },
+	{ 0x30C1, 0x08FE },
+	{ 0x30C3, 0x00ED },
+};
+
+static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+	struct regmap *regmap = arizona->regmap;
+	const struct reg_default *patch = NULL;
+	int i, patch_size;
+
+	switch (arizona->rev) {
+	case 0:
+		patch = wm5102_sysclk_reva_patch;
+		patch_size = ARRAY_SIZE(wm5102_sysclk_reva_patch);
+		break;
+	default:
+		patch = wm5102_sysclk_revb_patch;
+		patch_size = ARRAY_SIZE(wm5102_sysclk_revb_patch);
+		break;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (patch)
+			for (i = 0; i < patch_size; i++)
+				regmap_write_async(regmap, patch[i].reg,
+						   patch[i].def);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		break;
+	case SND_SOC_DAPM_PRE_PMU:
+	case SND_SOC_DAPM_POST_PMD:
+		return arizona_clk_ev(w, kcontrol, event);
+	default:
+		return 0;
+	}
+
+	return arizona_dvfs_sysclk_ev(w, kcontrol, event);
+}
+
+static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+	unsigned int v = 0;
+	int ret;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to read SYSCLK state: %d\n", ret);
+			return -EIO;
+		}
+
+		v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
+
+		if (v >= 3) {
+			ret = arizona_dvfs_up(component, ARIZONA_DVFS_ADSP1_RQ);
+			if (ret) {
+				dev_err(component->dev,
+					"Failed to raise DVFS: %d\n", ret);
+				return ret;
+			}
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		ret = arizona_dvfs_down(component, ARIZONA_DVFS_ADSP1_RQ);
+		if (ret)
+			dev_warn(component->dev,
+				 "Failed to lower DVFS: %d\n", ret);
+		break;
+
+	default:
+		break;
+	}
+
+	return wm_adsp2_early_event(w, kcontrol, event, v);
+}
+
+static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+
+	mutex_lock(&arizona->dac_comp_lock);
+	put_unaligned_be16(arizona->dac_comp_coeff,
+			   ucontrol->value.bytes.data);
+	mutex_unlock(&arizona->dac_comp_lock);
+
+	return 0;
+}
+
+static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+
+	mutex_lock(&arizona->dac_comp_lock);
+	memcpy(&arizona->dac_comp_coeff, ucontrol->value.bytes.data,
+	       sizeof(arizona->dac_comp_coeff));
+	arizona->dac_comp_coeff = be16_to_cpu(arizona->dac_comp_coeff);
+	mutex_unlock(&arizona->dac_comp_lock);
+
+	return 0;
+}
+
+static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+
+	mutex_lock(&arizona->dac_comp_lock);
+	ucontrol->value.integer.value[0] = arizona->dac_comp_enabled;
+	mutex_unlock(&arizona->dac_comp_lock);
+
+	return 0;
+}
+
+static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+
+	mutex_lock(&arizona->dac_comp_lock);
+	arizona->dac_comp_enabled = ucontrol->value.integer.value[0];
+	mutex_unlock(&arizona->dac_comp_lock);
+
+	return 0;
+}
+
+static const char * const wm5102_osr_text[] = {
+	"Low power", "Normal", "High performance",
+};
+
+static const unsigned int wm5102_osr_val[] = {
+	0x0, 0x3, 0x5,
+};
+
+static const struct soc_enum wm5102_hpout_osr[] = {
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
+			      ARIZONA_OUT1_OSR_SHIFT, 0x7,
+			      ARRAY_SIZE(wm5102_osr_text),
+			      wm5102_osr_text, wm5102_osr_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
+			      ARIZONA_OUT2_OSR_SHIFT, 0x7,
+			      ARRAY_SIZE(wm5102_osr_text),
+			      wm5102_osr_text, wm5102_osr_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
+			      ARIZONA_OUT3_OSR_SHIFT, 0x7,
+			      ARRAY_SIZE(wm5102_osr_text),
+			      wm5102_osr_text, wm5102_osr_val),
+};
+
+#define WM5102_NG_SRC(name, base) \
+	SOC_SINGLE(name " NG HPOUT1L Switch",  base, 0, 1, 0), \
+	SOC_SINGLE(name " NG HPOUT1R Switch",  base, 1, 1, 0), \
+	SOC_SINGLE(name " NG HPOUT2L Switch",  base, 2, 1, 0), \
+	SOC_SINGLE(name " NG HPOUT2R Switch",  base, 3, 1, 0), \
+	SOC_SINGLE(name " NG EPOUT Switch",    base, 4, 1, 0), \
+	SOC_SINGLE(name " NG SPKOUTL Switch",  base, 6, 1, 0), \
+	SOC_SINGLE(name " NG SPKOUTR Switch",  base, 7, 1, 0), \
+	SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \
+	SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0)
+
+static const struct snd_kcontrol_new wm5102_snd_controls[] = {
+SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL,
+	   ARIZONA_IN1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL,
+	   ARIZONA_IN2_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL,
+	   ARIZONA_IN3_OSR_SHIFT, 1, 0),
+
+SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
+		     ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
+		     ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL,
+		     ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL,
+		     ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL,
+		     ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL,
+		     ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+
+SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
+	       ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
+	       ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
+	       ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R,
+	       ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN3L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L,
+	       ARIZONA_IN3L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN3R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3R,
+	       ARIZONA_IN3R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+
+SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
+SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
+
+ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
+
+ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2),
+SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2),
+SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_EQ_CONTROL("EQ3 Coefficients", ARIZONA_EQ3_2),
+SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B3 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_EQ_CONTROL("EQ4 Coefficients", ARIZONA_EQ4_2),
+SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B3 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B4 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B5 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
+		   ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
+
+ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
+
+ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2),
+ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
+ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
+ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2),
+
+WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
+
+ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
+
+SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
+SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
+SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
+SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
+
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+
+ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR,
+	       ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv),
+
+ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT2L", ARIZONA_OUT2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT2R", ARIZONA_OUT2RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUTL", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L,
+	   ARIZONA_OUT4_OSR_SHIFT, 1, 0),
+SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,
+	   ARIZONA_OUT5_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("HPOUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_MUTE_SHIFT, 1, 1),
+SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	   ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKDAT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("HPOUT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_2L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	       ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+
+SOC_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]),
+SOC_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]),
+SOC_ENUM("EPOUT OSR", wm5102_hpout_osr[2]),
+
+SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,
+	   ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0),
+SOC_DOUBLE("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE,
+	   ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0),
+SOC_SINGLE("EPOUT DRE Switch", ARIZONA_DRE_ENABLE,
+	   ARIZONA_DRE3L_ENA_SHIFT, 1, 0),
+
+SOC_SINGLE("DRE Threshold", ARIZONA_DRE_CONTROL_2,
+	   ARIZONA_DRE_T_LOW_SHIFT, 63, 0),
+
+SOC_SINGLE("DRE Low Level ABS", ARIZONA_DRE_CONTROL_3,
+	   ARIZONA_DRE_LOW_LEVEL_ABS_SHIFT, 15, 0),
+
+SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
+SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
+
+SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
+	   ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
+
+SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
+	   ARIZONA_NGATE_ENA_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
+	       ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
+SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
+
+SND_SOC_BYTES_EXT("Output Compensation Coefficient", 2,
+		  wm5102_out_comp_coeff_get, wm5102_out_comp_coeff_put),
+
+SOC_SINGLE_EXT("Output Compensation Switch", 0, 0, 1, 0,
+	       wm5102_out_comp_switch_get, wm5102_out_comp_switch_put),
+
+WM5102_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L),
+WM5102_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R),
+WM5102_NG_SRC("HPOUT2L", ARIZONA_NOISE_GATE_SELECT_2L),
+WM5102_NG_SRC("HPOUT2R", ARIZONA_NOISE_GATE_SELECT_2R),
+WM5102_NG_SRC("EPOUT", ARIZONA_NOISE_GATE_SELECT_3L),
+WM5102_NG_SRC("SPKOUTL", ARIZONA_NOISE_GATE_SELECT_4L),
+WM5102_NG_SRC("SPKOUTR", ARIZONA_NOISE_GATE_SELECT_4R),
+WM5102_NG_SRC("SPKDAT1L", ARIZONA_NOISE_GATE_SELECT_5L),
+WM5102_NG_SRC("SPKDAT1R", ARIZONA_NOISE_GATE_SELECT_5R),
+
+ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("SLIMTX1", ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX2", ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX3", ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX4", ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
+
+WM_ADSP_FW_CONTROL("DSP1", 0),
+};
+
+ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ4, ARIZONA_EQ4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT2L, ARIZONA_OUT2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT2R, ARIZONA_OUT2RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT3, ARIZONA_OUT3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUTL, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUTR, ARIZONA_OUT4RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDAT1L, ARIZONA_OUT5LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDAT1R, ARIZONA_OUT5RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(SLIMTX1, ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX2, ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX3, ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX4, ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX5, ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX6, ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX7, ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX8, ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP1L, ARIZONA_DSP1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP1R, ARIZONA_DSP1RMIX_INPUT_1_SOURCE);
+
+ARIZONA_DSP_AUX_ENUMS(DSP1, ARIZONA_DSP1AUX1MIX_INPUT_1_SOURCE);
+
+static const char * const wm5102_aec_loopback_texts[] = {
+	"HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "EPOUT",
+	"SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R",
+};
+
+static const unsigned int wm5102_aec_loopback_values[] = {
+	0, 1, 2, 3, 4, 6, 7, 8, 9,
+};
+
+static const struct soc_enum wm5102_aec_loopback =
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
+			      ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+			      ARRAY_SIZE(wm5102_aec_loopback_texts),
+			      wm5102_aec_loopback_texts,
+			      wm5102_aec_loopback_values);
+
+static const struct snd_kcontrol_new wm5102_aec_loopback_mux =
+	SOC_DAPM_ENUM("AEC Loopback", wm5102_aec_loopback);
+
+static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
+		    0, wm5102_sysclk_ev,
+		    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
+		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+		    ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_SIGGEN("NOISE"),
+SND_SOC_DAPM_SIGGEN("HAPTICS"),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2,
+		    ARIZONA_MICB2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3,
+		    ARIZONA_MICB3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR,
+		 ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Mic Mute Mixer", ARIZONA_MIC_NOISE_MIX_CONTROL_1,
+		 ARIZONA_MICMUTE_MIX_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ3", ARIZONA_EQ3_1, ARIZONA_EQ3_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ4", ARIZONA_EQ4_1, ARIZONA_EQ4_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT,
+		 0, NULL, 0),
+SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT,
+		 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ASRC1L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("ASRC1R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1R_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0,
+		     ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0,
+		     ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
+		    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
+		    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX8_ENA_SHIFT, 0),
+
+ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
+
+SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+		 ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &wm5102_aec_loopback_mux),
+
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+		   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+		   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT5R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"),
+ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"),
+ARIZONA_MIXER_WIDGETS(EQ3, "EQ3"),
+ARIZONA_MIXER_WIDGETS(EQ4, "EQ4"),
+
+ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"),
+ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"),
+
+ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
+ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
+ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"),
+ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+ARIZONA_MIXER_WIDGETS(Mic, "Mic"),
+ARIZONA_MIXER_WIDGETS(Noise, "Noise"),
+
+ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"),
+ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"),
+
+ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),
+ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),
+ARIZONA_MIXER_WIDGETS(OUT2L, "HPOUT2L"),
+ARIZONA_MIXER_WIDGETS(OUT2R, "HPOUT2R"),
+ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"),
+ARIZONA_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"),
+ARIZONA_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"),
+ARIZONA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"),
+ARIZONA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"),
+
+ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
+ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
+
+ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
+ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+
+ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
+ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
+
+ARIZONA_MIXER_WIDGETS(SLIMTX1, "SLIMTX1"),
+ARIZONA_MIXER_WIDGETS(SLIMTX2, "SLIMTX2"),
+ARIZONA_MIXER_WIDGETS(SLIMTX3, "SLIMTX3"),
+ARIZONA_MIXER_WIDGETS(SLIMTX4, "SLIMTX4"),
+ARIZONA_MIXER_WIDGETS(SLIMTX5, "SLIMTX5"),
+ARIZONA_MIXER_WIDGETS(SLIMTX6, "SLIMTX6"),
+ARIZONA_MIXER_WIDGETS(SLIMTX7, "SLIMTX7"),
+ARIZONA_MIXER_WIDGETS(SLIMTX8, "SLIMTX8"),
+
+ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"),
+ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
+ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
+ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"),
+
+ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
+
+ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
+ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
+
+ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
+
+ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
+ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
+
+WM_ADSP2("DSP1", 0, wm5102_adsp_power_ev),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("HPOUT2L"),
+SND_SOC_DAPM_OUTPUT("HPOUT2R"),
+SND_SOC_DAPM_OUTPUT("EPOUTN"),
+SND_SOC_DAPM_OUTPUT("EPOUTP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
+SND_SOC_DAPM_OUTPUT("SPKDAT1L"),
+SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
+
+SND_SOC_DAPM_OUTPUT("MICSUPP"),
+};
+
+#define ARIZONA_MIXER_INPUT_ROUTES(name)	\
+	{ name, "Noise Generator", "Noise Generator" }, \
+	{ name, "Tone Generator 1", "Tone Generator 1" }, \
+	{ name, "Tone Generator 2", "Tone Generator 2" }, \
+	{ name, "Haptics", "HAPTICS" }, \
+	{ name, "AEC", "AEC Loopback" }, \
+	{ name, "IN1L", "IN1L PGA" }, \
+	{ name, "IN1R", "IN1R PGA" }, \
+	{ name, "IN2L", "IN2L PGA" }, \
+	{ name, "IN2R", "IN2R PGA" }, \
+	{ name, "IN3L", "IN3L PGA" }, \
+	{ name, "IN3R", "IN3R PGA" }, \
+	{ name, "Mic Mute Mixer", "Mic Mute Mixer" }, \
+	{ name, "AIF1RX1", "AIF1RX1" }, \
+	{ name, "AIF1RX2", "AIF1RX2" }, \
+	{ name, "AIF1RX3", "AIF1RX3" }, \
+	{ name, "AIF1RX4", "AIF1RX4" }, \
+	{ name, "AIF1RX5", "AIF1RX5" }, \
+	{ name, "AIF1RX6", "AIF1RX6" }, \
+	{ name, "AIF1RX7", "AIF1RX7" }, \
+	{ name, "AIF1RX8", "AIF1RX8" }, \
+	{ name, "AIF2RX1", "AIF2RX1" }, \
+	{ name, "AIF2RX2", "AIF2RX2" }, \
+	{ name, "AIF3RX1", "AIF3RX1" }, \
+	{ name, "AIF3RX2", "AIF3RX2" }, \
+	{ name, "SLIMRX1", "SLIMRX1" }, \
+	{ name, "SLIMRX2", "SLIMRX2" }, \
+	{ name, "SLIMRX3", "SLIMRX3" }, \
+	{ name, "SLIMRX4", "SLIMRX4" }, \
+	{ name, "SLIMRX5", "SLIMRX5" }, \
+	{ name, "SLIMRX6", "SLIMRX6" }, \
+	{ name, "SLIMRX7", "SLIMRX7" }, \
+	{ name, "SLIMRX8", "SLIMRX8" }, \
+	{ name, "EQ1", "EQ1" }, \
+	{ name, "EQ2", "EQ2" }, \
+	{ name, "EQ3", "EQ3" }, \
+	{ name, "EQ4", "EQ4" }, \
+	{ name, "DRC1L", "DRC1L" }, \
+	{ name, "DRC1R", "DRC1R" }, \
+	{ name, "LHPF1", "LHPF1" }, \
+	{ name, "LHPF2", "LHPF2" }, \
+	{ name, "LHPF3", "LHPF3" }, \
+	{ name, "LHPF4", "LHPF4" }, \
+	{ name, "ASRC1L", "ASRC1L" }, \
+	{ name, "ASRC1R", "ASRC1R" }, \
+	{ name, "ASRC2L", "ASRC2L" }, \
+	{ name, "ASRC2R", "ASRC2R" }, \
+	{ name, "ISRC1DEC1", "ISRC1DEC1" }, \
+	{ name, "ISRC1DEC2", "ISRC1DEC2" }, \
+	{ name, "ISRC1INT1", "ISRC1INT1" }, \
+	{ name, "ISRC1INT2", "ISRC1INT2" }, \
+	{ name, "ISRC2DEC1", "ISRC2DEC1" }, \
+	{ name, "ISRC2DEC2", "ISRC2DEC2" }, \
+	{ name, "ISRC2INT1", "ISRC2INT1" }, \
+	{ name, "ISRC2INT2", "ISRC2INT2" }, \
+	{ name, "DSP1.1", "DSP1" }, \
+	{ name, "DSP1.2", "DSP1" }, \
+	{ name, "DSP1.3", "DSP1" }, \
+	{ name, "DSP1.4", "DSP1" }, \
+	{ name, "DSP1.5", "DSP1" }, \
+	{ name, "DSP1.6", "DSP1" }
+
+static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
+	{ "AIF2 Capture", NULL, "DBVDD2" },
+	{ "AIF2 Playback", NULL, "DBVDD2" },
+
+	{ "AIF3 Capture", NULL, "DBVDD3" },
+	{ "AIF3 Playback", NULL, "DBVDD3" },
+
+	{ "OUT1L", NULL, "CPVDD" },
+	{ "OUT1R", NULL, "CPVDD" },
+	{ "OUT2L", NULL, "CPVDD" },
+	{ "OUT2R", NULL, "CPVDD" },
+	{ "OUT3L", NULL, "CPVDD" },
+
+	{ "OUT4L", NULL, "SPKVDDL" },
+	{ "OUT4R", NULL, "SPKVDDR" },
+
+	{ "OUT1L", NULL, "SYSCLK" },
+	{ "OUT1R", NULL, "SYSCLK" },
+	{ "OUT2L", NULL, "SYSCLK" },
+	{ "OUT2R", NULL, "SYSCLK" },
+	{ "OUT3L", NULL, "SYSCLK" },
+	{ "OUT4L", NULL, "SYSCLK" },
+	{ "OUT4R", NULL, "SYSCLK" },
+	{ "OUT5L", NULL, "SYSCLK" },
+	{ "OUT5R", NULL, "SYSCLK" },
+
+	{ "IN1L", NULL, "SYSCLK" },
+	{ "IN1R", NULL, "SYSCLK" },
+	{ "IN2L", NULL, "SYSCLK" },
+	{ "IN2R", NULL, "SYSCLK" },
+	{ "IN3L", NULL, "SYSCLK" },
+	{ "IN3R", NULL, "SYSCLK" },
+
+	{ "ASRC1L", NULL, "SYSCLK" },
+	{ "ASRC1R", NULL, "SYSCLK" },
+	{ "ASRC2L", NULL, "SYSCLK" },
+	{ "ASRC2R", NULL, "SYSCLK" },
+
+	{ "ASRC1L", NULL, "ASYNCCLK" },
+	{ "ASRC1R", NULL, "ASYNCCLK" },
+	{ "ASRC2L", NULL, "ASYNCCLK" },
+	{ "ASRC2R", NULL, "ASYNCCLK" },
+
+	{ "MICBIAS1", NULL, "MICVDD" },
+	{ "MICBIAS2", NULL, "MICVDD" },
+	{ "MICBIAS3", NULL, "MICVDD" },
+
+	{ "Noise Generator", NULL, "SYSCLK" },
+	{ "Tone Generator 1", NULL, "SYSCLK" },
+	{ "Tone Generator 2", NULL, "SYSCLK" },
+
+	{ "Noise Generator", NULL, "NOISE" },
+	{ "Tone Generator 1", NULL, "TONE" },
+	{ "Tone Generator 2", NULL, "TONE" },
+
+	{ "AIF1 Capture", NULL, "AIF1TX1" },
+	{ "AIF1 Capture", NULL, "AIF1TX2" },
+	{ "AIF1 Capture", NULL, "AIF1TX3" },
+	{ "AIF1 Capture", NULL, "AIF1TX4" },
+	{ "AIF1 Capture", NULL, "AIF1TX5" },
+	{ "AIF1 Capture", NULL, "AIF1TX6" },
+	{ "AIF1 Capture", NULL, "AIF1TX7" },
+	{ "AIF1 Capture", NULL, "AIF1TX8" },
+
+	{ "AIF1RX1", NULL, "AIF1 Playback" },
+	{ "AIF1RX2", NULL, "AIF1 Playback" },
+	{ "AIF1RX3", NULL, "AIF1 Playback" },
+	{ "AIF1RX4", NULL, "AIF1 Playback" },
+	{ "AIF1RX5", NULL, "AIF1 Playback" },
+	{ "AIF1RX6", NULL, "AIF1 Playback" },
+	{ "AIF1RX7", NULL, "AIF1 Playback" },
+	{ "AIF1RX8", NULL, "AIF1 Playback" },
+
+	{ "AIF2 Capture", NULL, "AIF2TX1" },
+	{ "AIF2 Capture", NULL, "AIF2TX2" },
+
+	{ "AIF2RX1", NULL, "AIF2 Playback" },
+	{ "AIF2RX2", NULL, "AIF2 Playback" },
+
+	{ "AIF3 Capture", NULL, "AIF3TX1" },
+	{ "AIF3 Capture", NULL, "AIF3TX2" },
+
+	{ "AIF3RX1", NULL, "AIF3 Playback" },
+	{ "AIF3RX2", NULL, "AIF3 Playback" },
+
+	{ "Slim1 Capture", NULL, "SLIMTX1" },
+	{ "Slim1 Capture", NULL, "SLIMTX2" },
+	{ "Slim1 Capture", NULL, "SLIMTX3" },
+	{ "Slim1 Capture", NULL, "SLIMTX4" },
+
+	{ "SLIMRX1", NULL, "Slim1 Playback" },
+	{ "SLIMRX2", NULL, "Slim1 Playback" },
+	{ "SLIMRX3", NULL, "Slim1 Playback" },
+	{ "SLIMRX4", NULL, "Slim1 Playback" },
+
+	{ "Slim2 Capture", NULL, "SLIMTX5" },
+	{ "Slim2 Capture", NULL, "SLIMTX6" },
+
+	{ "SLIMRX5", NULL, "Slim2 Playback" },
+	{ "SLIMRX6", NULL, "Slim2 Playback" },
+
+	{ "Slim3 Capture", NULL, "SLIMTX7" },
+	{ "Slim3 Capture", NULL, "SLIMTX8" },
+
+	{ "SLIMRX7", NULL, "Slim3 Playback" },
+	{ "SLIMRX8", NULL, "Slim3 Playback" },
+
+	{ "AIF1 Playback", NULL, "SYSCLK" },
+	{ "AIF2 Playback", NULL, "SYSCLK" },
+	{ "AIF3 Playback", NULL, "SYSCLK" },
+	{ "Slim1 Playback", NULL, "SYSCLK" },
+	{ "Slim2 Playback", NULL, "SYSCLK" },
+	{ "Slim3 Playback", NULL, "SYSCLK" },
+
+	{ "AIF1 Capture", NULL, "SYSCLK" },
+	{ "AIF2 Capture", NULL, "SYSCLK" },
+	{ "AIF3 Capture", NULL, "SYSCLK" },
+	{ "Slim1 Capture", NULL, "SYSCLK" },
+	{ "Slim2 Capture", NULL, "SYSCLK" },
+	{ "Slim3 Capture", NULL, "SYSCLK" },
+
+	{ "Audio Trace DSP", NULL, "DSP1" },
+
+	{ "IN1L PGA", NULL, "IN1L" },
+	{ "IN1R PGA", NULL, "IN1R" },
+
+	{ "IN2L PGA", NULL, "IN2L" },
+	{ "IN2R PGA", NULL, "IN2R" },
+
+	{ "IN3L PGA", NULL, "IN3L" },
+	{ "IN3R PGA", NULL, "IN3R" },
+
+	ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
+	ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
+	ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
+	ARIZONA_MIXER_ROUTES("OUT2R", "HPOUT2R"),
+	ARIZONA_MIXER_ROUTES("OUT3L", "EPOUT"),
+
+	ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUTL"),
+	ARIZONA_MIXER_ROUTES("OUT4R", "SPKOUTR"),
+	ARIZONA_MIXER_ROUTES("OUT5L", "SPKDAT1L"),
+	ARIZONA_MIXER_ROUTES("OUT5R", "SPKDAT1R"),
+
+	ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"),
+	ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"),
+
+	ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+	ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+	ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+	ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+	ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+	ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+	ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
+	ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
+
+	ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
+	ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+
+	ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
+	ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
+
+	ARIZONA_MIXER_ROUTES("SLIMTX1", "SLIMTX1"),
+	ARIZONA_MIXER_ROUTES("SLIMTX2", "SLIMTX2"),
+	ARIZONA_MIXER_ROUTES("SLIMTX3", "SLIMTX3"),
+	ARIZONA_MIXER_ROUTES("SLIMTX4", "SLIMTX4"),
+	ARIZONA_MIXER_ROUTES("SLIMTX5", "SLIMTX5"),
+	ARIZONA_MIXER_ROUTES("SLIMTX6", "SLIMTX6"),
+	ARIZONA_MIXER_ROUTES("SLIMTX7", "SLIMTX7"),
+	ARIZONA_MIXER_ROUTES("SLIMTX8", "SLIMTX8"),
+
+	ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
+	ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
+	ARIZONA_MIXER_ROUTES("EQ3", "EQ3"),
+	ARIZONA_MIXER_ROUTES("EQ4", "EQ4"),
+
+	ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"),
+	ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"),
+
+	ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
+	ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
+	ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
+	ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+	ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Noise"),
+	ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Mic"),
+
+	ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"),
+	ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"),
+	ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
+	ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
+
+	ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+	ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+
+	ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+
+	ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+	ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+
+	ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+
+	ARIZONA_DSP_ROUTES("DSP1"),
+
+	{ "AEC Loopback", "HPOUT1L", "OUT1L" },
+	{ "AEC Loopback", "HPOUT1R", "OUT1R" },
+	{ "HPOUT1L", NULL, "OUT1L" },
+	{ "HPOUT1R", NULL, "OUT1R" },
+
+	{ "AEC Loopback", "HPOUT2L", "OUT2L" },
+	{ "AEC Loopback", "HPOUT2R", "OUT2R" },
+	{ "HPOUT2L", NULL, "OUT2L" },
+	{ "HPOUT2R", NULL, "OUT2R" },
+
+	{ "AEC Loopback", "EPOUT", "OUT3L" },
+	{ "EPOUTN", NULL, "OUT3L" },
+	{ "EPOUTP", NULL, "OUT3L" },
+
+	{ "AEC Loopback", "SPKOUTL", "OUT4L" },
+	{ "SPKOUTLN", NULL, "OUT4L" },
+	{ "SPKOUTLP", NULL, "OUT4L" },
+
+	{ "AEC Loopback", "SPKOUTR", "OUT4R" },
+	{ "SPKOUTRN", NULL, "OUT4R" },
+	{ "SPKOUTRP", NULL, "OUT4R" },
+
+	{ "AEC Loopback", "SPKDAT1L", "OUT5L" },
+	{ "AEC Loopback", "SPKDAT1R", "OUT5R" },
+	{ "SPKDAT1L", NULL, "OUT5L" },
+	{ "SPKDAT1R", NULL, "OUT5R" },
+
+	{ "MICSUPP", NULL, "SYSCLK" },
+
+	{ "DRC1 Signal Activity", NULL, "SYSCLK" },
+	{ "DRC1 Signal Activity", NULL, "DRC1L" },
+	{ "DRC1 Signal Activity", NULL, "DRC1R" },
+};
+
+static int wm5102_set_fll(struct snd_soc_component *component, int fll_id,
+			  int source, unsigned int Fref, unsigned int Fout)
+{
+	struct wm5102_priv *wm5102 = snd_soc_component_get_drvdata(component);
+
+	switch (fll_id) {
+	case WM5102_FLL1:
+		return arizona_set_fll(&wm5102->fll[0], source, Fref, Fout);
+	case WM5102_FLL2:
+		return arizona_set_fll(&wm5102->fll[1], source, Fref, Fout);
+	case WM5102_FLL1_REFCLK:
+		return arizona_set_fll_refclk(&wm5102->fll[0], source, Fref,
+					      Fout);
+	case WM5102_FLL2_REFCLK:
+		return arizona_set_fll_refclk(&wm5102->fll[1], source, Fref,
+					      Fout);
+	default:
+		return -EINVAL;
+	}
+}
+
+#define WM5102_RATES SNDRV_PCM_RATE_KNOT
+
+#define WM5102_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm5102_dai[] = {
+	{
+		.name = "wm5102-aif1",
+		.id = 1,
+		.base = ARIZONA_AIF1_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = WM5102_RATES,
+			.formats = WM5102_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 8,
+			 .rates = WM5102_RATES,
+			 .formats = WM5102_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "wm5102-aif2",
+		.id = 2,
+		.base = ARIZONA_AIF2_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM5102_RATES,
+			.formats = WM5102_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM5102_RATES,
+			 .formats = WM5102_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "wm5102-aif3",
+		.id = 3,
+		.base = ARIZONA_AIF3_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM5102_RATES,
+			.formats = WM5102_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF3 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM5102_RATES,
+			 .formats = WM5102_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "wm5102-slim1",
+		.id = 4,
+		.playback = {
+			.stream_name = "Slim1 Playback",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = WM5102_RATES,
+			.formats = WM5102_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "Slim1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 4,
+			 .rates = WM5102_RATES,
+			 .formats = WM5102_FORMATS,
+		 },
+		.ops = &arizona_simple_dai_ops,
+	},
+	{
+		.name = "wm5102-slim2",
+		.id = 5,
+		.playback = {
+			.stream_name = "Slim2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM5102_RATES,
+			.formats = WM5102_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "Slim2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM5102_RATES,
+			 .formats = WM5102_FORMATS,
+		 },
+		.ops = &arizona_simple_dai_ops,
+	},
+	{
+		.name = "wm5102-slim3",
+		.id = 6,
+		.playback = {
+			.stream_name = "Slim3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM5102_RATES,
+			.formats = WM5102_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "Slim3 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM5102_RATES,
+			 .formats = WM5102_FORMATS,
+		 },
+		.ops = &arizona_simple_dai_ops,
+	},
+	{
+		.name = "wm5102-cpu-trace",
+		.capture = {
+			.stream_name = "Audio Trace CPU",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = WM5102_RATES,
+			.formats = WM5102_FORMATS,
+		},
+		.compress_new = snd_soc_new_compress,
+	},
+	{
+		.name = "wm5102-dsp-trace",
+		.capture = {
+			.stream_name = "Audio Trace DSP",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = WM5102_RATES,
+			.formats = WM5102_FORMATS,
+		},
+	},
+};
+
+static int wm5102_open(struct snd_compr_stream *stream)
+{
+	struct snd_soc_pcm_runtime *rtd = stream->private_data;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct wm5102_priv *priv = snd_soc_component_get_drvdata(component);
+
+	return wm_adsp_compr_open(&priv->core.adsp[0], stream);
+}
+
+static irqreturn_t wm5102_adsp2_irq(int irq, void *data)
+{
+	struct wm5102_priv *priv = data;
+	struct arizona *arizona = priv->core.arizona;
+	int ret;
+
+	ret = wm_adsp_compr_handle_irq(&priv->core.adsp[0]);
+	if (ret == -ENODEV) {
+		dev_err(arizona->dev, "Spurious compressed data IRQ\n");
+		return IRQ_NONE;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int wm5102_component_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm5102_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->core.arizona;
+	int ret;
+
+	snd_soc_component_init_regmap(component, arizona->regmap);
+
+	ret = wm_adsp2_component_probe(&priv->core.adsp[0], component);
+	if (ret)
+		return ret;
+
+	ret = snd_soc_add_component_controls(component,
+					     arizona_adsp2_rate_controls, 1);
+	if (ret)
+		goto err_adsp2_codec_probe;
+
+	ret = arizona_init_spk(component);
+	if (ret < 0)
+		return ret;
+
+	arizona_init_gpio(component);
+
+	snd_soc_component_disable_pin(component, "HAPTICS");
+
+	priv->core.arizona->dapm = dapm;
+
+	return 0;
+
+err_adsp2_codec_probe:
+	wm_adsp2_component_remove(&priv->core.adsp[0], component);
+
+	return ret;
+}
+
+static void wm5102_component_remove(struct snd_soc_component *component)
+{
+	struct wm5102_priv *priv = snd_soc_component_get_drvdata(component);
+
+	wm_adsp2_component_remove(&priv->core.adsp[0], component);
+
+	priv->core.arizona->dapm = NULL;
+}
+
+#define WM5102_DIG_VU 0x0200
+
+static unsigned int wm5102_digital_vu[] = {
+	ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	ARIZONA_DAC_DIGITAL_VOLUME_1R,
+	ARIZONA_DAC_DIGITAL_VOLUME_2L,
+	ARIZONA_DAC_DIGITAL_VOLUME_2R,
+	ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	ARIZONA_DAC_DIGITAL_VOLUME_4R,
+	ARIZONA_DAC_DIGITAL_VOLUME_5L,
+	ARIZONA_DAC_DIGITAL_VOLUME_5R,
+};
+
+static struct snd_compr_ops wm5102_compr_ops = {
+	.open		= wm5102_open,
+	.free		= wm_adsp_compr_free,
+	.set_params	= wm_adsp_compr_set_params,
+	.get_caps	= wm_adsp_compr_get_caps,
+	.trigger	= wm_adsp_compr_trigger,
+	.pointer	= wm_adsp_compr_pointer,
+	.copy		= wm_adsp_compr_copy,
+};
+
+static const struct snd_soc_component_driver soc_component_dev_wm5102 = {
+	.probe			= wm5102_component_probe,
+	.remove			= wm5102_component_remove,
+	.set_sysclk		= arizona_set_sysclk,
+	.set_pll		= wm5102_set_fll,
+	.name			= DRV_NAME,
+	.compr_ops		= &wm5102_compr_ops,
+	.controls		= wm5102_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm5102_snd_controls),
+	.dapm_widgets		= wm5102_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm5102_dapm_widgets),
+	.dapm_routes		= wm5102_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm5102_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm5102_probe(struct platform_device *pdev)
+{
+	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+	struct wm5102_priv *wm5102;
+	int i, ret;
+
+	wm5102 = devm_kzalloc(&pdev->dev, sizeof(struct wm5102_priv),
+			      GFP_KERNEL);
+	if (wm5102 == NULL)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, wm5102);
+
+	if (IS_ENABLED(CONFIG_OF)) {
+		if (!dev_get_platdata(arizona->dev)) {
+			ret = arizona_of_get_audio_pdata(arizona);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	mutex_init(&arizona->dac_comp_lock);
+
+	wm5102->core.arizona = arizona;
+	wm5102->core.num_inputs = 6;
+
+	arizona_init_dvfs(&wm5102->core);
+
+	wm5102->core.adsp[0].part = "wm5102";
+	wm5102->core.adsp[0].num = 1;
+	wm5102->core.adsp[0].type = WMFW_ADSP2;
+	wm5102->core.adsp[0].base = ARIZONA_DSP1_CONTROL_1;
+	wm5102->core.adsp[0].dev = arizona->dev;
+	wm5102->core.adsp[0].regmap = arizona->regmap;
+	wm5102->core.adsp[0].mem = wm5102_dsp1_regions;
+	wm5102->core.adsp[0].num_mems = ARRAY_SIZE(wm5102_dsp1_regions);
+
+	ret = wm_adsp2_init(&wm5102->core.adsp[0]);
+	if (ret != 0)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(wm5102->fll); i++)
+		wm5102->fll[i].vco_mult = 1;
+
+	arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK,
+			 &wm5102->fll[0]);
+	arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
+			 &wm5102->fll[1]);
+
+	/* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
+			   ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
+			   ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
+
+	for (i = 0; i < ARRAY_SIZE(wm5102_dai); i++)
+		arizona_init_dai(&wm5102->core, i);
+
+	/* Latch volume update bits */
+	for (i = 0; i < ARRAY_SIZE(wm5102_digital_vu); i++)
+		regmap_update_bits(arizona->regmap, wm5102_digital_vu[i],
+				   WM5102_DIG_VU, WM5102_DIG_VU);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_idle(&pdev->dev);
+
+	ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
+				  "ADSP2 Compressed IRQ", wm5102_adsp2_irq,
+				  wm5102);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret);
+		return ret;
+	}
+
+	ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 1);
+	if (ret != 0)
+		dev_warn(&pdev->dev,
+			 "Failed to set compressed IRQ as a wake source: %d\n",
+			 ret);
+
+	arizona_init_common(arizona);
+
+	ret = arizona_init_vol_limit(arizona);
+	if (ret < 0)
+		goto err_dsp_irq;
+	ret = arizona_init_spk_irqs(arizona);
+	if (ret < 0)
+		goto err_dsp_irq;
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					      &soc_component_dev_wm5102,
+					      wm5102_dai,
+					      ARRAY_SIZE(wm5102_dai));
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
+		goto err_spk_irqs;
+	}
+
+	return ret;
+
+err_spk_irqs:
+	arizona_free_spk_irqs(arizona);
+err_dsp_irq:
+	arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
+	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102);
+
+	return ret;
+}
+
+static int wm5102_remove(struct platform_device *pdev)
+{
+	struct wm5102_priv *wm5102 = platform_get_drvdata(pdev);
+	struct arizona *arizona = wm5102->core.arizona;
+
+	pm_runtime_disable(&pdev->dev);
+
+	wm_adsp2_remove(&wm5102->core.adsp[0]);
+
+	arizona_free_spk_irqs(arizona);
+
+	arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
+	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102);
+
+	return 0;
+}
+
+static struct platform_driver wm5102_codec_driver = {
+	.driver = {
+		.name = "wm5102-codec",
+	},
+	.probe = wm5102_probe,
+	.remove = wm5102_remove,
+};
+
+module_platform_driver(wm5102_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM5102 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm5102-codec");
diff --git a/sound/soc/codecs/wm5102.h b/sound/soc/codecs/wm5102.h
new file mode 100644
index 0000000..adb3804
--- /dev/null
+++ b/sound/soc/codecs/wm5102.h
@@ -0,0 +1,23 @@
+/*
+ * wm5102.h  --  WM5102 ALSA SoC Audio driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM5102_H
+#define _WM5102_H
+
+#include "arizona.h"
+
+#define WM5102_FLL1        1
+#define WM5102_FLL2        2
+#define WM5102_FLL1_REFCLK 3
+#define WM5102_FLL2_REFCLK 4
+
+#endif
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
new file mode 100644
index 0000000..b0789a0
--- /dev/null
+++ b/sound/soc/codecs/wm5110.c
@@ -0,0 +1,2530 @@
+/*
+ * wm5110.c  --  WM5110 ALSA SoC Audio driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+#include "wm_adsp.h"
+#include "wm5110.h"
+
+#define WM5110_NUM_ADSP 4
+
+#define DRV_NAME "wm5110-codec"
+
+struct wm5110_priv {
+	struct arizona_priv core;
+	struct arizona_fll fll[2];
+
+	unsigned int in_value;
+	int in_pre_pending;
+	int in_post_pending;
+
+	unsigned int in_pga_cache[6];
+};
+
+static const struct wm_adsp_region wm5110_dsp1_regions[] = {
+	{ .type = WMFW_ADSP2_PM, .base = 0x100000 },
+	{ .type = WMFW_ADSP2_ZM, .base = 0x180000 },
+	{ .type = WMFW_ADSP2_XM, .base = 0x190000 },
+	{ .type = WMFW_ADSP2_YM, .base = 0x1a8000 },
+};
+
+static const struct wm_adsp_region wm5110_dsp2_regions[] = {
+	{ .type = WMFW_ADSP2_PM, .base = 0x200000 },
+	{ .type = WMFW_ADSP2_ZM, .base = 0x280000 },
+	{ .type = WMFW_ADSP2_XM, .base = 0x290000 },
+	{ .type = WMFW_ADSP2_YM, .base = 0x2a8000 },
+};
+
+static const struct wm_adsp_region wm5110_dsp3_regions[] = {
+	{ .type = WMFW_ADSP2_PM, .base = 0x300000 },
+	{ .type = WMFW_ADSP2_ZM, .base = 0x380000 },
+	{ .type = WMFW_ADSP2_XM, .base = 0x390000 },
+	{ .type = WMFW_ADSP2_YM, .base = 0x3a8000 },
+};
+
+static const struct wm_adsp_region wm5110_dsp4_regions[] = {
+	{ .type = WMFW_ADSP2_PM, .base = 0x400000 },
+	{ .type = WMFW_ADSP2_ZM, .base = 0x480000 },
+	{ .type = WMFW_ADSP2_XM, .base = 0x490000 },
+	{ .type = WMFW_ADSP2_YM, .base = 0x4a8000 },
+};
+
+static const struct wm_adsp_region *wm5110_dsp_regions[] = {
+	wm5110_dsp1_regions,
+	wm5110_dsp2_regions,
+	wm5110_dsp3_regions,
+	wm5110_dsp4_regions,
+};
+
+static const struct reg_default wm5110_sysclk_revd_patch[] = {
+	{ 0x3093, 0x1001 },
+	{ 0x30E3, 0x1301 },
+	{ 0x3133, 0x1201 },
+	{ 0x3183, 0x1501 },
+	{ 0x31D3, 0x1401 },
+	{ 0x0049, 0x01ea },
+	{ 0x004a, 0x01f2 },
+	{ 0x0057, 0x01e7 },
+	{ 0x0058, 0x01fb },
+	{ 0x33ce, 0xc4f5 },
+	{ 0x33cf, 0x1361 },
+	{ 0x33d0, 0x0402 },
+	{ 0x33d1, 0x4700 },
+	{ 0x33d2, 0x026d },
+	{ 0x33d3, 0xff00 },
+	{ 0x33d4, 0x026d },
+	{ 0x33d5, 0x0101 },
+	{ 0x33d6, 0xc4f5 },
+	{ 0x33d7, 0x0361 },
+	{ 0x33d8, 0x0402 },
+	{ 0x33d9, 0x6701 },
+	{ 0x33da, 0xc4f5 },
+	{ 0x33db, 0x136f },
+	{ 0x33dc, 0xc4f5 },
+	{ 0x33dd, 0x134f },
+	{ 0x33de, 0xc4f5 },
+	{ 0x33df, 0x131f },
+	{ 0x33e0, 0x026d },
+	{ 0x33e1, 0x4f01 },
+	{ 0x33e2, 0x026d },
+	{ 0x33e3, 0xf100 },
+	{ 0x33e4, 0x026d },
+	{ 0x33e5, 0x0001 },
+	{ 0x33e6, 0xc4f5 },
+	{ 0x33e7, 0x0361 },
+	{ 0x33e8, 0x0402 },
+	{ 0x33e9, 0x6601 },
+	{ 0x33ea, 0xc4f5 },
+	{ 0x33eb, 0x136f },
+	{ 0x33ec, 0xc4f5 },
+	{ 0x33ed, 0x134f },
+	{ 0x33ee, 0xc4f5 },
+	{ 0x33ef, 0x131f },
+	{ 0x33f0, 0x026d },
+	{ 0x33f1, 0x4e01 },
+	{ 0x33f2, 0x026d },
+	{ 0x33f3, 0xf000 },
+	{ 0x33f6, 0xc4f5 },
+	{ 0x33f7, 0x1361 },
+	{ 0x33f8, 0x0402 },
+	{ 0x33f9, 0x4600 },
+	{ 0x33fa, 0x026d },
+	{ 0x33fb, 0xfe00 },
+};
+
+static const struct reg_default wm5110_sysclk_reve_patch[] = {
+	{ 0x3270, 0xE410 },
+	{ 0x3271, 0x3078 },
+	{ 0x3272, 0xE410 },
+	{ 0x3273, 0x3070 },
+	{ 0x3274, 0xE410 },
+	{ 0x3275, 0x3066 },
+	{ 0x3276, 0xE410 },
+	{ 0x3277, 0x3056 },
+	{ 0x327A, 0xE414 },
+	{ 0x327B, 0x3078 },
+	{ 0x327C, 0xE414 },
+	{ 0x327D, 0x3070 },
+	{ 0x327E, 0xE414 },
+	{ 0x327F, 0x3066 },
+	{ 0x3280, 0xE414 },
+	{ 0x3281, 0x3056 },
+};
+
+static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+	struct regmap *regmap = arizona->regmap;
+	const struct reg_default *patch = NULL;
+	int i, patch_size;
+
+	switch (arizona->rev) {
+	case 3:
+		patch = wm5110_sysclk_revd_patch;
+		patch_size = ARRAY_SIZE(wm5110_sysclk_revd_patch);
+		break;
+	default:
+		patch = wm5110_sysclk_reve_patch;
+		patch_size = ARRAY_SIZE(wm5110_sysclk_reve_patch);
+		break;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (patch)
+			for (i = 0; i < patch_size; i++)
+				regmap_write_async(regmap, patch[i].reg,
+						   patch[i].def);
+		break;
+	case SND_SOC_DAPM_PRE_PMU:
+	case SND_SOC_DAPM_POST_PMD:
+		return arizona_clk_ev(w, kcontrol, event);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int wm5110_adsp_power_ev(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+	unsigned int v;
+	int ret;
+
+	ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to read SYSCLK state: %d\n", ret);
+		return ret;
+	}
+
+	v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
+
+	return wm_adsp2_early_event(w, kcontrol, event, v);
+}
+
+static const struct reg_sequence wm5110_no_dre_left_enable[] = {
+	{ 0x3024, 0xE410 },
+	{ 0x3025, 0x0056 },
+	{ 0x301B, 0x0224 },
+	{ 0x301F, 0x4263 },
+	{ 0x3021, 0x5291 },
+	{ 0x3030, 0xE410 },
+	{ 0x3031, 0x3066 },
+	{ 0x3032, 0xE410 },
+	{ 0x3033, 0x3070 },
+	{ 0x3034, 0xE410 },
+	{ 0x3035, 0x3078 },
+	{ 0x3036, 0xE410 },
+	{ 0x3037, 0x3080 },
+	{ 0x3038, 0xE410 },
+	{ 0x3039, 0x3080 },
+};
+
+static const struct reg_sequence wm5110_dre_left_enable[] = {
+	{ 0x3024, 0x0231 },
+	{ 0x3025, 0x0B00 },
+	{ 0x301B, 0x0227 },
+	{ 0x301F, 0x4266 },
+	{ 0x3021, 0x5294 },
+	{ 0x3030, 0xE231 },
+	{ 0x3031, 0x0266 },
+	{ 0x3032, 0x8231 },
+	{ 0x3033, 0x4B15 },
+	{ 0x3034, 0x8231 },
+	{ 0x3035, 0x0B15 },
+	{ 0x3036, 0xE231 },
+	{ 0x3037, 0x5294 },
+	{ 0x3038, 0x0231 },
+	{ 0x3039, 0x0B00 },
+};
+
+static const struct reg_sequence wm5110_no_dre_right_enable[] = {
+	{ 0x3074, 0xE414 },
+	{ 0x3075, 0x0056 },
+	{ 0x306B, 0x0224 },
+	{ 0x306F, 0x4263 },
+	{ 0x3071, 0x5291 },
+	{ 0x3080, 0xE414 },
+	{ 0x3081, 0x3066 },
+	{ 0x3082, 0xE414 },
+	{ 0x3083, 0x3070 },
+	{ 0x3084, 0xE414 },
+	{ 0x3085, 0x3078 },
+	{ 0x3086, 0xE414 },
+	{ 0x3087, 0x3080 },
+	{ 0x3088, 0xE414 },
+	{ 0x3089, 0x3080 },
+};
+
+static const struct reg_sequence wm5110_dre_right_enable[] = {
+	{ 0x3074, 0x0231 },
+	{ 0x3075, 0x0B00 },
+	{ 0x306B, 0x0227 },
+	{ 0x306F, 0x4266 },
+	{ 0x3071, 0x5294 },
+	{ 0x3080, 0xE231 },
+	{ 0x3081, 0x0266 },
+	{ 0x3082, 0x8231 },
+	{ 0x3083, 0x4B17 },
+	{ 0x3084, 0x8231 },
+	{ 0x3085, 0x0B17 },
+	{ 0x3086, 0xE231 },
+	{ 0x3087, 0x5294 },
+	{ 0x3088, 0x0231 },
+	{ 0x3089, 0x0B00 },
+};
+
+static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+	unsigned int val = snd_soc_component_read32(component, ARIZONA_DRE_ENABLE);
+	const struct reg_sequence *wseq;
+	int nregs;
+
+	switch (w->shift) {
+	case ARIZONA_OUT1L_ENA_SHIFT:
+		if (val & ARIZONA_DRE1L_ENA_MASK) {
+			wseq = wm5110_dre_left_enable;
+			nregs = ARRAY_SIZE(wm5110_dre_left_enable);
+		} else {
+			wseq = wm5110_no_dre_left_enable;
+			nregs = ARRAY_SIZE(wm5110_no_dre_left_enable);
+			priv->out_up_delay += 10;
+		}
+		break;
+	case ARIZONA_OUT1R_ENA_SHIFT:
+		if (val & ARIZONA_DRE1R_ENA_MASK) {
+			wseq = wm5110_dre_right_enable;
+			nregs = ARRAY_SIZE(wm5110_dre_right_enable);
+		} else {
+			wseq = wm5110_no_dre_right_enable;
+			nregs = ARRAY_SIZE(wm5110_no_dre_right_enable);
+			priv->out_up_delay += 10;
+		}
+		break;
+	default:
+		return 0;
+	}
+
+	return regmap_multi_reg_write(arizona->regmap, wseq, nregs);
+}
+
+static int wm5110_hp_pre_disable(struct snd_soc_dapm_widget *w)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	unsigned int val = snd_soc_component_read32(component, ARIZONA_DRE_ENABLE);
+
+	switch (w->shift) {
+	case ARIZONA_OUT1L_ENA_SHIFT:
+		if (!(val & ARIZONA_DRE1L_ENA_MASK)) {
+			snd_soc_component_update_bits(component,
+						      ARIZONA_SPARE_TRIGGERS,
+						      ARIZONA_WS_TRG1,
+						      ARIZONA_WS_TRG1);
+			snd_soc_component_update_bits(component,
+						      ARIZONA_SPARE_TRIGGERS,
+						      ARIZONA_WS_TRG1, 0);
+			priv->out_down_delay += 27;
+		}
+		break;
+	case ARIZONA_OUT1R_ENA_SHIFT:
+		if (!(val & ARIZONA_DRE1R_ENA_MASK)) {
+			snd_soc_component_update_bits(component,
+						      ARIZONA_SPARE_TRIGGERS,
+						      ARIZONA_WS_TRG2,
+						      ARIZONA_WS_TRG2);
+			snd_soc_component_update_bits(component,
+						      ARIZONA_SPARE_TRIGGERS,
+						      ARIZONA_WS_TRG2, 0);
+			priv->out_down_delay += 27;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int wm5110_hp_ev(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+
+	switch (priv->arizona->rev) {
+	case 0 ... 3:
+		break;
+	default:
+		switch (event) {
+		case SND_SOC_DAPM_PRE_PMU:
+			wm5110_hp_pre_enable(w);
+			break;
+		case SND_SOC_DAPM_PRE_PMD:
+			wm5110_hp_pre_disable(w);
+			break;
+		default:
+			break;
+		}
+		break;
+	}
+
+	return arizona_hp_ev(w, kcontrol, event);
+}
+
+static int wm5110_clear_pga_volume(struct arizona *arizona, int output)
+{
+	unsigned int reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4;
+	int ret;
+
+	ret = regmap_write(arizona->regmap, reg, 0x80);
+	if (ret)
+		dev_err(arizona->dev, "Failed to clear PGA (0x%x): %d\n",
+			reg, ret);
+
+	return ret;
+}
+
+static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned int ena, dre;
+	unsigned int mask = (0x1 << mc->shift) | (0x1 << mc->rshift);
+	unsigned int lnew = (!!ucontrol->value.integer.value[0]) << mc->shift;
+	unsigned int rnew = (!!ucontrol->value.integer.value[1]) << mc->rshift;
+	unsigned int lold, rold;
+	unsigned int lena, rena;
+	int ret;
+
+	snd_soc_dapm_mutex_lock(dapm);
+
+	ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &ena);
+	if (ret) {
+		dev_err(arizona->dev, "Failed to read output state: %d\n", ret);
+		goto err;
+	}
+	ret = regmap_read(arizona->regmap, ARIZONA_DRE_ENABLE, &dre);
+	if (ret) {
+		dev_err(arizona->dev, "Failed to read DRE state: %d\n", ret);
+		goto err;
+	}
+
+	lold = dre & (1 << mc->shift);
+	rold = dre & (1 << mc->rshift);
+	/* Enables are channel wise swapped from the DRE enables */
+	lena = ena & (1 << mc->rshift);
+	rena = ena & (1 << mc->shift);
+
+	if ((lena && lnew != lold) || (rena && rnew != rold)) {
+		dev_err(arizona->dev, "Can't change DRE on active outputs\n");
+		ret = -EBUSY;
+		goto err;
+	}
+
+	ret = regmap_update_bits(arizona->regmap, ARIZONA_DRE_ENABLE,
+				 mask, lnew | rnew);
+	if (ret) {
+		dev_err(arizona->dev, "Failed to set DRE: %d\n", ret);
+		goto err;
+	}
+
+	/* Force reset of PGA volumes, if turning DRE off */
+	if (!lnew && lold)
+		wm5110_clear_pga_volume(arizona, mc->shift);
+
+	if (!rnew && rold)
+		wm5110_clear_pga_volume(arizona, mc->rshift);
+
+err:
+	snd_soc_dapm_mutex_unlock(dapm);
+
+	return ret;
+}
+
+static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int ret;
+
+	/*
+	 * PGA Volume is also used as part of the enable sequence, so
+	 * usage of it should be avoided whilst that is running.
+	 */
+	snd_soc_dapm_mutex_lock(dapm);
+
+	ret = snd_soc_get_volsw_range(kcontrol, ucontrol);
+
+	snd_soc_dapm_mutex_unlock(dapm);
+
+	return ret;
+}
+
+static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int ret;
+
+	/*
+	 * PGA Volume is also used as part of the enable sequence, so
+	 * usage of it should be avoided whilst that is running.
+	 */
+	snd_soc_dapm_mutex_lock(dapm);
+
+	ret = snd_soc_put_volsw_range(kcontrol, ucontrol);
+
+	snd_soc_dapm_mutex_unlock(dapm);
+
+	return ret;
+}
+
+static int wm5110_in_analog_ev(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct wm5110_priv *wm5110 = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+	unsigned int reg, mask;
+	struct reg_sequence analog_seq[] = {
+		{ 0x80, 0x3 },
+		{ 0x35d, 0 },
+		{ 0x80, 0x0 },
+	};
+
+	reg = ARIZONA_IN1L_CONTROL + ((w->shift ^ 0x1) * 4);
+	mask = ARIZONA_IN1L_PGA_VOL_MASK;
+
+	switch (event) {
+	case SND_SOC_DAPM_WILL_PMU:
+		wm5110->in_value |= 0x3 << ((w->shift ^ 0x1) * 2);
+		wm5110->in_pre_pending++;
+		wm5110->in_post_pending++;
+		return 0;
+	case SND_SOC_DAPM_PRE_PMU:
+		wm5110->in_pga_cache[w->shift] = snd_soc_component_read32(component, reg);
+
+		snd_soc_component_update_bits(component, reg, mask,
+				    0x40 << ARIZONA_IN1L_PGA_VOL_SHIFT);
+
+		wm5110->in_pre_pending--;
+		if (wm5110->in_pre_pending == 0) {
+			analog_seq[1].def = wm5110->in_value;
+			regmap_multi_reg_write_bypassed(arizona->regmap,
+							analog_seq,
+							ARRAY_SIZE(analog_seq));
+
+			msleep(55);
+
+			wm5110->in_value = 0;
+		}
+
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, reg, mask,
+					      wm5110->in_pga_cache[w->shift]);
+
+		wm5110->in_post_pending--;
+		if (wm5110->in_post_pending == 0)
+			regmap_multi_reg_write_bypassed(arizona->regmap,
+							analog_seq,
+							ARRAY_SIZE(analog_seq));
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int wm5110_in_ev(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->arizona;
+
+	switch (arizona->rev) {
+	case 0 ... 4:
+		if (arizona_input_analog(component, w->shift))
+			wm5110_in_analog_ev(w, kcontrol, event);
+
+		break;
+	default:
+		break;
+	}
+
+	return arizona_in_ev(w, kcontrol, event);
+}
+
+static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
+static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
+
+#define WM5110_NG_SRC(name, base) \
+	SOC_SINGLE(name " NG HPOUT1L Switch",  base,  0, 1, 0), \
+	SOC_SINGLE(name " NG HPOUT1R Switch",  base,  1, 1, 0), \
+	SOC_SINGLE(name " NG HPOUT2L Switch",  base,  2, 1, 0), \
+	SOC_SINGLE(name " NG HPOUT2R Switch",  base,  3, 1, 0), \
+	SOC_SINGLE(name " NG HPOUT3L Switch",  base,  4, 1, 0), \
+	SOC_SINGLE(name " NG HPOUT3R Switch",  base,  5, 1, 0), \
+	SOC_SINGLE(name " NG SPKOUTL Switch",  base,  6, 1, 0), \
+	SOC_SINGLE(name " NG SPKOUTR Switch",  base,  7, 1, 0), \
+	SOC_SINGLE(name " NG SPKDAT1L Switch", base,  8, 1, 0), \
+	SOC_SINGLE(name " NG SPKDAT1R Switch", base,  9, 1, 0), \
+	SOC_SINGLE(name " NG SPKDAT2L Switch", base, 10, 1, 0), \
+	SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0)
+
+#define WM5110_RXANC_INPUT_ROUTES(widget, name) \
+	{ widget, NULL, name " NG Mux" }, \
+	{ name " NG Internal", NULL, "RXANC NG Clock" }, \
+	{ name " NG Internal", NULL, name " Channel" }, \
+	{ name " NG External", NULL, "RXANC NG External Clock" }, \
+	{ name " NG External", NULL, name " Channel" }, \
+	{ name " NG Mux", "None", name " Channel" }, \
+	{ name " NG Mux", "Internal", name " NG Internal" }, \
+	{ name " NG Mux", "External", name " NG External" }, \
+	{ name " Channel", "Left", name " Left Input" }, \
+	{ name " Channel", "Combine", name " Left Input" }, \
+	{ name " Channel", "Right", name " Right Input" }, \
+	{ name " Channel", "Combine", name " Right Input" }, \
+	{ name " Left Input", "IN1", "IN1L PGA" }, \
+	{ name " Right Input", "IN1", "IN1R PGA" }, \
+	{ name " Left Input", "IN2", "IN2L PGA" }, \
+	{ name " Right Input", "IN2", "IN2R PGA" }, \
+	{ name " Left Input", "IN3", "IN3L PGA" }, \
+	{ name " Right Input", "IN3", "IN3R PGA" }, \
+	{ name " Left Input", "IN4", "IN4L PGA" }, \
+	{ name " Right Input", "IN4", "IN4R PGA" }
+
+#define WM5110_RXANC_OUTPUT_ROUTES(widget, name) \
+	{ widget, NULL, name " ANC Source" }, \
+	{ name " ANC Source", "RXANCL", "RXANCL" }, \
+	{ name " ANC Source", "RXANCR", "RXANCR" }
+
+static const struct snd_kcontrol_new wm5110_snd_controls[] = {
+SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]),
+SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
+SOC_ENUM("IN3 OSR", arizona_in_dmic_osr[2]),
+SOC_ENUM("IN4 OSR", arizona_in_dmic_osr[3]),
+
+SOC_SINGLE_RANGE_EXT_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
+			 ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+			 wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
+			 ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+			 wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL,
+			 ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+			 wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL,
+			 ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+			 wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL,
+			 ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+			 wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+SOC_SINGLE_RANGE_EXT_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL,
+			 ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0,
+			 wm5110_in_pga_get, wm5110_in_pga_put, ana_tlv),
+
+SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum),
+
+SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL,
+	   ARIZONA_IN1L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL,
+	   ARIZONA_IN1R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2L HPF Switch", ARIZONA_IN2L_CONTROL,
+	   ARIZONA_IN2L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2R HPF Switch", ARIZONA_IN2R_CONTROL,
+	   ARIZONA_IN2R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN3L HPF Switch", ARIZONA_IN3L_CONTROL,
+	   ARIZONA_IN3L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN3R HPF Switch", ARIZONA_IN3R_CONTROL,
+	   ARIZONA_IN3R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN4L HPF Switch", ARIZONA_IN4L_CONTROL,
+	   ARIZONA_IN4L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN4R HPF Switch", ARIZONA_IN4R_CONTROL,
+	   ARIZONA_IN4R_HPF_SHIFT, 1, 0),
+
+SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
+	       ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
+	       ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
+	       ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R,
+	       ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN3L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L,
+	       ARIZONA_IN3L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN3R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3R,
+	       ARIZONA_IN3R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN4L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4L,
+	       ARIZONA_IN4L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN4R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4R,
+	       ARIZONA_IN4R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+
+SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
+SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
+
+SND_SOC_BYTES("RXANC Coefficients", ARIZONA_ANC_COEFF_START,
+	      ARIZONA_ANC_COEFF_END - ARIZONA_ANC_COEFF_START + 1),
+SND_SOC_BYTES("RXANCL Config", ARIZONA_FCL_FILTER_CONTROL, 1),
+SND_SOC_BYTES("RXANCL Coefficients", ARIZONA_FCL_COEFF_START,
+	      ARIZONA_FCL_COEFF_END - ARIZONA_FCL_COEFF_START + 1),
+SND_SOC_BYTES("RXANCR Config", ARIZONA_FCR_FILTER_CONTROL, 1),
+SND_SOC_BYTES("RXANCR Coefficients", ARIZONA_FCR_COEFF_START,
+	      ARIZONA_FCR_COEFF_END - ARIZONA_FCR_COEFF_START + 1),
+
+ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
+
+ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2),
+SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2),
+SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_EQ_CONTROL("EQ3 Coefficients", ARIZONA_EQ3_2),
+SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B3 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_EQ_CONTROL("EQ4 Coefficients", ARIZONA_EQ4_2),
+SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B3 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B4 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B5 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC2L", ARIZONA_DRC2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC2R", ARIZONA_DRC2RMIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
+		   ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
+SND_SOC_BYTES_MASK("DRC2", ARIZONA_DRC2_CTRL1, 5,
+		   ARIZONA_DRC2R_ENA | ARIZONA_DRC2L_ENA),
+
+ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
+
+ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2),
+ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
+ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
+ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2),
+
+SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
+SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
+SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
+SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
+
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]),
+SOC_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]),
+SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
+SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
+SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
+
+WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
+WM_ADSP2_PRELOAD_SWITCH("DSP2", 2),
+WM_ADSP2_PRELOAD_SWITCH("DSP3", 3),
+WM_ADSP2_PRELOAD_SWITCH("DSP4", 4),
+
+ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP3R", ARIZONA_DSP3RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP4L", ARIZONA_DSP4LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP4R", ARIZONA_DSP4RMIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR,
+	       ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv),
+
+ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT2L", ARIZONA_OUT2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT2R", ARIZONA_OUT2RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT3L", ARIZONA_OUT3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT3R", ARIZONA_OUT3RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUTL", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDAT2L", ARIZONA_OUT6LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDAT2R", ARIZONA_OUT6RMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE("HPOUT1 SC Protect Switch", ARIZONA_HP1_SHORT_CIRCUIT_CTRL,
+	   ARIZONA_HP1_SC_ENA_SHIFT, 1, 0),
+SOC_SINGLE("HPOUT2 SC Protect Switch", ARIZONA_HP2_SHORT_CIRCUIT_CTRL,
+	   ARIZONA_HP2_SC_ENA_SHIFT, 1, 0),
+SOC_SINGLE("HPOUT3 SC Protect Switch", ARIZONA_HP3_SHORT_CIRCUIT_CTRL,
+	   ARIZONA_HP3_SC_ENA_SHIFT, 1, 0),
+
+SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,
+	   ARIZONA_OUT5_OSR_SHIFT, 1, 0),
+SOC_SINGLE("SPKDAT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_6L,
+	   ARIZONA_OUT6_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("HPOUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("HPOUT3 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_3R, ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKDAT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKDAT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_6L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_6R, ARIZONA_OUT6L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("HPOUT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_2L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("HPOUT3 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_3R, ARIZONA_OUT3L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("SPKDAT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_6L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_6R, ARIZONA_OUT6L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+
+SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
+	   ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT,
+	   ARIZONA_SPK2R_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_EXT("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,
+	       ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0,
+	       snd_soc_get_volsw, wm5110_put_dre),
+SOC_DOUBLE_EXT("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE,
+	       ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0,
+	       snd_soc_get_volsw, wm5110_put_dre),
+SOC_DOUBLE_EXT("HPOUT3 DRE Switch", ARIZONA_DRE_ENABLE,
+	       ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0,
+	       snd_soc_get_volsw, wm5110_put_dre),
+
+SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
+SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
+
+SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
+	   ARIZONA_NGATE_ENA_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
+	       ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
+SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
+
+WM5110_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L),
+WM5110_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R),
+WM5110_NG_SRC("HPOUT2L", ARIZONA_NOISE_GATE_SELECT_2L),
+WM5110_NG_SRC("HPOUT2R", ARIZONA_NOISE_GATE_SELECT_2R),
+WM5110_NG_SRC("HPOUT3L", ARIZONA_NOISE_GATE_SELECT_3L),
+WM5110_NG_SRC("HPOUT3R", ARIZONA_NOISE_GATE_SELECT_3R),
+WM5110_NG_SRC("SPKOUTL", ARIZONA_NOISE_GATE_SELECT_4L),
+WM5110_NG_SRC("SPKOUTR", ARIZONA_NOISE_GATE_SELECT_4R),
+WM5110_NG_SRC("SPKDAT1L", ARIZONA_NOISE_GATE_SELECT_5L),
+WM5110_NG_SRC("SPKDAT1R", ARIZONA_NOISE_GATE_SELECT_5R),
+WM5110_NG_SRC("SPKDAT2L", ARIZONA_NOISE_GATE_SELECT_6L),
+WM5110_NG_SRC("SPKDAT2R", ARIZONA_NOISE_GATE_SELECT_6R),
+
+ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("SLIMTX1", ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX2", ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX3", ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX4", ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
+
+WM_ADSP_FW_CONTROL("DSP1", 0),
+WM_ADSP_FW_CONTROL("DSP2", 1),
+WM_ADSP_FW_CONTROL("DSP3", 2),
+WM_ADSP_FW_CONTROL("DSP4", 3),
+};
+
+ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ4, ARIZONA_EQ4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC2L, ARIZONA_DRC2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC2R, ARIZONA_DRC2RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP1L, ARIZONA_DSP1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP1R, ARIZONA_DSP1RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP1, ARIZONA_DSP1AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP2L, ARIZONA_DSP2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP2R, ARIZONA_DSP2RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP2, ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP3L, ARIZONA_DSP3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP3R, ARIZONA_DSP3RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP3, ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP4L, ARIZONA_DSP4LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP4R, ARIZONA_DSP4RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP4, ARIZONA_DSP4AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT2L, ARIZONA_OUT2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT2R, ARIZONA_OUT2RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT3L, ARIZONA_OUT3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT3R, ARIZONA_OUT3RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUTL, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUTR, ARIZONA_OUT4RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDAT1L, ARIZONA_OUT5LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDAT1R, ARIZONA_OUT5RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDAT2L, ARIZONA_OUT6LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDAT2R, ARIZONA_OUT6RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(SLIMTX1, ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX2, ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX3, ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX4, ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX5, ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX6, ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX7, ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX8, ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT3, ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT4, ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC3, ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC4, ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT3, ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT4, ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC3, ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC4, ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC3INT1, ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT2, ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT3, ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT4, ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC3DEC1, ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC2, ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC3, ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC4, ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE);
+
+static const char * const wm5110_aec_loopback_texts[] = {
+	"HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "HPOUT3L", "HPOUT3R",
+	"SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R", "SPKDAT2L", "SPKDAT2R",
+};
+
+static const unsigned int wm5110_aec_loopback_values[] = {
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+};
+
+static const struct soc_enum wm5110_aec_loopback =
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
+			      ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+			      ARRAY_SIZE(wm5110_aec_loopback_texts),
+			      wm5110_aec_loopback_texts,
+			      wm5110_aec_loopback_values);
+
+static const struct snd_kcontrol_new wm5110_aec_loopback_mux =
+	SOC_DAPM_ENUM("AEC Loopback", wm5110_aec_loopback);
+
+static const struct snd_kcontrol_new wm5110_anc_input_mux[] = {
+	SOC_DAPM_ENUM("RXANCL Input", arizona_anc_input_src[0]),
+	SOC_DAPM_ENUM("RXANCL Channel", arizona_anc_input_src[1]),
+	SOC_DAPM_ENUM("RXANCR Input", arizona_anc_input_src[2]),
+	SOC_DAPM_ENUM("RXANCR Channel", arizona_anc_input_src[3]),
+};
+
+static const struct snd_kcontrol_new wm5110_anc_ng_mux =
+	SOC_DAPM_ENUM("RXANC NG Source", arizona_anc_ng_enum);
+
+static const struct snd_kcontrol_new wm5110_output_anc_src[] = {
+	SOC_DAPM_ENUM("HPOUT1L ANC Source", arizona_output_anc_src[0]),
+	SOC_DAPM_ENUM("HPOUT1R ANC Source", arizona_output_anc_src[1]),
+	SOC_DAPM_ENUM("HPOUT2L ANC Source", arizona_output_anc_src[2]),
+	SOC_DAPM_ENUM("HPOUT2R ANC Source", arizona_output_anc_src[3]),
+	SOC_DAPM_ENUM("HPOUT3L ANC Source", arizona_output_anc_src[4]),
+	SOC_DAPM_ENUM("HPOUT3R ANC Source", arizona_output_anc_src[5]),
+	SOC_DAPM_ENUM("SPKOUTL ANC Source", arizona_output_anc_src[6]),
+	SOC_DAPM_ENUM("SPKOUTR ANC Source", arizona_output_anc_src[7]),
+	SOC_DAPM_ENUM("SPKDAT1L ANC Source", arizona_output_anc_src[8]),
+	SOC_DAPM_ENUM("SPKDAT1R ANC Source", arizona_output_anc_src[9]),
+	SOC_DAPM_ENUM("SPKDAT2L ANC Source", arizona_output_anc_src[10]),
+	SOC_DAPM_ENUM("SPKDAT2R ANC Source", arizona_output_anc_src[11]),
+};
+
+static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
+		    0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU |
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
+		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+		    ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_SIGGEN("NOISE"),
+SND_SOC_DAPM_SIGGEN("HAPTICS"),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+SND_SOC_DAPM_INPUT("IN4L"),
+SND_SOC_DAPM_INPUT("IN4R"),
+
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"),
+
+SND_SOC_DAPM_OUTPUT("DSP Voice Trigger"),
+
+SND_SOC_DAPM_SWITCH("DSP3 Voice Trigger", SND_SOC_NOPM, 2, 0,
+		    &arizona_voice_trigger_switch[2]),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
+		   0, NULL, 0, wm5110_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_WILL_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
+		   0, NULL, 0, wm5110_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_WILL_PMU),
+SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
+		   0, NULL, 0, wm5110_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_WILL_PMU),
+SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
+		   0, NULL, 0, wm5110_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_WILL_PMU),
+SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
+		   0, NULL, 0, wm5110_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_WILL_PMU),
+SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
+		   0, NULL, 0, wm5110_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_WILL_PMU),
+SND_SOC_DAPM_PGA_E("IN4L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN4R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR,
+		 ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Mic Mute Mixer", ARIZONA_MIC_NOISE_MIX_CONTROL_1,
+		 ARIZONA_MICMUTE_MIX_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ3", ARIZONA_EQ3_1, ARIZONA_EQ3_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ4", ARIZONA_EQ4_1, ARIZONA_EQ4_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC2L", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC2R", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT,
+		 0, NULL, 0),
+SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT,
+		 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ASRC1L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("ASRC1R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1R_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+WM_ADSP2("DSP1", 0, wm5110_adsp_power_ev),
+WM_ADSP2("DSP2", 1, wm5110_adsp_power_ev),
+WM_ADSP2("DSP3", 2, wm5110_adsp_power_ev),
+WM_ADSP2("DSP4", 3, wm5110_adsp_power_ev),
+
+SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT3", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT4", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC3", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC4", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT3", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT4", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC3", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC4", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3INT1", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT2", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT3", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT4", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3DEC1", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC2", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+		 ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &wm5110_aec_loopback_mux),
+
+SND_SOC_DAPM_SUPPLY("RXANC NG External Clock", SND_SOC_NOPM,
+		    ARIZONA_EXT_NG_SEL_SET_SHIFT, 0, arizona_anc_ev,
+		    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA("RXANCL NG External", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("RXANCR NG External", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("RXANC NG Clock", SND_SOC_NOPM,
+		    ARIZONA_CLK_NG_ENA_SET_SHIFT, 0, arizona_anc_ev,
+		    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA("RXANCL NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("RXANCR NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("RXANCL Left Input", SND_SOC_NOPM, 0, 0,
+		 &wm5110_anc_input_mux[0]),
+SND_SOC_DAPM_MUX("RXANCL Right Input", SND_SOC_NOPM, 0, 0,
+		 &wm5110_anc_input_mux[0]),
+SND_SOC_DAPM_MUX("RXANCL Channel", SND_SOC_NOPM, 0, 0,
+		 &wm5110_anc_input_mux[1]),
+SND_SOC_DAPM_MUX("RXANCL NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux),
+SND_SOC_DAPM_MUX("RXANCR Left Input", SND_SOC_NOPM, 0, 0,
+		 &wm5110_anc_input_mux[2]),
+SND_SOC_DAPM_MUX("RXANCR Right Input", SND_SOC_NOPM, 0, 0,
+		 &wm5110_anc_input_mux[2]),
+SND_SOC_DAPM_MUX("RXANCR Channel", SND_SOC_NOPM, 0, 0,
+		 &wm5110_anc_input_mux[3]),
+SND_SOC_DAPM_MUX("RXANCR NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux),
+
+SND_SOC_DAPM_PGA_E("RXANCL", SND_SOC_NOPM, ARIZONA_CLK_L_ENA_SET_SHIFT,
+		   0, NULL, 0, arizona_anc_ev,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_E("RXANCR", SND_SOC_NOPM, ARIZONA_CLK_R_ENA_SET_SHIFT,
+		   0, NULL, 0, arizona_anc_ev,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_MUX("HPOUT1L ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[0]),
+SND_SOC_DAPM_MUX("HPOUT1R ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[1]),
+SND_SOC_DAPM_MUX("HPOUT2L ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[2]),
+SND_SOC_DAPM_MUX("HPOUT2R ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[3]),
+SND_SOC_DAPM_MUX("HPOUT3L ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[4]),
+SND_SOC_DAPM_MUX("HPOUT3R ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[5]),
+SND_SOC_DAPM_MUX("SPKOUTL ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[6]),
+SND_SOC_DAPM_MUX("SPKOUTR ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[7]),
+SND_SOC_DAPM_MUX("SPKDAT1L ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[8]),
+SND_SOC_DAPM_MUX("SPKDAT1R ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[9]),
+SND_SOC_DAPM_MUX("SPKDAT2L ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[10]),
+SND_SOC_DAPM_MUX("SPKDAT2R ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[11]),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0,
+		     ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0,
+		     ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
+		    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
+		    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+		   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, wm5110_hp_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+		   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, wm5110_hp_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT3R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT3R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT5R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT6L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT6L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT6R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT6R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"),
+ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"),
+ARIZONA_MIXER_WIDGETS(EQ3, "EQ3"),
+ARIZONA_MIXER_WIDGETS(EQ4, "EQ4"),
+
+ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"),
+ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"),
+ARIZONA_MIXER_WIDGETS(DRC2L, "DRC2L"),
+ARIZONA_MIXER_WIDGETS(DRC2R, "DRC2R"),
+
+ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
+ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
+ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"),
+ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+ARIZONA_MIXER_WIDGETS(Mic, "Mic"),
+ARIZONA_MIXER_WIDGETS(Noise, "Noise"),
+
+ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"),
+ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"),
+
+ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),
+ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),
+ARIZONA_MIXER_WIDGETS(OUT2L, "HPOUT2L"),
+ARIZONA_MIXER_WIDGETS(OUT2R, "HPOUT2R"),
+ARIZONA_MIXER_WIDGETS(OUT3L, "HPOUT3L"),
+ARIZONA_MIXER_WIDGETS(OUT3R, "HPOUT3R"),
+ARIZONA_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"),
+ARIZONA_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"),
+ARIZONA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"),
+ARIZONA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"),
+ARIZONA_MIXER_WIDGETS(SPKDAT2L, "SPKDAT2L"),
+ARIZONA_MIXER_WIDGETS(SPKDAT2R, "SPKDAT2R"),
+
+ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
+ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
+
+ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
+ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"),
+ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"),
+ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"),
+ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"),
+
+ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
+ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
+
+ARIZONA_MIXER_WIDGETS(SLIMTX1, "SLIMTX1"),
+ARIZONA_MIXER_WIDGETS(SLIMTX2, "SLIMTX2"),
+ARIZONA_MIXER_WIDGETS(SLIMTX3, "SLIMTX3"),
+ARIZONA_MIXER_WIDGETS(SLIMTX4, "SLIMTX4"),
+ARIZONA_MIXER_WIDGETS(SLIMTX5, "SLIMTX5"),
+ARIZONA_MIXER_WIDGETS(SLIMTX6, "SLIMTX6"),
+ARIZONA_MIXER_WIDGETS(SLIMTX7, "SLIMTX7"),
+ARIZONA_MIXER_WIDGETS(SLIMTX8, "SLIMTX8"),
+
+ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"),
+ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
+ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
+ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"),
+
+ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
+ARIZONA_DSP_WIDGETS(DSP2, "DSP2"),
+ARIZONA_DSP_WIDGETS(DSP3, "DSP3"),
+ARIZONA_DSP_WIDGETS(DSP4, "DSP4"),
+
+ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
+ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
+ARIZONA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"),
+ARIZONA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC3, "ISRC2DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC4, "ISRC2DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
+ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
+ARIZONA_MUX_WIDGETS(ISRC2INT3, "ISRC2INT3"),
+ARIZONA_MUX_WIDGETS(ISRC2INT4, "ISRC2INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC3DEC1, "ISRC3DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC2, "ISRC3DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC3, "ISRC3DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC4, "ISRC3DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC3INT1, "ISRC3INT1"),
+ARIZONA_MUX_WIDGETS(ISRC3INT2, "ISRC3INT2"),
+ARIZONA_MUX_WIDGETS(ISRC3INT3, "ISRC3INT3"),
+ARIZONA_MUX_WIDGETS(ISRC3INT4, "ISRC3INT4"),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("HPOUT2L"),
+SND_SOC_DAPM_OUTPUT("HPOUT2R"),
+SND_SOC_DAPM_OUTPUT("HPOUT3L"),
+SND_SOC_DAPM_OUTPUT("HPOUT3R"),
+SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
+SND_SOC_DAPM_OUTPUT("SPKDAT1L"),
+SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
+SND_SOC_DAPM_OUTPUT("SPKDAT2L"),
+SND_SOC_DAPM_OUTPUT("SPKDAT2R"),
+
+SND_SOC_DAPM_OUTPUT("MICSUPP"),
+};
+
+#define ARIZONA_MIXER_INPUT_ROUTES(name)	\
+	{ name, "Noise Generator", "Noise Generator" }, \
+	{ name, "Tone Generator 1", "Tone Generator 1" }, \
+	{ name, "Tone Generator 2", "Tone Generator 2" }, \
+	{ name, "Haptics", "HAPTICS" }, \
+	{ name, "AEC", "AEC Loopback" }, \
+	{ name, "IN1L", "IN1L PGA" }, \
+	{ name, "IN1R", "IN1R PGA" }, \
+	{ name, "IN2L", "IN2L PGA" }, \
+	{ name, "IN2R", "IN2R PGA" }, \
+	{ name, "IN3L", "IN3L PGA" }, \
+	{ name, "IN3R", "IN3R PGA" }, \
+	{ name, "IN4L", "IN4L PGA" }, \
+	{ name, "IN4R", "IN4R PGA" }, \
+	{ name, "Mic Mute Mixer", "Mic Mute Mixer" }, \
+	{ name, "AIF1RX1", "AIF1RX1" }, \
+	{ name, "AIF1RX2", "AIF1RX2" }, \
+	{ name, "AIF1RX3", "AIF1RX3" }, \
+	{ name, "AIF1RX4", "AIF1RX4" }, \
+	{ name, "AIF1RX5", "AIF1RX5" }, \
+	{ name, "AIF1RX6", "AIF1RX6" }, \
+	{ name, "AIF1RX7", "AIF1RX7" }, \
+	{ name, "AIF1RX8", "AIF1RX8" }, \
+	{ name, "AIF2RX1", "AIF2RX1" }, \
+	{ name, "AIF2RX2", "AIF2RX2" }, \
+	{ name, "AIF2RX3", "AIF2RX3" }, \
+	{ name, "AIF2RX4", "AIF2RX4" }, \
+	{ name, "AIF2RX5", "AIF2RX5" }, \
+	{ name, "AIF2RX6", "AIF2RX6" }, \
+	{ name, "AIF3RX1", "AIF3RX1" }, \
+	{ name, "AIF3RX2", "AIF3RX2" }, \
+	{ name, "SLIMRX1", "SLIMRX1" }, \
+	{ name, "SLIMRX2", "SLIMRX2" }, \
+	{ name, "SLIMRX3", "SLIMRX3" }, \
+	{ name, "SLIMRX4", "SLIMRX4" }, \
+	{ name, "SLIMRX5", "SLIMRX5" }, \
+	{ name, "SLIMRX6", "SLIMRX6" }, \
+	{ name, "SLIMRX7", "SLIMRX7" }, \
+	{ name, "SLIMRX8", "SLIMRX8" }, \
+	{ name, "EQ1", "EQ1" }, \
+	{ name, "EQ2", "EQ2" }, \
+	{ name, "EQ3", "EQ3" }, \
+	{ name, "EQ4", "EQ4" }, \
+	{ name, "DRC1L", "DRC1L" }, \
+	{ name, "DRC1R", "DRC1R" }, \
+	{ name, "DRC2L", "DRC2L" }, \
+	{ name, "DRC2R", "DRC2R" }, \
+	{ name, "LHPF1", "LHPF1" }, \
+	{ name, "LHPF2", "LHPF2" }, \
+	{ name, "LHPF3", "LHPF3" }, \
+	{ name, "LHPF4", "LHPF4" }, \
+	{ name, "ASRC1L", "ASRC1L" }, \
+	{ name, "ASRC1R", "ASRC1R" }, \
+	{ name, "ASRC2L", "ASRC2L" }, \
+	{ name, "ASRC2R", "ASRC2R" }, \
+	{ name, "ISRC1DEC1", "ISRC1DEC1" }, \
+	{ name, "ISRC1DEC2", "ISRC1DEC2" }, \
+	{ name, "ISRC1DEC3", "ISRC1DEC3" }, \
+	{ name, "ISRC1DEC4", "ISRC1DEC4" }, \
+	{ name, "ISRC1INT1", "ISRC1INT1" }, \
+	{ name, "ISRC1INT2", "ISRC1INT2" }, \
+	{ name, "ISRC1INT3", "ISRC1INT3" }, \
+	{ name, "ISRC1INT4", "ISRC1INT4" }, \
+	{ name, "ISRC2DEC1", "ISRC2DEC1" }, \
+	{ name, "ISRC2DEC2", "ISRC2DEC2" }, \
+	{ name, "ISRC2DEC3", "ISRC2DEC3" }, \
+	{ name, "ISRC2DEC4", "ISRC2DEC4" }, \
+	{ name, "ISRC2INT1", "ISRC2INT1" }, \
+	{ name, "ISRC2INT2", "ISRC2INT2" }, \
+	{ name, "ISRC2INT3", "ISRC2INT3" }, \
+	{ name, "ISRC2INT4", "ISRC2INT4" }, \
+	{ name, "ISRC3DEC1", "ISRC3DEC1" }, \
+	{ name, "ISRC3DEC2", "ISRC3DEC2" }, \
+	{ name, "ISRC3DEC3", "ISRC3DEC3" }, \
+	{ name, "ISRC3DEC4", "ISRC3DEC4" }, \
+	{ name, "ISRC3INT1", "ISRC3INT1" }, \
+	{ name, "ISRC3INT2", "ISRC3INT2" }, \
+	{ name, "ISRC3INT3", "ISRC3INT3" }, \
+	{ name, "ISRC3INT4", "ISRC3INT4" }, \
+	{ name, "DSP1.1", "DSP1" }, \
+	{ name, "DSP1.2", "DSP1" }, \
+	{ name, "DSP1.3", "DSP1" }, \
+	{ name, "DSP1.4", "DSP1" }, \
+	{ name, "DSP1.5", "DSP1" }, \
+	{ name, "DSP1.6", "DSP1" }, \
+	{ name, "DSP2.1", "DSP2" }, \
+	{ name, "DSP2.2", "DSP2" }, \
+	{ name, "DSP2.3", "DSP2" }, \
+	{ name, "DSP2.4", "DSP2" }, \
+	{ name, "DSP2.5", "DSP2" }, \
+	{ name, "DSP2.6", "DSP2" }, \
+	{ name, "DSP3.1", "DSP3" }, \
+	{ name, "DSP3.2", "DSP3" }, \
+	{ name, "DSP3.3", "DSP3" }, \
+	{ name, "DSP3.4", "DSP3" }, \
+	{ name, "DSP3.5", "DSP3" }, \
+	{ name, "DSP3.6", "DSP3" }, \
+	{ name, "DSP4.1", "DSP4" }, \
+	{ name, "DSP4.2", "DSP4" }, \
+	{ name, "DSP4.3", "DSP4" }, \
+	{ name, "DSP4.4", "DSP4" }, \
+	{ name, "DSP4.5", "DSP4" }, \
+	{ name, "DSP4.6", "DSP4" }
+
+static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
+	{ "AIF2 Capture", NULL, "DBVDD2" },
+	{ "AIF2 Playback", NULL, "DBVDD2" },
+
+	{ "AIF3 Capture", NULL, "DBVDD3" },
+	{ "AIF3 Playback", NULL, "DBVDD3" },
+
+	{ "OUT1L", NULL, "CPVDD" },
+	{ "OUT1R", NULL, "CPVDD" },
+	{ "OUT2L", NULL, "CPVDD" },
+	{ "OUT2R", NULL, "CPVDD" },
+	{ "OUT3L", NULL, "CPVDD" },
+	{ "OUT3R", NULL, "CPVDD" },
+
+	{ "OUT4L", NULL, "SPKVDDL" },
+	{ "OUT4R", NULL, "SPKVDDR" },
+
+	{ "OUT1L", NULL, "SYSCLK" },
+	{ "OUT1R", NULL, "SYSCLK" },
+	{ "OUT2L", NULL, "SYSCLK" },
+	{ "OUT2R", NULL, "SYSCLK" },
+	{ "OUT3L", NULL, "SYSCLK" },
+	{ "OUT3R", NULL, "SYSCLK" },
+	{ "OUT4L", NULL, "SYSCLK" },
+	{ "OUT4R", NULL, "SYSCLK" },
+	{ "OUT5L", NULL, "SYSCLK" },
+	{ "OUT5R", NULL, "SYSCLK" },
+	{ "OUT6L", NULL, "SYSCLK" },
+	{ "OUT6R", NULL, "SYSCLK" },
+
+	{ "IN1L", NULL, "SYSCLK" },
+	{ "IN1R", NULL, "SYSCLK" },
+	{ "IN2L", NULL, "SYSCLK" },
+	{ "IN2R", NULL, "SYSCLK" },
+	{ "IN3L", NULL, "SYSCLK" },
+	{ "IN3R", NULL, "SYSCLK" },
+	{ "IN4L", NULL, "SYSCLK" },
+	{ "IN4R", NULL, "SYSCLK" },
+
+	{ "ASRC1L", NULL, "SYSCLK" },
+	{ "ASRC1R", NULL, "SYSCLK" },
+	{ "ASRC2L", NULL, "SYSCLK" },
+	{ "ASRC2R", NULL, "SYSCLK" },
+
+	{ "ASRC1L", NULL, "ASYNCCLK" },
+	{ "ASRC1R", NULL, "ASYNCCLK" },
+	{ "ASRC2L", NULL, "ASYNCCLK" },
+	{ "ASRC2R", NULL, "ASYNCCLK" },
+
+	{ "MICBIAS1", NULL, "MICVDD" },
+	{ "MICBIAS2", NULL, "MICVDD" },
+	{ "MICBIAS3", NULL, "MICVDD" },
+
+	{ "Noise Generator", NULL, "SYSCLK" },
+	{ "Tone Generator 1", NULL, "SYSCLK" },
+	{ "Tone Generator 2", NULL, "SYSCLK" },
+
+	{ "Noise Generator", NULL, "NOISE" },
+	{ "Tone Generator 1", NULL, "TONE" },
+	{ "Tone Generator 2", NULL, "TONE" },
+
+	{ "AIF1 Capture", NULL, "AIF1TX1" },
+	{ "AIF1 Capture", NULL, "AIF1TX2" },
+	{ "AIF1 Capture", NULL, "AIF1TX3" },
+	{ "AIF1 Capture", NULL, "AIF1TX4" },
+	{ "AIF1 Capture", NULL, "AIF1TX5" },
+	{ "AIF1 Capture", NULL, "AIF1TX6" },
+	{ "AIF1 Capture", NULL, "AIF1TX7" },
+	{ "AIF1 Capture", NULL, "AIF1TX8" },
+
+	{ "AIF1RX1", NULL, "AIF1 Playback" },
+	{ "AIF1RX2", NULL, "AIF1 Playback" },
+	{ "AIF1RX3", NULL, "AIF1 Playback" },
+	{ "AIF1RX4", NULL, "AIF1 Playback" },
+	{ "AIF1RX5", NULL, "AIF1 Playback" },
+	{ "AIF1RX6", NULL, "AIF1 Playback" },
+	{ "AIF1RX7", NULL, "AIF1 Playback" },
+	{ "AIF1RX8", NULL, "AIF1 Playback" },
+
+	{ "AIF2 Capture", NULL, "AIF2TX1" },
+	{ "AIF2 Capture", NULL, "AIF2TX2" },
+	{ "AIF2 Capture", NULL, "AIF2TX3" },
+	{ "AIF2 Capture", NULL, "AIF2TX4" },
+	{ "AIF2 Capture", NULL, "AIF2TX5" },
+	{ "AIF2 Capture", NULL, "AIF2TX6" },
+
+	{ "AIF2RX1", NULL, "AIF2 Playback" },
+	{ "AIF2RX2", NULL, "AIF2 Playback" },
+	{ "AIF2RX3", NULL, "AIF2 Playback" },
+	{ "AIF2RX4", NULL, "AIF2 Playback" },
+	{ "AIF2RX5", NULL, "AIF2 Playback" },
+	{ "AIF2RX6", NULL, "AIF2 Playback" },
+
+	{ "AIF3 Capture", NULL, "AIF3TX1" },
+	{ "AIF3 Capture", NULL, "AIF3TX2" },
+
+	{ "AIF3RX1", NULL, "AIF3 Playback" },
+	{ "AIF3RX2", NULL, "AIF3 Playback" },
+
+	{ "Slim1 Capture", NULL, "SLIMTX1" },
+	{ "Slim1 Capture", NULL, "SLIMTX2" },
+	{ "Slim1 Capture", NULL, "SLIMTX3" },
+	{ "Slim1 Capture", NULL, "SLIMTX4" },
+
+	{ "SLIMRX1", NULL, "Slim1 Playback" },
+	{ "SLIMRX2", NULL, "Slim1 Playback" },
+	{ "SLIMRX3", NULL, "Slim1 Playback" },
+	{ "SLIMRX4", NULL, "Slim1 Playback" },
+
+	{ "Slim2 Capture", NULL, "SLIMTX5" },
+	{ "Slim2 Capture", NULL, "SLIMTX6" },
+
+	{ "SLIMRX5", NULL, "Slim2 Playback" },
+	{ "SLIMRX6", NULL, "Slim2 Playback" },
+
+	{ "Slim3 Capture", NULL, "SLIMTX7" },
+	{ "Slim3 Capture", NULL, "SLIMTX8" },
+
+	{ "SLIMRX7", NULL, "Slim3 Playback" },
+	{ "SLIMRX8", NULL, "Slim3 Playback" },
+
+	{ "AIF1 Playback", NULL, "SYSCLK" },
+	{ "AIF2 Playback", NULL, "SYSCLK" },
+	{ "AIF3 Playback", NULL, "SYSCLK" },
+	{ "Slim1 Playback", NULL, "SYSCLK" },
+	{ "Slim2 Playback", NULL, "SYSCLK" },
+	{ "Slim3 Playback", NULL, "SYSCLK" },
+
+	{ "AIF1 Capture", NULL, "SYSCLK" },
+	{ "AIF2 Capture", NULL, "SYSCLK" },
+	{ "AIF3 Capture", NULL, "SYSCLK" },
+	{ "Slim1 Capture", NULL, "SYSCLK" },
+	{ "Slim2 Capture", NULL, "SYSCLK" },
+	{ "Slim3 Capture", NULL, "SYSCLK" },
+
+	{ "Voice Control DSP", NULL, "DSP3" },
+
+	{ "Audio Trace DSP", NULL, "DSP1" },
+
+	{ "IN1L PGA", NULL, "IN1L" },
+	{ "IN1R PGA", NULL, "IN1R" },
+
+	{ "IN2L PGA", NULL, "IN2L" },
+	{ "IN2R PGA", NULL, "IN2R" },
+
+	{ "IN3L PGA", NULL, "IN3L" },
+	{ "IN3R PGA", NULL, "IN3R" },
+
+	{ "IN4L PGA", NULL, "IN4L" },
+	{ "IN4R PGA", NULL, "IN4R" },
+
+	ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
+	ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
+	ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
+	ARIZONA_MIXER_ROUTES("OUT2R", "HPOUT2R"),
+	ARIZONA_MIXER_ROUTES("OUT3L", "HPOUT3L"),
+	ARIZONA_MIXER_ROUTES("OUT3R", "HPOUT3R"),
+
+	ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUTL"),
+	ARIZONA_MIXER_ROUTES("OUT4R", "SPKOUTR"),
+	ARIZONA_MIXER_ROUTES("OUT5L", "SPKDAT1L"),
+	ARIZONA_MIXER_ROUTES("OUT5R", "SPKDAT1R"),
+	ARIZONA_MIXER_ROUTES("OUT6L", "SPKDAT2L"),
+	ARIZONA_MIXER_ROUTES("OUT6R", "SPKDAT2R"),
+
+	ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"),
+	ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"),
+
+	ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+	ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+	ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+	ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+	ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+	ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+	ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
+	ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
+
+	ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
+	ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+	ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"),
+	ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"),
+	ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"),
+	ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"),
+
+	ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
+	ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
+
+	ARIZONA_MIXER_ROUTES("SLIMTX1", "SLIMTX1"),
+	ARIZONA_MIXER_ROUTES("SLIMTX2", "SLIMTX2"),
+	ARIZONA_MIXER_ROUTES("SLIMTX3", "SLIMTX3"),
+	ARIZONA_MIXER_ROUTES("SLIMTX4", "SLIMTX4"),
+	ARIZONA_MIXER_ROUTES("SLIMTX5", "SLIMTX5"),
+	ARIZONA_MIXER_ROUTES("SLIMTX6", "SLIMTX6"),
+	ARIZONA_MIXER_ROUTES("SLIMTX7", "SLIMTX7"),
+	ARIZONA_MIXER_ROUTES("SLIMTX8", "SLIMTX8"),
+
+	ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
+	ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
+	ARIZONA_MIXER_ROUTES("EQ3", "EQ3"),
+	ARIZONA_MIXER_ROUTES("EQ4", "EQ4"),
+
+	ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"),
+	ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"),
+	ARIZONA_MIXER_ROUTES("DRC2L", "DRC2L"),
+	ARIZONA_MIXER_ROUTES("DRC2R", "DRC2R"),
+
+	ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
+	ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
+	ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
+	ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+	ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Noise"),
+	ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Mic"),
+
+	ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"),
+	ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"),
+	ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
+	ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
+
+	ARIZONA_DSP_ROUTES("DSP1"),
+	ARIZONA_DSP_ROUTES("DSP2"),
+	ARIZONA_DSP_ROUTES("DSP3"),
+	ARIZONA_DSP_ROUTES("DSP4"),
+
+	ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+	ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+	ARIZONA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"),
+	ARIZONA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"),
+
+	ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"),
+
+	ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+	ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+	ARIZONA_MUX_ROUTES("ISRC2INT3", "ISRC2INT3"),
+	ARIZONA_MUX_ROUTES("ISRC2INT4", "ISRC2INT4"),
+
+	ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC3", "ISRC2DEC3"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC4", "ISRC2DEC4"),
+
+	ARIZONA_MUX_ROUTES("ISRC3INT1", "ISRC3INT1"),
+	ARIZONA_MUX_ROUTES("ISRC3INT2", "ISRC3INT2"),
+	ARIZONA_MUX_ROUTES("ISRC3INT3", "ISRC3INT3"),
+	ARIZONA_MUX_ROUTES("ISRC3INT4", "ISRC3INT4"),
+
+	ARIZONA_MUX_ROUTES("ISRC3DEC1", "ISRC3DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC3DEC2", "ISRC3DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC3DEC3", "ISRC3DEC3"),
+	ARIZONA_MUX_ROUTES("ISRC3DEC4", "ISRC3DEC4"),
+
+	{ "AEC Loopback", "HPOUT1L", "OUT1L" },
+	{ "AEC Loopback", "HPOUT1R", "OUT1R" },
+	{ "HPOUT1L", NULL, "OUT1L" },
+	{ "HPOUT1R", NULL, "OUT1R" },
+
+	{ "AEC Loopback", "HPOUT2L", "OUT2L" },
+	{ "AEC Loopback", "HPOUT2R", "OUT2R" },
+	{ "HPOUT2L", NULL, "OUT2L" },
+	{ "HPOUT2R", NULL, "OUT2R" },
+
+	{ "AEC Loopback", "HPOUT3L", "OUT3L" },
+	{ "AEC Loopback", "HPOUT3R", "OUT3R" },
+	{ "HPOUT3L", NULL, "OUT3L" },
+	{ "HPOUT3R", NULL, "OUT3R" },
+
+	{ "AEC Loopback", "SPKOUTL", "OUT4L" },
+	{ "SPKOUTLN", NULL, "OUT4L" },
+	{ "SPKOUTLP", NULL, "OUT4L" },
+
+	{ "AEC Loopback", "SPKOUTR", "OUT4R" },
+	{ "SPKOUTRN", NULL, "OUT4R" },
+	{ "SPKOUTRP", NULL, "OUT4R" },
+
+	{ "AEC Loopback", "SPKDAT1L", "OUT5L" },
+	{ "AEC Loopback", "SPKDAT1R", "OUT5R" },
+	{ "SPKDAT1L", NULL, "OUT5L" },
+	{ "SPKDAT1R", NULL, "OUT5R" },
+
+	{ "AEC Loopback", "SPKDAT2L", "OUT6L" },
+	{ "AEC Loopback", "SPKDAT2R", "OUT6R" },
+	{ "SPKDAT2L", NULL, "OUT6L" },
+	{ "SPKDAT2R", NULL, "OUT6R" },
+
+	WM5110_RXANC_INPUT_ROUTES("RXANCL", "RXANCL"),
+	WM5110_RXANC_INPUT_ROUTES("RXANCR", "RXANCR"),
+
+	WM5110_RXANC_OUTPUT_ROUTES("OUT1L", "HPOUT1L"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT1R", "HPOUT1R"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT2L", "HPOUT2L"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT2R", "HPOUT2R"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT3L", "HPOUT3L"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT3R", "HPOUT3R"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT4L", "SPKOUTL"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT4R", "SPKOUTR"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT5L", "SPKDAT1L"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT5R", "SPKDAT1R"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT6L", "SPKDAT2L"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT6R", "SPKDAT2R"),
+
+	{ "MICSUPP", NULL, "SYSCLK" },
+
+	{ "DRC1 Signal Activity", NULL, "SYSCLK" },
+	{ "DRC2 Signal Activity", NULL, "SYSCLK" },
+	{ "DRC1 Signal Activity", NULL, "DRC1L" },
+	{ "DRC1 Signal Activity", NULL, "DRC1R" },
+	{ "DRC2 Signal Activity", NULL, "DRC2L" },
+	{ "DRC2 Signal Activity", NULL, "DRC2R" },
+
+	{ "DSP Voice Trigger", NULL, "SYSCLK" },
+	{ "DSP Voice Trigger", NULL, "DSP3 Voice Trigger" },
+	{ "DSP3 Voice Trigger", "Switch", "DSP3" },
+};
+
+static int wm5110_set_fll(struct snd_soc_component *component, int fll_id,
+			  int source, unsigned int Fref, unsigned int Fout)
+{
+	struct wm5110_priv *wm5110 = snd_soc_component_get_drvdata(component);
+
+	switch (fll_id) {
+	case WM5110_FLL1:
+		return arizona_set_fll(&wm5110->fll[0], source, Fref, Fout);
+	case WM5110_FLL2:
+		return arizona_set_fll(&wm5110->fll[1], source, Fref, Fout);
+	case WM5110_FLL1_REFCLK:
+		return arizona_set_fll_refclk(&wm5110->fll[0], source, Fref,
+					      Fout);
+	case WM5110_FLL2_REFCLK:
+		return arizona_set_fll_refclk(&wm5110->fll[1], source, Fref,
+					      Fout);
+	default:
+		return -EINVAL;
+	}
+}
+
+#define WM5110_RATES SNDRV_PCM_RATE_KNOT
+
+#define WM5110_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm5110_dai[] = {
+	{
+		.name = "wm5110-aif1",
+		.id = 1,
+		.base = ARIZONA_AIF1_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = WM5110_RATES,
+			.formats = WM5110_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 8,
+			 .rates = WM5110_RATES,
+			 .formats = WM5110_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "wm5110-aif2",
+		.id = 2,
+		.base = ARIZONA_AIF2_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = WM5110_RATES,
+			.formats = WM5110_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 6,
+			 .rates = WM5110_RATES,
+			 .formats = WM5110_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "wm5110-aif3",
+		.id = 3,
+		.base = ARIZONA_AIF3_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM5110_RATES,
+			.formats = WM5110_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF3 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM5110_RATES,
+			 .formats = WM5110_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "wm5110-slim1",
+		.id = 4,
+		.playback = {
+			.stream_name = "Slim1 Playback",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = WM5110_RATES,
+			.formats = WM5110_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "Slim1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 4,
+			 .rates = WM5110_RATES,
+			 .formats = WM5110_FORMATS,
+		 },
+		.ops = &arizona_simple_dai_ops,
+	},
+	{
+		.name = "wm5110-slim2",
+		.id = 5,
+		.playback = {
+			.stream_name = "Slim2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM5110_RATES,
+			.formats = WM5110_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "Slim2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM5110_RATES,
+			 .formats = WM5110_FORMATS,
+		 },
+		.ops = &arizona_simple_dai_ops,
+	},
+	{
+		.name = "wm5110-slim3",
+		.id = 6,
+		.playback = {
+			.stream_name = "Slim3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM5110_RATES,
+			.formats = WM5110_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "Slim3 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM5110_RATES,
+			 .formats = WM5110_FORMATS,
+		 },
+		.ops = &arizona_simple_dai_ops,
+	},
+	{
+		.name = "wm5110-cpu-voicectrl",
+		.capture = {
+			.stream_name = "Voice Control CPU",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = WM5110_RATES,
+			.formats = WM5110_FORMATS,
+		},
+		.compress_new = snd_soc_new_compress,
+	},
+	{
+		.name = "wm5110-dsp-voicectrl",
+		.capture = {
+			.stream_name = "Voice Control DSP",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = WM5110_RATES,
+			.formats = WM5110_FORMATS,
+		},
+	},
+	{
+		.name = "wm5110-cpu-trace",
+		.capture = {
+			.stream_name = "Audio Trace CPU",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = WM5110_RATES,
+			.formats = WM5110_FORMATS,
+		},
+		.compress_new = snd_soc_new_compress,
+	},
+	{
+		.name = "wm5110-dsp-trace",
+		.capture = {
+			.stream_name = "Audio Trace DSP",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = WM5110_RATES,
+			.formats = WM5110_FORMATS,
+		},
+	},
+};
+
+static int wm5110_open(struct snd_compr_stream *stream)
+{
+	struct snd_soc_pcm_runtime *rtd = stream->private_data;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct wm5110_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->core.arizona;
+	int n_adsp;
+
+	if (strcmp(rtd->codec_dai->name, "wm5110-dsp-voicectrl") == 0) {
+		n_adsp = 2;
+	} else if (strcmp(rtd->codec_dai->name, "wm5110-dsp-trace") == 0) {
+		n_adsp = 0;
+	} else {
+		dev_err(arizona->dev,
+			"No suitable compressed stream for DAI '%s'\n",
+			rtd->codec_dai->name);
+		return -EINVAL;
+	}
+
+	return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream);
+}
+
+static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
+{
+	struct wm5110_priv *priv = data;
+	struct arizona *arizona = priv->core.arizona;
+	struct arizona_voice_trigger_info info;
+	int serviced = 0;
+	int i, ret;
+
+	for (i = 0; i < WM5110_NUM_ADSP; ++i) {
+		ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]);
+		if (ret != -ENODEV)
+			serviced++;
+		if (ret == WM_ADSP_COMPR_VOICE_TRIGGER) {
+			info.core = i;
+			arizona_call_notifiers(arizona,
+					       ARIZONA_NOTIFY_VOICE_TRIGGER,
+					       &info);
+		}
+	}
+
+	if (!serviced) {
+		dev_err(arizona->dev, "Spurious compressed data IRQ\n");
+		return IRQ_NONE;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int wm5110_component_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm5110_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->core.arizona;
+	int i, ret;
+
+	arizona->dapm = dapm;
+	snd_soc_component_init_regmap(component, arizona->regmap);
+
+	ret = arizona_init_spk(component);
+	if (ret < 0)
+		return ret;
+
+	arizona_init_gpio(component);
+	arizona_init_mono(component);
+
+	for (i = 0; i < WM5110_NUM_ADSP; ++i) {
+		ret = wm_adsp2_component_probe(&priv->core.adsp[i], component);
+		if (ret)
+			goto err_adsp2_codec_probe;
+	}
+
+	ret = snd_soc_add_component_controls(component,
+					     arizona_adsp2_rate_controls,
+					     WM5110_NUM_ADSP);
+	if (ret)
+		goto err_adsp2_codec_probe;
+
+	snd_soc_component_disable_pin(component, "HAPTICS");
+
+	return 0;
+
+err_adsp2_codec_probe:
+	for (--i; i >= 0; --i)
+		wm_adsp2_component_remove(&priv->core.adsp[i], component);
+
+	return ret;
+}
+
+static void wm5110_component_remove(struct snd_soc_component *component)
+{
+	struct wm5110_priv *priv = snd_soc_component_get_drvdata(component);
+	int i;
+
+	for (i = 0; i < WM5110_NUM_ADSP; ++i)
+		wm_adsp2_component_remove(&priv->core.adsp[i], component);
+
+	priv->core.arizona->dapm = NULL;
+}
+
+#define WM5110_DIG_VU 0x0200
+
+static unsigned int wm5110_digital_vu[] = {
+	ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	ARIZONA_DAC_DIGITAL_VOLUME_1R,
+	ARIZONA_DAC_DIGITAL_VOLUME_2L,
+	ARIZONA_DAC_DIGITAL_VOLUME_2R,
+	ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	ARIZONA_DAC_DIGITAL_VOLUME_3R,
+	ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	ARIZONA_DAC_DIGITAL_VOLUME_4R,
+	ARIZONA_DAC_DIGITAL_VOLUME_5L,
+	ARIZONA_DAC_DIGITAL_VOLUME_5R,
+	ARIZONA_DAC_DIGITAL_VOLUME_6L,
+	ARIZONA_DAC_DIGITAL_VOLUME_6R,
+};
+
+static struct snd_compr_ops wm5110_compr_ops = {
+	.open		= wm5110_open,
+	.free		= wm_adsp_compr_free,
+	.set_params	= wm_adsp_compr_set_params,
+	.get_caps	= wm_adsp_compr_get_caps,
+	.trigger	= wm_adsp_compr_trigger,
+	.pointer	= wm_adsp_compr_pointer,
+	.copy		= wm_adsp_compr_copy,
+};
+
+static const struct snd_soc_component_driver soc_component_dev_wm5110 = {
+	.probe			= wm5110_component_probe,
+	.remove			= wm5110_component_remove,
+	.set_sysclk		= arizona_set_sysclk,
+	.set_pll		= wm5110_set_fll,
+	.name			= DRV_NAME,
+	.compr_ops		= &wm5110_compr_ops,
+	.controls		= wm5110_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm5110_snd_controls),
+	.dapm_widgets		= wm5110_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm5110_dapm_widgets),
+	.dapm_routes		= wm5110_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm5110_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm5110_probe(struct platform_device *pdev)
+{
+	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+	struct wm5110_priv *wm5110;
+	int i, ret;
+
+	wm5110 = devm_kzalloc(&pdev->dev, sizeof(struct wm5110_priv),
+			      GFP_KERNEL);
+	if (wm5110 == NULL)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, wm5110);
+
+	if (IS_ENABLED(CONFIG_OF)) {
+		if (!dev_get_platdata(arizona->dev)) {
+			ret = arizona_of_get_audio_pdata(arizona);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	wm5110->core.arizona = arizona;
+	wm5110->core.num_inputs = 8;
+
+	for (i = 0; i < WM5110_NUM_ADSP; i++) {
+		wm5110->core.adsp[i].part = "wm5110";
+		wm5110->core.adsp[i].num = i + 1;
+		wm5110->core.adsp[i].type = WMFW_ADSP2;
+		wm5110->core.adsp[i].dev = arizona->dev;
+		wm5110->core.adsp[i].regmap = arizona->regmap;
+
+		wm5110->core.adsp[i].base = ARIZONA_DSP1_CONTROL_1
+			+ (0x100 * i);
+		wm5110->core.adsp[i].mem = wm5110_dsp_regions[i];
+		wm5110->core.adsp[i].num_mems
+			= ARRAY_SIZE(wm5110_dsp1_regions);
+
+		ret = wm_adsp2_init(&wm5110->core.adsp[i]);
+		if (ret != 0)
+			return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++)
+		wm5110->fll[i].vco_mult = 3;
+
+	arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK,
+			 &wm5110->fll[0]);
+	arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
+			 &wm5110->fll[1]);
+
+	/* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
+			   ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
+			   ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
+
+	for (i = 0; i < ARRAY_SIZE(wm5110_dai); i++)
+		arizona_init_dai(&wm5110->core, i);
+
+	/* Latch volume update bits */
+	for (i = 0; i < ARRAY_SIZE(wm5110_digital_vu); i++)
+		regmap_update_bits(arizona->regmap, wm5110_digital_vu[i],
+				   WM5110_DIG_VU, WM5110_DIG_VU);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_idle(&pdev->dev);
+
+	ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
+				  "ADSP2 Compressed IRQ", wm5110_adsp2_irq,
+				  wm5110);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret);
+		return ret;
+	}
+
+	ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 1);
+	if (ret != 0)
+		dev_warn(&pdev->dev,
+			 "Failed to set compressed IRQ as a wake source: %d\n",
+			 ret);
+
+	arizona_init_common(arizona);
+
+	ret = arizona_init_vol_limit(arizona);
+	if (ret < 0)
+		goto err_dsp_irq;
+	ret = arizona_init_spk_irqs(arizona);
+	if (ret < 0)
+		goto err_dsp_irq;
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					      &soc_component_dev_wm5110,
+					      wm5110_dai,
+					      ARRAY_SIZE(wm5110_dai));
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
+		goto err_spk_irqs;
+	}
+
+	return ret;
+
+err_spk_irqs:
+	arizona_free_spk_irqs(arizona);
+err_dsp_irq:
+	arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
+	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110);
+
+	return ret;
+}
+
+static int wm5110_remove(struct platform_device *pdev)
+{
+	struct wm5110_priv *wm5110 = platform_get_drvdata(pdev);
+	struct arizona *arizona = wm5110->core.arizona;
+	int i;
+
+	pm_runtime_disable(&pdev->dev);
+
+	for (i = 0; i < WM5110_NUM_ADSP; i++)
+		wm_adsp2_remove(&wm5110->core.adsp[i]);
+
+	arizona_free_spk_irqs(arizona);
+
+	arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
+	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110);
+
+	return 0;
+}
+
+static struct platform_driver wm5110_codec_driver = {
+	.driver = {
+		.name = "wm5110-codec",
+	},
+	.probe = wm5110_probe,
+	.remove = wm5110_remove,
+};
+
+module_platform_driver(wm5110_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM5110 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm5110-codec");
diff --git a/sound/soc/codecs/wm5110.h b/sound/soc/codecs/wm5110.h
new file mode 100644
index 0000000..e6c0cd4
--- /dev/null
+++ b/sound/soc/codecs/wm5110.h
@@ -0,0 +1,23 @@
+/*
+ * wm5110.h  --  WM5110 ALSA SoC Audio driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM5110_H
+#define _WM5110_H
+
+#include "arizona.h"
+
+#define WM5110_FLL1        1
+#define WM5110_FLL2        2
+#define WM5110_FLL1_REFCLK 3
+#define WM5110_FLL2_REFCLK 4
+
+#endif
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
new file mode 100644
index 0000000..e92ebe5
--- /dev/null
+++ b/sound/soc/codecs/wm8350.c
@@ -0,0 +1,1619 @@
+/*
+ * wm8350.c -- WM8350 ALSA SoC audio driver
+ *
+ * Copyright (C) 2007-12 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/wm8350/audio.h>
+#include <linux/mfd/wm8350/core.h>
+#include <linux/regulator/consumer.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <trace/events/asoc.h>
+
+#include "wm8350.h"
+
+#define WM8350_OUTn_0dB 0x39
+
+#define WM8350_RAMP_NONE	0
+#define WM8350_RAMP_UP		1
+#define WM8350_RAMP_DOWN	2
+
+/* We only include the analogue supplies here; the digital supplies
+ * need to be available well before this driver can be probed.
+ */
+static const char *supply_names[] = {
+	"AVDD",
+	"HPVDD",
+};
+
+struct wm8350_output {
+	u16 active;
+	u16 left_vol;
+	u16 right_vol;
+	u16 ramp;
+	u16 mute;
+};
+
+struct wm8350_jack_data {
+	struct snd_soc_jack *jack;
+	struct delayed_work work;
+	int report;
+	int short_report;
+};
+
+struct wm8350_data {
+	struct wm8350 *wm8350;
+	struct wm8350_output out1;
+	struct wm8350_output out2;
+	struct wm8350_jack_data hpl;
+	struct wm8350_jack_data hpr;
+	struct wm8350_jack_data mic;
+	struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+	int fll_freq_out;
+	int fll_freq_in;
+	struct delayed_work pga_work;
+};
+
+/*
+ * Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown.
+ */
+static inline int wm8350_out1_ramp_step(struct wm8350_data *wm8350_data)
+{
+	struct wm8350_output *out1 = &wm8350_data->out1;
+	struct wm8350 *wm8350 = wm8350_data->wm8350;
+	int left_complete = 0, right_complete = 0;
+	u16 reg, val;
+
+	/* left channel */
+	reg = wm8350_reg_read(wm8350, WM8350_LOUT1_VOLUME);
+	val = (reg & WM8350_OUT1L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
+
+	if (out1->ramp == WM8350_RAMP_UP) {
+		/* ramp step up */
+		if (val < out1->left_vol) {
+			val++;
+			reg &= ~WM8350_OUT1L_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME,
+					 reg | (val << WM8350_OUT1L_VOL_SHIFT));
+		} else
+			left_complete = 1;
+	} else if (out1->ramp == WM8350_RAMP_DOWN) {
+		/* ramp step down */
+		if (val > 0) {
+			val--;
+			reg &= ~WM8350_OUT1L_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME,
+					 reg | (val << WM8350_OUT1L_VOL_SHIFT));
+		} else
+			left_complete = 1;
+	} else
+		return 1;
+
+	/* right channel */
+	reg = wm8350_reg_read(wm8350, WM8350_ROUT1_VOLUME);
+	val = (reg & WM8350_OUT1R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
+	if (out1->ramp == WM8350_RAMP_UP) {
+		/* ramp step up */
+		if (val < out1->right_vol) {
+			val++;
+			reg &= ~WM8350_OUT1R_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME,
+					 reg | (val << WM8350_OUT1R_VOL_SHIFT));
+		} else
+			right_complete = 1;
+	} else if (out1->ramp == WM8350_RAMP_DOWN) {
+		/* ramp step down */
+		if (val > 0) {
+			val--;
+			reg &= ~WM8350_OUT1R_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME,
+					 reg | (val << WM8350_OUT1R_VOL_SHIFT));
+		} else
+			right_complete = 1;
+	}
+
+	/* only hit the update bit if either volume has changed this step */
+	if (!left_complete || !right_complete)
+		wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME, WM8350_OUT1_VU);
+
+	return left_complete & right_complete;
+}
+
+/*
+ * Ramp OUT2 PGA volume to minimise pops at stream startup and shutdown.
+ */
+static inline int wm8350_out2_ramp_step(struct wm8350_data *wm8350_data)
+{
+	struct wm8350_output *out2 = &wm8350_data->out2;
+	struct wm8350 *wm8350 = wm8350_data->wm8350;
+	int left_complete = 0, right_complete = 0;
+	u16 reg, val;
+
+	/* left channel */
+	reg = wm8350_reg_read(wm8350, WM8350_LOUT2_VOLUME);
+	val = (reg & WM8350_OUT2L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
+	if (out2->ramp == WM8350_RAMP_UP) {
+		/* ramp step up */
+		if (val < out2->left_vol) {
+			val++;
+			reg &= ~WM8350_OUT2L_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME,
+					 reg | (val << WM8350_OUT1L_VOL_SHIFT));
+		} else
+			left_complete = 1;
+	} else if (out2->ramp == WM8350_RAMP_DOWN) {
+		/* ramp step down */
+		if (val > 0) {
+			val--;
+			reg &= ~WM8350_OUT2L_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME,
+					 reg | (val << WM8350_OUT1L_VOL_SHIFT));
+		} else
+			left_complete = 1;
+	} else
+		return 1;
+
+	/* right channel */
+	reg = wm8350_reg_read(wm8350, WM8350_ROUT2_VOLUME);
+	val = (reg & WM8350_OUT2R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
+	if (out2->ramp == WM8350_RAMP_UP) {
+		/* ramp step up */
+		if (val < out2->right_vol) {
+			val++;
+			reg &= ~WM8350_OUT2R_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME,
+					 reg | (val << WM8350_OUT1R_VOL_SHIFT));
+		} else
+			right_complete = 1;
+	} else if (out2->ramp == WM8350_RAMP_DOWN) {
+		/* ramp step down */
+		if (val > 0) {
+			val--;
+			reg &= ~WM8350_OUT2R_VOL_MASK;
+			wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME,
+					 reg | (val << WM8350_OUT1R_VOL_SHIFT));
+		} else
+			right_complete = 1;
+	}
+
+	/* only hit the update bit if either volume has changed this step */
+	if (!left_complete || !right_complete)
+		wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME, WM8350_OUT2_VU);
+
+	return left_complete & right_complete;
+}
+
+/*
+ * This work ramps both output PGAs at stream start/stop time to
+ * minimise pop associated with DAPM power switching.
+ * It's best to enable Zero Cross when ramping occurs to minimise any
+ * zipper noises.
+ */
+static void wm8350_pga_work(struct work_struct *work)
+{
+	struct wm8350_data *wm8350_data =
+		container_of(work, struct wm8350_data, pga_work.work);
+	struct wm8350_output *out1 = &wm8350_data->out1,
+	    *out2 = &wm8350_data->out2;
+	int i, out1_complete, out2_complete;
+
+	/* do we need to ramp at all ? */
+	if (out1->ramp == WM8350_RAMP_NONE && out2->ramp == WM8350_RAMP_NONE)
+		return;
+
+	/* PGA volumes have 6 bits of resolution to ramp */
+	for (i = 0; i <= 63; i++) {
+		out1_complete = 1, out2_complete = 1;
+		if (out1->ramp != WM8350_RAMP_NONE)
+			out1_complete = wm8350_out1_ramp_step(wm8350_data);
+		if (out2->ramp != WM8350_RAMP_NONE)
+			out2_complete = wm8350_out2_ramp_step(wm8350_data);
+
+		/* ramp finished ? */
+		if (out1_complete && out2_complete)
+			break;
+
+		/* we need to delay longer on the up ramp */
+		if (out1->ramp == WM8350_RAMP_UP ||
+		    out2->ramp == WM8350_RAMP_UP) {
+			/* delay is longer over 0dB as increases are larger */
+			if (i >= WM8350_OUTn_0dB)
+				schedule_timeout_interruptible(msecs_to_jiffies
+							       (2));
+			else
+				schedule_timeout_interruptible(msecs_to_jiffies
+							       (1));
+		} else
+			udelay(50);	/* doesn't matter if we delay longer */
+	}
+
+	out1->ramp = WM8350_RAMP_NONE;
+	out2->ramp = WM8350_RAMP_NONE;
+}
+
+/*
+ * WM8350 Controls
+ */
+
+static int pga_event(struct snd_soc_dapm_widget *w,
+		     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8350_data *wm8350_data = snd_soc_component_get_drvdata(component);
+	struct wm8350_output *out;
+
+	switch (w->shift) {
+	case 0:
+	case 1:
+		out = &wm8350_data->out1;
+		break;
+	case 2:
+	case 3:
+		out = &wm8350_data->out2;
+		break;
+
+	default:
+		WARN(1, "Invalid shift %d\n", w->shift);
+		return -1;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		out->ramp = WM8350_RAMP_UP;
+		out->active = 1;
+
+		schedule_delayed_work(&wm8350_data->pga_work,
+				      msecs_to_jiffies(1));
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		out->ramp = WM8350_RAMP_DOWN;
+		out->active = 0;
+
+		schedule_delayed_work(&wm8350_data->pga_work,
+				      msecs_to_jiffies(1));
+		break;
+	}
+
+	return 0;
+}
+
+static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8350_data *wm8350_priv = snd_soc_component_get_drvdata(component);
+	struct wm8350_output *out = NULL;
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	int ret;
+	unsigned int reg = mc->reg;
+	u16 val;
+
+	/* For OUT1 and OUT2 we shadow the values and only actually write
+	 * them out when active in order to ensure the amplifier comes on
+	 * as quietly as possible. */
+	switch (reg) {
+	case WM8350_LOUT1_VOLUME:
+		out = &wm8350_priv->out1;
+		break;
+	case WM8350_LOUT2_VOLUME:
+		out = &wm8350_priv->out2;
+		break;
+	default:
+		break;
+	}
+
+	if (out) {
+		out->left_vol = ucontrol->value.integer.value[0];
+		out->right_vol = ucontrol->value.integer.value[1];
+		if (!out->active)
+			return 1;
+	}
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+	if (ret < 0)
+		return ret;
+
+	/* now hit the volume update bits (always bit 8) */
+	val = snd_soc_component_read32(component, reg);
+	snd_soc_component_write(component, reg, val | WM8350_OUT1_VU);
+	return 1;
+}
+
+static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8350_data *wm8350_priv = snd_soc_component_get_drvdata(component);
+	struct wm8350_output *out1 = &wm8350_priv->out1;
+	struct wm8350_output *out2 = &wm8350_priv->out2;
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned int reg = mc->reg;
+
+	/* If these are cached registers use the cache */
+	switch (reg) {
+	case WM8350_LOUT1_VOLUME:
+		ucontrol->value.integer.value[0] = out1->left_vol;
+		ucontrol->value.integer.value[1] = out1->right_vol;
+		return 0;
+
+	case WM8350_LOUT2_VOLUME:
+		ucontrol->value.integer.value[0] = out2->left_vol;
+		ucontrol->value.integer.value[1] = out2->right_vol;
+		return 0;
+
+	default:
+		break;
+	}
+
+	return snd_soc_get_volsw(kcontrol, ucontrol);
+}
+
+static const char *wm8350_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
+static const char *wm8350_pol[] = { "Normal", "Inv R", "Inv L", "Inv L & R" };
+static const char *wm8350_dacmutem[] = { "Normal", "Soft" };
+static const char *wm8350_dacmutes[] = { "Fast", "Slow" };
+static const char *wm8350_adcfilter[] = { "None", "High Pass" };
+static const char *wm8350_adchp[] = { "44.1kHz", "8kHz", "16kHz", "32kHz" };
+static const char *wm8350_lr[] = { "Left", "Right" };
+
+static const struct soc_enum wm8350_enum[] = {
+	SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 4, 4, wm8350_deemp),
+	SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 0, 4, wm8350_pol),
+	SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 14, 2, wm8350_dacmutem),
+	SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 13, 2, wm8350_dacmutes),
+	SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 15, 2, wm8350_adcfilter),
+	SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 8, 4, wm8350_adchp),
+	SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 0, 4, wm8350_pol),
+	SOC_ENUM_SINGLE(WM8350_INPUT_MIXER_VOLUME, 15, 2, wm8350_lr),
+};
+
+static DECLARE_TLV_DB_SCALE(pre_amp_tlv, -1200, 3525, 0);
+static DECLARE_TLV_DB_SCALE(out_pga_tlv, -5700, 600, 0);
+static DECLARE_TLV_DB_SCALE(dac_pcm_tlv, -7163, 36, 1);
+static DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -12700, 50, 1);
+static DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 1);
+
+static const DECLARE_TLV_DB_RANGE(capture_sd_tlv,
+	0, 12, TLV_DB_SCALE_ITEM(-3600, 300, 1),
+	13, 15, TLV_DB_SCALE_ITEM(0, 0, 0)
+);
+
+static const struct snd_kcontrol_new wm8350_snd_controls[] = {
+	SOC_ENUM("Playback Deemphasis", wm8350_enum[0]),
+	SOC_ENUM("Playback DAC Inversion", wm8350_enum[1]),
+	SOC_DOUBLE_R_EXT_TLV("Playback PCM Volume",
+				WM8350_DAC_DIGITAL_VOLUME_L,
+				WM8350_DAC_DIGITAL_VOLUME_R,
+				0, 255, 0, wm8350_get_volsw_2r,
+				wm8350_put_volsw_2r_vu, dac_pcm_tlv),
+	SOC_ENUM("Playback PCM Mute Function", wm8350_enum[2]),
+	SOC_ENUM("Playback PCM Mute Speed", wm8350_enum[3]),
+	SOC_ENUM("Capture PCM Filter", wm8350_enum[4]),
+	SOC_ENUM("Capture PCM HP Filter", wm8350_enum[5]),
+	SOC_ENUM("Capture ADC Inversion", wm8350_enum[6]),
+	SOC_DOUBLE_R_EXT_TLV("Capture PCM Volume",
+				WM8350_ADC_DIGITAL_VOLUME_L,
+				WM8350_ADC_DIGITAL_VOLUME_R,
+				0, 255, 0, wm8350_get_volsw_2r,
+				wm8350_put_volsw_2r_vu, adc_pcm_tlv),
+	SOC_DOUBLE_TLV("Capture Sidetone Volume",
+		       WM8350_ADC_DIVIDER,
+		       8, 4, 15, 1, capture_sd_tlv),
+	SOC_DOUBLE_R_EXT_TLV("Capture Volume",
+				WM8350_LEFT_INPUT_VOLUME,
+				WM8350_RIGHT_INPUT_VOLUME,
+				2, 63, 0, wm8350_get_volsw_2r,
+				wm8350_put_volsw_2r_vu, pre_amp_tlv),
+	SOC_DOUBLE_R("Capture ZC Switch",
+		     WM8350_LEFT_INPUT_VOLUME,
+		     WM8350_RIGHT_INPUT_VOLUME, 13, 1, 0),
+	SOC_SINGLE_TLV("Left Input Left Sidetone Volume",
+		       WM8350_OUTPUT_LEFT_MIXER_VOLUME, 1, 7, 0, out_mix_tlv),
+	SOC_SINGLE_TLV("Left Input Right Sidetone Volume",
+		       WM8350_OUTPUT_LEFT_MIXER_VOLUME,
+		       5, 7, 0, out_mix_tlv),
+	SOC_SINGLE_TLV("Left Input Bypass Volume",
+		       WM8350_OUTPUT_LEFT_MIXER_VOLUME,
+		       9, 7, 0, out_mix_tlv),
+	SOC_SINGLE_TLV("Right Input Left Sidetone Volume",
+		       WM8350_OUTPUT_RIGHT_MIXER_VOLUME,
+		       1, 7, 0, out_mix_tlv),
+	SOC_SINGLE_TLV("Right Input Right Sidetone Volume",
+		       WM8350_OUTPUT_RIGHT_MIXER_VOLUME,
+		       5, 7, 0, out_mix_tlv),
+	SOC_SINGLE_TLV("Right Input Bypass Volume",
+		       WM8350_OUTPUT_RIGHT_MIXER_VOLUME,
+		       13, 7, 0, out_mix_tlv),
+	SOC_SINGLE("Left Input Mixer +20dB Switch",
+		   WM8350_INPUT_MIXER_VOLUME_L, 0, 1, 0),
+	SOC_SINGLE("Right Input Mixer +20dB Switch",
+		   WM8350_INPUT_MIXER_VOLUME_R, 0, 1, 0),
+	SOC_SINGLE_TLV("Out4 Capture Volume",
+		       WM8350_INPUT_MIXER_VOLUME,
+		       1, 7, 0, out_mix_tlv),
+	SOC_DOUBLE_R_EXT_TLV("Out1 Playback Volume",
+				WM8350_LOUT1_VOLUME,
+				WM8350_ROUT1_VOLUME,
+				2, 63, 0, wm8350_get_volsw_2r,
+				wm8350_put_volsw_2r_vu, out_pga_tlv),
+	SOC_DOUBLE_R("Out1 Playback ZC Switch",
+		     WM8350_LOUT1_VOLUME,
+		     WM8350_ROUT1_VOLUME, 13, 1, 0),
+	SOC_DOUBLE_R_EXT_TLV("Out2 Playback Volume",
+				WM8350_LOUT2_VOLUME,
+				WM8350_ROUT2_VOLUME,
+				2, 63, 0, wm8350_get_volsw_2r,
+				wm8350_put_volsw_2r_vu, out_pga_tlv),
+	SOC_DOUBLE_R("Out2 Playback ZC Switch", WM8350_LOUT2_VOLUME,
+		     WM8350_ROUT2_VOLUME, 13, 1, 0),
+	SOC_SINGLE("Out2 Right Invert Switch", WM8350_ROUT2_VOLUME, 10, 1, 0),
+	SOC_SINGLE_TLV("Out2 Beep Volume", WM8350_BEEP_VOLUME,
+		       5, 7, 0, out_mix_tlv),
+
+	SOC_DOUBLE_R("Out1 Playback Switch",
+		     WM8350_LOUT1_VOLUME,
+		     WM8350_ROUT1_VOLUME,
+		     14, 1, 1),
+	SOC_DOUBLE_R("Out2 Playback Switch",
+		     WM8350_LOUT2_VOLUME,
+		     WM8350_ROUT2_VOLUME,
+		     14, 1, 1),
+};
+
+/*
+ * DAPM Controls
+ */
+
+/* Left Playback Mixer */
+static const struct snd_kcontrol_new wm8350_left_play_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Playback Switch",
+			WM8350_LEFT_MIXER_CONTROL, 11, 1, 0),
+	SOC_DAPM_SINGLE("Left Bypass Switch",
+			WM8350_LEFT_MIXER_CONTROL, 2, 1, 0),
+	SOC_DAPM_SINGLE("Right Playback Switch",
+			WM8350_LEFT_MIXER_CONTROL, 12, 1, 0),
+	SOC_DAPM_SINGLE("Left Sidetone Switch",
+			WM8350_LEFT_MIXER_CONTROL, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right Sidetone Switch",
+			WM8350_LEFT_MIXER_CONTROL, 1, 1, 0),
+};
+
+/* Right Playback Mixer */
+static const struct snd_kcontrol_new wm8350_right_play_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Playback Switch",
+			WM8350_RIGHT_MIXER_CONTROL, 12, 1, 0),
+	SOC_DAPM_SINGLE("Right Bypass Switch",
+			WM8350_RIGHT_MIXER_CONTROL, 3, 1, 0),
+	SOC_DAPM_SINGLE("Left Playback Switch",
+			WM8350_RIGHT_MIXER_CONTROL, 11, 1, 0),
+	SOC_DAPM_SINGLE("Left Sidetone Switch",
+			WM8350_RIGHT_MIXER_CONTROL, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right Sidetone Switch",
+			WM8350_RIGHT_MIXER_CONTROL, 1, 1, 0),
+};
+
+/* Out4 Mixer */
+static const struct snd_kcontrol_new wm8350_out4_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Right Playback Switch",
+			WM8350_OUT4_MIXER_CONTROL, 12, 1, 0),
+	SOC_DAPM_SINGLE("Left Playback Switch",
+			WM8350_OUT4_MIXER_CONTROL, 11, 1, 0),
+	SOC_DAPM_SINGLE("Right Capture Switch",
+			WM8350_OUT4_MIXER_CONTROL, 9, 1, 0),
+	SOC_DAPM_SINGLE("Out3 Playback Switch",
+			WM8350_OUT4_MIXER_CONTROL, 2, 1, 0),
+	SOC_DAPM_SINGLE("Right Mixer Switch",
+			WM8350_OUT4_MIXER_CONTROL, 1, 1, 0),
+	SOC_DAPM_SINGLE("Left Mixer Switch",
+			WM8350_OUT4_MIXER_CONTROL, 0, 1, 0),
+};
+
+/* Out3 Mixer */
+static const struct snd_kcontrol_new wm8350_out3_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left Playback Switch",
+			WM8350_OUT3_MIXER_CONTROL, 11, 1, 0),
+	SOC_DAPM_SINGLE("Left Capture Switch",
+			WM8350_OUT3_MIXER_CONTROL, 8, 1, 0),
+	SOC_DAPM_SINGLE("Out4 Playback Switch",
+			WM8350_OUT3_MIXER_CONTROL, 3, 1, 0),
+	SOC_DAPM_SINGLE("Left Mixer Switch",
+			WM8350_OUT3_MIXER_CONTROL, 0, 1, 0),
+};
+
+/* Left Input Mixer */
+static const struct snd_kcontrol_new wm8350_left_capt_mixer_controls[] = {
+	SOC_DAPM_SINGLE_TLV("L2 Capture Volume",
+			    WM8350_INPUT_MIXER_VOLUME_L, 1, 7, 0, out_mix_tlv),
+	SOC_DAPM_SINGLE_TLV("L3 Capture Volume",
+			    WM8350_INPUT_MIXER_VOLUME_L, 9, 7, 0, out_mix_tlv),
+	SOC_DAPM_SINGLE("PGA Capture Switch",
+			WM8350_LEFT_INPUT_VOLUME, 14, 1, 1),
+};
+
+/* Right Input Mixer */
+static const struct snd_kcontrol_new wm8350_right_capt_mixer_controls[] = {
+	SOC_DAPM_SINGLE_TLV("L2 Capture Volume",
+			    WM8350_INPUT_MIXER_VOLUME_R, 5, 7, 0, out_mix_tlv),
+	SOC_DAPM_SINGLE_TLV("L3 Capture Volume",
+			    WM8350_INPUT_MIXER_VOLUME_R, 13, 7, 0, out_mix_tlv),
+	SOC_DAPM_SINGLE("PGA Capture Switch",
+			WM8350_RIGHT_INPUT_VOLUME, 14, 1, 1),
+};
+
+/* Left Mic Mixer */
+static const struct snd_kcontrol_new wm8350_left_mic_mixer_controls[] = {
+	SOC_DAPM_SINGLE("INN Capture Switch", WM8350_INPUT_CONTROL, 1, 1, 0),
+	SOC_DAPM_SINGLE("INP Capture Switch", WM8350_INPUT_CONTROL, 0, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Capture Switch", WM8350_INPUT_CONTROL, 2, 1, 0),
+};
+
+/* Right Mic Mixer */
+static const struct snd_kcontrol_new wm8350_right_mic_mixer_controls[] = {
+	SOC_DAPM_SINGLE("INN Capture Switch", WM8350_INPUT_CONTROL, 9, 1, 0),
+	SOC_DAPM_SINGLE("INP Capture Switch", WM8350_INPUT_CONTROL, 8, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Capture Switch", WM8350_INPUT_CONTROL, 10, 1, 0),
+};
+
+/* Beep Switch */
+static const struct snd_kcontrol_new wm8350_beep_switch_controls =
+SOC_DAPM_SINGLE("Switch", WM8350_BEEP_VOLUME, 15, 1, 1);
+
+/* Out4 Capture Mux */
+static const struct snd_kcontrol_new wm8350_out4_capture_controls =
+SOC_DAPM_ENUM("Route", wm8350_enum[7]);
+
+static const struct snd_soc_dapm_widget wm8350_dapm_widgets[] = {
+
+	SND_SOC_DAPM_PGA("IN3R PGA", WM8350_POWER_MGMT_2, 11, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IN3L PGA", WM8350_POWER_MGMT_2, 10, 0, NULL, 0),
+	SND_SOC_DAPM_PGA_E("Right Out2 PGA", WM8350_POWER_MGMT_3, 3, 0, NULL,
+			   0, pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA_E("Left Out2 PGA", WM8350_POWER_MGMT_3, 2, 0, NULL, 0,
+			   pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA_E("Right Out1 PGA", WM8350_POWER_MGMT_3, 1, 0, NULL,
+			   0, pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA_E("Left Out1 PGA", WM8350_POWER_MGMT_3, 0, 0, NULL, 0,
+			   pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_MIXER("Right Capture Mixer", WM8350_POWER_MGMT_2,
+			   7, 0, &wm8350_right_capt_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_right_capt_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left Capture Mixer", WM8350_POWER_MGMT_2,
+			   6, 0, &wm8350_left_capt_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_left_capt_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Out4 Mixer", WM8350_POWER_MGMT_2, 5, 0,
+			   &wm8350_out4_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_out4_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Out3 Mixer", WM8350_POWER_MGMT_2, 4, 0,
+			   &wm8350_out3_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_out3_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Playback Mixer", WM8350_POWER_MGMT_2, 1, 0,
+			   &wm8350_right_play_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_right_play_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left Playback Mixer", WM8350_POWER_MGMT_2, 0, 0,
+			   &wm8350_left_play_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_left_play_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left Mic Mixer", WM8350_POWER_MGMT_2, 8, 0,
+			   &wm8350_left_mic_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_left_mic_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Mic Mixer", WM8350_POWER_MGMT_2, 9, 0,
+			   &wm8350_right_mic_mixer_controls[0],
+			   ARRAY_SIZE(wm8350_right_mic_mixer_controls)),
+
+	/* virtual mixer for Beep and Out2R */
+	SND_SOC_DAPM_MIXER("Out2 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SWITCH("Beep", WM8350_POWER_MGMT_3, 7, 0,
+			    &wm8350_beep_switch_controls),
+
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture",
+			 WM8350_POWER_MGMT_4, 3, 0),
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture",
+			 WM8350_POWER_MGMT_4, 2, 0),
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback",
+			 WM8350_POWER_MGMT_4, 5, 0),
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback",
+			 WM8350_POWER_MGMT_4, 4, 0),
+
+	SND_SOC_DAPM_MICBIAS("Mic Bias", WM8350_POWER_MGMT_1, 4, 0),
+
+	SND_SOC_DAPM_MUX("Out4 Capture Channel", SND_SOC_NOPM, 0, 0,
+			 &wm8350_out4_capture_controls),
+
+	SND_SOC_DAPM_OUTPUT("OUT1R"),
+	SND_SOC_DAPM_OUTPUT("OUT1L"),
+	SND_SOC_DAPM_OUTPUT("OUT2R"),
+	SND_SOC_DAPM_OUTPUT("OUT2L"),
+	SND_SOC_DAPM_OUTPUT("OUT3"),
+	SND_SOC_DAPM_OUTPUT("OUT4"),
+
+	SND_SOC_DAPM_INPUT("IN1RN"),
+	SND_SOC_DAPM_INPUT("IN1RP"),
+	SND_SOC_DAPM_INPUT("IN2R"),
+	SND_SOC_DAPM_INPUT("IN1LP"),
+	SND_SOC_DAPM_INPUT("IN1LN"),
+	SND_SOC_DAPM_INPUT("IN2L"),
+	SND_SOC_DAPM_INPUT("IN3R"),
+	SND_SOC_DAPM_INPUT("IN3L"),
+};
+
+static const struct snd_soc_dapm_route wm8350_dapm_routes[] = {
+
+	/* left playback mixer */
+	{"Left Playback Mixer", "Playback Switch", "Left DAC"},
+	{"Left Playback Mixer", "Left Bypass Switch", "IN3L PGA"},
+	{"Left Playback Mixer", "Right Playback Switch", "Right DAC"},
+	{"Left Playback Mixer", "Left Sidetone Switch", "Left Mic Mixer"},
+	{"Left Playback Mixer", "Right Sidetone Switch", "Right Mic Mixer"},
+
+	/* right playback mixer */
+	{"Right Playback Mixer", "Playback Switch", "Right DAC"},
+	{"Right Playback Mixer", "Right Bypass Switch", "IN3R PGA"},
+	{"Right Playback Mixer", "Left Playback Switch", "Left DAC"},
+	{"Right Playback Mixer", "Left Sidetone Switch", "Left Mic Mixer"},
+	{"Right Playback Mixer", "Right Sidetone Switch", "Right Mic Mixer"},
+
+	/* out4 playback mixer */
+	{"Out4 Mixer", "Right Playback Switch", "Right DAC"},
+	{"Out4 Mixer", "Left Playback Switch", "Left DAC"},
+	{"Out4 Mixer", "Right Capture Switch", "Right Capture Mixer"},
+	{"Out4 Mixer", "Out3 Playback Switch", "Out3 Mixer"},
+	{"Out4 Mixer", "Right Mixer Switch", "Right Playback Mixer"},
+	{"Out4 Mixer", "Left Mixer Switch", "Left Playback Mixer"},
+	{"OUT4", NULL, "Out4 Mixer"},
+
+	/* out3 playback mixer */
+	{"Out3 Mixer", "Left Playback Switch", "Left DAC"},
+	{"Out3 Mixer", "Left Capture Switch", "Left Capture Mixer"},
+	{"Out3 Mixer", "Left Mixer Switch", "Left Playback Mixer"},
+	{"Out3 Mixer", "Out4 Playback Switch", "Out4 Mixer"},
+	{"OUT3", NULL, "Out3 Mixer"},
+
+	/* out2 */
+	{"Right Out2 PGA", NULL, "Right Playback Mixer"},
+	{"Left Out2 PGA", NULL, "Left Playback Mixer"},
+	{"OUT2L", NULL, "Left Out2 PGA"},
+	{"OUT2R", NULL, "Right Out2 PGA"},
+
+	/* out1 */
+	{"Right Out1 PGA", NULL, "Right Playback Mixer"},
+	{"Left Out1 PGA", NULL, "Left Playback Mixer"},
+	{"OUT1L", NULL, "Left Out1 PGA"},
+	{"OUT1R", NULL, "Right Out1 PGA"},
+
+	/* ADCs */
+	{"Left ADC", NULL, "Left Capture Mixer"},
+	{"Right ADC", NULL, "Right Capture Mixer"},
+
+	/* Left capture mixer */
+	{"Left Capture Mixer", "L2 Capture Volume", "IN2L"},
+	{"Left Capture Mixer", "L3 Capture Volume", "IN3L PGA"},
+	{"Left Capture Mixer", "PGA Capture Switch", "Left Mic Mixer"},
+	{"Left Capture Mixer", NULL, "Out4 Capture Channel"},
+
+	/* Right capture mixer */
+	{"Right Capture Mixer", "L2 Capture Volume", "IN2R"},
+	{"Right Capture Mixer", "L3 Capture Volume", "IN3R PGA"},
+	{"Right Capture Mixer", "PGA Capture Switch", "Right Mic Mixer"},
+	{"Right Capture Mixer", NULL, "Out4 Capture Channel"},
+
+	/* L3 Inputs */
+	{"IN3L PGA", NULL, "IN3L"},
+	{"IN3R PGA", NULL, "IN3R"},
+
+	/* Left Mic mixer */
+	{"Left Mic Mixer", "INN Capture Switch", "IN1LN"},
+	{"Left Mic Mixer", "INP Capture Switch", "IN1LP"},
+	{"Left Mic Mixer", "IN2 Capture Switch", "IN2L"},
+
+	/* Right Mic mixer */
+	{"Right Mic Mixer", "INN Capture Switch", "IN1RN"},
+	{"Right Mic Mixer", "INP Capture Switch", "IN1RP"},
+	{"Right Mic Mixer", "IN2 Capture Switch", "IN2R"},
+
+	/* out 4 capture */
+	{"Out4 Capture Channel", NULL, "Out4 Mixer"},
+
+	/* Beep */
+	{"Beep", NULL, "IN3R PGA"},
+};
+
+static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8350_data *wm8350_data = snd_soc_component_get_drvdata(component);
+	struct wm8350 *wm8350 = wm8350_data->wm8350;
+	u16 fll_4;
+
+	switch (clk_id) {
+	case WM8350_MCLK_SEL_MCLK:
+		wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_1,
+				  WM8350_MCLK_SEL);
+		break;
+	case WM8350_MCLK_SEL_PLL_MCLK:
+	case WM8350_MCLK_SEL_PLL_DAC:
+	case WM8350_MCLK_SEL_PLL_ADC:
+	case WM8350_MCLK_SEL_PLL_32K:
+		wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_1,
+				WM8350_MCLK_SEL);
+		fll_4 = snd_soc_component_read32(component, WM8350_FLL_CONTROL_4) &
+		    ~WM8350_FLL_CLK_SRC_MASK;
+		snd_soc_component_write(component, WM8350_FLL_CONTROL_4, fll_4 | clk_id);
+		break;
+	}
+
+	/* MCLK direction */
+	if (dir == SND_SOC_CLOCK_OUT)
+		wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_2,
+				WM8350_MCLK_DIR);
+	else
+		wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_2,
+				  WM8350_MCLK_DIR);
+
+	return 0;
+}
+
+static int wm8350_set_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 val;
+
+	switch (div_id) {
+	case WM8350_ADC_CLKDIV:
+		val = snd_soc_component_read32(component, WM8350_ADC_DIVIDER) &
+		    ~WM8350_ADC_CLKDIV_MASK;
+		snd_soc_component_write(component, WM8350_ADC_DIVIDER, val | div);
+		break;
+	case WM8350_DAC_CLKDIV:
+		val = snd_soc_component_read32(component, WM8350_DAC_CLOCK_CONTROL) &
+		    ~WM8350_DAC_CLKDIV_MASK;
+		snd_soc_component_write(component, WM8350_DAC_CLOCK_CONTROL, val | div);
+		break;
+	case WM8350_BCLK_CLKDIV:
+		val = snd_soc_component_read32(component, WM8350_CLOCK_CONTROL_1) &
+		    ~WM8350_BCLK_DIV_MASK;
+		snd_soc_component_write(component, WM8350_CLOCK_CONTROL_1, val | div);
+		break;
+	case WM8350_OPCLK_CLKDIV:
+		val = snd_soc_component_read32(component, WM8350_CLOCK_CONTROL_1) &
+		    ~WM8350_OPCLK_DIV_MASK;
+		snd_soc_component_write(component, WM8350_CLOCK_CONTROL_1, val | div);
+		break;
+	case WM8350_SYS_CLKDIV:
+		val = snd_soc_component_read32(component, WM8350_CLOCK_CONTROL_1) &
+		    ~WM8350_MCLK_DIV_MASK;
+		snd_soc_component_write(component, WM8350_CLOCK_CONTROL_1, val | div);
+		break;
+	case WM8350_DACLR_CLKDIV:
+		val = snd_soc_component_read32(component, WM8350_DAC_LR_RATE) &
+		    ~WM8350_DACLRC_RATE_MASK;
+		snd_soc_component_write(component, WM8350_DAC_LR_RATE, val | div);
+		break;
+	case WM8350_ADCLR_CLKDIV:
+		val = snd_soc_component_read32(component, WM8350_ADC_LR_RATE) &
+		    ~WM8350_ADCLRC_RATE_MASK;
+		snd_soc_component_write(component, WM8350_ADC_LR_RATE, val | div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = snd_soc_component_read32(component, WM8350_AI_FORMATING) &
+	    ~(WM8350_AIF_BCLK_INV | WM8350_AIF_LRCLK_INV | WM8350_AIF_FMT_MASK);
+	u16 master = snd_soc_component_read32(component, WM8350_AI_DAC_CONTROL) &
+	    ~WM8350_BCLK_MSTR;
+	u16 dac_lrc = snd_soc_component_read32(component, WM8350_DAC_LR_RATE) &
+	    ~WM8350_DACLRC_ENA;
+	u16 adc_lrc = snd_soc_component_read32(component, WM8350_ADC_LR_RATE) &
+	    ~WM8350_ADCLRC_ENA;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		master |= WM8350_BCLK_MSTR;
+		dac_lrc |= WM8350_DACLRC_ENA;
+		adc_lrc |= WM8350_ADCLRC_ENA;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x2 << 8;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x1 << 8;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x3 << 8;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x3 << 8 | WM8350_AIF_LRCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= WM8350_AIF_LRCLK_INV | WM8350_AIF_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= WM8350_AIF_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= WM8350_AIF_LRCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8350_AI_FORMATING, iface);
+	snd_soc_component_write(component, WM8350_AI_DAC_CONTROL, master);
+	snd_soc_component_write(component, WM8350_DAC_LR_RATE, dac_lrc);
+	snd_soc_component_write(component, WM8350_ADC_LR_RATE, adc_lrc);
+	return 0;
+}
+
+static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *codec_dai)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8350_data *wm8350_data = snd_soc_component_get_drvdata(component);
+	struct wm8350 *wm8350 = wm8350_data->wm8350;
+	u16 iface = snd_soc_component_read32(component, WM8350_AI_FORMATING) &
+	    ~WM8350_AIF_WL_MASK;
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		iface |= 0x1 << 10;
+		break;
+	case 24:
+		iface |= 0x2 << 10;
+		break;
+	case 32:
+		iface |= 0x3 << 10;
+		break;
+	}
+
+	snd_soc_component_write(component, WM8350_AI_FORMATING, iface);
+
+	/* The sloping stopband filter is recommended for use with
+	 * lower sample rates to improve performance.
+	 */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (params_rate(params) < 24000)
+			wm8350_set_bits(wm8350, WM8350_DAC_MUTE_VOLUME,
+					WM8350_DAC_SB_FILT);
+		else
+			wm8350_clear_bits(wm8350, WM8350_DAC_MUTE_VOLUME,
+					  WM8350_DAC_SB_FILT);
+	}
+
+	return 0;
+}
+
+static int wm8350_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int val;
+
+	if (mute)
+		val = WM8350_DAC_MUTE_ENA;
+	else
+		val = 0;
+
+	snd_soc_component_update_bits(component, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA, val);
+
+	return 0;
+}
+
+/* FLL divisors */
+struct _fll_div {
+	int div;		/* FLL_OUTDIV */
+	int n;
+	int k;
+	int ratio;		/* FLL_FRATIO */
+};
+
+/* The size in bits of the fll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static inline int fll_factors(struct _fll_div *fll_div, unsigned int input,
+			      unsigned int output)
+{
+	u64 Kpart;
+	unsigned int t1, t2, K, Nmod;
+
+	if (output >= 2815250 && output <= 3125000)
+		fll_div->div = 0x4;
+	else if (output >= 5625000 && output <= 6250000)
+		fll_div->div = 0x3;
+	else if (output >= 11250000 && output <= 12500000)
+		fll_div->div = 0x2;
+	else if (output >= 22500000 && output <= 25000000)
+		fll_div->div = 0x1;
+	else {
+		printk(KERN_ERR "wm8350: fll freq %d out of range\n", output);
+		return -EINVAL;
+	}
+
+	if (input > 48000)
+		fll_div->ratio = 1;
+	else
+		fll_div->ratio = 8;
+
+	t1 = output * (1 << (fll_div->div + 1));
+	t2 = input * fll_div->ratio;
+
+	fll_div->n = t1 / t2;
+	Nmod = t1 % t2;
+
+	if (Nmod) {
+		Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+		do_div(Kpart, t2);
+		K = Kpart & 0xFFFFFFFF;
+
+		/* Check if we need to round */
+		if ((K % 10) >= 5)
+			K += 5;
+
+		/* Move down to proper range now rounding is done */
+		K /= 10;
+		fll_div->k = K;
+	} else
+		fll_div->k = 0;
+
+	return 0;
+}
+
+static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
+			  int pll_id, int source, unsigned int freq_in,
+			  unsigned int freq_out)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
+	struct wm8350 *wm8350 = priv->wm8350;
+	struct _fll_div fll_div;
+	int ret = 0;
+	u16 fll_1, fll_4;
+
+	if (freq_in == priv->fll_freq_in && freq_out == priv->fll_freq_out)
+		return 0;
+
+	/* power down FLL - we need to do this for reconfiguration */
+	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4,
+			  WM8350_FLL_ENA | WM8350_FLL_OSC_ENA);
+
+	if (freq_out == 0 || freq_in == 0)
+		return ret;
+
+	ret = fll_factors(&fll_div, freq_in, freq_out);
+	if (ret < 0)
+		return ret;
+	dev_dbg(wm8350->dev,
+		"FLL in %u FLL out %u N 0x%x K 0x%x div %d ratio %d",
+		freq_in, freq_out, fll_div.n, fll_div.k, fll_div.div,
+		fll_div.ratio);
+
+	/* set up N.K & dividers */
+	fll_1 = snd_soc_component_read32(component, WM8350_FLL_CONTROL_1) &
+	    ~(WM8350_FLL_OUTDIV_MASK | WM8350_FLL_RSP_RATE_MASK | 0xc000);
+	snd_soc_component_write(component, WM8350_FLL_CONTROL_1,
+			   fll_1 | (fll_div.div << 8) | 0x50);
+	snd_soc_component_write(component, WM8350_FLL_CONTROL_2,
+			   (fll_div.ratio << 11) | (fll_div.
+						    n & WM8350_FLL_N_MASK));
+	snd_soc_component_write(component, WM8350_FLL_CONTROL_3, fll_div.k);
+	fll_4 = snd_soc_component_read32(component, WM8350_FLL_CONTROL_4) &
+	    ~(WM8350_FLL_FRAC | WM8350_FLL_SLOW_LOCK_REF);
+	snd_soc_component_write(component, WM8350_FLL_CONTROL_4,
+			   fll_4 | (fll_div.k ? WM8350_FLL_FRAC : 0) |
+			   (fll_div.ratio == 8 ? WM8350_FLL_SLOW_LOCK_REF : 0));
+
+	/* power FLL on */
+	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_OSC_ENA);
+	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA);
+
+	priv->fll_freq_out = freq_out;
+	priv->fll_freq_in = freq_in;
+
+	return 0;
+}
+
+static int wm8350_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
+	struct wm8350 *wm8350 = priv->wm8350;
+	struct wm8350_audio_platform_data *platform =
+		wm8350->codec.platform_data;
+	u16 pm1;
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
+		    ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK);
+		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
+				 pm1 | WM8350_VMID_50K |
+				 platform->codec_current_on << 14);
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1);
+		pm1 &= ~WM8350_VMID_MASK;
+		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
+				 pm1 | WM8350_VMID_50K);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
+						    priv->supplies);
+			if (ret != 0)
+				return ret;
+
+			/* Enable the system clock */
+			wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4,
+					WM8350_SYSCLK_ENA);
+
+			/* mute DAC & outputs */
+			wm8350_set_bits(wm8350, WM8350_DAC_MUTE,
+					WM8350_DAC_MUTE_ENA);
+
+			/* discharge cap memory */
+			wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
+					 platform->dis_out1 |
+					 (platform->dis_out2 << 2) |
+					 (platform->dis_out3 << 4) |
+					 (platform->dis_out4 << 6));
+
+			/* wait for discharge */
+			schedule_timeout_interruptible(msecs_to_jiffies
+						       (platform->
+							cap_discharge_msecs));
+
+			/* enable antipop */
+			wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
+					 (platform->vmid_s_curve << 8));
+
+			/* ramp up vmid */
+			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
+					 (platform->
+					  codec_current_charge << 14) |
+					 WM8350_VMID_5K | WM8350_VMIDEN |
+					 WM8350_VBUFEN);
+
+			/* wait for vmid */
+			schedule_timeout_interruptible(msecs_to_jiffies
+						       (platform->
+							vmid_charge_msecs));
+
+			/* turn on vmid 300k  */
+			pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
+			    ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK);
+			pm1 |= WM8350_VMID_300K |
+				(platform->codec_current_standby << 14);
+			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
+					 pm1);
+
+
+			/* enable analogue bias */
+			pm1 |= WM8350_BIASEN;
+			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1);
+
+			/* disable antipop */
+			wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 0);
+
+		} else {
+			/* turn on vmid 300k and reduce current */
+			pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
+			    ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK);
+			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
+					 pm1 | WM8350_VMID_300K |
+					 (platform->
+					  codec_current_standby << 14));
+
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+
+		/* mute DAC & enable outputs */
+		wm8350_set_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA);
+
+		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_3,
+				WM8350_OUT1L_ENA | WM8350_OUT1R_ENA |
+				WM8350_OUT2L_ENA | WM8350_OUT2R_ENA);
+
+		/* enable anti pop S curve */
+		wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
+				 (platform->vmid_s_curve << 8));
+
+		/* turn off vmid  */
+		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
+		    ~WM8350_VMIDEN;
+		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1);
+
+		/* wait */
+		schedule_timeout_interruptible(msecs_to_jiffies
+					       (platform->
+						vmid_discharge_msecs));
+
+		wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
+				 (platform->vmid_s_curve << 8) |
+				 platform->dis_out1 |
+				 (platform->dis_out2 << 2) |
+				 (platform->dis_out3 << 4) |
+				 (platform->dis_out4 << 6));
+
+		/* turn off VBuf and drain */
+		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
+		    ~(WM8350_VBUFEN | WM8350_VMID_MASK);
+		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
+				 pm1 | WM8350_OUTPUT_DRAIN_EN);
+
+		/* wait */
+		schedule_timeout_interruptible(msecs_to_jiffies
+					       (platform->drain_msecs));
+
+		pm1 &= ~WM8350_BIASEN;
+		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1);
+
+		/* disable anti-pop */
+		wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 0);
+
+		wm8350_clear_bits(wm8350, WM8350_LOUT1_VOLUME,
+				  WM8350_OUT1L_ENA);
+		wm8350_clear_bits(wm8350, WM8350_ROUT1_VOLUME,
+				  WM8350_OUT1R_ENA);
+		wm8350_clear_bits(wm8350, WM8350_LOUT2_VOLUME,
+				  WM8350_OUT2L_ENA);
+		wm8350_clear_bits(wm8350, WM8350_ROUT2_VOLUME,
+				  WM8350_OUT2R_ENA);
+
+		/* disable clock gen */
+		wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4,
+				  WM8350_SYSCLK_ENA);
+
+		regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
+				       priv->supplies);
+		break;
+	}
+	return 0;
+}
+
+static void wm8350_hp_work(struct wm8350_data *priv,
+			   struct wm8350_jack_data *jack,
+			   u16 mask)
+{
+	struct wm8350 *wm8350 = priv->wm8350;
+	u16 reg;
+	int report;
+
+	reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
+	if (reg & mask)
+		report = jack->report;
+	else
+		report = 0;
+
+	snd_soc_jack_report(jack->jack, report, jack->report);
+
+}
+
+static void wm8350_hpl_work(struct work_struct *work)
+{
+	struct wm8350_data *priv =
+	    container_of(work, struct wm8350_data, hpl.work.work);
+
+	wm8350_hp_work(priv, &priv->hpl, WM8350_JACK_L_LVL);
+}
+
+static void wm8350_hpr_work(struct work_struct *work)
+{
+	struct wm8350_data *priv =
+	    container_of(work, struct wm8350_data, hpr.work.work);
+	
+	wm8350_hp_work(priv, &priv->hpr, WM8350_JACK_R_LVL);
+}
+
+static irqreturn_t wm8350_hpl_jack_handler(int irq, void *data)
+{
+	struct wm8350_data *priv = data;
+	struct wm8350 *wm8350 = priv->wm8350;
+
+#ifndef CONFIG_SND_SOC_WM8350_MODULE
+	trace_snd_soc_jack_irq("WM8350 HPL");
+#endif
+
+	if (device_may_wakeup(wm8350->dev))
+		pm_wakeup_event(wm8350->dev, 250);
+
+	queue_delayed_work(system_power_efficient_wq,
+			   &priv->hpl.work, msecs_to_jiffies(200));
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wm8350_hpr_jack_handler(int irq, void *data)
+{
+	struct wm8350_data *priv = data;
+	struct wm8350 *wm8350 = priv->wm8350;
+
+#ifndef CONFIG_SND_SOC_WM8350_MODULE
+	trace_snd_soc_jack_irq("WM8350 HPR");
+#endif
+
+	if (device_may_wakeup(wm8350->dev))
+		pm_wakeup_event(wm8350->dev, 250);
+
+	queue_delayed_work(system_power_efficient_wq,
+			   &priv->hpr.work, msecs_to_jiffies(200));
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * wm8350_hp_jack_detect - Enable headphone jack detection.
+ *
+ * @component:  WM8350 component
+ * @which:  left or right jack detect signal
+ * @jack:   jack to report detection events on
+ * @report: value to report
+ *
+ * Enables the headphone jack detection of the WM8350.  If no report
+ * is specified then detection is disabled.
+ */
+int wm8350_hp_jack_detect(struct snd_soc_component *component, enum wm8350_jack which,
+			  struct snd_soc_jack *jack, int report)
+{
+	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
+	struct wm8350 *wm8350 = priv->wm8350;
+	int ena;
+
+	switch (which) {
+	case WM8350_JDL:
+		priv->hpl.jack = jack;
+		priv->hpl.report = report;
+		ena = WM8350_JDL_ENA;
+		break;
+
+	case WM8350_JDR:
+		priv->hpr.jack = jack;
+		priv->hpr.report = report;
+		ena = WM8350_JDR_ENA;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (report) {
+		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
+		wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena);
+	} else {
+		wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, ena);
+	}
+
+	/* Sync status */
+	switch (which) {
+	case WM8350_JDL:
+		wm8350_hpl_jack_handler(0, priv);
+		break;
+	case WM8350_JDR:
+		wm8350_hpr_jack_handler(0, priv);
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_hp_jack_detect);
+
+static irqreturn_t wm8350_mic_handler(int irq, void *data)
+{
+	struct wm8350_data *priv = data;
+	struct wm8350 *wm8350 = priv->wm8350;
+	u16 reg;
+	int report = 0;
+
+#ifndef CONFIG_SND_SOC_WM8350_MODULE
+	trace_snd_soc_jack_irq("WM8350 mic");
+#endif
+
+	reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
+	if (reg & WM8350_JACK_MICSCD_LVL)
+		report |= priv->mic.short_report;
+	if (reg & WM8350_JACK_MICSD_LVL)
+		report |= priv->mic.report;
+
+	snd_soc_jack_report(priv->mic.jack, report,
+			    priv->mic.report | priv->mic.short_report);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * wm8350_mic_jack_detect - Enable microphone jack detection.
+ *
+ * @component:         WM8350 component
+ * @jack:          jack to report detection events on
+ * @detect_report: value to report when presence detected
+ * @short_report:  value to report when microphone short detected
+ *
+ * Enables the microphone jack detection of the WM8350.  If both reports
+ * are specified as zero then detection is disabled.
+ */
+int wm8350_mic_jack_detect(struct snd_soc_component *component,
+			   struct snd_soc_jack *jack,
+			   int detect_report, int short_report)
+{
+	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
+	struct wm8350 *wm8350 = priv->wm8350;
+
+	priv->mic.jack = jack;
+	priv->mic.report = detect_report;
+	priv->mic.short_report = short_report;
+
+	if (detect_report || short_report) {
+		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
+		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_1,
+				WM8350_MIC_DET_ENA);
+	} else {
+		wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_1,
+				  WM8350_MIC_DET_ENA);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect);
+
+#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000)
+
+#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops wm8350_dai_ops = {
+	 .hw_params	= wm8350_pcm_hw_params,
+	 .digital_mute	= wm8350_mute,
+	 .set_fmt	= wm8350_set_dai_fmt,
+	 .set_sysclk	= wm8350_set_dai_sysclk,
+	 .set_pll	= wm8350_set_fll,
+	 .set_clkdiv	= wm8350_set_clkdiv,
+};
+
+static struct snd_soc_dai_driver wm8350_dai = {
+	.name = "wm8350-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8350_RATES,
+		.formats = WM8350_FORMATS,
+	},
+	.capture = {
+		 .stream_name = "Capture",
+		 .channels_min = 1,
+		 .channels_max = 2,
+		 .rates = WM8350_RATES,
+		 .formats = WM8350_FORMATS,
+	 },
+	.ops = &wm8350_dai_ops,
+};
+
+static  int wm8350_component_probe(struct snd_soc_component *component)
+{
+	struct wm8350 *wm8350 = dev_get_platdata(component->dev);
+	struct wm8350_data *priv;
+	struct wm8350_output *out1;
+	struct wm8350_output *out2;
+	int ret, i;
+
+	if (wm8350->codec.platform_data == NULL) {
+		dev_err(component->dev, "No audio platform data supplied\n");
+		return -EINVAL;
+	}
+
+	priv = devm_kzalloc(component->dev, sizeof(struct wm8350_data),
+			    GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	snd_soc_component_init_regmap(component, wm8350->regmap);
+	snd_soc_component_set_drvdata(component, priv);
+
+	priv->wm8350 = wm8350;
+
+	for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+		priv->supplies[i].supply = supply_names[i];
+
+	ret = devm_regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
+				 priv->supplies);
+	if (ret != 0)
+		return ret;
+
+	/* Put the codec into reset if it wasn't already */
+	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
+
+	INIT_DELAYED_WORK(&priv->pga_work, wm8350_pga_work);
+	INIT_DELAYED_WORK(&priv->hpl.work, wm8350_hpl_work);
+	INIT_DELAYED_WORK(&priv->hpr.work, wm8350_hpr_work);
+
+	/* Enable the codec */
+	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
+
+	/* Enable robust clocking mode in ADC */
+	snd_soc_component_write(component, WM8350_SECURITY, 0xa7);
+	snd_soc_component_write(component, 0xde, 0x13);
+	snd_soc_component_write(component, WM8350_SECURITY, 0);
+
+	/* read OUT1 & OUT2 volumes */
+	out1 = &priv->out1;
+	out2 = &priv->out2;
+	out1->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT1_VOLUME) &
+			  WM8350_OUT1L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
+	out1->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT1_VOLUME) &
+			   WM8350_OUT1R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
+	out2->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT2_VOLUME) &
+			  WM8350_OUT2L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
+	out2->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT2_VOLUME) &
+			   WM8350_OUT2R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
+	wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME, 0);
+	wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME, 0);
+	wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME, 0);
+	wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME, 0);
+
+	/* Latch VU bits & mute */
+	wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME,
+			WM8350_OUT1_VU | WM8350_OUT1L_MUTE);
+	wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME,
+			WM8350_OUT2_VU | WM8350_OUT2L_MUTE);
+	wm8350_set_bits(wm8350, WM8350_ROUT1_VOLUME,
+			WM8350_OUT1_VU | WM8350_OUT1R_MUTE);
+	wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME,
+			WM8350_OUT2_VU | WM8350_OUT2R_MUTE);
+
+	/* Make sure AIF tristating is disabled by default */
+	wm8350_clear_bits(wm8350, WM8350_AI_FORMATING, WM8350_AIF_TRI);
+
+	/* Make sure we've got a sane companding setup too */
+	wm8350_clear_bits(wm8350, WM8350_ADC_DAC_COMP,
+			  WM8350_DAC_COMP | WM8350_LOOPBACK);
+
+	/* Make sure jack detect is disabled to start off with */
+	wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
+			  WM8350_JDL_ENA | WM8350_JDR_ENA);
+
+	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L,
+			    wm8350_hpl_jack_handler, 0, "Left jack detect",
+			    priv);
+	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R,
+			    wm8350_hpr_jack_handler, 0, "Right jack detect",
+			    priv);
+	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD,
+			    wm8350_mic_handler, 0, "Microphone short", priv);
+	wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD,
+			    wm8350_mic_handler, 0, "Microphone detect", priv);
+
+	return 0;
+}
+
+static void wm8350_component_remove(struct snd_soc_component *component)
+{
+	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
+	struct wm8350 *wm8350 = dev_get_platdata(component->dev);
+
+	wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
+			  WM8350_JDL_ENA | WM8350_JDR_ENA);
+	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
+
+	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICD, priv);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, priv);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv);
+	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv);
+
+	priv->hpl.jack = NULL;
+	priv->hpr.jack = NULL;
+	priv->mic.jack = NULL;
+
+	cancel_delayed_work_sync(&priv->hpl.work);
+	cancel_delayed_work_sync(&priv->hpr.work);
+
+	/* if there was any work waiting then we run it now and
+	 * wait for its completion */
+	flush_delayed_work(&priv->pga_work);
+
+	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8350 = {
+	.probe			= wm8350_component_probe,
+	.remove			= wm8350_component_remove,
+	.set_bias_level		= wm8350_set_bias_level,
+	.controls		= wm8350_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8350_snd_controls),
+	.dapm_widgets		= wm8350_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8350_dapm_widgets),
+	.dapm_routes		= wm8350_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8350_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm8350_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm8350,
+			&wm8350_dai, 1);
+}
+
+static struct platform_driver wm8350_codec_driver = {
+	.driver = {
+		   .name = "wm8350-codec",
+		   },
+	.probe = wm8350_probe,
+};
+
+module_platform_driver(wm8350_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM8350 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8350-codec");
diff --git a/sound/soc/codecs/wm8350.h b/sound/soc/codecs/wm8350.h
new file mode 100644
index 0000000..1191326
--- /dev/null
+++ b/sound/soc/codecs/wm8350.h
@@ -0,0 +1,29 @@
+/*
+ * wm8350.h - WM8903 audio codec interface
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _WM8350_H
+#define _WM8350_H
+
+#include <sound/soc.h>
+#include <linux/mfd/wm8350/audio.h>
+
+enum wm8350_jack {
+	WM8350_JDL = 1,
+	WM8350_JDR = 2,
+};
+
+int wm8350_hp_jack_detect(struct snd_soc_component *component, enum wm8350_jack which,
+			  struct snd_soc_jack *jack, int report);
+int wm8350_mic_jack_detect(struct snd_soc_component *component,
+			   struct snd_soc_jack *jack,
+			   int detect_report, int short_report);
+
+#endif
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
new file mode 100644
index 0000000..57b2206
--- /dev/null
+++ b/sound/soc/codecs/wm8400.c
@@ -0,0 +1,1363 @@
+/*
+ * wm8400.c  --  WM8400 ALSA Soc Audio driver
+ *
+ * Copyright 2008-11 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/wm8400-audio.h>
+#include <linux/mfd/wm8400-private.h>
+#include <linux/mfd/core.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8400.h"
+
+static struct regulator_bulk_data power[] = {
+	{
+		.supply = "I2S1VDD",
+	},
+	{
+		.supply = "I2S2VDD",
+	},
+	{
+		.supply = "DCVDD",
+	},
+	{
+		.supply = "AVDD",
+	},
+	{
+		.supply = "FLLVDD",
+	},
+	{
+		.supply = "HPVDD",
+	},
+	{
+		.supply = "SPKVDD",
+	},
+};
+
+/* codec private data */
+struct wm8400_priv {
+	struct wm8400 *wm8400;
+	u16 fake_register;
+	unsigned int sysclk;
+	unsigned int pcmclk;
+	int fll_in, fll_out;
+};
+
+static void wm8400_component_reset(struct snd_soc_component *component)
+{
+	struct wm8400_priv *wm8400 = snd_soc_component_get_drvdata(component);
+
+	wm8400_reset_codec_reg_cache(wm8400->wm8400);
+}
+
+static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 600, 0);
+
+static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1650, 3000, 0);
+
+static const DECLARE_TLV_DB_SCALE(out_mix_tlv, -2100, 0, 0);
+
+static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -7300, 600, 0);
+
+static const DECLARE_TLV_DB_SCALE(out_omix_tlv, -600, 0, 0);
+
+static const DECLARE_TLV_DB_SCALE(out_dac_tlv, -7163, 0, 0);
+
+static const DECLARE_TLV_DB_SCALE(in_adc_tlv, -7163, 1763, 0);
+
+static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);
+
+static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
+        struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	int reg = mc->reg;
+        int ret;
+        u16 val;
+
+        ret = snd_soc_put_volsw(kcontrol, ucontrol);
+        if (ret < 0)
+                return ret;
+
+        /* now hit the volume update bits (always bit 8) */
+        val = snd_soc_component_read32(component, reg);
+        return snd_soc_component_write(component, reg, val | 0x0100);
+}
+
+#define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \
+	SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \
+		snd_soc_get_volsw, wm8400_outpga_put_volsw_vu, tlv_array)
+
+
+static const char *wm8400_digital_sidetone[] =
+	{"None", "Left ADC", "Right ADC", "Reserved"};
+
+static SOC_ENUM_SINGLE_DECL(wm8400_left_digital_sidetone_enum,
+			    WM8400_DIGITAL_SIDE_TONE,
+			    WM8400_ADC_TO_DACL_SHIFT,
+			    wm8400_digital_sidetone);
+
+static SOC_ENUM_SINGLE_DECL(wm8400_right_digital_sidetone_enum,
+			    WM8400_DIGITAL_SIDE_TONE,
+			    WM8400_ADC_TO_DACR_SHIFT,
+			    wm8400_digital_sidetone);
+
+static const char *wm8400_adcmode[] =
+	{"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
+
+static SOC_ENUM_SINGLE_DECL(wm8400_right_adcmode_enum,
+			    WM8400_ADC_CTRL,
+			    WM8400_ADC_HPF_CUT_SHIFT,
+			    wm8400_adcmode);
+
+static const struct snd_kcontrol_new wm8400_snd_controls[] = {
+/* INMIXL */
+SOC_SINGLE("LIN12 PGA Boost", WM8400_INPUT_MIXER3, WM8400_L12MNBST_SHIFT,
+	   1, 0),
+SOC_SINGLE("LIN34 PGA Boost", WM8400_INPUT_MIXER3, WM8400_L34MNBST_SHIFT,
+	   1, 0),
+/* INMIXR */
+SOC_SINGLE("RIN12 PGA Boost", WM8400_INPUT_MIXER3, WM8400_R12MNBST_SHIFT,
+	   1, 0),
+SOC_SINGLE("RIN34 PGA Boost", WM8400_INPUT_MIXER3, WM8400_R34MNBST_SHIFT,
+	   1, 0),
+
+/* LOMIX */
+SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8400_OUTPUT_MIXER3,
+	WM8400_LLI3LOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER3,
+	WM8400_LR12LOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER3,
+	WM8400_LL12LOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8400_OUTPUT_MIXER5,
+	WM8400_LRI3LOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8400_OUTPUT_MIXER5,
+	WM8400_LRBLOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8400_OUTPUT_MIXER5,
+	WM8400_LRBLOVOL_SHIFT, 7, 0, out_mix_tlv),
+
+/* ROMIX */
+SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8400_OUTPUT_MIXER4,
+	WM8400_RRI3ROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER4,
+	WM8400_RL12ROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER4,
+	WM8400_RR12ROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8400_OUTPUT_MIXER6,
+	WM8400_RLI3ROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8400_OUTPUT_MIXER6,
+	WM8400_RLBROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8400_OUTPUT_MIXER6,
+	WM8400_RRBROVOL_SHIFT, 7, 0, out_mix_tlv),
+
+/* LOUT */
+WM8400_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8400_LEFT_OUTPUT_VOLUME,
+	WM8400_LOUTVOL_SHIFT, WM8400_LOUTVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("LOUT ZC", WM8400_LEFT_OUTPUT_VOLUME, WM8400_LOZC_SHIFT, 1, 0),
+
+/* ROUT */
+WM8400_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8400_RIGHT_OUTPUT_VOLUME,
+	WM8400_ROUTVOL_SHIFT, WM8400_ROUTVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("ROUT ZC", WM8400_RIGHT_OUTPUT_VOLUME, WM8400_ROZC_SHIFT, 1, 0),
+
+/* LOPGA */
+WM8400_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8400_LEFT_OPGA_VOLUME,
+	WM8400_LOPGAVOL_SHIFT, WM8400_LOPGAVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("LOPGA ZC Switch", WM8400_LEFT_OPGA_VOLUME,
+	WM8400_LOPGAZC_SHIFT, 1, 0),
+
+/* ROPGA */
+WM8400_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8400_RIGHT_OPGA_VOLUME,
+	WM8400_ROPGAVOL_SHIFT, WM8400_ROPGAVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("ROPGA ZC Switch", WM8400_RIGHT_OPGA_VOLUME,
+	WM8400_ROPGAZC_SHIFT, 1, 0),
+
+SOC_SINGLE("LON Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
+	WM8400_LONMUTE_SHIFT, 1, 0),
+SOC_SINGLE("LOP Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
+	WM8400_LOPMUTE_SHIFT, 1, 0),
+SOC_SINGLE("LOP Attenuation Switch", WM8400_LINE_OUTPUTS_VOLUME,
+	WM8400_LOATTN_SHIFT, 1, 0),
+SOC_SINGLE("RON Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
+	WM8400_RONMUTE_SHIFT, 1, 0),
+SOC_SINGLE("ROP Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
+	WM8400_ROPMUTE_SHIFT, 1, 0),
+SOC_SINGLE("ROP Attenuation Switch", WM8400_LINE_OUTPUTS_VOLUME,
+	WM8400_ROATTN_SHIFT, 1, 0),
+
+SOC_SINGLE("OUT3 Mute Switch", WM8400_OUT3_4_VOLUME,
+	WM8400_OUT3MUTE_SHIFT, 1, 0),
+SOC_SINGLE("OUT3 Attenuation Switch", WM8400_OUT3_4_VOLUME,
+	WM8400_OUT3ATTN_SHIFT, 1, 0),
+
+SOC_SINGLE("OUT4 Mute Switch", WM8400_OUT3_4_VOLUME,
+	WM8400_OUT4MUTE_SHIFT, 1, 0),
+SOC_SINGLE("OUT4 Attenuation Switch", WM8400_OUT3_4_VOLUME,
+	WM8400_OUT4ATTN_SHIFT, 1, 0),
+
+SOC_SINGLE("Speaker Mode Switch", WM8400_CLASSD1,
+	WM8400_CDMODE_SHIFT, 1, 0),
+
+SOC_SINGLE("Speaker Output Attenuation Volume", WM8400_SPEAKER_VOLUME,
+	WM8400_SPKATTN_SHIFT, WM8400_SPKATTN_MASK, 0),
+SOC_SINGLE("Speaker DC Boost Volume", WM8400_CLASSD3,
+	WM8400_DCGAIN_SHIFT, 6, 0),
+SOC_SINGLE("Speaker AC Boost Volume", WM8400_CLASSD3,
+	WM8400_ACGAIN_SHIFT, 6, 0),
+
+WM8400_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume",
+	WM8400_LEFT_DAC_DIGITAL_VOLUME, WM8400_DACL_VOL_SHIFT,
+	127, 0, out_dac_tlv),
+
+WM8400_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume",
+	WM8400_RIGHT_DAC_DIGITAL_VOLUME, WM8400_DACR_VOL_SHIFT,
+	127, 0, out_dac_tlv),
+
+SOC_ENUM("Left Digital Sidetone", wm8400_left_digital_sidetone_enum),
+SOC_ENUM("Right Digital Sidetone", wm8400_right_digital_sidetone_enum),
+
+SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8400_DIGITAL_SIDE_TONE,
+	WM8400_ADCL_DAC_SVOL_SHIFT, 15, 0, out_sidetone_tlv),
+SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8400_DIGITAL_SIDE_TONE,
+	WM8400_ADCR_DAC_SVOL_SHIFT, 15, 0, out_sidetone_tlv),
+
+SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8400_ADC_CTRL,
+	WM8400_ADC_HPF_ENA_SHIFT, 1, 0),
+
+SOC_ENUM("ADC HPF Mode", wm8400_right_adcmode_enum),
+
+WM8400_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume",
+	WM8400_LEFT_ADC_DIGITAL_VOLUME,
+	WM8400_ADCL_VOL_SHIFT,
+	WM8400_ADCL_VOL_MASK,
+	0,
+	in_adc_tlv),
+
+WM8400_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume",
+	WM8400_RIGHT_ADC_DIGITAL_VOLUME,
+	WM8400_ADCR_VOL_SHIFT,
+	WM8400_ADCR_VOL_MASK,
+	0,
+	in_adc_tlv),
+
+WM8400_OUTPGA_SINGLE_R_TLV("LIN12 Volume",
+	WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+	WM8400_LIN12VOL_SHIFT,
+	WM8400_LIN12VOL_MASK,
+	0,
+	in_pga_tlv),
+
+SOC_SINGLE("LIN12 ZC Switch", WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+	WM8400_LI12ZC_SHIFT, 1, 0),
+
+SOC_SINGLE("LIN12 Mute Switch", WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+	WM8400_LI12MUTE_SHIFT, 1, 0),
+
+WM8400_OUTPGA_SINGLE_R_TLV("LIN34 Volume",
+	WM8400_LEFT_LINE_INPUT_3_4_VOLUME,
+	WM8400_LIN34VOL_SHIFT,
+	WM8400_LIN34VOL_MASK,
+	0,
+	in_pga_tlv),
+
+SOC_SINGLE("LIN34 ZC Switch", WM8400_LEFT_LINE_INPUT_3_4_VOLUME,
+	WM8400_LI34ZC_SHIFT, 1, 0),
+
+SOC_SINGLE("LIN34 Mute Switch", WM8400_LEFT_LINE_INPUT_3_4_VOLUME,
+	WM8400_LI34MUTE_SHIFT, 1, 0),
+
+WM8400_OUTPGA_SINGLE_R_TLV("RIN12 Volume",
+	WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+	WM8400_RIN12VOL_SHIFT,
+	WM8400_RIN12VOL_MASK,
+	0,
+	in_pga_tlv),
+
+SOC_SINGLE("RIN12 ZC Switch", WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+	WM8400_RI12ZC_SHIFT, 1, 0),
+
+SOC_SINGLE("RIN12 Mute Switch", WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+	WM8400_RI12MUTE_SHIFT, 1, 0),
+
+WM8400_OUTPGA_SINGLE_R_TLV("RIN34 Volume",
+	WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
+	WM8400_RIN34VOL_SHIFT,
+	WM8400_RIN34VOL_MASK,
+	0,
+	in_pga_tlv),
+
+SOC_SINGLE("RIN34 ZC Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
+	WM8400_RI34ZC_SHIFT, 1, 0),
+
+SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
+	WM8400_RI34MUTE_SHIFT, 1, 0),
+
+};
+
+/*
+ * _DAPM_ Controls
+ */
+
+static int outmixer_event (struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol * kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	u32 reg_shift = mc->shift;
+	int ret = 0;
+	u16 reg;
+
+	switch (reg_shift) {
+	case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) :
+		reg = snd_soc_component_read32(component, WM8400_OUTPUT_MIXER1);
+		if (reg & WM8400_LDLO) {
+			printk(KERN_WARNING
+			"Cannot set as Output Mixer 1 LDLO Set\n");
+			ret = -1;
+		}
+		break;
+	case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8):
+		reg = snd_soc_component_read32(component, WM8400_OUTPUT_MIXER2);
+		if (reg & WM8400_RDRO) {
+			printk(KERN_WARNING
+			"Cannot set as Output Mixer 2 RDRO Set\n");
+			ret = -1;
+		}
+		break;
+	case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8):
+		reg = snd_soc_component_read32(component, WM8400_SPEAKER_MIXER);
+		if (reg & WM8400_LDSPK) {
+			printk(KERN_WARNING
+			"Cannot set as Speaker Mixer LDSPK Set\n");
+			ret = -1;
+		}
+		break;
+	case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8):
+		reg = snd_soc_component_read32(component, WM8400_SPEAKER_MIXER);
+		if (reg & WM8400_RDSPK) {
+			printk(KERN_WARNING
+			"Cannot set as Speaker Mixer RDSPK Set\n");
+			ret = -1;
+		}
+		break;
+	}
+
+	return ret;
+}
+
+/* INMIX dB values */
+static const DECLARE_TLV_DB_SCALE(in_mix_tlv, -1200, 600, 0);
+
+/* Left In PGA Connections */
+static const struct snd_kcontrol_new wm8400_dapm_lin12_pga_controls[] = {
+SOC_DAPM_SINGLE("LIN1 Switch", WM8400_INPUT_MIXER2, WM8400_LMN1_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LIN2 Switch", WM8400_INPUT_MIXER2, WM8400_LMP2_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8400_dapm_lin34_pga_controls[] = {
+SOC_DAPM_SINGLE("LIN3 Switch", WM8400_INPUT_MIXER2, WM8400_LMN3_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LIN4 Switch", WM8400_INPUT_MIXER2, WM8400_LMP4_SHIFT, 1, 0),
+};
+
+/* Right In PGA Connections */
+static const struct snd_kcontrol_new wm8400_dapm_rin12_pga_controls[] = {
+SOC_DAPM_SINGLE("RIN1 Switch", WM8400_INPUT_MIXER2, WM8400_RMN1_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("RIN2 Switch", WM8400_INPUT_MIXER2, WM8400_RMP2_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8400_dapm_rin34_pga_controls[] = {
+SOC_DAPM_SINGLE("RIN3 Switch", WM8400_INPUT_MIXER2, WM8400_RMN3_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("RIN4 Switch", WM8400_INPUT_MIXER2, WM8400_RMP4_SHIFT, 1, 0),
+};
+
+/* INMIXL */
+static const struct snd_kcontrol_new wm8400_dapm_inmixl_controls[] = {
+SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8400_INPUT_MIXER3,
+	WM8400_LDBVOL_SHIFT, WM8400_LDBVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8400_INPUT_MIXER5, WM8400_LI2BVOL_SHIFT,
+	7, 0, in_mix_tlv),
+SOC_DAPM_SINGLE("LINPGA12 Switch", WM8400_INPUT_MIXER3, WM8400_L12MNB_SHIFT,
+		1, 0),
+SOC_DAPM_SINGLE("LINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT,
+		1, 0),
+};
+
+/* INMIXR */
+static const struct snd_kcontrol_new wm8400_dapm_inmixr_controls[] = {
+SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8400_INPUT_MIXER4,
+	WM8400_RDBVOL_SHIFT, WM8400_RDBVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8400_INPUT_MIXER6, WM8400_RI2BVOL_SHIFT,
+	7, 0, in_mix_tlv),
+SOC_DAPM_SINGLE("RINPGA12 Switch", WM8400_INPUT_MIXER3, WM8400_L12MNB_SHIFT,
+	1, 0),
+SOC_DAPM_SINGLE("RINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT,
+	1, 0),
+};
+
+/* AINLMUX */
+static const char *wm8400_ainlmux[] =
+	{"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
+
+static SOC_ENUM_SINGLE_DECL(wm8400_ainlmux_enum,
+			    WM8400_INPUT_MIXER1,
+			    WM8400_AINLMODE_SHIFT,
+			    wm8400_ainlmux);
+
+static const struct snd_kcontrol_new wm8400_dapm_ainlmux_controls =
+SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum);
+
+/* DIFFINL */
+
+/* AINRMUX */
+static const char *wm8400_ainrmux[] =
+	{"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
+
+static SOC_ENUM_SINGLE_DECL(wm8400_ainrmux_enum,
+			    WM8400_INPUT_MIXER1,
+			    WM8400_AINRMODE_SHIFT,
+			    wm8400_ainrmux);
+
+static const struct snd_kcontrol_new wm8400_dapm_ainrmux_controls =
+SOC_DAPM_ENUM("Route", wm8400_ainrmux_enum);
+
+/* RXVOICE */
+static const struct snd_kcontrol_new wm8400_dapm_rxvoice_controls[] = {
+SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8400_INPUT_MIXER5, WM8400_LR4BVOL_SHIFT,
+			WM8400_LR4BVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8400_INPUT_MIXER6, WM8400_RL4BVOL_SHIFT,
+			WM8400_RL4BVOL_MASK, 0, in_mix_tlv),
+};
+
+/* LOMIX */
+static const struct snd_kcontrol_new wm8400_dapm_lomix_controls[] = {
+SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8400_OUTPUT_MIXER1,
+	WM8400_LRBLO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8400_OUTPUT_MIXER1,
+	WM8400_LLBLO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8400_OUTPUT_MIXER1,
+	WM8400_LRI3LO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8400_OUTPUT_MIXER1,
+	WM8400_LLI3LO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER1,
+	WM8400_LR12LO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER1,
+	WM8400_LL12LO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8400_OUTPUT_MIXER1,
+	WM8400_LDLO_SHIFT, 1, 0),
+};
+
+/* ROMIX */
+static const struct snd_kcontrol_new wm8400_dapm_romix_controls[] = {
+SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8400_OUTPUT_MIXER2,
+	WM8400_RLBRO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8400_OUTPUT_MIXER2,
+	WM8400_RRBRO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8400_OUTPUT_MIXER2,
+	WM8400_RLI3RO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8400_OUTPUT_MIXER2,
+	WM8400_RRI3RO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER2,
+	WM8400_RL12RO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER2,
+	WM8400_RR12RO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8400_OUTPUT_MIXER2,
+	WM8400_RDRO_SHIFT, 1, 0),
+};
+
+/* LONMIX */
+static const struct snd_kcontrol_new wm8400_dapm_lonmix_controls[] = {
+SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8400_LINE_MIXER1,
+	WM8400_LLOPGALON_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8400_LINE_MIXER1,
+	WM8400_LROPGALON_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8400_LINE_MIXER1,
+	WM8400_LOPLON_SHIFT, 1, 0),
+};
+
+/* LOPMIX */
+static const struct snd_kcontrol_new wm8400_dapm_lopmix_controls[] = {
+SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8400_LINE_MIXER1,
+	WM8400_LR12LOP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8400_LINE_MIXER1,
+	WM8400_LL12LOP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8400_LINE_MIXER1,
+	WM8400_LLOPGALOP_SHIFT, 1, 0),
+};
+
+/* RONMIX */
+static const struct snd_kcontrol_new wm8400_dapm_ronmix_controls[] = {
+SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8400_LINE_MIXER2,
+	WM8400_RROPGARON_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8400_LINE_MIXER2,
+	WM8400_RLOPGARON_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8400_LINE_MIXER2,
+	WM8400_ROPRON_SHIFT, 1, 0),
+};
+
+/* ROPMIX */
+static const struct snd_kcontrol_new wm8400_dapm_ropmix_controls[] = {
+SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8400_LINE_MIXER2,
+	WM8400_RL12ROP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8400_LINE_MIXER2,
+	WM8400_RR12ROP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8400_LINE_MIXER2,
+	WM8400_RROPGAROP_SHIFT, 1, 0),
+};
+
+/* OUT3MIX */
+static const struct snd_kcontrol_new wm8400_dapm_out3mix_controls[] = {
+SOC_DAPM_SINGLE("OUT3MIX LIN4/RXP Bypass Switch", WM8400_OUT3_4_MIXER,
+	WM8400_LI4O3_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8400_OUT3_4_MIXER,
+	WM8400_LPGAO3_SHIFT, 1, 0),
+};
+
+/* OUT4MIX */
+static const struct snd_kcontrol_new wm8400_dapm_out4mix_controls[] = {
+SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8400_OUT3_4_MIXER,
+	WM8400_RPGAO4_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("OUT4MIX RIN4/RXP Bypass Switch", WM8400_OUT3_4_MIXER,
+	WM8400_RI4O4_SHIFT, 1, 0),
+};
+
+/* SPKMIX */
+static const struct snd_kcontrol_new wm8400_dapm_spkmix_controls[] = {
+SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8400_SPEAKER_MIXER,
+	WM8400_LI2SPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8400_SPEAKER_MIXER,
+	WM8400_LB2SPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8400_SPEAKER_MIXER,
+	WM8400_LOPGASPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8400_SPEAKER_MIXER,
+	WM8400_LDSPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8400_SPEAKER_MIXER,
+	WM8400_RDSPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8400_SPEAKER_MIXER,
+	WM8400_ROPGASPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8400_SPEAKER_MIXER,
+	WM8400_RL12ROP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8400_SPEAKER_MIXER,
+	WM8400_RI2SPK_SHIFT, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8400_dapm_widgets[] = {
+/* Input Side */
+/* Input Lines */
+SND_SOC_DAPM_INPUT("LIN1"),
+SND_SOC_DAPM_INPUT("LIN2"),
+SND_SOC_DAPM_INPUT("LIN3"),
+SND_SOC_DAPM_INPUT("LIN4/RXN"),
+SND_SOC_DAPM_INPUT("RIN3"),
+SND_SOC_DAPM_INPUT("RIN4/RXP"),
+SND_SOC_DAPM_INPUT("RIN1"),
+SND_SOC_DAPM_INPUT("RIN2"),
+SND_SOC_DAPM_INPUT("Internal ADC Source"),
+
+/* DACs */
+SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8400_POWER_MANAGEMENT_2,
+	WM8400_ADCL_ENA_SHIFT, 0),
+SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8400_POWER_MANAGEMENT_2,
+	WM8400_ADCR_ENA_SHIFT, 0),
+
+/* Input PGAs */
+SND_SOC_DAPM_MIXER("LIN12 PGA", WM8400_POWER_MANAGEMENT_2,
+		   WM8400_LIN12_ENA_SHIFT,
+		   0, &wm8400_dapm_lin12_pga_controls[0],
+		   ARRAY_SIZE(wm8400_dapm_lin12_pga_controls)),
+SND_SOC_DAPM_MIXER("LIN34 PGA", WM8400_POWER_MANAGEMENT_2,
+		   WM8400_LIN34_ENA_SHIFT,
+		   0, &wm8400_dapm_lin34_pga_controls[0],
+		   ARRAY_SIZE(wm8400_dapm_lin34_pga_controls)),
+SND_SOC_DAPM_MIXER("RIN12 PGA", WM8400_POWER_MANAGEMENT_2,
+		   WM8400_RIN12_ENA_SHIFT,
+		   0, &wm8400_dapm_rin12_pga_controls[0],
+		   ARRAY_SIZE(wm8400_dapm_rin12_pga_controls)),
+SND_SOC_DAPM_MIXER("RIN34 PGA", WM8400_POWER_MANAGEMENT_2,
+		   WM8400_RIN34_ENA_SHIFT,
+		   0, &wm8400_dapm_rin34_pga_controls[0],
+		   ARRAY_SIZE(wm8400_dapm_rin34_pga_controls)),
+
+SND_SOC_DAPM_SUPPLY("INL", WM8400_POWER_MANAGEMENT_2, WM8400_AINL_ENA_SHIFT,
+		    0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("INR", WM8400_POWER_MANAGEMENT_2, WM8400_AINR_ENA_SHIFT,
+		    0, NULL, 0),
+
+/* INMIXL */
+SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0,
+	&wm8400_dapm_inmixl_controls[0],
+	ARRAY_SIZE(wm8400_dapm_inmixl_controls)),
+
+/* AINLMUX */
+SND_SOC_DAPM_MUX("AILNMUX", SND_SOC_NOPM, 0, 0, &wm8400_dapm_ainlmux_controls),
+
+/* INMIXR */
+SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0,
+	&wm8400_dapm_inmixr_controls[0],
+	ARRAY_SIZE(wm8400_dapm_inmixr_controls)),
+
+/* AINRMUX */
+SND_SOC_DAPM_MUX("AIRNMUX", SND_SOC_NOPM, 0, 0, &wm8400_dapm_ainrmux_controls),
+
+/* Output Side */
+/* DACs */
+SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8400_POWER_MANAGEMENT_3,
+	WM8400_DACL_ENA_SHIFT, 0),
+SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8400_POWER_MANAGEMENT_3,
+	WM8400_DACR_ENA_SHIFT, 0),
+
+/* LOMIX */
+SND_SOC_DAPM_MIXER_E("LOMIX", WM8400_POWER_MANAGEMENT_3,
+		     WM8400_LOMIX_ENA_SHIFT,
+		     0, &wm8400_dapm_lomix_controls[0],
+		     ARRAY_SIZE(wm8400_dapm_lomix_controls),
+		     outmixer_event, SND_SOC_DAPM_PRE_REG),
+
+/* LONMIX */
+SND_SOC_DAPM_MIXER("LONMIX", WM8400_POWER_MANAGEMENT_3, WM8400_LON_ENA_SHIFT,
+		   0, &wm8400_dapm_lonmix_controls[0],
+		   ARRAY_SIZE(wm8400_dapm_lonmix_controls)),
+
+/* LOPMIX */
+SND_SOC_DAPM_MIXER("LOPMIX", WM8400_POWER_MANAGEMENT_3, WM8400_LOP_ENA_SHIFT,
+		   0, &wm8400_dapm_lopmix_controls[0],
+		   ARRAY_SIZE(wm8400_dapm_lopmix_controls)),
+
+/* OUT3MIX */
+SND_SOC_DAPM_MIXER("OUT3MIX", WM8400_POWER_MANAGEMENT_1, WM8400_OUT3_ENA_SHIFT,
+		   0, &wm8400_dapm_out3mix_controls[0],
+		   ARRAY_SIZE(wm8400_dapm_out3mix_controls)),
+
+/* SPKMIX */
+SND_SOC_DAPM_MIXER_E("SPKMIX", WM8400_POWER_MANAGEMENT_1, WM8400_SPK_ENA_SHIFT,
+		     0, &wm8400_dapm_spkmix_controls[0],
+		     ARRAY_SIZE(wm8400_dapm_spkmix_controls), outmixer_event,
+		     SND_SOC_DAPM_PRE_REG),
+
+/* OUT4MIX */
+SND_SOC_DAPM_MIXER("OUT4MIX", WM8400_POWER_MANAGEMENT_1, WM8400_OUT4_ENA_SHIFT,
+	0, &wm8400_dapm_out4mix_controls[0],
+	ARRAY_SIZE(wm8400_dapm_out4mix_controls)),
+
+/* ROPMIX */
+SND_SOC_DAPM_MIXER("ROPMIX", WM8400_POWER_MANAGEMENT_3, WM8400_ROP_ENA_SHIFT,
+		   0, &wm8400_dapm_ropmix_controls[0],
+		   ARRAY_SIZE(wm8400_dapm_ropmix_controls)),
+
+/* RONMIX */
+SND_SOC_DAPM_MIXER("RONMIX", WM8400_POWER_MANAGEMENT_3, WM8400_RON_ENA_SHIFT,
+		   0, &wm8400_dapm_ronmix_controls[0],
+		   ARRAY_SIZE(wm8400_dapm_ronmix_controls)),
+
+/* ROMIX */
+SND_SOC_DAPM_MIXER_E("ROMIX", WM8400_POWER_MANAGEMENT_3,
+		     WM8400_ROMIX_ENA_SHIFT,
+		     0, &wm8400_dapm_romix_controls[0],
+		     ARRAY_SIZE(wm8400_dapm_romix_controls),
+		     outmixer_event, SND_SOC_DAPM_PRE_REG),
+
+/* LOUT PGA */
+SND_SOC_DAPM_PGA("LOUT PGA", WM8400_POWER_MANAGEMENT_1, WM8400_LOUT_ENA_SHIFT,
+		 0, NULL, 0),
+
+/* ROUT PGA */
+SND_SOC_DAPM_PGA("ROUT PGA", WM8400_POWER_MANAGEMENT_1, WM8400_ROUT_ENA_SHIFT,
+		 0, NULL, 0),
+
+/* LOPGA */
+SND_SOC_DAPM_PGA("LOPGA", WM8400_POWER_MANAGEMENT_3, WM8400_LOPGA_ENA_SHIFT, 0,
+	NULL, 0),
+
+/* ROPGA */
+SND_SOC_DAPM_PGA("ROPGA", WM8400_POWER_MANAGEMENT_3, WM8400_ROPGA_ENA_SHIFT, 0,
+	NULL, 0),
+
+/* MICBIAS */
+SND_SOC_DAPM_SUPPLY("MICBIAS", WM8400_POWER_MANAGEMENT_1,
+		    WM8400_MIC1BIAS_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("LON"),
+SND_SOC_DAPM_OUTPUT("LOP"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("SPKN"),
+SND_SOC_DAPM_OUTPUT("SPKP"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("OUT4"),
+SND_SOC_DAPM_OUTPUT("ROP"),
+SND_SOC_DAPM_OUTPUT("RON"),
+
+SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
+};
+
+static const struct snd_soc_dapm_route wm8400_dapm_routes[] = {
+	/* Make DACs turn on when playing even if not mixed into any outputs */
+	{"Internal DAC Sink", NULL, "Left DAC"},
+	{"Internal DAC Sink", NULL, "Right DAC"},
+
+	/* Make ADCs turn on when recording
+	 * even if not mixed from any inputs */
+	{"Left ADC", NULL, "Internal ADC Source"},
+	{"Right ADC", NULL, "Internal ADC Source"},
+
+	/* Input Side */
+	/* LIN12 PGA */
+	{"LIN12 PGA", "LIN1 Switch", "LIN1"},
+	{"LIN12 PGA", "LIN2 Switch", "LIN2"},
+	/* LIN34 PGA */
+	{"LIN34 PGA", "LIN3 Switch", "LIN3"},
+	{"LIN34 PGA", "LIN4 Switch", "LIN4/RXN"},
+	/* INMIXL */
+	{"INMIXL", NULL, "INL"},
+	{"INMIXL", "Record Left Volume", "LOMIX"},
+	{"INMIXL", "LIN2 Volume", "LIN2"},
+	{"INMIXL", "LINPGA12 Switch", "LIN12 PGA"},
+	{"INMIXL", "LINPGA34 Switch", "LIN34 PGA"},
+	/* AILNMUX */
+	{"AILNMUX", NULL, "INL"},
+	{"AILNMUX", "INMIXL Mix", "INMIXL"},
+	{"AILNMUX", "DIFFINL Mix", "LIN12 PGA"},
+	{"AILNMUX", "DIFFINL Mix", "LIN34 PGA"},
+	{"AILNMUX", "RXVOICE Mix", "LIN4/RXN"},
+	{"AILNMUX", "RXVOICE Mix", "RIN4/RXP"},
+	/* ADC */
+	{"Left ADC", NULL, "AILNMUX"},
+
+	/* RIN12 PGA */
+	{"RIN12 PGA", "RIN1 Switch", "RIN1"},
+	{"RIN12 PGA", "RIN2 Switch", "RIN2"},
+	/* RIN34 PGA */
+	{"RIN34 PGA", "RIN3 Switch", "RIN3"},
+	{"RIN34 PGA", "RIN4 Switch", "RIN4/RXP"},
+	/* INMIXR */
+	{"INMIXR", NULL, "INR"},
+	{"INMIXR", "Record Right Volume", "ROMIX"},
+	{"INMIXR", "RIN2 Volume", "RIN2"},
+	{"INMIXR", "RINPGA12 Switch", "RIN12 PGA"},
+	{"INMIXR", "RINPGA34 Switch", "RIN34 PGA"},
+	/* AIRNMUX */
+	{"AIRNMUX", NULL, "INR"},
+	{"AIRNMUX", "INMIXR Mix", "INMIXR"},
+	{"AIRNMUX", "DIFFINR Mix", "RIN12 PGA"},
+	{"AIRNMUX", "DIFFINR Mix", "RIN34 PGA"},
+	{"AIRNMUX", "RXVOICE Mix", "LIN4/RXN"},
+	{"AIRNMUX", "RXVOICE Mix", "RIN4/RXP"},
+	/* ADC */
+	{"Right ADC", NULL, "AIRNMUX"},
+
+	/* LOMIX */
+	{"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"},
+	{"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"},
+	{"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
+	{"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
+	{"LOMIX", "LOMIX Right ADC Bypass Switch", "AIRNMUX"},
+	{"LOMIX", "LOMIX Left ADC Bypass Switch", "AILNMUX"},
+	{"LOMIX", "LOMIX Left DAC Switch", "Left DAC"},
+
+	/* ROMIX */
+	{"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"},
+	{"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"},
+	{"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
+	{"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
+	{"ROMIX", "ROMIX Right ADC Bypass Switch", "AIRNMUX"},
+	{"ROMIX", "ROMIX Left ADC Bypass Switch", "AILNMUX"},
+	{"ROMIX", "ROMIX Right DAC Switch", "Right DAC"},
+
+	/* SPKMIX */
+	{"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"},
+	{"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"},
+	{"SPKMIX", "SPKMIX LADC Bypass Switch", "AILNMUX"},
+	{"SPKMIX", "SPKMIX RADC Bypass Switch", "AIRNMUX"},
+	{"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"},
+	{"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"},
+	{"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"},
+	{"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"},
+
+	/* LONMIX */
+	{"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"},
+	{"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"},
+	{"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"},
+
+	/* LOPMIX */
+	{"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"},
+	{"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"},
+	{"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"},
+
+	/* OUT3MIX */
+	{"OUT3MIX", "OUT3MIX LIN4/RXP Bypass Switch", "LIN4/RXN"},
+	{"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"},
+
+	/* OUT4MIX */
+	{"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"},
+	{"OUT4MIX", "OUT4MIX RIN4/RXP Bypass Switch", "RIN4/RXP"},
+
+	/* RONMIX */
+	{"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"},
+	{"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"},
+	{"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"},
+
+	/* ROPMIX */
+	{"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"},
+	{"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"},
+	{"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"},
+
+	/* Out Mixer PGAs */
+	{"LOPGA", NULL, "LOMIX"},
+	{"ROPGA", NULL, "ROMIX"},
+
+	{"LOUT PGA", NULL, "LOMIX"},
+	{"ROUT PGA", NULL, "ROMIX"},
+
+	/* Output Pins */
+	{"LON", NULL, "LONMIX"},
+	{"LOP", NULL, "LOPMIX"},
+	{"OUT3", NULL, "OUT3MIX"},
+	{"LOUT", NULL, "LOUT PGA"},
+	{"SPKN", NULL, "SPKMIX"},
+	{"ROUT", NULL, "ROUT PGA"},
+	{"OUT4", NULL, "OUT4MIX"},
+	{"ROP", NULL, "ROPMIX"},
+	{"RON", NULL, "RONMIX"},
+};
+
+/*
+ * Clock after FLL and dividers
+ */
+static int wm8400_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8400_priv *wm8400 = snd_soc_component_get_drvdata(component);
+
+	wm8400->sysclk = freq;
+	return 0;
+}
+
+struct fll_factors {
+	u16 n;
+	u16 k;
+	u16 outdiv;
+	u16 fratio;
+	u16 freq_ref;
+};
+
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors,
+		       unsigned int Fref, unsigned int Fout)
+{
+	u64 Kpart;
+	unsigned int K, Nmod, target;
+
+	factors->outdiv = 2;
+	while (Fout * factors->outdiv <  90000000 ||
+	       Fout * factors->outdiv > 100000000) {
+		factors->outdiv *= 2;
+		if (factors->outdiv > 32) {
+			dev_err(wm8400->wm8400->dev,
+				"Unsupported FLL output frequency %uHz\n",
+				Fout);
+			return -EINVAL;
+		}
+	}
+	target = Fout * factors->outdiv;
+	factors->outdiv = factors->outdiv >> 2;
+
+	if (Fref < 48000)
+		factors->freq_ref = 1;
+	else
+		factors->freq_ref = 0;
+
+	if (Fref < 1000000)
+		factors->fratio = 9;
+	else
+		factors->fratio = 0;
+
+	/* Ensure we have a fractional part */
+	do {
+		if (Fref < 1000000)
+			factors->fratio--;
+		else
+			factors->fratio++;
+
+		if (factors->fratio < 1 || factors->fratio > 8) {
+			dev_err(wm8400->wm8400->dev,
+				"Unable to calculate FRATIO\n");
+			return -EINVAL;
+		}
+
+		factors->n = target / (Fref * factors->fratio);
+		Nmod = target % (Fref * factors->fratio);
+	} while (Nmod == 0);
+
+	/* Calculate fractional part - scale up so we can round. */
+	Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, (Fref * factors->fratio));
+
+	K = Kpart & 0xFFFFFFFF;
+
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	factors->k = K / 10;
+
+	dev_dbg(wm8400->wm8400->dev,
+		"FLL: Fref=%u Fout=%u N=%x K=%x, FRATIO=%x OUTDIV=%x\n",
+		Fref, Fout,
+		factors->n, factors->k, factors->fratio, factors->outdiv);
+
+	return 0;
+}
+
+static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+			      int source, unsigned int freq_in,
+			      unsigned int freq_out)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8400_priv *wm8400 = snd_soc_component_get_drvdata(component);
+	struct fll_factors factors;
+	int ret;
+	u16 reg;
+
+	if (freq_in == wm8400->fll_in && freq_out == wm8400->fll_out)
+		return 0;
+
+	if (freq_out) {
+		ret = fll_factors(wm8400, &factors, freq_in, freq_out);
+		if (ret != 0)
+			return ret;
+	} else {
+		/* Bodge GCC 4.4.0 uninitialised variable warning - it
+		 * doesn't seem capable of working out that we exit if
+		 * freq_out is 0 before any of the uses. */
+		memset(&factors, 0, sizeof(factors));
+	}
+
+	wm8400->fll_out = freq_out;
+	wm8400->fll_in = freq_in;
+
+	/* We *must* disable the FLL before any changes */
+	reg = snd_soc_component_read32(component, WM8400_POWER_MANAGEMENT_2);
+	reg &= ~WM8400_FLL_ENA;
+	snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_2, reg);
+
+	reg = snd_soc_component_read32(component, WM8400_FLL_CONTROL_1);
+	reg &= ~WM8400_FLL_OSC_ENA;
+	snd_soc_component_write(component, WM8400_FLL_CONTROL_1, reg);
+
+	if (!freq_out)
+		return 0;
+
+	reg &= ~(WM8400_FLL_REF_FREQ | WM8400_FLL_FRATIO_MASK);
+	reg |= WM8400_FLL_FRAC | factors.fratio;
+	reg |= factors.freq_ref << WM8400_FLL_REF_FREQ_SHIFT;
+	snd_soc_component_write(component, WM8400_FLL_CONTROL_1, reg);
+
+	snd_soc_component_write(component, WM8400_FLL_CONTROL_2, factors.k);
+	snd_soc_component_write(component, WM8400_FLL_CONTROL_3, factors.n);
+
+	reg = snd_soc_component_read32(component, WM8400_FLL_CONTROL_4);
+	reg &= ~WM8400_FLL_OUTDIV_MASK;
+	reg |= factors.outdiv;
+	snd_soc_component_write(component, WM8400_FLL_CONTROL_4, reg);
+
+	return 0;
+}
+
+/*
+ * Sets ADC and Voice DAC format.
+ */
+static int wm8400_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 audio1, audio3;
+
+	audio1 = snd_soc_component_read32(component, WM8400_AUDIO_INTERFACE_1);
+	audio3 = snd_soc_component_read32(component, WM8400_AUDIO_INTERFACE_3);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		audio3 &= ~WM8400_AIF_MSTR1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		audio3 |= WM8400_AIF_MSTR1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	audio1 &= ~WM8400_AIF_FMT_MASK;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		audio1 |= WM8400_AIF_FMT_I2S;
+		audio1 &= ~WM8400_AIF_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		audio1 |= WM8400_AIF_FMT_RIGHTJ;
+		audio1 &= ~WM8400_AIF_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		audio1 |= WM8400_AIF_FMT_LEFTJ;
+		audio1 &= ~WM8400_AIF_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		audio1 |= WM8400_AIF_FMT_DSP;
+		audio1 &= ~WM8400_AIF_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		audio1 |= WM8400_AIF_FMT_DSP | WM8400_AIF_LRCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8400_AUDIO_INTERFACE_1, audio1);
+	snd_soc_component_write(component, WM8400_AUDIO_INTERFACE_3, audio3);
+	return 0;
+}
+
+static int wm8400_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+		int div_id, int div)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 reg;
+
+	switch (div_id) {
+	case WM8400_MCLK_DIV:
+		reg = snd_soc_component_read32(component, WM8400_CLOCKING_2) &
+			~WM8400_MCLK_DIV_MASK;
+		snd_soc_component_write(component, WM8400_CLOCKING_2, reg | div);
+		break;
+	case WM8400_DACCLK_DIV:
+		reg = snd_soc_component_read32(component, WM8400_CLOCKING_2) &
+			~WM8400_DAC_CLKDIV_MASK;
+		snd_soc_component_write(component, WM8400_CLOCKING_2, reg | div);
+		break;
+	case WM8400_ADCCLK_DIV:
+		reg = snd_soc_component_read32(component, WM8400_CLOCKING_2) &
+			~WM8400_ADC_CLKDIV_MASK;
+		snd_soc_component_write(component, WM8400_CLOCKING_2, reg | div);
+		break;
+	case WM8400_BCLK_DIV:
+		reg = snd_soc_component_read32(component, WM8400_CLOCKING_1) &
+			~WM8400_BCLK_DIV_MASK;
+		snd_soc_component_write(component, WM8400_CLOCKING_1, reg | div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ */
+static int wm8400_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 audio1 = snd_soc_component_read32(component, WM8400_AUDIO_INTERFACE_1);
+
+	audio1 &= ~WM8400_AIF_WL_MASK;
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		audio1 |= WM8400_AIF_WL_20BITS;
+		break;
+	case 24:
+		audio1 |= WM8400_AIF_WL_24BITS;
+		break;
+	case 32:
+		audio1 |= WM8400_AIF_WL_32BITS;
+		break;
+	}
+
+	snd_soc_component_write(component, WM8400_AUDIO_INTERFACE_1, audio1);
+	return 0;
+}
+
+static int wm8400_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 val = snd_soc_component_read32(component, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE;
+
+	if (mute)
+		snd_soc_component_write(component, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+	else
+		snd_soc_component_write(component, WM8400_DAC_CTRL, val);
+
+	return 0;
+}
+
+/* TODO: set bias for best performance at standby */
+static int wm8400_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8400_priv *wm8400 = snd_soc_component_get_drvdata(component);
+	u16 val;
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* VMID=2*50k */
+		val = snd_soc_component_read32(component, WM8400_POWER_MANAGEMENT_1) &
+			~WM8400_VMID_MODE_MASK;
+		snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1, val | 0x2);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(power),
+						    &power[0]);
+			if (ret != 0) {
+				dev_err(wm8400->wm8400->dev,
+					"Failed to enable regulators: %d\n",
+					ret);
+				return ret;
+			}
+
+			snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1,
+				     WM8400_CODEC_ENA | WM8400_SYSCLK_ENA);
+
+			/* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
+			snd_soc_component_write(component, WM8400_ANTIPOP2, WM8400_SOFTST |
+				     WM8400_BUFDCOPEN | WM8400_POBCTRL);
+
+			msleep(50);
+
+			/* Enable VREF & VMID at 2x50k */
+			val = snd_soc_component_read32(component, WM8400_POWER_MANAGEMENT_1);
+			val |= 0x2 | WM8400_VREF_ENA;
+			snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1, val);
+
+			/* Enable BUFIOEN */
+			snd_soc_component_write(component, WM8400_ANTIPOP2, WM8400_SOFTST |
+				     WM8400_BUFDCOPEN | WM8400_POBCTRL |
+				     WM8400_BUFIOEN);
+
+			/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
+			snd_soc_component_write(component, WM8400_ANTIPOP2, WM8400_BUFIOEN);
+		}
+
+		/* VMID=2*300k */
+		val = snd_soc_component_read32(component, WM8400_POWER_MANAGEMENT_1) &
+			~WM8400_VMID_MODE_MASK;
+		snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1, val | 0x4);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* Enable POBCTRL and SOFT_ST */
+		snd_soc_component_write(component, WM8400_ANTIPOP2, WM8400_SOFTST |
+			WM8400_POBCTRL | WM8400_BUFIOEN);
+
+		/* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
+		snd_soc_component_write(component, WM8400_ANTIPOP2, WM8400_SOFTST |
+			WM8400_BUFDCOPEN | WM8400_POBCTRL |
+			WM8400_BUFIOEN);
+
+		/* mute DAC */
+		val = snd_soc_component_read32(component, WM8400_DAC_CTRL);
+		snd_soc_component_write(component, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+
+		/* Enable any disabled outputs */
+		val = snd_soc_component_read32(component, WM8400_POWER_MANAGEMENT_1);
+		val |= WM8400_SPK_ENA | WM8400_OUT3_ENA |
+			WM8400_OUT4_ENA | WM8400_LOUT_ENA |
+			WM8400_ROUT_ENA;
+		snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1, val);
+
+		/* Disable VMID */
+		val &= ~WM8400_VMID_MODE_MASK;
+		snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1, val);
+
+		msleep(300);
+
+		/* Enable all output discharge bits */
+		snd_soc_component_write(component, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
+			WM8400_DIS_RLINE | WM8400_DIS_OUT3 |
+			WM8400_DIS_OUT4 | WM8400_DIS_LOUT |
+			WM8400_DIS_ROUT);
+
+		/* Disable VREF */
+		val &= ~WM8400_VREF_ENA;
+		snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1, val);
+
+		/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
+		snd_soc_component_write(component, WM8400_ANTIPOP2, 0x0);
+
+		ret = regulator_bulk_disable(ARRAY_SIZE(power),
+					     &power[0]);
+		if (ret != 0)
+			return ret;
+
+		break;
+	}
+
+	return 0;
+}
+
+#define WM8400_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8400_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops wm8400_dai_ops = {
+	.hw_params = wm8400_hw_params,
+	.digital_mute = wm8400_mute,
+	.set_fmt = wm8400_set_dai_fmt,
+	.set_clkdiv = wm8400_set_dai_clkdiv,
+	.set_sysclk = wm8400_set_dai_sysclk,
+	.set_pll = wm8400_set_dai_pll,
+};
+
+/*
+ * The WM8400 supports 2 different and mutually exclusive DAI
+ * configurations.
+ *
+ * 1. ADC/DAC on Primary Interface
+ * 2. ADC on Primary Interface/DAC on secondary
+ */
+static struct snd_soc_dai_driver wm8400_dai = {
+/* ADC/DAC on primary */
+	.name = "wm8400-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8400_RATES,
+		.formats = WM8400_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8400_RATES,
+		.formats = WM8400_FORMATS,
+	},
+	.ops = &wm8400_dai_ops,
+};
+
+static int wm8400_component_probe(struct snd_soc_component *component)
+{
+	struct wm8400 *wm8400 = dev_get_platdata(component->dev);
+	struct wm8400_priv *priv;
+	int ret;
+	u16 reg;
+
+	priv = devm_kzalloc(component->dev, sizeof(struct wm8400_priv),
+			    GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	snd_soc_component_init_regmap(component, wm8400->regmap);
+	snd_soc_component_set_drvdata(component, priv);
+	priv->wm8400 = wm8400;
+
+	ret = devm_regulator_bulk_get(wm8400->dev,
+				 ARRAY_SIZE(power), &power[0]);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to get regulators: %d\n", ret);
+		return ret;
+	}
+
+	wm8400_component_reset(component);
+
+	reg = snd_soc_component_read32(component, WM8400_POWER_MANAGEMENT_1);
+	snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA);
+
+	/* Latch volume update bits */
+	reg = snd_soc_component_read32(component, WM8400_LEFT_LINE_INPUT_1_2_VOLUME);
+	snd_soc_component_write(component, WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+		     reg & WM8400_IPVU);
+	reg = snd_soc_component_read32(component, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME);
+	snd_soc_component_write(component, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+		     reg & WM8400_IPVU);
+
+	snd_soc_component_write(component, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
+	snd_soc_component_write(component, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
+
+	return 0;
+}
+
+static void  wm8400_component_remove(struct snd_soc_component *component)
+{
+	u16 reg;
+
+	reg = snd_soc_component_read32(component, WM8400_POWER_MANAGEMENT_1);
+	snd_soc_component_write(component, WM8400_POWER_MANAGEMENT_1,
+		     reg & (~WM8400_CODEC_ENA));
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8400 = {
+	.probe			= wm8400_component_probe,
+	.remove			= wm8400_component_remove,
+	.set_bias_level		= wm8400_set_bias_level,
+	.controls		= wm8400_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8400_snd_controls),
+	.dapm_widgets		= wm8400_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8400_dapm_widgets),
+	.dapm_routes		= wm8400_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8400_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm8400_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm8400,
+			&wm8400_dai, 1);
+}
+
+static struct platform_driver wm8400_codec_driver = {
+	.driver = {
+		   .name = "wm8400-codec",
+		   },
+	.probe = wm8400_probe,
+};
+
+module_platform_driver(wm8400_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM8400 driver");
+MODULE_AUTHOR("Mark Brown");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8400-codec");
diff --git a/sound/soc/codecs/wm8400.h b/sound/soc/codecs/wm8400.h
new file mode 100644
index 0000000..521adb1
--- /dev/null
+++ b/sound/soc/codecs/wm8400.h
@@ -0,0 +1,59 @@
+/*
+ * wm8400.h  --  audio driver for WM8400
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef _WM8400_CODEC_H
+#define _WM8400_CODEC_H
+
+#define WM8400_MCLK_DIV 0
+#define WM8400_DACCLK_DIV 1
+#define WM8400_ADCCLK_DIV 2
+#define WM8400_BCLK_DIV 3
+
+#define WM8400_MCLK_DIV_1 0x400
+#define WM8400_MCLK_DIV_2 0x800
+
+#define WM8400_DAC_CLKDIV_1    0x00
+#define WM8400_DAC_CLKDIV_1_5  0x04
+#define WM8400_DAC_CLKDIV_2    0x08
+#define WM8400_DAC_CLKDIV_3    0x0c
+#define WM8400_DAC_CLKDIV_4    0x10
+#define WM8400_DAC_CLKDIV_5_5  0x14
+#define WM8400_DAC_CLKDIV_6    0x18
+
+#define WM8400_ADC_CLKDIV_1    0x00
+#define WM8400_ADC_CLKDIV_1_5  0x20
+#define WM8400_ADC_CLKDIV_2    0x40
+#define WM8400_ADC_CLKDIV_3    0x60
+#define WM8400_ADC_CLKDIV_4    0x80
+#define WM8400_ADC_CLKDIV_5_5  0xa0
+#define WM8400_ADC_CLKDIV_6    0xc0
+
+
+#define WM8400_BCLK_DIV_1                       (0x0 << 1)
+#define WM8400_BCLK_DIV_1_5                     (0x1 << 1)
+#define WM8400_BCLK_DIV_2                       (0x2 << 1)
+#define WM8400_BCLK_DIV_3                       (0x3 << 1)
+#define WM8400_BCLK_DIV_4                       (0x4 << 1)
+#define WM8400_BCLK_DIV_5_5                     (0x5 << 1)
+#define WM8400_BCLK_DIV_6                       (0x6 << 1)
+#define WM8400_BCLK_DIV_8                       (0x7 << 1)
+#define WM8400_BCLK_DIV_11                      (0x8 << 1)
+#define WM8400_BCLK_DIV_12                      (0x9 << 1)
+#define WM8400_BCLK_DIV_16                      (0xA << 1)
+#define WM8400_BCLK_DIV_22                      (0xB << 1)
+#define WM8400_BCLK_DIV_24                      (0xC << 1)
+#define WM8400_BCLK_DIV_32                      (0xD << 1)
+#define WM8400_BCLK_DIV_44                      (0xE << 1)
+#define WM8400_BCLK_DIV_48                      (0xF << 1)
+
+#endif
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
new file mode 100644
index 0000000..1a2412d
--- /dev/null
+++ b/sound/soc/codecs/wm8510.c
@@ -0,0 +1,724 @@
+/*
+ * wm8510.c  --  WM8510 ALSA Soc Audio driver
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include "wm8510.h"
+
+/*
+ * wm8510 register cache
+ * We can't read the WM8510 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ */
+static const struct reg_default wm8510_reg_defaults[] = {
+	{  1, 0x0000 },
+	{  2, 0x0000 },
+	{  3, 0x0000 },
+	{  4, 0x0050 },
+	{  5, 0x0000 },
+	{  6, 0x0140 },
+	{  7, 0x0000 },
+	{  8, 0x0000 },
+	{  9, 0x0000 },
+	{ 10, 0x0000 },
+	{ 11, 0x00ff },
+	{ 12, 0x0000 },
+	{ 13, 0x0000 },
+	{ 14, 0x0100 },
+	{ 15, 0x00ff },
+	{ 16, 0x0000 },
+	{ 17, 0x0000 },
+	{ 18, 0x012c },
+	{ 19, 0x002c },
+	{ 20, 0x002c },
+	{ 21, 0x002c },
+	{ 22, 0x002c },
+	{ 23, 0x0000 },
+	{ 24, 0x0032 },
+	{ 25, 0x0000 },
+	{ 26, 0x0000 },
+	{ 27, 0x0000 },
+	{ 28, 0x0000 },
+	{ 29, 0x0000 },
+	{ 30, 0x0000 },
+	{ 31, 0x0000 },
+	{ 32, 0x0038 },
+	{ 33, 0x000b },
+	{ 34, 0x0032 },
+	{ 35, 0x0000 },
+	{ 36, 0x0008 },
+	{ 37, 0x000c },
+	{ 38, 0x0093 },
+	{ 39, 0x00e9 },
+	{ 40, 0x0000 },
+	{ 41, 0x0000 },
+	{ 42, 0x0000 },
+	{ 43, 0x0000 },
+	{ 44, 0x0003 },
+	{ 45, 0x0010 },
+	{ 46, 0x0000 },
+	{ 47, 0x0000 },
+	{ 48, 0x0000 },
+	{ 49, 0x0002 },
+	{ 50, 0x0001 },
+	{ 51, 0x0000 },
+	{ 52, 0x0000 },
+	{ 53, 0x0000 },
+	{ 54, 0x0039 },
+	{ 55, 0x0000 },
+	{ 56, 0x0001 },
+};
+
+static bool wm8510_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8510_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+#define WM8510_POWER1_BIASEN  0x08
+#define WM8510_POWER1_BUFIOEN 0x10
+
+#define wm8510_reset(c)	snd_soc_component_write(c, WM8510_RESET, 0)
+
+/* codec private data */
+struct wm8510_priv {
+	struct regmap *regmap;
+};
+
+static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" };
+static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
+static const char *wm8510_alc[] = { "ALC", "Limiter" };
+
+static const struct soc_enum wm8510_enum[] = {
+	SOC_ENUM_SINGLE(WM8510_COMP, 1, 4, wm8510_companding), /* adc */
+	SOC_ENUM_SINGLE(WM8510_COMP, 3, 4, wm8510_companding), /* dac */
+	SOC_ENUM_SINGLE(WM8510_DAC,  4, 4, wm8510_deemp),
+	SOC_ENUM_SINGLE(WM8510_ALC3,  8, 2, wm8510_alc),
+};
+
+static const struct snd_kcontrol_new wm8510_snd_controls[] = {
+
+SOC_SINGLE("Digital Loopback Switch", WM8510_COMP, 0, 1, 0),
+
+SOC_ENUM("DAC Companding", wm8510_enum[1]),
+SOC_ENUM("ADC Companding", wm8510_enum[0]),
+
+SOC_ENUM("Playback De-emphasis", wm8510_enum[2]),
+SOC_SINGLE("DAC Inversion Switch", WM8510_DAC, 0, 1, 0),
+
+SOC_SINGLE("Master Playback Volume", WM8510_DACVOL, 0, 127, 0),
+
+SOC_SINGLE("High Pass Filter Switch", WM8510_ADC, 8, 1, 0),
+SOC_SINGLE("High Pass Cut Off", WM8510_ADC, 4, 7, 0),
+SOC_SINGLE("ADC Inversion Switch", WM8510_COMP, 0, 1, 0),
+
+SOC_SINGLE("Capture Volume", WM8510_ADCVOL,  0, 127, 0),
+
+SOC_SINGLE("DAC Playback Limiter Switch", WM8510_DACLIM1,  8, 1, 0),
+SOC_SINGLE("DAC Playback Limiter Decay", WM8510_DACLIM1,  4, 15, 0),
+SOC_SINGLE("DAC Playback Limiter Attack", WM8510_DACLIM1,  0, 15, 0),
+
+SOC_SINGLE("DAC Playback Limiter Threshold", WM8510_DACLIM2,  4, 7, 0),
+SOC_SINGLE("DAC Playback Limiter Boost", WM8510_DACLIM2,  0, 15, 0),
+
+SOC_SINGLE("ALC Enable Switch", WM8510_ALC1,  8, 1, 0),
+SOC_SINGLE("ALC Capture Max Gain", WM8510_ALC1,  3, 7, 0),
+SOC_SINGLE("ALC Capture Min Gain", WM8510_ALC1,  0, 7, 0),
+
+SOC_SINGLE("ALC Capture ZC Switch", WM8510_ALC2,  8, 1, 0),
+SOC_SINGLE("ALC Capture Hold", WM8510_ALC2,  4, 7, 0),
+SOC_SINGLE("ALC Capture Target", WM8510_ALC2,  0, 15, 0),
+
+SOC_ENUM("ALC Capture Mode", wm8510_enum[3]),
+SOC_SINGLE("ALC Capture Decay", WM8510_ALC3,  4, 15, 0),
+SOC_SINGLE("ALC Capture Attack", WM8510_ALC3,  0, 15, 0),
+
+SOC_SINGLE("ALC Capture Noise Gate Switch", WM8510_NGATE,  3, 1, 0),
+SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8510_NGATE,  0, 7, 0),
+
+SOC_SINGLE("Capture PGA ZC Switch", WM8510_INPPGA,  7, 1, 0),
+SOC_SINGLE("Capture PGA Volume", WM8510_INPPGA,  0, 63, 0),
+
+SOC_SINGLE("Speaker Playback ZC Switch", WM8510_SPKVOL,  7, 1, 0),
+SOC_SINGLE("Speaker Playback Switch", WM8510_SPKVOL,  6, 1, 1),
+SOC_SINGLE("Speaker Playback Volume", WM8510_SPKVOL,  0, 63, 0),
+SOC_SINGLE("Speaker Boost", WM8510_OUTPUT, 2, 1, 0),
+
+SOC_SINGLE("Capture Boost(+20dB)", WM8510_ADCBOOST,  8, 1, 0),
+SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1),
+};
+
+/* Speaker Output Mixer */
+static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 1, 0),
+SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_SPKMIX, 5, 1, 0),
+SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_SPKMIX, 0, 1, 0),
+};
+
+/* Mono Output Mixer */
+static const struct snd_kcontrol_new wm8510_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_MONOMIX, 1, 1, 0),
+SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_MONOMIX, 2, 1, 0),
+SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_MONOMIX, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8510_boost_controls[] = {
+SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA,  6, 1, 1),
+SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0),
+SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0),
+};
+
+static const struct snd_kcontrol_new wm8510_micpga_controls[] = {
+SOC_DAPM_SINGLE("MICP Switch", WM8510_INPUT, 0, 1, 0),
+SOC_DAPM_SINGLE("MICN Switch", WM8510_INPUT, 1, 1, 0),
+SOC_DAPM_SINGLE("AUX Switch", WM8510_INPUT, 2, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8510_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Speaker Mixer", WM8510_POWER3, 2, 0,
+	&wm8510_speaker_mixer_controls[0],
+	ARRAY_SIZE(wm8510_speaker_mixer_controls)),
+SND_SOC_DAPM_MIXER("Mono Mixer", WM8510_POWER3, 3, 0,
+	&wm8510_mono_mixer_controls[0],
+	ARRAY_SIZE(wm8510_mono_mixer_controls)),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8510_POWER3, 0, 0),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8510_POWER2, 0, 0),
+SND_SOC_DAPM_PGA("Aux Input", WM8510_POWER1, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("Mic PGA", WM8510_POWER2, 2, 0,
+		   &wm8510_micpga_controls[0],
+		   ARRAY_SIZE(wm8510_micpga_controls)),
+SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0,
+	&wm8510_boost_controls[0],
+	ARRAY_SIZE(wm8510_boost_controls)),
+
+SND_SOC_DAPM_MICBIAS("Mic Bias", WM8510_POWER1, 4, 0),
+
+SND_SOC_DAPM_INPUT("MICN"),
+SND_SOC_DAPM_INPUT("MICP"),
+SND_SOC_DAPM_INPUT("AUX"),
+SND_SOC_DAPM_OUTPUT("MONOOUT"),
+SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+};
+
+static const struct snd_soc_dapm_route wm8510_dapm_routes[] = {
+	/* Mono output mixer */
+	{"Mono Mixer", "PCM Playback Switch", "DAC"},
+	{"Mono Mixer", "Aux Playback Switch", "Aux Input"},
+	{"Mono Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+	/* Speaker output mixer */
+	{"Speaker Mixer", "PCM Playback Switch", "DAC"},
+	{"Speaker Mixer", "Aux Playback Switch", "Aux Input"},
+	{"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+	/* Outputs */
+	{"Mono Out", NULL, "Mono Mixer"},
+	{"MONOOUT", NULL, "Mono Out"},
+	{"SpkN Out", NULL, "Speaker Mixer"},
+	{"SpkP Out", NULL, "Speaker Mixer"},
+	{"SPKOUTN", NULL, "SpkN Out"},
+	{"SPKOUTP", NULL, "SpkP Out"},
+
+	/* Microphone PGA */
+	{"Mic PGA", "MICN Switch", "MICN"},
+	{"Mic PGA", "MICP Switch", "MICP"},
+	{ "Mic PGA", "AUX Switch", "Aux Input" },
+
+	/* Boost Mixer */
+	{"Boost Mixer", "Mic PGA Switch", "Mic PGA"},
+	{"Boost Mixer", "Mic Volume", "MICP"},
+	{"Boost Mixer", "Aux Volume", "Aux Input"},
+
+	{"ADC", NULL, "Boost Mixer"},
+};
+
+struct pll_ {
+	unsigned int pre_div:4; /* prescale - 1 */
+	unsigned int n:4;
+	unsigned int k;
+};
+
+static struct pll_ pll_div;
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 24) * 10)
+
+static void pll_factors(unsigned int target, unsigned int source)
+{
+	unsigned long long Kpart;
+	unsigned int K, Ndiv, Nmod;
+
+	Ndiv = target / source;
+	if (Ndiv < 6) {
+		source >>= 1;
+		pll_div.pre_div = 1;
+		Ndiv = target / source;
+	} else
+		pll_div.pre_div = 0;
+
+	if ((Ndiv < 6) || (Ndiv > 12))
+		printk(KERN_WARNING
+			"WM8510 N value %u outwith recommended range!d\n",
+			Ndiv);
+
+	pll_div.n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	/* Check if we need to round */
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	K /= 10;
+
+	pll_div.k = K;
+}
+
+static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+		int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 reg;
+
+	if (freq_in == 0 || freq_out == 0) {
+		/* Clock CODEC directly from MCLK */
+		reg = snd_soc_component_read32(component, WM8510_CLOCK);
+		snd_soc_component_write(component, WM8510_CLOCK, reg & 0x0ff);
+
+		/* Turn off PLL */
+		reg = snd_soc_component_read32(component, WM8510_POWER1);
+		snd_soc_component_write(component, WM8510_POWER1, reg & 0x1df);
+		return 0;
+	}
+
+	pll_factors(freq_out*4, freq_in);
+
+	snd_soc_component_write(component, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
+	snd_soc_component_write(component, WM8510_PLLK1, pll_div.k >> 18);
+	snd_soc_component_write(component, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff);
+	snd_soc_component_write(component, WM8510_PLLK3, pll_div.k & 0x1ff);
+	reg = snd_soc_component_read32(component, WM8510_POWER1);
+	snd_soc_component_write(component, WM8510_POWER1, reg | 0x020);
+
+	/* Run CODEC from PLL instead of MCLK */
+	reg = snd_soc_component_read32(component, WM8510_CLOCK);
+	snd_soc_component_write(component, WM8510_CLOCK, reg | 0x100);
+
+	return 0;
+}
+
+/*
+ * Configure WM8510 clock dividers.
+ */
+static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+		int div_id, int div)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 reg;
+
+	switch (div_id) {
+	case WM8510_OPCLKDIV:
+		reg = snd_soc_component_read32(component, WM8510_GPIO) & 0x1cf;
+		snd_soc_component_write(component, WM8510_GPIO, reg | div);
+		break;
+	case WM8510_MCLKDIV:
+		reg = snd_soc_component_read32(component, WM8510_CLOCK) & 0x11f;
+		snd_soc_component_write(component, WM8510_CLOCK, reg | div);
+		break;
+	case WM8510_ADCCLK:
+		reg = snd_soc_component_read32(component, WM8510_ADC) & 0x1f7;
+		snd_soc_component_write(component, WM8510_ADC, reg | div);
+		break;
+	case WM8510_DACCLK:
+		reg = snd_soc_component_read32(component, WM8510_DAC) & 0x1f7;
+		snd_soc_component_write(component, WM8510_DAC, reg | div);
+		break;
+	case WM8510_BCLKDIV:
+		reg = snd_soc_component_read32(component, WM8510_CLOCK) & 0x1e3;
+		snd_soc_component_write(component, WM8510_CLOCK, reg | div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = 0;
+	u16 clk = snd_soc_component_read32(component, WM8510_CLOCK) & 0x1fe;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		clk |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0010;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0008;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x00018;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0180;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0100;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0080;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8510_IFACE, iface);
+	snd_soc_component_write(component, WM8510_CLOCK, clk);
+	return 0;
+}
+
+static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 iface = snd_soc_component_read32(component, WM8510_IFACE) & 0x19f;
+	u16 adn = snd_soc_component_read32(component, WM8510_ADD) & 0x1f1;
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		iface |= 0x0020;
+		break;
+	case 24:
+		iface |= 0x0040;
+		break;
+	case 32:
+		iface |= 0x0060;
+		break;
+	}
+
+	/* filter coefficient */
+	switch (params_rate(params)) {
+	case 8000:
+		adn |= 0x5 << 1;
+		break;
+	case 11025:
+		adn |= 0x4 << 1;
+		break;
+	case 16000:
+		adn |= 0x3 << 1;
+		break;
+	case 22050:
+		adn |= 0x2 << 1;
+		break;
+	case 32000:
+		adn |= 0x1 << 1;
+		break;
+	case 44100:
+	case 48000:
+		break;
+	}
+
+	snd_soc_component_write(component, WM8510_IFACE, iface);
+	snd_soc_component_write(component, WM8510_ADD, adn);
+	return 0;
+}
+
+static int wm8510_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8510_DAC) & 0xffbf;
+
+	if (mute)
+		snd_soc_component_write(component, WM8510_DAC, mute_reg | 0x40);
+	else
+		snd_soc_component_write(component, WM8510_DAC, mute_reg);
+	return 0;
+}
+
+/* liam need to make this lower power with dapm */
+static int wm8510_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	struct wm8510_priv *wm8510 = snd_soc_component_get_drvdata(component);
+	u16 power1 = snd_soc_component_read32(component, WM8510_POWER1) & ~0x3;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		power1 |= 0x1;  /* VMID 50k */
+		snd_soc_component_write(component, WM8510_POWER1, power1);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
+
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			regcache_sync(wm8510->regmap);
+
+			/* Initial cap charge at VMID 5k */
+			snd_soc_component_write(component, WM8510_POWER1, power1 | 0x3);
+			mdelay(100);
+		}
+
+		power1 |= 0x2;  /* VMID 500k */
+		snd_soc_component_write(component, WM8510_POWER1, power1);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_write(component, WM8510_POWER1, 0);
+		snd_soc_component_write(component, WM8510_POWER2, 0);
+		snd_soc_component_write(component, WM8510_POWER3, 0);
+		break;
+	}
+
+	return 0;
+}
+
+#define WM8510_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define WM8510_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8510_dai_ops = {
+	.hw_params	= wm8510_pcm_hw_params,
+	.digital_mute	= wm8510_mute,
+	.set_fmt	= wm8510_set_dai_fmt,
+	.set_clkdiv	= wm8510_set_dai_clkdiv,
+	.set_pll	= wm8510_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver wm8510_dai = {
+	.name = "wm8510-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM8510_RATES,
+		.formats = WM8510_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM8510_RATES,
+		.formats = WM8510_FORMATS,},
+	.ops = &wm8510_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int wm8510_probe(struct snd_soc_component *component)
+{
+	wm8510_reset(component);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8510 = {
+	.probe			= wm8510_probe,
+	.set_bias_level		= wm8510_set_bias_level,
+	.controls		= wm8510_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8510_snd_controls),
+	.dapm_widgets		= wm8510_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8510_dapm_widgets),
+	.dapm_routes		= wm8510_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8510_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct of_device_id wm8510_of_match[] = {
+	{ .compatible = "wlf,wm8510" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, wm8510_of_match);
+
+static const struct regmap_config wm8510_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+	.max_register = WM8510_MONOMIX,
+
+	.reg_defaults = wm8510_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8510_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = wm8510_volatile,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8510_spi_probe(struct spi_device *spi)
+{
+	struct wm8510_priv *wm8510;
+	int ret;
+
+	wm8510 = devm_kzalloc(&spi->dev, sizeof(struct wm8510_priv),
+			      GFP_KERNEL);
+	if (wm8510 == NULL)
+		return -ENOMEM;
+
+	wm8510->regmap = devm_regmap_init_spi(spi, &wm8510_regmap);
+	if (IS_ERR(wm8510->regmap))
+		return PTR_ERR(wm8510->regmap);
+
+	spi_set_drvdata(spi, wm8510);
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8510, &wm8510_dai, 1);
+
+	return ret;
+}
+
+static struct spi_driver wm8510_spi_driver = {
+	.driver = {
+		.name	= "wm8510",
+		.of_match_table = wm8510_of_match,
+	},
+	.probe		= wm8510_spi_probe,
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8510_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8510_priv *wm8510;
+	int ret;
+
+	wm8510 = devm_kzalloc(&i2c->dev, sizeof(struct wm8510_priv),
+			      GFP_KERNEL);
+	if (wm8510 == NULL)
+		return -ENOMEM;
+
+	wm8510->regmap = devm_regmap_init_i2c(i2c, &wm8510_regmap);
+	if (IS_ERR(wm8510->regmap))
+		return PTR_ERR(wm8510->regmap);
+
+	i2c_set_clientdata(i2c, wm8510);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8510, &wm8510_dai, 1);
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8510_i2c_id[] = {
+	{ "wm8510", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
+
+static struct i2c_driver wm8510_i2c_driver = {
+	.driver = {
+		.name = "wm8510",
+		.of_match_table = wm8510_of_match,
+	},
+	.probe =    wm8510_i2c_probe,
+	.id_table = wm8510_i2c_id,
+};
+#endif
+
+static int __init wm8510_modinit(void)
+{
+	int ret = 0;
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&wm8510_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8510 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8510_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8510 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return ret;
+}
+module_init(wm8510_modinit);
+
+static void __exit wm8510_exit(void)
+{
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&wm8510_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8510_spi_driver);
+#endif
+}
+module_exit(wm8510_exit);
+
+MODULE_DESCRIPTION("ASoC WM8510 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h
new file mode 100644
index 0000000..b3e26ed
--- /dev/null
+++ b/sound/soc/codecs/wm8510.h
@@ -0,0 +1,102 @@
+/*
+ * wm8510.h  --  WM8510 Soc Audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8510_H
+#define _WM8510_H
+
+/* WM8510 register space */
+
+#define WM8510_RESET		0x0
+#define WM8510_POWER1		0x1
+#define WM8510_POWER2		0x2
+#define WM8510_POWER3		0x3
+#define WM8510_IFACE		0x4
+#define WM8510_COMP			0x5
+#define WM8510_CLOCK		0x6
+#define WM8510_ADD			0x7
+#define WM8510_GPIO			0x8
+#define WM8510_DAC			0xa
+#define WM8510_DACVOL		0xb
+#define WM8510_ADC			0xe
+#define WM8510_ADCVOL		0xf
+#define WM8510_EQ1			0x12
+#define WM8510_EQ2			0x13
+#define WM8510_EQ3			0x14
+#define WM8510_EQ4			0x15
+#define WM8510_EQ5			0x16
+#define WM8510_DACLIM1		0x18
+#define WM8510_DACLIM2		0x19
+#define WM8510_NOTCH1		0x1b
+#define WM8510_NOTCH2		0x1c
+#define WM8510_NOTCH3		0x1d
+#define WM8510_NOTCH4		0x1e
+#define WM8510_ALC1			0x20
+#define WM8510_ALC2			0x21
+#define WM8510_ALC3			0x22
+#define WM8510_NGATE		0x23
+#define WM8510_PLLN			0x24
+#define WM8510_PLLK1		0x25
+#define WM8510_PLLK2		0x26
+#define WM8510_PLLK3		0x27
+#define WM8510_ATTEN		0x28
+#define WM8510_INPUT		0x2c
+#define WM8510_INPPGA		0x2d
+#define WM8510_ADCBOOST		0x2f
+#define WM8510_OUTPUT		0x31
+#define WM8510_SPKMIX		0x32
+#define WM8510_SPKVOL		0x36
+#define WM8510_MONOMIX		0x38
+
+#define WM8510_CACHEREGNUM 	57
+
+/* Clock divider Id's */
+#define WM8510_OPCLKDIV		0
+#define WM8510_MCLKDIV		1
+#define WM8510_ADCCLK		2
+#define WM8510_DACCLK		3
+#define WM8510_BCLKDIV		4
+
+/* DAC clock dividers */
+#define WM8510_DACCLK_F2	(1 << 3)
+#define WM8510_DACCLK_F4	(0 << 3)
+
+/* ADC clock dividers */
+#define WM8510_ADCCLK_F2	(1 << 3)
+#define WM8510_ADCCLK_F4	(0 << 3)
+
+/* PLL Out dividers */
+#define WM8510_OPCLKDIV_1	(0 << 4)
+#define WM8510_OPCLKDIV_2	(1 << 4)
+#define WM8510_OPCLKDIV_3	(2 << 4)
+#define WM8510_OPCLKDIV_4	(3 << 4)
+
+/* BCLK clock dividers */
+#define WM8510_BCLKDIV_1	(0 << 2)
+#define WM8510_BCLKDIV_2	(1 << 2)
+#define WM8510_BCLKDIV_4	(2 << 2)
+#define WM8510_BCLKDIV_8	(3 << 2)
+#define WM8510_BCLKDIV_16	(4 << 2)
+#define WM8510_BCLKDIV_32	(5 << 2)
+
+/* MCLK clock dividers */
+#define WM8510_MCLKDIV_1	(0 << 5)
+#define WM8510_MCLKDIV_1_5	(1 << 5)
+#define WM8510_MCLKDIV_2	(2 << 5)
+#define WM8510_MCLKDIV_3	(3 << 5)
+#define WM8510_MCLKDIV_4	(4 << 5)
+#define WM8510_MCLKDIV_6	(5 << 5)
+#define WM8510_MCLKDIV_8	(6 << 5)
+#define WM8510_MCLKDIV_12	(7 << 5)
+
+struct wm8510_setup_data {
+	int spi;
+	int i2c_bus;
+	unsigned short i2c_address;
+};
+
+#endif
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
new file mode 100644
index 0000000..f4a9e25
--- /dev/null
+++ b/sound/soc/codecs/wm8523.c
@@ -0,0 +1,544 @@
+/*
+ * wm8523.c  --  WM8523 ALSA SoC Audio driver
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8523.h"
+
+#define WM8523_NUM_SUPPLIES 2
+static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {
+	"AVDD",
+	"LINEVDD",
+};
+
+#define WM8523_NUM_RATES 7
+
+/* codec private data */
+struct wm8523_priv {
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES];
+	unsigned int sysclk;
+	unsigned int rate_constraint_list[WM8523_NUM_RATES];
+	struct snd_pcm_hw_constraint_list rate_constraint;
+};
+
+static const struct reg_default wm8523_reg_defaults[] = {
+	{ 2, 0x0000 },     /* R2 - PSCTRL1 */
+	{ 3, 0x1812 },     /* R3 - AIF_CTRL1 */
+	{ 4, 0x0000 },     /* R4 - AIF_CTRL2 */
+	{ 5, 0x0001 },     /* R5 - DAC_CTRL3 */
+	{ 6, 0x0190 },     /* R6 - DAC_GAINL */
+	{ 7, 0x0190 },     /* R7 - DAC_GAINR */
+	{ 8, 0x0000 },     /* R8 - ZERO_DETECT */
+};
+
+static bool wm8523_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8523_DEVICE_ID:
+	case WM8523_REVISION:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -10000, 25, 0);
+
+static const char *wm8523_zd_count_text[] = {
+	"1024",
+	"2048",
+};
+
+static SOC_ENUM_SINGLE_DECL(wm8523_zc_count, WM8523_ZERO_DETECT, 0,
+			    wm8523_zd_count_text);
+
+static const struct snd_kcontrol_new wm8523_controls[] = {
+SOC_DOUBLE_R_TLV("Playback Volume", WM8523_DAC_GAINL, WM8523_DAC_GAINR,
+		 0, 448, 0, dac_tlv),
+SOC_SINGLE("ZC Switch", WM8523_DAC_CTRL3, 4, 1, 0),
+SOC_SINGLE("Playback Deemphasis Switch", WM8523_AIF_CTRL1, 8, 1, 0),
+SOC_DOUBLE("Playback Switch", WM8523_DAC_CTRL3, 2, 3, 1, 1),
+SOC_SINGLE("Volume Ramp Up Switch", WM8523_DAC_CTRL3, 1, 1, 0),
+SOC_SINGLE("Volume Ramp Down Switch", WM8523_DAC_CTRL3, 0, 1, 0),
+SOC_ENUM("Zero Detect Count", wm8523_zc_count),
+};
+
+static const struct snd_soc_dapm_widget wm8523_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_OUTPUT("LINEVOUTL"),
+SND_SOC_DAPM_OUTPUT("LINEVOUTR"),
+};
+
+static const struct snd_soc_dapm_route wm8523_dapm_routes[] = {
+	{ "LINEVOUTL", NULL, "DAC" },
+	{ "LINEVOUTR", NULL, "DAC" },
+};
+
+static const struct {
+	int value;
+	int ratio;
+} lrclk_ratios[WM8523_NUM_RATES] = {
+	{ 1, 128 },
+	{ 2, 192 },
+	{ 3, 256 },
+	{ 4, 384 },
+	{ 5, 512 },
+	{ 6, 768 },
+	{ 7, 1152 },
+};
+
+static const struct {
+	int value;
+	int ratio;
+} bclk_ratios[] = {
+	{ 2, 32 },
+	{ 3, 64 },
+	{ 4, 128 },
+};
+
+static int wm8523_startup(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
+
+	/* The set of sample rates that can be supported depends on the
+	 * MCLK supplied to the CODEC - enforce this.
+	 */
+	if (!wm8523->sysclk) {
+		dev_err(component->dev,
+			"No MCLK configured, call set_sysclk() on init\n");
+		return -EINVAL;
+	}
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+				   SNDRV_PCM_HW_PARAM_RATE,
+				   &wm8523->rate_constraint);
+
+	return 0;
+}
+
+static int wm8523_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
+	int i;
+	u16 aifctrl1 = snd_soc_component_read32(component, WM8523_AIF_CTRL1);
+	u16 aifctrl2 = snd_soc_component_read32(component, WM8523_AIF_CTRL2);
+
+	/* Find a supported LRCLK ratio */
+	for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
+		if (wm8523->sysclk / params_rate(params) ==
+		    lrclk_ratios[i].ratio)
+			break;
+	}
+
+	/* Should never happen, should be handled by constraints */
+	if (i == ARRAY_SIZE(lrclk_ratios)) {
+		dev_err(component->dev, "MCLK/fs ratio %d unsupported\n",
+			wm8523->sysclk / params_rate(params));
+		return -EINVAL;
+	}
+
+	aifctrl2 &= ~WM8523_SR_MASK;
+	aifctrl2 |= lrclk_ratios[i].value;
+
+	if (aifctrl1 & WM8523_AIF_MSTR) {
+		/* Find a fs->bclk ratio */
+		for (i = 0; i < ARRAY_SIZE(bclk_ratios); i++)
+			if (params_width(params) * 2 <= bclk_ratios[i].ratio)
+				break;
+
+		if (i == ARRAY_SIZE(bclk_ratios)) {
+			dev_err(component->dev,
+				"No matching BCLK/fs ratio for word length %d\n",
+				params_width(params));
+			return -EINVAL;
+		}
+
+		aifctrl2 &= ~WM8523_BCLKDIV_MASK;
+		aifctrl2 |= bclk_ratios[i].value << WM8523_BCLKDIV_SHIFT;
+	}
+
+	aifctrl1 &= ~WM8523_WL_MASK;
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		aifctrl1 |= 0x8;
+		break;
+	case 24:
+		aifctrl1 |= 0x10;
+		break;
+	case 32:
+		aifctrl1 |= 0x18;
+		break;
+	}
+
+	snd_soc_component_write(component, WM8523_AIF_CTRL1, aifctrl1);
+	snd_soc_component_write(component, WM8523_AIF_CTRL2, aifctrl2);
+
+	return 0;
+}
+
+static int wm8523_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+	int i;
+
+	wm8523->sysclk = freq;
+
+	wm8523->rate_constraint.count = 0;
+	for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
+		val = freq / lrclk_ratios[i].ratio;
+		/* Check that it's a standard rate since core can't
+		 * cope with others and having the odd rates confuses
+		 * constraint matching.
+		 */
+		switch (val) {
+		case 8000:
+		case 11025:
+		case 16000:
+		case 22050:
+		case 32000:
+		case 44100:
+		case 48000:
+		case 64000:
+		case 88200:
+		case 96000:
+		case 176400:
+		case 192000:
+			dev_dbg(component->dev, "Supported sample rate: %dHz\n",
+				val);
+			wm8523->rate_constraint_list[i] = val;
+			wm8523->rate_constraint.count++;
+			break;
+		default:
+			dev_dbg(component->dev, "Skipping sample rate: %dHz\n",
+				val);
+		}
+	}
+
+	/* Need at least one supported rate... */
+	if (wm8523->rate_constraint.count == 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+
+static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 aifctrl1 = snd_soc_component_read32(component, WM8523_AIF_CTRL1);
+
+	aifctrl1 &= ~(WM8523_BCLK_INV_MASK | WM8523_LRCLK_INV_MASK |
+		      WM8523_FMT_MASK | WM8523_AIF_MSTR_MASK);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aifctrl1 |= WM8523_AIF_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		aifctrl1 |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aifctrl1 |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		aifctrl1 |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		aifctrl1 |= 0x0023;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		aifctrl1 |= WM8523_BCLK_INV | WM8523_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		aifctrl1 |= WM8523_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		aifctrl1 |= WM8523_LRCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8523_AIF_CTRL1, aifctrl1);
+
+	return 0;
+}
+
+static int wm8523_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* Full power on */
+		snd_soc_component_update_bits(component, WM8523_PSCTRL1,
+				    WM8523_SYS_ENA_MASK, 3);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
+						    wm8523->supplies);
+			if (ret != 0) {
+				dev_err(component->dev,
+					"Failed to enable supplies: %d\n",
+					ret);
+				return ret;
+			}
+
+			/* Sync back default/cached values */
+			regcache_sync(wm8523->regmap);
+
+			/* Initial power up */
+			snd_soc_component_update_bits(component, WM8523_PSCTRL1,
+					    WM8523_SYS_ENA_MASK, 1);
+
+			msleep(100);
+		}
+
+		/* Power up to mute */
+		snd_soc_component_update_bits(component, WM8523_PSCTRL1,
+				    WM8523_SYS_ENA_MASK, 2);
+
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* The chip runs through the power down sequence for us. */
+		snd_soc_component_update_bits(component, WM8523_PSCTRL1,
+				    WM8523_SYS_ENA_MASK, 0);
+		msleep(100);
+
+		regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies),
+				       wm8523->supplies);
+		break;
+	}
+	return 0;
+}
+
+#define WM8523_RATES SNDRV_PCM_RATE_8000_192000
+
+#define WM8523_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8523_dai_ops = {
+	.startup	= wm8523_startup,
+	.hw_params	= wm8523_hw_params,
+	.set_sysclk	= wm8523_set_dai_sysclk,
+	.set_fmt	= wm8523_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver wm8523_dai = {
+	.name = "wm8523-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,  /* Mono modes not yet supported */
+		.channels_max = 2,
+		.rates = WM8523_RATES,
+		.formats = WM8523_FORMATS,
+	},
+	.ops = &wm8523_dai_ops,
+};
+
+static int wm8523_probe(struct snd_soc_component *component)
+{
+	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
+
+	wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
+	wm8523->rate_constraint.count =
+		ARRAY_SIZE(wm8523->rate_constraint_list);
+
+	/* Change some default settings - latch VU and enable ZC */
+	snd_soc_component_update_bits(component, WM8523_DAC_GAINR,
+			    WM8523_DACR_VU, WM8523_DACR_VU);
+	snd_soc_component_update_bits(component, WM8523_DAC_CTRL3, WM8523_ZC, WM8523_ZC);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8523 = {
+	.probe			= wm8523_probe,
+	.set_bias_level		= wm8523_set_bias_level,
+	.controls		= wm8523_controls,
+	.num_controls		= ARRAY_SIZE(wm8523_controls),
+	.dapm_widgets		= wm8523_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8523_dapm_widgets),
+	.dapm_routes		= wm8523_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8523_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct of_device_id wm8523_of_match[] = {
+	{ .compatible = "wlf,wm8523" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, wm8523_of_match);
+
+static const struct regmap_config wm8523_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.max_register = WM8523_ZERO_DETECT,
+
+	.reg_defaults = wm8523_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8523_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = wm8523_volatile_register,
+};
+
+static int wm8523_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8523_priv *wm8523;
+	unsigned int val;
+	int ret, i;
+
+	wm8523 = devm_kzalloc(&i2c->dev, sizeof(struct wm8523_priv),
+			      GFP_KERNEL);
+	if (wm8523 == NULL)
+		return -ENOMEM;
+
+	wm8523->regmap = devm_regmap_init_i2c(i2c, &wm8523_regmap);
+	if (IS_ERR(wm8523->regmap)) {
+		ret = PTR_ERR(wm8523->regmap);
+		dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++)
+		wm8523->supplies[i].supply = wm8523_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8523->supplies),
+				      wm8523->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
+				    wm8523->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(wm8523->regmap, WM8523_DEVICE_ID, &val);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read ID register\n");
+		goto err_enable;
+	}
+	if (val != 0x8523) {
+		dev_err(&i2c->dev, "Device is not a WM8523, ID is %x\n", ret);
+		ret = -EINVAL;
+		goto err_enable;
+	}
+
+	ret = regmap_read(wm8523->regmap, WM8523_REVISION, &val);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read revision register\n");
+		goto err_enable;
+	}
+	dev_info(&i2c->dev, "revision %c\n",
+		 (val & WM8523_CHIP_REV_MASK) + 'A');
+
+	ret = regmap_write(wm8523->regmap, WM8523_DEVICE_ID, 0x8523);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to reset device: %d\n", ret);
+		goto err_enable;
+	}
+
+	regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
+
+	i2c_set_clientdata(i2c, wm8523);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8523, &wm8523_dai, 1);
+
+	return ret;
+
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
+	return ret;
+}
+
+static const struct i2c_device_id wm8523_i2c_id[] = {
+	{ "wm8523", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id);
+
+static struct i2c_driver wm8523_i2c_driver = {
+	.driver = {
+		.name = "wm8523",
+		.of_match_table = wm8523_of_match,
+	},
+	.probe =    wm8523_i2c_probe,
+	.id_table = wm8523_i2c_id,
+};
+
+module_i2c_driver(wm8523_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8523 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8523.h b/sound/soc/codecs/wm8523.h
new file mode 100644
index 0000000..4d5b1eb
--- /dev/null
+++ b/sound/soc/codecs/wm8523.h
@@ -0,0 +1,157 @@
+/*
+ * wm8523.h  --  WM8423 ASoC driver
+ *
+ * Copyright 2009 Wolfson Microelectronics, plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * Based on wm8753.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8523_H
+#define _WM8523_H
+
+/*
+ * Register values.
+ */
+#define WM8523_DEVICE_ID                        0x00
+#define WM8523_REVISION                         0x01
+#define WM8523_PSCTRL1                          0x02
+#define WM8523_AIF_CTRL1                        0x03
+#define WM8523_AIF_CTRL2                        0x04
+#define WM8523_DAC_CTRL3                        0x05
+#define WM8523_DAC_GAINL                        0x06
+#define WM8523_DAC_GAINR                        0x07
+#define WM8523_ZERO_DETECT                      0x08
+
+#define WM8523_REGISTER_COUNT                   9
+#define WM8523_MAX_REGISTER                     0x08
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - DEVICE_ID
+ */
+#define WM8523_CHIP_ID_MASK                     0xFFFF  /* CHIP_ID - [15:0] */
+#define WM8523_CHIP_ID_SHIFT                         0  /* CHIP_ID - [15:0] */
+#define WM8523_CHIP_ID_WIDTH                        16  /* CHIP_ID - [15:0] */
+
+/*
+ * R1 (0x01) - REVISION
+ */
+#define WM8523_CHIP_REV_MASK                    0x0007  /* CHIP_REV - [2:0] */
+#define WM8523_CHIP_REV_SHIFT                        0  /* CHIP_REV - [2:0] */
+#define WM8523_CHIP_REV_WIDTH                        3  /* CHIP_REV - [2:0] */
+
+/*
+ * R2 (0x02) - PSCTRL1
+ */
+#define WM8523_SYS_ENA_MASK                     0x0003  /* SYS_ENA - [1:0] */
+#define WM8523_SYS_ENA_SHIFT                         0  /* SYS_ENA - [1:0] */
+#define WM8523_SYS_ENA_WIDTH                         2  /* SYS_ENA - [1:0] */
+
+/*
+ * R3 (0x03) - AIF_CTRL1
+ */
+#define WM8523_TDM_MODE_MASK                    0x1800  /* TDM_MODE - [12:11] */
+#define WM8523_TDM_MODE_SHIFT                       11  /* TDM_MODE - [12:11] */
+#define WM8523_TDM_MODE_WIDTH                        2  /* TDM_MODE - [12:11] */
+#define WM8523_TDM_SLOT_MASK                    0x0600  /* TDM_SLOT - [10:9] */
+#define WM8523_TDM_SLOT_SHIFT                        9  /* TDM_SLOT - [10:9] */
+#define WM8523_TDM_SLOT_WIDTH                        2  /* TDM_SLOT - [10:9] */
+#define WM8523_DEEMPH                           0x0100  /* DEEMPH  */
+#define WM8523_DEEMPH_MASK                      0x0100  /* DEEMPH  */
+#define WM8523_DEEMPH_SHIFT                          8  /* DEEMPH  */
+#define WM8523_DEEMPH_WIDTH                          1  /* DEEMPH  */
+#define WM8523_AIF_MSTR                         0x0080  /* AIF_MSTR  */
+#define WM8523_AIF_MSTR_MASK                    0x0080  /* AIF_MSTR  */
+#define WM8523_AIF_MSTR_SHIFT                        7  /* AIF_MSTR  */
+#define WM8523_AIF_MSTR_WIDTH                        1  /* AIF_MSTR  */
+#define WM8523_LRCLK_INV                        0x0040  /* LRCLK_INV  */
+#define WM8523_LRCLK_INV_MASK                   0x0040  /* LRCLK_INV  */
+#define WM8523_LRCLK_INV_SHIFT                       6  /* LRCLK_INV  */
+#define WM8523_LRCLK_INV_WIDTH                       1  /* LRCLK_INV  */
+#define WM8523_BCLK_INV                         0x0020  /* BCLK_INV  */
+#define WM8523_BCLK_INV_MASK                    0x0020  /* BCLK_INV  */
+#define WM8523_BCLK_INV_SHIFT                        5  /* BCLK_INV  */
+#define WM8523_BCLK_INV_WIDTH                        1  /* BCLK_INV  */
+#define WM8523_WL_MASK                          0x0018  /* WL - [4:3] */
+#define WM8523_WL_SHIFT                              3  /* WL - [4:3] */
+#define WM8523_WL_WIDTH                              2  /* WL - [4:3] */
+#define WM8523_FMT_MASK                         0x0007  /* FMT - [2:0] */
+#define WM8523_FMT_SHIFT                             0  /* FMT - [2:0] */
+#define WM8523_FMT_WIDTH                             3  /* FMT - [2:0] */
+
+/*
+ * R4 (0x04) - AIF_CTRL2
+ */
+#define WM8523_DAC_OP_MUX_MASK                  0x00C0  /* DAC_OP_MUX - [7:6] */
+#define WM8523_DAC_OP_MUX_SHIFT                      6  /* DAC_OP_MUX - [7:6] */
+#define WM8523_DAC_OP_MUX_WIDTH                      2  /* DAC_OP_MUX - [7:6] */
+#define WM8523_BCLKDIV_MASK                     0x0038  /* BCLKDIV - [5:3] */
+#define WM8523_BCLKDIV_SHIFT                         3  /* BCLKDIV - [5:3] */
+#define WM8523_BCLKDIV_WIDTH                         3  /* BCLKDIV - [5:3] */
+#define WM8523_SR_MASK                          0x0007  /* SR - [2:0] */
+#define WM8523_SR_SHIFT                              0  /* SR - [2:0] */
+#define WM8523_SR_WIDTH                              3  /* SR - [2:0] */
+
+/*
+ * R5 (0x05) - DAC_CTRL3
+ */
+#define WM8523_ZC                               0x0010  /* ZC  */
+#define WM8523_ZC_MASK                          0x0010  /* ZC  */
+#define WM8523_ZC_SHIFT                              4  /* ZC  */
+#define WM8523_ZC_WIDTH                              1  /* ZC  */
+#define WM8523_DACR                             0x0008  /* DACR  */
+#define WM8523_DACR_MASK                        0x0008  /* DACR  */
+#define WM8523_DACR_SHIFT                            3  /* DACR  */
+#define WM8523_DACR_WIDTH                            1  /* DACR  */
+#define WM8523_DACL                             0x0004  /* DACL  */
+#define WM8523_DACL_MASK                        0x0004  /* DACL  */
+#define WM8523_DACL_SHIFT                            2  /* DACL  */
+#define WM8523_DACL_WIDTH                            1  /* DACL  */
+#define WM8523_VOL_UP_RAMP                      0x0002  /* VOL_UP_RAMP  */
+#define WM8523_VOL_UP_RAMP_MASK                 0x0002  /* VOL_UP_RAMP  */
+#define WM8523_VOL_UP_RAMP_SHIFT                     1  /* VOL_UP_RAMP  */
+#define WM8523_VOL_UP_RAMP_WIDTH                     1  /* VOL_UP_RAMP  */
+#define WM8523_VOL_DOWN_RAMP                    0x0001  /* VOL_DOWN_RAMP  */
+#define WM8523_VOL_DOWN_RAMP_MASK               0x0001  /* VOL_DOWN_RAMP  */
+#define WM8523_VOL_DOWN_RAMP_SHIFT                   0  /* VOL_DOWN_RAMP  */
+#define WM8523_VOL_DOWN_RAMP_WIDTH                   1  /* VOL_DOWN_RAMP  */
+
+/*
+ * R6 (0x06) - DAC_GAINL
+ */
+#define WM8523_DACL_VU                          0x0200  /* DACL_VU  */
+#define WM8523_DACL_VU_MASK                     0x0200  /* DACL_VU  */
+#define WM8523_DACL_VU_SHIFT                         9  /* DACL_VU  */
+#define WM8523_DACL_VU_WIDTH                         1  /* DACL_VU  */
+#define WM8523_DACL_VOL_MASK                    0x01FF  /* DACL_VOL - [8:0] */
+#define WM8523_DACL_VOL_SHIFT                        0  /* DACL_VOL - [8:0] */
+#define WM8523_DACL_VOL_WIDTH                        9  /* DACL_VOL - [8:0] */
+
+/*
+ * R7 (0x07) - DAC_GAINR
+ */
+#define WM8523_DACR_VU                          0x0200  /* DACR_VU  */
+#define WM8523_DACR_VU_MASK                     0x0200  /* DACR_VU  */
+#define WM8523_DACR_VU_SHIFT                         9  /* DACR_VU  */
+#define WM8523_DACR_VU_WIDTH                         1  /* DACR_VU  */
+#define WM8523_DACR_VOL_MASK                    0x01FF  /* DACR_VOL - [8:0] */
+#define WM8523_DACR_VOL_SHIFT                        0  /* DACR_VOL - [8:0] */
+#define WM8523_DACR_VOL_WIDTH                        9  /* DACR_VOL - [8:0] */
+
+/*
+ * R8 (0x08) - ZERO_DETECT
+ */
+#define WM8523_ZD_COUNT_MASK                    0x0003  /* ZD_COUNT - [1:0] */
+#define WM8523_ZD_COUNT_SHIFT                        0  /* ZD_COUNT - [1:0] */
+#define WM8523_ZD_COUNT_WIDTH                        2  /* ZD_COUNT - [1:0] */
+
+#endif
diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c
new file mode 100644
index 0000000..fde444d
--- /dev/null
+++ b/sound/soc/codecs/wm8524.c
@@ -0,0 +1,255 @@
+/*
+ * wm8524.c  --  WM8524 ALSA SoC Audio driver
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2017 NXP
+ *
+ * Based on WM8523 ALSA SoC Audio driver written by Mark Brown
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#define WM8524_NUM_RATES 7
+
+/* codec private data */
+struct wm8524_priv {
+	struct gpio_desc *mute;
+	unsigned int sysclk;
+	unsigned int rate_constraint_list[WM8524_NUM_RATES];
+	struct snd_pcm_hw_constraint_list rate_constraint;
+};
+
+
+static const struct snd_soc_dapm_widget wm8524_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_OUTPUT("LINEVOUTL"),
+SND_SOC_DAPM_OUTPUT("LINEVOUTR"),
+};
+
+static const struct snd_soc_dapm_route wm8524_dapm_routes[] = {
+	{ "LINEVOUTL", NULL, "DAC" },
+	{ "LINEVOUTR", NULL, "DAC" },
+};
+
+static const struct {
+	int value;
+	int ratio;
+} lrclk_ratios[WM8524_NUM_RATES] = {
+	{ 1, 128 },
+	{ 2, 192 },
+	{ 3, 256 },
+	{ 4, 384 },
+	{ 5, 512 },
+	{ 6, 768 },
+	{ 7, 1152 },
+};
+
+static int wm8524_startup(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(component);
+
+	/* The set of sample rates that can be supported depends on the
+	 * MCLK supplied to the CODEC - enforce this.
+	 */
+	if (!wm8524->sysclk) {
+		dev_err(component->dev,
+			"No MCLK configured, call set_sysclk() on init\n");
+		return -EINVAL;
+	}
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+				   SNDRV_PCM_HW_PARAM_RATE,
+				   &wm8524->rate_constraint);
+
+	gpiod_set_value_cansleep(wm8524->mute, 1);
+
+	return 0;
+}
+
+static void wm8524_shutdown(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(component);
+
+	gpiod_set_value_cansleep(wm8524->mute, 0);
+}
+
+static int wm8524_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(component);
+	unsigned int val;
+	int i, j = 0;
+
+	wm8524->sysclk = freq;
+
+	wm8524->rate_constraint.count = 0;
+	for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
+		val = freq / lrclk_ratios[i].ratio;
+		/* Check that it's a standard rate since core can't
+		 * cope with others and having the odd rates confuses
+		 * constraint matching.
+		 */
+		switch (val) {
+		case 8000:
+		case 32000:
+		case 44100:
+		case 48000:
+		case 88200:
+		case 96000:
+		case 176400:
+		case 192000:
+			dev_dbg(component->dev, "Supported sample rate: %dHz\n",
+				val);
+			wm8524->rate_constraint_list[j++] = val;
+			wm8524->rate_constraint.count++;
+			break;
+		default:
+			dev_dbg(component->dev, "Skipping sample rate: %dHz\n",
+				val);
+		}
+	}
+
+	/* Need at least one supported rate... */
+	if (wm8524->rate_constraint.count == 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int wm8524_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK |
+		SND_SOC_DAIFMT_MASTER_MASK);
+
+	if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+		    SND_SOC_DAIFMT_CBS_CFS)) {
+		dev_err(codec_dai->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8524_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(dai->component);
+
+	if (wm8524->mute)
+		gpiod_set_value_cansleep(wm8524->mute, mute);
+
+	return 0;
+}
+
+#define WM8524_RATES SNDRV_PCM_RATE_8000_192000
+
+#define WM8524_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops wm8524_dai_ops = {
+	.startup	= wm8524_startup,
+	.shutdown	= wm8524_shutdown,
+	.set_sysclk	= wm8524_set_dai_sysclk,
+	.set_fmt	= wm8524_set_fmt,
+	.mute_stream	= wm8524_mute_stream,
+};
+
+static struct snd_soc_dai_driver wm8524_dai = {
+	.name = "wm8524-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM8524_RATES,
+		.formats = WM8524_FORMATS,
+	},
+	.ops = &wm8524_dai_ops,
+};
+
+static int wm8524_probe(struct snd_soc_component *component)
+{
+	struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(component);
+
+	wm8524->rate_constraint.list = &wm8524->rate_constraint_list[0];
+	wm8524->rate_constraint.count =
+		ARRAY_SIZE(wm8524->rate_constraint_list);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8524 = {
+	.probe			= wm8524_probe,
+	.dapm_widgets		= wm8524_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8524_dapm_widgets),
+	.dapm_routes		= wm8524_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8524_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct of_device_id wm8524_of_match[] = {
+	{ .compatible = "wlf,wm8524" },
+	{ /* sentinel*/ }
+};
+MODULE_DEVICE_TABLE(of, wm8524_of_match);
+
+static int wm8524_codec_probe(struct platform_device *pdev)
+{
+	struct wm8524_priv *wm8524;
+	int ret;
+
+	wm8524 = devm_kzalloc(&pdev->dev, sizeof(struct wm8524_priv),
+						  GFP_KERNEL);
+	if (wm8524 == NULL)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, wm8524);
+
+	wm8524->mute = devm_gpiod_get(&pdev->dev, "wlf,mute", GPIOD_OUT_LOW);
+	if (IS_ERR(wm8524->mute)) {
+		ret = PTR_ERR(wm8524->mute);
+		dev_err(&pdev->dev, "Failed to get mute line: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm8524, &wm8524_dai, 1);
+	if (ret < 0)
+		dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
+
+	return ret;
+}
+
+static struct platform_driver wm8524_codec_driver = {
+	.probe		= wm8524_codec_probe,
+	.driver		= {
+		.name	= "wm8524-codec",
+		.of_match_table = wm8524_of_match,
+	},
+};
+module_platform_driver(wm8524_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM8524 driver");
+MODULE_AUTHOR("Mihai Serban <mihai.serban@nxp.com>");
+MODULE_ALIAS("platform:wm8524-codec");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
new file mode 100644
index 0000000..fa4ad1b
--- /dev/null
+++ b/sound/soc/codecs/wm8580.c
@@ -0,0 +1,1066 @@
+/*
+ * wm8580.c  --  WM8580 and WM8581 ALSA Soc Audio driver
+ *
+ * Copyright 2008-12 Wolfson Microelectronics PLC.
+ *
+ *  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.
+ *
+ * Notes:
+ *  The WM8580 is a multichannel codec with S/PDIF support, featuring six
+ *  DAC channels and two ADC channels.
+ *
+ *  The WM8581 is a multichannel codec with S/PDIF support, featuring eight
+ *  DAC channels and two ADC channels.
+ *
+ *  Currently only the primary audio interface is supported - S/PDIF and
+ *  the secondary audio interfaces are not.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <asm/div64.h>
+
+#include "wm8580.h"
+
+/* WM8580 register space */
+#define WM8580_PLLA1                         0x00
+#define WM8580_PLLA2                         0x01
+#define WM8580_PLLA3                         0x02
+#define WM8580_PLLA4                         0x03
+#define WM8580_PLLB1                         0x04
+#define WM8580_PLLB2                         0x05
+#define WM8580_PLLB3                         0x06
+#define WM8580_PLLB4                         0x07
+#define WM8580_CLKSEL                        0x08
+#define WM8580_PAIF1                         0x09
+#define WM8580_PAIF2                         0x0A
+#define WM8580_SAIF1                         0x0B
+#define WM8580_PAIF3                         0x0C
+#define WM8580_PAIF4                         0x0D
+#define WM8580_SAIF2                         0x0E
+#define WM8580_DAC_CONTROL1                  0x0F
+#define WM8580_DAC_CONTROL2                  0x10
+#define WM8580_DAC_CONTROL3                  0x11
+#define WM8580_DAC_CONTROL4                  0x12
+#define WM8580_DAC_CONTROL5                  0x13
+#define WM8580_DIGITAL_ATTENUATION_DACL1     0x14
+#define WM8580_DIGITAL_ATTENUATION_DACR1     0x15
+#define WM8580_DIGITAL_ATTENUATION_DACL2     0x16
+#define WM8580_DIGITAL_ATTENUATION_DACR2     0x17
+#define WM8580_DIGITAL_ATTENUATION_DACL3     0x18
+#define WM8580_DIGITAL_ATTENUATION_DACR3     0x19
+#define WM8581_DIGITAL_ATTENUATION_DACL4     0x1A
+#define WM8581_DIGITAL_ATTENUATION_DACR4     0x1B
+#define WM8580_MASTER_DIGITAL_ATTENUATION    0x1C
+#define WM8580_ADC_CONTROL1                  0x1D
+#define WM8580_SPDTXCHAN0                    0x1E
+#define WM8580_SPDTXCHAN1                    0x1F
+#define WM8580_SPDTXCHAN2                    0x20
+#define WM8580_SPDTXCHAN3                    0x21
+#define WM8580_SPDTXCHAN4                    0x22
+#define WM8580_SPDTXCHAN5                    0x23
+#define WM8580_SPDMODE                       0x24
+#define WM8580_INTMASK                       0x25
+#define WM8580_GPO1                          0x26
+#define WM8580_GPO2                          0x27
+#define WM8580_GPO3                          0x28
+#define WM8580_GPO4                          0x29
+#define WM8580_GPO5                          0x2A
+#define WM8580_INTSTAT                       0x2B
+#define WM8580_SPDRXCHAN1                    0x2C
+#define WM8580_SPDRXCHAN2                    0x2D
+#define WM8580_SPDRXCHAN3                    0x2E
+#define WM8580_SPDRXCHAN4                    0x2F
+#define WM8580_SPDRXCHAN5                    0x30
+#define WM8580_SPDSTAT                       0x31
+#define WM8580_PWRDN1                        0x32
+#define WM8580_PWRDN2                        0x33
+#define WM8580_READBACK                      0x34
+#define WM8580_RESET                         0x35
+
+#define WM8580_MAX_REGISTER                  0x35
+
+#define WM8580_DACOSR 0x40
+
+/* PLLB4 (register 7h) */
+#define WM8580_PLLB4_MCLKOUTSRC_MASK   0x60
+#define WM8580_PLLB4_MCLKOUTSRC_PLLA   0x20
+#define WM8580_PLLB4_MCLKOUTSRC_PLLB   0x40
+#define WM8580_PLLB4_MCLKOUTSRC_OSC    0x60
+
+#define WM8580_PLLB4_CLKOUTSRC_MASK    0x180
+#define WM8580_PLLB4_CLKOUTSRC_PLLACLK 0x080
+#define WM8580_PLLB4_CLKOUTSRC_PLLBCLK 0x100
+#define WM8580_PLLB4_CLKOUTSRC_OSCCLK  0x180
+
+/* CLKSEL (register 8h) */
+#define WM8580_CLKSEL_DAC_CLKSEL_MASK 0x03
+#define WM8580_CLKSEL_DAC_CLKSEL_PLLA 0x01
+#define WM8580_CLKSEL_DAC_CLKSEL_PLLB 0x02
+
+/* AIF control 1 (registers 9h-bh) */
+#define WM8580_AIF_RATE_MASK       0x7
+#define WM8580_AIF_BCLKSEL_MASK   0x18
+
+#define WM8580_AIF_MS             0x20
+
+#define WM8580_AIF_CLKSRC_MASK    0xc0
+#define WM8580_AIF_CLKSRC_PLLA    0x40
+#define WM8580_AIF_CLKSRC_PLLB    0x40
+#define WM8580_AIF_CLKSRC_MCLK    0xc0
+
+/* AIF control 2 (registers ch-eh) */
+#define WM8580_AIF_FMT_MASK    0x03
+#define WM8580_AIF_FMT_RIGHTJ  0x00
+#define WM8580_AIF_FMT_LEFTJ   0x01
+#define WM8580_AIF_FMT_I2S     0x02
+#define WM8580_AIF_FMT_DSP     0x03
+
+#define WM8580_AIF_LENGTH_MASK   0x0c
+#define WM8580_AIF_LENGTH_16     0x00
+#define WM8580_AIF_LENGTH_20     0x04
+#define WM8580_AIF_LENGTH_24     0x08
+#define WM8580_AIF_LENGTH_32     0x0c
+
+#define WM8580_AIF_LRP         0x10
+#define WM8580_AIF_BCP         0x20
+
+/* Powerdown Register 1 (register 32h) */
+#define WM8580_PWRDN1_PWDN     0x001
+#define WM8580_PWRDN1_ALLDACPD 0x040
+
+/* Powerdown Register 2 (register 33h) */
+#define WM8580_PWRDN2_OSSCPD   0x001
+#define WM8580_PWRDN2_PLLAPD   0x002
+#define WM8580_PWRDN2_PLLBPD   0x004
+#define WM8580_PWRDN2_SPDIFPD  0x008
+#define WM8580_PWRDN2_SPDIFTXD 0x010
+#define WM8580_PWRDN2_SPDIFRXD 0x020
+
+#define WM8580_DAC_CONTROL5_MUTEALL 0x10
+
+/*
+ * wm8580 register cache
+ * We can't read the WM8580 register space when we
+ * are using 2 wire for device control, so we cache them instead.
+ */
+static const struct reg_default wm8580_reg_defaults[] = {
+	{  0, 0x0121 },
+	{  1, 0x017e },
+	{  2, 0x007d },
+	{  3, 0x0014 },
+	{  4, 0x0121 },
+	{  5, 0x017e },
+	{  6, 0x007d },
+	{  7, 0x0194 },
+	{  8, 0x0010 },
+	{  9, 0x0002 },
+	{ 10, 0x0002 },
+	{ 11, 0x00c2 },
+	{ 12, 0x0182 },
+	{ 13, 0x0082 },
+	{ 14, 0x000a },
+	{ 15, 0x0024 },
+	{ 16, 0x0009 },
+	{ 17, 0x0000 },
+	{ 18, 0x00ff },
+	{ 19, 0x0000 },
+	{ 20, 0x00ff },
+	{ 21, 0x00ff },
+	{ 22, 0x00ff },
+	{ 23, 0x00ff },
+	{ 24, 0x00ff },
+	{ 25, 0x00ff },
+	{ 26, 0x00ff },
+	{ 27, 0x00ff },
+	{ 28, 0x01f0 },
+	{ 29, 0x0040 },
+	{ 30, 0x0000 },
+	{ 31, 0x0000 },
+	{ 32, 0x0000 },
+	{ 33, 0x0000 },
+	{ 34, 0x0031 },
+	{ 35, 0x000b },
+	{ 36, 0x0039 },
+	{ 37, 0x0000 },
+	{ 38, 0x0010 },
+	{ 39, 0x0032 },
+	{ 40, 0x0054 },
+	{ 41, 0x0076 },
+	{ 42, 0x0098 },
+	{ 43, 0x0000 },
+	{ 44, 0x0000 },
+	{ 45, 0x0000 },
+	{ 46, 0x0000 },
+	{ 47, 0x0000 },
+	{ 48, 0x0000 },
+	{ 49, 0x0000 },
+	{ 50, 0x005e },
+	{ 51, 0x003e },
+	{ 52, 0x0000 },
+};
+
+static bool wm8580_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8580_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+struct pll_state {
+	unsigned int in;
+	unsigned int out;
+};
+
+#define WM8580_NUM_SUPPLIES 3
+static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = {
+	"AVDD",
+	"DVDD",
+	"PVDD",
+};
+
+struct wm8580_driver_data {
+	int num_dacs;
+};
+
+/* codec private data */
+struct wm8580_priv {
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES];
+	struct pll_state a;
+	struct pll_state b;
+	const struct wm8580_driver_data *drvdata;
+	int sysclk[2];
+};
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+
+static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	int ret;
+
+	/* Clear the register cache VU so we write without VU set */
+	regcache_cache_only(wm8580->regmap, true);
+	regmap_update_bits(wm8580->regmap, reg, 0x100, 0x000);
+	regmap_update_bits(wm8580->regmap, reg2, 0x100, 0x000);
+	regcache_cache_only(wm8580->regmap, false);
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+	if (ret < 0)
+		return ret;
+
+	/* Now write again with the volume update bit set */
+	snd_soc_component_update_bits(component, reg, 0x100, 0x100);
+	snd_soc_component_update_bits(component, reg2, 0x100, 0x100);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new wm8580_snd_controls[] = {
+SOC_DOUBLE_R_EXT_TLV("DAC1 Playback Volume",
+		     WM8580_DIGITAL_ATTENUATION_DACL1,
+		     WM8580_DIGITAL_ATTENUATION_DACR1,
+		     0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),
+SOC_DOUBLE_R_EXT_TLV("DAC2 Playback Volume",
+		     WM8580_DIGITAL_ATTENUATION_DACL2,
+		     WM8580_DIGITAL_ATTENUATION_DACR2,
+		     0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),
+SOC_DOUBLE_R_EXT_TLV("DAC3 Playback Volume",
+		     WM8580_DIGITAL_ATTENUATION_DACL3,
+		     WM8580_DIGITAL_ATTENUATION_DACR3,
+		     0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),
+
+SOC_SINGLE("DAC1 Deemphasis Switch", WM8580_DAC_CONTROL3, 0, 1, 0),
+SOC_SINGLE("DAC2 Deemphasis Switch", WM8580_DAC_CONTROL3, 1, 1, 0),
+SOC_SINGLE("DAC3 Deemphasis Switch", WM8580_DAC_CONTROL3, 2, 1, 0),
+
+SOC_DOUBLE("DAC1 Invert Switch", WM8580_DAC_CONTROL4,  0, 1, 1, 0),
+SOC_DOUBLE("DAC2 Invert Switch", WM8580_DAC_CONTROL4,  2, 3, 1, 0),
+SOC_DOUBLE("DAC3 Invert Switch", WM8580_DAC_CONTROL4,  4, 5, 1, 0),
+
+SOC_SINGLE("DAC ZC Switch", WM8580_DAC_CONTROL5, 5, 1, 0),
+SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 1),
+SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 1),
+SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 1),
+
+SOC_DOUBLE("Capture Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 1),
+SOC_SINGLE("Capture High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8581_snd_controls[] = {
+SOC_DOUBLE_R_EXT_TLV("DAC4 Playback Volume",
+		     WM8581_DIGITAL_ATTENUATION_DACL4,
+		     WM8581_DIGITAL_ATTENUATION_DACR4,
+		     0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),
+
+SOC_SINGLE("DAC4 Deemphasis Switch", WM8580_DAC_CONTROL3, 3, 1, 0),
+
+SOC_DOUBLE("DAC4 Invert Switch", WM8580_DAC_CONTROL4,  8, 7, 1, 0),
+
+SOC_SINGLE("DAC4 Switch", WM8580_DAC_CONTROL5, 3, 1, 1),
+};
+
+static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1),
+SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1),
+SND_SOC_DAPM_DAC("DAC3", "Playback", WM8580_PWRDN1, 4, 1),
+
+SND_SOC_DAPM_OUTPUT("VOUT1L"),
+SND_SOC_DAPM_OUTPUT("VOUT1R"),
+SND_SOC_DAPM_OUTPUT("VOUT2L"),
+SND_SOC_DAPM_OUTPUT("VOUT2R"),
+SND_SOC_DAPM_OUTPUT("VOUT3L"),
+SND_SOC_DAPM_OUTPUT("VOUT3R"),
+
+SND_SOC_DAPM_ADC("ADC", "Capture", WM8580_PWRDN1, 1, 1),
+
+SND_SOC_DAPM_INPUT("AINL"),
+SND_SOC_DAPM_INPUT("AINR"),
+};
+
+static const struct snd_soc_dapm_widget wm8581_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC4", "Playback", WM8580_PWRDN1, 5, 1),
+
+SND_SOC_DAPM_OUTPUT("VOUT4L"),
+SND_SOC_DAPM_OUTPUT("VOUT4R"),
+};
+
+static const struct snd_soc_dapm_route wm8580_dapm_routes[] = {
+	{ "VOUT1L", NULL, "DAC1" },
+	{ "VOUT1R", NULL, "DAC1" },
+
+	{ "VOUT2L", NULL, "DAC2" },
+	{ "VOUT2R", NULL, "DAC2" },
+
+	{ "VOUT3L", NULL, "DAC3" },
+	{ "VOUT3R", NULL, "DAC3" },
+
+	{ "ADC", NULL, "AINL" },
+	{ "ADC", NULL, "AINR" },
+};
+
+static const struct snd_soc_dapm_route wm8581_dapm_routes[] = {
+	{ "VOUT4L", NULL, "DAC4" },
+	{ "VOUT4R", NULL, "DAC4" },
+};
+
+/* PLL divisors */
+struct _pll_div {
+	u32 prescale:1;
+	u32 postscale:1;
+	u32 freqmode:2;
+	u32 n:4;
+	u32 k:24;
+};
+
+/* The size in bits of the pll divide */
+#define FIXED_PLL_SIZE (1 << 22)
+
+/* PLL rate to output rate divisions */
+static struct {
+	unsigned int div;
+	unsigned int freqmode;
+	unsigned int postscale;
+} post_table[] = {
+	{  2,  0, 0 },
+	{  4,  0, 1 },
+	{  4,  1, 0 },
+	{  8,  1, 1 },
+	{  8,  2, 0 },
+	{ 16,  2, 1 },
+	{ 12,  3, 0 },
+	{ 24,  3, 1 }
+};
+
+static int pll_factors(struct _pll_div *pll_div, unsigned int target,
+		       unsigned int source)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod;
+	int i;
+
+	pr_debug("wm8580: PLL %uHz->%uHz\n", source, target);
+
+	/* Scale the output frequency up; the PLL should run in the
+	 * region of 90-100MHz.
+	 */
+	for (i = 0; i < ARRAY_SIZE(post_table); i++) {
+		if (target * post_table[i].div >=  90000000 &&
+		    target * post_table[i].div <= 100000000) {
+			pll_div->freqmode = post_table[i].freqmode;
+			pll_div->postscale = post_table[i].postscale;
+			target *= post_table[i].div;
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(post_table)) {
+		printk(KERN_ERR "wm8580: Unable to scale output frequency "
+		       "%u\n", target);
+		return -EINVAL;
+	}
+
+	Ndiv = target / source;
+
+	if (Ndiv < 5) {
+		source /= 2;
+		pll_div->prescale = 1;
+		Ndiv = target / source;
+	} else
+		pll_div->prescale = 0;
+
+	if ((Ndiv < 5) || (Ndiv > 13)) {
+		printk(KERN_ERR
+			"WM8580 N=%u outside supported range\n", Ndiv);
+		return -EINVAL;
+	}
+
+	pll_div->n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	pll_div->k = K;
+
+	pr_debug("PLL %x.%x prescale %d freqmode %d postscale %d\n",
+		 pll_div->n, pll_div->k, pll_div->prescale, pll_div->freqmode,
+		 pll_div->postscale);
+
+	return 0;
+}
+
+static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+		int source, unsigned int freq_in, unsigned int freq_out)
+{
+	int offset;
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
+	struct pll_state *state;
+	struct _pll_div pll_div;
+	unsigned int reg;
+	unsigned int pwr_mask;
+	int ret;
+
+	/* GCC isn't able to work out the ifs below for initialising/using
+	 * pll_div so suppress warnings.
+	 */
+	memset(&pll_div, 0, sizeof(pll_div));
+
+	switch (pll_id) {
+	case WM8580_PLLA:
+		state = &wm8580->a;
+		offset = 0;
+		pwr_mask = WM8580_PWRDN2_PLLAPD;
+		break;
+	case WM8580_PLLB:
+		state = &wm8580->b;
+		offset = 4;
+		pwr_mask = WM8580_PWRDN2_PLLBPD;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	if (freq_in && freq_out) {
+		ret = pll_factors(&pll_div, freq_out, freq_in);
+		if (ret != 0)
+			return ret;
+	}
+
+	state->in = freq_in;
+	state->out = freq_out;
+
+	/* Always disable the PLL - it is not safe to leave it running
+	 * while reprogramming it.
+	 */
+	snd_soc_component_update_bits(component, WM8580_PWRDN2, pwr_mask, pwr_mask);
+
+	if (!freq_in || !freq_out)
+		return 0;
+
+	snd_soc_component_write(component, WM8580_PLLA1 + offset, pll_div.k & 0x1ff);
+	snd_soc_component_write(component, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0x1ff);
+	snd_soc_component_write(component, WM8580_PLLA3 + offset,
+		     (pll_div.k >> 18 & 0xf) | (pll_div.n << 4));
+
+	reg = snd_soc_component_read32(component, WM8580_PLLA4 + offset);
+	reg &= ~0x1b;
+	reg |= pll_div.prescale | pll_div.postscale << 1 |
+		pll_div.freqmode << 3;
+
+	snd_soc_component_write(component, WM8580_PLLA4 + offset, reg);
+
+	/* All done, turn it on */
+	snd_soc_component_update_bits(component, WM8580_PWRDN2, pwr_mask, 0);
+
+	return 0;
+}
+
+static const int wm8580_sysclk_ratios[] = {
+	128, 192, 256, 384, 512, 768, 1152,
+};
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ */
+static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
+	u16 paifa = 0;
+	u16 paifb = 0;
+	int i, ratio, osr;
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		paifa |= 0x8;
+		break;
+	case 20:
+		paifa |= 0x0;
+		paifb |= WM8580_AIF_LENGTH_20;
+		break;
+	case 24:
+		paifa |= 0x0;
+		paifb |= WM8580_AIF_LENGTH_24;
+		break;
+	case 32:
+		paifa |= 0x0;
+		paifb |= WM8580_AIF_LENGTH_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Look up the SYSCLK ratio; accept only exact matches */
+	ratio = wm8580->sysclk[dai->driver->id] / params_rate(params);
+	for (i = 0; i < ARRAY_SIZE(wm8580_sysclk_ratios); i++)
+		if (ratio == wm8580_sysclk_ratios[i])
+			break;
+	if (i == ARRAY_SIZE(wm8580_sysclk_ratios)) {
+		dev_err(component->dev, "Invalid clock ratio %d/%d\n",
+			wm8580->sysclk[dai->driver->id], params_rate(params));
+		return -EINVAL;
+	}
+	paifa |= i;
+	dev_dbg(component->dev, "Running at %dfs with %dHz clock\n",
+		wm8580_sysclk_ratios[i], wm8580->sysclk[dai->driver->id]);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		switch (ratio) {
+		case 128:
+		case 192:
+			osr = WM8580_DACOSR;
+			dev_dbg(component->dev, "Selecting 64x OSR\n");
+			break;
+		default:
+			osr = 0;
+			dev_dbg(component->dev, "Selecting 128x OSR\n");
+			break;
+		}
+
+		snd_soc_component_update_bits(component, WM8580_PAIF3, WM8580_DACOSR, osr);
+	}
+
+	snd_soc_component_update_bits(component, WM8580_PAIF1 + dai->driver->id,
+			    WM8580_AIF_RATE_MASK | WM8580_AIF_BCLKSEL_MASK,
+			    paifa);
+	snd_soc_component_update_bits(component, WM8580_PAIF3 + dai->driver->id,
+			    WM8580_AIF_LENGTH_MASK, paifb);
+	return 0;
+}
+
+static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
+				      unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	unsigned int aifa;
+	unsigned int aifb;
+	int can_invert_lrclk;
+
+	aifa = snd_soc_component_read32(component, WM8580_PAIF1 + codec_dai->driver->id);
+	aifb = snd_soc_component_read32(component, WM8580_PAIF3 + codec_dai->driver->id);
+
+	aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		aifa &= ~WM8580_AIF_MS;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aifa |= WM8580_AIF_MS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		can_invert_lrclk = 1;
+		aifb |= WM8580_AIF_FMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		can_invert_lrclk = 1;
+		aifb |= WM8580_AIF_FMT_RIGHTJ;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		can_invert_lrclk = 1;
+		aifb |= WM8580_AIF_FMT_LEFTJ;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		can_invert_lrclk = 0;
+		aifb |= WM8580_AIF_FMT_DSP;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		can_invert_lrclk = 0;
+		aifb |= WM8580_AIF_FMT_DSP;
+		aifb |= WM8580_AIF_LRP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+
+	case SND_SOC_DAIFMT_IB_IF:
+		if (!can_invert_lrclk)
+			return -EINVAL;
+		aifb |= WM8580_AIF_BCP;
+		aifb |= WM8580_AIF_LRP;
+		break;
+
+	case SND_SOC_DAIFMT_IB_NF:
+		aifb |= WM8580_AIF_BCP;
+		break;
+
+	case SND_SOC_DAIFMT_NB_IF:
+		if (!can_invert_lrclk)
+			return -EINVAL;
+		aifb |= WM8580_AIF_LRP;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8580_PAIF1 + codec_dai->driver->id, aifa);
+	snd_soc_component_write(component, WM8580_PAIF3 + codec_dai->driver->id, aifb);
+
+	return 0;
+}
+
+static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+				 int div_id, int div)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	unsigned int reg;
+
+	switch (div_id) {
+	case WM8580_MCLK:
+		reg = snd_soc_component_read32(component, WM8580_PLLB4);
+		reg &= ~WM8580_PLLB4_MCLKOUTSRC_MASK;
+
+		switch (div) {
+		case WM8580_CLKSRC_MCLK:
+			/* Input */
+			break;
+
+		case WM8580_CLKSRC_PLLA:
+			reg |= WM8580_PLLB4_MCLKOUTSRC_PLLA;
+			break;
+		case WM8580_CLKSRC_PLLB:
+			reg |= WM8580_PLLB4_MCLKOUTSRC_PLLB;
+			break;
+
+		case WM8580_CLKSRC_OSC:
+			reg |= WM8580_PLLB4_MCLKOUTSRC_OSC;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+		snd_soc_component_write(component, WM8580_PLLB4, reg);
+		break;
+
+	case WM8580_CLKOUTSRC:
+		reg = snd_soc_component_read32(component, WM8580_PLLB4);
+		reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK;
+
+		switch (div) {
+		case WM8580_CLKSRC_NONE:
+			break;
+
+		case WM8580_CLKSRC_PLLA:
+			reg |= WM8580_PLLB4_CLKOUTSRC_PLLACLK;
+			break;
+
+		case WM8580_CLKSRC_PLLB:
+			reg |= WM8580_PLLB4_CLKOUTSRC_PLLBCLK;
+			break;
+
+		case WM8580_CLKSRC_OSC:
+			reg |= WM8580_PLLB4_CLKOUTSRC_OSCCLK;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+		snd_soc_component_write(component, WM8580_PLLB4, reg);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+			     unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
+	int ret, sel, sel_mask, sel_shift;
+
+	switch (dai->driver->id) {
+	case WM8580_DAI_PAIFRX:
+		sel_mask = 0x3;
+		sel_shift = 0;
+		break;
+
+	case WM8580_DAI_PAIFTX:
+		sel_mask = 0xc;
+		sel_shift = 2;
+		break;
+
+	default:
+		WARN(1, "Unknown DAI driver ID\n");
+		return -EINVAL;
+	}
+
+	switch (clk_id) {
+	case WM8580_CLKSRC_ADCMCLK:
+		if (dai->driver->id != WM8580_DAI_PAIFTX)
+			return -EINVAL;
+		sel = 0 << sel_shift;
+		break;
+	case WM8580_CLKSRC_PLLA:
+		sel = 1 << sel_shift;
+		break;
+	case WM8580_CLKSRC_PLLB:
+		sel = 2 << sel_shift;
+		break;
+	case WM8580_CLKSRC_MCLK:
+		sel = 3 << sel_shift;
+		break;
+	default:
+		dev_err(component->dev, "Unknown clock %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	/* We really should validate PLL settings but not yet */
+	wm8580->sysclk[dai->driver->id] = freq;
+
+	ret = snd_soc_component_update_bits(component, WM8580_CLKSEL, sel_mask, sel);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	unsigned int reg;
+
+	reg = snd_soc_component_read32(component, WM8580_DAC_CONTROL5);
+
+	if (mute)
+		reg |= WM8580_DAC_CONTROL5_MUTEALL;
+	else
+		reg &= ~WM8580_DAC_CONTROL5_MUTEALL;
+
+	snd_soc_component_write(component, WM8580_DAC_CONTROL5, reg);
+
+	return 0;
+}
+
+static int wm8580_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/* Power up and get individual control of the DACs */
+			snd_soc_component_update_bits(component, WM8580_PWRDN1,
+					    WM8580_PWRDN1_PWDN |
+					    WM8580_PWRDN1_ALLDACPD, 0);
+
+			/* Make VMID high impedance */
+			snd_soc_component_update_bits(component, WM8580_ADC_CONTROL1,
+					    0x100, 0);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, WM8580_PWRDN1,
+				    WM8580_PWRDN1_PWDN, WM8580_PWRDN1_PWDN);
+		break;
+	}
+	return 0;
+}
+
+static int wm8580_playback_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
+
+	return snd_pcm_hw_constraint_minmax(substream->runtime,
+		SNDRV_PCM_HW_PARAM_CHANNELS, 1, wm8580->drvdata->num_dacs * 2);
+}
+
+#define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8580_dai_ops_playback = {
+	.startup	= wm8580_playback_startup,
+	.set_sysclk	= wm8580_set_sysclk,
+	.hw_params	= wm8580_paif_hw_params,
+	.set_fmt	= wm8580_set_paif_dai_fmt,
+	.set_clkdiv	= wm8580_set_dai_clkdiv,
+	.set_pll	= wm8580_set_dai_pll,
+	.digital_mute	= wm8580_digital_mute,
+};
+
+static const struct snd_soc_dai_ops wm8580_dai_ops_capture = {
+	.set_sysclk	= wm8580_set_sysclk,
+	.hw_params	= wm8580_paif_hw_params,
+	.set_fmt	= wm8580_set_paif_dai_fmt,
+	.set_clkdiv	= wm8580_set_dai_clkdiv,
+	.set_pll	= wm8580_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver wm8580_dai[] = {
+	{
+		.name = "wm8580-hifi-playback",
+		.id	= WM8580_DAI_PAIFRX,
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = WM8580_FORMATS,
+		},
+		.ops = &wm8580_dai_ops_playback,
+	},
+	{
+		.name = "wm8580-hifi-capture",
+		.id	=	WM8580_DAI_PAIFTX,
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = WM8580_FORMATS,
+		},
+		.ops = &wm8580_dai_ops_capture,
+	},
+};
+
+static int wm8580_probe(struct snd_soc_component *component)
+{
+	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int ret = 0;
+
+	switch (wm8580->drvdata->num_dacs) {
+	case 4:
+		snd_soc_add_component_controls(component, wm8581_snd_controls,
+					ARRAY_SIZE(wm8581_snd_controls));
+		snd_soc_dapm_new_controls(dapm, wm8581_dapm_widgets,
+					ARRAY_SIZE(wm8581_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm, wm8581_dapm_routes,
+					ARRAY_SIZE(wm8581_dapm_routes));
+		break;
+	default:
+		break;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),
+				    wm8580->supplies);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
+		goto err_regulator_get;
+	}
+
+	/* Get the codec into a known state */
+	ret = snd_soc_component_write(component, WM8580_RESET, 0);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to reset component: %d\n", ret);
+		goto err_regulator_enable;
+	}
+
+	return 0;
+
+err_regulator_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
+err_regulator_get:
+	return ret;
+}
+
+/* power down chip */
+static void wm8580_remove(struct snd_soc_component *component)
+{
+	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
+
+	regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8580 = {
+	.probe			= wm8580_probe,
+	.remove			= wm8580_remove,
+	.set_bias_level		= wm8580_set_bias_level,
+	.controls		= wm8580_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8580_snd_controls),
+	.dapm_widgets		= wm8580_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8580_dapm_widgets),
+	.dapm_routes		= wm8580_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8580_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8580_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+	.max_register = WM8580_MAX_REGISTER,
+
+	.reg_defaults = wm8580_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8580_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = wm8580_volatile,
+};
+
+static const struct wm8580_driver_data wm8580_data = {
+	.num_dacs = 3,
+};
+
+static const struct wm8580_driver_data wm8581_data = {
+	.num_dacs = 4,
+};
+
+static const struct of_device_id wm8580_of_match[] = {
+	{ .compatible = "wlf,wm8580", .data = &wm8580_data },
+	{ .compatible = "wlf,wm8581", .data = &wm8581_data },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, wm8580_of_match);
+
+static int wm8580_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	const struct of_device_id *of_id;
+	struct wm8580_priv *wm8580;
+	int ret, i;
+
+	wm8580 = devm_kzalloc(&i2c->dev, sizeof(struct wm8580_priv),
+			      GFP_KERNEL);
+	if (wm8580 == NULL)
+		return -ENOMEM;
+
+	wm8580->regmap = devm_regmap_init_i2c(i2c, &wm8580_regmap);
+	if (IS_ERR(wm8580->regmap))
+		return PTR_ERR(wm8580->regmap);
+
+	for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++)
+		wm8580->supplies[i].supply = wm8580_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8580->supplies),
+				      wm8580->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, wm8580);
+
+	of_id = of_match_device(wm8580_of_match, &i2c->dev);
+	if (of_id)
+		wm8580->drvdata = of_id->data;
+
+	if (!wm8580->drvdata) {
+		dev_err(&i2c->dev, "failed to find driver data\n");
+		return -EINVAL;
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai));
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8580_i2c_id[] = {
+	{ "wm8580", (kernel_ulong_t)&wm8580_data },
+	{ "wm8581", (kernel_ulong_t)&wm8581_data },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id);
+
+static struct i2c_driver wm8580_i2c_driver = {
+	.driver = {
+		.name = "wm8580",
+		.of_match_table = wm8580_of_match,
+	},
+	.probe =    wm8580_i2c_probe,
+	.id_table = wm8580_i2c_id,
+};
+
+module_i2c_driver(wm8580_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8580 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_AUTHOR("Matt Flax <flatmax@flatmax.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h
new file mode 100644
index 0000000..1d34656
--- /dev/null
+++ b/sound/soc/codecs/wm8580.h
@@ -0,0 +1,35 @@
+/*
+ * wm8580.h  --  audio driver for WM8580
+ *
+ * Copyright 2008 Samsung Electronics.
+ * Author: Ryu Euiyoul
+ *         ryu.real@gmail.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef _WM8580_H
+#define _WM8580_H
+
+#define WM8580_PLLA  1
+#define WM8580_PLLB  2
+
+#define WM8580_MCLK       1
+#define WM8580_CLKOUTSRC  2
+
+#define WM8580_CLKSRC_MCLK    1
+#define WM8580_CLKSRC_PLLA    2
+#define WM8580_CLKSRC_PLLB    3
+#define WM8580_CLKSRC_OSC     4
+#define WM8580_CLKSRC_NONE    5
+#define WM8580_CLKSRC_ADCMCLK 6
+
+#define WM8580_DAI_PAIFRX 0
+#define WM8580_DAI_PAIFTX 1
+
+#endif
+
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
new file mode 100644
index 0000000..1da08d2
--- /dev/null
+++ b/sound/soc/codecs/wm8711.c
@@ -0,0 +1,510 @@
+/*
+ * wm8711.c  --  WM8711 ALSA SoC Audio driver
+ *
+ * Copyright 2006 Wolfson Microelectronics
+ *
+ * Author: Mike Arthur <Mike.Arthur@wolfsonmicro.com>
+ *
+ * Based on wm8731.c by Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+
+#include "wm8711.h"
+
+/* codec private data */
+struct wm8711_priv {
+	struct regmap *regmap;
+	unsigned int sysclk;
+};
+
+/*
+ * wm8711 register cache
+ * We can't read the WM8711 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ * There is no point in caching the reset register
+ */
+static const struct reg_default wm8711_reg_defaults[] = {
+	{ 0, 0x0079 }, { 1, 0x0079 }, { 2, 0x000a }, { 3, 0x0008 },
+	{ 4, 0x009f }, { 5, 0x000a }, { 6, 0x0000 }, { 7, 0x0000 },
+};
+
+static bool wm8711_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8711_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+#define wm8711_reset(c)	snd_soc_component_write(c, WM8711_RESET, 0)
+
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+
+static const struct snd_kcontrol_new wm8711_snd_controls[] = {
+
+SOC_DOUBLE_R_TLV("Master Playback Volume", WM8711_LOUT1V, WM8711_ROUT1V,
+		 0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Master Playback ZC Switch", WM8711_LOUT1V, WM8711_ROUT1V,
+	7, 1, 0),
+
+};
+
+/* Output Mixer */
+static const struct snd_kcontrol_new wm8711_output_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8711_APANA, 3, 1, 0),
+SOC_DAPM_SINGLE("HiFi Playback Switch", WM8711_APANA, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8711_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", WM8711_PWR, 4, 1,
+	&wm8711_output_mixer_controls[0],
+	ARRAY_SIZE(wm8711_output_mixer_controls)),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8711_PWR, 3, 1),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
+};
+
+static const struct snd_soc_dapm_route wm8711_intercon[] = {
+	/* output mixer */
+	{"Output Mixer", "Line Bypass Switch", "Line Input"},
+	{"Output Mixer", "HiFi Playback Switch", "DAC"},
+
+	/* outputs */
+	{"RHPOUT", NULL, "Output Mixer"},
+	{"ROUT", NULL, "Output Mixer"},
+	{"LHPOUT", NULL, "Output Mixer"},
+	{"LOUT", NULL, "Output Mixer"},
+};
+
+struct _coeff_div {
+	u32 mclk;
+	u32 rate;
+	u16 fs;
+	u8 sr:4;
+	u8 bosr:1;
+	u8 usb:1;
+};
+
+/* codec mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	/* 48k */
+	{12288000, 48000, 256, 0x0, 0x0, 0x0},
+	{18432000, 48000, 384, 0x0, 0x1, 0x0},
+	{12000000, 48000, 250, 0x0, 0x0, 0x1},
+
+	/* 32k */
+	{12288000, 32000, 384, 0x6, 0x0, 0x0},
+	{18432000, 32000, 576, 0x6, 0x1, 0x0},
+	{12000000, 32000, 375, 0x6, 0x0, 0x1},
+
+	/* 8k */
+	{12288000, 8000, 1536, 0x3, 0x0, 0x0},
+	{18432000, 8000, 2304, 0x3, 0x1, 0x0},
+	{11289600, 8000, 1408, 0xb, 0x0, 0x0},
+	{16934400, 8000, 2112, 0xb, 0x1, 0x0},
+	{12000000, 8000, 1500, 0x3, 0x0, 0x1},
+
+	/* 96k */
+	{12288000, 96000, 128, 0x7, 0x0, 0x0},
+	{18432000, 96000, 192, 0x7, 0x1, 0x0},
+	{12000000, 96000, 125, 0x7, 0x0, 0x1},
+
+	/* 44.1k */
+	{11289600, 44100, 256, 0x8, 0x0, 0x0},
+	{16934400, 44100, 384, 0x8, 0x1, 0x0},
+	{12000000, 44100, 272, 0x8, 0x1, 0x1},
+
+	/* 88.2k */
+	{11289600, 88200, 128, 0xf, 0x0, 0x0},
+	{16934400, 88200, 192, 0xf, 0x1, 0x0},
+	{12000000, 88200, 136, 0xf, 0x1, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+	return 0;
+}
+
+static int wm8711_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8711_priv *wm8711 =  snd_soc_component_get_drvdata(component);
+	u16 iface = snd_soc_component_read32(component, WM8711_IFACE) & 0xfff3;
+	int i = get_coeff(wm8711->sysclk, params_rate(params));
+	u16 srate = (coeff_div[i].sr << 2) |
+		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
+
+	snd_soc_component_write(component, WM8711_SRATE, srate);
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		iface |= 0x0004;
+		break;
+	case 24:
+		iface |= 0x0008;
+		break;
+	}
+
+	snd_soc_component_write(component, WM8711_IFACE, iface);
+	return 0;
+}
+
+static int wm8711_pcm_prepare(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+
+	/* set active */
+	snd_soc_component_write(component, WM8711_ACTIVE, 0x0001);
+
+	return 0;
+}
+
+static void wm8711_shutdown(struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+
+	/* deactivate */
+	if (!snd_soc_component_is_active(component)) {
+		udelay(50);
+		snd_soc_component_write(component, WM8711_ACTIVE, 0x0);
+	}
+}
+
+static int wm8711_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8711_APDIGI) & 0xfff7;
+
+	if (mute)
+		snd_soc_component_write(component, WM8711_APDIGI, mute_reg | 0x8);
+	else
+		snd_soc_component_write(component, WM8711_APDIGI, mute_reg);
+
+	return 0;
+}
+
+static int wm8711_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8711_priv *wm8711 =  snd_soc_component_get_drvdata(component);
+
+	switch (freq) {
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 16934400:
+	case 18432000:
+		wm8711->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = snd_soc_component_read32(component, WM8711_IFACE) & 0x000c;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface |= 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface */
+	snd_soc_component_write(component, WM8711_IFACE, iface);
+	return 0;
+}
+
+static int wm8711_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	struct wm8711_priv *wm8711 = snd_soc_component_get_drvdata(component);
+	u16 reg = snd_soc_component_read32(component, WM8711_PWR) & 0xff7f;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_soc_component_write(component, WM8711_PWR, reg);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			regcache_sync(wm8711->regmap);
+
+		snd_soc_component_write(component, WM8711_PWR, reg | 0x0040);
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_write(component, WM8711_ACTIVE, 0x0);
+		snd_soc_component_write(component, WM8711_PWR, 0xffff);
+		break;
+	}
+	return 0;
+}
+
+#define WM8711_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops wm8711_ops = {
+	.prepare = wm8711_pcm_prepare,
+	.hw_params = wm8711_hw_params,
+	.shutdown = wm8711_shutdown,
+	.digital_mute = wm8711_mute,
+	.set_sysclk = wm8711_set_dai_sysclk,
+	.set_fmt = wm8711_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver wm8711_dai = {
+	.name = "wm8711-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8711_RATES,
+		.formats = WM8711_FORMATS,
+	},
+	.ops = &wm8711_ops,
+};
+
+static int wm8711_probe(struct snd_soc_component *component)
+{
+	int ret;
+
+	ret = wm8711_reset(component);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	/* Latch the update bits */
+	snd_soc_component_update_bits(component, WM8711_LOUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8711_ROUT1V, 0x0100, 0x0100);
+
+	return ret;
+
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8711 = {
+	.probe			= wm8711_probe,
+	.set_bias_level		= wm8711_set_bias_level,
+	.controls		= wm8711_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8711_snd_controls),
+	.dapm_widgets		= wm8711_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8711_dapm_widgets),
+	.dapm_routes		= wm8711_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(wm8711_intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct of_device_id wm8711_of_match[] = {
+	{ .compatible = "wlf,wm8711", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wm8711_of_match);
+
+static const struct regmap_config wm8711_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+	.max_register = WM8711_RESET,
+
+	.reg_defaults = wm8711_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8711_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = wm8711_volatile,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8711_spi_probe(struct spi_device *spi)
+{
+	struct wm8711_priv *wm8711;
+	int ret;
+
+	wm8711 = devm_kzalloc(&spi->dev, sizeof(struct wm8711_priv),
+			      GFP_KERNEL);
+	if (wm8711 == NULL)
+		return -ENOMEM;
+
+	wm8711->regmap = devm_regmap_init_spi(spi, &wm8711_regmap);
+	if (IS_ERR(wm8711->regmap))
+		return PTR_ERR(wm8711->regmap);
+
+	spi_set_drvdata(spi, wm8711);
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8711, &wm8711_dai, 1);
+
+	return ret;
+}
+
+static struct spi_driver wm8711_spi_driver = {
+	.driver = {
+		.name	= "wm8711",
+		.of_match_table = wm8711_of_match,
+	},
+	.probe		= wm8711_spi_probe,
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8711_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct wm8711_priv *wm8711;
+	int ret;
+
+	wm8711 = devm_kzalloc(&client->dev, sizeof(struct wm8711_priv),
+			      GFP_KERNEL);
+	if (wm8711 == NULL)
+		return -ENOMEM;
+
+	wm8711->regmap = devm_regmap_init_i2c(client, &wm8711_regmap);
+	if (IS_ERR(wm8711->regmap))
+		return PTR_ERR(wm8711->regmap);
+
+	i2c_set_clientdata(client, wm8711);
+
+	ret = devm_snd_soc_register_component(&client->dev,
+			&soc_component_dev_wm8711, &wm8711_dai, 1);
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8711_i2c_id[] = {
+	{ "wm8711", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id);
+
+static struct i2c_driver wm8711_i2c_driver = {
+	.driver = {
+		.name = "wm8711",
+		.of_match_table = wm8711_of_match,
+	},
+	.probe =    wm8711_i2c_probe,
+	.id_table = wm8711_i2c_id,
+};
+#endif
+
+static int __init wm8711_modinit(void)
+{
+	int ret;
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&wm8711_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8711 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8711_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8711 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return 0;
+}
+module_init(wm8711_modinit);
+
+static void __exit wm8711_exit(void)
+{
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&wm8711_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8711_spi_driver);
+#endif
+}
+module_exit(wm8711_exit);
+
+MODULE_DESCRIPTION("ASoC WM8711 driver");
+MODULE_AUTHOR("Mike Arthur");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8711.h b/sound/soc/codecs/wm8711.h
new file mode 100644
index 0000000..a61db98
--- /dev/null
+++ b/sound/soc/codecs/wm8711.h
@@ -0,0 +1,39 @@
+/*
+ * wm8711.h  --  WM8711 Soc Audio driver
+ *
+ * Copyright 2006 Wolfson Microelectronics
+ *
+ * Author: Mike Arthur <linux@wolfsonmicro.com>
+ *
+ * Based on wm8731.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8711_H
+#define _WM8711_H
+
+/* WM8711 register space */
+
+#define WM8711_LOUT1V   0x02
+#define WM8711_ROUT1V   0x03
+#define WM8711_APANA    0x04
+#define WM8711_APDIGI   0x05
+#define WM8711_PWR      0x06
+#define WM8711_IFACE    0x07
+#define WM8711_SRATE    0x08
+#define WM8711_ACTIVE   0x09
+#define WM8711_RESET	0x0f
+
+#define WM8711_CACHEREGNUM 	8
+
+#define WM8711_SYSCLK	0
+#define WM8711_DAI		0
+
+struct wm8711_setup_data {
+	unsigned short i2c_address;
+};
+
+#endif
diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c
new file mode 100644
index 0000000..087ec6d
--- /dev/null
+++ b/sound/soc/codecs/wm8727.c
@@ -0,0 +1,83 @@
+/*
+ * wm8727.c
+ *
+ *  Created on: 15-Oct-2009
+ *      Author: neil.jones@imgtec.com
+ *
+ * Copyright (C) 2009 Imagination Technologies Ltd.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+static const struct snd_soc_dapm_widget wm8727_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("VOUTL"),
+SND_SOC_DAPM_OUTPUT("VOUTR"),
+};
+
+static const struct snd_soc_dapm_route wm8727_dapm_routes[] = {
+	{ "VOUTL", NULL, "Playback" },
+	{ "VOUTR", NULL, "Playback" },
+};
+
+/*
+ * Note this is a simple chip with no configuration interface, sample rate is
+ * determined automatically by examining the Master clock and Bit clock ratios
+ */
+#define WM8727_RATES  (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+			SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |\
+			SNDRV_PCM_RATE_192000)
+
+static struct snd_soc_dai_driver wm8727_dai = {
+	.name = "wm8727-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM8727_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+		},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_wm8727 = {
+	.dapm_widgets		= wm8727_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8727_dapm_widgets),
+	.dapm_routes		= wm8727_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8727_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm8727_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm8727, &wm8727_dai, 1);
+}
+
+static struct platform_driver wm8727_codec_driver = {
+	.driver = {
+			.name = "wm8727",
+	},
+
+	.probe = wm8727_probe,
+};
+
+module_platform_driver(wm8727_codec_driver);
+
+MODULE_DESCRIPTION("ASoC wm8727 driver");
+MODULE_AUTHOR("Neil Jones");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
new file mode 100644
index 0000000..839aee3
--- /dev/null
+++ b/sound/soc/codecs/wm8728.c
@@ -0,0 +1,351 @@
+/*
+ * wm8728.c  --  WM8728 ALSA SoC Audio driver
+ *
+ * Copyright 2008 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8728.h"
+
+/*
+ * We can't read the WM8728 register space so we cache them instead.
+ * Note that the defaults here aren't the physical defaults, we latch
+ * the volume update bits, mute the output and enable infinite zero
+ * detect.
+ */
+static const struct reg_default wm8728_reg_defaults[] = {
+	{ 0, 0x1ff },
+	{ 1, 0x1ff },
+	{ 2, 0x001 },
+	{ 3, 0x100 },
+};
+
+/* codec private data */
+struct wm8728_priv {
+	struct regmap *regmap;
+};
+
+static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1);
+
+static const struct snd_kcontrol_new wm8728_snd_controls[] = {
+
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8728_DACLVOL, WM8728_DACRVOL,
+		 0, 255, 0, wm8728_tlv),
+
+SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0),
+};
+
+/*
+ * DAPM controls.
+ */
+static const struct snd_soc_dapm_widget wm8728_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_OUTPUT("VOUTL"),
+SND_SOC_DAPM_OUTPUT("VOUTR"),
+};
+
+static const struct snd_soc_dapm_route wm8728_intercon[] = {
+	{"VOUTL", NULL, "DAC"},
+	{"VOUTR", NULL, "DAC"},
+};
+
+static int wm8728_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8728_DACCTL);
+
+	if (mute)
+		snd_soc_component_write(component, WM8728_DACCTL, mute_reg | 1);
+	else
+		snd_soc_component_write(component, WM8728_DACCTL, mute_reg & ~1);
+
+	return 0;
+}
+
+static int wm8728_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 dac = snd_soc_component_read32(component, WM8728_DACCTL);
+
+	dac &= ~0x18;
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		dac |= 0x10;
+		break;
+	case 24:
+		dac |= 0x08;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8728_DACCTL, dac);
+
+	return 0;
+}
+
+static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = snd_soc_component_read32(component, WM8728_IFCTL);
+
+	/* Currently only I2S is supported by the driver, though the
+	 * hardware is more flexible.
+	 */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* The hardware only support full slave mode */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		iface &= ~0x22;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |=  0x20;
+		iface &= ~0x02;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x02;
+		iface &= ~0x20;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x22;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8728_IFCTL, iface);
+	return 0;
+}
+
+static int wm8728_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8728_priv *wm8728 = snd_soc_component_get_drvdata(component);
+	u16 reg;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/* Power everything up... */
+			reg = snd_soc_component_read32(component, WM8728_DACCTL);
+			snd_soc_component_write(component, WM8728_DACCTL, reg & ~0x4);
+
+			/* ..then sync in the register cache. */
+			regcache_sync(wm8728->regmap);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		reg = snd_soc_component_read32(component, WM8728_DACCTL);
+		snd_soc_component_write(component, WM8728_DACCTL, reg | 0x4);
+		break;
+	}
+	return 0;
+}
+
+#define WM8728_RATES (SNDRV_PCM_RATE_8000_192000)
+
+#define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops wm8728_dai_ops = {
+	.hw_params	= wm8728_hw_params,
+	.digital_mute	= wm8728_mute,
+	.set_fmt	= wm8728_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver wm8728_dai = {
+	.name = "wm8728-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM8728_RATES,
+		.formats = WM8728_FORMATS,
+	},
+	.ops = &wm8728_dai_ops,
+};
+
+static const struct snd_soc_component_driver soc_component_dev_wm8728 = {
+	.set_bias_level		= wm8728_set_bias_level,
+	.controls		= wm8728_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8728_snd_controls),
+	.dapm_widgets		= wm8728_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8728_dapm_widgets),
+	.dapm_routes		= wm8728_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(wm8728_intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct of_device_id wm8728_of_match[] = {
+	{ .compatible = "wlf,wm8728", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wm8728_of_match);
+
+static const struct regmap_config wm8728_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+	.max_register = WM8728_IFCTL,
+
+	.reg_defaults = wm8728_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8728_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8728_spi_probe(struct spi_device *spi)
+{
+	struct wm8728_priv *wm8728;
+	int ret;
+
+	wm8728 = devm_kzalloc(&spi->dev, sizeof(struct wm8728_priv),
+			      GFP_KERNEL);
+	if (wm8728 == NULL)
+		return -ENOMEM;
+
+	wm8728->regmap = devm_regmap_init_spi(spi, &wm8728_regmap);
+	if (IS_ERR(wm8728->regmap))
+		return PTR_ERR(wm8728->regmap);
+
+	spi_set_drvdata(spi, wm8728);
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8728, &wm8728_dai, 1);
+
+	return ret;
+}
+
+static struct spi_driver wm8728_spi_driver = {
+	.driver = {
+		.name	= "wm8728",
+		.of_match_table = wm8728_of_match,
+	},
+	.probe		= wm8728_spi_probe,
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8728_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8728_priv *wm8728;
+	int ret;
+
+	wm8728 = devm_kzalloc(&i2c->dev, sizeof(struct wm8728_priv),
+			      GFP_KERNEL);
+	if (wm8728 == NULL)
+		return -ENOMEM;
+
+	wm8728->regmap = devm_regmap_init_i2c(i2c, &wm8728_regmap);
+	if (IS_ERR(wm8728->regmap))
+		return PTR_ERR(wm8728->regmap);
+
+	i2c_set_clientdata(i2c, wm8728);
+
+	ret =  devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8728, &wm8728_dai, 1);
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8728_i2c_id[] = {
+	{ "wm8728", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id);
+
+static struct i2c_driver wm8728_i2c_driver = {
+	.driver = {
+		.name = "wm8728",
+		.of_match_table = wm8728_of_match,
+	},
+	.probe =    wm8728_i2c_probe,
+	.id_table = wm8728_i2c_id,
+};
+#endif
+
+static int __init wm8728_modinit(void)
+{
+	int ret = 0;
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&wm8728_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register wm8728 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8728_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register wm8728 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return ret;
+}
+module_init(wm8728_modinit);
+
+static void __exit wm8728_exit(void)
+{
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&wm8728_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8728_spi_driver);
+#endif
+}
+module_exit(wm8728_exit);
+
+MODULE_DESCRIPTION("ASoC WM8728 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8728.h b/sound/soc/codecs/wm8728.h
new file mode 100644
index 0000000..8aea362
--- /dev/null
+++ b/sound/soc/codecs/wm8728.h
@@ -0,0 +1,21 @@
+/*
+ * wm8728.h  --  WM8728 ASoC codec driver
+ *
+ * Copyright 2008 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8728_H
+#define _WM8728_H
+
+#define WM8728_DACLVOL   0x00
+#define WM8728_DACRVOL   0x01
+#define WM8728_DACCTL    0x02
+#define WM8728_IFCTL     0x03
+
+#endif
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
new file mode 100644
index 0000000..7c8fad8
--- /dev/null
+++ b/sound/soc/codecs/wm8731.c
@@ -0,0 +1,844 @@
+/*
+ * wm8731.c  --  WM8731 ALSA SoC Audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ * Copyright 2006-12 Wolfson Microelectronics, plc
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on wm8753.c by Liam Girdwood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/of_device.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8731.h"
+
+#define WM8731_NUM_SUPPLIES 4
+static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
+	"AVDD",
+	"HPVDD",
+	"DCVDD",
+	"DBVDD",
+};
+
+/* codec private data */
+struct wm8731_priv {
+	struct regmap *regmap;
+	struct clk *mclk;
+	struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
+	const struct snd_pcm_hw_constraint_list *constraints;
+	unsigned int sysclk;
+	int sysclk_type;
+	int playback_fs;
+	bool deemph;
+
+	struct mutex lock;
+};
+
+
+/*
+ * wm8731 register cache
+ */
+static const struct reg_default wm8731_reg_defaults[] = {
+	{ 0, 0x0097 },
+	{ 1, 0x0097 },
+	{ 2, 0x0079 },
+	{ 3, 0x0079 },
+	{ 4, 0x000a },
+	{ 5, 0x0008 },
+	{ 6, 0x009f },
+	{ 7, 0x000a },
+	{ 8, 0x0000 },
+	{ 9, 0x0000 },
+};
+
+static bool wm8731_volatile(struct device *dev, unsigned int reg)
+{
+	return reg == WM8731_RESET;
+}
+
+#define wm8731_reset(m)	regmap_write(m, WM8731_RESET, 0)
+
+static const char *wm8731_input_select[] = {"Line In", "Mic"};
+
+static SOC_ENUM_SINGLE_DECL(wm8731_insel_enum,
+			    WM8731_APANA, 2, wm8731_input_select);
+
+static int wm8731_deemph[] = { 0, 32000, 44100, 48000 };
+
+static int wm8731_set_deemph(struct snd_soc_component *component)
+{
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
+	int val, i, best;
+
+	/* If we're using deemphasis select the nearest available sample
+	 * rate.
+	 */
+	if (wm8731->deemph) {
+		best = 1;
+		for (i = 2; i < ARRAY_SIZE(wm8731_deemph); i++) {
+			if (abs(wm8731_deemph[i] - wm8731->playback_fs) <
+			    abs(wm8731_deemph[best] - wm8731->playback_fs))
+				best = i;
+		}
+
+		val = best << 1;
+	} else {
+		best = 0;
+		val = 0;
+	}
+
+	dev_dbg(component->dev, "Set deemphasis %d (%dHz)\n",
+		best, wm8731_deemph[best]);
+
+	return snd_soc_component_update_bits(component, WM8731_APDIGI, 0x6, val);
+}
+
+static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wm8731->deemph;
+
+	return 0;
+}
+
+static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
+	unsigned int deemph = ucontrol->value.integer.value[0];
+	int ret = 0;
+
+	if (deemph > 1)
+		return -EINVAL;
+
+	mutex_lock(&wm8731->lock);
+	if (wm8731->deemph != deemph) {
+		wm8731->deemph = deemph;
+
+		wm8731_set_deemph(component);
+
+		ret = 1;
+	}
+	mutex_unlock(&wm8731->lock);
+
+	return ret;
+}
+
+static const DECLARE_TLV_DB_SCALE(in_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 2000, 0);
+
+static const struct snd_kcontrol_new wm8731_snd_controls[] = {
+
+SOC_DOUBLE_R_TLV("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V,
+		 0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V,
+	7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0,
+		 in_tlv),
+SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1),
+
+SOC_SINGLE_TLV("Mic Boost Volume", WM8731_APANA, 0, 1, 0, mic_tlv),
+SOC_SINGLE("Mic Capture Switch", WM8731_APANA, 1, 1, 1),
+
+SOC_SINGLE_TLV("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1,
+	       sidetone_tlv),
+
+SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1),
+SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
+
+SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
+		    wm8731_get_deemph, wm8731_put_deemph),
+};
+
+/* Output Mixer */
+static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0),
+SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0),
+SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
+};
+
+/* Input mux */
+static const struct snd_kcontrol_new wm8731_input_mux_controls =
+SOC_DAPM_ENUM("Input Select", wm8731_insel_enum);
+
+static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("ACTIVE",WM8731_ACTIVE, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0),
+SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1,
+	&wm8731_output_mixer_controls[0],
+	ARRAY_SIZE(wm8731_output_mixer_controls)),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8731_PWR, 3, 1),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8731_PWR, 2, 1),
+SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &wm8731_input_mux_controls),
+SND_SOC_DAPM_PGA("Line Input", WM8731_PWR, 0, 1, NULL, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias", WM8731_PWR, 1, 1),
+SND_SOC_DAPM_INPUT("MICIN"),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
+			    struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
+
+	return wm8731->sysclk_type == WM8731_SYSCLK_XTAL;
+}
+
+static const struct snd_soc_dapm_route wm8731_intercon[] = {
+	{"DAC", NULL, "OSC", wm8731_check_osc},
+	{"ADC", NULL, "OSC", wm8731_check_osc},
+	{"DAC", NULL, "ACTIVE"},
+	{"ADC", NULL, "ACTIVE"},
+
+	/* output mixer */
+	{"Output Mixer", "Line Bypass Switch", "Line Input"},
+	{"Output Mixer", "HiFi Playback Switch", "DAC"},
+	{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
+
+	/* outputs */
+	{"RHPOUT", NULL, "Output Mixer"},
+	{"ROUT", NULL, "Output Mixer"},
+	{"LHPOUT", NULL, "Output Mixer"},
+	{"LOUT", NULL, "Output Mixer"},
+
+	/* input mux */
+	{"Input Mux", "Line In", "Line Input"},
+	{"Input Mux", "Mic", "Mic Bias"},
+	{"ADC", NULL, "Input Mux"},
+
+	/* inputs */
+	{"Line Input", NULL, "LLINEIN"},
+	{"Line Input", NULL, "RLINEIN"},
+	{"Mic Bias", NULL, "MICIN"},
+};
+
+struct _coeff_div {
+	u32 mclk;
+	u32 rate;
+	u16 fs;
+	u8 sr:4;
+	u8 bosr:1;
+	u8 usb:1;
+};
+
+/* codec mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	/* 48k */
+	{12288000, 48000, 256, 0x0, 0x0, 0x0},
+	{18432000, 48000, 384, 0x0, 0x1, 0x0},
+	{12000000, 48000, 250, 0x0, 0x0, 0x1},
+
+	/* 32k */
+	{12288000, 32000, 384, 0x6, 0x0, 0x0},
+	{18432000, 32000, 576, 0x6, 0x1, 0x0},
+	{12000000, 32000, 375, 0x6, 0x0, 0x1},
+
+	/* 8k */
+	{12288000, 8000, 1536, 0x3, 0x0, 0x0},
+	{18432000, 8000, 2304, 0x3, 0x1, 0x0},
+	{11289600, 8000, 1408, 0xb, 0x0, 0x0},
+	{16934400, 8000, 2112, 0xb, 0x1, 0x0},
+	{12000000, 8000, 1500, 0x3, 0x0, 0x1},
+
+	/* 96k */
+	{12288000, 96000, 128, 0x7, 0x0, 0x0},
+	{18432000, 96000, 192, 0x7, 0x1, 0x0},
+	{12000000, 96000, 125, 0x7, 0x0, 0x1},
+
+	/* 44.1k */
+	{11289600, 44100, 256, 0x8, 0x0, 0x0},
+	{16934400, 44100, 384, 0x8, 0x1, 0x0},
+	{12000000, 44100, 272, 0x8, 0x1, 0x1},
+
+	/* 88.2k */
+	{11289600, 88200, 128, 0xf, 0x0, 0x0},
+	{16934400, 88200, 192, 0xf, 0x1, 0x0},
+	{12000000, 88200, 136, 0xf, 0x1, 0x1},
+};
+
+/* rates constraints */
+static const unsigned int wm8731_rates_12000000[] = {
+	8000, 32000, 44100, 48000, 96000, 88200,
+};
+
+static const unsigned int wm8731_rates_12288000_18432000[] = {
+	8000, 32000, 48000, 96000,
+};
+
+static const unsigned int wm8731_rates_11289600_16934400[] = {
+	8000, 44100, 88200,
+};
+
+static const struct snd_pcm_hw_constraint_list wm8731_constraints_12000000 = {
+	.list = wm8731_rates_12000000,
+	.count = ARRAY_SIZE(wm8731_rates_12000000),
+};
+
+static const
+struct snd_pcm_hw_constraint_list wm8731_constraints_12288000_18432000 = {
+	.list = wm8731_rates_12288000_18432000,
+	.count = ARRAY_SIZE(wm8731_rates_12288000_18432000),
+};
+
+static const
+struct snd_pcm_hw_constraint_list wm8731_constraints_11289600_16934400 = {
+	.list = wm8731_rates_11289600_16934400,
+	.count = ARRAY_SIZE(wm8731_rates_11289600_16934400),
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+	return 0;
+}
+
+static int wm8731_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
+	u16 iface = snd_soc_component_read32(component, WM8731_IFACE) & 0xfff3;
+	int i = get_coeff(wm8731->sysclk, params_rate(params));
+	u16 srate = (coeff_div[i].sr << 2) |
+		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
+
+	wm8731->playback_fs = params_rate(params);
+
+	snd_soc_component_write(component, WM8731_SRATE, srate);
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		iface |= 0x0004;
+		break;
+	case 24:
+		iface |= 0x0008;
+		break;
+	case 32:
+		iface |= 0x000c;
+		break;
+	}
+
+	wm8731_set_deemph(component);
+
+	snd_soc_component_write(component, WM8731_IFACE, iface);
+	return 0;
+}
+
+static int wm8731_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8731_APDIGI) & 0xfff7;
+
+	if (mute)
+		snd_soc_component_write(component, WM8731_APDIGI, mute_reg | 0x8);
+	else
+		snd_soc_component_write(component, WM8731_APDIGI, mute_reg);
+	return 0;
+}
+
+static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case WM8731_SYSCLK_XTAL:
+	case WM8731_SYSCLK_MCLK:
+		if (wm8731->mclk && clk_set_rate(wm8731->mclk, freq))
+			return -EINVAL;
+		wm8731->sysclk_type = clk_id;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (freq) {
+	case 0:
+		wm8731->constraints = NULL;
+		break;
+	case 12000000:
+		wm8731->constraints = &wm8731_constraints_12000000;
+		break;
+	case 12288000:
+	case 18432000:
+		wm8731->constraints = &wm8731_constraints_12288000_18432000;
+		break;
+	case 16934400:
+	case 11289600:
+		wm8731->constraints = &wm8731_constraints_11289600_16934400;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8731->sysclk = freq;
+
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+
+static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface |= 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0013;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0003;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface */
+	snd_soc_component_write(component, WM8731_IFACE, iface);
+	return 0;
+}
+
+static int wm8731_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
+	int ret;
+	u16 reg;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		if (wm8731->mclk) {
+			ret = clk_prepare_enable(wm8731->mclk);
+			if (ret)
+				return ret;
+		}
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
+						    wm8731->supplies);
+			if (ret != 0)
+				return ret;
+
+			regcache_sync(wm8731->regmap);
+		}
+
+		/* Clear PWROFF, gate CLKOUT, everything else as-is */
+		reg = snd_soc_component_read32(component, WM8731_PWR) & 0xff7f;
+		snd_soc_component_write(component, WM8731_PWR, reg | 0x0040);
+		break;
+	case SND_SOC_BIAS_OFF:
+		if (wm8731->mclk)
+			clk_disable_unprepare(wm8731->mclk);
+		snd_soc_component_write(component, WM8731_PWR, 0xffff);
+		regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
+				       wm8731->supplies);
+		regcache_mark_dirty(wm8731->regmap);
+		break;
+	}
+	return 0;
+}
+
+static int wm8731_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(dai->component);
+
+	if (wm8731->constraints)
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+					   SNDRV_PCM_HW_PARAM_RATE,
+					   wm8731->constraints);
+
+	return 0;
+}
+
+#define WM8731_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8731_dai_ops = {
+	.startup	= wm8731_startup,
+	.hw_params	= wm8731_hw_params,
+	.digital_mute	= wm8731_mute,
+	.set_sysclk	= wm8731_set_dai_sysclk,
+	.set_fmt	= wm8731_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver wm8731_dai = {
+	.name = "wm8731-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8731_RATES,
+		.formats = WM8731_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8731_RATES,
+		.formats = WM8731_FORMATS,},
+	.ops = &wm8731_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int wm8731_request_supplies(struct device *dev,
+		struct wm8731_priv *wm8731)
+{
+	int ret = 0, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
+		wm8731->supplies[i].supply = wm8731_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8731->supplies),
+				 wm8731->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
+				    wm8731->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int wm8731_hw_init(struct device *dev, struct wm8731_priv *wm8731)
+{
+	int ret = 0;
+
+	ret = wm8731_reset(wm8731->regmap);
+	if (ret < 0) {
+		dev_err(dev, "Failed to issue reset: %d\n", ret);
+		goto err_regulator_enable;
+	}
+
+	/* Clear POWEROFF, keep everything else disabled */
+	regmap_write(wm8731->regmap, WM8731_PWR, 0x7f);
+
+	/* Latch the update bits */
+	regmap_update_bits(wm8731->regmap, WM8731_LOUT1V, 0x100, 0);
+	regmap_update_bits(wm8731->regmap, WM8731_ROUT1V, 0x100, 0);
+	regmap_update_bits(wm8731->regmap, WM8731_LINVOL, 0x100, 0);
+	regmap_update_bits(wm8731->regmap, WM8731_RINVOL, 0x100, 0);
+
+	/* Disable bypass path by default */
+	regmap_update_bits(wm8731->regmap, WM8731_APANA, 0x8, 0);
+
+	regcache_mark_dirty(wm8731->regmap);
+
+err_regulator_enable:
+	/* Regulators will be enabled by bias management */
+	regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
+
+	return ret;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8731 = {
+	.set_bias_level		= wm8731_set_bias_level,
+	.controls		= wm8731_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8731_snd_controls),
+	.dapm_widgets		= wm8731_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8731_dapm_widgets),
+	.dapm_routes		= wm8731_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(wm8731_intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct of_device_id wm8731_of_match[] = {
+	{ .compatible = "wlf,wm8731", },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, wm8731_of_match);
+
+static const struct regmap_config wm8731_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = WM8731_RESET,
+	.volatile_reg = wm8731_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8731_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8731_reg_defaults),
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8731_spi_probe(struct spi_device *spi)
+{
+	struct wm8731_priv *wm8731;
+	int ret;
+
+	wm8731 = devm_kzalloc(&spi->dev, sizeof(*wm8731), GFP_KERNEL);
+	if (wm8731 == NULL)
+		return -ENOMEM;
+
+	wm8731->mclk = devm_clk_get(&spi->dev, "mclk");
+	if (IS_ERR(wm8731->mclk)) {
+		ret = PTR_ERR(wm8731->mclk);
+		if (ret == -ENOENT) {
+			wm8731->mclk = NULL;
+			dev_warn(&spi->dev, "Assuming static MCLK\n");
+		} else {
+			dev_err(&spi->dev, "Failed to get MCLK: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	mutex_init(&wm8731->lock);
+
+	spi_set_drvdata(spi, wm8731);
+
+	ret = wm8731_request_supplies(&spi->dev, wm8731);
+	if (ret != 0)
+		return ret;
+
+	wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap);
+	if (IS_ERR(wm8731->regmap)) {
+		ret = PTR_ERR(wm8731->regmap);
+		dev_err(&spi->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = wm8731_hw_init(&spi->dev, wm8731);
+	if (ret != 0)
+		return ret;
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8731, &wm8731_dai, 1);
+	if (ret != 0) {
+		dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int wm8731_spi_remove(struct spi_device *spi)
+{
+	return 0;
+}
+
+static struct spi_driver wm8731_spi_driver = {
+	.driver = {
+		.name	= "wm8731",
+		.of_match_table = wm8731_of_match,
+	},
+	.probe		= wm8731_spi_probe,
+	.remove		= wm8731_spi_remove,
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8731_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8731_priv *wm8731;
+	int ret;
+
+	wm8731 = devm_kzalloc(&i2c->dev, sizeof(struct wm8731_priv),
+			      GFP_KERNEL);
+	if (wm8731 == NULL)
+		return -ENOMEM;
+
+	wm8731->mclk = devm_clk_get(&i2c->dev, "mclk");
+	if (IS_ERR(wm8731->mclk)) {
+		ret = PTR_ERR(wm8731->mclk);
+		if (ret == -ENOENT) {
+			wm8731->mclk = NULL;
+			dev_warn(&i2c->dev, "Assuming static MCLK\n");
+		} else {
+			dev_err(&i2c->dev, "Failed to get MCLK: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	mutex_init(&wm8731->lock);
+
+	i2c_set_clientdata(i2c, wm8731);
+
+	ret = wm8731_request_supplies(&i2c->dev, wm8731);
+	if (ret != 0)
+		return ret;
+
+	wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap);
+	if (IS_ERR(wm8731->regmap)) {
+		ret = PTR_ERR(wm8731->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = wm8731_hw_init(&i2c->dev, wm8731);
+	if (ret != 0)
+		return ret;
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8731, &wm8731_dai, 1);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int wm8731_i2c_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id wm8731_i2c_id[] = {
+	{ "wm8731", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
+
+static struct i2c_driver wm8731_i2c_driver = {
+	.driver = {
+		.name = "wm8731",
+		.of_match_table = wm8731_of_match,
+	},
+	.probe =    wm8731_i2c_probe,
+	.remove =   wm8731_i2c_remove,
+	.id_table = wm8731_i2c_id,
+};
+#endif
+
+static int __init wm8731_modinit(void)
+{
+	int ret = 0;
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&wm8731_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8731_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8731 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return ret;
+}
+module_init(wm8731_modinit);
+
+static void __exit wm8731_exit(void)
+{
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&wm8731_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8731_spi_driver);
+#endif
+}
+module_exit(wm8731_exit);
+
+MODULE_DESCRIPTION("ASoC WM8731 driver");
+MODULE_AUTHOR("Richard Purdie");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h
new file mode 100644
index 0000000..c7c6f15
--- /dev/null
+++ b/sound/soc/codecs/wm8731.h
@@ -0,0 +1,39 @@
+/*
+ * wm8731.h  --  WM8731 Soc Audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on wm8753.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8731_H
+#define _WM8731_H
+
+/* WM8731 register space */
+
+#define WM8731_LINVOL   0x00
+#define WM8731_RINVOL   0x01
+#define WM8731_LOUT1V   0x02
+#define WM8731_ROUT1V   0x03
+#define WM8731_APANA    0x04
+#define WM8731_APDIGI   0x05
+#define WM8731_PWR      0x06
+#define WM8731_IFACE    0x07
+#define WM8731_SRATE    0x08
+#define WM8731_ACTIVE   0x09
+#define WM8731_RESET	0x0f
+
+#define WM8731_CACHEREGNUM 	10
+
+#define WM8731_SYSCLK_MCLK 0
+#define WM8731_SYSCLK_XTAL 1
+
+#define WM8731_DAI		0
+
+#endif
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
new file mode 100644
index 0000000..e9ae821
--- /dev/null
+++ b/sound/soc/codecs/wm8737.c
@@ -0,0 +1,738 @@
+/*
+ * wm8737.c  --  WM8737 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8737.h"
+
+#define WM8737_NUM_SUPPLIES 4
+static const char *wm8737_supply_names[WM8737_NUM_SUPPLIES] = {
+	"DCVDD",
+	"DBVDD",
+	"AVDD",
+	"MVDD",
+};
+
+/* codec private data */
+struct wm8737_priv {
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[WM8737_NUM_SUPPLIES];
+	unsigned int mclk;
+};
+
+static const struct reg_default wm8737_reg_defaults[] = {
+	{  0, 0x00C3 },     /* R0  - Left PGA volume */
+	{  1, 0x00C3 },     /* R1  - Right PGA volume */
+	{  2, 0x0007 },     /* R2  - AUDIO path L */
+	{  3, 0x0007 },     /* R3  - AUDIO path R */
+	{  4, 0x0000 },     /* R4  - 3D Enhance */
+	{  5, 0x0000 },     /* R5  - ADC Control */
+	{  6, 0x0000 },     /* R6  - Power Management */
+	{  7, 0x000A },     /* R7  - Audio Format */
+	{  8, 0x0000 },     /* R8  - Clocking */
+	{  9, 0x000F },     /* R9  - MIC Preamp Control */
+	{ 10, 0x0003 },     /* R10 - Misc Bias Control */
+	{ 11, 0x0000 },     /* R11 - Noise Gate */
+	{ 12, 0x007C },     /* R12 - ALC1 */
+	{ 13, 0x0000 },     /* R13 - ALC2 */
+	{ 14, 0x0032 },     /* R14 - ALC3 */
+};
+
+static bool wm8737_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8737_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int wm8737_reset(struct snd_soc_component *component)
+{
+	return snd_soc_component_write(component, WM8737_RESET, 0);
+}
+
+static const DECLARE_TLV_DB_RANGE(micboost_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(1300, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(1800, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2800, 0, 0),
+	3, 3, TLV_DB_SCALE_ITEM(3300, 0, 0)
+);
+static const DECLARE_TLV_DB_SCALE(pga_tlv, -9750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(ng_tlv, -7800, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_max_tlv, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_target_tlv, -1800, 100, 0);
+
+static const char *micbias_enum_text[] = {
+	"25%",
+	"50%",
+	"75%",
+	"100%",
+};
+
+static SOC_ENUM_SINGLE_DECL(micbias_enum,
+			    WM8737_MIC_PREAMP_CONTROL, 0, micbias_enum_text);
+
+static const char *low_cutoff_text[] = {
+	"Low", "High"
+};
+
+static SOC_ENUM_SINGLE_DECL(low_3d,
+			    WM8737_3D_ENHANCE, 6, low_cutoff_text);
+
+static const char *high_cutoff_text[] = {
+	"High", "Low"
+};
+
+static SOC_ENUM_SINGLE_DECL(high_3d,
+			    WM8737_3D_ENHANCE, 5, high_cutoff_text);
+
+static const char *alc_fn_text[] = {
+	"Disabled", "Right", "Left", "Stereo"
+};
+
+static SOC_ENUM_SINGLE_DECL(alc_fn,
+			    WM8737_ALC1, 7, alc_fn_text);
+
+static const char *alc_hold_text[] = {
+	"0", "2.67ms", "5.33ms", "10.66ms", "21.32ms", "42.64ms", "85.28ms",
+	"170.56ms", "341.12ms", "682.24ms", "1.364s", "2.728s", "5.458s",
+	"10.916s", "21.832s", "43.691s"
+};
+
+static SOC_ENUM_SINGLE_DECL(alc_hold,
+			    WM8737_ALC2, 0, alc_hold_text);
+
+static const char *alc_atk_text[] = {
+	"8.4ms", "16.8ms", "33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms",
+	"1.075s", "2.15s", "4.3s", "8.6s"
+};
+
+static SOC_ENUM_SINGLE_DECL(alc_atk,
+			    WM8737_ALC3, 0, alc_atk_text);
+
+static const char *alc_dcy_text[] = {
+	"33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms", "1.075s", "2.15s",
+	"4.3s", "8.6s", "17.2s", "34.41s"
+};
+
+static SOC_ENUM_SINGLE_DECL(alc_dcy,
+			    WM8737_ALC3, 4, alc_dcy_text);
+
+static const struct snd_kcontrol_new wm8737_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Mic Boost Volume", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
+		 6, 3, 0, micboost_tlv),
+SOC_DOUBLE_R("Mic Boost Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
+	     4, 1, 0),
+SOC_DOUBLE("Mic ZC Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
+	   3, 1, 0),
+
+SOC_DOUBLE_R_TLV("Capture Volume", WM8737_LEFT_PGA_VOLUME,
+		 WM8737_RIGHT_PGA_VOLUME, 0, 255, 0, pga_tlv),
+SOC_DOUBLE("Capture ZC Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
+	   2, 1, 0),
+
+SOC_DOUBLE("INPUT1 DC Bias Switch", WM8737_MISC_BIAS_CONTROL, 0, 1, 1, 0),
+
+SOC_ENUM("Mic PGA Bias", micbias_enum),
+SOC_SINGLE("ADC Low Power Switch", WM8737_ADC_CONTROL, 2, 1, 0),
+SOC_SINGLE("High Pass Filter Switch", WM8737_ADC_CONTROL, 0, 1, 1),
+SOC_DOUBLE("Polarity Invert Switch", WM8737_ADC_CONTROL, 5, 6, 1, 0),
+
+SOC_SINGLE("3D Switch", WM8737_3D_ENHANCE, 0, 1, 0),
+SOC_SINGLE("3D Depth", WM8737_3D_ENHANCE, 1, 15, 0),
+SOC_ENUM("3D Low Cut-off", low_3d),
+SOC_ENUM("3D High Cut-off", low_3d),
+SOC_SINGLE_TLV("3D ADC Volume", WM8737_3D_ENHANCE, 7, 1, 1, adc_tlv),
+
+SOC_SINGLE("Noise Gate Switch", WM8737_NOISE_GATE, 0, 1, 0),
+SOC_SINGLE_TLV("Noise Gate Threshold Volume", WM8737_NOISE_GATE, 2, 7, 0,
+	       ng_tlv),
+
+SOC_ENUM("ALC", alc_fn),
+SOC_SINGLE_TLV("ALC Max Gain Volume", WM8737_ALC1, 4, 7, 0, alc_max_tlv),
+SOC_SINGLE_TLV("ALC Target Volume", WM8737_ALC1, 0, 15, 0, alc_target_tlv),
+SOC_ENUM("ALC Hold Time", alc_hold),
+SOC_SINGLE("ALC ZC Switch", WM8737_ALC2, 4, 1, 0),
+SOC_ENUM("ALC Attack Time", alc_atk),
+SOC_ENUM("ALC Decay Time", alc_dcy),
+};
+
+static const char *linsel_text[] = {
+	"LINPUT1", "LINPUT2", "LINPUT3", "LINPUT1 DC",
+};
+
+static SOC_ENUM_SINGLE_DECL(linsel_enum,
+			    WM8737_AUDIO_PATH_L, 7, linsel_text);
+
+static const struct snd_kcontrol_new linsel_mux =
+	SOC_DAPM_ENUM("LINSEL", linsel_enum);
+
+
+static const char *rinsel_text[] = {
+	"RINPUT1", "RINPUT2", "RINPUT3", "RINPUT1 DC",
+};
+
+static SOC_ENUM_SINGLE_DECL(rinsel_enum,
+			    WM8737_AUDIO_PATH_R, 7, rinsel_text);
+
+static const struct snd_kcontrol_new rinsel_mux =
+	SOC_DAPM_ENUM("RINSEL", rinsel_enum);
+
+static const char *bypass_text[] = {
+	"Direct", "Preamp"
+};
+
+static SOC_ENUM_SINGLE_DECL(lbypass_enum,
+			    WM8737_MIC_PREAMP_CONTROL, 2, bypass_text);
+
+static const struct snd_kcontrol_new lbypass_mux =
+	SOC_DAPM_ENUM("Left Bypass", lbypass_enum);
+
+
+static SOC_ENUM_SINGLE_DECL(rbypass_enum,
+			    WM8737_MIC_PREAMP_CONTROL, 3, bypass_text);
+
+static const struct snd_kcontrol_new rbypass_mux =
+	SOC_DAPM_ENUM("Left Bypass", rbypass_enum);
+
+static const struct snd_soc_dapm_widget wm8737_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("LINPUT1"),
+SND_SOC_DAPM_INPUT("LINPUT2"),
+SND_SOC_DAPM_INPUT("LINPUT3"),
+SND_SOC_DAPM_INPUT("RINPUT1"),
+SND_SOC_DAPM_INPUT("RINPUT2"),
+SND_SOC_DAPM_INPUT("RINPUT3"),
+SND_SOC_DAPM_INPUT("LACIN"),
+SND_SOC_DAPM_INPUT("RACIN"),
+
+SND_SOC_DAPM_MUX("LINSEL", SND_SOC_NOPM, 0, 0, &linsel_mux),
+SND_SOC_DAPM_MUX("RINSEL", SND_SOC_NOPM, 0, 0, &rinsel_mux),
+
+SND_SOC_DAPM_MUX("Left Preamp Mux", SND_SOC_NOPM, 0, 0, &lbypass_mux),
+SND_SOC_DAPM_MUX("Right Preamp Mux", SND_SOC_NOPM, 0, 0, &rbypass_mux),
+
+SND_SOC_DAPM_PGA("PGAL", WM8737_POWER_MANAGEMENT, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("PGAR", WM8737_POWER_MANAGEMENT, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_DAC("ADCL", NULL, WM8737_POWER_MANAGEMENT, 3, 0),
+SND_SOC_DAPM_DAC("ADCR", NULL, WM8737_POWER_MANAGEMENT, 2, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF", "Capture", 0, WM8737_POWER_MANAGEMENT, 6, 0),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	{ "LINSEL", "LINPUT1", "LINPUT1" },
+	{ "LINSEL", "LINPUT2", "LINPUT2" },
+	{ "LINSEL", "LINPUT3", "LINPUT3" },
+	{ "LINSEL", "LINPUT1 DC", "LINPUT1" },
+
+	{ "RINSEL", "RINPUT1", "RINPUT1" },
+	{ "RINSEL", "RINPUT2", "RINPUT2" },
+	{ "RINSEL", "RINPUT3", "RINPUT3" },
+	{ "RINSEL", "RINPUT1 DC", "RINPUT1" },
+
+	{ "Left Preamp Mux", "Preamp", "LINSEL" },
+	{ "Left Preamp Mux", "Direct", "LACIN" },
+
+	{ "Right Preamp Mux", "Preamp", "RINSEL" },
+	{ "Right Preamp Mux", "Direct", "RACIN" },
+
+	{ "PGAL", NULL, "Left Preamp Mux" },
+	{ "PGAR", NULL, "Right Preamp Mux" },
+
+	{ "ADCL", NULL, "PGAL" },
+	{ "ADCR", NULL, "PGAR" },
+
+	{ "AIF", NULL, "ADCL" },
+	{ "AIF", NULL, "ADCR" },
+};
+
+/* codec mclk clock divider coefficients */
+static const struct {
+	u32 mclk;
+	u32 rate;
+	u8 usb;
+	u8 sr;
+} coeff_div[] = {
+	{ 12288000,  8000, 0,  0x4 },
+	{ 12288000, 12000, 0,  0x8 },
+	{ 12288000, 16000, 0,  0xa },
+	{ 12288000, 24000, 0, 0x1c },
+	{ 12288000, 32000, 0,  0xc },
+	{ 12288000, 48000, 0,    0 },
+	{ 12288000, 96000, 0,  0xe },
+
+	{ 11289600,  8000, 0, 0x14 },
+	{ 11289600, 11025, 0, 0x18 },
+	{ 11289600, 22050, 0, 0x1a },
+	{ 11289600, 44100, 0, 0x10 },
+	{ 11289600, 88200, 0, 0x1e },
+
+	{ 18432000,  8000, 0,  0x5 },
+	{ 18432000, 12000, 0,  0x9 },
+	{ 18432000, 16000, 0,  0xb },
+	{ 18432000, 24000, 0, 0x1b },
+	{ 18432000, 32000, 0,  0xd },
+	{ 18432000, 48000, 0,  0x1 },
+	{ 18432000, 96000, 0, 0x1f },
+
+	{ 16934400,  8000, 0, 0x15 },
+	{ 16934400, 11025, 0, 0x19 },
+	{ 16934400, 22050, 0, 0x1b },
+	{ 16934400, 44100, 0, 0x11 },
+	{ 16934400, 88200, 0, 0x1f },
+
+	{ 12000000,  8000, 1,  0x4 },
+	{ 12000000, 11025, 1, 0x19 },
+	{ 12000000, 12000, 1,  0x8 },
+	{ 12000000, 16000, 1,  0xa },
+	{ 12000000, 22050, 1, 0x1b },
+	{ 12000000, 24000, 1, 0x1c },
+	{ 12000000, 32000, 1,  0xc },
+	{ 12000000, 44100, 1, 0x11 },
+	{ 12000000, 48000, 1,  0x0 },
+	{ 12000000, 88200, 1, 0x1f },
+	{ 12000000, 96000, 1,  0xe },
+};
+
+static int wm8737_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8737_priv *wm8737 = snd_soc_component_get_drvdata(component);
+	int i;
+	u16 clocking = 0;
+	u16 af = 0;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate != params_rate(params))
+			continue;
+
+		if (coeff_div[i].mclk == wm8737->mclk)
+			break;
+
+		if (coeff_div[i].mclk == wm8737->mclk * 2) {
+			clocking |= WM8737_CLKDIV2;
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(coeff_div)) {
+		dev_err(component->dev, "%dHz MCLK can't support %dHz\n",
+			wm8737->mclk, params_rate(params));
+		return -EINVAL;
+	}
+
+	clocking |= coeff_div[i].usb | (coeff_div[i].sr << WM8737_SR_SHIFT);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		af |= 0x8;
+		break;
+	case 24:
+		af |= 0x10;
+		break;
+	case 32:
+		af |= 0x18;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8737_AUDIO_FORMAT, WM8737_WL_MASK, af);
+	snd_soc_component_update_bits(component, WM8737_CLOCKING,
+			    WM8737_USB_MODE | WM8737_CLKDIV2 | WM8737_SR_MASK,
+			    clocking);
+
+	return 0;
+}
+
+static int wm8737_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8737_priv *wm8737 = snd_soc_component_get_drvdata(component);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (freq == coeff_div[i].mclk ||
+		    freq == coeff_div[i].mclk * 2) {
+			wm8737->mclk = freq;
+			return 0;
+		}
+	}
+
+	dev_err(component->dev, "MCLK rate %dHz not supported\n", freq);
+
+	return -EINVAL;
+}
+
+
+static int wm8737_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 af = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		af |= WM8737_MS;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		af |= 0x2;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		af |= 0x1;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		af |= 0x3;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		af |= 0x13;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		af |= WM8737_LRP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8737_AUDIO_FORMAT,
+			    WM8737_FORMAT_MASK | WM8737_LRP | WM8737_MS, af);
+
+	return 0;
+}
+
+static int wm8737_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8737_priv *wm8737 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* VMID at 2*75k */
+		snd_soc_component_update_bits(component, WM8737_MISC_BIAS_CONTROL,
+				    WM8737_VMIDSEL_MASK, 0);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
+						    wm8737->supplies);
+			if (ret != 0) {
+				dev_err(component->dev,
+					"Failed to enable supplies: %d\n",
+					ret);
+				return ret;
+			}
+
+			regcache_sync(wm8737->regmap);
+
+			/* Fast VMID ramp at 2*2.5k */
+			snd_soc_component_update_bits(component, WM8737_MISC_BIAS_CONTROL,
+					    WM8737_VMIDSEL_MASK,
+					    2 << WM8737_VMIDSEL_SHIFT);
+
+			/* Bring VMID up */
+			snd_soc_component_update_bits(component, WM8737_POWER_MANAGEMENT,
+					    WM8737_VMID_MASK |
+					    WM8737_VREF_MASK,
+					    WM8737_VMID_MASK |
+					    WM8737_VREF_MASK);
+
+			msleep(500);
+		}
+
+		/* VMID at 2*300k */
+		snd_soc_component_update_bits(component, WM8737_MISC_BIAS_CONTROL,
+				    WM8737_VMIDSEL_MASK,
+				    1 << WM8737_VMIDSEL_SHIFT);
+
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, WM8737_POWER_MANAGEMENT,
+				    WM8737_VMID_MASK | WM8737_VREF_MASK, 0);
+
+		regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies),
+				       wm8737->supplies);
+		break;
+	}
+
+	return 0;
+}
+
+#define WM8737_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8737_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8737_dai_ops = {
+	.hw_params	= wm8737_hw_params,
+	.set_sysclk	= wm8737_set_dai_sysclk,
+	.set_fmt	= wm8737_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver wm8737_dai = {
+	.name = "wm8737",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,  /* Mono modes not yet supported */
+		.channels_max = 2,
+		.rates = WM8737_RATES,
+		.formats = WM8737_FORMATS,
+	},
+	.ops = &wm8737_dai_ops,
+};
+
+static int wm8737_probe(struct snd_soc_component *component)
+{
+	struct wm8737_priv *wm8737 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
+				    wm8737->supplies);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
+		goto err_get;
+	}
+
+	ret = wm8737_reset(component);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to issue reset\n");
+		goto err_enable;
+	}
+
+	snd_soc_component_update_bits(component, WM8737_LEFT_PGA_VOLUME, WM8737_LVU,
+			    WM8737_LVU);
+	snd_soc_component_update_bits(component, WM8737_RIGHT_PGA_VOLUME, WM8737_RVU,
+			    WM8737_RVU);
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	/* Bias level configuration will have done an extra enable */
+	regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
+
+	return 0;
+
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
+err_get:
+	return ret;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8737 = {
+	.probe			= wm8737_probe,
+	.set_bias_level		= wm8737_set_bias_level,
+	.controls		= wm8737_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8737_snd_controls),
+	.dapm_widgets		= wm8737_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8737_dapm_widgets),
+	.dapm_routes		= intercon,
+	.num_dapm_routes	= ARRAY_SIZE(intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct of_device_id wm8737_of_match[] = {
+	{ .compatible = "wlf,wm8737", },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, wm8737_of_match);
+
+static const struct regmap_config wm8737_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+	.max_register = WM8737_MAX_REGISTER,
+
+	.reg_defaults = wm8737_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8737_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = wm8737_volatile,
+};
+
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8737_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8737_priv *wm8737;
+	int ret, i;
+
+	wm8737 = devm_kzalloc(&i2c->dev, sizeof(struct wm8737_priv),
+			      GFP_KERNEL);
+	if (wm8737 == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(wm8737->supplies); i++)
+		wm8737->supplies[i].supply = wm8737_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8737->supplies),
+				      wm8737->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	wm8737->regmap = devm_regmap_init_i2c(i2c, &wm8737_regmap);
+	if (IS_ERR(wm8737->regmap))
+		return PTR_ERR(wm8737->regmap);
+
+	i2c_set_clientdata(i2c, wm8737);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				&soc_component_dev_wm8737, &wm8737_dai, 1);
+
+	return ret;
+
+}
+
+static const struct i2c_device_id wm8737_i2c_id[] = {
+	{ "wm8737", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8737_i2c_id);
+
+static struct i2c_driver wm8737_i2c_driver = {
+	.driver = {
+		.name = "wm8737",
+		.of_match_table = wm8737_of_match,
+	},
+	.probe =    wm8737_i2c_probe,
+	.id_table = wm8737_i2c_id,
+};
+#endif
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8737_spi_probe(struct spi_device *spi)
+{
+	struct wm8737_priv *wm8737;
+	int ret, i;
+
+	wm8737 = devm_kzalloc(&spi->dev, sizeof(struct wm8737_priv),
+			      GFP_KERNEL);
+	if (wm8737 == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(wm8737->supplies); i++)
+		wm8737->supplies[i].supply = wm8737_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8737->supplies),
+				      wm8737->supplies);
+	if (ret != 0) {
+		dev_err(&spi->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	wm8737->regmap = devm_regmap_init_spi(spi, &wm8737_regmap);
+	if (IS_ERR(wm8737->regmap))
+		return PTR_ERR(wm8737->regmap);
+
+	spi_set_drvdata(spi, wm8737);
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+				&soc_component_dev_wm8737, &wm8737_dai, 1);
+
+	return ret;
+}
+
+static struct spi_driver wm8737_spi_driver = {
+	.driver = {
+		.name	= "wm8737",
+		.of_match_table = wm8737_of_match,
+	},
+	.probe		= wm8737_spi_probe,
+};
+#endif /* CONFIG_SPI_MASTER */
+
+static int __init wm8737_modinit(void)
+{
+	int ret;
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&wm8737_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8737 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8737_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8737 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return 0;
+}
+module_init(wm8737_modinit);
+
+static void __exit wm8737_exit(void)
+{
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8737_spi_driver);
+#endif
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&wm8737_i2c_driver);
+#endif
+}
+module_exit(wm8737_exit);
+
+MODULE_DESCRIPTION("ASoC WM8737 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8737.h b/sound/soc/codecs/wm8737.h
new file mode 100644
index 0000000..23d14c8
--- /dev/null
+++ b/sound/soc/codecs/wm8737.h
@@ -0,0 +1,322 @@
+#ifndef _WM8737_H
+#define _WM8737_H
+
+/*
+ * wm8737.c  --  WM8523 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Register values.
+ */
+#define WM8737_LEFT_PGA_VOLUME                  0x00
+#define WM8737_RIGHT_PGA_VOLUME                 0x01
+#define WM8737_AUDIO_PATH_L                     0x02
+#define WM8737_AUDIO_PATH_R                     0x03
+#define WM8737_3D_ENHANCE                       0x04
+#define WM8737_ADC_CONTROL                      0x05
+#define WM8737_POWER_MANAGEMENT                 0x06
+#define WM8737_AUDIO_FORMAT                     0x07
+#define WM8737_CLOCKING                         0x08
+#define WM8737_MIC_PREAMP_CONTROL               0x09
+#define WM8737_MISC_BIAS_CONTROL                0x0A
+#define WM8737_NOISE_GATE                       0x0B
+#define WM8737_ALC1                             0x0C
+#define WM8737_ALC2                             0x0D
+#define WM8737_ALC3                             0x0E
+#define WM8737_RESET                            0x0F
+
+#define WM8737_REGISTER_COUNT                   16
+#define WM8737_MAX_REGISTER                     0x0F
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Left PGA volume
+ */
+#define WM8737_LVU                              0x0100  /* LVU */
+#define WM8737_LVU_MASK                         0x0100  /* LVU */
+#define WM8737_LVU_SHIFT                             8  /* LVU */
+#define WM8737_LVU_WIDTH                             1  /* LVU */
+#define WM8737_LINVOL_MASK                      0x00FF  /* LINVOL - [7:0] */
+#define WM8737_LINVOL_SHIFT                          0  /* LINVOL - [7:0] */
+#define WM8737_LINVOL_WIDTH                          8  /* LINVOL - [7:0] */
+
+/*
+ * R1 (0x01) - Right PGA volume
+ */
+#define WM8737_RVU                              0x0100  /* RVU */
+#define WM8737_RVU_MASK                         0x0100  /* RVU */
+#define WM8737_RVU_SHIFT                             8  /* RVU */
+#define WM8737_RVU_WIDTH                             1  /* RVU */
+#define WM8737_RINVOL_MASK                      0x00FF  /* RINVOL - [7:0] */
+#define WM8737_RINVOL_SHIFT                          0  /* RINVOL - [7:0] */
+#define WM8737_RINVOL_WIDTH                          8  /* RINVOL - [7:0] */
+
+/*
+ * R2 (0x02) - AUDIO path L
+ */
+#define WM8737_LINSEL_MASK                      0x0180  /* LINSEL - [8:7] */
+#define WM8737_LINSEL_SHIFT                          7  /* LINSEL - [8:7] */
+#define WM8737_LINSEL_WIDTH                          2  /* LINSEL - [8:7] */
+#define WM8737_LMICBOOST_MASK                   0x0060  /* LMICBOOST - [6:5] */
+#define WM8737_LMICBOOST_SHIFT                       5  /* LMICBOOST - [6:5] */
+#define WM8737_LMICBOOST_WIDTH                       2  /* LMICBOOST - [6:5] */
+#define WM8737_LMBE                             0x0010  /* LMBE */
+#define WM8737_LMBE_MASK                        0x0010  /* LMBE */
+#define WM8737_LMBE_SHIFT                            4  /* LMBE */
+#define WM8737_LMBE_WIDTH                            1  /* LMBE */
+#define WM8737_LMZC                             0x0008  /* LMZC */
+#define WM8737_LMZC_MASK                        0x0008  /* LMZC */
+#define WM8737_LMZC_SHIFT                            3  /* LMZC */
+#define WM8737_LMZC_WIDTH                            1  /* LMZC */
+#define WM8737_LPZC                             0x0004  /* LPZC */
+#define WM8737_LPZC_MASK                        0x0004  /* LPZC */
+#define WM8737_LPZC_SHIFT                            2  /* LPZC */
+#define WM8737_LPZC_WIDTH                            1  /* LPZC */
+#define WM8737_LZCTO_MASK                       0x0003  /* LZCTO - [1:0] */
+#define WM8737_LZCTO_SHIFT                           0  /* LZCTO - [1:0] */
+#define WM8737_LZCTO_WIDTH                           2  /* LZCTO - [1:0] */
+
+/*
+ * R3 (0x03) - AUDIO path R
+ */
+#define WM8737_RINSEL_MASK                      0x0180  /* RINSEL - [8:7] */
+#define WM8737_RINSEL_SHIFT                          7  /* RINSEL - [8:7] */
+#define WM8737_RINSEL_WIDTH                          2  /* RINSEL - [8:7] */
+#define WM8737_RMICBOOST_MASK                   0x0060  /* RMICBOOST - [6:5] */
+#define WM8737_RMICBOOST_SHIFT                       5  /* RMICBOOST - [6:5] */
+#define WM8737_RMICBOOST_WIDTH                       2  /* RMICBOOST - [6:5] */
+#define WM8737_RMBE                             0x0010  /* RMBE */
+#define WM8737_RMBE_MASK                        0x0010  /* RMBE */
+#define WM8737_RMBE_SHIFT                            4  /* RMBE */
+#define WM8737_RMBE_WIDTH                            1  /* RMBE */
+#define WM8737_RMZC                             0x0008  /* RMZC */
+#define WM8737_RMZC_MASK                        0x0008  /* RMZC */
+#define WM8737_RMZC_SHIFT                            3  /* RMZC */
+#define WM8737_RMZC_WIDTH                            1  /* RMZC */
+#define WM8737_RPZC                             0x0004  /* RPZC */
+#define WM8737_RPZC_MASK                        0x0004  /* RPZC */
+#define WM8737_RPZC_SHIFT                            2  /* RPZC */
+#define WM8737_RPZC_WIDTH                            1  /* RPZC */
+#define WM8737_RZCTO_MASK                       0x0003  /* RZCTO - [1:0] */
+#define WM8737_RZCTO_SHIFT                           0  /* RZCTO - [1:0] */
+#define WM8737_RZCTO_WIDTH                           2  /* RZCTO - [1:0] */
+
+/*
+ * R4 (0x04) - 3D Enhance
+ */
+#define WM8737_DIV2                             0x0080  /* DIV2 */
+#define WM8737_DIV2_MASK                        0x0080  /* DIV2 */
+#define WM8737_DIV2_SHIFT                            7  /* DIV2 */
+#define WM8737_DIV2_WIDTH                            1  /* DIV2 */
+#define WM8737_3DLC                             0x0040  /* 3DLC */
+#define WM8737_3DLC_MASK                        0x0040  /* 3DLC */
+#define WM8737_3DLC_SHIFT                            6  /* 3DLC */
+#define WM8737_3DLC_WIDTH                            1  /* 3DLC */
+#define WM8737_3DUC                             0x0020  /* 3DUC */
+#define WM8737_3DUC_MASK                        0x0020  /* 3DUC */
+#define WM8737_3DUC_SHIFT                            5  /* 3DUC */
+#define WM8737_3DUC_WIDTH                            1  /* 3DUC */
+#define WM8737_3DDEPTH_MASK                     0x001E  /* 3DDEPTH - [4:1] */
+#define WM8737_3DDEPTH_SHIFT                         1  /* 3DDEPTH - [4:1] */
+#define WM8737_3DDEPTH_WIDTH                         4  /* 3DDEPTH - [4:1] */
+#define WM8737_3DE                              0x0001  /* 3DE */
+#define WM8737_3DE_MASK                         0x0001  /* 3DE */
+#define WM8737_3DE_SHIFT                             0  /* 3DE */
+#define WM8737_3DE_WIDTH                             1  /* 3DE */
+
+/*
+ * R5 (0x05) - ADC Control
+ */
+#define WM8737_MONOMIX_MASK                     0x0180  /* MONOMIX - [8:7] */
+#define WM8737_MONOMIX_SHIFT                         7  /* MONOMIX - [8:7] */
+#define WM8737_MONOMIX_WIDTH                         2  /* MONOMIX - [8:7] */
+#define WM8737_POLARITY_MASK                    0x0060  /* POLARITY - [6:5] */
+#define WM8737_POLARITY_SHIFT                        5  /* POLARITY - [6:5] */
+#define WM8737_POLARITY_WIDTH                        2  /* POLARITY - [6:5] */
+#define WM8737_HPOR                             0x0010  /* HPOR */
+#define WM8737_HPOR_MASK                        0x0010  /* HPOR */
+#define WM8737_HPOR_SHIFT                            4  /* HPOR */
+#define WM8737_HPOR_WIDTH                            1  /* HPOR */
+#define WM8737_LP                               0x0004  /* LP */
+#define WM8737_LP_MASK                          0x0004  /* LP */
+#define WM8737_LP_SHIFT                              2  /* LP */
+#define WM8737_LP_WIDTH                              1  /* LP */
+#define WM8737_MONOUT                           0x0002  /* MONOUT */
+#define WM8737_MONOUT_MASK                      0x0002  /* MONOUT */
+#define WM8737_MONOUT_SHIFT                          1  /* MONOUT */
+#define WM8737_MONOUT_WIDTH                          1  /* MONOUT */
+#define WM8737_ADCHPD                           0x0001  /* ADCHPD */
+#define WM8737_ADCHPD_MASK                      0x0001  /* ADCHPD */
+#define WM8737_ADCHPD_SHIFT                          0  /* ADCHPD */
+#define WM8737_ADCHPD_WIDTH                          1  /* ADCHPD */
+
+/*
+ * R6 (0x06) - Power Management
+ */
+#define WM8737_VMID                             0x0100  /* VMID */
+#define WM8737_VMID_MASK                        0x0100  /* VMID */
+#define WM8737_VMID_SHIFT                            8  /* VMID */
+#define WM8737_VMID_WIDTH                            1  /* VMID */
+#define WM8737_VREF                             0x0080  /* VREF */
+#define WM8737_VREF_MASK                        0x0080  /* VREF */
+#define WM8737_VREF_SHIFT                            7  /* VREF */
+#define WM8737_VREF_WIDTH                            1  /* VREF */
+#define WM8737_AI                               0x0040  /* AI */
+#define WM8737_AI_MASK                          0x0040  /* AI */
+#define WM8737_AI_SHIFT                              6  /* AI */
+#define WM8737_AI_WIDTH                              1  /* AI */
+#define WM8737_PGL                              0x0020  /* PGL */
+#define WM8737_PGL_MASK                         0x0020  /* PGL */
+#define WM8737_PGL_SHIFT                             5  /* PGL */
+#define WM8737_PGL_WIDTH                             1  /* PGL */
+#define WM8737_PGR                              0x0010  /* PGR */
+#define WM8737_PGR_MASK                         0x0010  /* PGR */
+#define WM8737_PGR_SHIFT                             4  /* PGR */
+#define WM8737_PGR_WIDTH                             1  /* PGR */
+#define WM8737_ADL                              0x0008  /* ADL */
+#define WM8737_ADL_MASK                         0x0008  /* ADL */
+#define WM8737_ADL_SHIFT                             3  /* ADL */
+#define WM8737_ADL_WIDTH                             1  /* ADL */
+#define WM8737_ADR                              0x0004  /* ADR */
+#define WM8737_ADR_MASK                         0x0004  /* ADR */
+#define WM8737_ADR_SHIFT                             2  /* ADR */
+#define WM8737_ADR_WIDTH                             1  /* ADR */
+#define WM8737_MICBIAS_MASK                     0x0003  /* MICBIAS - [1:0] */
+#define WM8737_MICBIAS_SHIFT                         0  /* MICBIAS - [1:0] */
+#define WM8737_MICBIAS_WIDTH                         2  /* MICBIAS - [1:0] */
+
+/*
+ * R7 (0x07) - Audio Format
+ */
+#define WM8737_SDODIS                           0x0080  /* SDODIS */
+#define WM8737_SDODIS_MASK                      0x0080  /* SDODIS */
+#define WM8737_SDODIS_SHIFT                          7  /* SDODIS */
+#define WM8737_SDODIS_WIDTH                          1  /* SDODIS */
+#define WM8737_MS                               0x0040  /* MS */
+#define WM8737_MS_MASK                          0x0040  /* MS */
+#define WM8737_MS_SHIFT                              6  /* MS */
+#define WM8737_MS_WIDTH                              1  /* MS */
+#define WM8737_LRP                              0x0010  /* LRP */
+#define WM8737_LRP_MASK                         0x0010  /* LRP */
+#define WM8737_LRP_SHIFT                             4  /* LRP */
+#define WM8737_LRP_WIDTH                             1  /* LRP */
+#define WM8737_WL_MASK                          0x000C  /* WL - [3:2] */
+#define WM8737_WL_SHIFT                              2  /* WL - [3:2] */
+#define WM8737_WL_WIDTH                              2  /* WL - [3:2] */
+#define WM8737_FORMAT_MASK                      0x0003  /* FORMAT - [1:0] */
+#define WM8737_FORMAT_SHIFT                          0  /* FORMAT - [1:0] */
+#define WM8737_FORMAT_WIDTH                          2  /* FORMAT - [1:0] */
+
+/*
+ * R8 (0x08) - Clocking
+ */
+#define WM8737_AUTODETECT                       0x0080  /* AUTODETECT */
+#define WM8737_AUTODETECT_MASK                  0x0080  /* AUTODETECT */
+#define WM8737_AUTODETECT_SHIFT                      7  /* AUTODETECT */
+#define WM8737_AUTODETECT_WIDTH                      1  /* AUTODETECT */
+#define WM8737_CLKDIV2                          0x0040  /* CLKDIV2 */
+#define WM8737_CLKDIV2_MASK                     0x0040  /* CLKDIV2 */
+#define WM8737_CLKDIV2_SHIFT                         6  /* CLKDIV2 */
+#define WM8737_CLKDIV2_WIDTH                         1  /* CLKDIV2 */
+#define WM8737_SR_MASK                          0x003E  /* SR - [5:1] */
+#define WM8737_SR_SHIFT                              1  /* SR - [5:1] */
+#define WM8737_SR_WIDTH                              5  /* SR - [5:1] */
+#define WM8737_USB_MODE                         0x0001  /* USB MODE */
+#define WM8737_USB_MODE_MASK                    0x0001  /* USB MODE */
+#define WM8737_USB_MODE_SHIFT                        0  /* USB MODE */
+#define WM8737_USB_MODE_WIDTH                        1  /* USB MODE */
+
+/*
+ * R9 (0x09) - MIC Preamp Control
+ */
+#define WM8737_RBYPEN                           0x0008  /* RBYPEN */
+#define WM8737_RBYPEN_MASK                      0x0008  /* RBYPEN */
+#define WM8737_RBYPEN_SHIFT                          3  /* RBYPEN */
+#define WM8737_RBYPEN_WIDTH                          1  /* RBYPEN */
+#define WM8737_LBYPEN                           0x0004  /* LBYPEN */
+#define WM8737_LBYPEN_MASK                      0x0004  /* LBYPEN */
+#define WM8737_LBYPEN_SHIFT                          2  /* LBYPEN */
+#define WM8737_LBYPEN_WIDTH                          1  /* LBYPEN */
+#define WM8737_MBCTRL_MASK                      0x0003  /* MBCTRL - [1:0] */
+#define WM8737_MBCTRL_SHIFT                          0  /* MBCTRL - [1:0] */
+#define WM8737_MBCTRL_WIDTH                          2  /* MBCTRL - [1:0] */
+
+/*
+ * R10 (0x0A) - Misc Bias Control
+ */
+#define WM8737_VMIDSEL_MASK                     0x000C  /* VMIDSEL - [3:2] */
+#define WM8737_VMIDSEL_SHIFT                         2  /* VMIDSEL - [3:2] */
+#define WM8737_VMIDSEL_WIDTH                         2  /* VMIDSEL - [3:2] */
+#define WM8737_LINPUT1_DC_BIAS_ENABLE           0x0002  /* LINPUT1 DC BIAS ENABLE */
+#define WM8737_LINPUT1_DC_BIAS_ENABLE_MASK      0x0002  /* LINPUT1 DC BIAS ENABLE */
+#define WM8737_LINPUT1_DC_BIAS_ENABLE_SHIFT          1  /* LINPUT1 DC BIAS ENABLE */
+#define WM8737_LINPUT1_DC_BIAS_ENABLE_WIDTH          1  /* LINPUT1 DC BIAS ENABLE */
+#define WM8737_RINPUT1_DC_BIAS_ENABLE           0x0001  /* RINPUT1 DC BIAS ENABLE */
+#define WM8737_RINPUT1_DC_BIAS_ENABLE_MASK      0x0001  /* RINPUT1 DC BIAS ENABLE */
+#define WM8737_RINPUT1_DC_BIAS_ENABLE_SHIFT          0  /* RINPUT1 DC BIAS ENABLE */
+#define WM8737_RINPUT1_DC_BIAS_ENABLE_WIDTH          1  /* RINPUT1 DC BIAS ENABLE */
+
+/*
+ * R11 (0x0B) - Noise Gate
+ */
+#define WM8737_NGTH_MASK                        0x001C  /* NGTH - [4:2] */
+#define WM8737_NGTH_SHIFT                            2  /* NGTH - [4:2] */
+#define WM8737_NGTH_WIDTH                            3  /* NGTH - [4:2] */
+#define WM8737_NGAT                             0x0001  /* NGAT */
+#define WM8737_NGAT_MASK                        0x0001  /* NGAT */
+#define WM8737_NGAT_SHIFT                            0  /* NGAT */
+#define WM8737_NGAT_WIDTH                            1  /* NGAT */
+
+/*
+ * R12 (0x0C) - ALC1
+ */
+#define WM8737_ALCSEL_MASK                      0x0180  /* ALCSEL - [8:7] */
+#define WM8737_ALCSEL_SHIFT                          7  /* ALCSEL - [8:7] */
+#define WM8737_ALCSEL_WIDTH                          2  /* ALCSEL - [8:7] */
+#define WM8737_MAX_GAIN_MASK                    0x0070  /* MAX GAIN - [6:4] */
+#define WM8737_MAX_GAIN_SHIFT                        4  /* MAX GAIN - [6:4] */
+#define WM8737_MAX_GAIN_WIDTH                        3  /* MAX GAIN - [6:4] */
+#define WM8737_ALCL_MASK                        0x000F  /* ALCL - [3:0] */
+#define WM8737_ALCL_SHIFT                            0  /* ALCL - [3:0] */
+#define WM8737_ALCL_WIDTH                            4  /* ALCL - [3:0] */
+
+/*
+ * R13 (0x0D) - ALC2
+ */
+#define WM8737_ALCZCE                           0x0010  /* ALCZCE */
+#define WM8737_ALCZCE_MASK                      0x0010  /* ALCZCE */
+#define WM8737_ALCZCE_SHIFT                          4  /* ALCZCE */
+#define WM8737_ALCZCE_WIDTH                          1  /* ALCZCE */
+#define WM8737_HLD_MASK                         0x000F  /* HLD - [3:0] */
+#define WM8737_HLD_SHIFT                             0  /* HLD - [3:0] */
+#define WM8737_HLD_WIDTH                             4  /* HLD - [3:0] */
+
+/*
+ * R14 (0x0E) - ALC3
+ */
+#define WM8737_DCY_MASK                         0x00F0  /* DCY - [7:4] */
+#define WM8737_DCY_SHIFT                             4  /* DCY - [7:4] */
+#define WM8737_DCY_WIDTH                             4  /* DCY - [7:4] */
+#define WM8737_ATK_MASK                         0x000F  /* ATK - [3:0] */
+#define WM8737_ATK_SHIFT                             0  /* ATK - [3:0] */
+#define WM8737_ATK_WIDTH                             4  /* ATK - [3:0] */
+
+/*
+ * R15 (0x0F) - Reset
+ */
+#define WM8737_RESET_MASK                       0x01FF  /* RESET - [8:0] */
+#define WM8737_RESET_SHIFT                           0  /* RESET - [8:0] */
+#define WM8737_RESET_WIDTH                           9  /* RESET - [8:0] */
+
+#endif
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
new file mode 100644
index 0000000..1fedf74
--- /dev/null
+++ b/sound/soc/codecs/wm8741.c
@@ -0,0 +1,693 @@
+/*
+ * wm8741.c  --  WM8741 ALSA SoC Audio driver
+ *
+ * Copyright 2010-1 Wolfson Microelectronics plc
+ *
+ * Author: Ian Lartey <ian@opensource.wolfsonmicro.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8741.h"
+
+#define WM8741_NUM_SUPPLIES 2
+static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
+	"AVDD",
+	"DVDD",
+};
+
+/* codec private data */
+struct wm8741_priv {
+	struct wm8741_platform_data pdata;
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
+	unsigned int sysclk;
+	const struct snd_pcm_hw_constraint_list *sysclk_constraints;
+};
+
+static const struct reg_default wm8741_reg_defaults[] = {
+	{  0, 0x0000 },     /* R0  - DACLLSB Attenuation */
+	{  1, 0x0000 },     /* R1  - DACLMSB Attenuation */
+	{  2, 0x0000 },     /* R2  - DACRLSB Attenuation */
+	{  3, 0x0000 },     /* R3  - DACRMSB Attenuation */
+	{  4, 0x0000 },     /* R4  - Volume Control */
+	{  5, 0x000A },     /* R5  - Format Control */
+	{  6, 0x0000 },     /* R6  - Filter Control */
+	{  7, 0x0000 },     /* R7  - Mode Control 1 */
+	{  8, 0x0002 },     /* R8  - Mode Control 2 */
+	{ 32, 0x0002 },     /* R32 - ADDITONAL_CONTROL_1 */
+};
+
+static int wm8741_reset(struct snd_soc_component *component)
+{
+	return snd_soc_component_write(component, WM8741_RESET, 0);
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0);
+
+static const struct snd_kcontrol_new wm8741_snd_controls_stereo[] = {
+SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
+		 WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine),
+SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION,
+		 WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv),
+};
+
+static const struct snd_kcontrol_new wm8741_snd_controls_mono_left[] = {
+SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
+		 1, 255, 1, dac_tlv_fine),
+SOC_SINGLE_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION,
+		 0, 511, 1, dac_tlv),
+};
+
+static const struct snd_kcontrol_new wm8741_snd_controls_mono_right[] = {
+SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACRLSB_ATTENUATION,
+		1, 255, 1, dac_tlv_fine),
+SOC_SINGLE_TLV("Playback Volume", WM8741_DACRMSB_ATTENUATION,
+		0, 511, 1, dac_tlv),
+};
+
+static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_OUTPUT("VOUTLP"),
+SND_SOC_DAPM_OUTPUT("VOUTLN"),
+SND_SOC_DAPM_OUTPUT("VOUTRP"),
+SND_SOC_DAPM_OUTPUT("VOUTRN"),
+};
+
+static const struct snd_soc_dapm_route wm8741_dapm_routes[] = {
+	{ "VOUTLP", NULL, "DACL" },
+	{ "VOUTLN", NULL, "DACL" },
+	{ "VOUTRP", NULL, "DACR" },
+	{ "VOUTRN", NULL, "DACR" },
+};
+
+static const unsigned int rates_11289[] = {
+	44100, 88200,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_11289 = {
+	.count	= ARRAY_SIZE(rates_11289),
+	.list	= rates_11289,
+};
+
+static const unsigned int rates_12288[] = {
+	32000, 48000, 96000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_12288 = {
+	.count	= ARRAY_SIZE(rates_12288),
+	.list	= rates_12288,
+};
+
+static const unsigned int rates_16384[] = {
+	32000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_16384 = {
+	.count	= ARRAY_SIZE(rates_16384),
+	.list	= rates_16384,
+};
+
+static const unsigned int rates_16934[] = {
+	44100, 88200,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_16934 = {
+	.count	= ARRAY_SIZE(rates_16934),
+	.list	= rates_16934,
+};
+
+static const unsigned int rates_18432[] = {
+	48000, 96000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_18432 = {
+	.count	= ARRAY_SIZE(rates_18432),
+	.list	= rates_18432,
+};
+
+static const unsigned int rates_22579[] = {
+	44100, 88200, 176400
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_22579 = {
+	.count	= ARRAY_SIZE(rates_22579),
+	.list	= rates_22579,
+};
+
+static const unsigned int rates_24576[] = {
+	32000, 48000, 96000, 192000
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_24576 = {
+	.count	= ARRAY_SIZE(rates_24576),
+	.list	= rates_24576,
+};
+
+static const unsigned int rates_36864[] = {
+	48000, 96000, 192000
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_36864 = {
+	.count	= ARRAY_SIZE(rates_36864),
+	.list	= rates_36864,
+};
+
+static int wm8741_startup(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
+
+	if (wm8741->sysclk)
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				wm8741->sysclk_constraints);
+
+	return 0;
+}
+
+static int wm8741_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
+	unsigned int iface;
+	int i;
+
+	/* The set of sample rates that can be supported depends on the
+	 * MCLK supplied to the CODEC - enforce this.
+	 */
+	if (!wm8741->sysclk) {
+		dev_err(component->dev,
+			"No MCLK configured, call set_sysclk() on init or in hw_params\n");
+		return -EINVAL;
+	}
+
+	/* Find a supported LRCLK rate */
+	for (i = 0; i < wm8741->sysclk_constraints->count; i++) {
+		if (wm8741->sysclk_constraints->list[i] == params_rate(params))
+			break;
+	}
+
+	if (i == wm8741->sysclk_constraints->count) {
+		dev_err(component->dev, "LRCLK %d unsupported with MCLK %d\n",
+			params_rate(params), wm8741->sysclk);
+		return -EINVAL;
+	}
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		iface = 0x0;
+		break;
+	case 20:
+		iface = 0x1;
+		break;
+	case 24:
+		iface = 0x2;
+		break;
+	case 32:
+		iface = 0x3;
+		break;
+	default:
+		dev_dbg(component->dev, "wm8741_hw_params:    Unsupported bit size param = %d",
+			params_width(params));
+		return -EINVAL;
+	}
+
+	dev_dbg(component->dev, "wm8741_hw_params:    bit size param = %d, rate param = %d",
+		params_width(params), params_rate(params));
+
+	snd_soc_component_update_bits(component, WM8741_FORMAT_CONTROL, WM8741_IWL_MASK,
+			    iface);
+
+	return 0;
+}
+
+static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq);
+
+	switch (freq) {
+	case 0:
+		wm8741->sysclk_constraints = NULL;
+		break;
+	case 11289600:
+		wm8741->sysclk_constraints = &constraints_11289;
+		break;
+	case 12288000:
+		wm8741->sysclk_constraints = &constraints_12288;
+		break;
+	case 16384000:
+		wm8741->sysclk_constraints = &constraints_16384;
+		break;
+	case 16934400:
+		wm8741->sysclk_constraints = &constraints_16934;
+		break;
+	case 18432000:
+		wm8741->sysclk_constraints = &constraints_18432;
+		break;
+	case 22579200:
+	case 33868800:
+		wm8741->sysclk_constraints = &constraints_22579;
+		break;
+	case 24576000:
+		wm8741->sysclk_constraints = &constraints_24576;
+		break;
+	case 36864000:
+		wm8741->sysclk_constraints = &constraints_36864;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8741->sysclk = freq;
+	return 0;
+}
+
+static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	unsigned int iface;
+
+	/* check master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface = 0x08;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		iface = 0x00;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface = 0x04;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface = 0x0C;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface = 0x1C;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x10;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x20;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x30;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+
+	dev_dbg(component->dev, "wm8741_set_dai_fmt:    Format=%x, Clock Inv=%x\n",
+				fmt & SND_SOC_DAIFMT_FORMAT_MASK,
+				((fmt & SND_SOC_DAIFMT_INV_MASK)));
+
+	snd_soc_component_update_bits(component, WM8741_FORMAT_CONTROL,
+			    WM8741_BCP_MASK | WM8741_LRP_MASK | WM8741_FMT_MASK,
+			    iface);
+
+	return 0;
+}
+
+#define WM8741_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+			SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
+			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
+			SNDRV_PCM_RATE_192000)
+
+#define WM8741_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8741_dai_ops = {
+	.startup	= wm8741_startup,
+	.hw_params	= wm8741_hw_params,
+	.set_sysclk	= wm8741_set_dai_sysclk,
+	.set_fmt	= wm8741_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver wm8741_dai = {
+	.name = "wm8741",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM8741_RATES,
+		.formats = WM8741_FORMATS,
+	},
+	.ops = &wm8741_dai_ops,
+};
+
+#ifdef CONFIG_PM
+static int wm8741_resume(struct snd_soc_component *component)
+{
+	snd_soc_component_cache_sync(component);
+	return 0;
+}
+#else
+#define wm8741_resume NULL
+#endif
+
+static int wm8741_configure(struct snd_soc_component *component)
+{
+	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
+
+	/* Configure differential mode */
+	switch (wm8741->pdata.diff_mode) {
+	case WM8741_DIFF_MODE_STEREO:
+	case WM8741_DIFF_MODE_STEREO_REVERSED:
+	case WM8741_DIFF_MODE_MONO_LEFT:
+	case WM8741_DIFF_MODE_MONO_RIGHT:
+		snd_soc_component_update_bits(component, WM8741_MODE_CONTROL_2,
+				WM8741_DIFF_MASK,
+				wm8741->pdata.diff_mode << WM8741_DIFF_SHIFT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Change some default settings - latch VU */
+	snd_soc_component_update_bits(component, WM8741_DACLLSB_ATTENUATION,
+			WM8741_UPDATELL, WM8741_UPDATELL);
+	snd_soc_component_update_bits(component, WM8741_DACLMSB_ATTENUATION,
+			WM8741_UPDATELM, WM8741_UPDATELM);
+	snd_soc_component_update_bits(component, WM8741_DACRLSB_ATTENUATION,
+			WM8741_UPDATERL, WM8741_UPDATERL);
+	snd_soc_component_update_bits(component, WM8741_DACRMSB_ATTENUATION,
+			WM8741_UPDATERM, WM8741_UPDATERM);
+
+	return 0;
+}
+
+static int wm8741_add_controls(struct snd_soc_component *component)
+{
+	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
+
+	switch (wm8741->pdata.diff_mode) {
+	case WM8741_DIFF_MODE_STEREO:
+	case WM8741_DIFF_MODE_STEREO_REVERSED:
+		snd_soc_add_component_controls(component,
+				wm8741_snd_controls_stereo,
+				ARRAY_SIZE(wm8741_snd_controls_stereo));
+		break;
+	case WM8741_DIFF_MODE_MONO_LEFT:
+		snd_soc_add_component_controls(component,
+				wm8741_snd_controls_mono_left,
+				ARRAY_SIZE(wm8741_snd_controls_mono_left));
+		break;
+	case WM8741_DIFF_MODE_MONO_RIGHT:
+		snd_soc_add_component_controls(component,
+				wm8741_snd_controls_mono_right,
+				ARRAY_SIZE(wm8741_snd_controls_mono_right));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8741_probe(struct snd_soc_component *component)
+{
+	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
+				    wm8741->supplies);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
+		goto err_get;
+	}
+
+	ret = wm8741_reset(component);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to issue reset\n");
+		goto err_enable;
+	}
+
+	ret = wm8741_configure(component);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to change default settings\n");
+		goto err_enable;
+	}
+
+	ret = wm8741_add_controls(component);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to add controls\n");
+		goto err_enable;
+	}
+
+	dev_dbg(component->dev, "Successful registration\n");
+	return ret;
+
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
+err_get:
+	return ret;
+}
+
+static void wm8741_remove(struct snd_soc_component *component)
+{
+	struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
+
+	regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8741 = {
+	.probe			= wm8741_probe,
+	.remove			= wm8741_remove,
+	.resume			= wm8741_resume,
+	.dapm_widgets		= wm8741_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8741_dapm_widgets),
+	.dapm_routes		= wm8741_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8741_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct of_device_id wm8741_of_match[] = {
+	{ .compatible = "wlf,wm8741", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wm8741_of_match);
+
+static const struct regmap_config wm8741_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+	.max_register = WM8741_MAX_REGISTER,
+
+	.reg_defaults = wm8741_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741)
+{
+	const struct wm8741_platform_data *pdata = dev_get_platdata(dev);
+	u32 diff_mode;
+
+	if (dev->of_node) {
+		if (of_property_read_u32(dev->of_node, "diff-mode", &diff_mode)
+				>= 0)
+			wm8741->pdata.diff_mode = diff_mode;
+	} else {
+		if (pdata != NULL)
+			memcpy(&wm8741->pdata, pdata, sizeof(wm8741->pdata));
+	}
+
+	return 0;
+}
+
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8741_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8741_priv *wm8741;
+	int ret, i;
+
+	wm8741 = devm_kzalloc(&i2c->dev, sizeof(struct wm8741_priv),
+			      GFP_KERNEL);
+	if (wm8741 == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
+		wm8741->supplies[i].supply = wm8741_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8741->supplies),
+				      wm8741->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	wm8741->regmap = devm_regmap_init_i2c(i2c, &wm8741_regmap);
+	if (IS_ERR(wm8741->regmap)) {
+		ret = PTR_ERR(wm8741->regmap);
+		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = wm8741_set_pdata(&i2c->dev, wm8741);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to set pdata: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, wm8741);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_wm8741, &wm8741_dai, 1);
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8741_i2c_id[] = {
+	{ "wm8741", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
+
+static struct i2c_driver wm8741_i2c_driver = {
+	.driver = {
+		.name = "wm8741",
+		.of_match_table = wm8741_of_match,
+	},
+	.probe =    wm8741_i2c_probe,
+	.id_table = wm8741_i2c_id,
+};
+#endif
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8741_spi_probe(struct spi_device *spi)
+{
+	struct wm8741_priv *wm8741;
+	int ret, i;
+
+	wm8741 = devm_kzalloc(&spi->dev, sizeof(struct wm8741_priv),
+			     GFP_KERNEL);
+	if (wm8741 == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
+		wm8741->supplies[i].supply = wm8741_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8741->supplies),
+				      wm8741->supplies);
+	if (ret != 0) {
+		dev_err(&spi->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	wm8741->regmap = devm_regmap_init_spi(spi, &wm8741_regmap);
+	if (IS_ERR(wm8741->regmap)) {
+		ret = PTR_ERR(wm8741->regmap);
+		dev_err(&spi->dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = wm8741_set_pdata(&spi->dev, wm8741);
+	if (ret != 0) {
+		dev_err(&spi->dev, "Failed to set pdata: %d\n", ret);
+		return ret;
+	}
+
+	spi_set_drvdata(spi, wm8741);
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8741, &wm8741_dai, 1);
+	return ret;
+}
+
+static struct spi_driver wm8741_spi_driver = {
+	.driver = {
+		.name	= "wm8741",
+		.of_match_table = wm8741_of_match,
+	},
+	.probe		= wm8741_spi_probe,
+};
+#endif /* CONFIG_SPI_MASTER */
+
+static int __init wm8741_modinit(void)
+{
+	int ret = 0;
+
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&wm8741_i2c_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM8741 I2C driver: %d\n", ret);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8741_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register wm8741 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+
+	return ret;
+}
+module_init(wm8741_modinit);
+
+static void __exit wm8741_exit(void)
+{
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8741_spi_driver);
+#endif
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&wm8741_i2c_driver);
+#endif
+}
+module_exit(wm8741_exit);
+
+MODULE_DESCRIPTION("ASoC WM8741 driver");
+MODULE_AUTHOR("Ian Lartey <ian@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8741.h b/sound/soc/codecs/wm8741.h
new file mode 100644
index 0000000..c8835f6
--- /dev/null
+++ b/sound/soc/codecs/wm8741.h
@@ -0,0 +1,221 @@
+/*
+ * wm8741.h  --  WM8423 ASoC driver
+ *
+ * Copyright 2010 Wolfson Microelectronics, plc
+ *
+ * Author: Ian Lartey <ian@opensource.wolfsonmicro.com>
+ *
+ * Based on wm8753.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8741_H
+#define _WM8741_H
+
+/*
+ * Register values.
+ */
+#define WM8741_DACLLSB_ATTENUATION              0x00
+#define WM8741_DACLMSB_ATTENUATION              0x01
+#define WM8741_DACRLSB_ATTENUATION              0x02
+#define WM8741_DACRMSB_ATTENUATION              0x03
+#define WM8741_VOLUME_CONTROL                   0x04
+#define WM8741_FORMAT_CONTROL                   0x05
+#define WM8741_FILTER_CONTROL                   0x06
+#define WM8741_MODE_CONTROL_1                   0x07
+#define WM8741_MODE_CONTROL_2                   0x08
+#define WM8741_RESET                            0x09
+#define WM8741_ADDITIONAL_CONTROL_1             0x20
+
+#define WM8741_REGISTER_COUNT                   11
+#define WM8741_MAX_REGISTER                     0x20
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - DACLLSB_ATTENUATION
+ */
+#define WM8741_UPDATELL                         0x0020  /* UPDATELL */
+#define WM8741_UPDATELL_MASK                    0x0020  /* UPDATELL */
+#define WM8741_UPDATELL_SHIFT                        5  /* UPDATELL */
+#define WM8741_UPDATELL_WIDTH                        1  /* UPDATELL */
+#define WM8741_LAT_4_0_MASK                     0x001F  /* LAT[4:0] - [4:0] */
+#define WM8741_LAT_4_0_SHIFT                         0  /* LAT[4:0] - [4:0] */
+#define WM8741_LAT_4_0_WIDTH                         5  /* LAT[4:0] - [4:0] */
+
+/*
+ * R1 (0x01) - DACLMSB_ATTENUATION
+ */
+#define WM8741_UPDATELM                         0x0020  /* UPDATELM */
+#define WM8741_UPDATELM_MASK                    0x0020  /* UPDATELM */
+#define WM8741_UPDATELM_SHIFT                        5  /* UPDATELM */
+#define WM8741_UPDATELM_WIDTH                        1  /* UPDATELM */
+#define WM8741_LAT_9_5_0_MASK                   0x001F  /* LAT[9:5] - [4:0] */
+#define WM8741_LAT_9_5_0_SHIFT                       0  /* LAT[9:5] - [4:0] */
+#define WM8741_LAT_9_5_0_WIDTH                       5  /* LAT[9:5] - [4:0] */
+
+/*
+ * R2 (0x02) - DACRLSB_ATTENUATION
+ */
+#define WM8741_UPDATERL                         0x0020  /* UPDATERL */
+#define WM8741_UPDATERL_MASK                    0x0020  /* UPDATERL */
+#define WM8741_UPDATERL_SHIFT                        5  /* UPDATERL */
+#define WM8741_UPDATERL_WIDTH                        1  /* UPDATERL */
+#define WM8741_RAT_4_0_MASK                     0x001F  /* RAT[4:0] - [4:0] */
+#define WM8741_RAT_4_0_SHIFT                         0  /* RAT[4:0] - [4:0] */
+#define WM8741_RAT_4_0_WIDTH                         5  /* RAT[4:0] - [4:0] */
+
+/*
+ * R3 (0x03) - DACRMSB_ATTENUATION
+ */
+#define WM8741_UPDATERM                         0x0020  /* UPDATERM */
+#define WM8741_UPDATERM_MASK                    0x0020  /* UPDATERM */
+#define WM8741_UPDATERM_SHIFT                        5  /* UPDATERM */
+#define WM8741_UPDATERM_WIDTH                        1  /* UPDATERM */
+#define WM8741_RAT_9_5_0_MASK                   0x001F  /* RAT[9:5] - [4:0] */
+#define WM8741_RAT_9_5_0_SHIFT                       0  /* RAT[9:5] - [4:0] */
+#define WM8741_RAT_9_5_0_WIDTH                       5  /* RAT[9:5] - [4:0] */
+
+/*
+ * R4 (0x04) - VOLUME_CONTROL
+ */
+#define WM8741_AMUTE                            0x0080  /* AMUTE */
+#define WM8741_AMUTE_MASK                       0x0080  /* AMUTE */
+#define WM8741_AMUTE_SHIFT                           7  /* AMUTE */
+#define WM8741_AMUTE_WIDTH                           1  /* AMUTE */
+#define WM8741_ZFLAG_MASK                       0x0060  /* ZFLAG - [6:5] */
+#define WM8741_ZFLAG_SHIFT                           5  /* ZFLAG - [6:5] */
+#define WM8741_ZFLAG_WIDTH                           2  /* ZFLAG - [6:5] */
+#define WM8741_IZD                              0x0010  /* IZD */
+#define WM8741_IZD_MASK                         0x0010  /* IZD */
+#define WM8741_IZD_SHIFT                             4  /* IZD */
+#define WM8741_IZD_WIDTH                             1  /* IZD */
+#define WM8741_SOFT                             0x0008  /* SOFT MUTE */
+#define WM8741_SOFT_MASK                        0x0008  /* SOFT MUTE */
+#define WM8741_SOFT_SHIFT                            3  /* SOFT MUTE */
+#define WM8741_SOFT_WIDTH                            1  /* SOFT MUTE */
+#define WM8741_ATC                              0x0004  /* ATC */
+#define WM8741_ATC_MASK                         0x0004  /* ATC */
+#define WM8741_ATC_SHIFT                             2  /* ATC */
+#define WM8741_ATC_WIDTH                             1  /* ATC */
+#define WM8741_ATT2DB                           0x0002  /* ATT2DB */
+#define WM8741_ATT2DB_MASK                      0x0002  /* ATT2DB */
+#define WM8741_ATT2DB_SHIFT                          1  /* ATT2DB */
+#define WM8741_ATT2DB_WIDTH                          1  /* ATT2DB */
+#define WM8741_VOL_RAMP                         0x0001  /* VOL_RAMP */
+#define WM8741_VOL_RAMP_MASK                    0x0001  /* VOL_RAMP */
+#define WM8741_VOL_RAMP_SHIFT                        0  /* VOL_RAMP */
+#define WM8741_VOL_RAMP_WIDTH                        1  /* VOL_RAMP */
+
+/*
+ * R5 (0x05) - FORMAT_CONTROL
+ */
+#define WM8741_PWDN                             0x0080  /* PWDN */
+#define WM8741_PWDN_MASK                        0x0080  /* PWDN */
+#define WM8741_PWDN_SHIFT                            7  /* PWDN */
+#define WM8741_PWDN_WIDTH                            1  /* PWDN */
+#define WM8741_REV                              0x0040  /* REV */
+#define WM8741_REV_MASK                         0x0040  /* REV */
+#define WM8741_REV_SHIFT                             6  /* REV */
+#define WM8741_REV_WIDTH                             1  /* REV */
+#define WM8741_BCP                              0x0020  /* BCP */
+#define WM8741_BCP_MASK                         0x0020  /* BCP */
+#define WM8741_BCP_SHIFT                             5  /* BCP */
+#define WM8741_BCP_WIDTH                             1  /* BCP */
+#define WM8741_LRP                              0x0010  /* LRP */
+#define WM8741_LRP_MASK                         0x0010  /* LRP */
+#define WM8741_LRP_SHIFT                             4  /* LRP */
+#define WM8741_LRP_WIDTH                             1  /* LRP */
+#define WM8741_FMT_MASK                         0x000C  /* FMT - [3:2] */
+#define WM8741_FMT_SHIFT                             2  /* FMT - [3:2] */
+#define WM8741_FMT_WIDTH                             2  /* FMT - [3:2] */
+#define WM8741_IWL_MASK                         0x0003  /* IWL - [1:0] */
+#define WM8741_IWL_SHIFT                             0  /* IWL - [1:0] */
+#define WM8741_IWL_WIDTH                             2  /* IWL - [1:0] */
+
+/*
+ * R6 (0x06) - FILTER_CONTROL
+ */
+#define WM8741_ZFLAG_HI                         0x0080  /* ZFLAG_HI */
+#define WM8741_ZFLAG_HI_MASK                    0x0080  /* ZFLAG_HI */
+#define WM8741_ZFLAG_HI_SHIFT                        7  /* ZFLAG_HI */
+#define WM8741_ZFLAG_HI_WIDTH                        1  /* ZFLAG_HI */
+#define WM8741_DEEMPH_MASK                      0x0060  /* DEEMPH - [6:5] */
+#define WM8741_DEEMPH_SHIFT                          5  /* DEEMPH - [6:5] */
+#define WM8741_DEEMPH_WIDTH                          2  /* DEEMPH - [6:5] */
+#define WM8741_DSDFILT_MASK                     0x0018  /* DSDFILT - [4:3] */
+#define WM8741_DSDFILT_SHIFT                         3  /* DSDFILT - [4:3] */
+#define WM8741_DSDFILT_WIDTH                         2  /* DSDFILT - [4:3] */
+#define WM8741_FIRSEL_MASK                      0x0007  /* FIRSEL - [2:0] */
+#define WM8741_FIRSEL_SHIFT                          0  /* FIRSEL - [2:0] */
+#define WM8741_FIRSEL_WIDTH                          3  /* FIRSEL - [2:0] */
+
+/*
+ * R7 (0x07) - MODE_CONTROL_1
+ */
+#define WM8741_MODE8X                           0x0080  /* MODE8X */
+#define WM8741_MODE8X_MASK                      0x0080  /* MODE8X */
+#define WM8741_MODE8X_SHIFT                          7  /* MODE8X */
+#define WM8741_MODE8X_WIDTH                          1  /* MODE8X */
+#define WM8741_OSR_MASK                         0x0060  /* OSR - [6:5] */
+#define WM8741_OSR_SHIFT                             5  /* OSR - [6:5] */
+#define WM8741_OSR_WIDTH                             2  /* OSR - [6:5] */
+#define WM8741_SR_MASK                          0x001C  /* SR - [4:2] */
+#define WM8741_SR_SHIFT                              2  /* SR - [4:2] */
+#define WM8741_SR_WIDTH                              3  /* SR - [4:2] */
+#define WM8741_MODESEL_MASK                     0x0003  /* MODESEL - [1:0] */
+#define WM8741_MODESEL_SHIFT                         0  /* MODESEL - [1:0] */
+#define WM8741_MODESEL_WIDTH                         2  /* MODESEL - [1:0] */
+
+/*
+ * R8 (0x08) - MODE_CONTROL_2
+ */
+#define WM8741_DSD_GAIN                         0x0040  /* DSD_GAIN */
+#define WM8741_DSD_GAIN_MASK                    0x0040  /* DSD_GAIN */
+#define WM8741_DSD_GAIN_SHIFT                        6  /* DSD_GAIN */
+#define WM8741_DSD_GAIN_WIDTH                        1  /* DSD_GAIN */
+#define WM8741_SDOUT                            0x0020  /* SDOUT */
+#define WM8741_SDOUT_MASK                       0x0020  /* SDOUT */
+#define WM8741_SDOUT_SHIFT                           5  /* SDOUT */
+#define WM8741_SDOUT_WIDTH                           1  /* SDOUT */
+#define WM8741_DOUT                             0x0010  /* DOUT */
+#define WM8741_DOUT_MASK                        0x0010  /* DOUT */
+#define WM8741_DOUT_SHIFT                            4  /* DOUT */
+#define WM8741_DOUT_WIDTH                            1  /* DOUT */
+#define WM8741_DIFF_MASK                        0x000C  /* DIFF - [3:2] */
+#define WM8741_DIFF_SHIFT                            2  /* DIFF - [3:2] */
+#define WM8741_DIFF_WIDTH                            2  /* DIFF - [3:2] */
+#define WM8741_DITHER_MASK                      0x0003  /* DITHER - [1:0] */
+#define WM8741_DITHER_SHIFT                          0  /* DITHER - [1:0] */
+#define WM8741_DITHER_WIDTH                          2  /* DITHER - [1:0] */
+
+/* DIFF field values */
+#define WM8741_DIFF_MODE_STEREO                      0  /* stereo normal */
+#define WM8741_DIFF_MODE_STEREO_REVERSED             2  /* stereo reversed */
+#define WM8741_DIFF_MODE_MONO_LEFT                   1  /* mono left */
+#define WM8741_DIFF_MODE_MONO_RIGHT                  3  /* mono right */
+
+/*
+ * R32 (0x20) - ADDITONAL_CONTROL_1
+ */
+#define WM8741_DSD_LEVEL                        0x0002  /* DSD_LEVEL */
+#define WM8741_DSD_LEVEL_MASK                   0x0002  /* DSD_LEVEL */
+#define WM8741_DSD_LEVEL_SHIFT                       1  /* DSD_LEVEL */
+#define WM8741_DSD_LEVEL_WIDTH                       1  /* DSD_LEVEL */
+#define WM8741_DSD_NO_NOTCH                     0x0001  /* DSD_NO_NOTCH */
+#define WM8741_DSD_NO_NOTCH_MASK                0x0001  /* DSD_NO_NOTCH */
+#define WM8741_DSD_NO_NOTCH_SHIFT                    0  /* DSD_NO_NOTCH */
+#define WM8741_DSD_NO_NOTCH_WIDTH                    1  /* DSD_NO_NOTCH */
+
+#define  WM8741_SYSCLK 0
+
+struct wm8741_platform_data {
+	u32 diff_mode;   /* Differential Output Mode */
+};
+
+#endif
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
new file mode 100644
index 0000000..97239bc
--- /dev/null
+++ b/sound/soc/codecs/wm8750.c
@@ -0,0 +1,859 @@
+/*
+ * wm8750.c -- WM8750 ALSA SoC audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on WM8753.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include "wm8750.h"
+
+/*
+ * wm8750 register cache
+ * We can't read the WM8750 register space when we
+ * are using 2 wire for device control, so we cache them instead.
+ */
+static const struct reg_default wm8750_reg_defaults[] = {
+	{  0, 0x0097 },
+	{  1, 0x0097 },
+	{  2, 0x0079 },
+	{  3, 0x0079 },
+	{  4, 0x0000 },
+	{  5, 0x0008 },
+	{  6, 0x0000 },
+	{  7, 0x000a },
+	{  8, 0x0000 },
+	{  9, 0x0000 },
+	{ 10, 0x00ff },
+	{ 11, 0x00ff },
+	{ 12, 0x000f },
+	{ 13, 0x000f },
+	{ 14, 0x0000 },
+	{ 15, 0x0000 },
+	{ 16, 0x0000 },
+	{ 17, 0x007b },
+	{ 18, 0x0000 },
+	{ 19, 0x0032 },
+	{ 20, 0x0000 },
+	{ 21, 0x00c3 },
+	{ 22, 0x00c3 },
+	{ 23, 0x00c0 },
+	{ 24, 0x0000 },
+	{ 25, 0x0000 },
+	{ 26, 0x0000 },
+	{ 27, 0x0000 },
+	{ 28, 0x0000 },
+	{ 29, 0x0000 },
+	{ 30, 0x0000 },
+	{ 31, 0x0000 },
+	{ 32, 0x0000 },
+	{ 33, 0x0000 },
+	{ 34, 0x0050 },
+	{ 35, 0x0050 },
+	{ 36, 0x0050 },
+	{ 37, 0x0050 },
+	{ 38, 0x0050 },
+	{ 39, 0x0050 },
+	{ 40, 0x0079 },
+	{ 41, 0x0079 },
+	{ 42, 0x0079 },
+};
+
+/* codec private data */
+struct wm8750_priv {
+	unsigned int sysclk;
+};
+
+#define wm8750_reset(c)	snd_soc_component_write(c, WM8750_RESET, 0)
+
+/*
+ * WM8750 Controls
+ */
+static const char *wm8750_bass[] = {"Linear Control", "Adaptive Boost"};
+static const char *wm8750_bass_filter[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };
+static const char *wm8750_treble[] = {"8kHz", "4kHz"};
+static const char *wm8750_3d_lc[] = {"200Hz", "500Hz"};
+static const char *wm8750_3d_uc[] = {"2.2kHz", "1.5kHz"};
+static const char *wm8750_3d_func[] = {"Capture", "Playback"};
+static const char *wm8750_alc_func[] = {"Off", "Right", "Left", "Stereo"};
+static const char *wm8750_ng_type[] = {"Constant PGA Gain",
+	"Mute ADC Output"};
+static const char *wm8750_line_mux[] = {"Line 1", "Line 2", "Line 3", "PGA",
+	"Differential"};
+static const char *wm8750_pga_sel[] = {"Line 1", "Line 2", "Line 3",
+	"Differential"};
+static const char *wm8750_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut",
+	"ROUT1"};
+static const char *wm8750_diff_sel[] = {"Line 1", "Line 2"};
+static const char *wm8750_adcpol[] = {"Normal", "L Invert", "R Invert",
+	"L + R Invert"};
+static const char *wm8750_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+static const char *wm8750_mono_mux[] = {"Stereo", "Mono (Left)",
+	"Mono (Right)", "Digital Mono"};
+
+static const struct soc_enum wm8750_enum[] = {
+SOC_ENUM_SINGLE(WM8750_BASS, 7, 2, wm8750_bass),
+SOC_ENUM_SINGLE(WM8750_BASS, 6, 2, wm8750_bass_filter),
+SOC_ENUM_SINGLE(WM8750_TREBLE, 6, 2, wm8750_treble),
+SOC_ENUM_SINGLE(WM8750_3D, 5, 2, wm8750_3d_lc),
+SOC_ENUM_SINGLE(WM8750_3D, 6, 2, wm8750_3d_uc),
+SOC_ENUM_SINGLE(WM8750_3D, 7, 2, wm8750_3d_func),
+SOC_ENUM_SINGLE(WM8750_ALC1, 7, 4, wm8750_alc_func),
+SOC_ENUM_SINGLE(WM8750_NGATE, 1, 2, wm8750_ng_type),
+SOC_ENUM_SINGLE(WM8750_LOUTM1, 0, 5, wm8750_line_mux),
+SOC_ENUM_SINGLE(WM8750_ROUTM1, 0, 5, wm8750_line_mux),
+SOC_ENUM_SINGLE(WM8750_LADCIN, 6, 4, wm8750_pga_sel), /* 10 */
+SOC_ENUM_SINGLE(WM8750_RADCIN, 6, 4, wm8750_pga_sel),
+SOC_ENUM_SINGLE(WM8750_ADCTL2, 7, 4, wm8750_out3),
+SOC_ENUM_SINGLE(WM8750_ADCIN, 8, 2, wm8750_diff_sel),
+SOC_ENUM_SINGLE(WM8750_ADCDAC, 5, 4, wm8750_adcpol),
+SOC_ENUM_SINGLE(WM8750_ADCDAC, 1, 4, wm8750_deemph),
+SOC_ENUM_SINGLE(WM8750_ADCIN, 6, 4, wm8750_mono_mux), /* 16 */
+
+};
+
+static const struct snd_kcontrol_new wm8750_snd_controls[] = {
+
+SOC_DOUBLE_R("Capture Volume", WM8750_LINVOL, WM8750_RINVOL, 0, 63, 0),
+SOC_DOUBLE_R("Capture ZC Switch", WM8750_LINVOL, WM8750_RINVOL, 6, 1, 0),
+SOC_DOUBLE_R("Capture Switch", WM8750_LINVOL, WM8750_RINVOL, 7, 1, 1),
+
+SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8750_LOUT1V,
+	WM8750_ROUT1V, 7, 1, 0),
+SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8750_LOUT2V,
+	WM8750_ROUT2V, 7, 1, 0),
+
+SOC_ENUM("Playback De-emphasis", wm8750_enum[15]),
+
+SOC_ENUM("Capture Polarity", wm8750_enum[14]),
+SOC_SINGLE("Playback 6dB Attenuate", WM8750_ADCDAC, 7, 1, 0),
+SOC_SINGLE("Capture 6dB Attenuate", WM8750_ADCDAC, 8, 1, 0),
+
+SOC_DOUBLE_R("PCM Volume", WM8750_LDAC, WM8750_RDAC, 0, 255, 0),
+
+SOC_ENUM("Bass Boost", wm8750_enum[0]),
+SOC_ENUM("Bass Filter", wm8750_enum[1]),
+SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1),
+
+SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 1),
+SOC_ENUM("Treble Cut-off", wm8750_enum[2]),
+
+SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0),
+SOC_SINGLE("3D Volume", WM8750_3D, 1, 15, 0),
+SOC_ENUM("3D Lower Cut-off", wm8750_enum[3]),
+SOC_ENUM("3D Upper Cut-off", wm8750_enum[4]),
+SOC_ENUM("3D Mode", wm8750_enum[5]),
+
+SOC_SINGLE("ALC Capture Target Volume", WM8750_ALC1, 0, 7, 0),
+SOC_SINGLE("ALC Capture Max Volume", WM8750_ALC1, 4, 7, 0),
+SOC_ENUM("ALC Capture Function", wm8750_enum[6]),
+SOC_SINGLE("ALC Capture ZC Switch", WM8750_ALC2, 7, 1, 0),
+SOC_SINGLE("ALC Capture Hold Time", WM8750_ALC2, 0, 15, 0),
+SOC_SINGLE("ALC Capture Decay Time", WM8750_ALC3, 4, 15, 0),
+SOC_SINGLE("ALC Capture Attack Time", WM8750_ALC3, 0, 15, 0),
+SOC_SINGLE("ALC Capture NG Threshold", WM8750_NGATE, 3, 31, 0),
+SOC_ENUM("ALC Capture NG Type", wm8750_enum[4]),
+SOC_SINGLE("ALC Capture NG Switch", WM8750_NGATE, 0, 1, 0),
+
+SOC_SINGLE("Left ADC Capture Volume", WM8750_LADC, 0, 255, 0),
+SOC_SINGLE("Right ADC Capture Volume", WM8750_RADC, 0, 255, 0),
+
+SOC_SINGLE("ZC Timeout Switch", WM8750_ADCTL1, 0, 1, 0),
+SOC_SINGLE("Playback Invert Switch", WM8750_ADCTL1, 1, 1, 0),
+
+SOC_SINGLE("Right Speaker Playback Invert Switch", WM8750_ADCTL2, 4, 1, 0),
+
+/* Unimplemented */
+/* ADCDAC Bit 0 - ADCHPD */
+/* ADCDAC Bit 4 - HPOR */
+/* ADCTL1 Bit 2,3 - DATSEL */
+/* ADCTL1 Bit 4,5 - DMONOMIX */
+/* ADCTL1 Bit 6,7 - VSEL */
+/* ADCTL2 Bit 2 - LRCM */
+/* ADCTL2 Bit 3 - TRI */
+/* ADCTL3 Bit 5 - HPFLREN */
+/* ADCTL3 Bit 6 - VROI */
+/* ADCTL3 Bit 7,8 - ADCLRM */
+/* ADCIN Bit 4 - LDCM */
+/* ADCIN Bit 5 - RDCM */
+
+SOC_DOUBLE_R("Mic Boost", WM8750_LADCIN, WM8750_RADCIN, 4, 3, 0),
+
+SOC_DOUBLE_R("Bypass Left Playback Volume", WM8750_LOUTM1,
+	WM8750_LOUTM2, 4, 7, 1),
+SOC_DOUBLE_R("Bypass Right Playback Volume", WM8750_ROUTM1,
+	WM8750_ROUTM2, 4, 7, 1),
+SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8750_MOUTM1,
+	WM8750_MOUTM2, 4, 7, 1),
+
+SOC_SINGLE("Mono Playback ZC Switch", WM8750_MOUTV, 7, 1, 0),
+
+SOC_DOUBLE_R("Headphone Playback Volume", WM8750_LOUT1V, WM8750_ROUT1V,
+	0, 127, 0),
+SOC_DOUBLE_R("Speaker Playback Volume", WM8750_LOUT2V, WM8750_ROUT2V,
+	0, 127, 0),
+
+SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0),
+
+};
+
+/*
+ * DAPM Controls
+ */
+
+/* Left Mixer */
+static const struct snd_kcontrol_new wm8750_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("Playback Switch", WM8750_LOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_LOUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8750_LOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_LOUTM2, 7, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new wm8750_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8750_ROUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_ROUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Playback Switch", WM8750_ROUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_ROUTM2, 7, 1, 0),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new wm8750_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8750_MOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_MOUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8750_MOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_MOUTM2, 7, 1, 0),
+};
+
+/* Left Line Mux */
+static const struct snd_kcontrol_new wm8750_left_line_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[8]);
+
+/* Right Line Mux */
+static const struct snd_kcontrol_new wm8750_right_line_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[9]);
+
+/* Left PGA Mux */
+static const struct snd_kcontrol_new wm8750_left_pga_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[10]);
+
+/* Right PGA Mux */
+static const struct snd_kcontrol_new wm8750_right_pga_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[11]);
+
+/* Out 3 Mux */
+static const struct snd_kcontrol_new wm8750_out3_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[12]);
+
+/* Differential Mux */
+static const struct snd_kcontrol_new wm8750_diffmux_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[13]);
+
+/* Mono ADC Mux */
+static const struct snd_kcontrol_new wm8750_monomux_controls =
+SOC_DAPM_ENUM("Route", wm8750_enum[16]);
+
+static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+		&wm8750_left_mixer_controls[0],
+		ARRAY_SIZE(wm8750_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+		&wm8750_right_mixer_controls[0],
+		ARRAY_SIZE(wm8750_right_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono Mixer", WM8750_PWR2, 2, 0,
+		&wm8750_mono_mixer_controls[0],
+		ARRAY_SIZE(wm8750_mono_mixer_controls)),
+
+	SND_SOC_DAPM_PGA("Right Out 2", WM8750_PWR2, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 2", WM8750_PWR2, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Out 1", WM8750_PWR2, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 1", WM8750_PWR2, 6, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8750_PWR2, 7, 0),
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8750_PWR2, 8, 0),
+
+	SND_SOC_DAPM_MICBIAS("Mic Bias", WM8750_PWR1, 1, 0),
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8750_PWR1, 2, 0),
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8750_PWR1, 3, 0),
+
+	SND_SOC_DAPM_MUX("Left PGA Mux", WM8750_PWR1, 5, 0,
+		&wm8750_left_pga_controls),
+	SND_SOC_DAPM_MUX("Right PGA Mux", WM8750_PWR1, 4, 0,
+		&wm8750_right_pga_controls),
+	SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
+		&wm8750_left_line_controls),
+	SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
+		&wm8750_right_line_controls),
+
+	SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8750_out3_controls),
+	SND_SOC_DAPM_PGA("Out 3", WM8750_PWR2, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono Out 1", WM8750_PWR2, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+		&wm8750_diffmux_controls),
+	SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
+		&wm8750_monomux_controls),
+	SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
+		&wm8750_monomux_controls),
+
+	SND_SOC_DAPM_OUTPUT("LOUT1"),
+	SND_SOC_DAPM_OUTPUT("ROUT1"),
+	SND_SOC_DAPM_OUTPUT("LOUT2"),
+	SND_SOC_DAPM_OUTPUT("ROUT2"),
+	SND_SOC_DAPM_OUTPUT("MONO1"),
+	SND_SOC_DAPM_OUTPUT("OUT3"),
+	SND_SOC_DAPM_VMID("VREF"),
+
+	SND_SOC_DAPM_INPUT("LINPUT1"),
+	SND_SOC_DAPM_INPUT("LINPUT2"),
+	SND_SOC_DAPM_INPUT("LINPUT3"),
+	SND_SOC_DAPM_INPUT("RINPUT1"),
+	SND_SOC_DAPM_INPUT("RINPUT2"),
+	SND_SOC_DAPM_INPUT("RINPUT3"),
+};
+
+static const struct snd_soc_dapm_route wm8750_dapm_routes[] = {
+	/* left mixer */
+	{"Left Mixer", "Playback Switch", "Left DAC"},
+	{"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Left Mixer", "Right Playback Switch", "Right DAC"},
+	{"Left Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+	/* right mixer */
+	{"Right Mixer", "Left Playback Switch", "Left DAC"},
+	{"Right Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Right Mixer", "Playback Switch", "Right DAC"},
+	{"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+	/* left out 1 */
+	{"Left Out 1", NULL, "Left Mixer"},
+	{"LOUT1", NULL, "Left Out 1"},
+
+	/* left out 2 */
+	{"Left Out 2", NULL, "Left Mixer"},
+	{"LOUT2", NULL, "Left Out 2"},
+
+	/* right out 1 */
+	{"Right Out 1", NULL, "Right Mixer"},
+	{"ROUT1", NULL, "Right Out 1"},
+
+	/* right out 2 */
+	{"Right Out 2", NULL, "Right Mixer"},
+	{"ROUT2", NULL, "Right Out 2"},
+
+	/* mono mixer */
+	{"Mono Mixer", "Left Playback Switch", "Left DAC"},
+	{"Mono Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Mono Mixer", "Right Playback Switch", "Right DAC"},
+	{"Mono Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+	/* mono out */
+	{"Mono Out 1", NULL, "Mono Mixer"},
+	{"MONO1", NULL, "Mono Out 1"},
+
+	/* out 3 */
+	{"Out3 Mux", "VREF", "VREF"},
+	{"Out3 Mux", "ROUT1 + Vol", "ROUT1"},
+	{"Out3 Mux", "ROUT1", "Right Mixer"},
+	{"Out3 Mux", "MonoOut", "MONO1"},
+	{"Out 3", NULL, "Out3 Mux"},
+	{"OUT3", NULL, "Out 3"},
+
+	/* Left Line Mux */
+	{"Left Line Mux", "Line 1", "LINPUT1"},
+	{"Left Line Mux", "Line 2", "LINPUT2"},
+	{"Left Line Mux", "Line 3", "LINPUT3"},
+	{"Left Line Mux", "PGA", "Left PGA Mux"},
+	{"Left Line Mux", "Differential", "Differential Mux"},
+
+	/* Right Line Mux */
+	{"Right Line Mux", "Line 1", "RINPUT1"},
+	{"Right Line Mux", "Line 2", "RINPUT2"},
+	{"Right Line Mux", "Line 3", "RINPUT3"},
+	{"Right Line Mux", "PGA", "Right PGA Mux"},
+	{"Right Line Mux", "Differential", "Differential Mux"},
+
+	/* Left PGA Mux */
+	{"Left PGA Mux", "Line 1", "LINPUT1"},
+	{"Left PGA Mux", "Line 2", "LINPUT2"},
+	{"Left PGA Mux", "Line 3", "LINPUT3"},
+	{"Left PGA Mux", "Differential", "Differential Mux"},
+
+	/* Right PGA Mux */
+	{"Right PGA Mux", "Line 1", "RINPUT1"},
+	{"Right PGA Mux", "Line 2", "RINPUT2"},
+	{"Right PGA Mux", "Line 3", "RINPUT3"},
+	{"Right PGA Mux", "Differential", "Differential Mux"},
+
+	/* Differential Mux */
+	{"Differential Mux", "Line 1", "LINPUT1"},
+	{"Differential Mux", "Line 1", "RINPUT1"},
+	{"Differential Mux", "Line 2", "LINPUT2"},
+	{"Differential Mux", "Line 2", "RINPUT2"},
+
+	/* Left ADC Mux */
+	{"Left ADC Mux", "Stereo", "Left PGA Mux"},
+	{"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
+	{"Left ADC Mux", "Digital Mono", "Left PGA Mux"},
+
+	/* Right ADC Mux */
+	{"Right ADC Mux", "Stereo", "Right PGA Mux"},
+	{"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
+	{"Right ADC Mux", "Digital Mono", "Right PGA Mux"},
+
+	/* ADC */
+	{"Left ADC", NULL, "Left ADC Mux"},
+	{"Right ADC", NULL, "Right ADC Mux"},
+};
+
+struct _coeff_div {
+	u32 mclk;
+	u32 rate;
+	u16 fs;
+	u8 sr:5;
+	u8 usb:1;
+};
+
+/* codec hifi mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	/* 8k */
+	{12288000, 8000, 1536, 0x6, 0x0},
+	{11289600, 8000, 1408, 0x16, 0x0},
+	{18432000, 8000, 2304, 0x7, 0x0},
+	{16934400, 8000, 2112, 0x17, 0x0},
+	{12000000, 8000, 1500, 0x6, 0x1},
+
+	/* 11.025k */
+	{11289600, 11025, 1024, 0x18, 0x0},
+	{16934400, 11025, 1536, 0x19, 0x0},
+	{12000000, 11025, 1088, 0x19, 0x1},
+
+	/* 16k */
+	{12288000, 16000, 768, 0xa, 0x0},
+	{18432000, 16000, 1152, 0xb, 0x0},
+	{12000000, 16000, 750, 0xa, 0x1},
+
+	/* 22.05k */
+	{11289600, 22050, 512, 0x1a, 0x0},
+	{16934400, 22050, 768, 0x1b, 0x0},
+	{12000000, 22050, 544, 0x1b, 0x1},
+
+	/* 32k */
+	{12288000, 32000, 384, 0xc, 0x0},
+	{18432000, 32000, 576, 0xd, 0x0},
+	{12000000, 32000, 375, 0xa, 0x1},
+
+	/* 44.1k */
+	{11289600, 44100, 256, 0x10, 0x0},
+	{16934400, 44100, 384, 0x11, 0x0},
+	{12000000, 44100, 272, 0x11, 0x1},
+
+	/* 48k */
+	{12288000, 48000, 256, 0x0, 0x0},
+	{18432000, 48000, 384, 0x1, 0x0},
+	{12000000, 48000, 250, 0x0, 0x1},
+
+	/* 88.2k */
+	{11289600, 88200, 128, 0x1e, 0x0},
+	{16934400, 88200, 192, 0x1f, 0x0},
+	{12000000, 88200, 136, 0x1f, 0x1},
+
+	/* 96k */
+	{12288000, 96000, 128, 0xe, 0x0},
+	{18432000, 96000, 192, 0xf, 0x0},
+	{12000000, 96000, 125, 0xe, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+
+	printk(KERN_ERR "wm8750: could not get coeff for mclk %d @ rate %d\n",
+		mclk, rate);
+	return -EINVAL;
+}
+
+static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8750_priv *wm8750 = snd_soc_component_get_drvdata(component);
+
+	switch (freq) {
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 16934400:
+	case 18432000:
+		wm8750->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface = 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8750_IFACE, iface);
+	return 0;
+}
+
+static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8750_priv *wm8750 = snd_soc_component_get_drvdata(component);
+	u16 iface = snd_soc_component_read32(component, WM8750_IFACE) & 0x1f3;
+	u16 srate = snd_soc_component_read32(component, WM8750_SRATE) & 0x1c0;
+	int coeff = get_coeff(wm8750->sysclk, params_rate(params));
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		iface |= 0x0004;
+		break;
+	case 24:
+		iface |= 0x0008;
+		break;
+	case 32:
+		iface |= 0x000c;
+		break;
+	}
+
+	/* set iface & srate */
+	snd_soc_component_write(component, WM8750_IFACE, iface);
+	if (coeff >= 0)
+		snd_soc_component_write(component, WM8750_SRATE, srate |
+			(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
+
+	return 0;
+}
+
+static int wm8750_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8750_ADCDAC) & 0xfff7;
+
+	if (mute)
+		snd_soc_component_write(component, WM8750_ADCDAC, mute_reg | 0x8);
+	else
+		snd_soc_component_write(component, WM8750_ADCDAC, mute_reg);
+	return 0;
+}
+
+static int wm8750_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	u16 pwr_reg = snd_soc_component_read32(component, WM8750_PWR1) & 0xfe3e;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* set vmid to 50k and unmute dac */
+		snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x00c0);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_cache_sync(component);
+
+			/* Set VMID to 5k */
+			snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x01c1);
+
+			/* ...and ramp */
+			msleep(1000);
+		}
+
+		/* mute dac and set vmid to 500k, enable VREF */
+		snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x0141);
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_write(component, WM8750_PWR1, 0x0001);
+		break;
+	}
+	return 0;
+}
+
+#define WM8750_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+	SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops wm8750_dai_ops = {
+	.hw_params	= wm8750_pcm_hw_params,
+	.digital_mute	= wm8750_mute,
+	.set_fmt	= wm8750_set_dai_fmt,
+	.set_sysclk	= wm8750_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8750_dai = {
+	.name = "wm8750-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8750_RATES,
+		.formats = WM8750_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8750_RATES,
+		.formats = WM8750_FORMATS,},
+	.ops = &wm8750_dai_ops,
+};
+
+static int wm8750_probe(struct snd_soc_component *component)
+{
+	int ret;
+
+	ret = wm8750_reset(component);
+	if (ret < 0) {
+		printk(KERN_ERR "wm8750: failed to reset: %d\n", ret);
+		return ret;
+	}
+
+	/* set the update bits */
+	snd_soc_component_update_bits(component, WM8750_LDAC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_RDAC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_LOUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_ROUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_LOUT2V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_ROUT2V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_LINVOL, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8750_RINVOL, 0x0100, 0x0100);
+
+	return ret;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8750 = {
+	.probe			= wm8750_probe,
+	.set_bias_level		= wm8750_set_bias_level,
+	.controls		= wm8750_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8750_snd_controls),
+	.dapm_widgets		= wm8750_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8750_dapm_widgets),
+	.dapm_routes		= wm8750_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8750_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct of_device_id wm8750_of_match[] = {
+	{ .compatible = "wlf,wm8750", },
+	{ .compatible = "wlf,wm8987", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wm8750_of_match);
+
+static const struct regmap_config wm8750_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+	.max_register = WM8750_MOUTV,
+
+	.reg_defaults = wm8750_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8750_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8750_spi_probe(struct spi_device *spi)
+{
+	struct wm8750_priv *wm8750;
+	struct regmap *regmap;
+	int ret;
+
+	wm8750 = devm_kzalloc(&spi->dev, sizeof(struct wm8750_priv),
+			      GFP_KERNEL);
+	if (wm8750 == NULL)
+		return -ENOMEM;
+
+	regmap = devm_regmap_init_spi(spi, &wm8750_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	spi_set_drvdata(spi, wm8750);
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8750, &wm8750_dai, 1);
+	return ret;
+}
+
+static const struct spi_device_id wm8750_spi_ids[] = {
+	{ "wm8750", 0 },
+	{ "wm8987", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, wm8750_spi_ids);
+
+static struct spi_driver wm8750_spi_driver = {
+	.driver = {
+		.name	= "wm8750",
+		.of_match_table = wm8750_of_match,
+	},
+	.id_table	= wm8750_spi_ids,
+	.probe		= wm8750_spi_probe,
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8750_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8750_priv *wm8750;
+	struct regmap *regmap;
+	int ret;
+
+	wm8750 = devm_kzalloc(&i2c->dev, sizeof(struct wm8750_priv),
+			      GFP_KERNEL);
+	if (wm8750 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, wm8750);
+
+	regmap = devm_regmap_init_i2c(i2c, &wm8750_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8750, &wm8750_dai, 1);
+	return ret;
+}
+
+static const struct i2c_device_id wm8750_i2c_id[] = {
+	{ "wm8750", 0 },
+	{ "wm8987", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
+
+static struct i2c_driver wm8750_i2c_driver = {
+	.driver = {
+		.name = "wm8750",
+		.of_match_table = wm8750_of_match,
+	},
+	.probe =    wm8750_i2c_probe,
+	.id_table = wm8750_i2c_id,
+};
+#endif
+
+static int __init wm8750_modinit(void)
+{
+	int ret = 0;
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&wm8750_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register wm8750 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8750_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register wm8750 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return ret;
+}
+module_init(wm8750_modinit);
+
+static void __exit wm8750_exit(void)
+{
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&wm8750_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8750_spi_driver);
+#endif
+}
+module_exit(wm8750_exit);
+
+MODULE_DESCRIPTION("ASoC WM8750 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h
new file mode 100644
index 0000000..121427c
--- /dev/null
+++ b/sound/soc/codecs/wm8750.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on WM8753.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _WM8750_H
+#define _WM8750_H
+
+/* WM8750 register space */
+
+#define WM8750_LINVOL    0x00
+#define WM8750_RINVOL    0x01
+#define WM8750_LOUT1V    0x02
+#define WM8750_ROUT1V    0x03
+#define WM8750_ADCDAC    0x05
+#define WM8750_IFACE     0x07
+#define WM8750_SRATE     0x08
+#define WM8750_LDAC      0x0a
+#define WM8750_RDAC      0x0b
+#define WM8750_BASS      0x0c
+#define WM8750_TREBLE    0x0d
+#define WM8750_RESET     0x0f
+#define WM8750_3D        0x10
+#define WM8750_ALC1      0x11
+#define WM8750_ALC2      0x12
+#define WM8750_ALC3      0x13
+#define WM8750_NGATE     0x14
+#define WM8750_LADC      0x15
+#define WM8750_RADC      0x16
+#define WM8750_ADCTL1    0x17
+#define WM8750_ADCTL2    0x18
+#define WM8750_PWR1      0x19
+#define WM8750_PWR2      0x1a
+#define WM8750_ADCTL3    0x1b
+#define WM8750_ADCIN     0x1f
+#define WM8750_LADCIN    0x20
+#define WM8750_RADCIN    0x21
+#define WM8750_LOUTM1    0x22
+#define WM8750_LOUTM2    0x23
+#define WM8750_ROUTM1    0x24
+#define WM8750_ROUTM2    0x25
+#define WM8750_MOUTM1    0x26
+#define WM8750_MOUTM2    0x27
+#define WM8750_LOUT2V    0x28
+#define WM8750_ROUT2V    0x29
+#define WM8750_MOUTV     0x2a
+
+#define WM8750_CACHE_REGNUM 0x2a
+
+#define WM8750_SYSCLK	0
+
+#endif
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
new file mode 100644
index 0000000..1e2823e
--- /dev/null
+++ b/sound/soc/codecs/wm8753.c
@@ -0,0 +1,1635 @@
+/*
+ * wm8753.c  --  WM8753 ALSA Soc Audio driver
+ *
+ * Copyright 2003-11 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ *  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.
+ *
+ * Notes:
+ *  The WM8753 is a low power, high quality stereo codec with integrated PCM
+ *  codec designed for portable digital telephony applications.
+ *
+ * Dual DAI:-
+ *
+ * This driver support 2 DAI PCM's. This makes the default PCM available for
+ * HiFi audio (e.g. MP3, ogg) playback/capture and the other PCM available for
+ * voice.
+ *
+ * Please note that the voice PCM can be connected directly to a Bluetooth
+ * codec or GSM modem and thus cannot be read or written to, although it is
+ * available to be configured with snd_hw_params(), etc and kcontrols in the
+ * normal alsa manner.
+ *
+ * Fast DAI switching:-
+ *
+ * The driver can now fast switch between the DAI configurations via a
+ * an alsa kcontrol. This allows the PCM to remain open.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+
+#include "wm8753.h"
+
+static int caps_charge = 2000;
+module_param(caps_charge, int, 0);
+MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
+
+static int wm8753_hifi_write_dai_fmt(struct snd_soc_component *component,
+		unsigned int fmt);
+static int wm8753_voice_write_dai_fmt(struct snd_soc_component *component,
+		unsigned int fmt);
+
+/*
+ * wm8753 register cache
+ * We can't read the WM8753 register space when we
+ * are using 2 wire for device control, so we cache them instead.
+ */
+static const struct reg_default wm8753_reg_defaults[] = {
+	{ 0x00, 0x0000 },
+	{ 0x01, 0x0008 },
+	{ 0x02, 0x0000 },
+	{ 0x03, 0x000a },
+	{ 0x04, 0x000a },
+	{ 0x05, 0x0033 },
+	{ 0x06, 0x0000 },
+	{ 0x07, 0x0007 },
+	{ 0x08, 0x00ff },
+	{ 0x09, 0x00ff },
+	{ 0x0a, 0x000f },
+	{ 0x0b, 0x000f },
+	{ 0x0c, 0x007b },
+	{ 0x0d, 0x0000 },
+	{ 0x0e, 0x0032 },
+	{ 0x0f, 0x0000 },
+	{ 0x10, 0x00c3 },
+	{ 0x11, 0x00c3 },
+	{ 0x12, 0x00c0 },
+	{ 0x13, 0x0000 },
+	{ 0x14, 0x0000 },
+	{ 0x15, 0x0000 },
+	{ 0x16, 0x0000 },
+	{ 0x17, 0x0000 },
+	{ 0x18, 0x0000 },
+	{ 0x19, 0x0000 },
+	{ 0x1a, 0x0000 },
+	{ 0x1b, 0x0000 },
+	{ 0x1c, 0x0000 },
+	{ 0x1d, 0x0000 },
+	{ 0x1e, 0x0000 },
+	{ 0x1f, 0x0000 },
+	{ 0x20, 0x0055 },
+	{ 0x21, 0x0005 },
+	{ 0x22, 0x0050 },
+	{ 0x23, 0x0055 },
+	{ 0x24, 0x0050 },
+	{ 0x25, 0x0055 },
+	{ 0x26, 0x0050 },
+	{ 0x27, 0x0055 },
+	{ 0x28, 0x0079 },
+	{ 0x29, 0x0079 },
+	{ 0x2a, 0x0079 },
+	{ 0x2b, 0x0079 },
+	{ 0x2c, 0x0079 },
+	{ 0x2d, 0x0000 },
+	{ 0x2e, 0x0000 },
+	{ 0x2f, 0x0000 },
+	{ 0x30, 0x0000 },
+	{ 0x31, 0x0097 },
+	{ 0x32, 0x0097 },
+	{ 0x33, 0x0000 },
+	{ 0x34, 0x0004 },
+	{ 0x35, 0x0000 },
+	{ 0x36, 0x0083 },
+	{ 0x37, 0x0024 },
+	{ 0x38, 0x01ba },
+	{ 0x39, 0x0000 },
+	{ 0x3a, 0x0083 },
+	{ 0x3b, 0x0024 },
+	{ 0x3c, 0x01ba },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x0000 },
+	{ 0x3f, 0x0000 },
+};
+
+static bool wm8753_volatile(struct device *dev, unsigned int reg)
+{
+	return reg == WM8753_RESET;
+}
+
+/* codec private data */
+struct wm8753_priv {
+	struct regmap *regmap;
+	unsigned int sysclk;
+	unsigned int pcmclk;
+
+	unsigned int voice_fmt;
+	unsigned int hifi_fmt;
+
+	int dai_func;
+	struct delayed_work charge_work;
+};
+
+#define wm8753_reset(c) snd_soc_component_write(c, WM8753_RESET, 0)
+
+/*
+ * WM8753 Controls
+ */
+static const char *wm8753_base[] = {"Linear Control", "Adaptive Boost"};
+static const char *wm8753_base_filter[] =
+	{"130Hz @ 48kHz", "200Hz @ 48kHz", "100Hz @ 16kHz", "400Hz @ 48kHz",
+	"100Hz @ 8kHz", "200Hz @ 8kHz"};
+static const char *wm8753_treble[] = {"8kHz", "4kHz"};
+static const char *wm8753_alc_func[] = {"Off", "Right", "Left", "Stereo"};
+static const char *wm8753_ng_type[] = {"Constant PGA Gain", "Mute ADC Output"};
+static const char *wm8753_3d_func[] = {"Capture", "Playback"};
+static const char *wm8753_3d_uc[] = {"2.2kHz", "1.5kHz"};
+static const char *wm8753_3d_lc[] = {"200Hz", "500Hz"};
+static const char *wm8753_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz"};
+static const char *wm8753_mono_mix[] = {"Stereo", "Left", "Right", "Mono"};
+static const char *wm8753_dac_phase[] = {"Non Inverted", "Inverted"};
+static const char *wm8753_line_mix[] = {"Line 1 + 2", "Line 1 - 2",
+	"Line 1", "Line 2"};
+static const char *wm8753_mono_mux[] = {"Line Mix", "Rx Mix"};
+static const char *wm8753_right_mux[] = {"Line 2", "Rx Mix"};
+static const char *wm8753_left_mux[] = {"Line 1", "Rx Mix"};
+static const char *wm8753_rxmsel[] = {"RXP - RXN", "RXP + RXN", "RXP", "RXN"};
+static const char *wm8753_sidetone_mux[] = {"Left PGA", "Mic 1", "Mic 2",
+	"Right PGA"};
+static const char *wm8753_mono2_src[] = {"Inverted Mono 1", "Left", "Right",
+	"Left + Right"};
+static const char *wm8753_out3[] = {"VREF", "ROUT2", "Left + Right"};
+static const char *wm8753_out4[] = {"VREF", "Capture ST", "LOUT2"};
+static const char *wm8753_radcsel[] = {"PGA", "Line or RXP-RXN", "Sidetone"};
+static const char *wm8753_ladcsel[] = {"PGA", "Line or RXP-RXN", "Line"};
+static const char *wm8753_mono_adc[] = {"Stereo", "Analogue Mix Left",
+	"Analogue Mix Right", "Digital Mono Mix"};
+static const char *wm8753_adc_hp[] = {"3.4Hz @ 48kHz", "82Hz @ 16k",
+	"82Hz @ 8kHz", "170Hz @ 8kHz"};
+static const char *wm8753_adc_filter[] = {"HiFi", "Voice"};
+static const char *wm8753_mic_sel[] = {"Mic 1", "Mic 2", "Mic 3"};
+static const char *wm8753_dai_mode[] = {"DAI 0", "DAI 1", "DAI 2", "DAI 3"};
+static const char *wm8753_dat_sel[] = {"Stereo", "Left ADC", "Right ADC",
+	"Channel Swap"};
+static const char *wm8753_rout2_phase[] = {"Non Inverted", "Inverted"};
+
+static const struct soc_enum wm8753_enum[] = {
+SOC_ENUM_SINGLE(WM8753_BASS, 7, 2, wm8753_base),
+SOC_ENUM_SINGLE(WM8753_BASS, 4, 6, wm8753_base_filter),
+SOC_ENUM_SINGLE(WM8753_TREBLE, 6, 2, wm8753_treble),
+SOC_ENUM_SINGLE(WM8753_ALC1, 7, 4, wm8753_alc_func),
+SOC_ENUM_SINGLE(WM8753_NGATE, 1, 2, wm8753_ng_type),
+SOC_ENUM_SINGLE(WM8753_3D, 7, 2, wm8753_3d_func),
+SOC_ENUM_SINGLE(WM8753_3D, 6, 2, wm8753_3d_uc),
+SOC_ENUM_SINGLE(WM8753_3D, 5, 2, wm8753_3d_lc),
+SOC_ENUM_SINGLE(WM8753_DAC, 1, 4, wm8753_deemp),
+SOC_ENUM_SINGLE(WM8753_DAC, 4, 4, wm8753_mono_mix),
+SOC_ENUM_SINGLE(WM8753_DAC, 6, 2, wm8753_dac_phase),
+SOC_ENUM_SINGLE(WM8753_INCTL1, 3, 4, wm8753_line_mix),
+SOC_ENUM_SINGLE(WM8753_INCTL1, 2, 2, wm8753_mono_mux),
+SOC_ENUM_SINGLE(WM8753_INCTL1, 1, 2, wm8753_right_mux),
+SOC_ENUM_SINGLE(WM8753_INCTL1, 0, 2, wm8753_left_mux),
+SOC_ENUM_SINGLE(WM8753_INCTL2, 6, 4, wm8753_rxmsel),
+SOC_ENUM_SINGLE(WM8753_INCTL2, 4, 4, wm8753_sidetone_mux),
+SOC_ENUM_SINGLE(WM8753_OUTCTL, 7, 4, wm8753_mono2_src),
+SOC_ENUM_SINGLE(WM8753_OUTCTL, 0, 3, wm8753_out3),
+SOC_ENUM_SINGLE(WM8753_ADCTL2, 7, 3, wm8753_out4),
+SOC_ENUM_SINGLE(WM8753_ADCIN, 2, 3, wm8753_radcsel),
+SOC_ENUM_SINGLE(WM8753_ADCIN, 0, 3, wm8753_ladcsel),
+SOC_ENUM_SINGLE(WM8753_ADCIN, 4, 4, wm8753_mono_adc),
+SOC_ENUM_SINGLE(WM8753_ADC, 2, 4, wm8753_adc_hp),
+SOC_ENUM_SINGLE(WM8753_ADC, 4, 2, wm8753_adc_filter),
+SOC_ENUM_SINGLE(WM8753_MICBIAS, 6, 3, wm8753_mic_sel),
+SOC_ENUM_SINGLE(WM8753_IOCTL, 2, 4, wm8753_dai_mode),
+SOC_ENUM_SINGLE(WM8753_ADC, 7, 4, wm8753_dat_sel),
+SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase),
+};
+
+
+static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.enumerated.item[0] = wm8753->dai_func;
+	return 0;
+}
+
+static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+	u16 ioctl;
+
+	if (wm8753->dai_func == ucontrol->value.enumerated.item[0])
+		return 0;
+
+	if (snd_soc_component_is_active(component))
+		return -EBUSY;
+
+	ioctl = snd_soc_component_read32(component, WM8753_IOCTL);
+
+	wm8753->dai_func = ucontrol->value.enumerated.item[0];
+
+	if (((ioctl >> 2) & 0x3) == wm8753->dai_func)
+		return 1;
+
+	ioctl = (ioctl & 0x1f3) | (wm8753->dai_func << 2);
+	snd_soc_component_write(component, WM8753_IOCTL, ioctl);
+
+
+	wm8753_hifi_write_dai_fmt(component, wm8753->hifi_fmt);
+	wm8753_voice_write_dai_fmt(component, wm8753->voice_fmt);
+
+	return 1;
+}
+
+static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(mic_preamp_tlv, 1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_RANGE(out_tlv,
+	/* 0000000 - 0101111 = "Analogue mute" */
+	0, 48, TLV_DB_SCALE_ITEM(-25500, 0, 0),
+	48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0)
+);
+static const DECLARE_TLV_DB_SCALE(mix_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(voice_mix_tlv, -1200, 300, 0);
+static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);
+
+static const struct snd_kcontrol_new wm8753_snd_controls[] = {
+SOC_SINGLE("Hi-Fi DAC Left/Right channel Swap", WM8753_HIFI, 5, 1, 0),
+SOC_DOUBLE_R_TLV("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0, dac_tlv),
+
+SOC_DOUBLE_R_TLV("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0,
+		 adc_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V,
+		 0, 127, 0, out_tlv),
+SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0,
+		 127, 0, out_tlv),
+
+SOC_SINGLE_TLV("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0, out_tlv),
+
+SOC_DOUBLE_R_TLV("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7,
+		 1, mix_tlv),
+SOC_DOUBLE_R_TLV("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4,
+		 7, 1, mix_tlv),
+SOC_DOUBLE_R_TLV("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7,
+		 1, voice_mix_tlv),
+
+SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7,
+	     1, 0),
+SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7,
+	     1, 0),
+
+SOC_SINGLE_TLV("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1, mix_tlv),
+SOC_SINGLE_TLV("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1,
+	       mix_tlv),
+SOC_SINGLE_TLV("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1,
+	       voice_mix_tlv),
+SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0),
+
+SOC_ENUM("Bass Boost", wm8753_enum[0]),
+SOC_ENUM("Bass Filter", wm8753_enum[1]),
+SOC_SINGLE("Bass Volume", WM8753_BASS, 0, 15, 1),
+
+SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1),
+SOC_ENUM("Treble Cut-off", wm8753_enum[2]),
+
+SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1,
+	       rec_mix_tlv),
+SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1,
+	       rec_mix_tlv),
+
+SOC_DOUBLE_R_TLV("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0,
+		 pga_tlv),
+SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0),
+SOC_DOUBLE_R("Capture Switch", WM8753_LINVOL, WM8753_RINVOL, 7, 1, 1),
+
+SOC_ENUM("Capture Filter Select", wm8753_enum[23]),
+SOC_ENUM("Capture Filter Cut-off", wm8753_enum[24]),
+SOC_SINGLE("Capture Filter Switch", WM8753_ADC, 0, 1, 1),
+
+SOC_SINGLE("ALC Capture Target Volume", WM8753_ALC1, 0, 7, 0),
+SOC_SINGLE("ALC Capture Max Volume", WM8753_ALC1, 4, 7, 0),
+SOC_ENUM("ALC Capture Function", wm8753_enum[3]),
+SOC_SINGLE("ALC Capture ZC Switch", WM8753_ALC2, 8, 1, 0),
+SOC_SINGLE("ALC Capture Hold Time", WM8753_ALC2, 0, 15, 1),
+SOC_SINGLE("ALC Capture Decay Time", WM8753_ALC3, 4, 15, 1),
+SOC_SINGLE("ALC Capture Attack Time", WM8753_ALC3, 0, 15, 0),
+SOC_SINGLE("ALC Capture NG Threshold", WM8753_NGATE, 3, 31, 0),
+SOC_ENUM("ALC Capture NG Type", wm8753_enum[4]),
+SOC_SINGLE("ALC Capture NG Switch", WM8753_NGATE, 0, 1, 0),
+
+SOC_ENUM("3D Function", wm8753_enum[5]),
+SOC_ENUM("3D Upper Cut-off", wm8753_enum[6]),
+SOC_ENUM("3D Lower Cut-off", wm8753_enum[7]),
+SOC_SINGLE("3D Volume", WM8753_3D, 1, 15, 0),
+SOC_SINGLE("3D Switch", WM8753_3D, 0, 1, 0),
+
+SOC_SINGLE("Capture 6dB Attenuate", WM8753_ADCTL1, 2, 1, 0),
+SOC_SINGLE("Playback 6dB Attenuate", WM8753_ADCTL1, 1, 1, 0),
+
+SOC_ENUM("De-emphasis", wm8753_enum[8]),
+SOC_ENUM("Playback Mono Mix", wm8753_enum[9]),
+SOC_ENUM("Playback Phase", wm8753_enum[10]),
+
+SOC_SINGLE_TLV("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0, mic_preamp_tlv),
+SOC_SINGLE_TLV("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0, mic_preamp_tlv),
+
+SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai),
+
+SOC_ENUM("ADC Data Select", wm8753_enum[27]),
+SOC_ENUM("ROUT2 Phase", wm8753_enum[28]),
+};
+
+/*
+ * _DAPM_ Controls
+ */
+
+/* Left Mixer */
+static const struct snd_kcontrol_new wm8753_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_LOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_LOUTM2, 7, 1, 0),
+SOC_DAPM_SINGLE("Left Playback Switch", WM8753_LOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_LOUTM1, 7, 1, 0),
+};
+
+/* Right mixer */
+static const struct snd_kcontrol_new wm8753_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_ROUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_ROUTM2, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8753_ROUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_ROUTM1, 7, 1, 0),
+};
+
+/* Mono mixer */
+static const struct snd_kcontrol_new wm8753_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8753_MOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8753_MOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_MOUTM2, 3, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_MOUTM2, 7, 1, 0),
+SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_MOUTM1, 7, 1, 0),
+};
+
+/* Mono 2 Mux */
+static const struct snd_kcontrol_new wm8753_mono2_controls =
+SOC_DAPM_ENUM("Route", wm8753_enum[17]);
+
+/* Out 3 Mux */
+static const struct snd_kcontrol_new wm8753_out3_controls =
+SOC_DAPM_ENUM("Route", wm8753_enum[18]);
+
+/* Out 4 Mux */
+static const struct snd_kcontrol_new wm8753_out4_controls =
+SOC_DAPM_ENUM("Route", wm8753_enum[19]);
+
+/* ADC Mono Mix */
+static const struct snd_kcontrol_new wm8753_adc_mono_controls =
+SOC_DAPM_ENUM("Route", wm8753_enum[22]);
+
+/* Record mixer */
+static const struct snd_kcontrol_new wm8753_record_mixer_controls[] = {
+SOC_DAPM_SINGLE("Voice Capture Switch", WM8753_RECMIX2, 3, 1, 0),
+SOC_DAPM_SINGLE("Left Capture Switch", WM8753_RECMIX1, 3, 1, 0),
+SOC_DAPM_SINGLE("Right Capture Switch", WM8753_RECMIX1, 7, 1, 0),
+};
+
+/* Left ADC mux */
+static const struct snd_kcontrol_new wm8753_adc_left_controls =
+SOC_DAPM_ENUM("Route", wm8753_enum[21]);
+
+/* Right ADC mux */
+static const struct snd_kcontrol_new wm8753_adc_right_controls =
+SOC_DAPM_ENUM("Route", wm8753_enum[20]);
+
+/* MIC mux */
+static const struct snd_kcontrol_new wm8753_mic_mux_controls =
+SOC_DAPM_ENUM("Route", wm8753_enum[16]);
+
+/* ALC mixer */
+static const struct snd_kcontrol_new wm8753_alc_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Capture Switch", WM8753_INCTL2, 3, 1, 0),
+SOC_DAPM_SINGLE("Mic2 Capture Switch", WM8753_INCTL2, 2, 1, 0),
+SOC_DAPM_SINGLE("Mic1 Capture Switch", WM8753_INCTL2, 1, 1, 0),
+SOC_DAPM_SINGLE("Rx Capture Switch", WM8753_INCTL2, 0, 1, 0),
+};
+
+/* Left Line mux */
+static const struct snd_kcontrol_new wm8753_line_left_controls =
+SOC_DAPM_ENUM("Route", wm8753_enum[14]);
+
+/* Right Line mux */
+static const struct snd_kcontrol_new wm8753_line_right_controls =
+SOC_DAPM_ENUM("Route", wm8753_enum[13]);
+
+/* Mono Line mux */
+static const struct snd_kcontrol_new wm8753_line_mono_controls =
+SOC_DAPM_ENUM("Route", wm8753_enum[12]);
+
+/* Line mux and mixer */
+static const struct snd_kcontrol_new wm8753_line_mux_mix_controls =
+SOC_DAPM_ENUM("Route", wm8753_enum[11]);
+
+/* Rx mux and mixer */
+static const struct snd_kcontrol_new wm8753_rx_mux_mix_controls =
+SOC_DAPM_ENUM("Route", wm8753_enum[15]);
+
+/* Mic Selector Mux */
+static const struct snd_kcontrol_new wm8753_mic_sel_mux_controls =
+SOC_DAPM_ENUM("Route", wm8753_enum[25]);
+
+static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
+SND_SOC_DAPM_MICBIAS("Mic Bias", WM8753_PWR1, 5, 0),
+SND_SOC_DAPM_MIXER("Left Mixer", WM8753_PWR4, 0, 0,
+	&wm8753_left_mixer_controls[0], ARRAY_SIZE(wm8753_left_mixer_controls)),
+SND_SOC_DAPM_PGA("Left Out 1", WM8753_PWR3, 8, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Left Out 2", WM8753_PWR3, 6, 0, NULL, 0),
+SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", WM8753_PWR1, 3, 0),
+SND_SOC_DAPM_OUTPUT("LOUT1"),
+SND_SOC_DAPM_OUTPUT("LOUT2"),
+SND_SOC_DAPM_MIXER("Right Mixer", WM8753_PWR4, 1, 0,
+	&wm8753_right_mixer_controls[0], ARRAY_SIZE(wm8753_right_mixer_controls)),
+SND_SOC_DAPM_PGA("Right Out 1", WM8753_PWR3, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Out 2", WM8753_PWR3, 5, 0, NULL, 0),
+SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", WM8753_PWR1, 2, 0),
+SND_SOC_DAPM_OUTPUT("ROUT1"),
+SND_SOC_DAPM_OUTPUT("ROUT2"),
+SND_SOC_DAPM_MIXER("Mono Mixer", WM8753_PWR4, 2, 0,
+	&wm8753_mono_mixer_controls[0], ARRAY_SIZE(wm8753_mono_mixer_controls)),
+SND_SOC_DAPM_PGA("Mono Out 1", WM8753_PWR3, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Mono Out 2", WM8753_PWR3, 1, 0, NULL, 0),
+SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", WM8753_PWR1, 4, 0),
+SND_SOC_DAPM_OUTPUT("MONO1"),
+SND_SOC_DAPM_MUX("Mono 2 Mux", SND_SOC_NOPM, 0, 0, &wm8753_mono2_controls),
+SND_SOC_DAPM_OUTPUT("MONO2"),
+SND_SOC_DAPM_MIXER("Out3 Left + Right", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8753_out3_controls),
+SND_SOC_DAPM_PGA("Out 3", WM8753_PWR3, 4, 0, NULL, 0),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+SND_SOC_DAPM_MUX("Out4 Mux", SND_SOC_NOPM, 0, 0, &wm8753_out4_controls),
+SND_SOC_DAPM_PGA("Out 4", WM8753_PWR3, 3, 0, NULL, 0),
+SND_SOC_DAPM_OUTPUT("OUT4"),
+SND_SOC_DAPM_MIXER("Playback Mixer", WM8753_PWR4, 3, 0,
+	&wm8753_record_mixer_controls[0],
+	ARRAY_SIZE(wm8753_record_mixer_controls)),
+SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8753_PWR2, 3, 0),
+SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8753_PWR2, 2, 0),
+SND_SOC_DAPM_MUX("Capture Left Mixer", SND_SOC_NOPM, 0, 0,
+	&wm8753_adc_mono_controls),
+SND_SOC_DAPM_MUX("Capture Right Mixer", SND_SOC_NOPM, 0, 0,
+	&wm8753_adc_mono_controls),
+SND_SOC_DAPM_MUX("Capture Left Mux", SND_SOC_NOPM, 0, 0,
+	&wm8753_adc_left_controls),
+SND_SOC_DAPM_MUX("Capture Right Mux", SND_SOC_NOPM, 0, 0,
+	&wm8753_adc_right_controls),
+SND_SOC_DAPM_MUX("Mic Sidetone Mux", SND_SOC_NOPM, 0, 0,
+	&wm8753_mic_mux_controls),
+SND_SOC_DAPM_PGA("Left Capture Volume", WM8753_PWR2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Capture Volume", WM8753_PWR2, 4, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("ALC Mixer", WM8753_PWR2, 6, 0,
+	&wm8753_alc_mixer_controls[0], ARRAY_SIZE(wm8753_alc_mixer_controls)),
+SND_SOC_DAPM_MUX("Line Left Mux", SND_SOC_NOPM, 0, 0,
+	&wm8753_line_left_controls),
+SND_SOC_DAPM_MUX("Line Right Mux", SND_SOC_NOPM, 0, 0,
+	&wm8753_line_right_controls),
+SND_SOC_DAPM_MUX("Line Mono Mux", SND_SOC_NOPM, 0, 0,
+	&wm8753_line_mono_controls),
+SND_SOC_DAPM_MUX("Line Mixer", WM8753_PWR2, 0, 0,
+	&wm8753_line_mux_mix_controls),
+SND_SOC_DAPM_MUX("Rx Mixer", WM8753_PWR2, 1, 0,
+	&wm8753_rx_mux_mix_controls),
+SND_SOC_DAPM_PGA("Mic 1 Volume", WM8753_PWR2, 8, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Mic 2 Volume", WM8753_PWR2, 7, 0, NULL, 0),
+SND_SOC_DAPM_MUX("Mic Selection Mux", SND_SOC_NOPM, 0, 0,
+	&wm8753_mic_sel_mux_controls),
+SND_SOC_DAPM_INPUT("LINE1"),
+SND_SOC_DAPM_INPUT("LINE2"),
+SND_SOC_DAPM_INPUT("RXP"),
+SND_SOC_DAPM_INPUT("RXN"),
+SND_SOC_DAPM_INPUT("ACIN"),
+SND_SOC_DAPM_OUTPUT("ACOP"),
+SND_SOC_DAPM_INPUT("MIC1N"),
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2N"),
+SND_SOC_DAPM_INPUT("MIC2"),
+SND_SOC_DAPM_VMID("VREF"),
+};
+
+static const struct snd_soc_dapm_route wm8753_dapm_routes[] = {
+	/* left mixer */
+	{"Left Mixer", "Left Playback Switch", "Left DAC"},
+	{"Left Mixer", "Voice Playback Switch", "Voice DAC"},
+	{"Left Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},
+	{"Left Mixer", "Bypass Playback Switch", "Line Left Mux"},
+
+	/* right mixer */
+	{"Right Mixer", "Right Playback Switch", "Right DAC"},
+	{"Right Mixer", "Voice Playback Switch", "Voice DAC"},
+	{"Right Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},
+	{"Right Mixer", "Bypass Playback Switch", "Line Right Mux"},
+
+	/* mono mixer */
+	{"Mono Mixer", "Voice Playback Switch", "Voice DAC"},
+	{"Mono Mixer", "Left Playback Switch", "Left DAC"},
+	{"Mono Mixer", "Right Playback Switch", "Right DAC"},
+	{"Mono Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},
+	{"Mono Mixer", "Bypass Playback Switch", "Line Mono Mux"},
+
+	/* left out */
+	{"Left Out 1", NULL, "Left Mixer"},
+	{"Left Out 2", NULL, "Left Mixer"},
+	{"LOUT1", NULL, "Left Out 1"},
+	{"LOUT2", NULL, "Left Out 2"},
+
+	/* right out */
+	{"Right Out 1", NULL, "Right Mixer"},
+	{"Right Out 2", NULL, "Right Mixer"},
+	{"ROUT1", NULL, "Right Out 1"},
+	{"ROUT2", NULL, "Right Out 2"},
+
+	/* mono 1 out */
+	{"Mono Out 1", NULL, "Mono Mixer"},
+	{"MONO1", NULL, "Mono Out 1"},
+
+	/* mono 2 out */
+	{"Mono 2 Mux", "Left + Right", "Out3 Left + Right"},
+	{"Mono 2 Mux", "Inverted Mono 1", "MONO1"},
+	{"Mono 2 Mux", "Left", "Left Mixer"},
+	{"Mono 2 Mux", "Right", "Right Mixer"},
+	{"Mono Out 2", NULL, "Mono 2 Mux"},
+	{"MONO2", NULL, "Mono Out 2"},
+
+	/* out 3 */
+	{"Out3 Left + Right", NULL, "Left Mixer"},
+	{"Out3 Left + Right", NULL, "Right Mixer"},
+	{"Out3 Mux", "VREF", "VREF"},
+	{"Out3 Mux", "Left + Right", "Out3 Left + Right"},
+	{"Out3 Mux", "ROUT2", "ROUT2"},
+	{"Out 3", NULL, "Out3 Mux"},
+	{"OUT3", NULL, "Out 3"},
+
+	/* out 4 */
+	{"Out4 Mux", "VREF", "VREF"},
+	{"Out4 Mux", "Capture ST", "Playback Mixer"},
+	{"Out4 Mux", "LOUT2", "LOUT2"},
+	{"Out 4", NULL, "Out4 Mux"},
+	{"OUT4", NULL, "Out 4"},
+
+	/* record mixer  */
+	{"Playback Mixer", "Left Capture Switch", "Left Mixer"},
+	{"Playback Mixer", "Voice Capture Switch", "Mono Mixer"},
+	{"Playback Mixer", "Right Capture Switch", "Right Mixer"},
+
+	/* Mic/SideTone Mux */
+	{"Mic Sidetone Mux", "Left PGA", "Left Capture Volume"},
+	{"Mic Sidetone Mux", "Right PGA", "Right Capture Volume"},
+	{"Mic Sidetone Mux", "Mic 1", "Mic 1 Volume"},
+	{"Mic Sidetone Mux", "Mic 2", "Mic 2 Volume"},
+
+	/* Capture Left Mux */
+	{"Capture Left Mux", "PGA", "Left Capture Volume"},
+	{"Capture Left Mux", "Line or RXP-RXN", "Line Left Mux"},
+	{"Capture Left Mux", "Line", "LINE1"},
+
+	/* Capture Right Mux */
+	{"Capture Right Mux", "PGA", "Right Capture Volume"},
+	{"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"},
+	{"Capture Right Mux", "Sidetone", "Playback Mixer"},
+
+	/* Mono Capture mixer-mux */
+	{"Capture Right Mixer", "Stereo", "Capture Right Mux"},
+	{"Capture Left Mixer", "Stereo", "Capture Left Mux"},
+	{"Capture Left Mixer", "Analogue Mix Left", "Capture Left Mux"},
+	{"Capture Left Mixer", "Analogue Mix Left", "Capture Right Mux"},
+	{"Capture Right Mixer", "Analogue Mix Right", "Capture Left Mux"},
+	{"Capture Right Mixer", "Analogue Mix Right", "Capture Right Mux"},
+	{"Capture Left Mixer", "Digital Mono Mix", "Capture Left Mux"},
+	{"Capture Left Mixer", "Digital Mono Mix", "Capture Right Mux"},
+	{"Capture Right Mixer", "Digital Mono Mix", "Capture Left Mux"},
+	{"Capture Right Mixer", "Digital Mono Mix", "Capture Right Mux"},
+
+	/* ADC */
+	{"Left ADC", NULL, "Capture Left Mixer"},
+	{"Right ADC", NULL, "Capture Right Mixer"},
+
+	/* Left Capture Volume */
+	{"Left Capture Volume", NULL, "ACIN"},
+
+	/* Right Capture Volume */
+	{"Right Capture Volume", NULL, "Mic 2 Volume"},
+
+	/* ALC Mixer */
+	{"ALC Mixer", "Line Capture Switch", "Line Mixer"},
+	{"ALC Mixer", "Mic2 Capture Switch", "Mic 2 Volume"},
+	{"ALC Mixer", "Mic1 Capture Switch", "Mic 1 Volume"},
+	{"ALC Mixer", "Rx Capture Switch", "Rx Mixer"},
+
+	/* Line Left Mux */
+	{"Line Left Mux", "Line 1", "LINE1"},
+	{"Line Left Mux", "Rx Mix", "Rx Mixer"},
+
+	/* Line Right Mux */
+	{"Line Right Mux", "Line 2", "LINE2"},
+	{"Line Right Mux", "Rx Mix", "Rx Mixer"},
+
+	/* Line Mono Mux */
+	{"Line Mono Mux", "Line Mix", "Line Mixer"},
+	{"Line Mono Mux", "Rx Mix", "Rx Mixer"},
+
+	/* Line Mixer/Mux */
+	{"Line Mixer", "Line 1 + 2", "LINE1"},
+	{"Line Mixer", "Line 1 - 2", "LINE1"},
+	{"Line Mixer", "Line 1 + 2", "LINE2"},
+	{"Line Mixer", "Line 1 - 2", "LINE2"},
+	{"Line Mixer", "Line 1", "LINE1"},
+	{"Line Mixer", "Line 2", "LINE2"},
+
+	/* Rx Mixer/Mux */
+	{"Rx Mixer", "RXP - RXN", "RXP"},
+	{"Rx Mixer", "RXP + RXN", "RXP"},
+	{"Rx Mixer", "RXP - RXN", "RXN"},
+	{"Rx Mixer", "RXP + RXN", "RXN"},
+	{"Rx Mixer", "RXP", "RXP"},
+	{"Rx Mixer", "RXN", "RXN"},
+
+	/* Mic 1 Volume */
+	{"Mic 1 Volume", NULL, "MIC1N"},
+	{"Mic 1 Volume", NULL, "Mic Selection Mux"},
+
+	/* Mic 2 Volume */
+	{"Mic 2 Volume", NULL, "MIC2N"},
+	{"Mic 2 Volume", NULL, "MIC2"},
+
+	/* Mic Selector Mux */
+	{"Mic Selection Mux", "Mic 1", "MIC1"},
+	{"Mic Selection Mux", "Mic 2", "MIC2N"},
+	{"Mic Selection Mux", "Mic 3", "MIC2"},
+
+	/* ACOP */
+	{"ACOP", NULL, "ALC Mixer"},
+};
+
+/* PLL divisors */
+struct _pll_div {
+	u32 div2:1;
+	u32 n:4;
+	u32 k:24;
+};
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 22) * 10)
+
+static void pll_factors(struct _pll_div *pll_div, unsigned int target,
+	unsigned int source)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod;
+
+	Ndiv = target / source;
+	if (Ndiv < 6) {
+		source >>= 1;
+		pll_div->div2 = 1;
+		Ndiv = target / source;
+	} else
+		pll_div->div2 = 0;
+
+	if ((Ndiv < 6) || (Ndiv > 12))
+		printk(KERN_WARNING
+			"wm8753: unsupported N = %u\n", Ndiv);
+
+	pll_div->n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	/* Check if we need to round */
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	K /= 10;
+
+	pll_div->k = K;
+}
+
+static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+		int source, unsigned int freq_in, unsigned int freq_out)
+{
+	u16 reg, enable;
+	int offset;
+	struct snd_soc_component *component = codec_dai->component;
+
+	if (pll_id < WM8753_PLL1 || pll_id > WM8753_PLL2)
+		return -ENODEV;
+
+	if (pll_id == WM8753_PLL1) {
+		offset = 0;
+		enable = 0x10;
+		reg = snd_soc_component_read32(component, WM8753_CLOCK) & 0xffef;
+	} else {
+		offset = 4;
+		enable = 0x8;
+		reg = snd_soc_component_read32(component, WM8753_CLOCK) & 0xfff7;
+	}
+
+	if (!freq_in || !freq_out) {
+		/* disable PLL  */
+		snd_soc_component_write(component, WM8753_PLL1CTL1 + offset, 0x0026);
+		snd_soc_component_write(component, WM8753_CLOCK, reg);
+		return 0;
+	} else {
+		u16 value = 0;
+		struct _pll_div pll_div;
+
+		pll_factors(&pll_div, freq_out * 8, freq_in);
+
+		/* set up N and K PLL divisor ratios */
+		/* bits 8:5 = PLL_N, bits 3:0 = PLL_K[21:18] */
+		value = (pll_div.n << 5) + ((pll_div.k & 0x3c0000) >> 18);
+		snd_soc_component_write(component, WM8753_PLL1CTL2 + offset, value);
+
+		/* bits 8:0 = PLL_K[17:9] */
+		value = (pll_div.k & 0x03fe00) >> 9;
+		snd_soc_component_write(component, WM8753_PLL1CTL3 + offset, value);
+
+		/* bits 8:0 = PLL_K[8:0] */
+		value = pll_div.k & 0x0001ff;
+		snd_soc_component_write(component, WM8753_PLL1CTL4 + offset, value);
+
+		/* set PLL as input and enable */
+		snd_soc_component_write(component, WM8753_PLL1CTL1 + offset, 0x0027 |
+			(pll_div.div2 << 3));
+		snd_soc_component_write(component, WM8753_CLOCK, reg | enable);
+	}
+	return 0;
+}
+
+struct _coeff_div {
+	u32 mclk;
+	u32 rate;
+	u8 sr:5;
+	u8 usb:1;
+};
+
+/* codec hifi mclk (after PLL) clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	/* 8k */
+	{12288000, 8000, 0x6, 0x0},
+	{11289600, 8000, 0x16, 0x0},
+	{18432000, 8000, 0x7, 0x0},
+	{16934400, 8000, 0x17, 0x0},
+	{12000000, 8000, 0x6, 0x1},
+
+	/* 11.025k */
+	{11289600, 11025, 0x18, 0x0},
+	{16934400, 11025, 0x19, 0x0},
+	{12000000, 11025, 0x19, 0x1},
+
+	/* 16k */
+	{12288000, 16000, 0xa, 0x0},
+	{18432000, 16000, 0xb, 0x0},
+	{12000000, 16000, 0xa, 0x1},
+
+	/* 22.05k */
+	{11289600, 22050, 0x1a, 0x0},
+	{16934400, 22050, 0x1b, 0x0},
+	{12000000, 22050, 0x1b, 0x1},
+
+	/* 32k */
+	{12288000, 32000, 0xc, 0x0},
+	{18432000, 32000, 0xd, 0x0},
+	{12000000, 32000, 0xa, 0x1},
+
+	/* 44.1k */
+	{11289600, 44100, 0x10, 0x0},
+	{16934400, 44100, 0x11, 0x0},
+	{12000000, 44100, 0x11, 0x1},
+
+	/* 48k */
+	{12288000, 48000, 0x0, 0x0},
+	{18432000, 48000, 0x1, 0x0},
+	{12000000, 48000, 0x0, 0x1},
+
+	/* 88.2k */
+	{11289600, 88200, 0x1e, 0x0},
+	{16934400, 88200, 0x1f, 0x0},
+	{12000000, 88200, 0x1f, 0x1},
+
+	/* 96k */
+	{12288000, 96000, 0xe, 0x0},
+	{18432000, 96000, 0xf, 0x0},
+	{12000000, 96000, 0xe, 0x1},
+};
+
+static int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+	return -EINVAL;
+}
+
+/*
+ * Clock after PLL and dividers
+ */
+static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+
+	switch (freq) {
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 16934400:
+	case 18432000:
+		if (clk_id == WM8753_MCLK) {
+			wm8753->sysclk = freq;
+			return 0;
+		} else if (clk_id == WM8753_PCMCLK) {
+			wm8753->pcmclk = freq;
+			return 0;
+		}
+		break;
+	}
+	return -EINVAL;
+}
+
+/*
+ * Set's ADC and Voice DAC format.
+ */
+static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_component *component,
+		unsigned int fmt)
+{
+	u16 voice = snd_soc_component_read32(component, WM8753_PCM) & 0x01ec;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		voice |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		voice |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		voice |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		voice |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8753_PCM, voice);
+	return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ */
+static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+	u16 voice = snd_soc_component_read32(component, WM8753_PCM) & 0x01f3;
+	u16 srate = snd_soc_component_read32(component, WM8753_SRATE1) & 0x017f;
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		voice |= 0x0004;
+		break;
+	case 24:
+		voice |= 0x0008;
+		break;
+	case 32:
+		voice |= 0x000c;
+		break;
+	}
+
+	/* sample rate */
+	if (params_rate(params) * 384 == wm8753->pcmclk)
+		srate |= 0x80;
+	snd_soc_component_write(component, WM8753_SRATE1, srate);
+
+	snd_soc_component_write(component, WM8753_PCM, voice);
+	return 0;
+}
+
+/*
+ * Set's PCM dai fmt and BCLK.
+ */
+static int wm8753_pcm_set_dai_fmt(struct snd_soc_component *component,
+		unsigned int fmt)
+{
+	u16 voice, ioctl;
+
+	voice = snd_soc_component_read32(component, WM8753_PCM) & 0x011f;
+	ioctl = snd_soc_component_read32(component, WM8753_IOCTL) & 0x015d;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		ioctl |= 0x2; /* fall through */
+	case SND_SOC_DAIFMT_CBM_CFS:
+		voice |= 0x0040;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		/* frame inversion not valid for DSP modes */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			voice |= 0x0080;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		voice &= ~0x0010;
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			voice |= 0x0090;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			voice |= 0x0080;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			voice |= 0x0010;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8753_PCM, voice);
+	snd_soc_component_write(component, WM8753_IOCTL, ioctl);
+	return 0;
+}
+
+static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+		int div_id, int div)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 reg;
+
+	switch (div_id) {
+	case WM8753_PCMDIV:
+		reg = snd_soc_component_read32(component, WM8753_CLOCK) & 0x003f;
+		snd_soc_component_write(component, WM8753_CLOCK, reg | div);
+		break;
+	case WM8753_BCLKDIV:
+		reg = snd_soc_component_read32(component, WM8753_SRATE2) & 0x01c7;
+		snd_soc_component_write(component, WM8753_SRATE2, reg | div);
+		break;
+	case WM8753_VXCLKDIV:
+		reg = snd_soc_component_read32(component, WM8753_SRATE2) & 0x003f;
+		snd_soc_component_write(component, WM8753_SRATE2, reg | div);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * Set's HiFi DAC format.
+ */
+static int wm8753_hdac_set_dai_fmt(struct snd_soc_component *component,
+		unsigned int fmt)
+{
+	u16 hifi = snd_soc_component_read32(component, WM8753_HIFI) & 0x01e0;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		hifi |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		hifi |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		hifi |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		hifi |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8753_HIFI, hifi);
+	return 0;
+}
+
+/*
+ * Set's I2S DAI format.
+ */
+static int wm8753_i2s_set_dai_fmt(struct snd_soc_component *component,
+		unsigned int fmt)
+{
+	u16 ioctl, hifi;
+
+	hifi = snd_soc_component_read32(component, WM8753_HIFI) & 0x013f;
+	ioctl = snd_soc_component_read32(component, WM8753_IOCTL) & 0x00ae;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		ioctl |= 0x1; /* fall through */
+	case SND_SOC_DAIFMT_CBM_CFS:
+		hifi |= 0x0040;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		/* frame inversion not valid for DSP modes */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			hifi |= 0x0080;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		hifi &= ~0x0010;
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			hifi |= 0x0090;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			hifi |= 0x0080;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			hifi |= 0x0010;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8753_HIFI, hifi);
+	snd_soc_component_write(component, WM8753_IOCTL, ioctl);
+	return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ */
+static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+	u16 srate = snd_soc_component_read32(component, WM8753_SRATE1) & 0x01c0;
+	u16 hifi = snd_soc_component_read32(component, WM8753_HIFI) & 0x01f3;
+	int coeff;
+
+	/* is digital filter coefficient valid ? */
+	coeff = get_coeff(wm8753->sysclk, params_rate(params));
+	if (coeff < 0) {
+		printk(KERN_ERR "wm8753 invalid MCLK or rate\n");
+		return coeff;
+	}
+	snd_soc_component_write(component, WM8753_SRATE1, srate | (coeff_div[coeff].sr << 1) |
+		coeff_div[coeff].usb);
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		hifi |= 0x0004;
+		break;
+	case 24:
+		hifi |= 0x0008;
+		break;
+	case 32:
+		hifi |= 0x000c;
+		break;
+	}
+
+	snd_soc_component_write(component, WM8753_HIFI, hifi);
+	return 0;
+}
+
+static int wm8753_mode1v_set_dai_fmt(struct snd_soc_component *component,
+		unsigned int fmt)
+{
+	u16 clock;
+
+	/* set clk source as pcmclk */
+	clock = snd_soc_component_read32(component, WM8753_CLOCK) & 0xfffb;
+	snd_soc_component_write(component, WM8753_CLOCK, clock);
+
+	return wm8753_vdac_adc_set_dai_fmt(component, fmt);
+}
+
+static int wm8753_mode1h_set_dai_fmt(struct snd_soc_component *component,
+		unsigned int fmt)
+{
+	return wm8753_hdac_set_dai_fmt(component, fmt);
+}
+
+static int wm8753_mode2_set_dai_fmt(struct snd_soc_component *component,
+		unsigned int fmt)
+{
+	u16 clock;
+
+	/* set clk source as pcmclk */
+	clock = snd_soc_component_read32(component, WM8753_CLOCK) & 0xfffb;
+	snd_soc_component_write(component, WM8753_CLOCK, clock);
+
+	return wm8753_vdac_adc_set_dai_fmt(component, fmt);
+}
+
+static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_component *component,
+		unsigned int fmt)
+{
+	u16 clock;
+
+	/* set clk source as mclk */
+	clock = snd_soc_component_read32(component, WM8753_CLOCK) & 0xfffb;
+	snd_soc_component_write(component, WM8753_CLOCK, clock | 0x4);
+
+	if (wm8753_hdac_set_dai_fmt(component, fmt) < 0)
+		return -EINVAL;
+	return wm8753_vdac_adc_set_dai_fmt(component, fmt);
+}
+
+static int wm8753_hifi_write_dai_fmt(struct snd_soc_component *component,
+		unsigned int fmt)
+{
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	switch (wm8753->dai_func) {
+	case 0:
+		ret = wm8753_mode1h_set_dai_fmt(component, fmt);
+		break;
+	case 1:
+		ret = wm8753_mode2_set_dai_fmt(component, fmt);
+		break;
+	case 2:
+	case 3:
+		ret = wm8753_mode3_4_set_dai_fmt(component, fmt);
+		break;
+	default:
+		 break;
+	}
+	if (ret)
+		return ret;
+
+	return wm8753_i2s_set_dai_fmt(component, fmt);
+}
+
+static int wm8753_hifi_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+
+	wm8753->hifi_fmt = fmt;
+
+	return wm8753_hifi_write_dai_fmt(component, fmt);
+};
+
+static int wm8753_voice_write_dai_fmt(struct snd_soc_component *component,
+		unsigned int fmt)
+{
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	if (wm8753->dai_func != 0)
+		return 0;
+
+	ret = wm8753_mode1v_set_dai_fmt(component, fmt);
+	if (ret)
+		return ret;
+	ret = wm8753_pcm_set_dai_fmt(component, fmt);
+	if (ret)
+		return ret;
+
+	return 0;
+};
+
+static int wm8753_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+
+	wm8753->voice_fmt = fmt;
+
+	return wm8753_voice_write_dai_fmt(component, fmt);
+};
+
+static int wm8753_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8753_DAC) & 0xfff7;
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+
+	/* the digital mute covers the HiFi and Voice DAC's on the WM8753.
+	 * make sure we check if they are not both active when we mute */
+	if (mute && wm8753->dai_func == 1) {
+		if (!snd_soc_component_is_active(component))
+			snd_soc_component_write(component, WM8753_DAC, mute_reg | 0x8);
+	} else {
+		if (mute)
+			snd_soc_component_write(component, WM8753_DAC, mute_reg | 0x8);
+		else
+			snd_soc_component_write(component, WM8753_DAC, mute_reg);
+	}
+
+	return 0;
+}
+
+static void wm8753_charge_work(struct work_struct *work)
+{
+	struct wm8753_priv *wm8753 =
+		container_of(work, struct wm8753_priv, charge_work.work);
+
+	/* Set to 500k */
+	regmap_update_bits(wm8753->regmap, WM8753_PWR1, 0x0180, 0x0100);
+}
+
+static int wm8753_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+	u16 pwr_reg = snd_soc_component_read32(component, WM8753_PWR1) & 0xfe3e;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* set vmid to 50k and unmute dac */
+		snd_soc_component_write(component, WM8753_PWR1, pwr_reg | 0x00c0);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* Wait until fully charged */
+		flush_delayed_work(&wm8753->charge_work);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/* set vmid to 5k for quick power up */
+			snd_soc_component_write(component, WM8753_PWR1, pwr_reg | 0x01c1);
+			schedule_delayed_work(&wm8753->charge_work,
+				msecs_to_jiffies(caps_charge));
+		} else {
+			/* mute dac and set vmid to 500k, enable VREF */
+			snd_soc_component_write(component, WM8753_PWR1, pwr_reg | 0x0141);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		cancel_delayed_work_sync(&wm8753->charge_work);
+		snd_soc_component_write(component, WM8753_PWR1, 0x0001);
+		break;
+	}
+	return 0;
+}
+
+#define WM8753_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+		SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define WM8753_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+/*
+ * The WM8753 supports up to 4 different and mutually exclusive DAI
+ * configurations. This gives 2 PCM's available for use, hifi and voice.
+ * NOTE: The Voice PCM cannot play or capture audio to the CPU as it's DAI
+ * is connected between the wm8753 and a BT codec or GSM modem.
+ *
+ * 1. Voice over PCM DAI - HIFI DAC over HIFI DAI
+ * 2. Voice over HIFI DAI - HIFI disabled
+ * 3. Voice disabled - HIFI over HIFI
+ * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture
+ */
+static const struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode = {
+	.hw_params	= wm8753_i2s_hw_params,
+	.digital_mute	= wm8753_mute,
+	.set_fmt	= wm8753_hifi_set_dai_fmt,
+	.set_clkdiv	= wm8753_set_dai_clkdiv,
+	.set_pll	= wm8753_set_dai_pll,
+	.set_sysclk	= wm8753_set_dai_sysclk,
+};
+
+static const struct snd_soc_dai_ops wm8753_dai_ops_voice_mode = {
+	.hw_params	= wm8753_pcm_hw_params,
+	.digital_mute	= wm8753_mute,
+	.set_fmt	= wm8753_voice_set_dai_fmt,
+	.set_clkdiv	= wm8753_set_dai_clkdiv,
+	.set_pll	= wm8753_set_dai_pll,
+	.set_sysclk	= wm8753_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8753_dai[] = {
+/* DAI HiFi mode 1 */
+{	.name = "wm8753-hifi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8753_RATES,
+		.formats = WM8753_FORMATS
+	},
+	.capture = { /* dummy for fast DAI switching */
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8753_RATES,
+		.formats = WM8753_FORMATS
+	},
+	.ops = &wm8753_dai_ops_hifi_mode,
+},
+/* DAI Voice mode 1 */
+{	.name = "wm8753-voice",
+	.playback = {
+		.stream_name = "Voice Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = WM8753_RATES,
+		.formats = WM8753_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8753_RATES,
+		.formats = WM8753_FORMATS,
+	},
+	.ops = &wm8753_dai_ops_voice_mode,
+},
+};
+
+static int wm8753_resume(struct snd_soc_component *component)
+{
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+
+	regcache_sync(wm8753->regmap);
+
+	return 0;
+}
+
+static int wm8753_probe(struct snd_soc_component *component)
+{
+	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	INIT_DELAYED_WORK(&wm8753->charge_work, wm8753_charge_work);
+
+	ret = wm8753_reset(component);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
+		return ret;
+	}
+
+	wm8753->dai_func = 0;
+
+	/* set the update bits */
+	snd_soc_component_update_bits(component, WM8753_LDAC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_RDAC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_LADC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_RADC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_LOUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_ROUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_LOUT2V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_ROUT2V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_LINVOL, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8753_RINVOL, 0x0100, 0x0100);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8753 = {
+	.probe			= wm8753_probe,
+	.resume			= wm8753_resume,
+	.set_bias_level		= wm8753_set_bias_level,
+	.controls		= wm8753_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8753_snd_controls),
+	.dapm_widgets		= wm8753_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8753_dapm_widgets),
+	.dapm_routes		= wm8753_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8753_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct of_device_id wm8753_of_match[] = {
+	{ .compatible = "wlf,wm8753", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wm8753_of_match);
+
+static const struct regmap_config wm8753_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = WM8753_ADCTL2,
+	.volatile_reg = wm8753_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8753_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8753_reg_defaults),
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8753_spi_probe(struct spi_device *spi)
+{
+	struct wm8753_priv *wm8753;
+	int ret;
+
+	wm8753 = devm_kzalloc(&spi->dev, sizeof(struct wm8753_priv),
+			      GFP_KERNEL);
+	if (wm8753 == NULL)
+		return -ENOMEM;
+
+	spi_set_drvdata(spi, wm8753);
+
+	wm8753->regmap = devm_regmap_init_spi(spi, &wm8753_regmap);
+	if (IS_ERR(wm8753->regmap)) {
+		ret = PTR_ERR(wm8753->regmap);
+		dev_err(&spi->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&spi->dev, &soc_component_dev_wm8753,
+				     wm8753_dai, ARRAY_SIZE(wm8753_dai));
+	if (ret != 0)
+		dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret);
+
+	return ret;
+}
+
+static struct spi_driver wm8753_spi_driver = {
+	.driver = {
+		.name	= "wm8753",
+		.of_match_table = wm8753_of_match,
+	},
+	.probe		= wm8753_spi_probe,
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8753_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8753_priv *wm8753;
+	int ret;
+
+	wm8753 = devm_kzalloc(&i2c->dev, sizeof(struct wm8753_priv),
+			      GFP_KERNEL);
+	if (wm8753 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, wm8753);
+
+	wm8753->regmap = devm_regmap_init_i2c(i2c, &wm8753_regmap);
+	if (IS_ERR(wm8753->regmap)) {
+		ret = PTR_ERR(wm8753->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_wm8753,
+				     wm8753_dai, ARRAY_SIZE(wm8753_dai));
+	if (ret != 0)
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8753_i2c_id[] = {
+	{ "wm8753", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
+
+static struct i2c_driver wm8753_i2c_driver = {
+	.driver = {
+		.name = "wm8753",
+		.of_match_table = wm8753_of_match,
+	},
+	.probe =    wm8753_i2c_probe,
+	.id_table = wm8753_i2c_id,
+};
+#endif
+
+static int __init wm8753_modinit(void)
+{
+	int ret = 0;
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&wm8753_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register wm8753 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8753_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register wm8753 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return ret;
+}
+module_init(wm8753_modinit);
+
+static void __exit wm8753_exit(void)
+{
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&wm8753_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8753_spi_driver);
+#endif
+}
+module_exit(wm8753_exit);
+
+MODULE_DESCRIPTION("ASoC WM8753 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h
new file mode 100644
index 0000000..8b39e36
--- /dev/null
+++ b/sound/soc/codecs/wm8753.h
@@ -0,0 +1,115 @@
+/*
+ * wm8753.h  --  audio driver for WM8753
+ *
+ * Copyright 2003 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef _WM8753_H
+#define _WM8753_H
+
+/* WM8753 register space */
+
+#define WM8753_DAC		0x01
+#define WM8753_ADC		0x02
+#define WM8753_PCM		0x03
+#define WM8753_HIFI		0x04
+#define WM8753_IOCTL		0x05
+#define WM8753_SRATE1		0x06
+#define WM8753_SRATE2		0x07
+#define WM8753_LDAC		0x08
+#define WM8753_RDAC		0x09
+#define WM8753_BASS		0x0a
+#define WM8753_TREBLE		0x0b
+#define WM8753_ALC1		0x0c
+#define WM8753_ALC2		0x0d
+#define WM8753_ALC3		0x0e
+#define WM8753_NGATE		0x0f
+#define WM8753_LADC		0x10
+#define WM8753_RADC		0x11
+#define WM8753_ADCTL1		0x12
+#define WM8753_3D		0x13
+#define WM8753_PWR1		0x14
+#define WM8753_PWR2		0x15
+#define WM8753_PWR3		0x16
+#define WM8753_PWR4		0x17
+#define WM8753_ID		0x18
+#define WM8753_INTPOL		0x19
+#define WM8753_INTEN		0x1a
+#define WM8753_GPIO1		0x1b
+#define WM8753_GPIO2		0x1c
+#define WM8753_RESET		0x1f
+#define WM8753_RECMIX1		0x20
+#define WM8753_RECMIX2		0x21
+#define WM8753_LOUTM1		0x22
+#define WM8753_LOUTM2		0x23
+#define WM8753_ROUTM1		0x24
+#define WM8753_ROUTM2		0x25
+#define WM8753_MOUTM1		0x26
+#define WM8753_MOUTM2		0x27
+#define WM8753_LOUT1V		0x28
+#define WM8753_ROUT1V		0x29
+#define WM8753_LOUT2V		0x2a
+#define WM8753_ROUT2V		0x2b
+#define WM8753_MOUTV		0x2c
+#define WM8753_OUTCTL		0x2d
+#define WM8753_ADCIN		0x2e
+#define WM8753_INCTL1		0x2f
+#define WM8753_INCTL2		0x30
+#define WM8753_LINVOL		0x31
+#define WM8753_RINVOL		0x32
+#define WM8753_MICBIAS		0x33
+#define WM8753_CLOCK		0x34
+#define WM8753_PLL1CTL1		0x35
+#define WM8753_PLL1CTL2		0x36
+#define WM8753_PLL1CTL3		0x37
+#define WM8753_PLL1CTL4		0x38
+#define WM8753_PLL2CTL1		0x39
+#define WM8753_PLL2CTL2		0x3a
+#define WM8753_PLL2CTL3		0x3b
+#define WM8753_PLL2CTL4		0x3c
+#define WM8753_BIASCTL		0x3d
+#define WM8753_ADCTL2		0x3f
+
+#define WM8753_PLL1			0
+#define WM8753_PLL2			1
+
+/* clock inputs */
+#define WM8753_MCLK		0
+#define WM8753_PCMCLK		1
+
+/* clock divider id's */
+#define WM8753_PCMDIV		0
+#define WM8753_BCLKDIV		1
+#define WM8753_VXCLKDIV		2
+
+/* PCM clock dividers */
+#define WM8753_PCM_DIV_1	(0 << 6)
+#define WM8753_PCM_DIV_3	(2 << 6)
+#define WM8753_PCM_DIV_5_5	(3 << 6)
+#define WM8753_PCM_DIV_2	(4 << 6)
+#define WM8753_PCM_DIV_4	(5 << 6)
+#define WM8753_PCM_DIV_6	(6 << 6)
+#define WM8753_PCM_DIV_8	(7 << 6)
+
+/* BCLK clock dividers */
+#define WM8753_BCLK_DIV_1	(0 << 3)
+#define WM8753_BCLK_DIV_2	(1 << 3)
+#define WM8753_BCLK_DIV_4	(2 << 3)
+#define WM8753_BCLK_DIV_8	(3 << 3)
+#define WM8753_BCLK_DIV_16	(4 << 3)
+
+/* VXCLK clock dividers */
+#define WM8753_VXCLK_DIV_1	(0 << 6)
+#define WM8753_VXCLK_DIV_2	(1 << 6)
+#define WM8753_VXCLK_DIV_4	(2 << 6)
+#define WM8753_VXCLK_DIV_8	(3 << 6)
+#define WM8753_VXCLK_DIV_16	(4 << 6)
+
+#endif
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
new file mode 100644
index 0000000..806245c
--- /dev/null
+++ b/sound/soc/codecs/wm8770.c
@@ -0,0 +1,715 @@
+/*
+ * wm8770.c  --  WM8770 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/pm.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8770.h"
+
+#define WM8770_NUM_SUPPLIES 3
+static const char *wm8770_supply_names[WM8770_NUM_SUPPLIES] = {
+	"AVDD1",
+	"AVDD2",
+	"DVDD"
+};
+
+static const struct reg_default wm8770_reg_defaults[] = {
+	{  0, 0x7f },
+	{  1, 0x7f },
+	{  2, 0x7f },
+	{  3, 0x7f },
+	{  4, 0x7f },
+	{  5, 0x7f },
+	{  6, 0x7f },
+	{  7, 0x7f },
+	{  8, 0x7f },
+	{  9, 0xff },
+	{ 10, 0xff },
+	{ 11, 0xff },
+	{ 12, 0xff },
+	{ 13, 0xff },
+	{ 14, 0xff },
+	{ 15, 0xff },
+	{ 16, 0xff },
+	{ 17, 0xff },
+	{ 18, 0    },
+	{ 19, 0x90 },
+	{ 20, 0    },
+	{ 21, 0    },
+	{ 22, 0x22 },
+	{ 23, 0x22 },
+	{ 24, 0x3e },
+	{ 25, 0xc  },
+	{ 26, 0xc  },
+	{ 27, 0x100 },
+	{ 28, 0x189 },
+	{ 29, 0x189 },
+	{ 30, 0x8770 },
+};
+
+static bool wm8770_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8770_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+struct wm8770_priv {
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[WM8770_NUM_SUPPLIES];
+	struct notifier_block disable_nb[WM8770_NUM_SUPPLIES];
+	struct snd_soc_component *component;
+	int sysclk;
+};
+
+static int vout12supply_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event);
+static int vout34supply_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event);
+
+/*
+ * We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8770_REGULATOR_EVENT(n) \
+static int wm8770_regulator_event_##n(struct notifier_block *nb, \
+				      unsigned long event, void *data)    \
+{ \
+	struct wm8770_priv *wm8770 = container_of(nb, struct wm8770_priv, \
+				     disable_nb[n]); \
+	if (event & REGULATOR_EVENT_DISABLE) { \
+		regcache_mark_dirty(wm8770->regmap);	\
+	} \
+	return 0; \
+}
+
+WM8770_REGULATOR_EVENT(0)
+WM8770_REGULATOR_EVENT(1)
+WM8770_REGULATOR_EVENT(2)
+
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(dac_dig_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(dac_alg_tlv, -12700, 100, 1);
+
+static const char *dac_phase_text[][2] = {
+	{ "DAC1 Normal", "DAC1 Inverted" },
+	{ "DAC2 Normal", "DAC2 Inverted" },
+	{ "DAC3 Normal", "DAC3 Inverted" },
+	{ "DAC4 Normal", "DAC4 Inverted" },
+};
+
+static const struct soc_enum dac_phase[] = {
+	SOC_ENUM_DOUBLE(WM8770_DACPHASE, 0, 1, 2, dac_phase_text[0]),
+	SOC_ENUM_DOUBLE(WM8770_DACPHASE, 2, 3, 2, dac_phase_text[1]),
+	SOC_ENUM_DOUBLE(WM8770_DACPHASE, 4, 5, 2, dac_phase_text[2]),
+	SOC_ENUM_DOUBLE(WM8770_DACPHASE, 6, 7, 2, dac_phase_text[3]),
+};
+
+static const struct snd_kcontrol_new wm8770_snd_controls[] = {
+	/* global DAC playback controls */
+	SOC_SINGLE_TLV("DAC Playback Volume", WM8770_MSDIGVOL, 0, 255, 0,
+		dac_dig_tlv),
+	SOC_SINGLE("DAC Playback Switch", WM8770_DACMUTE, 4, 1, 1),
+	SOC_SINGLE("DAC Playback ZC Switch", WM8770_DACCTRL1, 0, 1, 0),
+
+	/* global VOUT playback controls */
+	SOC_SINGLE_TLV("VOUT Playback Volume", WM8770_MSALGVOL, 0, 127, 0,
+		dac_alg_tlv),
+	SOC_SINGLE("VOUT Playback ZC Switch", WM8770_MSALGVOL, 7, 1, 0),
+
+	/* VOUT1/2/3/4 specific controls */
+	SOC_DOUBLE_R_TLV("VOUT1 Playback Volume", WM8770_VOUT1LVOL,
+		WM8770_VOUT1RVOL, 0, 127, 0, dac_alg_tlv),
+	SOC_DOUBLE_R("VOUT1 Playback ZC Switch", WM8770_VOUT1LVOL,
+		WM8770_VOUT1RVOL, 7, 1, 0),
+	SOC_DOUBLE_R_TLV("VOUT2 Playback Volume", WM8770_VOUT2LVOL,
+		WM8770_VOUT2RVOL, 0, 127, 0, dac_alg_tlv),
+	SOC_DOUBLE_R("VOUT2 Playback ZC Switch", WM8770_VOUT2LVOL,
+		WM8770_VOUT2RVOL, 7, 1, 0),
+	SOC_DOUBLE_R_TLV("VOUT3 Playback Volume", WM8770_VOUT3LVOL,
+		WM8770_VOUT3RVOL, 0, 127, 0, dac_alg_tlv),
+	SOC_DOUBLE_R("VOUT3 Playback ZC Switch", WM8770_VOUT3LVOL,
+		WM8770_VOUT3RVOL, 7, 1, 0),
+	SOC_DOUBLE_R_TLV("VOUT4 Playback Volume", WM8770_VOUT4LVOL,
+		WM8770_VOUT4RVOL, 0, 127, 0, dac_alg_tlv),
+	SOC_DOUBLE_R("VOUT4 Playback ZC Switch", WM8770_VOUT4LVOL,
+		WM8770_VOUT4RVOL, 7, 1, 0),
+
+	/* DAC1/2/3/4 specific controls */
+	SOC_DOUBLE_R_TLV("DAC1 Playback Volume", WM8770_DAC1LVOL,
+		WM8770_DAC1RVOL, 0, 255, 0, dac_dig_tlv),
+	SOC_SINGLE("DAC1 Deemphasis Switch", WM8770_DACCTRL2, 0, 1, 0),
+	SOC_ENUM("DAC1 Phase", dac_phase[0]),
+	SOC_DOUBLE_R_TLV("DAC2 Playback Volume", WM8770_DAC2LVOL,
+		WM8770_DAC2RVOL, 0, 255, 0, dac_dig_tlv),
+	SOC_SINGLE("DAC2 Deemphasis Switch", WM8770_DACCTRL2, 1, 1, 0),
+	SOC_ENUM("DAC2 Phase", dac_phase[1]),
+	SOC_DOUBLE_R_TLV("DAC3 Playback Volume", WM8770_DAC3LVOL,
+		WM8770_DAC3RVOL, 0, 255, 0, dac_dig_tlv),
+	SOC_SINGLE("DAC3 Deemphasis Switch", WM8770_DACCTRL2, 2, 1, 0),
+	SOC_ENUM("DAC3 Phase", dac_phase[2]),
+	SOC_DOUBLE_R_TLV("DAC4 Playback Volume", WM8770_DAC4LVOL,
+		WM8770_DAC4RVOL, 0, 255, 0, dac_dig_tlv),
+	SOC_SINGLE("DAC4 Deemphasis Switch", WM8770_DACCTRL2, 3, 1, 0),
+	SOC_ENUM("DAC4 Phase", dac_phase[3]),
+
+	/* ADC specific controls */
+	SOC_DOUBLE_R_TLV("Capture Volume", WM8770_ADCLCTRL, WM8770_ADCRCTRL,
+		0, 31, 0, adc_tlv),
+	SOC_DOUBLE_R("Capture Switch", WM8770_ADCLCTRL, WM8770_ADCRCTRL,
+		5, 1, 1),
+
+	/* other controls */
+	SOC_SINGLE("ADC 128x Oversampling Switch", WM8770_MSTRCTRL, 3, 1, 0),
+	SOC_SINGLE("ADC Highpass Filter Switch", WM8770_IFACECTRL, 8, 1, 1)
+};
+
+static const char *ain_text[] = {
+	"AIN1", "AIN2", "AIN3", "AIN4",
+	"AIN5", "AIN6", "AIN7", "AIN8"
+};
+
+static SOC_ENUM_DOUBLE_DECL(ain_enum,
+			    WM8770_ADCMUX, 0, 4, ain_text);
+
+static const struct snd_kcontrol_new ain_mux =
+	SOC_DAPM_ENUM("Capture Mux", ain_enum);
+
+static const struct snd_kcontrol_new vout1_mix_controls[] = {
+	SOC_DAPM_SINGLE("DAC1 Switch", WM8770_OUTMUX1, 0, 1, 0),
+	SOC_DAPM_SINGLE("AUX1 Switch", WM8770_OUTMUX1, 1, 1, 0),
+	SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX1, 2, 1, 0)
+};
+
+static const struct snd_kcontrol_new vout2_mix_controls[] = {
+	SOC_DAPM_SINGLE("DAC2 Switch", WM8770_OUTMUX1, 3, 1, 0),
+	SOC_DAPM_SINGLE("AUX2 Switch", WM8770_OUTMUX1, 4, 1, 0),
+	SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX1, 5, 1, 0)
+};
+
+static const struct snd_kcontrol_new vout3_mix_controls[] = {
+	SOC_DAPM_SINGLE("DAC3 Switch", WM8770_OUTMUX2, 0, 1, 0),
+	SOC_DAPM_SINGLE("AUX3 Switch", WM8770_OUTMUX2, 1, 1, 0),
+	SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX2, 2, 1, 0)
+};
+
+static const struct snd_kcontrol_new vout4_mix_controls[] = {
+	SOC_DAPM_SINGLE("DAC4 Switch", WM8770_OUTMUX2, 3, 1, 0),
+	SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX2, 4, 1, 0)
+};
+
+static const struct snd_soc_dapm_widget wm8770_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("AUX1"),
+	SND_SOC_DAPM_INPUT("AUX2"),
+	SND_SOC_DAPM_INPUT("AUX3"),
+
+	SND_SOC_DAPM_INPUT("AIN1"),
+	SND_SOC_DAPM_INPUT("AIN2"),
+	SND_SOC_DAPM_INPUT("AIN3"),
+	SND_SOC_DAPM_INPUT("AIN4"),
+	SND_SOC_DAPM_INPUT("AIN5"),
+	SND_SOC_DAPM_INPUT("AIN6"),
+	SND_SOC_DAPM_INPUT("AIN7"),
+	SND_SOC_DAPM_INPUT("AIN8"),
+
+	SND_SOC_DAPM_MUX("Capture Mux", WM8770_ADCMUX, 8, 1, &ain_mux),
+
+	SND_SOC_DAPM_ADC("ADC", "Capture", WM8770_PWDNCTRL, 1, 1),
+
+	SND_SOC_DAPM_DAC("DAC1", "Playback", WM8770_PWDNCTRL, 2, 1),
+	SND_SOC_DAPM_DAC("DAC2", "Playback", WM8770_PWDNCTRL, 3, 1),
+	SND_SOC_DAPM_DAC("DAC3", "Playback", WM8770_PWDNCTRL, 4, 1),
+	SND_SOC_DAPM_DAC("DAC4", "Playback", WM8770_PWDNCTRL, 5, 1),
+
+	SND_SOC_DAPM_SUPPLY("VOUT12 Supply", SND_SOC_NOPM, 0, 0,
+		vout12supply_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("VOUT34 Supply", SND_SOC_NOPM, 0, 0,
+		vout34supply_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER("VOUT1 Mixer", SND_SOC_NOPM, 0, 0,
+		vout1_mix_controls, ARRAY_SIZE(vout1_mix_controls)),
+	SND_SOC_DAPM_MIXER("VOUT2 Mixer", SND_SOC_NOPM, 0, 0,
+		vout2_mix_controls, ARRAY_SIZE(vout2_mix_controls)),
+	SND_SOC_DAPM_MIXER("VOUT3 Mixer", SND_SOC_NOPM, 0, 0,
+		vout3_mix_controls, ARRAY_SIZE(vout3_mix_controls)),
+	SND_SOC_DAPM_MIXER("VOUT4 Mixer", SND_SOC_NOPM, 0, 0,
+		vout4_mix_controls, ARRAY_SIZE(vout4_mix_controls)),
+
+	SND_SOC_DAPM_OUTPUT("VOUT1"),
+	SND_SOC_DAPM_OUTPUT("VOUT2"),
+	SND_SOC_DAPM_OUTPUT("VOUT3"),
+	SND_SOC_DAPM_OUTPUT("VOUT4")
+};
+
+static const struct snd_soc_dapm_route wm8770_intercon[] = {
+	{ "Capture Mux", "AIN1", "AIN1" },
+	{ "Capture Mux", "AIN2", "AIN2" },
+	{ "Capture Mux", "AIN3", "AIN3" },
+	{ "Capture Mux", "AIN4", "AIN4" },
+	{ "Capture Mux", "AIN5", "AIN5" },
+	{ "Capture Mux", "AIN6", "AIN6" },
+	{ "Capture Mux", "AIN7", "AIN7" },
+	{ "Capture Mux", "AIN8", "AIN8" },
+
+	{ "ADC", NULL, "Capture Mux" },
+
+	{ "VOUT1 Mixer", NULL, "VOUT12 Supply" },
+	{ "VOUT1 Mixer", "DAC1 Switch", "DAC1" },
+	{ "VOUT1 Mixer", "AUX1 Switch", "AUX1" },
+	{ "VOUT1 Mixer", "Bypass Switch", "Capture Mux" },
+
+	{ "VOUT2 Mixer", NULL, "VOUT12 Supply" },
+	{ "VOUT2 Mixer", "DAC2 Switch", "DAC2" },
+	{ "VOUT2 Mixer", "AUX2 Switch", "AUX2" },
+	{ "VOUT2 Mixer", "Bypass Switch", "Capture Mux" },
+
+	{ "VOUT3 Mixer", NULL, "VOUT34 Supply" },
+	{ "VOUT3 Mixer", "DAC3 Switch", "DAC3" },
+	{ "VOUT3 Mixer", "AUX3 Switch", "AUX3" },
+	{ "VOUT3 Mixer", "Bypass Switch", "Capture Mux" },
+
+	{ "VOUT4 Mixer", NULL, "VOUT34 Supply" },
+	{ "VOUT4 Mixer", "DAC4 Switch", "DAC4" },
+	{ "VOUT4 Mixer", "Bypass Switch", "Capture Mux" },
+
+	{ "VOUT1", NULL, "VOUT1 Mixer" },
+	{ "VOUT2", NULL, "VOUT2 Mixer" },
+	{ "VOUT3", NULL, "VOUT3 Mixer" },
+	{ "VOUT4", NULL, "VOUT4 Mixer" }
+};
+
+static int vout12supply_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component, WM8770_OUTMUX1, 0x180, 0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, WM8770_OUTMUX1, 0x180, 0x180);
+		break;
+	}
+
+	return 0;
+}
+
+static int vout34supply_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_component_update_bits(component, WM8770_OUTMUX2, 0x180, 0);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, WM8770_OUTMUX2, 0x180, 0x180);
+		break;
+	}
+
+	return 0;
+}
+
+static int wm8770_reset(struct snd_soc_component *component)
+{
+	return snd_soc_component_write(component, WM8770_RESET, 0);
+}
+
+static int wm8770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component;
+	int iface, master;
+
+	component = dai->component;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		master = 0x100;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		master = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	iface = 0;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x2;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0xc;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x8;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x4;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8770_IFACECTRL, 0xf, iface);
+	snd_soc_component_update_bits(component, WM8770_MSTRCTRL, 0x100, master);
+
+	return 0;
+}
+
+static const int mclk_ratios[] = {
+	128,
+	192,
+	256,
+	384,
+	512,
+	768
+};
+
+static int wm8770_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component;
+	struct wm8770_priv *wm8770;
+	int i;
+	int iface;
+	int shift;
+	int ratio;
+
+	component = dai->component;
+	wm8770 = snd_soc_component_get_drvdata(component);
+
+	iface = 0;
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		iface |= 0x10;
+		break;
+	case 24:
+		iface |= 0x20;
+		break;
+	case 32:
+		iface |= 0x30;
+		break;
+	}
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		i = 0;
+		shift = 4;
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		i = 2;
+		shift = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Only need to set MCLK/LRCLK ratio if we're master */
+	if (snd_soc_component_read32(component, WM8770_MSTRCTRL) & 0x100) {
+		for (; i < ARRAY_SIZE(mclk_ratios); ++i) {
+			ratio = wm8770->sysclk / params_rate(params);
+			if (ratio == mclk_ratios[i])
+				break;
+		}
+
+		if (i == ARRAY_SIZE(mclk_ratios)) {
+			dev_err(component->dev,
+				"Unable to configure MCLK ratio %d/%d\n",
+				wm8770->sysclk, params_rate(params));
+			return -EINVAL;
+		}
+
+		dev_dbg(component->dev, "MCLK is %dfs\n", mclk_ratios[i]);
+
+		snd_soc_component_update_bits(component, WM8770_MSTRCTRL, 0x7 << shift,
+				    i << shift);
+	}
+
+	snd_soc_component_update_bits(component, WM8770_IFACECTRL, 0x30, iface);
+
+	return 0;
+}
+
+static int wm8770_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component;
+
+	component = dai->component;
+	return snd_soc_component_update_bits(component, WM8770_DACMUTE, 0x10,
+				   !!mute << 4);
+}
+
+static int wm8770_set_sysclk(struct snd_soc_dai *dai,
+			     int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component;
+	struct wm8770_priv *wm8770;
+
+	component = dai->component;
+	wm8770 = snd_soc_component_get_drvdata(component);
+	wm8770->sysclk = freq;
+	return 0;
+}
+
+static int wm8770_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	int ret;
+	struct wm8770_priv *wm8770;
+
+	wm8770 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
+						    wm8770->supplies);
+			if (ret) {
+				dev_err(component->dev,
+					"Failed to enable supplies: %d\n",
+					ret);
+				return ret;
+			}
+
+			regcache_sync(wm8770->regmap);
+
+			/* global powerup */
+			snd_soc_component_write(component, WM8770_PWDNCTRL, 0);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* global powerdown */
+		snd_soc_component_write(component, WM8770_PWDNCTRL, 1);
+		regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies),
+				       wm8770->supplies);
+		break;
+	}
+
+	return 0;
+}
+
+#define WM8770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8770_dai_ops = {
+	.digital_mute = wm8770_mute,
+	.hw_params = wm8770_hw_params,
+	.set_fmt = wm8770_set_fmt,
+	.set_sysclk = wm8770_set_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8770_dai = {
+	.name = "wm8770-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = WM8770_FORMATS
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = WM8770_FORMATS
+	},
+	.ops = &wm8770_dai_ops,
+	.symmetric_rates = 1
+};
+
+static int wm8770_probe(struct snd_soc_component *component)
+{
+	struct wm8770_priv *wm8770;
+	int ret;
+
+	wm8770 = snd_soc_component_get_drvdata(component);
+	wm8770->component = component;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
+				    wm8770->supplies);
+	if (ret) {
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = wm8770_reset(component);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
+		goto err_reg_enable;
+	}
+
+	/* latch the volume update bits */
+	snd_soc_component_update_bits(component, WM8770_MSDIGVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_MSALGVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_VOUT1RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_VOUT2RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_VOUT3RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_VOUT4RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_DAC1RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_DAC2RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_DAC3RVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8770_DAC4RVOL, 0x100, 0x100);
+
+	/* mute all DACs */
+	snd_soc_component_update_bits(component, WM8770_DACMUTE, 0x10, 0x10);
+
+err_reg_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
+	return ret;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8770 = {
+	.probe			= wm8770_probe,
+	.set_bias_level		= wm8770_set_bias_level,
+	.controls		= wm8770_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8770_snd_controls),
+	.dapm_widgets		= wm8770_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8770_dapm_widgets),
+	.dapm_routes		= wm8770_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(wm8770_intercon),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct of_device_id wm8770_of_match[] = {
+	{ .compatible = "wlf,wm8770", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wm8770_of_match);
+
+static const struct regmap_config wm8770_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+	.max_register = WM8770_RESET,
+
+	.reg_defaults = wm8770_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8770_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = wm8770_volatile_reg,
+};
+
+static int wm8770_spi_probe(struct spi_device *spi)
+{
+	struct wm8770_priv *wm8770;
+	int ret, i;
+
+	wm8770 = devm_kzalloc(&spi->dev, sizeof(struct wm8770_priv),
+			      GFP_KERNEL);
+	if (!wm8770)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++)
+		wm8770->supplies[i].supply = wm8770_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8770->supplies),
+				      wm8770->supplies);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	wm8770->disable_nb[0].notifier_call = wm8770_regulator_event_0;
+	wm8770->disable_nb[1].notifier_call = wm8770_regulator_event_1;
+	wm8770->disable_nb[2].notifier_call = wm8770_regulator_event_2;
+
+	/* This should really be moved into the regulator core */
+	for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) {
+		ret = regulator_register_notifier(wm8770->supplies[i].consumer,
+						  &wm8770->disable_nb[i]);
+		if (ret) {
+			dev_err(&spi->dev,
+				"Failed to register regulator notifier: %d\n",
+				ret);
+		}
+	}
+
+	wm8770->regmap = devm_regmap_init_spi(spi, &wm8770_regmap);
+	if (IS_ERR(wm8770->regmap))
+		return PTR_ERR(wm8770->regmap);
+
+	spi_set_drvdata(spi, wm8770);
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+				     &soc_component_dev_wm8770, &wm8770_dai, 1);
+
+	return ret;
+}
+
+static int wm8770_spi_remove(struct spi_device *spi)
+{
+	struct wm8770_priv *wm8770 = spi_get_drvdata(spi);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i)
+		regulator_unregister_notifier(wm8770->supplies[i].consumer,
+					      &wm8770->disable_nb[i]);
+
+	return 0;
+}
+
+static struct spi_driver wm8770_spi_driver = {
+	.driver = {
+		.name = "wm8770",
+		.of_match_table = wm8770_of_match,
+	},
+	.probe = wm8770_spi_probe,
+	.remove = wm8770_spi_remove
+};
+
+module_spi_driver(wm8770_spi_driver);
+
+MODULE_DESCRIPTION("ASoC WM8770 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8770.h b/sound/soc/codecs/wm8770.h
new file mode 100644
index 0000000..5f1b3bd
--- /dev/null
+++ b/sound/soc/codecs/wm8770.h
@@ -0,0 +1,51 @@
+/*
+ * wm8770.h  --  WM8770 ASoC driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8770_H
+#define _WM8770_H
+
+/* Registers */
+#define WM8770_VOUT1LVOL                0
+#define WM8770_VOUT1RVOL                0x1
+#define WM8770_VOUT2LVOL                0x2
+#define WM8770_VOUT2RVOL                0x3
+#define WM8770_VOUT3LVOL                0x4
+#define WM8770_VOUT3RVOL                0x5
+#define WM8770_VOUT4LVOL                0x6
+#define WM8770_VOUT4RVOL                0x7
+#define WM8770_MSALGVOL                 0x8
+#define WM8770_DAC1LVOL                 0x9
+#define WM8770_DAC1RVOL                 0xa
+#define WM8770_DAC2LVOL                 0xb
+#define WM8770_DAC2RVOL                 0xc
+#define WM8770_DAC3LVOL                 0xd
+#define WM8770_DAC3RVOL                 0xe
+#define WM8770_DAC4LVOL                 0xf
+#define WM8770_DAC4RVOL                 0x10
+#define WM8770_MSDIGVOL                 0x11
+#define WM8770_DACPHASE                 0x12
+#define WM8770_DACCTRL1                 0x13
+#define WM8770_DACMUTE                  0x14
+#define WM8770_DACCTRL2                 0x15
+#define WM8770_IFACECTRL                0x16
+#define WM8770_MSTRCTRL                 0x17
+#define WM8770_PWDNCTRL                 0x18
+#define WM8770_ADCLCTRL                 0x19
+#define WM8770_ADCRCTRL                 0x1a
+#define WM8770_ADCMUX                   0x1b
+#define WM8770_OUTMUX1                  0x1c
+#define WM8770_OUTMUX2                  0x1d
+#define WM8770_RESET                    0x31
+
+#define WM8770_CACHEREGNUM 0x20
+
+#endif
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
new file mode 100644
index 0000000..fb357e2
--- /dev/null
+++ b/sound/soc/codecs/wm8776.c
@@ -0,0 +1,569 @@
+/*
+ * wm8776.c  --  WM8776 ALSA SoC Audio driver
+ *
+ * Copyright 2009-12 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * TODO: Input ALC/limiter support
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8776.h"
+
+enum wm8776_chip_type {
+	WM8775 = 1,
+	WM8776,
+};
+
+/* codec private data */
+struct wm8776_priv {
+	struct regmap *regmap;
+	int sysclk[2];
+};
+
+static const struct reg_default wm8776_reg_defaults[] = {
+	{  0, 0x79 },
+	{  1, 0x79 },
+	{  2, 0x79 },
+	{  3, 0xff },
+	{  4, 0xff },
+	{  5, 0xff },
+	{  6, 0x00 },
+	{  7, 0x90 },
+	{  8, 0x00 },
+	{  9, 0x00 },
+	{ 10, 0x22 },
+	{ 11, 0x22 },
+	{ 12, 0x22 },
+	{ 13, 0x08 },
+	{ 14, 0xcf },
+	{ 15, 0xcf },
+	{ 16, 0x7b },
+	{ 17, 0x00 },
+	{ 18, 0x32 },
+	{ 19, 0x00 },
+	{ 20, 0xa6 },
+	{ 21, 0x01 },
+	{ 22, 0x01 },
+};
+
+static bool wm8776_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8776_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int wm8776_reset(struct snd_soc_component *component)
+{
+	return snd_soc_component_write(component, WM8776_RESET, 0);
+}
+
+static const DECLARE_TLV_DB_SCALE(hp_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -10350, 50, 1);
+
+static const struct snd_kcontrol_new wm8776_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8776_HPLVOL, WM8776_HPRVOL,
+		 0, 127, 0, hp_tlv),
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8776_DACLVOL, WM8776_DACRVOL,
+		 0, 255, 0, dac_tlv),
+SOC_SINGLE("Digital Playback ZC Switch", WM8776_DACCTRL1, 0, 1, 0),
+
+SOC_SINGLE("Deemphasis Switch", WM8776_DACCTRL2, 0, 1, 0),
+
+SOC_DOUBLE_R_TLV("Capture Volume", WM8776_ADCLVOL, WM8776_ADCRVOL,
+		 0, 255, 0, adc_tlv),
+SOC_DOUBLE("Capture Switch", WM8776_ADCMUX, 7, 6, 1, 1),
+SOC_DOUBLE_R("Capture ZC Switch", WM8776_ADCLVOL, WM8776_ADCRVOL, 8, 1, 0),
+SOC_SINGLE("Capture HPF Switch", WM8776_ADCIFCTRL, 8, 1, 1),
+};
+
+static const struct snd_kcontrol_new inmix_controls[] = {
+SOC_DAPM_SINGLE("AIN1 Switch", WM8776_ADCMUX, 0, 1, 0),
+SOC_DAPM_SINGLE("AIN2 Switch", WM8776_ADCMUX, 1, 1, 0),
+SOC_DAPM_SINGLE("AIN3 Switch", WM8776_ADCMUX, 2, 1, 0),
+SOC_DAPM_SINGLE("AIN4 Switch", WM8776_ADCMUX, 3, 1, 0),
+SOC_DAPM_SINGLE("AIN5 Switch", WM8776_ADCMUX, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new outmix_controls[] = {
+SOC_DAPM_SINGLE("DAC Switch", WM8776_OUTMUX, 0, 1, 0),
+SOC_DAPM_SINGLE("AUX Switch", WM8776_OUTMUX, 1, 1, 0),
+SOC_DAPM_SINGLE("Bypass Switch", WM8776_OUTMUX, 2, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8776_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AUX"),
+
+SND_SOC_DAPM_INPUT("AIN1"),
+SND_SOC_DAPM_INPUT("AIN2"),
+SND_SOC_DAPM_INPUT("AIN3"),
+SND_SOC_DAPM_INPUT("AIN4"),
+SND_SOC_DAPM_INPUT("AIN5"),
+
+SND_SOC_DAPM_MIXER("Input Mixer", WM8776_PWRDOWN, 6, 1,
+		   inmix_controls, ARRAY_SIZE(inmix_controls)),
+
+SND_SOC_DAPM_ADC("ADC", "Capture", WM8776_PWRDOWN, 1, 1),
+SND_SOC_DAPM_DAC("DAC", "Playback", WM8776_PWRDOWN, 2, 1),
+
+SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
+		   outmix_controls, ARRAY_SIZE(outmix_controls)),
+
+SND_SOC_DAPM_PGA("Headphone PGA", WM8776_PWRDOWN, 3, 1, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("VOUT"),
+
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+};
+
+static const struct snd_soc_dapm_route routes[] = {
+	{ "Input Mixer", "AIN1 Switch", "AIN1" },
+	{ "Input Mixer", "AIN2 Switch", "AIN2" },
+	{ "Input Mixer", "AIN3 Switch", "AIN3" },
+	{ "Input Mixer", "AIN4 Switch", "AIN4" },
+	{ "Input Mixer", "AIN5 Switch", "AIN5" },
+
+	{ "ADC", NULL, "Input Mixer" },
+
+	{ "Output Mixer", "DAC Switch", "DAC" },
+	{ "Output Mixer", "AUX Switch", "AUX" },
+	{ "Output Mixer", "Bypass Switch", "Input Mixer" },
+
+	{ "VOUT", NULL, "Output Mixer" },
+
+	{ "Headphone PGA", NULL, "Output Mixer" },
+
+	{ "HPOUTL", NULL, "Headphone PGA" },
+	{ "HPOUTR", NULL, "Headphone PGA" },
+};
+
+static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	int reg, iface, master;
+
+	switch (dai->driver->id) {
+	case WM8776_DAI_DAC:
+		reg = WM8776_DACIFCTRL;
+		master = 0x80;
+		break;
+	case WM8776_DAI_ADC:
+		reg = WM8776_ADCIFCTRL;
+		master = 0x100;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	iface = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		master = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x00c;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x008;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x004;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Finally, write out the values */
+	snd_soc_component_update_bits(component, reg, 0xf, iface);
+	snd_soc_component_update_bits(component, WM8776_MSTRCTRL, 0x180, master);
+
+	return 0;
+}
+
+static int mclk_ratios[] = {
+	128,
+	192,
+	256,
+	384,
+	512,
+	768,
+};
+
+static int wm8776_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8776_priv *wm8776 = snd_soc_component_get_drvdata(component);
+	int iface_reg, iface;
+	int ratio_shift, master;
+	int i;
+
+	switch (dai->driver->id) {
+	case WM8776_DAI_DAC:
+		iface_reg = WM8776_DACIFCTRL;
+		master = 0x80;
+		ratio_shift = 4;
+		break;
+	case WM8776_DAI_ADC:
+		iface_reg = WM8776_ADCIFCTRL;
+		master = 0x100;
+		ratio_shift = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Set word length */
+	switch (params_width(params)) {
+	case 16:
+		iface = 0;
+		break;
+	case 20:
+		iface = 0x10;
+		break;
+	case 24:
+		iface = 0x20;
+		break;
+	case 32:
+		iface = 0x30;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported sample size: %i\n",
+			params_width(params));
+		return -EINVAL;
+	}
+
+	/* Only need to set MCLK/LRCLK ratio if we're master */
+	if (snd_soc_component_read32(component, WM8776_MSTRCTRL) & master) {
+		for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) {
+			if (wm8776->sysclk[dai->driver->id] / params_rate(params)
+			    == mclk_ratios[i])
+				break;
+		}
+
+		if (i == ARRAY_SIZE(mclk_ratios)) {
+			dev_err(component->dev,
+				"Unable to configure MCLK ratio %d/%d\n",
+				wm8776->sysclk[dai->driver->id], params_rate(params));
+			return -EINVAL;
+		}
+
+		dev_dbg(component->dev, "MCLK is %dfs\n", mclk_ratios[i]);
+
+		snd_soc_component_update_bits(component, WM8776_MSTRCTRL,
+				    0x7 << ratio_shift, i << ratio_shift);
+	} else {
+		dev_dbg(component->dev, "DAI in slave mode\n");
+	}
+
+	snd_soc_component_update_bits(component, iface_reg, 0x30, iface);
+
+	return 0;
+}
+
+static int wm8776_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+
+	return snd_soc_component_write(component, WM8776_DACMUTE, !!mute);
+}
+
+static int wm8776_set_sysclk(struct snd_soc_dai *dai,
+			     int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8776_priv *wm8776 = snd_soc_component_get_drvdata(component);
+
+	if (WARN_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk)))
+		return -EINVAL;
+
+	wm8776->sysclk[dai->driver->id] = freq;
+
+	return 0;
+}
+
+static int wm8776_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8776_priv *wm8776 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			regcache_sync(wm8776->regmap);
+
+			/* Disable the global powerdown; DAPM does the rest */
+			snd_soc_component_update_bits(component, WM8776_PWRDOWN, 1, 0);
+		}
+
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, WM8776_PWRDOWN, 1, 1);
+		break;
+	}
+
+	return 0;
+}
+
+#define WM8776_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8776_dac_ops = {
+	.digital_mute	= wm8776_mute,
+	.hw_params      = wm8776_hw_params,
+	.set_fmt        = wm8776_set_fmt,
+	.set_sysclk     = wm8776_set_sysclk,
+};
+
+static const struct snd_soc_dai_ops wm8776_adc_ops = {
+	.hw_params      = wm8776_hw_params,
+	.set_fmt        = wm8776_set_fmt,
+	.set_sysclk     = wm8776_set_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8776_dai[] = {
+	{
+		.name = "wm8776-hifi-playback",
+		.id	= WM8776_DAI_DAC,
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_CONTINUOUS,
+			.rate_min = 32000,
+			.rate_max = 192000,
+			.formats = WM8776_FORMATS,
+		},
+		.ops = &wm8776_dac_ops,
+	},
+	{
+		.name = "wm8776-hifi-capture",
+		.id	= WM8776_DAI_ADC,
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_CONTINUOUS,
+			.rate_min = 32000,
+			.rate_max = 96000,
+			.formats = WM8776_FORMATS,
+		},
+		.ops = &wm8776_adc_ops,
+	},
+};
+
+static int wm8776_probe(struct snd_soc_component *component)
+{
+	int ret = 0;
+
+	ret = wm8776_reset(component);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
+		return ret;
+	}
+
+	/* Latch the update bits; right channel only since we always
+	 * update both. */
+	snd_soc_component_update_bits(component, WM8776_HPRVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8776_DACRVOL, 0x100, 0x100);
+
+	return ret;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8776 = {
+	.probe			= wm8776_probe,
+	.set_bias_level		= wm8776_set_bias_level,
+	.controls		= wm8776_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8776_snd_controls),
+	.dapm_widgets		= wm8776_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8776_dapm_widgets),
+	.dapm_routes		= routes,
+	.num_dapm_routes	= ARRAY_SIZE(routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct of_device_id wm8776_of_match[] = {
+	{ .compatible = "wlf,wm8776", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wm8776_of_match);
+
+static const struct regmap_config wm8776_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+	.max_register = WM8776_RESET,
+
+	.reg_defaults = wm8776_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8776_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = wm8776_volatile,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8776_spi_probe(struct spi_device *spi)
+{
+	struct wm8776_priv *wm8776;
+	int ret;
+
+	wm8776 = devm_kzalloc(&spi->dev, sizeof(struct wm8776_priv),
+			      GFP_KERNEL);
+	if (wm8776 == NULL)
+		return -ENOMEM;
+
+	wm8776->regmap = devm_regmap_init_spi(spi, &wm8776_regmap);
+	if (IS_ERR(wm8776->regmap))
+		return PTR_ERR(wm8776->regmap);
+
+	spi_set_drvdata(spi, wm8776);
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
+
+	return ret;
+}
+
+static struct spi_driver wm8776_spi_driver = {
+	.driver = {
+		.name	= "wm8776",
+		.of_match_table = wm8776_of_match,
+	},
+	.probe		= wm8776_spi_probe,
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8776_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8776_priv *wm8776;
+	int ret;
+
+	wm8776 = devm_kzalloc(&i2c->dev, sizeof(struct wm8776_priv),
+			      GFP_KERNEL);
+	if (wm8776 == NULL)
+		return -ENOMEM;
+
+	wm8776->regmap = devm_regmap_init_i2c(i2c, &wm8776_regmap);
+	if (IS_ERR(wm8776->regmap))
+		return PTR_ERR(wm8776->regmap);
+
+	i2c_set_clientdata(i2c, wm8776);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8776_i2c_id[] = {
+	{ "wm8775", WM8775 },
+	{ "wm8776", WM8776 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id);
+
+static struct i2c_driver wm8776_i2c_driver = {
+	.driver = {
+		.name = "wm8776",
+		.of_match_table = wm8776_of_match,
+	},
+	.probe =    wm8776_i2c_probe,
+	.id_table = wm8776_i2c_id,
+};
+#endif
+
+static int __init wm8776_modinit(void)
+{
+	int ret = 0;
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&wm8776_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8776_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register wm8776 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return ret;
+}
+module_init(wm8776_modinit);
+
+static void __exit wm8776_exit(void)
+{
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&wm8776_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8776_spi_driver);
+#endif
+}
+module_exit(wm8776_exit);
+
+MODULE_DESCRIPTION("ASoC WM8776 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8776.h b/sound/soc/codecs/wm8776.h
new file mode 100644
index 0000000..4cf1c8e
--- /dev/null
+++ b/sound/soc/codecs/wm8776.h
@@ -0,0 +1,48 @@
+/*
+ * wm8776.h  --  WM8776 ASoC driver
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8776_H
+#define _WM8776_H
+
+/* Registers */
+
+#define WM8776_HPLVOL    0x00
+#define WM8776_HPRVOL    0x01
+#define WM8776_HPMASTER  0x02
+#define WM8776_DACLVOL   0x03
+#define WM8776_DACRVOL   0x04
+#define WM8776_DACMASTER 0x05
+#define WM8776_PHASESWAP 0x06
+#define WM8776_DACCTRL1  0x07
+#define WM8776_DACMUTE   0x08
+#define WM8776_DACCTRL2  0x09
+#define WM8776_DACIFCTRL 0x0a
+#define WM8776_ADCIFCTRL 0x0b
+#define WM8776_MSTRCTRL  0x0c
+#define WM8776_PWRDOWN   0x0d
+#define WM8776_ADCLVOL   0x0e
+#define WM8776_ADCRVOL   0x0f
+#define WM8776_ALCCTRL1  0x10
+#define WM8776_ALCCTRL2  0x11
+#define WM8776_ALCCTRL3  0x12
+#define WM8776_NOISEGATE 0x13
+#define WM8776_LIMITER   0x14
+#define WM8776_ADCMUX    0x15
+#define WM8776_OUTMUX    0x16
+#define WM8776_RESET     0x17
+
+#define WM8776_CACHEREGNUM 0x17
+
+#define WM8776_DAI_DAC 0
+#define WM8776_DAI_ADC 1
+
+#endif
diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c
new file mode 100644
index 0000000..317db9a
--- /dev/null
+++ b/sound/soc/codecs/wm8782.c
@@ -0,0 +1,90 @@
+/*
+ * sound/soc/codecs/wm8782.c
+ * simple, strap-pin configured 24bit 2ch ADC
+ *
+ * Copyright: 2011 Raumfeld GmbH
+ * Author: Johannes Stezenbach <js@sig21.net>
+ *
+ * based on ad73311.c
+ * Copyright:	Analog Device Inc.
+ * Author:	Cliff Cai <cliff.cai@analog.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+static const struct snd_soc_dapm_widget wm8782_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AINL"),
+SND_SOC_DAPM_INPUT("AINR"),
+};
+
+static const struct snd_soc_dapm_route wm8782_dapm_routes[] = {
+	{ "Capture", NULL, "AINL" },
+	{ "Capture", NULL, "AINR" },
+};
+
+static struct snd_soc_dai_driver wm8782_dai = {
+	.name = "wm8782",
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		/* For configurations with FSAMPEN=0 */
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			   SNDRV_PCM_FMTBIT_S20_3LE |
+			   SNDRV_PCM_FMTBIT_S24_LE,
+	},
+};
+
+static const struct snd_soc_component_driver soc_component_dev_wm8782 = {
+	.dapm_widgets		= wm8782_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8782_dapm_widgets),
+	.dapm_routes		= wm8782_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8782_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm8782_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm8782, &wm8782_dai, 1);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id wm8782_of_match[] = {
+	{ .compatible = "wlf,wm8782", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wm8782_of_match);
+#endif
+
+static struct platform_driver wm8782_codec_driver = {
+	.driver = {
+		.name = "wm8782",
+		.of_match_table = of_match_ptr(wm8782_of_match),
+	},
+	.probe = wm8782_probe,
+};
+
+module_platform_driver(wm8782_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM8782 driver");
+MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c
new file mode 100644
index 0000000..7954196
--- /dev/null
+++ b/sound/soc/codecs/wm8804-i2c.c
@@ -0,0 +1,77 @@
+/*
+ * wm8804-i2c.c  --  WM8804 S/PDIF transceiver driver - I2C
+ *
+ * Copyright 2015 Cirrus Logic Inc
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+
+#include "wm8804.h"
+
+static int wm8804_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return wm8804_probe(&i2c->dev, regmap);
+}
+
+static int wm8804_i2c_remove(struct i2c_client *i2c)
+{
+	wm8804_remove(&i2c->dev);
+	return 0;
+}
+
+static const struct i2c_device_id wm8804_i2c_id[] = {
+	{ "wm8804", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id wm8804_of_match[] = {
+	{ .compatible = "wlf,wm8804", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wm8804_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id wm8804_acpi_match[] = {
+	{ "1AEC8804", 0 }, /* Wolfson PCI ID + part ID */
+	{ "10138804", 0 }, /* Cirrus Logic PCI ID + part ID */
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, wm8804_acpi_match);
+#endif
+
+static struct i2c_driver wm8804_i2c_driver = {
+	.driver = {
+		.name = "wm8804",
+		.pm = &wm8804_pm,
+		.of_match_table = of_match_ptr(wm8804_of_match),
+		.acpi_match_table = ACPI_PTR(wm8804_acpi_match),
+	},
+	.probe = wm8804_i2c_probe,
+	.remove = wm8804_i2c_remove,
+	.id_table = wm8804_i2c_id
+};
+
+module_i2c_driver(wm8804_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8804 driver - I2C");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8804-spi.c b/sound/soc/codecs/wm8804-spi.c
new file mode 100644
index 0000000..9998c78
--- /dev/null
+++ b/sound/soc/codecs/wm8804-spi.c
@@ -0,0 +1,56 @@
+/*
+ * wm8804-spi.c  --  WM8804 S/PDIF transceiver driver - SPI
+ *
+ * Copyright 2015 Cirrus Logic Inc
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "wm8804.h"
+
+static int wm8804_spi_probe(struct spi_device *spi)
+{
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return wm8804_probe(&spi->dev, regmap);
+}
+
+static int wm8804_spi_remove(struct spi_device *spi)
+{
+	wm8804_remove(&spi->dev);
+	return 0;
+}
+
+static const struct of_device_id wm8804_of_match[] = {
+	{ .compatible = "wlf,wm8804", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wm8804_of_match);
+
+static struct spi_driver wm8804_spi_driver = {
+	.driver = {
+		.name = "wm8804",
+		.pm = &wm8804_pm,
+		.of_match_table = wm8804_of_match,
+	},
+	.probe = wm8804_spi_probe,
+	.remove = wm8804_spi_remove
+};
+
+module_spi_driver(wm8804_spi_driver);
+
+MODULE_DESCRIPTION("ASoC WM8804 driver - SPI");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
new file mode 100644
index 0000000..89f1324
--- /dev/null
+++ b/sound/soc/codecs/wm8804.c
@@ -0,0 +1,730 @@
+/*
+ * wm8804.c  --  WM8804 S/PDIF transceiver driver
+ *
+ * Copyright 2010-11 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/gpio/consumer.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/soc-dapm.h>
+
+#include "wm8804.h"
+
+#define WM8804_NUM_SUPPLIES 2
+static const char *wm8804_supply_names[WM8804_NUM_SUPPLIES] = {
+	"PVDD",
+	"DVDD"
+};
+
+static const struct reg_default wm8804_reg_defaults[] = {
+	{ 3,  0x21 },     /* R3  - PLL1 */
+	{ 4,  0xFD },     /* R4  - PLL2 */
+	{ 5,  0x36 },     /* R5  - PLL3 */
+	{ 6,  0x07 },     /* R6  - PLL4 */
+	{ 7,  0x16 },     /* R7  - PLL5 */
+	{ 8,  0x18 },     /* R8  - PLL6 */
+	{ 9,  0xFF },     /* R9  - SPDMODE */
+	{ 10, 0x00 },     /* R10 - INTMASK */
+	{ 18, 0x00 },     /* R18 - SPDTX1 */
+	{ 19, 0x00 },     /* R19 - SPDTX2 */
+	{ 20, 0x00 },     /* R20 - SPDTX3 */
+	{ 21, 0x71 },     /* R21 - SPDTX4 */
+	{ 22, 0x0B },     /* R22 - SPDTX5 */
+	{ 23, 0x70 },     /* R23 - GPO0 */
+	{ 24, 0x57 },     /* R24 - GPO1 */
+	{ 26, 0x42 },     /* R26 - GPO2 */
+	{ 27, 0x06 },     /* R27 - AIFTX */
+	{ 28, 0x06 },     /* R28 - AIFRX */
+	{ 29, 0x80 },     /* R29 - SPDRX1 */
+	{ 30, 0x07 },     /* R30 - PWRDN */
+};
+
+struct wm8804_priv {
+	struct device *dev;
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES];
+	struct notifier_block disable_nb[WM8804_NUM_SUPPLIES];
+	int mclk_div;
+
+	struct gpio_desc *reset;
+
+	int aif_pwr;
+};
+
+static int txsrc_put(struct snd_kcontrol *kcontrol,
+		     struct snd_ctl_elem_value *ucontrol);
+
+static int wm8804_aif_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event);
+
+/*
+ * We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8804_REGULATOR_EVENT(n) \
+static int wm8804_regulator_event_##n(struct notifier_block *nb, \
+				      unsigned long event, void *data)    \
+{ \
+	struct wm8804_priv *wm8804 = container_of(nb, struct wm8804_priv, \
+						  disable_nb[n]); \
+	if (event & REGULATOR_EVENT_DISABLE) { \
+		regcache_mark_dirty(wm8804->regmap);	\
+	} \
+	return 0; \
+}
+
+WM8804_REGULATOR_EVENT(0)
+WM8804_REGULATOR_EVENT(1)
+
+static const char *txsrc_text[] = { "S/PDIF RX", "AIF" };
+static SOC_ENUM_SINGLE_DECL(txsrc, WM8804_SPDTX4, 6, txsrc_text);
+
+static const struct snd_kcontrol_new wm8804_tx_source_mux[] = {
+	SOC_DAPM_ENUM_EXT("Input Source", txsrc,
+			  snd_soc_dapm_get_enum_double, txsrc_put),
+};
+
+static const struct snd_soc_dapm_widget wm8804_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("SPDIF Out"),
+SND_SOC_DAPM_INPUT("SPDIF In"),
+
+SND_SOC_DAPM_PGA("SPDIFTX", WM8804_PWRDN, 2, 1, NULL, 0),
+SND_SOC_DAPM_PGA("SPDIFRX", WM8804_PWRDN, 1, 1, NULL, 0),
+
+SND_SOC_DAPM_MUX("Tx Source", SND_SOC_NOPM, 6, 0, wm8804_tx_source_mux),
+
+SND_SOC_DAPM_AIF_OUT_E("AIFTX", NULL, 0, SND_SOC_NOPM, 0, 0, wm8804_aif_event,
+		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_AIF_IN_E("AIFRX", NULL, 0, SND_SOC_NOPM, 0, 0, wm8804_aif_event,
+		      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route wm8804_dapm_routes[] = {
+	{ "AIFRX", NULL, "Playback" },
+	{ "Tx Source", "AIF", "AIFRX" },
+
+	{ "SPDIFRX", NULL, "SPDIF In" },
+	{ "Tx Source", "S/PDIF RX", "SPDIFRX" },
+
+	{ "SPDIFTX", NULL, "Tx Source" },
+	{ "SPDIF Out", NULL, "SPDIFTX" },
+
+	{ "AIFTX", NULL, "SPDIFRX" },
+	{ "Capture", NULL, "AIFTX" },
+};
+
+static int wm8804_aif_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8804_priv *wm8804 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* power up the aif */
+		if (!wm8804->aif_pwr)
+			snd_soc_component_update_bits(component, WM8804_PWRDN, 0x10, 0x0);
+		wm8804->aif_pwr++;
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* power down only both paths are disabled */
+		wm8804->aif_pwr--;
+		if (!wm8804->aif_pwr)
+			snd_soc_component_update_bits(component, WM8804_PWRDN, 0x10, 0x10);
+		break;
+	}
+
+	return 0;
+}
+
+static int txsrc_put(struct snd_kcontrol *kcontrol,
+		     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int val = ucontrol->value.enumerated.item[0] << e->shift_l;
+	unsigned int mask = 1 << e->shift_l;
+	unsigned int txpwr;
+
+	if (val != 0 && val != mask)
+		return -EINVAL;
+
+	snd_soc_dapm_mutex_lock(dapm);
+
+	if (snd_soc_component_test_bits(component, e->reg, mask, val)) {
+		/* save the current power state of the transmitter */
+		txpwr = snd_soc_component_read32(component, WM8804_PWRDN) & 0x4;
+
+		/* power down the transmitter */
+		snd_soc_component_update_bits(component, WM8804_PWRDN, 0x4, 0x4);
+
+		/* set the tx source */
+		snd_soc_component_update_bits(component, e->reg, mask, val);
+
+		/* restore the transmitter's configuration */
+		snd_soc_component_update_bits(component, WM8804_PWRDN, 0x4, txpwr);
+	}
+
+	snd_soc_dapm_mutex_unlock(dapm);
+
+	return 0;
+}
+
+static bool wm8804_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8804_RST_DEVID1:
+	case WM8804_DEVID2:
+	case WM8804_DEVREV:
+	case WM8804_INTSTAT:
+	case WM8804_SPDSTAT:
+	case WM8804_RXCHAN1:
+	case WM8804_RXCHAN2:
+	case WM8804_RXCHAN3:
+	case WM8804_RXCHAN4:
+	case WM8804_RXCHAN5:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int wm8804_soft_reset(struct wm8804_priv *wm8804)
+{
+	return regmap_write(wm8804->regmap, WM8804_RST_DEVID1, 0x0);
+}
+
+static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component;
+	u16 format, master, bcp, lrp;
+
+	component = dai->component;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		format = 0x2;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		format = 0x0;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		format = 0x1;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		format = 0x3;
+		break;
+	default:
+		dev_err(dai->dev, "Unknown dai format\n");
+		return -EINVAL;
+	}
+
+	/* set data format */
+	snd_soc_component_update_bits(component, WM8804_AIFTX, 0x3, format);
+	snd_soc_component_update_bits(component, WM8804_AIFRX, 0x3, format);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		master = 0;
+		break;
+	default:
+		dev_err(dai->dev, "Unknown master/slave configuration\n");
+		return -EINVAL;
+	}
+
+	/* set master/slave mode */
+	snd_soc_component_update_bits(component, WM8804_AIFRX, 0x40, master << 6);
+
+	bcp = lrp = 0;
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		bcp = lrp = 1;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		bcp = 1;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		lrp = 1;
+		break;
+	default:
+		dev_err(dai->dev, "Unknown polarity configuration\n");
+		return -EINVAL;
+	}
+
+	/* set frame inversion */
+	snd_soc_component_update_bits(component, WM8804_AIFTX, 0x10 | 0x20,
+			    (bcp << 4) | (lrp << 5));
+	snd_soc_component_update_bits(component, WM8804_AIFRX, 0x10 | 0x20,
+			    (bcp << 4) | (lrp << 5));
+	return 0;
+}
+
+static int wm8804_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component;
+	u16 blen;
+
+	component = dai->component;
+
+	switch (params_width(params)) {
+	case 16:
+		blen = 0x0;
+		break;
+	case 20:
+		blen = 0x1;
+		break;
+	case 24:
+		blen = 0x2;
+		break;
+	default:
+		dev_err(dai->dev, "Unsupported word length: %u\n",
+			params_width(params));
+		return -EINVAL;
+	}
+
+	/* set word length */
+	snd_soc_component_update_bits(component, WM8804_AIFTX, 0xc, blen << 2);
+	snd_soc_component_update_bits(component, WM8804_AIFRX, 0xc, blen << 2);
+
+	return 0;
+}
+
+struct pll_div {
+	u32 prescale:1;
+	u32 mclkdiv:1;
+	u32 freqmode:2;
+	u32 n:4;
+	u32 k:22;
+};
+
+/* PLL rate to output rate divisions */
+static struct {
+	unsigned int div;
+	unsigned int freqmode;
+	unsigned int mclkdiv;
+} post_table[] = {
+	{  2,  0, 0 },
+	{  4,  0, 1 },
+	{  4,  1, 0 },
+	{  8,  1, 1 },
+	{  8,  2, 0 },
+	{ 16,  2, 1 },
+	{ 12,  3, 0 },
+	{ 24,  3, 1 }
+};
+
+#define FIXED_PLL_SIZE ((1ULL << 22) * 10)
+static int pll_factors(struct pll_div *pll_div, unsigned int target,
+		       unsigned int source, unsigned int mclk_div)
+{
+	u64 Kpart;
+	unsigned long int K, Ndiv, Nmod, tmp;
+	int i;
+
+	/*
+	 * Scale the output frequency up; the PLL should run in the
+	 * region of 90-100MHz.
+	 */
+	for (i = 0; i < ARRAY_SIZE(post_table); i++) {
+		tmp = target * post_table[i].div;
+		if ((tmp >= 90000000 && tmp <= 100000000) &&
+		    (mclk_div == post_table[i].mclkdiv)) {
+			pll_div->freqmode = post_table[i].freqmode;
+			pll_div->mclkdiv = post_table[i].mclkdiv;
+			target *= post_table[i].div;
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(post_table)) {
+		pr_err("%s: Unable to scale output frequency: %uHz\n",
+		       __func__, target);
+		return -EINVAL;
+	}
+
+	pll_div->prescale = 0;
+	Ndiv = target / source;
+	if (Ndiv < 5) {
+		source >>= 1;
+		pll_div->prescale = 1;
+		Ndiv = target / source;
+	}
+
+	if (Ndiv < 5 || Ndiv > 13) {
+		pr_err("%s: WM8804 N value is not within the recommended range: %lu\n",
+		       __func__, Ndiv);
+		return -EINVAL;
+	}
+	pll_div->n = Ndiv;
+
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (u64)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xffffffff;
+	if ((K % 10) >= 5)
+		K += 5;
+	K /= 10;
+	pll_div->k = K;
+
+	return 0;
+}
+
+static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
+			  int source, unsigned int freq_in,
+			  unsigned int freq_out)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8804_priv *wm8804 = snd_soc_component_get_drvdata(component);
+	bool change;
+
+	if (!freq_in || !freq_out) {
+		/* disable the PLL */
+		regmap_update_bits_check(wm8804->regmap, WM8804_PWRDN,
+					 0x1, 0x1, &change);
+		if (change)
+			pm_runtime_put(wm8804->dev);
+	} else {
+		int ret;
+		struct pll_div pll_div;
+
+		ret = pll_factors(&pll_div, freq_out, freq_in,
+				  wm8804->mclk_div);
+		if (ret)
+			return ret;
+
+		/* power down the PLL before reprogramming it */
+		regmap_update_bits_check(wm8804->regmap, WM8804_PWRDN,
+					 0x1, 0x1, &change);
+		if (!change)
+			pm_runtime_get_sync(wm8804->dev);
+
+		/* set PLLN and PRESCALE */
+		snd_soc_component_update_bits(component, WM8804_PLL4, 0xf | 0x10,
+				    pll_div.n | (pll_div.prescale << 4));
+		/* set mclkdiv and freqmode */
+		snd_soc_component_update_bits(component, WM8804_PLL5, 0x3 | 0x8,
+				    pll_div.freqmode | (pll_div.mclkdiv << 3));
+		/* set PLLK */
+		snd_soc_component_write(component, WM8804_PLL1, pll_div.k & 0xff);
+		snd_soc_component_write(component, WM8804_PLL2, (pll_div.k >> 8) & 0xff);
+		snd_soc_component_write(component, WM8804_PLL3, pll_div.k >> 16);
+
+		/* power up the PLL */
+		snd_soc_component_update_bits(component, WM8804_PWRDN, 0x1, 0);
+	}
+
+	return 0;
+}
+
+static int wm8804_set_sysclk(struct snd_soc_dai *dai,
+			     int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component;
+
+	component = dai->component;
+
+	switch (clk_id) {
+	case WM8804_TX_CLKSRC_MCLK:
+		if ((freq >= 10000000 && freq <= 14400000)
+				|| (freq >= 16280000 && freq <= 27000000))
+			snd_soc_component_update_bits(component, WM8804_PLL6, 0x80, 0x80);
+		else {
+			dev_err(dai->dev, "OSCCLOCK is not within the "
+				"recommended range: %uHz\n", freq);
+			return -EINVAL;
+		}
+		break;
+	case WM8804_TX_CLKSRC_PLL:
+		snd_soc_component_update_bits(component, WM8804_PLL6, 0x80, 0);
+		break;
+	case WM8804_CLKOUT_SRC_CLK1:
+		snd_soc_component_update_bits(component, WM8804_PLL6, 0x8, 0);
+		break;
+	case WM8804_CLKOUT_SRC_OSCCLK:
+		snd_soc_component_update_bits(component, WM8804_PLL6, 0x8, 0x8);
+		break;
+	default:
+		dev_err(dai->dev, "Unknown clock source: %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
+			     int div_id, int div)
+{
+	struct snd_soc_component *component;
+	struct wm8804_priv *wm8804;
+
+	component = dai->component;
+	switch (div_id) {
+	case WM8804_CLKOUT_DIV:
+		snd_soc_component_update_bits(component, WM8804_PLL5, 0x30,
+				    (div & 0x3) << 4);
+		break;
+	case WM8804_MCLK_DIV:
+		wm8804 = snd_soc_component_get_drvdata(component);
+		wm8804->mclk_div = div;
+		break;
+	default:
+		dev_err(dai->dev, "Unknown clock divider: %d\n", div_id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops wm8804_dai_ops = {
+	.hw_params = wm8804_hw_params,
+	.set_fmt = wm8804_set_fmt,
+	.set_sysclk = wm8804_set_sysclk,
+	.set_clkdiv = wm8804_set_clkdiv,
+	.set_pll = wm8804_set_pll
+};
+
+#define WM8804_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE)
+
+#define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+		      SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
+		      SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
+		      SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
+
+static struct snd_soc_dai_driver wm8804_dai = {
+	.name = "wm8804-spdif",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM8804_RATES,
+		.formats = WM8804_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM8804_RATES,
+		.formats = WM8804_FORMATS,
+	},
+	.ops = &wm8804_dai_ops,
+	.symmetric_rates = 1
+};
+
+static const struct snd_soc_component_driver soc_component_dev_wm8804 = {
+	.dapm_widgets		= wm8804_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8804_dapm_widgets),
+	.dapm_routes		= wm8804_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8804_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+const struct regmap_config wm8804_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = WM8804_MAX_REGISTER,
+	.volatile_reg = wm8804_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8804_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults),
+};
+EXPORT_SYMBOL_GPL(wm8804_regmap_config);
+
+int wm8804_probe(struct device *dev, struct regmap *regmap)
+{
+	struct wm8804_priv *wm8804;
+	unsigned int id1, id2;
+	int i, ret;
+
+	wm8804 = devm_kzalloc(dev, sizeof(*wm8804), GFP_KERNEL);
+	if (!wm8804)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, wm8804);
+
+	wm8804->dev = dev;
+	wm8804->regmap = regmap;
+
+	wm8804->reset = devm_gpiod_get_optional(dev, "wlf,reset",
+						GPIOD_OUT_LOW);
+	if (IS_ERR(wm8804->reset)) {
+		ret = PTR_ERR(wm8804->reset);
+		dev_err(dev, "Failed to get reset line: %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
+		wm8804->supplies[i].supply = wm8804_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8804->supplies),
+				      wm8804->supplies);
+	if (ret) {
+		dev_err(dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0;
+	wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1;
+
+	/* This should really be moved into the regulator core */
+	for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) {
+		struct regulator *regulator = wm8804->supplies[i].consumer;
+
+		ret = devm_regulator_register_notifier(regulator,
+						       &wm8804->disable_nb[i]);
+		if (ret != 0) {
+			dev_err(dev,
+				"Failed to register regulator notifier: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
+				    wm8804->supplies);
+	if (ret) {
+		dev_err(dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	gpiod_set_value_cansleep(wm8804->reset, 1);
+
+	ret = regmap_read(regmap, WM8804_RST_DEVID1, &id1);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read device ID: %d\n", ret);
+		goto err_reg_enable;
+	}
+
+	ret = regmap_read(regmap, WM8804_DEVID2, &id2);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read device ID: %d\n", ret);
+		goto err_reg_enable;
+	}
+
+	id2 = (id2 << 8) | id1;
+
+	if (id2 != 0x8805) {
+		dev_err(dev, "Invalid device ID: %#x\n", id2);
+		ret = -EINVAL;
+		goto err_reg_enable;
+	}
+
+	ret = regmap_read(regmap, WM8804_DEVREV, &id1);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read device revision: %d\n",
+			ret);
+		goto err_reg_enable;
+	}
+	dev_info(dev, "revision %c\n", id1 + 'A');
+
+	if (!wm8804->reset) {
+		ret = wm8804_soft_reset(wm8804);
+		if (ret < 0) {
+			dev_err(dev, "Failed to issue reset: %d\n", ret);
+			goto err_reg_enable;
+		}
+	}
+
+	ret = devm_snd_soc_register_component(dev, &soc_component_dev_wm8804,
+				     &wm8804_dai, 1);
+	if (ret < 0) {
+		dev_err(dev, "Failed to register CODEC: %d\n", ret);
+		goto err_reg_enable;
+	}
+
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	pm_runtime_idle(dev);
+
+	return 0;
+
+err_reg_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm8804_probe);
+
+void wm8804_remove(struct device *dev)
+{
+	pm_runtime_disable(dev);
+}
+EXPORT_SYMBOL_GPL(wm8804_remove);
+
+#if IS_ENABLED(CONFIG_PM)
+static int wm8804_runtime_resume(struct device *dev)
+{
+	struct wm8804_priv *wm8804 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
+				    wm8804->supplies);
+	if (ret) {
+		dev_err(wm8804->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	regcache_sync(wm8804->regmap);
+
+	/* Power up OSCCLK */
+	regmap_update_bits(wm8804->regmap, WM8804_PWRDN, 0x8, 0x0);
+
+	return 0;
+}
+
+static int wm8804_runtime_suspend(struct device *dev)
+{
+	struct wm8804_priv *wm8804 = dev_get_drvdata(dev);
+
+	/* Power down OSCCLK */
+	regmap_update_bits(wm8804->regmap, WM8804_PWRDN, 0x8, 0x8);
+
+	regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies),
+			       wm8804->supplies);
+
+	return 0;
+}
+#endif
+
+const struct dev_pm_ops wm8804_pm = {
+	SET_RUNTIME_PM_OPS(wm8804_runtime_suspend, wm8804_runtime_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(wm8804_pm);
+
+MODULE_DESCRIPTION("ASoC WM8804 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8804.h b/sound/soc/codecs/wm8804.h
new file mode 100644
index 0000000..aa72fa6
--- /dev/null
+++ b/sound/soc/codecs/wm8804.h
@@ -0,0 +1,73 @@
+/*
+ * wm8804.h  --  WM8804 S/PDIF transceiver driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8804_H
+#define _WM8804_H
+
+#include <linux/regmap.h>
+
+/*
+ * Register values.
+ */
+#define WM8804_RST_DEVID1			0x00
+#define WM8804_DEVID2				0x01
+#define WM8804_DEVREV				0x02
+#define WM8804_PLL1				0x03
+#define WM8804_PLL2				0x04
+#define WM8804_PLL3				0x05
+#define WM8804_PLL4				0x06
+#define WM8804_PLL5				0x07
+#define WM8804_PLL6				0x08
+#define WM8804_SPDMODE				0x09
+#define WM8804_INTMASK				0x0A
+#define WM8804_INTSTAT				0x0B
+#define WM8804_SPDSTAT				0x0C
+#define WM8804_RXCHAN1				0x0D
+#define WM8804_RXCHAN2				0x0E
+#define WM8804_RXCHAN3				0x0F
+#define WM8804_RXCHAN4				0x10
+#define WM8804_RXCHAN5				0x11
+#define WM8804_SPDTX1				0x12
+#define WM8804_SPDTX2				0x13
+#define WM8804_SPDTX3				0x14
+#define WM8804_SPDTX4				0x15
+#define WM8804_SPDTX5				0x16
+#define WM8804_GPO0				0x17
+#define WM8804_GPO1				0x18
+#define WM8804_GPO2				0x1A
+#define WM8804_AIFTX				0x1B
+#define WM8804_AIFRX				0x1C
+#define WM8804_SPDRX1				0x1D
+#define WM8804_PWRDN				0x1E
+
+#define WM8804_REGISTER_COUNT			30
+#define WM8804_MAX_REGISTER			0x1E
+
+#define WM8804_TX_CLKSRC_MCLK			1
+#define WM8804_TX_CLKSRC_PLL			2
+
+#define WM8804_CLKOUT_SRC_CLK1			3
+#define WM8804_CLKOUT_SRC_OSCCLK		4
+
+#define WM8804_CLKOUT_DIV			1
+#define WM8804_MCLK_DIV				2
+
+#define WM8804_MCLKDIV_256FS			0
+#define WM8804_MCLKDIV_128FS			1
+
+extern const struct regmap_config wm8804_regmap_config;
+extern const struct dev_pm_ops wm8804_pm;
+
+int wm8804_probe(struct device *dev, struct regmap *regmap);
+void wm8804_remove(struct device *dev);
+
+#endif  /* _WM8804_H */
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
new file mode 100644
index 0000000..1a14e90
--- /dev/null
+++ b/sound/soc/codecs/wm8900.c
@@ -0,0 +1,1356 @@
+/*
+ * wm8900.c  --  WM8900 ALSA Soc Audio driver
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * TODO:
+ *  - Tristating.
+ *  - TDM.
+ *  - Jack detect.
+ *  - FLL source configuration, currently only MCLK is supported.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8900.h"
+
+/* WM8900 register space */
+#define WM8900_REG_RESET	0x0
+#define WM8900_REG_ID		0x0
+#define WM8900_REG_POWER1	0x1
+#define WM8900_REG_POWER2	0x2
+#define WM8900_REG_POWER3	0x3
+#define WM8900_REG_AUDIO1	0x4
+#define WM8900_REG_AUDIO2	0x5
+#define WM8900_REG_CLOCKING1    0x6
+#define WM8900_REG_CLOCKING2    0x7
+#define WM8900_REG_AUDIO3       0x8
+#define WM8900_REG_AUDIO4       0x9
+#define WM8900_REG_DACCTRL      0xa
+#define WM8900_REG_LDAC_DV      0xb
+#define WM8900_REG_RDAC_DV      0xc
+#define WM8900_REG_SIDETONE     0xd
+#define WM8900_REG_ADCCTRL      0xe
+#define WM8900_REG_LADC_DV	0xf
+#define WM8900_REG_RADC_DV      0x10
+#define WM8900_REG_GPIO         0x12
+#define WM8900_REG_INCTL	0x15
+#define WM8900_REG_LINVOL	0x16
+#define WM8900_REG_RINVOL	0x17
+#define WM8900_REG_INBOOSTMIX1  0x18
+#define WM8900_REG_INBOOSTMIX2  0x19
+#define WM8900_REG_ADCPATH	0x1a
+#define WM8900_REG_AUXBOOST	0x1b
+#define WM8900_REG_ADDCTL       0x1e
+#define WM8900_REG_FLLCTL1      0x24
+#define WM8900_REG_FLLCTL2      0x25
+#define WM8900_REG_FLLCTL3      0x26
+#define WM8900_REG_FLLCTL4      0x27
+#define WM8900_REG_FLLCTL5      0x28
+#define WM8900_REG_FLLCTL6      0x29
+#define WM8900_REG_LOUTMIXCTL1  0x2c
+#define WM8900_REG_ROUTMIXCTL1  0x2d
+#define WM8900_REG_BYPASS1	0x2e
+#define WM8900_REG_BYPASS2	0x2f
+#define WM8900_REG_AUXOUT_CTL   0x30
+#define WM8900_REG_LOUT1CTL     0x33
+#define WM8900_REG_ROUT1CTL     0x34
+#define WM8900_REG_LOUT2CTL	0x35
+#define WM8900_REG_ROUT2CTL	0x36
+#define WM8900_REG_HPCTL1	0x3a
+#define WM8900_REG_OUTBIASCTL   0x73
+
+#define WM8900_MAXREG		0x80
+
+#define WM8900_REG_ADDCTL_OUT1_DIS    0x80
+#define WM8900_REG_ADDCTL_OUT2_DIS    0x40
+#define WM8900_REG_ADDCTL_VMID_DIS    0x20
+#define WM8900_REG_ADDCTL_BIAS_SRC    0x10
+#define WM8900_REG_ADDCTL_VMID_SOFTST 0x04
+#define WM8900_REG_ADDCTL_TEMP_SD     0x02
+
+#define WM8900_REG_GPIO_TEMP_ENA   0x2
+
+#define WM8900_REG_POWER1_STARTUP_BIAS_ENA 0x0100
+#define WM8900_REG_POWER1_BIAS_ENA         0x0008
+#define WM8900_REG_POWER1_VMID_BUF_ENA     0x0004
+#define WM8900_REG_POWER1_FLL_ENA          0x0040
+
+#define WM8900_REG_POWER2_SYSCLK_ENA  0x8000
+#define WM8900_REG_POWER2_ADCL_ENA    0x0002
+#define WM8900_REG_POWER2_ADCR_ENA    0x0001
+
+#define WM8900_REG_POWER3_DACL_ENA    0x0002
+#define WM8900_REG_POWER3_DACR_ENA    0x0001
+
+#define WM8900_REG_AUDIO1_AIF_FMT_MASK 0x0018
+#define WM8900_REG_AUDIO1_LRCLK_INV    0x0080
+#define WM8900_REG_AUDIO1_BCLK_INV     0x0100
+
+#define WM8900_REG_CLOCKING1_BCLK_DIR   0x1
+#define WM8900_REG_CLOCKING1_MCLK_SRC   0x100
+#define WM8900_REG_CLOCKING1_BCLK_MASK  0x01e
+#define WM8900_REG_CLOCKING1_OPCLK_MASK 0x7000
+
+#define WM8900_REG_CLOCKING2_ADC_CLKDIV 0xe0
+#define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c
+
+#define WM8900_REG_DACCTRL_MUTE          0x004
+#define WM8900_REG_DACCTRL_DAC_SB_FILT   0x100
+#define WM8900_REG_DACCTRL_AIF_LRCLKRATE 0x400
+
+#define WM8900_REG_AUDIO3_ADCLRC_DIR    0x0800
+
+#define WM8900_REG_AUDIO4_DACLRC_DIR    0x0800
+
+#define WM8900_REG_FLLCTL1_OSC_ENA    0x100
+
+#define WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF 0x100
+
+#define WM8900_REG_HPCTL1_HP_IPSTAGE_ENA 0x80
+#define WM8900_REG_HPCTL1_HP_OPSTAGE_ENA 0x40
+#define WM8900_REG_HPCTL1_HP_CLAMP_IP    0x20
+#define WM8900_REG_HPCTL1_HP_CLAMP_OP    0x10
+#define WM8900_REG_HPCTL1_HP_SHORT       0x08
+#define WM8900_REG_HPCTL1_HP_SHORT2      0x04
+
+#define WM8900_LRC_MASK 0x03ff
+
+struct wm8900_priv {
+	struct regmap *regmap;
+
+	u32 fll_in; /* FLL input frequency */
+	u32 fll_out; /* FLL output frequency */
+};
+
+/*
+ * wm8900 register cache.  We can't read the entire register space and we
+ * have slow control buses so we cache the registers.
+ */
+static const struct reg_default wm8900_reg_defaults[] = {
+	{  1, 0x0000 },
+	{  2, 0xc000 },
+	{  3, 0x0000 },
+	{  4, 0x4050 },
+	{  5, 0x4000 },
+	{  6, 0x0008 },
+	{  7, 0x0000 },
+	{  8, 0x0040 },
+	{  9, 0x0040 },
+	{ 10, 0x1004 },
+	{ 11, 0x00c0 },
+	{ 12, 0x00c0 },
+	{ 13, 0x0000 },
+	{ 14, 0x0100 },
+	{ 15, 0x00c0 },
+	{ 16, 0x00c0 },
+	{ 17, 0x0000 },
+	{ 18, 0xb001 },
+	{ 19, 0x0000 },
+	{ 20, 0x0000 },
+	{ 21, 0x0044 },
+	{ 22, 0x004c },
+	{ 23, 0x004c },
+	{ 24, 0x0044 },
+	{ 25, 0x0044 },
+	{ 26, 0x0000 },
+	{ 27, 0x0044 },
+	{ 28, 0x0000 },
+	{ 29, 0x0000 },
+	{ 30, 0x0002 },
+	{ 31, 0x0000 },
+	{ 32, 0x0000 },
+	{ 33, 0x0000 },
+	{ 34, 0x0000 },
+	{ 35, 0x0000 },
+	{ 36, 0x0008 },
+	{ 37, 0x0000 },
+	{ 38, 0x0000 },
+	{ 39, 0x0008 },
+	{ 40, 0x0097 },
+	{ 41, 0x0100 },
+	{ 42, 0x0000 },
+	{ 43, 0x0000 },
+	{ 44, 0x0050 },
+	{ 45, 0x0050 },
+	{ 46, 0x0055 },
+	{ 47, 0x0055 },
+	{ 48, 0x0055 },
+	{ 49, 0x0000 },
+	{ 50, 0x0000 },
+	{ 51, 0x0079 },
+	{ 52, 0x0079 },
+	{ 53, 0x0079 },
+	{ 54, 0x0079 },
+	{ 55, 0x0000 },
+};
+
+static bool wm8900_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8900_REG_ID:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void wm8900_reset(struct snd_soc_component *component)
+{
+	snd_soc_component_write(component, WM8900_REG_RESET, 0);
+}
+
+static int wm8900_hp_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 hpctl1 = snd_soc_component_read32(component, WM8900_REG_HPCTL1);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Clamp headphone outputs */
+		hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP |
+			WM8900_REG_HPCTL1_HP_CLAMP_OP;
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		/* Enable the input stage */
+		hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_IP;
+		hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT |
+			WM8900_REG_HPCTL1_HP_SHORT2 |
+			WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
+
+		msleep(400);
+
+		/* Enable the output stage */
+		hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP;
+		hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
+
+		/* Remove the shorts */
+		hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2;
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
+		hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT;
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Short the output */
+		hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT;
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
+
+		/* Disable the output stage */
+		hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
+
+		/* Clamp the outputs and power down input */
+		hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP |
+			WM8900_REG_HPCTL1_HP_CLAMP_OP;
+		hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, hpctl1);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		/* Disable everything */
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, 0);
+		break;
+
+	default:
+		WARN(1, "Invalid event %d\n", event);
+		break;
+	}
+
+	return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -5700, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 0);
+
+static const DECLARE_TLV_DB_SCALE(in_boost_tlv, -1200, 600, 0);
+
+static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1200, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1);
+
+static const DECLARE_TLV_DB_SCALE(adc_svol_tlv, -3600, 300, 0);
+
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1);
+
+static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" };
+
+static SOC_ENUM_SINGLE_DECL(mic_bias_level,
+			    WM8900_REG_INCTL, 8, mic_bias_level_txt);
+
+static const char *dac_mute_rate_txt[] = { "Fast", "Slow" };
+
+static SOC_ENUM_SINGLE_DECL(dac_mute_rate,
+			    WM8900_REG_DACCTRL, 7, dac_mute_rate_txt);
+
+static const char *dac_deemphasis_txt[] = {
+	"Disabled", "32kHz", "44.1kHz", "48kHz"
+};
+
+static SOC_ENUM_SINGLE_DECL(dac_deemphasis,
+			    WM8900_REG_DACCTRL, 4, dac_deemphasis_txt);
+
+static const char *adc_hpf_cut_txt[] = {
+	"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"
+};
+
+static SOC_ENUM_SINGLE_DECL(adc_hpf_cut,
+			    WM8900_REG_ADCCTRL, 5, adc_hpf_cut_txt);
+
+static const char *lr_txt[] = {
+	"Left", "Right"
+};
+
+static SOC_ENUM_SINGLE_DECL(aifl_src,
+			    WM8900_REG_AUDIO1, 15, lr_txt);
+
+static SOC_ENUM_SINGLE_DECL(aifr_src,
+			    WM8900_REG_AUDIO1, 14, lr_txt);
+
+static SOC_ENUM_SINGLE_DECL(dacl_src,
+			    WM8900_REG_AUDIO2, 15, lr_txt);
+
+static SOC_ENUM_SINGLE_DECL(dacr_src,
+			    WM8900_REG_AUDIO2, 14, lr_txt);
+
+static const char *sidetone_txt[] = {
+	"Disabled", "Left ADC", "Right ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(dacl_sidetone,
+			    WM8900_REG_SIDETONE, 2, sidetone_txt);
+
+static SOC_ENUM_SINGLE_DECL(dacr_sidetone,
+			    WM8900_REG_SIDETONE, 0, sidetone_txt);
+
+static const struct snd_kcontrol_new wm8900_snd_controls[] = {
+SOC_ENUM("Mic Bias Level", mic_bias_level),
+
+SOC_SINGLE_TLV("Left Input PGA Volume", WM8900_REG_LINVOL, 0, 31, 0,
+	       in_pga_tlv),
+SOC_SINGLE("Left Input PGA Switch", WM8900_REG_LINVOL, 6, 1, 1),
+SOC_SINGLE("Left Input PGA ZC Switch", WM8900_REG_LINVOL, 7, 1, 0),
+
+SOC_SINGLE_TLV("Right Input PGA Volume", WM8900_REG_RINVOL, 0, 31, 0,
+	       in_pga_tlv),
+SOC_SINGLE("Right Input PGA Switch", WM8900_REG_RINVOL, 6, 1, 1),
+SOC_SINGLE("Right Input PGA ZC Switch", WM8900_REG_RINVOL, 7, 1, 0),
+
+SOC_SINGLE("DAC Soft Mute Switch", WM8900_REG_DACCTRL, 6, 1, 1),
+SOC_ENUM("DAC Mute Rate", dac_mute_rate),
+SOC_SINGLE("DAC Mono Switch", WM8900_REG_DACCTRL, 9, 1, 0),
+SOC_ENUM("DAC Deemphasis", dac_deemphasis),
+SOC_SINGLE("DAC Sigma-Delta Modulator Clock Switch", WM8900_REG_DACCTRL,
+	   12, 1, 0),
+
+SOC_SINGLE("ADC HPF Switch", WM8900_REG_ADCCTRL, 8, 1, 0),
+SOC_ENUM("ADC HPF Cut-Off", adc_hpf_cut),
+SOC_DOUBLE("ADC Invert Switch", WM8900_REG_ADCCTRL, 1, 0, 1, 0),
+SOC_SINGLE_TLV("Left ADC Sidetone Volume", WM8900_REG_SIDETONE, 9, 12, 0,
+	       adc_svol_tlv),
+SOC_SINGLE_TLV("Right ADC Sidetone Volume", WM8900_REG_SIDETONE, 5, 12, 0,
+	       adc_svol_tlv),
+SOC_ENUM("Left Digital Audio Source", aifl_src),
+SOC_ENUM("Right Digital Audio Source", aifr_src),
+
+SOC_SINGLE_TLV("DAC Input Boost Volume", WM8900_REG_AUDIO2, 10, 4, 0,
+	       dac_boost_tlv),
+SOC_ENUM("Left DAC Source", dacl_src),
+SOC_ENUM("Right DAC Source", dacr_src),
+SOC_ENUM("Left DAC Sidetone", dacl_sidetone),
+SOC_ENUM("Right DAC Sidetone", dacr_sidetone),
+SOC_DOUBLE("DAC Invert Switch", WM8900_REG_DACCTRL, 1, 0, 1, 0),
+
+SOC_DOUBLE_R_TLV("Digital Playback Volume",
+		 WM8900_REG_LDAC_DV, WM8900_REG_RDAC_DV,
+		 1, 96, 0, dac_tlv),
+SOC_DOUBLE_R_TLV("Digital Capture Volume",
+		 WM8900_REG_LADC_DV, WM8900_REG_RADC_DV, 1, 119, 0, adc_tlv),
+
+SOC_SINGLE_TLV("LINPUT3 Bypass Volume", WM8900_REG_LOUTMIXCTL1, 4, 7, 0,
+	       out_mix_tlv),
+SOC_SINGLE_TLV("RINPUT3 Bypass Volume", WM8900_REG_ROUTMIXCTL1, 4, 7, 0,
+	       out_mix_tlv),
+SOC_SINGLE_TLV("Left AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 4, 7, 0,
+	       out_mix_tlv),
+SOC_SINGLE_TLV("Right AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 0, 7, 0,
+	       out_mix_tlv),
+
+SOC_SINGLE_TLV("LeftIn to RightOut Mixer Volume", WM8900_REG_BYPASS1, 0, 7, 0,
+	       out_mix_tlv),
+SOC_SINGLE_TLV("LeftIn to LeftOut Mixer Volume", WM8900_REG_BYPASS1, 4, 7, 0,
+	       out_mix_tlv),
+SOC_SINGLE_TLV("RightIn to LeftOut Mixer Volume", WM8900_REG_BYPASS2, 0, 7, 0,
+	       out_mix_tlv),
+SOC_SINGLE_TLV("RightIn to RightOut Mixer Volume", WM8900_REG_BYPASS2, 4, 7, 0,
+	       out_mix_tlv),
+
+SOC_SINGLE_TLV("IN2L Boost Volume", WM8900_REG_INBOOSTMIX1, 0, 3, 0,
+	       in_boost_tlv),
+SOC_SINGLE_TLV("IN3L Boost Volume", WM8900_REG_INBOOSTMIX1, 4, 3, 0,
+	       in_boost_tlv),
+SOC_SINGLE_TLV("IN2R Boost Volume", WM8900_REG_INBOOSTMIX2, 0, 3, 0,
+	       in_boost_tlv),
+SOC_SINGLE_TLV("IN3R Boost Volume", WM8900_REG_INBOOSTMIX2, 4, 3, 0,
+	       in_boost_tlv),
+SOC_SINGLE_TLV("Left AUX Boost Volume", WM8900_REG_AUXBOOST, 4, 3, 0,
+	       in_boost_tlv),
+SOC_SINGLE_TLV("Right AUX Boost Volume", WM8900_REG_AUXBOOST, 0, 3, 0,
+	       in_boost_tlv),
+
+SOC_DOUBLE_R_TLV("LINEOUT1 Volume", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL,
+	       0, 63, 0, out_pga_tlv),
+SOC_DOUBLE_R("LINEOUT1 Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL,
+	     6, 1, 1),
+SOC_DOUBLE_R("LINEOUT1 ZC Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL,
+	     7, 1, 0),
+
+SOC_DOUBLE_R_TLV("LINEOUT2 Volume",
+		 WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL,
+		 0, 63, 0, out_pga_tlv),
+SOC_DOUBLE_R("LINEOUT2 Switch",
+	     WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 6, 1, 1),
+SOC_DOUBLE_R("LINEOUT2 ZC Switch",
+	     WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 7, 1, 0),
+SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1,
+	   0, 1, 1),
+
+};
+
+static const struct snd_kcontrol_new wm8900_dapm_loutput2_control =
+SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0);
+
+static const struct snd_kcontrol_new wm8900_dapm_routput2_control =
+SOC_DAPM_SINGLE("LINEOUT2R Switch", WM8900_REG_POWER3, 5, 1, 0);
+
+static const struct snd_kcontrol_new wm8900_loutmix_controls[] = {
+SOC_DAPM_SINGLE("LINPUT3 Bypass Switch", WM8900_REG_LOUTMIXCTL1, 7, 1, 0),
+SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 7, 1, 0),
+SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 3, 1, 0),
+SOC_DAPM_SINGLE("DACL Switch", WM8900_REG_LOUTMIXCTL1, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_routmix_controls[] = {
+SOC_DAPM_SINGLE("RINPUT3 Bypass Switch", WM8900_REG_ROUTMIXCTL1, 7, 1, 0),
+SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 3, 1, 0),
+SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 3, 1, 0),
+SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 7, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8900_REG_ROUTMIXCTL1, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_linmix_controls[] = {
+SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INBOOSTMIX1, 2, 1, 1),
+SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INBOOSTMIX1, 6, 1, 1),
+SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 6, 1, 1),
+SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_rinmix_controls[] = {
+SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INBOOSTMIX2, 2, 1, 1),
+SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INBOOSTMIX2, 6, 1, 1),
+SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 2, 1, 1),
+SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_linpga_controls[] = {
+SOC_DAPM_SINGLE("LINPUT1 Switch", WM8900_REG_INCTL, 6, 1, 0),
+SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INCTL, 5, 1, 0),
+SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INCTL, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8900_rinpga_controls[] = {
+SOC_DAPM_SINGLE("RINPUT1 Switch", WM8900_REG_INCTL, 2, 1, 0),
+SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INCTL, 1, 1, 0),
+SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0),
+};
+
+static const char *wm8900_lp_mux[] = { "Disabled", "Enabled" };
+
+static SOC_ENUM_SINGLE_DECL(wm8900_lineout2_lp_mux,
+			    WM8900_REG_LOUTMIXCTL1, 1, wm8900_lp_mux);
+
+static const struct snd_kcontrol_new wm8900_lineout2_lp =
+SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux);
+
+static const struct snd_soc_dapm_widget wm8900_dapm_widgets[] = {
+
+/* Externally visible pins */
+SND_SOC_DAPM_OUTPUT("LINEOUT1L"),
+SND_SOC_DAPM_OUTPUT("LINEOUT1R"),
+SND_SOC_DAPM_OUTPUT("LINEOUT2L"),
+SND_SOC_DAPM_OUTPUT("LINEOUT2R"),
+SND_SOC_DAPM_OUTPUT("HP_L"),
+SND_SOC_DAPM_OUTPUT("HP_R"),
+
+SND_SOC_DAPM_INPUT("RINPUT1"),
+SND_SOC_DAPM_INPUT("LINPUT1"),
+SND_SOC_DAPM_INPUT("RINPUT2"),
+SND_SOC_DAPM_INPUT("LINPUT2"),
+SND_SOC_DAPM_INPUT("RINPUT3"),
+SND_SOC_DAPM_INPUT("LINPUT3"),
+SND_SOC_DAPM_INPUT("AUX"),
+
+SND_SOC_DAPM_VMID("VMID"),
+
+/* Input */
+SND_SOC_DAPM_MIXER("Left Input PGA", WM8900_REG_POWER2, 3, 0,
+		   wm8900_linpga_controls,
+		   ARRAY_SIZE(wm8900_linpga_controls)),
+SND_SOC_DAPM_MIXER("Right Input PGA", WM8900_REG_POWER2, 2, 0,
+		   wm8900_rinpga_controls,
+		   ARRAY_SIZE(wm8900_rinpga_controls)),
+
+SND_SOC_DAPM_MIXER("Left Input Mixer", WM8900_REG_POWER2, 5, 0,
+		   wm8900_linmix_controls,
+		   ARRAY_SIZE(wm8900_linmix_controls)),
+SND_SOC_DAPM_MIXER("Right Input Mixer", WM8900_REG_POWER2, 4, 0,
+		   wm8900_rinmix_controls,
+		   ARRAY_SIZE(wm8900_rinmix_controls)),
+
+SND_SOC_DAPM_SUPPLY("Mic Bias", WM8900_REG_POWER1, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8900_REG_POWER2, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8900_REG_POWER2, 0, 0),
+
+/* Output */
+SND_SOC_DAPM_DAC("DACL", "Left HiFi Playback", WM8900_REG_POWER3, 1, 0),
+SND_SOC_DAPM_DAC("DACR", "Right HiFi Playback", WM8900_REG_POWER3, 0, 0),
+
+SND_SOC_DAPM_PGA_E("Headphone Amplifier", WM8900_REG_POWER3, 7, 0, NULL, 0,
+		   wm8900_hp_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_PGA("LINEOUT1L PGA", WM8900_REG_POWER2, 8, 0, NULL, 0),
+SND_SOC_DAPM_PGA("LINEOUT1R PGA", WM8900_REG_POWER2, 7, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("LINEOUT2 LP", SND_SOC_NOPM, 0, 0, &wm8900_lineout2_lp),
+SND_SOC_DAPM_PGA("LINEOUT2L PGA", WM8900_REG_POWER3, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("LINEOUT2R PGA", WM8900_REG_POWER3, 5, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("Left Output Mixer", WM8900_REG_POWER3, 3, 0,
+		   wm8900_loutmix_controls,
+		   ARRAY_SIZE(wm8900_loutmix_controls)),
+SND_SOC_DAPM_MIXER("Right Output Mixer", WM8900_REG_POWER3, 2, 0,
+		   wm8900_routmix_controls,
+		   ARRAY_SIZE(wm8900_routmix_controls)),
+};
+
+/* Target, Path, Source */
+static const struct snd_soc_dapm_route wm8900_dapm_routes[] = {
+/* Inputs */
+{"Left Input PGA", "LINPUT1 Switch", "LINPUT1"},
+{"Left Input PGA", "LINPUT2 Switch", "LINPUT2"},
+{"Left Input PGA", "LINPUT3 Switch", "LINPUT3"},
+
+{"Right Input PGA", "RINPUT1 Switch", "RINPUT1"},
+{"Right Input PGA", "RINPUT2 Switch", "RINPUT2"},
+{"Right Input PGA", "RINPUT3 Switch", "RINPUT3"},
+
+{"Left Input Mixer", "LINPUT2 Switch", "LINPUT2"},
+{"Left Input Mixer", "LINPUT3 Switch", "LINPUT3"},
+{"Left Input Mixer", "AUX Switch", "AUX"},
+{"Left Input Mixer", "Input PGA Switch", "Left Input PGA"},
+
+{"Right Input Mixer", "RINPUT2 Switch", "RINPUT2"},
+{"Right Input Mixer", "RINPUT3 Switch", "RINPUT3"},
+{"Right Input Mixer", "AUX Switch", "AUX"},
+{"Right Input Mixer", "Input PGA Switch", "Right Input PGA"},
+
+{"ADCL", NULL, "Left Input Mixer"},
+{"ADCR", NULL, "Right Input Mixer"},
+
+/* Outputs */
+{"LINEOUT1L", NULL, "LINEOUT1L PGA"},
+{"LINEOUT1L PGA", NULL, "Left Output Mixer"},
+{"LINEOUT1R", NULL, "LINEOUT1R PGA"},
+{"LINEOUT1R PGA", NULL, "Right Output Mixer"},
+
+{"LINEOUT2L PGA", NULL, "Left Output Mixer"},
+{"LINEOUT2 LP", "Disabled", "LINEOUT2L PGA"},
+{"LINEOUT2 LP", "Enabled", "Left Output Mixer"},
+{"LINEOUT2L", NULL, "LINEOUT2 LP"},
+
+{"LINEOUT2R PGA", NULL, "Right Output Mixer"},
+{"LINEOUT2 LP", "Disabled", "LINEOUT2R PGA"},
+{"LINEOUT2 LP", "Enabled", "Right Output Mixer"},
+{"LINEOUT2R", NULL, "LINEOUT2 LP"},
+
+{"Left Output Mixer", "LINPUT3 Bypass Switch", "LINPUT3"},
+{"Left Output Mixer", "AUX Bypass Switch", "AUX"},
+{"Left Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"},
+{"Left Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"},
+{"Left Output Mixer", "DACL Switch", "DACL"},
+
+{"Right Output Mixer", "RINPUT3 Bypass Switch", "RINPUT3"},
+{"Right Output Mixer", "AUX Bypass Switch", "AUX"},
+{"Right Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"},
+{"Right Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"},
+{"Right Output Mixer", "DACR Switch", "DACR"},
+
+/* Note that the headphone output stage needs to be connected
+ * externally to LINEOUT2 via DC blocking capacitors.  Other
+ * configurations are not supported.
+ *
+ * Note also that left and right headphone paths are treated as a
+ * mono path.
+ */
+{"Headphone Amplifier", NULL, "LINEOUT2 LP"},
+{"Headphone Amplifier", NULL, "LINEOUT2 LP"},
+{"HP_L", NULL, "Headphone Amplifier"},
+{"HP_R", NULL, "Headphone Amplifier"},
+};
+
+static int wm8900_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 reg;
+
+	reg = snd_soc_component_read32(component, WM8900_REG_AUDIO1) & ~0x60;
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		reg |= 0x20;
+		break;
+	case 24:
+		reg |= 0x40;
+		break;
+	case 32:
+		reg |= 0x60;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8900_REG_AUDIO1, reg);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		reg = snd_soc_component_read32(component, WM8900_REG_DACCTRL);
+
+		if (params_rate(params) <= 24000)
+			reg |= WM8900_REG_DACCTRL_DAC_SB_FILT;
+		else
+			reg &= ~WM8900_REG_DACCTRL_DAC_SB_FILT;
+
+		snd_soc_component_write(component, WM8900_REG_DACCTRL, reg);
+	}
+
+	return 0;
+}
+
+/* FLL divisors */
+struct _fll_div {
+	u16 fll_ratio;
+	u16 fllclk_div;
+	u16 fll_slow_lock_ref;
+	u16 n;
+	u16 k;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+		       unsigned int Fout)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod, target;
+	unsigned int div;
+
+	if (WARN_ON(!Fout))
+		return -EINVAL;
+
+	/* The FLL must run at 90-100MHz which is then scaled down to
+	 * the output value by FLLCLK_DIV. */
+	target = Fout;
+	div = 1;
+	while (target < 90000000) {
+		div *= 2;
+		target *= 2;
+	}
+
+	if (target > 100000000)
+		printk(KERN_WARNING "wm8900: FLL rate %u out of range, Fref=%u"
+		       " Fout=%u\n", target, Fref, Fout);
+	if (div > 32) {
+		printk(KERN_ERR "wm8900: Invalid FLL division rate %u, "
+		       "Fref=%u, Fout=%u, target=%u\n",
+		       div, Fref, Fout, target);
+		return -EINVAL;
+	}
+
+	fll_div->fllclk_div = div >> 2;
+
+	if (Fref < 48000)
+		fll_div->fll_slow_lock_ref = 1;
+	else
+		fll_div->fll_slow_lock_ref = 0;
+
+	Ndiv = target / Fref;
+
+	if (Fref < 1000000)
+		fll_div->fll_ratio = 8;
+	else
+		fll_div->fll_ratio = 1;
+
+	fll_div->n = Ndiv / fll_div->fll_ratio;
+	Nmod = (target / fll_div->fll_ratio) % Fref;
+
+	/* Calculate fractional part - scale up so we can round. */
+	Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, Fref);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	fll_div->k = K / 10;
+
+	if (WARN_ON(target != Fout * (fll_div->fllclk_div << 2)) ||
+	    WARN_ON(!K && target != Fref * fll_div->fll_ratio * fll_div->n))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int wm8900_set_fll(struct snd_soc_component *component,
+	int fll_id, unsigned int freq_in, unsigned int freq_out)
+{
+	struct wm8900_priv *wm8900 = snd_soc_component_get_drvdata(component);
+	struct _fll_div fll_div;
+
+	if (wm8900->fll_in == freq_in && wm8900->fll_out == freq_out)
+		return 0;
+
+	/* The digital side should be disabled during any change. */
+	snd_soc_component_update_bits(component, WM8900_REG_POWER1,
+			    WM8900_REG_POWER1_FLL_ENA, 0);
+
+	/* Disable the FLL? */
+	if (!freq_in || !freq_out) {
+		snd_soc_component_update_bits(component, WM8900_REG_CLOCKING1,
+				    WM8900_REG_CLOCKING1_MCLK_SRC, 0);
+		snd_soc_component_update_bits(component, WM8900_REG_FLLCTL1,
+				    WM8900_REG_FLLCTL1_OSC_ENA, 0);
+		wm8900->fll_in = freq_in;
+		wm8900->fll_out = freq_out;
+
+		return 0;
+	}
+
+	if (fll_factors(&fll_div, freq_in, freq_out) != 0)
+		goto reenable;
+
+	wm8900->fll_in = freq_in;
+	wm8900->fll_out = freq_out;
+
+	/* The osclilator *MUST* be enabled before we enable the
+	 * digital circuit. */
+	snd_soc_component_write(component, WM8900_REG_FLLCTL1,
+		     fll_div.fll_ratio | WM8900_REG_FLLCTL1_OSC_ENA);
+
+	snd_soc_component_write(component, WM8900_REG_FLLCTL4, fll_div.n >> 5);
+	snd_soc_component_write(component, WM8900_REG_FLLCTL5,
+		     (fll_div.fllclk_div << 6) | (fll_div.n & 0x1f));
+
+	if (fll_div.k) {
+		snd_soc_component_write(component, WM8900_REG_FLLCTL2,
+			     (fll_div.k >> 8) | 0x100);
+		snd_soc_component_write(component, WM8900_REG_FLLCTL3, fll_div.k & 0xff);
+	} else
+		snd_soc_component_write(component, WM8900_REG_FLLCTL2, 0);
+
+	if (fll_div.fll_slow_lock_ref)
+		snd_soc_component_write(component, WM8900_REG_FLLCTL6,
+			     WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF);
+	else
+		snd_soc_component_write(component, WM8900_REG_FLLCTL6, 0);
+
+	snd_soc_component_update_bits(component, WM8900_REG_POWER1,
+			    WM8900_REG_POWER1_FLL_ENA,
+			    WM8900_REG_POWER1_FLL_ENA);
+
+reenable:
+	snd_soc_component_update_bits(component, WM8900_REG_CLOCKING1,
+			    WM8900_REG_CLOCKING1_MCLK_SRC,
+			    WM8900_REG_CLOCKING1_MCLK_SRC);
+	return 0;
+}
+
+static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+		int source, unsigned int freq_in, unsigned int freq_out)
+{
+	return wm8900_set_fll(codec_dai->component, pll_id, freq_in, freq_out);
+}
+
+static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+				 int div_id, int div)
+{
+	struct snd_soc_component *component = codec_dai->component;
+
+	switch (div_id) {
+	case WM8900_BCLK_DIV:
+		snd_soc_component_update_bits(component, WM8900_REG_CLOCKING1,
+				    WM8900_REG_CLOCKING1_BCLK_MASK, div);
+		break;
+	case WM8900_OPCLK_DIV:
+		snd_soc_component_update_bits(component, WM8900_REG_CLOCKING1,
+				    WM8900_REG_CLOCKING1_OPCLK_MASK, div);
+		break;
+	case WM8900_DAC_LRCLK:
+		snd_soc_component_update_bits(component, WM8900_REG_AUDIO4,
+				    WM8900_LRC_MASK, div);
+		break;
+	case WM8900_ADC_LRCLK:
+		snd_soc_component_update_bits(component, WM8900_REG_AUDIO3,
+				    WM8900_LRC_MASK, div);
+		break;
+	case WM8900_DAC_CLKDIV:
+		snd_soc_component_update_bits(component, WM8900_REG_CLOCKING2,
+				    WM8900_REG_CLOCKING2_DAC_CLKDIV, div);
+		break;
+	case WM8900_ADC_CLKDIV:
+		snd_soc_component_update_bits(component, WM8900_REG_CLOCKING2,
+				    WM8900_REG_CLOCKING2_ADC_CLKDIV, div);
+		break;
+	case WM8900_LRCLK_MODE:
+		snd_soc_component_update_bits(component, WM8900_REG_DACCTRL,
+				    WM8900_REG_DACCTRL_AIF_LRCLKRATE, div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	unsigned int clocking1, aif1, aif3, aif4;
+
+	clocking1 = snd_soc_component_read32(component, WM8900_REG_CLOCKING1);
+	aif1 = snd_soc_component_read32(component, WM8900_REG_AUDIO1);
+	aif3 = snd_soc_component_read32(component, WM8900_REG_AUDIO3);
+	aif4 = snd_soc_component_read32(component, WM8900_REG_AUDIO4);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR;
+		aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR;
+		aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR;
+		aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR;
+		aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR;
+		aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR;
+		aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR;
+		aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR;
+		aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		aif1 |= WM8900_REG_AUDIO1_AIF_FMT_MASK;
+		aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		aif1 |= WM8900_REG_AUDIO1_AIF_FMT_MASK;
+		aif1 |= WM8900_REG_AUDIO1_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK;
+		aif1 |= 0x10;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK;
+		aif1 |= 0x8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		/* frame inversion not valid for DSP modes */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif1 |= WM8900_REG_AUDIO1_BCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV;
+			aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			aif1 |= WM8900_REG_AUDIO1_BCLK_INV;
+			aif1 |= WM8900_REG_AUDIO1_LRCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif1 |= WM8900_REG_AUDIO1_BCLK_INV;
+			aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV;
+			aif1 |= WM8900_REG_AUDIO1_LRCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8900_REG_CLOCKING1, clocking1);
+	snd_soc_component_write(component, WM8900_REG_AUDIO1, aif1);
+	snd_soc_component_write(component, WM8900_REG_AUDIO3, aif3);
+	snd_soc_component_write(component, WM8900_REG_AUDIO4, aif4);
+
+	return 0;
+}
+
+static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 reg;
+
+	reg = snd_soc_component_read32(component, WM8900_REG_DACCTRL);
+
+	if (mute)
+		reg |= WM8900_REG_DACCTRL_MUTE;
+	else
+		reg &= ~WM8900_REG_DACCTRL_MUTE;
+
+	snd_soc_component_write(component, WM8900_REG_DACCTRL, reg);
+
+	return 0;
+}
+
+#define WM8900_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		      SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+		      SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define WM8900_PCM_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	 SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops wm8900_dai_ops = {
+	.hw_params	= wm8900_hw_params,
+	.set_clkdiv	= wm8900_set_dai_clkdiv,
+	.set_pll	= wm8900_set_dai_pll,
+	.set_fmt	= wm8900_set_dai_fmt,
+	.digital_mute	= wm8900_digital_mute,
+};
+
+static struct snd_soc_dai_driver wm8900_dai = {
+	.name = "wm8900-hifi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8900_RATES,
+		.formats = WM8900_PCM_FORMATS,
+	},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8900_RATES,
+		.formats = WM8900_PCM_FORMATS,
+	 },
+	.ops = &wm8900_dai_ops,
+};
+
+static int wm8900_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	u16 reg;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* Enable thermal shutdown */
+		snd_soc_component_update_bits(component, WM8900_REG_GPIO,
+				    WM8900_REG_GPIO_TEMP_ENA,
+				    WM8900_REG_GPIO_TEMP_ENA);
+		snd_soc_component_update_bits(component, WM8900_REG_ADDCTL,
+				    WM8900_REG_ADDCTL_TEMP_SD,
+				    WM8900_REG_ADDCTL_TEMP_SD);
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		/* Charge capacitors if initial power up */
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/* STARTUP_BIAS_ENA on */
+			snd_soc_component_write(component, WM8900_REG_POWER1,
+				     WM8900_REG_POWER1_STARTUP_BIAS_ENA);
+
+			/* Startup bias mode */
+			snd_soc_component_write(component, WM8900_REG_ADDCTL,
+				     WM8900_REG_ADDCTL_BIAS_SRC |
+				     WM8900_REG_ADDCTL_VMID_SOFTST);
+
+			/* VMID 2x50k */
+			snd_soc_component_write(component, WM8900_REG_POWER1,
+				     WM8900_REG_POWER1_STARTUP_BIAS_ENA | 0x1);
+
+			/* Allow capacitors to charge */
+			schedule_timeout_interruptible(msecs_to_jiffies(400));
+
+			/* Enable bias */
+			snd_soc_component_write(component, WM8900_REG_POWER1,
+				     WM8900_REG_POWER1_STARTUP_BIAS_ENA |
+				     WM8900_REG_POWER1_BIAS_ENA | 0x1);
+
+			snd_soc_component_write(component, WM8900_REG_ADDCTL, 0);
+
+			snd_soc_component_write(component, WM8900_REG_POWER1,
+				     WM8900_REG_POWER1_BIAS_ENA | 0x1);
+		}
+
+		reg = snd_soc_component_read32(component, WM8900_REG_POWER1);
+		snd_soc_component_write(component, WM8900_REG_POWER1,
+			     (reg & WM8900_REG_POWER1_FLL_ENA) |
+			     WM8900_REG_POWER1_BIAS_ENA | 0x1);
+		snd_soc_component_write(component, WM8900_REG_POWER2,
+			     WM8900_REG_POWER2_SYSCLK_ENA);
+		snd_soc_component_write(component, WM8900_REG_POWER3, 0);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* Startup bias enable */
+		reg = snd_soc_component_read32(component, WM8900_REG_POWER1);
+		snd_soc_component_write(component, WM8900_REG_POWER1,
+			     reg & WM8900_REG_POWER1_STARTUP_BIAS_ENA);
+		snd_soc_component_write(component, WM8900_REG_ADDCTL,
+			     WM8900_REG_ADDCTL_BIAS_SRC |
+			     WM8900_REG_ADDCTL_VMID_SOFTST);
+
+		/* Discharge caps */
+		snd_soc_component_write(component, WM8900_REG_POWER1,
+			     WM8900_REG_POWER1_STARTUP_BIAS_ENA);
+		schedule_timeout_interruptible(msecs_to_jiffies(500));
+
+		/* Remove clamp */
+		snd_soc_component_write(component, WM8900_REG_HPCTL1, 0);
+
+		/* Power down */
+		snd_soc_component_write(component, WM8900_REG_ADDCTL, 0);
+		snd_soc_component_write(component, WM8900_REG_POWER1, 0);
+		snd_soc_component_write(component, WM8900_REG_POWER2, 0);
+		snd_soc_component_write(component, WM8900_REG_POWER3, 0);
+
+		/* Need to let things settle before stopping the clock
+		 * to ensure that restart works, see "Stopping the
+		 * master clock" in the datasheet. */
+		schedule_timeout_interruptible(msecs_to_jiffies(1));
+		snd_soc_component_write(component, WM8900_REG_POWER2,
+			     WM8900_REG_POWER2_SYSCLK_ENA);
+		break;
+	}
+	return 0;
+}
+
+static int wm8900_suspend(struct snd_soc_component *component)
+{
+	struct wm8900_priv *wm8900 = snd_soc_component_get_drvdata(component);
+	int fll_out = wm8900->fll_out;
+	int fll_in  = wm8900->fll_in;
+	int ret;
+
+	/* Stop the FLL in an orderly fashion */
+	ret = wm8900_set_fll(component, 0, 0, 0);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to stop FLL\n");
+		return ret;
+	}
+
+	wm8900->fll_out = fll_out;
+	wm8900->fll_in = fll_in;
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int wm8900_resume(struct snd_soc_component *component)
+{
+	struct wm8900_priv *wm8900 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	wm8900_reset(component);
+
+	ret = regcache_sync(wm8900->regmap);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to restore cache: %d\n", ret);
+		return ret;
+	}
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	/* Restart the FLL? */
+	if (wm8900->fll_out) {
+		int fll_out = wm8900->fll_out;
+		int fll_in  = wm8900->fll_in;
+
+		wm8900->fll_in = 0;
+		wm8900->fll_out = 0;
+
+		ret = wm8900_set_fll(component, 0, fll_in, fll_out);
+		if (ret != 0) {
+			dev_err(component->dev, "Failed to restart FLL\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int wm8900_probe(struct snd_soc_component *component)
+{
+	int reg;
+
+	reg = snd_soc_component_read32(component, WM8900_REG_ID);
+	if (reg != 0x8900) {
+		dev_err(component->dev, "Device is not a WM8900 - ID %x\n", reg);
+		return -ENODEV;
+	}
+
+	wm8900_reset(component);
+
+	/* Turn the chip on */
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	/* Latch the volume update bits */
+	snd_soc_component_update_bits(component, WM8900_REG_LINVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_RINVOL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_LOUT1CTL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_ROUT1CTL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_LOUT2CTL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_ROUT2CTL, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_LDAC_DV, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_RDAC_DV, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_LADC_DV, 0x100, 0x100);
+	snd_soc_component_update_bits(component, WM8900_REG_RADC_DV, 0x100, 0x100);
+
+	/* Set the DAC and mixer output bias */
+	snd_soc_component_write(component, WM8900_REG_OUTBIASCTL, 0x81);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8900 = {
+	.probe			= wm8900_probe,
+	.suspend		= wm8900_suspend,
+	.resume			= wm8900_resume,
+	.set_bias_level		= wm8900_set_bias_level,
+	.controls		= wm8900_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8900_snd_controls),
+	.dapm_widgets		= wm8900_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8900_dapm_widgets),
+	.dapm_routes		= wm8900_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8900_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8900_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.max_register = WM8900_MAXREG,
+
+	.reg_defaults = wm8900_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8900_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = wm8900_volatile_register,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8900_spi_probe(struct spi_device *spi)
+{
+	struct wm8900_priv *wm8900;
+	int ret;
+
+	wm8900 = devm_kzalloc(&spi->dev, sizeof(struct wm8900_priv),
+			      GFP_KERNEL);
+	if (wm8900 == NULL)
+		return -ENOMEM;
+
+	wm8900->regmap = devm_regmap_init_spi(spi, &wm8900_regmap);
+	if (IS_ERR(wm8900->regmap))
+		return PTR_ERR(wm8900->regmap);
+
+	spi_set_drvdata(spi, wm8900);
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8900, &wm8900_dai, 1);
+
+	return ret;
+}
+
+static int wm8900_spi_remove(struct spi_device *spi)
+{
+	return 0;
+}
+
+static struct spi_driver wm8900_spi_driver = {
+	.driver = {
+		.name	= "wm8900",
+	},
+	.probe		= wm8900_spi_probe,
+	.remove		= wm8900_spi_remove,
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8900_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8900_priv *wm8900;
+	int ret;
+
+	wm8900 = devm_kzalloc(&i2c->dev, sizeof(struct wm8900_priv),
+			      GFP_KERNEL);
+	if (wm8900 == NULL)
+		return -ENOMEM;
+
+	wm8900->regmap = devm_regmap_init_i2c(i2c, &wm8900_regmap);
+	if (IS_ERR(wm8900->regmap))
+		return PTR_ERR(wm8900->regmap);
+
+	i2c_set_clientdata(i2c, wm8900);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8900, &wm8900_dai, 1);
+
+	return ret;
+}
+
+static int wm8900_i2c_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id wm8900_i2c_id[] = {
+	{ "wm8900", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id);
+
+static struct i2c_driver wm8900_i2c_driver = {
+	.driver = {
+		.name = "wm8900",
+	},
+	.probe =    wm8900_i2c_probe,
+	.remove =   wm8900_i2c_remove,
+	.id_table = wm8900_i2c_id,
+};
+#endif
+
+static int __init wm8900_modinit(void)
+{
+	int ret = 0;
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&wm8900_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register wm8900 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8900_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register wm8900 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return ret;
+}
+module_init(wm8900_modinit);
+
+static void __exit wm8900_exit(void)
+{
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&wm8900_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8900_spi_driver);
+#endif
+}
+module_exit(wm8900_exit);
+
+MODULE_DESCRIPTION("ASoC WM8900 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h
new file mode 100644
index 0000000..583f257
--- /dev/null
+++ b/sound/soc/codecs/wm8900.h
@@ -0,0 +1,55 @@
+/*
+ * wm8900.h  --  WM890 Soc Audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8900_H
+#define _WM8900_H
+
+#define WM8900_FLL 1
+
+#define WM8900_BCLK_DIV   1
+#define WM8900_ADC_CLKDIV 2
+#define WM8900_DAC_CLKDIV 3
+#define WM8900_ADC_LRCLK  4
+#define WM8900_DAC_LRCLK  5
+#define WM8900_OPCLK_DIV  6
+#define WM8900_LRCLK_MODE 7
+
+#define WM8900_BCLK_DIV_1   0x00
+#define WM8900_BCLK_DIV_1_5 0x02
+#define WM8900_BCLK_DIV_2   0x04
+#define WM8900_BCLK_DIV_3   0x06
+#define WM8900_BCLK_DIV_4   0x08
+#define WM8900_BCLK_DIV_5_5 0x0a
+#define WM8900_BCLK_DIV_6   0x0c
+#define WM8900_BCLK_DIV_8   0x0e
+#define WM8900_BCLK_DIV_11  0x10
+#define WM8900_BCLK_DIV_12  0x12
+#define WM8900_BCLK_DIV_16  0x14
+#define WM8900_BCLK_DIV_22  0x16
+#define WM8900_BCLK_DIV_24  0x18
+#define WM8900_BCLK_DIV_32  0x1a
+#define WM8900_BCLK_DIV_44  0x1c
+#define WM8900_BCLK_DIV_48  0x1e
+
+#define WM8900_ADC_CLKDIV_1   0x00
+#define WM8900_ADC_CLKDIV_1_5 0x20
+#define WM8900_ADC_CLKDIV_2   0x40
+#define WM8900_ADC_CLKDIV_3   0x60
+#define WM8900_ADC_CLKDIV_4   0x80
+#define WM8900_ADC_CLKDIV_5_5 0xa0
+#define WM8900_ADC_CLKDIV_6   0xc0
+
+#define WM8900_DAC_CLKDIV_1   0x00
+#define WM8900_DAC_CLKDIV_1_5 0x04
+#define WM8900_DAC_CLKDIV_2   0x08
+#define WM8900_DAC_CLKDIV_3   0x0c
+#define WM8900_DAC_CLKDIV_4   0x10
+#define WM8900_DAC_CLKDIV_5_5 0x14
+#define WM8900_DAC_CLKDIV_6   0x18
+
+#endif
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
new file mode 100644
index 0000000..6cb3c15
--- /dev/null
+++ b/sound/soc/codecs/wm8903.c
@@ -0,0 +1,2230 @@
+/*
+ * wm8903.c  --  WM8903 ALSA SoC Audio driver
+ *
+ * Copyright 2008-12 Wolfson Microelectronics
+ * Copyright 2011-2012 NVIDIA, Inc.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * TODO:
+ *  - TDM mode configuration.
+ *  - Digital microphone support.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/gpio/driver.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/wm8903.h>
+#include <trace/events/asoc.h>
+
+#include "wm8903.h"
+
+/* Register defaults at reset */
+static const struct reg_default wm8903_reg_defaults[] = {
+	{ 4,  0x0018 },     /* R4   - Bias Control 0 */
+	{ 5,  0x0000 },     /* R5   - VMID Control 0 */
+	{ 6,  0x0000 },     /* R6   - Mic Bias Control 0 */
+	{ 8,  0x0001 },     /* R8   - Analogue DAC 0 */
+	{ 10, 0x0001 },     /* R10  - Analogue ADC 0 */
+	{ 12, 0x0000 },     /* R12  - Power Management 0 */
+	{ 13, 0x0000 },     /* R13  - Power Management 1 */
+	{ 14, 0x0000 },     /* R14  - Power Management 2 */
+	{ 15, 0x0000 },     /* R15  - Power Management 3 */
+	{ 16, 0x0000 },     /* R16  - Power Management 4 */
+	{ 17, 0x0000 },     /* R17  - Power Management 5 */
+	{ 18, 0x0000 },     /* R18  - Power Management 6 */
+	{ 20, 0x0400 },     /* R20  - Clock Rates 0 */
+	{ 21, 0x0D07 },     /* R21  - Clock Rates 1 */
+	{ 22, 0x0000 },     /* R22  - Clock Rates 2 */
+	{ 24, 0x0050 },     /* R24  - Audio Interface 0 */
+	{ 25, 0x0242 },     /* R25  - Audio Interface 1 */
+	{ 26, 0x0008 },     /* R26  - Audio Interface 2 */
+	{ 27, 0x0022 },     /* R27  - Audio Interface 3 */
+	{ 30, 0x00C0 },     /* R30  - DAC Digital Volume Left */
+	{ 31, 0x00C0 },     /* R31  - DAC Digital Volume Right */
+	{ 32, 0x0000 },     /* R32  - DAC Digital 0 */
+	{ 33, 0x0000 },     /* R33  - DAC Digital 1 */
+	{ 36, 0x00C0 },     /* R36  - ADC Digital Volume Left */
+	{ 37, 0x00C0 },     /* R37  - ADC Digital Volume Right */
+	{ 38, 0x0000 },     /* R38  - ADC Digital 0 */
+	{ 39, 0x0073 },     /* R39  - Digital Microphone 0 */
+	{ 40, 0x09BF },     /* R40  - DRC 0 */
+	{ 41, 0x3241 },     /* R41  - DRC 1 */
+	{ 42, 0x0020 },     /* R42  - DRC 2 */
+	{ 43, 0x0000 },     /* R43  - DRC 3 */
+	{ 44, 0x0085 },     /* R44  - Analogue Left Input 0 */
+	{ 45, 0x0085 },     /* R45  - Analogue Right Input 0 */
+	{ 46, 0x0044 },     /* R46  - Analogue Left Input 1 */
+	{ 47, 0x0044 },     /* R47  - Analogue Right Input 1 */
+	{ 50, 0x0008 },     /* R50  - Analogue Left Mix 0 */
+	{ 51, 0x0004 },     /* R51  - Analogue Right Mix 0 */
+	{ 52, 0x0000 },     /* R52  - Analogue Spk Mix Left 0 */
+	{ 53, 0x0000 },     /* R53  - Analogue Spk Mix Left 1 */
+	{ 54, 0x0000 },     /* R54  - Analogue Spk Mix Right 0 */
+	{ 55, 0x0000 },     /* R55  - Analogue Spk Mix Right 1 */
+	{ 57, 0x002D },     /* R57  - Analogue OUT1 Left */
+	{ 58, 0x002D },     /* R58  - Analogue OUT1 Right */
+	{ 59, 0x0039 },     /* R59  - Analogue OUT2 Left */
+	{ 60, 0x0039 },     /* R60  - Analogue OUT2 Right */
+	{ 62, 0x0139 },     /* R62  - Analogue OUT3 Left */
+	{ 63, 0x0139 },     /* R63  - Analogue OUT3 Right */
+	{ 64, 0x0000 },     /* R65  - Analogue SPK Output Control 0 */
+	{ 67, 0x0010 },     /* R67  - DC Servo 0 */
+	{ 69, 0x00A4 },     /* R69  - DC Servo 2 */
+	{ 90, 0x0000 },     /* R90  - Analogue HP 0 */
+	{ 94, 0x0000 },     /* R94  - Analogue Lineout 0 */
+	{ 98, 0x0000 },     /* R98  - Charge Pump 0 */
+	{ 104, 0x0000 },    /* R104 - Class W 0 */
+	{ 108, 0x0000 },    /* R108 - Write Sequencer 0 */
+	{ 109, 0x0000 },    /* R109 - Write Sequencer 1 */
+	{ 110, 0x0000 },    /* R110 - Write Sequencer 2 */
+	{ 111, 0x0000 },    /* R111 - Write Sequencer 3 */
+	{ 112, 0x0000 },    /* R112 - Write Sequencer 4 */
+	{ 114, 0x0000 },    /* R114 - Control Interface */
+	{ 116, 0x00A8 },    /* R116 - GPIO Control 1 */
+	{ 117, 0x00A8 },    /* R117 - GPIO Control 2 */
+	{ 118, 0x00A8 },    /* R118 - GPIO Control 3 */
+	{ 119, 0x0220 },    /* R119 - GPIO Control 4 */
+	{ 120, 0x01A0 },    /* R120 - GPIO Control 5 */
+	{ 122, 0xFFFF },    /* R122 - Interrupt Status 1 Mask */
+	{ 123, 0x0000 },    /* R123 - Interrupt Polarity 1 */
+	{ 126, 0x0000 },    /* R126 - Interrupt Control */
+	{ 129, 0x0000 },    /* R129 - Control Interface Test 1 */
+	{ 149, 0x6810 },    /* R149 - Charge Pump Test 1 */
+	{ 164, 0x0028 },    /* R164 - Clock Rate Test 4 */
+	{ 172, 0x0000 },    /* R172 - Analogue Output Bias 0 */
+};
+
+#define WM8903_NUM_SUPPLIES 4
+static const char *wm8903_supply_names[WM8903_NUM_SUPPLIES] = {
+	"AVDD",
+	"CPVDD",
+	"DBVDD",
+	"DCVDD",
+};
+
+struct wm8903_priv {
+	struct wm8903_platform_data *pdata;
+	struct device *dev;
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[WM8903_NUM_SUPPLIES];
+
+	int sysclk;
+	int irq;
+
+	struct mutex lock;
+	int fs;
+	int deemph;
+
+	int dcs_pending;
+	int dcs_cache[4];
+
+	/* Reference count */
+	int class_w_users;
+
+	struct snd_soc_jack *mic_jack;
+	int mic_det;
+	int mic_short;
+	int mic_last_report;
+	int mic_delay;
+
+#ifdef CONFIG_GPIOLIB
+	struct gpio_chip gpio_chip;
+#endif
+};
+
+static bool wm8903_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8903_SW_RESET_AND_ID:
+	case WM8903_REVISION_NUMBER:
+	case WM8903_BIAS_CONTROL_0:
+	case WM8903_VMID_CONTROL_0:
+	case WM8903_MIC_BIAS_CONTROL_0:
+	case WM8903_ANALOGUE_DAC_0:
+	case WM8903_ANALOGUE_ADC_0:
+	case WM8903_POWER_MANAGEMENT_0:
+	case WM8903_POWER_MANAGEMENT_1:
+	case WM8903_POWER_MANAGEMENT_2:
+	case WM8903_POWER_MANAGEMENT_3:
+	case WM8903_POWER_MANAGEMENT_4:
+	case WM8903_POWER_MANAGEMENT_5:
+	case WM8903_POWER_MANAGEMENT_6:
+	case WM8903_CLOCK_RATES_0:
+	case WM8903_CLOCK_RATES_1:
+	case WM8903_CLOCK_RATES_2:
+	case WM8903_AUDIO_INTERFACE_0:
+	case WM8903_AUDIO_INTERFACE_1:
+	case WM8903_AUDIO_INTERFACE_2:
+	case WM8903_AUDIO_INTERFACE_3:
+	case WM8903_DAC_DIGITAL_VOLUME_LEFT:
+	case WM8903_DAC_DIGITAL_VOLUME_RIGHT:
+	case WM8903_DAC_DIGITAL_0:
+	case WM8903_DAC_DIGITAL_1:
+	case WM8903_ADC_DIGITAL_VOLUME_LEFT:
+	case WM8903_ADC_DIGITAL_VOLUME_RIGHT:
+	case WM8903_ADC_DIGITAL_0:
+	case WM8903_DIGITAL_MICROPHONE_0:
+	case WM8903_DRC_0:
+	case WM8903_DRC_1:
+	case WM8903_DRC_2:
+	case WM8903_DRC_3:
+	case WM8903_ANALOGUE_LEFT_INPUT_0:
+	case WM8903_ANALOGUE_RIGHT_INPUT_0:
+	case WM8903_ANALOGUE_LEFT_INPUT_1:
+	case WM8903_ANALOGUE_RIGHT_INPUT_1:
+	case WM8903_ANALOGUE_LEFT_MIX_0:
+	case WM8903_ANALOGUE_RIGHT_MIX_0:
+	case WM8903_ANALOGUE_SPK_MIX_LEFT_0:
+	case WM8903_ANALOGUE_SPK_MIX_LEFT_1:
+	case WM8903_ANALOGUE_SPK_MIX_RIGHT_0:
+	case WM8903_ANALOGUE_SPK_MIX_RIGHT_1:
+	case WM8903_ANALOGUE_OUT1_LEFT:
+	case WM8903_ANALOGUE_OUT1_RIGHT:
+	case WM8903_ANALOGUE_OUT2_LEFT:
+	case WM8903_ANALOGUE_OUT2_RIGHT:
+	case WM8903_ANALOGUE_OUT3_LEFT:
+	case WM8903_ANALOGUE_OUT3_RIGHT:
+	case WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0:
+	case WM8903_DC_SERVO_0:
+	case WM8903_DC_SERVO_2:
+	case WM8903_DC_SERVO_READBACK_1:
+	case WM8903_DC_SERVO_READBACK_2:
+	case WM8903_DC_SERVO_READBACK_3:
+	case WM8903_DC_SERVO_READBACK_4:
+	case WM8903_ANALOGUE_HP_0:
+	case WM8903_ANALOGUE_LINEOUT_0:
+	case WM8903_CHARGE_PUMP_0:
+	case WM8903_CLASS_W_0:
+	case WM8903_WRITE_SEQUENCER_0:
+	case WM8903_WRITE_SEQUENCER_1:
+	case WM8903_WRITE_SEQUENCER_2:
+	case WM8903_WRITE_SEQUENCER_3:
+	case WM8903_WRITE_SEQUENCER_4:
+	case WM8903_CONTROL_INTERFACE:
+	case WM8903_GPIO_CONTROL_1:
+	case WM8903_GPIO_CONTROL_2:
+	case WM8903_GPIO_CONTROL_3:
+	case WM8903_GPIO_CONTROL_4:
+	case WM8903_GPIO_CONTROL_5:
+	case WM8903_INTERRUPT_STATUS_1:
+	case WM8903_INTERRUPT_STATUS_1_MASK:
+	case WM8903_INTERRUPT_POLARITY_1:
+	case WM8903_INTERRUPT_CONTROL:
+	case WM8903_CLOCK_RATE_TEST_4:
+	case WM8903_ANALOGUE_OUTPUT_BIAS_0:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm8903_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8903_SW_RESET_AND_ID:
+	case WM8903_REVISION_NUMBER:
+	case WM8903_INTERRUPT_STATUS_1:
+	case WM8903_WRITE_SEQUENCER_4:
+	case WM8903_DC_SERVO_READBACK_1:
+	case WM8903_DC_SERVO_READBACK_2:
+	case WM8903_DC_SERVO_READBACK_3:
+	case WM8903_DC_SERVO_READBACK_4:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+static int wm8903_cp_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	WARN_ON(event != SND_SOC_DAPM_POST_PMU);
+	mdelay(4);
+
+	return 0;
+}
+
+static int wm8903_dcs_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		wm8903->dcs_pending |= 1 << w->shift;
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, WM8903_DC_SERVO_0,
+				    1 << w->shift, 0);
+		break;
+	}
+
+	return 0;
+}
+
+#define WM8903_DCS_MODE_WRITE_STOP 0
+#define WM8903_DCS_MODE_START_STOP 2
+
+static void wm8903_seq_notifier(struct snd_soc_component *component,
+				enum snd_soc_dapm_type event, int subseq)
+{
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
+	int dcs_mode = WM8903_DCS_MODE_WRITE_STOP;
+	int i, val;
+
+	/* Complete any pending DC servo starts */
+	if (wm8903->dcs_pending) {
+		dev_dbg(component->dev, "Starting DC servo for %x\n",
+			wm8903->dcs_pending);
+
+		/* If we've no cached values then we need to do startup */
+		for (i = 0; i < ARRAY_SIZE(wm8903->dcs_cache); i++) {
+			if (!(wm8903->dcs_pending & (1 << i)))
+				continue;
+
+			if (wm8903->dcs_cache[i]) {
+				dev_dbg(component->dev,
+					"Restore DC servo %d value %x\n",
+					3 - i, wm8903->dcs_cache[i]);
+
+				snd_soc_component_write(component, WM8903_DC_SERVO_4 + i,
+					      wm8903->dcs_cache[i] & 0xff);
+			} else {
+				dev_dbg(component->dev,
+					"Calibrate DC servo %d\n", 3 - i);
+				dcs_mode = WM8903_DCS_MODE_START_STOP;
+			}
+		}
+
+		/* Don't trust the cache for analogue */
+		if (wm8903->class_w_users)
+			dcs_mode = WM8903_DCS_MODE_START_STOP;
+
+		snd_soc_component_update_bits(component, WM8903_DC_SERVO_2,
+				    WM8903_DCS_MODE_MASK, dcs_mode);
+
+		snd_soc_component_update_bits(component, WM8903_DC_SERVO_0,
+				    WM8903_DCS_ENA_MASK, wm8903->dcs_pending);
+
+		switch (dcs_mode) {
+		case WM8903_DCS_MODE_WRITE_STOP:
+			break;
+
+		case WM8903_DCS_MODE_START_STOP:
+			msleep(270);
+
+			/* Cache the measured offsets for digital */
+			if (wm8903->class_w_users)
+				break;
+
+			for (i = 0; i < ARRAY_SIZE(wm8903->dcs_cache); i++) {
+				if (!(wm8903->dcs_pending & (1 << i)))
+					continue;
+
+				val = snd_soc_component_read32(component,
+						   WM8903_DC_SERVO_READBACK_1 + i);
+				dev_dbg(component->dev, "DC servo %d: %x\n",
+					3 - i, val);
+				wm8903->dcs_cache[i] = val;
+			}
+			break;
+
+		default:
+			pr_warn("DCS mode %d delay not set\n", dcs_mode);
+			break;
+		}
+
+		wm8903->dcs_pending = 0;
+	}
+}
+
+/*
+ * When used with DAC outputs only the WM8903 charge pump supports
+ * operation in class W mode, providing very low power consumption
+ * when used with digital sources.  Enable and disable this mode
+ * automatically depending on the mixer configuration.
+ *
+ * All the relevant controls are simple switches.
+ */
+static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
+	u16 reg;
+	int ret;
+
+	reg = snd_soc_component_read32(component, WM8903_CLASS_W_0);
+
+	/* Turn it off if we're about to enable bypass */
+	if (ucontrol->value.integer.value[0]) {
+		if (wm8903->class_w_users == 0) {
+			dev_dbg(component->dev, "Disabling Class W\n");
+			snd_soc_component_write(component, WM8903_CLASS_W_0, reg &
+				     ~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V));
+		}
+		wm8903->class_w_users++;
+	}
+
+	/* Implement the change */
+	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+
+	/* If we've just disabled the last bypass path turn Class W on */
+	if (!ucontrol->value.integer.value[0]) {
+		if (wm8903->class_w_users == 1) {
+			dev_dbg(component->dev, "Enabling Class W\n");
+			snd_soc_component_write(component, WM8903_CLASS_W_0, reg |
+				     WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
+		}
+		wm8903->class_w_users--;
+	}
+
+	dev_dbg(component->dev, "Bypass use count now %d\n",
+		wm8903->class_w_users);
+
+	return ret;
+}
+
+#define SOC_DAPM_SINGLE_W(xname, reg, shift, max, invert) \
+	SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
+		snd_soc_dapm_get_volsw, wm8903_class_w_put)
+
+
+static int wm8903_deemph[] = { 0, 32000, 44100, 48000 };
+
+static int wm8903_set_deemph(struct snd_soc_component *component)
+{
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
+	int val, i, best;
+
+	/* If we're using deemphasis select the nearest available sample
+	 * rate.
+	 */
+	if (wm8903->deemph) {
+		best = 1;
+		for (i = 2; i < ARRAY_SIZE(wm8903_deemph); i++) {
+			if (abs(wm8903_deemph[i] - wm8903->fs) <
+			    abs(wm8903_deemph[best] - wm8903->fs))
+				best = i;
+		}
+
+		val = best << WM8903_DEEMPH_SHIFT;
+	} else {
+		best = 0;
+		val = 0;
+	}
+
+	dev_dbg(component->dev, "Set deemphasis %d (%dHz)\n",
+		best, wm8903_deemph[best]);
+
+	return snd_soc_component_update_bits(component, WM8903_DAC_DIGITAL_1,
+				   WM8903_DEEMPH_MASK, val);
+}
+
+static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wm8903->deemph;
+
+	return 0;
+}
+
+static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
+	unsigned int deemph = ucontrol->value.integer.value[0];
+	int ret = 0;
+
+	if (deemph > 1)
+		return -EINVAL;
+
+	mutex_lock(&wm8903->lock);
+	if (wm8903->deemph != deemph) {
+		wm8903->deemph = deemph;
+
+		wm8903_set_deemph(component);
+
+		ret = 1;
+	}
+	mutex_unlock(&wm8903->lock);
+
+	return ret;
+}
+
+/* ALSA can only do steps of .01dB */
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+
+static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
+
+static const DECLARE_TLV_DB_SCALE(digital_sidetone_tlv, -3600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(drc_tlv_thresh, 0, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_tlv_amp, -2250, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_tlv_min, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(drc_tlv_max, 1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(drc_tlv_startup, -300, 50, 0);
+
+static const char *hpf_mode_text[] = {
+	"Hi-fi", "Voice 1", "Voice 2", "Voice 3"
+};
+
+static SOC_ENUM_SINGLE_DECL(hpf_mode,
+			    WM8903_ADC_DIGITAL_0, 5, hpf_mode_text);
+
+static const char *osr_text[] = {
+	"Low power", "High performance"
+};
+
+static SOC_ENUM_SINGLE_DECL(adc_osr,
+			    WM8903_ANALOGUE_ADC_0, 0, osr_text);
+
+static SOC_ENUM_SINGLE_DECL(dac_osr,
+			    WM8903_DAC_DIGITAL_1, 0, osr_text);
+
+static const char *drc_slope_text[] = {
+	"1", "1/2", "1/4", "1/8", "1/16", "0"
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_slope_r0,
+			    WM8903_DRC_2, 3, drc_slope_text);
+
+static SOC_ENUM_SINGLE_DECL(drc_slope_r1,
+			    WM8903_DRC_2, 0, drc_slope_text);
+
+static const char *drc_attack_text[] = {
+	"instantaneous",
+	"363us", "762us", "1.45ms", "2.9ms", "5.8ms", "11.6ms", "23.2ms",
+	"46.4ms", "92.8ms", "185.6ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_attack,
+			    WM8903_DRC_1, 12, drc_attack_text);
+
+static const char *drc_decay_text[] = {
+	"186ms", "372ms", "743ms", "1.49s", "2.97s", "5.94s", "11.89s",
+	"23.87s", "47.56s"
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_decay,
+			    WM8903_DRC_1, 8, drc_decay_text);
+
+static const char *drc_ff_delay_text[] = {
+	"5 samples", "9 samples"
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_ff_delay,
+			    WM8903_DRC_0, 5, drc_ff_delay_text);
+
+static const char *drc_qr_decay_text[] = {
+	"0.725ms", "1.45ms", "5.8ms"
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_qr_decay,
+			    WM8903_DRC_1, 4, drc_qr_decay_text);
+
+static const char *drc_smoothing_text[] = {
+	"Low", "Medium", "High"
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_smoothing,
+			    WM8903_DRC_0, 11, drc_smoothing_text);
+
+static const char *soft_mute_text[] = {
+	"Fast (fs/2)", "Slow (fs/32)"
+};
+
+static SOC_ENUM_SINGLE_DECL(soft_mute,
+			    WM8903_DAC_DIGITAL_1, 10, soft_mute_text);
+
+static const char *mute_mode_text[] = {
+	"Hard", "Soft"
+};
+
+static SOC_ENUM_SINGLE_DECL(mute_mode,
+			    WM8903_DAC_DIGITAL_1, 9, mute_mode_text);
+
+static const char *companding_text[] = {
+	"ulaw", "alaw"
+};
+
+static SOC_ENUM_SINGLE_DECL(dac_companding,
+			    WM8903_AUDIO_INTERFACE_0, 0, companding_text);
+
+static SOC_ENUM_SINGLE_DECL(adc_companding,
+			    WM8903_AUDIO_INTERFACE_0, 2, companding_text);
+
+static const char *input_mode_text[] = {
+	"Single-Ended", "Differential Line", "Differential Mic"
+};
+
+static SOC_ENUM_SINGLE_DECL(linput_mode_enum,
+			    WM8903_ANALOGUE_LEFT_INPUT_1, 0, input_mode_text);
+
+static SOC_ENUM_SINGLE_DECL(rinput_mode_enum,
+			    WM8903_ANALOGUE_RIGHT_INPUT_1, 0, input_mode_text);
+
+static const char *linput_mux_text[] = {
+	"IN1L", "IN2L", "IN3L"
+};
+
+static SOC_ENUM_SINGLE_DECL(linput_enum,
+			    WM8903_ANALOGUE_LEFT_INPUT_1, 2, linput_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(linput_inv_enum,
+			    WM8903_ANALOGUE_LEFT_INPUT_1, 4, linput_mux_text);
+
+static const char *rinput_mux_text[] = {
+	"IN1R", "IN2R", "IN3R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rinput_enum,
+			    WM8903_ANALOGUE_RIGHT_INPUT_1, 2, rinput_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(rinput_inv_enum,
+			    WM8903_ANALOGUE_RIGHT_INPUT_1, 4, rinput_mux_text);
+
+
+static const char *sidetone_text[] = {
+	"None", "Left", "Right"
+};
+
+static SOC_ENUM_SINGLE_DECL(lsidetone_enum,
+			    WM8903_DAC_DIGITAL_0, 2, sidetone_text);
+
+static SOC_ENUM_SINGLE_DECL(rsidetone_enum,
+			    WM8903_DAC_DIGITAL_0, 0, sidetone_text);
+
+static const char *adcinput_text[] = {
+	"ADC", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(adcinput_enum,
+			    WM8903_CLOCK_RATE_TEST_4, 9, adcinput_text);
+
+static const char *aif_text[] = {
+	"Left", "Right"
+};
+
+static SOC_ENUM_SINGLE_DECL(lcapture_enum,
+			    WM8903_AUDIO_INTERFACE_0, 7, aif_text);
+
+static SOC_ENUM_SINGLE_DECL(rcapture_enum,
+			    WM8903_AUDIO_INTERFACE_0, 6, aif_text);
+
+static SOC_ENUM_SINGLE_DECL(lplay_enum,
+			    WM8903_AUDIO_INTERFACE_0, 5, aif_text);
+
+static SOC_ENUM_SINGLE_DECL(rplay_enum,
+			    WM8903_AUDIO_INTERFACE_0, 4, aif_text);
+
+static const struct snd_kcontrol_new wm8903_snd_controls[] = {
+
+/* Input PGAs - No TLV since the scale depends on PGA mode */
+SOC_SINGLE("Left Input PGA Switch", WM8903_ANALOGUE_LEFT_INPUT_0,
+	   7, 1, 1),
+SOC_SINGLE("Left Input PGA Volume", WM8903_ANALOGUE_LEFT_INPUT_0,
+	   0, 31, 0),
+SOC_SINGLE("Left Input PGA Common Mode Switch", WM8903_ANALOGUE_LEFT_INPUT_1,
+	   6, 1, 0),
+
+SOC_SINGLE("Right Input PGA Switch", WM8903_ANALOGUE_RIGHT_INPUT_0,
+	   7, 1, 1),
+SOC_SINGLE("Right Input PGA Volume", WM8903_ANALOGUE_RIGHT_INPUT_0,
+	   0, 31, 0),
+SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1,
+	   6, 1, 0),
+
+/* ADCs */
+SOC_ENUM("ADC OSR", adc_osr),
+SOC_SINGLE("HPF Switch", WM8903_ADC_DIGITAL_0, 4, 1, 0),
+SOC_ENUM("HPF Mode", hpf_mode),
+SOC_SINGLE("DRC Switch", WM8903_DRC_0, 15, 1, 0),
+SOC_ENUM("DRC Compressor Slope R0", drc_slope_r0),
+SOC_ENUM("DRC Compressor Slope R1", drc_slope_r1),
+SOC_SINGLE_TLV("DRC Compressor Threshold Volume", WM8903_DRC_3, 5, 124, 1,
+	       drc_tlv_thresh),
+SOC_SINGLE_TLV("DRC Volume", WM8903_DRC_3, 0, 30, 1, drc_tlv_amp),
+SOC_SINGLE_TLV("DRC Minimum Gain Volume", WM8903_DRC_1, 2, 3, 1, drc_tlv_min),
+SOC_SINGLE_TLV("DRC Maximum Gain Volume", WM8903_DRC_1, 0, 3, 0, drc_tlv_max),
+SOC_ENUM("DRC Attack Rate", drc_attack),
+SOC_ENUM("DRC Decay Rate", drc_decay),
+SOC_ENUM("DRC FF Delay", drc_ff_delay),
+SOC_SINGLE("DRC Anticlip Switch", WM8903_DRC_0, 1, 1, 0),
+SOC_SINGLE("DRC QR Switch", WM8903_DRC_0, 2, 1, 0),
+SOC_SINGLE_TLV("DRC QR Threshold Volume", WM8903_DRC_0, 6, 3, 0, drc_tlv_max),
+SOC_ENUM("DRC QR Decay Rate", drc_qr_decay),
+SOC_SINGLE("DRC Smoothing Switch", WM8903_DRC_0, 3, 1, 0),
+SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8903_DRC_0, 0, 1, 0),
+SOC_ENUM("DRC Smoothing Threshold", drc_smoothing),
+SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup),
+
+SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT,
+		 WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv),
+SOC_ENUM("ADC Companding Mode", adc_companding),
+SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0),
+
+SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8903_DAC_DIGITAL_0, 4, 8,
+	       12, 0, digital_sidetone_tlv),
+
+/* DAC */
+SOC_ENUM("DAC OSR", dac_osr),
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8903_DAC_DIGITAL_VOLUME_LEFT,
+		 WM8903_DAC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv),
+SOC_ENUM("DAC Soft Mute Rate", soft_mute),
+SOC_ENUM("DAC Mute Mode", mute_mode),
+SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0),
+SOC_ENUM("DAC Companding Mode", dac_companding),
+SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0),
+SOC_SINGLE_TLV("DAC Boost Volume", WM8903_AUDIO_INTERFACE_0, 9, 3, 0,
+	       dac_boost_tlv),
+SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
+		    wm8903_get_deemph, wm8903_put_deemph),
+
+/* Headphones */
+SOC_DOUBLE_R("Headphone Switch",
+	     WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT,
+	     8, 1, 1),
+SOC_DOUBLE_R("Headphone ZC Switch",
+	     WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT,
+	     6, 1, 0),
+SOC_DOUBLE_R_TLV("Headphone Volume",
+		 WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT,
+		 0, 63, 0, out_tlv),
+
+/* Line out */
+SOC_DOUBLE_R("Line Out Switch",
+	     WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT,
+	     8, 1, 1),
+SOC_DOUBLE_R("Line Out ZC Switch",
+	     WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT,
+	     6, 1, 0),
+SOC_DOUBLE_R_TLV("Line Out Volume",
+		 WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT,
+		 0, 63, 0, out_tlv),
+
+/* Speaker */
+SOC_DOUBLE_R("Speaker Switch",
+	     WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT, 8, 1, 1),
+SOC_DOUBLE_R("Speaker ZC Switch",
+	     WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT, 6, 1, 0),
+SOC_DOUBLE_R_TLV("Speaker Volume",
+		 WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT,
+		 0, 63, 0, out_tlv),
+};
+
+static const struct snd_kcontrol_new linput_mode_mux =
+	SOC_DAPM_ENUM("Left Input Mode Mux", linput_mode_enum);
+
+static const struct snd_kcontrol_new rinput_mode_mux =
+	SOC_DAPM_ENUM("Right Input Mode Mux", rinput_mode_enum);
+
+static const struct snd_kcontrol_new linput_mux =
+	SOC_DAPM_ENUM("Left Input Mux", linput_enum);
+
+static const struct snd_kcontrol_new linput_inv_mux =
+	SOC_DAPM_ENUM("Left Inverting Input Mux", linput_inv_enum);
+
+static const struct snd_kcontrol_new rinput_mux =
+	SOC_DAPM_ENUM("Right Input Mux", rinput_enum);
+
+static const struct snd_kcontrol_new rinput_inv_mux =
+	SOC_DAPM_ENUM("Right Inverting Input Mux", rinput_inv_enum);
+
+static const struct snd_kcontrol_new lsidetone_mux =
+	SOC_DAPM_ENUM("DACL Sidetone Mux", lsidetone_enum);
+
+static const struct snd_kcontrol_new rsidetone_mux =
+	SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum);
+
+static const struct snd_kcontrol_new adcinput_mux =
+	SOC_DAPM_ENUM("ADC Input", adcinput_enum);
+
+static const struct snd_kcontrol_new lcapture_mux =
+	SOC_DAPM_ENUM("Left Capture Mux", lcapture_enum);
+
+static const struct snd_kcontrol_new rcapture_mux =
+	SOC_DAPM_ENUM("Right Capture Mux", rcapture_enum);
+
+static const struct snd_kcontrol_new lplay_mux =
+	SOC_DAPM_ENUM("Left Playback Mux", lplay_enum);
+
+static const struct snd_kcontrol_new rplay_mux =
+	SOC_DAPM_ENUM("Right Playback Mux", rplay_enum);
+
+static const struct snd_kcontrol_new left_output_mixer[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0),
+SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0),
+SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_output_mixer[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 3, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 2, 1, 0),
+SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0),
+SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_speaker_mixer[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 3, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 2, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 1, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_speaker_mixer[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 3, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 2, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0,
+		1, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0,
+		0, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8903_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+SND_SOC_DAPM_INPUT("DMICDAT"),
+
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+SND_SOC_DAPM_OUTPUT("LINEOUTL"),
+SND_SOC_DAPM_OUTPUT("LINEOUTR"),
+SND_SOC_DAPM_OUTPUT("LOP"),
+SND_SOC_DAPM_OUTPUT("LON"),
+SND_SOC_DAPM_OUTPUT("ROP"),
+SND_SOC_DAPM_OUTPUT("RON"),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS", WM8903_MIC_BIAS_CONTROL_0, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("Left Input Mux", SND_SOC_NOPM, 0, 0, &linput_mux),
+SND_SOC_DAPM_MUX("Left Input Inverting Mux", SND_SOC_NOPM, 0, 0,
+		 &linput_inv_mux),
+SND_SOC_DAPM_MUX("Left Input Mode Mux", SND_SOC_NOPM, 0, 0, &linput_mode_mux),
+
+SND_SOC_DAPM_MUX("Right Input Mux", SND_SOC_NOPM, 0, 0, &rinput_mux),
+SND_SOC_DAPM_MUX("Right Input Inverting Mux", SND_SOC_NOPM, 0, 0,
+		 &rinput_inv_mux),
+SND_SOC_DAPM_MUX("Right Input Mode Mux", SND_SOC_NOPM, 0, 0, &rinput_mode_mux),
+
+SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("Left ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux),
+SND_SOC_DAPM_MUX("Right ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux),
+
+SND_SOC_DAPM_ADC("ADCL", NULL, WM8903_POWER_MANAGEMENT_6, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, WM8903_POWER_MANAGEMENT_6, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Capture Mux", SND_SOC_NOPM, 0, 0, &lcapture_mux),
+SND_SOC_DAPM_MUX("Right Capture Mux", SND_SOC_NOPM, 0, 0, &rcapture_mux),
+
+SND_SOC_DAPM_AIF_OUT("AIFTXL", "Left HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIFTXR", "Right HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &lsidetone_mux),
+SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &rsidetone_mux),
+
+SND_SOC_DAPM_AIF_IN("AIFRXL", "Left Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIFRXR", "Right Playback", 0, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Playback Mux", SND_SOC_NOPM, 0, 0, &lplay_mux),
+SND_SOC_DAPM_MUX("Right Playback Mux", SND_SOC_NOPM, 0, 0, &rplay_mux),
+
+SND_SOC_DAPM_DAC("DACL", NULL, WM8903_POWER_MANAGEMENT_6, 3, 0),
+SND_SOC_DAPM_DAC("DACR", NULL, WM8903_POWER_MANAGEMENT_6, 2, 0),
+
+SND_SOC_DAPM_MIXER("Left Output Mixer", WM8903_POWER_MANAGEMENT_1, 1, 0,
+		   left_output_mixer, ARRAY_SIZE(left_output_mixer)),
+SND_SOC_DAPM_MIXER("Right Output Mixer", WM8903_POWER_MANAGEMENT_1, 0, 0,
+		   right_output_mixer, ARRAY_SIZE(right_output_mixer)),
+
+SND_SOC_DAPM_MIXER("Left Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 1, 0,
+		   left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
+SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0,
+		   right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
+
+SND_SOC_DAPM_PGA_S("Left Headphone Output PGA", 0, WM8903_POWER_MANAGEMENT_2,
+		   1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("Right Headphone Output PGA", 0, WM8903_POWER_MANAGEMENT_2,
+		   0, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("Left Line Output PGA", 0, WM8903_POWER_MANAGEMENT_3, 1, 0,
+		   NULL, 0),
+SND_SOC_DAPM_PGA_S("Right Line Output PGA", 0, WM8903_POWER_MANAGEMENT_3, 0, 0,
+		   NULL, 0),
+
+SND_SOC_DAPM_PGA_S("HPL_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPL_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPL_ENA_DLY", 2, WM8903_ANALOGUE_HP_0, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPL_ENA", 1, WM8903_ANALOGUE_HP_0, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPR_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 3, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPR_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPR_ENA_DLY", 2, WM8903_ANALOGUE_HP_0, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPR_ENA", 1, WM8903_ANALOGUE_HP_0, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("LINEOUTL_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 7, 0,
+		   NULL, 0),
+SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 6, 0,
+		   NULL, 0),
+SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_DLY", 2, WM8903_ANALOGUE_LINEOUT_0, 5, 0,
+		   NULL, 0),
+SND_SOC_DAPM_PGA_S("LINEOUTL_ENA", 1, WM8903_ANALOGUE_LINEOUT_0, 4, 0,
+		   NULL, 0),
+SND_SOC_DAPM_PGA_S("LINEOUTR_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 3, 0,
+		   NULL, 0),
+SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 2, 0,
+		   NULL, 0),
+SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_DLY", 2, WM8903_ANALOGUE_LINEOUT_0, 1, 0,
+		   NULL, 0),
+SND_SOC_DAPM_PGA_S("LINEOUTR_ENA", 1, WM8903_ANALOGUE_LINEOUT_0, 0, 0,
+		   NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("DCS Master", WM8903_DC_SERVO_0, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPL_DCS", 3, SND_SOC_NOPM, 3, 0, wm8903_dcs_event,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_S("HPR_DCS", 3, SND_SOC_NOPM, 2, 0, wm8903_dcs_event,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_S("LINEOUTL_DCS", 3, SND_SOC_NOPM, 1, 0, wm8903_dcs_event,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_S("LINEOUTR_DCS", 3, SND_SOC_NOPM, 0, 0, wm8903_dcs_event,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("Right Speaker PGA", WM8903_POWER_MANAGEMENT_5, 0, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("Charge Pump", WM8903_CHARGE_PUMP_0, 0, 0,
+		    wm8903_cp_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8903_CLOCK_RATES_2, 2, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route wm8903_intercon[] = {
+
+	{ "CLK_DSP", NULL, "CLK_SYS" },
+	{ "MICBIAS", NULL, "CLK_SYS" },
+	{ "HPL_DCS", NULL, "CLK_SYS" },
+	{ "HPR_DCS", NULL, "CLK_SYS" },
+	{ "LINEOUTL_DCS", NULL, "CLK_SYS" },
+	{ "LINEOUTR_DCS", NULL, "CLK_SYS" },
+
+	{ "Left Input Mux", "IN1L", "IN1L" },
+	{ "Left Input Mux", "IN2L", "IN2L" },
+	{ "Left Input Mux", "IN3L", "IN3L" },
+
+	{ "Left Input Inverting Mux", "IN1L", "IN1L" },
+	{ "Left Input Inverting Mux", "IN2L", "IN2L" },
+	{ "Left Input Inverting Mux", "IN3L", "IN3L" },
+
+	{ "Right Input Mux", "IN1R", "IN1R" },
+	{ "Right Input Mux", "IN2R", "IN2R" },
+	{ "Right Input Mux", "IN3R", "IN3R" },
+
+	{ "Right Input Inverting Mux", "IN1R", "IN1R" },
+	{ "Right Input Inverting Mux", "IN2R", "IN2R" },
+	{ "Right Input Inverting Mux", "IN3R", "IN3R" },
+
+	{ "Left Input Mode Mux", "Single-Ended", "Left Input Inverting Mux" },
+	{ "Left Input Mode Mux", "Differential Line",
+	  "Left Input Mux" },
+	{ "Left Input Mode Mux", "Differential Line",
+	  "Left Input Inverting Mux" },
+	{ "Left Input Mode Mux", "Differential Mic",
+	  "Left Input Mux" },
+	{ "Left Input Mode Mux", "Differential Mic",
+	  "Left Input Inverting Mux" },
+
+	{ "Right Input Mode Mux", "Single-Ended",
+	  "Right Input Inverting Mux" },
+	{ "Right Input Mode Mux", "Differential Line",
+	  "Right Input Mux" },
+	{ "Right Input Mode Mux", "Differential Line",
+	  "Right Input Inverting Mux" },
+	{ "Right Input Mode Mux", "Differential Mic",
+	  "Right Input Mux" },
+	{ "Right Input Mode Mux", "Differential Mic",
+	  "Right Input Inverting Mux" },
+
+	{ "Left Input PGA", NULL, "Left Input Mode Mux" },
+	{ "Right Input PGA", NULL, "Right Input Mode Mux" },
+
+	{ "Left ADC Input", "ADC", "Left Input PGA" },
+	{ "Left ADC Input", "DMIC", "DMICDAT" },
+	{ "Right ADC Input", "ADC", "Right Input PGA" },
+	{ "Right ADC Input", "DMIC", "DMICDAT" },
+
+	{ "Left Capture Mux", "Left", "ADCL" },
+	{ "Left Capture Mux", "Right", "ADCR" },
+
+	{ "Right Capture Mux", "Left", "ADCL" },
+	{ "Right Capture Mux", "Right", "ADCR" },
+
+	{ "AIFTXL", NULL, "Left Capture Mux" },
+	{ "AIFTXR", NULL, "Right Capture Mux" },
+
+	{ "ADCL", NULL, "Left ADC Input" },
+	{ "ADCL", NULL, "CLK_DSP" },
+	{ "ADCR", NULL, "Right ADC Input" },
+	{ "ADCR", NULL, "CLK_DSP" },
+
+	{ "Left Playback Mux", "Left", "AIFRXL" },
+	{ "Left Playback Mux", "Right", "AIFRXR" },
+
+	{ "Right Playback Mux", "Left", "AIFRXL" },
+	{ "Right Playback Mux", "Right", "AIFRXR" },
+
+	{ "DACL Sidetone", "Left", "ADCL" },
+	{ "DACL Sidetone", "Right", "ADCR" },
+	{ "DACR Sidetone", "Left", "ADCL" },
+	{ "DACR Sidetone", "Right", "ADCR" },
+
+	{ "DACL", NULL, "Left Playback Mux" },
+	{ "DACL", NULL, "DACL Sidetone" },
+	{ "DACL", NULL, "CLK_DSP" },
+
+	{ "DACR", NULL, "Right Playback Mux" },
+	{ "DACR", NULL, "DACR Sidetone" },
+	{ "DACR", NULL, "CLK_DSP" },
+
+	{ "Left Output Mixer", "Left Bypass Switch", "Left Input PGA" },
+	{ "Left Output Mixer", "Right Bypass Switch", "Right Input PGA" },
+	{ "Left Output Mixer", "DACL Switch", "DACL" },
+	{ "Left Output Mixer", "DACR Switch", "DACR" },
+
+	{ "Right Output Mixer", "Left Bypass Switch", "Left Input PGA" },
+	{ "Right Output Mixer", "Right Bypass Switch", "Right Input PGA" },
+	{ "Right Output Mixer", "DACL Switch", "DACL" },
+	{ "Right Output Mixer", "DACR Switch", "DACR" },
+
+	{ "Left Speaker Mixer", "Left Bypass Switch", "Left Input PGA" },
+	{ "Left Speaker Mixer", "Right Bypass Switch", "Right Input PGA" },
+	{ "Left Speaker Mixer", "DACL Switch", "DACL" },
+	{ "Left Speaker Mixer", "DACR Switch", "DACR" },
+
+	{ "Right Speaker Mixer", "Left Bypass Switch", "Left Input PGA" },
+	{ "Right Speaker Mixer", "Right Bypass Switch", "Right Input PGA" },
+	{ "Right Speaker Mixer", "DACL Switch", "DACL" },
+	{ "Right Speaker Mixer", "DACR Switch", "DACR" },
+
+	{ "Left Line Output PGA", NULL, "Left Output Mixer" },
+	{ "Right Line Output PGA", NULL, "Right Output Mixer" },
+
+	{ "Left Headphone Output PGA", NULL, "Left Output Mixer" },
+	{ "Right Headphone Output PGA", NULL, "Right Output Mixer" },
+
+	{ "Left Speaker PGA", NULL, "Left Speaker Mixer" },
+	{ "Right Speaker PGA", NULL, "Right Speaker Mixer" },
+
+	{ "HPL_ENA", NULL, "Left Headphone Output PGA" },
+	{ "HPR_ENA", NULL, "Right Headphone Output PGA" },
+	{ "HPL_ENA_DLY", NULL, "HPL_ENA" },
+	{ "HPR_ENA_DLY", NULL, "HPR_ENA" },
+	{ "LINEOUTL_ENA", NULL, "Left Line Output PGA" },
+	{ "LINEOUTR_ENA", NULL, "Right Line Output PGA" },
+	{ "LINEOUTL_ENA_DLY", NULL, "LINEOUTL_ENA" },
+	{ "LINEOUTR_ENA_DLY", NULL, "LINEOUTR_ENA" },
+
+	{ "HPL_DCS", NULL, "DCS Master" },
+	{ "HPR_DCS", NULL, "DCS Master" },
+	{ "LINEOUTL_DCS", NULL, "DCS Master" },
+	{ "LINEOUTR_DCS", NULL, "DCS Master" },
+
+	{ "HPL_DCS", NULL, "HPL_ENA_DLY" },
+	{ "HPR_DCS", NULL, "HPR_ENA_DLY" },
+	{ "LINEOUTL_DCS", NULL, "LINEOUTL_ENA_DLY" },
+	{ "LINEOUTR_DCS", NULL, "LINEOUTR_ENA_DLY" },
+
+	{ "HPL_ENA_OUTP", NULL, "HPL_DCS" },
+	{ "HPR_ENA_OUTP", NULL, "HPR_DCS" },
+	{ "LINEOUTL_ENA_OUTP", NULL, "LINEOUTL_DCS" },
+	{ "LINEOUTR_ENA_OUTP", NULL, "LINEOUTR_DCS" },
+
+	{ "HPL_RMV_SHORT", NULL, "HPL_ENA_OUTP" },
+	{ "HPR_RMV_SHORT", NULL, "HPR_ENA_OUTP" },
+	{ "LINEOUTL_RMV_SHORT", NULL, "LINEOUTL_ENA_OUTP" },
+	{ "LINEOUTR_RMV_SHORT", NULL, "LINEOUTR_ENA_OUTP" },
+
+	{ "HPOUTL", NULL, "HPL_RMV_SHORT" },
+	{ "HPOUTR", NULL, "HPR_RMV_SHORT" },
+	{ "LINEOUTL", NULL, "LINEOUTL_RMV_SHORT" },
+	{ "LINEOUTR", NULL, "LINEOUTR_RMV_SHORT" },
+
+	{ "LOP", NULL, "Left Speaker PGA" },
+	{ "LON", NULL, "Left Speaker PGA" },
+
+	{ "ROP", NULL, "Right Speaker PGA" },
+	{ "RON", NULL, "Right Speaker PGA" },
+
+	{ "Charge Pump", NULL, "CLK_DSP" },
+
+	{ "Left Headphone Output PGA", NULL, "Charge Pump" },
+	{ "Right Headphone Output PGA", NULL, "Charge Pump" },
+	{ "Left Line Output PGA", NULL, "Charge Pump" },
+	{ "Right Line Output PGA", NULL, "Charge Pump" },
+};
+
+static int wm8903_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
+				    WM8903_VMID_RES_MASK,
+				    WM8903_VMID_RES_50K);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_update_bits(component, WM8903_BIAS_CONTROL_0,
+					    WM8903_POBCTRL | WM8903_ISEL_MASK |
+					    WM8903_STARTUP_BIAS_ENA |
+					    WM8903_BIAS_ENA,
+					    WM8903_POBCTRL |
+					    (2 << WM8903_ISEL_SHIFT) |
+					    WM8903_STARTUP_BIAS_ENA);
+
+			snd_soc_component_update_bits(component,
+					    WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0,
+					    WM8903_SPK_DISCHARGE,
+					    WM8903_SPK_DISCHARGE);
+
+			msleep(33);
+
+			snd_soc_component_update_bits(component, WM8903_POWER_MANAGEMENT_5,
+					    WM8903_SPKL_ENA | WM8903_SPKR_ENA,
+					    WM8903_SPKL_ENA | WM8903_SPKR_ENA);
+
+			snd_soc_component_update_bits(component,
+					    WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0,
+					    WM8903_SPK_DISCHARGE, 0);
+
+			snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
+					    WM8903_VMID_TIE_ENA |
+					    WM8903_BUFIO_ENA |
+					    WM8903_VMID_IO_ENA |
+					    WM8903_VMID_SOFT_MASK |
+					    WM8903_VMID_RES_MASK |
+					    WM8903_VMID_BUF_ENA,
+					    WM8903_VMID_TIE_ENA |
+					    WM8903_BUFIO_ENA |
+					    WM8903_VMID_IO_ENA |
+					    (2 << WM8903_VMID_SOFT_SHIFT) |
+					    WM8903_VMID_RES_250K |
+					    WM8903_VMID_BUF_ENA);
+
+			msleep(129);
+
+			snd_soc_component_update_bits(component, WM8903_POWER_MANAGEMENT_5,
+					    WM8903_SPKL_ENA | WM8903_SPKR_ENA,
+					    0);
+
+			snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
+					    WM8903_VMID_SOFT_MASK, 0);
+
+			snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
+					    WM8903_VMID_RES_MASK,
+					    WM8903_VMID_RES_50K);
+
+			snd_soc_component_update_bits(component, WM8903_BIAS_CONTROL_0,
+					    WM8903_BIAS_ENA | WM8903_POBCTRL,
+					    WM8903_BIAS_ENA);
+
+			/* By default no bypass paths are enabled so
+			 * enable Class W support.
+			 */
+			dev_dbg(component->dev, "Enabling Class W\n");
+			snd_soc_component_update_bits(component, WM8903_CLASS_W_0,
+					    WM8903_CP_DYN_FREQ |
+					    WM8903_CP_DYN_V,
+					    WM8903_CP_DYN_FREQ |
+					    WM8903_CP_DYN_V);
+		}
+
+		snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
+				    WM8903_VMID_RES_MASK,
+				    WM8903_VMID_RES_250K);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, WM8903_BIAS_CONTROL_0,
+				    WM8903_BIAS_ENA, 0);
+
+		snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
+				    WM8903_VMID_SOFT_MASK,
+				    2 << WM8903_VMID_SOFT_SHIFT);
+
+		snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
+				    WM8903_VMID_BUF_ENA, 0);
+
+		msleep(290);
+
+		snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
+				    WM8903_VMID_TIE_ENA | WM8903_BUFIO_ENA |
+				    WM8903_VMID_IO_ENA | WM8903_VMID_RES_MASK |
+				    WM8903_VMID_SOFT_MASK |
+				    WM8903_VMID_BUF_ENA, 0);
+
+		snd_soc_component_update_bits(component, WM8903_BIAS_CONTROL_0,
+				    WM8903_STARTUP_BIAS_ENA, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static int wm8903_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
+
+	wm8903->sysclk = freq;
+
+	return 0;
+}
+
+static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 aif1 = snd_soc_component_read32(component, WM8903_AUDIO_INTERFACE_1);
+
+	aif1 &= ~(WM8903_LRCLK_DIR | WM8903_BCLK_DIR | WM8903_AIF_FMT_MASK |
+		  WM8903_AIF_LRCLK_INV | WM8903_AIF_BCLK_INV);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		aif1 |= WM8903_LRCLK_DIR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif1 |= WM8903_LRCLK_DIR | WM8903_BCLK_DIR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		aif1 |= WM8903_BCLK_DIR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		aif1 |= 0x3;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		aif1 |= 0x3 | WM8903_AIF_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aif1 |= 0x2;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		aif1 |= 0x1;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		/* frame inversion not valid for DSP modes */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif1 |= WM8903_AIF_BCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			aif1 |= WM8903_AIF_BCLK_INV | WM8903_AIF_LRCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif1 |= WM8903_AIF_BCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			aif1 |= WM8903_AIF_LRCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8903_AUDIO_INTERFACE_1, aif1);
+
+	return 0;
+}
+
+static int wm8903_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 reg;
+
+	reg = snd_soc_component_read32(component, WM8903_DAC_DIGITAL_1);
+
+	if (mute)
+		reg |= WM8903_DAC_MUTE;
+	else
+		reg &= ~WM8903_DAC_MUTE;
+
+	snd_soc_component_write(component, WM8903_DAC_DIGITAL_1, reg);
+
+	return 0;
+}
+
+/* Lookup table for CLK_SYS/fs ratio.  256fs or more is recommended
+ * for optimal performance so we list the lower rates first and match
+ * on the last match we find. */
+static struct {
+	int div;
+	int rate;
+	int mode;
+	int mclk_div;
+} clk_sys_ratios[] = {
+	{   64, 0x0, 0x0, 1 },
+	{   68, 0x0, 0x1, 1 },
+	{  125, 0x0, 0x2, 1 },
+	{  128, 0x1, 0x0, 1 },
+	{  136, 0x1, 0x1, 1 },
+	{  192, 0x2, 0x0, 1 },
+	{  204, 0x2, 0x1, 1 },
+
+	{   64, 0x0, 0x0, 2 },
+	{   68, 0x0, 0x1, 2 },
+	{  125, 0x0, 0x2, 2 },
+	{  128, 0x1, 0x0, 2 },
+	{  136, 0x1, 0x1, 2 },
+	{  192, 0x2, 0x0, 2 },
+	{  204, 0x2, 0x1, 2 },
+
+	{  250, 0x2, 0x2, 1 },
+	{  256, 0x3, 0x0, 1 },
+	{  272, 0x3, 0x1, 1 },
+	{  384, 0x4, 0x0, 1 },
+	{  408, 0x4, 0x1, 1 },
+	{  375, 0x4, 0x2, 1 },
+	{  512, 0x5, 0x0, 1 },
+	{  544, 0x5, 0x1, 1 },
+	{  500, 0x5, 0x2, 1 },
+	{  768, 0x6, 0x0, 1 },
+	{  816, 0x6, 0x1, 1 },
+	{  750, 0x6, 0x2, 1 },
+	{ 1024, 0x7, 0x0, 1 },
+	{ 1088, 0x7, 0x1, 1 },
+	{ 1000, 0x7, 0x2, 1 },
+	{ 1408, 0x8, 0x0, 1 },
+	{ 1496, 0x8, 0x1, 1 },
+	{ 1536, 0x9, 0x0, 1 },
+	{ 1632, 0x9, 0x1, 1 },
+	{ 1500, 0x9, 0x2, 1 },
+
+	{  250, 0x2, 0x2, 2 },
+	{  256, 0x3, 0x0, 2 },
+	{  272, 0x3, 0x1, 2 },
+	{  384, 0x4, 0x0, 2 },
+	{  408, 0x4, 0x1, 2 },
+	{  375, 0x4, 0x2, 2 },
+	{  512, 0x5, 0x0, 2 },
+	{  544, 0x5, 0x1, 2 },
+	{  500, 0x5, 0x2, 2 },
+	{  768, 0x6, 0x0, 2 },
+	{  816, 0x6, 0x1, 2 },
+	{  750, 0x6, 0x2, 2 },
+	{ 1024, 0x7, 0x0, 2 },
+	{ 1088, 0x7, 0x1, 2 },
+	{ 1000, 0x7, 0x2, 2 },
+	{ 1408, 0x8, 0x0, 2 },
+	{ 1496, 0x8, 0x1, 2 },
+	{ 1536, 0x9, 0x0, 2 },
+	{ 1632, 0x9, 0x1, 2 },
+	{ 1500, 0x9, 0x2, 2 },
+};
+
+/* CLK_SYS/BCLK ratios - multiplied by 10 due to .5s */
+static struct {
+	int ratio;
+	int div;
+} bclk_divs[] = {
+	{  10,  0 },
+	{  20,  2 },
+	{  30,  3 },
+	{  40,  4 },
+	{  50,  5 },
+	{  60,  7 },
+	{  80,  8 },
+	{ 100,  9 },
+	{ 120, 11 },
+	{ 160, 12 },
+	{ 200, 13 },
+	{ 220, 14 },
+	{ 240, 15 },
+	{ 300, 17 },
+	{ 320, 18 },
+	{ 440, 19 },
+	{ 480, 20 },
+};
+
+/* Sample rates for DSP */
+static struct {
+	int rate;
+	int value;
+} sample_rates[] = {
+	{  8000,  0 },
+	{ 11025,  1 },
+	{ 12000,  2 },
+	{ 16000,  3 },
+	{ 22050,  4 },
+	{ 24000,  5 },
+	{ 32000,  6 },
+	{ 44100,  7 },
+	{ 48000,  8 },
+	{ 88200,  9 },
+	{ 96000, 10 },
+	{ 0,      0 },
+};
+
+static int wm8903_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
+	int fs = params_rate(params);
+	int bclk;
+	int bclk_div;
+	int i;
+	int dsp_config;
+	int clk_config;
+	int best_val;
+	int cur_val;
+	int clk_sys;
+
+	u16 aif1 = snd_soc_component_read32(component, WM8903_AUDIO_INTERFACE_1);
+	u16 aif2 = snd_soc_component_read32(component, WM8903_AUDIO_INTERFACE_2);
+	u16 aif3 = snd_soc_component_read32(component, WM8903_AUDIO_INTERFACE_3);
+	u16 clock0 = snd_soc_component_read32(component, WM8903_CLOCK_RATES_0);
+	u16 clock1 = snd_soc_component_read32(component, WM8903_CLOCK_RATES_1);
+	u16 dac_digital1 = snd_soc_component_read32(component, WM8903_DAC_DIGITAL_1);
+
+	/* Enable sloping stopband filter for low sample rates */
+	if (fs <= 24000)
+		dac_digital1 |= WM8903_DAC_SB_FILT;
+	else
+		dac_digital1 &= ~WM8903_DAC_SB_FILT;
+
+	/* Configure sample rate logic for DSP - choose nearest rate */
+	dsp_config = 0;
+	best_val = abs(sample_rates[dsp_config].rate - fs);
+	for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
+		cur_val = abs(sample_rates[i].rate - fs);
+		if (cur_val <= best_val) {
+			dsp_config = i;
+			best_val = cur_val;
+		}
+	}
+
+	dev_dbg(component->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
+	clock1 &= ~WM8903_SAMPLE_RATE_MASK;
+	clock1 |= sample_rates[dsp_config].value;
+
+	aif1 &= ~WM8903_AIF_WL_MASK;
+	bclk = 2 * fs;
+	switch (params_width(params)) {
+	case 16:
+		bclk *= 16;
+		break;
+	case 20:
+		bclk *= 20;
+		aif1 |= 0x4;
+		break;
+	case 24:
+		bclk *= 24;
+		aif1 |= 0x8;
+		break;
+	case 32:
+		bclk *= 32;
+		aif1 |= 0xc;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dev_dbg(component->dev, "MCLK = %dHz, target sample rate = %dHz\n",
+		wm8903->sysclk, fs);
+
+	/* We may not have an MCLK which allows us to generate exactly
+	 * the clock we want, particularly with USB derived inputs, so
+	 * approximate.
+	 */
+	clk_config = 0;
+	best_val = abs((wm8903->sysclk /
+			(clk_sys_ratios[0].mclk_div *
+			 clk_sys_ratios[0].div)) - fs);
+	for (i = 1; i < ARRAY_SIZE(clk_sys_ratios); i++) {
+		cur_val = abs((wm8903->sysclk /
+			       (clk_sys_ratios[i].mclk_div *
+				clk_sys_ratios[i].div)) - fs);
+
+		if (cur_val <= best_val) {
+			clk_config = i;
+			best_val = cur_val;
+		}
+	}
+
+	if (clk_sys_ratios[clk_config].mclk_div == 2) {
+		clock0 |= WM8903_MCLKDIV2;
+		clk_sys = wm8903->sysclk / 2;
+	} else {
+		clock0 &= ~WM8903_MCLKDIV2;
+		clk_sys = wm8903->sysclk;
+	}
+
+	clock1 &= ~(WM8903_CLK_SYS_RATE_MASK |
+		    WM8903_CLK_SYS_MODE_MASK);
+	clock1 |= clk_sys_ratios[clk_config].rate << WM8903_CLK_SYS_RATE_SHIFT;
+	clock1 |= clk_sys_ratios[clk_config].mode << WM8903_CLK_SYS_MODE_SHIFT;
+
+	dev_dbg(component->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n",
+		clk_sys_ratios[clk_config].rate,
+		clk_sys_ratios[clk_config].mode,
+		clk_sys_ratios[clk_config].div);
+
+	dev_dbg(component->dev, "Actual CLK_SYS = %dHz\n", clk_sys);
+
+	/* We may not get quite the right frequency if using
+	 * approximate clocks so look for the closest match that is
+	 * higher than the target (we need to ensure that there enough
+	 * BCLKs to clock out the samples).
+	 */
+	bclk_div = 0;
+	best_val = ((clk_sys * 10) / bclk_divs[0].ratio) - bclk;
+	i = 1;
+	while (i < ARRAY_SIZE(bclk_divs)) {
+		cur_val = ((clk_sys * 10) / bclk_divs[i].ratio) - bclk;
+		if (cur_val < 0) /* BCLK table is sorted */
+			break;
+		bclk_div = i;
+		best_val = cur_val;
+		i++;
+	}
+
+	aif2 &= ~WM8903_BCLK_DIV_MASK;
+	aif3 &= ~WM8903_LRCLK_RATE_MASK;
+
+	dev_dbg(component->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n",
+		bclk_divs[bclk_div].ratio / 10, bclk,
+		(clk_sys * 10) / bclk_divs[bclk_div].ratio);
+
+	aif2 |= bclk_divs[bclk_div].div;
+	aif3 |= bclk / fs;
+
+	wm8903->fs = params_rate(params);
+	wm8903_set_deemph(component);
+
+	snd_soc_component_write(component, WM8903_CLOCK_RATES_0, clock0);
+	snd_soc_component_write(component, WM8903_CLOCK_RATES_1, clock1);
+	snd_soc_component_write(component, WM8903_AUDIO_INTERFACE_1, aif1);
+	snd_soc_component_write(component, WM8903_AUDIO_INTERFACE_2, aif2);
+	snd_soc_component_write(component, WM8903_AUDIO_INTERFACE_3, aif3);
+	snd_soc_component_write(component, WM8903_DAC_DIGITAL_1, dac_digital1);
+
+	return 0;
+}
+
+/**
+ * wm8903_mic_detect - Enable microphone detection via the WM8903 IRQ
+ *
+ * @component:  WM8903 component
+ * @jack:   jack to report detection events on
+ * @det:    value to report for presence detection
+ * @shrt:   value to report for short detection
+ *
+ * Enable microphone detection via IRQ on the WM8903.  If GPIOs are
+ * being used to bring out signals to the processor then only platform
+ * data configuration is needed for WM8903 and processor GPIOs should
+ * be configured using snd_soc_jack_add_gpios() instead.
+ *
+ * The current threasholds for detection should be configured using
+ * micdet_cfg in the platform data.  Using this function will force on
+ * the microphone bias for the device.
+ */
+int wm8903_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
+		      int det, int shrt)
+{
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
+	int irq_mask = WM8903_MICDET_EINT | WM8903_MICSHRT_EINT;
+
+	dev_dbg(component->dev, "Enabling microphone detection: %x %x\n",
+		det, shrt);
+
+	/* Store the configuration */
+	wm8903->mic_jack = jack;
+	wm8903->mic_det = det;
+	wm8903->mic_short = shrt;
+
+	/* Enable interrupts we've got a report configured for */
+	if (det)
+		irq_mask &= ~WM8903_MICDET_EINT;
+	if (shrt)
+		irq_mask &= ~WM8903_MICSHRT_EINT;
+
+	snd_soc_component_update_bits(component, WM8903_INTERRUPT_STATUS_1_MASK,
+			    WM8903_MICDET_EINT | WM8903_MICSHRT_EINT,
+			    irq_mask);
+
+	if (det || shrt) {
+		/* Enable mic detection, this may not have been set through
+		 * platform data (eg, if the defaults are OK). */
+		snd_soc_component_update_bits(component, WM8903_WRITE_SEQUENCER_0,
+				    WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
+		snd_soc_component_update_bits(component, WM8903_MIC_BIAS_CONTROL_0,
+				    WM8903_MICDET_ENA, WM8903_MICDET_ENA);
+	} else {
+		snd_soc_component_update_bits(component, WM8903_MIC_BIAS_CONTROL_0,
+				    WM8903_MICDET_ENA, 0);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8903_mic_detect);
+
+static irqreturn_t wm8903_irq(int irq, void *data)
+{
+	struct wm8903_priv *wm8903 = data;
+	int mic_report, ret;
+	unsigned int int_val, mask, int_pol;
+
+	ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_STATUS_1_MASK,
+			  &mask);
+	if (ret != 0) {
+		dev_err(wm8903->dev, "Failed to read IRQ mask: %d\n", ret);
+		return IRQ_NONE;
+	}
+
+	ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_STATUS_1, &int_val);
+	if (ret != 0) {
+		dev_err(wm8903->dev, "Failed to read IRQ status: %d\n", ret);
+		return IRQ_NONE;
+	}
+
+	int_val &= ~mask;
+
+	if (int_val & WM8903_WSEQ_BUSY_EINT) {
+		dev_warn(wm8903->dev, "Write sequencer done\n");
+	}
+
+	/*
+	 * The rest is microphone jack detection.  We need to manually
+	 * invert the polarity of the interrupt after each event - to
+	 * simplify the code keep track of the last state we reported
+	 * and just invert the relevant bits in both the report and
+	 * the polarity register.
+	 */
+	mic_report = wm8903->mic_last_report;
+	ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1,
+			  &int_pol);
+	if (ret != 0) {
+		dev_err(wm8903->dev, "Failed to read interrupt polarity: %d\n",
+			ret);
+		return IRQ_HANDLED;
+	}
+
+#ifndef CONFIG_SND_SOC_WM8903_MODULE
+	if (int_val & (WM8903_MICSHRT_EINT | WM8903_MICDET_EINT))
+		trace_snd_soc_jack_irq(dev_name(wm8903->dev));
+#endif
+
+	if (int_val & WM8903_MICSHRT_EINT) {
+		dev_dbg(wm8903->dev, "Microphone short (pol=%x)\n", int_pol);
+
+		mic_report ^= wm8903->mic_short;
+		int_pol ^= WM8903_MICSHRT_INV;
+	}
+
+	if (int_val & WM8903_MICDET_EINT) {
+		dev_dbg(wm8903->dev, "Microphone detect (pol=%x)\n", int_pol);
+
+		mic_report ^= wm8903->mic_det;
+		int_pol ^= WM8903_MICDET_INV;
+
+		msleep(wm8903->mic_delay);
+	}
+
+	regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1,
+			   WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol);
+
+	snd_soc_jack_report(wm8903->mic_jack, mic_report,
+			    wm8903->mic_short | wm8903->mic_det);
+
+	wm8903->mic_last_report = mic_report;
+
+	return IRQ_HANDLED;
+}
+
+#define WM8903_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\
+			       SNDRV_PCM_RATE_11025 |	\
+			       SNDRV_PCM_RATE_16000 |	\
+			       SNDRV_PCM_RATE_22050 |	\
+			       SNDRV_PCM_RATE_32000 |	\
+			       SNDRV_PCM_RATE_44100 |	\
+			       SNDRV_PCM_RATE_48000 |	\
+			       SNDRV_PCM_RATE_88200 |	\
+			       SNDRV_PCM_RATE_96000)
+
+#define WM8903_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
+			      SNDRV_PCM_RATE_11025 |	\
+			      SNDRV_PCM_RATE_16000 |	\
+			      SNDRV_PCM_RATE_22050 |	\
+			      SNDRV_PCM_RATE_32000 |	\
+			      SNDRV_PCM_RATE_44100 |	\
+			      SNDRV_PCM_RATE_48000)
+
+#define WM8903_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops wm8903_dai_ops = {
+	.hw_params	= wm8903_hw_params,
+	.digital_mute	= wm8903_digital_mute,
+	.set_fmt	= wm8903_set_dai_fmt,
+	.set_sysclk	= wm8903_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8903_dai = {
+	.name = "wm8903-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM8903_PLAYBACK_RATES,
+		.formats = WM8903_FORMATS,
+	},
+	.capture = {
+		 .stream_name = "Capture",
+		 .channels_min = 2,
+		 .channels_max = 2,
+		 .rates = WM8903_CAPTURE_RATES,
+		 .formats = WM8903_FORMATS,
+	 },
+	.ops = &wm8903_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int wm8903_resume(struct snd_soc_component *component)
+{
+	struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
+
+	regcache_sync(wm8903->regmap);
+
+	return 0;
+}
+
+#ifdef CONFIG_GPIOLIB
+static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	if (offset >= WM8903_NUM_GPIO)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+	struct wm8903_priv *wm8903 = gpiochip_get_data(chip);
+	unsigned int mask, val;
+	int ret;
+
+	mask = WM8903_GP1_FN_MASK | WM8903_GP1_DIR_MASK;
+	val = (WM8903_GPn_FN_GPIO_INPUT << WM8903_GP1_FN_SHIFT) |
+		WM8903_GP1_DIR;
+
+	ret = regmap_update_bits(wm8903->regmap,
+				 WM8903_GPIO_CONTROL_1 + offset, mask, val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct wm8903_priv *wm8903 = gpiochip_get_data(chip);
+	unsigned int reg;
+
+	regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, &reg);
+
+	return !!((reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT);
+}
+
+static int wm8903_gpio_direction_out(struct gpio_chip *chip,
+				     unsigned offset, int value)
+{
+	struct wm8903_priv *wm8903 = gpiochip_get_data(chip);
+	unsigned int mask, val;
+	int ret;
+
+	mask = WM8903_GP1_FN_MASK | WM8903_GP1_DIR_MASK | WM8903_GP1_LVL_MASK;
+	val = (WM8903_GPn_FN_GPIO_OUTPUT << WM8903_GP1_FN_SHIFT) |
+		(value << WM8903_GP2_LVL_SHIFT);
+
+	ret = regmap_update_bits(wm8903->regmap,
+				 WM8903_GPIO_CONTROL_1 + offset, mask, val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct wm8903_priv *wm8903 = gpiochip_get_data(chip);
+
+	regmap_update_bits(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset,
+			   WM8903_GP1_LVL_MASK,
+			   !!value << WM8903_GP1_LVL_SHIFT);
+}
+
+static const struct gpio_chip wm8903_template_chip = {
+	.label			= "wm8903",
+	.owner			= THIS_MODULE,
+	.request		= wm8903_gpio_request,
+	.direction_input	= wm8903_gpio_direction_in,
+	.get			= wm8903_gpio_get,
+	.direction_output	= wm8903_gpio_direction_out,
+	.set			= wm8903_gpio_set,
+	.can_sleep		= 1,
+};
+
+static void wm8903_init_gpio(struct wm8903_priv *wm8903)
+{
+	struct wm8903_platform_data *pdata = wm8903->pdata;
+	int ret;
+
+	wm8903->gpio_chip = wm8903_template_chip;
+	wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO;
+	wm8903->gpio_chip.parent = wm8903->dev;
+
+	if (pdata->gpio_base)
+		wm8903->gpio_chip.base = pdata->gpio_base;
+	else
+		wm8903->gpio_chip.base = -1;
+
+	ret = gpiochip_add_data(&wm8903->gpio_chip, wm8903);
+	if (ret != 0)
+		dev_err(wm8903->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm8903_free_gpio(struct wm8903_priv *wm8903)
+{
+	gpiochip_remove(&wm8903->gpio_chip);
+}
+#else
+static void wm8903_init_gpio(struct wm8903_priv *wm8903)
+{
+}
+
+static void wm8903_free_gpio(struct wm8903_priv *wm8903)
+{
+}
+#endif
+
+static const struct snd_soc_component_driver soc_component_dev_wm8903 = {
+	.resume			= wm8903_resume,
+	.set_bias_level		= wm8903_set_bias_level,
+	.seq_notifier		= wm8903_seq_notifier,
+	.controls		= wm8903_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8903_snd_controls),
+	.dapm_widgets		= wm8903_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8903_dapm_widgets),
+	.dapm_routes		= wm8903_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(wm8903_intercon),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8903_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = WM8903_MAX_REGISTER,
+	.volatile_reg = wm8903_volatile_register,
+	.readable_reg = wm8903_readable_register,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8903_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8903_reg_defaults),
+};
+
+static int wm8903_set_pdata_irq_trigger(struct i2c_client *i2c,
+					struct wm8903_platform_data *pdata)
+{
+	struct irq_data *irq_data = irq_get_irq_data(i2c->irq);
+	if (!irq_data) {
+		dev_err(&i2c->dev, "Invalid IRQ: %d\n",
+			i2c->irq);
+		return -EINVAL;
+	}
+
+	switch (irqd_get_trigger_type(irq_data)) {
+	case IRQ_TYPE_NONE:
+	default:
+		/*
+		* We assume the controller imposes no restrictions,
+		* so we are able to select active-high
+		*/
+		/* Fall-through */
+	case IRQ_TYPE_LEVEL_HIGH:
+		pdata->irq_active_low = false;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		pdata->irq_active_low = true;
+		break;
+	}
+
+	return 0;
+}
+
+static int wm8903_set_pdata_from_of(struct i2c_client *i2c,
+				    struct wm8903_platform_data *pdata)
+{
+	const struct device_node *np = i2c->dev.of_node;
+	u32 val32;
+	int i;
+
+	if (of_property_read_u32(np, "micdet-cfg", &val32) >= 0)
+		pdata->micdet_cfg = val32;
+
+	if (of_property_read_u32(np, "micdet-delay", &val32) >= 0)
+		pdata->micdet_delay = val32;
+
+	if (of_property_read_u32_array(np, "gpio-cfg", pdata->gpio_cfg,
+				       ARRAY_SIZE(pdata->gpio_cfg)) >= 0) {
+		/*
+		 * In device tree: 0 means "write 0",
+		 * 0xffffffff means "don't touch".
+		 *
+		 * In platform data: 0 means "don't touch",
+		 * 0x8000 means "write 0".
+		 *
+		 * Note: WM8903_GPIO_CONFIG_ZERO == 0x8000.
+		 *
+		 *  Convert from DT to pdata representation here,
+		 * so no other code needs to change.
+		 */
+		for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
+			if (pdata->gpio_cfg[i] == 0) {
+				pdata->gpio_cfg[i] = WM8903_GPIO_CONFIG_ZERO;
+			} else if (pdata->gpio_cfg[i] == 0xffffffff) {
+				pdata->gpio_cfg[i] = 0;
+			} else if (pdata->gpio_cfg[i] > 0x7fff) {
+				dev_err(&i2c->dev, "Invalid gpio-cfg[%d] %x\n",
+					i, pdata->gpio_cfg[i]);
+				return -EINVAL;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int wm8903_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct wm8903_priv *wm8903;
+	int trigger;
+	bool mic_gpio = false;
+	unsigned int val, irq_pol;
+	int ret, i;
+
+	wm8903 = devm_kzalloc(&i2c->dev, sizeof(*wm8903), GFP_KERNEL);
+	if (wm8903 == NULL)
+		return -ENOMEM;
+
+	mutex_init(&wm8903->lock);
+	wm8903->dev = &i2c->dev;
+
+	wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap);
+	if (IS_ERR(wm8903->regmap)) {
+		ret = PTR_ERR(wm8903->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, wm8903);
+
+	/* If no platform data was supplied, create storage for defaults */
+	if (pdata) {
+		wm8903->pdata = pdata;
+	} else {
+		wm8903->pdata = devm_kzalloc(&i2c->dev, sizeof(*wm8903->pdata),
+					     GFP_KERNEL);
+		if (!wm8903->pdata)
+			return -ENOMEM;
+
+		if (i2c->irq) {
+			ret = wm8903_set_pdata_irq_trigger(i2c, wm8903->pdata);
+			if (ret != 0)
+				return ret;
+		}
+
+		if (i2c->dev.of_node) {
+			ret = wm8903_set_pdata_from_of(i2c, wm8903->pdata);
+			if (ret != 0)
+				return ret;
+		}
+	}
+
+	pdata = wm8903->pdata;
+
+	for (i = 0; i < ARRAY_SIZE(wm8903->supplies); i++)
+		wm8903->supplies[i].supply = wm8903_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8903->supplies),
+				      wm8903->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8903->supplies),
+				    wm8903->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(wm8903->regmap, WM8903_SW_RESET_AND_ID, &val);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
+		goto err;
+	}
+	if (val != 0x8903) {
+		dev_err(&i2c->dev, "Device with ID %x is not a WM8903\n", val);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	ret = regmap_read(wm8903->regmap, WM8903_REVISION_NUMBER, &val);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to read chip revision: %d\n", ret);
+		goto err;
+	}
+	dev_info(&i2c->dev, "WM8903 revision %c\n",
+		 (val & WM8903_CHIP_REV_MASK) + 'A');
+
+	/* Reset the device */
+	regmap_write(wm8903->regmap, WM8903_SW_RESET_AND_ID, 0x8903);
+
+	wm8903_init_gpio(wm8903);
+
+	/* Set up GPIO pin state, detect if any are MIC detect outputs */
+	for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
+		if ((!pdata->gpio_cfg[i]) ||
+		    (pdata->gpio_cfg[i] > WM8903_GPIO_CONFIG_ZERO))
+			continue;
+
+		regmap_write(wm8903->regmap, WM8903_GPIO_CONTROL_1 + i,
+				pdata->gpio_cfg[i] & 0x7fff);
+
+		val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK)
+			>> WM8903_GP1_FN_SHIFT;
+
+		switch (val) {
+		case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT:
+		case WM8903_GPn_FN_MICBIAS_SHORT_DETECT:
+			mic_gpio = true;
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* Set up microphone detection */
+	regmap_write(wm8903->regmap, WM8903_MIC_BIAS_CONTROL_0,
+		     pdata->micdet_cfg);
+
+	/* Microphone detection needs the WSEQ clock */
+	if (pdata->micdet_cfg)
+		regmap_update_bits(wm8903->regmap, WM8903_WRITE_SEQUENCER_0,
+				   WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
+
+	/* If microphone detection is enabled by pdata but
+	 * detected via IRQ then interrupts can be lost before
+	 * the machine driver has set up microphone detection
+	 * IRQs as the IRQs are clear on read.  The detection
+	 * will be enabled when the machine driver configures.
+	 */
+	WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA));
+
+	wm8903->mic_delay = pdata->micdet_delay;
+
+	if (i2c->irq) {
+		if (pdata->irq_active_low) {
+			trigger = IRQF_TRIGGER_LOW;
+			irq_pol = WM8903_IRQ_POL;
+		} else {
+			trigger = IRQF_TRIGGER_HIGH;
+			irq_pol = 0;
+		}
+
+		regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_CONTROL,
+				   WM8903_IRQ_POL, irq_pol);
+
+		ret = request_threaded_irq(i2c->irq, NULL, wm8903_irq,
+					   trigger | IRQF_ONESHOT,
+					   "wm8903", wm8903);
+		if (ret != 0) {
+			dev_err(wm8903->dev, "Failed to request IRQ: %d\n",
+				ret);
+			return ret;
+		}
+
+		/* Enable write sequencer interrupts */
+		regmap_update_bits(wm8903->regmap,
+				   WM8903_INTERRUPT_STATUS_1_MASK,
+				   WM8903_IM_WSEQ_BUSY_EINT, 0);
+	}
+
+	/* Latch volume update bits */
+	regmap_update_bits(wm8903->regmap, WM8903_ADC_DIGITAL_VOLUME_LEFT,
+			   WM8903_ADCVU, WM8903_ADCVU);
+	regmap_update_bits(wm8903->regmap, WM8903_ADC_DIGITAL_VOLUME_RIGHT,
+			   WM8903_ADCVU, WM8903_ADCVU);
+
+	regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_VOLUME_LEFT,
+			   WM8903_DACVU, WM8903_DACVU);
+	regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_VOLUME_RIGHT,
+			   WM8903_DACVU, WM8903_DACVU);
+
+	regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT1_LEFT,
+			   WM8903_HPOUTVU, WM8903_HPOUTVU);
+	regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT1_RIGHT,
+			   WM8903_HPOUTVU, WM8903_HPOUTVU);
+
+	regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT2_LEFT,
+			   WM8903_LINEOUTVU, WM8903_LINEOUTVU);
+	regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT2_RIGHT,
+			   WM8903_LINEOUTVU, WM8903_LINEOUTVU);
+
+	regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT3_LEFT,
+			   WM8903_SPKVU, WM8903_SPKVU);
+	regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT3_RIGHT,
+			   WM8903_SPKVU, WM8903_SPKVU);
+
+	/* Enable DAC soft mute by default */
+	regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_1,
+			   WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE,
+			   WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8903, &wm8903_dai, 1);
+	if (ret != 0)
+		goto err;
+
+	return 0;
+err:
+	regulator_bulk_disable(ARRAY_SIZE(wm8903->supplies),
+			       wm8903->supplies);
+	return ret;
+}
+
+static int wm8903_i2c_remove(struct i2c_client *client)
+{
+	struct wm8903_priv *wm8903 = i2c_get_clientdata(client);
+
+	regulator_bulk_disable(ARRAY_SIZE(wm8903->supplies),
+			       wm8903->supplies);
+	if (client->irq)
+		free_irq(client->irq, wm8903);
+	wm8903_free_gpio(wm8903);
+
+	return 0;
+}
+
+static const struct of_device_id wm8903_of_match[] = {
+	{ .compatible = "wlf,wm8903", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, wm8903_of_match);
+
+static const struct i2c_device_id wm8903_i2c_id[] = {
+	{ "wm8903", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id);
+
+static struct i2c_driver wm8903_i2c_driver = {
+	.driver = {
+		.name = "wm8903",
+		.of_match_table = wm8903_of_match,
+	},
+	.probe =    wm8903_i2c_probe,
+	.remove =   wm8903_i2c_remove,
+	.id_table = wm8903_i2c_id,
+};
+
+module_i2c_driver(wm8903_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8903 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h
new file mode 100644
index 0000000..1301aa9
--- /dev/null
+++ b/sound/soc/codecs/wm8903.h
@@ -0,0 +1,1225 @@
+/*
+ * wm8903.h - WM8903 audio codec interface
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _WM8903_H
+#define _WM8903_H
+
+#include <linux/i2c.h>
+
+extern int wm8903_mic_detect(struct snd_soc_component *component,
+			     struct snd_soc_jack *jack,
+			     int det, int shrt);
+
+
+/*
+ * Register values.
+ */
+#define WM8903_SW_RESET_AND_ID                  0x00
+#define WM8903_REVISION_NUMBER                  0x01
+#define WM8903_BIAS_CONTROL_0                   0x04
+#define WM8903_VMID_CONTROL_0                   0x05
+#define WM8903_MIC_BIAS_CONTROL_0               0x06
+#define WM8903_ANALOGUE_DAC_0                   0x08
+#define WM8903_ANALOGUE_ADC_0                   0x0A
+#define WM8903_POWER_MANAGEMENT_0               0x0C
+#define WM8903_POWER_MANAGEMENT_1               0x0D
+#define WM8903_POWER_MANAGEMENT_2               0x0E
+#define WM8903_POWER_MANAGEMENT_3               0x0F
+#define WM8903_POWER_MANAGEMENT_4               0x10
+#define WM8903_POWER_MANAGEMENT_5               0x11
+#define WM8903_POWER_MANAGEMENT_6               0x12
+#define WM8903_CLOCK_RATES_0                    0x14
+#define WM8903_CLOCK_RATES_1                    0x15
+#define WM8903_CLOCK_RATES_2                    0x16
+#define WM8903_AUDIO_INTERFACE_0                0x18
+#define WM8903_AUDIO_INTERFACE_1                0x19
+#define WM8903_AUDIO_INTERFACE_2                0x1A
+#define WM8903_AUDIO_INTERFACE_3                0x1B
+#define WM8903_DAC_DIGITAL_VOLUME_LEFT          0x1E
+#define WM8903_DAC_DIGITAL_VOLUME_RIGHT         0x1F
+#define WM8903_DAC_DIGITAL_0                    0x20
+#define WM8903_DAC_DIGITAL_1                    0x21
+#define WM8903_ADC_DIGITAL_VOLUME_LEFT          0x24
+#define WM8903_ADC_DIGITAL_VOLUME_RIGHT         0x25
+#define WM8903_ADC_DIGITAL_0                    0x26
+#define WM8903_DIGITAL_MICROPHONE_0             0x27
+#define WM8903_DRC_0                            0x28
+#define WM8903_DRC_1                            0x29
+#define WM8903_DRC_2                            0x2A
+#define WM8903_DRC_3                            0x2B
+#define WM8903_ANALOGUE_LEFT_INPUT_0            0x2C
+#define WM8903_ANALOGUE_RIGHT_INPUT_0           0x2D
+#define WM8903_ANALOGUE_LEFT_INPUT_1            0x2E
+#define WM8903_ANALOGUE_RIGHT_INPUT_1           0x2F
+#define WM8903_ANALOGUE_LEFT_MIX_0              0x32
+#define WM8903_ANALOGUE_RIGHT_MIX_0             0x33
+#define WM8903_ANALOGUE_SPK_MIX_LEFT_0          0x34
+#define WM8903_ANALOGUE_SPK_MIX_LEFT_1          0x35
+#define WM8903_ANALOGUE_SPK_MIX_RIGHT_0         0x36
+#define WM8903_ANALOGUE_SPK_MIX_RIGHT_1         0x37
+#define WM8903_ANALOGUE_OUT1_LEFT               0x39
+#define WM8903_ANALOGUE_OUT1_RIGHT              0x3A
+#define WM8903_ANALOGUE_OUT2_LEFT               0x3B
+#define WM8903_ANALOGUE_OUT2_RIGHT              0x3C
+#define WM8903_ANALOGUE_OUT3_LEFT               0x3E
+#define WM8903_ANALOGUE_OUT3_RIGHT              0x3F
+#define WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0    0x41
+#define WM8903_DC_SERVO_0                       0x43
+#define WM8903_DC_SERVO_2                       0x45
+#define WM8903_DC_SERVO_4			0x47
+#define WM8903_DC_SERVO_5			0x48
+#define WM8903_DC_SERVO_6			0x49
+#define WM8903_DC_SERVO_7			0x4A
+#define WM8903_DC_SERVO_READBACK_1		0x51
+#define WM8903_DC_SERVO_READBACK_2		0x52
+#define WM8903_DC_SERVO_READBACK_3		0x53
+#define WM8903_DC_SERVO_READBACK_4		0x54
+#define WM8903_ANALOGUE_HP_0                    0x5A
+#define WM8903_ANALOGUE_LINEOUT_0               0x5E
+#define WM8903_CHARGE_PUMP_0                    0x62
+#define WM8903_CLASS_W_0                        0x68
+#define WM8903_WRITE_SEQUENCER_0                0x6C
+#define WM8903_WRITE_SEQUENCER_1                0x6D
+#define WM8903_WRITE_SEQUENCER_2                0x6E
+#define WM8903_WRITE_SEQUENCER_3                0x6F
+#define WM8903_WRITE_SEQUENCER_4                0x70
+#define WM8903_CONTROL_INTERFACE                0x72
+#define WM8903_GPIO_CONTROL_1                   0x74
+#define WM8903_GPIO_CONTROL_2                   0x75
+#define WM8903_GPIO_CONTROL_3                   0x76
+#define WM8903_GPIO_CONTROL_4                   0x77
+#define WM8903_GPIO_CONTROL_5                   0x78
+#define WM8903_INTERRUPT_STATUS_1               0x79
+#define WM8903_INTERRUPT_STATUS_1_MASK          0x7A
+#define WM8903_INTERRUPT_POLARITY_1             0x7B
+#define WM8903_INTERRUPT_CONTROL                0x7E
+#define WM8903_CLOCK_RATE_TEST_4                0xA4
+#define WM8903_ANALOGUE_OUTPUT_BIAS_0           0xAC
+
+#define WM8903_REGISTER_COUNT                   75
+#define WM8903_MAX_REGISTER                     0xAC
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - SW Reset and ID
+ */
+#define WM8903_SW_RESET_DEV_ID1_MASK            0xFFFF  /* SW_RESET_DEV_ID1 - [15:0] */
+#define WM8903_SW_RESET_DEV_ID1_SHIFT                0  /* SW_RESET_DEV_ID1 - [15:0] */
+#define WM8903_SW_RESET_DEV_ID1_WIDTH               16  /* SW_RESET_DEV_ID1 - [15:0] */
+
+/*
+ * R1 (0x01) - Revision Number
+ */
+#define WM8903_CHIP_REV_MASK                    0x000F  /* CHIP_REV - [3:0] */
+#define WM8903_CHIP_REV_SHIFT                        0  /* CHIP_REV - [3:0] */
+#define WM8903_CHIP_REV_WIDTH                        4  /* CHIP_REV - [3:0] */
+
+/*
+ * R4 (0x04) - Bias Control 0
+ */
+#define WM8903_POBCTRL                          0x0010  /* POBCTRL */
+#define WM8903_POBCTRL_MASK                     0x0010  /* POBCTRL */
+#define WM8903_POBCTRL_SHIFT                         4  /* POBCTRL */
+#define WM8903_POBCTRL_WIDTH                         1  /* POBCTRL */
+#define WM8903_ISEL_MASK                        0x000C  /* ISEL - [3:2] */
+#define WM8903_ISEL_SHIFT                            2  /* ISEL - [3:2] */
+#define WM8903_ISEL_WIDTH                            2  /* ISEL - [3:2] */
+#define WM8903_STARTUP_BIAS_ENA                 0x0002  /* STARTUP_BIAS_ENA */
+#define WM8903_STARTUP_BIAS_ENA_MASK            0x0002  /* STARTUP_BIAS_ENA */
+#define WM8903_STARTUP_BIAS_ENA_SHIFT                1  /* STARTUP_BIAS_ENA */
+#define WM8903_STARTUP_BIAS_ENA_WIDTH                1  /* STARTUP_BIAS_ENA */
+#define WM8903_BIAS_ENA                         0x0001  /* BIAS_ENA */
+#define WM8903_BIAS_ENA_MASK                    0x0001  /* BIAS_ENA */
+#define WM8903_BIAS_ENA_SHIFT                        0  /* BIAS_ENA */
+#define WM8903_BIAS_ENA_WIDTH                        1  /* BIAS_ENA */
+
+/*
+ * R5 (0x05) - VMID Control 0
+ */
+#define WM8903_VMID_TIE_ENA                     0x0080  /* VMID_TIE_ENA */
+#define WM8903_VMID_TIE_ENA_MASK                0x0080  /* VMID_TIE_ENA */
+#define WM8903_VMID_TIE_ENA_SHIFT                    7  /* VMID_TIE_ENA */
+#define WM8903_VMID_TIE_ENA_WIDTH                    1  /* VMID_TIE_ENA */
+#define WM8903_BUFIO_ENA                        0x0040  /* BUFIO_ENA */
+#define WM8903_BUFIO_ENA_MASK                   0x0040  /* BUFIO_ENA */
+#define WM8903_BUFIO_ENA_SHIFT                       6  /* BUFIO_ENA */
+#define WM8903_BUFIO_ENA_WIDTH                       1  /* BUFIO_ENA */
+#define WM8903_VMID_IO_ENA                      0x0020  /* VMID_IO_ENA */
+#define WM8903_VMID_IO_ENA_MASK                 0x0020  /* VMID_IO_ENA */
+#define WM8903_VMID_IO_ENA_SHIFT                     5  /* VMID_IO_ENA */
+#define WM8903_VMID_IO_ENA_WIDTH                     1  /* VMID_IO_ENA */
+#define WM8903_VMID_SOFT_MASK                   0x0018  /* VMID_SOFT - [4:3] */
+#define WM8903_VMID_SOFT_SHIFT                       3  /* VMID_SOFT - [4:3] */
+#define WM8903_VMID_SOFT_WIDTH                       2  /* VMID_SOFT - [4:3] */
+#define WM8903_VMID_RES_MASK                    0x0006  /* VMID_RES - [2:1] */
+#define WM8903_VMID_RES_SHIFT                        1  /* VMID_RES - [2:1] */
+#define WM8903_VMID_RES_WIDTH                        2  /* VMID_RES - [2:1] */
+#define WM8903_VMID_BUF_ENA                     0x0001  /* VMID_BUF_ENA */
+#define WM8903_VMID_BUF_ENA_MASK                0x0001  /* VMID_BUF_ENA */
+#define WM8903_VMID_BUF_ENA_SHIFT                    0  /* VMID_BUF_ENA */
+#define WM8903_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
+
+#define WM8903_VMID_RES_50K                          2
+#define WM8903_VMID_RES_250K                         4
+#define WM8903_VMID_RES_5K                           6
+
+/*
+ * R8 (0x08) - Analogue DAC 0
+ */
+#define WM8903_DACBIAS_SEL_MASK                 0x0018  /* DACBIAS_SEL - [4:3] */
+#define WM8903_DACBIAS_SEL_SHIFT                     3  /* DACBIAS_SEL - [4:3] */
+#define WM8903_DACBIAS_SEL_WIDTH                     2  /* DACBIAS_SEL - [4:3] */
+#define WM8903_DACVMID_BIAS_SEL_MASK            0x0006  /* DACVMID_BIAS_SEL - [2:1] */
+#define WM8903_DACVMID_BIAS_SEL_SHIFT                1  /* DACVMID_BIAS_SEL - [2:1] */
+#define WM8903_DACVMID_BIAS_SEL_WIDTH                2  /* DACVMID_BIAS_SEL - [2:1] */
+
+/*
+ * R10 (0x0A) - Analogue ADC 0
+ */
+#define WM8903_ADC_OSR128                       0x0001  /* ADC_OSR128 */
+#define WM8903_ADC_OSR128_MASK                  0x0001  /* ADC_OSR128 */
+#define WM8903_ADC_OSR128_SHIFT                      0  /* ADC_OSR128 */
+#define WM8903_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
+
+/*
+ * R12 (0x0C) - Power Management 0
+ */
+#define WM8903_INL_ENA                          0x0002  /* INL_ENA */
+#define WM8903_INL_ENA_MASK                     0x0002  /* INL_ENA */
+#define WM8903_INL_ENA_SHIFT                         1  /* INL_ENA */
+#define WM8903_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8903_INR_ENA                          0x0001  /* INR_ENA */
+#define WM8903_INR_ENA_MASK                     0x0001  /* INR_ENA */
+#define WM8903_INR_ENA_SHIFT                         0  /* INR_ENA */
+#define WM8903_INR_ENA_WIDTH                         1  /* INR_ENA */
+
+/*
+ * R13 (0x0D) - Power Management 1
+ */
+#define WM8903_MIXOUTL_ENA                      0x0002  /* MIXOUTL_ENA */
+#define WM8903_MIXOUTL_ENA_MASK                 0x0002  /* MIXOUTL_ENA */
+#define WM8903_MIXOUTL_ENA_SHIFT                     1  /* MIXOUTL_ENA */
+#define WM8903_MIXOUTL_ENA_WIDTH                     1  /* MIXOUTL_ENA */
+#define WM8903_MIXOUTR_ENA                      0x0001  /* MIXOUTR_ENA */
+#define WM8903_MIXOUTR_ENA_MASK                 0x0001  /* MIXOUTR_ENA */
+#define WM8903_MIXOUTR_ENA_SHIFT                     0  /* MIXOUTR_ENA */
+#define WM8903_MIXOUTR_ENA_WIDTH                     1  /* MIXOUTR_ENA */
+
+/*
+ * R14 (0x0E) - Power Management 2
+ */
+#define WM8903_HPL_PGA_ENA                      0x0002  /* HPL_PGA_ENA */
+#define WM8903_HPL_PGA_ENA_MASK                 0x0002  /* HPL_PGA_ENA */
+#define WM8903_HPL_PGA_ENA_SHIFT                     1  /* HPL_PGA_ENA */
+#define WM8903_HPL_PGA_ENA_WIDTH                     1  /* HPL_PGA_ENA */
+#define WM8903_HPR_PGA_ENA                      0x0001  /* HPR_PGA_ENA */
+#define WM8903_HPR_PGA_ENA_MASK                 0x0001  /* HPR_PGA_ENA */
+#define WM8903_HPR_PGA_ENA_SHIFT                     0  /* HPR_PGA_ENA */
+#define WM8903_HPR_PGA_ENA_WIDTH                     1  /* HPR_PGA_ENA */
+
+/*
+ * R15 (0x0F) - Power Management 3
+ */
+#define WM8903_LINEOUTL_PGA_ENA                 0x0002  /* LINEOUTL_PGA_ENA */
+#define WM8903_LINEOUTL_PGA_ENA_MASK            0x0002  /* LINEOUTL_PGA_ENA */
+#define WM8903_LINEOUTL_PGA_ENA_SHIFT                1  /* LINEOUTL_PGA_ENA */
+#define WM8903_LINEOUTL_PGA_ENA_WIDTH                1  /* LINEOUTL_PGA_ENA */
+#define WM8903_LINEOUTR_PGA_ENA                 0x0001  /* LINEOUTR_PGA_ENA */
+#define WM8903_LINEOUTR_PGA_ENA_MASK            0x0001  /* LINEOUTR_PGA_ENA */
+#define WM8903_LINEOUTR_PGA_ENA_SHIFT                0  /* LINEOUTR_PGA_ENA */
+#define WM8903_LINEOUTR_PGA_ENA_WIDTH                1  /* LINEOUTR_PGA_ENA */
+
+/*
+ * R16 (0x10) - Power Management 4
+ */
+#define WM8903_MIXSPKL_ENA                      0x0002  /* MIXSPKL_ENA */
+#define WM8903_MIXSPKL_ENA_MASK                 0x0002  /* MIXSPKL_ENA */
+#define WM8903_MIXSPKL_ENA_SHIFT                     1  /* MIXSPKL_ENA */
+#define WM8903_MIXSPKL_ENA_WIDTH                     1  /* MIXSPKL_ENA */
+#define WM8903_MIXSPKR_ENA                      0x0001  /* MIXSPKR_ENA */
+#define WM8903_MIXSPKR_ENA_MASK                 0x0001  /* MIXSPKR_ENA */
+#define WM8903_MIXSPKR_ENA_SHIFT                     0  /* MIXSPKR_ENA */
+#define WM8903_MIXSPKR_ENA_WIDTH                     1  /* MIXSPKR_ENA */
+
+/*
+ * R17 (0x11) - Power Management 5
+ */
+#define WM8903_SPKL_ENA                         0x0002  /* SPKL_ENA */
+#define WM8903_SPKL_ENA_MASK                    0x0002  /* SPKL_ENA */
+#define WM8903_SPKL_ENA_SHIFT                        1  /* SPKL_ENA */
+#define WM8903_SPKL_ENA_WIDTH                        1  /* SPKL_ENA */
+#define WM8903_SPKR_ENA                         0x0001  /* SPKR_ENA */
+#define WM8903_SPKR_ENA_MASK                    0x0001  /* SPKR_ENA */
+#define WM8903_SPKR_ENA_SHIFT                        0  /* SPKR_ENA */
+#define WM8903_SPKR_ENA_WIDTH                        1  /* SPKR_ENA */
+
+/*
+ * R18 (0x12) - Power Management 6
+ */
+#define WM8903_DACL_ENA                         0x0008  /* DACL_ENA */
+#define WM8903_DACL_ENA_MASK                    0x0008  /* DACL_ENA */
+#define WM8903_DACL_ENA_SHIFT                        3  /* DACL_ENA */
+#define WM8903_DACL_ENA_WIDTH                        1  /* DACL_ENA */
+#define WM8903_DACR_ENA                         0x0004  /* DACR_ENA */
+#define WM8903_DACR_ENA_MASK                    0x0004  /* DACR_ENA */
+#define WM8903_DACR_ENA_SHIFT                        2  /* DACR_ENA */
+#define WM8903_DACR_ENA_WIDTH                        1  /* DACR_ENA */
+#define WM8903_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8903_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8903_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8903_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8903_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8903_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8903_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8903_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R20 (0x14) - Clock Rates 0
+ */
+#define WM8903_MCLKDIV2                         0x0001  /* MCLKDIV2 */
+#define WM8903_MCLKDIV2_MASK                    0x0001  /* MCLKDIV2 */
+#define WM8903_MCLKDIV2_SHIFT                        0  /* MCLKDIV2 */
+#define WM8903_MCLKDIV2_WIDTH                        1  /* MCLKDIV2 */
+
+/*
+ * R21 (0x15) - Clock Rates 1
+ */
+#define WM8903_CLK_SYS_RATE_MASK                0x3C00  /* CLK_SYS_RATE - [13:10] */
+#define WM8903_CLK_SYS_RATE_SHIFT                   10  /* CLK_SYS_RATE - [13:10] */
+#define WM8903_CLK_SYS_RATE_WIDTH                    4  /* CLK_SYS_RATE - [13:10] */
+#define WM8903_CLK_SYS_MODE_MASK                0x0300  /* CLK_SYS_MODE - [9:8] */
+#define WM8903_CLK_SYS_MODE_SHIFT                    8  /* CLK_SYS_MODE - [9:8] */
+#define WM8903_CLK_SYS_MODE_WIDTH                    2  /* CLK_SYS_MODE - [9:8] */
+#define WM8903_SAMPLE_RATE_MASK                 0x000F  /* SAMPLE_RATE - [3:0] */
+#define WM8903_SAMPLE_RATE_SHIFT                     0  /* SAMPLE_RATE - [3:0] */
+#define WM8903_SAMPLE_RATE_WIDTH                     4  /* SAMPLE_RATE - [3:0] */
+
+/*
+ * R22 (0x16) - Clock Rates 2
+ */
+#define WM8903_CLK_SYS_ENA                      0x0004  /* CLK_SYS_ENA */
+#define WM8903_CLK_SYS_ENA_MASK                 0x0004  /* CLK_SYS_ENA */
+#define WM8903_CLK_SYS_ENA_SHIFT                     2  /* CLK_SYS_ENA */
+#define WM8903_CLK_SYS_ENA_WIDTH                     1  /* CLK_SYS_ENA */
+#define WM8903_CLK_DSP_ENA                      0x0002  /* CLK_DSP_ENA */
+#define WM8903_CLK_DSP_ENA_MASK                 0x0002  /* CLK_DSP_ENA */
+#define WM8903_CLK_DSP_ENA_SHIFT                     1  /* CLK_DSP_ENA */
+#define WM8903_CLK_DSP_ENA_WIDTH                     1  /* CLK_DSP_ENA */
+#define WM8903_TO_ENA                           0x0001  /* TO_ENA */
+#define WM8903_TO_ENA_MASK                      0x0001  /* TO_ENA */
+#define WM8903_TO_ENA_SHIFT                          0  /* TO_ENA */
+#define WM8903_TO_ENA_WIDTH                          1  /* TO_ENA */
+
+/*
+ * R24 (0x18) - Audio Interface 0
+ */
+#define WM8903_DACL_DATINV                      0x1000  /* DACL_DATINV */
+#define WM8903_DACL_DATINV_MASK                 0x1000  /* DACL_DATINV */
+#define WM8903_DACL_DATINV_SHIFT                    12  /* DACL_DATINV */
+#define WM8903_DACL_DATINV_WIDTH                     1  /* DACL_DATINV */
+#define WM8903_DACR_DATINV                      0x0800  /* DACR_DATINV */
+#define WM8903_DACR_DATINV_MASK                 0x0800  /* DACR_DATINV */
+#define WM8903_DACR_DATINV_SHIFT                    11  /* DACR_DATINV */
+#define WM8903_DACR_DATINV_WIDTH                     1  /* DACR_DATINV */
+#define WM8903_DAC_BOOST_MASK                   0x0600  /* DAC_BOOST - [10:9] */
+#define WM8903_DAC_BOOST_SHIFT                       9  /* DAC_BOOST - [10:9] */
+#define WM8903_DAC_BOOST_WIDTH                       2  /* DAC_BOOST - [10:9] */
+#define WM8903_LOOPBACK                         0x0100  /* LOOPBACK */
+#define WM8903_LOOPBACK_MASK                    0x0100  /* LOOPBACK */
+#define WM8903_LOOPBACK_SHIFT                        8  /* LOOPBACK */
+#define WM8903_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+#define WM8903_AIFADCL_SRC                      0x0080  /* AIFADCL_SRC */
+#define WM8903_AIFADCL_SRC_MASK                 0x0080  /* AIFADCL_SRC */
+#define WM8903_AIFADCL_SRC_SHIFT                     7  /* AIFADCL_SRC */
+#define WM8903_AIFADCL_SRC_WIDTH                     1  /* AIFADCL_SRC */
+#define WM8903_AIFADCR_SRC                      0x0040  /* AIFADCR_SRC */
+#define WM8903_AIFADCR_SRC_MASK                 0x0040  /* AIFADCR_SRC */
+#define WM8903_AIFADCR_SRC_SHIFT                     6  /* AIFADCR_SRC */
+#define WM8903_AIFADCR_SRC_WIDTH                     1  /* AIFADCR_SRC */
+#define WM8903_AIFDACL_SRC                      0x0020  /* AIFDACL_SRC */
+#define WM8903_AIFDACL_SRC_MASK                 0x0020  /* AIFDACL_SRC */
+#define WM8903_AIFDACL_SRC_SHIFT                     5  /* AIFDACL_SRC */
+#define WM8903_AIFDACL_SRC_WIDTH                     1  /* AIFDACL_SRC */
+#define WM8903_AIFDACR_SRC                      0x0010  /* AIFDACR_SRC */
+#define WM8903_AIFDACR_SRC_MASK                 0x0010  /* AIFDACR_SRC */
+#define WM8903_AIFDACR_SRC_SHIFT                     4  /* AIFDACR_SRC */
+#define WM8903_AIFDACR_SRC_WIDTH                     1  /* AIFDACR_SRC */
+#define WM8903_ADC_COMP                         0x0008  /* ADC_COMP */
+#define WM8903_ADC_COMP_MASK                    0x0008  /* ADC_COMP */
+#define WM8903_ADC_COMP_SHIFT                        3  /* ADC_COMP */
+#define WM8903_ADC_COMP_WIDTH                        1  /* ADC_COMP */
+#define WM8903_ADC_COMPMODE                     0x0004  /* ADC_COMPMODE */
+#define WM8903_ADC_COMPMODE_MASK                0x0004  /* ADC_COMPMODE */
+#define WM8903_ADC_COMPMODE_SHIFT                    2  /* ADC_COMPMODE */
+#define WM8903_ADC_COMPMODE_WIDTH                    1  /* ADC_COMPMODE */
+#define WM8903_DAC_COMP                         0x0002  /* DAC_COMP */
+#define WM8903_DAC_COMP_MASK                    0x0002  /* DAC_COMP */
+#define WM8903_DAC_COMP_SHIFT                        1  /* DAC_COMP */
+#define WM8903_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM8903_DAC_COMPMODE                     0x0001  /* DAC_COMPMODE */
+#define WM8903_DAC_COMPMODE_MASK                0x0001  /* DAC_COMPMODE */
+#define WM8903_DAC_COMPMODE_SHIFT                    0  /* DAC_COMPMODE */
+#define WM8903_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+
+/*
+ * R25 (0x19) - Audio Interface 1
+ */
+#define WM8903_AIFDAC_TDM                       0x2000  /* AIFDAC_TDM */
+#define WM8903_AIFDAC_TDM_MASK                  0x2000  /* AIFDAC_TDM */
+#define WM8903_AIFDAC_TDM_SHIFT                     13  /* AIFDAC_TDM */
+#define WM8903_AIFDAC_TDM_WIDTH                      1  /* AIFDAC_TDM */
+#define WM8903_AIFDAC_TDM_CHAN                  0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8903_AIFDAC_TDM_CHAN_MASK             0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8903_AIFDAC_TDM_CHAN_SHIFT                12  /* AIFDAC_TDM_CHAN */
+#define WM8903_AIFDAC_TDM_CHAN_WIDTH                 1  /* AIFDAC_TDM_CHAN */
+#define WM8903_AIFADC_TDM                       0x0800  /* AIFADC_TDM */
+#define WM8903_AIFADC_TDM_MASK                  0x0800  /* AIFADC_TDM */
+#define WM8903_AIFADC_TDM_SHIFT                     11  /* AIFADC_TDM */
+#define WM8903_AIFADC_TDM_WIDTH                      1  /* AIFADC_TDM */
+#define WM8903_AIFADC_TDM_CHAN                  0x0400  /* AIFADC_TDM_CHAN */
+#define WM8903_AIFADC_TDM_CHAN_MASK             0x0400  /* AIFADC_TDM_CHAN */
+#define WM8903_AIFADC_TDM_CHAN_SHIFT                10  /* AIFADC_TDM_CHAN */
+#define WM8903_AIFADC_TDM_CHAN_WIDTH                 1  /* AIFADC_TDM_CHAN */
+#define WM8903_LRCLK_DIR                        0x0200  /* LRCLK_DIR */
+#define WM8903_LRCLK_DIR_MASK                   0x0200  /* LRCLK_DIR */
+#define WM8903_LRCLK_DIR_SHIFT                       9  /* LRCLK_DIR */
+#define WM8903_LRCLK_DIR_WIDTH                       1  /* LRCLK_DIR */
+#define WM8903_AIF_BCLK_INV                     0x0080  /* AIF_BCLK_INV */
+#define WM8903_AIF_BCLK_INV_MASK                0x0080  /* AIF_BCLK_INV */
+#define WM8903_AIF_BCLK_INV_SHIFT                    7  /* AIF_BCLK_INV */
+#define WM8903_AIF_BCLK_INV_WIDTH                    1  /* AIF_BCLK_INV */
+#define WM8903_BCLK_DIR                         0x0040  /* BCLK_DIR */
+#define WM8903_BCLK_DIR_MASK                    0x0040  /* BCLK_DIR */
+#define WM8903_BCLK_DIR_SHIFT                        6  /* BCLK_DIR */
+#define WM8903_BCLK_DIR_WIDTH                        1  /* BCLK_DIR */
+#define WM8903_AIF_LRCLK_INV                    0x0010  /* AIF_LRCLK_INV */
+#define WM8903_AIF_LRCLK_INV_MASK               0x0010  /* AIF_LRCLK_INV */
+#define WM8903_AIF_LRCLK_INV_SHIFT                   4  /* AIF_LRCLK_INV */
+#define WM8903_AIF_LRCLK_INV_WIDTH                   1  /* AIF_LRCLK_INV */
+#define WM8903_AIF_WL_MASK                      0x000C  /* AIF_WL - [3:2] */
+#define WM8903_AIF_WL_SHIFT                          2  /* AIF_WL - [3:2] */
+#define WM8903_AIF_WL_WIDTH                          2  /* AIF_WL - [3:2] */
+#define WM8903_AIF_FMT_MASK                     0x0003  /* AIF_FMT - [1:0] */
+#define WM8903_AIF_FMT_SHIFT                         0  /* AIF_FMT - [1:0] */
+#define WM8903_AIF_FMT_WIDTH                         2  /* AIF_FMT - [1:0] */
+
+/*
+ * R26 (0x1A) - Audio Interface 2
+ */
+#define WM8903_BCLK_DIV_MASK                    0x001F  /* BCLK_DIV - [4:0] */
+#define WM8903_BCLK_DIV_SHIFT                        0  /* BCLK_DIV - [4:0] */
+#define WM8903_BCLK_DIV_WIDTH                        5  /* BCLK_DIV - [4:0] */
+
+/*
+ * R27 (0x1B) - Audio Interface 3
+ */
+#define WM8903_LRCLK_RATE_MASK                  0x07FF  /* LRCLK_RATE - [10:0] */
+#define WM8903_LRCLK_RATE_SHIFT                      0  /* LRCLK_RATE - [10:0] */
+#define WM8903_LRCLK_RATE_WIDTH                     11  /* LRCLK_RATE - [10:0] */
+
+/*
+ * R30 (0x1E) - DAC Digital Volume Left
+ */
+#define WM8903_DACVU                            0x0100  /* DACVU */
+#define WM8903_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8903_DACVU_SHIFT                           8  /* DACVU */
+#define WM8903_DACVU_WIDTH                           1  /* DACVU */
+#define WM8903_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8903_DACL_VOL_SHIFT                        0  /* DACL_VOL - [7:0] */
+#define WM8903_DACL_VOL_WIDTH                        8  /* DACL_VOL - [7:0] */
+
+/*
+ * R31 (0x1F) - DAC Digital Volume Right
+ */
+#define WM8903_DACVU                            0x0100  /* DACVU */
+#define WM8903_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8903_DACVU_SHIFT                           8  /* DACVU */
+#define WM8903_DACVU_WIDTH                           1  /* DACVU */
+#define WM8903_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8903_DACR_VOL_SHIFT                        0  /* DACR_VOL - [7:0] */
+#define WM8903_DACR_VOL_WIDTH                        8  /* DACR_VOL - [7:0] */
+
+/*
+ * R32 (0x20) - DAC Digital 0
+ */
+#define WM8903_ADCL_DAC_SVOL_MASK               0x0F00  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8903_ADCL_DAC_SVOL_SHIFT                   8  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8903_ADCL_DAC_SVOL_WIDTH                   4  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8903_ADCR_DAC_SVOL_MASK               0x00F0  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8903_ADCR_DAC_SVOL_SHIFT                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8903_ADCR_DAC_SVOL_WIDTH                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8903_ADC_TO_DACL_MASK                 0x000C  /* ADC_TO_DACL - [3:2] */
+#define WM8903_ADC_TO_DACL_SHIFT                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8903_ADC_TO_DACL_WIDTH                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8903_ADC_TO_DACR_MASK                 0x0003  /* ADC_TO_DACR - [1:0] */
+#define WM8903_ADC_TO_DACR_SHIFT                     0  /* ADC_TO_DACR - [1:0] */
+#define WM8903_ADC_TO_DACR_WIDTH                     2  /* ADC_TO_DACR - [1:0] */
+
+/*
+ * R33 (0x21) - DAC Digital 1
+ */
+#define WM8903_DAC_MONO                         0x1000  /* DAC_MONO */
+#define WM8903_DAC_MONO_MASK                    0x1000  /* DAC_MONO */
+#define WM8903_DAC_MONO_SHIFT                       12  /* DAC_MONO */
+#define WM8903_DAC_MONO_WIDTH                        1  /* DAC_MONO */
+#define WM8903_DAC_SB_FILT                      0x0800  /* DAC_SB_FILT */
+#define WM8903_DAC_SB_FILT_MASK                 0x0800  /* DAC_SB_FILT */
+#define WM8903_DAC_SB_FILT_SHIFT                    11  /* DAC_SB_FILT */
+#define WM8903_DAC_SB_FILT_WIDTH                     1  /* DAC_SB_FILT */
+#define WM8903_DAC_MUTERATE                     0x0400  /* DAC_MUTERATE */
+#define WM8903_DAC_MUTERATE_MASK                0x0400  /* DAC_MUTERATE */
+#define WM8903_DAC_MUTERATE_SHIFT                   10  /* DAC_MUTERATE */
+#define WM8903_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM8903_DAC_MUTEMODE                     0x0200  /* DAC_MUTEMODE */
+#define WM8903_DAC_MUTEMODE_MASK                0x0200  /* DAC_MUTEMODE */
+#define WM8903_DAC_MUTEMODE_SHIFT                    9  /* DAC_MUTEMODE */
+#define WM8903_DAC_MUTEMODE_WIDTH                    1  /* DAC_MUTEMODE */
+#define WM8903_DAC_MUTE                         0x0008  /* DAC_MUTE */
+#define WM8903_DAC_MUTE_MASK                    0x0008  /* DAC_MUTE */
+#define WM8903_DAC_MUTE_SHIFT                        3  /* DAC_MUTE */
+#define WM8903_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM8903_DEEMPH_MASK                      0x0006  /* DEEMPH - [2:1] */
+#define WM8903_DEEMPH_SHIFT                          1  /* DEEMPH - [2:1] */
+#define WM8903_DEEMPH_WIDTH                          2  /* DEEMPH - [2:1] */
+
+/*
+ * R36 (0x24) - ADC Digital Volume Left
+ */
+#define WM8903_ADCVU                            0x0100  /* ADCVU */
+#define WM8903_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8903_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8903_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8903_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8903_ADCL_VOL_SHIFT                        0  /* ADCL_VOL - [7:0] */
+#define WM8903_ADCL_VOL_WIDTH                        8  /* ADCL_VOL - [7:0] */
+
+/*
+ * R37 (0x25) - ADC Digital Volume Right
+ */
+#define WM8903_ADCVU                            0x0100  /* ADCVU */
+#define WM8903_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8903_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8903_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8903_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8903_ADCR_VOL_SHIFT                        0  /* ADCR_VOL - [7:0] */
+#define WM8903_ADCR_VOL_WIDTH                        8  /* ADCR_VOL - [7:0] */
+
+/*
+ * R38 (0x26) - ADC Digital 0
+ */
+#define WM8903_ADC_HPF_CUT_MASK                 0x0060  /* ADC_HPF_CUT - [6:5] */
+#define WM8903_ADC_HPF_CUT_SHIFT                     5  /* ADC_HPF_CUT - [6:5] */
+#define WM8903_ADC_HPF_CUT_WIDTH                     2  /* ADC_HPF_CUT - [6:5] */
+#define WM8903_ADC_HPF_ENA                      0x0010  /* ADC_HPF_ENA */
+#define WM8903_ADC_HPF_ENA_MASK                 0x0010  /* ADC_HPF_ENA */
+#define WM8903_ADC_HPF_ENA_SHIFT                     4  /* ADC_HPF_ENA */
+#define WM8903_ADC_HPF_ENA_WIDTH                     1  /* ADC_HPF_ENA */
+#define WM8903_ADCL_DATINV                      0x0002  /* ADCL_DATINV */
+#define WM8903_ADCL_DATINV_MASK                 0x0002  /* ADCL_DATINV */
+#define WM8903_ADCL_DATINV_SHIFT                     1  /* ADCL_DATINV */
+#define WM8903_ADCL_DATINV_WIDTH                     1  /* ADCL_DATINV */
+#define WM8903_ADCR_DATINV                      0x0001  /* ADCR_DATINV */
+#define WM8903_ADCR_DATINV_MASK                 0x0001  /* ADCR_DATINV */
+#define WM8903_ADCR_DATINV_SHIFT                     0  /* ADCR_DATINV */
+#define WM8903_ADCR_DATINV_WIDTH                     1  /* ADCR_DATINV */
+
+/*
+ * R39 (0x27) - Digital Microphone 0
+ */
+#define WM8903_DIGMIC_MODE_SEL                  0x0100  /* DIGMIC_MODE_SEL */
+#define WM8903_DIGMIC_MODE_SEL_MASK             0x0100  /* DIGMIC_MODE_SEL */
+#define WM8903_DIGMIC_MODE_SEL_SHIFT                 8  /* DIGMIC_MODE_SEL */
+#define WM8903_DIGMIC_MODE_SEL_WIDTH                 1  /* DIGMIC_MODE_SEL */
+#define WM8903_DIGMIC_CLK_SEL_L_MASK            0x00C0  /* DIGMIC_CLK_SEL_L - [7:6] */
+#define WM8903_DIGMIC_CLK_SEL_L_SHIFT                6  /* DIGMIC_CLK_SEL_L - [7:6] */
+#define WM8903_DIGMIC_CLK_SEL_L_WIDTH                2  /* DIGMIC_CLK_SEL_L - [7:6] */
+#define WM8903_DIGMIC_CLK_SEL_R_MASK            0x0030  /* DIGMIC_CLK_SEL_R - [5:4] */
+#define WM8903_DIGMIC_CLK_SEL_R_SHIFT                4  /* DIGMIC_CLK_SEL_R - [5:4] */
+#define WM8903_DIGMIC_CLK_SEL_R_WIDTH                2  /* DIGMIC_CLK_SEL_R - [5:4] */
+#define WM8903_DIGMIC_CLK_SEL_RT_MASK           0x000C  /* DIGMIC_CLK_SEL_RT - [3:2] */
+#define WM8903_DIGMIC_CLK_SEL_RT_SHIFT               2  /* DIGMIC_CLK_SEL_RT - [3:2] */
+#define WM8903_DIGMIC_CLK_SEL_RT_WIDTH               2  /* DIGMIC_CLK_SEL_RT - [3:2] */
+#define WM8903_DIGMIC_CLK_SEL_MASK              0x0003  /* DIGMIC_CLK_SEL - [1:0] */
+#define WM8903_DIGMIC_CLK_SEL_SHIFT                  0  /* DIGMIC_CLK_SEL - [1:0] */
+#define WM8903_DIGMIC_CLK_SEL_WIDTH                  2  /* DIGMIC_CLK_SEL - [1:0] */
+
+/*
+ * R40 (0x28) - DRC 0
+ */
+#define WM8903_DRC_ENA                          0x8000  /* DRC_ENA */
+#define WM8903_DRC_ENA_MASK                     0x8000  /* DRC_ENA */
+#define WM8903_DRC_ENA_SHIFT                        15  /* DRC_ENA */
+#define WM8903_DRC_ENA_WIDTH                         1  /* DRC_ENA */
+#define WM8903_DRC_THRESH_HYST_MASK             0x1800  /* DRC_THRESH_HYST - [12:11] */
+#define WM8903_DRC_THRESH_HYST_SHIFT                11  /* DRC_THRESH_HYST - [12:11] */
+#define WM8903_DRC_THRESH_HYST_WIDTH                 2  /* DRC_THRESH_HYST - [12:11] */
+#define WM8903_DRC_STARTUP_GAIN_MASK            0x07C0  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8903_DRC_STARTUP_GAIN_SHIFT                6  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8903_DRC_STARTUP_GAIN_WIDTH                5  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8903_DRC_FF_DELAY                     0x0020  /* DRC_FF_DELAY */
+#define WM8903_DRC_FF_DELAY_MASK                0x0020  /* DRC_FF_DELAY */
+#define WM8903_DRC_FF_DELAY_SHIFT                    5  /* DRC_FF_DELAY */
+#define WM8903_DRC_FF_DELAY_WIDTH                    1  /* DRC_FF_DELAY */
+#define WM8903_DRC_SMOOTH_ENA                   0x0008  /* DRC_SMOOTH_ENA */
+#define WM8903_DRC_SMOOTH_ENA_MASK              0x0008  /* DRC_SMOOTH_ENA */
+#define WM8903_DRC_SMOOTH_ENA_SHIFT                  3  /* DRC_SMOOTH_ENA */
+#define WM8903_DRC_SMOOTH_ENA_WIDTH                  1  /* DRC_SMOOTH_ENA */
+#define WM8903_DRC_QR_ENA                       0x0004  /* DRC_QR_ENA */
+#define WM8903_DRC_QR_ENA_MASK                  0x0004  /* DRC_QR_ENA */
+#define WM8903_DRC_QR_ENA_SHIFT                      2  /* DRC_QR_ENA */
+#define WM8903_DRC_QR_ENA_WIDTH                      1  /* DRC_QR_ENA */
+#define WM8903_DRC_ANTICLIP_ENA                 0x0002  /* DRC_ANTICLIP_ENA */
+#define WM8903_DRC_ANTICLIP_ENA_MASK            0x0002  /* DRC_ANTICLIP_ENA */
+#define WM8903_DRC_ANTICLIP_ENA_SHIFT                1  /* DRC_ANTICLIP_ENA */
+#define WM8903_DRC_ANTICLIP_ENA_WIDTH                1  /* DRC_ANTICLIP_ENA */
+#define WM8903_DRC_HYST_ENA                     0x0001  /* DRC_HYST_ENA */
+#define WM8903_DRC_HYST_ENA_MASK                0x0001  /* DRC_HYST_ENA */
+#define WM8903_DRC_HYST_ENA_SHIFT                    0  /* DRC_HYST_ENA */
+#define WM8903_DRC_HYST_ENA_WIDTH                    1  /* DRC_HYST_ENA */
+
+/*
+ * R41 (0x29) - DRC 1
+ */
+#define WM8903_DRC_ATTACK_RATE_MASK             0xF000  /* DRC_ATTACK_RATE - [15:12] */
+#define WM8903_DRC_ATTACK_RATE_SHIFT                12  /* DRC_ATTACK_RATE - [15:12] */
+#define WM8903_DRC_ATTACK_RATE_WIDTH                 4  /* DRC_ATTACK_RATE - [15:12] */
+#define WM8903_DRC_DECAY_RATE_MASK              0x0F00  /* DRC_DECAY_RATE - [11:8] */
+#define WM8903_DRC_DECAY_RATE_SHIFT                  8  /* DRC_DECAY_RATE - [11:8] */
+#define WM8903_DRC_DECAY_RATE_WIDTH                  4  /* DRC_DECAY_RATE - [11:8] */
+#define WM8903_DRC_THRESH_QR_MASK               0x00C0  /* DRC_THRESH_QR - [7:6] */
+#define WM8903_DRC_THRESH_QR_SHIFT                   6  /* DRC_THRESH_QR - [7:6] */
+#define WM8903_DRC_THRESH_QR_WIDTH                   2  /* DRC_THRESH_QR - [7:6] */
+#define WM8903_DRC_RATE_QR_MASK                 0x0030  /* DRC_RATE_QR - [5:4] */
+#define WM8903_DRC_RATE_QR_SHIFT                     4  /* DRC_RATE_QR - [5:4] */
+#define WM8903_DRC_RATE_QR_WIDTH                     2  /* DRC_RATE_QR - [5:4] */
+#define WM8903_DRC_MINGAIN_MASK                 0x000C  /* DRC_MINGAIN - [3:2] */
+#define WM8903_DRC_MINGAIN_SHIFT                     2  /* DRC_MINGAIN - [3:2] */
+#define WM8903_DRC_MINGAIN_WIDTH                     2  /* DRC_MINGAIN - [3:2] */
+#define WM8903_DRC_MAXGAIN_MASK                 0x0003  /* DRC_MAXGAIN - [1:0] */
+#define WM8903_DRC_MAXGAIN_SHIFT                     0  /* DRC_MAXGAIN - [1:0] */
+#define WM8903_DRC_MAXGAIN_WIDTH                     2  /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R42 (0x2A) - DRC 2
+ */
+#define WM8903_DRC_R0_SLOPE_COMP_MASK           0x0038  /* DRC_R0_SLOPE_COMP - [5:3] */
+#define WM8903_DRC_R0_SLOPE_COMP_SHIFT               3  /* DRC_R0_SLOPE_COMP - [5:3] */
+#define WM8903_DRC_R0_SLOPE_COMP_WIDTH               3  /* DRC_R0_SLOPE_COMP - [5:3] */
+#define WM8903_DRC_R1_SLOPE_COMP_MASK           0x0007  /* DRC_R1_SLOPE_COMP - [2:0] */
+#define WM8903_DRC_R1_SLOPE_COMP_SHIFT               0  /* DRC_R1_SLOPE_COMP - [2:0] */
+#define WM8903_DRC_R1_SLOPE_COMP_WIDTH               3  /* DRC_R1_SLOPE_COMP - [2:0] */
+
+/*
+ * R43 (0x2B) - DRC 3
+ */
+#define WM8903_DRC_THRESH_COMP_MASK             0x07E0  /* DRC_THRESH_COMP - [10:5] */
+#define WM8903_DRC_THRESH_COMP_SHIFT                 5  /* DRC_THRESH_COMP - [10:5] */
+#define WM8903_DRC_THRESH_COMP_WIDTH                 6  /* DRC_THRESH_COMP - [10:5] */
+#define WM8903_DRC_AMP_COMP_MASK                0x001F  /* DRC_AMP_COMP - [4:0] */
+#define WM8903_DRC_AMP_COMP_SHIFT                    0  /* DRC_AMP_COMP - [4:0] */
+#define WM8903_DRC_AMP_COMP_WIDTH                    5  /* DRC_AMP_COMP - [4:0] */
+
+/*
+ * R44 (0x2C) - Analogue Left Input 0
+ */
+#define WM8903_LINMUTE                          0x0080  /* LINMUTE */
+#define WM8903_LINMUTE_MASK                     0x0080  /* LINMUTE */
+#define WM8903_LINMUTE_SHIFT                         7  /* LINMUTE */
+#define WM8903_LINMUTE_WIDTH                         1  /* LINMUTE */
+#define WM8903_LIN_VOL_MASK                     0x001F  /* LIN_VOL - [4:0] */
+#define WM8903_LIN_VOL_SHIFT                         0  /* LIN_VOL - [4:0] */
+#define WM8903_LIN_VOL_WIDTH                         5  /* LIN_VOL - [4:0] */
+
+/*
+ * R45 (0x2D) - Analogue Right Input 0
+ */
+#define WM8903_RINMUTE                          0x0080  /* RINMUTE */
+#define WM8903_RINMUTE_MASK                     0x0080  /* RINMUTE */
+#define WM8903_RINMUTE_SHIFT                         7  /* RINMUTE */
+#define WM8903_RINMUTE_WIDTH                         1  /* RINMUTE */
+#define WM8903_RIN_VOL_MASK                     0x001F  /* RIN_VOL - [4:0] */
+#define WM8903_RIN_VOL_SHIFT                         0  /* RIN_VOL - [4:0] */
+#define WM8903_RIN_VOL_WIDTH                         5  /* RIN_VOL - [4:0] */
+
+/*
+ * R46 (0x2E) - Analogue Left Input 1
+ */
+#define WM8903_INL_CM_ENA                       0x0040  /* INL_CM_ENA */
+#define WM8903_INL_CM_ENA_MASK                  0x0040  /* INL_CM_ENA */
+#define WM8903_INL_CM_ENA_SHIFT                      6  /* INL_CM_ENA */
+#define WM8903_INL_CM_ENA_WIDTH                      1  /* INL_CM_ENA */
+#define WM8903_L_IP_SEL_N_MASK                  0x0030  /* L_IP_SEL_N - [5:4] */
+#define WM8903_L_IP_SEL_N_SHIFT                      4  /* L_IP_SEL_N - [5:4] */
+#define WM8903_L_IP_SEL_N_WIDTH                      2  /* L_IP_SEL_N - [5:4] */
+#define WM8903_L_IP_SEL_P_MASK                  0x000C  /* L_IP_SEL_P - [3:2] */
+#define WM8903_L_IP_SEL_P_SHIFT                      2  /* L_IP_SEL_P - [3:2] */
+#define WM8903_L_IP_SEL_P_WIDTH                      2  /* L_IP_SEL_P - [3:2] */
+#define WM8903_L_MODE_MASK                      0x0003  /* L_MODE - [1:0] */
+#define WM8903_L_MODE_SHIFT                          0  /* L_MODE - [1:0] */
+#define WM8903_L_MODE_WIDTH                          2  /* L_MODE - [1:0] */
+
+/*
+ * R47 (0x2F) - Analogue Right Input 1
+ */
+#define WM8903_INR_CM_ENA                       0x0040  /* INR_CM_ENA */
+#define WM8903_INR_CM_ENA_MASK                  0x0040  /* INR_CM_ENA */
+#define WM8903_INR_CM_ENA_SHIFT                      6  /* INR_CM_ENA */
+#define WM8903_INR_CM_ENA_WIDTH                      1  /* INR_CM_ENA */
+#define WM8903_R_IP_SEL_N_MASK                  0x0030  /* R_IP_SEL_N - [5:4] */
+#define WM8903_R_IP_SEL_N_SHIFT                      4  /* R_IP_SEL_N - [5:4] */
+#define WM8903_R_IP_SEL_N_WIDTH                      2  /* R_IP_SEL_N - [5:4] */
+#define WM8903_R_IP_SEL_P_MASK                  0x000C  /* R_IP_SEL_P - [3:2] */
+#define WM8903_R_IP_SEL_P_SHIFT                      2  /* R_IP_SEL_P - [3:2] */
+#define WM8903_R_IP_SEL_P_WIDTH                      2  /* R_IP_SEL_P - [3:2] */
+#define WM8903_R_MODE_MASK                      0x0003  /* R_MODE - [1:0] */
+#define WM8903_R_MODE_SHIFT                          0  /* R_MODE - [1:0] */
+#define WM8903_R_MODE_WIDTH                          2  /* R_MODE - [1:0] */
+
+/*
+ * R50 (0x32) - Analogue Left Mix 0
+ */
+#define WM8903_DACL_TO_MIXOUTL                  0x0008  /* DACL_TO_MIXOUTL */
+#define WM8903_DACL_TO_MIXOUTL_MASK             0x0008  /* DACL_TO_MIXOUTL */
+#define WM8903_DACL_TO_MIXOUTL_SHIFT                 3  /* DACL_TO_MIXOUTL */
+#define WM8903_DACL_TO_MIXOUTL_WIDTH                 1  /* DACL_TO_MIXOUTL */
+#define WM8903_DACR_TO_MIXOUTL                  0x0004  /* DACR_TO_MIXOUTL */
+#define WM8903_DACR_TO_MIXOUTL_MASK             0x0004  /* DACR_TO_MIXOUTL */
+#define WM8903_DACR_TO_MIXOUTL_SHIFT                 2  /* DACR_TO_MIXOUTL */
+#define WM8903_DACR_TO_MIXOUTL_WIDTH                 1  /* DACR_TO_MIXOUTL */
+#define WM8903_BYPASSL_TO_MIXOUTL               0x0002  /* BYPASSL_TO_MIXOUTL */
+#define WM8903_BYPASSL_TO_MIXOUTL_MASK          0x0002  /* BYPASSL_TO_MIXOUTL */
+#define WM8903_BYPASSL_TO_MIXOUTL_SHIFT              1  /* BYPASSL_TO_MIXOUTL */
+#define WM8903_BYPASSL_TO_MIXOUTL_WIDTH              1  /* BYPASSL_TO_MIXOUTL */
+#define WM8903_BYPASSR_TO_MIXOUTL               0x0001  /* BYPASSR_TO_MIXOUTL */
+#define WM8903_BYPASSR_TO_MIXOUTL_MASK          0x0001  /* BYPASSR_TO_MIXOUTL */
+#define WM8903_BYPASSR_TO_MIXOUTL_SHIFT              0  /* BYPASSR_TO_MIXOUTL */
+#define WM8903_BYPASSR_TO_MIXOUTL_WIDTH              1  /* BYPASSR_TO_MIXOUTL */
+
+/*
+ * R51 (0x33) - Analogue Right Mix 0
+ */
+#define WM8903_DACL_TO_MIXOUTR                  0x0008  /* DACL_TO_MIXOUTR */
+#define WM8903_DACL_TO_MIXOUTR_MASK             0x0008  /* DACL_TO_MIXOUTR */
+#define WM8903_DACL_TO_MIXOUTR_SHIFT                 3  /* DACL_TO_MIXOUTR */
+#define WM8903_DACL_TO_MIXOUTR_WIDTH                 1  /* DACL_TO_MIXOUTR */
+#define WM8903_DACR_TO_MIXOUTR                  0x0004  /* DACR_TO_MIXOUTR */
+#define WM8903_DACR_TO_MIXOUTR_MASK             0x0004  /* DACR_TO_MIXOUTR */
+#define WM8903_DACR_TO_MIXOUTR_SHIFT                 2  /* DACR_TO_MIXOUTR */
+#define WM8903_DACR_TO_MIXOUTR_WIDTH                 1  /* DACR_TO_MIXOUTR */
+#define WM8903_BYPASSL_TO_MIXOUTR               0x0002  /* BYPASSL_TO_MIXOUTR */
+#define WM8903_BYPASSL_TO_MIXOUTR_MASK          0x0002  /* BYPASSL_TO_MIXOUTR */
+#define WM8903_BYPASSL_TO_MIXOUTR_SHIFT              1  /* BYPASSL_TO_MIXOUTR */
+#define WM8903_BYPASSL_TO_MIXOUTR_WIDTH              1  /* BYPASSL_TO_MIXOUTR */
+#define WM8903_BYPASSR_TO_MIXOUTR               0x0001  /* BYPASSR_TO_MIXOUTR */
+#define WM8903_BYPASSR_TO_MIXOUTR_MASK          0x0001  /* BYPASSR_TO_MIXOUTR */
+#define WM8903_BYPASSR_TO_MIXOUTR_SHIFT              0  /* BYPASSR_TO_MIXOUTR */
+#define WM8903_BYPASSR_TO_MIXOUTR_WIDTH              1  /* BYPASSR_TO_MIXOUTR */
+
+/*
+ * R52 (0x34) - Analogue Spk Mix Left 0
+ */
+#define WM8903_DACL_TO_MIXSPKL                  0x0008  /* DACL_TO_MIXSPKL */
+#define WM8903_DACL_TO_MIXSPKL_MASK             0x0008  /* DACL_TO_MIXSPKL */
+#define WM8903_DACL_TO_MIXSPKL_SHIFT                 3  /* DACL_TO_MIXSPKL */
+#define WM8903_DACL_TO_MIXSPKL_WIDTH                 1  /* DACL_TO_MIXSPKL */
+#define WM8903_DACR_TO_MIXSPKL                  0x0004  /* DACR_TO_MIXSPKL */
+#define WM8903_DACR_TO_MIXSPKL_MASK             0x0004  /* DACR_TO_MIXSPKL */
+#define WM8903_DACR_TO_MIXSPKL_SHIFT                 2  /* DACR_TO_MIXSPKL */
+#define WM8903_DACR_TO_MIXSPKL_WIDTH                 1  /* DACR_TO_MIXSPKL */
+#define WM8903_BYPASSL_TO_MIXSPKL               0x0002  /* BYPASSL_TO_MIXSPKL */
+#define WM8903_BYPASSL_TO_MIXSPKL_MASK          0x0002  /* BYPASSL_TO_MIXSPKL */
+#define WM8903_BYPASSL_TO_MIXSPKL_SHIFT              1  /* BYPASSL_TO_MIXSPKL */
+#define WM8903_BYPASSL_TO_MIXSPKL_WIDTH              1  /* BYPASSL_TO_MIXSPKL */
+#define WM8903_BYPASSR_TO_MIXSPKL               0x0001  /* BYPASSR_TO_MIXSPKL */
+#define WM8903_BYPASSR_TO_MIXSPKL_MASK          0x0001  /* BYPASSR_TO_MIXSPKL */
+#define WM8903_BYPASSR_TO_MIXSPKL_SHIFT              0  /* BYPASSR_TO_MIXSPKL */
+#define WM8903_BYPASSR_TO_MIXSPKL_WIDTH              1  /* BYPASSR_TO_MIXSPKL */
+
+/*
+ * R53 (0x35) - Analogue Spk Mix Left 1
+ */
+#define WM8903_DACL_MIXSPKL_VOL                 0x0008  /* DACL_MIXSPKL_VOL */
+#define WM8903_DACL_MIXSPKL_VOL_MASK            0x0008  /* DACL_MIXSPKL_VOL */
+#define WM8903_DACL_MIXSPKL_VOL_SHIFT                3  /* DACL_MIXSPKL_VOL */
+#define WM8903_DACL_MIXSPKL_VOL_WIDTH                1  /* DACL_MIXSPKL_VOL */
+#define WM8903_DACR_MIXSPKL_VOL                 0x0004  /* DACR_MIXSPKL_VOL */
+#define WM8903_DACR_MIXSPKL_VOL_MASK            0x0004  /* DACR_MIXSPKL_VOL */
+#define WM8903_DACR_MIXSPKL_VOL_SHIFT                2  /* DACR_MIXSPKL_VOL */
+#define WM8903_DACR_MIXSPKL_VOL_WIDTH                1  /* DACR_MIXSPKL_VOL */
+#define WM8903_BYPASSL_MIXSPKL_VOL              0x0002  /* BYPASSL_MIXSPKL_VOL */
+#define WM8903_BYPASSL_MIXSPKL_VOL_MASK         0x0002  /* BYPASSL_MIXSPKL_VOL */
+#define WM8903_BYPASSL_MIXSPKL_VOL_SHIFT             1  /* BYPASSL_MIXSPKL_VOL */
+#define WM8903_BYPASSL_MIXSPKL_VOL_WIDTH             1  /* BYPASSL_MIXSPKL_VOL */
+#define WM8903_BYPASSR_MIXSPKL_VOL              0x0001  /* BYPASSR_MIXSPKL_VOL */
+#define WM8903_BYPASSR_MIXSPKL_VOL_MASK         0x0001  /* BYPASSR_MIXSPKL_VOL */
+#define WM8903_BYPASSR_MIXSPKL_VOL_SHIFT             0  /* BYPASSR_MIXSPKL_VOL */
+#define WM8903_BYPASSR_MIXSPKL_VOL_WIDTH             1  /* BYPASSR_MIXSPKL_VOL */
+
+/*
+ * R54 (0x36) - Analogue Spk Mix Right 0
+ */
+#define WM8903_DACL_TO_MIXSPKR                  0x0008  /* DACL_TO_MIXSPKR */
+#define WM8903_DACL_TO_MIXSPKR_MASK             0x0008  /* DACL_TO_MIXSPKR */
+#define WM8903_DACL_TO_MIXSPKR_SHIFT                 3  /* DACL_TO_MIXSPKR */
+#define WM8903_DACL_TO_MIXSPKR_WIDTH                 1  /* DACL_TO_MIXSPKR */
+#define WM8903_DACR_TO_MIXSPKR                  0x0004  /* DACR_TO_MIXSPKR */
+#define WM8903_DACR_TO_MIXSPKR_MASK             0x0004  /* DACR_TO_MIXSPKR */
+#define WM8903_DACR_TO_MIXSPKR_SHIFT                 2  /* DACR_TO_MIXSPKR */
+#define WM8903_DACR_TO_MIXSPKR_WIDTH                 1  /* DACR_TO_MIXSPKR */
+#define WM8903_BYPASSL_TO_MIXSPKR               0x0002  /* BYPASSL_TO_MIXSPKR */
+#define WM8903_BYPASSL_TO_MIXSPKR_MASK          0x0002  /* BYPASSL_TO_MIXSPKR */
+#define WM8903_BYPASSL_TO_MIXSPKR_SHIFT              1  /* BYPASSL_TO_MIXSPKR */
+#define WM8903_BYPASSL_TO_MIXSPKR_WIDTH              1  /* BYPASSL_TO_MIXSPKR */
+#define WM8903_BYPASSR_TO_MIXSPKR               0x0001  /* BYPASSR_TO_MIXSPKR */
+#define WM8903_BYPASSR_TO_MIXSPKR_MASK          0x0001  /* BYPASSR_TO_MIXSPKR */
+#define WM8903_BYPASSR_TO_MIXSPKR_SHIFT              0  /* BYPASSR_TO_MIXSPKR */
+#define WM8903_BYPASSR_TO_MIXSPKR_WIDTH              1  /* BYPASSR_TO_MIXSPKR */
+
+/*
+ * R55 (0x37) - Analogue Spk Mix Right 1
+ */
+#define WM8903_DACL_MIXSPKR_VOL                 0x0008  /* DACL_MIXSPKR_VOL */
+#define WM8903_DACL_MIXSPKR_VOL_MASK            0x0008  /* DACL_MIXSPKR_VOL */
+#define WM8903_DACL_MIXSPKR_VOL_SHIFT                3  /* DACL_MIXSPKR_VOL */
+#define WM8903_DACL_MIXSPKR_VOL_WIDTH                1  /* DACL_MIXSPKR_VOL */
+#define WM8903_DACR_MIXSPKR_VOL                 0x0004  /* DACR_MIXSPKR_VOL */
+#define WM8903_DACR_MIXSPKR_VOL_MASK            0x0004  /* DACR_MIXSPKR_VOL */
+#define WM8903_DACR_MIXSPKR_VOL_SHIFT                2  /* DACR_MIXSPKR_VOL */
+#define WM8903_DACR_MIXSPKR_VOL_WIDTH                1  /* DACR_MIXSPKR_VOL */
+#define WM8903_BYPASSL_MIXSPKR_VOL              0x0002  /* BYPASSL_MIXSPKR_VOL */
+#define WM8903_BYPASSL_MIXSPKR_VOL_MASK         0x0002  /* BYPASSL_MIXSPKR_VOL */
+#define WM8903_BYPASSL_MIXSPKR_VOL_SHIFT             1  /* BYPASSL_MIXSPKR_VOL */
+#define WM8903_BYPASSL_MIXSPKR_VOL_WIDTH             1  /* BYPASSL_MIXSPKR_VOL */
+#define WM8903_BYPASSR_MIXSPKR_VOL              0x0001  /* BYPASSR_MIXSPKR_VOL */
+#define WM8903_BYPASSR_MIXSPKR_VOL_MASK         0x0001  /* BYPASSR_MIXSPKR_VOL */
+#define WM8903_BYPASSR_MIXSPKR_VOL_SHIFT             0  /* BYPASSR_MIXSPKR_VOL */
+#define WM8903_BYPASSR_MIXSPKR_VOL_WIDTH             1  /* BYPASSR_MIXSPKR_VOL */
+
+/*
+ * R57 (0x39) - Analogue OUT1 Left
+ */
+#define WM8903_HPL_MUTE                         0x0100  /* HPL_MUTE */
+#define WM8903_HPL_MUTE_MASK                    0x0100  /* HPL_MUTE */
+#define WM8903_HPL_MUTE_SHIFT                        8  /* HPL_MUTE */
+#define WM8903_HPL_MUTE_WIDTH                        1  /* HPL_MUTE */
+#define WM8903_HPOUTVU                          0x0080  /* HPOUTVU */
+#define WM8903_HPOUTVU_MASK                     0x0080  /* HPOUTVU */
+#define WM8903_HPOUTVU_SHIFT                         7  /* HPOUTVU */
+#define WM8903_HPOUTVU_WIDTH                         1  /* HPOUTVU */
+#define WM8903_HPOUTLZC                         0x0040  /* HPOUTLZC */
+#define WM8903_HPOUTLZC_MASK                    0x0040  /* HPOUTLZC */
+#define WM8903_HPOUTLZC_SHIFT                        6  /* HPOUTLZC */
+#define WM8903_HPOUTLZC_WIDTH                        1  /* HPOUTLZC */
+#define WM8903_HPOUTL_VOL_MASK                  0x003F  /* HPOUTL_VOL - [5:0] */
+#define WM8903_HPOUTL_VOL_SHIFT                      0  /* HPOUTL_VOL - [5:0] */
+#define WM8903_HPOUTL_VOL_WIDTH                      6  /* HPOUTL_VOL - [5:0] */
+
+/*
+ * R58 (0x3A) - Analogue OUT1 Right
+ */
+#define WM8903_HPR_MUTE                         0x0100  /* HPR_MUTE */
+#define WM8903_HPR_MUTE_MASK                    0x0100  /* HPR_MUTE */
+#define WM8903_HPR_MUTE_SHIFT                        8  /* HPR_MUTE */
+#define WM8903_HPR_MUTE_WIDTH                        1  /* HPR_MUTE */
+#define WM8903_HPOUTVU                          0x0080  /* HPOUTVU */
+#define WM8903_HPOUTVU_MASK                     0x0080  /* HPOUTVU */
+#define WM8903_HPOUTVU_SHIFT                         7  /* HPOUTVU */
+#define WM8903_HPOUTVU_WIDTH                         1  /* HPOUTVU */
+#define WM8903_HPOUTRZC                         0x0040  /* HPOUTRZC */
+#define WM8903_HPOUTRZC_MASK                    0x0040  /* HPOUTRZC */
+#define WM8903_HPOUTRZC_SHIFT                        6  /* HPOUTRZC */
+#define WM8903_HPOUTRZC_WIDTH                        1  /* HPOUTRZC */
+#define WM8903_HPOUTR_VOL_MASK                  0x003F  /* HPOUTR_VOL - [5:0] */
+#define WM8903_HPOUTR_VOL_SHIFT                      0  /* HPOUTR_VOL - [5:0] */
+#define WM8903_HPOUTR_VOL_WIDTH                      6  /* HPOUTR_VOL - [5:0] */
+
+/*
+ * R59 (0x3B) - Analogue OUT2 Left
+ */
+#define WM8903_LINEOUTL_MUTE                    0x0100  /* LINEOUTL_MUTE */
+#define WM8903_LINEOUTL_MUTE_MASK               0x0100  /* LINEOUTL_MUTE */
+#define WM8903_LINEOUTL_MUTE_SHIFT                   8  /* LINEOUTL_MUTE */
+#define WM8903_LINEOUTL_MUTE_WIDTH                   1  /* LINEOUTL_MUTE */
+#define WM8903_LINEOUTVU                        0x0080  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_MASK                   0x0080  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_SHIFT                       7  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_WIDTH                       1  /* LINEOUTVU */
+#define WM8903_LINEOUTLZC                       0x0040  /* LINEOUTLZC */
+#define WM8903_LINEOUTLZC_MASK                  0x0040  /* LINEOUTLZC */
+#define WM8903_LINEOUTLZC_SHIFT                      6  /* LINEOUTLZC */
+#define WM8903_LINEOUTLZC_WIDTH                      1  /* LINEOUTLZC */
+#define WM8903_LINEOUTL_VOL_MASK                0x003F  /* LINEOUTL_VOL - [5:0] */
+#define WM8903_LINEOUTL_VOL_SHIFT                    0  /* LINEOUTL_VOL - [5:0] */
+#define WM8903_LINEOUTL_VOL_WIDTH                    6  /* LINEOUTL_VOL - [5:0] */
+
+/*
+ * R60 (0x3C) - Analogue OUT2 Right
+ */
+#define WM8903_LINEOUTR_MUTE                    0x0100  /* LINEOUTR_MUTE */
+#define WM8903_LINEOUTR_MUTE_MASK               0x0100  /* LINEOUTR_MUTE */
+#define WM8903_LINEOUTR_MUTE_SHIFT                   8  /* LINEOUTR_MUTE */
+#define WM8903_LINEOUTR_MUTE_WIDTH                   1  /* LINEOUTR_MUTE */
+#define WM8903_LINEOUTVU                        0x0080  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_MASK                   0x0080  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_SHIFT                       7  /* LINEOUTVU */
+#define WM8903_LINEOUTVU_WIDTH                       1  /* LINEOUTVU */
+#define WM8903_LINEOUTRZC                       0x0040  /* LINEOUTRZC */
+#define WM8903_LINEOUTRZC_MASK                  0x0040  /* LINEOUTRZC */
+#define WM8903_LINEOUTRZC_SHIFT                      6  /* LINEOUTRZC */
+#define WM8903_LINEOUTRZC_WIDTH                      1  /* LINEOUTRZC */
+#define WM8903_LINEOUTR_VOL_MASK                0x003F  /* LINEOUTR_VOL - [5:0] */
+#define WM8903_LINEOUTR_VOL_SHIFT                    0  /* LINEOUTR_VOL - [5:0] */
+#define WM8903_LINEOUTR_VOL_WIDTH                    6  /* LINEOUTR_VOL - [5:0] */
+
+/*
+ * R62 (0x3E) - Analogue OUT3 Left
+ */
+#define WM8903_SPKL_MUTE                        0x0100  /* SPKL_MUTE */
+#define WM8903_SPKL_MUTE_MASK                   0x0100  /* SPKL_MUTE */
+#define WM8903_SPKL_MUTE_SHIFT                       8  /* SPKL_MUTE */
+#define WM8903_SPKL_MUTE_WIDTH                       1  /* SPKL_MUTE */
+#define WM8903_SPKVU                            0x0080  /* SPKVU */
+#define WM8903_SPKVU_MASK                       0x0080  /* SPKVU */
+#define WM8903_SPKVU_SHIFT                           7  /* SPKVU */
+#define WM8903_SPKVU_WIDTH                           1  /* SPKVU */
+#define WM8903_SPKLZC                           0x0040  /* SPKLZC */
+#define WM8903_SPKLZC_MASK                      0x0040  /* SPKLZC */
+#define WM8903_SPKLZC_SHIFT                          6  /* SPKLZC */
+#define WM8903_SPKLZC_WIDTH                          1  /* SPKLZC */
+#define WM8903_SPKL_VOL_MASK                    0x003F  /* SPKL_VOL - [5:0] */
+#define WM8903_SPKL_VOL_SHIFT                        0  /* SPKL_VOL - [5:0] */
+#define WM8903_SPKL_VOL_WIDTH                        6  /* SPKL_VOL - [5:0] */
+
+/*
+ * R63 (0x3F) - Analogue OUT3 Right
+ */
+#define WM8903_SPKR_MUTE                        0x0100  /* SPKR_MUTE */
+#define WM8903_SPKR_MUTE_MASK                   0x0100  /* SPKR_MUTE */
+#define WM8903_SPKR_MUTE_SHIFT                       8  /* SPKR_MUTE */
+#define WM8903_SPKR_MUTE_WIDTH                       1  /* SPKR_MUTE */
+#define WM8903_SPKVU                            0x0080  /* SPKVU */
+#define WM8903_SPKVU_MASK                       0x0080  /* SPKVU */
+#define WM8903_SPKVU_SHIFT                           7  /* SPKVU */
+#define WM8903_SPKVU_WIDTH                           1  /* SPKVU */
+#define WM8903_SPKRZC                           0x0040  /* SPKRZC */
+#define WM8903_SPKRZC_MASK                      0x0040  /* SPKRZC */
+#define WM8903_SPKRZC_SHIFT                          6  /* SPKRZC */
+#define WM8903_SPKRZC_WIDTH                          1  /* SPKRZC */
+#define WM8903_SPKR_VOL_MASK                    0x003F  /* SPKR_VOL - [5:0] */
+#define WM8903_SPKR_VOL_SHIFT                        0  /* SPKR_VOL - [5:0] */
+#define WM8903_SPKR_VOL_WIDTH                        6  /* SPKR_VOL - [5:0] */
+
+/*
+ * R65 (0x41) - Analogue SPK Output Control 0
+ */
+#define WM8903_SPK_DISCHARGE                    0x0002  /* SPK_DISCHARGE */
+#define WM8903_SPK_DISCHARGE_MASK               0x0002  /* SPK_DISCHARGE */
+#define WM8903_SPK_DISCHARGE_SHIFT                   1  /* SPK_DISCHARGE */
+#define WM8903_SPK_DISCHARGE_WIDTH                   1  /* SPK_DISCHARGE */
+#define WM8903_VROI                             0x0001  /* VROI */
+#define WM8903_VROI_MASK                        0x0001  /* VROI */
+#define WM8903_VROI_SHIFT                            0  /* VROI */
+#define WM8903_VROI_WIDTH                            1  /* VROI */
+
+/*
+ * R67 (0x43) - DC Servo 0
+ */
+#define WM8903_DCS_MASTER_ENA                   0x0010  /* DCS_MASTER_ENA */
+#define WM8903_DCS_MASTER_ENA_MASK              0x0010  /* DCS_MASTER_ENA */
+#define WM8903_DCS_MASTER_ENA_SHIFT                  4  /* DCS_MASTER_ENA */
+#define WM8903_DCS_MASTER_ENA_WIDTH                  1  /* DCS_MASTER_ENA */
+#define WM8903_DCS_ENA_MASK                     0x000F  /* DCS_ENA - [3:0] */
+#define WM8903_DCS_ENA_SHIFT                         0  /* DCS_ENA - [3:0] */
+#define WM8903_DCS_ENA_WIDTH                         4  /* DCS_ENA - [3:0] */
+
+/*
+ * R69 (0x45) - DC Servo 2
+ */
+#define WM8903_DCS_MODE_MASK                    0x0003  /* DCS_MODE - [1:0] */
+#define WM8903_DCS_MODE_SHIFT                        0  /* DCS_MODE - [1:0] */
+#define WM8903_DCS_MODE_WIDTH                        2  /* DCS_MODE - [1:0] */
+
+/*
+ * R90 (0x5A) - Analogue HP 0
+ */
+#define WM8903_HPL_RMV_SHORT                    0x0080  /* HPL_RMV_SHORT */
+#define WM8903_HPL_RMV_SHORT_MASK               0x0080  /* HPL_RMV_SHORT */
+#define WM8903_HPL_RMV_SHORT_SHIFT                   7  /* HPL_RMV_SHORT */
+#define WM8903_HPL_RMV_SHORT_WIDTH                   1  /* HPL_RMV_SHORT */
+#define WM8903_HPL_ENA_OUTP                     0x0040  /* HPL_ENA_OUTP */
+#define WM8903_HPL_ENA_OUTP_MASK                0x0040  /* HPL_ENA_OUTP */
+#define WM8903_HPL_ENA_OUTP_SHIFT                    6  /* HPL_ENA_OUTP */
+#define WM8903_HPL_ENA_OUTP_WIDTH                    1  /* HPL_ENA_OUTP */
+#define WM8903_HPL_ENA_DLY                      0x0020  /* HPL_ENA_DLY */
+#define WM8903_HPL_ENA_DLY_MASK                 0x0020  /* HPL_ENA_DLY */
+#define WM8903_HPL_ENA_DLY_SHIFT                     5  /* HPL_ENA_DLY */
+#define WM8903_HPL_ENA_DLY_WIDTH                     1  /* HPL_ENA_DLY */
+#define WM8903_HPL_ENA                          0x0010  /* HPL_ENA */
+#define WM8903_HPL_ENA_MASK                     0x0010  /* HPL_ENA */
+#define WM8903_HPL_ENA_SHIFT                         4  /* HPL_ENA */
+#define WM8903_HPL_ENA_WIDTH                         1  /* HPL_ENA */
+#define WM8903_HPR_RMV_SHORT                    0x0008  /* HPR_RMV_SHORT */
+#define WM8903_HPR_RMV_SHORT_MASK               0x0008  /* HPR_RMV_SHORT */
+#define WM8903_HPR_RMV_SHORT_SHIFT                   3  /* HPR_RMV_SHORT */
+#define WM8903_HPR_RMV_SHORT_WIDTH                   1  /* HPR_RMV_SHORT */
+#define WM8903_HPR_ENA_OUTP                     0x0004  /* HPR_ENA_OUTP */
+#define WM8903_HPR_ENA_OUTP_MASK                0x0004  /* HPR_ENA_OUTP */
+#define WM8903_HPR_ENA_OUTP_SHIFT                    2  /* HPR_ENA_OUTP */
+#define WM8903_HPR_ENA_OUTP_WIDTH                    1  /* HPR_ENA_OUTP */
+#define WM8903_HPR_ENA_DLY                      0x0002  /* HPR_ENA_DLY */
+#define WM8903_HPR_ENA_DLY_MASK                 0x0002  /* HPR_ENA_DLY */
+#define WM8903_HPR_ENA_DLY_SHIFT                     1  /* HPR_ENA_DLY */
+#define WM8903_HPR_ENA_DLY_WIDTH                     1  /* HPR_ENA_DLY */
+#define WM8903_HPR_ENA                          0x0001  /* HPR_ENA */
+#define WM8903_HPR_ENA_MASK                     0x0001  /* HPR_ENA */
+#define WM8903_HPR_ENA_SHIFT                         0  /* HPR_ENA */
+#define WM8903_HPR_ENA_WIDTH                         1  /* HPR_ENA */
+
+/*
+ * R94 (0x5E) - Analogue Lineout 0
+ */
+#define WM8903_LINEOUTL_RMV_SHORT               0x0080  /* LINEOUTL_RMV_SHORT */
+#define WM8903_LINEOUTL_RMV_SHORT_MASK          0x0080  /* LINEOUTL_RMV_SHORT */
+#define WM8903_LINEOUTL_RMV_SHORT_SHIFT              7  /* LINEOUTL_RMV_SHORT */
+#define WM8903_LINEOUTL_RMV_SHORT_WIDTH              1  /* LINEOUTL_RMV_SHORT */
+#define WM8903_LINEOUTL_ENA_OUTP                0x0040  /* LINEOUTL_ENA_OUTP */
+#define WM8903_LINEOUTL_ENA_OUTP_MASK           0x0040  /* LINEOUTL_ENA_OUTP */
+#define WM8903_LINEOUTL_ENA_OUTP_SHIFT               6  /* LINEOUTL_ENA_OUTP */
+#define WM8903_LINEOUTL_ENA_OUTP_WIDTH               1  /* LINEOUTL_ENA_OUTP */
+#define WM8903_LINEOUTL_ENA_DLY                 0x0020  /* LINEOUTL_ENA_DLY */
+#define WM8903_LINEOUTL_ENA_DLY_MASK            0x0020  /* LINEOUTL_ENA_DLY */
+#define WM8903_LINEOUTL_ENA_DLY_SHIFT                5  /* LINEOUTL_ENA_DLY */
+#define WM8903_LINEOUTL_ENA_DLY_WIDTH                1  /* LINEOUTL_ENA_DLY */
+#define WM8903_LINEOUTL_ENA                     0x0010  /* LINEOUTL_ENA */
+#define WM8903_LINEOUTL_ENA_MASK                0x0010  /* LINEOUTL_ENA */
+#define WM8903_LINEOUTL_ENA_SHIFT                    4  /* LINEOUTL_ENA */
+#define WM8903_LINEOUTL_ENA_WIDTH                    1  /* LINEOUTL_ENA */
+#define WM8903_LINEOUTR_RMV_SHORT               0x0008  /* LINEOUTR_RMV_SHORT */
+#define WM8903_LINEOUTR_RMV_SHORT_MASK          0x0008  /* LINEOUTR_RMV_SHORT */
+#define WM8903_LINEOUTR_RMV_SHORT_SHIFT              3  /* LINEOUTR_RMV_SHORT */
+#define WM8903_LINEOUTR_RMV_SHORT_WIDTH              1  /* LINEOUTR_RMV_SHORT */
+#define WM8903_LINEOUTR_ENA_OUTP                0x0004  /* LINEOUTR_ENA_OUTP */
+#define WM8903_LINEOUTR_ENA_OUTP_MASK           0x0004  /* LINEOUTR_ENA_OUTP */
+#define WM8903_LINEOUTR_ENA_OUTP_SHIFT               2  /* LINEOUTR_ENA_OUTP */
+#define WM8903_LINEOUTR_ENA_OUTP_WIDTH               1  /* LINEOUTR_ENA_OUTP */
+#define WM8903_LINEOUTR_ENA_DLY                 0x0002  /* LINEOUTR_ENA_DLY */
+#define WM8903_LINEOUTR_ENA_DLY_MASK            0x0002  /* LINEOUTR_ENA_DLY */
+#define WM8903_LINEOUTR_ENA_DLY_SHIFT                1  /* LINEOUTR_ENA_DLY */
+#define WM8903_LINEOUTR_ENA_DLY_WIDTH                1  /* LINEOUTR_ENA_DLY */
+#define WM8903_LINEOUTR_ENA                     0x0001  /* LINEOUTR_ENA */
+#define WM8903_LINEOUTR_ENA_MASK                0x0001  /* LINEOUTR_ENA */
+#define WM8903_LINEOUTR_ENA_SHIFT                    0  /* LINEOUTR_ENA */
+#define WM8903_LINEOUTR_ENA_WIDTH                    1  /* LINEOUTR_ENA */
+
+/*
+ * R98 (0x62) - Charge Pump 0
+ */
+#define WM8903_CP_ENA                           0x0001  /* CP_ENA */
+#define WM8903_CP_ENA_MASK                      0x0001  /* CP_ENA */
+#define WM8903_CP_ENA_SHIFT                          0  /* CP_ENA */
+#define WM8903_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R104 (0x68) - Class W 0
+ */
+#define WM8903_CP_DYN_FREQ                      0x0002  /* CP_DYN_FREQ */
+#define WM8903_CP_DYN_FREQ_MASK                 0x0002  /* CP_DYN_FREQ */
+#define WM8903_CP_DYN_FREQ_SHIFT                     1  /* CP_DYN_FREQ */
+#define WM8903_CP_DYN_FREQ_WIDTH                     1  /* CP_DYN_FREQ */
+#define WM8903_CP_DYN_V                         0x0001  /* CP_DYN_V */
+#define WM8903_CP_DYN_V_MASK                    0x0001  /* CP_DYN_V */
+#define WM8903_CP_DYN_V_SHIFT                        0  /* CP_DYN_V */
+#define WM8903_CP_DYN_V_WIDTH                        1  /* CP_DYN_V */
+
+/*
+ * R108 (0x6C) - Write Sequencer 0
+ */
+#define WM8903_WSEQ_ENA                         0x0100  /* WSEQ_ENA */
+#define WM8903_WSEQ_ENA_MASK                    0x0100  /* WSEQ_ENA */
+#define WM8903_WSEQ_ENA_SHIFT                        8  /* WSEQ_ENA */
+#define WM8903_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM8903_WSEQ_WRITE_INDEX_MASK            0x001F  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8903_WSEQ_WRITE_INDEX_SHIFT                0  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8903_WSEQ_WRITE_INDEX_WIDTH                5  /* WSEQ_WRITE_INDEX - [4:0] */
+
+/*
+ * R109 (0x6D) - Write Sequencer 1
+ */
+#define WM8903_WSEQ_DATA_WIDTH_MASK             0x7000  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8903_WSEQ_DATA_WIDTH_SHIFT                12  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8903_WSEQ_DATA_WIDTH_WIDTH                 3  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8903_WSEQ_DATA_START_MASK             0x0F00  /* WSEQ_DATA_START - [11:8] */
+#define WM8903_WSEQ_DATA_START_SHIFT                 8  /* WSEQ_DATA_START - [11:8] */
+#define WM8903_WSEQ_DATA_START_WIDTH                 4  /* WSEQ_DATA_START - [11:8] */
+#define WM8903_WSEQ_ADDR_MASK                   0x00FF  /* WSEQ_ADDR - [7:0] */
+#define WM8903_WSEQ_ADDR_SHIFT                       0  /* WSEQ_ADDR - [7:0] */
+#define WM8903_WSEQ_ADDR_WIDTH                       8  /* WSEQ_ADDR - [7:0] */
+
+/*
+ * R110 (0x6E) - Write Sequencer 2
+ */
+#define WM8903_WSEQ_EOS                         0x4000  /* WSEQ_EOS */
+#define WM8903_WSEQ_EOS_MASK                    0x4000  /* WSEQ_EOS */
+#define WM8903_WSEQ_EOS_SHIFT                       14  /* WSEQ_EOS */
+#define WM8903_WSEQ_EOS_WIDTH                        1  /* WSEQ_EOS */
+#define WM8903_WSEQ_DELAY_MASK                  0x0F00  /* WSEQ_DELAY - [11:8] */
+#define WM8903_WSEQ_DELAY_SHIFT                      8  /* WSEQ_DELAY - [11:8] */
+#define WM8903_WSEQ_DELAY_WIDTH                      4  /* WSEQ_DELAY - [11:8] */
+#define WM8903_WSEQ_DATA_MASK                   0x00FF  /* WSEQ_DATA - [7:0] */
+#define WM8903_WSEQ_DATA_SHIFT                       0  /* WSEQ_DATA - [7:0] */
+#define WM8903_WSEQ_DATA_WIDTH                       8  /* WSEQ_DATA - [7:0] */
+
+/*
+ * R111 (0x6F) - Write Sequencer 3
+ */
+#define WM8903_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM8903_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM8903_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM8903_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8903_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM8903_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM8903_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM8903_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8903_WSEQ_START_INDEX_MASK            0x003F  /* WSEQ_START_INDEX - [5:0] */
+#define WM8903_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [5:0] */
+#define WM8903_WSEQ_START_INDEX_WIDTH                6  /* WSEQ_START_INDEX - [5:0] */
+
+/*
+ * R112 (0x70) - Write Sequencer 4
+ */
+#define WM8903_WSEQ_CURRENT_INDEX_MASK          0x03F0  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8903_WSEQ_CURRENT_INDEX_SHIFT              4  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8903_WSEQ_CURRENT_INDEX_WIDTH              6  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8903_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM8903_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM8903_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM8903_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R114 (0x72) - Control Interface
+ */
+#define WM8903_MASK_WRITE_ENA                   0x0001  /* MASK_WRITE_ENA */
+#define WM8903_MASK_WRITE_ENA_MASK              0x0001  /* MASK_WRITE_ENA */
+#define WM8903_MASK_WRITE_ENA_SHIFT                  0  /* MASK_WRITE_ENA */
+#define WM8903_MASK_WRITE_ENA_WIDTH                  1  /* MASK_WRITE_ENA */
+
+/*
+ * R121 (0x79) - Interrupt Status 1
+ */
+#define WM8903_MICSHRT_EINT                     0x8000  /* MICSHRT_EINT */
+#define WM8903_MICSHRT_EINT_MASK                0x8000  /* MICSHRT_EINT */
+#define WM8903_MICSHRT_EINT_SHIFT                   15  /* MICSHRT_EINT */
+#define WM8903_MICSHRT_EINT_WIDTH                    1  /* MICSHRT_EINT */
+#define WM8903_MICDET_EINT                      0x4000  /* MICDET_EINT */
+#define WM8903_MICDET_EINT_MASK                 0x4000  /* MICDET_EINT */
+#define WM8903_MICDET_EINT_SHIFT                    14  /* MICDET_EINT */
+#define WM8903_MICDET_EINT_WIDTH                     1  /* MICDET_EINT */
+#define WM8903_WSEQ_BUSY_EINT                   0x2000  /* WSEQ_BUSY_EINT */
+#define WM8903_WSEQ_BUSY_EINT_MASK              0x2000  /* WSEQ_BUSY_EINT */
+#define WM8903_WSEQ_BUSY_EINT_SHIFT                 13  /* WSEQ_BUSY_EINT */
+#define WM8903_WSEQ_BUSY_EINT_WIDTH                  1  /* WSEQ_BUSY_EINT */
+#define WM8903_GP5_EINT                         0x0010  /* GP5_EINT */
+#define WM8903_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
+#define WM8903_GP5_EINT_SHIFT                        4  /* GP5_EINT */
+#define WM8903_GP5_EINT_WIDTH                        1  /* GP5_EINT */
+#define WM8903_GP4_EINT                         0x0008  /* GP4_EINT */
+#define WM8903_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
+#define WM8903_GP4_EINT_SHIFT                        3  /* GP4_EINT */
+#define WM8903_GP4_EINT_WIDTH                        1  /* GP4_EINT */
+#define WM8903_GP3_EINT                         0x0004  /* GP3_EINT */
+#define WM8903_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
+#define WM8903_GP3_EINT_SHIFT                        2  /* GP3_EINT */
+#define WM8903_GP3_EINT_WIDTH                        1  /* GP3_EINT */
+#define WM8903_GP2_EINT                         0x0002  /* GP2_EINT */
+#define WM8903_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
+#define WM8903_GP2_EINT_SHIFT                        1  /* GP2_EINT */
+#define WM8903_GP2_EINT_WIDTH                        1  /* GP2_EINT */
+#define WM8903_GP1_EINT                         0x0001  /* GP1_EINT */
+#define WM8903_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
+#define WM8903_GP1_EINT_SHIFT                        0  /* GP1_EINT */
+#define WM8903_GP1_EINT_WIDTH                        1  /* GP1_EINT */
+
+/*
+ * R122 (0x7A) - Interrupt Status 1 Mask
+ */
+#define WM8903_IM_MICSHRT_EINT                  0x8000  /* IM_MICSHRT_EINT */
+#define WM8903_IM_MICSHRT_EINT_MASK             0x8000  /* IM_MICSHRT_EINT */
+#define WM8903_IM_MICSHRT_EINT_SHIFT                15  /* IM_MICSHRT_EINT */
+#define WM8903_IM_MICSHRT_EINT_WIDTH                 1  /* IM_MICSHRT_EINT */
+#define WM8903_IM_MICDET_EINT                   0x4000  /* IM_MICDET_EINT */
+#define WM8903_IM_MICDET_EINT_MASK              0x4000  /* IM_MICDET_EINT */
+#define WM8903_IM_MICDET_EINT_SHIFT                 14  /* IM_MICDET_EINT */
+#define WM8903_IM_MICDET_EINT_WIDTH                  1  /* IM_MICDET_EINT */
+#define WM8903_IM_WSEQ_BUSY_EINT                0x2000  /* IM_WSEQ_BUSY_EINT */
+#define WM8903_IM_WSEQ_BUSY_EINT_MASK           0x2000  /* IM_WSEQ_BUSY_EINT */
+#define WM8903_IM_WSEQ_BUSY_EINT_SHIFT              13  /* IM_WSEQ_BUSY_EINT */
+#define WM8903_IM_WSEQ_BUSY_EINT_WIDTH               1  /* IM_WSEQ_BUSY_EINT */
+#define WM8903_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
+#define WM8903_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
+#define WM8903_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
+#define WM8903_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
+#define WM8903_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
+#define WM8903_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
+#define WM8903_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
+#define WM8903_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
+#define WM8903_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
+#define WM8903_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
+#define WM8903_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
+#define WM8903_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
+#define WM8903_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
+#define WM8903_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
+#define WM8903_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
+#define WM8903_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
+#define WM8903_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
+#define WM8903_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
+#define WM8903_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
+#define WM8903_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
+
+/*
+ * R123 (0x7B) - Interrupt Polarity 1
+ */
+#define WM8903_MICSHRT_INV                      0x8000  /* MICSHRT_INV */
+#define WM8903_MICSHRT_INV_MASK                 0x8000  /* MICSHRT_INV */
+#define WM8903_MICSHRT_INV_SHIFT                    15  /* MICSHRT_INV */
+#define WM8903_MICSHRT_INV_WIDTH                     1  /* MICSHRT_INV */
+#define WM8903_MICDET_INV                       0x4000  /* MICDET_INV */
+#define WM8903_MICDET_INV_MASK                  0x4000  /* MICDET_INV */
+#define WM8903_MICDET_INV_SHIFT                     14  /* MICDET_INV */
+#define WM8903_MICDET_INV_WIDTH                      1  /* MICDET_INV */
+
+/*
+ * R126 (0x7E) - Interrupt Control
+ */
+#define WM8903_IRQ_POL                          0x0001  /* IRQ_POL */
+#define WM8903_IRQ_POL_MASK                     0x0001  /* IRQ_POL */
+#define WM8903_IRQ_POL_SHIFT                         0  /* IRQ_POL */
+#define WM8903_IRQ_POL_WIDTH                         1  /* IRQ_POL */
+
+/*
+ * R164 (0xA4) - Clock Rate Test 4
+ */
+#define WM8903_ADC_DIG_MIC                      0x0200  /* ADC_DIG_MIC */
+#define WM8903_ADC_DIG_MIC_MASK                 0x0200  /* ADC_DIG_MIC */
+#define WM8903_ADC_DIG_MIC_SHIFT                     9  /* ADC_DIG_MIC */
+#define WM8903_ADC_DIG_MIC_WIDTH                     1  /* ADC_DIG_MIC */
+
+/*
+ * R172 (0xAC) - Analogue Output Bias 0
+ */
+#define WM8903_PGA_BIAS_MASK                    0x0070  /* PGA_BIAS - [6:4] */
+#define WM8903_PGA_BIAS_SHIFT                        4  /* PGA_BIAS - [6:4] */
+#define WM8903_PGA_BIAS_WIDTH                        3  /* PGA_BIAS - [6:4] */
+
+#endif
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
new file mode 100644
index 0000000..1965635
--- /dev/null
+++ b/sound/soc/codecs/wm8904.c
@@ -0,0 +1,2303 @@
+/*
+ * wm8904.c  --  WM8904 ALSA SoC Audio driver
+ *
+ * Copyright 2009-12 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/wm8904.h>
+
+#include "wm8904.h"
+
+enum wm8904_type {
+	WM8904,
+	WM8912,
+};
+
+#define WM8904_NUM_DCS_CHANNELS 4
+
+#define WM8904_NUM_SUPPLIES 5
+static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = {
+	"DCVDD",
+	"DBVDD",
+	"AVDD",
+	"CPVDD",
+	"MICVDD",
+};
+
+/* codec private data */
+struct wm8904_priv {
+	struct regmap *regmap;
+	struct clk *mclk;
+
+	enum wm8904_type devtype;
+
+	struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES];
+
+	struct wm8904_pdata *pdata;
+
+	int deemph;
+
+	/* Platform provided DRC configuration */
+	const char **drc_texts;
+	int drc_cfg;
+	struct soc_enum drc_enum;
+
+	/* Platform provided ReTune mobile configuration */
+	int num_retune_mobile_texts;
+	const char **retune_mobile_texts;
+	int retune_mobile_cfg;
+	struct soc_enum retune_mobile_enum;
+
+	/* FLL setup */
+	int fll_src;
+	int fll_fref;
+	int fll_fout;
+
+	/* Clocking configuration */
+	unsigned int mclk_rate;
+	int sysclk_src;
+	unsigned int sysclk_rate;
+
+	int tdm_width;
+	int tdm_slots;
+	int bclk;
+	int fs;
+
+	/* DC servo configuration - cached offset values */
+	int dcs_state[WM8904_NUM_DCS_CHANNELS];
+};
+
+static const struct reg_default wm8904_reg_defaults[] = {
+	{ 4,   0x0018 },     /* R4   - Bias Control 0 */
+	{ 5,   0x0000 },     /* R5   - VMID Control 0 */
+	{ 6,   0x0000 },     /* R6   - Mic Bias Control 0 */
+	{ 7,   0x0000 },     /* R7   - Mic Bias Control 1 */
+	{ 8,   0x0001 },     /* R8   - Analogue DAC 0 */
+	{ 9,   0x9696 },     /* R9   - mic Filter Control */
+	{ 10,  0x0001 },     /* R10  - Analogue ADC 0 */
+	{ 12,  0x0000 },     /* R12  - Power Management 0 */
+	{ 14,  0x0000 },     /* R14  - Power Management 2 */
+	{ 15,  0x0000 },     /* R15  - Power Management 3 */
+	{ 18,  0x0000 },     /* R18  - Power Management 6 */
+	{ 20,  0x945E },     /* R20  - Clock Rates 0 */
+	{ 21,  0x0C05 },     /* R21  - Clock Rates 1 */
+	{ 22,  0x0006 },     /* R22  - Clock Rates 2 */
+	{ 24,  0x0050 },     /* R24  - Audio Interface 0 */
+	{ 25,  0x000A },     /* R25  - Audio Interface 1 */
+	{ 26,  0x00E4 },     /* R26  - Audio Interface 2 */
+	{ 27,  0x0040 },     /* R27  - Audio Interface 3 */
+	{ 30,  0x00C0 },     /* R30  - DAC Digital Volume Left */
+	{ 31,  0x00C0 },     /* R31  - DAC Digital Volume Right */
+	{ 32,  0x0000 },     /* R32  - DAC Digital 0 */
+	{ 33,  0x0008 },     /* R33  - DAC Digital 1 */
+	{ 36,  0x00C0 },     /* R36  - ADC Digital Volume Left */
+	{ 37,  0x00C0 },     /* R37  - ADC Digital Volume Right */
+	{ 38,  0x0010 },     /* R38  - ADC Digital 0 */
+	{ 39,  0x0000 },     /* R39  - Digital Microphone 0 */
+	{ 40,  0x01AF },     /* R40  - DRC 0 */
+	{ 41,  0x3248 },     /* R41  - DRC 1 */
+	{ 42,  0x0000 },     /* R42  - DRC 2 */
+	{ 43,  0x0000 },     /* R43  - DRC 3 */
+	{ 44,  0x0085 },     /* R44  - Analogue Left Input 0 */
+	{ 45,  0x0085 },     /* R45  - Analogue Right Input 0 */
+	{ 46,  0x0044 },     /* R46  - Analogue Left Input 1 */
+	{ 47,  0x0044 },     /* R47  - Analogue Right Input 1 */
+	{ 57,  0x002D },     /* R57  - Analogue OUT1 Left */
+	{ 58,  0x002D },     /* R58  - Analogue OUT1 Right */
+	{ 59,  0x0039 },     /* R59  - Analogue OUT2 Left */
+	{ 60,  0x0039 },     /* R60  - Analogue OUT2 Right */
+	{ 61,  0x0000 },     /* R61  - Analogue OUT12 ZC */
+	{ 67,  0x0000 },     /* R67  - DC Servo 0 */
+	{ 69,  0xAAAA },     /* R69  - DC Servo 2 */
+	{ 71,  0xAAAA },     /* R71  - DC Servo 4 */
+	{ 72,  0xAAAA },     /* R72  - DC Servo 5 */
+	{ 90,  0x0000 },     /* R90  - Analogue HP 0 */
+	{ 94,  0x0000 },     /* R94  - Analogue Lineout 0 */
+	{ 98,  0x0000 },     /* R98  - Charge Pump 0 */
+	{ 104, 0x0004 },     /* R104 - Class W 0 */
+	{ 108, 0x0000 },     /* R108 - Write Sequencer 0 */
+	{ 109, 0x0000 },     /* R109 - Write Sequencer 1 */
+	{ 110, 0x0000 },     /* R110 - Write Sequencer 2 */
+	{ 111, 0x0000 },     /* R111 - Write Sequencer 3 */
+	{ 112, 0x0000 },     /* R112 - Write Sequencer 4 */
+	{ 116, 0x0000 },     /* R116 - FLL Control 1 */
+	{ 117, 0x0007 },     /* R117 - FLL Control 2 */
+	{ 118, 0x0000 },     /* R118 - FLL Control 3 */
+	{ 119, 0x2EE0 },     /* R119 - FLL Control 4 */
+	{ 120, 0x0004 },     /* R120 - FLL Control 5 */
+	{ 121, 0x0014 },     /* R121 - GPIO Control 1 */
+	{ 122, 0x0010 },     /* R122 - GPIO Control 2 */
+	{ 123, 0x0010 },     /* R123 - GPIO Control 3 */
+	{ 124, 0x0000 },     /* R124 - GPIO Control 4 */
+	{ 126, 0x0000 },     /* R126 - Digital Pulls */
+	{ 128, 0xFFFF },     /* R128 - Interrupt Status Mask */
+	{ 129, 0x0000 },     /* R129 - Interrupt Polarity */
+	{ 130, 0x0000 },     /* R130 - Interrupt Debounce */
+	{ 134, 0x0000 },     /* R134 - EQ1 */
+	{ 135, 0x000C },     /* R135 - EQ2 */
+	{ 136, 0x000C },     /* R136 - EQ3 */
+	{ 137, 0x000C },     /* R137 - EQ4 */
+	{ 138, 0x000C },     /* R138 - EQ5 */
+	{ 139, 0x000C },     /* R139 - EQ6 */
+	{ 140, 0x0FCA },     /* R140 - EQ7 */
+	{ 141, 0x0400 },     /* R141 - EQ8 */
+	{ 142, 0x00D8 },     /* R142 - EQ9 */
+	{ 143, 0x1EB5 },     /* R143 - EQ10 */
+	{ 144, 0xF145 },     /* R144 - EQ11 */
+	{ 145, 0x0B75 },     /* R145 - EQ12 */
+	{ 146, 0x01C5 },     /* R146 - EQ13 */
+	{ 147, 0x1C58 },     /* R147 - EQ14 */
+	{ 148, 0xF373 },     /* R148 - EQ15 */
+	{ 149, 0x0A54 },     /* R149 - EQ16 */
+	{ 150, 0x0558 },     /* R150 - EQ17 */
+	{ 151, 0x168E },     /* R151 - EQ18 */
+	{ 152, 0xF829 },     /* R152 - EQ19 */
+	{ 153, 0x07AD },     /* R153 - EQ20 */
+	{ 154, 0x1103 },     /* R154 - EQ21 */
+	{ 155, 0x0564 },     /* R155 - EQ22 */
+	{ 156, 0x0559 },     /* R156 - EQ23 */
+	{ 157, 0x4000 },     /* R157 - EQ24 */
+	{ 161, 0x0000 },     /* R161 - Control Interface Test 1 */
+	{ 204, 0x0000 },     /* R204 - Analogue Output Bias 0 */
+	{ 247, 0x0000 },     /* R247 - FLL NCO Test 0 */
+	{ 248, 0x0019 },     /* R248 - FLL NCO Test 1 */
+};
+
+static bool wm8904_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8904_SW_RESET_AND_ID:
+	case WM8904_REVISION:
+	case WM8904_DC_SERVO_1:
+	case WM8904_DC_SERVO_6:
+	case WM8904_DC_SERVO_7:
+	case WM8904_DC_SERVO_8:
+	case WM8904_DC_SERVO_9:
+	case WM8904_DC_SERVO_READBACK_0:
+	case WM8904_INTERRUPT_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm8904_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8904_SW_RESET_AND_ID:
+	case WM8904_REVISION:
+	case WM8904_BIAS_CONTROL_0:
+	case WM8904_VMID_CONTROL_0:
+	case WM8904_MIC_BIAS_CONTROL_0:
+	case WM8904_MIC_BIAS_CONTROL_1:
+	case WM8904_ANALOGUE_DAC_0:
+	case WM8904_MIC_FILTER_CONTROL:
+	case WM8904_ANALOGUE_ADC_0:
+	case WM8904_POWER_MANAGEMENT_0:
+	case WM8904_POWER_MANAGEMENT_2:
+	case WM8904_POWER_MANAGEMENT_3:
+	case WM8904_POWER_MANAGEMENT_6:
+	case WM8904_CLOCK_RATES_0:
+	case WM8904_CLOCK_RATES_1:
+	case WM8904_CLOCK_RATES_2:
+	case WM8904_AUDIO_INTERFACE_0:
+	case WM8904_AUDIO_INTERFACE_1:
+	case WM8904_AUDIO_INTERFACE_2:
+	case WM8904_AUDIO_INTERFACE_3:
+	case WM8904_DAC_DIGITAL_VOLUME_LEFT:
+	case WM8904_DAC_DIGITAL_VOLUME_RIGHT:
+	case WM8904_DAC_DIGITAL_0:
+	case WM8904_DAC_DIGITAL_1:
+	case WM8904_ADC_DIGITAL_VOLUME_LEFT:
+	case WM8904_ADC_DIGITAL_VOLUME_RIGHT:
+	case WM8904_ADC_DIGITAL_0:
+	case WM8904_DIGITAL_MICROPHONE_0:
+	case WM8904_DRC_0:
+	case WM8904_DRC_1:
+	case WM8904_DRC_2:
+	case WM8904_DRC_3:
+	case WM8904_ANALOGUE_LEFT_INPUT_0:
+	case WM8904_ANALOGUE_RIGHT_INPUT_0:
+	case WM8904_ANALOGUE_LEFT_INPUT_1:
+	case WM8904_ANALOGUE_RIGHT_INPUT_1:
+	case WM8904_ANALOGUE_OUT1_LEFT:
+	case WM8904_ANALOGUE_OUT1_RIGHT:
+	case WM8904_ANALOGUE_OUT2_LEFT:
+	case WM8904_ANALOGUE_OUT2_RIGHT:
+	case WM8904_ANALOGUE_OUT12_ZC:
+	case WM8904_DC_SERVO_0:
+	case WM8904_DC_SERVO_1:
+	case WM8904_DC_SERVO_2:
+	case WM8904_DC_SERVO_4:
+	case WM8904_DC_SERVO_5:
+	case WM8904_DC_SERVO_6:
+	case WM8904_DC_SERVO_7:
+	case WM8904_DC_SERVO_8:
+	case WM8904_DC_SERVO_9:
+	case WM8904_DC_SERVO_READBACK_0:
+	case WM8904_ANALOGUE_HP_0:
+	case WM8904_ANALOGUE_LINEOUT_0:
+	case WM8904_CHARGE_PUMP_0:
+	case WM8904_CLASS_W_0:
+	case WM8904_WRITE_SEQUENCER_0:
+	case WM8904_WRITE_SEQUENCER_1:
+	case WM8904_WRITE_SEQUENCER_2:
+	case WM8904_WRITE_SEQUENCER_3:
+	case WM8904_WRITE_SEQUENCER_4:
+	case WM8904_FLL_CONTROL_1:
+	case WM8904_FLL_CONTROL_2:
+	case WM8904_FLL_CONTROL_3:
+	case WM8904_FLL_CONTROL_4:
+	case WM8904_FLL_CONTROL_5:
+	case WM8904_GPIO_CONTROL_1:
+	case WM8904_GPIO_CONTROL_2:
+	case WM8904_GPIO_CONTROL_3:
+	case WM8904_GPIO_CONTROL_4:
+	case WM8904_DIGITAL_PULLS:
+	case WM8904_INTERRUPT_STATUS:
+	case WM8904_INTERRUPT_STATUS_MASK:
+	case WM8904_INTERRUPT_POLARITY:
+	case WM8904_INTERRUPT_DEBOUNCE:
+	case WM8904_EQ1:
+	case WM8904_EQ2:
+	case WM8904_EQ3:
+	case WM8904_EQ4:
+	case WM8904_EQ5:
+	case WM8904_EQ6:
+	case WM8904_EQ7:
+	case WM8904_EQ8:
+	case WM8904_EQ9:
+	case WM8904_EQ10:
+	case WM8904_EQ11:
+	case WM8904_EQ12:
+	case WM8904_EQ13:
+	case WM8904_EQ14:
+	case WM8904_EQ15:
+	case WM8904_EQ16:
+	case WM8904_EQ17:
+	case WM8904_EQ18:
+	case WM8904_EQ19:
+	case WM8904_EQ20:
+	case WM8904_EQ21:
+	case WM8904_EQ22:
+	case WM8904_EQ23:
+	case WM8904_EQ24:
+	case WM8904_CONTROL_INTERFACE_TEST_1:
+	case WM8904_ADC_TEST_0:
+	case WM8904_ANALOGUE_OUTPUT_BIAS_0:
+	case WM8904_FLL_NCO_TEST_0:
+	case WM8904_FLL_NCO_TEST_1:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int wm8904_configure_clocking(struct snd_soc_component *component)
+{
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	unsigned int clock0, clock2, rate;
+
+	/* Gate the clock while we're updating to avoid misclocking */
+	clock2 = snd_soc_component_read32(component, WM8904_CLOCK_RATES_2);
+	snd_soc_component_update_bits(component, WM8904_CLOCK_RATES_2,
+			    WM8904_SYSCLK_SRC, 0);
+
+	/* This should be done on init() for bypass paths */
+	switch (wm8904->sysclk_src) {
+	case WM8904_CLK_MCLK:
+		dev_dbg(component->dev, "Using %dHz MCLK\n", wm8904->mclk_rate);
+
+		clock2 &= ~WM8904_SYSCLK_SRC;
+		rate = wm8904->mclk_rate;
+
+		/* Ensure the FLL is stopped */
+		snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
+				    WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
+		break;
+
+	case WM8904_CLK_FLL:
+		dev_dbg(component->dev, "Using %dHz FLL clock\n",
+			wm8904->fll_fout);
+
+		clock2 |= WM8904_SYSCLK_SRC;
+		rate = wm8904->fll_fout;
+		break;
+
+	default:
+		dev_err(component->dev, "System clock not configured\n");
+		return -EINVAL;
+	}
+
+	/* SYSCLK shouldn't be over 13.5MHz */
+	if (rate > 13500000) {
+		clock0 = WM8904_MCLK_DIV;
+		wm8904->sysclk_rate = rate / 2;
+	} else {
+		clock0 = 0;
+		wm8904->sysclk_rate = rate;
+	}
+
+	snd_soc_component_update_bits(component, WM8904_CLOCK_RATES_0, WM8904_MCLK_DIV,
+			    clock0);
+
+	snd_soc_component_update_bits(component, WM8904_CLOCK_RATES_2,
+			    WM8904_CLK_SYS_ENA | WM8904_SYSCLK_SRC, clock2);
+
+	dev_dbg(component->dev, "CLK_SYS is %dHz\n", wm8904->sysclk_rate);
+
+	return 0;
+}
+
+static void wm8904_set_drc(struct snd_soc_component *component)
+{
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	struct wm8904_pdata *pdata = wm8904->pdata;
+	int save, i;
+
+	/* Save any enables; the configuration should clear them. */
+	save = snd_soc_component_read32(component, WM8904_DRC_0);
+
+	for (i = 0; i < WM8904_DRC_REGS; i++)
+		snd_soc_component_update_bits(component, WM8904_DRC_0 + i, 0xffff,
+				    pdata->drc_cfgs[wm8904->drc_cfg].regs[i]);
+
+	/* Reenable the DRC */
+	snd_soc_component_update_bits(component, WM8904_DRC_0,
+			    WM8904_DRC_ENA | WM8904_DRC_DAC_PATH, save);
+}
+
+static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	struct wm8904_pdata *pdata = wm8904->pdata;
+	int value = ucontrol->value.enumerated.item[0];
+
+	if (value >= pdata->num_drc_cfgs)
+		return -EINVAL;
+
+	wm8904->drc_cfg = value;
+
+	wm8904_set_drc(component);
+
+	return 0;
+}
+
+static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.enumerated.item[0] = wm8904->drc_cfg;
+
+	return 0;
+}
+
+static void wm8904_set_retune_mobile(struct snd_soc_component *component)
+{
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	struct wm8904_pdata *pdata = wm8904->pdata;
+	int best, best_val, save, i, cfg;
+
+	if (!pdata || !wm8904->num_retune_mobile_texts)
+		return;
+
+	/* Find the version of the currently selected configuration
+	 * with the nearest sample rate. */
+	cfg = wm8904->retune_mobile_cfg;
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+		if (strcmp(pdata->retune_mobile_cfgs[i].name,
+			   wm8904->retune_mobile_texts[cfg]) == 0 &&
+		    abs(pdata->retune_mobile_cfgs[i].rate
+			- wm8904->fs) < best_val) {
+			best = i;
+			best_val = abs(pdata->retune_mobile_cfgs[i].rate
+				       - wm8904->fs);
+		}
+	}
+
+	dev_dbg(component->dev, "ReTune Mobile %s/%dHz for %dHz sample rate\n",
+		pdata->retune_mobile_cfgs[best].name,
+		pdata->retune_mobile_cfgs[best].rate,
+		wm8904->fs);
+
+	/* The EQ will be disabled while reconfiguring it, remember the
+	 * current configuration. 
+	 */
+	save = snd_soc_component_read32(component, WM8904_EQ1);
+
+	for (i = 0; i < WM8904_EQ_REGS; i++)
+		snd_soc_component_update_bits(component, WM8904_EQ1 + i, 0xffff,
+				pdata->retune_mobile_cfgs[best].regs[i]);
+
+	snd_soc_component_update_bits(component, WM8904_EQ1, WM8904_EQ_ENA, save);
+}
+
+static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	struct wm8904_pdata *pdata = wm8904->pdata;
+	int value = ucontrol->value.enumerated.item[0];
+
+	if (value >= pdata->num_retune_mobile_cfgs)
+		return -EINVAL;
+
+	wm8904->retune_mobile_cfg = value;
+
+	wm8904_set_retune_mobile(component);
+
+	return 0;
+}
+
+static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg;
+
+	return 0;
+}
+
+static int deemph_settings[] = { 0, 32000, 44100, 48000 };
+
+static int wm8904_set_deemph(struct snd_soc_component *component)
+{
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	int val, i, best;
+
+	/* If we're using deemphasis select the nearest available sample 
+	 * rate.
+	 */
+	if (wm8904->deemph) {
+		best = 1;
+		for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
+			if (abs(deemph_settings[i] - wm8904->fs) <
+			    abs(deemph_settings[best] - wm8904->fs))
+				best = i;
+		}
+
+		val = best << WM8904_DEEMPH_SHIFT;
+	} else {
+		val = 0;
+	}
+
+	dev_dbg(component->dev, "Set deemphasis %d\n", val);
+
+	return snd_soc_component_update_bits(component, WM8904_DAC_DIGITAL_1,
+				   WM8904_DEEMPH_MASK, val);
+}
+
+static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wm8904->deemph;
+	return 0;
+}
+
+static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	unsigned int deemph = ucontrol->value.integer.value[0];
+
+	if (deemph > 1)
+		return -EINVAL;
+
+	wm8904->deemph = deemph;
+
+	return wm8904_set_deemph(component);
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+
+static const char *input_mode_text[] = {
+	"Single-Ended", "Differential Line", "Differential Mic"
+};
+
+static SOC_ENUM_SINGLE_DECL(lin_mode,
+			    WM8904_ANALOGUE_LEFT_INPUT_1, 0,
+			    input_mode_text);
+
+static SOC_ENUM_SINGLE_DECL(rin_mode,
+			    WM8904_ANALOGUE_RIGHT_INPUT_1, 0,
+			    input_mode_text);
+
+static const char *hpf_mode_text[] = {
+	"Hi-fi", "Voice 1", "Voice 2", "Voice 3"
+};
+
+static SOC_ENUM_SINGLE_DECL(hpf_mode, WM8904_ADC_DIGITAL_0, 5,
+			    hpf_mode_text);
+
+static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int val;
+	int ret;
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+	if (ret < 0)
+		return ret;
+
+	if (ucontrol->value.integer.value[0])
+		val = 0;
+	else
+		val = WM8904_ADC_128_OSR_TST_MODE | WM8904_ADC_BIASX1P5;
+
+	snd_soc_component_update_bits(component, WM8904_ADC_TEST_0,
+			    WM8904_ADC_128_OSR_TST_MODE | WM8904_ADC_BIASX1P5,
+			    val);
+
+	return ret;
+}
+
+static const struct snd_kcontrol_new wm8904_adc_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8904_ADC_DIGITAL_VOLUME_LEFT,
+		 WM8904_ADC_DIGITAL_VOLUME_RIGHT, 1, 119, 0, digital_tlv),
+
+SOC_ENUM("Left Capture Mode", lin_mode),
+SOC_ENUM("Right Capture Mode", rin_mode),
+
+/* No TLV since it depends on mode */
+SOC_DOUBLE_R("Capture Volume", WM8904_ANALOGUE_LEFT_INPUT_0,
+	     WM8904_ANALOGUE_RIGHT_INPUT_0, 0, 31, 0),
+SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0,
+	     WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 1),
+
+SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0),
+SOC_ENUM("High Pass Filter Mode", hpf_mode),
+SOC_SINGLE_EXT("ADC 128x OSR Switch", WM8904_ANALOGUE_ADC_0, 0, 1, 0,
+	snd_soc_get_volsw, wm8904_adc_osr_put),
+};
+
+static const char *drc_path_text[] = {
+	"ADC", "DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_path, WM8904_DRC_0, 14, drc_path_text);
+
+static const struct snd_kcontrol_new wm8904_dac_snd_controls[] = {
+SOC_SINGLE_TLV("Digital Playback Boost Volume", 
+	       WM8904_AUDIO_INTERFACE_0, 9, 3, 0, dac_boost_tlv),
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8904_DAC_DIGITAL_VOLUME_LEFT,
+		 WM8904_DAC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Volume", WM8904_ANALOGUE_OUT1_LEFT,
+		 WM8904_ANALOGUE_OUT1_RIGHT, 0, 63, 0, out_tlv),
+SOC_DOUBLE_R("Headphone Switch", WM8904_ANALOGUE_OUT1_LEFT,
+	     WM8904_ANALOGUE_OUT1_RIGHT, 8, 1, 1),
+SOC_DOUBLE_R("Headphone ZC Switch", WM8904_ANALOGUE_OUT1_LEFT,
+	     WM8904_ANALOGUE_OUT1_RIGHT, 6, 1, 0),
+
+SOC_DOUBLE_R_TLV("Line Output Volume", WM8904_ANALOGUE_OUT2_LEFT,
+		 WM8904_ANALOGUE_OUT2_RIGHT, 0, 63, 0, out_tlv),
+SOC_DOUBLE_R("Line Output Switch", WM8904_ANALOGUE_OUT2_LEFT,
+	     WM8904_ANALOGUE_OUT2_RIGHT, 8, 1, 1),
+SOC_DOUBLE_R("Line Output ZC Switch", WM8904_ANALOGUE_OUT2_LEFT,
+	     WM8904_ANALOGUE_OUT2_RIGHT, 6, 1, 0),
+
+SOC_SINGLE("EQ Switch", WM8904_EQ1, 0, 1, 0),
+SOC_SINGLE("DRC Switch", WM8904_DRC_0, 15, 1, 0),
+SOC_ENUM("DRC Path", drc_path),
+SOC_SINGLE("DAC OSRx2 Switch", WM8904_DAC_DIGITAL_1, 6, 1, 0),
+SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
+		    wm8904_get_deemph, wm8904_put_deemph),
+};
+
+static const struct snd_kcontrol_new wm8904_snd_controls[] = {
+SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8904_DAC_DIGITAL_0, 4, 8, 15, 0,
+	       sidetone_tlv),
+};
+
+static const struct snd_kcontrol_new wm8904_eq_controls[] = {
+SOC_SINGLE_TLV("EQ1 Volume", WM8904_EQ2, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Volume", WM8904_EQ3, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Volume", WM8904_EQ4, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Volume", WM8904_EQ5, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ5 Volume", WM8904_EQ6, 0, 24, 0, eq_tlv),
+};
+
+static int cp_event(struct snd_soc_dapm_widget *w,
+		    struct snd_kcontrol *kcontrol, int event)
+{
+	if (WARN_ON(event != SND_SOC_DAPM_POST_PMU))
+		return -EINVAL;
+
+	/* Maximum startup time */
+	udelay(500);
+
+	return 0;
+}
+
+static int sysclk_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* If we're using the FLL then we only start it when
+		 * required; we assume that the configuration has been
+		 * done previously and all we need to do is kick it
+		 * off.
+		 */
+		switch (wm8904->sysclk_src) {
+		case WM8904_CLK_FLL:
+			snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
+					    WM8904_FLL_OSC_ENA,
+					    WM8904_FLL_OSC_ENA);
+
+			snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
+					    WM8904_FLL_ENA,
+					    WM8904_FLL_ENA);
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
+				    WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static int out_pga_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	int reg, val;
+	int dcs_mask;
+	int dcs_l, dcs_r;
+	int dcs_l_reg, dcs_r_reg;
+	int timeout;
+	int pwr_reg;
+
+	/* This code is shared between HP and LINEOUT; we do all our
+	 * power management in stereo pairs to avoid latency issues so
+	 * we reuse shift to identify which rather than strcmp() the
+	 * name. */
+	reg = w->shift;
+
+	switch (reg) {
+	case WM8904_ANALOGUE_HP_0:
+		pwr_reg = WM8904_POWER_MANAGEMENT_2;
+		dcs_mask = WM8904_DCS_ENA_CHAN_0 | WM8904_DCS_ENA_CHAN_1;
+		dcs_r_reg = WM8904_DC_SERVO_8;
+		dcs_l_reg = WM8904_DC_SERVO_9;
+		dcs_l = 0;
+		dcs_r = 1;
+		break;
+	case WM8904_ANALOGUE_LINEOUT_0:
+		pwr_reg = WM8904_POWER_MANAGEMENT_3;
+		dcs_mask = WM8904_DCS_ENA_CHAN_2 | WM8904_DCS_ENA_CHAN_3;
+		dcs_r_reg = WM8904_DC_SERVO_6;
+		dcs_l_reg = WM8904_DC_SERVO_7;
+		dcs_l = 2;
+		dcs_r = 3;
+		break;
+	default:
+		WARN(1, "Invalid reg %d\n", reg);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Power on the PGAs */
+		snd_soc_component_update_bits(component, pwr_reg,
+				    WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA,
+				    WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA);
+
+		/* Power on the amplifier */
+		snd_soc_component_update_bits(component, reg,
+				    WM8904_HPL_ENA | WM8904_HPR_ENA,
+				    WM8904_HPL_ENA | WM8904_HPR_ENA);
+
+
+		/* Enable the first stage */
+		snd_soc_component_update_bits(component, reg,
+				    WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY,
+				    WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY);
+
+		/* Power up the DC servo */
+		snd_soc_component_update_bits(component, WM8904_DC_SERVO_0,
+				    dcs_mask, dcs_mask);
+
+		/* Either calibrate the DC servo or restore cached state
+		 * if we have that.
+		 */
+		if (wm8904->dcs_state[dcs_l] || wm8904->dcs_state[dcs_r]) {
+			dev_dbg(component->dev, "Restoring DC servo state\n");
+
+			snd_soc_component_write(component, dcs_l_reg,
+				      wm8904->dcs_state[dcs_l]);
+			snd_soc_component_write(component, dcs_r_reg,
+				      wm8904->dcs_state[dcs_r]);
+
+			snd_soc_component_write(component, WM8904_DC_SERVO_1, dcs_mask);
+
+			timeout = 20;
+		} else {
+			dev_dbg(component->dev, "Calibrating DC servo\n");
+
+			snd_soc_component_write(component, WM8904_DC_SERVO_1,
+				dcs_mask << WM8904_DCS_TRIG_STARTUP_0_SHIFT);
+
+			timeout = 500;
+		}
+
+		/* Wait for DC servo to complete */
+		dcs_mask <<= WM8904_DCS_CAL_COMPLETE_SHIFT;
+		do {
+			val = snd_soc_component_read32(component, WM8904_DC_SERVO_READBACK_0);
+			if ((val & dcs_mask) == dcs_mask)
+				break;
+
+			msleep(1);
+		} while (--timeout);
+
+		if ((val & dcs_mask) != dcs_mask)
+			dev_warn(component->dev, "DC servo timed out\n");
+		else
+			dev_dbg(component->dev, "DC servo ready\n");
+
+		/* Enable the output stage */
+		snd_soc_component_update_bits(component, reg,
+				    WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP,
+				    WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP);
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		/* Unshort the output itself */
+		snd_soc_component_update_bits(component, reg,
+				    WM8904_HPL_RMV_SHORT |
+				    WM8904_HPR_RMV_SHORT,
+				    WM8904_HPL_RMV_SHORT |
+				    WM8904_HPR_RMV_SHORT);
+
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Short the output */
+		snd_soc_component_update_bits(component, reg,
+				    WM8904_HPL_RMV_SHORT |
+				    WM8904_HPR_RMV_SHORT, 0);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		/* Cache the DC servo configuration; this will be
+		 * invalidated if we change the configuration. */
+		wm8904->dcs_state[dcs_l] = snd_soc_component_read32(component, dcs_l_reg);
+		wm8904->dcs_state[dcs_r] = snd_soc_component_read32(component, dcs_r_reg);
+
+		snd_soc_component_update_bits(component, WM8904_DC_SERVO_0,
+				    dcs_mask, 0);
+
+		/* Disable the amplifier input and output stages */
+		snd_soc_component_update_bits(component, reg,
+				    WM8904_HPL_ENA | WM8904_HPR_ENA |
+				    WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY |
+				    WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP,
+				    0);
+
+		/* PGAs too */
+		snd_soc_component_update_bits(component, pwr_reg,
+				    WM8904_HPL_PGA_ENA | WM8904_HPR_PGA_ENA,
+				    0);
+		break;
+	}
+
+	return 0;
+}
+
+static const char *lin_text[] = {
+	"IN1L", "IN2L", "IN3L"
+};
+
+static SOC_ENUM_SINGLE_DECL(lin_enum, WM8904_ANALOGUE_LEFT_INPUT_1, 2,
+			    lin_text);
+
+static const struct snd_kcontrol_new lin_mux =
+	SOC_DAPM_ENUM("Left Capture Mux", lin_enum);
+
+static SOC_ENUM_SINGLE_DECL(lin_inv_enum, WM8904_ANALOGUE_LEFT_INPUT_1, 4,
+			    lin_text);
+
+static const struct snd_kcontrol_new lin_inv_mux =
+	SOC_DAPM_ENUM("Left Capture Inveting Mux", lin_inv_enum);
+
+static const char *rin_text[] = {
+	"IN1R", "IN2R", "IN3R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rin_enum, WM8904_ANALOGUE_RIGHT_INPUT_1, 2,
+			    rin_text);
+
+static const struct snd_kcontrol_new rin_mux =
+	SOC_DAPM_ENUM("Right Capture Mux", rin_enum);
+
+static SOC_ENUM_SINGLE_DECL(rin_inv_enum, WM8904_ANALOGUE_RIGHT_INPUT_1, 4,
+			    rin_text);
+
+static const struct snd_kcontrol_new rin_inv_mux =
+	SOC_DAPM_ENUM("Right Capture Inveting Mux", rin_inv_enum);
+
+static const char *aif_text[] = {
+	"Left", "Right"
+};
+
+static SOC_ENUM_SINGLE_DECL(aifoutl_enum, WM8904_AUDIO_INTERFACE_0, 7,
+			    aif_text);
+
+static const struct snd_kcontrol_new aifoutl_mux =
+	SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum);
+
+static SOC_ENUM_SINGLE_DECL(aifoutr_enum, WM8904_AUDIO_INTERFACE_0, 6,
+			    aif_text);
+
+static const struct snd_kcontrol_new aifoutr_mux =
+	SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum);
+
+static SOC_ENUM_SINGLE_DECL(aifinl_enum, WM8904_AUDIO_INTERFACE_0, 5,
+			    aif_text);
+
+static const struct snd_kcontrol_new aifinl_mux =
+	SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum);
+
+static SOC_ENUM_SINGLE_DECL(aifinr_enum, WM8904_AUDIO_INTERFACE_0, 4,
+			    aif_text);
+
+static const struct snd_kcontrol_new aifinr_mux =
+	SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum);
+
+static const struct snd_soc_dapm_widget wm8904_core_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM8904_CLOCK_RATES_2, 2, 0, sysclk_event,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8904_CLOCK_RATES_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TOCLK", WM8904_CLOCK_RATES_2, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8904_adc_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS", WM8904_MIC_BIAS_CONTROL_0, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("Left Capture Mux", SND_SOC_NOPM, 0, 0, &lin_mux),
+SND_SOC_DAPM_MUX("Left Capture Inverting Mux", SND_SOC_NOPM, 0, 0,
+		 &lin_inv_mux),
+SND_SOC_DAPM_MUX("Right Capture Mux", SND_SOC_NOPM, 0, 0, &rin_mux),
+SND_SOC_DAPM_MUX("Right Capture Inverting Mux", SND_SOC_NOPM, 0, 0,
+		 &rin_inv_mux),
+
+SND_SOC_DAPM_PGA("Left Capture PGA", WM8904_POWER_MANAGEMENT_0, 1, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("Right Capture PGA", WM8904_POWER_MANAGEMENT_0, 0, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_ADC("ADCL", NULL, WM8904_POWER_MANAGEMENT_6, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, WM8904_POWER_MANAGEMENT_6, 0, 0),
+
+SND_SOC_DAPM_MUX("AIFOUTL Mux", SND_SOC_NOPM, 0, 0, &aifoutl_mux),
+SND_SOC_DAPM_MUX("AIFOUTR Mux", SND_SOC_NOPM, 0, 0, &aifoutr_mux),
+
+SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8904_dac_dapm_widgets[] = {
+SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &aifinl_mux),
+SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &aifinr_mux),
+
+SND_SOC_DAPM_DAC("DACL", NULL, WM8904_POWER_MANAGEMENT_6, 3, 0),
+SND_SOC_DAPM_DAC("DACR", NULL, WM8904_POWER_MANAGEMENT_6, 2, 0),
+
+SND_SOC_DAPM_SUPPLY("Charge pump", WM8904_CHARGE_PUMP_0, 0, 0, cp_event,
+		    SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA("HPL PGA", SND_SOC_NOPM, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA("HPR PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("LINEL PGA", SND_SOC_NOPM, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA("LINER PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_E("Headphone Output", SND_SOC_NOPM, WM8904_ANALOGUE_HP_0,
+		   0, NULL, 0, out_pga_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_PGA_E("Line Output", SND_SOC_NOPM, WM8904_ANALOGUE_LINEOUT_0,
+		   0, NULL, 0, out_pga_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+SND_SOC_DAPM_OUTPUT("LINEOUTL"),
+SND_SOC_DAPM_OUTPUT("LINEOUTR"),
+};
+
+static const char *out_mux_text[] = {
+	"DAC", "Bypass"
+};
+
+static SOC_ENUM_SINGLE_DECL(hpl_enum, WM8904_ANALOGUE_OUT12_ZC, 3,
+			    out_mux_text);
+
+static const struct snd_kcontrol_new hpl_mux =
+	SOC_DAPM_ENUM("HPL Mux", hpl_enum);
+
+static SOC_ENUM_SINGLE_DECL(hpr_enum, WM8904_ANALOGUE_OUT12_ZC, 2,
+			    out_mux_text);
+
+static const struct snd_kcontrol_new hpr_mux =
+	SOC_DAPM_ENUM("HPR Mux", hpr_enum);
+
+static SOC_ENUM_SINGLE_DECL(linel_enum, WM8904_ANALOGUE_OUT12_ZC, 1,
+			    out_mux_text);
+
+static const struct snd_kcontrol_new linel_mux =
+	SOC_DAPM_ENUM("LINEL Mux", linel_enum);
+
+static SOC_ENUM_SINGLE_DECL(liner_enum, WM8904_ANALOGUE_OUT12_ZC, 0,
+			    out_mux_text);
+
+static const struct snd_kcontrol_new liner_mux =
+	SOC_DAPM_ENUM("LINER Mux", liner_enum);
+
+static const char *sidetone_text[] = {
+	"None", "Left", "Right"
+};
+
+static SOC_ENUM_SINGLE_DECL(dacl_sidetone_enum, WM8904_DAC_DIGITAL_0, 2,
+			    sidetone_text);
+
+static const struct snd_kcontrol_new dacl_sidetone_mux =
+	SOC_DAPM_ENUM("Left Sidetone Mux", dacl_sidetone_enum);
+
+static SOC_ENUM_SINGLE_DECL(dacr_sidetone_enum, WM8904_DAC_DIGITAL_0, 0,
+			    sidetone_text);
+
+static const struct snd_kcontrol_new dacr_sidetone_mux =
+	SOC_DAPM_ENUM("Right Sidetone Mux", dacr_sidetone_enum);
+
+static const struct snd_soc_dapm_widget wm8904_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("Class G", WM8904_CLASS_W_0, 0, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Left Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &dacl_sidetone_mux),
+SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &dacr_sidetone_mux),
+
+SND_SOC_DAPM_MUX("HPL Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
+SND_SOC_DAPM_MUX("HPR Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
+SND_SOC_DAPM_MUX("LINEL Mux", SND_SOC_NOPM, 0, 0, &linel_mux),
+SND_SOC_DAPM_MUX("LINER Mux", SND_SOC_NOPM, 0, 0, &liner_mux),
+};
+
+static const struct snd_soc_dapm_route core_intercon[] = {
+	{ "CLK_DSP", NULL, "SYSCLK" },
+	{ "TOCLK", NULL, "SYSCLK" },
+};
+
+static const struct snd_soc_dapm_route adc_intercon[] = {
+	{ "Left Capture Mux", "IN1L", "IN1L" },
+	{ "Left Capture Mux", "IN2L", "IN2L" },
+	{ "Left Capture Mux", "IN3L", "IN3L" },
+
+	{ "Left Capture Inverting Mux", "IN1L", "IN1L" },
+	{ "Left Capture Inverting Mux", "IN2L", "IN2L" },
+	{ "Left Capture Inverting Mux", "IN3L", "IN3L" },
+
+	{ "Right Capture Mux", "IN1R", "IN1R" },
+	{ "Right Capture Mux", "IN2R", "IN2R" },
+	{ "Right Capture Mux", "IN3R", "IN3R" },
+
+	{ "Right Capture Inverting Mux", "IN1R", "IN1R" },
+	{ "Right Capture Inverting Mux", "IN2R", "IN2R" },
+	{ "Right Capture Inverting Mux", "IN3R", "IN3R" },
+
+	{ "Left Capture PGA", NULL, "Left Capture Mux" },
+	{ "Left Capture PGA", NULL, "Left Capture Inverting Mux" },
+
+	{ "Right Capture PGA", NULL, "Right Capture Mux" },
+	{ "Right Capture PGA", NULL, "Right Capture Inverting Mux" },
+
+	{ "AIFOUTL Mux", "Left", "ADCL" },
+	{ "AIFOUTL Mux", "Right", "ADCR" },
+	{ "AIFOUTR Mux", "Left", "ADCL" },
+	{ "AIFOUTR Mux", "Right", "ADCR" },
+
+	{ "AIFOUTL", NULL, "AIFOUTL Mux" },
+	{ "AIFOUTR", NULL, "AIFOUTR Mux" },
+
+	{ "ADCL", NULL, "CLK_DSP" },
+	{ "ADCL", NULL, "Left Capture PGA" },
+
+	{ "ADCR", NULL, "CLK_DSP" },
+	{ "ADCR", NULL, "Right Capture PGA" },
+};
+
+static const struct snd_soc_dapm_route dac_intercon[] = {
+	{ "DACL Mux", "Left", "AIFINL" },
+	{ "DACL Mux", "Right", "AIFINR" },
+
+	{ "DACR Mux", "Left", "AIFINL" },
+	{ "DACR Mux", "Right", "AIFINR" },
+
+	{ "DACL", NULL, "DACL Mux" },
+	{ "DACL", NULL, "CLK_DSP" },
+
+	{ "DACR", NULL, "DACR Mux" },
+	{ "DACR", NULL, "CLK_DSP" },
+
+	{ "Charge pump", NULL, "SYSCLK" },
+
+	{ "Headphone Output", NULL, "HPL PGA" },
+	{ "Headphone Output", NULL, "HPR PGA" },
+	{ "Headphone Output", NULL, "Charge pump" },
+	{ "Headphone Output", NULL, "TOCLK" },
+
+	{ "Line Output", NULL, "LINEL PGA" },
+	{ "Line Output", NULL, "LINER PGA" },
+	{ "Line Output", NULL, "Charge pump" },
+	{ "Line Output", NULL, "TOCLK" },
+
+	{ "HPOUTL", NULL, "Headphone Output" },
+	{ "HPOUTR", NULL, "Headphone Output" },
+
+	{ "LINEOUTL", NULL, "Line Output" },
+	{ "LINEOUTR", NULL, "Line Output" },
+};
+
+static const struct snd_soc_dapm_route wm8904_intercon[] = {
+	{ "Left Sidetone", "Left", "ADCL" },
+	{ "Left Sidetone", "Right", "ADCR" },
+	{ "DACL", NULL, "Left Sidetone" },
+	
+	{ "Right Sidetone", "Left", "ADCL" },
+	{ "Right Sidetone", "Right", "ADCR" },
+	{ "DACR", NULL, "Right Sidetone" },
+
+	{ "Left Bypass", NULL, "Class G" },
+	{ "Left Bypass", NULL, "Left Capture PGA" },
+
+	{ "Right Bypass", NULL, "Class G" },
+	{ "Right Bypass", NULL, "Right Capture PGA" },
+
+	{ "HPL Mux", "DAC", "DACL" },
+	{ "HPL Mux", "Bypass", "Left Bypass" },
+
+	{ "HPR Mux", "DAC", "DACR" },
+	{ "HPR Mux", "Bypass", "Right Bypass" },
+
+	{ "LINEL Mux", "DAC", "DACL" },
+	{ "LINEL Mux", "Bypass", "Left Bypass" },
+
+	{ "LINER Mux", "DAC", "DACR" },
+	{ "LINER Mux", "Bypass", "Right Bypass" },
+
+	{ "HPL PGA", NULL, "HPL Mux" },
+	{ "HPR PGA", NULL, "HPR Mux" },
+
+	{ "LINEL PGA", NULL, "LINEL Mux" },
+	{ "LINER PGA", NULL, "LINER Mux" },
+};
+
+static const struct snd_soc_dapm_route wm8912_intercon[] = {
+	{ "HPL PGA", NULL, "DACL" },
+	{ "HPR PGA", NULL, "DACR" },
+
+	{ "LINEL PGA", NULL, "DACL" },
+	{ "LINER PGA", NULL, "DACR" },
+};
+
+static int wm8904_add_widgets(struct snd_soc_component *component)
+{
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_dapm_new_controls(dapm, wm8904_core_dapm_widgets,
+				  ARRAY_SIZE(wm8904_core_dapm_widgets));
+	snd_soc_dapm_add_routes(dapm, core_intercon,
+				ARRAY_SIZE(core_intercon));
+
+	switch (wm8904->devtype) {
+	case WM8904:
+		snd_soc_add_component_controls(component, wm8904_adc_snd_controls,
+				     ARRAY_SIZE(wm8904_adc_snd_controls));
+		snd_soc_add_component_controls(component, wm8904_dac_snd_controls,
+				     ARRAY_SIZE(wm8904_dac_snd_controls));
+		snd_soc_add_component_controls(component, wm8904_snd_controls,
+				     ARRAY_SIZE(wm8904_snd_controls));
+
+		snd_soc_dapm_new_controls(dapm, wm8904_adc_dapm_widgets,
+					  ARRAY_SIZE(wm8904_adc_dapm_widgets));
+		snd_soc_dapm_new_controls(dapm, wm8904_dac_dapm_widgets,
+					  ARRAY_SIZE(wm8904_dac_dapm_widgets));
+		snd_soc_dapm_new_controls(dapm, wm8904_dapm_widgets,
+					  ARRAY_SIZE(wm8904_dapm_widgets));
+
+		snd_soc_dapm_add_routes(dapm, adc_intercon,
+					ARRAY_SIZE(adc_intercon));
+		snd_soc_dapm_add_routes(dapm, dac_intercon,
+					ARRAY_SIZE(dac_intercon));
+		snd_soc_dapm_add_routes(dapm, wm8904_intercon,
+					ARRAY_SIZE(wm8904_intercon));
+		break;
+
+	case WM8912:
+		snd_soc_add_component_controls(component, wm8904_dac_snd_controls,
+				     ARRAY_SIZE(wm8904_dac_snd_controls));
+
+		snd_soc_dapm_new_controls(dapm, wm8904_dac_dapm_widgets,
+					  ARRAY_SIZE(wm8904_dac_dapm_widgets));
+
+		snd_soc_dapm_add_routes(dapm, dac_intercon,
+					ARRAY_SIZE(dac_intercon));
+		snd_soc_dapm_add_routes(dapm, wm8912_intercon,
+					ARRAY_SIZE(wm8912_intercon));
+		break;
+	}
+
+	return 0;
+}
+
+static struct {
+	int ratio;
+	unsigned int clk_sys_rate;
+} clk_sys_rates[] = {
+	{   64,  0 },
+	{  128,  1 },
+	{  192,  2 },
+	{  256,  3 },
+	{  384,  4 },
+	{  512,  5 },
+	{  786,  6 },
+	{ 1024,  7 },
+	{ 1408,  8 },
+	{ 1536,  9 },
+};
+
+static struct {
+	int rate;
+	int sample_rate;
+} sample_rates[] = {
+	{ 8000,  0  },
+	{ 11025, 1  },
+	{ 12000, 1  },
+	{ 16000, 2  },
+	{ 22050, 3  },
+	{ 24000, 3  },
+	{ 32000, 4  },
+	{ 44100, 5  },
+	{ 48000, 5  },
+};
+
+static struct {
+	int div; /* *10 due to .5s */
+	int bclk_div;
+} bclk_divs[] = {
+	{ 10,  0  },
+	{ 15,  1  },
+	{ 20,  2  },
+	{ 30,  3  },
+	{ 40,  4  },
+	{ 50,  5  },
+	{ 55,  6  },
+	{ 60,  7  },
+	{ 80,  8  },
+	{ 100, 9  },
+	{ 110, 10 },
+	{ 120, 11 },
+	{ 160, 12 },
+	{ 200, 13 },
+	{ 220, 14 },
+	{ 240, 16 },
+	{ 200, 17 },
+	{ 320, 18 },
+	{ 440, 19 },
+	{ 480, 20 },
+};
+
+
+static int wm8904_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	int ret, i, best, best_val, cur_val;
+	unsigned int aif1 = 0;
+	unsigned int aif2 = 0;
+	unsigned int aif3 = 0;
+	unsigned int clock1 = 0;
+	unsigned int dac_digital1 = 0;
+
+	/* What BCLK do we need? */
+	wm8904->fs = params_rate(params);
+	if (wm8904->tdm_slots) {
+		dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n",
+			wm8904->tdm_slots, wm8904->tdm_width);
+		wm8904->bclk = snd_soc_calc_bclk(wm8904->fs,
+						 wm8904->tdm_width, 2,
+						 wm8904->tdm_slots);
+	} else {
+		wm8904->bclk = snd_soc_params_to_bclk(params);
+	}
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		aif1 |= 0x40;
+		break;
+	case 24:
+		aif1 |= 0x80;
+		break;
+	case 32:
+		aif1 |= 0xc0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+
+	dev_dbg(component->dev, "Target BCLK is %dHz\n", wm8904->bclk);
+
+	ret = wm8904_configure_clocking(component);
+	if (ret != 0)
+		return ret;
+
+	/* Select nearest CLK_SYS_RATE */
+	best = 0;
+	best_val = abs((wm8904->sysclk_rate / clk_sys_rates[0].ratio)
+		       - wm8904->fs);
+	for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) {
+		cur_val = abs((wm8904->sysclk_rate /
+			       clk_sys_rates[i].ratio) - wm8904->fs);
+		if (cur_val < best_val) {
+			best = i;
+			best_val = cur_val;
+		}
+	}
+	dev_dbg(component->dev, "Selected CLK_SYS_RATIO of %d\n",
+		clk_sys_rates[best].ratio);
+	clock1 |= (clk_sys_rates[best].clk_sys_rate
+		   << WM8904_CLK_SYS_RATE_SHIFT);
+
+	/* SAMPLE_RATE */
+	best = 0;
+	best_val = abs(wm8904->fs - sample_rates[0].rate);
+	for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
+		/* Closest match */
+		cur_val = abs(wm8904->fs - sample_rates[i].rate);
+		if (cur_val < best_val) {
+			best = i;
+			best_val = cur_val;
+		}
+	}
+	dev_dbg(component->dev, "Selected SAMPLE_RATE of %dHz\n",
+		sample_rates[best].rate);
+	clock1 |= (sample_rates[best].sample_rate
+		   << WM8904_SAMPLE_RATE_SHIFT);
+
+	/* Enable sloping stopband filter for low sample rates */
+	if (wm8904->fs <= 24000)
+		dac_digital1 |= WM8904_DAC_SB_FILT;
+
+	/* BCLK_DIV */
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+		cur_val = ((wm8904->sysclk_rate * 10) / bclk_divs[i].div)
+			- wm8904->bclk;
+		if (cur_val < 0) /* Table is sorted */
+			break;
+		if (cur_val < best_val) {
+			best = i;
+			best_val = cur_val;
+		}
+	}
+	wm8904->bclk = (wm8904->sysclk_rate * 10) / bclk_divs[best].div;
+	dev_dbg(component->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
+		bclk_divs[best].div, wm8904->bclk);
+	aif2 |= bclk_divs[best].bclk_div;
+
+	/* LRCLK is a simple fraction of BCLK */
+	dev_dbg(component->dev, "LRCLK_RATE is %d\n", wm8904->bclk / wm8904->fs);
+	aif3 |= wm8904->bclk / wm8904->fs;
+
+	/* Apply the settings */
+	snd_soc_component_update_bits(component, WM8904_DAC_DIGITAL_1,
+			    WM8904_DAC_SB_FILT, dac_digital1);
+	snd_soc_component_update_bits(component, WM8904_AUDIO_INTERFACE_1,
+			    WM8904_AIF_WL_MASK, aif1);
+	snd_soc_component_update_bits(component, WM8904_AUDIO_INTERFACE_2,
+			    WM8904_BCLK_DIV_MASK, aif2);
+	snd_soc_component_update_bits(component, WM8904_AUDIO_INTERFACE_3,
+			    WM8904_LRCLK_RATE_MASK, aif3);
+	snd_soc_component_update_bits(component, WM8904_CLOCK_RATES_1,
+			    WM8904_SAMPLE_RATE_MASK |
+			    WM8904_CLK_SYS_RATE_MASK, clock1);
+
+	/* Update filters for the new settings */
+	wm8904_set_retune_mobile(component);
+	wm8904_set_deemph(component);
+
+	return 0;
+}
+
+
+static int wm8904_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+			     unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8904_priv *priv = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case WM8904_CLK_MCLK:
+		priv->sysclk_src = clk_id;
+		priv->mclk_rate = freq;
+		break;
+
+	case WM8904_CLK_FLL:
+		priv->sysclk_src = clk_id;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+	wm8904_configure_clocking(component);
+
+	return 0;
+}
+
+static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	unsigned int aif1 = 0;
+	unsigned int aif3 = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		aif3 |= WM8904_LRCLK_DIR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		aif1 |= WM8904_BCLK_DIR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif1 |= WM8904_BCLK_DIR;
+		aif3 |= WM8904_LRCLK_DIR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_B:
+		aif1 |= 0x3 | WM8904_AIF_LRCLK_INV;
+		/* fall through */
+	case SND_SOC_DAIFMT_DSP_A:
+		aif1 |= 0x3;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aif1 |= 0x2;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif1 |= 0x1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		/* frame inversion not valid for DSP modes */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif1 |= WM8904_AIF_BCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			aif1 |= WM8904_AIF_BCLK_INV | WM8904_AIF_LRCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif1 |= WM8904_AIF_BCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			aif1 |= WM8904_AIF_LRCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8904_AUDIO_INTERFACE_1,
+			    WM8904_AIF_BCLK_INV | WM8904_AIF_LRCLK_INV |
+			    WM8904_AIF_FMT_MASK | WM8904_BCLK_DIR, aif1);
+	snd_soc_component_update_bits(component, WM8904_AUDIO_INTERFACE_3,
+			    WM8904_LRCLK_DIR, aif3);
+
+	return 0;
+}
+
+
+static int wm8904_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			       unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	int aif1 = 0;
+
+	/* Don't need to validate anything if we're turning off TDM */
+	if (slots == 0)
+		goto out;
+
+	/* Note that we allow configurations we can't handle ourselves - 
+	 * for example, we can generate clocks for slots 2 and up even if
+	 * we can't use those slots ourselves.
+	 */
+	aif1 |= WM8904_AIFADC_TDM | WM8904_AIFDAC_TDM;
+
+	switch (rx_mask) {
+	case 3:
+		break;
+	case 0xc:
+		aif1 |= WM8904_AIFADC_TDM_CHAN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+
+	switch (tx_mask) {
+	case 3:
+		break;
+	case 0xc:
+		aif1 |= WM8904_AIFDAC_TDM_CHAN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+out:
+	wm8904->tdm_width = slot_width;
+	wm8904->tdm_slots = slots / 2;
+
+	snd_soc_component_update_bits(component, WM8904_AUDIO_INTERFACE_1,
+			    WM8904_AIFADC_TDM | WM8904_AIFADC_TDM_CHAN |
+			    WM8904_AIFDAC_TDM | WM8904_AIFDAC_TDM_CHAN, aif1);
+
+	return 0;
+}
+
+struct _fll_div {
+	u16 fll_fratio;
+	u16 fll_outdiv;
+	u16 fll_clk_ref_div;
+	u16 n;
+	u16 k;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static struct {
+	unsigned int min;
+	unsigned int max;
+	u16 fll_fratio;
+	int ratio;
+} fll_fratios[] = {
+	{       0,    64000, 4, 16 },
+	{   64000,   128000, 3,  8 },
+	{  128000,   256000, 2,  4 },
+	{  256000,  1000000, 1,  2 },
+	{ 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+		       unsigned int Fout)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod, target;
+	unsigned int div;
+	int i;
+
+	/* Fref must be <=13.5MHz */
+	div = 1;
+	fll_div->fll_clk_ref_div = 0;
+	while ((Fref / div) > 13500000) {
+		div *= 2;
+		fll_div->fll_clk_ref_div++;
+
+		if (div > 8) {
+			pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+			       Fref);
+			return -EINVAL;
+		}
+	}
+
+	pr_debug("Fref=%u Fout=%u\n", Fref, Fout);
+
+	/* Apply the division for our remaining calculations */
+	Fref /= div;
+
+	/* Fvco should be 90-100MHz; don't check the upper bound */
+	div = 4;
+	while (Fout * div < 90000000) {
+		div++;
+		if (div > 64) {
+			pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+			       Fout);
+			return -EINVAL;
+		}
+	}
+	target = Fout * div;
+	fll_div->fll_outdiv = div - 1;
+
+	pr_debug("Fvco=%dHz\n", target);
+
+	/* Find an appropriate FLL_FRATIO and factor it out of the target */
+	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+			fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+			target /= fll_fratios[i].ratio;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(fll_fratios)) {
+		pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+		return -EINVAL;
+	}
+
+	/* Now, calculate N.K */
+	Ndiv = target / Fref;
+
+	fll_div->n = Ndiv;
+	Nmod = target % Fref;
+	pr_debug("Nmod=%d\n", Nmod);
+
+	/* Calculate fractional part - scale up so we can round. */
+	Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, Fref);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	fll_div->k = K / 10;
+
+	pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n",
+		 fll_div->n, fll_div->k,
+		 fll_div->fll_fratio, fll_div->fll_outdiv,
+		 fll_div->fll_clk_ref_div);
+
+	return 0;
+}
+
+static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	struct _fll_div fll_div;
+	int ret, val;
+	int clock2, fll1;
+
+	/* Any change? */
+	if (source == wm8904->fll_src && Fref == wm8904->fll_fref &&
+	    Fout == wm8904->fll_fout)
+		return 0;
+
+	clock2 = snd_soc_component_read32(component, WM8904_CLOCK_RATES_2);
+
+	if (Fout == 0) {
+		dev_dbg(component->dev, "FLL disabled\n");
+
+		wm8904->fll_fref = 0;
+		wm8904->fll_fout = 0;
+
+		/* Gate SYSCLK to avoid glitches */
+		snd_soc_component_update_bits(component, WM8904_CLOCK_RATES_2,
+				    WM8904_CLK_SYS_ENA, 0);
+
+		snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
+				    WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
+
+		goto out;
+	}
+
+	/* Validate the FLL ID */
+	switch (source) {
+	case WM8904_FLL_MCLK:
+	case WM8904_FLL_LRCLK:
+	case WM8904_FLL_BCLK:
+		ret = fll_factors(&fll_div, Fref, Fout);
+		if (ret != 0)
+			return ret;
+		break;
+
+	case WM8904_FLL_FREE_RUNNING:
+		dev_dbg(component->dev, "Using free running FLL\n");
+		/* Force 12MHz and output/4 for now */
+		Fout = 12000000;
+		Fref = 12000000;
+
+		memset(&fll_div, 0, sizeof(fll_div));
+		fll_div.fll_outdiv = 3;
+		break;
+
+	default:
+		dev_err(component->dev, "Unknown FLL ID %d\n", fll_id);
+		return -EINVAL;
+	}
+
+	/* Save current state then disable the FLL and SYSCLK to avoid
+	 * misclocking */
+	fll1 = snd_soc_component_read32(component, WM8904_FLL_CONTROL_1);
+	snd_soc_component_update_bits(component, WM8904_CLOCK_RATES_2,
+			    WM8904_CLK_SYS_ENA, 0);
+	snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
+			    WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
+
+	/* Unlock forced oscilator control to switch it on/off */
+	snd_soc_component_update_bits(component, WM8904_CONTROL_INTERFACE_TEST_1,
+			    WM8904_USER_KEY, WM8904_USER_KEY);
+
+	if (fll_id == WM8904_FLL_FREE_RUNNING) {
+		val = WM8904_FLL_FRC_NCO;
+	} else {
+		val = 0;
+	}
+
+	snd_soc_component_update_bits(component, WM8904_FLL_NCO_TEST_1, WM8904_FLL_FRC_NCO,
+			    val);
+	snd_soc_component_update_bits(component, WM8904_CONTROL_INTERFACE_TEST_1,
+			    WM8904_USER_KEY, 0);
+
+	switch (fll_id) {
+	case WM8904_FLL_MCLK:
+		snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_5,
+				    WM8904_FLL_CLK_REF_SRC_MASK, 0);
+		break;
+
+	case WM8904_FLL_LRCLK:
+		snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_5,
+				    WM8904_FLL_CLK_REF_SRC_MASK, 1);
+		break;
+
+	case WM8904_FLL_BCLK:
+		snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_5,
+				    WM8904_FLL_CLK_REF_SRC_MASK, 2);
+		break;
+	}
+
+	if (fll_div.k)
+		val = WM8904_FLL_FRACN_ENA;
+	else
+		val = 0;
+	snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
+			    WM8904_FLL_FRACN_ENA, val);
+
+	snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_2,
+			    WM8904_FLL_OUTDIV_MASK | WM8904_FLL_FRATIO_MASK,
+			    (fll_div.fll_outdiv << WM8904_FLL_OUTDIV_SHIFT) |
+			    (fll_div.fll_fratio << WM8904_FLL_FRATIO_SHIFT));
+
+	snd_soc_component_write(component, WM8904_FLL_CONTROL_3, fll_div.k);
+
+	snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_4, WM8904_FLL_N_MASK,
+			    fll_div.n << WM8904_FLL_N_SHIFT);
+
+	snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_5,
+			    WM8904_FLL_CLK_REF_DIV_MASK,
+			    fll_div.fll_clk_ref_div 
+			    << WM8904_FLL_CLK_REF_DIV_SHIFT);
+
+	dev_dbg(component->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+
+	wm8904->fll_fref = Fref;
+	wm8904->fll_fout = Fout;
+	wm8904->fll_src = source;
+
+	/* Enable the FLL if it was previously active */
+	snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
+			    WM8904_FLL_OSC_ENA, fll1);
+	snd_soc_component_update_bits(component, WM8904_FLL_CONTROL_1,
+			    WM8904_FLL_ENA, fll1);
+
+out:
+	/* Reenable SYSCLK if it was previously active */
+	snd_soc_component_update_bits(component, WM8904_CLOCK_RATES_2,
+			    WM8904_CLK_SYS_ENA, clock2);
+
+	return 0;
+}
+
+static int wm8904_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	int val;
+
+	if (mute)
+		val = WM8904_DAC_MUTE;
+	else
+		val = 0;
+
+	snd_soc_component_update_bits(component, WM8904_DAC_DIGITAL_1, WM8904_DAC_MUTE, val);
+
+	return 0;
+}
+
+static int wm8904_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		ret = clk_prepare_enable(wm8904->mclk);
+		if (ret)
+			return ret;
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* VMID resistance 2*50k */
+		snd_soc_component_update_bits(component, WM8904_VMID_CONTROL_0,
+				    WM8904_VMID_RES_MASK,
+				    0x1 << WM8904_VMID_RES_SHIFT);
+
+		/* Normal bias current */
+		snd_soc_component_update_bits(component, WM8904_BIAS_CONTROL_0,
+				    WM8904_ISEL_MASK, 2 << WM8904_ISEL_SHIFT);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
+						    wm8904->supplies);
+			if (ret != 0) {
+				dev_err(component->dev,
+					"Failed to enable supplies: %d\n",
+					ret);
+				return ret;
+			}
+
+			regcache_cache_only(wm8904->regmap, false);
+			regcache_sync(wm8904->regmap);
+
+			/* Enable bias */
+			snd_soc_component_update_bits(component, WM8904_BIAS_CONTROL_0,
+					    WM8904_BIAS_ENA, WM8904_BIAS_ENA);
+
+			/* Enable VMID, VMID buffering, 2*5k resistance */
+			snd_soc_component_update_bits(component, WM8904_VMID_CONTROL_0,
+					    WM8904_VMID_ENA |
+					    WM8904_VMID_RES_MASK,
+					    WM8904_VMID_ENA |
+					    0x3 << WM8904_VMID_RES_SHIFT);
+
+			/* Let VMID ramp */
+			msleep(1);
+		}
+
+		/* Maintain VMID with 2*250k */
+		snd_soc_component_update_bits(component, WM8904_VMID_CONTROL_0,
+				    WM8904_VMID_RES_MASK,
+				    0x2 << WM8904_VMID_RES_SHIFT);
+
+		/* Bias current *0.5 */
+		snd_soc_component_update_bits(component, WM8904_BIAS_CONTROL_0,
+				    WM8904_ISEL_MASK, 0);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* Turn off VMID */
+		snd_soc_component_update_bits(component, WM8904_VMID_CONTROL_0,
+				    WM8904_VMID_RES_MASK | WM8904_VMID_ENA, 0);
+
+		/* Stop bias generation */
+		snd_soc_component_update_bits(component, WM8904_BIAS_CONTROL_0,
+				    WM8904_BIAS_ENA, 0);
+
+		regcache_cache_only(wm8904->regmap, true);
+		regcache_mark_dirty(wm8904->regmap);
+
+		regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies),
+				       wm8904->supplies);
+		clk_disable_unprepare(wm8904->mclk);
+		break;
+	}
+	return 0;
+}
+
+#define WM8904_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8904_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8904_dai_ops = {
+	.set_sysclk = wm8904_set_sysclk,
+	.set_fmt = wm8904_set_fmt,
+	.set_tdm_slot = wm8904_set_tdm_slot,
+	.set_pll = wm8904_set_fll,
+	.hw_params = wm8904_hw_params,
+	.digital_mute = wm8904_digital_mute,
+};
+
+static struct snd_soc_dai_driver wm8904_dai = {
+	.name = "wm8904-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM8904_RATES,
+		.formats = WM8904_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM8904_RATES,
+		.formats = WM8904_FORMATS,
+	},
+	.ops = &wm8904_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static void wm8904_handle_retune_mobile_pdata(struct snd_soc_component *component)
+{
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	struct wm8904_pdata *pdata = wm8904->pdata;
+	struct snd_kcontrol_new control =
+		SOC_ENUM_EXT("EQ Mode",
+			     wm8904->retune_mobile_enum,
+			     wm8904_get_retune_mobile_enum,
+			     wm8904_put_retune_mobile_enum);
+	int ret, i, j;
+	const char **t;
+
+	/* We need an array of texts for the enum API but the number
+	 * of texts is likely to be less than the number of
+	 * configurations due to the sample rate dependency of the
+	 * configurations. */
+	wm8904->num_retune_mobile_texts = 0;
+	wm8904->retune_mobile_texts = NULL;
+	for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+		for (j = 0; j < wm8904->num_retune_mobile_texts; j++) {
+			if (strcmp(pdata->retune_mobile_cfgs[i].name,
+				   wm8904->retune_mobile_texts[j]) == 0)
+				break;
+		}
+
+		if (j != wm8904->num_retune_mobile_texts)
+			continue;
+
+		/* Expand the array... */
+		t = krealloc(wm8904->retune_mobile_texts,
+			     sizeof(char *) * 
+			     (wm8904->num_retune_mobile_texts + 1),
+			     GFP_KERNEL);
+		if (t == NULL)
+			continue;
+
+		/* ...store the new entry... */
+		t[wm8904->num_retune_mobile_texts] = 
+			pdata->retune_mobile_cfgs[i].name;
+
+		/* ...and remember the new version. */
+		wm8904->num_retune_mobile_texts++;
+		wm8904->retune_mobile_texts = t;
+	}
+
+	dev_dbg(component->dev, "Allocated %d unique ReTune Mobile names\n",
+		wm8904->num_retune_mobile_texts);
+
+	wm8904->retune_mobile_enum.items = wm8904->num_retune_mobile_texts;
+	wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts;
+
+	ret = snd_soc_add_component_controls(component, &control, 1);
+	if (ret != 0)
+		dev_err(component->dev,
+			"Failed to add ReTune Mobile control: %d\n", ret);
+}
+
+static void wm8904_handle_pdata(struct snd_soc_component *component)
+{
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+	struct wm8904_pdata *pdata = wm8904->pdata;
+	int ret, i;
+
+	if (!pdata) {
+		snd_soc_add_component_controls(component, wm8904_eq_controls,
+				     ARRAY_SIZE(wm8904_eq_controls));
+		return;
+	}
+
+	dev_dbg(component->dev, "%d DRC configurations\n", pdata->num_drc_cfgs);
+
+	if (pdata->num_drc_cfgs) {
+		struct snd_kcontrol_new control =
+			SOC_ENUM_EXT("DRC Mode", wm8904->drc_enum,
+				     wm8904_get_drc_enum, wm8904_put_drc_enum);
+
+		/* We need an array of texts for the enum API */
+		wm8904->drc_texts = kmalloc_array(pdata->num_drc_cfgs,
+						  sizeof(char *),
+						  GFP_KERNEL);
+		if (!wm8904->drc_texts)
+			return;
+
+		for (i = 0; i < pdata->num_drc_cfgs; i++)
+			wm8904->drc_texts[i] = pdata->drc_cfgs[i].name;
+
+		wm8904->drc_enum.items = pdata->num_drc_cfgs;
+		wm8904->drc_enum.texts = wm8904->drc_texts;
+
+		ret = snd_soc_add_component_controls(component, &control, 1);
+		if (ret != 0)
+			dev_err(component->dev,
+				"Failed to add DRC mode control: %d\n", ret);
+
+		wm8904_set_drc(component);
+	}
+
+	dev_dbg(component->dev, "%d ReTune Mobile configurations\n",
+		pdata->num_retune_mobile_cfgs);
+
+	if (pdata->num_retune_mobile_cfgs)
+		wm8904_handle_retune_mobile_pdata(component);
+	else
+		snd_soc_add_component_controls(component, wm8904_eq_controls,
+				     ARRAY_SIZE(wm8904_eq_controls));
+}
+
+
+static int wm8904_probe(struct snd_soc_component *component)
+{
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+
+	switch (wm8904->devtype) {
+	case WM8904:
+		break;
+	case WM8912:
+		memset(&wm8904_dai.capture, 0, sizeof(wm8904_dai.capture));
+		break;
+	default:
+		dev_err(component->dev, "Unknown device type %d\n",
+			wm8904->devtype);
+		return -EINVAL;
+	}
+
+	wm8904_handle_pdata(component);
+
+	wm8904_add_widgets(component);
+
+	return 0;
+}
+
+static void wm8904_remove(struct snd_soc_component *component)
+{
+	struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+
+	kfree(wm8904->retune_mobile_texts);
+	kfree(wm8904->drc_texts);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8904 = {
+	.probe			= wm8904_probe,
+	.remove			= wm8904_remove,
+	.set_bias_level		= wm8904_set_bias_level,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8904_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = WM8904_MAX_REGISTER,
+	.volatile_reg = wm8904_volatile_register,
+	.readable_reg = wm8904_readable_register,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8904_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8904_reg_defaults),
+};
+
+#ifdef CONFIG_OF
+static enum wm8904_type wm8904_data = WM8904;
+static enum wm8904_type wm8912_data = WM8912;
+
+static const struct of_device_id wm8904_of_match[] = {
+	{
+		.compatible = "wlf,wm8904",
+		.data = &wm8904_data,
+	}, {
+		.compatible = "wlf,wm8912",
+		.data = &wm8912_data,
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(of, wm8904_of_match);
+#endif
+
+static int wm8904_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8904_priv *wm8904;
+	unsigned int val;
+	int ret, i;
+
+	wm8904 = devm_kzalloc(&i2c->dev, sizeof(struct wm8904_priv),
+			      GFP_KERNEL);
+	if (wm8904 == NULL)
+		return -ENOMEM;
+
+	wm8904->mclk = devm_clk_get(&i2c->dev, "mclk");
+	if (IS_ERR(wm8904->mclk)) {
+		ret = PTR_ERR(wm8904->mclk);
+		dev_err(&i2c->dev, "Failed to get MCLK\n");
+		return ret;
+	}
+
+	wm8904->regmap = devm_regmap_init_i2c(i2c, &wm8904_regmap);
+	if (IS_ERR(wm8904->regmap)) {
+		ret = PTR_ERR(wm8904->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (i2c->dev.of_node) {
+		const struct of_device_id *match;
+
+		match = of_match_node(wm8904_of_match, i2c->dev.of_node);
+		if (match == NULL)
+			return -EINVAL;
+		wm8904->devtype = *((enum wm8904_type *)match->data);
+	} else {
+		wm8904->devtype = id->driver_data;
+	}
+
+	i2c_set_clientdata(i2c, wm8904);
+	wm8904->pdata = i2c->dev.platform_data;
+
+	for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++)
+		wm8904->supplies[i].supply = wm8904_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8904->supplies),
+				      wm8904->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
+				    wm8904->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(wm8904->regmap, WM8904_SW_RESET_AND_ID, &val);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
+		goto err_enable;
+	}
+	if (val != 0x8904) {
+		dev_err(&i2c->dev, "Device is not a WM8904, ID is %x\n", val);
+		ret = -EINVAL;
+		goto err_enable;
+	}
+
+	ret = regmap_read(wm8904->regmap, WM8904_REVISION, &val);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read device revision: %d\n",
+			ret);
+		goto err_enable;
+	}
+	dev_info(&i2c->dev, "revision %c\n", val + 'A');
+
+	ret = regmap_write(wm8904->regmap, WM8904_SW_RESET_AND_ID, 0);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
+		goto err_enable;
+	}
+
+	/* Change some default settings - latch VU and enable ZC */
+	regmap_update_bits(wm8904->regmap, WM8904_ADC_DIGITAL_VOLUME_LEFT,
+			   WM8904_ADC_VU, WM8904_ADC_VU);
+	regmap_update_bits(wm8904->regmap, WM8904_ADC_DIGITAL_VOLUME_RIGHT,
+			   WM8904_ADC_VU, WM8904_ADC_VU);
+	regmap_update_bits(wm8904->regmap, WM8904_DAC_DIGITAL_VOLUME_LEFT,
+			   WM8904_DAC_VU, WM8904_DAC_VU);
+	regmap_update_bits(wm8904->regmap, WM8904_DAC_DIGITAL_VOLUME_RIGHT,
+			   WM8904_DAC_VU, WM8904_DAC_VU);
+	regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT1_LEFT,
+			   WM8904_HPOUT_VU | WM8904_HPOUTLZC,
+			   WM8904_HPOUT_VU | WM8904_HPOUTLZC);
+	regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT1_RIGHT,
+			   WM8904_HPOUT_VU | WM8904_HPOUTRZC,
+			   WM8904_HPOUT_VU | WM8904_HPOUTRZC);
+	regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT2_LEFT,
+			   WM8904_LINEOUT_VU | WM8904_LINEOUTLZC,
+			   WM8904_LINEOUT_VU | WM8904_LINEOUTLZC);
+	regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT2_RIGHT,
+			   WM8904_LINEOUT_VU | WM8904_LINEOUTRZC,
+			   WM8904_LINEOUT_VU | WM8904_LINEOUTRZC);
+	regmap_update_bits(wm8904->regmap, WM8904_CLOCK_RATES_0,
+			   WM8904_SR_MODE, 0);
+
+	/* Apply configuration from the platform data. */
+	if (wm8904->pdata) {
+		for (i = 0; i < WM8904_GPIO_REGS; i++) {
+			if (!wm8904->pdata->gpio_cfg[i])
+				continue;
+
+			regmap_update_bits(wm8904->regmap,
+					   WM8904_GPIO_CONTROL_1 + i,
+					   0xffff,
+					   wm8904->pdata->gpio_cfg[i]);
+		}
+
+		/* Zero is the default value for these anyway */
+		for (i = 0; i < WM8904_MIC_REGS; i++)
+			regmap_update_bits(wm8904->regmap,
+					   WM8904_MIC_BIAS_CONTROL_0 + i,
+					   0xffff,
+					   wm8904->pdata->mic_cfg[i]);
+	}
+
+	/* Set Class W by default - this will be managed by the Class
+	 * G widget at runtime where bypass paths are available.
+	 */
+	regmap_update_bits(wm8904->regmap, WM8904_CLASS_W_0,
+			    WM8904_CP_DYN_PWR, WM8904_CP_DYN_PWR);
+
+	/* Use normal bias source */
+	regmap_update_bits(wm8904->regmap, WM8904_BIAS_CONTROL_0,
+			    WM8904_POBCTRL, 0);
+
+	/* Can leave the device powered off until we need it */
+	regcache_cache_only(wm8904->regmap, true);
+	regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8904, &wm8904_dai, 1);
+	if (ret != 0)
+		return ret;
+
+	return 0;
+
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
+	return ret;
+}
+
+static const struct i2c_device_id wm8904_i2c_id[] = {
+	{ "wm8904", WM8904 },
+	{ "wm8912", WM8912 },
+	{ "wm8918", WM8904 },   /* Actually a subset, updates to follow */
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id);
+
+static struct i2c_driver wm8904_i2c_driver = {
+	.driver = {
+		.name = "wm8904",
+		.of_match_table = of_match_ptr(wm8904_of_match),
+	},
+	.probe =    wm8904_i2c_probe,
+	.id_table = wm8904_i2c_id,
+};
+
+module_i2c_driver(wm8904_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8904 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8904.h b/sound/soc/codecs/wm8904.h
new file mode 100644
index 0000000..c29a0e8
--- /dev/null
+++ b/sound/soc/codecs/wm8904.h
@@ -0,0 +1,1592 @@
+/*
+ * wm8904.h  --  WM8904 ASoC driver
+ *
+ * Copyright 2009 Wolfson Microelectronics, plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8904_H
+#define _WM8904_H
+
+#define WM8904_CLK_MCLK 1
+#define WM8904_CLK_FLL  2
+
+#define WM8904_FLL_MCLK          1
+#define WM8904_FLL_BCLK          2
+#define WM8904_FLL_LRCLK         3
+#define WM8904_FLL_FREE_RUNNING  4
+
+/*
+ * Register values.
+ */
+#define WM8904_SW_RESET_AND_ID                  0x00
+#define WM8904_REVISION				0x01
+#define WM8904_BIAS_CONTROL_0                   0x04
+#define WM8904_VMID_CONTROL_0                   0x05
+#define WM8904_MIC_BIAS_CONTROL_0               0x06
+#define WM8904_MIC_BIAS_CONTROL_1               0x07
+#define WM8904_ANALOGUE_DAC_0                   0x08
+#define WM8904_MIC_FILTER_CONTROL               0x09
+#define WM8904_ANALOGUE_ADC_0                   0x0A
+#define WM8904_POWER_MANAGEMENT_0               0x0C
+#define WM8904_POWER_MANAGEMENT_2               0x0E
+#define WM8904_POWER_MANAGEMENT_3               0x0F
+#define WM8904_POWER_MANAGEMENT_6               0x12
+#define WM8904_CLOCK_RATES_0                    0x14
+#define WM8904_CLOCK_RATES_1                    0x15
+#define WM8904_CLOCK_RATES_2                    0x16
+#define WM8904_AUDIO_INTERFACE_0                0x18
+#define WM8904_AUDIO_INTERFACE_1                0x19
+#define WM8904_AUDIO_INTERFACE_2                0x1A
+#define WM8904_AUDIO_INTERFACE_3                0x1B
+#define WM8904_DAC_DIGITAL_VOLUME_LEFT          0x1E
+#define WM8904_DAC_DIGITAL_VOLUME_RIGHT         0x1F
+#define WM8904_DAC_DIGITAL_0                    0x20
+#define WM8904_DAC_DIGITAL_1                    0x21
+#define WM8904_ADC_DIGITAL_VOLUME_LEFT          0x24
+#define WM8904_ADC_DIGITAL_VOLUME_RIGHT         0x25
+#define WM8904_ADC_DIGITAL_0                    0x26
+#define WM8904_DIGITAL_MICROPHONE_0             0x27
+#define WM8904_DRC_0                            0x28
+#define WM8904_DRC_1                            0x29
+#define WM8904_DRC_2                            0x2A
+#define WM8904_DRC_3                            0x2B
+#define WM8904_ANALOGUE_LEFT_INPUT_0            0x2C
+#define WM8904_ANALOGUE_RIGHT_INPUT_0           0x2D
+#define WM8904_ANALOGUE_LEFT_INPUT_1            0x2E
+#define WM8904_ANALOGUE_RIGHT_INPUT_1           0x2F
+#define WM8904_ANALOGUE_OUT1_LEFT               0x39
+#define WM8904_ANALOGUE_OUT1_RIGHT              0x3A
+#define WM8904_ANALOGUE_OUT2_LEFT               0x3B
+#define WM8904_ANALOGUE_OUT2_RIGHT              0x3C
+#define WM8904_ANALOGUE_OUT12_ZC                0x3D
+#define WM8904_DC_SERVO_0                       0x43
+#define WM8904_DC_SERVO_1                       0x44
+#define WM8904_DC_SERVO_2                       0x45
+#define WM8904_DC_SERVO_4                       0x47
+#define WM8904_DC_SERVO_5                       0x48
+#define WM8904_DC_SERVO_6                       0x49
+#define WM8904_DC_SERVO_7                       0x4A
+#define WM8904_DC_SERVO_8                       0x4B
+#define WM8904_DC_SERVO_9                       0x4C
+#define WM8904_DC_SERVO_READBACK_0              0x4D
+#define WM8904_ANALOGUE_HP_0                    0x5A
+#define WM8904_ANALOGUE_LINEOUT_0               0x5E
+#define WM8904_CHARGE_PUMP_0                    0x62
+#define WM8904_CLASS_W_0                        0x68
+#define WM8904_WRITE_SEQUENCER_0                0x6C
+#define WM8904_WRITE_SEQUENCER_1                0x6D
+#define WM8904_WRITE_SEQUENCER_2                0x6E
+#define WM8904_WRITE_SEQUENCER_3                0x6F
+#define WM8904_WRITE_SEQUENCER_4                0x70
+#define WM8904_FLL_CONTROL_1                    0x74
+#define WM8904_FLL_CONTROL_2                    0x75
+#define WM8904_FLL_CONTROL_3                    0x76
+#define WM8904_FLL_CONTROL_4                    0x77
+#define WM8904_FLL_CONTROL_5                    0x78
+#define WM8904_GPIO_CONTROL_1                   0x79
+#define WM8904_GPIO_CONTROL_2                   0x7A
+#define WM8904_GPIO_CONTROL_3                   0x7B
+#define WM8904_GPIO_CONTROL_4                   0x7C
+#define WM8904_DIGITAL_PULLS                    0x7E
+#define WM8904_INTERRUPT_STATUS                 0x7F
+#define WM8904_INTERRUPT_STATUS_MASK            0x80
+#define WM8904_INTERRUPT_POLARITY               0x81
+#define WM8904_INTERRUPT_DEBOUNCE               0x82
+#define WM8904_EQ1                              0x86
+#define WM8904_EQ2                              0x87
+#define WM8904_EQ3                              0x88
+#define WM8904_EQ4                              0x89
+#define WM8904_EQ5                              0x8A
+#define WM8904_EQ6                              0x8B
+#define WM8904_EQ7                              0x8C
+#define WM8904_EQ8                              0x8D
+#define WM8904_EQ9                              0x8E
+#define WM8904_EQ10                             0x8F
+#define WM8904_EQ11                             0x90
+#define WM8904_EQ12                             0x91
+#define WM8904_EQ13                             0x92
+#define WM8904_EQ14                             0x93
+#define WM8904_EQ15                             0x94
+#define WM8904_EQ16                             0x95
+#define WM8904_EQ17                             0x96
+#define WM8904_EQ18                             0x97
+#define WM8904_EQ19                             0x98
+#define WM8904_EQ20                             0x99
+#define WM8904_EQ21                             0x9A
+#define WM8904_EQ22                             0x9B
+#define WM8904_EQ23                             0x9C
+#define WM8904_EQ24                             0x9D
+#define WM8904_CONTROL_INTERFACE_TEST_1         0xA1
+#define WM8904_ADC_TEST_0			0xC6
+#define WM8904_ANALOGUE_OUTPUT_BIAS_0           0xCC
+#define WM8904_FLL_NCO_TEST_0                   0xF7
+#define WM8904_FLL_NCO_TEST_1                   0xF8
+
+#define WM8904_REGISTER_COUNT                   101
+#define WM8904_MAX_REGISTER                     0xF8
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - SW Reset and ID
+ */
+#define WM8904_SW_RST_DEV_ID1_MASK              0xFFFF  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM8904_SW_RST_DEV_ID1_SHIFT                  0  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM8904_SW_RST_DEV_ID1_WIDTH                 16  /* SW_RST_DEV_ID1 - [15:0] */
+
+/*
+ * R1 (0x01) - Revision
+ */
+#define WM8904_REVISION_MASK              	0x000F  /* REVISION - [3:0] */
+#define WM8904_REVISION_SHIFT             	     0  /* REVISION - [3:0] */
+#define WM8904_REVISION_WIDTH             	    16  /* REVISION - [3:0] */
+
+/*
+ * R4 (0x04) - Bias Control 0
+ */
+#define WM8904_POBCTRL                          0x0010  /* POBCTRL */
+#define WM8904_POBCTRL_MASK                     0x0010  /* POBCTRL */
+#define WM8904_POBCTRL_SHIFT                         4  /* POBCTRL */
+#define WM8904_POBCTRL_WIDTH                         1  /* POBCTRL */
+#define WM8904_ISEL_MASK                        0x000C  /* ISEL - [3:2] */
+#define WM8904_ISEL_SHIFT                            2  /* ISEL - [3:2] */
+#define WM8904_ISEL_WIDTH                            2  /* ISEL - [3:2] */
+#define WM8904_STARTUP_BIAS_ENA                 0x0002  /* STARTUP_BIAS_ENA */
+#define WM8904_STARTUP_BIAS_ENA_MASK            0x0002  /* STARTUP_BIAS_ENA */
+#define WM8904_STARTUP_BIAS_ENA_SHIFT                1  /* STARTUP_BIAS_ENA */
+#define WM8904_STARTUP_BIAS_ENA_WIDTH                1  /* STARTUP_BIAS_ENA */
+#define WM8904_BIAS_ENA                         0x0001  /* BIAS_ENA */
+#define WM8904_BIAS_ENA_MASK                    0x0001  /* BIAS_ENA */
+#define WM8904_BIAS_ENA_SHIFT                        0  /* BIAS_ENA */
+#define WM8904_BIAS_ENA_WIDTH                        1  /* BIAS_ENA */
+
+/*
+ * R5 (0x05) - VMID Control 0
+ */
+#define WM8904_VMID_BUF_ENA                     0x0040  /* VMID_BUF_ENA */
+#define WM8904_VMID_BUF_ENA_MASK                0x0040  /* VMID_BUF_ENA */
+#define WM8904_VMID_BUF_ENA_SHIFT                    6  /* VMID_BUF_ENA */
+#define WM8904_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
+#define WM8904_VMID_RES_MASK                    0x0006  /* VMID_RES - [2:1] */
+#define WM8904_VMID_RES_SHIFT                        1  /* VMID_RES - [2:1] */
+#define WM8904_VMID_RES_WIDTH                        2  /* VMID_RES - [2:1] */
+#define WM8904_VMID_ENA                         0x0001  /* VMID_ENA */
+#define WM8904_VMID_ENA_MASK                    0x0001  /* VMID_ENA */
+#define WM8904_VMID_ENA_SHIFT                        0  /* VMID_ENA */
+#define WM8904_VMID_ENA_WIDTH                        1  /* VMID_ENA */
+
+/*
+ * R8 (0x08) - Analogue DAC 0
+ */
+#define WM8904_DAC_BIAS_SEL_MASK                0x0018  /* DAC_BIAS_SEL - [4:3] */
+#define WM8904_DAC_BIAS_SEL_SHIFT                    3  /* DAC_BIAS_SEL - [4:3] */
+#define WM8904_DAC_BIAS_SEL_WIDTH                    2  /* DAC_BIAS_SEL - [4:3] */
+#define WM8904_DAC_VMID_BIAS_SEL_MASK           0x0006  /* DAC_VMID_BIAS_SEL - [2:1] */
+#define WM8904_DAC_VMID_BIAS_SEL_SHIFT               1  /* DAC_VMID_BIAS_SEL - [2:1] */
+#define WM8904_DAC_VMID_BIAS_SEL_WIDTH               2  /* DAC_VMID_BIAS_SEL - [2:1] */
+
+/*
+ * R9 (0x09) - mic Filter Control
+ */
+#define WM8904_MIC_DET_SET_THRESHOLD_MASK       0xF000  /* MIC_DET_SET_THRESHOLD - [15:12] */
+#define WM8904_MIC_DET_SET_THRESHOLD_SHIFT          12  /* MIC_DET_SET_THRESHOLD - [15:12] */
+#define WM8904_MIC_DET_SET_THRESHOLD_WIDTH           4  /* MIC_DET_SET_THRESHOLD - [15:12] */
+#define WM8904_MIC_DET_RESET_THRESHOLD_MASK     0x0F00  /* MIC_DET_RESET_THRESHOLD - [11:8] */
+#define WM8904_MIC_DET_RESET_THRESHOLD_SHIFT         8  /* MIC_DET_RESET_THRESHOLD - [11:8] */
+#define WM8904_MIC_DET_RESET_THRESHOLD_WIDTH         4  /* MIC_DET_RESET_THRESHOLD - [11:8] */
+#define WM8904_MIC_SHORT_SET_THRESHOLD_MASK     0x00F0  /* MIC_SHORT_SET_THRESHOLD - [7:4] */
+#define WM8904_MIC_SHORT_SET_THRESHOLD_SHIFT         4  /* MIC_SHORT_SET_THRESHOLD - [7:4] */
+#define WM8904_MIC_SHORT_SET_THRESHOLD_WIDTH         4  /* MIC_SHORT_SET_THRESHOLD - [7:4] */
+#define WM8904_MIC_SHORT_RESET_THRESHOLD_MASK   0x000F  /* MIC_SHORT_RESET_THRESHOLD - [3:0] */
+#define WM8904_MIC_SHORT_RESET_THRESHOLD_SHIFT       0  /* MIC_SHORT_RESET_THRESHOLD - [3:0] */
+#define WM8904_MIC_SHORT_RESET_THRESHOLD_WIDTH       4  /* MIC_SHORT_RESET_THRESHOLD - [3:0] */
+
+/*
+ * R10 (0x0A) - Analogue ADC 0
+ */
+#define WM8904_ADC_OSR128                       0x0001  /* ADC_OSR128 */
+#define WM8904_ADC_OSR128_MASK                  0x0001  /* ADC_OSR128 */
+#define WM8904_ADC_OSR128_SHIFT                      0  /* ADC_OSR128 */
+#define WM8904_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
+
+/*
+ * R12 (0x0C) - Power Management 0
+ */
+#define WM8904_INL_ENA                          0x0002  /* INL_ENA */
+#define WM8904_INL_ENA_MASK                     0x0002  /* INL_ENA */
+#define WM8904_INL_ENA_SHIFT                         1  /* INL_ENA */
+#define WM8904_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8904_INR_ENA                          0x0001  /* INR_ENA */
+#define WM8904_INR_ENA_MASK                     0x0001  /* INR_ENA */
+#define WM8904_INR_ENA_SHIFT                         0  /* INR_ENA */
+#define WM8904_INR_ENA_WIDTH                         1  /* INR_ENA */
+
+/*
+ * R14 (0x0E) - Power Management 2
+ */
+#define WM8904_HPL_PGA_ENA                      0x0002  /* HPL_PGA_ENA */
+#define WM8904_HPL_PGA_ENA_MASK                 0x0002  /* HPL_PGA_ENA */
+#define WM8904_HPL_PGA_ENA_SHIFT                     1  /* HPL_PGA_ENA */
+#define WM8904_HPL_PGA_ENA_WIDTH                     1  /* HPL_PGA_ENA */
+#define WM8904_HPR_PGA_ENA                      0x0001  /* HPR_PGA_ENA */
+#define WM8904_HPR_PGA_ENA_MASK                 0x0001  /* HPR_PGA_ENA */
+#define WM8904_HPR_PGA_ENA_SHIFT                     0  /* HPR_PGA_ENA */
+#define WM8904_HPR_PGA_ENA_WIDTH                     1  /* HPR_PGA_ENA */
+
+/*
+ * R15 (0x0F) - Power Management 3
+ */
+#define WM8904_LINEOUTL_PGA_ENA                 0x0002  /* LINEOUTL_PGA_ENA */
+#define WM8904_LINEOUTL_PGA_ENA_MASK            0x0002  /* LINEOUTL_PGA_ENA */
+#define WM8904_LINEOUTL_PGA_ENA_SHIFT                1  /* LINEOUTL_PGA_ENA */
+#define WM8904_LINEOUTL_PGA_ENA_WIDTH                1  /* LINEOUTL_PGA_ENA */
+#define WM8904_LINEOUTR_PGA_ENA                 0x0001  /* LINEOUTR_PGA_ENA */
+#define WM8904_LINEOUTR_PGA_ENA_MASK            0x0001  /* LINEOUTR_PGA_ENA */
+#define WM8904_LINEOUTR_PGA_ENA_SHIFT                0  /* LINEOUTR_PGA_ENA */
+#define WM8904_LINEOUTR_PGA_ENA_WIDTH                1  /* LINEOUTR_PGA_ENA */
+
+/*
+ * R18 (0x12) - Power Management 6
+ */
+#define WM8904_DACL_ENA                         0x0008  /* DACL_ENA */
+#define WM8904_DACL_ENA_MASK                    0x0008  /* DACL_ENA */
+#define WM8904_DACL_ENA_SHIFT                        3  /* DACL_ENA */
+#define WM8904_DACL_ENA_WIDTH                        1  /* DACL_ENA */
+#define WM8904_DACR_ENA                         0x0004  /* DACR_ENA */
+#define WM8904_DACR_ENA_MASK                    0x0004  /* DACR_ENA */
+#define WM8904_DACR_ENA_SHIFT                        2  /* DACR_ENA */
+#define WM8904_DACR_ENA_WIDTH                        1  /* DACR_ENA */
+#define WM8904_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8904_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8904_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8904_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8904_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8904_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8904_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8904_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R20 (0x14) - Clock Rates 0
+ */
+#define WM8904_TOCLK_RATE_DIV16                 0x4000  /* TOCLK_RATE_DIV16 */
+#define WM8904_TOCLK_RATE_DIV16_MASK            0x4000  /* TOCLK_RATE_DIV16 */
+#define WM8904_TOCLK_RATE_DIV16_SHIFT               14  /* TOCLK_RATE_DIV16 */
+#define WM8904_TOCLK_RATE_DIV16_WIDTH                1  /* TOCLK_RATE_DIV16 */
+#define WM8904_TOCLK_RATE_X4                    0x2000  /* TOCLK_RATE_X4 */
+#define WM8904_TOCLK_RATE_X4_MASK               0x2000  /* TOCLK_RATE_X4 */
+#define WM8904_TOCLK_RATE_X4_SHIFT                  13  /* TOCLK_RATE_X4 */
+#define WM8904_TOCLK_RATE_X4_WIDTH                   1  /* TOCLK_RATE_X4 */
+#define WM8904_SR_MODE                          0x1000  /* SR_MODE */
+#define WM8904_SR_MODE_MASK                     0x1000  /* SR_MODE */
+#define WM8904_SR_MODE_SHIFT                        12  /* SR_MODE */
+#define WM8904_SR_MODE_WIDTH                         1  /* SR_MODE */
+#define WM8904_MCLK_DIV                         0x0001  /* MCLK_DIV */
+#define WM8904_MCLK_DIV_MASK                    0x0001  /* MCLK_DIV */
+#define WM8904_MCLK_DIV_SHIFT                        0  /* MCLK_DIV */
+#define WM8904_MCLK_DIV_WIDTH                        1  /* MCLK_DIV */
+
+/*
+ * R21 (0x15) - Clock Rates 1
+ */
+#define WM8904_CLK_SYS_RATE_MASK                0x3C00  /* CLK_SYS_RATE - [13:10] */
+#define WM8904_CLK_SYS_RATE_SHIFT                   10  /* CLK_SYS_RATE - [13:10] */
+#define WM8904_CLK_SYS_RATE_WIDTH                    4  /* CLK_SYS_RATE - [13:10] */
+#define WM8904_SAMPLE_RATE_MASK                 0x0007  /* SAMPLE_RATE - [2:0] */
+#define WM8904_SAMPLE_RATE_SHIFT                     0  /* SAMPLE_RATE - [2:0] */
+#define WM8904_SAMPLE_RATE_WIDTH                     3  /* SAMPLE_RATE - [2:0] */
+
+/*
+ * R22 (0x16) - Clock Rates 2
+ */
+#define WM8904_MCLK_INV                         0x8000  /* MCLK_INV */
+#define WM8904_MCLK_INV_MASK                    0x8000  /* MCLK_INV */
+#define WM8904_MCLK_INV_SHIFT                       15  /* MCLK_INV */
+#define WM8904_MCLK_INV_WIDTH                        1  /* MCLK_INV */
+#define WM8904_SYSCLK_SRC                       0x4000  /* SYSCLK_SRC */
+#define WM8904_SYSCLK_SRC_MASK                  0x4000  /* SYSCLK_SRC */
+#define WM8904_SYSCLK_SRC_SHIFT                     14  /* SYSCLK_SRC */
+#define WM8904_SYSCLK_SRC_WIDTH                      1  /* SYSCLK_SRC */
+#define WM8904_TOCLK_RATE                       0x1000  /* TOCLK_RATE */
+#define WM8904_TOCLK_RATE_MASK                  0x1000  /* TOCLK_RATE */
+#define WM8904_TOCLK_RATE_SHIFT                     12  /* TOCLK_RATE */
+#define WM8904_TOCLK_RATE_WIDTH                      1  /* TOCLK_RATE */
+#define WM8904_OPCLK_ENA                        0x0008  /* OPCLK_ENA */
+#define WM8904_OPCLK_ENA_MASK                   0x0008  /* OPCLK_ENA */
+#define WM8904_OPCLK_ENA_SHIFT                       3  /* OPCLK_ENA */
+#define WM8904_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8904_CLK_SYS_ENA                      0x0004  /* CLK_SYS_ENA */
+#define WM8904_CLK_SYS_ENA_MASK                 0x0004  /* CLK_SYS_ENA */
+#define WM8904_CLK_SYS_ENA_SHIFT                     2  /* CLK_SYS_ENA */
+#define WM8904_CLK_SYS_ENA_WIDTH                     1  /* CLK_SYS_ENA */
+#define WM8904_CLK_DSP_ENA                      0x0002  /* CLK_DSP_ENA */
+#define WM8904_CLK_DSP_ENA_MASK                 0x0002  /* CLK_DSP_ENA */
+#define WM8904_CLK_DSP_ENA_SHIFT                     1  /* CLK_DSP_ENA */
+#define WM8904_CLK_DSP_ENA_WIDTH                     1  /* CLK_DSP_ENA */
+#define WM8904_TOCLK_ENA                        0x0001  /* TOCLK_ENA */
+#define WM8904_TOCLK_ENA_MASK                   0x0001  /* TOCLK_ENA */
+#define WM8904_TOCLK_ENA_SHIFT                       0  /* TOCLK_ENA */
+#define WM8904_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+
+/*
+ * R24 (0x18) - Audio Interface 0
+ */
+#define WM8904_DACL_DATINV                      0x1000  /* DACL_DATINV */
+#define WM8904_DACL_DATINV_MASK                 0x1000  /* DACL_DATINV */
+#define WM8904_DACL_DATINV_SHIFT                    12  /* DACL_DATINV */
+#define WM8904_DACL_DATINV_WIDTH                     1  /* DACL_DATINV */
+#define WM8904_DACR_DATINV                      0x0800  /* DACR_DATINV */
+#define WM8904_DACR_DATINV_MASK                 0x0800  /* DACR_DATINV */
+#define WM8904_DACR_DATINV_SHIFT                    11  /* DACR_DATINV */
+#define WM8904_DACR_DATINV_WIDTH                     1  /* DACR_DATINV */
+#define WM8904_DAC_BOOST_MASK                   0x0600  /* DAC_BOOST - [10:9] */
+#define WM8904_DAC_BOOST_SHIFT                       9  /* DAC_BOOST - [10:9] */
+#define WM8904_DAC_BOOST_WIDTH                       2  /* DAC_BOOST - [10:9] */
+#define WM8904_LOOPBACK                         0x0100  /* LOOPBACK */
+#define WM8904_LOOPBACK_MASK                    0x0100  /* LOOPBACK */
+#define WM8904_LOOPBACK_SHIFT                        8  /* LOOPBACK */
+#define WM8904_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+#define WM8904_AIFADCL_SRC                      0x0080  /* AIFADCL_SRC */
+#define WM8904_AIFADCL_SRC_MASK                 0x0080  /* AIFADCL_SRC */
+#define WM8904_AIFADCL_SRC_SHIFT                     7  /* AIFADCL_SRC */
+#define WM8904_AIFADCL_SRC_WIDTH                     1  /* AIFADCL_SRC */
+#define WM8904_AIFADCR_SRC                      0x0040  /* AIFADCR_SRC */
+#define WM8904_AIFADCR_SRC_MASK                 0x0040  /* AIFADCR_SRC */
+#define WM8904_AIFADCR_SRC_SHIFT                     6  /* AIFADCR_SRC */
+#define WM8904_AIFADCR_SRC_WIDTH                     1  /* AIFADCR_SRC */
+#define WM8904_AIFDACL_SRC                      0x0020  /* AIFDACL_SRC */
+#define WM8904_AIFDACL_SRC_MASK                 0x0020  /* AIFDACL_SRC */
+#define WM8904_AIFDACL_SRC_SHIFT                     5  /* AIFDACL_SRC */
+#define WM8904_AIFDACL_SRC_WIDTH                     1  /* AIFDACL_SRC */
+#define WM8904_AIFDACR_SRC                      0x0010  /* AIFDACR_SRC */
+#define WM8904_AIFDACR_SRC_MASK                 0x0010  /* AIFDACR_SRC */
+#define WM8904_AIFDACR_SRC_SHIFT                     4  /* AIFDACR_SRC */
+#define WM8904_AIFDACR_SRC_WIDTH                     1  /* AIFDACR_SRC */
+#define WM8904_ADC_COMP                         0x0008  /* ADC_COMP */
+#define WM8904_ADC_COMP_MASK                    0x0008  /* ADC_COMP */
+#define WM8904_ADC_COMP_SHIFT                        3  /* ADC_COMP */
+#define WM8904_ADC_COMP_WIDTH                        1  /* ADC_COMP */
+#define WM8904_ADC_COMPMODE                     0x0004  /* ADC_COMPMODE */
+#define WM8904_ADC_COMPMODE_MASK                0x0004  /* ADC_COMPMODE */
+#define WM8904_ADC_COMPMODE_SHIFT                    2  /* ADC_COMPMODE */
+#define WM8904_ADC_COMPMODE_WIDTH                    1  /* ADC_COMPMODE */
+#define WM8904_DAC_COMP                         0x0002  /* DAC_COMP */
+#define WM8904_DAC_COMP_MASK                    0x0002  /* DAC_COMP */
+#define WM8904_DAC_COMP_SHIFT                        1  /* DAC_COMP */
+#define WM8904_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM8904_DAC_COMPMODE                     0x0001  /* DAC_COMPMODE */
+#define WM8904_DAC_COMPMODE_MASK                0x0001  /* DAC_COMPMODE */
+#define WM8904_DAC_COMPMODE_SHIFT                    0  /* DAC_COMPMODE */
+#define WM8904_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+
+/*
+ * R25 (0x19) - Audio Interface 1
+ */
+#define WM8904_AIFDAC_TDM                       0x2000  /* AIFDAC_TDM */
+#define WM8904_AIFDAC_TDM_MASK                  0x2000  /* AIFDAC_TDM */
+#define WM8904_AIFDAC_TDM_SHIFT                     13  /* AIFDAC_TDM */
+#define WM8904_AIFDAC_TDM_WIDTH                      1  /* AIFDAC_TDM */
+#define WM8904_AIFDAC_TDM_CHAN                  0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8904_AIFDAC_TDM_CHAN_MASK             0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8904_AIFDAC_TDM_CHAN_SHIFT                12  /* AIFDAC_TDM_CHAN */
+#define WM8904_AIFDAC_TDM_CHAN_WIDTH                 1  /* AIFDAC_TDM_CHAN */
+#define WM8904_AIFADC_TDM                       0x0800  /* AIFADC_TDM */
+#define WM8904_AIFADC_TDM_MASK                  0x0800  /* AIFADC_TDM */
+#define WM8904_AIFADC_TDM_SHIFT                     11  /* AIFADC_TDM */
+#define WM8904_AIFADC_TDM_WIDTH                      1  /* AIFADC_TDM */
+#define WM8904_AIFADC_TDM_CHAN                  0x0400  /* AIFADC_TDM_CHAN */
+#define WM8904_AIFADC_TDM_CHAN_MASK             0x0400  /* AIFADC_TDM_CHAN */
+#define WM8904_AIFADC_TDM_CHAN_SHIFT                10  /* AIFADC_TDM_CHAN */
+#define WM8904_AIFADC_TDM_CHAN_WIDTH                 1  /* AIFADC_TDM_CHAN */
+#define WM8904_AIF_TRIS                         0x0100  /* AIF_TRIS */
+#define WM8904_AIF_TRIS_MASK                    0x0100  /* AIF_TRIS */
+#define WM8904_AIF_TRIS_SHIFT                        8  /* AIF_TRIS */
+#define WM8904_AIF_TRIS_WIDTH                        1  /* AIF_TRIS */
+#define WM8904_AIF_BCLK_INV                     0x0080  /* AIF_BCLK_INV */
+#define WM8904_AIF_BCLK_INV_MASK                0x0080  /* AIF_BCLK_INV */
+#define WM8904_AIF_BCLK_INV_SHIFT                    7  /* AIF_BCLK_INV */
+#define WM8904_AIF_BCLK_INV_WIDTH                    1  /* AIF_BCLK_INV */
+#define WM8904_BCLK_DIR                         0x0040  /* BCLK_DIR */
+#define WM8904_BCLK_DIR_MASK                    0x0040  /* BCLK_DIR */
+#define WM8904_BCLK_DIR_SHIFT                        6  /* BCLK_DIR */
+#define WM8904_BCLK_DIR_WIDTH                        1  /* BCLK_DIR */
+#define WM8904_AIF_LRCLK_INV                    0x0010  /* AIF_LRCLK_INV */
+#define WM8904_AIF_LRCLK_INV_MASK               0x0010  /* AIF_LRCLK_INV */
+#define WM8904_AIF_LRCLK_INV_SHIFT                   4  /* AIF_LRCLK_INV */
+#define WM8904_AIF_LRCLK_INV_WIDTH                   1  /* AIF_LRCLK_INV */
+#define WM8904_AIF_WL_MASK                      0x000C  /* AIF_WL - [3:2] */
+#define WM8904_AIF_WL_SHIFT                          2  /* AIF_WL - [3:2] */
+#define WM8904_AIF_WL_WIDTH                          2  /* AIF_WL - [3:2] */
+#define WM8904_AIF_FMT_MASK                     0x0003  /* AIF_FMT - [1:0] */
+#define WM8904_AIF_FMT_SHIFT                         0  /* AIF_FMT - [1:0] */
+#define WM8904_AIF_FMT_WIDTH                         2  /* AIF_FMT - [1:0] */
+
+/*
+ * R26 (0x1A) - Audio Interface 2
+ */
+#define WM8904_OPCLK_DIV_MASK                   0x0F00  /* OPCLK_DIV - [11:8] */
+#define WM8904_OPCLK_DIV_SHIFT                       8  /* OPCLK_DIV - [11:8] */
+#define WM8904_OPCLK_DIV_WIDTH                       4  /* OPCLK_DIV - [11:8] */
+#define WM8904_BCLK_DIV_MASK                    0x001F  /* BCLK_DIV - [4:0] */
+#define WM8904_BCLK_DIV_SHIFT                        0  /* BCLK_DIV - [4:0] */
+#define WM8904_BCLK_DIV_WIDTH                        5  /* BCLK_DIV - [4:0] */
+
+/*
+ * R27 (0x1B) - Audio Interface 3
+ */
+#define WM8904_LRCLK_DIR                        0x0800  /* LRCLK_DIR */
+#define WM8904_LRCLK_DIR_MASK                   0x0800  /* LRCLK_DIR */
+#define WM8904_LRCLK_DIR_SHIFT                      11  /* LRCLK_DIR */
+#define WM8904_LRCLK_DIR_WIDTH                       1  /* LRCLK_DIR */
+#define WM8904_LRCLK_RATE_MASK                  0x07FF  /* LRCLK_RATE - [10:0] */
+#define WM8904_LRCLK_RATE_SHIFT                      0  /* LRCLK_RATE - [10:0] */
+#define WM8904_LRCLK_RATE_WIDTH                     11  /* LRCLK_RATE - [10:0] */
+
+/*
+ * R30 (0x1E) - DAC Digital Volume Left
+ */
+#define WM8904_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8904_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8904_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8904_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8904_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8904_DACL_VOL_SHIFT                        0  /* DACL_VOL - [7:0] */
+#define WM8904_DACL_VOL_WIDTH                        8  /* DACL_VOL - [7:0] */
+
+/*
+ * R31 (0x1F) - DAC Digital Volume Right
+ */
+#define WM8904_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8904_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8904_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8904_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8904_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8904_DACR_VOL_SHIFT                        0  /* DACR_VOL - [7:0] */
+#define WM8904_DACR_VOL_WIDTH                        8  /* DACR_VOL - [7:0] */
+
+/*
+ * R32 (0x20) - DAC Digital 0
+ */
+#define WM8904_ADCL_DAC_SVOL_MASK               0x0F00  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8904_ADCL_DAC_SVOL_SHIFT                   8  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8904_ADCL_DAC_SVOL_WIDTH                   4  /* ADCL_DAC_SVOL - [11:8] */
+#define WM8904_ADCR_DAC_SVOL_MASK               0x00F0  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8904_ADCR_DAC_SVOL_SHIFT                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8904_ADCR_DAC_SVOL_WIDTH                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8904_ADC_TO_DACL_MASK                 0x000C  /* ADC_TO_DACL - [3:2] */
+#define WM8904_ADC_TO_DACL_SHIFT                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8904_ADC_TO_DACL_WIDTH                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8904_ADC_TO_DACR_MASK                 0x0003  /* ADC_TO_DACR - [1:0] */
+#define WM8904_ADC_TO_DACR_SHIFT                     0  /* ADC_TO_DACR - [1:0] */
+#define WM8904_ADC_TO_DACR_WIDTH                     2  /* ADC_TO_DACR - [1:0] */
+
+/*
+ * R33 (0x21) - DAC Digital 1
+ */
+#define WM8904_DAC_MONO                         0x1000  /* DAC_MONO */
+#define WM8904_DAC_MONO_MASK                    0x1000  /* DAC_MONO */
+#define WM8904_DAC_MONO_SHIFT                       12  /* DAC_MONO */
+#define WM8904_DAC_MONO_WIDTH                        1  /* DAC_MONO */
+#define WM8904_DAC_SB_FILT                      0x0800  /* DAC_SB_FILT */
+#define WM8904_DAC_SB_FILT_MASK                 0x0800  /* DAC_SB_FILT */
+#define WM8904_DAC_SB_FILT_SHIFT                    11  /* DAC_SB_FILT */
+#define WM8904_DAC_SB_FILT_WIDTH                     1  /* DAC_SB_FILT */
+#define WM8904_DAC_MUTERATE                     0x0400  /* DAC_MUTERATE */
+#define WM8904_DAC_MUTERATE_MASK                0x0400  /* DAC_MUTERATE */
+#define WM8904_DAC_MUTERATE_SHIFT                   10  /* DAC_MUTERATE */
+#define WM8904_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM8904_DAC_UNMUTE_RAMP                  0x0200  /* DAC_UNMUTE_RAMP */
+#define WM8904_DAC_UNMUTE_RAMP_MASK             0x0200  /* DAC_UNMUTE_RAMP */
+#define WM8904_DAC_UNMUTE_RAMP_SHIFT                 9  /* DAC_UNMUTE_RAMP */
+#define WM8904_DAC_UNMUTE_RAMP_WIDTH                 1  /* DAC_UNMUTE_RAMP */
+#define WM8904_DAC_OSR128                       0x0040  /* DAC_OSR128 */
+#define WM8904_DAC_OSR128_MASK                  0x0040  /* DAC_OSR128 */
+#define WM8904_DAC_OSR128_SHIFT                      6  /* DAC_OSR128 */
+#define WM8904_DAC_OSR128_WIDTH                      1  /* DAC_OSR128 */
+#define WM8904_DAC_MUTE                         0x0008  /* DAC_MUTE */
+#define WM8904_DAC_MUTE_MASK                    0x0008  /* DAC_MUTE */
+#define WM8904_DAC_MUTE_SHIFT                        3  /* DAC_MUTE */
+#define WM8904_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM8904_DEEMPH_MASK                      0x0006  /* DEEMPH - [2:1] */
+#define WM8904_DEEMPH_SHIFT                          1  /* DEEMPH - [2:1] */
+#define WM8904_DEEMPH_WIDTH                          2  /* DEEMPH - [2:1] */
+
+/*
+ * R36 (0x24) - ADC Digital Volume Left
+ */
+#define WM8904_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8904_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8904_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8904_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8904_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8904_ADCL_VOL_SHIFT                        0  /* ADCL_VOL - [7:0] */
+#define WM8904_ADCL_VOL_WIDTH                        8  /* ADCL_VOL - [7:0] */
+
+/*
+ * R37 (0x25) - ADC Digital Volume Right
+ */
+#define WM8904_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8904_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8904_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8904_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8904_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8904_ADCR_VOL_SHIFT                        0  /* ADCR_VOL - [7:0] */
+#define WM8904_ADCR_VOL_WIDTH                        8  /* ADCR_VOL - [7:0] */
+
+/*
+ * R38 (0x26) - ADC Digital 0
+ */
+#define WM8904_ADC_HPF_CUT_MASK                 0x0060  /* ADC_HPF_CUT - [6:5] */
+#define WM8904_ADC_HPF_CUT_SHIFT                     5  /* ADC_HPF_CUT - [6:5] */
+#define WM8904_ADC_HPF_CUT_WIDTH                     2  /* ADC_HPF_CUT - [6:5] */
+#define WM8904_ADC_HPF                          0x0010  /* ADC_HPF */
+#define WM8904_ADC_HPF_MASK                     0x0010  /* ADC_HPF */
+#define WM8904_ADC_HPF_SHIFT                         4  /* ADC_HPF */
+#define WM8904_ADC_HPF_WIDTH                         1  /* ADC_HPF */
+#define WM8904_ADCL_DATINV                      0x0002  /* ADCL_DATINV */
+#define WM8904_ADCL_DATINV_MASK                 0x0002  /* ADCL_DATINV */
+#define WM8904_ADCL_DATINV_SHIFT                     1  /* ADCL_DATINV */
+#define WM8904_ADCL_DATINV_WIDTH                     1  /* ADCL_DATINV */
+#define WM8904_ADCR_DATINV                      0x0001  /* ADCR_DATINV */
+#define WM8904_ADCR_DATINV_MASK                 0x0001  /* ADCR_DATINV */
+#define WM8904_ADCR_DATINV_SHIFT                     0  /* ADCR_DATINV */
+#define WM8904_ADCR_DATINV_WIDTH                     1  /* ADCR_DATINV */
+
+/*
+ * R39 (0x27) - Digital Microphone 0
+ */
+#define WM8904_DMIC_ENA                         0x1000  /* DMIC_ENA */
+#define WM8904_DMIC_ENA_MASK                    0x1000  /* DMIC_ENA */
+#define WM8904_DMIC_ENA_SHIFT                       12  /* DMIC_ENA */
+#define WM8904_DMIC_ENA_WIDTH                        1  /* DMIC_ENA */
+#define WM8904_DMIC_SRC                         0x0800  /* DMIC_SRC */
+#define WM8904_DMIC_SRC_MASK                    0x0800  /* DMIC_SRC */
+#define WM8904_DMIC_SRC_SHIFT                       11  /* DMIC_SRC */
+#define WM8904_DMIC_SRC_WIDTH                        1  /* DMIC_SRC */
+
+/*
+ * R40 (0x28) - DRC 0
+ */
+#define WM8904_DRC_ENA                          0x8000  /* DRC_ENA */
+#define WM8904_DRC_ENA_MASK                     0x8000  /* DRC_ENA */
+#define WM8904_DRC_ENA_SHIFT                        15  /* DRC_ENA */
+#define WM8904_DRC_ENA_WIDTH                         1  /* DRC_ENA */
+#define WM8904_DRC_DAC_PATH                     0x4000  /* DRC_DAC_PATH */
+#define WM8904_DRC_DAC_PATH_MASK                0x4000  /* DRC_DAC_PATH */
+#define WM8904_DRC_DAC_PATH_SHIFT                   14  /* DRC_DAC_PATH */
+#define WM8904_DRC_DAC_PATH_WIDTH                    1  /* DRC_DAC_PATH */
+#define WM8904_DRC_GS_HYST_LVL_MASK             0x1800  /* DRC_GS_HYST_LVL - [12:11] */
+#define WM8904_DRC_GS_HYST_LVL_SHIFT                11  /* DRC_GS_HYST_LVL - [12:11] */
+#define WM8904_DRC_GS_HYST_LVL_WIDTH                 2  /* DRC_GS_HYST_LVL - [12:11] */
+#define WM8904_DRC_STARTUP_GAIN_MASK            0x07C0  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8904_DRC_STARTUP_GAIN_SHIFT                6  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8904_DRC_STARTUP_GAIN_WIDTH                5  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM8904_DRC_FF_DELAY                     0x0020  /* DRC_FF_DELAY */
+#define WM8904_DRC_FF_DELAY_MASK                0x0020  /* DRC_FF_DELAY */
+#define WM8904_DRC_FF_DELAY_SHIFT                    5  /* DRC_FF_DELAY */
+#define WM8904_DRC_FF_DELAY_WIDTH                    1  /* DRC_FF_DELAY */
+#define WM8904_DRC_GS_ENA                       0x0008  /* DRC_GS_ENA */
+#define WM8904_DRC_GS_ENA_MASK                  0x0008  /* DRC_GS_ENA */
+#define WM8904_DRC_GS_ENA_SHIFT                      3  /* DRC_GS_ENA */
+#define WM8904_DRC_GS_ENA_WIDTH                      1  /* DRC_GS_ENA */
+#define WM8904_DRC_QR                           0x0004  /* DRC_QR */
+#define WM8904_DRC_QR_MASK                      0x0004  /* DRC_QR */
+#define WM8904_DRC_QR_SHIFT                          2  /* DRC_QR */
+#define WM8904_DRC_QR_WIDTH                          1  /* DRC_QR */
+#define WM8904_DRC_ANTICLIP                     0x0002  /* DRC_ANTICLIP */
+#define WM8904_DRC_ANTICLIP_MASK                0x0002  /* DRC_ANTICLIP */
+#define WM8904_DRC_ANTICLIP_SHIFT                    1  /* DRC_ANTICLIP */
+#define WM8904_DRC_ANTICLIP_WIDTH                    1  /* DRC_ANTICLIP */
+#define WM8904_DRC_GS_HYST                      0x0001  /* DRC_GS_HYST */
+#define WM8904_DRC_GS_HYST_MASK                 0x0001  /* DRC_GS_HYST */
+#define WM8904_DRC_GS_HYST_SHIFT                     0  /* DRC_GS_HYST */
+#define WM8904_DRC_GS_HYST_WIDTH                     1  /* DRC_GS_HYST */
+
+/*
+ * R41 (0x29) - DRC 1
+ */
+#define WM8904_DRC_ATK_MASK                     0xF000  /* DRC_ATK - [15:12] */
+#define WM8904_DRC_ATK_SHIFT                        12  /* DRC_ATK - [15:12] */
+#define WM8904_DRC_ATK_WIDTH                         4  /* DRC_ATK - [15:12] */
+#define WM8904_DRC_DCY_MASK                     0x0F00  /* DRC_DCY - [11:8] */
+#define WM8904_DRC_DCY_SHIFT                         8  /* DRC_DCY - [11:8] */
+#define WM8904_DRC_DCY_WIDTH                         4  /* DRC_DCY - [11:8] */
+#define WM8904_DRC_QR_THR_MASK                  0x00C0  /* DRC_QR_THR - [7:6] */
+#define WM8904_DRC_QR_THR_SHIFT                      6  /* DRC_QR_THR - [7:6] */
+#define WM8904_DRC_QR_THR_WIDTH                      2  /* DRC_QR_THR - [7:6] */
+#define WM8904_DRC_QR_DCY_MASK                  0x0030  /* DRC_QR_DCY - [5:4] */
+#define WM8904_DRC_QR_DCY_SHIFT                      4  /* DRC_QR_DCY - [5:4] */
+#define WM8904_DRC_QR_DCY_WIDTH                      2  /* DRC_QR_DCY - [5:4] */
+#define WM8904_DRC_MINGAIN_MASK                 0x000C  /* DRC_MINGAIN - [3:2] */
+#define WM8904_DRC_MINGAIN_SHIFT                     2  /* DRC_MINGAIN - [3:2] */
+#define WM8904_DRC_MINGAIN_WIDTH                     2  /* DRC_MINGAIN - [3:2] */
+#define WM8904_DRC_MAXGAIN_MASK                 0x0003  /* DRC_MAXGAIN - [1:0] */
+#define WM8904_DRC_MAXGAIN_SHIFT                     0  /* DRC_MAXGAIN - [1:0] */
+#define WM8904_DRC_MAXGAIN_WIDTH                     2  /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R42 (0x2A) - DRC 2
+ */
+#define WM8904_DRC_HI_COMP_MASK                 0x0038  /* DRC_HI_COMP - [5:3] */
+#define WM8904_DRC_HI_COMP_SHIFT                     3  /* DRC_HI_COMP - [5:3] */
+#define WM8904_DRC_HI_COMP_WIDTH                     3  /* DRC_HI_COMP - [5:3] */
+#define WM8904_DRC_LO_COMP_MASK                 0x0007  /* DRC_LO_COMP - [2:0] */
+#define WM8904_DRC_LO_COMP_SHIFT                     0  /* DRC_LO_COMP - [2:0] */
+#define WM8904_DRC_LO_COMP_WIDTH                     3  /* DRC_LO_COMP - [2:0] */
+
+/*
+ * R43 (0x2B) - DRC 3
+ */
+#define WM8904_DRC_KNEE_IP_MASK                 0x07E0  /* DRC_KNEE_IP - [10:5] */
+#define WM8904_DRC_KNEE_IP_SHIFT                     5  /* DRC_KNEE_IP - [10:5] */
+#define WM8904_DRC_KNEE_IP_WIDTH                     6  /* DRC_KNEE_IP - [10:5] */
+#define WM8904_DRC_KNEE_OP_MASK                 0x001F  /* DRC_KNEE_OP - [4:0] */
+#define WM8904_DRC_KNEE_OP_SHIFT                     0  /* DRC_KNEE_OP - [4:0] */
+#define WM8904_DRC_KNEE_OP_WIDTH                     5  /* DRC_KNEE_OP - [4:0] */
+
+/*
+ * R44 (0x2C) - Analogue Left Input 0
+ */
+#define WM8904_LINMUTE                          0x0080  /* LINMUTE */
+#define WM8904_LINMUTE_MASK                     0x0080  /* LINMUTE */
+#define WM8904_LINMUTE_SHIFT                         7  /* LINMUTE */
+#define WM8904_LINMUTE_WIDTH                         1  /* LINMUTE */
+#define WM8904_LIN_VOL_MASK                     0x001F  /* LIN_VOL - [4:0] */
+#define WM8904_LIN_VOL_SHIFT                         0  /* LIN_VOL - [4:0] */
+#define WM8904_LIN_VOL_WIDTH                         5  /* LIN_VOL - [4:0] */
+
+/*
+ * R45 (0x2D) - Analogue Right Input 0
+ */
+#define WM8904_RINMUTE                          0x0080  /* RINMUTE */
+#define WM8904_RINMUTE_MASK                     0x0080  /* RINMUTE */
+#define WM8904_RINMUTE_SHIFT                         7  /* RINMUTE */
+#define WM8904_RINMUTE_WIDTH                         1  /* RINMUTE */
+#define WM8904_RIN_VOL_MASK                     0x001F  /* RIN_VOL - [4:0] */
+#define WM8904_RIN_VOL_SHIFT                         0  /* RIN_VOL - [4:0] */
+#define WM8904_RIN_VOL_WIDTH                         5  /* RIN_VOL - [4:0] */
+
+/*
+ * R46 (0x2E) - Analogue Left Input 1
+ */
+#define WM8904_INL_CM_ENA                       0x0040  /* INL_CM_ENA */
+#define WM8904_INL_CM_ENA_MASK                  0x0040  /* INL_CM_ENA */
+#define WM8904_INL_CM_ENA_SHIFT                      6  /* INL_CM_ENA */
+#define WM8904_INL_CM_ENA_WIDTH                      1  /* INL_CM_ENA */
+#define WM8904_L_IP_SEL_N_MASK                  0x0030  /* L_IP_SEL_N - [5:4] */
+#define WM8904_L_IP_SEL_N_SHIFT                      4  /* L_IP_SEL_N - [5:4] */
+#define WM8904_L_IP_SEL_N_WIDTH                      2  /* L_IP_SEL_N - [5:4] */
+#define WM8904_L_IP_SEL_P_MASK                  0x000C  /* L_IP_SEL_P - [3:2] */
+#define WM8904_L_IP_SEL_P_SHIFT                      2  /* L_IP_SEL_P - [3:2] */
+#define WM8904_L_IP_SEL_P_WIDTH                      2  /* L_IP_SEL_P - [3:2] */
+#define WM8904_L_MODE_MASK                      0x0003  /* L_MODE - [1:0] */
+#define WM8904_L_MODE_SHIFT                          0  /* L_MODE - [1:0] */
+#define WM8904_L_MODE_WIDTH                          2  /* L_MODE - [1:0] */
+
+/*
+ * R47 (0x2F) - Analogue Right Input 1
+ */
+#define WM8904_INR_CM_ENA                       0x0040  /* INR_CM_ENA */
+#define WM8904_INR_CM_ENA_MASK                  0x0040  /* INR_CM_ENA */
+#define WM8904_INR_CM_ENA_SHIFT                      6  /* INR_CM_ENA */
+#define WM8904_INR_CM_ENA_WIDTH                      1  /* INR_CM_ENA */
+#define WM8904_R_IP_SEL_N_MASK                  0x0030  /* R_IP_SEL_N - [5:4] */
+#define WM8904_R_IP_SEL_N_SHIFT                      4  /* R_IP_SEL_N - [5:4] */
+#define WM8904_R_IP_SEL_N_WIDTH                      2  /* R_IP_SEL_N - [5:4] */
+#define WM8904_R_IP_SEL_P_MASK                  0x000C  /* R_IP_SEL_P - [3:2] */
+#define WM8904_R_IP_SEL_P_SHIFT                      2  /* R_IP_SEL_P - [3:2] */
+#define WM8904_R_IP_SEL_P_WIDTH                      2  /* R_IP_SEL_P - [3:2] */
+#define WM8904_R_MODE_MASK                      0x0003  /* R_MODE - [1:0] */
+#define WM8904_R_MODE_SHIFT                          0  /* R_MODE - [1:0] */
+#define WM8904_R_MODE_WIDTH                          2  /* R_MODE - [1:0] */
+
+/*
+ * R57 (0x39) - Analogue OUT1 Left
+ */
+#define WM8904_HPOUTL_MUTE                      0x0100  /* HPOUTL_MUTE */
+#define WM8904_HPOUTL_MUTE_MASK                 0x0100  /* HPOUTL_MUTE */
+#define WM8904_HPOUTL_MUTE_SHIFT                     8  /* HPOUTL_MUTE */
+#define WM8904_HPOUTL_MUTE_WIDTH                     1  /* HPOUTL_MUTE */
+#define WM8904_HPOUT_VU                         0x0080  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_MASK                    0x0080  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_SHIFT                        7  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_WIDTH                        1  /* HPOUT_VU */
+#define WM8904_HPOUTLZC                         0x0040  /* HPOUTLZC */
+#define WM8904_HPOUTLZC_MASK                    0x0040  /* HPOUTLZC */
+#define WM8904_HPOUTLZC_SHIFT                        6  /* HPOUTLZC */
+#define WM8904_HPOUTLZC_WIDTH                        1  /* HPOUTLZC */
+#define WM8904_HPOUTL_VOL_MASK                  0x003F  /* HPOUTL_VOL - [5:0] */
+#define WM8904_HPOUTL_VOL_SHIFT                      0  /* HPOUTL_VOL - [5:0] */
+#define WM8904_HPOUTL_VOL_WIDTH                      6  /* HPOUTL_VOL - [5:0] */
+
+/*
+ * R58 (0x3A) - Analogue OUT1 Right
+ */
+#define WM8904_HPOUTR_MUTE                      0x0100  /* HPOUTR_MUTE */
+#define WM8904_HPOUTR_MUTE_MASK                 0x0100  /* HPOUTR_MUTE */
+#define WM8904_HPOUTR_MUTE_SHIFT                     8  /* HPOUTR_MUTE */
+#define WM8904_HPOUTR_MUTE_WIDTH                     1  /* HPOUTR_MUTE */
+#define WM8904_HPOUT_VU                         0x0080  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_MASK                    0x0080  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_SHIFT                        7  /* HPOUT_VU */
+#define WM8904_HPOUT_VU_WIDTH                        1  /* HPOUT_VU */
+#define WM8904_HPOUTRZC                         0x0040  /* HPOUTRZC */
+#define WM8904_HPOUTRZC_MASK                    0x0040  /* HPOUTRZC */
+#define WM8904_HPOUTRZC_SHIFT                        6  /* HPOUTRZC */
+#define WM8904_HPOUTRZC_WIDTH                        1  /* HPOUTRZC */
+#define WM8904_HPOUTR_VOL_MASK                  0x003F  /* HPOUTR_VOL - [5:0] */
+#define WM8904_HPOUTR_VOL_SHIFT                      0  /* HPOUTR_VOL - [5:0] */
+#define WM8904_HPOUTR_VOL_WIDTH                      6  /* HPOUTR_VOL - [5:0] */
+
+/*
+ * R59 (0x3B) - Analogue OUT2 Left
+ */
+#define WM8904_LINEOUTL_MUTE                    0x0100  /* LINEOUTL_MUTE */
+#define WM8904_LINEOUTL_MUTE_MASK               0x0100  /* LINEOUTL_MUTE */
+#define WM8904_LINEOUTL_MUTE_SHIFT                   8  /* LINEOUTL_MUTE */
+#define WM8904_LINEOUTL_MUTE_WIDTH                   1  /* LINEOUTL_MUTE */
+#define WM8904_LINEOUT_VU                       0x0080  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_MASK                  0x0080  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_SHIFT                      7  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_WIDTH                      1  /* LINEOUT_VU */
+#define WM8904_LINEOUTLZC                       0x0040  /* LINEOUTLZC */
+#define WM8904_LINEOUTLZC_MASK                  0x0040  /* LINEOUTLZC */
+#define WM8904_LINEOUTLZC_SHIFT                      6  /* LINEOUTLZC */
+#define WM8904_LINEOUTLZC_WIDTH                      1  /* LINEOUTLZC */
+#define WM8904_LINEOUTL_VOL_MASK                0x003F  /* LINEOUTL_VOL - [5:0] */
+#define WM8904_LINEOUTL_VOL_SHIFT                    0  /* LINEOUTL_VOL - [5:0] */
+#define WM8904_LINEOUTL_VOL_WIDTH                    6  /* LINEOUTL_VOL - [5:0] */
+
+/*
+ * R60 (0x3C) - Analogue OUT2 Right
+ */
+#define WM8904_LINEOUTR_MUTE                    0x0100  /* LINEOUTR_MUTE */
+#define WM8904_LINEOUTR_MUTE_MASK               0x0100  /* LINEOUTR_MUTE */
+#define WM8904_LINEOUTR_MUTE_SHIFT                   8  /* LINEOUTR_MUTE */
+#define WM8904_LINEOUTR_MUTE_WIDTH                   1  /* LINEOUTR_MUTE */
+#define WM8904_LINEOUT_VU                       0x0080  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_MASK                  0x0080  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_SHIFT                      7  /* LINEOUT_VU */
+#define WM8904_LINEOUT_VU_WIDTH                      1  /* LINEOUT_VU */
+#define WM8904_LINEOUTRZC                       0x0040  /* LINEOUTRZC */
+#define WM8904_LINEOUTRZC_MASK                  0x0040  /* LINEOUTRZC */
+#define WM8904_LINEOUTRZC_SHIFT                      6  /* LINEOUTRZC */
+#define WM8904_LINEOUTRZC_WIDTH                      1  /* LINEOUTRZC */
+#define WM8904_LINEOUTR_VOL_MASK                0x003F  /* LINEOUTR_VOL - [5:0] */
+#define WM8904_LINEOUTR_VOL_SHIFT                    0  /* LINEOUTR_VOL - [5:0] */
+#define WM8904_LINEOUTR_VOL_WIDTH                    6  /* LINEOUTR_VOL - [5:0] */
+
+/*
+ * R61 (0x3D) - Analogue OUT12 ZC
+ */
+#define WM8904_HPL_BYP_ENA                      0x0008  /* HPL_BYP_ENA */
+#define WM8904_HPL_BYP_ENA_MASK                 0x0008  /* HPL_BYP_ENA */
+#define WM8904_HPL_BYP_ENA_SHIFT                     3  /* HPL_BYP_ENA */
+#define WM8904_HPL_BYP_ENA_WIDTH                     1  /* HPL_BYP_ENA */
+#define WM8904_HPR_BYP_ENA                      0x0004  /* HPR_BYP_ENA */
+#define WM8904_HPR_BYP_ENA_MASK                 0x0004  /* HPR_BYP_ENA */
+#define WM8904_HPR_BYP_ENA_SHIFT                     2  /* HPR_BYP_ENA */
+#define WM8904_HPR_BYP_ENA_WIDTH                     1  /* HPR_BYP_ENA */
+#define WM8904_LINEOUTL_BYP_ENA                 0x0002  /* LINEOUTL_BYP_ENA */
+#define WM8904_LINEOUTL_BYP_ENA_MASK            0x0002  /* LINEOUTL_BYP_ENA */
+#define WM8904_LINEOUTL_BYP_ENA_SHIFT                1  /* LINEOUTL_BYP_ENA */
+#define WM8904_LINEOUTL_BYP_ENA_WIDTH                1  /* LINEOUTL_BYP_ENA */
+#define WM8904_LINEOUTR_BYP_ENA                 0x0001  /* LINEOUTR_BYP_ENA */
+#define WM8904_LINEOUTR_BYP_ENA_MASK            0x0001  /* LINEOUTR_BYP_ENA */
+#define WM8904_LINEOUTR_BYP_ENA_SHIFT                0  /* LINEOUTR_BYP_ENA */
+#define WM8904_LINEOUTR_BYP_ENA_WIDTH                1  /* LINEOUTR_BYP_ENA */
+
+/*
+ * R67 (0x43) - DC Servo 0
+ */
+#define WM8904_DCS_ENA_CHAN_3                   0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8904_DCS_ENA_CHAN_3_MASK              0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8904_DCS_ENA_CHAN_3_SHIFT                  3  /* DCS_ENA_CHAN_3 */
+#define WM8904_DCS_ENA_CHAN_3_WIDTH                  1  /* DCS_ENA_CHAN_3 */
+#define WM8904_DCS_ENA_CHAN_2                   0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8904_DCS_ENA_CHAN_2_MASK              0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8904_DCS_ENA_CHAN_2_SHIFT                  2  /* DCS_ENA_CHAN_2 */
+#define WM8904_DCS_ENA_CHAN_2_WIDTH                  1  /* DCS_ENA_CHAN_2 */
+#define WM8904_DCS_ENA_CHAN_1                   0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8904_DCS_ENA_CHAN_1_MASK              0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8904_DCS_ENA_CHAN_1_SHIFT                  1  /* DCS_ENA_CHAN_1 */
+#define WM8904_DCS_ENA_CHAN_1_WIDTH                  1  /* DCS_ENA_CHAN_1 */
+#define WM8904_DCS_ENA_CHAN_0                   0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8904_DCS_ENA_CHAN_0_MASK              0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8904_DCS_ENA_CHAN_0_SHIFT                  0  /* DCS_ENA_CHAN_0 */
+#define WM8904_DCS_ENA_CHAN_0_WIDTH                  1  /* DCS_ENA_CHAN_0 */
+
+/*
+ * R68 (0x44) - DC Servo 1
+ */
+#define WM8904_DCS_TRIG_SINGLE_3                0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8904_DCS_TRIG_SINGLE_3_MASK           0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8904_DCS_TRIG_SINGLE_3_SHIFT              15  /* DCS_TRIG_SINGLE_3 */
+#define WM8904_DCS_TRIG_SINGLE_3_WIDTH               1  /* DCS_TRIG_SINGLE_3 */
+#define WM8904_DCS_TRIG_SINGLE_2                0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8904_DCS_TRIG_SINGLE_2_MASK           0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8904_DCS_TRIG_SINGLE_2_SHIFT              14  /* DCS_TRIG_SINGLE_2 */
+#define WM8904_DCS_TRIG_SINGLE_2_WIDTH               1  /* DCS_TRIG_SINGLE_2 */
+#define WM8904_DCS_TRIG_SINGLE_1                0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8904_DCS_TRIG_SINGLE_1_MASK           0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8904_DCS_TRIG_SINGLE_1_SHIFT              13  /* DCS_TRIG_SINGLE_1 */
+#define WM8904_DCS_TRIG_SINGLE_1_WIDTH               1  /* DCS_TRIG_SINGLE_1 */
+#define WM8904_DCS_TRIG_SINGLE_0                0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8904_DCS_TRIG_SINGLE_0_MASK           0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8904_DCS_TRIG_SINGLE_0_SHIFT              12  /* DCS_TRIG_SINGLE_0 */
+#define WM8904_DCS_TRIG_SINGLE_0_WIDTH               1  /* DCS_TRIG_SINGLE_0 */
+#define WM8904_DCS_TRIG_SERIES_3                0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8904_DCS_TRIG_SERIES_3_MASK           0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8904_DCS_TRIG_SERIES_3_SHIFT              11  /* DCS_TRIG_SERIES_3 */
+#define WM8904_DCS_TRIG_SERIES_3_WIDTH               1  /* DCS_TRIG_SERIES_3 */
+#define WM8904_DCS_TRIG_SERIES_2                0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8904_DCS_TRIG_SERIES_2_MASK           0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8904_DCS_TRIG_SERIES_2_SHIFT              10  /* DCS_TRIG_SERIES_2 */
+#define WM8904_DCS_TRIG_SERIES_2_WIDTH               1  /* DCS_TRIG_SERIES_2 */
+#define WM8904_DCS_TRIG_SERIES_1                0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8904_DCS_TRIG_SERIES_1_MASK           0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8904_DCS_TRIG_SERIES_1_SHIFT               9  /* DCS_TRIG_SERIES_1 */
+#define WM8904_DCS_TRIG_SERIES_1_WIDTH               1  /* DCS_TRIG_SERIES_1 */
+#define WM8904_DCS_TRIG_SERIES_0                0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8904_DCS_TRIG_SERIES_0_MASK           0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8904_DCS_TRIG_SERIES_0_SHIFT               8  /* DCS_TRIG_SERIES_0 */
+#define WM8904_DCS_TRIG_SERIES_0_WIDTH               1  /* DCS_TRIG_SERIES_0 */
+#define WM8904_DCS_TRIG_STARTUP_3               0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8904_DCS_TRIG_STARTUP_3_MASK          0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8904_DCS_TRIG_STARTUP_3_SHIFT              7  /* DCS_TRIG_STARTUP_3 */
+#define WM8904_DCS_TRIG_STARTUP_3_WIDTH              1  /* DCS_TRIG_STARTUP_3 */
+#define WM8904_DCS_TRIG_STARTUP_2               0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8904_DCS_TRIG_STARTUP_2_MASK          0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8904_DCS_TRIG_STARTUP_2_SHIFT              6  /* DCS_TRIG_STARTUP_2 */
+#define WM8904_DCS_TRIG_STARTUP_2_WIDTH              1  /* DCS_TRIG_STARTUP_2 */
+#define WM8904_DCS_TRIG_STARTUP_1               0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8904_DCS_TRIG_STARTUP_1_MASK          0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8904_DCS_TRIG_STARTUP_1_SHIFT              5  /* DCS_TRIG_STARTUP_1 */
+#define WM8904_DCS_TRIG_STARTUP_1_WIDTH              1  /* DCS_TRIG_STARTUP_1 */
+#define WM8904_DCS_TRIG_STARTUP_0               0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8904_DCS_TRIG_STARTUP_0_MASK          0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8904_DCS_TRIG_STARTUP_0_SHIFT              4  /* DCS_TRIG_STARTUP_0 */
+#define WM8904_DCS_TRIG_STARTUP_0_WIDTH              1  /* DCS_TRIG_STARTUP_0 */
+#define WM8904_DCS_TRIG_DAC_WR_3                0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8904_DCS_TRIG_DAC_WR_3_MASK           0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8904_DCS_TRIG_DAC_WR_3_SHIFT               3  /* DCS_TRIG_DAC_WR_3 */
+#define WM8904_DCS_TRIG_DAC_WR_3_WIDTH               1  /* DCS_TRIG_DAC_WR_3 */
+#define WM8904_DCS_TRIG_DAC_WR_2                0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8904_DCS_TRIG_DAC_WR_2_MASK           0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8904_DCS_TRIG_DAC_WR_2_SHIFT               2  /* DCS_TRIG_DAC_WR_2 */
+#define WM8904_DCS_TRIG_DAC_WR_2_WIDTH               1  /* DCS_TRIG_DAC_WR_2 */
+#define WM8904_DCS_TRIG_DAC_WR_1                0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8904_DCS_TRIG_DAC_WR_1_MASK           0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8904_DCS_TRIG_DAC_WR_1_SHIFT               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8904_DCS_TRIG_DAC_WR_1_WIDTH               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8904_DCS_TRIG_DAC_WR_0                0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8904_DCS_TRIG_DAC_WR_0_MASK           0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8904_DCS_TRIG_DAC_WR_0_SHIFT               0  /* DCS_TRIG_DAC_WR_0 */
+#define WM8904_DCS_TRIG_DAC_WR_0_WIDTH               1  /* DCS_TRIG_DAC_WR_0 */
+
+/*
+ * R69 (0x45) - DC Servo 2
+ */
+#define WM8904_DCS_TIMER_PERIOD_23_MASK         0x0F00  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8904_DCS_TIMER_PERIOD_23_SHIFT             8  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8904_DCS_TIMER_PERIOD_23_WIDTH             4  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8904_DCS_TIMER_PERIOD_01_MASK         0x000F  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8904_DCS_TIMER_PERIOD_01_SHIFT             0  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8904_DCS_TIMER_PERIOD_01_WIDTH             4  /* DCS_TIMER_PERIOD_01 - [3:0] */
+
+/*
+ * R71 (0x47) - DC Servo 4
+ */
+#define WM8904_DCS_SERIES_NO_23_MASK            0x007F  /* DCS_SERIES_NO_23 - [6:0] */
+#define WM8904_DCS_SERIES_NO_23_SHIFT                0  /* DCS_SERIES_NO_23 - [6:0] */
+#define WM8904_DCS_SERIES_NO_23_WIDTH                7  /* DCS_SERIES_NO_23 - [6:0] */
+
+/*
+ * R72 (0x48) - DC Servo 5
+ */
+#define WM8904_DCS_SERIES_NO_01_MASK            0x007F  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8904_DCS_SERIES_NO_01_SHIFT                0  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8904_DCS_SERIES_NO_01_WIDTH                7  /* DCS_SERIES_NO_01 - [6:0] */
+
+/*
+ * R73 (0x49) - DC Servo 6
+ */
+#define WM8904_DCS_DAC_WR_VAL_3_MASK            0x00FF  /* DCS_DAC_WR_VAL_3 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_3_SHIFT                0  /* DCS_DAC_WR_VAL_3 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_3_WIDTH                8  /* DCS_DAC_WR_VAL_3 - [7:0] */
+
+/*
+ * R74 (0x4A) - DC Servo 7
+ */
+#define WM8904_DCS_DAC_WR_VAL_2_MASK            0x00FF  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_2_SHIFT                0  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_2_WIDTH                8  /* DCS_DAC_WR_VAL_2 - [7:0] */
+
+/*
+ * R75 (0x4B) - DC Servo 8
+ */
+#define WM8904_DCS_DAC_WR_VAL_1_MASK            0x00FF  /* DCS_DAC_WR_VAL_1 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_1_SHIFT                0  /* DCS_DAC_WR_VAL_1 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_1_WIDTH                8  /* DCS_DAC_WR_VAL_1 - [7:0] */
+
+/*
+ * R76 (0x4C) - DC Servo 9
+ */
+#define WM8904_DCS_DAC_WR_VAL_0_MASK            0x00FF  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_0_SHIFT                0  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8904_DCS_DAC_WR_VAL_0_WIDTH                8  /* DCS_DAC_WR_VAL_0 - [7:0] */
+
+/*
+ * R77 (0x4D) - DC Servo Readback 0
+ */
+#define WM8904_DCS_CAL_COMPLETE_MASK            0x0F00  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8904_DCS_CAL_COMPLETE_SHIFT                8  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8904_DCS_CAL_COMPLETE_WIDTH                4  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8904_DCS_DAC_WR_COMPLETE_MASK         0x00F0  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8904_DCS_DAC_WR_COMPLETE_SHIFT             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8904_DCS_DAC_WR_COMPLETE_WIDTH             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8904_DCS_STARTUP_COMPLETE_MASK        0x000F  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8904_DCS_STARTUP_COMPLETE_SHIFT            0  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8904_DCS_STARTUP_COMPLETE_WIDTH            4  /* DCS_STARTUP_COMPLETE - [3:0] */
+
+/*
+ * R90 (0x5A) - Analogue HP 0
+ */
+#define WM8904_HPL_RMV_SHORT                    0x0080  /* HPL_RMV_SHORT */
+#define WM8904_HPL_RMV_SHORT_MASK               0x0080  /* HPL_RMV_SHORT */
+#define WM8904_HPL_RMV_SHORT_SHIFT                   7  /* HPL_RMV_SHORT */
+#define WM8904_HPL_RMV_SHORT_WIDTH                   1  /* HPL_RMV_SHORT */
+#define WM8904_HPL_ENA_OUTP                     0x0040  /* HPL_ENA_OUTP */
+#define WM8904_HPL_ENA_OUTP_MASK                0x0040  /* HPL_ENA_OUTP */
+#define WM8904_HPL_ENA_OUTP_SHIFT                    6  /* HPL_ENA_OUTP */
+#define WM8904_HPL_ENA_OUTP_WIDTH                    1  /* HPL_ENA_OUTP */
+#define WM8904_HPL_ENA_DLY                      0x0020  /* HPL_ENA_DLY */
+#define WM8904_HPL_ENA_DLY_MASK                 0x0020  /* HPL_ENA_DLY */
+#define WM8904_HPL_ENA_DLY_SHIFT                     5  /* HPL_ENA_DLY */
+#define WM8904_HPL_ENA_DLY_WIDTH                     1  /* HPL_ENA_DLY */
+#define WM8904_HPL_ENA                          0x0010  /* HPL_ENA */
+#define WM8904_HPL_ENA_MASK                     0x0010  /* HPL_ENA */
+#define WM8904_HPL_ENA_SHIFT                         4  /* HPL_ENA */
+#define WM8904_HPL_ENA_WIDTH                         1  /* HPL_ENA */
+#define WM8904_HPR_RMV_SHORT                    0x0008  /* HPR_RMV_SHORT */
+#define WM8904_HPR_RMV_SHORT_MASK               0x0008  /* HPR_RMV_SHORT */
+#define WM8904_HPR_RMV_SHORT_SHIFT                   3  /* HPR_RMV_SHORT */
+#define WM8904_HPR_RMV_SHORT_WIDTH                   1  /* HPR_RMV_SHORT */
+#define WM8904_HPR_ENA_OUTP                     0x0004  /* HPR_ENA_OUTP */
+#define WM8904_HPR_ENA_OUTP_MASK                0x0004  /* HPR_ENA_OUTP */
+#define WM8904_HPR_ENA_OUTP_SHIFT                    2  /* HPR_ENA_OUTP */
+#define WM8904_HPR_ENA_OUTP_WIDTH                    1  /* HPR_ENA_OUTP */
+#define WM8904_HPR_ENA_DLY                      0x0002  /* HPR_ENA_DLY */
+#define WM8904_HPR_ENA_DLY_MASK                 0x0002  /* HPR_ENA_DLY */
+#define WM8904_HPR_ENA_DLY_SHIFT                     1  /* HPR_ENA_DLY */
+#define WM8904_HPR_ENA_DLY_WIDTH                     1  /* HPR_ENA_DLY */
+#define WM8904_HPR_ENA                          0x0001  /* HPR_ENA */
+#define WM8904_HPR_ENA_MASK                     0x0001  /* HPR_ENA */
+#define WM8904_HPR_ENA_SHIFT                         0  /* HPR_ENA */
+#define WM8904_HPR_ENA_WIDTH                         1  /* HPR_ENA */
+
+/*
+ * R94 (0x5E) - Analogue Lineout 0
+ */
+#define WM8904_LINEOUTL_RMV_SHORT               0x0080  /* LINEOUTL_RMV_SHORT */
+#define WM8904_LINEOUTL_RMV_SHORT_MASK          0x0080  /* LINEOUTL_RMV_SHORT */
+#define WM8904_LINEOUTL_RMV_SHORT_SHIFT              7  /* LINEOUTL_RMV_SHORT */
+#define WM8904_LINEOUTL_RMV_SHORT_WIDTH              1  /* LINEOUTL_RMV_SHORT */
+#define WM8904_LINEOUTL_ENA_OUTP                0x0040  /* LINEOUTL_ENA_OUTP */
+#define WM8904_LINEOUTL_ENA_OUTP_MASK           0x0040  /* LINEOUTL_ENA_OUTP */
+#define WM8904_LINEOUTL_ENA_OUTP_SHIFT               6  /* LINEOUTL_ENA_OUTP */
+#define WM8904_LINEOUTL_ENA_OUTP_WIDTH               1  /* LINEOUTL_ENA_OUTP */
+#define WM8904_LINEOUTL_ENA_DLY                 0x0020  /* LINEOUTL_ENA_DLY */
+#define WM8904_LINEOUTL_ENA_DLY_MASK            0x0020  /* LINEOUTL_ENA_DLY */
+#define WM8904_LINEOUTL_ENA_DLY_SHIFT                5  /* LINEOUTL_ENA_DLY */
+#define WM8904_LINEOUTL_ENA_DLY_WIDTH                1  /* LINEOUTL_ENA_DLY */
+#define WM8904_LINEOUTL_ENA                     0x0010  /* LINEOUTL_ENA */
+#define WM8904_LINEOUTL_ENA_MASK                0x0010  /* LINEOUTL_ENA */
+#define WM8904_LINEOUTL_ENA_SHIFT                    4  /* LINEOUTL_ENA */
+#define WM8904_LINEOUTL_ENA_WIDTH                    1  /* LINEOUTL_ENA */
+#define WM8904_LINEOUTR_RMV_SHORT               0x0008  /* LINEOUTR_RMV_SHORT */
+#define WM8904_LINEOUTR_RMV_SHORT_MASK          0x0008  /* LINEOUTR_RMV_SHORT */
+#define WM8904_LINEOUTR_RMV_SHORT_SHIFT              3  /* LINEOUTR_RMV_SHORT */
+#define WM8904_LINEOUTR_RMV_SHORT_WIDTH              1  /* LINEOUTR_RMV_SHORT */
+#define WM8904_LINEOUTR_ENA_OUTP                0x0004  /* LINEOUTR_ENA_OUTP */
+#define WM8904_LINEOUTR_ENA_OUTP_MASK           0x0004  /* LINEOUTR_ENA_OUTP */
+#define WM8904_LINEOUTR_ENA_OUTP_SHIFT               2  /* LINEOUTR_ENA_OUTP */
+#define WM8904_LINEOUTR_ENA_OUTP_WIDTH               1  /* LINEOUTR_ENA_OUTP */
+#define WM8904_LINEOUTR_ENA_DLY                 0x0002  /* LINEOUTR_ENA_DLY */
+#define WM8904_LINEOUTR_ENA_DLY_MASK            0x0002  /* LINEOUTR_ENA_DLY */
+#define WM8904_LINEOUTR_ENA_DLY_SHIFT                1  /* LINEOUTR_ENA_DLY */
+#define WM8904_LINEOUTR_ENA_DLY_WIDTH                1  /* LINEOUTR_ENA_DLY */
+#define WM8904_LINEOUTR_ENA                     0x0001  /* LINEOUTR_ENA */
+#define WM8904_LINEOUTR_ENA_MASK                0x0001  /* LINEOUTR_ENA */
+#define WM8904_LINEOUTR_ENA_SHIFT                    0  /* LINEOUTR_ENA */
+#define WM8904_LINEOUTR_ENA_WIDTH                    1  /* LINEOUTR_ENA */
+
+/*
+ * R98 (0x62) - Charge Pump 0
+ */
+#define WM8904_CP_ENA                           0x0001  /* CP_ENA */
+#define WM8904_CP_ENA_MASK                      0x0001  /* CP_ENA */
+#define WM8904_CP_ENA_SHIFT                          0  /* CP_ENA */
+#define WM8904_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R104 (0x68) - Class W 0
+ */
+#define WM8904_CP_DYN_PWR                       0x0001  /* CP_DYN_PWR */
+#define WM8904_CP_DYN_PWR_MASK                  0x0001  /* CP_DYN_PWR */
+#define WM8904_CP_DYN_PWR_SHIFT                      0  /* CP_DYN_PWR */
+#define WM8904_CP_DYN_PWR_WIDTH                      1  /* CP_DYN_PWR */
+
+/*
+ * R108 (0x6C) - Write Sequencer 0
+ */
+#define WM8904_WSEQ_ENA                         0x0100  /* WSEQ_ENA */
+#define WM8904_WSEQ_ENA_MASK                    0x0100  /* WSEQ_ENA */
+#define WM8904_WSEQ_ENA_SHIFT                        8  /* WSEQ_ENA */
+#define WM8904_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM8904_WSEQ_WRITE_INDEX_MASK            0x001F  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8904_WSEQ_WRITE_INDEX_SHIFT                0  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8904_WSEQ_WRITE_INDEX_WIDTH                5  /* WSEQ_WRITE_INDEX - [4:0] */
+
+/*
+ * R109 (0x6D) - Write Sequencer 1
+ */
+#define WM8904_WSEQ_DATA_WIDTH_MASK             0x7000  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8904_WSEQ_DATA_WIDTH_SHIFT                12  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8904_WSEQ_DATA_WIDTH_WIDTH                 3  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8904_WSEQ_DATA_START_MASK             0x0F00  /* WSEQ_DATA_START - [11:8] */
+#define WM8904_WSEQ_DATA_START_SHIFT                 8  /* WSEQ_DATA_START - [11:8] */
+#define WM8904_WSEQ_DATA_START_WIDTH                 4  /* WSEQ_DATA_START - [11:8] */
+#define WM8904_WSEQ_ADDR_MASK                   0x00FF  /* WSEQ_ADDR - [7:0] */
+#define WM8904_WSEQ_ADDR_SHIFT                       0  /* WSEQ_ADDR - [7:0] */
+#define WM8904_WSEQ_ADDR_WIDTH                       8  /* WSEQ_ADDR - [7:0] */
+
+/*
+ * R110 (0x6E) - Write Sequencer 2
+ */
+#define WM8904_WSEQ_EOS                         0x4000  /* WSEQ_EOS */
+#define WM8904_WSEQ_EOS_MASK                    0x4000  /* WSEQ_EOS */
+#define WM8904_WSEQ_EOS_SHIFT                       14  /* WSEQ_EOS */
+#define WM8904_WSEQ_EOS_WIDTH                        1  /* WSEQ_EOS */
+#define WM8904_WSEQ_DELAY_MASK                  0x0F00  /* WSEQ_DELAY - [11:8] */
+#define WM8904_WSEQ_DELAY_SHIFT                      8  /* WSEQ_DELAY - [11:8] */
+#define WM8904_WSEQ_DELAY_WIDTH                      4  /* WSEQ_DELAY - [11:8] */
+#define WM8904_WSEQ_DATA_MASK                   0x00FF  /* WSEQ_DATA - [7:0] */
+#define WM8904_WSEQ_DATA_SHIFT                       0  /* WSEQ_DATA - [7:0] */
+#define WM8904_WSEQ_DATA_WIDTH                       8  /* WSEQ_DATA - [7:0] */
+
+/*
+ * R111 (0x6F) - Write Sequencer 3
+ */
+#define WM8904_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM8904_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM8904_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM8904_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8904_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM8904_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM8904_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM8904_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8904_WSEQ_START_INDEX_MASK            0x003F  /* WSEQ_START_INDEX - [5:0] */
+#define WM8904_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [5:0] */
+#define WM8904_WSEQ_START_INDEX_WIDTH                6  /* WSEQ_START_INDEX - [5:0] */
+
+/*
+ * R112 (0x70) - Write Sequencer 4
+ */
+#define WM8904_WSEQ_CURRENT_INDEX_MASK          0x03F0  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8904_WSEQ_CURRENT_INDEX_SHIFT              4  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8904_WSEQ_CURRENT_INDEX_WIDTH              6  /* WSEQ_CURRENT_INDEX - [9:4] */
+#define WM8904_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM8904_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM8904_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM8904_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R116 (0x74) - FLL Control 1
+ */
+#define WM8904_FLL_FRACN_ENA                    0x0004  /* FLL_FRACN_ENA */
+#define WM8904_FLL_FRACN_ENA_MASK               0x0004  /* FLL_FRACN_ENA */
+#define WM8904_FLL_FRACN_ENA_SHIFT                   2  /* FLL_FRACN_ENA */
+#define WM8904_FLL_FRACN_ENA_WIDTH                   1  /* FLL_FRACN_ENA */
+#define WM8904_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM8904_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM8904_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM8904_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8904_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM8904_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM8904_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM8904_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R117 (0x75) - FLL Control 2
+ */
+#define WM8904_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
+#define WM8904_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
+#define WM8904_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
+#define WM8904_FLL_CTRL_RATE_MASK               0x0070  /* FLL_CTRL_RATE - [6:4] */
+#define WM8904_FLL_CTRL_RATE_SHIFT                   4  /* FLL_CTRL_RATE - [6:4] */
+#define WM8904_FLL_CTRL_RATE_WIDTH                   3  /* FLL_CTRL_RATE - [6:4] */
+#define WM8904_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM8904_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM8904_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R118 (0x76) - FLL Control 3
+ */
+#define WM8904_FLL_K_MASK                       0xFFFF  /* FLL_K - [15:0] */
+#define WM8904_FLL_K_SHIFT                           0  /* FLL_K - [15:0] */
+#define WM8904_FLL_K_WIDTH                          16  /* FLL_K - [15:0] */
+
+/*
+ * R119 (0x77) - FLL Control 4
+ */
+#define WM8904_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM8904_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM8904_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM8904_FLL_GAIN_MASK                    0x000F  /* FLL_GAIN - [3:0] */
+#define WM8904_FLL_GAIN_SHIFT                        0  /* FLL_GAIN - [3:0] */
+#define WM8904_FLL_GAIN_WIDTH                        4  /* FLL_GAIN - [3:0] */
+
+/*
+ * R120 (0x78) - FLL Control 5
+ */
+#define WM8904_FLL_CLK_REF_DIV_MASK             0x0018  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8904_FLL_CLK_REF_DIV_SHIFT                 3  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8904_FLL_CLK_REF_DIV_WIDTH                 2  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8904_FLL_CLK_REF_SRC_MASK             0x0003  /* FLL_CLK_REF_SRC - [1:0] */
+#define WM8904_FLL_CLK_REF_SRC_SHIFT                 0  /* FLL_CLK_REF_SRC - [1:0] */
+#define WM8904_FLL_CLK_REF_SRC_WIDTH                 2  /* FLL_CLK_REF_SRC - [1:0] */
+
+/*
+ * R126 (0x7E) - Digital Pulls
+ */
+#define WM8904_MCLK_PU                          0x0080  /* MCLK_PU */
+#define WM8904_MCLK_PU_MASK                     0x0080  /* MCLK_PU */
+#define WM8904_MCLK_PU_SHIFT                         7  /* MCLK_PU */
+#define WM8904_MCLK_PU_WIDTH                         1  /* MCLK_PU */
+#define WM8904_MCLK_PD                          0x0040  /* MCLK_PD */
+#define WM8904_MCLK_PD_MASK                     0x0040  /* MCLK_PD */
+#define WM8904_MCLK_PD_SHIFT                         6  /* MCLK_PD */
+#define WM8904_MCLK_PD_WIDTH                         1  /* MCLK_PD */
+#define WM8904_DACDAT_PU                        0x0020  /* DACDAT_PU */
+#define WM8904_DACDAT_PU_MASK                   0x0020  /* DACDAT_PU */
+#define WM8904_DACDAT_PU_SHIFT                       5  /* DACDAT_PU */
+#define WM8904_DACDAT_PU_WIDTH                       1  /* DACDAT_PU */
+#define WM8904_DACDAT_PD                        0x0010  /* DACDAT_PD */
+#define WM8904_DACDAT_PD_MASK                   0x0010  /* DACDAT_PD */
+#define WM8904_DACDAT_PD_SHIFT                       4  /* DACDAT_PD */
+#define WM8904_DACDAT_PD_WIDTH                       1  /* DACDAT_PD */
+#define WM8904_LRCLK_PU                         0x0008  /* LRCLK_PU */
+#define WM8904_LRCLK_PU_MASK                    0x0008  /* LRCLK_PU */
+#define WM8904_LRCLK_PU_SHIFT                        3  /* LRCLK_PU */
+#define WM8904_LRCLK_PU_WIDTH                        1  /* LRCLK_PU */
+#define WM8904_LRCLK_PD                         0x0004  /* LRCLK_PD */
+#define WM8904_LRCLK_PD_MASK                    0x0004  /* LRCLK_PD */
+#define WM8904_LRCLK_PD_SHIFT                        2  /* LRCLK_PD */
+#define WM8904_LRCLK_PD_WIDTH                        1  /* LRCLK_PD */
+#define WM8904_BCLK_PU                          0x0002  /* BCLK_PU */
+#define WM8904_BCLK_PU_MASK                     0x0002  /* BCLK_PU */
+#define WM8904_BCLK_PU_SHIFT                         1  /* BCLK_PU */
+#define WM8904_BCLK_PU_WIDTH                         1  /* BCLK_PU */
+#define WM8904_BCLK_PD                          0x0001  /* BCLK_PD */
+#define WM8904_BCLK_PD_MASK                     0x0001  /* BCLK_PD */
+#define WM8904_BCLK_PD_SHIFT                         0  /* BCLK_PD */
+#define WM8904_BCLK_PD_WIDTH                         1  /* BCLK_PD */
+
+/*
+ * R127 (0x7F) - Interrupt Status
+ */
+#define WM8904_IRQ                              0x0400  /* IRQ */
+#define WM8904_IRQ_MASK                         0x0400  /* IRQ */
+#define WM8904_IRQ_SHIFT                            10  /* IRQ */
+#define WM8904_IRQ_WIDTH                             1  /* IRQ */
+#define WM8904_GPIO_BCLK_EINT                   0x0200  /* GPIO_BCLK_EINT */
+#define WM8904_GPIO_BCLK_EINT_MASK              0x0200  /* GPIO_BCLK_EINT */
+#define WM8904_GPIO_BCLK_EINT_SHIFT                  9  /* GPIO_BCLK_EINT */
+#define WM8904_GPIO_BCLK_EINT_WIDTH                  1  /* GPIO_BCLK_EINT */
+#define WM8904_WSEQ_EINT                        0x0100  /* WSEQ_EINT */
+#define WM8904_WSEQ_EINT_MASK                   0x0100  /* WSEQ_EINT */
+#define WM8904_WSEQ_EINT_SHIFT                       8  /* WSEQ_EINT */
+#define WM8904_WSEQ_EINT_WIDTH                       1  /* WSEQ_EINT */
+#define WM8904_GPIO3_EINT                       0x0080  /* GPIO3_EINT */
+#define WM8904_GPIO3_EINT_MASK                  0x0080  /* GPIO3_EINT */
+#define WM8904_GPIO3_EINT_SHIFT                      7  /* GPIO3_EINT */
+#define WM8904_GPIO3_EINT_WIDTH                      1  /* GPIO3_EINT */
+#define WM8904_GPIO2_EINT                       0x0040  /* GPIO2_EINT */
+#define WM8904_GPIO2_EINT_MASK                  0x0040  /* GPIO2_EINT */
+#define WM8904_GPIO2_EINT_SHIFT                      6  /* GPIO2_EINT */
+#define WM8904_GPIO2_EINT_WIDTH                      1  /* GPIO2_EINT */
+#define WM8904_GPIO1_EINT                       0x0020  /* GPIO1_EINT */
+#define WM8904_GPIO1_EINT_MASK                  0x0020  /* GPIO1_EINT */
+#define WM8904_GPIO1_EINT_SHIFT                      5  /* GPIO1_EINT */
+#define WM8904_GPIO1_EINT_WIDTH                      1  /* GPIO1_EINT */
+#define WM8904_GPI8_EINT                        0x0010  /* GPI8_EINT */
+#define WM8904_GPI8_EINT_MASK                   0x0010  /* GPI8_EINT */
+#define WM8904_GPI8_EINT_SHIFT                       4  /* GPI8_EINT */
+#define WM8904_GPI8_EINT_WIDTH                       1  /* GPI8_EINT */
+#define WM8904_GPI7_EINT                        0x0008  /* GPI7_EINT */
+#define WM8904_GPI7_EINT_MASK                   0x0008  /* GPI7_EINT */
+#define WM8904_GPI7_EINT_SHIFT                       3  /* GPI7_EINT */
+#define WM8904_GPI7_EINT_WIDTH                       1  /* GPI7_EINT */
+#define WM8904_FLL_LOCK_EINT                    0x0004  /* FLL_LOCK_EINT */
+#define WM8904_FLL_LOCK_EINT_MASK               0x0004  /* FLL_LOCK_EINT */
+#define WM8904_FLL_LOCK_EINT_SHIFT                   2  /* FLL_LOCK_EINT */
+#define WM8904_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM8904_MIC_SHRT_EINT                    0x0002  /* MIC_SHRT_EINT */
+#define WM8904_MIC_SHRT_EINT_MASK               0x0002  /* MIC_SHRT_EINT */
+#define WM8904_MIC_SHRT_EINT_SHIFT                   1  /* MIC_SHRT_EINT */
+#define WM8904_MIC_SHRT_EINT_WIDTH                   1  /* MIC_SHRT_EINT */
+#define WM8904_MIC_DET_EINT                     0x0001  /* MIC_DET_EINT */
+#define WM8904_MIC_DET_EINT_MASK                0x0001  /* MIC_DET_EINT */
+#define WM8904_MIC_DET_EINT_SHIFT                    0  /* MIC_DET_EINT */
+#define WM8904_MIC_DET_EINT_WIDTH                    1  /* MIC_DET_EINT */
+
+/*
+ * R128 (0x80) - Interrupt Status Mask
+ */
+#define WM8904_IM_GPIO_BCLK_EINT                0x0200  /* IM_GPIO_BCLK_EINT */
+#define WM8904_IM_GPIO_BCLK_EINT_MASK           0x0200  /* IM_GPIO_BCLK_EINT */
+#define WM8904_IM_GPIO_BCLK_EINT_SHIFT               9  /* IM_GPIO_BCLK_EINT */
+#define WM8904_IM_GPIO_BCLK_EINT_WIDTH               1  /* IM_GPIO_BCLK_EINT */
+#define WM8904_IM_WSEQ_EINT                     0x0100  /* IM_WSEQ_EINT */
+#define WM8904_IM_WSEQ_EINT_MASK                0x0100  /* IM_WSEQ_EINT */
+#define WM8904_IM_WSEQ_EINT_SHIFT                    8  /* IM_WSEQ_EINT */
+#define WM8904_IM_WSEQ_EINT_WIDTH                    1  /* IM_WSEQ_EINT */
+#define WM8904_IM_GPIO3_EINT                    0x0080  /* IM_GPIO3_EINT */
+#define WM8904_IM_GPIO3_EINT_MASK               0x0080  /* IM_GPIO3_EINT */
+#define WM8904_IM_GPIO3_EINT_SHIFT                   7  /* IM_GPIO3_EINT */
+#define WM8904_IM_GPIO3_EINT_WIDTH                   1  /* IM_GPIO3_EINT */
+#define WM8904_IM_GPIO2_EINT                    0x0040  /* IM_GPIO2_EINT */
+#define WM8904_IM_GPIO2_EINT_MASK               0x0040  /* IM_GPIO2_EINT */
+#define WM8904_IM_GPIO2_EINT_SHIFT                   6  /* IM_GPIO2_EINT */
+#define WM8904_IM_GPIO2_EINT_WIDTH                   1  /* IM_GPIO2_EINT */
+#define WM8904_IM_GPIO1_EINT                    0x0020  /* IM_GPIO1_EINT */
+#define WM8904_IM_GPIO1_EINT_MASK               0x0020  /* IM_GPIO1_EINT */
+#define WM8904_IM_GPIO1_EINT_SHIFT                   5  /* IM_GPIO1_EINT */
+#define WM8904_IM_GPIO1_EINT_WIDTH                   1  /* IM_GPIO1_EINT */
+#define WM8904_IM_GPI8_EINT                     0x0010  /* IM_GPI8_EINT */
+#define WM8904_IM_GPI8_EINT_MASK                0x0010  /* IM_GPI8_EINT */
+#define WM8904_IM_GPI8_EINT_SHIFT                    4  /* IM_GPI8_EINT */
+#define WM8904_IM_GPI8_EINT_WIDTH                    1  /* IM_GPI8_EINT */
+#define WM8904_IM_GPI7_EINT                     0x0008  /* IM_GPI7_EINT */
+#define WM8904_IM_GPI7_EINT_MASK                0x0008  /* IM_GPI7_EINT */
+#define WM8904_IM_GPI7_EINT_SHIFT                    3  /* IM_GPI7_EINT */
+#define WM8904_IM_GPI7_EINT_WIDTH                    1  /* IM_GPI7_EINT */
+#define WM8904_IM_FLL_LOCK_EINT                 0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8904_IM_FLL_LOCK_EINT_MASK            0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8904_IM_FLL_LOCK_EINT_SHIFT                2  /* IM_FLL_LOCK_EINT */
+#define WM8904_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM8904_IM_MIC_SHRT_EINT                 0x0002  /* IM_MIC_SHRT_EINT */
+#define WM8904_IM_MIC_SHRT_EINT_MASK            0x0002  /* IM_MIC_SHRT_EINT */
+#define WM8904_IM_MIC_SHRT_EINT_SHIFT                1  /* IM_MIC_SHRT_EINT */
+#define WM8904_IM_MIC_SHRT_EINT_WIDTH                1  /* IM_MIC_SHRT_EINT */
+#define WM8904_IM_MIC_DET_EINT                  0x0001  /* IM_MIC_DET_EINT */
+#define WM8904_IM_MIC_DET_EINT_MASK             0x0001  /* IM_MIC_DET_EINT */
+#define WM8904_IM_MIC_DET_EINT_SHIFT                 0  /* IM_MIC_DET_EINT */
+#define WM8904_IM_MIC_DET_EINT_WIDTH                 1  /* IM_MIC_DET_EINT */
+
+/*
+ * R129 (0x81) - Interrupt Polarity
+ */
+#define WM8904_GPIO_BCLK_EINT_POL               0x0200  /* GPIO_BCLK_EINT_POL */
+#define WM8904_GPIO_BCLK_EINT_POL_MASK          0x0200  /* GPIO_BCLK_EINT_POL */
+#define WM8904_GPIO_BCLK_EINT_POL_SHIFT              9  /* GPIO_BCLK_EINT_POL */
+#define WM8904_GPIO_BCLK_EINT_POL_WIDTH              1  /* GPIO_BCLK_EINT_POL */
+#define WM8904_WSEQ_EINT_POL                    0x0100  /* WSEQ_EINT_POL */
+#define WM8904_WSEQ_EINT_POL_MASK               0x0100  /* WSEQ_EINT_POL */
+#define WM8904_WSEQ_EINT_POL_SHIFT                   8  /* WSEQ_EINT_POL */
+#define WM8904_WSEQ_EINT_POL_WIDTH                   1  /* WSEQ_EINT_POL */
+#define WM8904_GPIO3_EINT_POL                   0x0080  /* GPIO3_EINT_POL */
+#define WM8904_GPIO3_EINT_POL_MASK              0x0080  /* GPIO3_EINT_POL */
+#define WM8904_GPIO3_EINT_POL_SHIFT                  7  /* GPIO3_EINT_POL */
+#define WM8904_GPIO3_EINT_POL_WIDTH                  1  /* GPIO3_EINT_POL */
+#define WM8904_GPIO2_EINT_POL                   0x0040  /* GPIO2_EINT_POL */
+#define WM8904_GPIO2_EINT_POL_MASK              0x0040  /* GPIO2_EINT_POL */
+#define WM8904_GPIO2_EINT_POL_SHIFT                  6  /* GPIO2_EINT_POL */
+#define WM8904_GPIO2_EINT_POL_WIDTH                  1  /* GPIO2_EINT_POL */
+#define WM8904_GPIO1_EINT_POL                   0x0020  /* GPIO1_EINT_POL */
+#define WM8904_GPIO1_EINT_POL_MASK              0x0020  /* GPIO1_EINT_POL */
+#define WM8904_GPIO1_EINT_POL_SHIFT                  5  /* GPIO1_EINT_POL */
+#define WM8904_GPIO1_EINT_POL_WIDTH                  1  /* GPIO1_EINT_POL */
+#define WM8904_GPI8_EINT_POL                    0x0010  /* GPI8_EINT_POL */
+#define WM8904_GPI8_EINT_POL_MASK               0x0010  /* GPI8_EINT_POL */
+#define WM8904_GPI8_EINT_POL_SHIFT                   4  /* GPI8_EINT_POL */
+#define WM8904_GPI8_EINT_POL_WIDTH                   1  /* GPI8_EINT_POL */
+#define WM8904_GPI7_EINT_POL                    0x0008  /* GPI7_EINT_POL */
+#define WM8904_GPI7_EINT_POL_MASK               0x0008  /* GPI7_EINT_POL */
+#define WM8904_GPI7_EINT_POL_SHIFT                   3  /* GPI7_EINT_POL */
+#define WM8904_GPI7_EINT_POL_WIDTH                   1  /* GPI7_EINT_POL */
+#define WM8904_FLL_LOCK_EINT_POL                0x0004  /* FLL_LOCK_EINT_POL */
+#define WM8904_FLL_LOCK_EINT_POL_MASK           0x0004  /* FLL_LOCK_EINT_POL */
+#define WM8904_FLL_LOCK_EINT_POL_SHIFT               2  /* FLL_LOCK_EINT_POL */
+#define WM8904_FLL_LOCK_EINT_POL_WIDTH               1  /* FLL_LOCK_EINT_POL */
+#define WM8904_MIC_SHRT_EINT_POL                0x0002  /* MIC_SHRT_EINT_POL */
+#define WM8904_MIC_SHRT_EINT_POL_MASK           0x0002  /* MIC_SHRT_EINT_POL */
+#define WM8904_MIC_SHRT_EINT_POL_SHIFT               1  /* MIC_SHRT_EINT_POL */
+#define WM8904_MIC_SHRT_EINT_POL_WIDTH               1  /* MIC_SHRT_EINT_POL */
+#define WM8904_MIC_DET_EINT_POL                 0x0001  /* MIC_DET_EINT_POL */
+#define WM8904_MIC_DET_EINT_POL_MASK            0x0001  /* MIC_DET_EINT_POL */
+#define WM8904_MIC_DET_EINT_POL_SHIFT                0  /* MIC_DET_EINT_POL */
+#define WM8904_MIC_DET_EINT_POL_WIDTH                1  /* MIC_DET_EINT_POL */
+
+/*
+ * R130 (0x82) - Interrupt Debounce
+ */
+#define WM8904_GPIO_BCLK_EINT_DB                0x0200  /* GPIO_BCLK_EINT_DB */
+#define WM8904_GPIO_BCLK_EINT_DB_MASK           0x0200  /* GPIO_BCLK_EINT_DB */
+#define WM8904_GPIO_BCLK_EINT_DB_SHIFT               9  /* GPIO_BCLK_EINT_DB */
+#define WM8904_GPIO_BCLK_EINT_DB_WIDTH               1  /* GPIO_BCLK_EINT_DB */
+#define WM8904_WSEQ_EINT_DB                     0x0100  /* WSEQ_EINT_DB */
+#define WM8904_WSEQ_EINT_DB_MASK                0x0100  /* WSEQ_EINT_DB */
+#define WM8904_WSEQ_EINT_DB_SHIFT                    8  /* WSEQ_EINT_DB */
+#define WM8904_WSEQ_EINT_DB_WIDTH                    1  /* WSEQ_EINT_DB */
+#define WM8904_GPIO3_EINT_DB                    0x0080  /* GPIO3_EINT_DB */
+#define WM8904_GPIO3_EINT_DB_MASK               0x0080  /* GPIO3_EINT_DB */
+#define WM8904_GPIO3_EINT_DB_SHIFT                   7  /* GPIO3_EINT_DB */
+#define WM8904_GPIO3_EINT_DB_WIDTH                   1  /* GPIO3_EINT_DB */
+#define WM8904_GPIO2_EINT_DB                    0x0040  /* GPIO2_EINT_DB */
+#define WM8904_GPIO2_EINT_DB_MASK               0x0040  /* GPIO2_EINT_DB */
+#define WM8904_GPIO2_EINT_DB_SHIFT                   6  /* GPIO2_EINT_DB */
+#define WM8904_GPIO2_EINT_DB_WIDTH                   1  /* GPIO2_EINT_DB */
+#define WM8904_GPIO1_EINT_DB                    0x0020  /* GPIO1_EINT_DB */
+#define WM8904_GPIO1_EINT_DB_MASK               0x0020  /* GPIO1_EINT_DB */
+#define WM8904_GPIO1_EINT_DB_SHIFT                   5  /* GPIO1_EINT_DB */
+#define WM8904_GPIO1_EINT_DB_WIDTH                   1  /* GPIO1_EINT_DB */
+#define WM8904_GPI8_EINT_DB                     0x0010  /* GPI8_EINT_DB */
+#define WM8904_GPI8_EINT_DB_MASK                0x0010  /* GPI8_EINT_DB */
+#define WM8904_GPI8_EINT_DB_SHIFT                    4  /* GPI8_EINT_DB */
+#define WM8904_GPI8_EINT_DB_WIDTH                    1  /* GPI8_EINT_DB */
+#define WM8904_GPI7_EINT_DB                     0x0008  /* GPI7_EINT_DB */
+#define WM8904_GPI7_EINT_DB_MASK                0x0008  /* GPI7_EINT_DB */
+#define WM8904_GPI7_EINT_DB_SHIFT                    3  /* GPI7_EINT_DB */
+#define WM8904_GPI7_EINT_DB_WIDTH                    1  /* GPI7_EINT_DB */
+#define WM8904_FLL_LOCK_EINT_DB                 0x0004  /* FLL_LOCK_EINT_DB */
+#define WM8904_FLL_LOCK_EINT_DB_MASK            0x0004  /* FLL_LOCK_EINT_DB */
+#define WM8904_FLL_LOCK_EINT_DB_SHIFT                2  /* FLL_LOCK_EINT_DB */
+#define WM8904_FLL_LOCK_EINT_DB_WIDTH                1  /* FLL_LOCK_EINT_DB */
+#define WM8904_MIC_SHRT_EINT_DB                 0x0002  /* MIC_SHRT_EINT_DB */
+#define WM8904_MIC_SHRT_EINT_DB_MASK            0x0002  /* MIC_SHRT_EINT_DB */
+#define WM8904_MIC_SHRT_EINT_DB_SHIFT                1  /* MIC_SHRT_EINT_DB */
+#define WM8904_MIC_SHRT_EINT_DB_WIDTH                1  /* MIC_SHRT_EINT_DB */
+#define WM8904_MIC_DET_EINT_DB                  0x0001  /* MIC_DET_EINT_DB */
+#define WM8904_MIC_DET_EINT_DB_MASK             0x0001  /* MIC_DET_EINT_DB */
+#define WM8904_MIC_DET_EINT_DB_SHIFT                 0  /* MIC_DET_EINT_DB */
+#define WM8904_MIC_DET_EINT_DB_WIDTH                 1  /* MIC_DET_EINT_DB */
+
+/*
+ * R134 (0x86) - EQ1
+ */
+#define WM8904_EQ_ENA                           0x0001  /* EQ_ENA */
+#define WM8904_EQ_ENA_MASK                      0x0001  /* EQ_ENA */
+#define WM8904_EQ_ENA_SHIFT                          0  /* EQ_ENA */
+#define WM8904_EQ_ENA_WIDTH                          1  /* EQ_ENA */
+
+/*
+ * R135 (0x87) - EQ2
+ */
+#define WM8904_EQ_B1_GAIN_MASK                  0x001F  /* EQ_B1_GAIN - [4:0] */
+#define WM8904_EQ_B1_GAIN_SHIFT                      0  /* EQ_B1_GAIN - [4:0] */
+#define WM8904_EQ_B1_GAIN_WIDTH                      5  /* EQ_B1_GAIN - [4:0] */
+
+/*
+ * R136 (0x88) - EQ3
+ */
+#define WM8904_EQ_B2_GAIN_MASK                  0x001F  /* EQ_B2_GAIN - [4:0] */
+#define WM8904_EQ_B2_GAIN_SHIFT                      0  /* EQ_B2_GAIN - [4:0] */
+#define WM8904_EQ_B2_GAIN_WIDTH                      5  /* EQ_B2_GAIN - [4:0] */
+
+/*
+ * R137 (0x89) - EQ4
+ */
+#define WM8904_EQ_B3_GAIN_MASK                  0x001F  /* EQ_B3_GAIN - [4:0] */
+#define WM8904_EQ_B3_GAIN_SHIFT                      0  /* EQ_B3_GAIN - [4:0] */
+#define WM8904_EQ_B3_GAIN_WIDTH                      5  /* EQ_B3_GAIN - [4:0] */
+
+/*
+ * R138 (0x8A) - EQ5
+ */
+#define WM8904_EQ_B4_GAIN_MASK                  0x001F  /* EQ_B4_GAIN - [4:0] */
+#define WM8904_EQ_B4_GAIN_SHIFT                      0  /* EQ_B4_GAIN - [4:0] */
+#define WM8904_EQ_B4_GAIN_WIDTH                      5  /* EQ_B4_GAIN - [4:0] */
+
+/*
+ * R139 (0x8B) - EQ6
+ */
+#define WM8904_EQ_B5_GAIN_MASK                  0x001F  /* EQ_B5_GAIN - [4:0] */
+#define WM8904_EQ_B5_GAIN_SHIFT                      0  /* EQ_B5_GAIN - [4:0] */
+#define WM8904_EQ_B5_GAIN_WIDTH                      5  /* EQ_B5_GAIN - [4:0] */
+
+/*
+ * R140 (0x8C) - EQ7
+ */
+#define WM8904_EQ_B1_A_MASK                     0xFFFF  /* EQ_B1_A - [15:0] */
+#define WM8904_EQ_B1_A_SHIFT                         0  /* EQ_B1_A - [15:0] */
+#define WM8904_EQ_B1_A_WIDTH                        16  /* EQ_B1_A - [15:0] */
+
+/*
+ * R141 (0x8D) - EQ8
+ */
+#define WM8904_EQ_B1_B_MASK                     0xFFFF  /* EQ_B1_B - [15:0] */
+#define WM8904_EQ_B1_B_SHIFT                         0  /* EQ_B1_B - [15:0] */
+#define WM8904_EQ_B1_B_WIDTH                        16  /* EQ_B1_B - [15:0] */
+
+/*
+ * R142 (0x8E) - EQ9
+ */
+#define WM8904_EQ_B1_PG_MASK                    0xFFFF  /* EQ_B1_PG - [15:0] */
+#define WM8904_EQ_B1_PG_SHIFT                        0  /* EQ_B1_PG - [15:0] */
+#define WM8904_EQ_B1_PG_WIDTH                       16  /* EQ_B1_PG - [15:0] */
+
+/*
+ * R143 (0x8F) - EQ10
+ */
+#define WM8904_EQ_B2_A_MASK                     0xFFFF  /* EQ_B2_A - [15:0] */
+#define WM8904_EQ_B2_A_SHIFT                         0  /* EQ_B2_A - [15:0] */
+#define WM8904_EQ_B2_A_WIDTH                        16  /* EQ_B2_A - [15:0] */
+
+/*
+ * R144 (0x90) - EQ11
+ */
+#define WM8904_EQ_B2_B_MASK                     0xFFFF  /* EQ_B2_B - [15:0] */
+#define WM8904_EQ_B2_B_SHIFT                         0  /* EQ_B2_B - [15:0] */
+#define WM8904_EQ_B2_B_WIDTH                        16  /* EQ_B2_B - [15:0] */
+
+/*
+ * R145 (0x91) - EQ12
+ */
+#define WM8904_EQ_B2_C_MASK                     0xFFFF  /* EQ_B2_C - [15:0] */
+#define WM8904_EQ_B2_C_SHIFT                         0  /* EQ_B2_C - [15:0] */
+#define WM8904_EQ_B2_C_WIDTH                        16  /* EQ_B2_C - [15:0] */
+
+/*
+ * R146 (0x92) - EQ13
+ */
+#define WM8904_EQ_B2_PG_MASK                    0xFFFF  /* EQ_B2_PG - [15:0] */
+#define WM8904_EQ_B2_PG_SHIFT                        0  /* EQ_B2_PG - [15:0] */
+#define WM8904_EQ_B2_PG_WIDTH                       16  /* EQ_B2_PG - [15:0] */
+
+/*
+ * R147 (0x93) - EQ14
+ */
+#define WM8904_EQ_B3_A_MASK                     0xFFFF  /* EQ_B3_A - [15:0] */
+#define WM8904_EQ_B3_A_SHIFT                         0  /* EQ_B3_A - [15:0] */
+#define WM8904_EQ_B3_A_WIDTH                        16  /* EQ_B3_A - [15:0] */
+
+/*
+ * R148 (0x94) - EQ15
+ */
+#define WM8904_EQ_B3_B_MASK                     0xFFFF  /* EQ_B3_B - [15:0] */
+#define WM8904_EQ_B3_B_SHIFT                         0  /* EQ_B3_B - [15:0] */
+#define WM8904_EQ_B3_B_WIDTH                        16  /* EQ_B3_B - [15:0] */
+
+/*
+ * R149 (0x95) - EQ16
+ */
+#define WM8904_EQ_B3_C_MASK                     0xFFFF  /* EQ_B3_C - [15:0] */
+#define WM8904_EQ_B3_C_SHIFT                         0  /* EQ_B3_C - [15:0] */
+#define WM8904_EQ_B3_C_WIDTH                        16  /* EQ_B3_C - [15:0] */
+
+/*
+ * R150 (0x96) - EQ17
+ */
+#define WM8904_EQ_B3_PG_MASK                    0xFFFF  /* EQ_B3_PG - [15:0] */
+#define WM8904_EQ_B3_PG_SHIFT                        0  /* EQ_B3_PG - [15:0] */
+#define WM8904_EQ_B3_PG_WIDTH                       16  /* EQ_B3_PG - [15:0] */
+
+/*
+ * R151 (0x97) - EQ18
+ */
+#define WM8904_EQ_B4_A_MASK                     0xFFFF  /* EQ_B4_A - [15:0] */
+#define WM8904_EQ_B4_A_SHIFT                         0  /* EQ_B4_A - [15:0] */
+#define WM8904_EQ_B4_A_WIDTH                        16  /* EQ_B4_A - [15:0] */
+
+/*
+ * R152 (0x98) - EQ19
+ */
+#define WM8904_EQ_B4_B_MASK                     0xFFFF  /* EQ_B4_B - [15:0] */
+#define WM8904_EQ_B4_B_SHIFT                         0  /* EQ_B4_B - [15:0] */
+#define WM8904_EQ_B4_B_WIDTH                        16  /* EQ_B4_B - [15:0] */
+
+/*
+ * R153 (0x99) - EQ20
+ */
+#define WM8904_EQ_B4_C_MASK                     0xFFFF  /* EQ_B4_C - [15:0] */
+#define WM8904_EQ_B4_C_SHIFT                         0  /* EQ_B4_C - [15:0] */
+#define WM8904_EQ_B4_C_WIDTH                        16  /* EQ_B4_C - [15:0] */
+
+/*
+ * R154 (0x9A) - EQ21
+ */
+#define WM8904_EQ_B4_PG_MASK                    0xFFFF  /* EQ_B4_PG - [15:0] */
+#define WM8904_EQ_B4_PG_SHIFT                        0  /* EQ_B4_PG - [15:0] */
+#define WM8904_EQ_B4_PG_WIDTH                       16  /* EQ_B4_PG - [15:0] */
+
+/*
+ * R155 (0x9B) - EQ22
+ */
+#define WM8904_EQ_B5_A_MASK                     0xFFFF  /* EQ_B5_A - [15:0] */
+#define WM8904_EQ_B5_A_SHIFT                         0  /* EQ_B5_A - [15:0] */
+#define WM8904_EQ_B5_A_WIDTH                        16  /* EQ_B5_A - [15:0] */
+
+/*
+ * R156 (0x9C) - EQ23
+ */
+#define WM8904_EQ_B5_B_MASK                     0xFFFF  /* EQ_B5_B - [15:0] */
+#define WM8904_EQ_B5_B_SHIFT                         0  /* EQ_B5_B - [15:0] */
+#define WM8904_EQ_B5_B_WIDTH                        16  /* EQ_B5_B - [15:0] */
+
+/*
+ * R157 (0x9D) - EQ24
+ */
+#define WM8904_EQ_B5_PG_MASK                    0xFFFF  /* EQ_B5_PG - [15:0] */
+#define WM8904_EQ_B5_PG_SHIFT                        0  /* EQ_B5_PG - [15:0] */
+#define WM8904_EQ_B5_PG_WIDTH                       16  /* EQ_B5_PG - [15:0] */
+
+/*
+ * R161 (0xA1) - Control Interface Test 1
+ */
+#define WM8904_USER_KEY                         0x0002  /* USER_KEY */
+#define WM8904_USER_KEY_MASK                    0x0002  /* USER_KEY */
+#define WM8904_USER_KEY_SHIFT                        1  /* USER_KEY */
+#define WM8904_USER_KEY_WIDTH                        1  /* USER_KEY */
+
+/*
+ * R198 (0xC6) - ADC Test 0
+ */
+#define WM8904_ADC_128_OSR_TST_MODE             0x0004  /* ADC_128_OSR_TST_MODE */
+#define WM8904_ADC_128_OSR_TST_MODE_SHIFT            2  /* ADC_128_OSR_TST_MODE */
+#define WM8904_ADC_128_OSR_TST_MODE_WIDTH            1  /* ADC_128_OSR_TST_MODE */
+#define WM8904_ADC_BIASX1P5                     0x0001  /* ADC_BIASX1P5 */
+#define WM8904_ADC_BIASX1P5_SHIFT                    0  /* ADC_BIASX1P5 */
+#define WM8904_ADC_BIASX1P5_WIDTH                    1  /* ADC_BIASX1P5 */
+
+/*
+ * R204 (0xCC) - Analogue Output Bias 0
+ */
+#define WM8904_PGA_BIAS_MASK                    0x0070  /* PGA_BIAS - [6:4] */
+#define WM8904_PGA_BIAS_SHIFT                        4  /* PGA_BIAS - [6:4] */
+#define WM8904_PGA_BIAS_WIDTH                        3  /* PGA_BIAS - [6:4] */
+
+/*
+ * R247 (0xF7) - FLL NCO Test 0
+ */
+#define WM8904_FLL_FRC_NCO                      0x0001  /* FLL_FRC_NCO */
+#define WM8904_FLL_FRC_NCO_MASK                 0x0001  /* FLL_FRC_NCO */
+#define WM8904_FLL_FRC_NCO_SHIFT                     0  /* FLL_FRC_NCO */
+#define WM8904_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
+
+/*
+ * R248 (0xF8) - FLL NCO Test 1
+ */
+#define WM8904_FLL_FRC_NCO_VAL_MASK             0x003F  /* FLL_FRC_NCO_VAL - [5:0] */
+#define WM8904_FLL_FRC_NCO_VAL_SHIFT                 0  /* FLL_FRC_NCO_VAL - [5:0] */
+#define WM8904_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [5:0] */
+
+#endif
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
new file mode 100644
index 0000000..be4fce0
--- /dev/null
+++ b/sound/soc/codecs/wm8940.c
@@ -0,0 +1,796 @@
+/*
+ * wm8940.c  --  WM8940 ALSA Soc Audio driver
+ *
+ * Author: Jonathan Cameron <jic23@cam.ac.uk>
+ *
+ * Based on wm8510.c
+ *    Copyright  2006 Wolfson Microelectronics PLC.
+ *    Author:  Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Not currently handled:
+ * Notch filter control
+ * AUXMode (inverting vs mixer)
+ * No means to obtain current gain if alc enabled.
+ * No use made of gpio
+ * Fast VMID discharge for power down
+ * Soft Start
+ * DLR and ALR Swaps not enabled
+ * Digital Sidetone not supported
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8940.h"
+
+struct wm8940_priv {
+	unsigned int sysclk;
+	struct regmap *regmap;
+};
+
+static bool wm8940_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8940_SOFTRESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm8940_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8940_SOFTRESET:
+	case WM8940_POWER1:
+	case WM8940_POWER2:
+	case WM8940_POWER3:
+	case WM8940_IFACE:
+	case WM8940_COMPANDINGCTL:
+	case WM8940_CLOCK:
+	case WM8940_ADDCNTRL:
+	case WM8940_GPIO:
+	case WM8940_CTLINT:
+	case WM8940_DAC:
+	case WM8940_DACVOL:
+	case WM8940_ADC:
+	case WM8940_ADCVOL:
+	case WM8940_NOTCH1:
+	case WM8940_NOTCH2:
+	case WM8940_NOTCH3:
+	case WM8940_NOTCH4:
+	case WM8940_NOTCH5:
+	case WM8940_NOTCH6:
+	case WM8940_NOTCH7:
+	case WM8940_NOTCH8:
+	case WM8940_DACLIM1:
+	case WM8940_DACLIM2:
+	case WM8940_ALC1:
+	case WM8940_ALC2:
+	case WM8940_ALC3:
+	case WM8940_NOISEGATE:
+	case WM8940_PLLN:
+	case WM8940_PLLK1:
+	case WM8940_PLLK2:
+	case WM8940_PLLK3:
+	case WM8940_ALC4:
+	case WM8940_INPUTCTL:
+	case WM8940_PGAGAIN:
+	case WM8940_ADCBOOST:
+	case WM8940_OUTPUTCTL:
+	case WM8940_SPKMIX:
+	case WM8940_SPKVOL:
+	case WM8940_MONOMIX:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct reg_default wm8940_reg_defaults[] = {
+	{  0x1, 0x0000 }, /* Power 1 */
+	{  0x2, 0x0000 }, /* Power 2 */
+	{  0x3, 0x0000 }, /* Power 3 */
+	{  0x4, 0x0010 }, /* Interface Control */
+	{  0x5, 0x0000 }, /* Companding Control */
+	{  0x6, 0x0140 }, /* Clock Control */
+	{  0x7, 0x0000 }, /* Additional Controls */
+	{  0x8, 0x0000 }, /* GPIO Control */
+	{  0x9, 0x0002 }, /* Auto Increment Control */
+	{  0xa, 0x0000 }, /* DAC Control */
+	{  0xb, 0x00FF }, /* DAC Volume */
+
+	{  0xe, 0x0100 }, /* ADC Control */
+	{  0xf, 0x00FF }, /* ADC Volume */
+	{ 0x10, 0x0000 }, /* Notch Filter 1 Control 1 */
+	{ 0x11, 0x0000 }, /* Notch Filter 1 Control 2 */
+	{ 0x12, 0x0000 }, /* Notch Filter 2 Control 1 */
+	{ 0x13, 0x0000 }, /* Notch Filter 2 Control 2 */
+	{ 0x14, 0x0000 }, /* Notch Filter 3 Control 1 */
+	{ 0x15, 0x0000 }, /* Notch Filter 3 Control 2 */
+	{ 0x16, 0x0000 }, /* Notch Filter 4 Control 1 */
+	{ 0x17, 0x0000 }, /* Notch Filter 4 Control 2 */
+	{ 0x18, 0x0032 }, /* DAC Limit Control 1 */
+	{ 0x19, 0x0000 }, /* DAC Limit Control 2 */
+
+	{ 0x20, 0x0038 }, /* ALC Control 1 */
+	{ 0x21, 0x000B }, /* ALC Control 2 */
+	{ 0x22, 0x0032 }, /* ALC Control 3 */
+	{ 0x23, 0x0000 }, /* Noise Gate */
+	{ 0x24, 0x0041 }, /* PLLN */
+	{ 0x25, 0x000C }, /* PLLK1 */
+	{ 0x26, 0x0093 }, /* PLLK2 */
+	{ 0x27, 0x00E9 }, /* PLLK3 */
+
+	{ 0x2a, 0x0030 }, /* ALC Control 4 */
+
+	{ 0x2c, 0x0002 }, /* Input Control */
+	{ 0x2d, 0x0050 }, /* PGA Gain */
+
+	{ 0x2f, 0x0002 }, /* ADC Boost Control */
+
+	{ 0x31, 0x0002 }, /* Output Control */
+	{ 0x32, 0x0000 }, /* Speaker Mixer Control */
+
+	{ 0x36, 0x0079 }, /* Speaker Volume */
+
+	{ 0x38, 0x0000 }, /* Mono Mixer Control */
+};
+
+static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" };
+static SOC_ENUM_SINGLE_DECL(wm8940_adc_companding_enum,
+			    WM8940_COMPANDINGCTL, 1, wm8940_companding);
+static SOC_ENUM_SINGLE_DECL(wm8940_dac_companding_enum,
+			    WM8940_COMPANDINGCTL, 3, wm8940_companding);
+
+static const char *wm8940_alc_mode_text[] = {"ALC", "Limiter"};
+static SOC_ENUM_SINGLE_DECL(wm8940_alc_mode_enum,
+			    WM8940_ALC3, 8, wm8940_alc_mode_text);
+
+static const char *wm8940_mic_bias_level_text[] = {"0.9", "0.65"};
+static SOC_ENUM_SINGLE_DECL(wm8940_mic_bias_level_enum,
+			    WM8940_INPUTCTL, 8, wm8940_mic_bias_level_text);
+
+static const char *wm8940_filter_mode_text[] = {"Audio", "Application"};
+static SOC_ENUM_SINGLE_DECL(wm8940_filter_mode_enum,
+			    WM8940_ADC, 7, wm8940_filter_mode_text);
+
+static DECLARE_TLV_DB_SCALE(wm8940_spk_vol_tlv, -5700, 100, 1);
+static DECLARE_TLV_DB_SCALE(wm8940_att_tlv, -1000, 1000, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_pga_vol_tlv, -1200, 75, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_alc_min_tlv, -1200, 600, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_alc_max_tlv, 675, 600, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_alc_tar_tlv, -2250, 50, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_lim_boost_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_lim_thresh_tlv, -600, 100, 0);
+static DECLARE_TLV_DB_SCALE(wm8940_adc_tlv, -12750, 50, 1);
+static DECLARE_TLV_DB_SCALE(wm8940_capture_boost_vol_tlv, 0, 2000, 0);
+
+static const struct snd_kcontrol_new wm8940_snd_controls[] = {
+	SOC_SINGLE("Digital Loopback Switch", WM8940_COMPANDINGCTL,
+		   6, 1, 0),
+	SOC_ENUM("DAC Companding", wm8940_dac_companding_enum),
+	SOC_ENUM("ADC Companding", wm8940_adc_companding_enum),
+
+	SOC_ENUM("ALC Mode", wm8940_alc_mode_enum),
+	SOC_SINGLE("ALC Switch", WM8940_ALC1, 8, 1, 0),
+	SOC_SINGLE_TLV("ALC Capture Max Gain", WM8940_ALC1,
+		       3, 7, 1, wm8940_alc_max_tlv),
+	SOC_SINGLE_TLV("ALC Capture Min Gain", WM8940_ALC1,
+		       0, 7, 0, wm8940_alc_min_tlv),
+	SOC_SINGLE_TLV("ALC Capture Target", WM8940_ALC2,
+		       0, 14, 0, wm8940_alc_tar_tlv),
+	SOC_SINGLE("ALC Capture Hold", WM8940_ALC2, 4, 10, 0),
+	SOC_SINGLE("ALC Capture Decay", WM8940_ALC3, 4, 10, 0),
+	SOC_SINGLE("ALC Capture Attach", WM8940_ALC3, 0, 10, 0),
+	SOC_SINGLE("ALC ZC Switch", WM8940_ALC4, 1, 1, 0),
+	SOC_SINGLE("ALC Capture Noise Gate Switch", WM8940_NOISEGATE,
+		   3, 1, 0),
+	SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8940_NOISEGATE,
+		   0, 7, 0),
+
+	SOC_SINGLE("DAC Playback Limiter Switch", WM8940_DACLIM1, 8, 1, 0),
+	SOC_SINGLE("DAC Playback Limiter Attack", WM8940_DACLIM1, 0, 9, 0),
+	SOC_SINGLE("DAC Playback Limiter Decay", WM8940_DACLIM1, 4, 11, 0),
+	SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8940_DACLIM2,
+		       4, 9, 1, wm8940_lim_thresh_tlv),
+	SOC_SINGLE_TLV("DAC Playback Limiter Boost", WM8940_DACLIM2,
+		       0, 12, 0, wm8940_lim_boost_tlv),
+
+	SOC_SINGLE("Capture PGA ZC Switch", WM8940_PGAGAIN, 7, 1, 0),
+	SOC_SINGLE_TLV("Capture PGA Volume", WM8940_PGAGAIN,
+		       0, 63, 0, wm8940_pga_vol_tlv),
+	SOC_SINGLE_TLV("Digital Playback Volume", WM8940_DACVOL,
+		       0, 255, 0, wm8940_adc_tlv),
+	SOC_SINGLE_TLV("Digital Capture Volume", WM8940_ADCVOL,
+		       0, 255, 0, wm8940_adc_tlv),
+	SOC_ENUM("Mic Bias Level", wm8940_mic_bias_level_enum),
+	SOC_SINGLE_TLV("Capture Boost Volue", WM8940_ADCBOOST,
+		       8, 1, 0, wm8940_capture_boost_vol_tlv),
+	SOC_SINGLE_TLV("Speaker Playback Volume", WM8940_SPKVOL,
+		       0, 63, 0, wm8940_spk_vol_tlv),
+	SOC_SINGLE("Speaker Playback Switch", WM8940_SPKVOL,  6, 1, 1),
+
+	SOC_SINGLE_TLV("Speaker Mixer Line Bypass Volume", WM8940_SPKVOL,
+		       8, 1, 1, wm8940_att_tlv),
+	SOC_SINGLE("Speaker Playback ZC Switch", WM8940_SPKVOL, 7, 1, 0),
+
+	SOC_SINGLE("Mono Out Switch", WM8940_MONOMIX, 6, 1, 1),
+	SOC_SINGLE_TLV("Mono Mixer Line Bypass Volume", WM8940_MONOMIX,
+		       7, 1, 1, wm8940_att_tlv),
+
+	SOC_SINGLE("High Pass Filter Switch", WM8940_ADC, 8, 1, 0),
+	SOC_ENUM("High Pass Filter Mode", wm8940_filter_mode_enum),
+	SOC_SINGLE("High Pass Filter Cut Off", WM8940_ADC, 4, 7, 0),
+	SOC_SINGLE("ADC Inversion Switch", WM8940_ADC, 0, 1, 0),
+	SOC_SINGLE("DAC Inversion Switch", WM8940_DAC, 0, 1, 0),
+	SOC_SINGLE("DAC Auto Mute Switch", WM8940_DAC, 2, 1, 0),
+	SOC_SINGLE("ZC Timeout Clock Switch", WM8940_ADDCNTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8940_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", WM8940_SPKMIX, 1, 1, 0),
+	SOC_DAPM_SINGLE("Aux Playback Switch", WM8940_SPKMIX, 5, 1, 0),
+	SOC_DAPM_SINGLE("PCM Playback Switch", WM8940_SPKMIX, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8940_mono_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", WM8940_MONOMIX, 1, 1, 0),
+	SOC_DAPM_SINGLE("Aux Playback Switch", WM8940_MONOMIX, 2, 1, 0),
+	SOC_DAPM_SINGLE("PCM Playback Switch", WM8940_MONOMIX, 0, 1, 0),
+};
+
+static DECLARE_TLV_DB_SCALE(wm8940_boost_vol_tlv, -1500, 300, 1);
+static const struct snd_kcontrol_new wm8940_input_boost_controls[] = {
+	SOC_DAPM_SINGLE("Mic PGA Switch", WM8940_PGAGAIN, 6, 1, 1),
+	SOC_DAPM_SINGLE_TLV("Aux Volume", WM8940_ADCBOOST,
+			    0, 7, 0, wm8940_boost_vol_tlv),
+	SOC_DAPM_SINGLE_TLV("Mic Volume", WM8940_ADCBOOST,
+			    4, 7, 0, wm8940_boost_vol_tlv),
+};
+
+static const struct snd_kcontrol_new wm8940_micpga_controls[] = {
+	SOC_DAPM_SINGLE("AUX Switch", WM8940_INPUTCTL, 2, 1, 0),
+	SOC_DAPM_SINGLE("MICP Switch", WM8940_INPUTCTL, 0, 1, 0),
+	SOC_DAPM_SINGLE("MICN Switch", WM8940_INPUTCTL, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8940_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Speaker Mixer", WM8940_POWER3, 2, 0,
+			   &wm8940_speaker_mixer_controls[0],
+			   ARRAY_SIZE(wm8940_speaker_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono Mixer", WM8940_POWER3, 3, 0,
+			   &wm8940_mono_mixer_controls[0],
+			   ARRAY_SIZE(wm8940_mono_mixer_controls)),
+	SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8940_POWER3, 0, 0),
+
+	SND_SOC_DAPM_PGA("SpkN Out", WM8940_POWER3, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SpkP Out", WM8940_POWER3, 6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono Out", WM8940_POWER3, 7, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("MONOOUT"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+	SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+
+	SND_SOC_DAPM_PGA("Aux Input", WM8940_POWER1, 6, 0, NULL, 0),
+	SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8940_POWER2, 0, 0),
+	SND_SOC_DAPM_MIXER("Mic PGA", WM8940_POWER2, 2, 0,
+			   &wm8940_micpga_controls[0],
+			   ARRAY_SIZE(wm8940_micpga_controls)),
+	SND_SOC_DAPM_MIXER("Boost Mixer", WM8940_POWER2, 4, 0,
+			   &wm8940_input_boost_controls[0],
+			   ARRAY_SIZE(wm8940_input_boost_controls)),
+	SND_SOC_DAPM_MICBIAS("Mic Bias", WM8940_POWER1, 4, 0),
+
+	SND_SOC_DAPM_INPUT("MICN"),
+	SND_SOC_DAPM_INPUT("MICP"),
+	SND_SOC_DAPM_INPUT("AUX"),
+};
+
+static const struct snd_soc_dapm_route wm8940_dapm_routes[] = {
+	/* Mono output mixer */
+	{"Mono Mixer", "PCM Playback Switch", "DAC"},
+	{"Mono Mixer", "Aux Playback Switch", "Aux Input"},
+	{"Mono Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+	/* Speaker output mixer */
+	{"Speaker Mixer", "PCM Playback Switch", "DAC"},
+	{"Speaker Mixer", "Aux Playback Switch", "Aux Input"},
+	{"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+	/* Outputs */
+	{"Mono Out", NULL, "Mono Mixer"},
+	{"MONOOUT", NULL, "Mono Out"},
+	{"SpkN Out", NULL, "Speaker Mixer"},
+	{"SpkP Out", NULL, "Speaker Mixer"},
+	{"SPKOUTN", NULL, "SpkN Out"},
+	{"SPKOUTP", NULL, "SpkP Out"},
+
+	/*  Microphone PGA */
+	{"Mic PGA", "MICN Switch", "MICN"},
+	{"Mic PGA", "MICP Switch", "MICP"},
+	{"Mic PGA", "AUX Switch", "AUX"},
+
+	/* Boost Mixer */
+	{"Boost Mixer", "Mic PGA Switch", "Mic PGA"},
+	{"Boost Mixer", "Mic Volume",  "MICP"},
+	{"Boost Mixer", "Aux Volume", "Aux Input"},
+
+	{"ADC", NULL, "Boost Mixer"},
+};
+
+#define wm8940_reset(c) snd_soc_component_write(c, WM8940_SOFTRESET, 0);
+
+static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = snd_soc_component_read32(component, WM8940_IFACE) & 0xFE67;
+	u16 clk = snd_soc_component_read32(component, WM8940_CLOCK) & 0x1fe;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		clk |= 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_component_write(component, WM8940_CLOCK, clk);
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= (2 << 3);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= (1 << 3);
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= (3 << 3);
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= (3 << 3) | (1 << 7);
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= (1 << 7);
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= (1 << 8);
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= (1 << 8) | (1 << 7);
+		break;
+	}
+
+	snd_soc_component_write(component, WM8940_IFACE, iface);
+
+	return 0;
+}
+
+static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 iface = snd_soc_component_read32(component, WM8940_IFACE) & 0xFD9F;
+	u16 addcntrl = snd_soc_component_read32(component, WM8940_ADDCNTRL) & 0xFFF1;
+	u16 companding =  snd_soc_component_read32(component,
+						WM8940_COMPANDINGCTL) & 0xFFDF;
+	int ret;
+
+	/* LoutR control */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE
+	    && params_channels(params) == 2)
+		iface |= (1 << 9);
+
+	switch (params_rate(params)) {
+	case 8000:
+		addcntrl |= (0x5 << 1);
+		break;
+	case 11025:
+		addcntrl |= (0x4 << 1);
+		break;
+	case 16000:
+		addcntrl |= (0x3 << 1);
+		break;
+	case 22050:
+		addcntrl |= (0x2 << 1);
+		break;
+	case 32000:
+		addcntrl |= (0x1 << 1);
+		break;
+	case 44100:
+	case 48000:
+		break;
+	}
+	ret = snd_soc_component_write(component, WM8940_ADDCNTRL, addcntrl);
+	if (ret)
+		goto error_ret;
+
+	switch (params_width(params)) {
+	case 8:
+		companding = companding | (1 << 5);
+		break;
+	case 16:
+		break;
+	case 20:
+		iface |= (1 << 5);
+		break;
+	case 24:
+		iface |= (2 << 5);
+		break;
+	case 32:
+		iface |= (3 << 5);
+		break;
+	}
+	ret = snd_soc_component_write(component, WM8940_COMPANDINGCTL, companding);
+	if (ret)
+		goto error_ret;
+	ret = snd_soc_component_write(component, WM8940_IFACE, iface);
+
+error_ret:
+	return ret;
+}
+
+static int wm8940_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8940_DAC) & 0xffbf;
+
+	if (mute)
+		mute_reg |= 0x40;
+
+	return snd_soc_component_write(component, WM8940_DAC, mute_reg);
+}
+
+static int wm8940_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8940_priv *wm8940 = snd_soc_component_get_drvdata(component);
+	u16 val;
+	u16 pwr_reg = snd_soc_component_read32(component, WM8940_POWER1) & 0x1F0;
+	int ret = 0;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* ensure bufioen and biasen */
+		pwr_reg |= (1 << 2) | (1 << 3);
+		/* Enable thermal shutdown */
+		val = snd_soc_component_read32(component, WM8940_OUTPUTCTL);
+		ret = snd_soc_component_write(component, WM8940_OUTPUTCTL, val | 0x2);
+		if (ret)
+			break;
+		/* set vmid to 75k */
+		ret = snd_soc_component_write(component, WM8940_POWER1, pwr_reg | 0x1);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* ensure bufioen and biasen */
+		pwr_reg |= (1 << 2) | (1 << 3);
+		ret = snd_soc_component_write(component, WM8940_POWER1, pwr_reg | 0x1);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regcache_sync(wm8940->regmap);
+			if (ret < 0) {
+				dev_err(component->dev, "Failed to sync cache: %d\n", ret);
+				return ret;
+			}
+		}
+
+		/* ensure bufioen and biasen */
+		pwr_reg |= (1 << 2) | (1 << 3);
+		/* set vmid to 300k for standby */
+		ret = snd_soc_component_write(component, WM8940_POWER1, pwr_reg | 0x2);
+		break;
+	case SND_SOC_BIAS_OFF:
+		ret = snd_soc_component_write(component, WM8940_POWER1, pwr_reg);
+		break;
+	}
+
+	return ret;
+}
+
+struct pll_ {
+	unsigned int pre_scale:2;
+	unsigned int n:4;
+	unsigned int k;
+};
+
+static struct pll_ pll_div;
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 24) * 10)
+static void pll_factors(unsigned int target, unsigned int source)
+{
+	unsigned long long Kpart;
+	unsigned int K, Ndiv, Nmod;
+	/* The left shift ist to avoid accuracy loss when right shifting */
+	Ndiv = target / source;
+
+	if (Ndiv > 12) {
+		source <<= 1;
+		/* Multiply by 2 */
+		pll_div.pre_scale = 0;
+		Ndiv = target / source;
+	} else if (Ndiv < 3) {
+		source >>= 2;
+		/* Divide by 4 */
+		pll_div.pre_scale = 3;
+		Ndiv = target / source;
+	} else if (Ndiv < 6) {
+		source >>= 1;
+		/* divide by 2 */
+		pll_div.pre_scale = 2;
+		Ndiv = target / source;
+	} else
+		pll_div.pre_scale = 1;
+
+	if ((Ndiv < 6) || (Ndiv > 12))
+		printk(KERN_WARNING
+			"WM8940 N value %d outwith recommended range!d\n",
+			Ndiv);
+
+	pll_div.n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	/* Check if we need to round */
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	K /= 10;
+
+	pll_div.k = K;
+}
+
+/* Untested at the moment */
+static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+		int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 reg;
+
+	/* Turn off PLL */
+	reg = snd_soc_component_read32(component, WM8940_POWER1);
+	snd_soc_component_write(component, WM8940_POWER1, reg & 0x1df);
+
+	if (freq_in == 0 || freq_out == 0) {
+		/* Clock CODEC directly from MCLK */
+		reg = snd_soc_component_read32(component, WM8940_CLOCK);
+		snd_soc_component_write(component, WM8940_CLOCK, reg & 0x0ff);
+		/* Pll power down */
+		snd_soc_component_write(component, WM8940_PLLN, (1 << 7));
+		return 0;
+	}
+
+	/* Pll is followed by a frequency divide by 4 */
+	pll_factors(freq_out*4, freq_in);
+	if (pll_div.k)
+		snd_soc_component_write(component, WM8940_PLLN,
+			     (pll_div.pre_scale << 4) | pll_div.n | (1 << 6));
+	else /* No factional component */
+		snd_soc_component_write(component, WM8940_PLLN,
+			     (pll_div.pre_scale << 4) | pll_div.n);
+	snd_soc_component_write(component, WM8940_PLLK1, pll_div.k >> 18);
+	snd_soc_component_write(component, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff);
+	snd_soc_component_write(component, WM8940_PLLK3, pll_div.k & 0x1ff);
+	/* Enable the PLL */
+	reg = snd_soc_component_read32(component, WM8940_POWER1);
+	snd_soc_component_write(component, WM8940_POWER1, reg | 0x020);
+
+	/* Run CODEC from PLL instead of MCLK */
+	reg = snd_soc_component_read32(component, WM8940_CLOCK);
+	snd_soc_component_write(component, WM8940_CLOCK, reg | 0x100);
+
+	return 0;
+}
+
+static int wm8940_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8940_priv *wm8940 = snd_soc_component_get_drvdata(component);
+
+	switch (freq) {
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 16934400:
+	case 18432000:
+		wm8940->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+				 int div_id, int div)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 reg;
+	int ret = 0;
+
+	switch (div_id) {
+	case WM8940_BCLKDIV:
+		reg = snd_soc_component_read32(component, WM8940_CLOCK) & 0xFFE3;
+		ret = snd_soc_component_write(component, WM8940_CLOCK, reg | (div << 2));
+		break;
+	case WM8940_MCLKDIV:
+		reg = snd_soc_component_read32(component, WM8940_CLOCK) & 0xFF1F;
+		ret = snd_soc_component_write(component, WM8940_CLOCK, reg | (div << 5));
+		break;
+	case WM8940_OPCLKDIV:
+		reg = snd_soc_component_read32(component, WM8940_GPIO) & 0xFFCF;
+		ret = snd_soc_component_write(component, WM8940_GPIO, reg | (div << 4));
+		break;
+	}
+	return ret;
+}
+
+#define WM8940_RATES SNDRV_PCM_RATE_8000_48000
+
+#define WM8940_FORMATS (SNDRV_PCM_FMTBIT_S8 |				\
+			SNDRV_PCM_FMTBIT_S16_LE |			\
+			SNDRV_PCM_FMTBIT_S20_3LE |			\
+			SNDRV_PCM_FMTBIT_S24_LE |			\
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8940_dai_ops = {
+	.hw_params = wm8940_i2s_hw_params,
+	.set_sysclk = wm8940_set_dai_sysclk,
+	.digital_mute = wm8940_mute,
+	.set_fmt = wm8940_set_dai_fmt,
+	.set_clkdiv = wm8940_set_dai_clkdiv,
+	.set_pll = wm8940_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver wm8940_dai = {
+	.name = "wm8940-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8940_RATES,
+		.formats = WM8940_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8940_RATES,
+		.formats = WM8940_FORMATS,
+	},
+	.ops = &wm8940_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int wm8940_probe(struct snd_soc_component *component)
+{
+	struct wm8940_setup_data *pdata = component->dev->platform_data;
+	int ret;
+	u16 reg;
+
+	ret = wm8940_reset(component);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	ret = snd_soc_component_write(component, WM8940_POWER1, 0x180);
+	if (ret < 0)
+		return ret;
+
+	if (!pdata)
+		dev_warn(component->dev, "No platform data supplied\n");
+	else {
+		reg = snd_soc_component_read32(component, WM8940_OUTPUTCTL);
+		ret = snd_soc_component_write(component, WM8940_OUTPUTCTL, reg | pdata->vroi);
+		if (ret < 0)
+			return ret;
+	}
+
+	return ret;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8940 = {
+	.probe			= wm8940_probe,
+	.set_bias_level		= wm8940_set_bias_level,
+	.controls		= wm8940_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8940_snd_controls),
+	.dapm_widgets		= wm8940_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8940_dapm_widgets),
+	.dapm_routes		= wm8940_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8940_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8940_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = WM8940_MONOMIX,
+	.reg_defaults = wm8940_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8940_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.readable_reg = wm8940_readable_register,
+	.volatile_reg = wm8940_volatile_register,
+};
+
+static int wm8940_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8940_priv *wm8940;
+	int ret;
+
+	wm8940 = devm_kzalloc(&i2c->dev, sizeof(struct wm8940_priv),
+			      GFP_KERNEL);
+	if (wm8940 == NULL)
+		return -ENOMEM;
+
+	wm8940->regmap = devm_regmap_init_i2c(i2c, &wm8940_regmap);
+	if (IS_ERR(wm8940->regmap))
+		return PTR_ERR(wm8940->regmap);
+
+	i2c_set_clientdata(i2c, wm8940);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8940, &wm8940_dai, 1);
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8940_i2c_id[] = {
+	{ "wm8940", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id);
+
+static struct i2c_driver wm8940_i2c_driver = {
+	.driver = {
+		.name = "wm8940",
+	},
+	.probe =    wm8940_i2c_probe,
+	.id_table = wm8940_i2c_id,
+};
+
+module_i2c_driver(wm8940_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8940 driver");
+MODULE_AUTHOR("Jonathan Cameron");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8940.h b/sound/soc/codecs/wm8940.h
new file mode 100644
index 0000000..907fe19
--- /dev/null
+++ b/sound/soc/codecs/wm8940.h
@@ -0,0 +1,102 @@
+/*
+ * wm8940.h -- WM8940 Soc Audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8940_H
+#define _WM8940_H
+
+struct wm8940_setup_data {
+	/* Vref to analogue output resistance */
+#define WM8940_VROI_1K 0
+#define WM8940_VROI_30K 1
+	unsigned int vroi:1;
+};
+
+/* WM8940 register space */
+#define WM8940_SOFTRESET	0x00
+#define WM8940_POWER1		0x01
+#define WM8940_POWER2		0x02
+#define WM8940_POWER3		0x03
+#define WM8940_IFACE		0x04
+#define WM8940_COMPANDINGCTL	0x05
+#define WM8940_CLOCK		0x06
+#define WM8940_ADDCNTRL		0x07
+#define WM8940_GPIO		0x08
+#define WM8940_CTLINT		0x09
+#define WM8940_DAC		0x0A
+#define WM8940_DACVOL		0x0B
+
+#define WM8940_ADC		0x0E
+#define WM8940_ADCVOL		0x0F
+#define WM8940_NOTCH1		0x10
+#define WM8940_NOTCH2		0x11
+#define WM8940_NOTCH3		0x12
+#define WM8940_NOTCH4		0x13
+#define WM8940_NOTCH5		0x14
+#define WM8940_NOTCH6		0x15
+#define WM8940_NOTCH7		0x16
+#define WM8940_NOTCH8		0x17
+#define WM8940_DACLIM1		0x18
+#define WM8940_DACLIM2		0x19
+
+#define WM8940_ALC1		0x20
+#define WM8940_ALC2		0x21
+#define WM8940_ALC3		0x22
+#define WM8940_NOISEGATE	0x23
+#define WM8940_PLLN		0x24
+#define WM8940_PLLK1		0x25
+#define WM8940_PLLK2		0x26
+#define WM8940_PLLK3		0x27
+
+#define WM8940_ALC4		0x2A
+
+#define WM8940_INPUTCTL		0x2C
+#define WM8940_PGAGAIN		0x2D
+
+#define WM8940_ADCBOOST		0x2F
+
+#define WM8940_OUTPUTCTL	0x31
+#define WM8940_SPKMIX		0x32
+
+#define WM8940_SPKVOL		0x36
+
+#define WM8940_MONOMIX		0x38
+
+#define WM8940_CACHEREGNUM  0x57
+
+
+/* Clock divider Id's */
+#define WM8940_BCLKDIV 0
+#define WM8940_MCLKDIV 1
+#define WM8940_OPCLKDIV 2
+
+/* MCLK clock dividers */
+#define WM8940_MCLKDIV_1	0
+#define WM8940_MCLKDIV_1_5	1
+#define WM8940_MCLKDIV_2	2
+#define WM8940_MCLKDIV_3	3
+#define WM8940_MCLKDIV_4	4
+#define WM8940_MCLKDIV_6	5
+#define WM8940_MCLKDIV_8	6
+#define WM8940_MCLKDIV_12	7
+
+/* BCLK clock dividers */
+#define WM8940_BCLKDIV_1 0
+#define WM8940_BCLKDIV_2 1
+#define WM8940_BCLKDIV_4 2
+#define WM8940_BCLKDIV_8 3
+#define WM8940_BCLKDIV_16 4
+#define WM8940_BCLKDIV_32 5
+
+/* PLL Out Dividers */
+#define WM8940_OPCLKDIV_1 0
+#define WM8940_OPCLKDIV_2 1
+#define WM8940_OPCLKDIV_3 2
+#define WM8940_OPCLKDIV_4 3
+
+#endif /* _WM8940_H */
+
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
new file mode 100644
index 0000000..cd204f7
--- /dev/null
+++ b/sound/soc/codecs/wm8955.c
@@ -0,0 +1,1018 @@
+/*
+ * wm8955.c  --  WM8955 ALSA SoC Audio driver
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/wm8955.h>
+
+#include "wm8955.h"
+
+#define WM8955_NUM_SUPPLIES 4
+static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = {
+	"DCVDD",
+	"DBVDD",
+	"HPVDD",
+	"AVDD",
+};
+
+/* codec private data */
+struct wm8955_priv {
+	struct regmap *regmap;
+
+	unsigned int mclk_rate;
+
+	int deemph;
+	int fs;
+
+	struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES];
+};
+
+static const struct reg_default wm8955_reg_defaults[] = {
+	{ 2,  0x0079 },     /* R2  - LOUT1 volume */
+	{ 3,  0x0079 },     /* R3  - ROUT1 volume */
+	{ 5,  0x0008 },     /* R5  - DAC Control */
+	{ 7,  0x000A },     /* R7  - Audio Interface */
+	{ 8,  0x0000 },     /* R8  - Sample Rate */
+	{ 10, 0x00FF },     /* R10 - Left DAC volume */
+	{ 11, 0x00FF },     /* R11 - Right DAC volume */
+	{ 12, 0x000F },     /* R12 - Bass control */
+	{ 13, 0x000F },     /* R13 - Treble control */
+	{ 23, 0x00C1 },     /* R23 - Additional control (1) */
+	{ 24, 0x0000 },     /* R24 - Additional control (2) */
+	{ 25, 0x0000 },     /* R25 - Power Management (1) */
+	{ 26, 0x0000 },     /* R26 - Power Management (2) */
+	{ 27, 0x0000 },     /* R27 - Additional Control (3) */
+	{ 34, 0x0050 },     /* R34 - Left out Mix (1) */
+	{ 35, 0x0050 },     /* R35 - Left out Mix (2) */
+	{ 36, 0x0050 },     /* R36 - Right out Mix (1) */
+	{ 37, 0x0050 },     /* R37 - Right Out Mix (2) */
+	{ 38, 0x0050 },     /* R38 - Mono out Mix (1) */
+	{ 39, 0x0050 },     /* R39 - Mono out Mix (2) */
+	{ 40, 0x0079 },     /* R40 - LOUT2 volume */
+	{ 41, 0x0079 },     /* R41 - ROUT2 volume */
+	{ 42, 0x0079 },     /* R42 - MONOOUT volume */
+	{ 43, 0x0000 },     /* R43 - Clocking / PLL */
+	{ 44, 0x0103 },     /* R44 - PLL Control 1 */
+	{ 45, 0x0024 },     /* R45 - PLL Control 2 */
+	{ 46, 0x01BA },     /* R46 - PLL Control 3 */
+	{ 59, 0x0000 },     /* R59 - PLL Control 4 */
+};
+
+static bool wm8955_writeable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8955_LOUT1_VOLUME:
+	case WM8955_ROUT1_VOLUME:
+	case WM8955_DAC_CONTROL:
+	case WM8955_AUDIO_INTERFACE:
+	case WM8955_SAMPLE_RATE:
+	case WM8955_LEFT_DAC_VOLUME:
+	case WM8955_RIGHT_DAC_VOLUME:
+	case WM8955_BASS_CONTROL:
+	case WM8955_TREBLE_CONTROL:
+	case WM8955_RESET:
+	case WM8955_ADDITIONAL_CONTROL_1:
+	case WM8955_ADDITIONAL_CONTROL_2:
+	case WM8955_POWER_MANAGEMENT_1:
+	case WM8955_POWER_MANAGEMENT_2:
+	case WM8955_ADDITIONAL_CONTROL_3:
+	case WM8955_LEFT_OUT_MIX_1:
+	case WM8955_LEFT_OUT_MIX_2:
+	case WM8955_RIGHT_OUT_MIX_1:
+	case WM8955_RIGHT_OUT_MIX_2:
+	case WM8955_MONO_OUT_MIX_1:
+	case WM8955_MONO_OUT_MIX_2:
+	case WM8955_LOUT2_VOLUME:
+	case WM8955_ROUT2_VOLUME:
+	case WM8955_MONOOUT_VOLUME:
+	case WM8955_CLOCKING_PLL:
+	case WM8955_PLL_CONTROL_1:
+	case WM8955_PLL_CONTROL_2:
+	case WM8955_PLL_CONTROL_3:
+	case WM8955_PLL_CONTROL_4:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm8955_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8955_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int wm8955_reset(struct snd_soc_component *component)
+{
+	return snd_soc_component_write(component, WM8955_RESET, 0);
+}
+
+struct pll_factors {
+	int n;
+	int k;
+	int outdiv;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 22) * 10)
+
+static int wm8995_pll_factors(struct device *dev,
+			      int Fref, int Fout, struct pll_factors *pll)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod, target;
+
+	dev_dbg(dev, "Fref=%u Fout=%u\n", Fref, Fout);
+
+	/* The oscilator should run at should be 90-100MHz, and
+	 * there's a divide by 4 plus an optional divide by 2 in the
+	 * output path to generate the system clock.  The clock table
+	 * is sortd so we should always generate a suitable target. */
+	target = Fout * 4;
+	if (target < 90000000) {
+		pll->outdiv = 1;
+		target *= 2;
+	} else {
+		pll->outdiv = 0;
+	}
+
+	WARN_ON(target < 90000000 || target > 100000000);
+
+	dev_dbg(dev, "Fvco=%dHz\n", target);
+
+	/* Now, calculate N.K */
+	Ndiv = target / Fref;
+
+	pll->n = Ndiv;
+	Nmod = target % Fref;
+	dev_dbg(dev, "Nmod=%d\n", Nmod);
+
+	/* Calculate fractional part - scale up so we can round. */
+	Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, Fref);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	pll->k = K / 10;
+
+	dev_dbg(dev, "N=%x K=%x OUTDIV=%x\n", pll->n, pll->k, pll->outdiv);
+
+	return 0;
+}
+
+/* Lookup table specifying SRATE (table 25 in datasheet); some of the
+ * output frequencies have been rounded to the standard frequencies
+ * they are intended to match where the error is slight. */
+static struct {
+	int mclk;
+	int fs;
+	int usb;
+	int sr;
+} clock_cfgs[] = {
+	{ 18432000,  8000, 0,  3, },
+	{ 18432000, 12000, 0,  9, },
+	{ 18432000, 16000, 0, 11, },
+	{ 18432000, 24000, 0, 29, },
+	{ 18432000, 32000, 0, 13, },
+	{ 18432000, 48000, 0,  1, },
+	{ 18432000, 96000, 0, 15, },
+
+	{ 16934400,  8018, 0, 19, },
+	{ 16934400, 11025, 0, 25, },
+	{ 16934400, 22050, 0, 27, },
+	{ 16934400, 44100, 0, 17, },
+	{ 16934400, 88200, 0, 31, },
+
+	{ 12000000,  8000, 1,  2, },
+	{ 12000000, 11025, 1, 25, },
+	{ 12000000, 12000, 1,  8, },
+	{ 12000000, 16000, 1, 10, },
+	{ 12000000, 22050, 1, 27, },
+	{ 12000000, 24000, 1, 28, },
+	{ 12000000, 32000, 1, 12, },
+	{ 12000000, 44100, 1, 17, },
+	{ 12000000, 48000, 1,  0, },
+	{ 12000000, 88200, 1, 31, },
+	{ 12000000, 96000, 1, 14, },
+
+	{ 12288000,  8000, 0,  2, },
+	{ 12288000, 12000, 0,  8, },
+	{ 12288000, 16000, 0, 10, },
+	{ 12288000, 24000, 0, 28, },
+	{ 12288000, 32000, 0, 12, },
+	{ 12288000, 48000, 0,  0, },
+	{ 12288000, 96000, 0, 14, },
+
+	{ 12289600,  8018, 0, 18, },
+	{ 12289600, 11025, 0, 24, },
+	{ 12289600, 22050, 0, 26, },
+	{ 11289600, 44100, 0, 16, },
+	{ 11289600, 88200, 0, 31, },
+};
+
+static int wm8955_configure_clocking(struct snd_soc_component *component)
+{
+	struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
+	int i, ret, val;
+	int clocking = 0;
+	int srate = 0;
+	int sr = -1;
+	struct pll_factors pll;
+
+	/* If we're not running a sample rate currently just pick one */
+	if (wm8955->fs == 0)
+		wm8955->fs = 8000;
+
+	/* Can we generate an exact output? */
+	for (i = 0; i < ARRAY_SIZE(clock_cfgs); i++) {
+		if (wm8955->fs != clock_cfgs[i].fs)
+			continue;
+		sr = i;
+
+		if (wm8955->mclk_rate == clock_cfgs[i].mclk)
+			break;
+	}
+
+	/* We should never get here with an unsupported sample rate */
+	if (sr == -1) {
+		dev_err(component->dev, "Sample rate %dHz unsupported\n",
+			wm8955->fs);
+		WARN_ON(sr == -1);
+		return -EINVAL;
+	}
+
+	if (i == ARRAY_SIZE(clock_cfgs)) {
+		/* If we can't generate the right clock from MCLK then
+		 * we should configure the PLL to supply us with an
+		 * appropriate clock.
+		 */
+		clocking |= WM8955_MCLKSEL;
+
+		/* Use the last divider configuration we saw for the
+		 * sample rate. */
+		ret = wm8995_pll_factors(component->dev, wm8955->mclk_rate,
+					 clock_cfgs[sr].mclk, &pll);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Unable to generate %dHz from %dHz MCLK\n",
+				wm8955->fs, wm8955->mclk_rate);
+			return -EINVAL;
+		}
+
+		snd_soc_component_update_bits(component, WM8955_PLL_CONTROL_1,
+				    WM8955_N_MASK | WM8955_K_21_18_MASK,
+				    (pll.n << WM8955_N_SHIFT) |
+				    pll.k >> 18);
+		snd_soc_component_update_bits(component, WM8955_PLL_CONTROL_2,
+				    WM8955_K_17_9_MASK,
+				    (pll.k >> 9) & WM8955_K_17_9_MASK);
+		snd_soc_component_update_bits(component, WM8955_PLL_CONTROL_3,
+				    WM8955_K_8_0_MASK,
+				    pll.k & WM8955_K_8_0_MASK);
+		if (pll.k)
+			snd_soc_component_update_bits(component, WM8955_PLL_CONTROL_4,
+					    WM8955_KEN, WM8955_KEN);
+		else
+			snd_soc_component_update_bits(component, WM8955_PLL_CONTROL_4,
+					    WM8955_KEN, 0);
+
+		if (pll.outdiv)
+			val = WM8955_PLL_RB | WM8955_PLLOUTDIV2;
+		else
+			val = WM8955_PLL_RB;
+
+		/* Now start the PLL running */
+		snd_soc_component_update_bits(component, WM8955_CLOCKING_PLL,
+				    WM8955_PLL_RB | WM8955_PLLOUTDIV2, val);
+		snd_soc_component_update_bits(component, WM8955_CLOCKING_PLL,
+				    WM8955_PLLEN, WM8955_PLLEN);
+	}
+
+	srate = clock_cfgs[sr].usb | (clock_cfgs[sr].sr << WM8955_SR_SHIFT);
+
+	snd_soc_component_update_bits(component, WM8955_SAMPLE_RATE,
+			    WM8955_USB | WM8955_SR_MASK, srate);
+	snd_soc_component_update_bits(component, WM8955_CLOCKING_PLL,
+			    WM8955_MCLKSEL, clocking);
+
+	return 0;
+}
+
+static int wm8955_sysclk(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	int ret = 0;
+
+	/* Always disable the clocks - if we're doing reconfiguration this
+	 * avoids misclocking.
+	 */
+	snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
+			    WM8955_DIGENB, 0);
+	snd_soc_component_update_bits(component, WM8955_CLOCKING_PLL,
+			    WM8955_PLL_RB | WM8955_PLLEN, 0);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMD:
+		break;
+	case SND_SOC_DAPM_PRE_PMU:
+		ret = wm8955_configure_clocking(component);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int deemph_settings[] = { 0, 32000, 44100, 48000 };
+
+static int wm8955_set_deemph(struct snd_soc_component *component)
+{
+	struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
+	int val, i, best;
+
+	/* If we're using deemphasis select the nearest available sample
+	 * rate.
+	 */
+	if (wm8955->deemph) {
+		best = 1;
+		for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
+			if (abs(deemph_settings[i] - wm8955->fs) <
+			    abs(deemph_settings[best] - wm8955->fs))
+				best = i;
+		}
+
+		val = best << WM8955_DEEMPH_SHIFT;
+	} else {
+		val = 0;
+	}
+
+	dev_dbg(component->dev, "Set deemphasis %d\n", val);
+
+	return snd_soc_component_update_bits(component, WM8955_DAC_CONTROL,
+				   WM8955_DEEMPH_MASK, val);
+}
+
+static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wm8955->deemph;
+	return 0;
+}
+
+static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
+	unsigned int deemph = ucontrol->value.integer.value[0];
+
+	if (deemph > 1)
+		return -EINVAL;
+
+	wm8955->deemph = deemph;
+
+	return wm8955_set_deemph(component);
+}
+
+static const char *bass_mode_text[] = {
+	"Linear", "Adaptive",
+};
+
+static SOC_ENUM_SINGLE_DECL(bass_mode, WM8955_BASS_CONTROL, 7, bass_mode_text);
+
+static const char *bass_cutoff_text[] = {
+	"Low", "High"
+};
+
+static SOC_ENUM_SINGLE_DECL(bass_cutoff, WM8955_BASS_CONTROL, 6,
+			    bass_cutoff_text);
+
+static const char *treble_cutoff_text[] = {
+	"High", "Low"
+};
+
+static SOC_ENUM_SINGLE_DECL(treble_cutoff, WM8955_TREBLE_CONTROL, 2,
+			    treble_cutoff_text);
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(atten_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(mono_tlv, -2100, 300, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(treble_tlv, -1200, 150, 1);
+
+static const struct snd_kcontrol_new wm8955_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8955_LEFT_DAC_VOLUME,
+		 WM8955_RIGHT_DAC_VOLUME, 0, 255, 0, digital_tlv),
+SOC_SINGLE_TLV("Playback Attenuation Volume", WM8955_DAC_CONTROL, 7, 1, 1,
+	       atten_tlv),
+SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
+		    wm8955_get_deemph, wm8955_put_deemph),
+
+SOC_ENUM("Bass Mode", bass_mode),
+SOC_ENUM("Bass Cutoff", bass_cutoff),
+SOC_SINGLE("Bass Volume", WM8955_BASS_CONTROL, 0, 15, 1),
+
+SOC_ENUM("Treble Cutoff", treble_cutoff),
+SOC_SINGLE_TLV("Treble Volume", WM8955_TREBLE_CONTROL, 0, 14, 1, treble_tlv),
+
+SOC_SINGLE_TLV("Left Bypass Volume", WM8955_LEFT_OUT_MIX_1, 4, 7, 1,
+	       bypass_tlv),
+SOC_SINGLE_TLV("Left Mono Volume", WM8955_LEFT_OUT_MIX_2, 4, 7, 1,
+	       bypass_tlv),
+
+SOC_SINGLE_TLV("Right Mono Volume", WM8955_RIGHT_OUT_MIX_1, 4, 7, 1,
+	       bypass_tlv),
+SOC_SINGLE_TLV("Right Bypass Volume", WM8955_RIGHT_OUT_MIX_2, 4, 7, 1,
+	       bypass_tlv),
+
+/* Not a stereo pair so they line up with the DAPM switches */
+SOC_SINGLE_TLV("Mono Left Bypass Volume", WM8955_MONO_OUT_MIX_1, 4, 7, 1,
+	       mono_tlv),
+SOC_SINGLE_TLV("Mono Right Bypass Volume", WM8955_MONO_OUT_MIX_2, 4, 7, 1,
+	       mono_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Volume", WM8955_LOUT1_VOLUME,
+		 WM8955_ROUT1_VOLUME, 0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Headphone ZC Switch", WM8955_LOUT1_VOLUME,
+	     WM8955_ROUT1_VOLUME, 7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Speaker Volume", WM8955_LOUT2_VOLUME,
+		 WM8955_ROUT2_VOLUME, 0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8955_LOUT2_VOLUME,
+	     WM8955_ROUT2_VOLUME, 7, 1, 0),
+
+SOC_SINGLE_TLV("Mono Volume", WM8955_MONOOUT_VOLUME, 0, 127, 0, out_tlv),
+SOC_SINGLE("Mono ZC Switch", WM8955_MONOOUT_VOLUME, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lmixer[] = {
+SOC_DAPM_SINGLE("Playback Switch", WM8955_LEFT_OUT_MIX_1, 8, 1, 0),
+SOC_DAPM_SINGLE("Bypass Switch", WM8955_LEFT_OUT_MIX_1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8955_LEFT_OUT_MIX_2, 8, 1, 0),
+SOC_DAPM_SINGLE("Mono Switch", WM8955_LEFT_OUT_MIX_2, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new rmixer[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8955_RIGHT_OUT_MIX_1, 8, 1, 0),
+SOC_DAPM_SINGLE("Mono Switch", WM8955_RIGHT_OUT_MIX_1, 7, 1, 0),
+SOC_DAPM_SINGLE("Playback Switch", WM8955_RIGHT_OUT_MIX_2, 8, 1, 0),
+SOC_DAPM_SINGLE("Bypass Switch", WM8955_RIGHT_OUT_MIX_2, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mmixer[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8955_MONO_OUT_MIX_1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8955_MONO_OUT_MIX_1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8955_MONO_OUT_MIX_2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8955_MONO_OUT_MIX_2, 7, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8955_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("MONOIN-"),
+SND_SOC_DAPM_INPUT("MONOIN+"),
+SND_SOC_DAPM_INPUT("LINEINR"),
+SND_SOC_DAPM_INPUT("LINEINL"),
+
+SND_SOC_DAPM_PGA("Mono Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM8955_POWER_MANAGEMENT_1, 0, 1, wm8955_sysclk,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("TSDEN", WM8955_ADDITIONAL_CONTROL_1, 8, 0, NULL, 0),
+
+SND_SOC_DAPM_DAC("DACL", "Playback", WM8955_POWER_MANAGEMENT_2, 8, 0),
+SND_SOC_DAPM_DAC("DACR", "Playback", WM8955_POWER_MANAGEMENT_2, 7, 0),
+
+SND_SOC_DAPM_PGA("LOUT1 PGA", WM8955_POWER_MANAGEMENT_2, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ROUT1 PGA", WM8955_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("LOUT2 PGA", WM8955_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ROUT2 PGA", WM8955_POWER_MANAGEMENT_2, 3, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MOUT PGA", WM8955_POWER_MANAGEMENT_2, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA("OUT3 PGA", WM8955_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
+
+/* The names are chosen to make the control names nice */
+SND_SOC_DAPM_MIXER("Left", SND_SOC_NOPM, 0, 0,
+		   lmixer, ARRAY_SIZE(lmixer)),
+SND_SOC_DAPM_MIXER("Right", SND_SOC_NOPM, 0, 0,
+		   rmixer, ARRAY_SIZE(rmixer)),
+SND_SOC_DAPM_MIXER("Mono", SND_SOC_NOPM, 0, 0,
+		   mmixer, ARRAY_SIZE(mmixer)),
+
+SND_SOC_DAPM_OUTPUT("LOUT1"),
+SND_SOC_DAPM_OUTPUT("ROUT1"),
+SND_SOC_DAPM_OUTPUT("LOUT2"),
+SND_SOC_DAPM_OUTPUT("ROUT2"),
+SND_SOC_DAPM_OUTPUT("MONOOUT"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+};
+
+static const struct snd_soc_dapm_route wm8955_dapm_routes[] = {
+	{ "DACL", NULL, "SYSCLK" },
+	{ "DACR", NULL, "SYSCLK" },
+
+	{ "Mono Input", NULL, "MONOIN-" },
+	{ "Mono Input", NULL, "MONOIN+" },
+
+	{ "Left", "Playback Switch", "DACL" },
+	{ "Left", "Right Playback Switch", "DACR" },
+	{ "Left", "Bypass Switch", "LINEINL" },
+	{ "Left", "Mono Switch", "Mono Input" },
+
+	{ "Right", "Playback Switch", "DACR" },
+	{ "Right", "Left Playback Switch", "DACL" },
+	{ "Right", "Bypass Switch", "LINEINR" },
+	{ "Right", "Mono Switch", "Mono Input" },
+
+	{ "Mono", "Left Playback Switch", "DACL" },
+	{ "Mono", "Right Playback Switch", "DACR" },
+	{ "Mono", "Left Bypass Switch", "LINEINL" },
+	{ "Mono", "Right Bypass Switch", "LINEINR" },
+
+	{ "LOUT1 PGA", NULL, "Left" },
+	{ "LOUT1", NULL, "TSDEN" },
+	{ "LOUT1", NULL, "LOUT1 PGA" },
+
+	{ "ROUT1 PGA", NULL, "Right" },
+	{ "ROUT1", NULL, "TSDEN" },
+	{ "ROUT1", NULL, "ROUT1 PGA" },
+
+	{ "LOUT2 PGA", NULL, "Left" },
+	{ "LOUT2", NULL, "TSDEN" },
+	{ "LOUT2", NULL, "LOUT2 PGA" },
+
+	{ "ROUT2 PGA", NULL, "Right" },
+	{ "ROUT2", NULL, "TSDEN" },
+	{ "ROUT2", NULL, "ROUT2 PGA" },
+
+	{ "MOUT PGA", NULL, "Mono" },
+	{ "MONOOUT", NULL, "MOUT PGA" },
+
+	/* OUT3 not currently implemented */
+	{ "OUT3", NULL, "OUT3 PGA" },
+};
+
+static int wm8955_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
+	int ret;
+	int wl;
+
+	switch (params_width(params)) {
+	case 16:
+		wl = 0;
+		break;
+	case 20:
+		wl = 0x4;
+		break;
+	case 24:
+		wl = 0x8;
+		break;
+	case 32:
+		wl = 0xc;
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_component_update_bits(component, WM8955_AUDIO_INTERFACE,
+			    WM8955_WL_MASK, wl);
+
+	wm8955->fs = params_rate(params);
+	wm8955_set_deemph(component);
+
+	/* If the chip is clocked then disable the clocks and force a
+	 * reconfiguration, otherwise DAPM will power up the
+	 * clocks for us later. */
+	ret = snd_soc_component_read32(component, WM8955_POWER_MANAGEMENT_1);
+	if (ret < 0)
+		return ret;
+	if (ret & WM8955_DIGENB) {
+		snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
+				    WM8955_DIGENB, 0);
+		snd_soc_component_update_bits(component, WM8955_CLOCKING_PLL,
+				    WM8955_PLL_RB | WM8955_PLLEN, 0);
+
+		wm8955_configure_clocking(component);
+	}
+
+	return 0;
+}
+
+
+static int wm8955_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+			     unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8955_priv *priv = snd_soc_component_get_drvdata(component);
+	int div;
+
+	switch (clk_id) {
+	case WM8955_CLK_MCLK:
+		if (freq > 15000000) {
+			priv->mclk_rate = freq /= 2;
+			div = WM8955_MCLKDIV2;
+		} else {
+			priv->mclk_rate = freq;
+			div = 0;
+		}
+
+		snd_soc_component_update_bits(component, WM8955_SAMPLE_RATE,
+				    WM8955_MCLKDIV2, div);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+	return 0;
+}
+
+static int wm8955_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 aif = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif |= WM8955_MS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_B:
+		aif |= WM8955_LRP;
+		/* fall through */
+	case SND_SOC_DAIFMT_DSP_A:
+		aif |= 0x3;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aif |= 0x2;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif |= 0x1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		/* frame inversion not valid for DSP modes */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif |= WM8955_BCLKINV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			aif |= WM8955_BCLKINV | WM8955_LRP;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif |= WM8955_BCLKINV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			aif |= WM8955_LRP;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8955_AUDIO_INTERFACE,
+			    WM8955_MS | WM8955_FORMAT_MASK | WM8955_BCLKINV |
+			    WM8955_LRP, aif);
+
+	return 0;
+}
+
+
+static int wm8955_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	int val;
+
+	if (mute)
+		val = WM8955_DACMU;
+	else
+		val = 0;
+
+	snd_soc_component_update_bits(component, WM8955_DAC_CONTROL, WM8955_DACMU, val);
+
+	return 0;
+}
+
+static int wm8955_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* VMID resistance 2*50k */
+		snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
+				    WM8955_VMIDSEL_MASK,
+				    0x1 << WM8955_VMIDSEL_SHIFT);
+
+		/* Default bias current */
+		snd_soc_component_update_bits(component, WM8955_ADDITIONAL_CONTROL_1,
+				    WM8955_VSEL_MASK,
+				    0x2 << WM8955_VSEL_SHIFT);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
+						    wm8955->supplies);
+			if (ret != 0) {
+				dev_err(component->dev,
+					"Failed to enable supplies: %d\n",
+					ret);
+				return ret;
+			}
+
+			regcache_sync(wm8955->regmap);
+
+			/* Enable VREF and VMID */
+			snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
+					    WM8955_VREF |
+					    WM8955_VMIDSEL_MASK,
+					    WM8955_VREF |
+					    0x3 << WM8955_VREF_SHIFT);
+
+			/* Let VMID ramp */
+			msleep(500);
+
+			/* High resistance VROI to maintain outputs */
+			snd_soc_component_update_bits(component,
+					    WM8955_ADDITIONAL_CONTROL_3,
+					    WM8955_VROI, WM8955_VROI);
+		}
+
+		/* Maintain VMID with 2*250k */
+		snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
+				    WM8955_VMIDSEL_MASK,
+				    0x2 << WM8955_VMIDSEL_SHIFT);
+
+		/* Minimum bias current */
+		snd_soc_component_update_bits(component, WM8955_ADDITIONAL_CONTROL_1,
+				    WM8955_VSEL_MASK, 0);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* Low resistance VROI to help discharge */
+		snd_soc_component_update_bits(component,
+				    WM8955_ADDITIONAL_CONTROL_3,
+				    WM8955_VROI, 0);
+
+		/* Turn off VMID and VREF */
+		snd_soc_component_update_bits(component, WM8955_POWER_MANAGEMENT_1,
+				    WM8955_VREF |
+				    WM8955_VMIDSEL_MASK, 0);
+
+		regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies),
+				       wm8955->supplies);
+		break;
+	}
+	return 0;
+}
+
+#define WM8955_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8955_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8955_dai_ops = {
+	.set_sysclk = wm8955_set_sysclk,
+	.set_fmt = wm8955_set_fmt,
+	.hw_params = wm8955_hw_params,
+	.digital_mute = wm8955_digital_mute,
+};
+
+static struct snd_soc_dai_driver wm8955_dai = {
+	.name = "wm8955-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = WM8955_RATES,
+		.formats = WM8955_FORMATS,
+	},
+	.ops = &wm8955_dai_ops,
+};
+
+static int wm8955_probe(struct snd_soc_component *component)
+{
+	struct wm8955_priv *wm8955 = snd_soc_component_get_drvdata(component);
+	struct wm8955_pdata *pdata = dev_get_platdata(component->dev);
+	int ret, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)
+		wm8955->supplies[i].supply = wm8955_supply_names[i];
+
+	ret = devm_regulator_bulk_get(component->dev, ARRAY_SIZE(wm8955->supplies),
+				 wm8955->supplies);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
+				    wm8955->supplies);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = wm8955_reset(component);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
+		goto err_enable;
+	}
+
+	/* Change some default settings - latch VU and enable ZC */
+	snd_soc_component_update_bits(component, WM8955_LEFT_DAC_VOLUME,
+			    WM8955_LDVU, WM8955_LDVU);
+	snd_soc_component_update_bits(component, WM8955_RIGHT_DAC_VOLUME,
+			    WM8955_RDVU, WM8955_RDVU);
+	snd_soc_component_update_bits(component, WM8955_LOUT1_VOLUME,
+			    WM8955_LO1VU | WM8955_LO1ZC,
+			    WM8955_LO1VU | WM8955_LO1ZC);
+	snd_soc_component_update_bits(component, WM8955_ROUT1_VOLUME,
+			    WM8955_RO1VU | WM8955_RO1ZC,
+			    WM8955_RO1VU | WM8955_RO1ZC);
+	snd_soc_component_update_bits(component, WM8955_LOUT2_VOLUME,
+			    WM8955_LO2VU | WM8955_LO2ZC,
+			    WM8955_LO2VU | WM8955_LO2ZC);
+	snd_soc_component_update_bits(component, WM8955_ROUT2_VOLUME,
+			    WM8955_RO2VU | WM8955_RO2ZC,
+			    WM8955_RO2VU | WM8955_RO2ZC);
+	snd_soc_component_update_bits(component, WM8955_MONOOUT_VOLUME,
+			    WM8955_MOZC, WM8955_MOZC);
+
+	/* Also enable adaptive bass boost by default */
+	snd_soc_component_update_bits(component, WM8955_BASS_CONTROL, WM8955_BB, WM8955_BB);
+
+	/* Set platform data values */
+	if (pdata) {
+		if (pdata->out2_speaker)
+			snd_soc_component_update_bits(component, WM8955_ADDITIONAL_CONTROL_2,
+					    WM8955_ROUT2INV, WM8955_ROUT2INV);
+
+		if (pdata->monoin_diff)
+			snd_soc_component_update_bits(component, WM8955_MONO_OUT_MIX_1,
+					    WM8955_DMEN, WM8955_DMEN);
+	}
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	/* Bias level configuration will have done an extra enable */
+	regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
+
+	return 0;
+
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
+	return ret;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8955 = {
+	.probe			= wm8955_probe,
+	.set_bias_level		= wm8955_set_bias_level,
+	.controls		= wm8955_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8955_snd_controls),
+	.dapm_widgets		= wm8955_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8955_dapm_widgets),
+	.dapm_routes		= wm8955_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8955_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8955_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = WM8955_MAX_REGISTER,
+	.volatile_reg = wm8955_volatile,
+	.writeable_reg = wm8955_writeable,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8955_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8955_reg_defaults),
+};
+
+static int wm8955_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8955_priv *wm8955;
+	int ret;
+
+	wm8955 = devm_kzalloc(&i2c->dev, sizeof(struct wm8955_priv),
+			      GFP_KERNEL);
+	if (wm8955 == NULL)
+		return -ENOMEM;
+
+	wm8955->regmap = devm_regmap_init_i2c(i2c, &wm8955_regmap);
+	if (IS_ERR(wm8955->regmap)) {
+		ret = PTR_ERR(wm8955->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, wm8955);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8955, &wm8955_dai, 1);
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8955_i2c_id[] = {
+	{ "wm8955", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id);
+
+static struct i2c_driver wm8955_i2c_driver = {
+	.driver = {
+		.name = "wm8955",
+	},
+	.probe =    wm8955_i2c_probe,
+	.id_table = wm8955_i2c_id,
+};
+
+module_i2c_driver(wm8955_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8955 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8955.h b/sound/soc/codecs/wm8955.h
new file mode 100644
index 0000000..d13fd5c
--- /dev/null
+++ b/sound/soc/codecs/wm8955.h
@@ -0,0 +1,486 @@
+/*
+ * wm8955.h  --  WM8904 ASoC driver
+ *
+ * Copyright 2009 Wolfson Microelectronics, plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8955_H
+#define _WM8955_H
+
+#define WM8955_CLK_MCLK 1
+
+/*
+ * Register values.
+ */
+#define WM8955_LOUT1_VOLUME                     0x02
+#define WM8955_ROUT1_VOLUME                     0x03
+#define WM8955_DAC_CONTROL                      0x05
+#define WM8955_AUDIO_INTERFACE                  0x07
+#define WM8955_SAMPLE_RATE                      0x08
+#define WM8955_LEFT_DAC_VOLUME                  0x0A
+#define WM8955_RIGHT_DAC_VOLUME                 0x0B
+#define WM8955_BASS_CONTROL                     0x0C
+#define WM8955_TREBLE_CONTROL                   0x0D
+#define WM8955_RESET                            0x0F
+#define WM8955_ADDITIONAL_CONTROL_1             0x17
+#define WM8955_ADDITIONAL_CONTROL_2             0x18
+#define WM8955_POWER_MANAGEMENT_1               0x19
+#define WM8955_POWER_MANAGEMENT_2               0x1A
+#define WM8955_ADDITIONAL_CONTROL_3             0x1B
+#define WM8955_LEFT_OUT_MIX_1                   0x22
+#define WM8955_LEFT_OUT_MIX_2                   0x23
+#define WM8955_RIGHT_OUT_MIX_1                  0x24
+#define WM8955_RIGHT_OUT_MIX_2                  0x25
+#define WM8955_MONO_OUT_MIX_1                   0x26
+#define WM8955_MONO_OUT_MIX_2                   0x27
+#define WM8955_LOUT2_VOLUME                     0x28
+#define WM8955_ROUT2_VOLUME                     0x29
+#define WM8955_MONOOUT_VOLUME                   0x2A
+#define WM8955_CLOCKING_PLL                     0x2B
+#define WM8955_PLL_CONTROL_1                    0x2C
+#define WM8955_PLL_CONTROL_2                    0x2D
+#define WM8955_PLL_CONTROL_3                    0x2E
+#define WM8955_PLL_CONTROL_4                    0x3B
+
+#define WM8955_REGISTER_COUNT                   29
+#define WM8955_MAX_REGISTER                     0x3B
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R2 (0x02) - LOUT1 volume
+ */
+#define WM8955_LO1VU                            0x0100  /* LO1VU */
+#define WM8955_LO1VU_MASK                       0x0100  /* LO1VU */
+#define WM8955_LO1VU_SHIFT                           8  /* LO1VU */
+#define WM8955_LO1VU_WIDTH                           1  /* LO1VU */
+#define WM8955_LO1ZC                            0x0080  /* LO1ZC */
+#define WM8955_LO1ZC_MASK                       0x0080  /* LO1ZC */
+#define WM8955_LO1ZC_SHIFT                           7  /* LO1ZC */
+#define WM8955_LO1ZC_WIDTH                           1  /* LO1ZC */
+#define WM8955_LOUTVOL_MASK                     0x007F  /* LOUTVOL - [6:0] */
+#define WM8955_LOUTVOL_SHIFT                         0  /* LOUTVOL - [6:0] */
+#define WM8955_LOUTVOL_WIDTH                         7  /* LOUTVOL - [6:0] */
+
+/*
+ * R3 (0x03) - ROUT1 volume
+ */
+#define WM8955_RO1VU                            0x0100  /* RO1VU */
+#define WM8955_RO1VU_MASK                       0x0100  /* RO1VU */
+#define WM8955_RO1VU_SHIFT                           8  /* RO1VU */
+#define WM8955_RO1VU_WIDTH                           1  /* RO1VU */
+#define WM8955_RO1ZC                            0x0080  /* RO1ZC */
+#define WM8955_RO1ZC_MASK                       0x0080  /* RO1ZC */
+#define WM8955_RO1ZC_SHIFT                           7  /* RO1ZC */
+#define WM8955_RO1ZC_WIDTH                           1  /* RO1ZC */
+#define WM8955_ROUTVOL_MASK                     0x007F  /* ROUTVOL - [6:0] */
+#define WM8955_ROUTVOL_SHIFT                         0  /* ROUTVOL - [6:0] */
+#define WM8955_ROUTVOL_WIDTH                         7  /* ROUTVOL - [6:0] */
+
+/*
+ * R5 (0x05) - DAC Control
+ */
+#define WM8955_DAT                              0x0080  /* DAT */
+#define WM8955_DAT_MASK                         0x0080  /* DAT */
+#define WM8955_DAT_SHIFT                             7  /* DAT */
+#define WM8955_DAT_WIDTH                             1  /* DAT */
+#define WM8955_DACMU                            0x0008  /* DACMU */
+#define WM8955_DACMU_MASK                       0x0008  /* DACMU */
+#define WM8955_DACMU_SHIFT                           3  /* DACMU */
+#define WM8955_DACMU_WIDTH                           1  /* DACMU */
+#define WM8955_DEEMPH_MASK                      0x0006  /* DEEMPH - [2:1] */
+#define WM8955_DEEMPH_SHIFT                          1  /* DEEMPH - [2:1] */
+#define WM8955_DEEMPH_WIDTH                          2  /* DEEMPH - [2:1] */
+
+/*
+ * R7 (0x07) - Audio Interface
+ */
+#define WM8955_BCLKINV                          0x0080  /* BCLKINV */
+#define WM8955_BCLKINV_MASK                     0x0080  /* BCLKINV */
+#define WM8955_BCLKINV_SHIFT                         7  /* BCLKINV */
+#define WM8955_BCLKINV_WIDTH                         1  /* BCLKINV */
+#define WM8955_MS                               0x0040  /* MS */
+#define WM8955_MS_MASK                          0x0040  /* MS */
+#define WM8955_MS_SHIFT                              6  /* MS */
+#define WM8955_MS_WIDTH                              1  /* MS */
+#define WM8955_LRSWAP                           0x0020  /* LRSWAP */
+#define WM8955_LRSWAP_MASK                      0x0020  /* LRSWAP */
+#define WM8955_LRSWAP_SHIFT                          5  /* LRSWAP */
+#define WM8955_LRSWAP_WIDTH                          1  /* LRSWAP */
+#define WM8955_LRP                              0x0010  /* LRP */
+#define WM8955_LRP_MASK                         0x0010  /* LRP */
+#define WM8955_LRP_SHIFT                             4  /* LRP */
+#define WM8955_LRP_WIDTH                             1  /* LRP */
+#define WM8955_WL_MASK                          0x000C  /* WL - [3:2] */
+#define WM8955_WL_SHIFT                              2  /* WL - [3:2] */
+#define WM8955_WL_WIDTH                              2  /* WL - [3:2] */
+#define WM8955_FORMAT_MASK                      0x0003  /* FORMAT - [1:0] */
+#define WM8955_FORMAT_SHIFT                          0  /* FORMAT - [1:0] */
+#define WM8955_FORMAT_WIDTH                          2  /* FORMAT - [1:0] */
+
+/*
+ * R8 (0x08) - Sample Rate
+ */
+#define WM8955_BCLKDIV2                         0x0080  /* BCLKDIV2 */
+#define WM8955_BCLKDIV2_MASK                    0x0080  /* BCLKDIV2 */
+#define WM8955_BCLKDIV2_SHIFT                        7  /* BCLKDIV2 */
+#define WM8955_BCLKDIV2_WIDTH                        1  /* BCLKDIV2 */
+#define WM8955_MCLKDIV2                         0x0040  /* MCLKDIV2 */
+#define WM8955_MCLKDIV2_MASK                    0x0040  /* MCLKDIV2 */
+#define WM8955_MCLKDIV2_SHIFT                        6  /* MCLKDIV2 */
+#define WM8955_MCLKDIV2_WIDTH                        1  /* MCLKDIV2 */
+#define WM8955_SR_MASK                          0x003E  /* SR - [5:1] */
+#define WM8955_SR_SHIFT                              1  /* SR - [5:1] */
+#define WM8955_SR_WIDTH                              5  /* SR - [5:1] */
+#define WM8955_USB                              0x0001  /* USB */
+#define WM8955_USB_MASK                         0x0001  /* USB */
+#define WM8955_USB_SHIFT                             0  /* USB */
+#define WM8955_USB_WIDTH                             1  /* USB */
+
+/*
+ * R10 (0x0A) - Left DAC volume
+ */
+#define WM8955_LDVU                             0x0100  /* LDVU */
+#define WM8955_LDVU_MASK                        0x0100  /* LDVU */
+#define WM8955_LDVU_SHIFT                            8  /* LDVU */
+#define WM8955_LDVU_WIDTH                            1  /* LDVU */
+#define WM8955_LDACVOL_MASK                     0x00FF  /* LDACVOL - [7:0] */
+#define WM8955_LDACVOL_SHIFT                         0  /* LDACVOL - [7:0] */
+#define WM8955_LDACVOL_WIDTH                         8  /* LDACVOL - [7:0] */
+
+/*
+ * R11 (0x0B) - Right DAC volume
+ */
+#define WM8955_RDVU                             0x0100  /* RDVU */
+#define WM8955_RDVU_MASK                        0x0100  /* RDVU */
+#define WM8955_RDVU_SHIFT                            8  /* RDVU */
+#define WM8955_RDVU_WIDTH                            1  /* RDVU */
+#define WM8955_RDACVOL_MASK                     0x00FF  /* RDACVOL - [7:0] */
+#define WM8955_RDACVOL_SHIFT                         0  /* RDACVOL - [7:0] */
+#define WM8955_RDACVOL_WIDTH                         8  /* RDACVOL - [7:0] */
+
+/*
+ * R12 (0x0C) - Bass control
+ */
+#define WM8955_BB                               0x0080  /* BB */
+#define WM8955_BB_MASK                          0x0080  /* BB */
+#define WM8955_BB_SHIFT                              7  /* BB */
+#define WM8955_BB_WIDTH                              1  /* BB */
+#define WM8955_BC                               0x0040  /* BC */
+#define WM8955_BC_MASK                          0x0040  /* BC */
+#define WM8955_BC_SHIFT                              6  /* BC */
+#define WM8955_BC_WIDTH                              1  /* BC */
+#define WM8955_BASS_MASK                        0x000F  /* BASS - [3:0] */
+#define WM8955_BASS_SHIFT                            0  /* BASS - [3:0] */
+#define WM8955_BASS_WIDTH                            4  /* BASS - [3:0] */
+
+/*
+ * R13 (0x0D) - Treble control
+ */
+#define WM8955_TC                               0x0040  /* TC */
+#define WM8955_TC_MASK                          0x0040  /* TC */
+#define WM8955_TC_SHIFT                              6  /* TC */
+#define WM8955_TC_WIDTH                              1  /* TC */
+#define WM8955_TRBL_MASK                        0x000F  /* TRBL - [3:0] */
+#define WM8955_TRBL_SHIFT                            0  /* TRBL - [3:0] */
+#define WM8955_TRBL_WIDTH                            4  /* TRBL - [3:0] */
+
+/*
+ * R15 (0x0F) - Reset
+ */
+#define WM8955_RESET_MASK                       0x01FF  /* RESET - [8:0] */
+#define WM8955_RESET_SHIFT                           0  /* RESET - [8:0] */
+#define WM8955_RESET_WIDTH                           9  /* RESET - [8:0] */
+
+/*
+ * R23 (0x17) - Additional control (1)
+ */
+#define WM8955_TSDEN                            0x0100  /* TSDEN */
+#define WM8955_TSDEN_MASK                       0x0100  /* TSDEN */
+#define WM8955_TSDEN_SHIFT                           8  /* TSDEN */
+#define WM8955_TSDEN_WIDTH                           1  /* TSDEN */
+#define WM8955_VSEL_MASK                        0x00C0  /* VSEL - [7:6] */
+#define WM8955_VSEL_SHIFT                            6  /* VSEL - [7:6] */
+#define WM8955_VSEL_WIDTH                            2  /* VSEL - [7:6] */
+#define WM8955_DMONOMIX_MASK                    0x0030  /* DMONOMIX - [5:4] */
+#define WM8955_DMONOMIX_SHIFT                        4  /* DMONOMIX - [5:4] */
+#define WM8955_DMONOMIX_WIDTH                        2  /* DMONOMIX - [5:4] */
+#define WM8955_DACINV                           0x0002  /* DACINV */
+#define WM8955_DACINV_MASK                      0x0002  /* DACINV */
+#define WM8955_DACINV_SHIFT                          1  /* DACINV */
+#define WM8955_DACINV_WIDTH                          1  /* DACINV */
+#define WM8955_TOEN                             0x0001  /* TOEN */
+#define WM8955_TOEN_MASK                        0x0001  /* TOEN */
+#define WM8955_TOEN_SHIFT                            0  /* TOEN */
+#define WM8955_TOEN_WIDTH                            1  /* TOEN */
+
+/*
+ * R24 (0x18) - Additional control (2)
+ */
+#define WM8955_OUT3SW_MASK                      0x0180  /* OUT3SW - [8:7] */
+#define WM8955_OUT3SW_SHIFT                          7  /* OUT3SW - [8:7] */
+#define WM8955_OUT3SW_WIDTH                          2  /* OUT3SW - [8:7] */
+#define WM8955_ROUT2INV                         0x0010  /* ROUT2INV */
+#define WM8955_ROUT2INV_MASK                    0x0010  /* ROUT2INV */
+#define WM8955_ROUT2INV_SHIFT                        4  /* ROUT2INV */
+#define WM8955_ROUT2INV_WIDTH                        1  /* ROUT2INV */
+#define WM8955_DACOSR                           0x0001  /* DACOSR */
+#define WM8955_DACOSR_MASK                      0x0001  /* DACOSR */
+#define WM8955_DACOSR_SHIFT                          0  /* DACOSR */
+#define WM8955_DACOSR_WIDTH                          1  /* DACOSR */
+
+/*
+ * R25 (0x19) - Power Management (1)
+ */
+#define WM8955_VMIDSEL_MASK                     0x0180  /* VMIDSEL - [8:7] */
+#define WM8955_VMIDSEL_SHIFT                         7  /* VMIDSEL - [8:7] */
+#define WM8955_VMIDSEL_WIDTH                         2  /* VMIDSEL - [8:7] */
+#define WM8955_VREF                             0x0040  /* VREF */
+#define WM8955_VREF_MASK                        0x0040  /* VREF */
+#define WM8955_VREF_SHIFT                            6  /* VREF */
+#define WM8955_VREF_WIDTH                            1  /* VREF */
+#define WM8955_DIGENB                           0x0001  /* DIGENB */
+#define WM8955_DIGENB_MASK                      0x0001  /* DIGENB */
+#define WM8955_DIGENB_SHIFT                          0  /* DIGENB */
+#define WM8955_DIGENB_WIDTH                          1  /* DIGENB */
+
+/*
+ * R26 (0x1A) - Power Management (2)
+ */
+#define WM8955_DACL                             0x0100  /* DACL */
+#define WM8955_DACL_MASK                        0x0100  /* DACL */
+#define WM8955_DACL_SHIFT                            8  /* DACL */
+#define WM8955_DACL_WIDTH                            1  /* DACL */
+#define WM8955_DACR                             0x0080  /* DACR */
+#define WM8955_DACR_MASK                        0x0080  /* DACR */
+#define WM8955_DACR_SHIFT                            7  /* DACR */
+#define WM8955_DACR_WIDTH                            1  /* DACR */
+#define WM8955_LOUT1                            0x0040  /* LOUT1 */
+#define WM8955_LOUT1_MASK                       0x0040  /* LOUT1 */
+#define WM8955_LOUT1_SHIFT                           6  /* LOUT1 */
+#define WM8955_LOUT1_WIDTH                           1  /* LOUT1 */
+#define WM8955_ROUT1                            0x0020  /* ROUT1 */
+#define WM8955_ROUT1_MASK                       0x0020  /* ROUT1 */
+#define WM8955_ROUT1_SHIFT                           5  /* ROUT1 */
+#define WM8955_ROUT1_WIDTH                           1  /* ROUT1 */
+#define WM8955_LOUT2                            0x0010  /* LOUT2 */
+#define WM8955_LOUT2_MASK                       0x0010  /* LOUT2 */
+#define WM8955_LOUT2_SHIFT                           4  /* LOUT2 */
+#define WM8955_LOUT2_WIDTH                           1  /* LOUT2 */
+#define WM8955_ROUT2                            0x0008  /* ROUT2 */
+#define WM8955_ROUT2_MASK                       0x0008  /* ROUT2 */
+#define WM8955_ROUT2_SHIFT                           3  /* ROUT2 */
+#define WM8955_ROUT2_WIDTH                           1  /* ROUT2 */
+#define WM8955_MONO                             0x0004  /* MONO */
+#define WM8955_MONO_MASK                        0x0004  /* MONO */
+#define WM8955_MONO_SHIFT                            2  /* MONO */
+#define WM8955_MONO_WIDTH                            1  /* MONO */
+#define WM8955_OUT3                             0x0002  /* OUT3 */
+#define WM8955_OUT3_MASK                        0x0002  /* OUT3 */
+#define WM8955_OUT3_SHIFT                            1  /* OUT3 */
+#define WM8955_OUT3_WIDTH                            1  /* OUT3 */
+
+/*
+ * R27 (0x1B) - Additional Control (3)
+ */
+#define WM8955_VROI                             0x0040  /* VROI */
+#define WM8955_VROI_MASK                        0x0040  /* VROI */
+#define WM8955_VROI_SHIFT                            6  /* VROI */
+#define WM8955_VROI_WIDTH                            1  /* VROI */
+
+/*
+ * R34 (0x22) - Left out Mix (1)
+ */
+#define WM8955_LD2LO                            0x0100  /* LD2LO */
+#define WM8955_LD2LO_MASK                       0x0100  /* LD2LO */
+#define WM8955_LD2LO_SHIFT                           8  /* LD2LO */
+#define WM8955_LD2LO_WIDTH                           1  /* LD2LO */
+#define WM8955_LI2LO                            0x0080  /* LI2LO */
+#define WM8955_LI2LO_MASK                       0x0080  /* LI2LO */
+#define WM8955_LI2LO_SHIFT                           7  /* LI2LO */
+#define WM8955_LI2LO_WIDTH                           1  /* LI2LO */
+#define WM8955_LI2LOVOL_MASK                    0x0070  /* LI2LOVOL - [6:4] */
+#define WM8955_LI2LOVOL_SHIFT                        4  /* LI2LOVOL - [6:4] */
+#define WM8955_LI2LOVOL_WIDTH                        3  /* LI2LOVOL - [6:4] */
+
+/*
+ * R35 (0x23) - Left out Mix (2)
+ */
+#define WM8955_RD2LO                            0x0100  /* RD2LO */
+#define WM8955_RD2LO_MASK                       0x0100  /* RD2LO */
+#define WM8955_RD2LO_SHIFT                           8  /* RD2LO */
+#define WM8955_RD2LO_WIDTH                           1  /* RD2LO */
+#define WM8955_RI2LO                            0x0080  /* RI2LO */
+#define WM8955_RI2LO_MASK                       0x0080  /* RI2LO */
+#define WM8955_RI2LO_SHIFT                           7  /* RI2LO */
+#define WM8955_RI2LO_WIDTH                           1  /* RI2LO */
+#define WM8955_RI2LOVOL_MASK                    0x0070  /* RI2LOVOL - [6:4] */
+#define WM8955_RI2LOVOL_SHIFT                        4  /* RI2LOVOL - [6:4] */
+#define WM8955_RI2LOVOL_WIDTH                        3  /* RI2LOVOL - [6:4] */
+
+/*
+ * R36 (0x24) - Right out Mix (1)
+ */
+#define WM8955_LD2RO                            0x0100  /* LD2RO */
+#define WM8955_LD2RO_MASK                       0x0100  /* LD2RO */
+#define WM8955_LD2RO_SHIFT                           8  /* LD2RO */
+#define WM8955_LD2RO_WIDTH                           1  /* LD2RO */
+#define WM8955_LI2RO                            0x0080  /* LI2RO */
+#define WM8955_LI2RO_MASK                       0x0080  /* LI2RO */
+#define WM8955_LI2RO_SHIFT                           7  /* LI2RO */
+#define WM8955_LI2RO_WIDTH                           1  /* LI2RO */
+#define WM8955_LI2ROVOL_MASK                    0x0070  /* LI2ROVOL - [6:4] */
+#define WM8955_LI2ROVOL_SHIFT                        4  /* LI2ROVOL - [6:4] */
+#define WM8955_LI2ROVOL_WIDTH                        3  /* LI2ROVOL - [6:4] */
+
+/*
+ * R37 (0x25) - Right Out Mix (2)
+ */
+#define WM8955_RD2RO                            0x0100  /* RD2RO */
+#define WM8955_RD2RO_MASK                       0x0100  /* RD2RO */
+#define WM8955_RD2RO_SHIFT                           8  /* RD2RO */
+#define WM8955_RD2RO_WIDTH                           1  /* RD2RO */
+#define WM8955_RI2RO                            0x0080  /* RI2RO */
+#define WM8955_RI2RO_MASK                       0x0080  /* RI2RO */
+#define WM8955_RI2RO_SHIFT                           7  /* RI2RO */
+#define WM8955_RI2RO_WIDTH                           1  /* RI2RO */
+#define WM8955_RI2ROVOL_MASK                    0x0070  /* RI2ROVOL - [6:4] */
+#define WM8955_RI2ROVOL_SHIFT                        4  /* RI2ROVOL - [6:4] */
+#define WM8955_RI2ROVOL_WIDTH                        3  /* RI2ROVOL - [6:4] */
+
+/*
+ * R38 (0x26) - Mono out Mix (1)
+ */
+#define WM8955_LD2MO                            0x0100  /* LD2MO */
+#define WM8955_LD2MO_MASK                       0x0100  /* LD2MO */
+#define WM8955_LD2MO_SHIFT                           8  /* LD2MO */
+#define WM8955_LD2MO_WIDTH                           1  /* LD2MO */
+#define WM8955_LI2MO                            0x0080  /* LI2MO */
+#define WM8955_LI2MO_MASK                       0x0080  /* LI2MO */
+#define WM8955_LI2MO_SHIFT                           7  /* LI2MO */
+#define WM8955_LI2MO_WIDTH                           1  /* LI2MO */
+#define WM8955_LI2MOVOL_MASK                    0x0070  /* LI2MOVOL - [6:4] */
+#define WM8955_LI2MOVOL_SHIFT                        4  /* LI2MOVOL - [6:4] */
+#define WM8955_LI2MOVOL_WIDTH                        3  /* LI2MOVOL - [6:4] */
+#define WM8955_DMEN                             0x0001  /* DMEN */
+#define WM8955_DMEN_MASK                        0x0001  /* DMEN */
+#define WM8955_DMEN_SHIFT                            0  /* DMEN */
+#define WM8955_DMEN_WIDTH                            1  /* DMEN */
+
+/*
+ * R39 (0x27) - Mono out Mix (2)
+ */
+#define WM8955_RD2MO                            0x0100  /* RD2MO */
+#define WM8955_RD2MO_MASK                       0x0100  /* RD2MO */
+#define WM8955_RD2MO_SHIFT                           8  /* RD2MO */
+#define WM8955_RD2MO_WIDTH                           1  /* RD2MO */
+#define WM8955_RI2MO                            0x0080  /* RI2MO */
+#define WM8955_RI2MO_MASK                       0x0080  /* RI2MO */
+#define WM8955_RI2MO_SHIFT                           7  /* RI2MO */
+#define WM8955_RI2MO_WIDTH                           1  /* RI2MO */
+#define WM8955_RI2MOVOL_MASK                    0x0070  /* RI2MOVOL - [6:4] */
+#define WM8955_RI2MOVOL_SHIFT                        4  /* RI2MOVOL - [6:4] */
+#define WM8955_RI2MOVOL_WIDTH                        3  /* RI2MOVOL - [6:4] */
+
+/*
+ * R40 (0x28) - LOUT2 volume
+ */
+#define WM8955_LO2VU                            0x0100  /* LO2VU */
+#define WM8955_LO2VU_MASK                       0x0100  /* LO2VU */
+#define WM8955_LO2VU_SHIFT                           8  /* LO2VU */
+#define WM8955_LO2VU_WIDTH                           1  /* LO2VU */
+#define WM8955_LO2ZC                            0x0080  /* LO2ZC */
+#define WM8955_LO2ZC_MASK                       0x0080  /* LO2ZC */
+#define WM8955_LO2ZC_SHIFT                           7  /* LO2ZC */
+#define WM8955_LO2ZC_WIDTH                           1  /* LO2ZC */
+#define WM8955_LOUT2VOL_MASK                    0x007F  /* LOUT2VOL - [6:0] */
+#define WM8955_LOUT2VOL_SHIFT                        0  /* LOUT2VOL - [6:0] */
+#define WM8955_LOUT2VOL_WIDTH                        7  /* LOUT2VOL - [6:0] */
+
+/*
+ * R41 (0x29) - ROUT2 volume
+ */
+#define WM8955_RO2VU                            0x0100  /* RO2VU */
+#define WM8955_RO2VU_MASK                       0x0100  /* RO2VU */
+#define WM8955_RO2VU_SHIFT                           8  /* RO2VU */
+#define WM8955_RO2VU_WIDTH                           1  /* RO2VU */
+#define WM8955_RO2ZC                            0x0080  /* RO2ZC */
+#define WM8955_RO2ZC_MASK                       0x0080  /* RO2ZC */
+#define WM8955_RO2ZC_SHIFT                           7  /* RO2ZC */
+#define WM8955_RO2ZC_WIDTH                           1  /* RO2ZC */
+#define WM8955_ROUT2VOL_MASK                    0x007F  /* ROUT2VOL - [6:0] */
+#define WM8955_ROUT2VOL_SHIFT                        0  /* ROUT2VOL - [6:0] */
+#define WM8955_ROUT2VOL_WIDTH                        7  /* ROUT2VOL - [6:0] */
+
+/*
+ * R42 (0x2A) - MONOOUT volume
+ */
+#define WM8955_MOZC                             0x0080  /* MOZC */
+#define WM8955_MOZC_MASK                        0x0080  /* MOZC */
+#define WM8955_MOZC_SHIFT                            7  /* MOZC */
+#define WM8955_MOZC_WIDTH                            1  /* MOZC */
+#define WM8955_MOUTVOL_MASK                     0x007F  /* MOUTVOL - [6:0] */
+#define WM8955_MOUTVOL_SHIFT                         0  /* MOUTVOL - [6:0] */
+#define WM8955_MOUTVOL_WIDTH                         7  /* MOUTVOL - [6:0] */
+
+/*
+ * R43 (0x2B) - Clocking / PLL
+ */
+#define WM8955_MCLKSEL                          0x0100  /* MCLKSEL */
+#define WM8955_MCLKSEL_MASK                     0x0100  /* MCLKSEL */
+#define WM8955_MCLKSEL_SHIFT                         8  /* MCLKSEL */
+#define WM8955_MCLKSEL_WIDTH                         1  /* MCLKSEL */
+#define WM8955_PLLOUTDIV2                       0x0020  /* PLLOUTDIV2 */
+#define WM8955_PLLOUTDIV2_MASK                  0x0020  /* PLLOUTDIV2 */
+#define WM8955_PLLOUTDIV2_SHIFT                      5  /* PLLOUTDIV2 */
+#define WM8955_PLLOUTDIV2_WIDTH                      1  /* PLLOUTDIV2 */
+#define WM8955_PLL_RB                           0x0010  /* PLL_RB */
+#define WM8955_PLL_RB_MASK                      0x0010  /* PLL_RB */
+#define WM8955_PLL_RB_SHIFT                          4  /* PLL_RB */
+#define WM8955_PLL_RB_WIDTH                          1  /* PLL_RB */
+#define WM8955_PLLEN                            0x0008  /* PLLEN */
+#define WM8955_PLLEN_MASK                       0x0008  /* PLLEN */
+#define WM8955_PLLEN_SHIFT                           3  /* PLLEN */
+#define WM8955_PLLEN_WIDTH                           1  /* PLLEN */
+
+/*
+ * R44 (0x2C) - PLL Control 1
+ */
+#define WM8955_N_MASK                           0x01E0  /* N - [8:5] */
+#define WM8955_N_SHIFT                               5  /* N - [8:5] */
+#define WM8955_N_WIDTH                               4  /* N - [8:5] */
+#define WM8955_K_21_18_MASK                     0x000F  /* K(21:18) - [3:0] */
+#define WM8955_K_21_18_SHIFT                         0  /* K(21:18) - [3:0] */
+#define WM8955_K_21_18_WIDTH                         4  /* K(21:18) - [3:0] */
+
+/*
+ * R45 (0x2D) - PLL Control 2
+ */
+#define WM8955_K_17_9_MASK                      0x01FF  /* K(17:9) - [8:0] */
+#define WM8955_K_17_9_SHIFT                          0  /* K(17:9) - [8:0] */
+#define WM8955_K_17_9_WIDTH                          9  /* K(17:9) - [8:0] */
+
+/*
+ * R46 (0x2E) - PLL Control 3
+ */
+#define WM8955_K_8_0_MASK                       0x01FF  /* K(8:0) - [8:0] */
+#define WM8955_K_8_0_SHIFT                           0  /* K(8:0) - [8:0] */
+#define WM8955_K_8_0_WIDTH                           9  /* K(8:0) - [8:0] */
+
+/*
+ * R59 (0x3B) - PLL Control 4
+ */
+#define WM8955_KEN                              0x0080  /* KEN */
+#define WM8955_KEN_MASK                         0x0080  /* KEN */
+#define WM8955_KEN_SHIFT                             7  /* KEN */
+#define WM8955_KEN_WIDTH                             1  /* KEN */
+
+#endif
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
new file mode 100644
index 0000000..108e8bf
--- /dev/null
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -0,0 +1,1035 @@
+/*
+ * wm8958-dsp2.c  --  WM8958 DSP2 support
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <trace/events/asoc.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include <linux/mfd/wm8994/pdata.h>
+#include <linux/mfd/wm8994/gpio.h>
+
+#include "wm8994.h"
+
+#define WM_FW_BLOCK_INFO 0xff
+#define WM_FW_BLOCK_PM   0x00
+#define WM_FW_BLOCK_X    0x01
+#define WM_FW_BLOCK_Y    0x02
+#define WM_FW_BLOCK_Z    0x03
+#define WM_FW_BLOCK_I    0x06
+#define WM_FW_BLOCK_A    0x08
+#define WM_FW_BLOCK_C    0x0c
+
+static int wm8958_dsp2_fw(struct snd_soc_component *component, const char *name,
+			  const struct firmware *fw, bool check)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	u64 data64;
+	u32 data32;
+	const u8 *data;
+	char *str;
+	size_t block_len, len;
+	int ret = 0;
+
+	/* Suppress unneeded downloads */
+	if (wm8994->cur_fw == fw)
+		return 0;
+
+	if (fw->size < 32) {
+		dev_err(component->dev, "%s: firmware too short (%zd bytes)\n",
+			name, fw->size);
+		goto err;
+	}
+
+	if (memcmp(fw->data, "WMFW", 4) != 0) {
+		memcpy(&data32, fw->data, sizeof(data32));
+		data32 = be32_to_cpu(data32);
+		dev_err(component->dev, "%s: firmware has bad file magic %08x\n",
+			name, data32);
+		goto err;
+	}
+
+	memcpy(&data32, fw->data + 4, sizeof(data32));
+	len = be32_to_cpu(data32);
+
+	memcpy(&data32, fw->data + 8, sizeof(data32));
+	data32 = be32_to_cpu(data32);
+	if ((data32 >> 24) & 0xff) {
+		dev_err(component->dev, "%s: unsupported firmware version %d\n",
+			name, (data32 >> 24) & 0xff);
+		goto err;
+	}
+	if ((data32 & 0xffff) != 8958) {
+		dev_err(component->dev, "%s: unsupported target device %d\n",
+			name, data32 & 0xffff);
+		goto err;
+	}
+	if (((data32 >> 16) & 0xff) != 0xc) {
+		dev_err(component->dev, "%s: unsupported target core %d\n",
+			name, (data32 >> 16) & 0xff);
+		goto err;
+	}
+
+	if (check) {
+		memcpy(&data64, fw->data + 24, sizeof(u64));
+		dev_info(component->dev, "%s timestamp %llx\n",
+			 name, be64_to_cpu(data64));
+	} else {
+		snd_soc_component_write(component, 0x102, 0x2);
+		snd_soc_component_write(component, 0x900, 0x2);
+	}
+
+	data = fw->data + len;
+	len = fw->size - len;
+	while (len) {
+		if (len < 12) {
+			dev_err(component->dev, "%s short data block of %zd\n",
+				name, len);
+			goto err;
+		}
+
+		memcpy(&data32, data + 4, sizeof(data32));
+		block_len = be32_to_cpu(data32);
+		if (block_len + 8 > len) {
+			dev_err(component->dev, "%zd byte block longer than file\n",
+				block_len);
+			goto err;
+		}
+		if (block_len == 0) {
+			dev_err(component->dev, "Zero length block\n");
+			goto err;
+		}
+
+		memcpy(&data32, data, sizeof(data32));
+		data32 = be32_to_cpu(data32);
+
+		switch ((data32 >> 24) & 0xff) {
+		case WM_FW_BLOCK_INFO:
+			/* Informational text */
+			if (!check)
+				break;
+
+			str = kzalloc(block_len + 1, GFP_KERNEL);
+			if (str) {
+				memcpy(str, data + 8, block_len);
+				dev_info(component->dev, "%s: %s\n", name, str);
+				kfree(str);
+			} else {
+				dev_err(component->dev, "Out of memory\n");
+			}
+			break;
+		case WM_FW_BLOCK_PM:
+		case WM_FW_BLOCK_X:
+		case WM_FW_BLOCK_Y:
+		case WM_FW_BLOCK_Z:
+		case WM_FW_BLOCK_I:
+		case WM_FW_BLOCK_A:
+		case WM_FW_BLOCK_C:
+			dev_dbg(component->dev, "%s: %zd bytes of %x@%x\n", name,
+				block_len, (data32 >> 24) & 0xff,
+				data32 & 0xffffff);
+
+			if (check)
+				break;
+
+			data32 &= 0xffffff;
+
+			wm8994_bulk_write(wm8994->wm8994,
+					  data32 & 0xffffff,
+					  block_len / 2,
+					  (void *)(data + 8));
+
+			break;
+		default:
+			dev_warn(component->dev, "%s: unknown block type %d\n",
+				 name, (data32 >> 24) & 0xff);
+			break;
+		}
+
+		/* Round up to the next 32 bit word */
+		block_len += block_len % 4;
+
+		data += block_len + 8;
+		len -= block_len + 8;
+	}
+
+	if (!check) {
+		dev_dbg(component->dev, "%s: download done\n", name);
+		wm8994->cur_fw = fw;
+	} else {
+		dev_info(component->dev, "%s: got firmware\n", name);
+	}
+
+	goto ok;
+
+err:
+	ret = -EINVAL;
+ok:
+	if (!check) {
+		snd_soc_component_write(component, 0x900, 0x0);
+		snd_soc_component_write(component, 0x102, 0x0);
+	}
+
+	return ret;
+}
+
+static void wm8958_dsp_start_mbc(struct snd_soc_component *component, int path)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	int i;
+
+	/* If the DSP is already running then noop */
+	if (snd_soc_component_read32(component, WM8958_DSP2_PROGRAM) & WM8958_DSP2_ENA)
+		return;
+
+	/* If we have MBC firmware download it */
+	if (wm8994->mbc)
+		wm8958_dsp2_fw(component, "MBC", wm8994->mbc, false);
+
+	snd_soc_component_update_bits(component, WM8958_DSP2_PROGRAM,
+			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+	/* If we've got user supplied MBC settings use them */
+	if (control->pdata.num_mbc_cfgs) {
+		struct wm8958_mbc_cfg *cfg
+			= &control->pdata.mbc_cfgs[wm8994->mbc_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
+			snd_soc_component_write(component, i + WM8958_MBC_BAND_1_K_1,
+				      cfg->coeff_regs[i]);
+
+		for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
+			snd_soc_component_write(component,
+				      i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
+				      cfg->cutoff_regs[i]);
+	}
+
+	/* Run the DSP */
+	snd_soc_component_write(component, WM8958_DSP2_EXECCONTROL,
+		      WM8958_DSP2_RUNR);
+
+	/* And we're off! */
+	snd_soc_component_update_bits(component, WM8958_DSP2_CONFIG,
+			    WM8958_MBC_ENA |
+			    WM8958_MBC_SEL_MASK,
+			    path << WM8958_MBC_SEL_SHIFT |
+			    WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_start_vss(struct snd_soc_component *component, int path)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	int i, ena;
+
+	if (wm8994->mbc_vss)
+		wm8958_dsp2_fw(component, "MBC+VSS", wm8994->mbc_vss, false);
+
+	snd_soc_component_update_bits(component, WM8958_DSP2_PROGRAM,
+			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+	/* If we've got user supplied settings use them */
+	if (control->pdata.num_mbc_cfgs) {
+		struct wm8958_mbc_cfg *cfg
+			= &control->pdata.mbc_cfgs[wm8994->mbc_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++)
+			snd_soc_component_write(component, i + 0x2800,
+				      cfg->combined_regs[i]);
+	}
+
+	if (control->pdata.num_vss_cfgs) {
+		struct wm8958_vss_cfg *cfg
+			= &control->pdata.vss_cfgs[wm8994->vss_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+			snd_soc_component_write(component, i + 0x2600, cfg->regs[i]);
+	}
+
+	if (control->pdata.num_vss_hpf_cfgs) {
+		struct wm8958_vss_hpf_cfg *cfg
+			= &control->pdata.vss_hpf_cfgs[wm8994->vss_hpf_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+			snd_soc_component_write(component, i + 0x2400, cfg->regs[i]);
+	}
+
+	/* Run the DSP */
+	snd_soc_component_write(component, WM8958_DSP2_EXECCONTROL,
+		      WM8958_DSP2_RUNR);
+
+	/* Enable the algorithms we've selected */
+	ena = 0;
+	if (wm8994->mbc_ena[path])
+		ena |= 0x8;
+	if (wm8994->hpf2_ena[path])
+		ena |= 0x4;
+	if (wm8994->hpf1_ena[path])
+		ena |= 0x2;
+	if (wm8994->vss_ena[path])
+		ena |= 0x1;
+
+	snd_soc_component_write(component, 0x2201, ena);
+
+	/* Switch the DSP into the data path */
+	snd_soc_component_update_bits(component, WM8958_DSP2_CONFIG,
+			    WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
+			    path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_start_enh_eq(struct snd_soc_component *component, int path)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	int i;
+
+	wm8958_dsp2_fw(component, "ENH_EQ", wm8994->enh_eq, false);
+
+	snd_soc_component_update_bits(component, WM8958_DSP2_PROGRAM,
+			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+	/* If we've got user supplied settings use them */
+	if (control->pdata.num_enh_eq_cfgs) {
+		struct wm8958_enh_eq_cfg *cfg
+			= &control->pdata.enh_eq_cfgs[wm8994->enh_eq_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+			snd_soc_component_write(component, i + 0x2200,
+				      cfg->regs[i]);
+	}
+
+	/* Run the DSP */
+	snd_soc_component_write(component, WM8958_DSP2_EXECCONTROL,
+		      WM8958_DSP2_RUNR);
+
+	/* Switch the DSP into the data path */
+	snd_soc_component_update_bits(component, WM8958_DSP2_CONFIG,
+			    WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
+			    path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_apply(struct snd_soc_component *component, int path, int start)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	int pwr_reg = snd_soc_component_read32(component, WM8994_POWER_MANAGEMENT_5);
+	int ena, reg, aif;
+
+	switch (path) {
+	case 0:
+		pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA);
+		aif = 0;
+		break;
+	case 1:
+		pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
+		aif = 0;
+		break;
+	case 2:
+		pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA);
+		aif = 1;
+		break;
+	default:
+		WARN(1, "Invalid path %d\n", path);
+		return;
+	}
+
+	/* Do we have both an active AIF and an active algorithm? */
+	ena = wm8994->mbc_ena[path] || wm8994->vss_ena[path] ||
+		wm8994->hpf1_ena[path] || wm8994->hpf2_ena[path] ||
+		wm8994->enh_eq_ena[path];
+	if (!pwr_reg)
+		ena = 0;
+
+	reg = snd_soc_component_read32(component, WM8958_DSP2_PROGRAM);
+
+	dev_dbg(component->dev, "DSP path %d %d startup: %d, power: %x, DSP: %x\n",
+		path, wm8994->dsp_active, start, pwr_reg, reg);
+
+	if (start && ena) {
+		/* If the DSP is already running then noop */
+		if (reg & WM8958_DSP2_ENA)
+			return;
+
+		/* If either AIFnCLK is not yet enabled postpone */
+		if (!(snd_soc_component_read32(component, WM8994_AIF1_CLOCKING_1)
+		      & WM8994_AIF1CLK_ENA_MASK) &&
+		    !(snd_soc_component_read32(component, WM8994_AIF2_CLOCKING_1)
+		      & WM8994_AIF2CLK_ENA_MASK))
+			return;
+
+		/* Switch the clock over to the appropriate AIF */
+		snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
+				    WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
+				    aif << WM8958_DSP2CLK_SRC_SHIFT |
+				    WM8958_DSP2CLK_ENA);
+
+		if (wm8994->enh_eq_ena[path])
+			wm8958_dsp_start_enh_eq(component, path);
+		else if (wm8994->vss_ena[path] || wm8994->hpf1_ena[path] ||
+		    wm8994->hpf2_ena[path])
+			wm8958_dsp_start_vss(component, path);
+		else if (wm8994->mbc_ena[path])
+			wm8958_dsp_start_mbc(component, path);
+
+		wm8994->dsp_active = path;
+
+		dev_dbg(component->dev, "DSP running in path %d\n", path);
+	}
+
+	if (!start && wm8994->dsp_active == path) {
+		/* If the DSP is already stopped then noop */
+		if (!(reg & WM8958_DSP2_ENA))
+			return;
+
+		snd_soc_component_update_bits(component, WM8958_DSP2_CONFIG,
+				    WM8958_MBC_ENA, 0);	
+		snd_soc_component_write(component, WM8958_DSP2_EXECCONTROL,
+			      WM8958_DSP2_STOP);
+		snd_soc_component_update_bits(component, WM8958_DSP2_PROGRAM,
+				    WM8958_DSP2_ENA, 0);
+		snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
+				    WM8958_DSP2CLK_ENA, 0);
+
+		wm8994->dsp_active = -1;
+
+		dev_dbg(component->dev, "DSP stopped\n");
+	}
+}
+
+int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
+		  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	int i;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+	case SND_SOC_DAPM_PRE_PMU:
+		for (i = 0; i < 3; i++)
+			wm8958_dsp_apply(component, i, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+	case SND_SOC_DAPM_PRE_PMD:
+		for (i = 0; i < 3; i++)
+			wm8958_dsp_apply(component, i, 0);
+		break;
+	}
+
+	return 0;
+}
+
+/* Check if DSP2 is in use on another AIF */
+static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) {
+		if (i == aif)
+			continue;
+		if (wm8994->mbc_ena[i] || wm8994->vss_ena[i] ||
+		    wm8994->hpf1_ena[i] || wm8994->hpf2_ena[i])
+			return 1;
+	}
+
+	return 0;
+}
+
+static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	int value = ucontrol->value.enumerated.item[0];
+	int reg;
+
+	/* Don't allow on the fly reconfiguration */
+	reg = snd_soc_component_read32(component, WM8994_CLOCKING_1);
+	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+		return -EBUSY;
+
+	if (value >= control->pdata.num_mbc_cfgs)
+		return -EINVAL;
+
+	wm8994->mbc_cfg = value;
+
+	return 0;
+}
+
+static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
+
+	return 0;
+}
+
+static int wm8958_mbc_info(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int mbc = kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
+
+	return 0;
+}
+
+static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int mbc = kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0])
+		return 0;
+
+	if (ucontrol->value.integer.value[0] > 1)
+		return -EINVAL;
+
+	if (wm8958_dsp2_busy(wm8994, mbc)) {
+		dev_dbg(component->dev, "DSP2 active on %d already\n", mbc);
+		return -EBUSY;
+	}
+
+	if (wm8994->enh_eq_ena[mbc])
+		return -EBUSY;
+
+	wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
+
+	wm8958_dsp_apply(component, mbc, wm8994->mbc_ena[mbc]);
+
+	return 0;
+}
+
+#define WM8958_MBC_SWITCH(xname, xval) {\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.info = wm8958_mbc_info, \
+	.get = wm8958_mbc_get, .put = wm8958_mbc_put, \
+	.private_value = xval }
+
+static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	int value = ucontrol->value.enumerated.item[0];
+	int reg;
+
+	/* Don't allow on the fly reconfiguration */
+	reg = snd_soc_component_read32(component, WM8994_CLOCKING_1);
+	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+		return -EBUSY;
+
+	if (value >= control->pdata.num_vss_cfgs)
+		return -EINVAL;
+
+	wm8994->vss_cfg = value;
+
+	return 0;
+}
+
+static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.enumerated.item[0] = wm8994->vss_cfg;
+
+	return 0;
+}
+
+static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	int value = ucontrol->value.enumerated.item[0];
+	int reg;
+
+	/* Don't allow on the fly reconfiguration */
+	reg = snd_soc_component_read32(component, WM8994_CLOCKING_1);
+	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+		return -EBUSY;
+
+	if (value >= control->pdata.num_vss_hpf_cfgs)
+		return -EINVAL;
+
+	wm8994->vss_hpf_cfg = value;
+
+	return 0;
+}
+
+static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg;
+
+	return 0;
+}
+
+static int wm8958_vss_info(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int wm8958_vss_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int vss = kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wm8994->vss_ena[vss];
+
+	return 0;
+}
+
+static int wm8958_vss_put(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int vss = kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0])
+		return 0;
+
+	if (ucontrol->value.integer.value[0] > 1)
+		return -EINVAL;
+
+	if (!wm8994->mbc_vss)
+		return -ENODEV;
+
+	if (wm8958_dsp2_busy(wm8994, vss)) {
+		dev_dbg(component->dev, "DSP2 active on %d already\n", vss);
+		return -EBUSY;
+	}
+
+	if (wm8994->enh_eq_ena[vss])
+		return -EBUSY;
+
+	wm8994->vss_ena[vss] = ucontrol->value.integer.value[0];
+
+	wm8958_dsp_apply(component, vss, wm8994->vss_ena[vss]);
+
+	return 0;
+}
+
+
+#define WM8958_VSS_SWITCH(xname, xval) {\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.info = wm8958_vss_info, \
+	.get = wm8958_vss_get, .put = wm8958_vss_put, \
+	.private_value = xval }
+
+static int wm8958_hpf_info(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int wm8958_hpf_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int hpf = kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	if (hpf < 3)
+		ucontrol->value.integer.value[0] = wm8994->hpf1_ena[hpf % 3];
+	else
+		ucontrol->value.integer.value[0] = wm8994->hpf2_ena[hpf % 3];
+
+	return 0;
+}
+
+static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int hpf = kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	if (hpf < 3) {
+		if (wm8994->hpf1_ena[hpf % 3] ==
+		    ucontrol->value.integer.value[0])
+			return 0;
+	} else {
+		if (wm8994->hpf2_ena[hpf % 3] ==
+		    ucontrol->value.integer.value[0])
+			return 0;
+	}
+
+	if (ucontrol->value.integer.value[0] > 1)
+		return -EINVAL;
+
+	if (!wm8994->mbc_vss)
+		return -ENODEV;
+
+	if (wm8958_dsp2_busy(wm8994, hpf % 3)) {
+		dev_dbg(component->dev, "DSP2 active on %d already\n", hpf);
+		return -EBUSY;
+	}
+
+	if (wm8994->enh_eq_ena[hpf % 3])
+		return -EBUSY;
+
+	if (hpf < 3)
+		wm8994->hpf1_ena[hpf % 3] = ucontrol->value.integer.value[0];
+	else
+		wm8994->hpf2_ena[hpf % 3] = ucontrol->value.integer.value[0];
+
+	wm8958_dsp_apply(component, hpf % 3, ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+#define WM8958_HPF_SWITCH(xname, xval) {\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.info = wm8958_hpf_info, \
+	.get = wm8958_hpf_get, .put = wm8958_hpf_put, \
+	.private_value = xval }
+
+static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	int value = ucontrol->value.enumerated.item[0];
+	int reg;
+
+	/* Don't allow on the fly reconfiguration */
+	reg = snd_soc_component_read32(component, WM8994_CLOCKING_1);
+	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+		return -EBUSY;
+
+	if (value >= control->pdata.num_enh_eq_cfgs)
+		return -EINVAL;
+
+	wm8994->enh_eq_cfg = value;
+
+	return 0;
+}
+
+static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg;
+
+	return 0;
+}
+
+static int wm8958_enh_eq_info(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int eq = kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq];
+
+	return 0;
+}
+
+static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int eq = kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0])
+		return 0;
+
+	if (ucontrol->value.integer.value[0] > 1)
+		return -EINVAL;
+
+	if (!wm8994->enh_eq)
+		return -ENODEV;
+
+	if (wm8958_dsp2_busy(wm8994, eq)) {
+		dev_dbg(component->dev, "DSP2 active on %d already\n", eq);
+		return -EBUSY;
+	}
+
+	if (wm8994->mbc_ena[eq] || wm8994->vss_ena[eq] ||
+	    wm8994->hpf1_ena[eq] || wm8994->hpf2_ena[eq])
+		return -EBUSY;
+
+	wm8994->enh_eq_ena[eq] = ucontrol->value.integer.value[0];
+
+	wm8958_dsp_apply(component, eq, ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+#define WM8958_ENH_EQ_SWITCH(xname, xval) {\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.info = wm8958_enh_eq_info, \
+	.get = wm8958_enh_eq_get, .put = wm8958_enh_eq_put, \
+	.private_value = xval }
+
+static const struct snd_kcontrol_new wm8958_mbc_snd_controls[] = {
+WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
+WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
+WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
+};
+
+static const struct snd_kcontrol_new wm8958_vss_snd_controls[] = {
+WM8958_VSS_SWITCH("AIF1DAC1 VSS Switch", 0),
+WM8958_VSS_SWITCH("AIF1DAC2 VSS Switch", 1),
+WM8958_VSS_SWITCH("AIF2DAC VSS Switch", 2),
+WM8958_HPF_SWITCH("AIF1DAC1 HPF1 Switch", 0),
+WM8958_HPF_SWITCH("AIF1DAC2 HPF1 Switch", 1),
+WM8958_HPF_SWITCH("AIF2DAC HPF1 Switch", 2),
+WM8958_HPF_SWITCH("AIF1DAC1 HPF2 Switch", 3),
+WM8958_HPF_SWITCH("AIF1DAC2 HPF2 Switch", 4),
+WM8958_HPF_SWITCH("AIF2DAC HPF2 Switch", 5),
+};
+
+static const struct snd_kcontrol_new wm8958_enh_eq_snd_controls[] = {
+WM8958_ENH_EQ_SWITCH("AIF1DAC1 Enhanced EQ Switch", 0),
+WM8958_ENH_EQ_SWITCH("AIF1DAC2 Enhanced EQ Switch", 1),
+WM8958_ENH_EQ_SWITCH("AIF2DAC Enhanced EQ Switch", 2),
+};
+
+static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context)
+{
+	struct snd_soc_component *component = context;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	if (fw && (wm8958_dsp2_fw(component, "ENH_EQ", fw, true) == 0)) {
+		mutex_lock(&wm8994->fw_lock);
+		wm8994->enh_eq = fw;
+		mutex_unlock(&wm8994->fw_lock);
+	}
+}
+
+static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
+{
+	struct snd_soc_component *component = context;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	if (fw && (wm8958_dsp2_fw(component, "MBC+VSS", fw, true) == 0)) {
+		mutex_lock(&wm8994->fw_lock);
+		wm8994->mbc_vss = fw;
+		mutex_unlock(&wm8994->fw_lock);
+	}
+}
+
+static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
+{
+	struct snd_soc_component *component = context;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	if (fw && (wm8958_dsp2_fw(component, "MBC", fw, true) == 0)) {
+		mutex_lock(&wm8994->fw_lock);
+		wm8994->mbc = fw;
+		mutex_unlock(&wm8994->fw_lock);
+	}
+}
+
+void wm8958_dsp2_init(struct snd_soc_component *component)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	struct wm8994_pdata *pdata = &control->pdata;
+	int ret, i;
+
+	wm8994->dsp_active = -1;
+
+	snd_soc_add_component_controls(component, wm8958_mbc_snd_controls,
+			     ARRAY_SIZE(wm8958_mbc_snd_controls));
+	snd_soc_add_component_controls(component, wm8958_vss_snd_controls,
+			     ARRAY_SIZE(wm8958_vss_snd_controls));
+	snd_soc_add_component_controls(component, wm8958_enh_eq_snd_controls,
+			     ARRAY_SIZE(wm8958_enh_eq_snd_controls));
+
+
+	/* We don't *require* firmware and don't want to delay boot */
+	request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+				"wm8958_mbc.wfw", component->dev, GFP_KERNEL,
+				component, wm8958_mbc_loaded);
+	request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+				"wm8958_mbc_vss.wfw", component->dev, GFP_KERNEL,
+				component, wm8958_mbc_vss_loaded);
+	request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+				"wm8958_enh_eq.wfw", component->dev, GFP_KERNEL,
+				component, wm8958_enh_eq_loaded);
+
+	if (pdata->num_mbc_cfgs) {
+		struct snd_kcontrol_new control[] = {
+			SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
+				     wm8958_get_mbc_enum, wm8958_put_mbc_enum),
+		};
+
+		/* We need an array of texts for the enum API */
+		wm8994->mbc_texts = kmalloc_array(pdata->num_mbc_cfgs,
+						  sizeof(char *),
+						  GFP_KERNEL);
+		if (!wm8994->mbc_texts)
+			return;
+
+		for (i = 0; i < pdata->num_mbc_cfgs; i++)
+			wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
+
+		wm8994->mbc_enum.items = pdata->num_mbc_cfgs;
+		wm8994->mbc_enum.texts = wm8994->mbc_texts;
+
+		ret = snd_soc_add_component_controls(wm8994->hubs.component,
+						 control, 1);
+		if (ret != 0)
+			dev_err(wm8994->hubs.component->dev,
+				"Failed to add MBC mode controls: %d\n", ret);
+	}
+
+	if (pdata->num_vss_cfgs) {
+		struct snd_kcontrol_new control[] = {
+			SOC_ENUM_EXT("VSS Mode", wm8994->vss_enum,
+				     wm8958_get_vss_enum, wm8958_put_vss_enum),
+		};
+
+		/* We need an array of texts for the enum API */
+		wm8994->vss_texts = kmalloc_array(pdata->num_vss_cfgs,
+						  sizeof(char *),
+						  GFP_KERNEL);
+		if (!wm8994->vss_texts)
+			return;
+
+		for (i = 0; i < pdata->num_vss_cfgs; i++)
+			wm8994->vss_texts[i] = pdata->vss_cfgs[i].name;
+
+		wm8994->vss_enum.items = pdata->num_vss_cfgs;
+		wm8994->vss_enum.texts = wm8994->vss_texts;
+
+		ret = snd_soc_add_component_controls(wm8994->hubs.component,
+						 control, 1);
+		if (ret != 0)
+			dev_err(wm8994->hubs.component->dev,
+				"Failed to add VSS mode controls: %d\n", ret);
+	}
+
+	if (pdata->num_vss_hpf_cfgs) {
+		struct snd_kcontrol_new control[] = {
+			SOC_ENUM_EXT("VSS HPF Mode", wm8994->vss_hpf_enum,
+				     wm8958_get_vss_hpf_enum,
+				     wm8958_put_vss_hpf_enum),
+		};
+
+		/* We need an array of texts for the enum API */
+		wm8994->vss_hpf_texts = kmalloc_array(pdata->num_vss_hpf_cfgs,
+						      sizeof(char *),
+						      GFP_KERNEL);
+		if (!wm8994->vss_hpf_texts)
+			return;
+
+		for (i = 0; i < pdata->num_vss_hpf_cfgs; i++)
+			wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name;
+
+		wm8994->vss_hpf_enum.items = pdata->num_vss_hpf_cfgs;
+		wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
+
+		ret = snd_soc_add_component_controls(wm8994->hubs.component,
+						 control, 1);
+		if (ret != 0)
+			dev_err(wm8994->hubs.component->dev,
+				"Failed to add VSS HPFmode controls: %d\n",
+				ret);
+	}
+
+	if (pdata->num_enh_eq_cfgs) {
+		struct snd_kcontrol_new control[] = {
+			SOC_ENUM_EXT("Enhanced EQ Mode", wm8994->enh_eq_enum,
+				     wm8958_get_enh_eq_enum,
+				     wm8958_put_enh_eq_enum),
+		};
+
+		/* We need an array of texts for the enum API */
+		wm8994->enh_eq_texts = kmalloc_array(pdata->num_enh_eq_cfgs,
+						     sizeof(char *),
+						     GFP_KERNEL);
+		if (!wm8994->enh_eq_texts)
+			return;
+
+		for (i = 0; i < pdata->num_enh_eq_cfgs; i++)
+			wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name;
+
+		wm8994->enh_eq_enum.items = pdata->num_enh_eq_cfgs;
+		wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
+
+		ret = snd_soc_add_component_controls(wm8994->hubs.component,
+						 control, 1);
+		if (ret != 0)
+			dev_err(wm8994->hubs.component->dev,
+				"Failed to add enhanced EQ controls: %d\n",
+				ret);
+	}
+}
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
new file mode 100644
index 0000000..8dc1f3d
--- /dev/null
+++ b/sound/soc/codecs/wm8960.c
@@ -0,0 +1,1492 @@
+/*
+ * wm8960.c  --  WM8960 ALSA SoC Audio driver
+ *
+ * Copyright 2007-11 Wolfson Microelectronics, plc
+ *
+ * Author: Liam Girdwood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/wm8960.h>
+
+#include "wm8960.h"
+
+/* R25 - Power 1 */
+#define WM8960_VMID_MASK 0x180
+#define WM8960_VREF      0x40
+
+/* R26 - Power 2 */
+#define WM8960_PWR2_LOUT1	0x40
+#define WM8960_PWR2_ROUT1	0x20
+#define WM8960_PWR2_OUT3	0x02
+
+/* R28 - Anti-pop 1 */
+#define WM8960_POBCTRL   0x80
+#define WM8960_BUFDCOPEN 0x10
+#define WM8960_BUFIOEN   0x08
+#define WM8960_SOFT_ST   0x04
+#define WM8960_HPSTBY    0x01
+
+/* R29 - Anti-pop 2 */
+#define WM8960_DISOP     0x40
+#define WM8960_DRES_MASK 0x30
+
+static bool is_pll_freq_available(unsigned int source, unsigned int target);
+static int wm8960_set_pll(struct snd_soc_component *component,
+		unsigned int freq_in, unsigned int freq_out);
+/*
+ * wm8960 register cache
+ * We can't read the WM8960 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ */
+static const struct reg_default wm8960_reg_defaults[] = {
+	{  0x0, 0x00a7 },
+	{  0x1, 0x00a7 },
+	{  0x2, 0x0000 },
+	{  0x3, 0x0000 },
+	{  0x4, 0x0000 },
+	{  0x5, 0x0008 },
+	{  0x6, 0x0000 },
+	{  0x7, 0x000a },
+	{  0x8, 0x01c0 },
+	{  0x9, 0x0000 },
+	{  0xa, 0x00ff },
+	{  0xb, 0x00ff },
+
+	{ 0x10, 0x0000 },
+	{ 0x11, 0x007b },
+	{ 0x12, 0x0100 },
+	{ 0x13, 0x0032 },
+	{ 0x14, 0x0000 },
+	{ 0x15, 0x00c3 },
+	{ 0x16, 0x00c3 },
+	{ 0x17, 0x01c0 },
+	{ 0x18, 0x0000 },
+	{ 0x19, 0x0000 },
+	{ 0x1a, 0x0000 },
+	{ 0x1b, 0x0000 },
+	{ 0x1c, 0x0000 },
+	{ 0x1d, 0x0000 },
+
+	{ 0x20, 0x0100 },
+	{ 0x21, 0x0100 },
+	{ 0x22, 0x0050 },
+
+	{ 0x25, 0x0050 },
+	{ 0x26, 0x0000 },
+	{ 0x27, 0x0000 },
+	{ 0x28, 0x0000 },
+	{ 0x29, 0x0000 },
+	{ 0x2a, 0x0040 },
+	{ 0x2b, 0x0000 },
+	{ 0x2c, 0x0000 },
+	{ 0x2d, 0x0050 },
+	{ 0x2e, 0x0050 },
+	{ 0x2f, 0x0000 },
+	{ 0x30, 0x0002 },
+	{ 0x31, 0x0037 },
+
+	{ 0x33, 0x0080 },
+	{ 0x34, 0x0008 },
+	{ 0x35, 0x0031 },
+	{ 0x36, 0x0026 },
+	{ 0x37, 0x00e9 },
+};
+
+static bool wm8960_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8960_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+struct wm8960_priv {
+	struct clk *mclk;
+	struct regmap *regmap;
+	int (*set_bias_level)(struct snd_soc_component *,
+			      enum snd_soc_bias_level level);
+	struct snd_soc_dapm_widget *lout1;
+	struct snd_soc_dapm_widget *rout1;
+	struct snd_soc_dapm_widget *out3;
+	bool deemph;
+	int lrclk;
+	int bclk;
+	int sysclk;
+	int clk_id;
+	int freq_in;
+	bool is_stream_in_use[2];
+	struct wm8960_data pdata;
+};
+
+#define wm8960_reset(c)	regmap_write(c, WM8960_RESET, 0)
+
+/* enumerated controls */
+static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted",
+	"Right Inverted", "Stereo Inversion"};
+static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"};
+static const char *wm8960_3d_lower_cutoff[] = {"Low", "High"};
+static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"};
+static const char *wm8960_alcmode[] = {"ALC", "Limiter"};
+static const char *wm8960_adc_data_output_sel[] = {
+	"Left Data = Left ADC;  Right Data = Right ADC",
+	"Left Data = Left ADC;  Right Data = Left ADC",
+	"Left Data = Right ADC; Right Data = Right ADC",
+	"Left Data = Right ADC; Right Data = Left ADC",
+};
+static const char *wm8960_dmonomix[] = {"Stereo", "Mono"};
+
+static const struct soc_enum wm8960_enum[] = {
+	SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity),
+	SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity),
+	SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff),
+	SOC_ENUM_SINGLE(WM8960_3D, 5, 2, wm8960_3d_lower_cutoff),
+	SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc),
+	SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode),
+	SOC_ENUM_SINGLE(WM8960_ADDCTL1, 2, 4, wm8960_adc_data_output_sel),
+	SOC_ENUM_SINGLE(WM8960_ADDCTL1, 4, 2, wm8960_dmonomix),
+};
+
+static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
+
+static int wm8960_set_deemph(struct snd_soc_component *component)
+{
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+	int val, i, best;
+
+	/* If we're using deemphasis select the nearest available sample
+	 * rate.
+	 */
+	if (wm8960->deemph) {
+		best = 1;
+		for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
+			if (abs(deemph_settings[i] - wm8960->lrclk) <
+			    abs(deemph_settings[best] - wm8960->lrclk))
+				best = i;
+		}
+
+		val = best << 1;
+	} else {
+		val = 0;
+	}
+
+	dev_dbg(component->dev, "Set deemphasis %d\n", val);
+
+	return snd_soc_component_update_bits(component, WM8960_DACCTL1,
+				   0x6, val);
+}
+
+static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = wm8960->deemph;
+	return 0;
+}
+
+static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+	unsigned int deemph = ucontrol->value.integer.value[0];
+
+	if (deemph > 1)
+		return -EINVAL;
+
+	wm8960->deemph = deemph;
+
+	return wm8960_set_deemph(component);
+}
+
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(lineinboost_tlv, -1500, 300, 1);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(micboost_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(0, 1300, 0),
+	2, 3, TLV_DB_SCALE_ITEM(2000, 900, 0),
+);
+
+static const struct snd_kcontrol_new wm8960_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL,
+		 0, 63, 0, inpga_tlv),
+SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL,
+	6, 1, 0),
+SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL,
+	7, 1, 1),
+
+SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume",
+	       WM8960_INBMIX1, 4, 7, 0, lineinboost_tlv),
+SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume",
+	       WM8960_INBMIX1, 1, 7, 0, lineinboost_tlv),
+SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume",
+	       WM8960_INBMIX2, 4, 7, 0, lineinboost_tlv),
+SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume",
+	       WM8960_INBMIX2, 1, 7, 0, lineinboost_tlv),
+SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT1 Volume",
+		WM8960_RINPATH, 4, 3, 0, micboost_tlv),
+SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT1 Volume",
+		WM8960_LINPATH, 4, 3, 0, micboost_tlv),
+
+SOC_DOUBLE_R_TLV("Playback Volume", WM8960_LDAC, WM8960_RDAC,
+		 0, 255, 0, dac_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8960_LOUT1, WM8960_ROUT1,
+		 0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8960_LOUT1, WM8960_ROUT1,
+	7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8960_LOUT2, WM8960_ROUT2,
+		 0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8960_LOUT2, WM8960_ROUT2,
+	7, 1, 0),
+SOC_SINGLE("Speaker DC Volume", WM8960_CLASSD3, 3, 5, 0),
+SOC_SINGLE("Speaker AC Volume", WM8960_CLASSD3, 0, 5, 0),
+
+SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0),
+SOC_ENUM("ADC Polarity", wm8960_enum[0]),
+SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0),
+
+SOC_ENUM("DAC Polarity", wm8960_enum[1]),
+SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
+		    wm8960_get_deemph, wm8960_put_deemph),
+
+SOC_ENUM("3D Filter Upper Cut-Off", wm8960_enum[2]),
+SOC_ENUM("3D Filter Lower Cut-Off", wm8960_enum[3]),
+SOC_SINGLE("3D Volume", WM8960_3D, 1, 15, 0),
+SOC_SINGLE("3D Switch", WM8960_3D, 0, 1, 0),
+
+SOC_ENUM("ALC Function", wm8960_enum[4]),
+SOC_SINGLE("ALC Max Gain", WM8960_ALC1, 4, 7, 0),
+SOC_SINGLE("ALC Target", WM8960_ALC1, 0, 15, 1),
+SOC_SINGLE("ALC Min Gain", WM8960_ALC2, 4, 7, 0),
+SOC_SINGLE("ALC Hold Time", WM8960_ALC2, 0, 15, 0),
+SOC_ENUM("ALC Mode", wm8960_enum[5]),
+SOC_SINGLE("ALC Decay", WM8960_ALC3, 4, 15, 0),
+SOC_SINGLE("ALC Attack", WM8960_ALC3, 0, 15, 0),
+
+SOC_SINGLE("Noise Gate Threshold", WM8960_NOISEG, 3, 31, 0),
+SOC_SINGLE("Noise Gate Switch", WM8960_NOISEG, 0, 1, 0),
+
+SOC_DOUBLE_R_TLV("ADC PCM Capture Volume", WM8960_LADC, WM8960_RADC,
+	0, 255, 0, adc_tlv),
+
+SOC_SINGLE_TLV("Left Output Mixer Boost Bypass Volume",
+	       WM8960_BYPASS1, 4, 7, 1, bypass_tlv),
+SOC_SINGLE_TLV("Left Output Mixer LINPUT3 Volume",
+	       WM8960_LOUTMIX, 4, 7, 1, bypass_tlv),
+SOC_SINGLE_TLV("Right Output Mixer Boost Bypass Volume",
+	       WM8960_BYPASS2, 4, 7, 1, bypass_tlv),
+SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume",
+	       WM8960_ROUTMIX, 4, 7, 1, bypass_tlv),
+
+SOC_ENUM("ADC Data Output Select", wm8960_enum[6]),
+SOC_ENUM("DAC Mono Mix", wm8960_enum[7]),
+};
+
+static const struct snd_kcontrol_new wm8960_lin_boost[] = {
+SOC_DAPM_SINGLE("LINPUT2 Switch", WM8960_LINPATH, 6, 1, 0),
+SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LINPATH, 7, 1, 0),
+SOC_DAPM_SINGLE("LINPUT1 Switch", WM8960_LINPATH, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_lin[] = {
+SOC_DAPM_SINGLE("Boost Switch", WM8960_LINPATH, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_rin_boost[] = {
+SOC_DAPM_SINGLE("RINPUT2 Switch", WM8960_RINPATH, 6, 1, 0),
+SOC_DAPM_SINGLE("RINPUT3 Switch", WM8960_RINPATH, 7, 1, 0),
+SOC_DAPM_SINGLE("RINPUT1 Switch", WM8960_RINPATH, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_rin[] = {
+SOC_DAPM_SINGLE("Boost Switch", WM8960_RINPATH, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_loutput_mixer[] = {
+SOC_DAPM_SINGLE("PCM Playback Switch", WM8960_LOUTMIX, 8, 1, 0),
+SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LOUTMIX, 7, 1, 0),
+SOC_DAPM_SINGLE("Boost Bypass Switch", WM8960_BYPASS1, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_routput_mixer[] = {
+SOC_DAPM_SINGLE("PCM Playback Switch", WM8960_ROUTMIX, 8, 1, 0),
+SOC_DAPM_SINGLE("RINPUT3 Switch", WM8960_ROUTMIX, 7, 1, 0),
+SOC_DAPM_SINGLE("Boost Bypass Switch", WM8960_BYPASS2, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8960_mono_out[] = {
+SOC_DAPM_SINGLE("Left Switch", WM8960_MONOMIX1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Switch", WM8960_MONOMIX2, 7, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8960_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("LINPUT1"),
+SND_SOC_DAPM_INPUT("RINPUT1"),
+SND_SOC_DAPM_INPUT("LINPUT2"),
+SND_SOC_DAPM_INPUT("RINPUT2"),
+SND_SOC_DAPM_INPUT("LINPUT3"),
+SND_SOC_DAPM_INPUT("RINPUT3"),
+
+SND_SOC_DAPM_SUPPLY("MICB", WM8960_POWER1, 1, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8960_POWER1, 5, 0,
+		   wm8960_lin_boost, ARRAY_SIZE(wm8960_lin_boost)),
+SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8960_POWER1, 4, 0,
+		   wm8960_rin_boost, ARRAY_SIZE(wm8960_rin_boost)),
+
+SND_SOC_DAPM_MIXER("Left Input Mixer", WM8960_POWER3, 5, 0,
+		   wm8960_lin, ARRAY_SIZE(wm8960_lin)),
+SND_SOC_DAPM_MIXER("Right Input Mixer", WM8960_POWER3, 4, 0,
+		   wm8960_rin, ARRAY_SIZE(wm8960_rin)),
+
+SND_SOC_DAPM_ADC("Left ADC", "Capture", WM8960_POWER1, 3, 0),
+SND_SOC_DAPM_ADC("Right ADC", "Capture", WM8960_POWER1, 2, 0),
+
+SND_SOC_DAPM_DAC("Left DAC", "Playback", WM8960_POWER2, 8, 0),
+SND_SOC_DAPM_DAC("Right DAC", "Playback", WM8960_POWER2, 7, 0),
+
+SND_SOC_DAPM_MIXER("Left Output Mixer", WM8960_POWER3, 3, 0,
+	&wm8960_loutput_mixer[0],
+	ARRAY_SIZE(wm8960_loutput_mixer)),
+SND_SOC_DAPM_MIXER("Right Output Mixer", WM8960_POWER3, 2, 0,
+	&wm8960_routput_mixer[0],
+	ARRAY_SIZE(wm8960_routput_mixer)),
+
+SND_SOC_DAPM_PGA("LOUT1 PGA", WM8960_POWER2, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ROUT1 PGA", WM8960_POWER2, 5, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Left Speaker PGA", WM8960_POWER2, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Speaker PGA", WM8960_POWER2, 3, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Right Speaker Output", WM8960_CLASSD1, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Left Speaker Output", WM8960_CLASSD1, 6, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("SPK_LP"),
+SND_SOC_DAPM_OUTPUT("SPK_LN"),
+SND_SOC_DAPM_OUTPUT("HP_L"),
+SND_SOC_DAPM_OUTPUT("HP_R"),
+SND_SOC_DAPM_OUTPUT("SPK_RP"),
+SND_SOC_DAPM_OUTPUT("SPK_RN"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+};
+
+static const struct snd_soc_dapm_widget wm8960_dapm_widgets_out3[] = {
+SND_SOC_DAPM_MIXER("Mono Output Mixer", WM8960_POWER2, 1, 0,
+	&wm8960_mono_out[0],
+	ARRAY_SIZE(wm8960_mono_out)),
+};
+
+/* Represent OUT3 as a PGA so that it gets turned on with LOUT1/ROUT1 */
+static const struct snd_soc_dapm_widget wm8960_dapm_widgets_capless[] = {
+SND_SOC_DAPM_PGA("OUT3 VMID", WM8960_POWER2, 1, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route audio_paths[] = {
+	{ "Left Boost Mixer", "LINPUT1 Switch", "LINPUT1" },
+	{ "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" },
+	{ "Left Boost Mixer", "LINPUT3 Switch", "LINPUT3" },
+
+	{ "Left Input Mixer", "Boost Switch", "Left Boost Mixer" },
+	{ "Left Input Mixer", "Boost Switch", "LINPUT1" },  /* Really Boost Switch */
+	{ "Left Input Mixer", NULL, "LINPUT2" },
+	{ "Left Input Mixer", NULL, "LINPUT3" },
+
+	{ "Right Boost Mixer", "RINPUT1 Switch", "RINPUT1" },
+	{ "Right Boost Mixer", "RINPUT2 Switch", "RINPUT2" },
+	{ "Right Boost Mixer", "RINPUT3 Switch", "RINPUT3" },
+
+	{ "Right Input Mixer", "Boost Switch", "Right Boost Mixer" },
+	{ "Right Input Mixer", "Boost Switch", "RINPUT1" },  /* Really Boost Switch */
+	{ "Right Input Mixer", NULL, "RINPUT2" },
+	{ "Right Input Mixer", NULL, "RINPUT3" },
+
+	{ "Left ADC", NULL, "Left Input Mixer" },
+	{ "Right ADC", NULL, "Right Input Mixer" },
+
+	{ "Left Output Mixer", "LINPUT3 Switch", "LINPUT3" },
+	{ "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer" },
+	{ "Left Output Mixer", "PCM Playback Switch", "Left DAC" },
+
+	{ "Right Output Mixer", "RINPUT3 Switch", "RINPUT3" },
+	{ "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" },
+	{ "Right Output Mixer", "PCM Playback Switch", "Right DAC" },
+
+	{ "LOUT1 PGA", NULL, "Left Output Mixer" },
+	{ "ROUT1 PGA", NULL, "Right Output Mixer" },
+
+	{ "HP_L", NULL, "LOUT1 PGA" },
+	{ "HP_R", NULL, "ROUT1 PGA" },
+
+	{ "Left Speaker PGA", NULL, "Left Output Mixer" },
+	{ "Right Speaker PGA", NULL, "Right Output Mixer" },
+
+	{ "Left Speaker Output", NULL, "Left Speaker PGA" },
+	{ "Right Speaker Output", NULL, "Right Speaker PGA" },
+
+	{ "SPK_LN", NULL, "Left Speaker Output" },
+	{ "SPK_LP", NULL, "Left Speaker Output" },
+	{ "SPK_RN", NULL, "Right Speaker Output" },
+	{ "SPK_RP", NULL, "Right Speaker Output" },
+};
+
+static const struct snd_soc_dapm_route audio_paths_out3[] = {
+	{ "Mono Output Mixer", "Left Switch", "Left Output Mixer" },
+	{ "Mono Output Mixer", "Right Switch", "Right Output Mixer" },
+
+	{ "OUT3", NULL, "Mono Output Mixer", }
+};
+
+static const struct snd_soc_dapm_route audio_paths_capless[] = {
+	{ "HP_L", NULL, "OUT3 VMID" },
+	{ "HP_R", NULL, "OUT3 VMID" },
+
+	{ "OUT3 VMID", NULL, "Left Output Mixer" },
+	{ "OUT3 VMID", NULL, "Right Output Mixer" },
+};
+
+static int wm8960_add_widgets(struct snd_soc_component *component)
+{
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+	struct wm8960_data *pdata = &wm8960->pdata;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct snd_soc_dapm_widget *w;
+
+	snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets,
+				  ARRAY_SIZE(wm8960_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
+
+	/* In capless mode OUT3 is used to provide VMID for the
+	 * headphone outputs, otherwise it is used as a mono mixer.
+	 */
+	if (pdata && pdata->capless) {
+		snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets_capless,
+					  ARRAY_SIZE(wm8960_dapm_widgets_capless));
+
+		snd_soc_dapm_add_routes(dapm, audio_paths_capless,
+					ARRAY_SIZE(audio_paths_capless));
+	} else {
+		snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets_out3,
+					  ARRAY_SIZE(wm8960_dapm_widgets_out3));
+
+		snd_soc_dapm_add_routes(dapm, audio_paths_out3,
+					ARRAY_SIZE(audio_paths_out3));
+	}
+
+	/* We need to power up the headphone output stage out of
+	 * sequence for capless mode.  To save scanning the widget
+	 * list each time to find the desired power state do so now
+	 * and save the result.
+	 */
+	list_for_each_entry(w, &component->card->widgets, list) {
+		if (w->dapm != dapm)
+			continue;
+		if (strcmp(w->name, "LOUT1 PGA") == 0)
+			wm8960->lout1 = w;
+		if (strcmp(w->name, "ROUT1 PGA") == 0)
+			wm8960->rout1 = w;
+		if (strcmp(w->name, "OUT3 VMID") == 0)
+			wm8960->out3 = w;
+	}
+	
+	return 0;
+}
+
+static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface |= 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set iface */
+	snd_soc_component_write(component, WM8960_IFACE1, iface);
+	return 0;
+}
+
+static struct {
+	int rate;
+	unsigned int val;
+} alc_rates[] = {
+	{ 48000, 0 },
+	{ 44100, 0 },
+	{ 32000, 1 },
+	{ 22050, 2 },
+	{ 24000, 2 },
+	{ 16000, 3 },
+	{ 11025, 4 },
+	{ 12000, 4 },
+	{  8000, 5 },
+};
+
+/* -1 for reserved value */
+static const int sysclk_divs[] = { 1, -1, 2, -1 };
+
+/* Multiply 256 for internal 256 div */
+static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 };
+
+/* Multiply 10 to eliminate decimials */
+static const int bclk_divs[] = {
+	10, 15, 20, 30, 40, 55, 60, 80, 110,
+	120, 160, 220, 240, 320, 320, 320
+};
+
+/**
+ * wm8960_configure_sysclk - checks if there is a sysclk frequency available
+ *	The sysclk must be chosen such that:
+ *		- sysclk     = MCLK / sysclk_divs
+ *		- lrclk      = sysclk / dac_divs
+ *		- 10 * bclk  = sysclk / bclk_divs
+ *
+ *	If we cannot find an exact match for (sysclk, lrclk, bclk)
+ *	triplet, we relax the bclk such that bclk is chosen as the
+ *	closest available frequency greater than expected bclk.
+ *
+ * @wm8960_priv: wm8960 codec private data
+ * @mclk: MCLK used to derive sysclk
+ * @sysclk_idx: sysclk_divs index for found sysclk
+ * @dac_idx: dac_divs index for found lrclk
+ * @bclk_idx: bclk_divs index for found bclk
+ *
+ * Returns:
+ *  -1, in case no sysclk frequency available found
+ * >=0, in case we could derive bclk and lrclk from sysclk using
+ *      (@sysclk_idx, @dac_idx, @bclk_idx) dividers
+ */
+static
+int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk,
+			    int *sysclk_idx, int *dac_idx, int *bclk_idx)
+{
+	int sysclk, bclk, lrclk;
+	int i, j, k;
+	int diff, closest = mclk;
+
+	/* marker for no match */
+	*bclk_idx = -1;
+
+	bclk = wm8960->bclk;
+	lrclk = wm8960->lrclk;
+
+	/* check if the sysclk frequency is available. */
+	for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
+		if (sysclk_divs[i] == -1)
+			continue;
+		sysclk = mclk / sysclk_divs[i];
+		for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
+			if (sysclk != dac_divs[j] * lrclk)
+				continue;
+			for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) {
+				diff = sysclk - bclk * bclk_divs[k] / 10;
+				if (diff == 0) {
+					*sysclk_idx = i;
+					*dac_idx = j;
+					*bclk_idx = k;
+					break;
+				}
+				if (diff > 0 && closest > diff) {
+					*sysclk_idx = i;
+					*dac_idx = j;
+					*bclk_idx = k;
+					closest = diff;
+				}
+			}
+			if (k != ARRAY_SIZE(bclk_divs))
+				break;
+		}
+		if (j != ARRAY_SIZE(dac_divs))
+			break;
+	}
+	return *bclk_idx;
+}
+
+/**
+ * wm8960_configure_pll - checks if there is a PLL out frequency available
+ *	The PLL out frequency must be chosen such that:
+ *		- sysclk      = lrclk * dac_divs
+ *		- freq_out    = sysclk * sysclk_divs
+ *		- 10 * sysclk = bclk * bclk_divs
+ *
+ * 	If we cannot find an exact match for (sysclk, lrclk, bclk)
+ * 	triplet, we relax the bclk such that bclk is chosen as the
+ * 	closest available frequency greater than expected bclk.
+ *
+ * @component: component structure
+ * @freq_in: input frequency used to derive freq out via PLL
+ * @sysclk_idx: sysclk_divs index for found sysclk
+ * @dac_idx: dac_divs index for found lrclk
+ * @bclk_idx: bclk_divs index for found bclk
+ *
+ * Returns:
+ * < 0, in case no PLL frequency out available was found
+ * >=0, in case we could derive bclk, lrclk, sysclk from PLL out using
+ *      (@sysclk_idx, @dac_idx, @bclk_idx) dividers
+ */
+static
+int wm8960_configure_pll(struct snd_soc_component *component, int freq_in,
+			 int *sysclk_idx, int *dac_idx, int *bclk_idx)
+{
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+	int sysclk, bclk, lrclk, freq_out;
+	int diff, closest, best_freq_out;
+	int i, j, k;
+
+	bclk = wm8960->bclk;
+	lrclk = wm8960->lrclk;
+	closest = freq_in;
+
+	best_freq_out = -EINVAL;
+	*sysclk_idx = *dac_idx = *bclk_idx = -1;
+
+	for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
+		if (sysclk_divs[i] == -1)
+			continue;
+		for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
+			sysclk = lrclk * dac_divs[j];
+			freq_out = sysclk * sysclk_divs[i];
+
+			for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) {
+				if (!is_pll_freq_available(freq_in, freq_out))
+					continue;
+
+				diff = sysclk - bclk * bclk_divs[k] / 10;
+				if (diff == 0) {
+					*sysclk_idx = i;
+					*dac_idx = j;
+					*bclk_idx = k;
+					return freq_out;
+				}
+				if (diff > 0 && closest > diff) {
+					*sysclk_idx = i;
+					*dac_idx = j;
+					*bclk_idx = k;
+					closest = diff;
+					best_freq_out = freq_out;
+				}
+			}
+		}
+	}
+
+	return best_freq_out;
+}
+static int wm8960_configure_clocking(struct snd_soc_component *component)
+{
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+	int freq_out, freq_in;
+	u16 iface1 = snd_soc_component_read32(component, WM8960_IFACE1);
+	int i, j, k;
+	int ret;
+
+	if (!(iface1 & (1<<6))) {
+		dev_dbg(component->dev,
+			"Codec is slave mode, no need to configure clock\n");
+		return 0;
+	}
+
+	if (wm8960->clk_id != WM8960_SYSCLK_MCLK && !wm8960->freq_in) {
+		dev_err(component->dev, "No MCLK configured\n");
+		return -EINVAL;
+	}
+
+	freq_in = wm8960->freq_in;
+	/*
+	 * If it's sysclk auto mode, check if the MCLK can provide sysclk or
+	 * not. If MCLK can provide sysclk, using MCLK to provide sysclk
+	 * directly. Otherwise, auto select a available pll out frequency
+	 * and set PLL.
+	 */
+	if (wm8960->clk_id == WM8960_SYSCLK_AUTO) {
+		/* disable the PLL and using MCLK to provide sysclk */
+		wm8960_set_pll(component, 0, 0);
+		freq_out = freq_in;
+	} else if (wm8960->sysclk) {
+		freq_out = wm8960->sysclk;
+	} else {
+		dev_err(component->dev, "No SYSCLK configured\n");
+		return -EINVAL;
+	}
+
+	if (wm8960->clk_id != WM8960_SYSCLK_PLL) {
+		ret = wm8960_configure_sysclk(wm8960, freq_out, &i, &j, &k);
+		if (ret >= 0) {
+			goto configure_clock;
+		} else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
+			dev_err(component->dev, "failed to configure clock\n");
+			return -EINVAL;
+		}
+	}
+
+	freq_out = wm8960_configure_pll(component, freq_in, &i, &j, &k);
+	if (freq_out < 0) {
+		dev_err(component->dev, "failed to configure clock via PLL\n");
+		return freq_out;
+	}
+	wm8960_set_pll(component, freq_in, freq_out);
+
+configure_clock:
+	/* configure sysclk clock */
+	snd_soc_component_update_bits(component, WM8960_CLOCK1, 3 << 1, i << 1);
+
+	/* configure frame clock */
+	snd_soc_component_update_bits(component, WM8960_CLOCK1, 0x7 << 3, j << 3);
+	snd_soc_component_update_bits(component, WM8960_CLOCK1, 0x7 << 6, j << 6);
+
+	/* configure bit clock */
+	snd_soc_component_update_bits(component, WM8960_CLOCK2, 0xf, k);
+
+	return 0;
+}
+
+static int wm8960_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+	u16 iface = snd_soc_component_read32(component, WM8960_IFACE1) & 0xfff3;
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	int i;
+
+	wm8960->bclk = snd_soc_params_to_bclk(params);
+	if (params_channels(params) == 1)
+		wm8960->bclk *= 2;
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		iface |= 0x0004;
+		break;
+	case 24:
+		iface |= 0x0008;
+		break;
+	case 32:
+		/* right justify mode does not support 32 word length */
+		if ((iface & 0x3) != 0) {
+			iface |= 0x000c;
+			break;
+		}
+		/* fall through */
+	default:
+		dev_err(component->dev, "unsupported width %d\n",
+			params_width(params));
+		return -EINVAL;
+	}
+
+	wm8960->lrclk = params_rate(params);
+	/* Update filters for the new rate */
+	if (tx) {
+		wm8960_set_deemph(component);
+	} else {
+		for (i = 0; i < ARRAY_SIZE(alc_rates); i++)
+			if (alc_rates[i].rate == params_rate(params))
+				snd_soc_component_update_bits(component,
+						    WM8960_ADDCTL3, 0x7,
+						    alc_rates[i].val);
+	}
+
+	/* set iface */
+	snd_soc_component_write(component, WM8960_IFACE1, iface);
+
+	wm8960->is_stream_in_use[tx] = true;
+
+	if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON &&
+	    !wm8960->is_stream_in_use[!tx])
+		return wm8960_configure_clocking(component);
+
+	return 0;
+}
+
+static int wm8960_hw_free(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+
+	wm8960->is_stream_in_use[tx] = false;
+
+	return 0;
+}
+
+static int wm8960_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute)
+		snd_soc_component_update_bits(component, WM8960_DACCTL1, 0x8, 0x8);
+	else
+		snd_soc_component_update_bits(component, WM8960_DACCTL1, 0x8, 0);
+	return 0;
+}
+
+static int wm8960_set_bias_level_out3(struct snd_soc_component *component,
+				      enum snd_soc_bias_level level)
+{
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+	u16 pm2 = snd_soc_component_read32(component, WM8960_POWER2);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		switch (snd_soc_component_get_bias_level(component)) {
+		case SND_SOC_BIAS_STANDBY:
+			if (!IS_ERR(wm8960->mclk)) {
+				ret = clk_prepare_enable(wm8960->mclk);
+				if (ret) {
+					dev_err(component->dev,
+						"Failed to enable MCLK: %d\n",
+						ret);
+					return ret;
+				}
+			}
+
+			ret = wm8960_configure_clocking(component);
+			if (ret)
+				return ret;
+
+			/* Set VMID to 2x50k */
+			snd_soc_component_update_bits(component, WM8960_POWER1, 0x180, 0x80);
+			break;
+
+		case SND_SOC_BIAS_ON:
+			/*
+			 * If it's sysclk auto mode, and the pll is enabled,
+			 * disable the pll
+			 */
+			if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1))
+				wm8960_set_pll(component, 0, 0);
+
+			if (!IS_ERR(wm8960->mclk))
+				clk_disable_unprepare(wm8960->mclk);
+			break;
+
+		default:
+			break;
+		}
+
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			regcache_sync(wm8960->regmap);
+
+			/* Enable anti-pop features */
+			snd_soc_component_write(component, WM8960_APOP1,
+				      WM8960_POBCTRL | WM8960_SOFT_ST |
+				      WM8960_BUFDCOPEN | WM8960_BUFIOEN);
+
+			/* Enable & ramp VMID at 2x50k */
+			snd_soc_component_update_bits(component, WM8960_POWER1, 0x80, 0x80);
+			msleep(100);
+
+			/* Enable VREF */
+			snd_soc_component_update_bits(component, WM8960_POWER1, WM8960_VREF,
+					    WM8960_VREF);
+
+			/* Disable anti-pop features */
+			snd_soc_component_write(component, WM8960_APOP1, WM8960_BUFIOEN);
+		}
+
+		/* Set VMID to 2x250k */
+		snd_soc_component_update_bits(component, WM8960_POWER1, 0x180, 0x100);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* Enable anti-pop features */
+		snd_soc_component_write(component, WM8960_APOP1,
+			     WM8960_POBCTRL | WM8960_SOFT_ST |
+			     WM8960_BUFDCOPEN | WM8960_BUFIOEN);
+
+		/* Disable VMID and VREF, let them discharge */
+		snd_soc_component_write(component, WM8960_POWER1, 0);
+		msleep(600);
+		break;
+	}
+
+	return 0;
+}
+
+static int wm8960_set_bias_level_capless(struct snd_soc_component *component,
+					 enum snd_soc_bias_level level)
+{
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+	u16 pm2 = snd_soc_component_read32(component, WM8960_POWER2);
+	int reg, ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		switch (snd_soc_component_get_bias_level(component)) {
+		case SND_SOC_BIAS_STANDBY:
+			/* Enable anti pop mode */
+			snd_soc_component_update_bits(component, WM8960_APOP1,
+					    WM8960_POBCTRL | WM8960_SOFT_ST |
+					    WM8960_BUFDCOPEN,
+					    WM8960_POBCTRL | WM8960_SOFT_ST |
+					    WM8960_BUFDCOPEN);
+
+			/* Enable LOUT1, ROUT1 and OUT3 if they're enabled */
+			reg = 0;
+			if (wm8960->lout1 && wm8960->lout1->power)
+				reg |= WM8960_PWR2_LOUT1;
+			if (wm8960->rout1 && wm8960->rout1->power)
+				reg |= WM8960_PWR2_ROUT1;
+			if (wm8960->out3 && wm8960->out3->power)
+				reg |= WM8960_PWR2_OUT3;
+			snd_soc_component_update_bits(component, WM8960_POWER2,
+					    WM8960_PWR2_LOUT1 |
+					    WM8960_PWR2_ROUT1 |
+					    WM8960_PWR2_OUT3, reg);
+
+			/* Enable VMID at 2*50k */
+			snd_soc_component_update_bits(component, WM8960_POWER1,
+					    WM8960_VMID_MASK, 0x80);
+
+			/* Ramp */
+			msleep(100);
+
+			/* Enable VREF */
+			snd_soc_component_update_bits(component, WM8960_POWER1,
+					    WM8960_VREF, WM8960_VREF);
+
+			msleep(100);
+
+			if (!IS_ERR(wm8960->mclk)) {
+				ret = clk_prepare_enable(wm8960->mclk);
+				if (ret) {
+					dev_err(component->dev,
+						"Failed to enable MCLK: %d\n",
+						ret);
+					return ret;
+				}
+			}
+
+			ret = wm8960_configure_clocking(component);
+			if (ret)
+				return ret;
+
+			break;
+
+		case SND_SOC_BIAS_ON:
+			/*
+			 * If it's sysclk auto mode, and the pll is enabled,
+			 * disable the pll
+			 */
+			if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1))
+				wm8960_set_pll(component, 0, 0);
+
+			if (!IS_ERR(wm8960->mclk))
+				clk_disable_unprepare(wm8960->mclk);
+
+			/* Enable anti-pop mode */
+			snd_soc_component_update_bits(component, WM8960_APOP1,
+					    WM8960_POBCTRL | WM8960_SOFT_ST |
+					    WM8960_BUFDCOPEN,
+					    WM8960_POBCTRL | WM8960_SOFT_ST |
+					    WM8960_BUFDCOPEN);
+
+			/* Disable VMID and VREF */
+			snd_soc_component_update_bits(component, WM8960_POWER1,
+					    WM8960_VREF | WM8960_VMID_MASK, 0);
+			break;
+
+		case SND_SOC_BIAS_OFF:
+			regcache_sync(wm8960->regmap);
+			break;
+		default:
+			break;
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		switch (snd_soc_component_get_bias_level(component)) {
+		case SND_SOC_BIAS_PREPARE:
+			/* Disable HP discharge */
+			snd_soc_component_update_bits(component, WM8960_APOP2,
+					    WM8960_DISOP | WM8960_DRES_MASK,
+					    0);
+
+			/* Disable anti-pop features */
+			snd_soc_component_update_bits(component, WM8960_APOP1,
+					    WM8960_POBCTRL | WM8960_SOFT_ST |
+					    WM8960_BUFDCOPEN,
+					    WM8960_POBCTRL | WM8960_SOFT_ST |
+					    WM8960_BUFDCOPEN);
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		break;
+	}
+
+	return 0;
+}
+
+/* PLL divisors */
+struct _pll_div {
+	u32 pre_div:1;
+	u32 n:4;
+	u32 k:24;
+};
+
+static bool is_pll_freq_available(unsigned int source, unsigned int target)
+{
+	unsigned int Ndiv;
+
+	if (source == 0 || target == 0)
+		return false;
+
+	/* Scale up target to PLL operating frequency */
+	target *= 4;
+	Ndiv = target / source;
+
+	if (Ndiv < 6) {
+		source >>= 1;
+		Ndiv = target / source;
+	}
+
+	if ((Ndiv < 6) || (Ndiv > 12))
+		return false;
+
+	return true;
+}
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 24) * 10)
+
+static int pll_factors(unsigned int source, unsigned int target,
+		       struct _pll_div *pll_div)
+{
+	unsigned long long Kpart;
+	unsigned int K, Ndiv, Nmod;
+
+	pr_debug("WM8960 PLL: setting %dHz->%dHz\n", source, target);
+
+	/* Scale up target to PLL operating frequency */
+	target *= 4;
+
+	Ndiv = target / source;
+	if (Ndiv < 6) {
+		source >>= 1;
+		pll_div->pre_div = 1;
+		Ndiv = target / source;
+	} else
+		pll_div->pre_div = 0;
+
+	if ((Ndiv < 6) || (Ndiv > 12)) {
+		pr_err("WM8960 PLL: Unsupported N=%d\n", Ndiv);
+		return -EINVAL;
+	}
+
+	pll_div->n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	/* Check if we need to round */
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	K /= 10;
+
+	pll_div->k = K;
+
+	pr_debug("WM8960 PLL: N=%x K=%x pre_div=%d\n",
+		 pll_div->n, pll_div->k, pll_div->pre_div);
+
+	return 0;
+}
+
+static int wm8960_set_pll(struct snd_soc_component *component,
+		unsigned int freq_in, unsigned int freq_out)
+{
+	u16 reg;
+	static struct _pll_div pll_div;
+	int ret;
+
+	if (freq_in && freq_out) {
+		ret = pll_factors(freq_in, freq_out, &pll_div);
+		if (ret != 0)
+			return ret;
+	}
+
+	/* Disable the PLL: even if we are changing the frequency the
+	 * PLL needs to be disabled while we do so. */
+	snd_soc_component_update_bits(component, WM8960_CLOCK1, 0x1, 0);
+	snd_soc_component_update_bits(component, WM8960_POWER2, 0x1, 0);
+
+	if (!freq_in || !freq_out)
+		return 0;
+
+	reg = snd_soc_component_read32(component, WM8960_PLL1) & ~0x3f;
+	reg |= pll_div.pre_div << 4;
+	reg |= pll_div.n;
+
+	if (pll_div.k) {
+		reg |= 0x20;
+
+		snd_soc_component_write(component, WM8960_PLL2, (pll_div.k >> 16) & 0xff);
+		snd_soc_component_write(component, WM8960_PLL3, (pll_div.k >> 8) & 0xff);
+		snd_soc_component_write(component, WM8960_PLL4, pll_div.k & 0xff);
+	}
+	snd_soc_component_write(component, WM8960_PLL1, reg);
+
+	/* Turn it on */
+	snd_soc_component_update_bits(component, WM8960_POWER2, 0x1, 0x1);
+	msleep(250);
+	snd_soc_component_update_bits(component, WM8960_CLOCK1, 0x1, 0x1);
+
+	return 0;
+}
+
+static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+		int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+
+	wm8960->freq_in = freq_in;
+
+	if (pll_id == WM8960_SYSCLK_AUTO)
+		return 0;
+
+	return wm8960_set_pll(component, freq_in, freq_out);
+}
+
+static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+		int div_id, int div)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 reg;
+
+	switch (div_id) {
+	case WM8960_SYSCLKDIV:
+		reg = snd_soc_component_read32(component, WM8960_CLOCK1) & 0x1f9;
+		snd_soc_component_write(component, WM8960_CLOCK1, reg | div);
+		break;
+	case WM8960_DACDIV:
+		reg = snd_soc_component_read32(component, WM8960_CLOCK1) & 0x1c7;
+		snd_soc_component_write(component, WM8960_CLOCK1, reg | div);
+		break;
+	case WM8960_OPCLKDIV:
+		reg = snd_soc_component_read32(component, WM8960_PLL1) & 0x03f;
+		snd_soc_component_write(component, WM8960_PLL1, reg | div);
+		break;
+	case WM8960_DCLKDIV:
+		reg = snd_soc_component_read32(component, WM8960_CLOCK2) & 0x03f;
+		snd_soc_component_write(component, WM8960_CLOCK2, reg | div);
+		break;
+	case WM8960_TOCLKSEL:
+		reg = snd_soc_component_read32(component, WM8960_ADDCTL1) & 0x1fd;
+		snd_soc_component_write(component, WM8960_ADDCTL1, reg | div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8960_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+
+	return wm8960->set_bias_level(component, level);
+}
+
+static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+					unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case WM8960_SYSCLK_MCLK:
+		snd_soc_component_update_bits(component, WM8960_CLOCK1,
+					0x1, WM8960_SYSCLK_MCLK);
+		break;
+	case WM8960_SYSCLK_PLL:
+		snd_soc_component_update_bits(component, WM8960_CLOCK1,
+					0x1, WM8960_SYSCLK_PLL);
+		break;
+	case WM8960_SYSCLK_AUTO:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8960->sysclk = freq;
+	wm8960->clk_id = clk_id;
+
+	return 0;
+}
+
+#define WM8960_RATES SNDRV_PCM_RATE_8000_48000
+
+#define WM8960_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8960_dai_ops = {
+	.hw_params = wm8960_hw_params,
+	.hw_free = wm8960_hw_free,
+	.digital_mute = wm8960_mute,
+	.set_fmt = wm8960_set_dai_fmt,
+	.set_clkdiv = wm8960_set_dai_clkdiv,
+	.set_pll = wm8960_set_dai_pll,
+	.set_sysclk = wm8960_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8960_dai = {
+	.name = "wm8960-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8960_RATES,
+		.formats = WM8960_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8960_RATES,
+		.formats = WM8960_FORMATS,},
+	.ops = &wm8960_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int wm8960_probe(struct snd_soc_component *component)
+{
+	struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+	struct wm8960_data *pdata = &wm8960->pdata;
+
+	if (pdata->capless)
+		wm8960->set_bias_level = wm8960_set_bias_level_capless;
+	else
+		wm8960->set_bias_level = wm8960_set_bias_level_out3;
+
+	snd_soc_add_component_controls(component, wm8960_snd_controls,
+				     ARRAY_SIZE(wm8960_snd_controls));
+	wm8960_add_widgets(component);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8960 = {
+	.probe			= wm8960_probe,
+	.set_bias_level		= wm8960_set_bias_level,
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8960_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+	.max_register = WM8960_PLL4,
+
+	.reg_defaults = wm8960_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8960_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = wm8960_volatile,
+};
+
+static void wm8960_set_pdata_from_of(struct i2c_client *i2c,
+				struct wm8960_data *pdata)
+{
+	const struct device_node *np = i2c->dev.of_node;
+
+	if (of_property_read_bool(np, "wlf,capless"))
+		pdata->capless = true;
+
+	if (of_property_read_bool(np, "wlf,shared-lrclk"))
+		pdata->shared_lrclk = true;
+}
+
+static int wm8960_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8960_data *pdata = dev_get_platdata(&i2c->dev);
+	struct wm8960_priv *wm8960;
+	int ret;
+
+	wm8960 = devm_kzalloc(&i2c->dev, sizeof(struct wm8960_priv),
+			      GFP_KERNEL);
+	if (wm8960 == NULL)
+		return -ENOMEM;
+
+	wm8960->mclk = devm_clk_get(&i2c->dev, "mclk");
+	if (IS_ERR(wm8960->mclk)) {
+		if (PTR_ERR(wm8960->mclk) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+	}
+
+	wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap);
+	if (IS_ERR(wm8960->regmap))
+		return PTR_ERR(wm8960->regmap);
+
+	if (pdata)
+		memcpy(&wm8960->pdata, pdata, sizeof(struct wm8960_data));
+	else if (i2c->dev.of_node)
+		wm8960_set_pdata_from_of(i2c, &wm8960->pdata);
+
+	ret = wm8960_reset(wm8960->regmap);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	if (wm8960->pdata.shared_lrclk) {
+		ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2,
+					 0x4, 0x4);
+		if (ret != 0) {
+			dev_err(&i2c->dev, "Failed to enable LRCM: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	/* Latch the update bits */
+	regmap_update_bits(wm8960->regmap, WM8960_LINVOL, 0x100, 0x100);
+	regmap_update_bits(wm8960->regmap, WM8960_RINVOL, 0x100, 0x100);
+	regmap_update_bits(wm8960->regmap, WM8960_LADC, 0x100, 0x100);
+	regmap_update_bits(wm8960->regmap, WM8960_RADC, 0x100, 0x100);
+	regmap_update_bits(wm8960->regmap, WM8960_LDAC, 0x100, 0x100);
+	regmap_update_bits(wm8960->regmap, WM8960_RDAC, 0x100, 0x100);
+	regmap_update_bits(wm8960->regmap, WM8960_LOUT1, 0x100, 0x100);
+	regmap_update_bits(wm8960->regmap, WM8960_ROUT1, 0x100, 0x100);
+	regmap_update_bits(wm8960->regmap, WM8960_LOUT2, 0x100, 0x100);
+	regmap_update_bits(wm8960->regmap, WM8960_ROUT2, 0x100, 0x100);
+
+	i2c_set_clientdata(i2c, wm8960);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8960, &wm8960_dai, 1);
+
+	return ret;
+}
+
+static int wm8960_i2c_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id wm8960_i2c_id[] = {
+	{ "wm8960", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id);
+
+static const struct of_device_id wm8960_of_match[] = {
+       { .compatible = "wlf,wm8960", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wm8960_of_match);
+
+static struct i2c_driver wm8960_i2c_driver = {
+	.driver = {
+		.name = "wm8960",
+		.of_match_table = wm8960_of_match,
+	},
+	.probe =    wm8960_i2c_probe,
+	.remove =   wm8960_i2c_remove,
+	.id_table = wm8960_i2c_id,
+};
+
+module_i2c_driver(wm8960_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8960 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h
new file mode 100644
index 0000000..ab3220d
--- /dev/null
+++ b/sound/soc/codecs/wm8960.h
@@ -0,0 +1,114 @@
+/*
+ * wm8960.h  --  WM8960 Soc Audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8960_H
+#define _WM8960_H
+
+/* WM8960 register space */
+
+
+#define WM8960_CACHEREGNUM 	56
+
+#define WM8960_LINVOL		0x0
+#define WM8960_RINVOL		0x1
+#define WM8960_LOUT1		0x2
+#define WM8960_ROUT1		0x3
+#define WM8960_CLOCK1		0x4
+#define WM8960_DACCTL1		0x5
+#define WM8960_DACCTL2		0x6
+#define WM8960_IFACE1		0x7
+#define WM8960_CLOCK2		0x8
+#define WM8960_IFACE2		0x9
+#define WM8960_LDAC		0xa
+#define WM8960_RDAC		0xb
+
+#define WM8960_RESET		0xf
+#define WM8960_3D		0x10
+#define WM8960_ALC1		0x11
+#define WM8960_ALC2		0x12
+#define WM8960_ALC3		0x13
+#define WM8960_NOISEG		0x14
+#define WM8960_LADC		0x15
+#define WM8960_RADC		0x16
+#define WM8960_ADDCTL1		0x17
+#define WM8960_ADDCTL2		0x18
+#define WM8960_POWER1		0x19
+#define WM8960_POWER2		0x1a
+#define WM8960_ADDCTL3		0x1b
+#define WM8960_APOP1		0x1c
+#define WM8960_APOP2		0x1d
+
+#define WM8960_LINPATH		0x20
+#define WM8960_RINPATH		0x21
+#define WM8960_LOUTMIX		0x22
+
+#define WM8960_ROUTMIX		0x25
+#define WM8960_MONOMIX1		0x26
+#define WM8960_MONOMIX2		0x27
+#define WM8960_LOUT2		0x28
+#define WM8960_ROUT2		0x29
+#define WM8960_MONO		0x2a
+#define WM8960_INBMIX1		0x2b
+#define WM8960_INBMIX2		0x2c
+#define WM8960_BYPASS1		0x2d
+#define WM8960_BYPASS2		0x2e
+#define WM8960_POWER3		0x2f
+#define WM8960_ADDCTL4		0x30
+#define WM8960_CLASSD1		0x31
+
+#define WM8960_CLASSD3		0x33
+#define WM8960_PLL1		0x34
+#define WM8960_PLL2		0x35
+#define WM8960_PLL3		0x36
+#define WM8960_PLL4		0x37
+
+
+/*
+ * WM8960 Clock dividers
+ */
+#define WM8960_SYSCLKDIV 		0
+#define WM8960_DACDIV			1
+#define WM8960_OPCLKDIV			2
+#define WM8960_DCLKDIV			3
+#define WM8960_TOCLKSEL			4
+
+#define WM8960_SYSCLK_DIV_1		(0 << 1)
+#define WM8960_SYSCLK_DIV_2		(2 << 1)
+
+#define WM8960_SYSCLK_MCLK		(0 << 0)
+#define WM8960_SYSCLK_PLL		(1 << 0)
+#define WM8960_SYSCLK_AUTO		(2 << 0)
+
+#define WM8960_DAC_DIV_1		(0 << 3)
+#define WM8960_DAC_DIV_1_5		(1 << 3)
+#define WM8960_DAC_DIV_2		(2 << 3)
+#define WM8960_DAC_DIV_3		(3 << 3)
+#define WM8960_DAC_DIV_4		(4 << 3)
+#define WM8960_DAC_DIV_5_5		(5 << 3)
+#define WM8960_DAC_DIV_6		(6 << 3)
+
+#define WM8960_DCLK_DIV_1_5		(0 << 6)
+#define WM8960_DCLK_DIV_2		(1 << 6)
+#define WM8960_DCLK_DIV_3		(2 << 6)
+#define WM8960_DCLK_DIV_4		(3 << 6)
+#define WM8960_DCLK_DIV_6		(4 << 6)
+#define WM8960_DCLK_DIV_8		(5 << 6)
+#define WM8960_DCLK_DIV_12		(6 << 6)
+#define WM8960_DCLK_DIV_16		(7 << 6)
+
+#define WM8960_TOCLK_F19		(0 << 1)
+#define WM8960_TOCLK_F21		(1 << 1)
+
+#define WM8960_OPCLK_DIV_1		(0 << 0)
+#define WM8960_OPCLK_DIV_2		(1 << 0)
+#define WM8960_OPCLK_DIV_3		(2 << 0)
+#define WM8960_OPCLK_DIV_4		(3 << 0)
+#define WM8960_OPCLK_DIV_5_5		(4 << 0)
+#define WM8960_OPCLK_DIV_6		(5 << 0)
+
+#endif
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
new file mode 100644
index 0000000..68b4cad
--- /dev/null
+++ b/sound/soc/codecs/wm8961.c
@@ -0,0 +1,990 @@
+/*
+ * wm8961.c  --  WM8961 ALSA SoC Audio driver
+ *
+ * Copyright 2009-10 Wolfson Microelectronics, plc
+ *
+ * Author: Mark Brown
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Currently unimplemented features:
+ *  - ALC
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8961.h"
+
+#define WM8961_MAX_REGISTER                     0xFC
+
+static const struct reg_default wm8961_reg_defaults[] = {
+	{  0, 0x009F },     /* R0   - Left Input volume */
+	{  1, 0x009F },     /* R1   - Right Input volume */
+	{  2, 0x0000 },     /* R2   - LOUT1 volume */
+	{  3, 0x0000 },     /* R3   - ROUT1 volume */
+	{  4, 0x0020 },     /* R4   - Clocking1 */
+	{  5, 0x0008 },     /* R5   - ADC & DAC Control 1 */
+	{  6, 0x0000 },     /* R6   - ADC & DAC Control 2 */
+	{  7, 0x000A },     /* R7   - Audio Interface 0 */
+	{  8, 0x01F4 },     /* R8   - Clocking2 */
+	{  9, 0x0000 },     /* R9   - Audio Interface 1 */
+	{ 10, 0x00FF },     /* R10  - Left DAC volume */
+	{ 11, 0x00FF },     /* R11  - Right DAC volume */
+
+	{ 14, 0x0040 },     /* R14  - Audio Interface 2 */
+
+	{ 17, 0x007B },     /* R17  - ALC1 */
+	{ 18, 0x0000 },     /* R18  - ALC2 */
+	{ 19, 0x0032 },     /* R19  - ALC3 */
+	{ 20, 0x0000 },     /* R20  - Noise Gate */
+	{ 21, 0x00C0 },     /* R21  - Left ADC volume */
+	{ 22, 0x00C0 },     /* R22  - Right ADC volume */
+	{ 23, 0x0120 },     /* R23  - Additional control(1) */
+	{ 24, 0x0000 },     /* R24  - Additional control(2) */
+	{ 25, 0x0000 },     /* R25  - Pwr Mgmt (1) */
+	{ 26, 0x0000 },     /* R26  - Pwr Mgmt (2) */
+	{ 27, 0x0000 },     /* R27  - Additional Control (3) */
+	{ 28, 0x0000 },     /* R28  - Anti-pop */
+
+	{ 30, 0x005F },     /* R30  - Clocking 3 */
+
+	{ 32, 0x0000 },     /* R32  - ADCL signal path */
+	{ 33, 0x0000 },     /* R33  - ADCR signal path */
+
+	{ 40, 0x0000 },     /* R40  - LOUT2 volume */
+	{ 41, 0x0000 },     /* R41  - ROUT2 volume */
+
+	{ 47, 0x0000 },     /* R47  - Pwr Mgmt (3) */
+	{ 48, 0x0023 },     /* R48  - Additional Control (4) */
+	{ 49, 0x0000 },     /* R49  - Class D Control 1 */
+
+	{ 51, 0x0003 },     /* R51  - Class D Control 2 */
+
+	{ 56, 0x0106 },     /* R56  - Clocking 4 */
+	{ 57, 0x0000 },     /* R57  - DSP Sidetone 0 */
+	{ 58, 0x0000 },     /* R58  - DSP Sidetone 1 */
+
+	{ 60, 0x0000 },     /* R60  - DC Servo 0 */
+	{ 61, 0x0000 },     /* R61  - DC Servo 1 */
+
+	{ 63, 0x015E },     /* R63  - DC Servo 3 */
+
+	{ 65, 0x0010 },     /* R65  - DC Servo 5 */
+
+	{ 68, 0x0003 },     /* R68  - Analogue PGA Bias */
+	{ 69, 0x0000 },     /* R69  - Analogue HP 0 */
+
+	{ 71, 0x01FB },     /* R71  - Analogue HP 2 */
+	{ 72, 0x0000 },     /* R72  - Charge Pump 1 */
+
+	{ 82, 0x0000 },     /* R82  - Charge Pump B */
+
+	{ 87, 0x0000 },     /* R87  - Write Sequencer 1 */
+	{ 88, 0x0000 },     /* R88  - Write Sequencer 2 */
+	{ 89, 0x0000 },     /* R89  - Write Sequencer 3 */
+	{ 90, 0x0000 },     /* R90  - Write Sequencer 4 */
+	{ 91, 0x0000 },     /* R91  - Write Sequencer 5 */
+	{ 92, 0x0000 },     /* R92  - Write Sequencer 6 */
+	{ 93, 0x0000 },     /* R93  - Write Sequencer 7 */
+
+	{ 252, 0x0001 },     /* R252 - General test 1 */
+};
+
+struct wm8961_priv {
+	struct regmap *regmap;
+	int sysclk;
+};
+
+static bool wm8961_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8961_SOFTWARE_RESET:
+	case WM8961_WRITE_SEQUENCER_7:
+	case WM8961_DC_SERVO_1:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+static bool wm8961_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8961_LEFT_INPUT_VOLUME:
+	case WM8961_RIGHT_INPUT_VOLUME:
+	case WM8961_LOUT1_VOLUME:
+	case WM8961_ROUT1_VOLUME:
+	case WM8961_CLOCKING1:
+	case WM8961_ADC_DAC_CONTROL_1:
+	case WM8961_ADC_DAC_CONTROL_2:
+	case WM8961_AUDIO_INTERFACE_0:
+	case WM8961_CLOCKING2:
+	case WM8961_AUDIO_INTERFACE_1:
+	case WM8961_LEFT_DAC_VOLUME:
+	case WM8961_RIGHT_DAC_VOLUME:
+	case WM8961_AUDIO_INTERFACE_2:
+	case WM8961_SOFTWARE_RESET:
+	case WM8961_ALC1:
+	case WM8961_ALC2:
+	case WM8961_ALC3:
+	case WM8961_NOISE_GATE:
+	case WM8961_LEFT_ADC_VOLUME:
+	case WM8961_RIGHT_ADC_VOLUME:
+	case WM8961_ADDITIONAL_CONTROL_1:
+	case WM8961_ADDITIONAL_CONTROL_2:
+	case WM8961_PWR_MGMT_1:
+	case WM8961_PWR_MGMT_2:
+	case WM8961_ADDITIONAL_CONTROL_3:
+	case WM8961_ANTI_POP:
+	case WM8961_CLOCKING_3:
+	case WM8961_ADCL_SIGNAL_PATH:
+	case WM8961_ADCR_SIGNAL_PATH:
+	case WM8961_LOUT2_VOLUME:
+	case WM8961_ROUT2_VOLUME:
+	case WM8961_PWR_MGMT_3:
+	case WM8961_ADDITIONAL_CONTROL_4:
+	case WM8961_CLASS_D_CONTROL_1:
+	case WM8961_CLASS_D_CONTROL_2:
+	case WM8961_CLOCKING_4:
+	case WM8961_DSP_SIDETONE_0:
+	case WM8961_DSP_SIDETONE_1:
+	case WM8961_DC_SERVO_0:
+	case WM8961_DC_SERVO_1:
+	case WM8961_DC_SERVO_3:
+	case WM8961_DC_SERVO_5:
+	case WM8961_ANALOGUE_PGA_BIAS:
+	case WM8961_ANALOGUE_HP_0:
+	case WM8961_ANALOGUE_HP_2:
+	case WM8961_CHARGE_PUMP_1:
+	case WM8961_CHARGE_PUMP_B:
+	case WM8961_WRITE_SEQUENCER_1:
+	case WM8961_WRITE_SEQUENCER_2:
+	case WM8961_WRITE_SEQUENCER_3:
+	case WM8961_WRITE_SEQUENCER_4:
+	case WM8961_WRITE_SEQUENCER_5:
+	case WM8961_WRITE_SEQUENCER_6:
+	case WM8961_WRITE_SEQUENCER_7:
+	case WM8961_GENERAL_TEST_1:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/*
+ * The headphone output supports special anti-pop sequences giving
+ * silent power up and power down.
+ */
+static int wm8961_hp_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 hp_reg = snd_soc_component_read32(component, WM8961_ANALOGUE_HP_0);
+	u16 cp_reg = snd_soc_component_read32(component, WM8961_CHARGE_PUMP_1);
+	u16 pwr_reg = snd_soc_component_read32(component, WM8961_PWR_MGMT_2);
+	u16 dcs_reg = snd_soc_component_read32(component, WM8961_DC_SERVO_1);
+	int timeout = 500;
+
+	if (event & SND_SOC_DAPM_POST_PMU) {
+		/* Make sure the output is shorted */
+		hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT);
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
+
+		/* Enable the charge pump */
+		cp_reg |= WM8961_CP_ENA;
+		snd_soc_component_write(component, WM8961_CHARGE_PUMP_1, cp_reg);
+		mdelay(5);
+
+		/* Enable the PGA */
+		pwr_reg |= WM8961_LOUT1_PGA | WM8961_ROUT1_PGA;
+		snd_soc_component_write(component, WM8961_PWR_MGMT_2, pwr_reg);
+
+		/* Enable the amplifier */
+		hp_reg |= WM8961_HPR_ENA | WM8961_HPL_ENA;
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
+
+		/* Second stage enable */
+		hp_reg |= WM8961_HPR_ENA_DLY | WM8961_HPL_ENA_DLY;
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
+
+		/* Enable the DC servo & trigger startup */
+		dcs_reg |=
+			WM8961_DCS_ENA_CHAN_HPR | WM8961_DCS_TRIG_STARTUP_HPR |
+			WM8961_DCS_ENA_CHAN_HPL | WM8961_DCS_TRIG_STARTUP_HPL;
+		dev_dbg(component->dev, "Enabling DC servo\n");
+
+		snd_soc_component_write(component, WM8961_DC_SERVO_1, dcs_reg);
+		do {
+			msleep(1);
+			dcs_reg = snd_soc_component_read32(component, WM8961_DC_SERVO_1);
+		} while (--timeout &&
+			 dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR |
+				WM8961_DCS_TRIG_STARTUP_HPL));
+		if (dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR |
+			       WM8961_DCS_TRIG_STARTUP_HPL))
+			dev_err(component->dev, "DC servo timed out\n");
+		else
+			dev_dbg(component->dev, "DC servo startup complete\n");
+
+		/* Enable the output stage */
+		hp_reg |= WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP;
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
+
+		/* Remove the short on the output stage */
+		hp_reg |= WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT;
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
+	}
+
+	if (event & SND_SOC_DAPM_PRE_PMD) {
+		/* Short the output */
+		hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT);
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
+
+		/* Disable the output stage */
+		hp_reg &= ~(WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP);
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
+
+		/* Disable DC offset cancellation */
+		dcs_reg &= ~(WM8961_DCS_ENA_CHAN_HPR |
+			     WM8961_DCS_ENA_CHAN_HPL);
+		snd_soc_component_write(component, WM8961_DC_SERVO_1, dcs_reg);
+
+		/* Finish up */
+		hp_reg &= ~(WM8961_HPR_ENA_DLY | WM8961_HPR_ENA |
+			    WM8961_HPL_ENA_DLY | WM8961_HPL_ENA);
+		snd_soc_component_write(component, WM8961_ANALOGUE_HP_0, hp_reg);
+
+		/* Disable the PGA */
+		pwr_reg &= ~(WM8961_LOUT1_PGA | WM8961_ROUT1_PGA);
+		snd_soc_component_write(component, WM8961_PWR_MGMT_2, pwr_reg);
+
+		/* Disable the charge pump */
+		dev_dbg(component->dev, "Disabling charge pump\n");
+		snd_soc_component_write(component, WM8961_CHARGE_PUMP_1,
+			     cp_reg & ~WM8961_CP_ENA);
+	}
+
+	return 0;
+}
+
+static int wm8961_spk_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 pwr_reg = snd_soc_component_read32(component, WM8961_PWR_MGMT_2);
+	u16 spk_reg = snd_soc_component_read32(component, WM8961_CLASS_D_CONTROL_1);
+
+	if (event & SND_SOC_DAPM_POST_PMU) {
+		/* Enable the PGA */
+		pwr_reg |= WM8961_SPKL_PGA | WM8961_SPKR_PGA;
+		snd_soc_component_write(component, WM8961_PWR_MGMT_2, pwr_reg);
+
+		/* Enable the amplifier */
+		spk_reg |= WM8961_SPKL_ENA | WM8961_SPKR_ENA;
+		snd_soc_component_write(component, WM8961_CLASS_D_CONTROL_1, spk_reg);
+	}
+
+	if (event & SND_SOC_DAPM_PRE_PMD) {
+		/* Disable the amplifier */
+		spk_reg &= ~(WM8961_SPKL_ENA | WM8961_SPKR_ENA);
+		snd_soc_component_write(component, WM8961_CLASS_D_CONTROL_1, spk_reg);
+
+		/* Disable the PGA */
+		pwr_reg &= ~(WM8961_SPKL_PGA | WM8961_SPKR_PGA);
+		snd_soc_component_write(component, WM8961_PWR_MGMT_2, pwr_reg);
+	}
+
+	return 0;
+}
+
+static const char *adc_hpf_text[] = {
+	"Hi-fi", "Voice 1", "Voice 2", "Voice 3",
+};
+
+static SOC_ENUM_SINGLE_DECL(adc_hpf,
+			    WM8961_ADC_DAC_CONTROL_2, 7, adc_hpf_text);
+
+static const char *dac_deemph_text[] = {
+	"None", "32kHz", "44.1kHz", "48kHz",
+};
+
+static SOC_ENUM_SINGLE_DECL(dac_deemph,
+			    WM8961_ADC_DAC_CONTROL_1, 1, dac_deemph_text);
+
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(hp_sec_tlv, -700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0);
+static const DECLARE_TLV_DB_RANGE(boost_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(0,  0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(13, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(20, 0, 0),
+	3, 3, TLV_DB_SCALE_ITEM(29, 0, 0)
+);
+static const DECLARE_TLV_DB_SCALE(pga_tlv, -2325, 75, 0);
+
+static const struct snd_kcontrol_new wm8961_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Headphone Volume", WM8961_LOUT1_VOLUME, WM8961_ROUT1_VOLUME,
+		 0, 127, 0, out_tlv),
+SOC_DOUBLE_TLV("Headphone Secondary Volume", WM8961_ANALOGUE_HP_2,
+	       6, 3, 7, 0, hp_sec_tlv),
+SOC_DOUBLE_R("Headphone ZC Switch", WM8961_LOUT1_VOLUME, WM8961_ROUT1_VOLUME,
+	     7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Speaker Volume", WM8961_LOUT2_VOLUME, WM8961_ROUT2_VOLUME,
+		 0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8961_LOUT2_VOLUME, WM8961_ROUT2_VOLUME,
+	   7, 1, 0),
+SOC_SINGLE("Speaker AC Gain", WM8961_CLASS_D_CONTROL_2, 0, 7, 0),
+
+SOC_SINGLE("DAC x128 OSR Switch", WM8961_ADC_DAC_CONTROL_2, 0, 1, 0),
+SOC_ENUM("DAC Deemphasis", dac_deemph),
+SOC_SINGLE("DAC Soft Mute Switch", WM8961_ADC_DAC_CONTROL_2, 3, 1, 0),
+
+SOC_DOUBLE_R_TLV("Sidetone Volume", WM8961_DSP_SIDETONE_0,
+		 WM8961_DSP_SIDETONE_1, 4, 12, 0, sidetone_tlv),
+
+SOC_SINGLE("ADC High Pass Filter Switch", WM8961_ADC_DAC_CONTROL_1, 0, 1, 0),
+SOC_ENUM("ADC High Pass Filter Mode", adc_hpf),
+
+SOC_DOUBLE_R_TLV("Capture Volume",
+		 WM8961_LEFT_ADC_VOLUME, WM8961_RIGHT_ADC_VOLUME,
+		 1, 119, 0, adc_tlv),
+SOC_DOUBLE_R_TLV("Capture Boost Volume",
+		 WM8961_ADCL_SIGNAL_PATH, WM8961_ADCR_SIGNAL_PATH,
+		 4, 3, 0, boost_tlv),
+SOC_DOUBLE_R_TLV("Capture PGA Volume",
+		 WM8961_LEFT_INPUT_VOLUME, WM8961_RIGHT_INPUT_VOLUME,
+		 0, 62, 0, pga_tlv),
+SOC_DOUBLE_R("Capture PGA ZC Switch",
+	     WM8961_LEFT_INPUT_VOLUME, WM8961_RIGHT_INPUT_VOLUME,
+	     6, 1, 1),
+SOC_DOUBLE_R("Capture PGA Switch",
+	     WM8961_LEFT_INPUT_VOLUME, WM8961_RIGHT_INPUT_VOLUME,
+	     7, 1, 1),
+};
+
+static const char *sidetone_text[] = {
+	"None", "Left", "Right"
+};
+
+static SOC_ENUM_SINGLE_DECL(dacl_sidetone,
+			    WM8961_DSP_SIDETONE_0, 2, sidetone_text);
+
+static SOC_ENUM_SINGLE_DECL(dacr_sidetone,
+			    WM8961_DSP_SIDETONE_1, 2, sidetone_text);
+
+static const struct snd_kcontrol_new dacl_mux =
+	SOC_DAPM_ENUM("DACL Sidetone", dacl_sidetone);
+
+static const struct snd_kcontrol_new dacr_mux =
+	SOC_DAPM_ENUM("DACR Sidetone", dacr_sidetone);
+
+static const struct snd_soc_dapm_widget wm8961_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("LINPUT"),
+SND_SOC_DAPM_INPUT("RINPUT"),
+
+SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8961_CLOCKING2, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Left Input", WM8961_PWR_MGMT_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Input", WM8961_PWR_MGMT_1, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", WM8961_PWR_MGMT_1, 3, 0),
+SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", WM8961_PWR_MGMT_1, 2, 0),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS", WM8961_PWR_MGMT_1, 1, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &dacl_mux),
+SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &dacr_mux),
+
+SND_SOC_DAPM_DAC("DACL", "HiFi Playback", WM8961_PWR_MGMT_2, 8, 0),
+SND_SOC_DAPM_DAC("DACR", "HiFi Playback", WM8961_PWR_MGMT_2, 7, 0),
+
+/* Handle as a mono path for DCS */
+SND_SOC_DAPM_PGA_E("Headphone Output", SND_SOC_NOPM,
+		   4, 0, NULL, 0, wm8961_hp_event,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_E("Speaker Output", SND_SOC_NOPM,
+		   4, 0, NULL, 0, wm8961_spk_event,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("HP_L"),
+SND_SOC_DAPM_OUTPUT("HP_R"),
+SND_SOC_DAPM_OUTPUT("SPK_LN"),
+SND_SOC_DAPM_OUTPUT("SPK_LP"),
+SND_SOC_DAPM_OUTPUT("SPK_RN"),
+SND_SOC_DAPM_OUTPUT("SPK_RP"),
+};
+
+
+static const struct snd_soc_dapm_route audio_paths[] = {
+	{ "DACL", NULL, "CLK_DSP" },
+	{ "DACL", NULL, "DACL Sidetone" },
+	{ "DACR", NULL, "CLK_DSP" },
+	{ "DACR", NULL, "DACR Sidetone" },
+
+	{ "DACL Sidetone", "Left", "ADCL" },
+	{ "DACL Sidetone", "Right", "ADCR" },
+
+	{ "DACR Sidetone", "Left", "ADCL" },
+	{ "DACR Sidetone", "Right", "ADCR" },
+
+	{ "HP_L", NULL, "Headphone Output" },
+	{ "HP_R", NULL, "Headphone Output" },
+	{ "Headphone Output", NULL, "DACL" },
+	{ "Headphone Output", NULL, "DACR" },
+
+	{ "SPK_LN", NULL, "Speaker Output" },
+	{ "SPK_LP", NULL, "Speaker Output" },
+	{ "SPK_RN", NULL, "Speaker Output" },
+	{ "SPK_RP", NULL, "Speaker Output" },
+
+	{ "Speaker Output", NULL, "DACL" },
+	{ "Speaker Output", NULL, "DACR" },
+
+	{ "ADCL", NULL, "Left Input" },
+	{ "ADCL", NULL, "CLK_DSP" },
+	{ "ADCR", NULL, "Right Input" },
+	{ "ADCR", NULL, "CLK_DSP" },
+
+	{ "Left Input", NULL, "LINPUT" },
+	{ "Right Input", NULL, "RINPUT" },
+
+};
+
+/* Values for CLK_SYS_RATE */
+static struct {
+	int ratio;
+	u16 val;
+} wm8961_clk_sys_ratio[] = {
+	{  64,  0 },
+	{  128, 1 },
+	{  192, 2 },
+	{  256, 3 },
+	{  384, 4 },
+	{  512, 5 },
+	{  768, 6 },
+	{ 1024, 7 },
+	{ 1408, 8 },
+	{ 1536, 9 },
+};
+
+/* Values for SAMPLE_RATE */
+static struct {
+	int rate;
+	u16 val;
+} wm8961_srate[] = {
+	{ 48000, 0 },
+	{ 44100, 0 },
+	{ 32000, 1 },
+	{ 22050, 2 },
+	{ 24000, 2 },
+	{ 16000, 3 },
+	{ 11250, 4 },
+	{ 12000, 4 },
+	{  8000, 5 },
+};
+
+static int wm8961_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8961_priv *wm8961 = snd_soc_component_get_drvdata(component);
+	int i, best, target, fs;
+	u16 reg;
+
+	fs = params_rate(params);
+
+	if (!wm8961->sysclk) {
+		dev_err(component->dev, "MCLK has not been specified\n");
+		return -EINVAL;
+	}
+
+	/* Find the closest sample rate for the filters */
+	best = 0;
+	for (i = 0; i < ARRAY_SIZE(wm8961_srate); i++) {
+		if (abs(wm8961_srate[i].rate - fs) <
+		    abs(wm8961_srate[best].rate - fs))
+			best = i;
+	}
+	reg = snd_soc_component_read32(component, WM8961_ADDITIONAL_CONTROL_3);
+	reg &= ~WM8961_SAMPLE_RATE_MASK;
+	reg |= wm8961_srate[best].val;
+	snd_soc_component_write(component, WM8961_ADDITIONAL_CONTROL_3, reg);
+	dev_dbg(component->dev, "Selected SRATE %dHz for %dHz\n",
+		wm8961_srate[best].rate, fs);
+
+	/* Select a CLK_SYS/fs ratio equal to or higher than required */
+	target = wm8961->sysclk / fs;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && target < 64) {
+		dev_err(component->dev,
+			"SYSCLK must be at least 64*fs for DAC\n");
+		return -EINVAL;
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && target < 256) {
+		dev_err(component->dev,
+			"SYSCLK must be at least 256*fs for ADC\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm8961_clk_sys_ratio); i++) {
+		if (wm8961_clk_sys_ratio[i].ratio >= target)
+			break;
+	}
+	if (i == ARRAY_SIZE(wm8961_clk_sys_ratio)) {
+		dev_err(component->dev, "Unable to generate CLK_SYS_RATE\n");
+		return -EINVAL;
+	}
+	dev_dbg(component->dev, "Selected CLK_SYS_RATE of %d for %d/%d=%d\n",
+		wm8961_clk_sys_ratio[i].ratio, wm8961->sysclk, fs,
+		wm8961->sysclk / fs);
+
+	reg = snd_soc_component_read32(component, WM8961_CLOCKING_4);
+	reg &= ~WM8961_CLK_SYS_RATE_MASK;
+	reg |= wm8961_clk_sys_ratio[i].val << WM8961_CLK_SYS_RATE_SHIFT;
+	snd_soc_component_write(component, WM8961_CLOCKING_4, reg);
+
+	reg = snd_soc_component_read32(component, WM8961_AUDIO_INTERFACE_0);
+	reg &= ~WM8961_WL_MASK;
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		reg |= 1 << WM8961_WL_SHIFT;
+		break;
+	case 24:
+		reg |= 2 << WM8961_WL_SHIFT;
+		break;
+	case 32:
+		reg |= 3 << WM8961_WL_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_component_write(component, WM8961_AUDIO_INTERFACE_0, reg);
+
+	/* Sloping stop-band filter is recommended for <= 24kHz */
+	reg = snd_soc_component_read32(component, WM8961_ADC_DAC_CONTROL_2);
+	if (fs <= 24000)
+		reg |= WM8961_DACSLOPE;
+	else
+		reg &= ~WM8961_DACSLOPE;
+	snd_soc_component_write(component, WM8961_ADC_DAC_CONTROL_2, reg);
+
+	return 0;
+}
+
+static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+			     unsigned int freq,
+			     int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8961_priv *wm8961 = snd_soc_component_get_drvdata(component);
+	u16 reg = snd_soc_component_read32(component, WM8961_CLOCKING1);
+
+	if (freq > 33000000) {
+		dev_err(component->dev, "MCLK must be <33MHz\n");
+		return -EINVAL;
+	}
+
+	if (freq > 16500000) {
+		dev_dbg(component->dev, "Using MCLK/2 for %dHz MCLK\n", freq);
+		reg |= WM8961_MCLKDIV;
+		freq /= 2;
+	} else {
+		dev_dbg(component->dev, "Using MCLK/1 for %dHz MCLK\n", freq);
+		reg &= ~WM8961_MCLKDIV;
+	}
+
+	snd_soc_component_write(component, WM8961_CLOCKING1, reg);
+
+	wm8961->sysclk = freq;
+
+	return 0;
+}
+
+static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 aif = snd_soc_component_read32(component, WM8961_AUDIO_INTERFACE_0);
+
+	aif &= ~(WM8961_BCLKINV | WM8961_LRP |
+		 WM8961_MS | WM8961_FORMAT_MASK);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif |= WM8961_MS;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif |= 1;
+		break;
+
+	case SND_SOC_DAIFMT_I2S:
+		aif |= 2;
+		break;
+
+	case SND_SOC_DAIFMT_DSP_B:
+		aif |= WM8961_LRP;
+		/* fall through */
+	case SND_SOC_DAIFMT_DSP_A:
+		aif |= 3;
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+		case SND_SOC_DAIFMT_IB_NF:
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		aif |= WM8961_LRP;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		aif |= WM8961_BCLKINV;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		aif |= WM8961_BCLKINV | WM8961_LRP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_soc_component_write(component, WM8961_AUDIO_INTERFACE_0, aif);
+}
+
+static int wm8961_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 reg = snd_soc_component_read32(component, WM8961_ADDITIONAL_CONTROL_2);
+
+	if (tristate)
+		reg |= WM8961_TRIS;
+	else
+		reg &= ~WM8961_TRIS;
+
+	return snd_soc_component_write(component, WM8961_ADDITIONAL_CONTROL_2, reg);
+}
+
+static int wm8961_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 reg = snd_soc_component_read32(component, WM8961_ADC_DAC_CONTROL_1);
+
+	if (mute)
+		reg |= WM8961_DACMU;
+	else
+		reg &= ~WM8961_DACMU;
+
+	msleep(17);
+
+	return snd_soc_component_write(component, WM8961_ADC_DAC_CONTROL_1, reg);
+}
+
+static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 reg;
+
+	switch (div_id) {
+	case WM8961_BCLK:
+		reg = snd_soc_component_read32(component, WM8961_CLOCKING2);
+		reg &= ~WM8961_BCLKDIV_MASK;
+		reg |= div;
+		snd_soc_component_write(component, WM8961_CLOCKING2, reg);
+		break;
+
+	case WM8961_LRCLK:
+		reg = snd_soc_component_read32(component, WM8961_AUDIO_INTERFACE_2);
+		reg &= ~WM8961_LRCLK_RATE_MASK;
+		reg |= div;
+		snd_soc_component_write(component, WM8961_AUDIO_INTERFACE_2, reg);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8961_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	u16 reg;
+
+	/* This is all slightly unusual since we have no bypass paths
+	 * and the output amplifier structure means we can just slam
+	 * the biases straight up rather than having to ramp them
+	 * slowly.
+	 */
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY) {
+			/* Enable bias generation */
+			reg = snd_soc_component_read32(component, WM8961_ANTI_POP);
+			reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN;
+			snd_soc_component_write(component, WM8961_ANTI_POP, reg);
+
+			/* VMID=2*50k, VREF */
+			reg = snd_soc_component_read32(component, WM8961_PWR_MGMT_1);
+			reg &= ~WM8961_VMIDSEL_MASK;
+			reg |= (1 << WM8961_VMIDSEL_SHIFT) | WM8961_VREF;
+			snd_soc_component_write(component, WM8961_PWR_MGMT_1, reg);
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE) {
+			/* VREF off */
+			reg = snd_soc_component_read32(component, WM8961_PWR_MGMT_1);
+			reg &= ~WM8961_VREF;
+			snd_soc_component_write(component, WM8961_PWR_MGMT_1, reg);
+
+			/* Bias generation off */
+			reg = snd_soc_component_read32(component, WM8961_ANTI_POP);
+			reg &= ~(WM8961_BUFIOEN | WM8961_BUFDCOPEN);
+			snd_soc_component_write(component, WM8961_ANTI_POP, reg);
+
+			/* VMID off */
+			reg = snd_soc_component_read32(component, WM8961_PWR_MGMT_1);
+			reg &= ~WM8961_VMIDSEL_MASK;
+			snd_soc_component_write(component, WM8961_PWR_MGMT_1, reg);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		break;
+	}
+
+	return 0;
+}
+
+
+#define WM8961_RATES SNDRV_PCM_RATE_8000_48000
+
+#define WM8961_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops wm8961_dai_ops = {
+	.hw_params = wm8961_hw_params,
+	.set_sysclk = wm8961_set_sysclk,
+	.set_fmt = wm8961_set_fmt,
+	.digital_mute = wm8961_digital_mute,
+	.set_tristate = wm8961_set_tristate,
+	.set_clkdiv = wm8961_set_clkdiv,
+};
+
+static struct snd_soc_dai_driver wm8961_dai = {
+	.name = "wm8961-hifi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8961_RATES,
+		.formats = WM8961_FORMATS,},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8961_RATES,
+		.formats = WM8961_FORMATS,},
+	.ops = &wm8961_dai_ops,
+};
+
+static int wm8961_probe(struct snd_soc_component *component)
+{
+	u16 reg;
+
+	/* Enable class W */
+	reg = snd_soc_component_read32(component, WM8961_CHARGE_PUMP_B);
+	reg |= WM8961_CP_DYN_PWR_MASK;
+	snd_soc_component_write(component, WM8961_CHARGE_PUMP_B, reg);
+
+	/* Latch volume update bits (right channel only, we always
+	 * write both out) and default ZC on. */
+	reg = snd_soc_component_read32(component, WM8961_ROUT1_VOLUME);
+	snd_soc_component_write(component, WM8961_ROUT1_VOLUME,
+		     reg | WM8961_LO1ZC | WM8961_OUT1VU);
+	snd_soc_component_write(component, WM8961_LOUT1_VOLUME, reg | WM8961_LO1ZC);
+	reg = snd_soc_component_read32(component, WM8961_ROUT2_VOLUME);
+	snd_soc_component_write(component, WM8961_ROUT2_VOLUME,
+		     reg | WM8961_SPKRZC | WM8961_SPKVU);
+	snd_soc_component_write(component, WM8961_LOUT2_VOLUME, reg | WM8961_SPKLZC);
+
+	reg = snd_soc_component_read32(component, WM8961_RIGHT_ADC_VOLUME);
+	snd_soc_component_write(component, WM8961_RIGHT_ADC_VOLUME, reg | WM8961_ADCVU);
+	reg = snd_soc_component_read32(component, WM8961_RIGHT_INPUT_VOLUME);
+	snd_soc_component_write(component, WM8961_RIGHT_INPUT_VOLUME, reg | WM8961_IPVU);
+
+	/* Use soft mute by default */
+	reg = snd_soc_component_read32(component, WM8961_ADC_DAC_CONTROL_2);
+	reg |= WM8961_DACSMM;
+	snd_soc_component_write(component, WM8961_ADC_DAC_CONTROL_2, reg);
+
+	/* Use automatic clocking mode by default; for now this is all
+	 * we support.
+	 */
+	reg = snd_soc_component_read32(component, WM8961_CLOCKING_3);
+	reg &= ~WM8961_MANUAL_MODE;
+	snd_soc_component_write(component, WM8961_CLOCKING_3, reg);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int wm8961_resume(struct snd_soc_component *component)
+{
+	snd_soc_component_cache_sync(component);
+
+	return 0;
+}
+#else
+#define wm8961_resume NULL
+#endif
+
+static const struct snd_soc_component_driver soc_component_dev_wm8961 = {
+	.probe			= wm8961_probe,
+	.resume			= wm8961_resume,
+	.set_bias_level		= wm8961_set_bias_level,
+	.controls		= wm8961_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8961_snd_controls),
+	.dapm_widgets		= wm8961_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8961_dapm_widgets),
+	.dapm_routes		= audio_paths,
+	.num_dapm_routes	= ARRAY_SIZE(audio_paths),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8961_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.max_register = WM8961_MAX_REGISTER,
+
+	.reg_defaults = wm8961_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8961_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = wm8961_volatile,
+	.readable_reg = wm8961_readable,
+};
+
+static int wm8961_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8961_priv *wm8961;
+	unsigned int val;
+	int ret;
+
+	wm8961 = devm_kzalloc(&i2c->dev, sizeof(struct wm8961_priv),
+			      GFP_KERNEL);
+	if (wm8961 == NULL)
+		return -ENOMEM;
+
+	wm8961->regmap = devm_regmap_init_i2c(i2c, &wm8961_regmap);
+	if (IS_ERR(wm8961->regmap))
+		return PTR_ERR(wm8961->regmap);
+
+	ret = regmap_read(wm8961->regmap, WM8961_SOFTWARE_RESET, &val);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
+		return ret;
+	}
+
+	if (val != 0x1801) {
+		dev_err(&i2c->dev, "Device is not a WM8961: ID=0x%x\n", val);
+		return -EINVAL;
+	}
+
+	/* This isn't volatile - readback doesn't correspond to write */
+	regcache_cache_bypass(wm8961->regmap, true);
+	ret = regmap_read(wm8961->regmap, WM8961_RIGHT_INPUT_VOLUME, &val);
+	regcache_cache_bypass(wm8961->regmap, false);
+
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to read chip revision: %d\n", ret);
+		return ret;
+	}
+
+	dev_info(&i2c->dev, "WM8961 family %d revision %c\n",
+		 (val & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT,
+		 ((val & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT)
+		 + 'A');
+
+	ret = regmap_write(wm8961->regmap, WM8961_SOFTWARE_RESET, 0x1801);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, wm8961);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8961, &wm8961_dai, 1);
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8961_i2c_id[] = {
+	{ "wm8961", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id);
+
+static struct i2c_driver wm8961_i2c_driver = {
+	.driver = {
+		.name = "wm8961",
+	},
+	.probe =    wm8961_i2c_probe,
+	.id_table = wm8961_i2c_id,
+};
+
+module_i2c_driver(wm8961_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8961 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8961.h b/sound/soc/codecs/wm8961.h
new file mode 100644
index 0000000..1d736e5
--- /dev/null
+++ b/sound/soc/codecs/wm8961.h
@@ -0,0 +1,863 @@
+/*
+ * wm8961.h  --  WM8961 Soc Audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8961_H
+#define _WM8961_H
+
+#include <sound/soc.h>
+
+#define WM8961_BCLK  1
+#define WM8961_LRCLK 2
+
+#define WM8961_BCLK_DIV_1    0
+#define WM8961_BCLK_DIV_1_5  1
+#define WM8961_BCLK_DIV_2    2
+#define WM8961_BCLK_DIV_3    3
+#define WM8961_BCLK_DIV_4    4
+#define WM8961_BCLK_DIV_5_5  5
+#define WM8961_BCLK_DIV_6    6
+#define WM8961_BCLK_DIV_8    7
+#define WM8961_BCLK_DIV_11   8
+#define WM8961_BCLK_DIV_12   9
+#define WM8961_BCLK_DIV_16  10
+#define WM8961_BCLK_DIV_24  11
+#define WM8961_BCLK_DIV_32  13
+
+
+/*
+ * Register values.
+ */
+#define WM8961_LEFT_INPUT_VOLUME                0x00
+#define WM8961_RIGHT_INPUT_VOLUME               0x01
+#define WM8961_LOUT1_VOLUME                     0x02
+#define WM8961_ROUT1_VOLUME                     0x03
+#define WM8961_CLOCKING1                        0x04
+#define WM8961_ADC_DAC_CONTROL_1                0x05
+#define WM8961_ADC_DAC_CONTROL_2                0x06
+#define WM8961_AUDIO_INTERFACE_0                0x07
+#define WM8961_CLOCKING2                        0x08
+#define WM8961_AUDIO_INTERFACE_1                0x09
+#define WM8961_LEFT_DAC_VOLUME                  0x0A
+#define WM8961_RIGHT_DAC_VOLUME                 0x0B
+#define WM8961_AUDIO_INTERFACE_2                0x0E
+#define WM8961_SOFTWARE_RESET                   0x0F
+#define WM8961_ALC1                             0x11
+#define WM8961_ALC2                             0x12
+#define WM8961_ALC3                             0x13
+#define WM8961_NOISE_GATE                       0x14
+#define WM8961_LEFT_ADC_VOLUME                  0x15
+#define WM8961_RIGHT_ADC_VOLUME                 0x16
+#define WM8961_ADDITIONAL_CONTROL_1             0x17
+#define WM8961_ADDITIONAL_CONTROL_2             0x18
+#define WM8961_PWR_MGMT_1                       0x19
+#define WM8961_PWR_MGMT_2                       0x1A
+#define WM8961_ADDITIONAL_CONTROL_3             0x1B
+#define WM8961_ANTI_POP                         0x1C
+#define WM8961_CLOCKING_3                       0x1E
+#define WM8961_ADCL_SIGNAL_PATH                 0x20
+#define WM8961_ADCR_SIGNAL_PATH                 0x21
+#define WM8961_LOUT2_VOLUME                     0x28
+#define WM8961_ROUT2_VOLUME                     0x29
+#define WM8961_PWR_MGMT_3                       0x2F
+#define WM8961_ADDITIONAL_CONTROL_4             0x30
+#define WM8961_CLASS_D_CONTROL_1                0x31
+#define WM8961_CLASS_D_CONTROL_2                0x33
+#define WM8961_CLOCKING_4                       0x38
+#define WM8961_DSP_SIDETONE_0                   0x39
+#define WM8961_DSP_SIDETONE_1                   0x3A
+#define WM8961_DC_SERVO_0                       0x3C
+#define WM8961_DC_SERVO_1                       0x3D
+#define WM8961_DC_SERVO_3                       0x3F
+#define WM8961_DC_SERVO_5                       0x41
+#define WM8961_ANALOGUE_PGA_BIAS                0x44
+#define WM8961_ANALOGUE_HP_0                    0x45
+#define WM8961_ANALOGUE_HP_2                    0x47
+#define WM8961_CHARGE_PUMP_1                    0x48
+#define WM8961_CHARGE_PUMP_B                    0x52
+#define WM8961_WRITE_SEQUENCER_1                0x57
+#define WM8961_WRITE_SEQUENCER_2                0x58
+#define WM8961_WRITE_SEQUENCER_3                0x59
+#define WM8961_WRITE_SEQUENCER_4                0x5A
+#define WM8961_WRITE_SEQUENCER_5                0x5B
+#define WM8961_WRITE_SEQUENCER_6                0x5C
+#define WM8961_WRITE_SEQUENCER_7                0x5D
+#define WM8961_GENERAL_TEST_1                   0xFC
+
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Left Input volume
+ */
+#define WM8961_IPVU                             0x0100  /* IPVU */
+#define WM8961_IPVU_MASK                        0x0100  /* IPVU */
+#define WM8961_IPVU_SHIFT                            8  /* IPVU */
+#define WM8961_IPVU_WIDTH                            1  /* IPVU */
+#define WM8961_LINMUTE                          0x0080  /* LINMUTE */
+#define WM8961_LINMUTE_MASK                     0x0080  /* LINMUTE */
+#define WM8961_LINMUTE_SHIFT                         7  /* LINMUTE */
+#define WM8961_LINMUTE_WIDTH                         1  /* LINMUTE */
+#define WM8961_LIZC                             0x0040  /* LIZC */
+#define WM8961_LIZC_MASK                        0x0040  /* LIZC */
+#define WM8961_LIZC_SHIFT                            6  /* LIZC */
+#define WM8961_LIZC_WIDTH                            1  /* LIZC */
+#define WM8961_LINVOL_MASK                      0x003F  /* LINVOL - [5:0] */
+#define WM8961_LINVOL_SHIFT                          0  /* LINVOL - [5:0] */
+#define WM8961_LINVOL_WIDTH                          6  /* LINVOL - [5:0] */
+
+/*
+ * R1 (0x01) - Right Input volume
+ */
+#define WM8961_DEVICE_ID_MASK                   0xF000  /* DEVICE_ID - [15:12] */
+#define WM8961_DEVICE_ID_SHIFT                      12  /* DEVICE_ID - [15:12] */
+#define WM8961_DEVICE_ID_WIDTH                       4  /* DEVICE_ID - [15:12] */
+#define WM8961_CHIP_REV_MASK                    0x0E00  /* CHIP_REV - [11:9] */
+#define WM8961_CHIP_REV_SHIFT                        9  /* CHIP_REV - [11:9] */
+#define WM8961_CHIP_REV_WIDTH                        3  /* CHIP_REV - [11:9] */
+#define WM8961_IPVU                             0x0100  /* IPVU */
+#define WM8961_IPVU_MASK                        0x0100  /* IPVU */
+#define WM8961_IPVU_SHIFT                            8  /* IPVU */
+#define WM8961_IPVU_WIDTH                            1  /* IPVU */
+#define WM8961_RINMUTE                          0x0080  /* RINMUTE */
+#define WM8961_RINMUTE_MASK                     0x0080  /* RINMUTE */
+#define WM8961_RINMUTE_SHIFT                         7  /* RINMUTE */
+#define WM8961_RINMUTE_WIDTH                         1  /* RINMUTE */
+#define WM8961_RIZC                             0x0040  /* RIZC */
+#define WM8961_RIZC_MASK                        0x0040  /* RIZC */
+#define WM8961_RIZC_SHIFT                            6  /* RIZC */
+#define WM8961_RIZC_WIDTH                            1  /* RIZC */
+#define WM8961_RINVOL_MASK                      0x003F  /* RINVOL - [5:0] */
+#define WM8961_RINVOL_SHIFT                          0  /* RINVOL - [5:0] */
+#define WM8961_RINVOL_WIDTH                          6  /* RINVOL - [5:0] */
+
+/*
+ * R2 (0x02) - LOUT1 volume
+ */
+#define WM8961_OUT1VU                           0x0100  /* OUT1VU */
+#define WM8961_OUT1VU_MASK                      0x0100  /* OUT1VU */
+#define WM8961_OUT1VU_SHIFT                          8  /* OUT1VU */
+#define WM8961_OUT1VU_WIDTH                          1  /* OUT1VU */
+#define WM8961_LO1ZC                            0x0080  /* LO1ZC */
+#define WM8961_LO1ZC_MASK                       0x0080  /* LO1ZC */
+#define WM8961_LO1ZC_SHIFT                           7  /* LO1ZC */
+#define WM8961_LO1ZC_WIDTH                           1  /* LO1ZC */
+#define WM8961_LOUT1VOL_MASK                    0x007F  /* LOUT1VOL - [6:0] */
+#define WM8961_LOUT1VOL_SHIFT                        0  /* LOUT1VOL - [6:0] */
+#define WM8961_LOUT1VOL_WIDTH                        7  /* LOUT1VOL - [6:0] */
+
+/*
+ * R3 (0x03) - ROUT1 volume
+ */
+#define WM8961_OUT1VU                           0x0100  /* OUT1VU */
+#define WM8961_OUT1VU_MASK                      0x0100  /* OUT1VU */
+#define WM8961_OUT1VU_SHIFT                          8  /* OUT1VU */
+#define WM8961_OUT1VU_WIDTH                          1  /* OUT1VU */
+#define WM8961_RO1ZC                            0x0080  /* RO1ZC */
+#define WM8961_RO1ZC_MASK                       0x0080  /* RO1ZC */
+#define WM8961_RO1ZC_SHIFT                           7  /* RO1ZC */
+#define WM8961_RO1ZC_WIDTH                           1  /* RO1ZC */
+#define WM8961_ROUT1VOL_MASK                    0x007F  /* ROUT1VOL - [6:0] */
+#define WM8961_ROUT1VOL_SHIFT                        0  /* ROUT1VOL - [6:0] */
+#define WM8961_ROUT1VOL_WIDTH                        7  /* ROUT1VOL - [6:0] */
+
+/*
+ * R4 (0x04) - Clocking1
+ */
+#define WM8961_ADCDIV_MASK                      0x01C0  /* ADCDIV - [8:6] */
+#define WM8961_ADCDIV_SHIFT                          6  /* ADCDIV - [8:6] */
+#define WM8961_ADCDIV_WIDTH                          3  /* ADCDIV - [8:6] */
+#define WM8961_DACDIV_MASK                      0x0038  /* DACDIV - [5:3] */
+#define WM8961_DACDIV_SHIFT                          3  /* DACDIV - [5:3] */
+#define WM8961_DACDIV_WIDTH                          3  /* DACDIV - [5:3] */
+#define WM8961_MCLKDIV                          0x0004  /* MCLKDIV */
+#define WM8961_MCLKDIV_MASK                     0x0004  /* MCLKDIV */
+#define WM8961_MCLKDIV_SHIFT                         2  /* MCLKDIV */
+#define WM8961_MCLKDIV_WIDTH                         1  /* MCLKDIV */
+
+/*
+ * R5 (0x05) - ADC & DAC Control 1
+ */
+#define WM8961_ADCPOL_MASK                      0x0060  /* ADCPOL - [6:5] */
+#define WM8961_ADCPOL_SHIFT                          5  /* ADCPOL - [6:5] */
+#define WM8961_ADCPOL_WIDTH                          2  /* ADCPOL - [6:5] */
+#define WM8961_DACMU                            0x0008  /* DACMU */
+#define WM8961_DACMU_MASK                       0x0008  /* DACMU */
+#define WM8961_DACMU_SHIFT                           3  /* DACMU */
+#define WM8961_DACMU_WIDTH                           1  /* DACMU */
+#define WM8961_DEEMPH_MASK                      0x0006  /* DEEMPH - [2:1] */
+#define WM8961_DEEMPH_SHIFT                          1  /* DEEMPH - [2:1] */
+#define WM8961_DEEMPH_WIDTH                          2  /* DEEMPH - [2:1] */
+#define WM8961_ADCHPD                           0x0001  /* ADCHPD */
+#define WM8961_ADCHPD_MASK                      0x0001  /* ADCHPD */
+#define WM8961_ADCHPD_SHIFT                          0  /* ADCHPD */
+#define WM8961_ADCHPD_WIDTH                          1  /* ADCHPD */
+
+/*
+ * R6 (0x06) - ADC & DAC Control 2
+ */
+#define WM8961_ADC_HPF_CUT_MASK                 0x0180  /* ADC_HPF_CUT - [8:7] */
+#define WM8961_ADC_HPF_CUT_SHIFT                     7  /* ADC_HPF_CUT - [8:7] */
+#define WM8961_ADC_HPF_CUT_WIDTH                     2  /* ADC_HPF_CUT - [8:7] */
+#define WM8961_DACPOL_MASK                      0x0060  /* DACPOL - [6:5] */
+#define WM8961_DACPOL_SHIFT                          5  /* DACPOL - [6:5] */
+#define WM8961_DACPOL_WIDTH                          2  /* DACPOL - [6:5] */
+#define WM8961_DACSMM                           0x0008  /* DACSMM */
+#define WM8961_DACSMM_MASK                      0x0008  /* DACSMM */
+#define WM8961_DACSMM_SHIFT                          3  /* DACSMM */
+#define WM8961_DACSMM_WIDTH                          1  /* DACSMM */
+#define WM8961_DACMR                            0x0004  /* DACMR */
+#define WM8961_DACMR_MASK                       0x0004  /* DACMR */
+#define WM8961_DACMR_SHIFT                           2  /* DACMR */
+#define WM8961_DACMR_WIDTH                           1  /* DACMR */
+#define WM8961_DACSLOPE                         0x0002  /* DACSLOPE */
+#define WM8961_DACSLOPE_MASK                    0x0002  /* DACSLOPE */
+#define WM8961_DACSLOPE_SHIFT                        1  /* DACSLOPE */
+#define WM8961_DACSLOPE_WIDTH                        1  /* DACSLOPE */
+#define WM8961_DAC_OSR128                       0x0001  /* DAC_OSR128 */
+#define WM8961_DAC_OSR128_MASK                  0x0001  /* DAC_OSR128 */
+#define WM8961_DAC_OSR128_SHIFT                      0  /* DAC_OSR128 */
+#define WM8961_DAC_OSR128_WIDTH                      1  /* DAC_OSR128 */
+
+/*
+ * R7 (0x07) - Audio Interface 0
+ */
+#define WM8961_ALRSWAP                          0x0100  /* ALRSWAP */
+#define WM8961_ALRSWAP_MASK                     0x0100  /* ALRSWAP */
+#define WM8961_ALRSWAP_SHIFT                         8  /* ALRSWAP */
+#define WM8961_ALRSWAP_WIDTH                         1  /* ALRSWAP */
+#define WM8961_BCLKINV                          0x0080  /* BCLKINV */
+#define WM8961_BCLKINV_MASK                     0x0080  /* BCLKINV */
+#define WM8961_BCLKINV_SHIFT                         7  /* BCLKINV */
+#define WM8961_BCLKINV_WIDTH                         1  /* BCLKINV */
+#define WM8961_MS                               0x0040  /* MS */
+#define WM8961_MS_MASK                          0x0040  /* MS */
+#define WM8961_MS_SHIFT                              6  /* MS */
+#define WM8961_MS_WIDTH                              1  /* MS */
+#define WM8961_DLRSWAP                          0x0020  /* DLRSWAP */
+#define WM8961_DLRSWAP_MASK                     0x0020  /* DLRSWAP */
+#define WM8961_DLRSWAP_SHIFT                         5  /* DLRSWAP */
+#define WM8961_DLRSWAP_WIDTH                         1  /* DLRSWAP */
+#define WM8961_LRP                              0x0010  /* LRP */
+#define WM8961_LRP_MASK                         0x0010  /* LRP */
+#define WM8961_LRP_SHIFT                             4  /* LRP */
+#define WM8961_LRP_WIDTH                             1  /* LRP */
+#define WM8961_WL_MASK                          0x000C  /* WL - [3:2] */
+#define WM8961_WL_SHIFT                              2  /* WL - [3:2] */
+#define WM8961_WL_WIDTH                              2  /* WL - [3:2] */
+#define WM8961_FORMAT_MASK                      0x0003  /* FORMAT - [1:0] */
+#define WM8961_FORMAT_SHIFT                          0  /* FORMAT - [1:0] */
+#define WM8961_FORMAT_WIDTH                          2  /* FORMAT - [1:0] */
+
+/*
+ * R8 (0x08) - Clocking2
+ */
+#define WM8961_DCLKDIV_MASK                     0x01C0  /* DCLKDIV - [8:6] */
+#define WM8961_DCLKDIV_SHIFT                         6  /* DCLKDIV - [8:6] */
+#define WM8961_DCLKDIV_WIDTH                         3  /* DCLKDIV - [8:6] */
+#define WM8961_CLK_SYS_ENA                      0x0020  /* CLK_SYS_ENA */
+#define WM8961_CLK_SYS_ENA_MASK                 0x0020  /* CLK_SYS_ENA */
+#define WM8961_CLK_SYS_ENA_SHIFT                     5  /* CLK_SYS_ENA */
+#define WM8961_CLK_SYS_ENA_WIDTH                     1  /* CLK_SYS_ENA */
+#define WM8961_CLK_DSP_ENA                      0x0010  /* CLK_DSP_ENA */
+#define WM8961_CLK_DSP_ENA_MASK                 0x0010  /* CLK_DSP_ENA */
+#define WM8961_CLK_DSP_ENA_SHIFT                     4  /* CLK_DSP_ENA */
+#define WM8961_CLK_DSP_ENA_WIDTH                     1  /* CLK_DSP_ENA */
+#define WM8961_BCLKDIV_MASK                     0x000F  /* BCLKDIV - [3:0] */
+#define WM8961_BCLKDIV_SHIFT                         0  /* BCLKDIV - [3:0] */
+#define WM8961_BCLKDIV_WIDTH                         4  /* BCLKDIV - [3:0] */
+
+/*
+ * R9 (0x09) - Audio Interface 1
+ */
+#define WM8961_DACCOMP_MASK                     0x0018  /* DACCOMP - [4:3] */
+#define WM8961_DACCOMP_SHIFT                         3  /* DACCOMP - [4:3] */
+#define WM8961_DACCOMP_WIDTH                         2  /* DACCOMP - [4:3] */
+#define WM8961_ADCCOMP_MASK                     0x0006  /* ADCCOMP - [2:1] */
+#define WM8961_ADCCOMP_SHIFT                         1  /* ADCCOMP - [2:1] */
+#define WM8961_ADCCOMP_WIDTH                         2  /* ADCCOMP - [2:1] */
+#define WM8961_LOOPBACK                         0x0001  /* LOOPBACK */
+#define WM8961_LOOPBACK_MASK                    0x0001  /* LOOPBACK */
+#define WM8961_LOOPBACK_SHIFT                        0  /* LOOPBACK */
+#define WM8961_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+
+/*
+ * R10 (0x0A) - Left DAC volume
+ */
+#define WM8961_DACVU                            0x0100  /* DACVU */
+#define WM8961_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8961_DACVU_SHIFT                           8  /* DACVU */
+#define WM8961_DACVU_WIDTH                           1  /* DACVU */
+#define WM8961_LDACVOL_MASK                     0x00FF  /* LDACVOL - [7:0] */
+#define WM8961_LDACVOL_SHIFT                         0  /* LDACVOL - [7:0] */
+#define WM8961_LDACVOL_WIDTH                         8  /* LDACVOL - [7:0] */
+
+/*
+ * R11 (0x0B) - Right DAC volume
+ */
+#define WM8961_DACVU                            0x0100  /* DACVU */
+#define WM8961_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8961_DACVU_SHIFT                           8  /* DACVU */
+#define WM8961_DACVU_WIDTH                           1  /* DACVU */
+#define WM8961_RDACVOL_MASK                     0x00FF  /* RDACVOL - [7:0] */
+#define WM8961_RDACVOL_SHIFT                         0  /* RDACVOL - [7:0] */
+#define WM8961_RDACVOL_WIDTH                         8  /* RDACVOL - [7:0] */
+
+/*
+ * R14 (0x0E) - Audio Interface 2
+ */
+#define WM8961_LRCLK_RATE_MASK                  0x01FF  /* LRCLK_RATE - [8:0] */
+#define WM8961_LRCLK_RATE_SHIFT                      0  /* LRCLK_RATE - [8:0] */
+#define WM8961_LRCLK_RATE_WIDTH                      9  /* LRCLK_RATE - [8:0] */
+
+/*
+ * R15 (0x0F) - Software Reset
+ */
+#define WM8961_SW_RST_DEV_ID1_MASK              0xFFFF  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM8961_SW_RST_DEV_ID1_SHIFT                  0  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM8961_SW_RST_DEV_ID1_WIDTH                 16  /* SW_RST_DEV_ID1 - [15:0] */
+
+/*
+ * R17 (0x11) - ALC1
+ */
+#define WM8961_ALCSEL_MASK                      0x0180  /* ALCSEL - [8:7] */
+#define WM8961_ALCSEL_SHIFT                          7  /* ALCSEL - [8:7] */
+#define WM8961_ALCSEL_WIDTH                          2  /* ALCSEL - [8:7] */
+#define WM8961_MAXGAIN_MASK                     0x0070  /* MAXGAIN - [6:4] */
+#define WM8961_MAXGAIN_SHIFT                         4  /* MAXGAIN - [6:4] */
+#define WM8961_MAXGAIN_WIDTH                         3  /* MAXGAIN - [6:4] */
+#define WM8961_ALCL_MASK                        0x000F  /* ALCL - [3:0] */
+#define WM8961_ALCL_SHIFT                            0  /* ALCL - [3:0] */
+#define WM8961_ALCL_WIDTH                            4  /* ALCL - [3:0] */
+
+/*
+ * R18 (0x12) - ALC2
+ */
+#define WM8961_ALCZC                            0x0080  /* ALCZC */
+#define WM8961_ALCZC_MASK                       0x0080  /* ALCZC */
+#define WM8961_ALCZC_SHIFT                           7  /* ALCZC */
+#define WM8961_ALCZC_WIDTH                           1  /* ALCZC */
+#define WM8961_MINGAIN_MASK                     0x0070  /* MINGAIN - [6:4] */
+#define WM8961_MINGAIN_SHIFT                         4  /* MINGAIN - [6:4] */
+#define WM8961_MINGAIN_WIDTH                         3  /* MINGAIN - [6:4] */
+#define WM8961_HLD_MASK                         0x000F  /* HLD - [3:0] */
+#define WM8961_HLD_SHIFT                             0  /* HLD - [3:0] */
+#define WM8961_HLD_WIDTH                             4  /* HLD - [3:0] */
+
+/*
+ * R19 (0x13) - ALC3
+ */
+#define WM8961_ALCMODE                          0x0100  /* ALCMODE */
+#define WM8961_ALCMODE_MASK                     0x0100  /* ALCMODE */
+#define WM8961_ALCMODE_SHIFT                         8  /* ALCMODE */
+#define WM8961_ALCMODE_WIDTH                         1  /* ALCMODE */
+#define WM8961_DCY_MASK                         0x00F0  /* DCY - [7:4] */
+#define WM8961_DCY_SHIFT                             4  /* DCY - [7:4] */
+#define WM8961_DCY_WIDTH                             4  /* DCY - [7:4] */
+#define WM8961_ATK_MASK                         0x000F  /* ATK - [3:0] */
+#define WM8961_ATK_SHIFT                             0  /* ATK - [3:0] */
+#define WM8961_ATK_WIDTH                             4  /* ATK - [3:0] */
+
+/*
+ * R20 (0x14) - Noise Gate
+ */
+#define WM8961_NGTH_MASK                        0x00F8  /* NGTH - [7:3] */
+#define WM8961_NGTH_SHIFT                            3  /* NGTH - [7:3] */
+#define WM8961_NGTH_WIDTH                            5  /* NGTH - [7:3] */
+#define WM8961_NGG                              0x0002  /* NGG */
+#define WM8961_NGG_MASK                         0x0002  /* NGG */
+#define WM8961_NGG_SHIFT                             1  /* NGG */
+#define WM8961_NGG_WIDTH                             1  /* NGG */
+#define WM8961_NGAT                             0x0001  /* NGAT */
+#define WM8961_NGAT_MASK                        0x0001  /* NGAT */
+#define WM8961_NGAT_SHIFT                            0  /* NGAT */
+#define WM8961_NGAT_WIDTH                            1  /* NGAT */
+
+/*
+ * R21 (0x15) - Left ADC volume
+ */
+#define WM8961_ADCVU                            0x0100  /* ADCVU */
+#define WM8961_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8961_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8961_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8961_LADCVOL_MASK                     0x00FF  /* LADCVOL - [7:0] */
+#define WM8961_LADCVOL_SHIFT                         0  /* LADCVOL - [7:0] */
+#define WM8961_LADCVOL_WIDTH                         8  /* LADCVOL - [7:0] */
+
+/*
+ * R22 (0x16) - Right ADC volume
+ */
+#define WM8961_ADCVU                            0x0100  /* ADCVU */
+#define WM8961_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8961_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8961_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8961_RADCVOL_MASK                     0x00FF  /* RADCVOL - [7:0] */
+#define WM8961_RADCVOL_SHIFT                         0  /* RADCVOL - [7:0] */
+#define WM8961_RADCVOL_WIDTH                         8  /* RADCVOL - [7:0] */
+
+/*
+ * R23 (0x17) - Additional control(1)
+ */
+#define WM8961_TSDEN                            0x0100  /* TSDEN */
+#define WM8961_TSDEN_MASK                       0x0100  /* TSDEN */
+#define WM8961_TSDEN_SHIFT                           8  /* TSDEN */
+#define WM8961_TSDEN_WIDTH                           1  /* TSDEN */
+#define WM8961_DMONOMIX                         0x0010  /* DMONOMIX */
+#define WM8961_DMONOMIX_MASK                    0x0010  /* DMONOMIX */
+#define WM8961_DMONOMIX_SHIFT                        4  /* DMONOMIX */
+#define WM8961_DMONOMIX_WIDTH                        1  /* DMONOMIX */
+#define WM8961_TOEN                             0x0001  /* TOEN */
+#define WM8961_TOEN_MASK                        0x0001  /* TOEN */
+#define WM8961_TOEN_SHIFT                            0  /* TOEN */
+#define WM8961_TOEN_WIDTH                            1  /* TOEN */
+
+/*
+ * R24 (0x18) - Additional control(2)
+ */
+#define WM8961_TRIS                             0x0008  /* TRIS */
+#define WM8961_TRIS_MASK                        0x0008  /* TRIS */
+#define WM8961_TRIS_SHIFT                            3  /* TRIS */
+#define WM8961_TRIS_WIDTH                            1  /* TRIS */
+
+/*
+ * R25 (0x19) - Pwr Mgmt (1)
+ */
+#define WM8961_VMIDSEL_MASK                     0x0180  /* VMIDSEL - [8:7] */
+#define WM8961_VMIDSEL_SHIFT                         7  /* VMIDSEL - [8:7] */
+#define WM8961_VMIDSEL_WIDTH                         2  /* VMIDSEL - [8:7] */
+#define WM8961_VREF                             0x0040  /* VREF */
+#define WM8961_VREF_MASK                        0x0040  /* VREF */
+#define WM8961_VREF_SHIFT                            6  /* VREF */
+#define WM8961_VREF_WIDTH                            1  /* VREF */
+#define WM8961_AINL                             0x0020  /* AINL */
+#define WM8961_AINL_MASK                        0x0020  /* AINL */
+#define WM8961_AINL_SHIFT                            5  /* AINL */
+#define WM8961_AINL_WIDTH                            1  /* AINL */
+#define WM8961_AINR                             0x0010  /* AINR */
+#define WM8961_AINR_MASK                        0x0010  /* AINR */
+#define WM8961_AINR_SHIFT                            4  /* AINR */
+#define WM8961_AINR_WIDTH                            1  /* AINR */
+#define WM8961_ADCL                             0x0008  /* ADCL */
+#define WM8961_ADCL_MASK                        0x0008  /* ADCL */
+#define WM8961_ADCL_SHIFT                            3  /* ADCL */
+#define WM8961_ADCL_WIDTH                            1  /* ADCL */
+#define WM8961_ADCR                             0x0004  /* ADCR */
+#define WM8961_ADCR_MASK                        0x0004  /* ADCR */
+#define WM8961_ADCR_SHIFT                            2  /* ADCR */
+#define WM8961_ADCR_WIDTH                            1  /* ADCR */
+#define WM8961_MICB                             0x0002  /* MICB */
+#define WM8961_MICB_MASK                        0x0002  /* MICB */
+#define WM8961_MICB_SHIFT                            1  /* MICB */
+#define WM8961_MICB_WIDTH                            1  /* MICB */
+
+/*
+ * R26 (0x1A) - Pwr Mgmt (2)
+ */
+#define WM8961_DACL                             0x0100  /* DACL */
+#define WM8961_DACL_MASK                        0x0100  /* DACL */
+#define WM8961_DACL_SHIFT                            8  /* DACL */
+#define WM8961_DACL_WIDTH                            1  /* DACL */
+#define WM8961_DACR                             0x0080  /* DACR */
+#define WM8961_DACR_MASK                        0x0080  /* DACR */
+#define WM8961_DACR_SHIFT                            7  /* DACR */
+#define WM8961_DACR_WIDTH                            1  /* DACR */
+#define WM8961_LOUT1_PGA                        0x0040  /* LOUT1_PGA */
+#define WM8961_LOUT1_PGA_MASK                   0x0040  /* LOUT1_PGA */
+#define WM8961_LOUT1_PGA_SHIFT                       6  /* LOUT1_PGA */
+#define WM8961_LOUT1_PGA_WIDTH                       1  /* LOUT1_PGA */
+#define WM8961_ROUT1_PGA                        0x0020  /* ROUT1_PGA */
+#define WM8961_ROUT1_PGA_MASK                   0x0020  /* ROUT1_PGA */
+#define WM8961_ROUT1_PGA_SHIFT                       5  /* ROUT1_PGA */
+#define WM8961_ROUT1_PGA_WIDTH                       1  /* ROUT1_PGA */
+#define WM8961_SPKL_PGA                         0x0010  /* SPKL_PGA */
+#define WM8961_SPKL_PGA_MASK                    0x0010  /* SPKL_PGA */
+#define WM8961_SPKL_PGA_SHIFT                        4  /* SPKL_PGA */
+#define WM8961_SPKL_PGA_WIDTH                        1  /* SPKL_PGA */
+#define WM8961_SPKR_PGA                         0x0008  /* SPKR_PGA */
+#define WM8961_SPKR_PGA_MASK                    0x0008  /* SPKR_PGA */
+#define WM8961_SPKR_PGA_SHIFT                        3  /* SPKR_PGA */
+#define WM8961_SPKR_PGA_WIDTH                        1  /* SPKR_PGA */
+
+/*
+ * R27 (0x1B) - Additional Control (3)
+ */
+#define WM8961_SAMPLE_RATE_MASK                 0x0007  /* SAMPLE_RATE - [2:0] */
+#define WM8961_SAMPLE_RATE_SHIFT                     0  /* SAMPLE_RATE - [2:0] */
+#define WM8961_SAMPLE_RATE_WIDTH                     3  /* SAMPLE_RATE - [2:0] */
+
+/*
+ * R28 (0x1C) - Anti-pop
+ */
+#define WM8961_BUFDCOPEN                        0x0010  /* BUFDCOPEN */
+#define WM8961_BUFDCOPEN_MASK                   0x0010  /* BUFDCOPEN */
+#define WM8961_BUFDCOPEN_SHIFT                       4  /* BUFDCOPEN */
+#define WM8961_BUFDCOPEN_WIDTH                       1  /* BUFDCOPEN */
+#define WM8961_BUFIOEN                          0x0008  /* BUFIOEN */
+#define WM8961_BUFIOEN_MASK                     0x0008  /* BUFIOEN */
+#define WM8961_BUFIOEN_SHIFT                         3  /* BUFIOEN */
+#define WM8961_BUFIOEN_WIDTH                         1  /* BUFIOEN */
+#define WM8961_SOFT_ST                          0x0004  /* SOFT_ST */
+#define WM8961_SOFT_ST_MASK                     0x0004  /* SOFT_ST */
+#define WM8961_SOFT_ST_SHIFT                         2  /* SOFT_ST */
+#define WM8961_SOFT_ST_WIDTH                         1  /* SOFT_ST */
+
+/*
+ * R30 (0x1E) - Clocking 3
+ */
+#define WM8961_CLK_TO_DIV_MASK                  0x0180  /* CLK_TO_DIV - [8:7] */
+#define WM8961_CLK_TO_DIV_SHIFT                      7  /* CLK_TO_DIV - [8:7] */
+#define WM8961_CLK_TO_DIV_WIDTH                      2  /* CLK_TO_DIV - [8:7] */
+#define WM8961_CLK_256K_DIV_MASK                0x007E  /* CLK_256K_DIV - [6:1] */
+#define WM8961_CLK_256K_DIV_SHIFT                    1  /* CLK_256K_DIV - [6:1] */
+#define WM8961_CLK_256K_DIV_WIDTH                    6  /* CLK_256K_DIV - [6:1] */
+#define WM8961_MANUAL_MODE                      0x0001  /* MANUAL_MODE */
+#define WM8961_MANUAL_MODE_MASK                 0x0001  /* MANUAL_MODE */
+#define WM8961_MANUAL_MODE_SHIFT                     0  /* MANUAL_MODE */
+#define WM8961_MANUAL_MODE_WIDTH                     1  /* MANUAL_MODE */
+
+/*
+ * R32 (0x20) - ADCL signal path
+ */
+#define WM8961_LMICBOOST_MASK                   0x0030  /* LMICBOOST - [5:4] */
+#define WM8961_LMICBOOST_SHIFT                       4  /* LMICBOOST - [5:4] */
+#define WM8961_LMICBOOST_WIDTH                       2  /* LMICBOOST - [5:4] */
+
+/*
+ * R33 (0x21) - ADCR signal path
+ */
+#define WM8961_RMICBOOST_MASK                   0x0030  /* RMICBOOST - [5:4] */
+#define WM8961_RMICBOOST_SHIFT                       4  /* RMICBOOST - [5:4] */
+#define WM8961_RMICBOOST_WIDTH                       2  /* RMICBOOST - [5:4] */
+
+/*
+ * R40 (0x28) - LOUT2 volume
+ */
+#define WM8961_SPKVU                            0x0100  /* SPKVU */
+#define WM8961_SPKVU_MASK                       0x0100  /* SPKVU */
+#define WM8961_SPKVU_SHIFT                           8  /* SPKVU */
+#define WM8961_SPKVU_WIDTH                           1  /* SPKVU */
+#define WM8961_SPKLZC                           0x0080  /* SPKLZC */
+#define WM8961_SPKLZC_MASK                      0x0080  /* SPKLZC */
+#define WM8961_SPKLZC_SHIFT                          7  /* SPKLZC */
+#define WM8961_SPKLZC_WIDTH                          1  /* SPKLZC */
+#define WM8961_SPKLVOL_MASK                     0x007F  /* SPKLVOL - [6:0] */
+#define WM8961_SPKLVOL_SHIFT                         0  /* SPKLVOL - [6:0] */
+#define WM8961_SPKLVOL_WIDTH                         7  /* SPKLVOL - [6:0] */
+
+/*
+ * R41 (0x29) - ROUT2 volume
+ */
+#define WM8961_SPKVU                            0x0100  /* SPKVU */
+#define WM8961_SPKVU_MASK                       0x0100  /* SPKVU */
+#define WM8961_SPKVU_SHIFT                           8  /* SPKVU */
+#define WM8961_SPKVU_WIDTH                           1  /* SPKVU */
+#define WM8961_SPKRZC                           0x0080  /* SPKRZC */
+#define WM8961_SPKRZC_MASK                      0x0080  /* SPKRZC */
+#define WM8961_SPKRZC_SHIFT                          7  /* SPKRZC */
+#define WM8961_SPKRZC_WIDTH                          1  /* SPKRZC */
+#define WM8961_SPKRVOL_MASK                     0x007F  /* SPKRVOL - [6:0] */
+#define WM8961_SPKRVOL_SHIFT                         0  /* SPKRVOL - [6:0] */
+#define WM8961_SPKRVOL_WIDTH                         7  /* SPKRVOL - [6:0] */
+
+/*
+ * R47 (0x2F) - Pwr Mgmt (3)
+ */
+#define WM8961_TEMP_SHUT                        0x0002  /* TEMP_SHUT */
+#define WM8961_TEMP_SHUT_MASK                   0x0002  /* TEMP_SHUT */
+#define WM8961_TEMP_SHUT_SHIFT                       1  /* TEMP_SHUT */
+#define WM8961_TEMP_SHUT_WIDTH                       1  /* TEMP_SHUT */
+#define WM8961_TEMP_WARN                        0x0001  /* TEMP_WARN */
+#define WM8961_TEMP_WARN_MASK                   0x0001  /* TEMP_WARN */
+#define WM8961_TEMP_WARN_SHIFT                       0  /* TEMP_WARN */
+#define WM8961_TEMP_WARN_WIDTH                       1  /* TEMP_WARN */
+
+/*
+ * R48 (0x30) - Additional Control (4)
+ */
+#define WM8961_TSENSEN                          0x0002  /* TSENSEN */
+#define WM8961_TSENSEN_MASK                     0x0002  /* TSENSEN */
+#define WM8961_TSENSEN_SHIFT                         1  /* TSENSEN */
+#define WM8961_TSENSEN_WIDTH                         1  /* TSENSEN */
+#define WM8961_MBSEL                            0x0001  /* MBSEL */
+#define WM8961_MBSEL_MASK                       0x0001  /* MBSEL */
+#define WM8961_MBSEL_SHIFT                           0  /* MBSEL */
+#define WM8961_MBSEL_WIDTH                           1  /* MBSEL */
+
+/*
+ * R49 (0x31) - Class D Control 1
+ */
+#define WM8961_SPKR_ENA                         0x0080  /* SPKR_ENA */
+#define WM8961_SPKR_ENA_MASK                    0x0080  /* SPKR_ENA */
+#define WM8961_SPKR_ENA_SHIFT                        7  /* SPKR_ENA */
+#define WM8961_SPKR_ENA_WIDTH                        1  /* SPKR_ENA */
+#define WM8961_SPKL_ENA                         0x0040  /* SPKL_ENA */
+#define WM8961_SPKL_ENA_MASK                    0x0040  /* SPKL_ENA */
+#define WM8961_SPKL_ENA_SHIFT                        6  /* SPKL_ENA */
+#define WM8961_SPKL_ENA_WIDTH                        1  /* SPKL_ENA */
+
+/*
+ * R51 (0x33) - Class D Control 2
+ */
+#define WM8961_CLASSD_ACGAIN_MASK               0x0007  /* CLASSD_ACGAIN - [2:0] */
+#define WM8961_CLASSD_ACGAIN_SHIFT                   0  /* CLASSD_ACGAIN - [2:0] */
+#define WM8961_CLASSD_ACGAIN_WIDTH                   3  /* CLASSD_ACGAIN - [2:0] */
+
+/*
+ * R56 (0x38) - Clocking 4
+ */
+#define WM8961_CLK_DCS_DIV_MASK                 0x01E0  /* CLK_DCS_DIV - [8:5] */
+#define WM8961_CLK_DCS_DIV_SHIFT                     5  /* CLK_DCS_DIV - [8:5] */
+#define WM8961_CLK_DCS_DIV_WIDTH                     4  /* CLK_DCS_DIV - [8:5] */
+#define WM8961_CLK_SYS_RATE_MASK                0x001E  /* CLK_SYS_RATE - [4:1] */
+#define WM8961_CLK_SYS_RATE_SHIFT                    1  /* CLK_SYS_RATE - [4:1] */
+#define WM8961_CLK_SYS_RATE_WIDTH                    4  /* CLK_SYS_RATE - [4:1] */
+
+/*
+ * R57 (0x39) - DSP Sidetone 0
+ */
+#define WM8961_ADCR_DAC_SVOL_MASK               0x00F0  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8961_ADCR_DAC_SVOL_SHIFT                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8961_ADCR_DAC_SVOL_WIDTH                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8961_ADC_TO_DACR_MASK                 0x000C  /* ADC_TO_DACR - [3:2] */
+#define WM8961_ADC_TO_DACR_SHIFT                     2  /* ADC_TO_DACR - [3:2] */
+#define WM8961_ADC_TO_DACR_WIDTH                     2  /* ADC_TO_DACR - [3:2] */
+
+/*
+ * R58 (0x3A) - DSP Sidetone 1
+ */
+#define WM8961_ADCL_DAC_SVOL_MASK               0x00F0  /* ADCL_DAC_SVOL - [7:4] */
+#define WM8961_ADCL_DAC_SVOL_SHIFT                   4  /* ADCL_DAC_SVOL - [7:4] */
+#define WM8961_ADCL_DAC_SVOL_WIDTH                   4  /* ADCL_DAC_SVOL - [7:4] */
+#define WM8961_ADC_TO_DACL_MASK                 0x000C  /* ADC_TO_DACL - [3:2] */
+#define WM8961_ADC_TO_DACL_SHIFT                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8961_ADC_TO_DACL_WIDTH                     2  /* ADC_TO_DACL - [3:2] */
+
+/*
+ * R60 (0x3C) - DC Servo 0
+ */
+#define WM8961_DCS_ENA_CHAN_INL                 0x0080  /* DCS_ENA_CHAN_INL */
+#define WM8961_DCS_ENA_CHAN_INL_MASK            0x0080  /* DCS_ENA_CHAN_INL */
+#define WM8961_DCS_ENA_CHAN_INL_SHIFT                7  /* DCS_ENA_CHAN_INL */
+#define WM8961_DCS_ENA_CHAN_INL_WIDTH                1  /* DCS_ENA_CHAN_INL */
+#define WM8961_DCS_TRIG_STARTUP_INL             0x0040  /* DCS_TRIG_STARTUP_INL */
+#define WM8961_DCS_TRIG_STARTUP_INL_MASK        0x0040  /* DCS_TRIG_STARTUP_INL */
+#define WM8961_DCS_TRIG_STARTUP_INL_SHIFT            6  /* DCS_TRIG_STARTUP_INL */
+#define WM8961_DCS_TRIG_STARTUP_INL_WIDTH            1  /* DCS_TRIG_STARTUP_INL */
+#define WM8961_DCS_TRIG_SERIES_INL              0x0010  /* DCS_TRIG_SERIES_INL */
+#define WM8961_DCS_TRIG_SERIES_INL_MASK         0x0010  /* DCS_TRIG_SERIES_INL */
+#define WM8961_DCS_TRIG_SERIES_INL_SHIFT             4  /* DCS_TRIG_SERIES_INL */
+#define WM8961_DCS_TRIG_SERIES_INL_WIDTH             1  /* DCS_TRIG_SERIES_INL */
+#define WM8961_DCS_ENA_CHAN_INR                 0x0008  /* DCS_ENA_CHAN_INR */
+#define WM8961_DCS_ENA_CHAN_INR_MASK            0x0008  /* DCS_ENA_CHAN_INR */
+#define WM8961_DCS_ENA_CHAN_INR_SHIFT                3  /* DCS_ENA_CHAN_INR */
+#define WM8961_DCS_ENA_CHAN_INR_WIDTH                1  /* DCS_ENA_CHAN_INR */
+#define WM8961_DCS_TRIG_STARTUP_INR             0x0004  /* DCS_TRIG_STARTUP_INR */
+#define WM8961_DCS_TRIG_STARTUP_INR_MASK        0x0004  /* DCS_TRIG_STARTUP_INR */
+#define WM8961_DCS_TRIG_STARTUP_INR_SHIFT            2  /* DCS_TRIG_STARTUP_INR */
+#define WM8961_DCS_TRIG_STARTUP_INR_WIDTH            1  /* DCS_TRIG_STARTUP_INR */
+#define WM8961_DCS_TRIG_SERIES_INR              0x0001  /* DCS_TRIG_SERIES_INR */
+#define WM8961_DCS_TRIG_SERIES_INR_MASK         0x0001  /* DCS_TRIG_SERIES_INR */
+#define WM8961_DCS_TRIG_SERIES_INR_SHIFT             0  /* DCS_TRIG_SERIES_INR */
+#define WM8961_DCS_TRIG_SERIES_INR_WIDTH             1  /* DCS_TRIG_SERIES_INR */
+
+/*
+ * R61 (0x3D) - DC Servo 1
+ */
+#define WM8961_DCS_ENA_CHAN_HPL                 0x0080  /* DCS_ENA_CHAN_HPL */
+#define WM8961_DCS_ENA_CHAN_HPL_MASK            0x0080  /* DCS_ENA_CHAN_HPL */
+#define WM8961_DCS_ENA_CHAN_HPL_SHIFT                7  /* DCS_ENA_CHAN_HPL */
+#define WM8961_DCS_ENA_CHAN_HPL_WIDTH                1  /* DCS_ENA_CHAN_HPL */
+#define WM8961_DCS_TRIG_STARTUP_HPL             0x0040  /* DCS_TRIG_STARTUP_HPL */
+#define WM8961_DCS_TRIG_STARTUP_HPL_MASK        0x0040  /* DCS_TRIG_STARTUP_HPL */
+#define WM8961_DCS_TRIG_STARTUP_HPL_SHIFT            6  /* DCS_TRIG_STARTUP_HPL */
+#define WM8961_DCS_TRIG_STARTUP_HPL_WIDTH            1  /* DCS_TRIG_STARTUP_HPL */
+#define WM8961_DCS_TRIG_SERIES_HPL              0x0010  /* DCS_TRIG_SERIES_HPL */
+#define WM8961_DCS_TRIG_SERIES_HPL_MASK         0x0010  /* DCS_TRIG_SERIES_HPL */
+#define WM8961_DCS_TRIG_SERIES_HPL_SHIFT             4  /* DCS_TRIG_SERIES_HPL */
+#define WM8961_DCS_TRIG_SERIES_HPL_WIDTH             1  /* DCS_TRIG_SERIES_HPL */
+#define WM8961_DCS_ENA_CHAN_HPR                 0x0008  /* DCS_ENA_CHAN_HPR */
+#define WM8961_DCS_ENA_CHAN_HPR_MASK            0x0008  /* DCS_ENA_CHAN_HPR */
+#define WM8961_DCS_ENA_CHAN_HPR_SHIFT                3  /* DCS_ENA_CHAN_HPR */
+#define WM8961_DCS_ENA_CHAN_HPR_WIDTH                1  /* DCS_ENA_CHAN_HPR */
+#define WM8961_DCS_TRIG_STARTUP_HPR             0x0004  /* DCS_TRIG_STARTUP_HPR */
+#define WM8961_DCS_TRIG_STARTUP_HPR_MASK        0x0004  /* DCS_TRIG_STARTUP_HPR */
+#define WM8961_DCS_TRIG_STARTUP_HPR_SHIFT            2  /* DCS_TRIG_STARTUP_HPR */
+#define WM8961_DCS_TRIG_STARTUP_HPR_WIDTH            1  /* DCS_TRIG_STARTUP_HPR */
+#define WM8961_DCS_TRIG_SERIES_HPR              0x0001  /* DCS_TRIG_SERIES_HPR */
+#define WM8961_DCS_TRIG_SERIES_HPR_MASK         0x0001  /* DCS_TRIG_SERIES_HPR */
+#define WM8961_DCS_TRIG_SERIES_HPR_SHIFT             0  /* DCS_TRIG_SERIES_HPR */
+#define WM8961_DCS_TRIG_SERIES_HPR_WIDTH             1  /* DCS_TRIG_SERIES_HPR */
+
+/*
+ * R63 (0x3F) - DC Servo 3
+ */
+#define WM8961_DCS_FILT_BW_SERIES_MASK          0x0030  /* DCS_FILT_BW_SERIES - [5:4] */
+#define WM8961_DCS_FILT_BW_SERIES_SHIFT              4  /* DCS_FILT_BW_SERIES - [5:4] */
+#define WM8961_DCS_FILT_BW_SERIES_WIDTH              2  /* DCS_FILT_BW_SERIES - [5:4] */
+
+/*
+ * R65 (0x41) - DC Servo 5
+ */
+#define WM8961_DCS_SERIES_NO_HP_MASK            0x007F  /* DCS_SERIES_NO_HP - [6:0] */
+#define WM8961_DCS_SERIES_NO_HP_SHIFT                0  /* DCS_SERIES_NO_HP - [6:0] */
+#define WM8961_DCS_SERIES_NO_HP_WIDTH                7  /* DCS_SERIES_NO_HP - [6:0] */
+
+/*
+ * R68 (0x44) - Analogue PGA Bias
+ */
+#define WM8961_HP_PGAS_BIAS_MASK                0x0007  /* HP_PGAS_BIAS - [2:0] */
+#define WM8961_HP_PGAS_BIAS_SHIFT                    0  /* HP_PGAS_BIAS - [2:0] */
+#define WM8961_HP_PGAS_BIAS_WIDTH                    3  /* HP_PGAS_BIAS - [2:0] */
+
+/*
+ * R69 (0x45) - Analogue HP 0
+ */
+#define WM8961_HPL_RMV_SHORT                    0x0080  /* HPL_RMV_SHORT */
+#define WM8961_HPL_RMV_SHORT_MASK               0x0080  /* HPL_RMV_SHORT */
+#define WM8961_HPL_RMV_SHORT_SHIFT                   7  /* HPL_RMV_SHORT */
+#define WM8961_HPL_RMV_SHORT_WIDTH                   1  /* HPL_RMV_SHORT */
+#define WM8961_HPL_ENA_OUTP                     0x0040  /* HPL_ENA_OUTP */
+#define WM8961_HPL_ENA_OUTP_MASK                0x0040  /* HPL_ENA_OUTP */
+#define WM8961_HPL_ENA_OUTP_SHIFT                    6  /* HPL_ENA_OUTP */
+#define WM8961_HPL_ENA_OUTP_WIDTH                    1  /* HPL_ENA_OUTP */
+#define WM8961_HPL_ENA_DLY                      0x0020  /* HPL_ENA_DLY */
+#define WM8961_HPL_ENA_DLY_MASK                 0x0020  /* HPL_ENA_DLY */
+#define WM8961_HPL_ENA_DLY_SHIFT                     5  /* HPL_ENA_DLY */
+#define WM8961_HPL_ENA_DLY_WIDTH                     1  /* HPL_ENA_DLY */
+#define WM8961_HPL_ENA                          0x0010  /* HPL_ENA */
+#define WM8961_HPL_ENA_MASK                     0x0010  /* HPL_ENA */
+#define WM8961_HPL_ENA_SHIFT                         4  /* HPL_ENA */
+#define WM8961_HPL_ENA_WIDTH                         1  /* HPL_ENA */
+#define WM8961_HPR_RMV_SHORT                    0x0008  /* HPR_RMV_SHORT */
+#define WM8961_HPR_RMV_SHORT_MASK               0x0008  /* HPR_RMV_SHORT */
+#define WM8961_HPR_RMV_SHORT_SHIFT                   3  /* HPR_RMV_SHORT */
+#define WM8961_HPR_RMV_SHORT_WIDTH                   1  /* HPR_RMV_SHORT */
+#define WM8961_HPR_ENA_OUTP                     0x0004  /* HPR_ENA_OUTP */
+#define WM8961_HPR_ENA_OUTP_MASK                0x0004  /* HPR_ENA_OUTP */
+#define WM8961_HPR_ENA_OUTP_SHIFT                    2  /* HPR_ENA_OUTP */
+#define WM8961_HPR_ENA_OUTP_WIDTH                    1  /* HPR_ENA_OUTP */
+#define WM8961_HPR_ENA_DLY                      0x0002  /* HPR_ENA_DLY */
+#define WM8961_HPR_ENA_DLY_MASK                 0x0002  /* HPR_ENA_DLY */
+#define WM8961_HPR_ENA_DLY_SHIFT                     1  /* HPR_ENA_DLY */
+#define WM8961_HPR_ENA_DLY_WIDTH                     1  /* HPR_ENA_DLY */
+#define WM8961_HPR_ENA                          0x0001  /* HPR_ENA */
+#define WM8961_HPR_ENA_MASK                     0x0001  /* HPR_ENA */
+#define WM8961_HPR_ENA_SHIFT                         0  /* HPR_ENA */
+#define WM8961_HPR_ENA_WIDTH                         1  /* HPR_ENA */
+
+/*
+ * R71 (0x47) - Analogue HP 2
+ */
+#define WM8961_HPL_VOL_MASK                     0x01C0  /* HPL_VOL - [8:6] */
+#define WM8961_HPL_VOL_SHIFT                         6  /* HPL_VOL - [8:6] */
+#define WM8961_HPL_VOL_WIDTH                         3  /* HPL_VOL - [8:6] */
+#define WM8961_HPR_VOL_MASK                     0x0038  /* HPR_VOL - [5:3] */
+#define WM8961_HPR_VOL_SHIFT                         3  /* HPR_VOL - [5:3] */
+#define WM8961_HPR_VOL_WIDTH                         3  /* HPR_VOL - [5:3] */
+#define WM8961_HP_BIAS_BOOST_MASK               0x0007  /* HP_BIAS_BOOST - [2:0] */
+#define WM8961_HP_BIAS_BOOST_SHIFT                   0  /* HP_BIAS_BOOST - [2:0] */
+#define WM8961_HP_BIAS_BOOST_WIDTH                   3  /* HP_BIAS_BOOST - [2:0] */
+
+/*
+ * R72 (0x48) - Charge Pump 1
+ */
+#define WM8961_CP_ENA                           0x0001  /* CP_ENA */
+#define WM8961_CP_ENA_MASK                      0x0001  /* CP_ENA */
+#define WM8961_CP_ENA_SHIFT                          0  /* CP_ENA */
+#define WM8961_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R82 (0x52) - Charge Pump B
+ */
+#define WM8961_CP_DYN_PWR_MASK                  0x0003  /* CP_DYN_PWR - [1:0] */
+#define WM8961_CP_DYN_PWR_SHIFT                      0  /* CP_DYN_PWR - [1:0] */
+#define WM8961_CP_DYN_PWR_WIDTH                      2  /* CP_DYN_PWR - [1:0] */
+
+/*
+ * R87 (0x57) - Write Sequencer 1
+ */
+#define WM8961_WSEQ_ENA                         0x0020  /* WSEQ_ENA */
+#define WM8961_WSEQ_ENA_MASK                    0x0020  /* WSEQ_ENA */
+#define WM8961_WSEQ_ENA_SHIFT                        5  /* WSEQ_ENA */
+#define WM8961_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM8961_WSEQ_WRITE_INDEX_MASK            0x001F  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8961_WSEQ_WRITE_INDEX_SHIFT                0  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8961_WSEQ_WRITE_INDEX_WIDTH                5  /* WSEQ_WRITE_INDEX - [4:0] */
+
+/*
+ * R88 (0x58) - Write Sequencer 2
+ */
+#define WM8961_WSEQ_EOS                         0x0100  /* WSEQ_EOS */
+#define WM8961_WSEQ_EOS_MASK                    0x0100  /* WSEQ_EOS */
+#define WM8961_WSEQ_EOS_SHIFT                        8  /* WSEQ_EOS */
+#define WM8961_WSEQ_EOS_WIDTH                        1  /* WSEQ_EOS */
+#define WM8961_WSEQ_ADDR_MASK                   0x00FF  /* WSEQ_ADDR - [7:0] */
+#define WM8961_WSEQ_ADDR_SHIFT                       0  /* WSEQ_ADDR - [7:0] */
+#define WM8961_WSEQ_ADDR_WIDTH                       8  /* WSEQ_ADDR - [7:0] */
+
+/*
+ * R89 (0x59) - Write Sequencer 3
+ */
+#define WM8961_WSEQ_DATA_MASK                   0x00FF  /* WSEQ_DATA - [7:0] */
+#define WM8961_WSEQ_DATA_SHIFT                       0  /* WSEQ_DATA - [7:0] */
+#define WM8961_WSEQ_DATA_WIDTH                       8  /* WSEQ_DATA - [7:0] */
+
+/*
+ * R90 (0x5A) - Write Sequencer 4
+ */
+#define WM8961_WSEQ_ABORT                       0x0100  /* WSEQ_ABORT */
+#define WM8961_WSEQ_ABORT_MASK                  0x0100  /* WSEQ_ABORT */
+#define WM8961_WSEQ_ABORT_SHIFT                      8  /* WSEQ_ABORT */
+#define WM8961_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8961_WSEQ_START                       0x0080  /* WSEQ_START */
+#define WM8961_WSEQ_START_MASK                  0x0080  /* WSEQ_START */
+#define WM8961_WSEQ_START_SHIFT                      7  /* WSEQ_START */
+#define WM8961_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8961_WSEQ_START_INDEX_MASK            0x003F  /* WSEQ_START_INDEX - [5:0] */
+#define WM8961_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [5:0] */
+#define WM8961_WSEQ_START_INDEX_WIDTH                6  /* WSEQ_START_INDEX - [5:0] */
+
+/*
+ * R91 (0x5B) - Write Sequencer 5
+ */
+#define WM8961_WSEQ_DATA_WIDTH_MASK             0x0070  /* WSEQ_DATA_WIDTH - [6:4] */
+#define WM8961_WSEQ_DATA_WIDTH_SHIFT                 4  /* WSEQ_DATA_WIDTH - [6:4] */
+#define WM8961_WSEQ_DATA_WIDTH_WIDTH                 3  /* WSEQ_DATA_WIDTH - [6:4] */
+#define WM8961_WSEQ_DATA_START_MASK             0x000F  /* WSEQ_DATA_START - [3:0] */
+#define WM8961_WSEQ_DATA_START_SHIFT                 0  /* WSEQ_DATA_START - [3:0] */
+#define WM8961_WSEQ_DATA_START_WIDTH                 4  /* WSEQ_DATA_START - [3:0] */
+
+/*
+ * R92 (0x5C) - Write Sequencer 6
+ */
+#define WM8961_WSEQ_DELAY_MASK                  0x000F  /* WSEQ_DELAY - [3:0] */
+#define WM8961_WSEQ_DELAY_SHIFT                      0  /* WSEQ_DELAY - [3:0] */
+#define WM8961_WSEQ_DELAY_WIDTH                      4  /* WSEQ_DELAY - [3:0] */
+
+/*
+ * R93 (0x5D) - Write Sequencer 7
+ */
+#define WM8961_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM8961_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM8961_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM8961_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R252 (0xFC) - General test 1
+ */
+#define WM8961_ARA_ENA                          0x0002  /* ARA_ENA */
+#define WM8961_ARA_ENA_MASK                     0x0002  /* ARA_ENA */
+#define WM8961_ARA_ENA_SHIFT                         1  /* ARA_ENA */
+#define WM8961_ARA_ENA_WIDTH                         1  /* ARA_ENA */
+#define WM8961_AUTO_INC                         0x0001  /* AUTO_INC */
+#define WM8961_AUTO_INC_MASK                    0x0001  /* AUTO_INC */
+#define WM8961_AUTO_INC_SHIFT                        0  /* AUTO_INC */
+#define WM8961_AUTO_INC_WIDTH                        1  /* AUTO_INC */
+
+#endif
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
new file mode 100644
index 0000000..efd8910
--- /dev/null
+++ b/sound/soc/codecs/wm8962.c
@@ -0,0 +1,3894 @@
+/*
+ * wm8962.c  --  WM8962 ALSA SoC Audio driver
+ *
+ * Copyright 2010-2 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/wm8962.h>
+#include <trace/events/asoc.h>
+
+#include "wm8962.h"
+
+#define WM8962_NUM_SUPPLIES 8
+static const char *wm8962_supply_names[WM8962_NUM_SUPPLIES] = {
+	"DCVDD",
+	"DBVDD",
+	"AVDD",
+	"CPVDD",
+	"MICVDD",
+	"PLLVDD",
+	"SPKVDD1",
+	"SPKVDD2",
+};
+
+/* codec private data */
+struct wm8962_priv {
+	struct wm8962_pdata pdata;
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+
+	int sysclk;
+	int sysclk_rate;
+
+	int bclk;  /* Desired BCLK */
+	int lrclk;
+
+	struct completion fll_lock;
+	int fll_src;
+	int fll_fref;
+	int fll_fout;
+
+	struct mutex dsp2_ena_lock;
+	u16 dsp2_ena;
+
+	struct delayed_work mic_work;
+	struct snd_soc_jack *jack;
+
+	struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES];
+	struct notifier_block disable_nb[WM8962_NUM_SUPPLIES];
+
+	struct input_dev *beep;
+	struct work_struct beep_work;
+	int beep_rate;
+
+#ifdef CONFIG_GPIOLIB
+	struct gpio_chip gpio_chip;
+#endif
+
+	int irq;
+};
+
+/* We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8962_REGULATOR_EVENT(n) \
+static int wm8962_regulator_event_##n(struct notifier_block *nb, \
+				    unsigned long event, void *data)	\
+{ \
+	struct wm8962_priv *wm8962 = container_of(nb, struct wm8962_priv, \
+						  disable_nb[n]); \
+	if (event & REGULATOR_EVENT_DISABLE) { \
+		regcache_mark_dirty(wm8962->regmap);	\
+	} \
+	return 0; \
+}
+
+WM8962_REGULATOR_EVENT(0)
+WM8962_REGULATOR_EVENT(1)
+WM8962_REGULATOR_EVENT(2)
+WM8962_REGULATOR_EVENT(3)
+WM8962_REGULATOR_EVENT(4)
+WM8962_REGULATOR_EVENT(5)
+WM8962_REGULATOR_EVENT(6)
+WM8962_REGULATOR_EVENT(7)
+
+static const struct reg_default wm8962_reg[] = {
+	{ 0, 0x009F },   /* R0     - Left Input volume */
+	{ 1, 0x049F },   /* R1     - Right Input volume */
+	{ 2, 0x0000 },   /* R2     - HPOUTL volume */
+	{ 3, 0x0000 },   /* R3     - HPOUTR volume */
+
+	{ 5, 0x0018 },   /* R5     - ADC & DAC Control 1 */
+	{ 6, 0x2008 },   /* R6     - ADC & DAC Control 2 */
+	{ 7, 0x000A },   /* R7     - Audio Interface 0 */
+
+	{ 9, 0x0300 },   /* R9     - Audio Interface 1 */
+	{ 10, 0x00C0 },  /* R10    - Left DAC volume */
+	{ 11, 0x00C0 },  /* R11    - Right DAC volume */
+
+	{ 14, 0x0040 },   /* R14    - Audio Interface 2 */
+	{ 15, 0x6243 },   /* R15    - Software Reset */
+
+	{ 17, 0x007B },   /* R17    - ALC1 */
+	{ 18, 0x0000 },   /* R18    - ALC2 */
+	{ 19, 0x1C32 },   /* R19    - ALC3 */
+	{ 20, 0x3200 },   /* R20    - Noise Gate */
+	{ 21, 0x00C0 },   /* R21    - Left ADC volume */
+	{ 22, 0x00C0 },   /* R22    - Right ADC volume */
+	{ 23, 0x0160 },   /* R23    - Additional control(1) */
+	{ 24, 0x0000 },   /* R24    - Additional control(2) */
+	{ 25, 0x0000 },   /* R25    - Pwr Mgmt (1) */
+	{ 26, 0x0000 },   /* R26    - Pwr Mgmt (2) */
+	{ 27, 0x0010 },   /* R27    - Additional Control (3) */
+	{ 28, 0x0000 },   /* R28    - Anti-pop */
+
+	{ 30, 0x005E },   /* R30    - Clocking 3 */
+	{ 31, 0x0000 },   /* R31    - Input mixer control (1) */
+	{ 32, 0x0145 },   /* R32    - Left input mixer volume */
+	{ 33, 0x0145 },   /* R33    - Right input mixer volume */
+	{ 34, 0x0009 },   /* R34    - Input mixer control (2) */
+	{ 35, 0x0003 },   /* R35    - Input bias control */
+	{ 37, 0x0008 },   /* R37    - Left input PGA control */
+	{ 38, 0x0008 },   /* R38    - Right input PGA control */
+
+	{ 40, 0x0000 },   /* R40    - SPKOUTL volume */
+	{ 41, 0x0000 },   /* R41    - SPKOUTR volume */
+
+	{ 49, 0x0010 },   /* R49    - Class D Control 1 */
+	{ 51, 0x0003 },   /* R51    - Class D Control 2 */
+
+	{ 56, 0x0506 },   /* R56    - Clocking 4 */
+	{ 57, 0x0000 },   /* R57    - DAC DSP Mixing (1) */
+	{ 58, 0x0000 },   /* R58    - DAC DSP Mixing (2) */
+
+	{ 60, 0x0300 },   /* R60    - DC Servo 0 */
+	{ 61, 0x0300 },   /* R61    - DC Servo 1 */
+
+	{ 64, 0x0810 },   /* R64    - DC Servo 4 */
+
+	{ 68, 0x001B },   /* R68    - Analogue PGA Bias */
+	{ 69, 0x0000 },   /* R69    - Analogue HP 0 */
+
+	{ 71, 0x01FB },   /* R71    - Analogue HP 2 */
+	{ 72, 0x0000 },   /* R72    - Charge Pump 1 */
+
+	{ 82, 0x0004 },   /* R82    - Charge Pump B */
+
+	{ 87, 0x0000 },   /* R87    - Write Sequencer Control 1 */
+
+	{ 90, 0x0000 },   /* R90    - Write Sequencer Control 2 */
+
+	{ 93, 0x0000 },   /* R93    - Write Sequencer Control 3 */
+	{ 94, 0x0000 },   /* R94    - Control Interface */
+
+	{ 99, 0x0000 },   /* R99    - Mixer Enables */
+	{ 100, 0x0000 },   /* R100   - Headphone Mixer (1) */
+	{ 101, 0x0000 },   /* R101   - Headphone Mixer (2) */
+	{ 102, 0x013F },   /* R102   - Headphone Mixer (3) */
+	{ 103, 0x013F },   /* R103   - Headphone Mixer (4) */
+
+	{ 105, 0x0000 },   /* R105   - Speaker Mixer (1) */
+	{ 106, 0x0000 },   /* R106   - Speaker Mixer (2) */
+	{ 107, 0x013F },   /* R107   - Speaker Mixer (3) */
+	{ 108, 0x013F },   /* R108   - Speaker Mixer (4) */
+	{ 109, 0x0003 },   /* R109   - Speaker Mixer (5) */
+	{ 110, 0x0002 },   /* R110   - Beep Generator (1) */
+
+	{ 115, 0x0006 },   /* R115   - Oscillator Trim (3) */
+	{ 116, 0x0026 },   /* R116   - Oscillator Trim (4) */
+
+	{ 119, 0x0000 },   /* R119   - Oscillator Trim (7) */
+
+	{ 124, 0x0011 },   /* R124   - Analogue Clocking1 */
+	{ 125, 0x004B },   /* R125   - Analogue Clocking2 */
+	{ 126, 0x000D },   /* R126   - Analogue Clocking3 */
+	{ 127, 0x0000 },   /* R127   - PLL Software Reset */
+
+	{ 131, 0x0000 },   /* R131   - PLL 4 */
+
+	{ 136, 0x0067 },   /* R136   - PLL 9 */
+	{ 137, 0x001C },   /* R137   - PLL 10 */
+	{ 138, 0x0071 },   /* R138   - PLL 11 */
+	{ 139, 0x00C7 },   /* R139   - PLL 12 */
+	{ 140, 0x0067 },   /* R140   - PLL 13 */
+	{ 141, 0x0048 },   /* R141   - PLL 14 */
+	{ 142, 0x0022 },   /* R142   - PLL 15 */
+	{ 143, 0x0097 },   /* R143   - PLL 16 */
+
+	{ 155, 0x000C },   /* R155   - FLL Control (1) */
+	{ 156, 0x0039 },   /* R156   - FLL Control (2) */
+	{ 157, 0x0180 },   /* R157   - FLL Control (3) */
+
+	{ 159, 0x0032 },   /* R159   - FLL Control (5) */
+	{ 160, 0x0018 },   /* R160   - FLL Control (6) */
+	{ 161, 0x007D },   /* R161   - FLL Control (7) */
+	{ 162, 0x0008 },   /* R162   - FLL Control (8) */
+
+	{ 252, 0x0005 },   /* R252   - General test 1 */
+
+	{ 256, 0x0000 },   /* R256   - DF1 */
+	{ 257, 0x0000 },   /* R257   - DF2 */
+	{ 258, 0x0000 },   /* R258   - DF3 */
+	{ 259, 0x0000 },   /* R259   - DF4 */
+	{ 260, 0x0000 },   /* R260   - DF5 */
+	{ 261, 0x0000 },   /* R261   - DF6 */
+	{ 262, 0x0000 },   /* R262   - DF7 */
+
+	{ 264, 0x0000 },   /* R264   - LHPF1 */
+	{ 265, 0x0000 },   /* R265   - LHPF2 */
+
+	{ 268, 0x0000 },   /* R268   - THREED1 */
+	{ 269, 0x0000 },   /* R269   - THREED2 */
+	{ 270, 0x0000 },   /* R270   - THREED3 */
+	{ 271, 0x0000 },   /* R271   - THREED4 */
+
+	{ 276, 0x000C },   /* R276   - DRC 1 */
+	{ 277, 0x0925 },   /* R277   - DRC 2 */
+	{ 278, 0x0000 },   /* R278   - DRC 3 */
+	{ 279, 0x0000 },   /* R279   - DRC 4 */
+	{ 280, 0x0000 },   /* R280   - DRC 5 */
+
+	{ 285, 0x0000 },   /* R285   - Tloopback */
+
+	{ 335, 0x0004 },   /* R335   - EQ1 */
+	{ 336, 0x6318 },   /* R336   - EQ2 */
+	{ 337, 0x6300 },   /* R337   - EQ3 */
+	{ 338, 0x0FCA },   /* R338   - EQ4 */
+	{ 339, 0x0400 },   /* R339   - EQ5 */
+	{ 340, 0x00D8 },   /* R340   - EQ6 */
+	{ 341, 0x1EB5 },   /* R341   - EQ7 */
+	{ 342, 0xF145 },   /* R342   - EQ8 */
+	{ 343, 0x0B75 },   /* R343   - EQ9 */
+	{ 344, 0x01C5 },   /* R344   - EQ10 */
+	{ 345, 0x1C58 },   /* R345   - EQ11 */
+	{ 346, 0xF373 },   /* R346   - EQ12 */
+	{ 347, 0x0A54 },   /* R347   - EQ13 */
+	{ 348, 0x0558 },   /* R348   - EQ14 */
+	{ 349, 0x168E },   /* R349   - EQ15 */
+	{ 350, 0xF829 },   /* R350   - EQ16 */
+	{ 351, 0x07AD },   /* R351   - EQ17 */
+	{ 352, 0x1103 },   /* R352   - EQ18 */
+	{ 353, 0x0564 },   /* R353   - EQ19 */
+	{ 354, 0x0559 },   /* R354   - EQ20 */
+	{ 355, 0x4000 },   /* R355   - EQ21 */
+	{ 356, 0x6318 },   /* R356   - EQ22 */
+	{ 357, 0x6300 },   /* R357   - EQ23 */
+	{ 358, 0x0FCA },   /* R358   - EQ24 */
+	{ 359, 0x0400 },   /* R359   - EQ25 */
+	{ 360, 0x00D8 },   /* R360   - EQ26 */
+	{ 361, 0x1EB5 },   /* R361   - EQ27 */
+	{ 362, 0xF145 },   /* R362   - EQ28 */
+	{ 363, 0x0B75 },   /* R363   - EQ29 */
+	{ 364, 0x01C5 },   /* R364   - EQ30 */
+	{ 365, 0x1C58 },   /* R365   - EQ31 */
+	{ 366, 0xF373 },   /* R366   - EQ32 */
+	{ 367, 0x0A54 },   /* R367   - EQ33 */
+	{ 368, 0x0558 },   /* R368   - EQ34 */
+	{ 369, 0x168E },   /* R369   - EQ35 */
+	{ 370, 0xF829 },   /* R370   - EQ36 */
+	{ 371, 0x07AD },   /* R371   - EQ37 */
+	{ 372, 0x1103 },   /* R372   - EQ38 */
+	{ 373, 0x0564 },   /* R373   - EQ39 */
+	{ 374, 0x0559 },   /* R374   - EQ40 */
+	{ 375, 0x4000 },   /* R375   - EQ41 */
+
+	{ 513, 0x0000 },   /* R513   - GPIO 2 */
+	{ 514, 0x0000 },   /* R514   - GPIO 3 */
+
+	{ 516, 0x8100 },   /* R516   - GPIO 5 */
+	{ 517, 0x8100 },   /* R517   - GPIO 6 */
+
+	{ 568, 0x0030 },   /* R568   - Interrupt Status 1 Mask */
+	{ 569, 0xFFED },   /* R569   - Interrupt Status 2 Mask */
+
+	{ 576, 0x0000 },   /* R576   - Interrupt Control */
+
+	{ 584, 0x002D },   /* R584   - IRQ Debounce */
+
+	{ 586, 0x0000 },   /* R586   -  MICINT Source Pol */
+
+	{ 768, 0x1C00 },   /* R768   - DSP2 Power Management */
+
+	{ 8192, 0x0000 },   /* R8192  - DSP2 Instruction RAM 0 */
+
+	{ 9216, 0x0030 },   /* R9216  - DSP2 Address RAM 2 */
+	{ 9217, 0x0000 },   /* R9217  - DSP2 Address RAM 1 */
+	{ 9218, 0x0000 },   /* R9218  - DSP2 Address RAM 0 */
+
+	{ 12288, 0x0000 },   /* R12288 - DSP2 Data1 RAM 1 */
+	{ 12289, 0x0000 },   /* R12289 - DSP2 Data1 RAM 0 */
+
+	{ 13312, 0x0000 },   /* R13312 - DSP2 Data2 RAM 1 */
+	{ 13313, 0x0000 },   /* R13313 - DSP2 Data2 RAM 0 */
+
+	{ 14336, 0x0000 },   /* R14336 - DSP2 Data3 RAM 1 */
+	{ 14337, 0x0000 },   /* R14337 - DSP2 Data3 RAM 0 */
+
+	{ 15360, 0x000A },   /* R15360 - DSP2 Coeff RAM 0 */
+
+	{ 16384, 0x0000 },   /* R16384 - RETUNEADC_SHARED_COEFF_1 */
+	{ 16385, 0x0000 },   /* R16385 - RETUNEADC_SHARED_COEFF_0 */
+	{ 16386, 0x0000 },   /* R16386 - RETUNEDAC_SHARED_COEFF_1 */
+	{ 16387, 0x0000 },   /* R16387 - RETUNEDAC_SHARED_COEFF_0 */
+	{ 16388, 0x0000 },   /* R16388 - SOUNDSTAGE_ENABLES_1 */
+	{ 16389, 0x0000 },   /* R16389 - SOUNDSTAGE_ENABLES_0 */
+
+	{ 16896, 0x0002 },   /* R16896 - HDBASS_AI_1 */
+	{ 16897, 0xBD12 },   /* R16897 - HDBASS_AI_0 */
+	{ 16898, 0x007C },   /* R16898 - HDBASS_AR_1 */
+	{ 16899, 0x586C },   /* R16899 - HDBASS_AR_0 */
+	{ 16900, 0x0053 },   /* R16900 - HDBASS_B_1 */
+	{ 16901, 0x8121 },   /* R16901 - HDBASS_B_0 */
+	{ 16902, 0x003F },   /* R16902 - HDBASS_K_1 */
+	{ 16903, 0x8BD8 },   /* R16903 - HDBASS_K_0 */
+	{ 16904, 0x0032 },   /* R16904 - HDBASS_N1_1 */
+	{ 16905, 0xF52D },   /* R16905 - HDBASS_N1_0 */
+	{ 16906, 0x0065 },   /* R16906 - HDBASS_N2_1 */
+	{ 16907, 0xAC8C },   /* R16907 - HDBASS_N2_0 */
+	{ 16908, 0x006B },   /* R16908 - HDBASS_N3_1 */
+	{ 16909, 0xE087 },   /* R16909 - HDBASS_N3_0 */
+	{ 16910, 0x0072 },   /* R16910 - HDBASS_N4_1 */
+	{ 16911, 0x1483 },   /* R16911 - HDBASS_N4_0 */
+	{ 16912, 0x0072 },   /* R16912 - HDBASS_N5_1 */
+	{ 16913, 0x1483 },   /* R16913 - HDBASS_N5_0 */
+	{ 16914, 0x0043 },   /* R16914 - HDBASS_X1_1 */
+	{ 16915, 0x3525 },   /* R16915 - HDBASS_X1_0 */
+	{ 16916, 0x0006 },   /* R16916 - HDBASS_X2_1 */
+	{ 16917, 0x6A4A },   /* R16917 - HDBASS_X2_0 */
+	{ 16918, 0x0043 },   /* R16918 - HDBASS_X3_1 */
+	{ 16919, 0x6079 },   /* R16919 - HDBASS_X3_0 */
+	{ 16920, 0x0008 },   /* R16920 - HDBASS_ATK_1 */
+	{ 16921, 0x0000 },   /* R16921 - HDBASS_ATK_0 */
+	{ 16922, 0x0001 },   /* R16922 - HDBASS_DCY_1 */
+	{ 16923, 0x0000 },   /* R16923 - HDBASS_DCY_0 */
+	{ 16924, 0x0059 },   /* R16924 - HDBASS_PG_1 */
+	{ 16925, 0x999A },   /* R16925 - HDBASS_PG_0 */
+
+	{ 17408, 0x0083 },   /* R17408 - HPF_C_1 */
+	{ 17409, 0x98AD },   /* R17409 - HPF_C_0 */
+
+	{ 17920, 0x007F },   /* R17920 - ADCL_RETUNE_C1_1 */
+	{ 17921, 0xFFFF },   /* R17921 - ADCL_RETUNE_C1_0 */
+	{ 17922, 0x0000 },   /* R17922 - ADCL_RETUNE_C2_1 */
+	{ 17923, 0x0000 },   /* R17923 - ADCL_RETUNE_C2_0 */
+	{ 17924, 0x0000 },   /* R17924 - ADCL_RETUNE_C3_1 */
+	{ 17925, 0x0000 },   /* R17925 - ADCL_RETUNE_C3_0 */
+	{ 17926, 0x0000 },   /* R17926 - ADCL_RETUNE_C4_1 */
+	{ 17927, 0x0000 },   /* R17927 - ADCL_RETUNE_C4_0 */
+	{ 17928, 0x0000 },   /* R17928 - ADCL_RETUNE_C5_1 */
+	{ 17929, 0x0000 },   /* R17929 - ADCL_RETUNE_C5_0 */
+	{ 17930, 0x0000 },   /* R17930 - ADCL_RETUNE_C6_1 */
+	{ 17931, 0x0000 },   /* R17931 - ADCL_RETUNE_C6_0 */
+	{ 17932, 0x0000 },   /* R17932 - ADCL_RETUNE_C7_1 */
+	{ 17933, 0x0000 },   /* R17933 - ADCL_RETUNE_C7_0 */
+	{ 17934, 0x0000 },   /* R17934 - ADCL_RETUNE_C8_1 */
+	{ 17935, 0x0000 },   /* R17935 - ADCL_RETUNE_C8_0 */
+	{ 17936, 0x0000 },   /* R17936 - ADCL_RETUNE_C9_1 */
+	{ 17937, 0x0000 },   /* R17937 - ADCL_RETUNE_C9_0 */
+	{ 17938, 0x0000 },   /* R17938 - ADCL_RETUNE_C10_1 */
+	{ 17939, 0x0000 },   /* R17939 - ADCL_RETUNE_C10_0 */
+	{ 17940, 0x0000 },   /* R17940 - ADCL_RETUNE_C11_1 */
+	{ 17941, 0x0000 },   /* R17941 - ADCL_RETUNE_C11_0 */
+	{ 17942, 0x0000 },   /* R17942 - ADCL_RETUNE_C12_1 */
+	{ 17943, 0x0000 },   /* R17943 - ADCL_RETUNE_C12_0 */
+	{ 17944, 0x0000 },   /* R17944 - ADCL_RETUNE_C13_1 */
+	{ 17945, 0x0000 },   /* R17945 - ADCL_RETUNE_C13_0 */
+	{ 17946, 0x0000 },   /* R17946 - ADCL_RETUNE_C14_1 */
+	{ 17947, 0x0000 },   /* R17947 - ADCL_RETUNE_C14_0 */
+	{ 17948, 0x0000 },   /* R17948 - ADCL_RETUNE_C15_1 */
+	{ 17949, 0x0000 },   /* R17949 - ADCL_RETUNE_C15_0 */
+	{ 17950, 0x0000 },   /* R17950 - ADCL_RETUNE_C16_1 */
+	{ 17951, 0x0000 },   /* R17951 - ADCL_RETUNE_C16_0 */
+	{ 17952, 0x0000 },   /* R17952 - ADCL_RETUNE_C17_1 */
+	{ 17953, 0x0000 },   /* R17953 - ADCL_RETUNE_C17_0 */
+	{ 17954, 0x0000 },   /* R17954 - ADCL_RETUNE_C18_1 */
+	{ 17955, 0x0000 },   /* R17955 - ADCL_RETUNE_C18_0 */
+	{ 17956, 0x0000 },   /* R17956 - ADCL_RETUNE_C19_1 */
+	{ 17957, 0x0000 },   /* R17957 - ADCL_RETUNE_C19_0 */
+	{ 17958, 0x0000 },   /* R17958 - ADCL_RETUNE_C20_1 */
+	{ 17959, 0x0000 },   /* R17959 - ADCL_RETUNE_C20_0 */
+	{ 17960, 0x0000 },   /* R17960 - ADCL_RETUNE_C21_1 */
+	{ 17961, 0x0000 },   /* R17961 - ADCL_RETUNE_C21_0 */
+	{ 17962, 0x0000 },   /* R17962 - ADCL_RETUNE_C22_1 */
+	{ 17963, 0x0000 },   /* R17963 - ADCL_RETUNE_C22_0 */
+	{ 17964, 0x0000 },   /* R17964 - ADCL_RETUNE_C23_1 */
+	{ 17965, 0x0000 },   /* R17965 - ADCL_RETUNE_C23_0 */
+	{ 17966, 0x0000 },   /* R17966 - ADCL_RETUNE_C24_1 */
+	{ 17967, 0x0000 },   /* R17967 - ADCL_RETUNE_C24_0 */
+	{ 17968, 0x0000 },   /* R17968 - ADCL_RETUNE_C25_1 */
+	{ 17969, 0x0000 },   /* R17969 - ADCL_RETUNE_C25_0 */
+	{ 17970, 0x0000 },   /* R17970 - ADCL_RETUNE_C26_1 */
+	{ 17971, 0x0000 },   /* R17971 - ADCL_RETUNE_C26_0 */
+	{ 17972, 0x0000 },   /* R17972 - ADCL_RETUNE_C27_1 */
+	{ 17973, 0x0000 },   /* R17973 - ADCL_RETUNE_C27_0 */
+	{ 17974, 0x0000 },   /* R17974 - ADCL_RETUNE_C28_1 */
+	{ 17975, 0x0000 },   /* R17975 - ADCL_RETUNE_C28_0 */
+	{ 17976, 0x0000 },   /* R17976 - ADCL_RETUNE_C29_1 */
+	{ 17977, 0x0000 },   /* R17977 - ADCL_RETUNE_C29_0 */
+	{ 17978, 0x0000 },   /* R17978 - ADCL_RETUNE_C30_1 */
+	{ 17979, 0x0000 },   /* R17979 - ADCL_RETUNE_C30_0 */
+	{ 17980, 0x0000 },   /* R17980 - ADCL_RETUNE_C31_1 */
+	{ 17981, 0x0000 },   /* R17981 - ADCL_RETUNE_C31_0 */
+	{ 17982, 0x0000 },   /* R17982 - ADCL_RETUNE_C32_1 */
+	{ 17983, 0x0000 },   /* R17983 - ADCL_RETUNE_C32_0 */
+
+	{ 18432, 0x0020 },   /* R18432 - RETUNEADC_PG2_1 */
+	{ 18433, 0x0000 },   /* R18433 - RETUNEADC_PG2_0 */
+	{ 18434, 0x0040 },   /* R18434 - RETUNEADC_PG_1 */
+	{ 18435, 0x0000 },   /* R18435 - RETUNEADC_PG_0 */
+
+	{ 18944, 0x007F },   /* R18944 - ADCR_RETUNE_C1_1 */
+	{ 18945, 0xFFFF },   /* R18945 - ADCR_RETUNE_C1_0 */
+	{ 18946, 0x0000 },   /* R18946 - ADCR_RETUNE_C2_1 */
+	{ 18947, 0x0000 },   /* R18947 - ADCR_RETUNE_C2_0 */
+	{ 18948, 0x0000 },   /* R18948 - ADCR_RETUNE_C3_1 */
+	{ 18949, 0x0000 },   /* R18949 - ADCR_RETUNE_C3_0 */
+	{ 18950, 0x0000 },   /* R18950 - ADCR_RETUNE_C4_1 */
+	{ 18951, 0x0000 },   /* R18951 - ADCR_RETUNE_C4_0 */
+	{ 18952, 0x0000 },   /* R18952 - ADCR_RETUNE_C5_1 */
+	{ 18953, 0x0000 },   /* R18953 - ADCR_RETUNE_C5_0 */
+	{ 18954, 0x0000 },   /* R18954 - ADCR_RETUNE_C6_1 */
+	{ 18955, 0x0000 },   /* R18955 - ADCR_RETUNE_C6_0 */
+	{ 18956, 0x0000 },   /* R18956 - ADCR_RETUNE_C7_1 */
+	{ 18957, 0x0000 },   /* R18957 - ADCR_RETUNE_C7_0 */
+	{ 18958, 0x0000 },   /* R18958 - ADCR_RETUNE_C8_1 */
+	{ 18959, 0x0000 },   /* R18959 - ADCR_RETUNE_C8_0 */
+	{ 18960, 0x0000 },   /* R18960 - ADCR_RETUNE_C9_1 */
+	{ 18961, 0x0000 },   /* R18961 - ADCR_RETUNE_C9_0 */
+	{ 18962, 0x0000 },   /* R18962 - ADCR_RETUNE_C10_1 */
+	{ 18963, 0x0000 },   /* R18963 - ADCR_RETUNE_C10_0 */
+	{ 18964, 0x0000 },   /* R18964 - ADCR_RETUNE_C11_1 */
+	{ 18965, 0x0000 },   /* R18965 - ADCR_RETUNE_C11_0 */
+	{ 18966, 0x0000 },   /* R18966 - ADCR_RETUNE_C12_1 */
+	{ 18967, 0x0000 },   /* R18967 - ADCR_RETUNE_C12_0 */
+	{ 18968, 0x0000 },   /* R18968 - ADCR_RETUNE_C13_1 */
+	{ 18969, 0x0000 },   /* R18969 - ADCR_RETUNE_C13_0 */
+	{ 18970, 0x0000 },   /* R18970 - ADCR_RETUNE_C14_1 */
+	{ 18971, 0x0000 },   /* R18971 - ADCR_RETUNE_C14_0 */
+	{ 18972, 0x0000 },   /* R18972 - ADCR_RETUNE_C15_1 */
+	{ 18973, 0x0000 },   /* R18973 - ADCR_RETUNE_C15_0 */
+	{ 18974, 0x0000 },   /* R18974 - ADCR_RETUNE_C16_1 */
+	{ 18975, 0x0000 },   /* R18975 - ADCR_RETUNE_C16_0 */
+	{ 18976, 0x0000 },   /* R18976 - ADCR_RETUNE_C17_1 */
+	{ 18977, 0x0000 },   /* R18977 - ADCR_RETUNE_C17_0 */
+	{ 18978, 0x0000 },   /* R18978 - ADCR_RETUNE_C18_1 */
+	{ 18979, 0x0000 },   /* R18979 - ADCR_RETUNE_C18_0 */
+	{ 18980, 0x0000 },   /* R18980 - ADCR_RETUNE_C19_1 */
+	{ 18981, 0x0000 },   /* R18981 - ADCR_RETUNE_C19_0 */
+	{ 18982, 0x0000 },   /* R18982 - ADCR_RETUNE_C20_1 */
+	{ 18983, 0x0000 },   /* R18983 - ADCR_RETUNE_C20_0 */
+	{ 18984, 0x0000 },   /* R18984 - ADCR_RETUNE_C21_1 */
+	{ 18985, 0x0000 },   /* R18985 - ADCR_RETUNE_C21_0 */
+	{ 18986, 0x0000 },   /* R18986 - ADCR_RETUNE_C22_1 */
+	{ 18987, 0x0000 },   /* R18987 - ADCR_RETUNE_C22_0 */
+	{ 18988, 0x0000 },   /* R18988 - ADCR_RETUNE_C23_1 */
+	{ 18989, 0x0000 },   /* R18989 - ADCR_RETUNE_C23_0 */
+	{ 18990, 0x0000 },   /* R18990 - ADCR_RETUNE_C24_1 */
+	{ 18991, 0x0000 },   /* R18991 - ADCR_RETUNE_C24_0 */
+	{ 18992, 0x0000 },   /* R18992 - ADCR_RETUNE_C25_1 */
+	{ 18993, 0x0000 },   /* R18993 - ADCR_RETUNE_C25_0 */
+	{ 18994, 0x0000 },   /* R18994 - ADCR_RETUNE_C26_1 */
+	{ 18995, 0x0000 },   /* R18995 - ADCR_RETUNE_C26_0 */
+	{ 18996, 0x0000 },   /* R18996 - ADCR_RETUNE_C27_1 */
+	{ 18997, 0x0000 },   /* R18997 - ADCR_RETUNE_C27_0 */
+	{ 18998, 0x0000 },   /* R18998 - ADCR_RETUNE_C28_1 */
+	{ 18999, 0x0000 },   /* R18999 - ADCR_RETUNE_C28_0 */
+	{ 19000, 0x0000 },   /* R19000 - ADCR_RETUNE_C29_1 */
+	{ 19001, 0x0000 },   /* R19001 - ADCR_RETUNE_C29_0 */
+	{ 19002, 0x0000 },   /* R19002 - ADCR_RETUNE_C30_1 */
+	{ 19003, 0x0000 },   /* R19003 - ADCR_RETUNE_C30_0 */
+	{ 19004, 0x0000 },   /* R19004 - ADCR_RETUNE_C31_1 */
+	{ 19005, 0x0000 },   /* R19005 - ADCR_RETUNE_C31_0 */
+	{ 19006, 0x0000 },   /* R19006 - ADCR_RETUNE_C32_1 */
+	{ 19007, 0x0000 },   /* R19007 - ADCR_RETUNE_C32_0 */
+
+	{ 19456, 0x007F },   /* R19456 - DACL_RETUNE_C1_1 */
+	{ 19457, 0xFFFF },   /* R19457 - DACL_RETUNE_C1_0 */
+	{ 19458, 0x0000 },   /* R19458 - DACL_RETUNE_C2_1 */
+	{ 19459, 0x0000 },   /* R19459 - DACL_RETUNE_C2_0 */
+	{ 19460, 0x0000 },   /* R19460 - DACL_RETUNE_C3_1 */
+	{ 19461, 0x0000 },   /* R19461 - DACL_RETUNE_C3_0 */
+	{ 19462, 0x0000 },   /* R19462 - DACL_RETUNE_C4_1 */
+	{ 19463, 0x0000 },   /* R19463 - DACL_RETUNE_C4_0 */
+	{ 19464, 0x0000 },   /* R19464 - DACL_RETUNE_C5_1 */
+	{ 19465, 0x0000 },   /* R19465 - DACL_RETUNE_C5_0 */
+	{ 19466, 0x0000 },   /* R19466 - DACL_RETUNE_C6_1 */
+	{ 19467, 0x0000 },   /* R19467 - DACL_RETUNE_C6_0 */
+	{ 19468, 0x0000 },   /* R19468 - DACL_RETUNE_C7_1 */
+	{ 19469, 0x0000 },   /* R19469 - DACL_RETUNE_C7_0 */
+	{ 19470, 0x0000 },   /* R19470 - DACL_RETUNE_C8_1 */
+	{ 19471, 0x0000 },   /* R19471 - DACL_RETUNE_C8_0 */
+	{ 19472, 0x0000 },   /* R19472 - DACL_RETUNE_C9_1 */
+	{ 19473, 0x0000 },   /* R19473 - DACL_RETUNE_C9_0 */
+	{ 19474, 0x0000 },   /* R19474 - DACL_RETUNE_C10_1 */
+	{ 19475, 0x0000 },   /* R19475 - DACL_RETUNE_C10_0 */
+	{ 19476, 0x0000 },   /* R19476 - DACL_RETUNE_C11_1 */
+	{ 19477, 0x0000 },   /* R19477 - DACL_RETUNE_C11_0 */
+	{ 19478, 0x0000 },   /* R19478 - DACL_RETUNE_C12_1 */
+	{ 19479, 0x0000 },   /* R19479 - DACL_RETUNE_C12_0 */
+	{ 19480, 0x0000 },   /* R19480 - DACL_RETUNE_C13_1 */
+	{ 19481, 0x0000 },   /* R19481 - DACL_RETUNE_C13_0 */
+	{ 19482, 0x0000 },   /* R19482 - DACL_RETUNE_C14_1 */
+	{ 19483, 0x0000 },   /* R19483 - DACL_RETUNE_C14_0 */
+	{ 19484, 0x0000 },   /* R19484 - DACL_RETUNE_C15_1 */
+	{ 19485, 0x0000 },   /* R19485 - DACL_RETUNE_C15_0 */
+	{ 19486, 0x0000 },   /* R19486 - DACL_RETUNE_C16_1 */
+	{ 19487, 0x0000 },   /* R19487 - DACL_RETUNE_C16_0 */
+	{ 19488, 0x0000 },   /* R19488 - DACL_RETUNE_C17_1 */
+	{ 19489, 0x0000 },   /* R19489 - DACL_RETUNE_C17_0 */
+	{ 19490, 0x0000 },   /* R19490 - DACL_RETUNE_C18_1 */
+	{ 19491, 0x0000 },   /* R19491 - DACL_RETUNE_C18_0 */
+	{ 19492, 0x0000 },   /* R19492 - DACL_RETUNE_C19_1 */
+	{ 19493, 0x0000 },   /* R19493 - DACL_RETUNE_C19_0 */
+	{ 19494, 0x0000 },   /* R19494 - DACL_RETUNE_C20_1 */
+	{ 19495, 0x0000 },   /* R19495 - DACL_RETUNE_C20_0 */
+	{ 19496, 0x0000 },   /* R19496 - DACL_RETUNE_C21_1 */
+	{ 19497, 0x0000 },   /* R19497 - DACL_RETUNE_C21_0 */
+	{ 19498, 0x0000 },   /* R19498 - DACL_RETUNE_C22_1 */
+	{ 19499, 0x0000 },   /* R19499 - DACL_RETUNE_C22_0 */
+	{ 19500, 0x0000 },   /* R19500 - DACL_RETUNE_C23_1 */
+	{ 19501, 0x0000 },   /* R19501 - DACL_RETUNE_C23_0 */
+	{ 19502, 0x0000 },   /* R19502 - DACL_RETUNE_C24_1 */
+	{ 19503, 0x0000 },   /* R19503 - DACL_RETUNE_C24_0 */
+	{ 19504, 0x0000 },   /* R19504 - DACL_RETUNE_C25_1 */
+	{ 19505, 0x0000 },   /* R19505 - DACL_RETUNE_C25_0 */
+	{ 19506, 0x0000 },   /* R19506 - DACL_RETUNE_C26_1 */
+	{ 19507, 0x0000 },   /* R19507 - DACL_RETUNE_C26_0 */
+	{ 19508, 0x0000 },   /* R19508 - DACL_RETUNE_C27_1 */
+	{ 19509, 0x0000 },   /* R19509 - DACL_RETUNE_C27_0 */
+	{ 19510, 0x0000 },   /* R19510 - DACL_RETUNE_C28_1 */
+	{ 19511, 0x0000 },   /* R19511 - DACL_RETUNE_C28_0 */
+	{ 19512, 0x0000 },   /* R19512 - DACL_RETUNE_C29_1 */
+	{ 19513, 0x0000 },   /* R19513 - DACL_RETUNE_C29_0 */
+	{ 19514, 0x0000 },   /* R19514 - DACL_RETUNE_C30_1 */
+	{ 19515, 0x0000 },   /* R19515 - DACL_RETUNE_C30_0 */
+	{ 19516, 0x0000 },   /* R19516 - DACL_RETUNE_C31_1 */
+	{ 19517, 0x0000 },   /* R19517 - DACL_RETUNE_C31_0 */
+	{ 19518, 0x0000 },   /* R19518 - DACL_RETUNE_C32_1 */
+	{ 19519, 0x0000 },   /* R19519 - DACL_RETUNE_C32_0 */
+
+	{ 19968, 0x0020 },   /* R19968 - RETUNEDAC_PG2_1 */
+	{ 19969, 0x0000 },   /* R19969 - RETUNEDAC_PG2_0 */
+	{ 19970, 0x0040 },   /* R19970 - RETUNEDAC_PG_1 */
+	{ 19971, 0x0000 },   /* R19971 - RETUNEDAC_PG_0 */
+
+	{ 20480, 0x007F },   /* R20480 - DACR_RETUNE_C1_1 */
+	{ 20481, 0xFFFF },   /* R20481 - DACR_RETUNE_C1_0 */
+	{ 20482, 0x0000 },   /* R20482 - DACR_RETUNE_C2_1 */
+	{ 20483, 0x0000 },   /* R20483 - DACR_RETUNE_C2_0 */
+	{ 20484, 0x0000 },   /* R20484 - DACR_RETUNE_C3_1 */
+	{ 20485, 0x0000 },   /* R20485 - DACR_RETUNE_C3_0 */
+	{ 20486, 0x0000 },   /* R20486 - DACR_RETUNE_C4_1 */
+	{ 20487, 0x0000 },   /* R20487 - DACR_RETUNE_C4_0 */
+	{ 20488, 0x0000 },   /* R20488 - DACR_RETUNE_C5_1 */
+	{ 20489, 0x0000 },   /* R20489 - DACR_RETUNE_C5_0 */
+	{ 20490, 0x0000 },   /* R20490 - DACR_RETUNE_C6_1 */
+	{ 20491, 0x0000 },   /* R20491 - DACR_RETUNE_C6_0 */
+	{ 20492, 0x0000 },   /* R20492 - DACR_RETUNE_C7_1 */
+	{ 20493, 0x0000 },   /* R20493 - DACR_RETUNE_C7_0 */
+	{ 20494, 0x0000 },   /* R20494 - DACR_RETUNE_C8_1 */
+	{ 20495, 0x0000 },   /* R20495 - DACR_RETUNE_C8_0 */
+	{ 20496, 0x0000 },   /* R20496 - DACR_RETUNE_C9_1 */
+	{ 20497, 0x0000 },   /* R20497 - DACR_RETUNE_C9_0 */
+	{ 20498, 0x0000 },   /* R20498 - DACR_RETUNE_C10_1 */
+	{ 20499, 0x0000 },   /* R20499 - DACR_RETUNE_C10_0 */
+	{ 20500, 0x0000 },   /* R20500 - DACR_RETUNE_C11_1 */
+	{ 20501, 0x0000 },   /* R20501 - DACR_RETUNE_C11_0 */
+	{ 20502, 0x0000 },   /* R20502 - DACR_RETUNE_C12_1 */
+	{ 20503, 0x0000 },   /* R20503 - DACR_RETUNE_C12_0 */
+	{ 20504, 0x0000 },   /* R20504 - DACR_RETUNE_C13_1 */
+	{ 20505, 0x0000 },   /* R20505 - DACR_RETUNE_C13_0 */
+	{ 20506, 0x0000 },   /* R20506 - DACR_RETUNE_C14_1 */
+	{ 20507, 0x0000 },   /* R20507 - DACR_RETUNE_C14_0 */
+	{ 20508, 0x0000 },   /* R20508 - DACR_RETUNE_C15_1 */
+	{ 20509, 0x0000 },   /* R20509 - DACR_RETUNE_C15_0 */
+	{ 20510, 0x0000 },   /* R20510 - DACR_RETUNE_C16_1 */
+	{ 20511, 0x0000 },   /* R20511 - DACR_RETUNE_C16_0 */
+	{ 20512, 0x0000 },   /* R20512 - DACR_RETUNE_C17_1 */
+	{ 20513, 0x0000 },   /* R20513 - DACR_RETUNE_C17_0 */
+	{ 20514, 0x0000 },   /* R20514 - DACR_RETUNE_C18_1 */
+	{ 20515, 0x0000 },   /* R20515 - DACR_RETUNE_C18_0 */
+	{ 20516, 0x0000 },   /* R20516 - DACR_RETUNE_C19_1 */
+	{ 20517, 0x0000 },   /* R20517 - DACR_RETUNE_C19_0 */
+	{ 20518, 0x0000 },   /* R20518 - DACR_RETUNE_C20_1 */
+	{ 20519, 0x0000 },   /* R20519 - DACR_RETUNE_C20_0 */
+	{ 20520, 0x0000 },   /* R20520 - DACR_RETUNE_C21_1 */
+	{ 20521, 0x0000 },   /* R20521 - DACR_RETUNE_C21_0 */
+	{ 20522, 0x0000 },   /* R20522 - DACR_RETUNE_C22_1 */
+	{ 20523, 0x0000 },   /* R20523 - DACR_RETUNE_C22_0 */
+	{ 20524, 0x0000 },   /* R20524 - DACR_RETUNE_C23_1 */
+	{ 20525, 0x0000 },   /* R20525 - DACR_RETUNE_C23_0 */
+	{ 20526, 0x0000 },   /* R20526 - DACR_RETUNE_C24_1 */
+	{ 20527, 0x0000 },   /* R20527 - DACR_RETUNE_C24_0 */
+	{ 20528, 0x0000 },   /* R20528 - DACR_RETUNE_C25_1 */
+	{ 20529, 0x0000 },   /* R20529 - DACR_RETUNE_C25_0 */
+	{ 20530, 0x0000 },   /* R20530 - DACR_RETUNE_C26_1 */
+	{ 20531, 0x0000 },   /* R20531 - DACR_RETUNE_C26_0 */
+	{ 20532, 0x0000 },   /* R20532 - DACR_RETUNE_C27_1 */
+	{ 20533, 0x0000 },   /* R20533 - DACR_RETUNE_C27_0 */
+	{ 20534, 0x0000 },   /* R20534 - DACR_RETUNE_C28_1 */
+	{ 20535, 0x0000 },   /* R20535 - DACR_RETUNE_C28_0 */
+	{ 20536, 0x0000 },   /* R20536 - DACR_RETUNE_C29_1 */
+	{ 20537, 0x0000 },   /* R20537 - DACR_RETUNE_C29_0 */
+	{ 20538, 0x0000 },   /* R20538 - DACR_RETUNE_C30_1 */
+	{ 20539, 0x0000 },   /* R20539 - DACR_RETUNE_C30_0 */
+	{ 20540, 0x0000 },   /* R20540 - DACR_RETUNE_C31_1 */
+	{ 20541, 0x0000 },   /* R20541 - DACR_RETUNE_C31_0 */
+	{ 20542, 0x0000 },   /* R20542 - DACR_RETUNE_C32_1 */
+	{ 20543, 0x0000 },   /* R20543 - DACR_RETUNE_C32_0 */
+
+	{ 20992, 0x008C },   /* R20992 - VSS_XHD2_1 */
+	{ 20993, 0x0200 },   /* R20993 - VSS_XHD2_0 */
+	{ 20994, 0x0035 },   /* R20994 - VSS_XHD3_1 */
+	{ 20995, 0x0700 },   /* R20995 - VSS_XHD3_0 */
+	{ 20996, 0x003A },   /* R20996 - VSS_XHN1_1 */
+	{ 20997, 0x4100 },   /* R20997 - VSS_XHN1_0 */
+	{ 20998, 0x008B },   /* R20998 - VSS_XHN2_1 */
+	{ 20999, 0x7D00 },   /* R20999 - VSS_XHN2_0 */
+	{ 21000, 0x003A },   /* R21000 - VSS_XHN3_1 */
+	{ 21001, 0x4100 },   /* R21001 - VSS_XHN3_0 */
+	{ 21002, 0x008C },   /* R21002 - VSS_XLA_1 */
+	{ 21003, 0xFEE8 },   /* R21003 - VSS_XLA_0 */
+	{ 21004, 0x0078 },   /* R21004 - VSS_XLB_1 */
+	{ 21005, 0x0000 },   /* R21005 - VSS_XLB_0 */
+	{ 21006, 0x003F },   /* R21006 - VSS_XLG_1 */
+	{ 21007, 0xB260 },   /* R21007 - VSS_XLG_0 */
+	{ 21008, 0x002D },   /* R21008 - VSS_PG2_1 */
+	{ 21009, 0x1818 },   /* R21009 - VSS_PG2_0 */
+	{ 21010, 0x0020 },   /* R21010 - VSS_PG_1 */
+	{ 21011, 0x0000 },   /* R21011 - VSS_PG_0 */
+	{ 21012, 0x00F1 },   /* R21012 - VSS_XTD1_1 */
+	{ 21013, 0x8340 },   /* R21013 - VSS_XTD1_0 */
+	{ 21014, 0x00FB },   /* R21014 - VSS_XTD2_1 */
+	{ 21015, 0x8300 },   /* R21015 - VSS_XTD2_0 */
+	{ 21016, 0x00EE },   /* R21016 - VSS_XTD3_1 */
+	{ 21017, 0xAEC0 },   /* R21017 - VSS_XTD3_0 */
+	{ 21018, 0x00FB },   /* R21018 - VSS_XTD4_1 */
+	{ 21019, 0xAC40 },   /* R21019 - VSS_XTD4_0 */
+	{ 21020, 0x00F1 },   /* R21020 - VSS_XTD5_1 */
+	{ 21021, 0x7F80 },   /* R21021 - VSS_XTD5_0 */
+	{ 21022, 0x00F4 },   /* R21022 - VSS_XTD6_1 */
+	{ 21023, 0x3B40 },   /* R21023 - VSS_XTD6_0 */
+	{ 21024, 0x00F5 },   /* R21024 - VSS_XTD7_1 */
+	{ 21025, 0xFB00 },   /* R21025 - VSS_XTD7_0 */
+	{ 21026, 0x00EA },   /* R21026 - VSS_XTD8_1 */
+	{ 21027, 0x10C0 },   /* R21027 - VSS_XTD8_0 */
+	{ 21028, 0x00FC },   /* R21028 - VSS_XTD9_1 */
+	{ 21029, 0xC580 },   /* R21029 - VSS_XTD9_0 */
+	{ 21030, 0x00E2 },   /* R21030 - VSS_XTD10_1 */
+	{ 21031, 0x75C0 },   /* R21031 - VSS_XTD10_0 */
+	{ 21032, 0x0004 },   /* R21032 - VSS_XTD11_1 */
+	{ 21033, 0xB480 },   /* R21033 - VSS_XTD11_0 */
+	{ 21034, 0x00D4 },   /* R21034 - VSS_XTD12_1 */
+	{ 21035, 0xF980 },   /* R21035 - VSS_XTD12_0 */
+	{ 21036, 0x0004 },   /* R21036 - VSS_XTD13_1 */
+	{ 21037, 0x9140 },   /* R21037 - VSS_XTD13_0 */
+	{ 21038, 0x00D8 },   /* R21038 - VSS_XTD14_1 */
+	{ 21039, 0xA480 },   /* R21039 - VSS_XTD14_0 */
+	{ 21040, 0x0002 },   /* R21040 - VSS_XTD15_1 */
+	{ 21041, 0x3DC0 },   /* R21041 - VSS_XTD15_0 */
+	{ 21042, 0x00CF },   /* R21042 - VSS_XTD16_1 */
+	{ 21043, 0x7A80 },   /* R21043 - VSS_XTD16_0 */
+	{ 21044, 0x00DC },   /* R21044 - VSS_XTD17_1 */
+	{ 21045, 0x0600 },   /* R21045 - VSS_XTD17_0 */
+	{ 21046, 0x00F2 },   /* R21046 - VSS_XTD18_1 */
+	{ 21047, 0xDAC0 },   /* R21047 - VSS_XTD18_0 */
+	{ 21048, 0x00BA },   /* R21048 - VSS_XTD19_1 */
+	{ 21049, 0xF340 },   /* R21049 - VSS_XTD19_0 */
+	{ 21050, 0x000A },   /* R21050 - VSS_XTD20_1 */
+	{ 21051, 0x7940 },   /* R21051 - VSS_XTD20_0 */
+	{ 21052, 0x001C },   /* R21052 - VSS_XTD21_1 */
+	{ 21053, 0x0680 },   /* R21053 - VSS_XTD21_0 */
+	{ 21054, 0x00FD },   /* R21054 - VSS_XTD22_1 */
+	{ 21055, 0x2D00 },   /* R21055 - VSS_XTD22_0 */
+	{ 21056, 0x001C },   /* R21056 - VSS_XTD23_1 */
+	{ 21057, 0xE840 },   /* R21057 - VSS_XTD23_0 */
+	{ 21058, 0x000D },   /* R21058 - VSS_XTD24_1 */
+	{ 21059, 0xDC40 },   /* R21059 - VSS_XTD24_0 */
+	{ 21060, 0x00FC },   /* R21060 - VSS_XTD25_1 */
+	{ 21061, 0x9D00 },   /* R21061 - VSS_XTD25_0 */
+	{ 21062, 0x0009 },   /* R21062 - VSS_XTD26_1 */
+	{ 21063, 0x5580 },   /* R21063 - VSS_XTD26_0 */
+	{ 21064, 0x00FE },   /* R21064 - VSS_XTD27_1 */
+	{ 21065, 0x7E80 },   /* R21065 - VSS_XTD27_0 */
+	{ 21066, 0x000E },   /* R21066 - VSS_XTD28_1 */
+	{ 21067, 0xAB40 },   /* R21067 - VSS_XTD28_0 */
+	{ 21068, 0x00F9 },   /* R21068 - VSS_XTD29_1 */
+	{ 21069, 0x9880 },   /* R21069 - VSS_XTD29_0 */
+	{ 21070, 0x0009 },   /* R21070 - VSS_XTD30_1 */
+	{ 21071, 0x87C0 },   /* R21071 - VSS_XTD30_0 */
+	{ 21072, 0x00FD },   /* R21072 - VSS_XTD31_1 */
+	{ 21073, 0x2C40 },   /* R21073 - VSS_XTD31_0 */
+	{ 21074, 0x0009 },   /* R21074 - VSS_XTD32_1 */
+	{ 21075, 0x4800 },   /* R21075 - VSS_XTD32_0 */
+	{ 21076, 0x0003 },   /* R21076 - VSS_XTS1_1 */
+	{ 21077, 0x5F40 },   /* R21077 - VSS_XTS1_0 */
+	{ 21078, 0x0000 },   /* R21078 - VSS_XTS2_1 */
+	{ 21079, 0x8700 },   /* R21079 - VSS_XTS2_0 */
+	{ 21080, 0x00FA },   /* R21080 - VSS_XTS3_1 */
+	{ 21081, 0xE4C0 },   /* R21081 - VSS_XTS3_0 */
+	{ 21082, 0x0000 },   /* R21082 - VSS_XTS4_1 */
+	{ 21083, 0x0B40 },   /* R21083 - VSS_XTS4_0 */
+	{ 21084, 0x0004 },   /* R21084 - VSS_XTS5_1 */
+	{ 21085, 0xE180 },   /* R21085 - VSS_XTS5_0 */
+	{ 21086, 0x0001 },   /* R21086 - VSS_XTS6_1 */
+	{ 21087, 0x1F40 },   /* R21087 - VSS_XTS6_0 */
+	{ 21088, 0x00F8 },   /* R21088 - VSS_XTS7_1 */
+	{ 21089, 0xB000 },   /* R21089 - VSS_XTS7_0 */
+	{ 21090, 0x00FB },   /* R21090 - VSS_XTS8_1 */
+	{ 21091, 0xCBC0 },   /* R21091 - VSS_XTS8_0 */
+	{ 21092, 0x0004 },   /* R21092 - VSS_XTS9_1 */
+	{ 21093, 0xF380 },   /* R21093 - VSS_XTS9_0 */
+	{ 21094, 0x0007 },   /* R21094 - VSS_XTS10_1 */
+	{ 21095, 0xDF40 },   /* R21095 - VSS_XTS10_0 */
+	{ 21096, 0x00FF },   /* R21096 - VSS_XTS11_1 */
+	{ 21097, 0x0700 },   /* R21097 - VSS_XTS11_0 */
+	{ 21098, 0x00EF },   /* R21098 - VSS_XTS12_1 */
+	{ 21099, 0xD700 },   /* R21099 - VSS_XTS12_0 */
+	{ 21100, 0x00FB },   /* R21100 - VSS_XTS13_1 */
+	{ 21101, 0xAF40 },   /* R21101 - VSS_XTS13_0 */
+	{ 21102, 0x0010 },   /* R21102 - VSS_XTS14_1 */
+	{ 21103, 0x8A80 },   /* R21103 - VSS_XTS14_0 */
+	{ 21104, 0x0011 },   /* R21104 - VSS_XTS15_1 */
+	{ 21105, 0x07C0 },   /* R21105 - VSS_XTS15_0 */
+	{ 21106, 0x00E0 },   /* R21106 - VSS_XTS16_1 */
+	{ 21107, 0x0800 },   /* R21107 - VSS_XTS16_0 */
+	{ 21108, 0x00D2 },   /* R21108 - VSS_XTS17_1 */
+	{ 21109, 0x7600 },   /* R21109 - VSS_XTS17_0 */
+	{ 21110, 0x0020 },   /* R21110 - VSS_XTS18_1 */
+	{ 21111, 0xCF40 },   /* R21111 - VSS_XTS18_0 */
+	{ 21112, 0x0030 },   /* R21112 - VSS_XTS19_1 */
+	{ 21113, 0x2340 },   /* R21113 - VSS_XTS19_0 */
+	{ 21114, 0x00FD },   /* R21114 - VSS_XTS20_1 */
+	{ 21115, 0x69C0 },   /* R21115 - VSS_XTS20_0 */
+	{ 21116, 0x0028 },   /* R21116 - VSS_XTS21_1 */
+	{ 21117, 0x3500 },   /* R21117 - VSS_XTS21_0 */
+	{ 21118, 0x0006 },   /* R21118 - VSS_XTS22_1 */
+	{ 21119, 0x3300 },   /* R21119 - VSS_XTS22_0 */
+	{ 21120, 0x00D9 },   /* R21120 - VSS_XTS23_1 */
+	{ 21121, 0xF6C0 },   /* R21121 - VSS_XTS23_0 */
+	{ 21122, 0x00F3 },   /* R21122 - VSS_XTS24_1 */
+	{ 21123, 0x3340 },   /* R21123 - VSS_XTS24_0 */
+	{ 21124, 0x000F },   /* R21124 - VSS_XTS25_1 */
+	{ 21125, 0x4200 },   /* R21125 - VSS_XTS25_0 */
+	{ 21126, 0x0004 },   /* R21126 - VSS_XTS26_1 */
+	{ 21127, 0x0C80 },   /* R21127 - VSS_XTS26_0 */
+	{ 21128, 0x00FB },   /* R21128 - VSS_XTS27_1 */
+	{ 21129, 0x3F80 },   /* R21129 - VSS_XTS27_0 */
+	{ 21130, 0x00F7 },   /* R21130 - VSS_XTS28_1 */
+	{ 21131, 0x57C0 },   /* R21131 - VSS_XTS28_0 */
+	{ 21132, 0x0003 },   /* R21132 - VSS_XTS29_1 */
+	{ 21133, 0x5400 },   /* R21133 - VSS_XTS29_0 */
+	{ 21134, 0x0000 },   /* R21134 - VSS_XTS30_1 */
+	{ 21135, 0xC6C0 },   /* R21135 - VSS_XTS30_0 */
+	{ 21136, 0x0003 },   /* R21136 - VSS_XTS31_1 */
+	{ 21137, 0x12C0 },   /* R21137 - VSS_XTS31_0 */
+	{ 21138, 0x00FD },   /* R21138 - VSS_XTS32_1 */
+	{ 21139, 0x8580 },   /* R21139 - VSS_XTS32_0 */
+};
+
+static bool wm8962_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8962_CLOCKING1:
+	case WM8962_CLOCKING2:
+	case WM8962_SOFTWARE_RESET:
+	case WM8962_THERMAL_SHUTDOWN_STATUS:
+	case WM8962_ADDITIONAL_CONTROL_4:
+	case WM8962_DC_SERVO_6:
+	case WM8962_INTERRUPT_STATUS_1:
+	case WM8962_INTERRUPT_STATUS_2:
+	case WM8962_DSP2_EXECCONTROL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm8962_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8962_LEFT_INPUT_VOLUME:
+	case WM8962_RIGHT_INPUT_VOLUME:
+	case WM8962_HPOUTL_VOLUME:
+	case WM8962_HPOUTR_VOLUME:
+	case WM8962_CLOCKING1:
+	case WM8962_ADC_DAC_CONTROL_1:
+	case WM8962_ADC_DAC_CONTROL_2:
+	case WM8962_AUDIO_INTERFACE_0:
+	case WM8962_CLOCKING2:
+	case WM8962_AUDIO_INTERFACE_1:
+	case WM8962_LEFT_DAC_VOLUME:
+	case WM8962_RIGHT_DAC_VOLUME:
+	case WM8962_AUDIO_INTERFACE_2:
+	case WM8962_SOFTWARE_RESET:
+	case WM8962_ALC1:
+	case WM8962_ALC2:
+	case WM8962_ALC3:
+	case WM8962_NOISE_GATE:
+	case WM8962_LEFT_ADC_VOLUME:
+	case WM8962_RIGHT_ADC_VOLUME:
+	case WM8962_ADDITIONAL_CONTROL_1:
+	case WM8962_ADDITIONAL_CONTROL_2:
+	case WM8962_PWR_MGMT_1:
+	case WM8962_PWR_MGMT_2:
+	case WM8962_ADDITIONAL_CONTROL_3:
+	case WM8962_ANTI_POP:
+	case WM8962_CLOCKING_3:
+	case WM8962_INPUT_MIXER_CONTROL_1:
+	case WM8962_LEFT_INPUT_MIXER_VOLUME:
+	case WM8962_RIGHT_INPUT_MIXER_VOLUME:
+	case WM8962_INPUT_MIXER_CONTROL_2:
+	case WM8962_INPUT_BIAS_CONTROL:
+	case WM8962_LEFT_INPUT_PGA_CONTROL:
+	case WM8962_RIGHT_INPUT_PGA_CONTROL:
+	case WM8962_SPKOUTL_VOLUME:
+	case WM8962_SPKOUTR_VOLUME:
+	case WM8962_THERMAL_SHUTDOWN_STATUS:
+	case WM8962_ADDITIONAL_CONTROL_4:
+	case WM8962_CLASS_D_CONTROL_1:
+	case WM8962_CLASS_D_CONTROL_2:
+	case WM8962_CLOCKING_4:
+	case WM8962_DAC_DSP_MIXING_1:
+	case WM8962_DAC_DSP_MIXING_2:
+	case WM8962_DC_SERVO_0:
+	case WM8962_DC_SERVO_1:
+	case WM8962_DC_SERVO_4:
+	case WM8962_DC_SERVO_6:
+	case WM8962_ANALOGUE_PGA_BIAS:
+	case WM8962_ANALOGUE_HP_0:
+	case WM8962_ANALOGUE_HP_2:
+	case WM8962_CHARGE_PUMP_1:
+	case WM8962_CHARGE_PUMP_B:
+	case WM8962_WRITE_SEQUENCER_CONTROL_1:
+	case WM8962_WRITE_SEQUENCER_CONTROL_2:
+	case WM8962_WRITE_SEQUENCER_CONTROL_3:
+	case WM8962_CONTROL_INTERFACE:
+	case WM8962_MIXER_ENABLES:
+	case WM8962_HEADPHONE_MIXER_1:
+	case WM8962_HEADPHONE_MIXER_2:
+	case WM8962_HEADPHONE_MIXER_3:
+	case WM8962_HEADPHONE_MIXER_4:
+	case WM8962_SPEAKER_MIXER_1:
+	case WM8962_SPEAKER_MIXER_2:
+	case WM8962_SPEAKER_MIXER_3:
+	case WM8962_SPEAKER_MIXER_4:
+	case WM8962_SPEAKER_MIXER_5:
+	case WM8962_BEEP_GENERATOR_1:
+	case WM8962_OSCILLATOR_TRIM_3:
+	case WM8962_OSCILLATOR_TRIM_4:
+	case WM8962_OSCILLATOR_TRIM_7:
+	case WM8962_ANALOGUE_CLOCKING1:
+	case WM8962_ANALOGUE_CLOCKING2:
+	case WM8962_ANALOGUE_CLOCKING3:
+	case WM8962_PLL_SOFTWARE_RESET:
+	case WM8962_PLL2:
+	case WM8962_PLL_4:
+	case WM8962_PLL_9:
+	case WM8962_PLL_10:
+	case WM8962_PLL_11:
+	case WM8962_PLL_12:
+	case WM8962_PLL_13:
+	case WM8962_PLL_14:
+	case WM8962_PLL_15:
+	case WM8962_PLL_16:
+	case WM8962_FLL_CONTROL_1:
+	case WM8962_FLL_CONTROL_2:
+	case WM8962_FLL_CONTROL_3:
+	case WM8962_FLL_CONTROL_5:
+	case WM8962_FLL_CONTROL_6:
+	case WM8962_FLL_CONTROL_7:
+	case WM8962_FLL_CONTROL_8:
+	case WM8962_GENERAL_TEST_1:
+	case WM8962_DF1:
+	case WM8962_DF2:
+	case WM8962_DF3:
+	case WM8962_DF4:
+	case WM8962_DF5:
+	case WM8962_DF6:
+	case WM8962_DF7:
+	case WM8962_LHPF1:
+	case WM8962_LHPF2:
+	case WM8962_THREED1:
+	case WM8962_THREED2:
+	case WM8962_THREED3:
+	case WM8962_THREED4:
+	case WM8962_DRC_1:
+	case WM8962_DRC_2:
+	case WM8962_DRC_3:
+	case WM8962_DRC_4:
+	case WM8962_DRC_5:
+	case WM8962_TLOOPBACK:
+	case WM8962_EQ1:
+	case WM8962_EQ2:
+	case WM8962_EQ3:
+	case WM8962_EQ4:
+	case WM8962_EQ5:
+	case WM8962_EQ6:
+	case WM8962_EQ7:
+	case WM8962_EQ8:
+	case WM8962_EQ9:
+	case WM8962_EQ10:
+	case WM8962_EQ11:
+	case WM8962_EQ12:
+	case WM8962_EQ13:
+	case WM8962_EQ14:
+	case WM8962_EQ15:
+	case WM8962_EQ16:
+	case WM8962_EQ17:
+	case WM8962_EQ18:
+	case WM8962_EQ19:
+	case WM8962_EQ20:
+	case WM8962_EQ21:
+	case WM8962_EQ22:
+	case WM8962_EQ23:
+	case WM8962_EQ24:
+	case WM8962_EQ25:
+	case WM8962_EQ26:
+	case WM8962_EQ27:
+	case WM8962_EQ28:
+	case WM8962_EQ29:
+	case WM8962_EQ30:
+	case WM8962_EQ31:
+	case WM8962_EQ32:
+	case WM8962_EQ33:
+	case WM8962_EQ34:
+	case WM8962_EQ35:
+	case WM8962_EQ36:
+	case WM8962_EQ37:
+	case WM8962_EQ38:
+	case WM8962_EQ39:
+	case WM8962_EQ40:
+	case WM8962_EQ41:
+	case WM8962_GPIO_BASE:
+	case WM8962_GPIO_2:
+	case WM8962_GPIO_3:
+	case WM8962_GPIO_5:
+	case WM8962_GPIO_6:
+	case WM8962_INTERRUPT_STATUS_1:
+	case WM8962_INTERRUPT_STATUS_2:
+	case WM8962_INTERRUPT_STATUS_1_MASK:
+	case WM8962_INTERRUPT_STATUS_2_MASK:
+	case WM8962_INTERRUPT_CONTROL:
+	case WM8962_IRQ_DEBOUNCE:
+	case WM8962_MICINT_SOURCE_POL:
+	case WM8962_DSP2_POWER_MANAGEMENT:
+	case WM8962_DSP2_EXECCONTROL:
+	case WM8962_DSP2_INSTRUCTION_RAM_0:
+	case WM8962_DSP2_ADDRESS_RAM_2:
+	case WM8962_DSP2_ADDRESS_RAM_1:
+	case WM8962_DSP2_ADDRESS_RAM_0:
+	case WM8962_DSP2_DATA1_RAM_1:
+	case WM8962_DSP2_DATA1_RAM_0:
+	case WM8962_DSP2_DATA2_RAM_1:
+	case WM8962_DSP2_DATA2_RAM_0:
+	case WM8962_DSP2_DATA3_RAM_1:
+	case WM8962_DSP2_DATA3_RAM_0:
+	case WM8962_DSP2_COEFF_RAM_0:
+	case WM8962_RETUNEADC_SHARED_COEFF_1:
+	case WM8962_RETUNEADC_SHARED_COEFF_0:
+	case WM8962_RETUNEDAC_SHARED_COEFF_1:
+	case WM8962_RETUNEDAC_SHARED_COEFF_0:
+	case WM8962_SOUNDSTAGE_ENABLES_1:
+	case WM8962_SOUNDSTAGE_ENABLES_0:
+	case WM8962_HDBASS_AI_1:
+	case WM8962_HDBASS_AI_0:
+	case WM8962_HDBASS_AR_1:
+	case WM8962_HDBASS_AR_0:
+	case WM8962_HDBASS_B_1:
+	case WM8962_HDBASS_B_0:
+	case WM8962_HDBASS_K_1:
+	case WM8962_HDBASS_K_0:
+	case WM8962_HDBASS_N1_1:
+	case WM8962_HDBASS_N1_0:
+	case WM8962_HDBASS_N2_1:
+	case WM8962_HDBASS_N2_0:
+	case WM8962_HDBASS_N3_1:
+	case WM8962_HDBASS_N3_0:
+	case WM8962_HDBASS_N4_1:
+	case WM8962_HDBASS_N4_0:
+	case WM8962_HDBASS_N5_1:
+	case WM8962_HDBASS_N5_0:
+	case WM8962_HDBASS_X1_1:
+	case WM8962_HDBASS_X1_0:
+	case WM8962_HDBASS_X2_1:
+	case WM8962_HDBASS_X2_0:
+	case WM8962_HDBASS_X3_1:
+	case WM8962_HDBASS_X3_0:
+	case WM8962_HDBASS_ATK_1:
+	case WM8962_HDBASS_ATK_0:
+	case WM8962_HDBASS_DCY_1:
+	case WM8962_HDBASS_DCY_0:
+	case WM8962_HDBASS_PG_1:
+	case WM8962_HDBASS_PG_0:
+	case WM8962_HPF_C_1:
+	case WM8962_HPF_C_0:
+	case WM8962_ADCL_RETUNE_C1_1:
+	case WM8962_ADCL_RETUNE_C1_0:
+	case WM8962_ADCL_RETUNE_C2_1:
+	case WM8962_ADCL_RETUNE_C2_0:
+	case WM8962_ADCL_RETUNE_C3_1:
+	case WM8962_ADCL_RETUNE_C3_0:
+	case WM8962_ADCL_RETUNE_C4_1:
+	case WM8962_ADCL_RETUNE_C4_0:
+	case WM8962_ADCL_RETUNE_C5_1:
+	case WM8962_ADCL_RETUNE_C5_0:
+	case WM8962_ADCL_RETUNE_C6_1:
+	case WM8962_ADCL_RETUNE_C6_0:
+	case WM8962_ADCL_RETUNE_C7_1:
+	case WM8962_ADCL_RETUNE_C7_0:
+	case WM8962_ADCL_RETUNE_C8_1:
+	case WM8962_ADCL_RETUNE_C8_0:
+	case WM8962_ADCL_RETUNE_C9_1:
+	case WM8962_ADCL_RETUNE_C9_0:
+	case WM8962_ADCL_RETUNE_C10_1:
+	case WM8962_ADCL_RETUNE_C10_0:
+	case WM8962_ADCL_RETUNE_C11_1:
+	case WM8962_ADCL_RETUNE_C11_0:
+	case WM8962_ADCL_RETUNE_C12_1:
+	case WM8962_ADCL_RETUNE_C12_0:
+	case WM8962_ADCL_RETUNE_C13_1:
+	case WM8962_ADCL_RETUNE_C13_0:
+	case WM8962_ADCL_RETUNE_C14_1:
+	case WM8962_ADCL_RETUNE_C14_0:
+	case WM8962_ADCL_RETUNE_C15_1:
+	case WM8962_ADCL_RETUNE_C15_0:
+	case WM8962_ADCL_RETUNE_C16_1:
+	case WM8962_ADCL_RETUNE_C16_0:
+	case WM8962_ADCL_RETUNE_C17_1:
+	case WM8962_ADCL_RETUNE_C17_0:
+	case WM8962_ADCL_RETUNE_C18_1:
+	case WM8962_ADCL_RETUNE_C18_0:
+	case WM8962_ADCL_RETUNE_C19_1:
+	case WM8962_ADCL_RETUNE_C19_0:
+	case WM8962_ADCL_RETUNE_C20_1:
+	case WM8962_ADCL_RETUNE_C20_0:
+	case WM8962_ADCL_RETUNE_C21_1:
+	case WM8962_ADCL_RETUNE_C21_0:
+	case WM8962_ADCL_RETUNE_C22_1:
+	case WM8962_ADCL_RETUNE_C22_0:
+	case WM8962_ADCL_RETUNE_C23_1:
+	case WM8962_ADCL_RETUNE_C23_0:
+	case WM8962_ADCL_RETUNE_C24_1:
+	case WM8962_ADCL_RETUNE_C24_0:
+	case WM8962_ADCL_RETUNE_C25_1:
+	case WM8962_ADCL_RETUNE_C25_0:
+	case WM8962_ADCL_RETUNE_C26_1:
+	case WM8962_ADCL_RETUNE_C26_0:
+	case WM8962_ADCL_RETUNE_C27_1:
+	case WM8962_ADCL_RETUNE_C27_0:
+	case WM8962_ADCL_RETUNE_C28_1:
+	case WM8962_ADCL_RETUNE_C28_0:
+	case WM8962_ADCL_RETUNE_C29_1:
+	case WM8962_ADCL_RETUNE_C29_0:
+	case WM8962_ADCL_RETUNE_C30_1:
+	case WM8962_ADCL_RETUNE_C30_0:
+	case WM8962_ADCL_RETUNE_C31_1:
+	case WM8962_ADCL_RETUNE_C31_0:
+	case WM8962_ADCL_RETUNE_C32_1:
+	case WM8962_ADCL_RETUNE_C32_0:
+	case WM8962_RETUNEADC_PG2_1:
+	case WM8962_RETUNEADC_PG2_0:
+	case WM8962_RETUNEADC_PG_1:
+	case WM8962_RETUNEADC_PG_0:
+	case WM8962_ADCR_RETUNE_C1_1:
+	case WM8962_ADCR_RETUNE_C1_0:
+	case WM8962_ADCR_RETUNE_C2_1:
+	case WM8962_ADCR_RETUNE_C2_0:
+	case WM8962_ADCR_RETUNE_C3_1:
+	case WM8962_ADCR_RETUNE_C3_0:
+	case WM8962_ADCR_RETUNE_C4_1:
+	case WM8962_ADCR_RETUNE_C4_0:
+	case WM8962_ADCR_RETUNE_C5_1:
+	case WM8962_ADCR_RETUNE_C5_0:
+	case WM8962_ADCR_RETUNE_C6_1:
+	case WM8962_ADCR_RETUNE_C6_0:
+	case WM8962_ADCR_RETUNE_C7_1:
+	case WM8962_ADCR_RETUNE_C7_0:
+	case WM8962_ADCR_RETUNE_C8_1:
+	case WM8962_ADCR_RETUNE_C8_0:
+	case WM8962_ADCR_RETUNE_C9_1:
+	case WM8962_ADCR_RETUNE_C9_0:
+	case WM8962_ADCR_RETUNE_C10_1:
+	case WM8962_ADCR_RETUNE_C10_0:
+	case WM8962_ADCR_RETUNE_C11_1:
+	case WM8962_ADCR_RETUNE_C11_0:
+	case WM8962_ADCR_RETUNE_C12_1:
+	case WM8962_ADCR_RETUNE_C12_0:
+	case WM8962_ADCR_RETUNE_C13_1:
+	case WM8962_ADCR_RETUNE_C13_0:
+	case WM8962_ADCR_RETUNE_C14_1:
+	case WM8962_ADCR_RETUNE_C14_0:
+	case WM8962_ADCR_RETUNE_C15_1:
+	case WM8962_ADCR_RETUNE_C15_0:
+	case WM8962_ADCR_RETUNE_C16_1:
+	case WM8962_ADCR_RETUNE_C16_0:
+	case WM8962_ADCR_RETUNE_C17_1:
+	case WM8962_ADCR_RETUNE_C17_0:
+	case WM8962_ADCR_RETUNE_C18_1:
+	case WM8962_ADCR_RETUNE_C18_0:
+	case WM8962_ADCR_RETUNE_C19_1:
+	case WM8962_ADCR_RETUNE_C19_0:
+	case WM8962_ADCR_RETUNE_C20_1:
+	case WM8962_ADCR_RETUNE_C20_0:
+	case WM8962_ADCR_RETUNE_C21_1:
+	case WM8962_ADCR_RETUNE_C21_0:
+	case WM8962_ADCR_RETUNE_C22_1:
+	case WM8962_ADCR_RETUNE_C22_0:
+	case WM8962_ADCR_RETUNE_C23_1:
+	case WM8962_ADCR_RETUNE_C23_0:
+	case WM8962_ADCR_RETUNE_C24_1:
+	case WM8962_ADCR_RETUNE_C24_0:
+	case WM8962_ADCR_RETUNE_C25_1:
+	case WM8962_ADCR_RETUNE_C25_0:
+	case WM8962_ADCR_RETUNE_C26_1:
+	case WM8962_ADCR_RETUNE_C26_0:
+	case WM8962_ADCR_RETUNE_C27_1:
+	case WM8962_ADCR_RETUNE_C27_0:
+	case WM8962_ADCR_RETUNE_C28_1:
+	case WM8962_ADCR_RETUNE_C28_0:
+	case WM8962_ADCR_RETUNE_C29_1:
+	case WM8962_ADCR_RETUNE_C29_0:
+	case WM8962_ADCR_RETUNE_C30_1:
+	case WM8962_ADCR_RETUNE_C30_0:
+	case WM8962_ADCR_RETUNE_C31_1:
+	case WM8962_ADCR_RETUNE_C31_0:
+	case WM8962_ADCR_RETUNE_C32_1:
+	case WM8962_ADCR_RETUNE_C32_0:
+	case WM8962_DACL_RETUNE_C1_1:
+	case WM8962_DACL_RETUNE_C1_0:
+	case WM8962_DACL_RETUNE_C2_1:
+	case WM8962_DACL_RETUNE_C2_0:
+	case WM8962_DACL_RETUNE_C3_1:
+	case WM8962_DACL_RETUNE_C3_0:
+	case WM8962_DACL_RETUNE_C4_1:
+	case WM8962_DACL_RETUNE_C4_0:
+	case WM8962_DACL_RETUNE_C5_1:
+	case WM8962_DACL_RETUNE_C5_0:
+	case WM8962_DACL_RETUNE_C6_1:
+	case WM8962_DACL_RETUNE_C6_0:
+	case WM8962_DACL_RETUNE_C7_1:
+	case WM8962_DACL_RETUNE_C7_0:
+	case WM8962_DACL_RETUNE_C8_1:
+	case WM8962_DACL_RETUNE_C8_0:
+	case WM8962_DACL_RETUNE_C9_1:
+	case WM8962_DACL_RETUNE_C9_0:
+	case WM8962_DACL_RETUNE_C10_1:
+	case WM8962_DACL_RETUNE_C10_0:
+	case WM8962_DACL_RETUNE_C11_1:
+	case WM8962_DACL_RETUNE_C11_0:
+	case WM8962_DACL_RETUNE_C12_1:
+	case WM8962_DACL_RETUNE_C12_0:
+	case WM8962_DACL_RETUNE_C13_1:
+	case WM8962_DACL_RETUNE_C13_0:
+	case WM8962_DACL_RETUNE_C14_1:
+	case WM8962_DACL_RETUNE_C14_0:
+	case WM8962_DACL_RETUNE_C15_1:
+	case WM8962_DACL_RETUNE_C15_0:
+	case WM8962_DACL_RETUNE_C16_1:
+	case WM8962_DACL_RETUNE_C16_0:
+	case WM8962_DACL_RETUNE_C17_1:
+	case WM8962_DACL_RETUNE_C17_0:
+	case WM8962_DACL_RETUNE_C18_1:
+	case WM8962_DACL_RETUNE_C18_0:
+	case WM8962_DACL_RETUNE_C19_1:
+	case WM8962_DACL_RETUNE_C19_0:
+	case WM8962_DACL_RETUNE_C20_1:
+	case WM8962_DACL_RETUNE_C20_0:
+	case WM8962_DACL_RETUNE_C21_1:
+	case WM8962_DACL_RETUNE_C21_0:
+	case WM8962_DACL_RETUNE_C22_1:
+	case WM8962_DACL_RETUNE_C22_0:
+	case WM8962_DACL_RETUNE_C23_1:
+	case WM8962_DACL_RETUNE_C23_0:
+	case WM8962_DACL_RETUNE_C24_1:
+	case WM8962_DACL_RETUNE_C24_0:
+	case WM8962_DACL_RETUNE_C25_1:
+	case WM8962_DACL_RETUNE_C25_0:
+	case WM8962_DACL_RETUNE_C26_1:
+	case WM8962_DACL_RETUNE_C26_0:
+	case WM8962_DACL_RETUNE_C27_1:
+	case WM8962_DACL_RETUNE_C27_0:
+	case WM8962_DACL_RETUNE_C28_1:
+	case WM8962_DACL_RETUNE_C28_0:
+	case WM8962_DACL_RETUNE_C29_1:
+	case WM8962_DACL_RETUNE_C29_0:
+	case WM8962_DACL_RETUNE_C30_1:
+	case WM8962_DACL_RETUNE_C30_0:
+	case WM8962_DACL_RETUNE_C31_1:
+	case WM8962_DACL_RETUNE_C31_0:
+	case WM8962_DACL_RETUNE_C32_1:
+	case WM8962_DACL_RETUNE_C32_0:
+	case WM8962_RETUNEDAC_PG2_1:
+	case WM8962_RETUNEDAC_PG2_0:
+	case WM8962_RETUNEDAC_PG_1:
+	case WM8962_RETUNEDAC_PG_0:
+	case WM8962_DACR_RETUNE_C1_1:
+	case WM8962_DACR_RETUNE_C1_0:
+	case WM8962_DACR_RETUNE_C2_1:
+	case WM8962_DACR_RETUNE_C2_0:
+	case WM8962_DACR_RETUNE_C3_1:
+	case WM8962_DACR_RETUNE_C3_0:
+	case WM8962_DACR_RETUNE_C4_1:
+	case WM8962_DACR_RETUNE_C4_0:
+	case WM8962_DACR_RETUNE_C5_1:
+	case WM8962_DACR_RETUNE_C5_0:
+	case WM8962_DACR_RETUNE_C6_1:
+	case WM8962_DACR_RETUNE_C6_0:
+	case WM8962_DACR_RETUNE_C7_1:
+	case WM8962_DACR_RETUNE_C7_0:
+	case WM8962_DACR_RETUNE_C8_1:
+	case WM8962_DACR_RETUNE_C8_0:
+	case WM8962_DACR_RETUNE_C9_1:
+	case WM8962_DACR_RETUNE_C9_0:
+	case WM8962_DACR_RETUNE_C10_1:
+	case WM8962_DACR_RETUNE_C10_0:
+	case WM8962_DACR_RETUNE_C11_1:
+	case WM8962_DACR_RETUNE_C11_0:
+	case WM8962_DACR_RETUNE_C12_1:
+	case WM8962_DACR_RETUNE_C12_0:
+	case WM8962_DACR_RETUNE_C13_1:
+	case WM8962_DACR_RETUNE_C13_0:
+	case WM8962_DACR_RETUNE_C14_1:
+	case WM8962_DACR_RETUNE_C14_0:
+	case WM8962_DACR_RETUNE_C15_1:
+	case WM8962_DACR_RETUNE_C15_0:
+	case WM8962_DACR_RETUNE_C16_1:
+	case WM8962_DACR_RETUNE_C16_0:
+	case WM8962_DACR_RETUNE_C17_1:
+	case WM8962_DACR_RETUNE_C17_0:
+	case WM8962_DACR_RETUNE_C18_1:
+	case WM8962_DACR_RETUNE_C18_0:
+	case WM8962_DACR_RETUNE_C19_1:
+	case WM8962_DACR_RETUNE_C19_0:
+	case WM8962_DACR_RETUNE_C20_1:
+	case WM8962_DACR_RETUNE_C20_0:
+	case WM8962_DACR_RETUNE_C21_1:
+	case WM8962_DACR_RETUNE_C21_0:
+	case WM8962_DACR_RETUNE_C22_1:
+	case WM8962_DACR_RETUNE_C22_0:
+	case WM8962_DACR_RETUNE_C23_1:
+	case WM8962_DACR_RETUNE_C23_0:
+	case WM8962_DACR_RETUNE_C24_1:
+	case WM8962_DACR_RETUNE_C24_0:
+	case WM8962_DACR_RETUNE_C25_1:
+	case WM8962_DACR_RETUNE_C25_0:
+	case WM8962_DACR_RETUNE_C26_1:
+	case WM8962_DACR_RETUNE_C26_0:
+	case WM8962_DACR_RETUNE_C27_1:
+	case WM8962_DACR_RETUNE_C27_0:
+	case WM8962_DACR_RETUNE_C28_1:
+	case WM8962_DACR_RETUNE_C28_0:
+	case WM8962_DACR_RETUNE_C29_1:
+	case WM8962_DACR_RETUNE_C29_0:
+	case WM8962_DACR_RETUNE_C30_1:
+	case WM8962_DACR_RETUNE_C30_0:
+	case WM8962_DACR_RETUNE_C31_1:
+	case WM8962_DACR_RETUNE_C31_0:
+	case WM8962_DACR_RETUNE_C32_1:
+	case WM8962_DACR_RETUNE_C32_0:
+	case WM8962_VSS_XHD2_1:
+	case WM8962_VSS_XHD2_0:
+	case WM8962_VSS_XHD3_1:
+	case WM8962_VSS_XHD3_0:
+	case WM8962_VSS_XHN1_1:
+	case WM8962_VSS_XHN1_0:
+	case WM8962_VSS_XHN2_1:
+	case WM8962_VSS_XHN2_0:
+	case WM8962_VSS_XHN3_1:
+	case WM8962_VSS_XHN3_0:
+	case WM8962_VSS_XLA_1:
+	case WM8962_VSS_XLA_0:
+	case WM8962_VSS_XLB_1:
+	case WM8962_VSS_XLB_0:
+	case WM8962_VSS_XLG_1:
+	case WM8962_VSS_XLG_0:
+	case WM8962_VSS_PG2_1:
+	case WM8962_VSS_PG2_0:
+	case WM8962_VSS_PG_1:
+	case WM8962_VSS_PG_0:
+	case WM8962_VSS_XTD1_1:
+	case WM8962_VSS_XTD1_0:
+	case WM8962_VSS_XTD2_1:
+	case WM8962_VSS_XTD2_0:
+	case WM8962_VSS_XTD3_1:
+	case WM8962_VSS_XTD3_0:
+	case WM8962_VSS_XTD4_1:
+	case WM8962_VSS_XTD4_0:
+	case WM8962_VSS_XTD5_1:
+	case WM8962_VSS_XTD5_0:
+	case WM8962_VSS_XTD6_1:
+	case WM8962_VSS_XTD6_0:
+	case WM8962_VSS_XTD7_1:
+	case WM8962_VSS_XTD7_0:
+	case WM8962_VSS_XTD8_1:
+	case WM8962_VSS_XTD8_0:
+	case WM8962_VSS_XTD9_1:
+	case WM8962_VSS_XTD9_0:
+	case WM8962_VSS_XTD10_1:
+	case WM8962_VSS_XTD10_0:
+	case WM8962_VSS_XTD11_1:
+	case WM8962_VSS_XTD11_0:
+	case WM8962_VSS_XTD12_1:
+	case WM8962_VSS_XTD12_0:
+	case WM8962_VSS_XTD13_1:
+	case WM8962_VSS_XTD13_0:
+	case WM8962_VSS_XTD14_1:
+	case WM8962_VSS_XTD14_0:
+	case WM8962_VSS_XTD15_1:
+	case WM8962_VSS_XTD15_0:
+	case WM8962_VSS_XTD16_1:
+	case WM8962_VSS_XTD16_0:
+	case WM8962_VSS_XTD17_1:
+	case WM8962_VSS_XTD17_0:
+	case WM8962_VSS_XTD18_1:
+	case WM8962_VSS_XTD18_0:
+	case WM8962_VSS_XTD19_1:
+	case WM8962_VSS_XTD19_0:
+	case WM8962_VSS_XTD20_1:
+	case WM8962_VSS_XTD20_0:
+	case WM8962_VSS_XTD21_1:
+	case WM8962_VSS_XTD21_0:
+	case WM8962_VSS_XTD22_1:
+	case WM8962_VSS_XTD22_0:
+	case WM8962_VSS_XTD23_1:
+	case WM8962_VSS_XTD23_0:
+	case WM8962_VSS_XTD24_1:
+	case WM8962_VSS_XTD24_0:
+	case WM8962_VSS_XTD25_1:
+	case WM8962_VSS_XTD25_0:
+	case WM8962_VSS_XTD26_1:
+	case WM8962_VSS_XTD26_0:
+	case WM8962_VSS_XTD27_1:
+	case WM8962_VSS_XTD27_0:
+	case WM8962_VSS_XTD28_1:
+	case WM8962_VSS_XTD28_0:
+	case WM8962_VSS_XTD29_1:
+	case WM8962_VSS_XTD29_0:
+	case WM8962_VSS_XTD30_1:
+	case WM8962_VSS_XTD30_0:
+	case WM8962_VSS_XTD31_1:
+	case WM8962_VSS_XTD31_0:
+	case WM8962_VSS_XTD32_1:
+	case WM8962_VSS_XTD32_0:
+	case WM8962_VSS_XTS1_1:
+	case WM8962_VSS_XTS1_0:
+	case WM8962_VSS_XTS2_1:
+	case WM8962_VSS_XTS2_0:
+	case WM8962_VSS_XTS3_1:
+	case WM8962_VSS_XTS3_0:
+	case WM8962_VSS_XTS4_1:
+	case WM8962_VSS_XTS4_0:
+	case WM8962_VSS_XTS5_1:
+	case WM8962_VSS_XTS5_0:
+	case WM8962_VSS_XTS6_1:
+	case WM8962_VSS_XTS6_0:
+	case WM8962_VSS_XTS7_1:
+	case WM8962_VSS_XTS7_0:
+	case WM8962_VSS_XTS8_1:
+	case WM8962_VSS_XTS8_0:
+	case WM8962_VSS_XTS9_1:
+	case WM8962_VSS_XTS9_0:
+	case WM8962_VSS_XTS10_1:
+	case WM8962_VSS_XTS10_0:
+	case WM8962_VSS_XTS11_1:
+	case WM8962_VSS_XTS11_0:
+	case WM8962_VSS_XTS12_1:
+	case WM8962_VSS_XTS12_0:
+	case WM8962_VSS_XTS13_1:
+	case WM8962_VSS_XTS13_0:
+	case WM8962_VSS_XTS14_1:
+	case WM8962_VSS_XTS14_0:
+	case WM8962_VSS_XTS15_1:
+	case WM8962_VSS_XTS15_0:
+	case WM8962_VSS_XTS16_1:
+	case WM8962_VSS_XTS16_0:
+	case WM8962_VSS_XTS17_1:
+	case WM8962_VSS_XTS17_0:
+	case WM8962_VSS_XTS18_1:
+	case WM8962_VSS_XTS18_0:
+	case WM8962_VSS_XTS19_1:
+	case WM8962_VSS_XTS19_0:
+	case WM8962_VSS_XTS20_1:
+	case WM8962_VSS_XTS20_0:
+	case WM8962_VSS_XTS21_1:
+	case WM8962_VSS_XTS21_0:
+	case WM8962_VSS_XTS22_1:
+	case WM8962_VSS_XTS22_0:
+	case WM8962_VSS_XTS23_1:
+	case WM8962_VSS_XTS23_0:
+	case WM8962_VSS_XTS24_1:
+	case WM8962_VSS_XTS24_0:
+	case WM8962_VSS_XTS25_1:
+	case WM8962_VSS_XTS25_0:
+	case WM8962_VSS_XTS26_1:
+	case WM8962_VSS_XTS26_0:
+	case WM8962_VSS_XTS27_1:
+	case WM8962_VSS_XTS27_0:
+	case WM8962_VSS_XTS28_1:
+	case WM8962_VSS_XTS28_0:
+	case WM8962_VSS_XTS29_1:
+	case WM8962_VSS_XTS29_0:
+	case WM8962_VSS_XTS30_1:
+	case WM8962_VSS_XTS30_0:
+	case WM8962_VSS_XTS31_1:
+	case WM8962_VSS_XTS31_0:
+	case WM8962_VSS_XTS32_1:
+	case WM8962_VSS_XTS32_0:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int wm8962_reset(struct wm8962_priv *wm8962)
+{
+	int ret;
+
+	ret = regmap_write(wm8962->regmap, WM8962_SOFTWARE_RESET, 0x6243);
+	if (ret != 0)
+		return ret;
+
+	return regmap_write(wm8962->regmap, WM8962_PLL_SOFTWARE_RESET, 0);
+}
+
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, -2325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(mixin_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_RANGE(mixinpga_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
+	2, 2, TLV_DB_SCALE_ITEM(1300, 1300, 0),
+	3, 4, TLV_DB_SCALE_ITEM(1800, 200, 0),
+	5, 5, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	6, 7, TLV_DB_SCALE_ITEM(2700, 300, 0)
+);
+static const DECLARE_TLV_DB_SCALE(beep_tlv, -9600, 600, 1);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(inmix_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(hp_tlv, -700, 100, 0);
+static const DECLARE_TLV_DB_RANGE(classd_tlv,
+	0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
+	7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0)
+);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+
+static int wm8962_dsp2_write_config(struct snd_soc_component *component)
+{
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+
+	return regcache_sync_region(wm8962->regmap,
+				    WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER);
+}
+
+static int wm8962_dsp2_set_enable(struct snd_soc_component *component, u16 val)
+{
+	u16 adcl = snd_soc_component_read32(component, WM8962_LEFT_ADC_VOLUME);
+	u16 adcr = snd_soc_component_read32(component, WM8962_RIGHT_ADC_VOLUME);
+	u16 dac = snd_soc_component_read32(component, WM8962_ADC_DAC_CONTROL_1);
+
+	/* Mute the ADCs and DACs */
+	snd_soc_component_write(component, WM8962_LEFT_ADC_VOLUME, 0);
+	snd_soc_component_write(component, WM8962_RIGHT_ADC_VOLUME, WM8962_ADC_VU);
+	snd_soc_component_update_bits(component, WM8962_ADC_DAC_CONTROL_1,
+			    WM8962_DAC_MUTE, WM8962_DAC_MUTE);
+
+	snd_soc_component_write(component, WM8962_SOUNDSTAGE_ENABLES_0, val);
+
+	/* Restore the ADCs and DACs */
+	snd_soc_component_write(component, WM8962_LEFT_ADC_VOLUME, adcl);
+	snd_soc_component_write(component, WM8962_RIGHT_ADC_VOLUME, adcr);
+	snd_soc_component_update_bits(component, WM8962_ADC_DAC_CONTROL_1,
+			    WM8962_DAC_MUTE, dac);
+
+	return 0;
+}
+
+static int wm8962_dsp2_start(struct snd_soc_component *component)
+{
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+
+	wm8962_dsp2_write_config(component);
+
+	snd_soc_component_write(component, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_RUNR);
+
+	wm8962_dsp2_set_enable(component, wm8962->dsp2_ena);
+
+	return 0;
+}
+
+static int wm8962_dsp2_stop(struct snd_soc_component *component)
+{
+	wm8962_dsp2_set_enable(component, 0);
+
+	snd_soc_component_write(component, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_STOP);
+
+	return 0;
+}
+
+#define WM8962_DSP2_ENABLE(xname, xshift) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = wm8962_dsp2_ena_info, \
+	.get = wm8962_dsp2_ena_get, .put = wm8962_dsp2_ena_put, \
+	.private_value = xshift }
+
+static int wm8962_dsp2_ena_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+
+	return 0;
+}
+
+static int wm8962_dsp2_ena_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	int shift = kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.integer.value[0] = !!(wm8962->dsp2_ena & 1 << shift);
+
+	return 0;
+}
+
+static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	int shift = kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+	int old = wm8962->dsp2_ena;
+	int ret = 0;
+	int dsp2_running = snd_soc_component_read32(component, WM8962_DSP2_POWER_MANAGEMENT) &
+		WM8962_DSP2_ENA;
+
+	mutex_lock(&wm8962->dsp2_ena_lock);
+
+	if (ucontrol->value.integer.value[0])
+		wm8962->dsp2_ena |= 1 << shift;
+	else
+		wm8962->dsp2_ena &= ~(1 << shift);
+
+	if (wm8962->dsp2_ena == old)
+		goto out;
+
+	ret = 1;
+
+	if (dsp2_running) {
+		if (wm8962->dsp2_ena)
+			wm8962_dsp2_set_enable(component, wm8962->dsp2_ena);
+		else
+			wm8962_dsp2_stop(component);
+	}
+
+out:
+	mutex_unlock(&wm8962->dsp2_ena_lock);
+
+	return ret;
+}
+
+/* The VU bits for the headphones are in a different register to the mute
+ * bits and only take effect on the PGA if it is actually powered.
+ */
+static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int ret;
+
+	/* Apply the update (if any) */
+        ret = snd_soc_put_volsw(kcontrol, ucontrol);
+	if (ret == 0)
+		return 0;
+
+	/* If the left PGA is enabled hit that VU bit... */
+	ret = snd_soc_component_read32(component, WM8962_PWR_MGMT_2);
+	if (ret & WM8962_HPOUTL_PGA_ENA) {
+		snd_soc_component_write(component, WM8962_HPOUTL_VOLUME,
+			      snd_soc_component_read32(component, WM8962_HPOUTL_VOLUME));
+		return 1;
+	}
+
+	/* ...otherwise the right.  The VU is stereo. */
+	if (ret & WM8962_HPOUTR_PGA_ENA)
+		snd_soc_component_write(component, WM8962_HPOUTR_VOLUME,
+			      snd_soc_component_read32(component, WM8962_HPOUTR_VOLUME));
+
+	return 1;
+}
+
+/* The VU bits for the speakers are in a different register to the mute
+ * bits and only take effect on the PGA if it is actually powered.
+ */
+static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int ret;
+
+	/* Apply the update (if any) */
+        ret = snd_soc_put_volsw(kcontrol, ucontrol);
+	if (ret == 0)
+		return 0;
+
+	/* If the left PGA is enabled hit that VU bit... */
+	ret = snd_soc_component_read32(component, WM8962_PWR_MGMT_2);
+	if (ret & WM8962_SPKOUTL_PGA_ENA) {
+		snd_soc_component_write(component, WM8962_SPKOUTL_VOLUME,
+			      snd_soc_component_read32(component, WM8962_SPKOUTL_VOLUME));
+		return 1;
+	}
+
+	/* ...otherwise the right.  The VU is stereo. */
+	if (ret & WM8962_SPKOUTR_PGA_ENA)
+		snd_soc_component_write(component, WM8962_SPKOUTR_VOLUME,
+			      snd_soc_component_read32(component, WM8962_SPKOUTR_VOLUME));
+
+	return 1;
+}
+
+static const char *cap_hpf_mode_text[] = {
+	"Hi-fi", "Application"
+};
+
+static SOC_ENUM_SINGLE_DECL(cap_hpf_mode,
+			    WM8962_ADC_DAC_CONTROL_2, 10, cap_hpf_mode_text);
+
+
+static const char *cap_lhpf_mode_text[] = {
+	"LPF", "HPF"
+};
+
+static SOC_ENUM_SINGLE_DECL(cap_lhpf_mode,
+			    WM8962_LHPF1, 1, cap_lhpf_mode_text);
+
+static const struct snd_kcontrol_new wm8962_snd_controls[] = {
+SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1),
+
+SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 6, 7, 0,
+	       mixin_tlv),
+SOC_SINGLE_TLV("MIXINL PGA Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 3, 7, 0,
+	       mixinpga_tlv),
+SOC_SINGLE_TLV("MIXINL IN3L Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 0, 7, 0,
+	       mixin_tlv),
+
+SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 6, 7, 0,
+	       mixin_tlv),
+SOC_SINGLE_TLV("MIXINR PGA Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 3, 7, 0,
+	       mixinpga_tlv),
+SOC_SINGLE_TLV("MIXINR IN3R Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 0, 7, 0,
+	       mixin_tlv),
+
+SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8962_LEFT_ADC_VOLUME,
+		 WM8962_RIGHT_ADC_VOLUME, 1, 127, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("Capture Volume", WM8962_LEFT_INPUT_VOLUME,
+		 WM8962_RIGHT_INPUT_VOLUME, 0, 63, 0, inpga_tlv),
+SOC_DOUBLE_R("Capture Switch", WM8962_LEFT_INPUT_VOLUME,
+	     WM8962_RIGHT_INPUT_VOLUME, 7, 1, 1),
+SOC_DOUBLE_R("Capture ZC Switch", WM8962_LEFT_INPUT_VOLUME,
+	     WM8962_RIGHT_INPUT_VOLUME, 6, 1, 1),
+SOC_SINGLE("Capture HPF Switch", WM8962_ADC_DAC_CONTROL_1, 0, 1, 1),
+SOC_ENUM("Capture HPF Mode", cap_hpf_mode),
+SOC_SINGLE("Capture HPF Cutoff", WM8962_ADC_DAC_CONTROL_2, 7, 7, 0),
+SOC_SINGLE("Capture LHPF Switch", WM8962_LHPF1, 0, 1, 0),
+SOC_ENUM("Capture LHPF Mode", cap_lhpf_mode),
+
+SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1,
+		 WM8962_DAC_DSP_MIXING_2, 4, 12, 0, st_tlv),
+
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8962_LEFT_DAC_VOLUME,
+		 WM8962_RIGHT_DAC_VOLUME, 1, 127, 0, digital_tlv),
+SOC_SINGLE("DAC High Performance Switch", WM8962_ADC_DAC_CONTROL_2, 0, 1, 0),
+SOC_SINGLE("DAC L/R Swap Switch", WM8962_AUDIO_INTERFACE_0, 5, 1, 0),
+SOC_SINGLE("ADC L/R Swap Switch", WM8962_AUDIO_INTERFACE_0, 8, 1, 0),
+
+SOC_SINGLE("ADC High Performance Switch", WM8962_ADDITIONAL_CONTROL_1,
+	   5, 1, 0),
+
+SOC_SINGLE_TLV("Beep Volume", WM8962_BEEP_GENERATOR_1, 4, 15, 0, beep_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Volume", WM8962_HPOUTL_VOLUME,
+		 WM8962_HPOUTR_VOLUME, 0, 127, 0, out_tlv),
+SOC_DOUBLE_EXT("Headphone Switch", WM8962_PWR_MGMT_2, 1, 0, 1, 1,
+	       snd_soc_get_volsw, wm8962_put_hp_sw),
+SOC_DOUBLE_R("Headphone ZC Switch", WM8962_HPOUTL_VOLUME, WM8962_HPOUTR_VOLUME,
+	     7, 1, 0),
+SOC_DOUBLE_TLV("Headphone Aux Volume", WM8962_ANALOGUE_HP_2, 3, 6, 7, 0,
+	       hp_tlv),
+
+SOC_DOUBLE_R("Headphone Mixer Switch", WM8962_HEADPHONE_MIXER_3,
+	     WM8962_HEADPHONE_MIXER_4, 8, 1, 1),
+
+SOC_SINGLE_TLV("HPMIXL IN4L Volume", WM8962_HEADPHONE_MIXER_3,
+	       3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXL IN4R Volume", WM8962_HEADPHONE_MIXER_3,
+	       0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXL MIXINL Volume", WM8962_HEADPHONE_MIXER_3,
+	       7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("HPMIXL MIXINR Volume", WM8962_HEADPHONE_MIXER_3,
+	       6, 1, 1, inmix_tlv),
+
+SOC_SINGLE_TLV("HPMIXR IN4L Volume", WM8962_HEADPHONE_MIXER_4,
+	       3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXR IN4R Volume", WM8962_HEADPHONE_MIXER_4,
+	       0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXR MIXINL Volume", WM8962_HEADPHONE_MIXER_4,
+	       7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("HPMIXR MIXINR Volume", WM8962_HEADPHONE_MIXER_4,
+	       6, 1, 1, inmix_tlv),
+
+SOC_SINGLE_TLV("Speaker Boost Volume", WM8962_CLASS_D_CONTROL_2, 0, 7, 0,
+	       classd_tlv),
+
+SOC_SINGLE("EQ Switch", WM8962_EQ1, WM8962_EQ_ENA_SHIFT, 1, 0),
+SOC_DOUBLE_R_TLV("EQ1 Volume", WM8962_EQ2, WM8962_EQ22,
+		 WM8962_EQL_B1_GAIN_SHIFT, 31, 0, eq_tlv),
+SOC_DOUBLE_R_TLV("EQ2 Volume", WM8962_EQ2, WM8962_EQ22,
+		 WM8962_EQL_B2_GAIN_SHIFT, 31, 0, eq_tlv),
+SOC_DOUBLE_R_TLV("EQ3 Volume", WM8962_EQ2, WM8962_EQ22,
+		 WM8962_EQL_B3_GAIN_SHIFT, 31, 0, eq_tlv),
+SOC_DOUBLE_R_TLV("EQ4 Volume", WM8962_EQ3, WM8962_EQ23,
+		 WM8962_EQL_B4_GAIN_SHIFT, 31, 0, eq_tlv),
+SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23,
+		 WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv),
+SND_SOC_BYTES("EQL Coefficients", WM8962_EQ4, 18),
+SND_SOC_BYTES("EQR Coefficients", WM8962_EQ24, 18),
+
+
+SOC_SINGLE("3D Switch", WM8962_THREED1, 0, 1, 0),
+SND_SOC_BYTES_MASK("3D Coefficients", WM8962_THREED1, 4, WM8962_THREED_ENA),
+
+SOC_SINGLE("DF1 Switch", WM8962_DF1, 0, 1, 0),
+SND_SOC_BYTES_MASK("DF1 Coefficients", WM8962_DF1, 7, WM8962_DF1_ENA),
+
+SOC_SINGLE("DRC Switch", WM8962_DRC_1, 0, 1, 0),
+SND_SOC_BYTES_MASK("DRC Coefficients", WM8962_DRC_1, 5, WM8962_DRC_ENA),
+
+WM8962_DSP2_ENABLE("VSS Switch", WM8962_VSS_ENA_SHIFT),
+SND_SOC_BYTES("VSS Coefficients", WM8962_VSS_XHD2_1, 148),
+WM8962_DSP2_ENABLE("HPF1 Switch", WM8962_HPF1_ENA_SHIFT),
+WM8962_DSP2_ENABLE("HPF2 Switch", WM8962_HPF2_ENA_SHIFT),
+SND_SOC_BYTES("HPF Coefficients", WM8962_LHPF2, 1),
+WM8962_DSP2_ENABLE("HD Bass Switch", WM8962_HDBASS_ENA_SHIFT),
+SND_SOC_BYTES("HD Bass Coefficients", WM8962_HDBASS_AI_1, 30),
+
+SOC_DOUBLE("ALC Switch", WM8962_ALC1, WM8962_ALCL_ENA_SHIFT,
+		WM8962_ALCR_ENA_SHIFT, 1, 0),
+SND_SOC_BYTES_MASK("ALC Coefficients", WM8962_ALC1, 4,
+		WM8962_ALCL_ENA_MASK | WM8962_ALCR_ENA_MASK),
+};
+
+static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = {
+SOC_SINGLE_TLV("Speaker Volume", WM8962_SPKOUTL_VOLUME, 0, 127, 0, out_tlv),
+SOC_SINGLE_EXT("Speaker Switch", WM8962_CLASS_D_CONTROL_1, 1, 1, 1,
+	       snd_soc_get_volsw, wm8962_put_spk_sw),
+SOC_SINGLE("Speaker ZC Switch", WM8962_SPKOUTL_VOLUME, 7, 1, 0),
+
+SOC_SINGLE("Speaker Mixer Switch", WM8962_SPEAKER_MIXER_3, 8, 1, 1),
+SOC_SINGLE_TLV("Speaker Mixer IN4L Volume", WM8962_SPEAKER_MIXER_3,
+	       3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("Speaker Mixer IN4R Volume", WM8962_SPEAKER_MIXER_3,
+	       0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("Speaker Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_3,
+	       7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_3,
+	       6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+	       7, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+	       6, 1, 0, inmix_tlv),
+};
+
+static const struct snd_kcontrol_new wm8962_spk_stereo_controls[] = {
+SOC_DOUBLE_R_TLV("Speaker Volume", WM8962_SPKOUTL_VOLUME,
+		 WM8962_SPKOUTR_VOLUME, 0, 127, 0, out_tlv),
+SOC_DOUBLE_EXT("Speaker Switch", WM8962_CLASS_D_CONTROL_1, 1, 0, 1, 1,
+	       snd_soc_get_volsw, wm8962_put_spk_sw),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8962_SPKOUTL_VOLUME, WM8962_SPKOUTR_VOLUME,
+	     7, 1, 0),
+
+SOC_DOUBLE_R("Speaker Mixer Switch", WM8962_SPEAKER_MIXER_3,
+	     WM8962_SPEAKER_MIXER_4, 8, 1, 1),
+
+SOC_SINGLE_TLV("SPKOUTL Mixer IN4L Volume", WM8962_SPEAKER_MIXER_3,
+	       3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer IN4R Volume", WM8962_SPEAKER_MIXER_3,
+	       0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_3,
+	       7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_3,
+	       6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+	       7, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+	       6, 1, 0, inmix_tlv),
+
+SOC_SINGLE_TLV("SPKOUTR Mixer IN4L Volume", WM8962_SPEAKER_MIXER_4,
+	       3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer IN4R Volume", WM8962_SPEAKER_MIXER_4,
+	       0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_4,
+	       7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_4,
+	       6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+	       5, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+	       4, 1, 0, inmix_tlv),
+};
+
+static int cp_event(struct snd_soc_dapm_widget *w,
+		    struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		msleep(5);
+		break;
+
+	default:
+		WARN(1, "Invalid event %d\n", event);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int hp_event(struct snd_soc_dapm_widget *w,
+		    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	int timeout;
+	int reg;
+	int expected = (WM8962_DCS_STARTUP_DONE_HP1L |
+			WM8962_DCS_STARTUP_DONE_HP1R);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
+				    WM8962_HP1L_ENA | WM8962_HP1R_ENA,
+				    WM8962_HP1L_ENA | WM8962_HP1R_ENA);
+		udelay(20);
+
+		snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
+				    WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY,
+				    WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY);
+
+		/* Start the DC servo */
+		snd_soc_component_update_bits(component, WM8962_DC_SERVO_1,
+				    WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+				    WM8962_HP1L_DCS_STARTUP |
+				    WM8962_HP1R_DCS_STARTUP,
+				    WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+				    WM8962_HP1L_DCS_STARTUP |
+				    WM8962_HP1R_DCS_STARTUP);
+
+		/* Wait for it to complete, should be well under 100ms */
+		timeout = 0;
+		do {
+			msleep(1);
+			reg = snd_soc_component_read32(component, WM8962_DC_SERVO_6);
+			if (reg < 0) {
+				dev_err(component->dev,
+					"Failed to read DCS status: %d\n",
+					reg);
+				continue;
+			}
+			dev_dbg(component->dev, "DCS status: %x\n", reg);
+		} while (++timeout < 200 && (reg & expected) != expected);
+
+		if ((reg & expected) != expected)
+			dev_err(component->dev, "DC servo timed out\n");
+		else
+			dev_dbg(component->dev, "DC servo complete after %dms\n",
+				timeout);
+
+		snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
+				    WM8962_HP1L_ENA_OUTP |
+				    WM8962_HP1R_ENA_OUTP,
+				    WM8962_HP1L_ENA_OUTP |
+				    WM8962_HP1R_ENA_OUTP);
+		udelay(20);
+
+		snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
+				    WM8962_HP1L_RMV_SHORT |
+				    WM8962_HP1R_RMV_SHORT,
+				    WM8962_HP1L_RMV_SHORT |
+				    WM8962_HP1R_RMV_SHORT);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
+				    WM8962_HP1L_RMV_SHORT |
+				    WM8962_HP1R_RMV_SHORT, 0);
+
+		udelay(20);
+
+		snd_soc_component_update_bits(component, WM8962_DC_SERVO_1,
+				    WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+				    WM8962_HP1L_DCS_STARTUP |
+				    WM8962_HP1R_DCS_STARTUP,
+				    0);
+
+		snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0,
+				    WM8962_HP1L_ENA | WM8962_HP1R_ENA |
+				    WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY |
+				    WM8962_HP1L_ENA_OUTP |
+				    WM8962_HP1R_ENA_OUTP, 0);
+				    
+		break;
+
+	default:
+		WARN(1, "Invalid event %d\n", event);
+		return -EINVAL;
+	
+	}
+
+	return 0;
+}
+
+/* VU bits for the output PGAs only take effect while the PGA is powered */
+static int out_pga_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	int reg;
+
+	switch (w->shift) {
+	case WM8962_HPOUTR_PGA_ENA_SHIFT:
+		reg = WM8962_HPOUTR_VOLUME;
+		break;
+	case WM8962_HPOUTL_PGA_ENA_SHIFT:
+		reg = WM8962_HPOUTL_VOLUME;
+		break;
+	case WM8962_SPKOUTR_PGA_ENA_SHIFT:
+		reg = WM8962_SPKOUTR_VOLUME;
+		break;
+	case WM8962_SPKOUTL_PGA_ENA_SHIFT:
+		reg = WM8962_SPKOUTL_VOLUME;
+		break;
+	default:
+		WARN(1, "Invalid shift %d\n", w->shift);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		return snd_soc_component_write(component, reg, snd_soc_component_read32(component, reg));
+	default:
+		WARN(1, "Invalid event %d\n", event);
+		return -EINVAL;
+	}
+}
+
+static int dsp2_event(struct snd_soc_dapm_widget *w,
+		      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (wm8962->dsp2_ena)
+			wm8962_dsp2_start(component);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		if (wm8962->dsp2_ena)
+			wm8962_dsp2_stop(component);
+		break;
+
+	default:
+		WARN(1, "Invalid event %d\n", event);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const char *st_text[] = { "None", "Left", "Right" };
+
+static SOC_ENUM_SINGLE_DECL(str_enum,
+			    WM8962_DAC_DSP_MIXING_1, 2, st_text);
+
+static const struct snd_kcontrol_new str_mux =
+	SOC_DAPM_ENUM("Right Sidetone", str_enum);
+
+static SOC_ENUM_SINGLE_DECL(stl_enum,
+			    WM8962_DAC_DSP_MIXING_2, 2, st_text);
+
+static const struct snd_kcontrol_new stl_mux =
+	SOC_DAPM_ENUM("Left Sidetone", stl_enum);
+
+static const char *outmux_text[] = { "DAC", "Mixer" };
+
+static SOC_ENUM_SINGLE_DECL(spkoutr_enum,
+			    WM8962_SPEAKER_MIXER_2, 7, outmux_text);
+
+static const struct snd_kcontrol_new spkoutr_mux =
+	SOC_DAPM_ENUM("SPKOUTR Mux", spkoutr_enum);
+
+static SOC_ENUM_SINGLE_DECL(spkoutl_enum,
+			    WM8962_SPEAKER_MIXER_1, 7, outmux_text);
+
+static const struct snd_kcontrol_new spkoutl_mux =
+	SOC_DAPM_ENUM("SPKOUTL Mux", spkoutl_enum);
+
+static SOC_ENUM_SINGLE_DECL(hpoutr_enum,
+			    WM8962_HEADPHONE_MIXER_2, 7, outmux_text);
+
+static const struct snd_kcontrol_new hpoutr_mux =
+	SOC_DAPM_ENUM("HPOUTR Mux", hpoutr_enum);
+
+static SOC_ENUM_SINGLE_DECL(hpoutl_enum,
+			    WM8962_HEADPHONE_MIXER_1, 7, outmux_text);
+
+static const struct snd_kcontrol_new hpoutl_mux =
+	SOC_DAPM_ENUM("HPOUTL Mux", hpoutl_enum);
+
+static const struct snd_kcontrol_new inpgal[] = {
+SOC_DAPM_SINGLE("IN1L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 3, 1, 0),
+SOC_DAPM_SINGLE("IN2L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new inpgar[] = {
+SOC_DAPM_SINGLE("IN1R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 3, 1, 0),
+SOC_DAPM_SINGLE("IN2R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixinl[] = {
+SOC_DAPM_SINGLE("IN2L Switch", WM8962_INPUT_MIXER_CONTROL_2, 5, 1, 0),
+SOC_DAPM_SINGLE("IN3L Switch", WM8962_INPUT_MIXER_CONTROL_2, 4, 1, 0),
+SOC_DAPM_SINGLE("PGA Switch", WM8962_INPUT_MIXER_CONTROL_2, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixinr[] = {
+SOC_DAPM_SINGLE("IN2R Switch", WM8962_INPUT_MIXER_CONTROL_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3R Switch", WM8962_INPUT_MIXER_CONTROL_2, 1, 1, 0),
+SOC_DAPM_SINGLE("PGA Switch", WM8962_INPUT_MIXER_CONTROL_2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new hpmixl[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_HEADPHONE_MIXER_1, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_HEADPHONE_MIXER_1, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_HEADPHONE_MIXER_1, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_HEADPHONE_MIXER_1, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_HEADPHONE_MIXER_1, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_HEADPHONE_MIXER_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new hpmixr[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_HEADPHONE_MIXER_2, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_HEADPHONE_MIXER_2, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_HEADPHONE_MIXER_2, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_HEADPHONE_MIXER_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_HEADPHONE_MIXER_2, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_HEADPHONE_MIXER_2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new spkmixl[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_SPEAKER_MIXER_1, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_SPEAKER_MIXER_1, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_SPEAKER_MIXER_1, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_SPEAKER_MIXER_1, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_SPEAKER_MIXER_1, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_SPEAKER_MIXER_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new spkmixr[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_SPEAKER_MIXER_2, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_SPEAKER_MIXER_2, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_SPEAKER_MIXER_2, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_SPEAKER_MIXER_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_SPEAKER_MIXER_2, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_SPEAKER_MIXER_2, 0, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+SND_SOC_DAPM_INPUT("IN4L"),
+SND_SOC_DAPM_INPUT("IN4R"),
+SND_SOC_DAPM_SIGGEN("Beep"),
+SND_SOC_DAPM_INPUT("DMICDAT"),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS", WM8962_PWR_MGMT_1, 1, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("Class G", WM8962_CHARGE_PUMP_B, 0, 1, NULL, 0),
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("Charge Pump", WM8962_CHARGE_PUMP_1, 0, 0, cp_event,
+		    SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("DSP2", 1, WM8962_DSP2_POWER_MANAGEMENT,
+		      WM8962_DSP2_ENA_SHIFT, 0, dsp2_event,
+		      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_SUPPLY("TEMP_HP", WM8962_ADDITIONAL_CONTROL_4, 2, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TEMP_SPK", WM8962_ADDITIONAL_CONTROL_4, 1, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("INPGAL", WM8962_LEFT_INPUT_PGA_CONTROL, 4, 0,
+		   inpgal, ARRAY_SIZE(inpgal)),
+SND_SOC_DAPM_MIXER("INPGAR", WM8962_RIGHT_INPUT_PGA_CONTROL, 4, 0,
+		   inpgar, ARRAY_SIZE(inpgar)),
+SND_SOC_DAPM_MIXER("MIXINL", WM8962_PWR_MGMT_1, 5, 0,
+		   mixinl, ARRAY_SIZE(mixinl)),
+SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0,
+		   mixinr, ARRAY_SIZE(mixinr)),
+
+SND_SOC_DAPM_AIF_IN("DMIC_ENA", NULL, 0, WM8962_PWR_MGMT_1, 10, 0),
+
+SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0),
+SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0),
+
+SND_SOC_DAPM_MUX("STL", SND_SOC_NOPM, 0, 0, &stl_mux),
+SND_SOC_DAPM_MUX("STR", SND_SOC_NOPM, 0, 0, &str_mux),
+
+SND_SOC_DAPM_DAC("DACL", "Playback", WM8962_PWR_MGMT_2, 8, 0),
+SND_SOC_DAPM_DAC("DACR", "Playback", WM8962_PWR_MGMT_2, 7, 0),
+
+SND_SOC_DAPM_PGA("Left Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("HPMIXL", WM8962_MIXER_ENABLES, 3, 0,
+		   hpmixl, ARRAY_SIZE(hpmixl)),
+SND_SOC_DAPM_MIXER("HPMIXR", WM8962_MIXER_ENABLES, 2, 0,
+		   hpmixr, ARRAY_SIZE(hpmixr)),
+
+SND_SOC_DAPM_MUX_E("HPOUTL PGA", WM8962_PWR_MGMT_2, 6, 0, &hpoutl_mux,
+		   out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_MUX_E("HPOUTR PGA", WM8962_PWR_MGMT_2, 5, 0, &hpoutr_mux,
+		   out_pga_event, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA_E("HPOUT", SND_SOC_NOPM, 0, 0, NULL, 0, hp_event,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_spk_mono_widgets[] = {
+SND_SOC_DAPM_MIXER("Speaker Mixer", WM8962_MIXER_ENABLES, 1, 0,
+		   spkmixl, ARRAY_SIZE(spkmixl)),
+SND_SOC_DAPM_MUX_E("Speaker PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
+		   out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA("Speaker Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_OUTPUT("SPKOUT"),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_spk_stereo_widgets[] = {
+SND_SOC_DAPM_MIXER("SPKOUTL Mixer", WM8962_MIXER_ENABLES, 1, 0,
+		   spkmixl, ARRAY_SIZE(spkmixl)),
+SND_SOC_DAPM_MIXER("SPKOUTR Mixer", WM8962_MIXER_ENABLES, 0, 0,
+		   spkmixr, ARRAY_SIZE(spkmixr)),
+
+SND_SOC_DAPM_MUX_E("SPKOUTL PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
+		   out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_MUX_E("SPKOUTR PGA", WM8962_PWR_MGMT_2, 3, 0, &spkoutr_mux,
+		   out_pga_event, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA("SPKOUTR Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPKOUTL Output", WM8962_CLASS_D_CONTROL_1, 6, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("SPKOUTL"),
+SND_SOC_DAPM_OUTPUT("SPKOUTR"),
+};
+
+static const struct snd_soc_dapm_route wm8962_intercon[] = {
+	{ "INPGAL", "IN1L Switch", "IN1L" },
+	{ "INPGAL", "IN2L Switch", "IN2L" },
+	{ "INPGAL", "IN3L Switch", "IN3L" },
+	{ "INPGAL", "IN4L Switch", "IN4L" },
+
+	{ "INPGAR", "IN1R Switch", "IN1R" },
+	{ "INPGAR", "IN2R Switch", "IN2R" },
+	{ "INPGAR", "IN3R Switch", "IN3R" },
+	{ "INPGAR", "IN4R Switch", "IN4R" },
+
+	{ "MIXINL", "IN2L Switch", "IN2L" },
+	{ "MIXINL", "IN3L Switch", "IN3L" },
+	{ "MIXINL", "PGA Switch", "INPGAL" },
+
+	{ "MIXINR", "IN2R Switch", "IN2R" },
+	{ "MIXINR", "IN3R Switch", "IN3R" },
+	{ "MIXINR", "PGA Switch", "INPGAR" },
+
+	{ "MICBIAS", NULL, "SYSCLK" },
+
+	{ "DMIC_ENA", NULL, "DMICDAT" },
+
+	{ "ADCL", NULL, "SYSCLK" },
+	{ "ADCL", NULL, "TOCLK" },
+	{ "ADCL", NULL, "MIXINL" },
+	{ "ADCL", NULL, "DMIC_ENA" },
+	{ "ADCL", NULL, "DSP2" },
+
+	{ "ADCR", NULL, "SYSCLK" },
+	{ "ADCR", NULL, "TOCLK" },
+	{ "ADCR", NULL, "MIXINR" },
+	{ "ADCR", NULL, "DMIC_ENA" },
+	{ "ADCR", NULL, "DSP2" },
+
+	{ "STL", "Left", "ADCL" },
+	{ "STL", "Right", "ADCR" },
+	{ "STL", NULL, "Class G" },
+
+	{ "STR", "Left", "ADCL" },
+	{ "STR", "Right", "ADCR" },
+	{ "STR", NULL, "Class G" },
+
+	{ "DACL", NULL, "SYSCLK" },
+	{ "DACL", NULL, "TOCLK" },
+	{ "DACL", NULL, "Beep" },
+	{ "DACL", NULL, "STL" },
+	{ "DACL", NULL, "DSP2" },
+
+	{ "DACR", NULL, "SYSCLK" },
+	{ "DACR", NULL, "TOCLK" },
+	{ "DACR", NULL, "Beep" },
+	{ "DACR", NULL, "STR" },
+	{ "DACR", NULL, "DSP2" },
+
+	{ "HPMIXL", "IN4L Switch", "IN4L" },
+	{ "HPMIXL", "IN4R Switch", "IN4R" },
+	{ "HPMIXL", "DACL Switch", "DACL" },
+	{ "HPMIXL", "DACR Switch", "DACR" },
+	{ "HPMIXL", "MIXINL Switch", "MIXINL" },
+	{ "HPMIXL", "MIXINR Switch", "MIXINR" },
+
+	{ "HPMIXR", "IN4L Switch", "IN4L" },
+	{ "HPMIXR", "IN4R Switch", "IN4R" },
+	{ "HPMIXR", "DACL Switch", "DACL" },
+	{ "HPMIXR", "DACR Switch", "DACR" },
+	{ "HPMIXR", "MIXINL Switch", "MIXINL" },
+	{ "HPMIXR", "MIXINR Switch", "MIXINR" },
+
+	{ "Left Bypass", NULL, "HPMIXL" },
+	{ "Left Bypass", NULL, "Class G" },
+
+	{ "Right Bypass", NULL, "HPMIXR" },
+	{ "Right Bypass", NULL, "Class G" },
+
+	{ "HPOUTL PGA", "Mixer", "Left Bypass" },
+	{ "HPOUTL PGA", "DAC", "DACL" },
+
+	{ "HPOUTR PGA", "Mixer", "Right Bypass" },
+	{ "HPOUTR PGA", "DAC", "DACR" },
+
+	{ "HPOUT", NULL, "HPOUTL PGA" },
+	{ "HPOUT", NULL, "HPOUTR PGA" },
+	{ "HPOUT", NULL, "Charge Pump" },
+	{ "HPOUT", NULL, "SYSCLK" },
+	{ "HPOUT", NULL, "TOCLK" },
+
+	{ "HPOUTL", NULL, "HPOUT" },
+	{ "HPOUTR", NULL, "HPOUT" },
+
+	{ "HPOUTL", NULL, "TEMP_HP" },
+	{ "HPOUTR", NULL, "TEMP_HP" },
+};
+
+static const struct snd_soc_dapm_route wm8962_spk_mono_intercon[] = {
+	{ "Speaker Mixer", "IN4L Switch", "IN4L" },
+	{ "Speaker Mixer", "IN4R Switch", "IN4R" },
+	{ "Speaker Mixer", "DACL Switch", "DACL" },
+	{ "Speaker Mixer", "DACR Switch", "DACR" },
+	{ "Speaker Mixer", "MIXINL Switch", "MIXINL" },
+	{ "Speaker Mixer", "MIXINR Switch", "MIXINR" },
+
+	{ "Speaker PGA", "Mixer", "Speaker Mixer" },
+	{ "Speaker PGA", "DAC", "DACL" },
+
+	{ "Speaker Output", NULL, "Speaker PGA" },
+	{ "Speaker Output", NULL, "SYSCLK" },
+	{ "Speaker Output", NULL, "TOCLK" },
+	{ "Speaker Output", NULL, "TEMP_SPK" },
+
+	{ "SPKOUT", NULL, "Speaker Output" },
+};
+
+static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
+	{ "SPKOUTL Mixer", "IN4L Switch", "IN4L" },
+	{ "SPKOUTL Mixer", "IN4R Switch", "IN4R" },
+	{ "SPKOUTL Mixer", "DACL Switch", "DACL" },
+	{ "SPKOUTL Mixer", "DACR Switch", "DACR" },
+	{ "SPKOUTL Mixer", "MIXINL Switch", "MIXINL" },
+	{ "SPKOUTL Mixer", "MIXINR Switch", "MIXINR" },
+
+	{ "SPKOUTR Mixer", "IN4L Switch", "IN4L" },
+	{ "SPKOUTR Mixer", "IN4R Switch", "IN4R" },
+	{ "SPKOUTR Mixer", "DACL Switch", "DACL" },
+	{ "SPKOUTR Mixer", "DACR Switch", "DACR" },
+	{ "SPKOUTR Mixer", "MIXINL Switch", "MIXINL" },
+	{ "SPKOUTR Mixer", "MIXINR Switch", "MIXINR" },
+
+	{ "SPKOUTL PGA", "Mixer", "SPKOUTL Mixer" },
+	{ "SPKOUTL PGA", "DAC", "DACL" },
+
+	{ "SPKOUTR PGA", "Mixer", "SPKOUTR Mixer" },
+	{ "SPKOUTR PGA", "DAC", "DACR" },
+
+	{ "SPKOUTL Output", NULL, "SPKOUTL PGA" },
+	{ "SPKOUTL Output", NULL, "SYSCLK" },
+	{ "SPKOUTL Output", NULL, "TOCLK" },
+	{ "SPKOUTL Output", NULL, "TEMP_SPK" },
+
+	{ "SPKOUTR Output", NULL, "SPKOUTR PGA" },
+	{ "SPKOUTR Output", NULL, "SYSCLK" },
+	{ "SPKOUTR Output", NULL, "TOCLK" },
+	{ "SPKOUTR Output", NULL, "TEMP_SPK" },
+
+	{ "SPKOUTL", NULL, "SPKOUTL Output" },
+	{ "SPKOUTR", NULL, "SPKOUTR Output" },
+};
+
+static int wm8962_add_widgets(struct snd_soc_component *component)
+{
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+	struct wm8962_pdata *pdata = &wm8962->pdata;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	snd_soc_add_component_controls(component, wm8962_snd_controls,
+			     ARRAY_SIZE(wm8962_snd_controls));
+	if (pdata->spk_mono)
+		snd_soc_add_component_controls(component, wm8962_spk_mono_controls,
+				     ARRAY_SIZE(wm8962_spk_mono_controls));
+	else
+		snd_soc_add_component_controls(component, wm8962_spk_stereo_controls,
+				     ARRAY_SIZE(wm8962_spk_stereo_controls));
+
+
+	snd_soc_dapm_new_controls(dapm, wm8962_dapm_widgets,
+				  ARRAY_SIZE(wm8962_dapm_widgets));
+	if (pdata->spk_mono)
+		snd_soc_dapm_new_controls(dapm, wm8962_dapm_spk_mono_widgets,
+					  ARRAY_SIZE(wm8962_dapm_spk_mono_widgets));
+	else
+		snd_soc_dapm_new_controls(dapm, wm8962_dapm_spk_stereo_widgets,
+					  ARRAY_SIZE(wm8962_dapm_spk_stereo_widgets));
+
+	snd_soc_dapm_add_routes(dapm, wm8962_intercon,
+				ARRAY_SIZE(wm8962_intercon));
+	if (pdata->spk_mono)
+		snd_soc_dapm_add_routes(dapm, wm8962_spk_mono_intercon,
+					ARRAY_SIZE(wm8962_spk_mono_intercon));
+	else
+		snd_soc_dapm_add_routes(dapm, wm8962_spk_stereo_intercon,
+					ARRAY_SIZE(wm8962_spk_stereo_intercon));
+
+
+	snd_soc_dapm_disable_pin(dapm, "Beep");
+
+	return 0;
+}
+
+/* -1 for reserved values */
+static const int bclk_divs[] = {
+	1, -1, 2, 3, 4, -1, 6, 8, -1, 12, 16, 24, -1, 32, 32, 32
+};
+
+static const int sysclk_rates[] = {
+	64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, 3072, 6144
+};
+
+static void wm8962_configure_bclk(struct snd_soc_component *component)
+{
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+	int dspclk, i;
+	int clocking2 = 0;
+	int clocking4 = 0;
+	int aif2 = 0;
+
+	if (!wm8962->sysclk_rate) {
+		dev_dbg(component->dev, "No SYSCLK configured\n");
+		return;
+	}
+
+	if (!wm8962->bclk || !wm8962->lrclk) {
+		dev_dbg(component->dev, "No audio clocks configured\n");
+		return;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) {
+		if (sysclk_rates[i] == wm8962->sysclk_rate / wm8962->lrclk) {
+			clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT;
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(sysclk_rates)) {
+		dev_err(component->dev, "Unsupported sysclk ratio %d\n",
+			wm8962->sysclk_rate / wm8962->lrclk);
+		return;
+	}
+
+	dev_dbg(component->dev, "Selected sysclk ratio %d\n", sysclk_rates[i]);
+
+	snd_soc_component_update_bits(component, WM8962_CLOCKING_4,
+			    WM8962_SYSCLK_RATE_MASK, clocking4);
+
+	/* DSPCLK_DIV can be only generated correctly after enabling SYSCLK.
+	 * So we here provisionally enable it and then disable it afterward
+	 * if current bias_level hasn't reached SND_SOC_BIAS_ON.
+	 */
+	if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_ON)
+		snd_soc_component_update_bits(component, WM8962_CLOCKING2,
+				WM8962_SYSCLK_ENA_MASK, WM8962_SYSCLK_ENA);
+
+	dspclk = snd_soc_component_read32(component, WM8962_CLOCKING1);
+
+	if (snd_soc_component_get_bias_level(component) != SND_SOC_BIAS_ON)
+		snd_soc_component_update_bits(component, WM8962_CLOCKING2,
+				WM8962_SYSCLK_ENA_MASK, 0);
+
+	if (dspclk < 0) {
+		dev_err(component->dev, "Failed to read DSPCLK: %d\n", dspclk);
+		return;
+	}
+
+	dspclk = (dspclk & WM8962_DSPCLK_DIV_MASK) >> WM8962_DSPCLK_DIV_SHIFT;
+	switch (dspclk) {
+	case 0:
+		dspclk = wm8962->sysclk_rate;
+		break;
+	case 1:
+		dspclk = wm8962->sysclk_rate / 2;
+		break;
+	case 2:
+		dspclk = wm8962->sysclk_rate / 4;
+		break;
+	default:
+		dev_warn(component->dev, "Unknown DSPCLK divisor read back\n");
+		dspclk = wm8962->sysclk_rate;
+	}
+
+	dev_dbg(component->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk);
+
+	/* We're expecting an exact match */
+	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+		if (bclk_divs[i] < 0)
+			continue;
+
+		if (dspclk / bclk_divs[i] == wm8962->bclk) {
+			dev_dbg(component->dev, "Selected BCLK_DIV %d for %dHz\n",
+				bclk_divs[i], wm8962->bclk);
+			clocking2 |= i;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(bclk_divs)) {
+		dev_err(component->dev, "Unsupported BCLK ratio %d\n",
+			dspclk / wm8962->bclk);
+		return;
+	}
+
+	aif2 |= wm8962->bclk / wm8962->lrclk;
+	dev_dbg(component->dev, "Selected LRCLK divisor %d for %dHz\n",
+		wm8962->bclk / wm8962->lrclk, wm8962->lrclk);
+
+	snd_soc_component_update_bits(component, WM8962_CLOCKING2,
+			    WM8962_BCLK_DIV_MASK, clocking2);
+	snd_soc_component_update_bits(component, WM8962_AUDIO_INTERFACE_2,
+			    WM8962_AIF_RATE_MASK, aif2);
+}
+
+static int wm8962_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* VMID 2*50k */
+		snd_soc_component_update_bits(component, WM8962_PWR_MGMT_1,
+				    WM8962_VMID_SEL_MASK, 0x80);
+
+		wm8962_configure_bclk(component);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		/* VMID 2*250k */
+		snd_soc_component_update_bits(component, WM8962_PWR_MGMT_1,
+				    WM8962_VMID_SEL_MASK, 0x100);
+
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+			msleep(100);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct {
+	int rate;
+	int reg;
+} sr_vals[] = {
+	{ 48000, 0 },
+	{ 44100, 0 },
+	{ 32000, 1 },
+	{ 22050, 2 },
+	{ 24000, 2 },
+	{ 16000, 3 },
+	{ 11025, 4 },
+	{ 12000, 4 },
+	{ 8000,  5 },
+	{ 88200, 6 },
+	{ 96000, 6 },
+};
+
+static int wm8962_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+	int i;
+	int aif0 = 0;
+	int adctl3 = 0;
+
+	wm8962->bclk = snd_soc_params_to_bclk(params);
+	if (params_channels(params) == 1)
+		wm8962->bclk *= 2;
+
+	wm8962->lrclk = params_rate(params);
+
+	for (i = 0; i < ARRAY_SIZE(sr_vals); i++) {
+		if (sr_vals[i].rate == wm8962->lrclk) {
+			adctl3 |= sr_vals[i].reg;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(sr_vals)) {
+		dev_err(component->dev, "Unsupported rate %dHz\n", wm8962->lrclk);
+		return -EINVAL;
+	}
+
+	if (wm8962->lrclk % 8000 == 0)
+		adctl3 |= WM8962_SAMPLE_RATE_INT_MODE;
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		aif0 |= 0x4;
+		break;
+	case 24:
+		aif0 |= 0x8;
+		break;
+	case 32:
+		aif0 |= 0xc;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8962_AUDIO_INTERFACE_0,
+			    WM8962_WL_MASK, aif0);
+	snd_soc_component_update_bits(component, WM8962_ADDITIONAL_CONTROL_3,
+			    WM8962_SAMPLE_RATE_INT_MODE |
+			    WM8962_SAMPLE_RATE_MASK, adctl3);
+
+	dev_dbg(component->dev, "hw_params set BCLK %dHz LRCLK %dHz\n",
+		wm8962->bclk, wm8962->lrclk);
+
+	if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_ON)
+		wm8962_configure_bclk(component);
+
+	return 0;
+}
+
+static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+				 unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+	int src;
+
+	switch (clk_id) {
+	case WM8962_SYSCLK_MCLK:
+		wm8962->sysclk = WM8962_SYSCLK_MCLK;
+		src = 0;
+		break;
+	case WM8962_SYSCLK_FLL:
+		wm8962->sysclk = WM8962_SYSCLK_FLL;
+		src = 1 << WM8962_SYSCLK_SRC_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8962_CLOCKING2, WM8962_SYSCLK_SRC_MASK,
+			    src);
+
+	wm8962->sysclk_rate = freq;
+
+	return 0;
+}
+
+static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	int aif0 = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_B:
+		aif0 |= WM8962_LRCLK_INV | 3;
+		/* fall through */
+	case SND_SOC_DAIFMT_DSP_A:
+		aif0 |= 3;
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+		case SND_SOC_DAIFMT_IB_NF:
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif0 |= 1;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aif0 |= 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		aif0 |= WM8962_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		aif0 |= WM8962_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		aif0 |= WM8962_BCLK_INV | WM8962_LRCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif0 |= WM8962_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8962_AUDIO_INTERFACE_0,
+			    WM8962_FMT_MASK | WM8962_BCLK_INV | WM8962_MSTR |
+			    WM8962_LRCLK_INV, aif0);
+
+	return 0;
+}
+
+struct _fll_div {
+	u16 fll_fratio;
+	u16 fll_outdiv;
+	u16 fll_refclk_div;
+	u16 n;
+	u16 theta;
+	u16 lambda;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static struct {
+	unsigned int min;
+	unsigned int max;
+	u16 fll_fratio;
+	int ratio;
+} fll_fratios[] = {
+	{       0,    64000, 4, 16 },
+	{   64000,   128000, 3,  8 },
+	{  128000,   256000, 2,  4 },
+	{  256000,  1000000, 1,  2 },
+	{ 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+		       unsigned int Fout)
+{
+	unsigned int target;
+	unsigned int div;
+	unsigned int fratio, gcd_fll;
+	int i;
+
+	/* Fref must be <=13.5MHz */
+	div = 1;
+	fll_div->fll_refclk_div = 0;
+	while ((Fref / div) > 13500000) {
+		div *= 2;
+		fll_div->fll_refclk_div++;
+
+		if (div > 4) {
+			pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+			       Fref);
+			return -EINVAL;
+		}
+	}
+
+	pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+	/* Apply the division for our remaining calculations */
+	Fref /= div;
+
+	/* Fvco should be 90-100MHz; don't check the upper bound */
+	div = 2;
+	while (Fout * div < 90000000) {
+		div++;
+		if (div > 64) {
+			pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+			       Fout);
+			return -EINVAL;
+		}
+	}
+	target = Fout * div;
+	fll_div->fll_outdiv = div - 1;
+
+	pr_debug("FLL Fvco=%dHz\n", target);
+
+	/* Find an appropriate FLL_FRATIO and factor it out of the target */
+	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+			fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+			fratio = fll_fratios[i].ratio;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(fll_fratios)) {
+		pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+		return -EINVAL;
+	}
+
+	fll_div->n = target / (fratio * Fref);
+
+	if (target % Fref == 0) {
+		fll_div->theta = 0;
+		fll_div->lambda = 0;
+	} else {
+		gcd_fll = gcd(target, fratio * Fref);
+
+		fll_div->theta = (target - (fll_div->n * fratio * Fref))
+			/ gcd_fll;
+		fll_div->lambda = (fratio * Fref) / gcd_fll;
+	}
+
+	pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+		 fll_div->n, fll_div->theta, fll_div->lambda);
+	pr_debug("FLL_FRATIO=%x FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+		 fll_div->fll_fratio, fll_div->fll_outdiv,
+		 fll_div->fll_refclk_div);
+
+	return 0;
+}
+
+static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int source,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+	struct _fll_div fll_div;
+	unsigned long timeout;
+	int ret;
+	int fll1 = 0;
+
+	/* Any change? */
+	if (source == wm8962->fll_src && Fref == wm8962->fll_fref &&
+	    Fout == wm8962->fll_fout)
+		return 0;
+
+	if (Fout == 0) {
+		dev_dbg(component->dev, "FLL disabled\n");
+
+		wm8962->fll_fref = 0;
+		wm8962->fll_fout = 0;
+
+		snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
+				    WM8962_FLL_ENA, 0);
+
+		pm_runtime_put(component->dev);
+
+		return 0;
+	}
+
+	ret = fll_factors(&fll_div, Fref, Fout);
+	if (ret != 0)
+		return ret;
+
+	/* Parameters good, disable so we can reprogram */
+	snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
+
+	switch (fll_id) {
+	case WM8962_FLL_MCLK:
+	case WM8962_FLL_BCLK:
+	case WM8962_FLL_OSC:
+		fll1 |= (fll_id - 1) << WM8962_FLL_REFCLK_SRC_SHIFT;
+		break;
+	case WM8962_FLL_INT:
+		snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
+				    WM8962_FLL_OSC_ENA, WM8962_FLL_OSC_ENA);
+		snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_5,
+				    WM8962_FLL_FRC_NCO, WM8962_FLL_FRC_NCO);
+		break;
+	default:
+		dev_err(component->dev, "Unknown FLL source %d\n", ret);
+		return -EINVAL;
+	}
+
+	if (fll_div.theta || fll_div.lambda)
+		fll1 |= WM8962_FLL_FRAC;
+
+	/* Stop the FLL while we reconfigure */
+	snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
+
+	snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_2,
+			    WM8962_FLL_OUTDIV_MASK |
+			    WM8962_FLL_REFCLK_DIV_MASK,
+			    (fll_div.fll_outdiv << WM8962_FLL_OUTDIV_SHIFT) |
+			    (fll_div.fll_refclk_div));
+
+	snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_3,
+			    WM8962_FLL_FRATIO_MASK, fll_div.fll_fratio);
+
+	snd_soc_component_write(component, WM8962_FLL_CONTROL_6, fll_div.theta);
+	snd_soc_component_write(component, WM8962_FLL_CONTROL_7, fll_div.lambda);
+	snd_soc_component_write(component, WM8962_FLL_CONTROL_8, fll_div.n);
+
+	reinit_completion(&wm8962->fll_lock);
+
+	ret = pm_runtime_get_sync(component->dev);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to resume device: %d\n", ret);
+		return ret;
+	}
+
+	snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
+			    WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
+			    WM8962_FLL_ENA, fll1 | WM8962_FLL_ENA);
+
+	dev_dbg(component->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+
+	/* This should be a massive overestimate but go even
+	 * higher if we'll error out
+	 */
+	if (wm8962->irq)
+		timeout = msecs_to_jiffies(5);
+	else
+		timeout = msecs_to_jiffies(1);
+
+	timeout = wait_for_completion_timeout(&wm8962->fll_lock,
+					      timeout);
+
+	if (timeout == 0 && wm8962->irq) {
+		dev_err(component->dev, "FLL lock timed out");
+		snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1,
+				    WM8962_FLL_ENA, 0);
+		pm_runtime_put(component->dev);
+		return -ETIMEDOUT;
+	}
+
+	wm8962->fll_fref = Fref;
+	wm8962->fll_fout = Fout;
+	wm8962->fll_src = source;
+
+	return 0;
+}
+
+static int wm8962_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	int val, ret;
+
+	if (mute)
+		val = WM8962_DAC_MUTE | WM8962_DAC_MUTE_ALT;
+	else
+		val = 0;
+
+	/**
+	 * The DAC mute bit is mirrored in two registers, update both to keep
+	 * the register cache consistent.
+	 */
+	ret = snd_soc_component_update_bits(component, WM8962_CLASS_D_CONTROL_1,
+				  WM8962_DAC_MUTE_ALT, val);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_component_update_bits(component, WM8962_ADC_DAC_CONTROL_1,
+				   WM8962_DAC_MUTE, val);
+}
+
+#define WM8962_RATES (SNDRV_PCM_RATE_8000_48000 |\
+		SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define WM8962_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8962_dai_ops = {
+	.hw_params = wm8962_hw_params,
+	.set_sysclk = wm8962_set_dai_sysclk,
+	.set_fmt = wm8962_set_dai_fmt,
+	.digital_mute = wm8962_mute,
+};
+
+static struct snd_soc_dai_driver wm8962_dai = {
+	.name = "wm8962",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8962_RATES,
+		.formats = WM8962_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8962_RATES,
+		.formats = WM8962_FORMATS,
+	},
+	.ops = &wm8962_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static void wm8962_mic_work(struct work_struct *work)
+{
+	struct wm8962_priv *wm8962 = container_of(work,
+						  struct wm8962_priv,
+						  mic_work.work);
+	struct snd_soc_component *component = wm8962->component;
+	int status = 0;
+	int irq_pol = 0;
+	int reg;
+
+	reg = snd_soc_component_read32(component, WM8962_ADDITIONAL_CONTROL_4);
+
+	if (reg & WM8962_MICDET_STS) {
+		status |= SND_JACK_MICROPHONE;
+		irq_pol |= WM8962_MICD_IRQ_POL;
+	}
+
+	if (reg & WM8962_MICSHORT_STS) {
+		status |= SND_JACK_BTN_0;
+		irq_pol |= WM8962_MICSCD_IRQ_POL;
+	}
+
+	snd_soc_jack_report(wm8962->jack, status,
+			    SND_JACK_MICROPHONE | SND_JACK_BTN_0);
+
+	snd_soc_component_update_bits(component, WM8962_MICINT_SOURCE_POL,
+			    WM8962_MICSCD_IRQ_POL |
+			    WM8962_MICD_IRQ_POL, irq_pol);
+}
+
+static irqreturn_t wm8962_irq(int irq, void *data)
+{
+	struct device *dev = data;
+	struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+	unsigned int mask;
+	unsigned int active;
+	int reg, ret;
+
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0) {
+		dev_err(dev, "Failed to resume: %d\n", ret);
+		return IRQ_NONE;
+	}
+
+	ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2_MASK,
+			  &mask);
+	if (ret != 0) {
+		pm_runtime_put(dev);
+		dev_err(dev, "Failed to read interrupt mask: %d\n",
+			ret);
+		return IRQ_NONE;
+	}
+
+	ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, &active);
+	if (ret != 0) {
+		pm_runtime_put(dev);
+		dev_err(dev, "Failed to read interrupt: %d\n", ret);
+		return IRQ_NONE;
+	}
+
+	active &= ~mask;
+
+	if (!active) {
+		pm_runtime_put(dev);
+		return IRQ_NONE;
+	}
+
+	/* Acknowledge the interrupts */
+	ret = regmap_write(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, active);
+	if (ret != 0)
+		dev_warn(dev, "Failed to ack interrupt: %d\n", ret);
+
+	if (active & WM8962_FLL_LOCK_EINT) {
+		dev_dbg(dev, "FLL locked\n");
+		complete(&wm8962->fll_lock);
+	}
+
+	if (active & WM8962_FIFOS_ERR_EINT)
+		dev_err(dev, "FIFO error\n");
+
+	if (active & WM8962_TEMP_SHUT_EINT) {
+		dev_crit(dev, "Thermal shutdown\n");
+
+		ret = regmap_read(wm8962->regmap,
+				  WM8962_THERMAL_SHUTDOWN_STATUS,  &reg);
+		if (ret != 0) {
+			dev_warn(dev, "Failed to read thermal status: %d\n",
+				 ret);
+			reg = 0;
+		}
+
+		if (reg & WM8962_TEMP_ERR_HP)
+			dev_crit(dev, "Headphone thermal error\n");
+		if (reg & WM8962_TEMP_WARN_HP)
+			dev_crit(dev, "Headphone thermal warning\n");
+		if (reg & WM8962_TEMP_ERR_SPK)
+			dev_crit(dev, "Speaker thermal error\n");
+		if (reg & WM8962_TEMP_WARN_SPK)
+			dev_crit(dev, "Speaker thermal warning\n");
+	}
+
+	if (active & (WM8962_MICSCD_EINT | WM8962_MICD_EINT)) {
+		dev_dbg(dev, "Microphone event detected\n");
+
+#ifndef CONFIG_SND_SOC_WM8962_MODULE
+		trace_snd_soc_jack_irq(dev_name(dev));
+#endif
+
+		pm_wakeup_event(dev, 300);
+
+		queue_delayed_work(system_power_efficient_wq,
+				   &wm8962->mic_work,
+				   msecs_to_jiffies(250));
+	}
+
+	pm_runtime_put(dev);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * wm8962_mic_detect - Enable microphone detection via the WM8962 IRQ
+ *
+ * @component:  WM8962 component
+ * @jack:   jack to report detection events on
+ *
+ * Enable microphone detection via IRQ on the WM8962.  If GPIOs are
+ * being used to bring out signals to the processor then only platform
+ * data configuration is needed for WM8962 and processor GPIOs should
+ * be configured using snd_soc_jack_add_gpios() instead.
+ *
+ * If no jack is supplied detection will be disabled.
+ */
+int wm8962_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
+{
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int irq_mask, enable;
+
+	wm8962->jack = jack;
+	if (jack) {
+		irq_mask = 0;
+		enable = WM8962_MICDET_ENA;
+	} else {
+		irq_mask = WM8962_MICD_EINT | WM8962_MICSCD_EINT;
+		enable = 0;
+	}
+
+	snd_soc_component_update_bits(component, WM8962_INTERRUPT_STATUS_2_MASK,
+			    WM8962_MICD_EINT | WM8962_MICSCD_EINT, irq_mask);
+	snd_soc_component_update_bits(component, WM8962_ADDITIONAL_CONTROL_4,
+			    WM8962_MICDET_ENA, enable);
+
+	/* Send an initial empty report */
+	snd_soc_jack_report(wm8962->jack, 0,
+			    SND_JACK_MICROPHONE | SND_JACK_BTN_0);
+
+	snd_soc_dapm_mutex_lock(dapm);
+
+	if (jack) {
+		snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK");
+		snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS");
+	} else {
+		snd_soc_dapm_disable_pin_unlocked(dapm, "SYSCLK");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS");
+	}
+
+	snd_soc_dapm_mutex_unlock(dapm);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8962_mic_detect);
+
+static int beep_rates[] = {
+	500, 1000, 2000, 4000,
+};
+
+static void wm8962_beep_work(struct work_struct *work)
+{
+	struct wm8962_priv *wm8962 =
+		container_of(work, struct wm8962_priv, beep_work);
+	struct snd_soc_component *component = wm8962->component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int i;
+	int reg = 0;
+	int best = 0;
+
+	if (wm8962->beep_rate) {
+		for (i = 0; i < ARRAY_SIZE(beep_rates); i++) {
+			if (abs(wm8962->beep_rate - beep_rates[i]) <
+			    abs(wm8962->beep_rate - beep_rates[best]))
+				best = i;
+		}
+
+		dev_dbg(component->dev, "Set beep rate %dHz for requested %dHz\n",
+			beep_rates[best], wm8962->beep_rate);
+
+		reg = WM8962_BEEP_ENA | (best << WM8962_BEEP_RATE_SHIFT);
+
+		snd_soc_dapm_enable_pin(dapm, "Beep");
+	} else {
+		dev_dbg(component->dev, "Disabling beep\n");
+		snd_soc_dapm_disable_pin(dapm, "Beep");
+	}
+
+	snd_soc_component_update_bits(component, WM8962_BEEP_GENERATOR_1,
+			    WM8962_BEEP_ENA | WM8962_BEEP_RATE_MASK, reg);
+
+	snd_soc_dapm_sync(dapm);
+}
+
+/* For usability define a way of injecting beep events for the device -
+ * many systems will not have a keyboard.
+ */
+static int wm8962_beep_event(struct input_dev *dev, unsigned int type,
+			     unsigned int code, int hz)
+{
+	struct snd_soc_component *component = input_get_drvdata(dev);
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+
+	dev_dbg(component->dev, "Beep event %x %x\n", code, hz);
+
+	switch (code) {
+	case SND_BELL:
+		if (hz)
+			hz = 1000;
+	case SND_TONE:
+		break;
+	default:
+		return -1;
+	}
+
+	/* Kick the beep from a workqueue */
+	wm8962->beep_rate = hz;
+	schedule_work(&wm8962->beep_work);
+	return 0;
+}
+
+static ssize_t wm8962_beep_set(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+	long int time;
+	int ret;
+
+	ret = kstrtol(buf, 10, &time);
+	if (ret != 0)
+		return ret;
+
+	input_event(wm8962->beep, EV_SND, SND_TONE, time);
+
+	return count;
+}
+
+static DEVICE_ATTR(beep, 0200, NULL, wm8962_beep_set);
+
+static void wm8962_init_beep(struct snd_soc_component *component)
+{
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	wm8962->beep = devm_input_allocate_device(component->dev);
+	if (!wm8962->beep) {
+		dev_err(component->dev, "Failed to allocate beep device\n");
+		return;
+	}
+
+	INIT_WORK(&wm8962->beep_work, wm8962_beep_work);
+	wm8962->beep_rate = 0;
+
+	wm8962->beep->name = "WM8962 Beep Generator";
+	wm8962->beep->phys = dev_name(component->dev);
+	wm8962->beep->id.bustype = BUS_I2C;
+
+	wm8962->beep->evbit[0] = BIT_MASK(EV_SND);
+	wm8962->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+	wm8962->beep->event = wm8962_beep_event;
+	wm8962->beep->dev.parent = component->dev;
+	input_set_drvdata(wm8962->beep, component);
+
+	ret = input_register_device(wm8962->beep);
+	if (ret != 0) {
+		wm8962->beep = NULL;
+		dev_err(component->dev, "Failed to register beep device\n");
+	}
+
+	ret = device_create_file(component->dev, &dev_attr_beep);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to create keyclick file: %d\n",
+			ret);
+	}
+}
+
+static void wm8962_free_beep(struct snd_soc_component *component)
+{
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+
+	device_remove_file(component->dev, &dev_attr_beep);
+	cancel_work_sync(&wm8962->beep_work);
+	wm8962->beep = NULL;
+
+	snd_soc_component_update_bits(component, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0);
+}
+
+static void wm8962_set_gpio_mode(struct wm8962_priv *wm8962, int gpio)
+{
+	int mask = 0;
+	int val = 0;
+
+	/* Some of the GPIOs are behind MFP configuration and need to
+	 * be put into GPIO mode. */
+	switch (gpio) {
+	case 2:
+		mask = WM8962_CLKOUT2_SEL_MASK;
+		val = 1 << WM8962_CLKOUT2_SEL_SHIFT;
+		break;
+	case 3:
+		mask = WM8962_CLKOUT3_SEL_MASK;
+		val = 1 << WM8962_CLKOUT3_SEL_SHIFT;
+		break;
+	default:
+		break;
+	}
+
+	if (mask)
+		regmap_update_bits(wm8962->regmap, WM8962_ANALOGUE_CLOCKING1,
+				   mask, val);
+}
+
+#ifdef CONFIG_GPIOLIB
+static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	struct wm8962_priv *wm8962 = gpiochip_get_data(chip);
+
+	/* The WM8962 GPIOs aren't linearly numbered.  For simplicity
+	 * we export linear numbers and error out if the unsupported
+	 * ones are requsted.
+	 */
+	switch (offset + 1) {
+	case 2:
+	case 3:
+	case 5:
+	case 6:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8962_set_gpio_mode(wm8962, offset + 1);
+
+	return 0;
+}
+
+static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct wm8962_priv *wm8962 = gpiochip_get_data(chip);
+	struct snd_soc_component *component = wm8962->component;
+
+	snd_soc_component_update_bits(component, WM8962_GPIO_BASE + offset,
+			    WM8962_GP2_LVL, !!value << WM8962_GP2_LVL_SHIFT);
+}
+
+static int wm8962_gpio_direction_out(struct gpio_chip *chip,
+				     unsigned offset, int value)
+{
+	struct wm8962_priv *wm8962 = gpiochip_get_data(chip);
+	struct snd_soc_component *component = wm8962->component;
+	int ret, val;
+
+	/* Force function 1 (logic output) */
+	val = (1 << WM8962_GP2_FN_SHIFT) | (value << WM8962_GP2_LVL_SHIFT);
+
+	ret = snd_soc_component_update_bits(component, WM8962_GPIO_BASE + offset,
+				  WM8962_GP2_FN_MASK | WM8962_GP2_LVL, val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct gpio_chip wm8962_template_chip = {
+	.label			= "wm8962",
+	.owner			= THIS_MODULE,
+	.request		= wm8962_gpio_request,
+	.direction_output	= wm8962_gpio_direction_out,
+	.set			= wm8962_gpio_set,
+	.can_sleep		= 1,
+};
+
+static void wm8962_init_gpio(struct snd_soc_component *component)
+{
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+	struct wm8962_pdata *pdata = &wm8962->pdata;
+	int ret;
+
+	wm8962->gpio_chip = wm8962_template_chip;
+	wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO;
+	wm8962->gpio_chip.parent = component->dev;
+
+	if (pdata->gpio_base)
+		wm8962->gpio_chip.base = pdata->gpio_base;
+	else
+		wm8962->gpio_chip.base = -1;
+
+	ret = gpiochip_add_data(&wm8962->gpio_chip, wm8962);
+	if (ret != 0)
+		dev_err(component->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm8962_free_gpio(struct snd_soc_component *component)
+{
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+
+	gpiochip_remove(&wm8962->gpio_chip);
+}
+#else
+static void wm8962_init_gpio(struct snd_soc_component *component)
+{
+}
+
+static void wm8962_free_gpio(struct snd_soc_component *component)
+{
+}
+#endif
+
+static int wm8962_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int ret;
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+	int i;
+	bool dmicclk, dmicdat;
+
+	wm8962->component = component;
+
+	wm8962->disable_nb[0].notifier_call = wm8962_regulator_event_0;
+	wm8962->disable_nb[1].notifier_call = wm8962_regulator_event_1;
+	wm8962->disable_nb[2].notifier_call = wm8962_regulator_event_2;
+	wm8962->disable_nb[3].notifier_call = wm8962_regulator_event_3;
+	wm8962->disable_nb[4].notifier_call = wm8962_regulator_event_4;
+	wm8962->disable_nb[5].notifier_call = wm8962_regulator_event_5;
+	wm8962->disable_nb[6].notifier_call = wm8962_regulator_event_6;
+	wm8962->disable_nb[7].notifier_call = wm8962_regulator_event_7;
+
+	/* This should really be moved into the regulator core */
+	for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) {
+		ret = regulator_register_notifier(wm8962->supplies[i].consumer,
+						  &wm8962->disable_nb[i]);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to register regulator notifier: %d\n",
+				ret);
+		}
+	}
+
+	wm8962_add_widgets(component);
+
+	/* Save boards having to disable DMIC when not in use */
+	dmicclk = false;
+	dmicdat = false;
+	for (i = 0; i < WM8962_MAX_GPIO; i++) {
+		switch (snd_soc_component_read32(component, WM8962_GPIO_BASE + i)
+			& WM8962_GP2_FN_MASK) {
+		case WM8962_GPIO_FN_DMICCLK:
+			dmicclk = true;
+			break;
+		case WM8962_GPIO_FN_DMICDAT:
+			dmicdat = true;
+			break;
+		default:
+			break;
+		}
+	}
+	if (!dmicclk || !dmicdat) {
+		dev_dbg(component->dev, "DMIC not in use, disabling\n");
+		snd_soc_dapm_nc_pin(dapm, "DMICDAT");
+	}
+	if (dmicclk != dmicdat)
+		dev_warn(component->dev, "DMIC GPIOs partially configured\n");
+
+	wm8962_init_beep(component);
+	wm8962_init_gpio(component);
+
+	return 0;
+}
+
+static void wm8962_remove(struct snd_soc_component *component)
+{
+	struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
+	int i;
+
+	cancel_delayed_work_sync(&wm8962->mic_work);
+
+	wm8962_free_gpio(component);
+	wm8962_free_beep(component);
+	for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
+		regulator_unregister_notifier(wm8962->supplies[i].consumer,
+					      &wm8962->disable_nb[i]);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8962 = {
+	.probe			= wm8962_probe,
+	.remove			= wm8962_remove,
+	.set_bias_level		= wm8962_set_bias_level,
+	.set_pll		= wm8962_set_fll,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+/* Improve power consumption for IN4 DC measurement mode */
+static const struct reg_sequence wm8962_dc_measure[] = {
+	{ 0xfd, 0x1 },
+	{ 0xcc, 0x40 },
+	{ 0xfd, 0 },
+};
+
+static const struct regmap_config wm8962_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+
+	.max_register = WM8962_MAX_REGISTER,
+	.reg_defaults = wm8962_reg,
+	.num_reg_defaults = ARRAY_SIZE(wm8962_reg),
+	.volatile_reg = wm8962_volatile_register,
+	.readable_reg = wm8962_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int wm8962_set_pdata_from_of(struct i2c_client *i2c,
+				    struct wm8962_pdata *pdata)
+{
+	const struct device_node *np = i2c->dev.of_node;
+	u32 val32;
+	int i;
+
+	if (of_property_read_bool(np, "spk-mono"))
+		pdata->spk_mono = true;
+
+	if (of_property_read_u32(np, "mic-cfg", &val32) >= 0)
+		pdata->mic_cfg = val32;
+
+	if (of_property_read_u32_array(np, "gpio-cfg", pdata->gpio_init,
+				       ARRAY_SIZE(pdata->gpio_init)) >= 0)
+		for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++) {
+			/*
+			 * The range of GPIO register value is [0x0, 0xffff]
+			 * While the default value of each register is 0x0
+			 * Any other value will be regarded as default value
+			 */
+			if (pdata->gpio_init[i] > 0xffff)
+				pdata->gpio_init[i] = 0x0;
+		}
+
+	pdata->mclk = devm_clk_get(&i2c->dev, NULL);
+
+	return 0;
+}
+
+static int wm8962_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8962_pdata *pdata = dev_get_platdata(&i2c->dev);
+	struct wm8962_priv *wm8962;
+	unsigned int reg;
+	int ret, i, irq_pol, trigger;
+
+	wm8962 = devm_kzalloc(&i2c->dev, sizeof(*wm8962), GFP_KERNEL);
+	if (wm8962 == NULL)
+		return -ENOMEM;
+
+	mutex_init(&wm8962->dsp2_ena_lock);
+
+	i2c_set_clientdata(i2c, wm8962);
+
+	INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work);
+	init_completion(&wm8962->fll_lock);
+	wm8962->irq = i2c->irq;
+
+	/* If platform data was supplied, update the default data in priv */
+	if (pdata) {
+		memcpy(&wm8962->pdata, pdata, sizeof(struct wm8962_pdata));
+	} else if (i2c->dev.of_node) {
+		ret = wm8962_set_pdata_from_of(i2c, &wm8962->pdata);
+		if (ret != 0)
+			return ret;
+	}
+
+	/* Mark the mclk pointer to NULL if no mclk assigned */
+	if (IS_ERR(wm8962->pdata.mclk)) {
+		/* But do not ignore the request for probe defer */
+		if (PTR_ERR(wm8962->pdata.mclk) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+		wm8962->pdata.mclk = NULL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
+		wm8962->supplies[i].supply = wm8962_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8962->supplies),
+				 wm8962->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		goto err;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
+				    wm8962->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	wm8962->regmap = devm_regmap_init_i2c(i2c, &wm8962_regmap);
+	if (IS_ERR(wm8962->regmap)) {
+		ret = PTR_ERR(wm8962->regmap);
+		dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
+		goto err_enable;
+	}
+
+	/*
+	 * We haven't marked the chip revision as volatile due to
+	 * sharing a register with the right input volume; explicitly
+	 * bypass the cache to read it.
+	 */
+	regcache_cache_bypass(wm8962->regmap, true);
+
+	ret = regmap_read(wm8962->regmap, WM8962_SOFTWARE_RESET, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read ID register\n");
+		goto err_enable;
+	}
+	if (reg != 0x6243) {
+		dev_err(&i2c->dev,
+			"Device is not a WM8962, ID %x != 0x6243\n", reg);
+		ret = -EINVAL;
+		goto err_enable;
+	}
+
+	ret = regmap_read(wm8962->regmap, WM8962_RIGHT_INPUT_VOLUME, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read device revision: %d\n",
+			ret);
+		goto err_enable;
+	}
+
+	dev_info(&i2c->dev, "customer id %x revision %c\n",
+		 (reg & WM8962_CUST_ID_MASK) >> WM8962_CUST_ID_SHIFT,
+		 ((reg & WM8962_CHIP_REV_MASK) >> WM8962_CHIP_REV_SHIFT)
+		 + 'A');
+
+	regcache_cache_bypass(wm8962->regmap, false);
+
+	ret = wm8962_reset(wm8962);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to issue reset\n");
+		goto err_enable;
+	}
+
+	/* SYSCLK defaults to on; make sure it is off so we can safely
+	 * write to registers if the device is declocked.
+	 */
+	regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
+			   WM8962_SYSCLK_ENA, 0);
+
+	/* Ensure we have soft control over all registers */
+	regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
+			   WM8962_CLKREG_OVD, WM8962_CLKREG_OVD);
+
+	/* Ensure that the oscillator and PLLs are disabled */
+	regmap_update_bits(wm8962->regmap, WM8962_PLL2,
+			   WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
+			   0);
+
+	/* Apply static configuration for GPIOs */
+	for (i = 0; i < ARRAY_SIZE(wm8962->pdata.gpio_init); i++)
+		if (wm8962->pdata.gpio_init[i]) {
+			wm8962_set_gpio_mode(wm8962, i + 1);
+			regmap_write(wm8962->regmap, 0x200 + i,
+				     wm8962->pdata.gpio_init[i] & 0xffff);
+		}
+
+
+	/* Put the speakers into mono mode? */
+	if (wm8962->pdata.spk_mono)
+		regmap_update_bits(wm8962->regmap, WM8962_CLASS_D_CONTROL_2,
+				   WM8962_SPK_MONO_MASK, WM8962_SPK_MONO);
+
+	/* Micbias setup, detection enable and detection
+	 * threasholds. */
+	if (wm8962->pdata.mic_cfg)
+		regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4,
+				   WM8962_MICDET_ENA |
+				   WM8962_MICDET_THR_MASK |
+				   WM8962_MICSHORT_THR_MASK |
+				   WM8962_MICBIAS_LVL,
+				   wm8962->pdata.mic_cfg);
+
+	/* Latch volume update bits */
+	regmap_update_bits(wm8962->regmap, WM8962_LEFT_INPUT_VOLUME,
+			   WM8962_IN_VU, WM8962_IN_VU);
+	regmap_update_bits(wm8962->regmap, WM8962_RIGHT_INPUT_VOLUME,
+			   WM8962_IN_VU, WM8962_IN_VU);
+	regmap_update_bits(wm8962->regmap, WM8962_LEFT_ADC_VOLUME,
+			   WM8962_ADC_VU, WM8962_ADC_VU);
+	regmap_update_bits(wm8962->regmap, WM8962_RIGHT_ADC_VOLUME,
+			   WM8962_ADC_VU, WM8962_ADC_VU);
+	regmap_update_bits(wm8962->regmap, WM8962_LEFT_DAC_VOLUME,
+			   WM8962_DAC_VU, WM8962_DAC_VU);
+	regmap_update_bits(wm8962->regmap, WM8962_RIGHT_DAC_VOLUME,
+			   WM8962_DAC_VU, WM8962_DAC_VU);
+	regmap_update_bits(wm8962->regmap, WM8962_SPKOUTL_VOLUME,
+			   WM8962_SPKOUT_VU, WM8962_SPKOUT_VU);
+	regmap_update_bits(wm8962->regmap, WM8962_SPKOUTR_VOLUME,
+			   WM8962_SPKOUT_VU, WM8962_SPKOUT_VU);
+	regmap_update_bits(wm8962->regmap, WM8962_HPOUTL_VOLUME,
+			   WM8962_HPOUT_VU, WM8962_HPOUT_VU);
+	regmap_update_bits(wm8962->regmap, WM8962_HPOUTR_VOLUME,
+			   WM8962_HPOUT_VU, WM8962_HPOUT_VU);
+
+	/* Stereo control for EQ */
+	regmap_update_bits(wm8962->regmap, WM8962_EQ1,
+			   WM8962_EQ_SHARED_COEFF, 0);
+
+	/* Don't debouce interrupts so we don't need SYSCLK */
+	regmap_update_bits(wm8962->regmap, WM8962_IRQ_DEBOUNCE,
+			   WM8962_FLL_LOCK_DB | WM8962_PLL3_LOCK_DB |
+			   WM8962_PLL2_LOCK_DB | WM8962_TEMP_SHUT_DB,
+			   0);
+
+	if (wm8962->pdata.in4_dc_measure) {
+		ret = regmap_register_patch(wm8962->regmap,
+					    wm8962_dc_measure,
+					    ARRAY_SIZE(wm8962_dc_measure));
+		if (ret != 0)
+			dev_err(&i2c->dev,
+				"Failed to configure for DC measurement: %d\n",
+				ret);
+	}
+
+	if (wm8962->irq) {
+		if (wm8962->pdata.irq_active_low) {
+			trigger = IRQF_TRIGGER_LOW;
+			irq_pol = WM8962_IRQ_POL;
+		} else {
+			trigger = IRQF_TRIGGER_HIGH;
+			irq_pol = 0;
+		}
+
+		regmap_update_bits(wm8962->regmap, WM8962_INTERRUPT_CONTROL,
+				   WM8962_IRQ_POL, irq_pol);
+
+		ret = devm_request_threaded_irq(&i2c->dev, wm8962->irq, NULL,
+						wm8962_irq,
+						trigger | IRQF_ONESHOT,
+						"wm8962", &i2c->dev);
+		if (ret != 0) {
+			dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
+				wm8962->irq, ret);
+			wm8962->irq = 0;
+			/* Non-fatal */
+		} else {
+			/* Enable some IRQs by default */
+			regmap_update_bits(wm8962->regmap,
+					   WM8962_INTERRUPT_STATUS_2_MASK,
+					   WM8962_FLL_LOCK_EINT |
+					   WM8962_TEMP_SHUT_EINT |
+					   WM8962_FIFOS_ERR_EINT, 0);
+		}
+	}
+
+	pm_runtime_enable(&i2c->dev);
+	pm_request_idle(&i2c->dev);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_wm8962, &wm8962_dai, 1);
+	if (ret < 0)
+		goto err_pm_runtime;
+
+	regcache_cache_only(wm8962->regmap, true);
+
+	/* The drivers should power up as needed */
+	regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+
+	return 0;
+
+err_pm_runtime:
+	pm_runtime_disable(&i2c->dev);
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+err:
+	return ret;
+}
+
+static int wm8962_i2c_remove(struct i2c_client *client)
+{
+	pm_runtime_disable(&client->dev);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8962_runtime_resume(struct device *dev)
+{
+	struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(wm8962->pdata.mclk);
+	if (ret) {
+		dev_err(dev, "Failed to enable MCLK: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
+				    wm8962->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to enable supplies: %d\n", ret);
+		goto disable_clock;
+	}
+
+	regcache_cache_only(wm8962->regmap, false);
+
+	wm8962_reset(wm8962);
+
+	regcache_mark_dirty(wm8962->regmap);
+
+	/* SYSCLK defaults to on; make sure it is off so we can safely
+	 * write to registers if the device is declocked.
+	 */
+	regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
+			   WM8962_SYSCLK_ENA, 0);
+
+	/* Ensure we have soft control over all registers */
+	regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
+			   WM8962_CLKREG_OVD, WM8962_CLKREG_OVD);
+
+	/* Ensure that the oscillator and PLLs are disabled */
+	regmap_update_bits(wm8962->regmap, WM8962_PLL2,
+			   WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
+			   0);
+
+	regcache_sync(wm8962->regmap);
+
+	regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
+			   WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA,
+			   WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA);
+
+	/* Bias enable at 2*5k (fast start-up) */
+	regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
+			   WM8962_BIAS_ENA | WM8962_VMID_SEL_MASK,
+			   WM8962_BIAS_ENA | 0x180);
+
+	msleep(5);
+
+	return 0;
+
+disable_clock:
+	clk_disable_unprepare(wm8962->pdata.mclk);
+	return ret;
+}
+
+static int wm8962_runtime_suspend(struct device *dev)
+{
+	struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+
+	regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
+			   WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, 0);
+
+	regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
+			   WM8962_STARTUP_BIAS_ENA |
+			   WM8962_VMID_BUF_ENA, 0);
+
+	regcache_cache_only(wm8962->regmap, true);
+
+	regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies),
+			       wm8962->supplies);
+
+	clk_disable_unprepare(wm8962->pdata.mclk);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops wm8962_pm = {
+	SET_RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL)
+};
+
+static const struct i2c_device_id wm8962_i2c_id[] = {
+	{ "wm8962", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8962_i2c_id);
+
+static const struct of_device_id wm8962_of_match[] = {
+	{ .compatible = "wlf,wm8962", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wm8962_of_match);
+
+static struct i2c_driver wm8962_i2c_driver = {
+	.driver = {
+		.name = "wm8962",
+		.of_match_table = wm8962_of_match,
+		.pm = &wm8962_pm,
+	},
+	.probe =    wm8962_i2c_probe,
+	.remove =   wm8962_i2c_remove,
+	.id_table = wm8962_i2c_id,
+};
+
+module_i2c_driver(wm8962_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8962 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8962.h b/sound/soc/codecs/wm8962.h
new file mode 100644
index 0000000..a4a42d2
--- /dev/null
+++ b/sound/soc/codecs/wm8962.h
@@ -0,0 +1,3784 @@
+/*
+ * wm8962.h  --  WM8962 ASoC driver
+ *
+ * Copyright 2010 Wolfson Microelectronics, plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8962_H
+#define _WM8962_H
+
+#include <asm/types.h>
+#include <sound/soc.h>
+
+#define WM8962_SYSCLK_MCLK 0
+#define WM8962_SYSCLK_FLL  1
+#define WM8962_SYSCLK_PLL3 2
+
+#define WM8962_FLL  1
+
+#define WM8962_FLL_MCLK 1
+#define WM8962_FLL_BCLK 2
+#define WM8962_FLL_OSC  3
+#define WM8962_FLL_INT  4
+
+/*
+ * Register values.
+ */
+#define WM8962_LEFT_INPUT_VOLUME                0x00
+#define WM8962_RIGHT_INPUT_VOLUME               0x01
+#define WM8962_HPOUTL_VOLUME                    0x02
+#define WM8962_HPOUTR_VOLUME                    0x03
+#define WM8962_CLOCKING1                        0x04
+#define WM8962_ADC_DAC_CONTROL_1                0x05
+#define WM8962_ADC_DAC_CONTROL_2                0x06
+#define WM8962_AUDIO_INTERFACE_0                0x07
+#define WM8962_CLOCKING2                        0x08
+#define WM8962_AUDIO_INTERFACE_1                0x09
+#define WM8962_LEFT_DAC_VOLUME                  0x0A
+#define WM8962_RIGHT_DAC_VOLUME                 0x0B
+#define WM8962_AUDIO_INTERFACE_2                0x0E
+#define WM8962_SOFTWARE_RESET                   0x0F
+#define WM8962_ALC1                             0x11
+#define WM8962_ALC2                             0x12
+#define WM8962_ALC3                             0x13
+#define WM8962_NOISE_GATE                       0x14
+#define WM8962_LEFT_ADC_VOLUME                  0x15
+#define WM8962_RIGHT_ADC_VOLUME                 0x16
+#define WM8962_ADDITIONAL_CONTROL_1             0x17
+#define WM8962_ADDITIONAL_CONTROL_2             0x18
+#define WM8962_PWR_MGMT_1                       0x19
+#define WM8962_PWR_MGMT_2                       0x1A
+#define WM8962_ADDITIONAL_CONTROL_3             0x1B
+#define WM8962_ANTI_POP                         0x1C
+#define WM8962_CLOCKING_3                       0x1E
+#define WM8962_INPUT_MIXER_CONTROL_1            0x1F
+#define WM8962_LEFT_INPUT_MIXER_VOLUME          0x20
+#define WM8962_RIGHT_INPUT_MIXER_VOLUME         0x21
+#define WM8962_INPUT_MIXER_CONTROL_2            0x22
+#define WM8962_INPUT_BIAS_CONTROL               0x23
+#define WM8962_LEFT_INPUT_PGA_CONTROL           0x25
+#define WM8962_RIGHT_INPUT_PGA_CONTROL          0x26
+#define WM8962_SPKOUTL_VOLUME                   0x28
+#define WM8962_SPKOUTR_VOLUME                   0x29
+#define WM8962_THERMAL_SHUTDOWN_STATUS          0x2F
+#define WM8962_ADDITIONAL_CONTROL_4             0x30
+#define WM8962_CLASS_D_CONTROL_1                0x31
+#define WM8962_CLASS_D_CONTROL_2                0x33
+#define WM8962_CLOCKING_4                       0x38
+#define WM8962_DAC_DSP_MIXING_1                 0x39
+#define WM8962_DAC_DSP_MIXING_2                 0x3A
+#define WM8962_DC_SERVO_0                       0x3C
+#define WM8962_DC_SERVO_1                       0x3D
+#define WM8962_DC_SERVO_4                       0x40
+#define WM8962_DC_SERVO_6                       0x42
+#define WM8962_ANALOGUE_PGA_BIAS                0x44
+#define WM8962_ANALOGUE_HP_0                    0x45
+#define WM8962_ANALOGUE_HP_2                    0x47
+#define WM8962_CHARGE_PUMP_1                    0x48
+#define WM8962_CHARGE_PUMP_B                    0x52
+#define WM8962_WRITE_SEQUENCER_CONTROL_1        0x57
+#define WM8962_WRITE_SEQUENCER_CONTROL_2        0x5A
+#define WM8962_WRITE_SEQUENCER_CONTROL_3        0x5D
+#define WM8962_CONTROL_INTERFACE                0x5E
+#define WM8962_MIXER_ENABLES                    0x63
+#define WM8962_HEADPHONE_MIXER_1                0x64
+#define WM8962_HEADPHONE_MIXER_2                0x65
+#define WM8962_HEADPHONE_MIXER_3                0x66
+#define WM8962_HEADPHONE_MIXER_4                0x67
+#define WM8962_SPEAKER_MIXER_1                  0x69
+#define WM8962_SPEAKER_MIXER_2                  0x6A
+#define WM8962_SPEAKER_MIXER_3                  0x6B
+#define WM8962_SPEAKER_MIXER_4                  0x6C
+#define WM8962_SPEAKER_MIXER_5                  0x6D
+#define WM8962_BEEP_GENERATOR_1                 0x6E
+#define WM8962_OSCILLATOR_TRIM_3                0x73
+#define WM8962_OSCILLATOR_TRIM_4                0x74
+#define WM8962_OSCILLATOR_TRIM_7                0x77
+#define WM8962_ANALOGUE_CLOCKING1               0x7C
+#define WM8962_ANALOGUE_CLOCKING2               0x7D
+#define WM8962_ANALOGUE_CLOCKING3               0x7E
+#define WM8962_PLL_SOFTWARE_RESET               0x7F
+#define WM8962_PLL2                             0x81
+#define WM8962_PLL_4                            0x83
+#define WM8962_PLL_9                            0x88
+#define WM8962_PLL_10                           0x89
+#define WM8962_PLL_11                           0x8A
+#define WM8962_PLL_12                           0x8B
+#define WM8962_PLL_13                           0x8C
+#define WM8962_PLL_14                           0x8D
+#define WM8962_PLL_15                           0x8E
+#define WM8962_PLL_16                           0x8F
+#define WM8962_FLL_CONTROL_1                    0x9B
+#define WM8962_FLL_CONTROL_2                    0x9C
+#define WM8962_FLL_CONTROL_3                    0x9D
+#define WM8962_FLL_CONTROL_5                    0x9F
+#define WM8962_FLL_CONTROL_6                    0xA0
+#define WM8962_FLL_CONTROL_7                    0xA1
+#define WM8962_FLL_CONTROL_8                    0xA2
+#define WM8962_GENERAL_TEST_1                   0xFC
+#define WM8962_DF1                              0x100
+#define WM8962_DF2                              0x101
+#define WM8962_DF3                              0x102
+#define WM8962_DF4                              0x103
+#define WM8962_DF5                              0x104
+#define WM8962_DF6                              0x105
+#define WM8962_DF7                              0x106
+#define WM8962_LHPF1                            0x108
+#define WM8962_LHPF2                            0x109
+#define WM8962_THREED1                          0x10C
+#define WM8962_THREED2                          0x10D
+#define WM8962_THREED3                          0x10E
+#define WM8962_THREED4                          0x10F
+#define WM8962_DRC_1                            0x114
+#define WM8962_DRC_2                            0x115
+#define WM8962_DRC_3                            0x116
+#define WM8962_DRC_4                            0x117
+#define WM8962_DRC_5                            0x118
+#define WM8962_TLOOPBACK                        0x11D
+#define WM8962_EQ1                              0x14F
+#define WM8962_EQ2                              0x150
+#define WM8962_EQ3                              0x151
+#define WM8962_EQ4                              0x152
+#define WM8962_EQ5                              0x153
+#define WM8962_EQ6                              0x154
+#define WM8962_EQ7                              0x155
+#define WM8962_EQ8                              0x156
+#define WM8962_EQ9                              0x157
+#define WM8962_EQ10                             0x158
+#define WM8962_EQ11                             0x159
+#define WM8962_EQ12                             0x15A
+#define WM8962_EQ13                             0x15B
+#define WM8962_EQ14                             0x15C
+#define WM8962_EQ15                             0x15D
+#define WM8962_EQ16                             0x15E
+#define WM8962_EQ17                             0x15F
+#define WM8962_EQ18                             0x160
+#define WM8962_EQ19                             0x161
+#define WM8962_EQ20                             0x162
+#define WM8962_EQ21                             0x163
+#define WM8962_EQ22                             0x164
+#define WM8962_EQ23                             0x165
+#define WM8962_EQ24                             0x166
+#define WM8962_EQ25                             0x167
+#define WM8962_EQ26                             0x168
+#define WM8962_EQ27                             0x169
+#define WM8962_EQ28                             0x16A
+#define WM8962_EQ29                             0x16B
+#define WM8962_EQ30                             0x16C
+#define WM8962_EQ31                             0x16D
+#define WM8962_EQ32                             0x16E
+#define WM8962_EQ33                             0x16F
+#define WM8962_EQ34                             0x170
+#define WM8962_EQ35                             0x171
+#define WM8962_EQ36                             0x172
+#define WM8962_EQ37                             0x173
+#define WM8962_EQ38                             0x174
+#define WM8962_EQ39                             0x175
+#define WM8962_EQ40                             0x176
+#define WM8962_EQ41                             0x177
+#define WM8962_GPIO_BASE			0x200
+#define WM8962_GPIO_2                           0x201
+#define WM8962_GPIO_3                           0x202
+#define WM8962_GPIO_5                           0x204
+#define WM8962_GPIO_6                           0x205
+#define WM8962_INTERRUPT_STATUS_1               0x230
+#define WM8962_INTERRUPT_STATUS_2               0x231
+#define WM8962_INTERRUPT_STATUS_1_MASK          0x238
+#define WM8962_INTERRUPT_STATUS_2_MASK          0x239
+#define WM8962_INTERRUPT_CONTROL                0x240
+#define WM8962_IRQ_DEBOUNCE                     0x248
+#define WM8962_MICINT_SOURCE_POL                0x24A
+#define WM8962_DSP2_POWER_MANAGEMENT            0x300
+#define WM8962_DSP2_EXECCONTROL                 0x40D
+#define WM8962_WRITE_SEQUENCER_0                0x1000
+#define WM8962_WRITE_SEQUENCER_1                0x1001
+#define WM8962_WRITE_SEQUENCER_2                0x1002
+#define WM8962_WRITE_SEQUENCER_3                0x1003
+#define WM8962_WRITE_SEQUENCER_4                0x1004
+#define WM8962_WRITE_SEQUENCER_5                0x1005
+#define WM8962_WRITE_SEQUENCER_6                0x1006
+#define WM8962_WRITE_SEQUENCER_7                0x1007
+#define WM8962_WRITE_SEQUENCER_8                0x1008
+#define WM8962_WRITE_SEQUENCER_9                0x1009
+#define WM8962_WRITE_SEQUENCER_10               0x100A
+#define WM8962_WRITE_SEQUENCER_11               0x100B
+#define WM8962_WRITE_SEQUENCER_12               0x100C
+#define WM8962_WRITE_SEQUENCER_13               0x100D
+#define WM8962_WRITE_SEQUENCER_14               0x100E
+#define WM8962_WRITE_SEQUENCER_15               0x100F
+#define WM8962_WRITE_SEQUENCER_16               0x1010
+#define WM8962_WRITE_SEQUENCER_17               0x1011
+#define WM8962_WRITE_SEQUENCER_18               0x1012
+#define WM8962_WRITE_SEQUENCER_19               0x1013
+#define WM8962_WRITE_SEQUENCER_20               0x1014
+#define WM8962_WRITE_SEQUENCER_21               0x1015
+#define WM8962_WRITE_SEQUENCER_22               0x1016
+#define WM8962_WRITE_SEQUENCER_23               0x1017
+#define WM8962_WRITE_SEQUENCER_24               0x1018
+#define WM8962_WRITE_SEQUENCER_25               0x1019
+#define WM8962_WRITE_SEQUENCER_26               0x101A
+#define WM8962_WRITE_SEQUENCER_27               0x101B
+#define WM8962_WRITE_SEQUENCER_28               0x101C
+#define WM8962_WRITE_SEQUENCER_29               0x101D
+#define WM8962_WRITE_SEQUENCER_30               0x101E
+#define WM8962_WRITE_SEQUENCER_31               0x101F
+#define WM8962_WRITE_SEQUENCER_32               0x1020
+#define WM8962_WRITE_SEQUENCER_33               0x1021
+#define WM8962_WRITE_SEQUENCER_34               0x1022
+#define WM8962_WRITE_SEQUENCER_35               0x1023
+#define WM8962_WRITE_SEQUENCER_36               0x1024
+#define WM8962_WRITE_SEQUENCER_37               0x1025
+#define WM8962_WRITE_SEQUENCER_38               0x1026
+#define WM8962_WRITE_SEQUENCER_39               0x1027
+#define WM8962_WRITE_SEQUENCER_40               0x1028
+#define WM8962_WRITE_SEQUENCER_41               0x1029
+#define WM8962_WRITE_SEQUENCER_42               0x102A
+#define WM8962_WRITE_SEQUENCER_43               0x102B
+#define WM8962_WRITE_SEQUENCER_44               0x102C
+#define WM8962_WRITE_SEQUENCER_45               0x102D
+#define WM8962_WRITE_SEQUENCER_46               0x102E
+#define WM8962_WRITE_SEQUENCER_47               0x102F
+#define WM8962_WRITE_SEQUENCER_48               0x1030
+#define WM8962_WRITE_SEQUENCER_49               0x1031
+#define WM8962_WRITE_SEQUENCER_50               0x1032
+#define WM8962_WRITE_SEQUENCER_51               0x1033
+#define WM8962_WRITE_SEQUENCER_52               0x1034
+#define WM8962_WRITE_SEQUENCER_53               0x1035
+#define WM8962_WRITE_SEQUENCER_54               0x1036
+#define WM8962_WRITE_SEQUENCER_55               0x1037
+#define WM8962_WRITE_SEQUENCER_56               0x1038
+#define WM8962_WRITE_SEQUENCER_57               0x1039
+#define WM8962_WRITE_SEQUENCER_58               0x103A
+#define WM8962_WRITE_SEQUENCER_59               0x103B
+#define WM8962_WRITE_SEQUENCER_60               0x103C
+#define WM8962_WRITE_SEQUENCER_61               0x103D
+#define WM8962_WRITE_SEQUENCER_62               0x103E
+#define WM8962_WRITE_SEQUENCER_63               0x103F
+#define WM8962_WRITE_SEQUENCER_64               0x1040
+#define WM8962_WRITE_SEQUENCER_65               0x1041
+#define WM8962_WRITE_SEQUENCER_66               0x1042
+#define WM8962_WRITE_SEQUENCER_67               0x1043
+#define WM8962_WRITE_SEQUENCER_68               0x1044
+#define WM8962_WRITE_SEQUENCER_69               0x1045
+#define WM8962_WRITE_SEQUENCER_70               0x1046
+#define WM8962_WRITE_SEQUENCER_71               0x1047
+#define WM8962_WRITE_SEQUENCER_72               0x1048
+#define WM8962_WRITE_SEQUENCER_73               0x1049
+#define WM8962_WRITE_SEQUENCER_74               0x104A
+#define WM8962_WRITE_SEQUENCER_75               0x104B
+#define WM8962_WRITE_SEQUENCER_76               0x104C
+#define WM8962_WRITE_SEQUENCER_77               0x104D
+#define WM8962_WRITE_SEQUENCER_78               0x104E
+#define WM8962_WRITE_SEQUENCER_79               0x104F
+#define WM8962_WRITE_SEQUENCER_80               0x1050
+#define WM8962_WRITE_SEQUENCER_81               0x1051
+#define WM8962_WRITE_SEQUENCER_82               0x1052
+#define WM8962_WRITE_SEQUENCER_83               0x1053
+#define WM8962_WRITE_SEQUENCER_84               0x1054
+#define WM8962_WRITE_SEQUENCER_85               0x1055
+#define WM8962_WRITE_SEQUENCER_86               0x1056
+#define WM8962_WRITE_SEQUENCER_87               0x1057
+#define WM8962_WRITE_SEQUENCER_88               0x1058
+#define WM8962_WRITE_SEQUENCER_89               0x1059
+#define WM8962_WRITE_SEQUENCER_90               0x105A
+#define WM8962_WRITE_SEQUENCER_91               0x105B
+#define WM8962_WRITE_SEQUENCER_92               0x105C
+#define WM8962_WRITE_SEQUENCER_93               0x105D
+#define WM8962_WRITE_SEQUENCER_94               0x105E
+#define WM8962_WRITE_SEQUENCER_95               0x105F
+#define WM8962_WRITE_SEQUENCER_96               0x1060
+#define WM8962_WRITE_SEQUENCER_97               0x1061
+#define WM8962_WRITE_SEQUENCER_98               0x1062
+#define WM8962_WRITE_SEQUENCER_99               0x1063
+#define WM8962_WRITE_SEQUENCER_100              0x1064
+#define WM8962_WRITE_SEQUENCER_101              0x1065
+#define WM8962_WRITE_SEQUENCER_102              0x1066
+#define WM8962_WRITE_SEQUENCER_103              0x1067
+#define WM8962_WRITE_SEQUENCER_104              0x1068
+#define WM8962_WRITE_SEQUENCER_105              0x1069
+#define WM8962_WRITE_SEQUENCER_106              0x106A
+#define WM8962_WRITE_SEQUENCER_107              0x106B
+#define WM8962_WRITE_SEQUENCER_108              0x106C
+#define WM8962_WRITE_SEQUENCER_109              0x106D
+#define WM8962_WRITE_SEQUENCER_110              0x106E
+#define WM8962_WRITE_SEQUENCER_111              0x106F
+#define WM8962_WRITE_SEQUENCER_112              0x1070
+#define WM8962_WRITE_SEQUENCER_113              0x1071
+#define WM8962_WRITE_SEQUENCER_114              0x1072
+#define WM8962_WRITE_SEQUENCER_115              0x1073
+#define WM8962_WRITE_SEQUENCER_116              0x1074
+#define WM8962_WRITE_SEQUENCER_117              0x1075
+#define WM8962_WRITE_SEQUENCER_118              0x1076
+#define WM8962_WRITE_SEQUENCER_119              0x1077
+#define WM8962_WRITE_SEQUENCER_120              0x1078
+#define WM8962_WRITE_SEQUENCER_121              0x1079
+#define WM8962_WRITE_SEQUENCER_122              0x107A
+#define WM8962_WRITE_SEQUENCER_123              0x107B
+#define WM8962_WRITE_SEQUENCER_124              0x107C
+#define WM8962_WRITE_SEQUENCER_125              0x107D
+#define WM8962_WRITE_SEQUENCER_126              0x107E
+#define WM8962_WRITE_SEQUENCER_127              0x107F
+#define WM8962_WRITE_SEQUENCER_128              0x1080
+#define WM8962_WRITE_SEQUENCER_129              0x1081
+#define WM8962_WRITE_SEQUENCER_130              0x1082
+#define WM8962_WRITE_SEQUENCER_131              0x1083
+#define WM8962_WRITE_SEQUENCER_132              0x1084
+#define WM8962_WRITE_SEQUENCER_133              0x1085
+#define WM8962_WRITE_SEQUENCER_134              0x1086
+#define WM8962_WRITE_SEQUENCER_135              0x1087
+#define WM8962_WRITE_SEQUENCER_136              0x1088
+#define WM8962_WRITE_SEQUENCER_137              0x1089
+#define WM8962_WRITE_SEQUENCER_138              0x108A
+#define WM8962_WRITE_SEQUENCER_139              0x108B
+#define WM8962_WRITE_SEQUENCER_140              0x108C
+#define WM8962_WRITE_SEQUENCER_141              0x108D
+#define WM8962_WRITE_SEQUENCER_142              0x108E
+#define WM8962_WRITE_SEQUENCER_143              0x108F
+#define WM8962_WRITE_SEQUENCER_144              0x1090
+#define WM8962_WRITE_SEQUENCER_145              0x1091
+#define WM8962_WRITE_SEQUENCER_146              0x1092
+#define WM8962_WRITE_SEQUENCER_147              0x1093
+#define WM8962_WRITE_SEQUENCER_148              0x1094
+#define WM8962_WRITE_SEQUENCER_149              0x1095
+#define WM8962_WRITE_SEQUENCER_150              0x1096
+#define WM8962_WRITE_SEQUENCER_151              0x1097
+#define WM8962_WRITE_SEQUENCER_152              0x1098
+#define WM8962_WRITE_SEQUENCER_153              0x1099
+#define WM8962_WRITE_SEQUENCER_154              0x109A
+#define WM8962_WRITE_SEQUENCER_155              0x109B
+#define WM8962_WRITE_SEQUENCER_156              0x109C
+#define WM8962_WRITE_SEQUENCER_157              0x109D
+#define WM8962_WRITE_SEQUENCER_158              0x109E
+#define WM8962_WRITE_SEQUENCER_159              0x109F
+#define WM8962_WRITE_SEQUENCER_160              0x10A0
+#define WM8962_WRITE_SEQUENCER_161              0x10A1
+#define WM8962_WRITE_SEQUENCER_162              0x10A2
+#define WM8962_WRITE_SEQUENCER_163              0x10A3
+#define WM8962_WRITE_SEQUENCER_164              0x10A4
+#define WM8962_WRITE_SEQUENCER_165              0x10A5
+#define WM8962_WRITE_SEQUENCER_166              0x10A6
+#define WM8962_WRITE_SEQUENCER_167              0x10A7
+#define WM8962_WRITE_SEQUENCER_168              0x10A8
+#define WM8962_WRITE_SEQUENCER_169              0x10A9
+#define WM8962_WRITE_SEQUENCER_170              0x10AA
+#define WM8962_WRITE_SEQUENCER_171              0x10AB
+#define WM8962_WRITE_SEQUENCER_172              0x10AC
+#define WM8962_WRITE_SEQUENCER_173              0x10AD
+#define WM8962_WRITE_SEQUENCER_174              0x10AE
+#define WM8962_WRITE_SEQUENCER_175              0x10AF
+#define WM8962_WRITE_SEQUENCER_176              0x10B0
+#define WM8962_WRITE_SEQUENCER_177              0x10B1
+#define WM8962_WRITE_SEQUENCER_178              0x10B2
+#define WM8962_WRITE_SEQUENCER_179              0x10B3
+#define WM8962_WRITE_SEQUENCER_180              0x10B4
+#define WM8962_WRITE_SEQUENCER_181              0x10B5
+#define WM8962_WRITE_SEQUENCER_182              0x10B6
+#define WM8962_WRITE_SEQUENCER_183              0x10B7
+#define WM8962_WRITE_SEQUENCER_184              0x10B8
+#define WM8962_WRITE_SEQUENCER_185              0x10B9
+#define WM8962_WRITE_SEQUENCER_186              0x10BA
+#define WM8962_WRITE_SEQUENCER_187              0x10BB
+#define WM8962_WRITE_SEQUENCER_188              0x10BC
+#define WM8962_WRITE_SEQUENCER_189              0x10BD
+#define WM8962_WRITE_SEQUENCER_190              0x10BE
+#define WM8962_WRITE_SEQUENCER_191              0x10BF
+#define WM8962_WRITE_SEQUENCER_192              0x10C0
+#define WM8962_WRITE_SEQUENCER_193              0x10C1
+#define WM8962_WRITE_SEQUENCER_194              0x10C2
+#define WM8962_WRITE_SEQUENCER_195              0x10C3
+#define WM8962_WRITE_SEQUENCER_196              0x10C4
+#define WM8962_WRITE_SEQUENCER_197              0x10C5
+#define WM8962_WRITE_SEQUENCER_198              0x10C6
+#define WM8962_WRITE_SEQUENCER_199              0x10C7
+#define WM8962_WRITE_SEQUENCER_200              0x10C8
+#define WM8962_WRITE_SEQUENCER_201              0x10C9
+#define WM8962_WRITE_SEQUENCER_202              0x10CA
+#define WM8962_WRITE_SEQUENCER_203              0x10CB
+#define WM8962_WRITE_SEQUENCER_204              0x10CC
+#define WM8962_WRITE_SEQUENCER_205              0x10CD
+#define WM8962_WRITE_SEQUENCER_206              0x10CE
+#define WM8962_WRITE_SEQUENCER_207              0x10CF
+#define WM8962_WRITE_SEQUENCER_208              0x10D0
+#define WM8962_WRITE_SEQUENCER_209              0x10D1
+#define WM8962_WRITE_SEQUENCER_210              0x10D2
+#define WM8962_WRITE_SEQUENCER_211              0x10D3
+#define WM8962_WRITE_SEQUENCER_212              0x10D4
+#define WM8962_WRITE_SEQUENCER_213              0x10D5
+#define WM8962_WRITE_SEQUENCER_214              0x10D6
+#define WM8962_WRITE_SEQUENCER_215              0x10D7
+#define WM8962_WRITE_SEQUENCER_216              0x10D8
+#define WM8962_WRITE_SEQUENCER_217              0x10D9
+#define WM8962_WRITE_SEQUENCER_218              0x10DA
+#define WM8962_WRITE_SEQUENCER_219              0x10DB
+#define WM8962_WRITE_SEQUENCER_220              0x10DC
+#define WM8962_WRITE_SEQUENCER_221              0x10DD
+#define WM8962_WRITE_SEQUENCER_222              0x10DE
+#define WM8962_WRITE_SEQUENCER_223              0x10DF
+#define WM8962_WRITE_SEQUENCER_224              0x10E0
+#define WM8962_WRITE_SEQUENCER_225              0x10E1
+#define WM8962_WRITE_SEQUENCER_226              0x10E2
+#define WM8962_WRITE_SEQUENCER_227              0x10E3
+#define WM8962_WRITE_SEQUENCER_228              0x10E4
+#define WM8962_WRITE_SEQUENCER_229              0x10E5
+#define WM8962_WRITE_SEQUENCER_230              0x10E6
+#define WM8962_WRITE_SEQUENCER_231              0x10E7
+#define WM8962_WRITE_SEQUENCER_232              0x10E8
+#define WM8962_WRITE_SEQUENCER_233              0x10E9
+#define WM8962_WRITE_SEQUENCER_234              0x10EA
+#define WM8962_WRITE_SEQUENCER_235              0x10EB
+#define WM8962_WRITE_SEQUENCER_236              0x10EC
+#define WM8962_WRITE_SEQUENCER_237              0x10ED
+#define WM8962_WRITE_SEQUENCER_238              0x10EE
+#define WM8962_WRITE_SEQUENCER_239              0x10EF
+#define WM8962_WRITE_SEQUENCER_240              0x10F0
+#define WM8962_WRITE_SEQUENCER_241              0x10F1
+#define WM8962_WRITE_SEQUENCER_242              0x10F2
+#define WM8962_WRITE_SEQUENCER_243              0x10F3
+#define WM8962_WRITE_SEQUENCER_244              0x10F4
+#define WM8962_WRITE_SEQUENCER_245              0x10F5
+#define WM8962_WRITE_SEQUENCER_246              0x10F6
+#define WM8962_WRITE_SEQUENCER_247              0x10F7
+#define WM8962_WRITE_SEQUENCER_248              0x10F8
+#define WM8962_WRITE_SEQUENCER_249              0x10F9
+#define WM8962_WRITE_SEQUENCER_250              0x10FA
+#define WM8962_WRITE_SEQUENCER_251              0x10FB
+#define WM8962_WRITE_SEQUENCER_252              0x10FC
+#define WM8962_WRITE_SEQUENCER_253              0x10FD
+#define WM8962_WRITE_SEQUENCER_254              0x10FE
+#define WM8962_WRITE_SEQUENCER_255              0x10FF
+#define WM8962_WRITE_SEQUENCER_256              0x1100
+#define WM8962_WRITE_SEQUENCER_257              0x1101
+#define WM8962_WRITE_SEQUENCER_258              0x1102
+#define WM8962_WRITE_SEQUENCER_259              0x1103
+#define WM8962_WRITE_SEQUENCER_260              0x1104
+#define WM8962_WRITE_SEQUENCER_261              0x1105
+#define WM8962_WRITE_SEQUENCER_262              0x1106
+#define WM8962_WRITE_SEQUENCER_263              0x1107
+#define WM8962_WRITE_SEQUENCER_264              0x1108
+#define WM8962_WRITE_SEQUENCER_265              0x1109
+#define WM8962_WRITE_SEQUENCER_266              0x110A
+#define WM8962_WRITE_SEQUENCER_267              0x110B
+#define WM8962_WRITE_SEQUENCER_268              0x110C
+#define WM8962_WRITE_SEQUENCER_269              0x110D
+#define WM8962_WRITE_SEQUENCER_270              0x110E
+#define WM8962_WRITE_SEQUENCER_271              0x110F
+#define WM8962_WRITE_SEQUENCER_272              0x1110
+#define WM8962_WRITE_SEQUENCER_273              0x1111
+#define WM8962_WRITE_SEQUENCER_274              0x1112
+#define WM8962_WRITE_SEQUENCER_275              0x1113
+#define WM8962_WRITE_SEQUENCER_276              0x1114
+#define WM8962_WRITE_SEQUENCER_277              0x1115
+#define WM8962_WRITE_SEQUENCER_278              0x1116
+#define WM8962_WRITE_SEQUENCER_279              0x1117
+#define WM8962_WRITE_SEQUENCER_280              0x1118
+#define WM8962_WRITE_SEQUENCER_281              0x1119
+#define WM8962_WRITE_SEQUENCER_282              0x111A
+#define WM8962_WRITE_SEQUENCER_283              0x111B
+#define WM8962_WRITE_SEQUENCER_284              0x111C
+#define WM8962_WRITE_SEQUENCER_285              0x111D
+#define WM8962_WRITE_SEQUENCER_286              0x111E
+#define WM8962_WRITE_SEQUENCER_287              0x111F
+#define WM8962_WRITE_SEQUENCER_288              0x1120
+#define WM8962_WRITE_SEQUENCER_289              0x1121
+#define WM8962_WRITE_SEQUENCER_290              0x1122
+#define WM8962_WRITE_SEQUENCER_291              0x1123
+#define WM8962_WRITE_SEQUENCER_292              0x1124
+#define WM8962_WRITE_SEQUENCER_293              0x1125
+#define WM8962_WRITE_SEQUENCER_294              0x1126
+#define WM8962_WRITE_SEQUENCER_295              0x1127
+#define WM8962_WRITE_SEQUENCER_296              0x1128
+#define WM8962_WRITE_SEQUENCER_297              0x1129
+#define WM8962_WRITE_SEQUENCER_298              0x112A
+#define WM8962_WRITE_SEQUENCER_299              0x112B
+#define WM8962_WRITE_SEQUENCER_300              0x112C
+#define WM8962_WRITE_SEQUENCER_301              0x112D
+#define WM8962_WRITE_SEQUENCER_302              0x112E
+#define WM8962_WRITE_SEQUENCER_303              0x112F
+#define WM8962_WRITE_SEQUENCER_304              0x1130
+#define WM8962_WRITE_SEQUENCER_305              0x1131
+#define WM8962_WRITE_SEQUENCER_306              0x1132
+#define WM8962_WRITE_SEQUENCER_307              0x1133
+#define WM8962_WRITE_SEQUENCER_308              0x1134
+#define WM8962_WRITE_SEQUENCER_309              0x1135
+#define WM8962_WRITE_SEQUENCER_310              0x1136
+#define WM8962_WRITE_SEQUENCER_311              0x1137
+#define WM8962_WRITE_SEQUENCER_312              0x1138
+#define WM8962_WRITE_SEQUENCER_313              0x1139
+#define WM8962_WRITE_SEQUENCER_314              0x113A
+#define WM8962_WRITE_SEQUENCER_315              0x113B
+#define WM8962_WRITE_SEQUENCER_316              0x113C
+#define WM8962_WRITE_SEQUENCER_317              0x113D
+#define WM8962_WRITE_SEQUENCER_318              0x113E
+#define WM8962_WRITE_SEQUENCER_319              0x113F
+#define WM8962_WRITE_SEQUENCER_320              0x1140
+#define WM8962_WRITE_SEQUENCER_321              0x1141
+#define WM8962_WRITE_SEQUENCER_322              0x1142
+#define WM8962_WRITE_SEQUENCER_323              0x1143
+#define WM8962_WRITE_SEQUENCER_324              0x1144
+#define WM8962_WRITE_SEQUENCER_325              0x1145
+#define WM8962_WRITE_SEQUENCER_326              0x1146
+#define WM8962_WRITE_SEQUENCER_327              0x1147
+#define WM8962_WRITE_SEQUENCER_328              0x1148
+#define WM8962_WRITE_SEQUENCER_329              0x1149
+#define WM8962_WRITE_SEQUENCER_330              0x114A
+#define WM8962_WRITE_SEQUENCER_331              0x114B
+#define WM8962_WRITE_SEQUENCER_332              0x114C
+#define WM8962_WRITE_SEQUENCER_333              0x114D
+#define WM8962_WRITE_SEQUENCER_334              0x114E
+#define WM8962_WRITE_SEQUENCER_335              0x114F
+#define WM8962_WRITE_SEQUENCER_336              0x1150
+#define WM8962_WRITE_SEQUENCER_337              0x1151
+#define WM8962_WRITE_SEQUENCER_338              0x1152
+#define WM8962_WRITE_SEQUENCER_339              0x1153
+#define WM8962_WRITE_SEQUENCER_340              0x1154
+#define WM8962_WRITE_SEQUENCER_341              0x1155
+#define WM8962_WRITE_SEQUENCER_342              0x1156
+#define WM8962_WRITE_SEQUENCER_343              0x1157
+#define WM8962_WRITE_SEQUENCER_344              0x1158
+#define WM8962_WRITE_SEQUENCER_345              0x1159
+#define WM8962_WRITE_SEQUENCER_346              0x115A
+#define WM8962_WRITE_SEQUENCER_347              0x115B
+#define WM8962_WRITE_SEQUENCER_348              0x115C
+#define WM8962_WRITE_SEQUENCER_349              0x115D
+#define WM8962_WRITE_SEQUENCER_350              0x115E
+#define WM8962_WRITE_SEQUENCER_351              0x115F
+#define WM8962_WRITE_SEQUENCER_352              0x1160
+#define WM8962_WRITE_SEQUENCER_353              0x1161
+#define WM8962_WRITE_SEQUENCER_354              0x1162
+#define WM8962_WRITE_SEQUENCER_355              0x1163
+#define WM8962_WRITE_SEQUENCER_356              0x1164
+#define WM8962_WRITE_SEQUENCER_357              0x1165
+#define WM8962_WRITE_SEQUENCER_358              0x1166
+#define WM8962_WRITE_SEQUENCER_359              0x1167
+#define WM8962_WRITE_SEQUENCER_360              0x1168
+#define WM8962_WRITE_SEQUENCER_361              0x1169
+#define WM8962_WRITE_SEQUENCER_362              0x116A
+#define WM8962_WRITE_SEQUENCER_363              0x116B
+#define WM8962_WRITE_SEQUENCER_364              0x116C
+#define WM8962_WRITE_SEQUENCER_365              0x116D
+#define WM8962_WRITE_SEQUENCER_366              0x116E
+#define WM8962_WRITE_SEQUENCER_367              0x116F
+#define WM8962_WRITE_SEQUENCER_368              0x1170
+#define WM8962_WRITE_SEQUENCER_369              0x1171
+#define WM8962_WRITE_SEQUENCER_370              0x1172
+#define WM8962_WRITE_SEQUENCER_371              0x1173
+#define WM8962_WRITE_SEQUENCER_372              0x1174
+#define WM8962_WRITE_SEQUENCER_373              0x1175
+#define WM8962_WRITE_SEQUENCER_374              0x1176
+#define WM8962_WRITE_SEQUENCER_375              0x1177
+#define WM8962_WRITE_SEQUENCER_376              0x1178
+#define WM8962_WRITE_SEQUENCER_377              0x1179
+#define WM8962_WRITE_SEQUENCER_378              0x117A
+#define WM8962_WRITE_SEQUENCER_379              0x117B
+#define WM8962_WRITE_SEQUENCER_380              0x117C
+#define WM8962_WRITE_SEQUENCER_381              0x117D
+#define WM8962_WRITE_SEQUENCER_382              0x117E
+#define WM8962_WRITE_SEQUENCER_383              0x117F
+#define WM8962_WRITE_SEQUENCER_384              0x1180
+#define WM8962_WRITE_SEQUENCER_385              0x1181
+#define WM8962_WRITE_SEQUENCER_386              0x1182
+#define WM8962_WRITE_SEQUENCER_387              0x1183
+#define WM8962_WRITE_SEQUENCER_388              0x1184
+#define WM8962_WRITE_SEQUENCER_389              0x1185
+#define WM8962_WRITE_SEQUENCER_390              0x1186
+#define WM8962_WRITE_SEQUENCER_391              0x1187
+#define WM8962_WRITE_SEQUENCER_392              0x1188
+#define WM8962_WRITE_SEQUENCER_393              0x1189
+#define WM8962_WRITE_SEQUENCER_394              0x118A
+#define WM8962_WRITE_SEQUENCER_395              0x118B
+#define WM8962_WRITE_SEQUENCER_396              0x118C
+#define WM8962_WRITE_SEQUENCER_397              0x118D
+#define WM8962_WRITE_SEQUENCER_398              0x118E
+#define WM8962_WRITE_SEQUENCER_399              0x118F
+#define WM8962_WRITE_SEQUENCER_400              0x1190
+#define WM8962_WRITE_SEQUENCER_401              0x1191
+#define WM8962_WRITE_SEQUENCER_402              0x1192
+#define WM8962_WRITE_SEQUENCER_403              0x1193
+#define WM8962_WRITE_SEQUENCER_404              0x1194
+#define WM8962_WRITE_SEQUENCER_405              0x1195
+#define WM8962_WRITE_SEQUENCER_406              0x1196
+#define WM8962_WRITE_SEQUENCER_407              0x1197
+#define WM8962_WRITE_SEQUENCER_408              0x1198
+#define WM8962_WRITE_SEQUENCER_409              0x1199
+#define WM8962_WRITE_SEQUENCER_410              0x119A
+#define WM8962_WRITE_SEQUENCER_411              0x119B
+#define WM8962_WRITE_SEQUENCER_412              0x119C
+#define WM8962_WRITE_SEQUENCER_413              0x119D
+#define WM8962_WRITE_SEQUENCER_414              0x119E
+#define WM8962_WRITE_SEQUENCER_415              0x119F
+#define WM8962_WRITE_SEQUENCER_416              0x11A0
+#define WM8962_WRITE_SEQUENCER_417              0x11A1
+#define WM8962_WRITE_SEQUENCER_418              0x11A2
+#define WM8962_WRITE_SEQUENCER_419              0x11A3
+#define WM8962_WRITE_SEQUENCER_420              0x11A4
+#define WM8962_WRITE_SEQUENCER_421              0x11A5
+#define WM8962_WRITE_SEQUENCER_422              0x11A6
+#define WM8962_WRITE_SEQUENCER_423              0x11A7
+#define WM8962_WRITE_SEQUENCER_424              0x11A8
+#define WM8962_WRITE_SEQUENCER_425              0x11A9
+#define WM8962_WRITE_SEQUENCER_426              0x11AA
+#define WM8962_WRITE_SEQUENCER_427              0x11AB
+#define WM8962_WRITE_SEQUENCER_428              0x11AC
+#define WM8962_WRITE_SEQUENCER_429              0x11AD
+#define WM8962_WRITE_SEQUENCER_430              0x11AE
+#define WM8962_WRITE_SEQUENCER_431              0x11AF
+#define WM8962_WRITE_SEQUENCER_432              0x11B0
+#define WM8962_WRITE_SEQUENCER_433              0x11B1
+#define WM8962_WRITE_SEQUENCER_434              0x11B2
+#define WM8962_WRITE_SEQUENCER_435              0x11B3
+#define WM8962_WRITE_SEQUENCER_436              0x11B4
+#define WM8962_WRITE_SEQUENCER_437              0x11B5
+#define WM8962_WRITE_SEQUENCER_438              0x11B6
+#define WM8962_WRITE_SEQUENCER_439              0x11B7
+#define WM8962_WRITE_SEQUENCER_440              0x11B8
+#define WM8962_WRITE_SEQUENCER_441              0x11B9
+#define WM8962_WRITE_SEQUENCER_442              0x11BA
+#define WM8962_WRITE_SEQUENCER_443              0x11BB
+#define WM8962_WRITE_SEQUENCER_444              0x11BC
+#define WM8962_WRITE_SEQUENCER_445              0x11BD
+#define WM8962_WRITE_SEQUENCER_446              0x11BE
+#define WM8962_WRITE_SEQUENCER_447              0x11BF
+#define WM8962_WRITE_SEQUENCER_448              0x11C0
+#define WM8962_WRITE_SEQUENCER_449              0x11C1
+#define WM8962_WRITE_SEQUENCER_450              0x11C2
+#define WM8962_WRITE_SEQUENCER_451              0x11C3
+#define WM8962_WRITE_SEQUENCER_452              0x11C4
+#define WM8962_WRITE_SEQUENCER_453              0x11C5
+#define WM8962_WRITE_SEQUENCER_454              0x11C6
+#define WM8962_WRITE_SEQUENCER_455              0x11C7
+#define WM8962_WRITE_SEQUENCER_456              0x11C8
+#define WM8962_WRITE_SEQUENCER_457              0x11C9
+#define WM8962_WRITE_SEQUENCER_458              0x11CA
+#define WM8962_WRITE_SEQUENCER_459              0x11CB
+#define WM8962_WRITE_SEQUENCER_460              0x11CC
+#define WM8962_WRITE_SEQUENCER_461              0x11CD
+#define WM8962_WRITE_SEQUENCER_462              0x11CE
+#define WM8962_WRITE_SEQUENCER_463              0x11CF
+#define WM8962_WRITE_SEQUENCER_464              0x11D0
+#define WM8962_WRITE_SEQUENCER_465              0x11D1
+#define WM8962_WRITE_SEQUENCER_466              0x11D2
+#define WM8962_WRITE_SEQUENCER_467              0x11D3
+#define WM8962_WRITE_SEQUENCER_468              0x11D4
+#define WM8962_WRITE_SEQUENCER_469              0x11D5
+#define WM8962_WRITE_SEQUENCER_470              0x11D6
+#define WM8962_WRITE_SEQUENCER_471              0x11D7
+#define WM8962_WRITE_SEQUENCER_472              0x11D8
+#define WM8962_WRITE_SEQUENCER_473              0x11D9
+#define WM8962_WRITE_SEQUENCER_474              0x11DA
+#define WM8962_WRITE_SEQUENCER_475              0x11DB
+#define WM8962_WRITE_SEQUENCER_476              0x11DC
+#define WM8962_WRITE_SEQUENCER_477              0x11DD
+#define WM8962_WRITE_SEQUENCER_478              0x11DE
+#define WM8962_WRITE_SEQUENCER_479              0x11DF
+#define WM8962_WRITE_SEQUENCER_480              0x11E0
+#define WM8962_WRITE_SEQUENCER_481              0x11E1
+#define WM8962_WRITE_SEQUENCER_482              0x11E2
+#define WM8962_WRITE_SEQUENCER_483              0x11E3
+#define WM8962_WRITE_SEQUENCER_484              0x11E4
+#define WM8962_WRITE_SEQUENCER_485              0x11E5
+#define WM8962_WRITE_SEQUENCER_486              0x11E6
+#define WM8962_WRITE_SEQUENCER_487              0x11E7
+#define WM8962_WRITE_SEQUENCER_488              0x11E8
+#define WM8962_WRITE_SEQUENCER_489              0x11E9
+#define WM8962_WRITE_SEQUENCER_490              0x11EA
+#define WM8962_WRITE_SEQUENCER_491              0x11EB
+#define WM8962_WRITE_SEQUENCER_492              0x11EC
+#define WM8962_WRITE_SEQUENCER_493              0x11ED
+#define WM8962_WRITE_SEQUENCER_494              0x11EE
+#define WM8962_WRITE_SEQUENCER_495              0x11EF
+#define WM8962_WRITE_SEQUENCER_496              0x11F0
+#define WM8962_WRITE_SEQUENCER_497              0x11F1
+#define WM8962_WRITE_SEQUENCER_498              0x11F2
+#define WM8962_WRITE_SEQUENCER_499              0x11F3
+#define WM8962_WRITE_SEQUENCER_500              0x11F4
+#define WM8962_WRITE_SEQUENCER_501              0x11F5
+#define WM8962_WRITE_SEQUENCER_502              0x11F6
+#define WM8962_WRITE_SEQUENCER_503              0x11F7
+#define WM8962_WRITE_SEQUENCER_504              0x11F8
+#define WM8962_WRITE_SEQUENCER_505              0x11F9
+#define WM8962_WRITE_SEQUENCER_506              0x11FA
+#define WM8962_WRITE_SEQUENCER_507              0x11FB
+#define WM8962_WRITE_SEQUENCER_508              0x11FC
+#define WM8962_WRITE_SEQUENCER_509              0x11FD
+#define WM8962_WRITE_SEQUENCER_510              0x11FE
+#define WM8962_WRITE_SEQUENCER_511              0x11FF
+#define WM8962_DSP2_INSTRUCTION_RAM_0           0x2000
+#define WM8962_DSP2_ADDRESS_RAM_2               0x2400
+#define WM8962_DSP2_ADDRESS_RAM_1               0x2401
+#define WM8962_DSP2_ADDRESS_RAM_0               0x2402
+#define WM8962_DSP2_DATA1_RAM_1                 0x3000
+#define WM8962_DSP2_DATA1_RAM_0                 0x3001
+#define WM8962_DSP2_DATA2_RAM_1                 0x3400
+#define WM8962_DSP2_DATA2_RAM_0                 0x3401
+#define WM8962_DSP2_DATA3_RAM_1                 0x3800
+#define WM8962_DSP2_DATA3_RAM_0                 0x3801
+#define WM8962_DSP2_COEFF_RAM_0                 0x3C00
+#define WM8962_RETUNEADC_SHARED_COEFF_1         0x4000
+#define WM8962_RETUNEADC_SHARED_COEFF_0         0x4001
+#define WM8962_RETUNEDAC_SHARED_COEFF_1         0x4002
+#define WM8962_RETUNEDAC_SHARED_COEFF_0         0x4003
+#define WM8962_SOUNDSTAGE_ENABLES_1             0x4004
+#define WM8962_SOUNDSTAGE_ENABLES_0             0x4005
+#define WM8962_HDBASS_AI_1                      0x4200
+#define WM8962_HDBASS_AI_0                      0x4201
+#define WM8962_HDBASS_AR_1                      0x4202
+#define WM8962_HDBASS_AR_0                      0x4203
+#define WM8962_HDBASS_B_1                       0x4204
+#define WM8962_HDBASS_B_0                       0x4205
+#define WM8962_HDBASS_K_1                       0x4206
+#define WM8962_HDBASS_K_0                       0x4207
+#define WM8962_HDBASS_N1_1                      0x4208
+#define WM8962_HDBASS_N1_0                      0x4209
+#define WM8962_HDBASS_N2_1                      0x420A
+#define WM8962_HDBASS_N2_0                      0x420B
+#define WM8962_HDBASS_N3_1                      0x420C
+#define WM8962_HDBASS_N3_0                      0x420D
+#define WM8962_HDBASS_N4_1                      0x420E
+#define WM8962_HDBASS_N4_0                      0x420F
+#define WM8962_HDBASS_N5_1                      0x4210
+#define WM8962_HDBASS_N5_0                      0x4211
+#define WM8962_HDBASS_X1_1                      0x4212
+#define WM8962_HDBASS_X1_0                      0x4213
+#define WM8962_HDBASS_X2_1                      0x4214
+#define WM8962_HDBASS_X2_0                      0x4215
+#define WM8962_HDBASS_X3_1                      0x4216
+#define WM8962_HDBASS_X3_0                      0x4217
+#define WM8962_HDBASS_ATK_1                     0x4218
+#define WM8962_HDBASS_ATK_0                     0x4219
+#define WM8962_HDBASS_DCY_1                     0x421A
+#define WM8962_HDBASS_DCY_0                     0x421B
+#define WM8962_HDBASS_PG_1                      0x421C
+#define WM8962_HDBASS_PG_0                      0x421D
+#define WM8962_HPF_C_1                          0x4400
+#define WM8962_HPF_C_0                          0x4401
+#define WM8962_ADCL_RETUNE_C1_1                 0x4600
+#define WM8962_ADCL_RETUNE_C1_0                 0x4601
+#define WM8962_ADCL_RETUNE_C2_1                 0x4602
+#define WM8962_ADCL_RETUNE_C2_0                 0x4603
+#define WM8962_ADCL_RETUNE_C3_1                 0x4604
+#define WM8962_ADCL_RETUNE_C3_0                 0x4605
+#define WM8962_ADCL_RETUNE_C4_1                 0x4606
+#define WM8962_ADCL_RETUNE_C4_0                 0x4607
+#define WM8962_ADCL_RETUNE_C5_1                 0x4608
+#define WM8962_ADCL_RETUNE_C5_0                 0x4609
+#define WM8962_ADCL_RETUNE_C6_1                 0x460A
+#define WM8962_ADCL_RETUNE_C6_0                 0x460B
+#define WM8962_ADCL_RETUNE_C7_1                 0x460C
+#define WM8962_ADCL_RETUNE_C7_0                 0x460D
+#define WM8962_ADCL_RETUNE_C8_1                 0x460E
+#define WM8962_ADCL_RETUNE_C8_0                 0x460F
+#define WM8962_ADCL_RETUNE_C9_1                 0x4610
+#define WM8962_ADCL_RETUNE_C9_0                 0x4611
+#define WM8962_ADCL_RETUNE_C10_1                0x4612
+#define WM8962_ADCL_RETUNE_C10_0                0x4613
+#define WM8962_ADCL_RETUNE_C11_1                0x4614
+#define WM8962_ADCL_RETUNE_C11_0                0x4615
+#define WM8962_ADCL_RETUNE_C12_1                0x4616
+#define WM8962_ADCL_RETUNE_C12_0                0x4617
+#define WM8962_ADCL_RETUNE_C13_1                0x4618
+#define WM8962_ADCL_RETUNE_C13_0                0x4619
+#define WM8962_ADCL_RETUNE_C14_1                0x461A
+#define WM8962_ADCL_RETUNE_C14_0                0x461B
+#define WM8962_ADCL_RETUNE_C15_1                0x461C
+#define WM8962_ADCL_RETUNE_C15_0                0x461D
+#define WM8962_ADCL_RETUNE_C16_1                0x461E
+#define WM8962_ADCL_RETUNE_C16_0                0x461F
+#define WM8962_ADCL_RETUNE_C17_1                0x4620
+#define WM8962_ADCL_RETUNE_C17_0                0x4621
+#define WM8962_ADCL_RETUNE_C18_1                0x4622
+#define WM8962_ADCL_RETUNE_C18_0                0x4623
+#define WM8962_ADCL_RETUNE_C19_1                0x4624
+#define WM8962_ADCL_RETUNE_C19_0                0x4625
+#define WM8962_ADCL_RETUNE_C20_1                0x4626
+#define WM8962_ADCL_RETUNE_C20_0                0x4627
+#define WM8962_ADCL_RETUNE_C21_1                0x4628
+#define WM8962_ADCL_RETUNE_C21_0                0x4629
+#define WM8962_ADCL_RETUNE_C22_1                0x462A
+#define WM8962_ADCL_RETUNE_C22_0                0x462B
+#define WM8962_ADCL_RETUNE_C23_1                0x462C
+#define WM8962_ADCL_RETUNE_C23_0                0x462D
+#define WM8962_ADCL_RETUNE_C24_1                0x462E
+#define WM8962_ADCL_RETUNE_C24_0                0x462F
+#define WM8962_ADCL_RETUNE_C25_1                0x4630
+#define WM8962_ADCL_RETUNE_C25_0                0x4631
+#define WM8962_ADCL_RETUNE_C26_1                0x4632
+#define WM8962_ADCL_RETUNE_C26_0                0x4633
+#define WM8962_ADCL_RETUNE_C27_1                0x4634
+#define WM8962_ADCL_RETUNE_C27_0                0x4635
+#define WM8962_ADCL_RETUNE_C28_1                0x4636
+#define WM8962_ADCL_RETUNE_C28_0                0x4637
+#define WM8962_ADCL_RETUNE_C29_1                0x4638
+#define WM8962_ADCL_RETUNE_C29_0                0x4639
+#define WM8962_ADCL_RETUNE_C30_1                0x463A
+#define WM8962_ADCL_RETUNE_C30_0                0x463B
+#define WM8962_ADCL_RETUNE_C31_1                0x463C
+#define WM8962_ADCL_RETUNE_C31_0                0x463D
+#define WM8962_ADCL_RETUNE_C32_1                0x463E
+#define WM8962_ADCL_RETUNE_C32_0                0x463F
+#define WM8962_RETUNEADC_PG2_1                  0x4800
+#define WM8962_RETUNEADC_PG2_0                  0x4801
+#define WM8962_RETUNEADC_PG_1                   0x4802
+#define WM8962_RETUNEADC_PG_0                   0x4803
+#define WM8962_ADCR_RETUNE_C1_1                 0x4A00
+#define WM8962_ADCR_RETUNE_C1_0                 0x4A01
+#define WM8962_ADCR_RETUNE_C2_1                 0x4A02
+#define WM8962_ADCR_RETUNE_C2_0                 0x4A03
+#define WM8962_ADCR_RETUNE_C3_1                 0x4A04
+#define WM8962_ADCR_RETUNE_C3_0                 0x4A05
+#define WM8962_ADCR_RETUNE_C4_1                 0x4A06
+#define WM8962_ADCR_RETUNE_C4_0                 0x4A07
+#define WM8962_ADCR_RETUNE_C5_1                 0x4A08
+#define WM8962_ADCR_RETUNE_C5_0                 0x4A09
+#define WM8962_ADCR_RETUNE_C6_1                 0x4A0A
+#define WM8962_ADCR_RETUNE_C6_0                 0x4A0B
+#define WM8962_ADCR_RETUNE_C7_1                 0x4A0C
+#define WM8962_ADCR_RETUNE_C7_0                 0x4A0D
+#define WM8962_ADCR_RETUNE_C8_1                 0x4A0E
+#define WM8962_ADCR_RETUNE_C8_0                 0x4A0F
+#define WM8962_ADCR_RETUNE_C9_1                 0x4A10
+#define WM8962_ADCR_RETUNE_C9_0                 0x4A11
+#define WM8962_ADCR_RETUNE_C10_1                0x4A12
+#define WM8962_ADCR_RETUNE_C10_0                0x4A13
+#define WM8962_ADCR_RETUNE_C11_1                0x4A14
+#define WM8962_ADCR_RETUNE_C11_0                0x4A15
+#define WM8962_ADCR_RETUNE_C12_1                0x4A16
+#define WM8962_ADCR_RETUNE_C12_0                0x4A17
+#define WM8962_ADCR_RETUNE_C13_1                0x4A18
+#define WM8962_ADCR_RETUNE_C13_0                0x4A19
+#define WM8962_ADCR_RETUNE_C14_1                0x4A1A
+#define WM8962_ADCR_RETUNE_C14_0                0x4A1B
+#define WM8962_ADCR_RETUNE_C15_1                0x4A1C
+#define WM8962_ADCR_RETUNE_C15_0                0x4A1D
+#define WM8962_ADCR_RETUNE_C16_1                0x4A1E
+#define WM8962_ADCR_RETUNE_C16_0                0x4A1F
+#define WM8962_ADCR_RETUNE_C17_1                0x4A20
+#define WM8962_ADCR_RETUNE_C17_0                0x4A21
+#define WM8962_ADCR_RETUNE_C18_1                0x4A22
+#define WM8962_ADCR_RETUNE_C18_0                0x4A23
+#define WM8962_ADCR_RETUNE_C19_1                0x4A24
+#define WM8962_ADCR_RETUNE_C19_0                0x4A25
+#define WM8962_ADCR_RETUNE_C20_1                0x4A26
+#define WM8962_ADCR_RETUNE_C20_0                0x4A27
+#define WM8962_ADCR_RETUNE_C21_1                0x4A28
+#define WM8962_ADCR_RETUNE_C21_0                0x4A29
+#define WM8962_ADCR_RETUNE_C22_1                0x4A2A
+#define WM8962_ADCR_RETUNE_C22_0                0x4A2B
+#define WM8962_ADCR_RETUNE_C23_1                0x4A2C
+#define WM8962_ADCR_RETUNE_C23_0                0x4A2D
+#define WM8962_ADCR_RETUNE_C24_1                0x4A2E
+#define WM8962_ADCR_RETUNE_C24_0                0x4A2F
+#define WM8962_ADCR_RETUNE_C25_1                0x4A30
+#define WM8962_ADCR_RETUNE_C25_0                0x4A31
+#define WM8962_ADCR_RETUNE_C26_1                0x4A32
+#define WM8962_ADCR_RETUNE_C26_0                0x4A33
+#define WM8962_ADCR_RETUNE_C27_1                0x4A34
+#define WM8962_ADCR_RETUNE_C27_0                0x4A35
+#define WM8962_ADCR_RETUNE_C28_1                0x4A36
+#define WM8962_ADCR_RETUNE_C28_0                0x4A37
+#define WM8962_ADCR_RETUNE_C29_1                0x4A38
+#define WM8962_ADCR_RETUNE_C29_0                0x4A39
+#define WM8962_ADCR_RETUNE_C30_1                0x4A3A
+#define WM8962_ADCR_RETUNE_C30_0                0x4A3B
+#define WM8962_ADCR_RETUNE_C31_1                0x4A3C
+#define WM8962_ADCR_RETUNE_C31_0                0x4A3D
+#define WM8962_ADCR_RETUNE_C32_1                0x4A3E
+#define WM8962_ADCR_RETUNE_C32_0                0x4A3F
+#define WM8962_DACL_RETUNE_C1_1                 0x4C00
+#define WM8962_DACL_RETUNE_C1_0                 0x4C01
+#define WM8962_DACL_RETUNE_C2_1                 0x4C02
+#define WM8962_DACL_RETUNE_C2_0                 0x4C03
+#define WM8962_DACL_RETUNE_C3_1                 0x4C04
+#define WM8962_DACL_RETUNE_C3_0                 0x4C05
+#define WM8962_DACL_RETUNE_C4_1                 0x4C06
+#define WM8962_DACL_RETUNE_C4_0                 0x4C07
+#define WM8962_DACL_RETUNE_C5_1                 0x4C08
+#define WM8962_DACL_RETUNE_C5_0                 0x4C09
+#define WM8962_DACL_RETUNE_C6_1                 0x4C0A
+#define WM8962_DACL_RETUNE_C6_0                 0x4C0B
+#define WM8962_DACL_RETUNE_C7_1                 0x4C0C
+#define WM8962_DACL_RETUNE_C7_0                 0x4C0D
+#define WM8962_DACL_RETUNE_C8_1                 0x4C0E
+#define WM8962_DACL_RETUNE_C8_0                 0x4C0F
+#define WM8962_DACL_RETUNE_C9_1                 0x4C10
+#define WM8962_DACL_RETUNE_C9_0                 0x4C11
+#define WM8962_DACL_RETUNE_C10_1                0x4C12
+#define WM8962_DACL_RETUNE_C10_0                0x4C13
+#define WM8962_DACL_RETUNE_C11_1                0x4C14
+#define WM8962_DACL_RETUNE_C11_0                0x4C15
+#define WM8962_DACL_RETUNE_C12_1                0x4C16
+#define WM8962_DACL_RETUNE_C12_0                0x4C17
+#define WM8962_DACL_RETUNE_C13_1                0x4C18
+#define WM8962_DACL_RETUNE_C13_0                0x4C19
+#define WM8962_DACL_RETUNE_C14_1                0x4C1A
+#define WM8962_DACL_RETUNE_C14_0                0x4C1B
+#define WM8962_DACL_RETUNE_C15_1                0x4C1C
+#define WM8962_DACL_RETUNE_C15_0                0x4C1D
+#define WM8962_DACL_RETUNE_C16_1                0x4C1E
+#define WM8962_DACL_RETUNE_C16_0                0x4C1F
+#define WM8962_DACL_RETUNE_C17_1                0x4C20
+#define WM8962_DACL_RETUNE_C17_0                0x4C21
+#define WM8962_DACL_RETUNE_C18_1                0x4C22
+#define WM8962_DACL_RETUNE_C18_0                0x4C23
+#define WM8962_DACL_RETUNE_C19_1                0x4C24
+#define WM8962_DACL_RETUNE_C19_0                0x4C25
+#define WM8962_DACL_RETUNE_C20_1                0x4C26
+#define WM8962_DACL_RETUNE_C20_0                0x4C27
+#define WM8962_DACL_RETUNE_C21_1                0x4C28
+#define WM8962_DACL_RETUNE_C21_0                0x4C29
+#define WM8962_DACL_RETUNE_C22_1                0x4C2A
+#define WM8962_DACL_RETUNE_C22_0                0x4C2B
+#define WM8962_DACL_RETUNE_C23_1                0x4C2C
+#define WM8962_DACL_RETUNE_C23_0                0x4C2D
+#define WM8962_DACL_RETUNE_C24_1                0x4C2E
+#define WM8962_DACL_RETUNE_C24_0                0x4C2F
+#define WM8962_DACL_RETUNE_C25_1                0x4C30
+#define WM8962_DACL_RETUNE_C25_0                0x4C31
+#define WM8962_DACL_RETUNE_C26_1                0x4C32
+#define WM8962_DACL_RETUNE_C26_0                0x4C33
+#define WM8962_DACL_RETUNE_C27_1                0x4C34
+#define WM8962_DACL_RETUNE_C27_0                0x4C35
+#define WM8962_DACL_RETUNE_C28_1                0x4C36
+#define WM8962_DACL_RETUNE_C28_0                0x4C37
+#define WM8962_DACL_RETUNE_C29_1                0x4C38
+#define WM8962_DACL_RETUNE_C29_0                0x4C39
+#define WM8962_DACL_RETUNE_C30_1                0x4C3A
+#define WM8962_DACL_RETUNE_C30_0                0x4C3B
+#define WM8962_DACL_RETUNE_C31_1                0x4C3C
+#define WM8962_DACL_RETUNE_C31_0                0x4C3D
+#define WM8962_DACL_RETUNE_C32_1                0x4C3E
+#define WM8962_DACL_RETUNE_C32_0                0x4C3F
+#define WM8962_RETUNEDAC_PG2_1                  0x4E00
+#define WM8962_RETUNEDAC_PG2_0                  0x4E01
+#define WM8962_RETUNEDAC_PG_1                   0x4E02
+#define WM8962_RETUNEDAC_PG_0                   0x4E03
+#define WM8962_DACR_RETUNE_C1_1                 0x5000
+#define WM8962_DACR_RETUNE_C1_0                 0x5001
+#define WM8962_DACR_RETUNE_C2_1                 0x5002
+#define WM8962_DACR_RETUNE_C2_0                 0x5003
+#define WM8962_DACR_RETUNE_C3_1                 0x5004
+#define WM8962_DACR_RETUNE_C3_0                 0x5005
+#define WM8962_DACR_RETUNE_C4_1                 0x5006
+#define WM8962_DACR_RETUNE_C4_0                 0x5007
+#define WM8962_DACR_RETUNE_C5_1                 0x5008
+#define WM8962_DACR_RETUNE_C5_0                 0x5009
+#define WM8962_DACR_RETUNE_C6_1                 0x500A
+#define WM8962_DACR_RETUNE_C6_0                 0x500B
+#define WM8962_DACR_RETUNE_C7_1                 0x500C
+#define WM8962_DACR_RETUNE_C7_0                 0x500D
+#define WM8962_DACR_RETUNE_C8_1                 0x500E
+#define WM8962_DACR_RETUNE_C8_0                 0x500F
+#define WM8962_DACR_RETUNE_C9_1                 0x5010
+#define WM8962_DACR_RETUNE_C9_0                 0x5011
+#define WM8962_DACR_RETUNE_C10_1                0x5012
+#define WM8962_DACR_RETUNE_C10_0                0x5013
+#define WM8962_DACR_RETUNE_C11_1                0x5014
+#define WM8962_DACR_RETUNE_C11_0                0x5015
+#define WM8962_DACR_RETUNE_C12_1                0x5016
+#define WM8962_DACR_RETUNE_C12_0                0x5017
+#define WM8962_DACR_RETUNE_C13_1                0x5018
+#define WM8962_DACR_RETUNE_C13_0                0x5019
+#define WM8962_DACR_RETUNE_C14_1                0x501A
+#define WM8962_DACR_RETUNE_C14_0                0x501B
+#define WM8962_DACR_RETUNE_C15_1                0x501C
+#define WM8962_DACR_RETUNE_C15_0                0x501D
+#define WM8962_DACR_RETUNE_C16_1                0x501E
+#define WM8962_DACR_RETUNE_C16_0                0x501F
+#define WM8962_DACR_RETUNE_C17_1                0x5020
+#define WM8962_DACR_RETUNE_C17_0                0x5021
+#define WM8962_DACR_RETUNE_C18_1                0x5022
+#define WM8962_DACR_RETUNE_C18_0                0x5023
+#define WM8962_DACR_RETUNE_C19_1                0x5024
+#define WM8962_DACR_RETUNE_C19_0                0x5025
+#define WM8962_DACR_RETUNE_C20_1                0x5026
+#define WM8962_DACR_RETUNE_C20_0                0x5027
+#define WM8962_DACR_RETUNE_C21_1                0x5028
+#define WM8962_DACR_RETUNE_C21_0                0x5029
+#define WM8962_DACR_RETUNE_C22_1                0x502A
+#define WM8962_DACR_RETUNE_C22_0                0x502B
+#define WM8962_DACR_RETUNE_C23_1                0x502C
+#define WM8962_DACR_RETUNE_C23_0                0x502D
+#define WM8962_DACR_RETUNE_C24_1                0x502E
+#define WM8962_DACR_RETUNE_C24_0                0x502F
+#define WM8962_DACR_RETUNE_C25_1                0x5030
+#define WM8962_DACR_RETUNE_C25_0                0x5031
+#define WM8962_DACR_RETUNE_C26_1                0x5032
+#define WM8962_DACR_RETUNE_C26_0                0x5033
+#define WM8962_DACR_RETUNE_C27_1                0x5034
+#define WM8962_DACR_RETUNE_C27_0                0x5035
+#define WM8962_DACR_RETUNE_C28_1                0x5036
+#define WM8962_DACR_RETUNE_C28_0                0x5037
+#define WM8962_DACR_RETUNE_C29_1                0x5038
+#define WM8962_DACR_RETUNE_C29_0                0x5039
+#define WM8962_DACR_RETUNE_C30_1                0x503A
+#define WM8962_DACR_RETUNE_C30_0                0x503B
+#define WM8962_DACR_RETUNE_C31_1                0x503C
+#define WM8962_DACR_RETUNE_C31_0                0x503D
+#define WM8962_DACR_RETUNE_C32_1                0x503E
+#define WM8962_DACR_RETUNE_C32_0                0x503F
+#define WM8962_VSS_XHD2_1                       0x5200
+#define WM8962_VSS_XHD2_0                       0x5201
+#define WM8962_VSS_XHD3_1                       0x5202
+#define WM8962_VSS_XHD3_0                       0x5203
+#define WM8962_VSS_XHN1_1                       0x5204
+#define WM8962_VSS_XHN1_0                       0x5205
+#define WM8962_VSS_XHN2_1                       0x5206
+#define WM8962_VSS_XHN2_0                       0x5207
+#define WM8962_VSS_XHN3_1                       0x5208
+#define WM8962_VSS_XHN3_0                       0x5209
+#define WM8962_VSS_XLA_1                        0x520A
+#define WM8962_VSS_XLA_0                        0x520B
+#define WM8962_VSS_XLB_1                        0x520C
+#define WM8962_VSS_XLB_0                        0x520D
+#define WM8962_VSS_XLG_1                        0x520E
+#define WM8962_VSS_XLG_0                        0x520F
+#define WM8962_VSS_PG2_1                        0x5210
+#define WM8962_VSS_PG2_0                        0x5211
+#define WM8962_VSS_PG_1                         0x5212
+#define WM8962_VSS_PG_0                         0x5213
+#define WM8962_VSS_XTD1_1                       0x5214
+#define WM8962_VSS_XTD1_0                       0x5215
+#define WM8962_VSS_XTD2_1                       0x5216
+#define WM8962_VSS_XTD2_0                       0x5217
+#define WM8962_VSS_XTD3_1                       0x5218
+#define WM8962_VSS_XTD3_0                       0x5219
+#define WM8962_VSS_XTD4_1                       0x521A
+#define WM8962_VSS_XTD4_0                       0x521B
+#define WM8962_VSS_XTD5_1                       0x521C
+#define WM8962_VSS_XTD5_0                       0x521D
+#define WM8962_VSS_XTD6_1                       0x521E
+#define WM8962_VSS_XTD6_0                       0x521F
+#define WM8962_VSS_XTD7_1                       0x5220
+#define WM8962_VSS_XTD7_0                       0x5221
+#define WM8962_VSS_XTD8_1                       0x5222
+#define WM8962_VSS_XTD8_0                       0x5223
+#define WM8962_VSS_XTD9_1                       0x5224
+#define WM8962_VSS_XTD9_0                       0x5225
+#define WM8962_VSS_XTD10_1                      0x5226
+#define WM8962_VSS_XTD10_0                      0x5227
+#define WM8962_VSS_XTD11_1                      0x5228
+#define WM8962_VSS_XTD11_0                      0x5229
+#define WM8962_VSS_XTD12_1                      0x522A
+#define WM8962_VSS_XTD12_0                      0x522B
+#define WM8962_VSS_XTD13_1                      0x522C
+#define WM8962_VSS_XTD13_0                      0x522D
+#define WM8962_VSS_XTD14_1                      0x522E
+#define WM8962_VSS_XTD14_0                      0x522F
+#define WM8962_VSS_XTD15_1                      0x5230
+#define WM8962_VSS_XTD15_0                      0x5231
+#define WM8962_VSS_XTD16_1                      0x5232
+#define WM8962_VSS_XTD16_0                      0x5233
+#define WM8962_VSS_XTD17_1                      0x5234
+#define WM8962_VSS_XTD17_0                      0x5235
+#define WM8962_VSS_XTD18_1                      0x5236
+#define WM8962_VSS_XTD18_0                      0x5237
+#define WM8962_VSS_XTD19_1                      0x5238
+#define WM8962_VSS_XTD19_0                      0x5239
+#define WM8962_VSS_XTD20_1                      0x523A
+#define WM8962_VSS_XTD20_0                      0x523B
+#define WM8962_VSS_XTD21_1                      0x523C
+#define WM8962_VSS_XTD21_0                      0x523D
+#define WM8962_VSS_XTD22_1                      0x523E
+#define WM8962_VSS_XTD22_0                      0x523F
+#define WM8962_VSS_XTD23_1                      0x5240
+#define WM8962_VSS_XTD23_0                      0x5241
+#define WM8962_VSS_XTD24_1                      0x5242
+#define WM8962_VSS_XTD24_0                      0x5243
+#define WM8962_VSS_XTD25_1                      0x5244
+#define WM8962_VSS_XTD25_0                      0x5245
+#define WM8962_VSS_XTD26_1                      0x5246
+#define WM8962_VSS_XTD26_0                      0x5247
+#define WM8962_VSS_XTD27_1                      0x5248
+#define WM8962_VSS_XTD27_0                      0x5249
+#define WM8962_VSS_XTD28_1                      0x524A
+#define WM8962_VSS_XTD28_0                      0x524B
+#define WM8962_VSS_XTD29_1                      0x524C
+#define WM8962_VSS_XTD29_0                      0x524D
+#define WM8962_VSS_XTD30_1                      0x524E
+#define WM8962_VSS_XTD30_0                      0x524F
+#define WM8962_VSS_XTD31_1                      0x5250
+#define WM8962_VSS_XTD31_0                      0x5251
+#define WM8962_VSS_XTD32_1                      0x5252
+#define WM8962_VSS_XTD32_0                      0x5253
+#define WM8962_VSS_XTS1_1                       0x5254
+#define WM8962_VSS_XTS1_0                       0x5255
+#define WM8962_VSS_XTS2_1                       0x5256
+#define WM8962_VSS_XTS2_0                       0x5257
+#define WM8962_VSS_XTS3_1                       0x5258
+#define WM8962_VSS_XTS3_0                       0x5259
+#define WM8962_VSS_XTS4_1                       0x525A
+#define WM8962_VSS_XTS4_0                       0x525B
+#define WM8962_VSS_XTS5_1                       0x525C
+#define WM8962_VSS_XTS5_0                       0x525D
+#define WM8962_VSS_XTS6_1                       0x525E
+#define WM8962_VSS_XTS6_0                       0x525F
+#define WM8962_VSS_XTS7_1                       0x5260
+#define WM8962_VSS_XTS7_0                       0x5261
+#define WM8962_VSS_XTS8_1                       0x5262
+#define WM8962_VSS_XTS8_0                       0x5263
+#define WM8962_VSS_XTS9_1                       0x5264
+#define WM8962_VSS_XTS9_0                       0x5265
+#define WM8962_VSS_XTS10_1                      0x5266
+#define WM8962_VSS_XTS10_0                      0x5267
+#define WM8962_VSS_XTS11_1                      0x5268
+#define WM8962_VSS_XTS11_0                      0x5269
+#define WM8962_VSS_XTS12_1                      0x526A
+#define WM8962_VSS_XTS12_0                      0x526B
+#define WM8962_VSS_XTS13_1                      0x526C
+#define WM8962_VSS_XTS13_0                      0x526D
+#define WM8962_VSS_XTS14_1                      0x526E
+#define WM8962_VSS_XTS14_0                      0x526F
+#define WM8962_VSS_XTS15_1                      0x5270
+#define WM8962_VSS_XTS15_0                      0x5271
+#define WM8962_VSS_XTS16_1                      0x5272
+#define WM8962_VSS_XTS16_0                      0x5273
+#define WM8962_VSS_XTS17_1                      0x5274
+#define WM8962_VSS_XTS17_0                      0x5275
+#define WM8962_VSS_XTS18_1                      0x5276
+#define WM8962_VSS_XTS18_0                      0x5277
+#define WM8962_VSS_XTS19_1                      0x5278
+#define WM8962_VSS_XTS19_0                      0x5279
+#define WM8962_VSS_XTS20_1                      0x527A
+#define WM8962_VSS_XTS20_0                      0x527B
+#define WM8962_VSS_XTS21_1                      0x527C
+#define WM8962_VSS_XTS21_0                      0x527D
+#define WM8962_VSS_XTS22_1                      0x527E
+#define WM8962_VSS_XTS22_0                      0x527F
+#define WM8962_VSS_XTS23_1                      0x5280
+#define WM8962_VSS_XTS23_0                      0x5281
+#define WM8962_VSS_XTS24_1                      0x5282
+#define WM8962_VSS_XTS24_0                      0x5283
+#define WM8962_VSS_XTS25_1                      0x5284
+#define WM8962_VSS_XTS25_0                      0x5285
+#define WM8962_VSS_XTS26_1                      0x5286
+#define WM8962_VSS_XTS26_0                      0x5287
+#define WM8962_VSS_XTS27_1                      0x5288
+#define WM8962_VSS_XTS27_0                      0x5289
+#define WM8962_VSS_XTS28_1                      0x528A
+#define WM8962_VSS_XTS28_0                      0x528B
+#define WM8962_VSS_XTS29_1                      0x528C
+#define WM8962_VSS_XTS29_0                      0x528D
+#define WM8962_VSS_XTS30_1                      0x528E
+#define WM8962_VSS_XTS30_0                      0x528F
+#define WM8962_VSS_XTS31_1                      0x5290
+#define WM8962_VSS_XTS31_0                      0x5291
+#define WM8962_VSS_XTS32_1                      0x5292
+#define WM8962_VSS_XTS32_0                      0x5293
+
+#define WM8962_REGISTER_COUNT                   1138
+#define WM8962_MAX_REGISTER                     0x5293
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Left Input volume
+ */
+#define WM8962_IN_VU                            0x0100  /* IN_VU */
+#define WM8962_IN_VU_MASK                       0x0100  /* IN_VU */
+#define WM8962_IN_VU_SHIFT                           8  /* IN_VU */
+#define WM8962_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM8962_INPGAL_MUTE                      0x0080  /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_MASK                 0x0080  /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_SHIFT                     7  /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_WIDTH                     1  /* INPGAL_MUTE */
+#define WM8962_INL_ZC                           0x0040  /* INL_ZC */
+#define WM8962_INL_ZC_MASK                      0x0040  /* INL_ZC */
+#define WM8962_INL_ZC_SHIFT                          6  /* INL_ZC */
+#define WM8962_INL_ZC_WIDTH                          1  /* INL_ZC */
+#define WM8962_INL_VOL_MASK                     0x003F  /* INL_VOL - [5:0] */
+#define WM8962_INL_VOL_SHIFT                         0  /* INL_VOL - [5:0] */
+#define WM8962_INL_VOL_WIDTH                         6  /* INL_VOL - [5:0] */
+
+/*
+ * R1 (0x01) - Right Input volume
+ */
+#define WM8962_CUST_ID_MASK                     0xF000  /* CUST_ID - [15:12] */
+#define WM8962_CUST_ID_SHIFT                        12  /* CUST_ID - [15:12] */
+#define WM8962_CUST_ID_WIDTH                         4  /* CUST_ID - [15:12] */
+#define WM8962_CHIP_REV_MASK                    0x0E00  /* CHIP_REV - [11:9] */
+#define WM8962_CHIP_REV_SHIFT                        9  /* CHIP_REV - [11:9] */
+#define WM8962_CHIP_REV_WIDTH                        3  /* CHIP_REV - [11:9] */
+#define WM8962_IN_VU                            0x0100  /* IN_VU */
+#define WM8962_IN_VU_MASK                       0x0100  /* IN_VU */
+#define WM8962_IN_VU_SHIFT                           8  /* IN_VU */
+#define WM8962_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM8962_INPGAR_MUTE                      0x0080  /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_MASK                 0x0080  /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_SHIFT                     7  /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_WIDTH                     1  /* INPGAR_MUTE */
+#define WM8962_INR_ZC                           0x0040  /* INR_ZC */
+#define WM8962_INR_ZC_MASK                      0x0040  /* INR_ZC */
+#define WM8962_INR_ZC_SHIFT                          6  /* INR_ZC */
+#define WM8962_INR_ZC_WIDTH                          1  /* INR_ZC */
+#define WM8962_INR_VOL_MASK                     0x003F  /* INR_VOL - [5:0] */
+#define WM8962_INR_VOL_SHIFT                         0  /* INR_VOL - [5:0] */
+#define WM8962_INR_VOL_WIDTH                         6  /* INR_VOL - [5:0] */
+
+/*
+ * R2 (0x02) - HPOUTL volume
+ */
+#define WM8962_HPOUT_VU                         0x0100  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_MASK                    0x0100  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_SHIFT                        8  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_WIDTH                        1  /* HPOUT_VU */
+#define WM8962_HPOUTL_ZC                        0x0080  /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_MASK                   0x0080  /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_SHIFT                       7  /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_WIDTH                       1  /* HPOUTL_ZC */
+#define WM8962_HPOUTL_VOL_MASK                  0x007F  /* HPOUTL_VOL - [6:0] */
+#define WM8962_HPOUTL_VOL_SHIFT                      0  /* HPOUTL_VOL - [6:0] */
+#define WM8962_HPOUTL_VOL_WIDTH                      7  /* HPOUTL_VOL - [6:0] */
+
+/*
+ * R3 (0x03) - HPOUTR volume
+ */
+#define WM8962_HPOUT_VU                         0x0100  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_MASK                    0x0100  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_SHIFT                        8  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_WIDTH                        1  /* HPOUT_VU */
+#define WM8962_HPOUTR_ZC                        0x0080  /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_MASK                   0x0080  /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_SHIFT                       7  /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_WIDTH                       1  /* HPOUTR_ZC */
+#define WM8962_HPOUTR_VOL_MASK                  0x007F  /* HPOUTR_VOL - [6:0] */
+#define WM8962_HPOUTR_VOL_SHIFT                      0  /* HPOUTR_VOL - [6:0] */
+#define WM8962_HPOUTR_VOL_WIDTH                      7  /* HPOUTR_VOL - [6:0] */
+
+/*
+ * R4 (0x04) - Clocking1
+ */
+#define WM8962_DSPCLK_DIV_MASK                  0x0600  /* DSPCLK_DIV - [10:9] */
+#define WM8962_DSPCLK_DIV_SHIFT                      9  /* DSPCLK_DIV - [10:9] */
+#define WM8962_DSPCLK_DIV_WIDTH                      2  /* DSPCLK_DIV - [10:9] */
+#define WM8962_ADCSYS_CLK_DIV_MASK              0x01C0  /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_ADCSYS_CLK_DIV_SHIFT                  6  /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_ADCSYS_CLK_DIV_WIDTH                  3  /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_DACSYS_CLK_DIV_MASK              0x0038  /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_DACSYS_CLK_DIV_SHIFT                  3  /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_DACSYS_CLK_DIV_WIDTH                  3  /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_MCLKDIV_MASK                     0x0006  /* MCLKDIV - [2:1] */
+#define WM8962_MCLKDIV_SHIFT                         1  /* MCLKDIV - [2:1] */
+#define WM8962_MCLKDIV_WIDTH                         2  /* MCLKDIV - [2:1] */
+
+/*
+ * R5 (0x05) - ADC & DAC Control 1
+ */
+#define WM8962_ADCR_DAT_INV                     0x0040  /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_MASK                0x0040  /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_SHIFT                    6  /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_WIDTH                    1  /* ADCR_DAT_INV */
+#define WM8962_ADCL_DAT_INV                     0x0020  /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_MASK                0x0020  /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_SHIFT                    5  /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_WIDTH                    1  /* ADCL_DAT_INV */
+#define WM8962_DAC_MUTE_RAMP                    0x0010  /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_MASK               0x0010  /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_SHIFT                   4  /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_WIDTH                   1  /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE                         0x0008  /* DAC_MUTE */
+#define WM8962_DAC_MUTE_MASK                    0x0008  /* DAC_MUTE */
+#define WM8962_DAC_MUTE_SHIFT                        3  /* DAC_MUTE */
+#define WM8962_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM8962_DAC_DEEMP_MASK                   0x0006  /* DAC_DEEMP - [2:1] */
+#define WM8962_DAC_DEEMP_SHIFT                       1  /* DAC_DEEMP - [2:1] */
+#define WM8962_DAC_DEEMP_WIDTH                       2  /* DAC_DEEMP - [2:1] */
+#define WM8962_ADC_HPF_DIS                      0x0001  /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_MASK                 0x0001  /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_SHIFT                     0  /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_WIDTH                     1  /* ADC_HPF_DIS */
+
+/*
+ * R6 (0x06) - ADC & DAC Control 2
+ */
+#define WM8962_ADC_HPF_SR_MASK                  0x3000  /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_SR_SHIFT                     12  /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_SR_WIDTH                      2  /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_MODE                     0x0400  /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_MASK                0x0400  /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_SHIFT                   10  /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_WIDTH                    1  /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_CUT_MASK                 0x0380  /* ADC_HPF_CUT - [9:7] */
+#define WM8962_ADC_HPF_CUT_SHIFT                     7  /* ADC_HPF_CUT - [9:7] */
+#define WM8962_ADC_HPF_CUT_WIDTH                     3  /* ADC_HPF_CUT - [9:7] */
+#define WM8962_DACR_DAT_INV                     0x0040  /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_MASK                0x0040  /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_SHIFT                    6  /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_WIDTH                    1  /* DACR_DAT_INV */
+#define WM8962_DACL_DAT_INV                     0x0020  /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_MASK                0x0020  /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_SHIFT                    5  /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_WIDTH                    1  /* DACL_DAT_INV */
+#define WM8962_DAC_UNMUTE_RAMP                  0x0008  /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_MASK             0x0008  /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_SHIFT                 3  /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_WIDTH                 1  /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_MUTERATE                     0x0004  /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_MASK                0x0004  /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_SHIFT                    2  /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM8962_DAC_HP                           0x0001  /* DAC_HP */
+#define WM8962_DAC_HP_MASK                      0x0001  /* DAC_HP */
+#define WM8962_DAC_HP_SHIFT                          0  /* DAC_HP */
+#define WM8962_DAC_HP_WIDTH                          1  /* DAC_HP */
+
+/*
+ * R7 (0x07) - Audio Interface 0
+ */
+#define WM8962_AIFDAC_TDM_MODE                  0x1000  /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_MASK             0x1000  /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_SHIFT                12  /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_WIDTH                 1  /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_SLOT                  0x0800  /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_MASK             0x0800  /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_SHIFT                11  /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_WIDTH                 1  /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_MODE                  0x0400  /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_MASK             0x0400  /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_SHIFT                10  /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_WIDTH                 1  /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_SLOT                  0x0200  /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_MASK             0x0200  /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_SHIFT                 9  /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_WIDTH                 1  /* AIFADC_TDM_SLOT */
+#define WM8962_ADC_LRSWAP                       0x0100  /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_MASK                  0x0100  /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_SHIFT                      8  /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_WIDTH                      1  /* ADC_LRSWAP */
+#define WM8962_BCLK_INV                         0x0080  /* BCLK_INV */
+#define WM8962_BCLK_INV_MASK                    0x0080  /* BCLK_INV */
+#define WM8962_BCLK_INV_SHIFT                        7  /* BCLK_INV */
+#define WM8962_BCLK_INV_WIDTH                        1  /* BCLK_INV */
+#define WM8962_MSTR                             0x0040  /* MSTR */
+#define WM8962_MSTR_MASK                        0x0040  /* MSTR */
+#define WM8962_MSTR_SHIFT                            6  /* MSTR */
+#define WM8962_MSTR_WIDTH                            1  /* MSTR */
+#define WM8962_DAC_LRSWAP                       0x0020  /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_MASK                  0x0020  /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_SHIFT                      5  /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_WIDTH                      1  /* DAC_LRSWAP */
+#define WM8962_LRCLK_INV                        0x0010  /* LRCLK_INV */
+#define WM8962_LRCLK_INV_MASK                   0x0010  /* LRCLK_INV */
+#define WM8962_LRCLK_INV_SHIFT                       4  /* LRCLK_INV */
+#define WM8962_LRCLK_INV_WIDTH                       1  /* LRCLK_INV */
+#define WM8962_WL_MASK                          0x000C  /* WL - [3:2] */
+#define WM8962_WL_SHIFT                              2  /* WL - [3:2] */
+#define WM8962_WL_WIDTH                              2  /* WL - [3:2] */
+#define WM8962_FMT_MASK                         0x0003  /* FMT - [1:0] */
+#define WM8962_FMT_SHIFT                             0  /* FMT - [1:0] */
+#define WM8962_FMT_WIDTH                             2  /* FMT - [1:0] */
+
+/*
+ * R8 (0x08) - Clocking2
+ */
+#define WM8962_CLKREG_OVD                       0x0800  /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_MASK                  0x0800  /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_SHIFT                     11  /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_WIDTH                      1  /* CLKREG_OVD */
+#define WM8962_SYSCLK_SRC_MASK                  0x0600  /* SYSCLK_SRC - [10:9] */
+#define WM8962_SYSCLK_SRC_SHIFT                      9  /* SYSCLK_SRC - [10:9] */
+#define WM8962_SYSCLK_SRC_WIDTH                      2  /* SYSCLK_SRC - [10:9] */
+#define WM8962_CLASSD_CLK_DIV_MASK              0x01C0  /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_CLASSD_CLK_DIV_SHIFT                  6  /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_CLASSD_CLK_DIV_WIDTH                  3  /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_SYSCLK_ENA                       0x0020  /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_MASK                  0x0020  /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_SHIFT                      5  /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+#define WM8962_BCLK_DIV_MASK                    0x000F  /* BCLK_DIV - [3:0] */
+#define WM8962_BCLK_DIV_SHIFT                        0  /* BCLK_DIV - [3:0] */
+#define WM8962_BCLK_DIV_WIDTH                        4  /* BCLK_DIV - [3:0] */
+
+/*
+ * R9 (0x09) - Audio Interface 1
+ */
+#define WM8962_AUTOMUTE_STS                     0x0800  /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_MASK                0x0800  /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_SHIFT                   11  /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_WIDTH                    1  /* AUTOMUTE_STS */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_MASK        0x0300  /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_SHIFT            8  /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_WIDTH            2  /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE                     0x0080  /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_MASK                0x0080  /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_SHIFT                    7  /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_WIDTH                    1  /* DAC_AUTOMUTE */
+#define WM8962_DAC_COMP                         0x0010  /* DAC_COMP */
+#define WM8962_DAC_COMP_MASK                    0x0010  /* DAC_COMP */
+#define WM8962_DAC_COMP_SHIFT                        4  /* DAC_COMP */
+#define WM8962_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM8962_DAC_COMPMODE                     0x0008  /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_MASK                0x0008  /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_SHIFT                    3  /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+#define WM8962_ADC_COMP                         0x0004  /* ADC_COMP */
+#define WM8962_ADC_COMP_MASK                    0x0004  /* ADC_COMP */
+#define WM8962_ADC_COMP_SHIFT                        2  /* ADC_COMP */
+#define WM8962_ADC_COMP_WIDTH                        1  /* ADC_COMP */
+#define WM8962_ADC_COMPMODE                     0x0002  /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_MASK                0x0002  /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_SHIFT                    1  /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_WIDTH                    1  /* ADC_COMPMODE */
+#define WM8962_LOOPBACK                         0x0001  /* LOOPBACK */
+#define WM8962_LOOPBACK_MASK                    0x0001  /* LOOPBACK */
+#define WM8962_LOOPBACK_SHIFT                        0  /* LOOPBACK */
+#define WM8962_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+
+/*
+ * R10 (0x0A) - Left DAC volume
+ */
+#define WM8962_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8962_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8962_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8962_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8962_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8962_DACL_VOL_SHIFT                        0  /* DACL_VOL - [7:0] */
+#define WM8962_DACL_VOL_WIDTH                        8  /* DACL_VOL - [7:0] */
+
+/*
+ * R11 (0x0B) - Right DAC volume
+ */
+#define WM8962_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8962_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8962_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8962_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8962_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8962_DACR_VOL_SHIFT                        0  /* DACR_VOL - [7:0] */
+#define WM8962_DACR_VOL_WIDTH                        8  /* DACR_VOL - [7:0] */
+
+/*
+ * R14 (0x0E) - Audio Interface 2
+ */
+#define WM8962_AIF_RATE_MASK                    0x07FF  /* AIF_RATE - [10:0] */
+#define WM8962_AIF_RATE_SHIFT                        0  /* AIF_RATE - [10:0] */
+#define WM8962_AIF_RATE_WIDTH                       11  /* AIF_RATE - [10:0] */
+
+/*
+ * R15 (0x0F) - Software Reset
+ */
+#define WM8962_SW_RESET_MASK                    0xFFFF  /* SW_RESET - [15:0] */
+#define WM8962_SW_RESET_SHIFT                        0  /* SW_RESET - [15:0] */
+#define WM8962_SW_RESET_WIDTH                       16  /* SW_RESET - [15:0] */
+
+/*
+ * R17 (0x11) - ALC1
+ */
+#define WM8962_ALC_INACTIVE_ENA                 0x0400  /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_MASK            0x0400  /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_SHIFT               10  /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_WIDTH                1  /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_LVL_MODE                     0x0200  /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_MASK                0x0200  /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_SHIFT                    9  /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_WIDTH                    1  /* ALC_LVL_MODE */
+#define WM8962_ALCL_ENA                         0x0100  /* ALCL_ENA */
+#define WM8962_ALCL_ENA_MASK                    0x0100  /* ALCL_ENA */
+#define WM8962_ALCL_ENA_SHIFT                        8  /* ALCL_ENA */
+#define WM8962_ALCL_ENA_WIDTH                        1  /* ALCL_ENA */
+#define WM8962_ALCR_ENA                         0x0080  /* ALCR_ENA */
+#define WM8962_ALCR_ENA_MASK                    0x0080  /* ALCR_ENA */
+#define WM8962_ALCR_ENA_SHIFT                        7  /* ALCR_ENA */
+#define WM8962_ALCR_ENA_WIDTH                        1  /* ALCR_ENA */
+#define WM8962_ALC_MAXGAIN_MASK                 0x0070  /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_MAXGAIN_SHIFT                     4  /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_MAXGAIN_WIDTH                     3  /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_LVL_MASK                     0x000F  /* ALC_LVL - [3:0] */
+#define WM8962_ALC_LVL_SHIFT                         0  /* ALC_LVL - [3:0] */
+#define WM8962_ALC_LVL_WIDTH                         4  /* ALC_LVL - [3:0] */
+
+/*
+ * R18 (0x12) - ALC2
+ */
+#define WM8962_ALC_LOCK_STS                     0x8000  /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_MASK                0x8000  /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_SHIFT                   15  /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_WIDTH                    1  /* ALC_LOCK_STS */
+#define WM8962_ALC_THRESH_STS                   0x4000  /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_MASK              0x4000  /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_SHIFT                 14  /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_WIDTH                  1  /* ALC_THRESH_STS */
+#define WM8962_ALC_SAT_STS                      0x2000  /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_MASK                 0x2000  /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_SHIFT                    13  /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_WIDTH                     1  /* ALC_SAT_STS */
+#define WM8962_ALC_PKOVR_STS                    0x1000  /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_MASK               0x1000  /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_SHIFT                  12  /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_WIDTH                   1  /* ALC_PKOVR_STS */
+#define WM8962_ALC_NGATE_STS                    0x0800  /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_MASK               0x0800  /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_SHIFT                  11  /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_WIDTH                   1  /* ALC_NGATE_STS */
+#define WM8962_ALC_ZC                           0x0080  /* ALC_ZC */
+#define WM8962_ALC_ZC_MASK                      0x0080  /* ALC_ZC */
+#define WM8962_ALC_ZC_SHIFT                          7  /* ALC_ZC */
+#define WM8962_ALC_ZC_WIDTH                          1  /* ALC_ZC */
+#define WM8962_ALC_MINGAIN_MASK                 0x0070  /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_MINGAIN_SHIFT                     4  /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_MINGAIN_WIDTH                     3  /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_HLD_MASK                     0x000F  /* ALC_HLD - [3:0] */
+#define WM8962_ALC_HLD_SHIFT                         0  /* ALC_HLD - [3:0] */
+#define WM8962_ALC_HLD_WIDTH                         4  /* ALC_HLD - [3:0] */
+
+/*
+ * R19 (0x13) - ALC3
+ */
+#define WM8962_ALC_NGATE_GAIN_MASK              0x1C00  /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_NGATE_GAIN_SHIFT                 10  /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_NGATE_GAIN_WIDTH                  3  /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_MODE                         0x0100  /* ALC_MODE */
+#define WM8962_ALC_MODE_MASK                    0x0100  /* ALC_MODE */
+#define WM8962_ALC_MODE_SHIFT                        8  /* ALC_MODE */
+#define WM8962_ALC_MODE_WIDTH                        1  /* ALC_MODE */
+#define WM8962_ALC_DCY_MASK                     0x00F0  /* ALC_DCY - [7:4] */
+#define WM8962_ALC_DCY_SHIFT                         4  /* ALC_DCY - [7:4] */
+#define WM8962_ALC_DCY_WIDTH                         4  /* ALC_DCY - [7:4] */
+#define WM8962_ALC_ATK_MASK                     0x000F  /* ALC_ATK - [3:0] */
+#define WM8962_ALC_ATK_SHIFT                         0  /* ALC_ATK - [3:0] */
+#define WM8962_ALC_ATK_WIDTH                         4  /* ALC_ATK - [3:0] */
+
+/*
+ * R20 (0x14) - Noise Gate
+ */
+#define WM8962_ALC_NGATE_DCY_MASK               0xF000  /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_DCY_SHIFT                  12  /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_DCY_WIDTH                   4  /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_ATK_MASK               0x0F00  /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_ATK_SHIFT                   8  /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_ATK_WIDTH                   4  /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_THR_MASK               0x00F8  /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_THR_SHIFT                   3  /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_THR_WIDTH                   5  /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_MODE_MASK              0x0006  /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_MODE_SHIFT                  1  /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_MODE_WIDTH                  2  /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_ENA                    0x0001  /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_MASK               0x0001  /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_SHIFT                   0  /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_WIDTH                   1  /* ALC_NGATE_ENA */
+
+/*
+ * R21 (0x15) - Left ADC volume
+ */
+#define WM8962_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8962_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8962_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8962_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8962_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8962_ADCL_VOL_SHIFT                        0  /* ADCL_VOL - [7:0] */
+#define WM8962_ADCL_VOL_WIDTH                        8  /* ADCL_VOL - [7:0] */
+
+/*
+ * R22 (0x16) - Right ADC volume
+ */
+#define WM8962_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8962_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8962_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8962_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8962_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8962_ADCR_VOL_SHIFT                        0  /* ADCR_VOL - [7:0] */
+#define WM8962_ADCR_VOL_WIDTH                        8  /* ADCR_VOL - [7:0] */
+
+/*
+ * R23 (0x17) - Additional control(1)
+ */
+#define WM8962_THERR_ACT                        0x0100  /* THERR_ACT */
+#define WM8962_THERR_ACT_MASK                   0x0100  /* THERR_ACT */
+#define WM8962_THERR_ACT_SHIFT                       8  /* THERR_ACT */
+#define WM8962_THERR_ACT_WIDTH                       1  /* THERR_ACT */
+#define WM8962_ADC_BIAS                         0x0040  /* ADC_BIAS */
+#define WM8962_ADC_BIAS_MASK                    0x0040  /* ADC_BIAS */
+#define WM8962_ADC_BIAS_SHIFT                        6  /* ADC_BIAS */
+#define WM8962_ADC_BIAS_WIDTH                        1  /* ADC_BIAS */
+#define WM8962_ADC_HP                           0x0020  /* ADC_HP */
+#define WM8962_ADC_HP_MASK                      0x0020  /* ADC_HP */
+#define WM8962_ADC_HP_SHIFT                          5  /* ADC_HP */
+#define WM8962_ADC_HP_WIDTH                          1  /* ADC_HP */
+#define WM8962_TOCLK_ENA                        0x0001  /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_MASK                   0x0001  /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_SHIFT                       0  /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+
+/*
+ * R24 (0x18) - Additional control(2)
+ */
+#define WM8962_AIF_TRI                          0x0008  /* AIF_TRI */
+#define WM8962_AIF_TRI_MASK                     0x0008  /* AIF_TRI */
+#define WM8962_AIF_TRI_SHIFT                         3  /* AIF_TRI */
+#define WM8962_AIF_TRI_WIDTH                         1  /* AIF_TRI */
+
+/*
+ * R25 (0x19) - Pwr Mgmt (1)
+ */
+#define WM8962_DMIC_ENA                         0x0400  /* DMIC_ENA */
+#define WM8962_DMIC_ENA_MASK                    0x0400  /* DMIC_ENA */
+#define WM8962_DMIC_ENA_SHIFT                       10  /* DMIC_ENA */
+#define WM8962_DMIC_ENA_WIDTH                        1  /* DMIC_ENA */
+#define WM8962_OPCLK_ENA                        0x0200  /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_MASK                   0x0200  /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_SHIFT                       9  /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8962_VMID_SEL_MASK                    0x0180  /* VMID_SEL - [8:7] */
+#define WM8962_VMID_SEL_SHIFT                        7  /* VMID_SEL - [8:7] */
+#define WM8962_VMID_SEL_WIDTH                        2  /* VMID_SEL - [8:7] */
+#define WM8962_BIAS_ENA                         0x0040  /* BIAS_ENA */
+#define WM8962_BIAS_ENA_MASK                    0x0040  /* BIAS_ENA */
+#define WM8962_BIAS_ENA_SHIFT                        6  /* BIAS_ENA */
+#define WM8962_BIAS_ENA_WIDTH                        1  /* BIAS_ENA */
+#define WM8962_INL_ENA                          0x0020  /* INL_ENA */
+#define WM8962_INL_ENA_MASK                     0x0020  /* INL_ENA */
+#define WM8962_INL_ENA_SHIFT                         5  /* INL_ENA */
+#define WM8962_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8962_INR_ENA                          0x0010  /* INR_ENA */
+#define WM8962_INR_ENA_MASK                     0x0010  /* INR_ENA */
+#define WM8962_INR_ENA_SHIFT                         4  /* INR_ENA */
+#define WM8962_INR_ENA_WIDTH                         1  /* INR_ENA */
+#define WM8962_ADCL_ENA                         0x0008  /* ADCL_ENA */
+#define WM8962_ADCL_ENA_MASK                    0x0008  /* ADCL_ENA */
+#define WM8962_ADCL_ENA_SHIFT                        3  /* ADCL_ENA */
+#define WM8962_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8962_ADCR_ENA                         0x0004  /* ADCR_ENA */
+#define WM8962_ADCR_ENA_MASK                    0x0004  /* ADCR_ENA */
+#define WM8962_ADCR_ENA_SHIFT                        2  /* ADCR_ENA */
+#define WM8962_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+#define WM8962_MICBIAS_ENA                      0x0002  /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_MASK                 0x0002  /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_SHIFT                     1  /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_WIDTH                     1  /* MICBIAS_ENA */
+
+/*
+ * R26 (0x1A) - Pwr Mgmt (2)
+ */
+#define WM8962_DACL_ENA                         0x0100  /* DACL_ENA */
+#define WM8962_DACL_ENA_MASK                    0x0100  /* DACL_ENA */
+#define WM8962_DACL_ENA_SHIFT                        8  /* DACL_ENA */
+#define WM8962_DACL_ENA_WIDTH                        1  /* DACL_ENA */
+#define WM8962_DACR_ENA                         0x0080  /* DACR_ENA */
+#define WM8962_DACR_ENA_MASK                    0x0080  /* DACR_ENA */
+#define WM8962_DACR_ENA_SHIFT                        7  /* DACR_ENA */
+#define WM8962_DACR_ENA_WIDTH                        1  /* DACR_ENA */
+#define WM8962_HPOUTL_PGA_ENA                   0x0040  /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_MASK              0x0040  /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_SHIFT                  6  /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_WIDTH                  1  /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA                   0x0020  /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_MASK              0x0020  /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_SHIFT                  5  /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_WIDTH                  1  /* HPOUTR_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA                  0x0010  /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_MASK             0x0010  /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_SHIFT                 4  /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_WIDTH                 1  /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA                  0x0008  /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_MASK             0x0008  /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_SHIFT                 3  /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_WIDTH                 1  /* SPKOUTR_PGA_ENA */
+#define WM8962_HPOUTL_PGA_MUTE                  0x0002  /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_MASK             0x0002  /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_SHIFT                 1  /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_WIDTH                 1  /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE                  0x0001  /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_MASK             0x0001  /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_SHIFT                 0  /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_WIDTH                 1  /* HPOUTR_PGA_MUTE */
+
+/*
+ * R27 (0x1B) - Additional Control (3)
+ */
+#define WM8962_SAMPLE_RATE_INT_MODE             0x0010  /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_MASK        0x0010  /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_SHIFT            4  /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_WIDTH            1  /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_MASK                 0x0007  /* SAMPLE_RATE - [2:0] */
+#define WM8962_SAMPLE_RATE_SHIFT                     0  /* SAMPLE_RATE - [2:0] */
+#define WM8962_SAMPLE_RATE_WIDTH                     3  /* SAMPLE_RATE - [2:0] */
+
+/*
+ * R28 (0x1C) - Anti-pop
+ */
+#define WM8962_STARTUP_BIAS_ENA                 0x0010  /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_MASK            0x0010  /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_SHIFT                4  /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_WIDTH                1  /* STARTUP_BIAS_ENA */
+#define WM8962_VMID_BUF_ENA                     0x0008  /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_MASK                0x0008  /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_SHIFT                    3  /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
+#define WM8962_VMID_RAMP                        0x0004  /* VMID_RAMP */
+#define WM8962_VMID_RAMP_MASK                   0x0004  /* VMID_RAMP */
+#define WM8962_VMID_RAMP_SHIFT                       2  /* VMID_RAMP */
+#define WM8962_VMID_RAMP_WIDTH                       1  /* VMID_RAMP */
+
+/*
+ * R30 (0x1E) - Clocking 3
+ */
+#define WM8962_DBCLK_DIV_MASK                   0xE000  /* DBCLK_DIV - [15:13] */
+#define WM8962_DBCLK_DIV_SHIFT                      13  /* DBCLK_DIV - [15:13] */
+#define WM8962_DBCLK_DIV_WIDTH                       3  /* DBCLK_DIV - [15:13] */
+#define WM8962_OPCLK_DIV_MASK                   0x1C00  /* OPCLK_DIV - [12:10] */
+#define WM8962_OPCLK_DIV_SHIFT                      10  /* OPCLK_DIV - [12:10] */
+#define WM8962_OPCLK_DIV_WIDTH                       3  /* OPCLK_DIV - [12:10] */
+#define WM8962_TOCLK_DIV_MASK                   0x0380  /* TOCLK_DIV - [9:7] */
+#define WM8962_TOCLK_DIV_SHIFT                       7  /* TOCLK_DIV - [9:7] */
+#define WM8962_TOCLK_DIV_WIDTH                       3  /* TOCLK_DIV - [9:7] */
+#define WM8962_F256KCLK_DIV_MASK                0x007E  /* F256KCLK_DIV - [6:1] */
+#define WM8962_F256KCLK_DIV_SHIFT                    1  /* F256KCLK_DIV - [6:1] */
+#define WM8962_F256KCLK_DIV_WIDTH                    6  /* F256KCLK_DIV - [6:1] */
+
+/*
+ * R31 (0x1F) - Input mixer control (1)
+ */
+#define WM8962_MIXINL_MUTE                      0x0008  /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_MASK                 0x0008  /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_SHIFT                     3  /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_WIDTH                     1  /* MIXINL_MUTE */
+#define WM8962_MIXINR_MUTE                      0x0004  /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_MASK                 0x0004  /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_SHIFT                     2  /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_WIDTH                     1  /* MIXINR_MUTE */
+#define WM8962_MIXINL_ENA                       0x0002  /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_MASK                  0x0002  /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_SHIFT                      1  /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_WIDTH                      1  /* MIXINL_ENA */
+#define WM8962_MIXINR_ENA                       0x0001  /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_MASK                  0x0001  /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_SHIFT                      0  /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_WIDTH                      1  /* MIXINR_ENA */
+
+/*
+ * R32 (0x20) - Left input mixer volume
+ */
+#define WM8962_IN2L_MIXINL_VOL_MASK             0x01C0  /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_IN2L_MIXINL_VOL_SHIFT                 6  /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_IN2L_MIXINL_VOL_WIDTH                 3  /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_INPGAL_MIXINL_VOL_MASK           0x0038  /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_INPGAL_MIXINL_VOL_SHIFT               3  /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_INPGAL_MIXINL_VOL_WIDTH               3  /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_IN3L_MIXINL_VOL_MASK             0x0007  /* IN3L_MIXINL_VOL - [2:0] */
+#define WM8962_IN3L_MIXINL_VOL_SHIFT                 0  /* IN3L_MIXINL_VOL - [2:0] */
+#define WM8962_IN3L_MIXINL_VOL_WIDTH                 3  /* IN3L_MIXINL_VOL - [2:0] */
+
+/*
+ * R33 (0x21) - Right input mixer volume
+ */
+#define WM8962_IN2R_MIXINR_VOL_MASK             0x01C0  /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_IN2R_MIXINR_VOL_SHIFT                 6  /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_IN2R_MIXINR_VOL_WIDTH                 3  /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_INPGAR_MIXINR_VOL_MASK           0x0038  /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_INPGAR_MIXINR_VOL_SHIFT               3  /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_INPGAR_MIXINR_VOL_WIDTH               3  /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_IN3R_MIXINR_VOL_MASK             0x0007  /* IN3R_MIXINR_VOL - [2:0] */
+#define WM8962_IN3R_MIXINR_VOL_SHIFT                 0  /* IN3R_MIXINR_VOL - [2:0] */
+#define WM8962_IN3R_MIXINR_VOL_WIDTH                 3  /* IN3R_MIXINR_VOL - [2:0] */
+
+/*
+ * R34 (0x22) - Input mixer control (2)
+ */
+#define WM8962_IN2L_TO_MIXINL                   0x0020  /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_MASK              0x0020  /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_SHIFT                  5  /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_WIDTH                  1  /* IN2L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL                   0x0010  /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_MASK              0x0010  /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_SHIFT                  4  /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_WIDTH                  1  /* IN3L_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL                 0x0008  /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_MASK            0x0008  /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_SHIFT                3  /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_WIDTH                1  /* INPGAL_TO_MIXINL */
+#define WM8962_IN2R_TO_MIXINR                   0x0004  /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_MASK              0x0004  /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_SHIFT                  2  /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_WIDTH                  1  /* IN2R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR                   0x0002  /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_MASK              0x0002  /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_SHIFT                  1  /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_WIDTH                  1  /* IN3R_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR                 0x0001  /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_MASK            0x0001  /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_SHIFT                0  /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_WIDTH                1  /* INPGAR_TO_MIXINR */
+
+/*
+ * R35 (0x23) - Input bias control
+ */
+#define WM8962_MIXIN_BIAS_MASK                  0x0038  /* MIXIN_BIAS - [5:3] */
+#define WM8962_MIXIN_BIAS_SHIFT                      3  /* MIXIN_BIAS - [5:3] */
+#define WM8962_MIXIN_BIAS_WIDTH                      3  /* MIXIN_BIAS - [5:3] */
+#define WM8962_INPGA_BIAS_MASK                  0x0007  /* INPGA_BIAS - [2:0] */
+#define WM8962_INPGA_BIAS_SHIFT                      0  /* INPGA_BIAS - [2:0] */
+#define WM8962_INPGA_BIAS_WIDTH                      3  /* INPGA_BIAS - [2:0] */
+
+/*
+ * R37 (0x25) - Left input PGA control
+ */
+#define WM8962_INPGAL_ENA                       0x0010  /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_MASK                  0x0010  /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_SHIFT                      4  /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_WIDTH                      1  /* INPGAL_ENA */
+#define WM8962_IN1L_TO_INPGAL                   0x0008  /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_MASK              0x0008  /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_SHIFT                  3  /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_WIDTH                  1  /* IN1L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL                   0x0004  /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_MASK              0x0004  /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_SHIFT                  2  /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_WIDTH                  1  /* IN2L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL                   0x0002  /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_MASK              0x0002  /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_SHIFT                  1  /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_WIDTH                  1  /* IN3L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL                   0x0001  /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_MASK              0x0001  /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_SHIFT                  0  /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_WIDTH                  1  /* IN4L_TO_INPGAL */
+
+/*
+ * R38 (0x26) - Right input PGA control
+ */
+#define WM8962_INPGAR_ENA                       0x0010  /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_MASK                  0x0010  /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_SHIFT                      4  /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_WIDTH                      1  /* INPGAR_ENA */
+#define WM8962_IN1R_TO_INPGAR                   0x0008  /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_MASK              0x0008  /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_SHIFT                  3  /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_WIDTH                  1  /* IN1R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR                   0x0004  /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_MASK              0x0004  /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_SHIFT                  2  /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_WIDTH                  1  /* IN2R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR                   0x0002  /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_MASK              0x0002  /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_SHIFT                  1  /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_WIDTH                  1  /* IN3R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR                   0x0001  /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_MASK              0x0001  /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_SHIFT                  0  /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_WIDTH                  1  /* IN4R_TO_INPGAR */
+
+/*
+ * R40 (0x28) - SPKOUTL volume
+ */
+#define WM8962_SPKOUT_VU                        0x0100  /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_MASK                   0x0100  /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_SHIFT                       8  /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_WIDTH                       1  /* SPKOUT_VU */
+#define WM8962_SPKOUTL_ZC                       0x0080  /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_MASK                  0x0080  /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_SHIFT                      7  /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_WIDTH                      1  /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_VOL_MASK                 0x007F  /* SPKOUTL_VOL - [6:0] */
+#define WM8962_SPKOUTL_VOL_SHIFT                     0  /* SPKOUTL_VOL - [6:0] */
+#define WM8962_SPKOUTL_VOL_WIDTH                     7  /* SPKOUTL_VOL - [6:0] */
+
+/*
+ * R41 (0x29) - SPKOUTR volume
+ */
+#define WM8962_SPKOUTR_ZC                       0x0080  /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_MASK                  0x0080  /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_SHIFT                      7  /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_WIDTH                      1  /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_VOL_MASK                 0x007F  /* SPKOUTR_VOL - [6:0] */
+#define WM8962_SPKOUTR_VOL_SHIFT                     0  /* SPKOUTR_VOL - [6:0] */
+#define WM8962_SPKOUTR_VOL_WIDTH                     7  /* SPKOUTR_VOL - [6:0] */
+
+/*
+ * R47 (0x2F) - Thermal Shutdown Status
+ */
+#define WM8962_TEMP_ERR_HP                      0x0008  /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_MASK                 0x0008  /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_SHIFT                     3  /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_WIDTH                     1  /* TEMP_ERR_HP */
+#define WM8962_TEMP_WARN_HP                     0x0004  /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_MASK                0x0004  /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_SHIFT                    2  /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_WIDTH                    1  /* TEMP_WARN_HP */
+#define WM8962_TEMP_ERR_SPK                     0x0002  /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_MASK                0x0002  /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_SHIFT                    1  /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_WIDTH                    1  /* TEMP_ERR_SPK */
+#define WM8962_TEMP_WARN_SPK                    0x0001  /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_MASK               0x0001  /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_SHIFT                   0  /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_WIDTH                   1  /* TEMP_WARN_SPK */
+
+/*
+ * R48 (0x30) - Additional Control (4)
+ */
+#define WM8962_MICDET_THR_MASK                  0x7000  /* MICDET_THR - [14:12] */
+#define WM8962_MICDET_THR_SHIFT                     12  /* MICDET_THR - [14:12] */
+#define WM8962_MICDET_THR_WIDTH                      3  /* MICDET_THR - [14:12] */
+#define WM8962_MICSHORT_THR_MASK                0x0C00  /* MICSHORT_THR - [11:10] */
+#define WM8962_MICSHORT_THR_SHIFT                   10  /* MICSHORT_THR - [11:10] */
+#define WM8962_MICSHORT_THR_WIDTH                    2  /* MICSHORT_THR - [11:10] */
+#define WM8962_MICDET_ENA                       0x0200  /* MICDET_ENA */
+#define WM8962_MICDET_ENA_MASK                  0x0200  /* MICDET_ENA */
+#define WM8962_MICDET_ENA_SHIFT                      9  /* MICDET_ENA */
+#define WM8962_MICDET_ENA_WIDTH                      1  /* MICDET_ENA */
+#define WM8962_MICDET_STS                       0x0080  /* MICDET_STS */
+#define WM8962_MICDET_STS_MASK                  0x0080  /* MICDET_STS */
+#define WM8962_MICDET_STS_SHIFT                      7  /* MICDET_STS */
+#define WM8962_MICDET_STS_WIDTH                      1  /* MICDET_STS */
+#define WM8962_MICSHORT_STS                     0x0040  /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_MASK                0x0040  /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_SHIFT                    6  /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_WIDTH                    1  /* MICSHORT_STS */
+#define WM8962_TEMP_ENA_HP                      0x0004  /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_MASK                 0x0004  /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_SHIFT                     2  /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_WIDTH                     1  /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_SPK                     0x0002  /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_MASK                0x0002  /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_SHIFT                    1  /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_WIDTH                    1  /* TEMP_ENA_SPK */
+#define WM8962_MICBIAS_LVL                      0x0001  /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_MASK                 0x0001  /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_SHIFT                     0  /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_WIDTH                     1  /* MICBIAS_LVL */
+
+/*
+ * R49 (0x31) - Class D Control 1
+ */
+#define WM8962_SPKOUTR_ENA                      0x0080  /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_MASK                 0x0080  /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_SHIFT                     7  /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_WIDTH                     1  /* SPKOUTR_ENA */
+#define WM8962_SPKOUTL_ENA                      0x0040  /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_MASK                 0x0040  /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_SHIFT                     6  /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_WIDTH                     1  /* SPKOUTL_ENA */
+#define WM8962_DAC_MUTE_ALT                     0x0010  /* DAC_MUTE */
+#define WM8962_DAC_MUTE_ALT_MASK                0x0010  /* DAC_MUTE */
+#define WM8962_DAC_MUTE_ALT_SHIFT                    4  /* DAC_MUTE */
+#define WM8962_DAC_MUTE_ALT_WIDTH                    1  /* DAC_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE                 0x0002  /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_MASK            0x0002  /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_SHIFT                1  /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_WIDTH                1  /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE                 0x0001  /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_MASK            0x0001  /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_SHIFT                0  /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_WIDTH                1  /* SPKOUTR_PGA_MUTE */
+
+/*
+ * R51 (0x33) - Class D Control 2
+ */
+#define WM8962_SPK_MONO                         0x0040  /* SPK_MONO */
+#define WM8962_SPK_MONO_MASK                    0x0040  /* SPK_MONO */
+#define WM8962_SPK_MONO_SHIFT                        6  /* SPK_MONO */
+#define WM8962_SPK_MONO_WIDTH                        1  /* SPK_MONO */
+#define WM8962_CLASSD_VOL_MASK                  0x0007  /* CLASSD_VOL - [2:0] */
+#define WM8962_CLASSD_VOL_SHIFT                      0  /* CLASSD_VOL - [2:0] */
+#define WM8962_CLASSD_VOL_WIDTH                      3  /* CLASSD_VOL - [2:0] */
+
+/*
+ * R56 (0x38) - Clocking 4
+ */
+#define WM8962_SYSCLK_RATE_MASK                 0x001E  /* SYSCLK_RATE - [4:1] */
+#define WM8962_SYSCLK_RATE_SHIFT                     1  /* SYSCLK_RATE - [4:1] */
+#define WM8962_SYSCLK_RATE_WIDTH                     4  /* SYSCLK_RATE - [4:1] */
+
+/*
+ * R57 (0x39) - DAC DSP Mixing (1)
+ */
+#define WM8962_DAC_MONOMIX                      0x0200  /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_MASK                 0x0200  /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_SHIFT                     9  /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_WIDTH                     1  /* DAC_MONOMIX */
+#define WM8962_ADCR_DAC_SVOL_MASK               0x00F0  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADCR_DAC_SVOL_SHIFT                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADCR_DAC_SVOL_WIDTH                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADC_TO_DACR_MASK                 0x000C  /* ADC_TO_DACR - [3:2] */
+#define WM8962_ADC_TO_DACR_SHIFT                     2  /* ADC_TO_DACR - [3:2] */
+#define WM8962_ADC_TO_DACR_WIDTH                     2  /* ADC_TO_DACR - [3:2] */
+
+/*
+ * R58 (0x3A) - DAC DSP Mixing (2)
+ */
+#define WM8962_ADCL_DAC_SVOL_MASK               0x00F0  /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADCL_DAC_SVOL_SHIFT                   4  /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADCL_DAC_SVOL_WIDTH                   4  /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADC_TO_DACL_MASK                 0x000C  /* ADC_TO_DACL - [3:2] */
+#define WM8962_ADC_TO_DACL_SHIFT                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8962_ADC_TO_DACL_WIDTH                     2  /* ADC_TO_DACL - [3:2] */
+
+/*
+ * R60 (0x3C) - DC Servo 0
+ */
+#define WM8962_INL_DCS_ENA                      0x0080  /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_MASK                 0x0080  /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_SHIFT                     7  /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_WIDTH                     1  /* INL_DCS_ENA */
+#define WM8962_INL_DCS_STARTUP                  0x0040  /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_MASK             0x0040  /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_SHIFT                 6  /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_WIDTH                 1  /* INL_DCS_STARTUP */
+#define WM8962_INR_DCS_ENA                      0x0008  /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_MASK                 0x0008  /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_SHIFT                     3  /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_WIDTH                     1  /* INR_DCS_ENA */
+#define WM8962_INR_DCS_STARTUP                  0x0004  /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_MASK             0x0004  /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_SHIFT                 2  /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_WIDTH                 1  /* INR_DCS_STARTUP */
+
+/*
+ * R61 (0x3D) - DC Servo 1
+ */
+#define WM8962_HP1L_DCS_ENA                     0x0080  /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_MASK                0x0080  /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_SHIFT                    7  /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_WIDTH                    1  /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_STARTUP                 0x0040  /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_MASK            0x0040  /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_SHIFT                6  /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_WIDTH                1  /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_SYNC                    0x0010  /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_MASK               0x0010  /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_SHIFT                   4  /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_WIDTH                   1  /* HP1L_DCS_SYNC */
+#define WM8962_HP1R_DCS_ENA                     0x0008  /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_MASK                0x0008  /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_SHIFT                    3  /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_WIDTH                    1  /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_STARTUP                 0x0004  /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_MASK            0x0004  /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_SHIFT                2  /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_WIDTH                1  /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_SYNC                    0x0001  /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_MASK               0x0001  /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_SHIFT                   0  /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_WIDTH                   1  /* HP1R_DCS_SYNC */
+
+/*
+ * R64 (0x40) - DC Servo 4
+ */
+#define WM8962_HP1_DCS_SYNC_STEPS_MASK          0x3F80  /* HP1_DCS_SYNC_STEPS - [13:7] */
+#define WM8962_HP1_DCS_SYNC_STEPS_SHIFT              7  /* HP1_DCS_SYNC_STEPS - [13:7] */
+#define WM8962_HP1_DCS_SYNC_STEPS_WIDTH              7  /* HP1_DCS_SYNC_STEPS - [13:7] */
+
+/*
+ * R66 (0x42) - DC Servo 6
+ */
+#define WM8962_DCS_STARTUP_DONE_INL             0x0400  /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_MASK        0x0400  /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_SHIFT           10  /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_WIDTH            1  /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INR             0x0200  /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_MASK        0x0200  /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_SHIFT            9  /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_WIDTH            1  /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_HP1L            0x0100  /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_MASK       0x0100  /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_SHIFT           8  /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_WIDTH           1  /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1R            0x0080  /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_MASK       0x0080  /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_SHIFT           7  /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_WIDTH           1  /* DCS_STARTUP_DONE_HP1R */
+
+/*
+ * R68 (0x44) - Analogue PGA Bias
+ */
+#define WM8962_HP_PGAS_BIAS_MASK                0x0007  /* HP_PGAS_BIAS - [2:0] */
+#define WM8962_HP_PGAS_BIAS_SHIFT                    0  /* HP_PGAS_BIAS - [2:0] */
+#define WM8962_HP_PGAS_BIAS_WIDTH                    3  /* HP_PGAS_BIAS - [2:0] */
+
+/*
+ * R69 (0x45) - Analogue HP 0
+ */
+#define WM8962_HP1L_RMV_SHORT                   0x0080  /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_MASK              0x0080  /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_SHIFT                  7  /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_WIDTH                  1  /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_ENA_OUTP                    0x0040  /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_MASK               0x0040  /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_SHIFT                   6  /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_WIDTH                   1  /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_DLY                     0x0020  /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_MASK                0x0020  /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_SHIFT                    5  /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_WIDTH                    1  /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA                         0x0010  /* HP1L_ENA */
+#define WM8962_HP1L_ENA_MASK                    0x0010  /* HP1L_ENA */
+#define WM8962_HP1L_ENA_SHIFT                        4  /* HP1L_ENA */
+#define WM8962_HP1L_ENA_WIDTH                        1  /* HP1L_ENA */
+#define WM8962_HP1R_RMV_SHORT                   0x0008  /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_MASK              0x0008  /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_SHIFT                  3  /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_WIDTH                  1  /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_ENA_OUTP                    0x0004  /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_MASK               0x0004  /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_SHIFT                   2  /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_WIDTH                   1  /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_DLY                     0x0002  /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_MASK                0x0002  /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_SHIFT                    1  /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_WIDTH                    1  /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA                         0x0001  /* HP1R_ENA */
+#define WM8962_HP1R_ENA_MASK                    0x0001  /* HP1R_ENA */
+#define WM8962_HP1R_ENA_SHIFT                        0  /* HP1R_ENA */
+#define WM8962_HP1R_ENA_WIDTH                        1  /* HP1R_ENA */
+
+/*
+ * R71 (0x47) - Analogue HP 2
+ */
+#define WM8962_HP1L_VOL_MASK                    0x01C0  /* HP1L_VOL - [8:6] */
+#define WM8962_HP1L_VOL_SHIFT                        6  /* HP1L_VOL - [8:6] */
+#define WM8962_HP1L_VOL_WIDTH                        3  /* HP1L_VOL - [8:6] */
+#define WM8962_HP1R_VOL_MASK                    0x0038  /* HP1R_VOL - [5:3] */
+#define WM8962_HP1R_VOL_SHIFT                        3  /* HP1R_VOL - [5:3] */
+#define WM8962_HP1R_VOL_WIDTH                        3  /* HP1R_VOL - [5:3] */
+#define WM8962_HP_BIAS_BOOST_MASK               0x0007  /* HP_BIAS_BOOST - [2:0] */
+#define WM8962_HP_BIAS_BOOST_SHIFT                   0  /* HP_BIAS_BOOST - [2:0] */
+#define WM8962_HP_BIAS_BOOST_WIDTH                   3  /* HP_BIAS_BOOST - [2:0] */
+
+/*
+ * R72 (0x48) - Charge Pump 1
+ */
+#define WM8962_CP_ENA                           0x0001  /* CP_ENA */
+#define WM8962_CP_ENA_MASK                      0x0001  /* CP_ENA */
+#define WM8962_CP_ENA_SHIFT                          0  /* CP_ENA */
+#define WM8962_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R82 (0x52) - Charge Pump B
+ */
+#define WM8962_CP_DYN_PWR                       0x0001  /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_MASK                  0x0001  /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_SHIFT                      0  /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_WIDTH                      1  /* CP_DYN_PWR */
+
+/*
+ * R87 (0x57) - Write Sequencer Control 1
+ */
+#define WM8962_WSEQ_AUTOSEQ_ENA                 0x0080  /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_MASK            0x0080  /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_SHIFT                7  /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_WIDTH                1  /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_ENA                         0x0020  /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_MASK                    0x0020  /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_SHIFT                        5  /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+
+/*
+ * R90 (0x5A) - Write Sequencer Control 2
+ */
+#define WM8962_WSEQ_ABORT                       0x0100  /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_MASK                  0x0100  /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_SHIFT                      8  /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8962_WSEQ_START                       0x0080  /* WSEQ_START */
+#define WM8962_WSEQ_START_MASK                  0x0080  /* WSEQ_START */
+#define WM8962_WSEQ_START_SHIFT                      7  /* WSEQ_START */
+#define WM8962_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8962_WSEQ_START_INDEX_MASK            0x007F  /* WSEQ_START_INDEX - [6:0] */
+#define WM8962_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [6:0] */
+#define WM8962_WSEQ_START_INDEX_WIDTH                7  /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R93 (0x5D) - Write Sequencer Control 3
+ */
+#define WM8962_WSEQ_CURRENT_INDEX_MASK          0x03F8  /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_CURRENT_INDEX_SHIFT              3  /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_CURRENT_INDEX_WIDTH              7  /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R94 (0x5E) - Control Interface
+ */
+#define WM8962_SPI_CONTRD                       0x0040  /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_MASK                  0x0040  /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_SHIFT                      6  /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_WIDTH                      1  /* SPI_CONTRD */
+#define WM8962_SPI_4WIRE                        0x0020  /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_MASK                   0x0020  /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_SHIFT                       5  /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_WIDTH                       1  /* SPI_4WIRE */
+#define WM8962_SPI_CFG                          0x0010  /* SPI_CFG */
+#define WM8962_SPI_CFG_MASK                     0x0010  /* SPI_CFG */
+#define WM8962_SPI_CFG_SHIFT                         4  /* SPI_CFG */
+#define WM8962_SPI_CFG_WIDTH                         1  /* SPI_CFG */
+
+/*
+ * R99 (0x63) - Mixer Enables
+ */
+#define WM8962_HPMIXL_ENA                       0x0008  /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_MASK                  0x0008  /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_SHIFT                      3  /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_WIDTH                      1  /* HPMIXL_ENA */
+#define WM8962_HPMIXR_ENA                       0x0004  /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_MASK                  0x0004  /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_SHIFT                      2  /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_WIDTH                      1  /* HPMIXR_ENA */
+#define WM8962_SPKMIXL_ENA                      0x0002  /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_MASK                 0x0002  /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_SHIFT                     1  /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_WIDTH                     1  /* SPKMIXL_ENA */
+#define WM8962_SPKMIXR_ENA                      0x0001  /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_MASK                 0x0001  /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_SHIFT                     0  /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_WIDTH                     1  /* SPKMIXR_ENA */
+
+/*
+ * R100 (0x64) - Headphone Mixer (1)
+ */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA             0x0080  /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_MASK        0x0080  /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_SHIFT            7  /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_WIDTH            1  /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_DACL_TO_HPMIXL                   0x0020  /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_MASK              0x0020  /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_SHIFT                  5  /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_WIDTH                  1  /* DACL_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL                   0x0010  /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_MASK              0x0010  /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_SHIFT                  4  /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_WIDTH                  1  /* DACR_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL                 0x0008  /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_MASK            0x0008  /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_SHIFT                3  /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_WIDTH                1  /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL                 0x0004  /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_MASK            0x0004  /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_SHIFT                2  /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_WIDTH                1  /* MIXINR_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL                   0x0002  /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_MASK              0x0002  /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_SHIFT                  1  /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_WIDTH                  1  /* IN4L_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL                   0x0001  /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_MASK              0x0001  /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_SHIFT                  0  /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_WIDTH                  1  /* IN4R_TO_HPMIXL */
+
+/*
+ * R101 (0x65) - Headphone Mixer (2)
+ */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA             0x0080  /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_MASK        0x0080  /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_SHIFT            7  /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_WIDTH            1  /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_DACL_TO_HPMIXR                   0x0020  /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_MASK              0x0020  /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_SHIFT                  5  /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_WIDTH                  1  /* DACL_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR                   0x0010  /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_MASK              0x0010  /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_SHIFT                  4  /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_WIDTH                  1  /* DACR_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR                 0x0008  /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_MASK            0x0008  /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_SHIFT                3  /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_WIDTH                1  /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR                 0x0004  /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_MASK            0x0004  /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_SHIFT                2  /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_WIDTH                1  /* MIXINR_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR                   0x0002  /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_MASK              0x0002  /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_SHIFT                  1  /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_WIDTH                  1  /* IN4L_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR                   0x0001  /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_MASK              0x0001  /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_SHIFT                  0  /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_WIDTH                  1  /* IN4R_TO_HPMIXR */
+
+/*
+ * R102 (0x66) - Headphone Mixer (3)
+ */
+#define WM8962_HPMIXL_MUTE                      0x0100  /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_MASK                 0x0100  /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_SHIFT                     8  /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_WIDTH                     1  /* HPMIXL_MUTE */
+#define WM8962_MIXINL_HPMIXL_VOL                0x0080  /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_MASK           0x0080  /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_SHIFT               7  /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_WIDTH               1  /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL                0x0040  /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_MASK           0x0040  /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_SHIFT               6  /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_WIDTH               1  /* MIXINR_HPMIXL_VOL */
+#define WM8962_IN4L_HPMIXL_VOL_MASK             0x0038  /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXL_VOL_SHIFT                 3  /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXL_VOL_WIDTH                 3  /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4R_HPMIXL_VOL_MASK             0x0007  /* IN4R_HPMIXL_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXL_VOL_SHIFT                 0  /* IN4R_HPMIXL_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXL_VOL_WIDTH                 3  /* IN4R_HPMIXL_VOL - [2:0] */
+
+/*
+ * R103 (0x67) - Headphone Mixer (4)
+ */
+#define WM8962_HPMIXR_MUTE                      0x0100  /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_MASK                 0x0100  /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_SHIFT                     8  /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_WIDTH                     1  /* HPMIXR_MUTE */
+#define WM8962_MIXINL_HPMIXR_VOL                0x0080  /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_MASK           0x0080  /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_SHIFT               7  /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_WIDTH               1  /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL                0x0040  /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_MASK           0x0040  /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_SHIFT               6  /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_WIDTH               1  /* MIXINR_HPMIXR_VOL */
+#define WM8962_IN4L_HPMIXR_VOL_MASK             0x0038  /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXR_VOL_SHIFT                 3  /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXR_VOL_WIDTH                 3  /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4R_HPMIXR_VOL_MASK             0x0007  /* IN4R_HPMIXR_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXR_VOL_SHIFT                 0  /* IN4R_HPMIXR_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXR_VOL_WIDTH                 3  /* IN4R_HPMIXR_VOL - [2:0] */
+
+/*
+ * R105 (0x69) - Speaker Mixer (1)
+ */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA           0x0080  /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_MASK      0x0080  /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_SHIFT          7  /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_WIDTH          1  /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_DACL_TO_SPKMIXL                  0x0020  /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_MASK             0x0020  /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_SHIFT                 5  /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_WIDTH                 1  /* DACL_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL                  0x0010  /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_MASK             0x0010  /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_SHIFT                 4  /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_WIDTH                 1  /* DACR_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL                0x0008  /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_MASK           0x0008  /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_SHIFT               3  /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_WIDTH               1  /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL                0x0004  /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_MASK           0x0004  /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_SHIFT               2  /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_WIDTH               1  /* MIXINR_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL                  0x0002  /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_MASK             0x0002  /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_SHIFT                 1  /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_WIDTH                 1  /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL                  0x0001  /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_MASK             0x0001  /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_SHIFT                 0  /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_WIDTH                 1  /* IN4R_TO_SPKMIXL */
+
+/*
+ * R106 (0x6A) - Speaker Mixer (2)
+ */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA           0x0080  /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_MASK      0x0080  /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_SHIFT          7  /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_WIDTH          1  /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_DACL_TO_SPKMIXR                  0x0020  /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_MASK             0x0020  /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_SHIFT                 5  /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_WIDTH                 1  /* DACL_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR                  0x0010  /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_MASK             0x0010  /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_SHIFT                 4  /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_WIDTH                 1  /* DACR_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR                0x0008  /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_MASK           0x0008  /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_SHIFT               3  /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_WIDTH               1  /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR                0x0004  /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_MASK           0x0004  /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_SHIFT               2  /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_WIDTH               1  /* MIXINR_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR                  0x0002  /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_MASK             0x0002  /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_SHIFT                 1  /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_WIDTH                 1  /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR                  0x0001  /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_MASK             0x0001  /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_SHIFT                 0  /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_WIDTH                 1  /* IN4R_TO_SPKMIXR */
+
+/*
+ * R107 (0x6B) - Speaker Mixer (3)
+ */
+#define WM8962_SPKMIXL_MUTE                     0x0100  /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_MASK                0x0100  /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_SHIFT                    8  /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_WIDTH                    1  /* SPKMIXL_MUTE */
+#define WM8962_MIXINL_SPKMIXL_VOL               0x0080  /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_MASK          0x0080  /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_SHIFT              7  /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_WIDTH              1  /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL               0x0040  /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_MASK          0x0040  /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_SHIFT              6  /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_WIDTH              1  /* MIXINR_SPKMIXL_VOL */
+#define WM8962_IN4L_SPKMIXL_VOL_MASK            0x0038  /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXL_VOL_SHIFT                3  /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXL_VOL_WIDTH                3  /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4R_SPKMIXL_VOL_MASK            0x0007  /* IN4R_SPKMIXL_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXL_VOL_SHIFT                0  /* IN4R_SPKMIXL_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXL_VOL_WIDTH                3  /* IN4R_SPKMIXL_VOL - [2:0] */
+
+/*
+ * R108 (0x6C) - Speaker Mixer (4)
+ */
+#define WM8962_SPKMIXR_MUTE                     0x0100  /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_MASK                0x0100  /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_SHIFT                    8  /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_WIDTH                    1  /* SPKMIXR_MUTE */
+#define WM8962_MIXINL_SPKMIXR_VOL               0x0080  /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_MASK          0x0080  /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_SHIFT              7  /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_WIDTH              1  /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL               0x0040  /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_MASK          0x0040  /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_SHIFT              6  /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_WIDTH              1  /* MIXINR_SPKMIXR_VOL */
+#define WM8962_IN4L_SPKMIXR_VOL_MASK            0x0038  /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXR_VOL_SHIFT                3  /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXR_VOL_WIDTH                3  /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4R_SPKMIXR_VOL_MASK            0x0007  /* IN4R_SPKMIXR_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXR_VOL_SHIFT                0  /* IN4R_SPKMIXR_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXR_VOL_WIDTH                3  /* IN4R_SPKMIXR_VOL - [2:0] */
+
+/*
+ * R109 (0x6D) - Speaker Mixer (5)
+ */
+#define WM8962_DACL_SPKMIXL_VOL                 0x0080  /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_MASK            0x0080  /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_SHIFT                7  /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_WIDTH                1  /* DACL_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL                 0x0040  /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_MASK            0x0040  /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_SHIFT                6  /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_WIDTH                1  /* DACR_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXR_VOL                 0x0020  /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_MASK            0x0020  /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_SHIFT                5  /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_WIDTH                1  /* DACL_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL                 0x0010  /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_MASK            0x0010  /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_SHIFT                4  /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_WIDTH                1  /* DACR_SPKMIXR_VOL */
+
+/*
+ * R110 (0x6E) - Beep Generator (1)
+ */
+#define WM8962_BEEP_GAIN_MASK                   0x00F0  /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_GAIN_SHIFT                       4  /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_GAIN_WIDTH                       4  /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_RATE_MASK                   0x0006  /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_RATE_SHIFT                       1  /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_RATE_WIDTH                       2  /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_ENA                         0x0001  /* BEEP_ENA */
+#define WM8962_BEEP_ENA_MASK                    0x0001  /* BEEP_ENA */
+#define WM8962_BEEP_ENA_SHIFT                        0  /* BEEP_ENA */
+#define WM8962_BEEP_ENA_WIDTH                        1  /* BEEP_ENA */
+
+/*
+ * R115 (0x73) - Oscillator Trim (3)
+ */
+#define WM8962_OSC_TRIM_XTI_MASK                0x001F  /* OSC_TRIM_XTI - [4:0] */
+#define WM8962_OSC_TRIM_XTI_SHIFT                    0  /* OSC_TRIM_XTI - [4:0] */
+#define WM8962_OSC_TRIM_XTI_WIDTH                    5  /* OSC_TRIM_XTI - [4:0] */
+
+/*
+ * R116 (0x74) - Oscillator Trim (4)
+ */
+#define WM8962_OSC_TRIM_XTO_MASK                0x001F  /* OSC_TRIM_XTO - [4:0] */
+#define WM8962_OSC_TRIM_XTO_SHIFT                    0  /* OSC_TRIM_XTO - [4:0] */
+#define WM8962_OSC_TRIM_XTO_WIDTH                    5  /* OSC_TRIM_XTO - [4:0] */
+
+/*
+ * R119 (0x77) - Oscillator Trim (7)
+ */
+#define WM8962_XTO_CAP_SEL_MASK                 0x00F0  /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTO_CAP_SEL_SHIFT                     4  /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTO_CAP_SEL_WIDTH                     4  /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTI_CAP_SEL_MASK                 0x000F  /* XTI_CAP_SEL - [3:0] */
+#define WM8962_XTI_CAP_SEL_SHIFT                     0  /* XTI_CAP_SEL - [3:0] */
+#define WM8962_XTI_CAP_SEL_WIDTH                     4  /* XTI_CAP_SEL - [3:0] */
+
+/*
+ * R124 (0x7C) - Analogue Clocking1
+ */
+#define WM8962_CLKOUT2_SEL_MASK                 0x0060  /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT2_SEL_SHIFT                     5  /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT2_SEL_WIDTH                     2  /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT3_SEL_MASK                 0x0018  /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT3_SEL_SHIFT                     3  /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT3_SEL_WIDTH                     2  /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT5_SEL                      0x0001  /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_MASK                 0x0001  /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_SHIFT                     0  /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_WIDTH                     1  /* CLKOUT5_SEL */
+
+/*
+ * R125 (0x7D) - Analogue Clocking2
+ */
+#define WM8962_PLL2_OUTDIV                      0x0080  /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_MASK                 0x0080  /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_SHIFT                     7  /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_WIDTH                     1  /* PLL2_OUTDIV */
+#define WM8962_PLL3_OUTDIV                      0x0040  /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_MASK                 0x0040  /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_SHIFT                     6  /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_WIDTH                     1  /* PLL3_OUTDIV */
+#define WM8962_PLL_SYSCLK_DIV_MASK              0x0018  /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_PLL_SYSCLK_DIV_SHIFT                  3  /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_PLL_SYSCLK_DIV_WIDTH                  2  /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_CLKOUT3_DIV                      0x0004  /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_MASK                 0x0004  /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_SHIFT                     2  /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_WIDTH                     1  /* CLKOUT3_DIV */
+#define WM8962_CLKOUT2_DIV                      0x0002  /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_MASK                 0x0002  /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_SHIFT                     1  /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_WIDTH                     1  /* CLKOUT2_DIV */
+#define WM8962_CLKOUT5_DIV                      0x0001  /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_MASK                 0x0001  /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_SHIFT                     0  /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_WIDTH                     1  /* CLKOUT5_DIV */
+
+/*
+ * R126 (0x7E) - Analogue Clocking3
+ */
+#define WM8962_CLKOUT2_OE                       0x0008  /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_MASK                  0x0008  /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_SHIFT                      3  /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_WIDTH                      1  /* CLKOUT2_OE */
+#define WM8962_CLKOUT3_OE                       0x0004  /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_MASK                  0x0004  /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_SHIFT                      2  /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_WIDTH                      1  /* CLKOUT3_OE */
+#define WM8962_CLKOUT5_OE                       0x0001  /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_MASK                  0x0001  /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_SHIFT                      0  /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_WIDTH                      1  /* CLKOUT5_OE */
+
+/*
+ * R127 (0x7F) - PLL Software Reset
+ */
+#define WM8962_SW_RESET_PLL_MASK                0xFFFF  /* SW_RESET_PLL - [15:0] */
+#define WM8962_SW_RESET_PLL_SHIFT                    0  /* SW_RESET_PLL - [15:0] */
+#define WM8962_SW_RESET_PLL_WIDTH                   16  /* SW_RESET_PLL - [15:0] */
+
+/*
+ * R129 (0x81) - PLL2
+ */
+#define WM8962_OSC_ENA                          0x0080  /* OSC_ENA */
+#define WM8962_OSC_ENA_MASK                     0x0080  /* OSC_ENA */
+#define WM8962_OSC_ENA_SHIFT                         7  /* OSC_ENA */
+#define WM8962_OSC_ENA_WIDTH                         1  /* OSC_ENA */
+#define WM8962_PLL2_ENA                         0x0020  /* PLL2_ENA */
+#define WM8962_PLL2_ENA_MASK                    0x0020  /* PLL2_ENA */
+#define WM8962_PLL2_ENA_SHIFT                        5  /* PLL2_ENA */
+#define WM8962_PLL2_ENA_WIDTH                        1  /* PLL2_ENA */
+#define WM8962_PLL3_ENA                         0x0010  /* PLL3_ENA */
+#define WM8962_PLL3_ENA_MASK                    0x0010  /* PLL3_ENA */
+#define WM8962_PLL3_ENA_SHIFT                        4  /* PLL3_ENA */
+#define WM8962_PLL3_ENA_WIDTH                        1  /* PLL3_ENA */
+
+/*
+ * R131 (0x83) - PLL 4
+ */
+#define WM8962_PLL_CLK_SRC                      0x0002  /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_MASK                 0x0002  /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_SHIFT                     1  /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_WIDTH                     1  /* PLL_CLK_SRC */
+#define WM8962_FLL_TO_PLL3                      0x0001  /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_MASK                 0x0001  /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_SHIFT                     0  /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_WIDTH                     1  /* FLL_TO_PLL3 */
+
+/*
+ * R136 (0x88) - PLL 9
+ */
+#define WM8962_PLL2_FRAC                        0x0040  /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_MASK                   0x0040  /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_SHIFT                       6  /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_WIDTH                       1  /* PLL2_FRAC */
+#define WM8962_PLL2_N_MASK                      0x001F  /* PLL2_N - [4:0] */
+#define WM8962_PLL2_N_SHIFT                          0  /* PLL2_N - [4:0] */
+#define WM8962_PLL2_N_WIDTH                          5  /* PLL2_N - [4:0] */
+
+/*
+ * R137 (0x89) - PLL 10
+ */
+#define WM8962_PLL2_K_MASK                      0x00FF  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT                          0  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH                          8  /* PLL2_K - [7:0] */
+
+/*
+ * R138 (0x8A) - PLL 11
+ */
+#define WM8962_PLL2_K_MASK                      0x00FF  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT                          0  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH                          8  /* PLL2_K - [7:0] */
+
+/*
+ * R139 (0x8B) - PLL 12
+ */
+#define WM8962_PLL2_K_MASK                      0x00FF  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT                          0  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH                          8  /* PLL2_K - [7:0] */
+
+/*
+ * R140 (0x8C) - PLL 13
+ */
+#define WM8962_PLL3_FRAC                        0x0040  /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_MASK                   0x0040  /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_SHIFT                       6  /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_WIDTH                       1  /* PLL3_FRAC */
+#define WM8962_PLL3_N_MASK                      0x001F  /* PLL3_N - [4:0] */
+#define WM8962_PLL3_N_SHIFT                          0  /* PLL3_N - [4:0] */
+#define WM8962_PLL3_N_WIDTH                          5  /* PLL3_N - [4:0] */
+
+/*
+ * R141 (0x8D) - PLL 14
+ */
+#define WM8962_PLL3_K_MASK                      0x00FF  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT                          0  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH                          8  /* PLL3_K - [7:0] */
+
+/*
+ * R142 (0x8E) - PLL 15
+ */
+#define WM8962_PLL3_K_MASK                      0x00FF  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT                          0  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH                          8  /* PLL3_K - [7:0] */
+
+/*
+ * R143 (0x8F) - PLL 16
+ */
+#define WM8962_PLL3_K_MASK                      0x00FF  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT                          0  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH                          8  /* PLL3_K - [7:0] */
+
+/*
+ * R155 (0x9B) - FLL Control (1)
+ */
+#define WM8962_FLL_REFCLK_SRC_MASK              0x0060  /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_REFCLK_SRC_SHIFT                  5  /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_REFCLK_SRC_WIDTH                  2  /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_FRAC                         0x0004  /* FLL_FRAC */
+#define WM8962_FLL_FRAC_MASK                    0x0004  /* FLL_FRAC */
+#define WM8962_FLL_FRAC_SHIFT                        2  /* FLL_FRAC */
+#define WM8962_FLL_FRAC_WIDTH                        1  /* FLL_FRAC */
+#define WM8962_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8962_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM8962_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM8962_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM8962_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R156 (0x9C) - FLL Control (2)
+ */
+#define WM8962_FLL_OUTDIV_MASK                  0x01F8  /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_OUTDIV_SHIFT                      3  /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_REFCLK_DIV_MASK              0x0003  /* FLL_REFCLK_DIV - [1:0] */
+#define WM8962_FLL_REFCLK_DIV_SHIFT                  0  /* FLL_REFCLK_DIV - [1:0] */
+#define WM8962_FLL_REFCLK_DIV_WIDTH                  2  /* FLL_REFCLK_DIV - [1:0] */
+
+/*
+ * R157 (0x9D) - FLL Control (3)
+ */
+#define WM8962_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM8962_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM8962_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R159 (0x9F) - FLL Control (5)
+ */
+#define WM8962_FLL_FRC_NCO_VAL_MASK             0x007E  /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO_VAL_SHIFT                 1  /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO                      0x0001  /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_MASK                 0x0001  /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_SHIFT                     0  /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
+
+/*
+ * R160 (0xA0) - FLL Control (6)
+ */
+#define WM8962_FLL_THETA_MASK                   0xFFFF  /* FLL_THETA - [15:0] */
+#define WM8962_FLL_THETA_SHIFT                       0  /* FLL_THETA - [15:0] */
+#define WM8962_FLL_THETA_WIDTH                      16  /* FLL_THETA - [15:0] */
+
+/*
+ * R161 (0xA1) - FLL Control (7)
+ */
+#define WM8962_FLL_LAMBDA_MASK                  0xFFFF  /* FLL_LAMBDA - [15:0] */
+#define WM8962_FLL_LAMBDA_SHIFT                      0  /* FLL_LAMBDA - [15:0] */
+#define WM8962_FLL_LAMBDA_WIDTH                     16  /* FLL_LAMBDA - [15:0] */
+
+/*
+ * R162 (0xA2) - FLL Control (8)
+ */
+#define WM8962_FLL_N_MASK                       0x03FF  /* FLL_N - [9:0] */
+#define WM8962_FLL_N_SHIFT                           0  /* FLL_N - [9:0] */
+#define WM8962_FLL_N_WIDTH                          10  /* FLL_N - [9:0] */
+
+/*
+ * R252 (0xFC) - General test 1
+ */
+#define WM8962_REG_SYNC                         0x0004  /* REG_SYNC */
+#define WM8962_REG_SYNC_MASK                    0x0004  /* REG_SYNC */
+#define WM8962_REG_SYNC_SHIFT                        2  /* REG_SYNC */
+#define WM8962_REG_SYNC_WIDTH                        1  /* REG_SYNC */
+#define WM8962_AUTO_INC                         0x0001  /* AUTO_INC */
+#define WM8962_AUTO_INC_MASK                    0x0001  /* AUTO_INC */
+#define WM8962_AUTO_INC_SHIFT                        0  /* AUTO_INC */
+#define WM8962_AUTO_INC_WIDTH                        1  /* AUTO_INC */
+
+/*
+ * R256 (0x100) - DF1
+ */
+#define WM8962_DRC_DF1_ENA                      0x0008  /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_MASK                 0x0008  /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_SHIFT                     3  /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_WIDTH                     1  /* DRC_DF1_ENA */
+#define WM8962_DF1_SHARED_COEFF                 0x0004  /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_MASK            0x0004  /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_SHIFT                2  /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_WIDTH                1  /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_SEL             0x0002  /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_MASK        0x0002  /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_SHIFT            1  /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_WIDTH            1  /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_ENA                          0x0001  /* DF1_ENA */
+#define WM8962_DF1_ENA_MASK                     0x0001  /* DF1_ENA */
+#define WM8962_DF1_ENA_SHIFT                         0  /* DF1_ENA */
+#define WM8962_DF1_ENA_WIDTH                         1  /* DF1_ENA */
+
+/*
+ * R257 (0x101) - DF2
+ */
+#define WM8962_DF1_COEFF_L0_MASK                0xFFFF  /* DF1_COEFF_L0 - [15:0] */
+#define WM8962_DF1_COEFF_L0_SHIFT                    0  /* DF1_COEFF_L0 - [15:0] */
+#define WM8962_DF1_COEFF_L0_WIDTH                   16  /* DF1_COEFF_L0 - [15:0] */
+
+/*
+ * R258 (0x102) - DF3
+ */
+#define WM8962_DF1_COEFF_L1_MASK                0xFFFF  /* DF1_COEFF_L1 - [15:0] */
+#define WM8962_DF1_COEFF_L1_SHIFT                    0  /* DF1_COEFF_L1 - [15:0] */
+#define WM8962_DF1_COEFF_L1_WIDTH                   16  /* DF1_COEFF_L1 - [15:0] */
+
+/*
+ * R259 (0x103) - DF4
+ */
+#define WM8962_DF1_COEFF_L2_MASK                0xFFFF  /* DF1_COEFF_L2 - [15:0] */
+#define WM8962_DF1_COEFF_L2_SHIFT                    0  /* DF1_COEFF_L2 - [15:0] */
+#define WM8962_DF1_COEFF_L2_WIDTH                   16  /* DF1_COEFF_L2 - [15:0] */
+
+/*
+ * R260 (0x104) - DF5
+ */
+#define WM8962_DF1_COEFF_R0_MASK                0xFFFF  /* DF1_COEFF_R0 - [15:0] */
+#define WM8962_DF1_COEFF_R0_SHIFT                    0  /* DF1_COEFF_R0 - [15:0] */
+#define WM8962_DF1_COEFF_R0_WIDTH                   16  /* DF1_COEFF_R0 - [15:0] */
+
+/*
+ * R261 (0x105) - DF6
+ */
+#define WM8962_DF1_COEFF_R1_MASK                0xFFFF  /* DF1_COEFF_R1 - [15:0] */
+#define WM8962_DF1_COEFF_R1_SHIFT                    0  /* DF1_COEFF_R1 - [15:0] */
+#define WM8962_DF1_COEFF_R1_WIDTH                   16  /* DF1_COEFF_R1 - [15:0] */
+
+/*
+ * R262 (0x106) - DF7
+ */
+#define WM8962_DF1_COEFF_R2_MASK                0xFFFF  /* DF1_COEFF_R2 - [15:0] */
+#define WM8962_DF1_COEFF_R2_SHIFT                    0  /* DF1_COEFF_R2 - [15:0] */
+#define WM8962_DF1_COEFF_R2_WIDTH                   16  /* DF1_COEFF_R2 - [15:0] */
+
+/*
+ * R264 (0x108) - LHPF1
+ */
+#define WM8962_LHPF_MODE                        0x0002  /* LHPF_MODE */
+#define WM8962_LHPF_MODE_MASK                   0x0002  /* LHPF_MODE */
+#define WM8962_LHPF_MODE_SHIFT                       1  /* LHPF_MODE */
+#define WM8962_LHPF_MODE_WIDTH                       1  /* LHPF_MODE */
+#define WM8962_LHPF_ENA                         0x0001  /* LHPF_ENA */
+#define WM8962_LHPF_ENA_MASK                    0x0001  /* LHPF_ENA */
+#define WM8962_LHPF_ENA_SHIFT                        0  /* LHPF_ENA */
+#define WM8962_LHPF_ENA_WIDTH                        1  /* LHPF_ENA */
+
+/*
+ * R265 (0x109) - LHPF2
+ */
+#define WM8962_LHPF_COEFF_MASK                  0xFFFF  /* LHPF_COEFF - [15:0] */
+#define WM8962_LHPF_COEFF_SHIFT                      0  /* LHPF_COEFF - [15:0] */
+#define WM8962_LHPF_COEFF_WIDTH                     16  /* LHPF_COEFF - [15:0] */
+
+/*
+ * R268 (0x10C) - THREED1
+ */
+#define WM8962_ADC_MONOMIX                      0x0040  /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_MASK                 0x0040  /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_SHIFT                     6  /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_WIDTH                     1  /* ADC_MONOMIX */
+#define WM8962_THREED_SIGN_L                    0x0020  /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_MASK               0x0020  /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_SHIFT                   5  /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_WIDTH                   1  /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_R                    0x0010  /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_MASK               0x0010  /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_SHIFT                   4  /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_WIDTH                   1  /* THREED_SIGN_R */
+#define WM8962_THREED_LHPF_MODE                 0x0004  /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_MASK            0x0004  /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_SHIFT                2  /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_WIDTH                1  /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_ENA                  0x0002  /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_MASK             0x0002  /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_SHIFT                 1  /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_WIDTH                 1  /* THREED_LHPF_ENA */
+#define WM8962_THREED_ENA                       0x0001  /* THREED_ENA */
+#define WM8962_THREED_ENA_MASK                  0x0001  /* THREED_ENA */
+#define WM8962_THREED_ENA_SHIFT                      0  /* THREED_ENA */
+#define WM8962_THREED_ENA_WIDTH                      1  /* THREED_ENA */
+
+/*
+ * R269 (0x10D) - THREED2
+ */
+#define WM8962_THREED_FGAINL_MASK               0xF800  /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_FGAINL_SHIFT                  11  /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_FGAINL_WIDTH                   5  /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_CGAINL_MASK               0x07C0  /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_CGAINL_SHIFT                   6  /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_CGAINL_WIDTH                   5  /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_DELAYL_MASK               0x003C  /* THREED_DELAYL - [5:2] */
+#define WM8962_THREED_DELAYL_SHIFT                   2  /* THREED_DELAYL - [5:2] */
+#define WM8962_THREED_DELAYL_WIDTH                   4  /* THREED_DELAYL - [5:2] */
+
+/*
+ * R270 (0x10E) - THREED3
+ */
+#define WM8962_THREED_LHPF_COEFF_MASK           0xFFFF  /* THREED_LHPF_COEFF - [15:0] */
+#define WM8962_THREED_LHPF_COEFF_SHIFT               0  /* THREED_LHPF_COEFF - [15:0] */
+#define WM8962_THREED_LHPF_COEFF_WIDTH              16  /* THREED_LHPF_COEFF - [15:0] */
+
+/*
+ * R271 (0x10F) - THREED4
+ */
+#define WM8962_THREED_FGAINR_MASK               0xF800  /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_FGAINR_SHIFT                  11  /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_FGAINR_WIDTH                   5  /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_CGAINR_MASK               0x07C0  /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_CGAINR_SHIFT                   6  /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_CGAINR_WIDTH                   5  /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_DELAYR_MASK               0x003C  /* THREED_DELAYR - [5:2] */
+#define WM8962_THREED_DELAYR_SHIFT                   2  /* THREED_DELAYR - [5:2] */
+#define WM8962_THREED_DELAYR_WIDTH                   4  /* THREED_DELAYR - [5:2] */
+
+/*
+ * R276 (0x114) - DRC 1
+ */
+#define WM8962_DRC_SIG_DET_RMS_MASK             0x7C00  /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_RMS_SHIFT                10  /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_RMS_WIDTH                 5  /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_PK_MASK              0x0300  /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_SIG_DET_PK_SHIFT                  8  /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_SIG_DET_PK_WIDTH                  2  /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_NG_ENA                       0x0080  /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_MASK                  0x0080  /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_SHIFT                      7  /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_WIDTH                      1  /* DRC_NG_ENA */
+#define WM8962_DRC_SIG_DET_MODE                 0x0040  /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_MASK            0x0040  /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_SHIFT                6  /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_WIDTH                1  /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET                      0x0020  /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_MASK                 0x0020  /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_SHIFT                     5  /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_WIDTH                     1  /* DRC_SIG_DET */
+#define WM8962_DRC_KNEE2_OP_ENA                 0x0010  /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_MASK            0x0010  /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_SHIFT                4  /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_WIDTH                1  /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_QR                           0x0008  /* DRC_QR */
+#define WM8962_DRC_QR_MASK                      0x0008  /* DRC_QR */
+#define WM8962_DRC_QR_SHIFT                          3  /* DRC_QR */
+#define WM8962_DRC_QR_WIDTH                          1  /* DRC_QR */
+#define WM8962_DRC_ANTICLIP                     0x0004  /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_MASK                0x0004  /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_SHIFT                    2  /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_WIDTH                    1  /* DRC_ANTICLIP */
+#define WM8962_DRC_MODE                         0x0002  /* DRC_MODE */
+#define WM8962_DRC_MODE_MASK                    0x0002  /* DRC_MODE */
+#define WM8962_DRC_MODE_SHIFT                        1  /* DRC_MODE */
+#define WM8962_DRC_MODE_WIDTH                        1  /* DRC_MODE */
+#define WM8962_DRC_ENA                          0x0001  /* DRC_ENA */
+#define WM8962_DRC_ENA_MASK                     0x0001  /* DRC_ENA */
+#define WM8962_DRC_ENA_SHIFT                         0  /* DRC_ENA */
+#define WM8962_DRC_ENA_WIDTH                         1  /* DRC_ENA */
+
+/*
+ * R277 (0x115) - DRC 2
+ */
+#define WM8962_DRC_ATK_MASK                     0x1E00  /* DRC_ATK - [12:9] */
+#define WM8962_DRC_ATK_SHIFT                         9  /* DRC_ATK - [12:9] */
+#define WM8962_DRC_ATK_WIDTH                         4  /* DRC_ATK - [12:9] */
+#define WM8962_DRC_DCY_MASK                     0x01E0  /* DRC_DCY - [8:5] */
+#define WM8962_DRC_DCY_SHIFT                         5  /* DRC_DCY - [8:5] */
+#define WM8962_DRC_DCY_WIDTH                         4  /* DRC_DCY - [8:5] */
+#define WM8962_DRC_MINGAIN_MASK                 0x001C  /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MINGAIN_SHIFT                     2  /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MINGAIN_WIDTH                     3  /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MAXGAIN_MASK                 0x0003  /* DRC_MAXGAIN - [1:0] */
+#define WM8962_DRC_MAXGAIN_SHIFT                     0  /* DRC_MAXGAIN - [1:0] */
+#define WM8962_DRC_MAXGAIN_WIDTH                     2  /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R278 (0x116) - DRC 3
+ */
+#define WM8962_DRC_NG_MINGAIN_MASK              0xF000  /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_NG_MINGAIN_SHIFT                 12  /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_NG_MINGAIN_WIDTH                  4  /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_QR_THR_MASK                  0x0C00  /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_THR_SHIFT                     10  /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_THR_WIDTH                      2  /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_DCY_MASK                  0x0300  /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_QR_DCY_SHIFT                      8  /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_QR_DCY_WIDTH                      2  /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_NG_EXP_MASK                  0x00C0  /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_NG_EXP_SHIFT                      6  /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_NG_EXP_WIDTH                      2  /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_HI_COMP_MASK                 0x0038  /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_HI_COMP_SHIFT                     3  /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_HI_COMP_WIDTH                     3  /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_LO_COMP_MASK                 0x0007  /* DRC_LO_COMP - [2:0] */
+#define WM8962_DRC_LO_COMP_SHIFT                     0  /* DRC_LO_COMP - [2:0] */
+#define WM8962_DRC_LO_COMP_WIDTH                     3  /* DRC_LO_COMP - [2:0] */
+
+/*
+ * R279 (0x117) - DRC 4
+ */
+#define WM8962_DRC_KNEE_IP_MASK                 0x07E0  /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_IP_SHIFT                     5  /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_IP_WIDTH                     6  /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_OP_MASK                 0x001F  /* DRC_KNEE_OP - [4:0] */
+#define WM8962_DRC_KNEE_OP_SHIFT                     0  /* DRC_KNEE_OP - [4:0] */
+#define WM8962_DRC_KNEE_OP_WIDTH                     5  /* DRC_KNEE_OP - [4:0] */
+
+/*
+ * R280 (0x118) - DRC 5
+ */
+#define WM8962_DRC_KNEE2_IP_MASK                0x03E0  /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_IP_SHIFT                    5  /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_IP_WIDTH                    5  /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_OP_MASK                0x001F  /* DRC_KNEE2_OP - [4:0] */
+#define WM8962_DRC_KNEE2_OP_SHIFT                    0  /* DRC_KNEE2_OP - [4:0] */
+#define WM8962_DRC_KNEE2_OP_WIDTH                    5  /* DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R285 (0x11D) - Tloopback
+ */
+#define WM8962_TLB_ENA                          0x0002  /* TLB_ENA */
+#define WM8962_TLB_ENA_MASK                     0x0002  /* TLB_ENA */
+#define WM8962_TLB_ENA_SHIFT                         1  /* TLB_ENA */
+#define WM8962_TLB_ENA_WIDTH                         1  /* TLB_ENA */
+#define WM8962_TLB_MODE                         0x0001  /* TLB_MODE */
+#define WM8962_TLB_MODE_MASK                    0x0001  /* TLB_MODE */
+#define WM8962_TLB_MODE_SHIFT                        0  /* TLB_MODE */
+#define WM8962_TLB_MODE_WIDTH                        1  /* TLB_MODE */
+
+/*
+ * R335 (0x14F) - EQ1
+ */
+#define WM8962_EQ_SHARED_COEFF                  0x0004  /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_MASK             0x0004  /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_SHIFT                 2  /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_WIDTH                 1  /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_SEL              0x0002  /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_MASK         0x0002  /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_SHIFT             1  /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_WIDTH             1  /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_ENA                           0x0001  /* EQ_ENA */
+#define WM8962_EQ_ENA_MASK                      0x0001  /* EQ_ENA */
+#define WM8962_EQ_ENA_SHIFT                          0  /* EQ_ENA */
+#define WM8962_EQ_ENA_WIDTH                          1  /* EQ_ENA */
+
+/*
+ * R336 (0x150) - EQ2
+ */
+#define WM8962_EQL_B1_GAIN_MASK                 0xF800  /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B1_GAIN_SHIFT                    11  /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B1_GAIN_WIDTH                     5  /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B2_GAIN_MASK                 0x07C0  /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B2_GAIN_SHIFT                     6  /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B2_GAIN_WIDTH                     5  /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B3_GAIN_MASK                 0x003E  /* EQL_B3_GAIN - [5:1] */
+#define WM8962_EQL_B3_GAIN_SHIFT                     1  /* EQL_B3_GAIN - [5:1] */
+#define WM8962_EQL_B3_GAIN_WIDTH                     5  /* EQL_B3_GAIN - [5:1] */
+
+/*
+ * R337 (0x151) - EQ3
+ */
+#define WM8962_EQL_B4_GAIN_MASK                 0xF800  /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B4_GAIN_SHIFT                    11  /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B4_GAIN_WIDTH                     5  /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B5_GAIN_MASK                 0x07C0  /* EQL_B5_GAIN - [10:6] */
+#define WM8962_EQL_B5_GAIN_SHIFT                     6  /* EQL_B5_GAIN - [10:6] */
+#define WM8962_EQL_B5_GAIN_WIDTH                     5  /* EQL_B5_GAIN - [10:6] */
+
+/*
+ * R338 (0x152) - EQ4
+ */
+#define WM8962_EQL_B1_A_MASK                    0xFFFF  /* EQL_B1_A - [15:0] */
+#define WM8962_EQL_B1_A_SHIFT                        0  /* EQL_B1_A - [15:0] */
+#define WM8962_EQL_B1_A_WIDTH                       16  /* EQL_B1_A - [15:0] */
+
+/*
+ * R339 (0x153) - EQ5
+ */
+#define WM8962_EQL_B1_B_MASK                    0xFFFF  /* EQL_B1_B - [15:0] */
+#define WM8962_EQL_B1_B_SHIFT                        0  /* EQL_B1_B - [15:0] */
+#define WM8962_EQL_B1_B_WIDTH                       16  /* EQL_B1_B - [15:0] */
+
+/*
+ * R340 (0x154) - EQ6
+ */
+#define WM8962_EQL_B1_PG_MASK                   0xFFFF  /* EQL_B1_PG - [15:0] */
+#define WM8962_EQL_B1_PG_SHIFT                       0  /* EQL_B1_PG - [15:0] */
+#define WM8962_EQL_B1_PG_WIDTH                      16  /* EQL_B1_PG - [15:0] */
+
+/*
+ * R341 (0x155) - EQ7
+ */
+#define WM8962_EQL_B2_A_MASK                    0xFFFF  /* EQL_B2_A - [15:0] */
+#define WM8962_EQL_B2_A_SHIFT                        0  /* EQL_B2_A - [15:0] */
+#define WM8962_EQL_B2_A_WIDTH                       16  /* EQL_B2_A - [15:0] */
+
+/*
+ * R342 (0x156) - EQ8
+ */
+#define WM8962_EQL_B2_B_MASK                    0xFFFF  /* EQL_B2_B - [15:0] */
+#define WM8962_EQL_B2_B_SHIFT                        0  /* EQL_B2_B - [15:0] */
+#define WM8962_EQL_B2_B_WIDTH                       16  /* EQL_B2_B - [15:0] */
+
+/*
+ * R343 (0x157) - EQ9
+ */
+#define WM8962_EQL_B2_C_MASK                    0xFFFF  /* EQL_B2_C - [15:0] */
+#define WM8962_EQL_B2_C_SHIFT                        0  /* EQL_B2_C - [15:0] */
+#define WM8962_EQL_B2_C_WIDTH                       16  /* EQL_B2_C - [15:0] */
+
+/*
+ * R344 (0x158) - EQ10
+ */
+#define WM8962_EQL_B2_PG_MASK                   0xFFFF  /* EQL_B2_PG - [15:0] */
+#define WM8962_EQL_B2_PG_SHIFT                       0  /* EQL_B2_PG - [15:0] */
+#define WM8962_EQL_B2_PG_WIDTH                      16  /* EQL_B2_PG - [15:0] */
+
+/*
+ * R345 (0x159) - EQ11
+ */
+#define WM8962_EQL_B3_A_MASK                    0xFFFF  /* EQL_B3_A - [15:0] */
+#define WM8962_EQL_B3_A_SHIFT                        0  /* EQL_B3_A - [15:0] */
+#define WM8962_EQL_B3_A_WIDTH                       16  /* EQL_B3_A - [15:0] */
+
+/*
+ * R346 (0x15A) - EQ12
+ */
+#define WM8962_EQL_B3_B_MASK                    0xFFFF  /* EQL_B3_B - [15:0] */
+#define WM8962_EQL_B3_B_SHIFT                        0  /* EQL_B3_B - [15:0] */
+#define WM8962_EQL_B3_B_WIDTH                       16  /* EQL_B3_B - [15:0] */
+
+/*
+ * R347 (0x15B) - EQ13
+ */
+#define WM8962_EQL_B3_C_MASK                    0xFFFF  /* EQL_B3_C - [15:0] */
+#define WM8962_EQL_B3_C_SHIFT                        0  /* EQL_B3_C - [15:0] */
+#define WM8962_EQL_B3_C_WIDTH                       16  /* EQL_B3_C - [15:0] */
+
+/*
+ * R348 (0x15C) - EQ14
+ */
+#define WM8962_EQL_B3_PG_MASK                   0xFFFF  /* EQL_B3_PG - [15:0] */
+#define WM8962_EQL_B3_PG_SHIFT                       0  /* EQL_B3_PG - [15:0] */
+#define WM8962_EQL_B3_PG_WIDTH                      16  /* EQL_B3_PG - [15:0] */
+
+/*
+ * R349 (0x15D) - EQ15
+ */
+#define WM8962_EQL_B4_A_MASK                    0xFFFF  /* EQL_B4_A - [15:0] */
+#define WM8962_EQL_B4_A_SHIFT                        0  /* EQL_B4_A - [15:0] */
+#define WM8962_EQL_B4_A_WIDTH                       16  /* EQL_B4_A - [15:0] */
+
+/*
+ * R350 (0x15E) - EQ16
+ */
+#define WM8962_EQL_B4_B_MASK                    0xFFFF  /* EQL_B4_B - [15:0] */
+#define WM8962_EQL_B4_B_SHIFT                        0  /* EQL_B4_B - [15:0] */
+#define WM8962_EQL_B4_B_WIDTH                       16  /* EQL_B4_B - [15:0] */
+
+/*
+ * R351 (0x15F) - EQ17
+ */
+#define WM8962_EQL_B4_C_MASK                    0xFFFF  /* EQL_B4_C - [15:0] */
+#define WM8962_EQL_B4_C_SHIFT                        0  /* EQL_B4_C - [15:0] */
+#define WM8962_EQL_B4_C_WIDTH                       16  /* EQL_B4_C - [15:0] */
+
+/*
+ * R352 (0x160) - EQ18
+ */
+#define WM8962_EQL_B4_PG_MASK                   0xFFFF  /* EQL_B4_PG - [15:0] */
+#define WM8962_EQL_B4_PG_SHIFT                       0  /* EQL_B4_PG - [15:0] */
+#define WM8962_EQL_B4_PG_WIDTH                      16  /* EQL_B4_PG - [15:0] */
+
+/*
+ * R353 (0x161) - EQ19
+ */
+#define WM8962_EQL_B5_A_MASK                    0xFFFF  /* EQL_B5_A - [15:0] */
+#define WM8962_EQL_B5_A_SHIFT                        0  /* EQL_B5_A - [15:0] */
+#define WM8962_EQL_B5_A_WIDTH                       16  /* EQL_B5_A - [15:0] */
+
+/*
+ * R354 (0x162) - EQ20
+ */
+#define WM8962_EQL_B5_B_MASK                    0xFFFF  /* EQL_B5_B - [15:0] */
+#define WM8962_EQL_B5_B_SHIFT                        0  /* EQL_B5_B - [15:0] */
+#define WM8962_EQL_B5_B_WIDTH                       16  /* EQL_B5_B - [15:0] */
+
+/*
+ * R355 (0x163) - EQ21
+ */
+#define WM8962_EQL_B5_PG_MASK                   0xFFFF  /* EQL_B5_PG - [15:0] */
+#define WM8962_EQL_B5_PG_SHIFT                       0  /* EQL_B5_PG - [15:0] */
+#define WM8962_EQL_B5_PG_WIDTH                      16  /* EQL_B5_PG - [15:0] */
+
+/*
+ * R356 (0x164) - EQ22
+ */
+#define WM8962_EQR_B1_GAIN_MASK                 0xF800  /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B1_GAIN_SHIFT                    11  /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B1_GAIN_WIDTH                     5  /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B2_GAIN_MASK                 0x07C0  /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B2_GAIN_SHIFT                     6  /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B2_GAIN_WIDTH                     5  /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B3_GAIN_MASK                 0x003E  /* EQR_B3_GAIN - [5:1] */
+#define WM8962_EQR_B3_GAIN_SHIFT                     1  /* EQR_B3_GAIN - [5:1] */
+#define WM8962_EQR_B3_GAIN_WIDTH                     5  /* EQR_B3_GAIN - [5:1] */
+
+/*
+ * R357 (0x165) - EQ23
+ */
+#define WM8962_EQR_B4_GAIN_MASK                 0xF800  /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B4_GAIN_SHIFT                    11  /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B4_GAIN_WIDTH                     5  /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B5_GAIN_MASK                 0x07C0  /* EQR_B5_GAIN - [10:6] */
+#define WM8962_EQR_B5_GAIN_SHIFT                     6  /* EQR_B5_GAIN - [10:6] */
+#define WM8962_EQR_B5_GAIN_WIDTH                     5  /* EQR_B5_GAIN - [10:6] */
+
+/*
+ * R358 (0x166) - EQ24
+ */
+#define WM8962_EQR_B1_A_MASK                    0xFFFF  /* EQR_B1_A - [15:0] */
+#define WM8962_EQR_B1_A_SHIFT                        0  /* EQR_B1_A - [15:0] */
+#define WM8962_EQR_B1_A_WIDTH                       16  /* EQR_B1_A - [15:0] */
+
+/*
+ * R359 (0x167) - EQ25
+ */
+#define WM8962_EQR_B1_B_MASK                    0xFFFF  /* EQR_B1_B - [15:0] */
+#define WM8962_EQR_B1_B_SHIFT                        0  /* EQR_B1_B - [15:0] */
+#define WM8962_EQR_B1_B_WIDTH                       16  /* EQR_B1_B - [15:0] */
+
+/*
+ * R360 (0x168) - EQ26
+ */
+#define WM8962_EQR_B1_PG_MASK                   0xFFFF  /* EQR_B1_PG - [15:0] */
+#define WM8962_EQR_B1_PG_SHIFT                       0  /* EQR_B1_PG - [15:0] */
+#define WM8962_EQR_B1_PG_WIDTH                      16  /* EQR_B1_PG - [15:0] */
+
+/*
+ * R361 (0x169) - EQ27
+ */
+#define WM8962_EQR_B2_A_MASK                    0xFFFF  /* EQR_B2_A - [15:0] */
+#define WM8962_EQR_B2_A_SHIFT                        0  /* EQR_B2_A - [15:0] */
+#define WM8962_EQR_B2_A_WIDTH                       16  /* EQR_B2_A - [15:0] */
+
+/*
+ * R362 (0x16A) - EQ28
+ */
+#define WM8962_EQR_B2_B_MASK                    0xFFFF  /* EQR_B2_B - [15:0] */
+#define WM8962_EQR_B2_B_SHIFT                        0  /* EQR_B2_B - [15:0] */
+#define WM8962_EQR_B2_B_WIDTH                       16  /* EQR_B2_B - [15:0] */
+
+/*
+ * R363 (0x16B) - EQ29
+ */
+#define WM8962_EQR_B2_C_MASK                    0xFFFF  /* EQR_B2_C - [15:0] */
+#define WM8962_EQR_B2_C_SHIFT                        0  /* EQR_B2_C - [15:0] */
+#define WM8962_EQR_B2_C_WIDTH                       16  /* EQR_B2_C - [15:0] */
+
+/*
+ * R364 (0x16C) - EQ30
+ */
+#define WM8962_EQR_B2_PG_MASK                   0xFFFF  /* EQR_B2_PG - [15:0] */
+#define WM8962_EQR_B2_PG_SHIFT                       0  /* EQR_B2_PG - [15:0] */
+#define WM8962_EQR_B2_PG_WIDTH                      16  /* EQR_B2_PG - [15:0] */
+
+/*
+ * R365 (0x16D) - EQ31
+ */
+#define WM8962_EQR_B3_A_MASK                    0xFFFF  /* EQR_B3_A - [15:0] */
+#define WM8962_EQR_B3_A_SHIFT                        0  /* EQR_B3_A - [15:0] */
+#define WM8962_EQR_B3_A_WIDTH                       16  /* EQR_B3_A - [15:0] */
+
+/*
+ * R366 (0x16E) - EQ32
+ */
+#define WM8962_EQR_B3_B_MASK                    0xFFFF  /* EQR_B3_B - [15:0] */
+#define WM8962_EQR_B3_B_SHIFT                        0  /* EQR_B3_B - [15:0] */
+#define WM8962_EQR_B3_B_WIDTH                       16  /* EQR_B3_B - [15:0] */
+
+/*
+ * R367 (0x16F) - EQ33
+ */
+#define WM8962_EQR_B3_C_MASK                    0xFFFF  /* EQR_B3_C - [15:0] */
+#define WM8962_EQR_B3_C_SHIFT                        0  /* EQR_B3_C - [15:0] */
+#define WM8962_EQR_B3_C_WIDTH                       16  /* EQR_B3_C - [15:0] */
+
+/*
+ * R368 (0x170) - EQ34
+ */
+#define WM8962_EQR_B3_PG_MASK                   0xFFFF  /* EQR_B3_PG - [15:0] */
+#define WM8962_EQR_B3_PG_SHIFT                       0  /* EQR_B3_PG - [15:0] */
+#define WM8962_EQR_B3_PG_WIDTH                      16  /* EQR_B3_PG - [15:0] */
+
+/*
+ * R369 (0x171) - EQ35
+ */
+#define WM8962_EQR_B4_A_MASK                    0xFFFF  /* EQR_B4_A - [15:0] */
+#define WM8962_EQR_B4_A_SHIFT                        0  /* EQR_B4_A - [15:0] */
+#define WM8962_EQR_B4_A_WIDTH                       16  /* EQR_B4_A - [15:0] */
+
+/*
+ * R370 (0x172) - EQ36
+ */
+#define WM8962_EQR_B4_B_MASK                    0xFFFF  /* EQR_B4_B - [15:0] */
+#define WM8962_EQR_B4_B_SHIFT                        0  /* EQR_B4_B - [15:0] */
+#define WM8962_EQR_B4_B_WIDTH                       16  /* EQR_B4_B - [15:0] */
+
+/*
+ * R371 (0x173) - EQ37
+ */
+#define WM8962_EQR_B4_C_MASK                    0xFFFF  /* EQR_B4_C - [15:0] */
+#define WM8962_EQR_B4_C_SHIFT                        0  /* EQR_B4_C - [15:0] */
+#define WM8962_EQR_B4_C_WIDTH                       16  /* EQR_B4_C - [15:0] */
+
+/*
+ * R372 (0x174) - EQ38
+ */
+#define WM8962_EQR_B4_PG_MASK                   0xFFFF  /* EQR_B4_PG - [15:0] */
+#define WM8962_EQR_B4_PG_SHIFT                       0  /* EQR_B4_PG - [15:0] */
+#define WM8962_EQR_B4_PG_WIDTH                      16  /* EQR_B4_PG - [15:0] */
+
+/*
+ * R373 (0x175) - EQ39
+ */
+#define WM8962_EQR_B5_A_MASK                    0xFFFF  /* EQR_B5_A - [15:0] */
+#define WM8962_EQR_B5_A_SHIFT                        0  /* EQR_B5_A - [15:0] */
+#define WM8962_EQR_B5_A_WIDTH                       16  /* EQR_B5_A - [15:0] */
+
+/*
+ * R374 (0x176) - EQ40
+ */
+#define WM8962_EQR_B5_B_MASK                    0xFFFF  /* EQR_B5_B - [15:0] */
+#define WM8962_EQR_B5_B_SHIFT                        0  /* EQR_B5_B - [15:0] */
+#define WM8962_EQR_B5_B_WIDTH                       16  /* EQR_B5_B - [15:0] */
+
+/*
+ * R375 (0x177) - EQ41
+ */
+#define WM8962_EQR_B5_PG_MASK                   0xFFFF  /* EQR_B5_PG - [15:0] */
+#define WM8962_EQR_B5_PG_SHIFT                       0  /* EQR_B5_PG - [15:0] */
+#define WM8962_EQR_B5_PG_WIDTH                      16  /* EQR_B5_PG - [15:0] */
+
+/*
+ * R513 (0x201) - GPIO 2
+ */
+#define WM8962_GP2_POL                          0x0400  /* GP2_POL */
+#define WM8962_GP2_POL_MASK                     0x0400  /* GP2_POL */
+#define WM8962_GP2_POL_SHIFT                        10  /* GP2_POL */
+#define WM8962_GP2_POL_WIDTH                         1  /* GP2_POL */
+#define WM8962_GP2_LVL                          0x0040  /* GP2_LVL */
+#define WM8962_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
+#define WM8962_GP2_LVL_SHIFT                         6  /* GP2_LVL */
+#define WM8962_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM8962_GP2_FN_MASK                      0x001F  /* GP2_FN - [4:0] */
+#define WM8962_GP2_FN_SHIFT                          0  /* GP2_FN - [4:0] */
+#define WM8962_GP2_FN_WIDTH                          5  /* GP2_FN - [4:0] */
+
+/*
+ * R514 (0x202) - GPIO 3
+ */
+#define WM8962_GP3_POL                          0x0400  /* GP3_POL */
+#define WM8962_GP3_POL_MASK                     0x0400  /* GP3_POL */
+#define WM8962_GP3_POL_SHIFT                        10  /* GP3_POL */
+#define WM8962_GP3_POL_WIDTH                         1  /* GP3_POL */
+#define WM8962_GP3_LVL                          0x0040  /* GP3_LVL */
+#define WM8962_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
+#define WM8962_GP3_LVL_SHIFT                         6  /* GP3_LVL */
+#define WM8962_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM8962_GP3_FN_MASK                      0x001F  /* GP3_FN - [4:0] */
+#define WM8962_GP3_FN_SHIFT                          0  /* GP3_FN - [4:0] */
+#define WM8962_GP3_FN_WIDTH                          5  /* GP3_FN - [4:0] */
+
+/*
+ * R516 (0x204) - GPIO 5
+ */
+#define WM8962_GP5_DIR                          0x8000  /* GP5_DIR */
+#define WM8962_GP5_DIR_MASK                     0x8000  /* GP5_DIR */
+#define WM8962_GP5_DIR_SHIFT                        15  /* GP5_DIR */
+#define WM8962_GP5_DIR_WIDTH                         1  /* GP5_DIR */
+#define WM8962_GP5_PU                           0x4000  /* GP5_PU */
+#define WM8962_GP5_PU_MASK                      0x4000  /* GP5_PU */
+#define WM8962_GP5_PU_SHIFT                         14  /* GP5_PU */
+#define WM8962_GP5_PU_WIDTH                          1  /* GP5_PU */
+#define WM8962_GP5_PD                           0x2000  /* GP5_PD */
+#define WM8962_GP5_PD_MASK                      0x2000  /* GP5_PD */
+#define WM8962_GP5_PD_SHIFT                         13  /* GP5_PD */
+#define WM8962_GP5_PD_WIDTH                          1  /* GP5_PD */
+#define WM8962_GP5_POL                          0x0400  /* GP5_POL */
+#define WM8962_GP5_POL_MASK                     0x0400  /* GP5_POL */
+#define WM8962_GP5_POL_SHIFT                        10  /* GP5_POL */
+#define WM8962_GP5_POL_WIDTH                         1  /* GP5_POL */
+#define WM8962_GP5_OP_CFG                       0x0200  /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_MASK                  0x0200  /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_SHIFT                      9  /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
+#define WM8962_GP5_DB                           0x0100  /* GP5_DB */
+#define WM8962_GP5_DB_MASK                      0x0100  /* GP5_DB */
+#define WM8962_GP5_DB_SHIFT                          8  /* GP5_DB */
+#define WM8962_GP5_DB_WIDTH                          1  /* GP5_DB */
+#define WM8962_GP5_LVL                          0x0040  /* GP5_LVL */
+#define WM8962_GP5_LVL_MASK                     0x0040  /* GP5_LVL */
+#define WM8962_GP5_LVL_SHIFT                         6  /* GP5_LVL */
+#define WM8962_GP5_LVL_WIDTH                         1  /* GP5_LVL */
+#define WM8962_GP5_FN_MASK                      0x001F  /* GP5_FN - [4:0] */
+#define WM8962_GP5_FN_SHIFT                          0  /* GP5_FN - [4:0] */
+#define WM8962_GP5_FN_WIDTH                          5  /* GP5_FN - [4:0] */
+
+/*
+ * R517 (0x205) - GPIO 6
+ */
+#define WM8962_GP6_DIR                          0x8000  /* GP6_DIR */
+#define WM8962_GP6_DIR_MASK                     0x8000  /* GP6_DIR */
+#define WM8962_GP6_DIR_SHIFT                        15  /* GP6_DIR */
+#define WM8962_GP6_DIR_WIDTH                         1  /* GP6_DIR */
+#define WM8962_GP6_PU                           0x4000  /* GP6_PU */
+#define WM8962_GP6_PU_MASK                      0x4000  /* GP6_PU */
+#define WM8962_GP6_PU_SHIFT                         14  /* GP6_PU */
+#define WM8962_GP6_PU_WIDTH                          1  /* GP6_PU */
+#define WM8962_GP6_PD                           0x2000  /* GP6_PD */
+#define WM8962_GP6_PD_MASK                      0x2000  /* GP6_PD */
+#define WM8962_GP6_PD_SHIFT                         13  /* GP6_PD */
+#define WM8962_GP6_PD_WIDTH                          1  /* GP6_PD */
+#define WM8962_GP6_POL                          0x0400  /* GP6_POL */
+#define WM8962_GP6_POL_MASK                     0x0400  /* GP6_POL */
+#define WM8962_GP6_POL_SHIFT                        10  /* GP6_POL */
+#define WM8962_GP6_POL_WIDTH                         1  /* GP6_POL */
+#define WM8962_GP6_OP_CFG                       0x0200  /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_MASK                  0x0200  /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_SHIFT                      9  /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_WIDTH                      1  /* GP6_OP_CFG */
+#define WM8962_GP6_DB                           0x0100  /* GP6_DB */
+#define WM8962_GP6_DB_MASK                      0x0100  /* GP6_DB */
+#define WM8962_GP6_DB_SHIFT                          8  /* GP6_DB */
+#define WM8962_GP6_DB_WIDTH                          1  /* GP6_DB */
+#define WM8962_GP6_LVL                          0x0040  /* GP6_LVL */
+#define WM8962_GP6_LVL_MASK                     0x0040  /* GP6_LVL */
+#define WM8962_GP6_LVL_SHIFT                         6  /* GP6_LVL */
+#define WM8962_GP6_LVL_WIDTH                         1  /* GP6_LVL */
+#define WM8962_GP6_FN_MASK                      0x001F  /* GP6_FN - [4:0] */
+#define WM8962_GP6_FN_SHIFT                          0  /* GP6_FN - [4:0] */
+#define WM8962_GP6_FN_WIDTH                          5  /* GP6_FN - [4:0] */
+
+/*
+ * R560 (0x230) - Interrupt Status 1
+ */
+#define WM8962_GP6_EINT                         0x0020  /* GP6_EINT */
+#define WM8962_GP6_EINT_MASK                    0x0020  /* GP6_EINT */
+#define WM8962_GP6_EINT_SHIFT                        5  /* GP6_EINT */
+#define WM8962_GP6_EINT_WIDTH                        1  /* GP6_EINT */
+#define WM8962_GP5_EINT                         0x0010  /* GP5_EINT */
+#define WM8962_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
+#define WM8962_GP5_EINT_SHIFT                        4  /* GP5_EINT */
+#define WM8962_GP5_EINT_WIDTH                        1  /* GP5_EINT */
+
+/*
+ * R561 (0x231) - Interrupt Status 2
+ */
+#define WM8962_MICSCD_EINT                      0x8000  /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_MASK                 0x8000  /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_SHIFT                    15  /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_WIDTH                     1  /* MICSCD_EINT */
+#define WM8962_MICD_EINT                        0x4000  /* MICD_EINT */
+#define WM8962_MICD_EINT_MASK                   0x4000  /* MICD_EINT */
+#define WM8962_MICD_EINT_SHIFT                      14  /* MICD_EINT */
+#define WM8962_MICD_EINT_WIDTH                       1  /* MICD_EINT */
+#define WM8962_FIFOS_ERR_EINT                   0x2000  /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_MASK              0x2000  /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_SHIFT                 13  /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_WIDTH                  1  /* FIFOS_ERR_EINT */
+#define WM8962_ALC_LOCK_EINT                    0x1000  /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_MASK               0x1000  /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_SHIFT                  12  /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_WIDTH                   1  /* ALC_LOCK_EINT */
+#define WM8962_ALC_THRESH_EINT                  0x0800  /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_MASK             0x0800  /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_SHIFT                11  /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_WIDTH                 1  /* ALC_THRESH_EINT */
+#define WM8962_ALC_SAT_EINT                     0x0400  /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_MASK                0x0400  /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_SHIFT                   10  /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_WIDTH                    1  /* ALC_SAT_EINT */
+#define WM8962_ALC_PKOVR_EINT                   0x0200  /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_MASK              0x0200  /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_SHIFT                  9  /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_WIDTH                  1  /* ALC_PKOVR_EINT */
+#define WM8962_ALC_NGATE_EINT                   0x0100  /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_MASK              0x0100  /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_SHIFT                  8  /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_WIDTH                  1  /* ALC_NGATE_EINT */
+#define WM8962_WSEQ_DONE_EINT                   0x0080  /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_MASK              0x0080  /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_SHIFT                  7  /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_WIDTH                  1  /* WSEQ_DONE_EINT */
+#define WM8962_DRC_ACTDET_EINT                  0x0040  /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_MASK             0x0040  /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_SHIFT                 6  /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_WIDTH                 1  /* DRC_ACTDET_EINT */
+#define WM8962_FLL_LOCK_EINT                    0x0020  /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_MASK               0x0020  /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_SHIFT                   5  /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT                   0x0008  /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_MASK              0x0008  /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_SHIFT                  3  /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_WIDTH                  1  /* PLL3_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT                   0x0004  /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_MASK              0x0004  /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_SHIFT                  2  /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_WIDTH                  1  /* PLL2_LOCK_EINT */
+#define WM8962_TEMP_SHUT_EINT                   0x0001  /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_MASK              0x0001  /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_SHIFT                  0  /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_WIDTH                  1  /* TEMP_SHUT_EINT */
+
+/*
+ * R568 (0x238) - Interrupt Status 1 Mask
+ */
+#define WM8962_IM_GP6_EINT                      0x0020  /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_MASK                 0x0020  /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_SHIFT                     5  /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_WIDTH                     1  /* IM_GP6_EINT */
+#define WM8962_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
+
+/*
+ * R569 (0x239) - Interrupt Status 2 Mask
+ */
+#define WM8962_IM_MICSCD_EINT                   0x8000  /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_MASK              0x8000  /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_SHIFT                 15  /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_WIDTH                  1  /* IM_MICSCD_EINT */
+#define WM8962_IM_MICD_EINT                     0x4000  /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_MASK                0x4000  /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_SHIFT                   14  /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_WIDTH                    1  /* IM_MICD_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT                0x2000  /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_MASK           0x2000  /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_SHIFT              13  /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_WIDTH               1  /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_ALC_LOCK_EINT                 0x1000  /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_MASK            0x1000  /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_SHIFT               12  /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_WIDTH                1  /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_THRESH_EINT               0x0800  /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_MASK          0x0800  /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_SHIFT             11  /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_WIDTH              1  /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_SAT_EINT                  0x0400  /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_MASK             0x0400  /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_SHIFT                10  /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_WIDTH                 1  /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT                0x0200  /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_MASK           0x0200  /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_SHIFT               9  /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_WIDTH               1  /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_NGATE_EINT                0x0100  /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_MASK           0x0100  /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_SHIFT               8  /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_WIDTH               1  /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT                0x0080  /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_MASK           0x0080  /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_SHIFT               7  /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_WIDTH               1  /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT               0x0040  /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_MASK          0x0040  /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_SHIFT              6  /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_WIDTH              1  /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_FLL_LOCK_EINT                 0x0020  /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_MASK            0x0020  /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_SHIFT                5  /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT                0x0008  /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_MASK           0x0008  /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_SHIFT               3  /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_WIDTH               1  /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT                0x0004  /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_MASK           0x0004  /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_SHIFT               2  /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_WIDTH               1  /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT                0x0001  /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_MASK           0x0001  /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_SHIFT               0  /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_WIDTH               1  /* IM_TEMP_SHUT_EINT */
+
+/*
+ * R576 (0x240) - Interrupt Control
+ */
+#define WM8962_IRQ_POL                          0x0001  /* IRQ_POL */
+#define WM8962_IRQ_POL_MASK                     0x0001  /* IRQ_POL */
+#define WM8962_IRQ_POL_SHIFT                         0  /* IRQ_POL */
+#define WM8962_IRQ_POL_WIDTH                         1  /* IRQ_POL */
+
+/*
+ * R584 (0x248) - IRQ Debounce
+ */
+#define WM8962_FLL_LOCK_DB                      0x0020  /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_MASK                 0x0020  /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_SHIFT                     5  /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_WIDTH                     1  /* FLL_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB                     0x0008  /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_MASK                0x0008  /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_SHIFT                    3  /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_WIDTH                    1  /* PLL3_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB                     0x0004  /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_MASK                0x0004  /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_SHIFT                    2  /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_WIDTH                    1  /* PLL2_LOCK_DB */
+#define WM8962_TEMP_SHUT_DB                     0x0001  /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_MASK                0x0001  /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_SHIFT                    0  /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_WIDTH                    1  /* TEMP_SHUT_DB */
+
+/*
+ * R586 (0x24A) -  MICINT Source Pol
+ */
+#define WM8962_MICSCD_IRQ_POL                   0x8000  /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_MASK              0x8000  /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_SHIFT                 15  /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_WIDTH                  1  /* MICSCD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL                     0x4000  /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_MASK                0x4000  /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_SHIFT                   14  /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_WIDTH                    1  /* MICD_IRQ_POL */
+
+/*
+ * R768 (0x300) - DSP2 Power Management
+ */
+#define WM8962_DSP2_ENA                         0x0001  /* DSP2_ENA */
+#define WM8962_DSP2_ENA_MASK                    0x0001  /* DSP2_ENA */
+#define WM8962_DSP2_ENA_SHIFT                        0  /* DSP2_ENA */
+#define WM8962_DSP2_ENA_WIDTH                        1  /* DSP2_ENA */
+
+/*
+ * R1037 (0x40D) - DSP2_ExecControl
+ */
+#define WM8962_DSP2_STOPC                       0x0020  /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_MASK                  0x0020  /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_SHIFT                      5  /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_WIDTH                      1  /* DSP2_STOPC */
+#define WM8962_DSP2_STOPS                       0x0010  /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_MASK                  0x0010  /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_SHIFT                      4  /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_WIDTH                      1  /* DSP2_STOPS */
+#define WM8962_DSP2_STOPI                       0x0008  /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_MASK                  0x0008  /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_SHIFT                      3  /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_WIDTH                      1  /* DSP2_STOPI */
+#define WM8962_DSP2_STOP                        0x0004  /* DSP2_STOP */
+#define WM8962_DSP2_STOP_MASK                   0x0004  /* DSP2_STOP */
+#define WM8962_DSP2_STOP_SHIFT                       2  /* DSP2_STOP */
+#define WM8962_DSP2_STOP_WIDTH                       1  /* DSP2_STOP */
+#define WM8962_DSP2_RUNR                        0x0002  /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_MASK                   0x0002  /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_SHIFT                       1  /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_WIDTH                       1  /* DSP2_RUNR */
+#define WM8962_DSP2_RUN                         0x0001  /* DSP2_RUN */
+#define WM8962_DSP2_RUN_MASK                    0x0001  /* DSP2_RUN */
+#define WM8962_DSP2_RUN_SHIFT                        0  /* DSP2_RUN */
+#define WM8962_DSP2_RUN_WIDTH                        1  /* DSP2_RUN */
+
+/*
+ * R8192 (0x2000) - DSP2 Instruction RAM 0
+ */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_MASK  0x03FF  /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_SHIFT      0  /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_WIDTH     10  /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+
+/*
+ * R9216 (0x2400) - DSP2 Address RAM 2
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_MASK 0x003F  /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_SHIFT      0  /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_WIDTH      6  /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+
+/*
+ * R9217 (0x2401) - DSP2 Address RAM 1
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_MASK 0xFFFF  /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_SHIFT      0  /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_WIDTH     16  /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+
+/*
+ * R9218 (0x2402) - DSP2 Address RAM 0
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_MASK  0xFFFF  /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_SHIFT      0  /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_WIDTH     16  /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+
+/*
+ * R12288 (0x3000) - DSP2 Data1 RAM 1
+ */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_MASK 0x00FF  /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_SHIFT      0  /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_WIDTH      8  /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R12289 (0x3001) - DSP2 Data1 RAM 0
+ */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_MASK  0xFFFF  /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_SHIFT      0  /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_WIDTH     16  /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R13312 (0x3400) - DSP2 Data2 RAM 1
+ */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_MASK 0x00FF  /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_SHIFT      0  /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_WIDTH      8  /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R13313 (0x3401) - DSP2 Data2 RAM 0
+ */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_MASK  0xFFFF  /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_SHIFT      0  /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_WIDTH     16  /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R14336 (0x3800) - DSP2 Data3 RAM 1
+ */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_MASK 0x00FF  /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_SHIFT      0  /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_WIDTH      8  /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R14337 (0x3801) - DSP2 Data3 RAM 0
+ */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_MASK  0xFFFF  /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_SHIFT      0  /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_WIDTH     16  /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R15360 (0x3C00) - DSP2 Coeff RAM 0
+ */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_MASK   0x07FF  /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_SHIFT       0  /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_WIDTH      11  /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+
+/*
+ * R16384 (0x4000) - RETUNEADC_SHARED_COEFF_1
+ */
+#define WM8962_ADC_RETUNE_SCV                   0x0080  /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_MASK              0x0080  /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_SHIFT                  7  /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_WIDTH                  1  /* ADC_RETUNE_SCV */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_MASK 0x007F  /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_SHIFT      0  /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_WIDTH      7  /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+
+/*
+ * R16385 (0x4001) - RETUNEADC_SHARED_COEFF_0
+ */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_MASK 0xFFFF  /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_SHIFT      0  /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_WIDTH     16  /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+
+/*
+ * R16386 (0x4002) - RETUNEDAC_SHARED_COEFF_1
+ */
+#define WM8962_DAC_RETUNE_SCV                   0x0080  /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_MASK              0x0080  /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_SHIFT                  7  /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_WIDTH                  1  /* DAC_RETUNE_SCV */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_MASK 0x007F  /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_SHIFT      0  /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_WIDTH      7  /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+
+/*
+ * R16387 (0x4003) - RETUNEDAC_SHARED_COEFF_0
+ */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_MASK 0xFFFF  /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_SHIFT      0  /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_WIDTH     16  /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+
+/*
+ * R16388 (0x4004) - SOUNDSTAGE_ENABLES_1
+ */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_MASK    0x00FF  /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_SHIFT        0  /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_WIDTH        8  /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+
+/*
+ * R16389 (0x4005) - SOUNDSTAGE_ENABLES_0
+ */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_MASK    0xFFC0  /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_SHIFT        6  /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_WIDTH       10  /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_RTN_ADC_ENA                      0x0020  /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_MASK                 0x0020  /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_SHIFT                     5  /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_WIDTH                     1  /* RTN_ADC_ENA */
+#define WM8962_RTN_DAC_ENA                      0x0010  /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_MASK                 0x0010  /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_SHIFT                     4  /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_WIDTH                     1  /* RTN_DAC_ENA */
+#define WM8962_HDBASS_ENA                       0x0008  /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_MASK                  0x0008  /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_SHIFT                      3  /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_WIDTH                      1  /* HDBASS_ENA */
+#define WM8962_HPF2_ENA                         0x0004  /* HPF2_ENA */
+#define WM8962_HPF2_ENA_MASK                    0x0004  /* HPF2_ENA */
+#define WM8962_HPF2_ENA_SHIFT                        2  /* HPF2_ENA */
+#define WM8962_HPF2_ENA_WIDTH                        1  /* HPF2_ENA */
+#define WM8962_HPF1_ENA                         0x0002  /* HPF1_ENA */
+#define WM8962_HPF1_ENA_MASK                    0x0002  /* HPF1_ENA */
+#define WM8962_HPF1_ENA_SHIFT                        1  /* HPF1_ENA */
+#define WM8962_HPF1_ENA_WIDTH                        1  /* HPF1_ENA */
+#define WM8962_VSS_ENA                          0x0001  /* VSS_ENA */
+#define WM8962_VSS_ENA_MASK                     0x0001  /* VSS_ENA */
+#define WM8962_VSS_ENA_SHIFT                         0  /* VSS_ENA */
+#define WM8962_VSS_ENA_WIDTH                         1  /* VSS_ENA */
+
+int wm8962_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack);
+
+#endif
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
new file mode 100644
index 0000000..a79f7a7
--- /dev/null
+++ b/sound/soc/codecs/wm8971.c
@@ -0,0 +1,719 @@
+/*
+ * wm8971.c  --  WM8971 ALSA SoC Audio driver
+ *
+ * Copyright 2005 Lab126, Inc.
+ *
+ * Author: Kenneth Kiraly <kiraly@lab126.com>
+ *
+ * Based on wm8753.c by Liam Girdwood
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include "wm8971.h"
+
+#define	WM8971_REG_COUNT		43
+
+/* codec private data */
+struct wm8971_priv {
+	unsigned int sysclk;
+	struct delayed_work charge_work;
+	struct regmap *regmap;
+};
+
+/*
+ * wm8971 register cache
+ * We can't read the WM8971 register space when we
+ * are using 2 wire for device control, so we cache them instead.
+ */
+static const struct reg_default wm8971_reg_defaults[] = {
+	{  0, 0x0097 },
+	{  1, 0x0097 },
+	{  2, 0x0079 },
+	{  3, 0x0079 },
+	{  4, 0x0000 },
+	{  5, 0x0008 },
+	{  6, 0x0000 },
+	{  7, 0x000a },
+	{  8, 0x0000 },
+	{  9, 0x0000 },
+	{ 10, 0x00ff },
+	{ 11, 0x00ff },
+	{ 12, 0x000f },
+	{ 13, 0x000f },
+	{ 14, 0x0000 },
+	{ 15, 0x0000 },
+	{ 16, 0x0000 },
+	{ 17, 0x007b },
+	{ 18, 0x0000 },
+	{ 19, 0x0032 },
+	{ 20, 0x0000 },
+	{ 21, 0x00c3 },
+	{ 22, 0x00c3 },
+	{ 23, 0x00c0 },
+	{ 24, 0x0000 },
+	{ 25, 0x0000 },
+	{ 26, 0x0000 },
+	{ 27, 0x0000 },
+	{ 28, 0x0000 },
+	{ 29, 0x0000 },
+	{ 30, 0x0000 },
+	{ 31, 0x0000 },
+	{ 32, 0x0000 },
+	{ 33, 0x0000 },
+	{ 34, 0x0050 },
+	{ 35, 0x0050 },
+	{ 36, 0x0050 },
+	{ 37, 0x0050 },
+	{ 38, 0x0050 },
+	{ 39, 0x0050 },
+	{ 40, 0x0079 },
+	{ 41, 0x0079 },
+	{ 42, 0x0079 },
+};
+
+#define wm8971_reset(c)	snd_soc_component_write(c, WM8971_RESET, 0)
+
+/* WM8971 Controls */
+static const char *wm8971_bass[] = { "Linear Control", "Adaptive Boost" };
+static const char *wm8971_bass_filter[] = { "130Hz @ 48kHz",
+	"200Hz @ 48kHz" };
+static const char *wm8971_treble[] = { "8kHz", "4kHz" };
+static const char *wm8971_alc_func[] = { "Off", "Right", "Left", "Stereo" };
+static const char *wm8971_ng_type[] = { "Constant PGA Gain",
+	"Mute ADC Output" };
+static const char *wm8971_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
+static const char *wm8971_mono_mux[] = {"Stereo", "Mono (Left)",
+	"Mono (Right)", "Digital Mono"};
+static const char *wm8971_dac_phase[] = { "Non Inverted", "Inverted" };
+static const char *wm8971_lline_mux[] = {"Line", "NC", "NC", "PGA",
+	"Differential"};
+static const char *wm8971_rline_mux[] = {"Line", "Mic", "NC", "PGA",
+	"Differential"};
+static const char *wm8971_lpga_sel[] = {"Line", "NC", "NC", "Differential"};
+static const char *wm8971_rpga_sel[] = {"Line", "Mic", "NC", "Differential"};
+static const char *wm8971_adcpol[] = {"Normal", "L Invert", "R Invert",
+	"L + R Invert"};
+
+static const struct soc_enum wm8971_enum[] = {
+	SOC_ENUM_SINGLE(WM8971_BASS, 7, 2, wm8971_bass),	/* 0 */
+	SOC_ENUM_SINGLE(WM8971_BASS, 6, 2, wm8971_bass_filter),
+	SOC_ENUM_SINGLE(WM8971_TREBLE, 6, 2, wm8971_treble),
+	SOC_ENUM_SINGLE(WM8971_ALC1, 7, 4, wm8971_alc_func),
+	SOC_ENUM_SINGLE(WM8971_NGATE, 1, 2, wm8971_ng_type),    /* 4 */
+	SOC_ENUM_SINGLE(WM8971_ADCDAC, 1, 4, wm8971_deemp),
+	SOC_ENUM_SINGLE(WM8971_ADCTL1, 4, 4, wm8971_mono_mux),
+	SOC_ENUM_SINGLE(WM8971_ADCTL1, 1, 2, wm8971_dac_phase),
+	SOC_ENUM_SINGLE(WM8971_LOUTM1, 0, 5, wm8971_lline_mux), /* 8 */
+	SOC_ENUM_SINGLE(WM8971_ROUTM1, 0, 5, wm8971_rline_mux),
+	SOC_ENUM_SINGLE(WM8971_LADCIN, 6, 4, wm8971_lpga_sel),
+	SOC_ENUM_SINGLE(WM8971_RADCIN, 6, 4, wm8971_rpga_sel),
+	SOC_ENUM_SINGLE(WM8971_ADCDAC, 5, 4, wm8971_adcpol),    /* 12 */
+	SOC_ENUM_SINGLE(WM8971_ADCIN, 6, 4, wm8971_mono_mux),
+};
+
+static const struct snd_kcontrol_new wm8971_snd_controls[] = {
+	SOC_DOUBLE_R("Capture Volume", WM8971_LINVOL, WM8971_RINVOL, 0, 63, 0),
+	SOC_DOUBLE_R("Capture ZC Switch", WM8971_LINVOL, WM8971_RINVOL,
+		     6, 1, 0),
+	SOC_DOUBLE_R("Capture Switch", WM8971_LINVOL, WM8971_RINVOL, 7, 1, 1),
+
+	SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8971_LOUT1V,
+		WM8971_ROUT1V, 7, 1, 0),
+	SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8971_LOUT2V,
+		WM8971_ROUT2V, 7, 1, 0),
+	SOC_SINGLE("Mono Playback ZC Switch", WM8971_MOUTV, 7, 1, 0),
+
+	SOC_DOUBLE_R("PCM Volume", WM8971_LDAC, WM8971_RDAC, 0, 255, 0),
+
+	SOC_DOUBLE_R("Bypass Left Playback Volume", WM8971_LOUTM1,
+		WM8971_LOUTM2, 4, 7, 1),
+	SOC_DOUBLE_R("Bypass Right Playback Volume", WM8971_ROUTM1,
+		WM8971_ROUTM2, 4, 7, 1),
+	SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8971_MOUTM1,
+		WM8971_MOUTM2, 4, 7, 1),
+
+	SOC_DOUBLE_R("Headphone Playback Volume", WM8971_LOUT1V,
+		WM8971_ROUT1V, 0, 127, 0),
+	SOC_DOUBLE_R("Speaker Playback Volume", WM8971_LOUT2V,
+		WM8971_ROUT2V, 0, 127, 0),
+
+	SOC_ENUM("Bass Boost", wm8971_enum[0]),
+	SOC_ENUM("Bass Filter", wm8971_enum[1]),
+	SOC_SINGLE("Bass Volume", WM8971_BASS, 0, 7, 1),
+
+	SOC_SINGLE("Treble Volume", WM8971_TREBLE, 0, 7, 0),
+	SOC_ENUM("Treble Cut-off", wm8971_enum[2]),
+
+	SOC_SINGLE("Capture Filter Switch", WM8971_ADCDAC, 0, 1, 1),
+
+	SOC_SINGLE("ALC Target Volume", WM8971_ALC1, 0, 7, 0),
+	SOC_SINGLE("ALC Max Volume", WM8971_ALC1, 4, 7, 0),
+
+	SOC_SINGLE("ALC Capture Target Volume", WM8971_ALC1, 0, 7, 0),
+	SOC_SINGLE("ALC Capture Max Volume", WM8971_ALC1, 4, 7, 0),
+	SOC_ENUM("ALC Capture Function", wm8971_enum[3]),
+	SOC_SINGLE("ALC Capture ZC Switch", WM8971_ALC2, 7, 1, 0),
+	SOC_SINGLE("ALC Capture Hold Time", WM8971_ALC2, 0, 15, 0),
+	SOC_SINGLE("ALC Capture Decay Time", WM8971_ALC3, 4, 15, 0),
+	SOC_SINGLE("ALC Capture Attack Time", WM8971_ALC3, 0, 15, 0),
+	SOC_SINGLE("ALC Capture NG Threshold", WM8971_NGATE, 3, 31, 0),
+	SOC_ENUM("ALC Capture NG Type", wm8971_enum[4]),
+	SOC_SINGLE("ALC Capture NG Switch", WM8971_NGATE, 0, 1, 0),
+
+	SOC_SINGLE("Capture 6dB Attenuate", WM8971_ADCDAC, 8, 1, 0),
+	SOC_SINGLE("Playback 6dB Attenuate", WM8971_ADCDAC, 7, 1, 0),
+
+	SOC_ENUM("Playback De-emphasis", wm8971_enum[5]),
+	SOC_ENUM("Playback Function", wm8971_enum[6]),
+	SOC_ENUM("Playback Phase", wm8971_enum[7]),
+
+	SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0),
+};
+
+/*
+ * DAPM Controls
+ */
+
+/* Left Mixer */
+static const struct snd_kcontrol_new wm8971_left_mixer_controls[] = {
+SOC_DAPM_SINGLE("Playback Switch", WM8971_LOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_LOUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8971_LOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_LOUTM2, 7, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new wm8971_right_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8971_ROUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_ROUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Playback Switch", WM8971_ROUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_ROUTM2, 7, 1, 0),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new wm8971_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("Left Playback Switch", WM8971_MOUTM1, 8, 1, 0),
+SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_MOUTM1, 7, 1, 0),
+SOC_DAPM_SINGLE("Right Playback Switch", WM8971_MOUTM2, 8, 1, 0),
+SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_MOUTM2, 7, 1, 0),
+};
+
+/* Left Line Mux */
+static const struct snd_kcontrol_new wm8971_left_line_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[8]);
+
+/* Right Line Mux */
+static const struct snd_kcontrol_new wm8971_right_line_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[9]);
+
+/* Left PGA Mux */
+static const struct snd_kcontrol_new wm8971_left_pga_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[10]);
+
+/* Right PGA Mux */
+static const struct snd_kcontrol_new wm8971_right_pga_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[11]);
+
+/* Mono ADC Mux */
+static const struct snd_kcontrol_new wm8971_monomux_controls =
+SOC_DAPM_ENUM("Route", wm8971_enum[13]);
+
+static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+		&wm8971_left_mixer_controls[0],
+		ARRAY_SIZE(wm8971_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+		&wm8971_right_mixer_controls[0],
+		ARRAY_SIZE(wm8971_right_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono Mixer", WM8971_PWR2, 2, 0,
+		&wm8971_mono_mixer_controls[0],
+		ARRAY_SIZE(wm8971_mono_mixer_controls)),
+
+	SND_SOC_DAPM_PGA("Right Out 2", WM8971_PWR2, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 2", WM8971_PWR2, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Out 1", WM8971_PWR2, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 1", WM8971_PWR2, 6, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8971_PWR2, 7, 0),
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8971_PWR2, 8, 0),
+	SND_SOC_DAPM_PGA("Mono Out 1", WM8971_PWR2, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Mic Bias", WM8971_PWR1, 1, 0, NULL, 0),
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8971_PWR1, 2, 0),
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8971_PWR1, 3, 0),
+
+	SND_SOC_DAPM_MUX("Left PGA Mux", WM8971_PWR1, 5, 0,
+		&wm8971_left_pga_controls),
+	SND_SOC_DAPM_MUX("Right PGA Mux", WM8971_PWR1, 4, 0,
+		&wm8971_right_pga_controls),
+	SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
+		&wm8971_left_line_controls),
+	SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
+		&wm8971_right_line_controls),
+
+	SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
+		&wm8971_monomux_controls),
+	SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
+		&wm8971_monomux_controls),
+
+	SND_SOC_DAPM_OUTPUT("LOUT1"),
+	SND_SOC_DAPM_OUTPUT("ROUT1"),
+	SND_SOC_DAPM_OUTPUT("LOUT2"),
+	SND_SOC_DAPM_OUTPUT("ROUT2"),
+	SND_SOC_DAPM_OUTPUT("MONO"),
+
+	SND_SOC_DAPM_INPUT("LINPUT1"),
+	SND_SOC_DAPM_INPUT("RINPUT1"),
+	SND_SOC_DAPM_INPUT("MIC"),
+};
+
+static const struct snd_soc_dapm_route wm8971_dapm_routes[] = {
+	/* left mixer */
+	{"Left Mixer", "Playback Switch", "Left DAC"},
+	{"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Left Mixer", "Right Playback Switch", "Right DAC"},
+	{"Left Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+	/* right mixer */
+	{"Right Mixer", "Left Playback Switch", "Left DAC"},
+	{"Right Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Right Mixer", "Playback Switch", "Right DAC"},
+	{"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+	/* left out 1 */
+	{"Left Out 1", NULL, "Left Mixer"},
+	{"LOUT1", NULL, "Left Out 1"},
+
+	/* left out 2 */
+	{"Left Out 2", NULL, "Left Mixer"},
+	{"LOUT2", NULL, "Left Out 2"},
+
+	/* right out 1 */
+	{"Right Out 1", NULL, "Right Mixer"},
+	{"ROUT1", NULL, "Right Out 1"},
+
+	/* right out 2 */
+	{"Right Out 2", NULL, "Right Mixer"},
+	{"ROUT2", NULL, "Right Out 2"},
+
+	/* mono mixer */
+	{"Mono Mixer", "Left Playback Switch", "Left DAC"},
+	{"Mono Mixer", "Left Bypass Switch", "Left Line Mux"},
+	{"Mono Mixer", "Right Playback Switch", "Right DAC"},
+	{"Mono Mixer", "Right Bypass Switch", "Right Line Mux"},
+
+	/* mono out */
+	{"Mono Out", NULL, "Mono Mixer"},
+	{"MONO1", NULL, "Mono Out"},
+
+	/* Left Line Mux */
+	{"Left Line Mux", "Line", "LINPUT1"},
+	{"Left Line Mux", "PGA", "Left PGA Mux"},
+	{"Left Line Mux", "Differential", "Differential Mux"},
+
+	/* Right Line Mux */
+	{"Right Line Mux", "Line", "RINPUT1"},
+	{"Right Line Mux", "Mic", "MIC"},
+	{"Right Line Mux", "PGA", "Right PGA Mux"},
+	{"Right Line Mux", "Differential", "Differential Mux"},
+
+	/* Left PGA Mux */
+	{"Left PGA Mux", "Line", "LINPUT1"},
+	{"Left PGA Mux", "Differential", "Differential Mux"},
+
+	/* Right PGA Mux */
+	{"Right PGA Mux", "Line", "RINPUT1"},
+	{"Right PGA Mux", "Differential", "Differential Mux"},
+
+	/* Differential Mux */
+	{"Differential Mux", "Line", "LINPUT1"},
+	{"Differential Mux", "Line", "RINPUT1"},
+
+	/* Left ADC Mux */
+	{"Left ADC Mux", "Stereo", "Left PGA Mux"},
+	{"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
+	{"Left ADC Mux", "Digital Mono", "Left PGA Mux"},
+
+	/* Right ADC Mux */
+	{"Right ADC Mux", "Stereo", "Right PGA Mux"},
+	{"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
+	{"Right ADC Mux", "Digital Mono", "Right PGA Mux"},
+
+	/* ADC */
+	{"Left ADC", NULL, "Left ADC Mux"},
+	{"Right ADC", NULL, "Right ADC Mux"},
+};
+
+struct _coeff_div {
+	u32 mclk;
+	u32 rate;
+	u16 fs;
+	u8 sr:5;
+	u8 usb:1;
+};
+
+/* codec hifi mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	/* 8k */
+	{12288000, 8000, 1536, 0x6, 0x0},
+	{11289600, 8000, 1408, 0x16, 0x0},
+	{18432000, 8000, 2304, 0x7, 0x0},
+	{16934400, 8000, 2112, 0x17, 0x0},
+	{12000000, 8000, 1500, 0x6, 0x1},
+
+	/* 11.025k */
+	{11289600, 11025, 1024, 0x18, 0x0},
+	{16934400, 11025, 1536, 0x19, 0x0},
+	{12000000, 11025, 1088, 0x19, 0x1},
+
+	/* 16k */
+	{12288000, 16000, 768, 0xa, 0x0},
+	{18432000, 16000, 1152, 0xb, 0x0},
+	{12000000, 16000, 750, 0xa, 0x1},
+
+	/* 22.05k */
+	{11289600, 22050, 512, 0x1a, 0x0},
+	{16934400, 22050, 768, 0x1b, 0x0},
+	{12000000, 22050, 544, 0x1b, 0x1},
+
+	/* 32k */
+	{12288000, 32000, 384, 0xc, 0x0},
+	{18432000, 32000, 576, 0xd, 0x0},
+	{12000000, 32000, 375, 0xa, 0x1},
+
+	/* 44.1k */
+	{11289600, 44100, 256, 0x10, 0x0},
+	{16934400, 44100, 384, 0x11, 0x0},
+	{12000000, 44100, 272, 0x11, 0x1},
+
+	/* 48k */
+	{12288000, 48000, 256, 0x0, 0x0},
+	{18432000, 48000, 384, 0x1, 0x0},
+	{12000000, 48000, 250, 0x0, 0x1},
+
+	/* 88.2k */
+	{11289600, 88200, 128, 0x1e, 0x0},
+	{16934400, 88200, 192, 0x1f, 0x0},
+	{12000000, 88200, 136, 0x1f, 0x1},
+
+	/* 96k */
+	{12288000, 96000, 128, 0xe, 0x0},
+	{18432000, 96000, 192, 0xf, 0x0},
+	{12000000, 96000, 125, 0xe, 0x1},
+};
+
+static int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static int wm8971_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8971_priv *wm8971 = snd_soc_component_get_drvdata(component);
+
+	switch (freq) {
+	case 11289600:
+	case 12000000:
+	case 12288000:
+	case 16934400:
+	case 18432000:
+		wm8971->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface = 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8971_IFACE, iface);
+	return 0;
+}
+
+static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params,
+	struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8971_priv *wm8971 = snd_soc_component_get_drvdata(component);
+	u16 iface = snd_soc_component_read32(component, WM8971_IFACE) & 0x1f3;
+	u16 srate = snd_soc_component_read32(component, WM8971_SRATE) & 0x1c0;
+	int coeff = get_coeff(wm8971->sysclk, params_rate(params));
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		iface |= 0x0004;
+		break;
+	case 24:
+		iface |= 0x0008;
+		break;
+	case 32:
+		iface |= 0x000c;
+		break;
+	}
+
+	/* set iface & srate */
+	snd_soc_component_write(component, WM8971_IFACE, iface);
+	if (coeff >= 0)
+		snd_soc_component_write(component, WM8971_SRATE, srate |
+			(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
+
+	return 0;
+}
+
+static int wm8971_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8971_ADCDAC) & 0xfff7;
+
+	if (mute)
+		snd_soc_component_write(component, WM8971_ADCDAC, mute_reg | 0x8);
+	else
+		snd_soc_component_write(component, WM8971_ADCDAC, mute_reg);
+	return 0;
+}
+
+static void wm8971_charge_work(struct work_struct *work)
+{
+	struct wm8971_priv *wm8971 =
+		container_of(work, struct wm8971_priv, charge_work.work);
+
+	/* Set to 500k */
+	regmap_update_bits(wm8971->regmap, WM8971_PWR1, 0x0180, 0x0100);
+}
+
+static int wm8971_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	struct wm8971_priv *wm8971 = snd_soc_component_get_drvdata(component);
+	u16 pwr_reg = snd_soc_component_read32(component, WM8971_PWR1) & 0xfe3e;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* set vmid to 50k and unmute dac */
+		snd_soc_component_write(component, WM8971_PWR1, pwr_reg | 0x00c1);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* Wait until fully charged */
+		flush_delayed_work(&wm8971->charge_work);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			snd_soc_component_cache_sync(component);
+			/* charge output caps - set vmid to 5k for quick power up */
+			snd_soc_component_write(component, WM8971_PWR1, pwr_reg | 0x01c0);
+			queue_delayed_work(system_power_efficient_wq,
+				&wm8971->charge_work, msecs_to_jiffies(1000));
+		} else {
+			/* mute dac and set vmid to 500k, enable VREF */
+			snd_soc_component_write(component, WM8971_PWR1, pwr_reg | 0x0140);
+		}
+
+		break;
+	case SND_SOC_BIAS_OFF:
+		cancel_delayed_work_sync(&wm8971->charge_work);
+		snd_soc_component_write(component, WM8971_PWR1, 0x0001);
+		break;
+	}
+	return 0;
+}
+
+#define WM8971_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops wm8971_dai_ops = {
+	.hw_params	= wm8971_pcm_hw_params,
+	.digital_mute	= wm8971_mute,
+	.set_fmt	= wm8971_set_dai_fmt,
+	.set_sysclk	= wm8971_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8971_dai = {
+	.name = "wm8971-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8971_RATES,
+		.formats = WM8971_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8971_RATES,
+		.formats = WM8971_FORMATS,},
+	.ops = &wm8971_dai_ops,
+};
+
+static int wm8971_probe(struct snd_soc_component *component)
+{
+	struct wm8971_priv *wm8971 = snd_soc_component_get_drvdata(component);
+
+	INIT_DELAYED_WORK(&wm8971->charge_work, wm8971_charge_work);
+
+	wm8971_reset(component);
+
+	/* set the update bits */
+	snd_soc_component_update_bits(component, WM8971_LDAC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_RDAC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_LOUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_ROUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_LOUT2V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_ROUT2V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_LINVOL, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8971_RINVOL, 0x0100, 0x0100);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8971 = {
+	.probe			= wm8971_probe,
+	.set_bias_level		= wm8971_set_bias_level,
+	.controls		= wm8971_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8971_snd_controls),
+	.dapm_widgets		= wm8971_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8971_dapm_widgets),
+	.dapm_routes		= wm8971_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8971_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8971_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+	.max_register = WM8971_MOUTV,
+
+	.reg_defaults = wm8971_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8971_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int wm8971_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8971_priv *wm8971;
+	int ret;
+
+	wm8971 = devm_kzalloc(&i2c->dev, sizeof(struct wm8971_priv),
+			      GFP_KERNEL);
+	if (wm8971 == NULL)
+		return -ENOMEM;
+
+	wm8971->regmap = devm_regmap_init_i2c(i2c, &wm8971_regmap);
+	if (IS_ERR(wm8971->regmap))
+		return PTR_ERR(wm8971->regmap);
+
+	i2c_set_clientdata(i2c, wm8971);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8971, &wm8971_dai, 1);
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8971_i2c_id[] = {
+	{ "wm8971", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id);
+
+static struct i2c_driver wm8971_i2c_driver = {
+	.driver = {
+		.name = "wm8971",
+	},
+	.probe =    wm8971_i2c_probe,
+	.id_table = wm8971_i2c_id,
+};
+
+module_i2c_driver(wm8971_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8971 driver");
+MODULE_AUTHOR("Lab126");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8971.h b/sound/soc/codecs/wm8971.h
new file mode 100644
index 0000000..f31c38f
--- /dev/null
+++ b/sound/soc/codecs/wm8971.h
@@ -0,0 +1,56 @@
+/*
+ * wm8971.h  --  audio driver for WM8971
+ *
+ * Copyright 2005 Lab126, Inc.
+ *
+ * Author: Kenneth Kiraly <kiraly@lab126.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef _WM8971_H
+#define _WM8971_H
+
+#define WM8971_LINVOL	0x00
+#define WM8971_RINVOL	0x01
+#define WM8971_LOUT1V	0x02
+#define WM8971_ROUT1V	0x03
+#define WM8971_ADCDAC	0x05
+#define WM8971_IFACE	0x07
+#define WM8971_SRATE	0x08
+#define WM8971_LDAC		0x0a
+#define WM8971_RDAC		0x0b
+#define WM8971_BASS		0x0c
+#define WM8971_TREBLE	0x0d
+#define WM8971_RESET	0x0f
+#define WM8971_ALC1		0x11
+#define	WM8971_ALC2		0x12
+#define	WM8971_ALC3		0x13
+#define WM8971_NGATE	0x14
+#define WM8971_LADC		0x15
+#define WM8971_RADC		0x16
+#define	WM8971_ADCTL1	0x17
+#define	WM8971_ADCTL2	0x18
+#define WM8971_PWR1		0x19
+#define WM8971_PWR2		0x1a
+#define	WM8971_ADCTL3	0x1b
+#define WM8971_ADCIN	0x1f
+#define	WM8971_LADCIN	0x20
+#define	WM8971_RADCIN	0x21
+#define WM8971_LOUTM1	0x22
+#define WM8971_LOUTM2	0x23
+#define WM8971_ROUTM1	0x24
+#define WM8971_ROUTM2	0x25
+#define WM8971_MOUTM1	0x26
+#define WM8971_MOUTM2	0x27
+#define WM8971_LOUT2V	0x28
+#define WM8971_ROUT2V	0x29
+#define WM8971_MOUTV	0x2A
+
+#define WM8971_SYSCLK	0
+
+#endif
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
new file mode 100644
index 0000000..43edaf8
--- /dev/null
+++ b/sound/soc/codecs/wm8974.c
@@ -0,0 +1,743 @@
+/*
+ * wm8974.c  --  WM8974 ALSA Soc Audio driver
+ *
+ * Copyright 2006-2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood <Liam.Girdwood@wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8974.h"
+
+struct wm8974_priv {
+	unsigned int mclk;
+	unsigned int fs;
+};
+
+static const struct reg_default wm8974_reg_defaults[] = {
+	{  0, 0x0000 }, {  1, 0x0000 }, {  2, 0x0000 }, {  3, 0x0000 },
+	{  4, 0x0050 }, {  5, 0x0000 }, {  6, 0x0140 }, {  7, 0x0000 },
+	{  8, 0x0000 }, {  9, 0x0000 }, { 10, 0x0000 }, { 11, 0x00ff },
+	{ 12, 0x0000 }, { 13, 0x0000 }, { 14, 0x0100 }, { 15, 0x00ff },
+	{ 16, 0x0000 }, { 17, 0x0000 }, { 18, 0x012c }, { 19, 0x002c },
+	{ 20, 0x002c }, { 21, 0x002c }, { 22, 0x002c }, { 23, 0x0000 },
+	{ 24, 0x0032 }, { 25, 0x0000 }, { 26, 0x0000 }, { 27, 0x0000 },
+	{ 28, 0x0000 }, { 29, 0x0000 }, { 30, 0x0000 }, { 31, 0x0000 },
+	{ 32, 0x0038 }, { 33, 0x000b }, { 34, 0x0032 }, { 35, 0x0000 },
+	{ 36, 0x0008 }, { 37, 0x000c }, { 38, 0x0093 }, { 39, 0x00e9 },
+	{ 40, 0x0000 }, { 41, 0x0000 }, { 42, 0x0000 }, { 43, 0x0000 },
+	{ 44, 0x0003 }, { 45, 0x0010 }, { 46, 0x0000 }, { 47, 0x0000 },
+	{ 48, 0x0000 }, { 49, 0x0002 }, { 50, 0x0000 }, { 51, 0x0000 },
+	{ 52, 0x0000 }, { 53, 0x0000 }, { 54, 0x0039 }, { 55, 0x0000 },
+	{ 56, 0x0000 },
+};
+
+#define WM8974_POWER1_BIASEN  0x08
+#define WM8974_POWER1_BUFIOEN 0x04
+
+#define wm8974_reset(c)	snd_soc_component_write(c, WM8974_RESET, 0)
+
+static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" };
+static const char *wm8974_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz" };
+static const char *wm8974_eqmode[] = {"Capture", "Playback" };
+static const char *wm8974_bw[] = {"Narrow", "Wide" };
+static const char *wm8974_eq1[] = {"80Hz", "105Hz", "135Hz", "175Hz" };
+static const char *wm8974_eq2[] = {"230Hz", "300Hz", "385Hz", "500Hz" };
+static const char *wm8974_eq3[] = {"650Hz", "850Hz", "1.1kHz", "1.4kHz" };
+static const char *wm8974_eq4[] = {"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" };
+static const char *wm8974_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz" };
+static const char *wm8974_alc[] = {"ALC", "Limiter" };
+
+static const struct soc_enum wm8974_enum[] = {
+	SOC_ENUM_SINGLE(WM8974_COMP, 1, 4, wm8974_companding), /* adc */
+	SOC_ENUM_SINGLE(WM8974_COMP, 3, 4, wm8974_companding), /* dac */
+	SOC_ENUM_SINGLE(WM8974_DAC,  4, 4, wm8974_deemp),
+	SOC_ENUM_SINGLE(WM8974_EQ1,  8, 2, wm8974_eqmode),
+
+	SOC_ENUM_SINGLE(WM8974_EQ1,  5, 4, wm8974_eq1),
+	SOC_ENUM_SINGLE(WM8974_EQ2,  8, 2, wm8974_bw),
+	SOC_ENUM_SINGLE(WM8974_EQ2,  5, 4, wm8974_eq2),
+	SOC_ENUM_SINGLE(WM8974_EQ3,  8, 2, wm8974_bw),
+
+	SOC_ENUM_SINGLE(WM8974_EQ3,  5, 4, wm8974_eq3),
+	SOC_ENUM_SINGLE(WM8974_EQ4,  8, 2, wm8974_bw),
+	SOC_ENUM_SINGLE(WM8974_EQ4,  5, 4, wm8974_eq4),
+	SOC_ENUM_SINGLE(WM8974_EQ5,  8, 2, wm8974_bw),
+
+	SOC_ENUM_SINGLE(WM8974_EQ5,  5, 4, wm8974_eq5),
+	SOC_ENUM_SINGLE(WM8974_ALC3,  8, 2, wm8974_alc),
+};
+
+static const char *wm8974_auxmode_text[] = { "Buffer", "Mixer" };
+
+static SOC_ENUM_SINGLE_DECL(wm8974_auxmode,
+			    WM8974_INPUT,  3, wm8974_auxmode_text);
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0);
+
+static const struct snd_kcontrol_new wm8974_snd_controls[] = {
+
+SOC_SINGLE("Digital Loopback Switch", WM8974_COMP, 0, 1, 0),
+
+SOC_ENUM("DAC Companding", wm8974_enum[1]),
+SOC_ENUM("ADC Companding", wm8974_enum[0]),
+
+SOC_ENUM("Playback De-emphasis", wm8974_enum[2]),
+SOC_SINGLE("DAC Inversion Switch", WM8974_DAC, 0, 1, 0),
+
+SOC_SINGLE_TLV("PCM Volume", WM8974_DACVOL, 0, 255, 0, digital_tlv),
+
+SOC_SINGLE("High Pass Filter Switch", WM8974_ADC, 8, 1, 0),
+SOC_SINGLE("High Pass Cut Off", WM8974_ADC, 4, 7, 0),
+SOC_SINGLE("ADC Inversion Switch", WM8974_ADC, 0, 1, 0),
+
+SOC_SINGLE_TLV("Capture Volume", WM8974_ADCVOL,  0, 255, 0, digital_tlv),
+
+SOC_ENUM("Equaliser Function", wm8974_enum[3]),
+SOC_ENUM("EQ1 Cut Off", wm8974_enum[4]),
+SOC_SINGLE_TLV("EQ1 Volume", WM8974_EQ1,  0, 24, 1, eq_tlv),
+
+SOC_ENUM("Equaliser EQ2 Bandwidth", wm8974_enum[5]),
+SOC_ENUM("EQ2 Cut Off", wm8974_enum[6]),
+SOC_SINGLE_TLV("EQ2 Volume", WM8974_EQ2,  0, 24, 1, eq_tlv),
+
+SOC_ENUM("Equaliser EQ3 Bandwidth", wm8974_enum[7]),
+SOC_ENUM("EQ3 Cut Off", wm8974_enum[8]),
+SOC_SINGLE_TLV("EQ3 Volume", WM8974_EQ3,  0, 24, 1, eq_tlv),
+
+SOC_ENUM("Equaliser EQ4 Bandwidth", wm8974_enum[9]),
+SOC_ENUM("EQ4 Cut Off", wm8974_enum[10]),
+SOC_SINGLE_TLV("EQ4 Volume", WM8974_EQ4,  0, 24, 1, eq_tlv),
+
+SOC_ENUM("Equaliser EQ5 Bandwidth", wm8974_enum[11]),
+SOC_ENUM("EQ5 Cut Off", wm8974_enum[12]),
+SOC_SINGLE_TLV("EQ5 Volume", WM8974_EQ5,  0, 24, 1, eq_tlv),
+
+SOC_SINGLE("DAC Playback Limiter Switch", WM8974_DACLIM1,  8, 1, 0),
+SOC_SINGLE("DAC Playback Limiter Decay", WM8974_DACLIM1,  4, 15, 0),
+SOC_SINGLE("DAC Playback Limiter Attack", WM8974_DACLIM1,  0, 15, 0),
+
+SOC_SINGLE("DAC Playback Limiter Threshold", WM8974_DACLIM2,  4, 7, 0),
+SOC_SINGLE("DAC Playback Limiter Boost", WM8974_DACLIM2,  0, 15, 0),
+
+SOC_SINGLE("ALC Enable Switch", WM8974_ALC1,  8, 1, 0),
+SOC_SINGLE("ALC Capture Max Gain", WM8974_ALC1,  3, 7, 0),
+SOC_SINGLE("ALC Capture Min Gain", WM8974_ALC1,  0, 7, 0),
+
+SOC_SINGLE("ALC Capture ZC Switch", WM8974_ALC2,  8, 1, 0),
+SOC_SINGLE("ALC Capture Hold", WM8974_ALC2,  4, 7, 0),
+SOC_SINGLE("ALC Capture Target", WM8974_ALC2,  0, 15, 0),
+
+SOC_ENUM("ALC Capture Mode", wm8974_enum[13]),
+SOC_SINGLE("ALC Capture Decay", WM8974_ALC3,  4, 15, 0),
+SOC_SINGLE("ALC Capture Attack", WM8974_ALC3,  0, 15, 0),
+
+SOC_SINGLE("ALC Capture Noise Gate Switch", WM8974_NGATE,  3, 1, 0),
+SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8974_NGATE,  0, 7, 0),
+
+SOC_SINGLE("Capture PGA ZC Switch", WM8974_INPPGA,  7, 1, 0),
+SOC_SINGLE_TLV("Capture PGA Volume", WM8974_INPPGA,  0, 63, 0, inpga_tlv),
+
+SOC_SINGLE("Speaker Playback ZC Switch", WM8974_SPKVOL,  7, 1, 0),
+SOC_SINGLE("Speaker Playback Switch", WM8974_SPKVOL,  6, 1, 1),
+SOC_SINGLE_TLV("Speaker Playback Volume", WM8974_SPKVOL,  0, 63, 0, spk_tlv),
+
+SOC_ENUM("Aux Mode", wm8974_auxmode),
+
+SOC_SINGLE("Capture Boost(+20dB)", WM8974_ADCBOOST,  8, 1, 0),
+SOC_SINGLE("Mono Playback Switch", WM8974_MONOMIX, 6, 1, 1),
+
+/* DAC / ADC oversampling */
+SOC_SINGLE("DAC 128x Oversampling Switch", WM8974_DAC, 8, 1, 0),
+SOC_SINGLE("ADC 128x Oversampling Switch", WM8974_ADC, 8, 1, 0),
+};
+
+/* Speaker Output Mixer */
+static const struct snd_kcontrol_new wm8974_speaker_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8974_SPKMIX, 1, 1, 0),
+SOC_DAPM_SINGLE("Aux Playback Switch", WM8974_SPKMIX, 5, 1, 0),
+SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_SPKMIX, 0, 1, 0),
+};
+
+/* Mono Output Mixer */
+static const struct snd_kcontrol_new wm8974_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8974_MONOMIX, 1, 1, 0),
+SOC_DAPM_SINGLE("Aux Playback Switch", WM8974_MONOMIX, 2, 1, 0),
+SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_MONOMIX, 0, 1, 0),
+};
+
+/* Boost mixer */
+static const struct snd_kcontrol_new wm8974_boost_mixer[] = {
+SOC_DAPM_SINGLE("Aux Switch", WM8974_INPPGA, 6, 1, 0),
+};
+
+/* Input PGA */
+static const struct snd_kcontrol_new wm8974_inpga[] = {
+SOC_DAPM_SINGLE("Aux Switch", WM8974_INPUT, 2, 1, 0),
+SOC_DAPM_SINGLE("MicN Switch", WM8974_INPUT, 1, 1, 0),
+SOC_DAPM_SINGLE("MicP Switch", WM8974_INPUT, 0, 1, 0),
+};
+
+/* AUX Input boost vol */
+static const struct snd_kcontrol_new wm8974_aux_boost_controls =
+SOC_DAPM_SINGLE("Aux Volume", WM8974_ADCBOOST, 0, 7, 0);
+
+/* Mic Input boost vol */
+static const struct snd_kcontrol_new wm8974_mic_boost_controls =
+SOC_DAPM_SINGLE("Mic Volume", WM8974_ADCBOOST, 4, 7, 0);
+
+static const struct snd_soc_dapm_widget wm8974_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Speaker Mixer", WM8974_POWER3, 2, 0,
+	&wm8974_speaker_mixer_controls[0],
+	ARRAY_SIZE(wm8974_speaker_mixer_controls)),
+SND_SOC_DAPM_MIXER("Mono Mixer", WM8974_POWER3, 3, 0,
+	&wm8974_mono_mixer_controls[0],
+	ARRAY_SIZE(wm8974_mono_mixer_controls)),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8974_POWER3, 0, 0),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8974_POWER2, 0, 0),
+SND_SOC_DAPM_PGA("Aux Input", WM8974_POWER1, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SpkN Out", WM8974_POWER3, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SpkP Out", WM8974_POWER3, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Mono Out", WM8974_POWER3, 7, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("Input PGA", WM8974_POWER2, 2, 0, wm8974_inpga,
+		   ARRAY_SIZE(wm8974_inpga)),
+SND_SOC_DAPM_MIXER("Boost Mixer", WM8974_POWER2, 4, 0,
+		   wm8974_boost_mixer, ARRAY_SIZE(wm8974_boost_mixer)),
+
+SND_SOC_DAPM_SUPPLY("Mic Bias", WM8974_POWER1, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_INPUT("MICN"),
+SND_SOC_DAPM_INPUT("MICP"),
+SND_SOC_DAPM_INPUT("AUX"),
+SND_SOC_DAPM_OUTPUT("MONOOUT"),
+SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+};
+
+static const struct snd_soc_dapm_route wm8974_dapm_routes[] = {
+	/* Mono output mixer */
+	{"Mono Mixer", "PCM Playback Switch", "DAC"},
+	{"Mono Mixer", "Aux Playback Switch", "Aux Input"},
+	{"Mono Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+	/* Speaker output mixer */
+	{"Speaker Mixer", "PCM Playback Switch", "DAC"},
+	{"Speaker Mixer", "Aux Playback Switch", "Aux Input"},
+	{"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+	/* Outputs */
+	{"Mono Out", NULL, "Mono Mixer"},
+	{"MONOOUT", NULL, "Mono Out"},
+	{"SpkN Out", NULL, "Speaker Mixer"},
+	{"SpkP Out", NULL, "Speaker Mixer"},
+	{"SPKOUTN", NULL, "SpkN Out"},
+	{"SPKOUTP", NULL, "SpkP Out"},
+
+	/* Boost Mixer */
+	{"ADC", NULL, "Boost Mixer"},
+	{"Boost Mixer", "Aux Switch", "Aux Input"},
+	{"Boost Mixer", NULL, "Input PGA"},
+	{"Boost Mixer", NULL, "MICP"},
+
+	/* Input PGA */
+	{"Input PGA", "Aux Switch", "Aux Input"},
+	{"Input PGA", "MicN Switch", "MICN"},
+	{"Input PGA", "MicP Switch", "MICP"},
+
+	/* Inputs */
+	{"Aux Input", NULL, "AUX"},
+};
+
+struct pll_ {
+	unsigned int pre_div:1;
+	unsigned int n:4;
+	unsigned int k;
+};
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 24) * 10)
+
+static void pll_factors(struct pll_ *pll_div,
+			unsigned int target, unsigned int source)
+{
+	unsigned long long Kpart;
+	unsigned int K, Ndiv, Nmod;
+
+	/* There is a fixed divide by 4 in the output path */
+	target *= 4;
+
+	Ndiv = target / source;
+	if (Ndiv < 6) {
+		source /= 2;
+		pll_div->pre_div = 1;
+		Ndiv = target / source;
+	} else
+		pll_div->pre_div = 0;
+
+	if ((Ndiv < 6) || (Ndiv > 12))
+		printk(KERN_WARNING
+			"WM8974 N value %u outwith recommended range!\n",
+			Ndiv);
+
+	pll_div->n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	/* Check if we need to round */
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	K /= 10;
+
+	pll_div->k = K;
+}
+
+static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+		int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct pll_ pll_div;
+	u16 reg;
+
+	if (freq_in == 0 || freq_out == 0) {
+		/* Clock CODEC directly from MCLK */
+		reg = snd_soc_component_read32(component, WM8974_CLOCK);
+		snd_soc_component_write(component, WM8974_CLOCK, reg & 0x0ff);
+
+		/* Turn off PLL */
+		reg = snd_soc_component_read32(component, WM8974_POWER1);
+		snd_soc_component_write(component, WM8974_POWER1, reg & 0x1df);
+		return 0;
+	}
+
+	pll_factors(&pll_div, freq_out, freq_in);
+
+	snd_soc_component_write(component, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n);
+	snd_soc_component_write(component, WM8974_PLLK1, pll_div.k >> 18);
+	snd_soc_component_write(component, WM8974_PLLK2, (pll_div.k >> 9) & 0x1ff);
+	snd_soc_component_write(component, WM8974_PLLK3, pll_div.k & 0x1ff);
+	reg = snd_soc_component_read32(component, WM8974_POWER1);
+	snd_soc_component_write(component, WM8974_POWER1, reg | 0x020);
+
+	/* Run CODEC from PLL instead of MCLK */
+	reg = snd_soc_component_read32(component, WM8974_CLOCK);
+	snd_soc_component_write(component, WM8974_CLOCK, reg | 0x100);
+
+	return 0;
+}
+
+/*
+ * Configure WM8974 clock dividers.
+ */
+static int wm8974_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+		int div_id, int div)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 reg;
+
+	switch (div_id) {
+	case WM8974_OPCLKDIV:
+		reg = snd_soc_component_read32(component, WM8974_GPIO) & 0x1cf;
+		snd_soc_component_write(component, WM8974_GPIO, reg | div);
+		break;
+	case WM8974_MCLKDIV:
+		reg = snd_soc_component_read32(component, WM8974_CLOCK) & 0x11f;
+		snd_soc_component_write(component, WM8974_CLOCK, reg | div);
+		break;
+	case WM8974_BCLKDIV:
+		reg = snd_soc_component_read32(component, WM8974_CLOCK) & 0x1e3;
+		snd_soc_component_write(component, WM8974_CLOCK, reg | div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static unsigned int wm8974_get_mclkdiv(unsigned int f_in, unsigned int f_out,
+				       int *mclkdiv)
+{
+	unsigned int ratio = 2 * f_in / f_out;
+
+	if (ratio <= 2) {
+		*mclkdiv = WM8974_MCLKDIV_1;
+		ratio = 2;
+	} else if (ratio == 3) {
+		*mclkdiv = WM8974_MCLKDIV_1_5;
+	} else if (ratio == 4) {
+		*mclkdiv = WM8974_MCLKDIV_2;
+	} else if (ratio <= 6) {
+		*mclkdiv = WM8974_MCLKDIV_3;
+		ratio = 6;
+	} else if (ratio <= 8) {
+		*mclkdiv = WM8974_MCLKDIV_4;
+		ratio = 8;
+	} else if (ratio <= 12) {
+		*mclkdiv = WM8974_MCLKDIV_6;
+		ratio = 12;
+	} else if (ratio <= 16) {
+		*mclkdiv = WM8974_MCLKDIV_8;
+		ratio = 16;
+	} else {
+		*mclkdiv = WM8974_MCLKDIV_12;
+		ratio = 24;
+	}
+
+	return f_out * ratio / 2;
+}
+
+static int wm8974_update_clocks(struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8974_priv *priv = snd_soc_component_get_drvdata(component);
+	unsigned int fs256;
+	unsigned int fpll = 0;
+	unsigned int f;
+	int mclkdiv;
+
+	if (!priv->mclk || !priv->fs)
+		return 0;
+
+	fs256 = 256 * priv->fs;
+
+	f = wm8974_get_mclkdiv(priv->mclk, fs256, &mclkdiv);
+
+	if (f != priv->mclk) {
+		/* The PLL performs best around 90MHz */
+		fpll = wm8974_get_mclkdiv(22500000, fs256, &mclkdiv);
+	}
+
+	wm8974_set_dai_pll(dai, 0, 0, priv->mclk, fpll);
+	wm8974_set_dai_clkdiv(dai, WM8974_MCLKDIV, mclkdiv);
+
+	return 0;
+}
+
+static int wm8974_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+				 unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8974_priv *priv = snd_soc_component_get_drvdata(component);
+
+	if (dir != SND_SOC_CLOCK_IN)
+		return -EINVAL;
+
+	priv->mclk = freq;
+
+	return wm8974_update_clocks(dai);
+}
+
+static int wm8974_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = 0;
+	u16 clk = snd_soc_component_read32(component, WM8974_CLOCK) & 0x1fe;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		clk |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0010;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0008;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x00018;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0180;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0100;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0080;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8974_IFACE, iface);
+	snd_soc_component_write(component, WM8974_CLOCK, clk);
+	return 0;
+}
+
+static int wm8974_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8974_priv *priv = snd_soc_component_get_drvdata(component);
+	u16 iface = snd_soc_component_read32(component, WM8974_IFACE) & 0x19f;
+	u16 adn = snd_soc_component_read32(component, WM8974_ADD) & 0x1f1;
+	int err;
+
+	priv->fs = params_rate(params);
+	err = wm8974_update_clocks(dai);
+	if (err)
+		return err;
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		iface |= 0x0020;
+		break;
+	case 24:
+		iface |= 0x0040;
+		break;
+	case 32:
+		iface |= 0x0060;
+		break;
+	}
+
+	/* filter coefficient */
+	switch (params_rate(params)) {
+	case 8000:
+		adn |= 0x5 << 1;
+		break;
+	case 11025:
+		adn |= 0x4 << 1;
+		break;
+	case 16000:
+		adn |= 0x3 << 1;
+		break;
+	case 22050:
+		adn |= 0x2 << 1;
+		break;
+	case 32000:
+		adn |= 0x1 << 1;
+		break;
+	case 44100:
+	case 48000:
+		break;
+	}
+
+	snd_soc_component_write(component, WM8974_IFACE, iface);
+	snd_soc_component_write(component, WM8974_ADD, adn);
+	return 0;
+}
+
+static int wm8974_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8974_DAC) & 0xffbf;
+
+	if (mute)
+		snd_soc_component_write(component, WM8974_DAC, mute_reg | 0x40);
+	else
+		snd_soc_component_write(component, WM8974_DAC, mute_reg);
+	return 0;
+}
+
+/* liam need to make this lower power with dapm */
+static int wm8974_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	u16 power1 = snd_soc_component_read32(component, WM8974_POWER1) & ~0x3;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		power1 |= 0x1;  /* VMID 50k */
+		snd_soc_component_write(component, WM8974_POWER1, power1);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;
+
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			regcache_sync(dev_get_regmap(component->dev, NULL));
+
+			/* Initial cap charge at VMID 5k */
+			snd_soc_component_write(component, WM8974_POWER1, power1 | 0x3);
+			mdelay(100);
+		}
+
+		power1 |= 0x2;  /* VMID 500k */
+		snd_soc_component_write(component, WM8974_POWER1, power1);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_write(component, WM8974_POWER1, 0);
+		snd_soc_component_write(component, WM8974_POWER2, 0);
+		snd_soc_component_write(component, WM8974_POWER3, 0);
+		break;
+	}
+
+	return 0;
+}
+
+#define WM8974_RATES (SNDRV_PCM_RATE_8000_48000)
+
+#define WM8974_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops wm8974_ops = {
+	.hw_params = wm8974_pcm_hw_params,
+	.digital_mute = wm8974_mute,
+	.set_fmt = wm8974_set_dai_fmt,
+	.set_clkdiv = wm8974_set_dai_clkdiv,
+	.set_pll = wm8974_set_dai_pll,
+	.set_sysclk = wm8974_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8974_dai = {
+	.name = "wm8974-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,   /* Only 1 channel of data */
+		.rates = WM8974_RATES,
+		.formats = WM8974_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,   /* Only 1 channel of data */
+		.rates = WM8974_RATES,
+		.formats = WM8974_FORMATS,},
+	.ops = &wm8974_ops,
+	.symmetric_rates = 1,
+};
+
+static const struct regmap_config wm8974_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = WM8974_MONOMIX,
+	.reg_defaults = wm8974_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8974_reg_defaults),
+	.cache_type = REGCACHE_FLAT,
+};
+
+static int wm8974_probe(struct snd_soc_component *component)
+{
+	int ret = 0;
+
+	ret = wm8974_reset(component);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8974 = {
+	.probe			= wm8974_probe,
+	.set_bias_level		= wm8974_set_bias_level,
+	.controls		= wm8974_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8974_snd_controls),
+	.dapm_widgets		= wm8974_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8974_dapm_widgets),
+	.dapm_routes		= wm8974_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8974_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm8974_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8974_priv *priv;
+	struct regmap *regmap;
+	int ret;
+
+	priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, priv);
+
+	regmap = devm_regmap_init_i2c(i2c, &wm8974_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8974, &wm8974_dai, 1);
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8974_i2c_id[] = {
+	{ "wm8974", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id);
+
+static const struct of_device_id wm8974_of_match[] = {
+       { .compatible = "wlf,wm8974", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wm8974_of_match);
+
+static struct i2c_driver wm8974_i2c_driver = {
+	.driver = {
+		.name = "wm8974",
+		.of_match_table = wm8974_of_match,
+	},
+	.probe =    wm8974_i2c_probe,
+	.id_table = wm8974_i2c_id,
+};
+
+module_i2c_driver(wm8974_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8974 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8974.h b/sound/soc/codecs/wm8974.h
new file mode 100644
index 0000000..3c94e7b
--- /dev/null
+++ b/sound/soc/codecs/wm8974.h
@@ -0,0 +1,86 @@
+/*
+ * wm8974.h  --  WM8974 Soc Audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8974_H
+#define _WM8974_H
+
+/* WM8974 register space */
+
+#define WM8974_RESET		0x0
+#define WM8974_POWER1		0x1
+#define WM8974_POWER2		0x2
+#define WM8974_POWER3		0x3
+#define WM8974_IFACE		0x4
+#define WM8974_COMP		0x5
+#define WM8974_CLOCK		0x6
+#define WM8974_ADD		0x7
+#define WM8974_GPIO		0x8
+#define WM8974_DAC		0xa
+#define WM8974_DACVOL		0xb
+#define WM8974_ADC		0xe
+#define WM8974_ADCVOL		0xf
+#define WM8974_EQ1		0x12
+#define WM8974_EQ2		0x13
+#define WM8974_EQ3		0x14
+#define WM8974_EQ4		0x15
+#define WM8974_EQ5		0x16
+#define WM8974_DACLIM1		0x18
+#define WM8974_DACLIM2		0x19
+#define WM8974_NOTCH1		0x1b
+#define WM8974_NOTCH2		0x1c
+#define WM8974_NOTCH3		0x1d
+#define WM8974_NOTCH4		0x1e
+#define WM8974_ALC1		0x20
+#define WM8974_ALC2		0x21
+#define WM8974_ALC3		0x22
+#define WM8974_NGATE		0x23
+#define WM8974_PLLN		0x24
+#define WM8974_PLLK1		0x25
+#define WM8974_PLLK2		0x26
+#define WM8974_PLLK3		0x27
+#define WM8974_ATTEN		0x28
+#define WM8974_INPUT		0x2c
+#define WM8974_INPPGA		0x2d
+#define WM8974_ADCBOOST		0x2f
+#define WM8974_OUTPUT		0x31
+#define WM8974_SPKMIX		0x32
+#define WM8974_SPKVOL		0x36
+#define WM8974_MONOMIX		0x38
+
+#define WM8974_CACHEREGNUM 	57
+
+/* Clock divider Id's */
+#define WM8974_OPCLKDIV		0
+#define WM8974_MCLKDIV		1
+#define WM8974_BCLKDIV		2
+
+/* PLL Out dividers */
+#define WM8974_OPCLKDIV_1	(0 << 4)
+#define WM8974_OPCLKDIV_2	(1 << 4)
+#define WM8974_OPCLKDIV_3	(2 << 4)
+#define WM8974_OPCLKDIV_4	(3 << 4)
+
+/* BCLK clock dividers */
+#define WM8974_BCLKDIV_1	(0 << 2)
+#define WM8974_BCLKDIV_2	(1 << 2)
+#define WM8974_BCLKDIV_4	(2 << 2)
+#define WM8974_BCLKDIV_8	(3 << 2)
+#define WM8974_BCLKDIV_16	(4 << 2)
+#define WM8974_BCLKDIV_32	(5 << 2)
+
+/* MCLK clock dividers */
+#define WM8974_MCLKDIV_1	(0 << 5)
+#define WM8974_MCLKDIV_1_5	(1 << 5)
+#define WM8974_MCLKDIV_2	(2 << 5)
+#define WM8974_MCLKDIV_3	(3 << 5)
+#define WM8974_MCLKDIV_4	(4 << 5)
+#define WM8974_MCLKDIV_6	(5 << 5)
+#define WM8974_MCLKDIV_8	(6 << 5)
+#define WM8974_MCLKDIV_12	(7 << 5)
+
+#endif
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
new file mode 100644
index 0000000..bae4fe8
--- /dev/null
+++ b/sound/soc/codecs/wm8978.c
@@ -0,0 +1,1087 @@
+/*
+ * wm8978.c  --  WM8978 ALSA SoC Audio Codec driver
+ *
+ * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ * Copyright (C) 2007 Carlos Munoz <carlos@kenati.com>
+ * Copyright 2006-2009 Wolfson Microelectronics PLC.
+ * Based on wm8974 and wm8990 by Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+
+#include "wm8978.h"
+
+static const struct reg_default wm8978_reg_defaults[] = {
+	{ 1, 0x0000 },
+	{ 2, 0x0000 },
+	{ 3, 0x0000 },
+	{ 4, 0x0050 },
+	{ 5, 0x0000 },
+	{ 6, 0x0140 },
+	{ 7, 0x0000 },
+	{ 8, 0x0000 },
+	{ 9, 0x0000 },
+	{ 10, 0x0000 },
+	{ 11, 0x00ff },
+	{ 12, 0x00ff },
+	{ 13, 0x0000 },
+	{ 14, 0x0100 },
+	{ 15, 0x00ff },
+	{ 16, 0x00ff },
+	{ 17, 0x0000 },
+	{ 18, 0x012c },
+	{ 19, 0x002c },
+	{ 20, 0x002c },
+	{ 21, 0x002c },
+	{ 22, 0x002c },
+	{ 23, 0x0000 },
+	{ 24, 0x0032 },
+	{ 25, 0x0000 },
+	{ 26, 0x0000 },
+	{ 27, 0x0000 },
+	{ 28, 0x0000 },
+	{ 29, 0x0000 },
+	{ 30, 0x0000 },
+	{ 31, 0x0000 },
+	{ 32, 0x0038 },
+	{ 33, 0x000b },
+	{ 34, 0x0032 },
+	{ 35, 0x0000 },
+	{ 36, 0x0008 },
+	{ 37, 0x000c },
+	{ 38, 0x0093 },
+	{ 39, 0x00e9 },
+	{ 40, 0x0000 },
+	{ 41, 0x0000 },
+	{ 42, 0x0000 },
+	{ 43, 0x0000 },
+	{ 44, 0x0033 },
+	{ 45, 0x0010 },
+	{ 46, 0x0010 },
+	{ 47, 0x0100 },
+	{ 48, 0x0100 },
+	{ 49, 0x0002 },
+	{ 50, 0x0001 },
+	{ 51, 0x0001 },
+	{ 52, 0x0039 },
+	{ 53, 0x0039 },
+	{ 54, 0x0039 },
+	{ 55, 0x0039 },
+	{ 56, 0x0001 },
+	{ 57, 0x0001 },
+};
+
+static bool wm8978_volatile(struct device *dev, unsigned int reg)
+{
+	return reg == WM8978_RESET;
+}
+
+/* codec private data */
+struct wm8978_priv {
+	struct regmap *regmap;
+	unsigned int f_pllout;
+	unsigned int f_mclk;
+	unsigned int f_256fs;
+	unsigned int f_opclk;
+	int mclk_idx;
+	enum wm8978_sysclk_src sysclk;
+};
+
+static const char *wm8978_companding[] = {"Off", "NC", "u-law", "A-law"};
+static const char *wm8978_eqmode[] = {"Capture", "Playback"};
+static const char *wm8978_bw[] = {"Narrow", "Wide"};
+static const char *wm8978_eq1[] = {"80Hz", "105Hz", "135Hz", "175Hz"};
+static const char *wm8978_eq2[] = {"230Hz", "300Hz", "385Hz", "500Hz"};
+static const char *wm8978_eq3[] = {"650Hz", "850Hz", "1.1kHz", "1.4kHz"};
+static const char *wm8978_eq4[] = {"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"};
+static const char *wm8978_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"};
+static const char *wm8978_alc3[] = {"ALC", "Limiter"};
+static const char *wm8978_alc1[] = {"Off", "Right", "Left", "Both"};
+
+static SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1,
+			    wm8978_companding);
+static SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3,
+			    wm8978_companding);
+static SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode);
+static SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1);
+static SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw);
+static SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2);
+static SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw);
+static SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3);
+static SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw);
+static SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4);
+static SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5);
+static SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3);
+static SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1);
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, -1500, 300, 1);
+static const DECLARE_TLV_DB_SCALE(limiter_tlv, 0, 100, 0);
+
+static const struct snd_kcontrol_new wm8978_snd_controls[] = {
+
+	SOC_SINGLE("Digital Loopback Switch",
+		WM8978_COMPANDING_CONTROL, 0, 1, 0),
+
+	SOC_ENUM("ADC Companding", adc_compand),
+	SOC_ENUM("DAC Companding", dac_compand),
+
+	SOC_DOUBLE("DAC Inversion Switch", WM8978_DAC_CONTROL, 0, 1, 1, 0),
+
+	SOC_DOUBLE_R_TLV("PCM Volume",
+		WM8978_LEFT_DAC_DIGITAL_VOLUME, WM8978_RIGHT_DAC_DIGITAL_VOLUME,
+		0, 255, 0, digital_tlv),
+
+	SOC_SINGLE("High Pass Filter Switch", WM8978_ADC_CONTROL, 8, 1, 0),
+	SOC_SINGLE("High Pass Cut Off", WM8978_ADC_CONTROL, 4, 7, 0),
+	SOC_DOUBLE("ADC Inversion Switch", WM8978_ADC_CONTROL, 0, 1, 1, 0),
+
+	SOC_DOUBLE_R_TLV("ADC Volume",
+		WM8978_LEFT_ADC_DIGITAL_VOLUME, WM8978_RIGHT_ADC_DIGITAL_VOLUME,
+		0, 255, 0, digital_tlv),
+
+	SOC_ENUM("Equaliser Function", eqmode),
+	SOC_ENUM("EQ1 Cut Off", eq1),
+	SOC_SINGLE_TLV("EQ1 Volume", WM8978_EQ1,  0, 24, 1, eq_tlv),
+
+	SOC_ENUM("Equaliser EQ2 Bandwidth", eq2bw),
+	SOC_ENUM("EQ2 Cut Off", eq2),
+	SOC_SINGLE_TLV("EQ2 Volume", WM8978_EQ2,  0, 24, 1, eq_tlv),
+
+	SOC_ENUM("Equaliser EQ3 Bandwidth", eq3bw),
+	SOC_ENUM("EQ3 Cut Off", eq3),
+	SOC_SINGLE_TLV("EQ3 Volume", WM8978_EQ3,  0, 24, 1, eq_tlv),
+
+	SOC_ENUM("Equaliser EQ4 Bandwidth", eq4bw),
+	SOC_ENUM("EQ4 Cut Off", eq4),
+	SOC_SINGLE_TLV("EQ4 Volume", WM8978_EQ4,  0, 24, 1, eq_tlv),
+
+	SOC_ENUM("EQ5 Cut Off", eq5),
+	SOC_SINGLE_TLV("EQ5 Volume", WM8978_EQ5, 0, 24, 1, eq_tlv),
+
+	SOC_SINGLE("DAC Playback Limiter Switch",
+		WM8978_DAC_LIMITER_1, 8, 1, 0),
+	SOC_SINGLE("DAC Playback Limiter Decay",
+		WM8978_DAC_LIMITER_1, 4, 15, 0),
+	SOC_SINGLE("DAC Playback Limiter Attack",
+		WM8978_DAC_LIMITER_1, 0, 15, 0),
+
+	SOC_SINGLE("DAC Playback Limiter Threshold",
+		WM8978_DAC_LIMITER_2, 4, 7, 0),
+	SOC_SINGLE_TLV("DAC Playback Limiter Volume",
+		WM8978_DAC_LIMITER_2, 0, 12, 0, limiter_tlv),
+
+	SOC_ENUM("ALC Enable Switch", alc1),
+	SOC_SINGLE("ALC Capture Min Gain", WM8978_ALC_CONTROL_1, 0, 7, 0),
+	SOC_SINGLE("ALC Capture Max Gain", WM8978_ALC_CONTROL_1, 3, 7, 0),
+
+	SOC_SINGLE("ALC Capture Hold", WM8978_ALC_CONTROL_2, 4, 10, 0),
+	SOC_SINGLE("ALC Capture Target", WM8978_ALC_CONTROL_2, 0, 15, 0),
+
+	SOC_ENUM("ALC Capture Mode", alc3),
+	SOC_SINGLE("ALC Capture Decay", WM8978_ALC_CONTROL_3, 4, 10, 0),
+	SOC_SINGLE("ALC Capture Attack", WM8978_ALC_CONTROL_3, 0, 10, 0),
+
+	SOC_SINGLE("ALC Capture Noise Gate Switch", WM8978_NOISE_GATE, 3, 1, 0),
+	SOC_SINGLE("ALC Capture Noise Gate Threshold",
+		WM8978_NOISE_GATE, 0, 7, 0),
+
+	SOC_DOUBLE_R("Capture PGA ZC Switch",
+		WM8978_LEFT_INP_PGA_CONTROL, WM8978_RIGHT_INP_PGA_CONTROL,
+		7, 1, 0),
+
+	/* OUT1 - Headphones */
+	SOC_DOUBLE_R("Headphone Playback ZC Switch",
+		WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, 7, 1, 0),
+
+	SOC_DOUBLE_R_TLV("Headphone Playback Volume",
+		WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL,
+		0, 63, 0, spk_tlv),
+
+	/* OUT2 - Speakers */
+	SOC_DOUBLE_R("Speaker Playback ZC Switch",
+		WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, 7, 1, 0),
+
+	SOC_DOUBLE_R_TLV("Speaker Playback Volume",
+		WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL,
+		0, 63, 0, spk_tlv),
+
+	/* OUT3/4 - Line Output */
+	SOC_DOUBLE_R("Line Playback Switch",
+		WM8978_OUT3_MIXER_CONTROL, WM8978_OUT4_MIXER_CONTROL, 6, 1, 1),
+
+	/* Mixer #3: Boost (Input) mixer */
+	SOC_DOUBLE_R("PGA Boost (+20dB)",
+		WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL,
+		8, 1, 0),
+	SOC_DOUBLE_R_TLV("L2/R2 Boost Volume",
+		WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL,
+		4, 7, 0, boost_tlv),
+	SOC_DOUBLE_R_TLV("Aux Boost Volume",
+		WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL,
+		0, 7, 0, boost_tlv),
+
+	/* Input PGA volume */
+	SOC_DOUBLE_R_TLV("Input PGA Volume",
+		WM8978_LEFT_INP_PGA_CONTROL, WM8978_RIGHT_INP_PGA_CONTROL,
+		0, 63, 0, inpga_tlv),
+
+	/* Headphone */
+	SOC_DOUBLE_R("Headphone Switch",
+		WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, 6, 1, 1),
+
+	/* Speaker */
+	SOC_DOUBLE_R("Speaker Switch",
+		WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, 6, 1, 1),
+
+	/* DAC / ADC oversampling */
+	SOC_SINGLE("DAC 128x Oversampling Switch", WM8978_DAC_CONTROL,
+		   5, 1, 0),
+	SOC_SINGLE("ADC 128x Oversampling Switch", WM8978_ADC_CONTROL,
+		   5, 1, 0),
+};
+
+/* Mixer #1: Output (OUT1, OUT2) Mixer: mix AUX, Input mixer output and DAC */
+static const struct snd_kcontrol_new wm8978_left_out_mixer[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", WM8978_LEFT_MIXER_CONTROL, 1, 1, 0),
+	SOC_DAPM_SINGLE("Aux Playback Switch", WM8978_LEFT_MIXER_CONTROL, 5, 1, 0),
+	SOC_DAPM_SINGLE("PCM Playback Switch", WM8978_LEFT_MIXER_CONTROL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8978_right_out_mixer[] = {
+	SOC_DAPM_SINGLE("Line Bypass Switch", WM8978_RIGHT_MIXER_CONTROL, 1, 1, 0),
+	SOC_DAPM_SINGLE("Aux Playback Switch", WM8978_RIGHT_MIXER_CONTROL, 5, 1, 0),
+	SOC_DAPM_SINGLE("PCM Playback Switch", WM8978_RIGHT_MIXER_CONTROL, 0, 1, 0),
+};
+
+/* OUT3/OUT4 Mixer not implemented */
+
+/* Mixer #2: Input PGA Mute */
+static const struct snd_kcontrol_new wm8978_left_input_mixer[] = {
+	SOC_DAPM_SINGLE("L2 Switch", WM8978_INPUT_CONTROL, 2, 1, 0),
+	SOC_DAPM_SINGLE("MicN Switch", WM8978_INPUT_CONTROL, 1, 1, 0),
+	SOC_DAPM_SINGLE("MicP Switch", WM8978_INPUT_CONTROL, 0, 1, 0),
+};
+static const struct snd_kcontrol_new wm8978_right_input_mixer[] = {
+	SOC_DAPM_SINGLE("R2 Switch", WM8978_INPUT_CONTROL, 6, 1, 0),
+	SOC_DAPM_SINGLE("MicN Switch", WM8978_INPUT_CONTROL, 5, 1, 0),
+	SOC_DAPM_SINGLE("MicP Switch", WM8978_INPUT_CONTROL, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8978_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback",
+			 WM8978_POWER_MANAGEMENT_3, 0, 0),
+	SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback",
+			 WM8978_POWER_MANAGEMENT_3, 1, 0),
+	SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture",
+			 WM8978_POWER_MANAGEMENT_2, 0, 0),
+	SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture",
+			 WM8978_POWER_MANAGEMENT_2, 1, 0),
+
+	/* Mixer #1: OUT1,2 */
+	SOC_MIXER_ARRAY("Left Output Mixer", WM8978_POWER_MANAGEMENT_3,
+			2, 0, wm8978_left_out_mixer),
+	SOC_MIXER_ARRAY("Right Output Mixer", WM8978_POWER_MANAGEMENT_3,
+			3, 0, wm8978_right_out_mixer),
+
+	SOC_MIXER_ARRAY("Left Input Mixer", WM8978_POWER_MANAGEMENT_2,
+			2, 0, wm8978_left_input_mixer),
+	SOC_MIXER_ARRAY("Right Input Mixer", WM8978_POWER_MANAGEMENT_2,
+			3, 0, wm8978_right_input_mixer),
+
+	SND_SOC_DAPM_PGA("Left Boost Mixer", WM8978_POWER_MANAGEMENT_2,
+			 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Boost Mixer", WM8978_POWER_MANAGEMENT_2,
+			 5, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Left Capture PGA", WM8978_LEFT_INP_PGA_CONTROL,
+			 6, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Capture PGA", WM8978_RIGHT_INP_PGA_CONTROL,
+			 6, 1, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Left Headphone Out", WM8978_POWER_MANAGEMENT_2,
+			 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Headphone Out", WM8978_POWER_MANAGEMENT_2,
+			 8, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Left Speaker Out", WM8978_POWER_MANAGEMENT_3,
+			 6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Speaker Out", WM8978_POWER_MANAGEMENT_3,
+			 5, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("OUT4 VMID", WM8978_POWER_MANAGEMENT_3,
+			   8, 0, NULL, 0),
+
+	SND_SOC_DAPM_MICBIAS("Mic Bias", WM8978_POWER_MANAGEMENT_1, 4, 0),
+
+	SND_SOC_DAPM_INPUT("LMICN"),
+	SND_SOC_DAPM_INPUT("LMICP"),
+	SND_SOC_DAPM_INPUT("RMICN"),
+	SND_SOC_DAPM_INPUT("RMICP"),
+	SND_SOC_DAPM_INPUT("LAUX"),
+	SND_SOC_DAPM_INPUT("RAUX"),
+	SND_SOC_DAPM_INPUT("L2"),
+	SND_SOC_DAPM_INPUT("R2"),
+	SND_SOC_DAPM_OUTPUT("LHP"),
+	SND_SOC_DAPM_OUTPUT("RHP"),
+	SND_SOC_DAPM_OUTPUT("LSPK"),
+	SND_SOC_DAPM_OUTPUT("RSPK"),
+};
+
+static const struct snd_soc_dapm_route wm8978_dapm_routes[] = {
+	/* Output mixer */
+	{"Right Output Mixer", "PCM Playback Switch", "Right DAC"},
+	{"Right Output Mixer", "Aux Playback Switch", "RAUX"},
+	{"Right Output Mixer", "Line Bypass Switch", "Right Boost Mixer"},
+
+	{"Left Output Mixer", "PCM Playback Switch", "Left DAC"},
+	{"Left Output Mixer", "Aux Playback Switch", "LAUX"},
+	{"Left Output Mixer", "Line Bypass Switch", "Left Boost Mixer"},
+
+	/* Outputs */
+	{"Right Headphone Out", NULL, "Right Output Mixer"},
+	{"RHP", NULL, "Right Headphone Out"},
+
+	{"Left Headphone Out", NULL, "Left Output Mixer"},
+	{"LHP", NULL, "Left Headphone Out"},
+
+	{"Right Speaker Out", NULL, "Right Output Mixer"},
+	{"RSPK", NULL, "Right Speaker Out"},
+
+	{"Left Speaker Out", NULL, "Left Output Mixer"},
+	{"LSPK", NULL, "Left Speaker Out"},
+
+	/* Boost Mixer */
+	{"Right ADC", NULL, "Right Boost Mixer"},
+
+	{"Right Boost Mixer", NULL, "RAUX"},
+	{"Right Boost Mixer", NULL, "Right Capture PGA"},
+	{"Right Boost Mixer", NULL, "R2"},
+
+	{"Left ADC", NULL, "Left Boost Mixer"},
+
+	{"Left Boost Mixer", NULL, "LAUX"},
+	{"Left Boost Mixer", NULL, "Left Capture PGA"},
+	{"Left Boost Mixer", NULL, "L2"},
+
+	/* Input PGA */
+	{"Right Capture PGA", NULL, "Right Input Mixer"},
+	{"Left Capture PGA", NULL, "Left Input Mixer"},
+
+	{"Right Input Mixer", "R2 Switch", "R2"},
+	{"Right Input Mixer", "MicN Switch", "RMICN"},
+	{"Right Input Mixer", "MicP Switch", "RMICP"},
+
+	{"Left Input Mixer", "L2 Switch", "L2"},
+	{"Left Input Mixer", "MicN Switch", "LMICN"},
+	{"Left Input Mixer", "MicP Switch", "LMICP"},
+};
+
+/* PLL divisors */
+struct wm8978_pll_div {
+	u32 k;
+	u8 n;
+	u8 div2;
+};
+
+#define FIXED_PLL_SIZE (1 << 24)
+
+static void pll_factors(struct snd_soc_component *component,
+		struct wm8978_pll_div *pll_div, unsigned int target, unsigned int source)
+{
+	u64 k_part;
+	unsigned int k, n_div, n_mod;
+
+	n_div = target / source;
+	if (n_div < 6) {
+		source >>= 1;
+		pll_div->div2 = 1;
+		n_div = target / source;
+	} else {
+		pll_div->div2 = 0;
+	}
+
+	if (n_div < 6 || n_div > 12)
+		dev_warn(component->dev,
+			 "WM8978 N value exceeds recommended range! N = %u\n",
+			 n_div);
+
+	pll_div->n = n_div;
+	n_mod = target - source * n_div;
+	k_part = FIXED_PLL_SIZE * (long long)n_mod + source / 2;
+
+	do_div(k_part, source);
+
+	k = k_part & 0xFFFFFFFF;
+
+	pll_div->k = k;
+}
+
+/* MCLK dividers */
+static const int mclk_numerator[]	= {1, 3, 2, 3, 4, 6, 8, 12};
+static const int mclk_denominator[]	= {1, 2, 1, 1, 1, 1, 1, 1};
+
+/*
+ * find index >= idx, such that, for a given f_out,
+ * 3 * f_mclk / 4 <= f_PLLOUT < 13 * f_mclk / 4
+ * f_out can be f_256fs or f_opclk, currently only used for f_256fs. Can be
+ * generalised for f_opclk with suitable coefficient arrays, but currently
+ * the OPCLK divisor is calculated directly, not iteratively.
+ */
+static int wm8978_enum_mclk(unsigned int f_out, unsigned int f_mclk,
+			    unsigned int *f_pllout)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mclk_numerator); i++) {
+		unsigned int f_pllout_x4 = 4 * f_out * mclk_numerator[i] /
+			mclk_denominator[i];
+		if (3 * f_mclk <= f_pllout_x4 && f_pllout_x4 < 13 * f_mclk) {
+			*f_pllout = f_pllout_x4 / 4;
+			return i;
+		}
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * Calculate internal frequencies and dividers, according to Figure 40
+ * "PLL and Clock Select Circuit" in WM8978 datasheet Rev. 2.6
+ */
+static int wm8978_configure_pll(struct snd_soc_component *component)
+{
+	struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
+	struct wm8978_pll_div pll_div;
+	unsigned int f_opclk = wm8978->f_opclk, f_mclk = wm8978->f_mclk,
+		f_256fs = wm8978->f_256fs;
+	unsigned int f2;
+
+	if (!f_mclk)
+		return -EINVAL;
+
+	if (f_opclk) {
+		unsigned int opclk_div;
+		/* Cannot set up MCLK divider now, do later */
+		wm8978->mclk_idx = -1;
+
+		/*
+		 * The user needs OPCLK. Choose OPCLKDIV to put
+		 * 6 <= R = f2 / f1 < 13, 1 <= OPCLKDIV <= 4.
+		 * f_opclk = f_mclk * prescale * R / 4 / OPCLKDIV, where
+		 * prescale = 1, or prescale = 2. Prescale is calculated inside
+		 * pll_factors(). We have to select f_PLLOUT, such that
+		 * f_mclk * 3 / 4 <= f_PLLOUT < f_mclk * 13 / 4. Must be
+		 * f_mclk * 3 / 16 <= f_opclk < f_mclk * 13 / 4.
+		 */
+		if (16 * f_opclk < 3 * f_mclk || 4 * f_opclk >= 13 * f_mclk)
+			return -EINVAL;
+
+		if (4 * f_opclk < 3 * f_mclk)
+			/* Have to use OPCLKDIV */
+			opclk_div = (3 * f_mclk / 4 + f_opclk - 1) / f_opclk;
+		else
+			opclk_div = 1;
+
+		dev_dbg(component->dev, "%s: OPCLKDIV=%d\n", __func__, opclk_div);
+
+		snd_soc_component_update_bits(component, WM8978_GPIO_CONTROL, 0x30,
+				    (opclk_div - 1) << 4);
+
+		wm8978->f_pllout = f_opclk * opclk_div;
+	} else if (f_256fs) {
+		/*
+		 * Not using OPCLK, but PLL is used for the codec, choose R:
+		 * 6 <= R = f2 / f1 < 13, to put 1 <= MCLKDIV <= 12.
+		 * f_256fs = f_mclk * prescale * R / 4 / MCLKDIV, where
+		 * prescale = 1, or prescale = 2. Prescale is calculated inside
+		 * pll_factors(). We have to select f_PLLOUT, such that
+		 * f_mclk * 3 / 4 <= f_PLLOUT < f_mclk * 13 / 4. Must be
+		 * f_mclk * 3 / 48 <= f_256fs < f_mclk * 13 / 4. This means MCLK
+		 * must be 3.781MHz <= f_MCLK <= 32.768MHz
+		 */
+		int idx = wm8978_enum_mclk(f_256fs, f_mclk, &wm8978->f_pllout);
+		if (idx < 0)
+			return idx;
+
+		wm8978->mclk_idx = idx;
+	} else {
+		return -EINVAL;
+	}
+
+	f2 = wm8978->f_pllout * 4;
+
+	dev_dbg(component->dev, "%s: f_MCLK=%uHz, f_PLLOUT=%uHz\n", __func__,
+		wm8978->f_mclk, wm8978->f_pllout);
+
+	pll_factors(component, &pll_div, f2, wm8978->f_mclk);
+
+	dev_dbg(component->dev, "%s: calculated PLL N=0x%x, K=0x%x, div2=%d\n",
+		__func__, pll_div.n, pll_div.k, pll_div.div2);
+
+	/* Turn PLL off for configuration... */
+	snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, 0x20, 0);
+
+	snd_soc_component_write(component, WM8978_PLL_N, (pll_div.div2 << 4) | pll_div.n);
+	snd_soc_component_write(component, WM8978_PLL_K1, pll_div.k >> 18);
+	snd_soc_component_write(component, WM8978_PLL_K2, (pll_div.k >> 9) & 0x1ff);
+	snd_soc_component_write(component, WM8978_PLL_K3, pll_div.k & 0x1ff);
+
+	/* ...and on again */
+	snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, 0x20, 0x20);
+
+	if (f_opclk)
+		/* Output PLL (OPCLK) to GPIO1 */
+		snd_soc_component_update_bits(component, WM8978_GPIO_CONTROL, 7, 4);
+
+	return 0;
+}
+
+/*
+ * Configure WM8978 clock dividers.
+ */
+static int wm8978_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+				 int div_id, int div)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	switch (div_id) {
+	case WM8978_OPCLKRATE:
+		wm8978->f_opclk = div;
+
+		if (wm8978->f_mclk)
+			/*
+			 * We know the MCLK frequency, the user has requested
+			 * OPCLK, configure the PLL based on that and start it
+			 * and OPCLK immediately. We will configure PLL to match
+			 * user-requested OPCLK frquency as good as possible.
+			 * In fact, it is likely, that matching the sampling
+			 * rate, when it becomes known, is more important, and
+			 * we will not be reconfiguring PLL then, because we
+			 * must not interrupt OPCLK. But it should be fine,
+			 * because typically the user will request OPCLK to run
+			 * at 256fs or 512fs, and for these cases we will also
+			 * find an exact MCLK divider configuration - it will
+			 * be equal to or double the OPCLK divisor.
+			 */
+			ret = wm8978_configure_pll(component);
+		break;
+	case WM8978_BCLKDIV:
+		if (div & ~0x1c)
+			return -EINVAL;
+		snd_soc_component_update_bits(component, WM8978_CLOCKING, 0x1c, div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dev_dbg(component->dev, "%s: ID %d, value %u\n", __func__, div_id, div);
+
+	return ret;
+}
+
+/*
+ * @freq:	when .set_pll() us not used, freq is codec MCLK input frequency
+ */
+static int wm8978_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
+				 unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	dev_dbg(component->dev, "%s: ID %d, freq %u\n", __func__, clk_id, freq);
+
+	if (freq) {
+		wm8978->f_mclk = freq;
+
+		/* Even if MCLK is used for system clock, might have to drive OPCLK */
+		if (wm8978->f_opclk)
+			ret = wm8978_configure_pll(component);
+
+		/* Our sysclk is fixed to 256 * fs, will configure in .hw_params()  */
+
+		if (!ret)
+			wm8978->sysclk = clk_id;
+	}
+
+	if (wm8978->sysclk == WM8978_PLL && (!freq || clk_id == WM8978_MCLK)) {
+		/* Clock CODEC directly from MCLK */
+		snd_soc_component_update_bits(component, WM8978_CLOCKING, 0x100, 0);
+
+		/* GPIO1 into default mode as input - before configuring PLL */
+		snd_soc_component_update_bits(component, WM8978_GPIO_CONTROL, 7, 0);
+
+		/* Turn off PLL */
+		snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, 0x20, 0);
+		wm8978->sysclk = WM8978_MCLK;
+		wm8978->f_pllout = 0;
+		wm8978->f_opclk = 0;
+	}
+
+	return ret;
+}
+
+/*
+ * Set ADC and Voice DAC format.
+ */
+static int wm8978_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	/*
+	 * BCLK polarity mask = 0x100, LRC clock polarity mask = 0x80,
+	 * Data Format mask = 0x18: all will be calculated anew
+	 */
+	u16 iface = snd_soc_component_read32(component, WM8978_AUDIO_INTERFACE) & ~0x198;
+	u16 clk = snd_soc_component_read32(component, WM8978_CLOCKING);
+
+	dev_dbg(component->dev, "%s\n", __func__);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		clk |= 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		clk &= ~1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x10;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x8;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x18;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x180;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x100;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x80;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8978_AUDIO_INTERFACE, iface);
+	snd_soc_component_write(component, WM8978_CLOCKING, clk);
+
+	return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ */
+static int wm8978_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
+	/* Word length mask = 0x60 */
+	u16 iface_ctl = snd_soc_component_read32(component, WM8978_AUDIO_INTERFACE) & ~0x60;
+	/* Sampling rate mask = 0xe (for filters) */
+	u16 add_ctl = snd_soc_component_read32(component, WM8978_ADDITIONAL_CONTROL) & ~0xe;
+	u16 clking = snd_soc_component_read32(component, WM8978_CLOCKING);
+	enum wm8978_sysclk_src current_clk_id = clking & 0x100 ?
+		WM8978_PLL : WM8978_MCLK;
+	unsigned int f_sel, diff, diff_best = INT_MAX;
+	int i, best = 0;
+
+	if (!wm8978->f_mclk)
+		return -EINVAL;
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		iface_ctl |= 0x20;
+		break;
+	case 24:
+		iface_ctl |= 0x40;
+		break;
+	case 32:
+		iface_ctl |= 0x60;
+		break;
+	}
+
+	/* filter coefficient */
+	switch (params_rate(params)) {
+	case 8000:
+		add_ctl |= 0x5 << 1;
+		break;
+	case 11025:
+		add_ctl |= 0x4 << 1;
+		break;
+	case 16000:
+		add_ctl |= 0x3 << 1;
+		break;
+	case 22050:
+		add_ctl |= 0x2 << 1;
+		break;
+	case 32000:
+		add_ctl |= 0x1 << 1;
+		break;
+	case 44100:
+	case 48000:
+		break;
+	}
+
+	/* Sampling rate is known now, can configure the MCLK divider */
+	wm8978->f_256fs = params_rate(params) * 256;
+
+	if (wm8978->sysclk == WM8978_MCLK) {
+		wm8978->mclk_idx = -1;
+		f_sel = wm8978->f_mclk;
+	} else {
+		if (!wm8978->f_opclk) {
+			/* We only enter here, if OPCLK is not used */
+			int ret = wm8978_configure_pll(component);
+			if (ret < 0)
+				return ret;
+		}
+		f_sel = wm8978->f_pllout;
+	}
+
+	if (wm8978->mclk_idx < 0) {
+		/* Either MCLK is used directly, or OPCLK is used */
+		if (f_sel < wm8978->f_256fs || f_sel > 12 * wm8978->f_256fs)
+			return -EINVAL;
+
+		for (i = 0; i < ARRAY_SIZE(mclk_numerator); i++) {
+			diff = abs(wm8978->f_256fs * 3 -
+				   f_sel * 3 * mclk_denominator[i] / mclk_numerator[i]);
+
+			if (diff < diff_best) {
+				diff_best = diff;
+				best = i;
+			}
+
+			if (!diff)
+				break;
+		}
+	} else {
+		/* OPCLK not used, codec driven by PLL */
+		best = wm8978->mclk_idx;
+		diff = 0;
+	}
+
+	if (diff)
+		dev_warn(component->dev, "Imprecise sampling rate: %uHz%s\n",
+			f_sel * mclk_denominator[best] / mclk_numerator[best] / 256,
+			wm8978->sysclk == WM8978_MCLK ?
+			", consider using PLL" : "");
+
+	dev_dbg(component->dev, "%s: width %d, rate %u, MCLK divisor #%d\n", __func__,
+		params_width(params), params_rate(params), best);
+
+	/* MCLK divisor mask = 0xe0 */
+	snd_soc_component_update_bits(component, WM8978_CLOCKING, 0xe0, best << 5);
+
+	snd_soc_component_write(component, WM8978_AUDIO_INTERFACE, iface_ctl);
+	snd_soc_component_write(component, WM8978_ADDITIONAL_CONTROL, add_ctl);
+
+	if (wm8978->sysclk != current_clk_id) {
+		if (wm8978->sysclk == WM8978_PLL)
+			/* Run CODEC from PLL instead of MCLK */
+			snd_soc_component_update_bits(component, WM8978_CLOCKING,
+					    0x100, 0x100);
+		else
+			/* Clock CODEC directly from MCLK */
+			snd_soc_component_update_bits(component, WM8978_CLOCKING, 0x100, 0);
+	}
+
+	return 0;
+}
+
+static int wm8978_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+
+	dev_dbg(component->dev, "%s: %d\n", __func__, mute);
+
+	if (mute)
+		snd_soc_component_update_bits(component, WM8978_DAC_CONTROL, 0x40, 0x40);
+	else
+		snd_soc_component_update_bits(component, WM8978_DAC_CONTROL, 0x40, 0);
+
+	return 0;
+}
+
+static int wm8978_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	u16 power1 = snd_soc_component_read32(component, WM8978_POWER_MANAGEMENT_1) & ~3;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		power1 |= 1;  /* VMID 75k */
+		snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_1, power1);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* bit 3: enable bias, bit 2: enable I/O tie off buffer */
+		power1 |= 0xc;
+
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/* Initial cap charge at VMID 5k */
+			snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_1,
+				      power1 | 0x3);
+			mdelay(100);
+		}
+
+		power1 |= 0x2;  /* VMID 500k */
+		snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_1, power1);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* Preserve PLL - OPCLK may be used by someone */
+		snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, ~0x20, 0);
+		snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_2, 0);
+		snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_3, 0);
+		break;
+	}
+
+	dev_dbg(component->dev, "%s: %d, %x\n", __func__, level, power1);
+
+	return 0;
+}
+
+#define WM8978_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8978_dai_ops = {
+	.hw_params	= wm8978_hw_params,
+	.digital_mute	= wm8978_mute,
+	.set_fmt	= wm8978_set_dai_fmt,
+	.set_clkdiv	= wm8978_set_dai_clkdiv,
+	.set_sysclk	= wm8978_set_dai_sysclk,
+};
+
+/* Also supports 12kHz */
+static struct snd_soc_dai_driver wm8978_dai = {
+	.name = "wm8978-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = WM8978_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = WM8978_FORMATS,
+	},
+	.ops = &wm8978_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int wm8978_suspend(struct snd_soc_component *component)
+{
+	struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+	/* Also switch PLL off */
+	snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_1, 0);
+
+	regcache_mark_dirty(wm8978->regmap);
+
+	return 0;
+}
+
+static int wm8978_resume(struct snd_soc_component *component)
+{
+	struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
+
+	/* Sync reg_cache with the hardware */
+	regcache_sync(wm8978->regmap);
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	if (wm8978->f_pllout)
+		/* Switch PLL on */
+		snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, 0x20, 0x20);
+
+	return 0;
+}
+
+/*
+ * These registers contain an "update" bit - bit 8. This means, for example,
+ * that one can write new DAC digital volume for both channels, but only when
+ * the update bit is set, will also the volume be updated - simultaneously for
+ * both channels.
+ */
+static const int update_reg[] = {
+	WM8978_LEFT_DAC_DIGITAL_VOLUME,
+	WM8978_RIGHT_DAC_DIGITAL_VOLUME,
+	WM8978_LEFT_ADC_DIGITAL_VOLUME,
+	WM8978_RIGHT_ADC_DIGITAL_VOLUME,
+	WM8978_LEFT_INP_PGA_CONTROL,
+	WM8978_RIGHT_INP_PGA_CONTROL,
+	WM8978_LOUT1_HP_CONTROL,
+	WM8978_ROUT1_HP_CONTROL,
+	WM8978_LOUT2_SPK_CONTROL,
+	WM8978_ROUT2_SPK_CONTROL,
+};
+
+static int wm8978_probe(struct snd_soc_component *component)
+{
+	struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
+	int i;
+
+	/*
+	 * Set default system clock to PLL, it is more precise, this is also the
+	 * default hardware setting
+	 */
+	wm8978->sysclk = WM8978_PLL;
+
+	/*
+	 * Set the update bit in all registers, that have one. This way all
+	 * writes to those registers will also cause the update bit to be
+	 * written.
+	 */
+	for (i = 0; i < ARRAY_SIZE(update_reg); i++)
+		snd_soc_component_update_bits(component, update_reg[i], 0x100, 0x100);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8978 = {
+	.probe			= wm8978_probe,
+	.suspend		= wm8978_suspend,
+	.resume			= wm8978_resume,
+	.set_bias_level		= wm8978_set_bias_level,
+	.controls		= wm8978_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8978_snd_controls),
+	.dapm_widgets		= wm8978_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8978_dapm_widgets),
+	.dapm_routes		= wm8978_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8978_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8978_regmap_config = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = WM8978_MAX_REGISTER,
+	.volatile_reg = wm8978_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8978_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8978_reg_defaults),
+};
+
+static int wm8978_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8978_priv *wm8978;
+	int ret;
+
+	wm8978 = devm_kzalloc(&i2c->dev, sizeof(struct wm8978_priv),
+			      GFP_KERNEL);
+	if (wm8978 == NULL)
+		return -ENOMEM;
+
+	wm8978->regmap = devm_regmap_init_i2c(i2c, &wm8978_regmap_config);
+	if (IS_ERR(wm8978->regmap)) {
+		ret = PTR_ERR(wm8978->regmap);
+		dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, wm8978);
+
+	/* Reset the codec */
+	ret = regmap_write(wm8978->regmap, WM8978_RESET, 0);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8978, &wm8978_dai, 1);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct i2c_device_id wm8978_i2c_id[] = {
+	{ "wm8978", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id);
+
+static const struct of_device_id wm8978_of_match[] = {
+	{ .compatible = "wlf,wm8978", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, wm8978_of_match);
+
+static struct i2c_driver wm8978_i2c_driver = {
+	.driver = {
+		.name = "wm8978",
+		.of_match_table = wm8978_of_match,
+	},
+	.probe =    wm8978_i2c_probe,
+	.id_table = wm8978_i2c_id,
+};
+
+module_i2c_driver(wm8978_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8978 codec driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8978.h b/sound/soc/codecs/wm8978.h
new file mode 100644
index 0000000..0dcf686
--- /dev/null
+++ b/sound/soc/codecs/wm8978.h
@@ -0,0 +1,85 @@
+/*
+ * wm8978.h		--  codec driver for WM8978
+ *
+ * Copyright 2009 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __WM8978_H__
+#define __WM8978_H__
+
+/*
+ * Register values.
+ */
+#define WM8978_RESET				0x00
+#define WM8978_POWER_MANAGEMENT_1		0x01
+#define WM8978_POWER_MANAGEMENT_2		0x02
+#define WM8978_POWER_MANAGEMENT_3		0x03
+#define WM8978_AUDIO_INTERFACE			0x04
+#define WM8978_COMPANDING_CONTROL		0x05
+#define WM8978_CLOCKING				0x06
+#define WM8978_ADDITIONAL_CONTROL		0x07
+#define WM8978_GPIO_CONTROL			0x08
+#define WM8978_JACK_DETECT_CONTROL_1		0x09
+#define WM8978_DAC_CONTROL			0x0A
+#define WM8978_LEFT_DAC_DIGITAL_VOLUME		0x0B
+#define WM8978_RIGHT_DAC_DIGITAL_VOLUME		0x0C
+#define WM8978_JACK_DETECT_CONTROL_2		0x0D
+#define WM8978_ADC_CONTROL			0x0E
+#define WM8978_LEFT_ADC_DIGITAL_VOLUME		0x0F
+#define WM8978_RIGHT_ADC_DIGITAL_VOLUME		0x10
+#define WM8978_EQ1				0x12
+#define WM8978_EQ2				0x13
+#define WM8978_EQ3				0x14
+#define WM8978_EQ4				0x15
+#define WM8978_EQ5				0x16
+#define WM8978_DAC_LIMITER_1			0x18
+#define WM8978_DAC_LIMITER_2			0x19
+#define WM8978_NOTCH_FILTER_1			0x1b
+#define WM8978_NOTCH_FILTER_2			0x1c
+#define WM8978_NOTCH_FILTER_3			0x1d
+#define WM8978_NOTCH_FILTER_4			0x1e
+#define WM8978_ALC_CONTROL_1			0x20
+#define WM8978_ALC_CONTROL_2			0x21
+#define WM8978_ALC_CONTROL_3			0x22
+#define WM8978_NOISE_GATE			0x23
+#define WM8978_PLL_N				0x24
+#define WM8978_PLL_K1				0x25
+#define WM8978_PLL_K2				0x26
+#define WM8978_PLL_K3				0x27
+#define WM8978_3D_CONTROL			0x29
+#define WM8978_BEEP_CONTROL			0x2b
+#define WM8978_INPUT_CONTROL			0x2c
+#define WM8978_LEFT_INP_PGA_CONTROL		0x2d
+#define WM8978_RIGHT_INP_PGA_CONTROL		0x2e
+#define WM8978_LEFT_ADC_BOOST_CONTROL		0x2f
+#define WM8978_RIGHT_ADC_BOOST_CONTROL		0x30
+#define WM8978_OUTPUT_CONTROL			0x31
+#define WM8978_LEFT_MIXER_CONTROL		0x32
+#define WM8978_RIGHT_MIXER_CONTROL		0x33
+#define WM8978_LOUT1_HP_CONTROL			0x34
+#define WM8978_ROUT1_HP_CONTROL			0x35
+#define WM8978_LOUT2_SPK_CONTROL		0x36
+#define WM8978_ROUT2_SPK_CONTROL		0x37
+#define WM8978_OUT3_MIXER_CONTROL		0x38
+#define WM8978_OUT4_MIXER_CONTROL		0x39
+
+#define WM8978_MAX_REGISTER			0x39
+
+#define WM8978_CACHEREGNUM			58
+
+/* Clock divider Id's */
+enum wm8978_clk_id {
+	WM8978_OPCLKRATE,
+	WM8978_BCLKDIV,
+};
+
+enum wm8978_sysclk_src {
+	WM8978_MCLK = 0,
+	WM8978_PLL,
+};
+
+#endif	/* __WM8978_H__ */
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
new file mode 100644
index 0000000..9f35801
--- /dev/null
+++ b/sound/soc/codecs/wm8983.c
@@ -0,0 +1,1115 @@
+/*
+ * wm8983.c  --  WM8983 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8983.h"
+
+static const struct reg_default wm8983_defaults[] = {
+	{ 0x01, 0x0000 },     /* R1  - Power management 1 */
+	{ 0x02, 0x0000 },     /* R2  - Power management 2 */
+	{ 0x03, 0x0000 },     /* R3  - Power management 3 */
+	{ 0x04, 0x0050 },     /* R4  - Audio Interface */
+	{ 0x05, 0x0000 },     /* R5  - Companding control */
+	{ 0x06, 0x0140 },     /* R6  - Clock Gen control */
+	{ 0x07, 0x0000 },     /* R7  - Additional control */
+	{ 0x08, 0x0000 },     /* R8  - GPIO Control */
+	{ 0x09, 0x0000 },     /* R9  - Jack Detect Control 1 */
+	{ 0x0A, 0x0000 },     /* R10 - DAC Control */
+	{ 0x0B, 0x00FF },     /* R11 - Left DAC digital Vol */
+	{ 0x0C, 0x00FF },     /* R12 - Right DAC digital vol */
+	{ 0x0D, 0x0000 },     /* R13 - Jack Detect Control 2 */
+	{ 0x0E, 0x0100 },     /* R14 - ADC Control */
+	{ 0x0F, 0x00FF },     /* R15 - Left ADC Digital Vol */
+	{ 0x10, 0x00FF },     /* R16 - Right ADC Digital Vol */
+	{ 0x12, 0x012C },     /* R18 - EQ1 - low shelf */
+	{ 0x13, 0x002C },     /* R19 - EQ2 - peak 1 */
+	{ 0x14, 0x002C },     /* R20 - EQ3 - peak 2 */
+	{ 0x15, 0x002C },     /* R21 - EQ4 - peak 3 */
+	{ 0x16, 0x002C },     /* R22 - EQ5 - high shelf */
+	{ 0x18, 0x0032 },     /* R24 - DAC Limiter 1 */
+	{ 0x19, 0x0000 },     /* R25 - DAC Limiter 2 */
+	{ 0x1B, 0x0000 },     /* R27 - Notch Filter 1 */
+	{ 0x1C, 0x0000 },     /* R28 - Notch Filter 2 */
+	{ 0x1D, 0x0000 },     /* R29 - Notch Filter 3 */
+	{ 0x1E, 0x0000 },     /* R30 - Notch Filter 4 */
+	{ 0x20, 0x0038 },     /* R32 - ALC control 1 */
+	{ 0x21, 0x000B },     /* R33 - ALC control 2 */
+	{ 0x22, 0x0032 },     /* R34 - ALC control 3 */
+	{ 0x23, 0x0000 },     /* R35 - Noise Gate */
+	{ 0x24, 0x0008 },     /* R36 - PLL N */
+	{ 0x25, 0x000C },     /* R37 - PLL K 1 */
+	{ 0x26, 0x0093 },     /* R38 - PLL K 2 */
+	{ 0x27, 0x00E9 },     /* R39 - PLL K 3 */
+	{ 0x29, 0x0000 },     /* R41 - 3D control */
+	{ 0x2A, 0x0000 },     /* R42 - OUT4 to ADC */
+	{ 0x2B, 0x0000 },     /* R43 - Beep control */
+	{ 0x2C, 0x0033 },     /* R44 - Input ctrl */
+	{ 0x2D, 0x0010 },     /* R45 - Left INP PGA gain ctrl */
+	{ 0x2E, 0x0010 },     /* R46 - Right INP PGA gain ctrl */
+	{ 0x2F, 0x0100 },     /* R47 - Left ADC BOOST ctrl */
+	{ 0x30, 0x0100 },     /* R48 - Right ADC BOOST ctrl */
+	{ 0x31, 0x0002 },     /* R49 - Output ctrl */
+	{ 0x32, 0x0001 },     /* R50 - Left mixer ctrl */
+	{ 0x33, 0x0001 },     /* R51 - Right mixer ctrl */
+	{ 0x34, 0x0039 },     /* R52 - LOUT1 (HP) volume ctrl */
+	{ 0x35, 0x0039 },     /* R53 - ROUT1 (HP) volume ctrl */
+	{ 0x36, 0x0039 },     /* R54 - LOUT2 (SPK) volume ctrl */
+	{ 0x37, 0x0039 },     /* R55 - ROUT2 (SPK) volume ctrl */
+	{ 0x38, 0x0001 },     /* R56 - OUT3 mixer ctrl */
+	{ 0x39, 0x0001 },     /* R57 - OUT4 (MONO) mix ctrl */
+	{ 0x3D, 0x0000 },      /* R61 - BIAS CTRL */
+};
+
+/* vol/gain update regs */
+static const int vol_update_regs[] = {
+	WM8983_LEFT_DAC_DIGITAL_VOL,
+	WM8983_RIGHT_DAC_DIGITAL_VOL,
+	WM8983_LEFT_ADC_DIGITAL_VOL,
+	WM8983_RIGHT_ADC_DIGITAL_VOL,
+	WM8983_LOUT1_HP_VOLUME_CTRL,
+	WM8983_ROUT1_HP_VOLUME_CTRL,
+	WM8983_LOUT2_SPK_VOLUME_CTRL,
+	WM8983_ROUT2_SPK_VOLUME_CTRL,
+	WM8983_LEFT_INP_PGA_GAIN_CTRL,
+	WM8983_RIGHT_INP_PGA_GAIN_CTRL
+};
+
+struct wm8983_priv {
+	struct regmap *regmap;
+	u32 sysclk;
+	u32 bclk;
+};
+
+static const struct {
+	int div;
+	int ratio;
+} fs_ratios[] = {
+	{ 10, 128 },
+	{ 15, 192 },
+	{ 20, 256 },
+	{ 30, 384 },
+	{ 40, 512 },
+	{ 60, 768 },
+	{ 80, 1024 },
+	{ 120, 1536 }
+};
+
+static const int srates[] = { 48000, 32000, 24000, 16000, 12000, 8000 };
+
+static const int bclk_divs[] = {
+	1, 2, 4, 8, 16, 32
+};
+
+static int eqmode_get(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol);
+static int eqmode_put(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol);
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lim_thresh_tlv, -600, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lim_boost_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(alc_min_tlv, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_max_tlv, -675, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_tar_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(pga_vol_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, -1200, 300, 1);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(aux_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0);
+
+static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" };
+static SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7, alc_sel_text);
+
+static const char *alc_mode_text[] = { "ALC", "Limiter" };
+static SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8, alc_mode_text);
+
+static const char *filter_mode_text[] = { "Audio", "Application" };
+static SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7,
+			    filter_mode_text);
+
+static const char *eq_bw_text[] = { "Narrow", "Wide" };
+static const char *eqmode_text[] = { "Capture", "Playback" };
+static SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
+
+static const char *eq1_cutoff_text[] = {
+	"80Hz", "105Hz", "135Hz", "175Hz"
+};
+static SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5,
+			    eq1_cutoff_text);
+static const char *eq2_cutoff_text[] = {
+	"230Hz", "300Hz", "385Hz", "500Hz"
+};
+static SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5, eq2_cutoff_text);
+static const char *eq3_cutoff_text[] = {
+	"650Hz", "850Hz", "1.1kHz", "1.4kHz"
+};
+static SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5, eq3_cutoff_text);
+static const char *eq4_cutoff_text[] = {
+	"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"
+};
+static SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5, eq4_cutoff_text);
+static const char *eq5_cutoff_text[] = {
+	"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"
+};
+static SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5,
+			    eq5_cutoff_text);
+
+static const char *depth_3d_text[] = {
+	"Off",
+	"6.67%",
+	"13.3%",
+	"20%",
+	"26.7%",
+	"33.3%",
+	"40%",
+	"46.6%",
+	"53.3%",
+	"60%",
+	"66.7%",
+	"73.3%",
+	"80%",
+	"86.7%",
+	"93.3%",
+	"100%"
+};
+static SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0,
+			    depth_3d_text);
+
+static const struct snd_kcontrol_new wm8983_snd_controls[] = {
+	SOC_SINGLE("Digital Loopback Switch", WM8983_COMPANDING_CONTROL,
+		   0, 1, 0),
+
+	SOC_ENUM("ALC Capture Function", alc_sel),
+	SOC_SINGLE_TLV("ALC Capture Max Volume", WM8983_ALC_CONTROL_1,
+		       3, 7, 0, alc_max_tlv),
+	SOC_SINGLE_TLV("ALC Capture Min Volume", WM8983_ALC_CONTROL_1,
+		       0, 7, 0, alc_min_tlv),
+	SOC_SINGLE_TLV("ALC Capture Target Volume", WM8983_ALC_CONTROL_2,
+		       0, 15, 0, alc_tar_tlv),
+	SOC_SINGLE("ALC Capture Attack", WM8983_ALC_CONTROL_3, 0, 10, 0),
+	SOC_SINGLE("ALC Capture Hold", WM8983_ALC_CONTROL_2, 4, 10, 0),
+	SOC_SINGLE("ALC Capture Decay", WM8983_ALC_CONTROL_3, 4, 10, 0),
+	SOC_ENUM("ALC Mode", alc_mode),
+	SOC_SINGLE("ALC Capture NG Switch", WM8983_NOISE_GATE,
+		   3, 1, 0),
+	SOC_SINGLE("ALC Capture NG Threshold", WM8983_NOISE_GATE,
+		   0, 7, 1),
+
+	SOC_DOUBLE_R_TLV("Capture Volume", WM8983_LEFT_ADC_DIGITAL_VOL,
+			 WM8983_RIGHT_ADC_DIGITAL_VOL, 0, 255, 0, adc_tlv),
+	SOC_DOUBLE_R("Capture PGA ZC Switch", WM8983_LEFT_INP_PGA_GAIN_CTRL,
+		     WM8983_RIGHT_INP_PGA_GAIN_CTRL, 7, 1, 0),
+	SOC_DOUBLE_R_TLV("Capture PGA Volume", WM8983_LEFT_INP_PGA_GAIN_CTRL,
+			 WM8983_RIGHT_INP_PGA_GAIN_CTRL, 0, 63, 0, pga_vol_tlv),
+
+	SOC_DOUBLE_R_TLV("Capture PGA Boost Volume",
+			 WM8983_LEFT_ADC_BOOST_CTRL, WM8983_RIGHT_ADC_BOOST_CTRL,
+			 8, 1, 0, pga_boost_tlv),
+
+	SOC_DOUBLE("ADC Inversion Switch", WM8983_ADC_CONTROL, 0, 1, 1, 0),
+	SOC_SINGLE("ADC 128x Oversampling Switch", WM8983_ADC_CONTROL, 8, 1, 0),
+
+	SOC_DOUBLE_R_TLV("Playback Volume", WM8983_LEFT_DAC_DIGITAL_VOL,
+			 WM8983_RIGHT_DAC_DIGITAL_VOL, 0, 255, 0, dac_tlv),
+
+	SOC_SINGLE("DAC Playback Limiter Switch", WM8983_DAC_LIMITER_1, 8, 1, 0),
+	SOC_SINGLE("DAC Playback Limiter Decay", WM8983_DAC_LIMITER_1, 4, 10, 0),
+	SOC_SINGLE("DAC Playback Limiter Attack", WM8983_DAC_LIMITER_1, 0, 11, 0),
+	SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8983_DAC_LIMITER_2,
+		       4, 7, 1, lim_thresh_tlv),
+	SOC_SINGLE_TLV("DAC Playback Limiter Boost Volume", WM8983_DAC_LIMITER_2,
+		       0, 12, 0, lim_boost_tlv),
+	SOC_DOUBLE("DAC Inversion Switch", WM8983_DAC_CONTROL, 0, 1, 1, 0),
+	SOC_SINGLE("DAC Auto Mute Switch", WM8983_DAC_CONTROL, 2, 1, 0),
+	SOC_SINGLE("DAC 128x Oversampling Switch", WM8983_DAC_CONTROL, 3, 1, 0),
+
+	SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8983_LOUT1_HP_VOLUME_CTRL,
+			 WM8983_ROUT1_HP_VOLUME_CTRL, 0, 63, 0, out_tlv),
+	SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8983_LOUT1_HP_VOLUME_CTRL,
+		     WM8983_ROUT1_HP_VOLUME_CTRL, 7, 1, 0),
+	SOC_DOUBLE_R("Headphone Switch", WM8983_LOUT1_HP_VOLUME_CTRL,
+		     WM8983_ROUT1_HP_VOLUME_CTRL, 6, 1, 1),
+
+	SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8983_LOUT2_SPK_VOLUME_CTRL,
+			 WM8983_ROUT2_SPK_VOLUME_CTRL, 0, 63, 0, out_tlv),
+	SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8983_LOUT2_SPK_VOLUME_CTRL,
+		     WM8983_ROUT2_SPK_VOLUME_CTRL, 7, 1, 0),
+	SOC_DOUBLE_R("Speaker Switch", WM8983_LOUT2_SPK_VOLUME_CTRL,
+		     WM8983_ROUT2_SPK_VOLUME_CTRL, 6, 1, 1),
+
+	SOC_SINGLE("OUT3 Switch", WM8983_OUT3_MIXER_CTRL,
+		   6, 1, 1),
+
+	SOC_SINGLE("OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL,
+		   6, 1, 1),
+
+	SOC_SINGLE("High Pass Filter Switch", WM8983_ADC_CONTROL, 8, 1, 0),
+	SOC_ENUM("High Pass Filter Mode", filter_mode),
+	SOC_SINGLE("High Pass Filter Cutoff", WM8983_ADC_CONTROL, 4, 7, 0),
+
+	SOC_DOUBLE_R_TLV("Aux Bypass Volume",
+			 WM8983_LEFT_MIXER_CTRL, WM8983_RIGHT_MIXER_CTRL, 6, 7, 0,
+			 aux_tlv),
+
+	SOC_DOUBLE_R_TLV("Input PGA Bypass Volume",
+			 WM8983_LEFT_MIXER_CTRL, WM8983_RIGHT_MIXER_CTRL, 2, 7, 0,
+			 bypass_tlv),
+
+	SOC_ENUM_EXT("Equalizer Function", eqmode, eqmode_get, eqmode_put),
+	SOC_ENUM("EQ1 Cutoff", eq1_cutoff),
+	SOC_SINGLE_TLV("EQ1 Volume", WM8983_EQ1_LOW_SHELF,  0, 24, 1, eq_tlv),
+	SOC_ENUM("EQ2 Bandwidth", eq2_bw),
+	SOC_ENUM("EQ2 Cutoff", eq2_cutoff),
+	SOC_SINGLE_TLV("EQ2 Volume", WM8983_EQ2_PEAK_1, 0, 24, 1, eq_tlv),
+	SOC_ENUM("EQ3 Bandwidth", eq3_bw),
+	SOC_ENUM("EQ3 Cutoff", eq3_cutoff),
+	SOC_SINGLE_TLV("EQ3 Volume", WM8983_EQ3_PEAK_2, 0, 24, 1, eq_tlv),
+	SOC_ENUM("EQ4 Bandwidth", eq4_bw),
+	SOC_ENUM("EQ4 Cutoff", eq4_cutoff),
+	SOC_SINGLE_TLV("EQ4 Volume", WM8983_EQ4_PEAK_3, 0, 24, 1, eq_tlv),
+	SOC_ENUM("EQ5 Cutoff", eq5_cutoff),
+	SOC_SINGLE_TLV("EQ5 Volume", WM8983_EQ5_HIGH_SHELF, 0, 24, 1, eq_tlv),
+
+	SOC_ENUM("3D Depth", depth_3d),
+};
+
+static const struct snd_kcontrol_new left_out_mixer[] = {
+	SOC_DAPM_SINGLE("Line Switch", WM8983_LEFT_MIXER_CTRL, 1, 1, 0),
+	SOC_DAPM_SINGLE("Aux Switch", WM8983_LEFT_MIXER_CTRL, 5, 1, 0),
+	SOC_DAPM_SINGLE("PCM Switch", WM8983_LEFT_MIXER_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_out_mixer[] = {
+	SOC_DAPM_SINGLE("Line Switch", WM8983_RIGHT_MIXER_CTRL, 1, 1, 0),
+	SOC_DAPM_SINGLE("Aux Switch", WM8983_RIGHT_MIXER_CTRL, 5, 1, 0),
+	SOC_DAPM_SINGLE("PCM Switch", WM8983_RIGHT_MIXER_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_input_mixer[] = {
+	SOC_DAPM_SINGLE("L2 Switch", WM8983_INPUT_CTRL, 2, 1, 0),
+	SOC_DAPM_SINGLE("MicN Switch", WM8983_INPUT_CTRL, 1, 1, 0),
+	SOC_DAPM_SINGLE("MicP Switch", WM8983_INPUT_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_input_mixer[] = {
+	SOC_DAPM_SINGLE("R2 Switch", WM8983_INPUT_CTRL, 6, 1, 0),
+	SOC_DAPM_SINGLE("MicN Switch", WM8983_INPUT_CTRL, 5, 1, 0),
+	SOC_DAPM_SINGLE("MicP Switch", WM8983_INPUT_CTRL, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_boost_mixer[] = {
+	SOC_DAPM_SINGLE_TLV("L2 Volume", WM8983_LEFT_ADC_BOOST_CTRL,
+			    4, 7, 0, boost_tlv),
+	SOC_DAPM_SINGLE_TLV("AUXL Volume", WM8983_LEFT_ADC_BOOST_CTRL,
+			    0, 7, 0, boost_tlv)
+};
+
+static const struct snd_kcontrol_new out3_mixer[] = {
+	SOC_DAPM_SINGLE("LMIX2OUT3 Switch", WM8983_OUT3_MIXER_CTRL,
+			1, 1, 0),
+	SOC_DAPM_SINGLE("LDAC2OUT3 Switch", WM8983_OUT3_MIXER_CTRL,
+			0, 1, 0),
+};
+
+static const struct snd_kcontrol_new out4_mixer[] = {
+	SOC_DAPM_SINGLE("LMIX2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL,
+			4, 1, 0),
+	SOC_DAPM_SINGLE("RMIX2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL,
+			1, 1, 0),
+	SOC_DAPM_SINGLE("LDAC2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL,
+			3, 1, 0),
+	SOC_DAPM_SINGLE("RDAC2OUT4 Switch", WM8983_OUT4_MONO_MIX_CTRL,
+			0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_boost_mixer[] = {
+	SOC_DAPM_SINGLE_TLV("R2 Volume", WM8983_RIGHT_ADC_BOOST_CTRL,
+			    4, 7, 0, boost_tlv),
+	SOC_DAPM_SINGLE_TLV("AUXR Volume", WM8983_RIGHT_ADC_BOOST_CTRL,
+			    0, 7, 0, boost_tlv)
+};
+
+static const struct snd_soc_dapm_widget wm8983_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8983_POWER_MANAGEMENT_3,
+			 0, 0),
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8983_POWER_MANAGEMENT_3,
+			 1, 0),
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8983_POWER_MANAGEMENT_2,
+			 0, 0),
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8983_POWER_MANAGEMENT_2,
+			 1, 0),
+
+	SND_SOC_DAPM_MIXER("Left Output Mixer", WM8983_POWER_MANAGEMENT_3,
+			   2, 0, left_out_mixer, ARRAY_SIZE(left_out_mixer)),
+	SND_SOC_DAPM_MIXER("Right Output Mixer", WM8983_POWER_MANAGEMENT_3,
+			   3, 0, right_out_mixer, ARRAY_SIZE(right_out_mixer)),
+
+	SND_SOC_DAPM_MIXER("Left Input Mixer", WM8983_POWER_MANAGEMENT_2,
+			   2, 0, left_input_mixer, ARRAY_SIZE(left_input_mixer)),
+	SND_SOC_DAPM_MIXER("Right Input Mixer", WM8983_POWER_MANAGEMENT_2,
+			   3, 0, right_input_mixer, ARRAY_SIZE(right_input_mixer)),
+
+	SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8983_POWER_MANAGEMENT_2,
+			   4, 0, left_boost_mixer, ARRAY_SIZE(left_boost_mixer)),
+	SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8983_POWER_MANAGEMENT_2,
+			   5, 0, right_boost_mixer, ARRAY_SIZE(right_boost_mixer)),
+
+	SND_SOC_DAPM_MIXER("OUT3 Mixer", WM8983_POWER_MANAGEMENT_1,
+			   6, 0, out3_mixer, ARRAY_SIZE(out3_mixer)),
+
+	SND_SOC_DAPM_MIXER("OUT4 Mixer", WM8983_POWER_MANAGEMENT_1,
+			   7, 0, out4_mixer, ARRAY_SIZE(out4_mixer)),
+
+	SND_SOC_DAPM_PGA("Left Capture PGA", WM8983_LEFT_INP_PGA_GAIN_CTRL,
+			 6, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Capture PGA", WM8983_RIGHT_INP_PGA_GAIN_CTRL,
+			 6, 1, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Left Headphone Out", WM8983_POWER_MANAGEMENT_2,
+			 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Headphone Out", WM8983_POWER_MANAGEMENT_2,
+			 8, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Left Speaker Out", WM8983_POWER_MANAGEMENT_3,
+			 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Speaker Out", WM8983_POWER_MANAGEMENT_3,
+			 6, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("OUT3 Out", WM8983_POWER_MANAGEMENT_3,
+			 7, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("OUT4 Out", WM8983_POWER_MANAGEMENT_3,
+			 8, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Mic Bias", WM8983_POWER_MANAGEMENT_1, 4, 0,
+			    NULL, 0),
+
+	SND_SOC_DAPM_INPUT("LIN"),
+	SND_SOC_DAPM_INPUT("LIP"),
+	SND_SOC_DAPM_INPUT("RIN"),
+	SND_SOC_DAPM_INPUT("RIP"),
+	SND_SOC_DAPM_INPUT("AUXL"),
+	SND_SOC_DAPM_INPUT("AUXR"),
+	SND_SOC_DAPM_INPUT("L2"),
+	SND_SOC_DAPM_INPUT("R2"),
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("SPKL"),
+	SND_SOC_DAPM_OUTPUT("SPKR"),
+	SND_SOC_DAPM_OUTPUT("OUT3"),
+	SND_SOC_DAPM_OUTPUT("OUT4")
+};
+
+static const struct snd_soc_dapm_route wm8983_audio_map[] = {
+	{ "OUT3 Mixer", "LMIX2OUT3 Switch", "Left Output Mixer" },
+	{ "OUT3 Mixer", "LDAC2OUT3 Switch", "Left DAC" },
+
+	{ "OUT3 Out", NULL, "OUT3 Mixer" },
+	{ "OUT3", NULL, "OUT3 Out" },
+
+	{ "OUT4 Mixer", "LMIX2OUT4 Switch", "Left Output Mixer" },
+	{ "OUT4 Mixer", "RMIX2OUT4 Switch", "Right Output Mixer" },
+	{ "OUT4 Mixer", "LDAC2OUT4 Switch", "Left DAC" },
+	{ "OUT4 Mixer", "RDAC2OUT4 Switch", "Right DAC" },
+
+	{ "OUT4 Out", NULL, "OUT4 Mixer" },
+	{ "OUT4", NULL, "OUT4 Out" },
+
+	{ "Right Output Mixer", "PCM Switch", "Right DAC" },
+	{ "Right Output Mixer", "Aux Switch", "AUXR" },
+	{ "Right Output Mixer", "Line Switch", "Right Boost Mixer" },
+
+	{ "Left Output Mixer", "PCM Switch", "Left DAC" },
+	{ "Left Output Mixer", "Aux Switch", "AUXL" },
+	{ "Left Output Mixer", "Line Switch", "Left Boost Mixer" },
+
+	{ "Right Headphone Out", NULL, "Right Output Mixer" },
+	{ "HPR", NULL, "Right Headphone Out" },
+
+	{ "Left Headphone Out", NULL, "Left Output Mixer" },
+	{ "HPL", NULL, "Left Headphone Out" },
+
+	{ "Right Speaker Out", NULL, "Right Output Mixer" },
+	{ "SPKR", NULL, "Right Speaker Out" },
+
+	{ "Left Speaker Out", NULL, "Left Output Mixer" },
+	{ "SPKL", NULL, "Left Speaker Out" },
+
+	{ "Right ADC", NULL, "Right Boost Mixer" },
+
+	{ "Right Boost Mixer", "AUXR Volume", "AUXR" },
+	{ "Right Boost Mixer", NULL, "Right Capture PGA" },
+	{ "Right Boost Mixer", "R2 Volume", "R2" },
+
+	{ "Left ADC", NULL, "Left Boost Mixer" },
+
+	{ "Left Boost Mixer", "AUXL Volume", "AUXL" },
+	{ "Left Boost Mixer", NULL, "Left Capture PGA" },
+	{ "Left Boost Mixer", "L2 Volume", "L2" },
+
+	{ "Right Capture PGA", NULL, "Right Input Mixer" },
+	{ "Left Capture PGA", NULL, "Left Input Mixer" },
+
+	{ "Right Input Mixer", "R2 Switch", "R2" },
+	{ "Right Input Mixer", "MicN Switch", "RIN" },
+	{ "Right Input Mixer", "MicP Switch", "RIP" },
+
+	{ "Left Input Mixer", "L2 Switch", "L2" },
+	{ "Left Input Mixer", "MicN Switch", "LIN" },
+	{ "Left Input Mixer", "MicP Switch", "LIP" },
+};
+
+static int eqmode_get(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int reg;
+
+	reg = snd_soc_component_read32(component, WM8983_EQ1_LOW_SHELF);
+	if (reg & WM8983_EQ3DMODE)
+		ucontrol->value.enumerated.item[0] = 1;
+	else
+		ucontrol->value.enumerated.item[0] = 0;
+
+	return 0;
+}
+
+static int eqmode_put(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int regpwr2, regpwr3;
+	unsigned int reg_eq;
+
+	if (ucontrol->value.enumerated.item[0] != 0
+	    && ucontrol->value.enumerated.item[0] != 1)
+		return -EINVAL;
+
+	reg_eq = snd_soc_component_read32(component, WM8983_EQ1_LOW_SHELF);
+	switch ((reg_eq & WM8983_EQ3DMODE) >> WM8983_EQ3DMODE_SHIFT) {
+	case 0:
+		if (!ucontrol->value.enumerated.item[0])
+			return 0;
+		break;
+	case 1:
+		if (ucontrol->value.enumerated.item[0])
+			return 0;
+		break;
+	}
+
+	regpwr2 = snd_soc_component_read32(component, WM8983_POWER_MANAGEMENT_2);
+	regpwr3 = snd_soc_component_read32(component, WM8983_POWER_MANAGEMENT_3);
+	/* disable the DACs and ADCs */
+	snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_2,
+			    WM8983_ADCENR_MASK | WM8983_ADCENL_MASK, 0);
+	snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_3,
+			    WM8983_DACENR_MASK | WM8983_DACENL_MASK, 0);
+	/* set the desired eqmode */
+	snd_soc_component_update_bits(component, WM8983_EQ1_LOW_SHELF,
+			    WM8983_EQ3DMODE_MASK,
+			    ucontrol->value.enumerated.item[0]
+			    << WM8983_EQ3DMODE_SHIFT);
+	/* restore DAC/ADC configuration */
+	snd_soc_component_write(component, WM8983_POWER_MANAGEMENT_2, regpwr2);
+	snd_soc_component_write(component, WM8983_POWER_MANAGEMENT_3, regpwr3);
+	return 0;
+}
+
+static bool wm8983_writeable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8983_SOFTWARE_RESET ... WM8983_RIGHT_ADC_DIGITAL_VOL:
+	case WM8983_EQ1_LOW_SHELF ... WM8983_DAC_LIMITER_2:
+	case WM8983_NOTCH_FILTER_1 ... WM8983_NOTCH_FILTER_4:
+	case WM8983_ALC_CONTROL_1 ... WM8983_PLL_K_3:
+	case WM8983_3D_CONTROL ... WM8983_OUT4_MONO_MIX_CTRL:
+	case WM8983_BIAS_CTRL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int wm8983_dac_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+
+	return snd_soc_component_update_bits(component, WM8983_DAC_CONTROL,
+				   WM8983_SOFTMUTE_MASK,
+				   !!mute << WM8983_SOFTMUTE_SHIFT);
+}
+
+static int wm8983_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 format, master, bcp, lrp;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		format = 0x2;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		format = 0x0;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		format = 0x1;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		format = 0x3;
+		break;
+	default:
+		dev_err(dai->dev, "Unknown dai format\n");
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8983_AUDIO_INTERFACE,
+			    WM8983_FMT_MASK, format << WM8983_FMT_SHIFT);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		master = 0;
+		break;
+	default:
+		dev_err(dai->dev, "Unknown master/slave configuration\n");
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8983_CLOCK_GEN_CONTROL,
+			    WM8983_MS_MASK, master << WM8983_MS_SHIFT);
+
+	/* FIXME: We don't currently support DSP A/B modes */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		dev_err(dai->dev, "DSP A/B modes are not supported\n");
+		return -EINVAL;
+	default:
+		break;
+	}
+
+	bcp = lrp = 0;
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		bcp = lrp = 1;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		bcp = 1;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		lrp = 1;
+		break;
+	default:
+		dev_err(dai->dev, "Unknown polarity configuration\n");
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8983_AUDIO_INTERFACE,
+			    WM8983_LRCP_MASK, lrp << WM8983_LRCP_SHIFT);
+	snd_soc_component_update_bits(component, WM8983_AUDIO_INTERFACE,
+			    WM8983_BCP_MASK, bcp << WM8983_BCP_SHIFT);
+	return 0;
+}
+
+static int wm8983_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	int i;
+	struct snd_soc_component *component = dai->component;
+	struct wm8983_priv *wm8983 = snd_soc_component_get_drvdata(component);
+	u16 blen, srate_idx;
+	u32 tmp;
+	int srate_best;
+	int ret;
+
+	ret = snd_soc_params_to_bclk(params);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to convert params to bclk: %d\n", ret);
+		return ret;
+	}
+
+	wm8983->bclk = ret;
+
+	switch (params_width(params)) {
+	case 16:
+		blen = 0x0;
+		break;
+	case 20:
+		blen = 0x1;
+		break;
+	case 24:
+		blen = 0x2;
+		break;
+	case 32:
+		blen = 0x3;
+		break;
+	default:
+		dev_err(dai->dev, "Unsupported word length %u\n",
+			params_width(params));
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8983_AUDIO_INTERFACE,
+			    WM8983_WL_MASK, blen << WM8983_WL_SHIFT);
+
+	/*
+	 * match to the nearest possible sample rate and rely
+	 * on the array index to configure the SR register
+	 */
+	srate_idx = 0;
+	srate_best = abs(srates[0] - params_rate(params));
+	for (i = 1; i < ARRAY_SIZE(srates); ++i) {
+		if (abs(srates[i] - params_rate(params)) >= srate_best)
+			continue;
+		srate_idx = i;
+		srate_best = abs(srates[i] - params_rate(params));
+	}
+
+	dev_dbg(dai->dev, "Selected SRATE = %d\n", srates[srate_idx]);
+	snd_soc_component_update_bits(component, WM8983_ADDITIONAL_CONTROL,
+			    WM8983_SR_MASK, srate_idx << WM8983_SR_SHIFT);
+
+	dev_dbg(dai->dev, "Target BCLK = %uHz\n", wm8983->bclk);
+	dev_dbg(dai->dev, "SYSCLK = %uHz\n", wm8983->sysclk);
+
+	for (i = 0; i < ARRAY_SIZE(fs_ratios); ++i) {
+		if (wm8983->sysclk / params_rate(params)
+		    == fs_ratios[i].ratio)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(fs_ratios)) {
+		dev_err(dai->dev, "Unable to configure MCLK ratio %u/%u\n",
+			wm8983->sysclk, params_rate(params));
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "MCLK ratio = %dfs\n", fs_ratios[i].ratio);
+	snd_soc_component_update_bits(component, WM8983_CLOCK_GEN_CONTROL,
+			    WM8983_MCLKDIV_MASK, i << WM8983_MCLKDIV_SHIFT);
+
+	/* select the appropriate bclk divider */
+	tmp = (wm8983->sysclk / fs_ratios[i].div) * 10;
+	for (i = 0; i < ARRAY_SIZE(bclk_divs); ++i) {
+		if (wm8983->bclk == tmp / bclk_divs[i])
+			break;
+	}
+
+	if (i == ARRAY_SIZE(bclk_divs)) {
+		dev_err(dai->dev, "No matching BCLK divider found\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "BCLK div = %d\n", i);
+	snd_soc_component_update_bits(component, WM8983_CLOCK_GEN_CONTROL,
+			    WM8983_BCLKDIV_MASK, i << WM8983_BCLKDIV_SHIFT);
+
+	return 0;
+}
+
+struct pll_div {
+	u32 div2:1;
+	u32 n:4;
+	u32 k:24;
+};
+
+#define FIXED_PLL_SIZE ((1ULL << 24) * 10)
+static int pll_factors(struct pll_div *pll_div, unsigned int target,
+		       unsigned int source)
+{
+	u64 Kpart;
+	unsigned long int K, Ndiv, Nmod;
+
+	pll_div->div2 = 0;
+	Ndiv = target / source;
+	if (Ndiv < 6) {
+		source >>= 1;
+		pll_div->div2 = 1;
+		Ndiv = target / source;
+	}
+
+	if (Ndiv < 6 || Ndiv > 12) {
+		printk(KERN_ERR "%s: WM8983 N value is not within"
+		       " the recommended range: %lu\n", __func__, Ndiv);
+		return -EINVAL;
+	}
+	pll_div->n = Ndiv;
+
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (u64)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xffffffff;
+	if ((K % 10) >= 5)
+		K += 5;
+	K /= 10;
+	pll_div->k = K;
+	return 0;
+}
+
+static int wm8983_set_pll(struct snd_soc_dai *dai, int pll_id,
+			  int source, unsigned int freq_in,
+			  unsigned int freq_out)
+{
+	int ret;
+	struct snd_soc_component *component;
+	struct pll_div pll_div;
+
+	component = dai->component;
+	if (!freq_in || !freq_out) {
+		/* disable the PLL */
+		snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
+				    WM8983_PLLEN_MASK, 0);
+		return 0;
+	} else {
+		ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in);
+		if (ret)
+			return ret;
+
+		/* disable the PLL before re-programming it */
+		snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
+				    WM8983_PLLEN_MASK, 0);
+
+		/* set PLLN and PRESCALE */
+		snd_soc_component_write(component, WM8983_PLL_N,
+			(pll_div.div2 << WM8983_PLL_PRESCALE_SHIFT)
+			| pll_div.n);
+		/* set PLLK */
+		snd_soc_component_write(component, WM8983_PLL_K_3, pll_div.k & 0x1ff);
+		snd_soc_component_write(component, WM8983_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
+		snd_soc_component_write(component, WM8983_PLL_K_1, (pll_div.k >> 18));
+		/* enable the PLL */
+		snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
+					WM8983_PLLEN_MASK, WM8983_PLLEN);
+	}
+
+	return 0;
+}
+
+static int wm8983_set_sysclk(struct snd_soc_dai *dai,
+			     int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8983_priv *wm8983 = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case WM8983_CLKSRC_MCLK:
+		snd_soc_component_update_bits(component, WM8983_CLOCK_GEN_CONTROL,
+				    WM8983_CLKSEL_MASK, 0);
+		break;
+	case WM8983_CLKSRC_PLL:
+		snd_soc_component_update_bits(component, WM8983_CLOCK_GEN_CONTROL,
+				    WM8983_CLKSEL_MASK, WM8983_CLKSEL);
+		break;
+	default:
+		dev_err(dai->dev, "Unknown clock source: %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	wm8983->sysclk = freq;
+	return 0;
+}
+
+static int wm8983_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8983_priv *wm8983 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		/* VMID at 100k */
+		snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
+				    WM8983_VMIDSEL_MASK,
+				    1 << WM8983_VMIDSEL_SHIFT);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regcache_sync(wm8983->regmap);
+			if (ret < 0) {
+				dev_err(component->dev, "Failed to sync cache: %d\n", ret);
+				return ret;
+			}
+			/* enable anti-pop features */
+			snd_soc_component_update_bits(component, WM8983_OUT4_TO_ADC,
+					    WM8983_POBCTRL_MASK | WM8983_DELEN_MASK,
+					    WM8983_POBCTRL | WM8983_DELEN);
+			/* enable thermal shutdown */
+			snd_soc_component_update_bits(component, WM8983_OUTPUT_CTRL,
+					    WM8983_TSDEN_MASK, WM8983_TSDEN);
+			/* enable BIASEN */
+			snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
+					    WM8983_BIASEN_MASK, WM8983_BIASEN);
+			/* VMID at 100k */
+			snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
+					    WM8983_VMIDSEL_MASK,
+					    1 << WM8983_VMIDSEL_SHIFT);
+			msleep(250);
+			/* disable anti-pop features */
+			snd_soc_component_update_bits(component, WM8983_OUT4_TO_ADC,
+					    WM8983_POBCTRL_MASK |
+					    WM8983_DELEN_MASK, 0);
+		}
+
+		/* VMID at 500k */
+		snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
+				    WM8983_VMIDSEL_MASK,
+				    2 << WM8983_VMIDSEL_SHIFT);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* disable thermal shutdown */
+		snd_soc_component_update_bits(component, WM8983_OUTPUT_CTRL,
+				    WM8983_TSDEN_MASK, 0);
+		/* disable VMIDSEL and BIASEN */
+		snd_soc_component_update_bits(component, WM8983_POWER_MANAGEMENT_1,
+				    WM8983_VMIDSEL_MASK | WM8983_BIASEN_MASK,
+				    0);
+		/* wait for VMID to discharge */
+		msleep(100);
+		snd_soc_component_write(component, WM8983_POWER_MANAGEMENT_1, 0);
+		snd_soc_component_write(component, WM8983_POWER_MANAGEMENT_2, 0);
+		snd_soc_component_write(component, WM8983_POWER_MANAGEMENT_3, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static int wm8983_probe(struct snd_soc_component *component)
+{
+	int ret;
+	int i;
+
+	ret = snd_soc_component_write(component, WM8983_SOFTWARE_RESET, 0);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
+		return ret;
+	}
+
+	/* set the vol/gain update bits */
+	for (i = 0; i < ARRAY_SIZE(vol_update_regs); ++i)
+		snd_soc_component_update_bits(component, vol_update_regs[i],
+				    0x100, 0x100);
+
+	/* mute all outputs and set PGAs to minimum gain */
+	for (i = WM8983_LOUT1_HP_VOLUME_CTRL;
+	     i <= WM8983_OUT4_MONO_MIX_CTRL; ++i)
+		snd_soc_component_update_bits(component, i, 0x40, 0x40);
+
+	/* enable soft mute */
+	snd_soc_component_update_bits(component, WM8983_DAC_CONTROL,
+			    WM8983_SOFTMUTE_MASK,
+			    WM8983_SOFTMUTE);
+
+	/* enable BIASCUT */
+	snd_soc_component_update_bits(component, WM8983_BIAS_CTRL,
+			    WM8983_BIASCUT, WM8983_BIASCUT);
+	return 0;
+}
+
+static const struct snd_soc_dai_ops wm8983_dai_ops = {
+	.digital_mute = wm8983_dac_mute,
+	.hw_params = wm8983_hw_params,
+	.set_fmt = wm8983_set_fmt,
+	.set_sysclk = wm8983_set_sysclk,
+	.set_pll = wm8983_set_pll
+};
+
+#define WM8983_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm8983_dai = {
+	.name = "wm8983-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = WM8983_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = WM8983_FORMATS,
+	},
+	.ops = &wm8983_dai_ops,
+	.symmetric_rates = 1
+};
+
+static const struct snd_soc_component_driver soc_component_dev_wm8983 = {
+	.probe			= wm8983_probe,
+	.set_bias_level		= wm8983_set_bias_level,
+	.controls		= wm8983_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8983_snd_controls),
+	.dapm_widgets		= wm8983_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8983_dapm_widgets),
+	.dapm_routes		= wm8983_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(wm8983_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8983_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.reg_defaults = wm8983_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8983_defaults),
+	.cache_type = REGCACHE_RBTREE,
+	.max_register = WM8983_MAX_REGISTER,
+
+	.writeable_reg = wm8983_writeable,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8983_spi_probe(struct spi_device *spi)
+{
+	struct wm8983_priv *wm8983;
+	int ret;
+
+	wm8983 = devm_kzalloc(&spi->dev, sizeof *wm8983, GFP_KERNEL);
+	if (!wm8983)
+		return -ENOMEM;
+
+	wm8983->regmap = devm_regmap_init_spi(spi, &wm8983_regmap);
+	if (IS_ERR(wm8983->regmap)) {
+		ret = PTR_ERR(wm8983->regmap);
+		dev_err(&spi->dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
+	spi_set_drvdata(spi, wm8983);
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+				&soc_component_dev_wm8983, &wm8983_dai, 1);
+	return ret;
+}
+
+static struct spi_driver wm8983_spi_driver = {
+	.driver = {
+		.name = "wm8983",
+	},
+	.probe = wm8983_spi_probe,
+};
+#endif
+
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8983_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8983_priv *wm8983;
+	int ret;
+
+	wm8983 = devm_kzalloc(&i2c->dev, sizeof *wm8983, GFP_KERNEL);
+	if (!wm8983)
+		return -ENOMEM;
+
+	wm8983->regmap = devm_regmap_init_i2c(i2c, &wm8983_regmap);
+	if (IS_ERR(wm8983->regmap)) {
+		ret = PTR_ERR(wm8983->regmap);
+		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, wm8983);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				&soc_component_dev_wm8983, &wm8983_dai, 1);
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8983_i2c_id[] = {
+	{ "wm8983", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8983_i2c_id);
+
+static struct i2c_driver wm8983_i2c_driver = {
+	.driver = {
+		.name = "wm8983",
+	},
+	.probe = wm8983_i2c_probe,
+	.id_table = wm8983_i2c_id
+};
+#endif
+
+static int __init wm8983_modinit(void)
+{
+	int ret = 0;
+
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&wm8983_i2c_driver);
+	if (ret) {
+		printk(KERN_ERR "Failed to register wm8983 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8983_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register wm8983 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return ret;
+}
+module_init(wm8983_modinit);
+
+static void __exit wm8983_exit(void)
+{
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&wm8983_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8983_spi_driver);
+#endif
+}
+module_exit(wm8983_exit);
+
+MODULE_DESCRIPTION("ASoC WM8983 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8983.h b/sound/soc/codecs/wm8983.h
new file mode 100644
index 0000000..71ee619
--- /dev/null
+++ b/sound/soc/codecs/wm8983.h
@@ -0,0 +1,1029 @@
+/*
+ * wm8983.h  --  WM8983 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8983_H
+#define _WM8983_H
+
+/*
+ * Register values.
+ */
+#define WM8983_SOFTWARE_RESET                   0x00
+#define WM8983_POWER_MANAGEMENT_1               0x01
+#define WM8983_POWER_MANAGEMENT_2               0x02
+#define WM8983_POWER_MANAGEMENT_3               0x03
+#define WM8983_AUDIO_INTERFACE                  0x04
+#define WM8983_COMPANDING_CONTROL               0x05
+#define WM8983_CLOCK_GEN_CONTROL                0x06
+#define WM8983_ADDITIONAL_CONTROL               0x07
+#define WM8983_GPIO_CONTROL                     0x08
+#define WM8983_JACK_DETECT_CONTROL_1            0x09
+#define WM8983_DAC_CONTROL                      0x0A
+#define WM8983_LEFT_DAC_DIGITAL_VOL             0x0B
+#define WM8983_RIGHT_DAC_DIGITAL_VOL            0x0C
+#define WM8983_JACK_DETECT_CONTROL_2            0x0D
+#define WM8983_ADC_CONTROL                      0x0E
+#define WM8983_LEFT_ADC_DIGITAL_VOL             0x0F
+#define WM8983_RIGHT_ADC_DIGITAL_VOL            0x10
+#define WM8983_EQ1_LOW_SHELF                    0x12
+#define WM8983_EQ2_PEAK_1                       0x13
+#define WM8983_EQ3_PEAK_2                       0x14
+#define WM8983_EQ4_PEAK_3                       0x15
+#define WM8983_EQ5_HIGH_SHELF                   0x16
+#define WM8983_DAC_LIMITER_1                    0x18
+#define WM8983_DAC_LIMITER_2                    0x19
+#define WM8983_NOTCH_FILTER_1                   0x1B
+#define WM8983_NOTCH_FILTER_2                   0x1C
+#define WM8983_NOTCH_FILTER_3                   0x1D
+#define WM8983_NOTCH_FILTER_4                   0x1E
+#define WM8983_ALC_CONTROL_1                    0x20
+#define WM8983_ALC_CONTROL_2                    0x21
+#define WM8983_ALC_CONTROL_3                    0x22
+#define WM8983_NOISE_GATE                       0x23
+#define WM8983_PLL_N                            0x24
+#define WM8983_PLL_K_1                          0x25
+#define WM8983_PLL_K_2                          0x26
+#define WM8983_PLL_K_3                          0x27
+#define WM8983_3D_CONTROL                       0x29
+#define WM8983_OUT4_TO_ADC                      0x2A
+#define WM8983_BEEP_CONTROL                     0x2B
+#define WM8983_INPUT_CTRL                       0x2C
+#define WM8983_LEFT_INP_PGA_GAIN_CTRL           0x2D
+#define WM8983_RIGHT_INP_PGA_GAIN_CTRL          0x2E
+#define WM8983_LEFT_ADC_BOOST_CTRL              0x2F
+#define WM8983_RIGHT_ADC_BOOST_CTRL             0x30
+#define WM8983_OUTPUT_CTRL                      0x31
+#define WM8983_LEFT_MIXER_CTRL                  0x32
+#define WM8983_RIGHT_MIXER_CTRL                 0x33
+#define WM8983_LOUT1_HP_VOLUME_CTRL             0x34
+#define WM8983_ROUT1_HP_VOLUME_CTRL             0x35
+#define WM8983_LOUT2_SPK_VOLUME_CTRL            0x36
+#define WM8983_ROUT2_SPK_VOLUME_CTRL            0x37
+#define WM8983_OUT3_MIXER_CTRL                  0x38
+#define WM8983_OUT4_MONO_MIX_CTRL               0x39
+#define WM8983_BIAS_CTRL                        0x3D
+
+#define WM8983_REGISTER_COUNT                   59
+#define WM8983_MAX_REGISTER                     0x3F
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8983_SOFTWARE_RESET_MASK              0x01FF  /* SOFTWARE_RESET - [8:0] */
+#define WM8983_SOFTWARE_RESET_SHIFT                  0  /* SOFTWARE_RESET - [8:0] */
+#define WM8983_SOFTWARE_RESET_WIDTH                  9  /* SOFTWARE_RESET - [8:0] */
+
+/*
+ * R1 (0x01) - Power management 1
+ */
+#define WM8983_BUFDCOPEN                        0x0100  /* BUFDCOPEN */
+#define WM8983_BUFDCOPEN_MASK                   0x0100  /* BUFDCOPEN */
+#define WM8983_BUFDCOPEN_SHIFT                       8  /* BUFDCOPEN */
+#define WM8983_BUFDCOPEN_WIDTH                       1  /* BUFDCOPEN */
+#define WM8983_OUT4MIXEN                        0x0080  /* OUT4MIXEN */
+#define WM8983_OUT4MIXEN_MASK                   0x0080  /* OUT4MIXEN */
+#define WM8983_OUT4MIXEN_SHIFT                       7  /* OUT4MIXEN */
+#define WM8983_OUT4MIXEN_WIDTH                       1  /* OUT4MIXEN */
+#define WM8983_OUT3MIXEN                        0x0040  /* OUT3MIXEN */
+#define WM8983_OUT3MIXEN_MASK                   0x0040  /* OUT3MIXEN */
+#define WM8983_OUT3MIXEN_SHIFT                       6  /* OUT3MIXEN */
+#define WM8983_OUT3MIXEN_WIDTH                       1  /* OUT3MIXEN */
+#define WM8983_PLLEN                            0x0020  /* PLLEN */
+#define WM8983_PLLEN_MASK                       0x0020  /* PLLEN */
+#define WM8983_PLLEN_SHIFT                           5  /* PLLEN */
+#define WM8983_PLLEN_WIDTH                           1  /* PLLEN */
+#define WM8983_MICBEN                           0x0010  /* MICBEN */
+#define WM8983_MICBEN_MASK                      0x0010  /* MICBEN */
+#define WM8983_MICBEN_SHIFT                          4  /* MICBEN */
+#define WM8983_MICBEN_WIDTH                          1  /* MICBEN */
+#define WM8983_BIASEN                           0x0008  /* BIASEN */
+#define WM8983_BIASEN_MASK                      0x0008  /* BIASEN */
+#define WM8983_BIASEN_SHIFT                          3  /* BIASEN */
+#define WM8983_BIASEN_WIDTH                          1  /* BIASEN */
+#define WM8983_BUFIOEN                          0x0004  /* BUFIOEN */
+#define WM8983_BUFIOEN_MASK                     0x0004  /* BUFIOEN */
+#define WM8983_BUFIOEN_SHIFT                         2  /* BUFIOEN */
+#define WM8983_BUFIOEN_WIDTH                         1  /* BUFIOEN */
+#define WM8983_VMIDSEL_MASK                     0x0003  /* VMIDSEL - [1:0] */
+#define WM8983_VMIDSEL_SHIFT                         0  /* VMIDSEL - [1:0] */
+#define WM8983_VMIDSEL_WIDTH                         2  /* VMIDSEL - [1:0] */
+
+/*
+ * R2 (0x02) - Power management 2
+ */
+#define WM8983_ROUT1EN                          0x0100  /* ROUT1EN */
+#define WM8983_ROUT1EN_MASK                     0x0100  /* ROUT1EN */
+#define WM8983_ROUT1EN_SHIFT                         8  /* ROUT1EN */
+#define WM8983_ROUT1EN_WIDTH                         1  /* ROUT1EN */
+#define WM8983_LOUT1EN                          0x0080  /* LOUT1EN */
+#define WM8983_LOUT1EN_MASK                     0x0080  /* LOUT1EN */
+#define WM8983_LOUT1EN_SHIFT                         7  /* LOUT1EN */
+#define WM8983_LOUT1EN_WIDTH                         1  /* LOUT1EN */
+#define WM8983_SLEEP                            0x0040  /* SLEEP */
+#define WM8983_SLEEP_MASK                       0x0040  /* SLEEP */
+#define WM8983_SLEEP_SHIFT                           6  /* SLEEP */
+#define WM8983_SLEEP_WIDTH                           1  /* SLEEP */
+#define WM8983_BOOSTENR                         0x0020  /* BOOSTENR */
+#define WM8983_BOOSTENR_MASK                    0x0020  /* BOOSTENR */
+#define WM8983_BOOSTENR_SHIFT                        5  /* BOOSTENR */
+#define WM8983_BOOSTENR_WIDTH                        1  /* BOOSTENR */
+#define WM8983_BOOSTENL                         0x0010  /* BOOSTENL */
+#define WM8983_BOOSTENL_MASK                    0x0010  /* BOOSTENL */
+#define WM8983_BOOSTENL_SHIFT                        4  /* BOOSTENL */
+#define WM8983_BOOSTENL_WIDTH                        1  /* BOOSTENL */
+#define WM8983_INPGAENR                         0x0008  /* INPGAENR */
+#define WM8983_INPGAENR_MASK                    0x0008  /* INPGAENR */
+#define WM8983_INPGAENR_SHIFT                        3  /* INPGAENR */
+#define WM8983_INPGAENR_WIDTH                        1  /* INPGAENR */
+#define WM8983_INPPGAENL                        0x0004  /* INPPGAENL */
+#define WM8983_INPPGAENL_MASK                   0x0004  /* INPPGAENL */
+#define WM8983_INPPGAENL_SHIFT                       2  /* INPPGAENL */
+#define WM8983_INPPGAENL_WIDTH                       1  /* INPPGAENL */
+#define WM8983_ADCENR                           0x0002  /* ADCENR */
+#define WM8983_ADCENR_MASK                      0x0002  /* ADCENR */
+#define WM8983_ADCENR_SHIFT                          1  /* ADCENR */
+#define WM8983_ADCENR_WIDTH                          1  /* ADCENR */
+#define WM8983_ADCENL                           0x0001  /* ADCENL */
+#define WM8983_ADCENL_MASK                      0x0001  /* ADCENL */
+#define WM8983_ADCENL_SHIFT                          0  /* ADCENL */
+#define WM8983_ADCENL_WIDTH                          1  /* ADCENL */
+
+/*
+ * R3 (0x03) - Power management 3
+ */
+#define WM8983_OUT4EN                           0x0100  /* OUT4EN */
+#define WM8983_OUT4EN_MASK                      0x0100  /* OUT4EN */
+#define WM8983_OUT4EN_SHIFT                          8  /* OUT4EN */
+#define WM8983_OUT4EN_WIDTH                          1  /* OUT4EN */
+#define WM8983_OUT3EN                           0x0080  /* OUT3EN */
+#define WM8983_OUT3EN_MASK                      0x0080  /* OUT3EN */
+#define WM8983_OUT3EN_SHIFT                          7  /* OUT3EN */
+#define WM8983_OUT3EN_WIDTH                          1  /* OUT3EN */
+#define WM8983_LOUT2EN                          0x0040  /* LOUT2EN */
+#define WM8983_LOUT2EN_MASK                     0x0040  /* LOUT2EN */
+#define WM8983_LOUT2EN_SHIFT                         6  /* LOUT2EN */
+#define WM8983_LOUT2EN_WIDTH                         1  /* LOUT2EN */
+#define WM8983_ROUT2EN                          0x0020  /* ROUT2EN */
+#define WM8983_ROUT2EN_MASK                     0x0020  /* ROUT2EN */
+#define WM8983_ROUT2EN_SHIFT                         5  /* ROUT2EN */
+#define WM8983_ROUT2EN_WIDTH                         1  /* ROUT2EN */
+#define WM8983_RMIXEN                           0x0008  /* RMIXEN */
+#define WM8983_RMIXEN_MASK                      0x0008  /* RMIXEN */
+#define WM8983_RMIXEN_SHIFT                          3  /* RMIXEN */
+#define WM8983_RMIXEN_WIDTH                          1  /* RMIXEN */
+#define WM8983_LMIXEN                           0x0004  /* LMIXEN */
+#define WM8983_LMIXEN_MASK                      0x0004  /* LMIXEN */
+#define WM8983_LMIXEN_SHIFT                          2  /* LMIXEN */
+#define WM8983_LMIXEN_WIDTH                          1  /* LMIXEN */
+#define WM8983_DACENR                           0x0002  /* DACENR */
+#define WM8983_DACENR_MASK                      0x0002  /* DACENR */
+#define WM8983_DACENR_SHIFT                          1  /* DACENR */
+#define WM8983_DACENR_WIDTH                          1  /* DACENR */
+#define WM8983_DACENL                           0x0001  /* DACENL */
+#define WM8983_DACENL_MASK                      0x0001  /* DACENL */
+#define WM8983_DACENL_SHIFT                          0  /* DACENL */
+#define WM8983_DACENL_WIDTH                          1  /* DACENL */
+
+/*
+ * R4 (0x04) - Audio Interface
+ */
+#define WM8983_BCP                              0x0100  /* BCP */
+#define WM8983_BCP_MASK                         0x0100  /* BCP */
+#define WM8983_BCP_SHIFT                             8  /* BCP */
+#define WM8983_BCP_WIDTH                             1  /* BCP */
+#define WM8983_LRCP                             0x0080  /* LRCP */
+#define WM8983_LRCP_MASK                        0x0080  /* LRCP */
+#define WM8983_LRCP_SHIFT                            7  /* LRCP */
+#define WM8983_LRCP_WIDTH                            1  /* LRCP */
+#define WM8983_WL_MASK                          0x0060  /* WL - [6:5] */
+#define WM8983_WL_SHIFT                              5  /* WL - [6:5] */
+#define WM8983_WL_WIDTH                              2  /* WL - [6:5] */
+#define WM8983_FMT_MASK                         0x0018  /* FMT - [4:3] */
+#define WM8983_FMT_SHIFT                             3  /* FMT - [4:3] */
+#define WM8983_FMT_WIDTH                             2  /* FMT - [4:3] */
+#define WM8983_DLRSWAP                          0x0004  /* DLRSWAP */
+#define WM8983_DLRSWAP_MASK                     0x0004  /* DLRSWAP */
+#define WM8983_DLRSWAP_SHIFT                         2  /* DLRSWAP */
+#define WM8983_DLRSWAP_WIDTH                         1  /* DLRSWAP */
+#define WM8983_ALRSWAP                          0x0002  /* ALRSWAP */
+#define WM8983_ALRSWAP_MASK                     0x0002  /* ALRSWAP */
+#define WM8983_ALRSWAP_SHIFT                         1  /* ALRSWAP */
+#define WM8983_ALRSWAP_WIDTH                         1  /* ALRSWAP */
+#define WM8983_MONO                             0x0001  /* MONO */
+#define WM8983_MONO_MASK                        0x0001  /* MONO */
+#define WM8983_MONO_SHIFT                            0  /* MONO */
+#define WM8983_MONO_WIDTH                            1  /* MONO */
+
+/*
+ * R5 (0x05) - Companding control
+ */
+#define WM8983_WL8                              0x0020  /* WL8 */
+#define WM8983_WL8_MASK                         0x0020  /* WL8 */
+#define WM8983_WL8_SHIFT                             5  /* WL8 */
+#define WM8983_WL8_WIDTH                             1  /* WL8 */
+#define WM8983_DAC_COMP_MASK                    0x0018  /* DAC_COMP - [4:3] */
+#define WM8983_DAC_COMP_SHIFT                        3  /* DAC_COMP - [4:3] */
+#define WM8983_DAC_COMP_WIDTH                        2  /* DAC_COMP - [4:3] */
+#define WM8983_ADC_COMP_MASK                    0x0006  /* ADC_COMP - [2:1] */
+#define WM8983_ADC_COMP_SHIFT                        1  /* ADC_COMP - [2:1] */
+#define WM8983_ADC_COMP_WIDTH                        2  /* ADC_COMP - [2:1] */
+#define WM8983_LOOPBACK                         0x0001  /* LOOPBACK */
+#define WM8983_LOOPBACK_MASK                    0x0001  /* LOOPBACK */
+#define WM8983_LOOPBACK_SHIFT                        0  /* LOOPBACK */
+#define WM8983_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+
+/*
+ * R6 (0x06) - Clock Gen control
+ */
+#define WM8983_CLKSEL                           0x0100  /* CLKSEL */
+#define WM8983_CLKSEL_MASK                      0x0100  /* CLKSEL */
+#define WM8983_CLKSEL_SHIFT                          8  /* CLKSEL */
+#define WM8983_CLKSEL_WIDTH                          1  /* CLKSEL */
+#define WM8983_MCLKDIV_MASK                     0x00E0  /* MCLKDIV - [7:5] */
+#define WM8983_MCLKDIV_SHIFT                         5  /* MCLKDIV - [7:5] */
+#define WM8983_MCLKDIV_WIDTH                         3  /* MCLKDIV - [7:5] */
+#define WM8983_BCLKDIV_MASK                     0x001C  /* BCLKDIV - [4:2] */
+#define WM8983_BCLKDIV_SHIFT                         2  /* BCLKDIV - [4:2] */
+#define WM8983_BCLKDIV_WIDTH                         3  /* BCLKDIV - [4:2] */
+#define WM8983_MS                               0x0001  /* MS */
+#define WM8983_MS_MASK                          0x0001  /* MS */
+#define WM8983_MS_SHIFT                              0  /* MS */
+#define WM8983_MS_WIDTH                              1  /* MS */
+
+/*
+ * R7 (0x07) - Additional control
+ */
+#define WM8983_SR_MASK                          0x000E  /* SR - [3:1] */
+#define WM8983_SR_SHIFT                              1  /* SR - [3:1] */
+#define WM8983_SR_WIDTH                              3  /* SR - [3:1] */
+#define WM8983_SLOWCLKEN                        0x0001  /* SLOWCLKEN */
+#define WM8983_SLOWCLKEN_MASK                   0x0001  /* SLOWCLKEN */
+#define WM8983_SLOWCLKEN_SHIFT                       0  /* SLOWCLKEN */
+#define WM8983_SLOWCLKEN_WIDTH                       1  /* SLOWCLKEN */
+
+/*
+ * R8 (0x08) - GPIO Control
+ */
+#define WM8983_OPCLKDIV_MASK                    0x0030  /* OPCLKDIV - [5:4] */
+#define WM8983_OPCLKDIV_SHIFT                        4  /* OPCLKDIV - [5:4] */
+#define WM8983_OPCLKDIV_WIDTH                        2  /* OPCLKDIV - [5:4] */
+#define WM8983_GPIO1POL                         0x0008  /* GPIO1POL */
+#define WM8983_GPIO1POL_MASK                    0x0008  /* GPIO1POL */
+#define WM8983_GPIO1POL_SHIFT                        3  /* GPIO1POL */
+#define WM8983_GPIO1POL_WIDTH                        1  /* GPIO1POL */
+#define WM8983_GPIO1SEL_MASK                    0x0007  /* GPIO1SEL - [2:0] */
+#define WM8983_GPIO1SEL_SHIFT                        0  /* GPIO1SEL - [2:0] */
+#define WM8983_GPIO1SEL_WIDTH                        3  /* GPIO1SEL - [2:0] */
+
+/*
+ * R9 (0x09) - Jack Detect Control 1
+ */
+#define WM8983_JD_VMID1                         0x0100  /* JD_VMID1 */
+#define WM8983_JD_VMID1_MASK                    0x0100  /* JD_VMID1 */
+#define WM8983_JD_VMID1_SHIFT                        8  /* JD_VMID1 */
+#define WM8983_JD_VMID1_WIDTH                        1  /* JD_VMID1 */
+#define WM8983_JD_VMID0                         0x0080  /* JD_VMID0 */
+#define WM8983_JD_VMID0_MASK                    0x0080  /* JD_VMID0 */
+#define WM8983_JD_VMID0_SHIFT                        7  /* JD_VMID0 */
+#define WM8983_JD_VMID0_WIDTH                        1  /* JD_VMID0 */
+#define WM8983_JD_EN                            0x0040  /* JD_EN */
+#define WM8983_JD_EN_MASK                       0x0040  /* JD_EN */
+#define WM8983_JD_EN_SHIFT                           6  /* JD_EN */
+#define WM8983_JD_EN_WIDTH                           1  /* JD_EN */
+#define WM8983_JD_SEL_MASK                      0x0030  /* JD_SEL - [5:4] */
+#define WM8983_JD_SEL_SHIFT                          4  /* JD_SEL - [5:4] */
+#define WM8983_JD_SEL_WIDTH                          2  /* JD_SEL - [5:4] */
+
+/*
+ * R10 (0x0A) - DAC Control
+ */
+#define WM8983_SOFTMUTE                         0x0040  /* SOFTMUTE */
+#define WM8983_SOFTMUTE_MASK                    0x0040  /* SOFTMUTE */
+#define WM8983_SOFTMUTE_SHIFT                        6  /* SOFTMUTE */
+#define WM8983_SOFTMUTE_WIDTH                        1  /* SOFTMUTE */
+#define WM8983_DACOSR128                        0x0008  /* DACOSR128 */
+#define WM8983_DACOSR128_MASK                   0x0008  /* DACOSR128 */
+#define WM8983_DACOSR128_SHIFT                       3  /* DACOSR128 */
+#define WM8983_DACOSR128_WIDTH                       1  /* DACOSR128 */
+#define WM8983_AMUTE                            0x0004  /* AMUTE */
+#define WM8983_AMUTE_MASK                       0x0004  /* AMUTE */
+#define WM8983_AMUTE_SHIFT                           2  /* AMUTE */
+#define WM8983_AMUTE_WIDTH                           1  /* AMUTE */
+#define WM8983_DACRPOL                          0x0002  /* DACRPOL */
+#define WM8983_DACRPOL_MASK                     0x0002  /* DACRPOL */
+#define WM8983_DACRPOL_SHIFT                         1  /* DACRPOL */
+#define WM8983_DACRPOL_WIDTH                         1  /* DACRPOL */
+#define WM8983_DACLPOL                          0x0001  /* DACLPOL */
+#define WM8983_DACLPOL_MASK                     0x0001  /* DACLPOL */
+#define WM8983_DACLPOL_SHIFT                         0  /* DACLPOL */
+#define WM8983_DACLPOL_WIDTH                         1  /* DACLPOL */
+
+/*
+ * R11 (0x0B) - Left DAC digital Vol
+ */
+#define WM8983_DACVU                            0x0100  /* DACVU */
+#define WM8983_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8983_DACVU_SHIFT                           8  /* DACVU */
+#define WM8983_DACVU_WIDTH                           1  /* DACVU */
+#define WM8983_DACLVOL_MASK                     0x00FF  /* DACLVOL - [7:0] */
+#define WM8983_DACLVOL_SHIFT                         0  /* DACLVOL - [7:0] */
+#define WM8983_DACLVOL_WIDTH                         8  /* DACLVOL - [7:0] */
+
+/*
+ * R12 (0x0C) - Right DAC digital vol
+ */
+#define WM8983_DACVU                            0x0100  /* DACVU */
+#define WM8983_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8983_DACVU_SHIFT                           8  /* DACVU */
+#define WM8983_DACVU_WIDTH                           1  /* DACVU */
+#define WM8983_DACRVOL_MASK                     0x00FF  /* DACRVOL - [7:0] */
+#define WM8983_DACRVOL_SHIFT                         0  /* DACRVOL - [7:0] */
+#define WM8983_DACRVOL_WIDTH                         8  /* DACRVOL - [7:0] */
+
+/*
+ * R13 (0x0D) - Jack Detect Control 2
+ */
+#define WM8983_JD_EN1_MASK                      0x00F0  /* JD_EN1 - [7:4] */
+#define WM8983_JD_EN1_SHIFT                          4  /* JD_EN1 - [7:4] */
+#define WM8983_JD_EN1_WIDTH                          4  /* JD_EN1 - [7:4] */
+#define WM8983_JD_EN0_MASK                      0x000F  /* JD_EN0 - [3:0] */
+#define WM8983_JD_EN0_SHIFT                          0  /* JD_EN0 - [3:0] */
+#define WM8983_JD_EN0_WIDTH                          4  /* JD_EN0 - [3:0] */
+
+/*
+ * R14 (0x0E) - ADC Control
+ */
+#define WM8983_HPFEN                            0x0100  /* HPFEN */
+#define WM8983_HPFEN_MASK                       0x0100  /* HPFEN */
+#define WM8983_HPFEN_SHIFT                           8  /* HPFEN */
+#define WM8983_HPFEN_WIDTH                           1  /* HPFEN */
+#define WM8983_HPFAPP                           0x0080  /* HPFAPP */
+#define WM8983_HPFAPP_MASK                      0x0080  /* HPFAPP */
+#define WM8983_HPFAPP_SHIFT                          7  /* HPFAPP */
+#define WM8983_HPFAPP_WIDTH                          1  /* HPFAPP */
+#define WM8983_HPFCUT_MASK                      0x0070  /* HPFCUT - [6:4] */
+#define WM8983_HPFCUT_SHIFT                          4  /* HPFCUT - [6:4] */
+#define WM8983_HPFCUT_WIDTH                          3  /* HPFCUT - [6:4] */
+#define WM8983_ADCOSR128                        0x0008  /* ADCOSR128 */
+#define WM8983_ADCOSR128_MASK                   0x0008  /* ADCOSR128 */
+#define WM8983_ADCOSR128_SHIFT                       3  /* ADCOSR128 */
+#define WM8983_ADCOSR128_WIDTH                       1  /* ADCOSR128 */
+#define WM8983_ADCRPOL                          0x0002  /* ADCRPOL */
+#define WM8983_ADCRPOL_MASK                     0x0002  /* ADCRPOL */
+#define WM8983_ADCRPOL_SHIFT                         1  /* ADCRPOL */
+#define WM8983_ADCRPOL_WIDTH                         1  /* ADCRPOL */
+#define WM8983_ADCLPOL                          0x0001  /* ADCLPOL */
+#define WM8983_ADCLPOL_MASK                     0x0001  /* ADCLPOL */
+#define WM8983_ADCLPOL_SHIFT                         0  /* ADCLPOL */
+#define WM8983_ADCLPOL_WIDTH                         1  /* ADCLPOL */
+
+/*
+ * R15 (0x0F) - Left ADC Digital Vol
+ */
+#define WM8983_ADCVU                            0x0100  /* ADCVU */
+#define WM8983_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8983_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8983_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8983_ADCLVOL_MASK                     0x00FF  /* ADCLVOL - [7:0] */
+#define WM8983_ADCLVOL_SHIFT                         0  /* ADCLVOL - [7:0] */
+#define WM8983_ADCLVOL_WIDTH                         8  /* ADCLVOL - [7:0] */
+
+/*
+ * R16 (0x10) - Right ADC Digital Vol
+ */
+#define WM8983_ADCVU                            0x0100  /* ADCVU */
+#define WM8983_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8983_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8983_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8983_ADCRVOL_MASK                     0x00FF  /* ADCRVOL - [7:0] */
+#define WM8983_ADCRVOL_SHIFT                         0  /* ADCRVOL - [7:0] */
+#define WM8983_ADCRVOL_WIDTH                         8  /* ADCRVOL - [7:0] */
+
+/*
+ * R18 (0x12) - EQ1 - low shelf
+ */
+#define WM8983_EQ3DMODE                         0x0100  /* EQ3DMODE */
+#define WM8983_EQ3DMODE_MASK                    0x0100  /* EQ3DMODE */
+#define WM8983_EQ3DMODE_SHIFT                        8  /* EQ3DMODE */
+#define WM8983_EQ3DMODE_WIDTH                        1  /* EQ3DMODE */
+#define WM8983_EQ1C_MASK                        0x0060  /* EQ1C - [6:5] */
+#define WM8983_EQ1C_SHIFT                            5  /* EQ1C - [6:5] */
+#define WM8983_EQ1C_WIDTH                            2  /* EQ1C - [6:5] */
+#define WM8983_EQ1G_MASK                        0x001F  /* EQ1G - [4:0] */
+#define WM8983_EQ1G_SHIFT                            0  /* EQ1G - [4:0] */
+#define WM8983_EQ1G_WIDTH                            5  /* EQ1G - [4:0] */
+
+/*
+ * R19 (0x13) - EQ2 - peak 1
+ */
+#define WM8983_EQ2BW                            0x0100  /* EQ2BW */
+#define WM8983_EQ2BW_MASK                       0x0100  /* EQ2BW */
+#define WM8983_EQ2BW_SHIFT                           8  /* EQ2BW */
+#define WM8983_EQ2BW_WIDTH                           1  /* EQ2BW */
+#define WM8983_EQ2C_MASK                        0x0060  /* EQ2C - [6:5] */
+#define WM8983_EQ2C_SHIFT                            5  /* EQ2C - [6:5] */
+#define WM8983_EQ2C_WIDTH                            2  /* EQ2C - [6:5] */
+#define WM8983_EQ2G_MASK                        0x001F  /* EQ2G - [4:0] */
+#define WM8983_EQ2G_SHIFT                            0  /* EQ2G - [4:0] */
+#define WM8983_EQ2G_WIDTH                            5  /* EQ2G - [4:0] */
+
+/*
+ * R20 (0x14) - EQ3 - peak 2
+ */
+#define WM8983_EQ3BW                            0x0100  /* EQ3BW */
+#define WM8983_EQ3BW_MASK                       0x0100  /* EQ3BW */
+#define WM8983_EQ3BW_SHIFT                           8  /* EQ3BW */
+#define WM8983_EQ3BW_WIDTH                           1  /* EQ3BW */
+#define WM8983_EQ3C_MASK                        0x0060  /* EQ3C - [6:5] */
+#define WM8983_EQ3C_SHIFT                            5  /* EQ3C - [6:5] */
+#define WM8983_EQ3C_WIDTH                            2  /* EQ3C - [6:5] */
+#define WM8983_EQ3G_MASK                        0x001F  /* EQ3G - [4:0] */
+#define WM8983_EQ3G_SHIFT                            0  /* EQ3G - [4:0] */
+#define WM8983_EQ3G_WIDTH                            5  /* EQ3G - [4:0] */
+
+/*
+ * R21 (0x15) - EQ4 - peak 3
+ */
+#define WM8983_EQ4BW                            0x0100  /* EQ4BW */
+#define WM8983_EQ4BW_MASK                       0x0100  /* EQ4BW */
+#define WM8983_EQ4BW_SHIFT                           8  /* EQ4BW */
+#define WM8983_EQ4BW_WIDTH                           1  /* EQ4BW */
+#define WM8983_EQ4C_MASK                        0x0060  /* EQ4C - [6:5] */
+#define WM8983_EQ4C_SHIFT                            5  /* EQ4C - [6:5] */
+#define WM8983_EQ4C_WIDTH                            2  /* EQ4C - [6:5] */
+#define WM8983_EQ4G_MASK                        0x001F  /* EQ4G - [4:0] */
+#define WM8983_EQ4G_SHIFT                            0  /* EQ4G - [4:0] */
+#define WM8983_EQ4G_WIDTH                            5  /* EQ4G - [4:0] */
+
+/*
+ * R22 (0x16) - EQ5 - high shelf
+ */
+#define WM8983_EQ5C_MASK                        0x0060  /* EQ5C - [6:5] */
+#define WM8983_EQ5C_SHIFT                            5  /* EQ5C - [6:5] */
+#define WM8983_EQ5C_WIDTH                            2  /* EQ5C - [6:5] */
+#define WM8983_EQ5G_MASK                        0x001F  /* EQ5G - [4:0] */
+#define WM8983_EQ5G_SHIFT                            0  /* EQ5G - [4:0] */
+#define WM8983_EQ5G_WIDTH                            5  /* EQ5G - [4:0] */
+
+/*
+ * R24 (0x18) - DAC Limiter 1
+ */
+#define WM8983_LIMEN                            0x0100  /* LIMEN */
+#define WM8983_LIMEN_MASK                       0x0100  /* LIMEN */
+#define WM8983_LIMEN_SHIFT                           8  /* LIMEN */
+#define WM8983_LIMEN_WIDTH                           1  /* LIMEN */
+#define WM8983_LIMDCY_MASK                      0x00F0  /* LIMDCY - [7:4] */
+#define WM8983_LIMDCY_SHIFT                          4  /* LIMDCY - [7:4] */
+#define WM8983_LIMDCY_WIDTH                          4  /* LIMDCY - [7:4] */
+#define WM8983_LIMATK_MASK                      0x000F  /* LIMATK - [3:0] */
+#define WM8983_LIMATK_SHIFT                          0  /* LIMATK - [3:0] */
+#define WM8983_LIMATK_WIDTH                          4  /* LIMATK - [3:0] */
+
+/*
+ * R25 (0x19) - DAC Limiter 2
+ */
+#define WM8983_LIMLVL_MASK                      0x0070  /* LIMLVL - [6:4] */
+#define WM8983_LIMLVL_SHIFT                          4  /* LIMLVL - [6:4] */
+#define WM8983_LIMLVL_WIDTH                          3  /* LIMLVL - [6:4] */
+#define WM8983_LIMBOOST_MASK                    0x000F  /* LIMBOOST - [3:0] */
+#define WM8983_LIMBOOST_SHIFT                        0  /* LIMBOOST - [3:0] */
+#define WM8983_LIMBOOST_WIDTH                        4  /* LIMBOOST - [3:0] */
+
+/*
+ * R27 (0x1B) - Notch Filter 1
+ */
+#define WM8983_NFU                              0x0100  /* NFU */
+#define WM8983_NFU_MASK                         0x0100  /* NFU */
+#define WM8983_NFU_SHIFT                             8  /* NFU */
+#define WM8983_NFU_WIDTH                             1  /* NFU */
+#define WM8983_NFEN                             0x0080  /* NFEN */
+#define WM8983_NFEN_MASK                        0x0080  /* NFEN */
+#define WM8983_NFEN_SHIFT                            7  /* NFEN */
+#define WM8983_NFEN_WIDTH                            1  /* NFEN */
+#define WM8983_NFA0_13_7_MASK                   0x007F  /* NFA0(13:7) - [6:0] */
+#define WM8983_NFA0_13_7_SHIFT                       0  /* NFA0(13:7) - [6:0] */
+#define WM8983_NFA0_13_7_WIDTH                       7  /* NFA0(13:7) - [6:0] */
+
+/*
+ * R28 (0x1C) - Notch Filter 2
+ */
+#define WM8983_NFU                              0x0100  /* NFU */
+#define WM8983_NFU_MASK                         0x0100  /* NFU */
+#define WM8983_NFU_SHIFT                             8  /* NFU */
+#define WM8983_NFU_WIDTH                             1  /* NFU */
+#define WM8983_NFA0_6_0_MASK                    0x007F  /* NFA0(6:0) - [6:0] */
+#define WM8983_NFA0_6_0_SHIFT                        0  /* NFA0(6:0) - [6:0] */
+#define WM8983_NFA0_6_0_WIDTH                        7  /* NFA0(6:0) - [6:0] */
+
+/*
+ * R29 (0x1D) - Notch Filter 3
+ */
+#define WM8983_NFU                              0x0100  /* NFU */
+#define WM8983_NFU_MASK                         0x0100  /* NFU */
+#define WM8983_NFU_SHIFT                             8  /* NFU */
+#define WM8983_NFU_WIDTH                             1  /* NFU */
+#define WM8983_NFA1_13_7_MASK                   0x007F  /* NFA1(13:7) - [6:0] */
+#define WM8983_NFA1_13_7_SHIFT                       0  /* NFA1(13:7) - [6:0] */
+#define WM8983_NFA1_13_7_WIDTH                       7  /* NFA1(13:7) - [6:0] */
+
+/*
+ * R30 (0x1E) - Notch Filter 4
+ */
+#define WM8983_NFU                              0x0100  /* NFU */
+#define WM8983_NFU_MASK                         0x0100  /* NFU */
+#define WM8983_NFU_SHIFT                             8  /* NFU */
+#define WM8983_NFU_WIDTH                             1  /* NFU */
+#define WM8983_NFA1_6_0_MASK                    0x007F  /* NFA1(6:0) - [6:0] */
+#define WM8983_NFA1_6_0_SHIFT                        0  /* NFA1(6:0) - [6:0] */
+#define WM8983_NFA1_6_0_WIDTH                        7  /* NFA1(6:0) - [6:0] */
+
+/*
+ * R32 (0x20) - ALC control 1
+ */
+#define WM8983_ALCSEL_MASK                      0x0180  /* ALCSEL - [8:7] */
+#define WM8983_ALCSEL_SHIFT                          7  /* ALCSEL - [8:7] */
+#define WM8983_ALCSEL_WIDTH                          2  /* ALCSEL - [8:7] */
+#define WM8983_ALCMAX_MASK                      0x0038  /* ALCMAX - [5:3] */
+#define WM8983_ALCMAX_SHIFT                          3  /* ALCMAX - [5:3] */
+#define WM8983_ALCMAX_WIDTH                          3  /* ALCMAX - [5:3] */
+#define WM8983_ALCMIN_MASK                      0x0007  /* ALCMIN - [2:0] */
+#define WM8983_ALCMIN_SHIFT                          0  /* ALCMIN - [2:0] */
+#define WM8983_ALCMIN_WIDTH                          3  /* ALCMIN - [2:0] */
+
+/*
+ * R33 (0x21) - ALC control 2
+ */
+#define WM8983_ALCHLD_MASK                      0x00F0  /* ALCHLD - [7:4] */
+#define WM8983_ALCHLD_SHIFT                          4  /* ALCHLD - [7:4] */
+#define WM8983_ALCHLD_WIDTH                          4  /* ALCHLD - [7:4] */
+#define WM8983_ALCLVL_MASK                      0x000F  /* ALCLVL - [3:0] */
+#define WM8983_ALCLVL_SHIFT                          0  /* ALCLVL - [3:0] */
+#define WM8983_ALCLVL_WIDTH                          4  /* ALCLVL - [3:0] */
+
+/*
+ * R34 (0x22) - ALC control 3
+ */
+#define WM8983_ALCMODE                          0x0100  /* ALCMODE */
+#define WM8983_ALCMODE_MASK                     0x0100  /* ALCMODE */
+#define WM8983_ALCMODE_SHIFT                         8  /* ALCMODE */
+#define WM8983_ALCMODE_WIDTH                         1  /* ALCMODE */
+#define WM8983_ALCDCY_MASK                      0x00F0  /* ALCDCY - [7:4] */
+#define WM8983_ALCDCY_SHIFT                          4  /* ALCDCY - [7:4] */
+#define WM8983_ALCDCY_WIDTH                          4  /* ALCDCY - [7:4] */
+#define WM8983_ALCATK_MASK                      0x000F  /* ALCATK - [3:0] */
+#define WM8983_ALCATK_SHIFT                          0  /* ALCATK - [3:0] */
+#define WM8983_ALCATK_WIDTH                          4  /* ALCATK - [3:0] */
+
+/*
+ * R35 (0x23) - Noise Gate
+ */
+#define WM8983_NGEN                             0x0008  /* NGEN */
+#define WM8983_NGEN_MASK                        0x0008  /* NGEN */
+#define WM8983_NGEN_SHIFT                            3  /* NGEN */
+#define WM8983_NGEN_WIDTH                            1  /* NGEN */
+#define WM8983_NGTH_MASK                        0x0007  /* NGTH - [2:0] */
+#define WM8983_NGTH_SHIFT                            0  /* NGTH - [2:0] */
+#define WM8983_NGTH_WIDTH                            3  /* NGTH - [2:0] */
+
+/*
+ * R36 (0x24) - PLL N
+ */
+#define WM8983_PLL_PRESCALE                     0x0010  /* PLL_PRESCALE */
+#define WM8983_PLL_PRESCALE_MASK                0x0010  /* PLL_PRESCALE */
+#define WM8983_PLL_PRESCALE_SHIFT                    4  /* PLL_PRESCALE */
+#define WM8983_PLL_PRESCALE_WIDTH                    1  /* PLL_PRESCALE */
+#define WM8983_PLLN_MASK                        0x000F  /* PLLN - [3:0] */
+#define WM8983_PLLN_SHIFT                            0  /* PLLN - [3:0] */
+#define WM8983_PLLN_WIDTH                            4  /* PLLN - [3:0] */
+
+/*
+ * R37 (0x25) - PLL K 1
+ */
+#define WM8983_PLLK_23_18_MASK                  0x003F  /* PLLK(23:18) - [5:0] */
+#define WM8983_PLLK_23_18_SHIFT                      0  /* PLLK(23:18) - [5:0] */
+#define WM8983_PLLK_23_18_WIDTH                      6  /* PLLK(23:18) - [5:0] */
+
+/*
+ * R38 (0x26) - PLL K 2
+ */
+#define WM8983_PLLK_17_9_MASK                   0x01FF  /* PLLK(17:9) - [8:0] */
+#define WM8983_PLLK_17_9_SHIFT                       0  /* PLLK(17:9) - [8:0] */
+#define WM8983_PLLK_17_9_WIDTH                       9  /* PLLK(17:9) - [8:0] */
+
+/*
+ * R39 (0x27) - PLL K 3
+ */
+#define WM8983_PLLK_8_0_MASK                    0x01FF  /* PLLK(8:0) - [8:0] */
+#define WM8983_PLLK_8_0_SHIFT                        0  /* PLLK(8:0) - [8:0] */
+#define WM8983_PLLK_8_0_WIDTH                        9  /* PLLK(8:0) - [8:0] */
+
+/*
+ * R41 (0x29) - 3D control
+ */
+#define WM8983_DEPTH3D_MASK                     0x000F  /* DEPTH3D - [3:0] */
+#define WM8983_DEPTH3D_SHIFT                         0  /* DEPTH3D - [3:0] */
+#define WM8983_DEPTH3D_WIDTH                         4  /* DEPTH3D - [3:0] */
+
+/*
+ * R42 (0x2A) - OUT4 to ADC
+ */
+#define WM8983_OUT4_2ADCVOL_MASK                0x01C0  /* OUT4_2ADCVOL - [8:6] */
+#define WM8983_OUT4_2ADCVOL_SHIFT                    6  /* OUT4_2ADCVOL - [8:6] */
+#define WM8983_OUT4_2ADCVOL_WIDTH                    3  /* OUT4_2ADCVOL - [8:6] */
+#define WM8983_OUT4_2LNR                        0x0020  /* OUT4_2LNR */
+#define WM8983_OUT4_2LNR_MASK                   0x0020  /* OUT4_2LNR */
+#define WM8983_OUT4_2LNR_SHIFT                       5  /* OUT4_2LNR */
+#define WM8983_OUT4_2LNR_WIDTH                       1  /* OUT4_2LNR */
+#define WM8983_POBCTRL                          0x0004  /* POBCTRL */
+#define WM8983_POBCTRL_MASK                     0x0004  /* POBCTRL */
+#define WM8983_POBCTRL_SHIFT                         2  /* POBCTRL */
+#define WM8983_POBCTRL_WIDTH                         1  /* POBCTRL */
+#define WM8983_DELEN                            0x0002  /* DELEN */
+#define WM8983_DELEN_MASK                       0x0002  /* DELEN */
+#define WM8983_DELEN_SHIFT                           1  /* DELEN */
+#define WM8983_DELEN_WIDTH                           1  /* DELEN */
+#define WM8983_OUT1DEL                          0x0001  /* OUT1DEL */
+#define WM8983_OUT1DEL_MASK                     0x0001  /* OUT1DEL */
+#define WM8983_OUT1DEL_SHIFT                         0  /* OUT1DEL */
+#define WM8983_OUT1DEL_WIDTH                         1  /* OUT1DEL */
+
+/*
+ * R43 (0x2B) - Beep control
+ */
+#define WM8983_BYPL2RMIX                        0x0100  /* BYPL2RMIX */
+#define WM8983_BYPL2RMIX_MASK                   0x0100  /* BYPL2RMIX */
+#define WM8983_BYPL2RMIX_SHIFT                       8  /* BYPL2RMIX */
+#define WM8983_BYPL2RMIX_WIDTH                       1  /* BYPL2RMIX */
+#define WM8983_BYPR2LMIX                        0x0080  /* BYPR2LMIX */
+#define WM8983_BYPR2LMIX_MASK                   0x0080  /* BYPR2LMIX */
+#define WM8983_BYPR2LMIX_SHIFT                       7  /* BYPR2LMIX */
+#define WM8983_BYPR2LMIX_WIDTH                       1  /* BYPR2LMIX */
+#define WM8983_MUTERPGA2INV                     0x0020  /* MUTERPGA2INV */
+#define WM8983_MUTERPGA2INV_MASK                0x0020  /* MUTERPGA2INV */
+#define WM8983_MUTERPGA2INV_SHIFT                    5  /* MUTERPGA2INV */
+#define WM8983_MUTERPGA2INV_WIDTH                    1  /* MUTERPGA2INV */
+#define WM8983_INVROUT2                         0x0010  /* INVROUT2 */
+#define WM8983_INVROUT2_MASK                    0x0010  /* INVROUT2 */
+#define WM8983_INVROUT2_SHIFT                        4  /* INVROUT2 */
+#define WM8983_INVROUT2_WIDTH                        1  /* INVROUT2 */
+#define WM8983_BEEPVOL_MASK                     0x000E  /* BEEPVOL - [3:1] */
+#define WM8983_BEEPVOL_SHIFT                         1  /* BEEPVOL - [3:1] */
+#define WM8983_BEEPVOL_WIDTH                         3  /* BEEPVOL - [3:1] */
+#define WM8983_BEEPEN                           0x0001  /* BEEPEN */
+#define WM8983_BEEPEN_MASK                      0x0001  /* BEEPEN */
+#define WM8983_BEEPEN_SHIFT                          0  /* BEEPEN */
+#define WM8983_BEEPEN_WIDTH                          1  /* BEEPEN */
+
+/*
+ * R44 (0x2C) - Input ctrl
+ */
+#define WM8983_MBVSEL                           0x0100  /* MBVSEL */
+#define WM8983_MBVSEL_MASK                      0x0100  /* MBVSEL */
+#define WM8983_MBVSEL_SHIFT                          8  /* MBVSEL */
+#define WM8983_MBVSEL_WIDTH                          1  /* MBVSEL */
+#define WM8983_R2_2INPPGA                       0x0040  /* R2_2INPPGA */
+#define WM8983_R2_2INPPGA_MASK                  0x0040  /* R2_2INPPGA */
+#define WM8983_R2_2INPPGA_SHIFT                      6  /* R2_2INPPGA */
+#define WM8983_R2_2INPPGA_WIDTH                      1  /* R2_2INPPGA */
+#define WM8983_RIN2INPPGA                       0x0020  /* RIN2INPPGA */
+#define WM8983_RIN2INPPGA_MASK                  0x0020  /* RIN2INPPGA */
+#define WM8983_RIN2INPPGA_SHIFT                      5  /* RIN2INPPGA */
+#define WM8983_RIN2INPPGA_WIDTH                      1  /* RIN2INPPGA */
+#define WM8983_RIP2INPPGA                       0x0010  /* RIP2INPPGA */
+#define WM8983_RIP2INPPGA_MASK                  0x0010  /* RIP2INPPGA */
+#define WM8983_RIP2INPPGA_SHIFT                      4  /* RIP2INPPGA */
+#define WM8983_RIP2INPPGA_WIDTH                      1  /* RIP2INPPGA */
+#define WM8983_L2_2INPPGA                       0x0004  /* L2_2INPPGA */
+#define WM8983_L2_2INPPGA_MASK                  0x0004  /* L2_2INPPGA */
+#define WM8983_L2_2INPPGA_SHIFT                      2  /* L2_2INPPGA */
+#define WM8983_L2_2INPPGA_WIDTH                      1  /* L2_2INPPGA */
+#define WM8983_LIN2INPPGA                       0x0002  /* LIN2INPPGA */
+#define WM8983_LIN2INPPGA_MASK                  0x0002  /* LIN2INPPGA */
+#define WM8983_LIN2INPPGA_SHIFT                      1  /* LIN2INPPGA */
+#define WM8983_LIN2INPPGA_WIDTH                      1  /* LIN2INPPGA */
+#define WM8983_LIP2INPPGA                       0x0001  /* LIP2INPPGA */
+#define WM8983_LIP2INPPGA_MASK                  0x0001  /* LIP2INPPGA */
+#define WM8983_LIP2INPPGA_SHIFT                      0  /* LIP2INPPGA */
+#define WM8983_LIP2INPPGA_WIDTH                      1  /* LIP2INPPGA */
+
+/*
+ * R45 (0x2D) - Left INP PGA gain ctrl
+ */
+#define WM8983_INPGAVU                          0x0100  /* INPGAVU */
+#define WM8983_INPGAVU_MASK                     0x0100  /* INPGAVU */
+#define WM8983_INPGAVU_SHIFT                         8  /* INPGAVU */
+#define WM8983_INPGAVU_WIDTH                         1  /* INPGAVU */
+#define WM8983_INPPGAZCL                        0x0080  /* INPPGAZCL */
+#define WM8983_INPPGAZCL_MASK                   0x0080  /* INPPGAZCL */
+#define WM8983_INPPGAZCL_SHIFT                       7  /* INPPGAZCL */
+#define WM8983_INPPGAZCL_WIDTH                       1  /* INPPGAZCL */
+#define WM8983_INPPGAMUTEL                      0x0040  /* INPPGAMUTEL */
+#define WM8983_INPPGAMUTEL_MASK                 0x0040  /* INPPGAMUTEL */
+#define WM8983_INPPGAMUTEL_SHIFT                     6  /* INPPGAMUTEL */
+#define WM8983_INPPGAMUTEL_WIDTH                     1  /* INPPGAMUTEL */
+#define WM8983_INPPGAVOLL_MASK                  0x003F  /* INPPGAVOLL - [5:0] */
+#define WM8983_INPPGAVOLL_SHIFT                      0  /* INPPGAVOLL - [5:0] */
+#define WM8983_INPPGAVOLL_WIDTH                      6  /* INPPGAVOLL - [5:0] */
+
+/*
+ * R46 (0x2E) - Right INP PGA gain ctrl
+ */
+#define WM8983_INPGAVU                          0x0100  /* INPGAVU */
+#define WM8983_INPGAVU_MASK                     0x0100  /* INPGAVU */
+#define WM8983_INPGAVU_SHIFT                         8  /* INPGAVU */
+#define WM8983_INPGAVU_WIDTH                         1  /* INPGAVU */
+#define WM8983_INPPGAZCR                        0x0080  /* INPPGAZCR */
+#define WM8983_INPPGAZCR_MASK                   0x0080  /* INPPGAZCR */
+#define WM8983_INPPGAZCR_SHIFT                       7  /* INPPGAZCR */
+#define WM8983_INPPGAZCR_WIDTH                       1  /* INPPGAZCR */
+#define WM8983_INPPGAMUTER                      0x0040  /* INPPGAMUTER */
+#define WM8983_INPPGAMUTER_MASK                 0x0040  /* INPPGAMUTER */
+#define WM8983_INPPGAMUTER_SHIFT                     6  /* INPPGAMUTER */
+#define WM8983_INPPGAMUTER_WIDTH                     1  /* INPPGAMUTER */
+#define WM8983_INPPGAVOLR_MASK                  0x003F  /* INPPGAVOLR - [5:0] */
+#define WM8983_INPPGAVOLR_SHIFT                      0  /* INPPGAVOLR - [5:0] */
+#define WM8983_INPPGAVOLR_WIDTH                      6  /* INPPGAVOLR - [5:0] */
+
+/*
+ * R47 (0x2F) - Left ADC BOOST ctrl
+ */
+#define WM8983_PGABOOSTL                        0x0100  /* PGABOOSTL */
+#define WM8983_PGABOOSTL_MASK                   0x0100  /* PGABOOSTL */
+#define WM8983_PGABOOSTL_SHIFT                       8  /* PGABOOSTL */
+#define WM8983_PGABOOSTL_WIDTH                       1  /* PGABOOSTL */
+#define WM8983_L2_2BOOSTVOL_MASK                0x0070  /* L2_2BOOSTVOL - [6:4] */
+#define WM8983_L2_2BOOSTVOL_SHIFT                    4  /* L2_2BOOSTVOL - [6:4] */
+#define WM8983_L2_2BOOSTVOL_WIDTH                    3  /* L2_2BOOSTVOL - [6:4] */
+#define WM8983_AUXL2BOOSTVOL_MASK               0x0007  /* AUXL2BOOSTVOL - [2:0] */
+#define WM8983_AUXL2BOOSTVOL_SHIFT                   0  /* AUXL2BOOSTVOL - [2:0] */
+#define WM8983_AUXL2BOOSTVOL_WIDTH                   3  /* AUXL2BOOSTVOL - [2:0] */
+
+/*
+ * R48 (0x30) - Right ADC BOOST ctrl
+ */
+#define WM8983_PGABOOSTR                        0x0100  /* PGABOOSTR */
+#define WM8983_PGABOOSTR_MASK                   0x0100  /* PGABOOSTR */
+#define WM8983_PGABOOSTR_SHIFT                       8  /* PGABOOSTR */
+#define WM8983_PGABOOSTR_WIDTH                       1  /* PGABOOSTR */
+#define WM8983_R2_2BOOSTVOL_MASK                0x0070  /* R2_2BOOSTVOL - [6:4] */
+#define WM8983_R2_2BOOSTVOL_SHIFT                    4  /* R2_2BOOSTVOL - [6:4] */
+#define WM8983_R2_2BOOSTVOL_WIDTH                    3  /* R2_2BOOSTVOL - [6:4] */
+#define WM8983_AUXR2BOOSTVOL_MASK               0x0007  /* AUXR2BOOSTVOL - [2:0] */
+#define WM8983_AUXR2BOOSTVOL_SHIFT                   0  /* AUXR2BOOSTVOL - [2:0] */
+#define WM8983_AUXR2BOOSTVOL_WIDTH                   3  /* AUXR2BOOSTVOL - [2:0] */
+
+/*
+ * R49 (0x31) - Output ctrl
+ */
+#define WM8983_DACL2RMIX                        0x0040  /* DACL2RMIX */
+#define WM8983_DACL2RMIX_MASK                   0x0040  /* DACL2RMIX */
+#define WM8983_DACL2RMIX_SHIFT                       6  /* DACL2RMIX */
+#define WM8983_DACL2RMIX_WIDTH                       1  /* DACL2RMIX */
+#define WM8983_DACR2LMIX                        0x0020  /* DACR2LMIX */
+#define WM8983_DACR2LMIX_MASK                   0x0020  /* DACR2LMIX */
+#define WM8983_DACR2LMIX_SHIFT                       5  /* DACR2LMIX */
+#define WM8983_DACR2LMIX_WIDTH                       1  /* DACR2LMIX */
+#define WM8983_OUT4BOOST                        0x0010  /* OUT4BOOST */
+#define WM8983_OUT4BOOST_MASK                   0x0010  /* OUT4BOOST */
+#define WM8983_OUT4BOOST_SHIFT                       4  /* OUT4BOOST */
+#define WM8983_OUT4BOOST_WIDTH                       1  /* OUT4BOOST */
+#define WM8983_OUT3BOOST                        0x0008  /* OUT3BOOST */
+#define WM8983_OUT3BOOST_MASK                   0x0008  /* OUT3BOOST */
+#define WM8983_OUT3BOOST_SHIFT                       3  /* OUT3BOOST */
+#define WM8983_OUT3BOOST_WIDTH                       1  /* OUT3BOOST */
+#define WM8983_SPKBOOST                         0x0004  /* SPKBOOST */
+#define WM8983_SPKBOOST_MASK                    0x0004  /* SPKBOOST */
+#define WM8983_SPKBOOST_SHIFT                        2  /* SPKBOOST */
+#define WM8983_SPKBOOST_WIDTH                        1  /* SPKBOOST */
+#define WM8983_TSDEN                            0x0002  /* TSDEN */
+#define WM8983_TSDEN_MASK                       0x0002  /* TSDEN */
+#define WM8983_TSDEN_SHIFT                           1  /* TSDEN */
+#define WM8983_TSDEN_WIDTH                           1  /* TSDEN */
+#define WM8983_VROI                             0x0001  /* VROI */
+#define WM8983_VROI_MASK                        0x0001  /* VROI */
+#define WM8983_VROI_SHIFT                            0  /* VROI */
+#define WM8983_VROI_WIDTH                            1  /* VROI */
+
+/*
+ * R50 (0x32) - Left mixer ctrl
+ */
+#define WM8983_AUXLMIXVOL_MASK                  0x01C0  /* AUXLMIXVOL - [8:6] */
+#define WM8983_AUXLMIXVOL_SHIFT                      6  /* AUXLMIXVOL - [8:6] */
+#define WM8983_AUXLMIXVOL_WIDTH                      3  /* AUXLMIXVOL - [8:6] */
+#define WM8983_AUXL2LMIX                        0x0020  /* AUXL2LMIX */
+#define WM8983_AUXL2LMIX_MASK                   0x0020  /* AUXL2LMIX */
+#define WM8983_AUXL2LMIX_SHIFT                       5  /* AUXL2LMIX */
+#define WM8983_AUXL2LMIX_WIDTH                       1  /* AUXL2LMIX */
+#define WM8983_BYPLMIXVOL_MASK                  0x001C  /* BYPLMIXVOL - [4:2] */
+#define WM8983_BYPLMIXVOL_SHIFT                      2  /* BYPLMIXVOL - [4:2] */
+#define WM8983_BYPLMIXVOL_WIDTH                      3  /* BYPLMIXVOL - [4:2] */
+#define WM8983_BYPL2LMIX                        0x0002  /* BYPL2LMIX */
+#define WM8983_BYPL2LMIX_MASK                   0x0002  /* BYPL2LMIX */
+#define WM8983_BYPL2LMIX_SHIFT                       1  /* BYPL2LMIX */
+#define WM8983_BYPL2LMIX_WIDTH                       1  /* BYPL2LMIX */
+#define WM8983_DACL2LMIX                        0x0001  /* DACL2LMIX */
+#define WM8983_DACL2LMIX_MASK                   0x0001  /* DACL2LMIX */
+#define WM8983_DACL2LMIX_SHIFT                       0  /* DACL2LMIX */
+#define WM8983_DACL2LMIX_WIDTH                       1  /* DACL2LMIX */
+
+/*
+ * R51 (0x33) - Right mixer ctrl
+ */
+#define WM8983_AUXRMIXVOL_MASK                  0x01C0  /* AUXRMIXVOL - [8:6] */
+#define WM8983_AUXRMIXVOL_SHIFT                      6  /* AUXRMIXVOL - [8:6] */
+#define WM8983_AUXRMIXVOL_WIDTH                      3  /* AUXRMIXVOL - [8:6] */
+#define WM8983_AUXR2RMIX                        0x0020  /* AUXR2RMIX */
+#define WM8983_AUXR2RMIX_MASK                   0x0020  /* AUXR2RMIX */
+#define WM8983_AUXR2RMIX_SHIFT                       5  /* AUXR2RMIX */
+#define WM8983_AUXR2RMIX_WIDTH                       1  /* AUXR2RMIX */
+#define WM8983_BYPRMIXVOL_MASK                  0x001C  /* BYPRMIXVOL - [4:2] */
+#define WM8983_BYPRMIXVOL_SHIFT                      2  /* BYPRMIXVOL - [4:2] */
+#define WM8983_BYPRMIXVOL_WIDTH                      3  /* BYPRMIXVOL - [4:2] */
+#define WM8983_BYPR2RMIX                        0x0002  /* BYPR2RMIX */
+#define WM8983_BYPR2RMIX_MASK                   0x0002  /* BYPR2RMIX */
+#define WM8983_BYPR2RMIX_SHIFT                       1  /* BYPR2RMIX */
+#define WM8983_BYPR2RMIX_WIDTH                       1  /* BYPR2RMIX */
+#define WM8983_DACR2RMIX                        0x0001  /* DACR2RMIX */
+#define WM8983_DACR2RMIX_MASK                   0x0001  /* DACR2RMIX */
+#define WM8983_DACR2RMIX_SHIFT                       0  /* DACR2RMIX */
+#define WM8983_DACR2RMIX_WIDTH                       1  /* DACR2RMIX */
+
+/*
+ * R52 (0x34) - LOUT1 (HP) volume ctrl
+ */
+#define WM8983_OUT1VU                           0x0100  /* OUT1VU */
+#define WM8983_OUT1VU_MASK                      0x0100  /* OUT1VU */
+#define WM8983_OUT1VU_SHIFT                          8  /* OUT1VU */
+#define WM8983_OUT1VU_WIDTH                          1  /* OUT1VU */
+#define WM8983_LOUT1ZC                          0x0080  /* LOUT1ZC */
+#define WM8983_LOUT1ZC_MASK                     0x0080  /* LOUT1ZC */
+#define WM8983_LOUT1ZC_SHIFT                         7  /* LOUT1ZC */
+#define WM8983_LOUT1ZC_WIDTH                         1  /* LOUT1ZC */
+#define WM8983_LOUT1MUTE                        0x0040  /* LOUT1MUTE */
+#define WM8983_LOUT1MUTE_MASK                   0x0040  /* LOUT1MUTE */
+#define WM8983_LOUT1MUTE_SHIFT                       6  /* LOUT1MUTE */
+#define WM8983_LOUT1MUTE_WIDTH                       1  /* LOUT1MUTE */
+#define WM8983_LOUT1VOL_MASK                    0x003F  /* LOUT1VOL - [5:0] */
+#define WM8983_LOUT1VOL_SHIFT                        0  /* LOUT1VOL - [5:0] */
+#define WM8983_LOUT1VOL_WIDTH                        6  /* LOUT1VOL - [5:0] */
+
+/*
+ * R53 (0x35) - ROUT1 (HP) volume ctrl
+ */
+#define WM8983_OUT1VU                           0x0100  /* OUT1VU */
+#define WM8983_OUT1VU_MASK                      0x0100  /* OUT1VU */
+#define WM8983_OUT1VU_SHIFT                          8  /* OUT1VU */
+#define WM8983_OUT1VU_WIDTH                          1  /* OUT1VU */
+#define WM8983_ROUT1ZC                          0x0080  /* ROUT1ZC */
+#define WM8983_ROUT1ZC_MASK                     0x0080  /* ROUT1ZC */
+#define WM8983_ROUT1ZC_SHIFT                         7  /* ROUT1ZC */
+#define WM8983_ROUT1ZC_WIDTH                         1  /* ROUT1ZC */
+#define WM8983_ROUT1MUTE                        0x0040  /* ROUT1MUTE */
+#define WM8983_ROUT1MUTE_MASK                   0x0040  /* ROUT1MUTE */
+#define WM8983_ROUT1MUTE_SHIFT                       6  /* ROUT1MUTE */
+#define WM8983_ROUT1MUTE_WIDTH                       1  /* ROUT1MUTE */
+#define WM8983_ROUT1VOL_MASK                    0x003F  /* ROUT1VOL - [5:0] */
+#define WM8983_ROUT1VOL_SHIFT                        0  /* ROUT1VOL - [5:0] */
+#define WM8983_ROUT1VOL_WIDTH                        6  /* ROUT1VOL - [5:0] */
+
+/*
+ * R54 (0x36) - LOUT2 (SPK) volume ctrl
+ */
+#define WM8983_OUT2VU                           0x0100  /* OUT2VU */
+#define WM8983_OUT2VU_MASK                      0x0100  /* OUT2VU */
+#define WM8983_OUT2VU_SHIFT                          8  /* OUT2VU */
+#define WM8983_OUT2VU_WIDTH                          1  /* OUT2VU */
+#define WM8983_LOUT2ZC                          0x0080  /* LOUT2ZC */
+#define WM8983_LOUT2ZC_MASK                     0x0080  /* LOUT2ZC */
+#define WM8983_LOUT2ZC_SHIFT                         7  /* LOUT2ZC */
+#define WM8983_LOUT2ZC_WIDTH                         1  /* LOUT2ZC */
+#define WM8983_LOUT2MUTE                        0x0040  /* LOUT2MUTE */
+#define WM8983_LOUT2MUTE_MASK                   0x0040  /* LOUT2MUTE */
+#define WM8983_LOUT2MUTE_SHIFT                       6  /* LOUT2MUTE */
+#define WM8983_LOUT2MUTE_WIDTH                       1  /* LOUT2MUTE */
+#define WM8983_LOUT2VOL_MASK                    0x003F  /* LOUT2VOL - [5:0] */
+#define WM8983_LOUT2VOL_SHIFT                        0  /* LOUT2VOL - [5:0] */
+#define WM8983_LOUT2VOL_WIDTH                        6  /* LOUT2VOL - [5:0] */
+
+/*
+ * R55 (0x37) - ROUT2 (SPK) volume ctrl
+ */
+#define WM8983_OUT2VU                           0x0100  /* OUT2VU */
+#define WM8983_OUT2VU_MASK                      0x0100  /* OUT2VU */
+#define WM8983_OUT2VU_SHIFT                          8  /* OUT2VU */
+#define WM8983_OUT2VU_WIDTH                          1  /* OUT2VU */
+#define WM8983_ROUT2ZC                          0x0080  /* ROUT2ZC */
+#define WM8983_ROUT2ZC_MASK                     0x0080  /* ROUT2ZC */
+#define WM8983_ROUT2ZC_SHIFT                         7  /* ROUT2ZC */
+#define WM8983_ROUT2ZC_WIDTH                         1  /* ROUT2ZC */
+#define WM8983_ROUT2MUTE                        0x0040  /* ROUT2MUTE */
+#define WM8983_ROUT2MUTE_MASK                   0x0040  /* ROUT2MUTE */
+#define WM8983_ROUT2MUTE_SHIFT                       6  /* ROUT2MUTE */
+#define WM8983_ROUT2MUTE_WIDTH                       1  /* ROUT2MUTE */
+#define WM8983_ROUT2VOL_MASK                    0x003F  /* ROUT2VOL - [5:0] */
+#define WM8983_ROUT2VOL_SHIFT                        0  /* ROUT2VOL - [5:0] */
+#define WM8983_ROUT2VOL_WIDTH                        6  /* ROUT2VOL - [5:0] */
+
+/*
+ * R56 (0x38) - OUT3 mixer ctrl
+ */
+#define WM8983_OUT3MUTE                         0x0040  /* OUT3MUTE */
+#define WM8983_OUT3MUTE_MASK                    0x0040  /* OUT3MUTE */
+#define WM8983_OUT3MUTE_SHIFT                        6  /* OUT3MUTE */
+#define WM8983_OUT3MUTE_WIDTH                        1  /* OUT3MUTE */
+#define WM8983_OUT4_2OUT3                       0x0008  /* OUT4_2OUT3 */
+#define WM8983_OUT4_2OUT3_MASK                  0x0008  /* OUT4_2OUT3 */
+#define WM8983_OUT4_2OUT3_SHIFT                      3  /* OUT4_2OUT3 */
+#define WM8983_OUT4_2OUT3_WIDTH                      1  /* OUT4_2OUT3 */
+#define WM8983_BYPL2OUT3                        0x0004  /* BYPL2OUT3 */
+#define WM8983_BYPL2OUT3_MASK                   0x0004  /* BYPL2OUT3 */
+#define WM8983_BYPL2OUT3_SHIFT                       2  /* BYPL2OUT3 */
+#define WM8983_BYPL2OUT3_WIDTH                       1  /* BYPL2OUT3 */
+#define WM8983_LMIX2OUT3                        0x0002  /* LMIX2OUT3 */
+#define WM8983_LMIX2OUT3_MASK                   0x0002  /* LMIX2OUT3 */
+#define WM8983_LMIX2OUT3_SHIFT                       1  /* LMIX2OUT3 */
+#define WM8983_LMIX2OUT3_WIDTH                       1  /* LMIX2OUT3 */
+#define WM8983_LDAC2OUT3                        0x0001  /* LDAC2OUT3 */
+#define WM8983_LDAC2OUT3_MASK                   0x0001  /* LDAC2OUT3 */
+#define WM8983_LDAC2OUT3_SHIFT                       0  /* LDAC2OUT3 */
+#define WM8983_LDAC2OUT3_WIDTH                       1  /* LDAC2OUT3 */
+
+/*
+ * R57 (0x39) - OUT4 (MONO) mix ctrl
+ */
+#define WM8983_OUT3_2OUT4                       0x0080  /* OUT3_2OUT4 */
+#define WM8983_OUT3_2OUT4_MASK                  0x0080  /* OUT3_2OUT4 */
+#define WM8983_OUT3_2OUT4_SHIFT                      7  /* OUT3_2OUT4 */
+#define WM8983_OUT3_2OUT4_WIDTH                      1  /* OUT3_2OUT4 */
+#define WM8983_OUT4MUTE                         0x0040  /* OUT4MUTE */
+#define WM8983_OUT4MUTE_MASK                    0x0040  /* OUT4MUTE */
+#define WM8983_OUT4MUTE_SHIFT                        6  /* OUT4MUTE */
+#define WM8983_OUT4MUTE_WIDTH                        1  /* OUT4MUTE */
+#define WM8983_OUT4ATTN                         0x0020  /* OUT4ATTN */
+#define WM8983_OUT4ATTN_MASK                    0x0020  /* OUT4ATTN */
+#define WM8983_OUT4ATTN_SHIFT                        5  /* OUT4ATTN */
+#define WM8983_OUT4ATTN_WIDTH                        1  /* OUT4ATTN */
+#define WM8983_LMIX2OUT4                        0x0010  /* LMIX2OUT4 */
+#define WM8983_LMIX2OUT4_MASK                   0x0010  /* LMIX2OUT4 */
+#define WM8983_LMIX2OUT4_SHIFT                       4  /* LMIX2OUT4 */
+#define WM8983_LMIX2OUT4_WIDTH                       1  /* LMIX2OUT4 */
+#define WM8983_LDAC2OUT4                        0x0008  /* LDAC2OUT4 */
+#define WM8983_LDAC2OUT4_MASK                   0x0008  /* LDAC2OUT4 */
+#define WM8983_LDAC2OUT4_SHIFT                       3  /* LDAC2OUT4 */
+#define WM8983_LDAC2OUT4_WIDTH                       1  /* LDAC2OUT4 */
+#define WM8983_BYPR2OUT4                        0x0004  /* BYPR2OUT4 */
+#define WM8983_BYPR2OUT4_MASK                   0x0004  /* BYPR2OUT4 */
+#define WM8983_BYPR2OUT4_SHIFT                       2  /* BYPR2OUT4 */
+#define WM8983_BYPR2OUT4_WIDTH                       1  /* BYPR2OUT4 */
+#define WM8983_RMIX2OUT4                        0x0002  /* RMIX2OUT4 */
+#define WM8983_RMIX2OUT4_MASK                   0x0002  /* RMIX2OUT4 */
+#define WM8983_RMIX2OUT4_SHIFT                       1  /* RMIX2OUT4 */
+#define WM8983_RMIX2OUT4_WIDTH                       1  /* RMIX2OUT4 */
+#define WM8983_RDAC2OUT4                        0x0001  /* RDAC2OUT4 */
+#define WM8983_RDAC2OUT4_MASK                   0x0001  /* RDAC2OUT4 */
+#define WM8983_RDAC2OUT4_SHIFT                       0  /* RDAC2OUT4 */
+#define WM8983_RDAC2OUT4_WIDTH                       1  /* RDAC2OUT4 */
+
+/*
+ * R61 (0x3D) - BIAS CTRL
+ */
+#define WM8983_BIASCUT                          0x0100  /* BIASCUT */
+#define WM8983_BIASCUT_MASK                     0x0100  /* BIASCUT */
+#define WM8983_BIASCUT_SHIFT                         8  /* BIASCUT */
+#define WM8983_BIASCUT_WIDTH                         1  /* BIASCUT */
+#define WM8983_HALFIPBIAS                       0x0080  /* HALFIPBIAS */
+#define WM8983_HALFIPBIAS_MASK                  0x0080  /* HALFIPBIAS */
+#define WM8983_HALFIPBIAS_SHIFT                      7  /* HALFIPBIAS */
+#define WM8983_HALFIPBIAS_WIDTH                      1  /* HALFIPBIAS */
+#define WM8983_VBBIASTST_MASK                   0x0060  /* VBBIASTST - [6:5] */
+#define WM8983_VBBIASTST_SHIFT                       5  /* VBBIASTST - [6:5] */
+#define WM8983_VBBIASTST_WIDTH                       2  /* VBBIASTST - [6:5] */
+#define WM8983_BUFBIAS_MASK                     0x0018  /* BUFBIAS - [4:3] */
+#define WM8983_BUFBIAS_SHIFT                         3  /* BUFBIAS - [4:3] */
+#define WM8983_BUFBIAS_WIDTH                         2  /* BUFBIAS - [4:3] */
+#define WM8983_ADCBIAS_MASK                     0x0006  /* ADCBIAS - [2:1] */
+#define WM8983_ADCBIAS_SHIFT                         1  /* ADCBIAS - [2:1] */
+#define WM8983_ADCBIAS_WIDTH                         2  /* ADCBIAS - [2:1] */
+#define WM8983_HALFOPBIAS                       0x0001  /* HALFOPBIAS */
+#define WM8983_HALFOPBIAS_MASK                  0x0001  /* HALFOPBIAS */
+#define WM8983_HALFOPBIAS_SHIFT                      0  /* HALFOPBIAS */
+#define WM8983_HALFOPBIAS_WIDTH                      1  /* HALFOPBIAS */
+
+enum clk_src {
+	WM8983_CLKSRC_MCLK,
+	WM8983_CLKSRC_PLL
+};
+
+#endif /* _WM8983_H */
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
new file mode 100644
index 0000000..18b342c
--- /dev/null
+++ b/sound/soc/codecs/wm8985.c
@@ -0,0 +1,1250 @@
+/*
+ * wm8985.c  --  WM8985 / WM8758 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * WM8758 support:
+ * Copyright: 2016 Barix AG
+ * Author: Petr Kulhavy <petr@barix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * TODO:
+ *  o Add OUT3/OUT4 mixer controls.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8985.h"
+
+#define WM8985_NUM_SUPPLIES 4
+static const char *wm8985_supply_names[WM8985_NUM_SUPPLIES] = {
+	"DCVDD",
+	"DBVDD",
+	"AVDD1",
+	"AVDD2"
+};
+
+enum wm8985_type {
+	WM8985,
+	WM8758,
+};
+
+static const struct reg_default wm8985_reg_defaults[] = {
+	{ 1,  0x0000 },     /* R1  - Power management 1 */
+	{ 2,  0x0000 },     /* R2  - Power management 2 */
+	{ 3,  0x0000 },     /* R3  - Power management 3 */
+	{ 4,  0x0050 },     /* R4  - Audio Interface */
+	{ 5,  0x0000 },     /* R5  - Companding control */
+	{ 6,  0x0140 },     /* R6  - Clock Gen control */
+	{ 7,  0x0000 },     /* R7  - Additional control */
+	{ 8,  0x0000 },     /* R8  - GPIO Control */
+	{ 9,  0x0000 },     /* R9  - Jack Detect Control 1 */
+	{ 10, 0x0000 },     /* R10 - DAC Control */
+	{ 11, 0x00FF },     /* R11 - Left DAC digital Vol */
+	{ 12, 0x00FF },     /* R12 - Right DAC digital vol */
+	{ 13, 0x0000 },     /* R13 - Jack Detect Control 2 */
+	{ 14, 0x0100 },     /* R14 - ADC Control */
+	{ 15, 0x00FF },     /* R15 - Left ADC Digital Vol */
+	{ 16, 0x00FF },     /* R16 - Right ADC Digital Vol */
+	{ 18, 0x012C },     /* R18 - EQ1 - low shelf */
+	{ 19, 0x002C },     /* R19 - EQ2 - peak 1 */
+	{ 20, 0x002C },     /* R20 - EQ3 - peak 2 */
+	{ 21, 0x002C },     /* R21 - EQ4 - peak 3 */
+	{ 22, 0x002C },     /* R22 - EQ5 - high shelf */
+	{ 24, 0x0032 },     /* R24 - DAC Limiter 1 */
+	{ 25, 0x0000 },     /* R25 - DAC Limiter 2 */
+	{ 27, 0x0000 },     /* R27 - Notch Filter 1 */
+	{ 28, 0x0000 },     /* R28 - Notch Filter 2 */
+	{ 29, 0x0000 },     /* R29 - Notch Filter 3 */
+	{ 30, 0x0000 },     /* R30 - Notch Filter 4 */
+	{ 32, 0x0038 },     /* R32 - ALC control 1 */
+	{ 33, 0x000B },     /* R33 - ALC control 2 */
+	{ 34, 0x0032 },     /* R34 - ALC control 3 */
+	{ 35, 0x0000 },     /* R35 - Noise Gate */
+	{ 36, 0x0008 },     /* R36 - PLL N */
+	{ 37, 0x000C },     /* R37 - PLL K 1 */
+	{ 38, 0x0093 },     /* R38 - PLL K 2 */
+	{ 39, 0x00E9 },     /* R39 - PLL K 3 */
+	{ 41, 0x0000 },     /* R41 - 3D control */
+	{ 42, 0x0000 },     /* R42 - OUT4 to ADC */
+	{ 43, 0x0000 },     /* R43 - Beep control */
+	{ 44, 0x0033 },     /* R44 - Input ctrl */
+	{ 45, 0x0010 },     /* R45 - Left INP PGA gain ctrl */
+	{ 46, 0x0010 },     /* R46 - Right INP PGA gain ctrl */
+	{ 47, 0x0100 },     /* R47 - Left ADC BOOST ctrl */
+	{ 48, 0x0100 },     /* R48 - Right ADC BOOST ctrl */
+	{ 49, 0x0002 },     /* R49 - Output ctrl */
+	{ 50, 0x0001 },     /* R50 - Left mixer ctrl */
+	{ 51, 0x0001 },     /* R51 - Right mixer ctrl */
+	{ 52, 0x0039 },     /* R52 - LOUT1 (HP) volume ctrl */
+	{ 53, 0x0039 },     /* R53 - ROUT1 (HP) volume ctrl */
+	{ 54, 0x0039 },     /* R54 - LOUT2 (SPK) volume ctrl */
+	{ 55, 0x0039 },     /* R55 - ROUT2 (SPK) volume ctrl */
+	{ 56, 0x0001 },     /* R56 - OUT3 mixer ctrl */
+	{ 57, 0x0001 },     /* R57 - OUT4 (MONO) mix ctrl */
+	{ 60, 0x0004 },     /* R60 - OUTPUT ctrl */
+	{ 61, 0x0000 },     /* R61 - BIAS CTRL */
+};
+
+static bool wm8985_writeable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8985_SOFTWARE_RESET:
+	case WM8985_POWER_MANAGEMENT_1:
+	case WM8985_POWER_MANAGEMENT_2:
+	case WM8985_POWER_MANAGEMENT_3:
+	case WM8985_AUDIO_INTERFACE:
+	case WM8985_COMPANDING_CONTROL:
+	case WM8985_CLOCK_GEN_CONTROL:
+	case WM8985_ADDITIONAL_CONTROL:
+	case WM8985_GPIO_CONTROL:
+	case WM8985_JACK_DETECT_CONTROL_1:
+	case WM8985_DAC_CONTROL:
+	case WM8985_LEFT_DAC_DIGITAL_VOL:
+	case WM8985_RIGHT_DAC_DIGITAL_VOL:
+	case WM8985_JACK_DETECT_CONTROL_2:
+	case WM8985_ADC_CONTROL:
+	case WM8985_LEFT_ADC_DIGITAL_VOL:
+	case WM8985_RIGHT_ADC_DIGITAL_VOL:
+	case WM8985_EQ1_LOW_SHELF:
+	case WM8985_EQ2_PEAK_1:
+	case WM8985_EQ3_PEAK_2:
+	case WM8985_EQ4_PEAK_3:
+	case WM8985_EQ5_HIGH_SHELF:
+	case WM8985_DAC_LIMITER_1:
+	case WM8985_DAC_LIMITER_2:
+	case WM8985_NOTCH_FILTER_1:
+	case WM8985_NOTCH_FILTER_2:
+	case WM8985_NOTCH_FILTER_3:
+	case WM8985_NOTCH_FILTER_4:
+	case WM8985_ALC_CONTROL_1:
+	case WM8985_ALC_CONTROL_2:
+	case WM8985_ALC_CONTROL_3:
+	case WM8985_NOISE_GATE:
+	case WM8985_PLL_N:
+	case WM8985_PLL_K_1:
+	case WM8985_PLL_K_2:
+	case WM8985_PLL_K_3:
+	case WM8985_3D_CONTROL:
+	case WM8985_OUT4_TO_ADC:
+	case WM8985_BEEP_CONTROL:
+	case WM8985_INPUT_CTRL:
+	case WM8985_LEFT_INP_PGA_GAIN_CTRL:
+	case WM8985_RIGHT_INP_PGA_GAIN_CTRL:
+	case WM8985_LEFT_ADC_BOOST_CTRL:
+	case WM8985_RIGHT_ADC_BOOST_CTRL:
+	case WM8985_OUTPUT_CTRL0:
+	case WM8985_LEFT_MIXER_CTRL:
+	case WM8985_RIGHT_MIXER_CTRL:
+	case WM8985_LOUT1_HP_VOLUME_CTRL:
+	case WM8985_ROUT1_HP_VOLUME_CTRL:
+	case WM8985_LOUT2_SPK_VOLUME_CTRL:
+	case WM8985_ROUT2_SPK_VOLUME_CTRL:
+	case WM8985_OUT3_MIXER_CTRL:
+	case WM8985_OUT4_MONO_MIX_CTRL:
+	case WM8985_OUTPUT_CTRL1:
+	case WM8985_BIAS_CTRL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/*
+ * latch bit 8 of these registers to ensure instant
+ * volume updates
+ */
+static const int volume_update_regs[] = {
+	WM8985_LEFT_DAC_DIGITAL_VOL,
+	WM8985_RIGHT_DAC_DIGITAL_VOL,
+	WM8985_LEFT_ADC_DIGITAL_VOL,
+	WM8985_RIGHT_ADC_DIGITAL_VOL,
+	WM8985_LOUT2_SPK_VOLUME_CTRL,
+	WM8985_ROUT2_SPK_VOLUME_CTRL,
+	WM8985_LOUT1_HP_VOLUME_CTRL,
+	WM8985_ROUT1_HP_VOLUME_CTRL,
+	WM8985_LEFT_INP_PGA_GAIN_CTRL,
+	WM8985_RIGHT_INP_PGA_GAIN_CTRL
+};
+
+struct wm8985_priv {
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[WM8985_NUM_SUPPLIES];
+	enum wm8985_type dev_type;
+	unsigned int sysclk;
+	unsigned int bclk;
+};
+
+static const struct {
+	int div;
+	int ratio;
+} fs_ratios[] = {
+	{ 10, 128 },
+	{ 15, 192 },
+	{ 20, 256 },
+	{ 30, 384 },
+	{ 40, 512 },
+	{ 60, 768 },
+	{ 80, 1024 },
+	{ 120, 1536 }
+};
+
+static const int srates[] = { 48000, 32000, 24000, 16000, 12000, 8000 };
+
+static const int bclk_divs[] = {
+	1, 2, 4, 8, 16, 32
+};
+
+static int eqmode_get(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol);
+static int eqmode_put(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol);
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lim_thresh_tlv, -600, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lim_boost_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(alc_min_tlv, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_max_tlv, -675, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_tar_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(pga_vol_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, -1200, 300, 1);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(aux_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0);
+
+static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" };
+static SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7, alc_sel_text);
+
+static const char *alc_mode_text[] = { "ALC", "Limiter" };
+static SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8, alc_mode_text);
+
+static const char *filter_mode_text[] = { "Audio", "Application" };
+static SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7,
+			    filter_mode_text);
+
+static const char *eq_bw_text[] = { "Narrow", "Wide" };
+static const char *eqmode_text[] = { "Capture", "Playback" };
+static SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
+
+static const char *eq1_cutoff_text[] = {
+	"80Hz", "105Hz", "135Hz", "175Hz"
+};
+static SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5,
+			    eq1_cutoff_text);
+static const char *eq2_cutoff_text[] = {
+	"230Hz", "300Hz", "385Hz", "500Hz"
+};
+static SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5, eq2_cutoff_text);
+static const char *eq3_cutoff_text[] = {
+	"650Hz", "850Hz", "1.1kHz", "1.4kHz"
+};
+static SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5,
+			    eq3_cutoff_text);
+static const char *eq4_cutoff_text[] = {
+	"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"
+};
+static SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5, eq4_cutoff_text);
+static const char *eq5_cutoff_text[] = {
+	"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"
+};
+static SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5,
+				  eq5_cutoff_text);
+
+static const char *speaker_mode_text[] = { "Class A/B", "Class D" };
+static SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text);
+
+static const char *depth_3d_text[] = {
+	"Off",
+	"6.67%",
+	"13.3%",
+	"20%",
+	"26.7%",
+	"33.3%",
+	"40%",
+	"46.6%",
+	"53.3%",
+	"60%",
+	"66.7%",
+	"73.3%",
+	"80%",
+	"86.7%",
+	"93.3%",
+	"100%"
+};
+static SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0, depth_3d_text);
+
+static const struct snd_kcontrol_new wm8985_common_snd_controls[] = {
+	SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL,
+		0, 1, 0),
+
+	SOC_ENUM("ALC Capture Function", alc_sel),
+	SOC_SINGLE_TLV("ALC Capture Max Volume", WM8985_ALC_CONTROL_1,
+		3, 7, 0, alc_max_tlv),
+	SOC_SINGLE_TLV("ALC Capture Min Volume", WM8985_ALC_CONTROL_1,
+		0, 7, 0, alc_min_tlv),
+	SOC_SINGLE_TLV("ALC Capture Target Volume", WM8985_ALC_CONTROL_2,
+		0, 15, 0, alc_tar_tlv),
+	SOC_SINGLE("ALC Capture Attack", WM8985_ALC_CONTROL_3, 0, 10, 0),
+	SOC_SINGLE("ALC Capture Hold", WM8985_ALC_CONTROL_2, 4, 10, 0),
+	SOC_SINGLE("ALC Capture Decay", WM8985_ALC_CONTROL_3, 4, 10, 0),
+	SOC_ENUM("ALC Mode", alc_mode),
+	SOC_SINGLE("ALC Capture NG Switch", WM8985_NOISE_GATE,
+		3, 1, 0),
+	SOC_SINGLE("ALC Capture NG Threshold", WM8985_NOISE_GATE,
+		0, 7, 1),
+
+	SOC_DOUBLE_R_TLV("Capture Volume", WM8985_LEFT_ADC_DIGITAL_VOL,
+		WM8985_RIGHT_ADC_DIGITAL_VOL, 0, 255, 0, adc_tlv),
+	SOC_DOUBLE_R("Capture PGA ZC Switch", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+		WM8985_RIGHT_INP_PGA_GAIN_CTRL, 7, 1, 0),
+	SOC_DOUBLE_R_TLV("Capture PGA Volume", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+		WM8985_RIGHT_INP_PGA_GAIN_CTRL, 0, 63, 0, pga_vol_tlv),
+
+	SOC_DOUBLE_R_TLV("Capture PGA Boost Volume",
+		WM8985_LEFT_ADC_BOOST_CTRL, WM8985_RIGHT_ADC_BOOST_CTRL,
+		8, 1, 0, pga_boost_tlv),
+
+	SOC_DOUBLE("ADC Inversion Switch", WM8985_ADC_CONTROL, 0, 1, 1, 0),
+	SOC_SINGLE("ADC 128x Oversampling Switch", WM8985_ADC_CONTROL, 8, 1, 0),
+
+	SOC_DOUBLE_R_TLV("Playback Volume", WM8985_LEFT_DAC_DIGITAL_VOL,
+		WM8985_RIGHT_DAC_DIGITAL_VOL, 0, 255, 0, dac_tlv),
+
+	SOC_SINGLE("DAC Playback Limiter Switch", WM8985_DAC_LIMITER_1, 8, 1, 0),
+	SOC_SINGLE("DAC Playback Limiter Decay", WM8985_DAC_LIMITER_1, 4, 10, 0),
+	SOC_SINGLE("DAC Playback Limiter Attack", WM8985_DAC_LIMITER_1, 0, 11, 0),
+	SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8985_DAC_LIMITER_2,
+		4, 7, 1, lim_thresh_tlv),
+	SOC_SINGLE_TLV("DAC Playback Limiter Boost Volume", WM8985_DAC_LIMITER_2,
+		0, 12, 0, lim_boost_tlv),
+	SOC_DOUBLE("DAC Inversion Switch", WM8985_DAC_CONTROL, 0, 1, 1, 0),
+	SOC_SINGLE("DAC Auto Mute Switch", WM8985_DAC_CONTROL, 2, 1, 0),
+	SOC_SINGLE("DAC 128x Oversampling Switch", WM8985_DAC_CONTROL, 3, 1, 0),
+
+	SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8985_LOUT1_HP_VOLUME_CTRL,
+		WM8985_ROUT1_HP_VOLUME_CTRL, 0, 63, 0, out_tlv),
+	SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8985_LOUT1_HP_VOLUME_CTRL,
+		WM8985_ROUT1_HP_VOLUME_CTRL, 7, 1, 0),
+	SOC_DOUBLE_R("Headphone Switch", WM8985_LOUT1_HP_VOLUME_CTRL,
+		WM8985_ROUT1_HP_VOLUME_CTRL, 6, 1, 1),
+
+	SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8985_LOUT2_SPK_VOLUME_CTRL,
+		WM8985_ROUT2_SPK_VOLUME_CTRL, 0, 63, 0, out_tlv),
+	SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8985_LOUT2_SPK_VOLUME_CTRL,
+		WM8985_ROUT2_SPK_VOLUME_CTRL, 7, 1, 0),
+	SOC_DOUBLE_R("Speaker Switch", WM8985_LOUT2_SPK_VOLUME_CTRL,
+		WM8985_ROUT2_SPK_VOLUME_CTRL, 6, 1, 1),
+
+	SOC_SINGLE("High Pass Filter Switch", WM8985_ADC_CONTROL, 8, 1, 0),
+	SOC_ENUM("High Pass Filter Mode", filter_mode),
+	SOC_SINGLE("High Pass Filter Cutoff", WM8985_ADC_CONTROL, 4, 7, 0),
+
+	SOC_DOUBLE_R_TLV("Input PGA Bypass Volume",
+		WM8985_LEFT_MIXER_CTRL, WM8985_RIGHT_MIXER_CTRL, 2, 7, 0,
+		bypass_tlv),
+
+	SOC_ENUM_EXT("Equalizer Function", eqmode, eqmode_get, eqmode_put),
+	SOC_ENUM("EQ1 Cutoff", eq1_cutoff),
+	SOC_SINGLE_TLV("EQ1 Volume", WM8985_EQ1_LOW_SHELF,  0, 24, 1, eq_tlv),
+	SOC_ENUM("EQ2 Bandwidth", eq2_bw),
+	SOC_ENUM("EQ2 Cutoff", eq2_cutoff),
+	SOC_SINGLE_TLV("EQ2 Volume", WM8985_EQ2_PEAK_1, 0, 24, 1, eq_tlv),
+	SOC_ENUM("EQ3 Bandwidth", eq3_bw),
+	SOC_ENUM("EQ3 Cutoff", eq3_cutoff),
+	SOC_SINGLE_TLV("EQ3 Volume", WM8985_EQ3_PEAK_2, 0, 24, 1, eq_tlv),
+	SOC_ENUM("EQ4 Bandwidth", eq4_bw),
+	SOC_ENUM("EQ4 Cutoff", eq4_cutoff),
+	SOC_SINGLE_TLV("EQ4 Volume", WM8985_EQ4_PEAK_3, 0, 24, 1, eq_tlv),
+	SOC_ENUM("EQ5 Cutoff", eq5_cutoff),
+	SOC_SINGLE_TLV("EQ5 Volume", WM8985_EQ5_HIGH_SHELF, 0, 24, 1, eq_tlv),
+
+	SOC_ENUM("3D Depth", depth_3d),
+};
+
+static const struct snd_kcontrol_new wm8985_specific_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("Aux Bypass Volume",
+		WM8985_LEFT_MIXER_CTRL, WM8985_RIGHT_MIXER_CTRL, 6, 7, 0,
+		aux_tlv),
+
+	SOC_ENUM("Speaker Mode", speaker_mode)
+};
+
+static const struct snd_kcontrol_new left_out_mixer[] = {
+	SOC_DAPM_SINGLE("Line Switch", WM8985_LEFT_MIXER_CTRL, 1, 1, 0),
+	SOC_DAPM_SINGLE("PCM Switch", WM8985_LEFT_MIXER_CTRL, 0, 1, 0),
+
+	/* --- WM8985 only --- */
+	SOC_DAPM_SINGLE("Aux Switch", WM8985_LEFT_MIXER_CTRL, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_out_mixer[] = {
+	SOC_DAPM_SINGLE("Line Switch", WM8985_RIGHT_MIXER_CTRL, 1, 1, 0),
+	SOC_DAPM_SINGLE("PCM Switch", WM8985_RIGHT_MIXER_CTRL, 0, 1, 0),
+
+	/* --- WM8985 only --- */
+	SOC_DAPM_SINGLE("Aux Switch", WM8985_RIGHT_MIXER_CTRL, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_input_mixer[] = {
+	SOC_DAPM_SINGLE("L2 Switch", WM8985_INPUT_CTRL, 2, 1, 0),
+	SOC_DAPM_SINGLE("MicN Switch", WM8985_INPUT_CTRL, 1, 1, 0),
+	SOC_DAPM_SINGLE("MicP Switch", WM8985_INPUT_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_input_mixer[] = {
+	SOC_DAPM_SINGLE("R2 Switch", WM8985_INPUT_CTRL, 6, 1, 0),
+	SOC_DAPM_SINGLE("MicN Switch", WM8985_INPUT_CTRL, 5, 1, 0),
+	SOC_DAPM_SINGLE("MicP Switch", WM8985_INPUT_CTRL, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_boost_mixer[] = {
+	SOC_DAPM_SINGLE_TLV("L2 Volume", WM8985_LEFT_ADC_BOOST_CTRL,
+		4, 7, 0, boost_tlv),
+
+	/* --- WM8985 only --- */
+	SOC_DAPM_SINGLE_TLV("AUXL Volume", WM8985_LEFT_ADC_BOOST_CTRL,
+		0, 7, 0, boost_tlv)
+};
+
+static const struct snd_kcontrol_new right_boost_mixer[] = {
+	SOC_DAPM_SINGLE_TLV("R2 Volume", WM8985_RIGHT_ADC_BOOST_CTRL,
+		4, 7, 0, boost_tlv),
+
+	/* --- WM8985 only --- */
+	SOC_DAPM_SINGLE_TLV("AUXR Volume", WM8985_RIGHT_ADC_BOOST_CTRL,
+		0, 7, 0, boost_tlv)
+};
+
+static const struct snd_soc_dapm_widget wm8985_common_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8985_POWER_MANAGEMENT_3,
+		0, 0),
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8985_POWER_MANAGEMENT_3,
+		1, 0),
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8985_POWER_MANAGEMENT_2,
+		0, 0),
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8985_POWER_MANAGEMENT_2,
+		1, 0),
+
+	SND_SOC_DAPM_MIXER("Left Input Mixer", WM8985_POWER_MANAGEMENT_2,
+		2, 0, left_input_mixer, ARRAY_SIZE(left_input_mixer)),
+	SND_SOC_DAPM_MIXER("Right Input Mixer", WM8985_POWER_MANAGEMENT_2,
+		3, 0, right_input_mixer, ARRAY_SIZE(right_input_mixer)),
+
+	SND_SOC_DAPM_PGA("Left Capture PGA", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+		6, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Capture PGA", WM8985_RIGHT_INP_PGA_GAIN_CTRL,
+		6, 1, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Left Headphone Out", WM8985_POWER_MANAGEMENT_2,
+		7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Headphone Out", WM8985_POWER_MANAGEMENT_2,
+		8, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Left Speaker Out", WM8985_POWER_MANAGEMENT_3,
+		5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Speaker Out", WM8985_POWER_MANAGEMENT_3,
+		6, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Mic Bias", WM8985_POWER_MANAGEMENT_1, 4, 0,
+			    NULL, 0),
+
+	SND_SOC_DAPM_INPUT("LIN"),
+	SND_SOC_DAPM_INPUT("LIP"),
+	SND_SOC_DAPM_INPUT("RIN"),
+	SND_SOC_DAPM_INPUT("RIP"),
+	SND_SOC_DAPM_INPUT("L2"),
+	SND_SOC_DAPM_INPUT("R2"),
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("SPKL"),
+	SND_SOC_DAPM_OUTPUT("SPKR")
+};
+
+static const struct snd_soc_dapm_widget wm8985_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Left Output Mixer", WM8985_POWER_MANAGEMENT_3,
+		2, 0, left_out_mixer, ARRAY_SIZE(left_out_mixer)),
+	SND_SOC_DAPM_MIXER("Right Output Mixer", WM8985_POWER_MANAGEMENT_3,
+		3, 0, right_out_mixer, ARRAY_SIZE(right_out_mixer)),
+
+	SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8985_POWER_MANAGEMENT_2,
+		4, 0, left_boost_mixer, ARRAY_SIZE(left_boost_mixer)),
+	SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8985_POWER_MANAGEMENT_2,
+		5, 0, right_boost_mixer, ARRAY_SIZE(right_boost_mixer)),
+
+	SND_SOC_DAPM_INPUT("AUXL"),
+	SND_SOC_DAPM_INPUT("AUXR"),
+};
+
+static const struct snd_soc_dapm_widget wm8758_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Left Output Mixer", WM8985_POWER_MANAGEMENT_3,
+		2, 0, left_out_mixer,
+		ARRAY_SIZE(left_out_mixer) - 1),
+	SND_SOC_DAPM_MIXER("Right Output Mixer", WM8985_POWER_MANAGEMENT_3,
+		3, 0, right_out_mixer,
+		ARRAY_SIZE(right_out_mixer) - 1),
+
+	SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8985_POWER_MANAGEMENT_2,
+		4, 0, left_boost_mixer,
+		ARRAY_SIZE(left_boost_mixer) - 1),
+	SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8985_POWER_MANAGEMENT_2,
+		5, 0, right_boost_mixer,
+		ARRAY_SIZE(right_boost_mixer) - 1),
+};
+
+static const struct snd_soc_dapm_route wm8985_common_dapm_routes[] = {
+	{ "Right Output Mixer", "PCM Switch", "Right DAC" },
+	{ "Right Output Mixer", "Line Switch", "Right Boost Mixer" },
+
+	{ "Left Output Mixer", "PCM Switch", "Left DAC" },
+	{ "Left Output Mixer", "Line Switch", "Left Boost Mixer" },
+
+	{ "Right Headphone Out", NULL, "Right Output Mixer" },
+	{ "HPR", NULL, "Right Headphone Out" },
+
+	{ "Left Headphone Out", NULL, "Left Output Mixer" },
+	{ "HPL", NULL, "Left Headphone Out" },
+
+	{ "Right Speaker Out", NULL, "Right Output Mixer" },
+	{ "SPKR", NULL, "Right Speaker Out" },
+
+	{ "Left Speaker Out", NULL, "Left Output Mixer" },
+	{ "SPKL", NULL, "Left Speaker Out" },
+
+	{ "Right ADC", NULL, "Right Boost Mixer" },
+
+	{ "Right Boost Mixer", NULL, "Right Capture PGA" },
+	{ "Right Boost Mixer", "R2 Volume", "R2" },
+
+	{ "Left ADC", NULL, "Left Boost Mixer" },
+
+	{ "Left Boost Mixer", NULL, "Left Capture PGA" },
+	{ "Left Boost Mixer", "L2 Volume", "L2" },
+
+	{ "Right Capture PGA", NULL, "Right Input Mixer" },
+	{ "Left Capture PGA", NULL, "Left Input Mixer" },
+
+	{ "Right Input Mixer", "R2 Switch", "R2" },
+	{ "Right Input Mixer", "MicN Switch", "RIN" },
+	{ "Right Input Mixer", "MicP Switch", "RIP" },
+
+	{ "Left Input Mixer", "L2 Switch", "L2" },
+	{ "Left Input Mixer", "MicN Switch", "LIN" },
+	{ "Left Input Mixer", "MicP Switch", "LIP" },
+};
+static const struct snd_soc_dapm_route wm8985_aux_dapm_routes[] = {
+	{ "Right Output Mixer", "Aux Switch", "AUXR" },
+	{ "Left Output Mixer", "Aux Switch", "AUXL" },
+
+	{ "Right Boost Mixer", "AUXR Volume", "AUXR" },
+	{ "Left Boost Mixer", "AUXL Volume", "AUXL" },
+};
+
+static int wm8985_add_widgets(struct snd_soc_component *component)
+{
+	struct wm8985_priv *wm8985 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	switch (wm8985->dev_type) {
+	case WM8758:
+		snd_soc_dapm_new_controls(dapm, wm8758_dapm_widgets,
+					  ARRAY_SIZE(wm8758_dapm_widgets));
+		break;
+
+	case WM8985:
+		snd_soc_add_component_controls(component, wm8985_specific_snd_controls,
+			ARRAY_SIZE(wm8985_specific_snd_controls));
+
+		snd_soc_dapm_new_controls(dapm, wm8985_dapm_widgets,
+			ARRAY_SIZE(wm8985_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm, wm8985_aux_dapm_routes,
+			ARRAY_SIZE(wm8985_aux_dapm_routes));
+		break;
+	}
+
+	return 0;
+}
+
+static int eqmode_get(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int reg;
+
+	reg = snd_soc_component_read32(component, WM8985_EQ1_LOW_SHELF);
+	if (reg & WM8985_EQ3DMODE)
+		ucontrol->value.enumerated.item[0] = 1;
+	else
+		ucontrol->value.enumerated.item[0] = 0;
+
+	return 0;
+}
+
+static int eqmode_put(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int regpwr2, regpwr3;
+	unsigned int reg_eq;
+
+	if (ucontrol->value.enumerated.item[0] != 0
+			&& ucontrol->value.enumerated.item[0] != 1)
+		return -EINVAL;
+
+	reg_eq = snd_soc_component_read32(component, WM8985_EQ1_LOW_SHELF);
+	switch ((reg_eq & WM8985_EQ3DMODE) >> WM8985_EQ3DMODE_SHIFT) {
+	case 0:
+		if (!ucontrol->value.enumerated.item[0])
+			return 0;
+		break;
+	case 1:
+		if (ucontrol->value.enumerated.item[0])
+			return 0;
+		break;
+	}
+
+	regpwr2 = snd_soc_component_read32(component, WM8985_POWER_MANAGEMENT_2);
+	regpwr3 = snd_soc_component_read32(component, WM8985_POWER_MANAGEMENT_3);
+	/* disable the DACs and ADCs */
+	snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_2,
+			    WM8985_ADCENR_MASK | WM8985_ADCENL_MASK, 0);
+	snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_3,
+			    WM8985_DACENR_MASK | WM8985_DACENL_MASK, 0);
+	snd_soc_component_update_bits(component, WM8985_ADDITIONAL_CONTROL,
+			    WM8985_M128ENB_MASK, WM8985_M128ENB);
+	/* set the desired eqmode */
+	snd_soc_component_update_bits(component, WM8985_EQ1_LOW_SHELF,
+			    WM8985_EQ3DMODE_MASK,
+			    ucontrol->value.enumerated.item[0]
+			    << WM8985_EQ3DMODE_SHIFT);
+	/* restore DAC/ADC configuration */
+	snd_soc_component_write(component, WM8985_POWER_MANAGEMENT_2, regpwr2);
+	snd_soc_component_write(component, WM8985_POWER_MANAGEMENT_3, regpwr3);
+	return 0;
+}
+
+static int wm8985_reset(struct snd_soc_component *component)
+{
+	return snd_soc_component_write(component, WM8985_SOFTWARE_RESET, 0x0);
+}
+
+static int wm8985_dac_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+
+	return snd_soc_component_update_bits(component, WM8985_DAC_CONTROL,
+				   WM8985_SOFTMUTE_MASK,
+				   !!mute << WM8985_SOFTMUTE_SHIFT);
+}
+
+static int wm8985_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component;
+	u16 format, master, bcp, lrp;
+
+	component = dai->component;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		format = 0x2;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		format = 0x0;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		format = 0x1;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		format = 0x3;
+		break;
+	default:
+		dev_err(dai->dev, "Unknown dai format\n");
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8985_AUDIO_INTERFACE,
+			    WM8985_FMT_MASK, format << WM8985_FMT_SHIFT);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		master = 0;
+		break;
+	default:
+		dev_err(dai->dev, "Unknown master/slave configuration\n");
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8985_CLOCK_GEN_CONTROL,
+			    WM8985_MS_MASK, master << WM8985_MS_SHIFT);
+
+	/* frame inversion is not valid for dsp modes */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_IB_IF:
+		case SND_SOC_DAIFMT_NB_IF:
+			return -EINVAL;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	bcp = lrp = 0;
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		bcp = lrp = 1;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		bcp = 1;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		lrp = 1;
+		break;
+	default:
+		dev_err(dai->dev, "Unknown polarity configuration\n");
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8985_AUDIO_INTERFACE,
+			    WM8985_LRP_MASK, lrp << WM8985_LRP_SHIFT);
+	snd_soc_component_update_bits(component, WM8985_AUDIO_INTERFACE,
+			    WM8985_BCP_MASK, bcp << WM8985_BCP_SHIFT);
+	return 0;
+}
+
+static int wm8985_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	int i;
+	struct snd_soc_component *component;
+	struct wm8985_priv *wm8985;
+	u16 blen, srate_idx;
+	unsigned int tmp;
+	int srate_best;
+
+	component = dai->component;
+	wm8985 = snd_soc_component_get_drvdata(component);
+
+	wm8985->bclk = snd_soc_params_to_bclk(params);
+	if ((int)wm8985->bclk < 0)
+		return wm8985->bclk;
+
+	switch (params_width(params)) {
+	case 16:
+		blen = 0x0;
+		break;
+	case 20:
+		blen = 0x1;
+		break;
+	case 24:
+		blen = 0x2;
+		break;
+	case 32:
+		blen = 0x3;
+		break;
+	default:
+		dev_err(dai->dev, "Unsupported word length %u\n",
+			params_width(params));
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8985_AUDIO_INTERFACE,
+			    WM8985_WL_MASK, blen << WM8985_WL_SHIFT);
+
+	/*
+	 * match to the nearest possible sample rate and rely
+	 * on the array index to configure the SR register
+	 */
+	srate_idx = 0;
+	srate_best = abs(srates[0] - params_rate(params));
+	for (i = 1; i < ARRAY_SIZE(srates); ++i) {
+		if (abs(srates[i] - params_rate(params)) >= srate_best)
+			continue;
+		srate_idx = i;
+		srate_best = abs(srates[i] - params_rate(params));
+	}
+
+	dev_dbg(dai->dev, "Selected SRATE = %d\n", srates[srate_idx]);
+	snd_soc_component_update_bits(component, WM8985_ADDITIONAL_CONTROL,
+			    WM8985_SR_MASK, srate_idx << WM8985_SR_SHIFT);
+
+	dev_dbg(dai->dev, "Target BCLK = %uHz\n", wm8985->bclk);
+	dev_dbg(dai->dev, "SYSCLK = %uHz\n", wm8985->sysclk);
+
+	for (i = 0; i < ARRAY_SIZE(fs_ratios); ++i) {
+		if (wm8985->sysclk / params_rate(params)
+				== fs_ratios[i].ratio)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(fs_ratios)) {
+		dev_err(dai->dev, "Unable to configure MCLK ratio %u/%u\n",
+			wm8985->sysclk, params_rate(params));
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "MCLK ratio = %dfs\n", fs_ratios[i].ratio);
+	snd_soc_component_update_bits(component, WM8985_CLOCK_GEN_CONTROL,
+			    WM8985_MCLKDIV_MASK, i << WM8985_MCLKDIV_SHIFT);
+
+	/* select the appropriate bclk divider */
+	tmp = (wm8985->sysclk / fs_ratios[i].div) * 10;
+	for (i = 0; i < ARRAY_SIZE(bclk_divs); ++i) {
+		if (wm8985->bclk == tmp / bclk_divs[i])
+			break;
+	}
+
+	if (i == ARRAY_SIZE(bclk_divs)) {
+		dev_err(dai->dev, "No matching BCLK divider found\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "BCLK div = %d\n", i);
+	snd_soc_component_update_bits(component, WM8985_CLOCK_GEN_CONTROL,
+			    WM8985_BCLKDIV_MASK, i << WM8985_BCLKDIV_SHIFT);
+	return 0;
+}
+
+struct pll_div {
+	u32 div2:1;
+	u32 n:4;
+	u32 k:24;
+};
+
+#define FIXED_PLL_SIZE ((1ULL << 24) * 10)
+static int pll_factors(struct pll_div *pll_div, unsigned int target,
+		       unsigned int source)
+{
+	u64 Kpart;
+	unsigned long int K, Ndiv, Nmod;
+
+	pll_div->div2 = 0;
+	Ndiv = target / source;
+	if (Ndiv < 6) {
+		source >>= 1;
+		pll_div->div2 = 1;
+		Ndiv = target / source;
+	}
+
+	if (Ndiv < 6 || Ndiv > 12) {
+		printk(KERN_ERR "%s: WM8985 N value is not within"
+		       " the recommended range: %lu\n", __func__, Ndiv);
+		return -EINVAL;
+	}
+	pll_div->n = Ndiv;
+
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (u64)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xffffffff;
+	if ((K % 10) >= 5)
+		K += 5;
+	K /= 10;
+	pll_div->k = K;
+
+	return 0;
+}
+
+static int wm8985_set_pll(struct snd_soc_dai *dai, int pll_id,
+			  int source, unsigned int freq_in,
+			  unsigned int freq_out)
+{
+	int ret;
+	struct snd_soc_component *component;
+	struct pll_div pll_div;
+
+	component = dai->component;
+	if (!freq_in || !freq_out) {
+		/* disable the PLL */
+		snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
+				    WM8985_PLLEN_MASK, 0);
+	} else {
+		ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in);
+		if (ret)
+			return ret;
+
+		/* set PLLN and PRESCALE */
+		snd_soc_component_write(component, WM8985_PLL_N,
+			      (pll_div.div2 << WM8985_PLL_PRESCALE_SHIFT)
+			      | pll_div.n);
+		/* set PLLK */
+		snd_soc_component_write(component, WM8985_PLL_K_3, pll_div.k & 0x1ff);
+		snd_soc_component_write(component, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
+		snd_soc_component_write(component, WM8985_PLL_K_1, (pll_div.k >> 18));
+		/* set the source of the clock to be the PLL */
+		snd_soc_component_update_bits(component, WM8985_CLOCK_GEN_CONTROL,
+				    WM8985_CLKSEL_MASK, WM8985_CLKSEL);
+		/* enable the PLL */
+		snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
+				    WM8985_PLLEN_MASK, WM8985_PLLEN);
+	}
+	return 0;
+}
+
+static int wm8985_set_sysclk(struct snd_soc_dai *dai,
+			     int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component;
+	struct wm8985_priv *wm8985;
+
+	component = dai->component;
+	wm8985 = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case WM8985_CLKSRC_MCLK:
+		snd_soc_component_update_bits(component, WM8985_CLOCK_GEN_CONTROL,
+				    WM8985_CLKSEL_MASK, 0);
+		snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
+				    WM8985_PLLEN_MASK, 0);
+		break;
+	case WM8985_CLKSRC_PLL:
+		snd_soc_component_update_bits(component, WM8985_CLOCK_GEN_CONTROL,
+				    WM8985_CLKSEL_MASK, WM8985_CLKSEL);
+		break;
+	default:
+		dev_err(dai->dev, "Unknown clock source %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	wm8985->sysclk = freq;
+	return 0;
+}
+
+static int wm8985_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	int ret;
+	struct wm8985_priv *wm8985;
+
+	wm8985 = snd_soc_component_get_drvdata(component);
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		/* VMID at 75k */
+		snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
+				    WM8985_VMIDSEL_MASK,
+				    1 << WM8985_VMIDSEL_SHIFT);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
+						    wm8985->supplies);
+			if (ret) {
+				dev_err(component->dev,
+					"Failed to enable supplies: %d\n",
+					ret);
+				return ret;
+			}
+
+			regcache_sync(wm8985->regmap);
+
+			/* enable anti-pop features */
+			snd_soc_component_update_bits(component, WM8985_OUT4_TO_ADC,
+					    WM8985_POBCTRL_MASK,
+					    WM8985_POBCTRL);
+			/* enable thermal shutdown */
+			snd_soc_component_update_bits(component, WM8985_OUTPUT_CTRL0,
+					    WM8985_TSDEN_MASK, WM8985_TSDEN);
+			snd_soc_component_update_bits(component, WM8985_OUTPUT_CTRL0,
+					    WM8985_TSOPCTRL_MASK,
+					    WM8985_TSOPCTRL);
+			/* enable BIASEN */
+			snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
+					    WM8985_BIASEN_MASK, WM8985_BIASEN);
+			/* VMID at 75k */
+			snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
+					    WM8985_VMIDSEL_MASK,
+					    1 << WM8985_VMIDSEL_SHIFT);
+			msleep(500);
+			/* disable anti-pop features */
+			snd_soc_component_update_bits(component, WM8985_OUT4_TO_ADC,
+					    WM8985_POBCTRL_MASK, 0);
+		}
+		/* VMID at 300k */
+		snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
+				    WM8985_VMIDSEL_MASK,
+				    2 << WM8985_VMIDSEL_SHIFT);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* disable thermal shutdown */
+		snd_soc_component_update_bits(component, WM8985_OUTPUT_CTRL0,
+				    WM8985_TSOPCTRL_MASK, 0);
+		snd_soc_component_update_bits(component, WM8985_OUTPUT_CTRL0,
+				    WM8985_TSDEN_MASK, 0);
+		/* disable VMIDSEL and BIASEN */
+		snd_soc_component_update_bits(component, WM8985_POWER_MANAGEMENT_1,
+				    WM8985_VMIDSEL_MASK | WM8985_BIASEN_MASK,
+				    0);
+		snd_soc_component_write(component, WM8985_POWER_MANAGEMENT_1, 0);
+		snd_soc_component_write(component, WM8985_POWER_MANAGEMENT_2, 0);
+		snd_soc_component_write(component, WM8985_POWER_MANAGEMENT_3, 0);
+
+		regcache_mark_dirty(wm8985->regmap);
+
+		regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies),
+				       wm8985->supplies);
+		break;
+	}
+
+	return 0;
+}
+
+static int wm8985_probe(struct snd_soc_component *component)
+{
+	size_t i;
+	struct wm8985_priv *wm8985;
+	int ret;
+
+	wm8985 = snd_soc_component_get_drvdata(component);
+
+	for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++)
+		wm8985->supplies[i].supply = wm8985_supply_names[i];
+
+	ret = devm_regulator_bulk_get(component->dev, ARRAY_SIZE(wm8985->supplies),
+				 wm8985->supplies);
+	if (ret) {
+		dev_err(component->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
+				    wm8985->supplies);
+	if (ret) {
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = wm8985_reset(component);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
+		goto err_reg_enable;
+	}
+
+	/* latch volume update bits */
+	for (i = 0; i < ARRAY_SIZE(volume_update_regs); ++i)
+		snd_soc_component_update_bits(component, volume_update_regs[i],
+				    0x100, 0x100);
+	/* enable BIASCUT */
+	snd_soc_component_update_bits(component, WM8985_BIAS_CTRL, WM8985_BIASCUT,
+			    WM8985_BIASCUT);
+
+	wm8985_add_widgets(component);
+
+	return 0;
+
+err_reg_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
+	return ret;
+}
+
+static const struct snd_soc_dai_ops wm8985_dai_ops = {
+	.digital_mute = wm8985_dac_mute,
+	.hw_params = wm8985_hw_params,
+	.set_fmt = wm8985_set_fmt,
+	.set_sysclk = wm8985_set_sysclk,
+	.set_pll = wm8985_set_pll
+};
+
+#define WM8985_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm8985_dai = {
+	.name = "wm8985-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = WM8985_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = WM8985_FORMATS,
+	},
+	.ops = &wm8985_dai_ops,
+	.symmetric_rates = 1
+};
+
+static const struct snd_soc_component_driver soc_component_dev_wm8985 = {
+	.probe			= wm8985_probe,
+	.set_bias_level		= wm8985_set_bias_level,
+	.controls		= wm8985_common_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8985_common_snd_controls),
+	.dapm_widgets		= wm8985_common_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8985_common_dapm_widgets),
+	.dapm_routes		= wm8985_common_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8985_common_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8985_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = WM8985_MAX_REGISTER,
+	.writeable_reg = wm8985_writeable,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8985_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8985_reg_defaults),
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8985_spi_probe(struct spi_device *spi)
+{
+	struct wm8985_priv *wm8985;
+	int ret;
+
+	wm8985 = devm_kzalloc(&spi->dev, sizeof *wm8985, GFP_KERNEL);
+	if (!wm8985)
+		return -ENOMEM;
+
+	spi_set_drvdata(spi, wm8985);
+
+	wm8985->dev_type = WM8985;
+
+	wm8985->regmap = devm_regmap_init_spi(spi, &wm8985_regmap);
+	if (IS_ERR(wm8985->regmap)) {
+		ret = PTR_ERR(wm8985->regmap);
+		dev_err(&spi->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+				     &soc_component_dev_wm8985, &wm8985_dai, 1);
+	return ret;
+}
+
+static struct spi_driver wm8985_spi_driver = {
+	.driver = {
+		.name = "wm8985",
+	},
+	.probe = wm8985_spi_probe,
+};
+#endif
+
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8985_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8985_priv *wm8985;
+	int ret;
+
+	wm8985 = devm_kzalloc(&i2c->dev, sizeof *wm8985, GFP_KERNEL);
+	if (!wm8985)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, wm8985);
+
+	wm8985->dev_type = id->driver_data;
+
+	wm8985->regmap = devm_regmap_init_i2c(i2c, &wm8985_regmap);
+	if (IS_ERR(wm8985->regmap)) {
+		ret = PTR_ERR(wm8985->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_wm8985, &wm8985_dai, 1);
+	return ret;
+}
+
+static const struct i2c_device_id wm8985_i2c_id[] = {
+	{ "wm8985", WM8985 },
+	{ "wm8758", WM8758 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8985_i2c_id);
+
+static struct i2c_driver wm8985_i2c_driver = {
+	.driver = {
+		.name = "wm8985",
+	},
+	.probe = wm8985_i2c_probe,
+	.id_table = wm8985_i2c_id
+};
+#endif
+
+static int __init wm8985_modinit(void)
+{
+	int ret = 0;
+
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&wm8985_i2c_driver);
+	if (ret) {
+		printk(KERN_ERR "Failed to register wm8985 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8985_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register wm8985 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return ret;
+}
+module_init(wm8985_modinit);
+
+static void __exit wm8985_exit(void)
+{
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&wm8985_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8985_spi_driver);
+#endif
+}
+module_exit(wm8985_exit);
+
+MODULE_DESCRIPTION("ASoC WM8985 / WM8758 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8985.h b/sound/soc/codecs/wm8985.h
new file mode 100644
index 0000000..41b1048
--- /dev/null
+++ b/sound/soc/codecs/wm8985.h
@@ -0,0 +1,1083 @@
+/*
+ * wm8985.h  --  WM8985 ASoC driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8985_H
+#define _WM8985_H
+
+#define WM8985_SOFTWARE_RESET                   0x00
+#define WM8985_POWER_MANAGEMENT_1               0x01
+#define WM8985_POWER_MANAGEMENT_2               0x02
+#define WM8985_POWER_MANAGEMENT_3               0x03
+#define WM8985_AUDIO_INTERFACE                  0x04
+#define WM8985_COMPANDING_CONTROL               0x05
+#define WM8985_CLOCK_GEN_CONTROL                0x06
+#define WM8985_ADDITIONAL_CONTROL               0x07
+#define WM8985_GPIO_CONTROL                     0x08
+#define WM8985_JACK_DETECT_CONTROL_1            0x09
+#define WM8985_DAC_CONTROL                      0x0A
+#define WM8985_LEFT_DAC_DIGITAL_VOL             0x0B
+#define WM8985_RIGHT_DAC_DIGITAL_VOL            0x0C
+#define WM8985_JACK_DETECT_CONTROL_2            0x0D
+#define WM8985_ADC_CONTROL                      0x0E
+#define WM8985_LEFT_ADC_DIGITAL_VOL             0x0F
+#define WM8985_RIGHT_ADC_DIGITAL_VOL            0x10
+#define WM8985_EQ1_LOW_SHELF                    0x12
+#define WM8985_EQ2_PEAK_1                       0x13
+#define WM8985_EQ3_PEAK_2                       0x14
+#define WM8985_EQ4_PEAK_3                       0x15
+#define WM8985_EQ5_HIGH_SHELF                   0x16
+#define WM8985_DAC_LIMITER_1                    0x18
+#define WM8985_DAC_LIMITER_2                    0x19
+#define WM8985_NOTCH_FILTER_1                   0x1B
+#define WM8985_NOTCH_FILTER_2                   0x1C
+#define WM8985_NOTCH_FILTER_3                   0x1D
+#define WM8985_NOTCH_FILTER_4                   0x1E
+#define WM8985_ALC_CONTROL_1                    0x20
+#define WM8985_ALC_CONTROL_2                    0x21
+#define WM8985_ALC_CONTROL_3                    0x22
+#define WM8985_NOISE_GATE                       0x23
+#define WM8985_PLL_N                            0x24
+#define WM8985_PLL_K_1                          0x25
+#define WM8985_PLL_K_2                          0x26
+#define WM8985_PLL_K_3                          0x27
+#define WM8985_3D_CONTROL                       0x29
+#define WM8985_OUT4_TO_ADC                      0x2A
+#define WM8985_BEEP_CONTROL                     0x2B
+#define WM8985_INPUT_CTRL                       0x2C
+#define WM8985_LEFT_INP_PGA_GAIN_CTRL           0x2D
+#define WM8985_RIGHT_INP_PGA_GAIN_CTRL          0x2E
+#define WM8985_LEFT_ADC_BOOST_CTRL              0x2F
+#define WM8985_RIGHT_ADC_BOOST_CTRL             0x30
+#define WM8985_OUTPUT_CTRL0                     0x31
+#define WM8985_LEFT_MIXER_CTRL                  0x32
+#define WM8985_RIGHT_MIXER_CTRL                 0x33
+#define WM8985_LOUT1_HP_VOLUME_CTRL             0x34
+#define WM8985_ROUT1_HP_VOLUME_CTRL             0x35
+#define WM8985_LOUT2_SPK_VOLUME_CTRL            0x36
+#define WM8985_ROUT2_SPK_VOLUME_CTRL            0x37
+#define WM8985_OUT3_MIXER_CTRL                  0x38
+#define WM8985_OUT4_MONO_MIX_CTRL               0x39
+#define WM8985_OUTPUT_CTRL1                     0x3C
+#define WM8985_BIAS_CTRL                        0x3D
+
+#define WM8985_REGISTER_COUNT                   59
+#define WM8985_MAX_REGISTER                     0x3F
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8985_SOFTWARE_RESET_MASK              0x01FF  /* SOFTWARE_RESET - [8:0] */
+#define WM8985_SOFTWARE_RESET_SHIFT                  0  /* SOFTWARE_RESET - [8:0] */
+#define WM8985_SOFTWARE_RESET_WIDTH                  9  /* SOFTWARE_RESET - [8:0] */
+
+/*
+ * R1 (0x01) - Power management 1
+ */
+#define WM8985_OUT4MIXEN                        0x0080  /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_MASK                   0x0080  /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_SHIFT                       7  /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_WIDTH                       1  /* OUT4MIXEN */
+#define WM8985_OUT3MIXEN                        0x0040  /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_MASK                   0x0040  /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_SHIFT                       6  /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_WIDTH                       1  /* OUT3MIXEN */
+#define WM8985_PLLEN                            0x0020  /* PLLEN */
+#define WM8985_PLLEN_MASK                       0x0020  /* PLLEN */
+#define WM8985_PLLEN_SHIFT                           5  /* PLLEN */
+#define WM8985_PLLEN_WIDTH                           1  /* PLLEN */
+#define WM8985_MICBEN                           0x0010  /* MICBEN */
+#define WM8985_MICBEN_MASK                      0x0010  /* MICBEN */
+#define WM8985_MICBEN_SHIFT                          4  /* MICBEN */
+#define WM8985_MICBEN_WIDTH                          1  /* MICBEN */
+#define WM8985_BIASEN                           0x0008  /* BIASEN */
+#define WM8985_BIASEN_MASK                      0x0008  /* BIASEN */
+#define WM8985_BIASEN_SHIFT                          3  /* BIASEN */
+#define WM8985_BIASEN_WIDTH                          1  /* BIASEN */
+#define WM8985_BUFIOEN                          0x0004  /* BUFIOEN */
+#define WM8985_BUFIOEN_MASK                     0x0004  /* BUFIOEN */
+#define WM8985_BUFIOEN_SHIFT                         2  /* BUFIOEN */
+#define WM8985_BUFIOEN_WIDTH                         1  /* BUFIOEN */
+#define WM8985_VMIDSEL                          0x0003  /* VMIDSEL */
+#define WM8985_VMIDSEL_MASK                     0x0003  /* VMIDSEL - [1:0] */
+#define WM8985_VMIDSEL_SHIFT                         0  /* VMIDSEL - [1:0] */
+#define WM8985_VMIDSEL_WIDTH                         2  /* VMIDSEL - [1:0] */
+
+/*
+ * R2 (0x02) - Power management 2
+ */
+#define WM8985_ROUT1EN                          0x0100  /* ROUT1EN */
+#define WM8985_ROUT1EN_MASK                     0x0100  /* ROUT1EN */
+#define WM8985_ROUT1EN_SHIFT                         8  /* ROUT1EN */
+#define WM8985_ROUT1EN_WIDTH                         1  /* ROUT1EN */
+#define WM8985_LOUT1EN                          0x0080  /* LOUT1EN */
+#define WM8985_LOUT1EN_MASK                     0x0080  /* LOUT1EN */
+#define WM8985_LOUT1EN_SHIFT                         7  /* LOUT1EN */
+#define WM8985_LOUT1EN_WIDTH                         1  /* LOUT1EN */
+#define WM8985_SLEEP                            0x0040  /* SLEEP */
+#define WM8985_SLEEP_MASK                       0x0040  /* SLEEP */
+#define WM8985_SLEEP_SHIFT                           6  /* SLEEP */
+#define WM8985_SLEEP_WIDTH                           1  /* SLEEP */
+#define WM8985_BOOSTENR                         0x0020  /* BOOSTENR */
+#define WM8985_BOOSTENR_MASK                    0x0020  /* BOOSTENR */
+#define WM8985_BOOSTENR_SHIFT                        5  /* BOOSTENR */
+#define WM8985_BOOSTENR_WIDTH                        1  /* BOOSTENR */
+#define WM8985_BOOSTENL                         0x0010  /* BOOSTENL */
+#define WM8985_BOOSTENL_MASK                    0x0010  /* BOOSTENL */
+#define WM8985_BOOSTENL_SHIFT                        4  /* BOOSTENL */
+#define WM8985_BOOSTENL_WIDTH                        1  /* BOOSTENL */
+#define WM8985_INPGAENR                         0x0008  /* INPGAENR */
+#define WM8985_INPGAENR_MASK                    0x0008  /* INPGAENR */
+#define WM8985_INPGAENR_SHIFT                        3  /* INPGAENR */
+#define WM8985_INPGAENR_WIDTH                        1  /* INPGAENR */
+#define WM8985_INPPGAENL                        0x0004  /* INPPGAENL */
+#define WM8985_INPPGAENL_MASK                   0x0004  /* INPPGAENL */
+#define WM8985_INPPGAENL_SHIFT                       2  /* INPPGAENL */
+#define WM8985_INPPGAENL_WIDTH                       1  /* INPPGAENL */
+#define WM8985_ADCENR                           0x0002  /* ADCENR */
+#define WM8985_ADCENR_MASK                      0x0002  /* ADCENR */
+#define WM8985_ADCENR_SHIFT                          1  /* ADCENR */
+#define WM8985_ADCENR_WIDTH                          1  /* ADCENR */
+#define WM8985_ADCENL                           0x0001  /* ADCENL */
+#define WM8985_ADCENL_MASK                      0x0001  /* ADCENL */
+#define WM8985_ADCENL_SHIFT                          0  /* ADCENL */
+#define WM8985_ADCENL_WIDTH                          1  /* ADCENL */
+
+/*
+ * R3 (0x03) - Power management 3
+ */
+#define WM8985_OUT4EN                           0x0100  /* OUT4EN */
+#define WM8985_OUT4EN_MASK                      0x0100  /* OUT4EN */
+#define WM8985_OUT4EN_SHIFT                          8  /* OUT4EN */
+#define WM8985_OUT4EN_WIDTH                          1  /* OUT4EN */
+#define WM8985_OUT3EN                           0x0080  /* OUT3EN */
+#define WM8985_OUT3EN_MASK                      0x0080  /* OUT3EN */
+#define WM8985_OUT3EN_SHIFT                          7  /* OUT3EN */
+#define WM8985_OUT3EN_WIDTH                          1  /* OUT3EN */
+#define WM8985_ROUT2EN                          0x0040  /* ROUT2EN */
+#define WM8985_ROUT2EN_MASK                     0x0040  /* ROUT2EN */
+#define WM8985_ROUT2EN_SHIFT                         6  /* ROUT2EN */
+#define WM8985_ROUT2EN_WIDTH                         1  /* ROUT2EN */
+#define WM8985_LOUT2EN                          0x0020  /* LOUT2EN */
+#define WM8985_LOUT2EN_MASK                     0x0020  /* LOUT2EN */
+#define WM8985_LOUT2EN_SHIFT                         5  /* LOUT2EN */
+#define WM8985_LOUT2EN_WIDTH                         1  /* LOUT2EN */
+#define WM8985_RMIXEN                           0x0008  /* RMIXEN */
+#define WM8985_RMIXEN_MASK                      0x0008  /* RMIXEN */
+#define WM8985_RMIXEN_SHIFT                          3  /* RMIXEN */
+#define WM8985_RMIXEN_WIDTH                          1  /* RMIXEN */
+#define WM8985_LMIXEN                           0x0004  /* LMIXEN */
+#define WM8985_LMIXEN_MASK                      0x0004  /* LMIXEN */
+#define WM8985_LMIXEN_SHIFT                          2  /* LMIXEN */
+#define WM8985_LMIXEN_WIDTH                          1  /* LMIXEN */
+#define WM8985_DACENR                           0x0002  /* DACENR */
+#define WM8985_DACENR_MASK                      0x0002  /* DACENR */
+#define WM8985_DACENR_SHIFT                          1  /* DACENR */
+#define WM8985_DACENR_WIDTH                          1  /* DACENR */
+#define WM8985_DACENL                           0x0001  /* DACENL */
+#define WM8985_DACENL_MASK                      0x0001  /* DACENL */
+#define WM8985_DACENL_SHIFT                          0  /* DACENL */
+#define WM8985_DACENL_WIDTH                          1  /* DACENL */
+
+/*
+ * R4 (0x04) - Audio Interface
+ */
+#define WM8985_BCP                              0x0100  /* BCP */
+#define WM8985_BCP_MASK                         0x0100  /* BCP */
+#define WM8985_BCP_SHIFT                             8  /* BCP */
+#define WM8985_BCP_WIDTH                             1  /* BCP */
+#define WM8985_LRP                              0x0080  /* LRP */
+#define WM8985_LRP_MASK                         0x0080  /* LRP */
+#define WM8985_LRP_SHIFT                             7  /* LRP */
+#define WM8985_LRP_WIDTH                             1  /* LRP */
+#define WM8985_WL_MASK                          0x0060  /* WL - [6:5] */
+#define WM8985_WL_SHIFT                              5  /* WL - [6:5] */
+#define WM8985_WL_WIDTH                              2  /* WL - [6:5] */
+#define WM8985_FMT_MASK                         0x0018  /* FMT - [4:3] */
+#define WM8985_FMT_SHIFT                             3  /* FMT - [4:3] */
+#define WM8985_FMT_WIDTH                             2  /* FMT - [4:3] */
+#define WM8985_DLRSWAP                          0x0004  /* DLRSWAP */
+#define WM8985_DLRSWAP_MASK                     0x0004  /* DLRSWAP */
+#define WM8985_DLRSWAP_SHIFT                         2  /* DLRSWAP */
+#define WM8985_DLRSWAP_WIDTH                         1  /* DLRSWAP */
+#define WM8985_ALRSWAP                          0x0002  /* ALRSWAP */
+#define WM8985_ALRSWAP_MASK                     0x0002  /* ALRSWAP */
+#define WM8985_ALRSWAP_SHIFT                         1  /* ALRSWAP */
+#define WM8985_ALRSWAP_WIDTH                         1  /* ALRSWAP */
+#define WM8985_MONO                             0x0001  /* MONO */
+#define WM8985_MONO_MASK                        0x0001  /* MONO */
+#define WM8985_MONO_SHIFT                            0  /* MONO */
+#define WM8985_MONO_WIDTH                            1  /* MONO */
+
+/*
+ * R5 (0x05) - Companding control
+ */
+#define WM8985_WL8                              0x0020  /* WL8 */
+#define WM8985_WL8_MASK                         0x0020  /* WL8 */
+#define WM8985_WL8_SHIFT                             5  /* WL8 */
+#define WM8985_WL8_WIDTH                             1  /* WL8 */
+#define WM8985_DAC_COMP_MASK                    0x0018  /* DAC_COMP - [4:3] */
+#define WM8985_DAC_COMP_SHIFT                        3  /* DAC_COMP - [4:3] */
+#define WM8985_DAC_COMP_WIDTH                        2  /* DAC_COMP - [4:3] */
+#define WM8985_ADC_COMP_MASK                    0x0006  /* ADC_COMP - [2:1] */
+#define WM8985_ADC_COMP_SHIFT                        1  /* ADC_COMP - [2:1] */
+#define WM8985_ADC_COMP_WIDTH                        2  /* ADC_COMP - [2:1] */
+#define WM8985_LOOPBACK                         0x0001  /* LOOPBACK */
+#define WM8985_LOOPBACK_MASK                    0x0001  /* LOOPBACK */
+#define WM8985_LOOPBACK_SHIFT                        0  /* LOOPBACK */
+#define WM8985_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+
+/*
+ * R6 (0x06) - Clock Gen control
+ */
+#define WM8985_CLKSEL                           0x0100  /* CLKSEL */
+#define WM8985_CLKSEL_MASK                      0x0100  /* CLKSEL */
+#define WM8985_CLKSEL_SHIFT                          8  /* CLKSEL */
+#define WM8985_CLKSEL_WIDTH                          1  /* CLKSEL */
+#define WM8985_MCLKDIV_MASK                     0x00E0  /* MCLKDIV - [7:5] */
+#define WM8985_MCLKDIV_SHIFT                         5  /* MCLKDIV - [7:5] */
+#define WM8985_MCLKDIV_WIDTH                         3  /* MCLKDIV - [7:5] */
+#define WM8985_BCLKDIV_MASK                     0x001C  /* BCLKDIV - [4:2] */
+#define WM8985_BCLKDIV_SHIFT                         2  /* BCLKDIV - [4:2] */
+#define WM8985_BCLKDIV_WIDTH                         3  /* BCLKDIV - [4:2] */
+#define WM8985_MS                               0x0001  /* MS */
+#define WM8985_MS_MASK                          0x0001  /* MS */
+#define WM8985_MS_SHIFT                              0  /* MS */
+#define WM8985_MS_WIDTH                              1  /* MS */
+
+/*
+ * R7 (0x07) - Additional control
+ */
+#define WM8985_M128ENB                          0x0100  /* M128ENB */
+#define WM8985_M128ENB_MASK                     0x0100  /* M128ENB */
+#define WM8985_M128ENB_SHIFT                         8  /* M128ENB */
+#define WM8985_M128ENB_WIDTH                         1  /* M128ENB */
+#define WM8985_DCLKDIV_MASK                     0x00F0  /* DCLKDIV - [7:4] */
+#define WM8985_DCLKDIV_SHIFT                         4  /* DCLKDIV - [7:4] */
+#define WM8985_DCLKDIV_WIDTH                         4  /* DCLKDIV - [7:4] */
+#define WM8985_SR_MASK                          0x000E  /* SR - [3:1] */
+#define WM8985_SR_SHIFT                              1  /* SR - [3:1] */
+#define WM8985_SR_WIDTH                              3  /* SR - [3:1] */
+#define WM8985_SLOWCLKEN                        0x0001  /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_MASK                   0x0001  /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_SHIFT                       0  /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_WIDTH                       1  /* SLOWCLKEN */
+
+/*
+ * R8 (0x08) - GPIO Control
+ */
+#define WM8985_GPIO1GP                          0x0100  /* GPIO1GP */
+#define WM8985_GPIO1GP_MASK                     0x0100  /* GPIO1GP */
+#define WM8985_GPIO1GP_SHIFT                         8  /* GPIO1GP */
+#define WM8985_GPIO1GP_WIDTH                         1  /* GPIO1GP */
+#define WM8985_GPIO1GPU                         0x0080  /* GPIO1GPU */
+#define WM8985_GPIO1GPU_MASK                    0x0080  /* GPIO1GPU */
+#define WM8985_GPIO1GPU_SHIFT                        7  /* GPIO1GPU */
+#define WM8985_GPIO1GPU_WIDTH                        1  /* GPIO1GPU */
+#define WM8985_GPIO1GPD                         0x0040  /* GPIO1GPD */
+#define WM8985_GPIO1GPD_MASK                    0x0040  /* GPIO1GPD */
+#define WM8985_GPIO1GPD_SHIFT                        6  /* GPIO1GPD */
+#define WM8985_GPIO1GPD_WIDTH                        1  /* GPIO1GPD */
+#define WM8758_OPCLKDIV_MASK                    0x0030  /* OPCLKDIV - [1:0] */
+#define WM8758_OPCLKDIV_SHIFT                        4  /* OPCLKDIV - [1:0] */
+#define WM8758_OPCLKDIV_WIDTH                        2  /* OPCLKDIV - [1:0] */
+#define WM8985_GPIO1POL                         0x0008  /* GPIO1POL */
+#define WM8985_GPIO1POL_MASK                    0x0008  /* GPIO1POL */
+#define WM8985_GPIO1POL_SHIFT                        3  /* GPIO1POL */
+#define WM8985_GPIO1POL_WIDTH                        1  /* GPIO1POL */
+#define WM8985_GPIO1SEL_MASK                    0x0007  /* GPIO1SEL - [2:0] */
+#define WM8985_GPIO1SEL_SHIFT                        0  /* GPIO1SEL - [2:0] */
+#define WM8985_GPIO1SEL_WIDTH                        3  /* GPIO1SEL - [2:0] */
+
+/*
+ * R9 (0x09) - Jack Detect Control 1
+ */
+#define WM8758_JD_VMID1_MASK                    0x0100  /* JD_VMID1 */
+#define WM8758_JD_VMID1_SHIFT                        8  /* JD_VMID1 */
+#define WM8758_JD_VMID1_WIDTH                        1  /* JD_VMID1 */
+#define WM8758_JD_VMID0_MASK                    0x0080  /* JD_VMID0 */
+#define WM8758_JD_VMID0_SHIFT                        7  /* JD_VMID0 */
+#define WM8758_JD_VMID0_WIDTH                        1  /* JD_VMID0 */
+#define WM8985_JD_EN                            0x0040  /* JD_EN */
+#define WM8985_JD_EN_MASK                       0x0040  /* JD_EN */
+#define WM8985_JD_EN_SHIFT                           6  /* JD_EN */
+#define WM8985_JD_EN_WIDTH                           1  /* JD_EN */
+#define WM8985_JD_SEL_MASK                      0x0030  /* JD_SEL - [5:4] */
+#define WM8985_JD_SEL_SHIFT                          4  /* JD_SEL - [5:4] */
+#define WM8985_JD_SEL_WIDTH                          2  /* JD_SEL - [5:4] */
+
+/*
+ * R10 (0x0A) - DAC Control
+ */
+#define WM8985_SOFTMUTE                         0x0040  /* SOFTMUTE */
+#define WM8985_SOFTMUTE_MASK                    0x0040  /* SOFTMUTE */
+#define WM8985_SOFTMUTE_SHIFT                        6  /* SOFTMUTE */
+#define WM8985_SOFTMUTE_WIDTH                        1  /* SOFTMUTE */
+#define WM8985_DACOSR128                        0x0008  /* DACOSR128 */
+#define WM8985_DACOSR128_MASK                   0x0008  /* DACOSR128 */
+#define WM8985_DACOSR128_SHIFT                       3  /* DACOSR128 */
+#define WM8985_DACOSR128_WIDTH                       1  /* DACOSR128 */
+#define WM8985_AMUTE                            0x0004  /* AMUTE */
+#define WM8985_AMUTE_MASK                       0x0004  /* AMUTE */
+#define WM8985_AMUTE_SHIFT                           2  /* AMUTE */
+#define WM8985_AMUTE_WIDTH                           1  /* AMUTE */
+#define WM8985_DACPOLR                          0x0002  /* DACPOLR */
+#define WM8985_DACPOLR_MASK                     0x0002  /* DACPOLR */
+#define WM8985_DACPOLR_SHIFT                         1  /* DACPOLR */
+#define WM8985_DACPOLR_WIDTH                         1  /* DACPOLR */
+#define WM8985_DACPOLL                          0x0001  /* DACPOLL */
+#define WM8985_DACPOLL_MASK                     0x0001  /* DACPOLL */
+#define WM8985_DACPOLL_SHIFT                         0  /* DACPOLL */
+#define WM8985_DACPOLL_WIDTH                         1  /* DACPOLL */
+
+/*
+ * R11 (0x0B) - Left DAC digital Vol
+ */
+#define WM8985_DACVU                            0x0100  /* DACVU */
+#define WM8985_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8985_DACVU_SHIFT                           8  /* DACVU */
+#define WM8985_DACVU_WIDTH                           1  /* DACVU */
+#define WM8985_DACVOLL_MASK                     0x00FF  /* DACVOLL - [7:0] */
+#define WM8985_DACVOLL_SHIFT                         0  /* DACVOLL - [7:0] */
+#define WM8985_DACVOLL_WIDTH                         8  /* DACVOLL - [7:0] */
+
+/*
+ * R12 (0x0C) - Right DAC digital vol
+ */
+#define WM8985_DACVU                            0x0100  /* DACVU */
+#define WM8985_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8985_DACVU_SHIFT                           8  /* DACVU */
+#define WM8985_DACVU_WIDTH                           1  /* DACVU */
+#define WM8985_DACVOLR_MASK                     0x00FF  /* DACVOLR - [7:0] */
+#define WM8985_DACVOLR_SHIFT                         0  /* DACVOLR - [7:0] */
+#define WM8985_DACVOLR_WIDTH                         8  /* DACVOLR - [7:0] */
+
+/*
+ * R13 (0x0D) - Jack Detect Control 2
+ */
+#define WM8985_JD_EN1_MASK                      0x00F0  /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN1_SHIFT                          4  /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN1_WIDTH                          4  /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN0_MASK                      0x000F  /* JD_EN0 - [3:0] */
+#define WM8985_JD_EN0_SHIFT                          0  /* JD_EN0 - [3:0] */
+#define WM8985_JD_EN0_WIDTH                          4  /* JD_EN0 - [3:0] */
+
+/*
+ * R14 (0x0E) - ADC Control
+ */
+#define WM8985_HPFEN                            0x0100  /* HPFEN */
+#define WM8985_HPFEN_MASK                       0x0100  /* HPFEN */
+#define WM8985_HPFEN_SHIFT                           8  /* HPFEN */
+#define WM8985_HPFEN_WIDTH                           1  /* HPFEN */
+#define WM8985_HPFAPP                           0x0080  /* HPFAPP */
+#define WM8985_HPFAPP_MASK                      0x0080  /* HPFAPP */
+#define WM8985_HPFAPP_SHIFT                          7  /* HPFAPP */
+#define WM8985_HPFAPP_WIDTH                          1  /* HPFAPP */
+#define WM8985_HPFCUT_MASK                      0x0070  /* HPFCUT - [6:4] */
+#define WM8985_HPFCUT_SHIFT                          4  /* HPFCUT - [6:4] */
+#define WM8985_HPFCUT_WIDTH                          3  /* HPFCUT - [6:4] */
+#define WM8985_ADCOSR128                        0x0008  /* ADCOSR128 */
+#define WM8985_ADCOSR128_MASK                   0x0008  /* ADCOSR128 */
+#define WM8985_ADCOSR128_SHIFT                       3  /* ADCOSR128 */
+#define WM8985_ADCOSR128_WIDTH                       1  /* ADCOSR128 */
+#define WM8985_ADCRPOL                          0x0002  /* ADCRPOL */
+#define WM8985_ADCRPOL_MASK                     0x0002  /* ADCRPOL */
+#define WM8985_ADCRPOL_SHIFT                         1  /* ADCRPOL */
+#define WM8985_ADCRPOL_WIDTH                         1  /* ADCRPOL */
+#define WM8985_ADCLPOL                          0x0001  /* ADCLPOL */
+#define WM8985_ADCLPOL_MASK                     0x0001  /* ADCLPOL */
+#define WM8985_ADCLPOL_SHIFT                         0  /* ADCLPOL */
+#define WM8985_ADCLPOL_WIDTH                         1  /* ADCLPOL */
+
+/*
+ * R15 (0x0F) - Left ADC Digital Vol
+ */
+#define WM8985_ADCVU                            0x0100  /* ADCVU */
+#define WM8985_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8985_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8985_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8985_ADCVOLL_MASK                     0x00FF  /* ADCVOLL - [7:0] */
+#define WM8985_ADCVOLL_SHIFT                         0  /* ADCVOLL - [7:0] */
+#define WM8985_ADCVOLL_WIDTH                         8  /* ADCVOLL - [7:0] */
+
+/*
+ * R16 (0x10) - Right ADC Digital Vol
+ */
+#define WM8985_ADCVU                            0x0100  /* ADCVU */
+#define WM8985_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8985_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8985_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8985_ADCVOLR_MASK                     0x00FF  /* ADCVOLR - [7:0] */
+#define WM8985_ADCVOLR_SHIFT                         0  /* ADCVOLR - [7:0] */
+#define WM8985_ADCVOLR_WIDTH                         8  /* ADCVOLR - [7:0] */
+
+/*
+ * R18 (0x12) - EQ1 - low shelf
+ */
+#define WM8985_EQ3DMODE                         0x0100  /* EQ3DMODE */
+#define WM8985_EQ3DMODE_MASK                    0x0100  /* EQ3DMODE */
+#define WM8985_EQ3DMODE_SHIFT                        8  /* EQ3DMODE */
+#define WM8985_EQ3DMODE_WIDTH                        1  /* EQ3DMODE */
+#define WM8985_EQ1C_MASK                        0x0060  /* EQ1C - [6:5] */
+#define WM8985_EQ1C_SHIFT                            5  /* EQ1C - [6:5] */
+#define WM8985_EQ1C_WIDTH                            2  /* EQ1C - [6:5] */
+#define WM8985_EQ1G_MASK                        0x001F  /* EQ1G - [4:0] */
+#define WM8985_EQ1G_SHIFT                            0  /* EQ1G - [4:0] */
+#define WM8985_EQ1G_WIDTH                            5  /* EQ1G - [4:0] */
+
+/*
+ * R19 (0x13) - EQ2 - peak 1
+ */
+#define WM8985_EQ2BW                            0x0100  /* EQ2BW */
+#define WM8985_EQ2BW_MASK                       0x0100  /* EQ2BW */
+#define WM8985_EQ2BW_SHIFT                           8  /* EQ2BW */
+#define WM8985_EQ2BW_WIDTH                           1  /* EQ2BW */
+#define WM8985_EQ2C_MASK                        0x0060  /* EQ2C - [6:5] */
+#define WM8985_EQ2C_SHIFT                            5  /* EQ2C - [6:5] */
+#define WM8985_EQ2C_WIDTH                            2  /* EQ2C - [6:5] */
+#define WM8985_EQ2G_MASK                        0x001F  /* EQ2G - [4:0] */
+#define WM8985_EQ2G_SHIFT                            0  /* EQ2G - [4:0] */
+#define WM8985_EQ2G_WIDTH                            5  /* EQ2G - [4:0] */
+
+/*
+ * R20 (0x14) - EQ3 - peak 2
+ */
+#define WM8985_EQ3BW                            0x0100  /* EQ3BW */
+#define WM8985_EQ3BW_MASK                       0x0100  /* EQ3BW */
+#define WM8985_EQ3BW_SHIFT                           8  /* EQ3BW */
+#define WM8985_EQ3BW_WIDTH                           1  /* EQ3BW */
+#define WM8985_EQ3C_MASK                        0x0060  /* EQ3C - [6:5] */
+#define WM8985_EQ3C_SHIFT                            5  /* EQ3C - [6:5] */
+#define WM8985_EQ3C_WIDTH                            2  /* EQ3C - [6:5] */
+#define WM8985_EQ3G_MASK                        0x001F  /* EQ3G - [4:0] */
+#define WM8985_EQ3G_SHIFT                            0  /* EQ3G - [4:0] */
+#define WM8985_EQ3G_WIDTH                            5  /* EQ3G - [4:0] */
+
+/*
+ * R21 (0x15) - EQ4 - peak 3
+ */
+#define WM8985_EQ4BW                            0x0100  /* EQ4BW */
+#define WM8985_EQ4BW_MASK                       0x0100  /* EQ4BW */
+#define WM8985_EQ4BW_SHIFT                           8  /* EQ4BW */
+#define WM8985_EQ4BW_WIDTH                           1  /* EQ4BW */
+#define WM8985_EQ4C_MASK                        0x0060  /* EQ4C - [6:5] */
+#define WM8985_EQ4C_SHIFT                            5  /* EQ4C - [6:5] */
+#define WM8985_EQ4C_WIDTH                            2  /* EQ4C - [6:5] */
+#define WM8985_EQ4G_MASK                        0x001F  /* EQ4G - [4:0] */
+#define WM8985_EQ4G_SHIFT                            0  /* EQ4G - [4:0] */
+#define WM8985_EQ4G_WIDTH                            5  /* EQ4G - [4:0] */
+
+/*
+ * R22 (0x16) - EQ5 - high shelf
+ */
+#define WM8985_EQ5C_MASK                        0x0060  /* EQ5C - [6:5] */
+#define WM8985_EQ5C_SHIFT                            5  /* EQ5C - [6:5] */
+#define WM8985_EQ5C_WIDTH                            2  /* EQ5C - [6:5] */
+#define WM8985_EQ5G_MASK                        0x001F  /* EQ5G - [4:0] */
+#define WM8985_EQ5G_SHIFT                            0  /* EQ5G - [4:0] */
+#define WM8985_EQ5G_WIDTH                            5  /* EQ5G - [4:0] */
+
+/*
+ * R24 (0x18) - DAC Limiter 1
+ */
+#define WM8985_LIMEN                            0x0100  /* LIMEN */
+#define WM8985_LIMEN_MASK                       0x0100  /* LIMEN */
+#define WM8985_LIMEN_SHIFT                           8  /* LIMEN */
+#define WM8985_LIMEN_WIDTH                           1  /* LIMEN */
+#define WM8985_LIMDCY_MASK                      0x00F0  /* LIMDCY - [7:4] */
+#define WM8985_LIMDCY_SHIFT                          4  /* LIMDCY - [7:4] */
+#define WM8985_LIMDCY_WIDTH                          4  /* LIMDCY - [7:4] */
+#define WM8985_LIMATK_MASK                      0x000F  /* LIMATK - [3:0] */
+#define WM8985_LIMATK_SHIFT                          0  /* LIMATK - [3:0] */
+#define WM8985_LIMATK_WIDTH                          4  /* LIMATK - [3:0] */
+
+/*
+ * R25 (0x19) - DAC Limiter 2
+ */
+#define WM8985_LIMLVL_MASK                      0x0070  /* LIMLVL - [6:4] */
+#define WM8985_LIMLVL_SHIFT                          4  /* LIMLVL - [6:4] */
+#define WM8985_LIMLVL_WIDTH                          3  /* LIMLVL - [6:4] */
+#define WM8985_LIMBOOST_MASK                    0x000F  /* LIMBOOST - [3:0] */
+#define WM8985_LIMBOOST_SHIFT                        0  /* LIMBOOST - [3:0] */
+#define WM8985_LIMBOOST_WIDTH                        4  /* LIMBOOST - [3:0] */
+
+/*
+ * R27 (0x1B) - Notch Filter 1
+ */
+#define WM8985_NFU                              0x0100  /* NFU */
+#define WM8985_NFU_MASK                         0x0100  /* NFU */
+#define WM8985_NFU_SHIFT                             8  /* NFU */
+#define WM8985_NFU_WIDTH                             1  /* NFU */
+#define WM8985_NFEN                             0x0080  /* NFEN */
+#define WM8985_NFEN_MASK                        0x0080  /* NFEN */
+#define WM8985_NFEN_SHIFT                            7  /* NFEN */
+#define WM8985_NFEN_WIDTH                            1  /* NFEN */
+#define WM8985_NFA0_13_7_MASK                   0x007F  /* NFA0(13:7) - [6:0] */
+#define WM8985_NFA0_13_7_SHIFT                       0  /* NFA0(13:7) - [6:0] */
+#define WM8985_NFA0_13_7_WIDTH                       7  /* NFA0(13:7) - [6:0] */
+
+/*
+ * R28 (0x1C) - Notch Filter 2
+ */
+#define WM8985_NFU                              0x0100  /* NFU */
+#define WM8985_NFU_MASK                         0x0100  /* NFU */
+#define WM8985_NFU_SHIFT                             8  /* NFU */
+#define WM8985_NFU_WIDTH                             1  /* NFU */
+#define WM8985_NFA0_6_0_MASK                    0x007F  /* NFA0(6:0) - [6:0] */
+#define WM8985_NFA0_6_0_SHIFT                        0  /* NFA0(6:0) - [6:0] */
+#define WM8985_NFA0_6_0_WIDTH                        7  /* NFA0(6:0) - [6:0] */
+
+/*
+ * R29 (0x1D) - Notch Filter 3
+ */
+#define WM8985_NFU                              0x0100  /* NFU */
+#define WM8985_NFU_MASK                         0x0100  /* NFU */
+#define WM8985_NFU_SHIFT                             8  /* NFU */
+#define WM8985_NFU_WIDTH                             1  /* NFU */
+#define WM8985_NFA1_13_7_MASK                   0x007F  /* NFA1(13:7) - [6:0] */
+#define WM8985_NFA1_13_7_SHIFT                       0  /* NFA1(13:7) - [6:0] */
+#define WM8985_NFA1_13_7_WIDTH                       7  /* NFA1(13:7) - [6:0] */
+
+/*
+ * R30 (0x1E) - Notch Filter 4
+ */
+#define WM8985_NFU                              0x0100  /* NFU */
+#define WM8985_NFU_MASK                         0x0100  /* NFU */
+#define WM8985_NFU_SHIFT                             8  /* NFU */
+#define WM8985_NFU_WIDTH                             1  /* NFU */
+#define WM8985_NFA1_6_0_MASK                    0x007F  /* NFA1(6:0) - [6:0] */
+#define WM8985_NFA1_6_0_SHIFT                        0  /* NFA1(6:0) - [6:0] */
+#define WM8985_NFA1_6_0_WIDTH                        7  /* NFA1(6:0) - [6:0] */
+
+/*
+ * R32 (0x20) - ALC control 1
+ */
+#define WM8985_ALCSEL_MASK                      0x0180  /* ALCSEL - [8:7] */
+#define WM8985_ALCSEL_SHIFT                          7  /* ALCSEL - [8:7] */
+#define WM8985_ALCSEL_WIDTH                          2  /* ALCSEL - [8:7] */
+#define WM8985_ALCMAX_MASK                      0x0038  /* ALCMAX - [5:3] */
+#define WM8985_ALCMAX_SHIFT                          3  /* ALCMAX - [5:3] */
+#define WM8985_ALCMAX_WIDTH                          3  /* ALCMAX - [5:3] */
+#define WM8985_ALCMIN_MASK                      0x0007  /* ALCMIN - [2:0] */
+#define WM8985_ALCMIN_SHIFT                          0  /* ALCMIN - [2:0] */
+#define WM8985_ALCMIN_WIDTH                          3  /* ALCMIN - [2:0] */
+
+/*
+ * R33 (0x21) - ALC control 2
+ */
+#define WM8985_ALCHLD_MASK                      0x00F0  /* ALCHLD - [7:4] */
+#define WM8985_ALCHLD_SHIFT                          4  /* ALCHLD - [7:4] */
+#define WM8985_ALCHLD_WIDTH                          4  /* ALCHLD - [7:4] */
+#define WM8985_ALCLVL_MASK                      0x000F  /* ALCLVL - [3:0] */
+#define WM8985_ALCLVL_SHIFT                          0  /* ALCLVL - [3:0] */
+#define WM8985_ALCLVL_WIDTH                          4  /* ALCLVL - [3:0] */
+
+/*
+ * R34 (0x22) - ALC control 3
+ */
+#define WM8985_ALCMODE                          0x0100  /* ALCMODE */
+#define WM8985_ALCMODE_MASK                     0x0100  /* ALCMODE */
+#define WM8985_ALCMODE_SHIFT                         8  /* ALCMODE */
+#define WM8985_ALCMODE_WIDTH                         1  /* ALCMODE */
+#define WM8985_ALCDCY_MASK                      0x00F0  /* ALCDCY - [7:4] */
+#define WM8985_ALCDCY_SHIFT                          4  /* ALCDCY - [7:4] */
+#define WM8985_ALCDCY_WIDTH                          4  /* ALCDCY - [7:4] */
+#define WM8985_ALCATK_MASK                      0x000F  /* ALCATK - [3:0] */
+#define WM8985_ALCATK_SHIFT                          0  /* ALCATK - [3:0] */
+#define WM8985_ALCATK_WIDTH                          4  /* ALCATK - [3:0] */
+
+/*
+ * R35 (0x23) - Noise Gate
+ */
+#define WM8985_NGEN                             0x0008  /* NGEN */
+#define WM8985_NGEN_MASK                        0x0008  /* NGEN */
+#define WM8985_NGEN_SHIFT                            3  /* NGEN */
+#define WM8985_NGEN_WIDTH                            1  /* NGEN */
+#define WM8985_NGTH_MASK                        0x0007  /* NGTH - [2:0] */
+#define WM8985_NGTH_SHIFT                            0  /* NGTH - [2:0] */
+#define WM8985_NGTH_WIDTH                            3  /* NGTH - [2:0] */
+
+/*
+ * R36 (0x24) - PLL N
+ */
+#define WM8985_PLL_PRESCALE                     0x0010  /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_MASK                0x0010  /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_SHIFT                    4  /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_WIDTH                    1  /* PLL_PRESCALE */
+#define WM8985_PLLN_MASK                        0x000F  /* PLLN - [3:0] */
+#define WM8985_PLLN_SHIFT                            0  /* PLLN - [3:0] */
+#define WM8985_PLLN_WIDTH                            4  /* PLLN - [3:0] */
+
+/*
+ * R37 (0x25) - PLL K 1
+ */
+#define WM8985_PLLK_23_18_MASK                  0x003F  /* PLLK(23:18) - [5:0] */
+#define WM8985_PLLK_23_18_SHIFT                      0  /* PLLK(23:18) - [5:0] */
+#define WM8985_PLLK_23_18_WIDTH                      6  /* PLLK(23:18) - [5:0] */
+
+/*
+ * R38 (0x26) - PLL K 2
+ */
+#define WM8985_PLLK_17_9_MASK                   0x01FF  /* PLLK(17:9) - [8:0] */
+#define WM8985_PLLK_17_9_SHIFT                       0  /* PLLK(17:9) - [8:0] */
+#define WM8985_PLLK_17_9_WIDTH                       9  /* PLLK(17:9) - [8:0] */
+
+/*
+ * R39 (0x27) - PLL K 3
+ */
+#define WM8985_PLLK_8_0_MASK                    0x01FF  /* PLLK(8:0) - [8:0] */
+#define WM8985_PLLK_8_0_SHIFT                        0  /* PLLK(8:0) - [8:0] */
+#define WM8985_PLLK_8_0_WIDTH                        9  /* PLLK(8:0) - [8:0] */
+
+/*
+ * R41 (0x29) - 3D control
+ */
+#define WM8985_DEPTH3D_MASK                     0x000F  /* DEPTH3D - [3:0] */
+#define WM8985_DEPTH3D_SHIFT                         0  /* DEPTH3D - [3:0] */
+#define WM8985_DEPTH3D_WIDTH                         4  /* DEPTH3D - [3:0] */
+
+/*
+ * R42 (0x2A) - OUT4 to ADC
+ */
+#define WM8985_OUT4_2ADCVOL_MASK                0x01C0  /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2ADCVOL_SHIFT                    6  /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2ADCVOL_WIDTH                    3  /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2LNR                        0x0020  /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_MASK                   0x0020  /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_SHIFT                       5  /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_WIDTH                       1  /* OUT4_2LNR */
+#define WM8758_VMIDTOG_MASK                     0x0010  /* VMIDTOG */
+#define WM8758_VMIDTOG_SHIFT                         4  /* VMIDTOG */
+#define WM8758_VMIDTOG_WIDTH                         1  /* VMIDTOG */
+#define WM8758_OUT2DEL_MASK                     0x0008  /* OUT2DEL */
+#define WM8758_OUT2DEL_SHIFT                         3  /* OUT2DEL */
+#define WM8758_OUT2DEL_WIDTH                         1  /* OUT2DEL */
+#define WM8985_POBCTRL                          0x0004  /* POBCTRL */
+#define WM8985_POBCTRL_MASK                     0x0004  /* POBCTRL */
+#define WM8985_POBCTRL_SHIFT                         2  /* POBCTRL */
+#define WM8985_POBCTRL_WIDTH                         1  /* POBCTRL */
+#define WM8985_DELEN                            0x0002  /* DELEN */
+#define WM8985_DELEN_MASK                       0x0002  /* DELEN */
+#define WM8985_DELEN_SHIFT                           1  /* DELEN */
+#define WM8985_DELEN_WIDTH                           1  /* DELEN */
+#define WM8985_OUT1DEL                          0x0001  /* OUT1DEL */
+#define WM8985_OUT1DEL_MASK                     0x0001  /* OUT1DEL */
+#define WM8985_OUT1DEL_SHIFT                         0  /* OUT1DEL */
+#define WM8985_OUT1DEL_WIDTH                         1  /* OUT1DEL */
+
+/*
+ * R43 (0x2B) - Beep control
+ */
+#define WM8985_BYPL2RMIX                        0x0100  /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_MASK                   0x0100  /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_SHIFT                       8  /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_WIDTH                       1  /* BYPL2RMIX */
+#define WM8985_BYPR2LMIX                        0x0080  /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_MASK                   0x0080  /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_SHIFT                       7  /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_WIDTH                       1  /* BYPR2LMIX */
+#define WM8985_MUTERPGA2INV                     0x0020  /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_MASK                0x0020  /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_SHIFT                    5  /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_WIDTH                    1  /* MUTERPGA2INV */
+#define WM8985_INVROUT2                         0x0010  /* INVROUT2 */
+#define WM8985_INVROUT2_MASK                    0x0010  /* INVROUT2 */
+#define WM8985_INVROUT2_SHIFT                        4  /* INVROUT2 */
+#define WM8985_INVROUT2_WIDTH                        1  /* INVROUT2 */
+#define WM8985_BEEPVOL_MASK                     0x000E  /* BEEPVOL - [3:1] */
+#define WM8985_BEEPVOL_SHIFT                         1  /* BEEPVOL - [3:1] */
+#define WM8985_BEEPVOL_WIDTH                         3  /* BEEPVOL - [3:1] */
+#define WM8758_DELEN2_MASK                      0x0004  /* DELEN2 */
+#define WM8758_DELEN2_SHIFT                          2  /* DELEN2 */
+#define WM8758_DELEN2_WIDTH                          1  /* DELEN2 */
+#define WM8985_BEEPEN                           0x0001  /* BEEPEN */
+#define WM8985_BEEPEN_MASK                      0x0001  /* BEEPEN */
+#define WM8985_BEEPEN_SHIFT                          0  /* BEEPEN */
+#define WM8985_BEEPEN_WIDTH                          1  /* BEEPEN */
+
+/*
+ * R44 (0x2C) - Input ctrl
+ */
+#define WM8985_MBVSEL                           0x0100  /* MBVSEL */
+#define WM8985_MBVSEL_MASK                      0x0100  /* MBVSEL */
+#define WM8985_MBVSEL_SHIFT                          8  /* MBVSEL */
+#define WM8985_MBVSEL_WIDTH                          1  /* MBVSEL */
+#define WM8985_R2_2INPPGA                       0x0040  /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_MASK                  0x0040  /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_SHIFT                      6  /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_WIDTH                      1  /* R2_2INPPGA */
+#define WM8985_RIN2INPPGA                       0x0020  /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_MASK                  0x0020  /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_SHIFT                      5  /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_WIDTH                      1  /* RIN2INPPGA */
+#define WM8985_RIP2INPPGA                       0x0010  /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_MASK                  0x0010  /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_SHIFT                      4  /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_WIDTH                      1  /* RIP2INPPGA */
+#define WM8985_L2_2INPPGA                       0x0004  /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_MASK                  0x0004  /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_SHIFT                      2  /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_WIDTH                      1  /* L2_2INPPGA */
+#define WM8985_LIN2INPPGA                       0x0002  /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_MASK                  0x0002  /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_SHIFT                      1  /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_WIDTH                      1  /* LIN2INPPGA */
+#define WM8985_LIP2INPPGA                       0x0001  /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_MASK                  0x0001  /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_SHIFT                      0  /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_WIDTH                      1  /* LIP2INPPGA */
+
+/*
+ * R45 (0x2D) - Left INP PGA gain ctrl
+ */
+#define WM8985_INPGAVU                          0x0100  /* INPGAVU */
+#define WM8985_INPGAVU_MASK                     0x0100  /* INPGAVU */
+#define WM8985_INPGAVU_SHIFT                         8  /* INPGAVU */
+#define WM8985_INPGAVU_WIDTH                         1  /* INPGAVU */
+#define WM8985_INPPGAZCL                        0x0080  /* INPPGAZCL */
+#define WM8985_INPPGAZCL_MASK                   0x0080  /* INPPGAZCL */
+#define WM8985_INPPGAZCL_SHIFT                       7  /* INPPGAZCL */
+#define WM8985_INPPGAZCL_WIDTH                       1  /* INPPGAZCL */
+#define WM8985_INPPGAMUTEL                      0x0040  /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_MASK                 0x0040  /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_SHIFT                     6  /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_WIDTH                     1  /* INPPGAMUTEL */
+#define WM8985_INPPGAVOLL_MASK                  0x003F  /* INPPGAVOLL - [5:0] */
+#define WM8985_INPPGAVOLL_SHIFT                      0  /* INPPGAVOLL - [5:0] */
+#define WM8985_INPPGAVOLL_WIDTH                      6  /* INPPGAVOLL - [5:0] */
+
+/*
+ * R46 (0x2E) - Right INP PGA gain ctrl
+ */
+#define WM8985_INPGAVU                          0x0100  /* INPGAVU */
+#define WM8985_INPGAVU_MASK                     0x0100  /* INPGAVU */
+#define WM8985_INPGAVU_SHIFT                         8  /* INPGAVU */
+#define WM8985_INPGAVU_WIDTH                         1  /* INPGAVU */
+#define WM8985_INPPGAZCR                        0x0080  /* INPPGAZCR */
+#define WM8985_INPPGAZCR_MASK                   0x0080  /* INPPGAZCR */
+#define WM8985_INPPGAZCR_SHIFT                       7  /* INPPGAZCR */
+#define WM8985_INPPGAZCR_WIDTH                       1  /* INPPGAZCR */
+#define WM8985_INPPGAMUTER                      0x0040  /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_MASK                 0x0040  /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_SHIFT                     6  /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_WIDTH                     1  /* INPPGAMUTER */
+#define WM8985_INPPGAVOLR_MASK                  0x003F  /* INPPGAVOLR - [5:0] */
+#define WM8985_INPPGAVOLR_SHIFT                      0  /* INPPGAVOLR - [5:0] */
+#define WM8985_INPPGAVOLR_WIDTH                      6  /* INPPGAVOLR - [5:0] */
+
+/*
+ * R47 (0x2F) - Left ADC BOOST ctrl
+ */
+#define WM8985_PGABOOSTL                        0x0100  /* PGABOOSTL */
+#define WM8985_PGABOOSTL_MASK                   0x0100  /* PGABOOSTL */
+#define WM8985_PGABOOSTL_SHIFT                       8  /* PGABOOSTL */
+#define WM8985_PGABOOSTL_WIDTH                       1  /* PGABOOSTL */
+#define WM8985_L2_2BOOSTVOL_MASK                0x0070  /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_L2_2BOOSTVOL_SHIFT                    4  /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_L2_2BOOSTVOL_WIDTH                    3  /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_AUXL2BOOSTVOL_MASK               0x0007  /* AUXL2BOOSTVOL - [2:0] */
+#define WM8985_AUXL2BOOSTVOL_SHIFT                   0  /* AUXL2BOOSTVOL - [2:0] */
+#define WM8985_AUXL2BOOSTVOL_WIDTH                   3  /* AUXL2BOOSTVOL - [2:0] */
+
+/*
+ * R48 (0x30) - Right ADC BOOST ctrl
+ */
+#define WM8985_PGABOOSTR                        0x0100  /* PGABOOSTR */
+#define WM8985_PGABOOSTR_MASK                   0x0100  /* PGABOOSTR */
+#define WM8985_PGABOOSTR_SHIFT                       8  /* PGABOOSTR */
+#define WM8985_PGABOOSTR_WIDTH                       1  /* PGABOOSTR */
+#define WM8985_R2_2BOOSTVOL_MASK                0x0070  /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_R2_2BOOSTVOL_SHIFT                    4  /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_R2_2BOOSTVOL_WIDTH                    3  /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_AUXR2BOOSTVOL_MASK               0x0007  /* AUXR2BOOSTVOL - [2:0] */
+#define WM8985_AUXR2BOOSTVOL_SHIFT                   0  /* AUXR2BOOSTVOL - [2:0] */
+#define WM8985_AUXR2BOOSTVOL_WIDTH                   3  /* AUXR2BOOSTVOL - [2:0] */
+
+/*
+ * R49 (0x31) - Output ctrl
+ */
+#define WM8758_HP_COM                           0x0100  /* HP_COM */
+#define WM8758_HP_COM_MASK                      0x0100  /* HP_COM */
+#define WM8758_HP_COM_SHIFT                          8  /* HP_COM */
+#define WM8758_HP_COM_WIDTH                          1  /* HP_COM */
+#define WM8758_LINE_COM                         0x0080  /* LINE_COM */
+#define WM8758_LINE_COM_MASK                    0x0080  /* LINE_COM */
+#define WM8758_LINE_COM_SHIFT                        7  /* LINE_COM */
+#define WM8758_LINE_COM_WIDTH                        1  /* LINE_COM */
+#define WM8985_DACL2RMIX                        0x0040  /* DACL2RMIX */
+#define WM8985_DACL2RMIX_MASK                   0x0040  /* DACL2RMIX */
+#define WM8985_DACL2RMIX_SHIFT                       6  /* DACL2RMIX */
+#define WM8985_DACL2RMIX_WIDTH                       1  /* DACL2RMIX */
+#define WM8985_DACR2LMIX                        0x0020  /* DACR2LMIX */
+#define WM8985_DACR2LMIX_MASK                   0x0020  /* DACR2LMIX */
+#define WM8985_DACR2LMIX_SHIFT                       5  /* DACR2LMIX */
+#define WM8985_DACR2LMIX_WIDTH                       1  /* DACR2LMIX */
+#define WM8985_OUT4BOOST                        0x0010  /* OUT4BOOST */
+#define WM8985_OUT4BOOST_MASK                   0x0010  /* OUT4BOOST */
+#define WM8985_OUT4BOOST_SHIFT                       4  /* OUT4BOOST */
+#define WM8985_OUT4BOOST_WIDTH                       1  /* OUT4BOOST */
+#define WM8985_OUT3BOOST                        0x0008  /* OUT3BOOST */
+#define WM8985_OUT3BOOST_MASK                   0x0008  /* OUT3BOOST */
+#define WM8985_OUT3BOOST_SHIFT                       3  /* OUT3BOOST */
+#define WM8985_OUT3BOOST_WIDTH                       1  /* OUT3BOOST */
+#define WM8758_OUT4ENDEL                        0x0010  /* OUT4ENDEL */
+#define WM8758_OUT4ENDEL_MASK                   0x0010  /* OUT4ENDEL */
+#define WM8758_OUT4ENDEL_SHIFT                       4  /* OUT4ENDEL */
+#define WM8758_OUT4ENDEL_WIDTH                       1  /* OUT4ENDEL */
+#define WM8758_OUT3ENDEL                        0x0008  /* OUT3ENDEL */
+#define WM8758_OUT3ENDEL_MASK                   0x0008  /* OUT3ENDEL */
+#define WM8758_OUT3ENDEL_SHIFT                       3  /* OUT3ENDEL */
+#define WM8758_OUT3ENDEL_WIDTH                       1  /* OUT3ENDEL */
+#define WM8985_TSOPCTRL                         0x0004  /* TSOPCTRL */
+#define WM8985_TSOPCTRL_MASK                    0x0004  /* TSOPCTRL */
+#define WM8985_TSOPCTRL_SHIFT                        2  /* TSOPCTRL */
+#define WM8985_TSOPCTRL_WIDTH                        1  /* TSOPCTRL */
+#define WM8985_TSDEN                            0x0002  /* TSDEN */
+#define WM8985_TSDEN_MASK                       0x0002  /* TSDEN */
+#define WM8985_TSDEN_SHIFT                           1  /* TSDEN */
+#define WM8985_TSDEN_WIDTH                           1  /* TSDEN */
+#define WM8985_VROI                             0x0001  /* VROI */
+#define WM8985_VROI_MASK                        0x0001  /* VROI */
+#define WM8985_VROI_SHIFT                            0  /* VROI */
+#define WM8985_VROI_WIDTH                            1  /* VROI */
+
+/*
+ * R50 (0x32) - Left mixer ctrl
+ */
+#define WM8985_AUXLMIXVOL_MASK                  0x01C0  /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXLMIXVOL_SHIFT                      6  /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXLMIXVOL_WIDTH                      3  /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXL2LMIX                        0x0020  /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_MASK                   0x0020  /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_SHIFT                       5  /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_WIDTH                       1  /* AUXL2LMIX */
+#define WM8985_BYPLMIXVOL_MASK                  0x001C  /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPLMIXVOL_SHIFT                      2  /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPLMIXVOL_WIDTH                      3  /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPL2LMIX                        0x0002  /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_MASK                   0x0002  /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_SHIFT                       1  /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_WIDTH                       1  /* BYPL2LMIX */
+#define WM8985_DACL2LMIX                        0x0001  /* DACL2LMIX */
+#define WM8985_DACL2LMIX_MASK                   0x0001  /* DACL2LMIX */
+#define WM8985_DACL2LMIX_SHIFT                       0  /* DACL2LMIX */
+#define WM8985_DACL2LMIX_WIDTH                       1  /* DACL2LMIX */
+
+/*
+ * R51 (0x33) - Right mixer ctrl
+ */
+#define WM8985_AUXRMIXVOL_MASK                  0x01C0  /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXRMIXVOL_SHIFT                      6  /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXRMIXVOL_WIDTH                      3  /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXR2RMIX                        0x0020  /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_MASK                   0x0020  /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_SHIFT                       5  /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_WIDTH                       1  /* AUXR2RMIX */
+#define WM8985_BYPRMIXVOL_MASK                  0x001C  /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPRMIXVOL_SHIFT                      2  /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPRMIXVOL_WIDTH                      3  /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPR2RMIX                        0x0002  /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_MASK                   0x0002  /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_SHIFT                       1  /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_WIDTH                       1  /* BYPR2RMIX */
+#define WM8985_DACR2RMIX                        0x0001  /* DACR2RMIX */
+#define WM8985_DACR2RMIX_MASK                   0x0001  /* DACR2RMIX */
+#define WM8985_DACR2RMIX_SHIFT                       0  /* DACR2RMIX */
+#define WM8985_DACR2RMIX_WIDTH                       1  /* DACR2RMIX */
+
+/*
+ * R52 (0x34) - LOUT1 (HP) volume ctrl
+ */
+#define WM8985_OUT1VU                           0x0100  /* OUT1VU */
+#define WM8985_OUT1VU_MASK                      0x0100  /* OUT1VU */
+#define WM8985_OUT1VU_SHIFT                          8  /* OUT1VU */
+#define WM8985_OUT1VU_WIDTH                          1  /* OUT1VU */
+#define WM8985_LOUT1ZC                          0x0080  /* LOUT1ZC */
+#define WM8985_LOUT1ZC_MASK                     0x0080  /* LOUT1ZC */
+#define WM8985_LOUT1ZC_SHIFT                         7  /* LOUT1ZC */
+#define WM8985_LOUT1ZC_WIDTH                         1  /* LOUT1ZC */
+#define WM8985_LOUT1MUTE                        0x0040  /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_MASK                   0x0040  /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_SHIFT                       6  /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_WIDTH                       1  /* LOUT1MUTE */
+#define WM8985_LOUT1VOL_MASK                    0x003F  /* LOUT1VOL - [5:0] */
+#define WM8985_LOUT1VOL_SHIFT                        0  /* LOUT1VOL - [5:0] */
+#define WM8985_LOUT1VOL_WIDTH                        6  /* LOUT1VOL - [5:0] */
+
+/*
+ * R53 (0x35) - ROUT1 (HP) volume ctrl
+ */
+#define WM8985_OUT1VU                           0x0100  /* OUT1VU */
+#define WM8985_OUT1VU_MASK                      0x0100  /* OUT1VU */
+#define WM8985_OUT1VU_SHIFT                          8  /* OUT1VU */
+#define WM8985_OUT1VU_WIDTH                          1  /* OUT1VU */
+#define WM8985_ROUT1ZC                          0x0080  /* ROUT1ZC */
+#define WM8985_ROUT1ZC_MASK                     0x0080  /* ROUT1ZC */
+#define WM8985_ROUT1ZC_SHIFT                         7  /* ROUT1ZC */
+#define WM8985_ROUT1ZC_WIDTH                         1  /* ROUT1ZC */
+#define WM8985_ROUT1MUTE                        0x0040  /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_MASK                   0x0040  /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_SHIFT                       6  /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_WIDTH                       1  /* ROUT1MUTE */
+#define WM8985_ROUT1VOL_MASK                    0x003F  /* ROUT1VOL - [5:0] */
+#define WM8985_ROUT1VOL_SHIFT                        0  /* ROUT1VOL - [5:0] */
+#define WM8985_ROUT1VOL_WIDTH                        6  /* ROUT1VOL - [5:0] */
+
+/*
+ * R54 (0x36) - LOUT2 (SPK) volume ctrl
+ */
+#define WM8985_OUT2VU                           0x0100  /* OUT2VU */
+#define WM8985_OUT2VU_MASK                      0x0100  /* OUT2VU */
+#define WM8985_OUT2VU_SHIFT                          8  /* OUT2VU */
+#define WM8985_OUT2VU_WIDTH                          1  /* OUT2VU */
+#define WM8985_LOUT2ZC                          0x0080  /* LOUT2ZC */
+#define WM8985_LOUT2ZC_MASK                     0x0080  /* LOUT2ZC */
+#define WM8985_LOUT2ZC_SHIFT                         7  /* LOUT2ZC */
+#define WM8985_LOUT2ZC_WIDTH                         1  /* LOUT2ZC */
+#define WM8985_LOUT2MUTE                        0x0040  /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_MASK                   0x0040  /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_SHIFT                       6  /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_WIDTH                       1  /* LOUT2MUTE */
+#define WM8985_LOUT2VOL_MASK                    0x003F  /* LOUT2VOL - [5:0] */
+#define WM8985_LOUT2VOL_SHIFT                        0  /* LOUT2VOL - [5:0] */
+#define WM8985_LOUT2VOL_WIDTH                        6  /* LOUT2VOL - [5:0] */
+
+/*
+ * R55 (0x37) - ROUT2 (SPK) volume ctrl
+ */
+#define WM8985_OUT2VU                           0x0100  /* OUT2VU */
+#define WM8985_OUT2VU_MASK                      0x0100  /* OUT2VU */
+#define WM8985_OUT2VU_SHIFT                          8  /* OUT2VU */
+#define WM8985_OUT2VU_WIDTH                          1  /* OUT2VU */
+#define WM8985_ROUT2ZC                          0x0080  /* ROUT2ZC */
+#define WM8985_ROUT2ZC_MASK                     0x0080  /* ROUT2ZC */
+#define WM8985_ROUT2ZC_SHIFT                         7  /* ROUT2ZC */
+#define WM8985_ROUT2ZC_WIDTH                         1  /* ROUT2ZC */
+#define WM8985_ROUT2MUTE                        0x0040  /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_MASK                   0x0040  /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_SHIFT                       6  /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_WIDTH                       1  /* ROUT2MUTE */
+#define WM8985_ROUT2VOL_MASK                    0x003F  /* ROUT2VOL - [5:0] */
+#define WM8985_ROUT2VOL_SHIFT                        0  /* ROUT2VOL - [5:0] */
+#define WM8985_ROUT2VOL_WIDTH                        6  /* ROUT2VOL - [5:0] */
+
+/*
+ * R56 (0x38) - OUT3 mixer ctrl
+ */
+#define WM8985_OUT3MUTE                         0x0040  /* OUT3MUTE */
+#define WM8985_OUT3MUTE_MASK                    0x0040  /* OUT3MUTE */
+#define WM8985_OUT3MUTE_SHIFT                        6  /* OUT3MUTE */
+#define WM8985_OUT3MUTE_WIDTH                        1  /* OUT3MUTE */
+#define WM8985_OUT4_2OUT3                       0x0008  /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_MASK                  0x0008  /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_SHIFT                      3  /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_WIDTH                      1  /* OUT4_2OUT3 */
+#define WM8985_BYPL2OUT3                        0x0004  /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_MASK                   0x0004  /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_SHIFT                       2  /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_WIDTH                       1  /* BYPL2OUT3 */
+#define WM8985_LMIX2OUT3                        0x0002  /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_MASK                   0x0002  /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_SHIFT                       1  /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_WIDTH                       1  /* LMIX2OUT3 */
+#define WM8985_LDAC2OUT3                        0x0001  /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_MASK                   0x0001  /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_SHIFT                       0  /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_WIDTH                       1  /* LDAC2OUT3 */
+
+/*
+ * R57 (0x39) - OUT4 (MONO) mix ctrl
+ */
+#define WM8985_OUT3_2OUT4                       0x0080  /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_MASK                  0x0080  /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_SHIFT                      7  /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_WIDTH                      1  /* OUT3_2OUT4 */
+#define WM8985_OUT4MUTE                         0x0040  /* OUT4MUTE */
+#define WM8985_OUT4MUTE_MASK                    0x0040  /* OUT4MUTE */
+#define WM8985_OUT4MUTE_SHIFT                        6  /* OUT4MUTE */
+#define WM8985_OUT4MUTE_WIDTH                        1  /* OUT4MUTE */
+#define WM8985_OUT4ATTN                         0x0020  /* OUT4ATTN */
+#define WM8985_OUT4ATTN_MASK                    0x0020  /* OUT4ATTN */
+#define WM8985_OUT4ATTN_SHIFT                        5  /* OUT4ATTN */
+#define WM8985_OUT4ATTN_WIDTH                        1  /* OUT4ATTN */
+#define WM8985_LMIX2OUT4                        0x0010  /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_MASK                   0x0010  /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_SHIFT                       4  /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_WIDTH                       1  /* LMIX2OUT4 */
+#define WM8985_LDAC2OUT4                        0x0008  /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_MASK                   0x0008  /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_SHIFT                       3  /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_WIDTH                       1  /* LDAC2OUT4 */
+#define WM8985_BYPR2OUT4                        0x0004  /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_MASK                   0x0004  /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_SHIFT                       2  /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_WIDTH                       1  /* BYPR2OUT4 */
+#define WM8985_RMIX2OUT4                        0x0002  /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_MASK                   0x0002  /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_SHIFT                       1  /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_WIDTH                       1  /* RMIX2OUT4 */
+#define WM8985_RDAC2OUT4                        0x0001  /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_MASK                   0x0001  /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_SHIFT                       0  /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_WIDTH                       1  /* RDAC2OUT4 */
+
+/*
+ * R60 (0x3C) - OUTPUT ctrl
+ */
+#define WM8985_VIDBUFFTST_MASK                  0x01E0  /* VIDBUFFTST - [8:5] */
+#define WM8985_VIDBUFFTST_SHIFT                      5  /* VIDBUFFTST - [8:5] */
+#define WM8985_VIDBUFFTST_WIDTH                      4  /* VIDBUFFTST - [8:5] */
+#define WM8985_HPTOG                            0x0008  /* HPTOG */
+#define WM8985_HPTOG_MASK                       0x0008  /* HPTOG */
+#define WM8985_HPTOG_SHIFT                           3  /* HPTOG */
+#define WM8985_HPTOG_WIDTH                           1  /* HPTOG */
+
+/*
+ * R61 (0x3D) - BIAS CTRL
+ */
+#define WM8985_BIASCUT                          0x0100  /* BIASCUT */
+#define WM8985_BIASCUT_MASK                     0x0100  /* BIASCUT */
+#define WM8985_BIASCUT_SHIFT                         8  /* BIASCUT */
+#define WM8985_BIASCUT_WIDTH                         1  /* BIASCUT */
+#define WM8985_HALFIPBIAS                       0x0080  /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_MASK                  0x0080  /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_SHIFT                      7  /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_WIDTH                      1  /* HALFIPBIAS */
+#define WM8758_HALFIPBIAS                       0x0040  /* HALFI_IPGA */
+#define WM8758_HALFI_IPGA_MASK                  0x0040  /* HALFI_IPGA */
+#define WM8758_HALFI_IPGA_SHIFT                      6  /* HALFI_IPGA */
+#define WM8758_HALFI_IPGA_WIDTH                      1  /* HALFI_IPGA */
+#define WM8985_VBBIASTST_MASK                   0x0060  /* VBBIASTST - [6:5] */
+#define WM8985_VBBIASTST_SHIFT                       5  /* VBBIASTST - [6:5] */
+#define WM8985_VBBIASTST_WIDTH                       2  /* VBBIASTST - [6:5] */
+#define WM8985_BUFBIAS_MASK                     0x0018  /* BUFBIAS - [4:3] */
+#define WM8985_BUFBIAS_SHIFT                         3  /* BUFBIAS - [4:3] */
+#define WM8985_BUFBIAS_WIDTH                         2  /* BUFBIAS - [4:3] */
+#define WM8985_ADCBIAS_MASK                     0x0006  /* ADCBIAS - [2:1] */
+#define WM8985_ADCBIAS_SHIFT                         1  /* ADCBIAS - [2:1] */
+#define WM8985_ADCBIAS_WIDTH                         2  /* ADCBIAS - [2:1] */
+#define WM8985_HALFOPBIAS                       0x0001  /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_MASK                  0x0001  /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_SHIFT                      0  /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_WIDTH                      1  /* HALFOPBIAS */
+
+enum clk_src {
+	WM8985_CLKSRC_MCLK,
+	WM8985_CLKSRC_PLL
+};
+
+#define WM8985_PLL 0
+
+#endif
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
new file mode 100644
index 0000000..6e52c6a
--- /dev/null
+++ b/sound/soc/codecs/wm8988.c
@@ -0,0 +1,952 @@
+/*
+ * wm8988.c -- WM8988 ALSA SoC audio driver
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include "wm8988.h"
+
+/*
+ * wm8988 register cache
+ * We can't read the WM8988 register space when we
+ * are using 2 wire for device control, so we cache them instead.
+ */
+static const struct reg_default wm8988_reg_defaults[] = {
+	{ 0, 0x0097 },
+	{ 1, 0x0097 },
+	{ 2, 0x0079 },
+	{ 3, 0x0079 },
+	{ 5, 0x0008 },
+	{ 7, 0x000a },
+	{ 8, 0x0000 },
+	{ 10, 0x00ff },
+	{ 11, 0x00ff },
+	{ 12, 0x000f },
+	{ 13, 0x000f },
+	{ 16, 0x0000 },
+	{ 17, 0x007b },
+	{ 18, 0x0000 },
+	{ 19, 0x0032 },
+	{ 20, 0x0000 },
+	{ 21, 0x00c3 },
+	{ 22, 0x00c3 },
+	{ 23, 0x00c0 },
+	{ 24, 0x0000 },
+	{ 25, 0x0000 },
+	{ 26, 0x0000 },
+	{ 27, 0x0000 },
+	{ 31, 0x0000 },
+	{ 32, 0x0000 },
+	{ 33, 0x0000 },
+	{ 34, 0x0050 },
+	{ 35, 0x0050 },
+	{ 36, 0x0050 },
+	{ 37, 0x0050 },
+	{ 40, 0x0079 },
+	{ 41, 0x0079 },
+	{ 42, 0x0079 },
+};
+
+static bool wm8988_writeable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8988_LINVOL:
+	case WM8988_RINVOL:
+	case WM8988_LOUT1V:
+	case WM8988_ROUT1V:
+	case WM8988_ADCDAC:
+	case WM8988_IFACE:
+	case WM8988_SRATE:
+	case WM8988_LDAC:
+	case WM8988_RDAC:
+	case WM8988_BASS:
+	case WM8988_TREBLE:
+	case WM8988_RESET:
+	case WM8988_3D:
+	case WM8988_ALC1:
+	case WM8988_ALC2:
+	case WM8988_ALC3:
+	case WM8988_NGATE:
+	case WM8988_LADC:
+	case WM8988_RADC:
+	case WM8988_ADCTL1:
+	case WM8988_ADCTL2:
+	case WM8988_PWR1:
+	case WM8988_PWR2:
+	case WM8988_ADCTL3:
+	case WM8988_ADCIN:
+	case WM8988_LADCIN:
+	case WM8988_RADCIN:
+	case WM8988_LOUTM1:
+	case WM8988_LOUTM2:
+	case WM8988_ROUTM1:
+	case WM8988_ROUTM2:
+	case WM8988_LOUT2V:
+	case WM8988_ROUT2V:
+	case WM8988_LPPB:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/* codec private data */
+struct wm8988_priv {
+	struct regmap *regmap;
+	unsigned int sysclk;
+	const struct snd_pcm_hw_constraint_list *sysclk_constraints;
+};
+
+#define wm8988_reset(c)	snd_soc_component_write(c, WM8988_RESET, 0)
+
+/*
+ * WM8988 Controls
+ */
+
+static const char *bass_boost_txt[] = {"Linear Control", "Adaptive Boost"};
+static SOC_ENUM_SINGLE_DECL(bass_boost,
+			    WM8988_BASS, 7, bass_boost_txt);
+
+static const char *bass_filter_txt[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };
+static SOC_ENUM_SINGLE_DECL(bass_filter,
+			    WM8988_BASS, 6, bass_filter_txt);
+
+static const char *treble_txt[] = {"8kHz", "4kHz"};
+static SOC_ENUM_SINGLE_DECL(treble,
+			    WM8988_TREBLE, 6, treble_txt);
+
+static const char *stereo_3d_lc_txt[] = {"200Hz", "500Hz"};
+static SOC_ENUM_SINGLE_DECL(stereo_3d_lc,
+			    WM8988_3D, 5, stereo_3d_lc_txt);
+
+static const char *stereo_3d_uc_txt[] = {"2.2kHz", "1.5kHz"};
+static SOC_ENUM_SINGLE_DECL(stereo_3d_uc,
+			    WM8988_3D, 6, stereo_3d_uc_txt);
+
+static const char *stereo_3d_func_txt[] = {"Capture", "Playback"};
+static SOC_ENUM_SINGLE_DECL(stereo_3d_func,
+			    WM8988_3D, 7, stereo_3d_func_txt);
+
+static const char *alc_func_txt[] = {"Off", "Right", "Left", "Stereo"};
+static SOC_ENUM_SINGLE_DECL(alc_func,
+			    WM8988_ALC1, 7, alc_func_txt);
+
+static const char *ng_type_txt[] = {"Constant PGA Gain",
+				    "Mute ADC Output"};
+static SOC_ENUM_SINGLE_DECL(ng_type,
+			    WM8988_NGATE, 1, ng_type_txt);
+
+static const char *deemph_txt[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+static SOC_ENUM_SINGLE_DECL(deemph,
+			    WM8988_ADCDAC, 1, deemph_txt);
+
+static const char *adcpol_txt[] = {"Normal", "L Invert", "R Invert",
+				   "L + R Invert"};
+static SOC_ENUM_SINGLE_DECL(adcpol,
+			    WM8988_ADCDAC, 5, adcpol_txt);
+
+static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+
+static const struct snd_kcontrol_new wm8988_snd_controls[] = {
+
+SOC_ENUM("Bass Boost", bass_boost),
+SOC_ENUM("Bass Filter", bass_filter),
+SOC_SINGLE("Bass Volume", WM8988_BASS, 0, 15, 1),
+
+SOC_SINGLE("Treble Volume", WM8988_TREBLE, 0, 15, 0),
+SOC_ENUM("Treble Cut-off", treble),
+
+SOC_SINGLE("3D Switch", WM8988_3D, 0, 1, 0),
+SOC_SINGLE("3D Volume", WM8988_3D, 1, 15, 0),
+SOC_ENUM("3D Lower Cut-off", stereo_3d_lc),
+SOC_ENUM("3D Upper Cut-off", stereo_3d_uc),
+SOC_ENUM("3D Mode", stereo_3d_func),
+
+SOC_SINGLE("ALC Capture Target Volume", WM8988_ALC1, 0, 7, 0),
+SOC_SINGLE("ALC Capture Max Volume", WM8988_ALC1, 4, 7, 0),
+SOC_ENUM("ALC Capture Function", alc_func),
+SOC_SINGLE("ALC Capture ZC Switch", WM8988_ALC2, 7, 1, 0),
+SOC_SINGLE("ALC Capture Hold Time", WM8988_ALC2, 0, 15, 0),
+SOC_SINGLE("ALC Capture Decay Time", WM8988_ALC3, 4, 15, 0),
+SOC_SINGLE("ALC Capture Attack Time", WM8988_ALC3, 0, 15, 0),
+SOC_SINGLE("ALC Capture NG Threshold", WM8988_NGATE, 3, 31, 0),
+SOC_ENUM("ALC Capture NG Type", ng_type),
+SOC_SINGLE("ALC Capture NG Switch", WM8988_NGATE, 0, 1, 0),
+
+SOC_SINGLE("ZC Timeout Switch", WM8988_ADCTL1, 0, 1, 0),
+
+SOC_DOUBLE_R_TLV("Capture Digital Volume", WM8988_LADC, WM8988_RADC,
+		 0, 255, 0, adc_tlv),
+SOC_DOUBLE_R_TLV("Capture Volume", WM8988_LINVOL, WM8988_RINVOL,
+		 0, 63, 0, pga_tlv),
+SOC_DOUBLE_R("Capture ZC Switch", WM8988_LINVOL, WM8988_RINVOL, 6, 1, 0),
+SOC_DOUBLE_R("Capture Switch", WM8988_LINVOL, WM8988_RINVOL, 7, 1, 1),
+
+SOC_ENUM("Playback De-emphasis", deemph),
+
+SOC_ENUM("Capture Polarity", adcpol),
+SOC_SINGLE("Playback 6dB Attenuate", WM8988_ADCDAC, 7, 1, 0),
+SOC_SINGLE("Capture 6dB Attenuate", WM8988_ADCDAC, 8, 1, 0),
+
+SOC_DOUBLE_R_TLV("PCM Volume", WM8988_LDAC, WM8988_RDAC, 0, 255, 0, dac_tlv),
+
+SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", WM8988_LOUTM1, 4, 7, 1,
+	       bypass_tlv),
+SOC_SINGLE_TLV("Left Mixer Right Bypass Volume", WM8988_LOUTM2, 4, 7, 1,
+	       bypass_tlv),
+SOC_SINGLE_TLV("Right Mixer Left Bypass Volume", WM8988_ROUTM1, 4, 7, 1,
+	       bypass_tlv),
+SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", WM8988_ROUTM2, 4, 7, 1,
+	       bypass_tlv),
+
+SOC_DOUBLE_R("Output 1 Playback ZC Switch", WM8988_LOUT1V,
+	     WM8988_ROUT1V, 7, 1, 0),
+SOC_DOUBLE_R_TLV("Output 1 Playback Volume", WM8988_LOUT1V, WM8988_ROUT1V,
+		 0, 127, 0, out_tlv),
+
+SOC_DOUBLE_R("Output 2 Playback ZC Switch", WM8988_LOUT2V,
+	     WM8988_ROUT2V, 7, 1, 0),
+SOC_DOUBLE_R_TLV("Output 2 Playback Volume", WM8988_LOUT2V, WM8988_ROUT2V,
+		 0, 127, 0, out_tlv),
+
+};
+
+/*
+ * DAPM Controls
+ */
+
+static int wm8988_lrc_control(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 adctl2 = snd_soc_component_read32(component, WM8988_ADCTL2);
+
+	/* Use the DAC to gate LRC if active, otherwise use ADC */
+	if (snd_soc_component_read32(component, WM8988_PWR2) & 0x180)
+		adctl2 &= ~0x4;
+	else
+		adctl2 |= 0x4;
+
+	return snd_soc_component_write(component, WM8988_ADCTL2, adctl2);
+}
+
+static const char *wm8988_line_texts[] = {
+	"Line 1", "Line 2", "PGA", "Differential"};
+
+static const unsigned int wm8988_line_values[] = {
+	0, 1, 3, 4};
+
+static const struct soc_enum wm8988_lline_enum =
+	SOC_VALUE_ENUM_SINGLE(WM8988_LOUTM1, 0, 7,
+			      ARRAY_SIZE(wm8988_line_texts),
+			      wm8988_line_texts,
+			      wm8988_line_values);
+static const struct snd_kcontrol_new wm8988_left_line_controls =
+	SOC_DAPM_ENUM("Route", wm8988_lline_enum);
+
+static const struct soc_enum wm8988_rline_enum =
+	SOC_VALUE_ENUM_SINGLE(WM8988_ROUTM1, 0, 7,
+			      ARRAY_SIZE(wm8988_line_texts),
+			      wm8988_line_texts,
+			      wm8988_line_values);
+static const struct snd_kcontrol_new wm8988_right_line_controls =
+	SOC_DAPM_ENUM("Route", wm8988_lline_enum);
+
+/* Left Mixer */
+static const struct snd_kcontrol_new wm8988_left_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Playback Switch", WM8988_LOUTM1, 8, 1, 0),
+	SOC_DAPM_SINGLE("Left Bypass Switch", WM8988_LOUTM1, 7, 1, 0),
+	SOC_DAPM_SINGLE("Right Playback Switch", WM8988_LOUTM2, 8, 1, 0),
+	SOC_DAPM_SINGLE("Right Bypass Switch", WM8988_LOUTM2, 7, 1, 0),
+};
+
+/* Right Mixer */
+static const struct snd_kcontrol_new wm8988_right_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left Playback Switch", WM8988_ROUTM1, 8, 1, 0),
+	SOC_DAPM_SINGLE("Left Bypass Switch", WM8988_ROUTM1, 7, 1, 0),
+	SOC_DAPM_SINGLE("Playback Switch", WM8988_ROUTM2, 8, 1, 0),
+	SOC_DAPM_SINGLE("Right Bypass Switch", WM8988_ROUTM2, 7, 1, 0),
+};
+
+static const char *wm8988_pga_sel[] = {"Line 1", "Line 2", "Differential"};
+static const unsigned int wm8988_pga_val[] = { 0, 1, 3 };
+
+/* Left PGA Mux */
+static const struct soc_enum wm8988_lpga_enum =
+	SOC_VALUE_ENUM_SINGLE(WM8988_LADCIN, 6, 3,
+			      ARRAY_SIZE(wm8988_pga_sel),
+			      wm8988_pga_sel,
+			      wm8988_pga_val);
+static const struct snd_kcontrol_new wm8988_left_pga_controls =
+	SOC_DAPM_ENUM("Route", wm8988_lpga_enum);
+
+/* Right PGA Mux */
+static const struct soc_enum wm8988_rpga_enum =
+	SOC_VALUE_ENUM_SINGLE(WM8988_RADCIN, 6, 3,
+			      ARRAY_SIZE(wm8988_pga_sel),
+			      wm8988_pga_sel,
+			      wm8988_pga_val);
+static const struct snd_kcontrol_new wm8988_right_pga_controls =
+	SOC_DAPM_ENUM("Route", wm8988_rpga_enum);
+
+/* Differential Mux */
+static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"};
+static SOC_ENUM_SINGLE_DECL(diffmux,
+			    WM8988_ADCIN, 8, wm8988_diff_sel);
+static const struct snd_kcontrol_new wm8988_diffmux_controls =
+	SOC_DAPM_ENUM("Route", diffmux);
+
+/* Mono ADC Mux */
+static const char *wm8988_mono_mux[] = {"Stereo", "Mono (Left)",
+	"Mono (Right)", "Digital Mono"};
+static SOC_ENUM_SINGLE_DECL(monomux,
+			    WM8988_ADCIN, 6, wm8988_mono_mux);
+static const struct snd_kcontrol_new wm8988_monomux_controls =
+	SOC_DAPM_ENUM("Route", monomux);
+
+static const struct snd_soc_dapm_widget wm8988_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("Mic Bias", WM8988_PWR1, 1, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
+		&wm8988_diffmux_controls),
+	SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
+		&wm8988_monomux_controls),
+	SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
+		&wm8988_monomux_controls),
+
+	SND_SOC_DAPM_MUX("Left PGA Mux", WM8988_PWR1, 5, 0,
+		&wm8988_left_pga_controls),
+	SND_SOC_DAPM_MUX("Right PGA Mux", WM8988_PWR1, 4, 0,
+		&wm8988_right_pga_controls),
+
+	SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
+		&wm8988_left_line_controls),
+	SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
+		&wm8988_right_line_controls),
+
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8988_PWR1, 2, 0),
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8988_PWR1, 3, 0),
+
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8988_PWR2, 7, 0),
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8988_PWR2, 8, 0),
+
+	SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+		&wm8988_left_mixer_controls[0],
+		ARRAY_SIZE(wm8988_left_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+		&wm8988_right_mixer_controls[0],
+		ARRAY_SIZE(wm8988_right_mixer_controls)),
+
+	SND_SOC_DAPM_PGA("Right Out 2", WM8988_PWR2, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 2", WM8988_PWR2, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Right Out 1", WM8988_PWR2, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Left Out 1", WM8988_PWR2, 6, 0, NULL, 0),
+
+	SND_SOC_DAPM_POST("LRC control", wm8988_lrc_control),
+
+	SND_SOC_DAPM_OUTPUT("LOUT1"),
+	SND_SOC_DAPM_OUTPUT("ROUT1"),
+	SND_SOC_DAPM_OUTPUT("LOUT2"),
+	SND_SOC_DAPM_OUTPUT("ROUT2"),
+	SND_SOC_DAPM_OUTPUT("VREF"),
+
+	SND_SOC_DAPM_INPUT("LINPUT1"),
+	SND_SOC_DAPM_INPUT("LINPUT2"),
+	SND_SOC_DAPM_INPUT("RINPUT1"),
+	SND_SOC_DAPM_INPUT("RINPUT2"),
+};
+
+static const struct snd_soc_dapm_route wm8988_dapm_routes[] = {
+
+	{ "Left Line Mux", "Line 1", "LINPUT1" },
+	{ "Left Line Mux", "Line 2", "LINPUT2" },
+	{ "Left Line Mux", "PGA", "Left PGA Mux" },
+	{ "Left Line Mux", "Differential", "Differential Mux" },
+
+	{ "Right Line Mux", "Line 1", "RINPUT1" },
+	{ "Right Line Mux", "Line 2", "RINPUT2" },
+	{ "Right Line Mux", "PGA", "Right PGA Mux" },
+	{ "Right Line Mux", "Differential", "Differential Mux" },
+
+	{ "Left PGA Mux", "Line 1", "LINPUT1" },
+	{ "Left PGA Mux", "Line 2", "LINPUT2" },
+	{ "Left PGA Mux", "Differential", "Differential Mux" },
+
+	{ "Right PGA Mux", "Line 1", "RINPUT1" },
+	{ "Right PGA Mux", "Line 2", "RINPUT2" },
+	{ "Right PGA Mux", "Differential", "Differential Mux" },
+
+	{ "Differential Mux", "Line 1", "LINPUT1" },
+	{ "Differential Mux", "Line 1", "RINPUT1" },
+	{ "Differential Mux", "Line 2", "LINPUT2" },
+	{ "Differential Mux", "Line 2", "RINPUT2" },
+
+	{ "Left ADC Mux", "Stereo", "Left PGA Mux" },
+	{ "Left ADC Mux", "Mono (Left)", "Left PGA Mux" },
+	{ "Left ADC Mux", "Digital Mono", "Left PGA Mux" },
+
+	{ "Right ADC Mux", "Stereo", "Right PGA Mux" },
+	{ "Right ADC Mux", "Mono (Right)", "Right PGA Mux" },
+	{ "Right ADC Mux", "Digital Mono", "Right PGA Mux" },
+
+	{ "Left ADC", NULL, "Left ADC Mux" },
+	{ "Right ADC", NULL, "Right ADC Mux" },
+
+	{ "Left Line Mux", "Line 1", "LINPUT1" },
+	{ "Left Line Mux", "Line 2", "LINPUT2" },
+	{ "Left Line Mux", "PGA", "Left PGA Mux" },
+	{ "Left Line Mux", "Differential", "Differential Mux" },
+
+	{ "Right Line Mux", "Line 1", "RINPUT1" },
+	{ "Right Line Mux", "Line 2", "RINPUT2" },
+	{ "Right Line Mux", "PGA", "Right PGA Mux" },
+	{ "Right Line Mux", "Differential", "Differential Mux" },
+
+	{ "Left Mixer", "Playback Switch", "Left DAC" },
+	{ "Left Mixer", "Left Bypass Switch", "Left Line Mux" },
+	{ "Left Mixer", "Right Playback Switch", "Right DAC" },
+	{ "Left Mixer", "Right Bypass Switch", "Right Line Mux" },
+
+	{ "Right Mixer", "Left Playback Switch", "Left DAC" },
+	{ "Right Mixer", "Left Bypass Switch", "Left Line Mux" },
+	{ "Right Mixer", "Playback Switch", "Right DAC" },
+	{ "Right Mixer", "Right Bypass Switch", "Right Line Mux" },
+
+	{ "Left Out 1", NULL, "Left Mixer" },
+	{ "LOUT1", NULL, "Left Out 1" },
+	{ "Right Out 1", NULL, "Right Mixer" },
+	{ "ROUT1", NULL, "Right Out 1" },
+
+	{ "Left Out 2", NULL, "Left Mixer" },
+	{ "LOUT2", NULL, "Left Out 2" },
+	{ "Right Out 2", NULL, "Right Mixer" },
+	{ "ROUT2", NULL, "Right Out 2" },
+};
+
+struct _coeff_div {
+	u32 mclk;
+	u32 rate;
+	u16 fs;
+	u8 sr:5;
+	u8 usb:1;
+};
+
+/* codec hifi mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+	/* 8k */
+	{12288000, 8000, 1536, 0x6, 0x0},
+	{11289600, 8000, 1408, 0x16, 0x0},
+	{18432000, 8000, 2304, 0x7, 0x0},
+	{16934400, 8000, 2112, 0x17, 0x0},
+	{12000000, 8000, 1500, 0x6, 0x1},
+
+	/* 11.025k */
+	{11289600, 11025, 1024, 0x18, 0x0},
+	{16934400, 11025, 1536, 0x19, 0x0},
+	{12000000, 11025, 1088, 0x19, 0x1},
+
+	/* 16k */
+	{12288000, 16000, 768, 0xa, 0x0},
+	{18432000, 16000, 1152, 0xb, 0x0},
+	{12000000, 16000, 750, 0xa, 0x1},
+
+	/* 22.05k */
+	{11289600, 22050, 512, 0x1a, 0x0},
+	{16934400, 22050, 768, 0x1b, 0x0},
+	{12000000, 22050, 544, 0x1b, 0x1},
+
+	/* 32k */
+	{12288000, 32000, 384, 0xc, 0x0},
+	{18432000, 32000, 576, 0xd, 0x0},
+	{12000000, 32000, 375, 0xa, 0x1},
+
+	/* 44.1k */
+	{11289600, 44100, 256, 0x10, 0x0},
+	{16934400, 44100, 384, 0x11, 0x0},
+	{12000000, 44100, 272, 0x11, 0x1},
+
+	/* 48k */
+	{12288000, 48000, 256, 0x0, 0x0},
+	{18432000, 48000, 384, 0x1, 0x0},
+	{12000000, 48000, 250, 0x0, 0x1},
+
+	/* 88.2k */
+	{11289600, 88200, 128, 0x1e, 0x0},
+	{16934400, 88200, 192, 0x1f, 0x0},
+	{12000000, 88200, 136, 0x1f, 0x1},
+
+	/* 96k */
+	{12288000, 96000, 128, 0xe, 0x0},
+	{18432000, 96000, 192, 0xf, 0x0},
+	{12000000, 96000, 125, 0xe, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+/* The set of rates we can generate from the above for each SYSCLK */
+
+static const unsigned int rates_12288[] = {
+	8000, 12000, 16000, 24000, 32000, 48000, 96000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_12288 = {
+	.count	= ARRAY_SIZE(rates_12288),
+	.list	= rates_12288,
+};
+
+static const unsigned int rates_112896[] = {
+	8000, 11025, 22050, 44100,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_112896 = {
+	.count	= ARRAY_SIZE(rates_112896),
+	.list	= rates_112896,
+};
+
+static const unsigned int rates_12[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 41100, 48000,
+	48000, 88235, 96000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_12 = {
+	.count	= ARRAY_SIZE(rates_12),
+	.list	= rates_12,
+};
+
+/*
+ * Note that this should be called from init rather than from hw_params.
+ */
+static int wm8988_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8988_priv *wm8988 = snd_soc_component_get_drvdata(component);
+
+	switch (freq) {
+	case 11289600:
+	case 18432000:
+	case 22579200:
+	case 36864000:
+		wm8988->sysclk_constraints = &constraints_112896;
+		wm8988->sysclk = freq;
+		return 0;
+
+	case 12288000:
+	case 16934400:
+	case 24576000:
+	case 33868800:
+		wm8988->sysclk_constraints = &constraints_12288;
+		wm8988->sysclk = freq;
+		return 0;
+
+	case 12000000:
+	case 24000000:
+		wm8988->sysclk_constraints = &constraints_12;
+		wm8988->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int wm8988_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 iface = 0;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface = 0x0040;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		iface |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		iface |= 0x0013;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		iface |= 0x0090;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		iface |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		iface |= 0x0010;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8988_IFACE, iface);
+	return 0;
+}
+
+static int wm8988_pcm_startup(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8988_priv *wm8988 = snd_soc_component_get_drvdata(component);
+
+	/* The set of sample rates that can be supported depends on the
+	 * MCLK supplied to the CODEC - enforce this.
+	 */
+	if (!wm8988->sysclk) {
+		dev_err(component->dev,
+			"No MCLK configured, call set_sysclk() on init\n");
+		return -EINVAL;
+	}
+
+	snd_pcm_hw_constraint_list(substream->runtime, 0,
+				   SNDRV_PCM_HW_PARAM_RATE,
+				   wm8988->sysclk_constraints);
+
+	return 0;
+}
+
+static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8988_priv *wm8988 = snd_soc_component_get_drvdata(component);
+	u16 iface = snd_soc_component_read32(component, WM8988_IFACE) & 0x1f3;
+	u16 srate = snd_soc_component_read32(component, WM8988_SRATE) & 0x180;
+	int coeff;
+
+	coeff = get_coeff(wm8988->sysclk, params_rate(params));
+	if (coeff < 0) {
+		coeff = get_coeff(wm8988->sysclk / 2, params_rate(params));
+		srate |= 0x40;
+	}
+	if (coeff < 0) {
+		dev_err(component->dev,
+			"Unable to configure sample rate %dHz with %dHz MCLK\n",
+			params_rate(params), wm8988->sysclk);
+		return coeff;
+	}
+
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		iface |= 0x0004;
+		break;
+	case 24:
+		iface |= 0x0008;
+		break;
+	case 32:
+		iface |= 0x000c;
+		break;
+	}
+
+	/* set iface & srate */
+	snd_soc_component_write(component, WM8988_IFACE, iface);
+	if (coeff >= 0)
+		snd_soc_component_write(component, WM8988_SRATE, srate |
+			(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
+
+	return 0;
+}
+
+static int wm8988_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 mute_reg = snd_soc_component_read32(component, WM8988_ADCDAC) & 0xfff7;
+
+	if (mute)
+		snd_soc_component_write(component, WM8988_ADCDAC, mute_reg | 0x8);
+	else
+		snd_soc_component_write(component, WM8988_ADCDAC, mute_reg);
+	return 0;
+}
+
+static int wm8988_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8988_priv *wm8988 = snd_soc_component_get_drvdata(component);
+	u16 pwr_reg = snd_soc_component_read32(component, WM8988_PWR1) & ~0x1c1;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* VREF, VMID=2x50k, digital enabled */
+		snd_soc_component_write(component, WM8988_PWR1, pwr_reg | 0x00c0);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			regcache_sync(wm8988->regmap);
+
+			/* VREF, VMID=2x5k */
+			snd_soc_component_write(component, WM8988_PWR1, pwr_reg | 0x1c1);
+
+			/* Charge caps */
+			msleep(100);
+		}
+
+		/* VREF, VMID=2*500k, digital stopped */
+		snd_soc_component_write(component, WM8988_PWR1, pwr_reg | 0x0141);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_write(component, WM8988_PWR1, 0x0000);
+		break;
+	}
+	return 0;
+}
+
+#define WM8988_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8988_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops wm8988_ops = {
+	.startup = wm8988_pcm_startup,
+	.hw_params = wm8988_pcm_hw_params,
+	.set_fmt = wm8988_set_dai_fmt,
+	.set_sysclk = wm8988_set_dai_sysclk,
+	.digital_mute = wm8988_mute,
+};
+
+static struct snd_soc_dai_driver wm8988_dai = {
+	.name = "wm8988-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8988_RATES,
+		.formats = WM8988_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8988_RATES,
+		.formats = WM8988_FORMATS,
+	 },
+	.ops = &wm8988_ops,
+	.symmetric_rates = 1,
+};
+
+static int wm8988_probe(struct snd_soc_component *component)
+{
+	int ret = 0;
+
+	ret = wm8988_reset(component);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	/* set the update bits (we always update left then right) */
+	snd_soc_component_update_bits(component, WM8988_RADC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8988_RDAC, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8988_ROUT1V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8988_ROUT2V, 0x0100, 0x0100);
+	snd_soc_component_update_bits(component, WM8988_RINVOL, 0x0100, 0x0100);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8988 = {
+	.probe			= wm8988_probe,
+	.set_bias_level		= wm8988_set_bias_level,
+	.controls		= wm8988_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8988_snd_controls),
+	.dapm_widgets		= wm8988_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8988_dapm_widgets),
+	.dapm_routes		= wm8988_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8988_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8988_regmap = {
+	.reg_bits = 7,
+	.val_bits = 9,
+
+	.max_register = WM8988_LPPB,
+	.writeable_reg = wm8988_writeable,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8988_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8988_reg_defaults),
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8988_spi_probe(struct spi_device *spi)
+{
+	struct wm8988_priv *wm8988;
+	int ret;
+
+	wm8988 = devm_kzalloc(&spi->dev, sizeof(struct wm8988_priv),
+			      GFP_KERNEL);
+	if (wm8988 == NULL)
+		return -ENOMEM;
+
+	wm8988->regmap = devm_regmap_init_spi(spi, &wm8988_regmap);
+	if (IS_ERR(wm8988->regmap)) {
+		ret = PTR_ERR(wm8988->regmap);
+		dev_err(&spi->dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
+	spi_set_drvdata(spi, wm8988);
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+			&soc_component_dev_wm8988, &wm8988_dai, 1);
+	return ret;
+}
+
+static struct spi_driver wm8988_spi_driver = {
+	.driver = {
+		.name	= "wm8988",
+	},
+	.probe		= wm8988_spi_probe,
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8988_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8988_priv *wm8988;
+	int ret;
+
+	wm8988 = devm_kzalloc(&i2c->dev, sizeof(struct wm8988_priv),
+			      GFP_KERNEL);
+	if (wm8988 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, wm8988);
+
+	wm8988->regmap = devm_regmap_init_i2c(i2c, &wm8988_regmap);
+	if (IS_ERR(wm8988->regmap)) {
+		ret = PTR_ERR(wm8988->regmap);
+		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8988, &wm8988_dai, 1);
+	return ret;
+}
+
+static const struct i2c_device_id wm8988_i2c_id[] = {
+	{ "wm8988", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id);
+
+static struct i2c_driver wm8988_i2c_driver = {
+	.driver = {
+		.name = "wm8988",
+	},
+	.probe =    wm8988_i2c_probe,
+	.id_table = wm8988_i2c_id,
+};
+#endif
+
+static int __init wm8988_modinit(void)
+{
+	int ret = 0;
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&wm8988_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8988 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8988_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8988 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return ret;
+}
+module_init(wm8988_modinit);
+
+static void __exit wm8988_exit(void)
+{
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&wm8988_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8988_spi_driver);
+#endif
+}
+module_exit(wm8988_exit);
+
+
+MODULE_DESCRIPTION("ASoC WM8988 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8988.h b/sound/soc/codecs/wm8988.h
new file mode 100644
index 0000000..5c04024
--- /dev/null
+++ b/sound/soc/codecs/wm8988.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on WM8753.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _WM8988_H
+#define _WM8988_H
+
+/* WM8988 register space */
+
+#define WM8988_LINVOL    0x00
+#define WM8988_RINVOL    0x01
+#define WM8988_LOUT1V    0x02
+#define WM8988_ROUT1V    0x03
+#define WM8988_ADCDAC    0x05
+#define WM8988_IFACE     0x07
+#define WM8988_SRATE     0x08
+#define WM8988_LDAC      0x0a
+#define WM8988_RDAC      0x0b
+#define WM8988_BASS      0x0c
+#define WM8988_TREBLE    0x0d
+#define WM8988_RESET     0x0f
+#define WM8988_3D        0x10
+#define WM8988_ALC1      0x11
+#define WM8988_ALC2      0x12
+#define WM8988_ALC3      0x13
+#define WM8988_NGATE     0x14
+#define WM8988_LADC      0x15
+#define WM8988_RADC      0x16
+#define WM8988_ADCTL1    0x17
+#define WM8988_ADCTL2    0x18
+#define WM8988_PWR1      0x19
+#define WM8988_PWR2      0x1a
+#define WM8988_ADCTL3    0x1b
+#define WM8988_ADCIN     0x1f
+#define WM8988_LADCIN    0x20
+#define WM8988_RADCIN    0x21
+#define WM8988_LOUTM1    0x22
+#define WM8988_LOUTM2    0x23
+#define WM8988_ROUTM1    0x24
+#define WM8988_ROUTM2    0x25
+#define WM8988_LOUT2V    0x28
+#define WM8988_ROUT2V    0x29
+#define WM8988_LPPB      0x43
+#define WM8988_NUM_REG   0x44
+
+#define WM8988_SYSCLK	0
+
+#endif
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
new file mode 100644
index 0000000..457bc43
--- /dev/null
+++ b/sound/soc/codecs/wm8990.c
@@ -0,0 +1,1361 @@
+/*
+ * wm8990.c  --  WM8990 ALSA Soc Audio driver
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+
+#include "wm8990.h"
+
+/* codec private data */
+struct wm8990_priv {
+	struct regmap *regmap;
+	unsigned int sysclk;
+	unsigned int pcmclk;
+};
+
+static bool wm8990_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8990_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct reg_default wm8990_reg_defaults[] = {
+	{  1, 0x0000 },     /* R1  - Power Management (1) */
+	{  2, 0x6000 },     /* R2  - Power Management (2) */
+	{  3, 0x0000 },     /* R3  - Power Management (3) */
+	{  4, 0x4050 },     /* R4  - Audio Interface (1) */
+	{  5, 0x4000 },     /* R5  - Audio Interface (2) */
+	{  6, 0x01C8 },     /* R6  - Clocking (1) */
+	{  7, 0x0000 },     /* R7  - Clocking (2) */
+	{  8, 0x0040 },     /* R8  - Audio Interface (3) */
+	{  9, 0x0040 },     /* R9  - Audio Interface (4) */
+	{ 10, 0x0004 },     /* R10 - DAC CTRL */
+	{ 11, 0x00C0 },     /* R11 - Left DAC Digital Volume */
+	{ 12, 0x00C0 },     /* R12 - Right DAC Digital Volume */
+	{ 13, 0x0000 },     /* R13 - Digital Side Tone */
+	{ 14, 0x0100 },     /* R14 - ADC CTRL */
+	{ 15, 0x00C0 },     /* R15 - Left ADC Digital Volume */
+	{ 16, 0x00C0 },     /* R16 - Right ADC Digital Volume */
+
+	{ 18, 0x0000 },     /* R18 - GPIO CTRL 1 */
+	{ 19, 0x1000 },     /* R19 - GPIO1 & GPIO2 */
+	{ 20, 0x1010 },     /* R20 - GPIO3 & GPIO4 */
+	{ 21, 0x1010 },     /* R21 - GPIO5 & GPIO6 */
+	{ 22, 0x8000 },     /* R22 - GPIOCTRL 2 */
+	{ 23, 0x0800 },     /* R23 - GPIO_POL */
+	{ 24, 0x008B },     /* R24 - Left Line Input 1&2 Volume */
+	{ 25, 0x008B },     /* R25 - Left Line Input 3&4 Volume */
+	{ 26, 0x008B },     /* R26 - Right Line Input 1&2 Volume */
+	{ 27, 0x008B },     /* R27 - Right Line Input 3&4 Volume */
+	{ 28, 0x0000 },     /* R28 - Left Output Volume */
+	{ 29, 0x0000 },     /* R29 - Right Output Volume */
+	{ 30, 0x0066 },     /* R30 - Line Outputs Volume */
+	{ 31, 0x0022 },     /* R31 - Out3/4 Volume */
+	{ 32, 0x0079 },     /* R32 - Left OPGA Volume */
+	{ 33, 0x0079 },     /* R33 - Right OPGA Volume */
+	{ 34, 0x0003 },     /* R34 - Speaker Volume */
+	{ 35, 0x0003 },     /* R35 - ClassD1 */
+
+	{ 37, 0x0100 },     /* R37 - ClassD3 */
+	{ 38, 0x0079 },     /* R38 - ClassD4 */
+	{ 39, 0x0000 },     /* R39 - Input Mixer1 */
+	{ 40, 0x0000 },     /* R40 - Input Mixer2 */
+	{ 41, 0x0000 },     /* R41 - Input Mixer3 */
+	{ 42, 0x0000 },     /* R42 - Input Mixer4 */
+	{ 43, 0x0000 },     /* R43 - Input Mixer5 */
+	{ 44, 0x0000 },     /* R44 - Input Mixer6 */
+	{ 45, 0x0000 },     /* R45 - Output Mixer1 */
+	{ 46, 0x0000 },     /* R46 - Output Mixer2 */
+	{ 47, 0x0000 },     /* R47 - Output Mixer3 */
+	{ 48, 0x0000 },     /* R48 - Output Mixer4 */
+	{ 49, 0x0000 },     /* R49 - Output Mixer5 */
+	{ 50, 0x0000 },     /* R50 - Output Mixer6 */
+	{ 51, 0x0180 },     /* R51 - Out3/4 Mixer */
+	{ 52, 0x0000 },     /* R52 - Line Mixer1 */
+	{ 53, 0x0000 },     /* R53 - Line Mixer2 */
+	{ 54, 0x0000 },     /* R54 - Speaker Mixer */
+	{ 55, 0x0000 },     /* R55 - Additional Control */
+	{ 56, 0x0000 },     /* R56 - AntiPOP1 */
+	{ 57, 0x0000 },     /* R57 - AntiPOP2 */
+	{ 58, 0x0000 },     /* R58 - MICBIAS */
+
+	{ 60, 0x0008 },     /* R60 - PLL1 */
+	{ 61, 0x0031 },     /* R61 - PLL2 */
+	{ 62, 0x0026 },     /* R62 - PLL3 */
+};
+
+#define wm8990_reset(c) snd_soc_component_write(c, WM8990_RESET, 0)
+
+static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 600, 0);
+
+static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1650, 3000, 0);
+
+static const DECLARE_TLV_DB_SCALE(out_mix_tlv, 0, -2100, 0);
+
+static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -7300, 600, 0);
+
+static const DECLARE_TLV_DB_SCALE(out_omix_tlv, -600, 0, 0);
+
+static const DECLARE_TLV_DB_SCALE(out_dac_tlv, -7163, 0, 0);
+
+static const DECLARE_TLV_DB_SCALE(in_adc_tlv, -7163, 1763, 0);
+
+static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0);
+
+static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	int reg = mc->reg;
+	int ret;
+	u16 val;
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+	if (ret < 0)
+		return ret;
+
+	/* now hit the volume update bits (always bit 8) */
+	val = snd_soc_component_read32(component, reg);
+	return snd_soc_component_write(component, reg, val | 0x0100);
+}
+
+#define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\
+	tlv_array) \
+	SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \
+		snd_soc_get_volsw, wm899x_outpga_put_volsw_vu, tlv_array)
+
+
+static const char *wm8990_digital_sidetone[] =
+	{"None", "Left ADC", "Right ADC", "Reserved"};
+
+static SOC_ENUM_SINGLE_DECL(wm8990_left_digital_sidetone_enum,
+			    WM8990_DIGITAL_SIDE_TONE,
+			    WM8990_ADC_TO_DACL_SHIFT,
+			    wm8990_digital_sidetone);
+
+static SOC_ENUM_SINGLE_DECL(wm8990_right_digital_sidetone_enum,
+			    WM8990_DIGITAL_SIDE_TONE,
+			    WM8990_ADC_TO_DACR_SHIFT,
+			    wm8990_digital_sidetone);
+
+static const char *wm8990_adcmode[] =
+	{"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
+
+static SOC_ENUM_SINGLE_DECL(wm8990_right_adcmode_enum,
+			    WM8990_ADC_CTRL,
+			    WM8990_ADC_HPF_CUT_SHIFT,
+			    wm8990_adcmode);
+
+static const struct snd_kcontrol_new wm8990_snd_controls[] = {
+/* INMIXL */
+SOC_SINGLE("LIN12 PGA Boost", WM8990_INPUT_MIXER3, WM8990_L12MNBST_BIT, 1, 0),
+SOC_SINGLE("LIN34 PGA Boost", WM8990_INPUT_MIXER3, WM8990_L34MNBST_BIT, 1, 0),
+/* INMIXR */
+SOC_SINGLE("RIN12 PGA Boost", WM8990_INPUT_MIXER3, WM8990_R12MNBST_BIT, 1, 0),
+SOC_SINGLE("RIN34 PGA Boost", WM8990_INPUT_MIXER3, WM8990_R34MNBST_BIT, 1, 0),
+
+/* LOMIX */
+SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER3,
+	WM8990_LLI3LOVOL_SHIFT, WM8990_LLI3LOVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3,
+	WM8990_LR12LOVOL_SHIFT, WM8990_LR12LOVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3,
+	WM8990_LL12LOVOL_SHIFT, WM8990_LL12LOVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER5,
+	WM8990_LRI3LOVOL_SHIFT, WM8990_LRI3LOVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER5,
+	WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER5,
+	WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv),
+
+/* ROMIX */
+SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER4,
+	WM8990_RRI3ROVOL_SHIFT, WM8990_RRI3ROVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4,
+	WM8990_RL12ROVOL_SHIFT, WM8990_RL12ROVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4,
+	WM8990_RR12ROVOL_SHIFT, WM8990_RR12ROVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER6,
+	WM8990_RLI3ROVOL_SHIFT, WM8990_RLI3ROVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER6,
+	WM8990_RLBROVOL_SHIFT, WM8990_RLBROVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER6,
+	WM8990_RRBROVOL_SHIFT, WM8990_RRBROVOL_MASK, 1, out_mix_tlv),
+
+/* LOUT */
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8990_LEFT_OUTPUT_VOLUME,
+	WM8990_LOUTVOL_SHIFT, WM8990_LOUTVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("LOUT ZC", WM8990_LEFT_OUTPUT_VOLUME, WM8990_LOZC_BIT, 1, 0),
+
+/* ROUT */
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8990_RIGHT_OUTPUT_VOLUME,
+	WM8990_ROUTVOL_SHIFT, WM8990_ROUTVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("ROUT ZC", WM8990_RIGHT_OUTPUT_VOLUME, WM8990_ROZC_BIT, 1, 0),
+
+/* LOPGA */
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8990_LEFT_OPGA_VOLUME,
+	WM8990_LOPGAVOL_SHIFT, WM8990_LOPGAVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("LOPGA ZC Switch", WM8990_LEFT_OPGA_VOLUME,
+	WM8990_LOPGAZC_BIT, 1, 0),
+
+/* ROPGA */
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8990_RIGHT_OPGA_VOLUME,
+	WM8990_ROPGAVOL_SHIFT, WM8990_ROPGAVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("ROPGA ZC Switch", WM8990_RIGHT_OPGA_VOLUME,
+	WM8990_ROPGAZC_BIT, 1, 0),
+
+SOC_SINGLE("LON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME,
+	WM8990_LONMUTE_BIT, 1, 0),
+SOC_SINGLE("LOP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME,
+	WM8990_LOPMUTE_BIT, 1, 0),
+SOC_SINGLE("LOP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME,
+	WM8990_LOATTN_BIT, 1, 0),
+SOC_SINGLE("RON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME,
+	WM8990_RONMUTE_BIT, 1, 0),
+SOC_SINGLE("ROP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME,
+	WM8990_ROPMUTE_BIT, 1, 0),
+SOC_SINGLE("ROP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME,
+	WM8990_ROATTN_BIT, 1, 0),
+
+SOC_SINGLE("OUT3 Mute Switch", WM8990_OUT3_4_VOLUME,
+	WM8990_OUT3MUTE_BIT, 1, 0),
+SOC_SINGLE("OUT3 Attenuation Switch", WM8990_OUT3_4_VOLUME,
+	WM8990_OUT3ATTN_BIT, 1, 0),
+
+SOC_SINGLE("OUT4 Mute Switch", WM8990_OUT3_4_VOLUME,
+	WM8990_OUT4MUTE_BIT, 1, 0),
+SOC_SINGLE("OUT4 Attenuation Switch", WM8990_OUT3_4_VOLUME,
+	WM8990_OUT4ATTN_BIT, 1, 0),
+
+SOC_SINGLE("Speaker Mode Switch", WM8990_CLASSD1,
+	WM8990_CDMODE_BIT, 1, 0),
+
+SOC_SINGLE("Speaker Output Attenuation Volume", WM8990_SPEAKER_VOLUME,
+	WM8990_SPKATTN_SHIFT, WM8990_SPKATTN_MASK, 0),
+SOC_SINGLE("Speaker DC Boost Volume", WM8990_CLASSD3,
+	WM8990_DCGAIN_SHIFT, WM8990_DCGAIN_MASK, 0),
+SOC_SINGLE("Speaker AC Boost Volume", WM8990_CLASSD3,
+	WM8990_ACGAIN_SHIFT, WM8990_ACGAIN_MASK, 0),
+SOC_SINGLE_TLV("Speaker Volume", WM8990_CLASSD4,
+	WM8990_SPKVOL_SHIFT, WM8990_SPKVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("Speaker ZC Switch", WM8990_CLASSD4,
+	WM8990_SPKZC_SHIFT, WM8990_SPKZC_MASK, 0),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume",
+	WM8990_LEFT_DAC_DIGITAL_VOLUME,
+	WM8990_DACL_VOL_SHIFT,
+	WM8990_DACL_VOL_MASK,
+	0,
+	out_dac_tlv),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume",
+	WM8990_RIGHT_DAC_DIGITAL_VOLUME,
+	WM8990_DACR_VOL_SHIFT,
+	WM8990_DACR_VOL_MASK,
+	0,
+	out_dac_tlv),
+
+SOC_ENUM("Left Digital Sidetone", wm8990_left_digital_sidetone_enum),
+SOC_ENUM("Right Digital Sidetone", wm8990_right_digital_sidetone_enum),
+
+SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE,
+	WM8990_ADCL_DAC_SVOL_SHIFT, WM8990_ADCL_DAC_SVOL_MASK, 0,
+	out_sidetone_tlv),
+SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE,
+	WM8990_ADCR_DAC_SVOL_SHIFT, WM8990_ADCR_DAC_SVOL_MASK, 0,
+	out_sidetone_tlv),
+
+SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8990_ADC_CTRL,
+	WM8990_ADC_HPF_ENA_BIT, 1, 0),
+
+SOC_ENUM("ADC HPF Mode", wm8990_right_adcmode_enum),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume",
+	WM8990_LEFT_ADC_DIGITAL_VOLUME,
+	WM8990_ADCL_VOL_SHIFT,
+	WM8990_ADCL_VOL_MASK,
+	0,
+	in_adc_tlv),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume",
+	WM8990_RIGHT_ADC_DIGITAL_VOLUME,
+	WM8990_ADCR_VOL_SHIFT,
+	WM8990_ADCR_VOL_MASK,
+	0,
+	in_adc_tlv),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN12 Volume",
+	WM8990_LEFT_LINE_INPUT_1_2_VOLUME,
+	WM8990_LIN12VOL_SHIFT,
+	WM8990_LIN12VOL_MASK,
+	0,
+	in_pga_tlv),
+
+SOC_SINGLE("LIN12 ZC Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME,
+	WM8990_LI12ZC_BIT, 1, 0),
+
+SOC_SINGLE("LIN12 Mute Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME,
+	WM8990_LI12MUTE_BIT, 1, 0),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN34 Volume",
+	WM8990_LEFT_LINE_INPUT_3_4_VOLUME,
+	WM8990_LIN34VOL_SHIFT,
+	WM8990_LIN34VOL_MASK,
+	0,
+	in_pga_tlv),
+
+SOC_SINGLE("LIN34 ZC Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME,
+	WM8990_LI34ZC_BIT, 1, 0),
+
+SOC_SINGLE("LIN34 Mute Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME,
+	WM8990_LI34MUTE_BIT, 1, 0),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN12 Volume",
+	WM8990_RIGHT_LINE_INPUT_1_2_VOLUME,
+	WM8990_RIN12VOL_SHIFT,
+	WM8990_RIN12VOL_MASK,
+	0,
+	in_pga_tlv),
+
+SOC_SINGLE("RIN12 ZC Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME,
+	WM8990_RI12ZC_BIT, 1, 0),
+
+SOC_SINGLE("RIN12 Mute Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME,
+	WM8990_RI12MUTE_BIT, 1, 0),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN34 Volume",
+	WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
+	WM8990_RIN34VOL_SHIFT,
+	WM8990_RIN34VOL_MASK,
+	0,
+	in_pga_tlv),
+
+SOC_SINGLE("RIN34 ZC Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
+	WM8990_RI34ZC_BIT, 1, 0),
+
+SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
+	WM8990_RI34MUTE_BIT, 1, 0),
+
+};
+
+/*
+ * _DAPM_ Controls
+ */
+
+static int outmixer_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u32 reg_shift = kcontrol->private_value & 0xfff;
+	int ret = 0;
+	u16 reg;
+
+	switch (reg_shift) {
+	case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) :
+		reg = snd_soc_component_read32(component, WM8990_OUTPUT_MIXER1);
+		if (reg & WM8990_LDLO) {
+			printk(KERN_WARNING
+			"Cannot set as Output Mixer 1 LDLO Set\n");
+			ret = -1;
+		}
+		break;
+	case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8):
+		reg = snd_soc_component_read32(component, WM8990_OUTPUT_MIXER2);
+		if (reg & WM8990_RDRO) {
+			printk(KERN_WARNING
+			"Cannot set as Output Mixer 2 RDRO Set\n");
+			ret = -1;
+		}
+		break;
+	case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8):
+		reg = snd_soc_component_read32(component, WM8990_SPEAKER_MIXER);
+		if (reg & WM8990_LDSPK) {
+			printk(KERN_WARNING
+			"Cannot set as Speaker Mixer LDSPK Set\n");
+			ret = -1;
+		}
+		break;
+	case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8):
+		reg = snd_soc_component_read32(component, WM8990_SPEAKER_MIXER);
+		if (reg & WM8990_RDSPK) {
+			printk(KERN_WARNING
+			"Cannot set as Speaker Mixer RDSPK Set\n");
+			ret = -1;
+		}
+		break;
+	}
+
+	return ret;
+}
+
+/* INMIX dB values */
+static const DECLARE_TLV_DB_SCALE(in_mix_tlv, -1200, 600, 0);
+
+/* Left In PGA Connections */
+static const struct snd_kcontrol_new wm8990_dapm_lin12_pga_controls[] = {
+SOC_DAPM_SINGLE("LIN1 Switch", WM8990_INPUT_MIXER2, WM8990_LMN1_BIT, 1, 0),
+SOC_DAPM_SINGLE("LIN2 Switch", WM8990_INPUT_MIXER2, WM8990_LMP2_BIT, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8990_dapm_lin34_pga_controls[] = {
+SOC_DAPM_SINGLE("LIN3 Switch", WM8990_INPUT_MIXER2, WM8990_LMN3_BIT, 1, 0),
+SOC_DAPM_SINGLE("LIN4 Switch", WM8990_INPUT_MIXER2, WM8990_LMP4_BIT, 1, 0),
+};
+
+/* Right In PGA Connections */
+static const struct snd_kcontrol_new wm8990_dapm_rin12_pga_controls[] = {
+SOC_DAPM_SINGLE("RIN1 Switch", WM8990_INPUT_MIXER2, WM8990_RMN1_BIT, 1, 0),
+SOC_DAPM_SINGLE("RIN2 Switch", WM8990_INPUT_MIXER2, WM8990_RMP2_BIT, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8990_dapm_rin34_pga_controls[] = {
+SOC_DAPM_SINGLE("RIN3 Switch", WM8990_INPUT_MIXER2, WM8990_RMN3_BIT, 1, 0),
+SOC_DAPM_SINGLE("RIN4 Switch", WM8990_INPUT_MIXER2, WM8990_RMP4_BIT, 1, 0),
+};
+
+/* INMIXL */
+static const struct snd_kcontrol_new wm8990_dapm_inmixl_controls[] = {
+SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8990_INPUT_MIXER3,
+	WM8990_LDBVOL_SHIFT, WM8990_LDBVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8990_INPUT_MIXER5, WM8990_LI2BVOL_SHIFT,
+	7, 0, in_mix_tlv),
+SOC_DAPM_SINGLE("LINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT,
+	1, 0),
+SOC_DAPM_SINGLE("LINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT,
+	1, 0),
+};
+
+/* INMIXR */
+static const struct snd_kcontrol_new wm8990_dapm_inmixr_controls[] = {
+SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8990_INPUT_MIXER4,
+	WM8990_RDBVOL_SHIFT, WM8990_RDBVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8990_INPUT_MIXER6, WM8990_RI2BVOL_SHIFT,
+	7, 0, in_mix_tlv),
+SOC_DAPM_SINGLE("RINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT,
+	1, 0),
+SOC_DAPM_SINGLE("RINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT,
+	1, 0),
+};
+
+/* AINLMUX */
+static const char *wm8990_ainlmux[] =
+	{"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
+
+static SOC_ENUM_SINGLE_DECL(wm8990_ainlmux_enum,
+			    WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT,
+			    wm8990_ainlmux);
+
+static const struct snd_kcontrol_new wm8990_dapm_ainlmux_controls =
+SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum);
+
+/* DIFFINL */
+
+/* AINRMUX */
+static const char *wm8990_ainrmux[] =
+	{"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
+
+static SOC_ENUM_SINGLE_DECL(wm8990_ainrmux_enum,
+			    WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT,
+			    wm8990_ainrmux);
+
+static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls =
+SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum);
+
+/* RXVOICE */
+static const struct snd_kcontrol_new wm8990_dapm_rxvoice_controls[] = {
+SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8990_INPUT_MIXER5, WM8990_LR4BVOL_SHIFT,
+			WM8990_LR4BVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8990_INPUT_MIXER6, WM8990_RL4BVOL_SHIFT,
+			WM8990_RL4BVOL_MASK, 0, in_mix_tlv),
+};
+
+/* LOMIX */
+static const struct snd_kcontrol_new wm8990_dapm_lomix_controls[] = {
+SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER1,
+	WM8990_LRBLO_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER1,
+	WM8990_LLBLO_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER1,
+	WM8990_LRI3LO_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER1,
+	WM8990_LLI3LO_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1,
+	WM8990_LR12LO_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1,
+	WM8990_LL12LO_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8990_OUTPUT_MIXER1,
+	WM8990_LDLO_BIT, 1, 0),
+};
+
+/* ROMIX */
+static const struct snd_kcontrol_new wm8990_dapm_romix_controls[] = {
+SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER2,
+	WM8990_RLBRO_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER2,
+	WM8990_RRBRO_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER2,
+	WM8990_RLI3RO_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER2,
+	WM8990_RRI3RO_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2,
+	WM8990_RL12RO_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2,
+	WM8990_RR12RO_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8990_OUTPUT_MIXER2,
+	WM8990_RDRO_BIT, 1, 0),
+};
+
+/* LONMIX */
+static const struct snd_kcontrol_new wm8990_dapm_lonmix_controls[] = {
+SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1,
+	WM8990_LLOPGALON_BIT, 1, 0),
+SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER1,
+	WM8990_LROPGALON_BIT, 1, 0),
+SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8990_LINE_MIXER1,
+	WM8990_LOPLON_BIT, 1, 0),
+};
+
+/* LOPMIX */
+static const struct snd_kcontrol_new wm8990_dapm_lopmix_controls[] = {
+SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER1,
+	WM8990_LR12LOP_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER1,
+	WM8990_LL12LOP_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1,
+	WM8990_LLOPGALOP_BIT, 1, 0),
+};
+
+/* RONMIX */
+static const struct snd_kcontrol_new wm8990_dapm_ronmix_controls[] = {
+SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2,
+	WM8990_RROPGARON_BIT, 1, 0),
+SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER2,
+	WM8990_RLOPGARON_BIT, 1, 0),
+SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8990_LINE_MIXER2,
+	WM8990_ROPRON_BIT, 1, 0),
+};
+
+/* ROPMIX */
+static const struct snd_kcontrol_new wm8990_dapm_ropmix_controls[] = {
+SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER2,
+	WM8990_RL12ROP_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER2,
+	WM8990_RR12ROP_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2,
+	WM8990_RROPGAROP_BIT, 1, 0),
+};
+
+/* OUT3MIX */
+static const struct snd_kcontrol_new wm8990_dapm_out3mix_controls[] = {
+SOC_DAPM_SINGLE("OUT3MIX LIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER,
+	WM8990_LI4O3_BIT, 1, 0),
+SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8990_OUT3_4_MIXER,
+	WM8990_LPGAO3_BIT, 1, 0),
+};
+
+/* OUT4MIX */
+static const struct snd_kcontrol_new wm8990_dapm_out4mix_controls[] = {
+SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8990_OUT3_4_MIXER,
+	WM8990_RPGAO4_BIT, 1, 0),
+SOC_DAPM_SINGLE("OUT4MIX RIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER,
+	WM8990_RI4O4_BIT, 1, 0),
+};
+
+/* SPKMIX */
+static const struct snd_kcontrol_new wm8990_dapm_spkmix_controls[] = {
+SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8990_SPEAKER_MIXER,
+	WM8990_LI2SPK_BIT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8990_SPEAKER_MIXER,
+	WM8990_LB2SPK_BIT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8990_SPEAKER_MIXER,
+	WM8990_LOPGASPK_BIT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8990_SPEAKER_MIXER,
+	WM8990_LDSPK_BIT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8990_SPEAKER_MIXER,
+	WM8990_RDSPK_BIT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8990_SPEAKER_MIXER,
+	WM8990_ROPGASPK_BIT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8990_SPEAKER_MIXER,
+	WM8990_RL12ROP_BIT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8990_SPEAKER_MIXER,
+	WM8990_RI2SPK_BIT, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8990_dapm_widgets[] = {
+/* Input Side */
+/* Input Lines */
+SND_SOC_DAPM_INPUT("LIN1"),
+SND_SOC_DAPM_INPUT("LIN2"),
+SND_SOC_DAPM_INPUT("LIN3"),
+SND_SOC_DAPM_INPUT("LIN4/RXN"),
+SND_SOC_DAPM_INPUT("RIN3"),
+SND_SOC_DAPM_INPUT("RIN4/RXP"),
+SND_SOC_DAPM_INPUT("RIN1"),
+SND_SOC_DAPM_INPUT("RIN2"),
+SND_SOC_DAPM_INPUT("Internal ADC Source"),
+
+SND_SOC_DAPM_SUPPLY("INL", WM8990_POWER_MANAGEMENT_2, WM8990_AINL_ENA_BIT, 0,
+		    NULL, 0),
+SND_SOC_DAPM_SUPPLY("INR", WM8990_POWER_MANAGEMENT_2, WM8990_AINR_ENA_BIT, 0,
+		    NULL, 0),
+
+/* DACs */
+SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8990_POWER_MANAGEMENT_2,
+	WM8990_ADCL_ENA_BIT, 0),
+SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8990_POWER_MANAGEMENT_2,
+	WM8990_ADCR_ENA_BIT, 0),
+
+/* Input PGAs */
+SND_SOC_DAPM_MIXER("LIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN12_ENA_BIT,
+	0, &wm8990_dapm_lin12_pga_controls[0],
+	ARRAY_SIZE(wm8990_dapm_lin12_pga_controls)),
+SND_SOC_DAPM_MIXER("LIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN34_ENA_BIT,
+	0, &wm8990_dapm_lin34_pga_controls[0],
+	ARRAY_SIZE(wm8990_dapm_lin34_pga_controls)),
+SND_SOC_DAPM_MIXER("RIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN12_ENA_BIT,
+	0, &wm8990_dapm_rin12_pga_controls[0],
+	ARRAY_SIZE(wm8990_dapm_rin12_pga_controls)),
+SND_SOC_DAPM_MIXER("RIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN34_ENA_BIT,
+	0, &wm8990_dapm_rin34_pga_controls[0],
+	ARRAY_SIZE(wm8990_dapm_rin34_pga_controls)),
+
+/* INMIXL */
+SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0,
+	&wm8990_dapm_inmixl_controls[0],
+	ARRAY_SIZE(wm8990_dapm_inmixl_controls)),
+
+/* AINLMUX */
+SND_SOC_DAPM_MUX("AINLMUX", SND_SOC_NOPM, 0, 0, &wm8990_dapm_ainlmux_controls),
+
+/* INMIXR */
+SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0,
+	&wm8990_dapm_inmixr_controls[0],
+	ARRAY_SIZE(wm8990_dapm_inmixr_controls)),
+
+/* AINRMUX */
+SND_SOC_DAPM_MUX("AINRMUX", SND_SOC_NOPM, 0, 0, &wm8990_dapm_ainrmux_controls),
+
+/* Output Side */
+/* DACs */
+SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8990_POWER_MANAGEMENT_3,
+	WM8990_DACL_ENA_BIT, 0),
+SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8990_POWER_MANAGEMENT_3,
+	WM8990_DACR_ENA_BIT, 0),
+
+/* LOMIX */
+SND_SOC_DAPM_MIXER_E("LOMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOMIX_ENA_BIT,
+	0, &wm8990_dapm_lomix_controls[0],
+	ARRAY_SIZE(wm8990_dapm_lomix_controls),
+	outmixer_event, SND_SOC_DAPM_PRE_REG),
+
+/* LONMIX */
+SND_SOC_DAPM_MIXER("LONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LON_ENA_BIT, 0,
+	&wm8990_dapm_lonmix_controls[0],
+	ARRAY_SIZE(wm8990_dapm_lonmix_controls)),
+
+/* LOPMIX */
+SND_SOC_DAPM_MIXER("LOPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOP_ENA_BIT, 0,
+	&wm8990_dapm_lopmix_controls[0],
+	ARRAY_SIZE(wm8990_dapm_lopmix_controls)),
+
+/* OUT3MIX */
+SND_SOC_DAPM_MIXER("OUT3MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT3_ENA_BIT, 0,
+	&wm8990_dapm_out3mix_controls[0],
+	ARRAY_SIZE(wm8990_dapm_out3mix_controls)),
+
+/* SPKMIX */
+SND_SOC_DAPM_MIXER_E("SPKMIX", WM8990_POWER_MANAGEMENT_1, WM8990_SPK_ENA_BIT, 0,
+	&wm8990_dapm_spkmix_controls[0],
+	ARRAY_SIZE(wm8990_dapm_spkmix_controls), outmixer_event,
+	SND_SOC_DAPM_PRE_REG),
+
+/* OUT4MIX */
+SND_SOC_DAPM_MIXER("OUT4MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT4_ENA_BIT, 0,
+	&wm8990_dapm_out4mix_controls[0],
+	ARRAY_SIZE(wm8990_dapm_out4mix_controls)),
+
+/* ROPMIX */
+SND_SOC_DAPM_MIXER("ROPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROP_ENA_BIT, 0,
+	&wm8990_dapm_ropmix_controls[0],
+	ARRAY_SIZE(wm8990_dapm_ropmix_controls)),
+
+/* RONMIX */
+SND_SOC_DAPM_MIXER("RONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_RON_ENA_BIT, 0,
+	&wm8990_dapm_ronmix_controls[0],
+	ARRAY_SIZE(wm8990_dapm_ronmix_controls)),
+
+/* ROMIX */
+SND_SOC_DAPM_MIXER_E("ROMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROMIX_ENA_BIT,
+	0, &wm8990_dapm_romix_controls[0],
+	ARRAY_SIZE(wm8990_dapm_romix_controls),
+	outmixer_event, SND_SOC_DAPM_PRE_REG),
+
+/* LOUT PGA */
+SND_SOC_DAPM_PGA("LOUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_LOUT_ENA_BIT, 0,
+	NULL, 0),
+
+/* ROUT PGA */
+SND_SOC_DAPM_PGA("ROUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_ROUT_ENA_BIT, 0,
+	NULL, 0),
+
+/* LOPGA */
+SND_SOC_DAPM_PGA("LOPGA", WM8990_POWER_MANAGEMENT_3, WM8990_LOPGA_ENA_BIT, 0,
+	NULL, 0),
+
+/* ROPGA */
+SND_SOC_DAPM_PGA("ROPGA", WM8990_POWER_MANAGEMENT_3, WM8990_ROPGA_ENA_BIT, 0,
+	NULL, 0),
+
+/* MICBIAS */
+SND_SOC_DAPM_SUPPLY("MICBIAS", WM8990_POWER_MANAGEMENT_1,
+		    WM8990_MICBIAS_ENA_BIT, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("LON"),
+SND_SOC_DAPM_OUTPUT("LOP"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("SPKN"),
+SND_SOC_DAPM_OUTPUT("SPKP"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("OUT4"),
+SND_SOC_DAPM_OUTPUT("ROP"),
+SND_SOC_DAPM_OUTPUT("RON"),
+
+SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
+};
+
+static const struct snd_soc_dapm_route wm8990_dapm_routes[] = {
+	/* Make DACs turn on when playing even if not mixed into any outputs */
+	{"Internal DAC Sink", NULL, "Left DAC"},
+	{"Internal DAC Sink", NULL, "Right DAC"},
+
+	/* Make ADCs turn on when recording even if not mixed from any inputs */
+	{"Left ADC", NULL, "Internal ADC Source"},
+	{"Right ADC", NULL, "Internal ADC Source"},
+
+	{"AINLMUX", NULL, "INL"},
+	{"INMIXL", NULL, "INL"},
+	{"AINRMUX", NULL, "INR"},
+	{"INMIXR", NULL, "INR"},
+
+	/* Input Side */
+	/* LIN12 PGA */
+	{"LIN12 PGA", "LIN1 Switch", "LIN1"},
+	{"LIN12 PGA", "LIN2 Switch", "LIN2"},
+	/* LIN34 PGA */
+	{"LIN34 PGA", "LIN3 Switch", "LIN3"},
+	{"LIN34 PGA", "LIN4 Switch", "LIN4/RXN"},
+	/* INMIXL */
+	{"INMIXL", "Record Left Volume", "LOMIX"},
+	{"INMIXL", "LIN2 Volume", "LIN2"},
+	{"INMIXL", "LINPGA12 Switch", "LIN12 PGA"},
+	{"INMIXL", "LINPGA34 Switch", "LIN34 PGA"},
+	/* AINLMUX */
+	{"AINLMUX", "INMIXL Mix", "INMIXL"},
+	{"AINLMUX", "DIFFINL Mix", "LIN12 PGA"},
+	{"AINLMUX", "DIFFINL Mix", "LIN34 PGA"},
+	{"AINLMUX", "RXVOICE Mix", "LIN4/RXN"},
+	{"AINLMUX", "RXVOICE Mix", "RIN4/RXP"},
+	/* ADC */
+	{"Left ADC", NULL, "AINLMUX"},
+
+	/* RIN12 PGA */
+	{"RIN12 PGA", "RIN1 Switch", "RIN1"},
+	{"RIN12 PGA", "RIN2 Switch", "RIN2"},
+	/* RIN34 PGA */
+	{"RIN34 PGA", "RIN3 Switch", "RIN3"},
+	{"RIN34 PGA", "RIN4 Switch", "RIN4/RXP"},
+	/* INMIXL */
+	{"INMIXR", "Record Right Volume", "ROMIX"},
+	{"INMIXR", "RIN2 Volume", "RIN2"},
+	{"INMIXR", "RINPGA12 Switch", "RIN12 PGA"},
+	{"INMIXR", "RINPGA34 Switch", "RIN34 PGA"},
+	/* AINRMUX */
+	{"AINRMUX", "INMIXR Mix", "INMIXR"},
+	{"AINRMUX", "DIFFINR Mix", "RIN12 PGA"},
+	{"AINRMUX", "DIFFINR Mix", "RIN34 PGA"},
+	{"AINRMUX", "RXVOICE Mix", "LIN4/RXN"},
+	{"AINRMUX", "RXVOICE Mix", "RIN4/RXP"},
+	/* ADC */
+	{"Right ADC", NULL, "AINRMUX"},
+
+	/* LOMIX */
+	{"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"},
+	{"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"},
+	{"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
+	{"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
+	{"LOMIX", "LOMIX Right ADC Bypass Switch", "AINRMUX"},
+	{"LOMIX", "LOMIX Left ADC Bypass Switch", "AINLMUX"},
+	{"LOMIX", "LOMIX Left DAC Switch", "Left DAC"},
+
+	/* ROMIX */
+	{"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"},
+	{"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"},
+	{"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
+	{"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
+	{"ROMIX", "ROMIX Right ADC Bypass Switch", "AINRMUX"},
+	{"ROMIX", "ROMIX Left ADC Bypass Switch", "AINLMUX"},
+	{"ROMIX", "ROMIX Right DAC Switch", "Right DAC"},
+
+	/* SPKMIX */
+	{"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"},
+	{"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"},
+	{"SPKMIX", "SPKMIX LADC Bypass Switch", "AINLMUX"},
+	{"SPKMIX", "SPKMIX RADC Bypass Switch", "AINRMUX"},
+	{"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"},
+	{"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"},
+	{"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"},
+	{"SPKMIX", "SPKMIX Left DAC Switch", "Left DAC"},
+
+	/* LONMIX */
+	{"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"},
+	{"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"},
+	{"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"},
+
+	/* LOPMIX */
+	{"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"},
+	{"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"},
+	{"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"},
+
+	/* OUT3MIX */
+	{"OUT3MIX", "OUT3MIX LIN4/RXP Bypass Switch", "LIN4/RXN"},
+	{"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"},
+
+	/* OUT4MIX */
+	{"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"},
+	{"OUT4MIX", "OUT4MIX RIN4/RXP Bypass Switch", "RIN4/RXP"},
+
+	/* RONMIX */
+	{"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"},
+	{"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"},
+	{"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"},
+
+	/* ROPMIX */
+	{"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"},
+	{"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"},
+	{"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"},
+
+	/* Out Mixer PGAs */
+	{"LOPGA", NULL, "LOMIX"},
+	{"ROPGA", NULL, "ROMIX"},
+
+	{"LOUT PGA", NULL, "LOMIX"},
+	{"ROUT PGA", NULL, "ROMIX"},
+
+	/* Output Pins */
+	{"LON", NULL, "LONMIX"},
+	{"LOP", NULL, "LOPMIX"},
+	{"OUT3", NULL, "OUT3MIX"},
+	{"LOUT", NULL, "LOUT PGA"},
+	{"SPKN", NULL, "SPKMIX"},
+	{"ROUT", NULL, "ROUT PGA"},
+	{"OUT4", NULL, "OUT4MIX"},
+	{"ROP", NULL, "ROPMIX"},
+	{"RON", NULL, "RONMIX"},
+};
+
+/* PLL divisors */
+struct _pll_div {
+	u32 div2;
+	u32 n;
+	u32 k;
+};
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 16) * 10)
+
+static void pll_factors(struct _pll_div *pll_div, unsigned int target,
+	unsigned int source)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod;
+
+
+	Ndiv = target / source;
+	if (Ndiv < 6) {
+		source >>= 1;
+		pll_div->div2 = 1;
+		Ndiv = target / source;
+	} else
+		pll_div->div2 = 0;
+
+	if ((Ndiv < 6) || (Ndiv > 12))
+		printk(KERN_WARNING
+		"WM8990 N value outwith recommended range! N = %u\n", Ndiv);
+
+	pll_div->n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	/* Check if we need to round */
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	K /= 10;
+
+	pll_div->k = K;
+}
+
+static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+		int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct _pll_div pll_div;
+
+	if (freq_in && freq_out) {
+		pll_factors(&pll_div, freq_out * 4, freq_in);
+
+		/* Turn on PLL */
+		snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_2,
+				    WM8990_PLL_ENA, WM8990_PLL_ENA);
+
+		/* sysclk comes from PLL */
+		snd_soc_component_update_bits(component, WM8990_CLOCKING_2,
+				    WM8990_SYSCLK_SRC, WM8990_SYSCLK_SRC);
+
+		/* set up N , fractional mode and pre-divisor if necessary */
+		snd_soc_component_write(component, WM8990_PLL1, pll_div.n | WM8990_SDM |
+			(pll_div.div2?WM8990_PRESCALE:0));
+		snd_soc_component_write(component, WM8990_PLL2, (u8)(pll_div.k>>8));
+		snd_soc_component_write(component, WM8990_PLL3, (u8)(pll_div.k & 0xFF));
+	} else {
+		/* Turn off PLL */
+		snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_2,
+				    WM8990_PLL_ENA, 0);
+	}
+	return 0;
+}
+
+/*
+ * Clock after PLL and dividers
+ */
+static int wm8990_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8990_priv *wm8990 = snd_soc_component_get_drvdata(component);
+
+	wm8990->sysclk = freq;
+	return 0;
+}
+
+/*
+ * Set's ADC and Voice DAC format.
+ */
+static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 audio1, audio3;
+
+	audio1 = snd_soc_component_read32(component, WM8990_AUDIO_INTERFACE_1);
+	audio3 = snd_soc_component_read32(component, WM8990_AUDIO_INTERFACE_3);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		audio3 &= ~WM8990_AIF_MSTR1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		audio3 |= WM8990_AIF_MSTR1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	audio1 &= ~WM8990_AIF_FMT_MASK;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		audio1 |= WM8990_AIF_TMF_I2S;
+		audio1 &= ~WM8990_AIF_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		audio1 |= WM8990_AIF_TMF_RIGHTJ;
+		audio1 &= ~WM8990_AIF_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		audio1 |= WM8990_AIF_TMF_LEFTJ;
+		audio1 &= ~WM8990_AIF_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		audio1 |= WM8990_AIF_TMF_DSP;
+		audio1 &= ~WM8990_AIF_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		audio1 |= WM8990_AIF_TMF_DSP | WM8990_AIF_LRCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8990_AUDIO_INTERFACE_1, audio1);
+	snd_soc_component_write(component, WM8990_AUDIO_INTERFACE_3, audio3);
+	return 0;
+}
+
+static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+		int div_id, int div)
+{
+	struct snd_soc_component *component = codec_dai->component;
+
+	switch (div_id) {
+	case WM8990_MCLK_DIV:
+		snd_soc_component_update_bits(component, WM8990_CLOCKING_2,
+				    WM8990_MCLK_DIV_MASK, div);
+		break;
+	case WM8990_DACCLK_DIV:
+		snd_soc_component_update_bits(component, WM8990_CLOCKING_2,
+				    WM8990_DAC_CLKDIV_MASK, div);
+		break;
+	case WM8990_ADCCLK_DIV:
+		snd_soc_component_update_bits(component, WM8990_CLOCKING_2,
+				    WM8990_ADC_CLKDIV_MASK, div);
+		break;
+	case WM8990_BCLK_DIV:
+		snd_soc_component_update_bits(component, WM8990_CLOCKING_1,
+				    WM8990_BCLK_DIV_MASK, div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ */
+static int wm8990_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 audio1 = snd_soc_component_read32(component, WM8990_AUDIO_INTERFACE_1);
+
+	audio1 &= ~WM8990_AIF_WL_MASK;
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		audio1 |= WM8990_AIF_WL_20BITS;
+		break;
+	case 24:
+		audio1 |= WM8990_AIF_WL_24BITS;
+		break;
+	case 32:
+		audio1 |= WM8990_AIF_WL_32BITS;
+		break;
+	}
+
+	snd_soc_component_write(component, WM8990_AUDIO_INTERFACE_1, audio1);
+	return 0;
+}
+
+static int wm8990_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 val;
+
+	val  = snd_soc_component_read32(component, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE;
+
+	if (mute)
+		snd_soc_component_write(component, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
+	else
+		snd_soc_component_write(component, WM8990_DAC_CTRL, val);
+
+	return 0;
+}
+
+static int wm8990_set_bias_level(struct snd_soc_component *component,
+	enum snd_soc_bias_level level)
+{
+	struct wm8990_priv *wm8990 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* VMID=2*50k */
+		snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_1,
+				    WM8990_VMID_MODE_MASK, 0x2);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regcache_sync(wm8990->regmap);
+			if (ret < 0) {
+				dev_err(component->dev, "Failed to sync cache: %d\n", ret);
+				return ret;
+			}
+
+			/* Enable all output discharge bits */
+			snd_soc_component_write(component, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
+				WM8990_DIS_RLINE | WM8990_DIS_OUT3 |
+				WM8990_DIS_OUT4 | WM8990_DIS_LOUT |
+				WM8990_DIS_ROUT);
+
+			/* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
+			snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST |
+				     WM8990_BUFDCOPEN | WM8990_POBCTRL |
+				     WM8990_VMIDTOG);
+
+			/* Delay to allow output caps to discharge */
+			msleep(300);
+
+			/* Disable VMIDTOG */
+			snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST |
+				     WM8990_BUFDCOPEN | WM8990_POBCTRL);
+
+			/* disable all output discharge bits */
+			snd_soc_component_write(component, WM8990_ANTIPOP1, 0);
+
+			/* Enable outputs */
+			snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1b00);
+
+			msleep(50);
+
+			/* Enable VMID at 2x50k */
+			snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1f02);
+
+			msleep(100);
+
+			/* Enable VREF */
+			snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1f03);
+
+			msleep(600);
+
+			/* Enable BUFIOEN */
+			snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST |
+				     WM8990_BUFDCOPEN | WM8990_POBCTRL |
+				     WM8990_BUFIOEN);
+
+			/* Disable outputs */
+			snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x3);
+
+			/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
+			snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_BUFIOEN);
+
+			/* Enable workaround for ADC clocking issue. */
+			snd_soc_component_write(component, WM8990_EXT_ACCESS_ENA, 0x2);
+			snd_soc_component_write(component, WM8990_EXT_CTL1, 0xa003);
+			snd_soc_component_write(component, WM8990_EXT_ACCESS_ENA, 0);
+		}
+
+		/* VMID=2*250k */
+		snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_1,
+				    WM8990_VMID_MODE_MASK, 0x4);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* Enable POBCTRL and SOFT_ST */
+		snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST |
+			WM8990_POBCTRL | WM8990_BUFIOEN);
+
+		/* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
+		snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST |
+			WM8990_BUFDCOPEN | WM8990_POBCTRL |
+			WM8990_BUFIOEN);
+
+		/* mute DAC */
+		snd_soc_component_update_bits(component, WM8990_DAC_CTRL,
+				    WM8990_DAC_MUTE, WM8990_DAC_MUTE);
+
+		/* Enable any disabled outputs */
+		snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1f03);
+
+		/* Disable VMID */
+		snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1f01);
+
+		msleep(300);
+
+		/* Enable all output discharge bits */
+		snd_soc_component_write(component, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
+			WM8990_DIS_RLINE | WM8990_DIS_OUT3 |
+			WM8990_DIS_OUT4 | WM8990_DIS_LOUT |
+			WM8990_DIS_ROUT);
+
+		/* Disable VREF */
+		snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x0);
+
+		/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
+		snd_soc_component_write(component, WM8990_ANTIPOP2, 0x0);
+
+		regcache_mark_dirty(wm8990->regmap);
+		break;
+	}
+
+	return 0;
+}
+
+#define WM8990_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+	SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+	SNDRV_PCM_RATE_48000)
+
+#define WM8990_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+/*
+ * The WM8990 supports 2 different and mutually exclusive DAI
+ * configurations.
+ *
+ * 1. ADC/DAC on Primary Interface
+ * 2. ADC on Primary Interface/DAC on secondary
+ */
+static const struct snd_soc_dai_ops wm8990_dai_ops = {
+	.hw_params	= wm8990_hw_params,
+	.digital_mute	= wm8990_mute,
+	.set_fmt	= wm8990_set_dai_fmt,
+	.set_clkdiv	= wm8990_set_dai_clkdiv,
+	.set_pll	= wm8990_set_dai_pll,
+	.set_sysclk	= wm8990_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8990_dai = {
+/* ADC/DAC on primary */
+	.name = "wm8990-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8990_RATES,
+		.formats = WM8990_FORMATS,},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8990_RATES,
+		.formats = WM8990_FORMATS,},
+	.ops = &wm8990_dai_ops,
+};
+
+/*
+ * initialise the WM8990 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8990_probe(struct snd_soc_component *component)
+{
+	wm8990_reset(component);
+
+	/* charge output caps */
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	snd_soc_component_update_bits(component, WM8990_AUDIO_INTERFACE_4,
+			    WM8990_ALRCGPIO1, WM8990_ALRCGPIO1);
+
+	snd_soc_component_update_bits(component, WM8990_GPIO1_GPIO2,
+			    WM8990_GPIO1_SEL_MASK, 1);
+
+	snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_2,
+			    WM8990_OPCLK_ENA, WM8990_OPCLK_ENA);
+
+	snd_soc_component_write(component, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
+	snd_soc_component_write(component, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8990 = {
+	.probe			= wm8990_probe,
+	.set_bias_level		= wm8990_set_bias_level,
+	.controls		= wm8990_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8990_snd_controls),
+	.dapm_widgets		= wm8990_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8990_dapm_widgets),
+	.dapm_routes		= wm8990_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8990_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8990_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = WM8990_PLL3,
+	.volatile_reg = wm8990_volatile_register,
+	.reg_defaults = wm8990_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8990_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int wm8990_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8990_priv *wm8990;
+	int ret;
+
+	wm8990 = devm_kzalloc(&i2c->dev, sizeof(struct wm8990_priv),
+			      GFP_KERNEL);
+	if (wm8990 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, wm8990);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8990, &wm8990_dai, 1);
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8990_i2c_id[] = {
+	{ "wm8990", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id);
+
+static struct i2c_driver wm8990_i2c_driver = {
+	.driver = {
+		.name = "wm8990",
+	},
+	.probe =    wm8990_i2c_probe,
+	.id_table = wm8990_i2c_id,
+};
+
+module_i2c_driver(wm8990_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8990 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h
new file mode 100644
index 0000000..0e9c780
--- /dev/null
+++ b/sound/soc/codecs/wm8990.h
@@ -0,0 +1,826 @@
+/*
+ * wm8990.h  --  audio driver for WM8990
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __WM8990REGISTERDEFS_H__
+#define __WM8990REGISTERDEFS_H__
+
+/*
+ * Register values.
+ */
+#define WM8990_RESET                            0x00
+#define WM8990_POWER_MANAGEMENT_1               0x01
+#define WM8990_POWER_MANAGEMENT_2               0x02
+#define WM8990_POWER_MANAGEMENT_3               0x03
+#define WM8990_AUDIO_INTERFACE_1                0x04
+#define WM8990_AUDIO_INTERFACE_2                0x05
+#define WM8990_CLOCKING_1                       0x06
+#define WM8990_CLOCKING_2                       0x07
+#define WM8990_AUDIO_INTERFACE_3                0x08
+#define WM8990_AUDIO_INTERFACE_4                0x09
+#define WM8990_DAC_CTRL                         0x0A
+#define WM8990_LEFT_DAC_DIGITAL_VOLUME          0x0B
+#define WM8990_RIGHT_DAC_DIGITAL_VOLUME         0x0C
+#define WM8990_DIGITAL_SIDE_TONE                0x0D
+#define WM8990_ADC_CTRL                         0x0E
+#define WM8990_LEFT_ADC_DIGITAL_VOLUME          0x0F
+#define WM8990_RIGHT_ADC_DIGITAL_VOLUME         0x10
+#define WM8990_GPIO_CTRL_1                      0x12
+#define WM8990_GPIO1_GPIO2                      0x13
+#define WM8990_GPIO3_GPIO4                      0x14
+#define WM8990_GPIO5_GPIO6                      0x15
+#define WM8990_GPIOCTRL_2                       0x16
+#define WM8990_GPIO_POL                         0x17
+#define WM8990_LEFT_LINE_INPUT_1_2_VOLUME       0x18
+#define WM8990_LEFT_LINE_INPUT_3_4_VOLUME       0x19
+#define WM8990_RIGHT_LINE_INPUT_1_2_VOLUME      0x1A
+#define WM8990_RIGHT_LINE_INPUT_3_4_VOLUME      0x1B
+#define WM8990_LEFT_OUTPUT_VOLUME               0x1C
+#define WM8990_RIGHT_OUTPUT_VOLUME              0x1D
+#define WM8990_LINE_OUTPUTS_VOLUME              0x1E
+#define WM8990_OUT3_4_VOLUME                    0x1F
+#define WM8990_LEFT_OPGA_VOLUME                 0x20
+#define WM8990_RIGHT_OPGA_VOLUME                0x21
+#define WM8990_SPEAKER_VOLUME                   0x22
+#define WM8990_CLASSD1                          0x23
+#define WM8990_CLASSD3                          0x25
+#define WM8990_CLASSD4                          0x26
+#define WM8990_INPUT_MIXER1                     0x27
+#define WM8990_INPUT_MIXER2                     0x28
+#define WM8990_INPUT_MIXER3                     0x29
+#define WM8990_INPUT_MIXER4                     0x2A
+#define WM8990_INPUT_MIXER5                     0x2B
+#define WM8990_INPUT_MIXER6                     0x2C
+#define WM8990_OUTPUT_MIXER1                    0x2D
+#define WM8990_OUTPUT_MIXER2                    0x2E
+#define WM8990_OUTPUT_MIXER3                    0x2F
+#define WM8990_OUTPUT_MIXER4                    0x30
+#define WM8990_OUTPUT_MIXER5                    0x31
+#define WM8990_OUTPUT_MIXER6                    0x32
+#define WM8990_OUT3_4_MIXER                     0x33
+#define WM8990_LINE_MIXER1                      0x34
+#define WM8990_LINE_MIXER2                      0x35
+#define WM8990_SPEAKER_MIXER                    0x36
+#define WM8990_ADDITIONAL_CONTROL               0x37
+#define WM8990_ANTIPOP1                         0x38
+#define WM8990_ANTIPOP2                         0x39
+#define WM8990_MICBIAS                          0x3A
+#define WM8990_PLL1                             0x3C
+#define WM8990_PLL2                             0x3D
+#define WM8990_PLL3                             0x3E
+
+#define WM8990_EXT_ACCESS_ENA			0x75
+#define WM8990_EXT_CTL1				0x7a
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Reset
+ */
+#define WM8990_SW_RESET_CHIP_ID_MASK            0xFFFF  /* SW_RESET_CHIP_ID */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM8990_SPK_ENA                          0x1000  /* SPK_ENA */
+#define WM8990_SPK_ENA_BIT			12
+#define WM8990_OUT3_ENA                         0x0800  /* OUT3_ENA */
+#define WM8990_OUT3_ENA_BIT			11
+#define WM8990_OUT4_ENA                         0x0400  /* OUT4_ENA */
+#define WM8990_OUT4_ENA_BIT			10
+#define WM8990_LOUT_ENA                         0x0200  /* LOUT_ENA */
+#define WM8990_LOUT_ENA_BIT			9
+#define WM8990_ROUT_ENA                         0x0100  /* ROUT_ENA */
+#define WM8990_ROUT_ENA_BIT			8
+#define WM8990_MICBIAS_ENA                      0x0010  /* MICBIAS_ENA */
+#define WM8990_MICBIAS_ENA_BIT			4
+#define WM8990_VMID_MODE_MASK                   0x0006  /* VMID_MODE - [2:1] */
+#define WM8990_VREF_ENA                         0x0001  /* VREF_ENA */
+#define WM8990_VREF_ENA_BIT			0
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM8990_PLL_ENA                          0x8000  /* PLL_ENA */
+#define WM8990_PLL_ENA_BIT			15
+#define WM8990_TSHUT_ENA                        0x4000  /* TSHUT_ENA */
+#define WM8990_TSHUT_ENA_BIT			14
+#define WM8990_TSHUT_OPDIS                      0x2000  /* TSHUT_OPDIS */
+#define WM8990_TSHUT_OPDIS_BIT			13
+#define WM8990_OPCLK_ENA                        0x0800  /* OPCLK_ENA */
+#define WM8990_OPCLK_ENA_BIT			11
+#define WM8990_AINL_ENA                         0x0200  /* AINL_ENA */
+#define WM8990_AINL_ENA_BIT			9
+#define WM8990_AINR_ENA                         0x0100  /* AINR_ENA */
+#define WM8990_AINR_ENA_BIT			8
+#define WM8990_LIN34_ENA                        0x0080  /* LIN34_ENA */
+#define WM8990_LIN34_ENA_BIT			7
+#define WM8990_LIN12_ENA                        0x0040  /* LIN12_ENA */
+#define WM8990_LIN12_ENA_BIT			6
+#define WM8990_RIN34_ENA                        0x0020  /* RIN34_ENA */
+#define WM8990_RIN34_ENA_BIT			5
+#define WM8990_RIN12_ENA                        0x0010  /* RIN12_ENA */
+#define WM8990_RIN12_ENA_BIT			4
+#define WM8990_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8990_ADCL_ENA_BIT			1
+#define WM8990_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8990_ADCR_ENA_BIT			0
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM8990_LON_ENA                          0x2000  /* LON_ENA */
+#define WM8990_LON_ENA_BIT			13
+#define WM8990_LOP_ENA                          0x1000  /* LOP_ENA */
+#define WM8990_LOP_ENA_BIT			12
+#define WM8990_RON_ENA                          0x0800  /* RON_ENA */
+#define WM8990_RON_ENA_BIT			11
+#define WM8990_ROP_ENA                          0x0400  /* ROP_ENA */
+#define WM8990_ROP_ENA_BIT			10
+#define WM8990_LOPGA_ENA                        0x0080  /* LOPGA_ENA */
+#define WM8990_LOPGA_ENA_BIT			7
+#define WM8990_ROPGA_ENA                        0x0040  /* ROPGA_ENA */
+#define WM8990_ROPGA_ENA_BIT			6
+#define WM8990_LOMIX_ENA                        0x0020  /* LOMIX_ENA */
+#define WM8990_LOMIX_ENA_BIT			5
+#define WM8990_ROMIX_ENA                        0x0010  /* ROMIX_ENA */
+#define WM8990_ROMIX_ENA_BIT			4
+#define WM8990_DACL_ENA                         0x0002  /* DACL_ENA */
+#define WM8990_DACL_ENA_BIT			1
+#define WM8990_DACR_ENA                         0x0001  /* DACR_ENA */
+#define WM8990_DACR_ENA_BIT			0
+
+/*
+ * R4 (0x04) - Audio Interface (1)
+ */
+#define WM8990_AIFADCL_SRC                      0x8000  /* AIFADCL_SRC */
+#define WM8990_AIFADCR_SRC                      0x4000  /* AIFADCR_SRC */
+#define WM8990_AIFADC_TDM                       0x2000  /* AIFADC_TDM */
+#define WM8990_AIFADC_TDM_CHAN                  0x1000  /* AIFADC_TDM_CHAN */
+#define WM8990_AIF_BCLK_INV                     0x0100  /* AIF_BCLK_INV */
+#define WM8990_AIF_LRCLK_INV                    0x0080  /* AIF_LRCLK_INV */
+#define WM8990_AIF_WL_MASK                      0x0060  /* AIF_WL - [6:5] */
+#define WM8990_AIF_WL_16BITS			(0 << 5)
+#define WM8990_AIF_WL_20BITS			(1 << 5)
+#define WM8990_AIF_WL_24BITS			(2 << 5)
+#define WM8990_AIF_WL_32BITS			(3 << 5)
+#define WM8990_AIF_FMT_MASK                     0x0018  /* AIF_FMT - [4:3] */
+#define WM8990_AIF_TMF_RIGHTJ			(0 << 3)
+#define WM8990_AIF_TMF_LEFTJ			(1 << 3)
+#define WM8990_AIF_TMF_I2S			(2 << 3)
+#define WM8990_AIF_TMF_DSP			(3 << 3)
+
+/*
+ * R5 (0x05) - Audio Interface (2)
+ */
+#define WM8990_DACL_SRC                         0x8000  /* DACL_SRC */
+#define WM8990_DACR_SRC                         0x4000  /* DACR_SRC */
+#define WM8990_AIFDAC_TDM                       0x2000  /* AIFDAC_TDM */
+#define WM8990_AIFDAC_TDM_CHAN                  0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8990_DAC_BOOST_MASK                   0x0C00  /* DAC_BOOST */
+#define WM8990_DAC_COMP                         0x0010  /* DAC_COMP */
+#define WM8990_DAC_COMPMODE                     0x0008  /* DAC_COMPMODE */
+#define WM8990_ADC_COMP                         0x0004  /* ADC_COMP */
+#define WM8990_ADC_COMPMODE                     0x0002  /* ADC_COMPMODE */
+#define WM8990_LOOPBACK                         0x0001  /* LOOPBACK */
+
+/*
+ * R6 (0x06) - Clocking (1)
+ */
+#define WM8990_TOCLK_RATE                       0x8000  /* TOCLK_RATE */
+#define WM8990_TOCLK_ENA                        0x4000  /* TOCLK_ENA */
+#define WM8990_OPCLKDIV_MASK                    0x1E00  /* OPCLKDIV - [12:9] */
+#define WM8990_DCLKDIV_MASK                     0x01C0  /* DCLKDIV - [8:6] */
+#define WM8990_BCLK_DIV_MASK                    0x001E  /* BCLK_DIV - [4:1] */
+#define WM8990_BCLK_DIV_1			(0x0 << 1)
+#define WM8990_BCLK_DIV_1_5			(0x1 << 1)
+#define WM8990_BCLK_DIV_2			(0x2 << 1)
+#define WM8990_BCLK_DIV_3			(0x3 << 1)
+#define WM8990_BCLK_DIV_4			(0x4 << 1)
+#define WM8990_BCLK_DIV_5_5			(0x5 << 1)
+#define WM8990_BCLK_DIV_6			(0x6 << 1)
+#define WM8990_BCLK_DIV_8			(0x7 << 1)
+#define WM8990_BCLK_DIV_11			(0x8 << 1)
+#define WM8990_BCLK_DIV_12			(0x9 << 1)
+#define WM8990_BCLK_DIV_16			(0xA << 1)
+#define WM8990_BCLK_DIV_22			(0xB << 1)
+#define WM8990_BCLK_DIV_24			(0xC << 1)
+#define WM8990_BCLK_DIV_32			(0xD << 1)
+#define WM8990_BCLK_DIV_44			(0xE << 1)
+#define WM8990_BCLK_DIV_48			(0xF << 1)
+
+/*
+ * R7 (0x07) - Clocking (2)
+ */
+#define WM8990_MCLK_SRC                         0x8000  /* MCLK_SRC */
+#define WM8990_SYSCLK_SRC                       0x4000  /* SYSCLK_SRC */
+#define WM8990_CLK_FORCE                        0x2000  /* CLK_FORCE */
+#define WM8990_MCLK_DIV_MASK                    0x1800  /* MCLK_DIV - [12:11] */
+#define WM8990_MCLK_DIV_1			(0 << 11)
+#define WM8990_MCLK_DIV_2			(2 << 11)
+#define WM8990_MCLK_INV                         0x0400  /* MCLK_INV */
+#define WM8990_ADC_CLKDIV_MASK                  0x00E0  /* ADC_CLKDIV */
+#define WM8990_ADC_CLKDIV_1			(0 << 5)
+#define WM8990_ADC_CLKDIV_1_5			(1 << 5)
+#define WM8990_ADC_CLKDIV_2			(2 << 5)
+#define WM8990_ADC_CLKDIV_3			(3 << 5)
+#define WM8990_ADC_CLKDIV_4			(4 << 5)
+#define WM8990_ADC_CLKDIV_5_5			(5 << 5)
+#define WM8990_ADC_CLKDIV_6			(6 << 5)
+#define WM8990_DAC_CLKDIV_MASK                  0x001C  /* DAC_CLKDIV - [4:2] */
+#define WM8990_DAC_CLKDIV_1			(0 << 2)
+#define WM8990_DAC_CLKDIV_1_5			(1 << 2)
+#define WM8990_DAC_CLKDIV_2			(2 << 2)
+#define WM8990_DAC_CLKDIV_3			(3 << 2)
+#define WM8990_DAC_CLKDIV_4			(4 << 2)
+#define WM8990_DAC_CLKDIV_5_5			(5 << 2)
+#define WM8990_DAC_CLKDIV_6			(6 << 2)
+
+/*
+ * R8 (0x08) - Audio Interface (3)
+ */
+#define WM8990_AIF_MSTR1                        0x8000  /* AIF_MSTR1 */
+#define WM8990_AIF_MSTR2                        0x4000  /* AIF_MSTR2 */
+#define WM8990_AIF_SEL                          0x2000  /* AIF_SEL */
+#define WM8990_ADCLRC_DIR                       0x0800  /* ADCLRC_DIR */
+#define WM8990_ADCLRC_RATE_MASK                 0x07FF  /* ADCLRC_RATE */
+
+/*
+ * R9 (0x09) - Audio Interface (4)
+ */
+#define WM8990_ALRCGPIO1                        0x8000  /* ALRCGPIO1 */
+#define WM8990_ALRCBGPIO6                       0x4000  /* ALRCBGPIO6 */
+#define WM8990_AIF_TRIS                         0x2000  /* AIF_TRIS */
+#define WM8990_DACLRC_DIR                       0x0800  /* DACLRC_DIR */
+#define WM8990_DACLRC_RATE_MASK                 0x07FF  /* DACLRC_RATE */
+
+/*
+ * R10 (0x0A) - DAC CTRL
+ */
+#define WM8990_AIF_LRCLKRATE                    0x0400  /* AIF_LRCLKRATE */
+#define WM8990_DAC_MONO                         0x0200  /* DAC_MONO */
+#define WM8990_DAC_SB_FILT                      0x0100  /* DAC_SB_FILT */
+#define WM8990_DAC_MUTERATE                     0x0080  /* DAC_MUTERATE */
+#define WM8990_DAC_MUTEMODE                     0x0040  /* DAC_MUTEMODE */
+#define WM8990_DEEMP_MASK                       0x0030  /* DEEMP - [5:4] */
+#define WM8990_DAC_MUTE                         0x0004  /* DAC_MUTE */
+#define WM8990_DACL_DATINV                      0x0002  /* DACL_DATINV */
+#define WM8990_DACR_DATINV                      0x0001  /* DACR_DATINV */
+
+/*
+ * R11 (0x0B) - Left DAC Digital Volume
+ */
+#define WM8990_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8990_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8990_DACL_VOL_SHIFT			0
+/*
+ * R12 (0x0C) - Right DAC Digital Volume
+ */
+#define WM8990_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8990_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8990_DACR_VOL_SHIFT			0
+/*
+ * R13 (0x0D) - Digital Side Tone
+ */
+#define WM8990_ADCL_DAC_SVOL_MASK               0x0F  /* ADCL_DAC_SVOL */
+#define WM8990_ADCL_DAC_SVOL_SHIFT		9
+#define WM8990_ADCR_DAC_SVOL_MASK               0x0F  /* ADCR_DAC_SVOL */
+#define WM8990_ADCR_DAC_SVOL_SHIFT		5
+#define WM8990_ADC_TO_DACL_MASK                 0x03  /* ADC_TO_DACL - [3:2] */
+#define WM8990_ADC_TO_DACL_SHIFT		2
+#define WM8990_ADC_TO_DACR_MASK                 0x03  /* ADC_TO_DACR - [1:0] */
+#define WM8990_ADC_TO_DACR_SHIFT		0
+
+/*
+ * R14 (0x0E) - ADC CTRL
+ */
+#define WM8990_ADC_HPF_ENA                      0x0100  /* ADC_HPF_ENA */
+#define WM8990_ADC_HPF_ENA_BIT			8
+#define WM8990_ADC_HPF_CUT_MASK                 0x03  /* ADC_HPF_CUT - [6:5] */
+#define WM8990_ADC_HPF_CUT_SHIFT		5
+#define WM8990_ADCL_DATINV                      0x0002  /* ADCL_DATINV */
+#define WM8990_ADCL_DATINV_BIT			1
+#define WM8990_ADCR_DATINV                      0x0001  /* ADCR_DATINV */
+#define WM8990_ADCR_DATINV_BIT			0
+
+/*
+ * R15 (0x0F) - Left ADC Digital Volume
+ */
+#define WM8990_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8990_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8990_ADCL_VOL_SHIFT			0
+
+/*
+ * R16 (0x10) - Right ADC Digital Volume
+ */
+#define WM8990_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8990_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8990_ADCR_VOL_SHIFT			0
+
+/*
+ * R18 (0x12) - GPIO CTRL 1
+ */
+#define WM8990_IRQ                              0x1000  /* IRQ */
+#define WM8990_TEMPOK                           0x0800  /* TEMPOK */
+#define WM8990_MICSHRT                          0x0400  /* MICSHRT */
+#define WM8990_MICDET                           0x0200  /* MICDET */
+#define WM8990_PLL_LCK                          0x0100  /* PLL_LCK */
+#define WM8990_GPI8_STATUS                      0x0080  /* GPI8_STATUS */
+#define WM8990_GPI7_STATUS                      0x0040  /* GPI7_STATUS */
+#define WM8990_GPIO6_STATUS                     0x0020  /* GPIO6_STATUS */
+#define WM8990_GPIO5_STATUS                     0x0010  /* GPIO5_STATUS */
+#define WM8990_GPIO4_STATUS                     0x0008  /* GPIO4_STATUS */
+#define WM8990_GPIO3_STATUS                     0x0004  /* GPIO3_STATUS */
+#define WM8990_GPIO2_STATUS                     0x0002  /* GPIO2_STATUS */
+#define WM8990_GPIO1_STATUS                     0x0001  /* GPIO1_STATUS */
+
+/*
+ * R19 (0x13) - GPIO1 & GPIO2
+ */
+#define WM8990_GPIO2_DEB_ENA                    0x8000  /* GPIO2_DEB_ENA */
+#define WM8990_GPIO2_IRQ_ENA                    0x4000  /* GPIO2_IRQ_ENA */
+#define WM8990_GPIO2_PU                         0x2000  /* GPIO2_PU */
+#define WM8990_GPIO2_PD                         0x1000  /* GPIO2_PD */
+#define WM8990_GPIO2_SEL_MASK                   0x0F00  /* GPIO2_SEL - [11:8] */
+#define WM8990_GPIO1_DEB_ENA                    0x0080  /* GPIO1_DEB_ENA */
+#define WM8990_GPIO1_IRQ_ENA                    0x0040  /* GPIO1_IRQ_ENA */
+#define WM8990_GPIO1_PU                         0x0020  /* GPIO1_PU */
+#define WM8990_GPIO1_PD                         0x0010  /* GPIO1_PD */
+#define WM8990_GPIO1_SEL_MASK                   0x000F  /* GPIO1_SEL - [3:0] */
+
+/*
+ * R20 (0x14) - GPIO3 & GPIO4
+ */
+#define WM8990_GPIO4_DEB_ENA                    0x8000  /* GPIO4_DEB_ENA */
+#define WM8990_GPIO4_IRQ_ENA                    0x4000  /* GPIO4_IRQ_ENA */
+#define WM8990_GPIO4_PU                         0x2000  /* GPIO4_PU */
+#define WM8990_GPIO4_PD                         0x1000  /* GPIO4_PD */
+#define WM8990_GPIO4_SEL_MASK                   0x0F00  /* GPIO4_SEL - [11:8] */
+#define WM8990_GPIO3_DEB_ENA                    0x0080  /* GPIO3_DEB_ENA */
+#define WM8990_GPIO3_IRQ_ENA                    0x0040  /* GPIO3_IRQ_ENA */
+#define WM8990_GPIO3_PU                         0x0020  /* GPIO3_PU */
+#define WM8990_GPIO3_PD                         0x0010  /* GPIO3_PD */
+#define WM8990_GPIO3_SEL_MASK                   0x000F  /* GPIO3_SEL - [3:0] */
+
+/*
+ * R21 (0x15) - GPIO5 & GPIO6
+ */
+#define WM8990_GPIO6_DEB_ENA                    0x8000  /* GPIO6_DEB_ENA */
+#define WM8990_GPIO6_IRQ_ENA                    0x4000  /* GPIO6_IRQ_ENA */
+#define WM8990_GPIO6_PU                         0x2000  /* GPIO6_PU */
+#define WM8990_GPIO6_PD                         0x1000  /* GPIO6_PD */
+#define WM8990_GPIO6_SEL_MASK                   0x0F00  /* GPIO6_SEL - [11:8] */
+#define WM8990_GPIO5_DEB_ENA                    0x0080  /* GPIO5_DEB_ENA */
+#define WM8990_GPIO5_IRQ_ENA                    0x0040  /* GPIO5_IRQ_ENA */
+#define WM8990_GPIO5_PU                         0x0020  /* GPIO5_PU */
+#define WM8990_GPIO5_PD                         0x0010  /* GPIO5_PD */
+#define WM8990_GPIO5_SEL_MASK                   0x000F  /* GPIO5_SEL - [3:0] */
+
+/*
+ * R22 (0x16) - GPIOCTRL 2
+ */
+#define WM8990_RD_3W_ENA                        0x8000  /* RD_3W_ENA */
+#define WM8990_MODE_3W4W                        0x4000  /* MODE_3W4W */
+#define WM8990_TEMPOK_IRQ_ENA                   0x0800  /* TEMPOK_IRQ_ENA */
+#define WM8990_MICSHRT_IRQ_ENA                  0x0400  /* MICSHRT_IRQ_ENA */
+#define WM8990_MICDET_IRQ_ENA                   0x0200  /* MICDET_IRQ_ENA */
+#define WM8990_PLL_LCK_IRQ_ENA                  0x0100  /* PLL_LCK_IRQ_ENA */
+#define WM8990_GPI8_DEB_ENA                     0x0080  /* GPI8_DEB_ENA */
+#define WM8990_GPI8_IRQ_ENA                     0x0040  /* GPI8_IRQ_ENA */
+#define WM8990_GPI8_ENA                         0x0010  /* GPI8_ENA */
+#define WM8990_GPI7_DEB_ENA                     0x0008  /* GPI7_DEB_ENA */
+#define WM8990_GPI7_IRQ_ENA                     0x0004  /* GPI7_IRQ_ENA */
+#define WM8990_GPI7_ENA                         0x0001  /* GPI7_ENA */
+
+/*
+ * R23 (0x17) - GPIO_POL
+ */
+#define WM8990_IRQ_INV                          0x1000  /* IRQ_INV */
+#define WM8990_TEMPOK_POL                       0x0800  /* TEMPOK_POL */
+#define WM8990_MICSHRT_POL                      0x0400  /* MICSHRT_POL */
+#define WM8990_MICDET_POL                       0x0200  /* MICDET_POL */
+#define WM8990_PLL_LCK_POL                      0x0100  /* PLL_LCK_POL */
+#define WM8990_GPI8_POL                         0x0080  /* GPI8_POL */
+#define WM8990_GPI7_POL                         0x0040  /* GPI7_POL */
+#define WM8990_GPIO6_POL                        0x0020  /* GPIO6_POL */
+#define WM8990_GPIO5_POL                        0x0010  /* GPIO5_POL */
+#define WM8990_GPIO4_POL                        0x0008  /* GPIO4_POL */
+#define WM8990_GPIO3_POL                        0x0004  /* GPIO3_POL */
+#define WM8990_GPIO2_POL                        0x0002  /* GPIO2_POL */
+#define WM8990_GPIO1_POL                        0x0001  /* GPIO1_POL */
+
+/*
+ * R24 (0x18) - Left Line Input 1&2 Volume
+ */
+#define WM8990_IPVU                             0x0100  /* IPVU */
+#define WM8990_LI12MUTE                         0x0080  /* LI12MUTE */
+#define WM8990_LI12MUTE_BIT			7
+#define WM8990_LI12ZC                           0x0040  /* LI12ZC */
+#define WM8990_LI12ZC_BIT			6
+#define WM8990_LIN12VOL_MASK                    0x001F  /* LIN12VOL - [4:0] */
+#define WM8990_LIN12VOL_SHIFT			0
+/*
+ * R25 (0x19) - Left Line Input 3&4 Volume
+ */
+#define WM8990_IPVU                             0x0100  /* IPVU */
+#define WM8990_LI34MUTE                         0x0080  /* LI34MUTE */
+#define WM8990_LI34MUTE_BIT			7
+#define WM8990_LI34ZC                           0x0040  /* LI34ZC */
+#define WM8990_LI34ZC_BIT			6
+#define WM8990_LIN34VOL_MASK                    0x001F  /* LIN34VOL - [4:0] */
+#define WM8990_LIN34VOL_SHIFT			0
+
+/*
+ * R26 (0x1A) - Right Line Input 1&2 Volume
+ */
+#define WM8990_IPVU                             0x0100  /* IPVU */
+#define WM8990_RI12MUTE                         0x0080  /* RI12MUTE */
+#define WM8990_RI12MUTE_BIT			7
+#define WM8990_RI12ZC                           0x0040  /* RI12ZC */
+#define WM8990_RI12ZC_BIT			6
+#define WM8990_RIN12VOL_MASK                    0x001F  /* RIN12VOL - [4:0] */
+#define WM8990_RIN12VOL_SHIFT			0
+
+/*
+ * R27 (0x1B) - Right Line Input 3&4 Volume
+ */
+#define WM8990_IPVU                             0x0100  /* IPVU */
+#define WM8990_RI34MUTE                         0x0080  /* RI34MUTE */
+#define WM8990_RI34MUTE_BIT			7
+#define WM8990_RI34ZC                           0x0040  /* RI34ZC */
+#define WM8990_RI34ZC_BIT			6
+#define WM8990_RIN34VOL_MASK                    0x001F  /* RIN34VOL - [4:0] */
+#define WM8990_RIN34VOL_SHIFT			0
+
+/*
+ * R28 (0x1C) - Left Output Volume
+ */
+#define WM8990_OPVU                             0x0100  /* OPVU */
+#define WM8990_LOZC                             0x0080  /* LOZC */
+#define WM8990_LOZC_BIT				7
+#define WM8990_LOUTVOL_MASK                     0x007F  /* LOUTVOL - [6:0] */
+#define WM8990_LOUTVOL_SHIFT			0
+/*
+ * R29 (0x1D) - Right Output Volume
+ */
+#define WM8990_OPVU                             0x0100  /* OPVU */
+#define WM8990_ROZC                             0x0080  /* ROZC */
+#define WM8990_ROZC_BIT				7
+#define WM8990_ROUTVOL_MASK                     0x007F  /* ROUTVOL - [6:0] */
+#define WM8990_ROUTVOL_SHIFT			0
+/*
+ * R30 (0x1E) - Line Outputs Volume
+ */
+#define WM8990_LONMUTE                          0x0040  /* LONMUTE */
+#define WM8990_LONMUTE_BIT			6
+#define WM8990_LOPMUTE                          0x0020  /* LOPMUTE */
+#define WM8990_LOPMUTE_BIT			5
+#define WM8990_LOATTN                           0x0010  /* LOATTN */
+#define WM8990_LOATTN_BIT			4
+#define WM8990_RONMUTE                          0x0004  /* RONMUTE */
+#define WM8990_RONMUTE_BIT			2
+#define WM8990_ROPMUTE                          0x0002  /* ROPMUTE */
+#define WM8990_ROPMUTE_BIT			1
+#define WM8990_ROATTN                           0x0001  /* ROATTN */
+#define WM8990_ROATTN_BIT			0
+
+/*
+ * R31 (0x1F) - Out3/4 Volume
+ */
+#define WM8990_OUT3MUTE                         0x0020  /* OUT3MUTE */
+#define WM8990_OUT3MUTE_BIT			5
+#define WM8990_OUT3ATTN                         0x0010  /* OUT3ATTN */
+#define WM8990_OUT3ATTN_BIT			4
+#define WM8990_OUT4MUTE                         0x0002  /* OUT4MUTE */
+#define WM8990_OUT4MUTE_BIT			1
+#define WM8990_OUT4ATTN                         0x0001  /* OUT4ATTN */
+#define WM8990_OUT4ATTN_BIT			0
+
+/*
+ * R32 (0x20) - Left OPGA Volume
+ */
+#define WM8990_OPVU                             0x0100  /* OPVU */
+#define WM8990_LOPGAZC                          0x0080  /* LOPGAZC */
+#define WM8990_LOPGAZC_BIT			7
+#define WM8990_LOPGAVOL_MASK                    0x007F  /* LOPGAVOL - [6:0] */
+#define WM8990_LOPGAVOL_SHIFT			0
+
+/*
+ * R33 (0x21) - Right OPGA Volume
+ */
+#define WM8990_OPVU                             0x0100  /* OPVU */
+#define WM8990_ROPGAZC                          0x0080  /* ROPGAZC */
+#define WM8990_ROPGAZC_BIT			7
+#define WM8990_ROPGAVOL_MASK                    0x007F  /* ROPGAVOL - [6:0] */
+#define WM8990_ROPGAVOL_SHIFT			0
+/*
+ * R34 (0x22) - Speaker Volume
+ */
+#define WM8990_SPKATTN_MASK                      0x0003  /* SPKATTN - [1:0] */
+#define WM8990_SPKATTN_SHIFT			 0
+
+/*
+ * R35 (0x23) - ClassD1
+ */
+#define WM8990_CDMODE                           0x0100  /* CDMODE */
+#define WM8990_CDMODE_BIT			8
+
+/*
+ * R37 (0x25) - ClassD3
+ */
+#define WM8990_DCGAIN_MASK                      0x0007  /* DCGAIN - [5:3] */
+#define WM8990_DCGAIN_SHIFT			3
+#define WM8990_ACGAIN_MASK                      0x0007  /* ACGAIN - [2:0] */
+#define WM8990_ACGAIN_SHIFT			0
+
+/*
+ * R38 (0x26) - ClassD4
+ */
+#define WM8990_SPKZC_MASK                       0x0001  /* SPKZC */
+#define WM8990_SPKZC_SHIFT                           7  /* SPKZC */
+#define WM8990_SPKVOL_MASK                      0x007F  /* SPKVOL - [6:0] */
+#define WM8990_SPKVOL_SHIFT                          0  /* SPKVOL - [6:0] */
+
+/*
+ * R39 (0x27) - Input Mixer1
+ */
+#define WM8990_AINLMODE_MASK                    0x000C  /* AINLMODE - [3:2] */
+#define WM8990_AINLMODE_SHIFT			2
+#define WM8990_AINRMODE_MASK                    0x0003  /* AINRMODE - [1:0] */
+#define WM8990_AINRMODE_SHIFT			0
+
+/*
+ * R40 (0x28) - Input Mixer2
+ */
+#define WM8990_LMP4				0x0080	/* LMP4 */
+#define WM8990_LMP4_BIT                         7	/* LMP4 */
+#define WM8990_LMN3                             0x0040  /* LMN3 */
+#define WM8990_LMN3_BIT                         6       /* LMN3 */
+#define WM8990_LMP2                             0x0020  /* LMP2 */
+#define WM8990_LMP2_BIT                         5       /* LMP2 */
+#define WM8990_LMN1                             0x0010  /* LMN1 */
+#define WM8990_LMN1_BIT                         4       /* LMN1 */
+#define WM8990_RMP4                             0x0008  /* RMP4 */
+#define WM8990_RMP4_BIT                         3       /* RMP4 */
+#define WM8990_RMN3                             0x0004  /* RMN3 */
+#define WM8990_RMN3_BIT                         2       /* RMN3 */
+#define WM8990_RMP2                             0x0002  /* RMP2 */
+#define WM8990_RMP2_BIT                         1       /* RMP2 */
+#define WM8990_RMN1                             0x0001  /* RMN1 */
+#define WM8990_RMN1_BIT                         0       /* RMN1 */
+
+/*
+ * R41 (0x29) - Input Mixer3
+ */
+#define WM8990_L34MNB                           0x0100  /* L34MNB */
+#define WM8990_L34MNB_BIT			8
+#define WM8990_L34MNBST                         0x0080  /* L34MNBST */
+#define WM8990_L34MNBST_BIT			7
+#define WM8990_L12MNB                           0x0020  /* L12MNB */
+#define WM8990_L12MNB_BIT			5
+#define WM8990_L12MNBST                         0x0010  /* L12MNBST */
+#define WM8990_L12MNBST_BIT			4
+#define WM8990_LDBVOL_MASK                      0x0007  /* LDBVOL - [2:0] */
+#define WM8990_LDBVOL_SHIFT			0
+
+/*
+ * R42 (0x2A) - Input Mixer4
+ */
+#define WM8990_R34MNB                           0x0100  /* R34MNB */
+#define WM8990_R34MNB_BIT			8
+#define WM8990_R34MNBST                         0x0080  /* R34MNBST */
+#define WM8990_R34MNBST_BIT			7
+#define WM8990_R12MNB                           0x0020  /* R12MNB */
+#define WM8990_R12MNB_BIT			5
+#define WM8990_R12MNBST                         0x0010  /* R12MNBST */
+#define WM8990_R12MNBST_BIT			4
+#define WM8990_RDBVOL_MASK                      0x0007  /* RDBVOL - [2:0] */
+#define WM8990_RDBVOL_SHIFT			0
+
+/*
+ * R43 (0x2B) - Input Mixer5
+ */
+#define WM8990_LI2BVOL_MASK                     0x07  /* LI2BVOL - [8:6] */
+#define WM8990_LI2BVOL_SHIFT			6
+#define WM8990_LR4BVOL_MASK                     0x07  /* LR4BVOL - [5:3] */
+#define WM8990_LR4BVOL_SHIFT			3
+#define WM8990_LL4BVOL_MASK                     0x07  /* LL4BVOL - [2:0] */
+#define WM8990_LL4BVOL_SHIFT			0
+
+/*
+ * R44 (0x2C) - Input Mixer6
+ */
+#define WM8990_RI2BVOL_MASK                     0x07  /* RI2BVOL - [8:6] */
+#define WM8990_RI2BVOL_SHIFT			6
+#define WM8990_RL4BVOL_MASK                     0x07  /* RL4BVOL - [5:3] */
+#define WM8990_RL4BVOL_SHIFT			3
+#define WM8990_RR4BVOL_MASK                     0x07  /* RR4BVOL - [2:0] */
+#define WM8990_RR4BVOL_SHIFT			0
+
+/*
+ * R45 (0x2D) - Output Mixer1
+ */
+#define WM8990_LRBLO                            0x0080  /* LRBLO */
+#define WM8990_LRBLO_BIT			7
+#define WM8990_LLBLO                            0x0040  /* LLBLO */
+#define WM8990_LLBLO_BIT			6
+#define WM8990_LRI3LO                           0x0020  /* LRI3LO */
+#define WM8990_LRI3LO_BIT			5
+#define WM8990_LLI3LO                           0x0010  /* LLI3LO */
+#define WM8990_LLI3LO_BIT			4
+#define WM8990_LR12LO                           0x0008  /* LR12LO */
+#define WM8990_LR12LO_BIT			3
+#define WM8990_LL12LO                           0x0004  /* LL12LO */
+#define WM8990_LL12LO_BIT			2
+#define WM8990_LDLO                             0x0001  /* LDLO */
+#define WM8990_LDLO_BIT				0
+
+/*
+ * R46 (0x2E) - Output Mixer2
+ */
+#define WM8990_RLBRO                            0x0080  /* RLBRO */
+#define WM8990_RLBRO_BIT			7
+#define WM8990_RRBRO                            0x0040  /* RRBRO */
+#define WM8990_RRBRO_BIT			6
+#define WM8990_RLI3RO                           0x0020  /* RLI3RO */
+#define WM8990_RLI3RO_BIT			5
+#define WM8990_RRI3RO                           0x0010  /* RRI3RO */
+#define WM8990_RRI3RO_BIT			4
+#define WM8990_RL12RO                           0x0008  /* RL12RO */
+#define WM8990_RL12RO_BIT			3
+#define WM8990_RR12RO                           0x0004  /* RR12RO */
+#define WM8990_RR12RO_BIT			2
+#define WM8990_RDRO                             0x0001  /* RDRO */
+#define WM8990_RDRO_BIT				0
+
+/*
+ * R47 (0x2F) - Output Mixer3
+ */
+#define WM8990_LLI3LOVOL_MASK                   0x07  /* LLI3LOVOL - [8:6] */
+#define WM8990_LLI3LOVOL_SHIFT			6
+#define WM8990_LR12LOVOL_MASK                   0x07  /* LR12LOVOL - [5:3] */
+#define WM8990_LR12LOVOL_SHIFT			3
+#define WM8990_LL12LOVOL_MASK                   0x07  /* LL12LOVOL - [2:0] */
+#define WM8990_LL12LOVOL_SHIFT			0
+
+/*
+ * R48 (0x30) - Output Mixer4
+ */
+#define WM8990_RRI3ROVOL_MASK                   0x07  /* RRI3ROVOL - [8:6] */
+#define WM8990_RRI3ROVOL_SHIFT			6
+#define WM8990_RL12ROVOL_MASK                   0x07  /* RL12ROVOL - [5:3] */
+#define WM8990_RL12ROVOL_SHIFT			3
+#define WM8990_RR12ROVOL_MASK                   0x07  /* RR12ROVOL - [2:0] */
+#define WM8990_RR12ROVOL_SHIFT			0
+
+/*
+ * R49 (0x31) - Output Mixer5
+ */
+#define WM8990_LRI3LOVOL_MASK                   0x07  /* LRI3LOVOL - [8:6] */
+#define WM8990_LRI3LOVOL_SHIFT			6
+#define WM8990_LRBLOVOL_MASK                    0x07  /* LRBLOVOL - [5:3] */
+#define WM8990_LRBLOVOL_SHIFT			3
+#define WM8990_LLBLOVOL_MASK                    0x07  /* LLBLOVOL - [2:0] */
+#define WM8990_LLBLOVOL_SHIFT			0
+
+/*
+ * R50 (0x32) - Output Mixer6
+ */
+#define WM8990_RLI3ROVOL_MASK                   0x07  /* RLI3ROVOL - [8:6] */
+#define WM8990_RLI3ROVOL_SHIFT			6
+#define WM8990_RLBROVOL_MASK                    0x07  /* RLBROVOL - [5:3] */
+#define WM8990_RLBROVOL_SHIFT			3
+#define WM8990_RRBROVOL_MASK                    0x07  /* RRBROVOL - [2:0] */
+#define WM8990_RRBROVOL_SHIFT			0
+
+/*
+ * R51 (0x33) - Out3/4 Mixer
+ */
+#define WM8990_VSEL_MASK                        0x0180  /* VSEL - [8:7] */
+#define WM8990_LI4O3                            0x0020  /* LI4O3 */
+#define WM8990_LI4O3_BIT			5
+#define WM8990_LPGAO3                           0x0010  /* LPGAO3 */
+#define WM8990_LPGAO3_BIT			4
+#define WM8990_RI4O4                            0x0002  /* RI4O4 */
+#define WM8990_RI4O4_BIT			1
+#define WM8990_RPGAO4                           0x0001  /* RPGAO4 */
+#define WM8990_RPGAO4_BIT			0
+/*
+ * R52 (0x34) - Line Mixer1
+ */
+#define WM8990_LLOPGALON                        0x0040  /* LLOPGALON */
+#define WM8990_LLOPGALON_BIT			6
+#define WM8990_LROPGALON                        0x0020  /* LROPGALON */
+#define WM8990_LROPGALON_BIT			5
+#define WM8990_LOPLON                           0x0010  /* LOPLON */
+#define WM8990_LOPLON_BIT			4
+#define WM8990_LR12LOP                          0x0004  /* LR12LOP */
+#define WM8990_LR12LOP_BIT			2
+#define WM8990_LL12LOP                          0x0002  /* LL12LOP */
+#define WM8990_LL12LOP_BIT			1
+#define WM8990_LLOPGALOP                        0x0001  /* LLOPGALOP */
+#define WM8990_LLOPGALOP_BIT			0
+/*
+ * R53 (0x35) - Line Mixer2
+ */
+#define WM8990_RROPGARON                        0x0040  /* RROPGARON */
+#define WM8990_RROPGARON_BIT			6
+#define WM8990_RLOPGARON                        0x0020  /* RLOPGARON */
+#define WM8990_RLOPGARON_BIT			5
+#define WM8990_ROPRON                           0x0010  /* ROPRON */
+#define WM8990_ROPRON_BIT			4
+#define WM8990_RL12ROP                          0x0004  /* RL12ROP */
+#define WM8990_RL12ROP_BIT			2
+#define WM8990_RR12ROP                          0x0002  /* RR12ROP */
+#define WM8990_RR12ROP_BIT			1
+#define WM8990_RROPGAROP                        0x0001  /* RROPGAROP */
+#define WM8990_RROPGAROP_BIT			0
+
+/*
+ * R54 (0x36) - Speaker Mixer
+ */
+#define WM8990_LB2SPK                           0x0080  /* LB2SPK */
+#define WM8990_LB2SPK_BIT			7
+#define WM8990_RB2SPK                           0x0040  /* RB2SPK */
+#define WM8990_RB2SPK_BIT			6
+#define WM8990_LI2SPK                           0x0020  /* LI2SPK */
+#define WM8990_LI2SPK_BIT			5
+#define WM8990_RI2SPK                           0x0010  /* RI2SPK */
+#define WM8990_RI2SPK_BIT			4
+#define WM8990_LOPGASPK                         0x0008  /* LOPGASPK */
+#define WM8990_LOPGASPK_BIT			3
+#define WM8990_ROPGASPK                         0x0004  /* ROPGASPK */
+#define WM8990_ROPGASPK_BIT			2
+#define WM8990_LDSPK                            0x0002  /* LDSPK */
+#define WM8990_LDSPK_BIT			1
+#define WM8990_RDSPK                            0x0001  /* RDSPK */
+#define WM8990_RDSPK_BIT			0
+
+/*
+ * R55 (0x37) - Additional Control
+ */
+#define WM8990_VROI                             0x0001  /* VROI */
+
+/*
+ * R56 (0x38) - AntiPOP1
+ */
+#define WM8990_DIS_LLINE                        0x0020  /* DIS_LLINE */
+#define WM8990_DIS_RLINE                        0x0010  /* DIS_RLINE */
+#define WM8990_DIS_OUT3                         0x0008  /* DIS_OUT3 */
+#define WM8990_DIS_OUT4                         0x0004  /* DIS_OUT4 */
+#define WM8990_DIS_LOUT                         0x0002  /* DIS_LOUT */
+#define WM8990_DIS_ROUT                         0x0001  /* DIS_ROUT */
+
+/*
+ * R57 (0x39) - AntiPOP2
+ */
+#define WM8990_SOFTST                           0x0040  /* SOFTST */
+#define WM8990_BUFIOEN                          0x0008  /* BUFIOEN */
+#define WM8990_BUFDCOPEN                        0x0004  /* BUFDCOPEN */
+#define WM8990_POBCTRL                          0x0002  /* POBCTRL */
+#define WM8990_VMIDTOG                          0x0001  /* VMIDTOG */
+
+/*
+ * R58 (0x3A) - MICBIAS
+ */
+#define WM8990_MCDSCTH_MASK                     0x00C0  /* MCDSCTH - [7:6] */
+#define WM8990_MCDTHR_MASK                      0x0038  /* MCDTHR - [5:3] */
+#define WM8990_MCD                              0x0004  /* MCD */
+#define WM8990_MBSEL                            0x0001  /* MBSEL */
+
+/*
+ * R60 (0x3C) - PLL1
+ */
+#define WM8990_SDM                              0x0080  /* SDM */
+#define WM8990_PRESCALE                         0x0040  /* PRESCALE */
+#define WM8990_PLLN_MASK                        0x000F  /* PLLN - [3:0] */
+
+/*
+ * R61 (0x3D) - PLL2
+ */
+#define WM8990_PLLK1_MASK                       0x00FF  /* PLLK1 - [7:0] */
+
+/*
+ * R62 (0x3E) - PLL3
+ */
+#define WM8990_PLLK2_MASK                       0x00FF  /* PLLK2 - [7:0] */
+
+#define WM8990_MCLK_DIV 0
+#define WM8990_DACCLK_DIV 1
+#define WM8990_ADCCLK_DIV 2
+#define WM8990_BCLK_DIV 3
+
+#endif	/* __WM8990REGISTERDEFS_H__ */
+/*------------------------------ END OF FILE ---------------------------------*/
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
new file mode 100644
index 0000000..76a639d
--- /dev/null
+++ b/sound/soc/codecs/wm8991.c
@@ -0,0 +1,1347 @@
+/*
+ * wm8991.c  --  WM8991 ALSA Soc Audio driver
+ *
+ * Copyright 2007-2010 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         Graeme.Gregory@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+
+#include "wm8991.h"
+
+struct wm8991_priv {
+	struct regmap *regmap;
+	unsigned int pcmclk;
+};
+
+static const struct reg_default wm8991_reg_defaults[] = {
+	{  1, 0x0000 },     /* R1  - Power Management (1) */
+	{  2, 0x6000 },     /* R2  - Power Management (2) */
+	{  3, 0x0000 },     /* R3  - Power Management (3) */
+	{  4, 0x4050 },     /* R4  - Audio Interface (1) */
+	{  5, 0x4000 },     /* R5  - Audio Interface (2) */
+	{  6, 0x01C8 },     /* R6  - Clocking (1) */
+	{  7, 0x0000 },     /* R7  - Clocking (2) */
+	{  8, 0x0040 },     /* R8  - Audio Interface (3) */
+	{  9, 0x0040 },     /* R9  - Audio Interface (4) */
+	{ 10, 0x0004 },     /* R10 - DAC CTRL */
+	{ 11, 0x00C0 },     /* R11 - Left DAC Digital Volume */
+	{ 12, 0x00C0 },     /* R12 - Right DAC Digital Volume */
+	{ 13, 0x0000 },     /* R13 - Digital Side Tone */
+	{ 14, 0x0100 },     /* R14 - ADC CTRL */
+	{ 15, 0x00C0 },     /* R15 - Left ADC Digital Volume */
+	{ 16, 0x00C0 },     /* R16 - Right ADC Digital Volume */
+
+	{ 18, 0x0000 },     /* R18 - GPIO CTRL 1 */
+	{ 19, 0x1000 },     /* R19 - GPIO1 & GPIO2 */
+	{ 20, 0x1010 },     /* R20 - GPIO3 & GPIO4 */
+	{ 21, 0x1010 },     /* R21 - GPIO5 & GPIO6 */
+	{ 22, 0x8000 },     /* R22 - GPIOCTRL 2 */
+	{ 23, 0x0800 },     /* R23 - GPIO_POL */
+	{ 24, 0x008B },     /* R24 - Left Line Input 1&2 Volume */
+	{ 25, 0x008B },     /* R25 - Left Line Input 3&4 Volume */
+	{ 26, 0x008B },     /* R26 - Right Line Input 1&2 Volume */
+	{ 27, 0x008B },     /* R27 - Right Line Input 3&4 Volume */
+	{ 28, 0x0000 },     /* R28 - Left Output Volume */
+	{ 29, 0x0000 },     /* R29 - Right Output Volume */
+	{ 30, 0x0066 },     /* R30 - Line Outputs Volume */
+	{ 31, 0x0022 },     /* R31 - Out3/4 Volume */
+	{ 32, 0x0079 },     /* R32 - Left OPGA Volume */
+	{ 33, 0x0079 },     /* R33 - Right OPGA Volume */
+	{ 34, 0x0003 },     /* R34 - Speaker Volume */
+	{ 35, 0x0003 },     /* R35 - ClassD1 */
+
+	{ 37, 0x0100 },     /* R37 - ClassD3 */
+
+	{ 39, 0x0000 },     /* R39 - Input Mixer1 */
+	{ 40, 0x0000 },     /* R40 - Input Mixer2 */
+	{ 41, 0x0000 },     /* R41 - Input Mixer3 */
+	{ 42, 0x0000 },     /* R42 - Input Mixer4 */
+	{ 43, 0x0000 },     /* R43 - Input Mixer5 */
+	{ 44, 0x0000 },     /* R44 - Input Mixer6 */
+	{ 45, 0x0000 },     /* R45 - Output Mixer1 */
+	{ 46, 0x0000 },     /* R46 - Output Mixer2 */
+	{ 47, 0x0000 },     /* R47 - Output Mixer3 */
+	{ 48, 0x0000 },     /* R48 - Output Mixer4 */
+	{ 49, 0x0000 },     /* R49 - Output Mixer5 */
+	{ 50, 0x0000 },     /* R50 - Output Mixer6 */
+	{ 51, 0x0180 },     /* R51 - Out3/4 Mixer */
+	{ 52, 0x0000 },     /* R52 - Line Mixer1 */
+	{ 53, 0x0000 },     /* R53 - Line Mixer2 */
+	{ 54, 0x0000 },     /* R54 - Speaker Mixer */
+	{ 55, 0x0000 },     /* R55 - Additional Control */
+	{ 56, 0x0000 },     /* R56 - AntiPOP1 */
+	{ 57, 0x0000 },     /* R57 - AntiPOP2 */
+	{ 58, 0x0000 },     /* R58 - MICBIAS */
+
+	{ 60, 0x0008 },     /* R60 - PLL1 */
+	{ 61, 0x0031 },     /* R61 - PLL2 */
+	{ 62, 0x0026 },     /* R62 - PLL3 */
+};
+
+static bool wm8991_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8991_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(in_pga_tlv, -1650, 150, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(out_mix_tlv, -2100, 300, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(out_pga_tlv,
+	0x00, 0x2f, SNDRV_CTL_TLVD_DB_SCALE_ITEM(SNDRV_CTL_TLVD_DB_GAIN_MUTE, 0, 1),
+	0x30, 0x7f, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-7300, 100, 0),
+);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(out_dac_tlv,
+	0x00, 0xbf, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-71625, 375, 1),
+	0xc0, 0xff, SNDRV_CTL_TLVD_DB_SCALE_ITEM(0, 0, 0),
+);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(in_adc_tlv,
+	0x00, 0xef, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-71625, 375, 1),
+	0xf0, 0xff, SNDRV_CTL_TLVD_DB_SCALE_ITEM(17625, 0, 0),
+);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(out_sidetone_tlv,
+	0x00, 0x0c, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-3600, 300, 0),
+	0x0d, 0x0f, SNDRV_CTL_TLVD_DB_SCALE_ITEM(0, 0, 0),
+);
+
+static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int reg = kcontrol->private_value & 0xff;
+	int ret;
+	u16 val;
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+	if (ret < 0)
+		return ret;
+
+	/* now hit the volume update bits (always bit 8) */
+	val = snd_soc_component_read32(component, reg);
+	return snd_soc_component_write(component, reg, val | 0x0100);
+}
+
+static const char *wm8991_digital_sidetone[] =
+{"None", "Left ADC", "Right ADC", "Reserved"};
+
+static SOC_ENUM_SINGLE_DECL(wm8991_left_digital_sidetone_enum,
+			    WM8991_DIGITAL_SIDE_TONE,
+			    WM8991_ADC_TO_DACL_SHIFT,
+			    wm8991_digital_sidetone);
+
+static SOC_ENUM_SINGLE_DECL(wm8991_right_digital_sidetone_enum,
+			    WM8991_DIGITAL_SIDE_TONE,
+			    WM8991_ADC_TO_DACR_SHIFT,
+			    wm8991_digital_sidetone);
+
+static const char *wm8991_adcmode[] =
+{"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
+
+static SOC_ENUM_SINGLE_DECL(wm8991_right_adcmode_enum,
+			    WM8991_ADC_CTRL,
+			    WM8991_ADC_HPF_CUT_SHIFT,
+			    wm8991_adcmode);
+
+static const struct snd_kcontrol_new wm8991_snd_controls[] = {
+	/* INMIXL */
+	SOC_SINGLE("LIN12 PGA Boost", WM8991_INPUT_MIXER3, WM8991_L12MNBST_BIT, 1, 0),
+	SOC_SINGLE("LIN34 PGA Boost", WM8991_INPUT_MIXER3, WM8991_L34MNBST_BIT, 1, 0),
+	/* INMIXR */
+	SOC_SINGLE("RIN12 PGA Boost", WM8991_INPUT_MIXER3, WM8991_R12MNBST_BIT, 1, 0),
+	SOC_SINGLE("RIN34 PGA Boost", WM8991_INPUT_MIXER3, WM8991_R34MNBST_BIT, 1, 0),
+
+	/* LOMIX */
+	SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8991_OUTPUT_MIXER3,
+		WM8991_LLI3LOVOL_SHIFT, WM8991_LLI3LOVOL_MASK, 1, out_mix_tlv),
+	SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER3,
+		WM8991_LR12LOVOL_SHIFT, WM8991_LR12LOVOL_MASK, 1, out_mix_tlv),
+	SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER3,
+		WM8991_LL12LOVOL_SHIFT, WM8991_LL12LOVOL_MASK, 1, out_mix_tlv),
+	SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8991_OUTPUT_MIXER5,
+		WM8991_LRI3LOVOL_SHIFT, WM8991_LRI3LOVOL_MASK, 1, out_mix_tlv),
+	SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8991_OUTPUT_MIXER5,
+		WM8991_LRBLOVOL_SHIFT, WM8991_LRBLOVOL_MASK, 1, out_mix_tlv),
+	SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8991_OUTPUT_MIXER5,
+		WM8991_LRBLOVOL_SHIFT, WM8991_LRBLOVOL_MASK, 1, out_mix_tlv),
+
+	/* ROMIX */
+	SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8991_OUTPUT_MIXER4,
+		WM8991_RRI3ROVOL_SHIFT, WM8991_RRI3ROVOL_MASK, 1, out_mix_tlv),
+	SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER4,
+		WM8991_RL12ROVOL_SHIFT, WM8991_RL12ROVOL_MASK, 1, out_mix_tlv),
+	SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER4,
+		WM8991_RR12ROVOL_SHIFT, WM8991_RR12ROVOL_MASK, 1, out_mix_tlv),
+	SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8991_OUTPUT_MIXER6,
+		WM8991_RLI3ROVOL_SHIFT, WM8991_RLI3ROVOL_MASK, 1, out_mix_tlv),
+	SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8991_OUTPUT_MIXER6,
+		WM8991_RLBROVOL_SHIFT, WM8991_RLBROVOL_MASK, 1, out_mix_tlv),
+	SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8991_OUTPUT_MIXER6,
+		WM8991_RRBROVOL_SHIFT, WM8991_RRBROVOL_MASK, 1, out_mix_tlv),
+
+	/* LOUT */
+	SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8991_LEFT_OUTPUT_VOLUME,
+		WM8991_LOUTVOL_SHIFT, WM8991_LOUTVOL_MASK, 0, out_pga_tlv),
+	SOC_SINGLE("LOUT ZC", WM8991_LEFT_OUTPUT_VOLUME, WM8991_LOZC_BIT, 1, 0),
+
+	/* ROUT */
+	SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8991_RIGHT_OUTPUT_VOLUME,
+		WM8991_ROUTVOL_SHIFT, WM8991_ROUTVOL_MASK, 0, out_pga_tlv),
+	SOC_SINGLE("ROUT ZC", WM8991_RIGHT_OUTPUT_VOLUME, WM8991_ROZC_BIT, 1, 0),
+
+	/* LOPGA */
+	SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8991_LEFT_OPGA_VOLUME,
+		WM8991_LOPGAVOL_SHIFT, WM8991_LOPGAVOL_MASK, 0, out_pga_tlv),
+	SOC_SINGLE("LOPGA ZC Switch", WM8991_LEFT_OPGA_VOLUME,
+		WM8991_LOPGAZC_BIT, 1, 0),
+
+	/* ROPGA */
+	SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8991_RIGHT_OPGA_VOLUME,
+		WM8991_ROPGAVOL_SHIFT, WM8991_ROPGAVOL_MASK, 0, out_pga_tlv),
+	SOC_SINGLE("ROPGA ZC Switch", WM8991_RIGHT_OPGA_VOLUME,
+		WM8991_ROPGAZC_BIT, 1, 0),
+
+	SOC_SINGLE("LON Mute Switch", WM8991_LINE_OUTPUTS_VOLUME,
+		WM8991_LONMUTE_BIT, 1, 0),
+	SOC_SINGLE("LOP Mute Switch", WM8991_LINE_OUTPUTS_VOLUME,
+		WM8991_LOPMUTE_BIT, 1, 0),
+	SOC_SINGLE("LOP Attenuation Switch", WM8991_LINE_OUTPUTS_VOLUME,
+		WM8991_LOATTN_BIT, 1, 0),
+	SOC_SINGLE("RON Mute Switch", WM8991_LINE_OUTPUTS_VOLUME,
+		WM8991_RONMUTE_BIT, 1, 0),
+	SOC_SINGLE("ROP Mute Switch", WM8991_LINE_OUTPUTS_VOLUME,
+		WM8991_ROPMUTE_BIT, 1, 0),
+	SOC_SINGLE("ROP Attenuation Switch", WM8991_LINE_OUTPUTS_VOLUME,
+		WM8991_ROATTN_BIT, 1, 0),
+
+	SOC_SINGLE("OUT3 Mute Switch", WM8991_OUT3_4_VOLUME,
+		WM8991_OUT3MUTE_BIT, 1, 0),
+	SOC_SINGLE("OUT3 Attenuation Switch", WM8991_OUT3_4_VOLUME,
+		WM8991_OUT3ATTN_BIT, 1, 0),
+
+	SOC_SINGLE("OUT4 Mute Switch", WM8991_OUT3_4_VOLUME,
+		WM8991_OUT4MUTE_BIT, 1, 0),
+	SOC_SINGLE("OUT4 Attenuation Switch", WM8991_OUT3_4_VOLUME,
+		WM8991_OUT4ATTN_BIT, 1, 0),
+
+	SOC_SINGLE("Speaker Mode Switch", WM8991_CLASSD1,
+		WM8991_CDMODE_BIT, 1, 0),
+
+	SOC_SINGLE("Speaker Output Attenuation Volume", WM8991_SPEAKER_VOLUME,
+		WM8991_SPKVOL_SHIFT, WM8991_SPKVOL_MASK, 0),
+	SOC_SINGLE("Speaker DC Boost Volume", WM8991_CLASSD3,
+		WM8991_DCGAIN_SHIFT, WM8991_DCGAIN_MASK, 0),
+	SOC_SINGLE("Speaker AC Boost Volume", WM8991_CLASSD3,
+		WM8991_ACGAIN_SHIFT, WM8991_ACGAIN_MASK, 0),
+
+	SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume",
+		WM8991_LEFT_DAC_DIGITAL_VOLUME,
+		WM8991_DACL_VOL_SHIFT,
+		WM8991_DACL_VOL_MASK,
+		0,
+		out_dac_tlv),
+
+	SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume",
+		WM8991_RIGHT_DAC_DIGITAL_VOLUME,
+		WM8991_DACR_VOL_SHIFT,
+		WM8991_DACR_VOL_MASK,
+		0,
+		out_dac_tlv),
+
+	SOC_ENUM("Left Digital Sidetone", wm8991_left_digital_sidetone_enum),
+	SOC_ENUM("Right Digital Sidetone", wm8991_right_digital_sidetone_enum),
+
+	SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8991_DIGITAL_SIDE_TONE,
+		WM8991_ADCL_DAC_SVOL_SHIFT, WM8991_ADCL_DAC_SVOL_MASK, 0,
+		out_sidetone_tlv),
+	SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8991_DIGITAL_SIDE_TONE,
+		WM8991_ADCR_DAC_SVOL_SHIFT, WM8991_ADCR_DAC_SVOL_MASK, 0,
+		out_sidetone_tlv),
+
+	SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8991_ADC_CTRL,
+		WM8991_ADC_HPF_ENA_BIT, 1, 0),
+
+	SOC_ENUM("ADC HPF Mode", wm8991_right_adcmode_enum),
+
+	SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume",
+		WM8991_LEFT_ADC_DIGITAL_VOLUME,
+		WM8991_ADCL_VOL_SHIFT,
+		WM8991_ADCL_VOL_MASK,
+		0,
+		in_adc_tlv),
+
+	SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume",
+		WM8991_RIGHT_ADC_DIGITAL_VOLUME,
+		WM8991_ADCR_VOL_SHIFT,
+		WM8991_ADCR_VOL_MASK,
+		0,
+		in_adc_tlv),
+
+	SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN12 Volume",
+		WM8991_LEFT_LINE_INPUT_1_2_VOLUME,
+		WM8991_LIN12VOL_SHIFT,
+		WM8991_LIN12VOL_MASK,
+		0,
+		in_pga_tlv),
+
+	SOC_SINGLE("LIN12 ZC Switch", WM8991_LEFT_LINE_INPUT_1_2_VOLUME,
+		WM8991_LI12ZC_BIT, 1, 0),
+
+	SOC_SINGLE("LIN12 Mute Switch", WM8991_LEFT_LINE_INPUT_1_2_VOLUME,
+		WM8991_LI12MUTE_BIT, 1, 0),
+
+	SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN34 Volume",
+		WM8991_LEFT_LINE_INPUT_3_4_VOLUME,
+		WM8991_LIN34VOL_SHIFT,
+		WM8991_LIN34VOL_MASK,
+		0,
+		in_pga_tlv),
+
+	SOC_SINGLE("LIN34 ZC Switch", WM8991_LEFT_LINE_INPUT_3_4_VOLUME,
+		WM8991_LI34ZC_BIT, 1, 0),
+
+	SOC_SINGLE("LIN34 Mute Switch", WM8991_LEFT_LINE_INPUT_3_4_VOLUME,
+		WM8991_LI34MUTE_BIT, 1, 0),
+
+	SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN12 Volume",
+		WM8991_RIGHT_LINE_INPUT_1_2_VOLUME,
+		WM8991_RIN12VOL_SHIFT,
+		WM8991_RIN12VOL_MASK,
+		0,
+		in_pga_tlv),
+
+	SOC_SINGLE("RIN12 ZC Switch", WM8991_RIGHT_LINE_INPUT_1_2_VOLUME,
+		WM8991_RI12ZC_BIT, 1, 0),
+
+	SOC_SINGLE("RIN12 Mute Switch", WM8991_RIGHT_LINE_INPUT_1_2_VOLUME,
+		WM8991_RI12MUTE_BIT, 1, 0),
+
+	SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN34 Volume",
+		WM8991_RIGHT_LINE_INPUT_3_4_VOLUME,
+		WM8991_RIN34VOL_SHIFT,
+		WM8991_RIN34VOL_MASK,
+		0,
+		in_pga_tlv),
+
+	SOC_SINGLE("RIN34 ZC Switch", WM8991_RIGHT_LINE_INPUT_3_4_VOLUME,
+		WM8991_RI34ZC_BIT, 1, 0),
+
+	SOC_SINGLE("RIN34 Mute Switch", WM8991_RIGHT_LINE_INPUT_3_4_VOLUME,
+		WM8991_RI34MUTE_BIT, 1, 0),
+};
+
+/*
+ * _DAPM_ Controls
+ */
+static int outmixer_event(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u32 reg_shift = kcontrol->private_value & 0xfff;
+	int ret = 0;
+	u16 reg;
+
+	switch (reg_shift) {
+	case WM8991_SPEAKER_MIXER | (WM8991_LDSPK_BIT << 8):
+		reg = snd_soc_component_read32(component, WM8991_OUTPUT_MIXER1);
+		if (reg & WM8991_LDLO) {
+			printk(KERN_WARNING
+			       "Cannot set as Output Mixer 1 LDLO Set\n");
+			ret = -1;
+		}
+		break;
+
+	case WM8991_SPEAKER_MIXER | (WM8991_RDSPK_BIT << 8):
+		reg = snd_soc_component_read32(component, WM8991_OUTPUT_MIXER2);
+		if (reg & WM8991_RDRO) {
+			printk(KERN_WARNING
+			       "Cannot set as Output Mixer 2 RDRO Set\n");
+			ret = -1;
+		}
+		break;
+
+	case WM8991_OUTPUT_MIXER1 | (WM8991_LDLO_BIT << 8):
+		reg = snd_soc_component_read32(component, WM8991_SPEAKER_MIXER);
+		if (reg & WM8991_LDSPK) {
+			printk(KERN_WARNING
+			       "Cannot set as Speaker Mixer LDSPK Set\n");
+			ret = -1;
+		}
+		break;
+
+	case WM8991_OUTPUT_MIXER2 | (WM8991_RDRO_BIT << 8):
+		reg = snd_soc_component_read32(component, WM8991_SPEAKER_MIXER);
+		if (reg & WM8991_RDSPK) {
+			printk(KERN_WARNING
+			       "Cannot set as Speaker Mixer RDSPK Set\n");
+			ret = -1;
+		}
+		break;
+	}
+
+	return ret;
+}
+
+/* INMIX dB values */
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(in_mix_tlv, -1200, 300, 1);
+
+/* Left In PGA Connections */
+static const struct snd_kcontrol_new wm8991_dapm_lin12_pga_controls[] = {
+	SOC_DAPM_SINGLE("LIN1 Switch", WM8991_INPUT_MIXER2, WM8991_LMN1_BIT, 1, 0),
+	SOC_DAPM_SINGLE("LIN2 Switch", WM8991_INPUT_MIXER2, WM8991_LMP2_BIT, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8991_dapm_lin34_pga_controls[] = {
+	SOC_DAPM_SINGLE("LIN3 Switch", WM8991_INPUT_MIXER2, WM8991_LMN3_BIT, 1, 0),
+	SOC_DAPM_SINGLE("LIN4 Switch", WM8991_INPUT_MIXER2, WM8991_LMP4_BIT, 1, 0),
+};
+
+/* Right In PGA Connections */
+static const struct snd_kcontrol_new wm8991_dapm_rin12_pga_controls[] = {
+	SOC_DAPM_SINGLE("RIN1 Switch", WM8991_INPUT_MIXER2, WM8991_RMN1_BIT, 1, 0),
+	SOC_DAPM_SINGLE("RIN2 Switch", WM8991_INPUT_MIXER2, WM8991_RMP2_BIT, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8991_dapm_rin34_pga_controls[] = {
+	SOC_DAPM_SINGLE("RIN3 Switch", WM8991_INPUT_MIXER2, WM8991_RMN3_BIT, 1, 0),
+	SOC_DAPM_SINGLE("RIN4 Switch", WM8991_INPUT_MIXER2, WM8991_RMP4_BIT, 1, 0),
+};
+
+/* INMIXL */
+static const struct snd_kcontrol_new wm8991_dapm_inmixl_controls[] = {
+	SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8991_INPUT_MIXER3,
+		WM8991_LDBVOL_SHIFT, WM8991_LDBVOL_MASK, 0, in_mix_tlv),
+	SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8991_INPUT_MIXER5, WM8991_LI2BVOL_SHIFT,
+		7, 0, in_mix_tlv),
+	SOC_DAPM_SINGLE("LINPGA12 Switch", WM8991_INPUT_MIXER3, WM8991_L12MNB_BIT,
+		1, 0),
+	SOC_DAPM_SINGLE("LINPGA34 Switch", WM8991_INPUT_MIXER3, WM8991_L34MNB_BIT,
+		1, 0),
+};
+
+/* INMIXR */
+static const struct snd_kcontrol_new wm8991_dapm_inmixr_controls[] = {
+	SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8991_INPUT_MIXER4,
+		WM8991_RDBVOL_SHIFT, WM8991_RDBVOL_MASK, 0, in_mix_tlv),
+	SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8991_INPUT_MIXER6, WM8991_RI2BVOL_SHIFT,
+		7, 0, in_mix_tlv),
+	SOC_DAPM_SINGLE("RINPGA12 Switch", WM8991_INPUT_MIXER3, WM8991_L12MNB_BIT,
+		1, 0),
+	SOC_DAPM_SINGLE("RINPGA34 Switch", WM8991_INPUT_MIXER3, WM8991_L34MNB_BIT,
+		1, 0),
+};
+
+/* AINLMUX */
+static const char *wm8991_ainlmux[] =
+{"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
+
+static SOC_ENUM_SINGLE_DECL(wm8991_ainlmux_enum,
+			    WM8991_INPUT_MIXER1, WM8991_AINLMODE_SHIFT,
+			    wm8991_ainlmux);
+
+static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls =
+	SOC_DAPM_ENUM("Route", wm8991_ainlmux_enum);
+
+/* DIFFINL */
+
+/* AINRMUX */
+static const char *wm8991_ainrmux[] =
+{"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
+
+static SOC_ENUM_SINGLE_DECL(wm8991_ainrmux_enum,
+			    WM8991_INPUT_MIXER1, WM8991_AINRMODE_SHIFT,
+			    wm8991_ainrmux);
+
+static const struct snd_kcontrol_new wm8991_dapm_ainrmux_controls =
+	SOC_DAPM_ENUM("Route", wm8991_ainrmux_enum);
+
+/* RXVOICE */
+static const struct snd_kcontrol_new wm8991_dapm_rxvoice_controls[] = {
+	SOC_DAPM_SINGLE_TLV("LIN4RXN", WM8991_INPUT_MIXER5, WM8991_LR4BVOL_SHIFT,
+		WM8991_LR4BVOL_MASK, 0, in_mix_tlv),
+	SOC_DAPM_SINGLE_TLV("RIN4RXP", WM8991_INPUT_MIXER6, WM8991_RL4BVOL_SHIFT,
+		WM8991_RL4BVOL_MASK, 0, in_mix_tlv),
+};
+
+/* LOMIX */
+static const struct snd_kcontrol_new wm8991_dapm_lomix_controls[] = {
+	SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8991_OUTPUT_MIXER1,
+		WM8991_LRBLO_BIT, 1, 0),
+	SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8991_OUTPUT_MIXER1,
+		WM8991_LLBLO_BIT, 1, 0),
+	SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8991_OUTPUT_MIXER1,
+		WM8991_LRI3LO_BIT, 1, 0),
+	SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8991_OUTPUT_MIXER1,
+		WM8991_LLI3LO_BIT, 1, 0),
+	SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER1,
+		WM8991_LR12LO_BIT, 1, 0),
+	SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER1,
+		WM8991_LL12LO_BIT, 1, 0),
+	SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8991_OUTPUT_MIXER1,
+		WM8991_LDLO_BIT, 1, 0),
+};
+
+/* ROMIX */
+static const struct snd_kcontrol_new wm8991_dapm_romix_controls[] = {
+	SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8991_OUTPUT_MIXER2,
+		WM8991_RLBRO_BIT, 1, 0),
+	SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8991_OUTPUT_MIXER2,
+		WM8991_RRBRO_BIT, 1, 0),
+	SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8991_OUTPUT_MIXER2,
+		WM8991_RLI3RO_BIT, 1, 0),
+	SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8991_OUTPUT_MIXER2,
+		WM8991_RRI3RO_BIT, 1, 0),
+	SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER2,
+		WM8991_RL12RO_BIT, 1, 0),
+	SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER2,
+		WM8991_RR12RO_BIT, 1, 0),
+	SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8991_OUTPUT_MIXER2,
+		WM8991_RDRO_BIT, 1, 0),
+};
+
+/* LONMIX */
+static const struct snd_kcontrol_new wm8991_dapm_lonmix_controls[] = {
+	SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8991_LINE_MIXER1,
+		WM8991_LLOPGALON_BIT, 1, 0),
+	SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8991_LINE_MIXER1,
+		WM8991_LROPGALON_BIT, 1, 0),
+	SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8991_LINE_MIXER1,
+		WM8991_LOPLON_BIT, 1, 0),
+};
+
+/* LOPMIX */
+static const struct snd_kcontrol_new wm8991_dapm_lopmix_controls[] = {
+	SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8991_LINE_MIXER1,
+		WM8991_LR12LOP_BIT, 1, 0),
+	SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8991_LINE_MIXER1,
+		WM8991_LL12LOP_BIT, 1, 0),
+	SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8991_LINE_MIXER1,
+		WM8991_LLOPGALOP_BIT, 1, 0),
+};
+
+/* RONMIX */
+static const struct snd_kcontrol_new wm8991_dapm_ronmix_controls[] = {
+	SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8991_LINE_MIXER2,
+		WM8991_RROPGARON_BIT, 1, 0),
+	SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8991_LINE_MIXER2,
+		WM8991_RLOPGARON_BIT, 1, 0),
+	SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8991_LINE_MIXER2,
+		WM8991_ROPRON_BIT, 1, 0),
+};
+
+/* ROPMIX */
+static const struct snd_kcontrol_new wm8991_dapm_ropmix_controls[] = {
+	SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8991_LINE_MIXER2,
+		WM8991_RL12ROP_BIT, 1, 0),
+	SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8991_LINE_MIXER2,
+		WM8991_RR12ROP_BIT, 1, 0),
+	SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8991_LINE_MIXER2,
+		WM8991_RROPGAROP_BIT, 1, 0),
+};
+
+/* OUT3MIX */
+static const struct snd_kcontrol_new wm8991_dapm_out3mix_controls[] = {
+	SOC_DAPM_SINGLE("OUT3MIX LIN4RXN Bypass Switch", WM8991_OUT3_4_MIXER,
+		WM8991_LI4O3_BIT, 1, 0),
+	SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8991_OUT3_4_MIXER,
+		WM8991_LPGAO3_BIT, 1, 0),
+};
+
+/* OUT4MIX */
+static const struct snd_kcontrol_new wm8991_dapm_out4mix_controls[] = {
+	SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8991_OUT3_4_MIXER,
+		WM8991_RPGAO4_BIT, 1, 0),
+	SOC_DAPM_SINGLE("OUT4MIX RIN4RXP Bypass Switch", WM8991_OUT3_4_MIXER,
+		WM8991_RI4O4_BIT, 1, 0),
+};
+
+/* SPKMIX */
+static const struct snd_kcontrol_new wm8991_dapm_spkmix_controls[] = {
+	SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8991_SPEAKER_MIXER,
+		WM8991_LI2SPK_BIT, 1, 0),
+	SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8991_SPEAKER_MIXER,
+		WM8991_LB2SPK_BIT, 1, 0),
+	SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8991_SPEAKER_MIXER,
+		WM8991_LOPGASPK_BIT, 1, 0),
+	SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8991_SPEAKER_MIXER,
+		WM8991_LDSPK_BIT, 1, 0),
+	SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8991_SPEAKER_MIXER,
+		WM8991_RDSPK_BIT, 1, 0),
+	SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8991_SPEAKER_MIXER,
+		WM8991_ROPGASPK_BIT, 1, 0),
+	SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8991_SPEAKER_MIXER,
+		WM8991_RL12ROP_BIT, 1, 0),
+	SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8991_SPEAKER_MIXER,
+		WM8991_RI2SPK_BIT, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {
+	/* Input Side */
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("LIN1"),
+	SND_SOC_DAPM_INPUT("LIN2"),
+	SND_SOC_DAPM_INPUT("LIN3"),
+	SND_SOC_DAPM_INPUT("LIN4RXN"),
+	SND_SOC_DAPM_INPUT("RIN3"),
+	SND_SOC_DAPM_INPUT("RIN4RXP"),
+	SND_SOC_DAPM_INPUT("RIN1"),
+	SND_SOC_DAPM_INPUT("RIN2"),
+	SND_SOC_DAPM_INPUT("Internal ADC Source"),
+
+	SND_SOC_DAPM_SUPPLY("INL", WM8991_POWER_MANAGEMENT_2,
+			    WM8991_AINL_ENA_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("INR", WM8991_POWER_MANAGEMENT_2,
+			    WM8991_AINR_ENA_BIT, 0, NULL, 0),
+
+	/* DACs */
+	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8991_POWER_MANAGEMENT_2,
+		WM8991_ADCL_ENA_BIT, 0),
+	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8991_POWER_MANAGEMENT_2,
+		WM8991_ADCR_ENA_BIT, 0),
+
+	/* Input PGAs */
+	SND_SOC_DAPM_MIXER("LIN12 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_LIN12_ENA_BIT,
+		0, &wm8991_dapm_lin12_pga_controls[0],
+		ARRAY_SIZE(wm8991_dapm_lin12_pga_controls)),
+	SND_SOC_DAPM_MIXER("LIN34 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_LIN34_ENA_BIT,
+		0, &wm8991_dapm_lin34_pga_controls[0],
+		ARRAY_SIZE(wm8991_dapm_lin34_pga_controls)),
+	SND_SOC_DAPM_MIXER("RIN12 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_RIN12_ENA_BIT,
+		0, &wm8991_dapm_rin12_pga_controls[0],
+		ARRAY_SIZE(wm8991_dapm_rin12_pga_controls)),
+	SND_SOC_DAPM_MIXER("RIN34 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_RIN34_ENA_BIT,
+		0, &wm8991_dapm_rin34_pga_controls[0],
+		ARRAY_SIZE(wm8991_dapm_rin34_pga_controls)),
+
+	/* INMIXL */
+	SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0,
+		&wm8991_dapm_inmixl_controls[0],
+		ARRAY_SIZE(wm8991_dapm_inmixl_controls)),
+
+	/* AINLMUX */
+	SND_SOC_DAPM_MUX("AINLMUX", SND_SOC_NOPM, 0, 0,
+		&wm8991_dapm_ainlmux_controls),
+
+	/* INMIXR */
+	SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0,
+		&wm8991_dapm_inmixr_controls[0],
+		ARRAY_SIZE(wm8991_dapm_inmixr_controls)),
+
+	/* AINRMUX */
+	SND_SOC_DAPM_MUX("AINRMUX", SND_SOC_NOPM, 0, 0,
+		&wm8991_dapm_ainrmux_controls),
+
+	/* Output Side */
+	/* DACs */
+	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8991_POWER_MANAGEMENT_3,
+		WM8991_DACL_ENA_BIT, 0),
+	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8991_POWER_MANAGEMENT_3,
+		WM8991_DACR_ENA_BIT, 0),
+
+	/* LOMIX */
+	SND_SOC_DAPM_MIXER_E("LOMIX", WM8991_POWER_MANAGEMENT_3, WM8991_LOMIX_ENA_BIT,
+		0, &wm8991_dapm_lomix_controls[0],
+		ARRAY_SIZE(wm8991_dapm_lomix_controls),
+		outmixer_event, SND_SOC_DAPM_PRE_REG),
+
+	/* LONMIX */
+	SND_SOC_DAPM_MIXER("LONMIX", WM8991_POWER_MANAGEMENT_3, WM8991_LON_ENA_BIT, 0,
+		&wm8991_dapm_lonmix_controls[0],
+		ARRAY_SIZE(wm8991_dapm_lonmix_controls)),
+
+	/* LOPMIX */
+	SND_SOC_DAPM_MIXER("LOPMIX", WM8991_POWER_MANAGEMENT_3, WM8991_LOP_ENA_BIT, 0,
+		&wm8991_dapm_lopmix_controls[0],
+		ARRAY_SIZE(wm8991_dapm_lopmix_controls)),
+
+	/* OUT3MIX */
+	SND_SOC_DAPM_MIXER("OUT3MIX", WM8991_POWER_MANAGEMENT_1, WM8991_OUT3_ENA_BIT, 0,
+		&wm8991_dapm_out3mix_controls[0],
+		ARRAY_SIZE(wm8991_dapm_out3mix_controls)),
+
+	/* SPKMIX */
+	SND_SOC_DAPM_MIXER_E("SPKMIX", WM8991_POWER_MANAGEMENT_1, WM8991_SPK_ENA_BIT, 0,
+		&wm8991_dapm_spkmix_controls[0],
+		ARRAY_SIZE(wm8991_dapm_spkmix_controls), outmixer_event,
+		SND_SOC_DAPM_PRE_REG),
+
+	/* OUT4MIX */
+	SND_SOC_DAPM_MIXER("OUT4MIX", WM8991_POWER_MANAGEMENT_1, WM8991_OUT4_ENA_BIT, 0,
+		&wm8991_dapm_out4mix_controls[0],
+		ARRAY_SIZE(wm8991_dapm_out4mix_controls)),
+
+	/* ROPMIX */
+	SND_SOC_DAPM_MIXER("ROPMIX", WM8991_POWER_MANAGEMENT_3, WM8991_ROP_ENA_BIT, 0,
+		&wm8991_dapm_ropmix_controls[0],
+		ARRAY_SIZE(wm8991_dapm_ropmix_controls)),
+
+	/* RONMIX */
+	SND_SOC_DAPM_MIXER("RONMIX", WM8991_POWER_MANAGEMENT_3, WM8991_RON_ENA_BIT, 0,
+		&wm8991_dapm_ronmix_controls[0],
+		ARRAY_SIZE(wm8991_dapm_ronmix_controls)),
+
+	/* ROMIX */
+	SND_SOC_DAPM_MIXER_E("ROMIX", WM8991_POWER_MANAGEMENT_3, WM8991_ROMIX_ENA_BIT,
+		0, &wm8991_dapm_romix_controls[0],
+		ARRAY_SIZE(wm8991_dapm_romix_controls),
+		outmixer_event, SND_SOC_DAPM_PRE_REG),
+
+	/* LOUT PGA */
+	SND_SOC_DAPM_PGA("LOUT PGA", WM8991_POWER_MANAGEMENT_1, WM8991_LOUT_ENA_BIT, 0,
+		NULL, 0),
+
+	/* ROUT PGA */
+	SND_SOC_DAPM_PGA("ROUT PGA", WM8991_POWER_MANAGEMENT_1, WM8991_ROUT_ENA_BIT, 0,
+		NULL, 0),
+
+	/* LOPGA */
+	SND_SOC_DAPM_PGA("LOPGA", WM8991_POWER_MANAGEMENT_3, WM8991_LOPGA_ENA_BIT, 0,
+		NULL, 0),
+
+	/* ROPGA */
+	SND_SOC_DAPM_PGA("ROPGA", WM8991_POWER_MANAGEMENT_3, WM8991_ROPGA_ENA_BIT, 0,
+		NULL, 0),
+
+	/* MICBIAS */
+	SND_SOC_DAPM_SUPPLY("MICBIAS", WM8991_POWER_MANAGEMENT_1,
+			    WM8991_MICBIAS_ENA_BIT, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("LON"),
+	SND_SOC_DAPM_OUTPUT("LOP"),
+	SND_SOC_DAPM_OUTPUT("OUT3"),
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+	SND_SOC_DAPM_OUTPUT("SPKN"),
+	SND_SOC_DAPM_OUTPUT("SPKP"),
+	SND_SOC_DAPM_OUTPUT("ROUT"),
+	SND_SOC_DAPM_OUTPUT("OUT4"),
+	SND_SOC_DAPM_OUTPUT("ROP"),
+	SND_SOC_DAPM_OUTPUT("RON"),
+	SND_SOC_DAPM_OUTPUT("OUT"),
+
+	SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
+};
+
+static const struct snd_soc_dapm_route wm8991_dapm_routes[] = {
+	/* Make DACs turn on when playing even if not mixed into any outputs */
+	{"Internal DAC Sink", NULL, "Left DAC"},
+	{"Internal DAC Sink", NULL, "Right DAC"},
+
+	/* Make ADCs turn on when recording even if not mixed from any inputs */
+	{"Left ADC", NULL, "Internal ADC Source"},
+	{"Right ADC", NULL, "Internal ADC Source"},
+
+	/* Input Side */
+	{"INMIXL", NULL, "INL"},
+	{"AINLMUX", NULL, "INL"},
+	{"INMIXR", NULL, "INR"},
+	{"AINRMUX", NULL, "INR"},
+	/* LIN12 PGA */
+	{"LIN12 PGA", "LIN1 Switch", "LIN1"},
+	{"LIN12 PGA", "LIN2 Switch", "LIN2"},
+	/* LIN34 PGA */
+	{"LIN34 PGA", "LIN3 Switch", "LIN3"},
+	{"LIN34 PGA", "LIN4 Switch", "LIN4RXN"},
+	/* INMIXL */
+	{"INMIXL", "Record Left Volume", "LOMIX"},
+	{"INMIXL", "LIN2 Volume", "LIN2"},
+	{"INMIXL", "LINPGA12 Switch", "LIN12 PGA"},
+	{"INMIXL", "LINPGA34 Switch", "LIN34 PGA"},
+	/* AINLMUX */
+	{"AINLMUX", "INMIXL Mix", "INMIXL"},
+	{"AINLMUX", "DIFFINL Mix", "LIN12 PGA"},
+	{"AINLMUX", "DIFFINL Mix", "LIN34 PGA"},
+	{"AINLMUX", "RXVOICE Mix", "LIN4RXN"},
+	{"AINLMUX", "RXVOICE Mix", "RIN4RXP"},
+	/* ADC */
+	{"Left ADC", NULL, "AINLMUX"},
+
+	/* RIN12 PGA */
+	{"RIN12 PGA", "RIN1 Switch", "RIN1"},
+	{"RIN12 PGA", "RIN2 Switch", "RIN2"},
+	/* RIN34 PGA */
+	{"RIN34 PGA", "RIN3 Switch", "RIN3"},
+	{"RIN34 PGA", "RIN4 Switch", "RIN4RXP"},
+	/* INMIXL */
+	{"INMIXR", "Record Right Volume", "ROMIX"},
+	{"INMIXR", "RIN2 Volume", "RIN2"},
+	{"INMIXR", "RINPGA12 Switch", "RIN12 PGA"},
+	{"INMIXR", "RINPGA34 Switch", "RIN34 PGA"},
+	/* AINRMUX */
+	{"AINRMUX", "INMIXR Mix", "INMIXR"},
+	{"AINRMUX", "DIFFINR Mix", "RIN12 PGA"},
+	{"AINRMUX", "DIFFINR Mix", "RIN34 PGA"},
+	{"AINRMUX", "RXVOICE Mix", "LIN4RXN"},
+	{"AINRMUX", "RXVOICE Mix", "RIN4RXP"},
+	/* ADC */
+	{"Right ADC", NULL, "AINRMUX"},
+
+	/* LOMIX */
+	{"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"},
+	{"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"},
+	{"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
+	{"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
+	{"LOMIX", "LOMIX Right ADC Bypass Switch", "AINRMUX"},
+	{"LOMIX", "LOMIX Left ADC Bypass Switch", "AINLMUX"},
+	{"LOMIX", "LOMIX Left DAC Switch", "Left DAC"},
+
+	/* ROMIX */
+	{"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"},
+	{"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"},
+	{"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
+	{"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
+	{"ROMIX", "ROMIX Right ADC Bypass Switch", "AINRMUX"},
+	{"ROMIX", "ROMIX Left ADC Bypass Switch", "AINLMUX"},
+	{"ROMIX", "ROMIX Right DAC Switch", "Right DAC"},
+
+	/* SPKMIX */
+	{"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"},
+	{"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"},
+	{"SPKMIX", "SPKMIX LADC Bypass Switch", "AINLMUX"},
+	{"SPKMIX", "SPKMIX RADC Bypass Switch", "AINRMUX"},
+	{"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"},
+	{"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"},
+	{"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"},
+	{"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"},
+
+	/* LONMIX */
+	{"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"},
+	{"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"},
+	{"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"},
+
+	/* LOPMIX */
+	{"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"},
+	{"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"},
+	{"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"},
+
+	/* OUT3MIX */
+	{"OUT3MIX", "OUT3MIX LIN4RXN Bypass Switch", "LIN4RXN"},
+	{"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"},
+
+	/* OUT4MIX */
+	{"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"},
+	{"OUT4MIX", "OUT4MIX RIN4RXP Bypass Switch", "RIN4RXP"},
+
+	/* RONMIX */
+	{"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"},
+	{"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"},
+	{"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"},
+
+	/* ROPMIX */
+	{"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"},
+	{"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"},
+	{"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"},
+
+	/* Out Mixer PGAs */
+	{"LOPGA", NULL, "LOMIX"},
+	{"ROPGA", NULL, "ROMIX"},
+
+	{"LOUT PGA", NULL, "LOMIX"},
+	{"ROUT PGA", NULL, "ROMIX"},
+
+	/* Output Pins */
+	{"LON", NULL, "LONMIX"},
+	{"LOP", NULL, "LOPMIX"},
+	{"OUT", NULL, "OUT3MIX"},
+	{"LOUT", NULL, "LOUT PGA"},
+	{"SPKN", NULL, "SPKMIX"},
+	{"ROUT", NULL, "ROUT PGA"},
+	{"OUT4", NULL, "OUT4MIX"},
+	{"ROP", NULL, "ROPMIX"},
+	{"RON", NULL, "RONMIX"},
+};
+
+/* PLL divisors */
+struct _pll_div {
+	u32 div2;
+	u32 n;
+	u32 k;
+};
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 16) * 10)
+
+static void pll_factors(struct _pll_div *pll_div, unsigned int target,
+			unsigned int source)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod;
+
+
+	Ndiv = target / source;
+	if (Ndiv < 6) {
+		source >>= 1;
+		pll_div->div2 = 1;
+		Ndiv = target / source;
+	} else
+		pll_div->div2 = 0;
+
+	if ((Ndiv < 6) || (Ndiv > 12))
+		printk(KERN_WARNING
+		       "WM8991 N value outwith recommended range! N = %d\n", Ndiv);
+
+	pll_div->n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	/* Check if we need to round */
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	K /= 10;
+
+	pll_div->k = K;
+}
+
+static int wm8991_set_dai_pll(struct snd_soc_dai *codec_dai,
+			      int pll_id, int src, unsigned int freq_in, unsigned int freq_out)
+{
+	u16 reg;
+	struct snd_soc_component *component = codec_dai->component;
+	struct _pll_div pll_div;
+
+	if (freq_in && freq_out) {
+		pll_factors(&pll_div, freq_out * 4, freq_in);
+
+		/* Turn on PLL */
+		reg = snd_soc_component_read32(component, WM8991_POWER_MANAGEMENT_2);
+		reg |= WM8991_PLL_ENA;
+		snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_2, reg);
+
+		/* sysclk comes from PLL */
+		reg = snd_soc_component_read32(component, WM8991_CLOCKING_2);
+		snd_soc_component_write(component, WM8991_CLOCKING_2, reg | WM8991_SYSCLK_SRC);
+
+		/* set up N , fractional mode and pre-divisor if necessary */
+		snd_soc_component_write(component, WM8991_PLL1, pll_div.n | WM8991_SDM |
+			      (pll_div.div2 ? WM8991_PRESCALE : 0));
+		snd_soc_component_write(component, WM8991_PLL2, (u8)(pll_div.k>>8));
+		snd_soc_component_write(component, WM8991_PLL3, (u8)(pll_div.k & 0xFF));
+	} else {
+		/* Turn on PLL */
+		reg = snd_soc_component_read32(component, WM8991_POWER_MANAGEMENT_2);
+		reg &= ~WM8991_PLL_ENA;
+		snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_2, reg);
+	}
+	return 0;
+}
+
+/*
+ * Set's ADC and Voice DAC format.
+ */
+static int wm8991_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 audio1, audio3;
+
+	audio1 = snd_soc_component_read32(component, WM8991_AUDIO_INTERFACE_1);
+	audio3 = snd_soc_component_read32(component, WM8991_AUDIO_INTERFACE_3);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		audio3 &= ~WM8991_AIF_MSTR1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		audio3 |= WM8991_AIF_MSTR1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	audio1 &= ~WM8991_AIF_FMT_MASK;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		audio1 |= WM8991_AIF_TMF_I2S;
+		audio1 &= ~WM8991_AIF_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		audio1 |= WM8991_AIF_TMF_RIGHTJ;
+		audio1 &= ~WM8991_AIF_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		audio1 |= WM8991_AIF_TMF_LEFTJ;
+		audio1 &= ~WM8991_AIF_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		audio1 |= WM8991_AIF_TMF_DSP;
+		audio1 &= ~WM8991_AIF_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		audio1 |= WM8991_AIF_TMF_DSP | WM8991_AIF_LRCLK_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8991_AUDIO_INTERFACE_1, audio1);
+	snd_soc_component_write(component, WM8991_AUDIO_INTERFACE_3, audio3);
+	return 0;
+}
+
+static int wm8991_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+				 int div_id, int div)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 reg;
+
+	switch (div_id) {
+	case WM8991_MCLK_DIV:
+		reg = snd_soc_component_read32(component, WM8991_CLOCKING_2) &
+		      ~WM8991_MCLK_DIV_MASK;
+		snd_soc_component_write(component, WM8991_CLOCKING_2, reg | div);
+		break;
+	case WM8991_DACCLK_DIV:
+		reg = snd_soc_component_read32(component, WM8991_CLOCKING_2) &
+		      ~WM8991_DAC_CLKDIV_MASK;
+		snd_soc_component_write(component, WM8991_CLOCKING_2, reg | div);
+		break;
+	case WM8991_ADCCLK_DIV:
+		reg = snd_soc_component_read32(component, WM8991_CLOCKING_2) &
+		      ~WM8991_ADC_CLKDIV_MASK;
+		snd_soc_component_write(component, WM8991_CLOCKING_2, reg | div);
+		break;
+	case WM8991_BCLK_DIV:
+		reg = snd_soc_component_read32(component, WM8991_CLOCKING_1) &
+		      ~WM8991_BCLK_DIV_MASK;
+		snd_soc_component_write(component, WM8991_CLOCKING_1, reg | div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ */
+static int wm8991_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 audio1 = snd_soc_component_read32(component, WM8991_AUDIO_INTERFACE_1);
+
+	audio1 &= ~WM8991_AIF_WL_MASK;
+	/* bit size */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		audio1 |= WM8991_AIF_WL_20BITS;
+		break;
+	case 24:
+		audio1 |= WM8991_AIF_WL_24BITS;
+		break;
+	case 32:
+		audio1 |= WM8991_AIF_WL_32BITS;
+		break;
+	}
+
+	snd_soc_component_write(component, WM8991_AUDIO_INTERFACE_1, audio1);
+	return 0;
+}
+
+static int wm8991_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	u16 val;
+
+	val  = snd_soc_component_read32(component, WM8991_DAC_CTRL) & ~WM8991_DAC_MUTE;
+	if (mute)
+		snd_soc_component_write(component, WM8991_DAC_CTRL, val | WM8991_DAC_MUTE);
+	else
+		snd_soc_component_write(component, WM8991_DAC_CTRL, val);
+	return 0;
+}
+
+static int wm8991_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8991_priv *wm8991 = snd_soc_component_get_drvdata(component);
+	u16 val;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* VMID=2*50k */
+		val = snd_soc_component_read32(component, WM8991_POWER_MANAGEMENT_1) &
+		      ~WM8991_VMID_MODE_MASK;
+		snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, val | 0x2);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			regcache_sync(wm8991->regmap);
+			/* Enable all output discharge bits */
+			snd_soc_component_write(component, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
+				      WM8991_DIS_RLINE | WM8991_DIS_OUT3 |
+				      WM8991_DIS_OUT4 | WM8991_DIS_LOUT |
+				      WM8991_DIS_ROUT);
+
+			/* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
+			snd_soc_component_write(component, WM8991_ANTIPOP2, WM8991_SOFTST |
+				      WM8991_BUFDCOPEN | WM8991_POBCTRL |
+				      WM8991_VMIDTOG);
+
+			/* Delay to allow output caps to discharge */
+			msleep(300);
+
+			/* Disable VMIDTOG */
+			snd_soc_component_write(component, WM8991_ANTIPOP2, WM8991_SOFTST |
+				      WM8991_BUFDCOPEN | WM8991_POBCTRL);
+
+			/* disable all output discharge bits */
+			snd_soc_component_write(component, WM8991_ANTIPOP1, 0);
+
+			/* Enable outputs */
+			snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, 0x1b00);
+
+			msleep(50);
+
+			/* Enable VMID at 2x50k */
+			snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, 0x1f02);
+
+			msleep(100);
+
+			/* Enable VREF */
+			snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, 0x1f03);
+
+			msleep(600);
+
+			/* Enable BUFIOEN */
+			snd_soc_component_write(component, WM8991_ANTIPOP2, WM8991_SOFTST |
+				      WM8991_BUFDCOPEN | WM8991_POBCTRL |
+				      WM8991_BUFIOEN);
+
+			/* Disable outputs */
+			snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, 0x3);
+
+			/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
+			snd_soc_component_write(component, WM8991_ANTIPOP2, WM8991_BUFIOEN);
+		}
+
+		/* VMID=2*250k */
+		val = snd_soc_component_read32(component, WM8991_POWER_MANAGEMENT_1) &
+		      ~WM8991_VMID_MODE_MASK;
+		snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, val | 0x4);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* Enable POBCTRL and SOFT_ST */
+		snd_soc_component_write(component, WM8991_ANTIPOP2, WM8991_SOFTST |
+			      WM8991_POBCTRL | WM8991_BUFIOEN);
+
+		/* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
+		snd_soc_component_write(component, WM8991_ANTIPOP2, WM8991_SOFTST |
+			      WM8991_BUFDCOPEN | WM8991_POBCTRL |
+			      WM8991_BUFIOEN);
+
+		/* mute DAC */
+		val = snd_soc_component_read32(component, WM8991_DAC_CTRL);
+		snd_soc_component_write(component, WM8991_DAC_CTRL, val | WM8991_DAC_MUTE);
+
+		/* Enable any disabled outputs */
+		snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, 0x1f03);
+
+		/* Disable VMID */
+		snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, 0x1f01);
+
+		msleep(300);
+
+		/* Enable all output discharge bits */
+		snd_soc_component_write(component, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
+			      WM8991_DIS_RLINE | WM8991_DIS_OUT3 |
+			      WM8991_DIS_OUT4 | WM8991_DIS_LOUT |
+			      WM8991_DIS_ROUT);
+
+		/* Disable VREF */
+		snd_soc_component_write(component, WM8991_POWER_MANAGEMENT_1, 0x0);
+
+		/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
+		snd_soc_component_write(component, WM8991_ANTIPOP2, 0x0);
+		regcache_mark_dirty(wm8991->regmap);
+		break;
+	}
+
+	return 0;
+}
+
+#define WM8991_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops wm8991_ops = {
+	.hw_params = wm8991_hw_params,
+	.digital_mute = wm8991_mute,
+	.set_fmt = wm8991_set_dai_fmt,
+	.set_clkdiv = wm8991_set_dai_clkdiv,
+	.set_pll = wm8991_set_dai_pll
+};
+
+/*
+ * The WM8991 supports 2 different and mutually exclusive DAI
+ * configurations.
+ *
+ * 1. ADC/DAC on Primary Interface
+ * 2. ADC on Primary Interface/DAC on secondary
+ */
+static struct snd_soc_dai_driver wm8991_dai = {
+	/* ADC/DAC on primary */
+	.name = "wm8991",
+	.id = 1,
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = WM8991_FORMATS
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = WM8991_FORMATS
+	},
+	.ops = &wm8991_ops
+};
+
+static const struct snd_soc_component_driver soc_component_dev_wm8991 = {
+	.set_bias_level		= wm8991_set_bias_level,
+	.controls		= wm8991_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8991_snd_controls),
+	.dapm_widgets		= wm8991_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8991_dapm_widgets),
+	.dapm_routes		= wm8991_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8991_dapm_routes),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8991_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = WM8991_PLL3,
+	.volatile_reg = wm8991_volatile,
+	.reg_defaults = wm8991_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8991_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int wm8991_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8991_priv *wm8991;
+	unsigned int val;
+	int ret;
+
+	wm8991 = devm_kzalloc(&i2c->dev, sizeof(*wm8991), GFP_KERNEL);
+	if (!wm8991)
+		return -ENOMEM;
+
+	wm8991->regmap = devm_regmap_init_i2c(i2c, &wm8991_regmap);
+	if (IS_ERR(wm8991->regmap))
+		return PTR_ERR(wm8991->regmap);
+
+	i2c_set_clientdata(i2c, wm8991);
+
+	ret = regmap_read(wm8991->regmap, WM8991_RESET, &val);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to read device ID: %d\n", ret);
+		return ret;
+	}
+	if (val != 0x8991) {
+		dev_err(&i2c->dev, "Device with ID %x is not a WM8991\n", val);
+		return -EINVAL;
+	}
+
+	ret = regmap_write(wm8991->regmap, WM8991_RESET, 0);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
+		return ret;
+	}
+
+	regmap_update_bits(wm8991->regmap, WM8991_AUDIO_INTERFACE_4,
+			   WM8991_ALRCGPIO1, WM8991_ALRCGPIO1);
+
+	regmap_update_bits(wm8991->regmap, WM8991_GPIO1_GPIO2,
+			   WM8991_GPIO1_SEL_MASK, 1);
+
+	regmap_update_bits(wm8991->regmap, WM8991_POWER_MANAGEMENT_1,
+			   WM8991_VREF_ENA | WM8991_VMID_MODE_MASK,
+			   WM8991_VREF_ENA | WM8991_VMID_MODE_MASK);
+
+	regmap_update_bits(wm8991->regmap, WM8991_POWER_MANAGEMENT_2,
+			   WM8991_OPCLK_ENA, WM8991_OPCLK_ENA);
+
+	regmap_write(wm8991->regmap, WM8991_DAC_CTRL, 0);
+	regmap_write(wm8991->regmap, WM8991_LEFT_OUTPUT_VOLUME,
+		     0x50 | (1<<8));
+	regmap_write(wm8991->regmap, WM8991_RIGHT_OUTPUT_VOLUME,
+		     0x50 | (1<<8));
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_wm8991, &wm8991_dai, 1);
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8991_i2c_id[] = {
+	{ "wm8991", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8991_i2c_id);
+
+static struct i2c_driver wm8991_i2c_driver = {
+	.driver = {
+		.name = "wm8991",
+	},
+	.probe = wm8991_i2c_probe,
+	.id_table = wm8991_i2c_id,
+};
+
+module_i2c_driver(wm8991_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8991 driver");
+MODULE_AUTHOR("Graeme Gregory");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8991.h b/sound/soc/codecs/wm8991.h
new file mode 100644
index 0000000..08ed383
--- /dev/null
+++ b/sound/soc/codecs/wm8991.h
@@ -0,0 +1,819 @@
+/*
+ * wm8991.h  --  audio driver for WM8991
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _WM8991_H
+#define _WM8991_H
+
+/*
+ * Register values.
+ */
+#define WM8991_RESET                            0x00
+#define WM8991_POWER_MANAGEMENT_1               0x01
+#define WM8991_POWER_MANAGEMENT_2               0x02
+#define WM8991_POWER_MANAGEMENT_3               0x03
+#define WM8991_AUDIO_INTERFACE_1                0x04
+#define WM8991_AUDIO_INTERFACE_2                0x05
+#define WM8991_CLOCKING_1                       0x06
+#define WM8991_CLOCKING_2                       0x07
+#define WM8991_AUDIO_INTERFACE_3                0x08
+#define WM8991_AUDIO_INTERFACE_4                0x09
+#define WM8991_DAC_CTRL                         0x0A
+#define WM8991_LEFT_DAC_DIGITAL_VOLUME          0x0B
+#define WM8991_RIGHT_DAC_DIGITAL_VOLUME         0x0C
+#define WM8991_DIGITAL_SIDE_TONE                0x0D
+#define WM8991_ADC_CTRL                         0x0E
+#define WM8991_LEFT_ADC_DIGITAL_VOLUME          0x0F
+#define WM8991_RIGHT_ADC_DIGITAL_VOLUME         0x10
+#define WM8991_GPIO_CTRL_1                      0x12
+#define WM8991_GPIO1_GPIO2                      0x13
+#define WM8991_GPIO3_GPIO4                      0x14
+#define WM8991_GPIO5_GPIO6                      0x15
+#define WM8991_GPIOCTRL_2                       0x16
+#define WM8991_GPIO_POL                         0x17
+#define WM8991_LEFT_LINE_INPUT_1_2_VOLUME       0x18
+#define WM8991_LEFT_LINE_INPUT_3_4_VOLUME       0x19
+#define WM8991_RIGHT_LINE_INPUT_1_2_VOLUME      0x1A
+#define WM8991_RIGHT_LINE_INPUT_3_4_VOLUME      0x1B
+#define WM8991_LEFT_OUTPUT_VOLUME               0x1C
+#define WM8991_RIGHT_OUTPUT_VOLUME              0x1D
+#define WM8991_LINE_OUTPUTS_VOLUME              0x1E
+#define WM8991_OUT3_4_VOLUME                    0x1F
+#define WM8991_LEFT_OPGA_VOLUME                 0x20
+#define WM8991_RIGHT_OPGA_VOLUME                0x21
+#define WM8991_SPEAKER_VOLUME                   0x22
+#define WM8991_CLASSD1                          0x23
+#define WM8991_CLASSD3                          0x25
+#define WM8991_INPUT_MIXER1                     0x27
+#define WM8991_INPUT_MIXER2                     0x28
+#define WM8991_INPUT_MIXER3                     0x29
+#define WM8991_INPUT_MIXER4                     0x2A
+#define WM8991_INPUT_MIXER5                     0x2B
+#define WM8991_INPUT_MIXER6                     0x2C
+#define WM8991_OUTPUT_MIXER1                    0x2D
+#define WM8991_OUTPUT_MIXER2                    0x2E
+#define WM8991_OUTPUT_MIXER3                    0x2F
+#define WM8991_OUTPUT_MIXER4                    0x30
+#define WM8991_OUTPUT_MIXER5                    0x31
+#define WM8991_OUTPUT_MIXER6                    0x32
+#define WM8991_OUT3_4_MIXER                     0x33
+#define WM8991_LINE_MIXER1                      0x34
+#define WM8991_LINE_MIXER2                      0x35
+#define WM8991_SPEAKER_MIXER                    0x36
+#define WM8991_ADDITIONAL_CONTROL               0x37
+#define WM8991_ANTIPOP1                         0x38
+#define WM8991_ANTIPOP2                         0x39
+#define WM8991_MICBIAS                          0x3A
+#define WM8991_PLL1                             0x3C
+#define WM8991_PLL2                             0x3D
+#define WM8991_PLL3                             0x3E
+
+#define WM8991_REGISTER_COUNT                   60
+#define WM8991_MAX_REGISTER                     0x3F
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Reset
+ */
+#define WM8991_SW_RESET_CHIP_ID_MASK            0xFFFF  /* SW_RESET_CHIP_ID - [15:0] */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM8991_SPK_ENA                          0x1000  /* SPK_ENA */
+#define WM8991_SPK_ENA_BIT			12
+#define WM8991_OUT3_ENA                         0x0800  /* OUT3_ENA */
+#define WM8991_OUT3_ENA_BIT			11
+#define WM8991_OUT4_ENA                         0x0400  /* OUT4_ENA */
+#define WM8991_OUT4_ENA_BIT			10
+#define WM8991_LOUT_ENA                         0x0200  /* LOUT_ENA */
+#define WM8991_LOUT_ENA_BIT			9
+#define WM8991_ROUT_ENA                         0x0100  /* ROUT_ENA */
+#define WM8991_ROUT_ENA_BIT			8
+#define WM8991_MICBIAS_ENA                      0x0010  /* MICBIAS_ENA */
+#define WM8991_MICBIAS_ENA_BIT			4
+#define WM8991_VMID_MODE_MASK                   0x0006  /* VMID_MODE - [2:1] */
+#define WM8991_VREF_ENA                         0x0001  /* VREF_ENA */
+#define WM8991_VREF_ENA_BIT			0
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM8991_PLL_ENA                          0x8000  /* PLL_ENA */
+#define WM8991_PLL_ENA_BIT			15
+#define WM8991_TSHUT_ENA                        0x4000  /* TSHUT_ENA */
+#define WM8991_TSHUT_ENA_BIT			14
+#define WM8991_TSHUT_OPDIS                      0x2000  /* TSHUT_OPDIS */
+#define WM8991_TSHUT_OPDIS_BIT			13
+#define WM8991_OPCLK_ENA                        0x0800  /* OPCLK_ENA */
+#define WM8991_OPCLK_ENA_BIT			11
+#define WM8991_AINL_ENA                         0x0200  /* AINL_ENA */
+#define WM8991_AINL_ENA_BIT			9
+#define WM8991_AINR_ENA                         0x0100  /* AINR_ENA */
+#define WM8991_AINR_ENA_BIT			8
+#define WM8991_LIN34_ENA                        0x0080  /* LIN34_ENA */
+#define WM8991_LIN34_ENA_BIT			7
+#define WM8991_LIN12_ENA                        0x0040  /* LIN12_ENA */
+#define WM8991_LIN12_ENA_BIT			6
+#define WM8991_RIN34_ENA                        0x0020  /* RIN34_ENA */
+#define WM8991_RIN34_ENA_BIT			5
+#define WM8991_RIN12_ENA                        0x0010  /* RIN12_ENA */
+#define WM8991_RIN12_ENA_BIT			4
+#define WM8991_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8991_ADCL_ENA_BIT			1
+#define WM8991_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8991_ADCR_ENA_BIT			0
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM8991_LON_ENA                          0x2000  /* LON_ENA */
+#define WM8991_LON_ENA_BIT			13
+#define WM8991_LOP_ENA                          0x1000  /* LOP_ENA */
+#define WM8991_LOP_ENA_BIT			12
+#define WM8991_RON_ENA                          0x0800  /* RON_ENA */
+#define WM8991_RON_ENA_BIT			11
+#define WM8991_ROP_ENA                          0x0400  /* ROP_ENA */
+#define WM8991_ROP_ENA_BIT			10
+#define WM8991_LOPGA_ENA                        0x0080  /* LOPGA_ENA */
+#define WM8991_LOPGA_ENA_BIT			7
+#define WM8991_ROPGA_ENA                        0x0040  /* ROPGA_ENA */
+#define WM8991_ROPGA_ENA_BIT			6
+#define WM8991_LOMIX_ENA                        0x0020  /* LOMIX_ENA */
+#define WM8991_LOMIX_ENA_BIT			5
+#define WM8991_ROMIX_ENA                        0x0010  /* ROMIX_ENA */
+#define WM8991_ROMIX_ENA_BIT			4
+#define WM8991_DACL_ENA                         0x0002  /* DACL_ENA */
+#define WM8991_DACL_ENA_BIT			1
+#define WM8991_DACR_ENA                         0x0001  /* DACR_ENA */
+#define WM8991_DACR_ENA_BIT			0
+
+/*
+ * R4 (0x04) - Audio Interface (1)
+ */
+#define WM8991_AIFADCL_SRC                      0x8000  /* AIFADCL_SRC */
+#define WM8991_AIFADCR_SRC                      0x4000  /* AIFADCR_SRC */
+#define WM8991_AIFADC_TDM                       0x2000  /* AIFADC_TDM */
+#define WM8991_AIFADC_TDM_CHAN                  0x1000  /* AIFADC_TDM_CHAN */
+#define WM8991_AIF_BCLK_INV                     0x0100  /* AIF_BCLK_INV */
+#define WM8991_AIF_LRCLK_INV                    0x0080  /* AIF_LRCLK_INV */
+#define WM8991_AIF_WL_MASK                      0x0060  /* AIF_WL - [6:5] */
+#define WM8991_AIF_WL_16BITS			(0 << 5)
+#define WM8991_AIF_WL_20BITS			(1 << 5)
+#define WM8991_AIF_WL_24BITS			(2 << 5)
+#define WM8991_AIF_WL_32BITS			(3 << 5)
+#define WM8991_AIF_FMT_MASK                     0x0018  /* AIF_FMT - [4:3] */
+#define WM8991_AIF_TMF_RIGHTJ			(0 << 3)
+#define WM8991_AIF_TMF_LEFTJ			(1 << 3)
+#define WM8991_AIF_TMF_I2S			(2 << 3)
+#define WM8991_AIF_TMF_DSP			(3 << 3)
+
+/*
+ * R5 (0x05) - Audio Interface (2)
+ */
+#define WM8991_DACL_SRC                         0x8000  /* DACL_SRC */
+#define WM8991_DACR_SRC                         0x4000  /* DACR_SRC */
+#define WM8991_AIFDAC_TDM                       0x2000  /* AIFDAC_TDM */
+#define WM8991_AIFDAC_TDM_CHAN                  0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8991_DAC_BOOST_MASK                   0x0C00  /* DAC_BOOST - [11:10] */
+#define WM8991_DAC_COMP                         0x0010  /* DAC_COMP */
+#define WM8991_DAC_COMPMODE                     0x0008  /* DAC_COMPMODE */
+#define WM8991_ADC_COMP                         0x0004  /* ADC_COMP */
+#define WM8991_ADC_COMPMODE                     0x0002  /* ADC_COMPMODE */
+#define WM8991_LOOPBACK                         0x0001  /* LOOPBACK */
+
+/*
+ * R6 (0x06) - Clocking (1)
+ */
+#define WM8991_TOCLK_RATE                       0x8000  /* TOCLK_RATE */
+#define WM8991_TOCLK_ENA                        0x4000  /* TOCLK_ENA */
+#define WM8991_OPCLKDIV_MASK                    0x1E00  /* OPCLKDIV - [12:9] */
+#define WM8991_DCLKDIV_MASK                     0x01C0  /* DCLKDIV - [8:6] */
+#define WM8991_BCLK_DIV_MASK                    0x001E  /* BCLK_DIV - [4:1] */
+#define WM8991_BCLK_DIV_1			(0x0 << 1)
+#define WM8991_BCLK_DIV_1_5			(0x1 << 1)
+#define WM8991_BCLK_DIV_2			(0x2 << 1)
+#define WM8991_BCLK_DIV_3			(0x3 << 1)
+#define WM8991_BCLK_DIV_4			(0x4 << 1)
+#define WM8991_BCLK_DIV_5_5			(0x5 << 1)
+#define WM8991_BCLK_DIV_6			(0x6 << 1)
+#define WM8991_BCLK_DIV_8			(0x7 << 1)
+#define WM8991_BCLK_DIV_11			(0x8 << 1)
+#define WM8991_BCLK_DIV_12			(0x9 << 1)
+#define WM8991_BCLK_DIV_16			(0xA << 1)
+#define WM8991_BCLK_DIV_22			(0xB << 1)
+#define WM8991_BCLK_DIV_24			(0xC << 1)
+#define WM8991_BCLK_DIV_32			(0xD << 1)
+#define WM8991_BCLK_DIV_44			(0xE << 1)
+#define WM8991_BCLK_DIV_48			(0xF << 1)
+
+/*
+ * R7 (0x07) - Clocking (2)
+ */
+#define WM8991_MCLK_SRC                         0x8000  /* MCLK_SRC */
+#define WM8991_SYSCLK_SRC                       0x4000  /* SYSCLK_SRC */
+#define WM8991_CLK_FORCE                        0x2000  /* CLK_FORCE */
+#define WM8991_MCLK_DIV_MASK                    0x1800  /* MCLK_DIV - [12:11] */
+#define WM8991_MCLK_DIV_1			(0 << 11)
+#define WM8991_MCLK_DIV_2			( 2 << 11)
+#define WM8991_MCLK_INV                         0x0400  /* MCLK_INV */
+#define WM8991_ADC_CLKDIV_MASK                  0x00E0  /* ADC_CLKDIV - [7:5] */
+#define WM8991_ADC_CLKDIV_1			(0 << 5)
+#define WM8991_ADC_CLKDIV_1_5			(1 << 5)
+#define WM8991_ADC_CLKDIV_2			(2 << 5)
+#define WM8991_ADC_CLKDIV_3			(3 << 5)
+#define WM8991_ADC_CLKDIV_4			(4 << 5)
+#define WM8991_ADC_CLKDIV_5_5			(5 << 5)
+#define WM8991_ADC_CLKDIV_6			(6 << 5)
+#define WM8991_DAC_CLKDIV_MASK                  0x001C  /* DAC_CLKDIV - [4:2] */
+#define WM8991_DAC_CLKDIV_1			(0 << 2)
+#define WM8991_DAC_CLKDIV_1_5			(1 << 2)
+#define WM8991_DAC_CLKDIV_2			(2 << 2)
+#define WM8991_DAC_CLKDIV_3			(3 << 2)
+#define WM8991_DAC_CLKDIV_4			(4 << 2)
+#define WM8991_DAC_CLKDIV_5_5			(5 << 2)
+#define WM8991_DAC_CLKDIV_6			(6 << 2)
+
+/*
+ * R8 (0x08) - Audio Interface (3)
+ */
+#define WM8991_AIF_MSTR1                        0x8000  /* AIF_MSTR1 */
+#define WM8991_AIF_MSTR2                        0x4000  /* AIF_MSTR2 */
+#define WM8991_AIF_SEL                          0x2000  /* AIF_SEL */
+#define WM8991_ADCLRC_DIR                       0x0800  /* ADCLRC_DIR */
+#define WM8991_ADCLRC_RATE_MASK                 0x07FF  /* ADCLRC_RATE - [10:0] */
+
+/*
+ * R9 (0x09) - Audio Interface (4)
+ */
+#define WM8991_ALRCGPIO1                        0x8000  /* ALRCGPIO1 */
+#define WM8991_ALRCBGPIO6                       0x4000  /* ALRCBGPIO6 */
+#define WM8991_AIF_TRIS                         0x2000  /* AIF_TRIS */
+#define WM8991_DACLRC_DIR                       0x0800  /* DACLRC_DIR */
+#define WM8991_DACLRC_RATE_MASK                 0x07FF  /* DACLRC_RATE - [10:0] */
+
+/*
+ * R10 (0x0A) - DAC CTRL
+ */
+#define WM8991_AIF_LRCLKRATE                    0x0400  /* AIF_LRCLKRATE */
+#define WM8991_DAC_MONO                         0x0200  /* DAC_MONO */
+#define WM8991_DAC_SB_FILT                      0x0100  /* DAC_SB_FILT */
+#define WM8991_DAC_MUTERATE                     0x0080  /* DAC_MUTERATE */
+#define WM8991_DAC_MUTEMODE                     0x0040  /* DAC_MUTEMODE */
+#define WM8991_DEEMP_MASK                       0x0030  /* DEEMP - [5:4] */
+#define WM8991_DAC_MUTE                         0x0004  /* DAC_MUTE */
+#define WM8991_DACL_DATINV                      0x0002  /* DACL_DATINV */
+#define WM8991_DACR_DATINV                      0x0001  /* DACR_DATINV */
+
+/*
+ * R11 (0x0B) - Left DAC Digital Volume
+ */
+#define WM8991_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8991_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8991_DACL_VOL_SHIFT			0
+/*
+ * R12 (0x0C) - Right DAC Digital Volume
+ */
+#define WM8991_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8991_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8991_DACR_VOL_SHIFT			0
+/*
+ * R13 (0x0D) - Digital Side Tone
+ */
+#define WM8991_ADCL_DAC_SVOL_MASK               0x0F  /* ADCL_DAC_SVOL - [12:9] */
+#define WM8991_ADCL_DAC_SVOL_SHIFT		9
+#define WM8991_ADCR_DAC_SVOL_MASK               0x0F  /* ADCR_DAC_SVOL - [8:5] */
+#define WM8991_ADCR_DAC_SVOL_SHIFT		5
+#define WM8991_ADC_TO_DACL_MASK                 0x03  /* ADC_TO_DACL - [3:2] */
+#define WM8991_ADC_TO_DACL_SHIFT		2
+#define WM8991_ADC_TO_DACR_MASK                 0x03  /* ADC_TO_DACR - [1:0] */
+#define WM8991_ADC_TO_DACR_SHIFT		0
+
+/*
+ * R14 (0x0E) - ADC CTRL
+ */
+#define WM8991_ADC_HPF_ENA                      0x0100  /* ADC_HPF_ENA */
+#define WM8991_ADC_HPF_ENA_BIT			8
+#define WM8991_ADC_HPF_CUT_MASK                 0x03  /* ADC_HPF_CUT - [6:5] */
+#define WM8991_ADC_HPF_CUT_SHIFT		5
+#define WM8991_ADCL_DATINV                      0x0002  /* ADCL_DATINV */
+#define WM8991_ADCL_DATINV_BIT			1
+#define WM8991_ADCR_DATINV                      0x0001  /* ADCR_DATINV */
+#define WM8991_ADCR_DATINV_BIT			0
+
+/*
+ * R15 (0x0F) - Left ADC Digital Volume
+ */
+#define WM8991_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8991_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8991_ADCL_VOL_SHIFT			0
+
+/*
+ * R16 (0x10) - Right ADC Digital Volume
+ */
+#define WM8991_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8991_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8991_ADCR_VOL_SHIFT			0
+
+/*
+ * R18 (0x12) - GPIO CTRL 1
+ */
+#define WM8991_IRQ                              0x1000  /* IRQ */
+#define WM8991_TEMPOK                           0x0800  /* TEMPOK */
+#define WM8991_MICSHRT                          0x0400  /* MICSHRT */
+#define WM8991_MICDET                           0x0200  /* MICDET */
+#define WM8991_PLL_LCK                          0x0100  /* PLL_LCK */
+#define WM8991_GPI8_STATUS                      0x0080  /* GPI8_STATUS */
+#define WM8991_GPI7_STATUS                      0x0040  /* GPI7_STATUS */
+#define WM8991_GPIO6_STATUS                     0x0020  /* GPIO6_STATUS */
+#define WM8991_GPIO5_STATUS                     0x0010  /* GPIO5_STATUS */
+#define WM8991_GPIO4_STATUS                     0x0008  /* GPIO4_STATUS */
+#define WM8991_GPIO3_STATUS                     0x0004  /* GPIO3_STATUS */
+#define WM8991_GPIO2_STATUS                     0x0002  /* GPIO2_STATUS */
+#define WM8991_GPIO1_STATUS                     0x0001  /* GPIO1_STATUS */
+
+/*
+ * R19 (0x13) - GPIO1 & GPIO2
+ */
+#define WM8991_GPIO2_DEB_ENA                    0x8000  /* GPIO2_DEB_ENA */
+#define WM8991_GPIO2_IRQ_ENA                    0x4000  /* GPIO2_IRQ_ENA */
+#define WM8991_GPIO2_PU                         0x2000  /* GPIO2_PU */
+#define WM8991_GPIO2_PD                         0x1000  /* GPIO2_PD */
+#define WM8991_GPIO2_SEL_MASK                   0x0F00  /* GPIO2_SEL - [11:8] */
+#define WM8991_GPIO1_DEB_ENA                    0x0080  /* GPIO1_DEB_ENA */
+#define WM8991_GPIO1_IRQ_ENA                    0x0040  /* GPIO1_IRQ_ENA */
+#define WM8991_GPIO1_PU                         0x0020  /* GPIO1_PU */
+#define WM8991_GPIO1_PD                         0x0010  /* GPIO1_PD */
+#define WM8991_GPIO1_SEL_MASK                   0x000F  /* GPIO1_SEL - [3:0] */
+
+/*
+ * R20 (0x14) - GPIO3 & GPIO4
+ */
+#define WM8991_GPIO4_DEB_ENA                    0x8000  /* GPIO4_DEB_ENA */
+#define WM8991_GPIO4_IRQ_ENA                    0x4000  /* GPIO4_IRQ_ENA */
+#define WM8991_GPIO4_PU                         0x2000  /* GPIO4_PU */
+#define WM8991_GPIO4_PD                         0x1000  /* GPIO4_PD */
+#define WM8991_GPIO4_SEL_MASK                   0x0F00  /* GPIO4_SEL - [11:8] */
+#define WM8991_GPIO3_DEB_ENA                    0x0080  /* GPIO3_DEB_ENA */
+#define WM8991_GPIO3_IRQ_ENA                    0x0040  /* GPIO3_IRQ_ENA */
+#define WM8991_GPIO3_PU                         0x0020  /* GPIO3_PU */
+#define WM8991_GPIO3_PD                         0x0010  /* GPIO3_PD */
+#define WM8991_GPIO3_SEL_MASK                   0x000F  /* GPIO3_SEL - [3:0] */
+
+/*
+ * R21 (0x15) - GPIO5 & GPIO6
+ */
+#define WM8991_GPIO6_DEB_ENA                    0x8000  /* GPIO6_DEB_ENA */
+#define WM8991_GPIO6_IRQ_ENA                    0x4000  /* GPIO6_IRQ_ENA */
+#define WM8991_GPIO6_PU                         0x2000  /* GPIO6_PU */
+#define WM8991_GPIO6_PD                         0x1000  /* GPIO6_PD */
+#define WM8991_GPIO6_SEL_MASK                   0x0F00  /* GPIO6_SEL - [11:8] */
+#define WM8991_GPIO5_DEB_ENA                    0x0080  /* GPIO5_DEB_ENA */
+#define WM8991_GPIO5_IRQ_ENA                    0x0040  /* GPIO5_IRQ_ENA */
+#define WM8991_GPIO5_PU                         0x0020  /* GPIO5_PU */
+#define WM8991_GPIO5_PD                         0x0010  /* GPIO5_PD */
+#define WM8991_GPIO5_SEL_MASK                   0x000F  /* GPIO5_SEL - [3:0] */
+
+/*
+ * R22 (0x16) - GPIOCTRL 2
+ */
+#define WM8991_RD_3W_ENA                        0x8000  /* RD_3W_ENA */
+#define WM8991_MODE_3W4W                        0x4000  /* MODE_3W4W */
+#define WM8991_TEMPOK_IRQ_ENA                   0x0800  /* TEMPOK_IRQ_ENA */
+#define WM8991_MICSHRT_IRQ_ENA                  0x0400  /* MICSHRT_IRQ_ENA */
+#define WM8991_MICDET_IRQ_ENA                   0x0200  /* MICDET_IRQ_ENA */
+#define WM8991_PLL_LCK_IRQ_ENA                  0x0100  /* PLL_LCK_IRQ_ENA */
+#define WM8991_GPI8_DEB_ENA                     0x0080  /* GPI8_DEB_ENA */
+#define WM8991_GPI8_IRQ_ENA                     0x0040  /* GPI8_IRQ_ENA */
+#define WM8991_GPI8_ENA                         0x0010  /* GPI8_ENA */
+#define WM8991_GPI7_DEB_ENA                     0x0008  /* GPI7_DEB_ENA */
+#define WM8991_GPI7_IRQ_ENA                     0x0004  /* GPI7_IRQ_ENA */
+#define WM8991_GPI7_ENA                         0x0001  /* GPI7_ENA */
+
+/*
+ * R23 (0x17) - GPIO_POL
+ */
+#define WM8991_IRQ_INV                          0x1000  /* IRQ_INV */
+#define WM8991_TEMPOK_POL                       0x0800  /* TEMPOK_POL */
+#define WM8991_MICSHRT_POL                      0x0400  /* MICSHRT_POL */
+#define WM8991_MICDET_POL                       0x0200  /* MICDET_POL */
+#define WM8991_PLL_LCK_POL                      0x0100  /* PLL_LCK_POL */
+#define WM8991_GPI8_POL                         0x0080  /* GPI8_POL */
+#define WM8991_GPI7_POL                         0x0040  /* GPI7_POL */
+#define WM8991_GPIO6_POL                        0x0020  /* GPIO6_POL */
+#define WM8991_GPIO5_POL                        0x0010  /* GPIO5_POL */
+#define WM8991_GPIO4_POL                        0x0008  /* GPIO4_POL */
+#define WM8991_GPIO3_POL                        0x0004  /* GPIO3_POL */
+#define WM8991_GPIO2_POL                        0x0002  /* GPIO2_POL */
+#define WM8991_GPIO1_POL                        0x0001  /* GPIO1_POL */
+
+/*
+ * R24 (0x18) - Left Line Input 1&2 Volume
+ */
+#define WM8991_IPVU                             0x0100  /* IPVU */
+#define WM8991_LI12MUTE                         0x0080  /* LI12MUTE */
+#define WM8991_LI12MUTE_BIT			7
+#define WM8991_LI12ZC                           0x0040  /* LI12ZC */
+#define WM8991_LI12ZC_BIT			6
+#define WM8991_LIN12VOL_MASK                    0x001F  /* LIN12VOL - [4:0] */
+#define WM8991_LIN12VOL_SHIFT			0
+/*
+ * R25 (0x19) - Left Line Input 3&4 Volume
+ */
+#define WM8991_IPVU                             0x0100  /* IPVU */
+#define WM8991_LI34MUTE                         0x0080  /* LI34MUTE */
+#define WM8991_LI34MUTE_BIT			7
+#define WM8991_LI34ZC                           0x0040  /* LI34ZC */
+#define WM8991_LI34ZC_BIT			6
+#define WM8991_LIN34VOL_MASK                    0x001F  /* LIN34VOL - [4:0] */
+#define WM8991_LIN34VOL_SHIFT			0
+
+/*
+ * R26 (0x1A) - Right Line Input 1&2 Volume
+ */
+#define WM8991_IPVU                             0x0100  /* IPVU */
+#define WM8991_RI12MUTE                         0x0080  /* RI12MUTE */
+#define WM8991_RI12MUTE_BIT			7
+#define WM8991_RI12ZC                           0x0040  /* RI12ZC */
+#define WM8991_RI12ZC_BIT			6
+#define WM8991_RIN12VOL_MASK                    0x001F  /* RIN12VOL - [4:0] */
+#define WM8991_RIN12VOL_SHIFT			0
+
+/*
+ * R27 (0x1B) - Right Line Input 3&4 Volume
+ */
+#define WM8991_IPVU                             0x0100  /* IPVU */
+#define WM8991_RI34MUTE                         0x0080  /* RI34MUTE */
+#define WM8991_RI34MUTE_BIT			7
+#define WM8991_RI34ZC                           0x0040  /* RI34ZC */
+#define WM8991_RI34ZC_BIT			6
+#define WM8991_RIN34VOL_MASK                    0x001F  /* RIN34VOL - [4:0] */
+#define WM8991_RIN34VOL_SHIFT			0
+
+/*
+ * R28 (0x1C) - Left Output Volume
+ */
+#define WM8991_OPVU                             0x0100  /* OPVU */
+#define WM8991_LOZC                             0x0080  /* LOZC */
+#define WM8991_LOZC_BIT				7
+#define WM8991_LOUTVOL_MASK                     0x007F  /* LOUTVOL - [6:0] */
+#define WM8991_LOUTVOL_SHIFT			0
+/*
+ * R29 (0x1D) - Right Output Volume
+ */
+#define WM8991_OPVU                             0x0100  /* OPVU */
+#define WM8991_ROZC                             0x0080  /* ROZC */
+#define WM8991_ROZC_BIT				7
+#define WM8991_ROUTVOL_MASK                     0x007F  /* ROUTVOL - [6:0] */
+#define WM8991_ROUTVOL_SHIFT			0
+/*
+ * R30 (0x1E) - Line Outputs Volume
+ */
+#define WM8991_LONMUTE                          0x0040  /* LONMUTE */
+#define WM8991_LONMUTE_BIT			6
+#define WM8991_LOPMUTE                          0x0020  /* LOPMUTE */
+#define WM8991_LOPMUTE_BIT			5
+#define WM8991_LOATTN                           0x0010  /* LOATTN */
+#define WM8991_LOATTN_BIT			4
+#define WM8991_RONMUTE                          0x0004  /* RONMUTE */
+#define WM8991_RONMUTE_BIT			2
+#define WM8991_ROPMUTE                          0x0002  /* ROPMUTE */
+#define WM8991_ROPMUTE_BIT			1
+#define WM8991_ROATTN                           0x0001  /* ROATTN */
+#define WM8991_ROATTN_BIT			0
+
+/*
+ * R31 (0x1F) - Out3/4 Volume
+ */
+#define WM8991_OUT3MUTE                         0x0020  /* OUT3MUTE */
+#define WM8991_OUT3MUTE_BIT			5
+#define WM8991_OUT3ATTN                         0x0010  /* OUT3ATTN */
+#define WM8991_OUT3ATTN_BIT			4
+#define WM8991_OUT4MUTE                         0x0002  /* OUT4MUTE */
+#define WM8991_OUT4MUTE_BIT			1
+#define WM8991_OUT4ATTN                         0x0001  /* OUT4ATTN */
+#define WM8991_OUT4ATTN_BIT			0
+
+/*
+ * R32 (0x20) - Left OPGA Volume
+ */
+#define WM8991_OPVU                             0x0100  /* OPVU */
+#define WM8991_LOPGAZC                          0x0080  /* LOPGAZC */
+#define WM8991_LOPGAZC_BIT			7
+#define WM8991_LOPGAVOL_MASK                    0x007F  /* LOPGAVOL - [6:0] */
+#define WM8991_LOPGAVOL_SHIFT			0
+
+/*
+ * R33 (0x21) - Right OPGA Volume
+ */
+#define WM8991_OPVU                             0x0100  /* OPVU */
+#define WM8991_ROPGAZC                          0x0080  /* ROPGAZC */
+#define WM8991_ROPGAZC_BIT			7
+#define WM8991_ROPGAVOL_MASK                    0x007F  /* ROPGAVOL - [6:0] */
+#define WM8991_ROPGAVOL_SHIFT			0
+/*
+ * R34 (0x22) - Speaker Volume
+ */
+#define WM8991_SPKVOL_MASK                      0x0003  /* SPKVOL - [1:0] */
+#define WM8991_SPKVOL_SHIFT			0
+
+/*
+ * R35 (0x23) - ClassD1
+ */
+#define WM8991_CDMODE                           0x0100  /* CDMODE */
+#define WM8991_CDMODE_BIT			8
+
+/*
+ * R37 (0x25) - ClassD3
+ */
+#define WM8991_DCGAIN_MASK                      0x0007  /* DCGAIN - [5:3] */
+#define WM8991_DCGAIN_SHIFT			3
+#define WM8991_ACGAIN_MASK                      0x0007  /* ACGAIN - [2:0] */
+#define WM8991_ACGAIN_SHIFT			0
+/*
+ * R39 (0x27) - Input Mixer1
+ */
+#define WM8991_AINLMODE_MASK                    0x000C  /* AINLMODE - [3:2] */
+#define WM8991_AINLMODE_SHIFT			2
+#define WM8991_AINRMODE_MASK                    0x0003  /* AINRMODE - [1:0] */
+#define WM8991_AINRMODE_SHIFT			0
+
+/*
+ * R40 (0x28) - Input Mixer2
+ */
+#define WM8991_LMP4								0x0080	/* LMP4 */
+#define WM8991_LMP4_BIT                         7		/* LMP4 */
+#define WM8991_LMN3                             0x0040  /* LMN3 */
+#define WM8991_LMN3_BIT                         6       /* LMN3 */
+#define WM8991_LMP2                             0x0020  /* LMP2 */
+#define WM8991_LMP2_BIT                         5       /* LMP2 */
+#define WM8991_LMN1                             0x0010  /* LMN1 */
+#define WM8991_LMN1_BIT                         4       /* LMN1 */
+#define WM8991_RMP4                             0x0008  /* RMP4 */
+#define WM8991_RMP4_BIT                         3       /* RMP4 */
+#define WM8991_RMN3                             0x0004  /* RMN3 */
+#define WM8991_RMN3_BIT                         2       /* RMN3 */
+#define WM8991_RMP2                             0x0002  /* RMP2 */
+#define WM8991_RMP2_BIT                         1       /* RMP2 */
+#define WM8991_RMN1                             0x0001  /* RMN1 */
+#define WM8991_RMN1_BIT                         0       /* RMN1 */
+
+/*
+ * R41 (0x29) - Input Mixer3
+ */
+#define WM8991_L34MNB                           0x0100  /* L34MNB */
+#define WM8991_L34MNB_BIT			8
+#define WM8991_L34MNBST                         0x0080  /* L34MNBST */
+#define WM8991_L34MNBST_BIT			7
+#define WM8991_L12MNB                           0x0020  /* L12MNB */
+#define WM8991_L12MNB_BIT			5
+#define WM8991_L12MNBST                         0x0010  /* L12MNBST */
+#define WM8991_L12MNBST_BIT			4
+#define WM8991_LDBVOL_MASK                      0x0007  /* LDBVOL - [2:0] */
+#define WM8991_LDBVOL_SHIFT			0
+
+/*
+ * R42 (0x2A) - Input Mixer4
+ */
+#define WM8991_R34MNB                           0x0100  /* R34MNB */
+#define WM8991_R34MNB_BIT			8
+#define WM8991_R34MNBST                         0x0080  /* R34MNBST */
+#define WM8991_R34MNBST_BIT			7
+#define WM8991_R12MNB                           0x0020  /* R12MNB */
+#define WM8991_R12MNB_BIT			5
+#define WM8991_R12MNBST                         0x0010  /* R12MNBST */
+#define WM8991_R12MNBST_BIT			4
+#define WM8991_RDBVOL_MASK                      0x0007  /* RDBVOL - [2:0] */
+#define WM8991_RDBVOL_SHIFT			0
+
+/*
+ * R43 (0x2B) - Input Mixer5
+ */
+#define WM8991_LI2BVOL_MASK                     0x07  /* LI2BVOL - [8:6] */
+#define WM8991_LI2BVOL_SHIFT			6
+#define WM8991_LR4BVOL_MASK                     0x07  /* LR4BVOL - [5:3] */
+#define WM8991_LR4BVOL_SHIFT			3
+#define WM8991_LL4BVOL_MASK                     0x07  /* LL4BVOL - [2:0] */
+#define WM8991_LL4BVOL_SHIFT			0
+
+/*
+ * R44 (0x2C) - Input Mixer6
+ */
+#define WM8991_RI2BVOL_MASK                     0x07  /* RI2BVOL - [8:6] */
+#define WM8991_RI2BVOL_SHIFT			6
+#define WM8991_RL4BVOL_MASK                     0x07  /* RL4BVOL - [5:3] */
+#define WM8991_RL4BVOL_SHIFT			3
+#define WM8991_RR4BVOL_MASK                     0x07  /* RR4BVOL - [2:0] */
+#define WM8991_RR4BVOL_SHIFT			0
+
+/*
+ * R45 (0x2D) - Output Mixer1
+ */
+#define WM8991_LRBLO                            0x0080  /* LRBLO */
+#define WM8991_LRBLO_BIT			7
+#define WM8991_LLBLO                            0x0040  /* LLBLO */
+#define WM8991_LLBLO_BIT			6
+#define WM8991_LRI3LO                           0x0020  /* LRI3LO */
+#define WM8991_LRI3LO_BIT			5
+#define WM8991_LLI3LO                           0x0010  /* LLI3LO */
+#define WM8991_LLI3LO_BIT			4
+#define WM8991_LR12LO                           0x0008  /* LR12LO */
+#define WM8991_LR12LO_BIT			3
+#define WM8991_LL12LO                           0x0004  /* LL12LO */
+#define WM8991_LL12LO_BIT			2
+#define WM8991_LDLO                             0x0001  /* LDLO */
+#define WM8991_LDLO_BIT				0
+
+/*
+ * R46 (0x2E) - Output Mixer2
+ */
+#define WM8991_RLBRO                            0x0080  /* RLBRO */
+#define WM8991_RLBRO_BIT			7
+#define WM8991_RRBRO                            0x0040  /* RRBRO */
+#define WM8991_RRBRO_BIT			6
+#define WM8991_RLI3RO                           0x0020  /* RLI3RO */
+#define WM8991_RLI3RO_BIT			5
+#define WM8991_RRI3RO                           0x0010  /* RRI3RO */
+#define WM8991_RRI3RO_BIT			4
+#define WM8991_RL12RO                           0x0008  /* RL12RO */
+#define WM8991_RL12RO_BIT			3
+#define WM8991_RR12RO                           0x0004  /* RR12RO */
+#define WM8991_RR12RO_BIT			2
+#define WM8991_RDRO                             0x0001  /* RDRO */
+#define WM8991_RDRO_BIT				0
+
+/*
+ * R47 (0x2F) - Output Mixer3
+ */
+#define WM8991_LLI3LOVOL_MASK                   0x07  /* LLI3LOVOL - [8:6] */
+#define WM8991_LLI3LOVOL_SHIFT			6
+#define WM8991_LR12LOVOL_MASK                   0x07  /* LR12LOVOL - [5:3] */
+#define WM8991_LR12LOVOL_SHIFT			3
+#define WM8991_LL12LOVOL_MASK                   0x07  /* LL12LOVOL - [2:0] */
+#define WM8991_LL12LOVOL_SHIFT			0
+
+/*
+ * R48 (0x30) - Output Mixer4
+ */
+#define WM8991_RRI3ROVOL_MASK                   0x07  /* RRI3ROVOL - [8:6] */
+#define WM8991_RRI3ROVOL_SHIFT			6
+#define WM8991_RL12ROVOL_MASK                   0x07  /* RL12ROVOL - [5:3] */
+#define WM8991_RL12ROVOL_SHIFT			3
+#define WM8991_RR12ROVOL_MASK                   0x07  /* RR12ROVOL - [2:0] */
+#define WM8991_RR12ROVOL_SHIFT			0
+
+/*
+ * R49 (0x31) - Output Mixer5
+ */
+#define WM8991_LRI3LOVOL_MASK                   0x07  /* LRI3LOVOL - [8:6] */
+#define WM8991_LRI3LOVOL_SHIFT			6
+#define WM8991_LRBLOVOL_MASK                    0x07  /* LRBLOVOL - [5:3] */
+#define WM8991_LRBLOVOL_SHIFT			3
+#define WM8991_LLBLOVOL_MASK                    0x07  /* LLBLOVOL - [2:0] */
+#define WM8991_LLBLOVOL_SHIFT			0
+
+/*
+ * R50 (0x32) - Output Mixer6
+ */
+#define WM8991_RLI3ROVOL_MASK                   0x07  /* RLI3ROVOL - [8:6] */
+#define WM8991_RLI3ROVOL_SHIFT			6
+#define WM8991_RLBROVOL_MASK                    0x07  /* RLBROVOL - [5:3] */
+#define WM8991_RLBROVOL_SHIFT			3
+#define WM8991_RRBROVOL_MASK                    0x07  /* RRBROVOL - [2:0] */
+#define WM8991_RRBROVOL_SHIFT			0
+
+/*
+ * R51 (0x33) - Out3/4 Mixer
+ */
+#define WM8991_VSEL_MASK                        0x0180  /* VSEL - [8:7] */
+#define WM8991_LI4O3                            0x0020  /* LI4O3 */
+#define WM8991_LI4O3_BIT			5
+#define WM8991_LPGAO3                           0x0010  /* LPGAO3 */
+#define WM8991_LPGAO3_BIT			4
+#define WM8991_RI4O4                            0x0002  /* RI4O4 */
+#define WM8991_RI4O4_BIT			1
+#define WM8991_RPGAO4                           0x0001  /* RPGAO4 */
+#define WM8991_RPGAO4_BIT			0
+/*
+ * R52 (0x34) - Line Mixer1
+ */
+#define WM8991_LLOPGALON                        0x0040  /* LLOPGALON */
+#define WM8991_LLOPGALON_BIT			6
+#define WM8991_LROPGALON                        0x0020  /* LROPGALON */
+#define WM8991_LROPGALON_BIT			5
+#define WM8991_LOPLON                           0x0010  /* LOPLON */
+#define WM8991_LOPLON_BIT			4
+#define WM8991_LR12LOP                          0x0004  /* LR12LOP */
+#define WM8991_LR12LOP_BIT			2
+#define WM8991_LL12LOP                          0x0002  /* LL12LOP */
+#define WM8991_LL12LOP_BIT			1
+#define WM8991_LLOPGALOP                        0x0001  /* LLOPGALOP */
+#define WM8991_LLOPGALOP_BIT			0
+/*
+ * R53 (0x35) - Line Mixer2
+ */
+#define WM8991_RROPGARON                        0x0040  /* RROPGARON */
+#define WM8991_RROPGARON_BIT			6
+#define WM8991_RLOPGARON                        0x0020  /* RLOPGARON */
+#define WM8991_RLOPGARON_BIT			5
+#define WM8991_ROPRON                           0x0010  /* ROPRON */
+#define WM8991_ROPRON_BIT			4
+#define WM8991_RL12ROP                          0x0004  /* RL12ROP */
+#define WM8991_RL12ROP_BIT			2
+#define WM8991_RR12ROP                          0x0002  /* RR12ROP */
+#define WM8991_RR12ROP_BIT			1
+#define WM8991_RROPGAROP                        0x0001  /* RROPGAROP */
+#define WM8991_RROPGAROP_BIT			0
+
+/*
+ * R54 (0x36) - Speaker Mixer
+ */
+#define WM8991_LB2SPK                           0x0080  /* LB2SPK */
+#define WM8991_LB2SPK_BIT			7
+#define WM8991_RB2SPK                           0x0040  /* RB2SPK */
+#define WM8991_RB2SPK_BIT			6
+#define WM8991_LI2SPK                           0x0020  /* LI2SPK */
+#define WM8991_LI2SPK_BIT			5
+#define WM8991_RI2SPK                           0x0010  /* RI2SPK */
+#define WM8991_RI2SPK_BIT			4
+#define WM8991_LOPGASPK                         0x0008  /* LOPGASPK */
+#define WM8991_LOPGASPK_BIT			3
+#define WM8991_ROPGASPK                         0x0004  /* ROPGASPK */
+#define WM8991_ROPGASPK_BIT			2
+#define WM8991_LDSPK                            0x0002  /* LDSPK */
+#define WM8991_LDSPK_BIT			1
+#define WM8991_RDSPK                            0x0001  /* RDSPK */
+#define WM8991_RDSPK_BIT			0
+
+/*
+ * R55 (0x37) - Additional Control
+ */
+#define WM8991_VROI                             0x0001  /* VROI */
+
+/*
+ * R56 (0x38) - AntiPOP1
+ */
+#define WM8991_DIS_LLINE                        0x0020  /* DIS_LLINE */
+#define WM8991_DIS_RLINE                        0x0010  /* DIS_RLINE */
+#define WM8991_DIS_OUT3                         0x0008  /* DIS_OUT3 */
+#define WM8991_DIS_OUT4                         0x0004  /* DIS_OUT4 */
+#define WM8991_DIS_LOUT                         0x0002  /* DIS_LOUT */
+#define WM8991_DIS_ROUT                         0x0001  /* DIS_ROUT */
+
+/*
+ * R57 (0x39) - AntiPOP2
+ */
+#define WM8991_SOFTST                           0x0040  /* SOFTST */
+#define WM8991_BUFIOEN                          0x0008  /* BUFIOEN */
+#define WM8991_BUFDCOPEN                        0x0004  /* BUFDCOPEN */
+#define WM8991_POBCTRL                          0x0002  /* POBCTRL */
+#define WM8991_VMIDTOG                          0x0001  /* VMIDTOG */
+
+/*
+ * R58 (0x3A) - MICBIAS
+ */
+#define WM8991_MCDSCTH_MASK                     0x00C0  /* MCDSCTH - [7:6] */
+#define WM8991_MCDTHR_MASK                      0x0038  /* MCDTHR - [5:3] */
+#define WM8991_MCD                              0x0004  /* MCD */
+#define WM8991_MBSEL                            0x0001  /* MBSEL */
+
+/*
+ * R60 (0x3C) - PLL1
+ */
+#define WM8991_SDM                              0x0080  /* SDM */
+#define WM8991_PRESCALE                         0x0040  /* PRESCALE */
+#define WM8991_PLLN_MASK                        0x000F  /* PLLN - [3:0] */
+
+/*
+ * R61 (0x3D) - PLL2
+ */
+#define WM8991_PLLK1_MASK                       0x00FF  /* PLLK1 - [7:0] */
+
+/*
+ * R62 (0x3E) - PLL3
+ */
+#define WM8991_PLLK2_MASK                       0x00FF  /* PLLK2 - [7:0] */
+
+#define WM8991_MCLK_DIV 0
+#define WM8991_DACCLK_DIV 1
+#define WM8991_ADCCLK_DIV 2
+#define WM8991_BCLK_DIV 3
+
+#define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\
+					 tlv_array) \
+	SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \
+		snd_soc_get_volsw, wm899x_outpga_put_volsw_vu, tlv_array)
+
+#endif /* _WM8991_H */
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
new file mode 100644
index 0000000..2c61655
--- /dev/null
+++ b/sound/soc/codecs/wm8993.c
@@ -0,0 +1,1759 @@
+/*
+ * wm8993.c -- WM8993 ALSA SoC audio driver
+ *
+ * Copyright 2009-12 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/wm8993.h>
+
+#include "wm8993.h"
+#include "wm_hubs.h"
+
+#define WM8993_NUM_SUPPLIES 6
+static const char *wm8993_supply_names[WM8993_NUM_SUPPLIES] = {
+	"DCVDD",
+	"DBVDD",
+	"AVDD1",
+	"AVDD2",
+	"CPVDD",
+	"SPKVDD",
+};
+
+static const struct reg_default wm8993_reg_defaults[] = {
+	{ 1,   0x0000 },     /* R1   - Power Management (1) */
+	{ 2,   0x6000 },     /* R2   - Power Management (2) */
+	{ 3,   0x0000 },     /* R3   - Power Management (3) */
+	{ 4,   0x4050 },     /* R4   - Audio Interface (1) */
+	{ 5,   0x4000 },     /* R5   - Audio Interface (2) */
+	{ 6,   0x01C8 },     /* R6   - Clocking 1 */
+	{ 7,   0x0000 },     /* R7   - Clocking 2 */
+	{ 8,   0x0000 },     /* R8   - Audio Interface (3) */
+	{ 9,   0x0040 },     /* R9   - Audio Interface (4) */
+	{ 10,  0x0004 },     /* R10  - DAC CTRL */
+	{ 11,  0x00C0 },     /* R11  - Left DAC Digital Volume */
+	{ 12,  0x00C0 },     /* R12  - Right DAC Digital Volume */
+	{ 13,  0x0000 },     /* R13  - Digital Side Tone */
+	{ 14,  0x0300 },     /* R14  - ADC CTRL */
+	{ 15,  0x00C0 },     /* R15  - Left ADC Digital Volume */
+	{ 16,  0x00C0 },     /* R16  - Right ADC Digital Volume */
+	{ 18,  0x0000 },     /* R18  - GPIO CTRL 1 */
+	{ 19,  0x0010 },     /* R19  - GPIO1 */
+	{ 20,  0x0000 },     /* R20  - IRQ_DEBOUNCE */
+	{ 21,  0x0000 },     /* R21  - Inputs Clamp */
+	{ 22,  0x8000 },     /* R22  - GPIOCTRL 2 */
+	{ 23,  0x0800 },     /* R23  - GPIO_POL */
+	{ 24,  0x008B },     /* R24  - Left Line Input 1&2 Volume */
+	{ 25,  0x008B },     /* R25  - Left Line Input 3&4 Volume */
+	{ 26,  0x008B },     /* R26  - Right Line Input 1&2 Volume */
+	{ 27,  0x008B },     /* R27  - Right Line Input 3&4 Volume */
+	{ 28,  0x006D },     /* R28  - Left Output Volume */
+	{ 29,  0x006D },     /* R29  - Right Output Volume */
+	{ 30,  0x0066 },     /* R30  - Line Outputs Volume */
+	{ 31,  0x0020 },     /* R31  - HPOUT2 Volume */
+	{ 32,  0x0079 },     /* R32  - Left OPGA Volume */
+	{ 33,  0x0079 },     /* R33  - Right OPGA Volume */
+	{ 34,  0x0003 },     /* R34  - SPKMIXL Attenuation */
+	{ 35,  0x0003 },     /* R35  - SPKMIXR Attenuation */
+	{ 36,  0x0011 },     /* R36  - SPKOUT Mixers */
+	{ 37,  0x0100 },     /* R37  - SPKOUT Boost */
+	{ 38,  0x0079 },     /* R38  - Speaker Volume Left */
+	{ 39,  0x0079 },     /* R39  - Speaker Volume Right */
+	{ 40,  0x0000 },     /* R40  - Input Mixer2 */
+	{ 41,  0x0000 },     /* R41  - Input Mixer3 */
+	{ 42,  0x0000 },     /* R42  - Input Mixer4 */
+	{ 43,  0x0000 },     /* R43  - Input Mixer5 */
+	{ 44,  0x0000 },     /* R44  - Input Mixer6 */
+	{ 45,  0x0000 },     /* R45  - Output Mixer1 */
+	{ 46,  0x0000 },     /* R46  - Output Mixer2 */
+	{ 47,  0x0000 },     /* R47  - Output Mixer3 */
+	{ 48,  0x0000 },     /* R48  - Output Mixer4 */
+	{ 49,  0x0000 },     /* R49  - Output Mixer5 */
+	{ 50,  0x0000 },     /* R50  - Output Mixer6 */
+	{ 51,  0x0000 },     /* R51  - HPOUT2 Mixer */
+	{ 52,  0x0000 },     /* R52  - Line Mixer1 */
+	{ 53,  0x0000 },     /* R53  - Line Mixer2 */
+	{ 54,  0x0000 },     /* R54  - Speaker Mixer */
+	{ 55,  0x0000 },     /* R55  - Additional Control */
+	{ 56,  0x0000 },     /* R56  - AntiPOP1 */
+	{ 57,  0x0000 },     /* R57  - AntiPOP2 */
+	{ 58,  0x0000 },     /* R58  - MICBIAS */
+	{ 60,  0x0000 },     /* R60  - FLL Control 1 */
+	{ 61,  0x0000 },     /* R61  - FLL Control 2 */
+	{ 62,  0x0000 },     /* R62  - FLL Control 3 */
+	{ 63,  0x2EE0 },     /* R63  - FLL Control 4 */
+	{ 64,  0x0002 },     /* R64  - FLL Control 5 */
+	{ 65,  0x2287 },     /* R65  - Clocking 3 */
+	{ 66,  0x025F },     /* R66  - Clocking 4 */
+	{ 67,  0x0000 },     /* R67  - MW Slave Control */
+	{ 69,  0x0002 },     /* R69  - Bus Control 1 */
+	{ 70,  0x0000 },     /* R70  - Write Sequencer 0 */
+	{ 71,  0x0000 },     /* R71  - Write Sequencer 1 */
+	{ 72,  0x0000 },     /* R72  - Write Sequencer 2 */
+	{ 73,  0x0000 },     /* R73  - Write Sequencer 3 */
+	{ 74,  0x0000 },     /* R74  - Write Sequencer 4 */
+	{ 75,  0x0000 },     /* R75  - Write Sequencer 5 */
+	{ 76,  0x1F25 },     /* R76  - Charge Pump 1 */
+	{ 81,  0x0000 },     /* R81  - Class W 0 */
+	{ 85,  0x054A },     /* R85  - DC Servo 1 */
+	{ 87,  0x0000 },     /* R87  - DC Servo 3 */
+	{ 96,  0x0100 },     /* R96  - Analogue HP 0 */
+	{ 98,  0x0000 },     /* R98  - EQ1 */
+	{ 99,  0x000C },     /* R99  - EQ2 */
+	{ 100, 0x000C },     /* R100 - EQ3 */
+	{ 101, 0x000C },     /* R101 - EQ4 */
+	{ 102, 0x000C },     /* R102 - EQ5 */
+	{ 103, 0x000C },     /* R103 - EQ6 */
+	{ 104, 0x0FCA },     /* R104 - EQ7 */
+	{ 105, 0x0400 },     /* R105 - EQ8 */
+	{ 106, 0x00D8 },     /* R106 - EQ9 */
+	{ 107, 0x1EB5 },     /* R107 - EQ10 */
+	{ 108, 0xF145 },     /* R108 - EQ11 */
+	{ 109, 0x0B75 },     /* R109 - EQ12 */
+	{ 110, 0x01C5 },     /* R110 - EQ13 */
+	{ 111, 0x1C58 },     /* R111 - EQ14 */
+	{ 112, 0xF373 },     /* R112 - EQ15 */
+	{ 113, 0x0A54 },     /* R113 - EQ16 */
+	{ 114, 0x0558 },     /* R114 - EQ17 */
+	{ 115, 0x168E },     /* R115 - EQ18 */
+	{ 116, 0xF829 },     /* R116 - EQ19 */
+	{ 117, 0x07AD },     /* R117 - EQ20 */
+	{ 118, 0x1103 },     /* R118 - EQ21 */
+	{ 119, 0x0564 },     /* R119 - EQ22 */
+	{ 120, 0x0559 },     /* R120 - EQ23 */
+	{ 121, 0x4000 },     /* R121 - EQ24 */
+	{ 122, 0x0000 },     /* R122 - Digital Pulls */
+	{ 123, 0x0F08 },     /* R123 - DRC Control 1 */
+	{ 124, 0x0000 },     /* R124 - DRC Control 2 */
+	{ 125, 0x0080 },     /* R125 - DRC Control 3 */
+	{ 126, 0x0000 },     /* R126 - DRC Control 4 */
+};
+
+static struct {
+	int ratio;
+	int clk_sys_rate;
+} clk_sys_rates[] = {
+	{ 64,   0 },
+	{ 128,  1 },
+	{ 192,  2 },
+	{ 256,  3 },
+	{ 384,  4 },
+	{ 512,  5 },
+	{ 768,  6 },
+	{ 1024, 7 },
+	{ 1408, 8 },
+	{ 1536, 9 },
+};
+
+static struct {
+	int rate;
+	int sample_rate;
+} sample_rates[] = {
+	{ 8000,  0  },
+	{ 11025, 1  },
+	{ 12000, 1  },
+	{ 16000, 2  },
+	{ 22050, 3  },
+	{ 24000, 3  },
+	{ 32000, 4  },
+	{ 44100, 5  },
+	{ 48000, 5  },
+};
+
+static struct {
+	int div; /* *10 due to .5s */
+	int bclk_div;
+} bclk_divs[] = {
+	{ 10,  0  },
+	{ 15,  1  },
+	{ 20,  2  },
+	{ 30,  3  },
+	{ 40,  4  },
+	{ 55,  5  },
+	{ 60,  6  },
+	{ 80,  7  },
+	{ 110, 8  },
+	{ 120, 9  },
+	{ 160, 10 },
+	{ 220, 11 },
+	{ 240, 12 },
+	{ 320, 13 },
+	{ 440, 14 },
+	{ 480, 15 },
+};
+
+struct wm8993_priv {
+	struct wm_hubs_data hubs_data;
+	struct device *dev;
+	struct regmap *regmap;
+	struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES];
+	struct wm8993_platform_data pdata;
+	struct completion fll_lock;
+	int master;
+	int sysclk_source;
+	int tdm_slots;
+	int tdm_width;
+	unsigned int mclk_rate;
+	unsigned int sysclk_rate;
+	unsigned int fs;
+	unsigned int bclk;
+	unsigned int fll_fref;
+	unsigned int fll_fout;
+	int fll_src;
+};
+
+static bool wm8993_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8993_SOFTWARE_RESET:
+	case WM8993_GPIO_CTRL_1:
+	case WM8993_DC_SERVO_0:
+	case WM8993_DC_SERVO_READBACK_0:
+	case WM8993_DC_SERVO_READBACK_1:
+	case WM8993_DC_SERVO_READBACK_2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm8993_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8993_SOFTWARE_RESET:
+	case WM8993_POWER_MANAGEMENT_1:
+	case WM8993_POWER_MANAGEMENT_2:
+	case WM8993_POWER_MANAGEMENT_3:
+	case WM8993_AUDIO_INTERFACE_1:
+	case WM8993_AUDIO_INTERFACE_2:
+	case WM8993_CLOCKING_1:
+	case WM8993_CLOCKING_2:
+	case WM8993_AUDIO_INTERFACE_3:
+	case WM8993_AUDIO_INTERFACE_4:
+	case WM8993_DAC_CTRL:
+	case WM8993_LEFT_DAC_DIGITAL_VOLUME:
+	case WM8993_RIGHT_DAC_DIGITAL_VOLUME:
+	case WM8993_DIGITAL_SIDE_TONE:
+	case WM8993_ADC_CTRL:
+	case WM8993_LEFT_ADC_DIGITAL_VOLUME:
+	case WM8993_RIGHT_ADC_DIGITAL_VOLUME:
+	case WM8993_GPIO_CTRL_1:
+	case WM8993_GPIO1:
+	case WM8993_IRQ_DEBOUNCE:
+	case WM8993_GPIOCTRL_2:
+	case WM8993_GPIO_POL:
+	case WM8993_LEFT_LINE_INPUT_1_2_VOLUME:
+	case WM8993_LEFT_LINE_INPUT_3_4_VOLUME:
+	case WM8993_RIGHT_LINE_INPUT_1_2_VOLUME:
+	case WM8993_RIGHT_LINE_INPUT_3_4_VOLUME:
+	case WM8993_LEFT_OUTPUT_VOLUME:
+	case WM8993_RIGHT_OUTPUT_VOLUME:
+	case WM8993_LINE_OUTPUTS_VOLUME:
+	case WM8993_HPOUT2_VOLUME:
+	case WM8993_LEFT_OPGA_VOLUME:
+	case WM8993_RIGHT_OPGA_VOLUME:
+	case WM8993_SPKMIXL_ATTENUATION:
+	case WM8993_SPKMIXR_ATTENUATION:
+	case WM8993_SPKOUT_MIXERS:
+	case WM8993_SPKOUT_BOOST:
+	case WM8993_SPEAKER_VOLUME_LEFT:
+	case WM8993_SPEAKER_VOLUME_RIGHT:
+	case WM8993_INPUT_MIXER2:
+	case WM8993_INPUT_MIXER3:
+	case WM8993_INPUT_MIXER4:
+	case WM8993_INPUT_MIXER5:
+	case WM8993_INPUT_MIXER6:
+	case WM8993_OUTPUT_MIXER1:
+	case WM8993_OUTPUT_MIXER2:
+	case WM8993_OUTPUT_MIXER3:
+	case WM8993_OUTPUT_MIXER4:
+	case WM8993_OUTPUT_MIXER5:
+	case WM8993_OUTPUT_MIXER6:
+	case WM8993_HPOUT2_MIXER:
+	case WM8993_LINE_MIXER1:
+	case WM8993_LINE_MIXER2:
+	case WM8993_SPEAKER_MIXER:
+	case WM8993_ADDITIONAL_CONTROL:
+	case WM8993_ANTIPOP1:
+	case WM8993_ANTIPOP2:
+	case WM8993_MICBIAS:
+	case WM8993_FLL_CONTROL_1:
+	case WM8993_FLL_CONTROL_2:
+	case WM8993_FLL_CONTROL_3:
+	case WM8993_FLL_CONTROL_4:
+	case WM8993_FLL_CONTROL_5:
+	case WM8993_CLOCKING_3:
+	case WM8993_CLOCKING_4:
+	case WM8993_MW_SLAVE_CONTROL:
+	case WM8993_BUS_CONTROL_1:
+	case WM8993_WRITE_SEQUENCER_0:
+	case WM8993_WRITE_SEQUENCER_1:
+	case WM8993_WRITE_SEQUENCER_2:
+	case WM8993_WRITE_SEQUENCER_3:
+	case WM8993_WRITE_SEQUENCER_4:
+	case WM8993_WRITE_SEQUENCER_5:
+	case WM8993_CHARGE_PUMP_1:
+	case WM8993_CLASS_W_0:
+	case WM8993_DC_SERVO_0:
+	case WM8993_DC_SERVO_1:
+	case WM8993_DC_SERVO_3:
+	case WM8993_DC_SERVO_READBACK_0:
+	case WM8993_DC_SERVO_READBACK_1:
+	case WM8993_DC_SERVO_READBACK_2:
+	case WM8993_ANALOGUE_HP_0:
+	case WM8993_EQ1:
+	case WM8993_EQ2:
+	case WM8993_EQ3:
+	case WM8993_EQ4:
+	case WM8993_EQ5:
+	case WM8993_EQ6:
+	case WM8993_EQ7:
+	case WM8993_EQ8:
+	case WM8993_EQ9:
+	case WM8993_EQ10:
+	case WM8993_EQ11:
+	case WM8993_EQ12:
+	case WM8993_EQ13:
+	case WM8993_EQ14:
+	case WM8993_EQ15:
+	case WM8993_EQ16:
+	case WM8993_EQ17:
+	case WM8993_EQ18:
+	case WM8993_EQ19:
+	case WM8993_EQ20:
+	case WM8993_EQ21:
+	case WM8993_EQ22:
+	case WM8993_EQ23:
+	case WM8993_EQ24:
+	case WM8993_DIGITAL_PULLS:
+	case WM8993_DRC_CONTROL_1:
+	case WM8993_DRC_CONTROL_2:
+	case WM8993_DRC_CONTROL_3:
+	case WM8993_DRC_CONTROL_4:
+		return true;
+	default:
+		return false;
+	}
+}
+
+struct _fll_div {
+	u16 fll_fratio;
+	u16 fll_outdiv;
+	u16 fll_clk_ref_div;
+	u16 n;
+	u16 k;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static struct {
+	unsigned int min;
+	unsigned int max;
+	u16 fll_fratio;
+	int ratio;
+} fll_fratios[] = {
+	{       0,    64000, 4, 16 },
+	{   64000,   128000, 3,  8 },
+	{  128000,   256000, 2,  4 },
+	{  256000,  1000000, 1,  2 },
+	{ 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+		       unsigned int Fout)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod, target;
+	unsigned int div;
+	int i;
+
+	/* Fref must be <=13.5MHz */
+	div = 1;
+	fll_div->fll_clk_ref_div = 0;
+	while ((Fref / div) > 13500000) {
+		div *= 2;
+		fll_div->fll_clk_ref_div++;
+
+		if (div > 8) {
+			pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+			       Fref);
+			return -EINVAL;
+		}
+	}
+
+	pr_debug("Fref=%u Fout=%u\n", Fref, Fout);
+
+	/* Apply the division for our remaining calculations */
+	Fref /= div;
+
+	/* Fvco should be 90-100MHz; don't check the upper bound */
+	div = 0;
+	target = Fout * 2;
+	while (target < 90000000) {
+		div++;
+		target *= 2;
+		if (div > 7) {
+			pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+			       Fout);
+			return -EINVAL;
+		}
+	}
+	fll_div->fll_outdiv = div;
+
+	pr_debug("Fvco=%dHz\n", target);
+
+	/* Find an appropriate FLL_FRATIO and factor it out of the target */
+	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+			fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+			target /= fll_fratios[i].ratio;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(fll_fratios)) {
+		pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+		return -EINVAL;
+	}
+
+	/* Now, calculate N.K */
+	Ndiv = target / Fref;
+
+	fll_div->n = Ndiv;
+	Nmod = target % Fref;
+	pr_debug("Nmod=%d\n", Nmod);
+
+	/* Calculate fractional part - scale up so we can round. */
+	Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, Fref);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	fll_div->k = K / 10;
+
+	pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n",
+		 fll_div->n, fll_div->k,
+		 fll_div->fll_fratio, fll_div->fll_outdiv,
+		 fll_div->fll_clk_ref_div);
+
+	return 0;
+}
+
+static int _wm8993_set_fll(struct snd_soc_component *component, int fll_id, int source,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
+	u16 reg1, reg4, reg5;
+	struct _fll_div fll_div;
+	unsigned int timeout;
+	int ret;
+
+	/* Any change? */
+	if (Fref == wm8993->fll_fref && Fout == wm8993->fll_fout)
+		return 0;
+
+	/* Disable the FLL */
+	if (Fout == 0) {
+		dev_dbg(component->dev, "FLL disabled\n");
+		wm8993->fll_fref = 0;
+		wm8993->fll_fout = 0;
+
+		reg1 = snd_soc_component_read32(component, WM8993_FLL_CONTROL_1);
+		reg1 &= ~WM8993_FLL_ENA;
+		snd_soc_component_write(component, WM8993_FLL_CONTROL_1, reg1);
+
+		return 0;
+	}
+
+	ret = fll_factors(&fll_div, Fref, Fout);
+	if (ret != 0)
+		return ret;
+
+	reg5 = snd_soc_component_read32(component, WM8993_FLL_CONTROL_5);
+	reg5 &= ~WM8993_FLL_CLK_SRC_MASK;
+
+	switch (fll_id) {
+	case WM8993_FLL_MCLK:
+		break;
+
+	case WM8993_FLL_LRCLK:
+		reg5 |= 1;
+		break;
+
+	case WM8993_FLL_BCLK:
+		reg5 |= 2;
+		break;
+
+	default:
+		dev_err(component->dev, "Unknown FLL ID %d\n", fll_id);
+		return -EINVAL;
+	}
+
+	/* Any FLL configuration change requires that the FLL be
+	 * disabled first. */
+	reg1 = snd_soc_component_read32(component, WM8993_FLL_CONTROL_1);
+	reg1 &= ~WM8993_FLL_ENA;
+	snd_soc_component_write(component, WM8993_FLL_CONTROL_1, reg1);
+
+	/* Apply the configuration */
+	if (fll_div.k)
+		reg1 |= WM8993_FLL_FRAC_MASK;
+	else
+		reg1 &= ~WM8993_FLL_FRAC_MASK;
+	snd_soc_component_write(component, WM8993_FLL_CONTROL_1, reg1);
+
+	snd_soc_component_write(component, WM8993_FLL_CONTROL_2,
+		      (fll_div.fll_outdiv << WM8993_FLL_OUTDIV_SHIFT) |
+		      (fll_div.fll_fratio << WM8993_FLL_FRATIO_SHIFT));
+	snd_soc_component_write(component, WM8993_FLL_CONTROL_3, fll_div.k);
+
+	reg4 = snd_soc_component_read32(component, WM8993_FLL_CONTROL_4);
+	reg4 &= ~WM8993_FLL_N_MASK;
+	reg4 |= fll_div.n << WM8993_FLL_N_SHIFT;
+	snd_soc_component_write(component, WM8993_FLL_CONTROL_4, reg4);
+
+	reg5 &= ~WM8993_FLL_CLK_REF_DIV_MASK;
+	reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT;
+	snd_soc_component_write(component, WM8993_FLL_CONTROL_5, reg5);
+
+	/* If we've got an interrupt wired up make sure we get it */
+	if (i2c->irq)
+		timeout = msecs_to_jiffies(20);
+	else if (Fref < 1000000)
+		timeout = msecs_to_jiffies(3);
+	else
+		timeout = msecs_to_jiffies(1);
+
+	try_wait_for_completion(&wm8993->fll_lock);
+
+	/* Enable the FLL */
+	snd_soc_component_write(component, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA);
+
+	timeout = wait_for_completion_timeout(&wm8993->fll_lock, timeout);
+	if (i2c->irq && !timeout)
+		dev_warn(component->dev, "Timed out waiting for FLL\n");
+
+	dev_dbg(component->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
+
+	wm8993->fll_fref = Fref;
+	wm8993->fll_fout = Fout;
+	wm8993->fll_src = source;
+
+	return 0;
+}
+
+static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+			  unsigned int Fref, unsigned int Fout)
+{
+	return _wm8993_set_fll(dai->component, fll_id, source, Fref, Fout);
+}
+
+static int configure_clock(struct snd_soc_component *component)
+{
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+	unsigned int reg;
+
+	/* This should be done on init() for bypass paths */
+	switch (wm8993->sysclk_source) {
+	case WM8993_SYSCLK_MCLK:
+		dev_dbg(component->dev, "Using %dHz MCLK\n", wm8993->mclk_rate);
+
+		reg = snd_soc_component_read32(component, WM8993_CLOCKING_2);
+		reg &= ~(WM8993_MCLK_DIV | WM8993_SYSCLK_SRC);
+		if (wm8993->mclk_rate > 13500000) {
+			reg |= WM8993_MCLK_DIV;
+			wm8993->sysclk_rate = wm8993->mclk_rate / 2;
+		} else {
+			reg &= ~WM8993_MCLK_DIV;
+			wm8993->sysclk_rate = wm8993->mclk_rate;
+		}
+		snd_soc_component_write(component, WM8993_CLOCKING_2, reg);
+		break;
+
+	case WM8993_SYSCLK_FLL:
+		dev_dbg(component->dev, "Using %dHz FLL clock\n",
+			wm8993->fll_fout);
+
+		reg = snd_soc_component_read32(component, WM8993_CLOCKING_2);
+		reg |= WM8993_SYSCLK_SRC;
+		if (wm8993->fll_fout > 13500000) {
+			reg |= WM8993_MCLK_DIV;
+			wm8993->sysclk_rate = wm8993->fll_fout / 2;
+		} else {
+			reg &= ~WM8993_MCLK_DIV;
+			wm8993->sysclk_rate = wm8993->fll_fout;
+		}
+		snd_soc_component_write(component, WM8993_CLOCKING_2, reg);
+		break;
+
+	default:
+		dev_err(component->dev, "System clock not configured\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(component->dev, "CLK_SYS is %dHz\n", wm8993->sysclk_rate);
+
+	return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(drc_comp_threash, -4500, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_comp_amp, -2250, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0);
+static const DECLARE_TLV_DB_RANGE(drc_max_tlv,
+	0, 2, TLV_DB_SCALE_ITEM(1200, 600, 0),
+	3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0)
+);
+static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -1800, 300, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
+
+static const char *dac_deemph_text[] = {
+	"None",
+	"32kHz",
+	"44.1kHz",
+	"48kHz",
+};
+
+static SOC_ENUM_SINGLE_DECL(dac_deemph,
+			    WM8993_DAC_CTRL, 4, dac_deemph_text);
+
+static const char *adc_hpf_text[] = {
+	"Hi-Fi",
+	"Voice 1",
+	"Voice 2",
+	"Voice 3",
+};
+
+static SOC_ENUM_SINGLE_DECL(adc_hpf,
+			    WM8993_ADC_CTRL, 5, adc_hpf_text);
+
+static const char *drc_path_text[] = {
+	"ADC",
+	"DAC"
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_path,
+			    WM8993_DRC_CONTROL_1, 14, drc_path_text);
+
+static const char *drc_r0_text[] = {
+	"1",
+	"1/2",
+	"1/4",
+	"1/8",
+	"1/16",
+	"0",
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_r0,
+			    WM8993_DRC_CONTROL_3, 8, drc_r0_text);
+
+static const char *drc_r1_text[] = {
+	"1",
+	"1/2",
+	"1/4",
+	"1/8",
+	"0",
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_r1,
+			    WM8993_DRC_CONTROL_4, 13, drc_r1_text);
+
+static const char *drc_attack_text[] = {
+	"Reserved",
+	"181us",
+	"363us",
+	"726us",
+	"1.45ms",
+	"2.9ms",
+	"5.8ms",
+	"11.6ms",
+	"23.2ms",
+	"46.4ms",
+	"92.8ms",
+	"185.6ms",
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_attack,
+			    WM8993_DRC_CONTROL_2, 12, drc_attack_text);
+
+static const char *drc_decay_text[] = {
+	"186ms",
+	"372ms",
+	"743ms",
+	"1.49s",
+	"2.97ms",
+	"5.94ms",
+	"11.89ms",
+	"23.78ms",
+	"47.56ms",
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_decay,
+			    WM8993_DRC_CONTROL_2, 8, drc_decay_text);
+
+static const char *drc_ff_text[] = {
+	"5 samples",
+	"9 samples",
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_ff,
+			    WM8993_DRC_CONTROL_3, 7, drc_ff_text);
+
+static const char *drc_qr_rate_text[] = {
+	"0.725ms",
+	"1.45ms",
+	"5.8ms",
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_qr_rate,
+			    WM8993_DRC_CONTROL_3, 0, drc_qr_rate_text);
+
+static const char *drc_smooth_text[] = {
+	"Low",
+	"Medium",
+	"High",
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_smooth,
+			    WM8993_DRC_CONTROL_1, 4, drc_smooth_text);
+
+static const struct snd_kcontrol_new wm8993_snd_controls[] = {
+SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8993_DIGITAL_SIDE_TONE,
+	       5, 9, 12, 0, sidetone_tlv),
+
+SOC_SINGLE("DRC Switch", WM8993_DRC_CONTROL_1, 15, 1, 0),
+SOC_ENUM("DRC Path", drc_path),
+SOC_SINGLE_TLV("DRC Compressor Threshold Volume", WM8993_DRC_CONTROL_2,
+	       2, 60, 1, drc_comp_threash),
+SOC_SINGLE_TLV("DRC Compressor Amplitude Volume", WM8993_DRC_CONTROL_3,
+	       11, 30, 1, drc_comp_amp),
+SOC_ENUM("DRC R0", drc_r0),
+SOC_ENUM("DRC R1", drc_r1),
+SOC_SINGLE_TLV("DRC Minimum Volume", WM8993_DRC_CONTROL_1, 2, 3, 1,
+	       drc_min_tlv),
+SOC_SINGLE_TLV("DRC Maximum Volume", WM8993_DRC_CONTROL_1, 0, 3, 0,
+	       drc_max_tlv),
+SOC_ENUM("DRC Attack Rate", drc_attack),
+SOC_ENUM("DRC Decay Rate", drc_decay),
+SOC_ENUM("DRC FF Delay", drc_ff),
+SOC_SINGLE("DRC Anti-clip Switch", WM8993_DRC_CONTROL_1, 9, 1, 0),
+SOC_SINGLE("DRC Quick Release Switch", WM8993_DRC_CONTROL_1, 10, 1, 0),
+SOC_SINGLE_TLV("DRC Quick Release Volume", WM8993_DRC_CONTROL_3, 2, 3, 0,
+	       drc_qr_tlv),
+SOC_ENUM("DRC Quick Release Rate", drc_qr_rate),
+SOC_SINGLE("DRC Smoothing Switch", WM8993_DRC_CONTROL_1, 11, 1, 0),
+SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8993_DRC_CONTROL_1, 8, 1, 0),
+SOC_ENUM("DRC Smoothing Hysteresis Threshold", drc_smooth),
+SOC_SINGLE_TLV("DRC Startup Volume", WM8993_DRC_CONTROL_4, 8, 18, 0,
+	       drc_startup_tlv),
+
+SOC_SINGLE("EQ Switch", WM8993_EQ1, 0, 1, 0),
+
+SOC_DOUBLE_R_TLV("Capture Volume", WM8993_LEFT_ADC_DIGITAL_VOLUME,
+		 WM8993_RIGHT_ADC_DIGITAL_VOLUME, 1, 96, 0, digital_tlv),
+SOC_SINGLE("ADC High Pass Filter Switch", WM8993_ADC_CTRL, 8, 1, 0),
+SOC_ENUM("ADC High Pass Filter Mode", adc_hpf),
+
+SOC_DOUBLE_R_TLV("Playback Volume", WM8993_LEFT_DAC_DIGITAL_VOLUME,
+		 WM8993_RIGHT_DAC_DIGITAL_VOLUME, 1, 96, 0, digital_tlv),
+SOC_SINGLE_TLV("Playback Boost Volume", WM8993_AUDIO_INTERFACE_2, 10, 3, 0,
+	       dac_boost_tlv),
+SOC_ENUM("DAC Deemphasis", dac_deemph),
+
+SOC_SINGLE_TLV("SPKL DAC Volume", WM8993_SPKMIXL_ATTENUATION,
+	       2, 1, 1, wm_hubs_spkmix_tlv),
+
+SOC_SINGLE_TLV("SPKR DAC Volume", WM8993_SPKMIXR_ATTENUATION,
+	       2, 1, 1, wm_hubs_spkmix_tlv),
+};
+
+static const struct snd_kcontrol_new wm8993_eq_controls[] = {
+SOC_SINGLE_TLV("EQ1 Volume", WM8993_EQ2, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Volume", WM8993_EQ3, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Volume", WM8993_EQ4, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Volume", WM8993_EQ5, 0, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ5 Volume", WM8993_EQ6, 0, 24, 0, eq_tlv),
+};
+
+static int clk_sys_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		return configure_clock(component);
+
+	case SND_SOC_DAPM_POST_PMD:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new left_speaker_mixer[] = {
+SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 7, 1, 0),
+SOC_DAPM_SINGLE("IN1LP Switch", WM8993_SPEAKER_MIXER, 5, 1, 0),
+SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 3, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_speaker_mixer[] = {
+SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 6, 1, 0),
+SOC_DAPM_SINGLE("IN1RP Switch", WM8993_SPEAKER_MIXER, 4, 1, 0),
+SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 2, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 0, 1, 0),
+};
+
+static const char *aif_text[] = {
+	"Left", "Right"
+};
+
+static SOC_ENUM_SINGLE_DECL(aifoutl_enum,
+			    WM8993_AUDIO_INTERFACE_1, 15, aif_text);
+
+static const struct snd_kcontrol_new aifoutl_mux =
+	SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum);
+
+static SOC_ENUM_SINGLE_DECL(aifoutr_enum,
+			    WM8993_AUDIO_INTERFACE_1, 14, aif_text);
+
+static const struct snd_kcontrol_new aifoutr_mux =
+	SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum);
+
+static SOC_ENUM_SINGLE_DECL(aifinl_enum,
+			    WM8993_AUDIO_INTERFACE_2, 15, aif_text);
+
+static const struct snd_kcontrol_new aifinl_mux =
+	SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum);
+
+static SOC_ENUM_SINGLE_DECL(aifinr_enum,
+			    WM8993_AUDIO_INTERFACE_2, 14, aif_text);
+
+static const struct snd_kcontrol_new aifinr_mux =
+	SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum);
+
+static const char *sidetone_text[] = {
+	"None", "Left", "Right"
+};
+
+static SOC_ENUM_SINGLE_DECL(sidetonel_enum,
+			    WM8993_DIGITAL_SIDE_TONE, 2, sidetone_text);
+
+static const struct snd_kcontrol_new sidetonel_mux =
+	SOC_DAPM_ENUM("Left Sidetone", sidetonel_enum);
+
+static SOC_ENUM_SINGLE_DECL(sidetoner_enum,
+			    WM8993_DIGITAL_SIDE_TONE, 0, sidetone_text);
+
+static const struct snd_kcontrol_new sidetoner_mux =
+	SOC_DAPM_ENUM("Right Sidetone", sidetoner_enum);
+
+static const struct snd_soc_dapm_widget wm8993_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8993_BUS_CONTROL_1, 1, 0, clk_sys_event,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("TOCLK", WM8993_CLOCKING_1, 14, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8993_CLOCKING_3, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("ADCL", NULL, WM8993_POWER_MANAGEMENT_2, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, WM8993_POWER_MANAGEMENT_2, 0, 0),
+
+SND_SOC_DAPM_MUX("AIFOUTL Mux", SND_SOC_NOPM, 0, 0, &aifoutl_mux),
+SND_SOC_DAPM_MUX("AIFOUTR Mux", SND_SOC_NOPM, 0, 0, &aifoutr_mux),
+
+SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &aifinl_mux),
+SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &aifinr_mux),
+
+SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &sidetonel_mux),
+SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &sidetoner_mux),
+
+SND_SOC_DAPM_DAC("DACL", NULL, WM8993_POWER_MANAGEMENT_3, 1, 0),
+SND_SOC_DAPM_DAC("DACR", NULL, WM8993_POWER_MANAGEMENT_3, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux),
+
+SND_SOC_DAPM_MIXER("SPKL", WM8993_POWER_MANAGEMENT_3, 8, 0,
+		   left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
+SND_SOC_DAPM_MIXER("SPKR", WM8993_POWER_MANAGEMENT_3, 9, 0,
+		   right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
+SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route routes[] = {
+	{ "MICBIAS1", NULL, "VMID" },
+	{ "MICBIAS2", NULL, "VMID" },
+
+	{ "ADCL", NULL, "CLK_SYS" },
+	{ "ADCL", NULL, "CLK_DSP" },
+	{ "ADCR", NULL, "CLK_SYS" },
+	{ "ADCR", NULL, "CLK_DSP" },
+
+	{ "AIFOUTL Mux", "Left", "ADCL" },
+	{ "AIFOUTL Mux", "Right", "ADCR" },
+	{ "AIFOUTR Mux", "Left", "ADCL" },
+	{ "AIFOUTR Mux", "Right", "ADCR" },
+
+	{ "AIFOUTL", NULL, "AIFOUTL Mux" },
+	{ "AIFOUTR", NULL, "AIFOUTR Mux" },
+
+	{ "DACL Mux", "Left", "AIFINL" },
+	{ "DACL Mux", "Right", "AIFINR" },
+	{ "DACR Mux", "Left", "AIFINL" },
+	{ "DACR Mux", "Right", "AIFINR" },
+
+	{ "DACL Sidetone", "Left", "ADCL" },
+	{ "DACL Sidetone", "Right", "ADCR" },
+	{ "DACR Sidetone", "Left", "ADCL" },
+	{ "DACR Sidetone", "Right", "ADCR" },
+
+	{ "DACL", NULL, "CLK_SYS" },
+	{ "DACL", NULL, "CLK_DSP" },
+	{ "DACL", NULL, "DACL Mux" },
+	{ "DACL", NULL, "DACL Sidetone" },
+	{ "DACR", NULL, "CLK_SYS" },
+	{ "DACR", NULL, "CLK_DSP" },
+	{ "DACR", NULL, "DACR Mux" },
+	{ "DACR", NULL, "DACR Sidetone" },
+
+	{ "Left Output Mixer", "DAC Switch", "DACL" },
+
+	{ "Right Output Mixer", "DAC Switch", "DACR" },
+
+	{ "Left Output PGA", NULL, "CLK_SYS" },
+
+	{ "Right Output PGA", NULL, "CLK_SYS" },
+
+	{ "SPKL", "DAC Switch", "DACL" },
+	{ "SPKL", NULL, "CLK_SYS" },
+
+	{ "SPKR", "DAC Switch", "DACR" },
+	{ "SPKR", NULL, "CLK_SYS" },
+
+	{ "Left Headphone Mux", "DAC", "DACL" },
+	{ "Right Headphone Mux", "DAC", "DACR" },
+};
+
+static int wm8993_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	wm_hubs_set_bias_level(component, level);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		/* VMID=2*40k */
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
+				    WM8993_VMID_SEL_MASK, 0x2);
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_2,
+				    WM8993_TSHUT_ENA, WM8993_TSHUT_ENA);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
+						    wm8993->supplies);
+			if (ret != 0)
+				return ret;
+
+			regcache_cache_only(wm8993->regmap, false);
+			regcache_sync(wm8993->regmap);
+
+			wm_hubs_vmid_ena(component);
+
+			/* Bring up VMID with fast soft start */
+			snd_soc_component_update_bits(component, WM8993_ANTIPOP2,
+					    WM8993_STARTUP_BIAS_ENA |
+					    WM8993_VMID_BUF_ENA |
+					    WM8993_VMID_RAMP_MASK |
+					    WM8993_BIAS_SRC,
+					    WM8993_STARTUP_BIAS_ENA |
+					    WM8993_VMID_BUF_ENA |
+					    WM8993_VMID_RAMP_MASK |
+					    WM8993_BIAS_SRC);
+
+			/* If either line output is single ended we
+			 * need the VMID buffer */
+			if (!wm8993->pdata.lineout1_diff ||
+			    !wm8993->pdata.lineout2_diff)
+				snd_soc_component_update_bits(component, WM8993_ANTIPOP1,
+						 WM8993_LINEOUT_VMID_BUF_ENA,
+						 WM8993_LINEOUT_VMID_BUF_ENA);
+
+			/* VMID=2*40k */
+			snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
+					    WM8993_VMID_SEL_MASK |
+					    WM8993_BIAS_ENA,
+					    WM8993_BIAS_ENA | 0x2);
+			msleep(32);
+
+			/* Switch to normal bias */
+			snd_soc_component_update_bits(component, WM8993_ANTIPOP2,
+					    WM8993_BIAS_SRC |
+					    WM8993_STARTUP_BIAS_ENA, 0);
+		}
+
+		/* VMID=2*240k */
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
+				    WM8993_VMID_SEL_MASK, 0x4);
+
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_2,
+				    WM8993_TSHUT_ENA, 0);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, WM8993_ANTIPOP1,
+				    WM8993_LINEOUT_VMID_BUF_ENA, 0);
+
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
+				    WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA,
+				    0);
+
+		snd_soc_component_update_bits(component, WM8993_ANTIPOP2,
+				    WM8993_STARTUP_BIAS_ENA |
+				    WM8993_VMID_BUF_ENA |
+				    WM8993_VMID_RAMP_MASK |
+				    WM8993_BIAS_SRC, 0);
+
+		regcache_cache_only(wm8993->regmap, true);
+		regcache_mark_dirty(wm8993->regmap);
+
+		regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies),
+				       wm8993->supplies);
+		break;
+	}
+
+	return 0;
+}
+
+static int wm8993_set_sysclk(struct snd_soc_dai *codec_dai,
+			     int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case WM8993_SYSCLK_MCLK:
+		wm8993->mclk_rate = freq;
+		/* fall through */
+	case WM8993_SYSCLK_FLL:
+		wm8993->sysclk_source = clk_id;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8993_set_dai_fmt(struct snd_soc_dai *dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+	unsigned int aif1 = snd_soc_component_read32(component, WM8993_AUDIO_INTERFACE_1);
+	unsigned int aif4 = snd_soc_component_read32(component, WM8993_AUDIO_INTERFACE_4);
+
+	aif1 &= ~(WM8993_BCLK_DIR | WM8993_AIF_BCLK_INV |
+		  WM8993_AIF_LRCLK_INV | WM8993_AIF_FMT_MASK);
+	aif4 &= ~WM8993_LRCLK_DIR;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		wm8993->master = 0;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		aif4 |= WM8993_LRCLK_DIR;
+		wm8993->master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		aif1 |= WM8993_BCLK_DIR;
+		wm8993->master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif1 |= WM8993_BCLK_DIR;
+		aif4 |= WM8993_LRCLK_DIR;
+		wm8993->master = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_B:
+		aif1 |= WM8993_AIF_LRCLK_INV;
+		/* fall through */
+	case SND_SOC_DAIFMT_DSP_A:
+		aif1 |= 0x18;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aif1 |= 0x10;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif1 |= 0x8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		/* frame inversion not valid for DSP modes */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif1 |= WM8993_AIF_BCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			aif1 |= WM8993_AIF_BCLK_INV | WM8993_AIF_LRCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif1 |= WM8993_AIF_BCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			aif1 |= WM8993_AIF_LRCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM8993_AUDIO_INTERFACE_1, aif1);
+	snd_soc_component_write(component, WM8993_AUDIO_INTERFACE_4, aif4);
+
+	return 0;
+}
+
+static int wm8993_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+	int ret, i, best, best_val, cur_val;
+	unsigned int clocking1, clocking3, aif1, aif4;
+
+	clocking1 = snd_soc_component_read32(component, WM8993_CLOCKING_1);
+	clocking1 &= ~WM8993_BCLK_DIV_MASK;
+
+	clocking3 = snd_soc_component_read32(component, WM8993_CLOCKING_3);
+	clocking3 &= ~(WM8993_CLK_SYS_RATE_MASK | WM8993_SAMPLE_RATE_MASK);
+
+	aif1 = snd_soc_component_read32(component, WM8993_AUDIO_INTERFACE_1);
+	aif1 &= ~WM8993_AIF_WL_MASK;
+
+	aif4 = snd_soc_component_read32(component, WM8993_AUDIO_INTERFACE_4);
+	aif4 &= ~WM8993_LRCLK_RATE_MASK;
+
+	/* What BCLK do we need? */
+	wm8993->fs = params_rate(params);
+	wm8993->bclk = 2 * wm8993->fs;
+	if (wm8993->tdm_slots) {
+		dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n",
+			wm8993->tdm_slots, wm8993->tdm_width);
+		wm8993->bclk *= wm8993->tdm_width * wm8993->tdm_slots;
+	} else {
+		switch (params_width(params)) {
+		case 16:
+			wm8993->bclk *= 16;
+			break;
+		case 20:
+			wm8993->bclk *= 20;
+			aif1 |= 0x8;
+			break;
+		case 24:
+			wm8993->bclk *= 24;
+			aif1 |= 0x10;
+			break;
+		case 32:
+			wm8993->bclk *= 32;
+			aif1 |= 0x18;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	dev_dbg(component->dev, "Target BCLK is %dHz\n", wm8993->bclk);
+
+	ret = configure_clock(component);
+	if (ret != 0)
+		return ret;
+
+	/* Select nearest CLK_SYS_RATE */
+	best = 0;
+	best_val = abs((wm8993->sysclk_rate / clk_sys_rates[0].ratio)
+		       - wm8993->fs);
+	for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) {
+		cur_val = abs((wm8993->sysclk_rate /
+			       clk_sys_rates[i].ratio) - wm8993->fs);
+		if (cur_val < best_val) {
+			best = i;
+			best_val = cur_val;
+		}
+	}
+	dev_dbg(component->dev, "Selected CLK_SYS_RATIO of %d\n",
+		clk_sys_rates[best].ratio);
+	clocking3 |= (clk_sys_rates[best].clk_sys_rate
+		      << WM8993_CLK_SYS_RATE_SHIFT);
+
+	/* SAMPLE_RATE */
+	best = 0;
+	best_val = abs(wm8993->fs - sample_rates[0].rate);
+	for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
+		/* Closest match */
+		cur_val = abs(wm8993->fs - sample_rates[i].rate);
+		if (cur_val < best_val) {
+			best = i;
+			best_val = cur_val;
+		}
+	}
+	dev_dbg(component->dev, "Selected SAMPLE_RATE of %dHz\n",
+		sample_rates[best].rate);
+	clocking3 |= (sample_rates[best].sample_rate
+		      << WM8993_SAMPLE_RATE_SHIFT);
+
+	/* BCLK_DIV */
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+		cur_val = ((wm8993->sysclk_rate * 10) / bclk_divs[i].div)
+			- wm8993->bclk;
+		if (cur_val < 0) /* Table is sorted */
+			break;
+		if (cur_val < best_val) {
+			best = i;
+			best_val = cur_val;
+		}
+	}
+	wm8993->bclk = (wm8993->sysclk_rate * 10) / bclk_divs[best].div;
+	dev_dbg(component->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
+		bclk_divs[best].div, wm8993->bclk);
+	clocking1 |= bclk_divs[best].bclk_div << WM8993_BCLK_DIV_SHIFT;
+
+	/* LRCLK is a simple fraction of BCLK */
+	dev_dbg(component->dev, "LRCLK_RATE is %d\n", wm8993->bclk / wm8993->fs);
+	aif4 |= wm8993->bclk / wm8993->fs;
+
+	snd_soc_component_write(component, WM8993_CLOCKING_1, clocking1);
+	snd_soc_component_write(component, WM8993_CLOCKING_3, clocking3);
+	snd_soc_component_write(component, WM8993_AUDIO_INTERFACE_1, aif1);
+	snd_soc_component_write(component, WM8993_AUDIO_INTERFACE_4, aif4);
+
+	/* ReTune Mobile? */
+	if (wm8993->pdata.num_retune_configs) {
+		u16 eq1 = snd_soc_component_read32(component, WM8993_EQ1);
+		struct wm8993_retune_mobile_setting *s;
+
+		best = 0;
+		best_val = abs(wm8993->pdata.retune_configs[0].rate
+			       - wm8993->fs);
+		for (i = 0; i < wm8993->pdata.num_retune_configs; i++) {
+			cur_val = abs(wm8993->pdata.retune_configs[i].rate
+				      - wm8993->fs);
+			if (cur_val < best_val) {
+				best_val = cur_val;
+				best = i;
+			}
+		}
+		s = &wm8993->pdata.retune_configs[best];
+
+		dev_dbg(component->dev, "ReTune Mobile %s tuned for %dHz\n",
+			s->name, s->rate);
+
+		/* Disable EQ while we reconfigure */
+		snd_soc_component_update_bits(component, WM8993_EQ1, WM8993_EQ_ENA, 0);
+
+		for (i = 1; i < ARRAY_SIZE(s->config); i++)
+			snd_soc_component_write(component, WM8993_EQ1 + i, s->config[i]);
+
+		snd_soc_component_update_bits(component, WM8993_EQ1, WM8993_EQ_ENA, eq1);
+	}
+
+	return 0;
+}
+
+static int wm8993_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	unsigned int reg;
+
+	reg = snd_soc_component_read32(component, WM8993_DAC_CTRL);
+
+	if (mute)
+		reg |= WM8993_DAC_MUTE;
+	else
+		reg &= ~WM8993_DAC_MUTE;
+
+	snd_soc_component_write(component, WM8993_DAC_CTRL, reg);
+
+	return 0;
+}
+
+static int wm8993_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			       unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+	int aif1 = 0;
+	int aif2 = 0;
+
+	/* Don't need to validate anything if we're turning off TDM */
+	if (slots == 0) {
+		wm8993->tdm_slots = 0;
+		goto out;
+	}
+
+	/* Note that we allow configurations we can't handle ourselves - 
+	 * for example, we can generate clocks for slots 2 and up even if
+	 * we can't use those slots ourselves.
+	 */
+	aif1 |= WM8993_AIFADC_TDM;
+	aif2 |= WM8993_AIFDAC_TDM;
+
+	switch (rx_mask) {
+	case 3:
+		break;
+	case 0xc:
+		aif1 |= WM8993_AIFADC_TDM_CHAN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+
+	switch (tx_mask) {
+	case 3:
+		break;
+	case 0xc:
+		aif2 |= WM8993_AIFDAC_TDM_CHAN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+out:
+	wm8993->tdm_width = slot_width;
+	wm8993->tdm_slots = slots / 2;
+
+	snd_soc_component_update_bits(component, WM8993_AUDIO_INTERFACE_1,
+			    WM8993_AIFADC_TDM | WM8993_AIFADC_TDM_CHAN, aif1);
+	snd_soc_component_update_bits(component, WM8993_AUDIO_INTERFACE_2,
+			    WM8993_AIFDAC_TDM | WM8993_AIFDAC_TDM_CHAN, aif2);
+
+	return 0;
+}
+
+static irqreturn_t wm8993_irq(int irq, void *data)
+{
+	struct wm8993_priv *wm8993 = data;
+	int mask, val, ret;
+
+	ret = regmap_read(wm8993->regmap, WM8993_GPIO_CTRL_1, &val);
+	if (ret != 0) {
+		dev_err(wm8993->dev, "Failed to read interrupt status: %d\n",
+			ret);
+		return IRQ_NONE;
+	}
+
+	ret = regmap_read(wm8993->regmap, WM8993_GPIOCTRL_2, &mask);
+	if (ret != 0) {
+		dev_err(wm8993->dev, "Failed to read interrupt mask: %d\n",
+			ret);
+		return IRQ_NONE;
+	}
+
+	/* The IRQ pin status is visible in the register too */
+	val &= ~(mask | WM8993_IRQ);
+	if (!val)
+		return IRQ_NONE;
+
+	if (val & WM8993_TEMPOK_EINT)
+		dev_crit(wm8993->dev, "Thermal warning\n");
+
+	if (val & WM8993_FLL_LOCK_EINT) {
+		dev_dbg(wm8993->dev, "FLL locked\n");
+		complete(&wm8993->fll_lock);
+	}
+
+	ret = regmap_write(wm8993->regmap, WM8993_GPIO_CTRL_1, val);
+	if (ret != 0)
+		dev_err(wm8993->dev, "Failed to ack interrupt: %d\n", ret);
+
+	return IRQ_HANDLED;
+}
+
+static const struct snd_soc_dai_ops wm8993_ops = {
+	.set_sysclk = wm8993_set_sysclk,
+	.set_fmt = wm8993_set_dai_fmt,
+	.hw_params = wm8993_hw_params,
+	.digital_mute = wm8993_digital_mute,
+	.set_pll = wm8993_set_fll,
+	.set_tdm_slot = wm8993_set_tdm_slot,
+};
+
+#define WM8993_RATES SNDRV_PCM_RATE_8000_48000
+
+#define WM8993_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE |\
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm8993_dai = {
+	.name = "wm8993-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM8993_RATES,
+		.formats = WM8993_FORMATS,
+		.sig_bits = 24,
+	},
+	.capture = {
+		 .stream_name = "Capture",
+		 .channels_min = 1,
+		 .channels_max = 2,
+		 .rates = WM8993_RATES,
+		 .formats = WM8993_FORMATS,
+		 .sig_bits = 24,
+	 },
+	.ops = &wm8993_ops,
+	.symmetric_rates = 1,
+};
+
+static int wm8993_probe(struct snd_soc_component *component)
+{
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	wm8993->hubs_data.hp_startup_mode = 1;
+	wm8993->hubs_data.dcs_codes_l = -2;
+	wm8993->hubs_data.dcs_codes_r = -2;
+	wm8993->hubs_data.series_startup = 1;
+
+	/* Latch volume update bits and default ZC on */
+	snd_soc_component_update_bits(component, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
+			    WM8993_DAC_VU, WM8993_DAC_VU);
+	snd_soc_component_update_bits(component, WM8993_RIGHT_ADC_DIGITAL_VOLUME,
+			    WM8993_ADC_VU, WM8993_ADC_VU);
+
+	/* Manualy manage the HPOUT sequencing for independent stereo
+	 * control. */
+	snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
+			    WM8993_HPOUT1_AUTO_PU, 0);
+
+	/* Use automatic clock configuration */
+	snd_soc_component_update_bits(component, WM8993_CLOCKING_4, WM8993_SR_MODE, 0);
+
+	wm_hubs_handle_analogue_pdata(component, wm8993->pdata.lineout1_diff,
+				      wm8993->pdata.lineout2_diff,
+				      wm8993->pdata.lineout1fb,
+				      wm8993->pdata.lineout2fb,
+				      wm8993->pdata.jd_scthr,
+				      wm8993->pdata.jd_thr,
+				      wm8993->pdata.micbias1_delay,
+				      wm8993->pdata.micbias2_delay,
+				      wm8993->pdata.micbias1_lvl,
+				      wm8993->pdata.micbias2_lvl);
+
+	snd_soc_add_component_controls(component, wm8993_snd_controls,
+			     ARRAY_SIZE(wm8993_snd_controls));
+	if (wm8993->pdata.num_retune_configs != 0) {
+		dev_dbg(component->dev, "Using ReTune Mobile\n");
+	} else {
+		dev_dbg(component->dev, "No ReTune Mobile, using normal EQ\n");
+		snd_soc_add_component_controls(component, wm8993_eq_controls,
+				     ARRAY_SIZE(wm8993_eq_controls));
+	}
+
+	snd_soc_dapm_new_controls(dapm, wm8993_dapm_widgets,
+				  ARRAY_SIZE(wm8993_dapm_widgets));
+	wm_hubs_add_analogue_controls(component);
+
+	snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
+	wm_hubs_add_analogue_routes(component, wm8993->pdata.lineout1_diff,
+				    wm8993->pdata.lineout2_diff);
+
+	/* If the line outputs are differential then we aren't presenting
+	 * VMID as an output and can disable it.
+	 */
+	if (wm8993->pdata.lineout1_diff && wm8993->pdata.lineout2_diff)
+		dapm->idle_bias_off = 1;
+
+	return 0;
+
+}
+
+#ifdef CONFIG_PM
+static int wm8993_suspend(struct snd_soc_component *component)
+{
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+	int fll_fout = wm8993->fll_fout;
+	int fll_fref  = wm8993->fll_fref;
+	int ret;
+
+	/* Stop the FLL in an orderly fashion */
+	ret = _wm8993_set_fll(component, 0, 0, 0, 0);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to stop FLL\n");
+		return ret;
+	}
+
+	wm8993->fll_fout = fll_fout;
+	wm8993->fll_fref = fll_fref;
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int wm8993_resume(struct snd_soc_component *component)
+{
+	struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	/* Restart the FLL? */
+	if (wm8993->fll_fout) {
+		int fll_fout = wm8993->fll_fout;
+		int fll_fref  = wm8993->fll_fref;
+
+		wm8993->fll_fref = 0;
+		wm8993->fll_fout = 0;
+
+		ret = _wm8993_set_fll(component, 0, wm8993->fll_src,
+				     fll_fref, fll_fout);
+		if (ret != 0)
+			dev_err(component->dev, "Failed to restart FLL\n");
+	}
+
+	return 0;
+}
+#else
+#define wm8993_suspend NULL
+#define wm8993_resume NULL
+#endif
+
+/* Tune DC servo configuration */
+static const struct reg_sequence wm8993_regmap_patch[] = {
+	{ 0x44, 3 },
+	{ 0x56, 3 },
+	{ 0x44, 0 },
+};
+
+static const struct regmap_config wm8993_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = WM8993_MAX_REGISTER,
+	.volatile_reg = wm8993_volatile,
+	.readable_reg = wm8993_readable,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm8993_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8993_reg_defaults),
+};
+
+static const struct snd_soc_component_driver soc_component_dev_wm8993 = {
+	.probe			= wm8993_probe,
+	.suspend		= wm8993_suspend,
+	.resume			= wm8993_resume,
+	.set_bias_level		= wm8993_set_bias_level,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm8993_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8993_priv *wm8993;
+	unsigned int reg;
+	int ret, i;
+
+	wm8993 = devm_kzalloc(&i2c->dev, sizeof(struct wm8993_priv),
+			      GFP_KERNEL);
+	if (wm8993 == NULL)
+		return -ENOMEM;
+
+	wm8993->dev = &i2c->dev;
+	init_completion(&wm8993->fll_lock);
+
+	wm8993->regmap = devm_regmap_init_i2c(i2c, &wm8993_regmap);
+	if (IS_ERR(wm8993->regmap)) {
+		ret = PTR_ERR(wm8993->regmap);
+		dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, wm8993);
+
+	for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++)
+		wm8993->supplies[i].supply = wm8993_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8993->supplies),
+				 wm8993->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
+				    wm8993->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(wm8993->regmap, WM8993_SOFTWARE_RESET, &reg);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
+		goto err_enable;
+	}
+
+	if (reg != 0x8993) {
+		dev_err(&i2c->dev, "Invalid ID register value %x\n", reg);
+		ret = -EINVAL;
+		goto err_enable;
+	}
+
+	ret = regmap_write(wm8993->regmap, WM8993_SOFTWARE_RESET, 0xffff);
+	if (ret != 0)
+		goto err_enable;
+
+	ret = regmap_register_patch(wm8993->regmap, wm8993_regmap_patch,
+				    ARRAY_SIZE(wm8993_regmap_patch));
+	if (ret != 0)
+		dev_warn(wm8993->dev, "Failed to apply regmap patch: %d\n",
+			 ret);
+
+	if (i2c->irq) {
+		/* Put GPIO1 into interrupt mode (only GPIO1 can output IRQ) */
+		ret = regmap_update_bits(wm8993->regmap, WM8993_GPIO1,
+					 WM8993_GPIO1_PD |
+					 WM8993_GPIO1_SEL_MASK, 7);
+		if (ret != 0)
+			goto err_enable;
+
+		ret = request_threaded_irq(i2c->irq, NULL, wm8993_irq,
+					   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					   "wm8993", wm8993);
+		if (ret != 0)
+			goto err_enable;
+
+	}
+
+	regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
+
+	regcache_cache_only(wm8993->regmap, true);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm8993, &wm8993_dai, 1);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+		goto err_irq;
+	}
+
+	return 0;
+
+err_irq:
+	if (i2c->irq)
+		free_irq(i2c->irq, wm8993);
+err_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
+	return ret;
+}
+
+static int wm8993_i2c_remove(struct i2c_client *i2c)
+{
+	struct wm8993_priv *wm8993 = i2c_get_clientdata(i2c);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, wm8993);
+	regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
+
+	return 0;
+}
+
+static const struct i2c_device_id wm8993_i2c_id[] = {
+	{ "wm8993", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8993_i2c_id);
+
+static struct i2c_driver wm8993_i2c_driver = {
+	.driver = {
+		.name = "wm8993",
+	},
+	.probe =    wm8993_i2c_probe,
+	.remove =   wm8993_i2c_remove,
+	.id_table = wm8993_i2c_id,
+};
+
+module_i2c_driver(wm8993_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8993 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8993.h b/sound/soc/codecs/wm8993.h
new file mode 100644
index 0000000..91811aa
--- /dev/null
+++ b/sound/soc/codecs/wm8993.h
@@ -0,0 +1,2139 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef WM8993_H
+#define WM8993_H
+
+#define WM8993_SYSCLK_MCLK     1
+#define WM8993_SYSCLK_FLL      2
+
+#define WM8993_FLL_MCLK  1
+#define WM8993_FLL_BCLK  2
+#define WM8993_FLL_LRCLK 3
+
+/*
+ * Register values.
+ */
+#define WM8993_SOFTWARE_RESET                   0x00
+#define WM8993_POWER_MANAGEMENT_1               0x01
+#define WM8993_POWER_MANAGEMENT_2               0x02
+#define WM8993_POWER_MANAGEMENT_3               0x03
+#define WM8993_AUDIO_INTERFACE_1                0x04
+#define WM8993_AUDIO_INTERFACE_2                0x05
+#define WM8993_CLOCKING_1                       0x06
+#define WM8993_CLOCKING_2                       0x07
+#define WM8993_AUDIO_INTERFACE_3                0x08
+#define WM8993_AUDIO_INTERFACE_4                0x09
+#define WM8993_DAC_CTRL                         0x0A
+#define WM8993_LEFT_DAC_DIGITAL_VOLUME          0x0B
+#define WM8993_RIGHT_DAC_DIGITAL_VOLUME         0x0C
+#define WM8993_DIGITAL_SIDE_TONE                0x0D
+#define WM8993_ADC_CTRL                         0x0E
+#define WM8993_LEFT_ADC_DIGITAL_VOLUME          0x0F
+#define WM8993_RIGHT_ADC_DIGITAL_VOLUME         0x10
+#define WM8993_GPIO_CTRL_1                      0x12
+#define WM8993_GPIO1                            0x13
+#define WM8993_IRQ_DEBOUNCE                     0x14
+#define WM8993_INPUTS_CLAMP_REG			0x15
+#define WM8993_GPIOCTRL_2                       0x16
+#define WM8993_GPIO_POL                         0x17
+#define WM8993_LEFT_LINE_INPUT_1_2_VOLUME       0x18
+#define WM8993_LEFT_LINE_INPUT_3_4_VOLUME       0x19
+#define WM8993_RIGHT_LINE_INPUT_1_2_VOLUME      0x1A
+#define WM8993_RIGHT_LINE_INPUT_3_4_VOLUME      0x1B
+#define WM8993_LEFT_OUTPUT_VOLUME               0x1C
+#define WM8993_RIGHT_OUTPUT_VOLUME              0x1D
+#define WM8993_LINE_OUTPUTS_VOLUME              0x1E
+#define WM8993_HPOUT2_VOLUME                    0x1F
+#define WM8993_LEFT_OPGA_VOLUME                 0x20
+#define WM8993_RIGHT_OPGA_VOLUME                0x21
+#define WM8993_SPKMIXL_ATTENUATION              0x22
+#define WM8993_SPKMIXR_ATTENUATION              0x23
+#define WM8993_SPKOUT_MIXERS                    0x24
+#define WM8993_SPKOUT_BOOST                     0x25
+#define WM8993_SPEAKER_VOLUME_LEFT              0x26
+#define WM8993_SPEAKER_VOLUME_RIGHT             0x27
+#define WM8993_INPUT_MIXER2                     0x28
+#define WM8993_INPUT_MIXER3                     0x29
+#define WM8993_INPUT_MIXER4                     0x2A
+#define WM8993_INPUT_MIXER5                     0x2B
+#define WM8993_INPUT_MIXER6                     0x2C
+#define WM8993_OUTPUT_MIXER1                    0x2D
+#define WM8993_OUTPUT_MIXER2                    0x2E
+#define WM8993_OUTPUT_MIXER3                    0x2F
+#define WM8993_OUTPUT_MIXER4                    0x30
+#define WM8993_OUTPUT_MIXER5                    0x31
+#define WM8993_OUTPUT_MIXER6                    0x32
+#define WM8993_HPOUT2_MIXER                     0x33
+#define WM8993_LINE_MIXER1                      0x34
+#define WM8993_LINE_MIXER2                      0x35
+#define WM8993_SPEAKER_MIXER                    0x36
+#define WM8993_ADDITIONAL_CONTROL               0x37
+#define WM8993_ANTIPOP1                         0x38
+#define WM8993_ANTIPOP2                         0x39
+#define WM8993_MICBIAS                          0x3A
+#define WM8993_FLL_CONTROL_1                    0x3C
+#define WM8993_FLL_CONTROL_2                    0x3D
+#define WM8993_FLL_CONTROL_3                    0x3E
+#define WM8993_FLL_CONTROL_4                    0x3F
+#define WM8993_FLL_CONTROL_5                    0x40
+#define WM8993_CLOCKING_3                       0x41
+#define WM8993_CLOCKING_4                       0x42
+#define WM8993_MW_SLAVE_CONTROL                 0x43
+#define WM8993_BUS_CONTROL_1                    0x45
+#define WM8993_WRITE_SEQUENCER_0                0x46
+#define WM8993_WRITE_SEQUENCER_1                0x47
+#define WM8993_WRITE_SEQUENCER_2                0x48
+#define WM8993_WRITE_SEQUENCER_3                0x49
+#define WM8993_WRITE_SEQUENCER_4                0x4A
+#define WM8993_WRITE_SEQUENCER_5                0x4B
+#define WM8993_CHARGE_PUMP_1                    0x4C
+#define WM8993_CLASS_W_0                        0x51
+#define WM8993_DC_SERVO_0                       0x54
+#define WM8993_DC_SERVO_1                       0x55
+#define WM8993_DC_SERVO_3                       0x57
+#define WM8993_DC_SERVO_READBACK_0              0x58
+#define WM8993_DC_SERVO_READBACK_1              0x59
+#define WM8993_DC_SERVO_READBACK_2              0x5A
+#define WM8993_ANALOGUE_HP_0                    0x60
+#define WM8993_EQ1                              0x62
+#define WM8993_EQ2                              0x63
+#define WM8993_EQ3                              0x64
+#define WM8993_EQ4                              0x65
+#define WM8993_EQ5                              0x66
+#define WM8993_EQ6                              0x67
+#define WM8993_EQ7                              0x68
+#define WM8993_EQ8                              0x69
+#define WM8993_EQ9                              0x6A
+#define WM8993_EQ10                             0x6B
+#define WM8993_EQ11                             0x6C
+#define WM8993_EQ12                             0x6D
+#define WM8993_EQ13                             0x6E
+#define WM8993_EQ14                             0x6F
+#define WM8993_EQ15                             0x70
+#define WM8993_EQ16                             0x71
+#define WM8993_EQ17                             0x72
+#define WM8993_EQ18                             0x73
+#define WM8993_EQ19                             0x74
+#define WM8993_EQ20                             0x75
+#define WM8993_EQ21                             0x76
+#define WM8993_EQ22                             0x77
+#define WM8993_EQ23                             0x78
+#define WM8993_EQ24                             0x79
+#define WM8993_DIGITAL_PULLS                    0x7A
+#define WM8993_DRC_CONTROL_1                    0x7B
+#define WM8993_DRC_CONTROL_2                    0x7C
+#define WM8993_DRC_CONTROL_3                    0x7D
+#define WM8993_DRC_CONTROL_4                    0x7E
+
+#define WM8993_REGISTER_COUNT                   0x7F
+#define WM8993_MAX_REGISTER                     0x7E
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8993_SW_RESET_MASK                    0xFFFF  /* SW_RESET - [15:0] */
+#define WM8993_SW_RESET_SHIFT                        0  /* SW_RESET - [15:0] */
+#define WM8993_SW_RESET_WIDTH                       16  /* SW_RESET - [15:0] */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM8993_SPKOUTR_ENA                      0x2000  /* SPKOUTR_ENA */
+#define WM8993_SPKOUTR_ENA_MASK                 0x2000  /* SPKOUTR_ENA */
+#define WM8993_SPKOUTR_ENA_SHIFT                    13  /* SPKOUTR_ENA */
+#define WM8993_SPKOUTR_ENA_WIDTH                     1  /* SPKOUTR_ENA */
+#define WM8993_SPKOUTL_ENA                      0x1000  /* SPKOUTL_ENA */
+#define WM8993_SPKOUTL_ENA_MASK                 0x1000  /* SPKOUTL_ENA */
+#define WM8993_SPKOUTL_ENA_SHIFT                    12  /* SPKOUTL_ENA */
+#define WM8993_SPKOUTL_ENA_WIDTH                     1  /* SPKOUTL_ENA */
+#define WM8993_HPOUT2_ENA                       0x0800  /* HPOUT2_ENA */
+#define WM8993_HPOUT2_ENA_MASK                  0x0800  /* HPOUT2_ENA */
+#define WM8993_HPOUT2_ENA_SHIFT                     11  /* HPOUT2_ENA */
+#define WM8993_HPOUT2_ENA_WIDTH                      1  /* HPOUT2_ENA */
+#define WM8993_HPOUT1L_ENA                      0x0200  /* HPOUT1L_ENA */
+#define WM8993_HPOUT1L_ENA_MASK                 0x0200  /* HPOUT1L_ENA */
+#define WM8993_HPOUT1L_ENA_SHIFT                     9  /* HPOUT1L_ENA */
+#define WM8993_HPOUT1L_ENA_WIDTH                     1  /* HPOUT1L_ENA */
+#define WM8993_HPOUT1R_ENA                      0x0100  /* HPOUT1R_ENA */
+#define WM8993_HPOUT1R_ENA_MASK                 0x0100  /* HPOUT1R_ENA */
+#define WM8993_HPOUT1R_ENA_SHIFT                     8  /* HPOUT1R_ENA */
+#define WM8993_HPOUT1R_ENA_WIDTH                     1  /* HPOUT1R_ENA */
+#define WM8993_MICB2_ENA                        0x0020  /* MICB2_ENA */
+#define WM8993_MICB2_ENA_MASK                   0x0020  /* MICB2_ENA */
+#define WM8993_MICB2_ENA_SHIFT                       5  /* MICB2_ENA */
+#define WM8993_MICB2_ENA_WIDTH                       1  /* MICB2_ENA */
+#define WM8993_MICB1_ENA                        0x0010  /* MICB1_ENA */
+#define WM8993_MICB1_ENA_MASK                   0x0010  /* MICB1_ENA */
+#define WM8993_MICB1_ENA_SHIFT                       4  /* MICB1_ENA */
+#define WM8993_MICB1_ENA_WIDTH                       1  /* MICB1_ENA */
+#define WM8993_VMID_SEL_MASK                    0x0006  /* VMID_SEL - [2:1] */
+#define WM8993_VMID_SEL_SHIFT                        1  /* VMID_SEL - [2:1] */
+#define WM8993_VMID_SEL_WIDTH                        2  /* VMID_SEL - [2:1] */
+#define WM8993_BIAS_ENA                         0x0001  /* BIAS_ENA */
+#define WM8993_BIAS_ENA_MASK                    0x0001  /* BIAS_ENA */
+#define WM8993_BIAS_ENA_SHIFT                        0  /* BIAS_ENA */
+#define WM8993_BIAS_ENA_WIDTH                        1  /* BIAS_ENA */
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM8993_TSHUT_ENA                        0x4000  /* TSHUT_ENA */
+#define WM8993_TSHUT_ENA_MASK                   0x4000  /* TSHUT_ENA */
+#define WM8993_TSHUT_ENA_SHIFT                      14  /* TSHUT_ENA */
+#define WM8993_TSHUT_ENA_WIDTH                       1  /* TSHUT_ENA */
+#define WM8993_TSHUT_OPDIS                      0x2000  /* TSHUT_OPDIS */
+#define WM8993_TSHUT_OPDIS_MASK                 0x2000  /* TSHUT_OPDIS */
+#define WM8993_TSHUT_OPDIS_SHIFT                    13  /* TSHUT_OPDIS */
+#define WM8993_TSHUT_OPDIS_WIDTH                     1  /* TSHUT_OPDIS */
+#define WM8993_OPCLK_ENA                        0x0800  /* OPCLK_ENA */
+#define WM8993_OPCLK_ENA_MASK                   0x0800  /* OPCLK_ENA */
+#define WM8993_OPCLK_ENA_SHIFT                      11  /* OPCLK_ENA */
+#define WM8993_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8993_MIXINL_ENA                       0x0200  /* MIXINL_ENA */
+#define WM8993_MIXINL_ENA_MASK                  0x0200  /* MIXINL_ENA */
+#define WM8993_MIXINL_ENA_SHIFT                      9  /* MIXINL_ENA */
+#define WM8993_MIXINL_ENA_WIDTH                      1  /* MIXINL_ENA */
+#define WM8993_MIXINR_ENA                       0x0100  /* MIXINR_ENA */
+#define WM8993_MIXINR_ENA_MASK                  0x0100  /* MIXINR_ENA */
+#define WM8993_MIXINR_ENA_SHIFT                      8  /* MIXINR_ENA */
+#define WM8993_MIXINR_ENA_WIDTH                      1  /* MIXINR_ENA */
+#define WM8993_IN2L_ENA                         0x0080  /* IN2L_ENA */
+#define WM8993_IN2L_ENA_MASK                    0x0080  /* IN2L_ENA */
+#define WM8993_IN2L_ENA_SHIFT                        7  /* IN2L_ENA */
+#define WM8993_IN2L_ENA_WIDTH                        1  /* IN2L_ENA */
+#define WM8993_IN1L_ENA                         0x0040  /* IN1L_ENA */
+#define WM8993_IN1L_ENA_MASK                    0x0040  /* IN1L_ENA */
+#define WM8993_IN1L_ENA_SHIFT                        6  /* IN1L_ENA */
+#define WM8993_IN1L_ENA_WIDTH                        1  /* IN1L_ENA */
+#define WM8993_IN2R_ENA                         0x0020  /* IN2R_ENA */
+#define WM8993_IN2R_ENA_MASK                    0x0020  /* IN2R_ENA */
+#define WM8993_IN2R_ENA_SHIFT                        5  /* IN2R_ENA */
+#define WM8993_IN2R_ENA_WIDTH                        1  /* IN2R_ENA */
+#define WM8993_IN1R_ENA                         0x0010  /* IN1R_ENA */
+#define WM8993_IN1R_ENA_MASK                    0x0010  /* IN1R_ENA */
+#define WM8993_IN1R_ENA_SHIFT                        4  /* IN1R_ENA */
+#define WM8993_IN1R_ENA_WIDTH                        1  /* IN1R_ENA */
+#define WM8993_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8993_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8993_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8993_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8993_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8993_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8993_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8993_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM8993_LINEOUT1N_ENA                    0x2000  /* LINEOUT1N_ENA */
+#define WM8993_LINEOUT1N_ENA_MASK               0x2000  /* LINEOUT1N_ENA */
+#define WM8993_LINEOUT1N_ENA_SHIFT                  13  /* LINEOUT1N_ENA */
+#define WM8993_LINEOUT1N_ENA_WIDTH                   1  /* LINEOUT1N_ENA */
+#define WM8993_LINEOUT1P_ENA                    0x1000  /* LINEOUT1P_ENA */
+#define WM8993_LINEOUT1P_ENA_MASK               0x1000  /* LINEOUT1P_ENA */
+#define WM8993_LINEOUT1P_ENA_SHIFT                  12  /* LINEOUT1P_ENA */
+#define WM8993_LINEOUT1P_ENA_WIDTH                   1  /* LINEOUT1P_ENA */
+#define WM8993_LINEOUT2N_ENA                    0x0800  /* LINEOUT2N_ENA */
+#define WM8993_LINEOUT2N_ENA_MASK               0x0800  /* LINEOUT2N_ENA */
+#define WM8993_LINEOUT2N_ENA_SHIFT                  11  /* LINEOUT2N_ENA */
+#define WM8993_LINEOUT2N_ENA_WIDTH                   1  /* LINEOUT2N_ENA */
+#define WM8993_LINEOUT2P_ENA                    0x0400  /* LINEOUT2P_ENA */
+#define WM8993_LINEOUT2P_ENA_MASK               0x0400  /* LINEOUT2P_ENA */
+#define WM8993_LINEOUT2P_ENA_SHIFT                  10  /* LINEOUT2P_ENA */
+#define WM8993_LINEOUT2P_ENA_WIDTH                   1  /* LINEOUT2P_ENA */
+#define WM8993_SPKRVOL_ENA                      0x0200  /* SPKRVOL_ENA */
+#define WM8993_SPKRVOL_ENA_MASK                 0x0200  /* SPKRVOL_ENA */
+#define WM8993_SPKRVOL_ENA_SHIFT                     9  /* SPKRVOL_ENA */
+#define WM8993_SPKRVOL_ENA_WIDTH                     1  /* SPKRVOL_ENA */
+#define WM8993_SPKLVOL_ENA                      0x0100  /* SPKLVOL_ENA */
+#define WM8993_SPKLVOL_ENA_MASK                 0x0100  /* SPKLVOL_ENA */
+#define WM8993_SPKLVOL_ENA_SHIFT                     8  /* SPKLVOL_ENA */
+#define WM8993_SPKLVOL_ENA_WIDTH                     1  /* SPKLVOL_ENA */
+#define WM8993_MIXOUTLVOL_ENA                   0x0080  /* MIXOUTLVOL_ENA */
+#define WM8993_MIXOUTLVOL_ENA_MASK              0x0080  /* MIXOUTLVOL_ENA */
+#define WM8993_MIXOUTLVOL_ENA_SHIFT                  7  /* MIXOUTLVOL_ENA */
+#define WM8993_MIXOUTLVOL_ENA_WIDTH                  1  /* MIXOUTLVOL_ENA */
+#define WM8993_MIXOUTRVOL_ENA                   0x0040  /* MIXOUTRVOL_ENA */
+#define WM8993_MIXOUTRVOL_ENA_MASK              0x0040  /* MIXOUTRVOL_ENA */
+#define WM8993_MIXOUTRVOL_ENA_SHIFT                  6  /* MIXOUTRVOL_ENA */
+#define WM8993_MIXOUTRVOL_ENA_WIDTH                  1  /* MIXOUTRVOL_ENA */
+#define WM8993_MIXOUTL_ENA                      0x0020  /* MIXOUTL_ENA */
+#define WM8993_MIXOUTL_ENA_MASK                 0x0020  /* MIXOUTL_ENA */
+#define WM8993_MIXOUTL_ENA_SHIFT                     5  /* MIXOUTL_ENA */
+#define WM8993_MIXOUTL_ENA_WIDTH                     1  /* MIXOUTL_ENA */
+#define WM8993_MIXOUTR_ENA                      0x0010  /* MIXOUTR_ENA */
+#define WM8993_MIXOUTR_ENA_MASK                 0x0010  /* MIXOUTR_ENA */
+#define WM8993_MIXOUTR_ENA_SHIFT                     4  /* MIXOUTR_ENA */
+#define WM8993_MIXOUTR_ENA_WIDTH                     1  /* MIXOUTR_ENA */
+#define WM8993_DACL_ENA                         0x0002  /* DACL_ENA */
+#define WM8993_DACL_ENA_MASK                    0x0002  /* DACL_ENA */
+#define WM8993_DACL_ENA_SHIFT                        1  /* DACL_ENA */
+#define WM8993_DACL_ENA_WIDTH                        1  /* DACL_ENA */
+#define WM8993_DACR_ENA                         0x0001  /* DACR_ENA */
+#define WM8993_DACR_ENA_MASK                    0x0001  /* DACR_ENA */
+#define WM8993_DACR_ENA_SHIFT                        0  /* DACR_ENA */
+#define WM8993_DACR_ENA_WIDTH                        1  /* DACR_ENA */
+
+/*
+ * R4 (0x04) - Audio Interface (1)
+ */
+#define WM8993_AIFADCL_SRC                      0x8000  /* AIFADCL_SRC */
+#define WM8993_AIFADCL_SRC_MASK                 0x8000  /* AIFADCL_SRC */
+#define WM8993_AIFADCL_SRC_SHIFT                    15  /* AIFADCL_SRC */
+#define WM8993_AIFADCL_SRC_WIDTH                     1  /* AIFADCL_SRC */
+#define WM8993_AIFADCR_SRC                      0x4000  /* AIFADCR_SRC */
+#define WM8993_AIFADCR_SRC_MASK                 0x4000  /* AIFADCR_SRC */
+#define WM8993_AIFADCR_SRC_SHIFT                    14  /* AIFADCR_SRC */
+#define WM8993_AIFADCR_SRC_WIDTH                     1  /* AIFADCR_SRC */
+#define WM8993_AIFADC_TDM                       0x2000  /* AIFADC_TDM */
+#define WM8993_AIFADC_TDM_MASK                  0x2000  /* AIFADC_TDM */
+#define WM8993_AIFADC_TDM_SHIFT                     13  /* AIFADC_TDM */
+#define WM8993_AIFADC_TDM_WIDTH                      1  /* AIFADC_TDM */
+#define WM8993_AIFADC_TDM_CHAN                  0x1000  /* AIFADC_TDM_CHAN */
+#define WM8993_AIFADC_TDM_CHAN_MASK             0x1000  /* AIFADC_TDM_CHAN */
+#define WM8993_AIFADC_TDM_CHAN_SHIFT                12  /* AIFADC_TDM_CHAN */
+#define WM8993_AIFADC_TDM_CHAN_WIDTH                 1  /* AIFADC_TDM_CHAN */
+#define WM8993_BCLK_DIR                         0x0200  /* BCLK_DIR */
+#define WM8993_BCLK_DIR_MASK                    0x0200  /* BCLK_DIR */
+#define WM8993_BCLK_DIR_SHIFT                        9  /* BCLK_DIR */
+#define WM8993_BCLK_DIR_WIDTH                        1  /* BCLK_DIR */
+#define WM8993_AIF_BCLK_INV                     0x0100  /* AIF_BCLK_INV */
+#define WM8993_AIF_BCLK_INV_MASK                0x0100  /* AIF_BCLK_INV */
+#define WM8993_AIF_BCLK_INV_SHIFT                    8  /* AIF_BCLK_INV */
+#define WM8993_AIF_BCLK_INV_WIDTH                    1  /* AIF_BCLK_INV */
+#define WM8993_AIF_LRCLK_INV                    0x0080  /* AIF_LRCLK_INV */
+#define WM8993_AIF_LRCLK_INV_MASK               0x0080  /* AIF_LRCLK_INV */
+#define WM8993_AIF_LRCLK_INV_SHIFT                   7  /* AIF_LRCLK_INV */
+#define WM8993_AIF_LRCLK_INV_WIDTH                   1  /* AIF_LRCLK_INV */
+#define WM8993_AIF_WL_MASK                      0x0060  /* AIF_WL - [6:5] */
+#define WM8993_AIF_WL_SHIFT                          5  /* AIF_WL - [6:5] */
+#define WM8993_AIF_WL_WIDTH                          2  /* AIF_WL - [6:5] */
+#define WM8993_AIF_FMT_MASK                     0x0018  /* AIF_FMT - [4:3] */
+#define WM8993_AIF_FMT_SHIFT                         3  /* AIF_FMT - [4:3] */
+#define WM8993_AIF_FMT_WIDTH                         2  /* AIF_FMT - [4:3] */
+
+/*
+ * R5 (0x05) - Audio Interface (2)
+ */
+#define WM8993_AIFDACL_SRC                      0x8000  /* AIFDACL_SRC */
+#define WM8993_AIFDACL_SRC_MASK                 0x8000  /* AIFDACL_SRC */
+#define WM8993_AIFDACL_SRC_SHIFT                    15  /* AIFDACL_SRC */
+#define WM8993_AIFDACL_SRC_WIDTH                     1  /* AIFDACL_SRC */
+#define WM8993_AIFDACR_SRC                      0x4000  /* AIFDACR_SRC */
+#define WM8993_AIFDACR_SRC_MASK                 0x4000  /* AIFDACR_SRC */
+#define WM8993_AIFDACR_SRC_SHIFT                    14  /* AIFDACR_SRC */
+#define WM8993_AIFDACR_SRC_WIDTH                     1  /* AIFDACR_SRC */
+#define WM8993_AIFDAC_TDM                       0x2000  /* AIFDAC_TDM */
+#define WM8993_AIFDAC_TDM_MASK                  0x2000  /* AIFDAC_TDM */
+#define WM8993_AIFDAC_TDM_SHIFT                     13  /* AIFDAC_TDM */
+#define WM8993_AIFDAC_TDM_WIDTH                      1  /* AIFDAC_TDM */
+#define WM8993_AIFDAC_TDM_CHAN                  0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8993_AIFDAC_TDM_CHAN_MASK             0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8993_AIFDAC_TDM_CHAN_SHIFT                12  /* AIFDAC_TDM_CHAN */
+#define WM8993_AIFDAC_TDM_CHAN_WIDTH                 1  /* AIFDAC_TDM_CHAN */
+#define WM8993_DAC_BOOST_MASK                   0x0C00  /* DAC_BOOST - [11:10] */
+#define WM8993_DAC_BOOST_SHIFT                      10  /* DAC_BOOST - [11:10] */
+#define WM8993_DAC_BOOST_WIDTH                       2  /* DAC_BOOST - [11:10] */
+#define WM8993_DAC_COMP                         0x0010  /* DAC_COMP */
+#define WM8993_DAC_COMP_MASK                    0x0010  /* DAC_COMP */
+#define WM8993_DAC_COMP_SHIFT                        4  /* DAC_COMP */
+#define WM8993_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM8993_DAC_COMPMODE                     0x0008  /* DAC_COMPMODE */
+#define WM8993_DAC_COMPMODE_MASK                0x0008  /* DAC_COMPMODE */
+#define WM8993_DAC_COMPMODE_SHIFT                    3  /* DAC_COMPMODE */
+#define WM8993_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+#define WM8993_ADC_COMP                         0x0004  /* ADC_COMP */
+#define WM8993_ADC_COMP_MASK                    0x0004  /* ADC_COMP */
+#define WM8993_ADC_COMP_SHIFT                        2  /* ADC_COMP */
+#define WM8993_ADC_COMP_WIDTH                        1  /* ADC_COMP */
+#define WM8993_ADC_COMPMODE                     0x0002  /* ADC_COMPMODE */
+#define WM8993_ADC_COMPMODE_MASK                0x0002  /* ADC_COMPMODE */
+#define WM8993_ADC_COMPMODE_SHIFT                    1  /* ADC_COMPMODE */
+#define WM8993_ADC_COMPMODE_WIDTH                    1  /* ADC_COMPMODE */
+#define WM8993_LOOPBACK                         0x0001  /* LOOPBACK */
+#define WM8993_LOOPBACK_MASK                    0x0001  /* LOOPBACK */
+#define WM8993_LOOPBACK_SHIFT                        0  /* LOOPBACK */
+#define WM8993_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+
+/*
+ * R6 (0x06) - Clocking 1
+ */
+#define WM8993_TOCLK_RATE                       0x8000  /* TOCLK_RATE */
+#define WM8993_TOCLK_RATE_MASK                  0x8000  /* TOCLK_RATE */
+#define WM8993_TOCLK_RATE_SHIFT                     15  /* TOCLK_RATE */
+#define WM8993_TOCLK_RATE_WIDTH                      1  /* TOCLK_RATE */
+#define WM8993_TOCLK_ENA                        0x4000  /* TOCLK_ENA */
+#define WM8993_TOCLK_ENA_MASK                   0x4000  /* TOCLK_ENA */
+#define WM8993_TOCLK_ENA_SHIFT                      14  /* TOCLK_ENA */
+#define WM8993_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+#define WM8993_OPCLK_DIV_MASK                   0x1E00  /* OPCLK_DIV - [12:9] */
+#define WM8993_OPCLK_DIV_SHIFT                       9  /* OPCLK_DIV - [12:9] */
+#define WM8993_OPCLK_DIV_WIDTH                       4  /* OPCLK_DIV - [12:9] */
+#define WM8993_DCLK_DIV_MASK                    0x01C0  /* DCLK_DIV - [8:6] */
+#define WM8993_DCLK_DIV_SHIFT                        6  /* DCLK_DIV - [8:6] */
+#define WM8993_DCLK_DIV_WIDTH                        3  /* DCLK_DIV - [8:6] */
+#define WM8993_BCLK_DIV_MASK                    0x001E  /* BCLK_DIV - [4:1] */
+#define WM8993_BCLK_DIV_SHIFT                        1  /* BCLK_DIV - [4:1] */
+#define WM8993_BCLK_DIV_WIDTH                        4  /* BCLK_DIV - [4:1] */
+
+/*
+ * R7 (0x07) - Clocking 2
+ */
+#define WM8993_MCLK_SRC                         0x8000  /* MCLK_SRC */
+#define WM8993_MCLK_SRC_MASK                    0x8000  /* MCLK_SRC */
+#define WM8993_MCLK_SRC_SHIFT                       15  /* MCLK_SRC */
+#define WM8993_MCLK_SRC_WIDTH                        1  /* MCLK_SRC */
+#define WM8993_SYSCLK_SRC                       0x4000  /* SYSCLK_SRC */
+#define WM8993_SYSCLK_SRC_MASK                  0x4000  /* SYSCLK_SRC */
+#define WM8993_SYSCLK_SRC_SHIFT                     14  /* SYSCLK_SRC */
+#define WM8993_SYSCLK_SRC_WIDTH                      1  /* SYSCLK_SRC */
+#define WM8993_MCLK_DIV                         0x1000  /* MCLK_DIV */
+#define WM8993_MCLK_DIV_MASK                    0x1000  /* MCLK_DIV */
+#define WM8993_MCLK_DIV_SHIFT                       12  /* MCLK_DIV */
+#define WM8993_MCLK_DIV_WIDTH                        1  /* MCLK_DIV */
+#define WM8993_MCLK_INV                         0x0400  /* MCLK_INV */
+#define WM8993_MCLK_INV_MASK                    0x0400  /* MCLK_INV */
+#define WM8993_MCLK_INV_SHIFT                       10  /* MCLK_INV */
+#define WM8993_MCLK_INV_WIDTH                        1  /* MCLK_INV */
+#define WM8993_ADC_DIV_MASK                     0x00E0  /* ADC_DIV - [7:5] */
+#define WM8993_ADC_DIV_SHIFT                         5  /* ADC_DIV - [7:5] */
+#define WM8993_ADC_DIV_WIDTH                         3  /* ADC_DIV - [7:5] */
+#define WM8993_DAC_DIV_MASK                     0x001C  /* DAC_DIV - [4:2] */
+#define WM8993_DAC_DIV_SHIFT                         2  /* DAC_DIV - [4:2] */
+#define WM8993_DAC_DIV_WIDTH                         3  /* DAC_DIV - [4:2] */
+
+/*
+ * R8 (0x08) - Audio Interface (3)
+ */
+#define WM8993_AIF_MSTR1                        0x8000  /* AIF_MSTR1 */
+#define WM8993_AIF_MSTR1_MASK                   0x8000  /* AIF_MSTR1 */
+#define WM8993_AIF_MSTR1_SHIFT                      15  /* AIF_MSTR1 */
+#define WM8993_AIF_MSTR1_WIDTH                       1  /* AIF_MSTR1 */
+
+/*
+ * R9 (0x09) - Audio Interface (4)
+ */
+#define WM8993_AIF_TRIS                         0x2000  /* AIF_TRIS */
+#define WM8993_AIF_TRIS_MASK                    0x2000  /* AIF_TRIS */
+#define WM8993_AIF_TRIS_SHIFT                       13  /* AIF_TRIS */
+#define WM8993_AIF_TRIS_WIDTH                        1  /* AIF_TRIS */
+#define WM8993_LRCLK_DIR                        0x0800  /* LRCLK_DIR */
+#define WM8993_LRCLK_DIR_MASK                   0x0800  /* LRCLK_DIR */
+#define WM8993_LRCLK_DIR_SHIFT                      11  /* LRCLK_DIR */
+#define WM8993_LRCLK_DIR_WIDTH                       1  /* LRCLK_DIR */
+#define WM8993_LRCLK_RATE_MASK                  0x07FF  /* LRCLK_RATE - [10:0] */
+#define WM8993_LRCLK_RATE_SHIFT                      0  /* LRCLK_RATE - [10:0] */
+#define WM8993_LRCLK_RATE_WIDTH                     11  /* LRCLK_RATE - [10:0] */
+
+/*
+ * R10 (0x0A) - DAC CTRL
+ */
+#define WM8993_DAC_OSR128                       0x2000  /* DAC_OSR128 */
+#define WM8993_DAC_OSR128_MASK                  0x2000  /* DAC_OSR128 */
+#define WM8993_DAC_OSR128_SHIFT                     13  /* DAC_OSR128 */
+#define WM8993_DAC_OSR128_WIDTH                      1  /* DAC_OSR128 */
+#define WM8993_DAC_MONO                         0x0200  /* DAC_MONO */
+#define WM8993_DAC_MONO_MASK                    0x0200  /* DAC_MONO */
+#define WM8993_DAC_MONO_SHIFT                        9  /* DAC_MONO */
+#define WM8993_DAC_MONO_WIDTH                        1  /* DAC_MONO */
+#define WM8993_DAC_SB_FILT                      0x0100  /* DAC_SB_FILT */
+#define WM8993_DAC_SB_FILT_MASK                 0x0100  /* DAC_SB_FILT */
+#define WM8993_DAC_SB_FILT_SHIFT                     8  /* DAC_SB_FILT */
+#define WM8993_DAC_SB_FILT_WIDTH                     1  /* DAC_SB_FILT */
+#define WM8993_DAC_MUTERATE                     0x0080  /* DAC_MUTERATE */
+#define WM8993_DAC_MUTERATE_MASK                0x0080  /* DAC_MUTERATE */
+#define WM8993_DAC_MUTERATE_SHIFT                    7  /* DAC_MUTERATE */
+#define WM8993_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM8993_DAC_UNMUTE_RAMP                  0x0040  /* DAC_UNMUTE_RAMP */
+#define WM8993_DAC_UNMUTE_RAMP_MASK             0x0040  /* DAC_UNMUTE_RAMP */
+#define WM8993_DAC_UNMUTE_RAMP_SHIFT                 6  /* DAC_UNMUTE_RAMP */
+#define WM8993_DAC_UNMUTE_RAMP_WIDTH                 1  /* DAC_UNMUTE_RAMP */
+#define WM8993_DEEMPH_MASK                      0x0030  /* DEEMPH - [5:4] */
+#define WM8993_DEEMPH_SHIFT                          4  /* DEEMPH - [5:4] */
+#define WM8993_DEEMPH_WIDTH                          2  /* DEEMPH - [5:4] */
+#define WM8993_DAC_MUTE                         0x0004  /* DAC_MUTE */
+#define WM8993_DAC_MUTE_MASK                    0x0004  /* DAC_MUTE */
+#define WM8993_DAC_MUTE_SHIFT                        2  /* DAC_MUTE */
+#define WM8993_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM8993_DACL_DATINV                      0x0002  /* DACL_DATINV */
+#define WM8993_DACL_DATINV_MASK                 0x0002  /* DACL_DATINV */
+#define WM8993_DACL_DATINV_SHIFT                     1  /* DACL_DATINV */
+#define WM8993_DACL_DATINV_WIDTH                     1  /* DACL_DATINV */
+#define WM8993_DACR_DATINV                      0x0001  /* DACR_DATINV */
+#define WM8993_DACR_DATINV_MASK                 0x0001  /* DACR_DATINV */
+#define WM8993_DACR_DATINV_SHIFT                     0  /* DACR_DATINV */
+#define WM8993_DACR_DATINV_WIDTH                     1  /* DACR_DATINV */
+
+/*
+ * R11 (0x0B) - Left DAC Digital Volume
+ */
+#define WM8993_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8993_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8993_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8993_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8993_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8993_DACL_VOL_SHIFT                        0  /* DACL_VOL - [7:0] */
+#define WM8993_DACL_VOL_WIDTH                        8  /* DACL_VOL - [7:0] */
+
+/*
+ * R12 (0x0C) - Right DAC Digital Volume
+ */
+#define WM8993_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8993_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8993_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8993_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8993_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8993_DACR_VOL_SHIFT                        0  /* DACR_VOL - [7:0] */
+#define WM8993_DACR_VOL_WIDTH                        8  /* DACR_VOL - [7:0] */
+
+/*
+ * R13 (0x0D) - Digital Side Tone
+ */
+#define WM8993_ADCL_DAC_SVOL_MASK               0x1E00  /* ADCL_DAC_SVOL - [12:9] */
+#define WM8993_ADCL_DAC_SVOL_SHIFT                   9  /* ADCL_DAC_SVOL - [12:9] */
+#define WM8993_ADCL_DAC_SVOL_WIDTH                   4  /* ADCL_DAC_SVOL - [12:9] */
+#define WM8993_ADCR_DAC_SVOL_MASK               0x01E0  /* ADCR_DAC_SVOL - [8:5] */
+#define WM8993_ADCR_DAC_SVOL_SHIFT                   5  /* ADCR_DAC_SVOL - [8:5] */
+#define WM8993_ADCR_DAC_SVOL_WIDTH                   4  /* ADCR_DAC_SVOL - [8:5] */
+#define WM8993_ADC_TO_DACL_MASK                 0x000C  /* ADC_TO_DACL - [3:2] */
+#define WM8993_ADC_TO_DACL_SHIFT                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8993_ADC_TO_DACL_WIDTH                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8993_ADC_TO_DACR_MASK                 0x0003  /* ADC_TO_DACR - [1:0] */
+#define WM8993_ADC_TO_DACR_SHIFT                     0  /* ADC_TO_DACR - [1:0] */
+#define WM8993_ADC_TO_DACR_WIDTH                     2  /* ADC_TO_DACR - [1:0] */
+
+/*
+ * R14 (0x0E) - ADC CTRL
+ */
+#define WM8993_ADC_OSR128                       0x0200  /* ADC_OSR128 */
+#define WM8993_ADC_OSR128_MASK                  0x0200  /* ADC_OSR128 */
+#define WM8993_ADC_OSR128_SHIFT                      9  /* ADC_OSR128 */
+#define WM8993_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
+#define WM8993_ADC_HPF                          0x0100  /* ADC_HPF */
+#define WM8993_ADC_HPF_MASK                     0x0100  /* ADC_HPF */
+#define WM8993_ADC_HPF_SHIFT                         8  /* ADC_HPF */
+#define WM8993_ADC_HPF_WIDTH                         1  /* ADC_HPF */
+#define WM8993_ADC_HPF_CUT_MASK                 0x0060  /* ADC_HPF_CUT - [6:5] */
+#define WM8993_ADC_HPF_CUT_SHIFT                     5  /* ADC_HPF_CUT - [6:5] */
+#define WM8993_ADC_HPF_CUT_WIDTH                     2  /* ADC_HPF_CUT - [6:5] */
+#define WM8993_ADCL_DATINV                      0x0002  /* ADCL_DATINV */
+#define WM8993_ADCL_DATINV_MASK                 0x0002  /* ADCL_DATINV */
+#define WM8993_ADCL_DATINV_SHIFT                     1  /* ADCL_DATINV */
+#define WM8993_ADCL_DATINV_WIDTH                     1  /* ADCL_DATINV */
+#define WM8993_ADCR_DATINV                      0x0001  /* ADCR_DATINV */
+#define WM8993_ADCR_DATINV_MASK                 0x0001  /* ADCR_DATINV */
+#define WM8993_ADCR_DATINV_SHIFT                     0  /* ADCR_DATINV */
+#define WM8993_ADCR_DATINV_WIDTH                     1  /* ADCR_DATINV */
+
+/*
+ * R15 (0x0F) - Left ADC Digital Volume
+ */
+#define WM8993_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8993_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8993_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8993_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8993_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8993_ADCL_VOL_SHIFT                        0  /* ADCL_VOL - [7:0] */
+#define WM8993_ADCL_VOL_WIDTH                        8  /* ADCL_VOL - [7:0] */
+
+/*
+ * R16 (0x10) - Right ADC Digital Volume
+ */
+#define WM8993_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8993_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8993_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8993_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8993_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8993_ADCR_VOL_SHIFT                        0  /* ADCR_VOL - [7:0] */
+#define WM8993_ADCR_VOL_WIDTH                        8  /* ADCR_VOL - [7:0] */
+
+/*
+ * R18 (0x12) - GPIO CTRL 1
+ */
+#define WM8993_JD2_SC_EINT                      0x8000  /* JD2_SC_EINT */
+#define WM8993_JD2_SC_EINT_MASK                 0x8000  /* JD2_SC_EINT */
+#define WM8993_JD2_SC_EINT_SHIFT                    15  /* JD2_SC_EINT */
+#define WM8993_JD2_SC_EINT_WIDTH                     1  /* JD2_SC_EINT */
+#define WM8993_JD2_EINT                         0x4000  /* JD2_EINT */
+#define WM8993_JD2_EINT_MASK                    0x4000  /* JD2_EINT */
+#define WM8993_JD2_EINT_SHIFT                       14  /* JD2_EINT */
+#define WM8993_JD2_EINT_WIDTH                        1  /* JD2_EINT */
+#define WM8993_WSEQ_EINT                        0x2000  /* WSEQ_EINT */
+#define WM8993_WSEQ_EINT_MASK                   0x2000  /* WSEQ_EINT */
+#define WM8993_WSEQ_EINT_SHIFT                      13  /* WSEQ_EINT */
+#define WM8993_WSEQ_EINT_WIDTH                       1  /* WSEQ_EINT */
+#define WM8993_IRQ                              0x1000  /* IRQ */
+#define WM8993_IRQ_MASK                         0x1000  /* IRQ */
+#define WM8993_IRQ_SHIFT                            12  /* IRQ */
+#define WM8993_IRQ_WIDTH                             1  /* IRQ */
+#define WM8993_TEMPOK_EINT                      0x0800  /* TEMPOK_EINT */
+#define WM8993_TEMPOK_EINT_MASK                 0x0800  /* TEMPOK_EINT */
+#define WM8993_TEMPOK_EINT_SHIFT                    11  /* TEMPOK_EINT */
+#define WM8993_TEMPOK_EINT_WIDTH                     1  /* TEMPOK_EINT */
+#define WM8993_JD1_SC_EINT                      0x0400  /* JD1_SC_EINT */
+#define WM8993_JD1_SC_EINT_MASK                 0x0400  /* JD1_SC_EINT */
+#define WM8993_JD1_SC_EINT_SHIFT                    10  /* JD1_SC_EINT */
+#define WM8993_JD1_SC_EINT_WIDTH                     1  /* JD1_SC_EINT */
+#define WM8993_JD1_EINT                         0x0200  /* JD1_EINT */
+#define WM8993_JD1_EINT_MASK                    0x0200  /* JD1_EINT */
+#define WM8993_JD1_EINT_SHIFT                        9  /* JD1_EINT */
+#define WM8993_JD1_EINT_WIDTH                        1  /* JD1_EINT */
+#define WM8993_FLL_LOCK_EINT                    0x0100  /* FLL_LOCK_EINT */
+#define WM8993_FLL_LOCK_EINT_MASK               0x0100  /* FLL_LOCK_EINT */
+#define WM8993_FLL_LOCK_EINT_SHIFT                   8  /* FLL_LOCK_EINT */
+#define WM8993_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM8993_GPI8_EINT                        0x0080  /* GPI8_EINT */
+#define WM8993_GPI8_EINT_MASK                   0x0080  /* GPI8_EINT */
+#define WM8993_GPI8_EINT_SHIFT                       7  /* GPI8_EINT */
+#define WM8993_GPI8_EINT_WIDTH                       1  /* GPI8_EINT */
+#define WM8993_GPI7_EINT                        0x0040  /* GPI7_EINT */
+#define WM8993_GPI7_EINT_MASK                   0x0040  /* GPI7_EINT */
+#define WM8993_GPI7_EINT_SHIFT                       6  /* GPI7_EINT */
+#define WM8993_GPI7_EINT_WIDTH                       1  /* GPI7_EINT */
+#define WM8993_GPIO1_EINT                       0x0001  /* GPIO1_EINT */
+#define WM8993_GPIO1_EINT_MASK                  0x0001  /* GPIO1_EINT */
+#define WM8993_GPIO1_EINT_SHIFT                      0  /* GPIO1_EINT */
+#define WM8993_GPIO1_EINT_WIDTH                      1  /* GPIO1_EINT */
+
+/*
+ * R19 (0x13) - GPIO1
+ */
+#define WM8993_GPIO1_PU                         0x0020  /* GPIO1_PU */
+#define WM8993_GPIO1_PU_MASK                    0x0020  /* GPIO1_PU */
+#define WM8993_GPIO1_PU_SHIFT                        5  /* GPIO1_PU */
+#define WM8993_GPIO1_PU_WIDTH                        1  /* GPIO1_PU */
+#define WM8993_GPIO1_PD                         0x0010  /* GPIO1_PD */
+#define WM8993_GPIO1_PD_MASK                    0x0010  /* GPIO1_PD */
+#define WM8993_GPIO1_PD_SHIFT                        4  /* GPIO1_PD */
+#define WM8993_GPIO1_PD_WIDTH                        1  /* GPIO1_PD */
+#define WM8993_GPIO1_SEL_MASK                   0x000F  /* GPIO1_SEL - [3:0] */
+#define WM8993_GPIO1_SEL_SHIFT                       0  /* GPIO1_SEL - [3:0] */
+#define WM8993_GPIO1_SEL_WIDTH                       4  /* GPIO1_SEL - [3:0] */
+
+/*
+ * R20 (0x14) - IRQ_DEBOUNCE
+ */
+#define WM8993_JD2_SC_DB                        0x8000  /* JD2_SC_DB */
+#define WM8993_JD2_SC_DB_MASK                   0x8000  /* JD2_SC_DB */
+#define WM8993_JD2_SC_DB_SHIFT                      15  /* JD2_SC_DB */
+#define WM8993_JD2_SC_DB_WIDTH                       1  /* JD2_SC_DB */
+#define WM8993_JD2_DB                           0x4000  /* JD2_DB */
+#define WM8993_JD2_DB_MASK                      0x4000  /* JD2_DB */
+#define WM8993_JD2_DB_SHIFT                         14  /* JD2_DB */
+#define WM8993_JD2_DB_WIDTH                          1  /* JD2_DB */
+#define WM8993_WSEQ_DB                          0x2000  /* WSEQ_DB */
+#define WM8993_WSEQ_DB_MASK                     0x2000  /* WSEQ_DB */
+#define WM8993_WSEQ_DB_SHIFT                        13  /* WSEQ_DB */
+#define WM8993_WSEQ_DB_WIDTH                         1  /* WSEQ_DB */
+#define WM8993_TEMPOK_DB                        0x0800  /* TEMPOK_DB */
+#define WM8993_TEMPOK_DB_MASK                   0x0800  /* TEMPOK_DB */
+#define WM8993_TEMPOK_DB_SHIFT                      11  /* TEMPOK_DB */
+#define WM8993_TEMPOK_DB_WIDTH                       1  /* TEMPOK_DB */
+#define WM8993_JD1_SC_DB                        0x0400  /* JD1_SC_DB */
+#define WM8993_JD1_SC_DB_MASK                   0x0400  /* JD1_SC_DB */
+#define WM8993_JD1_SC_DB_SHIFT                      10  /* JD1_SC_DB */
+#define WM8993_JD1_SC_DB_WIDTH                       1  /* JD1_SC_DB */
+#define WM8993_JD1_DB                           0x0200  /* JD1_DB */
+#define WM8993_JD1_DB_MASK                      0x0200  /* JD1_DB */
+#define WM8993_JD1_DB_SHIFT                          9  /* JD1_DB */
+#define WM8993_JD1_DB_WIDTH                          1  /* JD1_DB */
+#define WM8993_FLL_LOCK_DB                      0x0100  /* FLL_LOCK_DB */
+#define WM8993_FLL_LOCK_DB_MASK                 0x0100  /* FLL_LOCK_DB */
+#define WM8993_FLL_LOCK_DB_SHIFT                     8  /* FLL_LOCK_DB */
+#define WM8993_FLL_LOCK_DB_WIDTH                     1  /* FLL_LOCK_DB */
+#define WM8993_GPI8_DB                          0x0080  /* GPI8_DB */
+#define WM8993_GPI8_DB_MASK                     0x0080  /* GPI8_DB */
+#define WM8993_GPI8_DB_SHIFT                         7  /* GPI8_DB */
+#define WM8993_GPI8_DB_WIDTH                         1  /* GPI8_DB */
+#define WM8993_GPI7_DB                          0x0008  /* GPI7_DB */
+#define WM8993_GPI7_DB_MASK                     0x0008  /* GPI7_DB */
+#define WM8993_GPI7_DB_SHIFT                         3  /* GPI7_DB */
+#define WM8993_GPI7_DB_WIDTH                         1  /* GPI7_DB */
+#define WM8993_GPIO1_DB                         0x0001  /* GPIO1_DB */
+#define WM8993_GPIO1_DB_MASK                    0x0001  /* GPIO1_DB */
+#define WM8993_GPIO1_DB_SHIFT                        0  /* GPIO1_DB */
+#define WM8993_GPIO1_DB_WIDTH                        1  /* GPIO1_DB */
+
+/*
+ * R21 (0x15) - Inputs Clamp
+ */
+#define WM8993_INPUTS_CLAMP                     0x0040  /* INPUTS_CLAMP */
+#define WM8993_INPUTS_CLAMP_MASK                0x0040  /* INPUTS_CLAMP */
+#define WM8993_INPUTS_CLAMP_SHIFT                    7  /* INPUTS_CLAMP */
+#define WM8993_INPUTS_CLAMP_WIDTH                    1  /* INPUTS_CLAMP */
+
+/*
+ * R22 (0x16) - GPIOCTRL 2
+ */
+#define WM8993_IM_JD2_EINT                      0x2000  /* IM_JD2_EINT */
+#define WM8993_IM_JD2_EINT_MASK                 0x2000  /* IM_JD2_EINT */
+#define WM8993_IM_JD2_EINT_SHIFT                    13  /* IM_JD2_EINT */
+#define WM8993_IM_JD2_EINT_WIDTH                     1  /* IM_JD2_EINT */
+#define WM8993_IM_JD2_SC_EINT                   0x1000  /* IM_JD2_SC_EINT */
+#define WM8993_IM_JD2_SC_EINT_MASK              0x1000  /* IM_JD2_SC_EINT */
+#define WM8993_IM_JD2_SC_EINT_SHIFT                 12  /* IM_JD2_SC_EINT */
+#define WM8993_IM_JD2_SC_EINT_WIDTH                  1  /* IM_JD2_SC_EINT */
+#define WM8993_IM_TEMPOK_EINT                   0x0800  /* IM_TEMPOK_EINT */
+#define WM8993_IM_TEMPOK_EINT_MASK              0x0800  /* IM_TEMPOK_EINT */
+#define WM8993_IM_TEMPOK_EINT_SHIFT                 11  /* IM_TEMPOK_EINT */
+#define WM8993_IM_TEMPOK_EINT_WIDTH                  1  /* IM_TEMPOK_EINT */
+#define WM8993_IM_JD1_SC_EINT                   0x0400  /* IM_JD1_SC_EINT */
+#define WM8993_IM_JD1_SC_EINT_MASK              0x0400  /* IM_JD1_SC_EINT */
+#define WM8993_IM_JD1_SC_EINT_SHIFT                 10  /* IM_JD1_SC_EINT */
+#define WM8993_IM_JD1_SC_EINT_WIDTH                  1  /* IM_JD1_SC_EINT */
+#define WM8993_IM_JD1_EINT                      0x0200  /* IM_JD1_EINT */
+#define WM8993_IM_JD1_EINT_MASK                 0x0200  /* IM_JD1_EINT */
+#define WM8993_IM_JD1_EINT_SHIFT                     9  /* IM_JD1_EINT */
+#define WM8993_IM_JD1_EINT_WIDTH                     1  /* IM_JD1_EINT */
+#define WM8993_IM_FLL_LOCK_EINT                 0x0100  /* IM_FLL_LOCK_EINT */
+#define WM8993_IM_FLL_LOCK_EINT_MASK            0x0100  /* IM_FLL_LOCK_EINT */
+#define WM8993_IM_FLL_LOCK_EINT_SHIFT                8  /* IM_FLL_LOCK_EINT */
+#define WM8993_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM8993_IM_GPI8_EINT                     0x0040  /* IM_GPI8_EINT */
+#define WM8993_IM_GPI8_EINT_MASK                0x0040  /* IM_GPI8_EINT */
+#define WM8993_IM_GPI8_EINT_SHIFT                    6  /* IM_GPI8_EINT */
+#define WM8993_IM_GPI8_EINT_WIDTH                    1  /* IM_GPI8_EINT */
+#define WM8993_IM_GPIO1_EINT                    0x0020  /* IM_GPIO1_EINT */
+#define WM8993_IM_GPIO1_EINT_MASK               0x0020  /* IM_GPIO1_EINT */
+#define WM8993_IM_GPIO1_EINT_SHIFT                   5  /* IM_GPIO1_EINT */
+#define WM8993_IM_GPIO1_EINT_WIDTH                   1  /* IM_GPIO1_EINT */
+#define WM8993_GPI8_ENA                         0x0010  /* GPI8_ENA */
+#define WM8993_GPI8_ENA_MASK                    0x0010  /* GPI8_ENA */
+#define WM8993_GPI8_ENA_SHIFT                        4  /* GPI8_ENA */
+#define WM8993_GPI8_ENA_WIDTH                        1  /* GPI8_ENA */
+#define WM8993_IM_GPI7_EINT                     0x0004  /* IM_GPI7_EINT */
+#define WM8993_IM_GPI7_EINT_MASK                0x0004  /* IM_GPI7_EINT */
+#define WM8993_IM_GPI7_EINT_SHIFT                    2  /* IM_GPI7_EINT */
+#define WM8993_IM_GPI7_EINT_WIDTH                    1  /* IM_GPI7_EINT */
+#define WM8993_IM_WSEQ_EINT                     0x0002  /* IM_WSEQ_EINT */
+#define WM8993_IM_WSEQ_EINT_MASK                0x0002  /* IM_WSEQ_EINT */
+#define WM8993_IM_WSEQ_EINT_SHIFT                    1  /* IM_WSEQ_EINT */
+#define WM8993_IM_WSEQ_EINT_WIDTH                    1  /* IM_WSEQ_EINT */
+#define WM8993_GPI7_ENA                         0x0001  /* GPI7_ENA */
+#define WM8993_GPI7_ENA_MASK                    0x0001  /* GPI7_ENA */
+#define WM8993_GPI7_ENA_SHIFT                        0  /* GPI7_ENA */
+#define WM8993_GPI7_ENA_WIDTH                        1  /* GPI7_ENA */
+
+/*
+ * R23 (0x17) - GPIO_POL
+ */
+#define WM8993_JD2_SC_POL                       0x8000  /* JD2_SC_POL */
+#define WM8993_JD2_SC_POL_MASK                  0x8000  /* JD2_SC_POL */
+#define WM8993_JD2_SC_POL_SHIFT                     15  /* JD2_SC_POL */
+#define WM8993_JD2_SC_POL_WIDTH                      1  /* JD2_SC_POL */
+#define WM8993_JD2_POL                          0x4000  /* JD2_POL */
+#define WM8993_JD2_POL_MASK                     0x4000  /* JD2_POL */
+#define WM8993_JD2_POL_SHIFT                        14  /* JD2_POL */
+#define WM8993_JD2_POL_WIDTH                         1  /* JD2_POL */
+#define WM8993_WSEQ_POL                         0x2000  /* WSEQ_POL */
+#define WM8993_WSEQ_POL_MASK                    0x2000  /* WSEQ_POL */
+#define WM8993_WSEQ_POL_SHIFT                       13  /* WSEQ_POL */
+#define WM8993_WSEQ_POL_WIDTH                        1  /* WSEQ_POL */
+#define WM8993_IRQ_POL                          0x1000  /* IRQ_POL */
+#define WM8993_IRQ_POL_MASK                     0x1000  /* IRQ_POL */
+#define WM8993_IRQ_POL_SHIFT                        12  /* IRQ_POL */
+#define WM8993_IRQ_POL_WIDTH                         1  /* IRQ_POL */
+#define WM8993_TEMPOK_POL                       0x0800  /* TEMPOK_POL */
+#define WM8993_TEMPOK_POL_MASK                  0x0800  /* TEMPOK_POL */
+#define WM8993_TEMPOK_POL_SHIFT                     11  /* TEMPOK_POL */
+#define WM8993_TEMPOK_POL_WIDTH                      1  /* TEMPOK_POL */
+#define WM8993_JD1_SC_POL                       0x0400  /* JD1_SC_POL */
+#define WM8993_JD1_SC_POL_MASK                  0x0400  /* JD1_SC_POL */
+#define WM8993_JD1_SC_POL_SHIFT                     10  /* JD1_SC_POL */
+#define WM8993_JD1_SC_POL_WIDTH                      1  /* JD1_SC_POL */
+#define WM8993_JD1_POL                          0x0200  /* JD1_POL */
+#define WM8993_JD1_POL_MASK                     0x0200  /* JD1_POL */
+#define WM8993_JD1_POL_SHIFT                         9  /* JD1_POL */
+#define WM8993_JD1_POL_WIDTH                         1  /* JD1_POL */
+#define WM8993_FLL_LOCK_POL                     0x0100  /* FLL_LOCK_POL */
+#define WM8993_FLL_LOCK_POL_MASK                0x0100  /* FLL_LOCK_POL */
+#define WM8993_FLL_LOCK_POL_SHIFT                    8  /* FLL_LOCK_POL */
+#define WM8993_FLL_LOCK_POL_WIDTH                    1  /* FLL_LOCK_POL */
+#define WM8993_GPI8_POL                         0x0080  /* GPI8_POL */
+#define WM8993_GPI8_POL_MASK                    0x0080  /* GPI8_POL */
+#define WM8993_GPI8_POL_SHIFT                        7  /* GPI8_POL */
+#define WM8993_GPI8_POL_WIDTH                        1  /* GPI8_POL */
+#define WM8993_GPI7_POL                         0x0040  /* GPI7_POL */
+#define WM8993_GPI7_POL_MASK                    0x0040  /* GPI7_POL */
+#define WM8993_GPI7_POL_SHIFT                        6  /* GPI7_POL */
+#define WM8993_GPI7_POL_WIDTH                        1  /* GPI7_POL */
+#define WM8993_GPIO1_POL                        0x0001  /* GPIO1_POL */
+#define WM8993_GPIO1_POL_MASK                   0x0001  /* GPIO1_POL */
+#define WM8993_GPIO1_POL_SHIFT                       0  /* GPIO1_POL */
+#define WM8993_GPIO1_POL_WIDTH                       1  /* GPIO1_POL */
+
+/*
+ * R24 (0x18) - Left Line Input 1&2 Volume
+ */
+#define WM8993_IN1_VU                           0x0100  /* IN1_VU */
+#define WM8993_IN1_VU_MASK                      0x0100  /* IN1_VU */
+#define WM8993_IN1_VU_SHIFT                          8  /* IN1_VU */
+#define WM8993_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM8993_IN1L_MUTE                        0x0080  /* IN1L_MUTE */
+#define WM8993_IN1L_MUTE_MASK                   0x0080  /* IN1L_MUTE */
+#define WM8993_IN1L_MUTE_SHIFT                       7  /* IN1L_MUTE */
+#define WM8993_IN1L_MUTE_WIDTH                       1  /* IN1L_MUTE */
+#define WM8993_IN1L_ZC                          0x0040  /* IN1L_ZC */
+#define WM8993_IN1L_ZC_MASK                     0x0040  /* IN1L_ZC */
+#define WM8993_IN1L_ZC_SHIFT                         6  /* IN1L_ZC */
+#define WM8993_IN1L_ZC_WIDTH                         1  /* IN1L_ZC */
+#define WM8993_IN1L_VOL_MASK                    0x001F  /* IN1L_VOL - [4:0] */
+#define WM8993_IN1L_VOL_SHIFT                        0  /* IN1L_VOL - [4:0] */
+#define WM8993_IN1L_VOL_WIDTH                        5  /* IN1L_VOL - [4:0] */
+
+/*
+ * R25 (0x19) - Left Line Input 3&4 Volume
+ */
+#define WM8993_IN2_VU                           0x0100  /* IN2_VU */
+#define WM8993_IN2_VU_MASK                      0x0100  /* IN2_VU */
+#define WM8993_IN2_VU_SHIFT                          8  /* IN2_VU */
+#define WM8993_IN2_VU_WIDTH                          1  /* IN2_VU */
+#define WM8993_IN2L_MUTE                        0x0080  /* IN2L_MUTE */
+#define WM8993_IN2L_MUTE_MASK                   0x0080  /* IN2L_MUTE */
+#define WM8993_IN2L_MUTE_SHIFT                       7  /* IN2L_MUTE */
+#define WM8993_IN2L_MUTE_WIDTH                       1  /* IN2L_MUTE */
+#define WM8993_IN2L_ZC                          0x0040  /* IN2L_ZC */
+#define WM8993_IN2L_ZC_MASK                     0x0040  /* IN2L_ZC */
+#define WM8993_IN2L_ZC_SHIFT                         6  /* IN2L_ZC */
+#define WM8993_IN2L_ZC_WIDTH                         1  /* IN2L_ZC */
+#define WM8993_IN2L_VOL_MASK                    0x001F  /* IN2L_VOL - [4:0] */
+#define WM8993_IN2L_VOL_SHIFT                        0  /* IN2L_VOL - [4:0] */
+#define WM8993_IN2L_VOL_WIDTH                        5  /* IN2L_VOL - [4:0] */
+
+/*
+ * R26 (0x1A) - Right Line Input 1&2 Volume
+ */
+#define WM8993_IN1_VU                           0x0100  /* IN1_VU */
+#define WM8993_IN1_VU_MASK                      0x0100  /* IN1_VU */
+#define WM8993_IN1_VU_SHIFT                          8  /* IN1_VU */
+#define WM8993_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM8993_IN1R_MUTE                        0x0080  /* IN1R_MUTE */
+#define WM8993_IN1R_MUTE_MASK                   0x0080  /* IN1R_MUTE */
+#define WM8993_IN1R_MUTE_SHIFT                       7  /* IN1R_MUTE */
+#define WM8993_IN1R_MUTE_WIDTH                       1  /* IN1R_MUTE */
+#define WM8993_IN1R_ZC                          0x0040  /* IN1R_ZC */
+#define WM8993_IN1R_ZC_MASK                     0x0040  /* IN1R_ZC */
+#define WM8993_IN1R_ZC_SHIFT                         6  /* IN1R_ZC */
+#define WM8993_IN1R_ZC_WIDTH                         1  /* IN1R_ZC */
+#define WM8993_IN1R_VOL_MASK                    0x001F  /* IN1R_VOL - [4:0] */
+#define WM8993_IN1R_VOL_SHIFT                        0  /* IN1R_VOL - [4:0] */
+#define WM8993_IN1R_VOL_WIDTH                        5  /* IN1R_VOL - [4:0] */
+
+/*
+ * R27 (0x1B) - Right Line Input 3&4 Volume
+ */
+#define WM8993_IN2_VU                           0x0100  /* IN2_VU */
+#define WM8993_IN2_VU_MASK                      0x0100  /* IN2_VU */
+#define WM8993_IN2_VU_SHIFT                          8  /* IN2_VU */
+#define WM8993_IN2_VU_WIDTH                          1  /* IN2_VU */
+#define WM8993_IN2R_MUTE                        0x0080  /* IN2R_MUTE */
+#define WM8993_IN2R_MUTE_MASK                   0x0080  /* IN2R_MUTE */
+#define WM8993_IN2R_MUTE_SHIFT                       7  /* IN2R_MUTE */
+#define WM8993_IN2R_MUTE_WIDTH                       1  /* IN2R_MUTE */
+#define WM8993_IN2R_ZC                          0x0040  /* IN2R_ZC */
+#define WM8993_IN2R_ZC_MASK                     0x0040  /* IN2R_ZC */
+#define WM8993_IN2R_ZC_SHIFT                         6  /* IN2R_ZC */
+#define WM8993_IN2R_ZC_WIDTH                         1  /* IN2R_ZC */
+#define WM8993_IN2R_VOL_MASK                    0x001F  /* IN2R_VOL - [4:0] */
+#define WM8993_IN2R_VOL_SHIFT                        0  /* IN2R_VOL - [4:0] */
+#define WM8993_IN2R_VOL_WIDTH                        5  /* IN2R_VOL - [4:0] */
+
+/*
+ * R28 (0x1C) - Left Output Volume
+ */
+#define WM8993_HPOUT1_VU                        0x0100  /* HPOUT1_VU */
+#define WM8993_HPOUT1_VU_MASK                   0x0100  /* HPOUT1_VU */
+#define WM8993_HPOUT1_VU_SHIFT                       8  /* HPOUT1_VU */
+#define WM8993_HPOUT1_VU_WIDTH                       1  /* HPOUT1_VU */
+#define WM8993_HPOUT1L_ZC                       0x0080  /* HPOUT1L_ZC */
+#define WM8993_HPOUT1L_ZC_MASK                  0x0080  /* HPOUT1L_ZC */
+#define WM8993_HPOUT1L_ZC_SHIFT                      7  /* HPOUT1L_ZC */
+#define WM8993_HPOUT1L_ZC_WIDTH                      1  /* HPOUT1L_ZC */
+#define WM8993_HPOUT1L_MUTE_N                   0x0040  /* HPOUT1L_MUTE_N */
+#define WM8993_HPOUT1L_MUTE_N_MASK              0x0040  /* HPOUT1L_MUTE_N */
+#define WM8993_HPOUT1L_MUTE_N_SHIFT                  6  /* HPOUT1L_MUTE_N */
+#define WM8993_HPOUT1L_MUTE_N_WIDTH                  1  /* HPOUT1L_MUTE_N */
+#define WM8993_HPOUT1L_VOL_MASK                 0x003F  /* HPOUT1L_VOL - [5:0] */
+#define WM8993_HPOUT1L_VOL_SHIFT                     0  /* HPOUT1L_VOL - [5:0] */
+#define WM8993_HPOUT1L_VOL_WIDTH                     6  /* HPOUT1L_VOL - [5:0] */
+
+/*
+ * R29 (0x1D) - Right Output Volume
+ */
+#define WM8993_HPOUT1_VU                        0x0100  /* HPOUT1_VU */
+#define WM8993_HPOUT1_VU_MASK                   0x0100  /* HPOUT1_VU */
+#define WM8993_HPOUT1_VU_SHIFT                       8  /* HPOUT1_VU */
+#define WM8993_HPOUT1_VU_WIDTH                       1  /* HPOUT1_VU */
+#define WM8993_HPOUT1R_ZC                       0x0080  /* HPOUT1R_ZC */
+#define WM8993_HPOUT1R_ZC_MASK                  0x0080  /* HPOUT1R_ZC */
+#define WM8993_HPOUT1R_ZC_SHIFT                      7  /* HPOUT1R_ZC */
+#define WM8993_HPOUT1R_ZC_WIDTH                      1  /* HPOUT1R_ZC */
+#define WM8993_HPOUT1R_MUTE_N                   0x0040  /* HPOUT1R_MUTE_N */
+#define WM8993_HPOUT1R_MUTE_N_MASK              0x0040  /* HPOUT1R_MUTE_N */
+#define WM8993_HPOUT1R_MUTE_N_SHIFT                  6  /* HPOUT1R_MUTE_N */
+#define WM8993_HPOUT1R_MUTE_N_WIDTH                  1  /* HPOUT1R_MUTE_N */
+#define WM8993_HPOUT1R_VOL_MASK                 0x003F  /* HPOUT1R_VOL - [5:0] */
+#define WM8993_HPOUT1R_VOL_SHIFT                     0  /* HPOUT1R_VOL - [5:0] */
+#define WM8993_HPOUT1R_VOL_WIDTH                     6  /* HPOUT1R_VOL - [5:0] */
+
+/*
+ * R30 (0x1E) - Line Outputs Volume
+ */
+#define WM8993_LINEOUT1N_MUTE                   0x0040  /* LINEOUT1N_MUTE */
+#define WM8993_LINEOUT1N_MUTE_MASK              0x0040  /* LINEOUT1N_MUTE */
+#define WM8993_LINEOUT1N_MUTE_SHIFT                  6  /* LINEOUT1N_MUTE */
+#define WM8993_LINEOUT1N_MUTE_WIDTH                  1  /* LINEOUT1N_MUTE */
+#define WM8993_LINEOUT1P_MUTE                   0x0020  /* LINEOUT1P_MUTE */
+#define WM8993_LINEOUT1P_MUTE_MASK              0x0020  /* LINEOUT1P_MUTE */
+#define WM8993_LINEOUT1P_MUTE_SHIFT                  5  /* LINEOUT1P_MUTE */
+#define WM8993_LINEOUT1P_MUTE_WIDTH                  1  /* LINEOUT1P_MUTE */
+#define WM8993_LINEOUT1_VOL                     0x0010  /* LINEOUT1_VOL */
+#define WM8993_LINEOUT1_VOL_MASK                0x0010  /* LINEOUT1_VOL */
+#define WM8993_LINEOUT1_VOL_SHIFT                    4  /* LINEOUT1_VOL */
+#define WM8993_LINEOUT1_VOL_WIDTH                    1  /* LINEOUT1_VOL */
+#define WM8993_LINEOUT2N_MUTE                   0x0004  /* LINEOUT2N_MUTE */
+#define WM8993_LINEOUT2N_MUTE_MASK              0x0004  /* LINEOUT2N_MUTE */
+#define WM8993_LINEOUT2N_MUTE_SHIFT                  2  /* LINEOUT2N_MUTE */
+#define WM8993_LINEOUT2N_MUTE_WIDTH                  1  /* LINEOUT2N_MUTE */
+#define WM8993_LINEOUT2P_MUTE                   0x0002  /* LINEOUT2P_MUTE */
+#define WM8993_LINEOUT2P_MUTE_MASK              0x0002  /* LINEOUT2P_MUTE */
+#define WM8993_LINEOUT2P_MUTE_SHIFT                  1  /* LINEOUT2P_MUTE */
+#define WM8993_LINEOUT2P_MUTE_WIDTH                  1  /* LINEOUT2P_MUTE */
+#define WM8993_LINEOUT2_VOL                     0x0001  /* LINEOUT2_VOL */
+#define WM8993_LINEOUT2_VOL_MASK                0x0001  /* LINEOUT2_VOL */
+#define WM8993_LINEOUT2_VOL_SHIFT                    0  /* LINEOUT2_VOL */
+#define WM8993_LINEOUT2_VOL_WIDTH                    1  /* LINEOUT2_VOL */
+
+/*
+ * R31 (0x1F) - HPOUT2 Volume
+ */
+#define WM8993_HPOUT2_MUTE                      0x0020  /* HPOUT2_MUTE */
+#define WM8993_HPOUT2_MUTE_MASK                 0x0020  /* HPOUT2_MUTE */
+#define WM8993_HPOUT2_MUTE_SHIFT                     5  /* HPOUT2_MUTE */
+#define WM8993_HPOUT2_MUTE_WIDTH                     1  /* HPOUT2_MUTE */
+#define WM8993_HPOUT2_VOL                       0x0010  /* HPOUT2_VOL */
+#define WM8993_HPOUT2_VOL_MASK                  0x0010  /* HPOUT2_VOL */
+#define WM8993_HPOUT2_VOL_SHIFT                      4  /* HPOUT2_VOL */
+#define WM8993_HPOUT2_VOL_WIDTH                      1  /* HPOUT2_VOL */
+
+/*
+ * R32 (0x20) - Left OPGA Volume
+ */
+#define WM8993_MIXOUT_VU                        0x0100  /* MIXOUT_VU */
+#define WM8993_MIXOUT_VU_MASK                   0x0100  /* MIXOUT_VU */
+#define WM8993_MIXOUT_VU_SHIFT                       8  /* MIXOUT_VU */
+#define WM8993_MIXOUT_VU_WIDTH                       1  /* MIXOUT_VU */
+#define WM8993_MIXOUTL_ZC                       0x0080  /* MIXOUTL_ZC */
+#define WM8993_MIXOUTL_ZC_MASK                  0x0080  /* MIXOUTL_ZC */
+#define WM8993_MIXOUTL_ZC_SHIFT                      7  /* MIXOUTL_ZC */
+#define WM8993_MIXOUTL_ZC_WIDTH                      1  /* MIXOUTL_ZC */
+#define WM8993_MIXOUTL_MUTE_N                   0x0040  /* MIXOUTL_MUTE_N */
+#define WM8993_MIXOUTL_MUTE_N_MASK              0x0040  /* MIXOUTL_MUTE_N */
+#define WM8993_MIXOUTL_MUTE_N_SHIFT                  6  /* MIXOUTL_MUTE_N */
+#define WM8993_MIXOUTL_MUTE_N_WIDTH                  1  /* MIXOUTL_MUTE_N */
+#define WM8993_MIXOUTL_VOL_MASK                 0x003F  /* MIXOUTL_VOL - [5:0] */
+#define WM8993_MIXOUTL_VOL_SHIFT                     0  /* MIXOUTL_VOL - [5:0] */
+#define WM8993_MIXOUTL_VOL_WIDTH                     6  /* MIXOUTL_VOL - [5:0] */
+
+/*
+ * R33 (0x21) - Right OPGA Volume
+ */
+#define WM8993_MIXOUT_VU                        0x0100  /* MIXOUT_VU */
+#define WM8993_MIXOUT_VU_MASK                   0x0100  /* MIXOUT_VU */
+#define WM8993_MIXOUT_VU_SHIFT                       8  /* MIXOUT_VU */
+#define WM8993_MIXOUT_VU_WIDTH                       1  /* MIXOUT_VU */
+#define WM8993_MIXOUTR_ZC                       0x0080  /* MIXOUTR_ZC */
+#define WM8993_MIXOUTR_ZC_MASK                  0x0080  /* MIXOUTR_ZC */
+#define WM8993_MIXOUTR_ZC_SHIFT                      7  /* MIXOUTR_ZC */
+#define WM8993_MIXOUTR_ZC_WIDTH                      1  /* MIXOUTR_ZC */
+#define WM8993_MIXOUTR_MUTE_N                   0x0040  /* MIXOUTR_MUTE_N */
+#define WM8993_MIXOUTR_MUTE_N_MASK              0x0040  /* MIXOUTR_MUTE_N */
+#define WM8993_MIXOUTR_MUTE_N_SHIFT                  6  /* MIXOUTR_MUTE_N */
+#define WM8993_MIXOUTR_MUTE_N_WIDTH                  1  /* MIXOUTR_MUTE_N */
+#define WM8993_MIXOUTR_VOL_MASK                 0x003F  /* MIXOUTR_VOL - [5:0] */
+#define WM8993_MIXOUTR_VOL_SHIFT                     0  /* MIXOUTR_VOL - [5:0] */
+#define WM8993_MIXOUTR_VOL_WIDTH                     6  /* MIXOUTR_VOL - [5:0] */
+
+/*
+ * R34 (0x22) - SPKMIXL Attenuation
+ */
+#define WM8993_MIXINL_SPKMIXL_VOL               0x0020  /* MIXINL_SPKMIXL_VOL */
+#define WM8993_MIXINL_SPKMIXL_VOL_MASK          0x0020  /* MIXINL_SPKMIXL_VOL */
+#define WM8993_MIXINL_SPKMIXL_VOL_SHIFT              5  /* MIXINL_SPKMIXL_VOL */
+#define WM8993_MIXINL_SPKMIXL_VOL_WIDTH              1  /* MIXINL_SPKMIXL_VOL */
+#define WM8993_IN1LP_SPKMIXL_VOL                0x0010  /* IN1LP_SPKMIXL_VOL */
+#define WM8993_IN1LP_SPKMIXL_VOL_MASK           0x0010  /* IN1LP_SPKMIXL_VOL */
+#define WM8993_IN1LP_SPKMIXL_VOL_SHIFT               4  /* IN1LP_SPKMIXL_VOL */
+#define WM8993_IN1LP_SPKMIXL_VOL_WIDTH               1  /* IN1LP_SPKMIXL_VOL */
+#define WM8993_MIXOUTL_SPKMIXL_VOL              0x0008  /* MIXOUTL_SPKMIXL_VOL */
+#define WM8993_MIXOUTL_SPKMIXL_VOL_MASK         0x0008  /* MIXOUTL_SPKMIXL_VOL */
+#define WM8993_MIXOUTL_SPKMIXL_VOL_SHIFT             3  /* MIXOUTL_SPKMIXL_VOL */
+#define WM8993_MIXOUTL_SPKMIXL_VOL_WIDTH             1  /* MIXOUTL_SPKMIXL_VOL */
+#define WM8993_DACL_SPKMIXL_VOL                 0x0004  /* DACL_SPKMIXL_VOL */
+#define WM8993_DACL_SPKMIXL_VOL_MASK            0x0004  /* DACL_SPKMIXL_VOL */
+#define WM8993_DACL_SPKMIXL_VOL_SHIFT                2  /* DACL_SPKMIXL_VOL */
+#define WM8993_DACL_SPKMIXL_VOL_WIDTH                1  /* DACL_SPKMIXL_VOL */
+#define WM8993_SPKMIXL_VOL_MASK                 0x0003  /* SPKMIXL_VOL - [1:0] */
+#define WM8993_SPKMIXL_VOL_SHIFT                     0  /* SPKMIXL_VOL - [1:0] */
+#define WM8993_SPKMIXL_VOL_WIDTH                     2  /* SPKMIXL_VOL - [1:0] */
+
+/*
+ * R35 (0x23) - SPKMIXR Attenuation
+ */
+#define WM8993_SPKOUT_CLASSAB_MODE              0x0100  /* SPKOUT_CLASSAB_MODE */
+#define WM8993_SPKOUT_CLASSAB_MODE_MASK         0x0100  /* SPKOUT_CLASSAB_MODE */
+#define WM8993_SPKOUT_CLASSAB_MODE_SHIFT             8  /* SPKOUT_CLASSAB_MODE */
+#define WM8993_SPKOUT_CLASSAB_MODE_WIDTH             1  /* SPKOUT_CLASSAB_MODE */
+#define WM8993_MIXINR_SPKMIXR_VOL               0x0020  /* MIXINR_SPKMIXR_VOL */
+#define WM8993_MIXINR_SPKMIXR_VOL_MASK          0x0020  /* MIXINR_SPKMIXR_VOL */
+#define WM8993_MIXINR_SPKMIXR_VOL_SHIFT              5  /* MIXINR_SPKMIXR_VOL */
+#define WM8993_MIXINR_SPKMIXR_VOL_WIDTH              1  /* MIXINR_SPKMIXR_VOL */
+#define WM8993_IN1RP_SPKMIXR_VOL                0x0010  /* IN1RP_SPKMIXR_VOL */
+#define WM8993_IN1RP_SPKMIXR_VOL_MASK           0x0010  /* IN1RP_SPKMIXR_VOL */
+#define WM8993_IN1RP_SPKMIXR_VOL_SHIFT               4  /* IN1RP_SPKMIXR_VOL */
+#define WM8993_IN1RP_SPKMIXR_VOL_WIDTH               1  /* IN1RP_SPKMIXR_VOL */
+#define WM8993_MIXOUTR_SPKMIXR_VOL              0x0008  /* MIXOUTR_SPKMIXR_VOL */
+#define WM8993_MIXOUTR_SPKMIXR_VOL_MASK         0x0008  /* MIXOUTR_SPKMIXR_VOL */
+#define WM8993_MIXOUTR_SPKMIXR_VOL_SHIFT             3  /* MIXOUTR_SPKMIXR_VOL */
+#define WM8993_MIXOUTR_SPKMIXR_VOL_WIDTH             1  /* MIXOUTR_SPKMIXR_VOL */
+#define WM8993_DACR_SPKMIXR_VOL                 0x0004  /* DACR_SPKMIXR_VOL */
+#define WM8993_DACR_SPKMIXR_VOL_MASK            0x0004  /* DACR_SPKMIXR_VOL */
+#define WM8993_DACR_SPKMIXR_VOL_SHIFT                2  /* DACR_SPKMIXR_VOL */
+#define WM8993_DACR_SPKMIXR_VOL_WIDTH                1  /* DACR_SPKMIXR_VOL */
+#define WM8993_SPKMIXR_VOL_MASK                 0x0003  /* SPKMIXR_VOL - [1:0] */
+#define WM8993_SPKMIXR_VOL_SHIFT                     0  /* SPKMIXR_VOL - [1:0] */
+#define WM8993_SPKMIXR_VOL_WIDTH                     2  /* SPKMIXR_VOL - [1:0] */
+
+/*
+ * R36 (0x24) - SPKOUT Mixers
+ */
+#define WM8993_VRX_TO_SPKOUTL                   0x0020  /* VRX_TO_SPKOUTL */
+#define WM8993_VRX_TO_SPKOUTL_MASK              0x0020  /* VRX_TO_SPKOUTL */
+#define WM8993_VRX_TO_SPKOUTL_SHIFT                  5  /* VRX_TO_SPKOUTL */
+#define WM8993_VRX_TO_SPKOUTL_WIDTH                  1  /* VRX_TO_SPKOUTL */
+#define WM8993_SPKMIXL_TO_SPKOUTL               0x0010  /* SPKMIXL_TO_SPKOUTL */
+#define WM8993_SPKMIXL_TO_SPKOUTL_MASK          0x0010  /* SPKMIXL_TO_SPKOUTL */
+#define WM8993_SPKMIXL_TO_SPKOUTL_SHIFT              4  /* SPKMIXL_TO_SPKOUTL */
+#define WM8993_SPKMIXL_TO_SPKOUTL_WIDTH              1  /* SPKMIXL_TO_SPKOUTL */
+#define WM8993_SPKMIXR_TO_SPKOUTL               0x0008  /* SPKMIXR_TO_SPKOUTL */
+#define WM8993_SPKMIXR_TO_SPKOUTL_MASK          0x0008  /* SPKMIXR_TO_SPKOUTL */
+#define WM8993_SPKMIXR_TO_SPKOUTL_SHIFT              3  /* SPKMIXR_TO_SPKOUTL */
+#define WM8993_SPKMIXR_TO_SPKOUTL_WIDTH              1  /* SPKMIXR_TO_SPKOUTL */
+#define WM8993_VRX_TO_SPKOUTR                   0x0004  /* VRX_TO_SPKOUTR */
+#define WM8993_VRX_TO_SPKOUTR_MASK              0x0004  /* VRX_TO_SPKOUTR */
+#define WM8993_VRX_TO_SPKOUTR_SHIFT                  2  /* VRX_TO_SPKOUTR */
+#define WM8993_VRX_TO_SPKOUTR_WIDTH                  1  /* VRX_TO_SPKOUTR */
+#define WM8993_SPKMIXL_TO_SPKOUTR               0x0002  /* SPKMIXL_TO_SPKOUTR */
+#define WM8993_SPKMIXL_TO_SPKOUTR_MASK          0x0002  /* SPKMIXL_TO_SPKOUTR */
+#define WM8993_SPKMIXL_TO_SPKOUTR_SHIFT              1  /* SPKMIXL_TO_SPKOUTR */
+#define WM8993_SPKMIXL_TO_SPKOUTR_WIDTH              1  /* SPKMIXL_TO_SPKOUTR */
+#define WM8993_SPKMIXR_TO_SPKOUTR               0x0001  /* SPKMIXR_TO_SPKOUTR */
+#define WM8993_SPKMIXR_TO_SPKOUTR_MASK          0x0001  /* SPKMIXR_TO_SPKOUTR */
+#define WM8993_SPKMIXR_TO_SPKOUTR_SHIFT              0  /* SPKMIXR_TO_SPKOUTR */
+#define WM8993_SPKMIXR_TO_SPKOUTR_WIDTH              1  /* SPKMIXR_TO_SPKOUTR */
+
+/*
+ * R37 (0x25) - SPKOUT Boost
+ */
+#define WM8993_SPKOUTL_BOOST_MASK               0x0038  /* SPKOUTL_BOOST - [5:3] */
+#define WM8993_SPKOUTL_BOOST_SHIFT                   3  /* SPKOUTL_BOOST - [5:3] */
+#define WM8993_SPKOUTL_BOOST_WIDTH                   3  /* SPKOUTL_BOOST - [5:3] */
+#define WM8993_SPKOUTR_BOOST_MASK               0x0007  /* SPKOUTR_BOOST - [2:0] */
+#define WM8993_SPKOUTR_BOOST_SHIFT                   0  /* SPKOUTR_BOOST - [2:0] */
+#define WM8993_SPKOUTR_BOOST_WIDTH                   3  /* SPKOUTR_BOOST - [2:0] */
+
+/*
+ * R38 (0x26) - Speaker Volume Left
+ */
+#define WM8993_SPKOUT_VU                        0x0100  /* SPKOUT_VU */
+#define WM8993_SPKOUT_VU_MASK                   0x0100  /* SPKOUT_VU */
+#define WM8993_SPKOUT_VU_SHIFT                       8  /* SPKOUT_VU */
+#define WM8993_SPKOUT_VU_WIDTH                       1  /* SPKOUT_VU */
+#define WM8993_SPKOUTL_ZC                       0x0080  /* SPKOUTL_ZC */
+#define WM8993_SPKOUTL_ZC_MASK                  0x0080  /* SPKOUTL_ZC */
+#define WM8993_SPKOUTL_ZC_SHIFT                      7  /* SPKOUTL_ZC */
+#define WM8993_SPKOUTL_ZC_WIDTH                      1  /* SPKOUTL_ZC */
+#define WM8993_SPKOUTL_MUTE_N                   0x0040  /* SPKOUTL_MUTE_N */
+#define WM8993_SPKOUTL_MUTE_N_MASK              0x0040  /* SPKOUTL_MUTE_N */
+#define WM8993_SPKOUTL_MUTE_N_SHIFT                  6  /* SPKOUTL_MUTE_N */
+#define WM8993_SPKOUTL_MUTE_N_WIDTH                  1  /* SPKOUTL_MUTE_N */
+#define WM8993_SPKOUTL_VOL_MASK                 0x003F  /* SPKOUTL_VOL - [5:0] */
+#define WM8993_SPKOUTL_VOL_SHIFT                     0  /* SPKOUTL_VOL - [5:0] */
+#define WM8993_SPKOUTL_VOL_WIDTH                     6  /* SPKOUTL_VOL - [5:0] */
+
+/*
+ * R39 (0x27) - Speaker Volume Right
+ */
+#define WM8993_SPKOUT_VU                        0x0100  /* SPKOUT_VU */
+#define WM8993_SPKOUT_VU_MASK                   0x0100  /* SPKOUT_VU */
+#define WM8993_SPKOUT_VU_SHIFT                       8  /* SPKOUT_VU */
+#define WM8993_SPKOUT_VU_WIDTH                       1  /* SPKOUT_VU */
+#define WM8993_SPKOUTR_ZC                       0x0080  /* SPKOUTR_ZC */
+#define WM8993_SPKOUTR_ZC_MASK                  0x0080  /* SPKOUTR_ZC */
+#define WM8993_SPKOUTR_ZC_SHIFT                      7  /* SPKOUTR_ZC */
+#define WM8993_SPKOUTR_ZC_WIDTH                      1  /* SPKOUTR_ZC */
+#define WM8993_SPKOUTR_MUTE_N                   0x0040  /* SPKOUTR_MUTE_N */
+#define WM8993_SPKOUTR_MUTE_N_MASK              0x0040  /* SPKOUTR_MUTE_N */
+#define WM8993_SPKOUTR_MUTE_N_SHIFT                  6  /* SPKOUTR_MUTE_N */
+#define WM8993_SPKOUTR_MUTE_N_WIDTH                  1  /* SPKOUTR_MUTE_N */
+#define WM8993_SPKOUTR_VOL_MASK                 0x003F  /* SPKOUTR_VOL - [5:0] */
+#define WM8993_SPKOUTR_VOL_SHIFT                     0  /* SPKOUTR_VOL - [5:0] */
+#define WM8993_SPKOUTR_VOL_WIDTH                     6  /* SPKOUTR_VOL - [5:0] */
+
+/*
+ * R40 (0x28) - Input Mixer2
+ */
+#define WM8993_IN2LP_TO_IN2L                    0x0080  /* IN2LP_TO_IN2L */
+#define WM8993_IN2LP_TO_IN2L_MASK               0x0080  /* IN2LP_TO_IN2L */
+#define WM8993_IN2LP_TO_IN2L_SHIFT                   7  /* IN2LP_TO_IN2L */
+#define WM8993_IN2LP_TO_IN2L_WIDTH                   1  /* IN2LP_TO_IN2L */
+#define WM8993_IN2LN_TO_IN2L                    0x0040  /* IN2LN_TO_IN2L */
+#define WM8993_IN2LN_TO_IN2L_MASK               0x0040  /* IN2LN_TO_IN2L */
+#define WM8993_IN2LN_TO_IN2L_SHIFT                   6  /* IN2LN_TO_IN2L */
+#define WM8993_IN2LN_TO_IN2L_WIDTH                   1  /* IN2LN_TO_IN2L */
+#define WM8993_IN1LP_TO_IN1L                    0x0020  /* IN1LP_TO_IN1L */
+#define WM8993_IN1LP_TO_IN1L_MASK               0x0020  /* IN1LP_TO_IN1L */
+#define WM8993_IN1LP_TO_IN1L_SHIFT                   5  /* IN1LP_TO_IN1L */
+#define WM8993_IN1LP_TO_IN1L_WIDTH                   1  /* IN1LP_TO_IN1L */
+#define WM8993_IN1LN_TO_IN1L                    0x0010  /* IN1LN_TO_IN1L */
+#define WM8993_IN1LN_TO_IN1L_MASK               0x0010  /* IN1LN_TO_IN1L */
+#define WM8993_IN1LN_TO_IN1L_SHIFT                   4  /* IN1LN_TO_IN1L */
+#define WM8993_IN1LN_TO_IN1L_WIDTH                   1  /* IN1LN_TO_IN1L */
+#define WM8993_IN2RP_TO_IN2R                    0x0008  /* IN2RP_TO_IN2R */
+#define WM8993_IN2RP_TO_IN2R_MASK               0x0008  /* IN2RP_TO_IN2R */
+#define WM8993_IN2RP_TO_IN2R_SHIFT                   3  /* IN2RP_TO_IN2R */
+#define WM8993_IN2RP_TO_IN2R_WIDTH                   1  /* IN2RP_TO_IN2R */
+#define WM8993_IN2RN_TO_IN2R                    0x0004  /* IN2RN_TO_IN2R */
+#define WM8993_IN2RN_TO_IN2R_MASK               0x0004  /* IN2RN_TO_IN2R */
+#define WM8993_IN2RN_TO_IN2R_SHIFT                   2  /* IN2RN_TO_IN2R */
+#define WM8993_IN2RN_TO_IN2R_WIDTH                   1  /* IN2RN_TO_IN2R */
+#define WM8993_IN1RP_TO_IN1R                    0x0002  /* IN1RP_TO_IN1R */
+#define WM8993_IN1RP_TO_IN1R_MASK               0x0002  /* IN1RP_TO_IN1R */
+#define WM8993_IN1RP_TO_IN1R_SHIFT                   1  /* IN1RP_TO_IN1R */
+#define WM8993_IN1RP_TO_IN1R_WIDTH                   1  /* IN1RP_TO_IN1R */
+#define WM8993_IN1RN_TO_IN1R                    0x0001  /* IN1RN_TO_IN1R */
+#define WM8993_IN1RN_TO_IN1R_MASK               0x0001  /* IN1RN_TO_IN1R */
+#define WM8993_IN1RN_TO_IN1R_SHIFT                   0  /* IN1RN_TO_IN1R */
+#define WM8993_IN1RN_TO_IN1R_WIDTH                   1  /* IN1RN_TO_IN1R */
+
+/*
+ * R41 (0x29) - Input Mixer3
+ */
+#define WM8993_IN2L_TO_MIXINL                   0x0100  /* IN2L_TO_MIXINL */
+#define WM8993_IN2L_TO_MIXINL_MASK              0x0100  /* IN2L_TO_MIXINL */
+#define WM8993_IN2L_TO_MIXINL_SHIFT                  8  /* IN2L_TO_MIXINL */
+#define WM8993_IN2L_TO_MIXINL_WIDTH                  1  /* IN2L_TO_MIXINL */
+#define WM8993_IN2L_MIXINL_VOL                  0x0080  /* IN2L_MIXINL_VOL */
+#define WM8993_IN2L_MIXINL_VOL_MASK             0x0080  /* IN2L_MIXINL_VOL */
+#define WM8993_IN2L_MIXINL_VOL_SHIFT                 7  /* IN2L_MIXINL_VOL */
+#define WM8993_IN2L_MIXINL_VOL_WIDTH                 1  /* IN2L_MIXINL_VOL */
+#define WM8993_IN1L_TO_MIXINL                   0x0020  /* IN1L_TO_MIXINL */
+#define WM8993_IN1L_TO_MIXINL_MASK              0x0020  /* IN1L_TO_MIXINL */
+#define WM8993_IN1L_TO_MIXINL_SHIFT                  5  /* IN1L_TO_MIXINL */
+#define WM8993_IN1L_TO_MIXINL_WIDTH                  1  /* IN1L_TO_MIXINL */
+#define WM8993_IN1L_MIXINL_VOL                  0x0010  /* IN1L_MIXINL_VOL */
+#define WM8993_IN1L_MIXINL_VOL_MASK             0x0010  /* IN1L_MIXINL_VOL */
+#define WM8993_IN1L_MIXINL_VOL_SHIFT                 4  /* IN1L_MIXINL_VOL */
+#define WM8993_IN1L_MIXINL_VOL_WIDTH                 1  /* IN1L_MIXINL_VOL */
+#define WM8993_MIXOUTL_MIXINL_VOL_MASK          0x0007  /* MIXOUTL_MIXINL_VOL - [2:0] */
+#define WM8993_MIXOUTL_MIXINL_VOL_SHIFT              0  /* MIXOUTL_MIXINL_VOL - [2:0] */
+#define WM8993_MIXOUTL_MIXINL_VOL_WIDTH              3  /* MIXOUTL_MIXINL_VOL - [2:0] */
+
+/*
+ * R42 (0x2A) - Input Mixer4
+ */
+#define WM8993_IN2R_TO_MIXINR                   0x0100  /* IN2R_TO_MIXINR */
+#define WM8993_IN2R_TO_MIXINR_MASK              0x0100  /* IN2R_TO_MIXINR */
+#define WM8993_IN2R_TO_MIXINR_SHIFT                  8  /* IN2R_TO_MIXINR */
+#define WM8993_IN2R_TO_MIXINR_WIDTH                  1  /* IN2R_TO_MIXINR */
+#define WM8993_IN2R_MIXINR_VOL                  0x0080  /* IN2R_MIXINR_VOL */
+#define WM8993_IN2R_MIXINR_VOL_MASK             0x0080  /* IN2R_MIXINR_VOL */
+#define WM8993_IN2R_MIXINR_VOL_SHIFT                 7  /* IN2R_MIXINR_VOL */
+#define WM8993_IN2R_MIXINR_VOL_WIDTH                 1  /* IN2R_MIXINR_VOL */
+#define WM8993_IN1R_TO_MIXINR                   0x0020  /* IN1R_TO_MIXINR */
+#define WM8993_IN1R_TO_MIXINR_MASK              0x0020  /* IN1R_TO_MIXINR */
+#define WM8993_IN1R_TO_MIXINR_SHIFT                  5  /* IN1R_TO_MIXINR */
+#define WM8993_IN1R_TO_MIXINR_WIDTH                  1  /* IN1R_TO_MIXINR */
+#define WM8993_IN1R_MIXINR_VOL                  0x0010  /* IN1R_MIXINR_VOL */
+#define WM8993_IN1R_MIXINR_VOL_MASK             0x0010  /* IN1R_MIXINR_VOL */
+#define WM8993_IN1R_MIXINR_VOL_SHIFT                 4  /* IN1R_MIXINR_VOL */
+#define WM8993_IN1R_MIXINR_VOL_WIDTH                 1  /* IN1R_MIXINR_VOL */
+#define WM8993_MIXOUTR_MIXINR_VOL_MASK          0x0007  /* MIXOUTR_MIXINR_VOL - [2:0] */
+#define WM8993_MIXOUTR_MIXINR_VOL_SHIFT              0  /* MIXOUTR_MIXINR_VOL - [2:0] */
+#define WM8993_MIXOUTR_MIXINR_VOL_WIDTH              3  /* MIXOUTR_MIXINR_VOL - [2:0] */
+
+/*
+ * R43 (0x2B) - Input Mixer5
+ */
+#define WM8993_IN1LP_MIXINL_VOL_MASK            0x01C0  /* IN1LP_MIXINL_VOL - [8:6] */
+#define WM8993_IN1LP_MIXINL_VOL_SHIFT                6  /* IN1LP_MIXINL_VOL - [8:6] */
+#define WM8993_IN1LP_MIXINL_VOL_WIDTH                3  /* IN1LP_MIXINL_VOL - [8:6] */
+#define WM8993_VRX_MIXINL_VOL_MASK              0x0007  /* VRX_MIXINL_VOL - [2:0] */
+#define WM8993_VRX_MIXINL_VOL_SHIFT                  0  /* VRX_MIXINL_VOL - [2:0] */
+#define WM8993_VRX_MIXINL_VOL_WIDTH                  3  /* VRX_MIXINL_VOL - [2:0] */
+
+/*
+ * R44 (0x2C) - Input Mixer6
+ */
+#define WM8993_IN1RP_MIXINR_VOL_MASK            0x01C0  /* IN1RP_MIXINR_VOL - [8:6] */
+#define WM8993_IN1RP_MIXINR_VOL_SHIFT                6  /* IN1RP_MIXINR_VOL - [8:6] */
+#define WM8993_IN1RP_MIXINR_VOL_WIDTH                3  /* IN1RP_MIXINR_VOL - [8:6] */
+#define WM8993_VRX_MIXINR_VOL_MASK              0x0007  /* VRX_MIXINR_VOL - [2:0] */
+#define WM8993_VRX_MIXINR_VOL_SHIFT                  0  /* VRX_MIXINR_VOL - [2:0] */
+#define WM8993_VRX_MIXINR_VOL_WIDTH                  3  /* VRX_MIXINR_VOL - [2:0] */
+
+/*
+ * R45 (0x2D) - Output Mixer1
+ */
+#define WM8993_DACL_TO_HPOUT1L                  0x0100  /* DACL_TO_HPOUT1L */
+#define WM8993_DACL_TO_HPOUT1L_MASK             0x0100  /* DACL_TO_HPOUT1L */
+#define WM8993_DACL_TO_HPOUT1L_SHIFT                 8  /* DACL_TO_HPOUT1L */
+#define WM8993_DACL_TO_HPOUT1L_WIDTH                 1  /* DACL_TO_HPOUT1L */
+#define WM8993_MIXINR_TO_MIXOUTL                0x0080  /* MIXINR_TO_MIXOUTL */
+#define WM8993_MIXINR_TO_MIXOUTL_MASK           0x0080  /* MIXINR_TO_MIXOUTL */
+#define WM8993_MIXINR_TO_MIXOUTL_SHIFT               7  /* MIXINR_TO_MIXOUTL */
+#define WM8993_MIXINR_TO_MIXOUTL_WIDTH               1  /* MIXINR_TO_MIXOUTL */
+#define WM8993_MIXINL_TO_MIXOUTL                0x0040  /* MIXINL_TO_MIXOUTL */
+#define WM8993_MIXINL_TO_MIXOUTL_MASK           0x0040  /* MIXINL_TO_MIXOUTL */
+#define WM8993_MIXINL_TO_MIXOUTL_SHIFT               6  /* MIXINL_TO_MIXOUTL */
+#define WM8993_MIXINL_TO_MIXOUTL_WIDTH               1  /* MIXINL_TO_MIXOUTL */
+#define WM8993_IN2RN_TO_MIXOUTL                 0x0020  /* IN2RN_TO_MIXOUTL */
+#define WM8993_IN2RN_TO_MIXOUTL_MASK            0x0020  /* IN2RN_TO_MIXOUTL */
+#define WM8993_IN2RN_TO_MIXOUTL_SHIFT                5  /* IN2RN_TO_MIXOUTL */
+#define WM8993_IN2RN_TO_MIXOUTL_WIDTH                1  /* IN2RN_TO_MIXOUTL */
+#define WM8993_IN2LN_TO_MIXOUTL                 0x0010  /* IN2LN_TO_MIXOUTL */
+#define WM8993_IN2LN_TO_MIXOUTL_MASK            0x0010  /* IN2LN_TO_MIXOUTL */
+#define WM8993_IN2LN_TO_MIXOUTL_SHIFT                4  /* IN2LN_TO_MIXOUTL */
+#define WM8993_IN2LN_TO_MIXOUTL_WIDTH                1  /* IN2LN_TO_MIXOUTL */
+#define WM8993_IN1R_TO_MIXOUTL                  0x0008  /* IN1R_TO_MIXOUTL */
+#define WM8993_IN1R_TO_MIXOUTL_MASK             0x0008  /* IN1R_TO_MIXOUTL */
+#define WM8993_IN1R_TO_MIXOUTL_SHIFT                 3  /* IN1R_TO_MIXOUTL */
+#define WM8993_IN1R_TO_MIXOUTL_WIDTH                 1  /* IN1R_TO_MIXOUTL */
+#define WM8993_IN1L_TO_MIXOUTL                  0x0004  /* IN1L_TO_MIXOUTL */
+#define WM8993_IN1L_TO_MIXOUTL_MASK             0x0004  /* IN1L_TO_MIXOUTL */
+#define WM8993_IN1L_TO_MIXOUTL_SHIFT                 2  /* IN1L_TO_MIXOUTL */
+#define WM8993_IN1L_TO_MIXOUTL_WIDTH                 1  /* IN1L_TO_MIXOUTL */
+#define WM8993_IN2LP_TO_MIXOUTL                 0x0002  /* IN2LP_TO_MIXOUTL */
+#define WM8993_IN2LP_TO_MIXOUTL_MASK            0x0002  /* IN2LP_TO_MIXOUTL */
+#define WM8993_IN2LP_TO_MIXOUTL_SHIFT                1  /* IN2LP_TO_MIXOUTL */
+#define WM8993_IN2LP_TO_MIXOUTL_WIDTH                1  /* IN2LP_TO_MIXOUTL */
+#define WM8993_DACL_TO_MIXOUTL                  0x0001  /* DACL_TO_MIXOUTL */
+#define WM8993_DACL_TO_MIXOUTL_MASK             0x0001  /* DACL_TO_MIXOUTL */
+#define WM8993_DACL_TO_MIXOUTL_SHIFT                 0  /* DACL_TO_MIXOUTL */
+#define WM8993_DACL_TO_MIXOUTL_WIDTH                 1  /* DACL_TO_MIXOUTL */
+
+/*
+ * R46 (0x2E) - Output Mixer2
+ */
+#define WM8993_DACR_TO_HPOUT1R                  0x0100  /* DACR_TO_HPOUT1R */
+#define WM8993_DACR_TO_HPOUT1R_MASK             0x0100  /* DACR_TO_HPOUT1R */
+#define WM8993_DACR_TO_HPOUT1R_SHIFT                 8  /* DACR_TO_HPOUT1R */
+#define WM8993_DACR_TO_HPOUT1R_WIDTH                 1  /* DACR_TO_HPOUT1R */
+#define WM8993_MIXINL_TO_MIXOUTR                0x0080  /* MIXINL_TO_MIXOUTR */
+#define WM8993_MIXINL_TO_MIXOUTR_MASK           0x0080  /* MIXINL_TO_MIXOUTR */
+#define WM8993_MIXINL_TO_MIXOUTR_SHIFT               7  /* MIXINL_TO_MIXOUTR */
+#define WM8993_MIXINL_TO_MIXOUTR_WIDTH               1  /* MIXINL_TO_MIXOUTR */
+#define WM8993_MIXINR_TO_MIXOUTR                0x0040  /* MIXINR_TO_MIXOUTR */
+#define WM8993_MIXINR_TO_MIXOUTR_MASK           0x0040  /* MIXINR_TO_MIXOUTR */
+#define WM8993_MIXINR_TO_MIXOUTR_SHIFT               6  /* MIXINR_TO_MIXOUTR */
+#define WM8993_MIXINR_TO_MIXOUTR_WIDTH               1  /* MIXINR_TO_MIXOUTR */
+#define WM8993_IN2LN_TO_MIXOUTR                 0x0020  /* IN2LN_TO_MIXOUTR */
+#define WM8993_IN2LN_TO_MIXOUTR_MASK            0x0020  /* IN2LN_TO_MIXOUTR */
+#define WM8993_IN2LN_TO_MIXOUTR_SHIFT                5  /* IN2LN_TO_MIXOUTR */
+#define WM8993_IN2LN_TO_MIXOUTR_WIDTH                1  /* IN2LN_TO_MIXOUTR */
+#define WM8993_IN2RN_TO_MIXOUTR                 0x0010  /* IN2RN_TO_MIXOUTR */
+#define WM8993_IN2RN_TO_MIXOUTR_MASK            0x0010  /* IN2RN_TO_MIXOUTR */
+#define WM8993_IN2RN_TO_MIXOUTR_SHIFT                4  /* IN2RN_TO_MIXOUTR */
+#define WM8993_IN2RN_TO_MIXOUTR_WIDTH                1  /* IN2RN_TO_MIXOUTR */
+#define WM8993_IN1L_TO_MIXOUTR                  0x0008  /* IN1L_TO_MIXOUTR */
+#define WM8993_IN1L_TO_MIXOUTR_MASK             0x0008  /* IN1L_TO_MIXOUTR */
+#define WM8993_IN1L_TO_MIXOUTR_SHIFT                 3  /* IN1L_TO_MIXOUTR */
+#define WM8993_IN1L_TO_MIXOUTR_WIDTH                 1  /* IN1L_TO_MIXOUTR */
+#define WM8993_IN1R_TO_MIXOUTR                  0x0004  /* IN1R_TO_MIXOUTR */
+#define WM8993_IN1R_TO_MIXOUTR_MASK             0x0004  /* IN1R_TO_MIXOUTR */
+#define WM8993_IN1R_TO_MIXOUTR_SHIFT                 2  /* IN1R_TO_MIXOUTR */
+#define WM8993_IN1R_TO_MIXOUTR_WIDTH                 1  /* IN1R_TO_MIXOUTR */
+#define WM8993_IN2RP_TO_MIXOUTR                 0x0002  /* IN2RP_TO_MIXOUTR */
+#define WM8993_IN2RP_TO_MIXOUTR_MASK            0x0002  /* IN2RP_TO_MIXOUTR */
+#define WM8993_IN2RP_TO_MIXOUTR_SHIFT                1  /* IN2RP_TO_MIXOUTR */
+#define WM8993_IN2RP_TO_MIXOUTR_WIDTH                1  /* IN2RP_TO_MIXOUTR */
+#define WM8993_DACR_TO_MIXOUTR                  0x0001  /* DACR_TO_MIXOUTR */
+#define WM8993_DACR_TO_MIXOUTR_MASK             0x0001  /* DACR_TO_MIXOUTR */
+#define WM8993_DACR_TO_MIXOUTR_SHIFT                 0  /* DACR_TO_MIXOUTR */
+#define WM8993_DACR_TO_MIXOUTR_WIDTH                 1  /* DACR_TO_MIXOUTR */
+
+/*
+ * R47 (0x2F) - Output Mixer3
+ */
+#define WM8993_IN2LP_MIXOUTL_VOL_MASK           0x0E00  /* IN2LP_MIXOUTL_VOL - [11:9] */
+#define WM8993_IN2LP_MIXOUTL_VOL_SHIFT               9  /* IN2LP_MIXOUTL_VOL - [11:9] */
+#define WM8993_IN2LP_MIXOUTL_VOL_WIDTH               3  /* IN2LP_MIXOUTL_VOL - [11:9] */
+#define WM8993_IN2LN_MIXOUTL_VOL_MASK           0x01C0  /* IN2LN_MIXOUTL_VOL - [8:6] */
+#define WM8993_IN2LN_MIXOUTL_VOL_SHIFT               6  /* IN2LN_MIXOUTL_VOL - [8:6] */
+#define WM8993_IN2LN_MIXOUTL_VOL_WIDTH               3  /* IN2LN_MIXOUTL_VOL - [8:6] */
+#define WM8993_IN1R_MIXOUTL_VOL_MASK            0x0038  /* IN1R_MIXOUTL_VOL - [5:3] */
+#define WM8993_IN1R_MIXOUTL_VOL_SHIFT                3  /* IN1R_MIXOUTL_VOL - [5:3] */
+#define WM8993_IN1R_MIXOUTL_VOL_WIDTH                3  /* IN1R_MIXOUTL_VOL - [5:3] */
+#define WM8993_IN1L_MIXOUTL_VOL_MASK            0x0007  /* IN1L_MIXOUTL_VOL - [2:0] */
+#define WM8993_IN1L_MIXOUTL_VOL_SHIFT                0  /* IN1L_MIXOUTL_VOL - [2:0] */
+#define WM8993_IN1L_MIXOUTL_VOL_WIDTH                3  /* IN1L_MIXOUTL_VOL - [2:0] */
+
+/*
+ * R48 (0x30) - Output Mixer4
+ */
+#define WM8993_IN2RP_MIXOUTR_VOL_MASK           0x0E00  /* IN2RP_MIXOUTR_VOL - [11:9] */
+#define WM8993_IN2RP_MIXOUTR_VOL_SHIFT               9  /* IN2RP_MIXOUTR_VOL - [11:9] */
+#define WM8993_IN2RP_MIXOUTR_VOL_WIDTH               3  /* IN2RP_MIXOUTR_VOL - [11:9] */
+#define WM8993_IN2RN_MIXOUTR_VOL_MASK           0x01C0  /* IN2RN_MIXOUTR_VOL - [8:6] */
+#define WM8993_IN2RN_MIXOUTR_VOL_SHIFT               6  /* IN2RN_MIXOUTR_VOL - [8:6] */
+#define WM8993_IN2RN_MIXOUTR_VOL_WIDTH               3  /* IN2RN_MIXOUTR_VOL - [8:6] */
+#define WM8993_IN1L_MIXOUTR_VOL_MASK            0x0038  /* IN1L_MIXOUTR_VOL - [5:3] */
+#define WM8993_IN1L_MIXOUTR_VOL_SHIFT                3  /* IN1L_MIXOUTR_VOL - [5:3] */
+#define WM8993_IN1L_MIXOUTR_VOL_WIDTH                3  /* IN1L_MIXOUTR_VOL - [5:3] */
+#define WM8993_IN1R_MIXOUTR_VOL_MASK            0x0007  /* IN1R_MIXOUTR_VOL - [2:0] */
+#define WM8993_IN1R_MIXOUTR_VOL_SHIFT                0  /* IN1R_MIXOUTR_VOL - [2:0] */
+#define WM8993_IN1R_MIXOUTR_VOL_WIDTH                3  /* IN1R_MIXOUTR_VOL - [2:0] */
+
+/*
+ * R49 (0x31) - Output Mixer5
+ */
+#define WM8993_DACL_MIXOUTL_VOL_MASK            0x0E00  /* DACL_MIXOUTL_VOL - [11:9] */
+#define WM8993_DACL_MIXOUTL_VOL_SHIFT                9  /* DACL_MIXOUTL_VOL - [11:9] */
+#define WM8993_DACL_MIXOUTL_VOL_WIDTH                3  /* DACL_MIXOUTL_VOL - [11:9] */
+#define WM8993_IN2RN_MIXOUTL_VOL_MASK           0x01C0  /* IN2RN_MIXOUTL_VOL - [8:6] */
+#define WM8993_IN2RN_MIXOUTL_VOL_SHIFT               6  /* IN2RN_MIXOUTL_VOL - [8:6] */
+#define WM8993_IN2RN_MIXOUTL_VOL_WIDTH               3  /* IN2RN_MIXOUTL_VOL - [8:6] */
+#define WM8993_MIXINR_MIXOUTL_VOL_MASK          0x0038  /* MIXINR_MIXOUTL_VOL - [5:3] */
+#define WM8993_MIXINR_MIXOUTL_VOL_SHIFT              3  /* MIXINR_MIXOUTL_VOL - [5:3] */
+#define WM8993_MIXINR_MIXOUTL_VOL_WIDTH              3  /* MIXINR_MIXOUTL_VOL - [5:3] */
+#define WM8993_MIXINL_MIXOUTL_VOL_MASK          0x0007  /* MIXINL_MIXOUTL_VOL - [2:0] */
+#define WM8993_MIXINL_MIXOUTL_VOL_SHIFT              0  /* MIXINL_MIXOUTL_VOL - [2:0] */
+#define WM8993_MIXINL_MIXOUTL_VOL_WIDTH              3  /* MIXINL_MIXOUTL_VOL - [2:0] */
+
+/*
+ * R50 (0x32) - Output Mixer6
+ */
+#define WM8993_DACR_MIXOUTR_VOL_MASK            0x0E00  /* DACR_MIXOUTR_VOL - [11:9] */
+#define WM8993_DACR_MIXOUTR_VOL_SHIFT                9  /* DACR_MIXOUTR_VOL - [11:9] */
+#define WM8993_DACR_MIXOUTR_VOL_WIDTH                3  /* DACR_MIXOUTR_VOL - [11:9] */
+#define WM8993_IN2LN_MIXOUTR_VOL_MASK           0x01C0  /* IN2LN_MIXOUTR_VOL - [8:6] */
+#define WM8993_IN2LN_MIXOUTR_VOL_SHIFT               6  /* IN2LN_MIXOUTR_VOL - [8:6] */
+#define WM8993_IN2LN_MIXOUTR_VOL_WIDTH               3  /* IN2LN_MIXOUTR_VOL - [8:6] */
+#define WM8993_MIXINL_MIXOUTR_VOL_MASK          0x0038  /* MIXINL_MIXOUTR_VOL - [5:3] */
+#define WM8993_MIXINL_MIXOUTR_VOL_SHIFT              3  /* MIXINL_MIXOUTR_VOL - [5:3] */
+#define WM8993_MIXINL_MIXOUTR_VOL_WIDTH              3  /* MIXINL_MIXOUTR_VOL - [5:3] */
+#define WM8993_MIXINR_MIXOUTR_VOL_MASK          0x0007  /* MIXINR_MIXOUTR_VOL - [2:0] */
+#define WM8993_MIXINR_MIXOUTR_VOL_SHIFT              0  /* MIXINR_MIXOUTR_VOL - [2:0] */
+#define WM8993_MIXINR_MIXOUTR_VOL_WIDTH              3  /* MIXINR_MIXOUTR_VOL - [2:0] */
+
+/*
+ * R51 (0x33) - HPOUT2 Mixer
+ */
+#define WM8993_VRX_TO_HPOUT2                    0x0020  /* VRX_TO_HPOUT2 */
+#define WM8993_VRX_TO_HPOUT2_MASK               0x0020  /* VRX_TO_HPOUT2 */
+#define WM8993_VRX_TO_HPOUT2_SHIFT                   5  /* VRX_TO_HPOUT2 */
+#define WM8993_VRX_TO_HPOUT2_WIDTH                   1  /* VRX_TO_HPOUT2 */
+#define WM8993_MIXOUTLVOL_TO_HPOUT2             0x0010  /* MIXOUTLVOL_TO_HPOUT2 */
+#define WM8993_MIXOUTLVOL_TO_HPOUT2_MASK        0x0010  /* MIXOUTLVOL_TO_HPOUT2 */
+#define WM8993_MIXOUTLVOL_TO_HPOUT2_SHIFT            4  /* MIXOUTLVOL_TO_HPOUT2 */
+#define WM8993_MIXOUTLVOL_TO_HPOUT2_WIDTH            1  /* MIXOUTLVOL_TO_HPOUT2 */
+#define WM8993_MIXOUTRVOL_TO_HPOUT2             0x0008  /* MIXOUTRVOL_TO_HPOUT2 */
+#define WM8993_MIXOUTRVOL_TO_HPOUT2_MASK        0x0008  /* MIXOUTRVOL_TO_HPOUT2 */
+#define WM8993_MIXOUTRVOL_TO_HPOUT2_SHIFT            3  /* MIXOUTRVOL_TO_HPOUT2 */
+#define WM8993_MIXOUTRVOL_TO_HPOUT2_WIDTH            1  /* MIXOUTRVOL_TO_HPOUT2 */
+
+/*
+ * R52 (0x34) - Line Mixer1
+ */
+#define WM8993_MIXOUTL_TO_LINEOUT1N             0x0040  /* MIXOUTL_TO_LINEOUT1N */
+#define WM8993_MIXOUTL_TO_LINEOUT1N_MASK        0x0040  /* MIXOUTL_TO_LINEOUT1N */
+#define WM8993_MIXOUTL_TO_LINEOUT1N_SHIFT            6  /* MIXOUTL_TO_LINEOUT1N */
+#define WM8993_MIXOUTL_TO_LINEOUT1N_WIDTH            1  /* MIXOUTL_TO_LINEOUT1N */
+#define WM8993_MIXOUTR_TO_LINEOUT1N             0x0020  /* MIXOUTR_TO_LINEOUT1N */
+#define WM8993_MIXOUTR_TO_LINEOUT1N_MASK        0x0020  /* MIXOUTR_TO_LINEOUT1N */
+#define WM8993_MIXOUTR_TO_LINEOUT1N_SHIFT            5  /* MIXOUTR_TO_LINEOUT1N */
+#define WM8993_MIXOUTR_TO_LINEOUT1N_WIDTH            1  /* MIXOUTR_TO_LINEOUT1N */
+#define WM8993_LINEOUT1_MODE                    0x0010  /* LINEOUT1_MODE */
+#define WM8993_LINEOUT1_MODE_MASK               0x0010  /* LINEOUT1_MODE */
+#define WM8993_LINEOUT1_MODE_SHIFT                   4  /* LINEOUT1_MODE */
+#define WM8993_LINEOUT1_MODE_WIDTH                   1  /* LINEOUT1_MODE */
+#define WM8993_IN1R_TO_LINEOUT1P                0x0004  /* IN1R_TO_LINEOUT1P */
+#define WM8993_IN1R_TO_LINEOUT1P_MASK           0x0004  /* IN1R_TO_LINEOUT1P */
+#define WM8993_IN1R_TO_LINEOUT1P_SHIFT               2  /* IN1R_TO_LINEOUT1P */
+#define WM8993_IN1R_TO_LINEOUT1P_WIDTH               1  /* IN1R_TO_LINEOUT1P */
+#define WM8993_IN1L_TO_LINEOUT1P                0x0002  /* IN1L_TO_LINEOUT1P */
+#define WM8993_IN1L_TO_LINEOUT1P_MASK           0x0002  /* IN1L_TO_LINEOUT1P */
+#define WM8993_IN1L_TO_LINEOUT1P_SHIFT               1  /* IN1L_TO_LINEOUT1P */
+#define WM8993_IN1L_TO_LINEOUT1P_WIDTH               1  /* IN1L_TO_LINEOUT1P */
+#define WM8993_MIXOUTL_TO_LINEOUT1P             0x0001  /* MIXOUTL_TO_LINEOUT1P */
+#define WM8993_MIXOUTL_TO_LINEOUT1P_MASK        0x0001  /* MIXOUTL_TO_LINEOUT1P */
+#define WM8993_MIXOUTL_TO_LINEOUT1P_SHIFT            0  /* MIXOUTL_TO_LINEOUT1P */
+#define WM8993_MIXOUTL_TO_LINEOUT1P_WIDTH            1  /* MIXOUTL_TO_LINEOUT1P */
+
+/*
+ * R53 (0x35) - Line Mixer2
+ */
+#define WM8993_MIXOUTR_TO_LINEOUT2N             0x0040  /* MIXOUTR_TO_LINEOUT2N */
+#define WM8993_MIXOUTR_TO_LINEOUT2N_MASK        0x0040  /* MIXOUTR_TO_LINEOUT2N */
+#define WM8993_MIXOUTR_TO_LINEOUT2N_SHIFT            6  /* MIXOUTR_TO_LINEOUT2N */
+#define WM8993_MIXOUTR_TO_LINEOUT2N_WIDTH            1  /* MIXOUTR_TO_LINEOUT2N */
+#define WM8993_MIXOUTL_TO_LINEOUT2N             0x0020  /* MIXOUTL_TO_LINEOUT2N */
+#define WM8993_MIXOUTL_TO_LINEOUT2N_MASK        0x0020  /* MIXOUTL_TO_LINEOUT2N */
+#define WM8993_MIXOUTL_TO_LINEOUT2N_SHIFT            5  /* MIXOUTL_TO_LINEOUT2N */
+#define WM8993_MIXOUTL_TO_LINEOUT2N_WIDTH            1  /* MIXOUTL_TO_LINEOUT2N */
+#define WM8993_LINEOUT2_MODE                    0x0010  /* LINEOUT2_MODE */
+#define WM8993_LINEOUT2_MODE_MASK               0x0010  /* LINEOUT2_MODE */
+#define WM8993_LINEOUT2_MODE_SHIFT                   4  /* LINEOUT2_MODE */
+#define WM8993_LINEOUT2_MODE_WIDTH                   1  /* LINEOUT2_MODE */
+#define WM8993_IN1L_TO_LINEOUT2P                0x0004  /* IN1L_TO_LINEOUT2P */
+#define WM8993_IN1L_TO_LINEOUT2P_MASK           0x0004  /* IN1L_TO_LINEOUT2P */
+#define WM8993_IN1L_TO_LINEOUT2P_SHIFT               2  /* IN1L_TO_LINEOUT2P */
+#define WM8993_IN1L_TO_LINEOUT2P_WIDTH               1  /* IN1L_TO_LINEOUT2P */
+#define WM8993_IN1R_TO_LINEOUT2P                0x0002  /* IN1R_TO_LINEOUT2P */
+#define WM8993_IN1R_TO_LINEOUT2P_MASK           0x0002  /* IN1R_TO_LINEOUT2P */
+#define WM8993_IN1R_TO_LINEOUT2P_SHIFT               1  /* IN1R_TO_LINEOUT2P */
+#define WM8993_IN1R_TO_LINEOUT2P_WIDTH               1  /* IN1R_TO_LINEOUT2P */
+#define WM8993_MIXOUTR_TO_LINEOUT2P             0x0001  /* MIXOUTR_TO_LINEOUT2P */
+#define WM8993_MIXOUTR_TO_LINEOUT2P_MASK        0x0001  /* MIXOUTR_TO_LINEOUT2P */
+#define WM8993_MIXOUTR_TO_LINEOUT2P_SHIFT            0  /* MIXOUTR_TO_LINEOUT2P */
+#define WM8993_MIXOUTR_TO_LINEOUT2P_WIDTH            1  /* MIXOUTR_TO_LINEOUT2P */
+
+/*
+ * R54 (0x36) - Speaker Mixer
+ */
+#define WM8993_SPKAB_REF_SEL                    0x0100  /* SPKAB_REF_SEL */
+#define WM8993_SPKAB_REF_SEL_MASK               0x0100  /* SPKAB_REF_SEL */
+#define WM8993_SPKAB_REF_SEL_SHIFT                   8  /* SPKAB_REF_SEL */
+#define WM8993_SPKAB_REF_SEL_WIDTH                   1  /* SPKAB_REF_SEL */
+#define WM8993_MIXINL_TO_SPKMIXL                0x0080  /* MIXINL_TO_SPKMIXL */
+#define WM8993_MIXINL_TO_SPKMIXL_MASK           0x0080  /* MIXINL_TO_SPKMIXL */
+#define WM8993_MIXINL_TO_SPKMIXL_SHIFT               7  /* MIXINL_TO_SPKMIXL */
+#define WM8993_MIXINL_TO_SPKMIXL_WIDTH               1  /* MIXINL_TO_SPKMIXL */
+#define WM8993_MIXINR_TO_SPKMIXR                0x0040  /* MIXINR_TO_SPKMIXR */
+#define WM8993_MIXINR_TO_SPKMIXR_MASK           0x0040  /* MIXINR_TO_SPKMIXR */
+#define WM8993_MIXINR_TO_SPKMIXR_SHIFT               6  /* MIXINR_TO_SPKMIXR */
+#define WM8993_MIXINR_TO_SPKMIXR_WIDTH               1  /* MIXINR_TO_SPKMIXR */
+#define WM8993_IN1LP_TO_SPKMIXL                 0x0020  /* IN1LP_TO_SPKMIXL */
+#define WM8993_IN1LP_TO_SPKMIXL_MASK            0x0020  /* IN1LP_TO_SPKMIXL */
+#define WM8993_IN1LP_TO_SPKMIXL_SHIFT                5  /* IN1LP_TO_SPKMIXL */
+#define WM8993_IN1LP_TO_SPKMIXL_WIDTH                1  /* IN1LP_TO_SPKMIXL */
+#define WM8993_IN1RP_TO_SPKMIXR                 0x0010  /* IN1RP_TO_SPKMIXR */
+#define WM8993_IN1RP_TO_SPKMIXR_MASK            0x0010  /* IN1RP_TO_SPKMIXR */
+#define WM8993_IN1RP_TO_SPKMIXR_SHIFT                4  /* IN1RP_TO_SPKMIXR */
+#define WM8993_IN1RP_TO_SPKMIXR_WIDTH                1  /* IN1RP_TO_SPKMIXR */
+#define WM8993_MIXOUTL_TO_SPKMIXL               0x0008  /* MIXOUTL_TO_SPKMIXL */
+#define WM8993_MIXOUTL_TO_SPKMIXL_MASK          0x0008  /* MIXOUTL_TO_SPKMIXL */
+#define WM8993_MIXOUTL_TO_SPKMIXL_SHIFT              3  /* MIXOUTL_TO_SPKMIXL */
+#define WM8993_MIXOUTL_TO_SPKMIXL_WIDTH              1  /* MIXOUTL_TO_SPKMIXL */
+#define WM8993_MIXOUTR_TO_SPKMIXR               0x0004  /* MIXOUTR_TO_SPKMIXR */
+#define WM8993_MIXOUTR_TO_SPKMIXR_MASK          0x0004  /* MIXOUTR_TO_SPKMIXR */
+#define WM8993_MIXOUTR_TO_SPKMIXR_SHIFT              2  /* MIXOUTR_TO_SPKMIXR */
+#define WM8993_MIXOUTR_TO_SPKMIXR_WIDTH              1  /* MIXOUTR_TO_SPKMIXR */
+#define WM8993_DACL_TO_SPKMIXL                  0x0002  /* DACL_TO_SPKMIXL */
+#define WM8993_DACL_TO_SPKMIXL_MASK             0x0002  /* DACL_TO_SPKMIXL */
+#define WM8993_DACL_TO_SPKMIXL_SHIFT                 1  /* DACL_TO_SPKMIXL */
+#define WM8993_DACL_TO_SPKMIXL_WIDTH                 1  /* DACL_TO_SPKMIXL */
+#define WM8993_DACR_TO_SPKMIXR                  0x0001  /* DACR_TO_SPKMIXR */
+#define WM8993_DACR_TO_SPKMIXR_MASK             0x0001  /* DACR_TO_SPKMIXR */
+#define WM8993_DACR_TO_SPKMIXR_SHIFT                 0  /* DACR_TO_SPKMIXR */
+#define WM8993_DACR_TO_SPKMIXR_WIDTH                 1  /* DACR_TO_SPKMIXR */
+
+/*
+ * R55 (0x37) - Additional Control
+ */
+#define WM8993_LINEOUT1_FB                      0x0080  /* LINEOUT1_FB */
+#define WM8993_LINEOUT1_FB_MASK                 0x0080  /* LINEOUT1_FB */
+#define WM8993_LINEOUT1_FB_SHIFT                     7  /* LINEOUT1_FB */
+#define WM8993_LINEOUT1_FB_WIDTH                     1  /* LINEOUT1_FB */
+#define WM8993_LINEOUT2_FB                      0x0040  /* LINEOUT2_FB */
+#define WM8993_LINEOUT2_FB_MASK                 0x0040  /* LINEOUT2_FB */
+#define WM8993_LINEOUT2_FB_SHIFT                     6  /* LINEOUT2_FB */
+#define WM8993_LINEOUT2_FB_WIDTH                     1  /* LINEOUT2_FB */
+#define WM8993_VROI                             0x0001  /* VROI */
+#define WM8993_VROI_MASK                        0x0001  /* VROI */
+#define WM8993_VROI_SHIFT                            0  /* VROI */
+#define WM8993_VROI_WIDTH                            1  /* VROI */
+
+/*
+ * R56 (0x38) - AntiPOP1
+ */
+#define WM8993_LINEOUT_VMID_BUF_ENA             0x0080  /* LINEOUT_VMID_BUF_ENA */
+#define WM8993_LINEOUT_VMID_BUF_ENA_MASK        0x0080  /* LINEOUT_VMID_BUF_ENA */
+#define WM8993_LINEOUT_VMID_BUF_ENA_SHIFT            7  /* LINEOUT_VMID_BUF_ENA */
+#define WM8993_LINEOUT_VMID_BUF_ENA_WIDTH            1  /* LINEOUT_VMID_BUF_ENA */
+#define WM8993_HPOUT2_IN_ENA                    0x0040  /* HPOUT2_IN_ENA */
+#define WM8993_HPOUT2_IN_ENA_MASK               0x0040  /* HPOUT2_IN_ENA */
+#define WM8993_HPOUT2_IN_ENA_SHIFT                   6  /* HPOUT2_IN_ENA */
+#define WM8993_HPOUT2_IN_ENA_WIDTH                   1  /* HPOUT2_IN_ENA */
+#define WM8993_LINEOUT1_DISCH                   0x0020  /* LINEOUT1_DISCH */
+#define WM8993_LINEOUT1_DISCH_MASK              0x0020  /* LINEOUT1_DISCH */
+#define WM8993_LINEOUT1_DISCH_SHIFT                  5  /* LINEOUT1_DISCH */
+#define WM8993_LINEOUT1_DISCH_WIDTH                  1  /* LINEOUT1_DISCH */
+#define WM8993_LINEOUT2_DISCH                   0x0010  /* LINEOUT2_DISCH */
+#define WM8993_LINEOUT2_DISCH_MASK              0x0010  /* LINEOUT2_DISCH */
+#define WM8993_LINEOUT2_DISCH_SHIFT                  4  /* LINEOUT2_DISCH */
+#define WM8993_LINEOUT2_DISCH_WIDTH                  1  /* LINEOUT2_DISCH */
+
+/*
+ * R57 (0x39) - AntiPOP2
+ */
+#define WM8993_VMID_RAMP_MASK                   0x0060  /* VMID_RAMP - [6:5] */
+#define WM8993_VMID_RAMP_SHIFT                       5  /* VMID_RAMP - [6:5] */
+#define WM8993_VMID_RAMP_WIDTH                       2  /* VMID_RAMP - [6:5] */
+#define WM8993_VMID_BUF_ENA                     0x0008  /* VMID_BUF_ENA */
+#define WM8993_VMID_BUF_ENA_MASK                0x0008  /* VMID_BUF_ENA */
+#define WM8993_VMID_BUF_ENA_SHIFT                    3  /* VMID_BUF_ENA */
+#define WM8993_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
+#define WM8993_STARTUP_BIAS_ENA                 0x0004  /* STARTUP_BIAS_ENA */
+#define WM8993_STARTUP_BIAS_ENA_MASK            0x0004  /* STARTUP_BIAS_ENA */
+#define WM8993_STARTUP_BIAS_ENA_SHIFT                2  /* STARTUP_BIAS_ENA */
+#define WM8993_STARTUP_BIAS_ENA_WIDTH                1  /* STARTUP_BIAS_ENA */
+#define WM8993_BIAS_SRC                         0x0002  /* BIAS_SRC */
+#define WM8993_BIAS_SRC_MASK                    0x0002  /* BIAS_SRC */
+#define WM8993_BIAS_SRC_SHIFT                        1  /* BIAS_SRC */
+#define WM8993_BIAS_SRC_WIDTH                        1  /* BIAS_SRC */
+#define WM8993_VMID_DISCH                       0x0001  /* VMID_DISCH */
+#define WM8993_VMID_DISCH_MASK                  0x0001  /* VMID_DISCH */
+#define WM8993_VMID_DISCH_SHIFT                      0  /* VMID_DISCH */
+#define WM8993_VMID_DISCH_WIDTH                      1  /* VMID_DISCH */
+
+/*
+ * R58 (0x3A) - MICBIAS
+ */
+#define WM8993_JD_SCTHR_MASK                    0x00C0  /* JD_SCTHR - [7:6] */
+#define WM8993_JD_SCTHR_SHIFT                        6  /* JD_SCTHR - [7:6] */
+#define WM8993_JD_SCTHR_WIDTH                        2  /* JD_SCTHR - [7:6] */
+#define WM8993_JD_THR_MASK                      0x0030  /* JD_THR - [5:4] */
+#define WM8993_JD_THR_SHIFT                          4  /* JD_THR - [5:4] */
+#define WM8993_JD_THR_WIDTH                          2  /* JD_THR - [5:4] */
+#define WM8993_JD_ENA                           0x0004  /* JD_ENA */
+#define WM8993_JD_ENA_MASK                      0x0004  /* JD_ENA */
+#define WM8993_JD_ENA_SHIFT                          2  /* JD_ENA */
+#define WM8993_JD_ENA_WIDTH                          1  /* JD_ENA */
+#define WM8993_MICB2_LVL                        0x0002  /* MICB2_LVL */
+#define WM8993_MICB2_LVL_MASK                   0x0002  /* MICB2_LVL */
+#define WM8993_MICB2_LVL_SHIFT                       1  /* MICB2_LVL */
+#define WM8993_MICB2_LVL_WIDTH                       1  /* MICB2_LVL */
+#define WM8993_MICB1_LVL                        0x0001  /* MICB1_LVL */
+#define WM8993_MICB1_LVL_MASK                   0x0001  /* MICB1_LVL */
+#define WM8993_MICB1_LVL_SHIFT                       0  /* MICB1_LVL */
+#define WM8993_MICB1_LVL_WIDTH                       1  /* MICB1_LVL */
+
+/*
+ * R60 (0x3C) - FLL Control 1
+ */
+#define WM8993_FLL_FRAC                         0x0004  /* FLL_FRAC */
+#define WM8993_FLL_FRAC_MASK                    0x0004  /* FLL_FRAC */
+#define WM8993_FLL_FRAC_SHIFT                        2  /* FLL_FRAC */
+#define WM8993_FLL_FRAC_WIDTH                        1  /* FLL_FRAC */
+#define WM8993_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM8993_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM8993_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM8993_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8993_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM8993_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM8993_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM8993_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R61 (0x3D) - FLL Control 2
+ */
+#define WM8993_FLL_OUTDIV_MASK                  0x0700  /* FLL_OUTDIV - [10:8] */
+#define WM8993_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [10:8] */
+#define WM8993_FLL_OUTDIV_WIDTH                      3  /* FLL_OUTDIV - [10:8] */
+#define WM8993_FLL_CTRL_RATE_MASK               0x0070  /* FLL_CTRL_RATE - [6:4] */
+#define WM8993_FLL_CTRL_RATE_SHIFT                   4  /* FLL_CTRL_RATE - [6:4] */
+#define WM8993_FLL_CTRL_RATE_WIDTH                   3  /* FLL_CTRL_RATE - [6:4] */
+#define WM8993_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM8993_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM8993_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R62 (0x3E) - FLL Control 3
+ */
+#define WM8993_FLL_K_MASK                       0xFFFF  /* FLL_K - [15:0] */
+#define WM8993_FLL_K_SHIFT                           0  /* FLL_K - [15:0] */
+#define WM8993_FLL_K_WIDTH                          16  /* FLL_K - [15:0] */
+
+/*
+ * R63 (0x3F) - FLL Control 4
+ */
+#define WM8993_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM8993_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM8993_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM8993_FLL_GAIN_MASK                    0x000F  /* FLL_GAIN - [3:0] */
+#define WM8993_FLL_GAIN_SHIFT                        0  /* FLL_GAIN - [3:0] */
+#define WM8993_FLL_GAIN_WIDTH                        4  /* FLL_GAIN - [3:0] */
+
+/*
+ * R64 (0x40) - FLL Control 5
+ */
+#define WM8993_FLL_FRC_NCO_VAL_MASK             0x1F80  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8993_FLL_FRC_NCO_VAL_SHIFT                 7  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8993_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8993_FLL_FRC_NCO                      0x0040  /* FLL_FRC_NCO */
+#define WM8993_FLL_FRC_NCO_MASK                 0x0040  /* FLL_FRC_NCO */
+#define WM8993_FLL_FRC_NCO_SHIFT                     6  /* FLL_FRC_NCO */
+#define WM8993_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
+#define WM8993_FLL_CLK_REF_DIV_MASK             0x0018  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8993_FLL_CLK_REF_DIV_SHIFT                 3  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8993_FLL_CLK_REF_DIV_WIDTH                 2  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM8993_FLL_CLK_SRC_MASK                 0x0003  /* FLL_CLK_SRC - [1:0] */
+#define WM8993_FLL_CLK_SRC_SHIFT                     0  /* FLL_CLK_SRC - [1:0] */
+#define WM8993_FLL_CLK_SRC_WIDTH                     2  /* FLL_CLK_SRC - [1:0] */
+
+/*
+ * R65 (0x41) - Clocking 3
+ */
+#define WM8993_CLK_DCS_DIV_MASK                 0x3C00  /* CLK_DCS_DIV - [13:10] */
+#define WM8993_CLK_DCS_DIV_SHIFT                    10  /* CLK_DCS_DIV - [13:10] */
+#define WM8993_CLK_DCS_DIV_WIDTH                     4  /* CLK_DCS_DIV - [13:10] */
+#define WM8993_SAMPLE_RATE_MASK                 0x0380  /* SAMPLE_RATE - [9:7] */
+#define WM8993_SAMPLE_RATE_SHIFT                     7  /* SAMPLE_RATE - [9:7] */
+#define WM8993_SAMPLE_RATE_WIDTH                     3  /* SAMPLE_RATE - [9:7] */
+#define WM8993_CLK_SYS_RATE_MASK                0x001E  /* CLK_SYS_RATE - [4:1] */
+#define WM8993_CLK_SYS_RATE_SHIFT                    1  /* CLK_SYS_RATE - [4:1] */
+#define WM8993_CLK_SYS_RATE_WIDTH                    4  /* CLK_SYS_RATE - [4:1] */
+#define WM8993_CLK_DSP_ENA                      0x0001  /* CLK_DSP_ENA */
+#define WM8993_CLK_DSP_ENA_MASK                 0x0001  /* CLK_DSP_ENA */
+#define WM8993_CLK_DSP_ENA_SHIFT                     0  /* CLK_DSP_ENA */
+#define WM8993_CLK_DSP_ENA_WIDTH                     1  /* CLK_DSP_ENA */
+
+/*
+ * R66 (0x42) - Clocking 4
+ */
+#define WM8993_DAC_DIV4                         0x0200  /* DAC_DIV4 */
+#define WM8993_DAC_DIV4_MASK                    0x0200  /* DAC_DIV4 */
+#define WM8993_DAC_DIV4_SHIFT                        9  /* DAC_DIV4 */
+#define WM8993_DAC_DIV4_WIDTH                        1  /* DAC_DIV4 */
+#define WM8993_CLK_256K_DIV_MASK                0x007E  /* CLK_256K_DIV - [6:1] */
+#define WM8993_CLK_256K_DIV_SHIFT                    1  /* CLK_256K_DIV - [6:1] */
+#define WM8993_CLK_256K_DIV_WIDTH                    6  /* CLK_256K_DIV - [6:1] */
+#define WM8993_SR_MODE                          0x0001  /* SR_MODE */
+#define WM8993_SR_MODE_MASK                     0x0001  /* SR_MODE */
+#define WM8993_SR_MODE_SHIFT                         0  /* SR_MODE */
+#define WM8993_SR_MODE_WIDTH                         1  /* SR_MODE */
+
+/*
+ * R67 (0x43) - MW Slave Control
+ */
+#define WM8993_MASK_WRITE_ENA                   0x0001  /* MASK_WRITE_ENA */
+#define WM8993_MASK_WRITE_ENA_MASK              0x0001  /* MASK_WRITE_ENA */
+#define WM8993_MASK_WRITE_ENA_SHIFT                  0  /* MASK_WRITE_ENA */
+#define WM8993_MASK_WRITE_ENA_WIDTH                  1  /* MASK_WRITE_ENA */
+
+/*
+ * R69 (0x45) - Bus Control 1
+ */
+#define WM8993_CLK_SYS_ENA                      0x0002  /* CLK_SYS_ENA */
+#define WM8993_CLK_SYS_ENA_MASK                 0x0002  /* CLK_SYS_ENA */
+#define WM8993_CLK_SYS_ENA_SHIFT                     1  /* CLK_SYS_ENA */
+#define WM8993_CLK_SYS_ENA_WIDTH                     1  /* CLK_SYS_ENA */
+
+/*
+ * R70 (0x46) - Write Sequencer 0
+ */
+#define WM8993_WSEQ_ENA                         0x0100  /* WSEQ_ENA */
+#define WM8993_WSEQ_ENA_MASK                    0x0100  /* WSEQ_ENA */
+#define WM8993_WSEQ_ENA_SHIFT                        8  /* WSEQ_ENA */
+#define WM8993_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM8993_WSEQ_WRITE_INDEX_MASK            0x001F  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8993_WSEQ_WRITE_INDEX_SHIFT                0  /* WSEQ_WRITE_INDEX - [4:0] */
+#define WM8993_WSEQ_WRITE_INDEX_WIDTH                5  /* WSEQ_WRITE_INDEX - [4:0] */
+
+/*
+ * R71 (0x47) - Write Sequencer 1
+ */
+#define WM8993_WSEQ_DATA_WIDTH_MASK             0x7000  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8993_WSEQ_DATA_WIDTH_SHIFT                12  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8993_WSEQ_DATA_WIDTH_WIDTH                 3  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM8993_WSEQ_DATA_START_MASK             0x0F00  /* WSEQ_DATA_START - [11:8] */
+#define WM8993_WSEQ_DATA_START_SHIFT                 8  /* WSEQ_DATA_START - [11:8] */
+#define WM8993_WSEQ_DATA_START_WIDTH                 4  /* WSEQ_DATA_START - [11:8] */
+#define WM8993_WSEQ_ADDR_MASK                   0x00FF  /* WSEQ_ADDR - [7:0] */
+#define WM8993_WSEQ_ADDR_SHIFT                       0  /* WSEQ_ADDR - [7:0] */
+#define WM8993_WSEQ_ADDR_WIDTH                       8  /* WSEQ_ADDR - [7:0] */
+
+/*
+ * R72 (0x48) - Write Sequencer 2
+ */
+#define WM8993_WSEQ_EOS                         0x4000  /* WSEQ_EOS */
+#define WM8993_WSEQ_EOS_MASK                    0x4000  /* WSEQ_EOS */
+#define WM8993_WSEQ_EOS_SHIFT                       14  /* WSEQ_EOS */
+#define WM8993_WSEQ_EOS_WIDTH                        1  /* WSEQ_EOS */
+#define WM8993_WSEQ_DELAY_MASK                  0x0F00  /* WSEQ_DELAY - [11:8] */
+#define WM8993_WSEQ_DELAY_SHIFT                      8  /* WSEQ_DELAY - [11:8] */
+#define WM8993_WSEQ_DELAY_WIDTH                      4  /* WSEQ_DELAY - [11:8] */
+#define WM8993_WSEQ_DATA_MASK                   0x00FF  /* WSEQ_DATA - [7:0] */
+#define WM8993_WSEQ_DATA_SHIFT                       0  /* WSEQ_DATA - [7:0] */
+#define WM8993_WSEQ_DATA_WIDTH                       8  /* WSEQ_DATA - [7:0] */
+
+/*
+ * R73 (0x49) - Write Sequencer 3
+ */
+#define WM8993_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM8993_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM8993_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM8993_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8993_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM8993_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM8993_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM8993_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8993_WSEQ_START_INDEX_MASK            0x003F  /* WSEQ_START_INDEX - [5:0] */
+#define WM8993_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [5:0] */
+#define WM8993_WSEQ_START_INDEX_WIDTH                6  /* WSEQ_START_INDEX - [5:0] */
+
+/*
+ * R74 (0x4A) - Write Sequencer 4
+ */
+#define WM8993_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM8993_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM8993_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM8993_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R75 (0x4B) - Write Sequencer 5
+ */
+#define WM8993_WSEQ_CURRENT_INDEX_MASK          0x003F  /* WSEQ_CURRENT_INDEX - [5:0] */
+#define WM8993_WSEQ_CURRENT_INDEX_SHIFT              0  /* WSEQ_CURRENT_INDEX - [5:0] */
+#define WM8993_WSEQ_CURRENT_INDEX_WIDTH              6  /* WSEQ_CURRENT_INDEX - [5:0] */
+
+/*
+ * R76 (0x4C) - Charge Pump 1
+ */
+#define WM8993_CP_ENA                           0x8000  /* CP_ENA */
+#define WM8993_CP_ENA_MASK                      0x8000  /* CP_ENA */
+#define WM8993_CP_ENA_SHIFT                         15  /* CP_ENA */
+#define WM8993_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R81 (0x51) - Class W 0
+ */
+#define WM8993_CP_DYN_FREQ                      0x0002  /* CP_DYN_FREQ */
+#define WM8993_CP_DYN_FREQ_MASK                 0x0002  /* CP_DYN_FREQ */
+#define WM8993_CP_DYN_FREQ_SHIFT                     1  /* CP_DYN_FREQ */
+#define WM8993_CP_DYN_FREQ_WIDTH                     1  /* CP_DYN_FREQ */
+#define WM8993_CP_DYN_V                         0x0001  /* CP_DYN_V */
+#define WM8993_CP_DYN_V_MASK                    0x0001  /* CP_DYN_V */
+#define WM8993_CP_DYN_V_SHIFT                        0  /* CP_DYN_V */
+#define WM8993_CP_DYN_V_WIDTH                        1  /* CP_DYN_V */
+
+/*
+ * R84 (0x54) - DC Servo 0
+ */
+#define WM8993_DCS_TRIG_SINGLE_1                0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8993_DCS_TRIG_SINGLE_1_MASK           0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8993_DCS_TRIG_SINGLE_1_SHIFT              13  /* DCS_TRIG_SINGLE_1 */
+#define WM8993_DCS_TRIG_SINGLE_1_WIDTH               1  /* DCS_TRIG_SINGLE_1 */
+#define WM8993_DCS_TRIG_SINGLE_0                0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8993_DCS_TRIG_SINGLE_0_MASK           0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8993_DCS_TRIG_SINGLE_0_SHIFT              12  /* DCS_TRIG_SINGLE_0 */
+#define WM8993_DCS_TRIG_SINGLE_0_WIDTH               1  /* DCS_TRIG_SINGLE_0 */
+#define WM8993_DCS_TRIG_SERIES_1                0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8993_DCS_TRIG_SERIES_1_MASK           0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8993_DCS_TRIG_SERIES_1_SHIFT               9  /* DCS_TRIG_SERIES_1 */
+#define WM8993_DCS_TRIG_SERIES_1_WIDTH               1  /* DCS_TRIG_SERIES_1 */
+#define WM8993_DCS_TRIG_SERIES_0                0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8993_DCS_TRIG_SERIES_0_MASK           0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8993_DCS_TRIG_SERIES_0_SHIFT               8  /* DCS_TRIG_SERIES_0 */
+#define WM8993_DCS_TRIG_SERIES_0_WIDTH               1  /* DCS_TRIG_SERIES_0 */
+#define WM8993_DCS_TRIG_STARTUP_1               0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8993_DCS_TRIG_STARTUP_1_MASK          0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8993_DCS_TRIG_STARTUP_1_SHIFT              5  /* DCS_TRIG_STARTUP_1 */
+#define WM8993_DCS_TRIG_STARTUP_1_WIDTH              1  /* DCS_TRIG_STARTUP_1 */
+#define WM8993_DCS_TRIG_STARTUP_0               0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8993_DCS_TRIG_STARTUP_0_MASK          0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8993_DCS_TRIG_STARTUP_0_SHIFT              4  /* DCS_TRIG_STARTUP_0 */
+#define WM8993_DCS_TRIG_STARTUP_0_WIDTH              1  /* DCS_TRIG_STARTUP_0 */
+#define WM8993_DCS_TRIG_DAC_WR_1                0x0008  /* DCS_TRIG_DAC_WR_1 */
+#define WM8993_DCS_TRIG_DAC_WR_1_MASK           0x0008  /* DCS_TRIG_DAC_WR_1 */
+#define WM8993_DCS_TRIG_DAC_WR_1_SHIFT               3  /* DCS_TRIG_DAC_WR_1 */
+#define WM8993_DCS_TRIG_DAC_WR_1_WIDTH               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8993_DCS_TRIG_DAC_WR_0                0x0004  /* DCS_TRIG_DAC_WR_0 */
+#define WM8993_DCS_TRIG_DAC_WR_0_MASK           0x0004  /* DCS_TRIG_DAC_WR_0 */
+#define WM8993_DCS_TRIG_DAC_WR_0_SHIFT               2  /* DCS_TRIG_DAC_WR_0 */
+#define WM8993_DCS_TRIG_DAC_WR_0_WIDTH               1  /* DCS_TRIG_DAC_WR_0 */
+#define WM8993_DCS_ENA_CHAN_1                   0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8993_DCS_ENA_CHAN_1_MASK              0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8993_DCS_ENA_CHAN_1_SHIFT                  1  /* DCS_ENA_CHAN_1 */
+#define WM8993_DCS_ENA_CHAN_1_WIDTH                  1  /* DCS_ENA_CHAN_1 */
+#define WM8993_DCS_ENA_CHAN_0                   0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8993_DCS_ENA_CHAN_0_MASK              0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8993_DCS_ENA_CHAN_0_SHIFT                  0  /* DCS_ENA_CHAN_0 */
+#define WM8993_DCS_ENA_CHAN_0_WIDTH                  1  /* DCS_ENA_CHAN_0 */
+
+/*
+ * R85 (0x55) - DC Servo 1
+ */
+#define WM8993_DCS_SERIES_NO_01_MASK            0x0FE0  /* DCS_SERIES_NO_01 - [11:5] */
+#define WM8993_DCS_SERIES_NO_01_SHIFT                5  /* DCS_SERIES_NO_01 - [11:5] */
+#define WM8993_DCS_SERIES_NO_01_WIDTH                7  /* DCS_SERIES_NO_01 - [11:5] */
+#define WM8993_DCS_TIMER_PERIOD_01_MASK         0x000F  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8993_DCS_TIMER_PERIOD_01_SHIFT             0  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8993_DCS_TIMER_PERIOD_01_WIDTH             4  /* DCS_TIMER_PERIOD_01 - [3:0] */
+
+/*
+ * R87 (0x57) - DC Servo 3
+ */
+#define WM8993_DCS_DAC_WR_VAL_1_MASK            0xFF00  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8993_DCS_DAC_WR_VAL_1_SHIFT                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8993_DCS_DAC_WR_VAL_1_WIDTH                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8993_DCS_DAC_WR_VAL_0_MASK            0x00FF  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8993_DCS_DAC_WR_VAL_0_SHIFT                0  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8993_DCS_DAC_WR_VAL_0_WIDTH                8  /* DCS_DAC_WR_VAL_0 - [7:0] */
+
+/*
+ * R88 (0x58) - DC Servo Readback 0
+ */
+#define WM8993_DCS_DATAPATH_BUSY                0x4000  /* DCS_DATAPATH_BUSY */
+#define WM8993_DCS_DATAPATH_BUSY_MASK           0x4000  /* DCS_DATAPATH_BUSY */
+#define WM8993_DCS_DATAPATH_BUSY_SHIFT              14  /* DCS_DATAPATH_BUSY */
+#define WM8993_DCS_DATAPATH_BUSY_WIDTH               1  /* DCS_DATAPATH_BUSY */
+#define WM8993_DCS_CHANNEL_MASK                 0x3000  /* DCS_CHANNEL - [13:12] */
+#define WM8993_DCS_CHANNEL_SHIFT                    12  /* DCS_CHANNEL - [13:12] */
+#define WM8993_DCS_CHANNEL_WIDTH                     2  /* DCS_CHANNEL - [13:12] */
+#define WM8993_DCS_CAL_COMPLETE_MASK            0x0300  /* DCS_CAL_COMPLETE - [9:8] */
+#define WM8993_DCS_CAL_COMPLETE_SHIFT                8  /* DCS_CAL_COMPLETE - [9:8] */
+#define WM8993_DCS_CAL_COMPLETE_WIDTH                2  /* DCS_CAL_COMPLETE - [9:8] */
+#define WM8993_DCS_DAC_WR_COMPLETE_MASK         0x0030  /* DCS_DAC_WR_COMPLETE - [5:4] */
+#define WM8993_DCS_DAC_WR_COMPLETE_SHIFT             4  /* DCS_DAC_WR_COMPLETE - [5:4] */
+#define WM8993_DCS_DAC_WR_COMPLETE_WIDTH             2  /* DCS_DAC_WR_COMPLETE - [5:4] */
+#define WM8993_DCS_STARTUP_COMPLETE_MASK        0x0003  /* DCS_STARTUP_COMPLETE - [1:0] */
+#define WM8993_DCS_STARTUP_COMPLETE_SHIFT            0  /* DCS_STARTUP_COMPLETE - [1:0] */
+#define WM8993_DCS_STARTUP_COMPLETE_WIDTH            2  /* DCS_STARTUP_COMPLETE - [1:0] */
+
+/*
+ * R89 (0x59) - DC Servo Readback 1
+ */
+#define WM8993_DCS_INTEG_CHAN_1_MASK            0x00FF  /* DCS_INTEG_CHAN_1 - [7:0] */
+#define WM8993_DCS_INTEG_CHAN_1_SHIFT                0  /* DCS_INTEG_CHAN_1 - [7:0] */
+#define WM8993_DCS_INTEG_CHAN_1_WIDTH                8  /* DCS_INTEG_CHAN_1 - [7:0] */
+
+/*
+ * R90 (0x5A) - DC Servo Readback 2
+ */
+#define WM8993_DCS_INTEG_CHAN_0_MASK            0x00FF  /* DCS_INTEG_CHAN_0 - [7:0] */
+#define WM8993_DCS_INTEG_CHAN_0_SHIFT                0  /* DCS_INTEG_CHAN_0 - [7:0] */
+#define WM8993_DCS_INTEG_CHAN_0_WIDTH                8  /* DCS_INTEG_CHAN_0 - [7:0] */
+
+/*
+ * R96 (0x60) - Analogue HP 0
+ */
+#define WM8993_HPOUT1_AUTO_PU                   0x0100  /* HPOUT1_AUTO_PU */
+#define WM8993_HPOUT1_AUTO_PU_MASK              0x0100  /* HPOUT1_AUTO_PU */
+#define WM8993_HPOUT1_AUTO_PU_SHIFT                  8  /* HPOUT1_AUTO_PU */
+#define WM8993_HPOUT1_AUTO_PU_WIDTH                  1  /* HPOUT1_AUTO_PU */
+#define WM8993_HPOUT1L_RMV_SHORT                0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM8993_HPOUT1L_RMV_SHORT_MASK           0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM8993_HPOUT1L_RMV_SHORT_SHIFT               7  /* HPOUT1L_RMV_SHORT */
+#define WM8993_HPOUT1L_RMV_SHORT_WIDTH               1  /* HPOUT1L_RMV_SHORT */
+#define WM8993_HPOUT1L_OUTP                     0x0040  /* HPOUT1L_OUTP */
+#define WM8993_HPOUT1L_OUTP_MASK                0x0040  /* HPOUT1L_OUTP */
+#define WM8993_HPOUT1L_OUTP_SHIFT                    6  /* HPOUT1L_OUTP */
+#define WM8993_HPOUT1L_OUTP_WIDTH                    1  /* HPOUT1L_OUTP */
+#define WM8993_HPOUT1L_DLY                      0x0020  /* HPOUT1L_DLY */
+#define WM8993_HPOUT1L_DLY_MASK                 0x0020  /* HPOUT1L_DLY */
+#define WM8993_HPOUT1L_DLY_SHIFT                     5  /* HPOUT1L_DLY */
+#define WM8993_HPOUT1L_DLY_WIDTH                     1  /* HPOUT1L_DLY */
+#define WM8993_HPOUT1R_RMV_SHORT                0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM8993_HPOUT1R_RMV_SHORT_MASK           0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM8993_HPOUT1R_RMV_SHORT_SHIFT               3  /* HPOUT1R_RMV_SHORT */
+#define WM8993_HPOUT1R_RMV_SHORT_WIDTH               1  /* HPOUT1R_RMV_SHORT */
+#define WM8993_HPOUT1R_OUTP                     0x0004  /* HPOUT1R_OUTP */
+#define WM8993_HPOUT1R_OUTP_MASK                0x0004  /* HPOUT1R_OUTP */
+#define WM8993_HPOUT1R_OUTP_SHIFT                    2  /* HPOUT1R_OUTP */
+#define WM8993_HPOUT1R_OUTP_WIDTH                    1  /* HPOUT1R_OUTP */
+#define WM8993_HPOUT1R_DLY                      0x0002  /* HPOUT1R_DLY */
+#define WM8993_HPOUT1R_DLY_MASK                 0x0002  /* HPOUT1R_DLY */
+#define WM8993_HPOUT1R_DLY_SHIFT                     1  /* HPOUT1R_DLY */
+#define WM8993_HPOUT1R_DLY_WIDTH                     1  /* HPOUT1R_DLY */
+
+/*
+ * R98 (0x62) - EQ1
+ */
+#define WM8993_EQ_ENA                           0x0001  /* EQ_ENA */
+#define WM8993_EQ_ENA_MASK                      0x0001  /* EQ_ENA */
+#define WM8993_EQ_ENA_SHIFT                          0  /* EQ_ENA */
+#define WM8993_EQ_ENA_WIDTH                          1  /* EQ_ENA */
+
+/*
+ * R99 (0x63) - EQ2
+ */
+#define WM8993_EQ_B1_GAIN_MASK                  0x001F  /* EQ_B1_GAIN - [4:0] */
+#define WM8993_EQ_B1_GAIN_SHIFT                      0  /* EQ_B1_GAIN - [4:0] */
+#define WM8993_EQ_B1_GAIN_WIDTH                      5  /* EQ_B1_GAIN - [4:0] */
+
+/*
+ * R100 (0x64) - EQ3
+ */
+#define WM8993_EQ_B2_GAIN_MASK                  0x001F  /* EQ_B2_GAIN - [4:0] */
+#define WM8993_EQ_B2_GAIN_SHIFT                      0  /* EQ_B2_GAIN - [4:0] */
+#define WM8993_EQ_B2_GAIN_WIDTH                      5  /* EQ_B2_GAIN - [4:0] */
+
+/*
+ * R101 (0x65) - EQ4
+ */
+#define WM8993_EQ_B3_GAIN_MASK                  0x001F  /* EQ_B3_GAIN - [4:0] */
+#define WM8993_EQ_B3_GAIN_SHIFT                      0  /* EQ_B3_GAIN - [4:0] */
+#define WM8993_EQ_B3_GAIN_WIDTH                      5  /* EQ_B3_GAIN - [4:0] */
+
+/*
+ * R102 (0x66) - EQ5
+ */
+#define WM8993_EQ_B4_GAIN_MASK                  0x001F  /* EQ_B4_GAIN - [4:0] */
+#define WM8993_EQ_B4_GAIN_SHIFT                      0  /* EQ_B4_GAIN - [4:0] */
+#define WM8993_EQ_B4_GAIN_WIDTH                      5  /* EQ_B4_GAIN - [4:0] */
+
+/*
+ * R103 (0x67) - EQ6
+ */
+#define WM8993_EQ_B5_GAIN_MASK                  0x001F  /* EQ_B5_GAIN - [4:0] */
+#define WM8993_EQ_B5_GAIN_SHIFT                      0  /* EQ_B5_GAIN - [4:0] */
+#define WM8993_EQ_B5_GAIN_WIDTH                      5  /* EQ_B5_GAIN - [4:0] */
+
+/*
+ * R104 (0x68) - EQ7
+ */
+#define WM8993_EQ_B1_A_MASK                     0xFFFF  /* EQ_B1_A - [15:0] */
+#define WM8993_EQ_B1_A_SHIFT                         0  /* EQ_B1_A - [15:0] */
+#define WM8993_EQ_B1_A_WIDTH                        16  /* EQ_B1_A - [15:0] */
+
+/*
+ * R105 (0x69) - EQ8
+ */
+#define WM8993_EQ_B1_B_MASK                     0xFFFF  /* EQ_B1_B - [15:0] */
+#define WM8993_EQ_B1_B_SHIFT                         0  /* EQ_B1_B - [15:0] */
+#define WM8993_EQ_B1_B_WIDTH                        16  /* EQ_B1_B - [15:0] */
+
+/*
+ * R106 (0x6A) - EQ9
+ */
+#define WM8993_EQ_B1_PG_MASK                    0xFFFF  /* EQ_B1_PG - [15:0] */
+#define WM8993_EQ_B1_PG_SHIFT                        0  /* EQ_B1_PG - [15:0] */
+#define WM8993_EQ_B1_PG_WIDTH                       16  /* EQ_B1_PG - [15:0] */
+
+/*
+ * R107 (0x6B) - EQ10
+ */
+#define WM8993_EQ_B2_A_MASK                     0xFFFF  /* EQ_B2_A - [15:0] */
+#define WM8993_EQ_B2_A_SHIFT                         0  /* EQ_B2_A - [15:0] */
+#define WM8993_EQ_B2_A_WIDTH                        16  /* EQ_B2_A - [15:0] */
+
+/*
+ * R108 (0x6C) - EQ11
+ */
+#define WM8993_EQ_B2_B_MASK                     0xFFFF  /* EQ_B2_B - [15:0] */
+#define WM8993_EQ_B2_B_SHIFT                         0  /* EQ_B2_B - [15:0] */
+#define WM8993_EQ_B2_B_WIDTH                        16  /* EQ_B2_B - [15:0] */
+
+/*
+ * R109 (0x6D) - EQ12
+ */
+#define WM8993_EQ_B2_C_MASK                     0xFFFF  /* EQ_B2_C - [15:0] */
+#define WM8993_EQ_B2_C_SHIFT                         0  /* EQ_B2_C - [15:0] */
+#define WM8993_EQ_B2_C_WIDTH                        16  /* EQ_B2_C - [15:0] */
+
+/*
+ * R110 (0x6E) - EQ13
+ */
+#define WM8993_EQ_B2_PG_MASK                    0xFFFF  /* EQ_B2_PG - [15:0] */
+#define WM8993_EQ_B2_PG_SHIFT                        0  /* EQ_B2_PG - [15:0] */
+#define WM8993_EQ_B2_PG_WIDTH                       16  /* EQ_B2_PG - [15:0] */
+
+/*
+ * R111 (0x6F) - EQ14
+ */
+#define WM8993_EQ_B3_A_MASK                     0xFFFF  /* EQ_B3_A - [15:0] */
+#define WM8993_EQ_B3_A_SHIFT                         0  /* EQ_B3_A - [15:0] */
+#define WM8993_EQ_B3_A_WIDTH                        16  /* EQ_B3_A - [15:0] */
+
+/*
+ * R112 (0x70) - EQ15
+ */
+#define WM8993_EQ_B3_B_MASK                     0xFFFF  /* EQ_B3_B - [15:0] */
+#define WM8993_EQ_B3_B_SHIFT                         0  /* EQ_B3_B - [15:0] */
+#define WM8993_EQ_B3_B_WIDTH                        16  /* EQ_B3_B - [15:0] */
+
+/*
+ * R113 (0x71) - EQ16
+ */
+#define WM8993_EQ_B3_C_MASK                     0xFFFF  /* EQ_B3_C - [15:0] */
+#define WM8993_EQ_B3_C_SHIFT                         0  /* EQ_B3_C - [15:0] */
+#define WM8993_EQ_B3_C_WIDTH                        16  /* EQ_B3_C - [15:0] */
+
+/*
+ * R114 (0x72) - EQ17
+ */
+#define WM8993_EQ_B3_PG_MASK                    0xFFFF  /* EQ_B3_PG - [15:0] */
+#define WM8993_EQ_B3_PG_SHIFT                        0  /* EQ_B3_PG - [15:0] */
+#define WM8993_EQ_B3_PG_WIDTH                       16  /* EQ_B3_PG - [15:0] */
+
+/*
+ * R115 (0x73) - EQ18
+ */
+#define WM8993_EQ_B4_A_MASK                     0xFFFF  /* EQ_B4_A - [15:0] */
+#define WM8993_EQ_B4_A_SHIFT                         0  /* EQ_B4_A - [15:0] */
+#define WM8993_EQ_B4_A_WIDTH                        16  /* EQ_B4_A - [15:0] */
+
+/*
+ * R116 (0x74) - EQ19
+ */
+#define WM8993_EQ_B4_B_MASK                     0xFFFF  /* EQ_B4_B - [15:0] */
+#define WM8993_EQ_B4_B_SHIFT                         0  /* EQ_B4_B - [15:0] */
+#define WM8993_EQ_B4_B_WIDTH                        16  /* EQ_B4_B - [15:0] */
+
+/*
+ * R117 (0x75) - EQ20
+ */
+#define WM8993_EQ_B4_C_MASK                     0xFFFF  /* EQ_B4_C - [15:0] */
+#define WM8993_EQ_B4_C_SHIFT                         0  /* EQ_B4_C - [15:0] */
+#define WM8993_EQ_B4_C_WIDTH                        16  /* EQ_B4_C - [15:0] */
+
+/*
+ * R118 (0x76) - EQ21
+ */
+#define WM8993_EQ_B4_PG_MASK                    0xFFFF  /* EQ_B4_PG - [15:0] */
+#define WM8993_EQ_B4_PG_SHIFT                        0  /* EQ_B4_PG - [15:0] */
+#define WM8993_EQ_B4_PG_WIDTH                       16  /* EQ_B4_PG - [15:0] */
+
+/*
+ * R119 (0x77) - EQ22
+ */
+#define WM8993_EQ_B5_A_MASK                     0xFFFF  /* EQ_B5_A - [15:0] */
+#define WM8993_EQ_B5_A_SHIFT                         0  /* EQ_B5_A - [15:0] */
+#define WM8993_EQ_B5_A_WIDTH                        16  /* EQ_B5_A - [15:0] */
+
+/*
+ * R120 (0x78) - EQ23
+ */
+#define WM8993_EQ_B5_B_MASK                     0xFFFF  /* EQ_B5_B - [15:0] */
+#define WM8993_EQ_B5_B_SHIFT                         0  /* EQ_B5_B - [15:0] */
+#define WM8993_EQ_B5_B_WIDTH                        16  /* EQ_B5_B - [15:0] */
+
+/*
+ * R121 (0x79) - EQ24
+ */
+#define WM8993_EQ_B5_PG_MASK                    0xFFFF  /* EQ_B5_PG - [15:0] */
+#define WM8993_EQ_B5_PG_SHIFT                        0  /* EQ_B5_PG - [15:0] */
+#define WM8993_EQ_B5_PG_WIDTH                       16  /* EQ_B5_PG - [15:0] */
+
+/*
+ * R122 (0x7A) - Digital Pulls
+ */
+#define WM8993_MCLK_PU                          0x0080  /* MCLK_PU */
+#define WM8993_MCLK_PU_MASK                     0x0080  /* MCLK_PU */
+#define WM8993_MCLK_PU_SHIFT                         7  /* MCLK_PU */
+#define WM8993_MCLK_PU_WIDTH                         1  /* MCLK_PU */
+#define WM8993_MCLK_PD                          0x0040  /* MCLK_PD */
+#define WM8993_MCLK_PD_MASK                     0x0040  /* MCLK_PD */
+#define WM8993_MCLK_PD_SHIFT                         6  /* MCLK_PD */
+#define WM8993_MCLK_PD_WIDTH                         1  /* MCLK_PD */
+#define WM8993_DACDAT_PU                        0x0020  /* DACDAT_PU */
+#define WM8993_DACDAT_PU_MASK                   0x0020  /* DACDAT_PU */
+#define WM8993_DACDAT_PU_SHIFT                       5  /* DACDAT_PU */
+#define WM8993_DACDAT_PU_WIDTH                       1  /* DACDAT_PU */
+#define WM8993_DACDAT_PD                        0x0010  /* DACDAT_PD */
+#define WM8993_DACDAT_PD_MASK                   0x0010  /* DACDAT_PD */
+#define WM8993_DACDAT_PD_SHIFT                       4  /* DACDAT_PD */
+#define WM8993_DACDAT_PD_WIDTH                       1  /* DACDAT_PD */
+#define WM8993_LRCLK_PU                         0x0008  /* LRCLK_PU */
+#define WM8993_LRCLK_PU_MASK                    0x0008  /* LRCLK_PU */
+#define WM8993_LRCLK_PU_SHIFT                        3  /* LRCLK_PU */
+#define WM8993_LRCLK_PU_WIDTH                        1  /* LRCLK_PU */
+#define WM8993_LRCLK_PD                         0x0004  /* LRCLK_PD */
+#define WM8993_LRCLK_PD_MASK                    0x0004  /* LRCLK_PD */
+#define WM8993_LRCLK_PD_SHIFT                        2  /* LRCLK_PD */
+#define WM8993_LRCLK_PD_WIDTH                        1  /* LRCLK_PD */
+#define WM8993_BCLK_PU                          0x0002  /* BCLK_PU */
+#define WM8993_BCLK_PU_MASK                     0x0002  /* BCLK_PU */
+#define WM8993_BCLK_PU_SHIFT                         1  /* BCLK_PU */
+#define WM8993_BCLK_PU_WIDTH                         1  /* BCLK_PU */
+#define WM8993_BCLK_PD                          0x0001  /* BCLK_PD */
+#define WM8993_BCLK_PD_MASK                     0x0001  /* BCLK_PD */
+#define WM8993_BCLK_PD_SHIFT                         0  /* BCLK_PD */
+#define WM8993_BCLK_PD_WIDTH                         1  /* BCLK_PD */
+
+/*
+ * R123 (0x7B) - DRC Control 1
+ */
+#define WM8993_DRC_ENA                          0x8000  /* DRC_ENA */
+#define WM8993_DRC_ENA_MASK                     0x8000  /* DRC_ENA */
+#define WM8993_DRC_ENA_SHIFT                        15  /* DRC_ENA */
+#define WM8993_DRC_ENA_WIDTH                         1  /* DRC_ENA */
+#define WM8993_DRC_DAC_PATH                     0x4000  /* DRC_DAC_PATH */
+#define WM8993_DRC_DAC_PATH_MASK                0x4000  /* DRC_DAC_PATH */
+#define WM8993_DRC_DAC_PATH_SHIFT                   14  /* DRC_DAC_PATH */
+#define WM8993_DRC_DAC_PATH_WIDTH                    1  /* DRC_DAC_PATH */
+#define WM8993_DRC_SMOOTH_ENA                   0x0800  /* DRC_SMOOTH_ENA */
+#define WM8993_DRC_SMOOTH_ENA_MASK              0x0800  /* DRC_SMOOTH_ENA */
+#define WM8993_DRC_SMOOTH_ENA_SHIFT                 11  /* DRC_SMOOTH_ENA */
+#define WM8993_DRC_SMOOTH_ENA_WIDTH                  1  /* DRC_SMOOTH_ENA */
+#define WM8993_DRC_QR_ENA                       0x0400  /* DRC_QR_ENA */
+#define WM8993_DRC_QR_ENA_MASK                  0x0400  /* DRC_QR_ENA */
+#define WM8993_DRC_QR_ENA_SHIFT                     10  /* DRC_QR_ENA */
+#define WM8993_DRC_QR_ENA_WIDTH                      1  /* DRC_QR_ENA */
+#define WM8993_DRC_ANTICLIP_ENA                 0x0200  /* DRC_ANTICLIP_ENA */
+#define WM8993_DRC_ANTICLIP_ENA_MASK            0x0200  /* DRC_ANTICLIP_ENA */
+#define WM8993_DRC_ANTICLIP_ENA_SHIFT                9  /* DRC_ANTICLIP_ENA */
+#define WM8993_DRC_ANTICLIP_ENA_WIDTH                1  /* DRC_ANTICLIP_ENA */
+#define WM8993_DRC_HYST_ENA                     0x0100  /* DRC_HYST_ENA */
+#define WM8993_DRC_HYST_ENA_MASK                0x0100  /* DRC_HYST_ENA */
+#define WM8993_DRC_HYST_ENA_SHIFT                    8  /* DRC_HYST_ENA */
+#define WM8993_DRC_HYST_ENA_WIDTH                    1  /* DRC_HYST_ENA */
+#define WM8993_DRC_THRESH_HYST_MASK             0x0030  /* DRC_THRESH_HYST - [5:4] */
+#define WM8993_DRC_THRESH_HYST_SHIFT                 4  /* DRC_THRESH_HYST - [5:4] */
+#define WM8993_DRC_THRESH_HYST_WIDTH                 2  /* DRC_THRESH_HYST - [5:4] */
+#define WM8993_DRC_MINGAIN_MASK                 0x000C  /* DRC_MINGAIN - [3:2] */
+#define WM8993_DRC_MINGAIN_SHIFT                     2  /* DRC_MINGAIN - [3:2] */
+#define WM8993_DRC_MINGAIN_WIDTH                     2  /* DRC_MINGAIN - [3:2] */
+#define WM8993_DRC_MAXGAIN_MASK                 0x0003  /* DRC_MAXGAIN - [1:0] */
+#define WM8993_DRC_MAXGAIN_SHIFT                     0  /* DRC_MAXGAIN - [1:0] */
+#define WM8993_DRC_MAXGAIN_WIDTH                     2  /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R124 (0x7C) - DRC Control 2
+ */
+#define WM8993_DRC_ATTACK_RATE_MASK             0xF000  /* DRC_ATTACK_RATE - [15:12] */
+#define WM8993_DRC_ATTACK_RATE_SHIFT                12  /* DRC_ATTACK_RATE - [15:12] */
+#define WM8993_DRC_ATTACK_RATE_WIDTH                 4  /* DRC_ATTACK_RATE - [15:12] */
+#define WM8993_DRC_DECAY_RATE_MASK              0x0F00  /* DRC_DECAY_RATE - [11:8] */
+#define WM8993_DRC_DECAY_RATE_SHIFT                  8  /* DRC_DECAY_RATE - [11:8] */
+#define WM8993_DRC_DECAY_RATE_WIDTH                  4  /* DRC_DECAY_RATE - [11:8] */
+#define WM8993_DRC_THRESH_COMP_MASK             0x00FC  /* DRC_THRESH_COMP - [7:2] */
+#define WM8993_DRC_THRESH_COMP_SHIFT                 2  /* DRC_THRESH_COMP - [7:2] */
+#define WM8993_DRC_THRESH_COMP_WIDTH                 6  /* DRC_THRESH_COMP - [7:2] */
+
+/*
+ * R125 (0x7D) - DRC Control 3
+ */
+#define WM8993_DRC_AMP_COMP_MASK                0xF800  /* DRC_AMP_COMP - [15:11] */
+#define WM8993_DRC_AMP_COMP_SHIFT                   11  /* DRC_AMP_COMP - [15:11] */
+#define WM8993_DRC_AMP_COMP_WIDTH                    5  /* DRC_AMP_COMP - [15:11] */
+#define WM8993_DRC_R0_SLOPE_COMP_MASK           0x0700  /* DRC_R0_SLOPE_COMP - [10:8] */
+#define WM8993_DRC_R0_SLOPE_COMP_SHIFT               8  /* DRC_R0_SLOPE_COMP - [10:8] */
+#define WM8993_DRC_R0_SLOPE_COMP_WIDTH               3  /* DRC_R0_SLOPE_COMP - [10:8] */
+#define WM8993_DRC_FF_DELAY                     0x0080  /* DRC_FF_DELAY */
+#define WM8993_DRC_FF_DELAY_MASK                0x0080  /* DRC_FF_DELAY */
+#define WM8993_DRC_FF_DELAY_SHIFT                    7  /* DRC_FF_DELAY */
+#define WM8993_DRC_FF_DELAY_WIDTH                    1  /* DRC_FF_DELAY */
+#define WM8993_DRC_THRESH_QR_MASK               0x000C  /* DRC_THRESH_QR - [3:2] */
+#define WM8993_DRC_THRESH_QR_SHIFT                   2  /* DRC_THRESH_QR - [3:2] */
+#define WM8993_DRC_THRESH_QR_WIDTH                   2  /* DRC_THRESH_QR - [3:2] */
+#define WM8993_DRC_RATE_QR_MASK                 0x0003  /* DRC_RATE_QR - [1:0] */
+#define WM8993_DRC_RATE_QR_SHIFT                     0  /* DRC_RATE_QR - [1:0] */
+#define WM8993_DRC_RATE_QR_WIDTH                     2  /* DRC_RATE_QR - [1:0] */
+
+/*
+ * R126 (0x7E) - DRC Control 4
+ */
+#define WM8993_DRC_R1_SLOPE_COMP_MASK           0xE000  /* DRC_R1_SLOPE_COMP - [15:13] */
+#define WM8993_DRC_R1_SLOPE_COMP_SHIFT              13  /* DRC_R1_SLOPE_COMP - [15:13] */
+#define WM8993_DRC_R1_SLOPE_COMP_WIDTH               3  /* DRC_R1_SLOPE_COMP - [15:13] */
+#define WM8993_DRC_STARTUP_GAIN_MASK            0x1F00  /* DRC_STARTUP_GAIN - [12:8] */
+#define WM8993_DRC_STARTUP_GAIN_SHIFT                8  /* DRC_STARTUP_GAIN - [12:8] */
+#define WM8993_DRC_STARTUP_GAIN_WIDTH                5  /* DRC_STARTUP_GAIN - [12:8] */
+
+#endif
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
new file mode 100644
index 0000000..14f1b0c
--- /dev/null
+++ b/sound/soc/codecs/wm8994.c
@@ -0,0 +1,4524 @@
+/*
+ * wm8994.c  --  WM8994 ALSA SoC Audio driver
+ *
+ * Copyright 2009-12 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <trace/events/asoc.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include <linux/mfd/wm8994/pdata.h>
+#include <linux/mfd/wm8994/gpio.h>
+
+#include "wm8994.h"
+#include "wm_hubs.h"
+
+#define WM1811_JACKDET_MODE_NONE  0x0000
+#define WM1811_JACKDET_MODE_JACK  0x0100
+#define WM1811_JACKDET_MODE_MIC   0x0080
+#define WM1811_JACKDET_MODE_AUDIO 0x0180
+
+#define WM8994_NUM_DRC 3
+#define WM8994_NUM_EQ  3
+
+static struct {
+	unsigned int reg;
+	unsigned int mask;
+} wm8994_vu_bits[] = {
+	{ WM8994_LEFT_LINE_INPUT_1_2_VOLUME, WM8994_IN1_VU },
+	{ WM8994_RIGHT_LINE_INPUT_1_2_VOLUME, WM8994_IN1_VU },
+	{ WM8994_LEFT_LINE_INPUT_3_4_VOLUME, WM8994_IN2_VU },
+	{ WM8994_RIGHT_LINE_INPUT_3_4_VOLUME, WM8994_IN2_VU },
+	{ WM8994_SPEAKER_VOLUME_LEFT, WM8994_SPKOUT_VU },
+	{ WM8994_SPEAKER_VOLUME_RIGHT, WM8994_SPKOUT_VU },
+	{ WM8994_LEFT_OUTPUT_VOLUME, WM8994_HPOUT1_VU },
+	{ WM8994_RIGHT_OUTPUT_VOLUME, WM8994_HPOUT1_VU },
+	{ WM8994_LEFT_OPGA_VOLUME, WM8994_MIXOUT_VU },
+	{ WM8994_RIGHT_OPGA_VOLUME, WM8994_MIXOUT_VU },
+
+	{ WM8994_AIF1_DAC1_LEFT_VOLUME, WM8994_AIF1DAC1_VU },
+	{ WM8994_AIF1_DAC1_RIGHT_VOLUME, WM8994_AIF1DAC1_VU },
+	{ WM8994_AIF1_DAC2_LEFT_VOLUME, WM8994_AIF1DAC2_VU },
+	{ WM8994_AIF1_DAC2_RIGHT_VOLUME, WM8994_AIF1DAC2_VU },
+	{ WM8994_AIF2_DAC_LEFT_VOLUME, WM8994_AIF2DAC_VU },
+	{ WM8994_AIF2_DAC_RIGHT_VOLUME, WM8994_AIF2DAC_VU },
+	{ WM8994_AIF1_ADC1_LEFT_VOLUME, WM8994_AIF1ADC1_VU },
+	{ WM8994_AIF1_ADC1_RIGHT_VOLUME, WM8994_AIF1ADC1_VU },
+	{ WM8994_AIF1_ADC2_LEFT_VOLUME, WM8994_AIF1ADC2_VU },
+	{ WM8994_AIF1_ADC2_RIGHT_VOLUME, WM8994_AIF1ADC2_VU },
+	{ WM8994_AIF2_ADC_LEFT_VOLUME, WM8994_AIF2ADC_VU },
+	{ WM8994_AIF2_ADC_RIGHT_VOLUME, WM8994_AIF1ADC2_VU },
+	{ WM8994_DAC1_LEFT_VOLUME, WM8994_DAC1_VU },
+	{ WM8994_DAC1_RIGHT_VOLUME, WM8994_DAC1_VU },
+	{ WM8994_DAC2_LEFT_VOLUME, WM8994_DAC2_VU },
+	{ WM8994_DAC2_RIGHT_VOLUME, WM8994_DAC2_VU },
+};
+
+static int wm8994_drc_base[] = {
+	WM8994_AIF1_DRC1_1,
+	WM8994_AIF1_DRC2_1,
+	WM8994_AIF2_DRC_1,
+};
+
+static int wm8994_retune_mobile_base[] = {
+	WM8994_AIF1_DAC1_EQ_GAINS_1,
+	WM8994_AIF1_DAC2_EQ_GAINS_1,
+	WM8994_AIF2_EQ_GAINS_1,
+};
+
+static const struct wm8958_micd_rate micdet_rates[] = {
+	{ 32768,       true,  1, 4 },
+	{ 32768,       false, 1, 1 },
+	{ 44100 * 256, true,  7, 10 },
+	{ 44100 * 256, false, 7, 10 },
+};
+
+static const struct wm8958_micd_rate jackdet_rates[] = {
+	{ 32768,       true,  0, 1 },
+	{ 32768,       false, 0, 1 },
+	{ 44100 * 256, true,  10, 10 },
+	{ 44100 * 256, false, 7, 8 },
+};
+
+static void wm8958_micd_set_rate(struct snd_soc_component *component)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	int best, i, sysclk, val;
+	bool idle;
+	const struct wm8958_micd_rate *rates;
+	int num_rates;
+
+	idle = !wm8994->jack_mic;
+
+	sysclk = snd_soc_component_read32(component, WM8994_CLOCKING_1);
+	if (sysclk & WM8994_SYSCLK_SRC)
+		sysclk = wm8994->aifclk[1];
+	else
+		sysclk = wm8994->aifclk[0];
+
+	if (control->pdata.micd_rates) {
+		rates = control->pdata.micd_rates;
+		num_rates = control->pdata.num_micd_rates;
+	} else if (wm8994->jackdet) {
+		rates = jackdet_rates;
+		num_rates = ARRAY_SIZE(jackdet_rates);
+	} else {
+		rates = micdet_rates;
+		num_rates = ARRAY_SIZE(micdet_rates);
+	}
+
+	best = 0;
+	for (i = 0; i < num_rates; i++) {
+		if (rates[i].idle != idle)
+			continue;
+		if (abs(rates[i].sysclk - sysclk) <
+		    abs(rates[best].sysclk - sysclk))
+			best = i;
+		else if (rates[best].idle != idle)
+			best = i;
+	}
+
+	val = rates[best].start << WM8958_MICD_BIAS_STARTTIME_SHIFT
+		| rates[best].rate << WM8958_MICD_RATE_SHIFT;
+
+	dev_dbg(component->dev, "MICD rate %d,%d for %dHz %s\n",
+		rates[best].start, rates[best].rate, sysclk,
+		idle ? "idle" : "active");
+
+	snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1,
+			    WM8958_MICD_BIAS_STARTTIME_MASK |
+			    WM8958_MICD_RATE_MASK, val);
+}
+
+static int configure_aif_clock(struct snd_soc_component *component, int aif)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	int rate;
+	int reg1 = 0;
+	int offset;
+
+	if (aif)
+		offset = 4;
+	else
+		offset = 0;
+
+	switch (wm8994->sysclk[aif]) {
+	case WM8994_SYSCLK_MCLK1:
+		rate = wm8994->mclk[0];
+		break;
+
+	case WM8994_SYSCLK_MCLK2:
+		reg1 |= 0x8;
+		rate = wm8994->mclk[1];
+		break;
+
+	case WM8994_SYSCLK_FLL1:
+		reg1 |= 0x10;
+		rate = wm8994->fll[0].out;
+		break;
+
+	case WM8994_SYSCLK_FLL2:
+		reg1 |= 0x18;
+		rate = wm8994->fll[1].out;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (rate >= 13500000) {
+		rate /= 2;
+		reg1 |= WM8994_AIF1CLK_DIV;
+
+		dev_dbg(component->dev, "Dividing AIF%d clock to %dHz\n",
+			aif + 1, rate);
+	}
+
+	wm8994->aifclk[aif] = rate;
+
+	snd_soc_component_update_bits(component, WM8994_AIF1_CLOCKING_1 + offset,
+			    WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
+			    reg1);
+
+	return 0;
+}
+
+static int configure_clock(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	int change, new;
+
+	/* Bring up the AIF clocks first */
+	configure_aif_clock(component, 0);
+	configure_aif_clock(component, 1);
+
+	/* Then switch CLK_SYS over to the higher of them; a change
+	 * can only happen as a result of a clocking change which can
+	 * only be made outside of DAPM so we can safely redo the
+	 * clocking.
+	 */
+
+	/* If they're equal it doesn't matter which is used */
+	if (wm8994->aifclk[0] == wm8994->aifclk[1]) {
+		wm8958_micd_set_rate(component);
+		return 0;
+	}
+
+	if (wm8994->aifclk[0] < wm8994->aifclk[1])
+		new = WM8994_SYSCLK_SRC;
+	else
+		new = 0;
+
+	change = snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
+				     WM8994_SYSCLK_SRC, new);
+	if (change)
+		snd_soc_dapm_sync(dapm);
+
+	wm8958_micd_set_rate(component);
+
+	return 0;
+}
+
+static int check_clk_sys(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	int reg = snd_soc_component_read32(component, WM8994_CLOCKING_1);
+	const char *clk;
+
+	/* Check what we're currently using for CLK_SYS */
+	if (reg & WM8994_SYSCLK_SRC)
+		clk = "AIF2CLK";
+	else
+		clk = "AIF1CLK";
+
+	return strcmp(source->name, clk) == 0;
+}
+
+static const char *sidetone_hpf_text[] = {
+	"2.7kHz", "1.35kHz", "675Hz", "370Hz", "180Hz", "90Hz", "45Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(sidetone_hpf,
+			    WM8994_SIDETONE, 7, sidetone_hpf_text);
+
+static const char *adc_hpf_text[] = {
+	"HiFi", "Voice 1", "Voice 2", "Voice 3"
+};
+
+static SOC_ENUM_SINGLE_DECL(aif1adc1_hpf,
+			    WM8994_AIF1_ADC1_FILTERS, 13, adc_hpf_text);
+
+static SOC_ENUM_SINGLE_DECL(aif1adc2_hpf,
+			    WM8994_AIF1_ADC2_FILTERS, 13, adc_hpf_text);
+
+static SOC_ENUM_SINGLE_DECL(aif2adc_hpf,
+			    WM8994_AIF2_ADC_FILTERS, 13, adc_hpf_text);
+
+static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(wm8994_3d_tlv, -1600, 183, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(mixin_boost_tlv, 0, 900, 0);
+
+#define WM8994_DRC_SWITCH(xname, reg, shift) \
+	SOC_SINGLE_EXT(xname, reg, shift, 1, 0, \
+		snd_soc_get_volsw, wm8994_put_drc_sw)
+
+static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	int mask, ret;
+
+	/* Can't enable both ADC and DAC paths simultaneously */
+	if (mc->shift == WM8994_AIF1DAC1_DRC_ENA_SHIFT)
+		mask = WM8994_AIF1ADC1L_DRC_ENA_MASK |
+			WM8994_AIF1ADC1R_DRC_ENA_MASK;
+	else
+		mask = WM8994_AIF1DAC1_DRC_ENA_MASK;
+
+	ret = snd_soc_component_read32(component, mc->reg);
+	if (ret < 0)
+		return ret;
+	if (ret & mask)
+		return -EINVAL;
+
+	return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+static void wm8994_set_drc(struct snd_soc_component *component, int drc)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	struct wm8994_pdata *pdata = &control->pdata;
+	int base = wm8994_drc_base[drc];
+	int cfg = wm8994->drc_cfg[drc];
+	int save, i;
+
+	/* Save any enables; the configuration should clear them. */
+	save = snd_soc_component_read32(component, base);
+	save &= WM8994_AIF1DAC1_DRC_ENA | WM8994_AIF1ADC1L_DRC_ENA |
+		WM8994_AIF1ADC1R_DRC_ENA;
+
+	for (i = 0; i < WM8994_DRC_REGS; i++)
+		snd_soc_component_update_bits(component, base + i, 0xffff,
+				    pdata->drc_cfgs[cfg].regs[i]);
+
+	snd_soc_component_update_bits(component, base, WM8994_AIF1DAC1_DRC_ENA |
+			     WM8994_AIF1ADC1L_DRC_ENA |
+			     WM8994_AIF1ADC1R_DRC_ENA, save);
+}
+
+/* Icky as hell but saves code duplication */
+static int wm8994_get_drc(const char *name)
+{
+	if (strcmp(name, "AIF1DRC1 Mode") == 0)
+		return 0;
+	if (strcmp(name, "AIF1DRC2 Mode") == 0)
+		return 1;
+	if (strcmp(name, "AIF2DRC Mode") == 0)
+		return 2;
+	return -EINVAL;
+}
+
+static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	struct wm8994_pdata *pdata = &control->pdata;
+	int drc = wm8994_get_drc(kcontrol->id.name);
+	int value = ucontrol->value.enumerated.item[0];
+
+	if (drc < 0)
+		return drc;
+
+	if (value >= pdata->num_drc_cfgs)
+		return -EINVAL;
+
+	wm8994->drc_cfg[drc] = value;
+
+	wm8994_set_drc(component, drc);
+
+	return 0;
+}
+
+static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	int drc = wm8994_get_drc(kcontrol->id.name);
+
+	if (drc < 0)
+		return drc;
+	ucontrol->value.enumerated.item[0] = wm8994->drc_cfg[drc];
+
+	return 0;
+}
+
+static void wm8994_set_retune_mobile(struct snd_soc_component *component, int block)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	struct wm8994_pdata *pdata = &control->pdata;
+	int base = wm8994_retune_mobile_base[block];
+	int iface, best, best_val, save, i, cfg;
+
+	if (!pdata || !wm8994->num_retune_mobile_texts)
+		return;
+
+	switch (block) {
+	case 0:
+	case 1:
+		iface = 0;
+		break;
+	case 2:
+		iface = 1;
+		break;
+	default:
+		return;
+	}
+
+	/* Find the version of the currently selected configuration
+	 * with the nearest sample rate. */
+	cfg = wm8994->retune_mobile_cfg[block];
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+		if (strcmp(pdata->retune_mobile_cfgs[i].name,
+			   wm8994->retune_mobile_texts[cfg]) == 0 &&
+		    abs(pdata->retune_mobile_cfgs[i].rate
+			- wm8994->dac_rates[iface]) < best_val) {
+			best = i;
+			best_val = abs(pdata->retune_mobile_cfgs[i].rate
+				       - wm8994->dac_rates[iface]);
+		}
+	}
+
+	dev_dbg(component->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
+		block,
+		pdata->retune_mobile_cfgs[best].name,
+		pdata->retune_mobile_cfgs[best].rate,
+		wm8994->dac_rates[iface]);
+
+	/* The EQ will be disabled while reconfiguring it, remember the
+	 * current configuration.
+	 */
+	save = snd_soc_component_read32(component, base);
+	save &= WM8994_AIF1DAC1_EQ_ENA;
+
+	for (i = 0; i < WM8994_EQ_REGS; i++)
+		snd_soc_component_update_bits(component, base + i, 0xffff,
+				pdata->retune_mobile_cfgs[best].regs[i]);
+
+	snd_soc_component_update_bits(component, base, WM8994_AIF1DAC1_EQ_ENA, save);
+}
+
+/* Icky as hell but saves code duplication */
+static int wm8994_get_retune_mobile_block(const char *name)
+{
+	if (strcmp(name, "AIF1.1 EQ Mode") == 0)
+		return 0;
+	if (strcmp(name, "AIF1.2 EQ Mode") == 0)
+		return 1;
+	if (strcmp(name, "AIF2 EQ Mode") == 0)
+		return 2;
+	return -EINVAL;
+}
+
+static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	struct wm8994_pdata *pdata = &control->pdata;
+	int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
+	int value = ucontrol->value.enumerated.item[0];
+
+	if (block < 0)
+		return block;
+
+	if (value >= pdata->num_retune_mobile_cfgs)
+		return -EINVAL;
+
+	wm8994->retune_mobile_cfg[block] = value;
+
+	wm8994_set_retune_mobile(component, block);
+
+	return 0;
+}
+
+static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
+
+	if (block < 0)
+		return block;
+
+	ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block];
+
+	return 0;
+}
+
+static const char *aif_chan_src_text[] = {
+	"Left", "Right"
+};
+
+static SOC_ENUM_SINGLE_DECL(aif1adcl_src,
+			    WM8994_AIF1_CONTROL_1, 15, aif_chan_src_text);
+
+static SOC_ENUM_SINGLE_DECL(aif1adcr_src,
+			    WM8994_AIF1_CONTROL_1, 14, aif_chan_src_text);
+
+static SOC_ENUM_SINGLE_DECL(aif2adcl_src,
+			    WM8994_AIF2_CONTROL_1, 15, aif_chan_src_text);
+
+static SOC_ENUM_SINGLE_DECL(aif2adcr_src,
+			    WM8994_AIF2_CONTROL_1, 14, aif_chan_src_text);
+
+static SOC_ENUM_SINGLE_DECL(aif1dacl_src,
+			    WM8994_AIF1_CONTROL_2, 15, aif_chan_src_text);
+
+static SOC_ENUM_SINGLE_DECL(aif1dacr_src,
+			    WM8994_AIF1_CONTROL_2, 14, aif_chan_src_text);
+
+static SOC_ENUM_SINGLE_DECL(aif2dacl_src,
+			    WM8994_AIF2_CONTROL_2, 15, aif_chan_src_text);
+
+static SOC_ENUM_SINGLE_DECL(aif2dacr_src,
+			    WM8994_AIF2_CONTROL_2, 14, aif_chan_src_text);
+
+static const char *osr_text[] = {
+	"Low Power", "High Performance",
+};
+
+static SOC_ENUM_SINGLE_DECL(dac_osr,
+			    WM8994_OVERSAMPLING, 0, osr_text);
+
+static SOC_ENUM_SINGLE_DECL(adc_osr,
+			    WM8994_OVERSAMPLING, 1, osr_text);
+
+static const struct snd_kcontrol_new wm8994_snd_controls[] = {
+SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
+		 WM8994_AIF1_ADC1_RIGHT_VOLUME,
+		 1, 119, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("AIF1ADC2 Volume", WM8994_AIF1_ADC2_LEFT_VOLUME,
+		 WM8994_AIF1_ADC2_RIGHT_VOLUME,
+		 1, 119, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8994_AIF2_ADC_LEFT_VOLUME,
+		 WM8994_AIF2_ADC_RIGHT_VOLUME,
+		 1, 119, 0, digital_tlv),
+
+SOC_ENUM("AIF1ADCL Source", aif1adcl_src),
+SOC_ENUM("AIF1ADCR Source", aif1adcr_src),
+SOC_ENUM("AIF2ADCL Source", aif2adcl_src),
+SOC_ENUM("AIF2ADCR Source", aif2adcr_src),
+
+SOC_ENUM("AIF1DACL Source", aif1dacl_src),
+SOC_ENUM("AIF1DACR Source", aif1dacr_src),
+SOC_ENUM("AIF2DACL Source", aif2dacl_src),
+SOC_ENUM("AIF2DACR Source", aif2dacr_src),
+
+SOC_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8994_AIF1_DAC1_LEFT_VOLUME,
+		 WM8994_AIF1_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8994_AIF1_DAC2_LEFT_VOLUME,
+		 WM8994_AIF1_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("AIF2DAC Volume", WM8994_AIF2_DAC_LEFT_VOLUME,
+		 WM8994_AIF2_DAC_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+
+SOC_SINGLE_TLV("AIF1 Boost Volume", WM8994_AIF1_CONTROL_2, 10, 3, 0, aif_tlv),
+SOC_SINGLE_TLV("AIF2 Boost Volume", WM8994_AIF2_CONTROL_2, 10, 3, 0, aif_tlv),
+
+SOC_SINGLE("AIF1DAC1 EQ Switch", WM8994_AIF1_DAC1_EQ_GAINS_1, 0, 1, 0),
+SOC_SINGLE("AIF1DAC2 EQ Switch", WM8994_AIF1_DAC2_EQ_GAINS_1, 0, 1, 0),
+SOC_SINGLE("AIF2 EQ Switch", WM8994_AIF2_EQ_GAINS_1, 0, 1, 0),
+
+WM8994_DRC_SWITCH("AIF1DAC1 DRC Switch", WM8994_AIF1_DRC1_1, 2),
+WM8994_DRC_SWITCH("AIF1ADC1L DRC Switch", WM8994_AIF1_DRC1_1, 1),
+WM8994_DRC_SWITCH("AIF1ADC1R DRC Switch", WM8994_AIF1_DRC1_1, 0),
+
+WM8994_DRC_SWITCH("AIF1DAC2 DRC Switch", WM8994_AIF1_DRC2_1, 2),
+WM8994_DRC_SWITCH("AIF1ADC2L DRC Switch", WM8994_AIF1_DRC2_1, 1),
+WM8994_DRC_SWITCH("AIF1ADC2R DRC Switch", WM8994_AIF1_DRC2_1, 0),
+
+WM8994_DRC_SWITCH("AIF2DAC DRC Switch", WM8994_AIF2_DRC_1, 2),
+WM8994_DRC_SWITCH("AIF2ADCL DRC Switch", WM8994_AIF2_DRC_1, 1),
+WM8994_DRC_SWITCH("AIF2ADCR DRC Switch", WM8994_AIF2_DRC_1, 0),
+
+SOC_SINGLE_TLV("DAC1 Right Sidetone Volume", WM8994_DAC1_MIXER_VOLUMES,
+	       5, 12, 0, st_tlv),
+SOC_SINGLE_TLV("DAC1 Left Sidetone Volume", WM8994_DAC1_MIXER_VOLUMES,
+	       0, 12, 0, st_tlv),
+SOC_SINGLE_TLV("DAC2 Right Sidetone Volume", WM8994_DAC2_MIXER_VOLUMES,
+	       5, 12, 0, st_tlv),
+SOC_SINGLE_TLV("DAC2 Left Sidetone Volume", WM8994_DAC2_MIXER_VOLUMES,
+	       0, 12, 0, st_tlv),
+SOC_ENUM("Sidetone HPF Mux", sidetone_hpf),
+SOC_SINGLE("Sidetone HPF Switch", WM8994_SIDETONE, 6, 1, 0),
+
+SOC_ENUM("AIF1ADC1 HPF Mode", aif1adc1_hpf),
+SOC_DOUBLE("AIF1ADC1 HPF Switch", WM8994_AIF1_ADC1_FILTERS, 12, 11, 1, 0),
+
+SOC_ENUM("AIF1ADC2 HPF Mode", aif1adc2_hpf),
+SOC_DOUBLE("AIF1ADC2 HPF Switch", WM8994_AIF1_ADC2_FILTERS, 12, 11, 1, 0),
+
+SOC_ENUM("AIF2ADC HPF Mode", aif2adc_hpf),
+SOC_DOUBLE("AIF2ADC HPF Switch", WM8994_AIF2_ADC_FILTERS, 12, 11, 1, 0),
+
+SOC_ENUM("ADC OSR", adc_osr),
+SOC_ENUM("DAC OSR", dac_osr),
+
+SOC_DOUBLE_R_TLV("DAC1 Volume", WM8994_DAC1_LEFT_VOLUME,
+		 WM8994_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+SOC_DOUBLE_R("DAC1 Switch", WM8994_DAC1_LEFT_VOLUME,
+	     WM8994_DAC1_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DAC2 Volume", WM8994_DAC2_LEFT_VOLUME,
+		 WM8994_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+SOC_DOUBLE_R("DAC2 Switch", WM8994_DAC2_LEFT_VOLUME,
+	     WM8994_DAC2_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_SINGLE_TLV("SPKL DAC2 Volume", WM8994_SPKMIXL_ATTENUATION,
+	       6, 1, 1, wm_hubs_spkmix_tlv),
+SOC_SINGLE_TLV("SPKL DAC1 Volume", WM8994_SPKMIXL_ATTENUATION,
+	       2, 1, 1, wm_hubs_spkmix_tlv),
+
+SOC_SINGLE_TLV("SPKR DAC2 Volume", WM8994_SPKMIXR_ATTENUATION,
+	       6, 1, 1, wm_hubs_spkmix_tlv),
+SOC_SINGLE_TLV("SPKR DAC1 Volume", WM8994_SPKMIXR_ATTENUATION,
+	       2, 1, 1, wm_hubs_spkmix_tlv),
+
+SOC_SINGLE_TLV("AIF1DAC1 3D Stereo Volume", WM8994_AIF1_DAC1_FILTERS_2,
+	       10, 15, 0, wm8994_3d_tlv),
+SOC_SINGLE("AIF1DAC1 3D Stereo Switch", WM8994_AIF1_DAC1_FILTERS_2,
+	   8, 1, 0),
+SOC_SINGLE_TLV("AIF1DAC2 3D Stereo Volume", WM8994_AIF1_DAC2_FILTERS_2,
+	       10, 15, 0, wm8994_3d_tlv),
+SOC_SINGLE("AIF1DAC2 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2,
+	   8, 1, 0),
+SOC_SINGLE_TLV("AIF2DAC 3D Stereo Volume", WM8994_AIF2_DAC_FILTERS_2,
+	       10, 15, 0, wm8994_3d_tlv),
+SOC_SINGLE("AIF2DAC 3D Stereo Switch", WM8994_AIF2_DAC_FILTERS_2,
+	   8, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8994_eq_controls[] = {
+SOC_SINGLE_TLV("AIF1DAC1 EQ1 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC1 EQ2 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 6, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC1 EQ3 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 1, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC1 EQ4 Volume", WM8994_AIF1_DAC1_EQ_GAINS_2, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC1 EQ5 Volume", WM8994_AIF1_DAC1_EQ_GAINS_2, 6, 31, 0,
+	       eq_tlv),
+
+SOC_SINGLE_TLV("AIF1DAC2 EQ1 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC2 EQ2 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 6, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC2 EQ3 Volume", WM8994_AIF1_DAC2_EQ_GAINS_1, 1, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC2 EQ4 Volume", WM8994_AIF1_DAC2_EQ_GAINS_2, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("AIF1DAC2 EQ5 Volume", WM8994_AIF1_DAC2_EQ_GAINS_2, 6, 31, 0,
+	       eq_tlv),
+
+SOC_SINGLE_TLV("AIF2 EQ1 Volume", WM8994_AIF2_EQ_GAINS_1, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("AIF2 EQ2 Volume", WM8994_AIF2_EQ_GAINS_1, 6, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("AIF2 EQ3 Volume", WM8994_AIF2_EQ_GAINS_1, 1, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("AIF2 EQ4 Volume", WM8994_AIF2_EQ_GAINS_2, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0,
+	       eq_tlv),
+};
+
+static const struct snd_kcontrol_new wm8994_drc_controls[] = {
+SND_SOC_BYTES_MASK("AIF1.1 DRC", WM8994_AIF1_DRC1_1, 5,
+		   WM8994_AIF1DAC1_DRC_ENA | WM8994_AIF1ADC1L_DRC_ENA |
+		   WM8994_AIF1ADC1R_DRC_ENA),
+SND_SOC_BYTES_MASK("AIF1.2 DRC", WM8994_AIF1_DRC2_1, 5,
+		   WM8994_AIF1DAC2_DRC_ENA | WM8994_AIF1ADC2L_DRC_ENA |
+		   WM8994_AIF1ADC2R_DRC_ENA),
+SND_SOC_BYTES_MASK("AIF2 DRC", WM8994_AIF2_DRC_1, 5,
+		   WM8994_AIF2DAC_DRC_ENA | WM8994_AIF2ADCL_DRC_ENA |
+		   WM8994_AIF2ADCR_DRC_ENA),
+};
+
+static const char *wm8958_ng_text[] = {
+	"30ms", "125ms", "250ms", "500ms",
+};
+
+static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac1_ng_hold,
+			    WM8958_AIF1_DAC1_NOISE_GATE,
+			    WM8958_AIF1DAC1_NG_THR_SHIFT,
+			    wm8958_ng_text);
+
+static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac2_ng_hold,
+			    WM8958_AIF1_DAC2_NOISE_GATE,
+			    WM8958_AIF1DAC2_NG_THR_SHIFT,
+			    wm8958_ng_text);
+
+static SOC_ENUM_SINGLE_DECL(wm8958_aif2dac_ng_hold,
+			    WM8958_AIF2_DAC_NOISE_GATE,
+			    WM8958_AIF2DAC_NG_THR_SHIFT,
+			    wm8958_ng_text);
+
+static const struct snd_kcontrol_new wm8958_snd_controls[] = {
+SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv),
+
+SOC_SINGLE("AIF1DAC1 Noise Gate Switch", WM8958_AIF1_DAC1_NOISE_GATE,
+	   WM8958_AIF1DAC1_NG_ENA_SHIFT, 1, 0),
+SOC_ENUM("AIF1DAC1 Noise Gate Hold Time", wm8958_aif1dac1_ng_hold),
+SOC_SINGLE_TLV("AIF1DAC1 Noise Gate Threshold Volume",
+	       WM8958_AIF1_DAC1_NOISE_GATE, WM8958_AIF1DAC1_NG_THR_SHIFT,
+	       7, 1, ng_tlv),
+
+SOC_SINGLE("AIF1DAC2 Noise Gate Switch", WM8958_AIF1_DAC2_NOISE_GATE,
+	   WM8958_AIF1DAC2_NG_ENA_SHIFT, 1, 0),
+SOC_ENUM("AIF1DAC2 Noise Gate Hold Time", wm8958_aif1dac2_ng_hold),
+SOC_SINGLE_TLV("AIF1DAC2 Noise Gate Threshold Volume",
+	       WM8958_AIF1_DAC2_NOISE_GATE, WM8958_AIF1DAC2_NG_THR_SHIFT,
+	       7, 1, ng_tlv),
+
+SOC_SINGLE("AIF2DAC Noise Gate Switch", WM8958_AIF2_DAC_NOISE_GATE,
+	   WM8958_AIF2DAC_NG_ENA_SHIFT, 1, 0),
+SOC_ENUM("AIF2DAC Noise Gate Hold Time", wm8958_aif2dac_ng_hold),
+SOC_SINGLE_TLV("AIF2DAC Noise Gate Threshold Volume",
+	       WM8958_AIF2_DAC_NOISE_GATE, WM8958_AIF2DAC_NG_THR_SHIFT,
+	       7, 1, ng_tlv),
+};
+
+static const struct snd_kcontrol_new wm1811_snd_controls[] = {
+SOC_SINGLE_TLV("MIXINL IN1LP Boost Volume", WM8994_INPUT_MIXER_1, 7, 1, 0,
+	       mixin_boost_tlv),
+SOC_SINGLE_TLV("MIXINL IN1RP Boost Volume", WM8994_INPUT_MIXER_1, 8, 1, 0,
+	       mixin_boost_tlv),
+};
+
+/* We run all mode setting through a function to enforce audio mode */
+static void wm1811_jackdet_set_mode(struct snd_soc_component *component, u16 mode)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	if (!wm8994->jackdet || !wm8994->micdet[0].jack)
+		return;
+
+	if (wm8994->active_refcount)
+		mode = WM1811_JACKDET_MODE_AUDIO;
+
+	if (mode == wm8994->jackdet_mode)
+		return;
+
+	wm8994->jackdet_mode = mode;
+
+	/* Always use audio mode to detect while the system is active */
+	if (mode != WM1811_JACKDET_MODE_NONE)
+		mode = WM1811_JACKDET_MODE_AUDIO;
+
+	snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
+			    WM1811_JACKDET_MODE_MASK, mode);
+}
+
+static void active_reference(struct snd_soc_component *component)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	mutex_lock(&wm8994->accdet_lock);
+
+	wm8994->active_refcount++;
+
+	dev_dbg(component->dev, "Active refcount incremented, now %d\n",
+		wm8994->active_refcount);
+
+	/* If we're using jack detection go into audio mode */
+	wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_AUDIO);
+
+	mutex_unlock(&wm8994->accdet_lock);
+}
+
+static void active_dereference(struct snd_soc_component *component)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	u16 mode;
+
+	mutex_lock(&wm8994->accdet_lock);
+
+	wm8994->active_refcount--;
+
+	dev_dbg(component->dev, "Active refcount decremented, now %d\n",
+		wm8994->active_refcount);
+
+	if (wm8994->active_refcount == 0) {
+		/* Go into appropriate detection only mode */
+		if (wm8994->jack_mic || wm8994->mic_detecting)
+			mode = WM1811_JACKDET_MODE_MIC;
+		else
+			mode = WM1811_JACKDET_MODE_JACK;
+
+		wm1811_jackdet_set_mode(component, mode);
+	}
+
+	mutex_unlock(&wm8994->accdet_lock);
+}
+
+static int clk_sys_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		return configure_clock(component);
+
+	case SND_SOC_DAPM_POST_PMU:
+		/*
+		 * JACKDET won't run until we start the clock and it
+		 * only reports deltas, make sure we notify the state
+		 * up the stack on startup.  Use a *very* generous
+		 * timeout for paranoia, there's no urgency and we
+		 * don't want false reports.
+		 */
+		if (wm8994->jackdet && !wm8994->clk_has_run) {
+			queue_delayed_work(system_power_efficient_wq,
+					   &wm8994->jackdet_bootstrap,
+					   msecs_to_jiffies(1000));
+			wm8994->clk_has_run = true;
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		configure_clock(component);
+		break;
+	}
+
+	return 0;
+}
+
+static void vmid_reference(struct snd_soc_component *component)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	pm_runtime_get_sync(component->dev);
+
+	wm8994->vmid_refcount++;
+
+	dev_dbg(component->dev, "Referencing VMID, refcount is now %d\n",
+		wm8994->vmid_refcount);
+
+	if (wm8994->vmid_refcount == 1) {
+		snd_soc_component_update_bits(component, WM8994_ANTIPOP_1,
+				    WM8994_LINEOUT1_DISCH |
+				    WM8994_LINEOUT2_DISCH, 0);
+
+		wm_hubs_vmid_ena(component);
+
+		switch (wm8994->vmid_mode) {
+		default:
+			WARN_ON(NULL == "Invalid VMID mode");
+			/* fall through */
+		case WM8994_VMID_NORMAL:
+			/* Startup bias, VMID ramp & buffer */
+			snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
+					    WM8994_BIAS_SRC |
+					    WM8994_VMID_DISCH |
+					    WM8994_STARTUP_BIAS_ENA |
+					    WM8994_VMID_BUF_ENA |
+					    WM8994_VMID_RAMP_MASK,
+					    WM8994_BIAS_SRC |
+					    WM8994_STARTUP_BIAS_ENA |
+					    WM8994_VMID_BUF_ENA |
+					    (0x2 << WM8994_VMID_RAMP_SHIFT));
+
+			/* Main bias enable, VMID=2x40k */
+			snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_1,
+					    WM8994_BIAS_ENA |
+					    WM8994_VMID_SEL_MASK,
+					    WM8994_BIAS_ENA | 0x2);
+
+			msleep(300);
+
+			snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
+					    WM8994_VMID_RAMP_MASK |
+					    WM8994_BIAS_SRC,
+					    0);
+			break;
+
+		case WM8994_VMID_FORCE:
+			/* Startup bias, slow VMID ramp & buffer */
+			snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
+					    WM8994_BIAS_SRC |
+					    WM8994_VMID_DISCH |
+					    WM8994_STARTUP_BIAS_ENA |
+					    WM8994_VMID_BUF_ENA |
+					    WM8994_VMID_RAMP_MASK,
+					    WM8994_BIAS_SRC |
+					    WM8994_STARTUP_BIAS_ENA |
+					    WM8994_VMID_BUF_ENA |
+					    (0x2 << WM8994_VMID_RAMP_SHIFT));
+
+			/* Main bias enable, VMID=2x40k */
+			snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_1,
+					    WM8994_BIAS_ENA |
+					    WM8994_VMID_SEL_MASK,
+					    WM8994_BIAS_ENA | 0x2);
+
+			msleep(400);
+
+			snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
+					    WM8994_VMID_RAMP_MASK |
+					    WM8994_BIAS_SRC,
+					    0);
+			break;
+		}
+	}
+}
+
+static void vmid_dereference(struct snd_soc_component *component)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	wm8994->vmid_refcount--;
+
+	dev_dbg(component->dev, "Dereferencing VMID, refcount is now %d\n",
+		wm8994->vmid_refcount);
+
+	if (wm8994->vmid_refcount == 0) {
+		if (wm8994->hubs.lineout1_se)
+			snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_3,
+					    WM8994_LINEOUT1N_ENA |
+					    WM8994_LINEOUT1P_ENA,
+					    WM8994_LINEOUT1N_ENA |
+					    WM8994_LINEOUT1P_ENA);
+
+		if (wm8994->hubs.lineout2_se)
+			snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_3,
+					    WM8994_LINEOUT2N_ENA |
+					    WM8994_LINEOUT2P_ENA,
+					    WM8994_LINEOUT2N_ENA |
+					    WM8994_LINEOUT2P_ENA);
+
+		/* Start discharging VMID */
+		snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
+				    WM8994_BIAS_SRC |
+				    WM8994_VMID_DISCH,
+				    WM8994_BIAS_SRC |
+				    WM8994_VMID_DISCH);
+
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_1,
+				    WM8994_VMID_SEL_MASK, 0);
+
+		msleep(400);
+
+		/* Active discharge */
+		snd_soc_component_update_bits(component, WM8994_ANTIPOP_1,
+				    WM8994_LINEOUT1_DISCH |
+				    WM8994_LINEOUT2_DISCH,
+				    WM8994_LINEOUT1_DISCH |
+				    WM8994_LINEOUT2_DISCH);
+
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_3,
+				    WM8994_LINEOUT1N_ENA |
+				    WM8994_LINEOUT1P_ENA |
+				    WM8994_LINEOUT2N_ENA |
+				    WM8994_LINEOUT2P_ENA, 0);
+
+		/* Switch off startup biases */
+		snd_soc_component_update_bits(component, WM8994_ANTIPOP_2,
+				    WM8994_BIAS_SRC |
+				    WM8994_STARTUP_BIAS_ENA |
+				    WM8994_VMID_BUF_ENA |
+				    WM8994_VMID_RAMP_MASK, 0);
+
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_1,
+				    WM8994_VMID_SEL_MASK, 0);
+	}
+
+	pm_runtime_put(component->dev);
+}
+
+static int vmid_event(struct snd_soc_dapm_widget *w,
+		      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		vmid_reference(component);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		vmid_dereference(component);
+		break;
+	}
+
+	return 0;
+}
+
+static bool wm8994_check_class_w_digital(struct snd_soc_component *component)
+{
+	int source = 0;  /* GCC flow analysis can't track enable */
+	int reg, reg_r;
+
+	/* We also need the same AIF source for L/R and only one path */
+	reg = snd_soc_component_read32(component, WM8994_DAC1_LEFT_MIXER_ROUTING);
+	switch (reg) {
+	case WM8994_AIF2DACL_TO_DAC1L:
+		dev_vdbg(component->dev, "Class W source AIF2DAC\n");
+		source = 2 << WM8994_CP_DYN_SRC_SEL_SHIFT;
+		break;
+	case WM8994_AIF1DAC2L_TO_DAC1L:
+		dev_vdbg(component->dev, "Class W source AIF1DAC2\n");
+		source = 1 << WM8994_CP_DYN_SRC_SEL_SHIFT;
+		break;
+	case WM8994_AIF1DAC1L_TO_DAC1L:
+		dev_vdbg(component->dev, "Class W source AIF1DAC1\n");
+		source = 0 << WM8994_CP_DYN_SRC_SEL_SHIFT;
+		break;
+	default:
+		dev_vdbg(component->dev, "DAC mixer setting: %x\n", reg);
+		return false;
+	}
+
+	reg_r = snd_soc_component_read32(component, WM8994_DAC1_RIGHT_MIXER_ROUTING);
+	if (reg_r != reg) {
+		dev_vdbg(component->dev, "Left and right DAC mixers different\n");
+		return false;
+	}
+
+	/* Set the source up */
+	snd_soc_component_update_bits(component, WM8994_CLASS_W_1,
+			    WM8994_CP_DYN_SRC_SEL_MASK, source);
+
+	return true;
+}
+
+static int aif1clk_ev(struct snd_soc_dapm_widget *w,
+		      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA;
+	int i;
+	int dac;
+	int adc;
+	int val;
+
+	switch (control->type) {
+	case WM8994:
+	case WM8958:
+		mask |= WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA;
+		break;
+	default:
+		break;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Don't enable timeslot 2 if not in use */
+		if (wm8994->channels[0] <= 2)
+			mask &= ~(WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
+
+		val = snd_soc_component_read32(component, WM8994_AIF1_CONTROL_1);
+		if ((val & WM8994_AIF1ADCL_SRC) &&
+		    (val & WM8994_AIF1ADCR_SRC))
+			adc = WM8994_AIF1ADC1R_ENA | WM8994_AIF1ADC2R_ENA;
+		else if (!(val & WM8994_AIF1ADCL_SRC) &&
+			 !(val & WM8994_AIF1ADCR_SRC))
+			adc = WM8994_AIF1ADC1L_ENA | WM8994_AIF1ADC2L_ENA;
+		else
+			adc = WM8994_AIF1ADC1R_ENA | WM8994_AIF1ADC2R_ENA |
+				WM8994_AIF1ADC1L_ENA | WM8994_AIF1ADC2L_ENA;
+
+		val = snd_soc_component_read32(component, WM8994_AIF1_CONTROL_2);
+		if ((val & WM8994_AIF1DACL_SRC) &&
+		    (val & WM8994_AIF1DACR_SRC))
+			dac = WM8994_AIF1DAC1R_ENA | WM8994_AIF1DAC2R_ENA;
+		else if (!(val & WM8994_AIF1DACL_SRC) &&
+			 !(val & WM8994_AIF1DACR_SRC))
+			dac = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC2L_ENA;
+		else
+			dac = WM8994_AIF1DAC1R_ENA | WM8994_AIF1DAC2R_ENA |
+				WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC2L_ENA;
+
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
+				    mask, adc);
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
+				    mask, dac);
+		snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
+				    WM8994_AIF1DSPCLK_ENA |
+				    WM8994_SYSDSPCLK_ENA,
+				    WM8994_AIF1DSPCLK_ENA |
+				    WM8994_SYSDSPCLK_ENA);
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4, mask,
+				    WM8994_AIF1ADC1R_ENA |
+				    WM8994_AIF1ADC1L_ENA |
+				    WM8994_AIF1ADC2R_ENA |
+				    WM8994_AIF1ADC2L_ENA);
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5, mask,
+				    WM8994_AIF1DAC1R_ENA |
+				    WM8994_AIF1DAC1L_ENA |
+				    WM8994_AIF1DAC2R_ENA |
+				    WM8994_AIF1DAC2L_ENA);
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		for (i = 0; i < ARRAY_SIZE(wm8994_vu_bits); i++)
+			snd_soc_component_write(component, wm8994_vu_bits[i].reg,
+				      snd_soc_component_read32(component,
+						   wm8994_vu_bits[i].reg));
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
+				    mask, 0);
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
+				    mask, 0);
+
+		val = snd_soc_component_read32(component, WM8994_CLOCKING_1);
+		if (val & WM8994_AIF2DSPCLK_ENA)
+			val = WM8994_SYSDSPCLK_ENA;
+		else
+			val = 0;
+		snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
+				    WM8994_SYSDSPCLK_ENA |
+				    WM8994_AIF1DSPCLK_ENA, val);
+		break;
+	}
+
+	return 0;
+}
+
+static int aif2clk_ev(struct snd_soc_dapm_widget *w,
+		      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	int i;
+	int dac;
+	int adc;
+	int val;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		val = snd_soc_component_read32(component, WM8994_AIF2_CONTROL_1);
+		if ((val & WM8994_AIF2ADCL_SRC) &&
+		    (val & WM8994_AIF2ADCR_SRC))
+			adc = WM8994_AIF2ADCR_ENA;
+		else if (!(val & WM8994_AIF2ADCL_SRC) &&
+			 !(val & WM8994_AIF2ADCR_SRC))
+			adc = WM8994_AIF2ADCL_ENA;
+		else
+			adc = WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA;
+
+
+		val = snd_soc_component_read32(component, WM8994_AIF2_CONTROL_2);
+		if ((val & WM8994_AIF2DACL_SRC) &&
+		    (val & WM8994_AIF2DACR_SRC))
+			dac = WM8994_AIF2DACR_ENA;
+		else if (!(val & WM8994_AIF2DACL_SRC) &&
+			 !(val & WM8994_AIF2DACR_SRC))
+			dac = WM8994_AIF2DACL_ENA;
+		else
+			dac = WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA;
+
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
+				    WM8994_AIF2ADCL_ENA |
+				    WM8994_AIF2ADCR_ENA, adc);
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
+				    WM8994_AIF2DACL_ENA |
+				    WM8994_AIF2DACR_ENA, dac);
+		snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
+				    WM8994_AIF2DSPCLK_ENA |
+				    WM8994_SYSDSPCLK_ENA,
+				    WM8994_AIF2DSPCLK_ENA |
+				    WM8994_SYSDSPCLK_ENA);
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
+				    WM8994_AIF2ADCL_ENA |
+				    WM8994_AIF2ADCR_ENA,
+				    WM8994_AIF2ADCL_ENA |
+				    WM8994_AIF2ADCR_ENA);
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
+				    WM8994_AIF2DACL_ENA |
+				    WM8994_AIF2DACR_ENA,
+				    WM8994_AIF2DACL_ENA |
+				    WM8994_AIF2DACR_ENA);
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		for (i = 0; i < ARRAY_SIZE(wm8994_vu_bits); i++)
+			snd_soc_component_write(component, wm8994_vu_bits[i].reg,
+				      snd_soc_component_read32(component,
+						   wm8994_vu_bits[i].reg));
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
+				    WM8994_AIF2DACL_ENA |
+				    WM8994_AIF2DACR_ENA, 0);
+		snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_4,
+				    WM8994_AIF2ADCL_ENA |
+				    WM8994_AIF2ADCR_ENA, 0);
+
+		val = snd_soc_component_read32(component, WM8994_CLOCKING_1);
+		if (val & WM8994_AIF1DSPCLK_ENA)
+			val = WM8994_SYSDSPCLK_ENA;
+		else
+			val = 0;
+		snd_soc_component_update_bits(component, WM8994_CLOCKING_1,
+				    WM8994_SYSDSPCLK_ENA |
+				    WM8994_AIF2DSPCLK_ENA, val);
+		break;
+	}
+
+	return 0;
+}
+
+static int aif1clk_late_ev(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wm8994->aif1clk_enable = 1;
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wm8994->aif1clk_disable = 1;
+		break;
+	}
+
+	return 0;
+}
+
+static int aif2clk_late_ev(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wm8994->aif2clk_enable = 1;
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wm8994->aif2clk_disable = 1;
+		break;
+	}
+
+	return 0;
+}
+
+static int late_enable_ev(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (wm8994->aif1clk_enable) {
+			aif1clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMU);
+			snd_soc_component_update_bits(component, WM8994_AIF1_CLOCKING_1,
+					    WM8994_AIF1CLK_ENA_MASK,
+					    WM8994_AIF1CLK_ENA);
+			aif1clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMU);
+			wm8994->aif1clk_enable = 0;
+		}
+		if (wm8994->aif2clk_enable) {
+			aif2clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMU);
+			snd_soc_component_update_bits(component, WM8994_AIF2_CLOCKING_1,
+					    WM8994_AIF2CLK_ENA_MASK,
+					    WM8994_AIF2CLK_ENA);
+			aif2clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMU);
+			wm8994->aif2clk_enable = 0;
+		}
+		break;
+	}
+
+	/* We may also have postponed startup of DSP, handle that. */
+	wm8958_aif_ev(w, kcontrol, event);
+
+	return 0;
+}
+
+static int late_disable_ev(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMD:
+		if (wm8994->aif1clk_disable) {
+			aif1clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMD);
+			snd_soc_component_update_bits(component, WM8994_AIF1_CLOCKING_1,
+					    WM8994_AIF1CLK_ENA_MASK, 0);
+			aif1clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMD);
+			wm8994->aif1clk_disable = 0;
+		}
+		if (wm8994->aif2clk_disable) {
+			aif2clk_ev(w, kcontrol, SND_SOC_DAPM_PRE_PMD);
+			snd_soc_component_update_bits(component, WM8994_AIF2_CLOCKING_1,
+					    WM8994_AIF2CLK_ENA_MASK, 0);
+			aif2clk_ev(w, kcontrol, SND_SOC_DAPM_POST_PMD);
+			wm8994->aif2clk_disable = 0;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int adc_mux_ev(struct snd_soc_dapm_widget *w,
+		      struct snd_kcontrol *kcontrol, int event)
+{
+	late_enable_ev(w, kcontrol, event);
+	return 0;
+}
+
+static int micbias_ev(struct snd_soc_dapm_widget *w,
+		      struct snd_kcontrol *kcontrol, int event)
+{
+	late_enable_ev(w, kcontrol, event);
+	return 0;
+}
+
+static int dac_ev(struct snd_soc_dapm_widget *w,
+		  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	unsigned int mask = 1 << w->shift;
+
+	snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_5,
+			    mask, mask);
+	return 0;
+}
+
+static const char *adc_mux_text[] = {
+	"ADC",
+	"DMIC",
+};
+
+static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text);
+
+static const struct snd_kcontrol_new adcl_mux =
+	SOC_DAPM_ENUM("ADCL Mux", adc_enum);
+
+static const struct snd_kcontrol_new adcr_mux =
+	SOC_DAPM_ENUM("ADCR Mux", adc_enum);
+
+static const struct snd_kcontrol_new left_speaker_mixer[] = {
+SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 9, 1, 0),
+SOC_DAPM_SINGLE("Input Switch", WM8994_SPEAKER_MIXER, 7, 1, 0),
+SOC_DAPM_SINGLE("IN1LP Switch", WM8994_SPEAKER_MIXER, 5, 1, 0),
+SOC_DAPM_SINGLE("Output Switch", WM8994_SPEAKER_MIXER, 3, 1, 0),
+SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_speaker_mixer[] = {
+SOC_DAPM_SINGLE("DAC2 Switch", WM8994_SPEAKER_MIXER, 8, 1, 0),
+SOC_DAPM_SINGLE("Input Switch", WM8994_SPEAKER_MIXER, 6, 1, 0),
+SOC_DAPM_SINGLE("IN1RP Switch", WM8994_SPEAKER_MIXER, 4, 1, 0),
+SOC_DAPM_SINGLE("Output Switch", WM8994_SPEAKER_MIXER, 2, 1, 0),
+SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 0, 1, 0),
+};
+
+/* Debugging; dump chip status after DAPM transitions */
+static int post_ev(struct snd_soc_dapm_widget *w,
+	    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	dev_dbg(component->dev, "SRC status: %x\n",
+		snd_soc_component_read32(component,
+			     WM8994_RATE_STATUS));
+	return 0;
+}
+
+static const struct snd_kcontrol_new aif1adc1l_mix[] = {
+SOC_DAPM_SINGLE("ADC/DMIC Switch", WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif1adc1r_mix[] = {
+SOC_DAPM_SINGLE("ADC/DMIC Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif1adc2l_mix[] = {
+SOC_DAPM_SINGLE("DMIC Switch", WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif1adc2r_mix[] = {
+SOC_DAPM_SINGLE("DMIC Switch", WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif2dac2l_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
+		5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
+		4, 1, 0),
+SOC_DAPM_SINGLE("AIF2 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
+		2, 1, 0),
+SOC_DAPM_SINGLE("AIF1.2 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif2dac2r_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
+		5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
+		4, 1, 0),
+SOC_DAPM_SINGLE("AIF2 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
+		2, 1, 0),
+SOC_DAPM_SINGLE("AIF1.2 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+#define WM8994_CLASS_W_SWITCH(xname, reg, shift, max, invert) \
+	SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
+		snd_soc_dapm_get_volsw, wm8994_put_class_w)
+
+static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	int ret;
+
+	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+
+	wm_hubs_update_class_w(component);
+
+	return ret;
+}
+
+static const struct snd_kcontrol_new dac1l_mix[] = {
+WM8994_CLASS_W_SWITCH("Right Sidetone Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
+		      5, 1, 0),
+WM8994_CLASS_W_SWITCH("Left Sidetone Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
+		      4, 1, 0),
+WM8994_CLASS_W_SWITCH("AIF2 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
+		      2, 1, 0),
+WM8994_CLASS_W_SWITCH("AIF1.2 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
+		      1, 1, 0),
+WM8994_CLASS_W_SWITCH("AIF1.1 Switch", WM8994_DAC1_LEFT_MIXER_ROUTING,
+		      0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1r_mix[] = {
+WM8994_CLASS_W_SWITCH("Right Sidetone Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
+		      5, 1, 0),
+WM8994_CLASS_W_SWITCH("Left Sidetone Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
+		      4, 1, 0),
+WM8994_CLASS_W_SWITCH("AIF2 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
+		      2, 1, 0),
+WM8994_CLASS_W_SWITCH("AIF1.2 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
+		      1, 1, 0),
+WM8994_CLASS_W_SWITCH("AIF1.1 Switch", WM8994_DAC1_RIGHT_MIXER_ROUTING,
+		      0, 1, 0),
+};
+
+static const char *sidetone_text[] = {
+	"ADC/DMIC1", "DMIC2",
+};
+
+static SOC_ENUM_SINGLE_DECL(sidetone1_enum,
+			    WM8994_SIDETONE, 0, sidetone_text);
+
+static const struct snd_kcontrol_new sidetone1_mux =
+	SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum);
+
+static SOC_ENUM_SINGLE_DECL(sidetone2_enum,
+			    WM8994_SIDETONE, 1, sidetone_text);
+
+static const struct snd_kcontrol_new sidetone2_mux =
+	SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum);
+
+static const char *aif1dac_text[] = {
+	"AIF1DACDAT", "AIF3DACDAT",
+};
+
+static const char *loopback_text[] = {
+	"None", "ADCDAT",
+};
+
+static SOC_ENUM_SINGLE_DECL(aif1_loopback_enum,
+			    WM8994_AIF1_CONTROL_2,
+			    WM8994_AIF1_LOOPBACK_SHIFT,
+			    loopback_text);
+
+static const struct snd_kcontrol_new aif1_loopback =
+	SOC_DAPM_ENUM("AIF1 Loopback", aif1_loopback_enum);
+
+static SOC_ENUM_SINGLE_DECL(aif2_loopback_enum,
+			    WM8994_AIF2_CONTROL_2,
+			    WM8994_AIF2_LOOPBACK_SHIFT,
+			    loopback_text);
+
+static const struct snd_kcontrol_new aif2_loopback =
+	SOC_DAPM_ENUM("AIF2 Loopback", aif2_loopback_enum);
+
+static SOC_ENUM_SINGLE_DECL(aif1dac_enum,
+			    WM8994_POWER_MANAGEMENT_6, 0, aif1dac_text);
+
+static const struct snd_kcontrol_new aif1dac_mux =
+	SOC_DAPM_ENUM("AIF1DAC Mux", aif1dac_enum);
+
+static const char *aif2dac_text[] = {
+	"AIF2DACDAT", "AIF3DACDAT",
+};
+
+static SOC_ENUM_SINGLE_DECL(aif2dac_enum,
+			    WM8994_POWER_MANAGEMENT_6, 1, aif2dac_text);
+
+static const struct snd_kcontrol_new aif2dac_mux =
+	SOC_DAPM_ENUM("AIF2DAC Mux", aif2dac_enum);
+
+static const char *aif2adc_text[] = {
+	"AIF2ADCDAT", "AIF3DACDAT",
+};
+
+static SOC_ENUM_SINGLE_DECL(aif2adc_enum,
+			    WM8994_POWER_MANAGEMENT_6, 2, aif2adc_text);
+
+static const struct snd_kcontrol_new aif2adc_mux =
+	SOC_DAPM_ENUM("AIF2ADC Mux", aif2adc_enum);
+
+static const char *aif3adc_text[] = {
+	"AIF1ADCDAT", "AIF2ADCDAT", "AIF2DACDAT", "Mono PCM",
+};
+
+static SOC_ENUM_SINGLE_DECL(wm8994_aif3adc_enum,
+			    WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text);
+
+static const struct snd_kcontrol_new wm8994_aif3adc_mux =
+	SOC_DAPM_ENUM("AIF3ADC Mux", wm8994_aif3adc_enum);
+
+static SOC_ENUM_SINGLE_DECL(wm8958_aif3adc_enum,
+			    WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text);
+
+static const struct snd_kcontrol_new wm8958_aif3adc_mux =
+	SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum);
+
+static const char *mono_pcm_out_text[] = {
+	"None", "AIF2ADCL", "AIF2ADCR",
+};
+
+static SOC_ENUM_SINGLE_DECL(mono_pcm_out_enum,
+			    WM8994_POWER_MANAGEMENT_6, 9, mono_pcm_out_text);
+
+static const struct snd_kcontrol_new mono_pcm_out_mux =
+	SOC_DAPM_ENUM("Mono PCM Out Mux", mono_pcm_out_enum);
+
+static const char *aif2dac_src_text[] = {
+	"AIF2", "AIF3",
+};
+
+/* Note that these two control shouldn't be simultaneously switched to AIF3 */
+static SOC_ENUM_SINGLE_DECL(aif2dacl_src_enum,
+			    WM8994_POWER_MANAGEMENT_6, 7, aif2dac_src_text);
+
+static const struct snd_kcontrol_new aif2dacl_src_mux =
+	SOC_DAPM_ENUM("AIF2DACL Mux", aif2dacl_src_enum);
+
+static SOC_ENUM_SINGLE_DECL(aif2dacr_src_enum,
+			    WM8994_POWER_MANAGEMENT_6, 8, aif2dac_src_text);
+
+static const struct snd_kcontrol_new aif2dacr_src_mux =
+	SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum);
+
+static const struct snd_soc_dapm_widget wm8994_lateclk_revd_widgets[] = {
+SND_SOC_DAPM_SUPPLY("AIF1CLK", SND_SOC_NOPM, 0, 0, aif1clk_late_ev,
+	SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("AIF2CLK", SND_SOC_NOPM, 0, 0, aif2clk_late_ev,
+	SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_PGA_E("Late DAC1L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
+	late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("Late DAC1R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
+	late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("Late DAC2L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
+	late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("Late DAC2R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
+	late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0,
+	late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+
+SND_SOC_DAPM_MIXER_E("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
+		     left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer),
+		     late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_MIXER_E("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
+		     right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer),
+		     late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux,
+		   late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux,
+		   late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+
+SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev)
+};
+
+static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = {
+SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, aif1clk_ev,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		    SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, aif2clk_ev,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		    SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
+		   left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
+SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
+		   right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux),
+};
+
+static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = {
+SND_SOC_DAPM_DAC_E("DAC2L", NULL, SND_SOC_NOPM, 3, 0,
+	dac_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_DAC_E("DAC2R", NULL, SND_SOC_NOPM, 2, 0,
+	dac_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_DAC_E("DAC1L", NULL, SND_SOC_NOPM, 1, 0,
+	dac_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_DAC_E("DAC1R", NULL, SND_SOC_NOPM, 0, 0,
+	dac_ev, SND_SOC_DAPM_PRE_PMU),
+};
+
+static const struct snd_soc_dapm_widget wm8994_dac_widgets[] = {
+SND_SOC_DAPM_DAC("DAC2L", NULL, WM8994_POWER_MANAGEMENT_5, 3, 0),
+SND_SOC_DAPM_DAC("DAC2R", NULL, WM8994_POWER_MANAGEMENT_5, 2, 0),
+SND_SOC_DAPM_DAC("DAC1L", NULL, WM8994_POWER_MANAGEMENT_5, 1, 0),
+SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8994_adc_revd_widgets[] = {
+SND_SOC_DAPM_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux,
+			adc_mux_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux,
+			adc_mux_ev, SND_SOC_DAPM_PRE_PMU),
+};
+
+static const struct snd_soc_dapm_widget wm8994_adc_widgets[] = {
+SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux),
+SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux),
+};
+
+static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("DMIC1DAT"),
+SND_SOC_DAPM_INPUT("DMIC2DAT"),
+SND_SOC_DAPM_INPUT("Clock"),
+
+SND_SOC_DAPM_SUPPLY_S("MICBIAS Supply", 1, SND_SOC_NOPM, 0, 0, micbias_ev,
+		      SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, vmid_event,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		    SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_SUPPLY("DSP1CLK", SND_SOC_NOPM, 3, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("DSP2CLK", SND_SOC_NOPM, 2, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("DSPINTCLK", SND_SOC_NOPM, 1, 0, NULL, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1ADC1L", NULL,
+		     0, SND_SOC_NOPM, 9, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1ADC1R", NULL,
+		     0, SND_SOC_NOPM, 8, 0),
+SND_SOC_DAPM_AIF_IN_E("AIF1DAC1L", NULL, 0,
+		      SND_SOC_NOPM, 9, 0, wm8958_aif_ev,
+		      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_AIF_IN_E("AIF1DAC1R", NULL, 0,
+		      SND_SOC_NOPM, 8, 0, wm8958_aif_ev,
+		      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_AIF_OUT("AIF1ADC2L", NULL,
+		     0, SND_SOC_NOPM, 11, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", NULL,
+		     0, SND_SOC_NOPM, 10, 0),
+SND_SOC_DAPM_AIF_IN_E("AIF1DAC2L", NULL, 0,
+		      SND_SOC_NOPM, 11, 0, wm8958_aif_ev,
+		      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_AIF_IN_E("AIF1DAC2R", NULL, 0,
+		      SND_SOC_NOPM, 10, 0, wm8958_aif_ev,
+		      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_MIXER("AIF1ADC1L Mixer", SND_SOC_NOPM, 0, 0,
+		   aif1adc1l_mix, ARRAY_SIZE(aif1adc1l_mix)),
+SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0,
+		   aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)),
+
+SND_SOC_DAPM_MIXER("AIF1ADC2L Mixer", SND_SOC_NOPM, 0, 0,
+		   aif1adc2l_mix, ARRAY_SIZE(aif1adc2l_mix)),
+SND_SOC_DAPM_MIXER("AIF1ADC2R Mixer", SND_SOC_NOPM, 0, 0,
+		   aif1adc2r_mix, ARRAY_SIZE(aif1adc2r_mix)),
+
+SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0,
+		   aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)),
+SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0,
+		   aif2dac2r_mix, ARRAY_SIZE(aif2dac2r_mix)),
+
+SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &sidetone1_mux),
+SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &sidetone2_mux),
+
+SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0,
+		   dac1l_mix, ARRAY_SIZE(dac1l_mix)),
+SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0,
+		   dac1r_mix, ARRAY_SIZE(dac1r_mix)),
+
+SND_SOC_DAPM_AIF_OUT("AIF2ADCL", NULL, 0,
+		     SND_SOC_NOPM, 13, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2ADCR", NULL, 0,
+		     SND_SOC_NOPM, 12, 0),
+SND_SOC_DAPM_AIF_IN_E("AIF2DACL", NULL, 0,
+		      SND_SOC_NOPM, 13, 0, wm8958_aif_ev,
+		      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_AIF_IN_E("AIF2DACR", NULL, 0,
+		      SND_SOC_NOPM, 12, 0, wm8958_aif_ev,
+		      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_AIF_IN("AIF1DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIF2DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1ADCDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2ADCDAT",  NULL, 0, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_MUX("AIF1DAC Mux", SND_SOC_NOPM, 0, 0, &aif1dac_mux),
+SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_NOPM, 0, 0, &aif2dac_mux),
+SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux),
+
+SND_SOC_DAPM_AIF_IN("AIF3DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8994_POWER_MANAGEMENT_4, 5, 0),
+SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8994_POWER_MANAGEMENT_4, 4, 0),
+SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8994_POWER_MANAGEMENT_4, 3, 0),
+SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0),
+
+/* Power is done with the muxes since the ADC power also controls the
+ * downsampling chain, the chip will automatically manage the analogue
+ * specific portions.
+ */
+SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_MUX("AIF1 Loopback", SND_SOC_NOPM, 0, 0, &aif1_loopback),
+SND_SOC_DAPM_MUX("AIF2 Loopback", SND_SOC_NOPM, 0, 0, &aif2_loopback),
+
+SND_SOC_DAPM_POST("Debug log", post_ev),
+};
+
+static const struct snd_soc_dapm_widget wm8994_specific_dapm_widgets[] = {
+SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &wm8994_aif3adc_mux),
+};
+
+static const struct snd_soc_dapm_widget wm8958_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("AIF3", WM8994_POWER_MANAGEMENT_6, 5, 1, NULL, 0),
+SND_SOC_DAPM_MUX("Mono PCM Out Mux", SND_SOC_NOPM, 0, 0, &mono_pcm_out_mux),
+SND_SOC_DAPM_MUX("AIF2DACL Mux", SND_SOC_NOPM, 0, 0, &aif2dacl_src_mux),
+SND_SOC_DAPM_MUX("AIF2DACR Mux", SND_SOC_NOPM, 0, 0, &aif2dacr_src_mux),
+SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &wm8958_aif3adc_mux),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	{ "CLK_SYS", NULL, "AIF1CLK", check_clk_sys },
+	{ "CLK_SYS", NULL, "AIF2CLK", check_clk_sys },
+
+	{ "DSP1CLK", NULL, "CLK_SYS" },
+	{ "DSP2CLK", NULL, "CLK_SYS" },
+	{ "DSPINTCLK", NULL, "CLK_SYS" },
+
+	{ "AIF1ADC1L", NULL, "AIF1CLK" },
+	{ "AIF1ADC1L", NULL, "DSP1CLK" },
+	{ "AIF1ADC1R", NULL, "AIF1CLK" },
+	{ "AIF1ADC1R", NULL, "DSP1CLK" },
+	{ "AIF1ADC1R", NULL, "DSPINTCLK" },
+
+	{ "AIF1DAC1L", NULL, "AIF1CLK" },
+	{ "AIF1DAC1L", NULL, "DSP1CLK" },
+	{ "AIF1DAC1R", NULL, "AIF1CLK" },
+	{ "AIF1DAC1R", NULL, "DSP1CLK" },
+	{ "AIF1DAC1R", NULL, "DSPINTCLK" },
+
+	{ "AIF1ADC2L", NULL, "AIF1CLK" },
+	{ "AIF1ADC2L", NULL, "DSP1CLK" },
+	{ "AIF1ADC2R", NULL, "AIF1CLK" },
+	{ "AIF1ADC2R", NULL, "DSP1CLK" },
+	{ "AIF1ADC2R", NULL, "DSPINTCLK" },
+
+	{ "AIF1DAC2L", NULL, "AIF1CLK" },
+	{ "AIF1DAC2L", NULL, "DSP1CLK" },
+	{ "AIF1DAC2R", NULL, "AIF1CLK" },
+	{ "AIF1DAC2R", NULL, "DSP1CLK" },
+	{ "AIF1DAC2R", NULL, "DSPINTCLK" },
+
+	{ "AIF2ADCL", NULL, "AIF2CLK" },
+	{ "AIF2ADCL", NULL, "DSP2CLK" },
+	{ "AIF2ADCR", NULL, "AIF2CLK" },
+	{ "AIF2ADCR", NULL, "DSP2CLK" },
+	{ "AIF2ADCR", NULL, "DSPINTCLK" },
+
+	{ "AIF2DACL", NULL, "AIF2CLK" },
+	{ "AIF2DACL", NULL, "DSP2CLK" },
+	{ "AIF2DACR", NULL, "AIF2CLK" },
+	{ "AIF2DACR", NULL, "DSP2CLK" },
+	{ "AIF2DACR", NULL, "DSPINTCLK" },
+
+	{ "DMIC1L", NULL, "DMIC1DAT" },
+	{ "DMIC1L", NULL, "CLK_SYS" },
+	{ "DMIC1R", NULL, "DMIC1DAT" },
+	{ "DMIC1R", NULL, "CLK_SYS" },
+	{ "DMIC2L", NULL, "DMIC2DAT" },
+	{ "DMIC2L", NULL, "CLK_SYS" },
+	{ "DMIC2R", NULL, "DMIC2DAT" },
+	{ "DMIC2R", NULL, "CLK_SYS" },
+
+	{ "ADCL", NULL, "AIF1CLK" },
+	{ "ADCL", NULL, "DSP1CLK" },
+	{ "ADCL", NULL, "DSPINTCLK" },
+
+	{ "ADCR", NULL, "AIF1CLK" },
+	{ "ADCR", NULL, "DSP1CLK" },
+	{ "ADCR", NULL, "DSPINTCLK" },
+
+	{ "ADCL Mux", "ADC", "ADCL" },
+	{ "ADCL Mux", "DMIC", "DMIC1L" },
+	{ "ADCR Mux", "ADC", "ADCR" },
+	{ "ADCR Mux", "DMIC", "DMIC1R" },
+
+	{ "DAC1L", NULL, "AIF1CLK" },
+	{ "DAC1L", NULL, "DSP1CLK" },
+	{ "DAC1L", NULL, "DSPINTCLK" },
+
+	{ "DAC1R", NULL, "AIF1CLK" },
+	{ "DAC1R", NULL, "DSP1CLK" },
+	{ "DAC1R", NULL, "DSPINTCLK" },
+
+	{ "DAC2L", NULL, "AIF2CLK" },
+	{ "DAC2L", NULL, "DSP2CLK" },
+	{ "DAC2L", NULL, "DSPINTCLK" },
+
+	{ "DAC2R", NULL, "AIF2DACR" },
+	{ "DAC2R", NULL, "AIF2CLK" },
+	{ "DAC2R", NULL, "DSP2CLK" },
+	{ "DAC2R", NULL, "DSPINTCLK" },
+
+	{ "TOCLK", NULL, "CLK_SYS" },
+
+	{ "AIF1DACDAT", NULL, "AIF1 Playback" },
+	{ "AIF2DACDAT", NULL, "AIF2 Playback" },
+	{ "AIF3DACDAT", NULL, "AIF3 Playback" },
+
+	{ "AIF1 Capture", NULL, "AIF1ADCDAT" },
+	{ "AIF2 Capture", NULL, "AIF2ADCDAT" },
+	{ "AIF3 Capture", NULL, "AIF3ADCDAT" },
+
+	/* AIF1 outputs */
+	{ "AIF1ADC1L", NULL, "AIF1ADC1L Mixer" },
+	{ "AIF1ADC1L Mixer", "ADC/DMIC Switch", "ADCL Mux" },
+	{ "AIF1ADC1L Mixer", "AIF2 Switch", "AIF2DACL" },
+
+	{ "AIF1ADC1R", NULL, "AIF1ADC1R Mixer" },
+	{ "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" },
+	{ "AIF1ADC1R Mixer", "AIF2 Switch", "AIF2DACR" },
+
+	{ "AIF1ADC2L", NULL, "AIF1ADC2L Mixer" },
+	{ "AIF1ADC2L Mixer", "DMIC Switch", "DMIC2L" },
+	{ "AIF1ADC2L Mixer", "AIF2 Switch", "AIF2DACL" },
+
+	{ "AIF1ADC2R", NULL, "AIF1ADC2R Mixer" },
+	{ "AIF1ADC2R Mixer", "DMIC Switch", "DMIC2R" },
+	{ "AIF1ADC2R Mixer", "AIF2 Switch", "AIF2DACR" },
+
+	/* Pin level routing for AIF3 */
+	{ "AIF1DAC1L", NULL, "AIF1DAC Mux" },
+	{ "AIF1DAC1R", NULL, "AIF1DAC Mux" },
+	{ "AIF1DAC2L", NULL, "AIF1DAC Mux" },
+	{ "AIF1DAC2R", NULL, "AIF1DAC Mux" },
+
+	{ "AIF1DAC Mux", "AIF1DACDAT", "AIF1 Loopback" },
+	{ "AIF1DAC Mux", "AIF3DACDAT", "AIF3DACDAT" },
+	{ "AIF2DAC Mux", "AIF2DACDAT", "AIF2 Loopback" },
+	{ "AIF2DAC Mux", "AIF3DACDAT", "AIF3DACDAT" },
+	{ "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCL" },
+	{ "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCR" },
+	{ "AIF2ADC Mux", "AIF3DACDAT", "AIF3ADCDAT" },
+
+	/* DAC1 inputs */
+	{ "DAC1L Mixer", "AIF2 Switch", "AIF2DACL" },
+	{ "DAC1L Mixer", "AIF1.2 Switch", "AIF1DAC2L" },
+	{ "DAC1L Mixer", "AIF1.1 Switch", "AIF1DAC1L" },
+	{ "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+	{ "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+
+	{ "DAC1R Mixer", "AIF2 Switch", "AIF2DACR" },
+	{ "DAC1R Mixer", "AIF1.2 Switch", "AIF1DAC2R" },
+	{ "DAC1R Mixer", "AIF1.1 Switch", "AIF1DAC1R" },
+	{ "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+	{ "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+
+	/* DAC2/AIF2 outputs  */
+	{ "AIF2ADCL", NULL, "AIF2DAC2L Mixer" },
+	{ "AIF2DAC2L Mixer", "AIF2 Switch", "AIF2DACL" },
+	{ "AIF2DAC2L Mixer", "AIF1.2 Switch", "AIF1DAC2L" },
+	{ "AIF2DAC2L Mixer", "AIF1.1 Switch", "AIF1DAC1L" },
+	{ "AIF2DAC2L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+	{ "AIF2DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+
+	{ "AIF2ADCR", NULL, "AIF2DAC2R Mixer" },
+	{ "AIF2DAC2R Mixer", "AIF2 Switch", "AIF2DACR" },
+	{ "AIF2DAC2R Mixer", "AIF1.2 Switch", "AIF1DAC2R" },
+	{ "AIF2DAC2R Mixer", "AIF1.1 Switch", "AIF1DAC1R" },
+	{ "AIF2DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+	{ "AIF2DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+
+	{ "AIF1ADCDAT", NULL, "AIF1ADC1L" },
+	{ "AIF1ADCDAT", NULL, "AIF1ADC1R" },
+	{ "AIF1ADCDAT", NULL, "AIF1ADC2L" },
+	{ "AIF1ADCDAT", NULL, "AIF1ADC2R" },
+
+	{ "AIF2ADCDAT", NULL, "AIF2ADC Mux" },
+
+	/* AIF3 output */
+	{ "AIF3ADC Mux", "AIF1ADCDAT", "AIF1ADC1L" },
+	{ "AIF3ADC Mux", "AIF1ADCDAT", "AIF1ADC1R" },
+	{ "AIF3ADC Mux", "AIF1ADCDAT", "AIF1ADC2L" },
+	{ "AIF3ADC Mux", "AIF1ADCDAT", "AIF1ADC2R" },
+	{ "AIF3ADC Mux", "AIF2ADCDAT", "AIF2ADCL" },
+	{ "AIF3ADC Mux", "AIF2ADCDAT", "AIF2ADCR" },
+	{ "AIF3ADC Mux", "AIF2DACDAT", "AIF2DACL" },
+	{ "AIF3ADC Mux", "AIF2DACDAT", "AIF2DACR" },
+
+	{ "AIF3ADCDAT", NULL, "AIF3ADC Mux" },
+
+	/* Loopback */
+	{ "AIF1 Loopback", "ADCDAT", "AIF1ADCDAT" },
+	{ "AIF1 Loopback", "None", "AIF1DACDAT" },
+	{ "AIF2 Loopback", "ADCDAT", "AIF2ADCDAT" },
+	{ "AIF2 Loopback", "None", "AIF2DACDAT" },
+
+	/* Sidetone */
+	{ "Left Sidetone", "ADC/DMIC1", "ADCL Mux" },
+	{ "Left Sidetone", "DMIC2", "DMIC2L" },
+	{ "Right Sidetone", "ADC/DMIC1", "ADCR Mux" },
+	{ "Right Sidetone", "DMIC2", "DMIC2R" },
+
+	/* Output stages */
+	{ "Left Output Mixer", "DAC Switch", "DAC1L" },
+	{ "Right Output Mixer", "DAC Switch", "DAC1R" },
+
+	{ "SPKL", "DAC1 Switch", "DAC1L" },
+	{ "SPKL", "DAC2 Switch", "DAC2L" },
+
+	{ "SPKR", "DAC1 Switch", "DAC1R" },
+	{ "SPKR", "DAC2 Switch", "DAC2R" },
+
+	{ "Left Headphone Mux", "DAC", "DAC1L" },
+	{ "Right Headphone Mux", "DAC", "DAC1R" },
+};
+
+static const struct snd_soc_dapm_route wm8994_lateclk_revd_intercon[] = {
+	{ "DAC1L", NULL, "Late DAC1L Enable PGA" },
+	{ "Late DAC1L Enable PGA", NULL, "DAC1L Mixer" },
+	{ "DAC1R", NULL, "Late DAC1R Enable PGA" },
+	{ "Late DAC1R Enable PGA", NULL, "DAC1R Mixer" },
+	{ "DAC2L", NULL, "Late DAC2L Enable PGA" },
+	{ "Late DAC2L Enable PGA", NULL, "AIF2DAC2L Mixer" },
+	{ "DAC2R", NULL, "Late DAC2R Enable PGA" },
+	{ "Late DAC2R Enable PGA", NULL, "AIF2DAC2R Mixer" }
+};
+
+static const struct snd_soc_dapm_route wm8994_lateclk_intercon[] = {
+	{ "DAC1L", NULL, "DAC1L Mixer" },
+	{ "DAC1R", NULL, "DAC1R Mixer" },
+	{ "DAC2L", NULL, "AIF2DAC2L Mixer" },
+	{ "DAC2R", NULL, "AIF2DAC2R Mixer" },
+};
+
+static const struct snd_soc_dapm_route wm8994_revd_intercon[] = {
+	{ "AIF1DACDAT", NULL, "AIF2DACDAT" },
+	{ "AIF2DACDAT", NULL, "AIF1DACDAT" },
+	{ "AIF1ADCDAT", NULL, "AIF2ADCDAT" },
+	{ "AIF2ADCDAT", NULL, "AIF1ADCDAT" },
+	{ "MICBIAS1", NULL, "CLK_SYS" },
+	{ "MICBIAS1", NULL, "MICBIAS Supply" },
+	{ "MICBIAS2", NULL, "CLK_SYS" },
+	{ "MICBIAS2", NULL, "MICBIAS Supply" },
+};
+
+static const struct snd_soc_dapm_route wm8994_intercon[] = {
+	{ "AIF2DACL", NULL, "AIF2DAC Mux" },
+	{ "AIF2DACR", NULL, "AIF2DAC Mux" },
+	{ "MICBIAS1", NULL, "VMID" },
+	{ "MICBIAS2", NULL, "VMID" },
+};
+
+static const struct snd_soc_dapm_route wm8958_intercon[] = {
+	{ "AIF2DACL", NULL, "AIF2DACL Mux" },
+	{ "AIF2DACR", NULL, "AIF2DACR Mux" },
+
+	{ "AIF2DACL Mux", "AIF2", "AIF2DAC Mux" },
+	{ "AIF2DACL Mux", "AIF3", "AIF3DACDAT" },
+	{ "AIF2DACR Mux", "AIF2", "AIF2DAC Mux" },
+	{ "AIF2DACR Mux", "AIF3", "AIF3DACDAT" },
+
+	{ "AIF3DACDAT", NULL, "AIF3" },
+	{ "AIF3ADCDAT", NULL, "AIF3" },
+
+	{ "Mono PCM Out Mux", "AIF2ADCL", "AIF2ADCL" },
+	{ "Mono PCM Out Mux", "AIF2ADCR", "AIF2ADCR" },
+
+	{ "AIF3ADC Mux", "Mono PCM", "Mono PCM Out Mux" },
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+struct fll_div {
+	u16 outdiv;
+	u16 n;
+	u16 k;
+	u16 lambda;
+	u16 clk_ref_div;
+	u16 fll_fratio;
+};
+
+static int wm8994_get_fll_config(struct wm8994 *control, struct fll_div *fll,
+				 int freq_in, int freq_out)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod, gcd_fll;
+
+	pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out);
+
+	/* Scale the input frequency down to <= 13.5MHz */
+	fll->clk_ref_div = 0;
+	while (freq_in > 13500000) {
+		fll->clk_ref_div++;
+		freq_in /= 2;
+
+		if (fll->clk_ref_div > 3)
+			return -EINVAL;
+	}
+	pr_debug("CLK_REF_DIV=%d, Fref=%dHz\n", fll->clk_ref_div, freq_in);
+
+	/* Scale the output to give 90MHz<=Fvco<=100MHz */
+	fll->outdiv = 3;
+	while (freq_out * (fll->outdiv + 1) < 90000000) {
+		fll->outdiv++;
+		if (fll->outdiv > 63)
+			return -EINVAL;
+	}
+	freq_out *= fll->outdiv + 1;
+	pr_debug("OUTDIV=%d, Fvco=%dHz\n", fll->outdiv, freq_out);
+
+	if (freq_in > 1000000) {
+		fll->fll_fratio = 0;
+	} else if (freq_in > 256000) {
+		fll->fll_fratio = 1;
+		freq_in *= 2;
+	} else if (freq_in > 128000) {
+		fll->fll_fratio = 2;
+		freq_in *= 4;
+	} else if (freq_in > 64000) {
+		fll->fll_fratio = 3;
+		freq_in *= 8;
+	} else {
+		fll->fll_fratio = 4;
+		freq_in *= 16;
+	}
+	pr_debug("FLL_FRATIO=%d, Fref=%dHz\n", fll->fll_fratio, freq_in);
+
+	/* Now, calculate N.K */
+	Ndiv = freq_out / freq_in;
+
+	fll->n = Ndiv;
+	Nmod = freq_out % freq_in;
+	pr_debug("Nmod=%d\n", Nmod);
+
+	switch (control->type) {
+	case WM8994:
+		/* Calculate fractional part - scale up so we can round. */
+		Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+		do_div(Kpart, freq_in);
+
+		K = Kpart & 0xFFFFFFFF;
+
+		if ((K % 10) >= 5)
+			K += 5;
+
+		/* Move down to proper range now rounding is done */
+		fll->k = K / 10;
+		fll->lambda = 0;
+
+		pr_debug("N=%x K=%x\n", fll->n, fll->k);
+		break;
+
+	default:
+		gcd_fll = gcd(freq_out, freq_in);
+
+		fll->k = (freq_out - (freq_in * fll->n)) / gcd_fll;
+		fll->lambda = freq_in / gcd_fll;
+		
+	}
+
+	return 0;
+}
+
+static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
+			  unsigned int freq_in, unsigned int freq_out)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	int reg_offset, ret;
+	struct fll_div fll;
+	u16 reg, clk1, aif_reg, aif_src;
+	unsigned long timeout;
+	bool was_enabled;
+
+	switch (id) {
+	case WM8994_FLL1:
+		reg_offset = 0;
+		id = 0;
+		aif_src = 0x10;
+		break;
+	case WM8994_FLL2:
+		reg_offset = 0x20;
+		id = 1;
+		aif_src = 0x18;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	reg = snd_soc_component_read32(component, WM8994_FLL1_CONTROL_1 + reg_offset);
+	was_enabled = reg & WM8994_FLL1_ENA;
+
+	switch (src) {
+	case 0:
+		/* Allow no source specification when stopping */
+		if (freq_out)
+			return -EINVAL;
+		src = wm8994->fll[id].src;
+		break;
+	case WM8994_FLL_SRC_MCLK1:
+	case WM8994_FLL_SRC_MCLK2:
+	case WM8994_FLL_SRC_LRCLK:
+	case WM8994_FLL_SRC_BCLK:
+		break;
+	case WM8994_FLL_SRC_INTERNAL:
+		freq_in = 12000000;
+		freq_out = 12000000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Are we changing anything? */
+	if (wm8994->fll[id].src == src &&
+	    wm8994->fll[id].in == freq_in && wm8994->fll[id].out == freq_out)
+		return 0;
+
+	/* If we're stopping the FLL redo the old config - no
+	 * registers will actually be written but we avoid GCC flow
+	 * analysis bugs spewing warnings.
+	 */
+	if (freq_out)
+		ret = wm8994_get_fll_config(control, &fll, freq_in, freq_out);
+	else
+		ret = wm8994_get_fll_config(control, &fll, wm8994->fll[id].in,
+					    wm8994->fll[id].out);
+	if (ret < 0)
+		return ret;
+
+	/* Make sure that we're not providing SYSCLK right now */
+	clk1 = snd_soc_component_read32(component, WM8994_CLOCKING_1);
+	if (clk1 & WM8994_SYSCLK_SRC)
+		aif_reg = WM8994_AIF2_CLOCKING_1;
+	else
+		aif_reg = WM8994_AIF1_CLOCKING_1;
+	reg = snd_soc_component_read32(component, aif_reg);
+
+	if ((reg & WM8994_AIF1CLK_ENA) &&
+	    (reg & WM8994_AIF1CLK_SRC_MASK) == aif_src) {
+		dev_err(component->dev, "FLL%d is currently providing SYSCLK\n",
+			id + 1);
+		return -EBUSY;
+	}
+
+	/* We always need to disable the FLL while reconfiguring */
+	snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_1 + reg_offset,
+			    WM8994_FLL1_ENA, 0);
+
+	if (wm8994->fll_byp && src == WM8994_FLL_SRC_BCLK &&
+	    freq_in == freq_out && freq_out) {
+		dev_dbg(component->dev, "Bypassing FLL%d\n", id + 1);
+		snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_5 + reg_offset,
+				    WM8958_FLL1_BYP, WM8958_FLL1_BYP);
+		goto out;
+	}
+
+	reg = (fll.outdiv << WM8994_FLL1_OUTDIV_SHIFT) |
+		(fll.fll_fratio << WM8994_FLL1_FRATIO_SHIFT);
+	snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_2 + reg_offset,
+			    WM8994_FLL1_OUTDIV_MASK |
+			    WM8994_FLL1_FRATIO_MASK, reg);
+
+	snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_3 + reg_offset,
+			    WM8994_FLL1_K_MASK, fll.k);
+
+	snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_4 + reg_offset,
+			    WM8994_FLL1_N_MASK,
+			    fll.n << WM8994_FLL1_N_SHIFT);
+
+	if (fll.lambda) {
+		snd_soc_component_update_bits(component, WM8958_FLL1_EFS_1 + reg_offset,
+				    WM8958_FLL1_LAMBDA_MASK,
+				    fll.lambda);
+		snd_soc_component_update_bits(component, WM8958_FLL1_EFS_2 + reg_offset,
+				    WM8958_FLL1_EFS_ENA, WM8958_FLL1_EFS_ENA);
+	} else {
+		snd_soc_component_update_bits(component, WM8958_FLL1_EFS_2 + reg_offset,
+				    WM8958_FLL1_EFS_ENA, 0);
+	}
+
+	snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_5 + reg_offset,
+			    WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP |
+			    WM8994_FLL1_REFCLK_DIV_MASK |
+			    WM8994_FLL1_REFCLK_SRC_MASK,
+			    ((src == WM8994_FLL_SRC_INTERNAL)
+			     << WM8994_FLL1_FRC_NCO_SHIFT) |
+			    (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) |
+			    (src - 1));
+
+	/* Clear any pending completion from a previous failure */
+	try_wait_for_completion(&wm8994->fll_locked[id]);
+
+	/* Enable (with fractional mode if required) */
+	if (freq_out) {
+		/* Enable VMID if we need it */
+		if (!was_enabled) {
+			active_reference(component);
+
+			switch (control->type) {
+			case WM8994:
+				vmid_reference(component);
+				break;
+			case WM8958:
+				if (control->revision < 1)
+					vmid_reference(component);
+				break;
+			default:
+				break;
+			}
+		}
+
+		reg = WM8994_FLL1_ENA;
+
+		if (fll.k)
+			reg |= WM8994_FLL1_FRAC;
+		if (src == WM8994_FLL_SRC_INTERNAL)
+			reg |= WM8994_FLL1_OSC_ENA;
+
+		snd_soc_component_update_bits(component, WM8994_FLL1_CONTROL_1 + reg_offset,
+				    WM8994_FLL1_ENA | WM8994_FLL1_OSC_ENA |
+				    WM8994_FLL1_FRAC, reg);
+
+		if (wm8994->fll_locked_irq) {
+			timeout = wait_for_completion_timeout(&wm8994->fll_locked[id],
+							      msecs_to_jiffies(10));
+			if (timeout == 0)
+				dev_warn(component->dev,
+					 "Timed out waiting for FLL lock\n");
+		} else {
+			msleep(5);
+		}
+	} else {
+		if (was_enabled) {
+			switch (control->type) {
+			case WM8994:
+				vmid_dereference(component);
+				break;
+			case WM8958:
+				if (control->revision < 1)
+					vmid_dereference(component);
+				break;
+			default:
+				break;
+			}
+
+			active_dereference(component);
+		}
+	}
+
+out:
+	wm8994->fll[id].in = freq_in;
+	wm8994->fll[id].out = freq_out;
+	wm8994->fll[id].src = src;
+
+	configure_clock(component);
+
+	/*
+	 * If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
+	 * for detection.
+	 */
+	if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
+		dev_dbg(component->dev, "Configuring AIFs for 128fs\n");
+
+		wm8994->aifdiv[0] = snd_soc_component_read32(component, WM8994_AIF1_RATE)
+			& WM8994_AIF1CLK_RATE_MASK;
+		wm8994->aifdiv[1] = snd_soc_component_read32(component, WM8994_AIF2_RATE)
+			& WM8994_AIF1CLK_RATE_MASK;
+
+		snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
+				    WM8994_AIF1CLK_RATE_MASK, 0x1);
+		snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
+				    WM8994_AIF2CLK_RATE_MASK, 0x1);
+	} else if (wm8994->aifdiv[0]) {
+		snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
+				    WM8994_AIF1CLK_RATE_MASK,
+				    wm8994->aifdiv[0]);
+		snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
+				    WM8994_AIF2CLK_RATE_MASK,
+				    wm8994->aifdiv[1]);
+
+		wm8994->aifdiv[0] = 0;
+		wm8994->aifdiv[1] = 0;
+	}
+
+	return 0;
+}
+
+static irqreturn_t wm8994_fll_locked_irq(int irq, void *data)
+{
+	struct completion *completion = data;
+
+	complete(completion);
+
+	return IRQ_HANDLED;
+}
+
+static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
+
+static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
+			  unsigned int freq_in, unsigned int freq_out)
+{
+	return _wm8994_set_fll(dai->component, id, src, freq_in, freq_out);
+}
+
+static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	int i;
+
+	switch (dai->id) {
+	case 1:
+	case 2:
+		break;
+
+	default:
+		/* AIF3 shares clocking with AIF1/2 */
+		return -EINVAL;
+	}
+
+	switch (clk_id) {
+	case WM8994_SYSCLK_MCLK1:
+		wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK1;
+		wm8994->mclk[0] = freq;
+		dev_dbg(dai->dev, "AIF%d using MCLK1 at %uHz\n",
+			dai->id, freq);
+		break;
+
+	case WM8994_SYSCLK_MCLK2:
+		/* TODO: Set GPIO AF */
+		wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK2;
+		wm8994->mclk[1] = freq;
+		dev_dbg(dai->dev, "AIF%d using MCLK2 at %uHz\n",
+			dai->id, freq);
+		break;
+
+	case WM8994_SYSCLK_FLL1:
+		wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_FLL1;
+		dev_dbg(dai->dev, "AIF%d using FLL1\n", dai->id);
+		break;
+
+	case WM8994_SYSCLK_FLL2:
+		wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_FLL2;
+		dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id);
+		break;
+
+	case WM8994_SYSCLK_OPCLK:
+		/* Special case - a division (times 10) is given and
+		 * no effect on main clocking.
+		 */
+		if (freq) {
+			for (i = 0; i < ARRAY_SIZE(opclk_divs); i++)
+				if (opclk_divs[i] == freq)
+					break;
+			if (i == ARRAY_SIZE(opclk_divs))
+				return -EINVAL;
+			snd_soc_component_update_bits(component, WM8994_CLOCKING_2,
+					    WM8994_OPCLK_DIV_MASK, i);
+			snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_2,
+					    WM8994_OPCLK_ENA, WM8994_OPCLK_ENA);
+		} else {
+			snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_2,
+					    WM8994_OPCLK_ENA, 0);
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	configure_clock(component);
+
+	/*
+	 * If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
+	 * for detection.
+	 */
+	if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
+		dev_dbg(component->dev, "Configuring AIFs for 128fs\n");
+
+		wm8994->aifdiv[0] = snd_soc_component_read32(component, WM8994_AIF1_RATE)
+			& WM8994_AIF1CLK_RATE_MASK;
+		wm8994->aifdiv[1] = snd_soc_component_read32(component, WM8994_AIF2_RATE)
+			& WM8994_AIF1CLK_RATE_MASK;
+
+		snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
+				    WM8994_AIF1CLK_RATE_MASK, 0x1);
+		snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
+				    WM8994_AIF2CLK_RATE_MASK, 0x1);
+	} else if (wm8994->aifdiv[0]) {
+		snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
+				    WM8994_AIF1CLK_RATE_MASK,
+				    wm8994->aifdiv[0]);
+		snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
+				    WM8994_AIF2CLK_RATE_MASK,
+				    wm8994->aifdiv[1]);
+
+		wm8994->aifdiv[0] = 0;
+		wm8994->aifdiv[1] = 0;
+	}
+
+	return 0;
+}
+
+static int wm8994_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+
+	wm_hubs_set_bias_level(component, level);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* MICBIAS into regulating mode */
+		switch (control->type) {
+		case WM8958:
+		case WM1811:
+			snd_soc_component_update_bits(component, WM8958_MICBIAS1,
+					    WM8958_MICB1_MODE, 0);
+			snd_soc_component_update_bits(component, WM8958_MICBIAS2,
+					    WM8958_MICB2_MODE, 0);
+			break;
+		default:
+			break;
+		}
+
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY)
+			active_reference(component);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			switch (control->type) {
+			case WM8958:
+				if (control->revision == 0) {
+					/* Optimise performance for rev A */
+					snd_soc_component_update_bits(component,
+							    WM8958_CHARGE_PUMP_2,
+							    WM8958_CP_DISCH,
+							    WM8958_CP_DISCH);
+				}
+				break;
+
+			default:
+				break;
+			}
+
+			/* Discharge LINEOUT1 & 2 */
+			snd_soc_component_update_bits(component, WM8994_ANTIPOP_1,
+					    WM8994_LINEOUT1_DISCH |
+					    WM8994_LINEOUT2_DISCH,
+					    WM8994_LINEOUT1_DISCH |
+					    WM8994_LINEOUT2_DISCH);
+		}
+
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE)
+			active_dereference(component);
+
+		/* MICBIAS into bypass mode on newer devices */
+		switch (control->type) {
+		case WM8958:
+		case WM1811:
+			snd_soc_component_update_bits(component, WM8958_MICBIAS1,
+					    WM8958_MICB1_MODE,
+					    WM8958_MICB1_MODE);
+			snd_soc_component_update_bits(component, WM8958_MICBIAS2,
+					    WM8958_MICB2_MODE,
+					    WM8958_MICB2_MODE);
+			break;
+		default:
+			break;
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_STANDBY)
+			wm8994->cur_fw = NULL;
+		break;
+	}
+
+	return 0;
+}
+
+int wm8994_vmid_mode(struct snd_soc_component *component, enum wm8994_vmid_mode mode)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	switch (mode) {
+	case WM8994_VMID_NORMAL:
+		snd_soc_dapm_mutex_lock(dapm);
+
+		if (wm8994->hubs.lineout1_se) {
+			snd_soc_dapm_disable_pin_unlocked(dapm,
+							  "LINEOUT1N Driver");
+			snd_soc_dapm_disable_pin_unlocked(dapm,
+							  "LINEOUT1P Driver");
+		}
+		if (wm8994->hubs.lineout2_se) {
+			snd_soc_dapm_disable_pin_unlocked(dapm,
+							  "LINEOUT2N Driver");
+			snd_soc_dapm_disable_pin_unlocked(dapm,
+							  "LINEOUT2P Driver");
+		}
+
+		/* Do the sync with the old mode to allow it to clean up */
+		snd_soc_dapm_sync_unlocked(dapm);
+		wm8994->vmid_mode = mode;
+
+		snd_soc_dapm_mutex_unlock(dapm);
+		break;
+
+	case WM8994_VMID_FORCE:
+		snd_soc_dapm_mutex_lock(dapm);
+
+		if (wm8994->hubs.lineout1_se) {
+			snd_soc_dapm_force_enable_pin_unlocked(dapm,
+							       "LINEOUT1N Driver");
+			snd_soc_dapm_force_enable_pin_unlocked(dapm,
+							       "LINEOUT1P Driver");
+		}
+		if (wm8994->hubs.lineout2_se) {
+			snd_soc_dapm_force_enable_pin_unlocked(dapm,
+							       "LINEOUT2N Driver");
+			snd_soc_dapm_force_enable_pin_unlocked(dapm,
+							       "LINEOUT2P Driver");
+		}
+
+		wm8994->vmid_mode = mode;
+		snd_soc_dapm_sync_unlocked(dapm);
+
+		snd_soc_dapm_mutex_unlock(dapm);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	int ms_reg;
+	int aif1_reg;
+	int dac_reg;
+	int adc_reg;
+	int ms = 0;
+	int aif1 = 0;
+	int lrclk = 0;
+
+	switch (dai->id) {
+	case 1:
+		ms_reg = WM8994_AIF1_MASTER_SLAVE;
+		aif1_reg = WM8994_AIF1_CONTROL_1;
+		dac_reg = WM8994_AIF1DAC_LRCLK;
+		adc_reg = WM8994_AIF1ADC_LRCLK;
+		break;
+	case 2:
+		ms_reg = WM8994_AIF2_MASTER_SLAVE;
+		aif1_reg = WM8994_AIF2_CONTROL_1;
+		dac_reg = WM8994_AIF1DAC_LRCLK;
+		adc_reg = WM8994_AIF1ADC_LRCLK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		ms = WM8994_AIF1_MSTR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_B:
+		aif1 |= WM8994_AIF1_LRCLK_INV;
+		lrclk |= WM8958_AIF1_LRCLK_INV;
+		/* fall through */
+	case SND_SOC_DAIFMT_DSP_A:
+		aif1 |= 0x18;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aif1 |= 0x10;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif1 |= 0x8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		/* frame inversion not valid for DSP modes */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif1 |= WM8994_AIF1_BCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			aif1 |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV;
+			lrclk |= WM8958_AIF1_LRCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif1 |= WM8994_AIF1_BCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			aif1 |= WM8994_AIF1_LRCLK_INV;
+			lrclk |= WM8958_AIF1_LRCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* The AIF2 format configuration needs to be mirrored to AIF3
+	 * on WM8958 if it's in use so just do it all the time. */
+	switch (control->type) {
+	case WM1811:
+	case WM8958:
+		if (dai->id == 2)
+			snd_soc_component_update_bits(component, WM8958_AIF3_CONTROL_1,
+					    WM8994_AIF1_LRCLK_INV |
+					    WM8958_AIF3_FMT_MASK, aif1);
+		break;
+
+	default:
+		break;
+	}
+
+	snd_soc_component_update_bits(component, aif1_reg,
+			    WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV |
+			    WM8994_AIF1_FMT_MASK,
+			    aif1);
+	snd_soc_component_update_bits(component, ms_reg, WM8994_AIF1_MSTR,
+			    ms);
+	snd_soc_component_update_bits(component, dac_reg,
+			    WM8958_AIF1_LRCLK_INV, lrclk);
+	snd_soc_component_update_bits(component, adc_reg,
+			    WM8958_AIF1_LRCLK_INV, lrclk);
+
+	return 0;
+}
+
+static struct {
+	int val, rate;
+} srs[] = {
+	{ 0,   8000 },
+	{ 1,  11025 },
+	{ 2,  12000 },
+	{ 3,  16000 },
+	{ 4,  22050 },
+	{ 5,  24000 },
+	{ 6,  32000 },
+	{ 7,  44100 },
+	{ 8,  48000 },
+	{ 9,  88200 },
+	{ 10, 96000 },
+};
+
+static int fs_ratios[] = {
+	64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536
+};
+
+static int bclk_divs[] = {
+	10, 15, 20, 30, 40, 50, 60, 80, 110, 120, 160, 220, 240, 320, 440, 480,
+	640, 880, 960, 1280, 1760, 1920
+};
+
+static int wm8994_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	struct wm8994_pdata *pdata = &control->pdata;
+	int aif1_reg;
+	int aif2_reg;
+	int bclk_reg;
+	int lrclk_reg;
+	int rate_reg;
+	int aif1 = 0;
+	int aif2 = 0;
+	int bclk = 0;
+	int lrclk = 0;
+	int rate_val = 0;
+	int id = dai->id - 1;
+
+	int i, cur_val, best_val, bclk_rate, best;
+
+	switch (dai->id) {
+	case 1:
+		aif1_reg = WM8994_AIF1_CONTROL_1;
+		aif2_reg = WM8994_AIF1_CONTROL_2;
+		bclk_reg = WM8994_AIF1_BCLK;
+		rate_reg = WM8994_AIF1_RATE;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+		    wm8994->lrclk_shared[0]) {
+			lrclk_reg = WM8994_AIF1DAC_LRCLK;
+		} else {
+			lrclk_reg = WM8994_AIF1ADC_LRCLK;
+			dev_dbg(component->dev, "AIF1 using split LRCLK\n");
+		}
+		break;
+	case 2:
+		aif1_reg = WM8994_AIF2_CONTROL_1;
+		aif2_reg = WM8994_AIF2_CONTROL_2;
+		bclk_reg = WM8994_AIF2_BCLK;
+		rate_reg = WM8994_AIF2_RATE;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+		    wm8994->lrclk_shared[1]) {
+			lrclk_reg = WM8994_AIF2DAC_LRCLK;
+		} else {
+			lrclk_reg = WM8994_AIF2ADC_LRCLK;
+			dev_dbg(component->dev, "AIF2 using split LRCLK\n");
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	bclk_rate = params_rate(params);
+	switch (params_width(params)) {
+	case 16:
+		bclk_rate *= 16;
+		break;
+	case 20:
+		bclk_rate *= 20;
+		aif1 |= 0x20;
+		break;
+	case 24:
+		bclk_rate *= 24;
+		aif1 |= 0x40;
+		break;
+	case 32:
+		bclk_rate *= 32;
+		aif1 |= 0x60;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	wm8994->channels[id] = params_channels(params);
+	if (pdata->max_channels_clocked[id] &&
+	    wm8994->channels[id] > pdata->max_channels_clocked[id]) {
+		dev_dbg(dai->dev, "Constraining channels to %d from %d\n",
+			pdata->max_channels_clocked[id], wm8994->channels[id]);
+		wm8994->channels[id] = pdata->max_channels_clocked[id];
+	}
+
+	switch (wm8994->channels[id]) {
+	case 1:
+	case 2:
+		bclk_rate *= 2;
+		break;
+	default:
+		bclk_rate *= 4;
+		break;
+	}
+
+	/* Try to find an appropriate sample rate; look for an exact match. */
+	for (i = 0; i < ARRAY_SIZE(srs); i++)
+		if (srs[i].rate == params_rate(params))
+			break;
+	if (i == ARRAY_SIZE(srs))
+		return -EINVAL;
+	rate_val |= srs[i].val << WM8994_AIF1_SR_SHIFT;
+
+	dev_dbg(dai->dev, "Sample rate is %dHz\n", srs[i].rate);
+	dev_dbg(dai->dev, "AIF%dCLK is %dHz, target BCLK %dHz\n",
+		dai->id, wm8994->aifclk[id], bclk_rate);
+
+	if (wm8994->channels[id] == 1 &&
+	    (snd_soc_component_read32(component, aif1_reg) & 0x18) == 0x18)
+		aif2 |= WM8994_AIF1_MONO;
+
+	if (wm8994->aifclk[id] == 0) {
+		dev_err(dai->dev, "AIF%dCLK not configured\n", dai->id);
+		return -EINVAL;
+	}
+
+	/* AIFCLK/fs ratio; look for a close match in either direction */
+	best = 0;
+	best_val = abs((fs_ratios[0] * params_rate(params))
+		       - wm8994->aifclk[id]);
+	for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) {
+		cur_val = abs((fs_ratios[i] * params_rate(params))
+			      - wm8994->aifclk[id]);
+		if (cur_val >= best_val)
+			continue;
+		best = i;
+		best_val = cur_val;
+	}
+	dev_dbg(dai->dev, "Selected AIF%dCLK/fs = %d\n",
+		dai->id, fs_ratios[best]);
+	rate_val |= best;
+
+	/* We may not get quite the right frequency if using
+	 * approximate clocks so look for the closest match that is
+	 * higher than the target (we need to ensure that there enough
+	 * BCLKs to clock out the samples).
+	 */
+	best = 0;
+	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+		cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate;
+		if (cur_val < 0) /* BCLK table is sorted */
+			break;
+		best = i;
+	}
+	bclk_rate = wm8994->aifclk[id] * 10 / bclk_divs[best];
+	dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
+		bclk_divs[best], bclk_rate);
+	bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT;
+
+	lrclk = bclk_rate / params_rate(params);
+	if (!lrclk) {
+		dev_err(dai->dev, "Unable to generate LRCLK from %dHz BCLK\n",
+			bclk_rate);
+		return -EINVAL;
+	}
+	dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
+		lrclk, bclk_rate / lrclk);
+
+	snd_soc_component_update_bits(component, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
+	snd_soc_component_update_bits(component, aif2_reg, WM8994_AIF1_MONO, aif2);
+	snd_soc_component_update_bits(component, bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, bclk);
+	snd_soc_component_update_bits(component, lrclk_reg, WM8994_AIF1DAC_RATE_MASK,
+			    lrclk);
+	snd_soc_component_update_bits(component, rate_reg, WM8994_AIF1_SR_MASK |
+			    WM8994_AIF1CLK_RATE_MASK, rate_val);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		switch (dai->id) {
+		case 1:
+			wm8994->dac_rates[0] = params_rate(params);
+			wm8994_set_retune_mobile(component, 0);
+			wm8994_set_retune_mobile(component, 1);
+			break;
+		case 2:
+			wm8994->dac_rates[1] = params_rate(params);
+			wm8994_set_retune_mobile(component, 2);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int wm8994_aif3_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	int aif1_reg;
+	int aif1 = 0;
+
+	switch (dai->id) {
+	case 3:
+		switch (control->type) {
+		case WM1811:
+		case WM8958:
+			aif1_reg = WM8958_AIF3_CONTROL_1;
+			break;
+		default:
+			return 0;
+		}
+		break;
+	default:
+		return 0;
+	}
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		aif1 |= 0x20;
+		break;
+	case 24:
+		aif1 |= 0x40;
+		break;
+	case 32:
+		aif1 |= 0x60;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_soc_component_update_bits(component, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
+}
+
+static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	int mute_reg;
+	int reg;
+
+	switch (codec_dai->id) {
+	case 1:
+		mute_reg = WM8994_AIF1_DAC1_FILTERS_1;
+		break;
+	case 2:
+		mute_reg = WM8994_AIF2_DAC_FILTERS_1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mute)
+		reg = WM8994_AIF1DAC1_MUTE;
+	else
+		reg = 0;
+
+	snd_soc_component_update_bits(component, mute_reg, WM8994_AIF1DAC1_MUTE, reg);
+
+	return 0;
+}
+
+static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	int reg, val, mask;
+
+	switch (codec_dai->id) {
+	case 1:
+		reg = WM8994_AIF1_MASTER_SLAVE;
+		mask = WM8994_AIF1_TRI;
+		break;
+	case 2:
+		reg = WM8994_AIF2_MASTER_SLAVE;
+		mask = WM8994_AIF2_TRI;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (tristate)
+		val = mask;
+	else
+		val = 0;
+
+	return snd_soc_component_update_bits(component, reg, mask, val);
+}
+
+static int wm8994_aif2_probe(struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+
+	/* Disable the pulls on the AIF if we're using it to save power. */
+	snd_soc_component_update_bits(component, WM8994_GPIO_3,
+			    WM8994_GPN_PU | WM8994_GPN_PD, 0);
+	snd_soc_component_update_bits(component, WM8994_GPIO_4,
+			    WM8994_GPN_PU | WM8994_GPN_PD, 0);
+	snd_soc_component_update_bits(component, WM8994_GPIO_5,
+			    WM8994_GPN_PU | WM8994_GPN_PD, 0);
+
+	return 0;
+}
+
+#define WM8994_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8994_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
+	.set_sysclk	= wm8994_set_dai_sysclk,
+	.set_fmt	= wm8994_set_dai_fmt,
+	.hw_params	= wm8994_hw_params,
+	.digital_mute	= wm8994_aif_mute,
+	.set_pll	= wm8994_set_fll,
+	.set_tristate	= wm8994_set_tristate,
+};
+
+static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
+	.set_sysclk	= wm8994_set_dai_sysclk,
+	.set_fmt	= wm8994_set_dai_fmt,
+	.hw_params	= wm8994_hw_params,
+	.digital_mute   = wm8994_aif_mute,
+	.set_pll	= wm8994_set_fll,
+	.set_tristate	= wm8994_set_tristate,
+};
+
+static const struct snd_soc_dai_ops wm8994_aif3_dai_ops = {
+	.hw_params	= wm8994_aif3_hw_params,
+};
+
+static struct snd_soc_dai_driver wm8994_dai[] = {
+	{
+		.name = "wm8994-aif1",
+		.id = 1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8994_RATES,
+			.formats = WM8994_FORMATS,
+			.sig_bits = 24,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8994_RATES,
+			.formats = WM8994_FORMATS,
+			.sig_bits = 24,
+		 },
+		.ops = &wm8994_aif1_dai_ops,
+	},
+	{
+		.name = "wm8994-aif2",
+		.id = 2,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8994_RATES,
+			.formats = WM8994_FORMATS,
+			.sig_bits = 24,
+		},
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8994_RATES,
+			.formats = WM8994_FORMATS,
+			.sig_bits = 24,
+		},
+		.probe = wm8994_aif2_probe,
+		.ops = &wm8994_aif2_dai_ops,
+	},
+	{
+		.name = "wm8994-aif3",
+		.id = 3,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8994_RATES,
+			.formats = WM8994_FORMATS,
+			.sig_bits = 24,
+		},
+		.capture = {
+			.stream_name = "AIF3 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8994_RATES,
+			.formats = WM8994_FORMATS,
+			.sig_bits = 24,
+		 },
+		.ops = &wm8994_aif3_dai_ops,
+	}
+};
+
+#ifdef CONFIG_PM
+static int wm8994_component_suspend(struct snd_soc_component *component)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
+		memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
+		       sizeof(struct wm8994_fll_config));
+		ret = _wm8994_set_fll(component, i + 1, 0, 0, 0);
+		if (ret < 0)
+			dev_warn(component->dev, "Failed to stop FLL%d: %d\n",
+				 i + 1, ret);
+	}
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int wm8994_component_resume(struct snd_soc_component *component)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
+		if (!wm8994->fll_suspend[i].out)
+			continue;
+
+		ret = _wm8994_set_fll(component, i + 1,
+				     wm8994->fll_suspend[i].src,
+				     wm8994->fll_suspend[i].in,
+				     wm8994->fll_suspend[i].out);
+		if (ret < 0)
+			dev_warn(component->dev, "Failed to restore FLL%d: %d\n",
+				 i + 1, ret);
+	}
+
+	return 0;
+}
+#else
+#define wm8994_component_suspend NULL
+#define wm8994_component_resume NULL
+#endif
+
+static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
+{
+	struct snd_soc_component *component = wm8994->hubs.component;
+	struct wm8994 *control = wm8994->wm8994;
+	struct wm8994_pdata *pdata = &control->pdata;
+	struct snd_kcontrol_new controls[] = {
+		SOC_ENUM_EXT("AIF1.1 EQ Mode",
+			     wm8994->retune_mobile_enum,
+			     wm8994_get_retune_mobile_enum,
+			     wm8994_put_retune_mobile_enum),
+		SOC_ENUM_EXT("AIF1.2 EQ Mode",
+			     wm8994->retune_mobile_enum,
+			     wm8994_get_retune_mobile_enum,
+			     wm8994_put_retune_mobile_enum),
+		SOC_ENUM_EXT("AIF2 EQ Mode",
+			     wm8994->retune_mobile_enum,
+			     wm8994_get_retune_mobile_enum,
+			     wm8994_put_retune_mobile_enum),
+	};
+	int ret, i, j;
+	const char **t;
+
+	/* We need an array of texts for the enum API but the number
+	 * of texts is likely to be less than the number of
+	 * configurations due to the sample rate dependency of the
+	 * configurations. */
+	wm8994->num_retune_mobile_texts = 0;
+	wm8994->retune_mobile_texts = NULL;
+	for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+		for (j = 0; j < wm8994->num_retune_mobile_texts; j++) {
+			if (strcmp(pdata->retune_mobile_cfgs[i].name,
+				   wm8994->retune_mobile_texts[j]) == 0)
+				break;
+		}
+
+		if (j != wm8994->num_retune_mobile_texts)
+			continue;
+
+		/* Expand the array... */
+		t = krealloc(wm8994->retune_mobile_texts,
+			     sizeof(char *) *
+			     (wm8994->num_retune_mobile_texts + 1),
+			     GFP_KERNEL);
+		if (t == NULL)
+			continue;
+
+		/* ...store the new entry... */
+		t[wm8994->num_retune_mobile_texts] =
+			pdata->retune_mobile_cfgs[i].name;
+
+		/* ...and remember the new version. */
+		wm8994->num_retune_mobile_texts++;
+		wm8994->retune_mobile_texts = t;
+	}
+
+	dev_dbg(component->dev, "Allocated %d unique ReTune Mobile names\n",
+		wm8994->num_retune_mobile_texts);
+
+	wm8994->retune_mobile_enum.items = wm8994->num_retune_mobile_texts;
+	wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts;
+
+	ret = snd_soc_add_component_controls(wm8994->hubs.component, controls,
+				   ARRAY_SIZE(controls));
+	if (ret != 0)
+		dev_err(wm8994->hubs.component->dev,
+			"Failed to add ReTune Mobile controls: %d\n", ret);
+}
+
+static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
+{
+	struct snd_soc_component *component = wm8994->hubs.component;
+	struct wm8994 *control = wm8994->wm8994;
+	struct wm8994_pdata *pdata = &control->pdata;
+	int ret, i;
+
+	if (!pdata)
+		return;
+
+	wm_hubs_handle_analogue_pdata(component, pdata->lineout1_diff,
+				      pdata->lineout2_diff,
+				      pdata->lineout1fb,
+				      pdata->lineout2fb,
+				      pdata->jd_scthr,
+				      pdata->jd_thr,
+				      pdata->micb1_delay,
+				      pdata->micb2_delay,
+				      pdata->micbias1_lvl,
+				      pdata->micbias2_lvl);
+
+	dev_dbg(component->dev, "%d DRC configurations\n", pdata->num_drc_cfgs);
+
+	if (pdata->num_drc_cfgs) {
+		struct snd_kcontrol_new controls[] = {
+			SOC_ENUM_EXT("AIF1DRC1 Mode", wm8994->drc_enum,
+				     wm8994_get_drc_enum, wm8994_put_drc_enum),
+			SOC_ENUM_EXT("AIF1DRC2 Mode", wm8994->drc_enum,
+				     wm8994_get_drc_enum, wm8994_put_drc_enum),
+			SOC_ENUM_EXT("AIF2DRC Mode", wm8994->drc_enum,
+				     wm8994_get_drc_enum, wm8994_put_drc_enum),
+		};
+
+		/* We need an array of texts for the enum API */
+		wm8994->drc_texts = devm_kcalloc(wm8994->hubs.component->dev,
+			    pdata->num_drc_cfgs, sizeof(char *), GFP_KERNEL);
+		if (!wm8994->drc_texts)
+			return;
+
+		for (i = 0; i < pdata->num_drc_cfgs; i++)
+			wm8994->drc_texts[i] = pdata->drc_cfgs[i].name;
+
+		wm8994->drc_enum.items = pdata->num_drc_cfgs;
+		wm8994->drc_enum.texts = wm8994->drc_texts;
+
+		ret = snd_soc_add_component_controls(wm8994->hubs.component, controls,
+					   ARRAY_SIZE(controls));
+		for (i = 0; i < WM8994_NUM_DRC; i++)
+			wm8994_set_drc(component, i);
+	} else {
+		ret = snd_soc_add_component_controls(wm8994->hubs.component,
+						 wm8994_drc_controls,
+						 ARRAY_SIZE(wm8994_drc_controls));
+	}
+
+	if (ret != 0)
+		dev_err(wm8994->hubs.component->dev,
+			"Failed to add DRC mode controls: %d\n", ret);
+
+
+	dev_dbg(component->dev, "%d ReTune Mobile configurations\n",
+		pdata->num_retune_mobile_cfgs);
+
+	if (pdata->num_retune_mobile_cfgs)
+		wm8994_handle_retune_mobile_pdata(wm8994);
+	else
+		snd_soc_add_component_controls(wm8994->hubs.component, wm8994_eq_controls,
+				     ARRAY_SIZE(wm8994_eq_controls));
+
+	for (i = 0; i < ARRAY_SIZE(pdata->micbias); i++) {
+		if (pdata->micbias[i]) {
+			snd_soc_component_write(component, WM8958_MICBIAS1 + i,
+				pdata->micbias[i] & 0xffff);
+		}
+	}
+}
+
+/**
+ * wm8994_mic_detect - Enable microphone detection via the WM8994 IRQ
+ *
+ * @component:   WM8994 component
+ * @jack:    jack to report detection events on
+ * @micbias: microphone bias to detect on
+ *
+ * Enable microphone detection via IRQ on the WM8994.  If GPIOs are
+ * being used to bring out signals to the processor then only platform
+ * data configuration is needed for WM8994 and processor GPIOs should
+ * be configured using snd_soc_jack_add_gpios() instead.
+ *
+ * Configuration of detection levels is available via the micbias1_lvl
+ * and micbias2_lvl platform data members.
+ */
+int wm8994_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
+		      int micbias)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994_micdet *micdet;
+	struct wm8994 *control = wm8994->wm8994;
+	int reg, ret;
+
+	if (control->type != WM8994) {
+		dev_warn(component->dev, "Not a WM8994\n");
+		return -EINVAL;
+	}
+
+	switch (micbias) {
+	case 1:
+		micdet = &wm8994->micdet[0];
+		if (jack)
+			ret = snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+		else
+			ret = snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+		break;
+	case 2:
+		micdet = &wm8994->micdet[1];
+		if (jack)
+			ret = snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+		else
+			ret = snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+		break;
+	default:
+		dev_warn(component->dev, "Invalid MICBIAS %d\n", micbias);
+		return -EINVAL;
+	}
+
+	if (ret != 0)
+		dev_warn(component->dev, "Failed to configure MICBIAS%d: %d\n",
+			 micbias, ret);
+
+	dev_dbg(component->dev, "Configuring microphone detection on %d %p\n",
+		micbias, jack);
+
+	/* Store the configuration */
+	micdet->jack = jack;
+	micdet->detecting = true;
+
+	/* If either of the jacks is set up then enable detection */
+	if (wm8994->micdet[0].jack || wm8994->micdet[1].jack)
+		reg = WM8994_MICD_ENA;
+	else
+		reg = 0;
+
+	snd_soc_component_update_bits(component, WM8994_MICBIAS, WM8994_MICD_ENA, reg);
+
+	/* enable MICDET and MICSHRT deboune */
+	snd_soc_component_update_bits(component, WM8994_IRQ_DEBOUNCE,
+			    WM8994_MIC1_DET_DB_MASK | WM8994_MIC1_SHRT_DB_MASK |
+			    WM8994_MIC2_DET_DB_MASK | WM8994_MIC2_SHRT_DB_MASK,
+			    WM8994_MIC1_DET_DB | WM8994_MIC1_SHRT_DB);
+
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8994_mic_detect);
+
+static void wm8994_mic_work(struct work_struct *work)
+{
+	struct wm8994_priv *priv = container_of(work,
+						struct wm8994_priv,
+						mic_work.work);
+	struct regmap *regmap = priv->wm8994->regmap;
+	struct device *dev = priv->wm8994->dev;
+	unsigned int reg;
+	int ret;
+	int report;
+
+	pm_runtime_get_sync(dev);
+
+	ret = regmap_read(regmap, WM8994_INTERRUPT_RAW_STATUS_2, &reg);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read microphone status: %d\n",
+			ret);
+		pm_runtime_put(dev);
+		return;
+	}
+
+	dev_dbg(dev, "Microphone status: %x\n", reg);
+
+	report = 0;
+	if (reg & WM8994_MIC1_DET_STS) {
+		if (priv->micdet[0].detecting)
+			report = SND_JACK_HEADSET;
+	}
+	if (reg & WM8994_MIC1_SHRT_STS) {
+		if (priv->micdet[0].detecting)
+			report = SND_JACK_HEADPHONE;
+		else
+			report |= SND_JACK_BTN_0;
+	}
+	if (report)
+		priv->micdet[0].detecting = false;
+	else
+		priv->micdet[0].detecting = true;
+
+	snd_soc_jack_report(priv->micdet[0].jack, report,
+			    SND_JACK_HEADSET | SND_JACK_BTN_0);
+
+	report = 0;
+	if (reg & WM8994_MIC2_DET_STS) {
+		if (priv->micdet[1].detecting)
+			report = SND_JACK_HEADSET;
+	}
+	if (reg & WM8994_MIC2_SHRT_STS) {
+		if (priv->micdet[1].detecting)
+			report = SND_JACK_HEADPHONE;
+		else
+			report |= SND_JACK_BTN_0;
+	}
+	if (report)
+		priv->micdet[1].detecting = false;
+	else
+		priv->micdet[1].detecting = true;
+
+	snd_soc_jack_report(priv->micdet[1].jack, report,
+			    SND_JACK_HEADSET | SND_JACK_BTN_0);
+
+	pm_runtime_put(dev);
+}
+
+static irqreturn_t wm8994_mic_irq(int irq, void *data)
+{
+	struct wm8994_priv *priv = data;
+	struct snd_soc_component *component = priv->hubs.component;
+
+#ifndef CONFIG_SND_SOC_WM8994_MODULE
+	trace_snd_soc_jack_irq(dev_name(component->dev));
+#endif
+
+	pm_wakeup_event(component->dev, 300);
+
+	queue_delayed_work(system_power_efficient_wq,
+			   &priv->mic_work, msecs_to_jiffies(250));
+
+	return IRQ_HANDLED;
+}
+
+/* Should be called with accdet_lock held */
+static void wm1811_micd_stop(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	if (!wm8994->jackdet)
+		return;
+
+	snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1, WM8958_MICD_ENA, 0);
+
+	wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_JACK);
+
+	if (wm8994->wm8994->pdata.jd_ext_cap)
+		snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
+}
+
+static void wm8958_button_det(struct snd_soc_component *component, u16 status)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	int report;
+
+	report = 0;
+	if (status & 0x4)
+		report |= SND_JACK_BTN_0;
+
+	if (status & 0x8)
+		report |= SND_JACK_BTN_1;
+
+	if (status & 0x10)
+		report |= SND_JACK_BTN_2;
+
+	if (status & 0x20)
+		report |= SND_JACK_BTN_3;
+
+	if (status & 0x40)
+		report |= SND_JACK_BTN_4;
+
+	if (status & 0x80)
+		report |= SND_JACK_BTN_5;
+
+	snd_soc_jack_report(wm8994->micdet[0].jack, report,
+			    wm8994->btn_mask);
+}
+
+static void wm8958_open_circuit_work(struct work_struct *work)
+{
+	struct wm8994_priv *wm8994 = container_of(work,
+						  struct wm8994_priv,
+						  open_circuit_work.work);
+	struct device *dev = wm8994->wm8994->dev;
+
+	mutex_lock(&wm8994->accdet_lock);
+
+	wm1811_micd_stop(wm8994->hubs.component);
+
+	dev_dbg(dev, "Reporting open circuit\n");
+
+	wm8994->jack_mic = false;
+	wm8994->mic_detecting = true;
+
+	wm8958_micd_set_rate(wm8994->hubs.component);
+
+	snd_soc_jack_report(wm8994->micdet[0].jack, 0,
+			    wm8994->btn_mask |
+			    SND_JACK_HEADSET);
+
+	mutex_unlock(&wm8994->accdet_lock);
+}
+
+static void wm8958_mic_id(void *data, u16 status)
+{
+	struct snd_soc_component *component = data;
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	/* Either nothing present or just starting detection */
+	if (!(status & WM8958_MICD_STS)) {
+		/* If nothing present then clear our statuses */
+		dev_dbg(component->dev, "Detected open circuit\n");
+
+		queue_delayed_work(system_power_efficient_wq,
+				   &wm8994->open_circuit_work,
+				   msecs_to_jiffies(2500));
+		return;
+	}
+
+	/* If the measurement is showing a high impedence we've got a
+	 * microphone.
+	 */
+	if (status & 0x600) {
+		dev_dbg(component->dev, "Detected microphone\n");
+
+		wm8994->mic_detecting = false;
+		wm8994->jack_mic = true;
+
+		wm8958_micd_set_rate(component);
+
+		snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADSET,
+				    SND_JACK_HEADSET);
+	}
+
+
+	if (status & 0xfc) {
+		dev_dbg(component->dev, "Detected headphone\n");
+		wm8994->mic_detecting = false;
+
+		wm8958_micd_set_rate(component);
+
+		/* If we have jackdet that will detect removal */
+		wm1811_micd_stop(component);
+
+		snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
+				    SND_JACK_HEADSET);
+	}
+}
+
+/* Deferred mic detection to allow for extra settling time */
+static void wm1811_mic_work(struct work_struct *work)
+{
+	struct wm8994_priv *wm8994 = container_of(work, struct wm8994_priv,
+						  mic_work.work);
+	struct wm8994 *control = wm8994->wm8994;
+	struct snd_soc_component *component = wm8994->hubs.component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	pm_runtime_get_sync(component->dev);
+
+	/* If required for an external cap force MICBIAS on */
+	if (control->pdata.jd_ext_cap) {
+		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS2");
+		snd_soc_dapm_sync(dapm);
+	}
+
+	mutex_lock(&wm8994->accdet_lock);
+
+	dev_dbg(component->dev, "Starting mic detection\n");
+
+	/* Use a user-supplied callback if we have one */
+	if (wm8994->micd_cb) {
+		wm8994->micd_cb(wm8994->micd_cb_data);
+	} else {
+		/*
+		 * Start off measument of microphone impedence to find out
+		 * what's actually there.
+		 */
+		wm8994->mic_detecting = true;
+		wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_MIC);
+
+		snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1,
+				    WM8958_MICD_ENA, WM8958_MICD_ENA);
+	}
+
+	mutex_unlock(&wm8994->accdet_lock);
+
+	pm_runtime_put(component->dev);
+}
+
+static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
+{
+	struct wm8994_priv *wm8994 = data;
+	struct wm8994 *control = wm8994->wm8994;
+	struct snd_soc_component *component = wm8994->hubs.component;
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int reg, delay;
+	bool present;
+
+	pm_runtime_get_sync(component->dev);
+
+	cancel_delayed_work_sync(&wm8994->mic_complete_work);
+
+	mutex_lock(&wm8994->accdet_lock);
+
+	reg = snd_soc_component_read32(component, WM1811_JACKDET_CTRL);
+	if (reg < 0) {
+		dev_err(component->dev, "Failed to read jack status: %d\n", reg);
+		mutex_unlock(&wm8994->accdet_lock);
+		pm_runtime_put(component->dev);
+		return IRQ_NONE;
+	}
+
+	dev_dbg(component->dev, "JACKDET %x\n", reg);
+
+	present = reg & WM1811_JACKDET_LVL;
+
+	if (present) {
+		dev_dbg(component->dev, "Jack detected\n");
+
+		wm8958_micd_set_rate(component);
+
+		snd_soc_component_update_bits(component, WM8958_MICBIAS2,
+				    WM8958_MICB2_DISCH, 0);
+
+		/* Disable debounce while inserted */
+		snd_soc_component_update_bits(component, WM1811_JACKDET_CTRL,
+				    WM1811_JACKDET_DB, 0);
+
+		delay = control->pdata.micdet_delay;
+		queue_delayed_work(system_power_efficient_wq,
+				   &wm8994->mic_work,
+				   msecs_to_jiffies(delay));
+	} else {
+		dev_dbg(component->dev, "Jack not detected\n");
+
+		cancel_delayed_work_sync(&wm8994->mic_work);
+
+		snd_soc_component_update_bits(component, WM8958_MICBIAS2,
+				    WM8958_MICB2_DISCH, WM8958_MICB2_DISCH);
+
+		/* Enable debounce while removed */
+		snd_soc_component_update_bits(component, WM1811_JACKDET_CTRL,
+				    WM1811_JACKDET_DB, WM1811_JACKDET_DB);
+
+		wm8994->mic_detecting = false;
+		wm8994->jack_mic = false;
+		snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1,
+				    WM8958_MICD_ENA, 0);
+		wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_JACK);
+	}
+
+	mutex_unlock(&wm8994->accdet_lock);
+
+	/* Turn off MICBIAS if it was on for an external cap */
+	if (control->pdata.jd_ext_cap && !present)
+		snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
+
+	if (present)
+		snd_soc_jack_report(wm8994->micdet[0].jack,
+				    SND_JACK_MECHANICAL, SND_JACK_MECHANICAL);
+	else
+		snd_soc_jack_report(wm8994->micdet[0].jack, 0,
+				    SND_JACK_MECHANICAL | SND_JACK_HEADSET |
+				    wm8994->btn_mask);
+
+	/* Since we only report deltas force an update, ensures we
+	 * avoid bootstrapping issues with the core. */
+	snd_soc_jack_report(wm8994->micdet[0].jack, 0, 0);
+
+	pm_runtime_put(component->dev);
+	return IRQ_HANDLED;
+}
+
+static void wm1811_jackdet_bootstrap(struct work_struct *work)
+{
+	struct wm8994_priv *wm8994 = container_of(work,
+						struct wm8994_priv,
+						jackdet_bootstrap.work);
+	wm1811_jackdet_irq(0, wm8994);
+}
+
+/**
+ * wm8958_mic_detect - Enable microphone detection via the WM8958 IRQ
+ *
+ * @component:   WM8958 component
+ * @jack:    jack to report detection events on
+ *
+ * Enable microphone detection functionality for the WM8958.  By
+ * default simple detection which supports the detection of up to 6
+ * buttons plus video and microphone functionality is supported.
+ *
+ * The WM8958 has an advanced jack detection facility which is able to
+ * support complex accessory detection, especially when used in
+ * conjunction with external circuitry.  In order to provide maximum
+ * flexiblity a callback is provided which allows a completely custom
+ * detection algorithm.
+ */
+int wm8958_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
+		      wm1811_micdet_cb det_cb, void *det_cb_data,
+		      wm1811_mic_id_cb id_cb, void *id_cb_data)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	u16 micd_lvl_sel;
+
+	switch (control->type) {
+	case WM1811:
+	case WM8958:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (jack) {
+		snd_soc_dapm_force_enable_pin(dapm, "CLK_SYS");
+		snd_soc_dapm_sync(dapm);
+
+		wm8994->micdet[0].jack = jack;
+
+		if (det_cb) {
+			wm8994->micd_cb = det_cb;
+			wm8994->micd_cb_data = det_cb_data;
+		} else {
+			wm8994->mic_detecting = true;
+			wm8994->jack_mic = false;
+		}
+
+		if (id_cb) {
+			wm8994->mic_id_cb = id_cb;
+			wm8994->mic_id_cb_data = id_cb_data;
+		} else {
+			wm8994->mic_id_cb = wm8958_mic_id;
+			wm8994->mic_id_cb_data = component;
+		}
+
+		wm8958_micd_set_rate(component);
+
+		/* Detect microphones and short circuits by default */
+		if (control->pdata.micd_lvl_sel)
+			micd_lvl_sel = control->pdata.micd_lvl_sel;
+		else
+			micd_lvl_sel = 0x41;
+
+		wm8994->btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+			SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+			SND_JACK_BTN_4 | SND_JACK_BTN_5;
+
+		snd_soc_component_update_bits(component, WM8958_MIC_DETECT_2,
+				    WM8958_MICD_LVL_SEL_MASK, micd_lvl_sel);
+
+		WARN_ON(snd_soc_component_get_bias_level(component) > SND_SOC_BIAS_STANDBY);
+
+		/*
+		 * If we can use jack detection start off with that,
+		 * otherwise jump straight to microphone detection.
+		 */
+		if (wm8994->jackdet) {
+			/* Disable debounce for the initial detect */
+			snd_soc_component_update_bits(component, WM1811_JACKDET_CTRL,
+					    WM1811_JACKDET_DB, 0);
+
+			snd_soc_component_update_bits(component, WM8958_MICBIAS2,
+					    WM8958_MICB2_DISCH,
+					    WM8958_MICB2_DISCH);
+			snd_soc_component_update_bits(component, WM8994_LDO_1,
+					    WM8994_LDO1_DISCH, 0);
+			wm1811_jackdet_set_mode(component,
+						WM1811_JACKDET_MODE_JACK);
+		} else {
+			snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1,
+					    WM8958_MICD_ENA, WM8958_MICD_ENA);
+		}
+
+	} else {
+		snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1,
+				    WM8958_MICD_ENA, 0);
+		wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_NONE);
+		snd_soc_dapm_disable_pin(dapm, "CLK_SYS");
+		snd_soc_dapm_sync(dapm);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8958_mic_detect);
+
+static void wm8958_mic_work(struct work_struct *work)
+{
+	struct wm8994_priv *wm8994 = container_of(work,
+						  struct wm8994_priv,
+						  mic_complete_work.work);
+	struct snd_soc_component *component = wm8994->hubs.component;
+
+	pm_runtime_get_sync(component->dev);
+
+	mutex_lock(&wm8994->accdet_lock);
+
+	wm8994->mic_id_cb(wm8994->mic_id_cb_data, wm8994->mic_status);
+
+	mutex_unlock(&wm8994->accdet_lock);
+
+	pm_runtime_put(component->dev);
+}
+
+static irqreturn_t wm8958_mic_irq(int irq, void *data)
+{
+	struct wm8994_priv *wm8994 = data;
+	struct snd_soc_component *component = wm8994->hubs.component;
+	int reg, count, ret, id_delay;
+
+	/*
+	 * Jack detection may have detected a removal simulataneously
+	 * with an update of the MICDET status; if so it will have
+	 * stopped detection and we can ignore this interrupt.
+	 */
+	if (!(snd_soc_component_read32(component, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA))
+		return IRQ_HANDLED;
+
+	cancel_delayed_work_sync(&wm8994->mic_complete_work);
+	cancel_delayed_work_sync(&wm8994->open_circuit_work);
+
+	pm_runtime_get_sync(component->dev);
+
+	/* We may occasionally read a detection without an impedence
+	 * range being provided - if that happens loop again.
+	 */
+	count = 10;
+	do {
+		reg = snd_soc_component_read32(component, WM8958_MIC_DETECT_3);
+		if (reg < 0) {
+			dev_err(component->dev,
+				"Failed to read mic detect status: %d\n",
+				reg);
+			pm_runtime_put(component->dev);
+			return IRQ_NONE;
+		}
+
+		if (!(reg & WM8958_MICD_VALID)) {
+			dev_dbg(component->dev, "Mic detect data not valid\n");
+			goto out;
+		}
+
+		if (!(reg & WM8958_MICD_STS) || (reg & WM8958_MICD_LVL_MASK))
+			break;
+
+		msleep(1);
+	} while (count--);
+
+	if (count == 0)
+		dev_warn(component->dev, "No impedance range reported for jack\n");
+
+#ifndef CONFIG_SND_SOC_WM8994_MODULE
+	trace_snd_soc_jack_irq(dev_name(component->dev));
+#endif
+
+	/* Avoid a transient report when the accessory is being removed */
+	if (wm8994->jackdet) {
+		ret = snd_soc_component_read32(component, WM1811_JACKDET_CTRL);
+		if (ret < 0) {
+			dev_err(component->dev, "Failed to read jack status: %d\n",
+				ret);
+		} else if (!(ret & WM1811_JACKDET_LVL)) {
+			dev_dbg(component->dev, "Ignoring removed jack\n");
+			goto out;
+		}
+	} else if (!(reg & WM8958_MICD_STS)) {
+		snd_soc_jack_report(wm8994->micdet[0].jack, 0,
+				    SND_JACK_MECHANICAL | SND_JACK_HEADSET |
+				    wm8994->btn_mask);
+		wm8994->mic_detecting = true;
+		goto out;
+	}
+
+	wm8994->mic_status = reg;
+	id_delay = wm8994->wm8994->pdata.mic_id_delay;
+
+	if (wm8994->mic_detecting)
+		queue_delayed_work(system_power_efficient_wq,
+				   &wm8994->mic_complete_work,
+				   msecs_to_jiffies(id_delay));
+	else
+		wm8958_button_det(component, reg);
+
+out:
+	pm_runtime_put(component->dev);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wm8994_fifo_error(int irq, void *data)
+{
+	struct snd_soc_component *component = data;
+
+	dev_err(component->dev, "FIFO error\n");
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wm8994_temp_warn(int irq, void *data)
+{
+	struct snd_soc_component *component = data;
+
+	dev_err(component->dev, "Thermal warning\n");
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wm8994_temp_shut(int irq, void *data)
+{
+	struct snd_soc_component *component = data;
+
+	dev_crit(component->dev, "Thermal shutdown\n");
+
+	return IRQ_HANDLED;
+}
+
+static int wm8994_component_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8994 *control = dev_get_drvdata(component->dev->parent);
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	unsigned int reg;
+	int ret, i;
+
+	snd_soc_component_init_regmap(component, control->regmap);
+
+	wm8994->hubs.component = component;
+
+	mutex_init(&wm8994->accdet_lock);
+	INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap,
+			  wm1811_jackdet_bootstrap);
+	INIT_DELAYED_WORK(&wm8994->open_circuit_work,
+			  wm8958_open_circuit_work);
+
+	switch (control->type) {
+	case WM8994:
+		INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work);
+		break;
+	case WM1811:
+		INIT_DELAYED_WORK(&wm8994->mic_work, wm1811_mic_work);
+		break;
+	default:
+		break;
+	}
+
+	INIT_DELAYED_WORK(&wm8994->mic_complete_work, wm8958_mic_work);
+
+	for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
+		init_completion(&wm8994->fll_locked[i]);
+
+	wm8994->micdet_irq = control->pdata.micdet_irq;
+
+	/* By default use idle_bias_off, will override for WM8994 */
+	dapm->idle_bias_off = 1;
+
+	/* Set revision-specific configuration */
+	switch (control->type) {
+	case WM8994:
+		/* Single ended line outputs should have VMID on. */
+		if (!control->pdata.lineout1_diff ||
+		    !control->pdata.lineout2_diff)
+			dapm->idle_bias_off = 0;
+
+		switch (control->revision) {
+		case 2:
+		case 3:
+			wm8994->hubs.dcs_codes_l = -5;
+			wm8994->hubs.dcs_codes_r = -5;
+			wm8994->hubs.hp_startup_mode = 1;
+			wm8994->hubs.dcs_readback_mode = 1;
+			wm8994->hubs.series_startup = 1;
+			break;
+		default:
+			wm8994->hubs.dcs_readback_mode = 2;
+			break;
+		}
+		break;
+
+	case WM8958:
+		wm8994->hubs.dcs_readback_mode = 1;
+		wm8994->hubs.hp_startup_mode = 1;
+
+		switch (control->revision) {
+		case 0:
+			break;
+		default:
+			wm8994->fll_byp = true;
+			break;
+		}
+		break;
+
+	case WM1811:
+		wm8994->hubs.dcs_readback_mode = 2;
+		wm8994->hubs.no_series_update = 1;
+		wm8994->hubs.hp_startup_mode = 1;
+		wm8994->hubs.no_cache_dac_hp_direct = true;
+		wm8994->fll_byp = true;
+
+		wm8994->hubs.dcs_codes_l = -9;
+		wm8994->hubs.dcs_codes_r = -7;
+
+		snd_soc_component_update_bits(component, WM8994_ANALOGUE_HP_1,
+				    WM1811_HPOUT1_ATTN, WM1811_HPOUT1_ATTN);
+		break;
+
+	default:
+		break;
+	}
+
+	wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_FIFOS_ERR,
+			   wm8994_fifo_error, "FIFO error", component);
+	wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_TEMP_WARN,
+			   wm8994_temp_warn, "Thermal warning", component);
+	wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT,
+			   wm8994_temp_shut, "Thermal shutdown", component);
+
+	switch (control->type) {
+	case WM8994:
+		if (wm8994->micdet_irq)
+			ret = request_threaded_irq(wm8994->micdet_irq, NULL,
+						   wm8994_mic_irq,
+						   IRQF_TRIGGER_RISING |
+						   IRQF_ONESHOT,
+						   "Mic1 detect",
+						   wm8994);
+		 else
+			ret = wm8994_request_irq(wm8994->wm8994,
+					WM8994_IRQ_MIC1_DET,
+					wm8994_mic_irq, "Mic 1 detect",
+					wm8994);
+
+		if (ret != 0)
+			dev_warn(component->dev,
+				 "Failed to request Mic1 detect IRQ: %d\n",
+				 ret);
+
+
+		ret = wm8994_request_irq(wm8994->wm8994,
+					 WM8994_IRQ_MIC1_SHRT,
+					 wm8994_mic_irq, "Mic 1 short",
+					 wm8994);
+		if (ret != 0)
+			dev_warn(component->dev,
+				 "Failed to request Mic1 short IRQ: %d\n",
+				 ret);
+
+		ret = wm8994_request_irq(wm8994->wm8994,
+					 WM8994_IRQ_MIC2_DET,
+					 wm8994_mic_irq, "Mic 2 detect",
+					 wm8994);
+		if (ret != 0)
+			dev_warn(component->dev,
+				 "Failed to request Mic2 detect IRQ: %d\n",
+				 ret);
+
+		ret = wm8994_request_irq(wm8994->wm8994,
+					 WM8994_IRQ_MIC2_SHRT,
+					 wm8994_mic_irq, "Mic 2 short",
+					 wm8994);
+		if (ret != 0)
+			dev_warn(component->dev,
+				 "Failed to request Mic2 short IRQ: %d\n",
+				 ret);
+		break;
+
+	case WM8958:
+	case WM1811:
+		if (wm8994->micdet_irq) {
+			ret = request_threaded_irq(wm8994->micdet_irq, NULL,
+						   wm8958_mic_irq,
+						   IRQF_TRIGGER_RISING |
+						   IRQF_ONESHOT,
+						   "Mic detect",
+						   wm8994);
+			if (ret != 0)
+				dev_warn(component->dev,
+					 "Failed to request Mic detect IRQ: %d\n",
+					 ret);
+		} else {
+			wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_MIC1_DET,
+					   wm8958_mic_irq, "Mic detect",
+					   wm8994);
+		}
+	}
+
+	switch (control->type) {
+	case WM1811:
+		if (control->cust_id > 1 || control->revision > 1) {
+			ret = wm8994_request_irq(wm8994->wm8994,
+						 WM8994_IRQ_GPIO(6),
+						 wm1811_jackdet_irq, "JACKDET",
+						 wm8994);
+			if (ret == 0)
+				wm8994->jackdet = true;
+		}
+		break;
+	default:
+		break;
+	}
+
+	wm8994->fll_locked_irq = true;
+	for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) {
+		ret = wm8994_request_irq(wm8994->wm8994,
+					 WM8994_IRQ_FLL1_LOCK + i,
+					 wm8994_fll_locked_irq, "FLL lock",
+					 &wm8994->fll_locked[i]);
+		if (ret != 0)
+			wm8994->fll_locked_irq = false;
+	}
+
+	/* Make sure we can read from the GPIOs if they're inputs */
+	pm_runtime_get_sync(component->dev);
+
+	/* Remember if AIFnLRCLK is configured as a GPIO.  This should be
+	 * configured on init - if a system wants to do this dynamically
+	 * at runtime we can deal with that then.
+	 */
+	ret = regmap_read(control->regmap, WM8994_GPIO_1, &reg);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to read GPIO1 state: %d\n", ret);
+		goto err_irq;
+	}
+	if ((reg & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
+		wm8994->lrclk_shared[0] = 1;
+		wm8994_dai[0].symmetric_rates = 1;
+	} else {
+		wm8994->lrclk_shared[0] = 0;
+	}
+
+	ret = regmap_read(control->regmap, WM8994_GPIO_6, &reg);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to read GPIO6 state: %d\n", ret);
+		goto err_irq;
+	}
+	if ((reg & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
+		wm8994->lrclk_shared[1] = 1;
+		wm8994_dai[1].symmetric_rates = 1;
+	} else {
+		wm8994->lrclk_shared[1] = 0;
+	}
+
+	pm_runtime_put(component->dev);
+
+	/* Latch volume update bits */
+	for (i = 0; i < ARRAY_SIZE(wm8994_vu_bits); i++)
+		snd_soc_component_update_bits(component, wm8994_vu_bits[i].reg,
+				    wm8994_vu_bits[i].mask,
+				    wm8994_vu_bits[i].mask);
+
+	/* Set the low bit of the 3D stereo depth so TLV matches */
+	snd_soc_component_update_bits(component, WM8994_AIF1_DAC1_FILTERS_2,
+			    1 << WM8994_AIF1DAC1_3D_GAIN_SHIFT,
+			    1 << WM8994_AIF1DAC1_3D_GAIN_SHIFT);
+	snd_soc_component_update_bits(component, WM8994_AIF1_DAC2_FILTERS_2,
+			    1 << WM8994_AIF1DAC2_3D_GAIN_SHIFT,
+			    1 << WM8994_AIF1DAC2_3D_GAIN_SHIFT);
+	snd_soc_component_update_bits(component, WM8994_AIF2_DAC_FILTERS_2,
+			    1 << WM8994_AIF2DAC_3D_GAIN_SHIFT,
+			    1 << WM8994_AIF2DAC_3D_GAIN_SHIFT);
+
+	/* Unconditionally enable AIF1 ADC TDM mode on chips which can
+	 * use this; it only affects behaviour on idle TDM clock
+	 * cycles. */
+	switch (control->type) {
+	case WM8994:
+	case WM8958:
+		snd_soc_component_update_bits(component, WM8994_AIF1_CONTROL_1,
+				    WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM);
+		break;
+	default:
+		break;
+	}
+
+	/* Put MICBIAS into bypass mode by default on newer devices */
+	switch (control->type) {
+	case WM8958:
+	case WM1811:
+		snd_soc_component_update_bits(component, WM8958_MICBIAS1,
+				    WM8958_MICB1_MODE, WM8958_MICB1_MODE);
+		snd_soc_component_update_bits(component, WM8958_MICBIAS2,
+				    WM8958_MICB2_MODE, WM8958_MICB2_MODE);
+		break;
+	default:
+		break;
+	}
+
+	wm8994->hubs.check_class_w_digital = wm8994_check_class_w_digital;
+	wm_hubs_update_class_w(component);
+
+	wm8994_handle_pdata(wm8994);
+
+	wm_hubs_add_analogue_controls(component);
+	snd_soc_add_component_controls(component, wm8994_snd_controls,
+			     ARRAY_SIZE(wm8994_snd_controls));
+	snd_soc_dapm_new_controls(dapm, wm8994_dapm_widgets,
+				  ARRAY_SIZE(wm8994_dapm_widgets));
+
+	switch (control->type) {
+	case WM8994:
+		snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets,
+					  ARRAY_SIZE(wm8994_specific_dapm_widgets));
+		if (control->revision < 4) {
+			snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
+						  ARRAY_SIZE(wm8994_lateclk_revd_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
+						  ARRAY_SIZE(wm8994_adc_revd_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_dac_revd_widgets,
+						  ARRAY_SIZE(wm8994_dac_revd_widgets));
+		} else {
+			snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
+						  ARRAY_SIZE(wm8994_lateclk_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
+						  ARRAY_SIZE(wm8994_adc_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
+						  ARRAY_SIZE(wm8994_dac_widgets));
+		}
+		break;
+	case WM8958:
+		snd_soc_add_component_controls(component, wm8958_snd_controls,
+				     ARRAY_SIZE(wm8958_snd_controls));
+		snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
+					  ARRAY_SIZE(wm8958_dapm_widgets));
+		if (control->revision < 1) {
+			snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
+						  ARRAY_SIZE(wm8994_lateclk_revd_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
+						  ARRAY_SIZE(wm8994_adc_revd_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_dac_revd_widgets,
+						  ARRAY_SIZE(wm8994_dac_revd_widgets));
+		} else {
+			snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
+						  ARRAY_SIZE(wm8994_lateclk_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
+						  ARRAY_SIZE(wm8994_adc_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
+						  ARRAY_SIZE(wm8994_dac_widgets));
+		}
+		break;
+
+	case WM1811:
+		snd_soc_add_component_controls(component, wm8958_snd_controls,
+				     ARRAY_SIZE(wm8958_snd_controls));
+		snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
+					  ARRAY_SIZE(wm8958_dapm_widgets));
+		snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
+					  ARRAY_SIZE(wm8994_lateclk_widgets));
+		snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
+					  ARRAY_SIZE(wm8994_adc_widgets));
+		snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
+					  ARRAY_SIZE(wm8994_dac_widgets));
+		break;
+	}
+
+	wm_hubs_add_analogue_routes(component, 0, 0);
+	ret = wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
+				 wm_hubs_dcs_done, "DC servo done",
+				 &wm8994->hubs);
+	if (ret == 0)
+		wm8994->hubs.dcs_done_irq = true;
+	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
+
+	switch (control->type) {
+	case WM8994:
+		snd_soc_dapm_add_routes(dapm, wm8994_intercon,
+					ARRAY_SIZE(wm8994_intercon));
+
+		if (control->revision < 4) {
+			snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
+						ARRAY_SIZE(wm8994_revd_intercon));
+			snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
+						ARRAY_SIZE(wm8994_lateclk_revd_intercon));
+		} else {
+			snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
+						ARRAY_SIZE(wm8994_lateclk_intercon));
+		}
+		break;
+	case WM8958:
+		if (control->revision < 1) {
+			snd_soc_dapm_add_routes(dapm, wm8994_intercon,
+						ARRAY_SIZE(wm8994_intercon));
+			snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
+						ARRAY_SIZE(wm8994_revd_intercon));
+			snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
+						ARRAY_SIZE(wm8994_lateclk_revd_intercon));
+		} else {
+			snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
+						ARRAY_SIZE(wm8994_lateclk_intercon));
+			snd_soc_dapm_add_routes(dapm, wm8958_intercon,
+						ARRAY_SIZE(wm8958_intercon));
+		}
+
+		wm8958_dsp2_init(component);
+		break;
+	case WM1811:
+		snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
+					ARRAY_SIZE(wm8994_lateclk_intercon));
+		snd_soc_dapm_add_routes(dapm, wm8958_intercon,
+					ARRAY_SIZE(wm8958_intercon));
+		break;
+	}
+
+	return 0;
+
+err_irq:
+	if (wm8994->jackdet)
+		wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_GPIO(6), wm8994);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC2_SHRT, wm8994);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC2_DET, wm8994);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC1_SHRT, wm8994);
+	if (wm8994->micdet_irq)
+		free_irq(wm8994->micdet_irq, wm8994);
+	for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
+		wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FLL1_LOCK + i,
+				&wm8994->fll_locked[i]);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
+			&wm8994->hubs);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FIFOS_ERR, component);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT, component);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_WARN, component);
+
+	return ret;
+}
+
+static void wm8994_component_remove(struct snd_soc_component *component)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
+		wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FLL1_LOCK + i,
+				&wm8994->fll_locked[i]);
+
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
+			&wm8994->hubs);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FIFOS_ERR, component);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT, component);
+	wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_WARN, component);
+
+	if (wm8994->jackdet)
+		wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_GPIO(6), wm8994);
+
+	switch (control->type) {
+	case WM8994:
+		if (wm8994->micdet_irq)
+			free_irq(wm8994->micdet_irq, wm8994);
+		wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC2_DET,
+				wm8994);
+		wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC1_SHRT,
+				wm8994);
+		wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC1_DET,
+				wm8994);
+		break;
+
+	case WM1811:
+	case WM8958:
+		if (wm8994->micdet_irq)
+			free_irq(wm8994->micdet_irq, wm8994);
+		break;
+	}
+	release_firmware(wm8994->mbc);
+	release_firmware(wm8994->mbc_vss);
+	release_firmware(wm8994->enh_eq);
+	kfree(wm8994->retune_mobile_texts);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8994 = {
+	.probe			= wm8994_component_probe,
+	.remove			= wm8994_component_remove,
+	.suspend		= wm8994_component_suspend,
+	.resume			= wm8994_component_resume,
+	.set_bias_level		= wm8994_set_bias_level,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm8994_probe(struct platform_device *pdev)
+{
+	struct wm8994_priv *wm8994;
+
+	wm8994 = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_priv),
+			      GFP_KERNEL);
+	if (wm8994 == NULL)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, wm8994);
+
+	mutex_init(&wm8994->fw_lock);
+
+	wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_idle(&pdev->dev);
+
+	return devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_wm8994,
+			wm8994_dai, ARRAY_SIZE(wm8994_dai));
+}
+
+static int wm8994_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int wm8994_suspend(struct device *dev)
+{
+	struct wm8994_priv *wm8994 = dev_get_drvdata(dev);
+
+	/* Drop down to power saving mode when system is suspended */
+	if (wm8994->jackdet && !wm8994->active_refcount)
+		regmap_update_bits(wm8994->wm8994->regmap, WM8994_ANTIPOP_2,
+				   WM1811_JACKDET_MODE_MASK,
+				   wm8994->jackdet_mode);
+
+	return 0;
+}
+
+static int wm8994_resume(struct device *dev)
+{
+	struct wm8994_priv *wm8994 = dev_get_drvdata(dev);
+
+	if (wm8994->jackdet && wm8994->jackdet_mode)
+		regmap_update_bits(wm8994->wm8994->regmap, WM8994_ANTIPOP_2,
+				   WM1811_JACKDET_MODE_MASK,
+				   WM1811_JACKDET_MODE_AUDIO);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops wm8994_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(wm8994_suspend, wm8994_resume)
+};
+
+static struct platform_driver wm8994_codec_driver = {
+	.driver = {
+		.name = "wm8994-codec",
+		.pm = &wm8994_pm_ops,
+	},
+	.probe = wm8994_probe,
+	.remove = wm8994_remove,
+};
+
+module_platform_driver(wm8994_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM8994 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8994-codec");
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
new file mode 100644
index 0000000..a72efb0
--- /dev/null
+++ b/sound/soc/codecs/wm8994.h
@@ -0,0 +1,168 @@
+/*
+ * wm8994.h  --  WM8994 Soc Audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8994_H
+#define _WM8994_H
+
+#include <sound/soc.h>
+#include <linux/firmware.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+
+#include "wm_hubs.h"
+
+/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
+#define WM8994_SYSCLK_MCLK1 1
+#define WM8994_SYSCLK_MCLK2 2
+#define WM8994_SYSCLK_FLL1  3
+#define WM8994_SYSCLK_FLL2  4
+
+/* OPCLK is also configured with set_dai_sysclk, specify division*10 as rate. */
+#define WM8994_SYSCLK_OPCLK 5
+
+#define WM8994_FLL1 1
+#define WM8994_FLL2 2
+
+#define WM8994_FLL_SRC_MCLK1    1
+#define WM8994_FLL_SRC_MCLK2    2
+#define WM8994_FLL_SRC_LRCLK    3
+#define WM8994_FLL_SRC_BCLK     4
+#define WM8994_FLL_SRC_INTERNAL 5
+
+enum wm8994_vmid_mode {
+	WM8994_VMID_NORMAL,
+	WM8994_VMID_FORCE,
+};
+
+typedef void (*wm1811_micdet_cb)(void *data);
+typedef void (*wm1811_mic_id_cb)(void *data, u16 status);
+
+int wm8994_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
+		      int micbias);
+int wm8958_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
+		      wm1811_micdet_cb cb, void *det_cb_data,
+		      wm1811_mic_id_cb id_cb, void *id_cb_data);
+
+int wm8994_vmid_mode(struct snd_soc_component *component, enum wm8994_vmid_mode mode);
+
+int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
+		  struct snd_kcontrol *kcontrol, int event);
+
+void wm8958_dsp2_init(struct snd_soc_component *component);
+
+struct wm8994_micdet {
+	struct snd_soc_jack *jack;
+	bool detecting;
+};
+
+/* codec private data */
+struct wm8994_fll_config {
+	int src;
+	int in;
+	int out;
+};
+
+#define WM8994_NUM_DRC 3
+#define WM8994_NUM_EQ  3
+
+struct wm8994;
+
+struct wm8994_priv {
+	struct wm_hubs_data hubs;
+	struct wm8994 *wm8994;
+	int sysclk[2];
+	int sysclk_rate[2];
+	int mclk[2];
+	int aifclk[2];
+	int aifdiv[2];
+	int channels[2];
+	struct wm8994_fll_config fll[2], fll_suspend[2];
+	struct completion fll_locked[2];
+	bool fll_locked_irq;
+	bool fll_byp;
+	bool clk_has_run;
+
+	int vmid_refcount;
+	int active_refcount;
+	enum wm8994_vmid_mode vmid_mode;
+
+	int dac_rates[2];
+	int lrclk_shared[2];
+
+	int mbc_ena[3];
+	int hpf1_ena[3];
+	int hpf2_ena[3];
+	int vss_ena[3];
+	int enh_eq_ena[3];
+
+	/* Platform dependant DRC configuration */
+	const char **drc_texts;
+	int drc_cfg[WM8994_NUM_DRC];
+	struct soc_enum drc_enum;
+
+	/* Platform dependant ReTune mobile configuration */
+	int num_retune_mobile_texts;
+	const char **retune_mobile_texts;
+	int retune_mobile_cfg[WM8994_NUM_EQ];
+	struct soc_enum retune_mobile_enum;
+
+	/* Platform dependant MBC configuration */
+	int mbc_cfg;
+	const char **mbc_texts;
+	struct soc_enum mbc_enum;
+
+	/* Platform dependant VSS configuration */
+	int vss_cfg;
+	const char **vss_texts;
+	struct soc_enum vss_enum;
+
+	/* Platform dependant VSS HPF configuration */
+	int vss_hpf_cfg;
+	const char **vss_hpf_texts;
+	struct soc_enum vss_hpf_enum;
+
+	/* Platform dependant enhanced EQ configuration */
+	int enh_eq_cfg;
+	const char **enh_eq_texts;
+	struct soc_enum enh_eq_enum;
+
+	struct mutex accdet_lock;
+	struct wm8994_micdet micdet[2];
+	struct delayed_work mic_work;
+	struct delayed_work open_circuit_work;
+	struct delayed_work mic_complete_work;
+	u16 mic_status;
+	bool mic_detecting;
+	bool jack_mic;
+	int btn_mask;
+	bool jackdet;
+	int jackdet_mode;
+	struct delayed_work jackdet_bootstrap;
+
+	int micdet_irq;
+	wm1811_micdet_cb micd_cb;
+	void *micd_cb_data;
+	wm1811_mic_id_cb mic_id_cb;
+	void *mic_id_cb_data;
+
+	unsigned int aif1clk_enable:1;
+	unsigned int aif2clk_enable:1;
+
+	unsigned int aif1clk_disable:1;
+	unsigned int aif2clk_disable:1;
+
+	struct mutex fw_lock;
+	int dsp_active;
+	const struct firmware *cur_fw;
+	const struct firmware *mbc;
+	const struct firmware *mbc_vss;
+	const struct firmware *enh_eq;
+};
+
+#endif
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
new file mode 100644
index 0000000..68c99fe
--- /dev/null
+++ b/sound/soc/codecs/wm8995.c
@@ -0,0 +1,2331 @@
+/*
+ * wm8995.c  --  WM8995 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * Based on wm8994.c and wm_hubs.c by Mark Brown
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8995.h"
+
+#define WM8995_NUM_SUPPLIES 8
+static const char *wm8995_supply_names[WM8995_NUM_SUPPLIES] = {
+	"DCVDD",
+	"DBVDD1",
+	"DBVDD2",
+	"DBVDD3",
+	"AVDD1",
+	"AVDD2",
+	"CPVDD",
+	"MICVDD"
+};
+
+static const struct reg_default wm8995_reg_defaults[] = {
+	{ 0, 0x8995 },
+	{ 5, 0x0100 },
+	{ 16, 0x000b },
+	{ 17, 0x000b },
+	{ 24, 0x02c0 },
+	{ 25, 0x02c0 },
+	{ 26, 0x02c0 },
+	{ 27, 0x02c0 },
+	{ 28, 0x000f },
+	{ 32, 0x0005 },
+	{ 33, 0x0005 },
+	{ 40, 0x0003 },
+	{ 41, 0x0013 },
+	{ 48, 0x0004 },
+	{ 56, 0x09f8 },
+	{ 64, 0x1f25 },
+	{ 69, 0x0004 },
+	{ 82, 0xaaaa },
+	{ 84, 0x2a2a },
+	{ 146, 0x0060 },
+	{ 256, 0x0002 },
+	{ 257, 0x8004 },
+	{ 520, 0x0010 },
+	{ 528, 0x0083 },
+	{ 529, 0x0083 },
+	{ 548, 0x0c80 },
+	{ 580, 0x0c80 },
+	{ 768, 0x4050 },
+	{ 769, 0x4000 },
+	{ 771, 0x0040 },
+	{ 772, 0x0040 },
+	{ 773, 0x0040 },
+	{ 774, 0x0004 },
+	{ 775, 0x0100 },
+	{ 784, 0x4050 },
+	{ 785, 0x4000 },
+	{ 787, 0x0040 },
+	{ 788, 0x0040 },
+	{ 789, 0x0040 },
+	{ 1024, 0x00c0 },
+	{ 1025, 0x00c0 },
+	{ 1026, 0x00c0 },
+	{ 1027, 0x00c0 },
+	{ 1028, 0x00c0 },
+	{ 1029, 0x00c0 },
+	{ 1030, 0x00c0 },
+	{ 1031, 0x00c0 },
+	{ 1056, 0x0200 },
+	{ 1057, 0x0010 },
+	{ 1058, 0x0200 },
+	{ 1059, 0x0010 },
+	{ 1088, 0x0098 },
+	{ 1089, 0x0845 },
+	{ 1104, 0x0098 },
+	{ 1105, 0x0845 },
+	{ 1152, 0x6318 },
+	{ 1153, 0x6300 },
+	{ 1154, 0x0fca },
+	{ 1155, 0x0400 },
+	{ 1156, 0x00d8 },
+	{ 1157, 0x1eb5 },
+	{ 1158, 0xf145 },
+	{ 1159, 0x0b75 },
+	{ 1160, 0x01c5 },
+	{ 1161, 0x1c58 },
+	{ 1162, 0xf373 },
+	{ 1163, 0x0a54 },
+	{ 1164, 0x0558 },
+	{ 1165, 0x168e },
+	{ 1166, 0xf829 },
+	{ 1167, 0x07ad },
+	{ 1168, 0x1103 },
+	{ 1169, 0x0564 },
+	{ 1170, 0x0559 },
+	{ 1171, 0x4000 },
+	{ 1184, 0x6318 },
+	{ 1185, 0x6300 },
+	{ 1186, 0x0fca },
+	{ 1187, 0x0400 },
+	{ 1188, 0x00d8 },
+	{ 1189, 0x1eb5 },
+	{ 1190, 0xf145 },
+	{ 1191, 0x0b75 },
+	{ 1192, 0x01c5 },
+	{ 1193, 0x1c58 },
+	{ 1194, 0xf373 },
+	{ 1195, 0x0a54 },
+	{ 1196, 0x0558 },
+	{ 1197, 0x168e },
+	{ 1198, 0xf829 },
+	{ 1199, 0x07ad },
+	{ 1200, 0x1103 },
+	{ 1201, 0x0564 },
+	{ 1202, 0x0559 },
+	{ 1203, 0x4000 },
+	{ 1280, 0x00c0 },
+	{ 1281, 0x00c0 },
+	{ 1282, 0x00c0 },
+	{ 1283, 0x00c0 },
+	{ 1312, 0x0200 },
+	{ 1313, 0x0010 },
+	{ 1344, 0x0098 },
+	{ 1345, 0x0845 },
+	{ 1408, 0x6318 },
+	{ 1409, 0x6300 },
+	{ 1410, 0x0fca },
+	{ 1411, 0x0400 },
+	{ 1412, 0x00d8 },
+	{ 1413, 0x1eb5 },
+	{ 1414, 0xf145 },
+	{ 1415, 0x0b75 },
+	{ 1416, 0x01c5 },
+	{ 1417, 0x1c58 },
+	{ 1418, 0xf373 },
+	{ 1419, 0x0a54 },
+	{ 1420, 0x0558 },
+	{ 1421, 0x168e },
+	{ 1422, 0xf829 },
+	{ 1423, 0x07ad },
+	{ 1424, 0x1103 },
+	{ 1425, 0x0564 },
+	{ 1426, 0x0559 },
+	{ 1427, 0x4000 },
+	{ 1568, 0x0002 },
+	{ 1792, 0xa100 },
+	{ 1793, 0xa101 },
+	{ 1794, 0xa101 },
+	{ 1795, 0xa101 },
+	{ 1796, 0xa101 },
+	{ 1797, 0xa101 },
+	{ 1798, 0xa101 },
+	{ 1799, 0xa101 },
+	{ 1800, 0xa101 },
+	{ 1801, 0xa101 },
+	{ 1802, 0xa101 },
+	{ 1803, 0xa101 },
+	{ 1804, 0xa101 },
+	{ 1805, 0xa101 },
+	{ 1825, 0x0055 },
+	{ 1848, 0x3fff },
+	{ 1849, 0x1fff },
+	{ 2049, 0x0001 },
+	{ 2050, 0x0069 },
+	{ 2056, 0x0002 },
+	{ 2057, 0x0003 },
+	{ 2058, 0x0069 },
+	{ 12288, 0x0001 },
+	{ 12289, 0x0001 },
+	{ 12291, 0x0006 },
+	{ 12292, 0x0040 },
+	{ 12293, 0x0001 },
+	{ 12294, 0x000f },
+	{ 12295, 0x0006 },
+	{ 12296, 0x0001 },
+	{ 12297, 0x0003 },
+	{ 12298, 0x0104 },
+	{ 12300, 0x0060 },
+	{ 12301, 0x0011 },
+	{ 12302, 0x0401 },
+	{ 12304, 0x0050 },
+	{ 12305, 0x0003 },
+	{ 12306, 0x0100 },
+	{ 12308, 0x0051 },
+	{ 12309, 0x0003 },
+	{ 12310, 0x0104 },
+	{ 12311, 0x000a },
+	{ 12312, 0x0060 },
+	{ 12313, 0x003b },
+	{ 12314, 0x0502 },
+	{ 12315, 0x0100 },
+	{ 12316, 0x2fff },
+	{ 12320, 0x2fff },
+	{ 12324, 0x2fff },
+	{ 12328, 0x2fff },
+	{ 12332, 0x2fff },
+	{ 12336, 0x2fff },
+	{ 12340, 0x2fff },
+	{ 12344, 0x2fff },
+	{ 12348, 0x2fff },
+	{ 12352, 0x0001 },
+	{ 12353, 0x0001 },
+	{ 12355, 0x0006 },
+	{ 12356, 0x0040 },
+	{ 12357, 0x0001 },
+	{ 12358, 0x000f },
+	{ 12359, 0x0006 },
+	{ 12360, 0x0001 },
+	{ 12361, 0x0003 },
+	{ 12362, 0x0104 },
+	{ 12364, 0x0060 },
+	{ 12365, 0x0011 },
+	{ 12366, 0x0401 },
+	{ 12368, 0x0050 },
+	{ 12369, 0x0003 },
+	{ 12370, 0x0100 },
+	{ 12372, 0x0060 },
+	{ 12373, 0x003b },
+	{ 12374, 0x0502 },
+	{ 12375, 0x0100 },
+	{ 12376, 0x2fff },
+	{ 12380, 0x2fff },
+	{ 12384, 0x2fff },
+	{ 12388, 0x2fff },
+	{ 12392, 0x2fff },
+	{ 12396, 0x2fff },
+	{ 12400, 0x2fff },
+	{ 12404, 0x2fff },
+	{ 12408, 0x2fff },
+	{ 12412, 0x2fff },
+	{ 12416, 0x0001 },
+	{ 12417, 0x0001 },
+	{ 12419, 0x0006 },
+	{ 12420, 0x0040 },
+	{ 12421, 0x0001 },
+	{ 12422, 0x000f },
+	{ 12423, 0x0006 },
+	{ 12424, 0x0001 },
+	{ 12425, 0x0003 },
+	{ 12426, 0x0106 },
+	{ 12428, 0x0061 },
+	{ 12429, 0x0011 },
+	{ 12430, 0x0401 },
+	{ 12432, 0x0050 },
+	{ 12433, 0x0003 },
+	{ 12434, 0x0102 },
+	{ 12436, 0x0051 },
+	{ 12437, 0x0003 },
+	{ 12438, 0x0106 },
+	{ 12439, 0x000a },
+	{ 12440, 0x0061 },
+	{ 12441, 0x003b },
+	{ 12442, 0x0502 },
+	{ 12443, 0x0100 },
+	{ 12444, 0x2fff },
+	{ 12448, 0x2fff },
+	{ 12452, 0x2fff },
+	{ 12456, 0x2fff },
+	{ 12460, 0x2fff },
+	{ 12464, 0x2fff },
+	{ 12468, 0x2fff },
+	{ 12472, 0x2fff },
+	{ 12476, 0x2fff },
+	{ 12480, 0x0001 },
+	{ 12481, 0x0001 },
+	{ 12483, 0x0006 },
+	{ 12484, 0x0040 },
+	{ 12485, 0x0001 },
+	{ 12486, 0x000f },
+	{ 12487, 0x0006 },
+	{ 12488, 0x0001 },
+	{ 12489, 0x0003 },
+	{ 12490, 0x0106 },
+	{ 12492, 0x0061 },
+	{ 12493, 0x0011 },
+	{ 12494, 0x0401 },
+	{ 12496, 0x0050 },
+	{ 12497, 0x0003 },
+	{ 12498, 0x0102 },
+	{ 12500, 0x0061 },
+	{ 12501, 0x003b },
+	{ 12502, 0x0502 },
+	{ 12503, 0x0100 },
+	{ 12504, 0x2fff },
+	{ 12508, 0x2fff },
+	{ 12512, 0x2fff },
+	{ 12516, 0x2fff },
+	{ 12520, 0x2fff },
+	{ 12524, 0x2fff },
+	{ 12528, 0x2fff },
+	{ 12532, 0x2fff },
+	{ 12536, 0x2fff },
+	{ 12540, 0x2fff },
+	{ 12544, 0x0060 },
+	{ 12546, 0x0601 },
+	{ 12548, 0x0050 },
+	{ 12550, 0x0100 },
+	{ 12552, 0x0001 },
+	{ 12554, 0x0104 },
+	{ 12555, 0x0100 },
+	{ 12556, 0x2fff },
+	{ 12560, 0x2fff },
+	{ 12564, 0x2fff },
+	{ 12568, 0x2fff },
+	{ 12572, 0x2fff },
+	{ 12576, 0x2fff },
+	{ 12580, 0x2fff },
+	{ 12584, 0x2fff },
+	{ 12588, 0x2fff },
+	{ 12592, 0x2fff },
+	{ 12596, 0x2fff },
+	{ 12600, 0x2fff },
+	{ 12604, 0x2fff },
+	{ 12608, 0x0061 },
+	{ 12610, 0x0601 },
+	{ 12612, 0x0050 },
+	{ 12614, 0x0102 },
+	{ 12616, 0x0001 },
+	{ 12618, 0x0106 },
+	{ 12619, 0x0100 },
+	{ 12620, 0x2fff },
+	{ 12624, 0x2fff },
+	{ 12628, 0x2fff },
+	{ 12632, 0x2fff },
+	{ 12636, 0x2fff },
+	{ 12640, 0x2fff },
+	{ 12644, 0x2fff },
+	{ 12648, 0x2fff },
+	{ 12652, 0x2fff },
+	{ 12656, 0x2fff },
+	{ 12660, 0x2fff },
+	{ 12664, 0x2fff },
+	{ 12668, 0x2fff },
+	{ 12672, 0x0060 },
+	{ 12674, 0x0601 },
+	{ 12676, 0x0061 },
+	{ 12678, 0x0601 },
+	{ 12680, 0x0050 },
+	{ 12682, 0x0300 },
+	{ 12684, 0x0001 },
+	{ 12686, 0x0304 },
+	{ 12688, 0x0040 },
+	{ 12690, 0x000f },
+	{ 12692, 0x0001 },
+	{ 12695, 0x0100 },
+};
+
+struct fll_config {
+	int src;
+	int in;
+	int out;
+};
+
+struct wm8995_priv {
+	struct regmap *regmap;
+	int sysclk[2];
+	int mclk[2];
+	int aifclk[2];
+	struct fll_config fll[2], fll_suspend[2];
+	struct regulator_bulk_data supplies[WM8995_NUM_SUPPLIES];
+	struct notifier_block disable_nb[WM8995_NUM_SUPPLIES];
+	struct snd_soc_component *component;
+};
+
+/*
+ * We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8995_REGULATOR_EVENT(n) \
+static int wm8995_regulator_event_##n(struct notifier_block *nb, \
+				      unsigned long event, void *data)    \
+{ \
+	struct wm8995_priv *wm8995 = container_of(nb, struct wm8995_priv, \
+				     disable_nb[n]); \
+	if (event & REGULATOR_EVENT_DISABLE) { \
+		regcache_mark_dirty(wm8995->regmap);	\
+	} \
+	return 0; \
+}
+
+WM8995_REGULATOR_EVENT(0)
+WM8995_REGULATOR_EVENT(1)
+WM8995_REGULATOR_EVENT(2)
+WM8995_REGULATOR_EVENT(3)
+WM8995_REGULATOR_EVENT(4)
+WM8995_REGULATOR_EVENT(5)
+WM8995_REGULATOR_EVENT(6)
+WM8995_REGULATOR_EVENT(7)
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(in1lr_pga_tlv, -1650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(in1l_boost_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 150, 0);
+
+static const char *in1l_text[] = {
+	"Differential", "Single-ended IN1LN", "Single-ended IN1LP"
+};
+
+static SOC_ENUM_SINGLE_DECL(in1l_enum, WM8995_LEFT_LINE_INPUT_CONTROL,
+			    2, in1l_text);
+
+static const char *in1r_text[] = {
+	"Differential", "Single-ended IN1RN", "Single-ended IN1RP"
+};
+
+static SOC_ENUM_SINGLE_DECL(in1r_enum, WM8995_LEFT_LINE_INPUT_CONTROL,
+			    0, in1r_text);
+
+static const char *dmic_src_text[] = {
+	"DMICDAT1", "DMICDAT2", "DMICDAT3"
+};
+
+static SOC_ENUM_SINGLE_DECL(dmic_src1_enum, WM8995_POWER_MANAGEMENT_5,
+			    8, dmic_src_text);
+static SOC_ENUM_SINGLE_DECL(dmic_src2_enum, WM8995_POWER_MANAGEMENT_5,
+			    6, dmic_src_text);
+
+static const struct snd_kcontrol_new wm8995_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("DAC1 Volume", WM8995_DAC1_LEFT_VOLUME,
+		WM8995_DAC1_RIGHT_VOLUME, 0, 96, 0, digital_tlv),
+	SOC_DOUBLE_R("DAC1 Switch", WM8995_DAC1_LEFT_VOLUME,
+		WM8995_DAC1_RIGHT_VOLUME, 9, 1, 1),
+
+	SOC_DOUBLE_R_TLV("DAC2 Volume", WM8995_DAC2_LEFT_VOLUME,
+		WM8995_DAC2_RIGHT_VOLUME, 0, 96, 0, digital_tlv),
+	SOC_DOUBLE_R("DAC2 Switch", WM8995_DAC2_LEFT_VOLUME,
+		WM8995_DAC2_RIGHT_VOLUME, 9, 1, 1),
+
+	SOC_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8995_AIF1_DAC1_LEFT_VOLUME,
+		WM8995_AIF1_DAC1_RIGHT_VOLUME, 0, 96, 0, digital_tlv),
+	SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8995_AIF1_DAC2_LEFT_VOLUME,
+		WM8995_AIF1_DAC2_RIGHT_VOLUME, 0, 96, 0, digital_tlv),
+	SOC_DOUBLE_R_TLV("AIF2DAC Volume", WM8995_AIF2_DAC_LEFT_VOLUME,
+		WM8995_AIF2_DAC_RIGHT_VOLUME, 0, 96, 0, digital_tlv),
+
+	SOC_DOUBLE_R_TLV("IN1LR Volume", WM8995_LEFT_LINE_INPUT_1_VOLUME,
+		WM8995_RIGHT_LINE_INPUT_1_VOLUME, 0, 31, 0, in1lr_pga_tlv),
+
+	SOC_SINGLE_TLV("IN1L Boost", WM8995_LEFT_LINE_INPUT_CONTROL,
+		4, 3, 0, in1l_boost_tlv),
+
+	SOC_ENUM("IN1L Mode", in1l_enum),
+	SOC_ENUM("IN1R Mode", in1r_enum),
+
+	SOC_ENUM("DMIC1 SRC", dmic_src1_enum),
+	SOC_ENUM("DMIC2 SRC", dmic_src2_enum),
+
+	SOC_DOUBLE_TLV("DAC1 Sidetone Volume", WM8995_DAC1_MIXER_VOLUMES, 0, 5,
+		24, 0, sidetone_tlv),
+	SOC_DOUBLE_TLV("DAC2 Sidetone Volume", WM8995_DAC2_MIXER_VOLUMES, 0, 5,
+		24, 0, sidetone_tlv),
+
+	SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8995_AIF1_ADC1_LEFT_VOLUME,
+		WM8995_AIF1_ADC1_RIGHT_VOLUME, 0, 96, 0, digital_tlv),
+	SOC_DOUBLE_R_TLV("AIF1ADC2 Volume", WM8995_AIF1_ADC2_LEFT_VOLUME,
+		WM8995_AIF1_ADC2_RIGHT_VOLUME, 0, 96, 0, digital_tlv),
+	SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8995_AIF2_ADC_LEFT_VOLUME,
+		WM8995_AIF2_ADC_RIGHT_VOLUME, 0, 96, 0, digital_tlv)
+};
+
+static void wm8995_update_class_w(struct snd_soc_component *component)
+{
+	int enable = 1;
+	int source = 0;  /* GCC flow analysis can't track enable */
+	int reg, reg_r;
+
+	/* We also need the same setting for L/R and only one path */
+	reg = snd_soc_component_read32(component, WM8995_DAC1_LEFT_MIXER_ROUTING);
+	switch (reg) {
+	case WM8995_AIF2DACL_TO_DAC1L:
+		dev_dbg(component->dev, "Class W source AIF2DAC\n");
+		source = 2 << WM8995_CP_DYN_SRC_SEL_SHIFT;
+		break;
+	case WM8995_AIF1DAC2L_TO_DAC1L:
+		dev_dbg(component->dev, "Class W source AIF1DAC2\n");
+		source = 1 << WM8995_CP_DYN_SRC_SEL_SHIFT;
+		break;
+	case WM8995_AIF1DAC1L_TO_DAC1L:
+		dev_dbg(component->dev, "Class W source AIF1DAC1\n");
+		source = 0 << WM8995_CP_DYN_SRC_SEL_SHIFT;
+		break;
+	default:
+		dev_dbg(component->dev, "DAC mixer setting: %x\n", reg);
+		enable = 0;
+		break;
+	}
+
+	reg_r = snd_soc_component_read32(component, WM8995_DAC1_RIGHT_MIXER_ROUTING);
+	if (reg_r != reg) {
+		dev_dbg(component->dev, "Left and right DAC mixers different\n");
+		enable = 0;
+	}
+
+	if (enable) {
+		dev_dbg(component->dev, "Class W enabled\n");
+		snd_soc_component_update_bits(component, WM8995_CLASS_W_1,
+				    WM8995_CP_DYN_PWR_MASK |
+				    WM8995_CP_DYN_SRC_SEL_MASK,
+				    source | WM8995_CP_DYN_PWR);
+	} else {
+		dev_dbg(component->dev, "Class W disabled\n");
+		snd_soc_component_update_bits(component, WM8995_CLASS_W_1,
+				    WM8995_CP_DYN_PWR_MASK, 0);
+	}
+}
+
+static int check_clk_sys(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+	unsigned int reg;
+	const char *clk;
+
+	reg = snd_soc_component_read32(component, WM8995_CLOCKING_1);
+	/* Check what we're currently using for CLK_SYS */
+	if (reg & WM8995_SYSCLK_SRC)
+		clk = "AIF2CLK";
+	else
+		clk = "AIF1CLK";
+	return !strcmp(source->name, clk);
+}
+
+static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	int ret;
+
+	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+	wm8995_update_class_w(component);
+	return ret;
+}
+
+static int hp_supply_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Enable the headphone amp */
+		snd_soc_component_update_bits(component, WM8995_POWER_MANAGEMENT_1,
+				    WM8995_HPOUT1L_ENA_MASK |
+				    WM8995_HPOUT1R_ENA_MASK,
+				    WM8995_HPOUT1L_ENA |
+				    WM8995_HPOUT1R_ENA);
+
+		/* Enable the second stage */
+		snd_soc_component_update_bits(component, WM8995_ANALOGUE_HP_1,
+				    WM8995_HPOUT1L_DLY_MASK |
+				    WM8995_HPOUT1R_DLY_MASK,
+				    WM8995_HPOUT1L_DLY |
+				    WM8995_HPOUT1R_DLY);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, WM8995_CHARGE_PUMP_1,
+				    WM8995_CP_ENA_MASK, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static void dc_servo_cmd(struct snd_soc_component *component,
+			 unsigned int reg, unsigned int val, unsigned int mask)
+{
+	int timeout = 10;
+
+	dev_dbg(component->dev, "%s: reg = %#x, val = %#x, mask = %#x\n",
+		__func__, reg, val, mask);
+
+	snd_soc_component_write(component, reg, val);
+	while (timeout--) {
+		msleep(10);
+		val = snd_soc_component_read32(component, WM8995_DC_SERVO_READBACK_0);
+		if ((val & mask) == mask)
+			return;
+	}
+
+	dev_err(component->dev, "Timed out waiting for DC Servo\n");
+}
+
+static int hp_event(struct snd_soc_dapm_widget *w,
+		    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	unsigned int reg;
+
+	reg = snd_soc_component_read32(component, WM8995_ANALOGUE_HP_1);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, WM8995_CHARGE_PUMP_1,
+				    WM8995_CP_ENA_MASK, WM8995_CP_ENA);
+
+		msleep(5);
+
+		snd_soc_component_update_bits(component, WM8995_POWER_MANAGEMENT_1,
+				    WM8995_HPOUT1L_ENA_MASK |
+				    WM8995_HPOUT1R_ENA_MASK,
+				    WM8995_HPOUT1L_ENA | WM8995_HPOUT1R_ENA);
+
+		udelay(20);
+
+		reg |= WM8995_HPOUT1L_DLY | WM8995_HPOUT1R_DLY;
+		snd_soc_component_write(component, WM8995_ANALOGUE_HP_1, reg);
+
+		snd_soc_component_write(component, WM8995_DC_SERVO_1, WM8995_DCS_ENA_CHAN_0 |
+			      WM8995_DCS_ENA_CHAN_1);
+
+		dc_servo_cmd(component, WM8995_DC_SERVO_2,
+			     WM8995_DCS_TRIG_STARTUP_0 |
+			     WM8995_DCS_TRIG_STARTUP_1,
+			     WM8995_DCS_TRIG_DAC_WR_0 |
+			     WM8995_DCS_TRIG_DAC_WR_1);
+
+		reg |= WM8995_HPOUT1R_OUTP | WM8995_HPOUT1R_RMV_SHORT |
+		       WM8995_HPOUT1L_OUTP | WM8995_HPOUT1L_RMV_SHORT;
+		snd_soc_component_write(component, WM8995_ANALOGUE_HP_1, reg);
+
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, WM8995_ANALOGUE_HP_1,
+				    WM8995_HPOUT1L_OUTP_MASK |
+				    WM8995_HPOUT1R_OUTP_MASK |
+				    WM8995_HPOUT1L_RMV_SHORT_MASK |
+				    WM8995_HPOUT1R_RMV_SHORT_MASK, 0);
+
+		snd_soc_component_update_bits(component, WM8995_ANALOGUE_HP_1,
+				    WM8995_HPOUT1L_DLY_MASK |
+				    WM8995_HPOUT1R_DLY_MASK, 0);
+
+		snd_soc_component_write(component, WM8995_DC_SERVO_1, 0);
+
+		snd_soc_component_update_bits(component, WM8995_POWER_MANAGEMENT_1,
+				    WM8995_HPOUT1L_ENA_MASK |
+				    WM8995_HPOUT1R_ENA_MASK,
+				    0);
+		break;
+	}
+
+	return 0;
+}
+
+static int configure_aif_clock(struct snd_soc_component *component, int aif)
+{
+	struct wm8995_priv *wm8995;
+	int rate;
+	int reg1 = 0;
+	int offset;
+
+	wm8995 = snd_soc_component_get_drvdata(component);
+
+	if (aif)
+		offset = 4;
+	else
+		offset = 0;
+
+	switch (wm8995->sysclk[aif]) {
+	case WM8995_SYSCLK_MCLK1:
+		rate = wm8995->mclk[0];
+		break;
+	case WM8995_SYSCLK_MCLK2:
+		reg1 |= 0x8;
+		rate = wm8995->mclk[1];
+		break;
+	case WM8995_SYSCLK_FLL1:
+		reg1 |= 0x10;
+		rate = wm8995->fll[0].out;
+		break;
+	case WM8995_SYSCLK_FLL2:
+		reg1 |= 0x18;
+		rate = wm8995->fll[1].out;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (rate >= 13500000) {
+		rate /= 2;
+		reg1 |= WM8995_AIF1CLK_DIV;
+
+		dev_dbg(component->dev, "Dividing AIF%d clock to %dHz\n",
+			aif + 1, rate);
+	}
+
+	wm8995->aifclk[aif] = rate;
+
+	snd_soc_component_update_bits(component, WM8995_AIF1_CLOCKING_1 + offset,
+			    WM8995_AIF1CLK_SRC_MASK | WM8995_AIF1CLK_DIV_MASK,
+			    reg1);
+	return 0;
+}
+
+static int configure_clock(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8995_priv *wm8995;
+	int change, new;
+
+	wm8995 = snd_soc_component_get_drvdata(component);
+
+	/* Bring up the AIF clocks first */
+	configure_aif_clock(component, 0);
+	configure_aif_clock(component, 1);
+
+	/*
+	 * Then switch CLK_SYS over to the higher of them; a change
+	 * can only happen as a result of a clocking change which can
+	 * only be made outside of DAPM so we can safely redo the
+	 * clocking.
+	 */
+
+	/* If they're equal it doesn't matter which is used */
+	if (wm8995->aifclk[0] == wm8995->aifclk[1])
+		return 0;
+
+	if (wm8995->aifclk[0] < wm8995->aifclk[1])
+		new = WM8995_SYSCLK_SRC;
+	else
+		new = 0;
+
+	change = snd_soc_component_update_bits(component, WM8995_CLOCKING_1,
+				     WM8995_SYSCLK_SRC_MASK, new);
+	if (!change)
+		return 0;
+
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static int clk_sys_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		return configure_clock(component);
+
+	case SND_SOC_DAPM_POST_PMD:
+		configure_clock(component);
+		break;
+	}
+
+	return 0;
+}
+
+static const char *sidetone_text[] = {
+	"ADC/DMIC1", "DMIC2",
+};
+
+static SOC_ENUM_SINGLE_DECL(sidetone1_enum, WM8995_SIDETONE, 0, sidetone_text);
+
+static const struct snd_kcontrol_new sidetone1_mux =
+	SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum);
+
+static SOC_ENUM_SINGLE_DECL(sidetone2_enum, WM8995_SIDETONE, 1, sidetone_text);
+
+static const struct snd_kcontrol_new sidetone2_mux =
+	SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum);
+
+static const struct snd_kcontrol_new aif1adc1l_mix[] = {
+	SOC_DAPM_SINGLE("ADC/DMIC Switch", WM8995_AIF1_ADC1_LEFT_MIXER_ROUTING,
+		1, 1, 0),
+	SOC_DAPM_SINGLE("AIF2 Switch", WM8995_AIF1_ADC1_LEFT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif1adc1r_mix[] = {
+	SOC_DAPM_SINGLE("ADC/DMIC Switch", WM8995_AIF1_ADC1_RIGHT_MIXER_ROUTING,
+		1, 1, 0),
+	SOC_DAPM_SINGLE("AIF2 Switch", WM8995_AIF1_ADC1_RIGHT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif1adc2l_mix[] = {
+	SOC_DAPM_SINGLE("DMIC Switch", WM8995_AIF1_ADC2_LEFT_MIXER_ROUTING,
+		1, 1, 0),
+	SOC_DAPM_SINGLE("AIF2 Switch", WM8995_AIF1_ADC2_LEFT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif1adc2r_mix[] = {
+	SOC_DAPM_SINGLE("DMIC Switch", WM8995_AIF1_ADC2_RIGHT_MIXER_ROUTING,
+		1, 1, 0),
+	SOC_DAPM_SINGLE("AIF2 Switch", WM8995_AIF1_ADC2_RIGHT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1l_mix[] = {
+	WM8995_CLASS_W_SWITCH("Right Sidetone Switch", WM8995_DAC1_LEFT_MIXER_ROUTING,
+		5, 1, 0),
+	WM8995_CLASS_W_SWITCH("Left Sidetone Switch", WM8995_DAC1_LEFT_MIXER_ROUTING,
+		4, 1, 0),
+	WM8995_CLASS_W_SWITCH("AIF2 Switch", WM8995_DAC1_LEFT_MIXER_ROUTING,
+		2, 1, 0),
+	WM8995_CLASS_W_SWITCH("AIF1.2 Switch", WM8995_DAC1_LEFT_MIXER_ROUTING,
+		1, 1, 0),
+	WM8995_CLASS_W_SWITCH("AIF1.1 Switch", WM8995_DAC1_LEFT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1r_mix[] = {
+	WM8995_CLASS_W_SWITCH("Right Sidetone Switch", WM8995_DAC1_RIGHT_MIXER_ROUTING,
+		5, 1, 0),
+	WM8995_CLASS_W_SWITCH("Left Sidetone Switch", WM8995_DAC1_RIGHT_MIXER_ROUTING,
+		4, 1, 0),
+	WM8995_CLASS_W_SWITCH("AIF2 Switch", WM8995_DAC1_RIGHT_MIXER_ROUTING,
+		2, 1, 0),
+	WM8995_CLASS_W_SWITCH("AIF1.2 Switch", WM8995_DAC1_RIGHT_MIXER_ROUTING,
+		1, 1, 0),
+	WM8995_CLASS_W_SWITCH("AIF1.1 Switch", WM8995_DAC1_RIGHT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif2dac2l_mix[] = {
+	SOC_DAPM_SINGLE("Right Sidetone Switch", WM8995_DAC2_LEFT_MIXER_ROUTING,
+		5, 1, 0),
+	SOC_DAPM_SINGLE("Left Sidetone Switch", WM8995_DAC2_LEFT_MIXER_ROUTING,
+		4, 1, 0),
+	SOC_DAPM_SINGLE("AIF2 Switch", WM8995_DAC2_LEFT_MIXER_ROUTING,
+		2, 1, 0),
+	SOC_DAPM_SINGLE("AIF1.2 Switch", WM8995_DAC2_LEFT_MIXER_ROUTING,
+		1, 1, 0),
+	SOC_DAPM_SINGLE("AIF1.1 Switch", WM8995_DAC2_LEFT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif2dac2r_mix[] = {
+	SOC_DAPM_SINGLE("Right Sidetone Switch", WM8995_DAC2_RIGHT_MIXER_ROUTING,
+		5, 1, 0),
+	SOC_DAPM_SINGLE("Left Sidetone Switch", WM8995_DAC2_RIGHT_MIXER_ROUTING,
+		4, 1, 0),
+	SOC_DAPM_SINGLE("AIF2 Switch", WM8995_DAC2_RIGHT_MIXER_ROUTING,
+		2, 1, 0),
+	SOC_DAPM_SINGLE("AIF1.2 Switch", WM8995_DAC2_RIGHT_MIXER_ROUTING,
+		1, 1, 0),
+	SOC_DAPM_SINGLE("AIF1.1 Switch", WM8995_DAC2_RIGHT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new in1l_pga =
+	SOC_DAPM_SINGLE("IN1L Switch", WM8995_POWER_MANAGEMENT_2, 5, 1, 0);
+
+static const struct snd_kcontrol_new in1r_pga =
+	SOC_DAPM_SINGLE("IN1R Switch", WM8995_POWER_MANAGEMENT_2, 4, 1, 0);
+
+static const char *adc_mux_text[] = {
+	"ADC",
+	"DMIC",
+};
+
+static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text);
+
+static const struct snd_kcontrol_new adcl_mux =
+	SOC_DAPM_ENUM("ADCL Mux", adc_enum);
+
+static const struct snd_kcontrol_new adcr_mux =
+	SOC_DAPM_ENUM("ADCR Mux", adc_enum);
+
+static const char *spk_src_text[] = {
+	"DAC1L", "DAC1R", "DAC2L", "DAC2R"
+};
+
+static SOC_ENUM_SINGLE_DECL(spk1l_src_enum, WM8995_LEFT_PDM_SPEAKER_1,
+			    0, spk_src_text);
+static SOC_ENUM_SINGLE_DECL(spk1r_src_enum, WM8995_RIGHT_PDM_SPEAKER_1,
+			    0, spk_src_text);
+static SOC_ENUM_SINGLE_DECL(spk2l_src_enum, WM8995_LEFT_PDM_SPEAKER_2,
+			    0, spk_src_text);
+static SOC_ENUM_SINGLE_DECL(spk2r_src_enum, WM8995_RIGHT_PDM_SPEAKER_2,
+			    0, spk_src_text);
+
+static const struct snd_kcontrol_new spk1l_mux =
+	SOC_DAPM_ENUM("SPK1L SRC", spk1l_src_enum);
+static const struct snd_kcontrol_new spk1r_mux =
+	SOC_DAPM_ENUM("SPK1R SRC", spk1r_src_enum);
+static const struct snd_kcontrol_new spk2l_mux =
+	SOC_DAPM_ENUM("SPK2L SRC", spk2l_src_enum);
+static const struct snd_kcontrol_new spk2r_mux =
+	SOC_DAPM_ENUM("SPK2R SRC", spk2r_src_enum);
+
+static const struct snd_soc_dapm_widget wm8995_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("DMIC1DAT"),
+	SND_SOC_DAPM_INPUT("DMIC2DAT"),
+
+	SND_SOC_DAPM_INPUT("IN1L"),
+	SND_SOC_DAPM_INPUT("IN1R"),
+
+	SND_SOC_DAPM_MIXER("IN1L PGA", SND_SOC_NOPM, 0, 0,
+		&in1l_pga, 1),
+	SND_SOC_DAPM_MIXER("IN1R PGA", SND_SOC_NOPM, 0, 0,
+		&in1r_pga, 1),
+
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8995_POWER_MANAGEMENT_1, 8, 0,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8995_POWER_MANAGEMENT_1, 9, 0,
+			    NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8995_AIF1_CLOCKING_1, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8995_AIF2_CLOCKING_1, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DSP1CLK", WM8995_CLOCKING_1, 3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DSP2CLK", WM8995_CLOCKING_1, 2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("SYSDSPCLK", WM8995_CLOCKING_1, 1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_AIF_OUT("AIF1ADC1L", "AIF1 Capture", 0,
+		WM8995_POWER_MANAGEMENT_3, 9, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1ADC1R", "AIF1 Capture", 0,
+		WM8995_POWER_MANAGEMENT_3, 8, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1ADCDAT", "AIF1 Capture", 0,
+	SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1ADC2L", "AIF1 Capture",
+		0, WM8995_POWER_MANAGEMENT_3, 11, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", "AIF1 Capture",
+		0, WM8995_POWER_MANAGEMENT_3, 10, 0),
+
+	SND_SOC_DAPM_MUX("ADCL Mux", SND_SOC_NOPM, 1, 0, &adcl_mux),
+	SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0, &adcr_mux),
+
+	SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8995_POWER_MANAGEMENT_3, 5, 0),
+	SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8995_POWER_MANAGEMENT_3, 4, 0),
+	SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8995_POWER_MANAGEMENT_3, 3, 0),
+	SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8995_POWER_MANAGEMENT_3, 2, 0),
+
+	SND_SOC_DAPM_ADC("ADCL", NULL, WM8995_POWER_MANAGEMENT_3, 1, 0),
+	SND_SOC_DAPM_ADC("ADCR", NULL, WM8995_POWER_MANAGEMENT_3, 0, 0),
+
+	SND_SOC_DAPM_MIXER("AIF1ADC1L Mixer", SND_SOC_NOPM, 0, 0,
+		aif1adc1l_mix, ARRAY_SIZE(aif1adc1l_mix)),
+	SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0,
+		aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)),
+	SND_SOC_DAPM_MIXER("AIF1ADC2L Mixer", SND_SOC_NOPM, 0, 0,
+		aif1adc2l_mix, ARRAY_SIZE(aif1adc2l_mix)),
+	SND_SOC_DAPM_MIXER("AIF1ADC2R Mixer", SND_SOC_NOPM, 0, 0,
+		aif1adc2r_mix, ARRAY_SIZE(aif1adc2r_mix)),
+
+	SND_SOC_DAPM_AIF_IN("AIF1DAC1L", NULL, 0, WM8995_POWER_MANAGEMENT_4,
+		9, 0),
+	SND_SOC_DAPM_AIF_IN("AIF1DAC1R", NULL, 0, WM8995_POWER_MANAGEMENT_4,
+		8, 0),
+	SND_SOC_DAPM_AIF_IN("AIF1DACDAT", "AIF1 Playback", 0, SND_SOC_NOPM,
+		0, 0),
+
+	SND_SOC_DAPM_AIF_IN("AIF1DAC2L", NULL, 0, WM8995_POWER_MANAGEMENT_4,
+		11, 0),
+	SND_SOC_DAPM_AIF_IN("AIF1DAC2R", NULL, 0, WM8995_POWER_MANAGEMENT_4,
+		10, 0),
+
+	SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0,
+		aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)),
+	SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0,
+		aif2dac2r_mix, ARRAY_SIZE(aif2dac2r_mix)),
+
+	SND_SOC_DAPM_DAC("DAC2L", NULL, WM8995_POWER_MANAGEMENT_4, 3, 0),
+	SND_SOC_DAPM_DAC("DAC2R", NULL, WM8995_POWER_MANAGEMENT_4, 2, 0),
+	SND_SOC_DAPM_DAC("DAC1L", NULL, WM8995_POWER_MANAGEMENT_4, 1, 0),
+	SND_SOC_DAPM_DAC("DAC1R", NULL, WM8995_POWER_MANAGEMENT_4, 0, 0),
+
+	SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0, dac1l_mix,
+		ARRAY_SIZE(dac1l_mix)),
+	SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0, dac1r_mix,
+		ARRAY_SIZE(dac1r_mix)),
+
+	SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &sidetone1_mux),
+	SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &sidetone2_mux),
+
+	SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
+		hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0,
+		hp_supply_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_MUX("SPK1L Driver", WM8995_LEFT_PDM_SPEAKER_1,
+		4, 0, &spk1l_mux),
+	SND_SOC_DAPM_MUX("SPK1R Driver", WM8995_RIGHT_PDM_SPEAKER_1,
+		4, 0, &spk1r_mux),
+	SND_SOC_DAPM_MUX("SPK2L Driver", WM8995_LEFT_PDM_SPEAKER_2,
+		4, 0, &spk2l_mux),
+	SND_SOC_DAPM_MUX("SPK2R Driver", WM8995_RIGHT_PDM_SPEAKER_2,
+		4, 0, &spk2r_mux),
+
+	SND_SOC_DAPM_SUPPLY("LDO2", WM8995_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
+
+	SND_SOC_DAPM_OUTPUT("HP1L"),
+	SND_SOC_DAPM_OUTPUT("HP1R"),
+	SND_SOC_DAPM_OUTPUT("SPK1L"),
+	SND_SOC_DAPM_OUTPUT("SPK1R"),
+	SND_SOC_DAPM_OUTPUT("SPK2L"),
+	SND_SOC_DAPM_OUTPUT("SPK2R")
+};
+
+static const struct snd_soc_dapm_route wm8995_intercon[] = {
+	{ "CLK_SYS", NULL, "AIF1CLK", check_clk_sys },
+	{ "CLK_SYS", NULL, "AIF2CLK", check_clk_sys },
+
+	{ "DSP1CLK", NULL, "CLK_SYS" },
+	{ "DSP2CLK", NULL, "CLK_SYS" },
+	{ "SYSDSPCLK", NULL, "CLK_SYS" },
+
+	{ "AIF1ADC1L", NULL, "AIF1CLK" },
+	{ "AIF1ADC1L", NULL, "DSP1CLK" },
+	{ "AIF1ADC1R", NULL, "AIF1CLK" },
+	{ "AIF1ADC1R", NULL, "DSP1CLK" },
+	{ "AIF1ADC1R", NULL, "SYSDSPCLK" },
+
+	{ "AIF1ADC2L", NULL, "AIF1CLK" },
+	{ "AIF1ADC2L", NULL, "DSP1CLK" },
+	{ "AIF1ADC2R", NULL, "AIF1CLK" },
+	{ "AIF1ADC2R", NULL, "DSP1CLK" },
+	{ "AIF1ADC2R", NULL, "SYSDSPCLK" },
+
+	{ "DMIC1L", NULL, "DMIC1DAT" },
+	{ "DMIC1L", NULL, "CLK_SYS" },
+	{ "DMIC1R", NULL, "DMIC1DAT" },
+	{ "DMIC1R", NULL, "CLK_SYS" },
+	{ "DMIC2L", NULL, "DMIC2DAT" },
+	{ "DMIC2L", NULL, "CLK_SYS" },
+	{ "DMIC2R", NULL, "DMIC2DAT" },
+	{ "DMIC2R", NULL, "CLK_SYS" },
+
+	{ "ADCL", NULL, "AIF1CLK" },
+	{ "ADCL", NULL, "DSP1CLK" },
+	{ "ADCL", NULL, "SYSDSPCLK" },
+
+	{ "ADCR", NULL, "AIF1CLK" },
+	{ "ADCR", NULL, "DSP1CLK" },
+	{ "ADCR", NULL, "SYSDSPCLK" },
+
+	{ "IN1L PGA", "IN1L Switch", "IN1L" },
+	{ "IN1R PGA", "IN1R Switch", "IN1R" },
+	{ "IN1L PGA", NULL, "LDO2" },
+	{ "IN1R PGA", NULL, "LDO2" },
+
+	{ "ADCL", NULL, "IN1L PGA" },
+	{ "ADCR", NULL, "IN1R PGA" },
+
+	{ "ADCL Mux", "ADC", "ADCL" },
+	{ "ADCL Mux", "DMIC", "DMIC1L" },
+	{ "ADCR Mux", "ADC", "ADCR" },
+	{ "ADCR Mux", "DMIC", "DMIC1R" },
+
+	/* AIF1 outputs */
+	{ "AIF1ADC1L", NULL, "AIF1ADC1L Mixer" },
+	{ "AIF1ADC1L Mixer", "ADC/DMIC Switch", "ADCL Mux" },
+
+	{ "AIF1ADC1R", NULL, "AIF1ADC1R Mixer" },
+	{ "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" },
+
+	{ "AIF1ADC2L", NULL, "AIF1ADC2L Mixer" },
+	{ "AIF1ADC2L Mixer", "DMIC Switch", "DMIC2L" },
+
+	{ "AIF1ADC2R", NULL, "AIF1ADC2R Mixer" },
+	{ "AIF1ADC2R Mixer", "DMIC Switch", "DMIC2R" },
+
+	/* Sidetone */
+	{ "Left Sidetone", "ADC/DMIC1", "AIF1ADC1L" },
+	{ "Left Sidetone", "DMIC2", "AIF1ADC2L" },
+	{ "Right Sidetone", "ADC/DMIC1", "AIF1ADC1R" },
+	{ "Right Sidetone", "DMIC2", "AIF1ADC2R" },
+
+	{ "AIF1DAC1L", NULL, "AIF1CLK" },
+	{ "AIF1DAC1L", NULL, "DSP1CLK" },
+	{ "AIF1DAC1R", NULL, "AIF1CLK" },
+	{ "AIF1DAC1R", NULL, "DSP1CLK" },
+	{ "AIF1DAC1R", NULL, "SYSDSPCLK" },
+
+	{ "AIF1DAC2L", NULL, "AIF1CLK" },
+	{ "AIF1DAC2L", NULL, "DSP1CLK" },
+	{ "AIF1DAC2R", NULL, "AIF1CLK" },
+	{ "AIF1DAC2R", NULL, "DSP1CLK" },
+	{ "AIF1DAC2R", NULL, "SYSDSPCLK" },
+
+	{ "DAC1L", NULL, "AIF1CLK" },
+	{ "DAC1L", NULL, "DSP1CLK" },
+	{ "DAC1L", NULL, "SYSDSPCLK" },
+
+	{ "DAC1R", NULL, "AIF1CLK" },
+	{ "DAC1R", NULL, "DSP1CLK" },
+	{ "DAC1R", NULL, "SYSDSPCLK" },
+
+	{ "AIF1DAC1L", NULL, "AIF1DACDAT" },
+	{ "AIF1DAC1R", NULL, "AIF1DACDAT" },
+	{ "AIF1DAC2L", NULL, "AIF1DACDAT" },
+	{ "AIF1DAC2R", NULL, "AIF1DACDAT" },
+
+	/* DAC1 inputs */
+	{ "DAC1L", NULL, "DAC1L Mixer" },
+	{ "DAC1L Mixer", "AIF1.1 Switch", "AIF1DAC1L" },
+	{ "DAC1L Mixer", "AIF1.2 Switch", "AIF1DAC2L" },
+	{ "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+	{ "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+
+	{ "DAC1R", NULL, "DAC1R Mixer" },
+	{ "DAC1R Mixer", "AIF1.1 Switch", "AIF1DAC1R" },
+	{ "DAC1R Mixer", "AIF1.2 Switch", "AIF1DAC2R" },
+	{ "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+	{ "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+
+	/* DAC2/AIF2 outputs */
+	{ "DAC2L", NULL, "AIF2DAC2L Mixer" },
+	{ "AIF2DAC2L Mixer", "AIF1.2 Switch", "AIF1DAC2L" },
+	{ "AIF2DAC2L Mixer", "AIF1.1 Switch", "AIF1DAC1L" },
+
+	{ "DAC2R", NULL, "AIF2DAC2R Mixer" },
+	{ "AIF2DAC2R Mixer", "AIF1.2 Switch", "AIF1DAC2R" },
+	{ "AIF2DAC2R Mixer", "AIF1.1 Switch", "AIF1DAC1R" },
+
+	/* Output stages */
+	{ "Headphone PGA", NULL, "DAC1L" },
+	{ "Headphone PGA", NULL, "DAC1R" },
+
+	{ "Headphone PGA", NULL, "DAC2L" },
+	{ "Headphone PGA", NULL, "DAC2R" },
+
+	{ "Headphone PGA", NULL, "Headphone Supply" },
+	{ "Headphone PGA", NULL, "CLK_SYS" },
+	{ "Headphone PGA", NULL, "LDO2" },
+
+	{ "HP1L", NULL, "Headphone PGA" },
+	{ "HP1R", NULL, "Headphone PGA" },
+
+	{ "SPK1L Driver", "DAC1L", "DAC1L" },
+	{ "SPK1L Driver", "DAC1R", "DAC1R" },
+	{ "SPK1L Driver", "DAC2L", "DAC2L" },
+	{ "SPK1L Driver", "DAC2R", "DAC2R" },
+	{ "SPK1L Driver", NULL, "CLK_SYS" },
+
+	{ "SPK1R Driver", "DAC1L", "DAC1L" },
+	{ "SPK1R Driver", "DAC1R", "DAC1R" },
+	{ "SPK1R Driver", "DAC2L", "DAC2L" },
+	{ "SPK1R Driver", "DAC2R", "DAC2R" },
+	{ "SPK1R Driver", NULL, "CLK_SYS" },
+
+	{ "SPK2L Driver", "DAC1L", "DAC1L" },
+	{ "SPK2L Driver", "DAC1R", "DAC1R" },
+	{ "SPK2L Driver", "DAC2L", "DAC2L" },
+	{ "SPK2L Driver", "DAC2R", "DAC2R" },
+	{ "SPK2L Driver", NULL, "CLK_SYS" },
+
+	{ "SPK2R Driver", "DAC1L", "DAC1L" },
+	{ "SPK2R Driver", "DAC1R", "DAC1R" },
+	{ "SPK2R Driver", "DAC2L", "DAC2L" },
+	{ "SPK2R Driver", "DAC2R", "DAC2R" },
+	{ "SPK2R Driver", NULL, "CLK_SYS" },
+
+	{ "SPK1L", NULL, "SPK1L Driver" },
+	{ "SPK1R", NULL, "SPK1R Driver" },
+	{ "SPK2L", NULL, "SPK2L Driver" },
+	{ "SPK2R", NULL, "SPK2R Driver" }
+};
+
+static bool wm8995_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8995_SOFTWARE_RESET:
+	case WM8995_POWER_MANAGEMENT_1:
+	case WM8995_POWER_MANAGEMENT_2:
+	case WM8995_POWER_MANAGEMENT_3:
+	case WM8995_POWER_MANAGEMENT_4:
+	case WM8995_POWER_MANAGEMENT_5:
+	case WM8995_LEFT_LINE_INPUT_1_VOLUME:
+	case WM8995_RIGHT_LINE_INPUT_1_VOLUME:
+	case WM8995_LEFT_LINE_INPUT_CONTROL:
+	case WM8995_DAC1_LEFT_VOLUME:
+	case WM8995_DAC1_RIGHT_VOLUME:
+	case WM8995_DAC2_LEFT_VOLUME:
+	case WM8995_DAC2_RIGHT_VOLUME:
+	case WM8995_OUTPUT_VOLUME_ZC_1:
+	case WM8995_MICBIAS_1:
+	case WM8995_MICBIAS_2:
+	case WM8995_LDO_1:
+	case WM8995_LDO_2:
+	case WM8995_ACCESSORY_DETECT_MODE1:
+	case WM8995_ACCESSORY_DETECT_MODE2:
+	case WM8995_HEADPHONE_DETECT1:
+	case WM8995_HEADPHONE_DETECT2:
+	case WM8995_MIC_DETECT_1:
+	case WM8995_MIC_DETECT_2:
+	case WM8995_CHARGE_PUMP_1:
+	case WM8995_CLASS_W_1:
+	case WM8995_DC_SERVO_1:
+	case WM8995_DC_SERVO_2:
+	case WM8995_DC_SERVO_3:
+	case WM8995_DC_SERVO_5:
+	case WM8995_DC_SERVO_6:
+	case WM8995_DC_SERVO_7:
+	case WM8995_DC_SERVO_READBACK_0:
+	case WM8995_ANALOGUE_HP_1:
+	case WM8995_ANALOGUE_HP_2:
+	case WM8995_CHIP_REVISION:
+	case WM8995_CONTROL_INTERFACE_1:
+	case WM8995_CONTROL_INTERFACE_2:
+	case WM8995_WRITE_SEQUENCER_CTRL_1:
+	case WM8995_WRITE_SEQUENCER_CTRL_2:
+	case WM8995_AIF1_CLOCKING_1:
+	case WM8995_AIF1_CLOCKING_2:
+	case WM8995_AIF2_CLOCKING_1:
+	case WM8995_AIF2_CLOCKING_2:
+	case WM8995_CLOCKING_1:
+	case WM8995_CLOCKING_2:
+	case WM8995_AIF1_RATE:
+	case WM8995_AIF2_RATE:
+	case WM8995_RATE_STATUS:
+	case WM8995_FLL1_CONTROL_1:
+	case WM8995_FLL1_CONTROL_2:
+	case WM8995_FLL1_CONTROL_3:
+	case WM8995_FLL1_CONTROL_4:
+	case WM8995_FLL1_CONTROL_5:
+	case WM8995_FLL2_CONTROL_1:
+	case WM8995_FLL2_CONTROL_2:
+	case WM8995_FLL2_CONTROL_3:
+	case WM8995_FLL2_CONTROL_4:
+	case WM8995_FLL2_CONTROL_5:
+	case WM8995_AIF1_CONTROL_1:
+	case WM8995_AIF1_CONTROL_2:
+	case WM8995_AIF1_MASTER_SLAVE:
+	case WM8995_AIF1_BCLK:
+	case WM8995_AIF1ADC_LRCLK:
+	case WM8995_AIF1DAC_LRCLK:
+	case WM8995_AIF1DAC_DATA:
+	case WM8995_AIF1ADC_DATA:
+	case WM8995_AIF2_CONTROL_1:
+	case WM8995_AIF2_CONTROL_2:
+	case WM8995_AIF2_MASTER_SLAVE:
+	case WM8995_AIF2_BCLK:
+	case WM8995_AIF2ADC_LRCLK:
+	case WM8995_AIF2DAC_LRCLK:
+	case WM8995_AIF2DAC_DATA:
+	case WM8995_AIF2ADC_DATA:
+	case WM8995_AIF1_ADC1_LEFT_VOLUME:
+	case WM8995_AIF1_ADC1_RIGHT_VOLUME:
+	case WM8995_AIF1_DAC1_LEFT_VOLUME:
+	case WM8995_AIF1_DAC1_RIGHT_VOLUME:
+	case WM8995_AIF1_ADC2_LEFT_VOLUME:
+	case WM8995_AIF1_ADC2_RIGHT_VOLUME:
+	case WM8995_AIF1_DAC2_LEFT_VOLUME:
+	case WM8995_AIF1_DAC2_RIGHT_VOLUME:
+	case WM8995_AIF1_ADC1_FILTERS:
+	case WM8995_AIF1_ADC2_FILTERS:
+	case WM8995_AIF1_DAC1_FILTERS_1:
+	case WM8995_AIF1_DAC1_FILTERS_2:
+	case WM8995_AIF1_DAC2_FILTERS_1:
+	case WM8995_AIF1_DAC2_FILTERS_2:
+	case WM8995_AIF1_DRC1_1:
+	case WM8995_AIF1_DRC1_2:
+	case WM8995_AIF1_DRC1_3:
+	case WM8995_AIF1_DRC1_4:
+	case WM8995_AIF1_DRC1_5:
+	case WM8995_AIF1_DRC2_1:
+	case WM8995_AIF1_DRC2_2:
+	case WM8995_AIF1_DRC2_3:
+	case WM8995_AIF1_DRC2_4:
+	case WM8995_AIF1_DRC2_5:
+	case WM8995_AIF1_DAC1_EQ_GAINS_1:
+	case WM8995_AIF1_DAC1_EQ_GAINS_2:
+	case WM8995_AIF1_DAC1_EQ_BAND_1_A:
+	case WM8995_AIF1_DAC1_EQ_BAND_1_B:
+	case WM8995_AIF1_DAC1_EQ_BAND_1_PG:
+	case WM8995_AIF1_DAC1_EQ_BAND_2_A:
+	case WM8995_AIF1_DAC1_EQ_BAND_2_B:
+	case WM8995_AIF1_DAC1_EQ_BAND_2_C:
+	case WM8995_AIF1_DAC1_EQ_BAND_2_PG:
+	case WM8995_AIF1_DAC1_EQ_BAND_3_A:
+	case WM8995_AIF1_DAC1_EQ_BAND_3_B:
+	case WM8995_AIF1_DAC1_EQ_BAND_3_C:
+	case WM8995_AIF1_DAC1_EQ_BAND_3_PG:
+	case WM8995_AIF1_DAC1_EQ_BAND_4_A:
+	case WM8995_AIF1_DAC1_EQ_BAND_4_B:
+	case WM8995_AIF1_DAC1_EQ_BAND_4_C:
+	case WM8995_AIF1_DAC1_EQ_BAND_4_PG:
+	case WM8995_AIF1_DAC1_EQ_BAND_5_A:
+	case WM8995_AIF1_DAC1_EQ_BAND_5_B:
+	case WM8995_AIF1_DAC1_EQ_BAND_5_PG:
+	case WM8995_AIF1_DAC2_EQ_GAINS_1:
+	case WM8995_AIF1_DAC2_EQ_GAINS_2:
+	case WM8995_AIF1_DAC2_EQ_BAND_1_A:
+	case WM8995_AIF1_DAC2_EQ_BAND_1_B:
+	case WM8995_AIF1_DAC2_EQ_BAND_1_PG:
+	case WM8995_AIF1_DAC2_EQ_BAND_2_A:
+	case WM8995_AIF1_DAC2_EQ_BAND_2_B:
+	case WM8995_AIF1_DAC2_EQ_BAND_2_C:
+	case WM8995_AIF1_DAC2_EQ_BAND_2_PG:
+	case WM8995_AIF1_DAC2_EQ_BAND_3_A:
+	case WM8995_AIF1_DAC2_EQ_BAND_3_B:
+	case WM8995_AIF1_DAC2_EQ_BAND_3_C:
+	case WM8995_AIF1_DAC2_EQ_BAND_3_PG:
+	case WM8995_AIF1_DAC2_EQ_BAND_4_A:
+	case WM8995_AIF1_DAC2_EQ_BAND_4_B:
+	case WM8995_AIF1_DAC2_EQ_BAND_4_C:
+	case WM8995_AIF1_DAC2_EQ_BAND_4_PG:
+	case WM8995_AIF1_DAC2_EQ_BAND_5_A:
+	case WM8995_AIF1_DAC2_EQ_BAND_5_B:
+	case WM8995_AIF1_DAC2_EQ_BAND_5_PG:
+	case WM8995_AIF2_ADC_LEFT_VOLUME:
+	case WM8995_AIF2_ADC_RIGHT_VOLUME:
+	case WM8995_AIF2_DAC_LEFT_VOLUME:
+	case WM8995_AIF2_DAC_RIGHT_VOLUME:
+	case WM8995_AIF2_ADC_FILTERS:
+	case WM8995_AIF2_DAC_FILTERS_1:
+	case WM8995_AIF2_DAC_FILTERS_2:
+	case WM8995_AIF2_DRC_1:
+	case WM8995_AIF2_DRC_2:
+	case WM8995_AIF2_DRC_3:
+	case WM8995_AIF2_DRC_4:
+	case WM8995_AIF2_DRC_5:
+	case WM8995_AIF2_EQ_GAINS_1:
+	case WM8995_AIF2_EQ_GAINS_2:
+	case WM8995_AIF2_EQ_BAND_1_A:
+	case WM8995_AIF2_EQ_BAND_1_B:
+	case WM8995_AIF2_EQ_BAND_1_PG:
+	case WM8995_AIF2_EQ_BAND_2_A:
+	case WM8995_AIF2_EQ_BAND_2_B:
+	case WM8995_AIF2_EQ_BAND_2_C:
+	case WM8995_AIF2_EQ_BAND_2_PG:
+	case WM8995_AIF2_EQ_BAND_3_A:
+	case WM8995_AIF2_EQ_BAND_3_B:
+	case WM8995_AIF2_EQ_BAND_3_C:
+	case WM8995_AIF2_EQ_BAND_3_PG:
+	case WM8995_AIF2_EQ_BAND_4_A:
+	case WM8995_AIF2_EQ_BAND_4_B:
+	case WM8995_AIF2_EQ_BAND_4_C:
+	case WM8995_AIF2_EQ_BAND_4_PG:
+	case WM8995_AIF2_EQ_BAND_5_A:
+	case WM8995_AIF2_EQ_BAND_5_B:
+	case WM8995_AIF2_EQ_BAND_5_PG:
+	case WM8995_DAC1_MIXER_VOLUMES:
+	case WM8995_DAC1_LEFT_MIXER_ROUTING:
+	case WM8995_DAC1_RIGHT_MIXER_ROUTING:
+	case WM8995_DAC2_MIXER_VOLUMES:
+	case WM8995_DAC2_LEFT_MIXER_ROUTING:
+	case WM8995_DAC2_RIGHT_MIXER_ROUTING:
+	case WM8995_AIF1_ADC1_LEFT_MIXER_ROUTING:
+	case WM8995_AIF1_ADC1_RIGHT_MIXER_ROUTING:
+	case WM8995_AIF1_ADC2_LEFT_MIXER_ROUTING:
+	case WM8995_AIF1_ADC2_RIGHT_MIXER_ROUTING:
+	case WM8995_DAC_SOFTMUTE:
+	case WM8995_OVERSAMPLING:
+	case WM8995_SIDETONE:
+	case WM8995_GPIO_1:
+	case WM8995_GPIO_2:
+	case WM8995_GPIO_3:
+	case WM8995_GPIO_4:
+	case WM8995_GPIO_5:
+	case WM8995_GPIO_6:
+	case WM8995_GPIO_7:
+	case WM8995_GPIO_8:
+	case WM8995_GPIO_9:
+	case WM8995_GPIO_10:
+	case WM8995_GPIO_11:
+	case WM8995_GPIO_12:
+	case WM8995_GPIO_13:
+	case WM8995_GPIO_14:
+	case WM8995_PULL_CONTROL_1:
+	case WM8995_PULL_CONTROL_2:
+	case WM8995_INTERRUPT_STATUS_1:
+	case WM8995_INTERRUPT_STATUS_2:
+	case WM8995_INTERRUPT_RAW_STATUS_2:
+	case WM8995_INTERRUPT_STATUS_1_MASK:
+	case WM8995_INTERRUPT_STATUS_2_MASK:
+	case WM8995_INTERRUPT_CONTROL:
+	case WM8995_LEFT_PDM_SPEAKER_1:
+	case WM8995_RIGHT_PDM_SPEAKER_1:
+	case WM8995_PDM_SPEAKER_1_MUTE_SEQUENCE:
+	case WM8995_LEFT_PDM_SPEAKER_2:
+	case WM8995_RIGHT_PDM_SPEAKER_2:
+	case WM8995_PDM_SPEAKER_2_MUTE_SEQUENCE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm8995_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8995_SOFTWARE_RESET:
+	case WM8995_DC_SERVO_READBACK_0:
+	case WM8995_INTERRUPT_STATUS_1:
+	case WM8995_INTERRUPT_STATUS_2:
+	case WM8995_INTERRUPT_CONTROL:
+	case WM8995_ACCESSORY_DETECT_MODE1:
+	case WM8995_ACCESSORY_DETECT_MODE2:
+	case WM8995_HEADPHONE_DETECT1:
+	case WM8995_HEADPHONE_DETECT2:
+	case WM8995_RATE_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int wm8995_aif_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_component *component = dai->component;
+	int mute_reg;
+
+	switch (dai->id) {
+	case 0:
+		mute_reg = WM8995_AIF1_DAC1_FILTERS_1;
+		break;
+	case 1:
+		mute_reg = WM8995_AIF2_DAC_FILTERS_1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, mute_reg, WM8995_AIF1DAC1_MUTE_MASK,
+			    !!mute << WM8995_AIF1DAC1_MUTE_SHIFT);
+	return 0;
+}
+
+static int wm8995_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component;
+	int master;
+	int aif;
+
+	component = dai->component;
+
+	master = 0;
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		master = WM8995_AIF1_MSTR;
+		break;
+	default:
+		dev_err(dai->dev, "Unknown master/slave configuration\n");
+		return -EINVAL;
+	}
+
+	aif = 0;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_B:
+		aif |= WM8995_AIF1_LRCLK_INV;
+		/* fall through */
+	case SND_SOC_DAIFMT_DSP_A:
+		aif |= (0x3 << WM8995_AIF1_FMT_SHIFT);
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aif |= (0x2 << WM8995_AIF1_FMT_SHIFT);
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif |= (0x1 << WM8995_AIF1_FMT_SHIFT);
+		break;
+	default:
+		dev_err(dai->dev, "Unknown dai format\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		/* frame inversion not valid for DSP modes */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif |= WM8995_AIF1_BCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			aif |= WM8995_AIF1_BCLK_INV | WM8995_AIF1_LRCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif |= WM8995_AIF1_BCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			aif |= WM8995_AIF1_LRCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, WM8995_AIF1_CONTROL_1,
+			    WM8995_AIF1_BCLK_INV_MASK |
+			    WM8995_AIF1_LRCLK_INV_MASK |
+			    WM8995_AIF1_FMT_MASK, aif);
+	snd_soc_component_update_bits(component, WM8995_AIF1_MASTER_SLAVE,
+			    WM8995_AIF1_MSTR_MASK, master);
+	return 0;
+}
+
+static const int srs[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100,
+	48000, 88200, 96000
+};
+
+static const int fs_ratios[] = {
+	-1 /* reserved */,
+	128, 192, 256, 384, 512, 768, 1024, 1408, 1536
+};
+
+static const int bclk_divs[] = {
+	10, 15, 20, 30, 40, 55, 60, 80, 110, 120, 160, 220, 240, 320, 440, 480
+};
+
+static int wm8995_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component;
+	struct wm8995_priv *wm8995;
+	int aif1_reg;
+	int bclk_reg;
+	int lrclk_reg;
+	int rate_reg;
+	int bclk_rate;
+	int aif1;
+	int lrclk, bclk;
+	int i, rate_val, best, best_val, cur_val;
+
+	component = dai->component;
+	wm8995 = snd_soc_component_get_drvdata(component);
+
+	switch (dai->id) {
+	case 0:
+		aif1_reg = WM8995_AIF1_CONTROL_1;
+		bclk_reg = WM8995_AIF1_BCLK;
+		rate_reg = WM8995_AIF1_RATE;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK /* ||
+			wm8995->lrclk_shared[0] */) {
+			lrclk_reg = WM8995_AIF1DAC_LRCLK;
+		} else {
+			lrclk_reg = WM8995_AIF1ADC_LRCLK;
+			dev_dbg(component->dev, "AIF1 using split LRCLK\n");
+		}
+		break;
+	case 1:
+		aif1_reg = WM8995_AIF2_CONTROL_1;
+		bclk_reg = WM8995_AIF2_BCLK;
+		rate_reg = WM8995_AIF2_RATE;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK /* ||
+		    wm8995->lrclk_shared[1] */) {
+			lrclk_reg = WM8995_AIF2DAC_LRCLK;
+		} else {
+			lrclk_reg = WM8995_AIF2ADC_LRCLK;
+			dev_dbg(component->dev, "AIF2 using split LRCLK\n");
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	bclk_rate = snd_soc_params_to_bclk(params);
+	if (bclk_rate < 0)
+		return bclk_rate;
+
+	aif1 = 0;
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		aif1 |= (0x1 << WM8995_AIF1_WL_SHIFT);
+		break;
+	case 24:
+		aif1 |= (0x2 << WM8995_AIF1_WL_SHIFT);
+		break;
+	case 32:
+		aif1 |= (0x3 << WM8995_AIF1_WL_SHIFT);
+		break;
+	default:
+		dev_err(dai->dev, "Unsupported word length %u\n",
+			params_width(params));
+		return -EINVAL;
+	}
+
+	/* try to find a suitable sample rate */
+	for (i = 0; i < ARRAY_SIZE(srs); ++i)
+		if (srs[i] == params_rate(params))
+			break;
+	if (i == ARRAY_SIZE(srs)) {
+		dev_err(dai->dev, "Sample rate %d is not supported\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	rate_val = i << WM8995_AIF1_SR_SHIFT;
+
+	dev_dbg(dai->dev, "Sample rate is %dHz\n", srs[i]);
+	dev_dbg(dai->dev, "AIF%dCLK is %dHz, target BCLK %dHz\n",
+		dai->id + 1, wm8995->aifclk[dai->id], bclk_rate);
+
+	/* AIFCLK/fs ratio; look for a close match in either direction */
+	best = 1;
+	best_val = abs((fs_ratios[1] * params_rate(params))
+		       - wm8995->aifclk[dai->id]);
+	for (i = 2; i < ARRAY_SIZE(fs_ratios); i++) {
+		cur_val = abs((fs_ratios[i] * params_rate(params))
+			      - wm8995->aifclk[dai->id]);
+		if (cur_val >= best_val)
+			continue;
+		best = i;
+		best_val = cur_val;
+	}
+	rate_val |= best;
+
+	dev_dbg(dai->dev, "Selected AIF%dCLK/fs = %d\n",
+		dai->id + 1, fs_ratios[best]);
+
+	/*
+	 * We may not get quite the right frequency if using
+	 * approximate clocks so look for the closest match that is
+	 * higher than the target (we need to ensure that there enough
+	 * BCLKs to clock out the samples).
+	 */
+	best = 0;
+	bclk = 0;
+	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+		cur_val = (wm8995->aifclk[dai->id] * 10 / bclk_divs[i]) - bclk_rate;
+		if (cur_val < 0) /* BCLK table is sorted */
+			break;
+		best = i;
+	}
+	bclk |= best << WM8995_AIF1_BCLK_DIV_SHIFT;
+
+	bclk_rate = wm8995->aifclk[dai->id] * 10 / bclk_divs[best];
+	dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
+		bclk_divs[best], bclk_rate);
+
+	lrclk = bclk_rate / params_rate(params);
+	dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
+		lrclk, bclk_rate / lrclk);
+
+	snd_soc_component_update_bits(component, aif1_reg,
+			    WM8995_AIF1_WL_MASK, aif1);
+	snd_soc_component_update_bits(component, bclk_reg,
+			    WM8995_AIF1_BCLK_DIV_MASK, bclk);
+	snd_soc_component_update_bits(component, lrclk_reg,
+			    WM8995_AIF1DAC_RATE_MASK, lrclk);
+	snd_soc_component_update_bits(component, rate_reg,
+			    WM8995_AIF1_SR_MASK |
+			    WM8995_AIF1CLK_RATE_MASK, rate_val);
+	return 0;
+}
+
+static int wm8995_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	int reg, val, mask;
+
+	switch (codec_dai->id) {
+	case 0:
+		reg = WM8995_AIF1_MASTER_SLAVE;
+		mask = WM8995_AIF1_TRI;
+		break;
+	case 1:
+		reg = WM8995_AIF2_MASTER_SLAVE;
+		mask = WM8995_AIF2_TRI;
+		break;
+	case 2:
+		reg = WM8995_POWER_MANAGEMENT_5;
+		mask = WM8995_AIF3_TRI;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (tristate)
+		val = mask;
+	else
+		val = 0;
+
+	return snd_soc_component_update_bits(component, reg, mask, val);
+}
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+struct fll_div {
+	u16 outdiv;
+	u16 n;
+	u16 k;
+	u16 clk_ref_div;
+	u16 fll_fratio;
+};
+
+static int wm8995_get_fll_config(struct fll_div *fll,
+				 int freq_in, int freq_out)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod;
+
+	pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out);
+
+	/* Scale the input frequency down to <= 13.5MHz */
+	fll->clk_ref_div = 0;
+	while (freq_in > 13500000) {
+		fll->clk_ref_div++;
+		freq_in /= 2;
+
+		if (fll->clk_ref_div > 3)
+			return -EINVAL;
+	}
+	pr_debug("CLK_REF_DIV=%d, Fref=%dHz\n", fll->clk_ref_div, freq_in);
+
+	/* Scale the output to give 90MHz<=Fvco<=100MHz */
+	fll->outdiv = 3;
+	while (freq_out * (fll->outdiv + 1) < 90000000) {
+		fll->outdiv++;
+		if (fll->outdiv > 63)
+			return -EINVAL;
+	}
+	freq_out *= fll->outdiv + 1;
+	pr_debug("OUTDIV=%d, Fvco=%dHz\n", fll->outdiv, freq_out);
+
+	if (freq_in > 1000000) {
+		fll->fll_fratio = 0;
+	} else if (freq_in > 256000) {
+		fll->fll_fratio = 1;
+		freq_in *= 2;
+	} else if (freq_in > 128000) {
+		fll->fll_fratio = 2;
+		freq_in *= 4;
+	} else if (freq_in > 64000) {
+		fll->fll_fratio = 3;
+		freq_in *= 8;
+	} else {
+		fll->fll_fratio = 4;
+		freq_in *= 16;
+	}
+	pr_debug("FLL_FRATIO=%d, Fref=%dHz\n", fll->fll_fratio, freq_in);
+
+	/* Now, calculate N.K */
+	Ndiv = freq_out / freq_in;
+
+	fll->n = Ndiv;
+	Nmod = freq_out % freq_in;
+	pr_debug("Nmod=%d\n", Nmod);
+
+	/* Calculate fractional part - scale up so we can round. */
+	Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, freq_in);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	fll->k = K / 10;
+
+	pr_debug("N=%x K=%x\n", fll->n, fll->k);
+
+	return 0;
+}
+
+static int wm8995_set_fll(struct snd_soc_dai *dai, int id,
+			  int src, unsigned int freq_in,
+			  unsigned int freq_out)
+{
+	struct snd_soc_component *component;
+	struct wm8995_priv *wm8995;
+	int reg_offset, ret;
+	struct fll_div fll;
+	u16 reg, aif1, aif2;
+
+	component = dai->component;
+	wm8995 = snd_soc_component_get_drvdata(component);
+
+	aif1 = snd_soc_component_read32(component, WM8995_AIF1_CLOCKING_1)
+	       & WM8995_AIF1CLK_ENA;
+
+	aif2 = snd_soc_component_read32(component, WM8995_AIF2_CLOCKING_1)
+	       & WM8995_AIF2CLK_ENA;
+
+	switch (id) {
+	case WM8995_FLL1:
+		reg_offset = 0;
+		id = 0;
+		break;
+	case WM8995_FLL2:
+		reg_offset = 0x20;
+		id = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (src) {
+	case 0:
+		/* Allow no source specification when stopping */
+		if (freq_out)
+			return -EINVAL;
+		break;
+	case WM8995_FLL_SRC_MCLK1:
+	case WM8995_FLL_SRC_MCLK2:
+	case WM8995_FLL_SRC_LRCLK:
+	case WM8995_FLL_SRC_BCLK:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Are we changing anything? */
+	if (wm8995->fll[id].src == src &&
+	    wm8995->fll[id].in == freq_in && wm8995->fll[id].out == freq_out)
+		return 0;
+
+	/* If we're stopping the FLL redo the old config - no
+	 * registers will actually be written but we avoid GCC flow
+	 * analysis bugs spewing warnings.
+	 */
+	if (freq_out)
+		ret = wm8995_get_fll_config(&fll, freq_in, freq_out);
+	else
+		ret = wm8995_get_fll_config(&fll, wm8995->fll[id].in,
+					    wm8995->fll[id].out);
+	if (ret < 0)
+		return ret;
+
+	/* Gate the AIF clocks while we reclock */
+	snd_soc_component_update_bits(component, WM8995_AIF1_CLOCKING_1,
+			    WM8995_AIF1CLK_ENA_MASK, 0);
+	snd_soc_component_update_bits(component, WM8995_AIF2_CLOCKING_1,
+			    WM8995_AIF2CLK_ENA_MASK, 0);
+
+	/* We always need to disable the FLL while reconfiguring */
+	snd_soc_component_update_bits(component, WM8995_FLL1_CONTROL_1 + reg_offset,
+			    WM8995_FLL1_ENA_MASK, 0);
+
+	reg = (fll.outdiv << WM8995_FLL1_OUTDIV_SHIFT) |
+	      (fll.fll_fratio << WM8995_FLL1_FRATIO_SHIFT);
+	snd_soc_component_update_bits(component, WM8995_FLL1_CONTROL_2 + reg_offset,
+			    WM8995_FLL1_OUTDIV_MASK |
+			    WM8995_FLL1_FRATIO_MASK, reg);
+
+	snd_soc_component_write(component, WM8995_FLL1_CONTROL_3 + reg_offset, fll.k);
+
+	snd_soc_component_update_bits(component, WM8995_FLL1_CONTROL_4 + reg_offset,
+			    WM8995_FLL1_N_MASK,
+			    fll.n << WM8995_FLL1_N_SHIFT);
+
+	snd_soc_component_update_bits(component, WM8995_FLL1_CONTROL_5 + reg_offset,
+			    WM8995_FLL1_REFCLK_DIV_MASK |
+			    WM8995_FLL1_REFCLK_SRC_MASK,
+			    (fll.clk_ref_div << WM8995_FLL1_REFCLK_DIV_SHIFT) |
+			    (src - 1));
+
+	if (freq_out)
+		snd_soc_component_update_bits(component, WM8995_FLL1_CONTROL_1 + reg_offset,
+				    WM8995_FLL1_ENA_MASK, WM8995_FLL1_ENA);
+
+	wm8995->fll[id].in = freq_in;
+	wm8995->fll[id].out = freq_out;
+	wm8995->fll[id].src = src;
+
+	/* Enable any gated AIF clocks */
+	snd_soc_component_update_bits(component, WM8995_AIF1_CLOCKING_1,
+			    WM8995_AIF1CLK_ENA_MASK, aif1);
+	snd_soc_component_update_bits(component, WM8995_AIF2_CLOCKING_1,
+			    WM8995_AIF2CLK_ENA_MASK, aif2);
+
+	configure_clock(component);
+
+	return 0;
+}
+
+static int wm8995_set_dai_sysclk(struct snd_soc_dai *dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component;
+	struct wm8995_priv *wm8995;
+
+	component = dai->component;
+	wm8995 = snd_soc_component_get_drvdata(component);
+
+	switch (dai->id) {
+	case 0:
+	case 1:
+		break;
+	default:
+		/* AIF3 shares clocking with AIF1/2 */
+		return -EINVAL;
+	}
+
+	switch (clk_id) {
+	case WM8995_SYSCLK_MCLK1:
+		wm8995->sysclk[dai->id] = WM8995_SYSCLK_MCLK1;
+		wm8995->mclk[0] = freq;
+		dev_dbg(dai->dev, "AIF%d using MCLK1 at %uHz\n",
+			dai->id + 1, freq);
+		break;
+	case WM8995_SYSCLK_MCLK2:
+		wm8995->sysclk[dai->id] = WM8995_SYSCLK_MCLK2;
+		wm8995->mclk[1] = freq;
+		dev_dbg(dai->dev, "AIF%d using MCLK2 at %uHz\n",
+			dai->id + 1, freq);
+		break;
+	case WM8995_SYSCLK_FLL1:
+		wm8995->sysclk[dai->id] = WM8995_SYSCLK_FLL1;
+		dev_dbg(dai->dev, "AIF%d using FLL1\n", dai->id + 1);
+		break;
+	case WM8995_SYSCLK_FLL2:
+		wm8995->sysclk[dai->id] = WM8995_SYSCLK_FLL2;
+		dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id + 1);
+		break;
+	case WM8995_SYSCLK_OPCLK:
+	default:
+		dev_err(dai->dev, "Unknown clock source %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	configure_clock(component);
+
+	return 0;
+}
+
+static int wm8995_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8995_priv *wm8995;
+	int ret;
+
+	wm8995 = snd_soc_component_get_drvdata(component);
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(wm8995->supplies),
+						    wm8995->supplies);
+			if (ret)
+				return ret;
+
+			ret = regcache_sync(wm8995->regmap);
+			if (ret) {
+				dev_err(component->dev,
+					"Failed to sync cache: %d\n", ret);
+				return ret;
+			}
+
+			snd_soc_component_update_bits(component, WM8995_POWER_MANAGEMENT_1,
+					    WM8995_BG_ENA_MASK, WM8995_BG_ENA);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_component_update_bits(component, WM8995_POWER_MANAGEMENT_1,
+				    WM8995_BG_ENA_MASK, 0);
+		regulator_bulk_disable(ARRAY_SIZE(wm8995->supplies),
+				       wm8995->supplies);
+		break;
+	}
+
+	return 0;
+}
+
+static void wm8995_remove(struct snd_soc_component *component)
+{
+	struct wm8995_priv *wm8995;
+	int i;
+
+	wm8995 = snd_soc_component_get_drvdata(component);
+
+	for (i = 0; i < ARRAY_SIZE(wm8995->supplies); ++i)
+		regulator_unregister_notifier(wm8995->supplies[i].consumer,
+					      &wm8995->disable_nb[i]);
+
+	regulator_bulk_free(ARRAY_SIZE(wm8995->supplies), wm8995->supplies);
+}
+
+static int wm8995_probe(struct snd_soc_component *component)
+{
+	struct wm8995_priv *wm8995;
+	int i;
+	int ret;
+
+	wm8995 = snd_soc_component_get_drvdata(component);
+	wm8995->component = component;
+
+	for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++)
+		wm8995->supplies[i].supply = wm8995_supply_names[i];
+
+	ret = regulator_bulk_get(component->dev, ARRAY_SIZE(wm8995->supplies),
+				 wm8995->supplies);
+	if (ret) {
+		dev_err(component->dev, "Failed to request supplies: %d\n", ret);
+		return ret;
+	}
+
+	wm8995->disable_nb[0].notifier_call = wm8995_regulator_event_0;
+	wm8995->disable_nb[1].notifier_call = wm8995_regulator_event_1;
+	wm8995->disable_nb[2].notifier_call = wm8995_regulator_event_2;
+	wm8995->disable_nb[3].notifier_call = wm8995_regulator_event_3;
+	wm8995->disable_nb[4].notifier_call = wm8995_regulator_event_4;
+	wm8995->disable_nb[5].notifier_call = wm8995_regulator_event_5;
+	wm8995->disable_nb[6].notifier_call = wm8995_regulator_event_6;
+	wm8995->disable_nb[7].notifier_call = wm8995_regulator_event_7;
+
+	/* This should really be moved into the regulator core */
+	for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++) {
+		ret = regulator_register_notifier(wm8995->supplies[i].consumer,
+						  &wm8995->disable_nb[i]);
+		if (ret) {
+			dev_err(component->dev,
+				"Failed to register regulator notifier: %d\n",
+				ret);
+		}
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8995->supplies),
+				    wm8995->supplies);
+	if (ret) {
+		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
+		goto err_reg_get;
+	}
+
+	ret = snd_soc_component_read32(component, WM8995_SOFTWARE_RESET);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to read device ID: %d\n", ret);
+		goto err_reg_enable;
+	}
+
+	if (ret != 0x8995) {
+		dev_err(component->dev, "Invalid device ID: %#x\n", ret);
+		ret = -EINVAL;
+		goto err_reg_enable;
+	}
+
+	ret = snd_soc_component_write(component, WM8995_SOFTWARE_RESET, 0);
+	if (ret < 0) {
+		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
+		goto err_reg_enable;
+	}
+
+	/* Latch volume updates (right only; we always do left then right). */
+	snd_soc_component_update_bits(component, WM8995_AIF1_DAC1_RIGHT_VOLUME,
+			    WM8995_AIF1DAC1_VU_MASK, WM8995_AIF1DAC1_VU);
+	snd_soc_component_update_bits(component, WM8995_AIF1_DAC2_RIGHT_VOLUME,
+			    WM8995_AIF1DAC2_VU_MASK, WM8995_AIF1DAC2_VU);
+	snd_soc_component_update_bits(component, WM8995_AIF2_DAC_RIGHT_VOLUME,
+			    WM8995_AIF2DAC_VU_MASK, WM8995_AIF2DAC_VU);
+	snd_soc_component_update_bits(component, WM8995_AIF1_ADC1_RIGHT_VOLUME,
+			    WM8995_AIF1ADC1_VU_MASK, WM8995_AIF1ADC1_VU);
+	snd_soc_component_update_bits(component, WM8995_AIF1_ADC2_RIGHT_VOLUME,
+			    WM8995_AIF1ADC2_VU_MASK, WM8995_AIF1ADC2_VU);
+	snd_soc_component_update_bits(component, WM8995_AIF2_ADC_RIGHT_VOLUME,
+			    WM8995_AIF2ADC_VU_MASK, WM8995_AIF1ADC2_VU);
+	snd_soc_component_update_bits(component, WM8995_DAC1_RIGHT_VOLUME,
+			    WM8995_DAC1_VU_MASK, WM8995_DAC1_VU);
+	snd_soc_component_update_bits(component, WM8995_DAC2_RIGHT_VOLUME,
+			    WM8995_DAC2_VU_MASK, WM8995_DAC2_VU);
+	snd_soc_component_update_bits(component, WM8995_RIGHT_LINE_INPUT_1_VOLUME,
+			    WM8995_IN1_VU_MASK, WM8995_IN1_VU);
+
+	wm8995_update_class_w(component);
+
+	return 0;
+
+err_reg_enable:
+	regulator_bulk_disable(ARRAY_SIZE(wm8995->supplies), wm8995->supplies);
+err_reg_get:
+	regulator_bulk_free(ARRAY_SIZE(wm8995->supplies), wm8995->supplies);
+	return ret;
+}
+
+#define WM8995_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8995_aif1_dai_ops = {
+	.set_sysclk = wm8995_set_dai_sysclk,
+	.set_fmt = wm8995_set_dai_fmt,
+	.hw_params = wm8995_hw_params,
+	.digital_mute = wm8995_aif_mute,
+	.set_pll = wm8995_set_fll,
+	.set_tristate = wm8995_set_tristate,
+};
+
+static const struct snd_soc_dai_ops wm8995_aif2_dai_ops = {
+	.set_sysclk = wm8995_set_dai_sysclk,
+	.set_fmt = wm8995_set_dai_fmt,
+	.hw_params = wm8995_hw_params,
+	.digital_mute = wm8995_aif_mute,
+	.set_pll = wm8995_set_fll,
+	.set_tristate = wm8995_set_tristate,
+};
+
+static const struct snd_soc_dai_ops wm8995_aif3_dai_ops = {
+	.set_tristate = wm8995_set_tristate,
+};
+
+static struct snd_soc_dai_driver wm8995_dai[] = {
+	{
+		.name = "wm8995-aif1",
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_96000,
+			.formats = WM8995_FORMATS
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = WM8995_FORMATS
+		},
+		.ops = &wm8995_aif1_dai_ops
+	},
+	{
+		.name = "wm8995-aif2",
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_96000,
+			.formats = WM8995_FORMATS
+		},
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = WM8995_FORMATS
+		},
+		.ops = &wm8995_aif2_dai_ops
+	},
+	{
+		.name = "wm8995-aif3",
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_96000,
+			.formats = WM8995_FORMATS
+		},
+		.capture = {
+			.stream_name = "AIF3 Capture",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = WM8995_FORMATS
+		},
+		.ops = &wm8995_aif3_dai_ops
+	}
+};
+
+static const struct snd_soc_component_driver soc_component_dev_wm8995 = {
+	.probe			= wm8995_probe,
+	.remove			= wm8995_remove,
+	.set_bias_level		= wm8995_set_bias_level,
+	.controls		= wm8995_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8995_snd_controls),
+	.dapm_widgets		= wm8995_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8995_dapm_widgets),
+	.dapm_routes		= wm8995_intercon,
+	.num_dapm_routes	= ARRAY_SIZE(wm8995_intercon),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm8995_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+
+	.max_register = WM8995_MAX_REGISTER,
+	.reg_defaults = wm8995_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm8995_reg_defaults),
+	.volatile_reg = wm8995_volatile,
+	.readable_reg = wm8995_readable,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int wm8995_spi_probe(struct spi_device *spi)
+{
+	struct wm8995_priv *wm8995;
+	int ret;
+
+	wm8995 = devm_kzalloc(&spi->dev, sizeof(*wm8995), GFP_KERNEL);
+	if (!wm8995)
+		return -ENOMEM;
+
+	spi_set_drvdata(spi, wm8995);
+
+	wm8995->regmap = devm_regmap_init_spi(spi, &wm8995_regmap);
+	if (IS_ERR(wm8995->regmap)) {
+		ret = PTR_ERR(wm8995->regmap);
+		dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&spi->dev,
+				     &soc_component_dev_wm8995, wm8995_dai,
+				     ARRAY_SIZE(wm8995_dai));
+	return ret;
+}
+
+static struct spi_driver wm8995_spi_driver = {
+	.driver = {
+		.name = "wm8995",
+	},
+	.probe = wm8995_spi_probe,
+};
+#endif
+
+#if IS_ENABLED(CONFIG_I2C)
+static int wm8995_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8995_priv *wm8995;
+	int ret;
+
+	wm8995 = devm_kzalloc(&i2c->dev, sizeof(*wm8995), GFP_KERNEL);
+	if (!wm8995)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, wm8995);
+
+	wm8995->regmap = devm_regmap_init_i2c(i2c, &wm8995_regmap);
+	if (IS_ERR(wm8995->regmap)) {
+		ret = PTR_ERR(wm8995->regmap);
+		dev_err(&i2c->dev, "Failed to register regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_wm8995, wm8995_dai,
+				     ARRAY_SIZE(wm8995_dai));
+	if (ret < 0)
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+
+	return ret;
+}
+
+static const struct i2c_device_id wm8995_i2c_id[] = {
+	{"wm8995", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, wm8995_i2c_id);
+
+static struct i2c_driver wm8995_i2c_driver = {
+	.driver = {
+		.name = "wm8995",
+	},
+	.probe = wm8995_i2c_probe,
+	.id_table = wm8995_i2c_id
+};
+#endif
+
+static int __init wm8995_modinit(void)
+{
+	int ret = 0;
+
+#if IS_ENABLED(CONFIG_I2C)
+	ret = i2c_add_driver(&wm8995_i2c_driver);
+	if (ret) {
+		printk(KERN_ERR "Failed to register wm8995 I2C driver: %d\n",
+		       ret);
+	}
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&wm8995_spi_driver);
+	if (ret) {
+		printk(KERN_ERR "Failed to register wm8995 SPI driver: %d\n",
+		       ret);
+	}
+#endif
+	return ret;
+}
+
+module_init(wm8995_modinit);
+
+static void __exit wm8995_exit(void)
+{
+#if IS_ENABLED(CONFIG_I2C)
+	i2c_del_driver(&wm8995_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&wm8995_spi_driver);
+#endif
+}
+
+module_exit(wm8995_exit);
+
+MODULE_DESCRIPTION("ASoC WM8995 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8995.h b/sound/soc/codecs/wm8995.h
new file mode 100644
index 0000000..508ad27
--- /dev/null
+++ b/sound/soc/codecs/wm8995.h
@@ -0,0 +1,4266 @@
+/*
+ * wm8995.h  --  WM8995 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8995_H
+#define _WM8995_H
+
+#include <asm/types.h>
+
+/*
+ * Register values.
+ */
+#define WM8995_SOFTWARE_RESET                   0x00
+#define WM8995_POWER_MANAGEMENT_1               0x01
+#define WM8995_POWER_MANAGEMENT_2               0x02
+#define WM8995_POWER_MANAGEMENT_3               0x03
+#define WM8995_POWER_MANAGEMENT_4               0x04
+#define WM8995_POWER_MANAGEMENT_5               0x05
+#define WM8995_LEFT_LINE_INPUT_1_VOLUME         0x10
+#define WM8995_RIGHT_LINE_INPUT_1_VOLUME        0x11
+#define WM8995_LEFT_LINE_INPUT_CONTROL          0x12
+#define WM8995_DAC1_LEFT_VOLUME                 0x18
+#define WM8995_DAC1_RIGHT_VOLUME                0x19
+#define WM8995_DAC2_LEFT_VOLUME                 0x1A
+#define WM8995_DAC2_RIGHT_VOLUME                0x1B
+#define WM8995_OUTPUT_VOLUME_ZC_1               0x1C
+#define WM8995_MICBIAS_1                        0x20
+#define WM8995_MICBIAS_2                        0x21
+#define WM8995_LDO_1                            0x28
+#define WM8995_LDO_2                            0x29
+#define WM8995_ACCESSORY_DETECT_MODE1           0x30
+#define WM8995_ACCESSORY_DETECT_MODE2           0x31
+#define WM8995_HEADPHONE_DETECT1                0x34
+#define WM8995_HEADPHONE_DETECT2                0x35
+#define WM8995_MIC_DETECT_1                     0x38
+#define WM8995_MIC_DETECT_2                     0x39
+#define WM8995_CHARGE_PUMP_1                    0x40
+#define WM8995_CLASS_W_1                        0x45
+#define WM8995_DC_SERVO_1                       0x50
+#define WM8995_DC_SERVO_2                       0x51
+#define WM8995_DC_SERVO_3                       0x52
+#define WM8995_DC_SERVO_5                       0x54
+#define WM8995_DC_SERVO_6                       0x55
+#define WM8995_DC_SERVO_7                       0x56
+#define WM8995_DC_SERVO_READBACK_0              0x57
+#define WM8995_ANALOGUE_HP_1                    0x60
+#define WM8995_ANALOGUE_HP_2                    0x61
+#define WM8995_CHIP_REVISION                    0x100
+#define WM8995_CONTROL_INTERFACE_1              0x101
+#define WM8995_CONTROL_INTERFACE_2              0x102
+#define WM8995_WRITE_SEQUENCER_CTRL_1           0x110
+#define WM8995_WRITE_SEQUENCER_CTRL_2           0x111
+#define WM8995_AIF1_CLOCKING_1                  0x200
+#define WM8995_AIF1_CLOCKING_2                  0x201
+#define WM8995_AIF2_CLOCKING_1                  0x204
+#define WM8995_AIF2_CLOCKING_2                  0x205
+#define WM8995_CLOCKING_1                       0x208
+#define WM8995_CLOCKING_2                       0x209
+#define WM8995_AIF1_RATE                        0x210
+#define WM8995_AIF2_RATE                        0x211
+#define WM8995_RATE_STATUS                      0x212
+#define WM8995_FLL1_CONTROL_1                   0x220
+#define WM8995_FLL1_CONTROL_2                   0x221
+#define WM8995_FLL1_CONTROL_3                   0x222
+#define WM8995_FLL1_CONTROL_4                   0x223
+#define WM8995_FLL1_CONTROL_5                   0x224
+#define WM8995_FLL2_CONTROL_1                   0x240
+#define WM8995_FLL2_CONTROL_2                   0x241
+#define WM8995_FLL2_CONTROL_3                   0x242
+#define WM8995_FLL2_CONTROL_4                   0x243
+#define WM8995_FLL2_CONTROL_5                   0x244
+#define WM8995_AIF1_CONTROL_1                   0x300
+#define WM8995_AIF1_CONTROL_2                   0x301
+#define WM8995_AIF1_MASTER_SLAVE                0x302
+#define WM8995_AIF1_BCLK                        0x303
+#define WM8995_AIF1ADC_LRCLK                    0x304
+#define WM8995_AIF1DAC_LRCLK                    0x305
+#define WM8995_AIF1DAC_DATA                     0x306
+#define WM8995_AIF1ADC_DATA                     0x307
+#define WM8995_AIF2_CONTROL_1                   0x310
+#define WM8995_AIF2_CONTROL_2                   0x311
+#define WM8995_AIF2_MASTER_SLAVE                0x312
+#define WM8995_AIF2_BCLK                        0x313
+#define WM8995_AIF2ADC_LRCLK                    0x314
+#define WM8995_AIF2DAC_LRCLK                    0x315
+#define WM8995_AIF2DAC_DATA                     0x316
+#define WM8995_AIF2ADC_DATA                     0x317
+#define WM8995_AIF1_ADC1_LEFT_VOLUME            0x400
+#define WM8995_AIF1_ADC1_RIGHT_VOLUME           0x401
+#define WM8995_AIF1_DAC1_LEFT_VOLUME            0x402
+#define WM8995_AIF1_DAC1_RIGHT_VOLUME           0x403
+#define WM8995_AIF1_ADC2_LEFT_VOLUME            0x404
+#define WM8995_AIF1_ADC2_RIGHT_VOLUME           0x405
+#define WM8995_AIF1_DAC2_LEFT_VOLUME            0x406
+#define WM8995_AIF1_DAC2_RIGHT_VOLUME           0x407
+#define WM8995_AIF1_ADC1_FILTERS                0x410
+#define WM8995_AIF1_ADC2_FILTERS                0x411
+#define WM8995_AIF1_DAC1_FILTERS_1              0x420
+#define WM8995_AIF1_DAC1_FILTERS_2              0x421
+#define WM8995_AIF1_DAC2_FILTERS_1              0x422
+#define WM8995_AIF1_DAC2_FILTERS_2              0x423
+#define WM8995_AIF1_DRC1_1                      0x440
+#define WM8995_AIF1_DRC1_2                      0x441
+#define WM8995_AIF1_DRC1_3                      0x442
+#define WM8995_AIF1_DRC1_4                      0x443
+#define WM8995_AIF1_DRC1_5                      0x444
+#define WM8995_AIF1_DRC2_1                      0x450
+#define WM8995_AIF1_DRC2_2                      0x451
+#define WM8995_AIF1_DRC2_3                      0x452
+#define WM8995_AIF1_DRC2_4                      0x453
+#define WM8995_AIF1_DRC2_5                      0x454
+#define WM8995_AIF1_DAC1_EQ_GAINS_1             0x480
+#define WM8995_AIF1_DAC1_EQ_GAINS_2             0x481
+#define WM8995_AIF1_DAC1_EQ_BAND_1_A            0x482
+#define WM8995_AIF1_DAC1_EQ_BAND_1_B            0x483
+#define WM8995_AIF1_DAC1_EQ_BAND_1_PG           0x484
+#define WM8995_AIF1_DAC1_EQ_BAND_2_A            0x485
+#define WM8995_AIF1_DAC1_EQ_BAND_2_B            0x486
+#define WM8995_AIF1_DAC1_EQ_BAND_2_C            0x487
+#define WM8995_AIF1_DAC1_EQ_BAND_2_PG           0x488
+#define WM8995_AIF1_DAC1_EQ_BAND_3_A            0x489
+#define WM8995_AIF1_DAC1_EQ_BAND_3_B            0x48A
+#define WM8995_AIF1_DAC1_EQ_BAND_3_C            0x48B
+#define WM8995_AIF1_DAC1_EQ_BAND_3_PG           0x48C
+#define WM8995_AIF1_DAC1_EQ_BAND_4_A            0x48D
+#define WM8995_AIF1_DAC1_EQ_BAND_4_B            0x48E
+#define WM8995_AIF1_DAC1_EQ_BAND_4_C            0x48F
+#define WM8995_AIF1_DAC1_EQ_BAND_4_PG           0x490
+#define WM8995_AIF1_DAC1_EQ_BAND_5_A            0x491
+#define WM8995_AIF1_DAC1_EQ_BAND_5_B            0x492
+#define WM8995_AIF1_DAC1_EQ_BAND_5_PG           0x493
+#define WM8995_AIF1_DAC2_EQ_GAINS_1             0x4A0
+#define WM8995_AIF1_DAC2_EQ_GAINS_2             0x4A1
+#define WM8995_AIF1_DAC2_EQ_BAND_1_A            0x4A2
+#define WM8995_AIF1_DAC2_EQ_BAND_1_B            0x4A3
+#define WM8995_AIF1_DAC2_EQ_BAND_1_PG           0x4A4
+#define WM8995_AIF1_DAC2_EQ_BAND_2_A            0x4A5
+#define WM8995_AIF1_DAC2_EQ_BAND_2_B            0x4A6
+#define WM8995_AIF1_DAC2_EQ_BAND_2_C            0x4A7
+#define WM8995_AIF1_DAC2_EQ_BAND_2_PG           0x4A8
+#define WM8995_AIF1_DAC2_EQ_BAND_3_A            0x4A9
+#define WM8995_AIF1_DAC2_EQ_BAND_3_B            0x4AA
+#define WM8995_AIF1_DAC2_EQ_BAND_3_C            0x4AB
+#define WM8995_AIF1_DAC2_EQ_BAND_3_PG           0x4AC
+#define WM8995_AIF1_DAC2_EQ_BAND_4_A            0x4AD
+#define WM8995_AIF1_DAC2_EQ_BAND_4_B            0x4AE
+#define WM8995_AIF1_DAC2_EQ_BAND_4_C            0x4AF
+#define WM8995_AIF1_DAC2_EQ_BAND_4_PG           0x4B0
+#define WM8995_AIF1_DAC2_EQ_BAND_5_A            0x4B1
+#define WM8995_AIF1_DAC2_EQ_BAND_5_B            0x4B2
+#define WM8995_AIF1_DAC2_EQ_BAND_5_PG           0x4B3
+#define WM8995_AIF2_ADC_LEFT_VOLUME             0x500
+#define WM8995_AIF2_ADC_RIGHT_VOLUME            0x501
+#define WM8995_AIF2_DAC_LEFT_VOLUME             0x502
+#define WM8995_AIF2_DAC_RIGHT_VOLUME            0x503
+#define WM8995_AIF2_ADC_FILTERS                 0x510
+#define WM8995_AIF2_DAC_FILTERS_1               0x520
+#define WM8995_AIF2_DAC_FILTERS_2               0x521
+#define WM8995_AIF2_DRC_1                       0x540
+#define WM8995_AIF2_DRC_2                       0x541
+#define WM8995_AIF2_DRC_3                       0x542
+#define WM8995_AIF2_DRC_4                       0x543
+#define WM8995_AIF2_DRC_5                       0x544
+#define WM8995_AIF2_EQ_GAINS_1                  0x580
+#define WM8995_AIF2_EQ_GAINS_2                  0x581
+#define WM8995_AIF2_EQ_BAND_1_A                 0x582
+#define WM8995_AIF2_EQ_BAND_1_B                 0x583
+#define WM8995_AIF2_EQ_BAND_1_PG                0x584
+#define WM8995_AIF2_EQ_BAND_2_A                 0x585
+#define WM8995_AIF2_EQ_BAND_2_B                 0x586
+#define WM8995_AIF2_EQ_BAND_2_C                 0x587
+#define WM8995_AIF2_EQ_BAND_2_PG                0x588
+#define WM8995_AIF2_EQ_BAND_3_A                 0x589
+#define WM8995_AIF2_EQ_BAND_3_B                 0x58A
+#define WM8995_AIF2_EQ_BAND_3_C                 0x58B
+#define WM8995_AIF2_EQ_BAND_3_PG                0x58C
+#define WM8995_AIF2_EQ_BAND_4_A                 0x58D
+#define WM8995_AIF2_EQ_BAND_4_B                 0x58E
+#define WM8995_AIF2_EQ_BAND_4_C                 0x58F
+#define WM8995_AIF2_EQ_BAND_4_PG                0x590
+#define WM8995_AIF2_EQ_BAND_5_A                 0x591
+#define WM8995_AIF2_EQ_BAND_5_B                 0x592
+#define WM8995_AIF2_EQ_BAND_5_PG                0x593
+#define WM8995_DAC1_MIXER_VOLUMES               0x600
+#define WM8995_DAC1_LEFT_MIXER_ROUTING          0x601
+#define WM8995_DAC1_RIGHT_MIXER_ROUTING         0x602
+#define WM8995_DAC2_MIXER_VOLUMES               0x603
+#define WM8995_DAC2_LEFT_MIXER_ROUTING          0x604
+#define WM8995_DAC2_RIGHT_MIXER_ROUTING         0x605
+#define WM8995_AIF1_ADC1_LEFT_MIXER_ROUTING     0x606
+#define WM8995_AIF1_ADC1_RIGHT_MIXER_ROUTING    0x607
+#define WM8995_AIF1_ADC2_LEFT_MIXER_ROUTING     0x608
+#define WM8995_AIF1_ADC2_RIGHT_MIXER_ROUTING    0x609
+#define WM8995_DAC_SOFTMUTE                     0x610
+#define WM8995_OVERSAMPLING                     0x620
+#define WM8995_SIDETONE                         0x621
+#define WM8995_GPIO_1                           0x700
+#define WM8995_GPIO_2                           0x701
+#define WM8995_GPIO_3                           0x702
+#define WM8995_GPIO_4                           0x703
+#define WM8995_GPIO_5                           0x704
+#define WM8995_GPIO_6                           0x705
+#define WM8995_GPIO_7                           0x706
+#define WM8995_GPIO_8                           0x707
+#define WM8995_GPIO_9                           0x708
+#define WM8995_GPIO_10                          0x709
+#define WM8995_GPIO_11                          0x70A
+#define WM8995_GPIO_12                          0x70B
+#define WM8995_GPIO_13                          0x70C
+#define WM8995_GPIO_14                          0x70D
+#define WM8995_PULL_CONTROL_1                   0x720
+#define WM8995_PULL_CONTROL_2                   0x721
+#define WM8995_INTERRUPT_STATUS_1               0x730
+#define WM8995_INTERRUPT_STATUS_2               0x731
+#define WM8995_INTERRUPT_RAW_STATUS_2           0x732
+#define WM8995_INTERRUPT_STATUS_1_MASK          0x738
+#define WM8995_INTERRUPT_STATUS_2_MASK          0x739
+#define WM8995_INTERRUPT_CONTROL                0x740
+#define WM8995_LEFT_PDM_SPEAKER_1               0x800
+#define WM8995_RIGHT_PDM_SPEAKER_1              0x801
+#define WM8995_PDM_SPEAKER_1_MUTE_SEQUENCE      0x802
+#define WM8995_LEFT_PDM_SPEAKER_2               0x808
+#define WM8995_RIGHT_PDM_SPEAKER_2              0x809
+#define WM8995_PDM_SPEAKER_2_MUTE_SEQUENCE      0x80A
+#define WM8995_WRITE_SEQUENCER_0                0x3000
+#define WM8995_WRITE_SEQUENCER_1                0x3001
+#define WM8995_WRITE_SEQUENCER_2                0x3002
+#define WM8995_WRITE_SEQUENCER_3                0x3003
+#define WM8995_WRITE_SEQUENCER_4                0x3004
+#define WM8995_WRITE_SEQUENCER_5                0x3005
+#define WM8995_WRITE_SEQUENCER_6                0x3006
+#define WM8995_WRITE_SEQUENCER_7                0x3007
+#define WM8995_WRITE_SEQUENCER_8                0x3008
+#define WM8995_WRITE_SEQUENCER_9                0x3009
+#define WM8995_WRITE_SEQUENCER_10               0x300A
+#define WM8995_WRITE_SEQUENCER_11               0x300B
+#define WM8995_WRITE_SEQUENCER_12               0x300C
+#define WM8995_WRITE_SEQUENCER_13               0x300D
+#define WM8995_WRITE_SEQUENCER_14               0x300E
+#define WM8995_WRITE_SEQUENCER_15               0x300F
+#define WM8995_WRITE_SEQUENCER_16               0x3010
+#define WM8995_WRITE_SEQUENCER_17               0x3011
+#define WM8995_WRITE_SEQUENCER_18               0x3012
+#define WM8995_WRITE_SEQUENCER_19               0x3013
+#define WM8995_WRITE_SEQUENCER_20               0x3014
+#define WM8995_WRITE_SEQUENCER_21               0x3015
+#define WM8995_WRITE_SEQUENCER_22               0x3016
+#define WM8995_WRITE_SEQUENCER_23               0x3017
+#define WM8995_WRITE_SEQUENCER_24               0x3018
+#define WM8995_WRITE_SEQUENCER_25               0x3019
+#define WM8995_WRITE_SEQUENCER_26               0x301A
+#define WM8995_WRITE_SEQUENCER_27               0x301B
+#define WM8995_WRITE_SEQUENCER_28               0x301C
+#define WM8995_WRITE_SEQUENCER_29               0x301D
+#define WM8995_WRITE_SEQUENCER_30               0x301E
+#define WM8995_WRITE_SEQUENCER_31               0x301F
+#define WM8995_WRITE_SEQUENCER_32               0x3020
+#define WM8995_WRITE_SEQUENCER_33               0x3021
+#define WM8995_WRITE_SEQUENCER_34               0x3022
+#define WM8995_WRITE_SEQUENCER_35               0x3023
+#define WM8995_WRITE_SEQUENCER_36               0x3024
+#define WM8995_WRITE_SEQUENCER_37               0x3025
+#define WM8995_WRITE_SEQUENCER_38               0x3026
+#define WM8995_WRITE_SEQUENCER_39               0x3027
+#define WM8995_WRITE_SEQUENCER_40               0x3028
+#define WM8995_WRITE_SEQUENCER_41               0x3029
+#define WM8995_WRITE_SEQUENCER_42               0x302A
+#define WM8995_WRITE_SEQUENCER_43               0x302B
+#define WM8995_WRITE_SEQUENCER_44               0x302C
+#define WM8995_WRITE_SEQUENCER_45               0x302D
+#define WM8995_WRITE_SEQUENCER_46               0x302E
+#define WM8995_WRITE_SEQUENCER_47               0x302F
+#define WM8995_WRITE_SEQUENCER_48               0x3030
+#define WM8995_WRITE_SEQUENCER_49               0x3031
+#define WM8995_WRITE_SEQUENCER_50               0x3032
+#define WM8995_WRITE_SEQUENCER_51               0x3033
+#define WM8995_WRITE_SEQUENCER_52               0x3034
+#define WM8995_WRITE_SEQUENCER_53               0x3035
+#define WM8995_WRITE_SEQUENCER_54               0x3036
+#define WM8995_WRITE_SEQUENCER_55               0x3037
+#define WM8995_WRITE_SEQUENCER_56               0x3038
+#define WM8995_WRITE_SEQUENCER_57               0x3039
+#define WM8995_WRITE_SEQUENCER_58               0x303A
+#define WM8995_WRITE_SEQUENCER_59               0x303B
+#define WM8995_WRITE_SEQUENCER_60               0x303C
+#define WM8995_WRITE_SEQUENCER_61               0x303D
+#define WM8995_WRITE_SEQUENCER_62               0x303E
+#define WM8995_WRITE_SEQUENCER_63               0x303F
+#define WM8995_WRITE_SEQUENCER_64               0x3040
+#define WM8995_WRITE_SEQUENCER_65               0x3041
+#define WM8995_WRITE_SEQUENCER_66               0x3042
+#define WM8995_WRITE_SEQUENCER_67               0x3043
+#define WM8995_WRITE_SEQUENCER_68               0x3044
+#define WM8995_WRITE_SEQUENCER_69               0x3045
+#define WM8995_WRITE_SEQUENCER_70               0x3046
+#define WM8995_WRITE_SEQUENCER_71               0x3047
+#define WM8995_WRITE_SEQUENCER_72               0x3048
+#define WM8995_WRITE_SEQUENCER_73               0x3049
+#define WM8995_WRITE_SEQUENCER_74               0x304A
+#define WM8995_WRITE_SEQUENCER_75               0x304B
+#define WM8995_WRITE_SEQUENCER_76               0x304C
+#define WM8995_WRITE_SEQUENCER_77               0x304D
+#define WM8995_WRITE_SEQUENCER_78               0x304E
+#define WM8995_WRITE_SEQUENCER_79               0x304F
+#define WM8995_WRITE_SEQUENCER_80               0x3050
+#define WM8995_WRITE_SEQUENCER_81               0x3051
+#define WM8995_WRITE_SEQUENCER_82               0x3052
+#define WM8995_WRITE_SEQUENCER_83               0x3053
+#define WM8995_WRITE_SEQUENCER_84               0x3054
+#define WM8995_WRITE_SEQUENCER_85               0x3055
+#define WM8995_WRITE_SEQUENCER_86               0x3056
+#define WM8995_WRITE_SEQUENCER_87               0x3057
+#define WM8995_WRITE_SEQUENCER_88               0x3058
+#define WM8995_WRITE_SEQUENCER_89               0x3059
+#define WM8995_WRITE_SEQUENCER_90               0x305A
+#define WM8995_WRITE_SEQUENCER_91               0x305B
+#define WM8995_WRITE_SEQUENCER_92               0x305C
+#define WM8995_WRITE_SEQUENCER_93               0x305D
+#define WM8995_WRITE_SEQUENCER_94               0x305E
+#define WM8995_WRITE_SEQUENCER_95               0x305F
+#define WM8995_WRITE_SEQUENCER_96               0x3060
+#define WM8995_WRITE_SEQUENCER_97               0x3061
+#define WM8995_WRITE_SEQUENCER_98               0x3062
+#define WM8995_WRITE_SEQUENCER_99               0x3063
+#define WM8995_WRITE_SEQUENCER_100              0x3064
+#define WM8995_WRITE_SEQUENCER_101              0x3065
+#define WM8995_WRITE_SEQUENCER_102              0x3066
+#define WM8995_WRITE_SEQUENCER_103              0x3067
+#define WM8995_WRITE_SEQUENCER_104              0x3068
+#define WM8995_WRITE_SEQUENCER_105              0x3069
+#define WM8995_WRITE_SEQUENCER_106              0x306A
+#define WM8995_WRITE_SEQUENCER_107              0x306B
+#define WM8995_WRITE_SEQUENCER_108              0x306C
+#define WM8995_WRITE_SEQUENCER_109              0x306D
+#define WM8995_WRITE_SEQUENCER_110              0x306E
+#define WM8995_WRITE_SEQUENCER_111              0x306F
+#define WM8995_WRITE_SEQUENCER_112              0x3070
+#define WM8995_WRITE_SEQUENCER_113              0x3071
+#define WM8995_WRITE_SEQUENCER_114              0x3072
+#define WM8995_WRITE_SEQUENCER_115              0x3073
+#define WM8995_WRITE_SEQUENCER_116              0x3074
+#define WM8995_WRITE_SEQUENCER_117              0x3075
+#define WM8995_WRITE_SEQUENCER_118              0x3076
+#define WM8995_WRITE_SEQUENCER_119              0x3077
+#define WM8995_WRITE_SEQUENCER_120              0x3078
+#define WM8995_WRITE_SEQUENCER_121              0x3079
+#define WM8995_WRITE_SEQUENCER_122              0x307A
+#define WM8995_WRITE_SEQUENCER_123              0x307B
+#define WM8995_WRITE_SEQUENCER_124              0x307C
+#define WM8995_WRITE_SEQUENCER_125              0x307D
+#define WM8995_WRITE_SEQUENCER_126              0x307E
+#define WM8995_WRITE_SEQUENCER_127              0x307F
+#define WM8995_WRITE_SEQUENCER_128              0x3080
+#define WM8995_WRITE_SEQUENCER_129              0x3081
+#define WM8995_WRITE_SEQUENCER_130              0x3082
+#define WM8995_WRITE_SEQUENCER_131              0x3083
+#define WM8995_WRITE_SEQUENCER_132              0x3084
+#define WM8995_WRITE_SEQUENCER_133              0x3085
+#define WM8995_WRITE_SEQUENCER_134              0x3086
+#define WM8995_WRITE_SEQUENCER_135              0x3087
+#define WM8995_WRITE_SEQUENCER_136              0x3088
+#define WM8995_WRITE_SEQUENCER_137              0x3089
+#define WM8995_WRITE_SEQUENCER_138              0x308A
+#define WM8995_WRITE_SEQUENCER_139              0x308B
+#define WM8995_WRITE_SEQUENCER_140              0x308C
+#define WM8995_WRITE_SEQUENCER_141              0x308D
+#define WM8995_WRITE_SEQUENCER_142              0x308E
+#define WM8995_WRITE_SEQUENCER_143              0x308F
+#define WM8995_WRITE_SEQUENCER_144              0x3090
+#define WM8995_WRITE_SEQUENCER_145              0x3091
+#define WM8995_WRITE_SEQUENCER_146              0x3092
+#define WM8995_WRITE_SEQUENCER_147              0x3093
+#define WM8995_WRITE_SEQUENCER_148              0x3094
+#define WM8995_WRITE_SEQUENCER_149              0x3095
+#define WM8995_WRITE_SEQUENCER_150              0x3096
+#define WM8995_WRITE_SEQUENCER_151              0x3097
+#define WM8995_WRITE_SEQUENCER_152              0x3098
+#define WM8995_WRITE_SEQUENCER_153              0x3099
+#define WM8995_WRITE_SEQUENCER_154              0x309A
+#define WM8995_WRITE_SEQUENCER_155              0x309B
+#define WM8995_WRITE_SEQUENCER_156              0x309C
+#define WM8995_WRITE_SEQUENCER_157              0x309D
+#define WM8995_WRITE_SEQUENCER_158              0x309E
+#define WM8995_WRITE_SEQUENCER_159              0x309F
+#define WM8995_WRITE_SEQUENCER_160              0x30A0
+#define WM8995_WRITE_SEQUENCER_161              0x30A1
+#define WM8995_WRITE_SEQUENCER_162              0x30A2
+#define WM8995_WRITE_SEQUENCER_163              0x30A3
+#define WM8995_WRITE_SEQUENCER_164              0x30A4
+#define WM8995_WRITE_SEQUENCER_165              0x30A5
+#define WM8995_WRITE_SEQUENCER_166              0x30A6
+#define WM8995_WRITE_SEQUENCER_167              0x30A7
+#define WM8995_WRITE_SEQUENCER_168              0x30A8
+#define WM8995_WRITE_SEQUENCER_169              0x30A9
+#define WM8995_WRITE_SEQUENCER_170              0x30AA
+#define WM8995_WRITE_SEQUENCER_171              0x30AB
+#define WM8995_WRITE_SEQUENCER_172              0x30AC
+#define WM8995_WRITE_SEQUENCER_173              0x30AD
+#define WM8995_WRITE_SEQUENCER_174              0x30AE
+#define WM8995_WRITE_SEQUENCER_175              0x30AF
+#define WM8995_WRITE_SEQUENCER_176              0x30B0
+#define WM8995_WRITE_SEQUENCER_177              0x30B1
+#define WM8995_WRITE_SEQUENCER_178              0x30B2
+#define WM8995_WRITE_SEQUENCER_179              0x30B3
+#define WM8995_WRITE_SEQUENCER_180              0x30B4
+#define WM8995_WRITE_SEQUENCER_181              0x30B5
+#define WM8995_WRITE_SEQUENCER_182              0x30B6
+#define WM8995_WRITE_SEQUENCER_183              0x30B7
+#define WM8995_WRITE_SEQUENCER_184              0x30B8
+#define WM8995_WRITE_SEQUENCER_185              0x30B9
+#define WM8995_WRITE_SEQUENCER_186              0x30BA
+#define WM8995_WRITE_SEQUENCER_187              0x30BB
+#define WM8995_WRITE_SEQUENCER_188              0x30BC
+#define WM8995_WRITE_SEQUENCER_189              0x30BD
+#define WM8995_WRITE_SEQUENCER_190              0x30BE
+#define WM8995_WRITE_SEQUENCER_191              0x30BF
+#define WM8995_WRITE_SEQUENCER_192              0x30C0
+#define WM8995_WRITE_SEQUENCER_193              0x30C1
+#define WM8995_WRITE_SEQUENCER_194              0x30C2
+#define WM8995_WRITE_SEQUENCER_195              0x30C3
+#define WM8995_WRITE_SEQUENCER_196              0x30C4
+#define WM8995_WRITE_SEQUENCER_197              0x30C5
+#define WM8995_WRITE_SEQUENCER_198              0x30C6
+#define WM8995_WRITE_SEQUENCER_199              0x30C7
+#define WM8995_WRITE_SEQUENCER_200              0x30C8
+#define WM8995_WRITE_SEQUENCER_201              0x30C9
+#define WM8995_WRITE_SEQUENCER_202              0x30CA
+#define WM8995_WRITE_SEQUENCER_203              0x30CB
+#define WM8995_WRITE_SEQUENCER_204              0x30CC
+#define WM8995_WRITE_SEQUENCER_205              0x30CD
+#define WM8995_WRITE_SEQUENCER_206              0x30CE
+#define WM8995_WRITE_SEQUENCER_207              0x30CF
+#define WM8995_WRITE_SEQUENCER_208              0x30D0
+#define WM8995_WRITE_SEQUENCER_209              0x30D1
+#define WM8995_WRITE_SEQUENCER_210              0x30D2
+#define WM8995_WRITE_SEQUENCER_211              0x30D3
+#define WM8995_WRITE_SEQUENCER_212              0x30D4
+#define WM8995_WRITE_SEQUENCER_213              0x30D5
+#define WM8995_WRITE_SEQUENCER_214              0x30D6
+#define WM8995_WRITE_SEQUENCER_215              0x30D7
+#define WM8995_WRITE_SEQUENCER_216              0x30D8
+#define WM8995_WRITE_SEQUENCER_217              0x30D9
+#define WM8995_WRITE_SEQUENCER_218              0x30DA
+#define WM8995_WRITE_SEQUENCER_219              0x30DB
+#define WM8995_WRITE_SEQUENCER_220              0x30DC
+#define WM8995_WRITE_SEQUENCER_221              0x30DD
+#define WM8995_WRITE_SEQUENCER_222              0x30DE
+#define WM8995_WRITE_SEQUENCER_223              0x30DF
+#define WM8995_WRITE_SEQUENCER_224              0x30E0
+#define WM8995_WRITE_SEQUENCER_225              0x30E1
+#define WM8995_WRITE_SEQUENCER_226              0x30E2
+#define WM8995_WRITE_SEQUENCER_227              0x30E3
+#define WM8995_WRITE_SEQUENCER_228              0x30E4
+#define WM8995_WRITE_SEQUENCER_229              0x30E5
+#define WM8995_WRITE_SEQUENCER_230              0x30E6
+#define WM8995_WRITE_SEQUENCER_231              0x30E7
+#define WM8995_WRITE_SEQUENCER_232              0x30E8
+#define WM8995_WRITE_SEQUENCER_233              0x30E9
+#define WM8995_WRITE_SEQUENCER_234              0x30EA
+#define WM8995_WRITE_SEQUENCER_235              0x30EB
+#define WM8995_WRITE_SEQUENCER_236              0x30EC
+#define WM8995_WRITE_SEQUENCER_237              0x30ED
+#define WM8995_WRITE_SEQUENCER_238              0x30EE
+#define WM8995_WRITE_SEQUENCER_239              0x30EF
+#define WM8995_WRITE_SEQUENCER_240              0x30F0
+#define WM8995_WRITE_SEQUENCER_241              0x30F1
+#define WM8995_WRITE_SEQUENCER_242              0x30F2
+#define WM8995_WRITE_SEQUENCER_243              0x30F3
+#define WM8995_WRITE_SEQUENCER_244              0x30F4
+#define WM8995_WRITE_SEQUENCER_245              0x30F5
+#define WM8995_WRITE_SEQUENCER_246              0x30F6
+#define WM8995_WRITE_SEQUENCER_247              0x30F7
+#define WM8995_WRITE_SEQUENCER_248              0x30F8
+#define WM8995_WRITE_SEQUENCER_249              0x30F9
+#define WM8995_WRITE_SEQUENCER_250              0x30FA
+#define WM8995_WRITE_SEQUENCER_251              0x30FB
+#define WM8995_WRITE_SEQUENCER_252              0x30FC
+#define WM8995_WRITE_SEQUENCER_253              0x30FD
+#define WM8995_WRITE_SEQUENCER_254              0x30FE
+#define WM8995_WRITE_SEQUENCER_255              0x30FF
+#define WM8995_WRITE_SEQUENCER_256              0x3100
+#define WM8995_WRITE_SEQUENCER_257              0x3101
+#define WM8995_WRITE_SEQUENCER_258              0x3102
+#define WM8995_WRITE_SEQUENCER_259              0x3103
+#define WM8995_WRITE_SEQUENCER_260              0x3104
+#define WM8995_WRITE_SEQUENCER_261              0x3105
+#define WM8995_WRITE_SEQUENCER_262              0x3106
+#define WM8995_WRITE_SEQUENCER_263              0x3107
+#define WM8995_WRITE_SEQUENCER_264              0x3108
+#define WM8995_WRITE_SEQUENCER_265              0x3109
+#define WM8995_WRITE_SEQUENCER_266              0x310A
+#define WM8995_WRITE_SEQUENCER_267              0x310B
+#define WM8995_WRITE_SEQUENCER_268              0x310C
+#define WM8995_WRITE_SEQUENCER_269              0x310D
+#define WM8995_WRITE_SEQUENCER_270              0x310E
+#define WM8995_WRITE_SEQUENCER_271              0x310F
+#define WM8995_WRITE_SEQUENCER_272              0x3110
+#define WM8995_WRITE_SEQUENCER_273              0x3111
+#define WM8995_WRITE_SEQUENCER_274              0x3112
+#define WM8995_WRITE_SEQUENCER_275              0x3113
+#define WM8995_WRITE_SEQUENCER_276              0x3114
+#define WM8995_WRITE_SEQUENCER_277              0x3115
+#define WM8995_WRITE_SEQUENCER_278              0x3116
+#define WM8995_WRITE_SEQUENCER_279              0x3117
+#define WM8995_WRITE_SEQUENCER_280              0x3118
+#define WM8995_WRITE_SEQUENCER_281              0x3119
+#define WM8995_WRITE_SEQUENCER_282              0x311A
+#define WM8995_WRITE_SEQUENCER_283              0x311B
+#define WM8995_WRITE_SEQUENCER_284              0x311C
+#define WM8995_WRITE_SEQUENCER_285              0x311D
+#define WM8995_WRITE_SEQUENCER_286              0x311E
+#define WM8995_WRITE_SEQUENCER_287              0x311F
+#define WM8995_WRITE_SEQUENCER_288              0x3120
+#define WM8995_WRITE_SEQUENCER_289              0x3121
+#define WM8995_WRITE_SEQUENCER_290              0x3122
+#define WM8995_WRITE_SEQUENCER_291              0x3123
+#define WM8995_WRITE_SEQUENCER_292              0x3124
+#define WM8995_WRITE_SEQUENCER_293              0x3125
+#define WM8995_WRITE_SEQUENCER_294              0x3126
+#define WM8995_WRITE_SEQUENCER_295              0x3127
+#define WM8995_WRITE_SEQUENCER_296              0x3128
+#define WM8995_WRITE_SEQUENCER_297              0x3129
+#define WM8995_WRITE_SEQUENCER_298              0x312A
+#define WM8995_WRITE_SEQUENCER_299              0x312B
+#define WM8995_WRITE_SEQUENCER_300              0x312C
+#define WM8995_WRITE_SEQUENCER_301              0x312D
+#define WM8995_WRITE_SEQUENCER_302              0x312E
+#define WM8995_WRITE_SEQUENCER_303              0x312F
+#define WM8995_WRITE_SEQUENCER_304              0x3130
+#define WM8995_WRITE_SEQUENCER_305              0x3131
+#define WM8995_WRITE_SEQUENCER_306              0x3132
+#define WM8995_WRITE_SEQUENCER_307              0x3133
+#define WM8995_WRITE_SEQUENCER_308              0x3134
+#define WM8995_WRITE_SEQUENCER_309              0x3135
+#define WM8995_WRITE_SEQUENCER_310              0x3136
+#define WM8995_WRITE_SEQUENCER_311              0x3137
+#define WM8995_WRITE_SEQUENCER_312              0x3138
+#define WM8995_WRITE_SEQUENCER_313              0x3139
+#define WM8995_WRITE_SEQUENCER_314              0x313A
+#define WM8995_WRITE_SEQUENCER_315              0x313B
+#define WM8995_WRITE_SEQUENCER_316              0x313C
+#define WM8995_WRITE_SEQUENCER_317              0x313D
+#define WM8995_WRITE_SEQUENCER_318              0x313E
+#define WM8995_WRITE_SEQUENCER_319              0x313F
+#define WM8995_WRITE_SEQUENCER_320              0x3140
+#define WM8995_WRITE_SEQUENCER_321              0x3141
+#define WM8995_WRITE_SEQUENCER_322              0x3142
+#define WM8995_WRITE_SEQUENCER_323              0x3143
+#define WM8995_WRITE_SEQUENCER_324              0x3144
+#define WM8995_WRITE_SEQUENCER_325              0x3145
+#define WM8995_WRITE_SEQUENCER_326              0x3146
+#define WM8995_WRITE_SEQUENCER_327              0x3147
+#define WM8995_WRITE_SEQUENCER_328              0x3148
+#define WM8995_WRITE_SEQUENCER_329              0x3149
+#define WM8995_WRITE_SEQUENCER_330              0x314A
+#define WM8995_WRITE_SEQUENCER_331              0x314B
+#define WM8995_WRITE_SEQUENCER_332              0x314C
+#define WM8995_WRITE_SEQUENCER_333              0x314D
+#define WM8995_WRITE_SEQUENCER_334              0x314E
+#define WM8995_WRITE_SEQUENCER_335              0x314F
+#define WM8995_WRITE_SEQUENCER_336              0x3150
+#define WM8995_WRITE_SEQUENCER_337              0x3151
+#define WM8995_WRITE_SEQUENCER_338              0x3152
+#define WM8995_WRITE_SEQUENCER_339              0x3153
+#define WM8995_WRITE_SEQUENCER_340              0x3154
+#define WM8995_WRITE_SEQUENCER_341              0x3155
+#define WM8995_WRITE_SEQUENCER_342              0x3156
+#define WM8995_WRITE_SEQUENCER_343              0x3157
+#define WM8995_WRITE_SEQUENCER_344              0x3158
+#define WM8995_WRITE_SEQUENCER_345              0x3159
+#define WM8995_WRITE_SEQUENCER_346              0x315A
+#define WM8995_WRITE_SEQUENCER_347              0x315B
+#define WM8995_WRITE_SEQUENCER_348              0x315C
+#define WM8995_WRITE_SEQUENCER_349              0x315D
+#define WM8995_WRITE_SEQUENCER_350              0x315E
+#define WM8995_WRITE_SEQUENCER_351              0x315F
+#define WM8995_WRITE_SEQUENCER_352              0x3160
+#define WM8995_WRITE_SEQUENCER_353              0x3161
+#define WM8995_WRITE_SEQUENCER_354              0x3162
+#define WM8995_WRITE_SEQUENCER_355              0x3163
+#define WM8995_WRITE_SEQUENCER_356              0x3164
+#define WM8995_WRITE_SEQUENCER_357              0x3165
+#define WM8995_WRITE_SEQUENCER_358              0x3166
+#define WM8995_WRITE_SEQUENCER_359              0x3167
+#define WM8995_WRITE_SEQUENCER_360              0x3168
+#define WM8995_WRITE_SEQUENCER_361              0x3169
+#define WM8995_WRITE_SEQUENCER_362              0x316A
+#define WM8995_WRITE_SEQUENCER_363              0x316B
+#define WM8995_WRITE_SEQUENCER_364              0x316C
+#define WM8995_WRITE_SEQUENCER_365              0x316D
+#define WM8995_WRITE_SEQUENCER_366              0x316E
+#define WM8995_WRITE_SEQUENCER_367              0x316F
+#define WM8995_WRITE_SEQUENCER_368              0x3170
+#define WM8995_WRITE_SEQUENCER_369              0x3171
+#define WM8995_WRITE_SEQUENCER_370              0x3172
+#define WM8995_WRITE_SEQUENCER_371              0x3173
+#define WM8995_WRITE_SEQUENCER_372              0x3174
+#define WM8995_WRITE_SEQUENCER_373              0x3175
+#define WM8995_WRITE_SEQUENCER_374              0x3176
+#define WM8995_WRITE_SEQUENCER_375              0x3177
+#define WM8995_WRITE_SEQUENCER_376              0x3178
+#define WM8995_WRITE_SEQUENCER_377              0x3179
+#define WM8995_WRITE_SEQUENCER_378              0x317A
+#define WM8995_WRITE_SEQUENCER_379              0x317B
+#define WM8995_WRITE_SEQUENCER_380              0x317C
+#define WM8995_WRITE_SEQUENCER_381              0x317D
+#define WM8995_WRITE_SEQUENCER_382              0x317E
+#define WM8995_WRITE_SEQUENCER_383              0x317F
+#define WM8995_WRITE_SEQUENCER_384              0x3180
+#define WM8995_WRITE_SEQUENCER_385              0x3181
+#define WM8995_WRITE_SEQUENCER_386              0x3182
+#define WM8995_WRITE_SEQUENCER_387              0x3183
+#define WM8995_WRITE_SEQUENCER_388              0x3184
+#define WM8995_WRITE_SEQUENCER_389              0x3185
+#define WM8995_WRITE_SEQUENCER_390              0x3186
+#define WM8995_WRITE_SEQUENCER_391              0x3187
+#define WM8995_WRITE_SEQUENCER_392              0x3188
+#define WM8995_WRITE_SEQUENCER_393              0x3189
+#define WM8995_WRITE_SEQUENCER_394              0x318A
+#define WM8995_WRITE_SEQUENCER_395              0x318B
+#define WM8995_WRITE_SEQUENCER_396              0x318C
+#define WM8995_WRITE_SEQUENCER_397              0x318D
+#define WM8995_WRITE_SEQUENCER_398              0x318E
+#define WM8995_WRITE_SEQUENCER_399              0x318F
+#define WM8995_WRITE_SEQUENCER_400              0x3190
+#define WM8995_WRITE_SEQUENCER_401              0x3191
+#define WM8995_WRITE_SEQUENCER_402              0x3192
+#define WM8995_WRITE_SEQUENCER_403              0x3193
+#define WM8995_WRITE_SEQUENCER_404              0x3194
+#define WM8995_WRITE_SEQUENCER_405              0x3195
+#define WM8995_WRITE_SEQUENCER_406              0x3196
+#define WM8995_WRITE_SEQUENCER_407              0x3197
+#define WM8995_WRITE_SEQUENCER_408              0x3198
+#define WM8995_WRITE_SEQUENCER_409              0x3199
+#define WM8995_WRITE_SEQUENCER_410              0x319A
+#define WM8995_WRITE_SEQUENCER_411              0x319B
+#define WM8995_WRITE_SEQUENCER_412              0x319C
+#define WM8995_WRITE_SEQUENCER_413              0x319D
+#define WM8995_WRITE_SEQUENCER_414              0x319E
+#define WM8995_WRITE_SEQUENCER_415              0x319F
+#define WM8995_WRITE_SEQUENCER_416              0x31A0
+#define WM8995_WRITE_SEQUENCER_417              0x31A1
+#define WM8995_WRITE_SEQUENCER_418              0x31A2
+#define WM8995_WRITE_SEQUENCER_419              0x31A3
+#define WM8995_WRITE_SEQUENCER_420              0x31A4
+#define WM8995_WRITE_SEQUENCER_421              0x31A5
+#define WM8995_WRITE_SEQUENCER_422              0x31A6
+#define WM8995_WRITE_SEQUENCER_423              0x31A7
+#define WM8995_WRITE_SEQUENCER_424              0x31A8
+#define WM8995_WRITE_SEQUENCER_425              0x31A9
+#define WM8995_WRITE_SEQUENCER_426              0x31AA
+#define WM8995_WRITE_SEQUENCER_427              0x31AB
+#define WM8995_WRITE_SEQUENCER_428              0x31AC
+#define WM8995_WRITE_SEQUENCER_429              0x31AD
+#define WM8995_WRITE_SEQUENCER_430              0x31AE
+#define WM8995_WRITE_SEQUENCER_431              0x31AF
+#define WM8995_WRITE_SEQUENCER_432              0x31B0
+#define WM8995_WRITE_SEQUENCER_433              0x31B1
+#define WM8995_WRITE_SEQUENCER_434              0x31B2
+#define WM8995_WRITE_SEQUENCER_435              0x31B3
+#define WM8995_WRITE_SEQUENCER_436              0x31B4
+#define WM8995_WRITE_SEQUENCER_437              0x31B5
+#define WM8995_WRITE_SEQUENCER_438              0x31B6
+#define WM8995_WRITE_SEQUENCER_439              0x31B7
+#define WM8995_WRITE_SEQUENCER_440              0x31B8
+#define WM8995_WRITE_SEQUENCER_441              0x31B9
+#define WM8995_WRITE_SEQUENCER_442              0x31BA
+#define WM8995_WRITE_SEQUENCER_443              0x31BB
+#define WM8995_WRITE_SEQUENCER_444              0x31BC
+#define WM8995_WRITE_SEQUENCER_445              0x31BD
+#define WM8995_WRITE_SEQUENCER_446              0x31BE
+#define WM8995_WRITE_SEQUENCER_447              0x31BF
+#define WM8995_WRITE_SEQUENCER_448              0x31C0
+#define WM8995_WRITE_SEQUENCER_449              0x31C1
+#define WM8995_WRITE_SEQUENCER_450              0x31C2
+#define WM8995_WRITE_SEQUENCER_451              0x31C3
+#define WM8995_WRITE_SEQUENCER_452              0x31C4
+#define WM8995_WRITE_SEQUENCER_453              0x31C5
+#define WM8995_WRITE_SEQUENCER_454              0x31C6
+#define WM8995_WRITE_SEQUENCER_455              0x31C7
+#define WM8995_WRITE_SEQUENCER_456              0x31C8
+#define WM8995_WRITE_SEQUENCER_457              0x31C9
+#define WM8995_WRITE_SEQUENCER_458              0x31CA
+#define WM8995_WRITE_SEQUENCER_459              0x31CB
+#define WM8995_WRITE_SEQUENCER_460              0x31CC
+#define WM8995_WRITE_SEQUENCER_461              0x31CD
+#define WM8995_WRITE_SEQUENCER_462              0x31CE
+#define WM8995_WRITE_SEQUENCER_463              0x31CF
+#define WM8995_WRITE_SEQUENCER_464              0x31D0
+#define WM8995_WRITE_SEQUENCER_465              0x31D1
+#define WM8995_WRITE_SEQUENCER_466              0x31D2
+#define WM8995_WRITE_SEQUENCER_467              0x31D3
+#define WM8995_WRITE_SEQUENCER_468              0x31D4
+#define WM8995_WRITE_SEQUENCER_469              0x31D5
+#define WM8995_WRITE_SEQUENCER_470              0x31D6
+#define WM8995_WRITE_SEQUENCER_471              0x31D7
+#define WM8995_WRITE_SEQUENCER_472              0x31D8
+#define WM8995_WRITE_SEQUENCER_473              0x31D9
+#define WM8995_WRITE_SEQUENCER_474              0x31DA
+#define WM8995_WRITE_SEQUENCER_475              0x31DB
+#define WM8995_WRITE_SEQUENCER_476              0x31DC
+#define WM8995_WRITE_SEQUENCER_477              0x31DD
+#define WM8995_WRITE_SEQUENCER_478              0x31DE
+#define WM8995_WRITE_SEQUENCER_479              0x31DF
+#define WM8995_WRITE_SEQUENCER_480              0x31E0
+#define WM8995_WRITE_SEQUENCER_481              0x31E1
+#define WM8995_WRITE_SEQUENCER_482              0x31E2
+#define WM8995_WRITE_SEQUENCER_483              0x31E3
+#define WM8995_WRITE_SEQUENCER_484              0x31E4
+#define WM8995_WRITE_SEQUENCER_485              0x31E5
+#define WM8995_WRITE_SEQUENCER_486              0x31E6
+#define WM8995_WRITE_SEQUENCER_487              0x31E7
+#define WM8995_WRITE_SEQUENCER_488              0x31E8
+#define WM8995_WRITE_SEQUENCER_489              0x31E9
+#define WM8995_WRITE_SEQUENCER_490              0x31EA
+#define WM8995_WRITE_SEQUENCER_491              0x31EB
+#define WM8995_WRITE_SEQUENCER_492              0x31EC
+#define WM8995_WRITE_SEQUENCER_493              0x31ED
+#define WM8995_WRITE_SEQUENCER_494              0x31EE
+#define WM8995_WRITE_SEQUENCER_495              0x31EF
+#define WM8995_WRITE_SEQUENCER_496              0x31F0
+#define WM8995_WRITE_SEQUENCER_497              0x31F1
+#define WM8995_WRITE_SEQUENCER_498              0x31F2
+#define WM8995_WRITE_SEQUENCER_499              0x31F3
+#define WM8995_WRITE_SEQUENCER_500              0x31F4
+#define WM8995_WRITE_SEQUENCER_501              0x31F5
+#define WM8995_WRITE_SEQUENCER_502              0x31F6
+#define WM8995_WRITE_SEQUENCER_503              0x31F7
+#define WM8995_WRITE_SEQUENCER_504              0x31F8
+#define WM8995_WRITE_SEQUENCER_505              0x31F9
+#define WM8995_WRITE_SEQUENCER_506              0x31FA
+#define WM8995_WRITE_SEQUENCER_507              0x31FB
+#define WM8995_WRITE_SEQUENCER_508              0x31FC
+#define WM8995_WRITE_SEQUENCER_509              0x31FD
+#define WM8995_WRITE_SEQUENCER_510              0x31FE
+#define WM8995_WRITE_SEQUENCER_511              0x31FF
+
+#define WM8995_REGISTER_COUNT                   725
+#define WM8995_MAX_REGISTER                     0x31FF
+
+#define WM8995_MAX_CACHED_REGISTER		WM8995_MAX_REGISTER
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8995_SW_RESET_MASK                    0xFFFF	/* SW_RESET - [15:0] */
+#define WM8995_SW_RESET_SHIFT                        0	/* SW_RESET - [15:0] */
+#define WM8995_SW_RESET_WIDTH                       16	/* SW_RESET - [15:0] */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM8995_MICB2_ENA                        0x0200	/* MICB2_ENA */
+#define WM8995_MICB2_ENA_MASK                   0x0200	/* MICB2_ENA */
+#define WM8995_MICB2_ENA_SHIFT                       9	/* MICB2_ENA */
+#define WM8995_MICB2_ENA_WIDTH                       1	/* MICB2_ENA */
+#define WM8995_MICB1_ENA                        0x0100	/* MICB1_ENA */
+#define WM8995_MICB1_ENA_MASK                   0x0100	/* MICB1_ENA */
+#define WM8995_MICB1_ENA_SHIFT                       8	/* MICB1_ENA */
+#define WM8995_MICB1_ENA_WIDTH                       1	/* MICB1_ENA */
+#define WM8995_HPOUT2L_ENA                      0x0080	/* HPOUT2L_ENA */
+#define WM8995_HPOUT2L_ENA_MASK                 0x0080	/* HPOUT2L_ENA */
+#define WM8995_HPOUT2L_ENA_SHIFT                     7	/* HPOUT2L_ENA */
+#define WM8995_HPOUT2L_ENA_WIDTH                     1	/* HPOUT2L_ENA */
+#define WM8995_HPOUT2R_ENA                      0x0040	/* HPOUT2R_ENA */
+#define WM8995_HPOUT2R_ENA_MASK                 0x0040	/* HPOUT2R_ENA */
+#define WM8995_HPOUT2R_ENA_SHIFT                     6	/* HPOUT2R_ENA */
+#define WM8995_HPOUT2R_ENA_WIDTH                     1	/* HPOUT2R_ENA */
+#define WM8995_HPOUT1L_ENA                      0x0020	/* HPOUT1L_ENA */
+#define WM8995_HPOUT1L_ENA_MASK                 0x0020	/* HPOUT1L_ENA */
+#define WM8995_HPOUT1L_ENA_SHIFT                     5	/* HPOUT1L_ENA */
+#define WM8995_HPOUT1L_ENA_WIDTH                     1	/* HPOUT1L_ENA */
+#define WM8995_HPOUT1R_ENA                      0x0010	/* HPOUT1R_ENA */
+#define WM8995_HPOUT1R_ENA_MASK                 0x0010	/* HPOUT1R_ENA */
+#define WM8995_HPOUT1R_ENA_SHIFT                     4	/* HPOUT1R_ENA */
+#define WM8995_HPOUT1R_ENA_WIDTH                     1	/* HPOUT1R_ENA */
+#define WM8995_BG_ENA                           0x0001	/* BG_ENA */
+#define WM8995_BG_ENA_MASK                      0x0001	/* BG_ENA */
+#define WM8995_BG_ENA_SHIFT                          0	/* BG_ENA */
+#define WM8995_BG_ENA_WIDTH                          1	/* BG_ENA */
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM8995_OPCLK_ENA                        0x0800	/* OPCLK_ENA */
+#define WM8995_OPCLK_ENA_MASK                   0x0800	/* OPCLK_ENA */
+#define WM8995_OPCLK_ENA_SHIFT                      11	/* OPCLK_ENA */
+#define WM8995_OPCLK_ENA_WIDTH                       1	/* OPCLK_ENA */
+#define WM8995_IN1L_ENA                         0x0020	/* IN1L_ENA */
+#define WM8995_IN1L_ENA_MASK                    0x0020	/* IN1L_ENA */
+#define WM8995_IN1L_ENA_SHIFT                        5	/* IN1L_ENA */
+#define WM8995_IN1L_ENA_WIDTH                        1	/* IN1L_ENA */
+#define WM8995_IN1R_ENA                         0x0010	/* IN1R_ENA */
+#define WM8995_IN1R_ENA_MASK                    0x0010	/* IN1R_ENA */
+#define WM8995_IN1R_ENA_SHIFT                        4	/* IN1R_ENA */
+#define WM8995_IN1R_ENA_WIDTH                        1	/* IN1R_ENA */
+#define WM8995_LDO2_ENA                         0x0002	/* LDO2_ENA */
+#define WM8995_LDO2_ENA_MASK                    0x0002	/* LDO2_ENA */
+#define WM8995_LDO2_ENA_SHIFT                        1	/* LDO2_ENA */
+#define WM8995_LDO2_ENA_WIDTH                        1	/* LDO2_ENA */
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM8995_AIF2ADCL_ENA                     0x2000	/* AIF2ADCL_ENA */
+#define WM8995_AIF2ADCL_ENA_MASK                0x2000	/* AIF2ADCL_ENA */
+#define WM8995_AIF2ADCL_ENA_SHIFT                   13	/* AIF2ADCL_ENA */
+#define WM8995_AIF2ADCL_ENA_WIDTH                    1	/* AIF2ADCL_ENA */
+#define WM8995_AIF2ADCR_ENA                     0x1000	/* AIF2ADCR_ENA */
+#define WM8995_AIF2ADCR_ENA_MASK                0x1000	/* AIF2ADCR_ENA */
+#define WM8995_AIF2ADCR_ENA_SHIFT                   12	/* AIF2ADCR_ENA */
+#define WM8995_AIF2ADCR_ENA_WIDTH                    1	/* AIF2ADCR_ENA */
+#define WM8995_AIF1ADC2L_ENA                    0x0800	/* AIF1ADC2L_ENA */
+#define WM8995_AIF1ADC2L_ENA_MASK               0x0800	/* AIF1ADC2L_ENA */
+#define WM8995_AIF1ADC2L_ENA_SHIFT                  11	/* AIF1ADC2L_ENA */
+#define WM8995_AIF1ADC2L_ENA_WIDTH                   1	/* AIF1ADC2L_ENA */
+#define WM8995_AIF1ADC2R_ENA                    0x0400	/* AIF1ADC2R_ENA */
+#define WM8995_AIF1ADC2R_ENA_MASK               0x0400	/* AIF1ADC2R_ENA */
+#define WM8995_AIF1ADC2R_ENA_SHIFT                  10	/* AIF1ADC2R_ENA */
+#define WM8995_AIF1ADC2R_ENA_WIDTH                   1	/* AIF1ADC2R_ENA */
+#define WM8995_AIF1ADC1L_ENA                    0x0200	/* AIF1ADC1L_ENA */
+#define WM8995_AIF1ADC1L_ENA_MASK               0x0200	/* AIF1ADC1L_ENA */
+#define WM8995_AIF1ADC1L_ENA_SHIFT                   9	/* AIF1ADC1L_ENA */
+#define WM8995_AIF1ADC1L_ENA_WIDTH                   1	/* AIF1ADC1L_ENA */
+#define WM8995_AIF1ADC1R_ENA                    0x0100	/* AIF1ADC1R_ENA */
+#define WM8995_AIF1ADC1R_ENA_MASK               0x0100	/* AIF1ADC1R_ENA */
+#define WM8995_AIF1ADC1R_ENA_SHIFT                   8	/* AIF1ADC1R_ENA */
+#define WM8995_AIF1ADC1R_ENA_WIDTH                   1	/* AIF1ADC1R_ENA */
+#define WM8995_DMIC3L_ENA                       0x0080	/* DMIC3L_ENA */
+#define WM8995_DMIC3L_ENA_MASK                  0x0080	/* DMIC3L_ENA */
+#define WM8995_DMIC3L_ENA_SHIFT                      7	/* DMIC3L_ENA */
+#define WM8995_DMIC3L_ENA_WIDTH                      1	/* DMIC3L_ENA */
+#define WM8995_DMIC3R_ENA                       0x0040	/* DMIC3R_ENA */
+#define WM8995_DMIC3R_ENA_MASK                  0x0040	/* DMIC3R_ENA */
+#define WM8995_DMIC3R_ENA_SHIFT                      6	/* DMIC3R_ENA */
+#define WM8995_DMIC3R_ENA_WIDTH                      1	/* DMIC3R_ENA */
+#define WM8995_DMIC2L_ENA                       0x0020	/* DMIC2L_ENA */
+#define WM8995_DMIC2L_ENA_MASK                  0x0020	/* DMIC2L_ENA */
+#define WM8995_DMIC2L_ENA_SHIFT                      5	/* DMIC2L_ENA */
+#define WM8995_DMIC2L_ENA_WIDTH                      1	/* DMIC2L_ENA */
+#define WM8995_DMIC2R_ENA                       0x0010	/* DMIC2R_ENA */
+#define WM8995_DMIC2R_ENA_MASK                  0x0010	/* DMIC2R_ENA */
+#define WM8995_DMIC2R_ENA_SHIFT                      4	/* DMIC2R_ENA */
+#define WM8995_DMIC2R_ENA_WIDTH                      1	/* DMIC2R_ENA */
+#define WM8995_DMIC1L_ENA                       0x0008	/* DMIC1L_ENA */
+#define WM8995_DMIC1L_ENA_MASK                  0x0008	/* DMIC1L_ENA */
+#define WM8995_DMIC1L_ENA_SHIFT                      3	/* DMIC1L_ENA */
+#define WM8995_DMIC1L_ENA_WIDTH                      1	/* DMIC1L_ENA */
+#define WM8995_DMIC1R_ENA                       0x0004	/* DMIC1R_ENA */
+#define WM8995_DMIC1R_ENA_MASK                  0x0004	/* DMIC1R_ENA */
+#define WM8995_DMIC1R_ENA_SHIFT                      2	/* DMIC1R_ENA */
+#define WM8995_DMIC1R_ENA_WIDTH                      1	/* DMIC1R_ENA */
+#define WM8995_ADCL_ENA                         0x0002	/* ADCL_ENA */
+#define WM8995_ADCL_ENA_MASK                    0x0002	/* ADCL_ENA */
+#define WM8995_ADCL_ENA_SHIFT                        1	/* ADCL_ENA */
+#define WM8995_ADCL_ENA_WIDTH                        1	/* ADCL_ENA */
+#define WM8995_ADCR_ENA                         0x0001	/* ADCR_ENA */
+#define WM8995_ADCR_ENA_MASK                    0x0001	/* ADCR_ENA */
+#define WM8995_ADCR_ENA_SHIFT                        0	/* ADCR_ENA */
+#define WM8995_ADCR_ENA_WIDTH                        1	/* ADCR_ENA */
+
+/*
+ * R4 (0x04) - Power Management (4)
+ */
+#define WM8995_AIF2DACL_ENA                     0x2000	/* AIF2DACL_ENA */
+#define WM8995_AIF2DACL_ENA_MASK                0x2000	/* AIF2DACL_ENA */
+#define WM8995_AIF2DACL_ENA_SHIFT                   13	/* AIF2DACL_ENA */
+#define WM8995_AIF2DACL_ENA_WIDTH                    1	/* AIF2DACL_ENA */
+#define WM8995_AIF2DACR_ENA                     0x1000	/* AIF2DACR_ENA */
+#define WM8995_AIF2DACR_ENA_MASK                0x1000	/* AIF2DACR_ENA */
+#define WM8995_AIF2DACR_ENA_SHIFT                   12	/* AIF2DACR_ENA */
+#define WM8995_AIF2DACR_ENA_WIDTH                    1	/* AIF2DACR_ENA */
+#define WM8995_AIF1DAC2L_ENA                    0x0800	/* AIF1DAC2L_ENA */
+#define WM8995_AIF1DAC2L_ENA_MASK               0x0800	/* AIF1DAC2L_ENA */
+#define WM8995_AIF1DAC2L_ENA_SHIFT                  11	/* AIF1DAC2L_ENA */
+#define WM8995_AIF1DAC2L_ENA_WIDTH                   1	/* AIF1DAC2L_ENA */
+#define WM8995_AIF1DAC2R_ENA                    0x0400	/* AIF1DAC2R_ENA */
+#define WM8995_AIF1DAC2R_ENA_MASK               0x0400	/* AIF1DAC2R_ENA */
+#define WM8995_AIF1DAC2R_ENA_SHIFT                  10	/* AIF1DAC2R_ENA */
+#define WM8995_AIF1DAC2R_ENA_WIDTH                   1	/* AIF1DAC2R_ENA */
+#define WM8995_AIF1DAC1L_ENA                    0x0200	/* AIF1DAC1L_ENA */
+#define WM8995_AIF1DAC1L_ENA_MASK               0x0200	/* AIF1DAC1L_ENA */
+#define WM8995_AIF1DAC1L_ENA_SHIFT                   9	/* AIF1DAC1L_ENA */
+#define WM8995_AIF1DAC1L_ENA_WIDTH                   1	/* AIF1DAC1L_ENA */
+#define WM8995_AIF1DAC1R_ENA                    0x0100	/* AIF1DAC1R_ENA */
+#define WM8995_AIF1DAC1R_ENA_MASK               0x0100	/* AIF1DAC1R_ENA */
+#define WM8995_AIF1DAC1R_ENA_SHIFT                   8	/* AIF1DAC1R_ENA */
+#define WM8995_AIF1DAC1R_ENA_WIDTH                   1	/* AIF1DAC1R_ENA */
+#define WM8995_DAC2L_ENA                        0x0008	/* DAC2L_ENA */
+#define WM8995_DAC2L_ENA_MASK                   0x0008	/* DAC2L_ENA */
+#define WM8995_DAC2L_ENA_SHIFT                       3	/* DAC2L_ENA */
+#define WM8995_DAC2L_ENA_WIDTH                       1	/* DAC2L_ENA */
+#define WM8995_DAC2R_ENA                        0x0004	/* DAC2R_ENA */
+#define WM8995_DAC2R_ENA_MASK                   0x0004	/* DAC2R_ENA */
+#define WM8995_DAC2R_ENA_SHIFT                       2	/* DAC2R_ENA */
+#define WM8995_DAC2R_ENA_WIDTH                       1	/* DAC2R_ENA */
+#define WM8995_DAC1L_ENA                        0x0002	/* DAC1L_ENA */
+#define WM8995_DAC1L_ENA_MASK                   0x0002	/* DAC1L_ENA */
+#define WM8995_DAC1L_ENA_SHIFT                       1	/* DAC1L_ENA */
+#define WM8995_DAC1L_ENA_WIDTH                       1	/* DAC1L_ENA */
+#define WM8995_DAC1R_ENA                        0x0001	/* DAC1R_ENA */
+#define WM8995_DAC1R_ENA_MASK                   0x0001	/* DAC1R_ENA */
+#define WM8995_DAC1R_ENA_SHIFT                       0	/* DAC1R_ENA */
+#define WM8995_DAC1R_ENA_WIDTH                       1	/* DAC1R_ENA */
+
+/*
+ * R5 (0x05) - Power Management (5)
+ */
+#define WM8995_DMIC_SRC2_MASK                   0x0300	/* DMIC_SRC2 - [9:8] */
+#define WM8995_DMIC_SRC2_SHIFT                       8	/* DMIC_SRC2 - [9:8] */
+#define WM8995_DMIC_SRC2_WIDTH                       2	/* DMIC_SRC2 - [9:8] */
+#define WM8995_DMIC_SRC1_MASK                   0x00C0	/* DMIC_SRC1 - [7:6] */
+#define WM8995_DMIC_SRC1_SHIFT                       6	/* DMIC_SRC1 - [7:6] */
+#define WM8995_DMIC_SRC1_WIDTH                       2	/* DMIC_SRC1 - [7:6] */
+#define WM8995_AIF3_TRI                         0x0020	/* AIF3_TRI */
+#define WM8995_AIF3_TRI_MASK                    0x0020	/* AIF3_TRI */
+#define WM8995_AIF3_TRI_SHIFT                        5	/* AIF3_TRI */
+#define WM8995_AIF3_TRI_WIDTH                        1	/* AIF3_TRI */
+#define WM8995_AIF3_ADCDAT_SRC_MASK             0x0018	/* AIF3_ADCDAT_SRC - [4:3] */
+#define WM8995_AIF3_ADCDAT_SRC_SHIFT                 3	/* AIF3_ADCDAT_SRC - [4:3] */
+#define WM8995_AIF3_ADCDAT_SRC_WIDTH                 2	/* AIF3_ADCDAT_SRC - [4:3] */
+#define WM8995_AIF2_ADCDAT_SRC                  0x0004	/* AIF2_ADCDAT_SRC */
+#define WM8995_AIF2_ADCDAT_SRC_MASK             0x0004	/* AIF2_ADCDAT_SRC */
+#define WM8995_AIF2_ADCDAT_SRC_SHIFT                 2	/* AIF2_ADCDAT_SRC */
+#define WM8995_AIF2_ADCDAT_SRC_WIDTH                 1	/* AIF2_ADCDAT_SRC */
+#define WM8995_AIF2_DACDAT_SRC                  0x0002	/* AIF2_DACDAT_SRC */
+#define WM8995_AIF2_DACDAT_SRC_MASK             0x0002	/* AIF2_DACDAT_SRC */
+#define WM8995_AIF2_DACDAT_SRC_SHIFT                 1	/* AIF2_DACDAT_SRC */
+#define WM8995_AIF2_DACDAT_SRC_WIDTH                 1	/* AIF2_DACDAT_SRC */
+#define WM8995_AIF1_DACDAT_SRC                  0x0001	/* AIF1_DACDAT_SRC */
+#define WM8995_AIF1_DACDAT_SRC_MASK             0x0001	/* AIF1_DACDAT_SRC */
+#define WM8995_AIF1_DACDAT_SRC_SHIFT                 0	/* AIF1_DACDAT_SRC */
+#define WM8995_AIF1_DACDAT_SRC_WIDTH                 1	/* AIF1_DACDAT_SRC */
+
+/*
+ * R16 (0x10) - Left Line Input 1 Volume
+ */
+#define WM8995_IN1_VU                           0x0080	/* IN1_VU */
+#define WM8995_IN1_VU_MASK                      0x0080	/* IN1_VU */
+#define WM8995_IN1_VU_SHIFT                          7	/* IN1_VU */
+#define WM8995_IN1_VU_WIDTH                          1	/* IN1_VU */
+#define WM8995_IN1L_ZC                          0x0020	/* IN1L_ZC */
+#define WM8995_IN1L_ZC_MASK                     0x0020	/* IN1L_ZC */
+#define WM8995_IN1L_ZC_SHIFT                         5	/* IN1L_ZC */
+#define WM8995_IN1L_ZC_WIDTH                         1	/* IN1L_ZC */
+#define WM8995_IN1L_VOL_MASK                    0x001F	/* IN1L_VOL - [4:0] */
+#define WM8995_IN1L_VOL_SHIFT                        0	/* IN1L_VOL - [4:0] */
+#define WM8995_IN1L_VOL_WIDTH                        5	/* IN1L_VOL - [4:0] */
+
+/*
+ * R17 (0x11) - Right Line Input 1 Volume
+ */
+#define WM8995_IN1_VU                           0x0080	/* IN1_VU */
+#define WM8995_IN1_VU_MASK                      0x0080	/* IN1_VU */
+#define WM8995_IN1_VU_SHIFT                          7	/* IN1_VU */
+#define WM8995_IN1_VU_WIDTH                          1	/* IN1_VU */
+#define WM8995_IN1R_ZC                          0x0020	/* IN1R_ZC */
+#define WM8995_IN1R_ZC_MASK                     0x0020	/* IN1R_ZC */
+#define WM8995_IN1R_ZC_SHIFT                         5	/* IN1R_ZC */
+#define WM8995_IN1R_ZC_WIDTH                         1	/* IN1R_ZC */
+#define WM8995_IN1R_VOL_MASK                    0x001F	/* IN1R_VOL - [4:0] */
+#define WM8995_IN1R_VOL_SHIFT                        0	/* IN1R_VOL - [4:0] */
+#define WM8995_IN1R_VOL_WIDTH                        5	/* IN1R_VOL - [4:0] */
+
+/*
+ * R18 (0x12) - Left Line Input Control
+ */
+#define WM8995_IN1L_BOOST_MASK                  0x0030	/* IN1L_BOOST - [5:4] */
+#define WM8995_IN1L_BOOST_SHIFT                      4	/* IN1L_BOOST - [5:4] */
+#define WM8995_IN1L_BOOST_WIDTH                      2	/* IN1L_BOOST - [5:4] */
+#define WM8995_IN1L_MODE_MASK                   0x000C	/* IN1L_MODE - [3:2] */
+#define WM8995_IN1L_MODE_SHIFT                       2	/* IN1L_MODE - [3:2] */
+#define WM8995_IN1L_MODE_WIDTH                       2	/* IN1L_MODE - [3:2] */
+#define WM8995_IN1R_MODE_MASK                   0x0003	/* IN1R_MODE - [1:0] */
+#define WM8995_IN1R_MODE_SHIFT                       0	/* IN1R_MODE - [1:0] */
+#define WM8995_IN1R_MODE_WIDTH                       2	/* IN1R_MODE - [1:0] */
+
+/*
+ * R24 (0x18) - DAC1 Left Volume
+ */
+#define WM8995_DAC1L_MUTE                       0x0200	/* DAC1L_MUTE */
+#define WM8995_DAC1L_MUTE_MASK                  0x0200	/* DAC1L_MUTE */
+#define WM8995_DAC1L_MUTE_SHIFT                      9	/* DAC1L_MUTE */
+#define WM8995_DAC1L_MUTE_WIDTH                      1	/* DAC1L_MUTE */
+#define WM8995_DAC1_VU                          0x0100	/* DAC1_VU */
+#define WM8995_DAC1_VU_MASK                     0x0100	/* DAC1_VU */
+#define WM8995_DAC1_VU_SHIFT                         8	/* DAC1_VU */
+#define WM8995_DAC1_VU_WIDTH                         1	/* DAC1_VU */
+#define WM8995_DAC1L_VOL_MASK                   0x00FF	/* DAC1L_VOL - [7:0] */
+#define WM8995_DAC1L_VOL_SHIFT                       0	/* DAC1L_VOL - [7:0] */
+#define WM8995_DAC1L_VOL_WIDTH                       8	/* DAC1L_VOL - [7:0] */
+
+/*
+ * R25 (0x19) - DAC1 Right Volume
+ */
+#define WM8995_DAC1R_MUTE                       0x0200	/* DAC1R_MUTE */
+#define WM8995_DAC1R_MUTE_MASK                  0x0200	/* DAC1R_MUTE */
+#define WM8995_DAC1R_MUTE_SHIFT                      9	/* DAC1R_MUTE */
+#define WM8995_DAC1R_MUTE_WIDTH                      1	/* DAC1R_MUTE */
+#define WM8995_DAC1_VU                          0x0100	/* DAC1_VU */
+#define WM8995_DAC1_VU_MASK                     0x0100	/* DAC1_VU */
+#define WM8995_DAC1_VU_SHIFT                         8	/* DAC1_VU */
+#define WM8995_DAC1_VU_WIDTH                         1	/* DAC1_VU */
+#define WM8995_DAC1R_VOL_MASK                   0x00FF	/* DAC1R_VOL - [7:0] */
+#define WM8995_DAC1R_VOL_SHIFT                       0	/* DAC1R_VOL - [7:0] */
+#define WM8995_DAC1R_VOL_WIDTH                       8	/* DAC1R_VOL - [7:0] */
+
+/*
+ * R26 (0x1A) - DAC2 Left Volume
+ */
+#define WM8995_DAC2L_MUTE                       0x0200	/* DAC2L_MUTE */
+#define WM8995_DAC2L_MUTE_MASK                  0x0200	/* DAC2L_MUTE */
+#define WM8995_DAC2L_MUTE_SHIFT                      9	/* DAC2L_MUTE */
+#define WM8995_DAC2L_MUTE_WIDTH                      1	/* DAC2L_MUTE */
+#define WM8995_DAC2_VU                          0x0100	/* DAC2_VU */
+#define WM8995_DAC2_VU_MASK                     0x0100	/* DAC2_VU */
+#define WM8995_DAC2_VU_SHIFT                         8	/* DAC2_VU */
+#define WM8995_DAC2_VU_WIDTH                         1	/* DAC2_VU */
+#define WM8995_DAC2L_VOL_MASK                   0x00FF	/* DAC2L_VOL - [7:0] */
+#define WM8995_DAC2L_VOL_SHIFT                       0	/* DAC2L_VOL - [7:0] */
+#define WM8995_DAC2L_VOL_WIDTH                       8	/* DAC2L_VOL - [7:0] */
+
+/*
+ * R27 (0x1B) - DAC2 Right Volume
+ */
+#define WM8995_DAC2R_MUTE                       0x0200	/* DAC2R_MUTE */
+#define WM8995_DAC2R_MUTE_MASK                  0x0200	/* DAC2R_MUTE */
+#define WM8995_DAC2R_MUTE_SHIFT                      9	/* DAC2R_MUTE */
+#define WM8995_DAC2R_MUTE_WIDTH                      1	/* DAC2R_MUTE */
+#define WM8995_DAC2_VU                          0x0100	/* DAC2_VU */
+#define WM8995_DAC2_VU_MASK                     0x0100	/* DAC2_VU */
+#define WM8995_DAC2_VU_SHIFT                         8	/* DAC2_VU */
+#define WM8995_DAC2_VU_WIDTH                         1	/* DAC2_VU */
+#define WM8995_DAC2R_VOL_MASK                   0x00FF	/* DAC2R_VOL - [7:0] */
+#define WM8995_DAC2R_VOL_SHIFT                       0	/* DAC2R_VOL - [7:0] */
+#define WM8995_DAC2R_VOL_WIDTH                       8	/* DAC2R_VOL - [7:0] */
+
+/*
+ * R28 (0x1C) - Output Volume ZC (1)
+ */
+#define WM8995_HPOUT2L_ZC                       0x0008	/* HPOUT2L_ZC */
+#define WM8995_HPOUT2L_ZC_MASK                  0x0008	/* HPOUT2L_ZC */
+#define WM8995_HPOUT2L_ZC_SHIFT                      3	/* HPOUT2L_ZC */
+#define WM8995_HPOUT2L_ZC_WIDTH                      1	/* HPOUT2L_ZC */
+#define WM8995_HPOUT2R_ZC                       0x0004	/* HPOUT2R_ZC */
+#define WM8995_HPOUT2R_ZC_MASK                  0x0004	/* HPOUT2R_ZC */
+#define WM8995_HPOUT2R_ZC_SHIFT                      2	/* HPOUT2R_ZC */
+#define WM8995_HPOUT2R_ZC_WIDTH                      1	/* HPOUT2R_ZC */
+#define WM8995_HPOUT1L_ZC                       0x0002	/* HPOUT1L_ZC */
+#define WM8995_HPOUT1L_ZC_MASK                  0x0002	/* HPOUT1L_ZC */
+#define WM8995_HPOUT1L_ZC_SHIFT                      1	/* HPOUT1L_ZC */
+#define WM8995_HPOUT1L_ZC_WIDTH                      1	/* HPOUT1L_ZC */
+#define WM8995_HPOUT1R_ZC                       0x0001	/* HPOUT1R_ZC */
+#define WM8995_HPOUT1R_ZC_MASK                  0x0001	/* HPOUT1R_ZC */
+#define WM8995_HPOUT1R_ZC_SHIFT                      0	/* HPOUT1R_ZC */
+#define WM8995_HPOUT1R_ZC_WIDTH                      1	/* HPOUT1R_ZC */
+
+/*
+ * R32 (0x20) - MICBIAS (1)
+ */
+#define WM8995_MICB1_MODE                       0x0008	/* MICB1_MODE */
+#define WM8995_MICB1_MODE_MASK                  0x0008	/* MICB1_MODE */
+#define WM8995_MICB1_MODE_SHIFT                      3	/* MICB1_MODE */
+#define WM8995_MICB1_MODE_WIDTH                      1	/* MICB1_MODE */
+#define WM8995_MICB1_LVL_MASK                   0x0006	/* MICB1_LVL - [2:1] */
+#define WM8995_MICB1_LVL_SHIFT                       1	/* MICB1_LVL - [2:1] */
+#define WM8995_MICB1_LVL_WIDTH                       2	/* MICB1_LVL - [2:1] */
+#define WM8995_MICB1_DISCH                      0x0001	/* MICB1_DISCH */
+#define WM8995_MICB1_DISCH_MASK                 0x0001	/* MICB1_DISCH */
+#define WM8995_MICB1_DISCH_SHIFT                     0	/* MICB1_DISCH */
+#define WM8995_MICB1_DISCH_WIDTH                     1	/* MICB1_DISCH */
+
+/*
+ * R33 (0x21) - MICBIAS (2)
+ */
+#define WM8995_MICB2_MODE                       0x0008	/* MICB2_MODE */
+#define WM8995_MICB2_MODE_MASK                  0x0008	/* MICB2_MODE */
+#define WM8995_MICB2_MODE_SHIFT                      3	/* MICB2_MODE */
+#define WM8995_MICB2_MODE_WIDTH                      1	/* MICB2_MODE */
+#define WM8995_MICB2_LVL_MASK                   0x0006	/* MICB2_LVL - [2:1] */
+#define WM8995_MICB2_LVL_SHIFT                       1	/* MICB2_LVL - [2:1] */
+#define WM8995_MICB2_LVL_WIDTH                       2	/* MICB2_LVL - [2:1] */
+#define WM8995_MICB2_DISCH                      0x0001	/* MICB2_DISCH */
+#define WM8995_MICB2_DISCH_MASK                 0x0001	/* MICB2_DISCH */
+#define WM8995_MICB2_DISCH_SHIFT                     0	/* MICB2_DISCH */
+#define WM8995_MICB2_DISCH_WIDTH                     1	/* MICB2_DISCH */
+
+/*
+ * R40 (0x28) - LDO 1
+ */
+#define WM8995_LDO1_MODE                        0x0020	/* LDO1_MODE */
+#define WM8995_LDO1_MODE_MASK                   0x0020	/* LDO1_MODE */
+#define WM8995_LDO1_MODE_SHIFT                       5	/* LDO1_MODE */
+#define WM8995_LDO1_MODE_WIDTH                       1	/* LDO1_MODE */
+#define WM8995_LDO1_VSEL_MASK                   0x0006	/* LDO1_VSEL - [2:1] */
+#define WM8995_LDO1_VSEL_SHIFT                       1	/* LDO1_VSEL - [2:1] */
+#define WM8995_LDO1_VSEL_WIDTH                       2	/* LDO1_VSEL - [2:1] */
+#define WM8995_LDO1_DISCH                       0x0001	/* LDO1_DISCH */
+#define WM8995_LDO1_DISCH_MASK                  0x0001	/* LDO1_DISCH */
+#define WM8995_LDO1_DISCH_SHIFT                      0	/* LDO1_DISCH */
+#define WM8995_LDO1_DISCH_WIDTH                      1	/* LDO1_DISCH */
+
+/*
+ * R41 (0x29) - LDO 2
+ */
+#define WM8995_LDO2_MODE                        0x0020	/* LDO2_MODE */
+#define WM8995_LDO2_MODE_MASK                   0x0020	/* LDO2_MODE */
+#define WM8995_LDO2_MODE_SHIFT                       5	/* LDO2_MODE */
+#define WM8995_LDO2_MODE_WIDTH                       1	/* LDO2_MODE */
+#define WM8995_LDO2_VSEL_MASK                   0x001E	/* LDO2_VSEL - [4:1] */
+#define WM8995_LDO2_VSEL_SHIFT                       1	/* LDO2_VSEL - [4:1] */
+#define WM8995_LDO2_VSEL_WIDTH                       4	/* LDO2_VSEL - [4:1] */
+#define WM8995_LDO2_DISCH                       0x0001	/* LDO2_DISCH */
+#define WM8995_LDO2_DISCH_MASK                  0x0001	/* LDO2_DISCH */
+#define WM8995_LDO2_DISCH_SHIFT                      0	/* LDO2_DISCH */
+#define WM8995_LDO2_DISCH_WIDTH                      1	/* LDO2_DISCH */
+
+/*
+ * R48 (0x30) - Accessory Detect Mode1
+ */
+#define WM8995_JD_MODE_MASK                     0x0003	/* JD_MODE - [1:0] */
+#define WM8995_JD_MODE_SHIFT                         0	/* JD_MODE - [1:0] */
+#define WM8995_JD_MODE_WIDTH                         2	/* JD_MODE - [1:0] */
+
+/*
+ * R49 (0x31) - Accessory Detect Mode2
+ */
+#define WM8995_VID_ENA                          0x0001	/* VID_ENA */
+#define WM8995_VID_ENA_MASK                     0x0001	/* VID_ENA */
+#define WM8995_VID_ENA_SHIFT                         0	/* VID_ENA */
+#define WM8995_VID_ENA_WIDTH                         1	/* VID_ENA */
+
+/*
+ * R52 (0x34) - Headphone Detect1
+ */
+#define WM8995_HP_RAMPRATE                      0x0002	/* HP_RAMPRATE */
+#define WM8995_HP_RAMPRATE_MASK                 0x0002	/* HP_RAMPRATE */
+#define WM8995_HP_RAMPRATE_SHIFT                     1	/* HP_RAMPRATE */
+#define WM8995_HP_RAMPRATE_WIDTH                     1	/* HP_RAMPRATE */
+#define WM8995_HP_POLL                          0x0001	/* HP_POLL */
+#define WM8995_HP_POLL_MASK                     0x0001	/* HP_POLL */
+#define WM8995_HP_POLL_SHIFT                         0	/* HP_POLL */
+#define WM8995_HP_POLL_WIDTH                         1	/* HP_POLL */
+
+/*
+ * R53 (0x35) - Headphone Detect2
+ */
+#define WM8995_HP_DONE                          0x0080	/* HP_DONE */
+#define WM8995_HP_DONE_MASK                     0x0080	/* HP_DONE */
+#define WM8995_HP_DONE_SHIFT                         7	/* HP_DONE */
+#define WM8995_HP_DONE_WIDTH                         1	/* HP_DONE */
+#define WM8995_HP_LVL_MASK                      0x007F	/* HP_LVL - [6:0] */
+#define WM8995_HP_LVL_SHIFT                          0	/* HP_LVL - [6:0] */
+#define WM8995_HP_LVL_WIDTH                          7	/* HP_LVL - [6:0] */
+
+/*
+ * R56 (0x38) - Mic Detect (1)
+ */
+#define WM8995_MICD_RATE_MASK                   0x7800	/* MICD_RATE - [14:11] */
+#define WM8995_MICD_RATE_SHIFT                      11	/* MICD_RATE - [14:11] */
+#define WM8995_MICD_RATE_WIDTH                       4	/* MICD_RATE - [14:11] */
+#define WM8995_MICD_LVL_SEL_MASK                0x01F8	/* MICD_LVL_SEL - [8:3] */
+#define WM8995_MICD_LVL_SEL_SHIFT                    3	/* MICD_LVL_SEL - [8:3] */
+#define WM8995_MICD_LVL_SEL_WIDTH                    6	/* MICD_LVL_SEL - [8:3] */
+#define WM8995_MICD_DBTIME                      0x0002	/* MICD_DBTIME */
+#define WM8995_MICD_DBTIME_MASK                 0x0002	/* MICD_DBTIME */
+#define WM8995_MICD_DBTIME_SHIFT                     1	/* MICD_DBTIME */
+#define WM8995_MICD_DBTIME_WIDTH                     1	/* MICD_DBTIME */
+#define WM8995_MICD_ENA                         0x0001	/* MICD_ENA */
+#define WM8995_MICD_ENA_MASK                    0x0001	/* MICD_ENA */
+#define WM8995_MICD_ENA_SHIFT                        0	/* MICD_ENA */
+#define WM8995_MICD_ENA_WIDTH                        1	/* MICD_ENA */
+
+/*
+ * R57 (0x39) - Mic Detect (2)
+ */
+#define WM8995_MICD_LVL_MASK                    0x01FC	/* MICD_LVL - [8:2] */
+#define WM8995_MICD_LVL_SHIFT                        2	/* MICD_LVL - [8:2] */
+#define WM8995_MICD_LVL_WIDTH                        7	/* MICD_LVL - [8:2] */
+#define WM8995_MICD_VALID                       0x0002	/* MICD_VALID */
+#define WM8995_MICD_VALID_MASK                  0x0002	/* MICD_VALID */
+#define WM8995_MICD_VALID_SHIFT                      1	/* MICD_VALID */
+#define WM8995_MICD_VALID_WIDTH                      1	/* MICD_VALID */
+#define WM8995_MICD_STS                         0x0001	/* MICD_STS */
+#define WM8995_MICD_STS_MASK                    0x0001	/* MICD_STS */
+#define WM8995_MICD_STS_SHIFT                        0	/* MICD_STS */
+#define WM8995_MICD_STS_WIDTH                        1	/* MICD_STS */
+
+/*
+ * R64 (0x40) - Charge Pump (1)
+ */
+#define WM8995_CP_ENA                           0x8000	/* CP_ENA */
+#define WM8995_CP_ENA_MASK                      0x8000	/* CP_ENA */
+#define WM8995_CP_ENA_SHIFT                         15	/* CP_ENA */
+#define WM8995_CP_ENA_WIDTH                          1	/* CP_ENA */
+
+/*
+ * R69 (0x45) - Class W (1)
+ */
+#define WM8995_CP_DYN_SRC_SEL_MASK              0x0300	/* CP_DYN_SRC_SEL - [9:8] */
+#define WM8995_CP_DYN_SRC_SEL_SHIFT                  8	/* CP_DYN_SRC_SEL - [9:8] */
+#define WM8995_CP_DYN_SRC_SEL_WIDTH                  2	/* CP_DYN_SRC_SEL - [9:8] */
+#define WM8995_CP_DYN_PWR                       0x0001	/* CP_DYN_PWR */
+#define WM8995_CP_DYN_PWR_MASK                  0x0001	/* CP_DYN_PWR */
+#define WM8995_CP_DYN_PWR_SHIFT                      0	/* CP_DYN_PWR */
+#define WM8995_CP_DYN_PWR_WIDTH                      1	/* CP_DYN_PWR */
+
+/*
+ * R80 (0x50) - DC Servo (1)
+ */
+#define WM8995_DCS_ENA_CHAN_3                   0x0008	/* DCS_ENA_CHAN_3 */
+#define WM8995_DCS_ENA_CHAN_3_MASK              0x0008	/* DCS_ENA_CHAN_3 */
+#define WM8995_DCS_ENA_CHAN_3_SHIFT                  3	/* DCS_ENA_CHAN_3 */
+#define WM8995_DCS_ENA_CHAN_3_WIDTH                  1	/* DCS_ENA_CHAN_3 */
+#define WM8995_DCS_ENA_CHAN_2                   0x0004	/* DCS_ENA_CHAN_2 */
+#define WM8995_DCS_ENA_CHAN_2_MASK              0x0004	/* DCS_ENA_CHAN_2 */
+#define WM8995_DCS_ENA_CHAN_2_SHIFT                  2	/* DCS_ENA_CHAN_2 */
+#define WM8995_DCS_ENA_CHAN_2_WIDTH                  1	/* DCS_ENA_CHAN_2 */
+#define WM8995_DCS_ENA_CHAN_1                   0x0002	/* DCS_ENA_CHAN_1 */
+#define WM8995_DCS_ENA_CHAN_1_MASK              0x0002	/* DCS_ENA_CHAN_1 */
+#define WM8995_DCS_ENA_CHAN_1_SHIFT                  1	/* DCS_ENA_CHAN_1 */
+#define WM8995_DCS_ENA_CHAN_1_WIDTH                  1	/* DCS_ENA_CHAN_1 */
+#define WM8995_DCS_ENA_CHAN_0                   0x0001	/* DCS_ENA_CHAN_0 */
+#define WM8995_DCS_ENA_CHAN_0_MASK              0x0001	/* DCS_ENA_CHAN_0 */
+#define WM8995_DCS_ENA_CHAN_0_SHIFT                  0	/* DCS_ENA_CHAN_0 */
+#define WM8995_DCS_ENA_CHAN_0_WIDTH                  1	/* DCS_ENA_CHAN_0 */
+
+/*
+ * R81 (0x51) - DC Servo (2)
+ */
+#define WM8995_DCS_TRIG_SINGLE_3                0x8000	/* DCS_TRIG_SINGLE_3 */
+#define WM8995_DCS_TRIG_SINGLE_3_MASK           0x8000	/* DCS_TRIG_SINGLE_3 */
+#define WM8995_DCS_TRIG_SINGLE_3_SHIFT              15	/* DCS_TRIG_SINGLE_3 */
+#define WM8995_DCS_TRIG_SINGLE_3_WIDTH               1	/* DCS_TRIG_SINGLE_3 */
+#define WM8995_DCS_TRIG_SINGLE_2                0x4000	/* DCS_TRIG_SINGLE_2 */
+#define WM8995_DCS_TRIG_SINGLE_2_MASK           0x4000	/* DCS_TRIG_SINGLE_2 */
+#define WM8995_DCS_TRIG_SINGLE_2_SHIFT              14	/* DCS_TRIG_SINGLE_2 */
+#define WM8995_DCS_TRIG_SINGLE_2_WIDTH               1	/* DCS_TRIG_SINGLE_2 */
+#define WM8995_DCS_TRIG_SINGLE_1                0x2000	/* DCS_TRIG_SINGLE_1 */
+#define WM8995_DCS_TRIG_SINGLE_1_MASK           0x2000	/* DCS_TRIG_SINGLE_1 */
+#define WM8995_DCS_TRIG_SINGLE_1_SHIFT              13	/* DCS_TRIG_SINGLE_1 */
+#define WM8995_DCS_TRIG_SINGLE_1_WIDTH               1	/* DCS_TRIG_SINGLE_1 */
+#define WM8995_DCS_TRIG_SINGLE_0                0x1000	/* DCS_TRIG_SINGLE_0 */
+#define WM8995_DCS_TRIG_SINGLE_0_MASK           0x1000	/* DCS_TRIG_SINGLE_0 */
+#define WM8995_DCS_TRIG_SINGLE_0_SHIFT              12	/* DCS_TRIG_SINGLE_0 */
+#define WM8995_DCS_TRIG_SINGLE_0_WIDTH               1	/* DCS_TRIG_SINGLE_0 */
+#define WM8995_DCS_TRIG_SERIES_3                0x0800	/* DCS_TRIG_SERIES_3 */
+#define WM8995_DCS_TRIG_SERIES_3_MASK           0x0800	/* DCS_TRIG_SERIES_3 */
+#define WM8995_DCS_TRIG_SERIES_3_SHIFT              11	/* DCS_TRIG_SERIES_3 */
+#define WM8995_DCS_TRIG_SERIES_3_WIDTH               1	/* DCS_TRIG_SERIES_3 */
+#define WM8995_DCS_TRIG_SERIES_2                0x0400	/* DCS_TRIG_SERIES_2 */
+#define WM8995_DCS_TRIG_SERIES_2_MASK           0x0400	/* DCS_TRIG_SERIES_2 */
+#define WM8995_DCS_TRIG_SERIES_2_SHIFT              10	/* DCS_TRIG_SERIES_2 */
+#define WM8995_DCS_TRIG_SERIES_2_WIDTH               1	/* DCS_TRIG_SERIES_2 */
+#define WM8995_DCS_TRIG_SERIES_1                0x0200	/* DCS_TRIG_SERIES_1 */
+#define WM8995_DCS_TRIG_SERIES_1_MASK           0x0200	/* DCS_TRIG_SERIES_1 */
+#define WM8995_DCS_TRIG_SERIES_1_SHIFT               9	/* DCS_TRIG_SERIES_1 */
+#define WM8995_DCS_TRIG_SERIES_1_WIDTH               1	/* DCS_TRIG_SERIES_1 */
+#define WM8995_DCS_TRIG_SERIES_0                0x0100	/* DCS_TRIG_SERIES_0 */
+#define WM8995_DCS_TRIG_SERIES_0_MASK           0x0100	/* DCS_TRIG_SERIES_0 */
+#define WM8995_DCS_TRIG_SERIES_0_SHIFT               8	/* DCS_TRIG_SERIES_0 */
+#define WM8995_DCS_TRIG_SERIES_0_WIDTH               1	/* DCS_TRIG_SERIES_0 */
+#define WM8995_DCS_TRIG_STARTUP_3               0x0080	/* DCS_TRIG_STARTUP_3 */
+#define WM8995_DCS_TRIG_STARTUP_3_MASK          0x0080	/* DCS_TRIG_STARTUP_3 */
+#define WM8995_DCS_TRIG_STARTUP_3_SHIFT              7	/* DCS_TRIG_STARTUP_3 */
+#define WM8995_DCS_TRIG_STARTUP_3_WIDTH              1	/* DCS_TRIG_STARTUP_3 */
+#define WM8995_DCS_TRIG_STARTUP_2               0x0040	/* DCS_TRIG_STARTUP_2 */
+#define WM8995_DCS_TRIG_STARTUP_2_MASK          0x0040	/* DCS_TRIG_STARTUP_2 */
+#define WM8995_DCS_TRIG_STARTUP_2_SHIFT              6	/* DCS_TRIG_STARTUP_2 */
+#define WM8995_DCS_TRIG_STARTUP_2_WIDTH              1	/* DCS_TRIG_STARTUP_2 */
+#define WM8995_DCS_TRIG_STARTUP_1               0x0020	/* DCS_TRIG_STARTUP_1 */
+#define WM8995_DCS_TRIG_STARTUP_1_MASK          0x0020	/* DCS_TRIG_STARTUP_1 */
+#define WM8995_DCS_TRIG_STARTUP_1_SHIFT              5	/* DCS_TRIG_STARTUP_1 */
+#define WM8995_DCS_TRIG_STARTUP_1_WIDTH              1	/* DCS_TRIG_STARTUP_1 */
+#define WM8995_DCS_TRIG_STARTUP_0               0x0010	/* DCS_TRIG_STARTUP_0 */
+#define WM8995_DCS_TRIG_STARTUP_0_MASK          0x0010	/* DCS_TRIG_STARTUP_0 */
+#define WM8995_DCS_TRIG_STARTUP_0_SHIFT              4	/* DCS_TRIG_STARTUP_0 */
+#define WM8995_DCS_TRIG_STARTUP_0_WIDTH              1	/* DCS_TRIG_STARTUP_0 */
+#define WM8995_DCS_TRIG_DAC_WR_3                0x0008	/* DCS_TRIG_DAC_WR_3 */
+#define WM8995_DCS_TRIG_DAC_WR_3_MASK           0x0008	/* DCS_TRIG_DAC_WR_3 */
+#define WM8995_DCS_TRIG_DAC_WR_3_SHIFT               3	/* DCS_TRIG_DAC_WR_3 */
+#define WM8995_DCS_TRIG_DAC_WR_3_WIDTH               1	/* DCS_TRIG_DAC_WR_3 */
+#define WM8995_DCS_TRIG_DAC_WR_2                0x0004	/* DCS_TRIG_DAC_WR_2 */
+#define WM8995_DCS_TRIG_DAC_WR_2_MASK           0x0004	/* DCS_TRIG_DAC_WR_2 */
+#define WM8995_DCS_TRIG_DAC_WR_2_SHIFT               2	/* DCS_TRIG_DAC_WR_2 */
+#define WM8995_DCS_TRIG_DAC_WR_2_WIDTH               1	/* DCS_TRIG_DAC_WR_2 */
+#define WM8995_DCS_TRIG_DAC_WR_1                0x0002	/* DCS_TRIG_DAC_WR_1 */
+#define WM8995_DCS_TRIG_DAC_WR_1_MASK           0x0002	/* DCS_TRIG_DAC_WR_1 */
+#define WM8995_DCS_TRIG_DAC_WR_1_SHIFT               1	/* DCS_TRIG_DAC_WR_1 */
+#define WM8995_DCS_TRIG_DAC_WR_1_WIDTH               1	/* DCS_TRIG_DAC_WR_1 */
+#define WM8995_DCS_TRIG_DAC_WR_0                0x0001	/* DCS_TRIG_DAC_WR_0 */
+#define WM8995_DCS_TRIG_DAC_WR_0_MASK           0x0001	/* DCS_TRIG_DAC_WR_0 */
+#define WM8995_DCS_TRIG_DAC_WR_0_SHIFT               0	/* DCS_TRIG_DAC_WR_0 */
+#define WM8995_DCS_TRIG_DAC_WR_0_WIDTH               1	/* DCS_TRIG_DAC_WR_0 */
+
+/*
+ * R82 (0x52) - DC Servo (3)
+ */
+#define WM8995_DCS_TIMER_PERIOD_23_MASK         0x0F00	/* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8995_DCS_TIMER_PERIOD_23_SHIFT             8	/* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8995_DCS_TIMER_PERIOD_23_WIDTH             4	/* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8995_DCS_TIMER_PERIOD_01_MASK         0x000F	/* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8995_DCS_TIMER_PERIOD_01_SHIFT             0	/* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8995_DCS_TIMER_PERIOD_01_WIDTH             4	/* DCS_TIMER_PERIOD_01 - [3:0] */
+
+/*
+ * R84 (0x54) - DC Servo (5)
+ */
+#define WM8995_DCS_SERIES_NO_23_MASK            0x7F00	/* DCS_SERIES_NO_23 - [14:8] */
+#define WM8995_DCS_SERIES_NO_23_SHIFT                8	/* DCS_SERIES_NO_23 - [14:8] */
+#define WM8995_DCS_SERIES_NO_23_WIDTH                7	/* DCS_SERIES_NO_23 - [14:8] */
+#define WM8995_DCS_SERIES_NO_01_MASK            0x007F	/* DCS_SERIES_NO_01 - [6:0] */
+#define WM8995_DCS_SERIES_NO_01_SHIFT                0	/* DCS_SERIES_NO_01 - [6:0] */
+#define WM8995_DCS_SERIES_NO_01_WIDTH                7	/* DCS_SERIES_NO_01 - [6:0] */
+
+/*
+ * R85 (0x55) - DC Servo (6)
+ */
+#define WM8995_DCS_DAC_WR_VAL_3_MASK            0xFF00	/* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8995_DCS_DAC_WR_VAL_3_SHIFT                8	/* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8995_DCS_DAC_WR_VAL_3_WIDTH                8	/* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8995_DCS_DAC_WR_VAL_2_MASK            0x00FF	/* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8995_DCS_DAC_WR_VAL_2_SHIFT                0	/* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8995_DCS_DAC_WR_VAL_2_WIDTH                8	/* DCS_DAC_WR_VAL_2 - [7:0] */
+
+/*
+ * R86 (0x56) - DC Servo (7)
+ */
+#define WM8995_DCS_DAC_WR_VAL_1_MASK            0xFF00	/* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8995_DCS_DAC_WR_VAL_1_SHIFT                8	/* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8995_DCS_DAC_WR_VAL_1_WIDTH                8	/* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8995_DCS_DAC_WR_VAL_0_MASK            0x00FF	/* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8995_DCS_DAC_WR_VAL_0_SHIFT                0	/* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8995_DCS_DAC_WR_VAL_0_WIDTH                8	/* DCS_DAC_WR_VAL_0 - [7:0] */
+
+/*
+ * R87 (0x57) - DC Servo Readback 0
+ */
+#define WM8995_DCS_CAL_COMPLETE_MASK            0x0F00	/* DCS_CAL_COMPLETE - [11:8] */
+#define WM8995_DCS_CAL_COMPLETE_SHIFT                8	/* DCS_CAL_COMPLETE - [11:8] */
+#define WM8995_DCS_CAL_COMPLETE_WIDTH                4	/* DCS_CAL_COMPLETE - [11:8] */
+#define WM8995_DCS_DAC_WR_COMPLETE_MASK         0x00F0	/* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8995_DCS_DAC_WR_COMPLETE_SHIFT             4	/* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8995_DCS_DAC_WR_COMPLETE_WIDTH             4	/* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8995_DCS_STARTUP_COMPLETE_MASK        0x000F	/* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8995_DCS_STARTUP_COMPLETE_SHIFT            0	/* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8995_DCS_STARTUP_COMPLETE_WIDTH            4	/* DCS_STARTUP_COMPLETE - [3:0] */
+
+/*
+ * R96 (0x60) - Analogue HP (1)
+ */
+#define WM8995_HPOUT1L_RMV_SHORT                0x0080	/* HPOUT1L_RMV_SHORT */
+#define WM8995_HPOUT1L_RMV_SHORT_MASK           0x0080	/* HPOUT1L_RMV_SHORT */
+#define WM8995_HPOUT1L_RMV_SHORT_SHIFT               7	/* HPOUT1L_RMV_SHORT */
+#define WM8995_HPOUT1L_RMV_SHORT_WIDTH               1	/* HPOUT1L_RMV_SHORT */
+#define WM8995_HPOUT1L_OUTP                     0x0040	/* HPOUT1L_OUTP */
+#define WM8995_HPOUT1L_OUTP_MASK                0x0040	/* HPOUT1L_OUTP */
+#define WM8995_HPOUT1L_OUTP_SHIFT                    6	/* HPOUT1L_OUTP */
+#define WM8995_HPOUT1L_OUTP_WIDTH                    1	/* HPOUT1L_OUTP */
+#define WM8995_HPOUT1L_DLY                      0x0020	/* HPOUT1L_DLY */
+#define WM8995_HPOUT1L_DLY_MASK                 0x0020	/* HPOUT1L_DLY */
+#define WM8995_HPOUT1L_DLY_SHIFT                     5	/* HPOUT1L_DLY */
+#define WM8995_HPOUT1L_DLY_WIDTH                     1	/* HPOUT1L_DLY */
+#define WM8995_HPOUT1R_RMV_SHORT                0x0008	/* HPOUT1R_RMV_SHORT */
+#define WM8995_HPOUT1R_RMV_SHORT_MASK           0x0008	/* HPOUT1R_RMV_SHORT */
+#define WM8995_HPOUT1R_RMV_SHORT_SHIFT               3	/* HPOUT1R_RMV_SHORT */
+#define WM8995_HPOUT1R_RMV_SHORT_WIDTH               1	/* HPOUT1R_RMV_SHORT */
+#define WM8995_HPOUT1R_OUTP                     0x0004	/* HPOUT1R_OUTP */
+#define WM8995_HPOUT1R_OUTP_MASK                0x0004	/* HPOUT1R_OUTP */
+#define WM8995_HPOUT1R_OUTP_SHIFT                    2	/* HPOUT1R_OUTP */
+#define WM8995_HPOUT1R_OUTP_WIDTH                    1	/* HPOUT1R_OUTP */
+#define WM8995_HPOUT1R_DLY                      0x0002	/* HPOUT1R_DLY */
+#define WM8995_HPOUT1R_DLY_MASK                 0x0002	/* HPOUT1R_DLY */
+#define WM8995_HPOUT1R_DLY_SHIFT                     1	/* HPOUT1R_DLY */
+#define WM8995_HPOUT1R_DLY_WIDTH                     1	/* HPOUT1R_DLY */
+
+/*
+ * R97 (0x61) - Analogue HP (2)
+ */
+#define WM8995_HPOUT2L_RMV_SHORT                0x0080	/* HPOUT2L_RMV_SHORT */
+#define WM8995_HPOUT2L_RMV_SHORT_MASK           0x0080	/* HPOUT2L_RMV_SHORT */
+#define WM8995_HPOUT2L_RMV_SHORT_SHIFT               7	/* HPOUT2L_RMV_SHORT */
+#define WM8995_HPOUT2L_RMV_SHORT_WIDTH               1	/* HPOUT2L_RMV_SHORT */
+#define WM8995_HPOUT2L_OUTP                     0x0040	/* HPOUT2L_OUTP */
+#define WM8995_HPOUT2L_OUTP_MASK                0x0040	/* HPOUT2L_OUTP */
+#define WM8995_HPOUT2L_OUTP_SHIFT                    6	/* HPOUT2L_OUTP */
+#define WM8995_HPOUT2L_OUTP_WIDTH                    1	/* HPOUT2L_OUTP */
+#define WM8995_HPOUT2L_DLY                      0x0020	/* HPOUT2L_DLY */
+#define WM8995_HPOUT2L_DLY_MASK                 0x0020	/* HPOUT2L_DLY */
+#define WM8995_HPOUT2L_DLY_SHIFT                     5	/* HPOUT2L_DLY */
+#define WM8995_HPOUT2L_DLY_WIDTH                     1	/* HPOUT2L_DLY */
+#define WM8995_HPOUT2R_RMV_SHORT                0x0008	/* HPOUT2R_RMV_SHORT */
+#define WM8995_HPOUT2R_RMV_SHORT_MASK           0x0008	/* HPOUT2R_RMV_SHORT */
+#define WM8995_HPOUT2R_RMV_SHORT_SHIFT               3	/* HPOUT2R_RMV_SHORT */
+#define WM8995_HPOUT2R_RMV_SHORT_WIDTH               1	/* HPOUT2R_RMV_SHORT */
+#define WM8995_HPOUT2R_OUTP                     0x0004	/* HPOUT2R_OUTP */
+#define WM8995_HPOUT2R_OUTP_MASK                0x0004	/* HPOUT2R_OUTP */
+#define WM8995_HPOUT2R_OUTP_SHIFT                    2	/* HPOUT2R_OUTP */
+#define WM8995_HPOUT2R_OUTP_WIDTH                    1	/* HPOUT2R_OUTP */
+#define WM8995_HPOUT2R_DLY                      0x0002	/* HPOUT2R_DLY */
+#define WM8995_HPOUT2R_DLY_MASK                 0x0002	/* HPOUT2R_DLY */
+#define WM8995_HPOUT2R_DLY_SHIFT                     1	/* HPOUT2R_DLY */
+#define WM8995_HPOUT2R_DLY_WIDTH                     1	/* HPOUT2R_DLY */
+
+/*
+ * R256 (0x100) - Chip Revision
+ */
+#define WM8995_CHIP_REV_MASK                    0x000F	/* CHIP_REV - [3:0] */
+#define WM8995_CHIP_REV_SHIFT                        0	/* CHIP_REV - [3:0] */
+#define WM8995_CHIP_REV_WIDTH                        4	/* CHIP_REV - [3:0] */
+
+/*
+ * R257 (0x101) - Control Interface (1)
+ */
+#define WM8995_REG_SYNC                         0x8000	/* REG_SYNC */
+#define WM8995_REG_SYNC_MASK                    0x8000	/* REG_SYNC */
+#define WM8995_REG_SYNC_SHIFT                       15	/* REG_SYNC */
+#define WM8995_REG_SYNC_WIDTH                        1	/* REG_SYNC */
+#define WM8995_SPI_CONTRD                       0x0040	/* SPI_CONTRD */
+#define WM8995_SPI_CONTRD_MASK                  0x0040	/* SPI_CONTRD */
+#define WM8995_SPI_CONTRD_SHIFT                      6	/* SPI_CONTRD */
+#define WM8995_SPI_CONTRD_WIDTH                      1	/* SPI_CONTRD */
+#define WM8995_SPI_4WIRE                        0x0020	/* SPI_4WIRE */
+#define WM8995_SPI_4WIRE_MASK                   0x0020	/* SPI_4WIRE */
+#define WM8995_SPI_4WIRE_SHIFT                       5	/* SPI_4WIRE */
+#define WM8995_SPI_4WIRE_WIDTH                       1	/* SPI_4WIRE */
+#define WM8995_SPI_CFG                          0x0010	/* SPI_CFG */
+#define WM8995_SPI_CFG_MASK                     0x0010	/* SPI_CFG */
+#define WM8995_SPI_CFG_SHIFT                         4	/* SPI_CFG */
+#define WM8995_SPI_CFG_WIDTH                         1	/* SPI_CFG */
+#define WM8995_AUTO_INC                         0x0004	/* AUTO_INC */
+#define WM8995_AUTO_INC_MASK                    0x0004	/* AUTO_INC */
+#define WM8995_AUTO_INC_SHIFT                        2	/* AUTO_INC */
+#define WM8995_AUTO_INC_WIDTH                        1	/* AUTO_INC */
+
+/*
+ * R258 (0x102) - Control Interface (2)
+ */
+#define WM8995_CTRL_IF_SRC                      0x0001	/* CTRL_IF_SRC */
+#define WM8995_CTRL_IF_SRC_MASK                 0x0001	/* CTRL_IF_SRC */
+#define WM8995_CTRL_IF_SRC_SHIFT                     0	/* CTRL_IF_SRC */
+#define WM8995_CTRL_IF_SRC_WIDTH                     1	/* CTRL_IF_SRC */
+
+/*
+ * R272 (0x110) - Write Sequencer Ctrl (1)
+ */
+#define WM8995_WSEQ_ENA                         0x8000	/* WSEQ_ENA */
+#define WM8995_WSEQ_ENA_MASK                    0x8000	/* WSEQ_ENA */
+#define WM8995_WSEQ_ENA_SHIFT                       15	/* WSEQ_ENA */
+#define WM8995_WSEQ_ENA_WIDTH                        1	/* WSEQ_ENA */
+#define WM8995_WSEQ_ABORT                       0x0200	/* WSEQ_ABORT */
+#define WM8995_WSEQ_ABORT_MASK                  0x0200	/* WSEQ_ABORT */
+#define WM8995_WSEQ_ABORT_SHIFT                      9	/* WSEQ_ABORT */
+#define WM8995_WSEQ_ABORT_WIDTH                      1	/* WSEQ_ABORT */
+#define WM8995_WSEQ_START                       0x0100	/* WSEQ_START */
+#define WM8995_WSEQ_START_MASK                  0x0100	/* WSEQ_START */
+#define WM8995_WSEQ_START_SHIFT                      8	/* WSEQ_START */
+#define WM8995_WSEQ_START_WIDTH                      1	/* WSEQ_START */
+#define WM8995_WSEQ_START_INDEX_MASK            0x007F	/* WSEQ_START_INDEX - [6:0] */
+#define WM8995_WSEQ_START_INDEX_SHIFT                0	/* WSEQ_START_INDEX - [6:0] */
+#define WM8995_WSEQ_START_INDEX_WIDTH                7	/* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R273 (0x111) - Write Sequencer Ctrl (2)
+ */
+#define WM8995_WSEQ_BUSY                        0x0100	/* WSEQ_BUSY */
+#define WM8995_WSEQ_BUSY_MASK                   0x0100	/* WSEQ_BUSY */
+#define WM8995_WSEQ_BUSY_SHIFT                       8	/* WSEQ_BUSY */
+#define WM8995_WSEQ_BUSY_WIDTH                       1	/* WSEQ_BUSY */
+#define WM8995_WSEQ_CURRENT_INDEX_MASK          0x007F	/* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8995_WSEQ_CURRENT_INDEX_SHIFT              0	/* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8995_WSEQ_CURRENT_INDEX_WIDTH              7	/* WSEQ_CURRENT_INDEX - [6:0] */
+
+/*
+ * R512 (0x200) - AIF1 Clocking (1)
+ */
+#define WM8995_AIF1CLK_SRC_MASK                 0x0018	/* AIF1CLK_SRC - [4:3] */
+#define WM8995_AIF1CLK_SRC_SHIFT                     3	/* AIF1CLK_SRC - [4:3] */
+#define WM8995_AIF1CLK_SRC_WIDTH                     2	/* AIF1CLK_SRC - [4:3] */
+#define WM8995_AIF1CLK_INV                      0x0004	/* AIF1CLK_INV */
+#define WM8995_AIF1CLK_INV_MASK                 0x0004	/* AIF1CLK_INV */
+#define WM8995_AIF1CLK_INV_SHIFT                     2	/* AIF1CLK_INV */
+#define WM8995_AIF1CLK_INV_WIDTH                     1	/* AIF1CLK_INV */
+#define WM8995_AIF1CLK_DIV                      0x0002	/* AIF1CLK_DIV */
+#define WM8995_AIF1CLK_DIV_MASK                 0x0002	/* AIF1CLK_DIV */
+#define WM8995_AIF1CLK_DIV_SHIFT                     1	/* AIF1CLK_DIV */
+#define WM8995_AIF1CLK_DIV_WIDTH                     1	/* AIF1CLK_DIV */
+#define WM8995_AIF1CLK_ENA                      0x0001	/* AIF1CLK_ENA */
+#define WM8995_AIF1CLK_ENA_MASK                 0x0001	/* AIF1CLK_ENA */
+#define WM8995_AIF1CLK_ENA_SHIFT                     0	/* AIF1CLK_ENA */
+#define WM8995_AIF1CLK_ENA_WIDTH                     1	/* AIF1CLK_ENA */
+
+/*
+ * R513 (0x201) - AIF1 Clocking (2)
+ */
+#define WM8995_AIF1DAC_DIV_MASK                 0x0038	/* AIF1DAC_DIV - [5:3] */
+#define WM8995_AIF1DAC_DIV_SHIFT                     3	/* AIF1DAC_DIV - [5:3] */
+#define WM8995_AIF1DAC_DIV_WIDTH                     3	/* AIF1DAC_DIV - [5:3] */
+#define WM8995_AIF1ADC_DIV_MASK                 0x0007	/* AIF1ADC_DIV - [2:0] */
+#define WM8995_AIF1ADC_DIV_SHIFT                     0	/* AIF1ADC_DIV - [2:0] */
+#define WM8995_AIF1ADC_DIV_WIDTH                     3	/* AIF1ADC_DIV - [2:0] */
+
+/*
+ * R516 (0x204) - AIF2 Clocking (1)
+ */
+#define WM8995_AIF2CLK_SRC_MASK                 0x0018	/* AIF2CLK_SRC - [4:3] */
+#define WM8995_AIF2CLK_SRC_SHIFT                     3	/* AIF2CLK_SRC - [4:3] */
+#define WM8995_AIF2CLK_SRC_WIDTH                     2	/* AIF2CLK_SRC - [4:3] */
+#define WM8995_AIF2CLK_INV                      0x0004	/* AIF2CLK_INV */
+#define WM8995_AIF2CLK_INV_MASK                 0x0004	/* AIF2CLK_INV */
+#define WM8995_AIF2CLK_INV_SHIFT                     2	/* AIF2CLK_INV */
+#define WM8995_AIF2CLK_INV_WIDTH                     1	/* AIF2CLK_INV */
+#define WM8995_AIF2CLK_DIV                      0x0002	/* AIF2CLK_DIV */
+#define WM8995_AIF2CLK_DIV_MASK                 0x0002	/* AIF2CLK_DIV */
+#define WM8995_AIF2CLK_DIV_SHIFT                     1	/* AIF2CLK_DIV */
+#define WM8995_AIF2CLK_DIV_WIDTH                     1	/* AIF2CLK_DIV */
+#define WM8995_AIF2CLK_ENA                      0x0001	/* AIF2CLK_ENA */
+#define WM8995_AIF2CLK_ENA_MASK                 0x0001	/* AIF2CLK_ENA */
+#define WM8995_AIF2CLK_ENA_SHIFT                     0	/* AIF2CLK_ENA */
+#define WM8995_AIF2CLK_ENA_WIDTH                     1	/* AIF2CLK_ENA */
+
+/*
+ * R517 (0x205) - AIF2 Clocking (2)
+ */
+#define WM8995_AIF2DAC_DIV_MASK                 0x0038	/* AIF2DAC_DIV - [5:3] */
+#define WM8995_AIF2DAC_DIV_SHIFT                     3	/* AIF2DAC_DIV - [5:3] */
+#define WM8995_AIF2DAC_DIV_WIDTH                     3	/* AIF2DAC_DIV - [5:3] */
+#define WM8995_AIF2ADC_DIV_MASK                 0x0007	/* AIF2ADC_DIV - [2:0] */
+#define WM8995_AIF2ADC_DIV_SHIFT                     0	/* AIF2ADC_DIV - [2:0] */
+#define WM8995_AIF2ADC_DIV_WIDTH                     3	/* AIF2ADC_DIV - [2:0] */
+
+/*
+ * R520 (0x208) - Clocking (1)
+ */
+#define WM8995_LFCLK_ENA                        0x0020	/* LFCLK_ENA */
+#define WM8995_LFCLK_ENA_MASK                   0x0020	/* LFCLK_ENA */
+#define WM8995_LFCLK_ENA_SHIFT                       5	/* LFCLK_ENA */
+#define WM8995_LFCLK_ENA_WIDTH                       1	/* LFCLK_ENA */
+#define WM8995_TOCLK_ENA                        0x0010	/* TOCLK_ENA */
+#define WM8995_TOCLK_ENA_MASK                   0x0010	/* TOCLK_ENA */
+#define WM8995_TOCLK_ENA_SHIFT                       4	/* TOCLK_ENA */
+#define WM8995_TOCLK_ENA_WIDTH                       1	/* TOCLK_ENA */
+#define WM8995_AIF1DSPCLK_ENA                   0x0008	/* AIF1DSPCLK_ENA */
+#define WM8995_AIF1DSPCLK_ENA_MASK              0x0008	/* AIF1DSPCLK_ENA */
+#define WM8995_AIF1DSPCLK_ENA_SHIFT                  3	/* AIF1DSPCLK_ENA */
+#define WM8995_AIF1DSPCLK_ENA_WIDTH                  1	/* AIF1DSPCLK_ENA */
+#define WM8995_AIF2DSPCLK_ENA                   0x0004	/* AIF2DSPCLK_ENA */
+#define WM8995_AIF2DSPCLK_ENA_MASK              0x0004	/* AIF2DSPCLK_ENA */
+#define WM8995_AIF2DSPCLK_ENA_SHIFT                  2	/* AIF2DSPCLK_ENA */
+#define WM8995_AIF2DSPCLK_ENA_WIDTH                  1	/* AIF2DSPCLK_ENA */
+#define WM8995_SYSDSPCLK_ENA                    0x0002	/* SYSDSPCLK_ENA */
+#define WM8995_SYSDSPCLK_ENA_MASK               0x0002	/* SYSDSPCLK_ENA */
+#define WM8995_SYSDSPCLK_ENA_SHIFT                   1	/* SYSDSPCLK_ENA */
+#define WM8995_SYSDSPCLK_ENA_WIDTH                   1	/* SYSDSPCLK_ENA */
+#define WM8995_SYSCLK_SRC                       0x0001	/* SYSCLK_SRC */
+#define WM8995_SYSCLK_SRC_MASK                  0x0001	/* SYSCLK_SRC */
+#define WM8995_SYSCLK_SRC_SHIFT                      0	/* SYSCLK_SRC */
+#define WM8995_SYSCLK_SRC_WIDTH                      1	/* SYSCLK_SRC */
+
+/*
+ * R521 (0x209) - Clocking (2)
+ */
+#define WM8995_TOCLK_DIV_MASK                   0x0700	/* TOCLK_DIV - [10:8] */
+#define WM8995_TOCLK_DIV_SHIFT                       8	/* TOCLK_DIV - [10:8] */
+#define WM8995_TOCLK_DIV_WIDTH                       3	/* TOCLK_DIV - [10:8] */
+#define WM8995_DBCLK_DIV_MASK                   0x00F0	/* DBCLK_DIV - [7:4] */
+#define WM8995_DBCLK_DIV_SHIFT                       4	/* DBCLK_DIV - [7:4] */
+#define WM8995_DBCLK_DIV_WIDTH                       4	/* DBCLK_DIV - [7:4] */
+#define WM8995_OPCLK_DIV_MASK                   0x0007	/* OPCLK_DIV - [2:0] */
+#define WM8995_OPCLK_DIV_SHIFT                       0	/* OPCLK_DIV - [2:0] */
+#define WM8995_OPCLK_DIV_WIDTH                       3	/* OPCLK_DIV - [2:0] */
+
+/*
+ * R528 (0x210) - AIF1 Rate
+ */
+#define WM8995_AIF1_SR_MASK                     0x00F0	/* AIF1_SR - [7:4] */
+#define WM8995_AIF1_SR_SHIFT                         4	/* AIF1_SR - [7:4] */
+#define WM8995_AIF1_SR_WIDTH                         4	/* AIF1_SR - [7:4] */
+#define WM8995_AIF1CLK_RATE_MASK                0x000F	/* AIF1CLK_RATE - [3:0] */
+#define WM8995_AIF1CLK_RATE_SHIFT                    0	/* AIF1CLK_RATE - [3:0] */
+#define WM8995_AIF1CLK_RATE_WIDTH                    4	/* AIF1CLK_RATE - [3:0] */
+
+/*
+ * R529 (0x211) - AIF2 Rate
+ */
+#define WM8995_AIF2_SR_MASK                     0x00F0	/* AIF2_SR - [7:4] */
+#define WM8995_AIF2_SR_SHIFT                         4	/* AIF2_SR - [7:4] */
+#define WM8995_AIF2_SR_WIDTH                         4	/* AIF2_SR - [7:4] */
+#define WM8995_AIF2CLK_RATE_MASK                0x000F	/* AIF2CLK_RATE - [3:0] */
+#define WM8995_AIF2CLK_RATE_SHIFT                    0	/* AIF2CLK_RATE - [3:0] */
+#define WM8995_AIF2CLK_RATE_WIDTH                    4	/* AIF2CLK_RATE - [3:0] */
+
+/*
+ * R530 (0x212) - Rate Status
+ */
+#define WM8995_SR_ERROR_MASK                    0x000F	/* SR_ERROR - [3:0] */
+#define WM8995_SR_ERROR_SHIFT                        0	/* SR_ERROR - [3:0] */
+#define WM8995_SR_ERROR_WIDTH                        4	/* SR_ERROR - [3:0] */
+
+/*
+ * R544 (0x220) - FLL1 Control (1)
+ */
+#define WM8995_FLL1_OSC_ENA                     0x0002	/* FLL1_OSC_ENA */
+#define WM8995_FLL1_OSC_ENA_MASK                0x0002	/* FLL1_OSC_ENA */
+#define WM8995_FLL1_OSC_ENA_SHIFT                    1	/* FLL1_OSC_ENA */
+#define WM8995_FLL1_OSC_ENA_WIDTH                    1	/* FLL1_OSC_ENA */
+#define WM8995_FLL1_ENA                         0x0001	/* FLL1_ENA */
+#define WM8995_FLL1_ENA_MASK                    0x0001	/* FLL1_ENA */
+#define WM8995_FLL1_ENA_SHIFT                        0	/* FLL1_ENA */
+#define WM8995_FLL1_ENA_WIDTH                        1	/* FLL1_ENA */
+
+/*
+ * R545 (0x221) - FLL1 Control (2)
+ */
+#define WM8995_FLL1_OUTDIV_MASK                 0x3F00	/* FLL1_OUTDIV - [13:8] */
+#define WM8995_FLL1_OUTDIV_SHIFT                     8	/* FLL1_OUTDIV - [13:8] */
+#define WM8995_FLL1_OUTDIV_WIDTH                     6	/* FLL1_OUTDIV - [13:8] */
+#define WM8995_FLL1_CTRL_RATE_MASK              0x0070	/* FLL1_CTRL_RATE - [6:4] */
+#define WM8995_FLL1_CTRL_RATE_SHIFT                  4	/* FLL1_CTRL_RATE - [6:4] */
+#define WM8995_FLL1_CTRL_RATE_WIDTH                  3	/* FLL1_CTRL_RATE - [6:4] */
+#define WM8995_FLL1_FRATIO_MASK                 0x0007	/* FLL1_FRATIO - [2:0] */
+#define WM8995_FLL1_FRATIO_SHIFT                     0	/* FLL1_FRATIO - [2:0] */
+#define WM8995_FLL1_FRATIO_WIDTH                     3	/* FLL1_FRATIO - [2:0] */
+
+/*
+ * R546 (0x222) - FLL1 Control (3)
+ */
+#define WM8995_FLL1_K_MASK                      0xFFFF	/* FLL1_K - [15:0] */
+#define WM8995_FLL1_K_SHIFT                          0	/* FLL1_K - [15:0] */
+#define WM8995_FLL1_K_WIDTH                         16	/* FLL1_K - [15:0] */
+
+/*
+ * R547 (0x223) - FLL1 Control (4)
+ */
+#define WM8995_FLL1_N_MASK                      0x7FE0	/* FLL1_N - [14:5] */
+#define WM8995_FLL1_N_SHIFT                          5	/* FLL1_N - [14:5] */
+#define WM8995_FLL1_N_WIDTH                         10	/* FLL1_N - [14:5] */
+#define WM8995_FLL1_LOOP_GAIN_MASK              0x000F	/* FLL1_LOOP_GAIN - [3:0] */
+#define WM8995_FLL1_LOOP_GAIN_SHIFT                  0	/* FLL1_LOOP_GAIN - [3:0] */
+#define WM8995_FLL1_LOOP_GAIN_WIDTH                  4	/* FLL1_LOOP_GAIN - [3:0] */
+
+/*
+ * R548 (0x224) - FLL1 Control (5)
+ */
+#define WM8995_FLL1_FRC_NCO_VAL_MASK            0x1F80	/* FLL1_FRC_NCO_VAL - [12:7] */
+#define WM8995_FLL1_FRC_NCO_VAL_SHIFT                7	/* FLL1_FRC_NCO_VAL - [12:7] */
+#define WM8995_FLL1_FRC_NCO_VAL_WIDTH                6	/* FLL1_FRC_NCO_VAL - [12:7] */
+#define WM8995_FLL1_FRC_NCO                     0x0040	/* FLL1_FRC_NCO */
+#define WM8995_FLL1_FRC_NCO_MASK                0x0040	/* FLL1_FRC_NCO */
+#define WM8995_FLL1_FRC_NCO_SHIFT                    6	/* FLL1_FRC_NCO */
+#define WM8995_FLL1_FRC_NCO_WIDTH                    1	/* FLL1_FRC_NCO */
+#define WM8995_FLL1_REFCLK_DIV_MASK             0x0018	/* FLL1_REFCLK_DIV - [4:3] */
+#define WM8995_FLL1_REFCLK_DIV_SHIFT                 3	/* FLL1_REFCLK_DIV - [4:3] */
+#define WM8995_FLL1_REFCLK_DIV_WIDTH                 2	/* FLL1_REFCLK_DIV - [4:3] */
+#define WM8995_FLL1_REFCLK_SRC_MASK             0x0003	/* FLL1_REFCLK_SRC - [1:0] */
+#define WM8995_FLL1_REFCLK_SRC_SHIFT                 0	/* FLL1_REFCLK_SRC - [1:0] */
+#define WM8995_FLL1_REFCLK_SRC_WIDTH                 2	/* FLL1_REFCLK_SRC - [1:0] */
+
+/*
+ * R576 (0x240) - FLL2 Control (1)
+ */
+#define WM8995_FLL2_OSC_ENA                     0x0002	/* FLL2_OSC_ENA */
+#define WM8995_FLL2_OSC_ENA_MASK                0x0002	/* FLL2_OSC_ENA */
+#define WM8995_FLL2_OSC_ENA_SHIFT                    1	/* FLL2_OSC_ENA */
+#define WM8995_FLL2_OSC_ENA_WIDTH                    1	/* FLL2_OSC_ENA */
+#define WM8995_FLL2_ENA                         0x0001	/* FLL2_ENA */
+#define WM8995_FLL2_ENA_MASK                    0x0001	/* FLL2_ENA */
+#define WM8995_FLL2_ENA_SHIFT                        0	/* FLL2_ENA */
+#define WM8995_FLL2_ENA_WIDTH                        1	/* FLL2_ENA */
+
+/*
+ * R577 (0x241) - FLL2 Control (2)
+ */
+#define WM8995_FLL2_OUTDIV_MASK                 0x3F00	/* FLL2_OUTDIV - [13:8] */
+#define WM8995_FLL2_OUTDIV_SHIFT                     8	/* FLL2_OUTDIV - [13:8] */
+#define WM8995_FLL2_OUTDIV_WIDTH                     6	/* FLL2_OUTDIV - [13:8] */
+#define WM8995_FLL2_CTRL_RATE_MASK              0x0070	/* FLL2_CTRL_RATE - [6:4] */
+#define WM8995_FLL2_CTRL_RATE_SHIFT                  4	/* FLL2_CTRL_RATE - [6:4] */
+#define WM8995_FLL2_CTRL_RATE_WIDTH                  3	/* FLL2_CTRL_RATE - [6:4] */
+#define WM8995_FLL2_FRATIO_MASK                 0x0007	/* FLL2_FRATIO - [2:0] */
+#define WM8995_FLL2_FRATIO_SHIFT                     0	/* FLL2_FRATIO - [2:0] */
+#define WM8995_FLL2_FRATIO_WIDTH                     3	/* FLL2_FRATIO - [2:0] */
+
+/*
+ * R578 (0x242) - FLL2 Control (3)
+ */
+#define WM8995_FLL2_K_MASK                      0xFFFF	/* FLL2_K - [15:0] */
+#define WM8995_FLL2_K_SHIFT                          0	/* FLL2_K - [15:0] */
+#define WM8995_FLL2_K_WIDTH                         16	/* FLL2_K - [15:0] */
+
+/*
+ * R579 (0x243) - FLL2 Control (4)
+ */
+#define WM8995_FLL2_N_MASK                      0x7FE0	/* FLL2_N - [14:5] */
+#define WM8995_FLL2_N_SHIFT                          5	/* FLL2_N - [14:5] */
+#define WM8995_FLL2_N_WIDTH                         10	/* FLL2_N - [14:5] */
+#define WM8995_FLL2_LOOP_GAIN_MASK              0x000F	/* FLL2_LOOP_GAIN - [3:0] */
+#define WM8995_FLL2_LOOP_GAIN_SHIFT                  0	/* FLL2_LOOP_GAIN - [3:0] */
+#define WM8995_FLL2_LOOP_GAIN_WIDTH                  4	/* FLL2_LOOP_GAIN - [3:0] */
+
+/*
+ * R580 (0x244) - FLL2 Control (5)
+ */
+#define WM8995_FLL2_FRC_NCO_VAL_MASK            0x1F80	/* FLL2_FRC_NCO_VAL - [12:7] */
+#define WM8995_FLL2_FRC_NCO_VAL_SHIFT                7	/* FLL2_FRC_NCO_VAL - [12:7] */
+#define WM8995_FLL2_FRC_NCO_VAL_WIDTH                6	/* FLL2_FRC_NCO_VAL - [12:7] */
+#define WM8995_FLL2_FRC_NCO                     0x0040	/* FLL2_FRC_NCO */
+#define WM8995_FLL2_FRC_NCO_MASK                0x0040	/* FLL2_FRC_NCO */
+#define WM8995_FLL2_FRC_NCO_SHIFT                    6	/* FLL2_FRC_NCO */
+#define WM8995_FLL2_FRC_NCO_WIDTH                    1	/* FLL2_FRC_NCO */
+#define WM8995_FLL2_REFCLK_DIV_MASK             0x0018	/* FLL2_REFCLK_DIV - [4:3] */
+#define WM8995_FLL2_REFCLK_DIV_SHIFT                 3	/* FLL2_REFCLK_DIV - [4:3] */
+#define WM8995_FLL2_REFCLK_DIV_WIDTH                 2	/* FLL2_REFCLK_DIV - [4:3] */
+#define WM8995_FLL2_REFCLK_SRC_MASK             0x0003	/* FLL2_REFCLK_SRC - [1:0] */
+#define WM8995_FLL2_REFCLK_SRC_SHIFT                 0	/* FLL2_REFCLK_SRC - [1:0] */
+#define WM8995_FLL2_REFCLK_SRC_WIDTH                 2	/* FLL2_REFCLK_SRC - [1:0] */
+
+/*
+ * R768 (0x300) - AIF1 Control (1)
+ */
+#define WM8995_AIF1ADCL_SRC                     0x8000	/* AIF1ADCL_SRC */
+#define WM8995_AIF1ADCL_SRC_MASK                0x8000	/* AIF1ADCL_SRC */
+#define WM8995_AIF1ADCL_SRC_SHIFT                   15	/* AIF1ADCL_SRC */
+#define WM8995_AIF1ADCL_SRC_WIDTH                    1	/* AIF1ADCL_SRC */
+#define WM8995_AIF1ADCR_SRC                     0x4000	/* AIF1ADCR_SRC */
+#define WM8995_AIF1ADCR_SRC_MASK                0x4000	/* AIF1ADCR_SRC */
+#define WM8995_AIF1ADCR_SRC_SHIFT                   14	/* AIF1ADCR_SRC */
+#define WM8995_AIF1ADCR_SRC_WIDTH                    1	/* AIF1ADCR_SRC */
+#define WM8995_AIF1ADC_TDM                      0x2000	/* AIF1ADC_TDM */
+#define WM8995_AIF1ADC_TDM_MASK                 0x2000	/* AIF1ADC_TDM */
+#define WM8995_AIF1ADC_TDM_SHIFT                    13	/* AIF1ADC_TDM */
+#define WM8995_AIF1ADC_TDM_WIDTH                     1	/* AIF1ADC_TDM */
+#define WM8995_AIF1_BCLK_INV                    0x0100	/* AIF1_BCLK_INV */
+#define WM8995_AIF1_BCLK_INV_MASK               0x0100	/* AIF1_BCLK_INV */
+#define WM8995_AIF1_BCLK_INV_SHIFT                   8	/* AIF1_BCLK_INV */
+#define WM8995_AIF1_BCLK_INV_WIDTH                   1	/* AIF1_BCLK_INV */
+#define WM8995_AIF1_LRCLK_INV                   0x0080	/* AIF1_LRCLK_INV */
+#define WM8995_AIF1_LRCLK_INV_MASK              0x0080	/* AIF1_LRCLK_INV */
+#define WM8995_AIF1_LRCLK_INV_SHIFT                  7	/* AIF1_LRCLK_INV */
+#define WM8995_AIF1_LRCLK_INV_WIDTH                  1	/* AIF1_LRCLK_INV */
+#define WM8995_AIF1_WL_MASK                     0x0060	/* AIF1_WL - [6:5] */
+#define WM8995_AIF1_WL_SHIFT                         5	/* AIF1_WL - [6:5] */
+#define WM8995_AIF1_WL_WIDTH                         2	/* AIF1_WL - [6:5] */
+#define WM8995_AIF1_FMT_MASK                    0x0018	/* AIF1_FMT - [4:3] */
+#define WM8995_AIF1_FMT_SHIFT                        3	/* AIF1_FMT - [4:3] */
+#define WM8995_AIF1_FMT_WIDTH                        2	/* AIF1_FMT - [4:3] */
+
+/*
+ * R769 (0x301) - AIF1 Control (2)
+ */
+#define WM8995_AIF1DACL_SRC                     0x8000	/* AIF1DACL_SRC */
+#define WM8995_AIF1DACL_SRC_MASK                0x8000	/* AIF1DACL_SRC */
+#define WM8995_AIF1DACL_SRC_SHIFT                   15	/* AIF1DACL_SRC */
+#define WM8995_AIF1DACL_SRC_WIDTH                    1	/* AIF1DACL_SRC */
+#define WM8995_AIF1DACR_SRC                     0x4000	/* AIF1DACR_SRC */
+#define WM8995_AIF1DACR_SRC_MASK                0x4000	/* AIF1DACR_SRC */
+#define WM8995_AIF1DACR_SRC_SHIFT                   14	/* AIF1DACR_SRC */
+#define WM8995_AIF1DACR_SRC_WIDTH                    1	/* AIF1DACR_SRC */
+#define WM8995_AIF1DAC_BOOST_MASK               0x0C00	/* AIF1DAC_BOOST - [11:10] */
+#define WM8995_AIF1DAC_BOOST_SHIFT                  10	/* AIF1DAC_BOOST - [11:10] */
+#define WM8995_AIF1DAC_BOOST_WIDTH                   2	/* AIF1DAC_BOOST - [11:10] */
+#define WM8995_AIF1DAC_COMP                     0x0010	/* AIF1DAC_COMP */
+#define WM8995_AIF1DAC_COMP_MASK                0x0010	/* AIF1DAC_COMP */
+#define WM8995_AIF1DAC_COMP_SHIFT                    4	/* AIF1DAC_COMP */
+#define WM8995_AIF1DAC_COMP_WIDTH                    1	/* AIF1DAC_COMP */
+#define WM8995_AIF1DAC_COMPMODE                 0x0008	/* AIF1DAC_COMPMODE */
+#define WM8995_AIF1DAC_COMPMODE_MASK            0x0008	/* AIF1DAC_COMPMODE */
+#define WM8995_AIF1DAC_COMPMODE_SHIFT                3	/* AIF1DAC_COMPMODE */
+#define WM8995_AIF1DAC_COMPMODE_WIDTH                1	/* AIF1DAC_COMPMODE */
+#define WM8995_AIF1ADC_COMP                     0x0004	/* AIF1ADC_COMP */
+#define WM8995_AIF1ADC_COMP_MASK                0x0004	/* AIF1ADC_COMP */
+#define WM8995_AIF1ADC_COMP_SHIFT                    2	/* AIF1ADC_COMP */
+#define WM8995_AIF1ADC_COMP_WIDTH                    1	/* AIF1ADC_COMP */
+#define WM8995_AIF1ADC_COMPMODE                 0x0002	/* AIF1ADC_COMPMODE */
+#define WM8995_AIF1ADC_COMPMODE_MASK            0x0002	/* AIF1ADC_COMPMODE */
+#define WM8995_AIF1ADC_COMPMODE_SHIFT                1	/* AIF1ADC_COMPMODE */
+#define WM8995_AIF1ADC_COMPMODE_WIDTH                1	/* AIF1ADC_COMPMODE */
+#define WM8995_AIF1_LOOPBACK                    0x0001	/* AIF1_LOOPBACK */
+#define WM8995_AIF1_LOOPBACK_MASK               0x0001	/* AIF1_LOOPBACK */
+#define WM8995_AIF1_LOOPBACK_SHIFT                   0	/* AIF1_LOOPBACK */
+#define WM8995_AIF1_LOOPBACK_WIDTH                   1	/* AIF1_LOOPBACK */
+
+/*
+ * R770 (0x302) - AIF1 Master/Slave
+ */
+#define WM8995_AIF1_TRI                         0x8000	/* AIF1_TRI */
+#define WM8995_AIF1_TRI_MASK                    0x8000	/* AIF1_TRI */
+#define WM8995_AIF1_TRI_SHIFT                       15	/* AIF1_TRI */
+#define WM8995_AIF1_TRI_WIDTH                        1	/* AIF1_TRI */
+#define WM8995_AIF1_MSTR                        0x4000	/* AIF1_MSTR */
+#define WM8995_AIF1_MSTR_MASK                   0x4000	/* AIF1_MSTR */
+#define WM8995_AIF1_MSTR_SHIFT                      14	/* AIF1_MSTR */
+#define WM8995_AIF1_MSTR_WIDTH                       1	/* AIF1_MSTR */
+#define WM8995_AIF1_CLK_FRC                     0x2000	/* AIF1_CLK_FRC */
+#define WM8995_AIF1_CLK_FRC_MASK                0x2000	/* AIF1_CLK_FRC */
+#define WM8995_AIF1_CLK_FRC_SHIFT                   13	/* AIF1_CLK_FRC */
+#define WM8995_AIF1_CLK_FRC_WIDTH                    1	/* AIF1_CLK_FRC */
+#define WM8995_AIF1_LRCLK_FRC                   0x1000	/* AIF1_LRCLK_FRC */
+#define WM8995_AIF1_LRCLK_FRC_MASK              0x1000	/* AIF1_LRCLK_FRC */
+#define WM8995_AIF1_LRCLK_FRC_SHIFT                 12	/* AIF1_LRCLK_FRC */
+#define WM8995_AIF1_LRCLK_FRC_WIDTH                  1	/* AIF1_LRCLK_FRC */
+
+/*
+ * R771 (0x303) - AIF1 BCLK
+ */
+#define WM8995_AIF1_BCLK_DIV_MASK               0x00F0	/* AIF1_BCLK_DIV - [7:4] */
+#define WM8995_AIF1_BCLK_DIV_SHIFT                   4	/* AIF1_BCLK_DIV - [7:4] */
+#define WM8995_AIF1_BCLK_DIV_WIDTH                   4	/* AIF1_BCLK_DIV - [7:4] */
+
+/*
+ * R772 (0x304) - AIF1ADC LRCLK
+ */
+#define WM8995_AIF1ADC_LRCLK_DIR                0x0800	/* AIF1ADC_LRCLK_DIR */
+#define WM8995_AIF1ADC_LRCLK_DIR_MASK           0x0800	/* AIF1ADC_LRCLK_DIR */
+#define WM8995_AIF1ADC_LRCLK_DIR_SHIFT              11	/* AIF1ADC_LRCLK_DIR */
+#define WM8995_AIF1ADC_LRCLK_DIR_WIDTH               1	/* AIF1ADC_LRCLK_DIR */
+#define WM8995_AIF1ADC_RATE_MASK                0x07FF	/* AIF1ADC_RATE - [10:0] */
+#define WM8995_AIF1ADC_RATE_SHIFT                    0	/* AIF1ADC_RATE - [10:0] */
+#define WM8995_AIF1ADC_RATE_WIDTH                   11	/* AIF1ADC_RATE - [10:0] */
+
+/*
+ * R773 (0x305) - AIF1DAC LRCLK
+ */
+#define WM8995_AIF1DAC_LRCLK_DIR                0x0800	/* AIF1DAC_LRCLK_DIR */
+#define WM8995_AIF1DAC_LRCLK_DIR_MASK           0x0800	/* AIF1DAC_LRCLK_DIR */
+#define WM8995_AIF1DAC_LRCLK_DIR_SHIFT              11	/* AIF1DAC_LRCLK_DIR */
+#define WM8995_AIF1DAC_LRCLK_DIR_WIDTH               1	/* AIF1DAC_LRCLK_DIR */
+#define WM8995_AIF1DAC_RATE_MASK                0x07FF	/* AIF1DAC_RATE - [10:0] */
+#define WM8995_AIF1DAC_RATE_SHIFT                    0	/* AIF1DAC_RATE - [10:0] */
+#define WM8995_AIF1DAC_RATE_WIDTH                   11	/* AIF1DAC_RATE - [10:0] */
+
+/*
+ * R774 (0x306) - AIF1DAC Data
+ */
+#define WM8995_AIF1DACL_DAT_INV                 0x0002	/* AIF1DACL_DAT_INV */
+#define WM8995_AIF1DACL_DAT_INV_MASK            0x0002	/* AIF1DACL_DAT_INV */
+#define WM8995_AIF1DACL_DAT_INV_SHIFT                1	/* AIF1DACL_DAT_INV */
+#define WM8995_AIF1DACL_DAT_INV_WIDTH                1	/* AIF1DACL_DAT_INV */
+#define WM8995_AIF1DACR_DAT_INV                 0x0001	/* AIF1DACR_DAT_INV */
+#define WM8995_AIF1DACR_DAT_INV_MASK            0x0001	/* AIF1DACR_DAT_INV */
+#define WM8995_AIF1DACR_DAT_INV_SHIFT                0	/* AIF1DACR_DAT_INV */
+#define WM8995_AIF1DACR_DAT_INV_WIDTH                1	/* AIF1DACR_DAT_INV */
+
+/*
+ * R775 (0x307) - AIF1ADC Data
+ */
+#define WM8995_AIF1ADCL_DAT_INV                 0x0002	/* AIF1ADCL_DAT_INV */
+#define WM8995_AIF1ADCL_DAT_INV_MASK            0x0002	/* AIF1ADCL_DAT_INV */
+#define WM8995_AIF1ADCL_DAT_INV_SHIFT                1	/* AIF1ADCL_DAT_INV */
+#define WM8995_AIF1ADCL_DAT_INV_WIDTH                1	/* AIF1ADCL_DAT_INV */
+#define WM8995_AIF1ADCR_DAT_INV                 0x0001	/* AIF1ADCR_DAT_INV */
+#define WM8995_AIF1ADCR_DAT_INV_MASK            0x0001	/* AIF1ADCR_DAT_INV */
+#define WM8995_AIF1ADCR_DAT_INV_SHIFT                0	/* AIF1ADCR_DAT_INV */
+#define WM8995_AIF1ADCR_DAT_INV_WIDTH                1	/* AIF1ADCR_DAT_INV */
+
+/*
+ * R784 (0x310) - AIF2 Control (1)
+ */
+#define WM8995_AIF2ADCL_SRC                     0x8000	/* AIF2ADCL_SRC */
+#define WM8995_AIF2ADCL_SRC_MASK                0x8000	/* AIF2ADCL_SRC */
+#define WM8995_AIF2ADCL_SRC_SHIFT                   15	/* AIF2ADCL_SRC */
+#define WM8995_AIF2ADCL_SRC_WIDTH                    1	/* AIF2ADCL_SRC */
+#define WM8995_AIF2ADCR_SRC                     0x4000	/* AIF2ADCR_SRC */
+#define WM8995_AIF2ADCR_SRC_MASK                0x4000	/* AIF2ADCR_SRC */
+#define WM8995_AIF2ADCR_SRC_SHIFT                   14	/* AIF2ADCR_SRC */
+#define WM8995_AIF2ADCR_SRC_WIDTH                    1	/* AIF2ADCR_SRC */
+#define WM8995_AIF2ADC_TDM                      0x2000	/* AIF2ADC_TDM */
+#define WM8995_AIF2ADC_TDM_MASK                 0x2000	/* AIF2ADC_TDM */
+#define WM8995_AIF2ADC_TDM_SHIFT                    13	/* AIF2ADC_TDM */
+#define WM8995_AIF2ADC_TDM_WIDTH                     1	/* AIF2ADC_TDM */
+#define WM8995_AIF2ADC_TDM_CHAN                 0x1000	/* AIF2ADC_TDM_CHAN */
+#define WM8995_AIF2ADC_TDM_CHAN_MASK            0x1000	/* AIF2ADC_TDM_CHAN */
+#define WM8995_AIF2ADC_TDM_CHAN_SHIFT               12	/* AIF2ADC_TDM_CHAN */
+#define WM8995_AIF2ADC_TDM_CHAN_WIDTH                1	/* AIF2ADC_TDM_CHAN */
+#define WM8995_AIF2_BCLK_INV                    0x0100	/* AIF2_BCLK_INV */
+#define WM8995_AIF2_BCLK_INV_MASK               0x0100	/* AIF2_BCLK_INV */
+#define WM8995_AIF2_BCLK_INV_SHIFT                   8	/* AIF2_BCLK_INV */
+#define WM8995_AIF2_BCLK_INV_WIDTH                   1	/* AIF2_BCLK_INV */
+#define WM8995_AIF2_LRCLK_INV                   0x0080	/* AIF2_LRCLK_INV */
+#define WM8995_AIF2_LRCLK_INV_MASK              0x0080	/* AIF2_LRCLK_INV */
+#define WM8995_AIF2_LRCLK_INV_SHIFT                  7	/* AIF2_LRCLK_INV */
+#define WM8995_AIF2_LRCLK_INV_WIDTH                  1	/* AIF2_LRCLK_INV */
+#define WM8995_AIF2_WL_MASK                     0x0060	/* AIF2_WL - [6:5] */
+#define WM8995_AIF2_WL_SHIFT                         5	/* AIF2_WL - [6:5] */
+#define WM8995_AIF2_WL_WIDTH                         2	/* AIF2_WL - [6:5] */
+#define WM8995_AIF2_FMT_MASK                    0x0018	/* AIF2_FMT - [4:3] */
+#define WM8995_AIF2_FMT_SHIFT                        3	/* AIF2_FMT - [4:3] */
+#define WM8995_AIF2_FMT_WIDTH                        2	/* AIF2_FMT - [4:3] */
+
+/*
+ * R785 (0x311) - AIF2 Control (2)
+ */
+#define WM8995_AIF2DACL_SRC                     0x8000	/* AIF2DACL_SRC */
+#define WM8995_AIF2DACL_SRC_MASK                0x8000	/* AIF2DACL_SRC */
+#define WM8995_AIF2DACL_SRC_SHIFT                   15	/* AIF2DACL_SRC */
+#define WM8995_AIF2DACL_SRC_WIDTH                    1	/* AIF2DACL_SRC */
+#define WM8995_AIF2DACR_SRC                     0x4000	/* AIF2DACR_SRC */
+#define WM8995_AIF2DACR_SRC_MASK                0x4000	/* AIF2DACR_SRC */
+#define WM8995_AIF2DACR_SRC_SHIFT                   14	/* AIF2DACR_SRC */
+#define WM8995_AIF2DACR_SRC_WIDTH                    1	/* AIF2DACR_SRC */
+#define WM8995_AIF2DAC_TDM                      0x2000	/* AIF2DAC_TDM */
+#define WM8995_AIF2DAC_TDM_MASK                 0x2000	/* AIF2DAC_TDM */
+#define WM8995_AIF2DAC_TDM_SHIFT                    13	/* AIF2DAC_TDM */
+#define WM8995_AIF2DAC_TDM_WIDTH                     1	/* AIF2DAC_TDM */
+#define WM8995_AIF2DAC_TDM_CHAN                 0x1000	/* AIF2DAC_TDM_CHAN */
+#define WM8995_AIF2DAC_TDM_CHAN_MASK            0x1000	/* AIF2DAC_TDM_CHAN */
+#define WM8995_AIF2DAC_TDM_CHAN_SHIFT               12	/* AIF2DAC_TDM_CHAN */
+#define WM8995_AIF2DAC_TDM_CHAN_WIDTH                1	/* AIF2DAC_TDM_CHAN */
+#define WM8995_AIF2DAC_BOOST_MASK               0x0C00	/* AIF2DAC_BOOST - [11:10] */
+#define WM8995_AIF2DAC_BOOST_SHIFT                  10	/* AIF2DAC_BOOST - [11:10] */
+#define WM8995_AIF2DAC_BOOST_WIDTH                   2	/* AIF2DAC_BOOST - [11:10] */
+#define WM8995_AIF2DAC_COMP                     0x0010	/* AIF2DAC_COMP */
+#define WM8995_AIF2DAC_COMP_MASK                0x0010	/* AIF2DAC_COMP */
+#define WM8995_AIF2DAC_COMP_SHIFT                    4	/* AIF2DAC_COMP */
+#define WM8995_AIF2DAC_COMP_WIDTH                    1	/* AIF2DAC_COMP */
+#define WM8995_AIF2DAC_COMPMODE                 0x0008	/* AIF2DAC_COMPMODE */
+#define WM8995_AIF2DAC_COMPMODE_MASK            0x0008	/* AIF2DAC_COMPMODE */
+#define WM8995_AIF2DAC_COMPMODE_SHIFT                3	/* AIF2DAC_COMPMODE */
+#define WM8995_AIF2DAC_COMPMODE_WIDTH                1	/* AIF2DAC_COMPMODE */
+#define WM8995_AIF2ADC_COMP                     0x0004	/* AIF2ADC_COMP */
+#define WM8995_AIF2ADC_COMP_MASK                0x0004	/* AIF2ADC_COMP */
+#define WM8995_AIF2ADC_COMP_SHIFT                    2	/* AIF2ADC_COMP */
+#define WM8995_AIF2ADC_COMP_WIDTH                    1	/* AIF2ADC_COMP */
+#define WM8995_AIF2ADC_COMPMODE                 0x0002	/* AIF2ADC_COMPMODE */
+#define WM8995_AIF2ADC_COMPMODE_MASK            0x0002	/* AIF2ADC_COMPMODE */
+#define WM8995_AIF2ADC_COMPMODE_SHIFT                1	/* AIF2ADC_COMPMODE */
+#define WM8995_AIF2ADC_COMPMODE_WIDTH                1	/* AIF2ADC_COMPMODE */
+#define WM8995_AIF2_LOOPBACK                    0x0001	/* AIF2_LOOPBACK */
+#define WM8995_AIF2_LOOPBACK_MASK               0x0001	/* AIF2_LOOPBACK */
+#define WM8995_AIF2_LOOPBACK_SHIFT                   0	/* AIF2_LOOPBACK */
+#define WM8995_AIF2_LOOPBACK_WIDTH                   1	/* AIF2_LOOPBACK */
+
+/*
+ * R786 (0x312) - AIF2 Master/Slave
+ */
+#define WM8995_AIF2_TRI                         0x8000	/* AIF2_TRI */
+#define WM8995_AIF2_TRI_MASK                    0x8000	/* AIF2_TRI */
+#define WM8995_AIF2_TRI_SHIFT                       15	/* AIF2_TRI */
+#define WM8995_AIF2_TRI_WIDTH                        1	/* AIF2_TRI */
+#define WM8995_AIF2_MSTR                        0x4000	/* AIF2_MSTR */
+#define WM8995_AIF2_MSTR_MASK                   0x4000	/* AIF2_MSTR */
+#define WM8995_AIF2_MSTR_SHIFT                      14	/* AIF2_MSTR */
+#define WM8995_AIF2_MSTR_WIDTH                       1	/* AIF2_MSTR */
+#define WM8995_AIF2_CLK_FRC                     0x2000	/* AIF2_CLK_FRC */
+#define WM8995_AIF2_CLK_FRC_MASK                0x2000	/* AIF2_CLK_FRC */
+#define WM8995_AIF2_CLK_FRC_SHIFT                   13	/* AIF2_CLK_FRC */
+#define WM8995_AIF2_CLK_FRC_WIDTH                    1	/* AIF2_CLK_FRC */
+#define WM8995_AIF2_LRCLK_FRC                   0x1000	/* AIF2_LRCLK_FRC */
+#define WM8995_AIF2_LRCLK_FRC_MASK              0x1000	/* AIF2_LRCLK_FRC */
+#define WM8995_AIF2_LRCLK_FRC_SHIFT                 12	/* AIF2_LRCLK_FRC */
+#define WM8995_AIF2_LRCLK_FRC_WIDTH                  1	/* AIF2_LRCLK_FRC */
+
+/*
+ * R787 (0x313) - AIF2 BCLK
+ */
+#define WM8995_AIF2_BCLK_DIV_MASK               0x00F0	/* AIF2_BCLK_DIV - [7:4] */
+#define WM8995_AIF2_BCLK_DIV_SHIFT                   4	/* AIF2_BCLK_DIV - [7:4] */
+#define WM8995_AIF2_BCLK_DIV_WIDTH                   4	/* AIF2_BCLK_DIV - [7:4] */
+
+/*
+ * R788 (0x314) - AIF2ADC LRCLK
+ */
+#define WM8995_AIF2ADC_LRCLK_DIR                0x0800	/* AIF2ADC_LRCLK_DIR */
+#define WM8995_AIF2ADC_LRCLK_DIR_MASK           0x0800	/* AIF2ADC_LRCLK_DIR */
+#define WM8995_AIF2ADC_LRCLK_DIR_SHIFT              11	/* AIF2ADC_LRCLK_DIR */
+#define WM8995_AIF2ADC_LRCLK_DIR_WIDTH               1	/* AIF2ADC_LRCLK_DIR */
+#define WM8995_AIF2ADC_RATE_MASK                0x07FF	/* AIF2ADC_RATE - [10:0] */
+#define WM8995_AIF2ADC_RATE_SHIFT                    0	/* AIF2ADC_RATE - [10:0] */
+#define WM8995_AIF2ADC_RATE_WIDTH                   11	/* AIF2ADC_RATE - [10:0] */
+
+/*
+ * R789 (0x315) - AIF2DAC LRCLK
+ */
+#define WM8995_AIF2DAC_LRCLK_DIR                0x0800	/* AIF2DAC_LRCLK_DIR */
+#define WM8995_AIF2DAC_LRCLK_DIR_MASK           0x0800	/* AIF2DAC_LRCLK_DIR */
+#define WM8995_AIF2DAC_LRCLK_DIR_SHIFT              11	/* AIF2DAC_LRCLK_DIR */
+#define WM8995_AIF2DAC_LRCLK_DIR_WIDTH               1	/* AIF2DAC_LRCLK_DIR */
+#define WM8995_AIF2DAC_RATE_MASK                0x07FF	/* AIF2DAC_RATE - [10:0] */
+#define WM8995_AIF2DAC_RATE_SHIFT                    0	/* AIF2DAC_RATE - [10:0] */
+#define WM8995_AIF2DAC_RATE_WIDTH                   11	/* AIF2DAC_RATE - [10:0] */
+
+/*
+ * R790 (0x316) - AIF2DAC Data
+ */
+#define WM8995_AIF2DACL_DAT_INV                 0x0002	/* AIF2DACL_DAT_INV */
+#define WM8995_AIF2DACL_DAT_INV_MASK            0x0002	/* AIF2DACL_DAT_INV */
+#define WM8995_AIF2DACL_DAT_INV_SHIFT                1	/* AIF2DACL_DAT_INV */
+#define WM8995_AIF2DACL_DAT_INV_WIDTH                1	/* AIF2DACL_DAT_INV */
+#define WM8995_AIF2DACR_DAT_INV                 0x0001	/* AIF2DACR_DAT_INV */
+#define WM8995_AIF2DACR_DAT_INV_MASK            0x0001	/* AIF2DACR_DAT_INV */
+#define WM8995_AIF2DACR_DAT_INV_SHIFT                0	/* AIF2DACR_DAT_INV */
+#define WM8995_AIF2DACR_DAT_INV_WIDTH                1	/* AIF2DACR_DAT_INV */
+
+/*
+ * R791 (0x317) - AIF2ADC Data
+ */
+#define WM8995_AIF2ADCL_DAT_INV                 0x0002	/* AIF2ADCL_DAT_INV */
+#define WM8995_AIF2ADCL_DAT_INV_MASK            0x0002	/* AIF2ADCL_DAT_INV */
+#define WM8995_AIF2ADCL_DAT_INV_SHIFT                1	/* AIF2ADCL_DAT_INV */
+#define WM8995_AIF2ADCL_DAT_INV_WIDTH                1	/* AIF2ADCL_DAT_INV */
+#define WM8995_AIF2ADCR_DAT_INV                 0x0001	/* AIF2ADCR_DAT_INV */
+#define WM8995_AIF2ADCR_DAT_INV_MASK            0x0001	/* AIF2ADCR_DAT_INV */
+#define WM8995_AIF2ADCR_DAT_INV_SHIFT                0	/* AIF2ADCR_DAT_INV */
+#define WM8995_AIF2ADCR_DAT_INV_WIDTH                1	/* AIF2ADCR_DAT_INV */
+
+/*
+ * R1024 (0x400) - AIF1 ADC1 Left Volume
+ */
+#define WM8995_AIF1ADC1_VU                      0x0100	/* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1_VU_MASK                 0x0100	/* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1_VU_SHIFT                     8	/* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1_VU_WIDTH                     1	/* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1L_VOL_MASK               0x00FF	/* AIF1ADC1L_VOL - [7:0] */
+#define WM8995_AIF1ADC1L_VOL_SHIFT                   0	/* AIF1ADC1L_VOL - [7:0] */
+#define WM8995_AIF1ADC1L_VOL_WIDTH                   8	/* AIF1ADC1L_VOL - [7:0] */
+
+/*
+ * R1025 (0x401) - AIF1 ADC1 Right Volume
+ */
+#define WM8995_AIF1ADC1_VU                      0x0100	/* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1_VU_MASK                 0x0100	/* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1_VU_SHIFT                     8	/* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1_VU_WIDTH                     1	/* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1R_VOL_MASK               0x00FF	/* AIF1ADC1R_VOL - [7:0] */
+#define WM8995_AIF1ADC1R_VOL_SHIFT                   0	/* AIF1ADC1R_VOL - [7:0] */
+#define WM8995_AIF1ADC1R_VOL_WIDTH                   8	/* AIF1ADC1R_VOL - [7:0] */
+
+/*
+ * R1026 (0x402) - AIF1 DAC1 Left Volume
+ */
+#define WM8995_AIF1DAC1_VU                      0x0100	/* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1_VU_MASK                 0x0100	/* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1_VU_SHIFT                     8	/* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1_VU_WIDTH                     1	/* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1L_VOL_MASK               0x00FF	/* AIF1DAC1L_VOL - [7:0] */
+#define WM8995_AIF1DAC1L_VOL_SHIFT                   0	/* AIF1DAC1L_VOL - [7:0] */
+#define WM8995_AIF1DAC1L_VOL_WIDTH                   8	/* AIF1DAC1L_VOL - [7:0] */
+
+/*
+ * R1027 (0x403) - AIF1 DAC1 Right Volume
+ */
+#define WM8995_AIF1DAC1_VU                      0x0100	/* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1_VU_MASK                 0x0100	/* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1_VU_SHIFT                     8	/* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1_VU_WIDTH                     1	/* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1R_VOL_MASK               0x00FF	/* AIF1DAC1R_VOL - [7:0] */
+#define WM8995_AIF1DAC1R_VOL_SHIFT                   0	/* AIF1DAC1R_VOL - [7:0] */
+#define WM8995_AIF1DAC1R_VOL_WIDTH                   8	/* AIF1DAC1R_VOL - [7:0] */
+
+/*
+ * R1028 (0x404) - AIF1 ADC2 Left Volume
+ */
+#define WM8995_AIF1ADC2_VU                      0x0100	/* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2_VU_MASK                 0x0100	/* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2_VU_SHIFT                     8	/* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2_VU_WIDTH                     1	/* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2L_VOL_MASK               0x00FF	/* AIF1ADC2L_VOL - [7:0] */
+#define WM8995_AIF1ADC2L_VOL_SHIFT                   0	/* AIF1ADC2L_VOL - [7:0] */
+#define WM8995_AIF1ADC2L_VOL_WIDTH                   8	/* AIF1ADC2L_VOL - [7:0] */
+
+/*
+ * R1029 (0x405) - AIF1 ADC2 Right Volume
+ */
+#define WM8995_AIF1ADC2_VU                      0x0100	/* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2_VU_MASK                 0x0100	/* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2_VU_SHIFT                     8	/* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2_VU_WIDTH                     1	/* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2R_VOL_MASK               0x00FF	/* AIF1ADC2R_VOL - [7:0] */
+#define WM8995_AIF1ADC2R_VOL_SHIFT                   0	/* AIF1ADC2R_VOL - [7:0] */
+#define WM8995_AIF1ADC2R_VOL_WIDTH                   8	/* AIF1ADC2R_VOL - [7:0] */
+
+/*
+ * R1030 (0x406) - AIF1 DAC2 Left Volume
+ */
+#define WM8995_AIF1DAC2_VU                      0x0100	/* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2_VU_MASK                 0x0100	/* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2_VU_SHIFT                     8	/* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2_VU_WIDTH                     1	/* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2L_VOL_MASK               0x00FF	/* AIF1DAC2L_VOL - [7:0] */
+#define WM8995_AIF1DAC2L_VOL_SHIFT                   0	/* AIF1DAC2L_VOL - [7:0] */
+#define WM8995_AIF1DAC2L_VOL_WIDTH                   8	/* AIF1DAC2L_VOL - [7:0] */
+
+/*
+ * R1031 (0x407) - AIF1 DAC2 Right Volume
+ */
+#define WM8995_AIF1DAC2_VU                      0x0100	/* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2_VU_MASK                 0x0100	/* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2_VU_SHIFT                     8	/* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2_VU_WIDTH                     1	/* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2R_VOL_MASK               0x00FF	/* AIF1DAC2R_VOL - [7:0] */
+#define WM8995_AIF1DAC2R_VOL_SHIFT                   0	/* AIF1DAC2R_VOL - [7:0] */
+#define WM8995_AIF1DAC2R_VOL_WIDTH                   8	/* AIF1DAC2R_VOL - [7:0] */
+
+/*
+ * R1040 (0x410) - AIF1 ADC1 Filters
+ */
+#define WM8995_AIF1ADC_4FS                      0x8000	/* AIF1ADC_4FS */
+#define WM8995_AIF1ADC_4FS_MASK                 0x8000	/* AIF1ADC_4FS */
+#define WM8995_AIF1ADC_4FS_SHIFT                    15	/* AIF1ADC_4FS */
+#define WM8995_AIF1ADC_4FS_WIDTH                     1	/* AIF1ADC_4FS */
+#define WM8995_AIF1ADC1L_HPF                    0x1000	/* AIF1ADC1L_HPF */
+#define WM8995_AIF1ADC1L_HPF_MASK               0x1000	/* AIF1ADC1L_HPF */
+#define WM8995_AIF1ADC1L_HPF_SHIFT                  12	/* AIF1ADC1L_HPF */
+#define WM8995_AIF1ADC1L_HPF_WIDTH                   1	/* AIF1ADC1L_HPF */
+#define WM8995_AIF1ADC1R_HPF                    0x0800	/* AIF1ADC1R_HPF */
+#define WM8995_AIF1ADC1R_HPF_MASK               0x0800	/* AIF1ADC1R_HPF */
+#define WM8995_AIF1ADC1R_HPF_SHIFT                  11	/* AIF1ADC1R_HPF */
+#define WM8995_AIF1ADC1R_HPF_WIDTH                   1	/* AIF1ADC1R_HPF */
+#define WM8995_AIF1ADC1_HPF_MODE                0x0008	/* AIF1ADC1_HPF_MODE */
+#define WM8995_AIF1ADC1_HPF_MODE_MASK           0x0008	/* AIF1ADC1_HPF_MODE */
+#define WM8995_AIF1ADC1_HPF_MODE_SHIFT               3	/* AIF1ADC1_HPF_MODE */
+#define WM8995_AIF1ADC1_HPF_MODE_WIDTH               1	/* AIF1ADC1_HPF_MODE */
+#define WM8995_AIF1ADC1_HPF_CUT_MASK            0x0007	/* AIF1ADC1_HPF_CUT - [2:0] */
+#define WM8995_AIF1ADC1_HPF_CUT_SHIFT                0	/* AIF1ADC1_HPF_CUT - [2:0] */
+#define WM8995_AIF1ADC1_HPF_CUT_WIDTH                3	/* AIF1ADC1_HPF_CUT - [2:0] */
+
+/*
+ * R1041 (0x411) - AIF1 ADC2 Filters
+ */
+#define WM8995_AIF1ADC2L_HPF                    0x1000	/* AIF1ADC2L_HPF */
+#define WM8995_AIF1ADC2L_HPF_MASK               0x1000	/* AIF1ADC2L_HPF */
+#define WM8995_AIF1ADC2L_HPF_SHIFT                  12	/* AIF1ADC2L_HPF */
+#define WM8995_AIF1ADC2L_HPF_WIDTH                   1	/* AIF1ADC2L_HPF */
+#define WM8995_AIF1ADC2R_HPF                    0x0800	/* AIF1ADC2R_HPF */
+#define WM8995_AIF1ADC2R_HPF_MASK               0x0800	/* AIF1ADC2R_HPF */
+#define WM8995_AIF1ADC2R_HPF_SHIFT                  11	/* AIF1ADC2R_HPF */
+#define WM8995_AIF1ADC2R_HPF_WIDTH                   1	/* AIF1ADC2R_HPF */
+#define WM8995_AIF1ADC2_HPF_MODE                0x0008	/* AIF1ADC2_HPF_MODE */
+#define WM8995_AIF1ADC2_HPF_MODE_MASK           0x0008	/* AIF1ADC2_HPF_MODE */
+#define WM8995_AIF1ADC2_HPF_MODE_SHIFT               3	/* AIF1ADC2_HPF_MODE */
+#define WM8995_AIF1ADC2_HPF_MODE_WIDTH               1	/* AIF1ADC2_HPF_MODE */
+#define WM8995_AIF1ADC2_HPF_CUT_MASK            0x0007	/* AIF1ADC2_HPF_CUT - [2:0] */
+#define WM8995_AIF1ADC2_HPF_CUT_SHIFT                0	/* AIF1ADC2_HPF_CUT - [2:0] */
+#define WM8995_AIF1ADC2_HPF_CUT_WIDTH                3	/* AIF1ADC2_HPF_CUT - [2:0] */
+
+/*
+ * R1056 (0x420) - AIF1 DAC1 Filters (1)
+ */
+#define WM8995_AIF1DAC1_MUTE                    0x0200	/* AIF1DAC1_MUTE */
+#define WM8995_AIF1DAC1_MUTE_MASK               0x0200	/* AIF1DAC1_MUTE */
+#define WM8995_AIF1DAC1_MUTE_SHIFT                   9	/* AIF1DAC1_MUTE */
+#define WM8995_AIF1DAC1_MUTE_WIDTH                   1	/* AIF1DAC1_MUTE */
+#define WM8995_AIF1DAC1_MONO                    0x0080	/* AIF1DAC1_MONO */
+#define WM8995_AIF1DAC1_MONO_MASK               0x0080	/* AIF1DAC1_MONO */
+#define WM8995_AIF1DAC1_MONO_SHIFT                   7	/* AIF1DAC1_MONO */
+#define WM8995_AIF1DAC1_MONO_WIDTH                   1	/* AIF1DAC1_MONO */
+#define WM8995_AIF1DAC1_MUTERATE                0x0020	/* AIF1DAC1_MUTERATE */
+#define WM8995_AIF1DAC1_MUTERATE_MASK           0x0020	/* AIF1DAC1_MUTERATE */
+#define WM8995_AIF1DAC1_MUTERATE_SHIFT               5	/* AIF1DAC1_MUTERATE */
+#define WM8995_AIF1DAC1_MUTERATE_WIDTH               1	/* AIF1DAC1_MUTERATE */
+#define WM8995_AIF1DAC1_UNMUTE_RAMP             0x0010	/* AIF1DAC1_UNMUTE_RAMP */
+#define WM8995_AIF1DAC1_UNMUTE_RAMP_MASK        0x0010	/* AIF1DAC1_UNMUTE_RAMP */
+#define WM8995_AIF1DAC1_UNMUTE_RAMP_SHIFT            4	/* AIF1DAC1_UNMUTE_RAMP */
+#define WM8995_AIF1DAC1_UNMUTE_RAMP_WIDTH            1	/* AIF1DAC1_UNMUTE_RAMP */
+#define WM8995_AIF1DAC1_DEEMP_MASK              0x0006	/* AIF1DAC1_DEEMP - [2:1] */
+#define WM8995_AIF1DAC1_DEEMP_SHIFT                  1	/* AIF1DAC1_DEEMP - [2:1] */
+#define WM8995_AIF1DAC1_DEEMP_WIDTH                  2	/* AIF1DAC1_DEEMP - [2:1] */
+
+/*
+ * R1057 (0x421) - AIF1 DAC1 Filters (2)
+ */
+#define WM8995_AIF1DAC1_3D_GAIN_MASK            0x3E00	/* AIF1DAC1_3D_GAIN - [13:9] */
+#define WM8995_AIF1DAC1_3D_GAIN_SHIFT                9	/* AIF1DAC1_3D_GAIN - [13:9] */
+#define WM8995_AIF1DAC1_3D_GAIN_WIDTH                5	/* AIF1DAC1_3D_GAIN - [13:9] */
+#define WM8995_AIF1DAC1_3D_ENA                  0x0100	/* AIF1DAC1_3D_ENA */
+#define WM8995_AIF1DAC1_3D_ENA_MASK             0x0100	/* AIF1DAC1_3D_ENA */
+#define WM8995_AIF1DAC1_3D_ENA_SHIFT                 8	/* AIF1DAC1_3D_ENA */
+#define WM8995_AIF1DAC1_3D_ENA_WIDTH                 1	/* AIF1DAC1_3D_ENA */
+
+/*
+ * R1058 (0x422) - AIF1 DAC2 Filters (1)
+ */
+#define WM8995_AIF1DAC2_MUTE                    0x0200	/* AIF1DAC2_MUTE */
+#define WM8995_AIF1DAC2_MUTE_MASK               0x0200	/* AIF1DAC2_MUTE */
+#define WM8995_AIF1DAC2_MUTE_SHIFT                   9	/* AIF1DAC2_MUTE */
+#define WM8995_AIF1DAC2_MUTE_WIDTH                   1	/* AIF1DAC2_MUTE */
+#define WM8995_AIF1DAC2_MONO                    0x0080	/* AIF1DAC2_MONO */
+#define WM8995_AIF1DAC2_MONO_MASK               0x0080	/* AIF1DAC2_MONO */
+#define WM8995_AIF1DAC2_MONO_SHIFT                   7	/* AIF1DAC2_MONO */
+#define WM8995_AIF1DAC2_MONO_WIDTH                   1	/* AIF1DAC2_MONO */
+#define WM8995_AIF1DAC2_MUTERATE                0x0020	/* AIF1DAC2_MUTERATE */
+#define WM8995_AIF1DAC2_MUTERATE_MASK           0x0020	/* AIF1DAC2_MUTERATE */
+#define WM8995_AIF1DAC2_MUTERATE_SHIFT               5	/* AIF1DAC2_MUTERATE */
+#define WM8995_AIF1DAC2_MUTERATE_WIDTH               1	/* AIF1DAC2_MUTERATE */
+#define WM8995_AIF1DAC2_UNMUTE_RAMP             0x0010	/* AIF1DAC2_UNMUTE_RAMP */
+#define WM8995_AIF1DAC2_UNMUTE_RAMP_MASK        0x0010	/* AIF1DAC2_UNMUTE_RAMP */
+#define WM8995_AIF1DAC2_UNMUTE_RAMP_SHIFT            4	/* AIF1DAC2_UNMUTE_RAMP */
+#define WM8995_AIF1DAC2_UNMUTE_RAMP_WIDTH            1	/* AIF1DAC2_UNMUTE_RAMP */
+#define WM8995_AIF1DAC2_DEEMP_MASK              0x0006	/* AIF1DAC2_DEEMP - [2:1] */
+#define WM8995_AIF1DAC2_DEEMP_SHIFT                  1	/* AIF1DAC2_DEEMP - [2:1] */
+#define WM8995_AIF1DAC2_DEEMP_WIDTH                  2	/* AIF1DAC2_DEEMP - [2:1] */
+
+/*
+ * R1059 (0x423) - AIF1 DAC2 Filters (2)
+ */
+#define WM8995_AIF1DAC2_3D_GAIN_MASK            0x3E00	/* AIF1DAC2_3D_GAIN - [13:9] */
+#define WM8995_AIF1DAC2_3D_GAIN_SHIFT                9	/* AIF1DAC2_3D_GAIN - [13:9] */
+#define WM8995_AIF1DAC2_3D_GAIN_WIDTH                5	/* AIF1DAC2_3D_GAIN - [13:9] */
+#define WM8995_AIF1DAC2_3D_ENA                  0x0100	/* AIF1DAC2_3D_ENA */
+#define WM8995_AIF1DAC2_3D_ENA_MASK             0x0100	/* AIF1DAC2_3D_ENA */
+#define WM8995_AIF1DAC2_3D_ENA_SHIFT                 8	/* AIF1DAC2_3D_ENA */
+#define WM8995_AIF1DAC2_3D_ENA_WIDTH                 1	/* AIF1DAC2_3D_ENA */
+
+/*
+ * R1088 (0x440) - AIF1 DRC1 (1)
+ */
+#define WM8995_AIF1DRC1_SIG_DET_RMS_MASK        0xF800	/* AIF1DRC1_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF1DRC1_SIG_DET_RMS_SHIFT           11	/* AIF1DRC1_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF1DRC1_SIG_DET_RMS_WIDTH            5	/* AIF1DRC1_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF1DRC1_SIG_DET_PK_MASK         0x0600	/* AIF1DRC1_SIG_DET_PK - [10:9] */
+#define WM8995_AIF1DRC1_SIG_DET_PK_SHIFT             9	/* AIF1DRC1_SIG_DET_PK - [10:9] */
+#define WM8995_AIF1DRC1_SIG_DET_PK_WIDTH             2	/* AIF1DRC1_SIG_DET_PK - [10:9] */
+#define WM8995_AIF1DRC1_NG_ENA                  0x0100	/* AIF1DRC1_NG_ENA */
+#define WM8995_AIF1DRC1_NG_ENA_MASK             0x0100	/* AIF1DRC1_NG_ENA */
+#define WM8995_AIF1DRC1_NG_ENA_SHIFT                 8	/* AIF1DRC1_NG_ENA */
+#define WM8995_AIF1DRC1_NG_ENA_WIDTH                 1	/* AIF1DRC1_NG_ENA */
+#define WM8995_AIF1DRC1_SIG_DET_MODE            0x0080	/* AIF1DRC1_SIG_DET_MODE */
+#define WM8995_AIF1DRC1_SIG_DET_MODE_MASK       0x0080	/* AIF1DRC1_SIG_DET_MODE */
+#define WM8995_AIF1DRC1_SIG_DET_MODE_SHIFT           7	/* AIF1DRC1_SIG_DET_MODE */
+#define WM8995_AIF1DRC1_SIG_DET_MODE_WIDTH           1	/* AIF1DRC1_SIG_DET_MODE */
+#define WM8995_AIF1DRC1_SIG_DET                 0x0040	/* AIF1DRC1_SIG_DET */
+#define WM8995_AIF1DRC1_SIG_DET_MASK            0x0040	/* AIF1DRC1_SIG_DET */
+#define WM8995_AIF1DRC1_SIG_DET_SHIFT                6	/* AIF1DRC1_SIG_DET */
+#define WM8995_AIF1DRC1_SIG_DET_WIDTH                1	/* AIF1DRC1_SIG_DET */
+#define WM8995_AIF1DRC1_KNEE2_OP_ENA            0x0020	/* AIF1DRC1_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC1_KNEE2_OP_ENA_MASK       0x0020	/* AIF1DRC1_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC1_KNEE2_OP_ENA_SHIFT           5	/* AIF1DRC1_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC1_KNEE2_OP_ENA_WIDTH           1	/* AIF1DRC1_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC1_QR                      0x0010	/* AIF1DRC1_QR */
+#define WM8995_AIF1DRC1_QR_MASK                 0x0010	/* AIF1DRC1_QR */
+#define WM8995_AIF1DRC1_QR_SHIFT                     4	/* AIF1DRC1_QR */
+#define WM8995_AIF1DRC1_QR_WIDTH                     1	/* AIF1DRC1_QR */
+#define WM8995_AIF1DRC1_ANTICLIP                0x0008	/* AIF1DRC1_ANTICLIP */
+#define WM8995_AIF1DRC1_ANTICLIP_MASK           0x0008	/* AIF1DRC1_ANTICLIP */
+#define WM8995_AIF1DRC1_ANTICLIP_SHIFT               3	/* AIF1DRC1_ANTICLIP */
+#define WM8995_AIF1DRC1_ANTICLIP_WIDTH               1	/* AIF1DRC1_ANTICLIP */
+#define WM8995_AIF1DAC1_DRC_ENA                 0x0004	/* AIF1DAC1_DRC_ENA */
+#define WM8995_AIF1DAC1_DRC_ENA_MASK            0x0004	/* AIF1DAC1_DRC_ENA */
+#define WM8995_AIF1DAC1_DRC_ENA_SHIFT                2	/* AIF1DAC1_DRC_ENA */
+#define WM8995_AIF1DAC1_DRC_ENA_WIDTH                1	/* AIF1DAC1_DRC_ENA */
+#define WM8995_AIF1ADC1L_DRC_ENA                0x0002	/* AIF1ADC1L_DRC_ENA */
+#define WM8995_AIF1ADC1L_DRC_ENA_MASK           0x0002	/* AIF1ADC1L_DRC_ENA */
+#define WM8995_AIF1ADC1L_DRC_ENA_SHIFT               1	/* AIF1ADC1L_DRC_ENA */
+#define WM8995_AIF1ADC1L_DRC_ENA_WIDTH               1	/* AIF1ADC1L_DRC_ENA */
+#define WM8995_AIF1ADC1R_DRC_ENA                0x0001	/* AIF1ADC1R_DRC_ENA */
+#define WM8995_AIF1ADC1R_DRC_ENA_MASK           0x0001	/* AIF1ADC1R_DRC_ENA */
+#define WM8995_AIF1ADC1R_DRC_ENA_SHIFT               0	/* AIF1ADC1R_DRC_ENA */
+#define WM8995_AIF1ADC1R_DRC_ENA_WIDTH               1	/* AIF1ADC1R_DRC_ENA */
+
+/*
+ * R1089 (0x441) - AIF1 DRC1 (2)
+ */
+#define WM8995_AIF1DRC1_ATK_MASK                0x1E00	/* AIF1DRC1_ATK - [12:9] */
+#define WM8995_AIF1DRC1_ATK_SHIFT                    9	/* AIF1DRC1_ATK - [12:9] */
+#define WM8995_AIF1DRC1_ATK_WIDTH                    4	/* AIF1DRC1_ATK - [12:9] */
+#define WM8995_AIF1DRC1_DCY_MASK                0x01E0	/* AIF1DRC1_DCY - [8:5] */
+#define WM8995_AIF1DRC1_DCY_SHIFT                    5	/* AIF1DRC1_DCY - [8:5] */
+#define WM8995_AIF1DRC1_DCY_WIDTH                    4	/* AIF1DRC1_DCY - [8:5] */
+#define WM8995_AIF1DRC1_MINGAIN_MASK            0x001C	/* AIF1DRC1_MINGAIN - [4:2] */
+#define WM8995_AIF1DRC1_MINGAIN_SHIFT                2	/* AIF1DRC1_MINGAIN - [4:2] */
+#define WM8995_AIF1DRC1_MINGAIN_WIDTH                3	/* AIF1DRC1_MINGAIN - [4:2] */
+#define WM8995_AIF1DRC1_MAXGAIN_MASK            0x0003	/* AIF1DRC1_MAXGAIN - [1:0] */
+#define WM8995_AIF1DRC1_MAXGAIN_SHIFT                0	/* AIF1DRC1_MAXGAIN - [1:0] */
+#define WM8995_AIF1DRC1_MAXGAIN_WIDTH                2	/* AIF1DRC1_MAXGAIN - [1:0] */
+
+/*
+ * R1090 (0x442) - AIF1 DRC1 (3)
+ */
+#define WM8995_AIF1DRC1_NG_MINGAIN_MASK         0xF000	/* AIF1DRC1_NG_MINGAIN - [15:12] */
+#define WM8995_AIF1DRC1_NG_MINGAIN_SHIFT            12	/* AIF1DRC1_NG_MINGAIN - [15:12] */
+#define WM8995_AIF1DRC1_NG_MINGAIN_WIDTH             4	/* AIF1DRC1_NG_MINGAIN - [15:12] */
+#define WM8995_AIF1DRC1_NG_EXP_MASK             0x0C00	/* AIF1DRC1_NG_EXP - [11:10] */
+#define WM8995_AIF1DRC1_NG_EXP_SHIFT                10	/* AIF1DRC1_NG_EXP - [11:10] */
+#define WM8995_AIF1DRC1_NG_EXP_WIDTH                 2	/* AIF1DRC1_NG_EXP - [11:10] */
+#define WM8995_AIF1DRC1_QR_THR_MASK             0x0300	/* AIF1DRC1_QR_THR - [9:8] */
+#define WM8995_AIF1DRC1_QR_THR_SHIFT                 8	/* AIF1DRC1_QR_THR - [9:8] */
+#define WM8995_AIF1DRC1_QR_THR_WIDTH                 2	/* AIF1DRC1_QR_THR - [9:8] */
+#define WM8995_AIF1DRC1_QR_DCY_MASK             0x00C0	/* AIF1DRC1_QR_DCY - [7:6] */
+#define WM8995_AIF1DRC1_QR_DCY_SHIFT                 6	/* AIF1DRC1_QR_DCY - [7:6] */
+#define WM8995_AIF1DRC1_QR_DCY_WIDTH                 2	/* AIF1DRC1_QR_DCY - [7:6] */
+#define WM8995_AIF1DRC1_HI_COMP_MASK            0x0038	/* AIF1DRC1_HI_COMP - [5:3] */
+#define WM8995_AIF1DRC1_HI_COMP_SHIFT                3	/* AIF1DRC1_HI_COMP - [5:3] */
+#define WM8995_AIF1DRC1_HI_COMP_WIDTH                3	/* AIF1DRC1_HI_COMP - [5:3] */
+#define WM8995_AIF1DRC1_LO_COMP_MASK            0x0007	/* AIF1DRC1_LO_COMP - [2:0] */
+#define WM8995_AIF1DRC1_LO_COMP_SHIFT                0	/* AIF1DRC1_LO_COMP - [2:0] */
+#define WM8995_AIF1DRC1_LO_COMP_WIDTH                3	/* AIF1DRC1_LO_COMP - [2:0] */
+
+/*
+ * R1091 (0x443) - AIF1 DRC1 (4)
+ */
+#define WM8995_AIF1DRC1_KNEE_IP_MASK            0x07E0	/* AIF1DRC1_KNEE_IP - [10:5] */
+#define WM8995_AIF1DRC1_KNEE_IP_SHIFT                5	/* AIF1DRC1_KNEE_IP - [10:5] */
+#define WM8995_AIF1DRC1_KNEE_IP_WIDTH                6	/* AIF1DRC1_KNEE_IP - [10:5] */
+#define WM8995_AIF1DRC1_KNEE_OP_MASK            0x001F	/* AIF1DRC1_KNEE_OP - [4:0] */
+#define WM8995_AIF1DRC1_KNEE_OP_SHIFT                0	/* AIF1DRC1_KNEE_OP - [4:0] */
+#define WM8995_AIF1DRC1_KNEE_OP_WIDTH                5	/* AIF1DRC1_KNEE_OP - [4:0] */
+
+/*
+ * R1092 (0x444) - AIF1 DRC1 (5)
+ */
+#define WM8995_AIF1DRC1_KNEE2_IP_MASK           0x03E0	/* AIF1DRC1_KNEE2_IP - [9:5] */
+#define WM8995_AIF1DRC1_KNEE2_IP_SHIFT               5	/* AIF1DRC1_KNEE2_IP - [9:5] */
+#define WM8995_AIF1DRC1_KNEE2_IP_WIDTH               5	/* AIF1DRC1_KNEE2_IP - [9:5] */
+#define WM8995_AIF1DRC1_KNEE2_OP_MASK           0x001F	/* AIF1DRC1_KNEE2_OP - [4:0] */
+#define WM8995_AIF1DRC1_KNEE2_OP_SHIFT               0	/* AIF1DRC1_KNEE2_OP - [4:0] */
+#define WM8995_AIF1DRC1_KNEE2_OP_WIDTH               5	/* AIF1DRC1_KNEE2_OP - [4:0] */
+
+/*
+ * R1104 (0x450) - AIF1 DRC2 (1)
+ */
+#define WM8995_AIF1DRC2_SIG_DET_RMS_MASK        0xF800	/* AIF1DRC2_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF1DRC2_SIG_DET_RMS_SHIFT           11	/* AIF1DRC2_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF1DRC2_SIG_DET_RMS_WIDTH            5	/* AIF1DRC2_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF1DRC2_SIG_DET_PK_MASK         0x0600	/* AIF1DRC2_SIG_DET_PK - [10:9] */
+#define WM8995_AIF1DRC2_SIG_DET_PK_SHIFT             9	/* AIF1DRC2_SIG_DET_PK - [10:9] */
+#define WM8995_AIF1DRC2_SIG_DET_PK_WIDTH             2	/* AIF1DRC2_SIG_DET_PK - [10:9] */
+#define WM8995_AIF1DRC2_NG_ENA                  0x0100	/* AIF1DRC2_NG_ENA */
+#define WM8995_AIF1DRC2_NG_ENA_MASK             0x0100	/* AIF1DRC2_NG_ENA */
+#define WM8995_AIF1DRC2_NG_ENA_SHIFT                 8	/* AIF1DRC2_NG_ENA */
+#define WM8995_AIF1DRC2_NG_ENA_WIDTH                 1	/* AIF1DRC2_NG_ENA */
+#define WM8995_AIF1DRC2_SIG_DET_MODE            0x0080	/* AIF1DRC2_SIG_DET_MODE */
+#define WM8995_AIF1DRC2_SIG_DET_MODE_MASK       0x0080	/* AIF1DRC2_SIG_DET_MODE */
+#define WM8995_AIF1DRC2_SIG_DET_MODE_SHIFT           7	/* AIF1DRC2_SIG_DET_MODE */
+#define WM8995_AIF1DRC2_SIG_DET_MODE_WIDTH           1	/* AIF1DRC2_SIG_DET_MODE */
+#define WM8995_AIF1DRC2_SIG_DET                 0x0040	/* AIF1DRC2_SIG_DET */
+#define WM8995_AIF1DRC2_SIG_DET_MASK            0x0040	/* AIF1DRC2_SIG_DET */
+#define WM8995_AIF1DRC2_SIG_DET_SHIFT                6	/* AIF1DRC2_SIG_DET */
+#define WM8995_AIF1DRC2_SIG_DET_WIDTH                1	/* AIF1DRC2_SIG_DET */
+#define WM8995_AIF1DRC2_KNEE2_OP_ENA            0x0020	/* AIF1DRC2_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC2_KNEE2_OP_ENA_MASK       0x0020	/* AIF1DRC2_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC2_KNEE2_OP_ENA_SHIFT           5	/* AIF1DRC2_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC2_KNEE2_OP_ENA_WIDTH           1	/* AIF1DRC2_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC2_QR                      0x0010	/* AIF1DRC2_QR */
+#define WM8995_AIF1DRC2_QR_MASK                 0x0010	/* AIF1DRC2_QR */
+#define WM8995_AIF1DRC2_QR_SHIFT                     4	/* AIF1DRC2_QR */
+#define WM8995_AIF1DRC2_QR_WIDTH                     1	/* AIF1DRC2_QR */
+#define WM8995_AIF1DRC2_ANTICLIP                0x0008	/* AIF1DRC2_ANTICLIP */
+#define WM8995_AIF1DRC2_ANTICLIP_MASK           0x0008	/* AIF1DRC2_ANTICLIP */
+#define WM8995_AIF1DRC2_ANTICLIP_SHIFT               3	/* AIF1DRC2_ANTICLIP */
+#define WM8995_AIF1DRC2_ANTICLIP_WIDTH               1	/* AIF1DRC2_ANTICLIP */
+#define WM8995_AIF1DAC2_DRC_ENA                 0x0004	/* AIF1DAC2_DRC_ENA */
+#define WM8995_AIF1DAC2_DRC_ENA_MASK            0x0004	/* AIF1DAC2_DRC_ENA */
+#define WM8995_AIF1DAC2_DRC_ENA_SHIFT                2	/* AIF1DAC2_DRC_ENA */
+#define WM8995_AIF1DAC2_DRC_ENA_WIDTH                1	/* AIF1DAC2_DRC_ENA */
+#define WM8995_AIF1ADC2L_DRC_ENA                0x0002	/* AIF1ADC2L_DRC_ENA */
+#define WM8995_AIF1ADC2L_DRC_ENA_MASK           0x0002	/* AIF1ADC2L_DRC_ENA */
+#define WM8995_AIF1ADC2L_DRC_ENA_SHIFT               1	/* AIF1ADC2L_DRC_ENA */
+#define WM8995_AIF1ADC2L_DRC_ENA_WIDTH               1	/* AIF1ADC2L_DRC_ENA */
+#define WM8995_AIF1ADC2R_DRC_ENA                0x0001	/* AIF1ADC2R_DRC_ENA */
+#define WM8995_AIF1ADC2R_DRC_ENA_MASK           0x0001	/* AIF1ADC2R_DRC_ENA */
+#define WM8995_AIF1ADC2R_DRC_ENA_SHIFT               0	/* AIF1ADC2R_DRC_ENA */
+#define WM8995_AIF1ADC2R_DRC_ENA_WIDTH               1	/* AIF1ADC2R_DRC_ENA */
+
+/*
+ * R1105 (0x451) - AIF1 DRC2 (2)
+ */
+#define WM8995_AIF1DRC2_ATK_MASK                0x1E00	/* AIF1DRC2_ATK - [12:9] */
+#define WM8995_AIF1DRC2_ATK_SHIFT                    9	/* AIF1DRC2_ATK - [12:9] */
+#define WM8995_AIF1DRC2_ATK_WIDTH                    4	/* AIF1DRC2_ATK - [12:9] */
+#define WM8995_AIF1DRC2_DCY_MASK                0x01E0	/* AIF1DRC2_DCY - [8:5] */
+#define WM8995_AIF1DRC2_DCY_SHIFT                    5	/* AIF1DRC2_DCY - [8:5] */
+#define WM8995_AIF1DRC2_DCY_WIDTH                    4	/* AIF1DRC2_DCY - [8:5] */
+#define WM8995_AIF1DRC2_MINGAIN_MASK            0x001C	/* AIF1DRC2_MINGAIN - [4:2] */
+#define WM8995_AIF1DRC2_MINGAIN_SHIFT                2	/* AIF1DRC2_MINGAIN - [4:2] */
+#define WM8995_AIF1DRC2_MINGAIN_WIDTH                3	/* AIF1DRC2_MINGAIN - [4:2] */
+#define WM8995_AIF1DRC2_MAXGAIN_MASK            0x0003	/* AIF1DRC2_MAXGAIN - [1:0] */
+#define WM8995_AIF1DRC2_MAXGAIN_SHIFT                0	/* AIF1DRC2_MAXGAIN - [1:0] */
+#define WM8995_AIF1DRC2_MAXGAIN_WIDTH                2	/* AIF1DRC2_MAXGAIN - [1:0] */
+
+/*
+ * R1106 (0x452) - AIF1 DRC2 (3)
+ */
+#define WM8995_AIF1DRC2_NG_MINGAIN_MASK         0xF000	/* AIF1DRC2_NG_MINGAIN - [15:12] */
+#define WM8995_AIF1DRC2_NG_MINGAIN_SHIFT            12	/* AIF1DRC2_NG_MINGAIN - [15:12] */
+#define WM8995_AIF1DRC2_NG_MINGAIN_WIDTH             4	/* AIF1DRC2_NG_MINGAIN - [15:12] */
+#define WM8995_AIF1DRC2_NG_EXP_MASK             0x0C00	/* AIF1DRC2_NG_EXP - [11:10] */
+#define WM8995_AIF1DRC2_NG_EXP_SHIFT                10	/* AIF1DRC2_NG_EXP - [11:10] */
+#define WM8995_AIF1DRC2_NG_EXP_WIDTH                 2	/* AIF1DRC2_NG_EXP - [11:10] */
+#define WM8995_AIF1DRC2_QR_THR_MASK             0x0300	/* AIF1DRC2_QR_THR - [9:8] */
+#define WM8995_AIF1DRC2_QR_THR_SHIFT                 8	/* AIF1DRC2_QR_THR - [9:8] */
+#define WM8995_AIF1DRC2_QR_THR_WIDTH                 2	/* AIF1DRC2_QR_THR - [9:8] */
+#define WM8995_AIF1DRC2_QR_DCY_MASK             0x00C0	/* AIF1DRC2_QR_DCY - [7:6] */
+#define WM8995_AIF1DRC2_QR_DCY_SHIFT                 6	/* AIF1DRC2_QR_DCY - [7:6] */
+#define WM8995_AIF1DRC2_QR_DCY_WIDTH                 2	/* AIF1DRC2_QR_DCY - [7:6] */
+#define WM8995_AIF1DRC2_HI_COMP_MASK            0x0038	/* AIF1DRC2_HI_COMP - [5:3] */
+#define WM8995_AIF1DRC2_HI_COMP_SHIFT                3	/* AIF1DRC2_HI_COMP - [5:3] */
+#define WM8995_AIF1DRC2_HI_COMP_WIDTH                3	/* AIF1DRC2_HI_COMP - [5:3] */
+#define WM8995_AIF1DRC2_LO_COMP_MASK            0x0007	/* AIF1DRC2_LO_COMP - [2:0] */
+#define WM8995_AIF1DRC2_LO_COMP_SHIFT                0	/* AIF1DRC2_LO_COMP - [2:0] */
+#define WM8995_AIF1DRC2_LO_COMP_WIDTH                3	/* AIF1DRC2_LO_COMP - [2:0] */
+
+/*
+ * R1107 (0x453) - AIF1 DRC2 (4)
+ */
+#define WM8995_AIF1DRC2_KNEE_IP_MASK            0x07E0	/* AIF1DRC2_KNEE_IP - [10:5] */
+#define WM8995_AIF1DRC2_KNEE_IP_SHIFT                5	/* AIF1DRC2_KNEE_IP - [10:5] */
+#define WM8995_AIF1DRC2_KNEE_IP_WIDTH                6	/* AIF1DRC2_KNEE_IP - [10:5] */
+#define WM8995_AIF1DRC2_KNEE_OP_MASK            0x001F	/* AIF1DRC2_KNEE_OP - [4:0] */
+#define WM8995_AIF1DRC2_KNEE_OP_SHIFT                0	/* AIF1DRC2_KNEE_OP - [4:0] */
+#define WM8995_AIF1DRC2_KNEE_OP_WIDTH                5	/* AIF1DRC2_KNEE_OP - [4:0] */
+
+/*
+ * R1108 (0x454) - AIF1 DRC2 (5)
+ */
+#define WM8995_AIF1DRC2_KNEE2_IP_MASK           0x03E0	/* AIF1DRC2_KNEE2_IP - [9:5] */
+#define WM8995_AIF1DRC2_KNEE2_IP_SHIFT               5	/* AIF1DRC2_KNEE2_IP - [9:5] */
+#define WM8995_AIF1DRC2_KNEE2_IP_WIDTH               5	/* AIF1DRC2_KNEE2_IP - [9:5] */
+#define WM8995_AIF1DRC2_KNEE2_OP_MASK           0x001F	/* AIF1DRC2_KNEE2_OP - [4:0] */
+#define WM8995_AIF1DRC2_KNEE2_OP_SHIFT               0	/* AIF1DRC2_KNEE2_OP - [4:0] */
+#define WM8995_AIF1DRC2_KNEE2_OP_WIDTH               5	/* AIF1DRC2_KNEE2_OP - [4:0] */
+
+/*
+ * R1152 (0x480) - AIF1 DAC1 EQ Gains (1)
+ */
+#define WM8995_AIF1DAC1_EQ_B1_GAIN_MASK         0xF800	/* AIF1DAC1_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF1DAC1_EQ_B1_GAIN_SHIFT            11	/* AIF1DAC1_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF1DAC1_EQ_B1_GAIN_WIDTH             5	/* AIF1DAC1_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF1DAC1_EQ_B2_GAIN_MASK         0x07C0	/* AIF1DAC1_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF1DAC1_EQ_B2_GAIN_SHIFT             6	/* AIF1DAC1_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF1DAC1_EQ_B2_GAIN_WIDTH             5	/* AIF1DAC1_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF1DAC1_EQ_B3_GAIN_MASK         0x003E	/* AIF1DAC1_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF1DAC1_EQ_B3_GAIN_SHIFT             1	/* AIF1DAC1_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF1DAC1_EQ_B3_GAIN_WIDTH             5	/* AIF1DAC1_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF1DAC1_EQ_ENA                  0x0001	/* AIF1DAC1_EQ_ENA */
+#define WM8995_AIF1DAC1_EQ_ENA_MASK             0x0001	/* AIF1DAC1_EQ_ENA */
+#define WM8995_AIF1DAC1_EQ_ENA_SHIFT                 0	/* AIF1DAC1_EQ_ENA */
+#define WM8995_AIF1DAC1_EQ_ENA_WIDTH                 1	/* AIF1DAC1_EQ_ENA */
+
+/*
+ * R1153 (0x481) - AIF1 DAC1 EQ Gains (2)
+ */
+#define WM8995_AIF1DAC1_EQ_B4_GAIN_MASK         0xF800	/* AIF1DAC1_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF1DAC1_EQ_B4_GAIN_SHIFT            11	/* AIF1DAC1_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF1DAC1_EQ_B4_GAIN_WIDTH             5	/* AIF1DAC1_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF1DAC1_EQ_B5_GAIN_MASK         0x07C0	/* AIF1DAC1_EQ_B5_GAIN - [10:6] */
+#define WM8995_AIF1DAC1_EQ_B5_GAIN_SHIFT             6	/* AIF1DAC1_EQ_B5_GAIN - [10:6] */
+#define WM8995_AIF1DAC1_EQ_B5_GAIN_WIDTH             5	/* AIF1DAC1_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1154 (0x482) - AIF1 DAC1 EQ Band 1 A
+ */
+#define WM8995_AIF1DAC1_EQ_B1_A_MASK            0xFFFF	/* AIF1DAC1_EQ_B1_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B1_A_SHIFT                0	/* AIF1DAC1_EQ_B1_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B1_A_WIDTH               16	/* AIF1DAC1_EQ_B1_A - [15:0] */
+
+/*
+ * R1155 (0x483) - AIF1 DAC1 EQ Band 1 B
+ */
+#define WM8995_AIF1DAC1_EQ_B1_B_MASK            0xFFFF	/* AIF1DAC1_EQ_B1_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B1_B_SHIFT                0	/* AIF1DAC1_EQ_B1_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B1_B_WIDTH               16	/* AIF1DAC1_EQ_B1_B - [15:0] */
+
+/*
+ * R1156 (0x484) - AIF1 DAC1 EQ Band 1 PG
+ */
+#define WM8995_AIF1DAC1_EQ_B1_PG_MASK           0xFFFF	/* AIF1DAC1_EQ_B1_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B1_PG_SHIFT               0	/* AIF1DAC1_EQ_B1_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B1_PG_WIDTH              16	/* AIF1DAC1_EQ_B1_PG - [15:0] */
+
+/*
+ * R1157 (0x485) - AIF1 DAC1 EQ Band 2 A
+ */
+#define WM8995_AIF1DAC1_EQ_B2_A_MASK            0xFFFF	/* AIF1DAC1_EQ_B2_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_A_SHIFT                0	/* AIF1DAC1_EQ_B2_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_A_WIDTH               16	/* AIF1DAC1_EQ_B2_A - [15:0] */
+
+/*
+ * R1158 (0x486) - AIF1 DAC1 EQ Band 2 B
+ */
+#define WM8995_AIF1DAC1_EQ_B2_B_MASK            0xFFFF	/* AIF1DAC1_EQ_B2_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_B_SHIFT                0	/* AIF1DAC1_EQ_B2_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_B_WIDTH               16	/* AIF1DAC1_EQ_B2_B - [15:0] */
+
+/*
+ * R1159 (0x487) - AIF1 DAC1 EQ Band 2 C
+ */
+#define WM8995_AIF1DAC1_EQ_B2_C_MASK            0xFFFF	/* AIF1DAC1_EQ_B2_C - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_C_SHIFT                0	/* AIF1DAC1_EQ_B2_C - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_C_WIDTH               16	/* AIF1DAC1_EQ_B2_C - [15:0] */
+
+/*
+ * R1160 (0x488) - AIF1 DAC1 EQ Band 2 PG
+ */
+#define WM8995_AIF1DAC1_EQ_B2_PG_MASK           0xFFFF	/* AIF1DAC1_EQ_B2_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_PG_SHIFT               0	/* AIF1DAC1_EQ_B2_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_PG_WIDTH              16	/* AIF1DAC1_EQ_B2_PG - [15:0] */
+
+/*
+ * R1161 (0x489) - AIF1 DAC1 EQ Band 3 A
+ */
+#define WM8995_AIF1DAC1_EQ_B3_A_MASK            0xFFFF	/* AIF1DAC1_EQ_B3_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_A_SHIFT                0	/* AIF1DAC1_EQ_B3_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_A_WIDTH               16	/* AIF1DAC1_EQ_B3_A - [15:0] */
+
+/*
+ * R1162 (0x48A) - AIF1 DAC1 EQ Band 3 B
+ */
+#define WM8995_AIF1DAC1_EQ_B3_B_MASK            0xFFFF	/* AIF1DAC1_EQ_B3_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_B_SHIFT                0	/* AIF1DAC1_EQ_B3_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_B_WIDTH               16	/* AIF1DAC1_EQ_B3_B - [15:0] */
+
+/*
+ * R1163 (0x48B) - AIF1 DAC1 EQ Band 3 C
+ */
+#define WM8995_AIF1DAC1_EQ_B3_C_MASK            0xFFFF	/* AIF1DAC1_EQ_B3_C - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_C_SHIFT                0	/* AIF1DAC1_EQ_B3_C - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_C_WIDTH               16	/* AIF1DAC1_EQ_B3_C - [15:0] */
+
+/*
+ * R1164 (0x48C) - AIF1 DAC1 EQ Band 3 PG
+ */
+#define WM8995_AIF1DAC1_EQ_B3_PG_MASK           0xFFFF	/* AIF1DAC1_EQ_B3_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_PG_SHIFT               0	/* AIF1DAC1_EQ_B3_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_PG_WIDTH              16	/* AIF1DAC1_EQ_B3_PG - [15:0] */
+
+/*
+ * R1165 (0x48D) - AIF1 DAC1 EQ Band 4 A
+ */
+#define WM8995_AIF1DAC1_EQ_B4_A_MASK            0xFFFF	/* AIF1DAC1_EQ_B4_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_A_SHIFT                0	/* AIF1DAC1_EQ_B4_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_A_WIDTH               16	/* AIF1DAC1_EQ_B4_A - [15:0] */
+
+/*
+ * R1166 (0x48E) - AIF1 DAC1 EQ Band 4 B
+ */
+#define WM8995_AIF1DAC1_EQ_B4_B_MASK            0xFFFF	/* AIF1DAC1_EQ_B4_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_B_SHIFT                0	/* AIF1DAC1_EQ_B4_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_B_WIDTH               16	/* AIF1DAC1_EQ_B4_B - [15:0] */
+
+/*
+ * R1167 (0x48F) - AIF1 DAC1 EQ Band 4 C
+ */
+#define WM8995_AIF1DAC1_EQ_B4_C_MASK            0xFFFF	/* AIF1DAC1_EQ_B4_C - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_C_SHIFT                0	/* AIF1DAC1_EQ_B4_C - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_C_WIDTH               16	/* AIF1DAC1_EQ_B4_C - [15:0] */
+
+/*
+ * R1168 (0x490) - AIF1 DAC1 EQ Band 4 PG
+ */
+#define WM8995_AIF1DAC1_EQ_B4_PG_MASK           0xFFFF	/* AIF1DAC1_EQ_B4_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_PG_SHIFT               0	/* AIF1DAC1_EQ_B4_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_PG_WIDTH              16	/* AIF1DAC1_EQ_B4_PG - [15:0] */
+
+/*
+ * R1169 (0x491) - AIF1 DAC1 EQ Band 5 A
+ */
+#define WM8995_AIF1DAC1_EQ_B5_A_MASK            0xFFFF	/* AIF1DAC1_EQ_B5_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B5_A_SHIFT                0	/* AIF1DAC1_EQ_B5_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B5_A_WIDTH               16	/* AIF1DAC1_EQ_B5_A - [15:0] */
+
+/*
+ * R1170 (0x492) - AIF1 DAC1 EQ Band 5 B
+ */
+#define WM8995_AIF1DAC1_EQ_B5_B_MASK            0xFFFF	/* AIF1DAC1_EQ_B5_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B5_B_SHIFT                0	/* AIF1DAC1_EQ_B5_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B5_B_WIDTH               16	/* AIF1DAC1_EQ_B5_B - [15:0] */
+
+/*
+ * R1171 (0x493) - AIF1 DAC1 EQ Band 5 PG
+ */
+#define WM8995_AIF1DAC1_EQ_B5_PG_MASK           0xFFFF	/* AIF1DAC1_EQ_B5_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B5_PG_SHIFT               0	/* AIF1DAC1_EQ_B5_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B5_PG_WIDTH              16	/* AIF1DAC1_EQ_B5_PG - [15:0] */
+
+/*
+ * R1184 (0x4A0) - AIF1 DAC2 EQ Gains (1)
+ */
+#define WM8995_AIF1DAC2_EQ_B1_GAIN_MASK         0xF800	/* AIF1DAC2_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF1DAC2_EQ_B1_GAIN_SHIFT            11	/* AIF1DAC2_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF1DAC2_EQ_B1_GAIN_WIDTH             5	/* AIF1DAC2_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF1DAC2_EQ_B2_GAIN_MASK         0x07C0	/* AIF1DAC2_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF1DAC2_EQ_B2_GAIN_SHIFT             6	/* AIF1DAC2_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF1DAC2_EQ_B2_GAIN_WIDTH             5	/* AIF1DAC2_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF1DAC2_EQ_B3_GAIN_MASK         0x003E	/* AIF1DAC2_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF1DAC2_EQ_B3_GAIN_SHIFT             1	/* AIF1DAC2_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF1DAC2_EQ_B3_GAIN_WIDTH             5	/* AIF1DAC2_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF1DAC2_EQ_ENA                  0x0001	/* AIF1DAC2_EQ_ENA */
+#define WM8995_AIF1DAC2_EQ_ENA_MASK             0x0001	/* AIF1DAC2_EQ_ENA */
+#define WM8995_AIF1DAC2_EQ_ENA_SHIFT                 0	/* AIF1DAC2_EQ_ENA */
+#define WM8995_AIF1DAC2_EQ_ENA_WIDTH                 1	/* AIF1DAC2_EQ_ENA */
+
+/*
+ * R1185 (0x4A1) - AIF1 DAC2 EQ Gains (2)
+ */
+#define WM8995_AIF1DAC2_EQ_B4_GAIN_MASK         0xF800	/* AIF1DAC2_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF1DAC2_EQ_B4_GAIN_SHIFT            11	/* AIF1DAC2_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF1DAC2_EQ_B4_GAIN_WIDTH             5	/* AIF1DAC2_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF1DAC2_EQ_B5_GAIN_MASK         0x07C0	/* AIF1DAC2_EQ_B5_GAIN - [10:6] */
+#define WM8995_AIF1DAC2_EQ_B5_GAIN_SHIFT             6	/* AIF1DAC2_EQ_B5_GAIN - [10:6] */
+#define WM8995_AIF1DAC2_EQ_B5_GAIN_WIDTH             5	/* AIF1DAC2_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1186 (0x4A2) - AIF1 DAC2 EQ Band 1 A
+ */
+#define WM8995_AIF1DAC2_EQ_B1_A_MASK            0xFFFF	/* AIF1DAC2_EQ_B1_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B1_A_SHIFT                0	/* AIF1DAC2_EQ_B1_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B1_A_WIDTH               16	/* AIF1DAC2_EQ_B1_A - [15:0] */
+
+/*
+ * R1187 (0x4A3) - AIF1 DAC2 EQ Band 1 B
+ */
+#define WM8995_AIF1DAC2_EQ_B1_B_MASK            0xFFFF	/* AIF1DAC2_EQ_B1_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B1_B_SHIFT                0	/* AIF1DAC2_EQ_B1_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B1_B_WIDTH               16	/* AIF1DAC2_EQ_B1_B - [15:0] */
+
+/*
+ * R1188 (0x4A4) - AIF1 DAC2 EQ Band 1 PG
+ */
+#define WM8995_AIF1DAC2_EQ_B1_PG_MASK           0xFFFF	/* AIF1DAC2_EQ_B1_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B1_PG_SHIFT               0	/* AIF1DAC2_EQ_B1_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B1_PG_WIDTH              16	/* AIF1DAC2_EQ_B1_PG - [15:0] */
+
+/*
+ * R1189 (0x4A5) - AIF1 DAC2 EQ Band 2 A
+ */
+#define WM8995_AIF1DAC2_EQ_B2_A_MASK            0xFFFF	/* AIF1DAC2_EQ_B2_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_A_SHIFT                0	/* AIF1DAC2_EQ_B2_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_A_WIDTH               16	/* AIF1DAC2_EQ_B2_A - [15:0] */
+
+/*
+ * R1190 (0x4A6) - AIF1 DAC2 EQ Band 2 B
+ */
+#define WM8995_AIF1DAC2_EQ_B2_B_MASK            0xFFFF	/* AIF1DAC2_EQ_B2_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_B_SHIFT                0	/* AIF1DAC2_EQ_B2_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_B_WIDTH               16	/* AIF1DAC2_EQ_B2_B - [15:0] */
+
+/*
+ * R1191 (0x4A7) - AIF1 DAC2 EQ Band 2 C
+ */
+#define WM8995_AIF1DAC2_EQ_B2_C_MASK            0xFFFF	/* AIF1DAC2_EQ_B2_C - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_C_SHIFT                0	/* AIF1DAC2_EQ_B2_C - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_C_WIDTH               16	/* AIF1DAC2_EQ_B2_C - [15:0] */
+
+/*
+ * R1192 (0x4A8) - AIF1 DAC2 EQ Band 2 PG
+ */
+#define WM8995_AIF1DAC2_EQ_B2_PG_MASK           0xFFFF	/* AIF1DAC2_EQ_B2_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_PG_SHIFT               0	/* AIF1DAC2_EQ_B2_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_PG_WIDTH              16	/* AIF1DAC2_EQ_B2_PG - [15:0] */
+
+/*
+ * R1193 (0x4A9) - AIF1 DAC2 EQ Band 3 A
+ */
+#define WM8995_AIF1DAC2_EQ_B3_A_MASK            0xFFFF	/* AIF1DAC2_EQ_B3_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_A_SHIFT                0	/* AIF1DAC2_EQ_B3_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_A_WIDTH               16	/* AIF1DAC2_EQ_B3_A - [15:0] */
+
+/*
+ * R1194 (0x4AA) - AIF1 DAC2 EQ Band 3 B
+ */
+#define WM8995_AIF1DAC2_EQ_B3_B_MASK            0xFFFF	/* AIF1DAC2_EQ_B3_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_B_SHIFT                0	/* AIF1DAC2_EQ_B3_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_B_WIDTH               16	/* AIF1DAC2_EQ_B3_B - [15:0] */
+
+/*
+ * R1195 (0x4AB) - AIF1 DAC2 EQ Band 3 C
+ */
+#define WM8995_AIF1DAC2_EQ_B3_C_MASK            0xFFFF	/* AIF1DAC2_EQ_B3_C - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_C_SHIFT                0	/* AIF1DAC2_EQ_B3_C - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_C_WIDTH               16	/* AIF1DAC2_EQ_B3_C - [15:0] */
+
+/*
+ * R1196 (0x4AC) - AIF1 DAC2 EQ Band 3 PG
+ */
+#define WM8995_AIF1DAC2_EQ_B3_PG_MASK           0xFFFF	/* AIF1DAC2_EQ_B3_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_PG_SHIFT               0	/* AIF1DAC2_EQ_B3_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_PG_WIDTH              16	/* AIF1DAC2_EQ_B3_PG - [15:0] */
+
+/*
+ * R1197 (0x4AD) - AIF1 DAC2 EQ Band 4 A
+ */
+#define WM8995_AIF1DAC2_EQ_B4_A_MASK            0xFFFF	/* AIF1DAC2_EQ_B4_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_A_SHIFT                0	/* AIF1DAC2_EQ_B4_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_A_WIDTH               16	/* AIF1DAC2_EQ_B4_A - [15:0] */
+
+/*
+ * R1198 (0x4AE) - AIF1 DAC2 EQ Band 4 B
+ */
+#define WM8995_AIF1DAC2_EQ_B4_B_MASK            0xFFFF	/* AIF1DAC2_EQ_B4_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_B_SHIFT                0	/* AIF1DAC2_EQ_B4_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_B_WIDTH               16	/* AIF1DAC2_EQ_B4_B - [15:0] */
+
+/*
+ * R1199 (0x4AF) - AIF1 DAC2 EQ Band 4 C
+ */
+#define WM8995_AIF1DAC2_EQ_B4_C_MASK            0xFFFF	/* AIF1DAC2_EQ_B4_C - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_C_SHIFT                0	/* AIF1DAC2_EQ_B4_C - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_C_WIDTH               16	/* AIF1DAC2_EQ_B4_C - [15:0] */
+
+/*
+ * R1200 (0x4B0) - AIF1 DAC2 EQ Band 4 PG
+ */
+#define WM8995_AIF1DAC2_EQ_B4_PG_MASK           0xFFFF	/* AIF1DAC2_EQ_B4_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_PG_SHIFT               0	/* AIF1DAC2_EQ_B4_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_PG_WIDTH              16	/* AIF1DAC2_EQ_B4_PG - [15:0] */
+
+/*
+ * R1201 (0x4B1) - AIF1 DAC2 EQ Band 5 A
+ */
+#define WM8995_AIF1DAC2_EQ_B5_A_MASK            0xFFFF	/* AIF1DAC2_EQ_B5_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B5_A_SHIFT                0	/* AIF1DAC2_EQ_B5_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B5_A_WIDTH               16	/* AIF1DAC2_EQ_B5_A - [15:0] */
+
+/*
+ * R1202 (0x4B2) - AIF1 DAC2 EQ Band 5 B
+ */
+#define WM8995_AIF1DAC2_EQ_B5_B_MASK            0xFFFF	/* AIF1DAC2_EQ_B5_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B5_B_SHIFT                0	/* AIF1DAC2_EQ_B5_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B5_B_WIDTH               16	/* AIF1DAC2_EQ_B5_B - [15:0] */
+
+/*
+ * R1203 (0x4B3) - AIF1 DAC2 EQ Band 5 PG
+ */
+#define WM8995_AIF1DAC2_EQ_B5_PG_MASK           0xFFFF	/* AIF1DAC2_EQ_B5_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B5_PG_SHIFT               0	/* AIF1DAC2_EQ_B5_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B5_PG_WIDTH              16	/* AIF1DAC2_EQ_B5_PG - [15:0] */
+
+/*
+ * R1280 (0x500) - AIF2 ADC Left Volume
+ */
+#define WM8995_AIF2ADC_VU                       0x0100	/* AIF2ADC_VU */
+#define WM8995_AIF2ADC_VU_MASK                  0x0100	/* AIF2ADC_VU */
+#define WM8995_AIF2ADC_VU_SHIFT                      8	/* AIF2ADC_VU */
+#define WM8995_AIF2ADC_VU_WIDTH                      1	/* AIF2ADC_VU */
+#define WM8995_AIF2ADCL_VOL_MASK                0x00FF	/* AIF2ADCL_VOL - [7:0] */
+#define WM8995_AIF2ADCL_VOL_SHIFT                    0	/* AIF2ADCL_VOL - [7:0] */
+#define WM8995_AIF2ADCL_VOL_WIDTH                    8	/* AIF2ADCL_VOL - [7:0] */
+
+/*
+ * R1281 (0x501) - AIF2 ADC Right Volume
+ */
+#define WM8995_AIF2ADC_VU                       0x0100	/* AIF2ADC_VU */
+#define WM8995_AIF2ADC_VU_MASK                  0x0100	/* AIF2ADC_VU */
+#define WM8995_AIF2ADC_VU_SHIFT                      8	/* AIF2ADC_VU */
+#define WM8995_AIF2ADC_VU_WIDTH                      1	/* AIF2ADC_VU */
+#define WM8995_AIF2ADCR_VOL_MASK                0x00FF	/* AIF2ADCR_VOL - [7:0] */
+#define WM8995_AIF2ADCR_VOL_SHIFT                    0	/* AIF2ADCR_VOL - [7:0] */
+#define WM8995_AIF2ADCR_VOL_WIDTH                    8	/* AIF2ADCR_VOL - [7:0] */
+
+/*
+ * R1282 (0x502) - AIF2 DAC Left Volume
+ */
+#define WM8995_AIF2DAC_VU                       0x0100	/* AIF2DAC_VU */
+#define WM8995_AIF2DAC_VU_MASK                  0x0100	/* AIF2DAC_VU */
+#define WM8995_AIF2DAC_VU_SHIFT                      8	/* AIF2DAC_VU */
+#define WM8995_AIF2DAC_VU_WIDTH                      1	/* AIF2DAC_VU */
+#define WM8995_AIF2DACL_VOL_MASK                0x00FF	/* AIF2DACL_VOL - [7:0] */
+#define WM8995_AIF2DACL_VOL_SHIFT                    0	/* AIF2DACL_VOL - [7:0] */
+#define WM8995_AIF2DACL_VOL_WIDTH                    8	/* AIF2DACL_VOL - [7:0] */
+
+/*
+ * R1283 (0x503) - AIF2 DAC Right Volume
+ */
+#define WM8995_AIF2DAC_VU                       0x0100	/* AIF2DAC_VU */
+#define WM8995_AIF2DAC_VU_MASK                  0x0100	/* AIF2DAC_VU */
+#define WM8995_AIF2DAC_VU_SHIFT                      8	/* AIF2DAC_VU */
+#define WM8995_AIF2DAC_VU_WIDTH                      1	/* AIF2DAC_VU */
+#define WM8995_AIF2DACR_VOL_MASK                0x00FF	/* AIF2DACR_VOL - [7:0] */
+#define WM8995_AIF2DACR_VOL_SHIFT                    0	/* AIF2DACR_VOL - [7:0] */
+#define WM8995_AIF2DACR_VOL_WIDTH                    8	/* AIF2DACR_VOL - [7:0] */
+
+/*
+ * R1296 (0x510) - AIF2 ADC Filters
+ */
+#define WM8995_AIF2ADC_4FS                      0x8000	/* AIF2ADC_4FS */
+#define WM8995_AIF2ADC_4FS_MASK                 0x8000	/* AIF2ADC_4FS */
+#define WM8995_AIF2ADC_4FS_SHIFT                    15	/* AIF2ADC_4FS */
+#define WM8995_AIF2ADC_4FS_WIDTH                     1	/* AIF2ADC_4FS */
+#define WM8995_AIF2ADCL_HPF                     0x1000	/* AIF2ADCL_HPF */
+#define WM8995_AIF2ADCL_HPF_MASK                0x1000	/* AIF2ADCL_HPF */
+#define WM8995_AIF2ADCL_HPF_SHIFT                   12	/* AIF2ADCL_HPF */
+#define WM8995_AIF2ADCL_HPF_WIDTH                    1	/* AIF2ADCL_HPF */
+#define WM8995_AIF2ADCR_HPF                     0x0800	/* AIF2ADCR_HPF */
+#define WM8995_AIF2ADCR_HPF_MASK                0x0800	/* AIF2ADCR_HPF */
+#define WM8995_AIF2ADCR_HPF_SHIFT                   11	/* AIF2ADCR_HPF */
+#define WM8995_AIF2ADCR_HPF_WIDTH                    1	/* AIF2ADCR_HPF */
+#define WM8995_AIF2ADC_HPF_MODE                 0x0008	/* AIF2ADC_HPF_MODE */
+#define WM8995_AIF2ADC_HPF_MODE_MASK            0x0008	/* AIF2ADC_HPF_MODE */
+#define WM8995_AIF2ADC_HPF_MODE_SHIFT                3	/* AIF2ADC_HPF_MODE */
+#define WM8995_AIF2ADC_HPF_MODE_WIDTH                1	/* AIF2ADC_HPF_MODE */
+#define WM8995_AIF2ADC_HPF_CUT_MASK             0x0007	/* AIF2ADC_HPF_CUT - [2:0] */
+#define WM8995_AIF2ADC_HPF_CUT_SHIFT                 0	/* AIF2ADC_HPF_CUT - [2:0] */
+#define WM8995_AIF2ADC_HPF_CUT_WIDTH                 3	/* AIF2ADC_HPF_CUT - [2:0] */
+
+/*
+ * R1312 (0x520) - AIF2 DAC Filters (1)
+ */
+#define WM8995_AIF2DAC_MUTE                     0x0200	/* AIF2DAC_MUTE */
+#define WM8995_AIF2DAC_MUTE_MASK                0x0200	/* AIF2DAC_MUTE */
+#define WM8995_AIF2DAC_MUTE_SHIFT                    9	/* AIF2DAC_MUTE */
+#define WM8995_AIF2DAC_MUTE_WIDTH                    1	/* AIF2DAC_MUTE */
+#define WM8995_AIF2DAC_MONO                     0x0080	/* AIF2DAC_MONO */
+#define WM8995_AIF2DAC_MONO_MASK                0x0080	/* AIF2DAC_MONO */
+#define WM8995_AIF2DAC_MONO_SHIFT                    7	/* AIF2DAC_MONO */
+#define WM8995_AIF2DAC_MONO_WIDTH                    1	/* AIF2DAC_MONO */
+#define WM8995_AIF2DAC_MUTERATE                 0x0020	/* AIF2DAC_MUTERATE */
+#define WM8995_AIF2DAC_MUTERATE_MASK            0x0020	/* AIF2DAC_MUTERATE */
+#define WM8995_AIF2DAC_MUTERATE_SHIFT                5	/* AIF2DAC_MUTERATE */
+#define WM8995_AIF2DAC_MUTERATE_WIDTH                1	/* AIF2DAC_MUTERATE */
+#define WM8995_AIF2DAC_UNMUTE_RAMP              0x0010	/* AIF2DAC_UNMUTE_RAMP */
+#define WM8995_AIF2DAC_UNMUTE_RAMP_MASK         0x0010	/* AIF2DAC_UNMUTE_RAMP */
+#define WM8995_AIF2DAC_UNMUTE_RAMP_SHIFT             4	/* AIF2DAC_UNMUTE_RAMP */
+#define WM8995_AIF2DAC_UNMUTE_RAMP_WIDTH             1	/* AIF2DAC_UNMUTE_RAMP */
+#define WM8995_AIF2DAC_DEEMP_MASK               0x0006	/* AIF2DAC_DEEMP - [2:1] */
+#define WM8995_AIF2DAC_DEEMP_SHIFT                   1	/* AIF2DAC_DEEMP - [2:1] */
+#define WM8995_AIF2DAC_DEEMP_WIDTH                   2	/* AIF2DAC_DEEMP - [2:1] */
+
+/*
+ * R1313 (0x521) - AIF2 DAC Filters (2)
+ */
+#define WM8995_AIF2DAC_3D_GAIN_MASK             0x3E00	/* AIF2DAC_3D_GAIN - [13:9] */
+#define WM8995_AIF2DAC_3D_GAIN_SHIFT                 9	/* AIF2DAC_3D_GAIN - [13:9] */
+#define WM8995_AIF2DAC_3D_GAIN_WIDTH                 5	/* AIF2DAC_3D_GAIN - [13:9] */
+#define WM8995_AIF2DAC_3D_ENA                   0x0100	/* AIF2DAC_3D_ENA */
+#define WM8995_AIF2DAC_3D_ENA_MASK              0x0100	/* AIF2DAC_3D_ENA */
+#define WM8995_AIF2DAC_3D_ENA_SHIFT                  8	/* AIF2DAC_3D_ENA */
+#define WM8995_AIF2DAC_3D_ENA_WIDTH                  1	/* AIF2DAC_3D_ENA */
+
+/*
+ * R1344 (0x540) - AIF2 DRC (1)
+ */
+#define WM8995_AIF2DRC_SIG_DET_RMS_MASK         0xF800	/* AIF2DRC_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF2DRC_SIG_DET_RMS_SHIFT            11	/* AIF2DRC_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF2DRC_SIG_DET_RMS_WIDTH             5	/* AIF2DRC_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF2DRC_SIG_DET_PK_MASK          0x0600	/* AIF2DRC_SIG_DET_PK - [10:9] */
+#define WM8995_AIF2DRC_SIG_DET_PK_SHIFT              9	/* AIF2DRC_SIG_DET_PK - [10:9] */
+#define WM8995_AIF2DRC_SIG_DET_PK_WIDTH              2	/* AIF2DRC_SIG_DET_PK - [10:9] */
+#define WM8995_AIF2DRC_NG_ENA                   0x0100	/* AIF2DRC_NG_ENA */
+#define WM8995_AIF2DRC_NG_ENA_MASK              0x0100	/* AIF2DRC_NG_ENA */
+#define WM8995_AIF2DRC_NG_ENA_SHIFT                  8	/* AIF2DRC_NG_ENA */
+#define WM8995_AIF2DRC_NG_ENA_WIDTH                  1	/* AIF2DRC_NG_ENA */
+#define WM8995_AIF2DRC_SIG_DET_MODE             0x0080	/* AIF2DRC_SIG_DET_MODE */
+#define WM8995_AIF2DRC_SIG_DET_MODE_MASK        0x0080	/* AIF2DRC_SIG_DET_MODE */
+#define WM8995_AIF2DRC_SIG_DET_MODE_SHIFT            7	/* AIF2DRC_SIG_DET_MODE */
+#define WM8995_AIF2DRC_SIG_DET_MODE_WIDTH            1	/* AIF2DRC_SIG_DET_MODE */
+#define WM8995_AIF2DRC_SIG_DET                  0x0040	/* AIF2DRC_SIG_DET */
+#define WM8995_AIF2DRC_SIG_DET_MASK             0x0040	/* AIF2DRC_SIG_DET */
+#define WM8995_AIF2DRC_SIG_DET_SHIFT                 6	/* AIF2DRC_SIG_DET */
+#define WM8995_AIF2DRC_SIG_DET_WIDTH                 1	/* AIF2DRC_SIG_DET */
+#define WM8995_AIF2DRC_KNEE2_OP_ENA             0x0020	/* AIF2DRC_KNEE2_OP_ENA */
+#define WM8995_AIF2DRC_KNEE2_OP_ENA_MASK        0x0020	/* AIF2DRC_KNEE2_OP_ENA */
+#define WM8995_AIF2DRC_KNEE2_OP_ENA_SHIFT            5	/* AIF2DRC_KNEE2_OP_ENA */
+#define WM8995_AIF2DRC_KNEE2_OP_ENA_WIDTH            1	/* AIF2DRC_KNEE2_OP_ENA */
+#define WM8995_AIF2DRC_QR                       0x0010	/* AIF2DRC_QR */
+#define WM8995_AIF2DRC_QR_MASK                  0x0010	/* AIF2DRC_QR */
+#define WM8995_AIF2DRC_QR_SHIFT                      4	/* AIF2DRC_QR */
+#define WM8995_AIF2DRC_QR_WIDTH                      1	/* AIF2DRC_QR */
+#define WM8995_AIF2DRC_ANTICLIP                 0x0008	/* AIF2DRC_ANTICLIP */
+#define WM8995_AIF2DRC_ANTICLIP_MASK            0x0008	/* AIF2DRC_ANTICLIP */
+#define WM8995_AIF2DRC_ANTICLIP_SHIFT                3	/* AIF2DRC_ANTICLIP */
+#define WM8995_AIF2DRC_ANTICLIP_WIDTH                1	/* AIF2DRC_ANTICLIP */
+#define WM8995_AIF2DAC_DRC_ENA                  0x0004	/* AIF2DAC_DRC_ENA */
+#define WM8995_AIF2DAC_DRC_ENA_MASK             0x0004	/* AIF2DAC_DRC_ENA */
+#define WM8995_AIF2DAC_DRC_ENA_SHIFT                 2	/* AIF2DAC_DRC_ENA */
+#define WM8995_AIF2DAC_DRC_ENA_WIDTH                 1	/* AIF2DAC_DRC_ENA */
+#define WM8995_AIF2ADCL_DRC_ENA                 0x0002	/* AIF2ADCL_DRC_ENA */
+#define WM8995_AIF2ADCL_DRC_ENA_MASK            0x0002	/* AIF2ADCL_DRC_ENA */
+#define WM8995_AIF2ADCL_DRC_ENA_SHIFT                1	/* AIF2ADCL_DRC_ENA */
+#define WM8995_AIF2ADCL_DRC_ENA_WIDTH                1	/* AIF2ADCL_DRC_ENA */
+#define WM8995_AIF2ADCR_DRC_ENA                 0x0001	/* AIF2ADCR_DRC_ENA */
+#define WM8995_AIF2ADCR_DRC_ENA_MASK            0x0001	/* AIF2ADCR_DRC_ENA */
+#define WM8995_AIF2ADCR_DRC_ENA_SHIFT                0	/* AIF2ADCR_DRC_ENA */
+#define WM8995_AIF2ADCR_DRC_ENA_WIDTH                1	/* AIF2ADCR_DRC_ENA */
+
+/*
+ * R1345 (0x541) - AIF2 DRC (2)
+ */
+#define WM8995_AIF2DRC_ATK_MASK                 0x1E00	/* AIF2DRC_ATK - [12:9] */
+#define WM8995_AIF2DRC_ATK_SHIFT                     9	/* AIF2DRC_ATK - [12:9] */
+#define WM8995_AIF2DRC_ATK_WIDTH                     4	/* AIF2DRC_ATK - [12:9] */
+#define WM8995_AIF2DRC_DCY_MASK                 0x01E0	/* AIF2DRC_DCY - [8:5] */
+#define WM8995_AIF2DRC_DCY_SHIFT                     5	/* AIF2DRC_DCY - [8:5] */
+#define WM8995_AIF2DRC_DCY_WIDTH                     4	/* AIF2DRC_DCY - [8:5] */
+#define WM8995_AIF2DRC_MINGAIN_MASK             0x001C	/* AIF2DRC_MINGAIN - [4:2] */
+#define WM8995_AIF2DRC_MINGAIN_SHIFT                 2	/* AIF2DRC_MINGAIN - [4:2] */
+#define WM8995_AIF2DRC_MINGAIN_WIDTH                 3	/* AIF2DRC_MINGAIN - [4:2] */
+#define WM8995_AIF2DRC_MAXGAIN_MASK             0x0003	/* AIF2DRC_MAXGAIN - [1:0] */
+#define WM8995_AIF2DRC_MAXGAIN_SHIFT                 0	/* AIF2DRC_MAXGAIN - [1:0] */
+#define WM8995_AIF2DRC_MAXGAIN_WIDTH                 2	/* AIF2DRC_MAXGAIN - [1:0] */
+
+/*
+ * R1346 (0x542) - AIF2 DRC (3)
+ */
+#define WM8995_AIF2DRC_NG_MINGAIN_MASK          0xF000	/* AIF2DRC_NG_MINGAIN - [15:12] */
+#define WM8995_AIF2DRC_NG_MINGAIN_SHIFT             12	/* AIF2DRC_NG_MINGAIN - [15:12] */
+#define WM8995_AIF2DRC_NG_MINGAIN_WIDTH              4	/* AIF2DRC_NG_MINGAIN - [15:12] */
+#define WM8995_AIF2DRC_NG_EXP_MASK              0x0C00	/* AIF2DRC_NG_EXP - [11:10] */
+#define WM8995_AIF2DRC_NG_EXP_SHIFT                 10	/* AIF2DRC_NG_EXP - [11:10] */
+#define WM8995_AIF2DRC_NG_EXP_WIDTH                  2	/* AIF2DRC_NG_EXP - [11:10] */
+#define WM8995_AIF2DRC_QR_THR_MASK              0x0300	/* AIF2DRC_QR_THR - [9:8] */
+#define WM8995_AIF2DRC_QR_THR_SHIFT                  8	/* AIF2DRC_QR_THR - [9:8] */
+#define WM8995_AIF2DRC_QR_THR_WIDTH                  2	/* AIF2DRC_QR_THR - [9:8] */
+#define WM8995_AIF2DRC_QR_DCY_MASK              0x00C0	/* AIF2DRC_QR_DCY - [7:6] */
+#define WM8995_AIF2DRC_QR_DCY_SHIFT                  6	/* AIF2DRC_QR_DCY - [7:6] */
+#define WM8995_AIF2DRC_QR_DCY_WIDTH                  2	/* AIF2DRC_QR_DCY - [7:6] */
+#define WM8995_AIF2DRC_HI_COMP_MASK             0x0038	/* AIF2DRC_HI_COMP - [5:3] */
+#define WM8995_AIF2DRC_HI_COMP_SHIFT                 3	/* AIF2DRC_HI_COMP - [5:3] */
+#define WM8995_AIF2DRC_HI_COMP_WIDTH                 3	/* AIF2DRC_HI_COMP - [5:3] */
+#define WM8995_AIF2DRC_LO_COMP_MASK             0x0007	/* AIF2DRC_LO_COMP - [2:0] */
+#define WM8995_AIF2DRC_LO_COMP_SHIFT                 0	/* AIF2DRC_LO_COMP - [2:0] */
+#define WM8995_AIF2DRC_LO_COMP_WIDTH                 3	/* AIF2DRC_LO_COMP - [2:0] */
+
+/*
+ * R1347 (0x543) - AIF2 DRC (4)
+ */
+#define WM8995_AIF2DRC_KNEE_IP_MASK             0x07E0	/* AIF2DRC_KNEE_IP - [10:5] */
+#define WM8995_AIF2DRC_KNEE_IP_SHIFT                 5	/* AIF2DRC_KNEE_IP - [10:5] */
+#define WM8995_AIF2DRC_KNEE_IP_WIDTH                 6	/* AIF2DRC_KNEE_IP - [10:5] */
+#define WM8995_AIF2DRC_KNEE_OP_MASK             0x001F	/* AIF2DRC_KNEE_OP - [4:0] */
+#define WM8995_AIF2DRC_KNEE_OP_SHIFT                 0	/* AIF2DRC_KNEE_OP - [4:0] */
+#define WM8995_AIF2DRC_KNEE_OP_WIDTH                 5	/* AIF2DRC_KNEE_OP - [4:0] */
+
+/*
+ * R1348 (0x544) - AIF2 DRC (5)
+ */
+#define WM8995_AIF2DRC_KNEE2_IP_MASK            0x03E0	/* AIF2DRC_KNEE2_IP - [9:5] */
+#define WM8995_AIF2DRC_KNEE2_IP_SHIFT                5	/* AIF2DRC_KNEE2_IP - [9:5] */
+#define WM8995_AIF2DRC_KNEE2_IP_WIDTH                5	/* AIF2DRC_KNEE2_IP - [9:5] */
+#define WM8995_AIF2DRC_KNEE2_OP_MASK            0x001F	/* AIF2DRC_KNEE2_OP - [4:0] */
+#define WM8995_AIF2DRC_KNEE2_OP_SHIFT                0	/* AIF2DRC_KNEE2_OP - [4:0] */
+#define WM8995_AIF2DRC_KNEE2_OP_WIDTH                5	/* AIF2DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R1408 (0x580) - AIF2 EQ Gains (1)
+ */
+#define WM8995_AIF2DAC_EQ_B1_GAIN_MASK          0xF800	/* AIF2DAC_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF2DAC_EQ_B1_GAIN_SHIFT             11	/* AIF2DAC_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF2DAC_EQ_B1_GAIN_WIDTH              5	/* AIF2DAC_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF2DAC_EQ_B2_GAIN_MASK          0x07C0	/* AIF2DAC_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF2DAC_EQ_B2_GAIN_SHIFT              6	/* AIF2DAC_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF2DAC_EQ_B2_GAIN_WIDTH              5	/* AIF2DAC_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF2DAC_EQ_B3_GAIN_MASK          0x003E	/* AIF2DAC_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF2DAC_EQ_B3_GAIN_SHIFT              1	/* AIF2DAC_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF2DAC_EQ_B3_GAIN_WIDTH              5	/* AIF2DAC_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF2DAC_EQ_ENA                   0x0001	/* AIF2DAC_EQ_ENA */
+#define WM8995_AIF2DAC_EQ_ENA_MASK              0x0001	/* AIF2DAC_EQ_ENA */
+#define WM8995_AIF2DAC_EQ_ENA_SHIFT                  0	/* AIF2DAC_EQ_ENA */
+#define WM8995_AIF2DAC_EQ_ENA_WIDTH                  1	/* AIF2DAC_EQ_ENA */
+
+/*
+ * R1409 (0x581) - AIF2 EQ Gains (2)
+ */
+#define WM8995_AIF2DAC_EQ_B4_GAIN_MASK          0xF800	/* AIF2DAC_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF2DAC_EQ_B4_GAIN_SHIFT             11	/* AIF2DAC_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF2DAC_EQ_B4_GAIN_WIDTH              5	/* AIF2DAC_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF2DAC_EQ_B5_GAIN_MASK          0x07C0	/* AIF2DAC_EQ_B5_GAIN - [10:6] */
+#define WM8995_AIF2DAC_EQ_B5_GAIN_SHIFT              6	/* AIF2DAC_EQ_B5_GAIN - [10:6] */
+#define WM8995_AIF2DAC_EQ_B5_GAIN_WIDTH              5	/* AIF2DAC_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1410 (0x582) - AIF2 EQ Band 1 A
+ */
+#define WM8995_AIF2DAC_EQ_B1_A_MASK             0xFFFF	/* AIF2DAC_EQ_B1_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B1_A_SHIFT                 0	/* AIF2DAC_EQ_B1_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B1_A_WIDTH                16	/* AIF2DAC_EQ_B1_A - [15:0] */
+
+/*
+ * R1411 (0x583) - AIF2 EQ Band 1 B
+ */
+#define WM8995_AIF2DAC_EQ_B1_B_MASK             0xFFFF	/* AIF2DAC_EQ_B1_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B1_B_SHIFT                 0	/* AIF2DAC_EQ_B1_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B1_B_WIDTH                16	/* AIF2DAC_EQ_B1_B - [15:0] */
+
+/*
+ * R1412 (0x584) - AIF2 EQ Band 1 PG
+ */
+#define WM8995_AIF2DAC_EQ_B1_PG_MASK            0xFFFF	/* AIF2DAC_EQ_B1_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B1_PG_SHIFT                0	/* AIF2DAC_EQ_B1_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B1_PG_WIDTH               16	/* AIF2DAC_EQ_B1_PG - [15:0] */
+
+/*
+ * R1413 (0x585) - AIF2 EQ Band 2 A
+ */
+#define WM8995_AIF2DAC_EQ_B2_A_MASK             0xFFFF	/* AIF2DAC_EQ_B2_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_A_SHIFT                 0	/* AIF2DAC_EQ_B2_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_A_WIDTH                16	/* AIF2DAC_EQ_B2_A - [15:0] */
+
+/*
+ * R1414 (0x586) - AIF2 EQ Band 2 B
+ */
+#define WM8995_AIF2DAC_EQ_B2_B_MASK             0xFFFF	/* AIF2DAC_EQ_B2_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_B_SHIFT                 0	/* AIF2DAC_EQ_B2_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_B_WIDTH                16	/* AIF2DAC_EQ_B2_B - [15:0] */
+
+/*
+ * R1415 (0x587) - AIF2 EQ Band 2 C
+ */
+#define WM8995_AIF2DAC_EQ_B2_C_MASK             0xFFFF	/* AIF2DAC_EQ_B2_C - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_C_SHIFT                 0	/* AIF2DAC_EQ_B2_C - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_C_WIDTH                16	/* AIF2DAC_EQ_B2_C - [15:0] */
+
+/*
+ * R1416 (0x588) - AIF2 EQ Band 2 PG
+ */
+#define WM8995_AIF2DAC_EQ_B2_PG_MASK            0xFFFF	/* AIF2DAC_EQ_B2_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_PG_SHIFT                0	/* AIF2DAC_EQ_B2_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_PG_WIDTH               16	/* AIF2DAC_EQ_B2_PG - [15:0] */
+
+/*
+ * R1417 (0x589) - AIF2 EQ Band 3 A
+ */
+#define WM8995_AIF2DAC_EQ_B3_A_MASK             0xFFFF	/* AIF2DAC_EQ_B3_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_A_SHIFT                 0	/* AIF2DAC_EQ_B3_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_A_WIDTH                16	/* AIF2DAC_EQ_B3_A - [15:0] */
+
+/*
+ * R1418 (0x58A) - AIF2 EQ Band 3 B
+ */
+#define WM8995_AIF2DAC_EQ_B3_B_MASK             0xFFFF	/* AIF2DAC_EQ_B3_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_B_SHIFT                 0	/* AIF2DAC_EQ_B3_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_B_WIDTH                16	/* AIF2DAC_EQ_B3_B - [15:0] */
+
+/*
+ * R1419 (0x58B) - AIF2 EQ Band 3 C
+ */
+#define WM8995_AIF2DAC_EQ_B3_C_MASK             0xFFFF	/* AIF2DAC_EQ_B3_C - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_C_SHIFT                 0	/* AIF2DAC_EQ_B3_C - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_C_WIDTH                16	/* AIF2DAC_EQ_B3_C - [15:0] */
+
+/*
+ * R1420 (0x58C) - AIF2 EQ Band 3 PG
+ */
+#define WM8995_AIF2DAC_EQ_B3_PG_MASK            0xFFFF	/* AIF2DAC_EQ_B3_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_PG_SHIFT                0	/* AIF2DAC_EQ_B3_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_PG_WIDTH               16	/* AIF2DAC_EQ_B3_PG - [15:0] */
+
+/*
+ * R1421 (0x58D) - AIF2 EQ Band 4 A
+ */
+#define WM8995_AIF2DAC_EQ_B4_A_MASK             0xFFFF	/* AIF2DAC_EQ_B4_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_A_SHIFT                 0	/* AIF2DAC_EQ_B4_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_A_WIDTH                16	/* AIF2DAC_EQ_B4_A - [15:0] */
+
+/*
+ * R1422 (0x58E) - AIF2 EQ Band 4 B
+ */
+#define WM8995_AIF2DAC_EQ_B4_B_MASK             0xFFFF	/* AIF2DAC_EQ_B4_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_B_SHIFT                 0	/* AIF2DAC_EQ_B4_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_B_WIDTH                16	/* AIF2DAC_EQ_B4_B - [15:0] */
+
+/*
+ * R1423 (0x58F) - AIF2 EQ Band 4 C
+ */
+#define WM8995_AIF2DAC_EQ_B4_C_MASK             0xFFFF	/* AIF2DAC_EQ_B4_C - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_C_SHIFT                 0	/* AIF2DAC_EQ_B4_C - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_C_WIDTH                16	/* AIF2DAC_EQ_B4_C - [15:0] */
+
+/*
+ * R1424 (0x590) - AIF2 EQ Band 4 PG
+ */
+#define WM8995_AIF2DAC_EQ_B4_PG_MASK            0xFFFF	/* AIF2DAC_EQ_B4_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_PG_SHIFT                0	/* AIF2DAC_EQ_B4_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_PG_WIDTH               16	/* AIF2DAC_EQ_B4_PG - [15:0] */
+
+/*
+ * R1425 (0x591) - AIF2 EQ Band 5 A
+ */
+#define WM8995_AIF2DAC_EQ_B5_A_MASK             0xFFFF	/* AIF2DAC_EQ_B5_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B5_A_SHIFT                 0	/* AIF2DAC_EQ_B5_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B5_A_WIDTH                16	/* AIF2DAC_EQ_B5_A - [15:0] */
+
+/*
+ * R1426 (0x592) - AIF2 EQ Band 5 B
+ */
+#define WM8995_AIF2DAC_EQ_B5_B_MASK             0xFFFF	/* AIF2DAC_EQ_B5_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B5_B_SHIFT                 0	/* AIF2DAC_EQ_B5_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B5_B_WIDTH                16	/* AIF2DAC_EQ_B5_B - [15:0] */
+
+/*
+ * R1427 (0x593) - AIF2 EQ Band 5 PG
+ */
+#define WM8995_AIF2DAC_EQ_B5_PG_MASK            0xFFFF	/* AIF2DAC_EQ_B5_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B5_PG_SHIFT                0	/* AIF2DAC_EQ_B5_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B5_PG_WIDTH               16	/* AIF2DAC_EQ_B5_PG - [15:0] */
+
+/*
+ * R1536 (0x600) - DAC1 Mixer Volumes
+ */
+#define WM8995_ADCR_DAC1_VOL_MASK               0x03E0	/* ADCR_DAC1_VOL - [9:5] */
+#define WM8995_ADCR_DAC1_VOL_SHIFT                   5	/* ADCR_DAC1_VOL - [9:5] */
+#define WM8995_ADCR_DAC1_VOL_WIDTH                   5	/* ADCR_DAC1_VOL - [9:5] */
+#define WM8995_ADCL_DAC1_VOL_MASK               0x001F	/* ADCL_DAC1_VOL - [4:0] */
+#define WM8995_ADCL_DAC1_VOL_SHIFT                   0	/* ADCL_DAC1_VOL - [4:0] */
+#define WM8995_ADCL_DAC1_VOL_WIDTH                   5	/* ADCL_DAC1_VOL - [4:0] */
+
+/*
+ * R1537 (0x601) - DAC1 Left Mixer Routing
+ */
+#define WM8995_ADCR_TO_DAC1L                    0x0020	/* ADCR_TO_DAC1L */
+#define WM8995_ADCR_TO_DAC1L_MASK               0x0020	/* ADCR_TO_DAC1L */
+#define WM8995_ADCR_TO_DAC1L_SHIFT                   5	/* ADCR_TO_DAC1L */
+#define WM8995_ADCR_TO_DAC1L_WIDTH                   1	/* ADCR_TO_DAC1L */
+#define WM8995_ADCL_TO_DAC1L                    0x0010	/* ADCL_TO_DAC1L */
+#define WM8995_ADCL_TO_DAC1L_MASK               0x0010	/* ADCL_TO_DAC1L */
+#define WM8995_ADCL_TO_DAC1L_SHIFT                   4	/* ADCL_TO_DAC1L */
+#define WM8995_ADCL_TO_DAC1L_WIDTH                   1	/* ADCL_TO_DAC1L */
+#define WM8995_AIF2DACL_TO_DAC1L                0x0004	/* AIF2DACL_TO_DAC1L */
+#define WM8995_AIF2DACL_TO_DAC1L_MASK           0x0004	/* AIF2DACL_TO_DAC1L */
+#define WM8995_AIF2DACL_TO_DAC1L_SHIFT               2	/* AIF2DACL_TO_DAC1L */
+#define WM8995_AIF2DACL_TO_DAC1L_WIDTH               1	/* AIF2DACL_TO_DAC1L */
+#define WM8995_AIF1DAC2L_TO_DAC1L               0x0002	/* AIF1DAC2L_TO_DAC1L */
+#define WM8995_AIF1DAC2L_TO_DAC1L_MASK          0x0002	/* AIF1DAC2L_TO_DAC1L */
+#define WM8995_AIF1DAC2L_TO_DAC1L_SHIFT              1	/* AIF1DAC2L_TO_DAC1L */
+#define WM8995_AIF1DAC2L_TO_DAC1L_WIDTH              1	/* AIF1DAC2L_TO_DAC1L */
+#define WM8995_AIF1DAC1L_TO_DAC1L               0x0001	/* AIF1DAC1L_TO_DAC1L */
+#define WM8995_AIF1DAC1L_TO_DAC1L_MASK          0x0001	/* AIF1DAC1L_TO_DAC1L */
+#define WM8995_AIF1DAC1L_TO_DAC1L_SHIFT              0	/* AIF1DAC1L_TO_DAC1L */
+#define WM8995_AIF1DAC1L_TO_DAC1L_WIDTH              1	/* AIF1DAC1L_TO_DAC1L */
+
+/*
+ * R1538 (0x602) - DAC1 Right Mixer Routing
+ */
+#define WM8995_ADCR_TO_DAC1R                    0x0020	/* ADCR_TO_DAC1R */
+#define WM8995_ADCR_TO_DAC1R_MASK               0x0020	/* ADCR_TO_DAC1R */
+#define WM8995_ADCR_TO_DAC1R_SHIFT                   5	/* ADCR_TO_DAC1R */
+#define WM8995_ADCR_TO_DAC1R_WIDTH                   1	/* ADCR_TO_DAC1R */
+#define WM8995_ADCL_TO_DAC1R                    0x0010	/* ADCL_TO_DAC1R */
+#define WM8995_ADCL_TO_DAC1R_MASK               0x0010	/* ADCL_TO_DAC1R */
+#define WM8995_ADCL_TO_DAC1R_SHIFT                   4	/* ADCL_TO_DAC1R */
+#define WM8995_ADCL_TO_DAC1R_WIDTH                   1	/* ADCL_TO_DAC1R */
+#define WM8995_AIF2DACR_TO_DAC1R                0x0004	/* AIF2DACR_TO_DAC1R */
+#define WM8995_AIF2DACR_TO_DAC1R_MASK           0x0004	/* AIF2DACR_TO_DAC1R */
+#define WM8995_AIF2DACR_TO_DAC1R_SHIFT               2	/* AIF2DACR_TO_DAC1R */
+#define WM8995_AIF2DACR_TO_DAC1R_WIDTH               1	/* AIF2DACR_TO_DAC1R */
+#define WM8995_AIF1DAC2R_TO_DAC1R               0x0002	/* AIF1DAC2R_TO_DAC1R */
+#define WM8995_AIF1DAC2R_TO_DAC1R_MASK          0x0002	/* AIF1DAC2R_TO_DAC1R */
+#define WM8995_AIF1DAC2R_TO_DAC1R_SHIFT              1	/* AIF1DAC2R_TO_DAC1R */
+#define WM8995_AIF1DAC2R_TO_DAC1R_WIDTH              1	/* AIF1DAC2R_TO_DAC1R */
+#define WM8995_AIF1DAC1R_TO_DAC1R               0x0001	/* AIF1DAC1R_TO_DAC1R */
+#define WM8995_AIF1DAC1R_TO_DAC1R_MASK          0x0001	/* AIF1DAC1R_TO_DAC1R */
+#define WM8995_AIF1DAC1R_TO_DAC1R_SHIFT              0	/* AIF1DAC1R_TO_DAC1R */
+#define WM8995_AIF1DAC1R_TO_DAC1R_WIDTH              1	/* AIF1DAC1R_TO_DAC1R */
+
+/*
+ * R1539 (0x603) - DAC2 Mixer Volumes
+ */
+#define WM8995_ADCR_DAC2_VOL_MASK               0x03E0	/* ADCR_DAC2_VOL - [9:5] */
+#define WM8995_ADCR_DAC2_VOL_SHIFT                   5	/* ADCR_DAC2_VOL - [9:5] */
+#define WM8995_ADCR_DAC2_VOL_WIDTH                   5	/* ADCR_DAC2_VOL - [9:5] */
+#define WM8995_ADCL_DAC2_VOL_MASK               0x001F	/* ADCL_DAC2_VOL - [4:0] */
+#define WM8995_ADCL_DAC2_VOL_SHIFT                   0	/* ADCL_DAC2_VOL - [4:0] */
+#define WM8995_ADCL_DAC2_VOL_WIDTH                   5	/* ADCL_DAC2_VOL - [4:0] */
+
+/*
+ * R1540 (0x604) - DAC2 Left Mixer Routing
+ */
+#define WM8995_ADCR_TO_DAC2L                    0x0020	/* ADCR_TO_DAC2L */
+#define WM8995_ADCR_TO_DAC2L_MASK               0x0020	/* ADCR_TO_DAC2L */
+#define WM8995_ADCR_TO_DAC2L_SHIFT                   5	/* ADCR_TO_DAC2L */
+#define WM8995_ADCR_TO_DAC2L_WIDTH                   1	/* ADCR_TO_DAC2L */
+#define WM8995_ADCL_TO_DAC2L                    0x0010	/* ADCL_TO_DAC2L */
+#define WM8995_ADCL_TO_DAC2L_MASK               0x0010	/* ADCL_TO_DAC2L */
+#define WM8995_ADCL_TO_DAC2L_SHIFT                   4	/* ADCL_TO_DAC2L */
+#define WM8995_ADCL_TO_DAC2L_WIDTH                   1	/* ADCL_TO_DAC2L */
+#define WM8995_AIF2DACL_TO_DAC2L                0x0004	/* AIF2DACL_TO_DAC2L */
+#define WM8995_AIF2DACL_TO_DAC2L_MASK           0x0004	/* AIF2DACL_TO_DAC2L */
+#define WM8995_AIF2DACL_TO_DAC2L_SHIFT               2	/* AIF2DACL_TO_DAC2L */
+#define WM8995_AIF2DACL_TO_DAC2L_WIDTH               1	/* AIF2DACL_TO_DAC2L */
+#define WM8995_AIF1DAC2L_TO_DAC2L               0x0002	/* AIF1DAC2L_TO_DAC2L */
+#define WM8995_AIF1DAC2L_TO_DAC2L_MASK          0x0002	/* AIF1DAC2L_TO_DAC2L */
+#define WM8995_AIF1DAC2L_TO_DAC2L_SHIFT              1	/* AIF1DAC2L_TO_DAC2L */
+#define WM8995_AIF1DAC2L_TO_DAC2L_WIDTH              1	/* AIF1DAC2L_TO_DAC2L */
+#define WM8995_AIF1DAC1L_TO_DAC2L               0x0001	/* AIF1DAC1L_TO_DAC2L */
+#define WM8995_AIF1DAC1L_TO_DAC2L_MASK          0x0001	/* AIF1DAC1L_TO_DAC2L */
+#define WM8995_AIF1DAC1L_TO_DAC2L_SHIFT              0	/* AIF1DAC1L_TO_DAC2L */
+#define WM8995_AIF1DAC1L_TO_DAC2L_WIDTH              1	/* AIF1DAC1L_TO_DAC2L */
+
+/*
+ * R1541 (0x605) - DAC2 Right Mixer Routing
+ */
+#define WM8995_ADCR_TO_DAC2R                    0x0020	/* ADCR_TO_DAC2R */
+#define WM8995_ADCR_TO_DAC2R_MASK               0x0020	/* ADCR_TO_DAC2R */
+#define WM8995_ADCR_TO_DAC2R_SHIFT                   5	/* ADCR_TO_DAC2R */
+#define WM8995_ADCR_TO_DAC2R_WIDTH                   1	/* ADCR_TO_DAC2R */
+#define WM8995_ADCL_TO_DAC2R                    0x0010	/* ADCL_TO_DAC2R */
+#define WM8995_ADCL_TO_DAC2R_MASK               0x0010	/* ADCL_TO_DAC2R */
+#define WM8995_ADCL_TO_DAC2R_SHIFT                   4	/* ADCL_TO_DAC2R */
+#define WM8995_ADCL_TO_DAC2R_WIDTH                   1	/* ADCL_TO_DAC2R */
+#define WM8995_AIF2DACR_TO_DAC2R                0x0004	/* AIF2DACR_TO_DAC2R */
+#define WM8995_AIF2DACR_TO_DAC2R_MASK           0x0004	/* AIF2DACR_TO_DAC2R */
+#define WM8995_AIF2DACR_TO_DAC2R_SHIFT               2	/* AIF2DACR_TO_DAC2R */
+#define WM8995_AIF2DACR_TO_DAC2R_WIDTH               1	/* AIF2DACR_TO_DAC2R */
+#define WM8995_AIF1DAC2R_TO_DAC2R               0x0002	/* AIF1DAC2R_TO_DAC2R */
+#define WM8995_AIF1DAC2R_TO_DAC2R_MASK          0x0002	/* AIF1DAC2R_TO_DAC2R */
+#define WM8995_AIF1DAC2R_TO_DAC2R_SHIFT              1	/* AIF1DAC2R_TO_DAC2R */
+#define WM8995_AIF1DAC2R_TO_DAC2R_WIDTH              1	/* AIF1DAC2R_TO_DAC2R */
+#define WM8995_AIF1DAC1R_TO_DAC2R               0x0001	/* AIF1DAC1R_TO_DAC2R */
+#define WM8995_AIF1DAC1R_TO_DAC2R_MASK          0x0001	/* AIF1DAC1R_TO_DAC2R */
+#define WM8995_AIF1DAC1R_TO_DAC2R_SHIFT              0	/* AIF1DAC1R_TO_DAC2R */
+#define WM8995_AIF1DAC1R_TO_DAC2R_WIDTH              1	/* AIF1DAC1R_TO_DAC2R */
+
+/*
+ * R1542 (0x606) - AIF1 ADC1 Left Mixer Routing
+ */
+#define WM8995_ADC1L_TO_AIF1ADC1L               0x0002	/* ADC1L_TO_AIF1ADC1L */
+#define WM8995_ADC1L_TO_AIF1ADC1L_MASK          0x0002	/* ADC1L_TO_AIF1ADC1L */
+#define WM8995_ADC1L_TO_AIF1ADC1L_SHIFT              1	/* ADC1L_TO_AIF1ADC1L */
+#define WM8995_ADC1L_TO_AIF1ADC1L_WIDTH              1	/* ADC1L_TO_AIF1ADC1L */
+#define WM8995_AIF2DACL_TO_AIF1ADC1L            0x0001	/* AIF2DACL_TO_AIF1ADC1L */
+#define WM8995_AIF2DACL_TO_AIF1ADC1L_MASK       0x0001	/* AIF2DACL_TO_AIF1ADC1L */
+#define WM8995_AIF2DACL_TO_AIF1ADC1L_SHIFT           0	/* AIF2DACL_TO_AIF1ADC1L */
+#define WM8995_AIF2DACL_TO_AIF1ADC1L_WIDTH           1	/* AIF2DACL_TO_AIF1ADC1L */
+
+/*
+ * R1543 (0x607) - AIF1 ADC1 Right Mixer Routing
+ */
+#define WM8995_ADC1R_TO_AIF1ADC1R               0x0002	/* ADC1R_TO_AIF1ADC1R */
+#define WM8995_ADC1R_TO_AIF1ADC1R_MASK          0x0002	/* ADC1R_TO_AIF1ADC1R */
+#define WM8995_ADC1R_TO_AIF1ADC1R_SHIFT              1	/* ADC1R_TO_AIF1ADC1R */
+#define WM8995_ADC1R_TO_AIF1ADC1R_WIDTH              1	/* ADC1R_TO_AIF1ADC1R */
+#define WM8995_AIF2DACR_TO_AIF1ADC1R            0x0001	/* AIF2DACR_TO_AIF1ADC1R */
+#define WM8995_AIF2DACR_TO_AIF1ADC1R_MASK       0x0001	/* AIF2DACR_TO_AIF1ADC1R */
+#define WM8995_AIF2DACR_TO_AIF1ADC1R_SHIFT           0	/* AIF2DACR_TO_AIF1ADC1R */
+#define WM8995_AIF2DACR_TO_AIF1ADC1R_WIDTH           1	/* AIF2DACR_TO_AIF1ADC1R */
+
+/*
+ * R1544 (0x608) - AIF1 ADC2 Left Mixer Routing
+ */
+#define WM8995_ADC2L_TO_AIF1ADC2L               0x0002	/* ADC2L_TO_AIF1ADC2L */
+#define WM8995_ADC2L_TO_AIF1ADC2L_MASK          0x0002	/* ADC2L_TO_AIF1ADC2L */
+#define WM8995_ADC2L_TO_AIF1ADC2L_SHIFT              1	/* ADC2L_TO_AIF1ADC2L */
+#define WM8995_ADC2L_TO_AIF1ADC2L_WIDTH              1	/* ADC2L_TO_AIF1ADC2L */
+#define WM8995_AIF2DACL_TO_AIF1ADC2L            0x0001	/* AIF2DACL_TO_AIF1ADC2L */
+#define WM8995_AIF2DACL_TO_AIF1ADC2L_MASK       0x0001	/* AIF2DACL_TO_AIF1ADC2L */
+#define WM8995_AIF2DACL_TO_AIF1ADC2L_SHIFT           0	/* AIF2DACL_TO_AIF1ADC2L */
+#define WM8995_AIF2DACL_TO_AIF1ADC2L_WIDTH           1	/* AIF2DACL_TO_AIF1ADC2L */
+
+/*
+ * R1545 (0x609) - AIF1 ADC2 Right mixer Routing
+ */
+#define WM8995_ADC2R_TO_AIF1ADC2R               0x0002	/* ADC2R_TO_AIF1ADC2R */
+#define WM8995_ADC2R_TO_AIF1ADC2R_MASK          0x0002	/* ADC2R_TO_AIF1ADC2R */
+#define WM8995_ADC2R_TO_AIF1ADC2R_SHIFT              1	/* ADC2R_TO_AIF1ADC2R */
+#define WM8995_ADC2R_TO_AIF1ADC2R_WIDTH              1	/* ADC2R_TO_AIF1ADC2R */
+#define WM8995_AIF2DACR_TO_AIF1ADC2R            0x0001	/* AIF2DACR_TO_AIF1ADC2R */
+#define WM8995_AIF2DACR_TO_AIF1ADC2R_MASK       0x0001	/* AIF2DACR_TO_AIF1ADC2R */
+#define WM8995_AIF2DACR_TO_AIF1ADC2R_SHIFT           0	/* AIF2DACR_TO_AIF1ADC2R */
+#define WM8995_AIF2DACR_TO_AIF1ADC2R_WIDTH           1	/* AIF2DACR_TO_AIF1ADC2R */
+
+/*
+ * R1552 (0x610) - DAC Softmute
+ */
+#define WM8995_DAC_SOFTMUTEMODE                 0x0002	/* DAC_SOFTMUTEMODE */
+#define WM8995_DAC_SOFTMUTEMODE_MASK            0x0002	/* DAC_SOFTMUTEMODE */
+#define WM8995_DAC_SOFTMUTEMODE_SHIFT                1	/* DAC_SOFTMUTEMODE */
+#define WM8995_DAC_SOFTMUTEMODE_WIDTH                1	/* DAC_SOFTMUTEMODE */
+#define WM8995_DAC_MUTERATE                     0x0001	/* DAC_MUTERATE */
+#define WM8995_DAC_MUTERATE_MASK                0x0001	/* DAC_MUTERATE */
+#define WM8995_DAC_MUTERATE_SHIFT                    0	/* DAC_MUTERATE */
+#define WM8995_DAC_MUTERATE_WIDTH                    1	/* DAC_MUTERATE */
+
+/*
+ * R1568 (0x620) - Oversampling
+ */
+#define WM8995_ADC_OSR128                       0x0002	/* ADC_OSR128 */
+#define WM8995_ADC_OSR128_MASK                  0x0002	/* ADC_OSR128 */
+#define WM8995_ADC_OSR128_SHIFT                      1	/* ADC_OSR128 */
+#define WM8995_ADC_OSR128_WIDTH                      1	/* ADC_OSR128 */
+#define WM8995_DAC_OSR128                       0x0001	/* DAC_OSR128 */
+#define WM8995_DAC_OSR128_MASK                  0x0001	/* DAC_OSR128 */
+#define WM8995_DAC_OSR128_SHIFT                      0	/* DAC_OSR128 */
+#define WM8995_DAC_OSR128_WIDTH                      1	/* DAC_OSR128 */
+
+/*
+ * R1569 (0x621) - Sidetone
+ */
+#define WM8995_ST_LPF                           0x1000	/* ST_LPF */
+#define WM8995_ST_LPF_MASK                      0x1000	/* ST_LPF */
+#define WM8995_ST_LPF_SHIFT                         12	/* ST_LPF */
+#define WM8995_ST_LPF_WIDTH                          1	/* ST_LPF */
+#define WM8995_ST_HPF_CUT_MASK                  0x0380	/* ST_HPF_CUT - [9:7] */
+#define WM8995_ST_HPF_CUT_SHIFT                      7	/* ST_HPF_CUT - [9:7] */
+#define WM8995_ST_HPF_CUT_WIDTH                      3	/* ST_HPF_CUT - [9:7] */
+#define WM8995_ST_HPF                           0x0040	/* ST_HPF */
+#define WM8995_ST_HPF_MASK                      0x0040	/* ST_HPF */
+#define WM8995_ST_HPF_SHIFT                          6	/* ST_HPF */
+#define WM8995_ST_HPF_WIDTH                          1	/* ST_HPF */
+#define WM8995_STR_SEL                          0x0002	/* STR_SEL */
+#define WM8995_STR_SEL_MASK                     0x0002	/* STR_SEL */
+#define WM8995_STR_SEL_SHIFT                         1	/* STR_SEL */
+#define WM8995_STR_SEL_WIDTH                         1	/* STR_SEL */
+#define WM8995_STL_SEL                          0x0001	/* STL_SEL */
+#define WM8995_STL_SEL_MASK                     0x0001	/* STL_SEL */
+#define WM8995_STL_SEL_SHIFT                         0	/* STL_SEL */
+#define WM8995_STL_SEL_WIDTH                         1	/* STL_SEL */
+
+/*
+ * R1792 (0x700) - GPIO 1
+ */
+#define WM8995_GP1_DIR                          0x8000	/* GP1_DIR */
+#define WM8995_GP1_DIR_MASK                     0x8000	/* GP1_DIR */
+#define WM8995_GP1_DIR_SHIFT                        15	/* GP1_DIR */
+#define WM8995_GP1_DIR_WIDTH                         1	/* GP1_DIR */
+#define WM8995_GP1_PU                           0x4000	/* GP1_PU */
+#define WM8995_GP1_PU_MASK                      0x4000	/* GP1_PU */
+#define WM8995_GP1_PU_SHIFT                         14	/* GP1_PU */
+#define WM8995_GP1_PU_WIDTH                          1	/* GP1_PU */
+#define WM8995_GP1_PD                           0x2000	/* GP1_PD */
+#define WM8995_GP1_PD_MASK                      0x2000	/* GP1_PD */
+#define WM8995_GP1_PD_SHIFT                         13	/* GP1_PD */
+#define WM8995_GP1_PD_WIDTH                          1	/* GP1_PD */
+#define WM8995_GP1_POL                          0x0400	/* GP1_POL */
+#define WM8995_GP1_POL_MASK                     0x0400	/* GP1_POL */
+#define WM8995_GP1_POL_SHIFT                        10	/* GP1_POL */
+#define WM8995_GP1_POL_WIDTH                         1	/* GP1_POL */
+#define WM8995_GP1_OP_CFG                       0x0200	/* GP1_OP_CFG */
+#define WM8995_GP1_OP_CFG_MASK                  0x0200	/* GP1_OP_CFG */
+#define WM8995_GP1_OP_CFG_SHIFT                      9	/* GP1_OP_CFG */
+#define WM8995_GP1_OP_CFG_WIDTH                      1	/* GP1_OP_CFG */
+#define WM8995_GP1_DB                           0x0100	/* GP1_DB */
+#define WM8995_GP1_DB_MASK                      0x0100	/* GP1_DB */
+#define WM8995_GP1_DB_SHIFT                          8	/* GP1_DB */
+#define WM8995_GP1_DB_WIDTH                          1	/* GP1_DB */
+#define WM8995_GP1_LVL                          0x0040	/* GP1_LVL */
+#define WM8995_GP1_LVL_MASK                     0x0040	/* GP1_LVL */
+#define WM8995_GP1_LVL_SHIFT                         6	/* GP1_LVL */
+#define WM8995_GP1_LVL_WIDTH                         1	/* GP1_LVL */
+#define WM8995_GP1_FN_MASK                      0x001F	/* GP1_FN - [4:0] */
+#define WM8995_GP1_FN_SHIFT                          0	/* GP1_FN - [4:0] */
+#define WM8995_GP1_FN_WIDTH                          5	/* GP1_FN - [4:0] */
+
+/*
+ * R1793 (0x701) - GPIO 2
+ */
+#define WM8995_GP2_DIR                          0x8000	/* GP2_DIR */
+#define WM8995_GP2_DIR_MASK                     0x8000	/* GP2_DIR */
+#define WM8995_GP2_DIR_SHIFT                        15	/* GP2_DIR */
+#define WM8995_GP2_DIR_WIDTH                         1	/* GP2_DIR */
+#define WM8995_GP2_PU                           0x4000	/* GP2_PU */
+#define WM8995_GP2_PU_MASK                      0x4000	/* GP2_PU */
+#define WM8995_GP2_PU_SHIFT                         14	/* GP2_PU */
+#define WM8995_GP2_PU_WIDTH                          1	/* GP2_PU */
+#define WM8995_GP2_PD                           0x2000	/* GP2_PD */
+#define WM8995_GP2_PD_MASK                      0x2000	/* GP2_PD */
+#define WM8995_GP2_PD_SHIFT                         13	/* GP2_PD */
+#define WM8995_GP2_PD_WIDTH                          1	/* GP2_PD */
+#define WM8995_GP2_POL                          0x0400	/* GP2_POL */
+#define WM8995_GP2_POL_MASK                     0x0400	/* GP2_POL */
+#define WM8995_GP2_POL_SHIFT                        10	/* GP2_POL */
+#define WM8995_GP2_POL_WIDTH                         1	/* GP2_POL */
+#define WM8995_GP2_OP_CFG                       0x0200	/* GP2_OP_CFG */
+#define WM8995_GP2_OP_CFG_MASK                  0x0200	/* GP2_OP_CFG */
+#define WM8995_GP2_OP_CFG_SHIFT                      9	/* GP2_OP_CFG */
+#define WM8995_GP2_OP_CFG_WIDTH                      1	/* GP2_OP_CFG */
+#define WM8995_GP2_DB                           0x0100	/* GP2_DB */
+#define WM8995_GP2_DB_MASK                      0x0100	/* GP2_DB */
+#define WM8995_GP2_DB_SHIFT                          8	/* GP2_DB */
+#define WM8995_GP2_DB_WIDTH                          1	/* GP2_DB */
+#define WM8995_GP2_LVL                          0x0040	/* GP2_LVL */
+#define WM8995_GP2_LVL_MASK                     0x0040	/* GP2_LVL */
+#define WM8995_GP2_LVL_SHIFT                         6	/* GP2_LVL */
+#define WM8995_GP2_LVL_WIDTH                         1	/* GP2_LVL */
+#define WM8995_GP2_FN_MASK                      0x001F	/* GP2_FN - [4:0] */
+#define WM8995_GP2_FN_SHIFT                          0	/* GP2_FN - [4:0] */
+#define WM8995_GP2_FN_WIDTH                          5	/* GP2_FN - [4:0] */
+
+/*
+ * R1794 (0x702) - GPIO 3
+ */
+#define WM8995_GP3_DIR                          0x8000	/* GP3_DIR */
+#define WM8995_GP3_DIR_MASK                     0x8000	/* GP3_DIR */
+#define WM8995_GP3_DIR_SHIFT                        15	/* GP3_DIR */
+#define WM8995_GP3_DIR_WIDTH                         1	/* GP3_DIR */
+#define WM8995_GP3_PU                           0x4000	/* GP3_PU */
+#define WM8995_GP3_PU_MASK                      0x4000	/* GP3_PU */
+#define WM8995_GP3_PU_SHIFT                         14	/* GP3_PU */
+#define WM8995_GP3_PU_WIDTH                          1	/* GP3_PU */
+#define WM8995_GP3_PD                           0x2000	/* GP3_PD */
+#define WM8995_GP3_PD_MASK                      0x2000	/* GP3_PD */
+#define WM8995_GP3_PD_SHIFT                         13	/* GP3_PD */
+#define WM8995_GP3_PD_WIDTH                          1	/* GP3_PD */
+#define WM8995_GP3_POL                          0x0400	/* GP3_POL */
+#define WM8995_GP3_POL_MASK                     0x0400	/* GP3_POL */
+#define WM8995_GP3_POL_SHIFT                        10	/* GP3_POL */
+#define WM8995_GP3_POL_WIDTH                         1	/* GP3_POL */
+#define WM8995_GP3_OP_CFG                       0x0200	/* GP3_OP_CFG */
+#define WM8995_GP3_OP_CFG_MASK                  0x0200	/* GP3_OP_CFG */
+#define WM8995_GP3_OP_CFG_SHIFT                      9	/* GP3_OP_CFG */
+#define WM8995_GP3_OP_CFG_WIDTH                      1	/* GP3_OP_CFG */
+#define WM8995_GP3_DB                           0x0100	/* GP3_DB */
+#define WM8995_GP3_DB_MASK                      0x0100	/* GP3_DB */
+#define WM8995_GP3_DB_SHIFT                          8	/* GP3_DB */
+#define WM8995_GP3_DB_WIDTH                          1	/* GP3_DB */
+#define WM8995_GP3_LVL                          0x0040	/* GP3_LVL */
+#define WM8995_GP3_LVL_MASK                     0x0040	/* GP3_LVL */
+#define WM8995_GP3_LVL_SHIFT                         6	/* GP3_LVL */
+#define WM8995_GP3_LVL_WIDTH                         1	/* GP3_LVL */
+#define WM8995_GP3_FN_MASK                      0x001F	/* GP3_FN - [4:0] */
+#define WM8995_GP3_FN_SHIFT                          0	/* GP3_FN - [4:0] */
+#define WM8995_GP3_FN_WIDTH                          5	/* GP3_FN - [4:0] */
+
+/*
+ * R1795 (0x703) - GPIO 4
+ */
+#define WM8995_GP4_DIR                          0x8000	/* GP4_DIR */
+#define WM8995_GP4_DIR_MASK                     0x8000	/* GP4_DIR */
+#define WM8995_GP4_DIR_SHIFT                        15	/* GP4_DIR */
+#define WM8995_GP4_DIR_WIDTH                         1	/* GP4_DIR */
+#define WM8995_GP4_PU                           0x4000	/* GP4_PU */
+#define WM8995_GP4_PU_MASK                      0x4000	/* GP4_PU */
+#define WM8995_GP4_PU_SHIFT                         14	/* GP4_PU */
+#define WM8995_GP4_PU_WIDTH                          1	/* GP4_PU */
+#define WM8995_GP4_PD                           0x2000	/* GP4_PD */
+#define WM8995_GP4_PD_MASK                      0x2000	/* GP4_PD */
+#define WM8995_GP4_PD_SHIFT                         13	/* GP4_PD */
+#define WM8995_GP4_PD_WIDTH                          1	/* GP4_PD */
+#define WM8995_GP4_POL                          0x0400	/* GP4_POL */
+#define WM8995_GP4_POL_MASK                     0x0400	/* GP4_POL */
+#define WM8995_GP4_POL_SHIFT                        10	/* GP4_POL */
+#define WM8995_GP4_POL_WIDTH                         1	/* GP4_POL */
+#define WM8995_GP4_OP_CFG                       0x0200	/* GP4_OP_CFG */
+#define WM8995_GP4_OP_CFG_MASK                  0x0200	/* GP4_OP_CFG */
+#define WM8995_GP4_OP_CFG_SHIFT                      9	/* GP4_OP_CFG */
+#define WM8995_GP4_OP_CFG_WIDTH                      1	/* GP4_OP_CFG */
+#define WM8995_GP4_DB                           0x0100	/* GP4_DB */
+#define WM8995_GP4_DB_MASK                      0x0100	/* GP4_DB */
+#define WM8995_GP4_DB_SHIFT                          8	/* GP4_DB */
+#define WM8995_GP4_DB_WIDTH                          1	/* GP4_DB */
+#define WM8995_GP4_LVL                          0x0040	/* GP4_LVL */
+#define WM8995_GP4_LVL_MASK                     0x0040	/* GP4_LVL */
+#define WM8995_GP4_LVL_SHIFT                         6	/* GP4_LVL */
+#define WM8995_GP4_LVL_WIDTH                         1	/* GP4_LVL */
+#define WM8995_GP4_FN_MASK                      0x001F	/* GP4_FN - [4:0] */
+#define WM8995_GP4_FN_SHIFT                          0	/* GP4_FN - [4:0] */
+#define WM8995_GP4_FN_WIDTH                          5	/* GP4_FN - [4:0] */
+
+/*
+ * R1796 (0x704) - GPIO 5
+ */
+#define WM8995_GP5_DIR                          0x8000	/* GP5_DIR */
+#define WM8995_GP5_DIR_MASK                     0x8000	/* GP5_DIR */
+#define WM8995_GP5_DIR_SHIFT                        15	/* GP5_DIR */
+#define WM8995_GP5_DIR_WIDTH                         1	/* GP5_DIR */
+#define WM8995_GP5_PU                           0x4000	/* GP5_PU */
+#define WM8995_GP5_PU_MASK                      0x4000	/* GP5_PU */
+#define WM8995_GP5_PU_SHIFT                         14	/* GP5_PU */
+#define WM8995_GP5_PU_WIDTH                          1	/* GP5_PU */
+#define WM8995_GP5_PD                           0x2000	/* GP5_PD */
+#define WM8995_GP5_PD_MASK                      0x2000	/* GP5_PD */
+#define WM8995_GP5_PD_SHIFT                         13	/* GP5_PD */
+#define WM8995_GP5_PD_WIDTH                          1	/* GP5_PD */
+#define WM8995_GP5_POL                          0x0400	/* GP5_POL */
+#define WM8995_GP5_POL_MASK                     0x0400	/* GP5_POL */
+#define WM8995_GP5_POL_SHIFT                        10	/* GP5_POL */
+#define WM8995_GP5_POL_WIDTH                         1	/* GP5_POL */
+#define WM8995_GP5_OP_CFG                       0x0200	/* GP5_OP_CFG */
+#define WM8995_GP5_OP_CFG_MASK                  0x0200	/* GP5_OP_CFG */
+#define WM8995_GP5_OP_CFG_SHIFT                      9	/* GP5_OP_CFG */
+#define WM8995_GP5_OP_CFG_WIDTH                      1	/* GP5_OP_CFG */
+#define WM8995_GP5_DB                           0x0100	/* GP5_DB */
+#define WM8995_GP5_DB_MASK                      0x0100	/* GP5_DB */
+#define WM8995_GP5_DB_SHIFT                          8	/* GP5_DB */
+#define WM8995_GP5_DB_WIDTH                          1	/* GP5_DB */
+#define WM8995_GP5_LVL                          0x0040	/* GP5_LVL */
+#define WM8995_GP5_LVL_MASK                     0x0040	/* GP5_LVL */
+#define WM8995_GP5_LVL_SHIFT                         6	/* GP5_LVL */
+#define WM8995_GP5_LVL_WIDTH                         1	/* GP5_LVL */
+#define WM8995_GP5_FN_MASK                      0x001F	/* GP5_FN - [4:0] */
+#define WM8995_GP5_FN_SHIFT                          0	/* GP5_FN - [4:0] */
+#define WM8995_GP5_FN_WIDTH                          5	/* GP5_FN - [4:0] */
+
+/*
+ * R1797 (0x705) - GPIO 6
+ */
+#define WM8995_GP6_DIR                          0x8000	/* GP6_DIR */
+#define WM8995_GP6_DIR_MASK                     0x8000	/* GP6_DIR */
+#define WM8995_GP6_DIR_SHIFT                        15	/* GP6_DIR */
+#define WM8995_GP6_DIR_WIDTH                         1	/* GP6_DIR */
+#define WM8995_GP6_PU                           0x4000	/* GP6_PU */
+#define WM8995_GP6_PU_MASK                      0x4000	/* GP6_PU */
+#define WM8995_GP6_PU_SHIFT                         14	/* GP6_PU */
+#define WM8995_GP6_PU_WIDTH                          1	/* GP6_PU */
+#define WM8995_GP6_PD                           0x2000	/* GP6_PD */
+#define WM8995_GP6_PD_MASK                      0x2000	/* GP6_PD */
+#define WM8995_GP6_PD_SHIFT                         13	/* GP6_PD */
+#define WM8995_GP6_PD_WIDTH                          1	/* GP6_PD */
+#define WM8995_GP6_POL                          0x0400	/* GP6_POL */
+#define WM8995_GP6_POL_MASK                     0x0400	/* GP6_POL */
+#define WM8995_GP6_POL_SHIFT                        10	/* GP6_POL */
+#define WM8995_GP6_POL_WIDTH                         1	/* GP6_POL */
+#define WM8995_GP6_OP_CFG                       0x0200	/* GP6_OP_CFG */
+#define WM8995_GP6_OP_CFG_MASK                  0x0200	/* GP6_OP_CFG */
+#define WM8995_GP6_OP_CFG_SHIFT                      9	/* GP6_OP_CFG */
+#define WM8995_GP6_OP_CFG_WIDTH                      1	/* GP6_OP_CFG */
+#define WM8995_GP6_DB                           0x0100	/* GP6_DB */
+#define WM8995_GP6_DB_MASK                      0x0100	/* GP6_DB */
+#define WM8995_GP6_DB_SHIFT                          8	/* GP6_DB */
+#define WM8995_GP6_DB_WIDTH                          1	/* GP6_DB */
+#define WM8995_GP6_LVL                          0x0040	/* GP6_LVL */
+#define WM8995_GP6_LVL_MASK                     0x0040	/* GP6_LVL */
+#define WM8995_GP6_LVL_SHIFT                         6	/* GP6_LVL */
+#define WM8995_GP6_LVL_WIDTH                         1	/* GP6_LVL */
+#define WM8995_GP6_FN_MASK                      0x001F	/* GP6_FN - [4:0] */
+#define WM8995_GP6_FN_SHIFT                          0	/* GP6_FN - [4:0] */
+#define WM8995_GP6_FN_WIDTH                          5	/* GP6_FN - [4:0] */
+
+/*
+ * R1798 (0x706) - GPIO 7
+ */
+#define WM8995_GP7_DIR                          0x8000	/* GP7_DIR */
+#define WM8995_GP7_DIR_MASK                     0x8000	/* GP7_DIR */
+#define WM8995_GP7_DIR_SHIFT                        15	/* GP7_DIR */
+#define WM8995_GP7_DIR_WIDTH                         1	/* GP7_DIR */
+#define WM8995_GP7_PU                           0x4000	/* GP7_PU */
+#define WM8995_GP7_PU_MASK                      0x4000	/* GP7_PU */
+#define WM8995_GP7_PU_SHIFT                         14	/* GP7_PU */
+#define WM8995_GP7_PU_WIDTH                          1	/* GP7_PU */
+#define WM8995_GP7_PD                           0x2000	/* GP7_PD */
+#define WM8995_GP7_PD_MASK                      0x2000	/* GP7_PD */
+#define WM8995_GP7_PD_SHIFT                         13	/* GP7_PD */
+#define WM8995_GP7_PD_WIDTH                          1	/* GP7_PD */
+#define WM8995_GP7_POL                          0x0400	/* GP7_POL */
+#define WM8995_GP7_POL_MASK                     0x0400	/* GP7_POL */
+#define WM8995_GP7_POL_SHIFT                        10	/* GP7_POL */
+#define WM8995_GP7_POL_WIDTH                         1	/* GP7_POL */
+#define WM8995_GP7_OP_CFG                       0x0200	/* GP7_OP_CFG */
+#define WM8995_GP7_OP_CFG_MASK                  0x0200	/* GP7_OP_CFG */
+#define WM8995_GP7_OP_CFG_SHIFT                      9	/* GP7_OP_CFG */
+#define WM8995_GP7_OP_CFG_WIDTH                      1	/* GP7_OP_CFG */
+#define WM8995_GP7_DB                           0x0100	/* GP7_DB */
+#define WM8995_GP7_DB_MASK                      0x0100	/* GP7_DB */
+#define WM8995_GP7_DB_SHIFT                          8	/* GP7_DB */
+#define WM8995_GP7_DB_WIDTH                          1	/* GP7_DB */
+#define WM8995_GP7_LVL                          0x0040	/* GP7_LVL */
+#define WM8995_GP7_LVL_MASK                     0x0040	/* GP7_LVL */
+#define WM8995_GP7_LVL_SHIFT                         6	/* GP7_LVL */
+#define WM8995_GP7_LVL_WIDTH                         1	/* GP7_LVL */
+#define WM8995_GP7_FN_MASK                      0x001F	/* GP7_FN - [4:0] */
+#define WM8995_GP7_FN_SHIFT                          0	/* GP7_FN - [4:0] */
+#define WM8995_GP7_FN_WIDTH                          5	/* GP7_FN - [4:0] */
+
+/*
+ * R1799 (0x707) - GPIO 8
+ */
+#define WM8995_GP8_DIR                          0x8000	/* GP8_DIR */
+#define WM8995_GP8_DIR_MASK                     0x8000	/* GP8_DIR */
+#define WM8995_GP8_DIR_SHIFT                        15	/* GP8_DIR */
+#define WM8995_GP8_DIR_WIDTH                         1	/* GP8_DIR */
+#define WM8995_GP8_PU                           0x4000	/* GP8_PU */
+#define WM8995_GP8_PU_MASK                      0x4000	/* GP8_PU */
+#define WM8995_GP8_PU_SHIFT                         14	/* GP8_PU */
+#define WM8995_GP8_PU_WIDTH                          1	/* GP8_PU */
+#define WM8995_GP8_PD                           0x2000	/* GP8_PD */
+#define WM8995_GP8_PD_MASK                      0x2000	/* GP8_PD */
+#define WM8995_GP8_PD_SHIFT                         13	/* GP8_PD */
+#define WM8995_GP8_PD_WIDTH                          1	/* GP8_PD */
+#define WM8995_GP8_POL                          0x0400	/* GP8_POL */
+#define WM8995_GP8_POL_MASK                     0x0400	/* GP8_POL */
+#define WM8995_GP8_POL_SHIFT                        10	/* GP8_POL */
+#define WM8995_GP8_POL_WIDTH                         1	/* GP8_POL */
+#define WM8995_GP8_OP_CFG                       0x0200	/* GP8_OP_CFG */
+#define WM8995_GP8_OP_CFG_MASK                  0x0200	/* GP8_OP_CFG */
+#define WM8995_GP8_OP_CFG_SHIFT                      9	/* GP8_OP_CFG */
+#define WM8995_GP8_OP_CFG_WIDTH                      1	/* GP8_OP_CFG */
+#define WM8995_GP8_DB                           0x0100	/* GP8_DB */
+#define WM8995_GP8_DB_MASK                      0x0100	/* GP8_DB */
+#define WM8995_GP8_DB_SHIFT                          8	/* GP8_DB */
+#define WM8995_GP8_DB_WIDTH                          1	/* GP8_DB */
+#define WM8995_GP8_LVL                          0x0040	/* GP8_LVL */
+#define WM8995_GP8_LVL_MASK                     0x0040	/* GP8_LVL */
+#define WM8995_GP8_LVL_SHIFT                         6	/* GP8_LVL */
+#define WM8995_GP8_LVL_WIDTH                         1	/* GP8_LVL */
+#define WM8995_GP8_FN_MASK                      0x001F	/* GP8_FN - [4:0] */
+#define WM8995_GP8_FN_SHIFT                          0	/* GP8_FN - [4:0] */
+#define WM8995_GP8_FN_WIDTH                          5	/* GP8_FN - [4:0] */
+
+/*
+ * R1800 (0x708) - GPIO 9
+ */
+#define WM8995_GP9_DIR                          0x8000	/* GP9_DIR */
+#define WM8995_GP9_DIR_MASK                     0x8000	/* GP9_DIR */
+#define WM8995_GP9_DIR_SHIFT                        15	/* GP9_DIR */
+#define WM8995_GP9_DIR_WIDTH                         1	/* GP9_DIR */
+#define WM8995_GP9_PU                           0x4000	/* GP9_PU */
+#define WM8995_GP9_PU_MASK                      0x4000	/* GP9_PU */
+#define WM8995_GP9_PU_SHIFT                         14	/* GP9_PU */
+#define WM8995_GP9_PU_WIDTH                          1	/* GP9_PU */
+#define WM8995_GP9_PD                           0x2000	/* GP9_PD */
+#define WM8995_GP9_PD_MASK                      0x2000	/* GP9_PD */
+#define WM8995_GP9_PD_SHIFT                         13	/* GP9_PD */
+#define WM8995_GP9_PD_WIDTH                          1	/* GP9_PD */
+#define WM8995_GP9_POL                          0x0400	/* GP9_POL */
+#define WM8995_GP9_POL_MASK                     0x0400	/* GP9_POL */
+#define WM8995_GP9_POL_SHIFT                        10	/* GP9_POL */
+#define WM8995_GP9_POL_WIDTH                         1	/* GP9_POL */
+#define WM8995_GP9_OP_CFG                       0x0200	/* GP9_OP_CFG */
+#define WM8995_GP9_OP_CFG_MASK                  0x0200	/* GP9_OP_CFG */
+#define WM8995_GP9_OP_CFG_SHIFT                      9	/* GP9_OP_CFG */
+#define WM8995_GP9_OP_CFG_WIDTH                      1	/* GP9_OP_CFG */
+#define WM8995_GP9_DB                           0x0100	/* GP9_DB */
+#define WM8995_GP9_DB_MASK                      0x0100	/* GP9_DB */
+#define WM8995_GP9_DB_SHIFT                          8	/* GP9_DB */
+#define WM8995_GP9_DB_WIDTH                          1	/* GP9_DB */
+#define WM8995_GP9_LVL                          0x0040	/* GP9_LVL */
+#define WM8995_GP9_LVL_MASK                     0x0040	/* GP9_LVL */
+#define WM8995_GP9_LVL_SHIFT                         6	/* GP9_LVL */
+#define WM8995_GP9_LVL_WIDTH                         1	/* GP9_LVL */
+#define WM8995_GP9_FN_MASK                      0x001F	/* GP9_FN - [4:0] */
+#define WM8995_GP9_FN_SHIFT                          0	/* GP9_FN - [4:0] */
+#define WM8995_GP9_FN_WIDTH                          5	/* GP9_FN - [4:0] */
+
+/*
+ * R1801 (0x709) - GPIO 10
+ */
+#define WM8995_GP10_DIR                         0x8000	/* GP10_DIR */
+#define WM8995_GP10_DIR_MASK                    0x8000	/* GP10_DIR */
+#define WM8995_GP10_DIR_SHIFT                       15	/* GP10_DIR */
+#define WM8995_GP10_DIR_WIDTH                        1	/* GP10_DIR */
+#define WM8995_GP10_PU                          0x4000	/* GP10_PU */
+#define WM8995_GP10_PU_MASK                     0x4000	/* GP10_PU */
+#define WM8995_GP10_PU_SHIFT                        14	/* GP10_PU */
+#define WM8995_GP10_PU_WIDTH                         1	/* GP10_PU */
+#define WM8995_GP10_PD                          0x2000	/* GP10_PD */
+#define WM8995_GP10_PD_MASK                     0x2000	/* GP10_PD */
+#define WM8995_GP10_PD_SHIFT                        13	/* GP10_PD */
+#define WM8995_GP10_PD_WIDTH                         1	/* GP10_PD */
+#define WM8995_GP10_POL                         0x0400	/* GP10_POL */
+#define WM8995_GP10_POL_MASK                    0x0400	/* GP10_POL */
+#define WM8995_GP10_POL_SHIFT                       10	/* GP10_POL */
+#define WM8995_GP10_POL_WIDTH                        1	/* GP10_POL */
+#define WM8995_GP10_OP_CFG                      0x0200	/* GP10_OP_CFG */
+#define WM8995_GP10_OP_CFG_MASK                 0x0200	/* GP10_OP_CFG */
+#define WM8995_GP10_OP_CFG_SHIFT                     9	/* GP10_OP_CFG */
+#define WM8995_GP10_OP_CFG_WIDTH                     1	/* GP10_OP_CFG */
+#define WM8995_GP10_DB                          0x0100	/* GP10_DB */
+#define WM8995_GP10_DB_MASK                     0x0100	/* GP10_DB */
+#define WM8995_GP10_DB_SHIFT                         8	/* GP10_DB */
+#define WM8995_GP10_DB_WIDTH                         1	/* GP10_DB */
+#define WM8995_GP10_LVL                         0x0040	/* GP10_LVL */
+#define WM8995_GP10_LVL_MASK                    0x0040	/* GP10_LVL */
+#define WM8995_GP10_LVL_SHIFT                        6	/* GP10_LVL */
+#define WM8995_GP10_LVL_WIDTH                        1	/* GP10_LVL */
+#define WM8995_GP10_FN_MASK                     0x001F	/* GP10_FN - [4:0] */
+#define WM8995_GP10_FN_SHIFT                         0	/* GP10_FN - [4:0] */
+#define WM8995_GP10_FN_WIDTH                         5	/* GP10_FN - [4:0] */
+
+/*
+ * R1802 (0x70A) - GPIO 11
+ */
+#define WM8995_GP11_DIR                         0x8000	/* GP11_DIR */
+#define WM8995_GP11_DIR_MASK                    0x8000	/* GP11_DIR */
+#define WM8995_GP11_DIR_SHIFT                       15	/* GP11_DIR */
+#define WM8995_GP11_DIR_WIDTH                        1	/* GP11_DIR */
+#define WM8995_GP11_PU                          0x4000	/* GP11_PU */
+#define WM8995_GP11_PU_MASK                     0x4000	/* GP11_PU */
+#define WM8995_GP11_PU_SHIFT                        14	/* GP11_PU */
+#define WM8995_GP11_PU_WIDTH                         1	/* GP11_PU */
+#define WM8995_GP11_PD                          0x2000	/* GP11_PD */
+#define WM8995_GP11_PD_MASK                     0x2000	/* GP11_PD */
+#define WM8995_GP11_PD_SHIFT                        13	/* GP11_PD */
+#define WM8995_GP11_PD_WIDTH                         1	/* GP11_PD */
+#define WM8995_GP11_POL                         0x0400	/* GP11_POL */
+#define WM8995_GP11_POL_MASK                    0x0400	/* GP11_POL */
+#define WM8995_GP11_POL_SHIFT                       10	/* GP11_POL */
+#define WM8995_GP11_POL_WIDTH                        1	/* GP11_POL */
+#define WM8995_GP11_OP_CFG                      0x0200	/* GP11_OP_CFG */
+#define WM8995_GP11_OP_CFG_MASK                 0x0200	/* GP11_OP_CFG */
+#define WM8995_GP11_OP_CFG_SHIFT                     9	/* GP11_OP_CFG */
+#define WM8995_GP11_OP_CFG_WIDTH                     1	/* GP11_OP_CFG */
+#define WM8995_GP11_DB                          0x0100	/* GP11_DB */
+#define WM8995_GP11_DB_MASK                     0x0100	/* GP11_DB */
+#define WM8995_GP11_DB_SHIFT                         8	/* GP11_DB */
+#define WM8995_GP11_DB_WIDTH                         1	/* GP11_DB */
+#define WM8995_GP11_LVL                         0x0040	/* GP11_LVL */
+#define WM8995_GP11_LVL_MASK                    0x0040	/* GP11_LVL */
+#define WM8995_GP11_LVL_SHIFT                        6	/* GP11_LVL */
+#define WM8995_GP11_LVL_WIDTH                        1	/* GP11_LVL */
+#define WM8995_GP11_FN_MASK                     0x001F	/* GP11_FN - [4:0] */
+#define WM8995_GP11_FN_SHIFT                         0	/* GP11_FN - [4:0] */
+#define WM8995_GP11_FN_WIDTH                         5	/* GP11_FN - [4:0] */
+
+/*
+ * R1803 (0x70B) - GPIO 12
+ */
+#define WM8995_GP12_DIR                         0x8000	/* GP12_DIR */
+#define WM8995_GP12_DIR_MASK                    0x8000	/* GP12_DIR */
+#define WM8995_GP12_DIR_SHIFT                       15	/* GP12_DIR */
+#define WM8995_GP12_DIR_WIDTH                        1	/* GP12_DIR */
+#define WM8995_GP12_PU                          0x4000	/* GP12_PU */
+#define WM8995_GP12_PU_MASK                     0x4000	/* GP12_PU */
+#define WM8995_GP12_PU_SHIFT                        14	/* GP12_PU */
+#define WM8995_GP12_PU_WIDTH                         1	/* GP12_PU */
+#define WM8995_GP12_PD                          0x2000	/* GP12_PD */
+#define WM8995_GP12_PD_MASK                     0x2000	/* GP12_PD */
+#define WM8995_GP12_PD_SHIFT                        13	/* GP12_PD */
+#define WM8995_GP12_PD_WIDTH                         1	/* GP12_PD */
+#define WM8995_GP12_POL                         0x0400	/* GP12_POL */
+#define WM8995_GP12_POL_MASK                    0x0400	/* GP12_POL */
+#define WM8995_GP12_POL_SHIFT                       10	/* GP12_POL */
+#define WM8995_GP12_POL_WIDTH                        1	/* GP12_POL */
+#define WM8995_GP12_OP_CFG                      0x0200	/* GP12_OP_CFG */
+#define WM8995_GP12_OP_CFG_MASK                 0x0200	/* GP12_OP_CFG */
+#define WM8995_GP12_OP_CFG_SHIFT                     9	/* GP12_OP_CFG */
+#define WM8995_GP12_OP_CFG_WIDTH                     1	/* GP12_OP_CFG */
+#define WM8995_GP12_DB                          0x0100	/* GP12_DB */
+#define WM8995_GP12_DB_MASK                     0x0100	/* GP12_DB */
+#define WM8995_GP12_DB_SHIFT                         8	/* GP12_DB */
+#define WM8995_GP12_DB_WIDTH                         1	/* GP12_DB */
+#define WM8995_GP12_LVL                         0x0040	/* GP12_LVL */
+#define WM8995_GP12_LVL_MASK                    0x0040	/* GP12_LVL */
+#define WM8995_GP12_LVL_SHIFT                        6	/* GP12_LVL */
+#define WM8995_GP12_LVL_WIDTH                        1	/* GP12_LVL */
+#define WM8995_GP12_FN_MASK                     0x001F	/* GP12_FN - [4:0] */
+#define WM8995_GP12_FN_SHIFT                         0	/* GP12_FN - [4:0] */
+#define WM8995_GP12_FN_WIDTH                         5	/* GP12_FN - [4:0] */
+
+/*
+ * R1804 (0x70C) - GPIO 13
+ */
+#define WM8995_GP13_DIR                         0x8000	/* GP13_DIR */
+#define WM8995_GP13_DIR_MASK                    0x8000	/* GP13_DIR */
+#define WM8995_GP13_DIR_SHIFT                       15	/* GP13_DIR */
+#define WM8995_GP13_DIR_WIDTH                        1	/* GP13_DIR */
+#define WM8995_GP13_PU                          0x4000	/* GP13_PU */
+#define WM8995_GP13_PU_MASK                     0x4000	/* GP13_PU */
+#define WM8995_GP13_PU_SHIFT                        14	/* GP13_PU */
+#define WM8995_GP13_PU_WIDTH                         1	/* GP13_PU */
+#define WM8995_GP13_PD                          0x2000	/* GP13_PD */
+#define WM8995_GP13_PD_MASK                     0x2000	/* GP13_PD */
+#define WM8995_GP13_PD_SHIFT                        13	/* GP13_PD */
+#define WM8995_GP13_PD_WIDTH                         1	/* GP13_PD */
+#define WM8995_GP13_POL                         0x0400	/* GP13_POL */
+#define WM8995_GP13_POL_MASK                    0x0400	/* GP13_POL */
+#define WM8995_GP13_POL_SHIFT                       10	/* GP13_POL */
+#define WM8995_GP13_POL_WIDTH                        1	/* GP13_POL */
+#define WM8995_GP13_OP_CFG                      0x0200	/* GP13_OP_CFG */
+#define WM8995_GP13_OP_CFG_MASK                 0x0200	/* GP13_OP_CFG */
+#define WM8995_GP13_OP_CFG_SHIFT                     9	/* GP13_OP_CFG */
+#define WM8995_GP13_OP_CFG_WIDTH                     1	/* GP13_OP_CFG */
+#define WM8995_GP13_DB                          0x0100	/* GP13_DB */
+#define WM8995_GP13_DB_MASK                     0x0100	/* GP13_DB */
+#define WM8995_GP13_DB_SHIFT                         8	/* GP13_DB */
+#define WM8995_GP13_DB_WIDTH                         1	/* GP13_DB */
+#define WM8995_GP13_LVL                         0x0040	/* GP13_LVL */
+#define WM8995_GP13_LVL_MASK                    0x0040	/* GP13_LVL */
+#define WM8995_GP13_LVL_SHIFT                        6	/* GP13_LVL */
+#define WM8995_GP13_LVL_WIDTH                        1	/* GP13_LVL */
+#define WM8995_GP13_FN_MASK                     0x001F	/* GP13_FN - [4:0] */
+#define WM8995_GP13_FN_SHIFT                         0	/* GP13_FN - [4:0] */
+#define WM8995_GP13_FN_WIDTH                         5	/* GP13_FN - [4:0] */
+
+/*
+ * R1805 (0x70D) - GPIO 14
+ */
+#define WM8995_GP14_DIR                         0x8000	/* GP14_DIR */
+#define WM8995_GP14_DIR_MASK                    0x8000	/* GP14_DIR */
+#define WM8995_GP14_DIR_SHIFT                       15	/* GP14_DIR */
+#define WM8995_GP14_DIR_WIDTH                        1	/* GP14_DIR */
+#define WM8995_GP14_PU                          0x4000	/* GP14_PU */
+#define WM8995_GP14_PU_MASK                     0x4000	/* GP14_PU */
+#define WM8995_GP14_PU_SHIFT                        14	/* GP14_PU */
+#define WM8995_GP14_PU_WIDTH                         1	/* GP14_PU */
+#define WM8995_GP14_PD                          0x2000	/* GP14_PD */
+#define WM8995_GP14_PD_MASK                     0x2000	/* GP14_PD */
+#define WM8995_GP14_PD_SHIFT                        13	/* GP14_PD */
+#define WM8995_GP14_PD_WIDTH                         1	/* GP14_PD */
+#define WM8995_GP14_POL                         0x0400	/* GP14_POL */
+#define WM8995_GP14_POL_MASK                    0x0400	/* GP14_POL */
+#define WM8995_GP14_POL_SHIFT                       10	/* GP14_POL */
+#define WM8995_GP14_POL_WIDTH                        1	/* GP14_POL */
+#define WM8995_GP14_OP_CFG                      0x0200	/* GP14_OP_CFG */
+#define WM8995_GP14_OP_CFG_MASK                 0x0200	/* GP14_OP_CFG */
+#define WM8995_GP14_OP_CFG_SHIFT                     9	/* GP14_OP_CFG */
+#define WM8995_GP14_OP_CFG_WIDTH                     1	/* GP14_OP_CFG */
+#define WM8995_GP14_DB                          0x0100	/* GP14_DB */
+#define WM8995_GP14_DB_MASK                     0x0100	/* GP14_DB */
+#define WM8995_GP14_DB_SHIFT                         8	/* GP14_DB */
+#define WM8995_GP14_DB_WIDTH                         1	/* GP14_DB */
+#define WM8995_GP14_LVL                         0x0040	/* GP14_LVL */
+#define WM8995_GP14_LVL_MASK                    0x0040	/* GP14_LVL */
+#define WM8995_GP14_LVL_SHIFT                        6	/* GP14_LVL */
+#define WM8995_GP14_LVL_WIDTH                        1	/* GP14_LVL */
+#define WM8995_GP14_FN_MASK                     0x001F	/* GP14_FN - [4:0] */
+#define WM8995_GP14_FN_SHIFT                         0	/* GP14_FN - [4:0] */
+#define WM8995_GP14_FN_WIDTH                         5	/* GP14_FN - [4:0] */
+
+/*
+ * R1824 (0x720) - Pull Control (1)
+ */
+#define WM8995_DMICDAT3_PD                      0x4000	/* DMICDAT3_PD */
+#define WM8995_DMICDAT3_PD_MASK                 0x4000	/* DMICDAT3_PD */
+#define WM8995_DMICDAT3_PD_SHIFT                    14	/* DMICDAT3_PD */
+#define WM8995_DMICDAT3_PD_WIDTH                     1	/* DMICDAT3_PD */
+#define WM8995_DMICDAT2_PD                      0x1000	/* DMICDAT2_PD */
+#define WM8995_DMICDAT2_PD_MASK                 0x1000	/* DMICDAT2_PD */
+#define WM8995_DMICDAT2_PD_SHIFT                    12	/* DMICDAT2_PD */
+#define WM8995_DMICDAT2_PD_WIDTH                     1	/* DMICDAT2_PD */
+#define WM8995_DMICDAT1_PD                      0x0400	/* DMICDAT1_PD */
+#define WM8995_DMICDAT1_PD_MASK                 0x0400	/* DMICDAT1_PD */
+#define WM8995_DMICDAT1_PD_SHIFT                    10	/* DMICDAT1_PD */
+#define WM8995_DMICDAT1_PD_WIDTH                     1	/* DMICDAT1_PD */
+#define WM8995_MCLK2_PU                         0x0200	/* MCLK2_PU */
+#define WM8995_MCLK2_PU_MASK                    0x0200	/* MCLK2_PU */
+#define WM8995_MCLK2_PU_SHIFT                        9	/* MCLK2_PU */
+#define WM8995_MCLK2_PU_WIDTH                        1	/* MCLK2_PU */
+#define WM8995_MCLK2_PD                         0x0100	/* MCLK2_PD */
+#define WM8995_MCLK2_PD_MASK                    0x0100	/* MCLK2_PD */
+#define WM8995_MCLK2_PD_SHIFT                        8	/* MCLK2_PD */
+#define WM8995_MCLK2_PD_WIDTH                        1	/* MCLK2_PD */
+#define WM8995_MCLK1_PU                         0x0080	/* MCLK1_PU */
+#define WM8995_MCLK1_PU_MASK                    0x0080	/* MCLK1_PU */
+#define WM8995_MCLK1_PU_SHIFT                        7	/* MCLK1_PU */
+#define WM8995_MCLK1_PU_WIDTH                        1	/* MCLK1_PU */
+#define WM8995_MCLK1_PD                         0x0040	/* MCLK1_PD */
+#define WM8995_MCLK1_PD_MASK                    0x0040	/* MCLK1_PD */
+#define WM8995_MCLK1_PD_SHIFT                        6	/* MCLK1_PD */
+#define WM8995_MCLK1_PD_WIDTH                        1	/* MCLK1_PD */
+#define WM8995_DACDAT1_PU                       0x0020	/* DACDAT1_PU */
+#define WM8995_DACDAT1_PU_MASK                  0x0020	/* DACDAT1_PU */
+#define WM8995_DACDAT1_PU_SHIFT                      5	/* DACDAT1_PU */
+#define WM8995_DACDAT1_PU_WIDTH                      1	/* DACDAT1_PU */
+#define WM8995_DACDAT1_PD                       0x0010	/* DACDAT1_PD */
+#define WM8995_DACDAT1_PD_MASK                  0x0010	/* DACDAT1_PD */
+#define WM8995_DACDAT1_PD_SHIFT                      4	/* DACDAT1_PD */
+#define WM8995_DACDAT1_PD_WIDTH                      1	/* DACDAT1_PD */
+#define WM8995_DACLRCLK1_PU                     0x0008	/* DACLRCLK1_PU */
+#define WM8995_DACLRCLK1_PU_MASK                0x0008	/* DACLRCLK1_PU */
+#define WM8995_DACLRCLK1_PU_SHIFT                    3	/* DACLRCLK1_PU */
+#define WM8995_DACLRCLK1_PU_WIDTH                    1	/* DACLRCLK1_PU */
+#define WM8995_DACLRCLK1_PD                     0x0004	/* DACLRCLK1_PD */
+#define WM8995_DACLRCLK1_PD_MASK                0x0004	/* DACLRCLK1_PD */
+#define WM8995_DACLRCLK1_PD_SHIFT                    2	/* DACLRCLK1_PD */
+#define WM8995_DACLRCLK1_PD_WIDTH                    1	/* DACLRCLK1_PD */
+#define WM8995_BCLK1_PU                         0x0002	/* BCLK1_PU */
+#define WM8995_BCLK1_PU_MASK                    0x0002	/* BCLK1_PU */
+#define WM8995_BCLK1_PU_SHIFT                        1	/* BCLK1_PU */
+#define WM8995_BCLK1_PU_WIDTH                        1	/* BCLK1_PU */
+#define WM8995_BCLK1_PD                         0x0001	/* BCLK1_PD */
+#define WM8995_BCLK1_PD_MASK                    0x0001	/* BCLK1_PD */
+#define WM8995_BCLK1_PD_SHIFT                        0	/* BCLK1_PD */
+#define WM8995_BCLK1_PD_WIDTH                        1	/* BCLK1_PD */
+
+/*
+ * R1825 (0x721) - Pull Control (2)
+ */
+#define WM8995_LDO1ENA_PD                       0x0010	/* LDO1ENA_PD */
+#define WM8995_LDO1ENA_PD_MASK                  0x0010	/* LDO1ENA_PD */
+#define WM8995_LDO1ENA_PD_SHIFT                      4	/* LDO1ENA_PD */
+#define WM8995_LDO1ENA_PD_WIDTH                      1	/* LDO1ENA_PD */
+#define WM8995_MODE_PD                          0x0004	/* MODE_PD */
+#define WM8995_MODE_PD_MASK                     0x0004	/* MODE_PD */
+#define WM8995_MODE_PD_SHIFT                         2	/* MODE_PD */
+#define WM8995_MODE_PD_WIDTH                         1	/* MODE_PD */
+#define WM8995_CSNADDR_PD                       0x0001	/* CSNADDR_PD */
+#define WM8995_CSNADDR_PD_MASK                  0x0001	/* CSNADDR_PD */
+#define WM8995_CSNADDR_PD_SHIFT                      0	/* CSNADDR_PD */
+#define WM8995_CSNADDR_PD_WIDTH                      1	/* CSNADDR_PD */
+
+/*
+ * R1840 (0x730) - Interrupt Status 1
+ */
+#define WM8995_GP14_EINT                        0x2000	/* GP14_EINT */
+#define WM8995_GP14_EINT_MASK                   0x2000	/* GP14_EINT */
+#define WM8995_GP14_EINT_SHIFT                      13	/* GP14_EINT */
+#define WM8995_GP14_EINT_WIDTH                       1	/* GP14_EINT */
+#define WM8995_GP13_EINT                        0x1000	/* GP13_EINT */
+#define WM8995_GP13_EINT_MASK                   0x1000	/* GP13_EINT */
+#define WM8995_GP13_EINT_SHIFT                      12	/* GP13_EINT */
+#define WM8995_GP13_EINT_WIDTH                       1	/* GP13_EINT */
+#define WM8995_GP12_EINT                        0x0800	/* GP12_EINT */
+#define WM8995_GP12_EINT_MASK                   0x0800	/* GP12_EINT */
+#define WM8995_GP12_EINT_SHIFT                      11	/* GP12_EINT */
+#define WM8995_GP12_EINT_WIDTH                       1	/* GP12_EINT */
+#define WM8995_GP11_EINT                        0x0400	/* GP11_EINT */
+#define WM8995_GP11_EINT_MASK                   0x0400	/* GP11_EINT */
+#define WM8995_GP11_EINT_SHIFT                      10	/* GP11_EINT */
+#define WM8995_GP11_EINT_WIDTH                       1	/* GP11_EINT */
+#define WM8995_GP10_EINT                        0x0200	/* GP10_EINT */
+#define WM8995_GP10_EINT_MASK                   0x0200	/* GP10_EINT */
+#define WM8995_GP10_EINT_SHIFT                       9	/* GP10_EINT */
+#define WM8995_GP10_EINT_WIDTH                       1	/* GP10_EINT */
+#define WM8995_GP9_EINT                         0x0100	/* GP9_EINT */
+#define WM8995_GP9_EINT_MASK                    0x0100	/* GP9_EINT */
+#define WM8995_GP9_EINT_SHIFT                        8	/* GP9_EINT */
+#define WM8995_GP9_EINT_WIDTH                        1	/* GP9_EINT */
+#define WM8995_GP8_EINT                         0x0080	/* GP8_EINT */
+#define WM8995_GP8_EINT_MASK                    0x0080	/* GP8_EINT */
+#define WM8995_GP8_EINT_SHIFT                        7	/* GP8_EINT */
+#define WM8995_GP8_EINT_WIDTH                        1	/* GP8_EINT */
+#define WM8995_GP7_EINT                         0x0040	/* GP7_EINT */
+#define WM8995_GP7_EINT_MASK                    0x0040	/* GP7_EINT */
+#define WM8995_GP7_EINT_SHIFT                        6	/* GP7_EINT */
+#define WM8995_GP7_EINT_WIDTH                        1	/* GP7_EINT */
+#define WM8995_GP6_EINT                         0x0020	/* GP6_EINT */
+#define WM8995_GP6_EINT_MASK                    0x0020	/* GP6_EINT */
+#define WM8995_GP6_EINT_SHIFT                        5	/* GP6_EINT */
+#define WM8995_GP6_EINT_WIDTH                        1	/* GP6_EINT */
+#define WM8995_GP5_EINT                         0x0010	/* GP5_EINT */
+#define WM8995_GP5_EINT_MASK                    0x0010	/* GP5_EINT */
+#define WM8995_GP5_EINT_SHIFT                        4	/* GP5_EINT */
+#define WM8995_GP5_EINT_WIDTH                        1	/* GP5_EINT */
+#define WM8995_GP4_EINT                         0x0008	/* GP4_EINT */
+#define WM8995_GP4_EINT_MASK                    0x0008	/* GP4_EINT */
+#define WM8995_GP4_EINT_SHIFT                        3	/* GP4_EINT */
+#define WM8995_GP4_EINT_WIDTH                        1	/* GP4_EINT */
+#define WM8995_GP3_EINT                         0x0004	/* GP3_EINT */
+#define WM8995_GP3_EINT_MASK                    0x0004	/* GP3_EINT */
+#define WM8995_GP3_EINT_SHIFT                        2	/* GP3_EINT */
+#define WM8995_GP3_EINT_WIDTH                        1	/* GP3_EINT */
+#define WM8995_GP2_EINT                         0x0002	/* GP2_EINT */
+#define WM8995_GP2_EINT_MASK                    0x0002	/* GP2_EINT */
+#define WM8995_GP2_EINT_SHIFT                        1	/* GP2_EINT */
+#define WM8995_GP2_EINT_WIDTH                        1	/* GP2_EINT */
+#define WM8995_GP1_EINT                         0x0001	/* GP1_EINT */
+#define WM8995_GP1_EINT_MASK                    0x0001	/* GP1_EINT */
+#define WM8995_GP1_EINT_SHIFT                        0	/* GP1_EINT */
+#define WM8995_GP1_EINT_WIDTH                        1	/* GP1_EINT */
+
+/*
+ * R1841 (0x731) - Interrupt Status 2
+ */
+#define WM8995_DCS_DONE_23_EINT                 0x1000	/* DCS_DONE_23_EINT */
+#define WM8995_DCS_DONE_23_EINT_MASK            0x1000	/* DCS_DONE_23_EINT */
+#define WM8995_DCS_DONE_23_EINT_SHIFT               12	/* DCS_DONE_23_EINT */
+#define WM8995_DCS_DONE_23_EINT_WIDTH                1	/* DCS_DONE_23_EINT */
+#define WM8995_DCS_DONE_01_EINT                 0x0800	/* DCS_DONE_01_EINT */
+#define WM8995_DCS_DONE_01_EINT_MASK            0x0800	/* DCS_DONE_01_EINT */
+#define WM8995_DCS_DONE_01_EINT_SHIFT               11	/* DCS_DONE_01_EINT */
+#define WM8995_DCS_DONE_01_EINT_WIDTH                1	/* DCS_DONE_01_EINT */
+#define WM8995_WSEQ_DONE_EINT                   0x0400	/* WSEQ_DONE_EINT */
+#define WM8995_WSEQ_DONE_EINT_MASK              0x0400	/* WSEQ_DONE_EINT */
+#define WM8995_WSEQ_DONE_EINT_SHIFT                 10	/* WSEQ_DONE_EINT */
+#define WM8995_WSEQ_DONE_EINT_WIDTH                  1	/* WSEQ_DONE_EINT */
+#define WM8995_FIFOS_ERR_EINT                   0x0200	/* FIFOS_ERR_EINT */
+#define WM8995_FIFOS_ERR_EINT_MASK              0x0200	/* FIFOS_ERR_EINT */
+#define WM8995_FIFOS_ERR_EINT_SHIFT                  9	/* FIFOS_ERR_EINT */
+#define WM8995_FIFOS_ERR_EINT_WIDTH                  1	/* FIFOS_ERR_EINT */
+#define WM8995_AIF2DRC_SIG_DET_EINT             0x0100	/* AIF2DRC_SIG_DET_EINT */
+#define WM8995_AIF2DRC_SIG_DET_EINT_MASK        0x0100	/* AIF2DRC_SIG_DET_EINT */
+#define WM8995_AIF2DRC_SIG_DET_EINT_SHIFT            8	/* AIF2DRC_SIG_DET_EINT */
+#define WM8995_AIF2DRC_SIG_DET_EINT_WIDTH            1	/* AIF2DRC_SIG_DET_EINT */
+#define WM8995_AIF1DRC2_SIG_DET_EINT            0x0080	/* AIF1DRC2_SIG_DET_EINT */
+#define WM8995_AIF1DRC2_SIG_DET_EINT_MASK       0x0080	/* AIF1DRC2_SIG_DET_EINT */
+#define WM8995_AIF1DRC2_SIG_DET_EINT_SHIFT           7	/* AIF1DRC2_SIG_DET_EINT */
+#define WM8995_AIF1DRC2_SIG_DET_EINT_WIDTH           1	/* AIF1DRC2_SIG_DET_EINT */
+#define WM8995_AIF1DRC1_SIG_DET_EINT            0x0040	/* AIF1DRC1_SIG_DET_EINT */
+#define WM8995_AIF1DRC1_SIG_DET_EINT_MASK       0x0040	/* AIF1DRC1_SIG_DET_EINT */
+#define WM8995_AIF1DRC1_SIG_DET_EINT_SHIFT           6	/* AIF1DRC1_SIG_DET_EINT */
+#define WM8995_AIF1DRC1_SIG_DET_EINT_WIDTH           1	/* AIF1DRC1_SIG_DET_EINT */
+#define WM8995_SRC2_LOCK_EINT                   0x0020	/* SRC2_LOCK_EINT */
+#define WM8995_SRC2_LOCK_EINT_MASK              0x0020	/* SRC2_LOCK_EINT */
+#define WM8995_SRC2_LOCK_EINT_SHIFT                  5	/* SRC2_LOCK_EINT */
+#define WM8995_SRC2_LOCK_EINT_WIDTH                  1	/* SRC2_LOCK_EINT */
+#define WM8995_SRC1_LOCK_EINT                   0x0010	/* SRC1_LOCK_EINT */
+#define WM8995_SRC1_LOCK_EINT_MASK              0x0010	/* SRC1_LOCK_EINT */
+#define WM8995_SRC1_LOCK_EINT_SHIFT                  4	/* SRC1_LOCK_EINT */
+#define WM8995_SRC1_LOCK_EINT_WIDTH                  1	/* SRC1_LOCK_EINT */
+#define WM8995_FLL2_LOCK_EINT                   0x0008	/* FLL2_LOCK_EINT */
+#define WM8995_FLL2_LOCK_EINT_MASK              0x0008	/* FLL2_LOCK_EINT */
+#define WM8995_FLL2_LOCK_EINT_SHIFT                  3	/* FLL2_LOCK_EINT */
+#define WM8995_FLL2_LOCK_EINT_WIDTH                  1	/* FLL2_LOCK_EINT */
+#define WM8995_FLL1_LOCK_EINT                   0x0004	/* FLL1_LOCK_EINT */
+#define WM8995_FLL1_LOCK_EINT_MASK              0x0004	/* FLL1_LOCK_EINT */
+#define WM8995_FLL1_LOCK_EINT_SHIFT                  2	/* FLL1_LOCK_EINT */
+#define WM8995_FLL1_LOCK_EINT_WIDTH                  1	/* FLL1_LOCK_EINT */
+#define WM8995_HP_DONE_EINT                     0x0002	/* HP_DONE_EINT */
+#define WM8995_HP_DONE_EINT_MASK                0x0002	/* HP_DONE_EINT */
+#define WM8995_HP_DONE_EINT_SHIFT                    1	/* HP_DONE_EINT */
+#define WM8995_HP_DONE_EINT_WIDTH                    1	/* HP_DONE_EINT */
+#define WM8995_MICD_EINT                        0x0001	/* MICD_EINT */
+#define WM8995_MICD_EINT_MASK                   0x0001	/* MICD_EINT */
+#define WM8995_MICD_EINT_SHIFT                       0	/* MICD_EINT */
+#define WM8995_MICD_EINT_WIDTH                       1	/* MICD_EINT */
+
+/*
+ * R1842 (0x732) - Interrupt Raw Status 2
+ */
+#define WM8995_DCS_DONE_23_STS                  0x1000	/* DCS_DONE_23_STS */
+#define WM8995_DCS_DONE_23_STS_MASK             0x1000	/* DCS_DONE_23_STS */
+#define WM8995_DCS_DONE_23_STS_SHIFT                12	/* DCS_DONE_23_STS */
+#define WM8995_DCS_DONE_23_STS_WIDTH                 1	/* DCS_DONE_23_STS */
+#define WM8995_DCS_DONE_01_STS                  0x0800	/* DCS_DONE_01_STS */
+#define WM8995_DCS_DONE_01_STS_MASK             0x0800	/* DCS_DONE_01_STS */
+#define WM8995_DCS_DONE_01_STS_SHIFT                11	/* DCS_DONE_01_STS */
+#define WM8995_DCS_DONE_01_STS_WIDTH                 1	/* DCS_DONE_01_STS */
+#define WM8995_WSEQ_DONE_STS                    0x0400	/* WSEQ_DONE_STS */
+#define WM8995_WSEQ_DONE_STS_MASK               0x0400	/* WSEQ_DONE_STS */
+#define WM8995_WSEQ_DONE_STS_SHIFT                  10	/* WSEQ_DONE_STS */
+#define WM8995_WSEQ_DONE_STS_WIDTH                   1	/* WSEQ_DONE_STS */
+#define WM8995_FIFOS_ERR_STS                    0x0200	/* FIFOS_ERR_STS */
+#define WM8995_FIFOS_ERR_STS_MASK               0x0200	/* FIFOS_ERR_STS */
+#define WM8995_FIFOS_ERR_STS_SHIFT                   9	/* FIFOS_ERR_STS */
+#define WM8995_FIFOS_ERR_STS_WIDTH                   1	/* FIFOS_ERR_STS */
+#define WM8995_AIF2DRC_SIG_DET_STS              0x0100	/* AIF2DRC_SIG_DET_STS */
+#define WM8995_AIF2DRC_SIG_DET_STS_MASK         0x0100	/* AIF2DRC_SIG_DET_STS */
+#define WM8995_AIF2DRC_SIG_DET_STS_SHIFT             8	/* AIF2DRC_SIG_DET_STS */
+#define WM8995_AIF2DRC_SIG_DET_STS_WIDTH             1	/* AIF2DRC_SIG_DET_STS */
+#define WM8995_AIF1DRC2_SIG_DET_STS             0x0080	/* AIF1DRC2_SIG_DET_STS */
+#define WM8995_AIF1DRC2_SIG_DET_STS_MASK        0x0080	/* AIF1DRC2_SIG_DET_STS */
+#define WM8995_AIF1DRC2_SIG_DET_STS_SHIFT            7	/* AIF1DRC2_SIG_DET_STS */
+#define WM8995_AIF1DRC2_SIG_DET_STS_WIDTH            1	/* AIF1DRC2_SIG_DET_STS */
+#define WM8995_AIF1DRC1_SIG_DET_STS             0x0040	/* AIF1DRC1_SIG_DET_STS */
+#define WM8995_AIF1DRC1_SIG_DET_STS_MASK        0x0040	/* AIF1DRC1_SIG_DET_STS */
+#define WM8995_AIF1DRC1_SIG_DET_STS_SHIFT            6	/* AIF1DRC1_SIG_DET_STS */
+#define WM8995_AIF1DRC1_SIG_DET_STS_WIDTH            1	/* AIF1DRC1_SIG_DET_STS */
+#define WM8995_SRC2_LOCK_STS                    0x0020	/* SRC2_LOCK_STS */
+#define WM8995_SRC2_LOCK_STS_MASK               0x0020	/* SRC2_LOCK_STS */
+#define WM8995_SRC2_LOCK_STS_SHIFT                   5	/* SRC2_LOCK_STS */
+#define WM8995_SRC2_LOCK_STS_WIDTH                   1	/* SRC2_LOCK_STS */
+#define WM8995_SRC1_LOCK_STS                    0x0010	/* SRC1_LOCK_STS */
+#define WM8995_SRC1_LOCK_STS_MASK               0x0010	/* SRC1_LOCK_STS */
+#define WM8995_SRC1_LOCK_STS_SHIFT                   4	/* SRC1_LOCK_STS */
+#define WM8995_SRC1_LOCK_STS_WIDTH                   1	/* SRC1_LOCK_STS */
+#define WM8995_FLL2_LOCK_STS                    0x0008	/* FLL2_LOCK_STS */
+#define WM8995_FLL2_LOCK_STS_MASK               0x0008	/* FLL2_LOCK_STS */
+#define WM8995_FLL2_LOCK_STS_SHIFT                   3	/* FLL2_LOCK_STS */
+#define WM8995_FLL2_LOCK_STS_WIDTH                   1	/* FLL2_LOCK_STS */
+#define WM8995_FLL1_LOCK_STS                    0x0004	/* FLL1_LOCK_STS */
+#define WM8995_FLL1_LOCK_STS_MASK               0x0004	/* FLL1_LOCK_STS */
+#define WM8995_FLL1_LOCK_STS_SHIFT                   2	/* FLL1_LOCK_STS */
+#define WM8995_FLL1_LOCK_STS_WIDTH                   1	/* FLL1_LOCK_STS */
+
+/*
+ * R1848 (0x738) - Interrupt Status 1 Mask
+ */
+#define WM8995_IM_GP14_EINT                     0x2000	/* IM_GP14_EINT */
+#define WM8995_IM_GP14_EINT_MASK                0x2000	/* IM_GP14_EINT */
+#define WM8995_IM_GP14_EINT_SHIFT                   13	/* IM_GP14_EINT */
+#define WM8995_IM_GP14_EINT_WIDTH                    1	/* IM_GP14_EINT */
+#define WM8995_IM_GP13_EINT                     0x1000	/* IM_GP13_EINT */
+#define WM8995_IM_GP13_EINT_MASK                0x1000	/* IM_GP13_EINT */
+#define WM8995_IM_GP13_EINT_SHIFT                   12	/* IM_GP13_EINT */
+#define WM8995_IM_GP13_EINT_WIDTH                    1	/* IM_GP13_EINT */
+#define WM8995_IM_GP12_EINT                     0x0800	/* IM_GP12_EINT */
+#define WM8995_IM_GP12_EINT_MASK                0x0800	/* IM_GP12_EINT */
+#define WM8995_IM_GP12_EINT_SHIFT                   11	/* IM_GP12_EINT */
+#define WM8995_IM_GP12_EINT_WIDTH                    1	/* IM_GP12_EINT */
+#define WM8995_IM_GP11_EINT                     0x0400	/* IM_GP11_EINT */
+#define WM8995_IM_GP11_EINT_MASK                0x0400	/* IM_GP11_EINT */
+#define WM8995_IM_GP11_EINT_SHIFT                   10	/* IM_GP11_EINT */
+#define WM8995_IM_GP11_EINT_WIDTH                    1	/* IM_GP11_EINT */
+#define WM8995_IM_GP10_EINT                     0x0200	/* IM_GP10_EINT */
+#define WM8995_IM_GP10_EINT_MASK                0x0200	/* IM_GP10_EINT */
+#define WM8995_IM_GP10_EINT_SHIFT                    9	/* IM_GP10_EINT */
+#define WM8995_IM_GP10_EINT_WIDTH                    1	/* IM_GP10_EINT */
+#define WM8995_IM_GP9_EINT                      0x0100	/* IM_GP9_EINT */
+#define WM8995_IM_GP9_EINT_MASK                 0x0100	/* IM_GP9_EINT */
+#define WM8995_IM_GP9_EINT_SHIFT                     8	/* IM_GP9_EINT */
+#define WM8995_IM_GP9_EINT_WIDTH                     1	/* IM_GP9_EINT */
+#define WM8995_IM_GP8_EINT                      0x0080	/* IM_GP8_EINT */
+#define WM8995_IM_GP8_EINT_MASK                 0x0080	/* IM_GP8_EINT */
+#define WM8995_IM_GP8_EINT_SHIFT                     7	/* IM_GP8_EINT */
+#define WM8995_IM_GP8_EINT_WIDTH                     1	/* IM_GP8_EINT */
+#define WM8995_IM_GP7_EINT                      0x0040	/* IM_GP7_EINT */
+#define WM8995_IM_GP7_EINT_MASK                 0x0040	/* IM_GP7_EINT */
+#define WM8995_IM_GP7_EINT_SHIFT                     6	/* IM_GP7_EINT */
+#define WM8995_IM_GP7_EINT_WIDTH                     1	/* IM_GP7_EINT */
+#define WM8995_IM_GP6_EINT                      0x0020	/* IM_GP6_EINT */
+#define WM8995_IM_GP6_EINT_MASK                 0x0020	/* IM_GP6_EINT */
+#define WM8995_IM_GP6_EINT_SHIFT                     5	/* IM_GP6_EINT */
+#define WM8995_IM_GP6_EINT_WIDTH                     1	/* IM_GP6_EINT */
+#define WM8995_IM_GP5_EINT                      0x0010	/* IM_GP5_EINT */
+#define WM8995_IM_GP5_EINT_MASK                 0x0010	/* IM_GP5_EINT */
+#define WM8995_IM_GP5_EINT_SHIFT                     4	/* IM_GP5_EINT */
+#define WM8995_IM_GP5_EINT_WIDTH                     1	/* IM_GP5_EINT */
+#define WM8995_IM_GP4_EINT                      0x0008	/* IM_GP4_EINT */
+#define WM8995_IM_GP4_EINT_MASK                 0x0008	/* IM_GP4_EINT */
+#define WM8995_IM_GP4_EINT_SHIFT                     3	/* IM_GP4_EINT */
+#define WM8995_IM_GP4_EINT_WIDTH                     1	/* IM_GP4_EINT */
+#define WM8995_IM_GP3_EINT                      0x0004	/* IM_GP3_EINT */
+#define WM8995_IM_GP3_EINT_MASK                 0x0004	/* IM_GP3_EINT */
+#define WM8995_IM_GP3_EINT_SHIFT                     2	/* IM_GP3_EINT */
+#define WM8995_IM_GP3_EINT_WIDTH                     1	/* IM_GP3_EINT */
+#define WM8995_IM_GP2_EINT                      0x0002	/* IM_GP2_EINT */
+#define WM8995_IM_GP2_EINT_MASK                 0x0002	/* IM_GP2_EINT */
+#define WM8995_IM_GP2_EINT_SHIFT                     1	/* IM_GP2_EINT */
+#define WM8995_IM_GP2_EINT_WIDTH                     1	/* IM_GP2_EINT */
+#define WM8995_IM_GP1_EINT                      0x0001	/* IM_GP1_EINT */
+#define WM8995_IM_GP1_EINT_MASK                 0x0001	/* IM_GP1_EINT */
+#define WM8995_IM_GP1_EINT_SHIFT                     0	/* IM_GP1_EINT */
+#define WM8995_IM_GP1_EINT_WIDTH                     1	/* IM_GP1_EINT */
+
+/*
+ * R1849 (0x739) - Interrupt Status 2 Mask
+ */
+#define WM8995_IM_DCS_DONE_23_EINT              0x1000	/* IM_DCS_DONE_23_EINT */
+#define WM8995_IM_DCS_DONE_23_EINT_MASK         0x1000	/* IM_DCS_DONE_23_EINT */
+#define WM8995_IM_DCS_DONE_23_EINT_SHIFT            12	/* IM_DCS_DONE_23_EINT */
+#define WM8995_IM_DCS_DONE_23_EINT_WIDTH             1	/* IM_DCS_DONE_23_EINT */
+#define WM8995_IM_DCS_DONE_01_EINT              0x0800	/* IM_DCS_DONE_01_EINT */
+#define WM8995_IM_DCS_DONE_01_EINT_MASK         0x0800	/* IM_DCS_DONE_01_EINT */
+#define WM8995_IM_DCS_DONE_01_EINT_SHIFT            11	/* IM_DCS_DONE_01_EINT */
+#define WM8995_IM_DCS_DONE_01_EINT_WIDTH             1	/* IM_DCS_DONE_01_EINT */
+#define WM8995_IM_WSEQ_DONE_EINT                0x0400	/* IM_WSEQ_DONE_EINT */
+#define WM8995_IM_WSEQ_DONE_EINT_MASK           0x0400	/* IM_WSEQ_DONE_EINT */
+#define WM8995_IM_WSEQ_DONE_EINT_SHIFT              10	/* IM_WSEQ_DONE_EINT */
+#define WM8995_IM_WSEQ_DONE_EINT_WIDTH               1	/* IM_WSEQ_DONE_EINT */
+#define WM8995_IM_FIFOS_ERR_EINT                0x0200	/* IM_FIFOS_ERR_EINT */
+#define WM8995_IM_FIFOS_ERR_EINT_MASK           0x0200	/* IM_FIFOS_ERR_EINT */
+#define WM8995_IM_FIFOS_ERR_EINT_SHIFT               9	/* IM_FIFOS_ERR_EINT */
+#define WM8995_IM_FIFOS_ERR_EINT_WIDTH               1	/* IM_FIFOS_ERR_EINT */
+#define WM8995_IM_AIF2DRC_SIG_DET_EINT          0x0100	/* IM_AIF2DRC_SIG_DET_EINT */
+#define WM8995_IM_AIF2DRC_SIG_DET_EINT_MASK     0x0100	/* IM_AIF2DRC_SIG_DET_EINT */
+#define WM8995_IM_AIF2DRC_SIG_DET_EINT_SHIFT         8	/* IM_AIF2DRC_SIG_DET_EINT */
+#define WM8995_IM_AIF2DRC_SIG_DET_EINT_WIDTH         1	/* IM_AIF2DRC_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC2_SIG_DET_EINT         0x0080	/* IM_AIF1DRC2_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC2_SIG_DET_EINT_MASK    0x0080	/* IM_AIF1DRC2_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC2_SIG_DET_EINT_SHIFT        7	/* IM_AIF1DRC2_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC2_SIG_DET_EINT_WIDTH        1	/* IM_AIF1DRC2_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC1_SIG_DET_EINT         0x0040	/* IM_AIF1DRC1_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC1_SIG_DET_EINT_MASK    0x0040	/* IM_AIF1DRC1_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC1_SIG_DET_EINT_SHIFT        6	/* IM_AIF1DRC1_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC1_SIG_DET_EINT_WIDTH        1	/* IM_AIF1DRC1_SIG_DET_EINT */
+#define WM8995_IM_SRC2_LOCK_EINT                0x0020	/* IM_SRC2_LOCK_EINT */
+#define WM8995_IM_SRC2_LOCK_EINT_MASK           0x0020	/* IM_SRC2_LOCK_EINT */
+#define WM8995_IM_SRC2_LOCK_EINT_SHIFT               5	/* IM_SRC2_LOCK_EINT */
+#define WM8995_IM_SRC2_LOCK_EINT_WIDTH               1	/* IM_SRC2_LOCK_EINT */
+#define WM8995_IM_SRC1_LOCK_EINT                0x0010	/* IM_SRC1_LOCK_EINT */
+#define WM8995_IM_SRC1_LOCK_EINT_MASK           0x0010	/* IM_SRC1_LOCK_EINT */
+#define WM8995_IM_SRC1_LOCK_EINT_SHIFT               4	/* IM_SRC1_LOCK_EINT */
+#define WM8995_IM_SRC1_LOCK_EINT_WIDTH               1	/* IM_SRC1_LOCK_EINT */
+#define WM8995_IM_FLL2_LOCK_EINT                0x0008	/* IM_FLL2_LOCK_EINT */
+#define WM8995_IM_FLL2_LOCK_EINT_MASK           0x0008	/* IM_FLL2_LOCK_EINT */
+#define WM8995_IM_FLL2_LOCK_EINT_SHIFT               3	/* IM_FLL2_LOCK_EINT */
+#define WM8995_IM_FLL2_LOCK_EINT_WIDTH               1	/* IM_FLL2_LOCK_EINT */
+#define WM8995_IM_FLL1_LOCK_EINT                0x0004	/* IM_FLL1_LOCK_EINT */
+#define WM8995_IM_FLL1_LOCK_EINT_MASK           0x0004	/* IM_FLL1_LOCK_EINT */
+#define WM8995_IM_FLL1_LOCK_EINT_SHIFT               2	/* IM_FLL1_LOCK_EINT */
+#define WM8995_IM_FLL1_LOCK_EINT_WIDTH               1	/* IM_FLL1_LOCK_EINT */
+#define WM8995_IM_HP_DONE_EINT                  0x0002	/* IM_HP_DONE_EINT */
+#define WM8995_IM_HP_DONE_EINT_MASK             0x0002	/* IM_HP_DONE_EINT */
+#define WM8995_IM_HP_DONE_EINT_SHIFT                 1	/* IM_HP_DONE_EINT */
+#define WM8995_IM_HP_DONE_EINT_WIDTH                 1	/* IM_HP_DONE_EINT */
+#define WM8995_IM_MICD_EINT                     0x0001	/* IM_MICD_EINT */
+#define WM8995_IM_MICD_EINT_MASK                0x0001	/* IM_MICD_EINT */
+#define WM8995_IM_MICD_EINT_SHIFT                    0	/* IM_MICD_EINT */
+#define WM8995_IM_MICD_EINT_WIDTH                    1	/* IM_MICD_EINT */
+
+/*
+ * R1856 (0x740) - Interrupt Control
+ */
+#define WM8995_IM_IRQ                           0x0001	/* IM_IRQ */
+#define WM8995_IM_IRQ_MASK                      0x0001	/* IM_IRQ */
+#define WM8995_IM_IRQ_SHIFT                          0	/* IM_IRQ */
+#define WM8995_IM_IRQ_WIDTH                          1	/* IM_IRQ */
+
+/*
+ * R2048 (0x800) - Left PDM Speaker 1
+ */
+#define WM8995_SPK1L_ENA                        0x0010	/* SPK1L_ENA */
+#define WM8995_SPK1L_ENA_MASK                   0x0010	/* SPK1L_ENA */
+#define WM8995_SPK1L_ENA_SHIFT                       4	/* SPK1L_ENA */
+#define WM8995_SPK1L_ENA_WIDTH                       1	/* SPK1L_ENA */
+#define WM8995_SPK1L_MUTE                       0x0008	/* SPK1L_MUTE */
+#define WM8995_SPK1L_MUTE_MASK                  0x0008	/* SPK1L_MUTE */
+#define WM8995_SPK1L_MUTE_SHIFT                      3	/* SPK1L_MUTE */
+#define WM8995_SPK1L_MUTE_WIDTH                      1	/* SPK1L_MUTE */
+#define WM8995_SPK1L_MUTE_ZC                    0x0004	/* SPK1L_MUTE_ZC */
+#define WM8995_SPK1L_MUTE_ZC_MASK               0x0004	/* SPK1L_MUTE_ZC */
+#define WM8995_SPK1L_MUTE_ZC_SHIFT                   2	/* SPK1L_MUTE_ZC */
+#define WM8995_SPK1L_MUTE_ZC_WIDTH                   1	/* SPK1L_MUTE_ZC */
+#define WM8995_SPK1L_SRC_MASK                   0x0003	/* SPK1L_SRC - [1:0] */
+#define WM8995_SPK1L_SRC_SHIFT                       0	/* SPK1L_SRC - [1:0] */
+#define WM8995_SPK1L_SRC_WIDTH                       2	/* SPK1L_SRC - [1:0] */
+
+/*
+ * R2049 (0x801) - Right PDM Speaker 1
+ */
+#define WM8995_SPK1R_ENA                        0x0010	/* SPK1R_ENA */
+#define WM8995_SPK1R_ENA_MASK                   0x0010	/* SPK1R_ENA */
+#define WM8995_SPK1R_ENA_SHIFT                       4	/* SPK1R_ENA */
+#define WM8995_SPK1R_ENA_WIDTH                       1	/* SPK1R_ENA */
+#define WM8995_SPK1R_MUTE                       0x0008	/* SPK1R_MUTE */
+#define WM8995_SPK1R_MUTE_MASK                  0x0008	/* SPK1R_MUTE */
+#define WM8995_SPK1R_MUTE_SHIFT                      3	/* SPK1R_MUTE */
+#define WM8995_SPK1R_MUTE_WIDTH                      1	/* SPK1R_MUTE */
+#define WM8995_SPK1R_MUTE_ZC                    0x0004	/* SPK1R_MUTE_ZC */
+#define WM8995_SPK1R_MUTE_ZC_MASK               0x0004	/* SPK1R_MUTE_ZC */
+#define WM8995_SPK1R_MUTE_ZC_SHIFT                   2	/* SPK1R_MUTE_ZC */
+#define WM8995_SPK1R_MUTE_ZC_WIDTH                   1	/* SPK1R_MUTE_ZC */
+#define WM8995_SPK1R_SRC_MASK                   0x0003	/* SPK1R_SRC - [1:0] */
+#define WM8995_SPK1R_SRC_SHIFT                       0	/* SPK1R_SRC - [1:0] */
+#define WM8995_SPK1R_SRC_WIDTH                       2	/* SPK1R_SRC - [1:0] */
+
+/*
+ * R2050 (0x802) - PDM Speaker 1 Mute Sequence
+ */
+#define WM8995_SPK1_MUTE_SEQ1_MASK              0x00FF	/* SPK1_MUTE_SEQ1 - [7:0] */
+#define WM8995_SPK1_MUTE_SEQ1_SHIFT                  0	/* SPK1_MUTE_SEQ1 - [7:0] */
+#define WM8995_SPK1_MUTE_SEQ1_WIDTH                  8	/* SPK1_MUTE_SEQ1 - [7:0] */
+
+/*
+ * R2056 (0x808) - Left PDM Speaker 2
+ */
+#define WM8995_SPK2L_ENA                        0x0010	/* SPK2L_ENA */
+#define WM8995_SPK2L_ENA_MASK                   0x0010	/* SPK2L_ENA */
+#define WM8995_SPK2L_ENA_SHIFT                       4	/* SPK2L_ENA */
+#define WM8995_SPK2L_ENA_WIDTH                       1	/* SPK2L_ENA */
+#define WM8995_SPK2L_MUTE                       0x0008	/* SPK2L_MUTE */
+#define WM8995_SPK2L_MUTE_MASK                  0x0008	/* SPK2L_MUTE */
+#define WM8995_SPK2L_MUTE_SHIFT                      3	/* SPK2L_MUTE */
+#define WM8995_SPK2L_MUTE_WIDTH                      1	/* SPK2L_MUTE */
+#define WM8995_SPK2L_MUTE_ZC                    0x0004	/* SPK2L_MUTE_ZC */
+#define WM8995_SPK2L_MUTE_ZC_MASK               0x0004	/* SPK2L_MUTE_ZC */
+#define WM8995_SPK2L_MUTE_ZC_SHIFT                   2	/* SPK2L_MUTE_ZC */
+#define WM8995_SPK2L_MUTE_ZC_WIDTH                   1	/* SPK2L_MUTE_ZC */
+#define WM8995_SPK2L_SRC_MASK                   0x0003	/* SPK2L_SRC - [1:0] */
+#define WM8995_SPK2L_SRC_SHIFT                       0	/* SPK2L_SRC - [1:0] */
+#define WM8995_SPK2L_SRC_WIDTH                       2	/* SPK2L_SRC - [1:0] */
+
+/*
+ * R2057 (0x809) - Right PDM Speaker 2
+ */
+#define WM8995_SPK2R_ENA                        0x0010	/* SPK2R_ENA */
+#define WM8995_SPK2R_ENA_MASK                   0x0010	/* SPK2R_ENA */
+#define WM8995_SPK2R_ENA_SHIFT                       4	/* SPK2R_ENA */
+#define WM8995_SPK2R_ENA_WIDTH                       1	/* SPK2R_ENA */
+#define WM8995_SPK2R_MUTE                       0x0008	/* SPK2R_MUTE */
+#define WM8995_SPK2R_MUTE_MASK                  0x0008	/* SPK2R_MUTE */
+#define WM8995_SPK2R_MUTE_SHIFT                      3	/* SPK2R_MUTE */
+#define WM8995_SPK2R_MUTE_WIDTH                      1	/* SPK2R_MUTE */
+#define WM8995_SPK2R_MUTE_ZC                    0x0004	/* SPK2R_MUTE_ZC */
+#define WM8995_SPK2R_MUTE_ZC_MASK               0x0004	/* SPK2R_MUTE_ZC */
+#define WM8995_SPK2R_MUTE_ZC_SHIFT                   2	/* SPK2R_MUTE_ZC */
+#define WM8995_SPK2R_MUTE_ZC_WIDTH                   1	/* SPK2R_MUTE_ZC */
+#define WM8995_SPK2R_SRC_MASK                   0x0003	/* SPK2R_SRC - [1:0] */
+#define WM8995_SPK2R_SRC_SHIFT                       0	/* SPK2R_SRC - [1:0] */
+#define WM8995_SPK2R_SRC_WIDTH                       2	/* SPK2R_SRC - [1:0] */
+
+/*
+ * R2058 (0x80A) - PDM Speaker 2 Mute Sequence
+ */
+#define WM8995_SPK2_MUTE_SEQ1_MASK              0x00FF	/* SPK2_MUTE_SEQ1 - [7:0] */
+#define WM8995_SPK2_MUTE_SEQ1_SHIFT                  0	/* SPK2_MUTE_SEQ1 - [7:0] */
+#define WM8995_SPK2_MUTE_SEQ1_WIDTH                  8	/* SPK2_MUTE_SEQ1 - [7:0] */
+
+#define WM8995_CLASS_W_SWITCH(xname, reg, shift, max, invert) \
+	SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
+		snd_soc_dapm_get_volsw, wm8995_put_class_w)
+
+struct wm8995_reg_access {
+	u16 read;
+	u16 write;
+	u16 vol;
+};
+
+/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
+enum clk_src {
+	WM8995_SYSCLK_MCLK1 = 1,
+	WM8995_SYSCLK_MCLK2,
+	WM8995_SYSCLK_FLL1,
+	WM8995_SYSCLK_FLL2,
+	WM8995_SYSCLK_OPCLK
+};
+
+#define WM8995_FLL1 1
+#define WM8995_FLL2 2
+
+#define WM8995_FLL_SRC_MCLK1  1
+#define WM8995_FLL_SRC_MCLK2  2
+#define WM8995_FLL_SRC_LRCLK  3
+#define WM8995_FLL_SRC_BCLK   4
+
+#endif /* _WM8995_H */
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
new file mode 100644
index 0000000..91711f8
--- /dev/null
+++ b/sound/soc/codecs/wm8996.c
@@ -0,0 +1,3107 @@
+/*
+ * wm8996.c - WM8996 audio codec interface
+ *
+ * Copyright 2011-2 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <trace/events/asoc.h>
+
+#include <sound/wm8996.h>
+#include "wm8996.h"
+
+#define WM8996_AIFS 2
+
+#define HPOUT1L 1
+#define HPOUT1R 2
+#define HPOUT2L 4
+#define HPOUT2R 8
+
+#define WM8996_NUM_SUPPLIES 3
+static const char *wm8996_supply_names[WM8996_NUM_SUPPLIES] = {
+	"DBVDD",
+	"AVDD1",
+	"AVDD2",
+};
+
+struct wm8996_priv {
+	struct device *dev;
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+
+	int ldo1ena;
+
+	int sysclk;
+	int sysclk_src;
+
+	int fll_src;
+	int fll_fref;
+	int fll_fout;
+
+	struct completion fll_lock;
+
+	u16 dcs_pending;
+	struct completion dcs_done;
+
+	u16 hpout_ena;
+	u16 hpout_pending;
+
+	struct regulator_bulk_data supplies[WM8996_NUM_SUPPLIES];
+	struct notifier_block disable_nb[WM8996_NUM_SUPPLIES];
+	int bg_ena;
+
+	struct wm8996_pdata pdata;
+
+	int rx_rate[WM8996_AIFS];
+	int bclk_rate[WM8996_AIFS];
+
+	/* Platform dependant ReTune mobile configuration */
+	int num_retune_mobile_texts;
+	const char **retune_mobile_texts;
+	int retune_mobile_cfg[2];
+	struct soc_enum retune_mobile_enum;
+
+	struct snd_soc_jack *jack;
+	bool detecting;
+	bool jack_mic;
+	int jack_flips;
+	wm8996_polarity_fn polarity_cb;
+
+#ifdef CONFIG_GPIOLIB
+	struct gpio_chip gpio_chip;
+#endif
+};
+
+/* We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8996_REGULATOR_EVENT(n) \
+static int wm8996_regulator_event_##n(struct notifier_block *nb, \
+				    unsigned long event, void *data)	\
+{ \
+	struct wm8996_priv *wm8996 = container_of(nb, struct wm8996_priv, \
+						  disable_nb[n]); \
+	if (event & REGULATOR_EVENT_DISABLE) { \
+		regcache_mark_dirty(wm8996->regmap);	\
+	} \
+	return 0; \
+}
+
+WM8996_REGULATOR_EVENT(0)
+WM8996_REGULATOR_EVENT(1)
+WM8996_REGULATOR_EVENT(2)
+
+static const struct reg_default wm8996_reg[] = {
+	{ WM8996_POWER_MANAGEMENT_1, 0x0 },
+	{ WM8996_POWER_MANAGEMENT_2, 0x0 },
+	{ WM8996_POWER_MANAGEMENT_3, 0x0 },
+	{ WM8996_POWER_MANAGEMENT_4, 0x0 },
+	{ WM8996_POWER_MANAGEMENT_5, 0x0 },
+	{ WM8996_POWER_MANAGEMENT_6, 0x0 },
+	{ WM8996_POWER_MANAGEMENT_7, 0x10 },
+	{ WM8996_POWER_MANAGEMENT_8, 0x0 },
+	{ WM8996_LEFT_LINE_INPUT_VOLUME, 0x0 },
+	{ WM8996_RIGHT_LINE_INPUT_VOLUME, 0x0 },
+	{ WM8996_LINE_INPUT_CONTROL, 0x0 },
+	{ WM8996_DAC1_HPOUT1_VOLUME, 0x88 },
+	{ WM8996_DAC2_HPOUT2_VOLUME, 0x88 },
+	{ WM8996_DAC1_LEFT_VOLUME, 0x2c0 },
+	{ WM8996_DAC1_RIGHT_VOLUME, 0x2c0 },
+	{ WM8996_DAC2_LEFT_VOLUME, 0x2c0 },
+	{ WM8996_DAC2_RIGHT_VOLUME, 0x2c0 },
+	{ WM8996_OUTPUT1_LEFT_VOLUME, 0x80 },
+	{ WM8996_OUTPUT1_RIGHT_VOLUME, 0x80 },
+	{ WM8996_OUTPUT2_LEFT_VOLUME, 0x80 },
+	{ WM8996_OUTPUT2_RIGHT_VOLUME, 0x80 },
+	{ WM8996_MICBIAS_1, 0x39 },
+	{ WM8996_MICBIAS_2, 0x39 },
+	{ WM8996_LDO_1, 0x3 },
+	{ WM8996_LDO_2, 0x13 },
+	{ WM8996_ACCESSORY_DETECT_MODE_1, 0x4 },
+	{ WM8996_ACCESSORY_DETECT_MODE_2, 0x0 },
+	{ WM8996_HEADPHONE_DETECT_1, 0x20 },
+	{ WM8996_HEADPHONE_DETECT_2, 0x0 },
+	{ WM8996_MIC_DETECT_1, 0x7600 },
+	{ WM8996_MIC_DETECT_2, 0xbf },
+	{ WM8996_CHARGE_PUMP_1, 0x1f25 },
+	{ WM8996_CHARGE_PUMP_2, 0xab19 },
+	{ WM8996_DC_SERVO_1, 0x0 },
+	{ WM8996_DC_SERVO_3, 0x0 },
+	{ WM8996_DC_SERVO_5, 0x2a2a },
+	{ WM8996_DC_SERVO_6, 0x0 },
+	{ WM8996_DC_SERVO_7, 0x0 },
+	{ WM8996_ANALOGUE_HP_1, 0x0 },
+	{ WM8996_ANALOGUE_HP_2, 0x0 },
+	{ WM8996_CONTROL_INTERFACE_1, 0x8004 },
+	{ WM8996_WRITE_SEQUENCER_CTRL_1, 0x0 },
+	{ WM8996_WRITE_SEQUENCER_CTRL_2, 0x0 },
+	{ WM8996_AIF_CLOCKING_1, 0x0 },
+	{ WM8996_AIF_CLOCKING_2, 0x0 },
+	{ WM8996_CLOCKING_1, 0x10 },
+	{ WM8996_CLOCKING_2, 0x0 },
+	{ WM8996_AIF_RATE, 0x83 },
+	{ WM8996_FLL_CONTROL_1, 0x0 },
+	{ WM8996_FLL_CONTROL_2, 0x0 },
+	{ WM8996_FLL_CONTROL_3, 0x0 },
+	{ WM8996_FLL_CONTROL_4, 0x5dc0 },
+	{ WM8996_FLL_CONTROL_5, 0xc84 },
+	{ WM8996_FLL_EFS_1, 0x0 },
+	{ WM8996_FLL_EFS_2, 0x2 },
+	{ WM8996_AIF1_CONTROL, 0x0 },
+	{ WM8996_AIF1_BCLK, 0x0 },
+	{ WM8996_AIF1_TX_LRCLK_1, 0x80 },
+	{ WM8996_AIF1_TX_LRCLK_2, 0x8 },
+	{ WM8996_AIF1_RX_LRCLK_1, 0x80 },
+	{ WM8996_AIF1_RX_LRCLK_2, 0x0 },
+	{ WM8996_AIF1TX_DATA_CONFIGURATION_1, 0x1818 },
+	{ WM8996_AIF1TX_DATA_CONFIGURATION_2, 0 },
+	{ WM8996_AIF1RX_DATA_CONFIGURATION, 0x1818 },
+	{ WM8996_AIF1TX_CHANNEL_0_CONFIGURATION, 0x0 },
+	{ WM8996_AIF1TX_CHANNEL_1_CONFIGURATION, 0x0 },
+	{ WM8996_AIF1TX_CHANNEL_2_CONFIGURATION, 0x0 },
+	{ WM8996_AIF1TX_CHANNEL_3_CONFIGURATION, 0x0 },
+	{ WM8996_AIF1TX_CHANNEL_4_CONFIGURATION, 0x0 },
+	{ WM8996_AIF1TX_CHANNEL_5_CONFIGURATION, 0x0 },
+	{ WM8996_AIF1RX_CHANNEL_0_CONFIGURATION, 0x0 },
+	{ WM8996_AIF1RX_CHANNEL_1_CONFIGURATION, 0x0 },
+	{ WM8996_AIF1RX_CHANNEL_2_CONFIGURATION, 0x0 },
+	{ WM8996_AIF1RX_CHANNEL_3_CONFIGURATION, 0x0 },
+	{ WM8996_AIF1RX_CHANNEL_4_CONFIGURATION, 0x0 },
+	{ WM8996_AIF1RX_CHANNEL_5_CONFIGURATION, 0x0 },
+	{ WM8996_AIF1RX_MONO_CONFIGURATION, 0x0 },
+	{ WM8996_AIF1TX_TEST, 0x7 },
+	{ WM8996_AIF2_CONTROL, 0x0 },
+	{ WM8996_AIF2_BCLK, 0x0 },
+	{ WM8996_AIF2_TX_LRCLK_1, 0x80 },
+	{ WM8996_AIF2_TX_LRCLK_2, 0x8 },
+	{ WM8996_AIF2_RX_LRCLK_1, 0x80 },
+	{ WM8996_AIF2_RX_LRCLK_2, 0x0 },
+	{ WM8996_AIF2TX_DATA_CONFIGURATION_1, 0x1818 },
+	{ WM8996_AIF2RX_DATA_CONFIGURATION, 0x1818 },
+	{ WM8996_AIF2RX_DATA_CONFIGURATION, 0x0 },
+	{ WM8996_AIF2TX_CHANNEL_0_CONFIGURATION, 0x0 },
+	{ WM8996_AIF2TX_CHANNEL_1_CONFIGURATION, 0x0 },
+	{ WM8996_AIF2RX_CHANNEL_0_CONFIGURATION, 0x0 },
+	{ WM8996_AIF2RX_CHANNEL_1_CONFIGURATION, 0x0 },
+	{ WM8996_AIF2RX_MONO_CONFIGURATION, 0x0 },
+	{ WM8996_AIF2TX_TEST, 0x1 },
+	{ WM8996_DSP1_TX_LEFT_VOLUME, 0xc0 },
+	{ WM8996_DSP1_TX_RIGHT_VOLUME, 0xc0 },
+	{ WM8996_DSP1_RX_LEFT_VOLUME, 0xc0 },
+	{ WM8996_DSP1_RX_RIGHT_VOLUME, 0xc0 },
+	{ WM8996_DSP1_TX_FILTERS, 0x2000 },
+	{ WM8996_DSP1_RX_FILTERS_1, 0x200 },
+	{ WM8996_DSP1_RX_FILTERS_2, 0x10 },
+	{ WM8996_DSP1_DRC_1, 0x98 },
+	{ WM8996_DSP1_DRC_2, 0x845 },
+	{ WM8996_DSP1_RX_EQ_GAINS_1, 0x6318 },
+	{ WM8996_DSP1_RX_EQ_GAINS_2, 0x6300 },
+	{ WM8996_DSP1_RX_EQ_BAND_1_A, 0xfca },
+	{ WM8996_DSP1_RX_EQ_BAND_1_B, 0x400 },
+	{ WM8996_DSP1_RX_EQ_BAND_1_PG, 0xd8 },
+	{ WM8996_DSP1_RX_EQ_BAND_2_A, 0x1eb5 },
+	{ WM8996_DSP1_RX_EQ_BAND_2_B, 0xf145 },
+	{ WM8996_DSP1_RX_EQ_BAND_2_C, 0xb75 },
+	{ WM8996_DSP1_RX_EQ_BAND_2_PG, 0x1c5 },
+	{ WM8996_DSP1_RX_EQ_BAND_3_A, 0x1c58 },
+	{ WM8996_DSP1_RX_EQ_BAND_3_B, 0xf373 },
+	{ WM8996_DSP1_RX_EQ_BAND_3_C, 0xa54 },
+	{ WM8996_DSP1_RX_EQ_BAND_3_PG, 0x558 },
+	{ WM8996_DSP1_RX_EQ_BAND_4_A, 0x168e },
+	{ WM8996_DSP1_RX_EQ_BAND_4_B, 0xf829 },
+	{ WM8996_DSP1_RX_EQ_BAND_4_C, 0x7ad },
+	{ WM8996_DSP1_RX_EQ_BAND_4_PG, 0x1103 },
+	{ WM8996_DSP1_RX_EQ_BAND_5_A, 0x564 },
+	{ WM8996_DSP1_RX_EQ_BAND_5_B, 0x559 },
+	{ WM8996_DSP1_RX_EQ_BAND_5_PG, 0x4000 },
+	{ WM8996_DSP2_TX_LEFT_VOLUME, 0xc0 },
+	{ WM8996_DSP2_TX_RIGHT_VOLUME, 0xc0 },
+	{ WM8996_DSP2_RX_LEFT_VOLUME, 0xc0 },
+	{ WM8996_DSP2_RX_RIGHT_VOLUME, 0xc0 },
+	{ WM8996_DSP2_TX_FILTERS, 0x2000 },
+	{ WM8996_DSP2_RX_FILTERS_1, 0x200 },
+	{ WM8996_DSP2_RX_FILTERS_2, 0x10 },
+	{ WM8996_DSP2_DRC_1, 0x98 },
+	{ WM8996_DSP2_DRC_2, 0x845 },
+	{ WM8996_DSP2_RX_EQ_GAINS_1, 0x6318 },
+	{ WM8996_DSP2_RX_EQ_GAINS_2, 0x6300 },
+	{ WM8996_DSP2_RX_EQ_BAND_1_A, 0xfca },
+	{ WM8996_DSP2_RX_EQ_BAND_1_B, 0x400 },
+	{ WM8996_DSP2_RX_EQ_BAND_1_PG, 0xd8 },
+	{ WM8996_DSP2_RX_EQ_BAND_2_A, 0x1eb5 },
+	{ WM8996_DSP2_RX_EQ_BAND_2_B, 0xf145 },
+	{ WM8996_DSP2_RX_EQ_BAND_2_C, 0xb75 },
+	{ WM8996_DSP2_RX_EQ_BAND_2_PG, 0x1c5 },
+	{ WM8996_DSP2_RX_EQ_BAND_3_A, 0x1c58 },
+	{ WM8996_DSP2_RX_EQ_BAND_3_B, 0xf373 },
+	{ WM8996_DSP2_RX_EQ_BAND_3_C, 0xa54 },
+	{ WM8996_DSP2_RX_EQ_BAND_3_PG, 0x558 },
+	{ WM8996_DSP2_RX_EQ_BAND_4_A, 0x168e },
+	{ WM8996_DSP2_RX_EQ_BAND_4_B, 0xf829 },
+	{ WM8996_DSP2_RX_EQ_BAND_4_C, 0x7ad },
+	{ WM8996_DSP2_RX_EQ_BAND_4_PG, 0x1103 },
+	{ WM8996_DSP2_RX_EQ_BAND_5_A, 0x564 },
+	{ WM8996_DSP2_RX_EQ_BAND_5_B, 0x559 },
+	{ WM8996_DSP2_RX_EQ_BAND_5_PG, 0x4000 },
+	{ WM8996_DAC1_MIXER_VOLUMES, 0x0 },
+	{ WM8996_DAC1_LEFT_MIXER_ROUTING, 0x0 },
+	{ WM8996_DAC1_RIGHT_MIXER_ROUTING, 0x0 },
+	{ WM8996_DAC2_MIXER_VOLUMES, 0x0 },
+	{ WM8996_DAC2_LEFT_MIXER_ROUTING, 0x0 },
+	{ WM8996_DAC2_RIGHT_MIXER_ROUTING, 0x0 },
+	{ WM8996_DSP1_TX_LEFT_MIXER_ROUTING, 0x0 },
+	{ WM8996_DSP1_TX_RIGHT_MIXER_ROUTING, 0x0 },
+	{ WM8996_DSP2_TX_LEFT_MIXER_ROUTING, 0x0 },
+	{ WM8996_DSP2_TX_RIGHT_MIXER_ROUTING, 0x0 },
+	{ WM8996_DSP_TX_MIXER_SELECT, 0x0 },
+	{ WM8996_DAC_SOFTMUTE, 0x0 },
+	{ WM8996_OVERSAMPLING, 0xd },
+	{ WM8996_SIDETONE, 0x1040 },
+	{ WM8996_GPIO_1, 0xa101 },
+	{ WM8996_GPIO_2, 0xa101 },
+	{ WM8996_GPIO_3, 0xa101 },
+	{ WM8996_GPIO_4, 0xa101 },
+	{ WM8996_GPIO_5, 0xa101 },
+	{ WM8996_PULL_CONTROL_1, 0x0 },
+	{ WM8996_PULL_CONTROL_2, 0x140 },
+	{ WM8996_INTERRUPT_STATUS_1_MASK, 0x1f },
+	{ WM8996_INTERRUPT_STATUS_2_MASK, 0x1ecf },
+	{ WM8996_LEFT_PDM_SPEAKER, 0x0 },
+	{ WM8996_RIGHT_PDM_SPEAKER, 0x1 },
+	{ WM8996_PDM_SPEAKER_MUTE_SEQUENCE, 0x69 },
+	{ WM8996_PDM_SPEAKER_VOLUME, 0x66 },
+};
+
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 150, 0);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(out_digital_tlv, -1200, 150, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -900, 75, 0);
+static const DECLARE_TLV_DB_SCALE(spk_tlv, -900, 150, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(threedstereo_tlv, -1600, 183, 1);
+
+static const char *sidetone_hpf_text[] = {
+	"2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(sidetone_hpf,
+			    WM8996_SIDETONE, 7, sidetone_hpf_text);
+
+static const char *hpf_mode_text[] = {
+	"HiFi", "Custom", "Voice"
+};
+
+static SOC_ENUM_SINGLE_DECL(dsp1tx_hpf_mode,
+			    WM8996_DSP1_TX_FILTERS, 3, hpf_mode_text);
+
+static SOC_ENUM_SINGLE_DECL(dsp2tx_hpf_mode,
+			    WM8996_DSP2_TX_FILTERS, 3, hpf_mode_text);
+
+static const char *hpf_cutoff_text[] = {
+	"50Hz", "75Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(dsp1tx_hpf_cutoff,
+			    WM8996_DSP1_TX_FILTERS, 0, hpf_cutoff_text);
+
+static SOC_ENUM_SINGLE_DECL(dsp2tx_hpf_cutoff,
+			    WM8996_DSP2_TX_FILTERS, 0, hpf_cutoff_text);
+
+static void wm8996_set_retune_mobile(struct snd_soc_component *component, int block)
+{
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	struct wm8996_pdata *pdata = &wm8996->pdata;
+	int base, best, best_val, save, i, cfg, iface;
+
+	if (!wm8996->num_retune_mobile_texts)
+		return;
+
+	switch (block) {
+	case 0:
+		base = WM8996_DSP1_RX_EQ_GAINS_1;
+		if (snd_soc_component_read32(component, WM8996_POWER_MANAGEMENT_8) &
+		    WM8996_DSP1RX_SRC)
+			iface = 1;
+		else
+			iface = 0;
+		break;
+	case 1:
+		base = WM8996_DSP1_RX_EQ_GAINS_2;
+		if (snd_soc_component_read32(component, WM8996_POWER_MANAGEMENT_8) &
+		    WM8996_DSP2RX_SRC)
+			iface = 1;
+		else
+			iface = 0;
+		break;
+	default:
+		return;
+	}
+
+	/* Find the version of the currently selected configuration
+	 * with the nearest sample rate. */
+	cfg = wm8996->retune_mobile_cfg[block];
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+		if (strcmp(pdata->retune_mobile_cfgs[i].name,
+			   wm8996->retune_mobile_texts[cfg]) == 0 &&
+		    abs(pdata->retune_mobile_cfgs[i].rate
+			- wm8996->rx_rate[iface]) < best_val) {
+			best = i;
+			best_val = abs(pdata->retune_mobile_cfgs[i].rate
+				       - wm8996->rx_rate[iface]);
+		}
+	}
+
+	dev_dbg(component->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
+		block,
+		pdata->retune_mobile_cfgs[best].name,
+		pdata->retune_mobile_cfgs[best].rate,
+		wm8996->rx_rate[iface]);
+
+	/* The EQ will be disabled while reconfiguring it, remember the
+	 * current configuration. 
+	 */
+	save = snd_soc_component_read32(component, base);
+	save &= WM8996_DSP1RX_EQ_ENA;
+
+	for (i = 0; i < ARRAY_SIZE(pdata->retune_mobile_cfgs[best].regs); i++)
+		snd_soc_component_update_bits(component, base + i, 0xffff,
+				    pdata->retune_mobile_cfgs[best].regs[i]);
+
+	snd_soc_component_update_bits(component, base, WM8996_DSP1RX_EQ_ENA, save);
+}
+
+/* Icky as hell but saves code duplication */
+static int wm8996_get_retune_mobile_block(const char *name)
+{
+	if (strcmp(name, "DSP1 EQ Mode") == 0)
+		return 0;
+	if (strcmp(name, "DSP2 EQ Mode") == 0)
+		return 1;
+	return -EINVAL;
+}
+
+static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	struct wm8996_pdata *pdata = &wm8996->pdata;
+	int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
+	int value = ucontrol->value.enumerated.item[0];
+
+	if (block < 0)
+		return block;
+
+	if (value >= pdata->num_retune_mobile_cfgs)
+		return -EINVAL;
+
+	wm8996->retune_mobile_cfg[block] = value;
+
+	wm8996_set_retune_mobile(component, block);
+
+	return 0;
+}
+
+static int wm8996_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
+
+	if (block < 0)
+		return block;
+	ucontrol->value.enumerated.item[0] = wm8996->retune_mobile_cfg[block];
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new wm8996_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Capture Volume", WM8996_LEFT_LINE_INPUT_VOLUME,
+		 WM8996_RIGHT_LINE_INPUT_VOLUME, 0, 31, 0, inpga_tlv),
+SOC_DOUBLE_R("Capture ZC Switch", WM8996_LEFT_LINE_INPUT_VOLUME,
+	     WM8996_RIGHT_LINE_INPUT_VOLUME, 5, 1, 0),
+
+SOC_DOUBLE_TLV("DAC1 Sidetone Volume", WM8996_DAC1_MIXER_VOLUMES,
+	       0, 5, 24, 0, sidetone_tlv),
+SOC_DOUBLE_TLV("DAC2 Sidetone Volume", WM8996_DAC2_MIXER_VOLUMES,
+	       0, 5, 24, 0, sidetone_tlv),
+SOC_SINGLE("Sidetone LPF Switch", WM8996_SIDETONE, 12, 1, 0),
+SOC_ENUM("Sidetone HPF Cut-off", sidetone_hpf),
+SOC_SINGLE("Sidetone HPF Switch", WM8996_SIDETONE, 6, 1, 0),
+
+SOC_DOUBLE_R_TLV("DSP1 Capture Volume", WM8996_DSP1_TX_LEFT_VOLUME,
+		 WM8996_DSP1_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("DSP2 Capture Volume", WM8996_DSP2_TX_LEFT_VOLUME,
+		 WM8996_DSP2_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+
+SOC_SINGLE("DSP1 Capture Notch Filter Switch", WM8996_DSP1_TX_FILTERS,
+	   13, 1, 0),
+SOC_DOUBLE("DSP1 Capture HPF Switch", WM8996_DSP1_TX_FILTERS, 12, 11, 1, 0),
+SOC_ENUM("DSP1 Capture HPF Mode", dsp1tx_hpf_mode),
+SOC_ENUM("DSP1 Capture HPF Cutoff", dsp1tx_hpf_cutoff),
+
+SOC_SINGLE("DSP2 Capture Notch Filter Switch", WM8996_DSP2_TX_FILTERS,
+	   13, 1, 0),
+SOC_DOUBLE("DSP2 Capture HPF Switch", WM8996_DSP2_TX_FILTERS, 12, 11, 1, 0),
+SOC_ENUM("DSP2 Capture HPF Mode", dsp2tx_hpf_mode),
+SOC_ENUM("DSP2 Capture HPF Cutoff", dsp2tx_hpf_cutoff),
+
+SOC_DOUBLE_R_TLV("DSP1 Playback Volume", WM8996_DSP1_RX_LEFT_VOLUME,
+		 WM8996_DSP1_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_SINGLE("DSP1 Playback Switch", WM8996_DSP1_RX_FILTERS_1, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DSP2 Playback Volume", WM8996_DSP2_RX_LEFT_VOLUME,
+		 WM8996_DSP2_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_SINGLE("DSP2 Playback Switch", WM8996_DSP2_RX_FILTERS_1, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DAC1 Volume", WM8996_DAC1_LEFT_VOLUME,
+		 WM8996_DAC1_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_DOUBLE_R("DAC1 Switch", WM8996_DAC1_LEFT_VOLUME,
+	     WM8996_DAC1_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DAC2 Volume", WM8996_DAC2_LEFT_VOLUME,
+		 WM8996_DAC2_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_DOUBLE_R("DAC2 Switch", WM8996_DAC2_LEFT_VOLUME,
+	     WM8996_DAC2_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_SINGLE("Speaker High Performance Switch", WM8996_OVERSAMPLING, 3, 1, 0),
+SOC_SINGLE("DMIC High Performance Switch", WM8996_OVERSAMPLING, 2, 1, 0),
+SOC_SINGLE("ADC High Performance Switch", WM8996_OVERSAMPLING, 1, 1, 0),
+SOC_SINGLE("DAC High Performance Switch", WM8996_OVERSAMPLING, 0, 1, 0),
+
+SOC_SINGLE("DAC Soft Mute Switch", WM8996_DAC_SOFTMUTE, 1, 1, 0),
+SOC_SINGLE("DAC Slow Soft Mute Switch", WM8996_DAC_SOFTMUTE, 0, 1, 0),
+
+SOC_SINGLE("DSP1 3D Stereo Switch", WM8996_DSP1_RX_FILTERS_2, 8, 1, 0),
+SOC_SINGLE("DSP2 3D Stereo Switch", WM8996_DSP2_RX_FILTERS_2, 8, 1, 0),
+
+SOC_SINGLE_TLV("DSP1 3D Stereo Volume", WM8996_DSP1_RX_FILTERS_2, 10, 15,
+		0, threedstereo_tlv),
+SOC_SINGLE_TLV("DSP2 3D Stereo Volume", WM8996_DSP2_RX_FILTERS_2, 10, 15,
+		0, threedstereo_tlv),
+
+SOC_DOUBLE_TLV("Digital Output 1 Volume", WM8996_DAC1_HPOUT1_VOLUME, 0, 4,
+	       8, 0, out_digital_tlv),
+SOC_DOUBLE_TLV("Digital Output 2 Volume", WM8996_DAC2_HPOUT2_VOLUME, 0, 4,
+	       8, 0, out_digital_tlv),
+
+SOC_DOUBLE_R_TLV("Output 1 Volume", WM8996_OUTPUT1_LEFT_VOLUME,
+		 WM8996_OUTPUT1_RIGHT_VOLUME, 0, 12, 0, out_tlv),
+SOC_DOUBLE_R("Output 1 ZC Switch",  WM8996_OUTPUT1_LEFT_VOLUME,
+	     WM8996_OUTPUT1_RIGHT_VOLUME, 7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Output 2 Volume", WM8996_OUTPUT2_LEFT_VOLUME,
+		 WM8996_OUTPUT2_RIGHT_VOLUME, 0, 12, 0, out_tlv),
+SOC_DOUBLE_R("Output 2 ZC Switch",  WM8996_OUTPUT2_LEFT_VOLUME,
+	     WM8996_OUTPUT2_RIGHT_VOLUME, 7, 1, 0),
+
+SOC_DOUBLE_TLV("Speaker Volume", WM8996_PDM_SPEAKER_VOLUME, 0, 4, 8, 0,
+	       spk_tlv),
+SOC_DOUBLE_R("Speaker Switch", WM8996_LEFT_PDM_SPEAKER,
+	     WM8996_RIGHT_PDM_SPEAKER, 3, 1, 1),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8996_LEFT_PDM_SPEAKER,
+	     WM8996_RIGHT_PDM_SPEAKER, 2, 1, 0),
+
+SOC_SINGLE("DSP1 EQ Switch", WM8996_DSP1_RX_EQ_GAINS_1, 0, 1, 0),
+SOC_SINGLE("DSP2 EQ Switch", WM8996_DSP2_RX_EQ_GAINS_1, 0, 1, 0),
+
+SOC_SINGLE("DSP1 DRC TXL Switch", WM8996_DSP1_DRC_1, 0, 1, 0),
+SOC_SINGLE("DSP1 DRC TXR Switch", WM8996_DSP1_DRC_1, 1, 1, 0),
+SOC_SINGLE("DSP1 DRC RX Switch", WM8996_DSP1_DRC_1, 2, 1, 0),
+SND_SOC_BYTES_MASK("DSP1 DRC", WM8996_DSP1_DRC_1, 5,
+		   WM8996_DSP1RX_DRC_ENA | WM8996_DSP1TXL_DRC_ENA |
+		   WM8996_DSP1TXR_DRC_ENA),
+
+SOC_SINGLE("DSP2 DRC TXL Switch", WM8996_DSP2_DRC_1, 0, 1, 0),
+SOC_SINGLE("DSP2 DRC TXR Switch", WM8996_DSP2_DRC_1, 1, 1, 0),
+SOC_SINGLE("DSP2 DRC RX Switch", WM8996_DSP2_DRC_1, 2, 1, 0),
+SND_SOC_BYTES_MASK("DSP2 DRC", WM8996_DSP2_DRC_1, 5,
+		   WM8996_DSP2RX_DRC_ENA | WM8996_DSP2TXL_DRC_ENA |
+		   WM8996_DSP2TXR_DRC_ENA),
+};
+
+static const struct snd_kcontrol_new wm8996_eq_controls[] = {
+SOC_SINGLE_TLV("DSP1 EQ B1 Volume", WM8996_DSP1_RX_EQ_GAINS_1, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B2 Volume", WM8996_DSP1_RX_EQ_GAINS_1, 6, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B3 Volume", WM8996_DSP1_RX_EQ_GAINS_1, 1, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B4 Volume", WM8996_DSP1_RX_EQ_GAINS_2, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B5 Volume", WM8996_DSP1_RX_EQ_GAINS_2, 6, 31, 0,
+	       eq_tlv),
+
+SOC_SINGLE_TLV("DSP2 EQ B1 Volume", WM8996_DSP2_RX_EQ_GAINS_1, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B2 Volume", WM8996_DSP2_RX_EQ_GAINS_1, 6, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B3 Volume", WM8996_DSP2_RX_EQ_GAINS_1, 1, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B4 Volume", WM8996_DSP2_RX_EQ_GAINS_2, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B5 Volume", WM8996_DSP2_RX_EQ_GAINS_2, 6, 31, 0,
+	       eq_tlv),
+};
+
+static void wm8996_bg_enable(struct snd_soc_component *component)
+{
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+
+	wm8996->bg_ena++;
+	if (wm8996->bg_ena == 1) {
+		snd_soc_component_update_bits(component, WM8996_POWER_MANAGEMENT_1,
+				    WM8996_BG_ENA, WM8996_BG_ENA);
+		msleep(2);
+	}
+}
+
+static void wm8996_bg_disable(struct snd_soc_component *component)
+{
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+
+	wm8996->bg_ena--;
+	if (!wm8996->bg_ena)
+		snd_soc_component_update_bits(component, WM8996_POWER_MANAGEMENT_1,
+				    WM8996_BG_ENA, 0);
+}
+
+static int bg_event(struct snd_soc_dapm_widget *w,
+		    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wm8996_bg_enable(component);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wm8996_bg_disable(component);
+		break;
+	default:
+		WARN(1, "Invalid event %d\n", event);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int cp_event(struct snd_soc_dapm_widget *w,
+		    struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		msleep(5);
+		break;
+	default:
+		WARN(1, "Invalid event %d\n", event);
+	}
+
+	return 0;
+}
+
+static int rmv_short_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+
+	/* Record which outputs we enabled */
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMD:
+		wm8996->hpout_pending &= ~w->shift;
+		break;
+	case SND_SOC_DAPM_PRE_PMU:
+		wm8996->hpout_pending |= w->shift;
+		break;
+	default:
+		WARN(1, "Invalid event %d\n", event);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void wait_for_dc_servo(struct snd_soc_component *component, u16 mask)
+{
+	struct i2c_client *i2c = to_i2c_client(component->dev);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	int ret;
+	unsigned long timeout = 200;
+
+	snd_soc_component_write(component, WM8996_DC_SERVO_2, mask);
+
+	/* Use the interrupt if possible */
+	do {
+		if (i2c->irq) {
+			timeout = wait_for_completion_timeout(&wm8996->dcs_done,
+							      msecs_to_jiffies(200));
+			if (timeout == 0)
+				dev_err(component->dev, "DC servo timed out\n");
+
+		} else {
+			msleep(1);
+			timeout--;
+		}
+
+		ret = snd_soc_component_read32(component, WM8996_DC_SERVO_2);
+		dev_dbg(component->dev, "DC servo state: %x\n", ret);
+	} while (timeout && ret & mask);
+
+	if (timeout == 0)
+		dev_err(component->dev, "DC servo timed out for %x\n", mask);
+	else
+		dev_dbg(component->dev, "DC servo complete for %x\n", mask);
+}
+
+static void wm8996_seq_notifier(struct snd_soc_component *component,
+				enum snd_soc_dapm_type event, int subseq)
+{
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	u16 val, mask;
+
+	/* Complete any pending DC servo starts */
+	if (wm8996->dcs_pending) {
+		dev_dbg(component->dev, "Starting DC servo for %x\n",
+			wm8996->dcs_pending);
+
+		/* Trigger a startup sequence */
+		wait_for_dc_servo(component, wm8996->dcs_pending
+				         << WM8996_DCS_TRIG_STARTUP_0_SHIFT);
+
+		wm8996->dcs_pending = 0;
+	}
+
+	if (wm8996->hpout_pending != wm8996->hpout_ena) {
+		dev_dbg(component->dev, "Applying RMV_SHORTs %x->%x\n",
+			wm8996->hpout_ena, wm8996->hpout_pending);
+
+		val = 0;
+		mask = 0;
+		if (wm8996->hpout_pending & HPOUT1L) {
+			val |= WM8996_HPOUT1L_RMV_SHORT | WM8996_HPOUT1L_OUTP;
+			mask |= WM8996_HPOUT1L_RMV_SHORT | WM8996_HPOUT1L_OUTP;
+		} else {
+			mask |= WM8996_HPOUT1L_RMV_SHORT |
+				WM8996_HPOUT1L_OUTP |
+				WM8996_HPOUT1L_DLY;
+		}
+
+		if (wm8996->hpout_pending & HPOUT1R) {
+			val |= WM8996_HPOUT1R_RMV_SHORT | WM8996_HPOUT1R_OUTP;
+			mask |= WM8996_HPOUT1R_RMV_SHORT | WM8996_HPOUT1R_OUTP;
+		} else {
+			mask |= WM8996_HPOUT1R_RMV_SHORT |
+				WM8996_HPOUT1R_OUTP |
+				WM8996_HPOUT1R_DLY;
+		}
+
+		snd_soc_component_update_bits(component, WM8996_ANALOGUE_HP_1, mask, val);
+
+		val = 0;
+		mask = 0;
+		if (wm8996->hpout_pending & HPOUT2L) {
+			val |= WM8996_HPOUT2L_RMV_SHORT | WM8996_HPOUT2L_OUTP;
+			mask |= WM8996_HPOUT2L_RMV_SHORT | WM8996_HPOUT2L_OUTP;
+		} else {
+			mask |= WM8996_HPOUT2L_RMV_SHORT |
+				WM8996_HPOUT2L_OUTP |
+				WM8996_HPOUT2L_DLY;
+		}
+
+		if (wm8996->hpout_pending & HPOUT2R) {
+			val |= WM8996_HPOUT2R_RMV_SHORT | WM8996_HPOUT2R_OUTP;
+			mask |= WM8996_HPOUT2R_RMV_SHORT | WM8996_HPOUT2R_OUTP;
+		} else {
+			mask |= WM8996_HPOUT2R_RMV_SHORT |
+				WM8996_HPOUT2R_OUTP |
+				WM8996_HPOUT2R_DLY;
+		}
+
+		snd_soc_component_update_bits(component, WM8996_ANALOGUE_HP_2, mask, val);
+
+		wm8996->hpout_ena = wm8996->hpout_pending;
+	}
+}
+
+static int dcs_start(struct snd_soc_dapm_widget *w,
+		     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		wm8996->dcs_pending |= 1 << w->shift;
+		break;
+	default:
+		WARN(1, "Invalid event %d\n", event);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const char *sidetone_text[] = {
+	"IN1", "IN2",
+};
+
+static SOC_ENUM_SINGLE_DECL(left_sidetone_enum,
+			    WM8996_SIDETONE, 0, sidetone_text);
+
+static const struct snd_kcontrol_new left_sidetone =
+	SOC_DAPM_ENUM("Left Sidetone", left_sidetone_enum);
+
+static SOC_ENUM_SINGLE_DECL(right_sidetone_enum,
+			    WM8996_SIDETONE, 1, sidetone_text);
+
+static const struct snd_kcontrol_new right_sidetone =
+	SOC_DAPM_ENUM("Right Sidetone", right_sidetone_enum);
+
+static const char *spk_text[] = {
+	"DAC1L", "DAC1R", "DAC2L", "DAC2R"
+};
+
+static SOC_ENUM_SINGLE_DECL(spkl_enum,
+			    WM8996_LEFT_PDM_SPEAKER, 0, spk_text);
+
+static const struct snd_kcontrol_new spkl_mux =
+	SOC_DAPM_ENUM("SPKL", spkl_enum);
+
+static SOC_ENUM_SINGLE_DECL(spkr_enum,
+			    WM8996_RIGHT_PDM_SPEAKER, 0, spk_text);
+
+static const struct snd_kcontrol_new spkr_mux =
+	SOC_DAPM_ENUM("SPKR", spkr_enum);
+
+static const char *dsp1rx_text[] = {
+	"AIF1", "AIF2"
+};
+
+static SOC_ENUM_SINGLE_DECL(dsp1rx_enum,
+			    WM8996_POWER_MANAGEMENT_8, 0, dsp1rx_text);
+
+static const struct snd_kcontrol_new dsp1rx =
+	SOC_DAPM_ENUM("DSP1RX", dsp1rx_enum);
+
+static const char *dsp2rx_text[] = {
+	 "AIF2", "AIF1"
+};
+
+static SOC_ENUM_SINGLE_DECL(dsp2rx_enum,
+			    WM8996_POWER_MANAGEMENT_8, 4, dsp2rx_text);
+
+static const struct snd_kcontrol_new dsp2rx =
+	SOC_DAPM_ENUM("DSP2RX", dsp2rx_enum);
+
+static const char *aif2tx_text[] = {
+	"DSP2", "DSP1", "AIF1"
+};
+
+static SOC_ENUM_SINGLE_DECL(aif2tx_enum,
+			    WM8996_POWER_MANAGEMENT_8, 6, aif2tx_text);
+
+static const struct snd_kcontrol_new aif2tx =
+	SOC_DAPM_ENUM("AIF2TX", aif2tx_enum);
+
+static const char *inmux_text[] = {
+	"ADC", "DMIC1", "DMIC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(in1_enum,
+			    WM8996_POWER_MANAGEMENT_7, 0, inmux_text);
+
+static const struct snd_kcontrol_new in1_mux =
+	SOC_DAPM_ENUM("IN1 Mux", in1_enum);
+
+static SOC_ENUM_SINGLE_DECL(in2_enum,
+			    WM8996_POWER_MANAGEMENT_7, 4, inmux_text);
+
+static const struct snd_kcontrol_new in2_mux =
+	SOC_DAPM_ENUM("IN2 Mux", in2_enum);
+
+static const struct snd_kcontrol_new dac2r_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8996_DAC2_RIGHT_MIXER_ROUTING,
+		5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8996_DAC2_RIGHT_MIXER_ROUTING,
+		4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8996_DAC2_RIGHT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8996_DAC2_RIGHT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac2l_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8996_DAC2_LEFT_MIXER_ROUTING,
+		5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8996_DAC2_LEFT_MIXER_ROUTING,
+		4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8996_DAC2_LEFT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8996_DAC2_LEFT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1r_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8996_DAC1_RIGHT_MIXER_ROUTING,
+		5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8996_DAC1_RIGHT_MIXER_ROUTING,
+		4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8996_DAC1_RIGHT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8996_DAC1_RIGHT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1l_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8996_DAC1_LEFT_MIXER_ROUTING,
+		5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8996_DAC1_LEFT_MIXER_ROUTING,
+		4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8996_DAC1_LEFT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8996_DAC1_LEFT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp1txl[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8996_DSP1_TX_LEFT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8996_DSP1_TX_LEFT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp1txr[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8996_DSP1_TX_RIGHT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8996_DSP1_TX_RIGHT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp2txl[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8996_DSP2_TX_LEFT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8996_DSP2_TX_LEFT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp2txr[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8996_DSP2_TX_RIGHT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8996_DSP2_TX_RIGHT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+
+static const struct snd_soc_dapm_widget wm8996_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1LN"),
+SND_SOC_DAPM_INPUT("IN1LP"),
+SND_SOC_DAPM_INPUT("IN1RN"),
+SND_SOC_DAPM_INPUT("IN1RP"),
+
+SND_SOC_DAPM_INPUT("IN2LN"),
+SND_SOC_DAPM_INPUT("IN2LP"),
+SND_SOC_DAPM_INPUT("IN2RN"),
+SND_SOC_DAPM_INPUT("IN2RP"),
+
+SND_SOC_DAPM_INPUT("DMIC1DAT"),
+SND_SOC_DAPM_INPUT("DMIC2DAT"),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8996_AIF_CLOCKING_1, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8996_CLOCKING_1, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8996_CLOCKING_1, 2, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8996_CHARGE_PUMP_1, 15, 0, cp_event,
+		      SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_SUPPLY("Bandgap", SND_SOC_NOPM, 0, 0, bg_event,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("LDO2", WM8996_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICB1 Audio", WM8996_MICBIAS_1, 4, 1, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICB2 Audio", WM8996_MICBIAS_2, 4, 1, NULL, 0),
+SND_SOC_DAPM_MICBIAS("MICB2", WM8996_POWER_MANAGEMENT_1, 9, 0),
+SND_SOC_DAPM_MICBIAS("MICB1", WM8996_POWER_MANAGEMENT_1, 8, 0),
+
+SND_SOC_DAPM_PGA("IN1L PGA", WM8996_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN1R PGA", WM8996_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("IN1L Mux", WM8996_POWER_MANAGEMENT_7, 2, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN1R Mux", WM8996_POWER_MANAGEMENT_7, 3, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN2L Mux", WM8996_POWER_MANAGEMENT_7, 6, 0, &in2_mux),
+SND_SOC_DAPM_MUX("IN2R Mux", WM8996_POWER_MANAGEMENT_7, 7, 0, &in2_mux),
+
+SND_SOC_DAPM_SUPPLY("DMIC2", WM8996_POWER_MANAGEMENT_7, 9, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("DMIC1", WM8996_POWER_MANAGEMENT_7, 8, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8996_POWER_MANAGEMENT_3, 5, 0),
+SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8996_POWER_MANAGEMENT_3, 4, 0),
+SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8996_POWER_MANAGEMENT_3, 3, 0),
+SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8996_POWER_MANAGEMENT_3, 2, 0),
+
+SND_SOC_DAPM_ADC("ADCL", NULL, WM8996_POWER_MANAGEMENT_3, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, WM8996_POWER_MANAGEMENT_3, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &left_sidetone),
+SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &right_sidetone),
+
+SND_SOC_DAPM_AIF_IN("DSP2RXL", NULL, 0, WM8996_POWER_MANAGEMENT_3, 11, 0),
+SND_SOC_DAPM_AIF_IN("DSP2RXR", NULL, 1, WM8996_POWER_MANAGEMENT_3, 10, 0),
+SND_SOC_DAPM_AIF_IN("DSP1RXL", NULL, 0, WM8996_POWER_MANAGEMENT_3, 9, 0),
+SND_SOC_DAPM_AIF_IN("DSP1RXR", NULL, 1, WM8996_POWER_MANAGEMENT_3, 8, 0),
+
+SND_SOC_DAPM_MIXER("DSP2TXL", WM8996_POWER_MANAGEMENT_5, 11, 0,
+		   dsp2txl, ARRAY_SIZE(dsp2txl)),
+SND_SOC_DAPM_MIXER("DSP2TXR", WM8996_POWER_MANAGEMENT_5, 10, 0,
+		   dsp2txr, ARRAY_SIZE(dsp2txr)),
+SND_SOC_DAPM_MIXER("DSP1TXL", WM8996_POWER_MANAGEMENT_5, 9, 0,
+		   dsp1txl, ARRAY_SIZE(dsp1txl)),
+SND_SOC_DAPM_MIXER("DSP1TXR", WM8996_POWER_MANAGEMENT_5, 8, 0,
+		   dsp1txr, ARRAY_SIZE(dsp1txr)),
+
+SND_SOC_DAPM_MIXER("DAC2L Mixer", SND_SOC_NOPM, 0, 0,
+		   dac2l_mix, ARRAY_SIZE(dac2l_mix)),
+SND_SOC_DAPM_MIXER("DAC2R Mixer", SND_SOC_NOPM, 0, 0,
+		   dac2r_mix, ARRAY_SIZE(dac2r_mix)),
+SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0,
+		   dac1l_mix, ARRAY_SIZE(dac1l_mix)),
+SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0,
+		   dac1r_mix, ARRAY_SIZE(dac1r_mix)),
+
+SND_SOC_DAPM_DAC("DAC2L", NULL, WM8996_POWER_MANAGEMENT_5, 3, 0),
+SND_SOC_DAPM_DAC("DAC2R", NULL, WM8996_POWER_MANAGEMENT_5, 2, 0),
+SND_SOC_DAPM_DAC("DAC1L", NULL, WM8996_POWER_MANAGEMENT_5, 1, 0),
+SND_SOC_DAPM_DAC("DAC1R", NULL, WM8996_POWER_MANAGEMENT_5, 0, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, WM8996_POWER_MANAGEMENT_4, 9, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX0", NULL, 1, WM8996_POWER_MANAGEMENT_4, 8, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, WM8996_POWER_MANAGEMENT_6, 9, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX0", NULL, 1, WM8996_POWER_MANAGEMENT_6, 8, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 5, WM8996_POWER_MANAGEMENT_4, 5, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 4, WM8996_POWER_MANAGEMENT_4, 4, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 3, WM8996_POWER_MANAGEMENT_4, 3, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 2, WM8996_POWER_MANAGEMENT_4, 2, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 1, WM8996_POWER_MANAGEMENT_4, 1, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX0", NULL, 0, WM8996_POWER_MANAGEMENT_4, 0, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 5, WM8996_POWER_MANAGEMENT_6, 5, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 4, WM8996_POWER_MANAGEMENT_6, 4, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 3, WM8996_POWER_MANAGEMENT_6, 3, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 2, WM8996_POWER_MANAGEMENT_6, 2, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 1, WM8996_POWER_MANAGEMENT_6, 1, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX0", NULL, 0, WM8996_POWER_MANAGEMENT_6, 0, 0),
+
+/* We route as stereo pairs so define some dummy widgets to squash
+ * things down for now.  RXA = 0,1, RXB = 2,3 and so on */
+SND_SOC_DAPM_PGA("AIF1RXA", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF1RXB", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF1RXC", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF2RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("DSP2TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("DSP1RX", SND_SOC_NOPM, 0, 0, &dsp1rx),
+SND_SOC_DAPM_MUX("DSP2RX", SND_SOC_NOPM, 0, 0, &dsp2rx),
+SND_SOC_DAPM_MUX("AIF2TX", SND_SOC_NOPM, 0, 0, &aif2tx),
+
+SND_SOC_DAPM_MUX("SPKL", SND_SOC_NOPM, 0, 0, &spkl_mux),
+SND_SOC_DAPM_MUX("SPKR", SND_SOC_NOPM, 0, 0, &spkr_mux),
+SND_SOC_DAPM_PGA("SPKL PGA", WM8996_LEFT_PDM_SPEAKER, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPKR PGA", WM8996_RIGHT_PDM_SPEAKER, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("HPOUT2L PGA", 0, WM8996_POWER_MANAGEMENT_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_DLY", 1, WM8996_ANALOGUE_HP_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_DCS", 2, WM8996_DC_SERVO_1, 2, 0, dcs_start,
+		   SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT2L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2L, 0,
+		   rmv_short_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT2R PGA", 0, WM8996_POWER_MANAGEMENT_1, 6, 0,NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_DLY", 1, WM8996_ANALOGUE_HP_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_DCS", 2, WM8996_DC_SERVO_1, 3, 0, dcs_start,
+		   SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT2R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2R, 0,
+		   rmv_short_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT1L PGA", 0, WM8996_POWER_MANAGEMENT_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_DLY", 1, WM8996_ANALOGUE_HP_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_DCS", 2, WM8996_DC_SERVO_1, 0, 0, dcs_start,
+		   SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT1L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1L, 0,
+		   rmv_short_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT1R PGA", 0, WM8996_POWER_MANAGEMENT_1, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_DLY", 1, WM8996_ANALOGUE_HP_1, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_DCS", 2, WM8996_DC_SERVO_1, 1, 0, dcs_start,
+		   SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT1R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1R, 0,
+		   rmv_short_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("HPOUT2L"),
+SND_SOC_DAPM_OUTPUT("HPOUT2R"),
+SND_SOC_DAPM_OUTPUT("SPKDAT"),
+};
+
+static const struct snd_soc_dapm_route wm8996_dapm_routes[] = {
+	{ "AIFCLK", NULL, "SYSCLK" },
+	{ "SYSDSPCLK", NULL, "SYSCLK" },
+	{ "Charge Pump", NULL, "SYSCLK" },
+	{ "Charge Pump", NULL, "CPVDD" },
+
+	{ "MICB1", NULL, "LDO2" },
+	{ "MICB1", NULL, "MICB1 Audio" },
+	{ "MICB1", NULL, "Bandgap" },
+	{ "MICB2", NULL, "LDO2" },
+	{ "MICB2", NULL, "MICB2 Audio" },
+	{ "MICB2", NULL, "Bandgap" },
+
+	{ "AIF1RX0", NULL, "AIF1 Playback" },
+	{ "AIF1RX1", NULL, "AIF1 Playback" },
+	{ "AIF1RX2", NULL, "AIF1 Playback" },
+	{ "AIF1RX3", NULL, "AIF1 Playback" },
+	{ "AIF1RX4", NULL, "AIF1 Playback" },
+	{ "AIF1RX5", NULL, "AIF1 Playback" },
+
+	{ "AIF2RX0", NULL, "AIF2 Playback" },
+	{ "AIF2RX1", NULL, "AIF2 Playback" },
+
+	{ "AIF1 Capture", NULL, "AIF1TX0" },
+	{ "AIF1 Capture", NULL, "AIF1TX1" },
+	{ "AIF1 Capture", NULL, "AIF1TX2" },
+	{ "AIF1 Capture", NULL, "AIF1TX3" },
+	{ "AIF1 Capture", NULL, "AIF1TX4" },
+	{ "AIF1 Capture", NULL, "AIF1TX5" },
+
+	{ "AIF2 Capture", NULL, "AIF2TX0" },
+	{ "AIF2 Capture", NULL, "AIF2TX1" },
+
+	{ "IN1L PGA", NULL, "IN2LN" },
+	{ "IN1L PGA", NULL, "IN2LP" },
+	{ "IN1L PGA", NULL, "IN1LN" },
+	{ "IN1L PGA", NULL, "IN1LP" },
+	{ "IN1L PGA", NULL, "Bandgap" },
+
+	{ "IN1R PGA", NULL, "IN2RN" },
+	{ "IN1R PGA", NULL, "IN2RP" },
+	{ "IN1R PGA", NULL, "IN1RN" },
+	{ "IN1R PGA", NULL, "IN1RP" },
+	{ "IN1R PGA", NULL, "Bandgap" },
+
+	{ "ADCL", NULL, "IN1L PGA" },
+
+	{ "ADCR", NULL, "IN1R PGA" },
+
+	{ "DMIC1L", NULL, "DMIC1DAT" },
+	{ "DMIC1R", NULL, "DMIC1DAT" },
+	{ "DMIC2L", NULL, "DMIC2DAT" },
+	{ "DMIC2R", NULL, "DMIC2DAT" },
+
+	{ "DMIC2L", NULL, "DMIC2" },
+	{ "DMIC2R", NULL, "DMIC2" },
+	{ "DMIC1L", NULL, "DMIC1" },
+	{ "DMIC1R", NULL, "DMIC1" },
+
+	{ "IN1L Mux", "ADC", "ADCL" },
+	{ "IN1L Mux", "DMIC1", "DMIC1L" },
+	{ "IN1L Mux", "DMIC2", "DMIC2L" },
+
+	{ "IN1R Mux", "ADC", "ADCR" },
+	{ "IN1R Mux", "DMIC1", "DMIC1R" },
+	{ "IN1R Mux", "DMIC2", "DMIC2R" },
+
+	{ "IN2L Mux", "ADC", "ADCL" },
+	{ "IN2L Mux", "DMIC1", "DMIC1L" },
+	{ "IN2L Mux", "DMIC2", "DMIC2L" },
+
+	{ "IN2R Mux", "ADC", "ADCR" },
+	{ "IN2R Mux", "DMIC1", "DMIC1R" },
+	{ "IN2R Mux", "DMIC2", "DMIC2R" },
+
+	{ "Left Sidetone", "IN1", "IN1L Mux" },
+	{ "Left Sidetone", "IN2", "IN2L Mux" },
+
+	{ "Right Sidetone", "IN1", "IN1R Mux" },
+	{ "Right Sidetone", "IN2", "IN2R Mux" },
+
+	{ "DSP1TXL", "IN1 Switch", "IN1L Mux" },
+	{ "DSP1TXR", "IN1 Switch", "IN1R Mux" },
+
+	{ "DSP2TXL", "IN1 Switch", "IN2L Mux" },
+	{ "DSP2TXR", "IN1 Switch", "IN2R Mux" },
+
+	{ "AIF1TX0", NULL, "DSP1TXL" },
+	{ "AIF1TX1", NULL, "DSP1TXR" },
+	{ "AIF1TX2", NULL, "DSP2TXL" },
+	{ "AIF1TX3", NULL, "DSP2TXR" },
+	{ "AIF1TX4", NULL, "AIF2RX0" },
+	{ "AIF1TX5", NULL, "AIF2RX1" },
+
+	{ "AIF1RX0", NULL, "AIFCLK" },
+	{ "AIF1RX1", NULL, "AIFCLK" },
+	{ "AIF1RX2", NULL, "AIFCLK" },
+	{ "AIF1RX3", NULL, "AIFCLK" },
+	{ "AIF1RX4", NULL, "AIFCLK" },
+	{ "AIF1RX5", NULL, "AIFCLK" },
+
+	{ "AIF2RX0", NULL, "AIFCLK" },
+	{ "AIF2RX1", NULL, "AIFCLK" },
+
+	{ "AIF1TX0", NULL, "AIFCLK" },
+	{ "AIF1TX1", NULL, "AIFCLK" },
+	{ "AIF1TX2", NULL, "AIFCLK" },
+	{ "AIF1TX3", NULL, "AIFCLK" },
+	{ "AIF1TX4", NULL, "AIFCLK" },
+	{ "AIF1TX5", NULL, "AIFCLK" },
+
+	{ "AIF2TX0", NULL, "AIFCLK" },
+	{ "AIF2TX1", NULL, "AIFCLK" },
+
+	{ "DSP1RXL", NULL, "SYSDSPCLK" },
+	{ "DSP1RXR", NULL, "SYSDSPCLK" },
+	{ "DSP2RXL", NULL, "SYSDSPCLK" },
+	{ "DSP2RXR", NULL, "SYSDSPCLK" },
+	{ "DSP1TXL", NULL, "SYSDSPCLK" },
+	{ "DSP1TXR", NULL, "SYSDSPCLK" },
+	{ "DSP2TXL", NULL, "SYSDSPCLK" },
+	{ "DSP2TXR", NULL, "SYSDSPCLK" },
+
+	{ "AIF1RXA", NULL, "AIF1RX0" },
+	{ "AIF1RXA", NULL, "AIF1RX1" },
+	{ "AIF1RXB", NULL, "AIF1RX2" },
+	{ "AIF1RXB", NULL, "AIF1RX3" },
+	{ "AIF1RXC", NULL, "AIF1RX4" },
+	{ "AIF1RXC", NULL, "AIF1RX5" },
+
+	{ "AIF2RX", NULL, "AIF2RX0" },
+	{ "AIF2RX", NULL, "AIF2RX1" },
+
+	{ "AIF2TX", "DSP2", "DSP2TX" },
+	{ "AIF2TX", "DSP1", "DSP1RX" },
+	{ "AIF2TX", "AIF1", "AIF1RXC" },
+
+	{ "DSP1RXL", NULL, "DSP1RX" },
+	{ "DSP1RXR", NULL, "DSP1RX" },
+	{ "DSP2RXL", NULL, "DSP2RX" },
+	{ "DSP2RXR", NULL, "DSP2RX" },
+
+	{ "DSP2TX", NULL, "DSP2TXL" },
+	{ "DSP2TX", NULL, "DSP2TXR" },
+
+	{ "DSP1RX", "AIF1", "AIF1RXA" },
+	{ "DSP1RX", "AIF2", "AIF2RX" },
+
+	{ "DSP2RX", "AIF1", "AIF1RXB" },
+	{ "DSP2RX", "AIF2", "AIF2RX" },
+
+	{ "DAC2L Mixer", "DSP2 Switch", "DSP2RXL" },
+	{ "DAC2L Mixer", "DSP1 Switch", "DSP1RXL" },
+	{ "DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+	{ "DAC2L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+	{ "DAC2R Mixer", "DSP2 Switch", "DSP2RXR" },
+	{ "DAC2R Mixer", "DSP1 Switch", "DSP1RXR" },
+	{ "DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+	{ "DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+	{ "DAC1L Mixer", "DSP2 Switch", "DSP2RXL" },
+	{ "DAC1L Mixer", "DSP1 Switch", "DSP1RXL" },
+	{ "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+	{ "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+	{ "DAC1R Mixer", "DSP2 Switch", "DSP2RXR" },
+	{ "DAC1R Mixer", "DSP1 Switch", "DSP1RXR" },
+	{ "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+	{ "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+	{ "DAC1L", NULL, "DAC1L Mixer" },
+	{ "DAC1R", NULL, "DAC1R Mixer" },
+	{ "DAC2L", NULL, "DAC2L Mixer" },
+	{ "DAC2R", NULL, "DAC2R Mixer" },
+
+	{ "HPOUT2L PGA", NULL, "Charge Pump" },
+	{ "HPOUT2L PGA", NULL, "Bandgap" },
+	{ "HPOUT2L PGA", NULL, "DAC2L" },
+	{ "HPOUT2L_DLY", NULL, "HPOUT2L PGA" },
+	{ "HPOUT2L_DCS", NULL, "HPOUT2L_DLY" },
+	{ "HPOUT2L_RMV_SHORT", NULL, "HPOUT2L_DCS" },
+
+	{ "HPOUT2R PGA", NULL, "Charge Pump" },
+	{ "HPOUT2R PGA", NULL, "Bandgap" },
+	{ "HPOUT2R PGA", NULL, "DAC2R" },
+	{ "HPOUT2R_DLY", NULL, "HPOUT2R PGA" },
+	{ "HPOUT2R_DCS", NULL, "HPOUT2R_DLY" },
+	{ "HPOUT2R_RMV_SHORT", NULL, "HPOUT2R_DCS" },
+
+	{ "HPOUT1L PGA", NULL, "Charge Pump" },
+	{ "HPOUT1L PGA", NULL, "Bandgap" },
+	{ "HPOUT1L PGA", NULL, "DAC1L" },
+	{ "HPOUT1L_DLY", NULL, "HPOUT1L PGA" },
+	{ "HPOUT1L_DCS", NULL, "HPOUT1L_DLY" },
+	{ "HPOUT1L_RMV_SHORT", NULL, "HPOUT1L_DCS" },
+
+	{ "HPOUT1R PGA", NULL, "Charge Pump" },
+	{ "HPOUT1R PGA", NULL, "Bandgap" },
+	{ "HPOUT1R PGA", NULL, "DAC1R" },
+	{ "HPOUT1R_DLY", NULL, "HPOUT1R PGA" },
+	{ "HPOUT1R_DCS", NULL, "HPOUT1R_DLY" },
+	{ "HPOUT1R_RMV_SHORT", NULL, "HPOUT1R_DCS" },
+
+	{ "HPOUT2L", NULL, "HPOUT2L_RMV_SHORT" },
+	{ "HPOUT2R", NULL, "HPOUT2R_RMV_SHORT" },
+	{ "HPOUT1L", NULL, "HPOUT1L_RMV_SHORT" },
+	{ "HPOUT1R", NULL, "HPOUT1R_RMV_SHORT" },
+
+	{ "SPKL", "DAC1L", "DAC1L" },
+	{ "SPKL", "DAC1R", "DAC1R" },
+	{ "SPKL", "DAC2L", "DAC2L" },
+	{ "SPKL", "DAC2R", "DAC2R" },
+
+	{ "SPKR", "DAC1L", "DAC1L" },
+	{ "SPKR", "DAC1R", "DAC1R" },
+	{ "SPKR", "DAC2L", "DAC2L" },
+	{ "SPKR", "DAC2R", "DAC2R" },
+
+	{ "SPKL PGA", NULL, "SPKL" },
+	{ "SPKR PGA", NULL, "SPKR" },
+
+	{ "SPKDAT", NULL, "SPKL PGA" },
+	{ "SPKDAT", NULL, "SPKR PGA" },
+};
+
+static bool wm8996_readable_register(struct device *dev, unsigned int reg)
+{
+	/* Due to the sparseness of the register map the compiler
+	 * output from an explicit switch statement ends up being much
+	 * more efficient than a table.
+	 */
+	switch (reg) {
+	case WM8996_SOFTWARE_RESET:
+	case WM8996_POWER_MANAGEMENT_1:
+	case WM8996_POWER_MANAGEMENT_2:
+	case WM8996_POWER_MANAGEMENT_3:
+	case WM8996_POWER_MANAGEMENT_4:
+	case WM8996_POWER_MANAGEMENT_5:
+	case WM8996_POWER_MANAGEMENT_6:
+	case WM8996_POWER_MANAGEMENT_7:
+	case WM8996_POWER_MANAGEMENT_8:
+	case WM8996_LEFT_LINE_INPUT_VOLUME:
+	case WM8996_RIGHT_LINE_INPUT_VOLUME:
+	case WM8996_LINE_INPUT_CONTROL:
+	case WM8996_DAC1_HPOUT1_VOLUME:
+	case WM8996_DAC2_HPOUT2_VOLUME:
+	case WM8996_DAC1_LEFT_VOLUME:
+	case WM8996_DAC1_RIGHT_VOLUME:
+	case WM8996_DAC2_LEFT_VOLUME:
+	case WM8996_DAC2_RIGHT_VOLUME:
+	case WM8996_OUTPUT1_LEFT_VOLUME:
+	case WM8996_OUTPUT1_RIGHT_VOLUME:
+	case WM8996_OUTPUT2_LEFT_VOLUME:
+	case WM8996_OUTPUT2_RIGHT_VOLUME:
+	case WM8996_MICBIAS_1:
+	case WM8996_MICBIAS_2:
+	case WM8996_LDO_1:
+	case WM8996_LDO_2:
+	case WM8996_ACCESSORY_DETECT_MODE_1:
+	case WM8996_ACCESSORY_DETECT_MODE_2:
+	case WM8996_HEADPHONE_DETECT_1:
+	case WM8996_HEADPHONE_DETECT_2:
+	case WM8996_MIC_DETECT_1:
+	case WM8996_MIC_DETECT_2:
+	case WM8996_MIC_DETECT_3:
+	case WM8996_CHARGE_PUMP_1:
+	case WM8996_CHARGE_PUMP_2:
+	case WM8996_DC_SERVO_1:
+	case WM8996_DC_SERVO_2:
+	case WM8996_DC_SERVO_3:
+	case WM8996_DC_SERVO_5:
+	case WM8996_DC_SERVO_6:
+	case WM8996_DC_SERVO_7:
+	case WM8996_DC_SERVO_READBACK_0:
+	case WM8996_ANALOGUE_HP_1:
+	case WM8996_ANALOGUE_HP_2:
+	case WM8996_CHIP_REVISION:
+	case WM8996_CONTROL_INTERFACE_1:
+	case WM8996_WRITE_SEQUENCER_CTRL_1:
+	case WM8996_WRITE_SEQUENCER_CTRL_2:
+	case WM8996_AIF_CLOCKING_1:
+	case WM8996_AIF_CLOCKING_2:
+	case WM8996_CLOCKING_1:
+	case WM8996_CLOCKING_2:
+	case WM8996_AIF_RATE:
+	case WM8996_FLL_CONTROL_1:
+	case WM8996_FLL_CONTROL_2:
+	case WM8996_FLL_CONTROL_3:
+	case WM8996_FLL_CONTROL_4:
+	case WM8996_FLL_CONTROL_5:
+	case WM8996_FLL_CONTROL_6:
+	case WM8996_FLL_EFS_1:
+	case WM8996_FLL_EFS_2:
+	case WM8996_AIF1_CONTROL:
+	case WM8996_AIF1_BCLK:
+	case WM8996_AIF1_TX_LRCLK_1:
+	case WM8996_AIF1_TX_LRCLK_2:
+	case WM8996_AIF1_RX_LRCLK_1:
+	case WM8996_AIF1_RX_LRCLK_2:
+	case WM8996_AIF1TX_DATA_CONFIGURATION_1:
+	case WM8996_AIF1TX_DATA_CONFIGURATION_2:
+	case WM8996_AIF1RX_DATA_CONFIGURATION:
+	case WM8996_AIF1TX_CHANNEL_0_CONFIGURATION:
+	case WM8996_AIF1TX_CHANNEL_1_CONFIGURATION:
+	case WM8996_AIF1TX_CHANNEL_2_CONFIGURATION:
+	case WM8996_AIF1TX_CHANNEL_3_CONFIGURATION:
+	case WM8996_AIF1TX_CHANNEL_4_CONFIGURATION:
+	case WM8996_AIF1TX_CHANNEL_5_CONFIGURATION:
+	case WM8996_AIF1RX_CHANNEL_0_CONFIGURATION:
+	case WM8996_AIF1RX_CHANNEL_1_CONFIGURATION:
+	case WM8996_AIF1RX_CHANNEL_2_CONFIGURATION:
+	case WM8996_AIF1RX_CHANNEL_3_CONFIGURATION:
+	case WM8996_AIF1RX_CHANNEL_4_CONFIGURATION:
+	case WM8996_AIF1RX_CHANNEL_5_CONFIGURATION:
+	case WM8996_AIF1RX_MONO_CONFIGURATION:
+	case WM8996_AIF1TX_TEST:
+	case WM8996_AIF2_CONTROL:
+	case WM8996_AIF2_BCLK:
+	case WM8996_AIF2_TX_LRCLK_1:
+	case WM8996_AIF2_TX_LRCLK_2:
+	case WM8996_AIF2_RX_LRCLK_1:
+	case WM8996_AIF2_RX_LRCLK_2:
+	case WM8996_AIF2TX_DATA_CONFIGURATION_1:
+	case WM8996_AIF2TX_DATA_CONFIGURATION_2:
+	case WM8996_AIF2RX_DATA_CONFIGURATION:
+	case WM8996_AIF2TX_CHANNEL_0_CONFIGURATION:
+	case WM8996_AIF2TX_CHANNEL_1_CONFIGURATION:
+	case WM8996_AIF2RX_CHANNEL_0_CONFIGURATION:
+	case WM8996_AIF2RX_CHANNEL_1_CONFIGURATION:
+	case WM8996_AIF2RX_MONO_CONFIGURATION:
+	case WM8996_AIF2TX_TEST:
+	case WM8996_DSP1_TX_LEFT_VOLUME:
+	case WM8996_DSP1_TX_RIGHT_VOLUME:
+	case WM8996_DSP1_RX_LEFT_VOLUME:
+	case WM8996_DSP1_RX_RIGHT_VOLUME:
+	case WM8996_DSP1_TX_FILTERS:
+	case WM8996_DSP1_RX_FILTERS_1:
+	case WM8996_DSP1_RX_FILTERS_2:
+	case WM8996_DSP1_DRC_1:
+	case WM8996_DSP1_DRC_2:
+	case WM8996_DSP1_DRC_3:
+	case WM8996_DSP1_DRC_4:
+	case WM8996_DSP1_DRC_5:
+	case WM8996_DSP1_RX_EQ_GAINS_1:
+	case WM8996_DSP1_RX_EQ_GAINS_2:
+	case WM8996_DSP1_RX_EQ_BAND_1_A:
+	case WM8996_DSP1_RX_EQ_BAND_1_B:
+	case WM8996_DSP1_RX_EQ_BAND_1_PG:
+	case WM8996_DSP1_RX_EQ_BAND_2_A:
+	case WM8996_DSP1_RX_EQ_BAND_2_B:
+	case WM8996_DSP1_RX_EQ_BAND_2_C:
+	case WM8996_DSP1_RX_EQ_BAND_2_PG:
+	case WM8996_DSP1_RX_EQ_BAND_3_A:
+	case WM8996_DSP1_RX_EQ_BAND_3_B:
+	case WM8996_DSP1_RX_EQ_BAND_3_C:
+	case WM8996_DSP1_RX_EQ_BAND_3_PG:
+	case WM8996_DSP1_RX_EQ_BAND_4_A:
+	case WM8996_DSP1_RX_EQ_BAND_4_B:
+	case WM8996_DSP1_RX_EQ_BAND_4_C:
+	case WM8996_DSP1_RX_EQ_BAND_4_PG:
+	case WM8996_DSP1_RX_EQ_BAND_5_A:
+	case WM8996_DSP1_RX_EQ_BAND_5_B:
+	case WM8996_DSP1_RX_EQ_BAND_5_PG:
+	case WM8996_DSP2_TX_LEFT_VOLUME:
+	case WM8996_DSP2_TX_RIGHT_VOLUME:
+	case WM8996_DSP2_RX_LEFT_VOLUME:
+	case WM8996_DSP2_RX_RIGHT_VOLUME:
+	case WM8996_DSP2_TX_FILTERS:
+	case WM8996_DSP2_RX_FILTERS_1:
+	case WM8996_DSP2_RX_FILTERS_2:
+	case WM8996_DSP2_DRC_1:
+	case WM8996_DSP2_DRC_2:
+	case WM8996_DSP2_DRC_3:
+	case WM8996_DSP2_DRC_4:
+	case WM8996_DSP2_DRC_5:
+	case WM8996_DSP2_RX_EQ_GAINS_1:
+	case WM8996_DSP2_RX_EQ_GAINS_2:
+	case WM8996_DSP2_RX_EQ_BAND_1_A:
+	case WM8996_DSP2_RX_EQ_BAND_1_B:
+	case WM8996_DSP2_RX_EQ_BAND_1_PG:
+	case WM8996_DSP2_RX_EQ_BAND_2_A:
+	case WM8996_DSP2_RX_EQ_BAND_2_B:
+	case WM8996_DSP2_RX_EQ_BAND_2_C:
+	case WM8996_DSP2_RX_EQ_BAND_2_PG:
+	case WM8996_DSP2_RX_EQ_BAND_3_A:
+	case WM8996_DSP2_RX_EQ_BAND_3_B:
+	case WM8996_DSP2_RX_EQ_BAND_3_C:
+	case WM8996_DSP2_RX_EQ_BAND_3_PG:
+	case WM8996_DSP2_RX_EQ_BAND_4_A:
+	case WM8996_DSP2_RX_EQ_BAND_4_B:
+	case WM8996_DSP2_RX_EQ_BAND_4_C:
+	case WM8996_DSP2_RX_EQ_BAND_4_PG:
+	case WM8996_DSP2_RX_EQ_BAND_5_A:
+	case WM8996_DSP2_RX_EQ_BAND_5_B:
+	case WM8996_DSP2_RX_EQ_BAND_5_PG:
+	case WM8996_DAC1_MIXER_VOLUMES:
+	case WM8996_DAC1_LEFT_MIXER_ROUTING:
+	case WM8996_DAC1_RIGHT_MIXER_ROUTING:
+	case WM8996_DAC2_MIXER_VOLUMES:
+	case WM8996_DAC2_LEFT_MIXER_ROUTING:
+	case WM8996_DAC2_RIGHT_MIXER_ROUTING:
+	case WM8996_DSP1_TX_LEFT_MIXER_ROUTING:
+	case WM8996_DSP1_TX_RIGHT_MIXER_ROUTING:
+	case WM8996_DSP2_TX_LEFT_MIXER_ROUTING:
+	case WM8996_DSP2_TX_RIGHT_MIXER_ROUTING:
+	case WM8996_DSP_TX_MIXER_SELECT:
+	case WM8996_DAC_SOFTMUTE:
+	case WM8996_OVERSAMPLING:
+	case WM8996_SIDETONE:
+	case WM8996_GPIO_1:
+	case WM8996_GPIO_2:
+	case WM8996_GPIO_3:
+	case WM8996_GPIO_4:
+	case WM8996_GPIO_5:
+	case WM8996_PULL_CONTROL_1:
+	case WM8996_PULL_CONTROL_2:
+	case WM8996_INTERRUPT_STATUS_1:
+	case WM8996_INTERRUPT_STATUS_2:
+	case WM8996_INTERRUPT_RAW_STATUS_2:
+	case WM8996_INTERRUPT_STATUS_1_MASK:
+	case WM8996_INTERRUPT_STATUS_2_MASK:
+	case WM8996_INTERRUPT_CONTROL:
+	case WM8996_LEFT_PDM_SPEAKER:
+	case WM8996_RIGHT_PDM_SPEAKER:
+	case WM8996_PDM_SPEAKER_MUTE_SEQUENCE:
+	case WM8996_PDM_SPEAKER_VOLUME:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm8996_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM8996_SOFTWARE_RESET:
+	case WM8996_CHIP_REVISION:
+	case WM8996_LDO_1:
+	case WM8996_LDO_2:
+	case WM8996_INTERRUPT_STATUS_1:
+	case WM8996_INTERRUPT_STATUS_2:
+	case WM8996_INTERRUPT_RAW_STATUS_2:
+	case WM8996_DC_SERVO_READBACK_0:
+	case WM8996_DC_SERVO_2:
+	case WM8996_DC_SERVO_6:
+	case WM8996_DC_SERVO_7:
+	case WM8996_FLL_CONTROL_6:
+	case WM8996_MIC_DETECT_3:
+	case WM8996_HEADPHONE_DETECT_1:
+	case WM8996_HEADPHONE_DETECT_2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const int bclk_divs[] = {
+	1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
+};
+
+static void wm8996_update_bclk(struct snd_soc_component *component)
+{
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	int aif, best, cur_val, bclk_rate, bclk_reg, i;
+
+	/* Don't bother if we're in a low frequency idle mode that
+	 * can't support audio.
+	 */
+	if (wm8996->sysclk < 64000)
+		return;
+
+	for (aif = 0; aif < WM8996_AIFS; aif++) {
+		switch (aif) {
+		case 0:
+			bclk_reg = WM8996_AIF1_BCLK;
+			break;
+		case 1:
+			bclk_reg = WM8996_AIF2_BCLK;
+			break;
+		}
+
+		bclk_rate = wm8996->bclk_rate[aif];
+
+		/* Pick a divisor for BCLK as close as we can get to ideal */
+		best = 0;
+		for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+			cur_val = (wm8996->sysclk / bclk_divs[i]) - bclk_rate;
+			if (cur_val < 0) /* BCLK table is sorted */
+				break;
+			best = i;
+		}
+		bclk_rate = wm8996->sysclk / bclk_divs[best];
+		dev_dbg(component->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
+			bclk_divs[best], bclk_rate);
+
+		snd_soc_component_update_bits(component, bclk_reg,
+				    WM8996_AIF1_BCLK_DIV_MASK, best);
+	}
+}
+
+static int wm8996_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* Put the MICBIASes into regulating mode */
+		snd_soc_component_update_bits(component, WM8996_MICBIAS_1,
+				    WM8996_MICB1_MODE, 0);
+		snd_soc_component_update_bits(component, WM8996_MICBIAS_2,
+				    WM8996_MICB2_MODE, 0);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies),
+						    wm8996->supplies);
+			if (ret != 0) {
+				dev_err(component->dev,
+					"Failed to enable supplies: %d\n",
+					ret);
+				return ret;
+			}
+
+			if (wm8996->pdata.ldo_ena >= 0) {
+				gpio_set_value_cansleep(wm8996->pdata.ldo_ena,
+							1);
+				msleep(5);
+			}
+
+			regcache_cache_only(wm8996->regmap, false);
+			regcache_sync(wm8996->regmap);
+		}
+
+		/* Bypass the MICBIASes for lowest power */
+		snd_soc_component_update_bits(component, WM8996_MICBIAS_1,
+				    WM8996_MICB1_MODE, WM8996_MICB1_MODE);
+		snd_soc_component_update_bits(component, WM8996_MICBIAS_2,
+				    WM8996_MICB2_MODE, WM8996_MICB2_MODE);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		regcache_cache_only(wm8996->regmap, true);
+		if (wm8996->pdata.ldo_ena >= 0) {
+			gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+			regcache_cache_only(wm8996->regmap, true);
+		}
+		regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies),
+				       wm8996->supplies);
+		break;
+	}
+
+	return 0;
+}
+
+static int wm8996_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	int aifctrl = 0;
+	int bclk = 0;
+	int lrclk_tx = 0;
+	int lrclk_rx = 0;
+	int aifctrl_reg, bclk_reg, lrclk_tx_reg, lrclk_rx_reg;
+
+	switch (dai->id) {
+	case 0:
+		aifctrl_reg = WM8996_AIF1_CONTROL;
+		bclk_reg = WM8996_AIF1_BCLK;
+		lrclk_tx_reg = WM8996_AIF1_TX_LRCLK_2;
+		lrclk_rx_reg = WM8996_AIF1_RX_LRCLK_2;
+		break;
+	case 1:
+		aifctrl_reg = WM8996_AIF2_CONTROL;
+		bclk_reg = WM8996_AIF2_BCLK;
+		lrclk_tx_reg = WM8996_AIF2_TX_LRCLK_2;
+		lrclk_rx_reg = WM8996_AIF2_RX_LRCLK_2;
+		break;
+	default:
+		WARN(1, "Invalid dai id %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		bclk |= WM8996_AIF1_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		lrclk_tx |= WM8996_AIF1TX_LRCLK_INV;
+		lrclk_rx |= WM8996_AIF1RX_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		bclk |= WM8996_AIF1_BCLK_INV;
+		lrclk_tx |= WM8996_AIF1TX_LRCLK_INV;
+		lrclk_rx |= WM8996_AIF1RX_LRCLK_INV;
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		lrclk_tx |= WM8996_AIF1TX_LRCLK_MSTR;
+		lrclk_rx |= WM8996_AIF1RX_LRCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		bclk |= WM8996_AIF1_BCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		bclk |= WM8996_AIF1_BCLK_MSTR;
+		lrclk_tx |= WM8996_AIF1TX_LRCLK_MSTR;
+		lrclk_rx |= WM8996_AIF1RX_LRCLK_MSTR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		aifctrl |= 1;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aifctrl |= 2;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aifctrl |= 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_update_bits(component, aifctrl_reg, WM8996_AIF1_FMT_MASK, aifctrl);
+	snd_soc_component_update_bits(component, bclk_reg,
+			    WM8996_AIF1_BCLK_INV | WM8996_AIF1_BCLK_MSTR,
+			    bclk);
+	snd_soc_component_update_bits(component, lrclk_tx_reg,
+			    WM8996_AIF1TX_LRCLK_INV |
+			    WM8996_AIF1TX_LRCLK_MSTR,
+			    lrclk_tx);
+	snd_soc_component_update_bits(component, lrclk_rx_reg,
+			    WM8996_AIF1RX_LRCLK_INV |
+			    WM8996_AIF1RX_LRCLK_MSTR,
+			    lrclk_rx);
+
+	return 0;
+}
+
+static const int dsp_divs[] = {
+	48000, 32000, 16000, 8000
+};
+
+static int wm8996_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	int bits, i, bclk_rate, best;
+	int aifdata = 0;
+	int lrclk = 0;
+	int dsp = 0;
+	int aifdata_reg, lrclk_reg, dsp_shift;
+
+	switch (dai->id) {
+	case 0:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+		    (snd_soc_component_read32(component, WM8996_GPIO_1)) & WM8996_GP1_FN_MASK) {
+			aifdata_reg = WM8996_AIF1RX_DATA_CONFIGURATION;
+			lrclk_reg = WM8996_AIF1_RX_LRCLK_1;
+		} else {
+			aifdata_reg = WM8996_AIF1TX_DATA_CONFIGURATION_1;
+			lrclk_reg = WM8996_AIF1_TX_LRCLK_1;
+		}
+		dsp_shift = 0;
+		break;
+	case 1:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+		    (snd_soc_component_read32(component, WM8996_GPIO_2)) & WM8996_GP2_FN_MASK) {
+			aifdata_reg = WM8996_AIF2RX_DATA_CONFIGURATION;
+			lrclk_reg = WM8996_AIF2_RX_LRCLK_1;
+		} else {
+			aifdata_reg = WM8996_AIF2TX_DATA_CONFIGURATION_1;
+			lrclk_reg = WM8996_AIF2_TX_LRCLK_1;
+		}
+		dsp_shift = WM8996_DSP2_DIV_SHIFT;
+		break;
+	default:
+		WARN(1, "Invalid dai id %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	bclk_rate = snd_soc_params_to_bclk(params);
+	if (bclk_rate < 0) {
+		dev_err(component->dev, "Unsupported BCLK rate: %d\n", bclk_rate);
+		return bclk_rate;
+	}
+
+	wm8996->bclk_rate[dai->id] = bclk_rate;
+	wm8996->rx_rate[dai->id] = params_rate(params);
+
+	/* Needs looking at for TDM */
+	bits = params_width(params);
+	if (bits < 0)
+		return bits;
+	aifdata |= (bits << WM8996_AIF1TX_WL_SHIFT) | bits;
+
+	best = 0;
+	for (i = 0; i < ARRAY_SIZE(dsp_divs); i++) {
+		if (abs(dsp_divs[i] - params_rate(params)) <
+		    abs(dsp_divs[best] - params_rate(params)))
+			best = i;
+	}
+	dsp |= i << dsp_shift;
+
+	wm8996_update_bclk(component);
+
+	lrclk = bclk_rate / params_rate(params);
+	dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
+		lrclk, bclk_rate / lrclk);
+
+	snd_soc_component_update_bits(component, aifdata_reg,
+			    WM8996_AIF1TX_WL_MASK |
+			    WM8996_AIF1TX_SLOT_LEN_MASK,
+			    aifdata);
+	snd_soc_component_update_bits(component, lrclk_reg, WM8996_AIF1RX_RATE_MASK,
+			    lrclk);
+	snd_soc_component_update_bits(component, WM8996_AIF_CLOCKING_2,
+			    WM8996_DSP1_DIV_MASK << dsp_shift, dsp);
+
+	return 0;
+}
+
+static int wm8996_set_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	int lfclk = 0;
+	int ratediv = 0;
+	int sync = WM8996_REG_SYNC;
+	int src;
+	int old;
+
+	if (freq == wm8996->sysclk && clk_id == wm8996->sysclk_src)
+		return 0;
+
+	/* Disable SYSCLK while we reconfigure */
+	old = snd_soc_component_read32(component, WM8996_AIF_CLOCKING_1) & WM8996_SYSCLK_ENA;
+	snd_soc_component_update_bits(component, WM8996_AIF_CLOCKING_1,
+			    WM8996_SYSCLK_ENA, 0);
+
+	switch (clk_id) {
+	case WM8996_SYSCLK_MCLK1:
+		wm8996->sysclk = freq;
+		src = 0;
+		break;
+	case WM8996_SYSCLK_MCLK2:
+		wm8996->sysclk = freq;
+		src = 1;
+		break;
+	case WM8996_SYSCLK_FLL:
+		wm8996->sysclk = freq;
+		src = 2;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported clock source %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	switch (wm8996->sysclk) {
+	case 5644800:
+	case 6144000:
+		snd_soc_component_update_bits(component, WM8996_AIF_RATE,
+				    WM8996_SYSCLK_RATE, 0);
+		break;
+	case 22579200:
+	case 24576000:
+		ratediv = WM8996_SYSCLK_DIV;
+		wm8996->sysclk /= 2;
+		/* fall through */
+	case 11289600:
+	case 12288000:
+		snd_soc_component_update_bits(component, WM8996_AIF_RATE,
+				    WM8996_SYSCLK_RATE, WM8996_SYSCLK_RATE);
+		break;
+	case 32000:
+	case 32768:
+		lfclk = WM8996_LFCLK_ENA;
+		sync = 0;
+		break;
+	default:
+		dev_warn(component->dev, "Unsupported clock rate %dHz\n",
+			 wm8996->sysclk);
+		return -EINVAL;
+	}
+
+	wm8996_update_bclk(component);
+
+	snd_soc_component_update_bits(component, WM8996_AIF_CLOCKING_1,
+			    WM8996_SYSCLK_SRC_MASK | WM8996_SYSCLK_DIV_MASK,
+			    src << WM8996_SYSCLK_SRC_SHIFT | ratediv);
+	snd_soc_component_update_bits(component, WM8996_CLOCKING_1, WM8996_LFCLK_ENA, lfclk);
+	snd_soc_component_update_bits(component, WM8996_CONTROL_INTERFACE_1,
+			    WM8996_REG_SYNC, sync);
+	snd_soc_component_update_bits(component, WM8996_AIF_CLOCKING_1,
+			    WM8996_SYSCLK_ENA, old);
+
+	wm8996->sysclk_src = clk_id;
+
+	return 0;
+}
+
+struct _fll_div {
+	u16 fll_fratio;
+	u16 fll_outdiv;
+	u16 fll_refclk_div;
+	u16 fll_loop_gain;
+	u16 fll_ref_freq;
+	u16 n;
+	u16 theta;
+	u16 lambda;
+};
+
+static struct {
+	unsigned int min;
+	unsigned int max;
+	u16 fll_fratio;
+	int ratio;
+} fll_fratios[] = {
+	{       0,    64000, 4, 16 },
+	{   64000,   128000, 3,  8 },
+	{  128000,   256000, 2,  4 },
+	{  256000,  1000000, 1,  2 },
+	{ 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+		       unsigned int Fout)
+{
+	unsigned int target;
+	unsigned int div;
+	unsigned int fratio, gcd_fll;
+	int i;
+
+	/* Fref must be <=13.5MHz */
+	div = 1;
+	fll_div->fll_refclk_div = 0;
+	while ((Fref / div) > 13500000) {
+		div *= 2;
+		fll_div->fll_refclk_div++;
+
+		if (div > 8) {
+			pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+			       Fref);
+			return -EINVAL;
+		}
+	}
+
+	pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+	/* Apply the division for our remaining calculations */
+	Fref /= div;
+
+	if (Fref >= 3000000)
+		fll_div->fll_loop_gain = 5;
+	else
+		fll_div->fll_loop_gain = 0;
+
+	if (Fref >= 48000)
+		fll_div->fll_ref_freq = 0;
+	else
+		fll_div->fll_ref_freq = 1;
+
+	/* Fvco should be 90-100MHz; don't check the upper bound */
+	div = 2;
+	while (Fout * div < 90000000) {
+		div++;
+		if (div > 64) {
+			pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+			       Fout);
+			return -EINVAL;
+		}
+	}
+	target = Fout * div;
+	fll_div->fll_outdiv = div - 1;
+
+	pr_debug("FLL Fvco=%dHz\n", target);
+
+	/* Find an appropraite FLL_FRATIO and factor it out of the target */
+	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+			fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+			fratio = fll_fratios[i].ratio;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(fll_fratios)) {
+		pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+		return -EINVAL;
+	}
+
+	fll_div->n = target / (fratio * Fref);
+
+	if (target % Fref == 0) {
+		fll_div->theta = 0;
+		fll_div->lambda = 0;
+	} else {
+		gcd_fll = gcd(target, fratio * Fref);
+
+		fll_div->theta = (target - (fll_div->n * fratio * Fref))
+			/ gcd_fll;
+		fll_div->lambda = (fratio * Fref) / gcd_fll;
+	}
+
+	pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+		 fll_div->n, fll_div->theta, fll_div->lambda);
+	pr_debug("FLL_FRATIO=%x FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+		 fll_div->fll_fratio, fll_div->fll_outdiv,
+		 fll_div->fll_refclk_div);
+
+	return 0;
+}
+
+static int wm8996_set_fll(struct snd_soc_component *component, int fll_id, int source,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
+	struct _fll_div fll_div;
+	unsigned long timeout, time_left;
+	int ret, reg, retry;
+
+	/* Any change? */
+	if (source == wm8996->fll_src && Fref == wm8996->fll_fref &&
+	    Fout == wm8996->fll_fout)
+		return 0;
+
+	if (Fout == 0) {
+		dev_dbg(component->dev, "FLL disabled\n");
+
+		wm8996->fll_fref = 0;
+		wm8996->fll_fout = 0;
+
+		snd_soc_component_update_bits(component, WM8996_FLL_CONTROL_1,
+				    WM8996_FLL_ENA, 0);
+
+		wm8996_bg_disable(component);
+
+		return 0;
+	}
+
+	ret = fll_factors(&fll_div, Fref, Fout);
+	if (ret != 0)
+		return ret;
+
+	switch (source) {
+	case WM8996_FLL_MCLK1:
+		reg = 0;
+		break;
+	case WM8996_FLL_MCLK2:
+		reg = 1;
+		break;
+	case WM8996_FLL_DACLRCLK1:
+		reg = 2;
+		break;
+	case WM8996_FLL_BCLK1:
+		reg = 3;
+		break;
+	default:
+		dev_err(component->dev, "Unknown FLL source %d\n", ret);
+		return -EINVAL;
+	}
+
+	reg |= fll_div.fll_refclk_div << WM8996_FLL_REFCLK_DIV_SHIFT;
+	reg |= fll_div.fll_ref_freq << WM8996_FLL_REF_FREQ_SHIFT;
+
+	snd_soc_component_update_bits(component, WM8996_FLL_CONTROL_5,
+			    WM8996_FLL_REFCLK_DIV_MASK | WM8996_FLL_REF_FREQ |
+			    WM8996_FLL_REFCLK_SRC_MASK, reg);
+
+	reg = 0;
+	if (fll_div.theta || fll_div.lambda)
+		reg |= WM8996_FLL_EFS_ENA | (3 << WM8996_FLL_LFSR_SEL_SHIFT);
+	else
+		reg |= 1 << WM8996_FLL_LFSR_SEL_SHIFT;
+	snd_soc_component_write(component, WM8996_FLL_EFS_2, reg);
+
+	snd_soc_component_update_bits(component, WM8996_FLL_CONTROL_2,
+			    WM8996_FLL_OUTDIV_MASK |
+			    WM8996_FLL_FRATIO_MASK,
+			    (fll_div.fll_outdiv << WM8996_FLL_OUTDIV_SHIFT) |
+			    (fll_div.fll_fratio));
+
+	snd_soc_component_write(component, WM8996_FLL_CONTROL_3, fll_div.theta);
+
+	snd_soc_component_update_bits(component, WM8996_FLL_CONTROL_4,
+			    WM8996_FLL_N_MASK | WM8996_FLL_LOOP_GAIN_MASK,
+			    (fll_div.n << WM8996_FLL_N_SHIFT) |
+			    fll_div.fll_loop_gain);
+
+	snd_soc_component_write(component, WM8996_FLL_EFS_1, fll_div.lambda);
+
+	/* Enable the bandgap if it's not already enabled */
+	ret = snd_soc_component_read32(component, WM8996_FLL_CONTROL_1);
+	if (!(ret & WM8996_FLL_ENA))
+		wm8996_bg_enable(component);
+
+	/* Clear any pending completions (eg, from failed startups) */
+	try_wait_for_completion(&wm8996->fll_lock);
+
+	snd_soc_component_update_bits(component, WM8996_FLL_CONTROL_1,
+			    WM8996_FLL_ENA, WM8996_FLL_ENA);
+
+	/* The FLL supports live reconfiguration - kick that in case we were
+	 * already enabled.
+	 */
+	snd_soc_component_write(component, WM8996_FLL_CONTROL_6, WM8996_FLL_SWITCH_CLK);
+
+	/* Wait for the FLL to lock, using the interrupt if possible */
+	if (Fref > 1000000)
+		timeout = usecs_to_jiffies(300);
+	else
+		timeout = msecs_to_jiffies(2);
+
+	/* Allow substantially longer if we've actually got the IRQ, poll
+	 * at a slightly higher rate if we don't.
+	 */
+	if (i2c->irq)
+		timeout *= 10;
+	else
+		/* ensure timeout of atleast 1 jiffies */
+		timeout = timeout/2 ? : 1;
+
+	for (retry = 0; retry < 10; retry++) {
+		time_left = wait_for_completion_timeout(&wm8996->fll_lock,
+							timeout);
+		if (time_left != 0) {
+			WARN_ON(!i2c->irq);
+			ret = 1;
+			break;
+		}
+
+		ret = snd_soc_component_read32(component, WM8996_INTERRUPT_RAW_STATUS_2);
+		if (ret & WM8996_FLL_LOCK_STS)
+			break;
+	}
+	if (retry == 10) {
+		dev_err(component->dev, "Timed out waiting for FLL\n");
+		ret = -ETIMEDOUT;
+	}
+
+	dev_dbg(component->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+
+	wm8996->fll_fref = Fref;
+	wm8996->fll_fout = Fout;
+	wm8996->fll_src = source;
+
+	return ret;
+}
+
+#ifdef CONFIG_GPIOLIB
+static void wm8996_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct wm8996_priv *wm8996 = gpiochip_get_data(chip);
+
+	regmap_update_bits(wm8996->regmap, WM8996_GPIO_1 + offset,
+			   WM8996_GP1_LVL, !!value << WM8996_GP1_LVL_SHIFT);
+}
+
+static int wm8996_gpio_direction_out(struct gpio_chip *chip,
+				     unsigned offset, int value)
+{
+	struct wm8996_priv *wm8996 = gpiochip_get_data(chip);
+	int val;
+
+	val = (1 << WM8996_GP1_FN_SHIFT) | (!!value << WM8996_GP1_LVL_SHIFT);
+
+	return regmap_update_bits(wm8996->regmap, WM8996_GPIO_1 + offset,
+				  WM8996_GP1_FN_MASK | WM8996_GP1_DIR |
+				  WM8996_GP1_LVL, val);
+}
+
+static int wm8996_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct wm8996_priv *wm8996 = gpiochip_get_data(chip);
+	unsigned int reg;
+	int ret;
+
+	ret = regmap_read(wm8996->regmap, WM8996_GPIO_1 + offset, &reg);
+	if (ret < 0)
+		return ret;
+
+	return (reg & WM8996_GP1_LVL) != 0;
+}
+
+static int wm8996_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+	struct wm8996_priv *wm8996 = gpiochip_get_data(chip);
+
+	return regmap_update_bits(wm8996->regmap, WM8996_GPIO_1 + offset,
+				  WM8996_GP1_FN_MASK | WM8996_GP1_DIR,
+				  (1 << WM8996_GP1_FN_SHIFT) |
+				  (1 << WM8996_GP1_DIR_SHIFT));
+}
+
+static const struct gpio_chip wm8996_template_chip = {
+	.label			= "wm8996",
+	.owner			= THIS_MODULE,
+	.direction_output	= wm8996_gpio_direction_out,
+	.set			= wm8996_gpio_set,
+	.direction_input	= wm8996_gpio_direction_in,
+	.get			= wm8996_gpio_get,
+	.can_sleep		= 1,
+};
+
+static void wm8996_init_gpio(struct wm8996_priv *wm8996)
+{
+	int ret;
+
+	wm8996->gpio_chip = wm8996_template_chip;
+	wm8996->gpio_chip.ngpio = 5;
+	wm8996->gpio_chip.parent = wm8996->dev;
+
+	if (wm8996->pdata.gpio_base)
+		wm8996->gpio_chip.base = wm8996->pdata.gpio_base;
+	else
+		wm8996->gpio_chip.base = -1;
+
+	ret = gpiochip_add_data(&wm8996->gpio_chip, wm8996);
+	if (ret != 0)
+		dev_err(wm8996->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm8996_free_gpio(struct wm8996_priv *wm8996)
+{
+	gpiochip_remove(&wm8996->gpio_chip);
+}
+#else
+static void wm8996_init_gpio(struct wm8996_priv *wm8996)
+{
+}
+
+static void wm8996_free_gpio(struct wm8996_priv *wm8996)
+{
+}
+#endif
+
+/**
+ * wm8996_detect - Enable default WM8996 jack detection
+ *
+ * The WM8996 has advanced accessory detection support for headsets.
+ * This function provides a default implementation which integrates
+ * the majority of this functionality with minimal user configuration.
+ *
+ * This will detect headset, headphone and short circuit button and
+ * will also detect inverted microphone ground connections and update
+ * the polarity of the connections.
+ */
+int wm8996_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
+		  wm8996_polarity_fn polarity_cb)
+{
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	wm8996->jack = jack;
+	wm8996->detecting = true;
+	wm8996->polarity_cb = polarity_cb;
+	wm8996->jack_flips = 0;
+
+	if (wm8996->polarity_cb)
+		wm8996->polarity_cb(component, 0);
+
+	/* Clear discarge to avoid noise during detection */
+	snd_soc_component_update_bits(component, WM8996_MICBIAS_1,
+			    WM8996_MICB1_DISCH, 0);
+	snd_soc_component_update_bits(component, WM8996_MICBIAS_2,
+			    WM8996_MICB2_DISCH, 0);
+
+	/* LDO2 powers the microphones, SYSCLK clocks detection */
+	snd_soc_dapm_mutex_lock(dapm);
+
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2");
+	snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK");
+
+	snd_soc_dapm_mutex_unlock(dapm);
+
+	/* We start off just enabling microphone detection - even a
+	 * plain headphone will trigger detection.
+	 */
+	snd_soc_component_update_bits(component, WM8996_MIC_DETECT_1,
+			    WM8996_MICD_ENA, WM8996_MICD_ENA);
+
+	/* Slowest detection rate, gives debounce for initial detection */
+	snd_soc_component_update_bits(component, WM8996_MIC_DETECT_1,
+			    WM8996_MICD_RATE_MASK,
+			    WM8996_MICD_RATE_MASK);
+
+	/* Enable interrupts and we're off */
+	snd_soc_component_update_bits(component, WM8996_INTERRUPT_STATUS_2_MASK,
+			    WM8996_IM_MICD_EINT | WM8996_HP_DONE_EINT, 0);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8996_detect);
+
+static void wm8996_hpdet_irq(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	int val, reg, report;
+
+	/* Assume headphone in error conditions; we need to report
+	 * something or we stall our state machine.
+	 */
+	report = SND_JACK_HEADPHONE;
+
+	reg = snd_soc_component_read32(component, WM8996_HEADPHONE_DETECT_2);
+	if (reg < 0) {
+		dev_err(component->dev, "Failed to read HPDET status\n");
+		goto out;
+	}
+
+	if (!(reg & WM8996_HP_DONE)) {
+		dev_err(component->dev, "Got HPDET IRQ but HPDET is busy\n");
+		goto out;
+	}
+
+	val = reg & WM8996_HP_LVL_MASK;
+
+	dev_dbg(component->dev, "HPDET measured %d ohms\n", val);
+
+	/* If we've got high enough impedence then report as line,
+	 * otherwise assume headphone.
+	 */
+	if (val >= 126)
+		report = SND_JACK_LINEOUT;
+	else
+		report = SND_JACK_HEADPHONE;
+
+out:
+	if (wm8996->jack_mic)
+		report |= SND_JACK_MICROPHONE;
+
+	snd_soc_jack_report(wm8996->jack, report,
+			    SND_JACK_LINEOUT | SND_JACK_HEADSET);
+
+	wm8996->detecting = false;
+
+	/* If the output isn't running re-clamp it */
+	if (!(snd_soc_component_read32(component, WM8996_POWER_MANAGEMENT_1) &
+	      (WM8996_HPOUT1L_ENA | WM8996_HPOUT1R_RMV_SHORT)))
+		snd_soc_component_update_bits(component, WM8996_ANALOGUE_HP_1,
+				    WM8996_HPOUT1L_RMV_SHORT |
+				    WM8996_HPOUT1R_RMV_SHORT, 0);
+
+	/* Go back to looking at the microphone */
+	snd_soc_component_update_bits(component, WM8996_ACCESSORY_DETECT_MODE_1,
+			    WM8996_JD_MODE_MASK, 0);
+	snd_soc_component_update_bits(component, WM8996_MIC_DETECT_1, WM8996_MICD_ENA,
+			    WM8996_MICD_ENA);
+
+	snd_soc_dapm_disable_pin(dapm, "Bandgap");
+	snd_soc_dapm_sync(dapm);
+}
+
+static void wm8996_hpdet_start(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	/* Unclamp the output, we can't measure while we're shorting it */
+	snd_soc_component_update_bits(component, WM8996_ANALOGUE_HP_1,
+			    WM8996_HPOUT1L_RMV_SHORT |
+			    WM8996_HPOUT1R_RMV_SHORT,
+			    WM8996_HPOUT1L_RMV_SHORT |
+			    WM8996_HPOUT1R_RMV_SHORT);
+
+	/* We need bandgap for HPDET */
+	snd_soc_dapm_force_enable_pin(dapm, "Bandgap");
+	snd_soc_dapm_sync(dapm);
+
+	/* Go into headphone detect left mode */
+	snd_soc_component_update_bits(component, WM8996_MIC_DETECT_1, WM8996_MICD_ENA, 0);
+	snd_soc_component_update_bits(component, WM8996_ACCESSORY_DETECT_MODE_1,
+			    WM8996_JD_MODE_MASK, 1);
+
+	/* Trigger a measurement */
+	snd_soc_component_update_bits(component, WM8996_HEADPHONE_DETECT_1,
+			    WM8996_HP_POLL, WM8996_HP_POLL);
+}
+
+static void wm8996_report_headphone(struct snd_soc_component *component)
+{
+	dev_dbg(component->dev, "Headphone detected\n");
+	wm8996_hpdet_start(component);
+
+	/* Increase the detection rate a bit for responsiveness. */
+	snd_soc_component_update_bits(component, WM8996_MIC_DETECT_1,
+			    WM8996_MICD_RATE_MASK |
+			    WM8996_MICD_BIAS_STARTTIME_MASK,
+			    7 << WM8996_MICD_RATE_SHIFT |
+			    7 << WM8996_MICD_BIAS_STARTTIME_SHIFT);
+}
+
+static void wm8996_micd(struct snd_soc_component *component)
+{
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	int val, reg;
+
+	val = snd_soc_component_read32(component, WM8996_MIC_DETECT_3);
+
+	dev_dbg(component->dev, "Microphone event: %x\n", val);
+
+	if (!(val & WM8996_MICD_VALID)) {
+		dev_warn(component->dev, "Microphone detection state invalid\n");
+		return;
+	}
+
+	/* No accessory, reset everything and report removal */
+	if (!(val & WM8996_MICD_STS)) {
+		dev_dbg(component->dev, "Jack removal detected\n");
+		wm8996->jack_mic = false;
+		wm8996->detecting = true;
+		wm8996->jack_flips = 0;
+		snd_soc_jack_report(wm8996->jack, 0,
+				    SND_JACK_LINEOUT | SND_JACK_HEADSET |
+				    SND_JACK_BTN_0);
+
+		snd_soc_component_update_bits(component, WM8996_MIC_DETECT_1,
+				    WM8996_MICD_RATE_MASK |
+				    WM8996_MICD_BIAS_STARTTIME_MASK,
+				    WM8996_MICD_RATE_MASK |
+				    9 << WM8996_MICD_BIAS_STARTTIME_SHIFT);
+		return;
+	}
+
+	/* If the measurement is very high we've got a microphone,
+	 * either we just detected one or if we already reported then
+	 * we've got a button release event.
+	 */
+	if (val & 0x400) {
+		if (wm8996->detecting) {
+			dev_dbg(component->dev, "Microphone detected\n");
+			wm8996->jack_mic = true;
+			wm8996_hpdet_start(component);
+
+			/* Increase poll rate to give better responsiveness
+			 * for buttons */
+			snd_soc_component_update_bits(component, WM8996_MIC_DETECT_1,
+					    WM8996_MICD_RATE_MASK |
+					    WM8996_MICD_BIAS_STARTTIME_MASK,
+					    5 << WM8996_MICD_RATE_SHIFT |
+					    7 << WM8996_MICD_BIAS_STARTTIME_SHIFT);
+		} else {
+			dev_dbg(component->dev, "Mic button up\n");
+			snd_soc_jack_report(wm8996->jack, 0, SND_JACK_BTN_0);
+		}
+
+		return;
+	}
+
+	/* If we detected a lower impedence during initial startup
+	 * then we probably have the wrong polarity, flip it.  Don't
+	 * do this for the lowest impedences to speed up detection of
+	 * plain headphones.  If both polarities report a low
+	 * impedence then give up and report headphones.
+	 */
+	if (wm8996->detecting && (val & 0x3f0)) {
+		wm8996->jack_flips++;
+
+		if (wm8996->jack_flips > 1) {
+			wm8996_report_headphone(component);
+			return;
+		}
+
+		reg = snd_soc_component_read32(component, WM8996_ACCESSORY_DETECT_MODE_2);
+		reg ^= WM8996_HPOUT1FB_SRC | WM8996_MICD_SRC |
+			WM8996_MICD_BIAS_SRC;
+		snd_soc_component_update_bits(component, WM8996_ACCESSORY_DETECT_MODE_2,
+				    WM8996_HPOUT1FB_SRC | WM8996_MICD_SRC |
+				    WM8996_MICD_BIAS_SRC, reg);
+
+		if (wm8996->polarity_cb)
+			wm8996->polarity_cb(component,
+					    (reg & WM8996_MICD_SRC) != 0);
+
+		dev_dbg(component->dev, "Set microphone polarity to %d\n",
+			(reg & WM8996_MICD_SRC) != 0);
+
+		return;
+	}
+
+	/* Don't distinguish between buttons, just report any low
+	 * impedence as BTN_0.
+	 */
+	if (val & 0x3fc) {
+		if (wm8996->jack_mic) {
+			dev_dbg(component->dev, "Mic button detected\n");
+			snd_soc_jack_report(wm8996->jack, SND_JACK_BTN_0,
+					    SND_JACK_BTN_0);
+		} else if (wm8996->detecting) {
+			wm8996_report_headphone(component);
+		}
+	}
+}
+
+static irqreturn_t wm8996_irq(int irq, void *data)
+{
+	struct snd_soc_component *component = data;
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	int irq_val;
+
+	irq_val = snd_soc_component_read32(component, WM8996_INTERRUPT_STATUS_2);
+	if (irq_val < 0) {
+		dev_err(component->dev, "Failed to read IRQ status: %d\n",
+			irq_val);
+		return IRQ_NONE;
+	}
+	irq_val &= ~snd_soc_component_read32(component, WM8996_INTERRUPT_STATUS_2_MASK);
+
+	if (!irq_val)
+		return IRQ_NONE;
+
+	snd_soc_component_write(component, WM8996_INTERRUPT_STATUS_2, irq_val);
+
+	if (irq_val & (WM8996_DCS_DONE_01_EINT | WM8996_DCS_DONE_23_EINT)) {
+		dev_dbg(component->dev, "DC servo IRQ\n");
+		complete(&wm8996->dcs_done);
+	}
+
+	if (irq_val & WM8996_FIFOS_ERR_EINT)
+		dev_err(component->dev, "Digital core FIFO error\n");
+
+	if (irq_val & WM8996_FLL_LOCK_EINT) {
+		dev_dbg(component->dev, "FLL locked\n");
+		complete(&wm8996->fll_lock);
+	}
+
+	if (irq_val & WM8996_MICD_EINT)
+		wm8996_micd(component);
+
+	if (irq_val & WM8996_HP_DONE_EINT)
+		wm8996_hpdet_irq(component);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wm8996_edge_irq(int irq, void *data)
+{
+	irqreturn_t ret = IRQ_NONE;
+	irqreturn_t val;
+
+	do {
+		val = wm8996_irq(irq, data);
+		if (val != IRQ_NONE)
+			ret = val;
+	} while (val != IRQ_NONE);
+
+	return ret;
+}
+
+static void wm8996_retune_mobile_pdata(struct snd_soc_component *component)
+{
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	struct wm8996_pdata *pdata = &wm8996->pdata;
+
+	struct snd_kcontrol_new controls[] = {
+		SOC_ENUM_EXT("DSP1 EQ Mode",
+			     wm8996->retune_mobile_enum,
+			     wm8996_get_retune_mobile_enum,
+			     wm8996_put_retune_mobile_enum),
+		SOC_ENUM_EXT("DSP2 EQ Mode",
+			     wm8996->retune_mobile_enum,
+			     wm8996_get_retune_mobile_enum,
+			     wm8996_put_retune_mobile_enum),
+	};
+	int ret, i, j;
+	const char **t;
+
+	/* We need an array of texts for the enum API but the number
+	 * of texts is likely to be less than the number of
+	 * configurations due to the sample rate dependency of the
+	 * configurations. */
+	wm8996->num_retune_mobile_texts = 0;
+	wm8996->retune_mobile_texts = NULL;
+	for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+		for (j = 0; j < wm8996->num_retune_mobile_texts; j++) {
+			if (strcmp(pdata->retune_mobile_cfgs[i].name,
+				   wm8996->retune_mobile_texts[j]) == 0)
+				break;
+		}
+
+		if (j != wm8996->num_retune_mobile_texts)
+			continue;
+
+		/* Expand the array... */
+		t = krealloc(wm8996->retune_mobile_texts,
+			     sizeof(char *) * 
+			     (wm8996->num_retune_mobile_texts + 1),
+			     GFP_KERNEL);
+		if (t == NULL)
+			continue;
+
+		/* ...store the new entry... */
+		t[wm8996->num_retune_mobile_texts] = 
+			pdata->retune_mobile_cfgs[i].name;
+
+		/* ...and remember the new version. */
+		wm8996->num_retune_mobile_texts++;
+		wm8996->retune_mobile_texts = t;
+	}
+
+	dev_dbg(component->dev, "Allocated %d unique ReTune Mobile names\n",
+		wm8996->num_retune_mobile_texts);
+
+	wm8996->retune_mobile_enum.items = wm8996->num_retune_mobile_texts;
+	wm8996->retune_mobile_enum.texts = wm8996->retune_mobile_texts;
+
+	ret = snd_soc_add_component_controls(component, controls, ARRAY_SIZE(controls));
+	if (ret != 0)
+		dev_err(component->dev,
+			"Failed to add ReTune Mobile controls: %d\n", ret);
+}
+
+static const struct regmap_config wm8996_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+
+	.max_register = WM8996_MAX_REGISTER,
+	.reg_defaults = wm8996_reg,
+	.num_reg_defaults = ARRAY_SIZE(wm8996_reg),
+	.volatile_reg = wm8996_volatile_register,
+	.readable_reg = wm8996_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int wm8996_probe(struct snd_soc_component *component)
+{
+	int ret;
+	struct wm8996_priv *wm8996 = snd_soc_component_get_drvdata(component);
+	struct i2c_client *i2c = to_i2c_client(component->dev);
+	int irq_flags;
+
+	wm8996->component = component;
+
+	init_completion(&wm8996->dcs_done);
+	init_completion(&wm8996->fll_lock);
+
+	if (wm8996->pdata.num_retune_mobile_cfgs)
+		wm8996_retune_mobile_pdata(component);
+	else
+		snd_soc_add_component_controls(component, wm8996_eq_controls,
+				     ARRAY_SIZE(wm8996_eq_controls));
+
+	if (i2c->irq) {
+		if (wm8996->pdata.irq_flags)
+			irq_flags = wm8996->pdata.irq_flags;
+		else
+			irq_flags = IRQF_TRIGGER_LOW;
+
+		irq_flags |= IRQF_ONESHOT;
+
+		if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+			ret = request_threaded_irq(i2c->irq, NULL,
+						   wm8996_edge_irq,
+						   irq_flags, "wm8996", component);
+		else
+			ret = request_threaded_irq(i2c->irq, NULL, wm8996_irq,
+						   irq_flags, "wm8996", component);
+
+		if (ret == 0) {
+			/* Unmask the interrupt */
+			snd_soc_component_update_bits(component, WM8996_INTERRUPT_CONTROL,
+					    WM8996_IM_IRQ, 0);
+
+			/* Enable error reporting and DC servo status */
+			snd_soc_component_update_bits(component,
+					    WM8996_INTERRUPT_STATUS_2_MASK,
+					    WM8996_IM_DCS_DONE_23_EINT |
+					    WM8996_IM_DCS_DONE_01_EINT |
+					    WM8996_IM_FLL_LOCK_EINT |
+					    WM8996_IM_FIFOS_ERR_EINT,
+					    0);
+		} else {
+			dev_err(component->dev, "Failed to request IRQ: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void wm8996_remove(struct snd_soc_component *component)
+{
+	struct i2c_client *i2c = to_i2c_client(component->dev);
+
+	snd_soc_component_update_bits(component, WM8996_INTERRUPT_CONTROL,
+			    WM8996_IM_IRQ, WM8996_IM_IRQ);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, component);
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm8996 = {
+	.probe			= wm8996_probe,
+	.remove			= wm8996_remove,
+	.set_bias_level		= wm8996_set_bias_level,
+	.seq_notifier		= wm8996_seq_notifier,
+	.controls		= wm8996_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8996_snd_controls),
+	.dapm_widgets		= wm8996_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8996_dapm_widgets),
+	.dapm_routes		= wm8996_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8996_dapm_routes),
+	.set_pll		= wm8996_set_fll,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+
+};
+
+#define WM8996_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+		      SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+		      SNDRV_PCM_RATE_48000)
+#define WM8996_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
+			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |\
+			SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm8996_dai_ops = {
+	.set_fmt = wm8996_set_fmt,
+	.hw_params = wm8996_hw_params,
+	.set_sysclk = wm8996_set_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8996_dai[] = {
+	{
+		.name = "wm8996-aif1",
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = WM8996_RATES,
+			.formats = WM8996_FORMATS,
+			.sig_bits = 24,
+		},
+		.capture = {
+			 .stream_name = "AIF1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 6,
+			 .rates = WM8996_RATES,
+			 .formats = WM8996_FORMATS,
+			 .sig_bits = 24,
+		 },
+		.ops = &wm8996_dai_ops,
+	},
+	{
+		.name = "wm8996-aif2",
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8996_RATES,
+			.formats = WM8996_FORMATS,
+			.sig_bits = 24,
+		},
+		.capture = {
+			 .stream_name = "AIF2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM8996_RATES,
+			 .formats = WM8996_FORMATS,
+			.sig_bits = 24,
+		 },
+		.ops = &wm8996_dai_ops,
+	},
+};
+
+static int wm8996_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm8996_priv *wm8996;
+	int ret, i;
+	unsigned int reg;
+
+	wm8996 = devm_kzalloc(&i2c->dev, sizeof(struct wm8996_priv),
+			      GFP_KERNEL);
+	if (wm8996 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, wm8996);
+	wm8996->dev = &i2c->dev;
+
+	if (dev_get_platdata(&i2c->dev))
+		memcpy(&wm8996->pdata, dev_get_platdata(&i2c->dev),
+		       sizeof(wm8996->pdata));
+
+	if (wm8996->pdata.ldo_ena > 0) {
+		ret = gpio_request_one(wm8996->pdata.ldo_ena,
+				       GPIOF_OUT_INIT_LOW, "WM8996 ENA");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request GPIO %d: %d\n",
+				wm8996->pdata.ldo_ena, ret);
+			goto err;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
+		wm8996->supplies[i].supply = wm8996_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8996->supplies),
+				      wm8996->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+		goto err_gpio;
+	}
+
+	wm8996->disable_nb[0].notifier_call = wm8996_regulator_event_0;
+	wm8996->disable_nb[1].notifier_call = wm8996_regulator_event_1;
+	wm8996->disable_nb[2].notifier_call = wm8996_regulator_event_2;
+
+	/* This should really be moved into the regulator core */
+	for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) {
+		ret = regulator_register_notifier(wm8996->supplies[i].consumer,
+						  &wm8996->disable_nb[i]);
+		if (ret != 0) {
+			dev_err(&i2c->dev,
+				"Failed to register regulator notifier: %d\n",
+				ret);
+		}
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies),
+				    wm8996->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		goto err_gpio;
+	}
+
+	if (wm8996->pdata.ldo_ena > 0) {
+		gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 1);
+		msleep(5);
+	}
+
+	wm8996->regmap = devm_regmap_init_i2c(i2c, &wm8996_regmap);
+	if (IS_ERR(wm8996->regmap)) {
+		ret = PTR_ERR(wm8996->regmap);
+		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+		goto err_enable;
+	}
+
+	ret = regmap_read(wm8996->regmap, WM8996_SOFTWARE_RESET, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
+		goto err_regmap;
+	}
+	if (reg != 0x8915) {
+		dev_err(&i2c->dev, "Device is not a WM8996, ID %x\n", reg);
+		ret = -EINVAL;
+		goto err_regmap;
+	}
+
+	ret = regmap_read(wm8996->regmap, WM8996_CHIP_REVISION, &reg);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read device revision: %d\n",
+			ret);
+		goto err_regmap;
+	}
+
+	dev_info(&i2c->dev, "revision %c\n",
+		 (reg & WM8996_CHIP_REV_MASK) + 'A');
+
+	if (wm8996->pdata.ldo_ena > 0) {
+		gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+		regcache_cache_only(wm8996->regmap, true);
+	} else {
+		ret = regmap_write(wm8996->regmap, WM8996_SOFTWARE_RESET,
+				   0x8915);
+		if (ret != 0) {
+			dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
+			goto err_regmap;
+		}
+	}
+
+	regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
+
+	/* Apply platform data settings */
+	regmap_update_bits(wm8996->regmap, WM8996_LINE_INPUT_CONTROL,
+			   WM8996_INL_MODE_MASK | WM8996_INR_MODE_MASK,
+			   wm8996->pdata.inl_mode << WM8996_INL_MODE_SHIFT |
+			   wm8996->pdata.inr_mode);
+
+	for (i = 0; i < ARRAY_SIZE(wm8996->pdata.gpio_default); i++) {
+		if (!wm8996->pdata.gpio_default[i])
+			continue;
+
+		regmap_write(wm8996->regmap, WM8996_GPIO_1 + i,
+			     wm8996->pdata.gpio_default[i] & 0xffff);
+	}
+
+	if (wm8996->pdata.spkmute_seq)
+		regmap_update_bits(wm8996->regmap,
+				   WM8996_PDM_SPEAKER_MUTE_SEQUENCE,
+				   WM8996_SPK_MUTE_ENDIAN |
+				   WM8996_SPK_MUTE_SEQ1_MASK,
+				   wm8996->pdata.spkmute_seq);
+
+	regmap_update_bits(wm8996->regmap, WM8996_ACCESSORY_DETECT_MODE_2,
+			   WM8996_MICD_BIAS_SRC | WM8996_HPOUT1FB_SRC |
+			   WM8996_MICD_SRC, wm8996->pdata.micdet_def);
+
+	/* Latch volume update bits */
+	regmap_update_bits(wm8996->regmap, WM8996_LEFT_LINE_INPUT_VOLUME,
+			   WM8996_IN1_VU, WM8996_IN1_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_RIGHT_LINE_INPUT_VOLUME,
+			   WM8996_IN1_VU, WM8996_IN1_VU);
+
+	regmap_update_bits(wm8996->regmap, WM8996_DAC1_LEFT_VOLUME,
+			   WM8996_DAC1_VU, WM8996_DAC1_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DAC1_RIGHT_VOLUME,
+			   WM8996_DAC1_VU, WM8996_DAC1_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DAC2_LEFT_VOLUME,
+			   WM8996_DAC2_VU, WM8996_DAC2_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DAC2_RIGHT_VOLUME,
+			   WM8996_DAC2_VU, WM8996_DAC2_VU);
+
+	regmap_update_bits(wm8996->regmap, WM8996_OUTPUT1_LEFT_VOLUME,
+			   WM8996_DAC1_VU, WM8996_DAC1_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_OUTPUT1_RIGHT_VOLUME,
+			   WM8996_DAC1_VU, WM8996_DAC1_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_OUTPUT2_LEFT_VOLUME,
+			   WM8996_DAC2_VU, WM8996_DAC2_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_OUTPUT2_RIGHT_VOLUME,
+			   WM8996_DAC2_VU, WM8996_DAC2_VU);
+
+	regmap_update_bits(wm8996->regmap, WM8996_DSP1_TX_LEFT_VOLUME,
+			   WM8996_DSP1TX_VU, WM8996_DSP1TX_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DSP1_TX_RIGHT_VOLUME,
+			   WM8996_DSP1TX_VU, WM8996_DSP1TX_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DSP2_TX_LEFT_VOLUME,
+			   WM8996_DSP2TX_VU, WM8996_DSP2TX_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DSP2_TX_RIGHT_VOLUME,
+			   WM8996_DSP2TX_VU, WM8996_DSP2TX_VU);
+
+	regmap_update_bits(wm8996->regmap, WM8996_DSP1_RX_LEFT_VOLUME,
+			   WM8996_DSP1RX_VU, WM8996_DSP1RX_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DSP1_RX_RIGHT_VOLUME,
+			   WM8996_DSP1RX_VU, WM8996_DSP1RX_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DSP2_RX_LEFT_VOLUME,
+			   WM8996_DSP2RX_VU, WM8996_DSP2RX_VU);
+	regmap_update_bits(wm8996->regmap, WM8996_DSP2_RX_RIGHT_VOLUME,
+			   WM8996_DSP2RX_VU, WM8996_DSP2RX_VU);
+
+	/* No support currently for the underclocked TDM modes and
+	 * pick a default TDM layout with each channel pair working with
+	 * slots 0 and 1. */
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1RX_CHANNEL_0_CONFIGURATION,
+			   WM8996_AIF1RX_CHAN0_SLOTS_MASK |
+			   WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1RX_CHAN0_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1RX_CHANNEL_1_CONFIGURATION,
+			   WM8996_AIF1RX_CHAN1_SLOTS_MASK |
+			   WM8996_AIF1RX_CHAN1_START_SLOT_MASK,
+			   1 << WM8996_AIF1RX_CHAN1_SLOTS_SHIFT | 1);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1RX_CHANNEL_2_CONFIGURATION,
+			   WM8996_AIF1RX_CHAN2_SLOTS_MASK |
+			   WM8996_AIF1RX_CHAN2_START_SLOT_MASK,
+			   1 << WM8996_AIF1RX_CHAN2_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1RX_CHANNEL_3_CONFIGURATION,
+			   WM8996_AIF1RX_CHAN3_SLOTS_MASK |
+			   WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1RX_CHAN3_SLOTS_SHIFT | 1);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1RX_CHANNEL_4_CONFIGURATION,
+			   WM8996_AIF1RX_CHAN4_SLOTS_MASK |
+			   WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1RX_CHAN4_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1RX_CHANNEL_5_CONFIGURATION,
+			   WM8996_AIF1RX_CHAN5_SLOTS_MASK |
+			   WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1RX_CHAN5_SLOTS_SHIFT | 1);
+
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF2RX_CHANNEL_0_CONFIGURATION,
+			   WM8996_AIF2RX_CHAN0_SLOTS_MASK |
+			   WM8996_AIF2RX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF2RX_CHAN0_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF2RX_CHANNEL_1_CONFIGURATION,
+			   WM8996_AIF2RX_CHAN1_SLOTS_MASK |
+			   WM8996_AIF2RX_CHAN1_START_SLOT_MASK,
+			   1 << WM8996_AIF2RX_CHAN1_SLOTS_SHIFT | 1);
+
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1TX_CHANNEL_0_CONFIGURATION,
+			   WM8996_AIF1TX_CHAN0_SLOTS_MASK |
+			   WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1TX_CHAN0_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1TX_CHANNEL_1_CONFIGURATION,
+			   WM8996_AIF1TX_CHAN1_SLOTS_MASK |
+			   WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1TX_CHANNEL_2_CONFIGURATION,
+			   WM8996_AIF1TX_CHAN2_SLOTS_MASK |
+			   WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1TX_CHAN2_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1TX_CHANNEL_3_CONFIGURATION,
+			   WM8996_AIF1TX_CHAN3_SLOTS_MASK |
+			   WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1TX_CHAN3_SLOTS_SHIFT | 1);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1TX_CHANNEL_4_CONFIGURATION,
+			   WM8996_AIF1TX_CHAN4_SLOTS_MASK |
+			   WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1TX_CHAN4_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1TX_CHANNEL_5_CONFIGURATION,
+			   WM8996_AIF1TX_CHAN5_SLOTS_MASK |
+			   WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF1TX_CHAN5_SLOTS_SHIFT | 1);
+
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF2TX_CHANNEL_0_CONFIGURATION,
+			   WM8996_AIF2TX_CHAN0_SLOTS_MASK |
+			   WM8996_AIF2TX_CHAN0_START_SLOT_MASK,
+			   1 << WM8996_AIF2TX_CHAN0_SLOTS_SHIFT | 0);
+	regmap_update_bits(wm8996->regmap,
+			   WM8996_AIF1TX_CHANNEL_1_CONFIGURATION,
+			   WM8996_AIF2TX_CHAN1_SLOTS_MASK |
+			   WM8996_AIF2TX_CHAN1_START_SLOT_MASK,
+			   1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
+
+	/* If the TX LRCLK pins are not in LRCLK mode configure the
+	 * AIFs to source their clocks from the RX LRCLKs.
+	 */
+	ret = regmap_read(wm8996->regmap, WM8996_GPIO_1, &reg);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to read GPIO1: %d\n", ret);
+		goto err_regmap;
+	}
+
+	if (reg & WM8996_GP1_FN_MASK)
+		regmap_update_bits(wm8996->regmap, WM8996_AIF1_TX_LRCLK_2,
+				   WM8996_AIF1TX_LRCLK_MODE,
+				   WM8996_AIF1TX_LRCLK_MODE);
+
+	ret = regmap_read(wm8996->regmap, WM8996_GPIO_2, &reg);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to read GPIO2: %d\n", ret);
+		goto err_regmap;
+	}
+
+	if (reg & WM8996_GP2_FN_MASK)
+		regmap_update_bits(wm8996->regmap, WM8996_AIF2_TX_LRCLK_2,
+				   WM8996_AIF2TX_LRCLK_MODE,
+				   WM8996_AIF2TX_LRCLK_MODE);
+
+	wm8996_init_gpio(wm8996);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+				     &soc_component_dev_wm8996, wm8996_dai,
+				     ARRAY_SIZE(wm8996_dai));
+	if (ret < 0)
+		goto err_gpiolib;
+
+	return ret;
+
+err_gpiolib:
+	wm8996_free_gpio(wm8996);
+err_regmap:
+err_enable:
+	if (wm8996->pdata.ldo_ena > 0)
+		gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+	regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
+err_gpio:
+	if (wm8996->pdata.ldo_ena > 0)
+		gpio_free(wm8996->pdata.ldo_ena);
+err:
+
+	return ret;
+}
+
+static int wm8996_i2c_remove(struct i2c_client *client)
+{
+	struct wm8996_priv *wm8996 = i2c_get_clientdata(client);
+	int i;
+
+	wm8996_free_gpio(wm8996);
+	if (wm8996->pdata.ldo_ena > 0) {
+		gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+		gpio_free(wm8996->pdata.ldo_ena);
+	}
+	for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
+		regulator_unregister_notifier(wm8996->supplies[i].consumer,
+					      &wm8996->disable_nb[i]);
+
+	return 0;
+}
+
+static const struct i2c_device_id wm8996_i2c_id[] = {
+	{ "wm8996", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8996_i2c_id);
+
+static struct i2c_driver wm8996_i2c_driver = {
+	.driver = {
+		.name = "wm8996",
+	},
+	.probe =    wm8996_i2c_probe,
+	.remove =   wm8996_i2c_remove,
+	.id_table = wm8996_i2c_id,
+};
+
+module_i2c_driver(wm8996_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8996 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8996.h b/sound/soc/codecs/wm8996.h
new file mode 100644
index 0000000..b387699
--- /dev/null
+++ b/sound/soc/codecs/wm8996.h
@@ -0,0 +1,3721 @@
+/*
+ * wm8996.h - WM8996 audio codec interface
+ *
+ * Copyright 2011 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _WM8996_H
+#define _WM8996_H
+
+#define WM8996_SYSCLK_MCLK1 1
+#define WM8996_SYSCLK_MCLK2 2
+#define WM8996_SYSCLK_FLL   3
+
+#define WM8996_FLL_MCLK1      1
+#define WM8996_FLL_MCLK2      2
+#define WM8996_FLL_DACLRCLK1  3
+#define WM8996_FLL_BCLK1      4
+
+typedef void (*wm8996_polarity_fn)(struct snd_soc_component *component, int polarity);
+
+int wm8996_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
+		  wm8996_polarity_fn polarity_cb);
+
+/*
+ * Register values.
+ */
+#define WM8996_SOFTWARE_RESET                   0x00
+#define WM8996_POWER_MANAGEMENT_1               0x01
+#define WM8996_POWER_MANAGEMENT_2               0x02
+#define WM8996_POWER_MANAGEMENT_3               0x03
+#define WM8996_POWER_MANAGEMENT_4               0x04
+#define WM8996_POWER_MANAGEMENT_5               0x05
+#define WM8996_POWER_MANAGEMENT_6               0x06
+#define WM8996_POWER_MANAGEMENT_7               0x07
+#define WM8996_POWER_MANAGEMENT_8               0x08
+#define WM8996_LEFT_LINE_INPUT_VOLUME           0x10
+#define WM8996_RIGHT_LINE_INPUT_VOLUME          0x11
+#define WM8996_LINE_INPUT_CONTROL               0x12
+#define WM8996_DAC1_HPOUT1_VOLUME               0x15
+#define WM8996_DAC2_HPOUT2_VOLUME               0x16
+#define WM8996_DAC1_LEFT_VOLUME                 0x18
+#define WM8996_DAC1_RIGHT_VOLUME                0x19
+#define WM8996_DAC2_LEFT_VOLUME                 0x1A
+#define WM8996_DAC2_RIGHT_VOLUME                0x1B
+#define WM8996_OUTPUT1_LEFT_VOLUME              0x1C
+#define WM8996_OUTPUT1_RIGHT_VOLUME             0x1D
+#define WM8996_OUTPUT2_LEFT_VOLUME              0x1E
+#define WM8996_OUTPUT2_RIGHT_VOLUME             0x1F
+#define WM8996_MICBIAS_1                        0x20
+#define WM8996_MICBIAS_2                        0x21
+#define WM8996_LDO_1                            0x28
+#define WM8996_LDO_2                            0x29
+#define WM8996_ACCESSORY_DETECT_MODE_1          0x30
+#define WM8996_ACCESSORY_DETECT_MODE_2          0x31
+#define WM8996_HEADPHONE_DETECT_1               0x34
+#define WM8996_HEADPHONE_DETECT_2               0x35
+#define WM8996_MIC_DETECT_1                     0x38
+#define WM8996_MIC_DETECT_2                     0x39
+#define WM8996_MIC_DETECT_3                     0x3A
+#define WM8996_CHARGE_PUMP_1                    0x40
+#define WM8996_CHARGE_PUMP_2                    0x41
+#define WM8996_DC_SERVO_1                       0x50
+#define WM8996_DC_SERVO_2                       0x51
+#define WM8996_DC_SERVO_3                       0x52
+#define WM8996_DC_SERVO_5                       0x54
+#define WM8996_DC_SERVO_6                       0x55
+#define WM8996_DC_SERVO_7                       0x56
+#define WM8996_DC_SERVO_READBACK_0              0x57
+#define WM8996_ANALOGUE_HP_1                    0x60
+#define WM8996_ANALOGUE_HP_2                    0x61
+#define WM8996_CHIP_REVISION                    0x100
+#define WM8996_CONTROL_INTERFACE_1              0x101
+#define WM8996_WRITE_SEQUENCER_CTRL_1           0x110
+#define WM8996_WRITE_SEQUENCER_CTRL_2           0x111
+#define WM8996_AIF_CLOCKING_1                   0x200
+#define WM8996_AIF_CLOCKING_2                   0x201
+#define WM8996_CLOCKING_1                       0x208
+#define WM8996_CLOCKING_2                       0x209
+#define WM8996_AIF_RATE                         0x210
+#define WM8996_FLL_CONTROL_1                    0x220
+#define WM8996_FLL_CONTROL_2                    0x221
+#define WM8996_FLL_CONTROL_3                    0x222
+#define WM8996_FLL_CONTROL_4                    0x223
+#define WM8996_FLL_CONTROL_5                    0x224
+#define WM8996_FLL_CONTROL_6                    0x225
+#define WM8996_FLL_EFS_1                        0x226
+#define WM8996_FLL_EFS_2                        0x227
+#define WM8996_AIF1_CONTROL                     0x300
+#define WM8996_AIF1_BCLK                        0x301
+#define WM8996_AIF1_TX_LRCLK_1                  0x302
+#define WM8996_AIF1_TX_LRCLK_2                  0x303
+#define WM8996_AIF1_RX_LRCLK_1                  0x304
+#define WM8996_AIF1_RX_LRCLK_2                  0x305
+#define WM8996_AIF1TX_DATA_CONFIGURATION_1      0x306
+#define WM8996_AIF1TX_DATA_CONFIGURATION_2      0x307
+#define WM8996_AIF1RX_DATA_CONFIGURATION        0x308
+#define WM8996_AIF1TX_CHANNEL_0_CONFIGURATION   0x309
+#define WM8996_AIF1TX_CHANNEL_1_CONFIGURATION   0x30A
+#define WM8996_AIF1TX_CHANNEL_2_CONFIGURATION   0x30B
+#define WM8996_AIF1TX_CHANNEL_3_CONFIGURATION   0x30C
+#define WM8996_AIF1TX_CHANNEL_4_CONFIGURATION   0x30D
+#define WM8996_AIF1TX_CHANNEL_5_CONFIGURATION   0x30E
+#define WM8996_AIF1RX_CHANNEL_0_CONFIGURATION   0x30F
+#define WM8996_AIF1RX_CHANNEL_1_CONFIGURATION   0x310
+#define WM8996_AIF1RX_CHANNEL_2_CONFIGURATION   0x311
+#define WM8996_AIF1RX_CHANNEL_3_CONFIGURATION   0x312
+#define WM8996_AIF1RX_CHANNEL_4_CONFIGURATION   0x313
+#define WM8996_AIF1RX_CHANNEL_5_CONFIGURATION   0x314
+#define WM8996_AIF1RX_MONO_CONFIGURATION        0x315
+#define WM8996_AIF1TX_TEST                      0x31A
+#define WM8996_AIF2_CONTROL                     0x320
+#define WM8996_AIF2_BCLK                        0x321
+#define WM8996_AIF2_TX_LRCLK_1                  0x322
+#define WM8996_AIF2_TX_LRCLK_2                  0x323
+#define WM8996_AIF2_RX_LRCLK_1                  0x324
+#define WM8996_AIF2_RX_LRCLK_2                  0x325
+#define WM8996_AIF2TX_DATA_CONFIGURATION_1      0x326
+#define WM8996_AIF2TX_DATA_CONFIGURATION_2      0x327
+#define WM8996_AIF2RX_DATA_CONFIGURATION        0x328
+#define WM8996_AIF2TX_CHANNEL_0_CONFIGURATION   0x329
+#define WM8996_AIF2TX_CHANNEL_1_CONFIGURATION   0x32A
+#define WM8996_AIF2RX_CHANNEL_0_CONFIGURATION   0x32B
+#define WM8996_AIF2RX_CHANNEL_1_CONFIGURATION   0x32C
+#define WM8996_AIF2RX_MONO_CONFIGURATION        0x32D
+#define WM8996_AIF2TX_TEST                      0x32F
+#define WM8996_DSP1_TX_LEFT_VOLUME              0x400
+#define WM8996_DSP1_TX_RIGHT_VOLUME             0x401
+#define WM8996_DSP1_RX_LEFT_VOLUME              0x402
+#define WM8996_DSP1_RX_RIGHT_VOLUME             0x403
+#define WM8996_DSP1_TX_FILTERS                  0x410
+#define WM8996_DSP1_RX_FILTERS_1                0x420
+#define WM8996_DSP1_RX_FILTERS_2                0x421
+#define WM8996_DSP1_DRC_1                       0x440
+#define WM8996_DSP1_DRC_2                       0x441
+#define WM8996_DSP1_DRC_3                       0x442
+#define WM8996_DSP1_DRC_4                       0x443
+#define WM8996_DSP1_DRC_5                       0x444
+#define WM8996_DSP1_RX_EQ_GAINS_1               0x480
+#define WM8996_DSP1_RX_EQ_GAINS_2               0x481
+#define WM8996_DSP1_RX_EQ_BAND_1_A              0x482
+#define WM8996_DSP1_RX_EQ_BAND_1_B              0x483
+#define WM8996_DSP1_RX_EQ_BAND_1_PG             0x484
+#define WM8996_DSP1_RX_EQ_BAND_2_A              0x485
+#define WM8996_DSP1_RX_EQ_BAND_2_B              0x486
+#define WM8996_DSP1_RX_EQ_BAND_2_C              0x487
+#define WM8996_DSP1_RX_EQ_BAND_2_PG             0x488
+#define WM8996_DSP1_RX_EQ_BAND_3_A              0x489
+#define WM8996_DSP1_RX_EQ_BAND_3_B              0x48A
+#define WM8996_DSP1_RX_EQ_BAND_3_C              0x48B
+#define WM8996_DSP1_RX_EQ_BAND_3_PG             0x48C
+#define WM8996_DSP1_RX_EQ_BAND_4_A              0x48D
+#define WM8996_DSP1_RX_EQ_BAND_4_B              0x48E
+#define WM8996_DSP1_RX_EQ_BAND_4_C              0x48F
+#define WM8996_DSP1_RX_EQ_BAND_4_PG             0x490
+#define WM8996_DSP1_RX_EQ_BAND_5_A              0x491
+#define WM8996_DSP1_RX_EQ_BAND_5_B              0x492
+#define WM8996_DSP1_RX_EQ_BAND_5_PG             0x493
+#define WM8996_DSP2_TX_LEFT_VOLUME              0x500
+#define WM8996_DSP2_TX_RIGHT_VOLUME             0x501
+#define WM8996_DSP2_RX_LEFT_VOLUME              0x502
+#define WM8996_DSP2_RX_RIGHT_VOLUME             0x503
+#define WM8996_DSP2_TX_FILTERS                  0x510
+#define WM8996_DSP2_RX_FILTERS_1                0x520
+#define WM8996_DSP2_RX_FILTERS_2                0x521
+#define WM8996_DSP2_DRC_1                       0x540
+#define WM8996_DSP2_DRC_2                       0x541
+#define WM8996_DSP2_DRC_3                       0x542
+#define WM8996_DSP2_DRC_4                       0x543
+#define WM8996_DSP2_DRC_5                       0x544
+#define WM8996_DSP2_RX_EQ_GAINS_1               0x580
+#define WM8996_DSP2_RX_EQ_GAINS_2               0x581
+#define WM8996_DSP2_RX_EQ_BAND_1_A              0x582
+#define WM8996_DSP2_RX_EQ_BAND_1_B              0x583
+#define WM8996_DSP2_RX_EQ_BAND_1_PG             0x584
+#define WM8996_DSP2_RX_EQ_BAND_2_A              0x585
+#define WM8996_DSP2_RX_EQ_BAND_2_B              0x586
+#define WM8996_DSP2_RX_EQ_BAND_2_C              0x587
+#define WM8996_DSP2_RX_EQ_BAND_2_PG             0x588
+#define WM8996_DSP2_RX_EQ_BAND_3_A              0x589
+#define WM8996_DSP2_RX_EQ_BAND_3_B              0x58A
+#define WM8996_DSP2_RX_EQ_BAND_3_C              0x58B
+#define WM8996_DSP2_RX_EQ_BAND_3_PG             0x58C
+#define WM8996_DSP2_RX_EQ_BAND_4_A              0x58D
+#define WM8996_DSP2_RX_EQ_BAND_4_B              0x58E
+#define WM8996_DSP2_RX_EQ_BAND_4_C              0x58F
+#define WM8996_DSP2_RX_EQ_BAND_4_PG             0x590
+#define WM8996_DSP2_RX_EQ_BAND_5_A              0x591
+#define WM8996_DSP2_RX_EQ_BAND_5_B              0x592
+#define WM8996_DSP2_RX_EQ_BAND_5_PG             0x593
+#define WM8996_DAC1_MIXER_VOLUMES               0x600
+#define WM8996_DAC1_LEFT_MIXER_ROUTING          0x601
+#define WM8996_DAC1_RIGHT_MIXER_ROUTING         0x602
+#define WM8996_DAC2_MIXER_VOLUMES               0x603
+#define WM8996_DAC2_LEFT_MIXER_ROUTING          0x604
+#define WM8996_DAC2_RIGHT_MIXER_ROUTING         0x605
+#define WM8996_DSP1_TX_LEFT_MIXER_ROUTING       0x606
+#define WM8996_DSP1_TX_RIGHT_MIXER_ROUTING      0x607
+#define WM8996_DSP2_TX_LEFT_MIXER_ROUTING       0x608
+#define WM8996_DSP2_TX_RIGHT_MIXER_ROUTING      0x609
+#define WM8996_DSP_TX_MIXER_SELECT              0x60A
+#define WM8996_DAC_SOFTMUTE                     0x610
+#define WM8996_OVERSAMPLING                     0x620
+#define WM8996_SIDETONE                         0x621
+#define WM8996_GPIO_1                           0x700
+#define WM8996_GPIO_2                           0x701
+#define WM8996_GPIO_3                           0x702
+#define WM8996_GPIO_4                           0x703
+#define WM8996_GPIO_5                           0x704
+#define WM8996_PULL_CONTROL_1                   0x720
+#define WM8996_PULL_CONTROL_2                   0x721
+#define WM8996_INTERRUPT_STATUS_1               0x730
+#define WM8996_INTERRUPT_STATUS_2               0x731
+#define WM8996_INTERRUPT_RAW_STATUS_2           0x732
+#define WM8996_INTERRUPT_STATUS_1_MASK          0x738
+#define WM8996_INTERRUPT_STATUS_2_MASK          0x739
+#define WM8996_INTERRUPT_CONTROL                0x740
+#define WM8996_LEFT_PDM_SPEAKER                 0x800
+#define WM8996_RIGHT_PDM_SPEAKER                0x801
+#define WM8996_PDM_SPEAKER_MUTE_SEQUENCE        0x802
+#define WM8996_PDM_SPEAKER_VOLUME               0x803
+#define WM8996_WRITE_SEQUENCER_0                0x3000
+#define WM8996_WRITE_SEQUENCER_1                0x3001
+#define WM8996_WRITE_SEQUENCER_2                0x3002
+#define WM8996_WRITE_SEQUENCER_3                0x3003
+#define WM8996_WRITE_SEQUENCER_4                0x3004
+#define WM8996_WRITE_SEQUENCER_5                0x3005
+#define WM8996_WRITE_SEQUENCER_6                0x3006
+#define WM8996_WRITE_SEQUENCER_7                0x3007
+#define WM8996_WRITE_SEQUENCER_8                0x3008
+#define WM8996_WRITE_SEQUENCER_9                0x3009
+#define WM8996_WRITE_SEQUENCER_10               0x300A
+#define WM8996_WRITE_SEQUENCER_11               0x300B
+#define WM8996_WRITE_SEQUENCER_12               0x300C
+#define WM8996_WRITE_SEQUENCER_13               0x300D
+#define WM8996_WRITE_SEQUENCER_14               0x300E
+#define WM8996_WRITE_SEQUENCER_15               0x300F
+#define WM8996_WRITE_SEQUENCER_16               0x3010
+#define WM8996_WRITE_SEQUENCER_17               0x3011
+#define WM8996_WRITE_SEQUENCER_18               0x3012
+#define WM8996_WRITE_SEQUENCER_19               0x3013
+#define WM8996_WRITE_SEQUENCER_20               0x3014
+#define WM8996_WRITE_SEQUENCER_21               0x3015
+#define WM8996_WRITE_SEQUENCER_22               0x3016
+#define WM8996_WRITE_SEQUENCER_23               0x3017
+#define WM8996_WRITE_SEQUENCER_24               0x3018
+#define WM8996_WRITE_SEQUENCER_25               0x3019
+#define WM8996_WRITE_SEQUENCER_26               0x301A
+#define WM8996_WRITE_SEQUENCER_27               0x301B
+#define WM8996_WRITE_SEQUENCER_28               0x301C
+#define WM8996_WRITE_SEQUENCER_29               0x301D
+#define WM8996_WRITE_SEQUENCER_30               0x301E
+#define WM8996_WRITE_SEQUENCER_31               0x301F
+#define WM8996_WRITE_SEQUENCER_32               0x3020
+#define WM8996_WRITE_SEQUENCER_33               0x3021
+#define WM8996_WRITE_SEQUENCER_34               0x3022
+#define WM8996_WRITE_SEQUENCER_35               0x3023
+#define WM8996_WRITE_SEQUENCER_36               0x3024
+#define WM8996_WRITE_SEQUENCER_37               0x3025
+#define WM8996_WRITE_SEQUENCER_38               0x3026
+#define WM8996_WRITE_SEQUENCER_39               0x3027
+#define WM8996_WRITE_SEQUENCER_40               0x3028
+#define WM8996_WRITE_SEQUENCER_41               0x3029
+#define WM8996_WRITE_SEQUENCER_42               0x302A
+#define WM8996_WRITE_SEQUENCER_43               0x302B
+#define WM8996_WRITE_SEQUENCER_44               0x302C
+#define WM8996_WRITE_SEQUENCER_45               0x302D
+#define WM8996_WRITE_SEQUENCER_46               0x302E
+#define WM8996_WRITE_SEQUENCER_47               0x302F
+#define WM8996_WRITE_SEQUENCER_48               0x3030
+#define WM8996_WRITE_SEQUENCER_49               0x3031
+#define WM8996_WRITE_SEQUENCER_50               0x3032
+#define WM8996_WRITE_SEQUENCER_51               0x3033
+#define WM8996_WRITE_SEQUENCER_52               0x3034
+#define WM8996_WRITE_SEQUENCER_53               0x3035
+#define WM8996_WRITE_SEQUENCER_54               0x3036
+#define WM8996_WRITE_SEQUENCER_55               0x3037
+#define WM8996_WRITE_SEQUENCER_56               0x3038
+#define WM8996_WRITE_SEQUENCER_57               0x3039
+#define WM8996_WRITE_SEQUENCER_58               0x303A
+#define WM8996_WRITE_SEQUENCER_59               0x303B
+#define WM8996_WRITE_SEQUENCER_60               0x303C
+#define WM8996_WRITE_SEQUENCER_61               0x303D
+#define WM8996_WRITE_SEQUENCER_62               0x303E
+#define WM8996_WRITE_SEQUENCER_63               0x303F
+#define WM8996_WRITE_SEQUENCER_64               0x3040
+#define WM8996_WRITE_SEQUENCER_65               0x3041
+#define WM8996_WRITE_SEQUENCER_66               0x3042
+#define WM8996_WRITE_SEQUENCER_67               0x3043
+#define WM8996_WRITE_SEQUENCER_68               0x3044
+#define WM8996_WRITE_SEQUENCER_69               0x3045
+#define WM8996_WRITE_SEQUENCER_70               0x3046
+#define WM8996_WRITE_SEQUENCER_71               0x3047
+#define WM8996_WRITE_SEQUENCER_72               0x3048
+#define WM8996_WRITE_SEQUENCER_73               0x3049
+#define WM8996_WRITE_SEQUENCER_74               0x304A
+#define WM8996_WRITE_SEQUENCER_75               0x304B
+#define WM8996_WRITE_SEQUENCER_76               0x304C
+#define WM8996_WRITE_SEQUENCER_77               0x304D
+#define WM8996_WRITE_SEQUENCER_78               0x304E
+#define WM8996_WRITE_SEQUENCER_79               0x304F
+#define WM8996_WRITE_SEQUENCER_80               0x3050
+#define WM8996_WRITE_SEQUENCER_81               0x3051
+#define WM8996_WRITE_SEQUENCER_82               0x3052
+#define WM8996_WRITE_SEQUENCER_83               0x3053
+#define WM8996_WRITE_SEQUENCER_84               0x3054
+#define WM8996_WRITE_SEQUENCER_85               0x3055
+#define WM8996_WRITE_SEQUENCER_86               0x3056
+#define WM8996_WRITE_SEQUENCER_87               0x3057
+#define WM8996_WRITE_SEQUENCER_88               0x3058
+#define WM8996_WRITE_SEQUENCER_89               0x3059
+#define WM8996_WRITE_SEQUENCER_90               0x305A
+#define WM8996_WRITE_SEQUENCER_91               0x305B
+#define WM8996_WRITE_SEQUENCER_92               0x305C
+#define WM8996_WRITE_SEQUENCER_93               0x305D
+#define WM8996_WRITE_SEQUENCER_94               0x305E
+#define WM8996_WRITE_SEQUENCER_95               0x305F
+#define WM8996_WRITE_SEQUENCER_96               0x3060
+#define WM8996_WRITE_SEQUENCER_97               0x3061
+#define WM8996_WRITE_SEQUENCER_98               0x3062
+#define WM8996_WRITE_SEQUENCER_99               0x3063
+#define WM8996_WRITE_SEQUENCER_100              0x3064
+#define WM8996_WRITE_SEQUENCER_101              0x3065
+#define WM8996_WRITE_SEQUENCER_102              0x3066
+#define WM8996_WRITE_SEQUENCER_103              0x3067
+#define WM8996_WRITE_SEQUENCER_104              0x3068
+#define WM8996_WRITE_SEQUENCER_105              0x3069
+#define WM8996_WRITE_SEQUENCER_106              0x306A
+#define WM8996_WRITE_SEQUENCER_107              0x306B
+#define WM8996_WRITE_SEQUENCER_108              0x306C
+#define WM8996_WRITE_SEQUENCER_109              0x306D
+#define WM8996_WRITE_SEQUENCER_110              0x306E
+#define WM8996_WRITE_SEQUENCER_111              0x306F
+#define WM8996_WRITE_SEQUENCER_112              0x3070
+#define WM8996_WRITE_SEQUENCER_113              0x3071
+#define WM8996_WRITE_SEQUENCER_114              0x3072
+#define WM8996_WRITE_SEQUENCER_115              0x3073
+#define WM8996_WRITE_SEQUENCER_116              0x3074
+#define WM8996_WRITE_SEQUENCER_117              0x3075
+#define WM8996_WRITE_SEQUENCER_118              0x3076
+#define WM8996_WRITE_SEQUENCER_119              0x3077
+#define WM8996_WRITE_SEQUENCER_120              0x3078
+#define WM8996_WRITE_SEQUENCER_121              0x3079
+#define WM8996_WRITE_SEQUENCER_122              0x307A
+#define WM8996_WRITE_SEQUENCER_123              0x307B
+#define WM8996_WRITE_SEQUENCER_124              0x307C
+#define WM8996_WRITE_SEQUENCER_125              0x307D
+#define WM8996_WRITE_SEQUENCER_126              0x307E
+#define WM8996_WRITE_SEQUENCER_127              0x307F
+#define WM8996_WRITE_SEQUENCER_128              0x3080
+#define WM8996_WRITE_SEQUENCER_129              0x3081
+#define WM8996_WRITE_SEQUENCER_130              0x3082
+#define WM8996_WRITE_SEQUENCER_131              0x3083
+#define WM8996_WRITE_SEQUENCER_132              0x3084
+#define WM8996_WRITE_SEQUENCER_133              0x3085
+#define WM8996_WRITE_SEQUENCER_134              0x3086
+#define WM8996_WRITE_SEQUENCER_135              0x3087
+#define WM8996_WRITE_SEQUENCER_136              0x3088
+#define WM8996_WRITE_SEQUENCER_137              0x3089
+#define WM8996_WRITE_SEQUENCER_138              0x308A
+#define WM8996_WRITE_SEQUENCER_139              0x308B
+#define WM8996_WRITE_SEQUENCER_140              0x308C
+#define WM8996_WRITE_SEQUENCER_141              0x308D
+#define WM8996_WRITE_SEQUENCER_142              0x308E
+#define WM8996_WRITE_SEQUENCER_143              0x308F
+#define WM8996_WRITE_SEQUENCER_144              0x3090
+#define WM8996_WRITE_SEQUENCER_145              0x3091
+#define WM8996_WRITE_SEQUENCER_146              0x3092
+#define WM8996_WRITE_SEQUENCER_147              0x3093
+#define WM8996_WRITE_SEQUENCER_148              0x3094
+#define WM8996_WRITE_SEQUENCER_149              0x3095
+#define WM8996_WRITE_SEQUENCER_150              0x3096
+#define WM8996_WRITE_SEQUENCER_151              0x3097
+#define WM8996_WRITE_SEQUENCER_152              0x3098
+#define WM8996_WRITE_SEQUENCER_153              0x3099
+#define WM8996_WRITE_SEQUENCER_154              0x309A
+#define WM8996_WRITE_SEQUENCER_155              0x309B
+#define WM8996_WRITE_SEQUENCER_156              0x309C
+#define WM8996_WRITE_SEQUENCER_157              0x309D
+#define WM8996_WRITE_SEQUENCER_158              0x309E
+#define WM8996_WRITE_SEQUENCER_159              0x309F
+#define WM8996_WRITE_SEQUENCER_160              0x30A0
+#define WM8996_WRITE_SEQUENCER_161              0x30A1
+#define WM8996_WRITE_SEQUENCER_162              0x30A2
+#define WM8996_WRITE_SEQUENCER_163              0x30A3
+#define WM8996_WRITE_SEQUENCER_164              0x30A4
+#define WM8996_WRITE_SEQUENCER_165              0x30A5
+#define WM8996_WRITE_SEQUENCER_166              0x30A6
+#define WM8996_WRITE_SEQUENCER_167              0x30A7
+#define WM8996_WRITE_SEQUENCER_168              0x30A8
+#define WM8996_WRITE_SEQUENCER_169              0x30A9
+#define WM8996_WRITE_SEQUENCER_170              0x30AA
+#define WM8996_WRITE_SEQUENCER_171              0x30AB
+#define WM8996_WRITE_SEQUENCER_172              0x30AC
+#define WM8996_WRITE_SEQUENCER_173              0x30AD
+#define WM8996_WRITE_SEQUENCER_174              0x30AE
+#define WM8996_WRITE_SEQUENCER_175              0x30AF
+#define WM8996_WRITE_SEQUENCER_176              0x30B0
+#define WM8996_WRITE_SEQUENCER_177              0x30B1
+#define WM8996_WRITE_SEQUENCER_178              0x30B2
+#define WM8996_WRITE_SEQUENCER_179              0x30B3
+#define WM8996_WRITE_SEQUENCER_180              0x30B4
+#define WM8996_WRITE_SEQUENCER_181              0x30B5
+#define WM8996_WRITE_SEQUENCER_182              0x30B6
+#define WM8996_WRITE_SEQUENCER_183              0x30B7
+#define WM8996_WRITE_SEQUENCER_184              0x30B8
+#define WM8996_WRITE_SEQUENCER_185              0x30B9
+#define WM8996_WRITE_SEQUENCER_186              0x30BA
+#define WM8996_WRITE_SEQUENCER_187              0x30BB
+#define WM8996_WRITE_SEQUENCER_188              0x30BC
+#define WM8996_WRITE_SEQUENCER_189              0x30BD
+#define WM8996_WRITE_SEQUENCER_190              0x30BE
+#define WM8996_WRITE_SEQUENCER_191              0x30BF
+#define WM8996_WRITE_SEQUENCER_192              0x30C0
+#define WM8996_WRITE_SEQUENCER_193              0x30C1
+#define WM8996_WRITE_SEQUENCER_194              0x30C2
+#define WM8996_WRITE_SEQUENCER_195              0x30C3
+#define WM8996_WRITE_SEQUENCER_196              0x30C4
+#define WM8996_WRITE_SEQUENCER_197              0x30C5
+#define WM8996_WRITE_SEQUENCER_198              0x30C6
+#define WM8996_WRITE_SEQUENCER_199              0x30C7
+#define WM8996_WRITE_SEQUENCER_200              0x30C8
+#define WM8996_WRITE_SEQUENCER_201              0x30C9
+#define WM8996_WRITE_SEQUENCER_202              0x30CA
+#define WM8996_WRITE_SEQUENCER_203              0x30CB
+#define WM8996_WRITE_SEQUENCER_204              0x30CC
+#define WM8996_WRITE_SEQUENCER_205              0x30CD
+#define WM8996_WRITE_SEQUENCER_206              0x30CE
+#define WM8996_WRITE_SEQUENCER_207              0x30CF
+#define WM8996_WRITE_SEQUENCER_208              0x30D0
+#define WM8996_WRITE_SEQUENCER_209              0x30D1
+#define WM8996_WRITE_SEQUENCER_210              0x30D2
+#define WM8996_WRITE_SEQUENCER_211              0x30D3
+#define WM8996_WRITE_SEQUENCER_212              0x30D4
+#define WM8996_WRITE_SEQUENCER_213              0x30D5
+#define WM8996_WRITE_SEQUENCER_214              0x30D6
+#define WM8996_WRITE_SEQUENCER_215              0x30D7
+#define WM8996_WRITE_SEQUENCER_216              0x30D8
+#define WM8996_WRITE_SEQUENCER_217              0x30D9
+#define WM8996_WRITE_SEQUENCER_218              0x30DA
+#define WM8996_WRITE_SEQUENCER_219              0x30DB
+#define WM8996_WRITE_SEQUENCER_220              0x30DC
+#define WM8996_WRITE_SEQUENCER_221              0x30DD
+#define WM8996_WRITE_SEQUENCER_222              0x30DE
+#define WM8996_WRITE_SEQUENCER_223              0x30DF
+#define WM8996_WRITE_SEQUENCER_224              0x30E0
+#define WM8996_WRITE_SEQUENCER_225              0x30E1
+#define WM8996_WRITE_SEQUENCER_226              0x30E2
+#define WM8996_WRITE_SEQUENCER_227              0x30E3
+#define WM8996_WRITE_SEQUENCER_228              0x30E4
+#define WM8996_WRITE_SEQUENCER_229              0x30E5
+#define WM8996_WRITE_SEQUENCER_230              0x30E6
+#define WM8996_WRITE_SEQUENCER_231              0x30E7
+#define WM8996_WRITE_SEQUENCER_232              0x30E8
+#define WM8996_WRITE_SEQUENCER_233              0x30E9
+#define WM8996_WRITE_SEQUENCER_234              0x30EA
+#define WM8996_WRITE_SEQUENCER_235              0x30EB
+#define WM8996_WRITE_SEQUENCER_236              0x30EC
+#define WM8996_WRITE_SEQUENCER_237              0x30ED
+#define WM8996_WRITE_SEQUENCER_238              0x30EE
+#define WM8996_WRITE_SEQUENCER_239              0x30EF
+#define WM8996_WRITE_SEQUENCER_240              0x30F0
+#define WM8996_WRITE_SEQUENCER_241              0x30F1
+#define WM8996_WRITE_SEQUENCER_242              0x30F2
+#define WM8996_WRITE_SEQUENCER_243              0x30F3
+#define WM8996_WRITE_SEQUENCER_244              0x30F4
+#define WM8996_WRITE_SEQUENCER_245              0x30F5
+#define WM8996_WRITE_SEQUENCER_246              0x30F6
+#define WM8996_WRITE_SEQUENCER_247              0x30F7
+#define WM8996_WRITE_SEQUENCER_248              0x30F8
+#define WM8996_WRITE_SEQUENCER_249              0x30F9
+#define WM8996_WRITE_SEQUENCER_250              0x30FA
+#define WM8996_WRITE_SEQUENCER_251              0x30FB
+#define WM8996_WRITE_SEQUENCER_252              0x30FC
+#define WM8996_WRITE_SEQUENCER_253              0x30FD
+#define WM8996_WRITE_SEQUENCER_254              0x30FE
+#define WM8996_WRITE_SEQUENCER_255              0x30FF
+#define WM8996_WRITE_SEQUENCER_256              0x3100
+#define WM8996_WRITE_SEQUENCER_257              0x3101
+#define WM8996_WRITE_SEQUENCER_258              0x3102
+#define WM8996_WRITE_SEQUENCER_259              0x3103
+#define WM8996_WRITE_SEQUENCER_260              0x3104
+#define WM8996_WRITE_SEQUENCER_261              0x3105
+#define WM8996_WRITE_SEQUENCER_262              0x3106
+#define WM8996_WRITE_SEQUENCER_263              0x3107
+#define WM8996_WRITE_SEQUENCER_264              0x3108
+#define WM8996_WRITE_SEQUENCER_265              0x3109
+#define WM8996_WRITE_SEQUENCER_266              0x310A
+#define WM8996_WRITE_SEQUENCER_267              0x310B
+#define WM8996_WRITE_SEQUENCER_268              0x310C
+#define WM8996_WRITE_SEQUENCER_269              0x310D
+#define WM8996_WRITE_SEQUENCER_270              0x310E
+#define WM8996_WRITE_SEQUENCER_271              0x310F
+#define WM8996_WRITE_SEQUENCER_272              0x3110
+#define WM8996_WRITE_SEQUENCER_273              0x3111
+#define WM8996_WRITE_SEQUENCER_274              0x3112
+#define WM8996_WRITE_SEQUENCER_275              0x3113
+#define WM8996_WRITE_SEQUENCER_276              0x3114
+#define WM8996_WRITE_SEQUENCER_277              0x3115
+#define WM8996_WRITE_SEQUENCER_278              0x3116
+#define WM8996_WRITE_SEQUENCER_279              0x3117
+#define WM8996_WRITE_SEQUENCER_280              0x3118
+#define WM8996_WRITE_SEQUENCER_281              0x3119
+#define WM8996_WRITE_SEQUENCER_282              0x311A
+#define WM8996_WRITE_SEQUENCER_283              0x311B
+#define WM8996_WRITE_SEQUENCER_284              0x311C
+#define WM8996_WRITE_SEQUENCER_285              0x311D
+#define WM8996_WRITE_SEQUENCER_286              0x311E
+#define WM8996_WRITE_SEQUENCER_287              0x311F
+#define WM8996_WRITE_SEQUENCER_288              0x3120
+#define WM8996_WRITE_SEQUENCER_289              0x3121
+#define WM8996_WRITE_SEQUENCER_290              0x3122
+#define WM8996_WRITE_SEQUENCER_291              0x3123
+#define WM8996_WRITE_SEQUENCER_292              0x3124
+#define WM8996_WRITE_SEQUENCER_293              0x3125
+#define WM8996_WRITE_SEQUENCER_294              0x3126
+#define WM8996_WRITE_SEQUENCER_295              0x3127
+#define WM8996_WRITE_SEQUENCER_296              0x3128
+#define WM8996_WRITE_SEQUENCER_297              0x3129
+#define WM8996_WRITE_SEQUENCER_298              0x312A
+#define WM8996_WRITE_SEQUENCER_299              0x312B
+#define WM8996_WRITE_SEQUENCER_300              0x312C
+#define WM8996_WRITE_SEQUENCER_301              0x312D
+#define WM8996_WRITE_SEQUENCER_302              0x312E
+#define WM8996_WRITE_SEQUENCER_303              0x312F
+#define WM8996_WRITE_SEQUENCER_304              0x3130
+#define WM8996_WRITE_SEQUENCER_305              0x3131
+#define WM8996_WRITE_SEQUENCER_306              0x3132
+#define WM8996_WRITE_SEQUENCER_307              0x3133
+#define WM8996_WRITE_SEQUENCER_308              0x3134
+#define WM8996_WRITE_SEQUENCER_309              0x3135
+#define WM8996_WRITE_SEQUENCER_310              0x3136
+#define WM8996_WRITE_SEQUENCER_311              0x3137
+#define WM8996_WRITE_SEQUENCER_312              0x3138
+#define WM8996_WRITE_SEQUENCER_313              0x3139
+#define WM8996_WRITE_SEQUENCER_314              0x313A
+#define WM8996_WRITE_SEQUENCER_315              0x313B
+#define WM8996_WRITE_SEQUENCER_316              0x313C
+#define WM8996_WRITE_SEQUENCER_317              0x313D
+#define WM8996_WRITE_SEQUENCER_318              0x313E
+#define WM8996_WRITE_SEQUENCER_319              0x313F
+#define WM8996_WRITE_SEQUENCER_320              0x3140
+#define WM8996_WRITE_SEQUENCER_321              0x3141
+#define WM8996_WRITE_SEQUENCER_322              0x3142
+#define WM8996_WRITE_SEQUENCER_323              0x3143
+#define WM8996_WRITE_SEQUENCER_324              0x3144
+#define WM8996_WRITE_SEQUENCER_325              0x3145
+#define WM8996_WRITE_SEQUENCER_326              0x3146
+#define WM8996_WRITE_SEQUENCER_327              0x3147
+#define WM8996_WRITE_SEQUENCER_328              0x3148
+#define WM8996_WRITE_SEQUENCER_329              0x3149
+#define WM8996_WRITE_SEQUENCER_330              0x314A
+#define WM8996_WRITE_SEQUENCER_331              0x314B
+#define WM8996_WRITE_SEQUENCER_332              0x314C
+#define WM8996_WRITE_SEQUENCER_333              0x314D
+#define WM8996_WRITE_SEQUENCER_334              0x314E
+#define WM8996_WRITE_SEQUENCER_335              0x314F
+#define WM8996_WRITE_SEQUENCER_336              0x3150
+#define WM8996_WRITE_SEQUENCER_337              0x3151
+#define WM8996_WRITE_SEQUENCER_338              0x3152
+#define WM8996_WRITE_SEQUENCER_339              0x3153
+#define WM8996_WRITE_SEQUENCER_340              0x3154
+#define WM8996_WRITE_SEQUENCER_341              0x3155
+#define WM8996_WRITE_SEQUENCER_342              0x3156
+#define WM8996_WRITE_SEQUENCER_343              0x3157
+#define WM8996_WRITE_SEQUENCER_344              0x3158
+#define WM8996_WRITE_SEQUENCER_345              0x3159
+#define WM8996_WRITE_SEQUENCER_346              0x315A
+#define WM8996_WRITE_SEQUENCER_347              0x315B
+#define WM8996_WRITE_SEQUENCER_348              0x315C
+#define WM8996_WRITE_SEQUENCER_349              0x315D
+#define WM8996_WRITE_SEQUENCER_350              0x315E
+#define WM8996_WRITE_SEQUENCER_351              0x315F
+#define WM8996_WRITE_SEQUENCER_352              0x3160
+#define WM8996_WRITE_SEQUENCER_353              0x3161
+#define WM8996_WRITE_SEQUENCER_354              0x3162
+#define WM8996_WRITE_SEQUENCER_355              0x3163
+#define WM8996_WRITE_SEQUENCER_356              0x3164
+#define WM8996_WRITE_SEQUENCER_357              0x3165
+#define WM8996_WRITE_SEQUENCER_358              0x3166
+#define WM8996_WRITE_SEQUENCER_359              0x3167
+#define WM8996_WRITE_SEQUENCER_360              0x3168
+#define WM8996_WRITE_SEQUENCER_361              0x3169
+#define WM8996_WRITE_SEQUENCER_362              0x316A
+#define WM8996_WRITE_SEQUENCER_363              0x316B
+#define WM8996_WRITE_SEQUENCER_364              0x316C
+#define WM8996_WRITE_SEQUENCER_365              0x316D
+#define WM8996_WRITE_SEQUENCER_366              0x316E
+#define WM8996_WRITE_SEQUENCER_367              0x316F
+#define WM8996_WRITE_SEQUENCER_368              0x3170
+#define WM8996_WRITE_SEQUENCER_369              0x3171
+#define WM8996_WRITE_SEQUENCER_370              0x3172
+#define WM8996_WRITE_SEQUENCER_371              0x3173
+#define WM8996_WRITE_SEQUENCER_372              0x3174
+#define WM8996_WRITE_SEQUENCER_373              0x3175
+#define WM8996_WRITE_SEQUENCER_374              0x3176
+#define WM8996_WRITE_SEQUENCER_375              0x3177
+#define WM8996_WRITE_SEQUENCER_376              0x3178
+#define WM8996_WRITE_SEQUENCER_377              0x3179
+#define WM8996_WRITE_SEQUENCER_378              0x317A
+#define WM8996_WRITE_SEQUENCER_379              0x317B
+#define WM8996_WRITE_SEQUENCER_380              0x317C
+#define WM8996_WRITE_SEQUENCER_381              0x317D
+#define WM8996_WRITE_SEQUENCER_382              0x317E
+#define WM8996_WRITE_SEQUENCER_383              0x317F
+#define WM8996_WRITE_SEQUENCER_384              0x3180
+#define WM8996_WRITE_SEQUENCER_385              0x3181
+#define WM8996_WRITE_SEQUENCER_386              0x3182
+#define WM8996_WRITE_SEQUENCER_387              0x3183
+#define WM8996_WRITE_SEQUENCER_388              0x3184
+#define WM8996_WRITE_SEQUENCER_389              0x3185
+#define WM8996_WRITE_SEQUENCER_390              0x3186
+#define WM8996_WRITE_SEQUENCER_391              0x3187
+#define WM8996_WRITE_SEQUENCER_392              0x3188
+#define WM8996_WRITE_SEQUENCER_393              0x3189
+#define WM8996_WRITE_SEQUENCER_394              0x318A
+#define WM8996_WRITE_SEQUENCER_395              0x318B
+#define WM8996_WRITE_SEQUENCER_396              0x318C
+#define WM8996_WRITE_SEQUENCER_397              0x318D
+#define WM8996_WRITE_SEQUENCER_398              0x318E
+#define WM8996_WRITE_SEQUENCER_399              0x318F
+#define WM8996_WRITE_SEQUENCER_400              0x3190
+#define WM8996_WRITE_SEQUENCER_401              0x3191
+#define WM8996_WRITE_SEQUENCER_402              0x3192
+#define WM8996_WRITE_SEQUENCER_403              0x3193
+#define WM8996_WRITE_SEQUENCER_404              0x3194
+#define WM8996_WRITE_SEQUENCER_405              0x3195
+#define WM8996_WRITE_SEQUENCER_406              0x3196
+#define WM8996_WRITE_SEQUENCER_407              0x3197
+#define WM8996_WRITE_SEQUENCER_408              0x3198
+#define WM8996_WRITE_SEQUENCER_409              0x3199
+#define WM8996_WRITE_SEQUENCER_410              0x319A
+#define WM8996_WRITE_SEQUENCER_411              0x319B
+#define WM8996_WRITE_SEQUENCER_412              0x319C
+#define WM8996_WRITE_SEQUENCER_413              0x319D
+#define WM8996_WRITE_SEQUENCER_414              0x319E
+#define WM8996_WRITE_SEQUENCER_415              0x319F
+#define WM8996_WRITE_SEQUENCER_416              0x31A0
+#define WM8996_WRITE_SEQUENCER_417              0x31A1
+#define WM8996_WRITE_SEQUENCER_418              0x31A2
+#define WM8996_WRITE_SEQUENCER_419              0x31A3
+#define WM8996_WRITE_SEQUENCER_420              0x31A4
+#define WM8996_WRITE_SEQUENCER_421              0x31A5
+#define WM8996_WRITE_SEQUENCER_422              0x31A6
+#define WM8996_WRITE_SEQUENCER_423              0x31A7
+#define WM8996_WRITE_SEQUENCER_424              0x31A8
+#define WM8996_WRITE_SEQUENCER_425              0x31A9
+#define WM8996_WRITE_SEQUENCER_426              0x31AA
+#define WM8996_WRITE_SEQUENCER_427              0x31AB
+#define WM8996_WRITE_SEQUENCER_428              0x31AC
+#define WM8996_WRITE_SEQUENCER_429              0x31AD
+#define WM8996_WRITE_SEQUENCER_430              0x31AE
+#define WM8996_WRITE_SEQUENCER_431              0x31AF
+#define WM8996_WRITE_SEQUENCER_432              0x31B0
+#define WM8996_WRITE_SEQUENCER_433              0x31B1
+#define WM8996_WRITE_SEQUENCER_434              0x31B2
+#define WM8996_WRITE_SEQUENCER_435              0x31B3
+#define WM8996_WRITE_SEQUENCER_436              0x31B4
+#define WM8996_WRITE_SEQUENCER_437              0x31B5
+#define WM8996_WRITE_SEQUENCER_438              0x31B6
+#define WM8996_WRITE_SEQUENCER_439              0x31B7
+#define WM8996_WRITE_SEQUENCER_440              0x31B8
+#define WM8996_WRITE_SEQUENCER_441              0x31B9
+#define WM8996_WRITE_SEQUENCER_442              0x31BA
+#define WM8996_WRITE_SEQUENCER_443              0x31BB
+#define WM8996_WRITE_SEQUENCER_444              0x31BC
+#define WM8996_WRITE_SEQUENCER_445              0x31BD
+#define WM8996_WRITE_SEQUENCER_446              0x31BE
+#define WM8996_WRITE_SEQUENCER_447              0x31BF
+#define WM8996_WRITE_SEQUENCER_448              0x31C0
+#define WM8996_WRITE_SEQUENCER_449              0x31C1
+#define WM8996_WRITE_SEQUENCER_450              0x31C2
+#define WM8996_WRITE_SEQUENCER_451              0x31C3
+#define WM8996_WRITE_SEQUENCER_452              0x31C4
+#define WM8996_WRITE_SEQUENCER_453              0x31C5
+#define WM8996_WRITE_SEQUENCER_454              0x31C6
+#define WM8996_WRITE_SEQUENCER_455              0x31C7
+#define WM8996_WRITE_SEQUENCER_456              0x31C8
+#define WM8996_WRITE_SEQUENCER_457              0x31C9
+#define WM8996_WRITE_SEQUENCER_458              0x31CA
+#define WM8996_WRITE_SEQUENCER_459              0x31CB
+#define WM8996_WRITE_SEQUENCER_460              0x31CC
+#define WM8996_WRITE_SEQUENCER_461              0x31CD
+#define WM8996_WRITE_SEQUENCER_462              0x31CE
+#define WM8996_WRITE_SEQUENCER_463              0x31CF
+#define WM8996_WRITE_SEQUENCER_464              0x31D0
+#define WM8996_WRITE_SEQUENCER_465              0x31D1
+#define WM8996_WRITE_SEQUENCER_466              0x31D2
+#define WM8996_WRITE_SEQUENCER_467              0x31D3
+#define WM8996_WRITE_SEQUENCER_468              0x31D4
+#define WM8996_WRITE_SEQUENCER_469              0x31D5
+#define WM8996_WRITE_SEQUENCER_470              0x31D6
+#define WM8996_WRITE_SEQUENCER_471              0x31D7
+#define WM8996_WRITE_SEQUENCER_472              0x31D8
+#define WM8996_WRITE_SEQUENCER_473              0x31D9
+#define WM8996_WRITE_SEQUENCER_474              0x31DA
+#define WM8996_WRITE_SEQUENCER_475              0x31DB
+#define WM8996_WRITE_SEQUENCER_476              0x31DC
+#define WM8996_WRITE_SEQUENCER_477              0x31DD
+#define WM8996_WRITE_SEQUENCER_478              0x31DE
+#define WM8996_WRITE_SEQUENCER_479              0x31DF
+#define WM8996_WRITE_SEQUENCER_480              0x31E0
+#define WM8996_WRITE_SEQUENCER_481              0x31E1
+#define WM8996_WRITE_SEQUENCER_482              0x31E2
+#define WM8996_WRITE_SEQUENCER_483              0x31E3
+#define WM8996_WRITE_SEQUENCER_484              0x31E4
+#define WM8996_WRITE_SEQUENCER_485              0x31E5
+#define WM8996_WRITE_SEQUENCER_486              0x31E6
+#define WM8996_WRITE_SEQUENCER_487              0x31E7
+#define WM8996_WRITE_SEQUENCER_488              0x31E8
+#define WM8996_WRITE_SEQUENCER_489              0x31E9
+#define WM8996_WRITE_SEQUENCER_490              0x31EA
+#define WM8996_WRITE_SEQUENCER_491              0x31EB
+#define WM8996_WRITE_SEQUENCER_492              0x31EC
+#define WM8996_WRITE_SEQUENCER_493              0x31ED
+#define WM8996_WRITE_SEQUENCER_494              0x31EE
+#define WM8996_WRITE_SEQUENCER_495              0x31EF
+#define WM8996_WRITE_SEQUENCER_496              0x31F0
+#define WM8996_WRITE_SEQUENCER_497              0x31F1
+#define WM8996_WRITE_SEQUENCER_498              0x31F2
+#define WM8996_WRITE_SEQUENCER_499              0x31F3
+#define WM8996_WRITE_SEQUENCER_500              0x31F4
+#define WM8996_WRITE_SEQUENCER_501              0x31F5
+#define WM8996_WRITE_SEQUENCER_502              0x31F6
+#define WM8996_WRITE_SEQUENCER_503              0x31F7
+#define WM8996_WRITE_SEQUENCER_504              0x31F8
+#define WM8996_WRITE_SEQUENCER_505              0x31F9
+#define WM8996_WRITE_SEQUENCER_506              0x31FA
+#define WM8996_WRITE_SEQUENCER_507              0x31FB
+#define WM8996_WRITE_SEQUENCER_508              0x31FC
+#define WM8996_WRITE_SEQUENCER_509              0x31FD
+#define WM8996_WRITE_SEQUENCER_510              0x31FE
+#define WM8996_WRITE_SEQUENCER_511              0x31FF
+
+#define WM8996_REGISTER_COUNT                   706
+#define WM8996_MAX_REGISTER                     0x31FF
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8996_SW_RESET_MASK                    0xFFFF  /* SW_RESET - [15:0] */
+#define WM8996_SW_RESET_SHIFT                        0  /* SW_RESET - [15:0] */
+#define WM8996_SW_RESET_WIDTH                       16  /* SW_RESET - [15:0] */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM8996_MICB2_ENA                        0x0200  /* MICB2_ENA */
+#define WM8996_MICB2_ENA_MASK                   0x0200  /* MICB2_ENA */
+#define WM8996_MICB2_ENA_SHIFT                       9  /* MICB2_ENA */
+#define WM8996_MICB2_ENA_WIDTH                       1  /* MICB2_ENA */
+#define WM8996_MICB1_ENA                        0x0100  /* MICB1_ENA */
+#define WM8996_MICB1_ENA_MASK                   0x0100  /* MICB1_ENA */
+#define WM8996_MICB1_ENA_SHIFT                       8  /* MICB1_ENA */
+#define WM8996_MICB1_ENA_WIDTH                       1  /* MICB1_ENA */
+#define WM8996_HPOUT2L_ENA                      0x0080  /* HPOUT2L_ENA */
+#define WM8996_HPOUT2L_ENA_MASK                 0x0080  /* HPOUT2L_ENA */
+#define WM8996_HPOUT2L_ENA_SHIFT                     7  /* HPOUT2L_ENA */
+#define WM8996_HPOUT2L_ENA_WIDTH                     1  /* HPOUT2L_ENA */
+#define WM8996_HPOUT2R_ENA                      0x0040  /* HPOUT2R_ENA */
+#define WM8996_HPOUT2R_ENA_MASK                 0x0040  /* HPOUT2R_ENA */
+#define WM8996_HPOUT2R_ENA_SHIFT                     6  /* HPOUT2R_ENA */
+#define WM8996_HPOUT2R_ENA_WIDTH                     1  /* HPOUT2R_ENA */
+#define WM8996_HPOUT1L_ENA                      0x0020  /* HPOUT1L_ENA */
+#define WM8996_HPOUT1L_ENA_MASK                 0x0020  /* HPOUT1L_ENA */
+#define WM8996_HPOUT1L_ENA_SHIFT                     5  /* HPOUT1L_ENA */
+#define WM8996_HPOUT1L_ENA_WIDTH                     1  /* HPOUT1L_ENA */
+#define WM8996_HPOUT1R_ENA                      0x0010  /* HPOUT1R_ENA */
+#define WM8996_HPOUT1R_ENA_MASK                 0x0010  /* HPOUT1R_ENA */
+#define WM8996_HPOUT1R_ENA_SHIFT                     4  /* HPOUT1R_ENA */
+#define WM8996_HPOUT1R_ENA_WIDTH                     1  /* HPOUT1R_ENA */
+#define WM8996_BG_ENA                           0x0001  /* BG_ENA */
+#define WM8996_BG_ENA_MASK                      0x0001  /* BG_ENA */
+#define WM8996_BG_ENA_SHIFT                          0  /* BG_ENA */
+#define WM8996_BG_ENA_WIDTH                          1  /* BG_ENA */
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM8996_OPCLK_ENA                        0x0800  /* OPCLK_ENA */
+#define WM8996_OPCLK_ENA_MASK                   0x0800  /* OPCLK_ENA */
+#define WM8996_OPCLK_ENA_SHIFT                      11  /* OPCLK_ENA */
+#define WM8996_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8996_INL_ENA                          0x0020  /* INL_ENA */
+#define WM8996_INL_ENA_MASK                     0x0020  /* INL_ENA */
+#define WM8996_INL_ENA_SHIFT                         5  /* INL_ENA */
+#define WM8996_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8996_INR_ENA                          0x0010  /* INR_ENA */
+#define WM8996_INR_ENA_MASK                     0x0010  /* INR_ENA */
+#define WM8996_INR_ENA_SHIFT                         4  /* INR_ENA */
+#define WM8996_INR_ENA_WIDTH                         1  /* INR_ENA */
+#define WM8996_LDO2_ENA                         0x0002  /* LDO2_ENA */
+#define WM8996_LDO2_ENA_MASK                    0x0002  /* LDO2_ENA */
+#define WM8996_LDO2_ENA_SHIFT                        1  /* LDO2_ENA */
+#define WM8996_LDO2_ENA_WIDTH                        1  /* LDO2_ENA */
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM8996_DSP2RXL_ENA                      0x0800  /* DSP2RXL_ENA */
+#define WM8996_DSP2RXL_ENA_MASK                 0x0800  /* DSP2RXL_ENA */
+#define WM8996_DSP2RXL_ENA_SHIFT                    11  /* DSP2RXL_ENA */
+#define WM8996_DSP2RXL_ENA_WIDTH                     1  /* DSP2RXL_ENA */
+#define WM8996_DSP2RXR_ENA                      0x0400  /* DSP2RXR_ENA */
+#define WM8996_DSP2RXR_ENA_MASK                 0x0400  /* DSP2RXR_ENA */
+#define WM8996_DSP2RXR_ENA_SHIFT                    10  /* DSP2RXR_ENA */
+#define WM8996_DSP2RXR_ENA_WIDTH                     1  /* DSP2RXR_ENA */
+#define WM8996_DSP1RXL_ENA                      0x0200  /* DSP1RXL_ENA */
+#define WM8996_DSP1RXL_ENA_MASK                 0x0200  /* DSP1RXL_ENA */
+#define WM8996_DSP1RXL_ENA_SHIFT                     9  /* DSP1RXL_ENA */
+#define WM8996_DSP1RXL_ENA_WIDTH                     1  /* DSP1RXL_ENA */
+#define WM8996_DSP1RXR_ENA                      0x0100  /* DSP1RXR_ENA */
+#define WM8996_DSP1RXR_ENA_MASK                 0x0100  /* DSP1RXR_ENA */
+#define WM8996_DSP1RXR_ENA_SHIFT                     8  /* DSP1RXR_ENA */
+#define WM8996_DSP1RXR_ENA_WIDTH                     1  /* DSP1RXR_ENA */
+#define WM8996_DMIC2L_ENA                       0x0020  /* DMIC2L_ENA */
+#define WM8996_DMIC2L_ENA_MASK                  0x0020  /* DMIC2L_ENA */
+#define WM8996_DMIC2L_ENA_SHIFT                      5  /* DMIC2L_ENA */
+#define WM8996_DMIC2L_ENA_WIDTH                      1  /* DMIC2L_ENA */
+#define WM8996_DMIC2R_ENA                       0x0010  /* DMIC2R_ENA */
+#define WM8996_DMIC2R_ENA_MASK                  0x0010  /* DMIC2R_ENA */
+#define WM8996_DMIC2R_ENA_SHIFT                      4  /* DMIC2R_ENA */
+#define WM8996_DMIC2R_ENA_WIDTH                      1  /* DMIC2R_ENA */
+#define WM8996_DMIC1L_ENA                       0x0008  /* DMIC1L_ENA */
+#define WM8996_DMIC1L_ENA_MASK                  0x0008  /* DMIC1L_ENA */
+#define WM8996_DMIC1L_ENA_SHIFT                      3  /* DMIC1L_ENA */
+#define WM8996_DMIC1L_ENA_WIDTH                      1  /* DMIC1L_ENA */
+#define WM8996_DMIC1R_ENA                       0x0004  /* DMIC1R_ENA */
+#define WM8996_DMIC1R_ENA_MASK                  0x0004  /* DMIC1R_ENA */
+#define WM8996_DMIC1R_ENA_SHIFT                      2  /* DMIC1R_ENA */
+#define WM8996_DMIC1R_ENA_WIDTH                      1  /* DMIC1R_ENA */
+#define WM8996_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8996_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8996_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8996_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8996_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8996_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8996_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8996_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R4 (0x04) - Power Management (4)
+ */
+#define WM8996_AIF2RX_CHAN1_ENA                 0x0200  /* AIF2RX_CHAN1_ENA */
+#define WM8996_AIF2RX_CHAN1_ENA_MASK            0x0200  /* AIF2RX_CHAN1_ENA */
+#define WM8996_AIF2RX_CHAN1_ENA_SHIFT                9  /* AIF2RX_CHAN1_ENA */
+#define WM8996_AIF2RX_CHAN1_ENA_WIDTH                1  /* AIF2RX_CHAN1_ENA */
+#define WM8996_AIF2RX_CHAN0_ENA                 0x0100  /* AIF2RX_CHAN0_ENA */
+#define WM8996_AIF2RX_CHAN0_ENA_MASK            0x0100  /* AIF2RX_CHAN0_ENA */
+#define WM8996_AIF2RX_CHAN0_ENA_SHIFT                8  /* AIF2RX_CHAN0_ENA */
+#define WM8996_AIF2RX_CHAN0_ENA_WIDTH                1  /* AIF2RX_CHAN0_ENA */
+#define WM8996_AIF1RX_CHAN5_ENA                 0x0020  /* AIF1RX_CHAN5_ENA */
+#define WM8996_AIF1RX_CHAN5_ENA_MASK            0x0020  /* AIF1RX_CHAN5_ENA */
+#define WM8996_AIF1RX_CHAN5_ENA_SHIFT                5  /* AIF1RX_CHAN5_ENA */
+#define WM8996_AIF1RX_CHAN5_ENA_WIDTH                1  /* AIF1RX_CHAN5_ENA */
+#define WM8996_AIF1RX_CHAN4_ENA                 0x0010  /* AIF1RX_CHAN4_ENA */
+#define WM8996_AIF1RX_CHAN4_ENA_MASK            0x0010  /* AIF1RX_CHAN4_ENA */
+#define WM8996_AIF1RX_CHAN4_ENA_SHIFT                4  /* AIF1RX_CHAN4_ENA */
+#define WM8996_AIF1RX_CHAN4_ENA_WIDTH                1  /* AIF1RX_CHAN4_ENA */
+#define WM8996_AIF1RX_CHAN3_ENA                 0x0008  /* AIF1RX_CHAN3_ENA */
+#define WM8996_AIF1RX_CHAN3_ENA_MASK            0x0008  /* AIF1RX_CHAN3_ENA */
+#define WM8996_AIF1RX_CHAN3_ENA_SHIFT                3  /* AIF1RX_CHAN3_ENA */
+#define WM8996_AIF1RX_CHAN3_ENA_WIDTH                1  /* AIF1RX_CHAN3_ENA */
+#define WM8996_AIF1RX_CHAN2_ENA                 0x0004  /* AIF1RX_CHAN2_ENA */
+#define WM8996_AIF1RX_CHAN2_ENA_MASK            0x0004  /* AIF1RX_CHAN2_ENA */
+#define WM8996_AIF1RX_CHAN2_ENA_SHIFT                2  /* AIF1RX_CHAN2_ENA */
+#define WM8996_AIF1RX_CHAN2_ENA_WIDTH                1  /* AIF1RX_CHAN2_ENA */
+#define WM8996_AIF1RX_CHAN1_ENA                 0x0002  /* AIF1RX_CHAN1_ENA */
+#define WM8996_AIF1RX_CHAN1_ENA_MASK            0x0002  /* AIF1RX_CHAN1_ENA */
+#define WM8996_AIF1RX_CHAN1_ENA_SHIFT                1  /* AIF1RX_CHAN1_ENA */
+#define WM8996_AIF1RX_CHAN1_ENA_WIDTH                1  /* AIF1RX_CHAN1_ENA */
+#define WM8996_AIF1RX_CHAN0_ENA                 0x0001  /* AIF1RX_CHAN0_ENA */
+#define WM8996_AIF1RX_CHAN0_ENA_MASK            0x0001  /* AIF1RX_CHAN0_ENA */
+#define WM8996_AIF1RX_CHAN0_ENA_SHIFT                0  /* AIF1RX_CHAN0_ENA */
+#define WM8996_AIF1RX_CHAN0_ENA_WIDTH                1  /* AIF1RX_CHAN0_ENA */
+
+/*
+ * R5 (0x05) - Power Management (5)
+ */
+#define WM8996_DSP2TXL_ENA                      0x0800  /* DSP2TXL_ENA */
+#define WM8996_DSP2TXL_ENA_MASK                 0x0800  /* DSP2TXL_ENA */
+#define WM8996_DSP2TXL_ENA_SHIFT                    11  /* DSP2TXL_ENA */
+#define WM8996_DSP2TXL_ENA_WIDTH                     1  /* DSP2TXL_ENA */
+#define WM8996_DSP2TXR_ENA                      0x0400  /* DSP2TXR_ENA */
+#define WM8996_DSP2TXR_ENA_MASK                 0x0400  /* DSP2TXR_ENA */
+#define WM8996_DSP2TXR_ENA_SHIFT                    10  /* DSP2TXR_ENA */
+#define WM8996_DSP2TXR_ENA_WIDTH                     1  /* DSP2TXR_ENA */
+#define WM8996_DSP1TXL_ENA                      0x0200  /* DSP1TXL_ENA */
+#define WM8996_DSP1TXL_ENA_MASK                 0x0200  /* DSP1TXL_ENA */
+#define WM8996_DSP1TXL_ENA_SHIFT                     9  /* DSP1TXL_ENA */
+#define WM8996_DSP1TXL_ENA_WIDTH                     1  /* DSP1TXL_ENA */
+#define WM8996_DSP1TXR_ENA                      0x0100  /* DSP1TXR_ENA */
+#define WM8996_DSP1TXR_ENA_MASK                 0x0100  /* DSP1TXR_ENA */
+#define WM8996_DSP1TXR_ENA_SHIFT                     8  /* DSP1TXR_ENA */
+#define WM8996_DSP1TXR_ENA_WIDTH                     1  /* DSP1TXR_ENA */
+#define WM8996_DAC2L_ENA                        0x0008  /* DAC2L_ENA */
+#define WM8996_DAC2L_ENA_MASK                   0x0008  /* DAC2L_ENA */
+#define WM8996_DAC2L_ENA_SHIFT                       3  /* DAC2L_ENA */
+#define WM8996_DAC2L_ENA_WIDTH                       1  /* DAC2L_ENA */
+#define WM8996_DAC2R_ENA                        0x0004  /* DAC2R_ENA */
+#define WM8996_DAC2R_ENA_MASK                   0x0004  /* DAC2R_ENA */
+#define WM8996_DAC2R_ENA_SHIFT                       2  /* DAC2R_ENA */
+#define WM8996_DAC2R_ENA_WIDTH                       1  /* DAC2R_ENA */
+#define WM8996_DAC1L_ENA                        0x0002  /* DAC1L_ENA */
+#define WM8996_DAC1L_ENA_MASK                   0x0002  /* DAC1L_ENA */
+#define WM8996_DAC1L_ENA_SHIFT                       1  /* DAC1L_ENA */
+#define WM8996_DAC1L_ENA_WIDTH                       1  /* DAC1L_ENA */
+#define WM8996_DAC1R_ENA                        0x0001  /* DAC1R_ENA */
+#define WM8996_DAC1R_ENA_MASK                   0x0001  /* DAC1R_ENA */
+#define WM8996_DAC1R_ENA_SHIFT                       0  /* DAC1R_ENA */
+#define WM8996_DAC1R_ENA_WIDTH                       1  /* DAC1R_ENA */
+
+/*
+ * R6 (0x06) - Power Management (6)
+ */
+#define WM8996_AIF2TX_CHAN1_ENA                 0x0200  /* AIF2TX_CHAN1_ENA */
+#define WM8996_AIF2TX_CHAN1_ENA_MASK            0x0200  /* AIF2TX_CHAN1_ENA */
+#define WM8996_AIF2TX_CHAN1_ENA_SHIFT                9  /* AIF2TX_CHAN1_ENA */
+#define WM8996_AIF2TX_CHAN1_ENA_WIDTH                1  /* AIF2TX_CHAN1_ENA */
+#define WM8996_AIF2TX_CHAN0_ENA                 0x0100  /* AIF2TX_CHAN0_ENA */
+#define WM8996_AIF2TX_CHAN0_ENA_MASK            0x0100  /* AIF2TX_CHAN0_ENA */
+#define WM8996_AIF2TX_CHAN0_ENA_SHIFT                8  /* AIF2TX_CHAN0_ENA */
+#define WM8996_AIF2TX_CHAN0_ENA_WIDTH                1  /* AIF2TX_CHAN0_ENA */
+#define WM8996_AIF1TX_CHAN5_ENA                 0x0020  /* AIF1TX_CHAN5_ENA */
+#define WM8996_AIF1TX_CHAN5_ENA_MASK            0x0020  /* AIF1TX_CHAN5_ENA */
+#define WM8996_AIF1TX_CHAN5_ENA_SHIFT                5  /* AIF1TX_CHAN5_ENA */
+#define WM8996_AIF1TX_CHAN5_ENA_WIDTH                1  /* AIF1TX_CHAN5_ENA */
+#define WM8996_AIF1TX_CHAN4_ENA                 0x0010  /* AIF1TX_CHAN4_ENA */
+#define WM8996_AIF1TX_CHAN4_ENA_MASK            0x0010  /* AIF1TX_CHAN4_ENA */
+#define WM8996_AIF1TX_CHAN4_ENA_SHIFT                4  /* AIF1TX_CHAN4_ENA */
+#define WM8996_AIF1TX_CHAN4_ENA_WIDTH                1  /* AIF1TX_CHAN4_ENA */
+#define WM8996_AIF1TX_CHAN3_ENA                 0x0008  /* AIF1TX_CHAN3_ENA */
+#define WM8996_AIF1TX_CHAN3_ENA_MASK            0x0008  /* AIF1TX_CHAN3_ENA */
+#define WM8996_AIF1TX_CHAN3_ENA_SHIFT                3  /* AIF1TX_CHAN3_ENA */
+#define WM8996_AIF1TX_CHAN3_ENA_WIDTH                1  /* AIF1TX_CHAN3_ENA */
+#define WM8996_AIF1TX_CHAN2_ENA                 0x0004  /* AIF1TX_CHAN2_ENA */
+#define WM8996_AIF1TX_CHAN2_ENA_MASK            0x0004  /* AIF1TX_CHAN2_ENA */
+#define WM8996_AIF1TX_CHAN2_ENA_SHIFT                2  /* AIF1TX_CHAN2_ENA */
+#define WM8996_AIF1TX_CHAN2_ENA_WIDTH                1  /* AIF1TX_CHAN2_ENA */
+#define WM8996_AIF1TX_CHAN1_ENA                 0x0002  /* AIF1TX_CHAN1_ENA */
+#define WM8996_AIF1TX_CHAN1_ENA_MASK            0x0002  /* AIF1TX_CHAN1_ENA */
+#define WM8996_AIF1TX_CHAN1_ENA_SHIFT                1  /* AIF1TX_CHAN1_ENA */
+#define WM8996_AIF1TX_CHAN1_ENA_WIDTH                1  /* AIF1TX_CHAN1_ENA */
+#define WM8996_AIF1TX_CHAN0_ENA                 0x0001  /* AIF1TX_CHAN0_ENA */
+#define WM8996_AIF1TX_CHAN0_ENA_MASK            0x0001  /* AIF1TX_CHAN0_ENA */
+#define WM8996_AIF1TX_CHAN0_ENA_SHIFT                0  /* AIF1TX_CHAN0_ENA */
+#define WM8996_AIF1TX_CHAN0_ENA_WIDTH                1  /* AIF1TX_CHAN0_ENA */
+
+/*
+ * R7 (0x07) - Power Management (7)
+ */
+#define WM8996_DMIC2_FN                         0x0200  /* DMIC2_FN */
+#define WM8996_DMIC2_FN_MASK                    0x0200  /* DMIC2_FN */
+#define WM8996_DMIC2_FN_SHIFT                        9  /* DMIC2_FN */
+#define WM8996_DMIC2_FN_WIDTH                        1  /* DMIC2_FN */
+#define WM8996_DMIC1_FN                         0x0100  /* DMIC1_FN */
+#define WM8996_DMIC1_FN_MASK                    0x0100  /* DMIC1_FN */
+#define WM8996_DMIC1_FN_SHIFT                        8  /* DMIC1_FN */
+#define WM8996_DMIC1_FN_WIDTH                        1  /* DMIC1_FN */
+#define WM8996_ADC_DMIC_DSP2R_ENA               0x0080  /* ADC_DMIC_DSP2R_ENA */
+#define WM8996_ADC_DMIC_DSP2R_ENA_MASK          0x0080  /* ADC_DMIC_DSP2R_ENA */
+#define WM8996_ADC_DMIC_DSP2R_ENA_SHIFT              7  /* ADC_DMIC_DSP2R_ENA */
+#define WM8996_ADC_DMIC_DSP2R_ENA_WIDTH              1  /* ADC_DMIC_DSP2R_ENA */
+#define WM8996_ADC_DMIC_DSP2L_ENA               0x0040  /* ADC_DMIC_DSP2L_ENA */
+#define WM8996_ADC_DMIC_DSP2L_ENA_MASK          0x0040  /* ADC_DMIC_DSP2L_ENA */
+#define WM8996_ADC_DMIC_DSP2L_ENA_SHIFT              6  /* ADC_DMIC_DSP2L_ENA */
+#define WM8996_ADC_DMIC_DSP2L_ENA_WIDTH              1  /* ADC_DMIC_DSP2L_ENA */
+#define WM8996_ADC_DMIC_SRC2_MASK               0x0030  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8996_ADC_DMIC_SRC2_SHIFT                   4  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8996_ADC_DMIC_SRC2_WIDTH                   2  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8996_ADC_DMIC_DSP1R_ENA               0x0008  /* ADC_DMIC_DSP1R_ENA */
+#define WM8996_ADC_DMIC_DSP1R_ENA_MASK          0x0008  /* ADC_DMIC_DSP1R_ENA */
+#define WM8996_ADC_DMIC_DSP1R_ENA_SHIFT              3  /* ADC_DMIC_DSP1R_ENA */
+#define WM8996_ADC_DMIC_DSP1R_ENA_WIDTH              1  /* ADC_DMIC_DSP1R_ENA */
+#define WM8996_ADC_DMIC_DSP1L_ENA               0x0004  /* ADC_DMIC_DSP1L_ENA */
+#define WM8996_ADC_DMIC_DSP1L_ENA_MASK          0x0004  /* ADC_DMIC_DSP1L_ENA */
+#define WM8996_ADC_DMIC_DSP1L_ENA_SHIFT              2  /* ADC_DMIC_DSP1L_ENA */
+#define WM8996_ADC_DMIC_DSP1L_ENA_WIDTH              1  /* ADC_DMIC_DSP1L_ENA */
+#define WM8996_ADC_DMIC_SRC1_MASK               0x0003  /* ADC_DMIC_SRC1 - [1:0] */
+#define WM8996_ADC_DMIC_SRC1_SHIFT                   0  /* ADC_DMIC_SRC1 - [1:0] */
+#define WM8996_ADC_DMIC_SRC1_WIDTH                   2  /* ADC_DMIC_SRC1 - [1:0] */
+
+/*
+ * R8 (0x08) - Power Management (8)
+ */
+#define WM8996_AIF2TX_SRC_MASK                  0x00C0  /* AIF2TX_SRC - [7:6] */
+#define WM8996_AIF2TX_SRC_SHIFT                      6  /* AIF2TX_SRC - [7:6] */
+#define WM8996_AIF2TX_SRC_WIDTH                      2  /* AIF2TX_SRC - [7:6] */
+#define WM8996_DSP2RX_SRC                       0x0010  /* DSP2RX_SRC */
+#define WM8996_DSP2RX_SRC_MASK                  0x0010  /* DSP2RX_SRC */
+#define WM8996_DSP2RX_SRC_SHIFT                      4  /* DSP2RX_SRC */
+#define WM8996_DSP2RX_SRC_WIDTH                      1  /* DSP2RX_SRC */
+#define WM8996_DSP1RX_SRC                       0x0001  /* DSP1RX_SRC */
+#define WM8996_DSP1RX_SRC_MASK                  0x0001  /* DSP1RX_SRC */
+#define WM8996_DSP1RX_SRC_SHIFT                      0  /* DSP1RX_SRC */
+#define WM8996_DSP1RX_SRC_WIDTH                      1  /* DSP1RX_SRC */
+
+/*
+ * R16 (0x10) - Left Line Input Volume
+ */
+#define WM8996_IN1_VU                           0x0080  /* IN1_VU */
+#define WM8996_IN1_VU_MASK                      0x0080  /* IN1_VU */
+#define WM8996_IN1_VU_SHIFT                          7  /* IN1_VU */
+#define WM8996_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM8996_IN1L_ZC                          0x0020  /* IN1L_ZC */
+#define WM8996_IN1L_ZC_MASK                     0x0020  /* IN1L_ZC */
+#define WM8996_IN1L_ZC_SHIFT                         5  /* IN1L_ZC */
+#define WM8996_IN1L_ZC_WIDTH                         1  /* IN1L_ZC */
+#define WM8996_IN1L_VOL_MASK                    0x001F  /* IN1L_VOL - [4:0] */
+#define WM8996_IN1L_VOL_SHIFT                        0  /* IN1L_VOL - [4:0] */
+#define WM8996_IN1L_VOL_WIDTH                        5  /* IN1L_VOL - [4:0] */
+
+/*
+ * R17 (0x11) - Right Line Input Volume
+ */
+#define WM8996_IN1_VU                           0x0080  /* IN1_VU */
+#define WM8996_IN1_VU_MASK                      0x0080  /* IN1_VU */
+#define WM8996_IN1_VU_SHIFT                          7  /* IN1_VU */
+#define WM8996_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM8996_IN1R_ZC                          0x0020  /* IN1R_ZC */
+#define WM8996_IN1R_ZC_MASK                     0x0020  /* IN1R_ZC */
+#define WM8996_IN1R_ZC_SHIFT                         5  /* IN1R_ZC */
+#define WM8996_IN1R_ZC_WIDTH                         1  /* IN1R_ZC */
+#define WM8996_IN1R_VOL_MASK                    0x001F  /* IN1R_VOL - [4:0] */
+#define WM8996_IN1R_VOL_SHIFT                        0  /* IN1R_VOL - [4:0] */
+#define WM8996_IN1R_VOL_WIDTH                        5  /* IN1R_VOL - [4:0] */
+
+/*
+ * R18 (0x12) - Line Input Control
+ */
+#define WM8996_INL_MODE_MASK                    0x000C  /* INL_MODE - [3:2] */
+#define WM8996_INL_MODE_SHIFT                        2  /* INL_MODE - [3:2] */
+#define WM8996_INL_MODE_WIDTH                        2  /* INL_MODE - [3:2] */
+#define WM8996_INR_MODE_MASK                    0x0003  /* INR_MODE - [1:0] */
+#define WM8996_INR_MODE_SHIFT                        0  /* INR_MODE - [1:0] */
+#define WM8996_INR_MODE_WIDTH                        2  /* INR_MODE - [1:0] */
+
+/*
+ * R21 (0x15) - DAC1 HPOUT1 Volume
+ */
+#define WM8996_DAC1R_HPOUT1R_VOL_MASK           0x00F0  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8996_DAC1R_HPOUT1R_VOL_SHIFT               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8996_DAC1R_HPOUT1R_VOL_WIDTH               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8996_DAC1L_HPOUT1L_VOL_MASK           0x000F  /* DAC1L_HPOUT1L_VOL - [3:0] */
+#define WM8996_DAC1L_HPOUT1L_VOL_SHIFT               0  /* DAC1L_HPOUT1L_VOL - [3:0] */
+#define WM8996_DAC1L_HPOUT1L_VOL_WIDTH               4  /* DAC1L_HPOUT1L_VOL - [3:0] */
+
+/*
+ * R22 (0x16) - DAC2 HPOUT2 Volume
+ */
+#define WM8996_DAC2R_HPOUT2R_VOL_MASK           0x00F0  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8996_DAC2R_HPOUT2R_VOL_SHIFT               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8996_DAC2R_HPOUT2R_VOL_WIDTH               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8996_DAC2L_HPOUT2L_VOL_MASK           0x000F  /* DAC2L_HPOUT2L_VOL - [3:0] */
+#define WM8996_DAC2L_HPOUT2L_VOL_SHIFT               0  /* DAC2L_HPOUT2L_VOL - [3:0] */
+#define WM8996_DAC2L_HPOUT2L_VOL_WIDTH               4  /* DAC2L_HPOUT2L_VOL - [3:0] */
+
+/*
+ * R24 (0x18) - DAC1 Left Volume
+ */
+#define WM8996_DAC1L_MUTE                       0x0200  /* DAC1L_MUTE */
+#define WM8996_DAC1L_MUTE_MASK                  0x0200  /* DAC1L_MUTE */
+#define WM8996_DAC1L_MUTE_SHIFT                      9  /* DAC1L_MUTE */
+#define WM8996_DAC1L_MUTE_WIDTH                      1  /* DAC1L_MUTE */
+#define WM8996_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8996_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8996_DAC1L_VOL_MASK                   0x00FF  /* DAC1L_VOL - [7:0] */
+#define WM8996_DAC1L_VOL_SHIFT                       0  /* DAC1L_VOL - [7:0] */
+#define WM8996_DAC1L_VOL_WIDTH                       8  /* DAC1L_VOL - [7:0] */
+
+/*
+ * R25 (0x19) - DAC1 Right Volume
+ */
+#define WM8996_DAC1R_MUTE                       0x0200  /* DAC1R_MUTE */
+#define WM8996_DAC1R_MUTE_MASK                  0x0200  /* DAC1R_MUTE */
+#define WM8996_DAC1R_MUTE_SHIFT                      9  /* DAC1R_MUTE */
+#define WM8996_DAC1R_MUTE_WIDTH                      1  /* DAC1R_MUTE */
+#define WM8996_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8996_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8996_DAC1R_VOL_MASK                   0x00FF  /* DAC1R_VOL - [7:0] */
+#define WM8996_DAC1R_VOL_SHIFT                       0  /* DAC1R_VOL - [7:0] */
+#define WM8996_DAC1R_VOL_WIDTH                       8  /* DAC1R_VOL - [7:0] */
+
+/*
+ * R26 (0x1A) - DAC2 Left Volume
+ */
+#define WM8996_DAC2L_MUTE                       0x0200  /* DAC2L_MUTE */
+#define WM8996_DAC2L_MUTE_MASK                  0x0200  /* DAC2L_MUTE */
+#define WM8996_DAC2L_MUTE_SHIFT                      9  /* DAC2L_MUTE */
+#define WM8996_DAC2L_MUTE_WIDTH                      1  /* DAC2L_MUTE */
+#define WM8996_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8996_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8996_DAC2L_VOL_MASK                   0x00FF  /* DAC2L_VOL - [7:0] */
+#define WM8996_DAC2L_VOL_SHIFT                       0  /* DAC2L_VOL - [7:0] */
+#define WM8996_DAC2L_VOL_WIDTH                       8  /* DAC2L_VOL - [7:0] */
+
+/*
+ * R27 (0x1B) - DAC2 Right Volume
+ */
+#define WM8996_DAC2R_MUTE                       0x0200  /* DAC2R_MUTE */
+#define WM8996_DAC2R_MUTE_MASK                  0x0200  /* DAC2R_MUTE */
+#define WM8996_DAC2R_MUTE_SHIFT                      9  /* DAC2R_MUTE */
+#define WM8996_DAC2R_MUTE_WIDTH                      1  /* DAC2R_MUTE */
+#define WM8996_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8996_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8996_DAC2R_VOL_MASK                   0x00FF  /* DAC2R_VOL - [7:0] */
+#define WM8996_DAC2R_VOL_SHIFT                       0  /* DAC2R_VOL - [7:0] */
+#define WM8996_DAC2R_VOL_WIDTH                       8  /* DAC2R_VOL - [7:0] */
+
+/*
+ * R28 (0x1C) - Output1 Left Volume
+ */
+#define WM8996_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8996_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8996_HPOUT1L_ZC                       0x0080  /* HPOUT1L_ZC */
+#define WM8996_HPOUT1L_ZC_MASK                  0x0080  /* HPOUT1L_ZC */
+#define WM8996_HPOUT1L_ZC_SHIFT                      7  /* HPOUT1L_ZC */
+#define WM8996_HPOUT1L_ZC_WIDTH                      1  /* HPOUT1L_ZC */
+#define WM8996_HPOUT1L_VOL_MASK                 0x000F  /* HPOUT1L_VOL - [3:0] */
+#define WM8996_HPOUT1L_VOL_SHIFT                     0  /* HPOUT1L_VOL - [3:0] */
+#define WM8996_HPOUT1L_VOL_WIDTH                     4  /* HPOUT1L_VOL - [3:0] */
+
+/*
+ * R29 (0x1D) - Output1 Right Volume
+ */
+#define WM8996_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8996_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8996_HPOUT1R_ZC                       0x0080  /* HPOUT1R_ZC */
+#define WM8996_HPOUT1R_ZC_MASK                  0x0080  /* HPOUT1R_ZC */
+#define WM8996_HPOUT1R_ZC_SHIFT                      7  /* HPOUT1R_ZC */
+#define WM8996_HPOUT1R_ZC_WIDTH                      1  /* HPOUT1R_ZC */
+#define WM8996_HPOUT1R_VOL_MASK                 0x000F  /* HPOUT1R_VOL - [3:0] */
+#define WM8996_HPOUT1R_VOL_SHIFT                     0  /* HPOUT1R_VOL - [3:0] */
+#define WM8996_HPOUT1R_VOL_WIDTH                     4  /* HPOUT1R_VOL - [3:0] */
+
+/*
+ * R30 (0x1E) - Output2 Left Volume
+ */
+#define WM8996_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8996_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8996_HPOUT2L_ZC                       0x0080  /* HPOUT2L_ZC */
+#define WM8996_HPOUT2L_ZC_MASK                  0x0080  /* HPOUT2L_ZC */
+#define WM8996_HPOUT2L_ZC_SHIFT                      7  /* HPOUT2L_ZC */
+#define WM8996_HPOUT2L_ZC_WIDTH                      1  /* HPOUT2L_ZC */
+#define WM8996_HPOUT2L_VOL_MASK                 0x000F  /* HPOUT2L_VOL - [3:0] */
+#define WM8996_HPOUT2L_VOL_SHIFT                     0  /* HPOUT2L_VOL - [3:0] */
+#define WM8996_HPOUT2L_VOL_WIDTH                     4  /* HPOUT2L_VOL - [3:0] */
+
+/*
+ * R31 (0x1F) - Output2 Right Volume
+ */
+#define WM8996_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8996_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8996_HPOUT2R_ZC                       0x0080  /* HPOUT2R_ZC */
+#define WM8996_HPOUT2R_ZC_MASK                  0x0080  /* HPOUT2R_ZC */
+#define WM8996_HPOUT2R_ZC_SHIFT                      7  /* HPOUT2R_ZC */
+#define WM8996_HPOUT2R_ZC_WIDTH                      1  /* HPOUT2R_ZC */
+#define WM8996_HPOUT2R_VOL_MASK                 0x000F  /* HPOUT2R_VOL - [3:0] */
+#define WM8996_HPOUT2R_VOL_SHIFT                     0  /* HPOUT2R_VOL - [3:0] */
+#define WM8996_HPOUT2R_VOL_WIDTH                     4  /* HPOUT2R_VOL - [3:0] */
+
+/*
+ * R32 (0x20) - MICBIAS (1)
+ */
+#define WM8996_MICB1_RATE                       0x0020  /* MICB1_RATE */
+#define WM8996_MICB1_RATE_MASK                  0x0020  /* MICB1_RATE */
+#define WM8996_MICB1_RATE_SHIFT                      5  /* MICB1_RATE */
+#define WM8996_MICB1_RATE_WIDTH                      1  /* MICB1_RATE */
+#define WM8996_MICB1_MODE                       0x0010  /* MICB1_MODE */
+#define WM8996_MICB1_MODE_MASK                  0x0010  /* MICB1_MODE */
+#define WM8996_MICB1_MODE_SHIFT                      4  /* MICB1_MODE */
+#define WM8996_MICB1_MODE_WIDTH                      1  /* MICB1_MODE */
+#define WM8996_MICB1_LVL_MASK                   0x000E  /* MICB1_LVL - [3:1] */
+#define WM8996_MICB1_LVL_SHIFT                       1  /* MICB1_LVL - [3:1] */
+#define WM8996_MICB1_LVL_WIDTH                       3  /* MICB1_LVL - [3:1] */
+#define WM8996_MICB1_DISCH                      0x0001  /* MICB1_DISCH */
+#define WM8996_MICB1_DISCH_MASK                 0x0001  /* MICB1_DISCH */
+#define WM8996_MICB1_DISCH_SHIFT                     0  /* MICB1_DISCH */
+#define WM8996_MICB1_DISCH_WIDTH                     1  /* MICB1_DISCH */
+
+/*
+ * R33 (0x21) - MICBIAS (2)
+ */
+#define WM8996_MICB2_RATE                       0x0020  /* MICB2_RATE */
+#define WM8996_MICB2_RATE_MASK                  0x0020  /* MICB2_RATE */
+#define WM8996_MICB2_RATE_SHIFT                      5  /* MICB2_RATE */
+#define WM8996_MICB2_RATE_WIDTH                      1  /* MICB2_RATE */
+#define WM8996_MICB2_MODE                       0x0010  /* MICB2_MODE */
+#define WM8996_MICB2_MODE_MASK                  0x0010  /* MICB2_MODE */
+#define WM8996_MICB2_MODE_SHIFT                      4  /* MICB2_MODE */
+#define WM8996_MICB2_MODE_WIDTH                      1  /* MICB2_MODE */
+#define WM8996_MICB2_LVL_MASK                   0x000E  /* MICB2_LVL - [3:1] */
+#define WM8996_MICB2_LVL_SHIFT                       1  /* MICB2_LVL - [3:1] */
+#define WM8996_MICB2_LVL_WIDTH                       3  /* MICB2_LVL - [3:1] */
+#define WM8996_MICB2_DISCH                      0x0001  /* MICB2_DISCH */
+#define WM8996_MICB2_DISCH_MASK                 0x0001  /* MICB2_DISCH */
+#define WM8996_MICB2_DISCH_SHIFT                     0  /* MICB2_DISCH */
+#define WM8996_MICB2_DISCH_WIDTH                     1  /* MICB2_DISCH */
+
+/*
+ * R40 (0x28) - LDO 1
+ */
+#define WM8996_LDO1_MODE                        0x0020  /* LDO1_MODE */
+#define WM8996_LDO1_MODE_MASK                   0x0020  /* LDO1_MODE */
+#define WM8996_LDO1_MODE_SHIFT                       5  /* LDO1_MODE */
+#define WM8996_LDO1_MODE_WIDTH                       1  /* LDO1_MODE */
+#define WM8996_LDO1_VSEL_MASK                   0x0006  /* LDO1_VSEL - [2:1] */
+#define WM8996_LDO1_VSEL_SHIFT                       1  /* LDO1_VSEL - [2:1] */
+#define WM8996_LDO1_VSEL_WIDTH                       2  /* LDO1_VSEL - [2:1] */
+#define WM8996_LDO1_DISCH                       0x0001  /* LDO1_DISCH */
+#define WM8996_LDO1_DISCH_MASK                  0x0001  /* LDO1_DISCH */
+#define WM8996_LDO1_DISCH_SHIFT                      0  /* LDO1_DISCH */
+#define WM8996_LDO1_DISCH_WIDTH                      1  /* LDO1_DISCH */
+
+/*
+ * R41 (0x29) - LDO 2
+ */
+#define WM8996_LDO2_MODE                        0x0020  /* LDO2_MODE */
+#define WM8996_LDO2_MODE_MASK                   0x0020  /* LDO2_MODE */
+#define WM8996_LDO2_MODE_SHIFT                       5  /* LDO2_MODE */
+#define WM8996_LDO2_MODE_WIDTH                       1  /* LDO2_MODE */
+#define WM8996_LDO2_VSEL_MASK                   0x001E  /* LDO2_VSEL - [4:1] */
+#define WM8996_LDO2_VSEL_SHIFT                       1  /* LDO2_VSEL - [4:1] */
+#define WM8996_LDO2_VSEL_WIDTH                       4  /* LDO2_VSEL - [4:1] */
+#define WM8996_LDO2_DISCH                       0x0001  /* LDO2_DISCH */
+#define WM8996_LDO2_DISCH_MASK                  0x0001  /* LDO2_DISCH */
+#define WM8996_LDO2_DISCH_SHIFT                      0  /* LDO2_DISCH */
+#define WM8996_LDO2_DISCH_WIDTH                      1  /* LDO2_DISCH */
+
+/*
+ * R48 (0x30) - Accessory Detect Mode 1
+ */
+#define WM8996_JD_MODE_MASK                     0x0003  /* JD_MODE - [1:0] */
+#define WM8996_JD_MODE_SHIFT                         0  /* JD_MODE - [1:0] */
+#define WM8996_JD_MODE_WIDTH                         2  /* JD_MODE - [1:0] */
+
+/*
+ * R49 (0x31) - Accessory Detect Mode 2
+ */
+#define WM8996_HPOUT1FB_SRC                     0x0004  /* HPOUT1FB_SRC */
+#define WM8996_HPOUT1FB_SRC_MASK                0x0004  /* HPOUT1FB_SRC */
+#define WM8996_HPOUT1FB_SRC_SHIFT                    2  /* HPOUT1FB_SRC */
+#define WM8996_HPOUT1FB_SRC_WIDTH                    1  /* HPOUT1FB_SRC */
+#define WM8996_MICD_SRC                         0x0002  /* MICD_SRC */
+#define WM8996_MICD_SRC_MASK                    0x0002  /* MICD_SRC */
+#define WM8996_MICD_SRC_SHIFT                        1  /* MICD_SRC */
+#define WM8996_MICD_SRC_WIDTH                        1  /* MICD_SRC */
+#define WM8996_MICD_BIAS_SRC                    0x0001  /* MICD_BIAS_SRC */
+#define WM8996_MICD_BIAS_SRC_MASK               0x0001  /* MICD_BIAS_SRC */
+#define WM8996_MICD_BIAS_SRC_SHIFT                   0  /* MICD_BIAS_SRC */
+#define WM8996_MICD_BIAS_SRC_WIDTH                   1  /* MICD_BIAS_SRC */
+
+/*
+ * R52 (0x34) - Headphone Detect 1
+ */
+#define WM8996_HP_HOLDTIME_MASK                 0x00E0  /* HP_HOLDTIME - [7:5] */
+#define WM8996_HP_HOLDTIME_SHIFT                     5  /* HP_HOLDTIME - [7:5] */
+#define WM8996_HP_HOLDTIME_WIDTH                     3  /* HP_HOLDTIME - [7:5] */
+#define WM8996_HP_CLK_DIV_MASK                  0x0018  /* HP_CLK_DIV - [4:3] */
+#define WM8996_HP_CLK_DIV_SHIFT                      3  /* HP_CLK_DIV - [4:3] */
+#define WM8996_HP_CLK_DIV_WIDTH                      2  /* HP_CLK_DIV - [4:3] */
+#define WM8996_HP_STEP_SIZE                     0x0002  /* HP_STEP_SIZE */
+#define WM8996_HP_STEP_SIZE_MASK                0x0002  /* HP_STEP_SIZE */
+#define WM8996_HP_STEP_SIZE_SHIFT                    1  /* HP_STEP_SIZE */
+#define WM8996_HP_STEP_SIZE_WIDTH                    1  /* HP_STEP_SIZE */
+#define WM8996_HP_POLL                          0x0001  /* HP_POLL */
+#define WM8996_HP_POLL_MASK                     0x0001  /* HP_POLL */
+#define WM8996_HP_POLL_SHIFT                         0  /* HP_POLL */
+#define WM8996_HP_POLL_WIDTH                         1  /* HP_POLL */
+
+/*
+ * R53 (0x35) - Headphone Detect 2
+ */
+#define WM8996_HP_DONE                          0x0080  /* HP_DONE */
+#define WM8996_HP_DONE_MASK                     0x0080  /* HP_DONE */
+#define WM8996_HP_DONE_SHIFT                         7  /* HP_DONE */
+#define WM8996_HP_DONE_WIDTH                         1  /* HP_DONE */
+#define WM8996_HP_LVL_MASK                      0x007F  /* HP_LVL - [6:0] */
+#define WM8996_HP_LVL_SHIFT                          0  /* HP_LVL - [6:0] */
+#define WM8996_HP_LVL_WIDTH                          7  /* HP_LVL - [6:0] */
+
+/*
+ * R56 (0x38) - Mic Detect 1
+ */
+#define WM8996_MICD_BIAS_STARTTIME_MASK         0xF000  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8996_MICD_BIAS_STARTTIME_SHIFT            12  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8996_MICD_BIAS_STARTTIME_WIDTH             4  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8996_MICD_RATE_MASK                   0x0F00  /* MICD_RATE - [11:8] */
+#define WM8996_MICD_RATE_SHIFT                       8  /* MICD_RATE - [11:8] */
+#define WM8996_MICD_RATE_WIDTH                       4  /* MICD_RATE - [11:8] */
+#define WM8996_MICD_DBTIME                      0x0002  /* MICD_DBTIME */
+#define WM8996_MICD_DBTIME_MASK                 0x0002  /* MICD_DBTIME */
+#define WM8996_MICD_DBTIME_SHIFT                     1  /* MICD_DBTIME */
+#define WM8996_MICD_DBTIME_WIDTH                     1  /* MICD_DBTIME */
+#define WM8996_MICD_ENA                         0x0001  /* MICD_ENA */
+#define WM8996_MICD_ENA_MASK                    0x0001  /* MICD_ENA */
+#define WM8996_MICD_ENA_SHIFT                        0  /* MICD_ENA */
+#define WM8996_MICD_ENA_WIDTH                        1  /* MICD_ENA */
+
+/*
+ * R57 (0x39) - Mic Detect 2
+ */
+#define WM8996_MICD_LVL_SEL_MASK                0x00FF  /* MICD_LVL_SEL - [7:0] */
+#define WM8996_MICD_LVL_SEL_SHIFT                    0  /* MICD_LVL_SEL - [7:0] */
+#define WM8996_MICD_LVL_SEL_WIDTH                    8  /* MICD_LVL_SEL - [7:0] */
+
+/*
+ * R58 (0x3A) - Mic Detect 3
+ */
+#define WM8996_MICD_LVL_MASK                    0x07FC  /* MICD_LVL - [10:2] */
+#define WM8996_MICD_LVL_SHIFT                        2  /* MICD_LVL - [10:2] */
+#define WM8996_MICD_LVL_WIDTH                        9  /* MICD_LVL - [10:2] */
+#define WM8996_MICD_VALID                       0x0002  /* MICD_VALID */
+#define WM8996_MICD_VALID_MASK                  0x0002  /* MICD_VALID */
+#define WM8996_MICD_VALID_SHIFT                      1  /* MICD_VALID */
+#define WM8996_MICD_VALID_WIDTH                      1  /* MICD_VALID */
+#define WM8996_MICD_STS                         0x0001  /* MICD_STS */
+#define WM8996_MICD_STS_MASK                    0x0001  /* MICD_STS */
+#define WM8996_MICD_STS_SHIFT                        0  /* MICD_STS */
+#define WM8996_MICD_STS_WIDTH                        1  /* MICD_STS */
+
+/*
+ * R64 (0x40) - Charge Pump (1)
+ */
+#define WM8996_CP_ENA                           0x8000  /* CP_ENA */
+#define WM8996_CP_ENA_MASK                      0x8000  /* CP_ENA */
+#define WM8996_CP_ENA_SHIFT                         15  /* CP_ENA */
+#define WM8996_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R65 (0x41) - Charge Pump (2)
+ */
+#define WM8996_CP_DISCH                         0x8000  /* CP_DISCH */
+#define WM8996_CP_DISCH_MASK                    0x8000  /* CP_DISCH */
+#define WM8996_CP_DISCH_SHIFT                       15  /* CP_DISCH */
+#define WM8996_CP_DISCH_WIDTH                        1  /* CP_DISCH */
+
+/*
+ * R80 (0x50) - DC Servo (1)
+ */
+#define WM8996_DCS_ENA_CHAN_3                   0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8996_DCS_ENA_CHAN_3_MASK              0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8996_DCS_ENA_CHAN_3_SHIFT                  3  /* DCS_ENA_CHAN_3 */
+#define WM8996_DCS_ENA_CHAN_3_WIDTH                  1  /* DCS_ENA_CHAN_3 */
+#define WM8996_DCS_ENA_CHAN_2                   0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8996_DCS_ENA_CHAN_2_MASK              0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8996_DCS_ENA_CHAN_2_SHIFT                  2  /* DCS_ENA_CHAN_2 */
+#define WM8996_DCS_ENA_CHAN_2_WIDTH                  1  /* DCS_ENA_CHAN_2 */
+#define WM8996_DCS_ENA_CHAN_1                   0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8996_DCS_ENA_CHAN_1_MASK              0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8996_DCS_ENA_CHAN_1_SHIFT                  1  /* DCS_ENA_CHAN_1 */
+#define WM8996_DCS_ENA_CHAN_1_WIDTH                  1  /* DCS_ENA_CHAN_1 */
+#define WM8996_DCS_ENA_CHAN_0                   0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8996_DCS_ENA_CHAN_0_MASK              0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8996_DCS_ENA_CHAN_0_SHIFT                  0  /* DCS_ENA_CHAN_0 */
+#define WM8996_DCS_ENA_CHAN_0_WIDTH                  1  /* DCS_ENA_CHAN_0 */
+
+/*
+ * R81 (0x51) - DC Servo (2)
+ */
+#define WM8996_DCS_TRIG_SINGLE_3                0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8996_DCS_TRIG_SINGLE_3_MASK           0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8996_DCS_TRIG_SINGLE_3_SHIFT              15  /* DCS_TRIG_SINGLE_3 */
+#define WM8996_DCS_TRIG_SINGLE_3_WIDTH               1  /* DCS_TRIG_SINGLE_3 */
+#define WM8996_DCS_TRIG_SINGLE_2                0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8996_DCS_TRIG_SINGLE_2_MASK           0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8996_DCS_TRIG_SINGLE_2_SHIFT              14  /* DCS_TRIG_SINGLE_2 */
+#define WM8996_DCS_TRIG_SINGLE_2_WIDTH               1  /* DCS_TRIG_SINGLE_2 */
+#define WM8996_DCS_TRIG_SINGLE_1                0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8996_DCS_TRIG_SINGLE_1_MASK           0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8996_DCS_TRIG_SINGLE_1_SHIFT              13  /* DCS_TRIG_SINGLE_1 */
+#define WM8996_DCS_TRIG_SINGLE_1_WIDTH               1  /* DCS_TRIG_SINGLE_1 */
+#define WM8996_DCS_TRIG_SINGLE_0                0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8996_DCS_TRIG_SINGLE_0_MASK           0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8996_DCS_TRIG_SINGLE_0_SHIFT              12  /* DCS_TRIG_SINGLE_0 */
+#define WM8996_DCS_TRIG_SINGLE_0_WIDTH               1  /* DCS_TRIG_SINGLE_0 */
+#define WM8996_DCS_TRIG_SERIES_3                0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8996_DCS_TRIG_SERIES_3_MASK           0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8996_DCS_TRIG_SERIES_3_SHIFT              11  /* DCS_TRIG_SERIES_3 */
+#define WM8996_DCS_TRIG_SERIES_3_WIDTH               1  /* DCS_TRIG_SERIES_3 */
+#define WM8996_DCS_TRIG_SERIES_2                0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8996_DCS_TRIG_SERIES_2_MASK           0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8996_DCS_TRIG_SERIES_2_SHIFT              10  /* DCS_TRIG_SERIES_2 */
+#define WM8996_DCS_TRIG_SERIES_2_WIDTH               1  /* DCS_TRIG_SERIES_2 */
+#define WM8996_DCS_TRIG_SERIES_1                0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8996_DCS_TRIG_SERIES_1_MASK           0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8996_DCS_TRIG_SERIES_1_SHIFT               9  /* DCS_TRIG_SERIES_1 */
+#define WM8996_DCS_TRIG_SERIES_1_WIDTH               1  /* DCS_TRIG_SERIES_1 */
+#define WM8996_DCS_TRIG_SERIES_0                0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8996_DCS_TRIG_SERIES_0_MASK           0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8996_DCS_TRIG_SERIES_0_SHIFT               8  /* DCS_TRIG_SERIES_0 */
+#define WM8996_DCS_TRIG_SERIES_0_WIDTH               1  /* DCS_TRIG_SERIES_0 */
+#define WM8996_DCS_TRIG_STARTUP_3               0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8996_DCS_TRIG_STARTUP_3_MASK          0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8996_DCS_TRIG_STARTUP_3_SHIFT              7  /* DCS_TRIG_STARTUP_3 */
+#define WM8996_DCS_TRIG_STARTUP_3_WIDTH              1  /* DCS_TRIG_STARTUP_3 */
+#define WM8996_DCS_TRIG_STARTUP_2               0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8996_DCS_TRIG_STARTUP_2_MASK          0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8996_DCS_TRIG_STARTUP_2_SHIFT              6  /* DCS_TRIG_STARTUP_2 */
+#define WM8996_DCS_TRIG_STARTUP_2_WIDTH              1  /* DCS_TRIG_STARTUP_2 */
+#define WM8996_DCS_TRIG_STARTUP_1               0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8996_DCS_TRIG_STARTUP_1_MASK          0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8996_DCS_TRIG_STARTUP_1_SHIFT              5  /* DCS_TRIG_STARTUP_1 */
+#define WM8996_DCS_TRIG_STARTUP_1_WIDTH              1  /* DCS_TRIG_STARTUP_1 */
+#define WM8996_DCS_TRIG_STARTUP_0               0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8996_DCS_TRIG_STARTUP_0_MASK          0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8996_DCS_TRIG_STARTUP_0_SHIFT              4  /* DCS_TRIG_STARTUP_0 */
+#define WM8996_DCS_TRIG_STARTUP_0_WIDTH              1  /* DCS_TRIG_STARTUP_0 */
+#define WM8996_DCS_TRIG_DAC_WR_3                0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8996_DCS_TRIG_DAC_WR_3_MASK           0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8996_DCS_TRIG_DAC_WR_3_SHIFT               3  /* DCS_TRIG_DAC_WR_3 */
+#define WM8996_DCS_TRIG_DAC_WR_3_WIDTH               1  /* DCS_TRIG_DAC_WR_3 */
+#define WM8996_DCS_TRIG_DAC_WR_2                0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8996_DCS_TRIG_DAC_WR_2_MASK           0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8996_DCS_TRIG_DAC_WR_2_SHIFT               2  /* DCS_TRIG_DAC_WR_2 */
+#define WM8996_DCS_TRIG_DAC_WR_2_WIDTH               1  /* DCS_TRIG_DAC_WR_2 */
+#define WM8996_DCS_TRIG_DAC_WR_1                0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8996_DCS_TRIG_DAC_WR_1_MASK           0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8996_DCS_TRIG_DAC_WR_1_SHIFT               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8996_DCS_TRIG_DAC_WR_1_WIDTH               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8996_DCS_TRIG_DAC_WR_0                0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8996_DCS_TRIG_DAC_WR_0_MASK           0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8996_DCS_TRIG_DAC_WR_0_SHIFT               0  /* DCS_TRIG_DAC_WR_0 */
+#define WM8996_DCS_TRIG_DAC_WR_0_WIDTH               1  /* DCS_TRIG_DAC_WR_0 */
+
+/*
+ * R82 (0x52) - DC Servo (3)
+ */
+#define WM8996_DCS_TIMER_PERIOD_23_MASK         0x0F00  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8996_DCS_TIMER_PERIOD_23_SHIFT             8  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8996_DCS_TIMER_PERIOD_23_WIDTH             4  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8996_DCS_TIMER_PERIOD_01_MASK         0x000F  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8996_DCS_TIMER_PERIOD_01_SHIFT             0  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8996_DCS_TIMER_PERIOD_01_WIDTH             4  /* DCS_TIMER_PERIOD_01 - [3:0] */
+
+/*
+ * R84 (0x54) - DC Servo (5)
+ */
+#define WM8996_DCS_SERIES_NO_23_MASK            0x7F00  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8996_DCS_SERIES_NO_23_SHIFT                8  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8996_DCS_SERIES_NO_23_WIDTH                7  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8996_DCS_SERIES_NO_01_MASK            0x007F  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8996_DCS_SERIES_NO_01_SHIFT                0  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8996_DCS_SERIES_NO_01_WIDTH                7  /* DCS_SERIES_NO_01 - [6:0] */
+
+/*
+ * R85 (0x55) - DC Servo (6)
+ */
+#define WM8996_DCS_DAC_WR_VAL_3_MASK            0xFF00  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_3_SHIFT                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_3_WIDTH                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_2_MASK            0x00FF  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8996_DCS_DAC_WR_VAL_2_SHIFT                0  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8996_DCS_DAC_WR_VAL_2_WIDTH                8  /* DCS_DAC_WR_VAL_2 - [7:0] */
+
+/*
+ * R86 (0x56) - DC Servo (7)
+ */
+#define WM8996_DCS_DAC_WR_VAL_1_MASK            0xFF00  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_1_SHIFT                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_1_WIDTH                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_0_MASK            0x00FF  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8996_DCS_DAC_WR_VAL_0_SHIFT                0  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8996_DCS_DAC_WR_VAL_0_WIDTH                8  /* DCS_DAC_WR_VAL_0 - [7:0] */
+
+/*
+ * R87 (0x57) - DC Servo Readback 0
+ */
+#define WM8996_DCS_CAL_COMPLETE_MASK            0x0F00  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8996_DCS_CAL_COMPLETE_SHIFT                8  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8996_DCS_CAL_COMPLETE_WIDTH                4  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8996_DCS_DAC_WR_COMPLETE_MASK         0x00F0  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8996_DCS_DAC_WR_COMPLETE_SHIFT             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8996_DCS_DAC_WR_COMPLETE_WIDTH             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8996_DCS_STARTUP_COMPLETE_MASK        0x000F  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8996_DCS_STARTUP_COMPLETE_SHIFT            0  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8996_DCS_STARTUP_COMPLETE_WIDTH            4  /* DCS_STARTUP_COMPLETE - [3:0] */
+
+/*
+ * R96 (0x60) - Analogue HP (1)
+ */
+#define WM8996_HPOUT1L_RMV_SHORT                0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM8996_HPOUT1L_RMV_SHORT_MASK           0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM8996_HPOUT1L_RMV_SHORT_SHIFT               7  /* HPOUT1L_RMV_SHORT */
+#define WM8996_HPOUT1L_RMV_SHORT_WIDTH               1  /* HPOUT1L_RMV_SHORT */
+#define WM8996_HPOUT1L_OUTP                     0x0040  /* HPOUT1L_OUTP */
+#define WM8996_HPOUT1L_OUTP_MASK                0x0040  /* HPOUT1L_OUTP */
+#define WM8996_HPOUT1L_OUTP_SHIFT                    6  /* HPOUT1L_OUTP */
+#define WM8996_HPOUT1L_OUTP_WIDTH                    1  /* HPOUT1L_OUTP */
+#define WM8996_HPOUT1L_DLY                      0x0020  /* HPOUT1L_DLY */
+#define WM8996_HPOUT1L_DLY_MASK                 0x0020  /* HPOUT1L_DLY */
+#define WM8996_HPOUT1L_DLY_SHIFT                     5  /* HPOUT1L_DLY */
+#define WM8996_HPOUT1L_DLY_WIDTH                     1  /* HPOUT1L_DLY */
+#define WM8996_HPOUT1R_RMV_SHORT                0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM8996_HPOUT1R_RMV_SHORT_MASK           0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM8996_HPOUT1R_RMV_SHORT_SHIFT               3  /* HPOUT1R_RMV_SHORT */
+#define WM8996_HPOUT1R_RMV_SHORT_WIDTH               1  /* HPOUT1R_RMV_SHORT */
+#define WM8996_HPOUT1R_OUTP                     0x0004  /* HPOUT1R_OUTP */
+#define WM8996_HPOUT1R_OUTP_MASK                0x0004  /* HPOUT1R_OUTP */
+#define WM8996_HPOUT1R_OUTP_SHIFT                    2  /* HPOUT1R_OUTP */
+#define WM8996_HPOUT1R_OUTP_WIDTH                    1  /* HPOUT1R_OUTP */
+#define WM8996_HPOUT1R_DLY                      0x0002  /* HPOUT1R_DLY */
+#define WM8996_HPOUT1R_DLY_MASK                 0x0002  /* HPOUT1R_DLY */
+#define WM8996_HPOUT1R_DLY_SHIFT                     1  /* HPOUT1R_DLY */
+#define WM8996_HPOUT1R_DLY_WIDTH                     1  /* HPOUT1R_DLY */
+
+/*
+ * R97 (0x61) - Analogue HP (2)
+ */
+#define WM8996_HPOUT2L_RMV_SHORT                0x0080  /* HPOUT2L_RMV_SHORT */
+#define WM8996_HPOUT2L_RMV_SHORT_MASK           0x0080  /* HPOUT2L_RMV_SHORT */
+#define WM8996_HPOUT2L_RMV_SHORT_SHIFT               7  /* HPOUT2L_RMV_SHORT */
+#define WM8996_HPOUT2L_RMV_SHORT_WIDTH               1  /* HPOUT2L_RMV_SHORT */
+#define WM8996_HPOUT2L_OUTP                     0x0040  /* HPOUT2L_OUTP */
+#define WM8996_HPOUT2L_OUTP_MASK                0x0040  /* HPOUT2L_OUTP */
+#define WM8996_HPOUT2L_OUTP_SHIFT                    6  /* HPOUT2L_OUTP */
+#define WM8996_HPOUT2L_OUTP_WIDTH                    1  /* HPOUT2L_OUTP */
+#define WM8996_HPOUT2L_DLY                      0x0020  /* HPOUT2L_DLY */
+#define WM8996_HPOUT2L_DLY_MASK                 0x0020  /* HPOUT2L_DLY */
+#define WM8996_HPOUT2L_DLY_SHIFT                     5  /* HPOUT2L_DLY */
+#define WM8996_HPOUT2L_DLY_WIDTH                     1  /* HPOUT2L_DLY */
+#define WM8996_HPOUT2R_RMV_SHORT                0x0008  /* HPOUT2R_RMV_SHORT */
+#define WM8996_HPOUT2R_RMV_SHORT_MASK           0x0008  /* HPOUT2R_RMV_SHORT */
+#define WM8996_HPOUT2R_RMV_SHORT_SHIFT               3  /* HPOUT2R_RMV_SHORT */
+#define WM8996_HPOUT2R_RMV_SHORT_WIDTH               1  /* HPOUT2R_RMV_SHORT */
+#define WM8996_HPOUT2R_OUTP                     0x0004  /* HPOUT2R_OUTP */
+#define WM8996_HPOUT2R_OUTP_MASK                0x0004  /* HPOUT2R_OUTP */
+#define WM8996_HPOUT2R_OUTP_SHIFT                    2  /* HPOUT2R_OUTP */
+#define WM8996_HPOUT2R_OUTP_WIDTH                    1  /* HPOUT2R_OUTP */
+#define WM8996_HPOUT2R_DLY                      0x0002  /* HPOUT2R_DLY */
+#define WM8996_HPOUT2R_DLY_MASK                 0x0002  /* HPOUT2R_DLY */
+#define WM8996_HPOUT2R_DLY_SHIFT                     1  /* HPOUT2R_DLY */
+#define WM8996_HPOUT2R_DLY_WIDTH                     1  /* HPOUT2R_DLY */
+
+/*
+ * R256 (0x100) - Chip Revision
+ */
+#define WM8996_CHIP_REV_MASK                    0x000F  /* CHIP_REV - [3:0] */
+#define WM8996_CHIP_REV_SHIFT                        0  /* CHIP_REV - [3:0] */
+#define WM8996_CHIP_REV_WIDTH                        4  /* CHIP_REV - [3:0] */
+
+/*
+ * R257 (0x101) - Control Interface (1)
+ */
+#define WM8996_REG_SYNC                         0x8000  /* REG_SYNC */
+#define WM8996_REG_SYNC_MASK                    0x8000  /* REG_SYNC */
+#define WM8996_REG_SYNC_SHIFT                       15  /* REG_SYNC */
+#define WM8996_REG_SYNC_WIDTH                        1  /* REG_SYNC */
+#define WM8996_AUTO_INC                         0x0004  /* AUTO_INC */
+#define WM8996_AUTO_INC_MASK                    0x0004  /* AUTO_INC */
+#define WM8996_AUTO_INC_SHIFT                        2  /* AUTO_INC */
+#define WM8996_AUTO_INC_WIDTH                        1  /* AUTO_INC */
+
+/*
+ * R272 (0x110) - Write Sequencer Ctrl (1)
+ */
+#define WM8996_WSEQ_ENA                         0x8000  /* WSEQ_ENA */
+#define WM8996_WSEQ_ENA_MASK                    0x8000  /* WSEQ_ENA */
+#define WM8996_WSEQ_ENA_SHIFT                       15  /* WSEQ_ENA */
+#define WM8996_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM8996_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM8996_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM8996_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM8996_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8996_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM8996_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM8996_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM8996_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8996_WSEQ_START_INDEX_MASK            0x007F  /* WSEQ_START_INDEX - [6:0] */
+#define WM8996_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [6:0] */
+#define WM8996_WSEQ_START_INDEX_WIDTH                7  /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R273 (0x111) - Write Sequencer Ctrl (2)
+ */
+#define WM8996_WSEQ_BUSY                        0x0100  /* WSEQ_BUSY */
+#define WM8996_WSEQ_BUSY_MASK                   0x0100  /* WSEQ_BUSY */
+#define WM8996_WSEQ_BUSY_SHIFT                       8  /* WSEQ_BUSY */
+#define WM8996_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+#define WM8996_WSEQ_CURRENT_INDEX_MASK          0x007F  /* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8996_WSEQ_CURRENT_INDEX_SHIFT              0  /* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8996_WSEQ_CURRENT_INDEX_WIDTH              7  /* WSEQ_CURRENT_INDEX - [6:0] */
+
+/*
+ * R512 (0x200) - AIF Clocking (1)
+ */
+#define WM8996_SYSCLK_SRC_MASK                  0x0018  /* SYSCLK_SRC - [4:3] */
+#define WM8996_SYSCLK_SRC_SHIFT                      3  /* SYSCLK_SRC - [4:3] */
+#define WM8996_SYSCLK_SRC_WIDTH                      2  /* SYSCLK_SRC - [4:3] */
+#define WM8996_SYSCLK_INV                       0x0004  /* SYSCLK_INV */
+#define WM8996_SYSCLK_INV_MASK                  0x0004  /* SYSCLK_INV */
+#define WM8996_SYSCLK_INV_SHIFT                      2  /* SYSCLK_INV */
+#define WM8996_SYSCLK_INV_WIDTH                      1  /* SYSCLK_INV */
+#define WM8996_SYSCLK_DIV                       0x0002  /* SYSCLK_DIV */
+#define WM8996_SYSCLK_DIV_MASK                  0x0002  /* SYSCLK_DIV */
+#define WM8996_SYSCLK_DIV_SHIFT                      1  /* SYSCLK_DIV */
+#define WM8996_SYSCLK_DIV_WIDTH                      1  /* SYSCLK_DIV */
+#define WM8996_SYSCLK_ENA                       0x0001  /* SYSCLK_ENA */
+#define WM8996_SYSCLK_ENA_MASK                  0x0001  /* SYSCLK_ENA */
+#define WM8996_SYSCLK_ENA_SHIFT                      0  /* SYSCLK_ENA */
+#define WM8996_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+
+/*
+ * R513 (0x201) - AIF Clocking (2)
+ */
+#define WM8996_DSP2_DIV_MASK                    0x0018  /* DSP2_DIV - [4:3] */
+#define WM8996_DSP2_DIV_SHIFT                        3  /* DSP2_DIV - [4:3] */
+#define WM8996_DSP2_DIV_WIDTH                        2  /* DSP2_DIV - [4:3] */
+#define WM8996_DSP1_DIV_MASK                    0x0003  /* DSP1_DIV - [1:0] */
+#define WM8996_DSP1_DIV_SHIFT                        0  /* DSP1_DIV - [1:0] */
+#define WM8996_DSP1_DIV_WIDTH                        2  /* DSP1_DIV - [1:0] */
+
+/*
+ * R520 (0x208) - Clocking (1)
+ */
+#define WM8996_LFCLK_ENA                        0x0020  /* LFCLK_ENA */
+#define WM8996_LFCLK_ENA_MASK                   0x0020  /* LFCLK_ENA */
+#define WM8996_LFCLK_ENA_SHIFT                       5  /* LFCLK_ENA */
+#define WM8996_LFCLK_ENA_WIDTH                       1  /* LFCLK_ENA */
+#define WM8996_TOCLK_ENA                        0x0010  /* TOCLK_ENA */
+#define WM8996_TOCLK_ENA_MASK                   0x0010  /* TOCLK_ENA */
+#define WM8996_TOCLK_ENA_SHIFT                       4  /* TOCLK_ENA */
+#define WM8996_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+#define WM8996_AIFCLK_ENA                       0x0004  /* AIFCLK_ENA */
+#define WM8996_AIFCLK_ENA_MASK                  0x0004  /* AIFCLK_ENA */
+#define WM8996_AIFCLK_ENA_SHIFT                      2  /* AIFCLK_ENA */
+#define WM8996_AIFCLK_ENA_WIDTH                      1  /* AIFCLK_ENA */
+#define WM8996_SYSDSPCLK_ENA                    0x0002  /* SYSDSPCLK_ENA */
+#define WM8996_SYSDSPCLK_ENA_MASK               0x0002  /* SYSDSPCLK_ENA */
+#define WM8996_SYSDSPCLK_ENA_SHIFT                   1  /* SYSDSPCLK_ENA */
+#define WM8996_SYSDSPCLK_ENA_WIDTH                   1  /* SYSDSPCLK_ENA */
+
+/*
+ * R521 (0x209) - Clocking (2)
+ */
+#define WM8996_TOCLK_DIV_MASK                   0x0700  /* TOCLK_DIV - [10:8] */
+#define WM8996_TOCLK_DIV_SHIFT                       8  /* TOCLK_DIV - [10:8] */
+#define WM8996_TOCLK_DIV_WIDTH                       3  /* TOCLK_DIV - [10:8] */
+#define WM8996_DBCLK_DIV_MASK                   0x00F0  /* DBCLK_DIV - [7:4] */
+#define WM8996_DBCLK_DIV_SHIFT                       4  /* DBCLK_DIV - [7:4] */
+#define WM8996_DBCLK_DIV_WIDTH                       4  /* DBCLK_DIV - [7:4] */
+#define WM8996_OPCLK_DIV_MASK                   0x0007  /* OPCLK_DIV - [2:0] */
+#define WM8996_OPCLK_DIV_SHIFT                       0  /* OPCLK_DIV - [2:0] */
+#define WM8996_OPCLK_DIV_WIDTH                       3  /* OPCLK_DIV - [2:0] */
+
+/*
+ * R528 (0x210) - AIF Rate
+ */
+#define WM8996_SYSCLK_RATE                      0x0001  /* SYSCLK_RATE */
+#define WM8996_SYSCLK_RATE_MASK                 0x0001  /* SYSCLK_RATE */
+#define WM8996_SYSCLK_RATE_SHIFT                     0  /* SYSCLK_RATE */
+#define WM8996_SYSCLK_RATE_WIDTH                     1  /* SYSCLK_RATE */
+
+/*
+ * R544 (0x220) - FLL Control (1)
+ */
+#define WM8996_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM8996_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM8996_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM8996_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8996_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM8996_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM8996_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM8996_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R545 (0x221) - FLL Control (2)
+ */
+#define WM8996_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
+#define WM8996_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
+#define WM8996_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
+#define WM8996_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM8996_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM8996_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R546 (0x222) - FLL Control (3)
+ */
+#define WM8996_FLL_THETA_MASK                   0xFFFF  /* FLL_THETA - [15:0] */
+#define WM8996_FLL_THETA_SHIFT                       0  /* FLL_THETA - [15:0] */
+#define WM8996_FLL_THETA_WIDTH                      16  /* FLL_THETA - [15:0] */
+
+/*
+ * R547 (0x223) - FLL Control (4)
+ */
+#define WM8996_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM8996_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM8996_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM8996_FLL_LOOP_GAIN_MASK               0x000F  /* FLL_LOOP_GAIN - [3:0] */
+#define WM8996_FLL_LOOP_GAIN_SHIFT                   0  /* FLL_LOOP_GAIN - [3:0] */
+#define WM8996_FLL_LOOP_GAIN_WIDTH                   4  /* FLL_LOOP_GAIN - [3:0] */
+
+/*
+ * R548 (0x224) - FLL Control (5)
+ */
+#define WM8996_FLL_FRC_NCO_VAL_MASK             0x1F80  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8996_FLL_FRC_NCO_VAL_SHIFT                 7  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8996_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8996_FLL_FRC_NCO                      0x0040  /* FLL_FRC_NCO */
+#define WM8996_FLL_FRC_NCO_MASK                 0x0040  /* FLL_FRC_NCO */
+#define WM8996_FLL_FRC_NCO_SHIFT                     6  /* FLL_FRC_NCO */
+#define WM8996_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
+#define WM8996_FLL_REFCLK_DIV_MASK              0x0018  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8996_FLL_REFCLK_DIV_SHIFT                  3  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8996_FLL_REFCLK_DIV_WIDTH                  2  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8996_FLL_REF_FREQ                     0x0004  /* FLL_REF_FREQ */
+#define WM8996_FLL_REF_FREQ_MASK                0x0004  /* FLL_REF_FREQ */
+#define WM8996_FLL_REF_FREQ_SHIFT                    2  /* FLL_REF_FREQ */
+#define WM8996_FLL_REF_FREQ_WIDTH                    1  /* FLL_REF_FREQ */
+#define WM8996_FLL_REFCLK_SRC_MASK              0x0003  /* FLL_REFCLK_SRC - [1:0] */
+#define WM8996_FLL_REFCLK_SRC_SHIFT                  0  /* FLL_REFCLK_SRC - [1:0] */
+#define WM8996_FLL_REFCLK_SRC_WIDTH                  2  /* FLL_REFCLK_SRC - [1:0] */
+
+/*
+ * R549 (0x225) - FLL Control (6)
+ */
+#define WM8996_FLL_REFCLK_SRC_STS_MASK          0x000C  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8996_FLL_REFCLK_SRC_STS_SHIFT              2  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8996_FLL_REFCLK_SRC_STS_WIDTH              2  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8996_FLL_SWITCH_CLK                   0x0001  /* FLL_SWITCH_CLK */
+#define WM8996_FLL_SWITCH_CLK_MASK              0x0001  /* FLL_SWITCH_CLK */
+#define WM8996_FLL_SWITCH_CLK_SHIFT                  0  /* FLL_SWITCH_CLK */
+#define WM8996_FLL_SWITCH_CLK_WIDTH                  1  /* FLL_SWITCH_CLK */
+
+/*
+ * R550 (0x226) - FLL EFS 1
+ */
+#define WM8996_FLL_LAMBDA_MASK                  0xFFFF  /* FLL_LAMBDA - [15:0] */
+#define WM8996_FLL_LAMBDA_SHIFT                      0  /* FLL_LAMBDA - [15:0] */
+#define WM8996_FLL_LAMBDA_WIDTH                     16  /* FLL_LAMBDA - [15:0] */
+
+/*
+ * R551 (0x227) - FLL EFS 2
+ */
+#define WM8996_FLL_LFSR_SEL_MASK                0x0006  /* FLL_LFSR_SEL - [2:1] */
+#define WM8996_FLL_LFSR_SEL_SHIFT                    1  /* FLL_LFSR_SEL - [2:1] */
+#define WM8996_FLL_LFSR_SEL_WIDTH                    2  /* FLL_LFSR_SEL - [2:1] */
+#define WM8996_FLL_EFS_ENA                      0x0001  /* FLL_EFS_ENA */
+#define WM8996_FLL_EFS_ENA_MASK                 0x0001  /* FLL_EFS_ENA */
+#define WM8996_FLL_EFS_ENA_SHIFT                     0  /* FLL_EFS_ENA */
+#define WM8996_FLL_EFS_ENA_WIDTH                     1  /* FLL_EFS_ENA */
+
+/*
+ * R768 (0x300) - AIF1 Control
+ */
+#define WM8996_AIF1_TRI                         0x0004  /* AIF1_TRI */
+#define WM8996_AIF1_TRI_MASK                    0x0004  /* AIF1_TRI */
+#define WM8996_AIF1_TRI_SHIFT                        2  /* AIF1_TRI */
+#define WM8996_AIF1_TRI_WIDTH                        1  /* AIF1_TRI */
+#define WM8996_AIF1_FMT_MASK                    0x0003  /* AIF1_FMT - [1:0] */
+#define WM8996_AIF1_FMT_SHIFT                        0  /* AIF1_FMT - [1:0] */
+#define WM8996_AIF1_FMT_WIDTH                        2  /* AIF1_FMT - [1:0] */
+
+/*
+ * R769 (0x301) - AIF1 BCLK
+ */
+#define WM8996_AIF1_BCLK_INV                    0x0400  /* AIF1_BCLK_INV */
+#define WM8996_AIF1_BCLK_INV_MASK               0x0400  /* AIF1_BCLK_INV */
+#define WM8996_AIF1_BCLK_INV_SHIFT                  10  /* AIF1_BCLK_INV */
+#define WM8996_AIF1_BCLK_INV_WIDTH                   1  /* AIF1_BCLK_INV */
+#define WM8996_AIF1_BCLK_FRC                    0x0200  /* AIF1_BCLK_FRC */
+#define WM8996_AIF1_BCLK_FRC_MASK               0x0200  /* AIF1_BCLK_FRC */
+#define WM8996_AIF1_BCLK_FRC_SHIFT                   9  /* AIF1_BCLK_FRC */
+#define WM8996_AIF1_BCLK_FRC_WIDTH                   1  /* AIF1_BCLK_FRC */
+#define WM8996_AIF1_BCLK_MSTR                   0x0100  /* AIF1_BCLK_MSTR */
+#define WM8996_AIF1_BCLK_MSTR_MASK              0x0100  /* AIF1_BCLK_MSTR */
+#define WM8996_AIF1_BCLK_MSTR_SHIFT                  8  /* AIF1_BCLK_MSTR */
+#define WM8996_AIF1_BCLK_MSTR_WIDTH                  1  /* AIF1_BCLK_MSTR */
+#define WM8996_AIF1_BCLK_DIV_MASK               0x000F  /* AIF1_BCLK_DIV - [3:0] */
+#define WM8996_AIF1_BCLK_DIV_SHIFT                   0  /* AIF1_BCLK_DIV - [3:0] */
+#define WM8996_AIF1_BCLK_DIV_WIDTH                   4  /* AIF1_BCLK_DIV - [3:0] */
+
+/*
+ * R770 (0x302) - AIF1 TX LRCLK(1)
+ */
+#define WM8996_AIF1TX_RATE_MASK                 0x07FF  /* AIF1TX_RATE - [10:0] */
+#define WM8996_AIF1TX_RATE_SHIFT                     0  /* AIF1TX_RATE - [10:0] */
+#define WM8996_AIF1TX_RATE_WIDTH                    11  /* AIF1TX_RATE - [10:0] */
+
+/*
+ * R771 (0x303) - AIF1 TX LRCLK(2)
+ */
+#define WM8996_AIF1TX_LRCLK_MODE                0x0008  /* AIF1TX_LRCLK_MODE */
+#define WM8996_AIF1TX_LRCLK_MODE_MASK           0x0008  /* AIF1TX_LRCLK_MODE */
+#define WM8996_AIF1TX_LRCLK_MODE_SHIFT               3  /* AIF1TX_LRCLK_MODE */
+#define WM8996_AIF1TX_LRCLK_MODE_WIDTH               1  /* AIF1TX_LRCLK_MODE */
+#define WM8996_AIF1TX_LRCLK_INV                 0x0004  /* AIF1TX_LRCLK_INV */
+#define WM8996_AIF1TX_LRCLK_INV_MASK            0x0004  /* AIF1TX_LRCLK_INV */
+#define WM8996_AIF1TX_LRCLK_INV_SHIFT                2  /* AIF1TX_LRCLK_INV */
+#define WM8996_AIF1TX_LRCLK_INV_WIDTH                1  /* AIF1TX_LRCLK_INV */
+#define WM8996_AIF1TX_LRCLK_FRC                 0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM8996_AIF1TX_LRCLK_FRC_MASK            0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM8996_AIF1TX_LRCLK_FRC_SHIFT                1  /* AIF1TX_LRCLK_FRC */
+#define WM8996_AIF1TX_LRCLK_FRC_WIDTH                1  /* AIF1TX_LRCLK_FRC */
+#define WM8996_AIF1TX_LRCLK_MSTR                0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM8996_AIF1TX_LRCLK_MSTR_MASK           0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM8996_AIF1TX_LRCLK_MSTR_SHIFT               0  /* AIF1TX_LRCLK_MSTR */
+#define WM8996_AIF1TX_LRCLK_MSTR_WIDTH               1  /* AIF1TX_LRCLK_MSTR */
+
+/*
+ * R772 (0x304) - AIF1 RX LRCLK(1)
+ */
+#define WM8996_AIF1RX_RATE_MASK                 0x07FF  /* AIF1RX_RATE - [10:0] */
+#define WM8996_AIF1RX_RATE_SHIFT                     0  /* AIF1RX_RATE - [10:0] */
+#define WM8996_AIF1RX_RATE_WIDTH                    11  /* AIF1RX_RATE - [10:0] */
+
+/*
+ * R773 (0x305) - AIF1 RX LRCLK(2)
+ */
+#define WM8996_AIF1RX_LRCLK_INV                 0x0004  /* AIF1RX_LRCLK_INV */
+#define WM8996_AIF1RX_LRCLK_INV_MASK            0x0004  /* AIF1RX_LRCLK_INV */
+#define WM8996_AIF1RX_LRCLK_INV_SHIFT                2  /* AIF1RX_LRCLK_INV */
+#define WM8996_AIF1RX_LRCLK_INV_WIDTH                1  /* AIF1RX_LRCLK_INV */
+#define WM8996_AIF1RX_LRCLK_FRC                 0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM8996_AIF1RX_LRCLK_FRC_MASK            0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM8996_AIF1RX_LRCLK_FRC_SHIFT                1  /* AIF1RX_LRCLK_FRC */
+#define WM8996_AIF1RX_LRCLK_FRC_WIDTH                1  /* AIF1RX_LRCLK_FRC */
+#define WM8996_AIF1RX_LRCLK_MSTR                0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM8996_AIF1RX_LRCLK_MSTR_MASK           0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM8996_AIF1RX_LRCLK_MSTR_SHIFT               0  /* AIF1RX_LRCLK_MSTR */
+#define WM8996_AIF1RX_LRCLK_MSTR_WIDTH               1  /* AIF1RX_LRCLK_MSTR */
+
+/*
+ * R774 (0x306) - AIF1TX Data Configuration (1)
+ */
+#define WM8996_AIF1TX_WL_MASK                   0xFF00  /* AIF1TX_WL - [15:8] */
+#define WM8996_AIF1TX_WL_SHIFT                       8  /* AIF1TX_WL - [15:8] */
+#define WM8996_AIF1TX_WL_WIDTH                       8  /* AIF1TX_WL - [15:8] */
+#define WM8996_AIF1TX_SLOT_LEN_MASK             0x00FF  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM8996_AIF1TX_SLOT_LEN_SHIFT                 0  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM8996_AIF1TX_SLOT_LEN_WIDTH                 8  /* AIF1TX_SLOT_LEN - [7:0] */
+
+/*
+ * R775 (0x307) - AIF1TX Data Configuration (2)
+ */
+#define WM8996_AIF1TX_DAT_TRI                   0x0001  /* AIF1TX_DAT_TRI */
+#define WM8996_AIF1TX_DAT_TRI_MASK              0x0001  /* AIF1TX_DAT_TRI */
+#define WM8996_AIF1TX_DAT_TRI_SHIFT                  0  /* AIF1TX_DAT_TRI */
+#define WM8996_AIF1TX_DAT_TRI_WIDTH                  1  /* AIF1TX_DAT_TRI */
+
+/*
+ * R776 (0x308) - AIF1RX Data Configuration
+ */
+#define WM8996_AIF1RX_WL_MASK                   0xFF00  /* AIF1RX_WL - [15:8] */
+#define WM8996_AIF1RX_WL_SHIFT                       8  /* AIF1RX_WL - [15:8] */
+#define WM8996_AIF1RX_WL_WIDTH                       8  /* AIF1RX_WL - [15:8] */
+#define WM8996_AIF1RX_SLOT_LEN_MASK             0x00FF  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM8996_AIF1RX_SLOT_LEN_SHIFT                 0  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM8996_AIF1RX_SLOT_LEN_WIDTH                 8  /* AIF1RX_SLOT_LEN - [7:0] */
+
+/*
+ * R777 (0x309) - AIF1TX Channel 0 Configuration
+ */
+#define WM8996_AIF1TX_CHAN0_DAT_INV             0x8000  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8996_AIF1TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8996_AIF1TX_CHAN0_DAT_INV_SHIFT           15  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8996_AIF1TX_CHAN0_DAT_INV_WIDTH            1  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8996_AIF1TX_CHAN0_SPACING_MASK        0x7E00  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN0_SPACING_SHIFT            9  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN0_SPACING_WIDTH            6  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN0_SLOTS_SHIFT              6  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN0_SLOTS_WIDTH              3  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN0_START_SLOT_SHIFT         0  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN0_START_SLOT_WIDTH         6  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R778 (0x30A) - AIF1TX Channel 1 Configuration
+ */
+#define WM8996_AIF1TX_CHAN1_DAT_INV             0x8000  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8996_AIF1TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8996_AIF1TX_CHAN1_DAT_INV_SHIFT           15  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8996_AIF1TX_CHAN1_DAT_INV_WIDTH            1  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8996_AIF1TX_CHAN1_SPACING_MASK        0x7E00  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN1_SPACING_SHIFT            9  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN1_SPACING_WIDTH            6  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN1_SLOTS_SHIFT              6  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN1_SLOTS_WIDTH              3  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN1_START_SLOT_SHIFT         0  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN1_START_SLOT_WIDTH         6  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R779 (0x30B) - AIF1TX Channel 2 Configuration
+ */
+#define WM8996_AIF1TX_CHAN2_DAT_INV             0x8000  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8996_AIF1TX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8996_AIF1TX_CHAN2_DAT_INV_SHIFT           15  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8996_AIF1TX_CHAN2_DAT_INV_WIDTH            1  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8996_AIF1TX_CHAN2_SPACING_MASK        0x7E00  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN2_SPACING_SHIFT            9  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN2_SPACING_WIDTH            6  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN2_SLOTS_SHIFT              6  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN2_SLOTS_WIDTH              3  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN2_START_SLOT_SHIFT         0  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN2_START_SLOT_WIDTH         6  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+
+/*
+ * R780 (0x30C) - AIF1TX Channel 3 Configuration
+ */
+#define WM8996_AIF1TX_CHAN3_DAT_INV             0x8000  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8996_AIF1TX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8996_AIF1TX_CHAN3_DAT_INV_SHIFT           15  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8996_AIF1TX_CHAN3_DAT_INV_WIDTH            1  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8996_AIF1TX_CHAN3_SPACING_MASK        0x7E00  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN3_SPACING_SHIFT            9  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN3_SPACING_WIDTH            6  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN3_SLOTS_SHIFT              6  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN3_SLOTS_WIDTH              3  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN3_START_SLOT_SHIFT         0  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN3_START_SLOT_WIDTH         6  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+
+/*
+ * R781 (0x30D) - AIF1TX Channel 4 Configuration
+ */
+#define WM8996_AIF1TX_CHAN4_DAT_INV             0x8000  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8996_AIF1TX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8996_AIF1TX_CHAN4_DAT_INV_SHIFT           15  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8996_AIF1TX_CHAN4_DAT_INV_WIDTH            1  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8996_AIF1TX_CHAN4_SPACING_MASK        0x7E00  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN4_SPACING_SHIFT            9  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN4_SPACING_WIDTH            6  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN4_SLOTS_SHIFT              6  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN4_SLOTS_WIDTH              3  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN4_START_SLOT_SHIFT         0  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN4_START_SLOT_WIDTH         6  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+
+/*
+ * R782 (0x30E) - AIF1TX Channel 5 Configuration
+ */
+#define WM8996_AIF1TX_CHAN5_DAT_INV             0x8000  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8996_AIF1TX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8996_AIF1TX_CHAN5_DAT_INV_SHIFT           15  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8996_AIF1TX_CHAN5_DAT_INV_WIDTH            1  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8996_AIF1TX_CHAN5_SPACING_MASK        0x7E00  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN5_SPACING_SHIFT            9  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN5_SPACING_WIDTH            6  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN5_SLOTS_SHIFT              6  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN5_SLOTS_WIDTH              3  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN5_START_SLOT_SHIFT         0  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN5_START_SLOT_WIDTH         6  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+
+/*
+ * R783 (0x30F) - AIF1RX Channel 0 Configuration
+ */
+#define WM8996_AIF1RX_CHAN0_DAT_INV             0x8000  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8996_AIF1RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8996_AIF1RX_CHAN0_DAT_INV_SHIFT           15  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8996_AIF1RX_CHAN0_DAT_INV_WIDTH            1  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8996_AIF1RX_CHAN0_SPACING_MASK        0x7E00  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN0_SPACING_SHIFT            9  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN0_SPACING_WIDTH            6  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN0_SLOTS_SHIFT              6  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN0_SLOTS_WIDTH              3  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN0_START_SLOT_SHIFT         0  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN0_START_SLOT_WIDTH         6  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R784 (0x310) - AIF1RX Channel 1 Configuration
+ */
+#define WM8996_AIF1RX_CHAN1_DAT_INV             0x8000  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8996_AIF1RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8996_AIF1RX_CHAN1_DAT_INV_SHIFT           15  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8996_AIF1RX_CHAN1_DAT_INV_WIDTH            1  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8996_AIF1RX_CHAN1_SPACING_MASK        0x7E00  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN1_SPACING_SHIFT            9  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN1_SPACING_WIDTH            6  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN1_SLOTS_SHIFT              6  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN1_SLOTS_WIDTH              3  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN1_START_SLOT_SHIFT         0  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN1_START_SLOT_WIDTH         6  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R785 (0x311) - AIF1RX Channel 2 Configuration
+ */
+#define WM8996_AIF1RX_CHAN2_DAT_INV             0x8000  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8996_AIF1RX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8996_AIF1RX_CHAN2_DAT_INV_SHIFT           15  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8996_AIF1RX_CHAN2_DAT_INV_WIDTH            1  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8996_AIF1RX_CHAN2_SPACING_MASK        0x7E00  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN2_SPACING_SHIFT            9  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN2_SPACING_WIDTH            6  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN2_SLOTS_SHIFT              6  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN2_SLOTS_WIDTH              3  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN2_START_SLOT_SHIFT         0  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN2_START_SLOT_WIDTH         6  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+
+/*
+ * R786 (0x312) - AIF1RX Channel 3 Configuration
+ */
+#define WM8996_AIF1RX_CHAN3_DAT_INV             0x8000  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8996_AIF1RX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8996_AIF1RX_CHAN3_DAT_INV_SHIFT           15  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8996_AIF1RX_CHAN3_DAT_INV_WIDTH            1  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8996_AIF1RX_CHAN3_SPACING_MASK        0x7E00  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN3_SPACING_SHIFT            9  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN3_SPACING_WIDTH            6  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN3_SLOTS_SHIFT              6  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN3_SLOTS_WIDTH              3  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN3_START_SLOT_SHIFT         0  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN3_START_SLOT_WIDTH         6  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+
+/*
+ * R787 (0x313) - AIF1RX Channel 4 Configuration
+ */
+#define WM8996_AIF1RX_CHAN4_DAT_INV             0x8000  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8996_AIF1RX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8996_AIF1RX_CHAN4_DAT_INV_SHIFT           15  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8996_AIF1RX_CHAN4_DAT_INV_WIDTH            1  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8996_AIF1RX_CHAN4_SPACING_MASK        0x7E00  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN4_SPACING_SHIFT            9  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN4_SPACING_WIDTH            6  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN4_SLOTS_SHIFT              6  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN4_SLOTS_WIDTH              3  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN4_START_SLOT_SHIFT         0  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN4_START_SLOT_WIDTH         6  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+
+/*
+ * R788 (0x314) - AIF1RX Channel 5 Configuration
+ */
+#define WM8996_AIF1RX_CHAN5_DAT_INV             0x8000  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8996_AIF1RX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8996_AIF1RX_CHAN5_DAT_INV_SHIFT           15  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8996_AIF1RX_CHAN5_DAT_INV_WIDTH            1  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8996_AIF1RX_CHAN5_SPACING_MASK        0x7E00  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN5_SPACING_SHIFT            9  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN5_SPACING_WIDTH            6  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN5_SLOTS_SHIFT              6  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN5_SLOTS_WIDTH              3  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN5_START_SLOT_SHIFT         0  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN5_START_SLOT_WIDTH         6  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+
+/*
+ * R789 (0x315) - AIF1RX Mono Configuration
+ */
+#define WM8996_AIF1RX_CHAN4_MONO_MODE           0x0004  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8996_AIF1RX_CHAN4_MONO_MODE_MASK      0x0004  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8996_AIF1RX_CHAN4_MONO_MODE_SHIFT          2  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8996_AIF1RX_CHAN4_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8996_AIF1RX_CHAN2_MONO_MODE           0x0002  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8996_AIF1RX_CHAN2_MONO_MODE_MASK      0x0002  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8996_AIF1RX_CHAN2_MONO_MODE_SHIFT          1  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8996_AIF1RX_CHAN2_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8996_AIF1RX_CHAN0_MONO_MODE           0x0001  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8996_AIF1RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8996_AIF1RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8996_AIF1RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN0_MONO_MODE */
+
+/*
+ * R794 (0x31A) - AIF1TX Test
+ */
+#define WM8996_AIF1TX45_DITHER_ENA              0x0004  /* AIF1TX45_DITHER_ENA */
+#define WM8996_AIF1TX45_DITHER_ENA_MASK         0x0004  /* AIF1TX45_DITHER_ENA */
+#define WM8996_AIF1TX45_DITHER_ENA_SHIFT             2  /* AIF1TX45_DITHER_ENA */
+#define WM8996_AIF1TX45_DITHER_ENA_WIDTH             1  /* AIF1TX45_DITHER_ENA */
+#define WM8996_AIF1TX23_DITHER_ENA              0x0002  /* AIF1TX23_DITHER_ENA */
+#define WM8996_AIF1TX23_DITHER_ENA_MASK         0x0002  /* AIF1TX23_DITHER_ENA */
+#define WM8996_AIF1TX23_DITHER_ENA_SHIFT             1  /* AIF1TX23_DITHER_ENA */
+#define WM8996_AIF1TX23_DITHER_ENA_WIDTH             1  /* AIF1TX23_DITHER_ENA */
+#define WM8996_AIF1TX01_DITHER_ENA              0x0001  /* AIF1TX01_DITHER_ENA */
+#define WM8996_AIF1TX01_DITHER_ENA_MASK         0x0001  /* AIF1TX01_DITHER_ENA */
+#define WM8996_AIF1TX01_DITHER_ENA_SHIFT             0  /* AIF1TX01_DITHER_ENA */
+#define WM8996_AIF1TX01_DITHER_ENA_WIDTH             1  /* AIF1TX01_DITHER_ENA */
+
+/*
+ * R800 (0x320) - AIF2 Control
+ */
+#define WM8996_AIF2_TRI                         0x0004  /* AIF2_TRI */
+#define WM8996_AIF2_TRI_MASK                    0x0004  /* AIF2_TRI */
+#define WM8996_AIF2_TRI_SHIFT                        2  /* AIF2_TRI */
+#define WM8996_AIF2_TRI_WIDTH                        1  /* AIF2_TRI */
+#define WM8996_AIF2_FMT_MASK                    0x0003  /* AIF2_FMT - [1:0] */
+#define WM8996_AIF2_FMT_SHIFT                        0  /* AIF2_FMT - [1:0] */
+#define WM8996_AIF2_FMT_WIDTH                        2  /* AIF2_FMT - [1:0] */
+
+/*
+ * R801 (0x321) - AIF2 BCLK
+ */
+#define WM8996_AIF2_BCLK_INV                    0x0400  /* AIF2_BCLK_INV */
+#define WM8996_AIF2_BCLK_INV_MASK               0x0400  /* AIF2_BCLK_INV */
+#define WM8996_AIF2_BCLK_INV_SHIFT                  10  /* AIF2_BCLK_INV */
+#define WM8996_AIF2_BCLK_INV_WIDTH                   1  /* AIF2_BCLK_INV */
+#define WM8996_AIF2_BCLK_FRC                    0x0200  /* AIF2_BCLK_FRC */
+#define WM8996_AIF2_BCLK_FRC_MASK               0x0200  /* AIF2_BCLK_FRC */
+#define WM8996_AIF2_BCLK_FRC_SHIFT                   9  /* AIF2_BCLK_FRC */
+#define WM8996_AIF2_BCLK_FRC_WIDTH                   1  /* AIF2_BCLK_FRC */
+#define WM8996_AIF2_BCLK_MSTR                   0x0100  /* AIF2_BCLK_MSTR */
+#define WM8996_AIF2_BCLK_MSTR_MASK              0x0100  /* AIF2_BCLK_MSTR */
+#define WM8996_AIF2_BCLK_MSTR_SHIFT                  8  /* AIF2_BCLK_MSTR */
+#define WM8996_AIF2_BCLK_MSTR_WIDTH                  1  /* AIF2_BCLK_MSTR */
+#define WM8996_AIF2_BCLK_DIV_MASK               0x000F  /* AIF2_BCLK_DIV - [3:0] */
+#define WM8996_AIF2_BCLK_DIV_SHIFT                   0  /* AIF2_BCLK_DIV - [3:0] */
+#define WM8996_AIF2_BCLK_DIV_WIDTH                   4  /* AIF2_BCLK_DIV - [3:0] */
+
+/*
+ * R802 (0x322) - AIF2 TX LRCLK(1)
+ */
+#define WM8996_AIF2TX_RATE_MASK                 0x07FF  /* AIF2TX_RATE - [10:0] */
+#define WM8996_AIF2TX_RATE_SHIFT                     0  /* AIF2TX_RATE - [10:0] */
+#define WM8996_AIF2TX_RATE_WIDTH                    11  /* AIF2TX_RATE - [10:0] */
+
+/*
+ * R803 (0x323) - AIF2 TX LRCLK(2)
+ */
+#define WM8996_AIF2TX_LRCLK_MODE                0x0008  /* AIF2TX_LRCLK_MODE */
+#define WM8996_AIF2TX_LRCLK_MODE_MASK           0x0008  /* AIF2TX_LRCLK_MODE */
+#define WM8996_AIF2TX_LRCLK_MODE_SHIFT               3  /* AIF2TX_LRCLK_MODE */
+#define WM8996_AIF2TX_LRCLK_MODE_WIDTH               1  /* AIF2TX_LRCLK_MODE */
+#define WM8996_AIF2TX_LRCLK_INV                 0x0004  /* AIF2TX_LRCLK_INV */
+#define WM8996_AIF2TX_LRCLK_INV_MASK            0x0004  /* AIF2TX_LRCLK_INV */
+#define WM8996_AIF2TX_LRCLK_INV_SHIFT                2  /* AIF2TX_LRCLK_INV */
+#define WM8996_AIF2TX_LRCLK_INV_WIDTH                1  /* AIF2TX_LRCLK_INV */
+#define WM8996_AIF2TX_LRCLK_FRC                 0x0002  /* AIF2TX_LRCLK_FRC */
+#define WM8996_AIF2TX_LRCLK_FRC_MASK            0x0002  /* AIF2TX_LRCLK_FRC */
+#define WM8996_AIF2TX_LRCLK_FRC_SHIFT                1  /* AIF2TX_LRCLK_FRC */
+#define WM8996_AIF2TX_LRCLK_FRC_WIDTH                1  /* AIF2TX_LRCLK_FRC */
+#define WM8996_AIF2TX_LRCLK_MSTR                0x0001  /* AIF2TX_LRCLK_MSTR */
+#define WM8996_AIF2TX_LRCLK_MSTR_MASK           0x0001  /* AIF2TX_LRCLK_MSTR */
+#define WM8996_AIF2TX_LRCLK_MSTR_SHIFT               0  /* AIF2TX_LRCLK_MSTR */
+#define WM8996_AIF2TX_LRCLK_MSTR_WIDTH               1  /* AIF2TX_LRCLK_MSTR */
+
+/*
+ * R804 (0x324) - AIF2 RX LRCLK(1)
+ */
+#define WM8996_AIF2RX_RATE_MASK                 0x07FF  /* AIF2RX_RATE - [10:0] */
+#define WM8996_AIF2RX_RATE_SHIFT                     0  /* AIF2RX_RATE - [10:0] */
+#define WM8996_AIF2RX_RATE_WIDTH                    11  /* AIF2RX_RATE - [10:0] */
+
+/*
+ * R805 (0x325) - AIF2 RX LRCLK(2)
+ */
+#define WM8996_AIF2RX_LRCLK_INV                 0x0004  /* AIF2RX_LRCLK_INV */
+#define WM8996_AIF2RX_LRCLK_INV_MASK            0x0004  /* AIF2RX_LRCLK_INV */
+#define WM8996_AIF2RX_LRCLK_INV_SHIFT                2  /* AIF2RX_LRCLK_INV */
+#define WM8996_AIF2RX_LRCLK_INV_WIDTH                1  /* AIF2RX_LRCLK_INV */
+#define WM8996_AIF2RX_LRCLK_FRC                 0x0002  /* AIF2RX_LRCLK_FRC */
+#define WM8996_AIF2RX_LRCLK_FRC_MASK            0x0002  /* AIF2RX_LRCLK_FRC */
+#define WM8996_AIF2RX_LRCLK_FRC_SHIFT                1  /* AIF2RX_LRCLK_FRC */
+#define WM8996_AIF2RX_LRCLK_FRC_WIDTH                1  /* AIF2RX_LRCLK_FRC */
+#define WM8996_AIF2RX_LRCLK_MSTR                0x0001  /* AIF2RX_LRCLK_MSTR */
+#define WM8996_AIF2RX_LRCLK_MSTR_MASK           0x0001  /* AIF2RX_LRCLK_MSTR */
+#define WM8996_AIF2RX_LRCLK_MSTR_SHIFT               0  /* AIF2RX_LRCLK_MSTR */
+#define WM8996_AIF2RX_LRCLK_MSTR_WIDTH               1  /* AIF2RX_LRCLK_MSTR */
+
+/*
+ * R806 (0x326) - AIF2TX Data Configuration (1)
+ */
+#define WM8996_AIF2TX_WL_MASK                   0xFF00  /* AIF2TX_WL - [15:8] */
+#define WM8996_AIF2TX_WL_SHIFT                       8  /* AIF2TX_WL - [15:8] */
+#define WM8996_AIF2TX_WL_WIDTH                       8  /* AIF2TX_WL - [15:8] */
+#define WM8996_AIF2TX_SLOT_LEN_MASK             0x00FF  /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM8996_AIF2TX_SLOT_LEN_SHIFT                 0  /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM8996_AIF2TX_SLOT_LEN_WIDTH                 8  /* AIF2TX_SLOT_LEN - [7:0] */
+
+/*
+ * R807 (0x327) - AIF2TX Data Configuration (2)
+ */
+#define WM8996_AIF2TX_DAT_TRI                   0x0001  /* AIF2TX_DAT_TRI */
+#define WM8996_AIF2TX_DAT_TRI_MASK              0x0001  /* AIF2TX_DAT_TRI */
+#define WM8996_AIF2TX_DAT_TRI_SHIFT                  0  /* AIF2TX_DAT_TRI */
+#define WM8996_AIF2TX_DAT_TRI_WIDTH                  1  /* AIF2TX_DAT_TRI */
+
+/*
+ * R808 (0x328) - AIF2RX Data Configuration
+ */
+#define WM8996_AIF2RX_WL_MASK                   0xFF00  /* AIF2RX_WL - [15:8] */
+#define WM8996_AIF2RX_WL_SHIFT                       8  /* AIF2RX_WL - [15:8] */
+#define WM8996_AIF2RX_WL_WIDTH                       8  /* AIF2RX_WL - [15:8] */
+#define WM8996_AIF2RX_SLOT_LEN_MASK             0x00FF  /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM8996_AIF2RX_SLOT_LEN_SHIFT                 0  /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM8996_AIF2RX_SLOT_LEN_WIDTH                 8  /* AIF2RX_SLOT_LEN - [7:0] */
+
+/*
+ * R809 (0x329) - AIF2TX Channel 0 Configuration
+ */
+#define WM8996_AIF2TX_CHAN0_DAT_INV             0x8000  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8996_AIF2TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8996_AIF2TX_CHAN0_DAT_INV_SHIFT           15  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8996_AIF2TX_CHAN0_DAT_INV_WIDTH            1  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8996_AIF2TX_CHAN0_SPACING_MASK        0x7E00  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN0_SPACING_SHIFT            9  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN0_SPACING_WIDTH            6  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN0_SLOTS_SHIFT              6  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN0_SLOTS_WIDTH              3  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF2TX_CHAN0_START_SLOT_SHIFT         0  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF2TX_CHAN0_START_SLOT_WIDTH         6  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R810 (0x32A) - AIF2TX Channel 1 Configuration
+ */
+#define WM8996_AIF2TX_CHAN1_DAT_INV             0x8000  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8996_AIF2TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8996_AIF2TX_CHAN1_DAT_INV_SHIFT           15  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8996_AIF2TX_CHAN1_DAT_INV_WIDTH            1  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8996_AIF2TX_CHAN1_SPACING_MASK        0x7E00  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN1_SPACING_SHIFT            9  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN1_SPACING_WIDTH            6  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN1_SLOTS_SHIFT              6  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN1_SLOTS_WIDTH              3  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF2TX_CHAN1_START_SLOT_SHIFT         0  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF2TX_CHAN1_START_SLOT_WIDTH         6  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R811 (0x32B) - AIF2RX Channel 0 Configuration
+ */
+#define WM8996_AIF2RX_CHAN0_DAT_INV             0x8000  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8996_AIF2RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8996_AIF2RX_CHAN0_DAT_INV_SHIFT           15  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8996_AIF2RX_CHAN0_DAT_INV_WIDTH            1  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8996_AIF2RX_CHAN0_SPACING_MASK        0x7E00  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN0_SPACING_SHIFT            9  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN0_SPACING_WIDTH            6  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN0_SLOTS_SHIFT              6  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN0_SLOTS_WIDTH              3  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF2RX_CHAN0_START_SLOT_SHIFT         0  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF2RX_CHAN0_START_SLOT_WIDTH         6  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R812 (0x32C) - AIF2RX Channel 1 Configuration
+ */
+#define WM8996_AIF2RX_CHAN1_DAT_INV             0x8000  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8996_AIF2RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8996_AIF2RX_CHAN1_DAT_INV_SHIFT           15  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8996_AIF2RX_CHAN1_DAT_INV_WIDTH            1  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8996_AIF2RX_CHAN1_SPACING_MASK        0x7E00  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN1_SPACING_SHIFT            9  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN1_SPACING_WIDTH            6  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN1_SLOTS_SHIFT              6  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN1_SLOTS_WIDTH              3  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF2RX_CHAN1_START_SLOT_SHIFT         0  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF2RX_CHAN1_START_SLOT_WIDTH         6  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R813 (0x32D) - AIF2RX Mono Configuration
+ */
+#define WM8996_AIF2RX_CHAN0_MONO_MODE           0x0001  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8996_AIF2RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8996_AIF2RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8996_AIF2RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF2RX_CHAN0_MONO_MODE */
+
+/*
+ * R815 (0x32F) - AIF2TX Test
+ */
+#define WM8996_AIF2TX_DITHER_ENA                0x0001  /* AIF2TX_DITHER_ENA */
+#define WM8996_AIF2TX_DITHER_ENA_MASK           0x0001  /* AIF2TX_DITHER_ENA */
+#define WM8996_AIF2TX_DITHER_ENA_SHIFT               0  /* AIF2TX_DITHER_ENA */
+#define WM8996_AIF2TX_DITHER_ENA_WIDTH               1  /* AIF2TX_DITHER_ENA */
+
+/*
+ * R1024 (0x400) - DSP1 TX Left Volume
+ */
+#define WM8996_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
+#define WM8996_DSP1TXL_VOL_MASK                 0x00FF  /* DSP1TXL_VOL - [7:0] */
+#define WM8996_DSP1TXL_VOL_SHIFT                     0  /* DSP1TXL_VOL - [7:0] */
+#define WM8996_DSP1TXL_VOL_WIDTH                     8  /* DSP1TXL_VOL - [7:0] */
+
+/*
+ * R1025 (0x401) - DSP1 TX Right Volume
+ */
+#define WM8996_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
+#define WM8996_DSP1TXR_VOL_MASK                 0x00FF  /* DSP1TXR_VOL - [7:0] */
+#define WM8996_DSP1TXR_VOL_SHIFT                     0  /* DSP1TXR_VOL - [7:0] */
+#define WM8996_DSP1TXR_VOL_WIDTH                     8  /* DSP1TXR_VOL - [7:0] */
+
+/*
+ * R1026 (0x402) - DSP1 RX Left Volume
+ */
+#define WM8996_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
+#define WM8996_DSP1RXL_VOL_MASK                 0x00FF  /* DSP1RXL_VOL - [7:0] */
+#define WM8996_DSP1RXL_VOL_SHIFT                     0  /* DSP1RXL_VOL - [7:0] */
+#define WM8996_DSP1RXL_VOL_WIDTH                     8  /* DSP1RXL_VOL - [7:0] */
+
+/*
+ * R1027 (0x403) - DSP1 RX Right Volume
+ */
+#define WM8996_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
+#define WM8996_DSP1RXR_VOL_MASK                 0x00FF  /* DSP1RXR_VOL - [7:0] */
+#define WM8996_DSP1RXR_VOL_SHIFT                     0  /* DSP1RXR_VOL - [7:0] */
+#define WM8996_DSP1RXR_VOL_WIDTH                     8  /* DSP1RXR_VOL - [7:0] */
+
+/*
+ * R1040 (0x410) - DSP1 TX Filters
+ */
+#define WM8996_DSP1TX_NF                        0x2000  /* DSP1TX_NF */
+#define WM8996_DSP1TX_NF_MASK                   0x2000  /* DSP1TX_NF */
+#define WM8996_DSP1TX_NF_SHIFT                      13  /* DSP1TX_NF */
+#define WM8996_DSP1TX_NF_WIDTH                       1  /* DSP1TX_NF */
+#define WM8996_DSP1TXL_HPF                      0x1000  /* DSP1TXL_HPF */
+#define WM8996_DSP1TXL_HPF_MASK                 0x1000  /* DSP1TXL_HPF */
+#define WM8996_DSP1TXL_HPF_SHIFT                    12  /* DSP1TXL_HPF */
+#define WM8996_DSP1TXL_HPF_WIDTH                     1  /* DSP1TXL_HPF */
+#define WM8996_DSP1TXR_HPF                      0x0800  /* DSP1TXR_HPF */
+#define WM8996_DSP1TXR_HPF_MASK                 0x0800  /* DSP1TXR_HPF */
+#define WM8996_DSP1TXR_HPF_SHIFT                    11  /* DSP1TXR_HPF */
+#define WM8996_DSP1TXR_HPF_WIDTH                     1  /* DSP1TXR_HPF */
+#define WM8996_DSP1TX_HPF_MODE_MASK             0x0018  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8996_DSP1TX_HPF_MODE_SHIFT                 3  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8996_DSP1TX_HPF_MODE_WIDTH                 2  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8996_DSP1TX_HPF_CUT_MASK              0x0007  /* DSP1TX_HPF_CUT - [2:0] */
+#define WM8996_DSP1TX_HPF_CUT_SHIFT                  0  /* DSP1TX_HPF_CUT - [2:0] */
+#define WM8996_DSP1TX_HPF_CUT_WIDTH                  3  /* DSP1TX_HPF_CUT - [2:0] */
+
+/*
+ * R1056 (0x420) - DSP1 RX Filters (1)
+ */
+#define WM8996_DSP1RX_MUTE                      0x0200  /* DSP1RX_MUTE */
+#define WM8996_DSP1RX_MUTE_MASK                 0x0200  /* DSP1RX_MUTE */
+#define WM8996_DSP1RX_MUTE_SHIFT                     9  /* DSP1RX_MUTE */
+#define WM8996_DSP1RX_MUTE_WIDTH                     1  /* DSP1RX_MUTE */
+#define WM8996_DSP1RX_MONO                      0x0080  /* DSP1RX_MONO */
+#define WM8996_DSP1RX_MONO_MASK                 0x0080  /* DSP1RX_MONO */
+#define WM8996_DSP1RX_MONO_SHIFT                     7  /* DSP1RX_MONO */
+#define WM8996_DSP1RX_MONO_WIDTH                     1  /* DSP1RX_MONO */
+#define WM8996_DSP1RX_MUTERATE                  0x0020  /* DSP1RX_MUTERATE */
+#define WM8996_DSP1RX_MUTERATE_MASK             0x0020  /* DSP1RX_MUTERATE */
+#define WM8996_DSP1RX_MUTERATE_SHIFT                 5  /* DSP1RX_MUTERATE */
+#define WM8996_DSP1RX_MUTERATE_WIDTH                 1  /* DSP1RX_MUTERATE */
+#define WM8996_DSP1RX_UNMUTE_RAMP               0x0010  /* DSP1RX_UNMUTE_RAMP */
+#define WM8996_DSP1RX_UNMUTE_RAMP_MASK          0x0010  /* DSP1RX_UNMUTE_RAMP */
+#define WM8996_DSP1RX_UNMUTE_RAMP_SHIFT              4  /* DSP1RX_UNMUTE_RAMP */
+#define WM8996_DSP1RX_UNMUTE_RAMP_WIDTH              1  /* DSP1RX_UNMUTE_RAMP */
+
+/*
+ * R1057 (0x421) - DSP1 RX Filters (2)
+ */
+#define WM8996_DSP1RX_3D_GAIN_MASK              0x3E00  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8996_DSP1RX_3D_GAIN_SHIFT                  9  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8996_DSP1RX_3D_GAIN_WIDTH                  5  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8996_DSP1RX_3D_ENA                    0x0100  /* DSP1RX_3D_ENA */
+#define WM8996_DSP1RX_3D_ENA_MASK               0x0100  /* DSP1RX_3D_ENA */
+#define WM8996_DSP1RX_3D_ENA_SHIFT                   8  /* DSP1RX_3D_ENA */
+#define WM8996_DSP1RX_3D_ENA_WIDTH                   1  /* DSP1RX_3D_ENA */
+
+/*
+ * R1088 (0x440) - DSP1 DRC (1)
+ */
+#define WM8996_DSP1DRC_SIG_DET_RMS_MASK         0xF800  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP1DRC_SIG_DET_RMS_SHIFT            11  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP1DRC_SIG_DET_RMS_WIDTH             5  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP1DRC_SIG_DET_PK_MASK          0x0600  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP1DRC_SIG_DET_PK_SHIFT              9  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP1DRC_SIG_DET_PK_WIDTH              2  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP1DRC_NG_ENA                   0x0100  /* DSP1DRC_NG_ENA */
+#define WM8996_DSP1DRC_NG_ENA_MASK              0x0100  /* DSP1DRC_NG_ENA */
+#define WM8996_DSP1DRC_NG_ENA_SHIFT                  8  /* DSP1DRC_NG_ENA */
+#define WM8996_DSP1DRC_NG_ENA_WIDTH                  1  /* DSP1DRC_NG_ENA */
+#define WM8996_DSP1DRC_SIG_DET_MODE             0x0080  /* DSP1DRC_SIG_DET_MODE */
+#define WM8996_DSP1DRC_SIG_DET_MODE_MASK        0x0080  /* DSP1DRC_SIG_DET_MODE */
+#define WM8996_DSP1DRC_SIG_DET_MODE_SHIFT            7  /* DSP1DRC_SIG_DET_MODE */
+#define WM8996_DSP1DRC_SIG_DET_MODE_WIDTH            1  /* DSP1DRC_SIG_DET_MODE */
+#define WM8996_DSP1DRC_SIG_DET                  0x0040  /* DSP1DRC_SIG_DET */
+#define WM8996_DSP1DRC_SIG_DET_MASK             0x0040  /* DSP1DRC_SIG_DET */
+#define WM8996_DSP1DRC_SIG_DET_SHIFT                 6  /* DSP1DRC_SIG_DET */
+#define WM8996_DSP1DRC_SIG_DET_WIDTH                 1  /* DSP1DRC_SIG_DET */
+#define WM8996_DSP1DRC_KNEE2_OP_ENA             0x0020  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8996_DSP1DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8996_DSP1DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8996_DSP1DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8996_DSP1DRC_QR                       0x0010  /* DSP1DRC_QR */
+#define WM8996_DSP1DRC_QR_MASK                  0x0010  /* DSP1DRC_QR */
+#define WM8996_DSP1DRC_QR_SHIFT                      4  /* DSP1DRC_QR */
+#define WM8996_DSP1DRC_QR_WIDTH                      1  /* DSP1DRC_QR */
+#define WM8996_DSP1DRC_ANTICLIP                 0x0008  /* DSP1DRC_ANTICLIP */
+#define WM8996_DSP1DRC_ANTICLIP_MASK            0x0008  /* DSP1DRC_ANTICLIP */
+#define WM8996_DSP1DRC_ANTICLIP_SHIFT                3  /* DSP1DRC_ANTICLIP */
+#define WM8996_DSP1DRC_ANTICLIP_WIDTH                1  /* DSP1DRC_ANTICLIP */
+#define WM8996_DSP1RX_DRC_ENA                   0x0004  /* DSP1RX_DRC_ENA */
+#define WM8996_DSP1RX_DRC_ENA_MASK              0x0004  /* DSP1RX_DRC_ENA */
+#define WM8996_DSP1RX_DRC_ENA_SHIFT                  2  /* DSP1RX_DRC_ENA */
+#define WM8996_DSP1RX_DRC_ENA_WIDTH                  1  /* DSP1RX_DRC_ENA */
+#define WM8996_DSP1TXL_DRC_ENA                  0x0002  /* DSP1TXL_DRC_ENA */
+#define WM8996_DSP1TXL_DRC_ENA_MASK             0x0002  /* DSP1TXL_DRC_ENA */
+#define WM8996_DSP1TXL_DRC_ENA_SHIFT                 1  /* DSP1TXL_DRC_ENA */
+#define WM8996_DSP1TXL_DRC_ENA_WIDTH                 1  /* DSP1TXL_DRC_ENA */
+#define WM8996_DSP1TXR_DRC_ENA                  0x0001  /* DSP1TXR_DRC_ENA */
+#define WM8996_DSP1TXR_DRC_ENA_MASK             0x0001  /* DSP1TXR_DRC_ENA */
+#define WM8996_DSP1TXR_DRC_ENA_SHIFT                 0  /* DSP1TXR_DRC_ENA */
+#define WM8996_DSP1TXR_DRC_ENA_WIDTH                 1  /* DSP1TXR_DRC_ENA */
+
+/*
+ * R1089 (0x441) - DSP1 DRC (2)
+ */
+#define WM8996_DSP1DRC_ATK_MASK                 0x1E00  /* DSP1DRC_ATK - [12:9] */
+#define WM8996_DSP1DRC_ATK_SHIFT                     9  /* DSP1DRC_ATK - [12:9] */
+#define WM8996_DSP1DRC_ATK_WIDTH                     4  /* DSP1DRC_ATK - [12:9] */
+#define WM8996_DSP1DRC_DCY_MASK                 0x01E0  /* DSP1DRC_DCY - [8:5] */
+#define WM8996_DSP1DRC_DCY_SHIFT                     5  /* DSP1DRC_DCY - [8:5] */
+#define WM8996_DSP1DRC_DCY_WIDTH                     4  /* DSP1DRC_DCY - [8:5] */
+#define WM8996_DSP1DRC_MINGAIN_MASK             0x001C  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8996_DSP1DRC_MINGAIN_SHIFT                 2  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8996_DSP1DRC_MINGAIN_WIDTH                 3  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8996_DSP1DRC_MAXGAIN_MASK             0x0003  /* DSP1DRC_MAXGAIN - [1:0] */
+#define WM8996_DSP1DRC_MAXGAIN_SHIFT                 0  /* DSP1DRC_MAXGAIN - [1:0] */
+#define WM8996_DSP1DRC_MAXGAIN_WIDTH                 2  /* DSP1DRC_MAXGAIN - [1:0] */
+
+/*
+ * R1090 (0x442) - DSP1 DRC (3)
+ */
+#define WM8996_DSP1DRC_NG_MINGAIN_MASK          0xF000  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP1DRC_NG_MINGAIN_SHIFT             12  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP1DRC_NG_MINGAIN_WIDTH              4  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP1DRC_NG_EXP_MASK              0x0C00  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8996_DSP1DRC_NG_EXP_SHIFT                 10  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8996_DSP1DRC_NG_EXP_WIDTH                  2  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8996_DSP1DRC_QR_THR_MASK              0x0300  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8996_DSP1DRC_QR_THR_SHIFT                  8  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8996_DSP1DRC_QR_THR_WIDTH                  2  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8996_DSP1DRC_QR_DCY_MASK              0x00C0  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8996_DSP1DRC_QR_DCY_SHIFT                  6  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8996_DSP1DRC_QR_DCY_WIDTH                  2  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8996_DSP1DRC_HI_COMP_MASK             0x0038  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8996_DSP1DRC_HI_COMP_SHIFT                 3  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8996_DSP1DRC_HI_COMP_WIDTH                 3  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8996_DSP1DRC_LO_COMP_MASK             0x0007  /* DSP1DRC_LO_COMP - [2:0] */
+#define WM8996_DSP1DRC_LO_COMP_SHIFT                 0  /* DSP1DRC_LO_COMP - [2:0] */
+#define WM8996_DSP1DRC_LO_COMP_WIDTH                 3  /* DSP1DRC_LO_COMP - [2:0] */
+
+/*
+ * R1091 (0x443) - DSP1 DRC (4)
+ */
+#define WM8996_DSP1DRC_KNEE_IP_MASK             0x07E0  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP1DRC_KNEE_IP_SHIFT                 5  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP1DRC_KNEE_IP_WIDTH                 6  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP1DRC_KNEE_OP_MASK             0x001F  /* DSP1DRC_KNEE_OP - [4:0] */
+#define WM8996_DSP1DRC_KNEE_OP_SHIFT                 0  /* DSP1DRC_KNEE_OP - [4:0] */
+#define WM8996_DSP1DRC_KNEE_OP_WIDTH                 5  /* DSP1DRC_KNEE_OP - [4:0] */
+
+/*
+ * R1092 (0x444) - DSP1 DRC (5)
+ */
+#define WM8996_DSP1DRC_KNEE2_IP_MASK            0x03E0  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP1DRC_KNEE2_IP_SHIFT                5  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP1DRC_KNEE2_IP_WIDTH                5  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP1DRC_KNEE2_OP_MASK            0x001F  /* DSP1DRC_KNEE2_OP - [4:0] */
+#define WM8996_DSP1DRC_KNEE2_OP_SHIFT                0  /* DSP1DRC_KNEE2_OP - [4:0] */
+#define WM8996_DSP1DRC_KNEE2_OP_WIDTH                5  /* DSP1DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R1152 (0x480) - DSP1 RX EQ Gains (1)
+ */
+#define WM8996_DSP1RX_EQ_B1_GAIN_MASK           0xF800  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B1_GAIN_SHIFT              11  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B1_GAIN_WIDTH               5  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B2_GAIN_SHIFT               6  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B2_GAIN_WIDTH               5  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B3_GAIN_MASK           0x003E  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP1RX_EQ_B3_GAIN_SHIFT               1  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP1RX_EQ_B3_GAIN_WIDTH               5  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP1RX_EQ_ENA                    0x0001  /* DSP1RX_EQ_ENA */
+#define WM8996_DSP1RX_EQ_ENA_MASK               0x0001  /* DSP1RX_EQ_ENA */
+#define WM8996_DSP1RX_EQ_ENA_SHIFT                   0  /* DSP1RX_EQ_ENA */
+#define WM8996_DSP1RX_EQ_ENA_WIDTH                   1  /* DSP1RX_EQ_ENA */
+
+/*
+ * R1153 (0x481) - DSP1 RX EQ Gains (2)
+ */
+#define WM8996_DSP1RX_EQ_B4_GAIN_MASK           0xF800  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B4_GAIN_SHIFT              11  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B4_GAIN_WIDTH               5  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B5_GAIN_SHIFT               6  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B5_GAIN_WIDTH               5  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1154 (0x482) - DSP1 RX EQ Band 1 A
+ */
+#define WM8996_DSP1RX_EQ_B1_A_MASK              0xFFFF  /* DSP1RX_EQ_B1_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_A_SHIFT                  0  /* DSP1RX_EQ_B1_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_A_WIDTH                 16  /* DSP1RX_EQ_B1_A - [15:0] */
+
+/*
+ * R1155 (0x483) - DSP1 RX EQ Band 1 B
+ */
+#define WM8996_DSP1RX_EQ_B1_B_MASK              0xFFFF  /* DSP1RX_EQ_B1_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_B_SHIFT                  0  /* DSP1RX_EQ_B1_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_B_WIDTH                 16  /* DSP1RX_EQ_B1_B - [15:0] */
+
+/*
+ * R1156 (0x484) - DSP1 RX EQ Band 1 PG
+ */
+#define WM8996_DSP1RX_EQ_B1_PG_MASK             0xFFFF  /* DSP1RX_EQ_B1_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_PG_SHIFT                 0  /* DSP1RX_EQ_B1_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_PG_WIDTH                16  /* DSP1RX_EQ_B1_PG - [15:0] */
+
+/*
+ * R1157 (0x485) - DSP1 RX EQ Band 2 A
+ */
+#define WM8996_DSP1RX_EQ_B2_A_MASK              0xFFFF  /* DSP1RX_EQ_B2_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_A_SHIFT                  0  /* DSP1RX_EQ_B2_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_A_WIDTH                 16  /* DSP1RX_EQ_B2_A - [15:0] */
+
+/*
+ * R1158 (0x486) - DSP1 RX EQ Band 2 B
+ */
+#define WM8996_DSP1RX_EQ_B2_B_MASK              0xFFFF  /* DSP1RX_EQ_B2_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_B_SHIFT                  0  /* DSP1RX_EQ_B2_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_B_WIDTH                 16  /* DSP1RX_EQ_B2_B - [15:0] */
+
+/*
+ * R1159 (0x487) - DSP1 RX EQ Band 2 C
+ */
+#define WM8996_DSP1RX_EQ_B2_C_MASK              0xFFFF  /* DSP1RX_EQ_B2_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_C_SHIFT                  0  /* DSP1RX_EQ_B2_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_C_WIDTH                 16  /* DSP1RX_EQ_B2_C - [15:0] */
+
+/*
+ * R1160 (0x488) - DSP1 RX EQ Band 2 PG
+ */
+#define WM8996_DSP1RX_EQ_B2_PG_MASK             0xFFFF  /* DSP1RX_EQ_B2_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_PG_SHIFT                 0  /* DSP1RX_EQ_B2_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_PG_WIDTH                16  /* DSP1RX_EQ_B2_PG - [15:0] */
+
+/*
+ * R1161 (0x489) - DSP1 RX EQ Band 3 A
+ */
+#define WM8996_DSP1RX_EQ_B3_A_MASK              0xFFFF  /* DSP1RX_EQ_B3_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_A_SHIFT                  0  /* DSP1RX_EQ_B3_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_A_WIDTH                 16  /* DSP1RX_EQ_B3_A - [15:0] */
+
+/*
+ * R1162 (0x48A) - DSP1 RX EQ Band 3 B
+ */
+#define WM8996_DSP1RX_EQ_B3_B_MASK              0xFFFF  /* DSP1RX_EQ_B3_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_B_SHIFT                  0  /* DSP1RX_EQ_B3_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_B_WIDTH                 16  /* DSP1RX_EQ_B3_B - [15:0] */
+
+/*
+ * R1163 (0x48B) - DSP1 RX EQ Band 3 C
+ */
+#define WM8996_DSP1RX_EQ_B3_C_MASK              0xFFFF  /* DSP1RX_EQ_B3_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_C_SHIFT                  0  /* DSP1RX_EQ_B3_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_C_WIDTH                 16  /* DSP1RX_EQ_B3_C - [15:0] */
+
+/*
+ * R1164 (0x48C) - DSP1 RX EQ Band 3 PG
+ */
+#define WM8996_DSP1RX_EQ_B3_PG_MASK             0xFFFF  /* DSP1RX_EQ_B3_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_PG_SHIFT                 0  /* DSP1RX_EQ_B3_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_PG_WIDTH                16  /* DSP1RX_EQ_B3_PG - [15:0] */
+
+/*
+ * R1165 (0x48D) - DSP1 RX EQ Band 4 A
+ */
+#define WM8996_DSP1RX_EQ_B4_A_MASK              0xFFFF  /* DSP1RX_EQ_B4_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_A_SHIFT                  0  /* DSP1RX_EQ_B4_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_A_WIDTH                 16  /* DSP1RX_EQ_B4_A - [15:0] */
+
+/*
+ * R1166 (0x48E) - DSP1 RX EQ Band 4 B
+ */
+#define WM8996_DSP1RX_EQ_B4_B_MASK              0xFFFF  /* DSP1RX_EQ_B4_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_B_SHIFT                  0  /* DSP1RX_EQ_B4_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_B_WIDTH                 16  /* DSP1RX_EQ_B4_B - [15:0] */
+
+/*
+ * R1167 (0x48F) - DSP1 RX EQ Band 4 C
+ */
+#define WM8996_DSP1RX_EQ_B4_C_MASK              0xFFFF  /* DSP1RX_EQ_B4_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_C_SHIFT                  0  /* DSP1RX_EQ_B4_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_C_WIDTH                 16  /* DSP1RX_EQ_B4_C - [15:0] */
+
+/*
+ * R1168 (0x490) - DSP1 RX EQ Band 4 PG
+ */
+#define WM8996_DSP1RX_EQ_B4_PG_MASK             0xFFFF  /* DSP1RX_EQ_B4_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_PG_SHIFT                 0  /* DSP1RX_EQ_B4_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_PG_WIDTH                16  /* DSP1RX_EQ_B4_PG - [15:0] */
+
+/*
+ * R1169 (0x491) - DSP1 RX EQ Band 5 A
+ */
+#define WM8996_DSP1RX_EQ_B5_A_MASK              0xFFFF  /* DSP1RX_EQ_B5_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_A_SHIFT                  0  /* DSP1RX_EQ_B5_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_A_WIDTH                 16  /* DSP1RX_EQ_B5_A - [15:0] */
+
+/*
+ * R1170 (0x492) - DSP1 RX EQ Band 5 B
+ */
+#define WM8996_DSP1RX_EQ_B5_B_MASK              0xFFFF  /* DSP1RX_EQ_B5_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_B_SHIFT                  0  /* DSP1RX_EQ_B5_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_B_WIDTH                 16  /* DSP1RX_EQ_B5_B - [15:0] */
+
+/*
+ * R1171 (0x493) - DSP1 RX EQ Band 5 PG
+ */
+#define WM8996_DSP1RX_EQ_B5_PG_MASK             0xFFFF  /* DSP1RX_EQ_B5_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_PG_SHIFT                 0  /* DSP1RX_EQ_B5_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_PG_WIDTH                16  /* DSP1RX_EQ_B5_PG - [15:0] */
+
+/*
+ * R1280 (0x500) - DSP2 TX Left Volume
+ */
+#define WM8996_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
+#define WM8996_DSP2TXL_VOL_MASK                 0x00FF  /* DSP2TXL_VOL - [7:0] */
+#define WM8996_DSP2TXL_VOL_SHIFT                     0  /* DSP2TXL_VOL - [7:0] */
+#define WM8996_DSP2TXL_VOL_WIDTH                     8  /* DSP2TXL_VOL - [7:0] */
+
+/*
+ * R1281 (0x501) - DSP2 TX Right Volume
+ */
+#define WM8996_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
+#define WM8996_DSP2TXR_VOL_MASK                 0x00FF  /* DSP2TXR_VOL - [7:0] */
+#define WM8996_DSP2TXR_VOL_SHIFT                     0  /* DSP2TXR_VOL - [7:0] */
+#define WM8996_DSP2TXR_VOL_WIDTH                     8  /* DSP2TXR_VOL - [7:0] */
+
+/*
+ * R1282 (0x502) - DSP2 RX Left Volume
+ */
+#define WM8996_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
+#define WM8996_DSP2RXL_VOL_MASK                 0x00FF  /* DSP2RXL_VOL - [7:0] */
+#define WM8996_DSP2RXL_VOL_SHIFT                     0  /* DSP2RXL_VOL - [7:0] */
+#define WM8996_DSP2RXL_VOL_WIDTH                     8  /* DSP2RXL_VOL - [7:0] */
+
+/*
+ * R1283 (0x503) - DSP2 RX Right Volume
+ */
+#define WM8996_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
+#define WM8996_DSP2RXR_VOL_MASK                 0x00FF  /* DSP2RXR_VOL - [7:0] */
+#define WM8996_DSP2RXR_VOL_SHIFT                     0  /* DSP2RXR_VOL - [7:0] */
+#define WM8996_DSP2RXR_VOL_WIDTH                     8  /* DSP2RXR_VOL - [7:0] */
+
+/*
+ * R1296 (0x510) - DSP2 TX Filters
+ */
+#define WM8996_DSP2TX_NF                        0x2000  /* DSP2TX_NF */
+#define WM8996_DSP2TX_NF_MASK                   0x2000  /* DSP2TX_NF */
+#define WM8996_DSP2TX_NF_SHIFT                      13  /* DSP2TX_NF */
+#define WM8996_DSP2TX_NF_WIDTH                       1  /* DSP2TX_NF */
+#define WM8996_DSP2TXL_HPF                      0x1000  /* DSP2TXL_HPF */
+#define WM8996_DSP2TXL_HPF_MASK                 0x1000  /* DSP2TXL_HPF */
+#define WM8996_DSP2TXL_HPF_SHIFT                    12  /* DSP2TXL_HPF */
+#define WM8996_DSP2TXL_HPF_WIDTH                     1  /* DSP2TXL_HPF */
+#define WM8996_DSP2TXR_HPF                      0x0800  /* DSP2TXR_HPF */
+#define WM8996_DSP2TXR_HPF_MASK                 0x0800  /* DSP2TXR_HPF */
+#define WM8996_DSP2TXR_HPF_SHIFT                    11  /* DSP2TXR_HPF */
+#define WM8996_DSP2TXR_HPF_WIDTH                     1  /* DSP2TXR_HPF */
+#define WM8996_DSP2TX_HPF_MODE_MASK             0x0018  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8996_DSP2TX_HPF_MODE_SHIFT                 3  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8996_DSP2TX_HPF_MODE_WIDTH                 2  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8996_DSP2TX_HPF_CUT_MASK              0x0007  /* DSP2TX_HPF_CUT - [2:0] */
+#define WM8996_DSP2TX_HPF_CUT_SHIFT                  0  /* DSP2TX_HPF_CUT - [2:0] */
+#define WM8996_DSP2TX_HPF_CUT_WIDTH                  3  /* DSP2TX_HPF_CUT - [2:0] */
+
+/*
+ * R1312 (0x520) - DSP2 RX Filters (1)
+ */
+#define WM8996_DSP2RX_MUTE                      0x0200  /* DSP2RX_MUTE */
+#define WM8996_DSP2RX_MUTE_MASK                 0x0200  /* DSP2RX_MUTE */
+#define WM8996_DSP2RX_MUTE_SHIFT                     9  /* DSP2RX_MUTE */
+#define WM8996_DSP2RX_MUTE_WIDTH                     1  /* DSP2RX_MUTE */
+#define WM8996_DSP2RX_MONO                      0x0080  /* DSP2RX_MONO */
+#define WM8996_DSP2RX_MONO_MASK                 0x0080  /* DSP2RX_MONO */
+#define WM8996_DSP2RX_MONO_SHIFT                     7  /* DSP2RX_MONO */
+#define WM8996_DSP2RX_MONO_WIDTH                     1  /* DSP2RX_MONO */
+#define WM8996_DSP2RX_MUTERATE                  0x0020  /* DSP2RX_MUTERATE */
+#define WM8996_DSP2RX_MUTERATE_MASK             0x0020  /* DSP2RX_MUTERATE */
+#define WM8996_DSP2RX_MUTERATE_SHIFT                 5  /* DSP2RX_MUTERATE */
+#define WM8996_DSP2RX_MUTERATE_WIDTH                 1  /* DSP2RX_MUTERATE */
+#define WM8996_DSP2RX_UNMUTE_RAMP               0x0010  /* DSP2RX_UNMUTE_RAMP */
+#define WM8996_DSP2RX_UNMUTE_RAMP_MASK          0x0010  /* DSP2RX_UNMUTE_RAMP */
+#define WM8996_DSP2RX_UNMUTE_RAMP_SHIFT              4  /* DSP2RX_UNMUTE_RAMP */
+#define WM8996_DSP2RX_UNMUTE_RAMP_WIDTH              1  /* DSP2RX_UNMUTE_RAMP */
+
+/*
+ * R1313 (0x521) - DSP2 RX Filters (2)
+ */
+#define WM8996_DSP2RX_3D_GAIN_MASK              0x3E00  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8996_DSP2RX_3D_GAIN_SHIFT                  9  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8996_DSP2RX_3D_GAIN_WIDTH                  5  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8996_DSP2RX_3D_ENA                    0x0100  /* DSP2RX_3D_ENA */
+#define WM8996_DSP2RX_3D_ENA_MASK               0x0100  /* DSP2RX_3D_ENA */
+#define WM8996_DSP2RX_3D_ENA_SHIFT                   8  /* DSP2RX_3D_ENA */
+#define WM8996_DSP2RX_3D_ENA_WIDTH                   1  /* DSP2RX_3D_ENA */
+
+/*
+ * R1344 (0x540) - DSP2 DRC (1)
+ */
+#define WM8996_DSP2DRC_SIG_DET_RMS_MASK         0xF800  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP2DRC_SIG_DET_RMS_SHIFT            11  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP2DRC_SIG_DET_RMS_WIDTH             5  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP2DRC_SIG_DET_PK_MASK          0x0600  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP2DRC_SIG_DET_PK_SHIFT              9  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP2DRC_SIG_DET_PK_WIDTH              2  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP2DRC_NG_ENA                   0x0100  /* DSP2DRC_NG_ENA */
+#define WM8996_DSP2DRC_NG_ENA_MASK              0x0100  /* DSP2DRC_NG_ENA */
+#define WM8996_DSP2DRC_NG_ENA_SHIFT                  8  /* DSP2DRC_NG_ENA */
+#define WM8996_DSP2DRC_NG_ENA_WIDTH                  1  /* DSP2DRC_NG_ENA */
+#define WM8996_DSP2DRC_SIG_DET_MODE             0x0080  /* DSP2DRC_SIG_DET_MODE */
+#define WM8996_DSP2DRC_SIG_DET_MODE_MASK        0x0080  /* DSP2DRC_SIG_DET_MODE */
+#define WM8996_DSP2DRC_SIG_DET_MODE_SHIFT            7  /* DSP2DRC_SIG_DET_MODE */
+#define WM8996_DSP2DRC_SIG_DET_MODE_WIDTH            1  /* DSP2DRC_SIG_DET_MODE */
+#define WM8996_DSP2DRC_SIG_DET                  0x0040  /* DSP2DRC_SIG_DET */
+#define WM8996_DSP2DRC_SIG_DET_MASK             0x0040  /* DSP2DRC_SIG_DET */
+#define WM8996_DSP2DRC_SIG_DET_SHIFT                 6  /* DSP2DRC_SIG_DET */
+#define WM8996_DSP2DRC_SIG_DET_WIDTH                 1  /* DSP2DRC_SIG_DET */
+#define WM8996_DSP2DRC_KNEE2_OP_ENA             0x0020  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8996_DSP2DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8996_DSP2DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8996_DSP2DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8996_DSP2DRC_QR                       0x0010  /* DSP2DRC_QR */
+#define WM8996_DSP2DRC_QR_MASK                  0x0010  /* DSP2DRC_QR */
+#define WM8996_DSP2DRC_QR_SHIFT                      4  /* DSP2DRC_QR */
+#define WM8996_DSP2DRC_QR_WIDTH                      1  /* DSP2DRC_QR */
+#define WM8996_DSP2DRC_ANTICLIP                 0x0008  /* DSP2DRC_ANTICLIP */
+#define WM8996_DSP2DRC_ANTICLIP_MASK            0x0008  /* DSP2DRC_ANTICLIP */
+#define WM8996_DSP2DRC_ANTICLIP_SHIFT                3  /* DSP2DRC_ANTICLIP */
+#define WM8996_DSP2DRC_ANTICLIP_WIDTH                1  /* DSP2DRC_ANTICLIP */
+#define WM8996_DSP2RX_DRC_ENA                   0x0004  /* DSP2RX_DRC_ENA */
+#define WM8996_DSP2RX_DRC_ENA_MASK              0x0004  /* DSP2RX_DRC_ENA */
+#define WM8996_DSP2RX_DRC_ENA_SHIFT                  2  /* DSP2RX_DRC_ENA */
+#define WM8996_DSP2RX_DRC_ENA_WIDTH                  1  /* DSP2RX_DRC_ENA */
+#define WM8996_DSP2TXL_DRC_ENA                  0x0002  /* DSP2TXL_DRC_ENA */
+#define WM8996_DSP2TXL_DRC_ENA_MASK             0x0002  /* DSP2TXL_DRC_ENA */
+#define WM8996_DSP2TXL_DRC_ENA_SHIFT                 1  /* DSP2TXL_DRC_ENA */
+#define WM8996_DSP2TXL_DRC_ENA_WIDTH                 1  /* DSP2TXL_DRC_ENA */
+#define WM8996_DSP2TXR_DRC_ENA                  0x0001  /* DSP2TXR_DRC_ENA */
+#define WM8996_DSP2TXR_DRC_ENA_MASK             0x0001  /* DSP2TXR_DRC_ENA */
+#define WM8996_DSP2TXR_DRC_ENA_SHIFT                 0  /* DSP2TXR_DRC_ENA */
+#define WM8996_DSP2TXR_DRC_ENA_WIDTH                 1  /* DSP2TXR_DRC_ENA */
+
+/*
+ * R1345 (0x541) - DSP2 DRC (2)
+ */
+#define WM8996_DSP2DRC_ATK_MASK                 0x1E00  /* DSP2DRC_ATK - [12:9] */
+#define WM8996_DSP2DRC_ATK_SHIFT                     9  /* DSP2DRC_ATK - [12:9] */
+#define WM8996_DSP2DRC_ATK_WIDTH                     4  /* DSP2DRC_ATK - [12:9] */
+#define WM8996_DSP2DRC_DCY_MASK                 0x01E0  /* DSP2DRC_DCY - [8:5] */
+#define WM8996_DSP2DRC_DCY_SHIFT                     5  /* DSP2DRC_DCY - [8:5] */
+#define WM8996_DSP2DRC_DCY_WIDTH                     4  /* DSP2DRC_DCY - [8:5] */
+#define WM8996_DSP2DRC_MINGAIN_MASK             0x001C  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8996_DSP2DRC_MINGAIN_SHIFT                 2  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8996_DSP2DRC_MINGAIN_WIDTH                 3  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8996_DSP2DRC_MAXGAIN_MASK             0x0003  /* DSP2DRC_MAXGAIN - [1:0] */
+#define WM8996_DSP2DRC_MAXGAIN_SHIFT                 0  /* DSP2DRC_MAXGAIN - [1:0] */
+#define WM8996_DSP2DRC_MAXGAIN_WIDTH                 2  /* DSP2DRC_MAXGAIN - [1:0] */
+
+/*
+ * R1346 (0x542) - DSP2 DRC (3)
+ */
+#define WM8996_DSP2DRC_NG_MINGAIN_MASK          0xF000  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP2DRC_NG_MINGAIN_SHIFT             12  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP2DRC_NG_MINGAIN_WIDTH              4  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP2DRC_NG_EXP_MASK              0x0C00  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8996_DSP2DRC_NG_EXP_SHIFT                 10  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8996_DSP2DRC_NG_EXP_WIDTH                  2  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8996_DSP2DRC_QR_THR_MASK              0x0300  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8996_DSP2DRC_QR_THR_SHIFT                  8  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8996_DSP2DRC_QR_THR_WIDTH                  2  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8996_DSP2DRC_QR_DCY_MASK              0x00C0  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8996_DSP2DRC_QR_DCY_SHIFT                  6  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8996_DSP2DRC_QR_DCY_WIDTH                  2  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8996_DSP2DRC_HI_COMP_MASK             0x0038  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8996_DSP2DRC_HI_COMP_SHIFT                 3  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8996_DSP2DRC_HI_COMP_WIDTH                 3  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8996_DSP2DRC_LO_COMP_MASK             0x0007  /* DSP2DRC_LO_COMP - [2:0] */
+#define WM8996_DSP2DRC_LO_COMP_SHIFT                 0  /* DSP2DRC_LO_COMP - [2:0] */
+#define WM8996_DSP2DRC_LO_COMP_WIDTH                 3  /* DSP2DRC_LO_COMP - [2:0] */
+
+/*
+ * R1347 (0x543) - DSP2 DRC (4)
+ */
+#define WM8996_DSP2DRC_KNEE_IP_MASK             0x07E0  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP2DRC_KNEE_IP_SHIFT                 5  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP2DRC_KNEE_IP_WIDTH                 6  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP2DRC_KNEE_OP_MASK             0x001F  /* DSP2DRC_KNEE_OP - [4:0] */
+#define WM8996_DSP2DRC_KNEE_OP_SHIFT                 0  /* DSP2DRC_KNEE_OP - [4:0] */
+#define WM8996_DSP2DRC_KNEE_OP_WIDTH                 5  /* DSP2DRC_KNEE_OP - [4:0] */
+
+/*
+ * R1348 (0x544) - DSP2 DRC (5)
+ */
+#define WM8996_DSP2DRC_KNEE2_IP_MASK            0x03E0  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP2DRC_KNEE2_IP_SHIFT                5  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP2DRC_KNEE2_IP_WIDTH                5  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP2DRC_KNEE2_OP_MASK            0x001F  /* DSP2DRC_KNEE2_OP - [4:0] */
+#define WM8996_DSP2DRC_KNEE2_OP_SHIFT                0  /* DSP2DRC_KNEE2_OP - [4:0] */
+#define WM8996_DSP2DRC_KNEE2_OP_WIDTH                5  /* DSP2DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R1408 (0x580) - DSP2 RX EQ Gains (1)
+ */
+#define WM8996_DSP2RX_EQ_B1_GAIN_MASK           0xF800  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B1_GAIN_SHIFT              11  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B1_GAIN_WIDTH               5  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B2_GAIN_SHIFT               6  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B2_GAIN_WIDTH               5  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B3_GAIN_MASK           0x003E  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP2RX_EQ_B3_GAIN_SHIFT               1  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP2RX_EQ_B3_GAIN_WIDTH               5  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP2RX_EQ_ENA                    0x0001  /* DSP2RX_EQ_ENA */
+#define WM8996_DSP2RX_EQ_ENA_MASK               0x0001  /* DSP2RX_EQ_ENA */
+#define WM8996_DSP2RX_EQ_ENA_SHIFT                   0  /* DSP2RX_EQ_ENA */
+#define WM8996_DSP2RX_EQ_ENA_WIDTH                   1  /* DSP2RX_EQ_ENA */
+
+/*
+ * R1409 (0x581) - DSP2 RX EQ Gains (2)
+ */
+#define WM8996_DSP2RX_EQ_B4_GAIN_MASK           0xF800  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B4_GAIN_SHIFT              11  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B4_GAIN_WIDTH               5  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B5_GAIN_SHIFT               6  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B5_GAIN_WIDTH               5  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1410 (0x582) - DSP2 RX EQ Band 1 A
+ */
+#define WM8996_DSP2RX_EQ_B1_A_MASK              0xFFFF  /* DSP2RX_EQ_B1_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_A_SHIFT                  0  /* DSP2RX_EQ_B1_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_A_WIDTH                 16  /* DSP2RX_EQ_B1_A - [15:0] */
+
+/*
+ * R1411 (0x583) - DSP2 RX EQ Band 1 B
+ */
+#define WM8996_DSP2RX_EQ_B1_B_MASK              0xFFFF  /* DSP2RX_EQ_B1_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_B_SHIFT                  0  /* DSP2RX_EQ_B1_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_B_WIDTH                 16  /* DSP2RX_EQ_B1_B - [15:0] */
+
+/*
+ * R1412 (0x584) - DSP2 RX EQ Band 1 PG
+ */
+#define WM8996_DSP2RX_EQ_B1_PG_MASK             0xFFFF  /* DSP2RX_EQ_B1_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_PG_SHIFT                 0  /* DSP2RX_EQ_B1_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_PG_WIDTH                16  /* DSP2RX_EQ_B1_PG - [15:0] */
+
+/*
+ * R1413 (0x585) - DSP2 RX EQ Band 2 A
+ */
+#define WM8996_DSP2RX_EQ_B2_A_MASK              0xFFFF  /* DSP2RX_EQ_B2_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_A_SHIFT                  0  /* DSP2RX_EQ_B2_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_A_WIDTH                 16  /* DSP2RX_EQ_B2_A - [15:0] */
+
+/*
+ * R1414 (0x586) - DSP2 RX EQ Band 2 B
+ */
+#define WM8996_DSP2RX_EQ_B2_B_MASK              0xFFFF  /* DSP2RX_EQ_B2_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_B_SHIFT                  0  /* DSP2RX_EQ_B2_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_B_WIDTH                 16  /* DSP2RX_EQ_B2_B - [15:0] */
+
+/*
+ * R1415 (0x587) - DSP2 RX EQ Band 2 C
+ */
+#define WM8996_DSP2RX_EQ_B2_C_MASK              0xFFFF  /* DSP2RX_EQ_B2_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_C_SHIFT                  0  /* DSP2RX_EQ_B2_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_C_WIDTH                 16  /* DSP2RX_EQ_B2_C - [15:0] */
+
+/*
+ * R1416 (0x588) - DSP2 RX EQ Band 2 PG
+ */
+#define WM8996_DSP2RX_EQ_B2_PG_MASK             0xFFFF  /* DSP2RX_EQ_B2_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_PG_SHIFT                 0  /* DSP2RX_EQ_B2_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_PG_WIDTH                16  /* DSP2RX_EQ_B2_PG - [15:0] */
+
+/*
+ * R1417 (0x589) - DSP2 RX EQ Band 3 A
+ */
+#define WM8996_DSP2RX_EQ_B3_A_MASK              0xFFFF  /* DSP2RX_EQ_B3_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_A_SHIFT                  0  /* DSP2RX_EQ_B3_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_A_WIDTH                 16  /* DSP2RX_EQ_B3_A - [15:0] */
+
+/*
+ * R1418 (0x58A) - DSP2 RX EQ Band 3 B
+ */
+#define WM8996_DSP2RX_EQ_B3_B_MASK              0xFFFF  /* DSP2RX_EQ_B3_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_B_SHIFT                  0  /* DSP2RX_EQ_B3_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_B_WIDTH                 16  /* DSP2RX_EQ_B3_B - [15:0] */
+
+/*
+ * R1419 (0x58B) - DSP2 RX EQ Band 3 C
+ */
+#define WM8996_DSP2RX_EQ_B3_C_MASK              0xFFFF  /* DSP2RX_EQ_B3_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_C_SHIFT                  0  /* DSP2RX_EQ_B3_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_C_WIDTH                 16  /* DSP2RX_EQ_B3_C - [15:0] */
+
+/*
+ * R1420 (0x58C) - DSP2 RX EQ Band 3 PG
+ */
+#define WM8996_DSP2RX_EQ_B3_PG_MASK             0xFFFF  /* DSP2RX_EQ_B3_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_PG_SHIFT                 0  /* DSP2RX_EQ_B3_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_PG_WIDTH                16  /* DSP2RX_EQ_B3_PG - [15:0] */
+
+/*
+ * R1421 (0x58D) - DSP2 RX EQ Band 4 A
+ */
+#define WM8996_DSP2RX_EQ_B4_A_MASK              0xFFFF  /* DSP2RX_EQ_B4_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_A_SHIFT                  0  /* DSP2RX_EQ_B4_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_A_WIDTH                 16  /* DSP2RX_EQ_B4_A - [15:0] */
+
+/*
+ * R1422 (0x58E) - DSP2 RX EQ Band 4 B
+ */
+#define WM8996_DSP2RX_EQ_B4_B_MASK              0xFFFF  /* DSP2RX_EQ_B4_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_B_SHIFT                  0  /* DSP2RX_EQ_B4_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_B_WIDTH                 16  /* DSP2RX_EQ_B4_B - [15:0] */
+
+/*
+ * R1423 (0x58F) - DSP2 RX EQ Band 4 C
+ */
+#define WM8996_DSP2RX_EQ_B4_C_MASK              0xFFFF  /* DSP2RX_EQ_B4_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_C_SHIFT                  0  /* DSP2RX_EQ_B4_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_C_WIDTH                 16  /* DSP2RX_EQ_B4_C - [15:0] */
+
+/*
+ * R1424 (0x590) - DSP2 RX EQ Band 4 PG
+ */
+#define WM8996_DSP2RX_EQ_B4_PG_MASK             0xFFFF  /* DSP2RX_EQ_B4_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_PG_SHIFT                 0  /* DSP2RX_EQ_B4_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_PG_WIDTH                16  /* DSP2RX_EQ_B4_PG - [15:0] */
+
+/*
+ * R1425 (0x591) - DSP2 RX EQ Band 5 A
+ */
+#define WM8996_DSP2RX_EQ_B5_A_MASK              0xFFFF  /* DSP2RX_EQ_B5_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_A_SHIFT                  0  /* DSP2RX_EQ_B5_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_A_WIDTH                 16  /* DSP2RX_EQ_B5_A - [15:0] */
+
+/*
+ * R1426 (0x592) - DSP2 RX EQ Band 5 B
+ */
+#define WM8996_DSP2RX_EQ_B5_B_MASK              0xFFFF  /* DSP2RX_EQ_B5_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_B_SHIFT                  0  /* DSP2RX_EQ_B5_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_B_WIDTH                 16  /* DSP2RX_EQ_B5_B - [15:0] */
+
+/*
+ * R1427 (0x593) - DSP2 RX EQ Band 5 PG
+ */
+#define WM8996_DSP2RX_EQ_B5_PG_MASK             0xFFFF  /* DSP2RX_EQ_B5_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_PG_SHIFT                 0  /* DSP2RX_EQ_B5_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_PG_WIDTH                16  /* DSP2RX_EQ_B5_PG - [15:0] */
+
+/*
+ * R1536 (0x600) - DAC1 Mixer Volumes
+ */
+#define WM8996_ADCR_DAC1_VOL_MASK               0x03E0  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8996_ADCR_DAC1_VOL_SHIFT                   5  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8996_ADCR_DAC1_VOL_WIDTH                   5  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8996_ADCL_DAC1_VOL_MASK               0x001F  /* ADCL_DAC1_VOL - [4:0] */
+#define WM8996_ADCL_DAC1_VOL_SHIFT                   0  /* ADCL_DAC1_VOL - [4:0] */
+#define WM8996_ADCL_DAC1_VOL_WIDTH                   5  /* ADCL_DAC1_VOL - [4:0] */
+
+/*
+ * R1537 (0x601) - DAC1 Left Mixer Routing
+ */
+#define WM8996_ADCR_TO_DAC1L                    0x0020  /* ADCR_TO_DAC1L */
+#define WM8996_ADCR_TO_DAC1L_MASK               0x0020  /* ADCR_TO_DAC1L */
+#define WM8996_ADCR_TO_DAC1L_SHIFT                   5  /* ADCR_TO_DAC1L */
+#define WM8996_ADCR_TO_DAC1L_WIDTH                   1  /* ADCR_TO_DAC1L */
+#define WM8996_ADCL_TO_DAC1L                    0x0010  /* ADCL_TO_DAC1L */
+#define WM8996_ADCL_TO_DAC1L_MASK               0x0010  /* ADCL_TO_DAC1L */
+#define WM8996_ADCL_TO_DAC1L_SHIFT                   4  /* ADCL_TO_DAC1L */
+#define WM8996_ADCL_TO_DAC1L_WIDTH                   1  /* ADCL_TO_DAC1L */
+#define WM8996_DSP2RXL_TO_DAC1L                 0x0002  /* DSP2RXL_TO_DAC1L */
+#define WM8996_DSP2RXL_TO_DAC1L_MASK            0x0002  /* DSP2RXL_TO_DAC1L */
+#define WM8996_DSP2RXL_TO_DAC1L_SHIFT                1  /* DSP2RXL_TO_DAC1L */
+#define WM8996_DSP2RXL_TO_DAC1L_WIDTH                1  /* DSP2RXL_TO_DAC1L */
+#define WM8996_DSP1RXL_TO_DAC1L                 0x0001  /* DSP1RXL_TO_DAC1L */
+#define WM8996_DSP1RXL_TO_DAC1L_MASK            0x0001  /* DSP1RXL_TO_DAC1L */
+#define WM8996_DSP1RXL_TO_DAC1L_SHIFT                0  /* DSP1RXL_TO_DAC1L */
+#define WM8996_DSP1RXL_TO_DAC1L_WIDTH                1  /* DSP1RXL_TO_DAC1L */
+
+/*
+ * R1538 (0x602) - DAC1 Right Mixer Routing
+ */
+#define WM8996_ADCR_TO_DAC1R                    0x0020  /* ADCR_TO_DAC1R */
+#define WM8996_ADCR_TO_DAC1R_MASK               0x0020  /* ADCR_TO_DAC1R */
+#define WM8996_ADCR_TO_DAC1R_SHIFT                   5  /* ADCR_TO_DAC1R */
+#define WM8996_ADCR_TO_DAC1R_WIDTH                   1  /* ADCR_TO_DAC1R */
+#define WM8996_ADCL_TO_DAC1R                    0x0010  /* ADCL_TO_DAC1R */
+#define WM8996_ADCL_TO_DAC1R_MASK               0x0010  /* ADCL_TO_DAC1R */
+#define WM8996_ADCL_TO_DAC1R_SHIFT                   4  /* ADCL_TO_DAC1R */
+#define WM8996_ADCL_TO_DAC1R_WIDTH                   1  /* ADCL_TO_DAC1R */
+#define WM8996_DSP2RXR_TO_DAC1R                 0x0002  /* DSP2RXR_TO_DAC1R */
+#define WM8996_DSP2RXR_TO_DAC1R_MASK            0x0002  /* DSP2RXR_TO_DAC1R */
+#define WM8996_DSP2RXR_TO_DAC1R_SHIFT                1  /* DSP2RXR_TO_DAC1R */
+#define WM8996_DSP2RXR_TO_DAC1R_WIDTH                1  /* DSP2RXR_TO_DAC1R */
+#define WM8996_DSP1RXR_TO_DAC1R                 0x0001  /* DSP1RXR_TO_DAC1R */
+#define WM8996_DSP1RXR_TO_DAC1R_MASK            0x0001  /* DSP1RXR_TO_DAC1R */
+#define WM8996_DSP1RXR_TO_DAC1R_SHIFT                0  /* DSP1RXR_TO_DAC1R */
+#define WM8996_DSP1RXR_TO_DAC1R_WIDTH                1  /* DSP1RXR_TO_DAC1R */
+
+/*
+ * R1539 (0x603) - DAC2 Mixer Volumes
+ */
+#define WM8996_ADCR_DAC2_VOL_MASK               0x03E0  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8996_ADCR_DAC2_VOL_SHIFT                   5  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8996_ADCR_DAC2_VOL_WIDTH                   5  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8996_ADCL_DAC2_VOL_MASK               0x001F  /* ADCL_DAC2_VOL - [4:0] */
+#define WM8996_ADCL_DAC2_VOL_SHIFT                   0  /* ADCL_DAC2_VOL - [4:0] */
+#define WM8996_ADCL_DAC2_VOL_WIDTH                   5  /* ADCL_DAC2_VOL - [4:0] */
+
+/*
+ * R1540 (0x604) - DAC2 Left Mixer Routing
+ */
+#define WM8996_ADCR_TO_DAC2L                    0x0020  /* ADCR_TO_DAC2L */
+#define WM8996_ADCR_TO_DAC2L_MASK               0x0020  /* ADCR_TO_DAC2L */
+#define WM8996_ADCR_TO_DAC2L_SHIFT                   5  /* ADCR_TO_DAC2L */
+#define WM8996_ADCR_TO_DAC2L_WIDTH                   1  /* ADCR_TO_DAC2L */
+#define WM8996_ADCL_TO_DAC2L                    0x0010  /* ADCL_TO_DAC2L */
+#define WM8996_ADCL_TO_DAC2L_MASK               0x0010  /* ADCL_TO_DAC2L */
+#define WM8996_ADCL_TO_DAC2L_SHIFT                   4  /* ADCL_TO_DAC2L */
+#define WM8996_ADCL_TO_DAC2L_WIDTH                   1  /* ADCL_TO_DAC2L */
+#define WM8996_DSP2RXL_TO_DAC2L                 0x0002  /* DSP2RXL_TO_DAC2L */
+#define WM8996_DSP2RXL_TO_DAC2L_MASK            0x0002  /* DSP2RXL_TO_DAC2L */
+#define WM8996_DSP2RXL_TO_DAC2L_SHIFT                1  /* DSP2RXL_TO_DAC2L */
+#define WM8996_DSP2RXL_TO_DAC2L_WIDTH                1  /* DSP2RXL_TO_DAC2L */
+#define WM8996_DSP1RXL_TO_DAC2L                 0x0001  /* DSP1RXL_TO_DAC2L */
+#define WM8996_DSP1RXL_TO_DAC2L_MASK            0x0001  /* DSP1RXL_TO_DAC2L */
+#define WM8996_DSP1RXL_TO_DAC2L_SHIFT                0  /* DSP1RXL_TO_DAC2L */
+#define WM8996_DSP1RXL_TO_DAC2L_WIDTH                1  /* DSP1RXL_TO_DAC2L */
+
+/*
+ * R1541 (0x605) - DAC2 Right Mixer Routing
+ */
+#define WM8996_ADCR_TO_DAC2R                    0x0020  /* ADCR_TO_DAC2R */
+#define WM8996_ADCR_TO_DAC2R_MASK               0x0020  /* ADCR_TO_DAC2R */
+#define WM8996_ADCR_TO_DAC2R_SHIFT                   5  /* ADCR_TO_DAC2R */
+#define WM8996_ADCR_TO_DAC2R_WIDTH                   1  /* ADCR_TO_DAC2R */
+#define WM8996_ADCL_TO_DAC2R                    0x0010  /* ADCL_TO_DAC2R */
+#define WM8996_ADCL_TO_DAC2R_MASK               0x0010  /* ADCL_TO_DAC2R */
+#define WM8996_ADCL_TO_DAC2R_SHIFT                   4  /* ADCL_TO_DAC2R */
+#define WM8996_ADCL_TO_DAC2R_WIDTH                   1  /* ADCL_TO_DAC2R */
+#define WM8996_DSP2RXR_TO_DAC2R                 0x0002  /* DSP2RXR_TO_DAC2R */
+#define WM8996_DSP2RXR_TO_DAC2R_MASK            0x0002  /* DSP2RXR_TO_DAC2R */
+#define WM8996_DSP2RXR_TO_DAC2R_SHIFT                1  /* DSP2RXR_TO_DAC2R */
+#define WM8996_DSP2RXR_TO_DAC2R_WIDTH                1  /* DSP2RXR_TO_DAC2R */
+#define WM8996_DSP1RXR_TO_DAC2R                 0x0001  /* DSP1RXR_TO_DAC2R */
+#define WM8996_DSP1RXR_TO_DAC2R_MASK            0x0001  /* DSP1RXR_TO_DAC2R */
+#define WM8996_DSP1RXR_TO_DAC2R_SHIFT                0  /* DSP1RXR_TO_DAC2R */
+#define WM8996_DSP1RXR_TO_DAC2R_WIDTH                1  /* DSP1RXR_TO_DAC2R */
+
+/*
+ * R1542 (0x606) - DSP1 TX Left Mixer Routing
+ */
+#define WM8996_ADC1L_TO_DSP1TXL                 0x0002  /* ADC1L_TO_DSP1TXL */
+#define WM8996_ADC1L_TO_DSP1TXL_MASK            0x0002  /* ADC1L_TO_DSP1TXL */
+#define WM8996_ADC1L_TO_DSP1TXL_SHIFT                1  /* ADC1L_TO_DSP1TXL */
+#define WM8996_ADC1L_TO_DSP1TXL_WIDTH                1  /* ADC1L_TO_DSP1TXL */
+#define WM8996_DACL_TO_DSP1TXL                  0x0001  /* DACL_TO_DSP1TXL */
+#define WM8996_DACL_TO_DSP1TXL_MASK             0x0001  /* DACL_TO_DSP1TXL */
+#define WM8996_DACL_TO_DSP1TXL_SHIFT                 0  /* DACL_TO_DSP1TXL */
+#define WM8996_DACL_TO_DSP1TXL_WIDTH                 1  /* DACL_TO_DSP1TXL */
+
+/*
+ * R1543 (0x607) - DSP1 TX Right Mixer Routing
+ */
+#define WM8996_ADC1R_TO_DSP1TXR                 0x0002  /* ADC1R_TO_DSP1TXR */
+#define WM8996_ADC1R_TO_DSP1TXR_MASK            0x0002  /* ADC1R_TO_DSP1TXR */
+#define WM8996_ADC1R_TO_DSP1TXR_SHIFT                1  /* ADC1R_TO_DSP1TXR */
+#define WM8996_ADC1R_TO_DSP1TXR_WIDTH                1  /* ADC1R_TO_DSP1TXR */
+#define WM8996_DACR_TO_DSP1TXR                  0x0001  /* DACR_TO_DSP1TXR */
+#define WM8996_DACR_TO_DSP1TXR_MASK             0x0001  /* DACR_TO_DSP1TXR */
+#define WM8996_DACR_TO_DSP1TXR_SHIFT                 0  /* DACR_TO_DSP1TXR */
+#define WM8996_DACR_TO_DSP1TXR_WIDTH                 1  /* DACR_TO_DSP1TXR */
+
+/*
+ * R1544 (0x608) - DSP2 TX Left Mixer Routing
+ */
+#define WM8996_ADC2L_TO_DSP2TXL                 0x0002  /* ADC2L_TO_DSP2TXL */
+#define WM8996_ADC2L_TO_DSP2TXL_MASK            0x0002  /* ADC2L_TO_DSP2TXL */
+#define WM8996_ADC2L_TO_DSP2TXL_SHIFT                1  /* ADC2L_TO_DSP2TXL */
+#define WM8996_ADC2L_TO_DSP2TXL_WIDTH                1  /* ADC2L_TO_DSP2TXL */
+#define WM8996_DACL_TO_DSP2TXL                  0x0001  /* DACL_TO_DSP2TXL */
+#define WM8996_DACL_TO_DSP2TXL_MASK             0x0001  /* DACL_TO_DSP2TXL */
+#define WM8996_DACL_TO_DSP2TXL_SHIFT                 0  /* DACL_TO_DSP2TXL */
+#define WM8996_DACL_TO_DSP2TXL_WIDTH                 1  /* DACL_TO_DSP2TXL */
+
+/*
+ * R1545 (0x609) - DSP2 TX Right Mixer Routing
+ */
+#define WM8996_ADC2R_TO_DSP2TXR                 0x0002  /* ADC2R_TO_DSP2TXR */
+#define WM8996_ADC2R_TO_DSP2TXR_MASK            0x0002  /* ADC2R_TO_DSP2TXR */
+#define WM8996_ADC2R_TO_DSP2TXR_SHIFT                1  /* ADC2R_TO_DSP2TXR */
+#define WM8996_ADC2R_TO_DSP2TXR_WIDTH                1  /* ADC2R_TO_DSP2TXR */
+#define WM8996_DACR_TO_DSP2TXR                  0x0001  /* DACR_TO_DSP2TXR */
+#define WM8996_DACR_TO_DSP2TXR_MASK             0x0001  /* DACR_TO_DSP2TXR */
+#define WM8996_DACR_TO_DSP2TXR_SHIFT                 0  /* DACR_TO_DSP2TXR */
+#define WM8996_DACR_TO_DSP2TXR_WIDTH                 1  /* DACR_TO_DSP2TXR */
+
+/*
+ * R1546 (0x60A) - DSP TX Mixer Select
+ */
+#define WM8996_DAC_TO_DSPTX_SRC                 0x0001  /* DAC_TO_DSPTX_SRC */
+#define WM8996_DAC_TO_DSPTX_SRC_MASK            0x0001  /* DAC_TO_DSPTX_SRC */
+#define WM8996_DAC_TO_DSPTX_SRC_SHIFT                0  /* DAC_TO_DSPTX_SRC */
+#define WM8996_DAC_TO_DSPTX_SRC_WIDTH                1  /* DAC_TO_DSPTX_SRC */
+
+/*
+ * R1552 (0x610) - DAC Softmute
+ */
+#define WM8996_DAC_SOFTMUTEMODE                 0x0002  /* DAC_SOFTMUTEMODE */
+#define WM8996_DAC_SOFTMUTEMODE_MASK            0x0002  /* DAC_SOFTMUTEMODE */
+#define WM8996_DAC_SOFTMUTEMODE_SHIFT                1  /* DAC_SOFTMUTEMODE */
+#define WM8996_DAC_SOFTMUTEMODE_WIDTH                1  /* DAC_SOFTMUTEMODE */
+#define WM8996_DAC_MUTERATE                     0x0001  /* DAC_MUTERATE */
+#define WM8996_DAC_MUTERATE_MASK                0x0001  /* DAC_MUTERATE */
+#define WM8996_DAC_MUTERATE_SHIFT                    0  /* DAC_MUTERATE */
+#define WM8996_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+
+/*
+ * R1568 (0x620) - Oversampling
+ */
+#define WM8996_SPK_OSR128                       0x0008  /* SPK_OSR128 */
+#define WM8996_SPK_OSR128_MASK                  0x0008  /* SPK_OSR128 */
+#define WM8996_SPK_OSR128_SHIFT                      3  /* SPK_OSR128 */
+#define WM8996_SPK_OSR128_WIDTH                      1  /* SPK_OSR128 */
+#define WM8996_DMIC_OSR64                       0x0004  /* DMIC_OSR64 */
+#define WM8996_DMIC_OSR64_MASK                  0x0004  /* DMIC_OSR64 */
+#define WM8996_DMIC_OSR64_SHIFT                      2  /* DMIC_OSR64 */
+#define WM8996_DMIC_OSR64_WIDTH                      1  /* DMIC_OSR64 */
+#define WM8996_ADC_OSR128                       0x0002  /* ADC_OSR128 */
+#define WM8996_ADC_OSR128_MASK                  0x0002  /* ADC_OSR128 */
+#define WM8996_ADC_OSR128_SHIFT                      1  /* ADC_OSR128 */
+#define WM8996_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
+#define WM8996_DAC_OSR128                       0x0001  /* DAC_OSR128 */
+#define WM8996_DAC_OSR128_MASK                  0x0001  /* DAC_OSR128 */
+#define WM8996_DAC_OSR128_SHIFT                      0  /* DAC_OSR128 */
+#define WM8996_DAC_OSR128_WIDTH                      1  /* DAC_OSR128 */
+
+/*
+ * R1569 (0x621) - Sidetone
+ */
+#define WM8996_ST_LPF                           0x1000  /* ST_LPF */
+#define WM8996_ST_LPF_MASK                      0x1000  /* ST_LPF */
+#define WM8996_ST_LPF_SHIFT                         12  /* ST_LPF */
+#define WM8996_ST_LPF_WIDTH                          1  /* ST_LPF */
+#define WM8996_ST_HPF_CUT_MASK                  0x0380  /* ST_HPF_CUT - [9:7] */
+#define WM8996_ST_HPF_CUT_SHIFT                      7  /* ST_HPF_CUT - [9:7] */
+#define WM8996_ST_HPF_CUT_WIDTH                      3  /* ST_HPF_CUT - [9:7] */
+#define WM8996_ST_HPF                           0x0040  /* ST_HPF */
+#define WM8996_ST_HPF_MASK                      0x0040  /* ST_HPF */
+#define WM8996_ST_HPF_SHIFT                          6  /* ST_HPF */
+#define WM8996_ST_HPF_WIDTH                          1  /* ST_HPF */
+#define WM8996_STR_SEL                          0x0002  /* STR_SEL */
+#define WM8996_STR_SEL_MASK                     0x0002  /* STR_SEL */
+#define WM8996_STR_SEL_SHIFT                         1  /* STR_SEL */
+#define WM8996_STR_SEL_WIDTH                         1  /* STR_SEL */
+#define WM8996_STL_SEL                          0x0001  /* STL_SEL */
+#define WM8996_STL_SEL_MASK                     0x0001  /* STL_SEL */
+#define WM8996_STL_SEL_SHIFT                         0  /* STL_SEL */
+#define WM8996_STL_SEL_WIDTH                         1  /* STL_SEL */
+
+/*
+ * R1792 (0x700) - GPIO 1
+ */
+#define WM8996_GP1_DIR                          0x8000  /* GP1_DIR */
+#define WM8996_GP1_DIR_MASK                     0x8000  /* GP1_DIR */
+#define WM8996_GP1_DIR_SHIFT                        15  /* GP1_DIR */
+#define WM8996_GP1_DIR_WIDTH                         1  /* GP1_DIR */
+#define WM8996_GP1_PU                           0x4000  /* GP1_PU */
+#define WM8996_GP1_PU_MASK                      0x4000  /* GP1_PU */
+#define WM8996_GP1_PU_SHIFT                         14  /* GP1_PU */
+#define WM8996_GP1_PU_WIDTH                          1  /* GP1_PU */
+#define WM8996_GP1_PD                           0x2000  /* GP1_PD */
+#define WM8996_GP1_PD_MASK                      0x2000  /* GP1_PD */
+#define WM8996_GP1_PD_SHIFT                         13  /* GP1_PD */
+#define WM8996_GP1_PD_WIDTH                          1  /* GP1_PD */
+#define WM8996_GP1_POL                          0x0400  /* GP1_POL */
+#define WM8996_GP1_POL_MASK                     0x0400  /* GP1_POL */
+#define WM8996_GP1_POL_SHIFT                        10  /* GP1_POL */
+#define WM8996_GP1_POL_WIDTH                         1  /* GP1_POL */
+#define WM8996_GP1_OP_CFG                       0x0200  /* GP1_OP_CFG */
+#define WM8996_GP1_OP_CFG_MASK                  0x0200  /* GP1_OP_CFG */
+#define WM8996_GP1_OP_CFG_SHIFT                      9  /* GP1_OP_CFG */
+#define WM8996_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
+#define WM8996_GP1_DB                           0x0100  /* GP1_DB */
+#define WM8996_GP1_DB_MASK                      0x0100  /* GP1_DB */
+#define WM8996_GP1_DB_SHIFT                          8  /* GP1_DB */
+#define WM8996_GP1_DB_WIDTH                          1  /* GP1_DB */
+#define WM8996_GP1_LVL                          0x0040  /* GP1_LVL */
+#define WM8996_GP1_LVL_MASK                     0x0040  /* GP1_LVL */
+#define WM8996_GP1_LVL_SHIFT                         6  /* GP1_LVL */
+#define WM8996_GP1_LVL_WIDTH                         1  /* GP1_LVL */
+#define WM8996_GP1_FN_MASK                      0x000F  /* GP1_FN - [3:0] */
+#define WM8996_GP1_FN_SHIFT                          0  /* GP1_FN - [3:0] */
+#define WM8996_GP1_FN_WIDTH                          4  /* GP1_FN - [3:0] */
+
+/*
+ * R1793 (0x701) - GPIO 2
+ */
+#define WM8996_GP2_DIR                          0x8000  /* GP2_DIR */
+#define WM8996_GP2_DIR_MASK                     0x8000  /* GP2_DIR */
+#define WM8996_GP2_DIR_SHIFT                        15  /* GP2_DIR */
+#define WM8996_GP2_DIR_WIDTH                         1  /* GP2_DIR */
+#define WM8996_GP2_PU                           0x4000  /* GP2_PU */
+#define WM8996_GP2_PU_MASK                      0x4000  /* GP2_PU */
+#define WM8996_GP2_PU_SHIFT                         14  /* GP2_PU */
+#define WM8996_GP2_PU_WIDTH                          1  /* GP2_PU */
+#define WM8996_GP2_PD                           0x2000  /* GP2_PD */
+#define WM8996_GP2_PD_MASK                      0x2000  /* GP2_PD */
+#define WM8996_GP2_PD_SHIFT                         13  /* GP2_PD */
+#define WM8996_GP2_PD_WIDTH                          1  /* GP2_PD */
+#define WM8996_GP2_POL                          0x0400  /* GP2_POL */
+#define WM8996_GP2_POL_MASK                     0x0400  /* GP2_POL */
+#define WM8996_GP2_POL_SHIFT                        10  /* GP2_POL */
+#define WM8996_GP2_POL_WIDTH                         1  /* GP2_POL */
+#define WM8996_GP2_OP_CFG                       0x0200  /* GP2_OP_CFG */
+#define WM8996_GP2_OP_CFG_MASK                  0x0200  /* GP2_OP_CFG */
+#define WM8996_GP2_OP_CFG_SHIFT                      9  /* GP2_OP_CFG */
+#define WM8996_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
+#define WM8996_GP2_DB                           0x0100  /* GP2_DB */
+#define WM8996_GP2_DB_MASK                      0x0100  /* GP2_DB */
+#define WM8996_GP2_DB_SHIFT                          8  /* GP2_DB */
+#define WM8996_GP2_DB_WIDTH                          1  /* GP2_DB */
+#define WM8996_GP2_LVL                          0x0040  /* GP2_LVL */
+#define WM8996_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
+#define WM8996_GP2_LVL_SHIFT                         6  /* GP2_LVL */
+#define WM8996_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM8996_GP2_FN_MASK                      0x000F  /* GP2_FN - [3:0] */
+#define WM8996_GP2_FN_SHIFT                          0  /* GP2_FN - [3:0] */
+#define WM8996_GP2_FN_WIDTH                          4  /* GP2_FN - [3:0] */
+
+/*
+ * R1794 (0x702) - GPIO 3
+ */
+#define WM8996_GP3_DIR                          0x8000  /* GP3_DIR */
+#define WM8996_GP3_DIR_MASK                     0x8000  /* GP3_DIR */
+#define WM8996_GP3_DIR_SHIFT                        15  /* GP3_DIR */
+#define WM8996_GP3_DIR_WIDTH                         1  /* GP3_DIR */
+#define WM8996_GP3_PU                           0x4000  /* GP3_PU */
+#define WM8996_GP3_PU_MASK                      0x4000  /* GP3_PU */
+#define WM8996_GP3_PU_SHIFT                         14  /* GP3_PU */
+#define WM8996_GP3_PU_WIDTH                          1  /* GP3_PU */
+#define WM8996_GP3_PD                           0x2000  /* GP3_PD */
+#define WM8996_GP3_PD_MASK                      0x2000  /* GP3_PD */
+#define WM8996_GP3_PD_SHIFT                         13  /* GP3_PD */
+#define WM8996_GP3_PD_WIDTH                          1  /* GP3_PD */
+#define WM8996_GP3_POL                          0x0400  /* GP3_POL */
+#define WM8996_GP3_POL_MASK                     0x0400  /* GP3_POL */
+#define WM8996_GP3_POL_SHIFT                        10  /* GP3_POL */
+#define WM8996_GP3_POL_WIDTH                         1  /* GP3_POL */
+#define WM8996_GP3_OP_CFG                       0x0200  /* GP3_OP_CFG */
+#define WM8996_GP3_OP_CFG_MASK                  0x0200  /* GP3_OP_CFG */
+#define WM8996_GP3_OP_CFG_SHIFT                      9  /* GP3_OP_CFG */
+#define WM8996_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
+#define WM8996_GP3_DB                           0x0100  /* GP3_DB */
+#define WM8996_GP3_DB_MASK                      0x0100  /* GP3_DB */
+#define WM8996_GP3_DB_SHIFT                          8  /* GP3_DB */
+#define WM8996_GP3_DB_WIDTH                          1  /* GP3_DB */
+#define WM8996_GP3_LVL                          0x0040  /* GP3_LVL */
+#define WM8996_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
+#define WM8996_GP3_LVL_SHIFT                         6  /* GP3_LVL */
+#define WM8996_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM8996_GP3_FN_MASK                      0x000F  /* GP3_FN - [3:0] */
+#define WM8996_GP3_FN_SHIFT                          0  /* GP3_FN - [3:0] */
+#define WM8996_GP3_FN_WIDTH                          4  /* GP3_FN - [3:0] */
+
+/*
+ * R1795 (0x703) - GPIO 4
+ */
+#define WM8996_GP4_DIR                          0x8000  /* GP4_DIR */
+#define WM8996_GP4_DIR_MASK                     0x8000  /* GP4_DIR */
+#define WM8996_GP4_DIR_SHIFT                        15  /* GP4_DIR */
+#define WM8996_GP4_DIR_WIDTH                         1  /* GP4_DIR */
+#define WM8996_GP4_PU                           0x4000  /* GP4_PU */
+#define WM8996_GP4_PU_MASK                      0x4000  /* GP4_PU */
+#define WM8996_GP4_PU_SHIFT                         14  /* GP4_PU */
+#define WM8996_GP4_PU_WIDTH                          1  /* GP4_PU */
+#define WM8996_GP4_PD                           0x2000  /* GP4_PD */
+#define WM8996_GP4_PD_MASK                      0x2000  /* GP4_PD */
+#define WM8996_GP4_PD_SHIFT                         13  /* GP4_PD */
+#define WM8996_GP4_PD_WIDTH                          1  /* GP4_PD */
+#define WM8996_GP4_POL                          0x0400  /* GP4_POL */
+#define WM8996_GP4_POL_MASK                     0x0400  /* GP4_POL */
+#define WM8996_GP4_POL_SHIFT                        10  /* GP4_POL */
+#define WM8996_GP4_POL_WIDTH                         1  /* GP4_POL */
+#define WM8996_GP4_OP_CFG                       0x0200  /* GP4_OP_CFG */
+#define WM8996_GP4_OP_CFG_MASK                  0x0200  /* GP4_OP_CFG */
+#define WM8996_GP4_OP_CFG_SHIFT                      9  /* GP4_OP_CFG */
+#define WM8996_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
+#define WM8996_GP4_DB                           0x0100  /* GP4_DB */
+#define WM8996_GP4_DB_MASK                      0x0100  /* GP4_DB */
+#define WM8996_GP4_DB_SHIFT                          8  /* GP4_DB */
+#define WM8996_GP4_DB_WIDTH                          1  /* GP4_DB */
+#define WM8996_GP4_LVL                          0x0040  /* GP4_LVL */
+#define WM8996_GP4_LVL_MASK                     0x0040  /* GP4_LVL */
+#define WM8996_GP4_LVL_SHIFT                         6  /* GP4_LVL */
+#define WM8996_GP4_LVL_WIDTH                         1  /* GP4_LVL */
+#define WM8996_GP4_FN_MASK                      0x000F  /* GP4_FN - [3:0] */
+#define WM8996_GP4_FN_SHIFT                          0  /* GP4_FN - [3:0] */
+#define WM8996_GP4_FN_WIDTH                          4  /* GP4_FN - [3:0] */
+
+/*
+ * R1796 (0x704) - GPIO 5
+ */
+#define WM8996_GP5_DIR                          0x8000  /* GP5_DIR */
+#define WM8996_GP5_DIR_MASK                     0x8000  /* GP5_DIR */
+#define WM8996_GP5_DIR_SHIFT                        15  /* GP5_DIR */
+#define WM8996_GP5_DIR_WIDTH                         1  /* GP5_DIR */
+#define WM8996_GP5_PU                           0x4000  /* GP5_PU */
+#define WM8996_GP5_PU_MASK                      0x4000  /* GP5_PU */
+#define WM8996_GP5_PU_SHIFT                         14  /* GP5_PU */
+#define WM8996_GP5_PU_WIDTH                          1  /* GP5_PU */
+#define WM8996_GP5_PD                           0x2000  /* GP5_PD */
+#define WM8996_GP5_PD_MASK                      0x2000  /* GP5_PD */
+#define WM8996_GP5_PD_SHIFT                         13  /* GP5_PD */
+#define WM8996_GP5_PD_WIDTH                          1  /* GP5_PD */
+#define WM8996_GP5_POL                          0x0400  /* GP5_POL */
+#define WM8996_GP5_POL_MASK                     0x0400  /* GP5_POL */
+#define WM8996_GP5_POL_SHIFT                        10  /* GP5_POL */
+#define WM8996_GP5_POL_WIDTH                         1  /* GP5_POL */
+#define WM8996_GP5_OP_CFG                       0x0200  /* GP5_OP_CFG */
+#define WM8996_GP5_OP_CFG_MASK                  0x0200  /* GP5_OP_CFG */
+#define WM8996_GP5_OP_CFG_SHIFT                      9  /* GP5_OP_CFG */
+#define WM8996_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
+#define WM8996_GP5_DB                           0x0100  /* GP5_DB */
+#define WM8996_GP5_DB_MASK                      0x0100  /* GP5_DB */
+#define WM8996_GP5_DB_SHIFT                          8  /* GP5_DB */
+#define WM8996_GP5_DB_WIDTH                          1  /* GP5_DB */
+#define WM8996_GP5_LVL                          0x0040  /* GP5_LVL */
+#define WM8996_GP5_LVL_MASK                     0x0040  /* GP5_LVL */
+#define WM8996_GP5_LVL_SHIFT                         6  /* GP5_LVL */
+#define WM8996_GP5_LVL_WIDTH                         1  /* GP5_LVL */
+#define WM8996_GP5_FN_MASK                      0x000F  /* GP5_FN - [3:0] */
+#define WM8996_GP5_FN_SHIFT                          0  /* GP5_FN - [3:0] */
+#define WM8996_GP5_FN_WIDTH                          4  /* GP5_FN - [3:0] */
+
+/*
+ * R1824 (0x720) - Pull Control (1)
+ */
+#define WM8996_DMICDAT2_PD                      0x1000  /* DMICDAT2_PD */
+#define WM8996_DMICDAT2_PD_MASK                 0x1000  /* DMICDAT2_PD */
+#define WM8996_DMICDAT2_PD_SHIFT                    12  /* DMICDAT2_PD */
+#define WM8996_DMICDAT2_PD_WIDTH                     1  /* DMICDAT2_PD */
+#define WM8996_DMICDAT1_PD                      0x0400  /* DMICDAT1_PD */
+#define WM8996_DMICDAT1_PD_MASK                 0x0400  /* DMICDAT1_PD */
+#define WM8996_DMICDAT1_PD_SHIFT                    10  /* DMICDAT1_PD */
+#define WM8996_DMICDAT1_PD_WIDTH                     1  /* DMICDAT1_PD */
+#define WM8996_MCLK2_PU                         0x0200  /* MCLK2_PU */
+#define WM8996_MCLK2_PU_MASK                    0x0200  /* MCLK2_PU */
+#define WM8996_MCLK2_PU_SHIFT                        9  /* MCLK2_PU */
+#define WM8996_MCLK2_PU_WIDTH                        1  /* MCLK2_PU */
+#define WM8996_MCLK2_PD                         0x0100  /* MCLK2_PD */
+#define WM8996_MCLK2_PD_MASK                    0x0100  /* MCLK2_PD */
+#define WM8996_MCLK2_PD_SHIFT                        8  /* MCLK2_PD */
+#define WM8996_MCLK2_PD_WIDTH                        1  /* MCLK2_PD */
+#define WM8996_MCLK1_PU                         0x0080  /* MCLK1_PU */
+#define WM8996_MCLK1_PU_MASK                    0x0080  /* MCLK1_PU */
+#define WM8996_MCLK1_PU_SHIFT                        7  /* MCLK1_PU */
+#define WM8996_MCLK1_PU_WIDTH                        1  /* MCLK1_PU */
+#define WM8996_MCLK1_PD                         0x0040  /* MCLK1_PD */
+#define WM8996_MCLK1_PD_MASK                    0x0040  /* MCLK1_PD */
+#define WM8996_MCLK1_PD_SHIFT                        6  /* MCLK1_PD */
+#define WM8996_MCLK1_PD_WIDTH                        1  /* MCLK1_PD */
+#define WM8996_DACDAT1_PU                       0x0020  /* DACDAT1_PU */
+#define WM8996_DACDAT1_PU_MASK                  0x0020  /* DACDAT1_PU */
+#define WM8996_DACDAT1_PU_SHIFT                      5  /* DACDAT1_PU */
+#define WM8996_DACDAT1_PU_WIDTH                      1  /* DACDAT1_PU */
+#define WM8996_DACDAT1_PD                       0x0010  /* DACDAT1_PD */
+#define WM8996_DACDAT1_PD_MASK                  0x0010  /* DACDAT1_PD */
+#define WM8996_DACDAT1_PD_SHIFT                      4  /* DACDAT1_PD */
+#define WM8996_DACDAT1_PD_WIDTH                      1  /* DACDAT1_PD */
+#define WM8996_DACLRCLK1_PU                     0x0008  /* DACLRCLK1_PU */
+#define WM8996_DACLRCLK1_PU_MASK                0x0008  /* DACLRCLK1_PU */
+#define WM8996_DACLRCLK1_PU_SHIFT                    3  /* DACLRCLK1_PU */
+#define WM8996_DACLRCLK1_PU_WIDTH                    1  /* DACLRCLK1_PU */
+#define WM8996_DACLRCLK1_PD                     0x0004  /* DACLRCLK1_PD */
+#define WM8996_DACLRCLK1_PD_MASK                0x0004  /* DACLRCLK1_PD */
+#define WM8996_DACLRCLK1_PD_SHIFT                    2  /* DACLRCLK1_PD */
+#define WM8996_DACLRCLK1_PD_WIDTH                    1  /* DACLRCLK1_PD */
+#define WM8996_BCLK1_PU                         0x0002  /* BCLK1_PU */
+#define WM8996_BCLK1_PU_MASK                    0x0002  /* BCLK1_PU */
+#define WM8996_BCLK1_PU_SHIFT                        1  /* BCLK1_PU */
+#define WM8996_BCLK1_PU_WIDTH                        1  /* BCLK1_PU */
+#define WM8996_BCLK1_PD                         0x0001  /* BCLK1_PD */
+#define WM8996_BCLK1_PD_MASK                    0x0001  /* BCLK1_PD */
+#define WM8996_BCLK1_PD_SHIFT                        0  /* BCLK1_PD */
+#define WM8996_BCLK1_PD_WIDTH                        1  /* BCLK1_PD */
+
+/*
+ * R1825 (0x721) - Pull Control (2)
+ */
+#define WM8996_LDO1ENA_PD                       0x0100  /* LDO1ENA_PD */
+#define WM8996_LDO1ENA_PD_MASK                  0x0100  /* LDO1ENA_PD */
+#define WM8996_LDO1ENA_PD_SHIFT                      8  /* LDO1ENA_PD */
+#define WM8996_LDO1ENA_PD_WIDTH                      1  /* LDO1ENA_PD */
+#define WM8996_ADDR_PD                          0x0040  /* ADDR_PD */
+#define WM8996_ADDR_PD_MASK                     0x0040  /* ADDR_PD */
+#define WM8996_ADDR_PD_SHIFT                         6  /* ADDR_PD */
+#define WM8996_ADDR_PD_WIDTH                         1  /* ADDR_PD */
+#define WM8996_DACDAT2_PU                       0x0020  /* DACDAT2_PU */
+#define WM8996_DACDAT2_PU_MASK                  0x0020  /* DACDAT2_PU */
+#define WM8996_DACDAT2_PU_SHIFT                      5  /* DACDAT2_PU */
+#define WM8996_DACDAT2_PU_WIDTH                      1  /* DACDAT2_PU */
+#define WM8996_DACDAT2_PD                       0x0010  /* DACDAT2_PD */
+#define WM8996_DACDAT2_PD_MASK                  0x0010  /* DACDAT2_PD */
+#define WM8996_DACDAT2_PD_SHIFT                      4  /* DACDAT2_PD */
+#define WM8996_DACDAT2_PD_WIDTH                      1  /* DACDAT2_PD */
+#define WM8996_DACLRCLK2_PU                     0x0008  /* DACLRCLK2_PU */
+#define WM8996_DACLRCLK2_PU_MASK                0x0008  /* DACLRCLK2_PU */
+#define WM8996_DACLRCLK2_PU_SHIFT                    3  /* DACLRCLK2_PU */
+#define WM8996_DACLRCLK2_PU_WIDTH                    1  /* DACLRCLK2_PU */
+#define WM8996_DACLRCLK2_PD                     0x0004  /* DACLRCLK2_PD */
+#define WM8996_DACLRCLK2_PD_MASK                0x0004  /* DACLRCLK2_PD */
+#define WM8996_DACLRCLK2_PD_SHIFT                    2  /* DACLRCLK2_PD */
+#define WM8996_DACLRCLK2_PD_WIDTH                    1  /* DACLRCLK2_PD */
+#define WM8996_BCLK2_PU                         0x0002  /* BCLK2_PU */
+#define WM8996_BCLK2_PU_MASK                    0x0002  /* BCLK2_PU */
+#define WM8996_BCLK2_PU_SHIFT                        1  /* BCLK2_PU */
+#define WM8996_BCLK2_PU_WIDTH                        1  /* BCLK2_PU */
+#define WM8996_BCLK2_PD                         0x0001  /* BCLK2_PD */
+#define WM8996_BCLK2_PD_MASK                    0x0001  /* BCLK2_PD */
+#define WM8996_BCLK2_PD_SHIFT                        0  /* BCLK2_PD */
+#define WM8996_BCLK2_PD_WIDTH                        1  /* BCLK2_PD */
+
+/*
+ * R1840 (0x730) - Interrupt Status 1
+ */
+#define WM8996_GP5_EINT                         0x0010  /* GP5_EINT */
+#define WM8996_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
+#define WM8996_GP5_EINT_SHIFT                        4  /* GP5_EINT */
+#define WM8996_GP5_EINT_WIDTH                        1  /* GP5_EINT */
+#define WM8996_GP4_EINT                         0x0008  /* GP4_EINT */
+#define WM8996_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
+#define WM8996_GP4_EINT_SHIFT                        3  /* GP4_EINT */
+#define WM8996_GP4_EINT_WIDTH                        1  /* GP4_EINT */
+#define WM8996_GP3_EINT                         0x0004  /* GP3_EINT */
+#define WM8996_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
+#define WM8996_GP3_EINT_SHIFT                        2  /* GP3_EINT */
+#define WM8996_GP3_EINT_WIDTH                        1  /* GP3_EINT */
+#define WM8996_GP2_EINT                         0x0002  /* GP2_EINT */
+#define WM8996_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
+#define WM8996_GP2_EINT_SHIFT                        1  /* GP2_EINT */
+#define WM8996_GP2_EINT_WIDTH                        1  /* GP2_EINT */
+#define WM8996_GP1_EINT                         0x0001  /* GP1_EINT */
+#define WM8996_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
+#define WM8996_GP1_EINT_SHIFT                        0  /* GP1_EINT */
+#define WM8996_GP1_EINT_WIDTH                        1  /* GP1_EINT */
+
+/*
+ * R1841 (0x731) - Interrupt Status 2
+ */
+#define WM8996_DCS_DONE_23_EINT                 0x1000  /* DCS_DONE_23_EINT */
+#define WM8996_DCS_DONE_23_EINT_MASK            0x1000  /* DCS_DONE_23_EINT */
+#define WM8996_DCS_DONE_23_EINT_SHIFT               12  /* DCS_DONE_23_EINT */
+#define WM8996_DCS_DONE_23_EINT_WIDTH                1  /* DCS_DONE_23_EINT */
+#define WM8996_DCS_DONE_01_EINT                 0x0800  /* DCS_DONE_01_EINT */
+#define WM8996_DCS_DONE_01_EINT_MASK            0x0800  /* DCS_DONE_01_EINT */
+#define WM8996_DCS_DONE_01_EINT_SHIFT               11  /* DCS_DONE_01_EINT */
+#define WM8996_DCS_DONE_01_EINT_WIDTH                1  /* DCS_DONE_01_EINT */
+#define WM8996_WSEQ_DONE_EINT                   0x0400  /* WSEQ_DONE_EINT */
+#define WM8996_WSEQ_DONE_EINT_MASK              0x0400  /* WSEQ_DONE_EINT */
+#define WM8996_WSEQ_DONE_EINT_SHIFT                 10  /* WSEQ_DONE_EINT */
+#define WM8996_WSEQ_DONE_EINT_WIDTH                  1  /* WSEQ_DONE_EINT */
+#define WM8996_FIFOS_ERR_EINT                   0x0200  /* FIFOS_ERR_EINT */
+#define WM8996_FIFOS_ERR_EINT_MASK              0x0200  /* FIFOS_ERR_EINT */
+#define WM8996_FIFOS_ERR_EINT_SHIFT                  9  /* FIFOS_ERR_EINT */
+#define WM8996_FIFOS_ERR_EINT_WIDTH                  1  /* FIFOS_ERR_EINT */
+#define WM8996_DSP2DRC_SIG_DET_EINT             0x0080  /* DSP2DRC_SIG_DET_EINT */
+#define WM8996_DSP2DRC_SIG_DET_EINT_MASK        0x0080  /* DSP2DRC_SIG_DET_EINT */
+#define WM8996_DSP2DRC_SIG_DET_EINT_SHIFT            7  /* DSP2DRC_SIG_DET_EINT */
+#define WM8996_DSP2DRC_SIG_DET_EINT_WIDTH            1  /* DSP2DRC_SIG_DET_EINT */
+#define WM8996_DSP1DRC_SIG_DET_EINT             0x0040  /* DSP1DRC_SIG_DET_EINT */
+#define WM8996_DSP1DRC_SIG_DET_EINT_MASK        0x0040  /* DSP1DRC_SIG_DET_EINT */
+#define WM8996_DSP1DRC_SIG_DET_EINT_SHIFT            6  /* DSP1DRC_SIG_DET_EINT */
+#define WM8996_DSP1DRC_SIG_DET_EINT_WIDTH            1  /* DSP1DRC_SIG_DET_EINT */
+#define WM8996_FLL_SW_CLK_DONE_EINT             0x0008  /* FLL_SW_CLK_DONE_EINT */
+#define WM8996_FLL_SW_CLK_DONE_EINT_MASK        0x0008  /* FLL_SW_CLK_DONE_EINT */
+#define WM8996_FLL_SW_CLK_DONE_EINT_SHIFT            3  /* FLL_SW_CLK_DONE_EINT */
+#define WM8996_FLL_SW_CLK_DONE_EINT_WIDTH            1  /* FLL_SW_CLK_DONE_EINT */
+#define WM8996_FLL_LOCK_EINT                    0x0004  /* FLL_LOCK_EINT */
+#define WM8996_FLL_LOCK_EINT_MASK               0x0004  /* FLL_LOCK_EINT */
+#define WM8996_FLL_LOCK_EINT_SHIFT                   2  /* FLL_LOCK_EINT */
+#define WM8996_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM8996_HP_DONE_EINT                     0x0002  /* HP_DONE_EINT */
+#define WM8996_HP_DONE_EINT_MASK                0x0002  /* HP_DONE_EINT */
+#define WM8996_HP_DONE_EINT_SHIFT                    1  /* HP_DONE_EINT */
+#define WM8996_HP_DONE_EINT_WIDTH                    1  /* HP_DONE_EINT */
+#define WM8996_MICD_EINT                        0x0001  /* MICD_EINT */
+#define WM8996_MICD_EINT_MASK                   0x0001  /* MICD_EINT */
+#define WM8996_MICD_EINT_SHIFT                       0  /* MICD_EINT */
+#define WM8996_MICD_EINT_WIDTH                       1  /* MICD_EINT */
+
+/*
+ * R1842 (0x732) - Interrupt Raw Status 2
+ */
+#define WM8996_DCS_DONE_23_STS                  0x1000  /* DCS_DONE_23_STS */
+#define WM8996_DCS_DONE_23_STS_MASK             0x1000  /* DCS_DONE_23_STS */
+#define WM8996_DCS_DONE_23_STS_SHIFT                12  /* DCS_DONE_23_STS */
+#define WM8996_DCS_DONE_23_STS_WIDTH                 1  /* DCS_DONE_23_STS */
+#define WM8996_DCS_DONE_01_STS                  0x0800  /* DCS_DONE_01_STS */
+#define WM8996_DCS_DONE_01_STS_MASK             0x0800  /* DCS_DONE_01_STS */
+#define WM8996_DCS_DONE_01_STS_SHIFT                11  /* DCS_DONE_01_STS */
+#define WM8996_DCS_DONE_01_STS_WIDTH                 1  /* DCS_DONE_01_STS */
+#define WM8996_WSEQ_DONE_STS                    0x0400  /* WSEQ_DONE_STS */
+#define WM8996_WSEQ_DONE_STS_MASK               0x0400  /* WSEQ_DONE_STS */
+#define WM8996_WSEQ_DONE_STS_SHIFT                  10  /* WSEQ_DONE_STS */
+#define WM8996_WSEQ_DONE_STS_WIDTH                   1  /* WSEQ_DONE_STS */
+#define WM8996_FIFOS_ERR_STS                    0x0200  /* FIFOS_ERR_STS */
+#define WM8996_FIFOS_ERR_STS_MASK               0x0200  /* FIFOS_ERR_STS */
+#define WM8996_FIFOS_ERR_STS_SHIFT                   9  /* FIFOS_ERR_STS */
+#define WM8996_FIFOS_ERR_STS_WIDTH                   1  /* FIFOS_ERR_STS */
+#define WM8996_DSP2DRC_SIG_DET_STS              0x0080  /* DSP2DRC_SIG_DET_STS */
+#define WM8996_DSP2DRC_SIG_DET_STS_MASK         0x0080  /* DSP2DRC_SIG_DET_STS */
+#define WM8996_DSP2DRC_SIG_DET_STS_SHIFT             7  /* DSP2DRC_SIG_DET_STS */
+#define WM8996_DSP2DRC_SIG_DET_STS_WIDTH             1  /* DSP2DRC_SIG_DET_STS */
+#define WM8996_DSP1DRC_SIG_DET_STS              0x0040  /* DSP1DRC_SIG_DET_STS */
+#define WM8996_DSP1DRC_SIG_DET_STS_MASK         0x0040  /* DSP1DRC_SIG_DET_STS */
+#define WM8996_DSP1DRC_SIG_DET_STS_SHIFT             6  /* DSP1DRC_SIG_DET_STS */
+#define WM8996_DSP1DRC_SIG_DET_STS_WIDTH             1  /* DSP1DRC_SIG_DET_STS */
+#define WM8996_FLL_LOCK_STS                     0x0004  /* FLL_LOCK_STS */
+#define WM8996_FLL_LOCK_STS_MASK                0x0004  /* FLL_LOCK_STS */
+#define WM8996_FLL_LOCK_STS_SHIFT                    2  /* FLL_LOCK_STS */
+#define WM8996_FLL_LOCK_STS_WIDTH                    1  /* FLL_LOCK_STS */
+
+/*
+ * R1848 (0x738) - Interrupt Status 1 Mask
+ */
+#define WM8996_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
+#define WM8996_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
+#define WM8996_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
+#define WM8996_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
+#define WM8996_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
+#define WM8996_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
+#define WM8996_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
+#define WM8996_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
+#define WM8996_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
+#define WM8996_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
+#define WM8996_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
+#define WM8996_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
+#define WM8996_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
+#define WM8996_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
+#define WM8996_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
+#define WM8996_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
+#define WM8996_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
+#define WM8996_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
+#define WM8996_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
+#define WM8996_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
+
+/*
+ * R1849 (0x739) - Interrupt Status 2 Mask
+ */
+#define WM8996_IM_DCS_DONE_23_EINT              0x1000  /* IM_DCS_DONE_23_EINT */
+#define WM8996_IM_DCS_DONE_23_EINT_MASK         0x1000  /* IM_DCS_DONE_23_EINT */
+#define WM8996_IM_DCS_DONE_23_EINT_SHIFT            12  /* IM_DCS_DONE_23_EINT */
+#define WM8996_IM_DCS_DONE_23_EINT_WIDTH             1  /* IM_DCS_DONE_23_EINT */
+#define WM8996_IM_DCS_DONE_01_EINT              0x0800  /* IM_DCS_DONE_01_EINT */
+#define WM8996_IM_DCS_DONE_01_EINT_MASK         0x0800  /* IM_DCS_DONE_01_EINT */
+#define WM8996_IM_DCS_DONE_01_EINT_SHIFT            11  /* IM_DCS_DONE_01_EINT */
+#define WM8996_IM_DCS_DONE_01_EINT_WIDTH             1  /* IM_DCS_DONE_01_EINT */
+#define WM8996_IM_WSEQ_DONE_EINT                0x0400  /* IM_WSEQ_DONE_EINT */
+#define WM8996_IM_WSEQ_DONE_EINT_MASK           0x0400  /* IM_WSEQ_DONE_EINT */
+#define WM8996_IM_WSEQ_DONE_EINT_SHIFT              10  /* IM_WSEQ_DONE_EINT */
+#define WM8996_IM_WSEQ_DONE_EINT_WIDTH               1  /* IM_WSEQ_DONE_EINT */
+#define WM8996_IM_FIFOS_ERR_EINT                0x0200  /* IM_FIFOS_ERR_EINT */
+#define WM8996_IM_FIFOS_ERR_EINT_MASK           0x0200  /* IM_FIFOS_ERR_EINT */
+#define WM8996_IM_FIFOS_ERR_EINT_SHIFT               9  /* IM_FIFOS_ERR_EINT */
+#define WM8996_IM_FIFOS_ERR_EINT_WIDTH               1  /* IM_FIFOS_ERR_EINT */
+#define WM8996_IM_DSP2DRC_SIG_DET_EINT          0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP2DRC_SIG_DET_EINT_MASK     0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP2DRC_SIG_DET_EINT_SHIFT         7  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP2DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP1DRC_SIG_DET_EINT          0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP1DRC_SIG_DET_EINT_MASK     0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP1DRC_SIG_DET_EINT_SHIFT         6  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP1DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8996_IM_FLL_SW_CLK_DONE_EINT          0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8996_IM_FLL_SW_CLK_DONE_EINT_MASK     0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8996_IM_FLL_SW_CLK_DONE_EINT_SHIFT         3  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8996_IM_FLL_SW_CLK_DONE_EINT_WIDTH         1  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8996_IM_FLL_LOCK_EINT                 0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8996_IM_FLL_LOCK_EINT_MASK            0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8996_IM_FLL_LOCK_EINT_SHIFT                2  /* IM_FLL_LOCK_EINT */
+#define WM8996_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM8996_IM_HP_DONE_EINT                  0x0002  /* IM_HP_DONE_EINT */
+#define WM8996_IM_HP_DONE_EINT_MASK             0x0002  /* IM_HP_DONE_EINT */
+#define WM8996_IM_HP_DONE_EINT_SHIFT                 1  /* IM_HP_DONE_EINT */
+#define WM8996_IM_HP_DONE_EINT_WIDTH                 1  /* IM_HP_DONE_EINT */
+#define WM8996_IM_MICD_EINT                     0x0001  /* IM_MICD_EINT */
+#define WM8996_IM_MICD_EINT_MASK                0x0001  /* IM_MICD_EINT */
+#define WM8996_IM_MICD_EINT_SHIFT                    0  /* IM_MICD_EINT */
+#define WM8996_IM_MICD_EINT_WIDTH                    1  /* IM_MICD_EINT */
+
+/*
+ * R1856 (0x740) - Interrupt Control
+ */
+#define WM8996_IM_IRQ                           0x0001  /* IM_IRQ */
+#define WM8996_IM_IRQ_MASK                      0x0001  /* IM_IRQ */
+#define WM8996_IM_IRQ_SHIFT                          0  /* IM_IRQ */
+#define WM8996_IM_IRQ_WIDTH                          1  /* IM_IRQ */
+
+/*
+ * R2048 (0x800) - Left PDM Speaker
+ */
+#define WM8996_SPKL_ENA                         0x0010  /* SPKL_ENA */
+#define WM8996_SPKL_ENA_MASK                    0x0010  /* SPKL_ENA */
+#define WM8996_SPKL_ENA_SHIFT                        4  /* SPKL_ENA */
+#define WM8996_SPKL_ENA_WIDTH                        1  /* SPKL_ENA */
+#define WM8996_SPKL_MUTE                        0x0008  /* SPKL_MUTE */
+#define WM8996_SPKL_MUTE_MASK                   0x0008  /* SPKL_MUTE */
+#define WM8996_SPKL_MUTE_SHIFT                       3  /* SPKL_MUTE */
+#define WM8996_SPKL_MUTE_WIDTH                       1  /* SPKL_MUTE */
+#define WM8996_SPKL_MUTE_ZC                     0x0004  /* SPKL_MUTE_ZC */
+#define WM8996_SPKL_MUTE_ZC_MASK                0x0004  /* SPKL_MUTE_ZC */
+#define WM8996_SPKL_MUTE_ZC_SHIFT                    2  /* SPKL_MUTE_ZC */
+#define WM8996_SPKL_MUTE_ZC_WIDTH                    1  /* SPKL_MUTE_ZC */
+#define WM8996_SPKL_SRC_MASK                    0x0003  /* SPKL_SRC - [1:0] */
+#define WM8996_SPKL_SRC_SHIFT                        0  /* SPKL_SRC - [1:0] */
+#define WM8996_SPKL_SRC_WIDTH                        2  /* SPKL_SRC - [1:0] */
+
+/*
+ * R2049 (0x801) - Right PDM Speaker
+ */
+#define WM8996_SPKR_ENA                         0x0010  /* SPKR_ENA */
+#define WM8996_SPKR_ENA_MASK                    0x0010  /* SPKR_ENA */
+#define WM8996_SPKR_ENA_SHIFT                        4  /* SPKR_ENA */
+#define WM8996_SPKR_ENA_WIDTH                        1  /* SPKR_ENA */
+#define WM8996_SPKR_MUTE                        0x0008  /* SPKR_MUTE */
+#define WM8996_SPKR_MUTE_MASK                   0x0008  /* SPKR_MUTE */
+#define WM8996_SPKR_MUTE_SHIFT                       3  /* SPKR_MUTE */
+#define WM8996_SPKR_MUTE_WIDTH                       1  /* SPKR_MUTE */
+#define WM8996_SPKR_MUTE_ZC                     0x0004  /* SPKR_MUTE_ZC */
+#define WM8996_SPKR_MUTE_ZC_MASK                0x0004  /* SPKR_MUTE_ZC */
+#define WM8996_SPKR_MUTE_ZC_SHIFT                    2  /* SPKR_MUTE_ZC */
+#define WM8996_SPKR_MUTE_ZC_WIDTH                    1  /* SPKR_MUTE_ZC */
+#define WM8996_SPKR_SRC_MASK                    0x0003  /* SPKR_SRC - [1:0] */
+#define WM8996_SPKR_SRC_SHIFT                        0  /* SPKR_SRC - [1:0] */
+#define WM8996_SPKR_SRC_WIDTH                        2  /* SPKR_SRC - [1:0] */
+
+/*
+ * R2050 (0x802) - PDM Speaker Mute Sequence
+ */
+#define WM8996_SPK_MUTE_ENDIAN                  0x0100  /* SPK_MUTE_ENDIAN */
+#define WM8996_SPK_MUTE_ENDIAN_MASK             0x0100  /* SPK_MUTE_ENDIAN */
+#define WM8996_SPK_MUTE_ENDIAN_SHIFT                 8  /* SPK_MUTE_ENDIAN */
+#define WM8996_SPK_MUTE_ENDIAN_WIDTH                 1  /* SPK_MUTE_ENDIAN */
+#define WM8996_SPK_MUTE_SEQ1_MASK               0x00FF  /* SPK_MUTE_SEQ1 - [7:0] */
+#define WM8996_SPK_MUTE_SEQ1_SHIFT                   0  /* SPK_MUTE_SEQ1 - [7:0] */
+#define WM8996_SPK_MUTE_SEQ1_WIDTH                   8  /* SPK_MUTE_SEQ1 - [7:0] */
+
+/*
+ * R2051 (0x803) - PDM Speaker Volume
+ */
+#define WM8996_SPKR_VOL_MASK                    0x00F0  /* SPKR_VOL - [7:4] */
+#define WM8996_SPKR_VOL_SHIFT                        4  /* SPKR_VOL - [7:4] */
+#define WM8996_SPKR_VOL_WIDTH                        4  /* SPKR_VOL - [7:4] */
+#define WM8996_SPKL_VOL_MASK                    0x000F  /* SPKL_VOL - [3:0] */
+#define WM8996_SPKL_VOL_SHIFT                        0  /* SPKL_VOL - [3:0] */
+#define WM8996_SPKL_VOL_WIDTH                        4  /* SPKL_VOL - [3:0] */
+
+#endif
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
new file mode 100644
index 0000000..df5b36b
--- /dev/null
+++ b/sound/soc/codecs/wm8997.c
@@ -0,0 +1,1214 @@
+/*
+ * wm8997.c  --  WM8997 ALSA SoC Audio driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+#include "wm8997.h"
+
+struct wm8997_priv {
+	struct arizona_priv core;
+	struct arizona_fll fll[2];
+};
+
+static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
+static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
+
+static const struct reg_default wm8997_sysclk_reva_patch[] = {
+	{ 0x301D, 0x7B15 },
+	{ 0x301B, 0x0050 },
+	{ 0x305D, 0x7B17 },
+	{ 0x305B, 0x0050 },
+	{ 0x3001, 0x08FE },
+	{ 0x3003, 0x00F4 },
+	{ 0x3041, 0x08FF },
+	{ 0x3043, 0x0005 },
+	{ 0x3020, 0x0225 },
+	{ 0x3021, 0x0A00 },
+	{ 0x3022, 0xE24D },
+	{ 0x3023, 0x0800 },
+	{ 0x3024, 0xE24D },
+	{ 0x3025, 0xF000 },
+	{ 0x3060, 0x0226 },
+	{ 0x3061, 0x0A00 },
+	{ 0x3062, 0xE252 },
+	{ 0x3063, 0x0800 },
+	{ 0x3064, 0xE252 },
+	{ 0x3065, 0xF000 },
+	{ 0x3116, 0x022B },
+	{ 0x3117, 0xFA00 },
+	{ 0x3110, 0x246C },
+	{ 0x3111, 0x0A03 },
+	{ 0x3112, 0x246E },
+	{ 0x3113, 0x0A03 },
+	{ 0x3114, 0x2470 },
+	{ 0x3115, 0x0A03 },
+	{ 0x3126, 0x246C },
+	{ 0x3127, 0x0A02 },
+	{ 0x3128, 0x246E },
+	{ 0x3129, 0x0A02 },
+	{ 0x312A, 0x2470 },
+	{ 0x312B, 0xFA02 },
+	{ 0x3125, 0x0800 },
+};
+
+static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+	struct regmap *regmap = arizona->regmap;
+	const struct reg_default *patch = NULL;
+	int i, patch_size;
+
+	switch (arizona->rev) {
+	case 0:
+		patch = wm8997_sysclk_reva_patch;
+		patch_size = ARRAY_SIZE(wm8997_sysclk_reva_patch);
+		break;
+	default:
+		break;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (patch)
+			for (i = 0; i < patch_size; i++)
+				regmap_write_async(regmap, patch[i].reg,
+						   patch[i].def);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		break;
+	case SND_SOC_DAPM_PRE_PMU:
+	case SND_SOC_DAPM_POST_PMD:
+		return arizona_clk_ev(w, kcontrol, event);
+	default:
+		return 0;
+	}
+
+	return arizona_dvfs_sysclk_ev(w, kcontrol, event);
+}
+
+static const char * const wm8997_osr_text[] = {
+	"Low power", "Normal", "High performance",
+};
+
+static const unsigned int wm8997_osr_val[] = {
+	0x0, 0x3, 0x5,
+};
+
+static const struct soc_enum wm8997_hpout_osr[] = {
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
+			      ARIZONA_OUT1_OSR_SHIFT, 0x7,
+			      ARRAY_SIZE(wm8997_osr_text),
+			      wm8997_osr_text, wm8997_osr_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
+			      ARIZONA_OUT3_OSR_SHIFT, 0x7,
+			      ARRAY_SIZE(wm8997_osr_text),
+			      wm8997_osr_text, wm8997_osr_val),
+};
+
+#define WM8997_NG_SRC(name, base) \
+	SOC_SINGLE(name " NG HPOUT1L Switch",  base, 0, 1, 0), \
+	SOC_SINGLE(name " NG HPOUT1R Switch",  base, 1, 1, 0), \
+	SOC_SINGLE(name " NG EPOUT Switch",    base, 4, 1, 0), \
+	SOC_SINGLE(name " NG SPKOUT Switch",   base, 6, 1, 0), \
+	SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \
+	SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0)
+
+static const struct snd_kcontrol_new wm8997_snd_controls[] = {
+SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL,
+	   ARIZONA_IN1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL,
+	   ARIZONA_IN2_OSR_SHIFT, 1, 0),
+
+SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
+		     ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
+		     ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL,
+		     ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL,
+		     ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+
+SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
+	       ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
+	       ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
+	       ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R,
+	       ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+
+SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
+SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
+
+ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
+
+ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2),
+SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2),
+SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_EQ_CONTROL("EQ3 Coefficients", ARIZONA_EQ3_2),
+SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B3 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_EQ_CONTROL("EQ4 Coefficients", ARIZONA_EQ4_2),
+SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B3 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B4 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B5 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
+		   ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
+
+ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
+
+SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
+SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
+SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
+SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
+
+ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2),
+ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
+ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
+ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2),
+
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+
+ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR,
+	       ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv),
+
+ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUT", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L,
+	   ARIZONA_OUT4_OSR_SHIFT, 1, 0),
+SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,
+	   ARIZONA_OUT5_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	   ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
+SOC_SINGLE("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	   ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKDAT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	       ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	       ARIZONA_OUT4L_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+
+SOC_ENUM("HPOUT1 OSR", wm8997_hpout_osr[0]),
+SOC_ENUM("EPOUT OSR", wm8997_hpout_osr[1]),
+
+SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
+SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
+
+SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
+	   ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
+
+SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
+	   ARIZONA_NGATE_ENA_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
+	       ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
+SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
+
+WM8997_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L),
+WM8997_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R),
+WM8997_NG_SRC("EPOUT", ARIZONA_NOISE_GATE_SELECT_3L),
+WM8997_NG_SRC("SPKOUT", ARIZONA_NOISE_GATE_SELECT_4L),
+WM8997_NG_SRC("SPKDAT1L", ARIZONA_NOISE_GATE_SELECT_5L),
+WM8997_NG_SRC("SPKDAT1R", ARIZONA_NOISE_GATE_SELECT_5R),
+
+ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("SLIMTX1", ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX2", ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX3", ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX4", ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
+};
+
+ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ4, ARIZONA_EQ4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT3, ARIZONA_OUT3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUT, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDAT1L, ARIZONA_OUT5LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDAT1R, ARIZONA_OUT5RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(SLIMTX1, ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX2, ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX3, ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX4, ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX5, ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX6, ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX7, ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX8, ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
+
+static const char *wm8997_aec_loopback_texts[] = {
+	"HPOUT1L", "HPOUT1R", "EPOUT", "SPKOUT", "SPKDAT1L", "SPKDAT1R",
+};
+
+static const unsigned int wm8997_aec_loopback_values[] = {
+	0, 1, 4, 6, 8, 9,
+};
+
+static const struct soc_enum wm8997_aec_loopback =
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
+			      ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+			      ARRAY_SIZE(wm8997_aec_loopback_texts),
+			      wm8997_aec_loopback_texts,
+			      wm8997_aec_loopback_values);
+
+static const struct snd_kcontrol_new wm8997_aec_loopback_mux =
+	SOC_DAPM_ENUM("AEC Loopback", wm8997_aec_loopback);
+
+static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
+		    0, wm8997_sysclk_ev,
+		    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
+		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+		    ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDD", 0, 0),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_SIGGEN("NOISE"),
+SND_SOC_DAPM_SIGGEN("HAPTICS"),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2,
+		    ARIZONA_MICB2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3,
+		    ARIZONA_MICB3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR,
+		 ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Mic Mute Mixer", ARIZONA_MIC_NOISE_MIX_CONTROL_1,
+		 ARIZONA_MICMUTE_MIX_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ3", ARIZONA_EQ3_1, ARIZONA_EQ3_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ4", ARIZONA_EQ4_1, ARIZONA_EQ4_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT,
+		 0, NULL, 0),
+SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT,
+		 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+		 ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &wm8997_aec_loopback_mux),
+
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+		   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+		   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT5R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"),
+ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"),
+ARIZONA_MIXER_WIDGETS(EQ3, "EQ3"),
+ARIZONA_MIXER_WIDGETS(EQ4, "EQ4"),
+
+ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"),
+ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"),
+
+ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
+ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
+ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"),
+ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+ARIZONA_MIXER_WIDGETS(Mic, "Mic"),
+ARIZONA_MIXER_WIDGETS(Noise, "Noise"),
+
+ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"),
+ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"),
+
+ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),
+ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),
+ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"),
+ARIZONA_MIXER_WIDGETS(SPKOUT, "SPKOUT"),
+ARIZONA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"),
+ARIZONA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"),
+
+ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
+ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
+
+ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
+ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+
+ARIZONA_MIXER_WIDGETS(SLIMTX1, "SLIMTX1"),
+ARIZONA_MIXER_WIDGETS(SLIMTX2, "SLIMTX2"),
+ARIZONA_MIXER_WIDGETS(SLIMTX3, "SLIMTX3"),
+ARIZONA_MIXER_WIDGETS(SLIMTX4, "SLIMTX4"),
+ARIZONA_MIXER_WIDGETS(SLIMTX5, "SLIMTX5"),
+ARIZONA_MIXER_WIDGETS(SLIMTX6, "SLIMTX6"),
+ARIZONA_MIXER_WIDGETS(SLIMTX7, "SLIMTX7"),
+ARIZONA_MIXER_WIDGETS(SLIMTX8, "SLIMTX8"),
+
+ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
+
+ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
+ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
+
+ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
+
+ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
+ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("EPOUTN"),
+SND_SOC_DAPM_OUTPUT("EPOUTP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+SND_SOC_DAPM_OUTPUT("SPKDAT1L"),
+SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
+
+SND_SOC_DAPM_OUTPUT("MICSUPP"),
+};
+
+#define ARIZONA_MIXER_INPUT_ROUTES(name)	\
+	{ name, "Noise Generator", "Noise Generator" }, \
+	{ name, "Tone Generator 1", "Tone Generator 1" }, \
+	{ name, "Tone Generator 2", "Tone Generator 2" }, \
+	{ name, "Haptics", "HAPTICS" }, \
+	{ name, "AEC", "AEC Loopback" }, \
+	{ name, "IN1L", "IN1L PGA" }, \
+	{ name, "IN1R", "IN1R PGA" }, \
+	{ name, "IN2L", "IN2L PGA" }, \
+	{ name, "IN2R", "IN2R PGA" }, \
+	{ name, "Mic Mute Mixer", "Mic Mute Mixer" }, \
+	{ name, "AIF1RX1", "AIF1RX1" }, \
+	{ name, "AIF1RX2", "AIF1RX2" }, \
+	{ name, "AIF1RX3", "AIF1RX3" }, \
+	{ name, "AIF1RX4", "AIF1RX4" }, \
+	{ name, "AIF1RX5", "AIF1RX5" }, \
+	{ name, "AIF1RX6", "AIF1RX6" }, \
+	{ name, "AIF1RX7", "AIF1RX7" }, \
+	{ name, "AIF1RX8", "AIF1RX8" }, \
+	{ name, "AIF2RX1", "AIF2RX1" }, \
+	{ name, "AIF2RX2", "AIF2RX2" }, \
+	{ name, "SLIMRX1", "SLIMRX1" }, \
+	{ name, "SLIMRX2", "SLIMRX2" }, \
+	{ name, "SLIMRX3", "SLIMRX3" }, \
+	{ name, "SLIMRX4", "SLIMRX4" }, \
+	{ name, "SLIMRX5", "SLIMRX5" }, \
+	{ name, "SLIMRX6", "SLIMRX6" }, \
+	{ name, "SLIMRX7", "SLIMRX7" }, \
+	{ name, "SLIMRX8", "SLIMRX8" }, \
+	{ name, "EQ1", "EQ1" }, \
+	{ name, "EQ2", "EQ2" }, \
+	{ name, "EQ3", "EQ3" }, \
+	{ name, "EQ4", "EQ4" }, \
+	{ name, "DRC1L", "DRC1L" }, \
+	{ name, "DRC1R", "DRC1R" }, \
+	{ name, "LHPF1", "LHPF1" }, \
+	{ name, "LHPF2", "LHPF2" }, \
+	{ name, "LHPF3", "LHPF3" }, \
+	{ name, "LHPF4", "LHPF4" }, \
+	{ name, "ISRC1DEC1", "ISRC1DEC1" }, \
+	{ name, "ISRC1DEC2", "ISRC1DEC2" }, \
+	{ name, "ISRC1INT1", "ISRC1INT1" }, \
+	{ name, "ISRC1INT2", "ISRC1INT2" }, \
+	{ name, "ISRC2DEC1", "ISRC2DEC1" }, \
+	{ name, "ISRC2DEC2", "ISRC2DEC2" }, \
+	{ name, "ISRC2INT1", "ISRC2INT1" }, \
+	{ name, "ISRC2INT2", "ISRC2INT2" }
+
+static const struct snd_soc_dapm_route wm8997_dapm_routes[] = {
+	{ "AIF2 Capture", NULL, "DBVDD2" },
+	{ "AIF2 Playback", NULL, "DBVDD2" },
+
+	{ "OUT1L", NULL, "CPVDD" },
+	{ "OUT1R", NULL, "CPVDD" },
+	{ "OUT3L", NULL, "CPVDD" },
+
+	{ "OUT4L", NULL, "SPKVDD" },
+
+	{ "OUT1L", NULL, "SYSCLK" },
+	{ "OUT1R", NULL, "SYSCLK" },
+	{ "OUT3L", NULL, "SYSCLK" },
+	{ "OUT4L", NULL, "SYSCLK" },
+
+	{ "IN1L", NULL, "SYSCLK" },
+	{ "IN1R", NULL, "SYSCLK" },
+	{ "IN2L", NULL, "SYSCLK" },
+	{ "IN2R", NULL, "SYSCLK" },
+
+	{ "MICBIAS1", NULL, "MICVDD" },
+	{ "MICBIAS2", NULL, "MICVDD" },
+	{ "MICBIAS3", NULL, "MICVDD" },
+
+	{ "Noise Generator", NULL, "SYSCLK" },
+	{ "Tone Generator 1", NULL, "SYSCLK" },
+	{ "Tone Generator 2", NULL, "SYSCLK" },
+
+	{ "Noise Generator", NULL, "NOISE" },
+	{ "Tone Generator 1", NULL, "TONE" },
+	{ "Tone Generator 2", NULL, "TONE" },
+
+	{ "AIF1 Capture", NULL, "AIF1TX1" },
+	{ "AIF1 Capture", NULL, "AIF1TX2" },
+	{ "AIF1 Capture", NULL, "AIF1TX3" },
+	{ "AIF1 Capture", NULL, "AIF1TX4" },
+	{ "AIF1 Capture", NULL, "AIF1TX5" },
+	{ "AIF1 Capture", NULL, "AIF1TX6" },
+	{ "AIF1 Capture", NULL, "AIF1TX7" },
+	{ "AIF1 Capture", NULL, "AIF1TX8" },
+
+	{ "AIF1RX1", NULL, "AIF1 Playback" },
+	{ "AIF1RX2", NULL, "AIF1 Playback" },
+	{ "AIF1RX3", NULL, "AIF1 Playback" },
+	{ "AIF1RX4", NULL, "AIF1 Playback" },
+	{ "AIF1RX5", NULL, "AIF1 Playback" },
+	{ "AIF1RX6", NULL, "AIF1 Playback" },
+	{ "AIF1RX7", NULL, "AIF1 Playback" },
+	{ "AIF1RX8", NULL, "AIF1 Playback" },
+
+	{ "AIF2 Capture", NULL, "AIF2TX1" },
+	{ "AIF2 Capture", NULL, "AIF2TX2" },
+
+	{ "AIF2RX1", NULL, "AIF2 Playback" },
+	{ "AIF2RX2", NULL, "AIF2 Playback" },
+
+	{ "Slim1 Capture", NULL, "SLIMTX1" },
+	{ "Slim1 Capture", NULL, "SLIMTX2" },
+	{ "Slim1 Capture", NULL, "SLIMTX3" },
+	{ "Slim1 Capture", NULL, "SLIMTX4" },
+
+	{ "SLIMRX1", NULL, "Slim1 Playback" },
+	{ "SLIMRX2", NULL, "Slim1 Playback" },
+	{ "SLIMRX3", NULL, "Slim1 Playback" },
+	{ "SLIMRX4", NULL, "Slim1 Playback" },
+
+	{ "Slim2 Capture", NULL, "SLIMTX5" },
+	{ "Slim2 Capture", NULL, "SLIMTX6" },
+
+	{ "SLIMRX5", NULL, "Slim2 Playback" },
+	{ "SLIMRX6", NULL, "Slim2 Playback" },
+
+	{ "Slim3 Capture", NULL, "SLIMTX7" },
+	{ "Slim3 Capture", NULL, "SLIMTX8" },
+
+	{ "SLIMRX7", NULL, "Slim3 Playback" },
+	{ "SLIMRX8", NULL, "Slim3 Playback" },
+
+	{ "AIF1 Playback", NULL, "SYSCLK" },
+	{ "AIF2 Playback", NULL, "SYSCLK" },
+	{ "Slim1 Playback", NULL, "SYSCLK" },
+	{ "Slim2 Playback", NULL, "SYSCLK" },
+	{ "Slim3 Playback", NULL, "SYSCLK" },
+
+	{ "AIF1 Capture", NULL, "SYSCLK" },
+	{ "AIF2 Capture", NULL, "SYSCLK" },
+	{ "Slim1 Capture", NULL, "SYSCLK" },
+	{ "Slim2 Capture", NULL, "SYSCLK" },
+	{ "Slim3 Capture", NULL, "SYSCLK" },
+
+	{ "IN1L PGA", NULL, "IN1L" },
+	{ "IN1R PGA", NULL, "IN1R" },
+
+	{ "IN2L PGA", NULL, "IN2L" },
+	{ "IN2R PGA", NULL, "IN2R" },
+
+	ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
+	ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
+	ARIZONA_MIXER_ROUTES("OUT3L", "EPOUT"),
+
+	ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUT"),
+	ARIZONA_MIXER_ROUTES("OUT5L", "SPKDAT1L"),
+	ARIZONA_MIXER_ROUTES("OUT5R", "SPKDAT1R"),
+
+	ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"),
+	ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"),
+
+	ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+	ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+	ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+	ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+	ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+	ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+	ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
+	ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
+
+	ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
+	ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+
+	ARIZONA_MIXER_ROUTES("SLIMTX1", "SLIMTX1"),
+	ARIZONA_MIXER_ROUTES("SLIMTX2", "SLIMTX2"),
+	ARIZONA_MIXER_ROUTES("SLIMTX3", "SLIMTX3"),
+	ARIZONA_MIXER_ROUTES("SLIMTX4", "SLIMTX4"),
+	ARIZONA_MIXER_ROUTES("SLIMTX5", "SLIMTX5"),
+	ARIZONA_MIXER_ROUTES("SLIMTX6", "SLIMTX6"),
+	ARIZONA_MIXER_ROUTES("SLIMTX7", "SLIMTX7"),
+	ARIZONA_MIXER_ROUTES("SLIMTX8", "SLIMTX8"),
+
+	ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
+	ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
+	ARIZONA_MIXER_ROUTES("EQ3", "EQ3"),
+	ARIZONA_MIXER_ROUTES("EQ4", "EQ4"),
+
+	ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"),
+	ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"),
+
+	ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
+	ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
+	ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
+	ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+	ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Noise"),
+	ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Mic"),
+
+	ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+	ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+
+	ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+
+	ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+	ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+
+	ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+
+	{ "AEC Loopback", "HPOUT1L", "OUT1L" },
+	{ "AEC Loopback", "HPOUT1R", "OUT1R" },
+	{ "HPOUT1L", NULL, "OUT1L" },
+	{ "HPOUT1R", NULL, "OUT1R" },
+
+	{ "AEC Loopback", "EPOUT", "OUT3L" },
+	{ "EPOUTN", NULL, "OUT3L" },
+	{ "EPOUTP", NULL, "OUT3L" },
+
+	{ "AEC Loopback", "SPKOUT", "OUT4L" },
+	{ "SPKOUTN", NULL, "OUT4L" },
+	{ "SPKOUTP", NULL, "OUT4L" },
+
+	{ "AEC Loopback", "SPKDAT1L", "OUT5L" },
+	{ "AEC Loopback", "SPKDAT1R", "OUT5R" },
+	{ "SPKDAT1L", NULL, "OUT5L" },
+	{ "SPKDAT1R", NULL, "OUT5R" },
+
+	{ "MICSUPP", NULL, "SYSCLK" },
+};
+
+static int wm8997_set_fll(struct snd_soc_component *component, int fll_id,
+			  int source, unsigned int Fref, unsigned int Fout)
+{
+	struct wm8997_priv *wm8997 = snd_soc_component_get_drvdata(component);
+
+	switch (fll_id) {
+	case WM8997_FLL1:
+		return arizona_set_fll(&wm8997->fll[0], source, Fref, Fout);
+	case WM8997_FLL2:
+		return arizona_set_fll(&wm8997->fll[1], source, Fref, Fout);
+	case WM8997_FLL1_REFCLK:
+		return arizona_set_fll_refclk(&wm8997->fll[0], source, Fref,
+					      Fout);
+	case WM8997_FLL2_REFCLK:
+		return arizona_set_fll_refclk(&wm8997->fll[1], source, Fref,
+					      Fout);
+	default:
+		return -EINVAL;
+	}
+}
+
+#define WM8997_RATES SNDRV_PCM_RATE_KNOT
+
+#define WM8997_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm8997_dai[] = {
+	{
+		.name = "wm8997-aif1",
+		.id = 1,
+		.base = ARIZONA_AIF1_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 8,
+			 .rates = WM8997_RATES,
+			 .formats = WM8997_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "wm8997-aif2",
+		.id = 2,
+		.base = ARIZONA_AIF2_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM8997_RATES,
+			 .formats = WM8997_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "wm8997-slim1",
+		.id = 3,
+		.playback = {
+			.stream_name = "Slim1 Playback",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Slim1 Capture",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.ops = &arizona_simple_dai_ops,
+	},
+	{
+		.name = "wm8997-slim2",
+		.id = 4,
+		.playback = {
+			.stream_name = "Slim2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Slim2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.ops = &arizona_simple_dai_ops,
+	},
+	{
+		.name = "wm8997-slim3",
+		.id = 5,
+		.playback = {
+			.stream_name = "Slim3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Slim3 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.ops = &arizona_simple_dai_ops,
+	},
+};
+
+static int wm8997_component_probe(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8997_priv *priv = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = priv->core.arizona;
+	int ret;
+
+	snd_soc_component_init_regmap(component, arizona->regmap);
+
+	ret = arizona_init_spk(component);
+	if (ret < 0)
+		return ret;
+
+	snd_soc_component_disable_pin(component, "HAPTICS");
+
+	priv->core.arizona->dapm = dapm;
+
+	return 0;
+}
+
+static void wm8997_component_remove(struct snd_soc_component *component)
+{
+	struct wm8997_priv *priv = snd_soc_component_get_drvdata(component);
+
+	priv->core.arizona->dapm = NULL;
+}
+
+#define WM8997_DIG_VU 0x0200
+
+static unsigned int wm8997_digital_vu[] = {
+	ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	ARIZONA_DAC_DIGITAL_VOLUME_1R,
+	ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	ARIZONA_DAC_DIGITAL_VOLUME_5L,
+	ARIZONA_DAC_DIGITAL_VOLUME_5R,
+};
+
+static const struct snd_soc_component_driver soc_component_dev_wm8997 = {
+	.probe			= wm8997_component_probe,
+	.remove			= wm8997_component_remove,
+	.set_sysclk		= arizona_set_sysclk,
+	.set_pll		= wm8997_set_fll,
+	.controls		= wm8997_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8997_snd_controls),
+	.dapm_widgets		= wm8997_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8997_dapm_widgets),
+	.dapm_routes		= wm8997_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8997_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm8997_probe(struct platform_device *pdev)
+{
+	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+	struct wm8997_priv *wm8997;
+	int i, ret;
+
+	wm8997 = devm_kzalloc(&pdev->dev, sizeof(struct wm8997_priv),
+			      GFP_KERNEL);
+	if (wm8997 == NULL)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, wm8997);
+
+	if (IS_ENABLED(CONFIG_OF)) {
+		if (!dev_get_platdata(arizona->dev)) {
+			ret = arizona_of_get_audio_pdata(arizona);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	wm8997->core.arizona = arizona;
+	wm8997->core.num_inputs = 4;
+
+	arizona_init_dvfs(&wm8997->core);
+
+	for (i = 0; i < ARRAY_SIZE(wm8997->fll); i++)
+		wm8997->fll[i].vco_mult = 1;
+
+	arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK,
+			 &wm8997->fll[0]);
+	arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
+			 &wm8997->fll[1]);
+
+	/* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
+			   ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
+			   ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
+
+	for (i = 0; i < ARRAY_SIZE(wm8997_dai); i++)
+		arizona_init_dai(&wm8997->core, i);
+
+	/* Latch volume update bits */
+	for (i = 0; i < ARRAY_SIZE(wm8997_digital_vu); i++)
+		regmap_update_bits(arizona->regmap, wm8997_digital_vu[i],
+				   WM8997_DIG_VU, WM8997_DIG_VU);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_idle(&pdev->dev);
+
+	arizona_init_common(arizona);
+
+	ret = arizona_init_vol_limit(arizona);
+	if (ret < 0)
+		return ret;
+	ret = arizona_init_spk_irqs(arizona);
+	if (ret < 0)
+		return ret;
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					      &soc_component_dev_wm8997,
+					      wm8997_dai,
+					      ARRAY_SIZE(wm8997_dai));
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
+		goto err_spk_irqs;
+	}
+
+err_spk_irqs:
+	arizona_free_spk_irqs(arizona);
+
+	return ret;
+}
+
+static int wm8997_remove(struct platform_device *pdev)
+{
+	struct wm8997_priv *wm8997 = platform_get_drvdata(pdev);
+	struct arizona *arizona = wm8997->core.arizona;
+
+	pm_runtime_disable(&pdev->dev);
+
+	arizona_free_spk_irqs(arizona);
+
+	return 0;
+}
+
+static struct platform_driver wm8997_codec_driver = {
+	.driver = {
+		.name = "wm8997-codec",
+	},
+	.probe = wm8997_probe,
+	.remove = wm8997_remove,
+};
+
+module_platform_driver(wm8997_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM8997 driver");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8997-codec");
diff --git a/sound/soc/codecs/wm8997.h b/sound/soc/codecs/wm8997.h
new file mode 100644
index 0000000..5e91c6a
--- /dev/null
+++ b/sound/soc/codecs/wm8997.h
@@ -0,0 +1,23 @@
+/*
+ * wm8997.h  --  WM8997 ALSA SoC Audio driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8997_H
+#define _WM8997_H
+
+#include "arizona.h"
+
+#define WM8997_FLL1        1
+#define WM8997_FLL2        2
+#define WM8997_FLL1_REFCLK 3
+#define WM8997_FLL2_REFCLK 4
+
+#endif
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c
new file mode 100644
index 0000000..61294c7
--- /dev/null
+++ b/sound/soc/codecs/wm8998.c
@@ -0,0 +1,1425 @@
+/*
+ * wm8998.c -- ALSA SoC Audio driver for WM8998 codecs
+ *
+ * Copyright 2015 Cirrus Logic, Inc.
+ *
+ * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+#include "wm8998.h"
+
+struct wm8998_priv {
+	struct arizona_priv core;
+	struct arizona_fll fll[2];
+};
+
+static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol,
+			  int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	unsigned int val;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		val = snd_soc_component_read32(component, ARIZONA_ASRC_RATE1);
+		val &= ARIZONA_ASRC_RATE1_MASK;
+		val >>= ARIZONA_ASRC_RATE1_SHIFT;
+
+		switch (val) {
+		case 0:
+		case 1:
+		case 2:
+			val = snd_soc_component_read32(component,
+					   ARIZONA_SAMPLE_RATE_1 + val);
+			if (val >= 0x11) {
+				dev_warn(component->dev,
+					 "Unsupported ASRC rate1 (%s)\n",
+					 arizona_sample_rate_val_to_name(val));
+			return -EINVAL;
+			}
+			break;
+		default:
+			dev_err(component->dev,
+				"Illegal ASRC rate1 selector (0x%x)\n",
+				val);
+			return -EINVAL;
+		}
+
+		val = snd_soc_component_read32(component, ARIZONA_ASRC_RATE2);
+		val &= ARIZONA_ASRC_RATE2_MASK;
+		val >>= ARIZONA_ASRC_RATE2_SHIFT;
+
+		switch (val) {
+		case 8:
+		case 9:
+			val -= 0x8;
+			val = snd_soc_component_read32(component,
+					   ARIZONA_ASYNC_SAMPLE_RATE_1 + val);
+			if (val >= 0x11) {
+				dev_warn(component->dev,
+					 "Unsupported ASRC rate2 (%s)\n",
+					 arizona_sample_rate_val_to_name(val));
+				return -EINVAL;
+			}
+			break;
+		default:
+			dev_err(component->dev,
+				"Illegal ASRC rate2 selector (0x%x)\n",
+				val);
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8998_inmux_put(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct wm8998_priv *wm8998 = snd_soc_component_get_drvdata(component);
+	struct arizona *arizona = wm8998->core.arizona;
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int mode_reg, mode_index;
+	unsigned int mux, inmode, src_val, mode_val;
+
+	mux = ucontrol->value.enumerated.item[0];
+	if (mux > 1)
+		return -EINVAL;
+
+	switch (e->reg) {
+	case ARIZONA_ADC_DIGITAL_VOLUME_2L:
+		mode_reg = ARIZONA_IN2L_CONTROL;
+		mode_index = 1 + (2 * mux);
+		break;
+	default:
+		mode_reg = ARIZONA_IN1L_CONTROL;
+		mode_index = (2 * mux);
+		break;
+	}
+
+	inmode = arizona->pdata.inmode[mode_index];
+	if (inmode & ARIZONA_INMODE_DMIC)
+		mode_val = 1 << ARIZONA_IN1_MODE_SHIFT;
+	else
+		mode_val = 0;
+
+	src_val = mux << ARIZONA_IN1L_SRC_SHIFT;
+	if (inmode & ARIZONA_INMODE_SE)
+		src_val |= 1 << ARIZONA_IN1L_SRC_SE_SHIFT;
+
+	snd_soc_component_update_bits(component, mode_reg,
+				      ARIZONA_IN1_MODE_MASK, mode_val);
+
+	snd_soc_component_update_bits(component, e->reg,
+				      ARIZONA_IN1L_SRC_MASK |
+				      ARIZONA_IN1L_SRC_SE_MASK,
+				      src_val);
+
+	return snd_soc_dapm_mux_update_power(dapm, kcontrol,
+					     ucontrol->value.enumerated.item[0],
+					     e, NULL);
+}
+
+static const char * const wm8998_inmux_texts[] = {
+	"A",
+	"B",
+};
+
+static SOC_ENUM_SINGLE_DECL(wm8998_in1muxl_enum,
+			    ARIZONA_ADC_DIGITAL_VOLUME_1L,
+			    ARIZONA_IN1L_SRC_SHIFT,
+			    wm8998_inmux_texts);
+
+static SOC_ENUM_SINGLE_DECL(wm8998_in1muxr_enum,
+			    ARIZONA_ADC_DIGITAL_VOLUME_1R,
+			    ARIZONA_IN1R_SRC_SHIFT,
+			    wm8998_inmux_texts);
+
+static SOC_ENUM_SINGLE_DECL(wm8998_in2mux_enum,
+			    ARIZONA_ADC_DIGITAL_VOLUME_2L,
+			    ARIZONA_IN2L_SRC_SHIFT,
+			    wm8998_inmux_texts);
+
+static const struct snd_kcontrol_new wm8998_in1mux[2] = {
+	SOC_DAPM_ENUM_EXT("IN1L Mux", wm8998_in1muxl_enum,
+			  snd_soc_dapm_get_enum_double, wm8998_inmux_put),
+	SOC_DAPM_ENUM_EXT("IN1R Mux", wm8998_in1muxr_enum,
+			  snd_soc_dapm_get_enum_double, wm8998_inmux_put),
+};
+
+static const struct snd_kcontrol_new wm8998_in2mux =
+	SOC_DAPM_ENUM_EXT("IN2 Mux", wm8998_in2mux_enum,
+			  snd_soc_dapm_get_enum_double, wm8998_inmux_put);
+
+static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
+
+#define WM8998_NG_SRC(name, base) \
+	SOC_SINGLE(name " NG HPOUTL Switch",  base,  0, 1, 0), \
+	SOC_SINGLE(name " NG HPOUTR Switch",  base,  1, 1, 0), \
+	SOC_SINGLE(name " NG LINEOUTL Switch",  base,  2, 1, 0), \
+	SOC_SINGLE(name " NG LINEOUTR Switch",  base,  3, 1, 0), \
+	SOC_SINGLE(name " NG EPOUT Switch",   base,  4, 1, 0), \
+	SOC_SINGLE(name " NG SPKOUTL Switch",  base,  6, 1, 0), \
+	SOC_SINGLE(name " NG SPKOUTR Switch",  base,  7, 1, 0)
+
+static const struct snd_kcontrol_new wm8998_snd_controls[] = {
+SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]),
+SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
+
+SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
+		     ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
+		     ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN2 Volume", ARIZONA_IN2L_CONTROL,
+		     ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+
+SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum),
+
+SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL,
+	   ARIZONA_IN1L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL,
+	   ARIZONA_IN1R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2 HPF Switch", ARIZONA_IN2L_CONTROL,
+	   ARIZONA_IN2L_HPF_SHIFT, 1, 0),
+
+SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
+	       ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
+	       ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
+	       ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+
+SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
+SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
+
+ARIZONA_GAINMUX_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19),
+SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE_SHIFT, 1, 0),
+SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19),
+SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE_SHIFT, 1, 0),
+SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19),
+SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE_SHIFT, 1, 0),
+SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B3 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19),
+SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE_SHIFT, 1, 0),
+SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B3 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B4 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B5 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_GAINMUX_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
+		   ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
+
+ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1),
+SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1),
+SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1),
+SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1),
+
+SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
+SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
+SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
+SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
+
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]),
+SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
+SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
+
+ARIZONA_MIXER_CONTROLS("HPOUTL", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUTR", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LINEOUTL", ARIZONA_OUT2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LINEOUTR", ARIZONA_OUT2RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUTL", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDATL", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDATR", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),
+
+SOC_DOUBLE_R("HPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("LINEOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_MUTE_SHIFT, 1, 1),
+SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	   ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKDAT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("HPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("LINEOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_2L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	       ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("SPKDAT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+
+SOC_DOUBLE("SPKDAT Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
+	   ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
+
+SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
+SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
+
+SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
+	   ARIZONA_NGATE_ENA_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
+	       ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
+SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
+
+WM8998_NG_SRC("HPOUTL", ARIZONA_NOISE_GATE_SELECT_1L),
+WM8998_NG_SRC("HPOUTR", ARIZONA_NOISE_GATE_SELECT_1R),
+WM8998_NG_SRC("LINEOUTL", ARIZONA_NOISE_GATE_SELECT_2L),
+WM8998_NG_SRC("LINEOUTR", ARIZONA_NOISE_GATE_SELECT_2R),
+WM8998_NG_SRC("EPOUT",  ARIZONA_NOISE_GATE_SELECT_3L),
+WM8998_NG_SRC("SPKOUTL", ARIZONA_NOISE_GATE_SELECT_4L),
+WM8998_NG_SRC("SPKOUTR", ARIZONA_NOISE_GATE_SELECT_4R),
+WM8998_NG_SRC("SPKDATL", ARIZONA_NOISE_GATE_SELECT_5L),
+WM8998_NG_SRC("SPKDATR", ARIZONA_NOISE_GATE_SELECT_5R),
+
+ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+
+ARIZONA_GAINMUX_CONTROLS("SLIMTX1", ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("SLIMTX2", ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("SLIMTX3", ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("SLIMTX4", ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
+
+ARIZONA_GAINMUX_CONTROLS("SPDIFTX1", ARIZONA_SPDIFTX1MIX_INPUT_1_SOURCE),
+ARIZONA_GAINMUX_CONTROLS("SPDIFTX2", ARIZONA_SPDIFTX2MIX_INPUT_1_SOURCE),
+};
+
+ARIZONA_MUX_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(EQ4, ARIZONA_EQ4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT2L, ARIZONA_OUT2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT2R, ARIZONA_OUT2RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT3,  ARIZONA_OUT3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUTL, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUTR, ARIZONA_OUT4RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDATL, ARIZONA_OUT5LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDATR, ARIZONA_OUT5RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(SLIMTX1, ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(SLIMTX2, ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(SLIMTX3, ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(SLIMTX4, ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(SLIMTX5, ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(SLIMTX6, ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(SPD1TX1, ARIZONA_SPDIFTX1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(SPD1TX2, ARIZONA_SPDIFTX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT3, ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT4, ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC3, ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC4, ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
+
+static const char * const wm8998_aec_loopback_texts[] = {
+	"HPOUTL", "HPOUTR", "LINEOUTL", "LINEOUTR", "EPOUT",
+	"SPKOUTL", "SPKOUTR", "SPKDATL", "SPKDATR",
+};
+
+static const unsigned int wm8998_aec_loopback_values[] = {
+	0, 1, 2, 3, 4, 6, 7, 8, 9,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec1_loopback,
+				  ARIZONA_DAC_AEC_CONTROL_1,
+				  ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+				  wm8998_aec_loopback_texts,
+				  wm8998_aec_loopback_values);
+
+static SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec2_loopback,
+				  ARIZONA_DAC_AEC_CONTROL_2,
+				  ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+				  wm8998_aec_loopback_texts,
+				  wm8998_aec_loopback_values);
+
+static const struct snd_kcontrol_new wm8998_aec_loopback_mux[] = {
+	SOC_DAPM_ENUM("AEC1 Loopback", wm8998_aec1_loopback),
+	SOC_DAPM_ENUM("AEC2 Loopback", wm8998_aec2_loopback),
+};
+
+static const struct snd_soc_dapm_widget wm8998_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1,
+		    ARIZONA_SYSCLK_ENA_SHIFT, 0, arizona_clk_ev,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
+		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+		    ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_SIGGEN("HAPTICS"),
+
+SND_SOC_DAPM_INPUT("IN1AL"),
+SND_SOC_DAPM_INPUT("IN1AR"),
+SND_SOC_DAPM_INPUT("IN1BL"),
+SND_SOC_DAPM_INPUT("IN1BR"),
+SND_SOC_DAPM_INPUT("IN2A"),
+SND_SOC_DAPM_INPUT("IN2B"),
+
+SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &wm8998_in1mux[0]),
+SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &wm8998_in1mux[1]),
+SND_SOC_DAPM_MUX("IN2 Mux", SND_SOC_NOPM, 0, 0, &wm8998_in2mux),
+
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2 PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ3", ARIZONA_EQ3_1, ARIZONA_EQ3_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ4", ARIZONA_EQ4_1, ARIZONA_EQ4_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT,
+		 0, NULL, 0),
+SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT,
+		 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_E("ASRC1L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1L_ENA_SHIFT, 0,
+		   NULL, 0, wm8998_asrc_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("ASRC1R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1R_ENA_SHIFT, 0,
+		   NULL, 0, wm8998_asrc_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
+		   NULL, 0, wm8998_asrc_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
+		   NULL, 0, wm8998_asrc_ev, SND_SOC_DAPM_PRE_PMU),
+
+SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT3", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT4", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC3", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC4", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("AEC1 Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+		 ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
+		 &wm8998_aec_loopback_mux[0]),
+
+SND_SOC_DAPM_MUX("AEC2 Loopback", ARIZONA_DAC_AEC_CONTROL_2,
+		 ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
+		 &wm8998_aec_loopback_mux[1]),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX4_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0,
+		     ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0,
+		     ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
+		    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
+		    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+		   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+		   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT3", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT5R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA("SPD1TX1", ARIZONA_SPD1_TX_CONTROL,
+		 ARIZONA_SPD1_VAL1_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPD1TX2", ARIZONA_SPD1_TX_CONTROL,
+		 ARIZONA_SPD1_VAL2_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_OUT_DRV("SPD1", ARIZONA_SPD1_TX_CONTROL,
+		     ARIZONA_SPD1_ENA_SHIFT, 0, NULL, 0),
+
+ARIZONA_MUX_WIDGETS(EQ1, "EQ1"),
+ARIZONA_MUX_WIDGETS(EQ2, "EQ2"),
+ARIZONA_MUX_WIDGETS(EQ3, "EQ3"),
+ARIZONA_MUX_WIDGETS(EQ4, "EQ4"),
+
+ARIZONA_MUX_WIDGETS(DRC1L, "DRC1L"),
+ARIZONA_MUX_WIDGETS(DRC1R, "DRC1R"),
+
+ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
+ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
+ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"),
+ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"),
+ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"),
+
+ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUTL"),
+ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUTR"),
+ARIZONA_MIXER_WIDGETS(OUT2L, "LINEOUTL"),
+ARIZONA_MIXER_WIDGETS(OUT2R, "LINEOUTR"),
+ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"),
+ARIZONA_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"),
+ARIZONA_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"),
+ARIZONA_MIXER_WIDGETS(SPKDATL, "SPKDATL"),
+ARIZONA_MIXER_WIDGETS(SPKDATR, "SPKDATR"),
+
+ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+
+ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
+ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"),
+ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"),
+ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"),
+ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"),
+
+ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
+ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
+
+ARIZONA_MUX_WIDGETS(SLIMTX1, "SLIMTX1"),
+ARIZONA_MUX_WIDGETS(SLIMTX2, "SLIMTX2"),
+ARIZONA_MUX_WIDGETS(SLIMTX3, "SLIMTX3"),
+ARIZONA_MUX_WIDGETS(SLIMTX4, "SLIMTX4"),
+ARIZONA_MUX_WIDGETS(SLIMTX5, "SLIMTX5"),
+ARIZONA_MUX_WIDGETS(SLIMTX6, "SLIMTX6"),
+
+ARIZONA_MUX_WIDGETS(SPD1TX1, "SPDIFTX1"),
+ARIZONA_MUX_WIDGETS(SPD1TX2, "SPDIFTX2"),
+
+ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"),
+ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
+ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
+ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"),
+
+ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
+ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
+ARIZONA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"),
+ARIZONA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
+
+ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
+ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
+
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+SND_SOC_DAPM_OUTPUT("LINEOUTL"),
+SND_SOC_DAPM_OUTPUT("LINEOUTR"),
+SND_SOC_DAPM_OUTPUT("EPOUT"),
+SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
+SND_SOC_DAPM_OUTPUT("SPKDATL"),
+SND_SOC_DAPM_OUTPUT("SPKDATR"),
+SND_SOC_DAPM_OUTPUT("SPDIF"),
+
+SND_SOC_DAPM_OUTPUT("MICSUPP"),
+};
+
+#define ARIZONA_MIXER_INPUT_ROUTES(name)	\
+	{ name, "Tone Generator 1", "Tone Generator 1" }, \
+	{ name, "Tone Generator 2", "Tone Generator 2" }, \
+	{ name, "Haptics", "HAPTICS" }, \
+	{ name, "AEC", "AEC1 Loopback" }, \
+	{ name, "AEC2", "AEC2 Loopback" }, \
+	{ name, "IN1L", "IN1L PGA" }, \
+	{ name, "IN1R", "IN1R PGA" }, \
+	{ name, "IN2L", "IN2 PGA" }, \
+	{ name, "AIF1RX1", "AIF1RX1" }, \
+	{ name, "AIF1RX2", "AIF1RX2" }, \
+	{ name, "AIF1RX3", "AIF1RX3" }, \
+	{ name, "AIF1RX4", "AIF1RX4" }, \
+	{ name, "AIF1RX5", "AIF1RX5" }, \
+	{ name, "AIF1RX6", "AIF1RX6" }, \
+	{ name, "AIF2RX1", "AIF2RX1" }, \
+	{ name, "AIF2RX2", "AIF2RX2" }, \
+	{ name, "AIF2RX3", "AIF2RX3" }, \
+	{ name, "AIF2RX4", "AIF2RX4" }, \
+	{ name, "AIF2RX5", "AIF2RX5" }, \
+	{ name, "AIF2RX6", "AIF2RX6" }, \
+	{ name, "AIF3RX1", "AIF3RX1" }, \
+	{ name, "AIF3RX2", "AIF3RX2" }, \
+	{ name, "SLIMRX1", "SLIMRX1" }, \
+	{ name, "SLIMRX2", "SLIMRX2" }, \
+	{ name, "SLIMRX3", "SLIMRX3" }, \
+	{ name, "SLIMRX4", "SLIMRX4" }, \
+	{ name, "EQ1", "EQ1" }, \
+	{ name, "EQ2", "EQ2" }, \
+	{ name, "EQ3", "EQ3" }, \
+	{ name, "EQ4", "EQ4" }, \
+	{ name, "DRC1L", "DRC1L" }, \
+	{ name, "DRC1R", "DRC1R" }, \
+	{ name, "LHPF1", "LHPF1" }, \
+	{ name, "LHPF2", "LHPF2" }, \
+	{ name, "LHPF3", "LHPF3" }, \
+	{ name, "LHPF4", "LHPF4" }, \
+	{ name, "ASRC1L", "ASRC1L" }, \
+	{ name, "ASRC1R", "ASRC1R" }, \
+	{ name, "ASRC2L", "ASRC2L" }, \
+	{ name, "ASRC2R", "ASRC2R" }, \
+	{ name, "ISRC1DEC1", "ISRC1DEC1" }, \
+	{ name, "ISRC1DEC2", "ISRC1DEC2" }, \
+	{ name, "ISRC1DEC3", "ISRC1DEC3" }, \
+	{ name, "ISRC1DEC4", "ISRC1DEC4" }, \
+	{ name, "ISRC1INT1", "ISRC1INT1" }, \
+	{ name, "ISRC1INT2", "ISRC1INT2" }, \
+	{ name, "ISRC1INT3", "ISRC1INT3" }, \
+	{ name, "ISRC1INT4", "ISRC1INT4" }, \
+	{ name, "ISRC2DEC1", "ISRC2DEC1" }, \
+	{ name, "ISRC2DEC2", "ISRC2DEC2" }, \
+	{ name, "ISRC2INT1", "ISRC2INT1" }, \
+	{ name, "ISRC2INT2", "ISRC2INT2" }
+
+static const struct snd_soc_dapm_route wm8998_dapm_routes[] = {
+	{ "AIF2 Capture", NULL, "DBVDD2" },
+	{ "AIF2 Playback", NULL, "DBVDD2" },
+
+	{ "AIF3 Capture", NULL, "DBVDD3" },
+	{ "AIF3 Playback", NULL, "DBVDD3" },
+
+	{ "OUT1L", NULL, "CPVDD" },
+	{ "OUT1R", NULL, "CPVDD" },
+	{ "OUT2L", NULL, "CPVDD" },
+	{ "OUT2R", NULL, "CPVDD" },
+	{ "OUT3",  NULL, "CPVDD" },
+
+	{ "OUT4L", NULL, "SPKVDDL" },
+	{ "OUT4R", NULL, "SPKVDDR" },
+
+	{ "OUT1L", NULL, "SYSCLK" },
+	{ "OUT1R", NULL, "SYSCLK" },
+	{ "OUT2L", NULL, "SYSCLK" },
+	{ "OUT2R", NULL, "SYSCLK" },
+	{ "OUT3",  NULL, "SYSCLK" },
+	{ "OUT4L", NULL, "SYSCLK" },
+	{ "OUT4R", NULL, "SYSCLK" },
+	{ "OUT5L", NULL, "SYSCLK" },
+	{ "OUT5R", NULL, "SYSCLK" },
+
+	{ "IN1AL", NULL, "SYSCLK" },
+	{ "IN1AR", NULL, "SYSCLK" },
+	{ "IN1BL", NULL, "SYSCLK" },
+	{ "IN1BR", NULL, "SYSCLK" },
+	{ "IN2A", NULL, "SYSCLK" },
+	{ "IN2B", NULL, "SYSCLK" },
+
+	{ "ASRC1L", NULL, "SYSCLK" },
+	{ "ASRC1R", NULL, "SYSCLK" },
+	{ "ASRC2L", NULL, "SYSCLK" },
+	{ "ASRC2R", NULL, "SYSCLK" },
+
+	{ "ASRC1L", NULL, "ASYNCCLK" },
+	{ "ASRC1R", NULL, "ASYNCCLK" },
+	{ "ASRC2L", NULL, "ASYNCCLK" },
+	{ "ASRC2R", NULL, "ASYNCCLK" },
+
+	{ "SPD1", NULL, "SYSCLK" },
+	{ "SPD1", NULL, "SPD1TX1" },
+	{ "SPD1", NULL, "SPD1TX2" },
+
+	{ "MICBIAS1", NULL, "MICVDD" },
+	{ "MICBIAS2", NULL, "MICVDD" },
+	{ "MICBIAS3", NULL, "MICVDD" },
+
+	{ "Tone Generator 1", NULL, "SYSCLK" },
+	{ "Tone Generator 2", NULL, "SYSCLK" },
+
+	{ "Tone Generator 1", NULL, "TONE" },
+	{ "Tone Generator 2", NULL, "TONE" },
+
+	{ "AIF1 Capture", NULL, "AIF1TX1" },
+	{ "AIF1 Capture", NULL, "AIF1TX2" },
+	{ "AIF1 Capture", NULL, "AIF1TX3" },
+	{ "AIF1 Capture", NULL, "AIF1TX4" },
+	{ "AIF1 Capture", NULL, "AIF1TX5" },
+	{ "AIF1 Capture", NULL, "AIF1TX6" },
+
+	{ "AIF1RX1", NULL, "AIF1 Playback" },
+	{ "AIF1RX2", NULL, "AIF1 Playback" },
+	{ "AIF1RX3", NULL, "AIF1 Playback" },
+	{ "AIF1RX4", NULL, "AIF1 Playback" },
+	{ "AIF1RX5", NULL, "AIF1 Playback" },
+	{ "AIF1RX6", NULL, "AIF1 Playback" },
+
+	{ "AIF2 Capture", NULL, "AIF2TX1" },
+	{ "AIF2 Capture", NULL, "AIF2TX2" },
+	{ "AIF2 Capture", NULL, "AIF2TX3" },
+	{ "AIF2 Capture", NULL, "AIF2TX4" },
+	{ "AIF2 Capture", NULL, "AIF2TX5" },
+	{ "AIF2 Capture", NULL, "AIF2TX6" },
+
+	{ "AIF2RX1", NULL, "AIF2 Playback" },
+	{ "AIF2RX2", NULL, "AIF2 Playback" },
+	{ "AIF2RX3", NULL, "AIF2 Playback" },
+	{ "AIF2RX4", NULL, "AIF2 Playback" },
+	{ "AIF2RX5", NULL, "AIF2 Playback" },
+	{ "AIF2RX6", NULL, "AIF2 Playback" },
+
+	{ "AIF3 Capture", NULL, "AIF3TX1" },
+	{ "AIF3 Capture", NULL, "AIF3TX2" },
+
+	{ "AIF3RX1", NULL, "AIF3 Playback" },
+	{ "AIF3RX2", NULL, "AIF3 Playback" },
+
+	{ "Slim1 Capture", NULL, "SLIMTX1" },
+	{ "Slim1 Capture", NULL, "SLIMTX2" },
+	{ "Slim1 Capture", NULL, "SLIMTX3" },
+	{ "Slim1 Capture", NULL, "SLIMTX4" },
+
+	{ "Slim2 Capture", NULL, "SLIMTX5" },
+	{ "Slim2 Capture", NULL, "SLIMTX6" },
+
+	{ "SLIMRX1", NULL, "Slim1 Playback" },
+	{ "SLIMRX2", NULL, "Slim1 Playback" },
+
+	{ "SLIMRX3", NULL, "Slim2 Playback" },
+	{ "SLIMRX4", NULL, "Slim2 Playback" },
+
+	{ "AIF1 Playback", NULL, "SYSCLK" },
+	{ "AIF2 Playback", NULL, "SYSCLK" },
+	{ "AIF3 Playback", NULL, "SYSCLK" },
+	{ "Slim1 Playback", NULL, "SYSCLK" },
+	{ "Slim2 Playback", NULL, "SYSCLK" },
+
+	{ "AIF1 Capture", NULL, "SYSCLK" },
+	{ "AIF2 Capture", NULL, "SYSCLK" },
+	{ "AIF3 Capture", NULL, "SYSCLK" },
+	{ "Slim1 Capture", NULL, "SYSCLK" },
+	{ "Slim2 Capture", NULL, "SYSCLK" },
+
+	{ "IN1L Mux", "A", "IN1AL" },
+	{ "IN1R Mux", "A", "IN1AR" },
+	{ "IN1L Mux", "B", "IN1BL" },
+	{ "IN1R Mux", "B", "IN1BR" },
+
+	{ "IN2 Mux", "A", "IN2A" },
+	{ "IN2 Mux", "B", "IN2B" },
+
+	{ "IN1L PGA", NULL, "IN1L Mux" },
+	{ "IN1R PGA", NULL, "IN1R Mux" },
+	{ "IN2 PGA",  NULL, "IN2 Mux" },
+
+	ARIZONA_MIXER_ROUTES("OUT1L", "HPOUTL"),
+	ARIZONA_MIXER_ROUTES("OUT1R", "HPOUTR"),
+	ARIZONA_MIXER_ROUTES("OUT2L", "LINEOUTL"),
+	ARIZONA_MIXER_ROUTES("OUT2R", "LINEOUTR"),
+	ARIZONA_MIXER_ROUTES("OUT3",  "EPOUT"),
+
+	ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUTL"),
+	ARIZONA_MIXER_ROUTES("OUT4R", "SPKOUTR"),
+	ARIZONA_MIXER_ROUTES("OUT5L", "SPKDATL"),
+	ARIZONA_MIXER_ROUTES("OUT5R", "SPKDATR"),
+
+	ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"),
+	ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"),
+
+	ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+	ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+	ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+	ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+	ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+	ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+
+	ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
+	ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+	ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"),
+	ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"),
+	ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"),
+	ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"),
+
+	ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
+	ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
+
+	ARIZONA_MUX_ROUTES("SLIMTX1", "SLIMTX1"),
+	ARIZONA_MUX_ROUTES("SLIMTX2", "SLIMTX2"),
+	ARIZONA_MUX_ROUTES("SLIMTX3", "SLIMTX3"),
+	ARIZONA_MUX_ROUTES("SLIMTX4", "SLIMTX4"),
+	ARIZONA_MUX_ROUTES("SLIMTX5", "SLIMTX5"),
+	ARIZONA_MUX_ROUTES("SLIMTX6", "SLIMTX6"),
+
+	ARIZONA_MUX_ROUTES("SPD1TX1", "SPDIFTX1"),
+	ARIZONA_MUX_ROUTES("SPD1TX2", "SPDIFTX2"),
+
+	ARIZONA_MUX_ROUTES("EQ1", "EQ1"),
+	ARIZONA_MUX_ROUTES("EQ2", "EQ2"),
+	ARIZONA_MUX_ROUTES("EQ3", "EQ3"),
+	ARIZONA_MUX_ROUTES("EQ4", "EQ4"),
+
+	ARIZONA_MUX_ROUTES("DRC1L", "DRC1L"),
+	ARIZONA_MUX_ROUTES("DRC1R", "DRC1R"),
+
+	ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
+	ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
+	ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
+	ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+	ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"),
+	ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"),
+	ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
+	ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
+
+	ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+	ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+	ARIZONA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"),
+	ARIZONA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"),
+
+	ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"),
+
+	ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+	ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+
+	ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+
+	{ "AEC1 Loopback", "HPOUTL", "OUT1L" },
+	{ "AEC1 Loopback", "HPOUTR", "OUT1R" },
+	{ "AEC2 Loopback", "HPOUTL", "OUT1L" },
+	{ "AEC2 Loopback", "HPOUTR", "OUT1R" },
+	{ "HPOUTL", NULL, "OUT1L" },
+	{ "HPOUTR", NULL, "OUT1R" },
+
+	{ "AEC1 Loopback", "LINEOUTL", "OUT2L" },
+	{ "AEC1 Loopback", "LINEOUTR", "OUT2R" },
+	{ "AEC2 Loopback", "LINEOUTL", "OUT2L" },
+	{ "AEC2 Loopback", "LINEOUTR", "OUT2R" },
+	{ "LINEOUTL", NULL, "OUT2L" },
+	{ "LINEOUTR", NULL, "OUT2R" },
+
+	{ "AEC1 Loopback", "EPOUT", "OUT3" },
+	{ "AEC2 Loopback", "EPOUT", "OUT3" },
+	{ "EPOUT", NULL, "OUT3" },
+
+	{ "AEC1 Loopback", "SPKOUTL", "OUT4L" },
+	{ "AEC2 Loopback", "SPKOUTL", "OUT4L" },
+	{ "SPKOUTLN", NULL, "OUT4L" },
+	{ "SPKOUTLP", NULL, "OUT4L" },
+
+	{ "AEC1 Loopback", "SPKOUTR", "OUT4R" },
+	{ "AEC2 Loopback", "SPKOUTR", "OUT4R" },
+	{ "SPKOUTRN", NULL, "OUT4R" },
+	{ "SPKOUTRP", NULL, "OUT4R" },
+
+	{ "SPDIF", NULL, "SPD1" },
+
+	{ "AEC1 Loopback", "SPKDATL", "OUT5L" },
+	{ "AEC1 Loopback", "SPKDATR", "OUT5R" },
+	{ "AEC2 Loopback", "SPKDATL", "OUT5L" },
+	{ "AEC2 Loopback", "SPKDATR", "OUT5R" },
+	{ "SPKDATL", NULL, "OUT5L" },
+	{ "SPKDATR", NULL, "OUT5R" },
+
+	{ "MICSUPP", NULL, "SYSCLK" },
+
+	{ "DRC1 Signal Activity", NULL, "SYSCLK" },
+	{ "DRC1 Signal Activity", NULL, "DRC1L" },
+	{ "DRC1 Signal Activity", NULL, "DRC1R" },
+};
+
+#define WM8998_RATES SNDRV_PCM_RATE_KNOT
+
+#define WM8998_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm8998_dai[] = {
+	{
+		.name = "wm8998-aif1",
+		.id = 1,
+		.base = ARIZONA_AIF1_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = WM8998_RATES,
+			.formats = WM8998_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 6,
+			 .rates = WM8998_RATES,
+			 .formats = WM8998_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "wm8998-aif2",
+		.id = 2,
+		.base = ARIZONA_AIF2_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = WM8998_RATES,
+			.formats = WM8998_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 6,
+			 .rates = WM8998_RATES,
+			 .formats = WM8998_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "wm8998-aif3",
+		.id = 3,
+		.base = ARIZONA_AIF3_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8998_RATES,
+			.formats = WM8998_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF3 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM8998_RATES,
+			 .formats = WM8998_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "wm8998-slim1",
+		.id = 4,
+		.playback = {
+			.stream_name = "Slim1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8998_RATES,
+			.formats = WM8998_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "Slim1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 4,
+			 .rates = WM8998_RATES,
+			 .formats = WM8998_FORMATS,
+		 },
+		.ops = &arizona_simple_dai_ops,
+	},
+	{
+		.name = "wm8998-slim2",
+		.id = 5,
+		.playback = {
+			.stream_name = "Slim2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8998_RATES,
+			.formats = WM8998_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "Slim2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM8998_RATES,
+			 .formats = WM8998_FORMATS,
+		 },
+		.ops = &arizona_simple_dai_ops,
+	},
+};
+
+static int wm8998_set_fll(struct snd_soc_component *component, int fll_id,
+			  int source, unsigned int Fref, unsigned int Fout)
+{
+	struct wm8998_priv *wm8998 = snd_soc_component_get_drvdata(component);
+
+	switch (fll_id) {
+	case WM8998_FLL1:
+		return arizona_set_fll(&wm8998->fll[0], source, Fref, Fout);
+	case WM8998_FLL2:
+		return arizona_set_fll(&wm8998->fll[1], source, Fref, Fout);
+	case WM8998_FLL1_REFCLK:
+		return arizona_set_fll_refclk(&wm8998->fll[0], source, Fref,
+					      Fout);
+	case WM8998_FLL2_REFCLK:
+		return arizona_set_fll_refclk(&wm8998->fll[1], source, Fref,
+					      Fout);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int wm8998_component_probe(struct snd_soc_component *component)
+{
+	struct wm8998_priv *priv = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct arizona *arizona = priv->core.arizona;
+	int ret;
+
+	arizona->dapm = dapm;
+	snd_soc_component_init_regmap(component, arizona->regmap);
+
+	ret = arizona_init_spk(component);
+	if (ret < 0)
+		return ret;
+
+	arizona_init_gpio(component);
+
+	snd_soc_component_disable_pin(component, "HAPTICS");
+
+	return 0;
+}
+
+static void wm8998_component_remove(struct snd_soc_component *component)
+{
+	struct wm8998_priv *priv = snd_soc_component_get_drvdata(component);
+
+	priv->core.arizona->dapm = NULL;
+}
+
+#define WM8998_DIG_VU 0x0200
+
+static unsigned int wm8998_digital_vu[] = {
+	ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	ARIZONA_DAC_DIGITAL_VOLUME_1R,
+	ARIZONA_DAC_DIGITAL_VOLUME_2L,
+	ARIZONA_DAC_DIGITAL_VOLUME_2R,
+	ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	ARIZONA_DAC_DIGITAL_VOLUME_4R,
+	ARIZONA_DAC_DIGITAL_VOLUME_5L,
+	ARIZONA_DAC_DIGITAL_VOLUME_5R,
+};
+
+static const struct snd_soc_component_driver soc_component_dev_wm8998 = {
+	.probe			= wm8998_component_probe,
+	.remove			= wm8998_component_remove,
+	.set_sysclk		= arizona_set_sysclk,
+	.set_pll		= wm8998_set_fll,
+	.controls		= wm8998_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm8998_snd_controls),
+	.dapm_widgets		= wm8998_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm8998_dapm_widgets),
+	.dapm_routes		= wm8998_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(wm8998_dapm_routes),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm8998_probe(struct platform_device *pdev)
+{
+	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+	struct wm8998_priv *wm8998;
+	int i, ret;
+
+	wm8998 = devm_kzalloc(&pdev->dev, sizeof(struct wm8998_priv),
+			      GFP_KERNEL);
+	if (!wm8998)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, wm8998);
+
+	if (IS_ENABLED(CONFIG_OF)) {
+		if (!dev_get_platdata(arizona->dev)) {
+			ret = arizona_of_get_audio_pdata(arizona);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	wm8998->core.arizona = arizona;
+	wm8998->core.num_inputs = 3;	/* IN1L, IN1R, IN2 */
+
+	for (i = 0; i < ARRAY_SIZE(wm8998->fll); i++)
+		wm8998->fll[i].vco_mult = 1;
+
+	arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK,
+			 &wm8998->fll[0]);
+	arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
+			 &wm8998->fll[1]);
+
+	for (i = 0; i < ARRAY_SIZE(wm8998_dai); i++)
+		arizona_init_dai(&wm8998->core, i);
+
+	/* Latch volume update bits */
+	for (i = 0; i < ARRAY_SIZE(wm8998_digital_vu); i++)
+		regmap_update_bits(arizona->regmap, wm8998_digital_vu[i],
+				   WM8998_DIG_VU, WM8998_DIG_VU);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_idle(&pdev->dev);
+
+	arizona_init_common(arizona);
+
+	ret = arizona_init_spk_irqs(arizona);
+	if (ret < 0)
+		return ret;
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					      &soc_component_dev_wm8998,
+					      wm8998_dai,
+					      ARRAY_SIZE(wm8998_dai));
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
+		goto err_spk_irqs;
+	}
+
+	return ret;
+
+err_spk_irqs:
+	arizona_free_spk_irqs(arizona);
+
+	return ret;
+}
+
+static int wm8998_remove(struct platform_device *pdev)
+{
+	struct wm8998_priv *wm8998 = platform_get_drvdata(pdev);
+	struct arizona *arizona = wm8998->core.arizona;
+
+	pm_runtime_disable(&pdev->dev);
+
+	arizona_free_spk_irqs(arizona);
+
+	return 0;
+}
+
+static struct platform_driver wm8998_codec_driver = {
+	.driver = {
+		.name = "wm8998-codec",
+	},
+	.probe = wm8998_probe,
+	.remove = wm8998_remove,
+};
+
+module_platform_driver(wm8998_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM8998 driver");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:wm8998-codec");
diff --git a/sound/soc/codecs/wm8998.h b/sound/soc/codecs/wm8998.h
new file mode 100644
index 0000000..1e86472
--- /dev/null
+++ b/sound/soc/codecs/wm8998.h
@@ -0,0 +1,23 @@
+/*
+ * wm8998.h -- ALSA SoC Audio driver for WM8998 codecs
+ *
+ * Copyright 2015 Cirrus Logic, Inc.
+ *
+ * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8998_H
+#define _WM8998_H
+
+#include "arizona.h"
+
+#define WM8998_FLL1        1
+#define WM8998_FLL2        2
+#define WM8998_FLL1_REFCLK 3
+#define WM8998_FLL2_REFCLK 4
+
+#endif
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
new file mode 100644
index 0000000..399255d1
--- /dev/null
+++ b/sound/soc/codecs/wm9081.c
@@ -0,0 +1,1388 @@
+/*
+ * wm9081.c  --  WM9081 ALSA SoC Audio driver
+ *
+ * Author: Mark Brown
+ *
+ * Copyright 2009-12 Wolfson Microelectronics plc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <sound/wm9081.h>
+#include "wm9081.h"
+
+static const struct reg_default wm9081_reg[] = {
+	{  2, 0x00B9 },     /* R2  - Analogue Lineout */
+	{  3, 0x00B9 },     /* R3  - Analogue Speaker PGA */
+	{  4, 0x0001 },     /* R4  - VMID Control */
+	{  5, 0x0068 },     /* R5  - Bias Control 1 */
+	{  7, 0x0000 },     /* R7  - Analogue Mixer */
+	{  8, 0x0000 },     /* R8  - Anti Pop Control */
+	{  9, 0x01DB },     /* R9  - Analogue Speaker 1 */
+	{ 10, 0x0018 },     /* R10 - Analogue Speaker 2 */
+	{ 11, 0x0180 },     /* R11 - Power Management */
+	{ 12, 0x0000 },     /* R12 - Clock Control 1 */
+	{ 13, 0x0038 },     /* R13 - Clock Control 2 */
+	{ 14, 0x4000 },     /* R14 - Clock Control 3 */
+	{ 16, 0x0000 },     /* R16 - FLL Control 1 */
+	{ 17, 0x0200 },     /* R17 - FLL Control 2 */
+	{ 18, 0x0000 },     /* R18 - FLL Control 3 */
+	{ 19, 0x0204 },     /* R19 - FLL Control 4 */
+	{ 20, 0x0000 },     /* R20 - FLL Control 5 */
+	{ 22, 0x0000 },     /* R22 - Audio Interface 1 */
+	{ 23, 0x0002 },     /* R23 - Audio Interface 2 */
+	{ 24, 0x0008 },     /* R24 - Audio Interface 3 */
+	{ 25, 0x0022 },     /* R25 - Audio Interface 4 */
+	{ 27, 0x0006 },     /* R27 - Interrupt Status Mask */
+	{ 28, 0x0000 },     /* R28 - Interrupt Polarity */
+	{ 29, 0x0000 },     /* R29 - Interrupt Control */
+	{ 30, 0x00C0 },     /* R30 - DAC Digital 1 */
+	{ 31, 0x0008 },     /* R31 - DAC Digital 2 */
+	{ 32, 0x09AF },     /* R32 - DRC 1 */
+	{ 33, 0x4201 },     /* R33 - DRC 2 */
+	{ 34, 0x0000 },     /* R34 - DRC 3 */
+	{ 35, 0x0000 },     /* R35 - DRC 4 */
+	{ 38, 0x0000 },     /* R38 - Write Sequencer 1 */
+	{ 39, 0x0000 },     /* R39 - Write Sequencer 2 */
+	{ 40, 0x0002 },     /* R40 - MW Slave 1 */
+	{ 42, 0x0000 },     /* R42 - EQ 1 */
+	{ 43, 0x0000 },     /* R43 - EQ 2 */
+	{ 44, 0x0FCA },     /* R44 - EQ 3 */
+	{ 45, 0x0400 },     /* R45 - EQ 4 */
+	{ 46, 0x00B8 },     /* R46 - EQ 5 */
+	{ 47, 0x1EB5 },     /* R47 - EQ 6 */
+	{ 48, 0xF145 },     /* R48 - EQ 7 */
+	{ 49, 0x0B75 },     /* R49 - EQ 8 */
+	{ 50, 0x01C5 },     /* R50 - EQ 9 */
+	{ 51, 0x169E },     /* R51 - EQ 10 */
+	{ 52, 0xF829 },     /* R52 - EQ 11 */
+	{ 53, 0x07AD },     /* R53 - EQ 12 */
+	{ 54, 0x1103 },     /* R54 - EQ 13 */
+	{ 55, 0x1C58 },     /* R55 - EQ 14 */
+	{ 56, 0xF373 },     /* R56 - EQ 15 */
+	{ 57, 0x0A54 },     /* R57 - EQ 16 */
+	{ 58, 0x0558 },     /* R58 - EQ 17 */
+	{ 59, 0x0564 },     /* R59 - EQ 18 */
+	{ 60, 0x0559 },     /* R60 - EQ 19 */
+	{ 61, 0x4000 },     /* R61 - EQ 20 */
+};
+
+static struct {
+	int ratio;
+	int clk_sys_rate;
+} clk_sys_rates[] = {
+	{ 64,   0 },
+	{ 128,  1 },
+	{ 192,  2 },
+	{ 256,  3 },
+	{ 384,  4 },
+	{ 512,  5 },
+	{ 768,  6 },
+	{ 1024, 7 },
+	{ 1408, 8 },
+	{ 1536, 9 },
+};
+
+static struct {
+	int rate;
+	int sample_rate;
+} sample_rates[] = {
+	{ 8000,  0  },
+	{ 11025, 1  },
+	{ 12000, 2  },
+	{ 16000, 3  },
+	{ 22050, 4  },
+	{ 24000, 5  },
+	{ 32000, 6  },
+	{ 44100, 7  },
+	{ 48000, 8  },
+	{ 88200, 9  },
+	{ 96000, 10 },
+};
+
+static struct {
+	int div; /* *10 due to .5s */
+	int bclk_div;
+} bclk_divs[] = {
+	{ 10,  0  },
+	{ 15,  1  },
+	{ 20,  2  },
+	{ 30,  3  },
+	{ 40,  4  },
+	{ 50,  5  },
+	{ 55,  6  },
+	{ 60,  7  },
+	{ 80,  8  },
+	{ 100, 9  },
+	{ 110, 10 },
+	{ 120, 11 },
+	{ 160, 12 },
+	{ 200, 13 },
+	{ 220, 14 },
+	{ 240, 15 },
+	{ 250, 16 },
+	{ 300, 17 },
+	{ 320, 18 },
+	{ 440, 19 },
+	{ 480, 20 },
+};
+
+struct wm9081_priv {
+	struct regmap *regmap;
+	int sysclk_source;
+	int mclk_rate;
+	int sysclk_rate;
+	int fs;
+	int bclk;
+	int master;
+	int fll_fref;
+	int fll_fout;
+	int tdm_width;
+	struct wm9081_pdata pdata;
+};
+
+static bool wm9081_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM9081_SOFTWARE_RESET:
+	case WM9081_INTERRUPT_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm9081_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM9081_SOFTWARE_RESET:
+	case WM9081_ANALOGUE_LINEOUT:
+	case WM9081_ANALOGUE_SPEAKER_PGA:
+	case WM9081_VMID_CONTROL:
+	case WM9081_BIAS_CONTROL_1:
+	case WM9081_ANALOGUE_MIXER:
+	case WM9081_ANTI_POP_CONTROL:
+	case WM9081_ANALOGUE_SPEAKER_1:
+	case WM9081_ANALOGUE_SPEAKER_2:
+	case WM9081_POWER_MANAGEMENT:
+	case WM9081_CLOCK_CONTROL_1:
+	case WM9081_CLOCK_CONTROL_2:
+	case WM9081_CLOCK_CONTROL_3:
+	case WM9081_FLL_CONTROL_1:
+	case WM9081_FLL_CONTROL_2:
+	case WM9081_FLL_CONTROL_3:
+	case WM9081_FLL_CONTROL_4:
+	case WM9081_FLL_CONTROL_5:
+	case WM9081_AUDIO_INTERFACE_1:
+	case WM9081_AUDIO_INTERFACE_2:
+	case WM9081_AUDIO_INTERFACE_3:
+	case WM9081_AUDIO_INTERFACE_4:
+	case WM9081_INTERRUPT_STATUS:
+	case WM9081_INTERRUPT_STATUS_MASK:
+	case WM9081_INTERRUPT_POLARITY:
+	case WM9081_INTERRUPT_CONTROL:
+	case WM9081_DAC_DIGITAL_1:
+	case WM9081_DAC_DIGITAL_2:
+	case WM9081_DRC_1:
+	case WM9081_DRC_2:
+	case WM9081_DRC_3:
+	case WM9081_DRC_4:
+	case WM9081_WRITE_SEQUENCER_1:
+	case WM9081_WRITE_SEQUENCER_2:
+	case WM9081_MW_SLAVE_1:
+	case WM9081_EQ_1:
+	case WM9081_EQ_2:
+	case WM9081_EQ_3:
+	case WM9081_EQ_4:
+	case WM9081_EQ_5:
+	case WM9081_EQ_6:
+	case WM9081_EQ_7:
+	case WM9081_EQ_8:
+	case WM9081_EQ_9:
+	case WM9081_EQ_10:
+	case WM9081_EQ_11:
+	case WM9081_EQ_12:
+	case WM9081_EQ_13:
+	case WM9081_EQ_14:
+	case WM9081_EQ_15:
+	case WM9081_EQ_16:
+	case WM9081_EQ_17:
+	case WM9081_EQ_18:
+	case WM9081_EQ_19:
+	case WM9081_EQ_20:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int wm9081_reset(struct regmap *map)
+{
+	return regmap_write(map, WM9081_SOFTWARE_RESET, 0x9081);
+}
+
+static const DECLARE_TLV_DB_SCALE(drc_in_tlv, -4500, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_out_tlv, -2250, 75, 0);
+static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0);
+static const DECLARE_TLV_DB_RANGE(drc_max_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(1200, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(1800, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+	3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0)
+);
+static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -300, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+
+static const DECLARE_TLV_DB_SCALE(in_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+
+static const char *drc_high_text[] = {
+	"1",
+	"1/2",
+	"1/4",
+	"1/8",
+	"1/16",
+	"0",
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_high, WM9081_DRC_3, 3, drc_high_text);
+
+static const char *drc_low_text[] = {
+	"1",
+	"1/2",
+	"1/4",
+	"1/8",
+	"0",
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_low, WM9081_DRC_3, 0, drc_low_text);
+
+static const char *drc_atk_text[] = {
+	"181us",
+	"181us",
+	"363us",
+	"726us",
+	"1.45ms",
+	"2.9ms",
+	"5.8ms",
+	"11.6ms",
+	"23.2ms",
+	"46.4ms",
+	"92.8ms",
+	"185.6ms",
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_atk, WM9081_DRC_2, 12, drc_atk_text);
+
+static const char *drc_dcy_text[] = {
+	"186ms",
+	"372ms",
+	"743ms",
+	"1.49s",
+	"2.97s",
+	"5.94s",
+	"11.89s",
+	"23.78s",
+	"47.56s",
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_dcy, WM9081_DRC_2, 8, drc_dcy_text);
+
+static const char *drc_qr_dcy_text[] = {
+	"0.725ms",
+	"1.45ms",
+	"5.8ms",
+};
+
+static SOC_ENUM_SINGLE_DECL(drc_qr_dcy, WM9081_DRC_2, 4, drc_qr_dcy_text);
+
+static const char *dac_deemph_text[] = {
+	"None",
+	"32kHz",
+	"44.1kHz",
+	"48kHz",
+};
+
+static SOC_ENUM_SINGLE_DECL(dac_deemph, WM9081_DAC_DIGITAL_2, 1,
+			    dac_deemph_text);
+
+static const char *speaker_mode_text[] = {
+	"Class D",
+	"Class AB",
+};
+
+static SOC_ENUM_SINGLE_DECL(speaker_mode, WM9081_ANALOGUE_SPEAKER_2, 6,
+			    speaker_mode_text);
+
+static int speaker_mode_get(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int reg;
+
+	reg = snd_soc_component_read32(component, WM9081_ANALOGUE_SPEAKER_2);
+	if (reg & WM9081_SPK_MODE)
+		ucontrol->value.enumerated.item[0] = 1;
+	else
+		ucontrol->value.enumerated.item[0] = 0;
+
+	return 0;
+}
+
+/*
+ * Stop any attempts to change speaker mode while the speaker is enabled.
+ *
+ * We also have some special anti-pop controls dependent on speaker
+ * mode which must be changed along with the mode.
+ */
+static int speaker_mode_put(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	unsigned int reg_pwr = snd_soc_component_read32(component, WM9081_POWER_MANAGEMENT);
+	unsigned int reg2 = snd_soc_component_read32(component, WM9081_ANALOGUE_SPEAKER_2);
+
+	/* Are we changing anything? */
+	if (ucontrol->value.enumerated.item[0] ==
+	    ((reg2 & WM9081_SPK_MODE) != 0))
+		return 0;
+
+	/* Don't try to change modes while enabled */
+	if (reg_pwr & WM9081_SPK_ENA)
+		return -EINVAL;
+
+	if (ucontrol->value.enumerated.item[0]) {
+		/* Class AB */
+		reg2 &= ~(WM9081_SPK_INV_MUTE | WM9081_OUT_SPK_CTRL);
+		reg2 |= WM9081_SPK_MODE;
+	} else {
+		/* Class D */
+		reg2 |= WM9081_SPK_INV_MUTE | WM9081_OUT_SPK_CTRL;
+		reg2 &= ~WM9081_SPK_MODE;
+	}
+
+	snd_soc_component_write(component, WM9081_ANALOGUE_SPEAKER_2, reg2);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new wm9081_snd_controls[] = {
+SOC_SINGLE_TLV("IN1 Volume", WM9081_ANALOGUE_MIXER, 1, 1, 1, in_tlv),
+SOC_SINGLE_TLV("IN2 Volume", WM9081_ANALOGUE_MIXER, 3, 1, 1, in_tlv),
+
+SOC_SINGLE_TLV("Playback Volume", WM9081_DAC_DIGITAL_1, 1, 96, 0, dac_tlv),
+
+SOC_SINGLE("LINEOUT Switch", WM9081_ANALOGUE_LINEOUT, 7, 1, 1),
+SOC_SINGLE("LINEOUT ZC Switch", WM9081_ANALOGUE_LINEOUT, 6, 1, 0),
+SOC_SINGLE_TLV("LINEOUT Volume", WM9081_ANALOGUE_LINEOUT, 0, 63, 0, out_tlv),
+
+SOC_SINGLE("DRC Switch", WM9081_DRC_1, 15, 1, 0),
+SOC_ENUM("DRC High Slope", drc_high),
+SOC_ENUM("DRC Low Slope", drc_low),
+SOC_SINGLE_TLV("DRC Input Volume", WM9081_DRC_4, 5, 60, 1, drc_in_tlv),
+SOC_SINGLE_TLV("DRC Output Volume", WM9081_DRC_4, 0, 30, 1, drc_out_tlv),
+SOC_SINGLE_TLV("DRC Minimum Volume", WM9081_DRC_2, 2, 3, 1, drc_min_tlv),
+SOC_SINGLE_TLV("DRC Maximum Volume", WM9081_DRC_2, 0, 3, 0, drc_max_tlv),
+SOC_ENUM("DRC Attack", drc_atk),
+SOC_ENUM("DRC Decay", drc_dcy),
+SOC_SINGLE("DRC Quick Release Switch", WM9081_DRC_1, 2, 1, 0),
+SOC_SINGLE_TLV("DRC Quick Release Volume", WM9081_DRC_2, 6, 3, 0, drc_qr_tlv),
+SOC_ENUM("DRC Quick Release Decay", drc_qr_dcy),
+SOC_SINGLE_TLV("DRC Startup Volume", WM9081_DRC_1, 6, 18, 0, drc_startup_tlv),
+
+SOC_SINGLE("EQ Switch", WM9081_EQ_1, 0, 1, 0),
+
+SOC_SINGLE("Speaker DC Volume", WM9081_ANALOGUE_SPEAKER_1, 3, 5, 0),
+SOC_SINGLE("Speaker AC Volume", WM9081_ANALOGUE_SPEAKER_1, 0, 5, 0),
+SOC_SINGLE("Speaker Switch", WM9081_ANALOGUE_SPEAKER_PGA, 7, 1, 1),
+SOC_SINGLE("Speaker ZC Switch", WM9081_ANALOGUE_SPEAKER_PGA, 6, 1, 0),
+SOC_SINGLE_TLV("Speaker Volume", WM9081_ANALOGUE_SPEAKER_PGA, 0, 63, 0,
+	       out_tlv),
+SOC_ENUM("DAC Deemphasis", dac_deemph),
+SOC_ENUM_EXT("Speaker Mode", speaker_mode, speaker_mode_get, speaker_mode_put),
+};
+
+static const struct snd_kcontrol_new wm9081_eq_controls[] = {
+SOC_SINGLE_TLV("EQ1 Volume", WM9081_EQ_1, 11, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 Volume", WM9081_EQ_1, 6, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 Volume", WM9081_EQ_1, 1, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 Volume", WM9081_EQ_2, 11, 24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ5 Volume", WM9081_EQ_2, 6, 24, 0, eq_tlv),
+};
+
+static const struct snd_kcontrol_new mixer[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM9081_ANALOGUE_MIXER, 0, 1, 0),
+SOC_DAPM_SINGLE("IN2 Switch", WM9081_ANALOGUE_MIXER, 2, 1, 0),
+SOC_DAPM_SINGLE("Playback Switch", WM9081_ANALOGUE_MIXER, 4, 1, 0),
+};
+
+struct _fll_div {
+	u16 fll_fratio;
+	u16 fll_outdiv;
+	u16 fll_clk_ref_div;
+	u16 n;
+	u16 k;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static struct {
+	unsigned int min;
+	unsigned int max;
+	u16 fll_fratio;
+	int ratio;
+} fll_fratios[] = {
+	{       0,    64000, 4, 16 },
+	{   64000,   128000, 3,  8 },
+	{  128000,   256000, 2,  4 },
+	{  256000,  1000000, 1,  2 },
+	{ 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+		       unsigned int Fout)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod, target;
+	unsigned int div;
+	int i;
+
+	/* Fref must be <=13.5MHz */
+	div = 1;
+	while ((Fref / div) > 13500000) {
+		div *= 2;
+
+		if (div > 8) {
+			pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+			       Fref);
+			return -EINVAL;
+		}
+	}
+	fll_div->fll_clk_ref_div = div / 2;
+
+	pr_debug("Fref=%u Fout=%u\n", Fref, Fout);
+
+	/* Apply the division for our remaining calculations */
+	Fref /= div;
+
+	/* Fvco should be 90-100MHz; don't check the upper bound */
+	div = 0;
+	target = Fout * 2;
+	while (target < 90000000) {
+		div++;
+		target *= 2;
+		if (div > 7) {
+			pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+			       Fout);
+			return -EINVAL;
+		}
+	}
+	fll_div->fll_outdiv = div;
+
+	pr_debug("Fvco=%dHz\n", target);
+
+	/* Find an appropriate FLL_FRATIO and factor it out of the target */
+	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+			fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+			target /= fll_fratios[i].ratio;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(fll_fratios)) {
+		pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+		return -EINVAL;
+	}
+
+	/* Now, calculate N.K */
+	Ndiv = target / Fref;
+
+	fll_div->n = Ndiv;
+	Nmod = target % Fref;
+	pr_debug("Nmod=%d\n", Nmod);
+
+	/* Calculate fractional part - scale up so we can round. */
+	Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, Fref);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	fll_div->k = K / 10;
+
+	pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n",
+		 fll_div->n, fll_div->k,
+		 fll_div->fll_fratio, fll_div->fll_outdiv,
+		 fll_div->fll_clk_ref_div);
+
+	return 0;
+}
+
+static int wm9081_set_fll(struct snd_soc_component *component, int fll_id,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
+	u16 reg1, reg4, reg5;
+	struct _fll_div fll_div;
+	int ret;
+	int clk_sys_reg;
+
+	/* Any change? */
+	if (Fref == wm9081->fll_fref && Fout == wm9081->fll_fout)
+		return 0;
+
+	/* Disable the FLL */
+	if (Fout == 0) {
+		dev_dbg(component->dev, "FLL disabled\n");
+		wm9081->fll_fref = 0;
+		wm9081->fll_fout = 0;
+
+		return 0;
+	}
+
+	ret = fll_factors(&fll_div, Fref, Fout);
+	if (ret != 0)
+		return ret;
+
+	reg5 = snd_soc_component_read32(component, WM9081_FLL_CONTROL_5);
+	reg5 &= ~WM9081_FLL_CLK_SRC_MASK;
+
+	switch (fll_id) {
+	case WM9081_SYSCLK_FLL_MCLK:
+		reg5 |= 0x1;
+		break;
+
+	default:
+		dev_err(component->dev, "Unknown FLL ID %d\n", fll_id);
+		return -EINVAL;
+	}
+
+	/* Disable CLK_SYS while we reconfigure */
+	clk_sys_reg = snd_soc_component_read32(component, WM9081_CLOCK_CONTROL_3);
+	if (clk_sys_reg & WM9081_CLK_SYS_ENA)
+		snd_soc_component_write(component, WM9081_CLOCK_CONTROL_3,
+			     clk_sys_reg & ~WM9081_CLK_SYS_ENA);
+
+	/* Any FLL configuration change requires that the FLL be
+	 * disabled first. */
+	reg1 = snd_soc_component_read32(component, WM9081_FLL_CONTROL_1);
+	reg1 &= ~WM9081_FLL_ENA;
+	snd_soc_component_write(component, WM9081_FLL_CONTROL_1, reg1);
+
+	/* Apply the configuration */
+	if (fll_div.k)
+		reg1 |= WM9081_FLL_FRAC_MASK;
+	else
+		reg1 &= ~WM9081_FLL_FRAC_MASK;
+	snd_soc_component_write(component, WM9081_FLL_CONTROL_1, reg1);
+
+	snd_soc_component_write(component, WM9081_FLL_CONTROL_2,
+		     (fll_div.fll_outdiv << WM9081_FLL_OUTDIV_SHIFT) |
+		     (fll_div.fll_fratio << WM9081_FLL_FRATIO_SHIFT));
+	snd_soc_component_write(component, WM9081_FLL_CONTROL_3, fll_div.k);
+
+	reg4 = snd_soc_component_read32(component, WM9081_FLL_CONTROL_4);
+	reg4 &= ~WM9081_FLL_N_MASK;
+	reg4 |= fll_div.n << WM9081_FLL_N_SHIFT;
+	snd_soc_component_write(component, WM9081_FLL_CONTROL_4, reg4);
+
+	reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK;
+	reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT;
+	snd_soc_component_write(component, WM9081_FLL_CONTROL_5, reg5);
+
+	/* Set gain to the recommended value */
+	snd_soc_component_update_bits(component, WM9081_FLL_CONTROL_4,
+			    WM9081_FLL_GAIN_MASK, 0);
+
+	/* Enable the FLL */
+	snd_soc_component_write(component, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA);
+
+	/* Then bring CLK_SYS up again if it was disabled */
+	if (clk_sys_reg & WM9081_CLK_SYS_ENA)
+		snd_soc_component_write(component, WM9081_CLOCK_CONTROL_3, clk_sys_reg);
+
+	dev_dbg(component->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
+
+	wm9081->fll_fref = Fref;
+	wm9081->fll_fout = Fout;
+
+	return 0;
+}
+
+static int configure_clock(struct snd_soc_component *component)
+{
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
+	int new_sysclk, i, target;
+	unsigned int reg;
+	int ret = 0;
+	int mclkdiv = 0;
+	int fll = 0;
+
+	switch (wm9081->sysclk_source) {
+	case WM9081_SYSCLK_MCLK:
+		if (wm9081->mclk_rate > 12225000) {
+			mclkdiv = 1;
+			wm9081->sysclk_rate = wm9081->mclk_rate / 2;
+		} else {
+			wm9081->sysclk_rate = wm9081->mclk_rate;
+		}
+		wm9081_set_fll(component, WM9081_SYSCLK_FLL_MCLK, 0, 0);
+		break;
+
+	case WM9081_SYSCLK_FLL_MCLK:
+		/* If we have a sample rate calculate a CLK_SYS that
+		 * gives us a suitable DAC configuration, plus BCLK.
+		 * Ideally we would check to see if we can clock
+		 * directly from MCLK and only use the FLL if this is
+		 * not the case, though care must be taken with free
+		 * running mode.
+		 */
+		if (wm9081->master && wm9081->bclk) {
+			/* Make sure we can generate CLK_SYS and BCLK
+			 * and that we've got 3MHz for optimal
+			 * performance. */
+			for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) {
+				target = wm9081->fs * clk_sys_rates[i].ratio;
+				new_sysclk = target;
+				if (target >= wm9081->bclk &&
+				    target > 3000000)
+					break;
+			}
+
+			if (i == ARRAY_SIZE(clk_sys_rates))
+				return -EINVAL;
+
+		} else if (wm9081->fs) {
+			for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) {
+				new_sysclk = clk_sys_rates[i].ratio
+					* wm9081->fs;
+				if (new_sysclk > 3000000)
+					break;
+			}
+
+			if (i == ARRAY_SIZE(clk_sys_rates))
+				return -EINVAL;
+
+		} else {
+			new_sysclk = 12288000;
+		}
+
+		ret = wm9081_set_fll(component, WM9081_SYSCLK_FLL_MCLK,
+				     wm9081->mclk_rate, new_sysclk);
+		if (ret == 0) {
+			wm9081->sysclk_rate = new_sysclk;
+
+			/* Switch SYSCLK over to FLL */
+			fll = 1;
+		} else {
+			wm9081->sysclk_rate = wm9081->mclk_rate;
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	reg = snd_soc_component_read32(component, WM9081_CLOCK_CONTROL_1);
+	if (mclkdiv)
+		reg |= WM9081_MCLKDIV2;
+	else
+		reg &= ~WM9081_MCLKDIV2;
+	snd_soc_component_write(component, WM9081_CLOCK_CONTROL_1, reg);
+
+	reg = snd_soc_component_read32(component, WM9081_CLOCK_CONTROL_3);
+	if (fll)
+		reg |= WM9081_CLK_SRC_SEL;
+	else
+		reg &= ~WM9081_CLK_SRC_SEL;
+	snd_soc_component_write(component, WM9081_CLOCK_CONTROL_3, reg);
+
+	dev_dbg(component->dev, "CLK_SYS is %dHz\n", wm9081->sysclk_rate);
+
+	return ret;
+}
+
+static int clk_sys_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
+
+	/* This should be done on init() for bypass paths */
+	switch (wm9081->sysclk_source) {
+	case WM9081_SYSCLK_MCLK:
+		dev_dbg(component->dev, "Using %dHz MCLK\n", wm9081->mclk_rate);
+		break;
+	case WM9081_SYSCLK_FLL_MCLK:
+		dev_dbg(component->dev, "Using %dHz MCLK with FLL\n",
+			wm9081->mclk_rate);
+		break;
+	default:
+		dev_err(component->dev, "System clock not configured\n");
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		configure_clock(component);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		/* Disable the FLL if it's running */
+		wm9081_set_fll(component, 0, 0, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget wm9081_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1"),
+SND_SOC_DAPM_INPUT("IN2"),
+
+SND_SOC_DAPM_DAC("DAC", NULL, WM9081_POWER_MANAGEMENT, 0, 0),
+
+SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0,
+			     mixer, ARRAY_SIZE(mixer)),
+
+SND_SOC_DAPM_PGA("LINEOUT PGA", WM9081_POWER_MANAGEMENT, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0),
+SND_SOC_DAPM_OUT_DRV("Speaker", WM9081_POWER_MANAGEMENT, 1, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("LINEOUT"),
+SND_SOC_DAPM_OUTPUT("SPKN"),
+SND_SOC_DAPM_OUTPUT("SPKP"),
+
+SND_SOC_DAPM_SUPPLY("CLK_SYS", WM9081_CLOCK_CONTROL_3, 0, 0, clk_sys_event,
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("CLK_DSP", WM9081_CLOCK_CONTROL_3, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TOCLK", WM9081_CLOCK_CONTROL_3, 2, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TSENSE", WM9081_POWER_MANAGEMENT, 7, 0, NULL, 0),
+};
+
+
+static const struct snd_soc_dapm_route wm9081_audio_paths[] = {
+	{ "DAC", NULL, "CLK_SYS" },
+	{ "DAC", NULL, "CLK_DSP" },
+	{ "DAC", NULL, "AIF" },
+
+	{ "Mixer", "IN1 Switch", "IN1" },
+	{ "Mixer", "IN2 Switch", "IN2" },
+	{ "Mixer", "Playback Switch", "DAC" },
+
+	{ "LINEOUT PGA", NULL, "Mixer" },
+	{ "LINEOUT PGA", NULL, "TOCLK" },
+	{ "LINEOUT PGA", NULL, "CLK_SYS" },
+
+	{ "LINEOUT", NULL, "LINEOUT PGA" },
+
+	{ "Speaker PGA", NULL, "Mixer" },
+	{ "Speaker PGA", NULL, "TOCLK" },
+	{ "Speaker PGA", NULL, "CLK_SYS" },
+
+	{ "Speaker", NULL, "Speaker PGA" },
+	{ "Speaker", NULL, "TSENSE" },
+
+	{ "SPKN", NULL, "Speaker" },
+	{ "SPKP", NULL, "Speaker" },
+};
+
+static int wm9081_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		/* VMID=2*40k */
+		snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
+				    WM9081_VMID_SEL_MASK, 0x2);
+
+		/* Normal bias current */
+		snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
+				    WM9081_STBY_BIAS_ENA, 0);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		/* Initial cold start */
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			regcache_cache_only(wm9081->regmap, false);
+			regcache_sync(wm9081->regmap);
+
+			/* Disable LINEOUT discharge */
+			snd_soc_component_update_bits(component, WM9081_ANTI_POP_CONTROL,
+					    WM9081_LINEOUT_DISCH, 0);
+
+			/* Select startup bias source */
+			snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
+					    WM9081_BIAS_SRC | WM9081_BIAS_ENA,
+					    WM9081_BIAS_SRC | WM9081_BIAS_ENA);
+
+			/* VMID 2*4k; Soft VMID ramp enable */
+			snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
+					    WM9081_VMID_RAMP |
+					    WM9081_VMID_SEL_MASK,
+					    WM9081_VMID_RAMP | 0x6);
+
+			mdelay(100);
+
+			/* Normal bias enable & soft start off */
+			snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
+					    WM9081_VMID_RAMP, 0);
+
+			/* Standard bias source */
+			snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
+					    WM9081_BIAS_SRC, 0);
+		}
+
+		/* VMID 2*240k */
+		snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
+				    WM9081_VMID_SEL_MASK, 0x04);
+
+		/* Standby bias current on */
+		snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
+				    WM9081_STBY_BIAS_ENA,
+				    WM9081_STBY_BIAS_ENA);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* Startup bias source and disable bias */
+		snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
+				    WM9081_BIAS_SRC | WM9081_BIAS_ENA,
+				    WM9081_BIAS_SRC);
+
+		/* Disable VMID with soft ramping */
+		snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
+				    WM9081_VMID_RAMP | WM9081_VMID_SEL_MASK,
+				    WM9081_VMID_RAMP);
+
+		/* Actively discharge LINEOUT */
+		snd_soc_component_update_bits(component, WM9081_ANTI_POP_CONTROL,
+				    WM9081_LINEOUT_DISCH,
+				    WM9081_LINEOUT_DISCH);
+
+		regcache_cache_only(wm9081->regmap, true);
+		break;
+	}
+
+	return 0;
+}
+
+static int wm9081_set_dai_fmt(struct snd_soc_dai *dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
+	unsigned int aif2 = snd_soc_component_read32(component, WM9081_AUDIO_INTERFACE_2);
+
+	aif2 &= ~(WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV |
+		  WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		wm9081->master = 0;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		aif2 |= WM9081_LRCLK_DIR;
+		wm9081->master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		aif2 |= WM9081_BCLK_DIR;
+		wm9081->master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aif2 |= WM9081_LRCLK_DIR | WM9081_BCLK_DIR;
+		wm9081->master = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_B:
+		aif2 |= WM9081_AIF_LRCLK_INV;
+		/* fall through */
+	case SND_SOC_DAIFMT_DSP_A:
+		aif2 |= 0x3;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aif2 |= 0x2;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif2 |= 0x1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+	case SND_SOC_DAIFMT_DSP_B:
+		/* frame inversion not valid for DSP modes */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif2 |= WM9081_AIF_BCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_RIGHT_J:
+	case SND_SOC_DAIFMT_LEFT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			aif2 |= WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			aif2 |= WM9081_AIF_BCLK_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			aif2 |= WM9081_AIF_LRCLK_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_2, aif2);
+
+	return 0;
+}
+
+static int wm9081_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
+	int ret, i, best, best_val, cur_val;
+	unsigned int clk_ctrl2, aif1, aif2, aif3, aif4;
+
+	clk_ctrl2 = snd_soc_component_read32(component, WM9081_CLOCK_CONTROL_2);
+	clk_ctrl2 &= ~(WM9081_CLK_SYS_RATE_MASK | WM9081_SAMPLE_RATE_MASK);
+
+	aif1 = snd_soc_component_read32(component, WM9081_AUDIO_INTERFACE_1);
+
+	aif2 = snd_soc_component_read32(component, WM9081_AUDIO_INTERFACE_2);
+	aif2 &= ~WM9081_AIF_WL_MASK;
+
+	aif3 = snd_soc_component_read32(component, WM9081_AUDIO_INTERFACE_3);
+	aif3 &= ~WM9081_BCLK_DIV_MASK;
+
+	aif4 = snd_soc_component_read32(component, WM9081_AUDIO_INTERFACE_4);
+	aif4 &= ~WM9081_LRCLK_RATE_MASK;
+
+	wm9081->fs = params_rate(params);
+
+	if (wm9081->tdm_width) {
+		/* If TDM is set up then that fixes our BCLK. */
+		int slots = ((aif1 & WM9081_AIFDAC_TDM_MODE_MASK) >>
+			     WM9081_AIFDAC_TDM_MODE_SHIFT) + 1;
+
+		wm9081->bclk = wm9081->fs * wm9081->tdm_width * slots;
+	} else {
+		/* Otherwise work out a BCLK from the sample size */
+		wm9081->bclk = 2 * wm9081->fs;
+
+		switch (params_width(params)) {
+		case 16:
+			wm9081->bclk *= 16;
+			break;
+		case 20:
+			wm9081->bclk *= 20;
+			aif2 |= 0x4;
+			break;
+		case 24:
+			wm9081->bclk *= 24;
+			aif2 |= 0x8;
+			break;
+		case 32:
+			wm9081->bclk *= 32;
+			aif2 |= 0xc;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	dev_dbg(component->dev, "Target BCLK is %dHz\n", wm9081->bclk);
+
+	ret = configure_clock(component);
+	if (ret != 0)
+		return ret;
+
+	/* Select nearest CLK_SYS_RATE */
+	best = 0;
+	best_val = abs((wm9081->sysclk_rate / clk_sys_rates[0].ratio)
+		       - wm9081->fs);
+	for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) {
+		cur_val = abs((wm9081->sysclk_rate /
+			       clk_sys_rates[i].ratio) - wm9081->fs);
+		if (cur_val < best_val) {
+			best = i;
+			best_val = cur_val;
+		}
+	}
+	dev_dbg(component->dev, "Selected CLK_SYS_RATIO of %d\n",
+		clk_sys_rates[best].ratio);
+	clk_ctrl2 |= (clk_sys_rates[best].clk_sys_rate
+		      << WM9081_CLK_SYS_RATE_SHIFT);
+
+	/* SAMPLE_RATE */
+	best = 0;
+	best_val = abs(wm9081->fs - sample_rates[0].rate);
+	for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
+		/* Closest match */
+		cur_val = abs(wm9081->fs - sample_rates[i].rate);
+		if (cur_val < best_val) {
+			best = i;
+			best_val = cur_val;
+		}
+	}
+	dev_dbg(component->dev, "Selected SAMPLE_RATE of %dHz\n",
+		sample_rates[best].rate);
+	clk_ctrl2 |= (sample_rates[best].sample_rate
+			<< WM9081_SAMPLE_RATE_SHIFT);
+
+	/* BCLK_DIV */
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+		cur_val = ((wm9081->sysclk_rate * 10) / bclk_divs[i].div)
+			- wm9081->bclk;
+		if (cur_val < 0) /* Table is sorted */
+			break;
+		if (cur_val < best_val) {
+			best = i;
+			best_val = cur_val;
+		}
+	}
+	wm9081->bclk = (wm9081->sysclk_rate * 10) / bclk_divs[best].div;
+	dev_dbg(component->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
+		bclk_divs[best].div, wm9081->bclk);
+	aif3 |= bclk_divs[best].bclk_div;
+
+	/* LRCLK is a simple fraction of BCLK */
+	dev_dbg(component->dev, "LRCLK_RATE is %d\n", wm9081->bclk / wm9081->fs);
+	aif4 |= wm9081->bclk / wm9081->fs;
+
+	/* Apply a ReTune Mobile configuration if it's in use */
+	if (wm9081->pdata.num_retune_configs) {
+		struct wm9081_pdata *pdata = &wm9081->pdata;
+		struct wm9081_retune_mobile_setting *s;
+		int eq1;
+
+		best = 0;
+		best_val = abs(pdata->retune_configs[0].rate - wm9081->fs);
+		for (i = 0; i < pdata->num_retune_configs; i++) {
+			cur_val = abs(pdata->retune_configs[i].rate -
+				      wm9081->fs);
+			if (cur_val < best_val) {
+				best_val = cur_val;
+				best = i;
+			}
+		}
+		s = &pdata->retune_configs[best];
+
+		dev_dbg(component->dev, "ReTune Mobile %s tuned for %dHz\n",
+			s->name, s->rate);
+
+		/* If the EQ is enabled then disable it while we write out */
+		eq1 = snd_soc_component_read32(component, WM9081_EQ_1) & WM9081_EQ_ENA;
+		if (eq1 & WM9081_EQ_ENA)
+			snd_soc_component_write(component, WM9081_EQ_1, 0);
+
+		/* Write out the other values */
+		for (i = 1; i < ARRAY_SIZE(s->config); i++)
+			snd_soc_component_write(component, WM9081_EQ_1 + i, s->config[i]);
+
+		eq1 |= (s->config[0] & ~WM9081_EQ_ENA);
+		snd_soc_component_write(component, WM9081_EQ_1, eq1);
+	}
+
+	snd_soc_component_write(component, WM9081_CLOCK_CONTROL_2, clk_ctrl2);
+	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_2, aif2);
+	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_3, aif3);
+	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_4, aif4);
+
+	return 0;
+}
+
+static int wm9081_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	unsigned int reg;
+
+	reg = snd_soc_component_read32(component, WM9081_DAC_DIGITAL_2);
+
+	if (mute)
+		reg |= WM9081_DAC_MUTE;
+	else
+		reg &= ~WM9081_DAC_MUTE;
+
+	snd_soc_component_write(component, WM9081_DAC_DIGITAL_2, reg);
+
+	return 0;
+}
+
+static int wm9081_set_sysclk(struct snd_soc_component *component, int clk_id,
+			     int source, unsigned int freq, int dir)
+{
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
+
+	switch (clk_id) {
+	case WM9081_SYSCLK_MCLK:
+	case WM9081_SYSCLK_FLL_MCLK:
+		wm9081->sysclk_source = clk_id;
+		wm9081->mclk_rate = freq;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
+	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
+	unsigned int aif1 = snd_soc_component_read32(component, WM9081_AUDIO_INTERFACE_1);
+
+	aif1 &= ~(WM9081_AIFDAC_TDM_SLOT_MASK | WM9081_AIFDAC_TDM_MODE_MASK);
+
+	if (slots < 0 || slots > 4)
+		return -EINVAL;
+
+	wm9081->tdm_width = slot_width;
+
+	if (slots == 0)
+		slots = 1;
+
+	aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT;
+
+	switch (rx_mask) {
+	case 1:
+		break;
+	case 2:
+		aif1 |= 0x10;
+		break;
+	case 4:
+		aif1 |= 0x20;
+		break;
+	case 8:
+		aif1 |= 0x30;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_1, aif1);
+
+	return 0;
+}
+
+#define WM9081_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM9081_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops wm9081_dai_ops = {
+	.hw_params = wm9081_hw_params,
+	.set_fmt = wm9081_set_dai_fmt,
+	.digital_mute = wm9081_digital_mute,
+	.set_tdm_slot = wm9081_set_tdm_slot,
+};
+
+/* We report two channels because the CODEC processes a stereo signal, even
+ * though it is only capable of handling a mono output.
+ */
+static struct snd_soc_dai_driver wm9081_dai = {
+	.name = "wm9081-hifi",
+	.playback = {
+		.stream_name = "AIF",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM9081_RATES,
+		.formats = WM9081_FORMATS,
+	},
+	.ops = &wm9081_dai_ops,
+};
+
+static int wm9081_probe(struct snd_soc_component *component)
+{
+	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
+
+	/* Enable zero cross by default */
+	snd_soc_component_update_bits(component, WM9081_ANALOGUE_LINEOUT,
+			    WM9081_LINEOUTZC, WM9081_LINEOUTZC);
+	snd_soc_component_update_bits(component, WM9081_ANALOGUE_SPEAKER_PGA,
+			    WM9081_SPKPGAZC, WM9081_SPKPGAZC);
+
+	if (!wm9081->pdata.num_retune_configs) {
+		dev_dbg(component->dev,
+			"No ReTune Mobile data, using normal EQ\n");
+		snd_soc_add_component_controls(component, wm9081_eq_controls,
+				     ARRAY_SIZE(wm9081_eq_controls));
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm9081 = {
+	.probe			= wm9081_probe,
+	.set_sysclk		= wm9081_set_sysclk,
+	.set_bias_level		= wm9081_set_bias_level,
+	.controls		= wm9081_snd_controls,
+	.num_controls		= ARRAY_SIZE(wm9081_snd_controls),
+	.dapm_widgets		= wm9081_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm9081_dapm_widgets),
+	.dapm_routes		= wm9081_audio_paths,
+	.num_dapm_routes	= ARRAY_SIZE(wm9081_audio_paths),
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm9081_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = WM9081_MAX_REGISTER,
+	.reg_defaults = wm9081_reg,
+	.num_reg_defaults = ARRAY_SIZE(wm9081_reg),
+	.volatile_reg = wm9081_volatile_register,
+	.readable_reg = wm9081_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int wm9081_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm9081_priv *wm9081;
+	unsigned int reg;
+	int ret;
+
+	wm9081 = devm_kzalloc(&i2c->dev, sizeof(struct wm9081_priv),
+			      GFP_KERNEL);
+	if (wm9081 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, wm9081);
+
+	wm9081->regmap = devm_regmap_init_i2c(i2c, &wm9081_regmap);
+	if (IS_ERR(wm9081->regmap)) {
+		ret = PTR_ERR(wm9081->regmap);
+		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(wm9081->regmap, WM9081_SOFTWARE_RESET, &reg);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
+		return ret;
+	}
+	if (reg != 0x9081) {
+		dev_err(&i2c->dev, "Device is not a WM9081: ID=0x%x\n", reg);
+		return -EINVAL;
+	}
+
+	ret = wm9081_reset(wm9081->regmap);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to issue reset\n");
+		return ret;
+	}
+
+	if (dev_get_platdata(&i2c->dev))
+		memcpy(&wm9081->pdata, dev_get_platdata(&i2c->dev),
+		       sizeof(wm9081->pdata));
+
+	reg = 0;
+	if (wm9081->pdata.irq_high)
+		reg |= WM9081_IRQ_POL;
+	if (!wm9081->pdata.irq_cmos)
+		reg |= WM9081_IRQ_OP_CTRL;
+	regmap_update_bits(wm9081->regmap, WM9081_INTERRUPT_CONTROL,
+			   WM9081_IRQ_POL | WM9081_IRQ_OP_CTRL, reg);
+
+	regcache_cache_only(wm9081->regmap, true);
+
+	ret = devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm9081, &wm9081_dai, 1);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int wm9081_i2c_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id wm9081_i2c_id[] = {
+	{ "wm9081", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id);
+
+static struct i2c_driver wm9081_i2c_driver = {
+	.driver = {
+		.name = "wm9081",
+	},
+	.probe =    wm9081_i2c_probe,
+	.remove =   wm9081_i2c_remove,
+	.id_table = wm9081_i2c_id,
+};
+
+module_i2c_driver(wm9081_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM9081 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm9081.h b/sound/soc/codecs/wm9081.h
new file mode 100644
index 0000000..871cccb
--- /dev/null
+++ b/sound/soc/codecs/wm9081.h
@@ -0,0 +1,784 @@
+#ifndef WM9081_H
+#define WM9081_H
+
+/*
+ * wm9081.c  --  WM9081 ALSA SoC Audio driver
+ *
+ * Author: Mark Brown
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <sound/soc.h>
+
+/*
+ * SYSCLK sources
+ */
+#define WM9081_SYSCLK_MCLK      1   /* Use MCLK without FLL */
+#define WM9081_SYSCLK_FLL_MCLK  2   /* Use MCLK, enabling FLL if required */
+
+/*
+ * Register values.
+ */
+#define WM9081_SOFTWARE_RESET                   0x00
+#define WM9081_ANALOGUE_LINEOUT                 0x02
+#define WM9081_ANALOGUE_SPEAKER_PGA             0x03
+#define WM9081_VMID_CONTROL                     0x04
+#define WM9081_BIAS_CONTROL_1                   0x05
+#define WM9081_ANALOGUE_MIXER                   0x07
+#define WM9081_ANTI_POP_CONTROL                 0x08
+#define WM9081_ANALOGUE_SPEAKER_1               0x09
+#define WM9081_ANALOGUE_SPEAKER_2               0x0A
+#define WM9081_POWER_MANAGEMENT                 0x0B
+#define WM9081_CLOCK_CONTROL_1                  0x0C
+#define WM9081_CLOCK_CONTROL_2                  0x0D
+#define WM9081_CLOCK_CONTROL_3                  0x0E
+#define WM9081_FLL_CONTROL_1                    0x10
+#define WM9081_FLL_CONTROL_2                    0x11
+#define WM9081_FLL_CONTROL_3                    0x12
+#define WM9081_FLL_CONTROL_4                    0x13
+#define WM9081_FLL_CONTROL_5                    0x14
+#define WM9081_AUDIO_INTERFACE_1                0x16
+#define WM9081_AUDIO_INTERFACE_2                0x17
+#define WM9081_AUDIO_INTERFACE_3                0x18
+#define WM9081_AUDIO_INTERFACE_4                0x19
+#define WM9081_INTERRUPT_STATUS                 0x1A
+#define WM9081_INTERRUPT_STATUS_MASK            0x1B
+#define WM9081_INTERRUPT_POLARITY               0x1C
+#define WM9081_INTERRUPT_CONTROL                0x1D
+#define WM9081_DAC_DIGITAL_1                    0x1E
+#define WM9081_DAC_DIGITAL_2                    0x1F
+#define WM9081_DRC_1                            0x20
+#define WM9081_DRC_2                            0x21
+#define WM9081_DRC_3                            0x22
+#define WM9081_DRC_4                            0x23
+#define WM9081_WRITE_SEQUENCER_1                0x26
+#define WM9081_WRITE_SEQUENCER_2                0x27
+#define WM9081_MW_SLAVE_1                       0x28
+#define WM9081_EQ_1                             0x2A
+#define WM9081_EQ_2                             0x2B
+#define WM9081_EQ_3                             0x2C
+#define WM9081_EQ_4                             0x2D
+#define WM9081_EQ_5                             0x2E
+#define WM9081_EQ_6                             0x2F
+#define WM9081_EQ_7                             0x30
+#define WM9081_EQ_8                             0x31
+#define WM9081_EQ_9                             0x32
+#define WM9081_EQ_10                            0x33
+#define WM9081_EQ_11                            0x34
+#define WM9081_EQ_12                            0x35
+#define WM9081_EQ_13                            0x36
+#define WM9081_EQ_14                            0x37
+#define WM9081_EQ_15                            0x38
+#define WM9081_EQ_16                            0x39
+#define WM9081_EQ_17                            0x3A
+#define WM9081_EQ_18                            0x3B
+#define WM9081_EQ_19                            0x3C
+#define WM9081_EQ_20                            0x3D
+
+#define WM9081_REGISTER_COUNT                   55
+#define WM9081_MAX_REGISTER                     0x3D
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM9081_SW_RST_DEV_ID1_MASK              0xFFFF  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM9081_SW_RST_DEV_ID1_SHIFT                  0  /* SW_RST_DEV_ID1 - [15:0] */
+#define WM9081_SW_RST_DEV_ID1_WIDTH                 16  /* SW_RST_DEV_ID1 - [15:0] */
+
+/*
+ * R2 (0x02) - Analogue Lineout
+ */
+#define WM9081_LINEOUT_MUTE                     0x0080  /* LINEOUT_MUTE */
+#define WM9081_LINEOUT_MUTE_MASK                0x0080  /* LINEOUT_MUTE */
+#define WM9081_LINEOUT_MUTE_SHIFT                    7  /* LINEOUT_MUTE */
+#define WM9081_LINEOUT_MUTE_WIDTH                    1  /* LINEOUT_MUTE */
+#define WM9081_LINEOUTZC                        0x0040  /* LINEOUTZC */
+#define WM9081_LINEOUTZC_MASK                   0x0040  /* LINEOUTZC */
+#define WM9081_LINEOUTZC_SHIFT                       6  /* LINEOUTZC */
+#define WM9081_LINEOUTZC_WIDTH                       1  /* LINEOUTZC */
+#define WM9081_LINEOUT_VOL_MASK                 0x003F  /* LINEOUT_VOL - [5:0] */
+#define WM9081_LINEOUT_VOL_SHIFT                     0  /* LINEOUT_VOL - [5:0] */
+#define WM9081_LINEOUT_VOL_WIDTH                     6  /* LINEOUT_VOL - [5:0] */
+
+/*
+ * R3 (0x03) - Analogue Speaker PGA
+ */
+#define WM9081_SPKPGA_MUTE                      0x0080  /* SPKPGA_MUTE */
+#define WM9081_SPKPGA_MUTE_MASK                 0x0080  /* SPKPGA_MUTE */
+#define WM9081_SPKPGA_MUTE_SHIFT                     7  /* SPKPGA_MUTE */
+#define WM9081_SPKPGA_MUTE_WIDTH                     1  /* SPKPGA_MUTE */
+#define WM9081_SPKPGAZC                         0x0040  /* SPKPGAZC */
+#define WM9081_SPKPGAZC_MASK                    0x0040  /* SPKPGAZC */
+#define WM9081_SPKPGAZC_SHIFT                        6  /* SPKPGAZC */
+#define WM9081_SPKPGAZC_WIDTH                        1  /* SPKPGAZC */
+#define WM9081_SPKPGA_VOL_MASK                  0x003F  /* SPKPGA_VOL - [5:0] */
+#define WM9081_SPKPGA_VOL_SHIFT                      0  /* SPKPGA_VOL - [5:0] */
+#define WM9081_SPKPGA_VOL_WIDTH                      6  /* SPKPGA_VOL - [5:0] */
+
+/*
+ * R4 (0x04) - VMID Control
+ */
+#define WM9081_VMID_BUF_ENA                     0x0020  /* VMID_BUF_ENA */
+#define WM9081_VMID_BUF_ENA_MASK                0x0020  /* VMID_BUF_ENA */
+#define WM9081_VMID_BUF_ENA_SHIFT                    5  /* VMID_BUF_ENA */
+#define WM9081_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
+#define WM9081_VMID_RAMP                        0x0008  /* VMID_RAMP */
+#define WM9081_VMID_RAMP_MASK                   0x0008  /* VMID_RAMP */
+#define WM9081_VMID_RAMP_SHIFT                       3  /* VMID_RAMP */
+#define WM9081_VMID_RAMP_WIDTH                       1  /* VMID_RAMP */
+#define WM9081_VMID_SEL_MASK                    0x0006  /* VMID_SEL - [2:1] */
+#define WM9081_VMID_SEL_SHIFT                        1  /* VMID_SEL - [2:1] */
+#define WM9081_VMID_SEL_WIDTH                        2  /* VMID_SEL - [2:1] */
+#define WM9081_VMID_FAST_ST                     0x0001  /* VMID_FAST_ST */
+#define WM9081_VMID_FAST_ST_MASK                0x0001  /* VMID_FAST_ST */
+#define WM9081_VMID_FAST_ST_SHIFT                    0  /* VMID_FAST_ST */
+#define WM9081_VMID_FAST_ST_WIDTH                    1  /* VMID_FAST_ST */
+
+/*
+ * R5 (0x05) - Bias Control 1
+ */
+#define WM9081_BIAS_SRC                         0x0040  /* BIAS_SRC */
+#define WM9081_BIAS_SRC_MASK                    0x0040  /* BIAS_SRC */
+#define WM9081_BIAS_SRC_SHIFT                        6  /* BIAS_SRC */
+#define WM9081_BIAS_SRC_WIDTH                        1  /* BIAS_SRC */
+#define WM9081_STBY_BIAS_LVL                    0x0020  /* STBY_BIAS_LVL */
+#define WM9081_STBY_BIAS_LVL_MASK               0x0020  /* STBY_BIAS_LVL */
+#define WM9081_STBY_BIAS_LVL_SHIFT                   5  /* STBY_BIAS_LVL */
+#define WM9081_STBY_BIAS_LVL_WIDTH                   1  /* STBY_BIAS_LVL */
+#define WM9081_STBY_BIAS_ENA                    0x0010  /* STBY_BIAS_ENA */
+#define WM9081_STBY_BIAS_ENA_MASK               0x0010  /* STBY_BIAS_ENA */
+#define WM9081_STBY_BIAS_ENA_SHIFT                   4  /* STBY_BIAS_ENA */
+#define WM9081_STBY_BIAS_ENA_WIDTH                   1  /* STBY_BIAS_ENA */
+#define WM9081_BIAS_LVL_MASK                    0x000C  /* BIAS_LVL - [3:2] */
+#define WM9081_BIAS_LVL_SHIFT                        2  /* BIAS_LVL - [3:2] */
+#define WM9081_BIAS_LVL_WIDTH                        2  /* BIAS_LVL - [3:2] */
+#define WM9081_BIAS_ENA                         0x0002  /* BIAS_ENA */
+#define WM9081_BIAS_ENA_MASK                    0x0002  /* BIAS_ENA */
+#define WM9081_BIAS_ENA_SHIFT                        1  /* BIAS_ENA */
+#define WM9081_BIAS_ENA_WIDTH                        1  /* BIAS_ENA */
+#define WM9081_STARTUP_BIAS_ENA                 0x0001  /* STARTUP_BIAS_ENA */
+#define WM9081_STARTUP_BIAS_ENA_MASK            0x0001  /* STARTUP_BIAS_ENA */
+#define WM9081_STARTUP_BIAS_ENA_SHIFT                0  /* STARTUP_BIAS_ENA */
+#define WM9081_STARTUP_BIAS_ENA_WIDTH                1  /* STARTUP_BIAS_ENA */
+
+/*
+ * R7 (0x07) - Analogue Mixer
+ */
+#define WM9081_DAC_SEL                          0x0010  /* DAC_SEL */
+#define WM9081_DAC_SEL_MASK                     0x0010  /* DAC_SEL */
+#define WM9081_DAC_SEL_SHIFT                         4  /* DAC_SEL */
+#define WM9081_DAC_SEL_WIDTH                         1  /* DAC_SEL */
+#define WM9081_IN2_VOL                          0x0008  /* IN2_VOL */
+#define WM9081_IN2_VOL_MASK                     0x0008  /* IN2_VOL */
+#define WM9081_IN2_VOL_SHIFT                         3  /* IN2_VOL */
+#define WM9081_IN2_VOL_WIDTH                         1  /* IN2_VOL */
+#define WM9081_IN2_ENA                          0x0004  /* IN2_ENA */
+#define WM9081_IN2_ENA_MASK                     0x0004  /* IN2_ENA */
+#define WM9081_IN2_ENA_SHIFT                         2  /* IN2_ENA */
+#define WM9081_IN2_ENA_WIDTH                         1  /* IN2_ENA */
+#define WM9081_IN1_VOL                          0x0002  /* IN1_VOL */
+#define WM9081_IN1_VOL_MASK                     0x0002  /* IN1_VOL */
+#define WM9081_IN1_VOL_SHIFT                         1  /* IN1_VOL */
+#define WM9081_IN1_VOL_WIDTH                         1  /* IN1_VOL */
+#define WM9081_IN1_ENA                          0x0001  /* IN1_ENA */
+#define WM9081_IN1_ENA_MASK                     0x0001  /* IN1_ENA */
+#define WM9081_IN1_ENA_SHIFT                         0  /* IN1_ENA */
+#define WM9081_IN1_ENA_WIDTH                         1  /* IN1_ENA */
+
+/*
+ * R8 (0x08) - Anti Pop Control
+ */
+#define WM9081_LINEOUT_DISCH                    0x0004  /* LINEOUT_DISCH */
+#define WM9081_LINEOUT_DISCH_MASK               0x0004  /* LINEOUT_DISCH */
+#define WM9081_LINEOUT_DISCH_SHIFT                   2  /* LINEOUT_DISCH */
+#define WM9081_LINEOUT_DISCH_WIDTH                   1  /* LINEOUT_DISCH */
+#define WM9081_LINEOUT_VROI                     0x0002  /* LINEOUT_VROI */
+#define WM9081_LINEOUT_VROI_MASK                0x0002  /* LINEOUT_VROI */
+#define WM9081_LINEOUT_VROI_SHIFT                    1  /* LINEOUT_VROI */
+#define WM9081_LINEOUT_VROI_WIDTH                    1  /* LINEOUT_VROI */
+#define WM9081_LINEOUT_CLAMP                    0x0001  /* LINEOUT_CLAMP */
+#define WM9081_LINEOUT_CLAMP_MASK               0x0001  /* LINEOUT_CLAMP */
+#define WM9081_LINEOUT_CLAMP_SHIFT                   0  /* LINEOUT_CLAMP */
+#define WM9081_LINEOUT_CLAMP_WIDTH                   1  /* LINEOUT_CLAMP */
+
+/*
+ * R9 (0x09) - Analogue Speaker 1
+ */
+#define WM9081_SPK_DCGAIN_MASK                  0x0038  /* SPK_DCGAIN - [5:3] */
+#define WM9081_SPK_DCGAIN_SHIFT                      3  /* SPK_DCGAIN - [5:3] */
+#define WM9081_SPK_DCGAIN_WIDTH                      3  /* SPK_DCGAIN - [5:3] */
+#define WM9081_SPK_ACGAIN_MASK                  0x0007  /* SPK_ACGAIN - [2:0] */
+#define WM9081_SPK_ACGAIN_SHIFT                      0  /* SPK_ACGAIN - [2:0] */
+#define WM9081_SPK_ACGAIN_WIDTH                      3  /* SPK_ACGAIN - [2:0] */
+
+/*
+ * R10 (0x0A) - Analogue Speaker 2
+ */
+#define WM9081_SPK_MODE                         0x0040  /* SPK_MODE */
+#define WM9081_SPK_MODE_MASK                    0x0040  /* SPK_MODE */
+#define WM9081_SPK_MODE_SHIFT                        6  /* SPK_MODE */
+#define WM9081_SPK_MODE_WIDTH                        1  /* SPK_MODE */
+#define WM9081_SPK_INV_MUTE                     0x0010  /* SPK_INV_MUTE */
+#define WM9081_SPK_INV_MUTE_MASK                0x0010  /* SPK_INV_MUTE */
+#define WM9081_SPK_INV_MUTE_SHIFT                    4  /* SPK_INV_MUTE */
+#define WM9081_SPK_INV_MUTE_WIDTH                    1  /* SPK_INV_MUTE */
+#define WM9081_OUT_SPK_CTRL                     0x0008  /* OUT_SPK_CTRL */
+#define WM9081_OUT_SPK_CTRL_MASK                0x0008  /* OUT_SPK_CTRL */
+#define WM9081_OUT_SPK_CTRL_SHIFT                    3  /* OUT_SPK_CTRL */
+#define WM9081_OUT_SPK_CTRL_WIDTH                    1  /* OUT_SPK_CTRL */
+
+/*
+ * R11 (0x0B) - Power Management
+ */
+#define WM9081_TSHUT_ENA                        0x0100  /* TSHUT_ENA */
+#define WM9081_TSHUT_ENA_MASK                   0x0100  /* TSHUT_ENA */
+#define WM9081_TSHUT_ENA_SHIFT                       8  /* TSHUT_ENA */
+#define WM9081_TSHUT_ENA_WIDTH                       1  /* TSHUT_ENA */
+#define WM9081_TSENSE_ENA                       0x0080  /* TSENSE_ENA */
+#define WM9081_TSENSE_ENA_MASK                  0x0080  /* TSENSE_ENA */
+#define WM9081_TSENSE_ENA_SHIFT                      7  /* TSENSE_ENA */
+#define WM9081_TSENSE_ENA_WIDTH                      1  /* TSENSE_ENA */
+#define WM9081_TEMP_SHUT                        0x0040  /* TEMP_SHUT */
+#define WM9081_TEMP_SHUT_MASK                   0x0040  /* TEMP_SHUT */
+#define WM9081_TEMP_SHUT_SHIFT                       6  /* TEMP_SHUT */
+#define WM9081_TEMP_SHUT_WIDTH                       1  /* TEMP_SHUT */
+#define WM9081_LINEOUT_ENA                      0x0010  /* LINEOUT_ENA */
+#define WM9081_LINEOUT_ENA_MASK                 0x0010  /* LINEOUT_ENA */
+#define WM9081_LINEOUT_ENA_SHIFT                     4  /* LINEOUT_ENA */
+#define WM9081_LINEOUT_ENA_WIDTH                     1  /* LINEOUT_ENA */
+#define WM9081_SPKPGA_ENA                       0x0004  /* SPKPGA_ENA */
+#define WM9081_SPKPGA_ENA_MASK                  0x0004  /* SPKPGA_ENA */
+#define WM9081_SPKPGA_ENA_SHIFT                      2  /* SPKPGA_ENA */
+#define WM9081_SPKPGA_ENA_WIDTH                      1  /* SPKPGA_ENA */
+#define WM9081_SPK_ENA                          0x0002  /* SPK_ENA */
+#define WM9081_SPK_ENA_MASK                     0x0002  /* SPK_ENA */
+#define WM9081_SPK_ENA_SHIFT                         1  /* SPK_ENA */
+#define WM9081_SPK_ENA_WIDTH                         1  /* SPK_ENA */
+#define WM9081_DAC_ENA                          0x0001  /* DAC_ENA */
+#define WM9081_DAC_ENA_MASK                     0x0001  /* DAC_ENA */
+#define WM9081_DAC_ENA_SHIFT                         0  /* DAC_ENA */
+#define WM9081_DAC_ENA_WIDTH                         1  /* DAC_ENA */
+
+/*
+ * R12 (0x0C) - Clock Control 1
+ */
+#define WM9081_CLK_OP_DIV_MASK                  0x1C00  /* CLK_OP_DIV - [12:10] */
+#define WM9081_CLK_OP_DIV_SHIFT                     10  /* CLK_OP_DIV - [12:10] */
+#define WM9081_CLK_OP_DIV_WIDTH                      3  /* CLK_OP_DIV - [12:10] */
+#define WM9081_CLK_TO_DIV_MASK                  0x0300  /* CLK_TO_DIV - [9:8] */
+#define WM9081_CLK_TO_DIV_SHIFT                      8  /* CLK_TO_DIV - [9:8] */
+#define WM9081_CLK_TO_DIV_WIDTH                      2  /* CLK_TO_DIV - [9:8] */
+#define WM9081_MCLKDIV2                         0x0080  /* MCLKDIV2 */
+#define WM9081_MCLKDIV2_MASK                    0x0080  /* MCLKDIV2 */
+#define WM9081_MCLKDIV2_SHIFT                        7  /* MCLKDIV2 */
+#define WM9081_MCLKDIV2_WIDTH                        1  /* MCLKDIV2 */
+
+/*
+ * R13 (0x0D) - Clock Control 2
+ */
+#define WM9081_CLK_SYS_RATE_MASK                0x00F0  /* CLK_SYS_RATE - [7:4] */
+#define WM9081_CLK_SYS_RATE_SHIFT                    4  /* CLK_SYS_RATE - [7:4] */
+#define WM9081_CLK_SYS_RATE_WIDTH                    4  /* CLK_SYS_RATE - [7:4] */
+#define WM9081_SAMPLE_RATE_MASK                 0x000F  /* SAMPLE_RATE - [3:0] */
+#define WM9081_SAMPLE_RATE_SHIFT                     0  /* SAMPLE_RATE - [3:0] */
+#define WM9081_SAMPLE_RATE_WIDTH                     4  /* SAMPLE_RATE - [3:0] */
+
+/*
+ * R14 (0x0E) - Clock Control 3
+ */
+#define WM9081_CLK_SRC_SEL                      0x2000  /* CLK_SRC_SEL */
+#define WM9081_CLK_SRC_SEL_MASK                 0x2000  /* CLK_SRC_SEL */
+#define WM9081_CLK_SRC_SEL_SHIFT                    13  /* CLK_SRC_SEL */
+#define WM9081_CLK_SRC_SEL_WIDTH                     1  /* CLK_SRC_SEL */
+#define WM9081_CLK_OP_ENA                       0x0020  /* CLK_OP_ENA */
+#define WM9081_CLK_OP_ENA_MASK                  0x0020  /* CLK_OP_ENA */
+#define WM9081_CLK_OP_ENA_SHIFT                      5  /* CLK_OP_ENA */
+#define WM9081_CLK_OP_ENA_WIDTH                      1  /* CLK_OP_ENA */
+#define WM9081_CLK_TO_ENA                       0x0004  /* CLK_TO_ENA */
+#define WM9081_CLK_TO_ENA_MASK                  0x0004  /* CLK_TO_ENA */
+#define WM9081_CLK_TO_ENA_SHIFT                      2  /* CLK_TO_ENA */
+#define WM9081_CLK_TO_ENA_WIDTH                      1  /* CLK_TO_ENA */
+#define WM9081_CLK_DSP_ENA                      0x0002  /* CLK_DSP_ENA */
+#define WM9081_CLK_DSP_ENA_MASK                 0x0002  /* CLK_DSP_ENA */
+#define WM9081_CLK_DSP_ENA_SHIFT                     1  /* CLK_DSP_ENA */
+#define WM9081_CLK_DSP_ENA_WIDTH                     1  /* CLK_DSP_ENA */
+#define WM9081_CLK_SYS_ENA                      0x0001  /* CLK_SYS_ENA */
+#define WM9081_CLK_SYS_ENA_MASK                 0x0001  /* CLK_SYS_ENA */
+#define WM9081_CLK_SYS_ENA_SHIFT                     0  /* CLK_SYS_ENA */
+#define WM9081_CLK_SYS_ENA_WIDTH                     1  /* CLK_SYS_ENA */
+
+/*
+ * R16 (0x10) - FLL Control 1
+ */
+#define WM9081_FLL_HOLD                         0x0008  /* FLL_HOLD */
+#define WM9081_FLL_HOLD_MASK                    0x0008  /* FLL_HOLD */
+#define WM9081_FLL_HOLD_SHIFT                        3  /* FLL_HOLD */
+#define WM9081_FLL_HOLD_WIDTH                        1  /* FLL_HOLD */
+#define WM9081_FLL_FRAC                         0x0004  /* FLL_FRAC */
+#define WM9081_FLL_FRAC_MASK                    0x0004  /* FLL_FRAC */
+#define WM9081_FLL_FRAC_SHIFT                        2  /* FLL_FRAC */
+#define WM9081_FLL_FRAC_WIDTH                        1  /* FLL_FRAC */
+#define WM9081_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM9081_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM9081_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM9081_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R17 (0x11) - FLL Control 2
+ */
+#define WM9081_FLL_OUTDIV_MASK                  0x0700  /* FLL_OUTDIV - [10:8] */
+#define WM9081_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [10:8] */
+#define WM9081_FLL_OUTDIV_WIDTH                      3  /* FLL_OUTDIV - [10:8] */
+#define WM9081_FLL_CTRL_RATE_MASK               0x0070  /* FLL_CTRL_RATE - [6:4] */
+#define WM9081_FLL_CTRL_RATE_SHIFT                   4  /* FLL_CTRL_RATE - [6:4] */
+#define WM9081_FLL_CTRL_RATE_WIDTH                   3  /* FLL_CTRL_RATE - [6:4] */
+#define WM9081_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM9081_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM9081_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R18 (0x12) - FLL Control 3
+ */
+#define WM9081_FLL_K_MASK                       0xFFFF  /* FLL_K - [15:0] */
+#define WM9081_FLL_K_SHIFT                           0  /* FLL_K - [15:0] */
+#define WM9081_FLL_K_WIDTH                          16  /* FLL_K - [15:0] */
+
+/*
+ * R19 (0x13) - FLL Control 4
+ */
+#define WM9081_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM9081_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM9081_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM9081_FLL_GAIN_MASK                    0x000F  /* FLL_GAIN - [3:0] */
+#define WM9081_FLL_GAIN_SHIFT                        0  /* FLL_GAIN - [3:0] */
+#define WM9081_FLL_GAIN_WIDTH                        4  /* FLL_GAIN - [3:0] */
+
+/*
+ * R20 (0x14) - FLL Control 5
+ */
+#define WM9081_FLL_CLK_REF_DIV_MASK             0x0018  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM9081_FLL_CLK_REF_DIV_SHIFT                 3  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM9081_FLL_CLK_REF_DIV_WIDTH                 2  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM9081_FLL_CLK_SRC_MASK                 0x0003  /* FLL_CLK_SRC - [1:0] */
+#define WM9081_FLL_CLK_SRC_SHIFT                     0  /* FLL_CLK_SRC - [1:0] */
+#define WM9081_FLL_CLK_SRC_WIDTH                     2  /* FLL_CLK_SRC - [1:0] */
+
+/*
+ * R22 (0x16) - Audio Interface 1
+ */
+#define WM9081_AIFDAC_CHAN                      0x0040  /* AIFDAC_CHAN */
+#define WM9081_AIFDAC_CHAN_MASK                 0x0040  /* AIFDAC_CHAN */
+#define WM9081_AIFDAC_CHAN_SHIFT                     6  /* AIFDAC_CHAN */
+#define WM9081_AIFDAC_CHAN_WIDTH                     1  /* AIFDAC_CHAN */
+#define WM9081_AIFDAC_TDM_SLOT_MASK             0x0030  /* AIFDAC_TDM_SLOT - [5:4] */
+#define WM9081_AIFDAC_TDM_SLOT_SHIFT                 4  /* AIFDAC_TDM_SLOT - [5:4] */
+#define WM9081_AIFDAC_TDM_SLOT_WIDTH                 2  /* AIFDAC_TDM_SLOT - [5:4] */
+#define WM9081_AIFDAC_TDM_MODE_MASK             0x000C  /* AIFDAC_TDM_MODE - [3:2] */
+#define WM9081_AIFDAC_TDM_MODE_SHIFT                 2  /* AIFDAC_TDM_MODE - [3:2] */
+#define WM9081_AIFDAC_TDM_MODE_WIDTH                 2  /* AIFDAC_TDM_MODE - [3:2] */
+#define WM9081_DAC_COMP                         0x0002  /* DAC_COMP */
+#define WM9081_DAC_COMP_MASK                    0x0002  /* DAC_COMP */
+#define WM9081_DAC_COMP_SHIFT                        1  /* DAC_COMP */
+#define WM9081_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM9081_DAC_COMPMODE                     0x0001  /* DAC_COMPMODE */
+#define WM9081_DAC_COMPMODE_MASK                0x0001  /* DAC_COMPMODE */
+#define WM9081_DAC_COMPMODE_SHIFT                    0  /* DAC_COMPMODE */
+#define WM9081_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+
+/*
+ * R23 (0x17) - Audio Interface 2
+ */
+#define WM9081_AIF_TRIS                         0x0200  /* AIF_TRIS */
+#define WM9081_AIF_TRIS_MASK                    0x0200  /* AIF_TRIS */
+#define WM9081_AIF_TRIS_SHIFT                        9  /* AIF_TRIS */
+#define WM9081_AIF_TRIS_WIDTH                        1  /* AIF_TRIS */
+#define WM9081_DAC_DAT_INV                      0x0100  /* DAC_DAT_INV */
+#define WM9081_DAC_DAT_INV_MASK                 0x0100  /* DAC_DAT_INV */
+#define WM9081_DAC_DAT_INV_SHIFT                     8  /* DAC_DAT_INV */
+#define WM9081_DAC_DAT_INV_WIDTH                     1  /* DAC_DAT_INV */
+#define WM9081_AIF_BCLK_INV                     0x0080  /* AIF_BCLK_INV */
+#define WM9081_AIF_BCLK_INV_MASK                0x0080  /* AIF_BCLK_INV */
+#define WM9081_AIF_BCLK_INV_SHIFT                    7  /* AIF_BCLK_INV */
+#define WM9081_AIF_BCLK_INV_WIDTH                    1  /* AIF_BCLK_INV */
+#define WM9081_BCLK_DIR                         0x0040  /* BCLK_DIR */
+#define WM9081_BCLK_DIR_MASK                    0x0040  /* BCLK_DIR */
+#define WM9081_BCLK_DIR_SHIFT                        6  /* BCLK_DIR */
+#define WM9081_BCLK_DIR_WIDTH                        1  /* BCLK_DIR */
+#define WM9081_LRCLK_DIR                        0x0020  /* LRCLK_DIR */
+#define WM9081_LRCLK_DIR_MASK                   0x0020  /* LRCLK_DIR */
+#define WM9081_LRCLK_DIR_SHIFT                       5  /* LRCLK_DIR */
+#define WM9081_LRCLK_DIR_WIDTH                       1  /* LRCLK_DIR */
+#define WM9081_AIF_LRCLK_INV                    0x0010  /* AIF_LRCLK_INV */
+#define WM9081_AIF_LRCLK_INV_MASK               0x0010  /* AIF_LRCLK_INV */
+#define WM9081_AIF_LRCLK_INV_SHIFT                   4  /* AIF_LRCLK_INV */
+#define WM9081_AIF_LRCLK_INV_WIDTH                   1  /* AIF_LRCLK_INV */
+#define WM9081_AIF_WL_MASK                      0x000C  /* AIF_WL - [3:2] */
+#define WM9081_AIF_WL_SHIFT                          2  /* AIF_WL - [3:2] */
+#define WM9081_AIF_WL_WIDTH                          2  /* AIF_WL - [3:2] */
+#define WM9081_AIF_FMT_MASK                     0x0003  /* AIF_FMT - [1:0] */
+#define WM9081_AIF_FMT_SHIFT                         0  /* AIF_FMT - [1:0] */
+#define WM9081_AIF_FMT_WIDTH                         2  /* AIF_FMT - [1:0] */
+
+/*
+ * R24 (0x18) - Audio Interface 3
+ */
+#define WM9081_BCLK_DIV_MASK                    0x001F  /* BCLK_DIV - [4:0] */
+#define WM9081_BCLK_DIV_SHIFT                        0  /* BCLK_DIV - [4:0] */
+#define WM9081_BCLK_DIV_WIDTH                        5  /* BCLK_DIV - [4:0] */
+
+/*
+ * R25 (0x19) - Audio Interface 4
+ */
+#define WM9081_LRCLK_RATE_MASK                  0x07FF  /* LRCLK_RATE - [10:0] */
+#define WM9081_LRCLK_RATE_SHIFT                      0  /* LRCLK_RATE - [10:0] */
+#define WM9081_LRCLK_RATE_WIDTH                     11  /* LRCLK_RATE - [10:0] */
+
+/*
+ * R26 (0x1A) - Interrupt Status
+ */
+#define WM9081_WSEQ_BUSY_EINT                   0x0004  /* WSEQ_BUSY_EINT */
+#define WM9081_WSEQ_BUSY_EINT_MASK              0x0004  /* WSEQ_BUSY_EINT */
+#define WM9081_WSEQ_BUSY_EINT_SHIFT                  2  /* WSEQ_BUSY_EINT */
+#define WM9081_WSEQ_BUSY_EINT_WIDTH                  1  /* WSEQ_BUSY_EINT */
+#define WM9081_TSHUT_EINT                       0x0001  /* TSHUT_EINT */
+#define WM9081_TSHUT_EINT_MASK                  0x0001  /* TSHUT_EINT */
+#define WM9081_TSHUT_EINT_SHIFT                      0  /* TSHUT_EINT */
+#define WM9081_TSHUT_EINT_WIDTH                      1  /* TSHUT_EINT */
+
+/*
+ * R27 (0x1B) - Interrupt Status Mask
+ */
+#define WM9081_IM_WSEQ_BUSY_EINT                0x0004  /* IM_WSEQ_BUSY_EINT */
+#define WM9081_IM_WSEQ_BUSY_EINT_MASK           0x0004  /* IM_WSEQ_BUSY_EINT */
+#define WM9081_IM_WSEQ_BUSY_EINT_SHIFT               2  /* IM_WSEQ_BUSY_EINT */
+#define WM9081_IM_WSEQ_BUSY_EINT_WIDTH               1  /* IM_WSEQ_BUSY_EINT */
+#define WM9081_IM_TSHUT_EINT                    0x0001  /* IM_TSHUT_EINT */
+#define WM9081_IM_TSHUT_EINT_MASK               0x0001  /* IM_TSHUT_EINT */
+#define WM9081_IM_TSHUT_EINT_SHIFT                   0  /* IM_TSHUT_EINT */
+#define WM9081_IM_TSHUT_EINT_WIDTH                   1  /* IM_TSHUT_EINT */
+
+/*
+ * R28 (0x1C) - Interrupt Polarity
+ */
+#define WM9081_TSHUT_INV                        0x0001  /* TSHUT_INV */
+#define WM9081_TSHUT_INV_MASK                   0x0001  /* TSHUT_INV */
+#define WM9081_TSHUT_INV_SHIFT                       0  /* TSHUT_INV */
+#define WM9081_TSHUT_INV_WIDTH                       1  /* TSHUT_INV */
+
+/*
+ * R29 (0x1D) - Interrupt Control
+ */
+#define WM9081_IRQ_POL                          0x8000  /* IRQ_POL */
+#define WM9081_IRQ_POL_MASK                     0x8000  /* IRQ_POL */
+#define WM9081_IRQ_POL_SHIFT                        15  /* IRQ_POL */
+#define WM9081_IRQ_POL_WIDTH                         1  /* IRQ_POL */
+#define WM9081_IRQ_OP_CTRL                      0x0001  /* IRQ_OP_CTRL */
+#define WM9081_IRQ_OP_CTRL_MASK                 0x0001  /* IRQ_OP_CTRL */
+#define WM9081_IRQ_OP_CTRL_SHIFT                     0  /* IRQ_OP_CTRL */
+#define WM9081_IRQ_OP_CTRL_WIDTH                     1  /* IRQ_OP_CTRL */
+
+/*
+ * R30 (0x1E) - DAC Digital 1
+ */
+#define WM9081_DAC_VOL_MASK                     0x00FF  /* DAC_VOL - [7:0] */
+#define WM9081_DAC_VOL_SHIFT                         0  /* DAC_VOL - [7:0] */
+#define WM9081_DAC_VOL_WIDTH                         8  /* DAC_VOL - [7:0] */
+
+/*
+ * R31 (0x1F) - DAC Digital 2
+ */
+#define WM9081_DAC_MUTERATE                     0x0400  /* DAC_MUTERATE */
+#define WM9081_DAC_MUTERATE_MASK                0x0400  /* DAC_MUTERATE */
+#define WM9081_DAC_MUTERATE_SHIFT                   10  /* DAC_MUTERATE */
+#define WM9081_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM9081_DAC_MUTEMODE                     0x0200  /* DAC_MUTEMODE */
+#define WM9081_DAC_MUTEMODE_MASK                0x0200  /* DAC_MUTEMODE */
+#define WM9081_DAC_MUTEMODE_SHIFT                    9  /* DAC_MUTEMODE */
+#define WM9081_DAC_MUTEMODE_WIDTH                    1  /* DAC_MUTEMODE */
+#define WM9081_DAC_MUTE                         0x0008  /* DAC_MUTE */
+#define WM9081_DAC_MUTE_MASK                    0x0008  /* DAC_MUTE */
+#define WM9081_DAC_MUTE_SHIFT                        3  /* DAC_MUTE */
+#define WM9081_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM9081_DEEMPH_MASK                      0x0006  /* DEEMPH - [2:1] */
+#define WM9081_DEEMPH_SHIFT                          1  /* DEEMPH - [2:1] */
+#define WM9081_DEEMPH_WIDTH                          2  /* DEEMPH - [2:1] */
+
+/*
+ * R32 (0x20) - DRC 1
+ */
+#define WM9081_DRC_ENA                          0x8000  /* DRC_ENA */
+#define WM9081_DRC_ENA_MASK                     0x8000  /* DRC_ENA */
+#define WM9081_DRC_ENA_SHIFT                        15  /* DRC_ENA */
+#define WM9081_DRC_ENA_WIDTH                         1  /* DRC_ENA */
+#define WM9081_DRC_STARTUP_GAIN_MASK            0x07C0  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM9081_DRC_STARTUP_GAIN_SHIFT                6  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM9081_DRC_STARTUP_GAIN_WIDTH                5  /* DRC_STARTUP_GAIN - [10:6] */
+#define WM9081_DRC_FF_DLY                       0x0020  /* DRC_FF_DLY */
+#define WM9081_DRC_FF_DLY_MASK                  0x0020  /* DRC_FF_DLY */
+#define WM9081_DRC_FF_DLY_SHIFT                      5  /* DRC_FF_DLY */
+#define WM9081_DRC_FF_DLY_WIDTH                      1  /* DRC_FF_DLY */
+#define WM9081_DRC_QR                           0x0004  /* DRC_QR */
+#define WM9081_DRC_QR_MASK                      0x0004  /* DRC_QR */
+#define WM9081_DRC_QR_SHIFT                          2  /* DRC_QR */
+#define WM9081_DRC_QR_WIDTH                          1  /* DRC_QR */
+#define WM9081_DRC_ANTICLIP                     0x0002  /* DRC_ANTICLIP */
+#define WM9081_DRC_ANTICLIP_MASK                0x0002  /* DRC_ANTICLIP */
+#define WM9081_DRC_ANTICLIP_SHIFT                    1  /* DRC_ANTICLIP */
+#define WM9081_DRC_ANTICLIP_WIDTH                    1  /* DRC_ANTICLIP */
+
+/*
+ * R33 (0x21) - DRC 2
+ */
+#define WM9081_DRC_ATK_MASK                     0xF000  /* DRC_ATK - [15:12] */
+#define WM9081_DRC_ATK_SHIFT                        12  /* DRC_ATK - [15:12] */
+#define WM9081_DRC_ATK_WIDTH                         4  /* DRC_ATK - [15:12] */
+#define WM9081_DRC_DCY_MASK                     0x0F00  /* DRC_DCY - [11:8] */
+#define WM9081_DRC_DCY_SHIFT                         8  /* DRC_DCY - [11:8] */
+#define WM9081_DRC_DCY_WIDTH                         4  /* DRC_DCY - [11:8] */
+#define WM9081_DRC_QR_THR_MASK                  0x00C0  /* DRC_QR_THR - [7:6] */
+#define WM9081_DRC_QR_THR_SHIFT                      6  /* DRC_QR_THR - [7:6] */
+#define WM9081_DRC_QR_THR_WIDTH                      2  /* DRC_QR_THR - [7:6] */
+#define WM9081_DRC_QR_DCY_MASK                  0x0030  /* DRC_QR_DCY - [5:4] */
+#define WM9081_DRC_QR_DCY_SHIFT                      4  /* DRC_QR_DCY - [5:4] */
+#define WM9081_DRC_QR_DCY_WIDTH                      2  /* DRC_QR_DCY - [5:4] */
+#define WM9081_DRC_MINGAIN_MASK                 0x000C  /* DRC_MINGAIN - [3:2] */
+#define WM9081_DRC_MINGAIN_SHIFT                     2  /* DRC_MINGAIN - [3:2] */
+#define WM9081_DRC_MINGAIN_WIDTH                     2  /* DRC_MINGAIN - [3:2] */
+#define WM9081_DRC_MAXGAIN_MASK                 0x0003  /* DRC_MAXGAIN - [1:0] */
+#define WM9081_DRC_MAXGAIN_SHIFT                     0  /* DRC_MAXGAIN - [1:0] */
+#define WM9081_DRC_MAXGAIN_WIDTH                     2  /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R34 (0x22) - DRC 3
+ */
+#define WM9081_DRC_HI_COMP_MASK                 0x0038  /* DRC_HI_COMP - [5:3] */
+#define WM9081_DRC_HI_COMP_SHIFT                     3  /* DRC_HI_COMP - [5:3] */
+#define WM9081_DRC_HI_COMP_WIDTH                     3  /* DRC_HI_COMP - [5:3] */
+#define WM9081_DRC_LO_COMP_MASK                 0x0007  /* DRC_LO_COMP - [2:0] */
+#define WM9081_DRC_LO_COMP_SHIFT                     0  /* DRC_LO_COMP - [2:0] */
+#define WM9081_DRC_LO_COMP_WIDTH                     3  /* DRC_LO_COMP - [2:0] */
+
+/*
+ * R35 (0x23) - DRC 4
+ */
+#define WM9081_DRC_KNEE_IP_MASK                 0x07E0  /* DRC_KNEE_IP - [10:5] */
+#define WM9081_DRC_KNEE_IP_SHIFT                     5  /* DRC_KNEE_IP - [10:5] */
+#define WM9081_DRC_KNEE_IP_WIDTH                     6  /* DRC_KNEE_IP - [10:5] */
+#define WM9081_DRC_KNEE_OP_MASK                 0x001F  /* DRC_KNEE_OP - [4:0] */
+#define WM9081_DRC_KNEE_OP_SHIFT                     0  /* DRC_KNEE_OP - [4:0] */
+#define WM9081_DRC_KNEE_OP_WIDTH                     5  /* DRC_KNEE_OP - [4:0] */
+
+/*
+ * R38 (0x26) - Write Sequencer 1
+ */
+#define WM9081_WSEQ_ENA                         0x8000  /* WSEQ_ENA */
+#define WM9081_WSEQ_ENA_MASK                    0x8000  /* WSEQ_ENA */
+#define WM9081_WSEQ_ENA_SHIFT                       15  /* WSEQ_ENA */
+#define WM9081_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM9081_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM9081_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM9081_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM9081_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM9081_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM9081_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM9081_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM9081_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM9081_WSEQ_START_INDEX_MASK            0x007F  /* WSEQ_START_INDEX - [6:0] */
+#define WM9081_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [6:0] */
+#define WM9081_WSEQ_START_INDEX_WIDTH                7  /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R39 (0x27) - Write Sequencer 2
+ */
+#define WM9081_WSEQ_CURRENT_INDEX_MASK          0x07F0  /* WSEQ_CURRENT_INDEX - [10:4] */
+#define WM9081_WSEQ_CURRENT_INDEX_SHIFT              4  /* WSEQ_CURRENT_INDEX - [10:4] */
+#define WM9081_WSEQ_CURRENT_INDEX_WIDTH              7  /* WSEQ_CURRENT_INDEX - [10:4] */
+#define WM9081_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM9081_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM9081_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM9081_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R40 (0x28) - MW Slave 1
+ */
+#define WM9081_SPI_CFG                          0x0020  /* SPI_CFG */
+#define WM9081_SPI_CFG_MASK                     0x0020  /* SPI_CFG */
+#define WM9081_SPI_CFG_SHIFT                         5  /* SPI_CFG */
+#define WM9081_SPI_CFG_WIDTH                         1  /* SPI_CFG */
+#define WM9081_SPI_4WIRE                        0x0010  /* SPI_4WIRE */
+#define WM9081_SPI_4WIRE_MASK                   0x0010  /* SPI_4WIRE */
+#define WM9081_SPI_4WIRE_SHIFT                       4  /* SPI_4WIRE */
+#define WM9081_SPI_4WIRE_WIDTH                       1  /* SPI_4WIRE */
+#define WM9081_ARA_ENA                          0x0008  /* ARA_ENA */
+#define WM9081_ARA_ENA_MASK                     0x0008  /* ARA_ENA */
+#define WM9081_ARA_ENA_SHIFT                         3  /* ARA_ENA */
+#define WM9081_ARA_ENA_WIDTH                         1  /* ARA_ENA */
+#define WM9081_AUTO_INC                         0x0002  /* AUTO_INC */
+#define WM9081_AUTO_INC_MASK                    0x0002  /* AUTO_INC */
+#define WM9081_AUTO_INC_SHIFT                        1  /* AUTO_INC */
+#define WM9081_AUTO_INC_WIDTH                        1  /* AUTO_INC */
+
+/*
+ * R42 (0x2A) - EQ 1
+ */
+#define WM9081_EQ_B1_GAIN_MASK                  0xF800  /* EQ_B1_GAIN - [15:11] */
+#define WM9081_EQ_B1_GAIN_SHIFT                     11  /* EQ_B1_GAIN - [15:11] */
+#define WM9081_EQ_B1_GAIN_WIDTH                      5  /* EQ_B1_GAIN - [15:11] */
+#define WM9081_EQ_B2_GAIN_MASK                  0x07C0  /* EQ_B2_GAIN - [10:6] */
+#define WM9081_EQ_B2_GAIN_SHIFT                      6  /* EQ_B2_GAIN - [10:6] */
+#define WM9081_EQ_B2_GAIN_WIDTH                      5  /* EQ_B2_GAIN - [10:6] */
+#define WM9081_EQ_B4_GAIN_MASK                  0x003E  /* EQ_B4_GAIN - [5:1] */
+#define WM9081_EQ_B4_GAIN_SHIFT                      1  /* EQ_B4_GAIN - [5:1] */
+#define WM9081_EQ_B4_GAIN_WIDTH                      5  /* EQ_B4_GAIN - [5:1] */
+#define WM9081_EQ_ENA                           0x0001  /* EQ_ENA */
+#define WM9081_EQ_ENA_MASK                      0x0001  /* EQ_ENA */
+#define WM9081_EQ_ENA_SHIFT                          0  /* EQ_ENA */
+#define WM9081_EQ_ENA_WIDTH                          1  /* EQ_ENA */
+
+/*
+ * R43 (0x2B) - EQ 2
+ */
+#define WM9081_EQ_B3_GAIN_MASK                  0xF800  /* EQ_B3_GAIN - [15:11] */
+#define WM9081_EQ_B3_GAIN_SHIFT                     11  /* EQ_B3_GAIN - [15:11] */
+#define WM9081_EQ_B3_GAIN_WIDTH                      5  /* EQ_B3_GAIN - [15:11] */
+#define WM9081_EQ_B5_GAIN_MASK                  0x07C0  /* EQ_B5_GAIN - [10:6] */
+#define WM9081_EQ_B5_GAIN_SHIFT                      6  /* EQ_B5_GAIN - [10:6] */
+#define WM9081_EQ_B5_GAIN_WIDTH                      5  /* EQ_B5_GAIN - [10:6] */
+
+/*
+ * R44 (0x2C) - EQ 3
+ */
+#define WM9081_EQ_B1_A_MASK                     0xFFFF  /* EQ_B1_A - [15:0] */
+#define WM9081_EQ_B1_A_SHIFT                         0  /* EQ_B1_A - [15:0] */
+#define WM9081_EQ_B1_A_WIDTH                        16  /* EQ_B1_A - [15:0] */
+
+/*
+ * R45 (0x2D) - EQ 4
+ */
+#define WM9081_EQ_B1_B_MASK                     0xFFFF  /* EQ_B1_B - [15:0] */
+#define WM9081_EQ_B1_B_SHIFT                         0  /* EQ_B1_B - [15:0] */
+#define WM9081_EQ_B1_B_WIDTH                        16  /* EQ_B1_B - [15:0] */
+
+/*
+ * R46 (0x2E) - EQ 5
+ */
+#define WM9081_EQ_B1_PG_MASK                    0xFFFF  /* EQ_B1_PG - [15:0] */
+#define WM9081_EQ_B1_PG_SHIFT                        0  /* EQ_B1_PG - [15:0] */
+#define WM9081_EQ_B1_PG_WIDTH                       16  /* EQ_B1_PG - [15:0] */
+
+/*
+ * R47 (0x2F) - EQ 6
+ */
+#define WM9081_EQ_B2_A_MASK                     0xFFFF  /* EQ_B2_A - [15:0] */
+#define WM9081_EQ_B2_A_SHIFT                         0  /* EQ_B2_A - [15:0] */
+#define WM9081_EQ_B2_A_WIDTH                        16  /* EQ_B2_A - [15:0] */
+
+/*
+ * R48 (0x30) - EQ 7
+ */
+#define WM9081_EQ_B2_B_MASK                     0xFFFF  /* EQ_B2_B - [15:0] */
+#define WM9081_EQ_B2_B_SHIFT                         0  /* EQ_B2_B - [15:0] */
+#define WM9081_EQ_B2_B_WIDTH                        16  /* EQ_B2_B - [15:0] */
+
+/*
+ * R49 (0x31) - EQ 8
+ */
+#define WM9081_EQ_B2_C_MASK                     0xFFFF  /* EQ_B2_C - [15:0] */
+#define WM9081_EQ_B2_C_SHIFT                         0  /* EQ_B2_C - [15:0] */
+#define WM9081_EQ_B2_C_WIDTH                        16  /* EQ_B2_C - [15:0] */
+
+/*
+ * R50 (0x32) - EQ 9
+ */
+#define WM9081_EQ_B2_PG_MASK                    0xFFFF  /* EQ_B2_PG - [15:0] */
+#define WM9081_EQ_B2_PG_SHIFT                        0  /* EQ_B2_PG - [15:0] */
+#define WM9081_EQ_B2_PG_WIDTH                       16  /* EQ_B2_PG - [15:0] */
+
+/*
+ * R51 (0x33) - EQ 10
+ */
+#define WM9081_EQ_B4_A_MASK                     0xFFFF  /* EQ_B4_A - [15:0] */
+#define WM9081_EQ_B4_A_SHIFT                         0  /* EQ_B4_A - [15:0] */
+#define WM9081_EQ_B4_A_WIDTH                        16  /* EQ_B4_A - [15:0] */
+
+/*
+ * R52 (0x34) - EQ 11
+ */
+#define WM9081_EQ_B4_B_MASK                     0xFFFF  /* EQ_B4_B - [15:0] */
+#define WM9081_EQ_B4_B_SHIFT                         0  /* EQ_B4_B - [15:0] */
+#define WM9081_EQ_B4_B_WIDTH                        16  /* EQ_B4_B - [15:0] */
+
+/*
+ * R53 (0x35) - EQ 12
+ */
+#define WM9081_EQ_B4_C_MASK                     0xFFFF  /* EQ_B4_C - [15:0] */
+#define WM9081_EQ_B4_C_SHIFT                         0  /* EQ_B4_C - [15:0] */
+#define WM9081_EQ_B4_C_WIDTH                        16  /* EQ_B4_C - [15:0] */
+
+/*
+ * R54 (0x36) - EQ 13
+ */
+#define WM9081_EQ_B4_PG_MASK                    0xFFFF  /* EQ_B4_PG - [15:0] */
+#define WM9081_EQ_B4_PG_SHIFT                        0  /* EQ_B4_PG - [15:0] */
+#define WM9081_EQ_B4_PG_WIDTH                       16  /* EQ_B4_PG - [15:0] */
+
+/*
+ * R55 (0x37) - EQ 14
+ */
+#define WM9081_EQ_B3_A_MASK                     0xFFFF  /* EQ_B3_A - [15:0] */
+#define WM9081_EQ_B3_A_SHIFT                         0  /* EQ_B3_A - [15:0] */
+#define WM9081_EQ_B3_A_WIDTH                        16  /* EQ_B3_A - [15:0] */
+
+/*
+ * R56 (0x38) - EQ 15
+ */
+#define WM9081_EQ_B3_B_MASK                     0xFFFF  /* EQ_B3_B - [15:0] */
+#define WM9081_EQ_B3_B_SHIFT                         0  /* EQ_B3_B - [15:0] */
+#define WM9081_EQ_B3_B_WIDTH                        16  /* EQ_B3_B - [15:0] */
+
+/*
+ * R57 (0x39) - EQ 16
+ */
+#define WM9081_EQ_B3_C_MASK                     0xFFFF  /* EQ_B3_C - [15:0] */
+#define WM9081_EQ_B3_C_SHIFT                         0  /* EQ_B3_C - [15:0] */
+#define WM9081_EQ_B3_C_WIDTH                        16  /* EQ_B3_C - [15:0] */
+
+/*
+ * R58 (0x3A) - EQ 17
+ */
+#define WM9081_EQ_B3_PG_MASK                    0xFFFF  /* EQ_B3_PG - [15:0] */
+#define WM9081_EQ_B3_PG_SHIFT                        0  /* EQ_B3_PG - [15:0] */
+#define WM9081_EQ_B3_PG_WIDTH                       16  /* EQ_B3_PG - [15:0] */
+
+/*
+ * R59 (0x3B) - EQ 18
+ */
+#define WM9081_EQ_B5_A_MASK                     0xFFFF  /* EQ_B5_A - [15:0] */
+#define WM9081_EQ_B5_A_SHIFT                         0  /* EQ_B5_A - [15:0] */
+#define WM9081_EQ_B5_A_WIDTH                        16  /* EQ_B5_A - [15:0] */
+
+/*
+ * R60 (0x3C) - EQ 19
+ */
+#define WM9081_EQ_B5_B_MASK                     0xFFFF  /* EQ_B5_B - [15:0] */
+#define WM9081_EQ_B5_B_SHIFT                         0  /* EQ_B5_B - [15:0] */
+#define WM9081_EQ_B5_B_WIDTH                        16  /* EQ_B5_B - [15:0] */
+
+/*
+ * R61 (0x3D) - EQ 20
+ */
+#define WM9081_EQ_B5_PG_MASK                    0xFFFF  /* EQ_B5_PG - [15:0] */
+#define WM9081_EQ_B5_PG_SHIFT                        0  /* EQ_B5_PG - [15:0] */
+#define WM9081_EQ_B5_PG_WIDTH                       16  /* EQ_B5_PG - [15:0] */
+
+
+#endif
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
new file mode 100644
index 0000000..a9f1a03
--- /dev/null
+++ b/sound/soc/codecs/wm9090.c
@@ -0,0 +1,643 @@
+/*
+ * ALSA SoC WM9090 driver
+ *
+ * Copyright 2009-12 Wolfson Microelectronics
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/wm9090.h>
+
+#include "wm9090.h"
+
+static const struct reg_default wm9090_reg_defaults[] = {
+	{ 1,  0x0006 },     /* R1   - Power Management (1) */
+	{ 2,  0x6000 },     /* R2   - Power Management (2) */
+	{ 3,  0x0000 },     /* R3   - Power Management (3) */
+	{ 6,  0x01C0 },     /* R6   - Clocking 1 */
+	{ 22, 0x0003 },     /* R22  - IN1 Line Control */
+	{ 23, 0x0003 },     /* R23  - IN2 Line Control */
+	{ 24, 0x0083 },     /* R24  - IN1 Line Input A Volume */
+	{ 25, 0x0083 },     /* R25  - IN1  Line Input B Volume */
+	{ 26, 0x0083 },     /* R26  - IN2 Line Input A Volume */
+	{ 27, 0x0083 },     /* R27  - IN2 Line Input B Volume */
+	{ 28, 0x002D },     /* R28  - Left Output Volume */
+	{ 29, 0x002D },     /* R29  - Right Output Volume */
+	{ 34, 0x0100 },     /* R34  - SPKMIXL Attenuation */
+	{ 35, 0x0010 },     /* R36  - SPKOUT Mixers */
+	{ 37, 0x0140 },     /* R37  - ClassD3 */
+	{ 38, 0x0039 },     /* R38  - Speaker Volume Left */
+	{ 45, 0x0000 },     /* R45  - Output Mixer1 */
+	{ 46, 0x0000 },     /* R46  - Output Mixer2 */
+	{ 47, 0x0100 },     /* R47  - Output Mixer3 */
+	{ 48, 0x0100 },     /* R48  - Output Mixer4 */
+	{ 54, 0x0000 },     /* R54  - Speaker Mixer */
+	{ 57, 0x000D },     /* R57  - AntiPOP2 */
+	{ 70, 0x0000 },     /* R70  - Write Sequencer 0 */
+	{ 71, 0x0000 },     /* R71  - Write Sequencer 1 */
+	{ 72, 0x0000 },     /* R72  - Write Sequencer 2 */
+	{ 73, 0x0000 },     /* R73  - Write Sequencer 3 */
+	{ 74, 0x0000 },     /* R74  - Write Sequencer 4 */
+	{ 75, 0x0000 },     /* R75  - Write Sequencer 5 */
+	{ 76, 0x1F25 },     /* R76  - Charge Pump 1 */
+	{ 85, 0x054A },     /* R85  - DC Servo 1 */
+	{ 87, 0x0000 },     /* R87  - DC Servo 3 */
+	{ 96, 0x0100 },     /* R96  - Analogue HP 0 */
+	{ 98, 0x8640 },     /* R98  - AGC Control 0 */
+	{ 99, 0xC000 },     /* R99  - AGC Control 1 */
+	{ 100, 0x0200 },     /* R100 - AGC Control 2 */
+};
+
+/* This struct is used to save the context */
+struct wm9090_priv {
+	struct wm9090_platform_data pdata;
+	struct regmap *regmap;
+};
+
+static bool wm9090_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM9090_SOFTWARE_RESET:
+	case WM9090_DC_SERVO_0:
+	case WM9090_DC_SERVO_READBACK_0:
+	case WM9090_DC_SERVO_READBACK_1:
+	case WM9090_DC_SERVO_READBACK_2:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+static bool wm9090_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WM9090_SOFTWARE_RESET:
+	case WM9090_POWER_MANAGEMENT_1:
+	case WM9090_POWER_MANAGEMENT_2:
+	case WM9090_POWER_MANAGEMENT_3:
+	case WM9090_CLOCKING_1:
+	case WM9090_IN1_LINE_CONTROL:
+	case WM9090_IN2_LINE_CONTROL:
+	case WM9090_IN1_LINE_INPUT_A_VOLUME:
+	case WM9090_IN1_LINE_INPUT_B_VOLUME:
+	case WM9090_IN2_LINE_INPUT_A_VOLUME:
+	case WM9090_IN2_LINE_INPUT_B_VOLUME:
+	case WM9090_LEFT_OUTPUT_VOLUME:
+	case WM9090_RIGHT_OUTPUT_VOLUME:
+	case WM9090_SPKMIXL_ATTENUATION:
+	case WM9090_SPKOUT_MIXERS:
+	case WM9090_CLASSD3:
+	case WM9090_SPEAKER_VOLUME_LEFT:
+	case WM9090_OUTPUT_MIXER1:
+	case WM9090_OUTPUT_MIXER2:
+	case WM9090_OUTPUT_MIXER3:
+	case WM9090_OUTPUT_MIXER4:
+	case WM9090_SPEAKER_MIXER:
+	case WM9090_ANTIPOP2:
+	case WM9090_WRITE_SEQUENCER_0:
+	case WM9090_WRITE_SEQUENCER_1:
+	case WM9090_WRITE_SEQUENCER_2:
+	case WM9090_WRITE_SEQUENCER_3:
+	case WM9090_WRITE_SEQUENCER_4:
+	case WM9090_WRITE_SEQUENCER_5:
+	case WM9090_CHARGE_PUMP_1:
+	case WM9090_DC_SERVO_0:
+	case WM9090_DC_SERVO_1:
+	case WM9090_DC_SERVO_3:
+	case WM9090_DC_SERVO_READBACK_0:
+	case WM9090_DC_SERVO_READBACK_1:
+	case WM9090_DC_SERVO_READBACK_2:
+	case WM9090_ANALOGUE_HP_0:
+	case WM9090_AGC_CONTROL_0:
+	case WM9090_AGC_CONTROL_1:
+	case WM9090_AGC_CONTROL_2:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+static void wait_for_dc_servo(struct snd_soc_component *component)
+{
+	unsigned int reg;
+	int count = 0;
+
+	dev_dbg(component->dev, "Waiting for DC servo...\n");
+	do {
+		count++;
+		msleep(1);
+		reg = snd_soc_component_read32(component, WM9090_DC_SERVO_READBACK_0);
+		dev_dbg(component->dev, "DC servo status: %x\n", reg);
+	} while ((reg & WM9090_DCS_CAL_COMPLETE_MASK)
+		 != WM9090_DCS_CAL_COMPLETE_MASK && count < 1000);
+
+	if ((reg & WM9090_DCS_CAL_COMPLETE_MASK)
+	    != WM9090_DCS_CAL_COMPLETE_MASK)
+		dev_err(component->dev, "Timed out waiting for DC Servo\n");
+}
+
+static const DECLARE_TLV_DB_RANGE(in_tlv,
+	0, 0, TLV_DB_SCALE_ITEM(-600, 0, 0),
+	1, 3, TLV_DB_SCALE_ITEM(-350, 350, 0),
+	4, 6, TLV_DB_SCALE_ITEM(600, 600, 0)
+);
+static const DECLARE_TLV_DB_RANGE(mix_tlv,
+	0, 2, TLV_DB_SCALE_ITEM(-1200, 300, 0),
+	3, 3, TLV_DB_SCALE_ITEM(0, 0, 0)
+);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_RANGE(spkboost_tlv,
+	0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
+	7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0)
+);
+
+static const struct snd_kcontrol_new wm9090_controls[] = {
+SOC_SINGLE_TLV("IN1A Volume", WM9090_IN1_LINE_INPUT_A_VOLUME, 0, 6, 0,
+	       in_tlv),
+SOC_SINGLE("IN1A Switch", WM9090_IN1_LINE_INPUT_A_VOLUME, 7, 1, 1),
+SOC_SINGLE("IN1A ZC Switch", WM9090_IN1_LINE_INPUT_A_VOLUME, 6, 1, 0),
+
+SOC_SINGLE_TLV("IN2A Volume", WM9090_IN2_LINE_INPUT_A_VOLUME, 0, 6, 0,
+	       in_tlv),
+SOC_SINGLE("IN2A Switch", WM9090_IN2_LINE_INPUT_A_VOLUME, 7, 1, 1),
+SOC_SINGLE("IN2A ZC Switch", WM9090_IN2_LINE_INPUT_A_VOLUME, 6, 1, 0),
+
+SOC_SINGLE("MIXOUTL Switch", WM9090_OUTPUT_MIXER3, 8, 1, 1),
+SOC_SINGLE_TLV("MIXOUTL IN1A Volume", WM9090_OUTPUT_MIXER3, 6, 3, 1,
+	       mix_tlv),
+SOC_SINGLE_TLV("MIXOUTL IN2A Volume", WM9090_OUTPUT_MIXER3, 2, 3, 1,
+	       mix_tlv),
+
+SOC_SINGLE("MIXOUTR Switch", WM9090_OUTPUT_MIXER4, 8, 1, 1),
+SOC_SINGLE_TLV("MIXOUTR IN1A Volume", WM9090_OUTPUT_MIXER4, 6, 3, 1,
+	       mix_tlv),
+SOC_SINGLE_TLV("MIXOUTR IN2A Volume", WM9090_OUTPUT_MIXER4, 2, 3, 1,
+	       mix_tlv),
+
+SOC_SINGLE("SPKMIX Switch", WM9090_SPKMIXL_ATTENUATION, 8, 1, 1),
+SOC_SINGLE_TLV("SPKMIX IN1A Volume", WM9090_SPKMIXL_ATTENUATION, 6, 3, 1,
+	       mix_tlv),
+SOC_SINGLE_TLV("SPKMIX IN2A Volume", WM9090_SPKMIXL_ATTENUATION, 2, 3, 1,
+	       mix_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Volume", WM9090_LEFT_OUTPUT_VOLUME,
+		 WM9090_RIGHT_OUTPUT_VOLUME, 0, 63, 0, out_tlv),
+SOC_DOUBLE_R("Headphone Switch", WM9090_LEFT_OUTPUT_VOLUME,
+	     WM9090_RIGHT_OUTPUT_VOLUME, 6, 1, 1),
+SOC_DOUBLE_R("Headphone ZC Switch", WM9090_LEFT_OUTPUT_VOLUME,
+	     WM9090_RIGHT_OUTPUT_VOLUME, 7, 1, 0),
+
+SOC_SINGLE_TLV("Speaker Volume", WM9090_SPEAKER_VOLUME_LEFT, 0, 63, 0,
+	       out_tlv),
+SOC_SINGLE("Speaker Switch", WM9090_SPEAKER_VOLUME_LEFT, 6, 1, 1),
+SOC_SINGLE("Speaker ZC Switch", WM9090_SPEAKER_VOLUME_LEFT, 7, 1, 0),
+SOC_SINGLE_TLV("Speaker Boost Volume", WM9090_CLASSD3, 3, 7, 0, spkboost_tlv),
+};
+
+static const struct snd_kcontrol_new wm9090_in1_se_controls[] = {
+SOC_SINGLE_TLV("IN1B Volume", WM9090_IN1_LINE_INPUT_B_VOLUME, 0, 6, 0,
+	       in_tlv),
+SOC_SINGLE("IN1B Switch", WM9090_IN1_LINE_INPUT_B_VOLUME, 7, 1, 1),
+SOC_SINGLE("IN1B ZC Switch", WM9090_IN1_LINE_INPUT_B_VOLUME, 6, 1, 0),
+
+SOC_SINGLE_TLV("SPKMIX IN1B Volume", WM9090_SPKMIXL_ATTENUATION, 4, 3, 1,
+	       mix_tlv),
+SOC_SINGLE_TLV("MIXOUTL IN1B Volume", WM9090_OUTPUT_MIXER3, 4, 3, 1,
+	       mix_tlv),
+SOC_SINGLE_TLV("MIXOUTR IN1B Volume", WM9090_OUTPUT_MIXER4, 4, 3, 1,
+	       mix_tlv),
+};
+
+static const struct snd_kcontrol_new wm9090_in2_se_controls[] = {
+SOC_SINGLE_TLV("IN2B Volume", WM9090_IN2_LINE_INPUT_B_VOLUME, 0, 6, 0,
+	       in_tlv),
+SOC_SINGLE("IN2B Switch", WM9090_IN2_LINE_INPUT_B_VOLUME, 7, 1, 1),
+SOC_SINGLE("IN2B ZC Switch", WM9090_IN2_LINE_INPUT_B_VOLUME, 6, 1, 0),
+
+SOC_SINGLE_TLV("SPKMIX IN2B Volume", WM9090_SPKMIXL_ATTENUATION, 0, 3, 1,
+	       mix_tlv),
+SOC_SINGLE_TLV("MIXOUTL IN2B Volume", WM9090_OUTPUT_MIXER3, 0, 3, 1,
+	       mix_tlv),
+SOC_SINGLE_TLV("MIXOUTR IN2B Volume", WM9090_OUTPUT_MIXER4, 0, 3, 1,
+	       mix_tlv),
+};
+
+static int hp_ev(struct snd_soc_dapm_widget *w,
+		 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	unsigned int reg = snd_soc_component_read32(component, WM9090_ANALOGUE_HP_0);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, WM9090_CHARGE_PUMP_1,
+				    WM9090_CP_ENA, WM9090_CP_ENA);
+
+		msleep(5);
+
+		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_1,
+				    WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA,
+				    WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA);
+
+		reg |= WM9090_HPOUT1L_DLY | WM9090_HPOUT1R_DLY;
+		snd_soc_component_write(component, WM9090_ANALOGUE_HP_0, reg);
+
+		/* Start the DC servo.  We don't currently use the
+		 * ability to save the state since we don't have full
+		 * control of the analogue paths and they can change
+		 * DC offsets; see the WM8904 driver for an example of
+		 * doing so.
+		 */
+		snd_soc_component_write(component, WM9090_DC_SERVO_0,
+			      WM9090_DCS_ENA_CHAN_0 |
+			      WM9090_DCS_ENA_CHAN_1 |
+			      WM9090_DCS_TRIG_STARTUP_1 |
+			      WM9090_DCS_TRIG_STARTUP_0);
+		wait_for_dc_servo(component);
+
+		reg |= WM9090_HPOUT1R_OUTP | WM9090_HPOUT1R_RMV_SHORT |
+			WM9090_HPOUT1L_OUTP | WM9090_HPOUT1L_RMV_SHORT;
+		snd_soc_component_write(component, WM9090_ANALOGUE_HP_0, reg);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		reg &= ~(WM9090_HPOUT1L_RMV_SHORT |
+			 WM9090_HPOUT1L_DLY |
+			 WM9090_HPOUT1L_OUTP |
+			 WM9090_HPOUT1R_RMV_SHORT |
+			 WM9090_HPOUT1R_DLY |
+			 WM9090_HPOUT1R_OUTP);
+
+		snd_soc_component_write(component, WM9090_ANALOGUE_HP_0, reg);
+
+		snd_soc_component_write(component, WM9090_DC_SERVO_0, 0);
+
+		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_1,
+				    WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA,
+				    0);
+
+		snd_soc_component_update_bits(component, WM9090_CHARGE_PUMP_1,
+				    WM9090_CP_ENA, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new spkmix[] = {
+SOC_DAPM_SINGLE("IN1A Switch", WM9090_SPEAKER_MIXER, 6, 1, 0),
+SOC_DAPM_SINGLE("IN1B Switch", WM9090_SPEAKER_MIXER, 4, 1, 0),
+SOC_DAPM_SINGLE("IN2A Switch", WM9090_SPEAKER_MIXER, 2, 1, 0),
+SOC_DAPM_SINGLE("IN2B Switch", WM9090_SPEAKER_MIXER, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new spkout[] = {
+SOC_DAPM_SINGLE("Mixer Switch", WM9090_SPKOUT_MIXERS, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixoutl[] = {
+SOC_DAPM_SINGLE("IN1A Switch", WM9090_OUTPUT_MIXER1, 6, 1, 0),
+SOC_DAPM_SINGLE("IN1B Switch", WM9090_OUTPUT_MIXER1, 4, 1, 0),
+SOC_DAPM_SINGLE("IN2A Switch", WM9090_OUTPUT_MIXER1, 2, 1, 0),
+SOC_DAPM_SINGLE("IN2B Switch", WM9090_OUTPUT_MIXER1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixoutr[] = {
+SOC_DAPM_SINGLE("IN1A Switch", WM9090_OUTPUT_MIXER2, 6, 1, 0),
+SOC_DAPM_SINGLE("IN1B Switch", WM9090_OUTPUT_MIXER2, 4, 1, 0),
+SOC_DAPM_SINGLE("IN2A Switch", WM9090_OUTPUT_MIXER2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN2B Switch", WM9090_OUTPUT_MIXER2, 0, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm9090_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1+"),
+SND_SOC_DAPM_INPUT("IN1-"),
+SND_SOC_DAPM_INPUT("IN2+"),
+SND_SOC_DAPM_INPUT("IN2-"),
+
+SND_SOC_DAPM_SUPPLY("OSC", WM9090_POWER_MANAGEMENT_1, 3, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("IN1A PGA", WM9090_POWER_MANAGEMENT_2, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN1B PGA", WM9090_POWER_MANAGEMENT_2, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN2A PGA", WM9090_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN2B PGA", WM9090_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("SPKMIX", WM9090_POWER_MANAGEMENT_3, 3, 0,
+		   spkmix, ARRAY_SIZE(spkmix)),
+SND_SOC_DAPM_MIXER("MIXOUTL", WM9090_POWER_MANAGEMENT_3, 5, 0,
+		   mixoutl, ARRAY_SIZE(mixoutl)),
+SND_SOC_DAPM_MIXER("MIXOUTR", WM9090_POWER_MANAGEMENT_3, 4, 0,
+		   mixoutr, ARRAY_SIZE(mixoutr)),
+
+SND_SOC_DAPM_PGA_E("HP PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
+		   hp_ev, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA("SPKPGA", WM9090_POWER_MANAGEMENT_3, 8, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("SPKOUT", WM9090_POWER_MANAGEMENT_1, 12, 0,
+		   spkout, ARRAY_SIZE(spkout)),
+
+SND_SOC_DAPM_OUTPUT("HPR"),
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("Speaker"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	{ "IN1A PGA", NULL, "IN1+" },
+	{ "IN2A PGA", NULL, "IN2+" },
+
+	{ "SPKMIX", "IN1A Switch", "IN1A PGA" },
+	{ "SPKMIX", "IN2A Switch", "IN2A PGA" },
+
+	{ "MIXOUTL", "IN1A Switch", "IN1A PGA" },
+	{ "MIXOUTL", "IN2A Switch", "IN2A PGA" },
+
+	{ "MIXOUTR", "IN1A Switch", "IN1A PGA" },
+	{ "MIXOUTR", "IN2A Switch", "IN2A PGA" },
+
+	{ "HP PGA", NULL, "OSC" },
+	{ "HP PGA", NULL, "MIXOUTL" },
+	{ "HP PGA", NULL, "MIXOUTR" },
+
+	{ "HPL", NULL, "HP PGA" },
+	{ "HPR", NULL, "HP PGA" },
+
+	{ "SPKPGA", NULL, "OSC" },
+	{ "SPKPGA", NULL, "SPKMIX" },
+
+	{ "SPKOUT", "Mixer Switch", "SPKPGA" },
+
+	{ "Speaker", NULL, "SPKOUT" },
+};
+
+static const struct snd_soc_dapm_route audio_map_in1_se[] = {
+	{ "IN1B PGA", NULL, "IN1-" },	
+
+	{ "SPKMIX", "IN1B Switch", "IN1B PGA" },
+	{ "MIXOUTL", "IN1B Switch", "IN1B PGA" },
+	{ "MIXOUTR", "IN1B Switch", "IN1B PGA" },
+};
+
+static const struct snd_soc_dapm_route audio_map_in1_diff[] = {
+	{ "IN1A PGA", NULL, "IN1-" },	
+};
+
+static const struct snd_soc_dapm_route audio_map_in2_se[] = {
+	{ "IN2B PGA", NULL, "IN2-" },	
+
+	{ "SPKMIX", "IN2B Switch", "IN2B PGA" },
+	{ "MIXOUTL", "IN2B Switch", "IN2B PGA" },
+	{ "MIXOUTR", "IN2B Switch", "IN2B PGA" },
+};
+
+static const struct snd_soc_dapm_route audio_map_in2_diff[] = {
+	{ "IN2A PGA", NULL, "IN2-" },	
+};
+
+static int wm9090_add_controls(struct snd_soc_component *component)
+{
+	struct wm9090_priv *wm9090 = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	int i;
+
+	snd_soc_dapm_new_controls(dapm, wm9090_dapm_widgets,
+				  ARRAY_SIZE(wm9090_dapm_widgets));
+
+	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+
+	snd_soc_add_component_controls(component, wm9090_controls,
+			     ARRAY_SIZE(wm9090_controls));
+
+	if (wm9090->pdata.lin1_diff) {
+		snd_soc_dapm_add_routes(dapm, audio_map_in1_diff,
+					ARRAY_SIZE(audio_map_in1_diff));
+	} else {
+		snd_soc_dapm_add_routes(dapm, audio_map_in1_se,
+					ARRAY_SIZE(audio_map_in1_se));
+		snd_soc_add_component_controls(component, wm9090_in1_se_controls,
+				     ARRAY_SIZE(wm9090_in1_se_controls));
+	}
+
+	if (wm9090->pdata.lin2_diff) {
+		snd_soc_dapm_add_routes(dapm, audio_map_in2_diff,
+					ARRAY_SIZE(audio_map_in2_diff));
+	} else {
+		snd_soc_dapm_add_routes(dapm, audio_map_in2_se,
+					ARRAY_SIZE(audio_map_in2_se));
+		snd_soc_add_component_controls(component, wm9090_in2_se_controls,
+				     ARRAY_SIZE(wm9090_in2_se_controls));
+	}
+
+	if (wm9090->pdata.agc_ena) {
+		for (i = 0; i < ARRAY_SIZE(wm9090->pdata.agc); i++)
+			snd_soc_component_write(component, WM9090_AGC_CONTROL_0 + i,
+				      wm9090->pdata.agc[i]);
+		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_3,
+				    WM9090_AGC_ENA, WM9090_AGC_ENA);
+	} else {
+		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_3,
+				    WM9090_AGC_ENA, 0);
+	}
+
+	return 0;
+
+}
+
+/*
+ * The machine driver should call this from their set_bias_level; if there
+ * isn't one then this can just be set as the set_bias_level function.
+ */
+static int wm9090_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	struct wm9090_priv *wm9090 = snd_soc_component_get_drvdata(component);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		snd_soc_component_update_bits(component, WM9090_ANTIPOP2, WM9090_VMID_ENA,
+				    WM9090_VMID_ENA);
+		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_1,
+				    WM9090_BIAS_ENA |
+				    WM9090_VMID_RES_MASK,
+				    WM9090_BIAS_ENA |
+				    1 << WM9090_VMID_RES_SHIFT);
+		msleep(1);  /* Probably an overestimate */
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+			/* Restore the register cache */
+			regcache_sync(wm9090->regmap);
+		}
+
+		/* We keep VMID off during standby since the combination of
+		 * ground referenced outputs and class D speaker mean that
+		 * latency is not an issue.
+		 */
+		snd_soc_component_update_bits(component, WM9090_POWER_MANAGEMENT_1,
+				    WM9090_BIAS_ENA | WM9090_VMID_RES_MASK, 0);
+		snd_soc_component_update_bits(component, WM9090_ANTIPOP2,
+				    WM9090_VMID_ENA, 0);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		break;
+	}
+
+	return 0;
+}
+
+static int wm9090_probe(struct snd_soc_component *component)
+{
+	/* Configure some defaults; they will be written out when we
+	 * bring the bias up.
+	 */
+	snd_soc_component_update_bits(component, WM9090_IN1_LINE_INPUT_A_VOLUME,
+			    WM9090_IN1_VU | WM9090_IN1A_ZC,
+			    WM9090_IN1_VU | WM9090_IN1A_ZC);
+	snd_soc_component_update_bits(component, WM9090_IN1_LINE_INPUT_B_VOLUME,
+			    WM9090_IN1_VU | WM9090_IN1B_ZC,
+			    WM9090_IN1_VU | WM9090_IN1B_ZC);
+	snd_soc_component_update_bits(component, WM9090_IN2_LINE_INPUT_A_VOLUME,
+			    WM9090_IN2_VU | WM9090_IN2A_ZC,
+			    WM9090_IN2_VU | WM9090_IN2A_ZC);
+	snd_soc_component_update_bits(component, WM9090_IN2_LINE_INPUT_B_VOLUME,
+			    WM9090_IN2_VU | WM9090_IN2B_ZC,
+			    WM9090_IN2_VU | WM9090_IN2B_ZC);
+	snd_soc_component_update_bits(component, WM9090_SPEAKER_VOLUME_LEFT,
+			    WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC,
+			    WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC);
+	snd_soc_component_update_bits(component, WM9090_LEFT_OUTPUT_VOLUME,
+			    WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC,
+			    WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC);
+	snd_soc_component_update_bits(component, WM9090_RIGHT_OUTPUT_VOLUME,
+			    WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC,
+			    WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC);
+
+	snd_soc_component_update_bits(component, WM9090_CLOCKING_1,
+			    WM9090_TOCLK_ENA, WM9090_TOCLK_ENA);
+
+	wm9090_add_controls(component);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm9090 = {
+	.probe			= wm9090_probe,
+	.set_bias_level		= wm9090_set_bias_level,
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static const struct regmap_config wm9090_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+
+	.max_register = WM9090_MAX_REGISTER,
+	.volatile_reg = wm9090_volatile,
+	.readable_reg = wm9090_readable,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = wm9090_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm9090_reg_defaults),
+};
+
+
+static int wm9090_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm9090_priv *wm9090;
+	unsigned int reg;
+	int ret;
+
+	wm9090 = devm_kzalloc(&i2c->dev, sizeof(*wm9090), GFP_KERNEL);
+	if (!wm9090)
+		return -ENOMEM;
+
+	wm9090->regmap = devm_regmap_init_i2c(i2c, &wm9090_regmap);
+	if (IS_ERR(wm9090->regmap)) {
+		ret = PTR_ERR(wm9090->regmap);
+		dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(wm9090->regmap, WM9090_SOFTWARE_RESET, &reg);
+	if (ret < 0)
+		return ret;
+
+	if (reg != 0x9093) {
+		dev_err(&i2c->dev, "Device is not a WM9090, ID=%x\n", reg);
+		return -ENODEV;
+	}
+
+	ret = regmap_write(wm9090->regmap, WM9090_SOFTWARE_RESET, 0);
+	if (ret < 0)
+		return ret;
+
+	if (i2c->dev.platform_data)
+		memcpy(&wm9090->pdata, i2c->dev.platform_data,
+		       sizeof(wm9090->pdata));
+
+	i2c_set_clientdata(i2c, wm9090);
+
+	ret =  devm_snd_soc_register_component(&i2c->dev,
+			&soc_component_dev_wm9090,  NULL, 0);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct i2c_device_id wm9090_id[] = {
+	{ "wm9090", 0 },
+	{ "wm9093", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm9090_id);
+
+static struct i2c_driver wm9090_i2c_driver = {
+	.driver = {
+		.name = "wm9090",
+	},
+	.probe = wm9090_i2c_probe,
+	.id_table = wm9090_id,
+};
+
+module_i2c_driver(wm9090_i2c_driver);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM9090 ASoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm9090.h b/sound/soc/codecs/wm9090.h
new file mode 100644
index 0000000..29b9d9f
--- /dev/null
+++ b/sound/soc/codecs/wm9090.h
@@ -0,0 +1,713 @@
+/*
+ * ALSA SoC WM9090 driver
+ *
+ * Copyright 2009 Wolfson Microelectronics
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __WM9090_H
+#define __WM9090_H
+
+/*
+ * Register values.
+ */
+#define WM9090_SOFTWARE_RESET                   0x00
+#define WM9090_POWER_MANAGEMENT_1               0x01
+#define WM9090_POWER_MANAGEMENT_2               0x02
+#define WM9090_POWER_MANAGEMENT_3               0x03
+#define WM9090_CLOCKING_1                       0x06
+#define WM9090_IN1_LINE_CONTROL                 0x16
+#define WM9090_IN2_LINE_CONTROL                 0x17
+#define WM9090_IN1_LINE_INPUT_A_VOLUME          0x18
+#define WM9090_IN1_LINE_INPUT_B_VOLUME          0x19
+#define WM9090_IN2_LINE_INPUT_A_VOLUME          0x1A
+#define WM9090_IN2_LINE_INPUT_B_VOLUME          0x1B
+#define WM9090_LEFT_OUTPUT_VOLUME               0x1C
+#define WM9090_RIGHT_OUTPUT_VOLUME              0x1D
+#define WM9090_SPKMIXL_ATTENUATION              0x22
+#define WM9090_SPKOUT_MIXERS                    0x24
+#define WM9090_CLASSD3                          0x25
+#define WM9090_SPEAKER_VOLUME_LEFT              0x26
+#define WM9090_OUTPUT_MIXER1                    0x2D
+#define WM9090_OUTPUT_MIXER2                    0x2E
+#define WM9090_OUTPUT_MIXER3                    0x2F
+#define WM9090_OUTPUT_MIXER4                    0x30
+#define WM9090_SPEAKER_MIXER                    0x36
+#define WM9090_ANTIPOP2                         0x39
+#define WM9090_WRITE_SEQUENCER_0                0x46
+#define WM9090_WRITE_SEQUENCER_1                0x47
+#define WM9090_WRITE_SEQUENCER_2                0x48
+#define WM9090_WRITE_SEQUENCER_3                0x49
+#define WM9090_WRITE_SEQUENCER_4                0x4A
+#define WM9090_WRITE_SEQUENCER_5                0x4B
+#define WM9090_CHARGE_PUMP_1                    0x4C
+#define WM9090_DC_SERVO_0                       0x54
+#define WM9090_DC_SERVO_1                       0x55
+#define WM9090_DC_SERVO_3                       0x57
+#define WM9090_DC_SERVO_READBACK_0              0x58
+#define WM9090_DC_SERVO_READBACK_1              0x59
+#define WM9090_DC_SERVO_READBACK_2              0x5A
+#define WM9090_ANALOGUE_HP_0                    0x60
+#define WM9090_AGC_CONTROL_0                    0x62
+#define WM9090_AGC_CONTROL_1                    0x63
+#define WM9090_AGC_CONTROL_2                    0x64
+
+#define WM9090_REGISTER_COUNT                   40
+#define WM9090_MAX_REGISTER                     0x64
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM9090_SW_RESET_MASK                    0xFFFF  /* SW_RESET - [15:0] */
+#define WM9090_SW_RESET_SHIFT                        0  /* SW_RESET - [15:0] */
+#define WM9090_SW_RESET_WIDTH                       16  /* SW_RESET - [15:0] */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM9090_SPKOUTL_ENA                      0x1000  /* SPKOUTL_ENA */
+#define WM9090_SPKOUTL_ENA_MASK                 0x1000  /* SPKOUTL_ENA */
+#define WM9090_SPKOUTL_ENA_SHIFT                    12  /* SPKOUTL_ENA */
+#define WM9090_SPKOUTL_ENA_WIDTH                     1  /* SPKOUTL_ENA */
+#define WM9090_HPOUT1L_ENA                      0x0200  /* HPOUT1L_ENA */
+#define WM9090_HPOUT1L_ENA_MASK                 0x0200  /* HPOUT1L_ENA */
+#define WM9090_HPOUT1L_ENA_SHIFT                     9  /* HPOUT1L_ENA */
+#define WM9090_HPOUT1L_ENA_WIDTH                     1  /* HPOUT1L_ENA */
+#define WM9090_HPOUT1R_ENA                      0x0100  /* HPOUT1R_ENA */
+#define WM9090_HPOUT1R_ENA_MASK                 0x0100  /* HPOUT1R_ENA */
+#define WM9090_HPOUT1R_ENA_SHIFT                     8  /* HPOUT1R_ENA */
+#define WM9090_HPOUT1R_ENA_WIDTH                     1  /* HPOUT1R_ENA */
+#define WM9090_OSC_ENA                          0x0008  /* OSC_ENA */
+#define WM9090_OSC_ENA_MASK                     0x0008  /* OSC_ENA */
+#define WM9090_OSC_ENA_SHIFT                         3  /* OSC_ENA */
+#define WM9090_OSC_ENA_WIDTH                         1  /* OSC_ENA */
+#define WM9090_VMID_RES_MASK                    0x0006  /* VMID_RES - [2:1] */
+#define WM9090_VMID_RES_SHIFT                        1  /* VMID_RES - [2:1] */
+#define WM9090_VMID_RES_WIDTH                        2  /* VMID_RES - [2:1] */
+#define WM9090_BIAS_ENA                         0x0001  /* BIAS_ENA */
+#define WM9090_BIAS_ENA_MASK                    0x0001  /* BIAS_ENA */
+#define WM9090_BIAS_ENA_SHIFT                        0  /* BIAS_ENA */
+#define WM9090_BIAS_ENA_WIDTH                        1  /* BIAS_ENA */
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM9090_TSHUT                            0x8000  /* TSHUT */
+#define WM9090_TSHUT_MASK                       0x8000  /* TSHUT */
+#define WM9090_TSHUT_SHIFT                          15  /* TSHUT */
+#define WM9090_TSHUT_WIDTH                           1  /* TSHUT */
+#define WM9090_TSHUT_ENA                        0x4000  /* TSHUT_ENA */
+#define WM9090_TSHUT_ENA_MASK                   0x4000  /* TSHUT_ENA */
+#define WM9090_TSHUT_ENA_SHIFT                      14  /* TSHUT_ENA */
+#define WM9090_TSHUT_ENA_WIDTH                       1  /* TSHUT_ENA */
+#define WM9090_TSHUT_OPDIS                      0x2000  /* TSHUT_OPDIS */
+#define WM9090_TSHUT_OPDIS_MASK                 0x2000  /* TSHUT_OPDIS */
+#define WM9090_TSHUT_OPDIS_SHIFT                    13  /* TSHUT_OPDIS */
+#define WM9090_TSHUT_OPDIS_WIDTH                     1  /* TSHUT_OPDIS */
+#define WM9090_IN1A_ENA                         0x0080  /* IN1A_ENA */
+#define WM9090_IN1A_ENA_MASK                    0x0080  /* IN1A_ENA */
+#define WM9090_IN1A_ENA_SHIFT                        7  /* IN1A_ENA */
+#define WM9090_IN1A_ENA_WIDTH                        1  /* IN1A_ENA */
+#define WM9090_IN1B_ENA                         0x0040  /* IN1B_ENA */
+#define WM9090_IN1B_ENA_MASK                    0x0040  /* IN1B_ENA */
+#define WM9090_IN1B_ENA_SHIFT                        6  /* IN1B_ENA */
+#define WM9090_IN1B_ENA_WIDTH                        1  /* IN1B_ENA */
+#define WM9090_IN2A_ENA                         0x0020  /* IN2A_ENA */
+#define WM9090_IN2A_ENA_MASK                    0x0020  /* IN2A_ENA */
+#define WM9090_IN2A_ENA_SHIFT                        5  /* IN2A_ENA */
+#define WM9090_IN2A_ENA_WIDTH                        1  /* IN2A_ENA */
+#define WM9090_IN2B_ENA                         0x0010  /* IN2B_ENA */
+#define WM9090_IN2B_ENA_MASK                    0x0010  /* IN2B_ENA */
+#define WM9090_IN2B_ENA_SHIFT                        4  /* IN2B_ENA */
+#define WM9090_IN2B_ENA_WIDTH                        1  /* IN2B_ENA */
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM9090_AGC_ENA                          0x4000  /* AGC_ENA */
+#define WM9090_AGC_ENA_MASK                     0x4000  /* AGC_ENA */
+#define WM9090_AGC_ENA_SHIFT                        14  /* AGC_ENA */
+#define WM9090_AGC_ENA_WIDTH                         1  /* AGC_ENA */
+#define WM9090_SPKLVOL_ENA                      0x0100  /* SPKLVOL_ENA */
+#define WM9090_SPKLVOL_ENA_MASK                 0x0100  /* SPKLVOL_ENA */
+#define WM9090_SPKLVOL_ENA_SHIFT                     8  /* SPKLVOL_ENA */
+#define WM9090_SPKLVOL_ENA_WIDTH                     1  /* SPKLVOL_ENA */
+#define WM9090_MIXOUTL_ENA                      0x0020  /* MIXOUTL_ENA */
+#define WM9090_MIXOUTL_ENA_MASK                 0x0020  /* MIXOUTL_ENA */
+#define WM9090_MIXOUTL_ENA_SHIFT                     5  /* MIXOUTL_ENA */
+#define WM9090_MIXOUTL_ENA_WIDTH                     1  /* MIXOUTL_ENA */
+#define WM9090_MIXOUTR_ENA                      0x0010  /* MIXOUTR_ENA */
+#define WM9090_MIXOUTR_ENA_MASK                 0x0010  /* MIXOUTR_ENA */
+#define WM9090_MIXOUTR_ENA_SHIFT                     4  /* MIXOUTR_ENA */
+#define WM9090_MIXOUTR_ENA_WIDTH                     1  /* MIXOUTR_ENA */
+#define WM9090_SPKMIX_ENA                       0x0008  /* SPKMIX_ENA */
+#define WM9090_SPKMIX_ENA_MASK                  0x0008  /* SPKMIX_ENA */
+#define WM9090_SPKMIX_ENA_SHIFT                      3  /* SPKMIX_ENA */
+#define WM9090_SPKMIX_ENA_WIDTH                      1  /* SPKMIX_ENA */
+
+/*
+ * R6 (0x06) - Clocking 1
+ */
+#define WM9090_TOCLK_RATE                       0x8000  /* TOCLK_RATE */
+#define WM9090_TOCLK_RATE_MASK                  0x8000  /* TOCLK_RATE */
+#define WM9090_TOCLK_RATE_SHIFT                     15  /* TOCLK_RATE */
+#define WM9090_TOCLK_RATE_WIDTH                      1  /* TOCLK_RATE */
+#define WM9090_TOCLK_ENA                        0x4000  /* TOCLK_ENA */
+#define WM9090_TOCLK_ENA_MASK                   0x4000  /* TOCLK_ENA */
+#define WM9090_TOCLK_ENA_SHIFT                      14  /* TOCLK_ENA */
+#define WM9090_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+
+/*
+ * R22 (0x16) - IN1 Line Control
+ */
+#define WM9090_IN1_DIFF                         0x0002  /* IN1_DIFF */
+#define WM9090_IN1_DIFF_MASK                    0x0002  /* IN1_DIFF */
+#define WM9090_IN1_DIFF_SHIFT                        1  /* IN1_DIFF */
+#define WM9090_IN1_DIFF_WIDTH                        1  /* IN1_DIFF */
+#define WM9090_IN1_CLAMP                        0x0001  /* IN1_CLAMP */
+#define WM9090_IN1_CLAMP_MASK                   0x0001  /* IN1_CLAMP */
+#define WM9090_IN1_CLAMP_SHIFT                       0  /* IN1_CLAMP */
+#define WM9090_IN1_CLAMP_WIDTH                       1  /* IN1_CLAMP */
+
+/*
+ * R23 (0x17) - IN2 Line Control
+ */
+#define WM9090_IN2_DIFF                         0x0002  /* IN2_DIFF */
+#define WM9090_IN2_DIFF_MASK                    0x0002  /* IN2_DIFF */
+#define WM9090_IN2_DIFF_SHIFT                        1  /* IN2_DIFF */
+#define WM9090_IN2_DIFF_WIDTH                        1  /* IN2_DIFF */
+#define WM9090_IN2_CLAMP                        0x0001  /* IN2_CLAMP */
+#define WM9090_IN2_CLAMP_MASK                   0x0001  /* IN2_CLAMP */
+#define WM9090_IN2_CLAMP_SHIFT                       0  /* IN2_CLAMP */
+#define WM9090_IN2_CLAMP_WIDTH                       1  /* IN2_CLAMP */
+
+/*
+ * R24 (0x18) - IN1 Line Input A Volume
+ */
+#define WM9090_IN1_VU                           0x0100  /* IN1_VU */
+#define WM9090_IN1_VU_MASK                      0x0100  /* IN1_VU */
+#define WM9090_IN1_VU_SHIFT                          8  /* IN1_VU */
+#define WM9090_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM9090_IN1A_MUTE                        0x0080  /* IN1A_MUTE */
+#define WM9090_IN1A_MUTE_MASK                   0x0080  /* IN1A_MUTE */
+#define WM9090_IN1A_MUTE_SHIFT                       7  /* IN1A_MUTE */
+#define WM9090_IN1A_MUTE_WIDTH                       1  /* IN1A_MUTE */
+#define WM9090_IN1A_ZC                          0x0040  /* IN1A_ZC */
+#define WM9090_IN1A_ZC_MASK                     0x0040  /* IN1A_ZC */
+#define WM9090_IN1A_ZC_SHIFT                         6  /* IN1A_ZC */
+#define WM9090_IN1A_ZC_WIDTH                         1  /* IN1A_ZC */
+#define WM9090_IN1A_VOL_MASK                    0x0007  /* IN1A_VOL - [2:0] */
+#define WM9090_IN1A_VOL_SHIFT                        0  /* IN1A_VOL - [2:0] */
+#define WM9090_IN1A_VOL_WIDTH                        3  /* IN1A_VOL - [2:0] */
+
+/*
+ * R25 (0x19) - IN1  Line Input B Volume
+ */
+#define WM9090_IN1_VU                           0x0100  /* IN1_VU */
+#define WM9090_IN1_VU_MASK                      0x0100  /* IN1_VU */
+#define WM9090_IN1_VU_SHIFT                          8  /* IN1_VU */
+#define WM9090_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM9090_IN1B_MUTE                        0x0080  /* IN1B_MUTE */
+#define WM9090_IN1B_MUTE_MASK                   0x0080  /* IN1B_MUTE */
+#define WM9090_IN1B_MUTE_SHIFT                       7  /* IN1B_MUTE */
+#define WM9090_IN1B_MUTE_WIDTH                       1  /* IN1B_MUTE */
+#define WM9090_IN1B_ZC                          0x0040  /* IN1B_ZC */
+#define WM9090_IN1B_ZC_MASK                     0x0040  /* IN1B_ZC */
+#define WM9090_IN1B_ZC_SHIFT                         6  /* IN1B_ZC */
+#define WM9090_IN1B_ZC_WIDTH                         1  /* IN1B_ZC */
+#define WM9090_IN1B_VOL_MASK                    0x0007  /* IN1B_VOL - [2:0] */
+#define WM9090_IN1B_VOL_SHIFT                        0  /* IN1B_VOL - [2:0] */
+#define WM9090_IN1B_VOL_WIDTH                        3  /* IN1B_VOL - [2:0] */
+
+/*
+ * R26 (0x1A) - IN2 Line Input A Volume
+ */
+#define WM9090_IN2_VU                           0x0100  /* IN2_VU */
+#define WM9090_IN2_VU_MASK                      0x0100  /* IN2_VU */
+#define WM9090_IN2_VU_SHIFT                          8  /* IN2_VU */
+#define WM9090_IN2_VU_WIDTH                          1  /* IN2_VU */
+#define WM9090_IN2A_MUTE                        0x0080  /* IN2A_MUTE */
+#define WM9090_IN2A_MUTE_MASK                   0x0080  /* IN2A_MUTE */
+#define WM9090_IN2A_MUTE_SHIFT                       7  /* IN2A_MUTE */
+#define WM9090_IN2A_MUTE_WIDTH                       1  /* IN2A_MUTE */
+#define WM9090_IN2A_ZC                          0x0040  /* IN2A_ZC */
+#define WM9090_IN2A_ZC_MASK                     0x0040  /* IN2A_ZC */
+#define WM9090_IN2A_ZC_SHIFT                         6  /* IN2A_ZC */
+#define WM9090_IN2A_ZC_WIDTH                         1  /* IN2A_ZC */
+#define WM9090_IN2A_VOL_MASK                    0x0007  /* IN2A_VOL - [2:0] */
+#define WM9090_IN2A_VOL_SHIFT                        0  /* IN2A_VOL - [2:0] */
+#define WM9090_IN2A_VOL_WIDTH                        3  /* IN2A_VOL - [2:0] */
+
+/*
+ * R27 (0x1B) - IN2 Line Input B Volume
+ */
+#define WM9090_IN2_VU                           0x0100  /* IN2_VU */
+#define WM9090_IN2_VU_MASK                      0x0100  /* IN2_VU */
+#define WM9090_IN2_VU_SHIFT                          8  /* IN2_VU */
+#define WM9090_IN2_VU_WIDTH                          1  /* IN2_VU */
+#define WM9090_IN2B_MUTE                        0x0080  /* IN2B_MUTE */
+#define WM9090_IN2B_MUTE_MASK                   0x0080  /* IN2B_MUTE */
+#define WM9090_IN2B_MUTE_SHIFT                       7  /* IN2B_MUTE */
+#define WM9090_IN2B_MUTE_WIDTH                       1  /* IN2B_MUTE */
+#define WM9090_IN2B_ZC                          0x0040  /* IN2B_ZC */
+#define WM9090_IN2B_ZC_MASK                     0x0040  /* IN2B_ZC */
+#define WM9090_IN2B_ZC_SHIFT                         6  /* IN2B_ZC */
+#define WM9090_IN2B_ZC_WIDTH                         1  /* IN2B_ZC */
+#define WM9090_IN2B_VOL_MASK                    0x0007  /* IN2B_VOL - [2:0] */
+#define WM9090_IN2B_VOL_SHIFT                        0  /* IN2B_VOL - [2:0] */
+#define WM9090_IN2B_VOL_WIDTH                        3  /* IN2B_VOL - [2:0] */
+
+/*
+ * R28 (0x1C) - Left Output Volume
+ */
+#define WM9090_HPOUT1_VU                        0x0100  /* HPOUT1_VU */
+#define WM9090_HPOUT1_VU_MASK                   0x0100  /* HPOUT1_VU */
+#define WM9090_HPOUT1_VU_SHIFT                       8  /* HPOUT1_VU */
+#define WM9090_HPOUT1_VU_WIDTH                       1  /* HPOUT1_VU */
+#define WM9090_HPOUT1L_ZC                       0x0080  /* HPOUT1L_ZC */
+#define WM9090_HPOUT1L_ZC_MASK                  0x0080  /* HPOUT1L_ZC */
+#define WM9090_HPOUT1L_ZC_SHIFT                      7  /* HPOUT1L_ZC */
+#define WM9090_HPOUT1L_ZC_WIDTH                      1  /* HPOUT1L_ZC */
+#define WM9090_HPOUT1L_MUTE                     0x0040  /* HPOUT1L_MUTE */
+#define WM9090_HPOUT1L_MUTE_MASK                0x0040  /* HPOUT1L_MUTE */
+#define WM9090_HPOUT1L_MUTE_SHIFT                    6  /* HPOUT1L_MUTE */
+#define WM9090_HPOUT1L_MUTE_WIDTH                    1  /* HPOUT1L_MUTE */
+#define WM9090_HPOUT1L_VOL_MASK                 0x003F  /* HPOUT1L_VOL - [5:0] */
+#define WM9090_HPOUT1L_VOL_SHIFT                     0  /* HPOUT1L_VOL - [5:0] */
+#define WM9090_HPOUT1L_VOL_WIDTH                     6  /* HPOUT1L_VOL - [5:0] */
+
+/*
+ * R29 (0x1D) - Right Output Volume
+ */
+#define WM9090_HPOUT1_VU                        0x0100  /* HPOUT1_VU */
+#define WM9090_HPOUT1_VU_MASK                   0x0100  /* HPOUT1_VU */
+#define WM9090_HPOUT1_VU_SHIFT                       8  /* HPOUT1_VU */
+#define WM9090_HPOUT1_VU_WIDTH                       1  /* HPOUT1_VU */
+#define WM9090_HPOUT1R_ZC                       0x0080  /* HPOUT1R_ZC */
+#define WM9090_HPOUT1R_ZC_MASK                  0x0080  /* HPOUT1R_ZC */
+#define WM9090_HPOUT1R_ZC_SHIFT                      7  /* HPOUT1R_ZC */
+#define WM9090_HPOUT1R_ZC_WIDTH                      1  /* HPOUT1R_ZC */
+#define WM9090_HPOUT1R_MUTE                     0x0040  /* HPOUT1R_MUTE */
+#define WM9090_HPOUT1R_MUTE_MASK                0x0040  /* HPOUT1R_MUTE */
+#define WM9090_HPOUT1R_MUTE_SHIFT                    6  /* HPOUT1R_MUTE */
+#define WM9090_HPOUT1R_MUTE_WIDTH                    1  /* HPOUT1R_MUTE */
+#define WM9090_HPOUT1R_VOL_MASK                 0x003F  /* HPOUT1R_VOL - [5:0] */
+#define WM9090_HPOUT1R_VOL_SHIFT                     0  /* HPOUT1R_VOL - [5:0] */
+#define WM9090_HPOUT1R_VOL_WIDTH                     6  /* HPOUT1R_VOL - [5:0] */
+
+/*
+ * R34 (0x22) - SPKMIXL Attenuation
+ */
+#define WM9090_SPKMIX_MUTE                      0x0100  /* SPKMIX_MUTE */
+#define WM9090_SPKMIX_MUTE_MASK                 0x0100  /* SPKMIX_MUTE */
+#define WM9090_SPKMIX_MUTE_SHIFT                     8  /* SPKMIX_MUTE */
+#define WM9090_SPKMIX_MUTE_WIDTH                     1  /* SPKMIX_MUTE */
+#define WM9090_IN1A_SPKMIX_VOL_MASK             0x00C0  /* IN1A_SPKMIX_VOL - [7:6] */
+#define WM9090_IN1A_SPKMIX_VOL_SHIFT                 6  /* IN1A_SPKMIX_VOL - [7:6] */
+#define WM9090_IN1A_SPKMIX_VOL_WIDTH                 2  /* IN1A_SPKMIX_VOL - [7:6] */
+#define WM9090_IN1B_SPKMIX_VOL_MASK             0x0030  /* IN1B_SPKMIX_VOL - [5:4] */
+#define WM9090_IN1B_SPKMIX_VOL_SHIFT                 4  /* IN1B_SPKMIX_VOL - [5:4] */
+#define WM9090_IN1B_SPKMIX_VOL_WIDTH                 2  /* IN1B_SPKMIX_VOL - [5:4] */
+#define WM9090_IN2A_SPKMIX_VOL_MASK             0x000C  /* IN2A_SPKMIX_VOL - [3:2] */
+#define WM9090_IN2A_SPKMIX_VOL_SHIFT                 2  /* IN2A_SPKMIX_VOL - [3:2] */
+#define WM9090_IN2A_SPKMIX_VOL_WIDTH                 2  /* IN2A_SPKMIX_VOL - [3:2] */
+#define WM9090_IN2B_SPKMIX_VOL_MASK             0x0003  /* IN2B_SPKMIX_VOL - [1:0] */
+#define WM9090_IN2B_SPKMIX_VOL_SHIFT                 0  /* IN2B_SPKMIX_VOL - [1:0] */
+#define WM9090_IN2B_SPKMIX_VOL_WIDTH                 2  /* IN2B_SPKMIX_VOL - [1:0] */
+
+/*
+ * R36 (0x24) - SPKOUT Mixers
+ */
+#define WM9090_SPKMIXL_TO_SPKOUTL               0x0010  /* SPKMIXL_TO_SPKOUTL */
+#define WM9090_SPKMIXL_TO_SPKOUTL_MASK          0x0010  /* SPKMIXL_TO_SPKOUTL */
+#define WM9090_SPKMIXL_TO_SPKOUTL_SHIFT              4  /* SPKMIXL_TO_SPKOUTL */
+#define WM9090_SPKMIXL_TO_SPKOUTL_WIDTH              1  /* SPKMIXL_TO_SPKOUTL */
+
+/*
+ * R37 (0x25) - ClassD3
+ */
+#define WM9090_SPKOUTL_BOOST_MASK               0x0038  /* SPKOUTL_BOOST - [5:3] */
+#define WM9090_SPKOUTL_BOOST_SHIFT                   3  /* SPKOUTL_BOOST - [5:3] */
+#define WM9090_SPKOUTL_BOOST_WIDTH                   3  /* SPKOUTL_BOOST - [5:3] */
+
+/*
+ * R38 (0x26) - Speaker Volume Left
+ */
+#define WM9090_SPKOUT_VU                        0x0100  /* SPKOUT_VU */
+#define WM9090_SPKOUT_VU_MASK                   0x0100  /* SPKOUT_VU */
+#define WM9090_SPKOUT_VU_SHIFT                       8  /* SPKOUT_VU */
+#define WM9090_SPKOUT_VU_WIDTH                       1  /* SPKOUT_VU */
+#define WM9090_SPKOUTL_ZC                       0x0080  /* SPKOUTL_ZC */
+#define WM9090_SPKOUTL_ZC_MASK                  0x0080  /* SPKOUTL_ZC */
+#define WM9090_SPKOUTL_ZC_SHIFT                      7  /* SPKOUTL_ZC */
+#define WM9090_SPKOUTL_ZC_WIDTH                      1  /* SPKOUTL_ZC */
+#define WM9090_SPKOUTL_MUTE                     0x0040  /* SPKOUTL_MUTE */
+#define WM9090_SPKOUTL_MUTE_MASK                0x0040  /* SPKOUTL_MUTE */
+#define WM9090_SPKOUTL_MUTE_SHIFT                    6  /* SPKOUTL_MUTE */
+#define WM9090_SPKOUTL_MUTE_WIDTH                    1  /* SPKOUTL_MUTE */
+#define WM9090_SPKOUTL_VOL_MASK                 0x003F  /* SPKOUTL_VOL - [5:0] */
+#define WM9090_SPKOUTL_VOL_SHIFT                     0  /* SPKOUTL_VOL - [5:0] */
+#define WM9090_SPKOUTL_VOL_WIDTH                     6  /* SPKOUTL_VOL - [5:0] */
+
+/*
+ * R45 (0x2D) - Output Mixer1
+ */
+#define WM9090_IN1A_TO_MIXOUTL                  0x0040  /* IN1A_TO_MIXOUTL */
+#define WM9090_IN1A_TO_MIXOUTL_MASK             0x0040  /* IN1A_TO_MIXOUTL */
+#define WM9090_IN1A_TO_MIXOUTL_SHIFT                 6  /* IN1A_TO_MIXOUTL */
+#define WM9090_IN1A_TO_MIXOUTL_WIDTH                 1  /* IN1A_TO_MIXOUTL */
+#define WM9090_IN2A_TO_MIXOUTL                  0x0004  /* IN2A_TO_MIXOUTL */
+#define WM9090_IN2A_TO_MIXOUTL_MASK             0x0004  /* IN2A_TO_MIXOUTL */
+#define WM9090_IN2A_TO_MIXOUTL_SHIFT                 2  /* IN2A_TO_MIXOUTL */
+#define WM9090_IN2A_TO_MIXOUTL_WIDTH                 1  /* IN2A_TO_MIXOUTL */
+
+/*
+ * R46 (0x2E) - Output Mixer2
+ */
+#define WM9090_IN1A_TO_MIXOUTR                  0x0040  /* IN1A_TO_MIXOUTR */
+#define WM9090_IN1A_TO_MIXOUTR_MASK             0x0040  /* IN1A_TO_MIXOUTR */
+#define WM9090_IN1A_TO_MIXOUTR_SHIFT                 6  /* IN1A_TO_MIXOUTR */
+#define WM9090_IN1A_TO_MIXOUTR_WIDTH                 1  /* IN1A_TO_MIXOUTR */
+#define WM9090_IN1B_TO_MIXOUTR                  0x0010  /* IN1B_TO_MIXOUTR */
+#define WM9090_IN1B_TO_MIXOUTR_MASK             0x0010  /* IN1B_TO_MIXOUTR */
+#define WM9090_IN1B_TO_MIXOUTR_SHIFT                 4  /* IN1B_TO_MIXOUTR */
+#define WM9090_IN1B_TO_MIXOUTR_WIDTH                 1  /* IN1B_TO_MIXOUTR */
+#define WM9090_IN2A_TO_MIXOUTR                  0x0004  /* IN2A_TO_MIXOUTR */
+#define WM9090_IN2A_TO_MIXOUTR_MASK             0x0004  /* IN2A_TO_MIXOUTR */
+#define WM9090_IN2A_TO_MIXOUTR_SHIFT                 2  /* IN2A_TO_MIXOUTR */
+#define WM9090_IN2A_TO_MIXOUTR_WIDTH                 1  /* IN2A_TO_MIXOUTR */
+#define WM9090_IN2B_TO_MIXOUTR                  0x0001  /* IN2B_TO_MIXOUTR */
+#define WM9090_IN2B_TO_MIXOUTR_MASK             0x0001  /* IN2B_TO_MIXOUTR */
+#define WM9090_IN2B_TO_MIXOUTR_SHIFT                 0  /* IN2B_TO_MIXOUTR */
+#define WM9090_IN2B_TO_MIXOUTR_WIDTH                 1  /* IN2B_TO_MIXOUTR */
+
+/*
+ * R47 (0x2F) - Output Mixer3
+ */
+#define WM9090_MIXOUTL_MUTE                     0x0100  /* MIXOUTL_MUTE */
+#define WM9090_MIXOUTL_MUTE_MASK                0x0100  /* MIXOUTL_MUTE */
+#define WM9090_MIXOUTL_MUTE_SHIFT                    8  /* MIXOUTL_MUTE */
+#define WM9090_MIXOUTL_MUTE_WIDTH                    1  /* MIXOUTL_MUTE */
+#define WM9090_IN1A_MIXOUTL_VOL_MASK            0x00C0  /* IN1A_MIXOUTL_VOL - [7:6] */
+#define WM9090_IN1A_MIXOUTL_VOL_SHIFT                6  /* IN1A_MIXOUTL_VOL - [7:6] */
+#define WM9090_IN1A_MIXOUTL_VOL_WIDTH                2  /* IN1A_MIXOUTL_VOL - [7:6] */
+#define WM9090_IN2A_MIXOUTL_VOL_MASK            0x000C  /* IN2A_MIXOUTL_VOL - [3:2] */
+#define WM9090_IN2A_MIXOUTL_VOL_SHIFT                2  /* IN2A_MIXOUTL_VOL - [3:2] */
+#define WM9090_IN2A_MIXOUTL_VOL_WIDTH                2  /* IN2A_MIXOUTL_VOL - [3:2] */
+
+/*
+ * R48 (0x30) - Output Mixer4
+ */
+#define WM9090_MIXOUTR_MUTE                     0x0100  /* MIXOUTR_MUTE */
+#define WM9090_MIXOUTR_MUTE_MASK                0x0100  /* MIXOUTR_MUTE */
+#define WM9090_MIXOUTR_MUTE_SHIFT                    8  /* MIXOUTR_MUTE */
+#define WM9090_MIXOUTR_MUTE_WIDTH                    1  /* MIXOUTR_MUTE */
+#define WM9090_IN1A_MIXOUTR_VOL_MASK            0x00C0  /* IN1A_MIXOUTR_VOL - [7:6] */
+#define WM9090_IN1A_MIXOUTR_VOL_SHIFT                6  /* IN1A_MIXOUTR_VOL - [7:6] */
+#define WM9090_IN1A_MIXOUTR_VOL_WIDTH                2  /* IN1A_MIXOUTR_VOL - [7:6] */
+#define WM9090_IN1B_MIXOUTR_VOL_MASK            0x0030  /* IN1B_MIXOUTR_VOL - [5:4] */
+#define WM9090_IN1B_MIXOUTR_VOL_SHIFT                4  /* IN1B_MIXOUTR_VOL - [5:4] */
+#define WM9090_IN1B_MIXOUTR_VOL_WIDTH                2  /* IN1B_MIXOUTR_VOL - [5:4] */
+#define WM9090_IN2A_MIXOUTR_VOL_MASK            0x000C  /* IN2A_MIXOUTR_VOL - [3:2] */
+#define WM9090_IN2A_MIXOUTR_VOL_SHIFT                2  /* IN2A_MIXOUTR_VOL - [3:2] */
+#define WM9090_IN2A_MIXOUTR_VOL_WIDTH                2  /* IN2A_MIXOUTR_VOL - [3:2] */
+#define WM9090_IN2B_MIXOUTR_VOL_MASK            0x0003  /* IN2B_MIXOUTR_VOL - [1:0] */
+#define WM9090_IN2B_MIXOUTR_VOL_SHIFT                0  /* IN2B_MIXOUTR_VOL - [1:0] */
+#define WM9090_IN2B_MIXOUTR_VOL_WIDTH                2  /* IN2B_MIXOUTR_VOL - [1:0] */
+
+/*
+ * R54 (0x36) - Speaker Mixer
+ */
+#define WM9090_IN1A_TO_SPKMIX                   0x0040  /* IN1A_TO_SPKMIX */
+#define WM9090_IN1A_TO_SPKMIX_MASK              0x0040  /* IN1A_TO_SPKMIX */
+#define WM9090_IN1A_TO_SPKMIX_SHIFT                  6  /* IN1A_TO_SPKMIX */
+#define WM9090_IN1A_TO_SPKMIX_WIDTH                  1  /* IN1A_TO_SPKMIX */
+#define WM9090_IN1B_TO_SPKMIX                   0x0010  /* IN1B_TO_SPKMIX */
+#define WM9090_IN1B_TO_SPKMIX_MASK              0x0010  /* IN1B_TO_SPKMIX */
+#define WM9090_IN1B_TO_SPKMIX_SHIFT                  4  /* IN1B_TO_SPKMIX */
+#define WM9090_IN1B_TO_SPKMIX_WIDTH                  1  /* IN1B_TO_SPKMIX */
+#define WM9090_IN2A_TO_SPKMIX                   0x0004  /* IN2A_TO_SPKMIX */
+#define WM9090_IN2A_TO_SPKMIX_MASK              0x0004  /* IN2A_TO_SPKMIX */
+#define WM9090_IN2A_TO_SPKMIX_SHIFT                  2  /* IN2A_TO_SPKMIX */
+#define WM9090_IN2A_TO_SPKMIX_WIDTH                  1  /* IN2A_TO_SPKMIX */
+#define WM9090_IN2B_TO_SPKMIX                   0x0001  /* IN2B_TO_SPKMIX */
+#define WM9090_IN2B_TO_SPKMIX_MASK              0x0001  /* IN2B_TO_SPKMIX */
+#define WM9090_IN2B_TO_SPKMIX_SHIFT                  0  /* IN2B_TO_SPKMIX */
+#define WM9090_IN2B_TO_SPKMIX_WIDTH                  1  /* IN2B_TO_SPKMIX */
+
+/*
+ * R57 (0x39) - AntiPOP2
+ */
+#define WM9090_VMID_BUF_ENA                     0x0008  /* VMID_BUF_ENA */
+#define WM9090_VMID_BUF_ENA_MASK                0x0008  /* VMID_BUF_ENA */
+#define WM9090_VMID_BUF_ENA_SHIFT                    3  /* VMID_BUF_ENA */
+#define WM9090_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
+#define WM9090_VMID_ENA                         0x0001  /* VMID_ENA */
+#define WM9090_VMID_ENA_MASK                    0x0001  /* VMID_ENA */
+#define WM9090_VMID_ENA_SHIFT                        0  /* VMID_ENA */
+#define WM9090_VMID_ENA_WIDTH                        1  /* VMID_ENA */
+
+/*
+ * R70 (0x46) - Write Sequencer 0
+ */
+#define WM9090_WSEQ_ENA                         0x0100  /* WSEQ_ENA */
+#define WM9090_WSEQ_ENA_MASK                    0x0100  /* WSEQ_ENA */
+#define WM9090_WSEQ_ENA_SHIFT                        8  /* WSEQ_ENA */
+#define WM9090_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM9090_WSEQ_WRITE_INDEX_MASK            0x000F  /* WSEQ_WRITE_INDEX - [3:0] */
+#define WM9090_WSEQ_WRITE_INDEX_SHIFT                0  /* WSEQ_WRITE_INDEX - [3:0] */
+#define WM9090_WSEQ_WRITE_INDEX_WIDTH                4  /* WSEQ_WRITE_INDEX - [3:0] */
+
+/*
+ * R71 (0x47) - Write Sequencer 1
+ */
+#define WM9090_WSEQ_DATA_WIDTH_MASK             0x7000  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM9090_WSEQ_DATA_WIDTH_SHIFT                12  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM9090_WSEQ_DATA_WIDTH_WIDTH                 3  /* WSEQ_DATA_WIDTH - [14:12] */
+#define WM9090_WSEQ_DATA_START_MASK             0x0F00  /* WSEQ_DATA_START - [11:8] */
+#define WM9090_WSEQ_DATA_START_SHIFT                 8  /* WSEQ_DATA_START - [11:8] */
+#define WM9090_WSEQ_DATA_START_WIDTH                 4  /* WSEQ_DATA_START - [11:8] */
+#define WM9090_WSEQ_ADDR_MASK                   0x00FF  /* WSEQ_ADDR - [7:0] */
+#define WM9090_WSEQ_ADDR_SHIFT                       0  /* WSEQ_ADDR - [7:0] */
+#define WM9090_WSEQ_ADDR_WIDTH                       8  /* WSEQ_ADDR - [7:0] */
+
+/*
+ * R72 (0x48) - Write Sequencer 2
+ */
+#define WM9090_WSEQ_EOS                         0x4000  /* WSEQ_EOS */
+#define WM9090_WSEQ_EOS_MASK                    0x4000  /* WSEQ_EOS */
+#define WM9090_WSEQ_EOS_SHIFT                       14  /* WSEQ_EOS */
+#define WM9090_WSEQ_EOS_WIDTH                        1  /* WSEQ_EOS */
+#define WM9090_WSEQ_DELAY_MASK                  0x0F00  /* WSEQ_DELAY - [11:8] */
+#define WM9090_WSEQ_DELAY_SHIFT                      8  /* WSEQ_DELAY - [11:8] */
+#define WM9090_WSEQ_DELAY_WIDTH                      4  /* WSEQ_DELAY - [11:8] */
+#define WM9090_WSEQ_DATA_MASK                   0x00FF  /* WSEQ_DATA - [7:0] */
+#define WM9090_WSEQ_DATA_SHIFT                       0  /* WSEQ_DATA - [7:0] */
+#define WM9090_WSEQ_DATA_WIDTH                       8  /* WSEQ_DATA - [7:0] */
+
+/*
+ * R73 (0x49) - Write Sequencer 3
+ */
+#define WM9090_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM9090_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM9090_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM9090_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM9090_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM9090_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM9090_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM9090_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM9090_WSEQ_START_INDEX_MASK            0x003F  /* WSEQ_START_INDEX - [5:0] */
+#define WM9090_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [5:0] */
+#define WM9090_WSEQ_START_INDEX_WIDTH                6  /* WSEQ_START_INDEX - [5:0] */
+
+/*
+ * R74 (0x4A) - Write Sequencer 4
+ */
+#define WM9090_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM9090_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM9090_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM9090_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R75 (0x4B) - Write Sequencer 5
+ */
+#define WM9090_WSEQ_CURRENT_INDEX_MASK          0x003F  /* WSEQ_CURRENT_INDEX - [5:0] */
+#define WM9090_WSEQ_CURRENT_INDEX_SHIFT              0  /* WSEQ_CURRENT_INDEX - [5:0] */
+#define WM9090_WSEQ_CURRENT_INDEX_WIDTH              6  /* WSEQ_CURRENT_INDEX - [5:0] */
+
+/*
+ * R76 (0x4C) - Charge Pump 1
+ */
+#define WM9090_CP_ENA                           0x8000  /* CP_ENA */
+#define WM9090_CP_ENA_MASK                      0x8000  /* CP_ENA */
+#define WM9090_CP_ENA_SHIFT                         15  /* CP_ENA */
+#define WM9090_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R84 (0x54) - DC Servo 0
+ */
+#define WM9090_DCS_TRIG_SINGLE_1                0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM9090_DCS_TRIG_SINGLE_1_MASK           0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM9090_DCS_TRIG_SINGLE_1_SHIFT              13  /* DCS_TRIG_SINGLE_1 */
+#define WM9090_DCS_TRIG_SINGLE_1_WIDTH               1  /* DCS_TRIG_SINGLE_1 */
+#define WM9090_DCS_TRIG_SINGLE_0                0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM9090_DCS_TRIG_SINGLE_0_MASK           0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM9090_DCS_TRIG_SINGLE_0_SHIFT              12  /* DCS_TRIG_SINGLE_0 */
+#define WM9090_DCS_TRIG_SINGLE_0_WIDTH               1  /* DCS_TRIG_SINGLE_0 */
+#define WM9090_DCS_TRIG_SERIES_1                0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM9090_DCS_TRIG_SERIES_1_MASK           0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM9090_DCS_TRIG_SERIES_1_SHIFT               9  /* DCS_TRIG_SERIES_1 */
+#define WM9090_DCS_TRIG_SERIES_1_WIDTH               1  /* DCS_TRIG_SERIES_1 */
+#define WM9090_DCS_TRIG_SERIES_0                0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM9090_DCS_TRIG_SERIES_0_MASK           0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM9090_DCS_TRIG_SERIES_0_SHIFT               8  /* DCS_TRIG_SERIES_0 */
+#define WM9090_DCS_TRIG_SERIES_0_WIDTH               1  /* DCS_TRIG_SERIES_0 */
+#define WM9090_DCS_TRIG_STARTUP_1               0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM9090_DCS_TRIG_STARTUP_1_MASK          0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM9090_DCS_TRIG_STARTUP_1_SHIFT              5  /* DCS_TRIG_STARTUP_1 */
+#define WM9090_DCS_TRIG_STARTUP_1_WIDTH              1  /* DCS_TRIG_STARTUP_1 */
+#define WM9090_DCS_TRIG_STARTUP_0               0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM9090_DCS_TRIG_STARTUP_0_MASK          0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM9090_DCS_TRIG_STARTUP_0_SHIFT              4  /* DCS_TRIG_STARTUP_0 */
+#define WM9090_DCS_TRIG_STARTUP_0_WIDTH              1  /* DCS_TRIG_STARTUP_0 */
+#define WM9090_DCS_TRIG_DAC_WR_1                0x0008  /* DCS_TRIG_DAC_WR_1 */
+#define WM9090_DCS_TRIG_DAC_WR_1_MASK           0x0008  /* DCS_TRIG_DAC_WR_1 */
+#define WM9090_DCS_TRIG_DAC_WR_1_SHIFT               3  /* DCS_TRIG_DAC_WR_1 */
+#define WM9090_DCS_TRIG_DAC_WR_1_WIDTH               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM9090_DCS_TRIG_DAC_WR_0                0x0004  /* DCS_TRIG_DAC_WR_0 */
+#define WM9090_DCS_TRIG_DAC_WR_0_MASK           0x0004  /* DCS_TRIG_DAC_WR_0 */
+#define WM9090_DCS_TRIG_DAC_WR_0_SHIFT               2  /* DCS_TRIG_DAC_WR_0 */
+#define WM9090_DCS_TRIG_DAC_WR_0_WIDTH               1  /* DCS_TRIG_DAC_WR_0 */
+#define WM9090_DCS_ENA_CHAN_1                   0x0002  /* DCS_ENA_CHAN_1 */
+#define WM9090_DCS_ENA_CHAN_1_MASK              0x0002  /* DCS_ENA_CHAN_1 */
+#define WM9090_DCS_ENA_CHAN_1_SHIFT                  1  /* DCS_ENA_CHAN_1 */
+#define WM9090_DCS_ENA_CHAN_1_WIDTH                  1  /* DCS_ENA_CHAN_1 */
+#define WM9090_DCS_ENA_CHAN_0                   0x0001  /* DCS_ENA_CHAN_0 */
+#define WM9090_DCS_ENA_CHAN_0_MASK              0x0001  /* DCS_ENA_CHAN_0 */
+#define WM9090_DCS_ENA_CHAN_0_SHIFT                  0  /* DCS_ENA_CHAN_0 */
+#define WM9090_DCS_ENA_CHAN_0_WIDTH                  1  /* DCS_ENA_CHAN_0 */
+
+/*
+ * R85 (0x55) - DC Servo 1
+ */
+#define WM9090_DCS_SERIES_NO_01_MASK            0x0FE0  /* DCS_SERIES_NO_01 - [11:5] */
+#define WM9090_DCS_SERIES_NO_01_SHIFT                5  /* DCS_SERIES_NO_01 - [11:5] */
+#define WM9090_DCS_SERIES_NO_01_WIDTH                7  /* DCS_SERIES_NO_01 - [11:5] */
+#define WM9090_DCS_TIMER_PERIOD_01_MASK         0x000F  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM9090_DCS_TIMER_PERIOD_01_SHIFT             0  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM9090_DCS_TIMER_PERIOD_01_WIDTH             4  /* DCS_TIMER_PERIOD_01 - [3:0] */
+
+/*
+ * R87 (0x57) - DC Servo 3
+ */
+#define WM9090_DCS_DAC_WR_VAL_1_MASK            0xFF00  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM9090_DCS_DAC_WR_VAL_1_SHIFT                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM9090_DCS_DAC_WR_VAL_1_WIDTH                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM9090_DCS_DAC_WR_VAL_0_MASK            0x00FF  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM9090_DCS_DAC_WR_VAL_0_SHIFT                0  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM9090_DCS_DAC_WR_VAL_0_WIDTH                8  /* DCS_DAC_WR_VAL_0 - [7:0] */
+
+/*
+ * R88 (0x58) - DC Servo Readback 0
+ */
+#define WM9090_DCS_CAL_COMPLETE_MASK            0x0300  /* DCS_CAL_COMPLETE - [9:8] */
+#define WM9090_DCS_CAL_COMPLETE_SHIFT                8  /* DCS_CAL_COMPLETE - [9:8] */
+#define WM9090_DCS_CAL_COMPLETE_WIDTH                2  /* DCS_CAL_COMPLETE - [9:8] */
+#define WM9090_DCS_DAC_WR_COMPLETE_MASK         0x0030  /* DCS_DAC_WR_COMPLETE - [5:4] */
+#define WM9090_DCS_DAC_WR_COMPLETE_SHIFT             4  /* DCS_DAC_WR_COMPLETE - [5:4] */
+#define WM9090_DCS_DAC_WR_COMPLETE_WIDTH             2  /* DCS_DAC_WR_COMPLETE - [5:4] */
+#define WM9090_DCS_STARTUP_COMPLETE_MASK        0x0003  /* DCS_STARTUP_COMPLETE - [1:0] */
+#define WM9090_DCS_STARTUP_COMPLETE_SHIFT            0  /* DCS_STARTUP_COMPLETE - [1:0] */
+#define WM9090_DCS_STARTUP_COMPLETE_WIDTH            2  /* DCS_STARTUP_COMPLETE - [1:0] */
+
+/*
+ * R89 (0x59) - DC Servo Readback 1
+ */
+#define WM9090_DCS_DAC_WR_VAL_1_RD_MASK         0x00FF  /* DCS_DAC_WR_VAL_1_RD - [7:0] */
+#define WM9090_DCS_DAC_WR_VAL_1_RD_SHIFT             0  /* DCS_DAC_WR_VAL_1_RD - [7:0] */
+#define WM9090_DCS_DAC_WR_VAL_1_RD_WIDTH             8  /* DCS_DAC_WR_VAL_1_RD - [7:0] */
+
+/*
+ * R90 (0x5A) - DC Servo Readback 2
+ */
+#define WM9090_DCS_DAC_WR_VAL_0_RD_MASK         0x00FF  /* DCS_DAC_WR_VAL_0_RD - [7:0] */
+#define WM9090_DCS_DAC_WR_VAL_0_RD_SHIFT             0  /* DCS_DAC_WR_VAL_0_RD - [7:0] */
+#define WM9090_DCS_DAC_WR_VAL_0_RD_WIDTH             8  /* DCS_DAC_WR_VAL_0_RD - [7:0] */
+
+/*
+ * R96 (0x60) - Analogue HP 0
+ */
+#define WM9090_HPOUT1L_RMV_SHORT                0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM9090_HPOUT1L_RMV_SHORT_MASK           0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM9090_HPOUT1L_RMV_SHORT_SHIFT               7  /* HPOUT1L_RMV_SHORT */
+#define WM9090_HPOUT1L_RMV_SHORT_WIDTH               1  /* HPOUT1L_RMV_SHORT */
+#define WM9090_HPOUT1L_OUTP                     0x0040  /* HPOUT1L_OUTP */
+#define WM9090_HPOUT1L_OUTP_MASK                0x0040  /* HPOUT1L_OUTP */
+#define WM9090_HPOUT1L_OUTP_SHIFT                    6  /* HPOUT1L_OUTP */
+#define WM9090_HPOUT1L_OUTP_WIDTH                    1  /* HPOUT1L_OUTP */
+#define WM9090_HPOUT1L_DLY                      0x0020  /* HPOUT1L_DLY */
+#define WM9090_HPOUT1L_DLY_MASK                 0x0020  /* HPOUT1L_DLY */
+#define WM9090_HPOUT1L_DLY_SHIFT                     5  /* HPOUT1L_DLY */
+#define WM9090_HPOUT1L_DLY_WIDTH                     1  /* HPOUT1L_DLY */
+#define WM9090_HPOUT1R_RMV_SHORT                0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM9090_HPOUT1R_RMV_SHORT_MASK           0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM9090_HPOUT1R_RMV_SHORT_SHIFT               3  /* HPOUT1R_RMV_SHORT */
+#define WM9090_HPOUT1R_RMV_SHORT_WIDTH               1  /* HPOUT1R_RMV_SHORT */
+#define WM9090_HPOUT1R_OUTP                     0x0004  /* HPOUT1R_OUTP */
+#define WM9090_HPOUT1R_OUTP_MASK                0x0004  /* HPOUT1R_OUTP */
+#define WM9090_HPOUT1R_OUTP_SHIFT                    2  /* HPOUT1R_OUTP */
+#define WM9090_HPOUT1R_OUTP_WIDTH                    1  /* HPOUT1R_OUTP */
+#define WM9090_HPOUT1R_DLY                      0x0002  /* HPOUT1R_DLY */
+#define WM9090_HPOUT1R_DLY_MASK                 0x0002  /* HPOUT1R_DLY */
+#define WM9090_HPOUT1R_DLY_SHIFT                     1  /* HPOUT1R_DLY */
+#define WM9090_HPOUT1R_DLY_WIDTH                     1  /* HPOUT1R_DLY */
+
+/*
+ * R98 (0x62) - AGC Control 0
+ */
+#define WM9090_AGC_CLIP_ENA                     0x8000  /* AGC_CLIP_ENA */
+#define WM9090_AGC_CLIP_ENA_MASK                0x8000  /* AGC_CLIP_ENA */
+#define WM9090_AGC_CLIP_ENA_SHIFT                   15  /* AGC_CLIP_ENA */
+#define WM9090_AGC_CLIP_ENA_WIDTH                    1  /* AGC_CLIP_ENA */
+#define WM9090_AGC_CLIP_THR_MASK                0x0F00  /* AGC_CLIP_THR - [11:8] */
+#define WM9090_AGC_CLIP_THR_SHIFT                    8  /* AGC_CLIP_THR - [11:8] */
+#define WM9090_AGC_CLIP_THR_WIDTH                    4  /* AGC_CLIP_THR - [11:8] */
+#define WM9090_AGC_CLIP_ATK_MASK                0x0070  /* AGC_CLIP_ATK - [6:4] */
+#define WM9090_AGC_CLIP_ATK_SHIFT                    4  /* AGC_CLIP_ATK - [6:4] */
+#define WM9090_AGC_CLIP_ATK_WIDTH                    3  /* AGC_CLIP_ATK - [6:4] */
+#define WM9090_AGC_CLIP_DCY_MASK                0x0007  /* AGC_CLIP_DCY - [2:0] */
+#define WM9090_AGC_CLIP_DCY_SHIFT                    0  /* AGC_CLIP_DCY - [2:0] */
+#define WM9090_AGC_CLIP_DCY_WIDTH                    3  /* AGC_CLIP_DCY - [2:0] */
+
+/*
+ * R99 (0x63) - AGC Control 1
+ */
+#define WM9090_AGC_PWR_ENA                      0x8000  /* AGC_PWR_ENA */
+#define WM9090_AGC_PWR_ENA_MASK                 0x8000  /* AGC_PWR_ENA */
+#define WM9090_AGC_PWR_ENA_SHIFT                    15  /* AGC_PWR_ENA */
+#define WM9090_AGC_PWR_ENA_WIDTH                     1  /* AGC_PWR_ENA */
+#define WM9090_AGC_PWR_AVG                      0x1000  /* AGC_PWR_AVG */
+#define WM9090_AGC_PWR_AVG_MASK                 0x1000  /* AGC_PWR_AVG */
+#define WM9090_AGC_PWR_AVG_SHIFT                    12  /* AGC_PWR_AVG */
+#define WM9090_AGC_PWR_AVG_WIDTH                     1  /* AGC_PWR_AVG */
+#define WM9090_AGC_PWR_THR_MASK                 0x0F00  /* AGC_PWR_THR - [11:8] */
+#define WM9090_AGC_PWR_THR_SHIFT                     8  /* AGC_PWR_THR - [11:8] */
+#define WM9090_AGC_PWR_THR_WIDTH                     4  /* AGC_PWR_THR - [11:8] */
+#define WM9090_AGC_PWR_ATK_MASK                 0x0070  /* AGC_PWR_ATK - [6:4] */
+#define WM9090_AGC_PWR_ATK_SHIFT                     4  /* AGC_PWR_ATK - [6:4] */
+#define WM9090_AGC_PWR_ATK_WIDTH                     3  /* AGC_PWR_ATK - [6:4] */
+#define WM9090_AGC_PWR_DCY_MASK                 0x0007  /* AGC_PWR_DCY - [2:0] */
+#define WM9090_AGC_PWR_DCY_SHIFT                     0  /* AGC_PWR_DCY - [2:0] */
+#define WM9090_AGC_PWR_DCY_WIDTH                     3  /* AGC_PWR_DCY - [2:0] */
+
+/*
+ * R100 (0x64) - AGC Control 2
+ */
+#define WM9090_AGC_RAMP                         0x0100  /* AGC_RAMP */
+#define WM9090_AGC_RAMP_MASK                    0x0100  /* AGC_RAMP */
+#define WM9090_AGC_RAMP_SHIFT                        8  /* AGC_RAMP */
+#define WM9090_AGC_RAMP_WIDTH                        1  /* AGC_RAMP */
+#define WM9090_AGC_MINGAIN_MASK                 0x003F  /* AGC_MINGAIN - [5:0] */
+#define WM9090_AGC_MINGAIN_SHIFT                     0  /* AGC_MINGAIN - [5:0] */
+#define WM9090_AGC_MINGAIN_WIDTH                     6  /* AGC_MINGAIN - [5:0] */
+
+#endif
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
new file mode 100644
index 0000000..ccdf088
--- /dev/null
+++ b/sound/soc/codecs/wm9705.c
@@ -0,0 +1,407 @@
+/*
+ * wm9705.c  --  ALSA Soc WM9705 codec support
+ *
+ * Copyright 2008 Ian Molton <spyro@f2s.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation; Version 2 of the  License only.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/mfd/wm97xx.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/ac97/codec.h>
+#include <sound/ac97/compat.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#define WM9705_VENDOR_ID 0x574d4c05
+#define WM9705_VENDOR_ID_MASK 0xffffffff
+
+struct wm9705_priv {
+	struct snd_ac97 *ac97;
+	struct wm97xx_platform_data *mfd_pdata;
+};
+
+static const struct reg_default wm9705_reg_defaults[] = {
+	{ 0x02, 0x8000 },
+	{ 0x04, 0x8000 },
+	{ 0x06, 0x8000 },
+	{ 0x0a, 0x8000 },
+	{ 0x0c, 0x8008 },
+	{ 0x0e, 0x8008 },
+	{ 0x10, 0x8808 },
+	{ 0x12, 0x8808 },
+	{ 0x14, 0x8808 },
+	{ 0x16, 0x8808 },
+	{ 0x18, 0x8808 },
+	{ 0x1a, 0x0000 },
+	{ 0x1c, 0x8000 },
+	{ 0x20, 0x0000 },
+	{ 0x22, 0x0000 },
+	{ 0x26, 0x000f },
+	{ 0x28, 0x0605 },
+	{ 0x2a, 0x0000 },
+	{ 0x2c, 0xbb80 },
+	{ 0x32, 0xbb80 },
+	{ 0x34, 0x2000 },
+	{ 0x5a, 0x0000 },
+	{ 0x5c, 0x0000 },
+	{ 0x72, 0x0808 },
+	{ 0x74, 0x0000 },
+	{ 0x76, 0x0006 },
+	{ 0x78, 0x0000 },
+	{ 0x7a, 0x0000 },
+};
+
+static const struct regmap_config wm9705_regmap_config = {
+	.reg_bits = 16,
+	.reg_stride = 2,
+	.val_bits = 16,
+	.max_register = 0x7e,
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = regmap_ac97_default_volatile,
+
+	.reg_defaults = wm9705_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm9705_reg_defaults),
+};
+
+static const struct snd_kcontrol_new wm9705_snd_ac97_controls[] = {
+	SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1),
+	SOC_SINGLE("Master Playback Switch", AC97_MASTER, 15, 1, 1),
+	SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
+	SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1),
+	SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1),
+	SOC_SINGLE("PCM Playback Switch", AC97_PCM, 15, 1, 1),
+	SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1),
+	SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
+	SOC_SINGLE("PCBeep Playback Volume", AC97_PC_BEEP, 1, 15, 1),
+	SOC_SINGLE("Phone Playback Volume", AC97_PHONE, 0, 31, 1),
+	SOC_DOUBLE("Line Playback Volume", AC97_LINE, 8, 0, 31, 1),
+	SOC_DOUBLE("CD Playback Volume", AC97_CD, 8, 0, 31, 1),
+	SOC_SINGLE("Mic Playback Volume", AC97_MIC, 0, 31, 1),
+	SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 6, 1, 0),
+	SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 0),
+	SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1),
+};
+
+static const char *wm9705_mic[] = {"Mic 1", "Mic 2"};
+static const char *wm9705_rec_sel[] = {"Mic", "CD", "NC", "NC",
+	"Line", "Stereo Mix", "Mono Mix", "Phone"};
+
+static SOC_ENUM_SINGLE_DECL(wm9705_enum_mic,
+			    AC97_GENERAL_PURPOSE, 8, wm9705_mic);
+static SOC_ENUM_SINGLE_DECL(wm9705_enum_rec_l,
+			    AC97_REC_SEL, 8, wm9705_rec_sel);
+static SOC_ENUM_SINGLE_DECL(wm9705_enum_rec_r,
+			    AC97_REC_SEL, 0, wm9705_rec_sel);
+
+/* Headphone Mixer */
+static const struct snd_kcontrol_new wm9705_hp_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PCBeep Playback Switch", AC97_PC_BEEP, 15, 1, 1),
+	SOC_DAPM_SINGLE("CD Playback Switch", AC97_CD, 15, 1, 1),
+	SOC_DAPM_SINGLE("Mic Playback Switch", AC97_MIC, 15, 1, 1),
+	SOC_DAPM_SINGLE("Phone Playback Switch", AC97_PHONE, 15, 1, 1),
+	SOC_DAPM_SINGLE("Line Playback Switch", AC97_LINE, 15, 1, 1),
+};
+
+/* Mic source */
+static const struct snd_kcontrol_new wm9705_mic_src_controls =
+	SOC_DAPM_ENUM("Route", wm9705_enum_mic);
+
+/* Capture source */
+static const struct snd_kcontrol_new wm9705_capture_selectl_controls =
+	SOC_DAPM_ENUM("Route", wm9705_enum_rec_l);
+static const struct snd_kcontrol_new wm9705_capture_selectr_controls =
+	SOC_DAPM_ENUM("Route", wm9705_enum_rec_r);
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget wm9705_dapm_widgets[] = {
+	SND_SOC_DAPM_MUX("Mic Source", SND_SOC_NOPM, 0, 0,
+		&wm9705_mic_src_controls),
+	SND_SOC_DAPM_MUX("Left Capture Source", SND_SOC_NOPM, 0, 0,
+		&wm9705_capture_selectl_controls),
+	SND_SOC_DAPM_MUX("Right Capture Source", SND_SOC_NOPM, 0, 0,
+		&wm9705_capture_selectr_controls),
+	SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback",
+		SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback",
+		SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_MIXER_NAMED_CTL("HP Mixer", SND_SOC_NOPM, 0, 0,
+		&wm9705_hp_mixer_controls[0],
+		ARRAY_SIZE(wm9705_hp_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_PGA("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Speaker PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Line PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Line out PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Phone PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mic PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PCBEEP PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("CD PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("ADC PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("HPOUTL"),
+	SND_SOC_DAPM_OUTPUT("HPOUTR"),
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+	SND_SOC_DAPM_OUTPUT("ROUT"),
+	SND_SOC_DAPM_OUTPUT("MONOOUT"),
+	SND_SOC_DAPM_INPUT("PHONE"),
+	SND_SOC_DAPM_INPUT("LINEINL"),
+	SND_SOC_DAPM_INPUT("LINEINR"),
+	SND_SOC_DAPM_INPUT("CDINL"),
+	SND_SOC_DAPM_INPUT("CDINR"),
+	SND_SOC_DAPM_INPUT("PCBEEP"),
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+};
+
+/* Audio map
+ * WM9705 has no switches to disable the route from the inputs to the HP mixer
+ * so in order to prevent active inputs from forcing the audio outputs to be
+ * constantly enabled, we use the mutes on those inputs to simulate such
+ * controls.
+ */
+static const struct snd_soc_dapm_route wm9705_audio_map[] = {
+	/* HP mixer */
+	{"HP Mixer", "PCBeep Playback Switch", "PCBEEP PGA"},
+	{"HP Mixer", "CD Playback Switch", "CD PGA"},
+	{"HP Mixer", "Mic Playback Switch", "Mic PGA"},
+	{"HP Mixer", "Phone Playback Switch", "Phone PGA"},
+	{"HP Mixer", "Line Playback Switch", "Line PGA"},
+	{"HP Mixer", NULL, "Left DAC"},
+	{"HP Mixer", NULL, "Right DAC"},
+
+	/* mono mixer */
+	{"Mono Mixer", NULL, "HP Mixer"},
+
+	/* outputs */
+	{"Headphone PGA", NULL, "HP Mixer"},
+	{"HPOUTL", NULL, "Headphone PGA"},
+	{"HPOUTR", NULL, "Headphone PGA"},
+	{"Line out PGA", NULL, "HP Mixer"},
+	{"LOUT", NULL, "Line out PGA"},
+	{"ROUT", NULL, "Line out PGA"},
+	{"Mono PGA", NULL, "Mono Mixer"},
+	{"MONOOUT", NULL, "Mono PGA"},
+
+	/* inputs */
+	{"CD PGA", NULL, "CDINL"},
+	{"CD PGA", NULL, "CDINR"},
+	{"Line PGA", NULL, "LINEINL"},
+	{"Line PGA", NULL, "LINEINR"},
+	{"Phone PGA", NULL, "PHONE"},
+	{"Mic Source", "Mic 1", "MIC1"},
+	{"Mic Source", "Mic 2", "MIC2"},
+	{"Mic PGA", NULL, "Mic Source"},
+	{"PCBEEP PGA", NULL, "PCBEEP"},
+
+	/* Left capture selector */
+	{"Left Capture Source", "Mic", "Mic Source"},
+	{"Left Capture Source", "CD", "CDINL"},
+	{"Left Capture Source", "Line", "LINEINL"},
+	{"Left Capture Source", "Stereo Mix", "HP Mixer"},
+	{"Left Capture Source", "Mono Mix", "HP Mixer"},
+	{"Left Capture Source", "Phone", "PHONE"},
+
+	/* Right capture source */
+	{"Right Capture Source", "Mic", "Mic Source"},
+	{"Right Capture Source", "CD", "CDINR"},
+	{"Right Capture Source", "Line", "LINEINR"},
+	{"Right Capture Source", "Stereo Mix", "HP Mixer"},
+	{"Right Capture Source", "Mono Mix", "HP Mixer"},
+	{"Right Capture Source", "Phone", "PHONE"},
+
+	{"ADC PGA", NULL, "Left Capture Source"},
+	{"ADC PGA", NULL, "Right Capture Source"},
+
+	/* ADC's */
+	{"Left ADC",  NULL, "ADC PGA"},
+	{"Right ADC", NULL, "ADC PGA"},
+};
+
+static int ac97_prepare(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	int reg;
+
+	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x1, 0x1);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		reg = AC97_PCM_FRONT_DAC_RATE;
+	else
+		reg = AC97_PCM_LR_ADC_RATE;
+
+	return snd_soc_component_write(component, reg, substream->runtime->rate);
+}
+
+#define WM9705_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
+			SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+			SNDRV_PCM_RATE_48000)
+
+static const struct snd_soc_dai_ops wm9705_dai_ops = {
+	.prepare	= ac97_prepare,
+};
+
+static struct snd_soc_dai_driver wm9705_dai[] = {
+	{
+		.name = "wm9705-hifi",
+		.playback = {
+			.stream_name = "HiFi Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM9705_AC97_RATES,
+			.formats = SND_SOC_STD_AC97_FMTS,
+		},
+		.capture = {
+			.stream_name = "HiFi Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM9705_AC97_RATES,
+			.formats = SND_SOC_STD_AC97_FMTS,
+		},
+		.ops = &wm9705_dai_ops,
+	},
+	{
+		.name = "wm9705-aux",
+		.playback = {
+			.stream_name = "Aux Playback",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = WM9705_AC97_RATES,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+	}
+};
+
+#ifdef CONFIG_PM
+static int wm9705_soc_suspend(struct snd_soc_component *component)
+{
+	regcache_cache_bypass(component->regmap, true);
+	snd_soc_component_write(component, AC97_POWERDOWN, 0xffff);
+	regcache_cache_bypass(component->regmap, false);
+
+	return 0;
+}
+
+static int wm9705_soc_resume(struct snd_soc_component *component)
+{
+	struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = snd_ac97_reset(wm9705->ac97, true, WM9705_VENDOR_ID,
+		WM9705_VENDOR_ID_MASK);
+	if (ret < 0)
+		return ret;
+
+	snd_soc_component_cache_sync(component);
+
+	return 0;
+}
+#else
+#define wm9705_soc_suspend NULL
+#define wm9705_soc_resume NULL
+#endif
+
+static int wm9705_soc_probe(struct snd_soc_component *component)
+{
+	struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap;
+
+	if (wm9705->mfd_pdata) {
+		wm9705->ac97 = wm9705->mfd_pdata->ac97;
+		regmap = wm9705->mfd_pdata->regmap;
+	} else {
+#ifdef CONFIG_SND_SOC_AC97_BUS
+		wm9705->ac97 = snd_soc_new_ac97_component(component, WM9705_VENDOR_ID,
+						      WM9705_VENDOR_ID_MASK);
+		if (IS_ERR(wm9705->ac97)) {
+			dev_err(component->dev, "Failed to register AC97 codec\n");
+			return PTR_ERR(wm9705->ac97);
+		}
+
+		regmap = regmap_init_ac97(wm9705->ac97, &wm9705_regmap_config);
+		if (IS_ERR(regmap)) {
+			snd_soc_free_ac97_component(wm9705->ac97);
+			return PTR_ERR(regmap);
+		}
+#endif
+	}
+
+	snd_soc_component_set_drvdata(component, wm9705->ac97);
+	snd_soc_component_init_regmap(component, regmap);
+
+	return 0;
+}
+
+static void wm9705_soc_remove(struct snd_soc_component *component)
+{
+#ifdef CONFIG_SND_SOC_AC97_BUS
+	struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component);
+
+	if (!wm9705->mfd_pdata) {
+		snd_soc_component_exit_regmap(component);
+		snd_soc_free_ac97_component(wm9705->ac97);
+	}
+#endif
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm9705 = {
+	.probe			= wm9705_soc_probe,
+	.remove			= wm9705_soc_remove,
+	.suspend		= wm9705_soc_suspend,
+	.resume			= wm9705_soc_resume,
+	.controls		= wm9705_snd_ac97_controls,
+	.num_controls		= ARRAY_SIZE(wm9705_snd_ac97_controls),
+	.dapm_widgets		= wm9705_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm9705_dapm_widgets),
+	.dapm_routes		= wm9705_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(wm9705_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm9705_probe(struct platform_device *pdev)
+{
+	struct wm9705_priv *wm9705;
+
+	wm9705 = devm_kzalloc(&pdev->dev, sizeof(*wm9705), GFP_KERNEL);
+	if (wm9705 == NULL)
+		return -ENOMEM;
+
+	wm9705->mfd_pdata = dev_get_platdata(&pdev->dev);
+	platform_set_drvdata(pdev, wm9705);
+
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm9705, wm9705_dai, ARRAY_SIZE(wm9705_dai));
+}
+
+static struct platform_driver wm9705_codec_driver = {
+	.driver = {
+			.name = "wm9705-codec",
+	},
+
+	.probe = wm9705_probe,
+};
+
+module_platform_driver(wm9705_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM9705 driver");
+MODULE_AUTHOR("Ian Molton");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
new file mode 100644
index 0000000..ade34c2
--- /dev/null
+++ b/sound/soc/codecs/wm9712.c
@@ -0,0 +1,732 @@
+/*
+ * wm9712.c  --  ALSA Soc WM9712 codec support
+ *
+ * Copyright 2006-12 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/mfd/wm97xx.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/ac97/codec.h>
+#include <sound/ac97/compat.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#define WM9712_VENDOR_ID 0x574d4c12
+#define WM9712_VENDOR_ID_MASK 0xffffffff
+
+struct wm9712_priv {
+	struct snd_ac97 *ac97;
+	unsigned int hp_mixer[2];
+	struct mutex lock;
+	struct wm97xx_platform_data *mfd_pdata;
+};
+
+static const struct reg_default wm9712_reg_defaults[] = {
+	{ 0x02, 0x8000 },
+	{ 0x04, 0x8000 },
+	{ 0x06, 0x8000 },
+	{ 0x08, 0x0f0f },
+	{ 0x0a, 0xaaa0 },
+	{ 0x0c, 0xc008 },
+	{ 0x0e, 0x6808 },
+	{ 0x10, 0xe808 },
+	{ 0x12, 0xaaa0 },
+	{ 0x14, 0xad00 },
+	{ 0x16, 0x8000 },
+	{ 0x18, 0xe808 },
+	{ 0x1a, 0x3000 },
+	{ 0x1c, 0x8000 },
+	{ 0x20, 0x0000 },
+	{ 0x22, 0x0000 },
+	{ 0x26, 0x000f },
+	{ 0x28, 0x0605 },
+	{ 0x2a, 0x0410 },
+	{ 0x2c, 0xbb80 },
+	{ 0x2e, 0xbb80 },
+	{ 0x32, 0xbb80 },
+	{ 0x34, 0x2000 },
+	{ 0x4c, 0xf83e },
+	{ 0x4e, 0xffff },
+	{ 0x50, 0x0000 },
+	{ 0x52, 0x0000 },
+	{ 0x56, 0xf83e },
+	{ 0x58, 0x0008 },
+	{ 0x5c, 0x0000 },
+	{ 0x60, 0xb032 },
+	{ 0x62, 0x3e00 },
+	{ 0x64, 0x0000 },
+	{ 0x76, 0x0006 },
+	{ 0x78, 0x0001 },
+	{ 0x7a, 0x0000 },
+};
+
+static bool wm9712_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AC97_REC_GAIN:
+		return true;
+	default:
+		return regmap_ac97_default_volatile(dev, reg);
+	}
+}
+
+static const struct regmap_config wm9712_regmap_config = {
+	.reg_bits = 16,
+	.reg_stride = 2,
+	.val_bits = 16,
+	.max_register = 0x7e,
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = wm9712_volatile_reg,
+
+	.reg_defaults = wm9712_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm9712_reg_defaults),
+};
+
+#define HPL_MIXER	0x0
+#define HPR_MIXER	0x1
+
+static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"};
+static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"};
+static const char *wm9712_out3_src[] = {"Left", "VREF", "Left + Right",
+	"Mono"};
+static const char *wm9712_spk_src[] = {"Speaker Mix", "Headphone Mix"};
+static const char *wm9712_rec_adc[] = {"Stereo", "Left", "Right", "Mute"};
+static const char *wm9712_base[] = {"Linear Control", "Adaptive Boost"};
+static const char *wm9712_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
+static const char *wm9712_mic[] = {"Mic 1", "Differential", "Mic 2",
+	"Stereo"};
+static const char *wm9712_rec_sel[] = {"Mic", "NC", "NC", "Speaker Mixer",
+	"Line", "Headphone Mixer", "Phone Mixer", "Phone"};
+static const char *wm9712_ng_type[] = {"Constant Gain", "Mute"};
+static const char *wm9712_diff_sel[] = {"Mic", "Line"};
+
+static const DECLARE_TLV_DB_SCALE(main_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 2000, 0);
+
+static const struct soc_enum wm9712_enum[] = {
+SOC_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9712_alc_select),
+SOC_ENUM_SINGLE(AC97_VIDEO, 12, 4, wm9712_alc_mux),
+SOC_ENUM_SINGLE(AC97_AUX, 9, 4, wm9712_out3_src),
+SOC_ENUM_SINGLE(AC97_AUX, 8, 2, wm9712_spk_src),
+SOC_ENUM_SINGLE(AC97_REC_SEL, 12, 4, wm9712_rec_adc),
+SOC_ENUM_SINGLE(AC97_MASTER_TONE, 15, 2, wm9712_base),
+SOC_ENUM_DOUBLE(AC97_REC_GAIN, 14, 6, 2, wm9712_rec_gain),
+SOC_ENUM_SINGLE(AC97_MIC, 5, 4, wm9712_mic),
+SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9712_rec_sel),
+SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9712_rec_sel),
+SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9712_ng_type),
+SOC_ENUM_SINGLE(0x5c, 8, 2, wm9712_diff_sel),
+};
+
+static const struct snd_kcontrol_new wm9712_snd_ac97_controls[] = {
+SOC_DOUBLE("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1),
+SOC_SINGLE("Speaker Playback Switch", AC97_MASTER, 15, 1, 1),
+SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
+SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1),
+SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1),
+
+SOC_SINGLE("Speaker Playback ZC Switch", AC97_MASTER, 7, 1, 0),
+SOC_SINGLE("Speaker Playback Invert Switch", AC97_MASTER, 6, 1, 0),
+SOC_SINGLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 7, 1, 0),
+SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_MONO, 7, 1, 0),
+SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1),
+SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
+
+SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
+SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
+SOC_SINGLE("ALC Decay Time", AC97_CODEC_CLASS_REV, 4, 15, 0),
+SOC_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
+SOC_ENUM("ALC Function", wm9712_enum[0]),
+SOC_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 0),
+SOC_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 1),
+SOC_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
+SOC_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
+SOC_ENUM("ALC NG Type", wm9712_enum[10]),
+SOC_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 1),
+
+SOC_SINGLE("Mic Headphone  Volume", AC97_VIDEO, 12, 7, 1),
+SOC_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1),
+
+SOC_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1),
+SOC_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1),
+SOC_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1),
+
+SOC_SINGLE("PCBeep Bypass Headphone Volume", AC97_PC_BEEP, 12, 7, 1),
+SOC_SINGLE("PCBeep Bypass Speaker Volume", AC97_PC_BEEP, 8, 7, 1),
+SOC_SINGLE("PCBeep Bypass Phone Volume", AC97_PC_BEEP, 4, 7, 1),
+
+SOC_SINGLE("Aux Playback Headphone Volume", AC97_CD, 12, 7, 1),
+SOC_SINGLE("Aux Playback Speaker Volume", AC97_CD, 8, 7, 1),
+SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1),
+
+SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 1),
+SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1),
+
+SOC_SINGLE_TLV("Capture Boost Switch", AC97_REC_SEL, 14, 1, 0, boost_tlv),
+SOC_SINGLE_TLV("Capture to Phone Boost Switch", AC97_REC_SEL, 11, 1, 1,
+	       boost_tlv),
+
+SOC_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1),
+SOC_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1),
+SOC_SINGLE("3D Playback Volume", AC97_3D_CONTROL, 0, 15, 0),
+
+SOC_ENUM("Bass Control", wm9712_enum[5]),
+SOC_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1),
+SOC_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1),
+SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
+SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 1),
+SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 1),
+
+SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1),
+SOC_ENUM("Capture Volume Steps", wm9712_enum[6]),
+SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 0),
+SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
+
+SOC_SINGLE_TLV("Mic 1 Volume", AC97_MIC, 8, 31, 1, main_tlv),
+SOC_SINGLE_TLV("Mic 2 Volume", AC97_MIC, 0, 31, 1, main_tlv),
+SOC_SINGLE_TLV("Mic Boost Volume", AC97_MIC, 7, 1, 0, boost_tlv),
+};
+
+static const unsigned int wm9712_mixer_mute_regs[] = {
+	AC97_VIDEO,
+	AC97_PCM,
+	AC97_LINE,
+	AC97_PHONE,
+	AC97_CD,
+	AC97_PC_BEEP,
+};
+
+/* We have to create a fake left and right HP mixers because
+ * the codec only has a single control that is shared by both channels.
+ * This makes it impossible to determine the audio path.
+ */
+static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+	struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
+	unsigned int val = ucontrol->value.integer.value[0];
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned int mixer, mask, shift, old;
+	struct snd_soc_dapm_update update = {};
+	bool change;
+
+	mixer = mc->shift >> 8;
+	shift = mc->shift & 0xff;
+	mask = 1 << shift;
+
+	mutex_lock(&wm9712->lock);
+	old = wm9712->hp_mixer[mixer];
+	if (ucontrol->value.integer.value[0])
+		wm9712->hp_mixer[mixer] |= mask;
+	else
+		wm9712->hp_mixer[mixer] &= ~mask;
+
+	change = old != wm9712->hp_mixer[mixer];
+	if (change) {
+		update.kcontrol = kcontrol;
+		update.reg = wm9712_mixer_mute_regs[shift];
+		update.mask = 0x8000;
+		if ((wm9712->hp_mixer[0] & mask) ||
+		    (wm9712->hp_mixer[1] & mask))
+			update.val = 0x0;
+		else
+			update.val = 0x8000;
+
+		snd_soc_dapm_mixer_update_power(dapm, kcontrol, val,
+			&update);
+	}
+
+	mutex_unlock(&wm9712->lock);
+
+	return change;
+}
+
+static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+	struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned int shift, mixer;
+
+	mixer = mc->shift >> 8;
+	shift = mc->shift & 0xff;
+
+	ucontrol->value.integer.value[0] =
+		(wm9712->hp_mixer[mixer] >> shift) & 1;
+
+	return 0;
+}
+
+#define WM9712_HP_MIXER_CTRL(xname, xmixer, xshift) { \
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_volsw, \
+	.get = wm9712_hp_mixer_get, .put = wm9712_hp_mixer_put, \
+	.private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, \
+		(xmixer << 8) | xshift, 1, 0, 0) \
+}
+
+/* Left Headphone Mixers */
+static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = {
+	WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPL_MIXER, 5),
+	WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 4),
+	WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPL_MIXER, 3),
+	WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPL_MIXER, 2),
+	WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 1),
+	WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPL_MIXER, 0),
+};
+
+/* Right Headphone Mixers */
+static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = {
+	WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPR_MIXER, 5),
+	WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 4),
+	WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPR_MIXER, 3),
+	WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPR_MIXER, 2),
+	WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 1),
+	WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPR_MIXER, 0),
+};
+
+/* Speaker Mixer */
+static const struct snd_kcontrol_new wm9712_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 11, 1, 1),
+	SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 11, 1, 1),
+	SOC_DAPM_SINGLE("Phone Bypass Switch", AC97_PHONE, 14, 1, 1),
+	SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 14, 1, 1),
+	SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 14, 1, 1),
+};
+
+/* Phone Mixer */
+static const struct snd_kcontrol_new wm9712_phone_mixer_controls[] = {
+	SOC_DAPM_SINGLE("PCBeep Bypass Switch", AC97_PC_BEEP, 7, 1, 1),
+	SOC_DAPM_SINGLE("Aux Playback Switch", AC97_CD, 7, 1, 1),
+	SOC_DAPM_SINGLE("Line Bypass Switch", AC97_LINE, 13, 1, 1),
+	SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PCM, 13, 1, 1),
+	SOC_DAPM_SINGLE("Mic 1 Sidetone Switch", AC97_MIC, 14, 1, 1),
+	SOC_DAPM_SINGLE("Mic 2 Sidetone Switch", AC97_MIC, 13, 1, 1),
+};
+
+/* ALC headphone mux */
+static const struct snd_kcontrol_new wm9712_alc_mux_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[1]);
+
+/* out 3 mux */
+static const struct snd_kcontrol_new wm9712_out3_mux_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[2]);
+
+/* spk mux */
+static const struct snd_kcontrol_new wm9712_spk_mux_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[3]);
+
+/* Capture to Phone mux */
+static const struct snd_kcontrol_new wm9712_capture_phone_mux_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[4]);
+
+/* Capture left select */
+static const struct snd_kcontrol_new wm9712_capture_selectl_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[8]);
+
+/* Capture right select */
+static const struct snd_kcontrol_new wm9712_capture_selectr_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[9]);
+
+/* Mic select */
+static const struct snd_kcontrol_new wm9712_mic_src_controls =
+SOC_DAPM_ENUM("Mic Source Select", wm9712_enum[7]);
+
+/* diff select */
+static const struct snd_kcontrol_new wm9712_diff_sel_controls =
+SOC_DAPM_ENUM("Route", wm9712_enum[11]);
+
+static const struct snd_soc_dapm_widget wm9712_dapm_widgets[] = {
+SND_SOC_DAPM_MUX("ALC Sidetone Mux", SND_SOC_NOPM, 0, 0,
+	&wm9712_alc_mux_controls),
+SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0,
+	&wm9712_out3_mux_controls),
+SND_SOC_DAPM_MUX("Speaker Mux", SND_SOC_NOPM, 0, 0,
+	&wm9712_spk_mux_controls),
+SND_SOC_DAPM_MUX("Capture Phone Mux", SND_SOC_NOPM, 0, 0,
+	&wm9712_capture_phone_mux_controls),
+SND_SOC_DAPM_MUX("Left Capture Select", SND_SOC_NOPM, 0, 0,
+	&wm9712_capture_selectl_controls),
+SND_SOC_DAPM_MUX("Right Capture Select", SND_SOC_NOPM, 0, 0,
+	&wm9712_capture_selectr_controls),
+SND_SOC_DAPM_MUX("Left Mic Select Source", SND_SOC_NOPM, 0, 0,
+	&wm9712_mic_src_controls),
+SND_SOC_DAPM_MUX("Right Mic Select Source", SND_SOC_NOPM, 0, 0,
+	&wm9712_mic_src_controls),
+SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0,
+	&wm9712_diff_sel_controls),
+SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_INT_PAGING, 9, 1,
+	&wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls)),
+SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_INT_PAGING, 8, 1,
+	&wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls)),
+SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1,
+	&wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)),
+SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1,
+	&wm9712_speaker_mixer_controls[0],
+	ARRAY_SIZE(wm9712_speaker_mixer_controls)),
+SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", AC97_INT_PAGING, 14, 1),
+SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", AC97_INT_PAGING, 13, 1),
+SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", AC97_INT_PAGING, 12, 1),
+SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", AC97_INT_PAGING, 11, 1),
+SND_SOC_DAPM_PGA("Headphone PGA", AC97_INT_PAGING, 4, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Speaker PGA", AC97_INT_PAGING, 3, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Out 3 PGA", AC97_INT_PAGING, 5, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Line PGA", AC97_INT_PAGING, 2, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Phone PGA", AC97_INT_PAGING, 1, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mic PGA", AC97_INT_PAGING, 0, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Differential Mic", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias", AC97_INT_PAGING, 10, 1),
+SND_SOC_DAPM_OUTPUT("MONOOUT"),
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+SND_SOC_DAPM_OUTPUT("LOUT2"),
+SND_SOC_DAPM_OUTPUT("ROUT2"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+SND_SOC_DAPM_INPUT("LINEINL"),
+SND_SOC_DAPM_INPUT("LINEINR"),
+SND_SOC_DAPM_INPUT("PHONE"),
+SND_SOC_DAPM_INPUT("PCBEEP"),
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2"),
+};
+
+static const struct snd_soc_dapm_route wm9712_audio_map[] = {
+	/* virtual mixer - mixes left & right channels for spk and mono */
+	{"AC97 Mixer", NULL, "Left DAC"},
+	{"AC97 Mixer", NULL, "Right DAC"},
+
+	/* Left HP mixer */
+	{"Left HP Mixer", "PCBeep Bypass Switch", "PCBEEP"},
+	{"Left HP Mixer", "Aux Playback Switch",  "Aux DAC"},
+	{"Left HP Mixer", "Phone Bypass Switch",  "Phone PGA"},
+	{"Left HP Mixer", "Line Bypass Switch",   "Line PGA"},
+	{"Left HP Mixer", "PCM Playback Switch",  "Left DAC"},
+	{"Left HP Mixer", "Mic Sidetone Switch",  "Mic PGA"},
+	{"Left HP Mixer", NULL,  "ALC Sidetone Mux"},
+
+	/* Right HP mixer */
+	{"Right HP Mixer", "PCBeep Bypass Switch", "PCBEEP"},
+	{"Right HP Mixer", "Aux Playback Switch",  "Aux DAC"},
+	{"Right HP Mixer", "Phone Bypass Switch",  "Phone PGA"},
+	{"Right HP Mixer", "Line Bypass Switch",   "Line PGA"},
+	{"Right HP Mixer", "PCM Playback Switch",  "Right DAC"},
+	{"Right HP Mixer", "Mic Sidetone Switch",  "Mic PGA"},
+	{"Right HP Mixer", NULL,  "ALC Sidetone Mux"},
+
+	/* speaker mixer */
+	{"Speaker Mixer", "PCBeep Bypass Switch", "PCBEEP"},
+	{"Speaker Mixer", "Line Bypass Switch",   "Line PGA"},
+	{"Speaker Mixer", "PCM Playback Switch",  "AC97 Mixer"},
+	{"Speaker Mixer", "Phone Bypass Switch",  "Phone PGA"},
+	{"Speaker Mixer", "Aux Playback Switch",  "Aux DAC"},
+
+	/* Phone mixer */
+	{"Phone Mixer", "PCBeep Bypass Switch",  "PCBEEP"},
+	{"Phone Mixer", "Line Bypass Switch",    "Line PGA"},
+	{"Phone Mixer", "Aux Playback Switch",   "Aux DAC"},
+	{"Phone Mixer", "PCM Playback Switch",   "AC97 Mixer"},
+	{"Phone Mixer", "Mic 1 Sidetone Switch", "Mic PGA"},
+	{"Phone Mixer", "Mic 2 Sidetone Switch", "Mic PGA"},
+
+	/* inputs */
+	{"Line PGA", NULL, "LINEINL"},
+	{"Line PGA", NULL, "LINEINR"},
+	{"Phone PGA", NULL, "PHONE"},
+	{"Mic PGA", NULL, "MIC1"},
+	{"Mic PGA", NULL, "MIC2"},
+
+	/* microphones */
+	{"Differential Mic", NULL, "MIC1"},
+	{"Differential Mic", NULL, "MIC2"},
+	{"Left Mic Select Source", "Mic 1", "MIC1"},
+	{"Left Mic Select Source", "Mic 2", "MIC2"},
+	{"Left Mic Select Source", "Stereo", "MIC1"},
+	{"Left Mic Select Source", "Differential", "Differential Mic"},
+	{"Right Mic Select Source", "Mic 1", "MIC1"},
+	{"Right Mic Select Source", "Mic 2", "MIC2"},
+	{"Right Mic Select Source", "Stereo", "MIC2"},
+	{"Right Mic Select Source", "Differential", "Differential Mic"},
+
+	/* left capture selector */
+	{"Left Capture Select", "Mic", "MIC1"},
+	{"Left Capture Select", "Speaker Mixer", "Speaker Mixer"},
+	{"Left Capture Select", "Line", "LINEINL"},
+	{"Left Capture Select", "Headphone Mixer", "Left HP Mixer"},
+	{"Left Capture Select", "Phone Mixer", "Phone Mixer"},
+	{"Left Capture Select", "Phone", "PHONE"},
+
+	/* right capture selector */
+	{"Right Capture Select", "Mic", "MIC2"},
+	{"Right Capture Select", "Speaker Mixer", "Speaker Mixer"},
+	{"Right Capture Select", "Line", "LINEINR"},
+	{"Right Capture Select", "Headphone Mixer", "Right HP Mixer"},
+	{"Right Capture Select", "Phone Mixer", "Phone Mixer"},
+	{"Right Capture Select", "Phone", "PHONE"},
+
+	/* ALC Sidetone */
+	{"ALC Sidetone Mux", "Stereo", "Left Capture Select"},
+	{"ALC Sidetone Mux", "Stereo", "Right Capture Select"},
+	{"ALC Sidetone Mux", "Left", "Left Capture Select"},
+	{"ALC Sidetone Mux", "Right", "Right Capture Select"},
+
+	/* ADC's */
+	{"Left ADC", NULL, "Left Capture Select"},
+	{"Right ADC", NULL, "Right Capture Select"},
+
+	/* outputs */
+	{"MONOOUT", NULL, "Phone Mixer"},
+	{"HPOUTL", NULL, "Headphone PGA"},
+	{"Headphone PGA", NULL, "Left HP Mixer"},
+	{"HPOUTR", NULL, "Headphone PGA"},
+	{"Headphone PGA", NULL, "Right HP Mixer"},
+
+	/* mono mixer */
+	{"Mono Mixer", NULL, "Left HP Mixer"},
+	{"Mono Mixer", NULL, "Right HP Mixer"},
+
+	/* Out3 Mux */
+	{"Out3 Mux", "Left", "Left HP Mixer"},
+	{"Out3 Mux", "Mono", "Phone Mixer"},
+	{"Out3 Mux", "Left + Right", "Mono Mixer"},
+	{"Out 3 PGA", NULL, "Out3 Mux"},
+	{"OUT3", NULL, "Out 3 PGA"},
+
+	/* speaker Mux */
+	{"Speaker Mux", "Speaker Mix", "Speaker Mixer"},
+	{"Speaker Mux", "Headphone Mix", "Mono Mixer"},
+	{"Speaker PGA", NULL, "Speaker Mux"},
+	{"LOUT2", NULL, "Speaker PGA"},
+	{"ROUT2", NULL, "Speaker PGA"},
+};
+
+static int ac97_prepare(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	int reg;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x1, 0x1);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		reg = AC97_PCM_FRONT_DAC_RATE;
+	else
+		reg = AC97_PCM_LR_ADC_RATE;
+
+	return snd_soc_component_write(component, reg, runtime->rate);
+}
+
+static int ac97_aux_prepare(struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x1, 0x1);
+	snd_soc_component_update_bits(component, AC97_PCI_SID, 0x8000, 0x8000);
+
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+		return -ENODEV;
+
+	return snd_soc_component_write(component, AC97_PCM_SURR_DAC_RATE, runtime->rate);
+}
+
+#define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
+		SNDRV_PCM_RATE_48000)
+
+static const struct snd_soc_dai_ops wm9712_dai_ops_hifi = {
+	.prepare	= ac97_prepare,
+};
+
+static const struct snd_soc_dai_ops wm9712_dai_ops_aux = {
+	.prepare	= ac97_aux_prepare,
+};
+
+static struct snd_soc_dai_driver wm9712_dai[] = {
+{
+	.name = "wm9712-hifi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM9712_AC97_RATES,
+		.formats = SND_SOC_STD_AC97_FMTS,},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM9712_AC97_RATES,
+		.formats = SND_SOC_STD_AC97_FMTS,},
+	.ops = &wm9712_dai_ops_hifi,
+},
+{
+	.name = "wm9712-aux",
+	.playback = {
+		.stream_name = "Aux Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = WM9712_AC97_RATES,
+		.formats = SND_SOC_STD_AC97_FMTS,},
+	.ops = &wm9712_dai_ops_aux,
+}
+};
+
+static int wm9712_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		snd_soc_component_write(component, AC97_POWERDOWN, 0x0000);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* disable everything including AC link */
+		snd_soc_component_write(component, AC97_EXTENDED_MSTATUS, 0xffff);
+		snd_soc_component_write(component, AC97_POWERDOWN, 0xffff);
+		break;
+	}
+	return 0;
+}
+
+static int wm9712_soc_resume(struct snd_soc_component *component)
+{
+	struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = snd_ac97_reset(wm9712->ac97, true, WM9712_VENDOR_ID,
+		WM9712_VENDOR_ID_MASK);
+	if (ret < 0)
+		return ret;
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	if (ret == 0)
+		snd_soc_component_cache_sync(component);
+
+	return ret;
+}
+
+static int wm9712_soc_probe(struct snd_soc_component *component)
+{
+	struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap;
+	int ret;
+
+	if (wm9712->mfd_pdata) {
+		wm9712->ac97 = wm9712->mfd_pdata->ac97;
+		regmap = wm9712->mfd_pdata->regmap;
+	} else {
+#ifdef CONFIG_SND_SOC_AC97_BUS
+		wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID,
+						      WM9712_VENDOR_ID_MASK);
+		if (IS_ERR(wm9712->ac97)) {
+			ret = PTR_ERR(wm9712->ac97);
+			dev_err(component->dev,
+				"Failed to register AC97 codec: %d\n", ret);
+			return ret;
+		}
+
+		regmap = regmap_init_ac97(wm9712->ac97, &wm9712_regmap_config);
+		if (IS_ERR(regmap)) {
+			snd_soc_free_ac97_component(wm9712->ac97);
+			return PTR_ERR(regmap);
+		}
+#endif
+	}
+
+	snd_soc_component_init_regmap(component, regmap);
+
+	/* set alc mux to none */
+	snd_soc_component_update_bits(component, AC97_VIDEO, 0x3000, 0x3000);
+
+	return 0;
+}
+
+static void wm9712_soc_remove(struct snd_soc_component *component)
+{
+#ifdef CONFIG_SND_SOC_AC97_BUS
+	struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
+
+	if (!wm9712->mfd_pdata) {
+		snd_soc_component_exit_regmap(component);
+		snd_soc_free_ac97_component(wm9712->ac97);
+	}
+#endif
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm9712 = {
+	.probe			= wm9712_soc_probe,
+	.remove			= wm9712_soc_remove,
+	.resume			= wm9712_soc_resume,
+	.set_bias_level		= wm9712_set_bias_level,
+	.controls		= wm9712_snd_ac97_controls,
+	.num_controls		= ARRAY_SIZE(wm9712_snd_ac97_controls),
+	.dapm_widgets		= wm9712_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm9712_dapm_widgets),
+	.dapm_routes		= wm9712_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(wm9712_audio_map),
+	.suspend_bias_off	= 1,
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm9712_probe(struct platform_device *pdev)
+{
+	struct wm9712_priv *wm9712;
+
+	wm9712 = devm_kzalloc(&pdev->dev, sizeof(*wm9712), GFP_KERNEL);
+	if (wm9712 == NULL)
+		return -ENOMEM;
+
+	mutex_init(&wm9712->lock);
+
+	wm9712->mfd_pdata = dev_get_platdata(&pdev->dev);
+	platform_set_drvdata(pdev, wm9712);
+
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai));
+}
+
+static struct platform_driver wm9712_component_driver = {
+	.driver = {
+		.name = "wm9712-codec",
+	},
+
+	.probe = wm9712_probe,
+};
+
+module_platform_driver(wm9712_component_driver);
+
+MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
new file mode 100644
index 0000000..643863b
--- /dev/null
+++ b/sound/soc/codecs/wm9713.c
@@ -0,0 +1,1298 @@
+/*
+ * wm9713.c  --  ALSA Soc WM9713 codec support
+ *
+ * Copyright 2006-10 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ *  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.
+ *
+ *  Features:-
+ *
+ *   o Support for AC97 Codec, Voice DAC and Aux DAC
+ *   o Support for DAPM
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/mfd/wm97xx.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/ac97/codec.h>
+#include <sound/ac97/compat.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+
+#include "wm9713.h"
+
+#define WM9713_VENDOR_ID 0x574d4c13
+#define WM9713_VENDOR_ID_MASK 0xffffffff
+
+struct wm9713_priv {
+	struct snd_ac97 *ac97;
+	u32 pll_in; /* PLL input frequency */
+	unsigned int hp_mixer[2];
+	struct mutex lock;
+	struct wm97xx_platform_data *mfd_pdata;
+};
+
+#define HPL_MIXER 0
+#define HPR_MIXER 1
+
+static const char *wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"};
+static const char *wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"};
+static const char *wm9713_rec_src[] =
+	{"Mic 1", "Mic 2", "Line", "Mono In", "Headphone", "Speaker",
+	"Mono Out", "Zh"};
+static const char *wm9713_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
+static const char *wm9713_alc_select[] = {"None", "Left", "Right", "Stereo"};
+static const char *wm9713_mono_pga[] = {"Vmid", "Zh", "Mono", "Inv"};
+static const char *wm9713_spk_pga[] =
+	{"Vmid", "Zh", "Headphone", "Speaker", "Inv", "Headphone Vmid",
+	"Speaker Vmid", "Inv Vmid"};
+static const char *wm9713_hp_pga[] = {"Vmid", "Zh", "Headphone",
+	"Headphone Vmid"};
+static const char *wm9713_out3_pga[] = {"Vmid", "Zh", "Inv 1", "Inv 1 Vmid"};
+static const char *wm9713_out4_pga[] = {"Vmid", "Zh", "Inv 2", "Inv 2 Vmid"};
+static const char *wm9713_dac_inv[] =
+	{"Off", "Mono", "Speaker", "Left Headphone", "Right Headphone",
+	"Headphone Mono", "NC", "Vmid"};
+static const char *wm9713_bass[] = {"Linear Control", "Adaptive Boost"};
+static const char *wm9713_ng_type[] = {"Constant Gain", "Mute"};
+static const char *wm9713_mic_select[] = {"Mic 1", "Mic 2 A", "Mic 2 B"};
+static const char *wm9713_micb_select[] = {"MPB", "MPA"};
+
+static const struct soc_enum wm9713_enum[] = {
+SOC_ENUM_SINGLE(AC97_LINE, 3, 4, wm9713_mic_mixer), /* record mic mixer 0 */
+SOC_ENUM_SINGLE(AC97_VIDEO, 14, 4, wm9713_rec_mux), /* record mux hp 1 */
+SOC_ENUM_SINGLE(AC97_VIDEO, 9, 4, wm9713_rec_mux),  /* record mux mono 2 */
+SOC_ENUM_SINGLE(AC97_VIDEO, 3, 8, wm9713_rec_src),  /* record mux left 3 */
+SOC_ENUM_SINGLE(AC97_VIDEO, 0, 8, wm9713_rec_src),  /* record mux right 4*/
+SOC_ENUM_DOUBLE(AC97_CD, 14, 6, 2, wm9713_rec_gain), /* record step size 5 */
+SOC_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9713_alc_select), /* alc source select 6*/
+SOC_ENUM_SINGLE(AC97_REC_GAIN, 14, 4, wm9713_mono_pga), /* mono input select 7 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN, 11, 8, wm9713_spk_pga), /* speaker left input select 8 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN, 8, 8, wm9713_spk_pga), /* speaker right input select 9 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN, 6, 3, wm9713_hp_pga), /* headphone left input 10 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN, 4, 3, wm9713_hp_pga), /* headphone right input 11 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN, 2, 4, wm9713_out3_pga), /* out 3 source 12 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN, 0, 4, wm9713_out4_pga), /* out 4 source 13 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN_MIC, 13, 8, wm9713_dac_inv), /* dac invert 1 14 */
+SOC_ENUM_SINGLE(AC97_REC_GAIN_MIC, 10, 8, wm9713_dac_inv), /* dac invert 2 15 */
+SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, wm9713_bass), /* bass control 16 */
+SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9713_ng_type), /* noise gate type 17 */
+SOC_ENUM_SINGLE(AC97_3D_CONTROL, 12, 3, wm9713_mic_select), /* mic selection 18 */
+SOC_ENUM_SINGLE_VIRT(2, wm9713_micb_select), /* mic selection 19 */
+};
+
+static const DECLARE_TLV_DB_SCALE(out_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(main_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(misc_tlv, -1500, 300, 0);
+static const  DECLARE_TLV_DB_RANGE(mic_tlv,
+	0, 2, TLV_DB_SCALE_ITEM(1200, 600, 0),
+	3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0)
+);
+
+static const struct snd_kcontrol_new wm9713_snd_ac97_controls[] = {
+SOC_DOUBLE_TLV("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1, out_tlv),
+SOC_DOUBLE("Speaker Playback Switch", AC97_MASTER, 15, 7, 1, 1),
+SOC_DOUBLE_TLV("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1,
+	       out_tlv),
+SOC_DOUBLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 7, 1, 1),
+SOC_DOUBLE_TLV("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1, main_tlv),
+SOC_DOUBLE_TLV("PCM Playback Volume", AC97_PHONE, 8, 0, 31, 1, main_tlv),
+SOC_SINGLE_TLV("Mic 1 Volume", AC97_MIC, 8, 31, 1, main_tlv),
+SOC_SINGLE_TLV("Mic 2 Volume", AC97_MIC, 0, 31, 1, main_tlv),
+SOC_SINGLE_TLV("Mic 1 Preamp Volume", AC97_3D_CONTROL, 10, 3, 0, mic_tlv),
+SOC_SINGLE_TLV("Mic 2 Preamp Volume", AC97_3D_CONTROL, 12, 3, 0, mic_tlv),
+
+SOC_SINGLE("Mic Boost (+20dB) Switch", AC97_LINE, 5, 1, 0),
+SOC_SINGLE("Mic Headphone Mixer Volume", AC97_LINE, 0, 7, 1),
+
+SOC_SINGLE("Capture Switch", AC97_CD, 15, 1, 1),
+SOC_ENUM("Capture Volume Steps", wm9713_enum[5]),
+SOC_DOUBLE("Capture Volume", AC97_CD, 8, 0, 31, 0),
+SOC_SINGLE("Capture ZC Switch", AC97_CD, 7, 1, 0),
+
+SOC_SINGLE_TLV("Capture to Headphone Volume", AC97_VIDEO, 11, 7, 1, misc_tlv),
+SOC_SINGLE("Capture to Mono Boost (+20dB) Switch", AC97_VIDEO, 8, 1, 0),
+SOC_SINGLE("Capture ADC Boost (+20dB) Switch", AC97_VIDEO, 6, 1, 0),
+
+SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
+SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
+SOC_SINGLE("ALC Decay Time", AC97_CODEC_CLASS_REV, 4, 15, 0),
+SOC_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
+SOC_ENUM("ALC Function", wm9713_enum[6]),
+SOC_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 0),
+SOC_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 0),
+SOC_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
+SOC_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
+SOC_ENUM("ALC NG Type", wm9713_enum[17]),
+SOC_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 0),
+
+SOC_DOUBLE("Speaker Playback ZC Switch", AC97_MASTER, 14, 6, 1, 0),
+SOC_DOUBLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 14, 6, 1, 0),
+
+SOC_SINGLE("Out4 Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
+SOC_SINGLE("Out4 Playback ZC Switch", AC97_MASTER_MONO, 14, 1, 0),
+SOC_SINGLE_TLV("Out4 Playback Volume", AC97_MASTER_MONO, 8, 31, 1, out_tlv),
+
+SOC_SINGLE("Out3 Playback Switch", AC97_MASTER_MONO, 7, 1, 1),
+SOC_SINGLE("Out3 Playback ZC Switch", AC97_MASTER_MONO, 6, 1, 0),
+SOC_SINGLE_TLV("Out3 Playback Volume", AC97_MASTER_MONO, 0, 31, 1, out_tlv),
+
+SOC_SINGLE_TLV("Mono Capture Volume", AC97_MASTER_TONE, 8, 31, 1, main_tlv),
+SOC_SINGLE("Mono Playback Switch", AC97_MASTER_TONE, 7, 1, 1),
+SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_TONE, 6, 1, 0),
+SOC_SINGLE_TLV("Mono Playback Volume", AC97_MASTER_TONE, 0, 31, 1, out_tlv),
+
+SOC_SINGLE_TLV("Headphone Mixer Beep Playback Volume", AC97_AUX, 12, 7, 1,
+	       misc_tlv),
+SOC_SINGLE_TLV("Speaker Mixer Beep Playback Volume", AC97_AUX, 8, 7, 1,
+	       misc_tlv),
+SOC_SINGLE_TLV("Mono Mixer Beep Playback Volume", AC97_AUX, 4, 7, 1, misc_tlv),
+
+SOC_SINGLE_TLV("Voice Playback Headphone Volume", AC97_PCM, 12, 7, 1,
+	       misc_tlv),
+SOC_SINGLE("Voice Playback Master Volume", AC97_PCM, 8, 7, 1),
+SOC_SINGLE("Voice Playback Mono Volume", AC97_PCM, 4, 7, 1),
+
+SOC_SINGLE_TLV("Headphone Mixer Aux Playback Volume", AC97_REC_SEL, 12, 7, 1,
+	       misc_tlv),
+
+SOC_SINGLE_TLV("Speaker Mixer Voice Playback Volume", AC97_PCM, 8, 7, 1,
+	       misc_tlv),
+SOC_SINGLE_TLV("Speaker Mixer Aux Playback Volume", AC97_REC_SEL, 8, 7, 1,
+	       misc_tlv),
+
+SOC_SINGLE_TLV("Mono Mixer Voice Playback Volume", AC97_PCM, 4, 7, 1,
+	       misc_tlv),
+SOC_SINGLE_TLV("Mono Mixer Aux Playback Volume", AC97_REC_SEL, 4, 7, 1,
+	       misc_tlv),
+
+SOC_SINGLE("Aux Playback Headphone Volume", AC97_REC_SEL, 12, 7, 1),
+SOC_SINGLE("Aux Playback Master Volume", AC97_REC_SEL, 8, 7, 1),
+
+SOC_ENUM("Bass Control", wm9713_enum[16]),
+SOC_SINGLE("Bass Cut-off Switch", AC97_GENERAL_PURPOSE, 12, 1, 1),
+SOC_SINGLE("Tone Cut-off Switch", AC97_GENERAL_PURPOSE, 4, 1, 1),
+SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_GENERAL_PURPOSE, 6, 1, 0),
+SOC_SINGLE("Bass Volume", AC97_GENERAL_PURPOSE, 8, 15, 1),
+SOC_SINGLE("Tone Volume", AC97_GENERAL_PURPOSE, 0, 15, 1),
+
+SOC_SINGLE("3D Upper Cut-off Switch", AC97_REC_GAIN_MIC, 5, 1, 0),
+SOC_SINGLE("3D Lower Cut-off Switch", AC97_REC_GAIN_MIC, 4, 1, 0),
+SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1),
+};
+
+static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+	if (WARN_ON(event != SND_SOC_DAPM_PRE_PMD))
+		return -EINVAL;
+
+	/* Gracefully shut down the voice interface. */
+	snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0f00, 0x0200);
+	schedule_timeout_interruptible(msecs_to_jiffies(1));
+	snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0f00, 0x0f00);
+	snd_soc_component_update_bits(component, AC97_EXTENDED_MID, 0x1000, 0x1000);
+
+	return 0;
+}
+
+static const unsigned int wm9713_mixer_mute_regs[] = {
+	AC97_PC_BEEP,
+	AC97_MASTER_TONE,
+	AC97_PHONE,
+	AC97_REC_SEL,
+	AC97_PCM,
+	AC97_AUX,
+};
+
+/* We have to create a fake left and right HP mixers because
+ * the codec only has a single control that is shared by both channels.
+ * This makes it impossible to determine the audio path using the current
+ * register map, thus we add a new (virtual) register to help determine the
+ * audio route within the device.
+ */
+static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+	struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
+	unsigned int val = ucontrol->value.integer.value[0];
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned int mixer, mask, shift, old;
+	struct snd_soc_dapm_update update = {};
+	bool change;
+
+	mixer = mc->shift >> 8;
+	shift = mc->shift & 0xff;
+	mask = (1 << shift);
+
+	mutex_lock(&wm9713->lock);
+	old = wm9713->hp_mixer[mixer];
+	if (ucontrol->value.integer.value[0])
+		wm9713->hp_mixer[mixer] |= mask;
+	else
+		wm9713->hp_mixer[mixer] &= ~mask;
+
+	change = old != wm9713->hp_mixer[mixer];
+	if (change) {
+		update.kcontrol = kcontrol;
+		update.reg = wm9713_mixer_mute_regs[shift];
+		update.mask = 0x8000;
+		if ((wm9713->hp_mixer[0] & mask) ||
+		    (wm9713->hp_mixer[1] & mask))
+			update.val = 0x0;
+		else
+			update.val = 0x8000;
+
+		snd_soc_dapm_mixer_update_power(dapm, kcontrol, val,
+			&update);
+	}
+
+	mutex_unlock(&wm9713->lock);
+
+	return change;
+}
+
+static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+	struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned int mixer, shift;
+
+	mixer = mc->shift >> 8;
+	shift = mc->shift & 0xff;
+
+	ucontrol->value.integer.value[0] =
+		(wm9713->hp_mixer[mixer] >> shift) & 1;
+
+	return 0;
+}
+
+#define WM9713_HP_MIXER_CTRL(xname, xmixer, xshift) { \
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_volsw, \
+	.get = wm9713_hp_mixer_get, .put = wm9713_hp_mixer_put, \
+	.private_value = SOC_DOUBLE_VALUE(SND_SOC_NOPM, \
+		xshift, xmixer, 1, 0, 0) \
+}
+
+/* Left Headphone Mixers */
+static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = {
+WM9713_HP_MIXER_CTRL("Beep Playback Switch", HPL_MIXER, 5),
+WM9713_HP_MIXER_CTRL("Voice Playback Switch", HPL_MIXER, 4),
+WM9713_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 3),
+WM9713_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 2),
+WM9713_HP_MIXER_CTRL("MonoIn Playback Switch", HPL_MIXER, 1),
+WM9713_HP_MIXER_CTRL("Bypass Playback Switch", HPL_MIXER, 0),
+};
+
+/* Right Headphone Mixers */
+static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = {
+WM9713_HP_MIXER_CTRL("Beep Playback Switch", HPR_MIXER, 5),
+WM9713_HP_MIXER_CTRL("Voice Playback Switch", HPR_MIXER, 4),
+WM9713_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 3),
+WM9713_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 2),
+WM9713_HP_MIXER_CTRL("MonoIn Playback Switch", HPR_MIXER, 1),
+WM9713_HP_MIXER_CTRL("Bypass Playback Switch", HPR_MIXER, 0),
+};
+
+/* headphone capture mux */
+static const struct snd_kcontrol_new wm9713_hp_rec_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[1]);
+
+/* headphone mic mux */
+static const struct snd_kcontrol_new wm9713_hp_mic_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[0]);
+
+/* Speaker Mixer */
+static const struct snd_kcontrol_new wm9713_speaker_mixer_controls[] = {
+SOC_DAPM_SINGLE("Beep Playback Switch", AC97_AUX, 11, 1, 1),
+SOC_DAPM_SINGLE("Voice Playback Switch", AC97_PCM, 11, 1, 1),
+SOC_DAPM_SINGLE("Aux Playback Switch", AC97_REC_SEL, 11, 1, 1),
+SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PHONE, 14, 1, 1),
+SOC_DAPM_SINGLE("MonoIn Playback Switch", AC97_MASTER_TONE, 14, 1, 1),
+SOC_DAPM_SINGLE("Bypass Playback Switch", AC97_PC_BEEP, 14, 1, 1),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new wm9713_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("Beep Playback Switch", AC97_AUX, 7, 1, 1),
+SOC_DAPM_SINGLE("Voice Playback Switch", AC97_PCM, 7, 1, 1),
+SOC_DAPM_SINGLE("Aux Playback Switch", AC97_REC_SEL, 7, 1, 1),
+SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PHONE, 13, 1, 1),
+SOC_DAPM_SINGLE("MonoIn Playback Switch", AC97_MASTER_TONE, 13, 1, 1),
+SOC_DAPM_SINGLE("Bypass Playback Switch", AC97_PC_BEEP, 13, 1, 1),
+SOC_DAPM_SINGLE("Mic 1 Sidetone Switch", AC97_LINE, 7, 1, 1),
+SOC_DAPM_SINGLE("Mic 2 Sidetone Switch", AC97_LINE, 6, 1, 1),
+};
+
+/* mono mic mux */
+static const struct snd_kcontrol_new wm9713_mono_mic_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[2]);
+
+/* mono output mux */
+static const struct snd_kcontrol_new wm9713_mono_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[7]);
+
+/* speaker left output mux */
+static const struct snd_kcontrol_new wm9713_hp_spkl_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[8]);
+
+/* speaker right output mux */
+static const struct snd_kcontrol_new wm9713_hp_spkr_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[9]);
+
+/* headphone left output mux */
+static const struct snd_kcontrol_new wm9713_hpl_out_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[10]);
+
+/* headphone right output mux */
+static const struct snd_kcontrol_new wm9713_hpr_out_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[11]);
+
+/* Out3 mux */
+static const struct snd_kcontrol_new wm9713_out3_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[12]);
+
+/* Out4 mux */
+static const struct snd_kcontrol_new wm9713_out4_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[13]);
+
+/* DAC inv mux 1 */
+static const struct snd_kcontrol_new wm9713_dac_inv1_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[14]);
+
+/* DAC inv mux 2 */
+static const struct snd_kcontrol_new wm9713_dac_inv2_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[15]);
+
+/* Capture source left */
+static const struct snd_kcontrol_new wm9713_rec_srcl_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[3]);
+
+/* Capture source right */
+static const struct snd_kcontrol_new wm9713_rec_srcr_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[4]);
+
+/* mic source */
+static const struct snd_kcontrol_new wm9713_mic_sel_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[18]);
+
+/* mic source B virtual control */
+static const struct snd_kcontrol_new wm9713_micb_sel_mux_controls =
+SOC_DAPM_ENUM("Route", wm9713_enum[19]);
+
+static const struct snd_soc_dapm_widget wm9713_dapm_widgets[] = {
+SND_SOC_DAPM_MUX("Capture Headphone Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_hp_rec_mux_controls),
+SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_hp_mic_mux_controls),
+SND_SOC_DAPM_MUX("Capture Mono Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_mono_mic_mux_controls),
+SND_SOC_DAPM_MUX("Mono Out Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_mono_mux_controls),
+SND_SOC_DAPM_MUX("Left Speaker Out Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_hp_spkl_mux_controls),
+SND_SOC_DAPM_MUX("Right Speaker Out Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_hp_spkr_mux_controls),
+SND_SOC_DAPM_MUX("Left Headphone Out Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_hpl_out_mux_controls),
+SND_SOC_DAPM_MUX("Right Headphone Out Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_hpr_out_mux_controls),
+SND_SOC_DAPM_MUX("Out 3 Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_out3_mux_controls),
+SND_SOC_DAPM_MUX("Out 4 Mux", SND_SOC_NOPM, 0, 0,
+	&wm9713_out4_mux_controls),
+SND_SOC_DAPM_MUX("DAC Inv Mux 1", SND_SOC_NOPM, 0, 0,
+	&wm9713_dac_inv1_mux_controls),
+SND_SOC_DAPM_MUX("DAC Inv Mux 2", SND_SOC_NOPM, 0, 0,
+	&wm9713_dac_inv2_mux_controls),
+SND_SOC_DAPM_MUX("Left Capture Source", SND_SOC_NOPM, 0, 0,
+	&wm9713_rec_srcl_mux_controls),
+SND_SOC_DAPM_MUX("Right Capture Source", SND_SOC_NOPM, 0, 0,
+	&wm9713_rec_srcr_mux_controls),
+SND_SOC_DAPM_MUX("Mic A Source", SND_SOC_NOPM, 0, 0,
+	&wm9713_mic_sel_mux_controls),
+SND_SOC_DAPM_MUX("Mic B Source", SND_SOC_NOPM, 0, 0,
+	&wm9713_micb_sel_mux_controls),
+SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_EXTENDED_MID, 3, 1,
+	&wm9713_hpl_mixer_controls[0], ARRAY_SIZE(wm9713_hpl_mixer_controls)),
+SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_EXTENDED_MID, 2, 1,
+	&wm9713_hpr_mixer_controls[0], ARRAY_SIZE(wm9713_hpr_mixer_controls)),
+SND_SOC_DAPM_MIXER("Mono Mixer", AC97_EXTENDED_MID, 0, 1,
+	&wm9713_mono_mixer_controls[0], ARRAY_SIZE(wm9713_mono_mixer_controls)),
+SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_EXTENDED_MID, 1, 1,
+	&wm9713_speaker_mixer_controls[0],
+	ARRAY_SIZE(wm9713_speaker_mixer_controls)),
+SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", AC97_EXTENDED_MID, 7, 1),
+SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", AC97_EXTENDED_MID, 6, 1),
+SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("HP Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Capture Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_DAC_E("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1,
+		   wm9713_voice_shutdown, SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", AC97_EXTENDED_MID, 11, 1),
+SND_SOC_DAPM_PGA("Left ADC", AC97_EXTENDED_MID, 5, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Right ADC", AC97_EXTENDED_MID, 4, 1, NULL, 0),
+SND_SOC_DAPM_ADC("Left HiFi ADC", "Left HiFi Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_ADC("Right HiFi ADC", "Right HiFi Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_ADC("Left Voice ADC", "Left Voice Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_ADC("Right Voice ADC", "Right Voice Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_PGA("Left Headphone", AC97_EXTENDED_MSTATUS, 10, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Right Headphone", AC97_EXTENDED_MSTATUS, 9, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Left Speaker", AC97_EXTENDED_MSTATUS, 8, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Right Speaker", AC97_EXTENDED_MSTATUS, 7, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Out 3", AC97_EXTENDED_MSTATUS, 11, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Out 4", AC97_EXTENDED_MSTATUS, 12, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mono Out", AC97_EXTENDED_MSTATUS, 13, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Left Line In", AC97_EXTENDED_MSTATUS, 6, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Right Line In", AC97_EXTENDED_MSTATUS, 5, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mono In", AC97_EXTENDED_MSTATUS, 4, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mic A PGA", AC97_EXTENDED_MSTATUS, 3, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mic B PGA", AC97_EXTENDED_MSTATUS, 2, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mic A Pre Amp", AC97_EXTENDED_MSTATUS, 1, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Mic B Pre Amp", AC97_EXTENDED_MSTATUS, 0, 1, NULL, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias", AC97_EXTENDED_MSTATUS, 14, 1),
+SND_SOC_DAPM_OUTPUT("MONO"),
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("HPR"),
+SND_SOC_DAPM_OUTPUT("SPKL"),
+SND_SOC_DAPM_OUTPUT("SPKR"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+SND_SOC_DAPM_OUTPUT("OUT4"),
+SND_SOC_DAPM_INPUT("LINEL"),
+SND_SOC_DAPM_INPUT("LINER"),
+SND_SOC_DAPM_INPUT("MONOIN"),
+SND_SOC_DAPM_INPUT("PCBEEP"),
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2A"),
+SND_SOC_DAPM_INPUT("MIC2B"),
+SND_SOC_DAPM_VMID("VMID"),
+};
+
+static const struct snd_soc_dapm_route wm9713_audio_map[] = {
+	/* left HP mixer */
+	{"Left HP Mixer", "Beep Playback Switch",    "PCBEEP"},
+	{"Left HP Mixer", "Voice Playback Switch",   "Voice DAC"},
+	{"Left HP Mixer", "Aux Playback Switch",     "Aux DAC"},
+	{"Left HP Mixer", "Bypass Playback Switch",  "Left Line In"},
+	{"Left HP Mixer", "PCM Playback Switch",     "Left DAC"},
+	{"Left HP Mixer", "MonoIn Playback Switch",  "Mono In"},
+	{"Left HP Mixer", NULL,  "Capture Headphone Mux"},
+
+	/* right HP mixer */
+	{"Right HP Mixer", "Beep Playback Switch",    "PCBEEP"},
+	{"Right HP Mixer", "Voice Playback Switch",   "Voice DAC"},
+	{"Right HP Mixer", "Aux Playback Switch",     "Aux DAC"},
+	{"Right HP Mixer", "Bypass Playback Switch",  "Right Line In"},
+	{"Right HP Mixer", "PCM Playback Switch",     "Right DAC"},
+	{"Right HP Mixer", "MonoIn Playback Switch",  "Mono In"},
+	{"Right HP Mixer", NULL,  "Capture Headphone Mux"},
+
+	/* virtual mixer - mixes left & right channels for spk and mono */
+	{"AC97 Mixer", NULL, "Left DAC"},
+	{"AC97 Mixer", NULL, "Right DAC"},
+	{"Line Mixer", NULL, "Right Line In"},
+	{"Line Mixer", NULL, "Left Line In"},
+	{"HP Mixer", NULL, "Left HP Mixer"},
+	{"HP Mixer", NULL, "Right HP Mixer"},
+	{"Capture Mixer", NULL, "Left Capture Source"},
+	{"Capture Mixer", NULL, "Right Capture Source"},
+
+	/* speaker mixer */
+	{"Speaker Mixer", "Beep Playback Switch",    "PCBEEP"},
+	{"Speaker Mixer", "Voice Playback Switch",   "Voice DAC"},
+	{"Speaker Mixer", "Aux Playback Switch",     "Aux DAC"},
+	{"Speaker Mixer", "Bypass Playback Switch",  "Line Mixer"},
+	{"Speaker Mixer", "PCM Playback Switch",     "AC97 Mixer"},
+	{"Speaker Mixer", "MonoIn Playback Switch",  "Mono In"},
+
+	/* mono mixer */
+	{"Mono Mixer", "Beep Playback Switch",    "PCBEEP"},
+	{"Mono Mixer", "Voice Playback Switch",   "Voice DAC"},
+	{"Mono Mixer", "Aux Playback Switch",     "Aux DAC"},
+	{"Mono Mixer", "Bypass Playback Switch",  "Line Mixer"},
+	{"Mono Mixer", "PCM Playback Switch",     "AC97 Mixer"},
+	{"Mono Mixer", "Mic 1 Sidetone Switch", "Mic A PGA"},
+	{"Mono Mixer", "Mic 2 Sidetone Switch", "Mic B PGA"},
+	{"Mono Mixer", NULL,  "Capture Mono Mux"},
+
+	/* DAC inv mux 1 */
+	{"DAC Inv Mux 1", "Mono", "Mono Mixer"},
+	{"DAC Inv Mux 1", "Speaker", "Speaker Mixer"},
+	{"DAC Inv Mux 1", "Left Headphone", "Left HP Mixer"},
+	{"DAC Inv Mux 1", "Right Headphone", "Right HP Mixer"},
+	{"DAC Inv Mux 1", "Headphone Mono", "HP Mixer"},
+
+	/* DAC inv mux 2 */
+	{"DAC Inv Mux 2", "Mono", "Mono Mixer"},
+	{"DAC Inv Mux 2", "Speaker", "Speaker Mixer"},
+	{"DAC Inv Mux 2", "Left Headphone", "Left HP Mixer"},
+	{"DAC Inv Mux 2", "Right Headphone", "Right HP Mixer"},
+	{"DAC Inv Mux 2", "Headphone Mono", "HP Mixer"},
+
+	/* headphone left mux */
+	{"Left Headphone Out Mux", "Headphone", "Left HP Mixer"},
+
+	/* headphone right mux */
+	{"Right Headphone Out Mux", "Headphone", "Right HP Mixer"},
+
+	/* speaker left mux */
+	{"Left Speaker Out Mux", "Headphone", "Left HP Mixer"},
+	{"Left Speaker Out Mux", "Speaker", "Speaker Mixer"},
+	{"Left Speaker Out Mux", "Inv", "DAC Inv Mux 1"},
+
+	/* speaker right mux */
+	{"Right Speaker Out Mux", "Headphone", "Right HP Mixer"},
+	{"Right Speaker Out Mux", "Speaker", "Speaker Mixer"},
+	{"Right Speaker Out Mux", "Inv", "DAC Inv Mux 2"},
+
+	/* mono mux */
+	{"Mono Out Mux", "Mono", "Mono Mixer"},
+	{"Mono Out Mux", "Inv", "DAC Inv Mux 1"},
+
+	/* out 3 mux */
+	{"Out 3 Mux", "Inv 1", "DAC Inv Mux 1"},
+
+	/* out 4 mux */
+	{"Out 4 Mux", "Inv 2", "DAC Inv Mux 2"},
+
+	/* output pga */
+	{"HPL", NULL, "Left Headphone"},
+	{"Left Headphone", NULL, "Left Headphone Out Mux"},
+	{"HPR", NULL, "Right Headphone"},
+	{"Right Headphone", NULL, "Right Headphone Out Mux"},
+	{"OUT3", NULL, "Out 3"},
+	{"Out 3", NULL, "Out 3 Mux"},
+	{"OUT4", NULL, "Out 4"},
+	{"Out 4", NULL, "Out 4 Mux"},
+	{"SPKL", NULL, "Left Speaker"},
+	{"Left Speaker", NULL, "Left Speaker Out Mux"},
+	{"SPKR", NULL, "Right Speaker"},
+	{"Right Speaker", NULL, "Right Speaker Out Mux"},
+	{"MONO", NULL, "Mono Out"},
+	{"Mono Out", NULL, "Mono Out Mux"},
+
+	/* input pga */
+	{"Left Line In", NULL, "LINEL"},
+	{"Right Line In", NULL, "LINER"},
+	{"Mono In", NULL, "MONOIN"},
+	{"Mic A PGA", NULL, "Mic A Pre Amp"},
+	{"Mic B PGA", NULL, "Mic B Pre Amp"},
+
+	/* left capture select */
+	{"Left Capture Source", "Mic 1", "Mic A Pre Amp"},
+	{"Left Capture Source", "Mic 2", "Mic B Pre Amp"},
+	{"Left Capture Source", "Line", "LINEL"},
+	{"Left Capture Source", "Mono In", "MONOIN"},
+	{"Left Capture Source", "Headphone", "Left HP Mixer"},
+	{"Left Capture Source", "Speaker", "Speaker Mixer"},
+	{"Left Capture Source", "Mono Out", "Mono Mixer"},
+
+	/* right capture select */
+	{"Right Capture Source", "Mic 1", "Mic A Pre Amp"},
+	{"Right Capture Source", "Mic 2", "Mic B Pre Amp"},
+	{"Right Capture Source", "Line", "LINER"},
+	{"Right Capture Source", "Mono In", "MONOIN"},
+	{"Right Capture Source", "Headphone", "Right HP Mixer"},
+	{"Right Capture Source", "Speaker", "Speaker Mixer"},
+	{"Right Capture Source", "Mono Out", "Mono Mixer"},
+
+	/* left ADC */
+	{"Left ADC", NULL, "Left Capture Source"},
+	{"Left Voice ADC", NULL, "Left ADC"},
+	{"Left HiFi ADC", NULL, "Left ADC"},
+
+	/* right ADC */
+	{"Right ADC", NULL, "Right Capture Source"},
+	{"Right Voice ADC", NULL, "Right ADC"},
+	{"Right HiFi ADC", NULL, "Right ADC"},
+
+	/* mic */
+	{"Mic A Pre Amp", NULL, "Mic A Source"},
+	{"Mic A Source", "Mic 1", "MIC1"},
+	{"Mic A Source", "Mic 2 A", "MIC2A"},
+	{"Mic A Source", "Mic 2 B", "Mic B Source"},
+	{"Mic B Pre Amp", "MPB", "Mic B Source"},
+	{"Mic B Source", NULL, "MIC2B"},
+
+	/* headphone capture */
+	{"Capture Headphone Mux", "Stereo", "Capture Mixer"},
+	{"Capture Headphone Mux", "Left", "Left Capture Source"},
+	{"Capture Headphone Mux", "Right", "Right Capture Source"},
+
+	/* mono capture */
+	{"Capture Mono Mux", "Stereo", "Capture Mixer"},
+	{"Capture Mono Mux", "Left", "Left Capture Source"},
+	{"Capture Mono Mux", "Right", "Right Capture Source"},
+};
+
+static bool wm9713_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AC97_RESET ... AC97_PCM_SURR_DAC_RATE:
+	case AC97_PCM_LR_ADC_RATE:
+	case AC97_CENTER_LFE_MASTER:
+	case AC97_SPDIF ... AC97_LINE1_LEVEL:
+	case AC97_GPIO_CFG ... 0x5c:
+	case AC97_CODEC_CLASS_REV ... AC97_PCI_SID:
+	case 0x74 ... AC97_VENDOR_ID2:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool wm9713_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AC97_VENDOR_ID1:
+	case AC97_VENDOR_ID2:
+		return false;
+	default:
+		return wm9713_readable_reg(dev, reg);
+	}
+}
+
+static const struct reg_default wm9713_reg_defaults[] = {
+	{ 0x02, 0x8080 },	/* Speaker Output Volume */
+	{ 0x04, 0x8080 },	/* Headphone Output Volume */
+	{ 0x06, 0x8080 },	/* Out3/OUT4 Volume */
+	{ 0x08, 0xc880 },	/* Mono Volume */
+	{ 0x0a, 0xe808 },	/* LINEIN Volume */
+	{ 0x0c, 0xe808 },	/* DAC PGA Volume */
+	{ 0x0e, 0x0808 },	/* MIC PGA Volume */
+	{ 0x10, 0x00da },	/* MIC Routing Control */
+	{ 0x12, 0x8000 },	/* Record PGA Volume */
+	{ 0x14, 0xd600 },	/* Record Routing */
+	{ 0x16, 0xaaa0 },	/* PCBEEP Volume */
+	{ 0x18, 0xaaa0 },	/* VxDAC Volume */
+	{ 0x1a, 0xaaa0 },	/* AUXDAC Volume */
+	{ 0x1c, 0x0000 },	/* Output PGA Mux */
+	{ 0x1e, 0x0000 },	/* DAC 3D control */
+	{ 0x20, 0x0f0f },	/* DAC Tone Control*/
+	{ 0x22, 0x0040 },	/* MIC Input Select & Bias */
+	{ 0x24, 0x0000 },	/* Output Volume Mapping & Jack */
+	{ 0x26, 0x7f00 },	/* Powerdown Ctrl/Stat*/
+	{ 0x28, 0x0405 },	/* Extended Audio ID */
+	{ 0x2a, 0x0410 },	/* Extended Audio Start/Ctrl */
+	{ 0x2c, 0xbb80 },	/* Audio DACs Sample Rate */
+	{ 0x2e, 0xbb80 },	/* AUXDAC Sample Rate */
+	{ 0x32, 0xbb80 },	/* Audio ADCs Sample Rate */
+	{ 0x36, 0x4523 },	/* PCM codec control */
+	{ 0x3a, 0x2000 },	/* SPDIF control */
+	{ 0x3c, 0xfdff },	/* Powerdown 1 */
+	{ 0x3e, 0xffff },	/* Powerdown 2 */
+	{ 0x40, 0x0000 },	/* General Purpose */
+	{ 0x42, 0x0000 },	/* Fast Power-Up Control */
+	{ 0x44, 0x0080 },	/* MCLK/PLL Control */
+	{ 0x46, 0x0000 },	/* MCLK/PLL Control */
+	{ 0x4c, 0xfffe },	/* GPIO Pin Configuration */
+	{ 0x4e, 0xffff },	/* GPIO Pin Polarity / Type */
+	{ 0x50, 0x0000 },	/* GPIO Pin Sticky */
+	{ 0x52, 0x0000 },	/* GPIO Pin Wake-Up */
+				/* GPIO Pin Status */
+	{ 0x56, 0xfffe },	/* GPIO Pin Sharing */
+	{ 0x58, 0x4000 },	/* GPIO PullUp/PullDown */
+	{ 0x5a, 0x0000 },	/* Additional Functions 1 */
+	{ 0x5c, 0x0000 },	/* Additional Functions 2 */
+	{ 0x60, 0xb032 },	/* ALC Control */
+	{ 0x62, 0x3e00 },	/* ALC / Noise Gate Control */
+	{ 0x64, 0x0000 },	/* AUXDAC input control */
+	{ 0x74, 0x0000 },	/* Digitiser Reg 1 */
+	{ 0x76, 0x0006 },	/* Digitiser Reg 2 */
+	{ 0x78, 0x0001 },	/* Digitiser Reg 3 */
+	{ 0x7a, 0x0000 },	/* Digitiser Read Back */
+};
+
+static const struct regmap_config wm9713_regmap_config = {
+	.reg_bits = 16,
+	.reg_stride = 2,
+	.val_bits = 16,
+	.max_register = 0x7e,
+	.cache_type = REGCACHE_RBTREE,
+
+	.reg_defaults = wm9713_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults),
+	.volatile_reg = regmap_ac97_default_volatile,
+	.readable_reg = wm9713_readable_reg,
+	.writeable_reg = wm9713_writeable_reg,
+};
+
+/* PLL divisors */
+struct _pll_div {
+	u32 divsel:1;
+	u32 divctl:1;
+	u32 lf:1;
+	u32 n:4;
+	u32 k:24;
+};
+
+/* The size in bits of the PLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 22) * 10)
+
+static void pll_factors(struct snd_soc_component *component,
+	struct _pll_div *pll_div, unsigned int source)
+{
+	u64 Kpart;
+	unsigned int K, Ndiv, Nmod, target;
+
+	/* The the PLL output is always 98.304MHz. */
+	target = 98304000;
+
+	/* If the input frequency is over 14.4MHz then scale it down. */
+	if (source > 14400000) {
+		source >>= 1;
+		pll_div->divsel = 1;
+
+		if (source > 14400000) {
+			source >>= 1;
+			pll_div->divctl = 1;
+		} else
+			pll_div->divctl = 0;
+
+	} else {
+		pll_div->divsel = 0;
+		pll_div->divctl = 0;
+	}
+
+	/* Low frequency sources require an additional divide in the
+	 * loop.
+	 */
+	if (source < 8192000) {
+		pll_div->lf = 1;
+		target >>= 2;
+	} else
+		pll_div->lf = 0;
+
+	Ndiv = target / source;
+	if ((Ndiv < 5) || (Ndiv > 12))
+		dev_warn(component->dev,
+			"WM9713 PLL N value %u out of recommended range!\n",
+			Ndiv);
+
+	pll_div->n = Ndiv;
+	Nmod = target % source;
+	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+	do_div(Kpart, source);
+
+	K = Kpart & 0xFFFFFFFF;
+
+	/* Check if we need to round */
+	if ((K % 10) >= 5)
+		K += 5;
+
+	/* Move down to proper range now rounding is done */
+	K /= 10;
+
+	pll_div->k = K;
+}
+
+/**
+ * Please note that changing the PLL input frequency may require
+ * resynchronisation with the AC97 controller.
+ */
+static int wm9713_set_pll(struct snd_soc_component *component,
+	int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+	struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
+	u16 reg, reg2;
+	struct _pll_div pll_div;
+
+	/* turn PLL off ? */
+	if (freq_in == 0) {
+		/* disable PLL power and select ext source */
+		snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0080, 0x0080);
+		snd_soc_component_update_bits(component, AC97_EXTENDED_MID, 0x0200, 0x0200);
+		wm9713->pll_in = 0;
+		return 0;
+	}
+
+	pll_factors(component, &pll_div, freq_in);
+
+	if (pll_div.k == 0) {
+		reg = (pll_div.n << 12) | (pll_div.lf << 11) |
+			(pll_div.divsel << 9) | (pll_div.divctl << 8);
+		snd_soc_component_write(component, AC97_LINE1_LEVEL, reg);
+	} else {
+		/* write the fractional k to the reg 0x46 pages */
+		reg2 = (pll_div.n << 12) | (pll_div.lf << 11) | (1 << 10) |
+			(pll_div.divsel << 9) | (pll_div.divctl << 8);
+
+		/* K [21:20] */
+		reg = reg2 | (0x5 << 4) | (pll_div.k >> 20);
+		snd_soc_component_write(component, AC97_LINE1_LEVEL, reg);
+
+		/* K [19:16] */
+		reg = reg2 | (0x4 << 4) | ((pll_div.k >> 16) & 0xf);
+		snd_soc_component_write(component, AC97_LINE1_LEVEL, reg);
+
+		/* K [15:12] */
+		reg = reg2 | (0x3 << 4) | ((pll_div.k >> 12) & 0xf);
+		snd_soc_component_write(component, AC97_LINE1_LEVEL, reg);
+
+		/* K [11:8] */
+		reg = reg2 | (0x2 << 4) | ((pll_div.k >> 8) & 0xf);
+		snd_soc_component_write(component, AC97_LINE1_LEVEL, reg);
+
+		/* K [7:4] */
+		reg = reg2 | (0x1 << 4) | ((pll_div.k >> 4) & 0xf);
+		snd_soc_component_write(component, AC97_LINE1_LEVEL, reg);
+
+		reg = reg2 | (0x0 << 4) | (pll_div.k & 0xf); /* K [3:0] */
+		snd_soc_component_write(component, AC97_LINE1_LEVEL, reg);
+	}
+
+	/* turn PLL on and select as source */
+	snd_soc_component_update_bits(component, AC97_EXTENDED_MID, 0x0200, 0x0000);
+	snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0080, 0x0000);
+	wm9713->pll_in = freq_in;
+
+	/* wait 10ms AC97 link frames for the link to stabilise */
+	schedule_timeout_interruptible(msecs_to_jiffies(10));
+	return 0;
+}
+
+static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+		int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	return wm9713_set_pll(component, pll_id, freq_in, freq_out);
+}
+
+/*
+ * Tristate the PCM DAI lines, tristate can be disabled by calling
+ * wm9713_set_dai_fmt()
+ */
+static int wm9713_set_dai_tristate(struct snd_soc_dai *codec_dai,
+	int tristate)
+{
+	struct snd_soc_component *component = codec_dai->component;
+
+	if (tristate)
+		snd_soc_component_update_bits(component, AC97_CENTER_LFE_MASTER,
+				    0x6000, 0x0000);
+
+	return 0;
+}
+
+/*
+ * Configure WM9713 clock dividers.
+ * Voice DAC needs 256 FS
+ */
+static int wm9713_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+		int div_id, int div)
+{
+	struct snd_soc_component *component = codec_dai->component;
+
+	switch (div_id) {
+	case WM9713_PCMCLK_DIV:
+		snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0f00, div);
+		break;
+	case WM9713_CLKA_MULT:
+		snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0002, div);
+		break;
+	case WM9713_CLKB_MULT:
+		snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x0004, div);
+		break;
+	case WM9713_HIFI_DIV:
+		snd_soc_component_update_bits(component, AC97_HANDSET_RATE, 0x7000, div);
+		break;
+	case WM9713_PCMBCLK_DIV:
+		snd_soc_component_update_bits(component, AC97_CENTER_LFE_MASTER, 0x0e00, div);
+		break;
+	case WM9713_PCMCLK_PLL_DIV:
+		snd_soc_component_update_bits(component, AC97_LINE1_LEVEL,
+				    0x007f, div | 0x60);
+		break;
+	case WM9713_HIFI_PLL_DIV:
+		snd_soc_component_update_bits(component, AC97_LINE1_LEVEL,
+				    0x007f, div | 0x70);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_component *component = codec_dai->component;
+	u16 gpio = snd_soc_component_read32(component, AC97_GPIO_CFG) & 0xffc5;
+	u16 reg = 0x8000;
+
+	/* clock masters */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		reg |= 0x4000;
+		gpio |= 0x0010;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		reg |= 0x6000;
+		gpio |= 0x0018;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg |= 0x2000;
+		gpio |= 0x001a;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		gpio |= 0x0012;
+		break;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_IF:
+		reg |= 0x00c0;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg |= 0x0080;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		reg |= 0x0040;
+		break;
+	}
+
+	/* DAI format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		reg |= 0x0002;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg |= 0x0001;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg |= 0x0003;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg |= 0x0043;
+		break;
+	}
+
+	snd_soc_component_write(component, AC97_GPIO_CFG, gpio);
+	snd_soc_component_write(component, AC97_CENTER_LFE_MASTER, reg);
+	return 0;
+}
+
+static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+
+	/* enable PCM interface in master mode */
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		snd_soc_component_update_bits(component, AC97_CENTER_LFE_MASTER,
+				    0x000c, 0x0004);
+		break;
+	case 24:
+		snd_soc_component_update_bits(component, AC97_CENTER_LFE_MASTER,
+				    0x000c, 0x0008);
+		break;
+	case 32:
+		snd_soc_component_update_bits(component, AC97_CENTER_LFE_MASTER,
+				    0x000c, 0x000c);
+		break;
+	}
+	return 0;
+}
+
+static int ac97_hifi_prepare(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int reg;
+
+	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x0001, 0x0001);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		reg = AC97_PCM_FRONT_DAC_RATE;
+	else
+		reg = AC97_PCM_LR_ADC_RATE;
+
+	return snd_soc_component_write(component, reg, runtime->rate);
+}
+
+static int ac97_aux_prepare(struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	snd_soc_component_update_bits(component, AC97_EXTENDED_STATUS, 0x0001, 0x0001);
+	snd_soc_component_update_bits(component, AC97_PCI_SID, 0x8000, 0x8000);
+
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+		return -ENODEV;
+
+	return snd_soc_component_write(component, AC97_PCM_SURR_DAC_RATE, runtime->rate);
+}
+
+#define WM9713_RATES (SNDRV_PCM_RATE_8000  |	\
+		      SNDRV_PCM_RATE_11025 |	\
+		      SNDRV_PCM_RATE_22050 |	\
+		      SNDRV_PCM_RATE_44100 |	\
+		      SNDRV_PCM_RATE_48000)
+
+#define WM9713_PCM_RATES (SNDRV_PCM_RATE_8000  |	\
+			  SNDRV_PCM_RATE_11025 |	\
+			  SNDRV_PCM_RATE_16000 |	\
+			  SNDRV_PCM_RATE_22050 |	\
+			  SNDRV_PCM_RATE_44100 |	\
+			  SNDRV_PCM_RATE_48000)
+
+#define WM9713_PCM_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	 SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops wm9713_dai_ops_hifi = {
+	.prepare	= ac97_hifi_prepare,
+	.set_clkdiv	= wm9713_set_dai_clkdiv,
+	.set_pll	= wm9713_set_dai_pll,
+};
+
+static const struct snd_soc_dai_ops wm9713_dai_ops_aux = {
+	.prepare	= ac97_aux_prepare,
+	.set_clkdiv	= wm9713_set_dai_clkdiv,
+	.set_pll	= wm9713_set_dai_pll,
+};
+
+static const struct snd_soc_dai_ops wm9713_dai_ops_voice = {
+	.hw_params	= wm9713_pcm_hw_params,
+	.set_clkdiv	= wm9713_set_dai_clkdiv,
+	.set_pll	= wm9713_set_dai_pll,
+	.set_fmt	= wm9713_set_dai_fmt,
+	.set_tristate	= wm9713_set_dai_tristate,
+};
+
+static struct snd_soc_dai_driver wm9713_dai[] = {
+{
+	.name = "wm9713-hifi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM9713_RATES,
+		.formats = SND_SOC_STD_AC97_FMTS,},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM9713_RATES,
+		.formats = SND_SOC_STD_AC97_FMTS,},
+	.ops = &wm9713_dai_ops_hifi,
+	},
+	{
+	.name = "wm9713-aux",
+	.playback = {
+		.stream_name = "Aux Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = WM9713_RATES,
+		.formats = SND_SOC_STD_AC97_FMTS,},
+	.ops = &wm9713_dai_ops_aux,
+	},
+	{
+	.name = "wm9713-voice",
+	.playback = {
+		.stream_name = "Voice Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = WM9713_PCM_RATES,
+		.formats = WM9713_PCM_FORMATS,},
+	.capture = {
+		.stream_name = "Voice Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = WM9713_PCM_RATES,
+		.formats = WM9713_PCM_FORMATS,},
+	.ops = &wm9713_dai_ops_voice,
+	.symmetric_rates = 1,
+	},
+};
+
+static int wm9713_set_bias_level(struct snd_soc_component *component,
+				 enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* enable thermal shutdown */
+		snd_soc_component_update_bits(component, AC97_EXTENDED_MID, 0xe400, 0x0000);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* enable master bias and vmid */
+		snd_soc_component_update_bits(component, AC97_EXTENDED_MID, 0xc400, 0x0000);
+		snd_soc_component_write(component, AC97_POWERDOWN, 0x0000);
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* disable everything including AC link */
+		snd_soc_component_write(component, AC97_EXTENDED_MID, 0xffff);
+		snd_soc_component_write(component, AC97_EXTENDED_MSTATUS, 0xffff);
+		snd_soc_component_write(component, AC97_POWERDOWN, 0xffff);
+		break;
+	}
+	return 0;
+}
+
+static int wm9713_soc_suspend(struct snd_soc_component *component)
+{
+	/* Disable everything except touchpanel - that will be handled
+	 * by the touch driver and left disabled if touch is not in
+	 * use. */
+	snd_soc_component_update_bits(component, AC97_EXTENDED_MID, 0x7fff,
+				 0x7fff);
+	snd_soc_component_write(component, AC97_EXTENDED_MSTATUS, 0xffff);
+	snd_soc_component_write(component, AC97_POWERDOWN, 0x6f00);
+	snd_soc_component_write(component, AC97_POWERDOWN, 0xffff);
+
+	return 0;
+}
+
+static int wm9713_soc_resume(struct snd_soc_component *component)
+{
+	struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = snd_ac97_reset(wm9713->ac97, true, WM9713_VENDOR_ID,
+		WM9713_VENDOR_ID_MASK);
+	if (ret < 0)
+		return ret;
+
+	snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
+
+	/* do we need to re-start the PLL ? */
+	if (wm9713->pll_in)
+		wm9713_set_pll(component, 0, wm9713->pll_in, 0);
+
+	/* only synchronise the codec if warm reset failed */
+	if (ret == 0) {
+		regcache_mark_dirty(component->regmap);
+		snd_soc_component_cache_sync(component);
+	}
+
+	return ret;
+}
+
+static int wm9713_soc_probe(struct snd_soc_component *component)
+{
+	struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = NULL;
+
+	if (wm9713->mfd_pdata) {
+		wm9713->ac97 = wm9713->mfd_pdata->ac97;
+		regmap = wm9713->mfd_pdata->regmap;
+	} else {
+#ifdef CONFIG_SND_SOC_AC97_BUS
+		wm9713->ac97 = snd_soc_new_ac97_component(component, WM9713_VENDOR_ID,
+						      WM9713_VENDOR_ID_MASK);
+		if (IS_ERR(wm9713->ac97))
+			return PTR_ERR(wm9713->ac97);
+		regmap = regmap_init_ac97(wm9713->ac97, &wm9713_regmap_config);
+		if (IS_ERR(regmap)) {
+			snd_soc_free_ac97_component(wm9713->ac97);
+			return PTR_ERR(regmap);
+		}
+#endif
+	}
+
+	snd_soc_component_init_regmap(component, regmap);
+
+	/* unmute the adc - move to kcontrol */
+	snd_soc_component_update_bits(component, AC97_CD, 0x7fff, 0x0000);
+
+	return 0;
+}
+
+static void wm9713_soc_remove(struct snd_soc_component *component)
+{
+#ifdef CONFIG_SND_SOC_AC97_BUS
+	struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
+
+	if (!wm9713->mfd_pdata) {
+		snd_soc_component_exit_regmap(component);
+		snd_soc_free_ac97_component(wm9713->ac97);
+	}
+#endif
+}
+
+static const struct snd_soc_component_driver soc_component_dev_wm9713 = {
+	.probe			= wm9713_soc_probe,
+	.remove			= wm9713_soc_remove,
+	.suspend		= wm9713_soc_suspend,
+	.resume			= wm9713_soc_resume,
+	.set_bias_level		= wm9713_set_bias_level,
+	.controls		= wm9713_snd_ac97_controls,
+	.num_controls		= ARRAY_SIZE(wm9713_snd_ac97_controls),
+	.dapm_widgets		= wm9713_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(wm9713_dapm_widgets),
+	.dapm_routes		= wm9713_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(wm9713_audio_map),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int wm9713_probe(struct platform_device *pdev)
+{
+	struct wm9713_priv *wm9713;
+
+	wm9713 = devm_kzalloc(&pdev->dev, sizeof(*wm9713), GFP_KERNEL);
+	if (wm9713 == NULL)
+		return -ENOMEM;
+
+	mutex_init(&wm9713->lock);
+
+	wm9713->mfd_pdata = dev_get_platdata(&pdev->dev);
+	platform_set_drvdata(pdev, wm9713);
+
+	return devm_snd_soc_register_component(&pdev->dev,
+			&soc_component_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai));
+}
+
+static struct platform_driver wm9713_codec_driver = {
+	.driver = {
+			.name = "wm9713-codec",
+	},
+
+	.probe = wm9713_probe,
+};
+
+module_platform_driver(wm9713_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM9713/WM9714 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm9713.h b/sound/soc/codecs/wm9713.h
new file mode 100644
index 0000000..f0800dc
--- /dev/null
+++ b/sound/soc/codecs/wm9713.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * wm9713.h  --  WM9713 Soc Audio driver
+ */
+
+#ifndef _WM9713_H
+#define _WM9713_H
+
+/* clock inputs */
+#define WM9713_CLKA_PIN			0
+#define WM9713_CLKB_PIN			1
+
+/* clock divider ID's */
+#define WM9713_PCMCLK_DIV		0
+#define WM9713_CLKA_MULT		1
+#define WM9713_CLKB_MULT		2
+#define WM9713_HIFI_DIV			3
+#define WM9713_PCMBCLK_DIV		4
+#define WM9713_PCMCLK_PLL_DIV           5
+#define WM9713_HIFI_PLL_DIV             6
+
+/* Calculate the appropriate bit mask for the external PCM clock divider */
+#define WM9713_PCMDIV(x)	((x - 1) << 8)
+
+/* Calculate the appropriate bit mask for the external HiFi clock divider */
+#define WM9713_HIFIDIV(x)	((x - 1) << 12)
+
+/* MCLK clock mulitipliers */
+#define WM9713_CLKA_X1		(0 << 1)
+#define WM9713_CLKA_X2		(1 << 1)
+#define WM9713_CLKB_X1		(0 << 2)
+#define WM9713_CLKB_X2		(1 << 2)
+
+/* MCLK clock MUX */
+#define WM9713_CLK_MUX_A		(0 << 0)
+#define WM9713_CLK_MUX_B		(1 << 0)
+
+/* Voice DAI BCLK divider */
+#define WM9713_PCMBCLK_DIV_1	(0 << 9)
+#define WM9713_PCMBCLK_DIV_2	(1 << 9)
+#define WM9713_PCMBCLK_DIV_4	(2 << 9)
+#define WM9713_PCMBCLK_DIV_8	(3 << 9)
+#define WM9713_PCMBCLK_DIV_16	(4 << 9)
+
+#endif
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
new file mode 100644
index 0000000..4d3ec29
--- /dev/null
+++ b/sound/soc/codecs/wm_adsp.c
@@ -0,0 +1,3875 @@
+/*
+ * wm_adsp.c  --  Wolfson ADSP support
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/list.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include <linux/debugfs.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm_adsp.h"
+
+#define adsp_crit(_dsp, fmt, ...) \
+	dev_crit(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
+#define adsp_err(_dsp, fmt, ...) \
+	dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
+#define adsp_warn(_dsp, fmt, ...) \
+	dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
+#define adsp_info(_dsp, fmt, ...) \
+	dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
+#define adsp_dbg(_dsp, fmt, ...) \
+	dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
+
+#define ADSP1_CONTROL_1                   0x00
+#define ADSP1_CONTROL_2                   0x02
+#define ADSP1_CONTROL_3                   0x03
+#define ADSP1_CONTROL_4                   0x04
+#define ADSP1_CONTROL_5                   0x06
+#define ADSP1_CONTROL_6                   0x07
+#define ADSP1_CONTROL_7                   0x08
+#define ADSP1_CONTROL_8                   0x09
+#define ADSP1_CONTROL_9                   0x0A
+#define ADSP1_CONTROL_10                  0x0B
+#define ADSP1_CONTROL_11                  0x0C
+#define ADSP1_CONTROL_12                  0x0D
+#define ADSP1_CONTROL_13                  0x0F
+#define ADSP1_CONTROL_14                  0x10
+#define ADSP1_CONTROL_15                  0x11
+#define ADSP1_CONTROL_16                  0x12
+#define ADSP1_CONTROL_17                  0x13
+#define ADSP1_CONTROL_18                  0x14
+#define ADSP1_CONTROL_19                  0x16
+#define ADSP1_CONTROL_20                  0x17
+#define ADSP1_CONTROL_21                  0x18
+#define ADSP1_CONTROL_22                  0x1A
+#define ADSP1_CONTROL_23                  0x1B
+#define ADSP1_CONTROL_24                  0x1C
+#define ADSP1_CONTROL_25                  0x1E
+#define ADSP1_CONTROL_26                  0x20
+#define ADSP1_CONTROL_27                  0x21
+#define ADSP1_CONTROL_28                  0x22
+#define ADSP1_CONTROL_29                  0x23
+#define ADSP1_CONTROL_30                  0x24
+#define ADSP1_CONTROL_31                  0x26
+
+/*
+ * ADSP1 Control 19
+ */
+#define ADSP1_WDMA_BUFFER_LENGTH_MASK     0x00FF  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+#define ADSP1_WDMA_BUFFER_LENGTH_SHIFT         0  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+#define ADSP1_WDMA_BUFFER_LENGTH_WIDTH         8  /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
+
+
+/*
+ * ADSP1 Control 30
+ */
+#define ADSP1_DBG_CLK_ENA                 0x0008  /* DSP1_DBG_CLK_ENA */
+#define ADSP1_DBG_CLK_ENA_MASK            0x0008  /* DSP1_DBG_CLK_ENA */
+#define ADSP1_DBG_CLK_ENA_SHIFT                3  /* DSP1_DBG_CLK_ENA */
+#define ADSP1_DBG_CLK_ENA_WIDTH                1  /* DSP1_DBG_CLK_ENA */
+#define ADSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
+#define ADSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
+#define ADSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
+#define ADSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
+#define ADSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
+#define ADSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
+#define ADSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
+#define ADSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
+#define ADSP1_START                       0x0001  /* DSP1_START */
+#define ADSP1_START_MASK                  0x0001  /* DSP1_START */
+#define ADSP1_START_SHIFT                      0  /* DSP1_START */
+#define ADSP1_START_WIDTH                      1  /* DSP1_START */
+
+/*
+ * ADSP1 Control 31
+ */
+#define ADSP1_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
+#define ADSP1_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
+#define ADSP1_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
+
+#define ADSP2_CONTROL                     0x0
+#define ADSP2_CLOCKING                    0x1
+#define ADSP2V2_CLOCKING                  0x2
+#define ADSP2_STATUS1                     0x4
+#define ADSP2_WDMA_CONFIG_1               0x30
+#define ADSP2_WDMA_CONFIG_2               0x31
+#define ADSP2V2_WDMA_CONFIG_2             0x32
+#define ADSP2_RDMA_CONFIG_1               0x34
+
+#define ADSP2_SCRATCH0                    0x40
+#define ADSP2_SCRATCH1                    0x41
+#define ADSP2_SCRATCH2                    0x42
+#define ADSP2_SCRATCH3                    0x43
+
+#define ADSP2V2_SCRATCH0_1                0x40
+#define ADSP2V2_SCRATCH2_3                0x42
+
+/*
+ * ADSP2 Control
+ */
+
+#define ADSP2_MEM_ENA                     0x0010  /* DSP1_MEM_ENA */
+#define ADSP2_MEM_ENA_MASK                0x0010  /* DSP1_MEM_ENA */
+#define ADSP2_MEM_ENA_SHIFT                    4  /* DSP1_MEM_ENA */
+#define ADSP2_MEM_ENA_WIDTH                    1  /* DSP1_MEM_ENA */
+#define ADSP2_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
+#define ADSP2_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
+#define ADSP2_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
+#define ADSP2_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
+#define ADSP2_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
+#define ADSP2_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
+#define ADSP2_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
+#define ADSP2_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
+#define ADSP2_START                       0x0001  /* DSP1_START */
+#define ADSP2_START_MASK                  0x0001  /* DSP1_START */
+#define ADSP2_START_SHIFT                      0  /* DSP1_START */
+#define ADSP2_START_WIDTH                      1  /* DSP1_START */
+
+/*
+ * ADSP2 clocking
+ */
+#define ADSP2_CLK_SEL_MASK                0x0007  /* CLK_SEL_ENA */
+#define ADSP2_CLK_SEL_SHIFT                    0  /* CLK_SEL_ENA */
+#define ADSP2_CLK_SEL_WIDTH                    3  /* CLK_SEL_ENA */
+
+/*
+ * ADSP2V2 clocking
+ */
+#define ADSP2V2_CLK_SEL_MASK             0x70000  /* CLK_SEL_ENA */
+#define ADSP2V2_CLK_SEL_SHIFT                 16  /* CLK_SEL_ENA */
+#define ADSP2V2_CLK_SEL_WIDTH                  3  /* CLK_SEL_ENA */
+
+#define ADSP2V2_RATE_MASK                 0x7800  /* DSP_RATE */
+#define ADSP2V2_RATE_SHIFT                    11  /* DSP_RATE */
+#define ADSP2V2_RATE_WIDTH                     4  /* DSP_RATE */
+
+/*
+ * ADSP2 Status 1
+ */
+#define ADSP2_RAM_RDY                     0x0001
+#define ADSP2_RAM_RDY_MASK                0x0001
+#define ADSP2_RAM_RDY_SHIFT                    0
+#define ADSP2_RAM_RDY_WIDTH                    1
+
+/*
+ * ADSP2 Lock support
+ */
+#define ADSP2_LOCK_CODE_0                    0x5555
+#define ADSP2_LOCK_CODE_1                    0xAAAA
+
+#define ADSP2_WATCHDOG                       0x0A
+#define ADSP2_BUS_ERR_ADDR                   0x52
+#define ADSP2_REGION_LOCK_STATUS             0x64
+#define ADSP2_LOCK_REGION_1_LOCK_REGION_0    0x66
+#define ADSP2_LOCK_REGION_3_LOCK_REGION_2    0x68
+#define ADSP2_LOCK_REGION_5_LOCK_REGION_4    0x6A
+#define ADSP2_LOCK_REGION_7_LOCK_REGION_6    0x6C
+#define ADSP2_LOCK_REGION_9_LOCK_REGION_8    0x6E
+#define ADSP2_LOCK_REGION_CTRL               0x7A
+#define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR    0x7C
+
+#define ADSP2_REGION_LOCK_ERR_MASK           0x8000
+#define ADSP2_SLAVE_ERR_MASK                 0x4000
+#define ADSP2_WDT_TIMEOUT_STS_MASK           0x2000
+#define ADSP2_CTRL_ERR_PAUSE_ENA             0x0002
+#define ADSP2_CTRL_ERR_EINT                  0x0001
+
+#define ADSP2_BUS_ERR_ADDR_MASK              0x00FFFFFF
+#define ADSP2_XMEM_ERR_ADDR_MASK             0x0000FFFF
+#define ADSP2_PMEM_ERR_ADDR_MASK             0x7FFF0000
+#define ADSP2_PMEM_ERR_ADDR_SHIFT            16
+#define ADSP2_WDT_ENA_MASK                   0xFFFFFFFD
+
+#define ADSP2_LOCK_REGION_SHIFT              16
+
+#define ADSP_MAX_STD_CTRL_SIZE               512
+
+#define WM_ADSP_ACKED_CTL_TIMEOUT_MS         100
+#define WM_ADSP_ACKED_CTL_N_QUICKPOLLS       10
+#define WM_ADSP_ACKED_CTL_MIN_VALUE          0
+#define WM_ADSP_ACKED_CTL_MAX_VALUE          0xFFFFFF
+
+/*
+ * Event control messages
+ */
+#define WM_ADSP_FW_EVENT_SHUTDOWN            0x000001
+
+struct wm_adsp_buf {
+	struct list_head list;
+	void *buf;
+};
+
+static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
+					     struct list_head *list)
+{
+	struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+
+	if (buf == NULL)
+		return NULL;
+
+	buf->buf = vmalloc(len);
+	if (!buf->buf) {
+		kfree(buf);
+		return NULL;
+	}
+	memcpy(buf->buf, src, len);
+
+	if (list)
+		list_add_tail(&buf->list, list);
+
+	return buf;
+}
+
+static void wm_adsp_buf_free(struct list_head *list)
+{
+	while (!list_empty(list)) {
+		struct wm_adsp_buf *buf = list_first_entry(list,
+							   struct wm_adsp_buf,
+							   list);
+		list_del(&buf->list);
+		vfree(buf->buf);
+		kfree(buf);
+	}
+}
+
+#define WM_ADSP_FW_MBC_VSS  0
+#define WM_ADSP_FW_HIFI     1
+#define WM_ADSP_FW_TX       2
+#define WM_ADSP_FW_TX_SPK   3
+#define WM_ADSP_FW_RX       4
+#define WM_ADSP_FW_RX_ANC   5
+#define WM_ADSP_FW_CTRL     6
+#define WM_ADSP_FW_ASR      7
+#define WM_ADSP_FW_TRACE    8
+#define WM_ADSP_FW_SPK_PROT 9
+#define WM_ADSP_FW_MISC     10
+
+#define WM_ADSP_NUM_FW      11
+
+static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
+	[WM_ADSP_FW_MBC_VSS] =  "MBC/VSS",
+	[WM_ADSP_FW_HIFI] =     "MasterHiFi",
+	[WM_ADSP_FW_TX] =       "Tx",
+	[WM_ADSP_FW_TX_SPK] =   "Tx Speaker",
+	[WM_ADSP_FW_RX] =       "Rx",
+	[WM_ADSP_FW_RX_ANC] =   "Rx ANC",
+	[WM_ADSP_FW_CTRL] =     "Voice Ctrl",
+	[WM_ADSP_FW_ASR] =      "ASR Assist",
+	[WM_ADSP_FW_TRACE] =    "Dbg Trace",
+	[WM_ADSP_FW_SPK_PROT] = "Protection",
+	[WM_ADSP_FW_MISC] =     "Misc",
+};
+
+struct wm_adsp_system_config_xm_hdr {
+	__be32 sys_enable;
+	__be32 fw_id;
+	__be32 fw_rev;
+	__be32 boot_status;
+	__be32 watchdog;
+	__be32 dma_buffer_size;
+	__be32 rdma[6];
+	__be32 wdma[8];
+	__be32 build_job_name[3];
+	__be32 build_job_number;
+};
+
+struct wm_adsp_alg_xm_struct {
+	__be32 magic;
+	__be32 smoothing;
+	__be32 threshold;
+	__be32 host_buf_ptr;
+	__be32 start_seq;
+	__be32 high_water_mark;
+	__be32 low_water_mark;
+	__be64 smoothed_power;
+};
+
+struct wm_adsp_buffer {
+	__be32 X_buf_base;		/* XM base addr of first X area */
+	__be32 X_buf_size;		/* Size of 1st X area in words */
+	__be32 X_buf_base2;		/* XM base addr of 2nd X area */
+	__be32 X_buf_brk;		/* Total X size in words */
+	__be32 Y_buf_base;		/* YM base addr of Y area */
+	__be32 wrap;			/* Total size X and Y in words */
+	__be32 high_water_mark;		/* Point at which IRQ is asserted */
+	__be32 irq_count;		/* bits 1-31 count IRQ assertions */
+	__be32 irq_ack;			/* acked IRQ count, bit 0 enables IRQ */
+	__be32 next_write_index;	/* word index of next write */
+	__be32 next_read_index;		/* word index of next read */
+	__be32 error;			/* error if any */
+	__be32 oldest_block_index;	/* word index of oldest surviving */
+	__be32 requested_rewind;	/* how many blocks rewind was done */
+	__be32 reserved_space;		/* internal */
+	__be32 min_free;		/* min free space since stream start */
+	__be32 blocks_written[2];	/* total blocks written (64 bit) */
+	__be32 words_written[2];	/* total words written (64 bit) */
+};
+
+struct wm_adsp_compr;
+
+struct wm_adsp_compr_buf {
+	struct wm_adsp *dsp;
+	struct wm_adsp_compr *compr;
+
+	struct wm_adsp_buffer_region *regions;
+	u32 host_buf_ptr;
+
+	u32 error;
+	u32 irq_count;
+	int read_index;
+	int avail;
+};
+
+struct wm_adsp_compr {
+	struct wm_adsp *dsp;
+	struct wm_adsp_compr_buf *buf;
+
+	struct snd_compr_stream *stream;
+	struct snd_compressed_buffer size;
+
+	u32 *raw_buf;
+	unsigned int copied_total;
+
+	unsigned int sample_rate;
+};
+
+#define WM_ADSP_DATA_WORD_SIZE         3
+
+#define WM_ADSP_MIN_FRAGMENTS          1
+#define WM_ADSP_MAX_FRAGMENTS          256
+#define WM_ADSP_MIN_FRAGMENT_SIZE      (64 * WM_ADSP_DATA_WORD_SIZE)
+#define WM_ADSP_MAX_FRAGMENT_SIZE      (4096 * WM_ADSP_DATA_WORD_SIZE)
+
+#define WM_ADSP_ALG_XM_STRUCT_MAGIC    0x49aec7
+
+#define HOST_BUFFER_FIELD(field) \
+	(offsetof(struct wm_adsp_buffer, field) / sizeof(__be32))
+
+#define ALG_XM_FIELD(field) \
+	(offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32))
+
+static int wm_adsp_buffer_init(struct wm_adsp *dsp);
+static int wm_adsp_buffer_free(struct wm_adsp *dsp);
+
+struct wm_adsp_buffer_region {
+	unsigned int offset;
+	unsigned int cumulative_size;
+	unsigned int mem_type;
+	unsigned int base_addr;
+};
+
+struct wm_adsp_buffer_region_def {
+	unsigned int mem_type;
+	unsigned int base_offset;
+	unsigned int size_offset;
+};
+
+static const struct wm_adsp_buffer_region_def default_regions[] = {
+	{
+		.mem_type = WMFW_ADSP2_XM,
+		.base_offset = HOST_BUFFER_FIELD(X_buf_base),
+		.size_offset = HOST_BUFFER_FIELD(X_buf_size),
+	},
+	{
+		.mem_type = WMFW_ADSP2_XM,
+		.base_offset = HOST_BUFFER_FIELD(X_buf_base2),
+		.size_offset = HOST_BUFFER_FIELD(X_buf_brk),
+	},
+	{
+		.mem_type = WMFW_ADSP2_YM,
+		.base_offset = HOST_BUFFER_FIELD(Y_buf_base),
+		.size_offset = HOST_BUFFER_FIELD(wrap),
+	},
+};
+
+struct wm_adsp_fw_caps {
+	u32 id;
+	struct snd_codec_desc desc;
+	int num_regions;
+	const struct wm_adsp_buffer_region_def *region_defs;
+};
+
+static const struct wm_adsp_fw_caps ctrl_caps[] = {
+	{
+		.id = SND_AUDIOCODEC_BESPOKE,
+		.desc = {
+			.max_ch = 8,
+			.sample_rates = { 16000 },
+			.num_sample_rates = 1,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.num_regions = ARRAY_SIZE(default_regions),
+		.region_defs = default_regions,
+	},
+};
+
+static const struct wm_adsp_fw_caps trace_caps[] = {
+	{
+		.id = SND_AUDIOCODEC_BESPOKE,
+		.desc = {
+			.max_ch = 8,
+			.sample_rates = {
+				4000, 8000, 11025, 12000, 16000, 22050,
+				24000, 32000, 44100, 48000, 64000, 88200,
+				96000, 176400, 192000
+			},
+			.num_sample_rates = 15,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.num_regions = ARRAY_SIZE(default_regions),
+		.region_defs = default_regions,
+	},
+};
+
+static const struct {
+	const char *file;
+	int compr_direction;
+	int num_caps;
+	const struct wm_adsp_fw_caps *caps;
+	bool voice_trigger;
+} wm_adsp_fw[WM_ADSP_NUM_FW] = {
+	[WM_ADSP_FW_MBC_VSS] =  { .file = "mbc-vss" },
+	[WM_ADSP_FW_HIFI] =     { .file = "hifi" },
+	[WM_ADSP_FW_TX] =       { .file = "tx" },
+	[WM_ADSP_FW_TX_SPK] =   { .file = "tx-spk" },
+	[WM_ADSP_FW_RX] =       { .file = "rx" },
+	[WM_ADSP_FW_RX_ANC] =   { .file = "rx-anc" },
+	[WM_ADSP_FW_CTRL] =     {
+		.file = "ctrl",
+		.compr_direction = SND_COMPRESS_CAPTURE,
+		.num_caps = ARRAY_SIZE(ctrl_caps),
+		.caps = ctrl_caps,
+		.voice_trigger = true,
+	},
+	[WM_ADSP_FW_ASR] =      { .file = "asr" },
+	[WM_ADSP_FW_TRACE] =    {
+		.file = "trace",
+		.compr_direction = SND_COMPRESS_CAPTURE,
+		.num_caps = ARRAY_SIZE(trace_caps),
+		.caps = trace_caps,
+	},
+	[WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" },
+	[WM_ADSP_FW_MISC] =     { .file = "misc" },
+};
+
+struct wm_coeff_ctl_ops {
+	int (*xget)(struct snd_kcontrol *kcontrol,
+		    struct snd_ctl_elem_value *ucontrol);
+	int (*xput)(struct snd_kcontrol *kcontrol,
+		    struct snd_ctl_elem_value *ucontrol);
+};
+
+struct wm_coeff_ctl {
+	const char *name;
+	const char *fw_name;
+	struct wm_adsp_alg_region alg_region;
+	struct wm_coeff_ctl_ops ops;
+	struct wm_adsp *dsp;
+	unsigned int enabled:1;
+	struct list_head list;
+	void *cache;
+	unsigned int offset;
+	size_t len;
+	unsigned int set:1;
+	struct soc_bytes_ext bytes_ext;
+	unsigned int flags;
+	unsigned int type;
+};
+
+static const char *wm_adsp_mem_region_name(unsigned int type)
+{
+	switch (type) {
+	case WMFW_ADSP1_PM:
+		return "PM";
+	case WMFW_ADSP1_DM:
+		return "DM";
+	case WMFW_ADSP2_XM:
+		return "XM";
+	case WMFW_ADSP2_YM:
+		return "YM";
+	case WMFW_ADSP1_ZM:
+		return "ZM";
+	default:
+		return NULL;
+	}
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s)
+{
+	char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
+
+	kfree(dsp->wmfw_file_name);
+	dsp->wmfw_file_name = tmp;
+}
+
+static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s)
+{
+	char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
+
+	kfree(dsp->bin_file_name);
+	dsp->bin_file_name = tmp;
+}
+
+static void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
+{
+	kfree(dsp->wmfw_file_name);
+	kfree(dsp->bin_file_name);
+	dsp->wmfw_file_name = NULL;
+	dsp->bin_file_name = NULL;
+}
+
+static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct wm_adsp *dsp = file->private_data;
+	ssize_t ret;
+
+	mutex_lock(&dsp->pwr_lock);
+
+	if (!dsp->wmfw_file_name || !dsp->booted)
+		ret = 0;
+	else
+		ret = simple_read_from_buffer(user_buf, count, ppos,
+					      dsp->wmfw_file_name,
+					      strlen(dsp->wmfw_file_name));
+
+	mutex_unlock(&dsp->pwr_lock);
+	return ret;
+}
+
+static ssize_t wm_adsp_debugfs_bin_read(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct wm_adsp *dsp = file->private_data;
+	ssize_t ret;
+
+	mutex_lock(&dsp->pwr_lock);
+
+	if (!dsp->bin_file_name || !dsp->booted)
+		ret = 0;
+	else
+		ret = simple_read_from_buffer(user_buf, count, ppos,
+					      dsp->bin_file_name,
+					      strlen(dsp->bin_file_name));
+
+	mutex_unlock(&dsp->pwr_lock);
+	return ret;
+}
+
+static const struct {
+	const char *name;
+	const struct file_operations fops;
+} wm_adsp_debugfs_fops[] = {
+	{
+		.name = "wmfw_file_name",
+		.fops = {
+			.open = simple_open,
+			.read = wm_adsp_debugfs_wmfw_read,
+		},
+	},
+	{
+		.name = "bin_file_name",
+		.fops = {
+			.open = simple_open,
+			.read = wm_adsp_debugfs_bin_read,
+		},
+	},
+};
+
+static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
+				  struct snd_soc_component *component)
+{
+	struct dentry *root = NULL;
+	int i;
+
+	if (!component->debugfs_root) {
+		adsp_err(dsp, "No codec debugfs root\n");
+		goto err;
+	}
+
+	root = debugfs_create_dir(dsp->name, component->debugfs_root);
+
+	if (!root)
+		goto err;
+
+	if (!debugfs_create_bool("booted", 0444, root, &dsp->booted))
+		goto err;
+
+	if (!debugfs_create_bool("running", 0444, root, &dsp->running))
+		goto err;
+
+	if (!debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id))
+		goto err;
+
+	if (!debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version))
+		goto err;
+
+	for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i) {
+		if (!debugfs_create_file(wm_adsp_debugfs_fops[i].name,
+					 0444, root, dsp,
+					 &wm_adsp_debugfs_fops[i].fops))
+			goto err;
+	}
+
+	dsp->debugfs_root = root;
+	return;
+
+err:
+	debugfs_remove_recursive(root);
+	adsp_err(dsp, "Failed to create debugfs\n");
+}
+
+static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
+{
+	wm_adsp_debugfs_clear(dsp);
+	debugfs_remove_recursive(dsp->debugfs_root);
+}
+#else
+static inline void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
+					 struct snd_soc_component *component)
+{
+}
+
+static inline void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
+{
+}
+
+static inline void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp,
+						 const char *s)
+{
+}
+
+static inline void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp,
+						const char *s)
+{
+}
+
+static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
+{
+}
+#endif
+
+int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
+		   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
+
+	ucontrol->value.enumerated.item[0] = dsp[e->shift_l].fw;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_fw_get);
+
+int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
+		   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw)
+		return 0;
+
+	if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW)
+		return -EINVAL;
+
+	mutex_lock(&dsp[e->shift_l].pwr_lock);
+
+	if (dsp[e->shift_l].booted || dsp[e->shift_l].compr)
+		ret = -EBUSY;
+	else
+		dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0];
+
+	mutex_unlock(&dsp[e->shift_l].pwr_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_fw_put);
+
+const struct soc_enum wm_adsp_fw_enum[] = {
+	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
+	SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
+	SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
+	SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
+	SOC_ENUM_SINGLE(0, 4, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
+	SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
+	SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
+};
+EXPORT_SYMBOL_GPL(wm_adsp_fw_enum);
+
+static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
+							int type)
+{
+	int i;
+
+	for (i = 0; i < dsp->num_mems; i++)
+		if (dsp->mem[i].type == type)
+			return &dsp->mem[i];
+
+	return NULL;
+}
+
+static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
+					  unsigned int offset)
+{
+	if (WARN_ON(!mem))
+		return offset;
+	switch (mem->type) {
+	case WMFW_ADSP1_PM:
+		return mem->base + (offset * 3);
+	case WMFW_ADSP1_DM:
+		return mem->base + (offset * 2);
+	case WMFW_ADSP2_XM:
+		return mem->base + (offset * 2);
+	case WMFW_ADSP2_YM:
+		return mem->base + (offset * 2);
+	case WMFW_ADSP1_ZM:
+		return mem->base + (offset * 2);
+	default:
+		WARN(1, "Unknown memory region type");
+		return offset;
+	}
+}
+
+static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
+{
+	unsigned int scratch[4];
+	unsigned int addr = dsp->base + ADSP2_SCRATCH0;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(scratch); ++i) {
+		ret = regmap_read(dsp->regmap, addr + i, &scratch[i]);
+		if (ret) {
+			adsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret);
+			return;
+		}
+	}
+
+	adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
+		 scratch[0], scratch[1], scratch[2], scratch[3]);
+}
+
+static void wm_adsp2v2_show_fw_status(struct wm_adsp *dsp)
+{
+	unsigned int scratch[2];
+	int ret;
+
+	ret = regmap_read(dsp->regmap, dsp->base + ADSP2V2_SCRATCH0_1,
+			  &scratch[0]);
+	if (ret) {
+		adsp_err(dsp, "Failed to read SCRATCH0_1: %d\n", ret);
+		return;
+	}
+
+	ret = regmap_read(dsp->regmap, dsp->base + ADSP2V2_SCRATCH2_3,
+			  &scratch[1]);
+	if (ret) {
+		adsp_err(dsp, "Failed to read SCRATCH2_3: %d\n", ret);
+		return;
+	}
+
+	adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
+		 scratch[0] & 0xFFFF,
+		 scratch[0] >> 16,
+		 scratch[1] & 0xFFFF,
+		 scratch[1] >> 16);
+}
+
+static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
+{
+	return container_of(ext, struct wm_coeff_ctl, bytes_ext);
+}
+
+static int wm_coeff_base_reg(struct wm_coeff_ctl *ctl, unsigned int *reg)
+{
+	const struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
+	struct wm_adsp *dsp = ctl->dsp;
+	const struct wm_adsp_region *mem;
+
+	mem = wm_adsp_find_region(dsp, alg_region->type);
+	if (!mem) {
+		adsp_err(dsp, "No base for region %x\n",
+			 alg_region->type);
+		return -EINVAL;
+	}
+
+	*reg = wm_adsp_region_to_reg(mem, ctl->alg_region.base + ctl->offset);
+
+	return 0;
+}
+
+static int wm_coeff_info(struct snd_kcontrol *kctl,
+			 struct snd_ctl_elem_info *uinfo)
+{
+	struct soc_bytes_ext *bytes_ext =
+		(struct soc_bytes_ext *)kctl->private_value;
+	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
+
+	switch (ctl->type) {
+	case WMFW_CTL_TYPE_ACKED:
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+		uinfo->value.integer.min = WM_ADSP_ACKED_CTL_MIN_VALUE;
+		uinfo->value.integer.max = WM_ADSP_ACKED_CTL_MAX_VALUE;
+		uinfo->value.integer.step = 1;
+		uinfo->count = 1;
+		break;
+	default:
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+		uinfo->count = ctl->len;
+		break;
+	}
+
+	return 0;
+}
+
+static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl,
+					unsigned int event_id)
+{
+	struct wm_adsp *dsp = ctl->dsp;
+	u32 val = cpu_to_be32(event_id);
+	unsigned int reg;
+	int i, ret;
+
+	ret = wm_coeff_base_reg(ctl, &reg);
+	if (ret)
+		return ret;
+
+	adsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n",
+		 event_id, ctl->alg_region.alg,
+		 wm_adsp_mem_region_name(ctl->alg_region.type), ctl->offset);
+
+	ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
+	if (ret) {
+		adsp_err(dsp, "Failed to write %x: %d\n", reg, ret);
+		return ret;
+	}
+
+	/*
+	 * Poll for ack, we initially poll at ~1ms intervals for firmwares
+	 * that respond quickly, then go to ~10ms polls. A firmware is unlikely
+	 * to ack instantly so we do the first 1ms delay before reading the
+	 * control to avoid a pointless bus transaction
+	 */
+	for (i = 0; i < WM_ADSP_ACKED_CTL_TIMEOUT_MS;) {
+		switch (i) {
+		case 0 ... WM_ADSP_ACKED_CTL_N_QUICKPOLLS - 1:
+			usleep_range(1000, 2000);
+			i++;
+			break;
+		default:
+			usleep_range(10000, 20000);
+			i += 10;
+			break;
+		}
+
+		ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
+		if (ret) {
+			adsp_err(dsp, "Failed to read %x: %d\n", reg, ret);
+			return ret;
+		}
+
+		if (val == 0) {
+			adsp_dbg(dsp, "Acked control ACKED at poll %u\n", i);
+			return 0;
+		}
+	}
+
+	adsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n",
+		  reg, ctl->alg_region.alg,
+		  wm_adsp_mem_region_name(ctl->alg_region.type),
+		  ctl->offset);
+
+	return -ETIMEDOUT;
+}
+
+static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
+				  const void *buf, size_t len)
+{
+	struct wm_adsp *dsp = ctl->dsp;
+	void *scratch;
+	int ret;
+	unsigned int reg;
+
+	ret = wm_coeff_base_reg(ctl, &reg);
+	if (ret)
+		return ret;
+
+	scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA);
+	if (!scratch)
+		return -ENOMEM;
+
+	ret = regmap_raw_write(dsp->regmap, reg, scratch,
+			       len);
+	if (ret) {
+		adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
+			 len, reg, ret);
+		kfree(scratch);
+		return ret;
+	}
+	adsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg);
+
+	kfree(scratch);
+
+	return 0;
+}
+
+static int wm_coeff_put(struct snd_kcontrol *kctl,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_bytes_ext *bytes_ext =
+		(struct soc_bytes_ext *)kctl->private_value;
+	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
+	char *p = ucontrol->value.bytes.data;
+	int ret = 0;
+
+	mutex_lock(&ctl->dsp->pwr_lock);
+
+	if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+		ret = -EPERM;
+	else
+		memcpy(ctl->cache, p, ctl->len);
+
+	ctl->set = 1;
+	if (ctl->enabled && ctl->dsp->running)
+		ret = wm_coeff_write_control(ctl, p, ctl->len);
+
+	mutex_unlock(&ctl->dsp->pwr_lock);
+
+	return ret;
+}
+
+static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
+			    const unsigned int __user *bytes, unsigned int size)
+{
+	struct soc_bytes_ext *bytes_ext =
+		(struct soc_bytes_ext *)kctl->private_value;
+	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
+	int ret = 0;
+
+	mutex_lock(&ctl->dsp->pwr_lock);
+
+	if (copy_from_user(ctl->cache, bytes, size)) {
+		ret = -EFAULT;
+	} else {
+		ctl->set = 1;
+		if (ctl->enabled && ctl->dsp->running)
+			ret = wm_coeff_write_control(ctl, ctl->cache, size);
+		else if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+			ret = -EPERM;
+	}
+
+	mutex_unlock(&ctl->dsp->pwr_lock);
+
+	return ret;
+}
+
+static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_bytes_ext *bytes_ext =
+		(struct soc_bytes_ext *)kctl->private_value;
+	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
+	unsigned int val = ucontrol->value.integer.value[0];
+	int ret;
+
+	if (val == 0)
+		return 0;	/* 0 means no event */
+
+	mutex_lock(&ctl->dsp->pwr_lock);
+
+	if (ctl->enabled && ctl->dsp->running)
+		ret = wm_coeff_write_acked_control(ctl, val);
+	else
+		ret = -EPERM;
+
+	mutex_unlock(&ctl->dsp->pwr_lock);
+
+	return ret;
+}
+
+static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
+				 void *buf, size_t len)
+{
+	struct wm_adsp *dsp = ctl->dsp;
+	void *scratch;
+	int ret;
+	unsigned int reg;
+
+	ret = wm_coeff_base_reg(ctl, &reg);
+	if (ret)
+		return ret;
+
+	scratch = kmalloc(len, GFP_KERNEL | GFP_DMA);
+	if (!scratch)
+		return -ENOMEM;
+
+	ret = regmap_raw_read(dsp->regmap, reg, scratch, len);
+	if (ret) {
+		adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
+			 len, reg, ret);
+		kfree(scratch);
+		return ret;
+	}
+	adsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg);
+
+	memcpy(buf, scratch, len);
+	kfree(scratch);
+
+	return 0;
+}
+
+static int wm_coeff_get(struct snd_kcontrol *kctl,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_bytes_ext *bytes_ext =
+		(struct soc_bytes_ext *)kctl->private_value;
+	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
+	char *p = ucontrol->value.bytes.data;
+	int ret = 0;
+
+	mutex_lock(&ctl->dsp->pwr_lock);
+
+	if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
+		if (ctl->enabled && ctl->dsp->running)
+			ret = wm_coeff_read_control(ctl, p, ctl->len);
+		else
+			ret = -EPERM;
+	} else {
+		if (!ctl->flags && ctl->enabled && ctl->dsp->running)
+			ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len);
+
+		memcpy(p, ctl->cache, ctl->len);
+	}
+
+	mutex_unlock(&ctl->dsp->pwr_lock);
+
+	return ret;
+}
+
+static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
+			    unsigned int __user *bytes, unsigned int size)
+{
+	struct soc_bytes_ext *bytes_ext =
+		(struct soc_bytes_ext *)kctl->private_value;
+	struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
+	int ret = 0;
+
+	mutex_lock(&ctl->dsp->pwr_lock);
+
+	if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
+		if (ctl->enabled && ctl->dsp->running)
+			ret = wm_coeff_read_control(ctl, ctl->cache, size);
+		else
+			ret = -EPERM;
+	} else {
+		if (!ctl->flags && ctl->enabled && ctl->dsp->running)
+			ret = wm_coeff_read_control(ctl, ctl->cache, size);
+	}
+
+	if (!ret && copy_to_user(bytes, ctl->cache, size))
+		ret = -EFAULT;
+
+	mutex_unlock(&ctl->dsp->pwr_lock);
+
+	return ret;
+}
+
+static int wm_coeff_get_acked(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	/*
+	 * Although it's not useful to read an acked control, we must satisfy
+	 * user-side assumptions that all controls are readable and that a
+	 * write of the same value should be filtered out (it's valid to send
+	 * the same event number again to the firmware). We therefore return 0,
+	 * meaning "no event" so valid event numbers will always be a change
+	 */
+	ucontrol->value.integer.value[0] = 0;
+
+	return 0;
+}
+
+struct wmfw_ctl_work {
+	struct wm_adsp *dsp;
+	struct wm_coeff_ctl *ctl;
+	struct work_struct work;
+};
+
+static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len)
+{
+	unsigned int out, rd, wr, vol;
+
+	if (len > ADSP_MAX_STD_CTRL_SIZE) {
+		rd = SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+		wr = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE;
+		vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
+
+		out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+	} else {
+		rd = SNDRV_CTL_ELEM_ACCESS_READ;
+		wr = SNDRV_CTL_ELEM_ACCESS_WRITE;
+		vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
+
+		out = 0;
+	}
+
+	if (in) {
+		if (in & WMFW_CTL_FLAG_READABLE)
+			out |= rd;
+		if (in & WMFW_CTL_FLAG_WRITEABLE)
+			out |= wr;
+		if (in & WMFW_CTL_FLAG_VOLATILE)
+			out |= vol;
+	} else {
+		out |= rd | wr | vol;
+	}
+
+	return out;
+}
+
+static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
+{
+	struct snd_kcontrol_new *kcontrol;
+	int ret;
+
+	if (!ctl || !ctl->name)
+		return -EINVAL;
+
+	kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
+	if (!kcontrol)
+		return -ENOMEM;
+
+	kcontrol->name = ctl->name;
+	kcontrol->info = wm_coeff_info;
+	kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	kcontrol->tlv.c = snd_soc_bytes_tlv_callback;
+	kcontrol->private_value = (unsigned long)&ctl->bytes_ext;
+	kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len);
+
+	switch (ctl->type) {
+	case WMFW_CTL_TYPE_ACKED:
+		kcontrol->get = wm_coeff_get_acked;
+		kcontrol->put = wm_coeff_put_acked;
+		break;
+	default:
+		if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+			ctl->bytes_ext.max = ctl->len;
+			ctl->bytes_ext.get = wm_coeff_tlv_get;
+			ctl->bytes_ext.put = wm_coeff_tlv_put;
+		} else {
+			kcontrol->get = wm_coeff_get;
+			kcontrol->put = wm_coeff_put;
+		}
+		break;
+	}
+
+	ret = snd_soc_add_component_controls(dsp->component, kcontrol, 1);
+	if (ret < 0)
+		goto err_kcontrol;
+
+	kfree(kcontrol);
+
+	return 0;
+
+err_kcontrol:
+	kfree(kcontrol);
+	return ret;
+}
+
+static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
+{
+	struct wm_coeff_ctl *ctl;
+	int ret;
+
+	list_for_each_entry(ctl, &dsp->ctl_list, list) {
+		if (!ctl->enabled || ctl->set)
+			continue;
+		if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+			continue;
+
+		/*
+		 * For readable controls populate the cache from the DSP memory.
+		 * For non-readable controls the cache was zero-filled when
+		 * created so we don't need to do anything.
+		 */
+		if (!ctl->flags || (ctl->flags & WMFW_CTL_FLAG_READABLE)) {
+			ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int wm_coeff_sync_controls(struct wm_adsp *dsp)
+{
+	struct wm_coeff_ctl *ctl;
+	int ret;
+
+	list_for_each_entry(ctl, &dsp->ctl_list, list) {
+		if (!ctl->enabled)
+			continue;
+		if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
+			ret = wm_coeff_write_control(ctl, ctl->cache, ctl->len);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void wm_adsp_signal_event_controls(struct wm_adsp *dsp,
+					  unsigned int event)
+{
+	struct wm_coeff_ctl *ctl;
+	int ret;
+
+	list_for_each_entry(ctl, &dsp->ctl_list, list) {
+		if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT)
+			continue;
+
+		if (!ctl->enabled)
+			continue;
+
+		ret = wm_coeff_write_acked_control(ctl, event);
+		if (ret)
+			adsp_warn(dsp,
+				  "Failed to send 0x%x event to alg 0x%x (%d)\n",
+				  event, ctl->alg_region.alg, ret);
+	}
+}
+
+static void wm_adsp_ctl_work(struct work_struct *work)
+{
+	struct wmfw_ctl_work *ctl_work = container_of(work,
+						      struct wmfw_ctl_work,
+						      work);
+
+	wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl);
+	kfree(ctl_work);
+}
+
+static void wm_adsp_free_ctl_blk(struct wm_coeff_ctl *ctl)
+{
+	kfree(ctl->cache);
+	kfree(ctl->name);
+	kfree(ctl);
+}
+
+static int wm_adsp_create_control(struct wm_adsp *dsp,
+				  const struct wm_adsp_alg_region *alg_region,
+				  unsigned int offset, unsigned int len,
+				  const char *subname, unsigned int subname_len,
+				  unsigned int flags, unsigned int type)
+{
+	struct wm_coeff_ctl *ctl;
+	struct wmfw_ctl_work *ctl_work;
+	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+	const char *region_name;
+	int ret;
+
+	region_name = wm_adsp_mem_region_name(alg_region->type);
+	if (!region_name) {
+		adsp_err(dsp, "Unknown region type: %d\n", alg_region->type);
+		return -EINVAL;
+	}
+
+	switch (dsp->fw_ver) {
+	case 0:
+	case 1:
+		snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x",
+			 dsp->name, region_name, alg_region->alg);
+		break;
+	default:
+		ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+				"%s%c %.12s %x", dsp->name, *region_name,
+				wm_adsp_fw_text[dsp->fw], alg_region->alg);
+
+		/* Truncate the subname from the start if it is too long */
+		if (subname) {
+			int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
+			int skip = 0;
+
+			if (dsp->component->name_prefix)
+				avail -= strlen(dsp->component->name_prefix) + 1;
+
+			if (subname_len > avail)
+				skip = subname_len - avail;
+
+			snprintf(name + ret,
+				 SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, " %.*s",
+				 subname_len - skip, subname + skip);
+		}
+		break;
+	}
+
+	list_for_each_entry(ctl, &dsp->ctl_list, list) {
+		if (!strcmp(ctl->name, name)) {
+			if (!ctl->enabled)
+				ctl->enabled = 1;
+			return 0;
+		}
+	}
+
+	ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
+	if (!ctl)
+		return -ENOMEM;
+	ctl->fw_name = wm_adsp_fw_text[dsp->fw];
+	ctl->alg_region = *alg_region;
+	ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
+	if (!ctl->name) {
+		ret = -ENOMEM;
+		goto err_ctl;
+	}
+	ctl->enabled = 1;
+	ctl->set = 0;
+	ctl->ops.xget = wm_coeff_get;
+	ctl->ops.xput = wm_coeff_put;
+	ctl->dsp = dsp;
+
+	ctl->flags = flags;
+	ctl->type = type;
+	ctl->offset = offset;
+	ctl->len = len;
+	ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
+	if (!ctl->cache) {
+		ret = -ENOMEM;
+		goto err_ctl_name;
+	}
+
+	list_add(&ctl->list, &dsp->ctl_list);
+
+	if (flags & WMFW_CTL_FLAG_SYS)
+		return 0;
+
+	ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
+	if (!ctl_work) {
+		ret = -ENOMEM;
+		goto err_ctl_cache;
+	}
+
+	ctl_work->dsp = dsp;
+	ctl_work->ctl = ctl;
+	INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
+	schedule_work(&ctl_work->work);
+
+	return 0;
+
+err_ctl_cache:
+	kfree(ctl->cache);
+err_ctl_name:
+	kfree(ctl->name);
+err_ctl:
+	kfree(ctl);
+
+	return ret;
+}
+
+struct wm_coeff_parsed_alg {
+	int id;
+	const u8 *name;
+	int name_len;
+	int ncoeff;
+};
+
+struct wm_coeff_parsed_coeff {
+	int offset;
+	int mem_type;
+	const u8 *name;
+	int name_len;
+	int ctl_type;
+	int flags;
+	int len;
+};
+
+static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
+{
+	int length;
+
+	switch (bytes) {
+	case 1:
+		length = **pos;
+		break;
+	case 2:
+		length = le16_to_cpu(*((__le16 *)*pos));
+		break;
+	default:
+		return 0;
+	}
+
+	if (str)
+		*str = *pos + bytes;
+
+	*pos += ((length + bytes) + 3) & ~0x03;
+
+	return length;
+}
+
+static int wm_coeff_parse_int(int bytes, const u8 **pos)
+{
+	int val = 0;
+
+	switch (bytes) {
+	case 2:
+		val = le16_to_cpu(*((__le16 *)*pos));
+		break;
+	case 4:
+		val = le32_to_cpu(*((__le32 *)*pos));
+		break;
+	default:
+		break;
+	}
+
+	*pos += bytes;
+
+	return val;
+}
+
+static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data,
+				      struct wm_coeff_parsed_alg *blk)
+{
+	const struct wmfw_adsp_alg_data *raw;
+
+	switch (dsp->fw_ver) {
+	case 0:
+	case 1:
+		raw = (const struct wmfw_adsp_alg_data *)*data;
+		*data = raw->data;
+
+		blk->id = le32_to_cpu(raw->id);
+		blk->name = raw->name;
+		blk->name_len = strlen(raw->name);
+		blk->ncoeff = le32_to_cpu(raw->ncoeff);
+		break;
+	default:
+		blk->id = wm_coeff_parse_int(sizeof(raw->id), data);
+		blk->name_len = wm_coeff_parse_string(sizeof(u8), data,
+						      &blk->name);
+		wm_coeff_parse_string(sizeof(u16), data, NULL);
+		blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data);
+		break;
+	}
+
+	adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
+	adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
+	adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
+}
+
+static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
+					struct wm_coeff_parsed_coeff *blk)
+{
+	const struct wmfw_adsp_coeff_data *raw;
+	const u8 *tmp;
+	int length;
+
+	switch (dsp->fw_ver) {
+	case 0:
+	case 1:
+		raw = (const struct wmfw_adsp_coeff_data *)*data;
+		*data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
+
+		blk->offset = le16_to_cpu(raw->hdr.offset);
+		blk->mem_type = le16_to_cpu(raw->hdr.type);
+		blk->name = raw->name;
+		blk->name_len = strlen(raw->name);
+		blk->ctl_type = le16_to_cpu(raw->ctl_type);
+		blk->flags = le16_to_cpu(raw->flags);
+		blk->len = le32_to_cpu(raw->len);
+		break;
+	default:
+		tmp = *data;
+		blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
+		blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
+		length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
+		blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp,
+						      &blk->name);
+		wm_coeff_parse_string(sizeof(u8), &tmp, NULL);
+		wm_coeff_parse_string(sizeof(u16), &tmp, NULL);
+		blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
+		blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp);
+		blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp);
+
+		*data = *data + sizeof(raw->hdr) + length;
+		break;
+	}
+
+	adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
+	adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
+	adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
+	adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
+	adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
+	adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
+}
+
+static int wm_adsp_check_coeff_flags(struct wm_adsp *dsp,
+				const struct wm_coeff_parsed_coeff *coeff_blk,
+				unsigned int f_required,
+				unsigned int f_illegal)
+{
+	if ((coeff_blk->flags & f_illegal) ||
+	    ((coeff_blk->flags & f_required) != f_required)) {
+		adsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n",
+			 coeff_blk->flags, coeff_blk->ctl_type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
+			       const struct wmfw_region *region)
+{
+	struct wm_adsp_alg_region alg_region = {};
+	struct wm_coeff_parsed_alg alg_blk;
+	struct wm_coeff_parsed_coeff coeff_blk;
+	const u8 *data = region->data;
+	int i, ret;
+
+	wm_coeff_parse_alg(dsp, &data, &alg_blk);
+	for (i = 0; i < alg_blk.ncoeff; i++) {
+		wm_coeff_parse_coeff(dsp, &data, &coeff_blk);
+
+		switch (coeff_blk.ctl_type) {
+		case SNDRV_CTL_ELEM_TYPE_BYTES:
+			break;
+		case WMFW_CTL_TYPE_ACKED:
+			if (coeff_blk.flags & WMFW_CTL_FLAG_SYS)
+				continue;	/* ignore */
+
+			ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
+						WMFW_CTL_FLAG_VOLATILE |
+						WMFW_CTL_FLAG_WRITEABLE |
+						WMFW_CTL_FLAG_READABLE,
+						0);
+			if (ret)
+				return -EINVAL;
+			break;
+		case WMFW_CTL_TYPE_HOSTEVENT:
+			ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
+						WMFW_CTL_FLAG_SYS |
+						WMFW_CTL_FLAG_VOLATILE |
+						WMFW_CTL_FLAG_WRITEABLE |
+						WMFW_CTL_FLAG_READABLE,
+						0);
+			if (ret)
+				return -EINVAL;
+			break;
+		case WMFW_CTL_TYPE_HOST_BUFFER:
+			ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
+						WMFW_CTL_FLAG_SYS |
+						WMFW_CTL_FLAG_VOLATILE |
+						WMFW_CTL_FLAG_READABLE,
+						0);
+			if (ret)
+				return -EINVAL;
+			break;
+		default:
+			adsp_err(dsp, "Unknown control type: %d\n",
+				 coeff_blk.ctl_type);
+			return -EINVAL;
+		}
+
+		alg_region.type = coeff_blk.mem_type;
+		alg_region.alg = alg_blk.id;
+
+		ret = wm_adsp_create_control(dsp, &alg_region,
+					     coeff_blk.offset,
+					     coeff_blk.len,
+					     coeff_blk.name,
+					     coeff_blk.name_len,
+					     coeff_blk.flags,
+					     coeff_blk.ctl_type);
+		if (ret < 0)
+			adsp_err(dsp, "Failed to create control: %.*s, %d\n",
+				 coeff_blk.name_len, coeff_blk.name, ret);
+	}
+
+	return 0;
+}
+
+static int wm_adsp_load(struct wm_adsp *dsp)
+{
+	LIST_HEAD(buf_list);
+	const struct firmware *firmware;
+	struct regmap *regmap = dsp->regmap;
+	unsigned int pos = 0;
+	const struct wmfw_header *header;
+	const struct wmfw_adsp1_sizes *adsp1_sizes;
+	const struct wmfw_adsp2_sizes *adsp2_sizes;
+	const struct wmfw_footer *footer;
+	const struct wmfw_region *region;
+	const struct wm_adsp_region *mem;
+	const char *region_name;
+	char *file, *text = NULL;
+	struct wm_adsp_buf *buf;
+	unsigned int reg;
+	int regions = 0;
+	int ret, offset, type, sizes;
+
+	file = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (file == NULL)
+		return -ENOMEM;
+
+	snprintf(file, PAGE_SIZE, "%s-%s-%s.wmfw", dsp->part, dsp->fwf_name,
+		 wm_adsp_fw[dsp->fw].file);
+	file[PAGE_SIZE - 1] = '\0';
+
+	ret = request_firmware(&firmware, file, dsp->dev);
+	if (ret != 0) {
+		adsp_err(dsp, "Failed to request '%s'\n", file);
+		goto out;
+	}
+	ret = -EINVAL;
+
+	pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
+	if (pos >= firmware->size) {
+		adsp_err(dsp, "%s: file too short, %zu bytes\n",
+			 file, firmware->size);
+		goto out_fw;
+	}
+
+	header = (void *)&firmware->data[0];
+
+	if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
+		adsp_err(dsp, "%s: invalid magic\n", file);
+		goto out_fw;
+	}
+
+	switch (header->ver) {
+	case 0:
+		adsp_warn(dsp, "%s: Depreciated file format %d\n",
+			  file, header->ver);
+		break;
+	case 1:
+	case 2:
+		break;
+	default:
+		adsp_err(dsp, "%s: unknown file format %d\n",
+			 file, header->ver);
+		goto out_fw;
+	}
+
+	adsp_info(dsp, "Firmware version: %d\n", header->ver);
+	dsp->fw_ver = header->ver;
+
+	if (header->core != dsp->type) {
+		adsp_err(dsp, "%s: invalid core %d != %d\n",
+			 file, header->core, dsp->type);
+		goto out_fw;
+	}
+
+	switch (dsp->type) {
+	case WMFW_ADSP1:
+		pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
+		adsp1_sizes = (void *)&(header[1]);
+		footer = (void *)&(adsp1_sizes[1]);
+		sizes = sizeof(*adsp1_sizes);
+
+		adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n",
+			 file, le32_to_cpu(adsp1_sizes->dm),
+			 le32_to_cpu(adsp1_sizes->pm),
+			 le32_to_cpu(adsp1_sizes->zm));
+		break;
+
+	case WMFW_ADSP2:
+		pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer);
+		adsp2_sizes = (void *)&(header[1]);
+		footer = (void *)&(adsp2_sizes[1]);
+		sizes = sizeof(*adsp2_sizes);
+
+		adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n",
+			 file, le32_to_cpu(adsp2_sizes->xm),
+			 le32_to_cpu(adsp2_sizes->ym),
+			 le32_to_cpu(adsp2_sizes->pm),
+			 le32_to_cpu(adsp2_sizes->zm));
+		break;
+
+	default:
+		WARN(1, "Unknown DSP type");
+		goto out_fw;
+	}
+
+	if (le32_to_cpu(header->len) != sizeof(*header) +
+	    sizes + sizeof(*footer)) {
+		adsp_err(dsp, "%s: unexpected header length %d\n",
+			 file, le32_to_cpu(header->len));
+		goto out_fw;
+	}
+
+	adsp_dbg(dsp, "%s: timestamp %llu\n", file,
+		 le64_to_cpu(footer->timestamp));
+
+	while (pos < firmware->size &&
+	       sizeof(*region) < firmware->size - pos) {
+		region = (void *)&(firmware->data[pos]);
+		region_name = "Unknown";
+		reg = 0;
+		text = NULL;
+		offset = le32_to_cpu(region->offset) & 0xffffff;
+		type = be32_to_cpu(region->type) & 0xff;
+		mem = wm_adsp_find_region(dsp, type);
+
+		switch (type) {
+		case WMFW_NAME_TEXT:
+			region_name = "Firmware name";
+			text = kzalloc(le32_to_cpu(region->len) + 1,
+				       GFP_KERNEL);
+			break;
+		case WMFW_ALGORITHM_DATA:
+			region_name = "Algorithm";
+			ret = wm_adsp_parse_coeff(dsp, region);
+			if (ret != 0)
+				goto out_fw;
+			break;
+		case WMFW_INFO_TEXT:
+			region_name = "Information";
+			text = kzalloc(le32_to_cpu(region->len) + 1,
+				       GFP_KERNEL);
+			break;
+		case WMFW_ABSOLUTE:
+			region_name = "Absolute";
+			reg = offset;
+			break;
+		case WMFW_ADSP1_PM:
+		case WMFW_ADSP1_DM:
+		case WMFW_ADSP2_XM:
+		case WMFW_ADSP2_YM:
+		case WMFW_ADSP1_ZM:
+			region_name = wm_adsp_mem_region_name(type);
+			reg = wm_adsp_region_to_reg(mem, offset);
+			break;
+		default:
+			adsp_warn(dsp,
+				  "%s.%d: Unknown region type %x at %d(%x)\n",
+				  file, regions, type, pos, pos);
+			break;
+		}
+
+		adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
+			 regions, le32_to_cpu(region->len), offset,
+			 region_name);
+
+		if (le32_to_cpu(region->len) >
+		    firmware->size - pos - sizeof(*region)) {
+			adsp_err(dsp,
+				 "%s.%d: %s region len %d bytes exceeds file length %zu\n",
+				 file, regions, region_name,
+				 le32_to_cpu(region->len), firmware->size);
+			ret = -EINVAL;
+			goto out_fw;
+		}
+
+		if (text) {
+			memcpy(text, region->data, le32_to_cpu(region->len));
+			adsp_info(dsp, "%s: %s\n", file, text);
+			kfree(text);
+			text = NULL;
+		}
+
+		if (reg) {
+			buf = wm_adsp_buf_alloc(region->data,
+						le32_to_cpu(region->len),
+						&buf_list);
+			if (!buf) {
+				adsp_err(dsp, "Out of memory\n");
+				ret = -ENOMEM;
+				goto out_fw;
+			}
+
+			ret = regmap_raw_write_async(regmap, reg, buf->buf,
+						     le32_to_cpu(region->len));
+			if (ret != 0) {
+				adsp_err(dsp,
+					"%s.%d: Failed to write %d bytes at %d in %s: %d\n",
+					file, regions,
+					le32_to_cpu(region->len), offset,
+					region_name, ret);
+				goto out_fw;
+			}
+		}
+
+		pos += le32_to_cpu(region->len) + sizeof(*region);
+		regions++;
+	}
+
+	ret = regmap_async_complete(regmap);
+	if (ret != 0) {
+		adsp_err(dsp, "Failed to complete async write: %d\n", ret);
+		goto out_fw;
+	}
+
+	if (pos > firmware->size)
+		adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
+			  file, regions, pos - firmware->size);
+
+	wm_adsp_debugfs_save_wmfwname(dsp, file);
+
+out_fw:
+	regmap_async_complete(regmap);
+	wm_adsp_buf_free(&buf_list);
+	release_firmware(firmware);
+	kfree(text);
+out:
+	kfree(file);
+
+	return ret;
+}
+
+static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
+				  const struct wm_adsp_alg_region *alg_region)
+{
+	struct wm_coeff_ctl *ctl;
+
+	list_for_each_entry(ctl, &dsp->ctl_list, list) {
+		if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] &&
+		    alg_region->alg == ctl->alg_region.alg &&
+		    alg_region->type == ctl->alg_region.type) {
+			ctl->alg_region.base = alg_region->base;
+		}
+	}
+}
+
+static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
+			       const struct wm_adsp_region *mem,
+			       unsigned int pos, unsigned int len)
+{
+	void *alg;
+	unsigned int reg;
+	int ret;
+	__be32 val;
+
+	if (n_algs == 0) {
+		adsp_err(dsp, "No algorithms\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (n_algs > 1024) {
+		adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* Read the terminator first to validate the length */
+	reg = wm_adsp_region_to_reg(mem, pos + len);
+
+	ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
+	if (ret != 0) {
+		adsp_err(dsp, "Failed to read algorithm list end: %d\n",
+			ret);
+		return ERR_PTR(ret);
+	}
+
+	if (be32_to_cpu(val) != 0xbedead)
+		adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n",
+			  reg, be32_to_cpu(val));
+
+	/* Convert length from DSP words to bytes */
+	len *= sizeof(u32);
+
+	alg = kzalloc(len, GFP_KERNEL | GFP_DMA);
+	if (!alg)
+		return ERR_PTR(-ENOMEM);
+
+	reg = wm_adsp_region_to_reg(mem, pos);
+
+	ret = regmap_raw_read(dsp->regmap, reg, alg, len);
+	if (ret != 0) {
+		adsp_err(dsp, "Failed to read algorithm list: %d\n", ret);
+		kfree(alg);
+		return ERR_PTR(ret);
+	}
+
+	return alg;
+}
+
+static struct wm_adsp_alg_region *
+	wm_adsp_find_alg_region(struct wm_adsp *dsp, int type, unsigned int id)
+{
+	struct wm_adsp_alg_region *alg_region;
+
+	list_for_each_entry(alg_region, &dsp->alg_regions, list) {
+		if (id == alg_region->alg && type == alg_region->type)
+			return alg_region;
+	}
+
+	return NULL;
+}
+
+static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
+							int type, __be32 id,
+							__be32 base)
+{
+	struct wm_adsp_alg_region *alg_region;
+
+	alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
+	if (!alg_region)
+		return ERR_PTR(-ENOMEM);
+
+	alg_region->type = type;
+	alg_region->alg = be32_to_cpu(id);
+	alg_region->base = be32_to_cpu(base);
+
+	list_add_tail(&alg_region->list, &dsp->alg_regions);
+
+	if (dsp->fw_ver > 0)
+		wm_adsp_ctl_fixup_base(dsp, alg_region);
+
+	return alg_region;
+}
+
+static void wm_adsp_free_alg_regions(struct wm_adsp *dsp)
+{
+	struct wm_adsp_alg_region *alg_region;
+
+	while (!list_empty(&dsp->alg_regions)) {
+		alg_region = list_first_entry(&dsp->alg_regions,
+					      struct wm_adsp_alg_region,
+					      list);
+		list_del(&alg_region->list);
+		kfree(alg_region);
+	}
+}
+
+static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
+{
+	struct wmfw_adsp1_id_hdr adsp1_id;
+	struct wmfw_adsp1_alg_hdr *adsp1_alg;
+	struct wm_adsp_alg_region *alg_region;
+	const struct wm_adsp_region *mem;
+	unsigned int pos, len;
+	size_t n_algs;
+	int i, ret;
+
+	mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
+	if (WARN_ON(!mem))
+		return -EINVAL;
+
+	ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
+			      sizeof(adsp1_id));
+	if (ret != 0) {
+		adsp_err(dsp, "Failed to read algorithm info: %d\n",
+			 ret);
+		return ret;
+	}
+
+	n_algs = be32_to_cpu(adsp1_id.n_algs);
+	dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
+	adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
+		  dsp->fw_id,
+		  (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
+		  (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
+		  be32_to_cpu(adsp1_id.fw.ver) & 0xff,
+		  n_algs);
+
+	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
+					   adsp1_id.fw.id, adsp1_id.zm);
+	if (IS_ERR(alg_region))
+		return PTR_ERR(alg_region);
+
+	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
+					   adsp1_id.fw.id, adsp1_id.dm);
+	if (IS_ERR(alg_region))
+		return PTR_ERR(alg_region);
+
+	/* Calculate offset and length in DSP words */
+	pos = sizeof(adsp1_id) / sizeof(u32);
+	len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32);
+
+	adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
+	if (IS_ERR(adsp1_alg))
+		return PTR_ERR(adsp1_alg);
+
+	for (i = 0; i < n_algs; i++) {
+		adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
+			  i, be32_to_cpu(adsp1_alg[i].alg.id),
+			  (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
+			  (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
+			  be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
+			  be32_to_cpu(adsp1_alg[i].dm),
+			  be32_to_cpu(adsp1_alg[i].zm));
+
+		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
+						   adsp1_alg[i].alg.id,
+						   adsp1_alg[i].dm);
+		if (IS_ERR(alg_region)) {
+			ret = PTR_ERR(alg_region);
+			goto out;
+		}
+		if (dsp->fw_ver == 0) {
+			if (i + 1 < n_algs) {
+				len = be32_to_cpu(adsp1_alg[i + 1].dm);
+				len -= be32_to_cpu(adsp1_alg[i].dm);
+				len *= 4;
+				wm_adsp_create_control(dsp, alg_region, 0,
+						     len, NULL, 0, 0,
+						     SNDRV_CTL_ELEM_TYPE_BYTES);
+			} else {
+				adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
+					  be32_to_cpu(adsp1_alg[i].alg.id));
+			}
+		}
+
+		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
+						   adsp1_alg[i].alg.id,
+						   adsp1_alg[i].zm);
+		if (IS_ERR(alg_region)) {
+			ret = PTR_ERR(alg_region);
+			goto out;
+		}
+		if (dsp->fw_ver == 0) {
+			if (i + 1 < n_algs) {
+				len = be32_to_cpu(adsp1_alg[i + 1].zm);
+				len -= be32_to_cpu(adsp1_alg[i].zm);
+				len *= 4;
+				wm_adsp_create_control(dsp, alg_region, 0,
+						     len, NULL, 0, 0,
+						     SNDRV_CTL_ELEM_TYPE_BYTES);
+			} else {
+				adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
+					  be32_to_cpu(adsp1_alg[i].alg.id));
+			}
+		}
+	}
+
+out:
+	kfree(adsp1_alg);
+	return ret;
+}
+
+static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
+{
+	struct wmfw_adsp2_id_hdr adsp2_id;
+	struct wmfw_adsp2_alg_hdr *adsp2_alg;
+	struct wm_adsp_alg_region *alg_region;
+	const struct wm_adsp_region *mem;
+	unsigned int pos, len;
+	size_t n_algs;
+	int i, ret;
+
+	mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
+	if (WARN_ON(!mem))
+		return -EINVAL;
+
+	ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
+			      sizeof(adsp2_id));
+	if (ret != 0) {
+		adsp_err(dsp, "Failed to read algorithm info: %d\n",
+			 ret);
+		return ret;
+	}
+
+	n_algs = be32_to_cpu(adsp2_id.n_algs);
+	dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
+	dsp->fw_id_version = be32_to_cpu(adsp2_id.fw.ver);
+	adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
+		  dsp->fw_id,
+		  (dsp->fw_id_version & 0xff0000) >> 16,
+		  (dsp->fw_id_version & 0xff00) >> 8,
+		  dsp->fw_id_version & 0xff,
+		  n_algs);
+
+	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
+					   adsp2_id.fw.id, adsp2_id.xm);
+	if (IS_ERR(alg_region))
+		return PTR_ERR(alg_region);
+
+	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
+					   adsp2_id.fw.id, adsp2_id.ym);
+	if (IS_ERR(alg_region))
+		return PTR_ERR(alg_region);
+
+	alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
+					   adsp2_id.fw.id, adsp2_id.zm);
+	if (IS_ERR(alg_region))
+		return PTR_ERR(alg_region);
+
+	/* Calculate offset and length in DSP words */
+	pos = sizeof(adsp2_id) / sizeof(u32);
+	len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32);
+
+	adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
+	if (IS_ERR(adsp2_alg))
+		return PTR_ERR(adsp2_alg);
+
+	for (i = 0; i < n_algs; i++) {
+		adsp_info(dsp,
+			  "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
+			  i, be32_to_cpu(adsp2_alg[i].alg.id),
+			  (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
+			  (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
+			  be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
+			  be32_to_cpu(adsp2_alg[i].xm),
+			  be32_to_cpu(adsp2_alg[i].ym),
+			  be32_to_cpu(adsp2_alg[i].zm));
+
+		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
+						   adsp2_alg[i].alg.id,
+						   adsp2_alg[i].xm);
+		if (IS_ERR(alg_region)) {
+			ret = PTR_ERR(alg_region);
+			goto out;
+		}
+		if (dsp->fw_ver == 0) {
+			if (i + 1 < n_algs) {
+				len = be32_to_cpu(adsp2_alg[i + 1].xm);
+				len -= be32_to_cpu(adsp2_alg[i].xm);
+				len *= 4;
+				wm_adsp_create_control(dsp, alg_region, 0,
+						     len, NULL, 0, 0,
+						     SNDRV_CTL_ELEM_TYPE_BYTES);
+			} else {
+				adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
+					  be32_to_cpu(adsp2_alg[i].alg.id));
+			}
+		}
+
+		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
+						   adsp2_alg[i].alg.id,
+						   adsp2_alg[i].ym);
+		if (IS_ERR(alg_region)) {
+			ret = PTR_ERR(alg_region);
+			goto out;
+		}
+		if (dsp->fw_ver == 0) {
+			if (i + 1 < n_algs) {
+				len = be32_to_cpu(adsp2_alg[i + 1].ym);
+				len -= be32_to_cpu(adsp2_alg[i].ym);
+				len *= 4;
+				wm_adsp_create_control(dsp, alg_region, 0,
+						     len, NULL, 0, 0,
+						     SNDRV_CTL_ELEM_TYPE_BYTES);
+			} else {
+				adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
+					  be32_to_cpu(adsp2_alg[i].alg.id));
+			}
+		}
+
+		alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
+						   adsp2_alg[i].alg.id,
+						   adsp2_alg[i].zm);
+		if (IS_ERR(alg_region)) {
+			ret = PTR_ERR(alg_region);
+			goto out;
+		}
+		if (dsp->fw_ver == 0) {
+			if (i + 1 < n_algs) {
+				len = be32_to_cpu(adsp2_alg[i + 1].zm);
+				len -= be32_to_cpu(adsp2_alg[i].zm);
+				len *= 4;
+				wm_adsp_create_control(dsp, alg_region, 0,
+						     len, NULL, 0, 0,
+						     SNDRV_CTL_ELEM_TYPE_BYTES);
+			} else {
+				adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
+					  be32_to_cpu(adsp2_alg[i].alg.id));
+			}
+		}
+	}
+
+out:
+	kfree(adsp2_alg);
+	return ret;
+}
+
+static int wm_adsp_load_coeff(struct wm_adsp *dsp)
+{
+	LIST_HEAD(buf_list);
+	struct regmap *regmap = dsp->regmap;
+	struct wmfw_coeff_hdr *hdr;
+	struct wmfw_coeff_item *blk;
+	const struct firmware *firmware;
+	const struct wm_adsp_region *mem;
+	struct wm_adsp_alg_region *alg_region;
+	const char *region_name;
+	int ret, pos, blocks, type, offset, reg;
+	char *file;
+	struct wm_adsp_buf *buf;
+
+	file = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (file == NULL)
+		return -ENOMEM;
+
+	snprintf(file, PAGE_SIZE, "%s-%s-%s.bin", dsp->part, dsp->fwf_name,
+		 wm_adsp_fw[dsp->fw].file);
+	file[PAGE_SIZE - 1] = '\0';
+
+	ret = request_firmware(&firmware, file, dsp->dev);
+	if (ret != 0) {
+		adsp_warn(dsp, "Failed to request '%s'\n", file);
+		ret = 0;
+		goto out;
+	}
+	ret = -EINVAL;
+
+	if (sizeof(*hdr) >= firmware->size) {
+		adsp_err(dsp, "%s: file too short, %zu bytes\n",
+			file, firmware->size);
+		goto out_fw;
+	}
+
+	hdr = (void *)&firmware->data[0];
+	if (memcmp(hdr->magic, "WMDR", 4) != 0) {
+		adsp_err(dsp, "%s: invalid magic\n", file);
+		goto out_fw;
+	}
+
+	switch (be32_to_cpu(hdr->rev) & 0xff) {
+	case 1:
+		break;
+	default:
+		adsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
+			 file, be32_to_cpu(hdr->rev) & 0xff);
+		ret = -EINVAL;
+		goto out_fw;
+	}
+
+	adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
+		(le32_to_cpu(hdr->ver) >> 16) & 0xff,
+		(le32_to_cpu(hdr->ver) >>  8) & 0xff,
+		le32_to_cpu(hdr->ver) & 0xff);
+
+	pos = le32_to_cpu(hdr->len);
+
+	blocks = 0;
+	while (pos < firmware->size &&
+	       sizeof(*blk) < firmware->size - pos) {
+		blk = (void *)(&firmware->data[pos]);
+
+		type = le16_to_cpu(blk->type);
+		offset = le16_to_cpu(blk->offset);
+
+		adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
+			 file, blocks, le32_to_cpu(blk->id),
+			 (le32_to_cpu(blk->ver) >> 16) & 0xff,
+			 (le32_to_cpu(blk->ver) >>  8) & 0xff,
+			 le32_to_cpu(blk->ver) & 0xff);
+		adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
+			 file, blocks, le32_to_cpu(blk->len), offset, type);
+
+		reg = 0;
+		region_name = "Unknown";
+		switch (type) {
+		case (WMFW_NAME_TEXT << 8):
+		case (WMFW_INFO_TEXT << 8):
+			break;
+		case (WMFW_ABSOLUTE << 8):
+			/*
+			 * Old files may use this for global
+			 * coefficients.
+			 */
+			if (le32_to_cpu(blk->id) == dsp->fw_id &&
+			    offset == 0) {
+				region_name = "global coefficients";
+				mem = wm_adsp_find_region(dsp, type);
+				if (!mem) {
+					adsp_err(dsp, "No ZM\n");
+					break;
+				}
+				reg = wm_adsp_region_to_reg(mem, 0);
+
+			} else {
+				region_name = "register";
+				reg = offset;
+			}
+			break;
+
+		case WMFW_ADSP1_DM:
+		case WMFW_ADSP1_ZM:
+		case WMFW_ADSP2_XM:
+		case WMFW_ADSP2_YM:
+			adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
+				 file, blocks, le32_to_cpu(blk->len),
+				 type, le32_to_cpu(blk->id));
+
+			mem = wm_adsp_find_region(dsp, type);
+			if (!mem) {
+				adsp_err(dsp, "No base for region %x\n", type);
+				break;
+			}
+
+			alg_region = wm_adsp_find_alg_region(dsp, type,
+						le32_to_cpu(blk->id));
+			if (alg_region) {
+				reg = alg_region->base;
+				reg = wm_adsp_region_to_reg(mem, reg);
+				reg += offset;
+			} else {
+				adsp_err(dsp, "No %x for algorithm %x\n",
+					 type, le32_to_cpu(blk->id));
+			}
+			break;
+
+		default:
+			adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
+				 file, blocks, type, pos);
+			break;
+		}
+
+		if (reg) {
+			if (le32_to_cpu(blk->len) >
+			    firmware->size - pos - sizeof(*blk)) {
+				adsp_err(dsp,
+					 "%s.%d: %s region len %d bytes exceeds file length %zu\n",
+					 file, blocks, region_name,
+					 le32_to_cpu(blk->len),
+					 firmware->size);
+				ret = -EINVAL;
+				goto out_fw;
+			}
+
+			buf = wm_adsp_buf_alloc(blk->data,
+						le32_to_cpu(blk->len),
+						&buf_list);
+			if (!buf) {
+				adsp_err(dsp, "Out of memory\n");
+				ret = -ENOMEM;
+				goto out_fw;
+			}
+
+			adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
+				 file, blocks, le32_to_cpu(blk->len),
+				 reg);
+			ret = regmap_raw_write_async(regmap, reg, buf->buf,
+						     le32_to_cpu(blk->len));
+			if (ret != 0) {
+				adsp_err(dsp,
+					"%s.%d: Failed to write to %x in %s: %d\n",
+					file, blocks, reg, region_name, ret);
+			}
+		}
+
+		pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03;
+		blocks++;
+	}
+
+	ret = regmap_async_complete(regmap);
+	if (ret != 0)
+		adsp_err(dsp, "Failed to complete async write: %d\n", ret);
+
+	if (pos > firmware->size)
+		adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
+			  file, blocks, pos - firmware->size);
+
+	wm_adsp_debugfs_save_binname(dsp, file);
+
+out_fw:
+	regmap_async_complete(regmap);
+	release_firmware(firmware);
+	wm_adsp_buf_free(&buf_list);
+out:
+	kfree(file);
+	return ret;
+}
+
+static int wm_adsp_create_name(struct wm_adsp *dsp)
+{
+	char *p;
+
+	if (!dsp->name) {
+		dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d",
+					   dsp->num);
+		if (!dsp->name)
+			return -ENOMEM;
+	}
+
+	if (!dsp->fwf_name) {
+		p = devm_kstrdup(dsp->dev, dsp->name, GFP_KERNEL);
+		if (!p)
+			return -ENOMEM;
+
+		dsp->fwf_name = p;
+		for (; *p != 0; ++p)
+			*p = tolower(*p);
+	}
+
+	return 0;
+}
+
+int wm_adsp1_init(struct wm_adsp *dsp)
+{
+	int ret;
+
+	ret = wm_adsp_create_name(dsp);
+	if (ret)
+		return ret;
+
+	INIT_LIST_HEAD(&dsp->alg_regions);
+
+	mutex_init(&dsp->pwr_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp1_init);
+
+int wm_adsp1_event(struct snd_soc_dapm_widget *w,
+		   struct snd_kcontrol *kcontrol,
+		   int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
+	struct wm_adsp *dsp = &dsps[w->shift];
+	struct wm_coeff_ctl *ctl;
+	int ret;
+	unsigned int val;
+
+	dsp->component = component;
+
+	mutex_lock(&dsp->pwr_lock);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
+				   ADSP1_SYS_ENA, ADSP1_SYS_ENA);
+
+		/*
+		 * For simplicity set the DSP clock rate to be the
+		 * SYSCLK rate rather than making it configurable.
+		 */
+		if (dsp->sysclk_reg) {
+			ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
+			if (ret != 0) {
+				adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
+				ret);
+				goto err_mutex;
+			}
+
+			val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift;
+
+			ret = regmap_update_bits(dsp->regmap,
+						 dsp->base + ADSP1_CONTROL_31,
+						 ADSP1_CLK_SEL_MASK, val);
+			if (ret != 0) {
+				adsp_err(dsp, "Failed to set clock rate: %d\n",
+					 ret);
+				goto err_mutex;
+			}
+		}
+
+		ret = wm_adsp_load(dsp);
+		if (ret != 0)
+			goto err_ena;
+
+		ret = wm_adsp1_setup_algs(dsp);
+		if (ret != 0)
+			goto err_ena;
+
+		ret = wm_adsp_load_coeff(dsp);
+		if (ret != 0)
+			goto err_ena;
+
+		/* Initialize caches for enabled and unset controls */
+		ret = wm_coeff_init_control_caches(dsp);
+		if (ret != 0)
+			goto err_ena;
+
+		/* Sync set controls */
+		ret = wm_coeff_sync_controls(dsp);
+		if (ret != 0)
+			goto err_ena;
+
+		dsp->booted = true;
+
+		/* Start the core running */
+		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
+				   ADSP1_CORE_ENA | ADSP1_START,
+				   ADSP1_CORE_ENA | ADSP1_START);
+
+		dsp->running = true;
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		dsp->running = false;
+		dsp->booted = false;
+
+		/* Halt the core */
+		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
+				   ADSP1_CORE_ENA | ADSP1_START, 0);
+
+		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
+				   ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
+
+		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
+				   ADSP1_SYS_ENA, 0);
+
+		list_for_each_entry(ctl, &dsp->ctl_list, list)
+			ctl->enabled = 0;
+
+
+		wm_adsp_free_alg_regions(dsp);
+		break;
+
+	default:
+		break;
+	}
+
+	mutex_unlock(&dsp->pwr_lock);
+
+	return 0;
+
+err_ena:
+	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
+			   ADSP1_SYS_ENA, 0);
+err_mutex:
+	mutex_unlock(&dsp->pwr_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp1_event);
+
+static int wm_adsp2_ena(struct wm_adsp *dsp)
+{
+	unsigned int val;
+	int ret, count;
+
+	switch (dsp->rev) {
+	case 0:
+		ret = regmap_update_bits_async(dsp->regmap,
+					       dsp->base + ADSP2_CONTROL,
+					       ADSP2_SYS_ENA, ADSP2_SYS_ENA);
+		if (ret != 0)
+			return ret;
+		break;
+	default:
+		break;
+	}
+
+	/* Wait for the RAM to start, should be near instantaneous */
+	for (count = 0; count < 10; ++count) {
+		ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
+		if (ret != 0)
+			return ret;
+
+		if (val & ADSP2_RAM_RDY)
+			break;
+
+		usleep_range(250, 500);
+	}
+
+	if (!(val & ADSP2_RAM_RDY)) {
+		adsp_err(dsp, "Failed to start DSP RAM\n");
+		return -EBUSY;
+	}
+
+	adsp_dbg(dsp, "RAM ready after %d polls\n", count);
+
+	return 0;
+}
+
+static void wm_adsp2_boot_work(struct work_struct *work)
+{
+	struct wm_adsp *dsp = container_of(work,
+					   struct wm_adsp,
+					   boot_work);
+	int ret;
+
+	mutex_lock(&dsp->pwr_lock);
+
+	ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+				 ADSP2_MEM_ENA, ADSP2_MEM_ENA);
+	if (ret != 0)
+		goto err_mutex;
+
+	ret = wm_adsp2_ena(dsp);
+	if (ret != 0)
+		goto err_mem;
+
+	ret = wm_adsp_load(dsp);
+	if (ret != 0)
+		goto err_ena;
+
+	ret = wm_adsp2_setup_algs(dsp);
+	if (ret != 0)
+		goto err_ena;
+
+	ret = wm_adsp_load_coeff(dsp);
+	if (ret != 0)
+		goto err_ena;
+
+	/* Initialize caches for enabled and unset controls */
+	ret = wm_coeff_init_control_caches(dsp);
+	if (ret != 0)
+		goto err_ena;
+
+	switch (dsp->rev) {
+	case 0:
+		/* Turn DSP back off until we are ready to run */
+		ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+					 ADSP2_SYS_ENA, 0);
+		if (ret != 0)
+			goto err_ena;
+		break;
+	default:
+		break;
+	}
+
+	dsp->booted = true;
+
+	mutex_unlock(&dsp->pwr_lock);
+
+	return;
+
+err_ena:
+	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+			   ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
+err_mem:
+	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+			   ADSP2_MEM_ENA, 0);
+err_mutex:
+	mutex_unlock(&dsp->pwr_lock);
+}
+
+static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq)
+{
+	int ret;
+
+	switch (dsp->rev) {
+	case 0:
+		ret = regmap_update_bits_async(dsp->regmap,
+					       dsp->base + ADSP2_CLOCKING,
+					       ADSP2_CLK_SEL_MASK,
+					       freq << ADSP2_CLK_SEL_SHIFT);
+		if (ret) {
+			adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
+			return;
+		}
+		break;
+	default:
+		/* clock is handled by parent codec driver */
+		break;
+	}
+}
+
+int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct wm_adsp *dsp = &dsps[mc->shift - 1];
+
+	ucontrol->value.integer.value[0] = dsp->preloaded;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get);
+
+int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct wm_adsp *dsp = &dsps[mc->shift - 1];
+	char preload[32];
+
+	snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
+
+	dsp->preloaded = ucontrol->value.integer.value[0];
+
+	if (ucontrol->value.integer.value[0])
+		snd_soc_component_force_enable_pin(component, preload);
+	else
+		snd_soc_component_disable_pin(component, preload);
+
+	snd_soc_dapm_sync(dapm);
+
+	flush_work(&dsp->boot_work);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
+
+static void wm_adsp_stop_watchdog(struct wm_adsp *dsp)
+{
+	switch (dsp->rev) {
+	case 0:
+	case 1:
+		return;
+	default:
+		regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
+				   ADSP2_WDT_ENA_MASK, 0);
+	}
+}
+
+int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event,
+			 unsigned int freq)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
+	struct wm_adsp *dsp = &dsps[w->shift];
+	struct wm_coeff_ctl *ctl;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wm_adsp2_set_dspclk(dsp, freq);
+		queue_work(system_unbound_wq, &dsp->boot_work);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		mutex_lock(&dsp->pwr_lock);
+
+		wm_adsp_debugfs_clear(dsp);
+
+		dsp->fw_id = 0;
+		dsp->fw_id_version = 0;
+
+		dsp->booted = false;
+
+		regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+				   ADSP2_MEM_ENA, 0);
+
+		list_for_each_entry(ctl, &dsp->ctl_list, list)
+			ctl->enabled = 0;
+
+		wm_adsp_free_alg_regions(dsp);
+
+		mutex_unlock(&dsp->pwr_lock);
+
+		adsp_dbg(dsp, "Shutdown complete\n");
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
+
+int wm_adsp2_event(struct snd_soc_dapm_widget *w,
+		   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
+	struct wm_adsp *dsp = &dsps[w->shift];
+	int ret;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		flush_work(&dsp->boot_work);
+
+		mutex_lock(&dsp->pwr_lock);
+
+		if (!dsp->booted) {
+			ret = -EIO;
+			goto err;
+		}
+
+		ret = wm_adsp2_ena(dsp);
+		if (ret != 0)
+			goto err;
+
+		/* Sync set controls */
+		ret = wm_coeff_sync_controls(dsp);
+		if (ret != 0)
+			goto err;
+
+		wm_adsp2_lock(dsp, dsp->lock_regions);
+
+		ret = regmap_update_bits(dsp->regmap,
+					 dsp->base + ADSP2_CONTROL,
+					 ADSP2_CORE_ENA | ADSP2_START,
+					 ADSP2_CORE_ENA | ADSP2_START);
+		if (ret != 0)
+			goto err;
+
+		if (wm_adsp_fw[dsp->fw].num_caps != 0) {
+			ret = wm_adsp_buffer_init(dsp);
+			if (ret < 0)
+				goto err;
+		}
+
+		dsp->running = true;
+
+		mutex_unlock(&dsp->pwr_lock);
+
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Tell the firmware to cleanup */
+		wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN);
+
+		wm_adsp_stop_watchdog(dsp);
+
+		/* Log firmware state, it can be useful for analysis */
+		switch (dsp->rev) {
+		case 0:
+			wm_adsp2_show_fw_status(dsp);
+			break;
+		default:
+			wm_adsp2v2_show_fw_status(dsp);
+			break;
+		}
+
+		mutex_lock(&dsp->pwr_lock);
+
+		dsp->running = false;
+
+		regmap_update_bits(dsp->regmap,
+				   dsp->base + ADSP2_CONTROL,
+				   ADSP2_CORE_ENA | ADSP2_START, 0);
+
+		/* Make sure DMAs are quiesced */
+		switch (dsp->rev) {
+		case 0:
+			regmap_write(dsp->regmap,
+				     dsp->base + ADSP2_RDMA_CONFIG_1, 0);
+			regmap_write(dsp->regmap,
+				     dsp->base + ADSP2_WDMA_CONFIG_1, 0);
+			regmap_write(dsp->regmap,
+				     dsp->base + ADSP2_WDMA_CONFIG_2, 0);
+
+			regmap_update_bits(dsp->regmap,
+					   dsp->base + ADSP2_CONTROL,
+					   ADSP2_SYS_ENA, 0);
+			break;
+		default:
+			regmap_write(dsp->regmap,
+				     dsp->base + ADSP2_RDMA_CONFIG_1, 0);
+			regmap_write(dsp->regmap,
+				     dsp->base + ADSP2_WDMA_CONFIG_1, 0);
+			regmap_write(dsp->regmap,
+				     dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
+			break;
+		}
+
+		if (wm_adsp_fw[dsp->fw].num_caps != 0)
+			wm_adsp_buffer_free(dsp);
+
+		mutex_unlock(&dsp->pwr_lock);
+
+		adsp_dbg(dsp, "Execution stopped\n");
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+err:
+	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+			   ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
+	mutex_unlock(&dsp->pwr_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_event);
+
+int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
+{
+	char preload[32];
+
+	snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
+	snd_soc_component_disable_pin(component, preload);
+
+	wm_adsp2_init_debugfs(dsp, component);
+
+	dsp->component = component;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_component_probe);
+
+int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component)
+{
+	wm_adsp2_cleanup_debugfs(dsp);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_component_remove);
+
+int wm_adsp2_init(struct wm_adsp *dsp)
+{
+	int ret;
+
+	ret = wm_adsp_create_name(dsp);
+	if (ret)
+		return ret;
+
+	switch (dsp->rev) {
+	case 0:
+		/*
+		 * Disable the DSP memory by default when in reset for a small
+		 * power saving.
+		 */
+		ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+					 ADSP2_MEM_ENA, 0);
+		if (ret) {
+			adsp_err(dsp,
+				 "Failed to clear memory retention: %d\n", ret);
+			return ret;
+		}
+		break;
+	default:
+		break;
+	}
+
+	INIT_LIST_HEAD(&dsp->alg_regions);
+	INIT_LIST_HEAD(&dsp->ctl_list);
+	INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
+
+	mutex_init(&dsp->pwr_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_init);
+
+void wm_adsp2_remove(struct wm_adsp *dsp)
+{
+	struct wm_coeff_ctl *ctl;
+
+	while (!list_empty(&dsp->ctl_list)) {
+		ctl = list_first_entry(&dsp->ctl_list, struct wm_coeff_ctl,
+					list);
+		list_del(&ctl->list);
+		wm_adsp_free_ctl_blk(ctl);
+	}
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_remove);
+
+static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
+{
+	return compr->buf != NULL;
+}
+
+static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
+{
+	/*
+	 * Note this will be more complex once each DSP can support multiple
+	 * streams
+	 */
+	if (!compr->dsp->buffer)
+		return -EINVAL;
+
+	compr->buf = compr->dsp->buffer;
+	compr->buf->compr = compr;
+
+	return 0;
+}
+
+static void wm_adsp_compr_detach(struct wm_adsp_compr *compr)
+{
+	if (!compr)
+		return;
+
+	/* Wake the poll so it can see buffer is no longer attached */
+	if (compr->stream)
+		snd_compr_fragment_elapsed(compr->stream);
+
+	if (wm_adsp_compr_attached(compr)) {
+		compr->buf->compr = NULL;
+		compr->buf = NULL;
+	}
+}
+
+int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
+{
+	struct wm_adsp_compr *compr;
+	int ret = 0;
+
+	mutex_lock(&dsp->pwr_lock);
+
+	if (wm_adsp_fw[dsp->fw].num_caps == 0) {
+		adsp_err(dsp, "Firmware does not support compressed API\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
+		adsp_err(dsp, "Firmware does not support stream direction\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (dsp->compr) {
+		/* It is expect this limitation will be removed in future */
+		adsp_err(dsp, "Only a single stream supported per DSP\n");
+		ret = -EBUSY;
+		goto out;
+	}
+
+	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
+	if (!compr) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	compr->dsp = dsp;
+	compr->stream = stream;
+
+	dsp->compr = compr;
+
+	stream->runtime->private_data = compr;
+
+out:
+	mutex_unlock(&dsp->pwr_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_open);
+
+int wm_adsp_compr_free(struct snd_compr_stream *stream)
+{
+	struct wm_adsp_compr *compr = stream->runtime->private_data;
+	struct wm_adsp *dsp = compr->dsp;
+
+	mutex_lock(&dsp->pwr_lock);
+
+	wm_adsp_compr_detach(compr);
+	dsp->compr = NULL;
+
+	kfree(compr->raw_buf);
+	kfree(compr);
+
+	mutex_unlock(&dsp->pwr_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_free);
+
+static int wm_adsp_compr_check_params(struct snd_compr_stream *stream,
+				      struct snd_compr_params *params)
+{
+	struct wm_adsp_compr *compr = stream->runtime->private_data;
+	struct wm_adsp *dsp = compr->dsp;
+	const struct wm_adsp_fw_caps *caps;
+	const struct snd_codec_desc *desc;
+	int i, j;
+
+	if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE ||
+	    params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE ||
+	    params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS ||
+	    params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS ||
+	    params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) {
+		adsp_err(dsp, "Invalid buffer fragsize=%d fragments=%d\n",
+			 params->buffer.fragment_size,
+			 params->buffer.fragments);
+
+		return -EINVAL;
+	}
+
+	for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) {
+		caps = &wm_adsp_fw[dsp->fw].caps[i];
+		desc = &caps->desc;
+
+		if (caps->id != params->codec.id)
+			continue;
+
+		if (stream->direction == SND_COMPRESS_PLAYBACK) {
+			if (desc->max_ch < params->codec.ch_out)
+				continue;
+		} else {
+			if (desc->max_ch < params->codec.ch_in)
+				continue;
+		}
+
+		if (!(desc->formats & (1 << params->codec.format)))
+			continue;
+
+		for (j = 0; j < desc->num_sample_rates; ++j)
+			if (desc->sample_rates[j] == params->codec.sample_rate)
+				return 0;
+	}
+
+	adsp_err(dsp, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
+		 params->codec.id, params->codec.ch_in, params->codec.ch_out,
+		 params->codec.sample_rate, params->codec.format);
+	return -EINVAL;
+}
+
+static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr)
+{
+	return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE;
+}
+
+int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
+			     struct snd_compr_params *params)
+{
+	struct wm_adsp_compr *compr = stream->runtime->private_data;
+	unsigned int size;
+	int ret;
+
+	ret = wm_adsp_compr_check_params(stream, params);
+	if (ret)
+		return ret;
+
+	compr->size = params->buffer;
+
+	adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n",
+		 compr->size.fragment_size, compr->size.fragments);
+
+	size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf);
+	compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL);
+	if (!compr->raw_buf)
+		return -ENOMEM;
+
+	compr->sample_rate = params->codec.sample_rate;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
+
+int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
+			   struct snd_compr_caps *caps)
+{
+	struct wm_adsp_compr *compr = stream->runtime->private_data;
+	int fw = compr->dsp->fw;
+	int i;
+
+	if (wm_adsp_fw[fw].caps) {
+		for (i = 0; i < wm_adsp_fw[fw].num_caps; i++)
+			caps->codecs[i] = wm_adsp_fw[fw].caps[i].id;
+
+		caps->num_codecs = i;
+		caps->direction = wm_adsp_fw[fw].compr_direction;
+
+		caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE;
+		caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE;
+		caps->min_fragments = WM_ADSP_MIN_FRAGMENTS;
+		caps->max_fragments = WM_ADSP_MAX_FRAGMENTS;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps);
+
+static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type,
+				   unsigned int mem_addr,
+				   unsigned int num_words, u32 *data)
+{
+	struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
+	unsigned int i, reg;
+	int ret;
+
+	if (!mem)
+		return -EINVAL;
+
+	reg = wm_adsp_region_to_reg(mem, mem_addr);
+
+	ret = regmap_raw_read(dsp->regmap, reg, data,
+			      sizeof(*data) * num_words);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < num_words; ++i)
+		data[i] = be32_to_cpu(data[i]) & 0x00ffffffu;
+
+	return 0;
+}
+
+static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type,
+					 unsigned int mem_addr, u32 *data)
+{
+	return wm_adsp_read_data_block(dsp, mem_type, mem_addr, 1, data);
+}
+
+static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type,
+				   unsigned int mem_addr, u32 data)
+{
+	struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
+	unsigned int reg;
+
+	if (!mem)
+		return -EINVAL;
+
+	reg = wm_adsp_region_to_reg(mem, mem_addr);
+
+	data = cpu_to_be32(data & 0x00ffffffu);
+
+	return regmap_raw_write(dsp->regmap, reg, &data, sizeof(data));
+}
+
+static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
+				      unsigned int field_offset, u32 *data)
+{
+	return wm_adsp_read_data_word(buf->dsp, WMFW_ADSP2_XM,
+				      buf->host_buf_ptr + field_offset, data);
+}
+
+static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
+				       unsigned int field_offset, u32 data)
+{
+	return wm_adsp_write_data_word(buf->dsp, WMFW_ADSP2_XM,
+				       buf->host_buf_ptr + field_offset, data);
+}
+
+static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf)
+{
+	struct wm_adsp_alg_region *alg_region;
+	struct wm_adsp *dsp = buf->dsp;
+	u32 xmalg, addr, magic;
+	int i, ret;
+
+	alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
+	xmalg = sizeof(struct wm_adsp_system_config_xm_hdr) / sizeof(__be32);
+
+	addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
+	ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic);
+	if (ret < 0)
+		return ret;
+
+	if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC)
+		return -EINVAL;
+
+	addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr);
+	for (i = 0; i < 5; ++i) {
+		ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr,
+					     &buf->host_buf_ptr);
+		if (ret < 0)
+			return ret;
+
+		if (buf->host_buf_ptr)
+			break;
+
+		usleep_range(1000, 2000);
+	}
+
+	if (!buf->host_buf_ptr)
+		return -EIO;
+
+	adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr);
+
+	return 0;
+}
+
+static struct wm_coeff_ctl *
+wm_adsp_find_host_buffer_ctrl(struct wm_adsp_compr_buf *buf)
+{
+	struct wm_adsp *dsp = buf->dsp;
+	struct wm_coeff_ctl *ctl;
+
+	list_for_each_entry(ctl, &dsp->ctl_list, list) {
+		if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
+			continue;
+
+		if (!ctl->enabled)
+			continue;
+
+		return ctl;
+	}
+
+	return NULL;
+}
+
+static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
+{
+	struct wm_adsp *dsp = buf->dsp;
+	struct wm_coeff_ctl *ctl;
+	unsigned int reg;
+	u32 val;
+	int i, ret;
+
+	ctl = wm_adsp_find_host_buffer_ctrl(buf);
+	if (!ctl)
+		return wm_adsp_legacy_host_buf_addr(buf);
+
+	ret = wm_coeff_base_reg(ctl, &reg);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < 5; ++i) {
+		ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
+		if (ret < 0)
+			return ret;
+
+		if (val)
+			break;
+
+		usleep_range(1000, 2000);
+	}
+
+	if (!val)
+		return -EIO;
+
+	buf->host_buf_ptr = be32_to_cpu(val);
+	adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr);
+
+	return 0;
+}
+
+static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
+{
+	const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
+	struct wm_adsp_buffer_region *region;
+	u32 offset = 0;
+	int i, ret;
+
+	for (i = 0; i < caps->num_regions; ++i) {
+		region = &buf->regions[i];
+
+		region->offset = offset;
+		region->mem_type = caps->region_defs[i].mem_type;
+
+		ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset,
+					  &region->base_addr);
+		if (ret < 0)
+			return ret;
+
+		ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset,
+					  &offset);
+		if (ret < 0)
+			return ret;
+
+		region->cumulative_size = offset;
+
+		adsp_dbg(buf->dsp,
+			 "region=%d type=%d base=%04x off=%04x size=%04x\n",
+			 i, region->mem_type, region->base_addr,
+			 region->offset, region->cumulative_size);
+	}
+
+	return 0;
+}
+
+static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf)
+{
+	buf->irq_count = 0xFFFFFFFF;
+	buf->read_index = -1;
+	buf->avail = 0;
+}
+
+static int wm_adsp_buffer_init(struct wm_adsp *dsp)
+{
+	struct wm_adsp_compr_buf *buf;
+	int ret;
+
+	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	buf->dsp = dsp;
+
+	wm_adsp_buffer_clear(buf);
+
+	ret = wm_adsp_buffer_locate(buf);
+	if (ret < 0) {
+		adsp_err(dsp, "Failed to acquire host buffer: %d\n", ret);
+		goto err_buffer;
+	}
+
+	buf->regions = kcalloc(wm_adsp_fw[dsp->fw].caps->num_regions,
+			       sizeof(*buf->regions), GFP_KERNEL);
+	if (!buf->regions) {
+		ret = -ENOMEM;
+		goto err_buffer;
+	}
+
+	ret = wm_adsp_buffer_populate(buf);
+	if (ret < 0) {
+		adsp_err(dsp, "Failed to populate host buffer: %d\n", ret);
+		goto err_regions;
+	}
+
+	dsp->buffer = buf;
+
+	return 0;
+
+err_regions:
+	kfree(buf->regions);
+err_buffer:
+	kfree(buf);
+	return ret;
+}
+
+static int wm_adsp_buffer_free(struct wm_adsp *dsp)
+{
+	if (dsp->buffer) {
+		wm_adsp_compr_detach(dsp->buffer->compr);
+
+		kfree(dsp->buffer->regions);
+		kfree(dsp->buffer);
+
+		dsp->buffer = NULL;
+	}
+
+	return 0;
+}
+
+int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd)
+{
+	struct wm_adsp_compr *compr = stream->runtime->private_data;
+	struct wm_adsp *dsp = compr->dsp;
+	int ret = 0;
+
+	adsp_dbg(dsp, "Trigger: %d\n", cmd);
+
+	mutex_lock(&dsp->pwr_lock);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (!wm_adsp_compr_attached(compr)) {
+			ret = wm_adsp_compr_attach(compr);
+			if (ret < 0) {
+				adsp_err(dsp, "Failed to link buffer and stream: %d\n",
+					 ret);
+				break;
+			}
+		}
+
+		wm_adsp_buffer_clear(compr->buf);
+
+		/* Trigger the IRQ at one fragment of data */
+		ret = wm_adsp_buffer_write(compr->buf,
+					   HOST_BUFFER_FIELD(high_water_mark),
+					   wm_adsp_compr_frag_words(compr));
+		if (ret < 0) {
+			adsp_err(dsp, "Failed to set high water mark: %d\n",
+				 ret);
+			break;
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&dsp->pwr_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger);
+
+static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf)
+{
+	int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1;
+
+	return buf->regions[last_region].cumulative_size;
+}
+
+static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
+{
+	u32 next_read_index, next_write_index;
+	int write_index, read_index, avail;
+	int ret;
+
+	/* Only sync read index if we haven't already read a valid index */
+	if (buf->read_index < 0) {
+		ret = wm_adsp_buffer_read(buf,
+				HOST_BUFFER_FIELD(next_read_index),
+				&next_read_index);
+		if (ret < 0)
+			return ret;
+
+		read_index = sign_extend32(next_read_index, 23);
+
+		if (read_index < 0) {
+			adsp_dbg(buf->dsp, "Avail check on unstarted stream\n");
+			return 0;
+		}
+
+		buf->read_index = read_index;
+	}
+
+	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index),
+			&next_write_index);
+	if (ret < 0)
+		return ret;
+
+	write_index = sign_extend32(next_write_index, 23);
+
+	avail = write_index - buf->read_index;
+	if (avail < 0)
+		avail += wm_adsp_buffer_size(buf);
+
+	adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
+		 buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE);
+
+	buf->avail = avail;
+
+	return 0;
+}
+
+static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf)
+{
+	int ret;
+
+	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
+	if (ret < 0) {
+		adsp_err(buf->dsp, "Failed to check buffer error: %d\n", ret);
+		return ret;
+	}
+	if (buf->error != 0) {
+		adsp_err(buf->dsp, "Buffer error occurred: %d\n", buf->error);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
+{
+	struct wm_adsp_compr_buf *buf;
+	struct wm_adsp_compr *compr;
+	int ret = 0;
+
+	mutex_lock(&dsp->pwr_lock);
+
+	buf = dsp->buffer;
+	compr = dsp->compr;
+
+	if (!buf) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	adsp_dbg(dsp, "Handling buffer IRQ\n");
+
+	ret = wm_adsp_buffer_get_error(buf);
+	if (ret < 0)
+		goto out_notify; /* Wake poll to report error */
+
+	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
+				  &buf->irq_count);
+	if (ret < 0) {
+		adsp_err(dsp, "Failed to get irq_count: %d\n", ret);
+		goto out;
+	}
+
+	ret = wm_adsp_buffer_update_avail(buf);
+	if (ret < 0) {
+		adsp_err(dsp, "Error reading avail: %d\n", ret);
+		goto out;
+	}
+
+	if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2)
+		ret = WM_ADSP_COMPR_VOICE_TRIGGER;
+
+out_notify:
+	if (compr && compr->stream)
+		snd_compr_fragment_elapsed(compr->stream);
+
+out:
+	mutex_unlock(&dsp->pwr_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq);
+
+static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
+{
+	if (buf->irq_count & 0x01)
+		return 0;
+
+	adsp_dbg(buf->dsp, "Enable IRQ(0x%x) for next fragment\n",
+		 buf->irq_count);
+
+	buf->irq_count |= 0x01;
+
+	return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack),
+				    buf->irq_count);
+}
+
+int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
+			  struct snd_compr_tstamp *tstamp)
+{
+	struct wm_adsp_compr *compr = stream->runtime->private_data;
+	struct wm_adsp *dsp = compr->dsp;
+	struct wm_adsp_compr_buf *buf;
+	int ret = 0;
+
+	adsp_dbg(dsp, "Pointer request\n");
+
+	mutex_lock(&dsp->pwr_lock);
+
+	buf = compr->buf;
+
+	if (!compr->buf || compr->buf->error) {
+		snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
+		ret = -EIO;
+		goto out;
+	}
+
+	if (buf->avail < wm_adsp_compr_frag_words(compr)) {
+		ret = wm_adsp_buffer_update_avail(buf);
+		if (ret < 0) {
+			adsp_err(dsp, "Error reading avail: %d\n", ret);
+			goto out;
+		}
+
+		/*
+		 * If we really have less than 1 fragment available tell the
+		 * DSP to inform us once a whole fragment is available.
+		 */
+		if (buf->avail < wm_adsp_compr_frag_words(compr)) {
+			ret = wm_adsp_buffer_get_error(buf);
+			if (ret < 0) {
+				if (compr->buf->error)
+					snd_compr_stop_error(stream,
+							SNDRV_PCM_STATE_XRUN);
+				goto out;
+			}
+
+			ret = wm_adsp_buffer_reenable_irq(buf);
+			if (ret < 0) {
+				adsp_err(dsp,
+					 "Failed to re-enable buffer IRQ: %d\n",
+					 ret);
+				goto out;
+			}
+		}
+	}
+
+	tstamp->copied_total = compr->copied_total;
+	tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE;
+	tstamp->sampling_rate = compr->sample_rate;
+
+out:
+	mutex_unlock(&dsp->pwr_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
+
+static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
+{
+	struct wm_adsp_compr_buf *buf = compr->buf;
+	u8 *pack_in = (u8 *)compr->raw_buf;
+	u8 *pack_out = (u8 *)compr->raw_buf;
+	unsigned int adsp_addr;
+	int mem_type, nwords, max_read;
+	int i, j, ret;
+
+	/* Calculate read parameters */
+	for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i)
+		if (buf->read_index < buf->regions[i].cumulative_size)
+			break;
+
+	if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions)
+		return -EINVAL;
+
+	mem_type = buf->regions[i].mem_type;
+	adsp_addr = buf->regions[i].base_addr +
+		    (buf->read_index - buf->regions[i].offset);
+
+	max_read = wm_adsp_compr_frag_words(compr);
+	nwords = buf->regions[i].cumulative_size - buf->read_index;
+
+	if (nwords > target)
+		nwords = target;
+	if (nwords > buf->avail)
+		nwords = buf->avail;
+	if (nwords > max_read)
+		nwords = max_read;
+	if (!nwords)
+		return 0;
+
+	/* Read data from DSP */
+	ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr,
+				      nwords, compr->raw_buf);
+	if (ret < 0)
+		return ret;
+
+	/* Remove the padding bytes from the data read from the DSP */
+	for (i = 0; i < nwords; i++) {
+		for (j = 0; j < WM_ADSP_DATA_WORD_SIZE; j++)
+			*pack_out++ = *pack_in++;
+
+		pack_in += sizeof(*(compr->raw_buf)) - WM_ADSP_DATA_WORD_SIZE;
+	}
+
+	/* update read index to account for words read */
+	buf->read_index += nwords;
+	if (buf->read_index == wm_adsp_buffer_size(buf))
+		buf->read_index = 0;
+
+	ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index),
+				   buf->read_index);
+	if (ret < 0)
+		return ret;
+
+	/* update avail to account for words read */
+	buf->avail -= nwords;
+
+	return nwords;
+}
+
+static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
+			      char __user *buf, size_t count)
+{
+	struct wm_adsp *dsp = compr->dsp;
+	int ntotal = 0;
+	int nwords, nbytes;
+
+	adsp_dbg(dsp, "Requested read of %zu bytes\n", count);
+
+	if (!compr->buf || compr->buf->error) {
+		snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN);
+		return -EIO;
+	}
+
+	count /= WM_ADSP_DATA_WORD_SIZE;
+
+	do {
+		nwords = wm_adsp_buffer_capture_block(compr, count);
+		if (nwords < 0) {
+			adsp_err(dsp, "Failed to capture block: %d\n", nwords);
+			return nwords;
+		}
+
+		nbytes = nwords * WM_ADSP_DATA_WORD_SIZE;
+
+		adsp_dbg(dsp, "Read %d bytes\n", nbytes);
+
+		if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) {
+			adsp_err(dsp, "Failed to copy data to user: %d, %d\n",
+				 ntotal, nbytes);
+			return -EFAULT;
+		}
+
+		count -= nwords;
+		ntotal += nbytes;
+	} while (nwords > 0 && count > 0);
+
+	compr->copied_total += ntotal;
+
+	return ntotal;
+}
+
+int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf,
+		       size_t count)
+{
+	struct wm_adsp_compr *compr = stream->runtime->private_data;
+	struct wm_adsp *dsp = compr->dsp;
+	int ret;
+
+	mutex_lock(&dsp->pwr_lock);
+
+	if (stream->direction == SND_COMPRESS_CAPTURE)
+		ret = wm_adsp_compr_read(compr, buf, count);
+	else
+		ret = -ENOTSUPP;
+
+	mutex_unlock(&dsp->pwr_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
+
+int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)
+{
+	struct regmap *regmap = dsp->regmap;
+	unsigned int code0, code1, lock_reg;
+
+	if (!(lock_regions & WM_ADSP2_REGION_ALL))
+		return 0;
+
+	lock_regions &= WM_ADSP2_REGION_ALL;
+	lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0;
+
+	while (lock_regions) {
+		code0 = code1 = 0;
+		if (lock_regions & BIT(0)) {
+			code0 = ADSP2_LOCK_CODE_0;
+			code1 = ADSP2_LOCK_CODE_1;
+		}
+		if (lock_regions & BIT(1)) {
+			code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT;
+			code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT;
+		}
+		regmap_write(regmap, lock_reg, code0);
+		regmap_write(regmap, lock_reg, code1);
+		lock_regions >>= 2;
+		lock_reg += 2;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_lock);
+
+irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp)
+{
+	unsigned int val;
+	struct regmap *regmap = dsp->regmap;
+	int ret = 0;
+
+	ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val);
+	if (ret) {
+		adsp_err(dsp,
+			"Failed to read Region Lock Ctrl register: %d\n", ret);
+		return IRQ_HANDLED;
+	}
+
+	if (val & ADSP2_WDT_TIMEOUT_STS_MASK) {
+		adsp_err(dsp, "watchdog timeout error\n");
+		wm_adsp_stop_watchdog(dsp);
+	}
+
+	if (val & (ADSP2_SLAVE_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) {
+		if (val & ADSP2_SLAVE_ERR_MASK)
+			adsp_err(dsp, "bus error: slave error\n");
+		else
+			adsp_err(dsp, "bus error: region lock error\n");
+
+		ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val);
+		if (ret) {
+			adsp_err(dsp,
+				 "Failed to read Bus Err Addr register: %d\n",
+				 ret);
+			return IRQ_HANDLED;
+		}
+
+		adsp_err(dsp, "bus error address = 0x%x\n",
+			 val & ADSP2_BUS_ERR_ADDR_MASK);
+
+		ret = regmap_read(regmap,
+				  dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR,
+				  &val);
+		if (ret) {
+			adsp_err(dsp,
+				 "Failed to read Pmem Xmem Err Addr register: %d\n",
+				 ret);
+			return IRQ_HANDLED;
+		}
+
+		adsp_err(dsp, "xmem error address = 0x%x\n",
+			 val & ADSP2_XMEM_ERR_ADDR_MASK);
+		adsp_err(dsp, "pmem error address = 0x%x\n",
+			 (val & ADSP2_PMEM_ERR_ADDR_MASK) >>
+			 ADSP2_PMEM_ERR_ADDR_SHIFT);
+	}
+
+	regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL,
+			   ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT);
+
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
+
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
new file mode 100644
index 0000000..4b8778b
--- /dev/null
+++ b/sound/soc/codecs/wm_adsp.h
@@ -0,0 +1,171 @@
+/*
+ * wm_adsp.h  --  Wolfson ADSP support
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __WM_ADSP_H
+#define __WM_ADSP_H
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/compress_driver.h>
+
+#include "wmfw.h"
+
+/* Return values for wm_adsp_compr_handle_irq */
+#define WM_ADSP_COMPR_OK                 0
+#define WM_ADSP_COMPR_VOICE_TRIGGER      1
+
+#define WM_ADSP2_REGION_0 BIT(0)
+#define WM_ADSP2_REGION_1 BIT(1)
+#define WM_ADSP2_REGION_2 BIT(2)
+#define WM_ADSP2_REGION_3 BIT(3)
+#define WM_ADSP2_REGION_4 BIT(4)
+#define WM_ADSP2_REGION_5 BIT(5)
+#define WM_ADSP2_REGION_6 BIT(6)
+#define WM_ADSP2_REGION_7 BIT(7)
+#define WM_ADSP2_REGION_8 BIT(8)
+#define WM_ADSP2_REGION_9 BIT(9)
+#define WM_ADSP2_REGION_1_9 (WM_ADSP2_REGION_1 | \
+		WM_ADSP2_REGION_2 | WM_ADSP2_REGION_3 | \
+		WM_ADSP2_REGION_4 | WM_ADSP2_REGION_5 | \
+		WM_ADSP2_REGION_6 | WM_ADSP2_REGION_7 | \
+		WM_ADSP2_REGION_8 | WM_ADSP2_REGION_9)
+#define WM_ADSP2_REGION_ALL (WM_ADSP2_REGION_0 | WM_ADSP2_REGION_1_9)
+
+struct wm_adsp_region {
+	int type;
+	unsigned int base;
+};
+
+struct wm_adsp_alg_region {
+	struct list_head list;
+	unsigned int alg;
+	int type;
+	unsigned int base;
+};
+
+struct wm_adsp_compr;
+struct wm_adsp_compr_buf;
+
+struct wm_adsp {
+	const char *part;
+	const char *name;
+	const char *fwf_name;
+	int rev;
+	int num;
+	int type;
+	struct device *dev;
+	struct regmap *regmap;
+	struct snd_soc_component *component;
+
+	unsigned int base;
+	unsigned int sysclk_reg;
+	unsigned int sysclk_mask;
+	unsigned int sysclk_shift;
+
+	struct list_head alg_regions;
+
+	unsigned int fw_id;
+	unsigned int fw_id_version;
+
+	const struct wm_adsp_region *mem;
+	int num_mems;
+
+	int fw;
+	int fw_ver;
+
+	bool preloaded;
+	bool booted;
+	bool running;
+
+	struct list_head ctl_list;
+
+	struct work_struct boot_work;
+
+	struct wm_adsp_compr *compr;
+	struct wm_adsp_compr_buf *buffer;
+
+	struct mutex pwr_lock;
+
+	unsigned int lock_regions;
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_root;
+	char *wmfw_file_name;
+	char *bin_file_name;
+#endif
+
+};
+
+#define WM_ADSP1(wname, num) \
+	SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
+		wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
+
+#define WM_ADSP2_PRELOAD_SWITCH(wname, num) \
+	SOC_SINGLE_EXT(wname " Preload Switch", SND_SOC_NOPM, num, 1, 0, \
+		wm_adsp2_preloader_get, wm_adsp2_preloader_put)
+
+#define WM_ADSP2(wname, num, event_fn) \
+	SND_SOC_DAPM_SPK(wname " Preload", NULL), \
+{	.id = snd_soc_dapm_supply, .name = wname " Preloader", \
+	.reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \
+	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \
+	.subseq = 100, /* Ensure we run after SYSCLK supply widget */ }, \
+{	.id = snd_soc_dapm_out_drv, .name = wname, \
+	.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \
+	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
+
+#define WM_ADSP_FW_CONTROL(dspname, num) \
+	SOC_ENUM_EXT(dspname " Firmware", wm_adsp_fw_enum[num], \
+		     wm_adsp_fw_get, wm_adsp_fw_put)
+
+extern const struct soc_enum wm_adsp_fw_enum[];
+
+int wm_adsp1_init(struct wm_adsp *dsp);
+int wm_adsp2_init(struct wm_adsp *dsp);
+void wm_adsp2_remove(struct wm_adsp *dsp);
+int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component);
+int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component);
+int wm_adsp1_event(struct snd_soc_dapm_widget *w,
+		   struct snd_kcontrol *kcontrol, int event);
+int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event,
+			 unsigned int freq);
+
+int wm_adsp2_lock(struct wm_adsp *adsp, unsigned int regions);
+irqreturn_t wm_adsp2_bus_error(struct wm_adsp *adsp);
+
+int wm_adsp2_event(struct snd_soc_dapm_widget *w,
+		   struct snd_kcontrol *kcontrol, int event);
+
+int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol);
+int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol);
+int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
+		   struct snd_ctl_elem_value *ucontrol);
+int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
+		   struct snd_ctl_elem_value *ucontrol);
+
+int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream);
+int wm_adsp_compr_free(struct snd_compr_stream *stream);
+int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
+			     struct snd_compr_params *params);
+int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
+			   struct snd_compr_caps *caps);
+int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd);
+int wm_adsp_compr_handle_irq(struct wm_adsp *dsp);
+int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
+			  struct snd_compr_tstamp *tstamp);
+int wm_adsp_compr_copy(struct snd_compr_stream *stream,
+		       char __user *buf, size_t count);
+
+#endif
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
new file mode 100644
index 0000000..fed6ea9
--- /dev/null
+++ b/sound/soc/codecs/wm_hubs.c
@@ -0,0 +1,1310 @@
+/*
+ * wm_hubs.c  --  WM8993/4 common code
+ *
+ * Copyright 2009-12 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/mfd/wm8994/registers.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8993.h"
+#include "wm_hubs.h"
+
+const DECLARE_TLV_DB_SCALE(wm_hubs_spkmix_tlv, -300, 300, 0);
+EXPORT_SYMBOL_GPL(wm_hubs_spkmix_tlv);
+
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(inmix_sw_tlv, 0, 3000, 0);
+static const DECLARE_TLV_DB_SCALE(inmix_tlv, -1500, 300, 1);
+static const DECLARE_TLV_DB_SCALE(earpiece_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(outmix_tlv, -2100, 300, 0);
+static const DECLARE_TLV_DB_SCALE(spkmixout_tlv, -1800, 600, 1);
+static const DECLARE_TLV_DB_SCALE(outpga_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_RANGE(spkboost_tlv,
+	0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
+	7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0)
+);
+static const DECLARE_TLV_DB_SCALE(line_tlv, -600, 600, 0);
+
+static const char *speaker_ref_text[] = {
+	"SPKVDD/2",
+	"VMID",
+};
+
+static SOC_ENUM_SINGLE_DECL(speaker_ref,
+			    WM8993_SPEAKER_MIXER, 8, speaker_ref_text);
+
+static const char *speaker_mode_text[] = {
+	"Class D",
+	"Class AB",
+};
+
+static SOC_ENUM_SINGLE_DECL(speaker_mode,
+			    WM8993_SPKMIXR_ATTENUATION, 8, speaker_mode_text);
+
+static void wait_for_dc_servo(struct snd_soc_component *component, unsigned int op)
+{
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+	unsigned int reg;
+	int count = 0;
+	int timeout;
+	unsigned int val;
+
+	val = op | WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1;
+
+	/* Trigger the command */
+	snd_soc_component_write(component, WM8993_DC_SERVO_0, val);
+
+	dev_dbg(component->dev, "Waiting for DC servo...\n");
+
+	if (hubs->dcs_done_irq)
+		timeout = 4;
+	else
+		timeout = 400;
+
+	do {
+		count++;
+
+		if (hubs->dcs_done_irq)
+			wait_for_completion_timeout(&hubs->dcs_done,
+						    msecs_to_jiffies(250));
+		else
+			msleep(1);
+
+		reg = snd_soc_component_read32(component, WM8993_DC_SERVO_0);
+		dev_dbg(component->dev, "DC servo: %x\n", reg);
+	} while (reg & op && count < timeout);
+
+	if (reg & op)
+		dev_err(component->dev, "Timed out waiting for DC Servo %x\n",
+			op);
+}
+
+irqreturn_t wm_hubs_dcs_done(int irq, void *data)
+{
+	struct wm_hubs_data *hubs = data;
+
+	complete(&hubs->dcs_done);
+
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(wm_hubs_dcs_done);
+
+static bool wm_hubs_dac_hp_direct(struct snd_soc_component *component)
+{
+	int reg;
+
+	/* If we're going via the mixer we'll need to do additional checks */
+	reg = snd_soc_component_read32(component, WM8993_OUTPUT_MIXER1);
+	if (!(reg & WM8993_DACL_TO_HPOUT1L)) {
+		if (reg & ~WM8993_DACL_TO_MIXOUTL) {
+			dev_vdbg(component->dev, "Analogue paths connected: %x\n",
+				 reg & ~WM8993_DACL_TO_HPOUT1L);
+			return false;
+		} else {
+			dev_vdbg(component->dev, "HPL connected to mixer\n");
+		}
+	} else {
+		dev_vdbg(component->dev, "HPL connected to DAC\n");
+	}
+
+	reg = snd_soc_component_read32(component, WM8993_OUTPUT_MIXER2);
+	if (!(reg & WM8993_DACR_TO_HPOUT1R)) {
+		if (reg & ~WM8993_DACR_TO_MIXOUTR) {
+			dev_vdbg(component->dev, "Analogue paths connected: %x\n",
+				 reg & ~WM8993_DACR_TO_HPOUT1R);
+			return false;
+		} else {
+			dev_vdbg(component->dev, "HPR connected to mixer\n");
+		}
+	} else {
+		dev_vdbg(component->dev, "HPR connected to DAC\n");
+	}
+
+	return true;
+}
+
+struct wm_hubs_dcs_cache {
+	struct list_head list;
+	unsigned int left;
+	unsigned int right;
+	u16 dcs_cfg;
+};
+
+static bool wm_hubs_dcs_cache_get(struct snd_soc_component *component,
+				  struct wm_hubs_dcs_cache **entry)
+{
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+	struct wm_hubs_dcs_cache *cache;
+	unsigned int left, right;
+
+	left = snd_soc_component_read32(component, WM8993_LEFT_OUTPUT_VOLUME);
+	left &= WM8993_HPOUT1L_VOL_MASK;
+
+	right = snd_soc_component_read32(component, WM8993_RIGHT_OUTPUT_VOLUME);
+	right &= WM8993_HPOUT1R_VOL_MASK;
+
+	list_for_each_entry(cache, &hubs->dcs_cache, list) {
+		if (cache->left != left || cache->right != right)
+			continue;
+
+		*entry = cache;
+		return true;
+	}
+
+	return false;
+}
+
+static void wm_hubs_dcs_cache_set(struct snd_soc_component *component, u16 dcs_cfg)
+{
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+	struct wm_hubs_dcs_cache *cache;
+
+	if (hubs->no_cache_dac_hp_direct)
+		return;
+
+	cache = devm_kzalloc(component->dev, sizeof(*cache), GFP_KERNEL);
+	if (!cache)
+		return;
+
+	cache->left = snd_soc_component_read32(component, WM8993_LEFT_OUTPUT_VOLUME);
+	cache->left &= WM8993_HPOUT1L_VOL_MASK;
+
+	cache->right = snd_soc_component_read32(component, WM8993_RIGHT_OUTPUT_VOLUME);
+	cache->right &= WM8993_HPOUT1R_VOL_MASK;
+
+	cache->dcs_cfg = dcs_cfg;
+
+	list_add_tail(&cache->list, &hubs->dcs_cache);
+}
+
+static int wm_hubs_read_dc_servo(struct snd_soc_component *component,
+				  u16 *reg_l, u16 *reg_r)
+{
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+	u16 dcs_reg, reg;
+	int ret = 0;
+
+	switch (hubs->dcs_readback_mode) {
+	case 2:
+		dcs_reg = WM8994_DC_SERVO_4E;
+		break;
+	case 1:
+		dcs_reg = WM8994_DC_SERVO_READBACK;
+		break;
+	default:
+		dcs_reg = WM8993_DC_SERVO_3;
+		break;
+	}
+
+	/* Different chips in the family support different readback
+	 * methods.
+	 */
+	switch (hubs->dcs_readback_mode) {
+	case 0:
+		*reg_l = snd_soc_component_read32(component, WM8993_DC_SERVO_READBACK_1)
+			& WM8993_DCS_INTEG_CHAN_0_MASK;
+		*reg_r = snd_soc_component_read32(component, WM8993_DC_SERVO_READBACK_2)
+			& WM8993_DCS_INTEG_CHAN_1_MASK;
+		break;
+	case 2:
+	case 1:
+		reg = snd_soc_component_read32(component, dcs_reg);
+		*reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
+			>> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
+		*reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
+		break;
+	default:
+		WARN(1, "Unknown DCS readback method\n");
+		ret = -1;
+	}
+	return ret;
+}
+
+/*
+ * Startup calibration of the DC servo
+ */
+static void enable_dc_servo(struct snd_soc_component *component)
+{
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+	struct wm_hubs_dcs_cache *cache;
+	s8 offset;
+	u16 reg_l, reg_r, dcs_cfg, dcs_reg;
+
+	switch (hubs->dcs_readback_mode) {
+	case 2:
+		dcs_reg = WM8994_DC_SERVO_4E;
+		break;
+	default:
+		dcs_reg = WM8993_DC_SERVO_3;
+		break;
+	}
+
+	/* If we're using a digital only path and have a previously
+	 * callibrated DC servo offset stored then use that. */
+	if (wm_hubs_dac_hp_direct(component) &&
+	    wm_hubs_dcs_cache_get(component, &cache)) {
+		dev_dbg(component->dev, "Using cached DCS offset %x for %d,%d\n",
+			cache->dcs_cfg, cache->left, cache->right);
+		snd_soc_component_write(component, dcs_reg, cache->dcs_cfg);
+		wait_for_dc_servo(component,
+				  WM8993_DCS_TRIG_DAC_WR_0 |
+				  WM8993_DCS_TRIG_DAC_WR_1);
+		return;
+	}
+
+	if (hubs->series_startup) {
+		/* Set for 32 series updates */
+		snd_soc_component_update_bits(component, WM8993_DC_SERVO_1,
+				    WM8993_DCS_SERIES_NO_01_MASK,
+				    32 << WM8993_DCS_SERIES_NO_01_SHIFT);
+		wait_for_dc_servo(component,
+				  WM8993_DCS_TRIG_SERIES_0 |
+				  WM8993_DCS_TRIG_SERIES_1);
+	} else {
+		wait_for_dc_servo(component,
+				  WM8993_DCS_TRIG_STARTUP_0 |
+				  WM8993_DCS_TRIG_STARTUP_1);
+	}
+
+	if (wm_hubs_read_dc_servo(component, &reg_l, &reg_r) < 0)
+		return;
+
+	dev_dbg(component->dev, "DCS input: %x %x\n", reg_l, reg_r);
+
+	/* Apply correction to DC servo result */
+	if (hubs->dcs_codes_l || hubs->dcs_codes_r) {
+		dev_dbg(component->dev,
+			"Applying %d/%d code DC servo correction\n",
+			hubs->dcs_codes_l, hubs->dcs_codes_r);
+
+		/* HPOUT1R */
+		offset = (s8)reg_r;
+		dev_dbg(component->dev, "DCS right %d->%d\n", offset,
+			offset + hubs->dcs_codes_r);
+		offset += hubs->dcs_codes_r;
+		dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
+
+		/* HPOUT1L */
+		offset = (s8)reg_l;
+		dev_dbg(component->dev, "DCS left %d->%d\n", offset,
+			offset + hubs->dcs_codes_l);
+		offset += hubs->dcs_codes_l;
+		dcs_cfg |= (u8)offset;
+
+		dev_dbg(component->dev, "DCS result: %x\n", dcs_cfg);
+
+		/* Do it */
+		snd_soc_component_write(component, dcs_reg, dcs_cfg);
+		wait_for_dc_servo(component,
+				  WM8993_DCS_TRIG_DAC_WR_0 |
+				  WM8993_DCS_TRIG_DAC_WR_1);
+	} else {
+		dcs_cfg = reg_r << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
+		dcs_cfg |= reg_l;
+	}
+
+	/* Save the callibrated offset if we're in class W mode and
+	 * therefore don't have any analogue signal mixed in. */
+	if (wm_hubs_dac_hp_direct(component))
+		wm_hubs_dcs_cache_set(component, dcs_cfg);
+}
+
+/*
+ * Update the DC servo calibration on gain changes
+ */
+static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+	/* If we're applying an offset correction then updating the
+	 * callibration would be likely to introduce further offsets. */
+	if (hubs->dcs_codes_l || hubs->dcs_codes_r || hubs->no_series_update)
+		return ret;
+
+	/* Only need to do this if the outputs are active */
+	if (snd_soc_component_read32(component, WM8993_POWER_MANAGEMENT_1)
+	    & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA))
+		snd_soc_component_update_bits(component,
+				    WM8993_DC_SERVO_0,
+				    WM8993_DCS_TRIG_SINGLE_0 |
+				    WM8993_DCS_TRIG_SINGLE_1,
+				    WM8993_DCS_TRIG_SINGLE_0 |
+				    WM8993_DCS_TRIG_SINGLE_1);
+
+	return ret;
+}
+
+static const struct snd_kcontrol_new analogue_snd_controls[] = {
+SOC_SINGLE_TLV("IN1L Volume", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
+	       inpga_tlv),
+SOC_SINGLE("IN1L Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
+SOC_SINGLE("IN1L ZC Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 6, 1, 0),
+
+SOC_SINGLE_TLV("IN1R Volume", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
+	       inpga_tlv),
+SOC_SINGLE("IN1R Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
+SOC_SINGLE("IN1R ZC Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 6, 1, 0),
+
+
+SOC_SINGLE_TLV("IN2L Volume", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
+	       inpga_tlv),
+SOC_SINGLE("IN2L Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
+SOC_SINGLE("IN2L ZC Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 6, 1, 0),
+
+SOC_SINGLE_TLV("IN2R Volume", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
+	       inpga_tlv),
+SOC_SINGLE("IN2R Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
+SOC_SINGLE("IN2R ZC Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 6, 1, 0),
+
+SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8993_INPUT_MIXER3, 7, 1, 0,
+	       inmix_sw_tlv),
+SOC_SINGLE_TLV("MIXINL IN1L Volume", WM8993_INPUT_MIXER3, 4, 1, 0,
+	       inmix_sw_tlv),
+SOC_SINGLE_TLV("MIXINL Output Record Volume", WM8993_INPUT_MIXER3, 0, 7, 0,
+	       inmix_tlv),
+SOC_SINGLE_TLV("MIXINL IN1LP Volume", WM8993_INPUT_MIXER5, 6, 7, 0, inmix_tlv),
+SOC_SINGLE_TLV("MIXINL Direct Voice Volume", WM8993_INPUT_MIXER5, 0, 6, 0,
+	       inmix_tlv),
+
+SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8993_INPUT_MIXER4, 7, 1, 0,
+	       inmix_sw_tlv),
+SOC_SINGLE_TLV("MIXINR IN1R Volume", WM8993_INPUT_MIXER4, 4, 1, 0,
+	       inmix_sw_tlv),
+SOC_SINGLE_TLV("MIXINR Output Record Volume", WM8993_INPUT_MIXER4, 0, 7, 0,
+	       inmix_tlv),
+SOC_SINGLE_TLV("MIXINR IN1RP Volume", WM8993_INPUT_MIXER6, 6, 7, 0, inmix_tlv),
+SOC_SINGLE_TLV("MIXINR Direct Voice Volume", WM8993_INPUT_MIXER6, 0, 6, 0,
+	       inmix_tlv),
+
+SOC_SINGLE_TLV("Left Output Mixer IN2RN Volume", WM8993_OUTPUT_MIXER5, 6, 7, 1,
+	       outmix_tlv),
+SOC_SINGLE_TLV("Left Output Mixer IN2LN Volume", WM8993_OUTPUT_MIXER3, 6, 7, 1,
+	       outmix_tlv),
+SOC_SINGLE_TLV("Left Output Mixer IN2LP Volume", WM8993_OUTPUT_MIXER3, 9, 7, 1,
+	       outmix_tlv),
+SOC_SINGLE_TLV("Left Output Mixer IN1L Volume", WM8993_OUTPUT_MIXER3, 0, 7, 1,
+	       outmix_tlv),
+SOC_SINGLE_TLV("Left Output Mixer IN1R Volume", WM8993_OUTPUT_MIXER3, 3, 7, 1,
+	       outmix_tlv),
+SOC_SINGLE_TLV("Left Output Mixer Right Input Volume",
+	       WM8993_OUTPUT_MIXER5, 3, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Left Output Mixer Left Input Volume",
+	       WM8993_OUTPUT_MIXER5, 0, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Left Output Mixer DAC Volume", WM8993_OUTPUT_MIXER5, 9, 7, 1,
+	       outmix_tlv),
+
+SOC_SINGLE_TLV("Right Output Mixer IN2LN Volume",
+	       WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Right Output Mixer IN2RN Volume",
+	       WM8993_OUTPUT_MIXER4, 6, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Right Output Mixer IN1L Volume",
+	       WM8993_OUTPUT_MIXER4, 3, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Right Output Mixer IN1R Volume",
+	       WM8993_OUTPUT_MIXER4, 0, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Right Output Mixer IN2RP Volume",
+	       WM8993_OUTPUT_MIXER4, 9, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Right Output Mixer Left Input Volume",
+	       WM8993_OUTPUT_MIXER6, 3, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Right Output Mixer Right Input Volume",
+	       WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
+SOC_SINGLE_TLV("Right Output Mixer DAC Volume",
+	       WM8993_OUTPUT_MIXER6, 9, 7, 1, outmix_tlv),
+
+SOC_DOUBLE_R_TLV("Output Volume", WM8993_LEFT_OPGA_VOLUME,
+		 WM8993_RIGHT_OPGA_VOLUME, 0, 63, 0, outpga_tlv),
+SOC_DOUBLE_R("Output Switch", WM8993_LEFT_OPGA_VOLUME,
+	     WM8993_RIGHT_OPGA_VOLUME, 6, 1, 0),
+SOC_DOUBLE_R("Output ZC Switch", WM8993_LEFT_OPGA_VOLUME,
+	     WM8993_RIGHT_OPGA_VOLUME, 7, 1, 0),
+
+SOC_SINGLE("Earpiece Switch", WM8993_HPOUT2_VOLUME, 5, 1, 1),
+SOC_SINGLE_TLV("Earpiece Volume", WM8993_HPOUT2_VOLUME, 4, 1, 1, earpiece_tlv),
+
+SOC_SINGLE_TLV("SPKL Input Volume", WM8993_SPKMIXL_ATTENUATION,
+	       5, 1, 1, wm_hubs_spkmix_tlv),
+SOC_SINGLE_TLV("SPKL IN1LP Volume", WM8993_SPKMIXL_ATTENUATION,
+	       4, 1, 1, wm_hubs_spkmix_tlv),
+SOC_SINGLE_TLV("SPKL Output Volume", WM8993_SPKMIXL_ATTENUATION,
+	       3, 1, 1, wm_hubs_spkmix_tlv),
+
+SOC_SINGLE_TLV("SPKR Input Volume", WM8993_SPKMIXR_ATTENUATION,
+	       5, 1, 1, wm_hubs_spkmix_tlv),
+SOC_SINGLE_TLV("SPKR IN1RP Volume", WM8993_SPKMIXR_ATTENUATION,
+	       4, 1, 1, wm_hubs_spkmix_tlv),
+SOC_SINGLE_TLV("SPKR Output Volume", WM8993_SPKMIXR_ATTENUATION,
+	       3, 1, 1, wm_hubs_spkmix_tlv),
+
+SOC_DOUBLE_R_TLV("Speaker Mixer Volume",
+		 WM8993_SPKMIXL_ATTENUATION, WM8993_SPKMIXR_ATTENUATION,
+		 0, 3, 1, spkmixout_tlv),
+SOC_DOUBLE_R_TLV("Speaker Volume",
+		 WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
+		 0, 63, 0, outpga_tlv),
+SOC_DOUBLE_R("Speaker Switch",
+	     WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
+	     6, 1, 0),
+SOC_DOUBLE_R("Speaker ZC Switch",
+	     WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
+	     7, 1, 0),
+SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 3, 0, 7, 0,
+	       spkboost_tlv),
+SOC_ENUM("Speaker Reference", speaker_ref),
+SOC_ENUM("Speaker Mode", speaker_mode),
+
+SOC_DOUBLE_R_EXT_TLV("Headphone Volume",
+		     WM8993_LEFT_OUTPUT_VOLUME, WM8993_RIGHT_OUTPUT_VOLUME,
+		     0, 63, 0, snd_soc_get_volsw, wm8993_put_dc_servo,
+		     outpga_tlv),
+
+SOC_DOUBLE_R("Headphone Switch", WM8993_LEFT_OUTPUT_VOLUME,
+	     WM8993_RIGHT_OUTPUT_VOLUME, 6, 1, 0),
+SOC_DOUBLE_R("Headphone ZC Switch", WM8993_LEFT_OUTPUT_VOLUME,
+	     WM8993_RIGHT_OUTPUT_VOLUME, 7, 1, 0),
+
+SOC_SINGLE("LINEOUT1N Switch", WM8993_LINE_OUTPUTS_VOLUME, 6, 1, 1),
+SOC_SINGLE("LINEOUT1P Switch", WM8993_LINE_OUTPUTS_VOLUME, 5, 1, 1),
+SOC_SINGLE_TLV("LINEOUT1 Volume", WM8993_LINE_OUTPUTS_VOLUME, 4, 1, 1,
+	       line_tlv),
+
+SOC_SINGLE("LINEOUT2N Switch", WM8993_LINE_OUTPUTS_VOLUME, 2, 1, 1),
+SOC_SINGLE("LINEOUT2P Switch", WM8993_LINE_OUTPUTS_VOLUME, 1, 1, 1),
+SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1,
+	       line_tlv),
+};
+
+static int hp_supply_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		switch (hubs->hp_startup_mode) {
+		case 0:
+			break;
+		case 1:
+			/* Enable the headphone amp */
+			snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
+					    WM8993_HPOUT1L_ENA |
+					    WM8993_HPOUT1R_ENA,
+					    WM8993_HPOUT1L_ENA |
+					    WM8993_HPOUT1R_ENA);
+
+			/* Enable the second stage */
+			snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
+					    WM8993_HPOUT1L_DLY |
+					    WM8993_HPOUT1R_DLY,
+					    WM8993_HPOUT1L_DLY |
+					    WM8993_HPOUT1R_DLY);
+			break;
+		default:
+			dev_err(component->dev, "Unknown HP startup mode %d\n",
+				hubs->hp_startup_mode);
+			break;
+		}
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, WM8993_CHARGE_PUMP_1,
+				    WM8993_CP_ENA, 0);
+		break;
+	}
+
+	return 0;
+}
+
+static int hp_event(struct snd_soc_dapm_widget *w,
+		    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	unsigned int reg = snd_soc_component_read32(component, WM8993_ANALOGUE_HP_0);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(component, WM8993_CHARGE_PUMP_1,
+				    WM8993_CP_ENA, WM8993_CP_ENA);
+
+		msleep(5);
+
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
+				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
+				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA);
+
+		reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY;
+		snd_soc_component_write(component, WM8993_ANALOGUE_HP_0, reg);
+
+		snd_soc_component_update_bits(component, WM8993_DC_SERVO_1,
+				    WM8993_DCS_TIMER_PERIOD_01_MASK, 0);
+
+		enable_dc_servo(component);
+
+		reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT |
+			WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT;
+		snd_soc_component_write(component, WM8993_ANALOGUE_HP_0, reg);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
+				    WM8993_HPOUT1L_OUTP |
+				    WM8993_HPOUT1R_OUTP |
+				    WM8993_HPOUT1L_RMV_SHORT |
+				    WM8993_HPOUT1R_RMV_SHORT, 0);
+
+		snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
+				    WM8993_HPOUT1L_DLY |
+				    WM8993_HPOUT1R_DLY, 0);
+
+		snd_soc_component_write(component, WM8993_DC_SERVO_0, 0);
+
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
+				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
+				    0);
+		break;
+	}
+
+	return 0;
+}
+
+static int earpiece_event(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *control, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	u16 reg = snd_soc_component_read32(component, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		reg |= WM8993_HPOUT2_IN_ENA;
+		snd_soc_component_write(component, WM8993_ANTIPOP1, reg);
+		udelay(50);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_write(component, WM8993_ANTIPOP1, reg);
+		break;
+
+	default:
+		WARN(1, "Invalid event %d\n", event);
+		break;
+	}
+
+	return 0;
+}
+
+static int lineout_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *control, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+	bool *flag;
+
+	switch (w->shift) {
+	case WM8993_LINEOUT1N_ENA_SHIFT:
+		flag = &hubs->lineout1n_ena;
+		break;
+	case WM8993_LINEOUT1P_ENA_SHIFT:
+		flag = &hubs->lineout1p_ena;
+		break;
+	case WM8993_LINEOUT2N_ENA_SHIFT:
+		flag = &hubs->lineout2n_ena;
+		break;
+	case WM8993_LINEOUT2P_ENA_SHIFT:
+		flag = &hubs->lineout2p_ena;
+		break;
+	default:
+		WARN(1, "Unknown line output");
+		return -EINVAL;
+	}
+
+	*flag = SND_SOC_DAPM_EVENT_ON(event);
+
+	return 0;
+}
+
+static int micbias_event(struct snd_soc_dapm_widget *w,
+			 struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+
+	switch (w->shift) {
+	case WM8993_MICB1_ENA_SHIFT:
+		if (hubs->micb1_delay)
+			msleep(hubs->micb1_delay);
+		break;
+	case WM8993_MICB2_ENA_SHIFT:
+		if (hubs->micb2_delay)
+			msleep(hubs->micb2_delay);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void wm_hubs_update_class_w(struct snd_soc_component *component)
+{
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+	int enable = WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ;
+
+	if (!wm_hubs_dac_hp_direct(component))
+		enable = false;
+
+	if (hubs->check_class_w_digital && !hubs->check_class_w_digital(component))
+		enable = false;
+
+	dev_vdbg(component->dev, "Class W %s\n", enable ? "enabled" : "disabled");
+
+	snd_soc_component_update_bits(component, WM8993_CLASS_W_0,
+			    WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable);
+
+	snd_soc_component_write(component, WM8993_LEFT_OUTPUT_VOLUME,
+		      snd_soc_component_read32(component, WM8993_LEFT_OUTPUT_VOLUME));
+	snd_soc_component_write(component, WM8993_RIGHT_OUTPUT_VOLUME,
+		      snd_soc_component_read32(component, WM8993_RIGHT_OUTPUT_VOLUME));
+}
+EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
+
+#define WM_HUBS_SINGLE_W(xname, reg, shift, max, invert) \
+	SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
+		snd_soc_dapm_get_volsw, class_w_put_volsw)
+
+static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	int ret;
+
+	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+
+	wm_hubs_update_class_w(component);
+
+	return ret;
+}
+
+#define WM_HUBS_ENUM_W(xname, xenum) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_enum_double, \
+	.get = snd_soc_dapm_get_enum_double, \
+	.put = class_w_put_double, \
+	.private_value = (unsigned long)&xenum }
+
+static int class_w_put_double(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+	int ret;
+
+	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+	wm_hubs_update_class_w(component);
+
+	return ret;
+}
+
+static const char *hp_mux_text[] = {
+	"Mixer",
+	"DAC",
+};
+
+static SOC_ENUM_SINGLE_DECL(hpl_enum,
+			    WM8993_OUTPUT_MIXER1, 8, hp_mux_text);
+
+const struct snd_kcontrol_new wm_hubs_hpl_mux =
+	WM_HUBS_ENUM_W("Left Headphone Mux", hpl_enum);
+EXPORT_SYMBOL_GPL(wm_hubs_hpl_mux);
+
+static SOC_ENUM_SINGLE_DECL(hpr_enum,
+			    WM8993_OUTPUT_MIXER2, 8, hp_mux_text);
+
+const struct snd_kcontrol_new wm_hubs_hpr_mux =
+	WM_HUBS_ENUM_W("Right Headphone Mux", hpr_enum);
+EXPORT_SYMBOL_GPL(wm_hubs_hpr_mux);
+
+static const struct snd_kcontrol_new in1l_pga[] = {
+SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0),
+SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new in1r_pga[] = {
+SOC_DAPM_SINGLE("IN1RP Switch", WM8993_INPUT_MIXER2, 1, 1, 0),
+SOC_DAPM_SINGLE("IN1RN Switch", WM8993_INPUT_MIXER2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new in2l_pga[] = {
+SOC_DAPM_SINGLE("IN2LP Switch", WM8993_INPUT_MIXER2, 7, 1, 0),
+SOC_DAPM_SINGLE("IN2LN Switch", WM8993_INPUT_MIXER2, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new in2r_pga[] = {
+SOC_DAPM_SINGLE("IN2RP Switch", WM8993_INPUT_MIXER2, 3, 1, 0),
+SOC_DAPM_SINGLE("IN2RN Switch", WM8993_INPUT_MIXER2, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixinl[] = {
+SOC_DAPM_SINGLE("IN2L Switch", WM8993_INPUT_MIXER3, 8, 1, 0),
+SOC_DAPM_SINGLE("IN1L Switch", WM8993_INPUT_MIXER3, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixinr[] = {
+SOC_DAPM_SINGLE("IN2R Switch", WM8993_INPUT_MIXER4, 8, 1, 0),
+SOC_DAPM_SINGLE("IN1R Switch", WM8993_INPUT_MIXER4, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_output_mixer[] = {
+WM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0),
+WM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0),
+WM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0),
+WM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0),
+WM_HUBS_SINGLE_W("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0),
+WM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0),
+WM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0),
+WM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_output_mixer[] = {
+WM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0),
+WM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0),
+WM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0),
+WM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0),
+WM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0),
+WM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0),
+WM_HUBS_SINGLE_W("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0),
+WM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new earpiece_mixer[] = {
+SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_HPOUT2_MIXER, 5, 1, 0),
+SOC_DAPM_SINGLE("Left Output Switch", WM8993_HPOUT2_MIXER, 4, 1, 0),
+SOC_DAPM_SINGLE("Right Output Switch", WM8993_HPOUT2_MIXER, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_speaker_boost[] = {
+SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 5, 1, 0),
+SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 4, 1, 0),
+SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_speaker_boost[] = {
+SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 2, 1, 0),
+SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 1, 1, 0),
+SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new line1_mix[] = {
+SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER1, 2, 1, 0),
+SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER1, 1, 1, 0),
+SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new line1n_mix[] = {
+SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 6, 1, 0),
+SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER1, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new line1p_mix[] = {
+SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new line2_mix[] = {
+SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER2, 1, 1, 0),
+SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new line2n_mix[] = {
+SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 5, 1, 0),
+SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new line2p_mix[] = {
+SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget analogue_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1LN"),
+SND_SOC_DAPM_INPUT("IN1LP"),
+SND_SOC_DAPM_INPUT("IN2LN"),
+SND_SOC_DAPM_INPUT("IN2LP:VXRN"),
+SND_SOC_DAPM_INPUT("IN1RN"),
+SND_SOC_DAPM_INPUT("IN1RP"),
+SND_SOC_DAPM_INPUT("IN2RN"),
+SND_SOC_DAPM_INPUT("IN2RP:VXRP"),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0,
+		    micbias_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0,
+		    micbias_event, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
+		   in1l_pga, ARRAY_SIZE(in1l_pga)),
+SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0,
+		   in1r_pga, ARRAY_SIZE(in1r_pga)),
+
+SND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0,
+		   in2l_pga, ARRAY_SIZE(in2l_pga)),
+SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0,
+		   in2r_pga, ARRAY_SIZE(in2r_pga)),
+
+SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0,
+		   mixinl, ARRAY_SIZE(mixinl)),
+SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0,
+		   mixinr, ARRAY_SIZE(mixinr)),
+
+SND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0,
+		   left_output_mixer, ARRAY_SIZE(left_output_mixer)),
+SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0,
+		   right_output_mixer, ARRAY_SIZE(right_output_mixer)),
+
+SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event, 
+		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_OUT_DRV_E("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
+		       hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
+		   earpiece_mixer, ARRAY_SIZE(earpiece_mixer)),
+SND_SOC_DAPM_PGA_E("Earpiece Driver", WM8993_POWER_MANAGEMENT_1, 11, 0,
+		   NULL, 0, earpiece_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_MIXER("SPKL Boost", SND_SOC_NOPM, 0, 0,
+		   left_speaker_boost, ARRAY_SIZE(left_speaker_boost)),
+SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0,
+		   right_speaker_boost, ARRAY_SIZE(right_speaker_boost)),
+
+SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0),
+SND_SOC_DAPM_OUT_DRV("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0,
+		     NULL, 0),
+SND_SOC_DAPM_OUT_DRV("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0,
+		     NULL, 0),
+
+SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0,
+		   line1_mix, ARRAY_SIZE(line1_mix)),
+SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0,
+		   line2_mix, ARRAY_SIZE(line2_mix)),
+
+SND_SOC_DAPM_MIXER("LINEOUT1N Mixer", SND_SOC_NOPM, 0, 0,
+		   line1n_mix, ARRAY_SIZE(line1n_mix)),
+SND_SOC_DAPM_MIXER("LINEOUT1P Mixer", SND_SOC_NOPM, 0, 0,
+		   line1p_mix, ARRAY_SIZE(line1p_mix)),
+SND_SOC_DAPM_MIXER("LINEOUT2N Mixer", SND_SOC_NOPM, 0, 0,
+		   line2n_mix, ARRAY_SIZE(line2n_mix)),
+SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0,
+		   line2p_mix, ARRAY_SIZE(line2p_mix)),
+
+SND_SOC_DAPM_OUT_DRV_E("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0,
+		       NULL, 0, lineout_event,
+		     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_OUT_DRV_E("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0,
+		       NULL, 0, lineout_event,
+		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_OUT_DRV_E("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0,
+		       NULL, 0, lineout_event,
+		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_OUT_DRV_E("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0,
+		       NULL, 0, lineout_event,
+		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("HPOUT2P"),
+SND_SOC_DAPM_OUTPUT("HPOUT2N"),
+SND_SOC_DAPM_OUTPUT("LINEOUT1P"),
+SND_SOC_DAPM_OUTPUT("LINEOUT1N"),
+SND_SOC_DAPM_OUTPUT("LINEOUT2P"),
+SND_SOC_DAPM_OUTPUT("LINEOUT2N"),
+};
+
+static const struct snd_soc_dapm_route analogue_routes[] = {
+	{ "MICBIAS1", NULL, "CLK_SYS" },
+	{ "MICBIAS2", NULL, "CLK_SYS" },
+
+	{ "IN1L PGA", "IN1LP Switch", "IN1LP" },
+	{ "IN1L PGA", "IN1LN Switch", "IN1LN" },
+
+	{ "IN1L PGA", NULL, "VMID" },
+	{ "IN1R PGA", NULL, "VMID" },
+	{ "IN2L PGA", NULL, "VMID" },
+	{ "IN2R PGA", NULL, "VMID" },
+
+	{ "IN1R PGA", "IN1RP Switch", "IN1RP" },
+	{ "IN1R PGA", "IN1RN Switch", "IN1RN" },
+
+	{ "IN2L PGA", "IN2LP Switch", "IN2LP:VXRN" },
+	{ "IN2L PGA", "IN2LN Switch", "IN2LN" },
+
+	{ "IN2R PGA", "IN2RP Switch", "IN2RP:VXRP" },
+	{ "IN2R PGA", "IN2RN Switch", "IN2RN" },
+
+	{ "Direct Voice", NULL, "IN2LP:VXRN" },
+	{ "Direct Voice", NULL, "IN2RP:VXRP" },
+
+	{ "MIXINL", "IN1L Switch", "IN1L PGA" },
+	{ "MIXINL", "IN2L Switch", "IN2L PGA" },
+	{ "MIXINL", NULL, "Direct Voice" },
+	{ "MIXINL", NULL, "IN1LP" },
+	{ "MIXINL", NULL, "Left Output Mixer" },
+	{ "MIXINL", NULL, "VMID" },
+
+	{ "MIXINR", "IN1R Switch", "IN1R PGA" },
+	{ "MIXINR", "IN2R Switch", "IN2R PGA" },
+	{ "MIXINR", NULL, "Direct Voice" },
+	{ "MIXINR", NULL, "IN1RP" },
+	{ "MIXINR", NULL, "Right Output Mixer" },
+	{ "MIXINR", NULL, "VMID" },
+
+	{ "ADCL", NULL, "MIXINL" },
+	{ "ADCR", NULL, "MIXINR" },
+
+	{ "Left Output Mixer", "Left Input Switch", "MIXINL" },
+	{ "Left Output Mixer", "Right Input Switch", "MIXINR" },
+	{ "Left Output Mixer", "IN2RN Switch", "IN2RN" },
+	{ "Left Output Mixer", "IN2LN Switch", "IN2LN" },
+	{ "Left Output Mixer", "IN2LP Switch", "IN2LP:VXRN" },
+	{ "Left Output Mixer", "IN1L Switch", "IN1L PGA" },
+	{ "Left Output Mixer", "IN1R Switch", "IN1R PGA" },
+
+	{ "Right Output Mixer", "Left Input Switch", "MIXINL" },
+	{ "Right Output Mixer", "Right Input Switch", "MIXINR" },
+	{ "Right Output Mixer", "IN2LN Switch", "IN2LN" },
+	{ "Right Output Mixer", "IN2RN Switch", "IN2RN" },
+	{ "Right Output Mixer", "IN2RP Switch", "IN2RP:VXRP" },
+	{ "Right Output Mixer", "IN1L Switch", "IN1L PGA" },
+	{ "Right Output Mixer", "IN1R Switch", "IN1R PGA" },
+
+	{ "Left Output PGA", NULL, "Left Output Mixer" },
+	{ "Left Output PGA", NULL, "TOCLK" },
+
+	{ "Right Output PGA", NULL, "Right Output Mixer" },
+	{ "Right Output PGA", NULL, "TOCLK" },
+
+	{ "Earpiece Mixer", "Direct Voice Switch", "Direct Voice" },
+	{ "Earpiece Mixer", "Left Output Switch", "Left Output PGA" },
+	{ "Earpiece Mixer", "Right Output Switch", "Right Output PGA" },
+
+	{ "Earpiece Driver", NULL, "VMID" },
+	{ "Earpiece Driver", NULL, "Earpiece Mixer" },
+	{ "HPOUT2N", NULL, "Earpiece Driver" },
+	{ "HPOUT2P", NULL, "Earpiece Driver" },
+
+	{ "SPKL", "Input Switch", "MIXINL" },
+	{ "SPKL", "IN1LP Switch", "IN1LP" },
+	{ "SPKL", "Output Switch", "Left Output PGA" },
+	{ "SPKL", NULL, "TOCLK" },
+
+	{ "SPKR", "Input Switch", "MIXINR" },
+	{ "SPKR", "IN1RP Switch", "IN1RP" },
+	{ "SPKR", "Output Switch", "Right Output PGA" },
+	{ "SPKR", NULL, "TOCLK" },
+
+	{ "SPKL Boost", "Direct Voice Switch", "Direct Voice" },
+	{ "SPKL Boost", "SPKL Switch", "SPKL" },
+	{ "SPKL Boost", "SPKR Switch", "SPKR" },
+
+	{ "SPKR Boost", "Direct Voice Switch", "Direct Voice" },
+	{ "SPKR Boost", "SPKR Switch", "SPKR" },
+	{ "SPKR Boost", "SPKL Switch", "SPKL" },
+
+	{ "SPKL Driver", NULL, "VMID" },
+	{ "SPKL Driver", NULL, "SPKL Boost" },
+	{ "SPKL Driver", NULL, "CLK_SYS" },
+	{ "SPKL Driver", NULL, "TSHUT" },
+
+	{ "SPKR Driver", NULL, "VMID" },
+	{ "SPKR Driver", NULL, "SPKR Boost" },
+	{ "SPKR Driver", NULL, "CLK_SYS" },
+	{ "SPKR Driver", NULL, "TSHUT" },
+
+	{ "SPKOUTLP", NULL, "SPKL Driver" },
+	{ "SPKOUTLN", NULL, "SPKL Driver" },
+	{ "SPKOUTRP", NULL, "SPKR Driver" },
+	{ "SPKOUTRN", NULL, "SPKR Driver" },
+
+	{ "Left Headphone Mux", "Mixer", "Left Output PGA" },
+	{ "Right Headphone Mux", "Mixer", "Right Output PGA" },
+
+	{ "Headphone PGA", NULL, "Left Headphone Mux" },
+	{ "Headphone PGA", NULL, "Right Headphone Mux" },
+	{ "Headphone PGA", NULL, "VMID" },
+	{ "Headphone PGA", NULL, "CLK_SYS" },
+	{ "Headphone PGA", NULL, "Headphone Supply" },
+
+	{ "HPOUT1L", NULL, "Headphone PGA" },
+	{ "HPOUT1R", NULL, "Headphone PGA" },
+
+	{ "LINEOUT1N Driver", NULL, "VMID" },
+	{ "LINEOUT1P Driver", NULL, "VMID" },
+	{ "LINEOUT2N Driver", NULL, "VMID" },
+	{ "LINEOUT2P Driver", NULL, "VMID" },
+
+	{ "LINEOUT1N", NULL, "LINEOUT1N Driver" },
+	{ "LINEOUT1P", NULL, "LINEOUT1P Driver" },
+	{ "LINEOUT2N", NULL, "LINEOUT2N Driver" },
+	{ "LINEOUT2P", NULL, "LINEOUT2P Driver" },
+};
+
+static const struct snd_soc_dapm_route lineout1_diff_routes[] = {
+	{ "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" },
+	{ "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" },
+	{ "LINEOUT1 Mixer", "Output Switch", "Left Output PGA" },
+
+	{ "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" },
+	{ "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" },
+};
+
+static const struct snd_soc_dapm_route lineout1_se_routes[] = {
+	{ "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" },
+	{ "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" },
+
+	{ "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" },
+
+	{ "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
+	{ "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" },
+};
+
+static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
+	{ "LINEOUT2 Mixer", "IN1L Switch", "IN1L PGA" },
+	{ "LINEOUT2 Mixer", "IN1R Switch", "IN1R PGA" },
+	{ "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" },
+
+	{ "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" },
+	{ "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" },
+};
+
+static const struct snd_soc_dapm_route lineout2_se_routes[] = {
+	{ "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" },
+	{ "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" },
+
+	{ "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" },
+
+	{ "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
+	{ "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" },
+};
+
+int wm_hubs_add_analogue_controls(struct snd_soc_component *component)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	/* Latch volume update bits & default ZC on */
+	snd_soc_component_update_bits(component, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
+			    WM8993_IN1_VU, WM8993_IN1_VU);
+	snd_soc_component_update_bits(component, WM8993_RIGHT_LINE_INPUT_1_2_VOLUME,
+			    WM8993_IN1_VU, WM8993_IN1_VU);
+	snd_soc_component_update_bits(component, WM8993_LEFT_LINE_INPUT_3_4_VOLUME,
+			    WM8993_IN2_VU, WM8993_IN2_VU);
+	snd_soc_component_update_bits(component, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME,
+			    WM8993_IN2_VU, WM8993_IN2_VU);
+
+	snd_soc_component_update_bits(component, WM8993_SPEAKER_VOLUME_LEFT,
+			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
+	snd_soc_component_update_bits(component, WM8993_SPEAKER_VOLUME_RIGHT,
+			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
+
+	snd_soc_component_update_bits(component, WM8993_LEFT_OUTPUT_VOLUME,
+			    WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC,
+			    WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC);
+	snd_soc_component_update_bits(component, WM8993_RIGHT_OUTPUT_VOLUME,
+			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC,
+			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC);
+
+	snd_soc_component_update_bits(component, WM8993_LEFT_OPGA_VOLUME,
+			    WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU,
+			    WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU);
+	snd_soc_component_update_bits(component, WM8993_RIGHT_OPGA_VOLUME,
+			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
+			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);
+
+	snd_soc_add_component_controls(component, analogue_snd_controls,
+			     ARRAY_SIZE(analogue_snd_controls));
+
+	snd_soc_dapm_new_controls(dapm, analogue_dapm_widgets,
+				  ARRAY_SIZE(analogue_dapm_widgets));
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_controls);
+
+int wm_hubs_add_analogue_routes(struct snd_soc_component *component,
+				int lineout1_diff, int lineout2_diff)
+{
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+	hubs->component = component;
+
+	INIT_LIST_HEAD(&hubs->dcs_cache);
+	init_completion(&hubs->dcs_done);
+
+	snd_soc_dapm_add_routes(dapm, analogue_routes,
+				ARRAY_SIZE(analogue_routes));
+
+	if (lineout1_diff)
+		snd_soc_dapm_add_routes(dapm,
+					lineout1_diff_routes,
+					ARRAY_SIZE(lineout1_diff_routes));
+	else
+		snd_soc_dapm_add_routes(dapm,
+					lineout1_se_routes,
+					ARRAY_SIZE(lineout1_se_routes));
+
+	if (lineout2_diff)
+		snd_soc_dapm_add_routes(dapm,
+					lineout2_diff_routes,
+					ARRAY_SIZE(lineout2_diff_routes));
+	else
+		snd_soc_dapm_add_routes(dapm,
+					lineout2_se_routes,
+					ARRAY_SIZE(lineout2_se_routes));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes);
+
+int wm_hubs_handle_analogue_pdata(struct snd_soc_component *component,
+				  int lineout1_diff, int lineout2_diff,
+				  int lineout1fb, int lineout2fb,
+				  int jd_scthr, int jd_thr,
+				  int micbias1_delay, int micbias2_delay,
+				  int micbias1_lvl, int micbias2_lvl)
+{
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+
+	hubs->lineout1_se = !lineout1_diff;
+	hubs->lineout2_se = !lineout2_diff;
+	hubs->micb1_delay = micbias1_delay;
+	hubs->micb2_delay = micbias2_delay;
+
+	if (!lineout1_diff)
+		snd_soc_component_update_bits(component, WM8993_LINE_MIXER1,
+				    WM8993_LINEOUT1_MODE,
+				    WM8993_LINEOUT1_MODE);
+	if (!lineout2_diff)
+		snd_soc_component_update_bits(component, WM8993_LINE_MIXER2,
+				    WM8993_LINEOUT2_MODE,
+				    WM8993_LINEOUT2_MODE);
+
+	if (!lineout1_diff && !lineout2_diff)
+		snd_soc_component_update_bits(component, WM8993_ANTIPOP1,
+				    WM8993_LINEOUT_VMID_BUF_ENA,
+				    WM8993_LINEOUT_VMID_BUF_ENA);
+
+	if (lineout1fb)
+		snd_soc_component_update_bits(component, WM8993_ADDITIONAL_CONTROL,
+				    WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
+
+	if (lineout2fb)
+		snd_soc_component_update_bits(component, WM8993_ADDITIONAL_CONTROL,
+				    WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB);
+
+	snd_soc_component_update_bits(component, WM8993_MICBIAS,
+			    WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK |
+			    WM8993_MICB1_LVL | WM8993_MICB2_LVL,
+			    jd_scthr << WM8993_JD_SCTHR_SHIFT |
+			    jd_thr << WM8993_JD_THR_SHIFT |
+			    micbias1_lvl |
+			    micbias2_lvl << WM8993_MICB2_LVL_SHIFT);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata);
+
+void wm_hubs_vmid_ena(struct snd_soc_component *component)
+{
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+	int val = 0;
+
+	if (hubs->lineout1_se)
+		val |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA;
+
+	if (hubs->lineout2_se)
+		val |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA;
+
+	/* Enable the line outputs while we power up */
+	snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_3, val, val);
+}
+EXPORT_SYMBOL_GPL(wm_hubs_vmid_ena);
+
+void wm_hubs_set_bias_level(struct snd_soc_component *component,
+			    enum snd_soc_bias_level level)
+{
+	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
+	int mask, val;
+
+	switch (level) {
+	case SND_SOC_BIAS_STANDBY:
+		/* Clamp the inputs to VMID while we ramp to charge caps */
+		snd_soc_component_update_bits(component, WM8993_INPUTS_CLAMP_REG,
+				    WM8993_INPUTS_CLAMP, WM8993_INPUTS_CLAMP);
+		break;
+
+	case SND_SOC_BIAS_ON:
+		/* Turn off any unneeded single ended outputs */
+		val = 0;
+		mask = 0;
+
+		if (hubs->lineout1_se)
+			mask |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA;
+
+		if (hubs->lineout2_se)
+			mask |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA;
+
+		if (hubs->lineout1_se && hubs->lineout1n_ena)
+			val |= WM8993_LINEOUT1N_ENA;
+
+		if (hubs->lineout1_se && hubs->lineout1p_ena)
+			val |= WM8993_LINEOUT1P_ENA;
+
+		if (hubs->lineout2_se && hubs->lineout2n_ena)
+			val |= WM8993_LINEOUT2N_ENA;
+
+		if (hubs->lineout2_se && hubs->lineout2p_ena)
+			val |= WM8993_LINEOUT2P_ENA;
+
+		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_3,
+				    mask, val);
+
+		/* Remove the input clamps */
+		snd_soc_component_update_bits(component, WM8993_INPUTS_CLAMP_REG,
+				    WM8993_INPUTS_CLAMP, 0);
+		break;
+
+	default:
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(wm_hubs_set_bias_level);
+
+MODULE_DESCRIPTION("Shared support for Wolfson hubs products");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h
new file mode 100644
index 0000000..ee339ad
--- /dev/null
+++ b/sound/soc/codecs/wm_hubs.h
@@ -0,0 +1,74 @@
+/*
+ * wm_hubs.h  --  WM899x common code
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM_HUBS_H
+#define _WM_HUBS_H
+
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <sound/control.h>
+
+struct snd_soc_component;
+
+extern const unsigned int wm_hubs_spkmix_tlv[];
+
+/* This *must* be the first element of the codec->private_data struct */
+struct wm_hubs_data {
+	int dcs_codes_l;
+	int dcs_codes_r;
+	int dcs_readback_mode;
+	int hp_startup_mode;
+	int series_startup;
+	int no_series_update;
+
+	bool no_cache_dac_hp_direct;
+	struct list_head dcs_cache;
+	bool (*check_class_w_digital)(struct snd_soc_component *);
+
+	int micb1_delay;
+	int micb2_delay;
+
+	bool lineout1_se;
+	bool lineout1n_ena;
+	bool lineout1p_ena;
+
+	bool lineout2_se;
+	bool lineout2n_ena;
+	bool lineout2p_ena;
+
+	bool dcs_done_irq;
+	struct completion dcs_done;
+
+	struct snd_soc_component *component;
+};
+
+extern int wm_hubs_add_analogue_controls(struct snd_soc_component *);
+extern int wm_hubs_add_analogue_routes(struct snd_soc_component *, int, int);
+extern int wm_hubs_handle_analogue_pdata(struct snd_soc_component *,
+					 int lineout1_diff, int lineout2_diff,
+					 int lineout1fb, int lineout2fb,
+					 int jd_scthr, int jd_thr,
+					 int micbias1_dly, int micbias2_dly,
+					 int micbias1_lvl, int micbias2_lvl);
+
+extern irqreturn_t wm_hubs_dcs_done(int irq, void *data);
+extern void wm_hubs_vmid_ena(struct snd_soc_component *component);
+extern void wm_hubs_set_bias_level(struct snd_soc_component *component,
+				   enum snd_soc_bias_level level);
+extern void wm_hubs_update_class_w(struct snd_soc_component *component);
+
+extern const struct snd_kcontrol_new wm_hubs_hpl_mux;
+extern const struct snd_kcontrol_new wm_hubs_hpr_mux;
+
+#endif
diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h
new file mode 100644
index 0000000..0c3f50a
--- /dev/null
+++ b/sound/soc/codecs/wmfw.h
@@ -0,0 +1,172 @@
+/*
+ * wmfw.h - Wolfson firmware format information
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __WMFW_H
+#define __WMFW_H
+
+#include <linux/types.h>
+
+#define WMFW_MAX_ALG_NAME         256
+#define WMFW_MAX_ALG_DESCR_NAME   256
+
+#define WMFW_MAX_COEFF_NAME       256
+#define WMFW_MAX_COEFF_DESCR_NAME 256
+
+#define WMFW_CTL_FLAG_SYS         0x8000
+#define WMFW_CTL_FLAG_VOLATILE    0x0004
+#define WMFW_CTL_FLAG_WRITEABLE   0x0002
+#define WMFW_CTL_FLAG_READABLE    0x0001
+
+/* Non-ALSA coefficient types start at 0x1000 */
+#define WMFW_CTL_TYPE_ACKED       0x1000 /* acked control */
+#define WMFW_CTL_TYPE_HOSTEVENT   0x1001 /* event control */
+#define WMFW_CTL_TYPE_HOST_BUFFER 0x1002 /* host buffer pointer */
+
+struct wmfw_header {
+	char magic[4];
+	__le32 len;
+	__le16 rev;
+	u8 core;
+	u8 ver;
+} __packed;
+
+struct wmfw_footer {
+	__le64 timestamp;
+	__le32 checksum;
+} __packed;
+
+struct wmfw_adsp1_sizes {
+	__le32 dm;
+	__le32 pm;
+	__le32 zm;
+} __packed;
+
+struct wmfw_adsp2_sizes {
+	__le32 xm;
+	__le32 ym;
+	__le32 pm;
+	__le32 zm;
+} __packed;
+
+struct wmfw_region {
+	union {
+		__be32 type;
+		__le32 offset;
+	};
+	__le32 len;
+	u8 data[];
+} __packed;
+
+struct wmfw_id_hdr {
+	__be32 core_id;
+	__be32 core_rev;
+	__be32 id;
+	__be32 ver;
+} __packed;
+
+struct wmfw_adsp1_id_hdr {
+	struct wmfw_id_hdr fw;
+	__be32 zm;
+	__be32 dm;
+	__be32 n_algs;
+} __packed;
+
+struct wmfw_adsp2_id_hdr {
+	struct wmfw_id_hdr fw;
+	__be32 zm;
+	__be32 xm;
+	__be32 ym;
+	__be32 n_algs;
+} __packed;
+
+struct wmfw_alg_hdr {
+	__be32 id;
+	__be32 ver;
+} __packed;
+
+struct wmfw_adsp1_alg_hdr {
+	struct wmfw_alg_hdr alg;
+	__be32 zm;
+	__be32 dm;
+} __packed;
+
+struct wmfw_adsp2_alg_hdr {
+	struct wmfw_alg_hdr alg;
+	__be32 zm;
+	__be32 xm;
+	__be32 ym;
+} __packed;
+
+struct wmfw_adsp_alg_data {
+	__le32 id;
+	u8 name[WMFW_MAX_ALG_NAME];
+	u8 descr[WMFW_MAX_ALG_DESCR_NAME];
+	__le32 ncoeff;
+	u8 data[];
+} __packed;
+
+struct wmfw_adsp_coeff_data {
+	struct {
+		__le16 offset;
+		__le16 type;
+		__le32 size;
+	} hdr;
+	u8 name[WMFW_MAX_COEFF_NAME];
+	u8 descr[WMFW_MAX_COEFF_DESCR_NAME];
+	__le16 ctl_type;
+	__le16 flags;
+	__le32 len;
+	u8 data[];
+} __packed;
+
+struct wmfw_coeff_hdr {
+	u8 magic[4];
+	__le32 len;
+	union {
+		__be32 rev;
+		__le32 ver;
+	};
+	union {
+		__be32 core;
+		__le32 core_ver;
+	};
+	u8 data[];
+} __packed;
+
+struct wmfw_coeff_item {
+	__le16 offset;
+	__le16 type;
+	__le32 id;
+	__le32 ver;
+	__le32 sr;
+	__le32 len;
+	u8 data[];
+} __packed;
+
+#define WMFW_ADSP1 1
+#define WMFW_ADSP2 2
+
+#define WMFW_ABSOLUTE         0xf0
+#define WMFW_ALGORITHM_DATA   0xf2
+#define WMFW_NAME_TEXT        0xfe
+#define WMFW_INFO_TEXT        0xff
+
+#define WMFW_ADSP1_PM 2
+#define WMFW_ADSP1_DM 3
+#define WMFW_ADSP1_ZM 4
+
+#define WMFW_ADSP2_PM 2
+#define WMFW_ADSP2_ZM 4
+#define WMFW_ADSP2_XM 5
+#define WMFW_ADSP2_YM 6
+
+#endif
diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c
new file mode 100644
index 0000000..7a2d6ea
--- /dev/null
+++ b/sound/soc/codecs/zx_aud96p22.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2017 Sanechips Technology Co., Ltd.
+ * Copyright 2017 Linaro Ltd.
+ *
+ * Author: Baoyou Xie <baoyou.xie@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/tlv.h>
+
+#define AUD96P22_RESET			0x00
+#define RST_DAC_DPZ			BIT(0)
+#define RST_ADC_DPZ			BIT(1)
+#define AUD96P22_I2S1_CONFIG_0		0x03
+#define I2S1_MS_MODE			BIT(3)
+#define I2S1_MODE_MASK			0x7
+#define I2S1_MODE_RIGHT_J		0x0
+#define I2S1_MODE_I2S			0x1
+#define I2S1_MODE_LEFT_J		0x2
+#define AUD96P22_PD_0			0x15
+#define AUD96P22_PD_1			0x16
+#define AUD96P22_PD_3			0x18
+#define AUD96P22_PD_4			0x19
+#define AUD96P22_MUTE_0			0x1d
+#define AUD96P22_MUTE_2			0x1f
+#define AUD96P22_MUTE_4			0x21
+#define AUD96P22_RECVOL_0		0x24
+#define AUD96P22_RECVOL_1		0x25
+#define AUD96P22_PGA1VOL_0		0x26
+#define AUD96P22_PGA1VOL_1		0x27
+#define AUD96P22_LMVOL_0		0x34
+#define AUD96P22_LMVOL_1		0x35
+#define AUD96P22_HS1VOL_0		0x38
+#define AUD96P22_HS1VOL_1		0x39
+#define AUD96P22_PGA1SEL_0		0x47
+#define AUD96P22_PGA1SEL_1		0x48
+#define AUD96P22_LDR1SEL_0		0x59
+#define AUD96P22_LDR1SEL_1		0x60
+#define AUD96P22_LDR2SEL_0		0x5d
+#define AUD96P22_REG_MAX		0xfb
+
+struct aud96p22_priv {
+	struct regmap *regmap;
+};
+
+static int aud96p22_adc_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct aud96p22_priv *priv = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = priv->regmap;
+
+	if (event != SND_SOC_DAPM_POST_PMU)
+		return -EINVAL;
+
+	/* Assert/de-assert the bit to reset ADC data path  */
+	regmap_update_bits(regmap, AUD96P22_RESET, RST_ADC_DPZ, 0);
+	regmap_update_bits(regmap, AUD96P22_RESET, RST_ADC_DPZ, RST_ADC_DPZ);
+
+	return 0;
+}
+
+static int aud96p22_dac_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+	struct aud96p22_priv *priv = snd_soc_component_get_drvdata(component);
+	struct regmap *regmap = priv->regmap;
+
+	if (event != SND_SOC_DAPM_POST_PMU)
+		return -EINVAL;
+
+	/* Assert/de-assert the bit to reset DAC data path  */
+	regmap_update_bits(regmap, AUD96P22_RESET, RST_DAC_DPZ, 0);
+	regmap_update_bits(regmap, AUD96P22_RESET, RST_DAC_DPZ, RST_DAC_DPZ);
+
+	return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(lm_tlv, -11550, 50, 0);
+static const DECLARE_TLV_DB_SCALE(hs_tlv, -3900, 300, 0);
+static const DECLARE_TLV_DB_SCALE(rec_tlv, -9550, 50, 0);
+static const DECLARE_TLV_DB_SCALE(pga_tlv, -1800, 100, 0);
+
+static const struct snd_kcontrol_new aud96p22_snd_controls[] = {
+	/* Volume control */
+	SOC_DOUBLE_R_TLV("Master Playback Volume", AUD96P22_LMVOL_0,
+			 AUD96P22_LMVOL_1, 0, 0xff, 0, lm_tlv),
+	SOC_DOUBLE_R_TLV("Headphone Volume", AUD96P22_HS1VOL_0,
+			 AUD96P22_HS1VOL_1, 0, 0xf, 0, hs_tlv),
+	SOC_DOUBLE_R_TLV("Master Capture Volume", AUD96P22_RECVOL_0,
+			 AUD96P22_RECVOL_1, 0, 0xff, 0, rec_tlv),
+	SOC_DOUBLE_R_TLV("Analogue Capture Volume", AUD96P22_PGA1VOL_0,
+			 AUD96P22_PGA1VOL_1, 0, 0x37, 0, pga_tlv),
+
+	/* Mute control */
+	SOC_DOUBLE("Master Playback Switch", AUD96P22_MUTE_2, 0, 1, 1, 1),
+	SOC_DOUBLE("Headphone Switch", AUD96P22_MUTE_2, 4, 5, 1, 1),
+	SOC_DOUBLE("Line Out Switch", AUD96P22_MUTE_4, 0, 1, 1, 1),
+	SOC_DOUBLE("Speaker Switch", AUD96P22_MUTE_4, 2, 3, 1, 1),
+	SOC_DOUBLE("Master Capture Switch", AUD96P22_MUTE_0, 0, 1, 1, 1),
+	SOC_DOUBLE("Analogue Capture Switch", AUD96P22_MUTE_0, 2, 3, 1, 1),
+};
+
+/* Input mux kcontrols */
+static const unsigned int ain_mux_values[] = {
+	0, 1, 3, 4, 5,
+};
+
+static const char * const ainl_mux_texts[] = {
+	"AINL1 differential",
+	"AINL1 single-ended",
+	"AINL3 single-ended",
+	"AINL2 differential",
+	"AINL2 single-ended",
+};
+
+static const char * const ainr_mux_texts[] = {
+	"AINR1 differential",
+	"AINR1 single-ended",
+	"AINR3 single-ended",
+	"AINR2 differential",
+	"AINR2 single-ended",
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(ainl_mux_enum, AUD96P22_PGA1SEL_0,
+				  0, 0x7, ainl_mux_texts, ain_mux_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(ainr_mux_enum, AUD96P22_PGA1SEL_1,
+				  0, 0x7, ainr_mux_texts, ain_mux_values);
+
+static const struct snd_kcontrol_new ainl_mux_kcontrol =
+			SOC_DAPM_ENUM("AINL Mux", ainl_mux_enum);
+static const struct snd_kcontrol_new ainr_mux_kcontrol =
+			SOC_DAPM_ENUM("AINR Mux", ainr_mux_enum);
+
+/* Output mixer kcontrols */
+static const struct snd_kcontrol_new ld1_left_kcontrols[] = {
+	SOC_DAPM_SINGLE("DACL LD1L Switch", AUD96P22_LDR1SEL_0, 0, 1, 0),
+	SOC_DAPM_SINGLE("AINL LD1L Switch", AUD96P22_LDR1SEL_0, 1, 1, 0),
+	SOC_DAPM_SINGLE("AINR LD1L Switch", AUD96P22_LDR1SEL_0, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new ld1_right_kcontrols[] = {
+	SOC_DAPM_SINGLE("DACR LD1R Switch", AUD96P22_LDR1SEL_1, 8, 1, 0),
+	SOC_DAPM_SINGLE("AINR LD1R Switch", AUD96P22_LDR1SEL_1, 9, 1, 0),
+	SOC_DAPM_SINGLE("AINL LD1R Switch", AUD96P22_LDR1SEL_1, 10, 1, 0),
+};
+
+static const struct snd_kcontrol_new ld2_kcontrols[] = {
+	SOC_DAPM_SINGLE("DACL LD2 Switch", AUD96P22_LDR2SEL_0, 0, 1, 0),
+	SOC_DAPM_SINGLE("AINL LD2 Switch", AUD96P22_LDR2SEL_0, 1, 1, 0),
+	SOC_DAPM_SINGLE("DACR LD2 Switch", AUD96P22_LDR2SEL_0, 2, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget aud96p22_dapm_widgets[] = {
+	/* Overall power bit */
+	SND_SOC_DAPM_SUPPLY("POWER", AUD96P22_PD_0, 0, 0, NULL, 0),
+
+	/* Input pins */
+	SND_SOC_DAPM_INPUT("AINL1P"),
+	SND_SOC_DAPM_INPUT("AINL2P"),
+	SND_SOC_DAPM_INPUT("AINL3"),
+	SND_SOC_DAPM_INPUT("AINL1N"),
+	SND_SOC_DAPM_INPUT("AINL2N"),
+	SND_SOC_DAPM_INPUT("AINR2N"),
+	SND_SOC_DAPM_INPUT("AINR1N"),
+	SND_SOC_DAPM_INPUT("AINR3"),
+	SND_SOC_DAPM_INPUT("AINR2P"),
+	SND_SOC_DAPM_INPUT("AINR1P"),
+
+	/* Input muxes */
+	SND_SOC_DAPM_MUX("AINLMUX", AUD96P22_PD_1, 2, 0, &ainl_mux_kcontrol),
+	SND_SOC_DAPM_MUX("AINRMUX", AUD96P22_PD_1, 3, 0, &ainr_mux_kcontrol),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC_E("ADCL", "Capture Left", AUD96P22_PD_1, 0, 0,
+			   aud96p22_adc_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_ADC_E("ADCR", "Capture Right", AUD96P22_PD_1, 1, 0,
+			   aud96p22_adc_event, SND_SOC_DAPM_POST_PMU),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC_E("DACL", "Playback Left", AUD96P22_PD_3, 0, 0,
+			   aud96p22_dac_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_DAC_E("DACR", "Playback Right", AUD96P22_PD_3, 1, 0,
+			   aud96p22_dac_event, SND_SOC_DAPM_POST_PMU),
+
+	/* Output mixers */
+	SND_SOC_DAPM_MIXER("LD1L", AUD96P22_PD_3, 6, 0, ld1_left_kcontrols,
+			   ARRAY_SIZE(ld1_left_kcontrols)),
+	SND_SOC_DAPM_MIXER("LD1R", AUD96P22_PD_3, 7, 0, ld1_right_kcontrols,
+			   ARRAY_SIZE(ld1_right_kcontrols)),
+	SND_SOC_DAPM_MIXER("LD2", AUD96P22_PD_4, 2, 0, ld2_kcontrols,
+			   ARRAY_SIZE(ld2_kcontrols)),
+
+	/* Headset power switch */
+	SND_SOC_DAPM_SUPPLY("HS1L", AUD96P22_PD_3, 4, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HS1R", AUD96P22_PD_3, 5, 0, NULL, 0),
+
+	/* Output pins */
+	SND_SOC_DAPM_OUTPUT("HSOUTL"),
+	SND_SOC_DAPM_OUTPUT("LINEOUTL"),
+	SND_SOC_DAPM_OUTPUT("LINEOUTMP"),
+	SND_SOC_DAPM_OUTPUT("LINEOUTMN"),
+	SND_SOC_DAPM_OUTPUT("LINEOUTR"),
+	SND_SOC_DAPM_OUTPUT("HSOUTR"),
+};
+
+static const struct snd_soc_dapm_route aud96p22_dapm_routes[] = {
+	{ "AINLMUX", "AINL1 differential", "AINL1N" },
+	{ "AINLMUX", "AINL1 single-ended", "AINL1P" },
+	{ "AINLMUX", "AINL3 single-ended", "AINL3" },
+	{ "AINLMUX", "AINL2 differential", "AINL2N" },
+	{ "AINLMUX", "AINL2 single-ended", "AINL2P" },
+
+	{ "AINRMUX", "AINR1 differential", "AINR1N" },
+	{ "AINRMUX", "AINR1 single-ended", "AINR1P" },
+	{ "AINRMUX", "AINR3 single-ended", "AINR3" },
+	{ "AINRMUX", "AINR2 differential", "AINR2N" },
+	{ "AINRMUX", "AINR2 single-ended", "AINR2P" },
+
+	{ "ADCL", NULL, "AINLMUX" },
+	{ "ADCR", NULL, "AINRMUX" },
+
+	{ "ADCL", NULL, "POWER" },
+	{ "ADCR", NULL, "POWER" },
+	{ "DACL", NULL, "POWER" },
+	{ "DACR", NULL, "POWER" },
+
+	{ "LD1L", "DACL LD1L Switch", "DACL" },
+	{ "LD1L", "AINL LD1L Switch", "AINLMUX" },
+	{ "LD1L", "AINR LD1L Switch", "AINRMUX" },
+
+	{ "LD1R", "DACR LD1R Switch", "DACR" },
+	{ "LD1R", "AINR LD1R Switch", "AINRMUX" },
+	{ "LD1R", "AINL LD1R Switch", "AINLMUX" },
+
+	{ "LD2", "DACL LD2 Switch", "DACL" },
+	{ "LD2", "AINL LD2 Switch", "AINLMUX" },
+	{ "LD2", "DACR LD2 Switch", "DACR" },
+
+	{ "HSOUTL", NULL, "LD1L" },
+	{ "HSOUTR", NULL, "LD1R" },
+	{ "HSOUTL", NULL, "HS1L" },
+	{ "HSOUTR", NULL, "HS1R" },
+
+	{ "LINEOUTL", NULL, "LD1L" },
+	{ "LINEOUTR", NULL, "LD1R" },
+
+	{ "LINEOUTMP", NULL, "LD2" },
+	{ "LINEOUTMN", NULL, "LD2" },
+};
+
+static const struct snd_soc_component_driver aud96p22_driver = {
+	.controls		= aud96p22_snd_controls,
+	.num_controls		= ARRAY_SIZE(aud96p22_snd_controls),
+	.dapm_widgets		= aud96p22_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(aud96p22_dapm_widgets),
+	.dapm_routes		= aud96p22_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(aud96p22_dapm_routes),
+	.idle_bias_on		= 1,
+	.use_pmdown_time	= 1,
+	.endianness		= 1,
+	.non_legacy_dai_naming	= 1,
+};
+
+static int aud96p22_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct aud96p22_priv *priv = snd_soc_component_get_drvdata(dai->component);
+	struct regmap *regmap = priv->regmap;
+	unsigned int val;
+
+	/* Master/slave mode */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		val = 0;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		val = I2S1_MS_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(regmap, AUD96P22_I2S1_CONFIG_0, I2S1_MS_MODE, val);
+
+	/* Audio format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		val = I2S1_MODE_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		val = I2S1_MODE_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val = I2S1_MODE_LEFT_J;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap_update_bits(regmap, AUD96P22_I2S1_CONFIG_0, I2S1_MODE_MASK, val);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops aud96p22_dai_ops = {
+	.set_fmt = aud96p22_set_fmt,
+};
+
+#define AUD96P22_RATES	SNDRV_PCM_RATE_8000_192000
+#define AUD96P22_FORMATS (\
+		SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
+		SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver aud96p22_dai = {
+	.name = "aud96p22-dai",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = AUD96P22_RATES,
+		.formats = AUD96P22_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = AUD96P22_RATES,
+		.formats = AUD96P22_FORMATS,
+	},
+	.ops = &aud96p22_dai_ops,
+};
+
+static const struct regmap_config aud96p22_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = AUD96P22_REG_MAX,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int aud96p22_i2c_probe(struct i2c_client *i2c,
+			      const struct i2c_device_id *id)
+{
+	struct device *dev = &i2c->dev;
+	struct aud96p22_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	priv->regmap = devm_regmap_init_i2c(i2c, &aud96p22_regmap);
+	if (IS_ERR(priv->regmap)) {
+		ret = PTR_ERR(priv->regmap);
+		dev_err(dev, "failed to init i2c regmap: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(i2c, priv);
+
+	ret = devm_snd_soc_register_component(dev, &aud96p22_driver, &aud96p22_dai, 1);
+	if (ret) {
+		dev_err(dev, "failed to register component: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int aud96p22_i2c_remove(struct i2c_client *i2c)
+{
+	return 0;
+}
+
+static const struct of_device_id aud96p22_dt_ids[] = {
+	{ .compatible = "zte,zx-aud96p22", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, aud96p22_dt_ids);
+
+static struct i2c_driver aud96p22_i2c_driver = {
+	.driver = {
+		.name = "zx_aud96p22",
+		.of_match_table = aud96p22_dt_ids,
+	},
+	.probe = aud96p22_i2c_probe,
+	.remove = aud96p22_i2c_remove,
+};
+module_i2c_driver(aud96p22_i2c_driver);
+
+MODULE_DESCRIPTION("ZTE ASoC AUD96P22 CODEC driver");
+MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
+MODULE_LICENSE("GPL v2");